{"version":3,"sources":["jsdelivr-header.js","/npm/@zeainc/zea-engine@4.17.0/dist/index.esm.mjs"],"names":[],"mappings":"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","file":"/npm/@zeainc/zea-engine@4.17.0/dist/index.esm.mjs","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.39.0.\n * Original file: /npm/@zeainc/zea-engine@4.17.0/dist/index.esm.mjs\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","var version = \"4.17.0\";\n\n/**\n * Libraries registry.\n */\nclass LibsRegistry {\n    registry;\n    version;\n    /**\n     * Construct a new libraries registry for the specific version.\n     * @param version - The version of the Zea Engine that will be validated against the registered libraries.\n     */\n    constructor(version) {\n        this.version = version;\n        this.registry = {};\n    }\n    /**\n     * Validate and register a library.\n     * @param packageJson - The package.json of the library to register.\n     */\n    registerLib(packageJson) {\n        const libName = packageJson.name;\n        const libVersion = packageJson.version;\n        if (this.registry[libName]) {\n            console.warn(\"Library already registered:\" + libName);\n        }\n        this.registry[libName] = libVersion;\n        console.log(`Registered lib '${libName}' v${libVersion}`);\n    }\n    /**\n     * List the registered libraries with their versions.\n     * @return Libraries list.\n     */\n    listLibs() {\n        return this.registry;\n    }\n}\n\n// https://stackoverflow.com/questions/57776001/how-to-detect-ipad-pro-as-ipad-using-javascript\nfunction isIOSDevice() {\n    if (/iPad|iPhone|iPod/.test(navigator.platform)) {\n        return true;\n    }\n    else {\n        return navigator.maxTouchPoints && navigator.maxTouchPoints > 2 && /MacIntel/.test(navigator.platform);\n    }\n}\n// https://stackdiary.com/detect-mobile-browser-javascript/\nfunction isMobileDevice() {\n    return (navigator.maxTouchPoints && navigator.maxTouchPoints > 0 && /Android|iPhone|iPad|iPod/i.test(navigator.userAgent));\n}\nfunction getBrowserDesc() {\n    const nAgt = navigator.userAgent;\n    let browserName = '';\n    let fullVersion = '' + parseFloat(navigator.appVersion);\n    let nameOffset;\n    let verOffset;\n    let ix;\n    if (navigator.brave) {\n        browserName = 'Brave';\n        verOffset = nAgt.indexOf('Chrome');\n        fullVersion = nAgt.substring(verOffset + 7, nAgt.indexOf(' ', verOffset + 7));\n    }\n    // In Opera, the true version is after \"Opera\" or after \"Version\"\n    else if ((verOffset = nAgt.indexOf('Opera')) != -1) {\n        browserName = 'Opera';\n        fullVersion = nAgt.substring(verOffset + 6);\n        if ((verOffset = nAgt.indexOf('Version')) != -1)\n            fullVersion = nAgt.substring(verOffset + 8);\n    }\n    // In MSIE, the true version is after \"MSIE\" in userAgent\n    else if ((verOffset = nAgt.indexOf('MSIE')) != -1) {\n        browserName = 'Microsoft Internet Explorer';\n        fullVersion = nAgt.substring(verOffset + 5);\n    }\n    else if ((verOffset = nAgt.indexOf('Edge')) != -1) {\n        browserName = 'Edge';\n        fullVersion = nAgt.substring(verOffset + 4);\n    }\n    // In Chrome, the true version is after \"Chrome\"\n    else if ((verOffset = nAgt.indexOf('Chrome')) != -1) {\n        browserName = 'Chrome';\n        fullVersion = nAgt.substring(verOffset + 7, nAgt.indexOf(' ', verOffset + 7));\n    }\n    // TOOD: Parse Samsung userAgent\n    // https://developer.samsung.com/technical-doc/view.do?v=T000000203\n    // In Safari, the true version is after \"Safari\" or after \"Version\"\n    else if ((verOffset = nAgt.indexOf('Safari')) != -1) {\n        browserName = 'Safari';\n        fullVersion = nAgt.substring(verOffset + 7);\n        if ((verOffset = nAgt.indexOf('Version')) != -1)\n            fullVersion = nAgt.substring(verOffset + 8);\n    }\n    // In Firefox, the true version is after \"Firefox\"\n    else if ((verOffset = nAgt.indexOf('Firefox')) != -1) {\n        browserName = 'Firefox';\n        fullVersion = nAgt.substring(verOffset + 8);\n    }\n    // In most other browsers, \"name/version\" is at the end of userAgent\n    else if ((nameOffset = nAgt.lastIndexOf(' ') + 1) < (verOffset = nAgt.lastIndexOf('/'))) {\n        browserName = nAgt.substring(nameOffset, verOffset);\n        fullVersion = nAgt.substring(verOffset + 1);\n    }\n    // trim the fullVersion string at semicolon/space if present\n    if ((ix = fullVersion.indexOf(';')) != -1)\n        fullVersion = fullVersion.substring(0, ix);\n    if ((ix = fullVersion.indexOf(' ')) != -1)\n        fullVersion = fullVersion.substring(0, ix);\n    return {\n        browserName,\n        fullVersion,\n    };\n}\n// eslint-disable-next-line require-jsdoc\nfunction getGPUDesc() {\n    let webgl;\n    try {\n        webgl = document.createElement('canvas').getContext('webgl');\n    }\n    catch (e) { }\n    if (!webgl) {\n        return {\n            vendor: 'Unknown',\n            renderer: 'Unknown',\n            gpuVendor: 'Unknown',\n            maxTextureSize: 0,\n            supportsWebGL: false,\n            supportsWebGL2: false,\n        };\n    }\n    let webgl2;\n    try {\n        webgl2 = document.createElement('canvas').getContext('webgl2');\n    }\n    catch (e) { }\n    const debugInfo = webgl.getExtension('WEBGL_debug_renderer_info');\n    if (!debugInfo) {\n        console.warn('Unable to determine GPU Info:');\n        return {\n            vendor: 'Unknown',\n            renderer: 'Unknown',\n            gpuVendor: 'Unknown',\n            maxTextureSize: 0,\n            supportsWebGL: webgl != undefined,\n            supportsWebGL2: webgl2 != undefined,\n        };\n    }\n    const vendor = webgl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL);\n    const renderer = webgl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL);\n    const maxTextureSize = webgl.getParameter(webgl.MAX_TEXTURE_SIZE);\n    let gpuVendor;\n    if (renderer.match(/NVIDIA/i)) {\n        gpuVendor = 'NVidia';\n    }\n    else if (renderer.match(/AMD/i) || renderer.match(/Radeon/i)) {\n        gpuVendor = 'AMD';\n    }\n    else if (renderer.match(/Intel/i)) {\n        gpuVendor = 'Intel';\n    }\n    else if (renderer.match(/Mali/i)) {\n        gpuVendor = 'ARM';\n    }\n    else if (renderer.match(/Apple/i)) {\n        gpuVendor = 'Apple';\n    }\n    else if (renderer.match(/Adreno/i)) {\n        gpuVendor = 'Adreno';\n    }\n    else if (renderer.match(/Swiftshader/i)) {\n        gpuVendor = 'Google';\n        console.warn('Hardware rendering is disabled or not working on your system. Falling back to the Swiftshader. Expect poor performance:', renderer);\n    }\n    else {\n        console.warn('Unable to determine GPU vendor:', renderer);\n    }\n    return {\n        vendor,\n        renderer,\n        gpuVendor,\n        maxTextureSize,\n        supportsWebGL: true,\n        supportsWebGL2: webgl2 != undefined,\n    };\n}\nconst getOS = () => {\n    const { userAgent } = window.navigator;\n    let os = null;\n    if (/macintosh/i.test(userAgent)) {\n        os = 'macOS';\n    }\n    else if (/ios/i.test(userAgent)) {\n        os = 'iOS';\n    }\n    else if (/win/i.test(userAgent)) {\n        os = 'Windows';\n    }\n    else if (/android/i.test(userAgent)) {\n        os = 'Android';\n    }\n    else if (/linux/i.test(userAgent)) {\n        os = 'Linux';\n    }\n    return os;\n};\nconst SystemDesc = (function () {\n    if (!globalThis.navigator || /node/i.test(globalThis.navigator.userAgent)) {\n        // When running in NodeJS\n        return {\n            OS: 'Node',\n            isMobileDevice: false,\n            isIOSDevice: false,\n            browserName: 'Node',\n            webGLSupported: false,\n            deviceCategory: 'High',\n            hardwareConcurrency: 4,\n        };\n    }\n    const isMobile = isMobileDevice();\n    const browserDesc = getBrowserDesc();\n    const gpuDesc = getGPUDesc();\n    let deviceCategory = 'Low';\n    if (gpuDesc.supportsWebGL) {\n        // We divide devices into 3 categories.\n        // 0: low end, we dial everything down as much as possible\n        // 1: mid-range, Enb maps and Textures go to mid-lods.\n        //    Typically these devices are laptops, so the textures can't be too blurry\n        // 2: High-end: turn up as much as needed.\n        if (!isMobile) {\n            // Remove braces and split into parts\n            const parts = gpuDesc.renderer.replace(/[()]/g, '').split(' ');\n            if (gpuDesc.gpuVendor == 'NVidia') {\n                const gtxIdx = parts.indexOf('GTX');\n                if (gtxIdx != -1) {\n                    const model = parts[gtxIdx + 1];\n                    if (model.endsWith('M')) {\n                        // laptop GPU.\n                        const modelNumber = parseInt(model.substring(0, model.length - 2));\n                        if (modelNumber >= 900) {\n                            deviceCategory = 'Medium';\n                        }\n                        else {\n                            deviceCategory = 'Low';\n                        }\n                    }\n                    else {\n                        const modelNumber = parseInt(model);\n                        if (modelNumber >= 1030) {\n                            deviceCategory = 'High';\n                        }\n                        else {\n                            deviceCategory = 'Medium';\n                        }\n                    }\n                }\n                else {\n                    if (parts.includes('RTX') || parts.includes('TITAN') || parts.includes('Quadro')) {\n                        deviceCategory = 'High';\n                    }\n                    else {\n                        deviceCategory = 'Low';\n                    }\n                }\n            }\n            else if (gpuDesc.gpuVendor == 'AMD') {\n                const radeonIdx = parts.indexOf('Radeon');\n                if (radeonIdx != -1) {\n                    const rxIdx = parts.indexOf('RX');\n                    if (rxIdx != -1) {\n                        if (parts[rxIdx + 1] == 'Vega') {\n                            deviceCategory = 'High';\n                        }\n                        else {\n                            const model = parts[rxIdx + 1];\n                            let modelNumber;\n                            if (model.endsWith('X')) {\n                                modelNumber = parseInt(model.substring(0, model.length - 2));\n                                deviceCategory = 'High';\n                            }\n                            else {\n                                modelNumber = parseInt(model);\n                            }\n                            if (modelNumber >= 480) {\n                                deviceCategory = 'High';\n                            }\n                            else {\n                                deviceCategory = 'Medium';\n                            }\n                        }\n                    }\n                    else if (parts[radeonIdx + 1] == 'Pro') {\n                        const modelNumber = parseInt(parts[rxIdx + 1]);\n                        if (modelNumber >= 450) {\n                            deviceCategory = 'Medium';\n                        }\n                        else {\n                            deviceCategory = 'Low';\n                        }\n                    }\n                    else if (parts[radeonIdx + 1] == 'Sky') {\n                        const modelNumber = parseInt(parts[rxIdx + 1]);\n                        if (modelNumber >= 700) {\n                            deviceCategory = 'Medium';\n                        }\n                        else {\n                            deviceCategory = 'Low';\n                        }\n                    }\n                    else {\n                        deviceCategory = 'Low';\n                    }\n                }\n                else {\n                    if (parts.includes('FirePro') || parts.includes('Quadro')) {\n                        deviceCategory = 'High';\n                    }\n                    else {\n                        deviceCategory = 'Low';\n                    }\n                }\n            }\n            else if (gpuDesc.gpuVendor == 'Adreno') {\n                deviceCategory = 'Low';\n            }\n            else if (gpuDesc.gpuVendor == 'Intel') {\n                deviceCategory = 'Low';\n            }\n            else if (gpuDesc.gpuVendor == 'Google') {\n                deviceCategory = 'Low';\n            }\n        }\n        else {\n            deviceCategory = 'Low';\n        }\n    }\n    let hardwareConcurrency = globalThis.navigator.hardwareConcurrency;\n    if (!hardwareConcurrency) {\n        if (isMobile)\n            hardwareConcurrency = 4;\n        else\n            hardwareConcurrency = 6;\n    }\n    return {\n        OS: getOS(),\n        isMobileDevice: isMobile,\n        isIOSDevice: isIOSDevice(),\n        browserName: browserDesc.browserName,\n        fullVersion: browserDesc.fullVersion,\n        webGLSupported: gpuDesc.supportsWebGL,\n        gpuDesc,\n        deviceCategory,\n        hardwareConcurrency,\n    };\n})();\n// @ts-ignore\nif (!globalThis.ZeaSystemDesc) {\n    // @ts-ignore\n    globalThis.ZeaSystemDesc = SystemDesc;\n}\n\nlet registeredClasses = {};\nlet classNames = {};\nlet classDefinitions = [];\n/**\n * Registry is a static factory that handles registration/reconstruction of\n * classes bases on BaseClass. Registered classes can then be constructed by the Registry by name.\n *\n * Note: className is required because on minification process\n * the name of classes change and we can't simply use '....constructor.name'.\n * So, we need a way of relating minified class names to the one stored for persistency.\n *\n * i.e.\n * ```javascript\n * // Import registry class\n * class Foo() extends BaseClass {}\n *\n * Registry.register('Foo', Foo)\n * // In case 'Foo' class gets its name changed to 'c' on minification,\n * // and the persisted data type is 'Foo', we would know how to relate them.\n * ```\n *\n * @static\n * @class Registry\n */\nclass Registry {\n    /**\n     * Registers a new class to the factory.\n     *\n     * @param className - Name of the registered class\n     * @param classDef - Class representation(Class function, type)\n     */\n    static register(className, classDef) {\n        if (className in registeredClasses) {\n            console.warn(`There's a class registered with '${className}' name. Second registration failed.`);\n            return;\n        }\n        // Note: To provide backwards compatibility, same classDef can be stored under multiple names.\n        // Thats the reason behind using indexes instead of the classDef.\n        const index = classDefinitions.length;\n        classDefinitions.push(classDef);\n        classNames[index] = className;\n        registeredClasses[className] = index;\n    }\n    /**\n     * Returns class definition using the name it was registered with.\n     *\n     * @param className - Name of the registered class\n     * @return - Class representation(Class function, type)\n     */\n    static getClassDefinition(className) {\n        if (!(className in registeredClasses))\n            throw new Error(`${className} class is not registered`);\n        return classDefinitions[registeredClasses[className]];\n    }\n    /**\n     * Returns class name registered for the instantiated object.\n     * @param classDefinition - Class type definition.\n     * @return - Name of the registered class\n     */\n    static getClassName(classDefinition) {\n        const classId = classDefinitions.indexOf(classDefinition);\n        if (classId >= 0 && classNames[classId])\n            return classNames[classId];\n        throw new Error(`class is not registered`);\n    }\n    /**\n     * The factory function that construct the class registered under the given name.\n     *\n     * @param className - Name of the registered class\n     * @return - Instantiated object of the specified class\n     */\n    static constructClass(className) {\n        const classDefinition = classDefinitions[registeredClasses[className]];\n        if (!classDefinition)\n            throw new Error(`${className} class is not registered`);\n        return new classDefinition();\n    }\n    /**\n     * For testing purpose only, never call this outside of the test scope.\n     *\n     * @private\n     */\n    static flush() {\n        registeredClasses = {};\n        classNames = {};\n        classDefinitions = [];\n    }\n}\n\n/**\n * String functions\n *\n */\nclass StringFunctions {\n    /**\n     * Replaces all matches in a string.\n     *\n     * @static\n     * @param str -\n     * @param pattern -\n     * @param replacement -\n     * @return -\n     */\n    static replaceAll(str, pattern, replacement) {\n        return str.replace(new RegExp(pattern, 'g'), replacement);\n    }\n    /**\n     * Returns JSON object as a formatted string, but the numeric values are fixed to the specified precision.\n     *\n     * @static\n     * @param val -\n     * @param space -\n     * @param precision -\n     * @return -\n     */\n    static stringifyJSONWithFixedPrecision(val, space = 0, precision = 5) {\n        return JSON.stringify(val, (_, val) => {\n            return val ? (val.toFixed ? Number(val.toFixed(precision)) : val) : val;\n        }, space);\n    }\n    /**\n     * Transforms the given string into a numeric value.\n     *\n     * @static\n     * @param str -\n     * @return -\n     */\n    static hashStr(str) {\n        let hash = 0;\n        let i;\n        let chr;\n        let len;\n        if (str.length === 0)\n            return hash;\n        for (i = 0, len = str.length; i < len; i++) {\n            chr = str.charCodeAt(i);\n            hash = (hash << 5) - hash + chr;\n            hash |= 0; // Convert to 32bit integer\n        }\n        return Math.abs(hash);\n    }\n}\n\n/**\n * Representing a Vec2(two-dimensional floating point vector). A Vec2 is for representing 2 dimensional values, such as screen coordinates or pixel coordinates within an image.\n *\n * Math types internally store values in {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float32Array|Float32Array} and\n * expose getters and setters for the component values.\n *\n */\nclass Vec2 {\n    x;\n    y;\n    /**\n     * Creates a Vec2.\n     *\n     * ```javascript\n     *  const myVec2 = new Vec2(1.2, 3.4)\n     * ```\n     *\n     */\n    constructor(x = 0, y = 0) {\n        this.x = x;\n        this.y = y;\n    }\n    /**\n     * Setter from scalar components.\n     * @param x - The x component.\n     * @param y  - The y component.\n     */\n    set(x, y) {\n        this.x = x;\n        this.y = y;\n    }\n    /**\n     * Replaces this Vec2 data with the Vec2 data passed as parameter.\n     *\n     * @param other - The other Vec2 to set from.\n     */\n    setFromOther(other) {\n        this.x = other.x;\n        this.y = other.y;\n    }\n    /**\n     * Checks if this Vec2 contains the same values as the other Vec2.\n     *\n     * @param other - The other Vec2 to compare with.\n     * @return - Returns `true` if are the same Vector, otherwise, `false`.\n     */\n    isEqual(other) {\n        return this.x == other.x && this.y == other.y;\n    }\n    /**\n     * Checks if this Vec2 is different from another Vec2.\n     *\n     * @param other - The other Vec2 to compare with.\n     * @return - Returns `true` if the Vec2s are different, otherwise, `false`.\n     */\n    notEqual(other) {\n        return this.x != other.x && this.y != other.y;\n    }\n    /**\n     * Returns true if this Vec2 is approximately the same as other.\n     *\n     * @param other - The other Vec2 to compare with.\n     * @param precision - The precision to which the values must match.\n     * @return - Returns true or false.\n     */\n    approxEqual(other, precision = Number.EPSILON) {\n        return Math.abs(this.x - other.x) < precision && Math.abs(this.y - other.y) < precision;\n    }\n    /**\n     * Adds other to this Vec2 and returns the result as a new Vec2.\n     *\n     * @param other - The other Vec2 to add.\n     * @return - Returns a new Vec2.\n     */\n    add(other) {\n        return new Vec2(this.x + other.x, this.y + other.y);\n    }\n    /**\n     * Adds a Vec2 to this Vec2.\n     *\n     * @param other - The other Vec2 to add.\n     */\n    addInPlace(other) {\n        this.x += other.x;\n        this.y += other.y;\n    }\n    /**\n     * Subtracts a Vec2 from this Vec2 and returns the result as a new Vec2.\n     *\n     * @param other - The other Vec2 to subtract.\n     * @return - Returns a new Vec2.\n     */\n    subtract(other) {\n        return new Vec2(this.x - other.x, this.y - other.y);\n    }\n    /**\n     * Subtracts a Vec2 from this Vec2.\n     *\n     * @param other - The other Vec2 to subtract.\n     * @return - Returns a new Vec2.\n     */\n    subtractInPlace(other) {\n        this.x -= other.x;\n        this.y -= other.y;\n        return this;\n    }\n    /**\n     * Scales this Vec2 by scalar and returns the result as a new Vec2.\n     *\n     * @param scalar - The scalar value.\n     * @return - Returns a new Vec2.\n     */\n    scale(scalar) {\n        return new Vec2(this.x * scalar, this.y * scalar);\n    }\n    /**\n     * Scales this Vec2 by scalar.\n     *\n     * @param scalar - The scalar value.\n     */\n    scaleInPlace(scalar) {\n        this.x *= scalar;\n        this.y *= scalar;\n    }\n    /**\n     * Inverts this Vec2 and returns the result as a new Vec2.\n     *\n     * @return - Returns a new Vec2.\n     */\n    invert() {\n        return new Vec2(1.0 / this.x, 1.0 / this.y);\n    }\n    /**\n     * Inverts this Vec2.\n     *\n     * @return - The return value.\n     */\n    invertInPlace() {\n        this.x = 1.0 / this.x;\n        this.y = 1.0 / this.y;\n        return this;\n    }\n    /**\n     * Multiplies a Vec2 with this Vec2 and returns the result as a new Vec2.\n     *\n     * @param other - The other Vec2 to multiply with.\n     * @return - Returns a new Vec2.\n     */\n    multiply(other) {\n        return new Vec2(this.x * other.x, this.y * other.y);\n    }\n    /**\n     * Multiplies a Vec2 with this Vec2.\n     *\n     * @param other - The other Vec2 to multiply with.\n     */\n    multiplyInPlace(other) {\n        this.x *= other.x;\n        this.y *= other.y;\n    }\n    /**\n     * Calculates the squared length of this Vec2.\n     *\n     * @return - Returns the length squared.\n     */\n    lengthSquared() {\n        const x = this.x;\n        const y = this.y;\n        return x * x + y * y;\n    }\n    /**\n     * Calculates the length of this Vec2.\n     *\n     * @return - Returns the length.\n     */\n    length() {\n        return Math.sqrt(this.lengthSquared());\n    }\n    /**\n     * Calculates the distance to another vector.\n     *\n     * @param other - The other value.\n     * @return - Returns the distance between vectors.\n     */\n    distanceTo(other) {\n        const x = this.x - other.x;\n        const y = this.y - other.y;\n        return Math.sqrt(x * x + y * y);\n    }\n    /**\n     * Normalizes the Vec2 and returns it as a new Vec2.\n     * Multiplies coordinates value by the inverse of the vector length.\n     *\n     * @return - Returns the Vec2 normalized.\n     */\n    normalize() {\n        const x = this.x;\n        const y = this.y;\n        let len = x * x + y * y;\n        if (len < Number.EPSILON) {\n            return new Vec2();\n        }\n        // TODO: evaluate use of glm_invsqrt here?\n        len = 1 / Math.sqrt(len);\n        return new Vec2(x * len, y * len);\n    }\n    /**\n     * Normalizes this Vec2 multiplying coordinate values by the inverse of the vector length.\n     */\n    normalizeInPlace() {\n        const x = this.x;\n        const y = this.y;\n        let len = x * x + y * y;\n        if (len < Number.EPSILON) {\n            return;\n        }\n        len = 1 / Math.sqrt(len);\n        this.set(x * len, y * len);\n    }\n    /**\n     * Calculates the dot product of this Vec2 against another Vec2.\n     *\n     * @param other - The other Vec2 to compare with.\n     * @return - Returns the dot product.\n     */\n    dot(other) {\n        return this.x * other.x + this.y * other.y;\n    }\n    /**\n     * Calculates the cross product of this Vec2 against another Vec2.\n     *\n     * @param other - The other Vec2 to compare with.\n     * @return - Returns the cross product.\n     */\n    cross(other) {\n        // just calculate the z-component\n        return this.x * other.y - this.y * other.x;\n    }\n    /**\n     * Gets the angle between this Vec2 and other assuming both are normalized vectors.\n     *\n     * @param other - The other Vec2 to compare with.\n     * @return - Returns the angle in radians.\n     */\n    angleTo(other) {\n        const cosine = this.normalize().dot(other.normalize());\n        if (cosine > 1.0)\n            return 0.0;\n        else if (cosine < -1.0)\n            return Math.PI;\n        else\n            return Math.acos(cosine);\n    }\n    /**\n     * Gets the angle between this Vec2 and other.\n     *\n     * @param other - The other Vec2 to compare with.\n     * @return - Returns the angle in radians.\n     */\n    signedAngleTo(other) {\n        const angle = this.angleTo(other);\n        if (this.cross(other) < 0.0)\n            return -angle;\n        else\n            return angle;\n    }\n    /**\n     * Rotates a Vec2 in a clockwise direction and returns a new rotated Vec2.\n     *\n     * @param angle - The angle of rotation.\n     * @return - Returns the rotated vector.\n     */\n    rotate(angle) {\n        const cosA = Math.cos(angle);\n        const sinA = Math.sin(angle);\n        return new Vec2(this.x * cosA - this.y * sinA, this.x * sinA + this.y * cosA);\n    }\n    /**\n     * Performs a linear interpolation between this Vec2 and other Vec2.\n     *\n     * @param other - The other Vec2 to interpolate between.\n     * @param t - Interpolation amount between the two inputs.\n     * @return - Returns a new Vec2.\n     */\n    lerp(other, t) {\n        const ax = this.x;\n        const ay = this.y;\n        return new Vec2(ax + t * (other.x - ax), ay + t * (other.y - ay));\n    }\n    /**\n     * Generates a random vector with the given scale.\n     *\n     * @param scale - Length of the resulting vector. If omitted, a unit vector will be returned.\n     * @return - The return value.\n     */\n    setRandomDir(scale = 1.0) {\n        const r = Math.random() * 2.0 * Math.PI;\n        this.x = Math.cos(r) * scale;\n        this.y = Math.sin(r) * scale;\n        return this;\n    }\n    /**\n     * Randomizes the scale of this Vec2 coordinates.\n     *\n     * @param scale - The scale value.\n     * @return - The return value.\n     */\n    setRandom(scale = 1.0) {\n        this.x = Math.random() * scale;\n        this.y = Math.random() * scale;\n        return this;\n    }\n    /**\n     * Clones this Vec2 and returns a new Vec2.\n     *\n     * @return - Returns a new Vec2.\n     */\n    clone() {\n        return new Vec2(this.x, this.y);\n    }\n    /**\n     * Returns current Vec2 data as array. Often used to pass types to the GPU.\n     *\n     * @return - Returns as an array.\n     */\n    asArray() {\n        return [this.x, this.y];\n    }\n    /**\n     * Setter from an array.\n     */\n    fromArray(vals) {\n        this.x = vals[0];\n        this.y = vals[1];\n    }\n    // ///////////////////////////\n    // Persistence\n    /**\n     * Converts this Vec3 to a string in JSON format.\n     *\n     * @return - The return value.\n     */\n    toString() {\n        // eslint-disable-next-line new-cap\n        return StringFunctions.stringifyJSONWithFixedPrecision(this.toJSON());\n    }\n    /**\n     * Encodes Vec2 Class as a JSON object for persistence.\n     *\n     * @return - The json object.\n     */\n    toJSON() {\n        return {\n            x: this.x,\n            y: this.y,\n        };\n    }\n    /**\n     * Decodes a JSON object to set the state of this class.\n     *\n     * @param j - The json object.\n     */\n    fromJSON(j) {\n        this.x = j.x;\n        this.y = j.y;\n    }\n    /**\n     * Loads the state of the value from a binary reader.\n     *\n     * @param reader - The reader value.\n     */\n    readBinary(reader) {\n        this.x = reader.loadFloat32();\n        this.y = reader.loadFloat32();\n    }\n    /**\n     * Calculate the intersection point of 2 2d lines, returning the parameters values for each line.\n     *\n     * @param p0 - The point of the first line\n     * @param d0 - The direction of the first line\n     * @param p1 - The point of the second line\n     * @param d1 - The direction of the second line\n     * @return - Returns an array containing 2 parameter values for the 2 lines.\n     */\n    static intersectionOfLines(p1, p2, p3, p4) {\n        // https://dirask.com/posts/JavaScript-how-to-calculate-intersection-point-of-two-lines-for-given-4-points-VjvnAj\n        // down part of intersection point formula\n        const d1 = (p1.x - p2.x) * (p3.y - p4.y); // (x1 - x2) * (y3 - y4)\n        const d2 = (p1.y - p2.y) * (p3.x - p4.x); // (y1 - y2) * (x3 - x4)\n        const d = d1 - d2;\n        if (d == 0) {\n            return null;\n        }\n        // upper part of intersection point formula\n        const u1 = p1.x * p2.y - p1.y * p2.x; // (x1 * y2 - y1 * x2)\n        const u4 = p3.x * p4.y - p3.y * p4.x; // (x3 * y4 - y3 * x4)\n        const u2x = p3.x - p4.x; // (x3 - x4)\n        const u3x = p1.x - p2.x; // (x1 - x2)\n        const u2y = p3.y - p4.y; // (y3 - y4)\n        const u3y = p1.y - p2.y; // (y1 - y2)\n        // intersection point formula\n        const px = (u1 * u2x - u3x * u4) / d;\n        const py = (u1 * u2y - u3y * u4) / d;\n        return new Vec2(px, py);\n    }\n    isValid() {\n        for (const v of this.asArray()) {\n            if (v == Infinity || isNaN(v))\n                return false;\n        }\n        return true;\n    }\n}\n\n/**\n * Represents a three dimensional coordinate, such as 3D scene values, or mesh vertex positions.\n */\nclass Vec3 {\n    x;\n    y;\n    z;\n    /**\n     * Creates a Vec3.\n     */\n    constructor(x = 0, y = 0, z = 0) {\n        this.x = x;\n        this.y = y;\n        this.z = z;\n    }\n    /**\n     * Getter for `xy` swizzel.\n     *\n     * @return - Returns the xy components as a Vec2.\n     */\n    get xy() {\n        return new Vec2(this.x, this.y);\n    }\n    /**\n     * Getter for `yz` swizzel.\n     *\n     * @return - Returns the yz components as a Vec2.\n     */\n    get yz() {\n        return new Vec2(this.y, this.z);\n    }\n    /**\n     * Setter from scalar components.\n     *\n     * @param x - The x component.\n     * @param y - The y component.\n     * @param z - The y component.\n     */\n    set(x, y, z) {\n        this.x = x;\n        this.y = y !== undefined ? y : x;\n        this.z = z !== undefined ? z : x;\n    }\n    /**\n     * Sets the state of a Vec3 Object from another Vec3.\n     *\n     * @param other - The other Vec3 to set from.\n     */\n    setFromOther(other) {\n        this.x = other.x;\n        this.y = other.y;\n        this.z = other.z;\n    }\n    /**\n     * Checks if the coordinates of this Vec3 are 0 0 0.\n     *\n     * @return - Returns `true` if the coordinates are(0, 0, 0), otherwise, `false`.\n     */\n    isNull() {\n        return Math.abs(this.x) < Number.EPSILON && Math.abs(this.y) < Number.EPSILON && Math.abs(this.z) < Number.EPSILON;\n    }\n    /**\n     * Checks if the coordinates of this Vec3 are 1 1 1.\n     *\n     * @return - Returns `true` if the coordinates are(1, 1, 1), otherwise, `false`.\n     */\n    is111() {\n        return (Math.abs(1.0 - this.x) < Number.EPSILON &&\n            Math.abs(1.0 - this.y) < Number.EPSILON &&\n            Math.abs(1.0 - this.z) < Number.EPSILON);\n    }\n    /**\n     * Checks if this Vec3 contains the same values as the other Vec3.\n     *\n     * @param other - The other Vec3 to compare with.\n     * @return - Returns `true` if the values are the same, otherwise, `false`.\n     */\n    isEqual(other) {\n        return this.x == other.x && this.y == other.y && this.z == other.z;\n    }\n    /**\n     * Checks if this Vec2 is different from another Vec2.\n     *\n     * @param other - The other Vec3 to compare with.\n     * @return - Returns `true` if the Vec3s are different, otherwise, `false`.\n     */\n    notEqual(other) {\n        return this.x != other.x && this.y != other.y && this.z != other.z;\n    }\n    /**\n     * Returns true if this Vec2 is approximately the same as other.\n     *\n     * @param other - The other Vec3 to compare with.\n     * @param precision - The precision to which the values must match.\n     * @return - Returns true or false.\n     */\n    approxEqual(other, precision = Number.EPSILON) {\n        return (Math.abs(this.x - other.x) < precision &&\n            Math.abs(this.y - other.y) < precision &&\n            Math.abs(this.z - other.z) < precision);\n    }\n    /**\n     * Adds other to this Vec3 and return the result as a new Vec3.\n     *\n     * @param other - The other Vec3 to add.\n     * @return - Returns a new Vec3.\n     */\n    add(other) {\n        return new Vec3(this.x + other.x, this.y + other.y, this.z + other.z);\n    }\n    /**\n     * Adds other to this Vec3.\n     *\n     * @param other - The other Vec3 to add.\n     */\n    addInPlace(other) {\n        this.x += other.x;\n        this.y += other.y;\n        this.z += other.z;\n    }\n    /**\n     * Subtracts other from this Vec3 and returns the result as a new Vec3.\n     *\n     * @param other - The other Vec3 to subtract.\n     * @return - Returns a new Vec3.\n     */\n    subtract(other) {\n        return new Vec3(this.x - other.x, this.y - other.y, this.z - other.z);\n    }\n    /**\n     * Subtracts other from this Vec3.\n     *\n     * @param other - The other Vec3 to subtract.\n     */\n    subtractInPlace(other) {\n        this.x -= other.x;\n        this.y -= other.y;\n        this.z -= other.z;\n    }\n    /**\n     * Multiplies two Vec3s and returns the result as a new Vec3.\n     *\n     * @param other - The other Vec3 to multiply with.\n     * @return - Returns a new Vec3.\n     */\n    multiply(other) {\n        return new Vec3(this.x * other.x, this.y * other.y, this.z * other.z);\n    }\n    /**\n     * Multiplies two Vec3s.\n     *\n     * @param other - The other Vec3 to multiply with.\n     */\n    multiplyInPlace(other) {\n        this.x *= other.x;\n        this.y *= other.y;\n        this.z *= other.z;\n    }\n    /**\n     * Divides two Vec3s and returns the result as a new Vec3.\n     *\n     * @param vec3 - The other Vec3 to divide by.\n     * @return - Returns a new Vec3.\n     */\n    divide(vec3) {\n        return new Vec3(this.x / vec3.x, this.y / vec3.y, this.z / vec3.z);\n    }\n    /**\n     * Divides two Vec3s.\n     *\n     * @param vec3 - The other Vec3 to divide by.\n     */\n    divideInPlace(vec3) {\n        this.x /= vec3.x;\n        this.y /= vec3.y;\n        this.z /= vec3.z;\n    }\n    /**\n     * Scales this Vec3 by scalar and returns the result as a new Vec3.\n     *\n     * @param scalar - The scalar value.\n     * @return - Returns a new Vec3.\n     */\n    scale(scalar) {\n        return new Vec3(this.x * scalar, this.y * scalar, this.z * scalar);\n    }\n    /**\n     * Scales this Vec3 by scalar.\n     *\n     * @param scalar - The scalar value.\n     */\n    scaleInPlace(scalar) {\n        this.x *= scalar;\n        this.y *= scalar;\n        this.z *= scalar;\n    }\n    /**\n     * Negates this Vec3 (x = -x, y = -y and z = -z), but returns the result as a new Vec3.\n     *\n     * @return - Returns a new Vec3.\n     */\n    negate() {\n        return new Vec3(-this.x, -this.y, -this.z);\n    }\n    /**\n     * Returns the inverse of this Vec3, but returns. the result as a new Vec3\n     *\n     * @return - Returns a new Vec3.\n     */\n    inverse() {\n        return new Vec3(1.0 / this.x, 1.0 / this.y, 1.0 / this.z);\n    }\n    /**\n     * Calculates the squared length of this Vec3.\n     *\n     * @return - Returns the length.\n     */\n    lengthSquared() {\n        const x = this.x;\n        const y = this.y;\n        const z = this.z;\n        return x * x + y * y + z * z;\n    }\n    /**\n     * Calculates the length of this Vec3.\n     *\n     * @return - Returns the length.\n     */\n    length() {\n        return Math.sqrt(this.lengthSquared());\n    }\n    /**\n     * Calculates the distance to another Vec3.\n     *\n     * @param other - The other Vec3 to calculate the distance to.\n     * @return - Returns the distance between vectors.\n     */\n    distanceTo(other) {\n        const x = this.x - other.x;\n        const y = this.y - other.y;\n        const z = this.z - other.z;\n        return Math.sqrt(x * x + y * y + z * z);\n    }\n    /**\n     * Normalizes the Vec3 and returns it as a new Vec3.\n     * Multiplies coordinates value by the inverse of the vector length.\n     *\n     * @return - Returns the Vec3 normalized.\n     */\n    normalize() {\n        let len = this.x * this.x + this.y * this.y + this.z * this.z;\n        if (len < Number.EPSILON) {\n            return new Vec3();\n        }\n        // TODO: evaluate use of glm_invsqrt here?\n        len = 1.0 / Math.sqrt(len);\n        return new Vec3(this.x * len, this.y * len, this.z * len);\n    }\n    /**\n     * Normalizes this Vec3 multiplying coordinate values by the inverse of the vector length.\n     *\n     * @return - The return value.\n     */\n    normalizeInPlace() {\n        let len = this.x * this.x + this.y * this.y + this.z * this.z;\n        if (len < Number.EPSILON) {\n            return;\n        }\n        len = Math.sqrt(len);\n        const tmp = 1.0 / len;\n        this.x *= tmp;\n        this.y *= tmp;\n        this.z *= tmp;\n        return len;\n    }\n    /**\n     * Creates and returns a new Vec3 with the new coordinates(calculated with this Vec3 coordinates and the specified length).\n     *\n     * @param length - The length value.\n     * @return - The return value.\n     */\n    resize(length) {\n        const currLen = this.x * this.x + this.y * this.y + this.z * this.z;\n        if (currLen < Number.EPSILON) {\n            return;\n        }\n        const scl = length / Math.sqrt(currLen);\n        return new Vec3(this.x * scl, this.y * scl, this.z * scl);\n    }\n    /**\n     * Modifies current coordinates using the specified length.\n     *\n     * @param length - The length value.\n     */\n    resizeInPlace(length) {\n        const currLen = this.x * this.x + this.y * this.y + this.z * this.z;\n        if (currLen < Number.EPSILON) {\n            return;\n        }\n        const scl = length / Math.sqrt(currLen);\n        this.x *= scl;\n        this.y *= scl;\n        this.z *= scl;\n    }\n    /**\n     * Calculates the dot product of this Vec3 against another Vec3.\n     *\n     * @param other - The other Vec3 to compare with.\n     * @return - Returns the dot product.\n     */\n    dot(other) {\n        return this.x * other.x + this.y * other.y + this.z * other.z;\n    }\n    /**\n     * Calculates the cross product of two Vec3s and returns the result as a new Vec3.\n     *\n     * @param other - The other Vec3 to calculate with.\n     * @return - Returns the cross product as a new Vec3.\n     */\n    cross(other) {\n        const ax = this.x;\n        const ay = this.y;\n        const az = this.z;\n        const bx = other.x;\n        const by = other.y;\n        const bz = other.z;\n        return new Vec3(ay * bz - az * by, az * bx - ax * bz, ax * by - ay * bx);\n    }\n    /**\n     * Gets the angle between this Vec3 and b.\n     *\n     * @param other - The other Vec3 to compare with.\n     * @return - Returns the angle in radians.\n     */\n    angleTo(other) {\n        const cosine = this.dot(other);\n        if (cosine > 1.0) {\n            return 0;\n        }\n        else {\n            return Math.acos(cosine);\n        }\n    }\n    /**\n     * Performs a linear interpolation between this Vec3 and other.\n     *\n     * @param other - The other Vec3 to interpolate towards.\n     * @param t - Interpolation ratio.\n     * @return - Returns a new Vec3.\n     */\n    lerp(other, t) {\n        const ax = this.x;\n        const ay = this.y;\n        const az = this.z;\n        return new Vec3(ax + t * (other.x - ax), ay + t * (other.y - ay), az + t * (other.z - az));\n    }\n    /**\n     * Returns a new Vec3 whose component values are the abs of this Vec3s component values.\n     *\n     * @return - Returns a new Vec3.\n     */\n    abs() {\n        return new Vec3(Math.abs(this.x), Math.abs(this.y), Math.abs(this.z));\n    }\n    /**\n     * Sets the vector a random vector on the surface of a sphere with the radius of the given scale value.\n     *\n     * @param scale - The radius of the surface sphere.\n     * @return - The random Vec3.\n     */\n    setRandomDir(scale = 1.0) {\n        const r = Math.random() * 2.0 * Math.PI;\n        const z = Math.random() * 2.0 - 1.0;\n        const zScale = Math.sqrt(1.0 - z * z) * scale;\n        this.x = Math.cos(r) * zScale;\n        this.y = Math.sin(r) * zScale;\n        this.z = z * scale;\n        return this;\n    }\n    /**\n     * Generates a random vector anywhere in the sphere defined by the provided scale value.\n     *\n     * @param scale - The radius of the bounding sphere.\n     * @return - The random Vec3.\n     */\n    setRandom(scale = 1.0) {\n        this.x = (Math.random() - 0.5) * scale;\n        this.y = (Math.random() - 0.5) * scale;\n        this.z = (Math.random() - 0.5) * scale;\n        return this;\n    }\n    /**\n     * Clones this Vec3 and returns a new Vec3.\n     *\n     * @return - Returns a new Vec3.\n     */\n    clone() {\n        return new Vec3(this.x, this.y, this.z);\n    }\n    /**\n     * Returns the type as an array. Often used to pass types to the GPU.\n     *\n     * @return - Returns as an array.\n     */\n    asArray() {\n        return [this.x, this.y, this.z];\n    }\n    /**\n     * Setter from an array.\n     */\n    fromArray(vals) {\n        this.x = vals[0];\n        this.y = vals[1];\n        this.z = vals[1];\n    }\n    // ///////////////////////////\n    // Persistence\n    /**\n     * Converts this Vec3 to a string in JSON format.\n     *\n     * @return - The return value.\n     */\n    toString() {\n        // eslint-disable-next-line new-cap\n        return StringFunctions.stringifyJSONWithFixedPrecision(this.toJSON());\n    }\n    /**\n     * Encodes Vec3 Class as a JSON object for persistence.\n     *\n     * @return - The json object.\n     */\n    toJSON() {\n        return {\n            x: this.x,\n            y: this.y,\n            z: this.z,\n        };\n    }\n    /**\n     * Decodes a JSON object to set the state of this class.\n     *\n     * @param j - The json object.\n     */\n    fromJSON(j) {\n        this.x = j.x;\n        this.y = j.y;\n        this.z = j.z;\n    }\n    /**\n     * Loads the state of the value from a binary reader.\n     *\n     * @param reader - The reader value.\n     */\n    readBinary(reader) {\n        this.x = reader.loadFloat32();\n        this.y = reader.loadFloat32();\n        this.z = reader.loadFloat32();\n    }\n    isValid() {\n        for (const v of this.asArray()) {\n            if (v == Infinity || isNaN(v))\n                return false;\n        }\n        return true;\n    }\n}\n\n/* eslint-disable new-cap */\n/**\n * Represents a four-dimensional coordinate.\n * Math types internally store values in {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float32Array|Float32Array} and\n * expose getters and setters for the component values.\n *\n */\nclass Vec4 {\n    x;\n    y;\n    z;\n    w;\n    /**\n     * Creates a Vec4.\n     *\n     */\n    constructor(x = 0, y = 0, z = 0, w = 0) {\n        this.x = x;\n        this.y = y;\n        this.z = z;\n        this.w = w;\n    }\n    /**\n     * Getter for `xyz` swizzel.\n     *\n     * @return - Returns the z value.\n     */\n    get xyz() {\n        return new Vec3(this.x, this.y, this.z);\n    }\n    /**\n     * Setter from scalar components.\n     *\n     * @param x - The x value.\n     * @param y  - The y value.\n     * @param z  - The y value.\n     * @param w  - The w value.\n     */\n    set(x, y, z, w) {\n        this.x = x;\n        this.y = y;\n        this.z = z;\n        this.w = w;\n    }\n    /**\n     * Sets the state of a Vec4 Object from another Vec4.\n     *\n     * @param other - The other Vec4 to set from.\n     */\n    setFromOther(other) {\n        this.x = other.x;\n        this.y = other.y;\n        this.z = other.z;\n        this.w = other.w;\n    }\n    /**\n     * Checks if this Vec4 contains the same values as the other Vec4.\n     *\n     * @param other - The other Vec4 to compare with.\n     * @return - Returns true or false.\n     */\n    isEqual(other) {\n        return this.x == other.x && this.y == other.y && this.z == other.z && this.w == other.w;\n    }\n    /**\n     * Checks if this Vec4 is different from another Vec4.\n     *\n     * @param other - The other Vec4 to compare with.\n     * @return - Returns true or false.\n     */\n    notEqual(other) {\n        return this.x != other.x && this.y != other.y && this.z != other.z && this.w != other.w;\n    }\n    /**\n     * Returns true if this Vec4 is approximately the same as other.\n     *\n     * @param other - The other Vec4 to compare with.\n     * @param precision - The precision to which the values must match.\n     * @return - The return value.\n     */\n    approxEqual(other, precision = Number.EPSILON) {\n        return (Math.abs(this.x - other.x) < precision &&\n            Math.abs(this.y - other.y) < precision &&\n            Math.abs(this.z - other.z) < precision &&\n            Math.abs(this.w - other.w) < precision);\n    }\n    /**\n     * Adds other to this Vec4 and returns the result as a new Vec4.\n     *\n     * @param other - The other Vec4 to add.\n     * @return - Returns a new Vec4.\n     */\n    add(other) {\n        return new Vec4(this.x + other.x, this.y + other.y, this.z + other.z, this.w + other.w);\n    }\n    /**\n     * Adds other to this Vec4 mutating the values of this instance\n     *\n     * @param other - The other Vec4 to add.\n     */\n    addInPlace(other) {\n        this.x += other.x;\n        this.y += other.y;\n        this.z += other.z;\n        this.w += other.w;\n    }\n    /**\n     * Subtracts other from this Vec4 and returns then result as a new Vec4.\n     *\n     * @param other - The other Vec4 to subtract.\n     * @return - Returns a new Vec4.\n     */\n    subtract(other) {\n        return new Vec4(this.x - other.x, this.y - other.y, this.z - other.z, this.w - other.w);\n    }\n    /**\n     * Subtracts other from this Vec4 mutating the values of this instance\n     *\n     * @param other - The other Vec4 to subtract.\n     */\n    subtractInPlace(other) {\n        this.x -= other.x;\n        this.y -= other.y;\n        this.z -= other.z;\n        this.w -= other.w;\n    }\n    /**\n     * Multiplies two Vec4s and returns the result as a new Vec4.\n     *\n     * @param other - The other Vec4 to multiply with.\n     * @return - Returns a new Vec4.\n     */\n    multiply(other) {\n        return new Vec4(this.x * other.x, this.y * other.y, this.z * other.z, this.w * other.w);\n    }\n    /**\n     * Multiplies two Vec4s mutating the values of this instance\n     *\n     * @param other - The other Vec4 to multiply with.\n     */\n    multiplyInPlace(other) {\n        this.x *= other.x;\n        this.y *= other.y;\n        this.z *= other.z;\n        this.w *= other.w;\n    }\n    /**\n     * Divides two Vec4s and returns the result as a new Vec4.\n     *\n     * @param other - The other Vec4 to divide by.\n     * @return - Returns a new Vec4.\n     */\n    divide(other) {\n        return new Vec4(this.x / other.x, this.y / other.y, this.z / other.z, this.w / other.w);\n    }\n    /**\n     * Divides two Vec4s.\n     *\n     * @param other - The other Vec4 to divide by.\n     */\n    divideInPlace(other) {\n        this.x /= other.x;\n        this.y /= other.y;\n        this.z /= other.z;\n        this.w /= other.w;\n    }\n    /**\n     * Scales this Vec4 by scalar and returns the result as a new Vec4.\n     *\n     * @param scalar - The scalar value.\n     * @return - The return value.\n     */\n    scale(scalar) {\n        return new Vec4(this.x * scalar, this.y * scalar, this.z * scalar, this.w * scalar);\n    }\n    /**\n     * Scales this Vec4 by scalar.\n     *\n     * @param scalar - The scalar value.\n     */\n    scaleInPlace(scalar) {\n        this.set(this.x * scalar, this.y * scalar, this.z * scalar, this.w * scalar);\n    }\n    /**\n     * Calculates the length of this Vec4.\n     *\n     * @return - Returns the length.\n     */\n    length() {\n        const x = this.x;\n        const y = this.y;\n        const z = this.z;\n        const w = this.w;\n        return Math.sqrt(x * x + y * y + z * z + w * w);\n    }\n    /**\n     * Calculates the squared length of this Vec4.\n     *\n     * @return - Returns the length.\n     */\n    lengthSquared() {\n        const x = this.x;\n        const y = this.y;\n        const z = this.z;\n        const w = this.w;\n        return x * x + y * y + z * z + w * w;\n    }\n    /**\n     * Normalizes the Vec4 and returns it as a new Vec4.\n     * Multiplies coordinates value by the inverse of the vector length.\n     *\n     * @return - Returns the Vec4 normalized.\n     */\n    normalize() {\n        const x = this.x;\n        const y = this.y;\n        const z = this.z;\n        const w = this.w;\n        let len = x * x + y * y + z * z + w * w;\n        if (len < Number.EPSILON) {\n            return new Vec4();\n        }\n        // TODO: evaluate use of glm_invsqrt here?\n        len = 1 / Math.sqrt(len);\n        return new Vec4(x * len, y * len, z * len);\n    }\n    /**\n     * Normalizes this Vec4 multiplying coordinate values by the inverse of the vector length.\n     */\n    normalizeInPlace() {\n        const x = this.x;\n        const y = this.y;\n        const z = this.z;\n        const w = this.w;\n        let len = x * x + y * y + z * z + w * w;\n        if (len < Number.EPSILON) {\n            return;\n        }\n        len = 1 / Math.sqrt(len);\n        this.set(x * len, y * len, z * len, w * len);\n    }\n    /**\n     * Calculates the dot product of this Vec4 against another Vec4.\n     *\n     * @param other - The other Vec4 to compare with.\n     * @return - Returns the dot product.\n     */\n    dot(other) {\n        return this.x * other.x + this.y * other.y + this.z * other.z + this.w * other.w; // TODO: other.w used to be b.w?\n    }\n    /**\n     * Calculates the cross product of two Vec4s and returns the result as a new Vec4.\n     *\n     * @param other - The other Vec4 to calculate with.\n     * @return - Returns the cross product as a new Vec4.\n     */\n    cross(other) {\n        const ax = this.x;\n        const ay = this.y;\n        const az = this.z;\n        const at = this.w;\n        const bx = other.x;\n        const by = other.y;\n        const bz = other.z;\n        const bt = other.w;\n        return new Vec4(ay * bz - az * by, az * bt - at * bz, at * bx - ax * bt, ax * by - ay * bx);\n    }\n    /**\n     * Gets the angle between this Vec4 and b.\n     *\n     * @param other - The other Vec4 to compare with.\n     * @return - Returns the angle in radians.\n     */\n    angleTo(other) {\n        const tempA = this.normalize();\n        const tempB = other.normalize();\n        const cosine = tempA.dot(tempB);\n        if (cosine > 1.0) {\n            return 0;\n        }\n        else {\n            return Math.acos(cosine);\n        }\n    }\n    /**\n     * Performs a linear interpolation between this Vec4 and other.\n     *\n     * @param other - The other Vec4 to interpolate between.\n     * @param w - Interpolation amount between the two inputs.\n     * @return - Returns a new Vec4.\n     */\n    lerp(other, t) {\n        const ax = this.x;\n        const ay = this.y;\n        const az = this.z;\n        const at = this.w;\n        return new Vec4(ax + t * (other.x - ax), ay + t * (other.y - ay), az + t * (other.z - az), at + t * (other.w - at));\n    }\n    /**\n     * Generates a random vector with the given scale.\n     *\n     * @param scale - Length of the resulting vector. If omitted, a unit vector will be returned.\n     * @return - The return value.\n     */\n    // random(scale = 1.0) {\n    //   const r = glMatrix.RANDOM() * 2.0 * Math.PI\n    //   const z = glMatrix.RANDOM() * 2.0 - 1.0\n    //   const zScale = Math.sqrt(1.0 - z * z) * scale\n    //   out[0] = Math.cos(r) * zScale\n    //   out[1] = Math.sin(r) * zScale\n    //   out[2] = z * scale\n    //   return out\n    // }\n    /**\n     * Clones this Vec4 and returns a new Vec4.\n     *\n     * @return - Returns a new Vec4.\n     */\n    clone() {\n        return new Vec4(this.x, this.y, this.z, this.w);\n    }\n    /**\n     * Converts this Vec4 into a Vec3.\n     *\n     * @return - Returns the value as a new Vec3.\n     */\n    toVec3() {\n        return new Vec3(this.x, this.y, this.z);\n    }\n    /**\n     * Returns the type as an array. Often used to pass types to the GPU.\n     *\n     * @return - Returns as an array.\n     */\n    asArray() {\n        return [this.x, this.y, this.z, this.w];\n    }\n    /**\n     * Setter from an array.\n     */\n    fromArray(vals) {\n        this.x = vals[0];\n        this.y = vals[1];\n        this.z = vals[1];\n        this.w = vals[1];\n    }\n    // ///////////////////////////\n    // Persistence\n    /**\n     * Converts this Vec3 to a string in JSON format.\n     *\n     * @return - The return value.\n     */\n    toString() {\n        // eslint-disable-next-line new-cap\n        return StringFunctions.stringifyJSONWithFixedPrecision(this.toJSON());\n    }\n    /**\n     * The toJSON method encodes this type as a json object for persistence.\n     * @return - The json object.\n     */\n    toJSON() {\n        return {\n            x: this.x,\n            y: this.y,\n            z: this.z,\n            w: this.w,\n        };\n    }\n    /**\n     * Decodes a JSON object to set the state of this class.\n     *\n     * @param j - The json object.\n     */\n    fromJSON(j) {\n        this.x = j.x;\n        this.y = j.y;\n        this.z = j.z;\n        this.w = j.w;\n    }\n    /**\n     * Loads the state of the value from a binary reader.\n     *\n     * @param reader - The reader value.\n     */\n    readBinary(reader) {\n        this.x = reader.loadFloat32();\n        this.y = reader.loadFloat32();\n        this.z = reader.loadFloat32();\n        this.w = reader.loadFloat32();\n    }\n    /**\n     * Verifies if the values stored in this Math type are valid numeric values.\n     * Returns `false` If at least one of the values is either {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Referencia/Objetos_globales/Infinity|Infinity} or\n     * {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Referencia/Objetos_globales/NaN|NaN}.\n     *\n     * @return - Returns the result as a boolean.\n     */\n    isValid() {\n        for (const v of this.asArray()) {\n            if (v == Infinity || isNaN(v))\n                return false;\n        }\n        return true;\n    }\n}\n\n/* eslint-disable require-jsdoc */\n/**\n * Class representing the red, green, blue and alpha channel of a color as 8bit values.\n *\n */\nclass RGBA {\n    r = 0;\n    g = 0;\n    b = 0;\n    a = 255;\n    /**\n     * Create a RGBA.\n     * @param r - The red channel of a color.\n     * @param g - The green channel of a color.\n     * @param b - The blue channel of a color.\n     * @param a - The alpha (transparency) channel of a color.\n     */\n    constructor(r = 0, g = 0, b = 0, a = 255) {\n        if (typeof r == 'string') {\n            if (r.startsWith('#')) {\n                this.setFromHex(r);\n            }\n            else {\n                this.setFromCSSColorName(r);\n            }\n        }\n        else {\n            this.r = r;\n            this.g = g;\n            this.b = b;\n            this.a = a;\n        }\n    }\n    /**\n     * Setter from scalar components.\n     *\n     * @param r - The red channel.\n     * @param g  - The green channel.\n     * @param b  - The blue channel.\n     * @param a  - The alpha channel.\n     */\n    set(r, g, b, a = 255) {\n        this.r = r;\n        this.g = g;\n        this.b = b;\n        this.a = a;\n    }\n    /**\n     * Setter from another RGBA color.\n     *\n     * @param other - The other RGBA to set from.\n     */\n    setFromOther(other) {\n        this.r = other.r;\n        this.g = other.g;\n        this.b = other.b;\n        this.a = other.a;\n    }\n    /**\n     * Setter from a scalar array.\n     *\n     * @param values - The array of values.\n     */\n    setFromArray(values) {\n        this.r = values[0];\n        this.g = values[1];\n        this.b = values[2];\n        this.a = values.length == 4 ? values[3] : 1.0;\n    }\n    /**\n     * Setter from a hexadecimal value.\n     * E.g. #ff0000\n     *\n     * @param hex - The hex value.\n     */\n    setFromHex(hex) {\n        function hexToRgb(hex) {\n            const result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex);\n            return result\n                ? {\n                    r: parseInt(result[1], 16),\n                    g: parseInt(result[2], 16),\n                    b: parseInt(result[3], 16),\n                }\n                : null;\n        }\n        const rgb = hexToRgb(hex);\n        if (!rgb) {\n            console.warn('Invalid hex code:' + hex);\n            return;\n        }\n        this.set(rgb.r, rgb.g, rgb.b);\n    }\n    /**\n     * Setter from a CSS color name.\n     * E.g. \"red\"\n     *\n     * @param name - The CSS color name.\n     */\n    setFromCSSColorName(name) {\n        const colourNameToHex = (colour) => {\n            const colors = {\n                aliceblue: '#f0f8ff',\n                antiquewhite: '#faebd7',\n                aqua: '#00ffff',\n                aquamarine: '#7fffd4',\n                azure: '#f0ffff',\n                beige: '#f5f5dc',\n                bisque: '#ffe4c4',\n                black: '#000000',\n                blanchedalmond: '#ffebcd',\n                blue: '#0000ff',\n                blueviolet: '#8a2be2',\n                brown: '#a52a2a',\n                burlywood: '#deb887',\n                cadetblue: '#5f9ea0',\n                chartreuse: '#7fff00',\n                chocolate: '#d2691e',\n                coral: '#ff7f50',\n                cornflowerblue: '#6495ed',\n                cornsilk: '#fff8dc',\n                crimson: '#dc143c',\n                cyan: '#00ffff',\n                darkblue: '#00008b',\n                darkcyan: '#008b8b',\n                darkgoldenrod: '#b8860b',\n                darkgray: '#a9a9a9',\n                darkgreen: '#006400',\n                darkkhaki: '#bdb76b',\n                darkmagenta: '#8b008b',\n                darkolivegreen: '#556b2f',\n                darkorange: '#ff8c00',\n                darkorchid: '#9932cc',\n                darkred: '#8b0000',\n                darksalmon: '#e9967a',\n                darkseagreen: '#8fbc8f',\n                darkslateblue: '#483d8b',\n                darkslategray: '#2f4f4f',\n                darkturquoise: '#00ced1',\n                darkviolet: '#9400d3',\n                deeppink: '#ff1493',\n                deepskyblue: '#00bfff',\n                dimgray: '#696969',\n                dodgerblue: '#1e90ff',\n                firebrick: '#b22222',\n                floralwhite: '#fffaf0',\n                forestgreen: '#228b22',\n                fuchsia: '#ff00ff',\n                gainsboro: '#dcdcdc',\n                ghostwhite: '#f8f8ff',\n                gold: '#ffd700',\n                goldenrod: '#daa520',\n                gray: '#808080',\n                green: '#008000',\n                greenyellow: '#adff2f',\n                honeydew: '#f0fff0',\n                hotpink: '#ff69b4',\n                'indianred ': '#cd5c5c',\n                indigo: '#4b0082',\n                ivory: '#fffff0',\n                khaki: '#f0e68c',\n                lavender: '#e6e6fa',\n                lavenderblush: '#fff0f5',\n                lawngreen: '#7cfc00',\n                lemonchiffon: '#fffacd',\n                lightblue: '#add8e6',\n                lightcoral: '#f08080',\n                lightcyan: '#e0ffff',\n                lightgoldenrodyellow: '#fafad2',\n                lightgrey: '#d3d3d3',\n                lightgreen: '#90ee90',\n                lightpink: '#ffb6c1',\n                lightsalmon: '#ffa07a',\n                lightseagreen: '#20b2aa',\n                lightskyblue: '#87cefa',\n                lightslategray: '#778899',\n                lightsteelblue: '#b0c4de',\n                lightyellow: '#ffffe0',\n                lime: '#00ff00',\n                limegreen: '#32cd32',\n                linen: '#faf0e6',\n                magenta: '#ff00ff',\n                maroon: '#800000',\n                mediumaquamarine: '#66cdaa',\n                mediumblue: '#0000cd',\n                mediumorchid: '#ba55d3',\n                mediumpurple: '#9370d8',\n                mediumseagreen: '#3cb371',\n                mediumslateblue: '#7b68ee',\n                mediumspringgreen: '#00fa9a',\n                mediumturquoise: '#48d1cc',\n                mediumvioletred: '#c71585',\n                midnightblue: '#191970',\n                mintcream: '#f5fffa',\n                mistyrose: '#ffe4e1',\n                moccasin: '#ffe4b5',\n                navajowhite: '#ffdead',\n                navy: '#000080',\n                oldlace: '#fdf5e6',\n                olive: '#808000',\n                olivedrab: '#6b8e23',\n                orange: '#ffa500',\n                orangered: '#ff4500',\n                orchid: '#da70d6',\n                palegoldenrod: '#eee8aa',\n                palegreen: '#98fb98',\n                paleturquoise: '#afeeee',\n                palevioletred: '#d87093',\n                papayawhip: '#ffefd5',\n                peachpuff: '#ffdab9',\n                peru: '#cd853f',\n                pink: '#ffc0cb',\n                plum: '#dda0dd',\n                powderblue: '#b0e0e6',\n                purple: '#800080',\n                rebeccapurple: '#663399',\n                red: '#ff0000',\n                rosybrown: '#bc8f8f',\n                royalblue: '#4169e1',\n                saddlebrown: '#8b4513',\n                salmon: '#fa8072',\n                sandybrown: '#f4a460',\n                seagreen: '#2e8b57',\n                seashell: '#fff5ee',\n                sienna: '#a0522d',\n                silver: '#c0c0c0',\n                skyblue: '#87ceeb',\n                slateblue: '#6a5acd',\n                slategray: '#708090',\n                snow: '#fffafa',\n                springgreen: '#00ff7f',\n                steelblue: '#4682b4',\n                tan: '#d2b48c',\n                teal: '#008080',\n                thistle: '#d8bfd8',\n                tomato: '#ff6347',\n                turquoise: '#40e0d0',\n                violet: '#ee82ee',\n                wheat: '#f5deb3',\n                white: '#ffffff',\n                whitesmoke: '#f5f5f5',\n                yellow: '#ffff00',\n                yellowgreen: '#9acd32',\n            };\n            return colors[colour.toLowerCase()];\n        };\n        if (name.startsWith('#')) {\n            this.setFromHex(name);\n        }\n        else {\n            const hexColor = colourNameToHex(name);\n            if (hexColor)\n                this.setFromHex(hexColor);\n        }\n    }\n    /**\n     * Returns the hexadecimal value of this RGBA color.\n     *\n     * @return - Returns the hex value.\n     */\n    toHex() {\n        function componentToHex(int) {\n            const hex = int.toString(16);\n            return hex.length == 1 ? '0' + hex : hex;\n        }\n        return '#' + componentToHex(this.r) + componentToHex(this.g) + componentToHex(this.b);\n    }\n    /**\n     * Returns true if this RGBA color is exactly the same as other.\n     *\n     * @param other - The other RGBA to compare with.\n     * @return - Returns true or false.\n     */\n    equal(other) {\n        return this.r == other.r && this.g == other.g && this.b == other.b && this.a == other.a;\n    }\n    /**\n     * Returns true if this RGBA color is NOT exactly the same as other.\n     *\n     * @param other -  The other RGBA to compare with.\n     * @return - Returns true or false.\n     */\n    notEquals(other) {\n        return this.r != other.r && this.g != other.g && this.b != other.b && this.a != other.a;\n    }\n    /**\n     * Returns true if this RGBA color is approximately the same as other.\n     *\n     * @param other - The other RGBA to compare with.\n     * @param precision - The precision to which the values must match.\n     * @return - Returns true or false.\n     */\n    approxEqual(other, precision = Number.EPSILON) {\n        return (Math.abs(this.r - other.r) < precision &&\n            Math.abs(this.g - other.g) < precision &&\n            Math.abs(this.b - other.b) < precision &&\n            Math.abs(this.a - other.a) < precision);\n    }\n    /**\n     * Returns a new RGBA color which is this RGBA color added to other.\n     *\n     * @param other - The other RGBA to add.\n     * @return - Returns a new RGBA.\n     */\n    add(other) {\n        return new RGBA(this.r + other.r, this.g + other.g, this.b + other.b, this.a + other.a);\n    }\n    /**\n     * Returns a new RGBA color which is this RGBA color subtracted from other.\n     *\n     * @param other - The other RGBA to subtract.\n     * @return - Returns a new RGBA.\n     */\n    subtract(other) {\n        return new RGBA(this.r - other.r, this.g - other.g, this.b - other.b, this.a - other.a);\n    }\n    /**\n     * Returns a new RGBA color which is this vector scaled by scalar.\n     *\n     * @param scalar - The scalar value.\n     * @return - Returns a new RGBA.\n     */\n    scale(scalar) {\n        return new RGBA(this.r * scalar, this.g * scalar, this.b * scalar, this.a * scalar);\n    }\n    /**\n     * Scales this RGBA color by scalar.\n     *\n     * @param scalar - The scalar value.\n     */\n    scaleInPlace(scalar) {\n        this.r *= scalar;\n        this.g *= scalar;\n        this.b *= scalar;\n        this.a *= scalar;\n    }\n    /**\n     * Apply gamma correction to this RGBA color.\n     *\n     * @param gamma - The gamma value.\n     */\n    applyGamma(gamma) {\n        this.set(Math.pow(this.r, gamma), Math.pow(this.g, gamma), Math.pow(this.b, gamma), this.a);\n    }\n    /**\n     * Converts to linear color space and returns a new color.\n     * @param gamma - The gamma value.\n     * @return - Returns a new RGBA.\n     */\n    toLinear(gamma = 2.2) {\n        return new RGBA(Math.pow(this.r, gamma), Math.pow(this.g, gamma), Math.pow(this.b, gamma), this.a);\n    }\n    /**\n     * Converts to gamma color space and returns a new RGBA color.\n     *\n     * @param gamma - The gamma value.\n     * @return - Returns a new RGBA.\n     */\n    toGamma(gamma = 2.2) {\n        return new RGBA(Math.pow(this.r, 1.0 / gamma), Math.pow(this.g, 1.0 / gamma), Math.pow(this.b, 1.0 / gamma), this.a);\n    }\n    /**\n     * Calculates and returns the relative luminance of the linear RGB component.\n     *\n     * @return - The return value.\n     */\n    luminance() {\n        return 0.2126 * this.r + 0.7152 * this.g + 0.0722 * this.b;\n    }\n    /**\n     * Performs a linear interpolation between this RGBA color and other.\n     *\n     * @param other - The other RGBA to interpolate between.\n     * @param t - Interpolation amount between the two inputs.\n     * @return - Returns a new RGBA.\n     */\n    lerp(other, t) {\n        const ar = this.r;\n        const ag = this.g;\n        const ab = this.b;\n        const aa = this.a;\n        return new RGBA(ar + t * (other.r - ar), ag + t * (other.g - ag), ab + t * (other.b - ab), aa + t * (other.a - aa));\n    }\n    /**\n     * Creates a random RGBA.\n     *\n     * @param gammaOffset - The gamma offset.\n     * @param randomAlpha - Determines whether the alpha channel is random.\n     * @return - Returns a new random RGBA.\n     */\n    static random(gammaOffset = 0.0, randomAlpha = false) {\n        if (gammaOffset > 0.0) {\n            return new RGBA(gammaOffset + Math.random() * (1.0 - gammaOffset), gammaOffset + Math.random() * (1.0 - gammaOffset), gammaOffset + Math.random() * (1.0 - gammaOffset), randomAlpha ? gammaOffset + Math.random() * (1.0 - gammaOffset) : 1.0);\n        }\n        else if (gammaOffset < 0.0) {\n            return new RGBA(Math.random() * (1.0 + gammaOffset), Math.random() * (1.0 + gammaOffset), Math.random() * (1.0 + gammaOffset), randomAlpha ? Math.random() * (1.0 + gammaOffset) : 1.0);\n        }\n        else {\n            return new RGBA(Math.random(), Math.random(), Math.random(), randomAlpha ? Math.random() : 1.0);\n        }\n    }\n    /**\n     * Clones this RGBA color and returns a new RGBA color.\n     *\n     * @return - Returns a new RGBA.\n     */\n    clone() {\n        return new RGBA(this.r, this.g, this.b, this.a);\n    }\n    /**\n     * Returns the type as an array. Often used to pass types to the GPU.\n     *\n     * @return - Returns as an array.\n     */\n    asArray() {\n        return [this.r, this.g, this.b, this.a];\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * The toJSON method encodes this type as a json object for persistence.\n     *\n     * @return - The json object.\n     */\n    toJSON() {\n        return {\n            r: this.r,\n            g: this.g,\n            b: this.b,\n            a: this.a,\n        };\n    }\n    /**\n     * The fromJSON method decodes a json object for this type.\n     *\n     * @param j - The json object.\n     */\n    fromJSON(j) {\n        this.r = j.r;\n        this.g = j.g;\n        this.b = j.b;\n        this.a = j.a;\n    }\n    /**\n     * Returns the CSS rgba string.\n     *\n     * @return - The return value.\n     */\n    toCSSString() {\n        return ('rgba(' +\n            Math.round(this.r * 255) +\n            ', ' +\n            Math.round(this.g * 255) +\n            ', ' +\n            Math.round(this.b * 255) +\n            ', ' +\n            this.a +\n            ')');\n    }\n}\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\nlet counter = 0;\n/**\n * Class representing a BaseClass.\n * The BaseClass is the foundation class of the SceneTree, as almost all classes derive from it.\n */\nclass BaseClass {\n    __id;\n    /**\n     * Create an BaseClass.\n     */\n    constructor() {\n        this.__id = ++counter;\n    }\n    /**\n     * Every instance of each class based on BaseClass is assigned a unique number.\n     * This number is not persistent in between different loads of a scene.\n     * Returns the unique id of the object.\n     * @return - The Id of the object.\n     */\n    getId() {\n        return this.__id;\n    }\n    /**\n     * Returns the unmangled name of the class.\n     * @return - The name of the class definition.\n     */\n    getClassName() {\n        return Registry.getClassName(Object.getPrototypeOf(this).constructor);\n    }\n}\n\n/** Class representing a BaseEvent. */\nclass BaseEvent {\n    /**\n     * Create an BaseEvent.\n     */\n    constructor() { }\n}\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/**\n * Provides an interface for emitting events under given names, and registering listeners to those events.\n * This is a base class for most classes in the Scene Tree and Renderer, enabling observers to listen to changes throughout the system.\n * The interface exposed is similar to [EventEmitter](https://nodejs.org/api/events.html#events_class_eventemitter) in Node.\n *\n * Similar to how the DOM event system in the browser works, events are registered by name.\n * Example: Registering a listener for a custom event, and then emitting that event.\n * ```javascript\n *  const ee = new EventEmitter()\n *\n *  const eventID = ee.on('myEvent', (event) => {\n *    console.log('My Event was emitted:', event)\n *  })\n *\n *  ee.emit('myEvent', { data: 42 })\n *  // We no longer want to listen to this event, so let's remove the listener.\n *  ee.off('myEvent', eventID)\n * ```\n *\n *\n */\nclass EventEmitter extends BaseClass {\n    listeners = {};\n    /**\n     * Initializes an empty `listeners` map that will host all the events,\n     * which implies that it doesn't allow multiple events with the same name.\n     *\n     */\n    constructor() {\n        super();\n    }\n    /**\n     * Adds a listener function for a given event name.\n     *\n     * @param eventName - The name of the event.\n     * @param listener - The listener function(callback).\n     * @return - the id that can be used to remove the listener.\n     */\n    on(eventName, listener) {\n        if (!listener) {\n            throw new Error('Missing listener.');\n        }\n        if (!this.listeners[eventName]) {\n            this.listeners[eventName] = [];\n        }\n        const listeners = this.listeners[eventName];\n        if (listeners.includes(listener)) {\n            throw new Error(`Listener \"${listener.name}\" already connected to event \"${eventName}\".`);\n        }\n        // TODO: Deprecate alongside #addListener.\n        const id = listeners.length;\n        listeners[id] = listener;\n        return id;\n    }\n    /**\n     * Similar to the `on` method with the difference that when the event is triggered,\n     * it is automatically unregistered meaning that the event listener will be triggered at most one time.\n     *\n     * Useful for events that we expect to trigger one time, such as when assets load.\n     * ```javascript\n     * const asset = new Asset();\n     * asset.once('loaded', () => {\n     *   console.log(\"Yay! the asset is loaded\")\n     * })\n     * ```\n     *\n     * @param eventName - The eventName value\n     * @param listener - The listener value\n     * @return - the id that can be used to remove the listener.\n     */\n    once(eventName, listener) {\n        const cb = (event) => {\n            this.off(eventName, cb);\n            listener(event);\n        };\n        return this.on(eventName, cb);\n    }\n    /**\n     * Removes a listener from the specified event, using either the function or the index id. Depends on what is passed in.\n     *\n     * @param eventName - The name of the event.\n     * @param listenerOrId - The listener function or the id number returned by 'on'.\n     */\n    off(eventName, listenerOrId) {\n        if (listenerOrId == undefined) {\n            throw new Error('Missing callback function (listener).');\n        }\n        const listeners = this.listeners[eventName] || [];\n        if (typeof listenerOrId == 'number') {\n            const id = listenerOrId;\n            // Note: do not splice the array as that would change the indexes of existing listeners.\n            listeners[id] = null;\n            return;\n        }\n        const listener = listenerOrId;\n        listeners.forEach((e, i) => {\n            if (e === listener) {\n                // Note: do not splice the array as that would change the indexes of existing listeners.\n                listeners[i] = null;\n            }\n        });\n    }\n    /**\n     * remove listener by ID returned from #on\n     *\n     * @param eventName - The name of the event.\n     * @param id - The id returned by addListener\n     */\n    removeListenerById(eventName, id) {\n        this.off(eventName, id);\n    }\n    /**\n     * Triggers all listener functions in an event.\n     *\n     * @param eventName - The name of the event.\n     * @param event - The data you want to pass down to all listener functions as parameter.\n     *\n     */\n    emit(eventName, event = new BaseEvent()) {\n        const listeners = this.listeners[eventName] || [];\n        listeners.forEach((fn) => {\n            // Skip disconnected listeners.\n            if (fn) {\n                try {\n                    fn(event);\n                }\n                catch (e) {\n                    console.warn(e);\n                }\n            }\n        });\n    }\n}\n\nclass ResizedEvent extends BaseEvent {\n    width;\n    height;\n    constructor(newWidth, newHeight) {\n        super();\n        this.width = newWidth;\n        this.height = newHeight;\n    }\n}\n\n// Taken from here: https://github.com/jakesgordon/bin-packing/blob/master/js/packer.growing.js\nclass GrowingPacker extends EventEmitter {\n    root;\n    freeNodes = [];\n    constructor(w = 0, h = 0) {\n        super();\n        this.root = {\n            x: 0,\n            y: 0,\n            w: w,\n            h: h,\n            a: w * h,\n        };\n        this.freeNodes.push(this.root);\n    }\n    fit(blocks) {\n        const len = blocks.length;\n        if (len == 0)\n            return;\n        let resized = false;\n        if (this.root.w < blocks[0].w) {\n            this.root.w = blocks[0].w;\n            resized = true;\n        }\n        if (this.root.h < blocks[0].h) {\n            this.root.h = blocks[0].h;\n            resized = true;\n        }\n        if (resized) {\n            const event = new ResizedEvent(this.root.w, this.root.h);\n            this.emit('resized', event);\n        }\n        blocks.forEach((block) => {\n            block.fit = this.__addBlock(block);\n        });\n    }\n    __addBlock(block) {\n        const node = this.findNode(block.w, block.h);\n        if (node)\n            return this.splitNode(node, block.w, block.h);\n        else\n            return this.growNode(block.w, block.h);\n    }\n    addBlock(block) {\n        let resized = false;\n        if (this.root.w < block.w) {\n            this.root.w = block.w;\n            resized = true;\n        }\n        if (this.root.h < block.h) {\n            this.root.h = block.h;\n            resized = true;\n        }\n        if (resized) {\n            const event = new ResizedEvent(this.root.w, this.root.h);\n            this.emit('resized', event);\n        }\n        const node = this.findNode(block.w, block.h);\n        if (node)\n            return this.splitNode(node, block.w, block.h);\n        else\n            return this.growNode(block.w, block.h);\n    }\n    findNode(w, h) {\n        const index = this.freeNodes.findIndex((node) => w <= node.w && h <= node.h);\n        if (index >= 0)\n            return this.freeNodes.splice(index, 1)[0];\n        else\n            return null;\n    }\n    splitNode(node, w, h) {\n        node.used = true;\n        // Split the node along the shorter axis, i.e. split horizontally if\n        // the node is wider than it is tall, and vice versa.\n        if (node.w - w < node.h - h) {\n            if (node.h - h > 0) {\n                node.down = {\n                    x: node.x,\n                    y: node.y + h,\n                    w: node.w,\n                    h: node.h - h,\n                    a: node.w * (node.h - h),\n                };\n                this.freeNodes.push(node.down);\n            }\n            if (node.w - w > 0) {\n                node.right = {\n                    x: node.x + w,\n                    y: node.y,\n                    w: node.w - w,\n                    h: h,\n                    a: (node.w - w) * h,\n                };\n                this.freeNodes.push(node.right);\n            }\n        }\n        else {\n            if (node.w - w > 0) {\n                node.right = {\n                    x: node.x + w,\n                    y: node.y,\n                    w: node.w - w,\n                    h: node.h,\n                    a: (node.w - w) * node.h,\n                };\n                this.freeNodes.push(node.right);\n            }\n            if (node.h - h > 0) {\n                node.down = {\n                    x: node.x,\n                    y: node.y + h,\n                    w: w,\n                    h: node.h - h,\n                    a: w * (node.h - h),\n                };\n                this.freeNodes.push(node.down);\n            }\n        }\n        this.freeNodes.sort((a, b) => a.a - b.a);\n        return node;\n    }\n    growNode(w, h) {\n        const canGrowDown = w <= this.root.w;\n        const canGrowRight = h <= this.root.h;\n        const shouldGrowRight = canGrowRight && this.root.h >= this.root.w + w; // attempt to keep square-ish by growing right when height is much greater than width\n        const shouldGrowDown = canGrowDown && this.root.w >= this.root.h + h; // attempt to keep square-ish by growing down  when width  is much greater than height\n        if (shouldGrowRight)\n            return this.growRight(w, h);\n        else if (shouldGrowDown)\n            return this.growDown(w, h);\n        else if (canGrowRight)\n            return this.growRight(w, h);\n        else if (canGrowDown)\n            return this.growDown(w, h);\n        else\n            return null; // need to ensure sensible root starting size to avoid this happening\n    }\n    growRight(w, h) {\n        this.root = {\n            used: true,\n            x: 0,\n            y: 0,\n            w: this.root.w + w,\n            h: this.root.h,\n            a: (this.root.w + w) * this.root.h,\n            down: this.root,\n            right: {\n                x: this.root.w,\n                y: 0,\n                w: w,\n                h: this.root.h,\n                a: w * this.root.h,\n            },\n        };\n        this.freeNodes.push(this.root.right);\n        this.freeNodes.sort((a, b) => a.a - b.a);\n        const node = this.findNode(w, h);\n        let res;\n        if (node)\n            res = this.splitNode(node, w, h);\n        const event = new ResizedEvent(this.root.w, this.root.h);\n        this.emit('resized', event);\n        return res;\n    }\n    growDown(w, h) {\n        this.root = {\n            used: true,\n            x: 0,\n            y: 0,\n            w: this.root.w,\n            h: this.root.h + h,\n            a: this.root.w * (this.root.h + h),\n            down: {\n                x: 0,\n                y: this.root.h,\n                w: this.root.w,\n                h: h,\n                a: this.root.w * h,\n            },\n            right: this.root,\n        };\n        this.freeNodes.push(this.root.down);\n        this.freeNodes.sort((a, b) => a.a - b.a);\n        const node = this.findNode(w, h);\n        let res;\n        if (node)\n            res = this.splitNode(node, w, h);\n        const event = new ResizedEvent(this.root.w, this.root.h);\n        this.emit('resized', event);\n        return res;\n    }\n}\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable @typescript-eslint/explicit-module-boundary-types */\nconst UInt8 = 0;\nconst SInt8 = 1;\nconst UInt16 = 2;\nconst SInt16 = 3;\nconst UInt32 = 4;\nconst SInt32 = 5;\nconst Float32 = 6;\n/**\n * Math Functions\n */\nclass MathFunctions {\n    /**\n     * Converts Radians to Degrees\n     *\n     * @static\n     * @param rad - Radians value\n     * @return - Degrees equivalent\n     */\n    static radToDeg(rad) {\n        return rad / (Math.PI / 180);\n    }\n    /**\n     * Converts Degrees to Radiants\n     *\n     * @static\n     * @param deg - Degrees value\n     * @return -  Radians equivalent\n     */\n    static degToRad(deg) {\n        return deg * (Math.PI / 180);\n    }\n    /**\n     * Verifies if the specified parameter is numeric.\n     *\n     * @static\n     * @param number - Number to test\n     * @return - `true` when is a valid number\n     */\n    static isNumeric(number) {\n        return !isNaN(parseFloat(number)) && isFinite(number);\n    }\n    /**\n     * Generates and returns a random integer within the specified range.\n     *\n     * @static\n     * @param min - Lower value random int can be.\n     * @param max - Highest value random int can be.\n     * @return - Random number inside range.\n     */\n    static randomInt(min, max) {\n        min = Math.ceil(min);\n        max = Math.floor(max);\n        return Math.floor(Math.random() * (max - min)) + min;\n    }\n    /**\n     * Calculates a lineal interpolation between two inputs for the specified parameter(t).\n     *\n     * @static\n     * @param v0 -\n     * @param v1 -\n     * @param t -\n     * @return -\n     */\n    static lerp(v0, v1, t) {\n        return v0 + t * (v1 - v0);\n    }\n    /**\n     * Restricts the specified value between two numbers\n     *\n     * @static\n     * @param value\n     * @param min\n     * @param max\n     * @return\n     */\n    static clamp(value, min, max) {\n        return Math.min(Math.max(value, min), max);\n    }\n    /**\n     * Returns the nearest pow of two value of the specified number.\n     *\n     * @static\n     * @param value -\n     * @return -\n     */\n    static nearestPow2(value) {\n        return Math.pow(2, Math.round(Math.log(value) / Math.log(2)));\n    }\n    /**\n     * Returns the nearest pow of ten value of the specified number.\n     *\n     * @static\n     * @param value -\n     * @return -\n     */\n    static nearestPow10(value) {\n        return Math.pow(10, Math.round(Math.log10(value) / Math.log10(10)));\n    }\n    /**\n     * Returns the next pow of two value of the specified number.\n     *\n     * @static\n     * @param value -\n     * @return -\n     */\n    static nextPow2(value) {\n        if (this.fract(Math.log2(value)) == 0) {\n            return value;\n        }\n        let exp = 0;\n        while (value > 0) {\n            exp++;\n            value = value >> 1;\n        }\n        return 1 << exp;\n    }\n    /**\n     * Returns the fractional component of a number\n     *\n     * @static\n     * @param value -\n     * @return -\n     */\n    static fract(value) {\n        if (value == 0)\n            return 0;\n        if (value < 0) {\n            if (value > -1.0)\n                return -value;\n            return -value % Math.floor(-value);\n        }\n        if (value < 1.0)\n            return value;\n        return value % Math.floor(value);\n    }\n    /**\n     * Moves the specified value from one numeric domain(range) to another.\n     *\n     * @static\n     * @param value -\n     * @param start1 -\n     * @param end1 -\n     * @param start2 -\n     * @param end2 -\n     * @return -\n     */\n    static remap(value, start1, end1, start2, end2) {\n        return start2 + (end2 - start2) * ((value - start1) / (end1 - start1));\n    }\n    /**\n     * Perform Hermite interpolation between two values\n     *\n     * @static\n     * @param edge0 -\n     * @param edge1 -\n     * @param x -\n     * @return -\n     */\n    static smoothStep(edge0, edge1, x) {\n        const t = this.clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);\n        return t * t * (3.0 - 2.0 * t);\n    }\n    /**\n     * Performs - interpolation between two values\n     *\n     * @static\n     * @param edge0 -\n     * @param edge1 -\n     * @param x -\n     * @return -\n     */\n    static linStep(edge0, edge1, x) {\n        return this.clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);\n    }\n    /**\n     * Decodes a Float16 from two unsigned Int8\n     *\n     * @static\n     * @param c - Array with the two UInt8\n     * @return - Decoded Float16\n     */\n    static decode16BitFloatFrom2xUInt8(c) {\n        const ix = c[0]; // 1st byte: 1 bit signed num, 4 bits exponent, 3 bits mantissa (MSB)\n        const iy = c[1]; // 2nd byte: 8 bit mantissa (LSB)\n        const s = ix & 0x80 ? 1 : -1; // get bit 8\n        const iexp = (ix & 0x78) >> 3; // mask bits 7-4\n        const msb = ix & 0x7; // mask bits 3-1\n        let norm = iexp == 0 ? 0 : 2048; // distinguish between normalized and sub-normalized numbers\n        const mantissa = norm + (msb << 8) + iy; // implicit preceding 1 or 0 added here\n        norm = iexp == 0 ? 1 : 0; // normalization toggle\n        const exponent = Math.pow(2, iexp + norm - 16); // -5 for the the exponent bias from 2^-5 to 2^10 plus another -11 for the normalized 12 bit mantissa\n        const v = s * mantissa * exponent;\n        return v;\n    }\n    /**\n     * Encodes an array of two unsigned Int8 to a Float16\n     *\n     * @static\n     * @param v - Float16 number\n     * @return - Encoded Unsigned Int8 array\n     */\n    static encode16BitFloatInto2xUInt8(v) {\n        const c = new Uint8Array(2);\n        // const c = [0, 0];\n        const signum = v >= 0 ? 128 : 0;\n        v = Math.abs(v);\n        let exponent = 15;\n        let limit = 1024; // considering the bias from 2^-5 to 2^10 (==1024)\n        for (let exp = 15; exp > 0; exp--) {\n            if (v < limit) {\n                limit /= 2;\n                exponent--;\n            }\n        }\n        let rest;\n        if (exponent == 0) {\n            rest = v / limit / 2; // \"sub-normalize\" implicit preceding 0.\n        }\n        else {\n            rest = (v - limit) / limit; // normalize accordingly to implicit preceding 1.\n        }\n        const mantissa = Math.round(rest * 2048); // 2048 = 2^11 for the (split) 11 bit mantissa\n        const msb = mantissa / 256; // the most significant 3 bits go into the lower part of the first byte\n        const lsb = mantissa - msb * 256; // there go the other 8 bit of the lower significance\n        c[0] = signum + exponent * 8 + msb; // color normalization for texture2D\n        c[1] = lsb;\n        if (v >= 2048) {\n            c[0] = 255;\n        }\n        return c;\n    }\n    /**\n     * Transforms a 16 bit float to an encoded integer.\n     *\n     * @static\n     * @param v - Float16 number to encode\n     * @return - Encoded number\n     */\n    static encode16BitFloat(v) {\n        const float32Array = new Float32Array(1);\n        float32Array[0] = v;\n        const int32View = new Int32Array(float32Array.buffer);\n        const toUInt16 = (x) => {\n            let bits = (x >> 16) & 0x8000; /* Get the sign */\n            let m = (x >> 12) & 0x07ff; /* Keep one extra bit for rounding */\n            const e = (x >> 23) & 0xff; /* Using int is faster here */\n            /* If zero, or de-normal, or exponent underflows too much for a de-normal\n             * half, return signed zero. */\n            if (e < 103) {\n                return bits;\n            }\n            /* If NaN, return NaN. If Inf or exponent overflow, return Inf. */\n            if (e > 142) {\n                bits |= 0x7c00;\n                /* If exponent was 0xff and one mantissa bit was set, it means NaN,\n                 * not Inf, so make sure we set one mantissa bit too. */\n                bits |= (e == 255 ? 0 : 1) && x & 0x007fffff;\n                return bits;\n            }\n            /* If exponent underflows but not too much, return a de-normal */\n            if (e < 113) {\n                m |= 0x0800;\n                /* Extra rounding may overflow and set mantissa to 0 and exponent\n                 * to 1, which is OK. */\n                bits |= (m >> (114 - e)) + ((m >> (113 - e)) & 1);\n                return bits;\n            }\n            bits |= ((e - 112) << 10) | (m >> 1);\n            /* Extra rounding. An overflow will set mantissa to 0 and increment\n             * the exponent, which is OK. */\n            bits += m & 1;\n            return bits;\n        };\n        return toUInt16(int32View[0]);\n    }\n    /**\n     * As opposite of the `encode16BitFloat` method, this takes an encoded integer value,\n     * and returns the 16 bit float.\n     *\n     * @static\n     * @param h - Encoded integer\n     * @return - Decoded 16 bit float.\n     */\n    static decode16BitFloat(h) {\n        const s = (h & 0x8000) >> 15;\n        const e = (h & 0x7c00) >> 10;\n        const f = h & 0x03ff;\n        if (e == 0) {\n            return (s ? -1 : 1) * Math.pow(2, -14) * (f / Math.pow(2, 10));\n        }\n        else if (e == 0x1f) {\n            return f ? NaN : (s ? -1 : 1) * Infinity;\n        }\n        return (s ? -1 : 1) * Math.pow(2, e - 15) * (1 + f / Math.pow(2, 10));\n    }\n    /**\n     * Transforms an array of Float 32 to an array of unsigned Int16.\n     *\n     * @static\n     * @param float32Array -\n     * @return - Unsigned Int16 array representative of the Float32Array\n     */\n    static convertFloat32ArrayToUInt16Array(float32Array) {\n        const unit16s = new Uint16Array(float32Array.length);\n        const int32View = new Int32Array(float32Array.buffer);\n        const toUInt16 = (x) => {\n            let bits = (x >> 16) & 0x8000; /* Get the sign */\n            let m = (x >> 12) & 0x07ff; /* Keep one extra bit for rounding */\n            const e = (x >> 23) & 0xff; /* Using int is faster here */\n            /* If zero, or de-normal, or exponent underflows too much for a de-normal\n             * half, return signed zero. */\n            if (e < 103) {\n                return bits;\n            }\n            /* If NaN, return NaN. If Inf or exponent overflow, return Inf. */\n            if (e > 142) {\n                bits |= 0x7c00;\n                /* If exponent was 0xff and one mantissa bit was set, it means NaN,\n                 * not Inf, so make sure we set one mantissa bit too. */\n                bits |= (e == 255 ? 0 : 1) && x & 0x007fffff;\n                return bits;\n            }\n            /* If exponent underflows but not too much, return a de-normal */\n            if (e < 113) {\n                m |= 0x0800;\n                /* Extra rounding may overflow and set mantissa to 0 and exponent\n                 * to 1, which is OK. */\n                bits |= (m >> (114 - e)) + ((m >> (113 - e)) & 1);\n                return bits;\n            }\n            bits |= ((e - 112) << 10) | (m >> 1);\n            /* Extra rounding. An overflow will set mantissa to 0 and increment\n             * the exponent, which is OK. */\n            bits += m & 1;\n            return bits;\n        };\n        for (let i = 0; i < float32Array.length; i++) {\n            unit16s[i] = toUInt16(int32View[i]);\n        }\n        return unit16s;\n    }\n}\n\n// import { BaseEvent } from './BaseEvent'\n// TODO:\n// class AllocatorResized extends BaseEvent {\n//   id: number\n//   allocation: any\n//   constructor() {\n//     super()\n//   }\n// }\n/**\n * An Allocation1D represents an allocated block of memory.\n *\n */\nclass Allocation1D {\n    start;\n    size;\n    /**\n     * Initializes the allocation\n     * @param start - The start of the allocated block of memory.\n     * @param size - The size of the allocated block of memory.\n     */\n    constructor(start = 0, size = 0) {\n        this.start = start;\n        this.size = size;\n    }\n}\n/**\n * An 1D allocator is used to manage packing multiple smaller blocks of data\n * into a single large block of memory, supporting resizing and re-allocating.\n * As allocations are changed, fragmentation occurs as blocks must be moved\n *\n * Example:\n * ```javascript\n * const allocator = new Allocator1D()\n *\n * let memory = new Uint32Array(25)\n * allocator.on('resize', () => {\n *   memory = new Uint32Array(allocator.reservedSpace)\n * })\n * allocator.on('dataReallocated', (event) => {\n *   // during allocation, a defragment might occur, which means\n *   // we need to reload some of our data.\n * })\n *\n * allocator.allocate(1, 5)\n * allocator.allocate(2, 10)\n * allocator.allocate(3, 10)\n * allocator.allocate(4, 20)\n * allocator.allocate(3, 20) // resize 3 to grow the allocated space.\n * allocator.allocate(1, 7) // resize 1 to fit into the previous space of 3, leaving a new free block.\n * allocator.allocate(1, 10) // resize 1 to fit into the previous space of 3, consuming the free block.\n * ```\n *\n */\nclass Allocator1D extends EventEmitter {\n    freeList = [];\n    allocations = [];\n    allocationsMap = {}; // A mapping of id to index within the allocations list\n    allocatedSpace = 0;\n    reservedSpace = 0;\n    freeSpace = 0;\n    /**\n     * Initializes the allocator ready to start work\n     */\n    constructor() {\n        super();\n    }\n    /**\n     * Returns the Allocates for the given Id.\n     *\n     * @param id - The unique numerical identifer for the block.\n     * @return - The allocation\n     */\n    getAllocation(id) {\n        return this.allocations[this.allocationsMap[id]];\n    }\n    /**\n     * Allocates space for a new or existing item. The id is a handle that the consuming code uses to\n     * track allocations.\n     *\n     * @param id - The unique numerical identifer for the block.\n     * @param size - The name of the event.\n     * @return - The new allocation\n     */\n    allocate(id, size) {\n        if (this.allocationsMap[id] != undefined) {\n            const index = this.allocationsMap[id];\n            const allocation = this.allocations[index];\n            // Resizing smaller\n            if (size == allocation.size) {\n                return allocation;\n            }\n            else if (size < allocation.size) {\n                // Split this block into 2. We use the first one for our item, and the second is put on the free list.\n                const splitBlockSize = allocation.size - size;\n                // this.allocations.splice(index + 1, 0, new Allocation1D(allocation.start + size, splitBlockSize))\n                this.addBlock(index + 1, new Allocation1D(allocation.start + size, splitBlockSize));\n                this.freeBlock(index + 1);\n                allocation.size = size;\n                return allocation;\n            }\n            else {\n                // Try to consume any free blocks directly to our right.\n                const nextIndex = index + 1;\n                if (this.freeList.includes(nextIndex) && allocation.size + this.allocations[nextIndex].size >= size) {\n                    const freeBlock = this.allocations[nextIndex];\n                    if (allocation.size + freeBlock.size == size) {\n                        // consume this free block\n                        allocation.size += freeBlock.size;\n                        this.freeSpace -= freeBlock.size;\n                        this.freeList.splice(this.freeList.indexOf(nextIndex), 1);\n                        // this.allocations.splice(nextIndex, 1)\n                        this.removeBlock(nextIndex);\n                        return allocation;\n                    }\n                    else {\n                        // We want to shrink the next block by the amount we consumed\n                        const consumed = size - allocation.size;\n                        allocation.size += consumed;\n                        this.freeSpace -= consumed;\n                        freeBlock.start += consumed;\n                        freeBlock.size -= consumed;\n                        return allocation;\n                    }\n                }\n                else {\n                    // free up this slot an find a new one\n                    // If the slot was at the end of the allocated memory, just decrement\n                    // the allocated space making it immediately available for use.\n                    delete this.allocationsMap[id];\n                    if (allocation.start + allocation.size == this.allocatedSpace) {\n                        this.removeBlock(index);\n                        this.allocatedSpace -= allocation.size;\n                    }\n                    else {\n                        this.freeBlock(index);\n                    }\n                }\n            }\n        }\n        let freeItemIndex = -1;\n        for (let i = 0; i < this.freeList.length; i++) {\n            const freeIndex = this.freeList[i];\n            const allocation = this.allocations[freeIndex];\n            if (allocation.size == size) {\n                freeItemIndex = freeIndex;\n                break;\n            }\n            else if (allocation.size > size) {\n                freeItemIndex = freeIndex;\n            }\n        }\n        if (freeItemIndex != -1) {\n            const freeItem = this.allocations[freeItemIndex];\n            this.freeSpace -= freeItem.size;\n            this.freeList.splice(this.freeList.indexOf(freeItemIndex), 1);\n            if (freeItem.size > size) {\n                // Split this block into 2. We use the first one for our item, and the second is put on the free list.\n                const splitBlockSize = freeItem.size - size;\n                // this.allocations.splice(freeItemIndex + 1, 0, new Allocation1D(freeItem.start + size, splitBlockSize))\n                this.addBlock(freeItemIndex + 1, new Allocation1D(freeItem.start + size, splitBlockSize));\n                this.freeBlock(freeItemIndex + 1);\n                this.allocations[freeItemIndex].size = size;\n            }\n            this.allocationsMap[id] = freeItemIndex;\n        }\n        else {\n            const start = this.allocatedSpace;\n            const index = this.allocations.length;\n            this.allocatedSpace += size;\n            const reserved = MathFunctions.nextPow2(this.allocatedSpace);\n            // Only re-allocate if we  need more space than is reserved.\n            // this means we won't resize smaller, even if we free up all allocated space\n            // In general, we don't want that anyway, as we would prefer to grow memory, and then\n            // keep it.\n            if (reserved > this.reservedSpace) {\n                this.reservedSpace = reserved;\n                this.emit('resized', { reservedSpace: this.reservedSpace });\n            }\n            this.allocations.push(new Allocation1D(start, size));\n            this.allocationsMap[id] = index;\n        }\n        return this.allocations[this.allocationsMap[id]];\n    }\n    /**\n     * Adds a new block\n     * @private\n     *\n     * @param index - The index where the block should be inserted.\n     * @param allocation - The allocation to insert\n     */\n    addBlock(index, allocation) {\n        this.allocations.splice(index, 0, allocation);\n        for (const id in this.allocationsMap) {\n            if (this.allocationsMap[id] >= index) {\n                this.allocationsMap[id]++;\n            }\n        }\n        for (let i = 0; i < this.freeList.length; i++) {\n            if (this.freeList[i] >= index) {\n                this.freeList[i]++;\n            }\n        }\n    }\n    /**\n     * Remove a new block\n     * @private\n     *\n     * @param index - The index where the block should be removed\n     */\n    removeBlock(index) {\n        this.allocations.splice(index, 1);\n        for (const id in this.allocationsMap) {\n            if (this.allocationsMap[id] > index) {\n                this.allocationsMap[id]--;\n            }\n        }\n        for (let i = 0; i < this.freeList.length; i++) {\n            if (this.freeList[i] > index) {\n                this.freeList[i]--;\n            }\n        }\n    }\n    /**\n     * Frees a block by either growing neighboring blocks or adding a new free block\n     * @private\n     *\n     * @param index - The index of the block to free.\n     */\n    freeBlock(index) {\n        const allocation = this.allocations[index];\n        this.freeSpace += allocation.size;\n        // check for free blocks on either side of the allocated space\n        // and allow them to consume this block instead of adding a new smaller\n        // block.\n        const prevIndex = index - 1;\n        if (this.freeList.includes(prevIndex)) {\n            const prevAllocation = this.allocations[prevIndex];\n            prevAllocation.size += allocation.size;\n            this.removeBlock(index);\n            return;\n        }\n        const nextIndex = index + 1;\n        if (this.freeList.includes(nextIndex)) {\n            const nextAllocation = this.allocations[nextIndex];\n            nextAllocation.start -= allocation.size;\n            nextAllocation.size += allocation.size;\n            this.removeBlock(index);\n            return;\n        }\n        this.freeList.push(index);\n        // Sort the free blocks by size so we use the smallest ones first.\n        // This reduces the chance of fragmentation by always consuming the smallerest free blocks first.\n        this.freeList.sort((a, b) => this.allocations[a].size - this.allocations[b].size);\n    }\n    /**\n     * Deallocate space for an existing item, making it free for other uses.\n     *\n     * @param id - The unique numerical identifer for the block.\n     */\n    deallocate(id) {\n        const index = this.allocationsMap[id];\n        if (index == undefined) {\n            throw new Error(`allocation ${id} does not exist.`);\n        }\n        this.freeBlock(index);\n        delete this.allocationsMap[id];\n    }\n    /**\n     * Returns the ratio of fragmented memory over reserved memory.\n     *\n     * @return The fragmentation ratio. Between 0 and some value less than 1\n     */\n    getFragmentation() {\n        return this.freeSpace / this.allocatedSpace;\n    }\n    /**\n     * Defragment the memory space reducing memory requirements.\n     * TODO: Implement this method.\n     */\n    defragment() {\n        // move the freeblocks to the end of the memory so that\n        // we can then reduce the memory used.\n    }\n    /**\n     * Checks that the allocations are consistent and not corrupt in any way.\n     */\n    verifyConsistency() {\n        if (Object.keys(this.allocationsMap).length + this.freeList.length != this.allocations.length) {\n            throw new Error('number of blocks does not match the number of allocations');\n        }\n        // eslint-disable-next-line guard-for-in\n        for (const id in this.allocationsMap) {\n            const index = this.allocationsMap[id];\n            if (this.freeList.includes(index)) {\n                // eslint-disable-next-line no-throw-literal\n                throw new Error('block of used memory is also on the free list');\n            }\n        }\n        let size = 0;\n        for (let i = 0; i < this.allocations.length; i++) {\n            const allocation = this.allocations[i];\n            if (allocation.start != size) {\n                // eslint-disable-next-line no-throw-literal\n                throw 'blocks of memory are not sequential';\n            }\n            size += allocation.size;\n        }\n        if (size != this.allocatedSpace) {\n            // eslint-disable-next-line no-throw-literal\n            throw `allocated size: ${this.allocatedSpace}  does not match allocated blocks: ${size}`;\n        }\n        if (this.reservedSpace < this.allocatedSpace) {\n            // eslint-disable-next-line no-throw-literal\n            throw `reserved space: ${this.reservedSpace} is less than allocated space: ${this.allocatedSpace}`;\n        }\n    }\n}\n\nclass IntersectionData {\n    screenPos;\n    pointerRay;\n    intersectionPos;\n    geomData;\n    geomItem;\n    componentId;\n    componentIds = [];\n    dist;\n    constructor(screenPos, pointerRay, intersectionPos, geomData, geomItemAndDist) {\n        this.screenPos = screenPos;\n        this.pointerRay = pointerRay;\n        this.intersectionPos = intersectionPos;\n        this.geomData = geomData;\n        this.geomItem = geomItemAndDist.geomItem;\n        this.componentId = geomItemAndDist.componentId;\n        this.dist = geomItemAndDist.dist;\n    }\n}\n\nclass ChildAddedEvent extends BaseEvent {\n    index;\n    childItem;\n    constructor(index, childItem) {\n        super();\n        this.index = index;\n        this.childItem = childItem;\n    }\n}\n\nclass ControllerAddedEvent extends BaseEvent {\n    controller;\n    constructor(controller) {\n        super();\n        this.controller = controller;\n    }\n}\n\nclass CountChangedEvent extends BaseEvent {\n    change;\n    count;\n    constructor(change, count) {\n        super();\n        this.change = change;\n        this.count = count;\n    }\n}\n\nclass EnvMapAssignedEvent extends BaseEvent {\n    envMap;\n    constructor(envMap) {\n        super();\n        this.envMap = envMap;\n    }\n}\n\nclass IndexEvent extends BaseEvent {\n    index;\n    constructor(index) {\n        super();\n        this.index = index;\n    }\n}\n\n/**\n * ZeaUIEvent are emitted from a 2D UI, such as from a HTMLCanvas element generated from\n * a mouse or touch interaction, or key presses\n */\nclass ZeaUIEvent extends BaseEvent {\n    viewport;\n    propagating = true;\n    constructor() {\n        super();\n    }\n}\n\nclass ZeaKeyboardEvent extends ZeaUIEvent {\n    sourceEvent;\n    propagating = true;\n    // Returns a boolean value that is true if the Alt (Option or ⌥ on OS X) key was active when the key event was generated.\n    altKey;\n    // Returns a DOMString with the code value of the physical key represented by the event.\n    code;\n    // Returns a boolean value that is true if the Ctrl key was active when the key event was generated.\n    ctrlKey;\n    // Returns a boolean value that is true if the event is fired between after compositionstart and before compositionend.\n    isComposing;\n    // Returns a DOMString representing the key value of the key represented by the event.\n    key;\n    // Returns a Number representing the location of the key on the keyboard or other input device. A list of the constants identifying the locations is shown above in Keyboard locations.\n    location;\n    // Returns a boolean value that is true if the Meta key (on Mac keyboards, the ⌘ Command key; on Windows keyboards, the Windows key (⊞)) was active when the key event was generated.\n    metaKey;\n    // Returns a boolean value that is true if the key is being held down such that it is automatically repeating.\n    repeat;\n    // Returns a boolean value that is true if the Shift key was active when the key event was generated.\n    shiftKey;\n    // Returns a Number representing a system and implementation dependent numeric code identifying the unmodified value of the pressed key; this is usually the same as keyCode.\n    which;\n    constructor(sourceEvent) {\n        super();\n        if (sourceEvent) {\n            this.sourceEvent = sourceEvent;\n            this.altKey = sourceEvent.altKey;\n            this.code = sourceEvent.code;\n            this.ctrlKey = sourceEvent.ctrlKey;\n            this.isComposing = sourceEvent.isComposing;\n            this.key = sourceEvent.key;\n            this.location = sourceEvent.location;\n            this.metaKey = sourceEvent.metaKey;\n            this.repeat = sourceEvent.repeat;\n            this.shiftKey = sourceEvent.shiftKey;\n        }\n    }\n    stopPropagation() {\n        this.propagating = false;\n        if (this.sourceEvent)\n            this.sourceEvent.stopPropagation();\n    }\n    preventDefault() {\n        if (this.sourceEvent)\n            this.sourceEvent.preventDefault();\n    }\n}\n// deprecated class. Please stop using it.\nclass KeyboardEvent extends ZeaKeyboardEvent {\n}\n\nclass NameChangedEvent extends BaseEvent {\n    oldName;\n    newName;\n    constructor(oldName, newName) {\n        super();\n        this.oldName = oldName;\n        this.newName = newName;\n    }\n}\n\nclass OpacityStateChangedEvent extends BaseEvent {\n    isOpaque;\n    isOpaqueStateChanged;\n    constructor(isOpaque, isOpaqueStateChanged) {\n        super();\n        this.isOpaque = isOpaque;\n        this.isOpaqueStateChanged = isOpaqueStateChanged;\n    }\n}\n\nclass ParameterAddedEvent extends BaseEvent {\n    name;\n    constructor(name) {\n        super();\n        this.name = name;\n    }\n}\n\nclass ParameterRemovedEvent extends BaseEvent {\n    name;\n    constructor(name) {\n        super();\n        this.name = name;\n    }\n}\n\nclass RangeLoadedEvent extends BaseEvent {\n    range;\n    constructor(range) {\n        super();\n        this.range = range;\n    }\n}\n\nclass SceneSetEvent extends BaseEvent {\n    scene;\n    constructor(scene) {\n        super();\n        this.scene = scene;\n    }\n}\n\nclass SelectabilityChangedEvent extends BaseEvent {\n    value;\n    constructor(value) {\n        super();\n        this.value = value;\n    }\n}\n\nclass SelectedEvent extends BaseEvent {\n    selected;\n    constructor(selected) {\n        super();\n        this.selected = selected;\n    }\n}\n\nclass ShaderNameChangedEvent extends BaseEvent {\n    shaderName;\n    constructor(shaderName) {\n        super();\n        this.shaderName = shaderName;\n    }\n}\n\nclass StateChangedEvent extends BaseEvent {\n    state;\n    constructor(state) {\n        super();\n        this.state = state;\n    }\n}\n\nclass StreamFileParsedEvent extends BaseEvent {\n    geomFileID;\n    geomCount;\n    constructor(geomFileID, geomCount) {\n        super();\n        this.geomFileID = geomFileID;\n        this.geomCount = geomCount;\n    }\n}\n\n//{ isTextured, param }\nclass TexturedChangedEvent extends BaseEvent {\n    isTextured;\n    param;\n    constructor(isTextured, param) {\n        super();\n        this.isTextured = isTextured;\n        this.param = param;\n    }\n}\n\nclass ViewChangedEvent extends BaseEvent {\n    interfaceType;\n    viewXfo;\n    viewport;\n    constructor(interfaceType, viewXfo) {\n        super();\n        this.interfaceType = interfaceType;\n        this.viewXfo = viewXfo;\n    }\n}\n\nclass ProgressEvent extends BaseEvent {\n    percent;\n    constructor(percent) {\n        super();\n        this.percent = percent;\n    }\n}\n\nconst POINTER_TYPES = {\n    mouse: 'mouse',\n    touch: 'touch',\n    xr: 'xr',\n};\nlet capturedItem$1 = null;\n/**\n * ZeaPointerEvent are emitted from mouse or touch interactions or from WebXR controllers.\n */\nclass ZeaPointerEvent extends ZeaUIEvent {\n    pointerType;\n    pointerRay;\n    pointerPos;\n    detail;\n    intersectionData;\n    leftGeometry;\n    constructor(pointerType) {\n        super();\n        this.pointerType = pointerType;\n    }\n    stopPropagation() {\n        this.propagating = false;\n    }\n    setCapture(item) {\n        capturedItem$1 = item;\n    }\n    getCapture() {\n        return capturedItem$1;\n    }\n    releaseCapture() {\n        capturedItem$1 = null;\n    }\n}\n\nconst captureItems = [];\nclass XRControllerEvent extends ZeaPointerEvent {\n    controller;\n    button;\n    buttonPressed = 0;\n    constructor(viewport, controller, button, buttonPressed) {\n        super(POINTER_TYPES.xr);\n        this.viewport = viewport;\n        this.controller = controller;\n        this.button = button;\n        this.buttonPressed = buttonPressed;\n    }\n    stopPropagation() {\n        this.propagating = false;\n    }\n    setCapture(item) {\n        captureItems[this.controller.id] = item;\n    }\n    getCapture() {\n        return captureItems[this.controller.id];\n    }\n    releaseCapture() {\n        captureItems[this.controller.id] = null;\n    }\n}\n\nlet capturedItem = null;\nclass XRPointerEvent extends ZeaPointerEvent {\n    xfo;\n    xrSelectEvent;\n    hitTestResults;\n    constructor(viewport, xfo, xrSelectEvent, hitTestResults) {\n        super(POINTER_TYPES.xr);\n        this.viewport = viewport;\n        this.xfo = xfo;\n        this.xrSelectEvent = xrSelectEvent;\n        this.hitTestResults = hitTestResults;\n    }\n    stopPropagation() {\n        this.propagating = false;\n    }\n    setCapture(item) {\n        capturedItem = item;\n    }\n    getCapture() {\n        return capturedItem;\n    }\n    releaseCapture() {\n        capturedItem = null;\n    }\n}\n\n// TODO: Once we start the migration to AssemblyScript\n// we will need to extract the cotroller data and package\n// into this struct. Untill then, we will just put the whole\n// controller.\n// class XRControllerPose {\n//   controller: XRController\n//   constructor(controller: XRController) {\n//     this.controller = controller\n//   }\n// }\nclass XRPoseEvent extends ZeaPointerEvent {\n    viewXfo;\n    controllers = [];\n    constructor(viewport, viewXfo, controllers = []) {\n        super(POINTER_TYPES.xr);\n        this.viewport = viewport;\n        this.viewXfo = viewXfo;\n        controllers.forEach((controller) => {\n            this.controllers.push(controller);\n        });\n    }\n}\n\nclass XRViewChangedEvent extends ViewChangedEvent {\n    hmd = '';\n    controllers = [];\n    xrviewport;\n    constructor(viewXfo) {\n        super('VR', viewXfo);\n    }\n}\n\nclass XrViewportEvent extends BaseEvent {\n    xrViewport;\n    constructor(xrViewport) {\n        super();\n        this.xrViewport = xrViewport;\n    }\n}\n\nclass ZeaMouseEvent extends ZeaPointerEvent {\n    button;\n    clientX;\n    clientY;\n    rendererX;\n    rendererY;\n    altKey;\n    metaKey;\n    ctrlKey;\n    shiftKey;\n    sourceEvent;\n    constructor(sourceEvent, rect) {\n        super(POINTER_TYPES.mouse);\n        this.sourceEvent = sourceEvent;\n        this.button = sourceEvent.button;\n        this.clientX = sourceEvent.clientX;\n        this.clientY = sourceEvent.clientY;\n        // Note: the rendererX/Y values are relative to the viewport,\n        // but are available outside the viewport. So when a mouse\n        // drag occurs, and drags outside the viewport, these values\n        // provide consistent coords.\n        // offsetX/Y are only valid inside the viewport and so cause\n        // jumps when the mouse leaves the viewport.\n        this.rendererX = this.clientX - rect.left;\n        this.rendererY = this.clientY - rect.top;\n        this.altKey = sourceEvent.altKey;\n        this.metaKey = sourceEvent.metaKey;\n        this.ctrlKey = sourceEvent.ctrlKey;\n        this.shiftKey = sourceEvent.shiftKey;\n    }\n    stopPropagation() {\n        super.stopPropagation();\n        if (this.sourceEvent)\n            this.sourceEvent.stopPropagation();\n    }\n    preventDefault() {\n        if (this.sourceEvent)\n            this.sourceEvent.preventDefault();\n    }\n}\n\n/* eslint-disable new-cap */\n/**\n * Class representing a ray that starts from an origin in a specified direction.\n */\nclass Ray {\n    dir;\n    start;\n    /**\n     * Create a ray.\n     *\n     * @param start - The origin of the ray.\n     * @param dir - The direction of the ray.\n     */\n    constructor(start, dir) {\n        if (start instanceof Vec3) {\n            this.start = start;\n        }\n        else {\n            this.start = new Vec3();\n        }\n        if (dir instanceof Vec3) {\n            this.dir = dir;\n        }\n        else {\n            this.dir = new Vec3();\n        }\n    }\n    /**\n     * Get the closest point on the ray to the given point.\n     *\n     * @param point - The point in 3D space.\n     * @return - returns a number\n     */\n    closestPoint(point) {\n        const w = point.subtract(this.start);\n        const c1 = w.dot(this.dir);\n        if (c1 < Number.EPSILON)\n            return 0;\n        const c2 = this.dir.dot(this.dir);\n        if (c2 < Number.EPSILON)\n            return 0;\n        return c1 / c2;\n    }\n    /**\n     * Get the closest point between the ray and the given line segment made of the 2 points.\n     *\n     * @param p0 - The point in 3D space.\n     * @param p1 - The point in 3D space.\n     * @return - Returns an array containing 2 scalar values indicating 0: the fraction of the line segment, 1: distance along the Ray\n     */\n    closestPointOnLineSegment(p0, p1) {\n        const u = this.dir;\n        const v = p1.subtract(p0);\n        const v_len = v.length();\n        v.normalizeInPlace();\n        const w = this.start.subtract(p0);\n        const a = u.dot(u); // always >= 0\n        const b = u.dot(v);\n        const c = v.dot(v); // always >= 0\n        const d = u.dot(w);\n        const e = v.dot(w);\n        if (a == 0.0 && c == 0.0) {\n            return [this.start.distanceTo(p0), 0.0];\n        }\n        if (a == 0.0) {\n            return [0.0, 0.0];\n        }\n        if (c == 0.0) {\n            return [this.closestPoint(p0), 0.0];\n        }\n        const D = a * c - b * b; // always >= 0\n        // compute the ray parameters of the two closest points\n        let this_t;\n        let seg_t;\n        if (D < 0.001) {\n            // the lines are almost parallel\n            this_t = 0.0;\n            if (b > c) {\n                // use the largest denominator\n                seg_t = d / b;\n            }\n            else {\n                seg_t = e / c;\n            }\n        }\n        else {\n            this_t = (b * e - c * d) / D;\n            seg_t = (a * e - b * d) / D;\n        }\n        return [this_t, MathFunctions.clamp(seg_t / v_len, 0, 1)];\n    }\n    /**\n     * Get the closest point at a distance.\n     *\n     * @param dist - The distance value.\n     * @return - Returns a Vec3.\n     */\n    pointAtDist(dist) {\n        return this.start.add(this.dir.scale(dist));\n    }\n    /**\n     * Returns the two ray params that represent the closest point between the two rays.\n     *\n     * @param ray - The ray value.\n     * @return - Returns a Ray.\n     */\n    intersectRayVector(ray) {\n        const u = this.dir;\n        const v = ray.dir;\n        const w = this.start.subtract(ray.start);\n        const a = u.dot(u); // always >= 0\n        const b = u.dot(v);\n        const c = v.dot(v); // always >= 0\n        const d = u.dot(w);\n        const e = v.dot(w);\n        if (a == 0.0 && c == 0.0) {\n            return undefined;\n        }\n        if (a == 0.0) {\n            const ray_t = ray.closestPoint(this.start);\n            return [0, ray_t];\n        }\n        if (c == 0.0) {\n            const this_t = this.closestPoint(ray.start);\n            return [this_t, 0.0];\n        }\n        const D = a * c - b * b; // always >= 0\n        // compute the ray parameters of the two closest points\n        let this_t;\n        let ray_t;\n        if (D < 0.001) {\n            // the lines are almost parallel\n            this_t = 0.0;\n            if (b > c) {\n                // use the largest denominator\n                ray_t = d / b;\n            }\n            else {\n                ray_t = e / c;\n            }\n        }\n        else {\n            this_t = (b * e - c * d) / D;\n            ray_t = (a * e - b * d) / D;\n        }\n        return [this_t, ray_t];\n    }\n    /**\n     * Returns one ray param representing the intersection\n     * of this ray against the plane defined by the given ray.\n     *\n     * @param plane - The plane to intersect with.\n     * @return - The return value.\n     */\n    intersectRayPlane(plane) {\n        const w = this.start.subtract(plane.start);\n        const D = plane.dir.dot(this.dir);\n        const N = -plane.dir.dot(w);\n        if (Math.abs(D) < Number.PRECISION) {\n            // segment is parallel to plane\n            if (N == 0.0)\n                return -1.0;\n            // segment lies in plane\n            else\n                return -1.0; // no intersection\n        }\n        // they are not parallel\n        // compute intersect param\n        const sI = N / D;\n        if (sI < -Number.PRECISION) {\n            return -1; // no intersection\n        }\n        return sI;\n    }\n    /**\n     * Determines if this Box3 intersects a ray.\n     *\n     * @param box3 - The box to check for intersection against.\n     * @param tolerance - The tolerance of the test.\n     * @return - The return value.\n     */\n    intersectRayBox3(box3, tolerance = 0) {\n        // https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-box-intersection\n        const invDir = new Vec3(1 / this.dir.x, 1 / this.dir.y, 1 / this.dir.z);\n        const sign = [];\n        sign[0] = invDir.x < 0 ? 1 : 0;\n        sign[1] = invDir.y < 0 ? 1 : 0;\n        sign[2] = invDir.z < 0 ? 1 : 0;\n        const bounds = [];\n        if (tolerance > 0) {\n            const diag = box3.diagonal();\n            diag.normalizeInPlace();\n            diag.scaleInPlace(tolerance);\n            bounds[0] = box3.p0.subtract(diag);\n            bounds[1] = box3.p1.add(diag);\n        }\n        else {\n            bounds[0] = box3.p0;\n            bounds[1] = box3.p1;\n        }\n        let tMin = (bounds[sign[0]].x - this.start.x) * invDir.x;\n        let tMax = (bounds[1 - sign[0]].x - this.start.x) * invDir.x;\n        const tyMin = (bounds[sign[1]].y - this.start.y) * invDir.y;\n        const tyMax = (bounds[1 - sign[1]].y - this.start.y) * invDir.y;\n        if (tMin > tyMax || tyMin > tMax)\n            return false;\n        if (tyMin > tMin)\n            tMin = tyMin;\n        if (tyMax < tMax)\n            tMax = tyMax;\n        const tzMin = (bounds[sign[2]].z - this.start.z) * invDir.z;\n        const tzMax = (bounds[1 - sign[2]].z - this.start.z) * invDir.z;\n        if (tMin > tzMax || tzMin > tMax)\n            return false;\n        if (tzMin > tMin)\n            tMin = tzMin;\n        if (tzMax < tMax)\n            tMax = tzMax;\n        return true;\n    }\n    /**\n     * Clones this Ray and returns a new Ray.\n     *\n     * @return - Returns a new Ray.\n     */\n    clone() {\n        return new Ray(this.start.clone(), this.dir.clone());\n    }\n    // ///////////////////////////\n    // Persistence\n    /**\n     * The toJSON method encodes this type as a json object for persistence.\n     *\n     * @return - The json object.\n     */\n    toJSON() {\n        return {\n            start: this.start.toJSON(),\n            dir: this.dir.toJSON(),\n        };\n    }\n    /**\n     * The fromJSON method decodes a json object for this type.\n     *\n     * @param j - The json object.\n     */\n    fromJSON(j) {\n        this.start.fromJSON(j.start);\n        this.dir.fromJSON(j.dir);\n    }\n    /**\n     * Calls `toJSON` method and stringifies it.\n     *\n     * @return - The return value.\n     */\n    toString() {\n        return StringFunctions.stringifyJSONWithFixedPrecision(this.toJSON());\n    }\n}\n\nclass Touch {\n    identifier;\n    clientX = 0;\n    clientY = 0;\n    screenX = 0;\n    screenY = 0;\n    pageX = 0;\n    pageY = 0;\n    radiusX = 0;\n    radiusY = 0;\n    rotationAngle = 0;\n    force = 0;\n    altitudeAngle = 0;\n    azimuthAngle = 0;\n    touchType = 'direct';\n    rendererX;\n    rendererY;\n    touchPos;\n    touchRay;\n    constructor(touch, rect) {\n        this.identifier = touch.identifier;\n        this.clientX = touch.clientX;\n        this.clientY = touch.clientY;\n        this.screenX = touch.screenX;\n        this.screenY = touch.screenY;\n        this.pageX = touch.pageX;\n        this.pageY = touch.pageY;\n        this.radiusX = touch.radiusX;\n        this.radiusY = touch.radiusY;\n        this.rotationAngle = touch.rotationAngle;\n        this.force = touch.force;\n        // this.altitudeAngle = touch.altitudeAngle\n        // this.azimuthAngle = touch.azimuthAngle\n        // this.touchType = touch.touchType\n        // Note: the rendererX/Y values are relative to the viewport,\n        // but are available outside the viewport. So when a mouse\n        // drag occurs, and drags outside the viewport, these values\n        // provide consistent coords.\n        // offsetX/Y are only valid inside the viewport and so cause\n        // jumps when the mouse leaves the viewport.\n        this.rendererX = this.clientX - rect.left;\n        this.rendererY = this.clientY - rect.top;\n        this.touchPos = new Vec2(this.rendererX, this.rendererY);\n        this.touchRay = new Ray();\n    }\n}\nclass ZeaTouchEvent extends ZeaPointerEvent {\n    touches = [];\n    changedTouches = [];\n    targetTouches = [];\n    altKey = false;\n    metaKey = false;\n    ctrlKey = false;\n    shiftKey = false;\n    sourceEvent;\n    constructor(sourceEvent, rect) {\n        super(POINTER_TYPES.touch);\n        this.sourceEvent = sourceEvent;\n        this.sourceEvent.stopPropagation();\n        this.altKey = sourceEvent.altKey;\n        this.metaKey = sourceEvent.metaKey;\n        this.ctrlKey = sourceEvent.ctrlKey;\n        this.shiftKey = sourceEvent.shiftKey;\n        for (let i = 0; i < sourceEvent.touches.length; i++) {\n            this.touches.push(new Touch(sourceEvent.touches[i], rect));\n        }\n        if (sourceEvent.changedTouches) {\n            for (let i = 0; i < sourceEvent.changedTouches.length; i++) {\n                this.changedTouches.push(new Touch(sourceEvent.changedTouches[i], rect));\n            }\n        }\n        if (sourceEvent.targetTouches) {\n            for (let i = 0; i < sourceEvent.targetTouches.length; i++) {\n                this.targetTouches.push(new Touch(sourceEvent.targetTouches[i], rect));\n            }\n        }\n    }\n    stopPropagation() {\n        super.stopPropagation();\n        if (this.sourceEvent)\n            this.sourceEvent.stopPropagation();\n    }\n    // Touch events are passive and so cannot call prevent default\n    // replace with a stub here...\n    preventDefault() { }\n}\n\nclass ZeaWheelEvent extends ZeaMouseEvent {\n    wheelDelta;\n    deltaMode;\n    deltaX;\n    deltaY;\n    deltaZ;\n    constructor(sourceEvent, rect) {\n        super(sourceEvent, rect);\n        // @ts-ignore\n        this.wheelDelta = sourceEvent.wheelDelta;\n        this.deltaMode = sourceEvent.deltaMode;\n        this.deltaX = sourceEvent.deltaX;\n        this.deltaY = sourceEvent.deltaY;\n        this.deltaZ = sourceEvent.deltaZ;\n    }\n}\n\n/**\n * Class representing a color as 4 floating point values.\n */\nclass Color {\n    r = 0;\n    g = 0;\n    b = 0;\n    a = 255;\n    /**\n     * Creates a `Color` object with an RGBA structure.\n     *\n     * @param r - The red channel of a color.\n     * @param g - The green channel of a color.\n     * @param b - The blue channel of a color.\n     * @param a - The alpha (transparency) channel of a color.\n     */\n    constructor(r = 0, g = 0, b = 0, a = 1.0) {\n        if (typeof r == 'string') {\n            if (r.startsWith('#')) {\n                this.setFromHex(r);\n            }\n            else {\n                this.setFromCSSColorName(r);\n            }\n        }\n        else {\n            this.r = r;\n            this.g = g;\n            this.b = b;\n            this.a = a;\n        }\n    }\n    /**\n     * Setter from scalar components.\n     *\n     * @param r - The red channel.\n     * @param g  - The green channel.\n     * @param b  - The blue channel.\n     * @param a  - The alpha channel.\n     */\n    set(r, g, b, a = 1.0) {\n        this.r = r;\n        this.g = g;\n        this.b = b;\n        this.a = a;\n    }\n    /**\n     * Sets current color state with another `Color` object.\n     *\n     * @param other - The other color to set from.\n     */\n    setFromOther(other) {\n        this.r = other.r;\n        this.g = other.g;\n        this.b = other.b;\n        this.a = other.a;\n    }\n    /**\n     * Getter from an RGB array.\n     *\n     * @return - The return value.\n     */\n    getAsRGBArray() {\n        return [this.r * 255, this.g * 255, this.b * 255];\n    }\n    /**\n     * Getter from an RGB dict.\n     *\n     * @return - The return value.\n     */\n    getAsRGBDict() {\n        return {\n            r: this.r * 255,\n            g: this.g * 255,\n            b: this.b * 255,\n        };\n    }\n    /**\n     * Setter from a RGB value.\n     *\n     * @param r - The red channel.\n     * @param g  - The green channel.\n     * @param b  - The blue channel.\n     * @param a  - The alpha channel.\n     */\n    setFromRGB(r, g, b, a) {\n        this.r = r / 255;\n        this.g = g / 255;\n        this.b = b / 255;\n        this.a = a ? a / 255 : 1.0;\n    }\n    /**\n     * Setter from an RGB dict.\n     *\n     * @param vals - The vals param.\n     */\n    setFromRGBDict(vals) {\n        this.r = vals.r / 255;\n        this.g = vals.g / 255;\n        this.b = vals.b / 255;\n        this.a = vals.a == 4 ? vals.a / 255 : 1.0;\n    }\n    /**\n     * Setter from a hexadecimal value.\n     * E.g. #ff0000\n     * @param hex - The hex value.\n     */\n    setFromHex(hex) {\n        function hexToRgb(hex) {\n            const result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex);\n            return result\n                ? {\n                    r: parseInt(result[1], 16),\n                    g: parseInt(result[2], 16),\n                    b: parseInt(result[3], 16),\n                }\n                : null;\n        }\n        const rgb = hexToRgb(hex);\n        if (!rgb) {\n            console.warn('Invalid hex code:' + hex);\n            return;\n        }\n        this.setFromRGB(rgb.r, rgb.g, rgb.b);\n    }\n    /**\n     * Sets the Color values from a CSS color name.\n     * E.g. \"red\"\n     * @param name - The CSS color name.\n     */\n    setFromCSSColorName(name) {\n        const colourNameToHex = (colour) => {\n            const colors = {\n                aliceblue: '#f0f8ff',\n                antiquewhite: '#faebd7',\n                aqua: '#00ffff',\n                aquamarine: '#7fffd4',\n                azure: '#f0ffff',\n                beige: '#f5f5dc',\n                bisque: '#ffe4c4',\n                black: '#000000',\n                blanchedalmond: '#ffebcd',\n                blue: '#0000ff',\n                blueviolet: '#8a2be2',\n                brown: '#a52a2a',\n                burlywood: '#deb887',\n                cadetblue: '#5f9ea0',\n                chartreuse: '#7fff00',\n                chocolate: '#d2691e',\n                coral: '#ff7f50',\n                cornflowerblue: '#6495ed',\n                cornsilk: '#fff8dc',\n                crimson: '#dc143c',\n                cyan: '#00ffff',\n                darkblue: '#00008b',\n                darkcyan: '#008b8b',\n                darkgoldenrod: '#b8860b',\n                darkgray: '#a9a9a9',\n                darkgreen: '#006400',\n                darkkhaki: '#bdb76b',\n                darkmagenta: '#8b008b',\n                darkolivegreen: '#556b2f',\n                darkorange: '#ff8c00',\n                darkorchid: '#9932cc',\n                darkred: '#8b0000',\n                darksalmon: '#e9967a',\n                darkseagreen: '#8fbc8f',\n                darkslateblue: '#483d8b',\n                darkslategray: '#2f4f4f',\n                darkturquoise: '#00ced1',\n                darkviolet: '#9400d3',\n                deeppink: '#ff1493',\n                deepskyblue: '#00bfff',\n                dimgray: '#696969',\n                dodgerblue: '#1e90ff',\n                firebrick: '#b22222',\n                floralwhite: '#fffaf0',\n                forestgreen: '#228b22',\n                fuchsia: '#ff00ff',\n                gainsboro: '#dcdcdc',\n                ghostwhite: '#f8f8ff',\n                gold: '#ffd700',\n                goldenrod: '#daa520',\n                gray: '#808080',\n                green: '#008000',\n                greenyellow: '#adff2f',\n                honeydew: '#f0fff0',\n                hotpink: '#ff69b4',\n                'indianred ': '#cd5c5c',\n                indigo: '#4b0082',\n                ivory: '#fffff0',\n                khaki: '#f0e68c',\n                lavender: '#e6e6fa',\n                lavenderblush: '#fff0f5',\n                lawngreen: '#7cfc00',\n                lemonchiffon: '#fffacd',\n                lightblue: '#add8e6',\n                lightcoral: '#f08080',\n                lightcyan: '#e0ffff',\n                lightgoldenrodyellow: '#fafad2',\n                lightgrey: '#d3d3d3',\n                lightgreen: '#90ee90',\n                lightpink: '#ffb6c1',\n                lightsalmon: '#ffa07a',\n                lightseagreen: '#20b2aa',\n                lightskyblue: '#87cefa',\n                lightslategray: '#778899',\n                lightsteelblue: '#b0c4de',\n                lightyellow: '#ffffe0',\n                lime: '#00ff00',\n                limegreen: '#32cd32',\n                linen: '#faf0e6',\n                magenta: '#ff00ff',\n                maroon: '#800000',\n                mediumaquamarine: '#66cdaa',\n                mediumblue: '#0000cd',\n                mediumorchid: '#ba55d3',\n                mediumpurple: '#9370d8',\n                mediumseagreen: '#3cb371',\n                mediumslateblue: '#7b68ee',\n                mediumspringgreen: '#00fa9a',\n                mediumturquoise: '#48d1cc',\n                mediumvioletred: '#c71585',\n                midnightblue: '#191970',\n                mintcream: '#f5fffa',\n                mistyrose: '#ffe4e1',\n                moccasin: '#ffe4b5',\n                navajowhite: '#ffdead',\n                navy: '#000080',\n                oldlace: '#fdf5e6',\n                olive: '#808000',\n                olivedrab: '#6b8e23',\n                orange: '#ffa500',\n                orangered: '#ff4500',\n                orchid: '#da70d6',\n                palegoldenrod: '#eee8aa',\n                palegreen: '#98fb98',\n                paleturquoise: '#afeeee',\n                palevioletred: '#d87093',\n                papayawhip: '#ffefd5',\n                peachpuff: '#ffdab9',\n                peru: '#cd853f',\n                pink: '#ffc0cb',\n                plum: '#dda0dd',\n                powderblue: '#b0e0e6',\n                purple: '#800080',\n                rebeccapurple: '#663399',\n                red: '#ff0000',\n                rosybrown: '#bc8f8f',\n                royalblue: '#4169e1',\n                saddlebrown: '#8b4513',\n                salmon: '#fa8072',\n                sandybrown: '#f4a460',\n                seagreen: '#2e8b57',\n                seashell: '#fff5ee',\n                sienna: '#a0522d',\n                silver: '#c0c0c0',\n                skyblue: '#87ceeb',\n                slateblue: '#6a5acd',\n                slategray: '#708090',\n                snow: '#fffafa',\n                springgreen: '#00ff7f',\n                steelblue: '#4682b4',\n                tan: '#d2b48c',\n                teal: '#008080',\n                thistle: '#d8bfd8',\n                tomato: '#ff6347',\n                turquoise: '#40e0d0',\n                violet: '#ee82ee',\n                wheat: '#f5deb3',\n                white: '#ffffff',\n                whitesmoke: '#f5f5f5',\n                yellow: '#ffff00',\n                yellowgreen: '#9acd32',\n            };\n            return colors[colour.toLowerCase()];\n            //  if (typeof colors[colour.toLowerCase()] != 'undefined') return colors[colour.toLowerCase()]\n            // return false\n        };\n        if (name.startsWith('#')) {\n            this.setFromHex(name);\n        }\n        else {\n            const hexColor = colourNameToHex(name);\n            if (hexColor)\n                this.setFromHex(hexColor);\n        }\n    }\n    /**\n     * Returns the hexadecimal value of this color, including the leading \"#\" character.\n     *\n     * @return - Returns the hex value.\n     */\n    toHex() {\n        function componentToHex(c) {\n            const int = Math.round(c * 255);\n            const hex = int.toString(16);\n            return hex.length == 1 ? '0' + hex : hex;\n        }\n        return '#' + componentToHex(this.r) + componentToHex(this.g) + componentToHex(this.b);\n    }\n    /**\n     * Checks if this Color  contains the same values as the other.\n     *\n     * @param other - The other Color to compare with.\n     * @return - Returns `true` if the values are the same, otherwise, `false`.\n     */\n    isEqual(other) {\n        return this.r == other.r && this.g == other.g && this.b == other.b && this.a == other.a;\n    }\n    /**\n     * Returns true if this color is NOT exactly the same as other.\n     *\n     * @param other - The other color to compare with.\n     * @return - Returns true or false.\n     */\n    notEquals(other) {\n        return this.r != other.r && this.g != other.g && this.b != other.b && this.a != other.a;\n    }\n    /**\n     * Returns true if this color is approximately the same as other.\n     *\n     * @param other - The other color to compare with.\n     * @param precision - The precision to which the values must match.\n     * @return - Returns true or false.\n     */\n    approxEqual(other, precision = Number.EPSILON) {\n        return (Math.abs(this.r - other.r) < precision &&\n            Math.abs(this.g - other.g) < precision &&\n            Math.abs(this.b - other.b) < precision &&\n            Math.abs(this.a - other.a) < precision);\n    }\n    /**\n     * Returns a new Color which is this Color added to other.\n     *\n     * @param other - The other color to add.\n     * @return - Returns a new color.\n     */\n    add(other) {\n        return new Color(this.r + other.r, this.g + other.g, this.b + other.b, this.a + other.a);\n    }\n    /**\n     * Updates this Color by adding the values from the other color.\n     *\n     * @param other - The other color to add.\n     */\n    addInPlace(other) {\n        this.r += other.r;\n        this.g += other.g;\n        this.b += other.b;\n        this.a += other.a;\n    }\n    /**\n     * Returns a new color which is this color subtracted from other.\n     *\n     * @param other - The other color to subtract.\n     * @return - Returns a new color.\n     */\n    subtract(other) {\n        return new Color(this.r - other.r, this.g - other.g, this.b - other.b, this.a - other.a);\n    }\n    /**\n     * Scales this color by scalar and return the result as a new Vec4.\n     *\n     * @param scalar - The scalar value.\n     * @return - Returns a new color.\n     */\n    scale(scalar) {\n        return new Color(this.r * scalar, this.g * scalar, this.b * scalar, this.a * scalar);\n    }\n    /**\n     * Scales this color by scalar.\n     *\n     * @param scalar - The scalar value.\n     */\n    scaleInPlace(scalar) {\n        this.r *= scalar;\n        this.g *= scalar;\n        this.b *= scalar;\n        this.a *= scalar;\n    }\n    /**\n     * Apply gamma correction to this color\n     *\n     * @param gamma - The gamma value.\n     */\n    applyGamma(gamma) {\n        this.set(Math.pow(this.r, gamma), Math.pow(this.g, gamma), Math.pow(this.b, gamma), this.a);\n    }\n    /**\n     * Converts to linear color space and returns a new color\n     *\n     * @param gamma - The gamma value.\n     * @return - Returns a new color.\n     */\n    toLinear(gamma = 2.2) {\n        return new Color(Math.pow(this.r, gamma), Math.pow(this.g, gamma), Math.pow(this.b, gamma), this.a);\n    }\n    /**\n     * returns a new color value value is mapped into a gamma curve\n     *\n     * @param gamma - The gamma value.\n     * @return - Returns a new color.\n     */\n    toGamma(gamma = 2.2) {\n        return new Color(Math.pow(this.r, 1.0 / gamma), Math.pow(this.g, 1.0 / gamma), Math.pow(this.b, 1.0 / gamma), this.a);\n    }\n    /**\n     * Calculates and returns the luminance of the linear RGB components.\n     *\n     * @return - The return value.\n     */\n    luminance() {\n        return 0.2126 * this.r + 0.7152 * this.g + 0.0722 * this.b;\n    }\n    /**\n     * Performs a linear interpolation between this color and other.\n     *\n     * @param other - The other color to interpolate between.\n     * @param t - Interpolation amount between the two inputs.\n     * @return - Returns a new color.\n     */\n    lerp(other, t) {\n        const ar = this.r;\n        const ag = this.g;\n        const ab = this.b;\n        const aa = this.a;\n        return new Color(ar + t * (other.r - ar), ag + t * (other.g - ag), ab + t * (other.b - ab), aa + t * (other.a - aa));\n    }\n    /**\n     * Creates a random color.\n     *\n     * @param gammaOffset - The gamma offset. Values between 0 and 1 increase the average brightness of the generated color. Values between 0 and -1 darken the generated color values.\n     * @param randomAlpha - Determines whether the alpha channel is random. If not, the alpha values will be 1.0.\n     * @return - The new random color.\n     */\n    static random(gammaOffset = 0.0, randomAlpha = false) {\n        if (gammaOffset > 0.0) {\n            return new Color(gammaOffset + Math.random() * (1.0 - gammaOffset), gammaOffset + Math.random() * (1.0 - gammaOffset), gammaOffset + Math.random() * (1.0 - gammaOffset), randomAlpha ? gammaOffset + Math.random() * (1.0 - gammaOffset) : 1.0);\n        }\n        if (gammaOffset < 0.0) {\n            return new Color(Math.random() * (1.0 + gammaOffset), Math.random() * (1.0 + gammaOffset), Math.random() * (1.0 + gammaOffset), randomAlpha ? Math.random() * (1.0 + gammaOffset) : 1.0);\n        }\n        return new Color(Math.random(), Math.random(), Math.random(), randomAlpha ? Math.random() : 1.0);\n    }\n    /**\n     * Clones this color and returns a new color.\n     *\n     * @return - Returns a new color.\n     */\n    clone() {\n        return new Color(this.r, this.g, this.b, this.a);\n    }\n    /**\n     * Returns the type as an array. Often used to pass types to the GPU.\n     *\n     * @return - Returns as an array.\n     */\n    asArray() {\n        return [this.r, this.g, this.b, this.a];\n    }\n    /**\n     * Setter from an RGB array.\n     *\n     * @param vals - The vals param.\n     */\n    fromArray(vals) {\n        this.r = vals[0] / 255;\n        this.g = vals[1] / 255;\n        this.b = vals[2] / 255;\n        this.a = vals.length == 4 ? vals[3] / 255 : 1.0;\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * The toJSON method encodes this type as a json object for persistence.\n     *\n     * @return - The json object.\n     */\n    toJSON() {\n        return {\n            r: this.r,\n            g: this.g,\n            b: this.b,\n            a: this.a,\n        };\n    }\n    /**\n     * The fromJSON method decodes a json object for this type.\n     *\n     * @param j - The json object.\n     */\n    fromJSON(j) {\n        this.r = j.r;\n        this.g = j.g;\n        this.b = j.b;\n        this.a = j.a;\n    }\n    /**\n     * Loads the state of the value from a binary reader.\n     *\n     * @param reader - The reader value.\n     */\n    readBinary(reader) {\n        this.r = reader.loadFloat32();\n        this.g = reader.loadFloat32();\n        this.b = reader.loadFloat32();\n        this.a = reader.loadFloat32();\n    }\n    /**\n     * Returns the CSS rgba string.\n     *\n     * @return - The return value.\n     */\n    toCSSString() {\n        return ('rgba(' +\n            Math.round(this.r * 255) +\n            ', ' +\n            Math.round(this.g * 255) +\n            ', ' +\n            Math.round(this.b * 255) +\n            ', ' +\n            this.a +\n            ')');\n    }\n    /**\n     * Converts this Vec3 to a string in JSON format.\n     *\n     * @return - The return value.\n     */\n    toString() {\n        // eslint-disable-next-line new-cap\n        return StringFunctions.stringifyJSONWithFixedPrecision(this.toJSON());\n    }\n}\n\nvar EulerAnglesAxisOrder;\n(function (EulerAnglesAxisOrder) {\n    EulerAnglesAxisOrder[EulerAnglesAxisOrder[\"XYZ\"] = 0] = \"XYZ\";\n    EulerAnglesAxisOrder[EulerAnglesAxisOrder[\"YZX\"] = 1] = \"YZX\";\n    EulerAnglesAxisOrder[EulerAnglesAxisOrder[\"ZXY\"] = 2] = \"ZXY\";\n    EulerAnglesAxisOrder[EulerAnglesAxisOrder[\"XZY\"] = 3] = \"XZY\";\n    EulerAnglesAxisOrder[EulerAnglesAxisOrder[\"ZYX\"] = 4] = \"ZYX\";\n    EulerAnglesAxisOrder[EulerAnglesAxisOrder[\"YXZ\"] = 5] = \"YXZ\";\n})(EulerAnglesAxisOrder || (EulerAnglesAxisOrder = {}));\n/**\n * Class representing euler angles. Euler angles describe rotating an object\n * around its various axis in a specified axis order.\n *\n */\nclass EulerAngles {\n    x;\n    y;\n    z;\n    order;\n    /**\n     * Create a euler angle. Receives the xyz values in radians and the order that the rotations are applied.\n     *\n     * Order parameter values: `XYZ: 0`, `YZX: 1`, `ZXY: 2`, `XZY: 3`, `ZYX: 4`, `YXZ: 5`\n     *\n     * It could be either the `string` or the `number` value.\n     *\n     * @param x - The angle of the x axis in radians. Default is 0.\n     * @param y - The angle of the y axis in radians. Default is 0.\n     * @param z - The angle of the z axis in radians. Default is 0.\n     * @param order - The order in which the rotations are applied.\n     */\n    constructor(x = 0, y = 0, z = 0, order = 0) {\n        this.x = x;\n        this.y = y;\n        this.z = z;\n        if (typeof order === 'number' && !isNaN(order))\n            this.order = order;\n        else {\n            switch (order) {\n                case 'XYZ':\n                    this.order = 0;\n                    break;\n                case 'YZX':\n                    this.order = 1;\n                    break;\n                case 'ZXY':\n                    this.order = 2;\n                    break;\n                case 'XZY':\n                    this.order = 3;\n                    break;\n                case 'ZYX':\n                    this.order = 4;\n                    break;\n                case 'YXZ':\n                    this.order = 5;\n                    break;\n                default:\n                    throw new Error('Invalid Euler Angles Order:' + order);\n            }\n        }\n    }\n    /**\n     * Sets the EulerAngles\n     *\n     * @param x - The x axis rotation in radians.\n     * @param y - The y axis rotation in radians.\n     * @param z - The z axis rotation in radians.\n     */\n    set(x, y, z) {\n        this.x = x;\n        this.y = y;\n        this.z = z;\n    }\n    // ///////////////////////////\n    // Persistence\n    /**\n     * Converts this Vec3 to a string in JSON format.\n     *\n     * @return - The return value.\n     */\n    toString() {\n        // eslint-disable-next-line new-cap\n        return StringFunctions.stringifyJSONWithFixedPrecision(this.toJSON());\n    }\n    toJSON() {\n        return {\n            x: this.x,\n            y: this.y,\n            z: this.z,\n            order: this.order,\n        };\n    }\n    fromJSON(json) {\n        this.x = json.x;\n        this.y = json.y;\n        this.z = json.z;\n        this.order = json.order;\n    }\n}\n\n/* eslint-disable new-cap */\n/**\n * A class representing a 3x3 matrix.\n * This matrix class is based on GLM, and is column major.\n *\n */\nclass Mat3 {\n    m00 = 1;\n    m01 = 0;\n    m02 = 0;\n    m10 = 0;\n    m11 = 1;\n    m12 = 0;\n    m20 = 0;\n    m21 = 0;\n    m22 = 1;\n    /**\n     * Initializes the Mat3 class with given data.\n     *\n     * @param m00 - Row 0, column 0.\n     * @param m01 - Row 0, column 1.\n     * @param m02 - Row 0, column 2.\n     * @param m10 - Row 1, column 0.\n     * @param m11 - Row 1, column 1.\n     * @param m12 - Row 1, column 2.\n     * @param m20 - Row 2, column 0.\n     * @param m21 - Row 2, column 1.\n     * @param m22 - Row 2, column 2.\n     */\n    constructor(m00 = 1, m01 = 0, m02 = 0, m10 = 0, m11 = 1, m12 = 0, m20 = 0, m21 = 0, m22 = 1) {\n        if (m00 instanceof Vec3 && m01 instanceof Vec3 && m02 instanceof Vec3) {\n            this.set(m00.x, m00.y, m00.z, m01.x, m01.y, m01.z, m02.x, m02.y, m02.z);\n        }\n        else {\n            this.set(m00, m01, m02, m10, m11, m12, m20, m21, m22);\n        }\n    }\n    /**\n     * Getter for the `x` axis.\n     *\n     * @return - Returns the `x` axis as a Vec3.\n     */\n    get xAxis() {\n        return new Vec3(this.m00, this.m01, this.m02);\n    }\n    /**\n     * Setter for the `x` axis.\n     *\n     * @param vec3 - The vec3 value.\n     */\n    set xAxis(vec3) {\n        this.xAxis.set(vec3.x, vec3.y, vec3.z);\n    }\n    /**\n     * Getter for the `y` axis.\n     * * @return - Returns the `y` axis as a Vec3.\n     */\n    get yAxis() {\n        return new Vec3(this.m10, this.m11, this.m12);\n    }\n    /**\n     * Setter for the `y` axis.\n     * @param vec3 - The vec3 value.\n     */\n    set yAxis(vec3) {\n        this.yAxis.set(vec3.x, vec3.y, vec3.z);\n    }\n    /**\n     * Getter for the `z` axis.\n     * * @return - Returns the `z` axis as a Vec3.\n     */\n    get zAxis() {\n        return new Vec3(this.m20, this.m21, this.m22);\n    }\n    /**\n     * Setter for the `z` axis.\n     * @param vec3 - The vec3 value.\n     */\n    set zAxis(vec3) {\n        this.zAxis.set(vec3.x, vec3.y, vec3.z);\n    }\n    // /////////////////////////////////////////\n    // Setters\n    /**\n     * Sets the state of the Mat3 class\n     *\n     * @param m00 - Row 0, column 0.\n     * @param m01 - Row 0, column 1.\n     * @param m02 - Row 0, column 2.\n     * @param m10 - Row 1, column 0.\n     * @param m11 - Row 1, column 1.\n     * @param m12 - Row 1, column 2.\n     * @param m20 - Row 2, column 0.\n     * @param m21 - Row 2, column 1.\n     * @param m22 - Row 2, column 2.\n     */\n    set(m00 = 1, m01 = 0, m02 = 0, m10 = 0, m11 = 1, m12 = 0, m20 = 0, m21 = 0, m22 = 1) {\n        this.m00 = m00;\n        this.m01 = m01;\n        this.m02 = m02;\n        this.m10 = m10;\n        this.m11 = m11;\n        this.m12 = m12;\n        this.m20 = m20;\n        this.m21 = m21;\n        this.m22 = m22;\n    }\n    /**\n     * Sets state of the Mat3 with the identity  Matrix\n     */\n    setIdentity() {\n        this.set();\n    }\n    /**\n     * Sets state of the Mat3 from another Mat3\n     *\n     * Note: works with either Mat3 or Mat4.\n     *\n     * @param mat - The mat value.\n     */\n    setFromMat(mat) {\n        this.m00 = mat.m00;\n        this.m01 = mat.m01;\n        this.m02 = mat.m02;\n        this.m10 = mat.m10;\n        this.m11 = mat.m11;\n        this.m12 = mat.m12;\n        this.m20 = mat.m20;\n        this.m21 = mat.m21;\n        this.m22 = mat.m22;\n    }\n    /**\n     * Scales and calculates the cross product of the `Vec3` and sets the result in the Mat3\n     * Note: the resulting matrix +Z axis is aligned with the provided direction value.\n     *\n     * @param dir - The dir value.\n     * @param up - The up value.\n     */\n    setFromDirectionAndUpvector(dir, up) {\n        const zAxis = dir;\n        const zLen = zAxis.length();\n        if (zLen < Number.EPSILON) {\n            this.setIdentity();\n            return;\n        }\n        zAxis.scaleInPlace(1 / zLen);\n        const xAxis = up.cross(zAxis);\n        const xLen = xAxis.length();\n        if (xLen > Number.EPSILON)\n            xAxis.scaleInPlace(1 / xLen);\n        const yAxis = zAxis.cross(xAxis);\n        const yLen = yAxis.length();\n        if (yLen > Number.EPSILON)\n            yAxis.scaleInPlace(1 / yLen);\n        this.set(xAxis.x, xAxis.y, xAxis.z, yAxis.x, yAxis.y, yAxis.z, zAxis.x, zAxis.y, zAxis.z);\n    }\n    /**\n     * Inverts a Mat3 and returns the result as a new instance.\n     *\n     * @return - Returns a new Mat3.\n     */\n    inverse() {\n        const a00 = this.m00;\n        const a01 = this.m01;\n        const a02 = this.m02;\n        const a10 = this.m10;\n        const a11 = this.m11;\n        const a12 = this.m12;\n        const a20 = this.m20;\n        const a21 = this.m21;\n        const a22 = this.m22;\n        const b01 = a22 * a11 - a12 * a21;\n        const b11 = -a22 * a10 + a12 * a20;\n        const b21 = a21 * a10 - a11 * a20;\n        // Calculate the determinant\n        let det = a00 * b01 + a01 * b11 + a02 * b21;\n        if (!det) {\n            console.warn('Unable to invert Mat3');\n            return new Mat3();\n        }\n        det = 1.0 / det;\n        return new Mat3(b01 * det, (-a22 * a01 + a02 * a21) * det, (a12 * a01 - a02 * a11) * det, b11 * det, (a22 * a00 - a02 * a20) * det, (-a12 * a00 + a02 * a10) * det, b21 * det, (-a21 * a00 + a01 * a20) * det, (a11 * a00 - a01 * a10) * det);\n    }\n    /**\n     * Inverts a Mat3 in place modifying its values.\n     *\n     * @return - The return value.\n     */\n    invertInPlace() {\n        const a00 = this.m00;\n        const a01 = this.m01;\n        const a02 = this.m02;\n        const a10 = this.m10;\n        const a11 = this.m11;\n        const a12 = this.m12;\n        const a20 = this.m20;\n        const a21 = this.m21;\n        const a22 = this.m22;\n        const b01 = a22 * a11 - a12 * a21;\n        const b11 = -a22 * a10 + a12 * a20;\n        const b21 = a21 * a10 - a11 * a20;\n        // Calculate the determinant\n        let det = a00 * b01 + a01 * b11 + a02 * b21;\n        if (!det) {\n            console.warn('Unable to invert Mat3');\n            return false;\n        }\n        det = 1.0 / det;\n        this.set(b01 * det, (-a22 * a01 + a02 * a21) * det, (a12 * a01 - a02 * a11) * det, b11 * det, (a22 * a00 - a02 * a20) * det, (-a12 * a00 + a02 * a10) * det, b21 * det, (-a21 * a00 + a01 * a20) * det, (a11 * a00 - a01 * a10) * det);\n        return true;\n    }\n    /**\n     * Transposes (exchanges columns with rows) this matrix\n     * and returns the result as a new instance.\n     *\n     * @return - Return a new transposed Mat3.\n     */\n    transpose() {\n        return new Mat3(this.m00, this.m10, this.m20, this.m01, this.m11, this.m21, this.m02, this.m12, this.m22);\n    }\n    /**\n     * Transposes (exchanges columns with rows) this matrix modifying its values.\n     */\n    transposeInPlace() {\n        // If we are transposing ourselves we can skip a few steps but have to cache some values\n        const a01 = this.m01;\n        const a02 = this.m02;\n        const a12 = this.m12;\n        this.m01 = this.m10;\n        this.m02 = this.m20;\n        this.m10 = a01;\n        this.m12 = this.m21;\n        this.m20 = a02;\n        this.m21 = a12;\n    }\n    /**\n     * Transforms the Vec3 with a Mat3.\n     *\n     * @param vec3 - The vec3 value.\n     * @return - Return the result as a new Vec3.\n     */\n    transformVec3(vec3) {\n        return new Vec3(this.m00 * vec3.x + this.m01 * vec3.y + this.m02 * vec3.z, this.m10 * vec3.x + this.m11 * vec3.y + this.m12 * vec3.z, this.m20 * vec3.x + this.m21 * vec3.y + this.m22 * vec3.z);\n    }\n    /**\n     * Clones this Mat3 returning a new instance.\n     *\n     * @return - Returns a new Mat3.\n     */\n    clone() {\n        return new Mat3(this.m00, this.m01, this.m02, this.m10, this.m11, this.m12, this.m20, this.m21, this.m22);\n    }\n    // ///////////////////////////\n    // Persistence\n    /**\n     * Loads the state of the value from a binary reader.\n     *\n     * @param reader - The reader value.\n     */\n    readBinary(reader) {\n        const data = reader.loadFloat32Array(9);\n        this.fromArray(data);\n    }\n    /**\n     * The toJSON method encodes this type as a json object for persistence.\n     */\n    toJSON() {\n        return this.asArray();\n    }\n    /**\n     * The fromJSON method decodes a json object for this type.\n     *\n     * @param json - The json param.\n     */\n    fromJSON(json) {\n        this.fromArray(json);\n    }\n    // ///////////////////////////\n    // Debugging\n    /**\n     * Converts this Vec3 to a string in JSON format.\n     *\n     * @return - The return value.\n     */\n    toString() {\n        // eslint-disable-next-line new-cap\n        return StringFunctions.stringifyJSONWithFixedPrecision(this.toJSON());\n    }\n    /**\n     * Returns current Math type data as array. Often used to pass types to the GPU.\n     *\n     * @return - Returns the result as an array.\n     */\n    asArray() {\n        return [this.m00, this.m01, this.m02, this.m10, this.m11, this.m12, this.m20, this.m21, this.m22];\n    }\n    fromArray(array) {\n        this.m00 = array[0];\n        this.m01 = array[1];\n        this.m02 = array[2];\n        this.m10 = array[3];\n        this.m11 = array[4];\n        this.m12 = array[5];\n        this.m20 = array[6];\n        this.m21 = array[7];\n        this.m22 = array[8];\n    }\n}\n\n/**\n * A class representing a 4x4 matrix.\n * This matrix class is based on GLM, and is column major.\n *\n */\nclass Mat4 {\n    m00;\n    m01;\n    m02;\n    m03;\n    m10;\n    m11;\n    m12;\n    m13;\n    m20;\n    m21;\n    m22;\n    m23;\n    m30;\n    m31;\n    m32;\n    m33;\n    constructor(m00 = 1, m01 = 0, m02 = 0, m03 = 0, m10 = 0, m11 = 1, m12 = 0, m13 = 0, m20 = 0, m21 = 0, m22 = 1, m23 = 0, m30 = 0, m31 = 0, m32 = 0, m33 = 1) {\n        this.m00 = m00;\n        this.m01 = m01;\n        this.m02 = m02;\n        this.m03 = m03;\n        this.m10 = m10;\n        this.m11 = m11;\n        this.m12 = m12;\n        this.m13 = m13;\n        this.m20 = m20;\n        this.m21 = m21;\n        this.m22 = m22;\n        this.m23 = m23;\n        this.m30 = m30;\n        this.m31 = m31;\n        this.m32 = m32;\n        this.m33 = m33;\n    }\n    /**\n     * Getter for the `x` axis.\n     *\n     * @return - Returns the `x` axis as a Vec3.\n     */\n    get xAxis() {\n        return new Vec3(this.m00, this.m01, this.m02);\n    }\n    /**\n     * Setter for the `x` axis.\n     *\n     * @param vec3 - The vec3 value.\n     */\n    set xAxis(vec3) {\n        this.xAxis.set(vec3.x, vec3.y, vec3.z);\n    }\n    /**\n     * Getter for the `y` axis.\n     *\n     * @return - Returns the `y` axis as a Vec3.\n     */\n    get yAxis() {\n        return new Vec3(this.m10, this.m11, this.m12);\n    }\n    /**\n     * Setter for the `y` axis.\n     *\n     * @param vec3 - The vec3 value.\n     */\n    set yAxis(vec3) {\n        this.yAxis.set(vec3.x, vec3.y, vec3.z);\n    }\n    /**\n     * Getter for the `z` axis.\n     *\n     * @return - Returns the `z` axis as a Vec3.\n     */\n    get zAxis() {\n        return new Vec3(this.m20, this.m21, this.m22);\n    }\n    /**\n     * Setter for the `z` axis.\n     *\n     * @param vec3 - The vec3 value.\n     */\n    set zAxis(vec3) {\n        this.zAxis.set(vec3.x, vec3.y, vec3.z);\n    }\n    /**\n     * Getter for the translation of the matrix. Assumes the translation values are 12, 13, & 14.\n     *\n     * @return - Returns the translation.\n     */\n    get translation() {\n        return new Vec3(this.m30, this.m31, this.m32);\n    }\n    /**\n     * Setter for the translation of the matrix. Assumes the translation values are 12, 13, & 14.\n     *\n     * @param vec3 - The translation.\n     */\n    set translation(vec3) {\n        this.m30 = vec3.x;\n        this.m31 = vec3.y;\n        this.m32 = vec3.z;\n    }\n    // /////////////////////////////////////////\n    // Setters\n    /**\n     * Sets the state of the Mat4 class\n     *\n     * @param m00 - Row 0, column 0.\n     * @param m01 - Row 0, column 1.\n     * @param m02 - Row 0, column 2.\n     * @param m03 - Row 0, column 3.\n     * @param m10 - Row 1, column 0.\n     * @param m11 - Row 1, column 1.\n     * @param m12 - Row 1, column 2.\n     * @param m13 - Row 1, column 3.\n     * @param m20 - Row 2, column 0.\n     * @param m21 - Row 2, column 1.\n     * @param m22 - Row 2, column 2.\n     * @param m23 - Row 2, column 3.\n     * @param m30 - Row 3, column 0.\n     * @param m31 - Row 3, column 1.\n     * @param m32 - Row 3, column 2.\n     * @param m33 - Row 3, column 3.\n     */\n    set(m00 = 1, m01 = 0, m02 = 0, m03 = 0, m10 = 0, m11 = 1, m12 = 0, m13 = 0, m20 = 0, m21 = 0, m22 = 1, m23 = 0, m30 = 0, m31 = 0, m32 = 0, m33 = 1) {\n        this.m00 = m00;\n        this.m01 = m01;\n        this.m02 = m02;\n        this.m03 = m03;\n        this.m10 = m10;\n        this.m11 = m11;\n        this.m12 = m12;\n        this.m13 = m13;\n        this.m20 = m20;\n        this.m21 = m21;\n        this.m22 = m22;\n        this.m23 = m23;\n        this.m30 = m30;\n        this.m31 = m31;\n        this.m32 = m32;\n        this.m33 = m33;\n    }\n    /**\n     * Sets state of the Mat4 with the identity  Matrix\n     */\n    setIdentity() {\n        this.set();\n    }\n    /**\n     * Sets state of the Mat4 from another Mat4\n     *\n     * Note: works with either Mat3 or Mat4.\n     *\n     * @param mat4 - The mat4 value.\n     */\n    setFromMat4(mat4) {\n        this.m00 = mat4.m00;\n        this.m01 = mat4.m01;\n        this.m02 = mat4.m02;\n        this.m03 = mat4.m03;\n        this.m10 = mat4.m10;\n        this.m11 = mat4.m11;\n        this.m12 = mat4.m12;\n        this.m13 = mat4.m13;\n        this.m20 = mat4.m20;\n        this.m21 = mat4.m21;\n        this.m22 = mat4.m22;\n        this.m23 = mat4.m23;\n        this.m30 = mat4.m30;\n        this.m31 = mat4.m31;\n        this.m32 = mat4.m32;\n        this.m33 = mat4.m33;\n    }\n    /**\n     * Converts a Mat4 to a Mat3.\n     *\n     * @return - Returns a new Mat3.\n     */\n    toMat3() {\n        return new Mat3(this.m00, this.m01, this.m02, this.m10, this.m11, this.m12, this.m20, this.m21, this.m22);\n    }\n    /**\n     * Transposes (exchanges columns with rows) this matrix.\n     */\n    transposeInPlace() {\n        // If we are transposing ourselves we can skip a few steps but have to cache some values\n        const a01 = this.m01;\n        const a02 = this.m02;\n        const a03 = this.m03;\n        const a12 = this.m12;\n        const a13 = this.m13;\n        const a23 = this.m23;\n        this.m01 = this.m10;\n        this.m02 = this.m20;\n        this.m03 = this.m30;\n        this.m10 = a01;\n        this.m12 = this.m21;\n        this.m13 = this.m31;\n        this.m20 = a02;\n        this.m21 = a12;\n        this.m23 = this.m32;\n        this.m30 = a03;\n        this.m31 = a13;\n        this.m32 = a23;\n    }\n    /**\n     * Transposes (exchanges columns with rows) this matrix\n     * and returns the result as a new instance.\n     *\n     * @return - Return a new transposed Mat4.\n     */\n    transpose() {\n        return new Mat4(this.m00, this.m10, this.m20, this.m30, this.m01, this.m11, this.m21, this.m31, this.m02, this.m12, this.m22, this.m32, this.m03, this.m13, this.m23, this.m33);\n    }\n    /**\n     * Inverts a Mat4 and returns the result as a new instance.\n     *\n     * @return - Returns a new Mat4.\n     */\n    inverse() {\n        const a00 = this.m00;\n        const a01 = this.m01;\n        const a02 = this.m02;\n        const a03 = this.m03;\n        const a10 = this.m10;\n        const a11 = this.m11;\n        const a12 = this.m12;\n        const a13 = this.m13;\n        const a20 = this.m20;\n        const a21 = this.m21;\n        const a22 = this.m22;\n        const a23 = this.m23;\n        const a30 = this.m30;\n        const a31 = this.m31;\n        const a32 = this.m32;\n        const a33 = this.m33;\n        const b00 = a00 * a11 - a01 * a10;\n        const b01 = a00 * a12 - a02 * a10;\n        const b02 = a00 * a13 - a03 * a10;\n        const b03 = a01 * a12 - a02 * a11;\n        const b04 = a01 * a13 - a03 * a11;\n        const b05 = a02 * a13 - a03 * a12;\n        const b06 = a20 * a31 - a21 * a30;\n        const b07 = a20 * a32 - a22 * a30;\n        const b08 = a20 * a33 - a23 * a30;\n        const b09 = a21 * a32 - a22 * a31;\n        const b10 = a21 * a33 - a23 * a31;\n        const b11 = a22 * a33 - a23 * a32;\n        // Calculate the determinant\n        let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;\n        if (!det) {\n            console.warn('Unable to invert Mat4');\n            return this;\n        }\n        det = 1.0 / det;\n        return new Mat4((a11 * b11 - a12 * b10 + a13 * b09) * det, (a02 * b10 - a01 * b11 - a03 * b09) * det, (a31 * b05 - a32 * b04 + a33 * b03) * det, (a22 * b04 - a21 * b05 - a23 * b03) * det, (a12 * b08 - a10 * b11 - a13 * b07) * det, (a00 * b11 - a02 * b08 + a03 * b07) * det, (a32 * b02 - a30 * b05 - a33 * b01) * det, (a20 * b05 - a22 * b02 + a23 * b01) * det, (a10 * b10 - a11 * b08 + a13 * b06) * det, (a01 * b08 - a00 * b10 - a03 * b06) * det, (a30 * b04 - a31 * b02 + a33 * b00) * det, (a21 * b02 - a20 * b04 - a23 * b00) * det, (a11 * b07 - a10 * b09 - a12 * b06) * det, (a00 * b09 - a01 * b07 + a02 * b06) * det, (a31 * b01 - a30 * b03 - a32 * b00) * det, (a20 * b03 - a21 * b01 + a22 * b00) * det);\n    }\n    /**\n     * Inverts a Mat4.\n     *\n     * @return - The return value.\n     */\n    invertInPlace() {\n        const a00 = this.m00;\n        const a01 = this.m01;\n        const a02 = this.m02;\n        const a03 = this.m03;\n        const a10 = this.m10;\n        const a11 = this.m11;\n        const a12 = this.m12;\n        const a13 = this.m13;\n        const a20 = this.m20;\n        const a21 = this.m21;\n        const a22 = this.m22;\n        const a23 = this.m23;\n        const a30 = this.m30;\n        const a31 = this.m31;\n        const a32 = this.m32;\n        const a33 = this.m33;\n        const b00 = a00 * a11 - a01 * a10;\n        const b01 = a00 * a12 - a02 * a10;\n        const b02 = a00 * a13 - a03 * a10;\n        const b03 = a01 * a12 - a02 * a11;\n        const b04 = a01 * a13 - a03 * a11;\n        const b05 = a02 * a13 - a03 * a12;\n        const b06 = a20 * a31 - a21 * a30;\n        const b07 = a20 * a32 - a22 * a30;\n        const b08 = a20 * a33 - a23 * a30;\n        const b09 = a21 * a32 - a22 * a31;\n        const b10 = a21 * a33 - a23 * a31;\n        const b11 = a22 * a33 - a23 * a32;\n        // Calculate the determinant\n        let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;\n        if (!det) {\n            console.warn('Unable to invert Mat4');\n            return false;\n        }\n        det = 1.0 / det;\n        this.set((a11 * b11 - a12 * b10 + a13 * b09) * det, (a02 * b10 - a01 * b11 - a03 * b09) * det, (a31 * b05 - a32 * b04 + a33 * b03) * det, (a22 * b04 - a21 * b05 - a23 * b03) * det, (a12 * b08 - a10 * b11 - a13 * b07) * det, (a00 * b11 - a02 * b08 + a03 * b07) * det, (a32 * b02 - a30 * b05 - a33 * b01) * det, (a20 * b05 - a22 * b02 + a23 * b01) * det, (a10 * b10 - a11 * b08 + a13 * b06) * det, (a01 * b08 - a00 * b10 - a03 * b06) * det, (a30 * b04 - a31 * b02 + a33 * b00) * det, (a21 * b02 - a20 * b04 - a23 * b00) * det, (a11 * b07 - a10 * b09 - a12 * b06) * det, (a00 * b09 - a01 * b07 + a02 * b06) * det, (a31 * b01 - a30 * b03 - a32 * b00) * det, (a20 * b03 - a21 * b01 + a22 * b00) * det);\n        return true;\n    }\n    /**\n     * Sets this matrix as the inverse of the given Mat4.\n     *\n     * @param mat4 - The mat4 value.\n     * @return - In case the `determinant` can't be calculated, a `null` will be returned, otherwise, nothing is returned\n     */\n    setInverse(mat4) {\n        const a00 = mat4.m00;\n        const a01 = mat4.m01;\n        const a02 = mat4.m02;\n        const a03 = mat4.m03;\n        const a10 = mat4.m10;\n        const a11 = mat4.m11;\n        const a12 = mat4.m12;\n        const a13 = mat4.m13;\n        const a20 = mat4.m20;\n        const a21 = mat4.m21;\n        const a22 = mat4.m22;\n        const a23 = mat4.m23;\n        const a30 = mat4.m30;\n        const a31 = mat4.m31;\n        const a32 = mat4.m32;\n        const a33 = mat4.m33;\n        const b00 = a00 * a11 - a01 * a10;\n        const b01 = a00 * a12 - a02 * a10;\n        const b02 = a00 * a13 - a03 * a10;\n        const b03 = a01 * a12 - a02 * a11;\n        const b04 = a01 * a13 - a03 * a11;\n        const b05 = a02 * a13 - a03 * a12;\n        const b06 = a20 * a31 - a21 * a30;\n        const b07 = a20 * a32 - a22 * a30;\n        const b08 = a20 * a33 - a23 * a30;\n        const b09 = a21 * a32 - a22 * a31;\n        const b10 = a21 * a33 - a23 * a31;\n        const b11 = a22 * a33 - a23 * a32;\n        // Calculate the determinant\n        let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;\n        if (!det) {\n            throw new Error('Unable to invert Mat4');\n        }\n        det = 1.0 / det;\n        this.set((a11 * b11 - a12 * b10 + a13 * b09) * det, (a02 * b10 - a01 * b11 - a03 * b09) * det, (a31 * b05 - a32 * b04 + a33 * b03) * det, (a22 * b04 - a21 * b05 - a23 * b03) * det, (a12 * b08 - a10 * b11 - a13 * b07) * det, (a00 * b11 - a02 * b08 + a03 * b07) * det, (a32 * b02 - a30 * b05 - a33 * b01) * det, (a20 * b05 - a22 * b02 + a23 * b01) * det, (a10 * b10 - a11 * b08 + a13 * b06) * det, (a01 * b08 - a00 * b10 - a03 * b06) * det, (a30 * b04 - a31 * b02 + a33 * b00) * det, (a21 * b02 - a20 * b04 - a23 * b00) * det, (a11 * b07 - a10 * b09 - a12 * b06) * det, (a00 * b09 - a01 * b07 + a02 * b06) * det, (a31 * b01 - a30 * b03 - a32 * b00) * det, (a20 * b03 - a21 * b01 + a22 * b00) * det);\n    }\n    /**\n     * Multiplies two Mat4s and returns the result as a new instance.\n     *\n     * @param other - The other Mat4 to multiply with.\n     * @return - Returns a new Mat4.\n     */\n    multiply(other) {\n        const a00 = this.m00;\n        const a01 = this.m01;\n        const a02 = this.m02;\n        const a03 = this.m03;\n        const a10 = this.m10;\n        const a11 = this.m11;\n        const a12 = this.m12;\n        const a13 = this.m13;\n        const a20 = this.m20;\n        const a21 = this.m21;\n        const a22 = this.m22;\n        const a23 = this.m23;\n        const a30 = this.m30;\n        const a31 = this.m31;\n        const a32 = this.m32;\n        const a33 = this.m33;\n        // Cache only the current line of the second matrix\n        const b = other.asArray();\n        let b0 = b[0];\n        let b1 = b[1];\n        let b2 = b[2];\n        let b3 = b[3];\n        const result = new Mat4();\n        result.m00 = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;\n        result.m01 = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;\n        result.m02 = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;\n        result.m03 = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;\n        b0 = b[4];\n        b1 = b[5];\n        b2 = b[6];\n        b3 = b[7];\n        result.m10 = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;\n        result.m11 = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;\n        result.m12 = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;\n        result.m13 = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;\n        b0 = b[8];\n        b1 = b[9];\n        b2 = b[10];\n        b3 = b[11];\n        result.m20 = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;\n        result.m21 = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;\n        result.m22 = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;\n        result.m23 = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;\n        b0 = b[12];\n        b1 = b[13];\n        b2 = b[14];\n        b3 = b[15];\n        result.m30 = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;\n        result.m31 = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;\n        result.m32 = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;\n        result.m33 = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;\n        return result;\n    }\n    /**\n     * Multiplies two Mat4s in place explicitly not using SIMD.\n     *\n     * @param other - The other Mat4 to multiply with.\n     * @return - Returns a new Mat4.\n     */\n    multiplyInPlace(other) {\n        const a = this.asArray();\n        const a00 = a[0];\n        const a01 = a[1];\n        const a02 = a[2];\n        const a03 = a[3];\n        const a10 = a[4];\n        const a11 = a[5];\n        const a12 = a[6];\n        const a13 = a[7];\n        const a20 = a[8];\n        const a21 = a[9];\n        const a22 = a[10];\n        const a23 = a[11];\n        const a30 = a[12];\n        const a31 = a[13];\n        const a32 = a[14];\n        const a33 = a[15];\n        // Cache only the current line of the second matrix\n        const b = other.asArray();\n        let b0 = b[0];\n        let b1 = b[1];\n        let b2 = b[2];\n        let b3 = b[3];\n        this.m00 = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;\n        this.m01 = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;\n        this.m02 = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;\n        this.m03 = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;\n        b0 = b[4];\n        b1 = b[5];\n        b2 = b[6];\n        b3 = b[7];\n        this.m10 = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;\n        this.m11 = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;\n        this.m12 = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;\n        this.m13 = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;\n        b0 = b[8];\n        b1 = b[9];\n        b2 = b[10];\n        b3 = b[11];\n        this.m20 = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;\n        this.m21 = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;\n        this.m22 = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;\n        this.m23 = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;\n        b0 = b[12];\n        b1 = b[13];\n        b2 = b[14];\n        b3 = b[15];\n        this.m30 = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;\n        this.m31 = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;\n        this.m32 = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;\n        this.m33 = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;\n        return this;\n    }\n    /**\n     * Post multiplies two Mat4s in place explicitly not using SIMD.\n     *\n     * @param other - The other Mat4 to multiply with.\n     * @return - Returns the result as a new Mat4.\n     */\n    postMultiplyInPlace(other) {\n        const a = other.asArray();\n        const a00 = a[0];\n        const a01 = a[1];\n        const a02 = a[2];\n        const a03 = a[3];\n        const a10 = a[4];\n        const a11 = a[5];\n        const a12 = a[6];\n        const a13 = a[7];\n        const a20 = a[8];\n        const a21 = a[9];\n        const a22 = a[10];\n        const a23 = a[11];\n        const a30 = a[12];\n        const a31 = a[13];\n        const a32 = a[14];\n        const a33 = a[15];\n        // Cache only the current line of the second matrix\n        const b = this.asArray();\n        let b0 = b[0];\n        let b1 = b[1];\n        let b2 = b[2];\n        let b3 = b[3];\n        this.m00 = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;\n        this.m01 = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;\n        this.m02 = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;\n        this.m03 = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;\n        b0 = b[4];\n        b1 = b[5];\n        b2 = b[6];\n        b3 = b[7];\n        this.m10 = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;\n        this.m11 = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;\n        this.m12 = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;\n        this.m13 = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;\n        b0 = b[8];\n        b1 = b[9];\n        b2 = b[10];\n        b3 = b[11];\n        this.m20 = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;\n        this.m21 = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;\n        this.m22 = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;\n        this.m23 = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;\n        b0 = b[12];\n        b1 = b[13];\n        b2 = b[14];\n        b3 = b[15];\n        this.m30 = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;\n        this.m31 = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;\n        this.m32 = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;\n        this.m33 = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;\n        return this;\n    }\n    /**\n     * Translate a Mat4 by the given vector not using SIMD.\n     *\n     * @param v3 - The given vector to translate along.\n     * @return - The return value.\n     */\n    translateInPlace(v3) {\n        const a = this.asArray();\n        const x = v3.x;\n        const y = v3.y;\n        const z = v3.z;\n        a[12] = a[0] * x + a[4] * y + a[8] * z + a[12];\n        a[13] = a[1] * x + a[5] * y + a[9] * z + a[13];\n        a[14] = a[2] * x + a[6] * y + a[10] * z + a[14];\n        a[15] = a[3] * x + a[7] * y + a[11] * z + a[15];\n        return this;\n    }\n    /**\n     * Generates a look-at matrix with the given position, focal point, and up axis.\n     *\n     * @param pos - Position of the viewer.\n     * @param target - Point the viewer is looking at.\n     * @param up - Vec3 pointing up.\n     */\n    setLookAt(pos, target, up) {\n        const zAxis = pos.subtract(target);\n        const zLen = zAxis.length();\n        if (zLen < Number.EPSILON) {\n            this.setIdentity();\n            return;\n        }\n        zAxis.scaleInPlace(1.0 / zLen);\n        const xAxis = up.cross(zAxis);\n        const xLen = xAxis.length();\n        if (xLen > Number.EPSILON)\n            xAxis.scaleInPlace(1.0 / xLen);\n        const yAxis = zAxis.cross(xAxis);\n        const yLen = yAxis.length();\n        if (yLen > Number.EPSILON)\n            yAxis.scaleInPlace(1.0 / yLen);\n        /* eslint-disable prettier/prettier*/\n        this.set(xAxis.x, xAxis.y, xAxis.z, 0, yAxis.x, yAxis.y, yAxis.z, 0, zAxis.x, zAxis.y, zAxis.z, 0, pos.x, pos.y, pos.z, 1);\n        /* eslint-enable prettier/prettier*/\n    }\n    /**\n     * Creates a matrix from a given angle around a given axis.\n     * This is equivalent to (but much faster than):\n     *\n     *     mat4.identity(dest);\n     *     mat4.rotate(dest, dest, rad, axis);\n     *\n     * @param axis - The axis to rotate around.\n     * @param rad - The angle to rotate the matrix by.\n     * @return - The return value.\n     */\n    setRotation(axis, rad) {\n        const len = axis.length();\n        if (Math.abs(len) < Number.EPSILON) {\n            return null;\n        }\n        const x = axis.x / len;\n        const y = axis.y / len;\n        const z = axis.z / len;\n        const s = Math.sin(rad);\n        const c = Math.cos(rad);\n        const t = 1 - c;\n        // Perform rotation-specific matrix multiplication\n        const a = this.asArray();\n        a[0] = x * x * t + c;\n        a[1] = y * x * t + z * s;\n        a[2] = z * x * t - y * s;\n        a[3] = 0;\n        a[4] = x * y * t - z * s;\n        a[5] = y * y * t + c;\n        a[6] = z * y * t + x * s;\n        a[7] = 0;\n        a[8] = x * z * t + y * s;\n        a[9] = y * z * t - x * s;\n        a[10] = z * z * t + c;\n        a[11] = 0;\n        a[12] = 0;\n        a[13] = 0;\n        a[14] = 0;\n        a[15] = 1;\n        return this;\n    }\n    /**\n     * Creates a matrix from the given angle around the X axis.\n     * This is equivalent to (but much faster than):\n     *\n     *     mat4.identity(dest);\n     *     mat4.rotateX(dest, dest, rad);\n     *\n     * @param rad - The angle to rotate the matrix by.\n     * @return - The return value.\n     */\n    setXRotation(rad) {\n        const s = Math.sin(rad);\n        const c = Math.cos(rad);\n        // Perform axis-specific matrix multiplication\n        const a = this.asArray();\n        /* eslint-disable prettier/prettier*/\n        a[0] = 1;\n        a[1] = 0;\n        a[2] = 0;\n        a[3] = 0;\n        a[4] = 0;\n        a[5] = c;\n        a[6] = s;\n        a[7] = 0;\n        a[8] = 0;\n        a[9] = -s;\n        a[10] = c;\n        a[11] = 0;\n        a[12] = 0;\n        a[13] = 0;\n        a[14] = 0;\n        a[15] = 1;\n        /* eslint-enable prettier/prettier*/\n        return this;\n    }\n    /**\n     * Creates a matrix from the given angle around the Y axis.\n     * This is equivalent to (but much faster than):\n     *\n     *     mat4.identity(dest);\n     *     mat4.rotateY(dest, dest, rad);\n     *\n     * @param rad - The angle to rotate the matrix by.\n     * @return - The return value.\n     */\n    setYRotation(rad) {\n        const s = Math.sin(rad);\n        const c = Math.cos(rad);\n        // Perform axis-specific matrix multiplication\n        const a = this.asArray();\n        /* eslint-disable prettier/prettier*/\n        a[0] = c;\n        a[1] = 0;\n        a[2] = -s;\n        a[3] = 0;\n        a[4] = 0;\n        a[5] = 1;\n        a[6] = 0;\n        a[7] = 0;\n        a[8] = s;\n        a[9] = 0;\n        a[10] = c;\n        a[11] = 0;\n        a[12] = 0;\n        a[13] = 0;\n        a[14] = 0;\n        a[15] = 1;\n        /* eslint-enable prettier/prettier*/\n        return this;\n    }\n    /**\n     * Creates a matrix from the given angle around the Z axis.\n     * This is equivalent to (but much faster than):\n     *\n     *     mat4.identity(dest);\n     *     mat4.rotateZ(dest, dest, rad);\n     *\n     * @param rad - The angle to rotate the matrix by.\n     * @return - The return value.\n     */\n    setZRotation(rad) {\n        const s = Math.sin(rad);\n        const c = Math.cos(rad);\n        // Perform axis-specific matrix multiplication\n        const a = this.asArray();\n        /* eslint-disable prettier/prettier*/\n        a[0] = c;\n        a[1] = s;\n        a[2] = 0;\n        a[3] = 0;\n        a[4] = -s;\n        a[5] = c;\n        a[6] = 0;\n        a[7] = 0;\n        a[8] = 0;\n        a[9] = 0;\n        a[10] = 1;\n        a[11] = 0;\n        a[12] = 0;\n        a[13] = 0;\n        a[14] = 0;\n        a[15] = 1;\n        /* eslint-enable prettier/prettier*/\n        return this;\n    }\n    /**\n     * Transforms the Vec4 with a Mat4.\n     *\n     * @param vec - The vec value.\n     * @return - Return the result as a new Vec4.\n     */\n    transformVec4(vec) {\n        const a = this.asArray();\n        const x = vec.x;\n        const y = vec.y;\n        const z = vec.z;\n        const w = vec.w;\n        return new Vec4(a[0] * x + a[4] * y + a[8] * z + a[12] * w, a[1] * x + a[5] * y + a[9] * z + a[13] * w, a[2] * x + a[6] * y + a[10] * z + a[14] * w, a[3] * x + a[7] * y + a[11] * z + a[15] * w);\n    }\n    /**\n     * Transforms the Vec3 with a Mat4.\n     *\n     * @param vec - The vec value.\n     * @return - Return the result as a new Vec3.\n     */\n    transformVec3(vec) {\n        const a = this.asArray();\n        const x = vec.x;\n        const y = vec.y;\n        const z = vec.z;\n        return new Vec3(a[0] * x + a[4] * y + a[8] * z + a[12], a[1] * x + a[5] * y + a[9] * z + a[13], a[2] * x + a[6] * y + a[10] * z + a[14]);\n    }\n    /**\n     * Rotates a given `Vec3` and the result is returned as a new `Vec3`, applying only the top left components of the matrix, so not applying any translation.\n     * @param vec - The vec value.\n     * @return - Return the result as a new Vec3.\n     */\n    rotateVec3(vec) {\n        const a = this.asArray();\n        const x = vec.x;\n        const y = vec.y;\n        const z = vec.z;\n        return new Vec3(a[0] * x + a[4] * y + a[8] * z, a[1] * x + a[5] * y + a[9] * z, a[2] * x + a[6] * y + a[10] * z);\n    }\n    /**\n     * Set the perspective from a Mat4.\n     *\n     * @param fovY - The fovY value.\n     * @param aspect - The aspect value.\n     * @param near - The near value.\n     * @param far - The far value.\n     */\n    setPerspectiveMatrix(fovy, aspect, near, far) {\n        const f = Math.tan(Math.PI * 0.5 - 0.5 * fovy);\n        const rangeInv = 1.0 / (near - far);\n        /* eslint-disable prettier/prettier*/\n        this.set(f / aspect, 0, 0, 0, 0, f, 0, 0, 0, 0, (near + far) * rangeInv, -1, 0, 0, near * far * rangeInv * 2, 0);\n        /* eslint-enable prettier/prettier*/\n    }\n    /**\n     * Calculates the orthographic matrix and sets the state of the Mat4 class\n     *\n     * @param left - The left value.\n     * @param right - The right value.\n     * @param bottom - The bottom value.\n     * @param top - The top value.\n     * @param near - The near value.\n     * @param far - The far value.\n     */\n    setOrthographicMatrix(left, right, bottom, top, near, far) {\n        const lr = 1 / (left - right);\n        const bt = 1 / (bottom - top);\n        const nf = 1 / (near - far);\n        /* eslint-disable prettier/prettier*/\n        this.set(-2 * lr, 0, 0, 0, 0, -2 * bt, 0, 0, 0, 0, 2 * nf, 0, (left + right) * lr, (top + bottom) * bt, (far + near) * nf, 1);\n        /* eslint-enable prettier/prettier*/\n    }\n    /**\n     * Set the Matrix to be a scale matrix.\n     *\n     * @param x - The x value.\n     * @param y - The y value.\n     * @param z - The z value.\n     */\n    setScale(x, y, z) {\n        /* eslint-disable prettier/prettier*/\n        if (x instanceof Vec3) {\n            this.set(x.x, 0, 0, 0, 0, x.y, 0, 0, 0, 0, x.z, 0, 0, 0, 0, 1);\n        }\n        else {\n            this.set(x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, 0, 0, 0, 1);\n        }\n        /* eslint-enable prettier/prettier*/\n    }\n    /**\n     * Transforms a 3x4 matrix into a 4x4 matrix and set the result to the Math4 state.\n     *\n     * @param m3x4 - The m3x4 value.\n     */\n    setFromMat3x4Array(m3x4) {\n        /* eslint-disable prettier/prettier*/\n        this.set(m3x4[0], m3x4[1], m3x4[2], 0, m3x4[3], m3x4[4], m3x4[5], 0, m3x4[6], m3x4[7], m3x4[8], 0, m3x4[9], m3x4[10], m3x4[11], 1);\n        /* eslint-enable prettier/prettier*/\n    }\n    /**\n     * Clones this Mat4 returning a new instance.\n     *\n     * @return - Returns a new Mat4.\n     */\n    clone() {\n        return new Mat4(this.m00, this.m01, this.m02, this.m03, this.m10, this.m11, this.m12, this.m13, this.m20, this.m21, this.m22, this.m23, this.m30, this.m31, this.m32, this.m33);\n    }\n    // ///////////////////////////\n    // Persistence\n    /**\n     * Converts this Vec3 to a string in JSON format.\n     *\n     * @return - The return value.\n     */\n    toString() {\n        // eslint-disable-next-line new-cap\n        return StringFunctions.stringifyJSONWithFixedPrecision(this.toJSON());\n    }\n    /**\n     * The toJSON method encodes this type as a json object for persistence.\n     *\n     */\n    toJSON() {\n        return this.asArray();\n    }\n    /**\n     * The fromJSON method decodes a json object for this type.\n     *\n     */\n    fromJSON(json) {\n        this.fromArray(json);\n    }\n    /**\n     * Loads the state of the value from a binary reader.\n     *\n     * @param reader - The reader value.\n     */\n    readBinary(reader) {\n        this.fromArray(reader.loadFloat32Array(16));\n    }\n    /**\n     * Returns current Math type data as array. Often used to pass types to the GPU.\n     *\n     * @return - Returns the result as an array.\n     */\n    asArray() {\n        return [\n            this.m00,\n            this.m01,\n            this.m02,\n            this.m03,\n            this.m10,\n            this.m11,\n            this.m12,\n            this.m13,\n            this.m20,\n            this.m21,\n            this.m22,\n            this.m23,\n            this.m30,\n            this.m31,\n            this.m32,\n            this.m33,\n        ];\n    }\n    fromArray(array) {\n        this.m00 = array[0];\n        this.m01 = array[1];\n        this.m02 = array[2];\n        this.m03 = array[3];\n        this.m10 = array[4];\n        this.m11 = array[5];\n        this.m12 = array[6];\n        this.m13 = array[7];\n        this.m20 = array[8];\n        this.m21 = array[9];\n        this.m22 = array[10];\n        this.m23 = array[11];\n        this.m30 = array[12];\n        this.m31 = array[13];\n        this.m32 = array[14];\n        this.m33 = array[15];\n    }\n}\n\n/* eslint-disable no-unused-vars */\n/**\n * Class representing a quaternion. Quaternions are used to represent 3 dimensional rotations.\n *\n * While Quaternions are difficult to understand they have important mathematical properties that make them very useful in 3d engines.\n * They can be directly multiplied together in the same was as matrices.\n * They can be interpolated from one value to another while maintaining constant angular velocity.\n * They can be converted to other more easily understood representations such as EulerAngles or Matrices.\n *\n\n */\nclass Quat {\n    x;\n    y;\n    z;\n    w;\n    /**\n     * Creates a quaternion.\n     */\n    constructor(x = 0, y = 0, z = 0, w = 1) {\n        this.x = x;\n        this.y = y;\n        this.z = z;\n        this.w = w;\n    }\n    /**\n     * Setter from scalar components.\n     *\n     * @param x - The x axis rotation.\n     * @param y  - The y axis rotation.\n     * @param z  - The z axis rotation.\n     * @param w  - The w value.\n     */\n    set(x, y, z, w) {\n        this.x = x;\n        this.y = y;\n        this.z = z;\n        this.w = w;\n    }\n    /**\n     * Setter from another vector.\n     *\n     * @param other - The other vector to set from.\n     */\n    setFromOther(other) {\n        this.x = other.x;\n        this.y = other.y;\n        this.z = other.z;\n        this.w = other.w;\n    }\n    /**\n     * Set this Quat from a euler rotation.\n     *\n     * @param eulerAngles - The euler angles rotation.\n     */\n    setFromEulerAngles(eulerAngles) {\n        const ordered = new Vec3();\n        switch (eulerAngles.order) {\n            case EulerAnglesAxisOrder.XYZ:\n                ordered.set(eulerAngles.x, -eulerAngles.y, eulerAngles.z);\n                break;\n            case EulerAnglesAxisOrder.YZX:\n                ordered.set(eulerAngles.y, -eulerAngles.z, eulerAngles.x);\n                break;\n            case EulerAnglesAxisOrder.ZXY:\n                ordered.set(eulerAngles.z, -eulerAngles.x, eulerAngles.y);\n                break;\n            case EulerAnglesAxisOrder.XZY:\n                ordered.set(eulerAngles.x, eulerAngles.z, eulerAngles.y);\n                break;\n            case EulerAnglesAxisOrder.ZYX:\n                ordered.set(eulerAngles.z, eulerAngles.y, eulerAngles.x);\n                break;\n            case EulerAnglesAxisOrder.YXZ:\n                ordered.set(eulerAngles.y, eulerAngles.x, eulerAngles.z);\n                break;\n            default:\n                throw new Error(`Invalid EulerAngles order: ${eulerAngles.order}`);\n        }\n        const ti = ordered.x * 0.5;\n        const tj = ordered.y * 0.5;\n        const tk = ordered.z * 0.5;\n        const ci = Math.cos(ti);\n        const cj = Math.cos(tj);\n        const ck = Math.cos(tk);\n        const si = Math.sin(ti);\n        const sj = Math.sin(tj);\n        const sk = Math.sin(tk);\n        const cc = ci * ck;\n        const cs = ci * sk;\n        const sc = si * ck;\n        const ss = si * sk;\n        const ai = cj * sc - sj * cs;\n        const aj = cj * ss + sj * cc;\n        const ak = cj * cs - sj * sc;\n        this.w = cj * cc + sj * ss;\n        switch (eulerAngles.order) {\n            case 0:\n                // ' XYZ'\n                this.x = ai;\n                this.y = -aj;\n                this.z = ak;\n                break;\n            case 1:\n                // 'YZX'\n                this.x = ak;\n                this.y = ai;\n                this.z = -aj;\n                break;\n            case 2:\n                // 'ZXY'\n                this.x = -aj;\n                this.y = ak;\n                this.z = ai;\n                break;\n            case 3:\n                // 'XZY'\n                this.x = ai;\n                this.y = ak;\n                this.z = aj;\n                break;\n            case 4:\n                // 'ZYX'\n                this.x = ak;\n                this.y = aj;\n                this.z = ai;\n                break;\n            case 5:\n                // 'YXZ'\n                this.x = aj;\n                this.y = ai;\n                this.z = ak;\n                break;\n            default:\n                throw new Error(`Invalid EulerAngles order: ${eulerAngles.order}`);\n        }\n    }\n    /**\n     * Converts Quat to an EulerAngles\n     *\n     * @param rotationOrder - The order in which the rotations are applied.\n     * @return - The return value.\n     */\n    toEulerAngles(rotationOrder) {\n        const ordered = new Vec3();\n        switch (rotationOrder) {\n            case EulerAnglesAxisOrder.XYZ:\n            case 'XYZ':\n                ordered.set(this.z, this.x, this.y);\n                break;\n            case EulerAnglesAxisOrder.YZX:\n            case 'YZX':\n                ordered.set(this.x, this.y, this.z);\n                break;\n            case EulerAnglesAxisOrder.ZXY:\n            case 'ZXY':\n                ordered.set(this.y, this.z, this.x);\n                break;\n            case EulerAnglesAxisOrder.XZY:\n            case 'XZY':\n                ordered.set(this.y, -this.x, this.z);\n                break;\n            case EulerAnglesAxisOrder.ZYX:\n            case 'ZYX':\n                ordered.set(this.x, -this.z, this.y);\n                break;\n            case EulerAnglesAxisOrder.YXZ:\n            case 'YXZ':\n                ordered.set(this.z, -this.y, this.x);\n                break;\n            default:\n                throw new Error('Invalid rotation order:' + rotationOrder);\n        }\n        const euler = new Vec3();\n        const test = ordered.x * ordered.y + ordered.z * this.w;\n        if (test > 0.49999) {\n            // singularity at north pole\n            euler.y = 2.0 * Math.atan2(ordered.x, this.w);\n            euler.z = Math.PI * 0.5;\n            euler.x = 0.0;\n        }\n        else if (test < -0.49999) {\n            // singularity at south pole\n            euler.y = -2.0 * Math.atan2(ordered.x, this.w);\n            euler.z = Math.PI * -0.5;\n            euler.x = 0.0;\n        }\n        else {\n            const sqx = ordered.x * ordered.x;\n            const sqy = ordered.y * ordered.y;\n            const sqz = ordered.z * ordered.z;\n            euler.y = Math.atan2(2.0 * ordered.y * this.w - 2.0 * ordered.x * ordered.z, 1.0 - 2.0 * sqy - 2.0 * sqz);\n            euler.z = Math.asin(2.0 * test);\n            euler.x = Math.atan2(2.0 * ordered.x * this.w - 2.0 * ordered.y * ordered.z, 1.0 - 2.0 * sqx - 2.0 * sqz);\n        }\n        switch (rotationOrder) {\n            case EulerAnglesAxisOrder.XYZ:\n            case 'XYZ':\n                return new EulerAngles(euler.y, euler.z, euler.x, rotationOrder);\n            case EulerAnglesAxisOrder.YZX:\n            case 'YZX':\n                return new EulerAngles(euler.x, euler.y, euler.z, rotationOrder);\n            case EulerAnglesAxisOrder.ZXY:\n            case 'ZXY':\n                return new EulerAngles(euler.z, euler.x, euler.y, rotationOrder);\n            case EulerAnglesAxisOrder.XZY:\n            case 'XZY':\n                return new EulerAngles(-euler.y, euler.x, euler.z, rotationOrder);\n            case EulerAnglesAxisOrder.ZYX:\n            case 'ZYX':\n                return new EulerAngles(euler.x, euler.z, -euler.y, rotationOrder);\n            case EulerAnglesAxisOrder.YXZ:\n            case 'YXZ':\n                return new EulerAngles(euler.z, -euler.y, euler.x, rotationOrder);\n        }\n    }\n    /**\n     * Set this Quat to a rotation defined by an axis and an angle (in radians).\n     *\n     * @param axis - The axis around which to rotate.\n     * @param angle - The angle to rotate\n     */\n    setFromAxisAndAngle(axis, angle) {\n        const halfAngle = angle / 2.0;\n        const vec = axis.normalize().scale(Math.sin(halfAngle));\n        this.set(vec.x, vec.y, vec.z, Math.cos(halfAngle));\n    }\n    /**\n     * Sets the state of the Quat to look in a particular direction along the z axis.\n     * > The camera looks down the negative z axis, so to set a rotation value\n     * > for the camera, remember to negate the direction vector.\n     *\n     * @param dir - The direction value.\n     * @param up - The up vector.\n     */\n    setFromDirectionAndUpvector(dir, up) {\n        const mat3 = new Mat3();\n        mat3.setFromDirectionAndUpvector(dir, up);\n        this.setFromMat3(mat3);\n    }\n    /**\n     * Sets the state of the `Quat` from two `Vec3`. The quaternion would then represent the rotation from v0 to v1 in 3d space.\n     *\n     * @param v0 - The v0 unit vector.\n     * @param v1 - The v1 unit vector.\n     */\n    setFrom2Vectors(v0, v1) {\n        const c = v0.cross(v1);\n        const d = v0.dot(v1);\n        const s = Math.sqrt((1 + d) * 2);\n        // this.set( s/2, c.x / s, c.y / s, c.z / s );\n        this.set(c.x / s, c.y / s, c.z / s, s / 2);\n        this.normalizeInPlace();\n    }\n    /**\n     * Set the Quat from a Mat3.\n     *\n     * @param mat3 - The mat3 value.\n     */\n    setFromMat3(mat3) {\n        // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes\n        // article \"Quaternion Calculus and Fast Animation\".\n        const data = mat3.asArray();\n        const fTrace = data[0] + data[4] + data[8];\n        let fRoot;\n        if (fTrace > 0.0) {\n            // |w| > 1/2, may as well choose w > 1/2\n            fRoot = Math.sqrt(fTrace + 1); // 2w\n            this.w = 0.5 * fRoot;\n            fRoot = 0.5 / fRoot; // 1/(4w)\n            this.x = (data[5] - data[7]) * fRoot;\n            this.y = (data[6] - data[2]) * fRoot;\n            this.z = (data[1] - data[3]) * fRoot;\n        }\n        else {\n            // |w| <= 1/2\n            let i = 0;\n            if (data[4] > data[0])\n                i = 1;\n            if (data[8] > data[i * 3 + i])\n                i = 2;\n            const j = (i + 1) % 3;\n            const k = (i + 2) % 3;\n            fRoot = Math.sqrt(data[i * 3 + i] - data[j * 3 + j] - data[k * 3 + k] + 1.0);\n            const array = [0, 0, 0, 0];\n            array[i] = 0.5 * fRoot;\n            fRoot = 0.5 / fRoot;\n            array[3] = (data[j * 3 + k] - data[k * 3 + j]) * fRoot;\n            array[j] = (data[j * 3 + i] + data[i * 3 + j]) * fRoot;\n            array[k] = (data[k * 3 + i] + data[i * 3 + k]) * fRoot;\n            this.fromArray(array);\n        }\n        this.normalizeInPlace();\n    }\n    /**\n     * Set the Quat from a Mat4.\n     *\n     * @param mat4 - The mat4 value.\n     */\n    setFromMat4(mat4) {\n        // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes\n        // article \"Quaternion Calculus and Fast Animation\".\n        const data = mat4.asArray();\n        const fTrace = data[0] + data[5] + data[10];\n        let fRoot;\n        if (fTrace > 0.0) {\n            // |w| > 1/2, may as well choose w > 1/2\n            fRoot = Math.sqrt(fTrace + 1); // 2w\n            this.w = 0.5 * fRoot;\n            fRoot = 0.5 / fRoot; // 1/(4w)\n            this.x = (data[6] - data[9]) * fRoot;\n            this.y = (data[8] - data[2]) * fRoot;\n            this.z = (data[1] - data[4]) * fRoot;\n        }\n        else {\n            // |w| <= 1/2\n            let i = 0;\n            if (data[5] > data[0])\n                i = 1;\n            if (data[10] > data[i * 4 + i])\n                i = 2;\n            const j = (i + 1) % 3;\n            const k = (i + 2) % 3;\n            fRoot = Math.sqrt(data[i * 4 + i] - data[j * 4 + j] - data[k * 4 + k] + 1.0);\n            const array = [0, 0, 0, 0];\n            array[i] = 0.5 * fRoot;\n            fRoot = 0.5 / fRoot;\n            array[3] = (data[j * 4 + k] - data[k * 4 + j]) * fRoot;\n            array[j] = (data[j * 4 + i] + data[i * 4 + j]) * fRoot;\n            array[k] = (data[k * 4 + i] + data[i * 4 + k]) * fRoot;\n            this.fromArray(array);\n        }\n        this.normalizeInPlace();\n    }\n    /**\n     * Checks if the angle of the Quat is less that ` Number.EPSILON`\n     *\n     * @return - Returns true or false.\n     */\n    isIdentity() {\n        return this.getAngle() < Number.EPSILON;\n    }\n    /**\n     * Return the angle of the Quat.\n     *\n     * @return - The return value.\n     */\n    getAngle() {\n        return Math.acos(this.w) * 2.0;\n    }\n    /**\n     * Checks if this Quat contains the same values as the other Quat.\n     *\n     * @param other - The other Quat to compare with.\n     * @return - Returns `true` if are the same Vector, otherwise, `false`.\n     */\n    isEqual(other) {\n        return this.x == other.x && this.y == other.y && this.z == other.z && this.w == other.w;\n    }\n    /**\n     * Returns true if this Quat is NOT exactly the same other.\n     *\n     * @param other - The other Quat to compare with.\n     * @return - Returns true or false.\n     */\n    notEquals(other) {\n        return this.x != other.x && this.y != other.y && this.z != other.z && this.w != other.w;\n    }\n    /**\n     * Returns true if this Quat is approximately the same as other\n     *\n     * @param other - The other Quat to compare with.\n     * @param precision - The precision to which the values must match.\n     * @return - Returns true or false.\n     */\n    approxEqual(other, precision = Number.EPSILON) {\n        return (Math.abs(this.x - other.x) < precision &&\n            Math.abs(this.y - other.y) < precision &&\n            Math.abs(this.z - other.z) < precision &&\n            Math.abs(this.w - other.w) < precision);\n    }\n    /**\n     * Adds other to this Quat and return the result as a new Quat.\n     *\n     * @param other - The other Quat to add.\n     * @return - Returns a new Quat.\n     */\n    add(other) {\n        return new Quat(this.x + other.x, this.y + other.y, this.z + other.z, this.w + other.w);\n    }\n    /**\n     * Adds other to this Quat.\n     *\n     * @param other - The other Quat to add.\n     */\n    addInPlace(other) {\n        this.x += other.x;\n        this.y += other.y;\n        this.z += other.z;\n        this.w += other.w;\n    }\n    /**\n     * Subtracts other from this Quat and returns the result as a new Quat.\n     *\n     * @param other - The other Quat to subtract.\n     * @return - Returns a new Quat.\n     */\n    subtract(other) {\n        return new Quat(this.x - other.x, this.y - other.y, this.z - other.z, this.w - other.w);\n    }\n    /**\n     * Scales this Quat by scalar and returns the result as a new Quat.\n     *\n     * @param scalar - The scalar value.\n     * @return - Returns a new Vec3.\n     */\n    scale(scalar) {\n        return new Quat(this.x * scalar, this.y * scalar, this.z * scalar, this.w * scalar);\n    }\n    /**\n     * Scales this Quat by scalar.\n     *\n     * @param scalar - The scalar value.\n     */\n    scaleInPlace(scalar) {\n        this.x *= scalar;\n        this.y *= scalar;\n        this.z *= scalar;\n        this.w *= scalar;\n    }\n    /**\n     * Calculates the length of this Quat.\n     *\n     * @return - Returns the length.\n     */\n    length() {\n        const x = this.x;\n        const y = this.y;\n        const z = this.z;\n        const w = this.w;\n        return Math.sqrt(x * x + y * y + z * z + w * w);\n    }\n    /**\n     * Calculates the squared length of this Quat.\n     *\n     * @return - Returns the length.\n     */\n    lengthSquared() {\n        const x = this.x;\n        const y = this.y;\n        const z = this.z;\n        const w = this.w;\n        return x * x + y * y + z * z + w * w;\n    }\n    /**\n     * Normalizes the Quat and returns it as a new Quat.\n     *\n     * @return - Returns the Quat normalized.\n     */\n    normalize() {\n        const x = this.x;\n        const y = this.y;\n        const z = this.z;\n        const w = this.w;\n        let len = x * x + y * y + z * z + w * w;\n        if (len < Number.EPSILON) {\n            return new Quat();\n        }\n        // TODO: evaluate use of glm_invsqrt here?\n        len = 1 / Math.sqrt(len);\n        return new Quat(x * len, y * len, z * len, w * len);\n    }\n    /**\n     * Normalizes the Quat, modifying its values in place.\n     */\n    normalizeInPlace() {\n        const x = this.x;\n        const y = this.y;\n        const z = this.z;\n        const w = this.w;\n        let len = x * x + y * y + z * z + w * w;\n        if (len < Number.EPSILON) {\n            return;\n        }\n        len = 1 / Math.sqrt(len);\n        this.set(x * len, y * len, z * len, w * len);\n    }\n    /**\n     * Calculates the dot product of this quat against another.\n     *\n     * @param other - The other Quat to compare with.\n     * @return - Returns the dot product.\n     */\n    dot(other) {\n        return this.x * other.x + this.y * other.y + this.z * other.z + this.w * other.w;\n    }\n    /**\n     * Calculates the cross product of two Quats and returns the result as a new Quat.\n     *\n     * @param other - The other Quat to calculate with.\n     * @return - Returns the cross product as a new Quat.\n     */\n    cross(other) {\n        const ax = this.x;\n        const ay = this.y;\n        const az = this.z;\n        const at = this.w;\n        const bx = other.x;\n        const by = other.y;\n        const bz = other.z;\n        const bt = other.w;\n        return new Quat(ay * bz - az * by, az * bt - at * bz, at * bx - ax * bt, ax * by - ay * bx);\n    }\n    /**\n     * Returns the rotational conjugate of this Quat.\n     * Conjugation represents the same rotation of the Quat but\n     * in the opposite direction around the rotational axis.\n     *\n     * @return - the return value.\n     */\n    conjugate() {\n        return new Quat(-this.x, -this.y, -this.z, this.w);\n    }\n    /**\n     * Return the inverse of the `Quat`\n     *\n     * @return - Returns a new Quat.\n     */\n    inverse() {\n        return this.conjugate();\n    }\n    /**\n     * Aligns this quaternion with another one ensuring that the delta between\n     * the Quat values is the shortest path over the hyper-sphere.\n     *\n     *  @param other - The other Quat to divide by.\n     */\n    alignWith(other) {\n        if (this.dot(other) < 0.0) {\n            this.set(-this.x, -this.y, -this.z, -this.w);\n        }\n    }\n    /**\n     * Multiplies two this quat by another returning the result as a new Quat.\n     *\n     * @param other - The other Quat to multiply.\n     * @return - Returns a new Quat.\n     */\n    multiply(other) {\n        const ax = this.x;\n        const ay = this.y;\n        const az = this.z;\n        const aw = this.w;\n        const bx = other.x;\n        const by = other.y;\n        const bz = other.z;\n        const bw = other.w;\n        return new Quat(ax * bw + aw * bx + ay * bz - az * by, ay * bw + aw * by + az * bx - ax * bz, az * bw + aw * bz + ax * by - ay * bx, aw * bw - ax * bx - ay * by - az * bz);\n    }\n    /**\n     * Multiplies this quat by another, modifying its values in place.\n     *\n     * @param other - The other Quat to multiply.\n     */\n    multiplyInPlace(other) {\n        const ax = this.x;\n        const ay = this.y;\n        const az = this.z;\n        const aw = this.w;\n        const bx = other.x;\n        const by = other.y;\n        const bz = other.z;\n        const bw = other.w;\n        this.set(ax * bw + aw * bx + ay * bz - az * by, ay * bw + aw * by + az * bx - ax * bz, az * bw + aw * bz + ax * by - ay * bx, aw * bw - ax * bx - ay * by - az * bz);\n    }\n    /**\n     * Rotates a vector by this quaternion.\n     * Don't forget to normalize the quaternion unless\n     * you want axial translation as well as rotation.\n     *\n     * @param vec3 - The vec3 value.\n     * @return - Returns a new Vec3.\n     */\n    rotateVec3(vec3) {\n        const vq = new Quat(vec3.x, vec3.y, vec3.z, 0.0);\n        const pq = this.multiply(vq).multiply(this.conjugate());\n        return new Vec3(pq.x, pq.y, pq.z);\n    }\n    /**\n     * Sets this quaternion to a rotation by the given angle about the X axis.\n     *\n     * @param rad - Angle (in radians) to rotate.\n     */\n    rotateX(rad) {\n        rad *= 0.5;\n        const ax = this.x;\n        const ay = this.y;\n        const az = this.z;\n        const aw = this.w;\n        const bx = Math.sin(rad);\n        const bw = Math.cos(rad);\n        this.x = ax * bw + aw * bx;\n        this.y = ay * bw + az * bx;\n        this.z = az * bw - ay * bx;\n        this.w = aw * bw - ax * bx;\n    }\n    /**\n     * Sets this quaternion to a rotation by the given angle about the Y axis.\n     *\n     * @param rad - Angle (in radians) to rotate.\n     */\n    rotateY(rad) {\n        rad *= 0.5;\n        const ax = this.x;\n        const ay = this.y;\n        const az = this.z;\n        const aw = this.w;\n        const by = Math.sin(rad);\n        const bw = Math.cos(rad);\n        this.x = ax * bw - az * by;\n        this.y = ay * bw + aw * by;\n        this.z = az * bw + ax * by;\n        this.w = aw * bw - ay * by;\n    }\n    /**\n     * Sets this quaternion to a rotation by the given angle about the Z axis.\n     *\n     * @param rad - Angle (in radians) to rotate.\n     */\n    rotateZ(rad) {\n        rad *= 0.5;\n        const ax = this.x;\n        const ay = this.y;\n        const az = this.z;\n        const aw = this.w;\n        const bz = Math.sin(rad);\n        const bw = Math.cos(rad);\n        this.x = ax * bw + ay * bz;\n        this.y = ay * bw - ax * bz;\n        this.z = az * bw + aw * bz;\n        this.w = aw * bw - az * bz;\n    }\n    /**\n     * Converts this Quat to a Mat3 (a 3x3 matrix).\n     *\n     * @return - TReturns a new Mat3.\n     */\n    toMat3() {\n        const x = this.x;\n        const y = this.y;\n        const z = this.z;\n        const w = this.w;\n        const x2 = x + x;\n        const y2 = y + y;\n        const z2 = z + z;\n        const xx = x * x2;\n        const yx = y * x2;\n        const yy = y * y2;\n        const zx = z * x2;\n        const zy = z * y2;\n        const zz = z * z2;\n        const wx = w * x2;\n        const wy = w * y2;\n        const wz = w * z2;\n        const mat3 = new Mat3();\n        mat3.m00 = 1 - yy - zz;\n        mat3.m10 = yx - wz;\n        mat3.m20 = zx + wy;\n        mat3.m01 = yx + wz;\n        mat3.m11 = 1 - xx - zz;\n        mat3.m21 = zy - wx;\n        mat3.m02 = zx - wy;\n        mat3.m12 = zy + wx;\n        mat3.m22 = 1 - xx - yy;\n        return mat3;\n    }\n    /**\n     * Calculates a Vec3 value aligned with the X axis of this quaternion.\n     *\n     * @return - The resulting Vec3 value\n     */\n    getXaxis() {\n        const xy = this.x * this.y;\n        const xz = this.x * this.z;\n        const yy = this.y * this.y;\n        const yw = this.y * this.w;\n        const zz = this.z * this.z;\n        const zw = this.z * this.w;\n        return new Vec3(1.0 - 2.0 * (zz + yy), 2.0 * (xy + zw), 2.0 * (xz - yw));\n    }\n    /**\n     * Calculates a Vec3 value aligned with the Y axis of this quaternion.\n     *\n     * @return - The resulting Vec3 value\n     */\n    getYaxis() {\n        const xx = this.x * this.x;\n        const xy = this.x * this.y;\n        const xw = this.x * this.w;\n        const yz = this.y * this.z;\n        const zz = this.z * this.z;\n        const zw = this.z * this.w;\n        return new Vec3(2.0 * (xy - zw), 1.0 - 2.0 * (zz + xx), 2.0 * (yz + xw));\n    }\n    /**\n     * Calculates a Vec3 value aligned with the Z axis of this quaternion.\n     *\n     * @return - The resulting Vec3 value\n     */\n    getZaxis() {\n        const xx = this.x * this.x;\n        const xz = this.x * this.z;\n        const xw = this.x * this.w;\n        const yy = this.y * this.y;\n        const yz = this.y * this.z;\n        const yw = this.y * this.w;\n        // const temp = new Vec3()\n        return new Vec3(2.0 * (yw + xz), 2.0 * (yz - xw), 1.0 - 2.0 * (yy + xx));\n    }\n    /**\n     * Reflects this quaternion according to the axis provided.\n     *\n     * @param axisIndex - An integer with value of 0 for the X axis, 1 for the Y axis, and 2 for the Z axis.\n     * @return - Returns a new Quat.\n     */\n    mirror(axisIndex) {\n        switch (axisIndex) {\n            case 0:\n                return new Quat(this.z, this.w, this.x, this.y);\n            case 1:\n                return new Quat(-this.w, this.z, this.y, -this.x);\n            case 2:\n                return new Quat(this.x, this.y, this.z, -this.w);\n            case 0:\n            default:\n                return new Quat(this.z, this.w, this.x, this.y);\n        }\n    }\n    /**\n     * Converts this Quat to a Mat4 (a 4x4 matrix).\n     *\n     * @return - Returns a new Mat4.\n     */\n    toMat4() {\n        const x = this.x;\n        const y = this.y;\n        const z = this.z;\n        const w = this.w;\n        const x2 = x + x;\n        const y2 = y + y;\n        const z2 = z + z;\n        const xx = x * x2;\n        const yx = y * x2;\n        const yy = y * y2;\n        const zx = z * x2;\n        const zy = z * y2;\n        const zz = z * z2;\n        const wx = w * x2;\n        const wy = w * y2;\n        const wz = w * z2;\n        // Set the columns\n        const mat4 = new Mat4();\n        mat4.m00 = 1 - yy - zz;\n        mat4.m10 = yx - wz;\n        mat4.m20 = zx + wy;\n        mat4.m01 = yx + wz;\n        mat4.m11 = 1 - xx - zz;\n        mat4.m21 = zy - wx;\n        mat4.m02 = zx - wy;\n        mat4.m12 = zy + wx;\n        mat4.m22 = 1 - xx - yy;\n        return mat4;\n    }\n    /**\n     * Performs a linear interpolation of this Quat towards another Quat, returning the result as a new Quat.\n     *\n     * @param other  - The other Quat to interpolate towards.\n     * @param t - Interpolation ratio.\n     * @return - Returns a new Quat.\n     */\n    lerp(other, t) {\n        const result = new Quat(this.x + t * (other.x - this.x), this.y + t * (other.y - this.y), this.z + t * (other.z - this.z), this.w + t * (other.w - this.w));\n        result.normalizeInPlace();\n        return result;\n    }\n    /**\n     * Performs a spherical linear interpolation of this Quat towards another Quat, returning the result as a new Quat.\n     *\n     * @param other - The other Quat to interpolate towards.\n     * @param t - Interpolation amount between the two inputs.\n     * @return - Returns a new Quat.\n     */\n    slerp(other, lambda) {\n        /// https://www.geometrictools.com/Documentation/FastAndAccurateSlerp.pdf\n        const dotProduct = this.dot(other);\n        if (dotProduct > 0.999)\n            return this;\n        // algorithm adapted from Shoemake's paper\n        // lambda is in (0, π/2]\n        const theta = Math.acos(dotProduct);\n        const st = Math.sin(theta);\n        const sut = Math.sin(lambda * theta);\n        const sout = Math.sin((1 - lambda) * theta);\n        const coeff1 = sout / st;\n        const coeff2 = sut / st;\n        const result = new Quat(coeff1 * this.x + coeff2 * other.x, coeff1 * this.y + coeff2 * other.y, coeff1 * this.z + coeff2 * other.z, coeff1 * this.w + coeff2 * other.w);\n        result.normalizeInPlace();\n        return result;\n    }\n    /**\n     * Clones this Quat and returns a new Quat.\n     *\n     * @return - Returns a new Quat.\n     */\n    clone() {\n        return new Quat(this.x, this.y, this.z, this.w);\n    }\n    /**\n     * Returns the type as an array. Often used to pass types to the GPU.\n     *\n     * @return - Returns as an array.\n     */\n    asArray() {\n        return [this.x, this.y, this.z, this.w];\n    }\n    fromArray(array) {\n        this.x = array[0];\n        this.y = array[1];\n        this.z = array[2];\n        this.w = array[3];\n    }\n    // ///////////////////////////\n    // Persistence\n    /**\n     * Converts this Vec3 to a string in JSON format.\n     *\n     * @return - The return value.\n     */\n    toString() {\n        // eslint-disable-next-line new-cap\n        return StringFunctions.stringifyJSONWithFixedPrecision(this.toJSON());\n    }\n    /**\n     * The toJSON method encodes this type as a json object for persistence.\n     *\n     * @return - The json object.\n     */\n    toJSON() {\n        return {\n            x: this.x,\n            y: this.y,\n            z: this.z,\n            w: this.w,\n        };\n    }\n    /**\n     * The fromJSON method decodes a json object for this type.\n     *\n     * @param j - The json object.\n     */\n    fromJSON(j) {\n        this.x = j.x;\n        this.y = j.y;\n        this.z = j.z;\n        this.w = j.w;\n        this.normalizeInPlace();\n    }\n    /**\n     * Loads the state of the value from a binary reader.\n     *\n     * @param reader - The reader value.\n     */\n    readBinary(reader) {\n        this.x = reader.loadFloat32();\n        this.y = reader.loadFloat32();\n        this.z = reader.loadFloat32();\n        this.w = reader.loadFloat32();\n    }\n}\n\n/* eslint-disable no-unused-vars */\n/**\n * Class representing an Xfo transform, which is a transformation decomposed into 3 component values. Translation, Orientation, and Scaling.\n */\nclass Xfo {\n    tr;\n    ori;\n    sc;\n    /**\n     * Initializes the Xfo object.\n     *\n     * @param tr - The translation value.\n     * @param ori - The orientation value.\n     * @param sc - The scaling value.\n     */\n    constructor(tr = new Vec3(), ori = new Quat(), sc = new Vec3(1, 1, 1)) {\n        this.tr = tr;\n        this.ori = ori;\n        this.sc = sc;\n    }\n    /**\n     * Sets the state of the Xfo object.\n     *\n     * @param tr - The translation value.\n     * @param ori - The orientation value.\n     * @param sc - The scaling value.\n     */\n    set(tr, ori, sc) {\n        this.tr = tr;\n        this.ori = ori;\n        if (sc instanceof Vec3)\n            this.sc = sc;\n    }\n    /**\n     * Sets the state of the Xfo object using another Xfo object.\n     *\n     * @param other - The other Xfo to set from.\n     */\n    setFromOther(other) {\n        this.tr = other.tr;\n        this.ori = other.ori;\n        this.sc = other.sc;\n    }\n    /**\n     * Verifies that the Xfo object is an `identity`, checking that the translation, orientation and scaling attributes are in their initial state.\n     *\n     * @return - The return value.\n     */\n    isIdentity() {\n        return this.tr.isNull() && this.ori.isIdentity() && this.sc.is111();\n    }\n    /**\n     * Checks if this Vec3 contains the same values as the other Vec3.\n     *\n     * @param other - The other Vec3 to compare with.\n     * @return - Returns `true` if are the same Vector, otherwise, `false`.\n     */\n    isEqual(other) {\n        return this.tr.isEqual(other.tr) && this.ori.isEqual(other.ori) && this.sc.isEqual(other.sc);\n    }\n    /**\n     * Returns true if this Vec2 is approximately the same as other.\n     *\n     * @param other - The other Vec3 to compare with.\n     * @param precision - The precision to which the values must match.\n     * @return - Returns true or false.\n     */\n    approxEqual(other, precision = Number.EPSILON) {\n        return ((other.tr ? this.tr.approxEqual(other.tr, precision) : true) &&\n            (other.ori ? this.ori.approxEqual(other.ori, precision) : true) &&\n            (other.sc ? this.sc.approxEqual(other.sc, precision) : true));\n    }\n    /**\n     * The setLookAt method.\n     * @param pos - The position value.\n     * @param target - The target value.\n     * @param up - The up value.\n     */\n    setLookAt(pos, target, up) {\n        // Note: We look along the -z axis. Negate the direction.\n        const dir = pos.subtract(target);\n        const dirLen = dir.length();\n        if (dirLen < Number.EPSILON) {\n            throw new Error('Invalid dir');\n        }\n        this.ori.setFromDirectionAndUpvector(dir, up);\n        this.tr = pos;\n    }\n    /**\n     * Multiplies two Xfo transforms.\n     *\n     * @param xfo - The xfo to multiply with.\n     * @return - Returns an Xfo.\n     */\n    multiply(xfo) {\n        let this_sc = this.sc;\n        // check for non-uniform scale.\n        if (Math.abs(this.sc.y - this.sc.x) > 0.001 ||\n            Math.abs(this.sc.z - this.sc.x) > 0.001 ||\n            Math.abs(this.sc.z - this.sc.y) > 0.001) {\n            const this_mat4 = this.toMat4();\n            const other_mat4 = xfo.ori.toMat4();\n            const resM4 = this_mat4.multiply(other_mat4);\n            this_sc = new Vec3(resM4.xAxis.length(), resM4.yAxis.length(), resM4.zAxis.length());\n        }\n        const result = new Xfo(this.tr.add(this.ori.rotateVec3(this.sc.multiply(xfo.tr))), this.ori.multiply(xfo.ori), this_sc.multiply(xfo.sc));\n        return result;\n    }\n    /**\n     * Returns the inverse of the Xfo object, but returns. the result as a new Xfo.\n     *\n     * @return - Returns a new Xfo.\n     */\n    inverse() {\n        const result = new Xfo();\n        result.ori = this.ori.inverse();\n        // check for non-uniform scale.\n        if (Math.abs(this.sc.y - this.sc.x) > 0.001 ||\n            Math.abs(this.sc.z - this.sc.x) > 0.001 ||\n            Math.abs(this.sc.z - this.sc.y) > 0.001) {\n            const this_mat4 = this.toMat4().inverse();\n            result.sc = new Vec3(this_mat4.xAxis.length(), this_mat4.yAxis.length(), this_mat4.zAxis.length());\n        }\n        else {\n            result.sc = this.sc.inverse();\n        }\n        result.tr = result.ori.rotateVec3(this.tr.negate().multiply(result.sc));\n        return result;\n    }\n    /**\n     * Transforms Xfo object using a `Vec3` object. First scaling it, then rotating and finally adding the result to current translation object.\n     *\n     * @param vec3 - The vec3 value.\n     * @return - The return value.\n     */\n    transformVec3(vec3) {\n        return this.tr.add(this.ori.rotateVec3(this.sc.multiply(vec3)));\n    }\n    /**\n     * Performs a linear interpolation between this Xfo and other.\n     *\n     * @param other - The other Xfo to interpolate towards.\n     * @param t - Interpolation ratio.\n     * @return - Returns a new Xfo.\n     */\n    lerp(other, t) {\n        return new Xfo(this.tr.lerp(other.tr, t), this.ori.slerp(other.ori, t), this.sc.lerp(other.sc, t));\n    }\n    /**\n     * Converts this Xfo to a Mat4 (a 4x4 matrix).\n     *\n     * @return - Returns a new Mat4.\n     */\n    toMat4() {\n        const scl = new Mat4(this.sc.x, 0, 0, 0, 0, this.sc.y, 0, 0, 0, 0, this.sc.z, 0, 0, 0, 0, 1.0);\n        const rot = this.ori.toMat4();\n        const trn = new Mat4();\n        trn.translation = this.tr;\n        return trn.multiply(rot).multiply(scl);\n    }\n    /**\n     * Sets the state of the Xfo object using Mat4.\n     * @param mat4 - The mat4 value.\n     */\n    setFromMat4(mat4) {\n        this.tr = mat4.translation;\n        this.ori.setFromMat4(mat4);\n        this.sc.set(mat4.xAxis.length(), mat4.yAxis.length(), mat4.zAxis.length());\n    }\n    /**\n     * Clones this Xfo and returns a new Xfo.\n     *\n     * @return - Returns a new Xfo.\n     */\n    clone() {\n        return new Xfo(this.tr.clone(), this.ori.clone(), this.sc.clone());\n    }\n    // ///////////////////////////\n    // Persistence\n    /**\n     * The toJSON method encodes this type as a json object for persistence.\n     *\n     * @return - The json object.\n     */\n    toJSON() {\n        const j = {\n            tr: this.tr.toJSON(),\n            ori: this.ori.toJSON(),\n            sc: this.sc.toJSON(),\n        };\n        return j;\n    }\n    /**\n     * The fromJSON method decodes a json object for this type.\n     *\n     * @param j - The json object.\n     */\n    fromJSON(j) {\n        this.tr.fromJSON(j.tr);\n        this.ori.fromJSON(j.ori);\n        if (j.sc) {\n            this.sc.fromJSON(j.sc);\n        }\n    }\n    /**\n     * Loads the state of the value from a binary reader.\n     *\n     * @param reader - The reader value.\n     */\n    readBinary(reader) {\n        this.tr.readBinary(reader);\n        this.ori.readBinary(reader);\n        this.sc.readBinary(reader);\n    }\n    /**\n     * The fromJSON method decodes a json object for this type.\n     *\n     * @return - The return value.\n     */\n    toString() {\n        // eslint-disable-next-line new-cap\n        return StringFunctions.stringifyJSONWithFixedPrecision(this.toJSON());\n    }\n}\n\n/**\n * Represents a box in 2D space. Needing two Vec2 vectors describing the corners\n */\nclass Box2 {\n    p0;\n    p1;\n    /**\n     * Creates a Box2 object using Vec2s.\n     * In case the parameters are not passed by, their values are pre-defined:\n     *\n     * p0 is a Vec2 with {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/POSITIVE_INFINITY|`Number.POSITIVE_INFINITY`}\n     *\n     * p1 is a Vec2 with {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/NEGATIVE_INFINITY|`Number.NEGATIVE_INFINITY`}\n     *\n     * @param p0 - A point representing the corners of a 2D box.\n     * @param p1 - A point representing the corners of a 2D box.\n     */\n    constructor(p0, p1) {\n        if (p0 instanceof Vec2) {\n            this.p0 = p0;\n        }\n        else {\n            this.p0 = new Vec2(Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY);\n        }\n        if (p1 instanceof Vec2) {\n            this.p1 = p1;\n        }\n        else {\n            this.p1 = new Vec2(Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY);\n        }\n    }\n    /**\n     * Sets both Vec2 points\n     *\n     * @param p0 - A point representing the corners of a 2D box.\n     * @param p1 - A point representing the corners of a 2D box.\n     */\n    set(p0, p1) {\n        this.p0 = p0;\n        this.p1 = p1;\n    }\n    /**\n     * Resets the box2 back to an uninitialized state.\n     *\n     * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/POSITIVE_INFINITY|`Number.POSITIVE_INFINITY`}\n     * and {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/NEGATIVE_INFINITY|`Number.NEGATIVE_INFINITY`}\n     */\n    reset() {\n        this.p0.x = Number.POSITIVE_INFINITY;\n        this.p1.x = Number.NEGATIVE_INFINITY;\n        this.p0.y = Number.POSITIVE_INFINITY;\n        this.p1.y = Number.NEGATIVE_INFINITY;\n    }\n    /**\n     * Returns `true` if the box has been expanded to contain a point.\n     *\n     * @return - The return value.\n     */\n    isValid() {\n        return (this.p0.x != Number.POSITIVE_INFINITY &&\n            this.p1.x != Number.NEGATIVE_INFINITY &&\n            this.p0.y != Number.POSITIVE_INFINITY &&\n            this.p1.y != Number.NEGATIVE_INFINITY);\n    }\n    /**\n     * Expands the Box2 to contain the new point.\n     *\n     * @param point - A point represents the corners of a 2D box.\n     */\n    addPoint(point) {\n        if (this.p0.x == Number.POSITIVE_INFINITY || point.x < this.p0.x)\n            this.p0.x = point.x;\n        if (this.p0.y == Number.POSITIVE_INFINITY || point.y < this.p0.y)\n            this.p0.y = point.y;\n        if (this.p1.y == Number.NEGATIVE_INFINITY || point.x > this.p1.x)\n            this.p1.x = point.x;\n        if (this.p1.y == Number.NEGATIVE_INFINITY || point.y > this.p1.y)\n            this.p1.y = point.y;\n    }\n    /**\n     * Returns the length of the diagonal of the box.\n     *\n     * @return - Returns the distance.\n     */\n    size() {\n        return this.p1.distanceTo(this.p0);\n    }\n    /**\n     * Returns the size of a Box2 - the same as size().\n     *\n     * @return - Returns a Vec2.\n     */\n    diagonal() {\n        return this.p1.subtract(this.p0);\n    }\n    /**\n     * Returns the center point of a Box2.\n     *\n     * @return - Returns a Vec2.\n     */\n    center() {\n        const result = this.p1.subtract(this.p0);\n        result.scaleInPlace(0.5);\n        result.addInPlace(this.p0);\n        return result;\n    }\n    /**\n     * Clones this Vec2 and returns a new Vec2.\n     *\n     * @return - Returns a new Vec2.\n     */\n    clone() {\n        return new Box2(this.p0.clone(), this.p1.clone());\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * Encodes `Box2` Class as a JSON object for persistence.\n     *\n     * @return - The json object.\n     */\n    toJSON() {\n        return {\n            p0: this.p0.toJSON(),\n            p1: this.p1.toJSON(),\n        };\n    }\n    /**\n     * Decodes a JSON object to set the state of this class.\n     *\n     * @param j - The json object.\n     */\n    fromJSON(j) {\n        // We need to verify that p0 and p1 axes are numeric, so in case they are not, we restore them to their default values.\n        // This, because 'Infinity' and '-Infinity' are stringified as 'null'.\n        const p0 = {\n            x: MathFunctions.isNumeric(j.p0.x) ? j.p0.x : Number.POSITIVE_INFINITY,\n            y: MathFunctions.isNumeric(j.p0.y) ? j.p0.y : Number.POSITIVE_INFINITY,\n        };\n        const p1 = {\n            x: MathFunctions.isNumeric(j.p1.x) ? j.p1.x : Number.NEGATIVE_INFINITY,\n            y: MathFunctions.isNumeric(j.p1.y) ? j.p1.y : Number.NEGATIVE_INFINITY,\n        };\n        this.p0.fromJSON(p0);\n        this.p1.fromJSON(p1);\n    }\n    /**\n     * Calls `toJSON` method and stringifies it.\n     *\n     * @return - The return value.\n     */\n    toString() {\n        // eslint-disable-next-line new-cap\n        return StringFunctions.stringifyJSONWithFixedPrecision(this.toJSON());\n    }\n}\n\n/* eslint-disable new-cap */\n/**\n * Class representing a mathematical sphere, as opposed to the Sphere class derived from ProceduralMesh.\n *\n */\nclass SphereType {\n    pos;\n    radius;\n    /**\n     * Create a sphere.\n     * @param pos - The position of the sphere.\n     * @param radius - The radius of the sphere.\n     */\n    constructor(pos = new Vec3(), radius = 0) {\n        if (pos instanceof Vec3) {\n            this.pos = pos;\n        }\n        else {\n            this.pos = new Vec3();\n        }\n        this.radius = radius;\n    }\n    /**\n     * Clones this sphere and returns a new sphere.\n     *\n     * @return - Returns a new sphere.\n     */\n    clone() {\n        return new SphereType(this.pos.clone(), this.radius);\n    }\n    /**\n     * Checks if this sphere intersects a box.\n     *\n     * @param box - The box value.\n     * @return - The return value.\n     */\n    intersectsBox(box) {\n        return box.intersectsSphere(this);\n    }\n    // ///////////////////////////\n    // Persistence\n    /**\n     * The toJSON method encodes this type as a json object for persistence.\n     *\n     * @return - The json object.\n     */\n    toJSON() {\n        return {\n            pos: this.pos.toJSON(),\n            radius: this.radius,\n        };\n    }\n    /**\n     * Calls `toJSON` method and stringifies it.\n     *\n     * @return - The return value.\n     */\n    toString() {\n        return StringFunctions.stringifyJSONWithFixedPrecision(this.toJSON());\n    }\n}\n\n/**\n * Class representing a box in 3D space.\n * Represents a box in 3D space defined by two Vec3 values which define opposing corners of the box.\n */\nclass Box3 {\n    p0;\n    p1;\n    /**\n     * Creates a Box3 object using Vec3s.\n     * In case the parameters are not passed by, their values are pre-defined:\n     *\n     * p0 is a Vec2 with {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/POSITIVE_INFINITY|`Number.POSITIVE_INFINITY`}\n     *\n     * p1 is a Vec2 with {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/NEGATIVE_INFINITY|`Number.NEGATIVE_INFINITY`}\n     *\n     * @param p0 - A point representing the corners of a 3D box.\n     * @param p1 - A point representing the corners of a 3D box.\n     */\n    constructor(p0 = new Vec3(Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY), p1 = new Vec3(Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY)) {\n        this.p0 = p0;\n        this.p1 = p1;\n    }\n    /**\n     * Getter for the lower (x, y, z) boundary of the box.\n     *\n     * @return - Returns the minimum Vec3.\n     */\n    get min() {\n        return this.p0;\n    }\n    /**\n     * Getter for the upper (x, y, z) boundary of the box.\n     *\n     * @return - Returns the maximum Vec3.\n     */\n    get max() {\n        return this.p1;\n    }\n    /**\n     * Sets both Vec3 points\n     *\n     * @param p0 - A point representing the corners of a 3D box.\n     * @param p1 - A point representing the corners of a 3D box.\n     */\n    set(p0, p1) {\n        this.p0 = p0;\n        this.p1 = p1;\n    }\n    /**\n     * Resets the box3 back to an uninitialized state.\n     */\n    reset() {\n        this.p0.x = Number.POSITIVE_INFINITY;\n        this.p0.y = Number.POSITIVE_INFINITY;\n        this.p0.z = Number.POSITIVE_INFINITY;\n        this.p1.x = Number.NEGATIVE_INFINITY;\n        this.p1.y = Number.NEGATIVE_INFINITY;\n        this.p1.z = Number.NEGATIVE_INFINITY;\n    }\n    /**\n     * Returns `true` if the box has been expanded to contain a point.\n     *\n     * @return - The return value.\n     */\n    isValid() {\n        return (this.p0.x != Number.POSITIVE_INFINITY &&\n            this.p1.x != Number.NEGATIVE_INFINITY &&\n            this.p0.y != Number.POSITIVE_INFINITY &&\n            this.p1.y != Number.NEGATIVE_INFINITY &&\n            this.p0.z != Number.POSITIVE_INFINITY &&\n            this.p1.z != Number.NEGATIVE_INFINITY);\n    }\n    /**\n     * Expands the Box3 to contain the new point.\n     *\n     * @param point - A point represents the corners of a 3D box.\n     */\n    addPoint(point) {\n        if (point.x != Number.POSITIVE_INFINITY && point.x != Number.NEGATIVE_INFINITY) {\n            if (point.x < this.p0.x)\n                this.p0.x = point.x;\n            if (point.x > this.p1.x)\n                this.p1.x = point.x;\n        }\n        if (point.y != Number.POSITIVE_INFINITY && point.y != Number.NEGATIVE_INFINITY) {\n            if (point.y < this.p0.y)\n                this.p0.y = point.y;\n            if (point.y > this.p1.y)\n                this.p1.y = point.y;\n        }\n        if (point.z != Number.POSITIVE_INFINITY && point.z != Number.NEGATIVE_INFINITY) {\n            if (point.z < this.p0.z)\n                this.p0.z = point.z;\n            if (point.z > this.p1.z)\n                this.p1.z = point.z;\n        }\n    }\n    /**\n     * Adds `Box3` to this `Box3`, of the Xfo instance is passed in the parameters\n     * it proceeds to apply the transform for the Vec3.\n     *\n     * @param box3 - A 3D box.\n     * @param xfo - A 3D transform.\n     */\n    addBox3(box3, transform) {\n        if (transform) {\n            // Transform each corner of the Box3 into the new coordinate system.\n            this.addPoint(transform.transformVec3(box3.p0));\n            this.addPoint(transform.transformVec3(new Vec3(box3.p0.x, box3.p0.y, box3.p1.z)));\n            this.addPoint(transform.transformVec3(new Vec3(box3.p0.x, box3.p1.y, box3.p0.z)));\n            this.addPoint(transform.transformVec3(new Vec3(box3.p1.x, box3.p0.y, box3.p0.z)));\n            this.addPoint(transform.transformVec3(new Vec3(box3.p0.x, box3.p1.y, box3.p1.z)));\n            this.addPoint(transform.transformVec3(new Vec3(box3.p1.x, box3.p0.y, box3.p1.z)));\n            this.addPoint(transform.transformVec3(new Vec3(box3.p1.x, box3.p1.y, box3.p0.z)));\n            this.addPoint(transform.transformVec3(box3.p1));\n        }\n        else {\n            this.addPoint(box3.p0);\n            this.addPoint(box3.p1);\n        }\n    }\n    /**\n     * Returns the length of the diagonal of the box.\n     *\n     * @return - Returns the distance.\n     */\n    size() {\n        return this.p1.distanceTo(this.p0);\n    }\n    /**\n     * Returns the diagonal vector of the B=box from p0 to p1.\n     *\n     * @return - Returns a Box3.\n     */\n    diagonal() {\n        return this.p1.subtract(this.p0);\n    }\n    /**\n     * Returns the center point of a Box3.\n     *\n     * @return - Returns a Vec3.\n     */\n    center() {\n        const result = this.p1.subtract(this.p0);\n        result.scaleInPlace(0.5);\n        result.addInPlace(this.p0);\n        return result;\n    }\n    /**\n     * Converts this Box3 to a Mat4 (a 4x4 matrix). The returned mat4 would transform a unit cube into the shape of the Bounding box.\n     *\n     * @return - Returns a new Mat4.\n     */\n    toMat4() {\n        const scx = this.p1.x - this.p0.x;\n        const scy = this.p1.y - this.p0.y;\n        const scz = this.p1.z - this.p0.z;\n        return new Mat4(scx, 0, 0, 0, 0, scy, 0, 0, 0, 0, scz, 0, this.p0.x, this.p0.y, this.p0.z, 1.0);\n    }\n    /**\n     * Calculates and returns the bounding Sphere of the Box3\n     *\n     * @return - The return value.\n     */\n    getBoundingSphere() {\n        return new SphereType(this.center(), this.diagonal().length() * 0.5);\n    }\n    /**\n     * Determines if this Box3 intersects a given box value.\n     *\n     * @param box - The box to check for intersection against.\n     * @return - Returns true if the shapes intersect.\n     */\n    intersectsBox(box) {\n        // Using 6 splitting planes to rule out intersections.\n        return box.max.x < this.min.x ||\n            box.min.x > this.max.x ||\n            box.max.y < this.min.y ||\n            box.min.y > this.max.y ||\n            box.max.z < this.min.z ||\n            box.min.z > this.max.z\n            ? false\n            : true;\n    }\n    /**\n     * Determines if this Box3 intersects a sphere.\n     *\n     * @param sphere - The sphere to check for intersection against.\n     * @return - Returns true if the shapes intersect.\n     */\n    intersectsSphere(sphere) {\n        let closestPoint = new Vec3();\n        // Find the point on the AABB closest to the sphere center.\n        // this.clampPoint( sphere.center, closestPoint );\n        // If that point is inside the sphere, the AABB and sphere intersect.\n        return closestPoint.distanceTo(sphere.pos) <= sphere.radius * sphere.radius;\n    }\n    /**\n     * Determines if this Box3 intersects a plane.\n     *\n     * @param plane - The plane to check for intersection against.\n     * @return - The return value.\n     */\n    intersectsPlane(plane) {\n        // We compute the minimum and maximum dot product values. If those values\n        // are on the same side (back or front) of the plane, then there is no intersection.\n        let min;\n        let max;\n        if (plane.normal.x > 0) {\n            min = plane.normal.x * this.min.x;\n            max = plane.normal.x * this.max.x;\n        }\n        else {\n            min = plane.normal.x * this.max.x;\n            max = plane.normal.x * this.min.x;\n        }\n        if (plane.normal.y > 0) {\n            min += plane.normal.y * this.min.y;\n            max += plane.normal.y * this.max.y;\n        }\n        else {\n            min += plane.normal.y * this.max.y;\n            max += plane.normal.y * this.min.y;\n        }\n        if (plane.normal.z > 0) {\n            min += plane.normal.z * this.min.z;\n            max += plane.normal.z * this.max.z;\n        }\n        else {\n            min += plane.normal.z * this.max.z;\n            max += plane.normal.z * this.min.z;\n        }\n        return min <= -plane.w && max >= -plane.w;\n    }\n    /**\n     * Clones this Box3 and returns a new Box3.\n     * @return - Returns a new Box3.\n     */\n    clone() {\n        return new Box3(this.p0.clone(), this.p1.clone());\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * Encodes `Box3` Class as a JSON object for persistence.\n     *\n     * @return - The json object.\n     */\n    toJSON() {\n        return {\n            p0: this.p0.toJSON(),\n            p1: this.p1.toJSON(),\n        };\n    }\n    /**\n     * Decodes a JSON object to set the state of this class.\n     *\n     * @param j - The json object.\n     */\n    fromJSON(j) {\n        // We need to verify that p0 and p1 axes are numeric, so in case they are not, we restore them to their default values.\n        // This, because 'Infinity' and '-Infinity' are stringified as 'null'.\n        const p0 = {\n            x: MathFunctions.isNumeric(j.p0.x) ? j.p0.x : Number.POSITIVE_INFINITY,\n            y: MathFunctions.isNumeric(j.p0.y) ? j.p0.y : Number.POSITIVE_INFINITY,\n            z: MathFunctions.isNumeric(j.p0.z) ? j.p0.z : Number.POSITIVE_INFINITY,\n        };\n        const p1 = {\n            x: MathFunctions.isNumeric(j.p1.x) ? j.p1.x : Number.NEGATIVE_INFINITY,\n            y: MathFunctions.isNumeric(j.p1.y) ? j.p1.y : Number.NEGATIVE_INFINITY,\n            z: MathFunctions.isNumeric(j.p1.z) ? j.p1.z : Number.NEGATIVE_INFINITY,\n        };\n        this.p0.fromJSON(p0);\n        this.p1.fromJSON(p1);\n    }\n    /**\n     * Calls `toJSON` method and stringifies it.\n     *\n     * @return - The return value.\n     */\n    toString() {\n        // eslint-disable-next-line new-cap\n        return StringFunctions.stringifyJSONWithFixedPrecision(this.toJSON());\n    }\n}\n\n/* eslint-disable new-cap */\n/**\n * Class representing a plane.\n */\nclass PlaneType {\n    normal;\n    w;\n    /**\n     * Create a plane.\n     *\n     * @param normal - The normal of the plane.\n     * @param w - The w value.\n     */\n    constructor(normal, w = 0) {\n        if (normal instanceof Vec3) {\n            this.normal = normal;\n        }\n        else {\n            this.normal = new Vec3();\n        }\n        this.w = w;\n    }\n    /**\n     * Setter from scalar components.\n     *\n     * @param x - The x value.\n     * @param y - The y value.\n     * @param z - The z value.\n     * @param w - The w value.\n     */\n    set(x, y, z, w) {\n        this.normal.set(x, y, z);\n        this.w = w;\n    }\n    /**\n     * The divideScalar method\n     *\n     * @param value - The value value.\n     */\n    divideScalar(value) {\n        this.normal.scaleInPlace(1 / value);\n        this.w /= value;\n    }\n    /**\n     * Calculates the distance from a point to this plane.\n     *\n     * @param point - The point value.\n     * @return - The return value.\n     */\n    distanceToPoint(point) {\n        return point.dot(this.normal) + this.w;\n    }\n    /**\n     * Normalize this plane in place modifying its values.\n     */\n    normalizeInPlace() {\n        const inverseNormalLength = 1.0 / this.normal.length();\n        this.normal.scaleInPlace(inverseNormalLength);\n        this.w *= inverseNormalLength;\n    }\n    /**\n     * Clones this plane and returns a new plane.\n     *\n     * @return - Returns a new plane.\n     */\n    clone() {\n        return new PlaneType(this.normal.clone(), this.w);\n    }\n    // ///////////////////////////\n    // Persistence\n    /**\n     * The toJSON method encodes this type as a json object for persistence.\n     *\n     * @return - The json object.\n     */\n    toJSON() {\n        return {\n            normal: this.normal.toJSON(),\n            w: this.w,\n        };\n    }\n    fromJSON(json) {\n        this.normal.fromJSON(json.normal);\n        this.w = json.w;\n    }\n    /**\n     * Calls `toJSON` method and stringifies it.\n     *\n     * @return - The return value.\n     */\n    toString() {\n        return StringFunctions.stringifyJSONWithFixedPrecision(this.toJSON());\n    }\n}\n\n/* eslint-disable new-cap */\n/**\n * Class representing a Frustum. Frustums are used to determine what\n * is inside the camera's field of view.\n * @private\n * */\nclass Frustum {\n    planes;\n    /**\n     * Create a Frustum\n     * @param p0 - the p0 value.\n     * @param p1 - the p1 value.\n     * @param p2 - the p2 value.\n     * @param p3 - the p3 value.\n     * @param p4 - the p4 value.\n     * @param p5 - the p5 value.\n     */\n    constructor(p0, p1, p2, p3, p4, p5) {\n        this.planes = [\n            p0 || new PlaneType(),\n            p1 || new PlaneType(),\n            p2 || new PlaneType(),\n            p3 || new PlaneType(),\n            p4 || new PlaneType(),\n            p5 || new PlaneType(),\n        ];\n    }\n    /**\n     * The setFromMatrix configures a Frustum object using a matrix.\n     * Typically the matrix is a model view projection matrix.\n     * @param mat4 - The matrix to use.\n     */\n    setFromMatrix(mat4) {\n        const m = mat4;\n        const planes = this.planes;\n        planes[0].set(m.m03 - m.m00, m.m13 - m.m10, m.m23 - m.m20, m.m33 - m.m30);\n        planes[1].set(m.m03 + m.m00, m.m13 + m.m10, m.m23 + m.m20, m.m33 + m.m30);\n        planes[2].set(m.m03 + m.m01, m.m13 + m.m11, m.m23 + m.m21, m.m33 + m.m31);\n        planes[3].set(m.m03 - m.m01, m.m13 - m.m11, m.m23 - m.m21, m.m33 - m.m31);\n        planes[4].set(m.m03 - m.m02, m.m13 - m.m12, m.m23 - m.m22, m.m33 - m.m32);\n        planes[5].set(m.m03 + m.m02, m.m13 + m.m12, m.m23 + m.m22, m.m33 + m.m32);\n        planes.forEach((plane) => plane.normalizeInPlace());\n    }\n    /**\n     * Tests a box to see if it is entirely within the frustum.\n     * @param box3 - The box to test.\n     * @return - True if the frustum intersects the box.\n     */\n    intersectsBox(box3) {\n        const p = new Vec3();\n        const planes = this.planes;\n        const { min, max } = box3;\n        for (let i = 0; i < 6; i++) {\n            const plane = planes[i];\n            // corner at max distance\n            p.x = plane.normal.x > 0 ? max.x : min.x;\n            p.y = plane.normal.y > 0 ? max.y : min.y;\n            p.z = plane.normal.z > 0 ? max.z : min.z;\n            if (plane.distanceToPoint(p) < 0)\n                return false;\n        }\n        return true;\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * The toJSON method encodes this type as a json object for persistence.\n     *\n     * @return - The json object.\n     */\n    toJSON() {\n        return {\n            p0: this.planes[0].toJSON(),\n            p1: this.planes[1].toJSON(),\n            p2: this.planes[2].toJSON(),\n            p3: this.planes[3].toJSON(),\n            p4: this.planes[4].toJSON(),\n            p5: this.planes[5].toJSON(),\n        };\n    }\n    /**\n     * The fromJSON method decodes a json object for this type.\n     *\n     * @param j - The json object.\n     */\n    fromJSON(j) {\n        this.planes[0].fromJSON(j.p0);\n        this.planes[1].fromJSON(j.p1);\n        this.planes[2].fromJSON(j.p2);\n        this.planes[3].fromJSON(j.p3);\n        this.planes[4].fromJSON(j.p4);\n        this.planes[5].fromJSON(j.p5);\n    }\n    /**\n     * Calls `toJSON` method and stringifies it.\n     *\n     * @return - The return value.\n     */\n    toString() {\n        return StringFunctions.stringifyJSONWithFixedPrecision(this.toJSON());\n    }\n}\n\n/** Class representing a ref counted object. RefCounted\n *  objects track ownership and allow explicit cleanup\n *  of resources. This is necessary when JavaScript\n *  objects own references to GPU resources that need to\n *  be cleaned up when the JavaScript object is destroyed.\n * @private\n */\nclass RefCounted extends EventEmitter {\n    #refs;\n    /**\n     * Create a ref counted object.\n     */\n    constructor() {\n        super();\n        if (this.constructor.name == 'RefCounted') {\n            throw new Error('RefCounted should not be instantiated directly.');\n        }\n        this.#refs = [];\n    }\n    get refs() {\n        return this.#refs;\n    }\n    /**\n     * The numRefs method.\n     * @return - The return value.\n     */\n    numRefs() {\n        return this.#refs.length;\n    }\n    /**\n     * The addRef method.\n     * @param referer - The referer value.\n     * @return - The return value.\n     */\n    addRef(referer) {\n        if (!referer)\n            throw new Error('Error in RefCounted.addRef: Must provide a referer');\n        // Note: an object can be reffeed multiple times.\n        // e.g. we can create a temporary ref while we re-attach a tree item to a new parent.\n        this.#refs.push(referer);\n        return true;\n    }\n    /**\n     * The removeRef method.\n     * @param referer - The referer value.\n     */\n    removeRef(referer) {\n        if (!referer)\n            throw new Error('Error in RefCounted.removeRef: Must provide a referer');\n        const index = this.#refs.indexOf(referer);\n        if (index == -1)\n            throw new Error('Error in RefCounted.removeRef: referer not found in refs list.');\n        this.#refs.splice(index, 1);\n        if (this.#refs.length == 0) {\n            this.destroy();\n        }\n    }\n    /**\n     * The destroy method is invoked when the last owner\n     * is removed from a RefCounted object. Derived objects can\n     * override this method to perform explicit cleanup.\n     * The destructing signal is triggered so observers can\n     * respond to this objects destruction.\n     */\n    destroy() {\n        this.emit('destructing');\n    }\n}\n\nlet numBaseItems = 0;\n/**\n * Base class for Items in the scene. It can be parameterized and can emit events.\n *\n * **Events**\n * * **nameChanged:** Emitted every time the Item's name is change. mostly in `setName` method.\n * * **selectedChanged:** Emitted `selected` status changes, mostly in `setSelected` method.\n *\n * @extends {EventEmitter}\n */\nclass BaseItem extends EventEmitter {\n    #name;\n    #ownerItem = undefined;\n    selected = false;\n    /**\n     * Create a base item by defining its name.\n     *\n     * @param name - The name of the base item.\n     */\n    constructor(name = '') {\n        super();\n        this.#name = name;\n        numBaseItems++;\n    }\n    // ////////////////////////////////////////\n    // Static Methods\n    /**\n     * The getNumBaseItems method returns the total number of base items created.\n     * This method is used in debugging memory consumption.\n     *\n     * @return - Returns the total number of base items created.\n     */\n    static getNumBaseItems() {\n        return numBaseItems;\n    }\n    // ////////////////////////////////////////\n    // Name and Path\n    /**\n     * Returns the name of the base item.\n     *\n     * @return - Returns the base item name.\n     */\n    get name() {\n        return this.#name;\n    }\n    /**\n     * Sets the name of the base item(Updates path).\n     *\n     * @emits `nameChanged` with `newName` and `oldName` data.\n     * @param name - The base item name.\n     */\n    set name(value) {\n        if (this.#name != value) {\n            const oldName = this.#name;\n            this.#name = value;\n            const event = new NameChangedEvent(oldName, value);\n            this.emit('nameChanged', event);\n        }\n    }\n    /**\n     * Returns the current path of the item in the tree as an array of names.\n     *\n     * @return - Returns an array.\n     */\n    get path() {\n        return this.getPath();\n    }\n    /**\n     * Returns the current path of the item in the tree as an array of names.\n     *\n     * @return - Returns an array.\n     */\n    get ownerItem() {\n        return this.#ownerItem;\n    }\n    /**\n     * Returns the name of the base item.\n     *\n     * @return - Returns the base item name.\n     */\n    getName() {\n        return this.#name;\n    }\n    /**\n     * Sets the name of the base item(Updates path).\n     *\n     * @emits `nameChanged` with `newName` and `oldName` data.\n     * @param name - The base item name.\n     */\n    setName(name) {\n        this.name = name;\n    }\n    /**\n     * Returns the current path of the item in the tree as an array of names.\n     *\n     * @return - Returns an array.\n     */\n    getPath() {\n        if (this.#ownerItem == undefined)\n            return [this.#name];\n        return [...this.#ownerItem.getPath(), this.#name];\n    }\n    // Path Traversal\n    /**\n     * The resolvePath method traverses the subtree from this item down\n     * matching each name in the path with a child until it reaches the\n     * end of the path.\n     *\n     * @param path - The path value.\n     * @param index - The index value.\n     * @return - The return value.\n     */\n    resolvePath(path, index = 0) {\n        if (index == 0) {\n            if (path[0] == '.' || path[0] == this.#name)\n                index++;\n        }\n        if (path[index] == '..') {\n            if (this.#ownerItem) {\n                return this.#ownerItem.resolvePath(path, index + 1);\n            }\n            else {\n                throw Error('this.#ownerItem is undefined');\n            }\n        }\n        if (index == path.length) {\n            return this;\n        }\n    }\n    // ////////////////////////////////////////\n    // Owner Item\n    /**\n     * The getOwner method returns the current owner of the item.\n     * The item is a child of the current owner.\n     *\n     * @return - Returns the current owner.\n     */\n    getOwner() {\n        return this.#ownerItem;\n    }\n    /**\n     * The setOwner method assigns a new owner to the item.\n     *\n     * @param ownerItem - The new owner item.\n     */\n    setOwner(ownerItem) {\n        this.#ownerItem = ownerItem;\n    }\n    // ////////////////////////////////////////\n    // Selection\n    /**\n     * The isSelected method.\n     * @return - The return value.\n     */\n    isSelected() {\n        return this.selected;\n    }\n    /**\n     * Changes the current state of the selection of this item.\n     *\n     * @emits `selectedChanged` with selected state\n     * @param sel - Boolean indicating the new selection state.\n     */\n    setSelected(sel) {\n        this.selected = sel;\n        let event = new SelectedEvent(this.selected);\n        this.emit('selectedChanged', event);\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * Encodes the current object as a json object.\n     *\n     * @param context - The context value.\n     * @return - Returns the json object.\n     */\n    toJSON(context) {\n        const json = {\n            type: this.getClassName(),\n            name: this.#name,\n        };\n        return json;\n    }\n    /**\n     * Decodes a json object for this type.\n     *\n     * @param json - The json object this item must decode.\n     * @param context - The context value.\n     */\n    fromJSON(json, context) {\n        if (json.name)\n            this.#name = json.name;\n    }\n    /**\n     * Sets state of current Item(Including parameters) using a binary reader object.\n     *\n     * @param reader - The reader value.\n     * @param context - The context value.\n     */\n    readBinary(reader, context) {\n        // read the type, but don't use it. This line must not be removed.\n        // as the binary pointer is incremented.\n        /*const type = */ reader.loadStr();\n        this.setName(reader.loadStr());\n    }\n    /**\n     * Converts object's JSON value and converts it to a string.\n     * @param context\n     * @return - String of object's parameter list state.\n     */\n    toString(context) {\n        return JSON.stringify(this.toJSON(), null, 2);\n    }\n    // ////////////////////////////////////////\n    // Clone and Destroy\n    /**\n     * Clones this base item and returns a new base item.\n     *\n     * **Note:** Each class should implement clone to be clonable.\n     * @param context - The context value.\n     */\n    clone(context) {\n        throw new Error(this.constructor.name + ' does not implement its clone method');\n    }\n    /**\n     * When a BaseItem is cloned, initially the constructor is\n     * called to generate a new instance. This instance then copies\n     * its values from the source using this method.\n     * This method copies any relevant data from the source object to\n     * ensure that it represents a valid clone.\n     * Derived classes override this method to copy any relevant\n     * data from the source object.\n     *\n     * @param src - The BaseItem to copy from.\n     * @param context - The context value\n     */\n    copyFrom(src, context) {\n        this.setName(src.getName());\n    }\n}\n\n/**\n * Class that allows other classes to be parameterized by `Parameter` type of objects.\n * Not only hosting parameters, but their events.\n *\n * @extends {BaseItem}\n */\nclass ParameterOwner extends BaseItem {\n    paramEventListenerIDs = {};\n    paramMapping = {};\n    params = [];\n    deprecatedParamMapping = {};\n    /**\n     * Creates an instance of ParameterOwner by initializing parameter hosting mappings and events.\n     *\n     * Every Object has a unique identifier which is based on a counter that is incremented.\n     */\n    constructor(name) {\n        super(name);\n    }\n    /**\n     * Returns the number of parameters current object has.\n     */\n    getNumParameters() {\n        return this.params.length;\n    }\n    /**\n     * Returns the number of parameters current object has.\n     */\n    get numParameters() {\n        return this.params.length;\n    }\n    /**\n     * Returns all the parameters of the object.\n     *\n     * @return - Parameter List\n     */\n    getParameters() {\n        return this.params;\n    }\n    /**\n     * Returns the index of a parameter in parameter list.\n     *\n     * @param paramName - Name of the parameter.\n     * @return - Position in the array\n     */\n    getParameterIndex(paramName) {\n        return this.paramMapping[paramName];\n    }\n    /**\n     * Returns `Parameter` object in a given index\n     *\n     * @param index - Position of the parameter in the array\n     * @return - Parameter object value\n     */\n    getParameterByIndex(index) {\n        return this.params[index];\n    }\n    /**\n     * Validates if the specified parameter exists in the object.\n     *\n     * @param paramName - The parameter name.\n     * @return - The return value.\n     */\n    hasParameter(paramName) {\n        return paramName in this.paramMapping;\n    }\n    /**\n     * Add a mapping from one name to a new parameter.\n     * This is used to handle migrating parameters to new names.\n     *\n     * @param key - The parameter name.\n     * @param paramName - The parameter name.\n     * @return - The return value.\n     */\n    addParameterDeprecationMapping(key, paramName) {\n        this.deprecatedParamMapping[key] = paramName;\n    }\n    /**\n     * Returns `Parameter` object using the given name\n     *\n     * @param paramName - The parameter name.\n     * @return - Parameter object value\n     */\n    getParameter(paramName) {\n        let index = this.paramMapping[paramName];\n        if (index == undefined) {\n            const newParamName = this.deprecatedParamMapping[paramName];\n            if (!newParamName) {\n                // TODO: Should this method not return null?\n                return null;\n                // throw Error(`No Parameter with that name exists: ${paramName} `)\n            }\n            else {\n                console.warn(`Parameter name ${paramName} is now deprecated. Please use ${newParamName} instead.`);\n                index = this.paramMapping[newParamName];\n            }\n        }\n        return this.params[index];\n    }\n    /**\n     * This method can be overridden in derived classes\n     * to perform general updates (see GLPass or BaseItem).\n     * @param event - The event object emitted by the parameter.\n     * @private\n     */\n    parameterValueChanged(event) {\n        this.emit('parameterValueChanged', event);\n    }\n    /**\n     * Adds `Parameter` object to the owner's parameter list.\n     *\n     * @emits `parameterAdded` with the name of the param.\n     * @param param - The parameter to add.\n     * @return - With `owner` and `valueChanged` event set.\n     */\n    addParameter(param) {\n        return this.insertParameter(param, this.params.length);\n    }\n    /**\n     * Adds `Parameter` object to the owner's parameter list using the index.\n     * It replaces the event in the specified index.\n     *\n     *\n     * @emits `parameterAdded` with the name of the param.\n     * @param param - The parameter to insert.\n     * @param index - The index value.\n     * @return - With `owner` and `valueChanged` event set.\n     */\n    insertParameter(param, index) {\n        const name = param.getName();\n        if (this.paramMapping[name] != undefined) {\n            console.warn('Replacing Parameter:' + name);\n            this.removeParameter(name);\n        }\n        param.setOwner(this);\n        this.paramEventListenerIDs[name] = param.on('valueChanged', (event) => {\n            // Note: spread operators cause errors on iOS 11.\n            const newEvent = { param };\n            for (const key in event)\n                newEvent[key] = event[key];\n            this.parameterValueChanged(newEvent);\n        });\n        this.params.splice(index, 0, param);\n        for (let i = index; i < this.params.length; i++) {\n            this.paramMapping[this.params[i].getName()] = i;\n        }\n        const event = new ParameterAddedEvent(name);\n        this.emit('parameterAdded', event);\n        return param;\n    }\n    /**\n     * Removes `Parameter` from owner, by using parameter's name.\n     * @emits `parameterRemoved` with the name of the param.\n     * @param name - The parameter name.\n     */\n    removeParameter(name) {\n        if (this.paramMapping[name] == undefined) {\n            throw new Error('Unable to remove Parameter:' + name);\n        }\n        const index = this.paramMapping[name];\n        const param = this.params[this.paramMapping[name]];\n        param.off('valueChanged', this.paramEventListenerIDs[name]);\n        this.params.splice(index, 1);\n        delete this.paramMapping[name];\n        for (let i = index; i < this.params.length; i++) {\n            this.paramMapping[this.params[i].getName()] = i;\n        }\n        const event = new ParameterRemovedEvent(name);\n        this.emit('parameterRemoved', event);\n    }\n    /**\n     * Replaces old `Parameter` by passing a new one with the same name.\n     *\n     * @param param - The parameter to replace.\n     * @return - `Parameter` with `valueChanged` event set.\n     */\n    replaceParameter(param) {\n        const name = param.getName();\n        if (this.paramMapping[name] == undefined) {\n            throw new Error('Unable to replace Parameter:' + name);\n        }\n        const index = this.paramMapping[name];\n        this.removeParameter(name);\n        this.insertParameter(param, index);\n        return param;\n    }\n    /**\n     * The resolvePath method traverses the subtree from this item down\n     * matching each name in the path with a child until it reaches the\n     * end of the path.\n     *\n     * @param path - The path value.\n     * @param index - The index value.\n     * @return - The return value.\n     */\n    resolvePath(path, index = 0) {\n        if (index == 0) {\n            if (path[0] == '.' || path[0] == this.name)\n                index++;\n        }\n        if (path[index] == '..') {\n            if (this.ownerItem) {\n                return this.ownerItem.resolvePath(path, index + 1);\n            }\n            else {\n                throw Error('this.ownerItem is undefined');\n            }\n        }\n        if (index == path.length) {\n            return this;\n        }\n        // Maybe the name is a parameter name.\n        const param = this.getParameter(path[index]);\n        if (param) {\n            if (index < path.length) {\n                return param.resolvePath(path, index + 1);\n            }\n            return param;\n        }\n        throw new Error(`Unable to resolve path : [${path.toString()}] after: ${this.getName()} \\nNo child or parameter called : \"${path[index]}\"`);\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * The toJSON method encodes this type as a json object for persistence.\n     *\n     * @param context - The context value.\n     * @return - Returns the json object.\n     */\n    toJSON(context) {\n        const json = super.toJSON(context);\n        const paramsJSON = {};\n        let savedParams = 0;\n        for (const param of this.params) {\n            if (param.isDrivenByOperator())\n                continue;\n            const paramJSON = param.toJSON(context);\n            if (paramJSON) {\n                paramsJSON[param.getName()] = paramJSON;\n                savedParams++;\n            }\n        }\n        if (savedParams > 0)\n            json.params = paramsJSON;\n        return json;\n    }\n    /**\n     * The fromJSON method decodes a json object for this type.\n     *\n     * @param json - The json object this item must decode.\n     * @param context - The context value.\n     */\n    fromJSON(json, context) {\n        super.fromJSON(json, context);\n        if (json.params) {\n            for (const key in json.params) {\n                const pj = json.params[key];\n                if (pj.paramPath) {\n                    context?.resolvePath(pj.paramPath, (param) => {\n                        this.replaceParameter(param);\n                    }, () => {\n                        console.warn('Unable to resolve shared parameter:' + pj.paramPath);\n                    });\n                }\n                else {\n                    let param = this.getParameter(key);\n                    if (!param && pj.type && pj.name) {\n                        param = Registry.constructClass(pj.type);\n                        if (!param) {\n                            console.error('Unable to construct prop:' + pj.name + ' of type:' + pj.type);\n                            continue;\n                        }\n                        param.setName(pj.name);\n                        this.addParameter(param);\n                    }\n                    if (param)\n                        param.fromJSON(pj, context);\n                }\n            }\n        }\n    }\n    /**\n     * Uses passed in BinReader object(containing an Int32 array with all the parameters) to reconstruct all parameters state.\n     *\n     * In each iteration of the array, propType and propName are extracted and\n     * used to build the right `Parameter` class. Then all of them are added to the object.\n     *\n     * @emits `parameterAdded` with the name of the param.\n     * @param reader - The reader value.\n     * @param context - The context value.\n     */\n    readBinary(reader, context) {\n        super.readBinary(reader, context);\n        this.readBinaryParams(reader, context);\n    }\n    readBinaryParams(reader, context) {\n        if (context?.versions['zea-engine'].compare([0, 0, 3]) >= 0) {\n            const numProps = reader.loadUInt32();\n            for (let i = 0; i < numProps; i++) {\n                const propType = reader.loadStr();\n                const propName = reader.loadStr();\n                let param = this.getParameter(propName);\n                if (!param) {\n                    param = Registry.constructClass(propType);\n                    if (!param) {\n                        console.error('Unable to construct prop:' + propName + ' of type:' + propType);\n                        continue;\n                    }\n                    param.setName(propName);\n                    this.addParameter(param);\n                }\n                param.readBinary(reader, context);\n            }\n        }\n    }\n    // ////////////////////////////////////////\n    // Clone and Destroy\n    /**\n     * Clones this base item and returns a new base item.\n     *\n     * **Note:** Each class should implement clone to be clonable.\n     * @param context - The context value.\n     */\n    clone(context) {\n        throw new Error(this.constructor.name + ' does not implement its clone method');\n    }\n    /**\n     * Copies Parameters from another `ParameterOwner` to current object.\n     *\n     * @param src - The ParameterOwner copy from.\n     * @param context - The context value\n     */\n    copyFrom(src, context) {\n        if (!(src instanceof ParameterOwner)) {\n            throw new Error('cannot copy from src');\n        }\n        super.copyFrom(src, context);\n        // Note: Loop over the parameters in reverse order,\n        // this is because often, parameter dependencies\n        // are bottom to top (bottom params dependent on higher params).\n        // This means that as a parameter is set with a new value\n        // it will dirty the params below it.\n        let i = src.getNumParameters();\n        while (i--) {\n            const srcParam = src.getParameterByIndex(i);\n            const param = this.getParameter(srcParam.getName());\n            if (param) {\n                // Note: we are not cloning the values.\n                param.copyFrom(srcParam);\n            }\n            else {\n                this.addParameter(srcParam.clone());\n            }\n        }\n    }\n}\n\nconst getFileFolder = function (filePath) {\n    return filePath.substring(0, filePath.lastIndexOf('/')) + '/';\n};\nconst loadFile = function (url, responseType, onSucceed, onFail, onProgress = undefined) {\n    try {\n        const xhr = new XMLHttpRequest();\n        xhr.responseType = responseType;\n        xhr.addEventListener('timeout', (event) => {\n            throw new Error('The request for ' + url + ' timed out.');\n        });\n        xhr.addEventListener('error', (event) => {\n            throw new Error('The request for ' + url + ': xhr.readyState:' + xhr.readyState);\n            onFail(xhr.statusText);\n        });\n        xhr.addEventListener('abort', (event) => {\n            throw new Error('The request for ' + url + ': xhr.readyState:' + xhr.readyState);\n            onFail(xhr.statusText);\n        });\n        xhr.addEventListener('progress', (event) => {\n            if (onProgress)\n                onProgress(event.total, event.loaded);\n        });\n        xhr.addEventListener('loadend', (event) => {\n            if (xhr.status == 200)\n                onSucceed(xhr);\n            else\n                onFail(xhr.statusText);\n        });\n        xhr.open('GET', url, true);\n        xhr.send();\n        // xhr.open();\n    }\n    catch (err) {\n        onFail(err);\n    }\n};\nconst loadTextfile = function (url, onSucceed, onFail = undefined, onProgress = undefined) {\n    loadFile(url, 'text', (xhr) => {\n        onSucceed(xhr.responseText);\n    }, (statusText) => {\n        if (onFail != undefined)\n            onFail(statusText);\n        else {\n            throw new Error('Unable to XHR File:' + url);\n        }\n    }, onProgress);\n};\nconst loadJSONfile = function (url, onSucceed, onFail = undefined, onProgress = undefined) {\n    loadFile(url, 'json', (xhr) => {\n        onSucceed(xhr.response, xhr);\n    }, (statusText) => {\n        if (onFail != undefined)\n            onFail(statusText);\n        else {\n            throw new Error('Unable to XHR File:' + url);\n        }\n    }, onProgress);\n};\nconst loadXMLfile = function (url, onSucceed, onFail = undefined, onProgress = undefined) {\n    loadFile(url, 'document', (xhr) => {\n        onSucceed(xhr.responseXML);\n    }, (statusText) => {\n        if (onFail != undefined)\n            onFail(statusText);\n        else {\n            throw new Error('Unable to XHR File:' + url);\n        }\n    }, onProgress);\n};\nconst loadBinfile = function (url, onSucceed, onFail = undefined, onProgress = undefined) {\n    loadFile(url, 'arraybuffer', (xhr) => {\n        onSucceed(xhr.response);\n    }, (statusText) => {\n        if (onFail != undefined)\n            onFail(statusText);\n        else {\n            throw new Error('Unable to XHR File:' + url);\n        }\n    }, onProgress);\n};\n\nvar unpackBase64Str = \"AGFzbQEAAAABrgIlYAF/AX5gA39/fwF/YAN/fn8AYAR/f39/AX9gAn9/AX9gAAF/YAJ/fwBgA39/fwBgAABgAX8Bf2AEf39/fwBgBn9/f39/fwBgBX9/f39/AGACf38BfGAFf39/f38Bf2AGf39/f39/AX9gCX9/f39/f39/fwF/YAh/f39/f35/fwF/YAJ+fgF/YAF/AGADf398AGAJf39/f39/f39/AGAKf39/f39/f39/fwBgAn9+AGAHf39/f39/fwF/YAp/f39/f39/f39/AX9gB39/f39/f38AYAt/f39/f39/f39/fwBgDX9/f39/f39/f39/f38AYAh/f39/f39/fwBgA39+fwF/YAN+f38Bf2ACfn8Bf2AGf3x/f39/AX9gAnx/AXxgA39/fwF8YAR/f398AAKID1cDZW52Bm1lbW9yeQIAgAIDZW52BXRhYmxlAXABvAK8AgNlbnYJdGFibGVCYXNlA38AA2Vudg5EWU5BTUlDVE9QX1BUUgN/AANlbnYIU1RBQ0tUT1ADfwADZW52BWFib3J0ABMDZW52DWVubGFyZ2VNZW1vcnkABQNlbnYOZ2V0VG90YWxNZW1vcnkABQNlbnYXYWJvcnRPbkNhbm5vdEdyb3dNZW1vcnkABQNlbnYIaW52b2tlX2kACQNlbnYJaW52b2tlX2lpAAQDZW52Cmludm9rZV9paWkAAQNlbnYLaW52b2tlX2lpaWkAAwNlbnYMaW52b2tlX2lpaWlpAA4DZW52Dmludm9rZV9paWlpaWlpABgDZW52EWludm9rZV9paWlpaWlpaWlpABkDZW52CGludm9rZV92ABMDZW52CWludm9rZV92aQAGA2VudgppbnZva2VfdmlpAAcDZW52C2ludm9rZV92aWlpAAoDZW52DGludm9rZV92aWlpaQAMA2Vudg1pbnZva2VfdmlpaWlpAAsDZW52Dmludm9rZV92aWlpaWlpABoDZW52EWludm9rZV92aWlpaWlpaWlpABYDZW52Emludm9rZV92aWlpaWlpaWlpaQAbA2VudhlfX19jeGFfYWxsb2NhdGVfZXhjZXB0aW9uAAkDZW52El9fX2N4YV9iZWdpbl9jYXRjaAAJA2VudhBfX19jeGFfZW5kX2NhdGNoAAgDZW52HF9fX2N4YV9maW5kX21hdGNoaW5nX2NhdGNoXzIABQNlbnYcX19fY3hhX2ZpbmRfbWF0Y2hpbmdfY2F0Y2hfMwAJA2VudhxfX19jeGFfZmluZF9tYXRjaGluZ19jYXRjaF80AAQDZW52FV9fX2N4YV9mcmVlX2V4Y2VwdGlvbgATA2VudgxfX19jeGFfdGhyb3cABwNlbnYHX19fbG9jawATA2VudgtfX19tYXBfZmlsZQAEA2VudhJfX19yZXN1bWVFeGNlcHRpb24AEwNlbnYLX19fc2V0RXJyTm8AEwNlbnYNX19fc3lzY2FsbDE0MAAEA2Vudg1fX19zeXNjYWxsMTQ1AAQDZW52DV9fX3N5c2NhbGwxNDYABANlbnYNX19fc3lzY2FsbDE4MwAEA2Vudg1fX19zeXNjYWxsMTk4AAQDZW52DF9fX3N5c2NhbGwyMAAEA2VudgtfX19zeXNjYWxsNgAEA2VudgxfX19zeXNjYWxsNjAABANlbnYMX19fc3lzY2FsbDgzAAQDZW52DF9fX3N5c2NhbGw5MQAEA2VudglfX191bmxvY2sAEwNlbnYeX19lbWJpbmRfZmluYWxpemVfdmFsdWVfb2JqZWN0ABMDZW52Fl9fZW1iaW5kX3JlZ2lzdGVyX2Jvb2wADANlbnYXX19lbWJpbmRfcmVnaXN0ZXJfY2xhc3MAHANlbnYjX19lbWJpbmRfcmVnaXN0ZXJfY2xhc3NfY29uc3RydWN0b3IACwNlbnYgX19lbWJpbmRfcmVnaXN0ZXJfY2xhc3NfZnVuY3Rpb24AHQNlbnYXX19lbWJpbmRfcmVnaXN0ZXJfZW12YWwABgNlbnYXX19lbWJpbmRfcmVnaXN0ZXJfZmxvYXQABwNlbnYZX19lbWJpbmRfcmVnaXN0ZXJfaW50ZWdlcgAMA2Vudh1fX2VtYmluZF9yZWdpc3Rlcl9tZW1vcnlfdmlldwAHA2VudhxfX2VtYmluZF9yZWdpc3Rlcl9zdGRfc3RyaW5nAAYDZW52HV9fZW1iaW5kX3JlZ2lzdGVyX3N0ZF93c3RyaW5nAAcDZW52Hl9fZW1iaW5kX3JlZ2lzdGVyX3ZhbHVlX29iamVjdAALA2VudiRfX2VtYmluZF9yZWdpc3Rlcl92YWx1ZV9vYmplY3RfZmllbGQAFgNlbnYWX19lbWJpbmRfcmVnaXN0ZXJfdm9pZAAGA2VudgZfYWJvcnQACANlbnYWX2Vtc2NyaXB0ZW5fbWVtY3B5X2JpZwABA2VudgdfZ2V0ZW52AAkDZW52CV9nZXRncm5hbQAJA2VudglfZ2V0cHduYW0ACQNlbnYIX2pzQ2xvc2UAEwNlbnYJX2pzQ3JlYXRlAAkDZW52B19qc09wZW4ACQNlbnYHX2pzUmVhZAABA2VudgdfanNTZWVrAAEDZW52CF9qc1dyaXRlAAEDZW52E19sbHZtX2VoX3R5cGVpZF9mb3IACQNlbnYKX2xvY2FsdGltZQAJA2VudgdfbWt0aW1lAAkDZW52FF9wdGhyZWFkX2dldHNwZWNpZmljAAkDZW52E19wdGhyZWFkX2tleV9jcmVhdGUABANlbnYNX3B0aHJlYWRfb25jZQAEA2VudhRfcHRocmVhZF9zZXRzcGVjaWZpYwAEA2VudgVfdGltZQAJA2VudhBpbnZva2VfaWlpaWlpamlpABkDZW52Cmludm9rZV9pamoADgNlbnYJaW52b2tlX2ppAAQDZW52Cmludm9rZV92aWoACgNlbnYLaW52b2tlX3ZpamkADANlbnYHX2pzVGVsbAAJA4QEggQTAQEGEwQJCRMGEwEBCQcAEwcGBwwJCgEEAQkGCQETCQkEBAQHBAETAQEJBxMHAwkGBhMIBgkTARMEBBMTAQEBIAkJExMGEwEDCQIEEwcEExMKBgEJDAsIBAwEBAEEBAcJBwkDChMGEAERDAAFCwwKBwMBBwEEBgEJAQEOAQkEABMAAQYHBBMTAQkTEwYTBhMJCgYMCgEABwcGBAcTBAQEAhcKDwQHBwoBExMTBQEDBAcJDgQECQEBAwQJASIJAQQJBAkGCQEBBwQHBBMBCQ4JBgMBEwYTAQwBBwcHBhMXBhMHBhMTEwkPBAkTEwQGFR0MBgYGBwkTCQkJAQEJAQAJBAoTCQkJEwYGBBMEAAIBARMMCgQOGRYVCBQSERIGEA4BDRsWGgsMCiQHBhMZGA8OAwEEIwkBCgwLBwETCQkIEwYICgwLCgwLAQgEBh0BAQkEBh0EBgYGCQMEBAEEAQEBAQEEBAQJAwMHBAEhIB8DAwQBBAQBBAkBBQEBCQQJEwgECQEEHhMDFA0FCgUHBBMFAQcEBg4MBRMJEwcIAwYPExMTBgcHBgMEAQYBBgMJCQYTBAYTBhMEBgQTARMTBh4GFw8BBwkDBgQDBwcBBAQGBgYBCQkGEwYGAwcTEwoTBhMTBwoGEwcGBwYTBwcTFQcHExMTBgkGBgQLEwQJBAMBEwgJBhoFfwEjAQt/ASMCC38BQQALfwFBAAt/AUEACweXBSUYX19HTE9CQUxfX3N1Yl9JX2JpbmRfY3BwANEDGl9fR0xPQkFMX19zdWJfSV9icmlkZ2VfY3BwAO0DF19fR0xPQkFMX19zdWJfSV9jcmNfY3BwANIEGl9fR0xPQkFMX19zdWJfSV9nbG9iYWxfY3BwAOoCEF9fX2N4YV9jYW5fY2F0Y2gAhwMWX19fY3hhX2lzX3BvaW50ZXJfdHlwZQCGAxFfX19lcnJub19sb2NhdGlvbgDKAw5fX19nZXRUeXBlTmFtZQDPAwVfZnJlZQBSB19tYWxsb2MAbAtkeW5DYWxsX2RpaQCFAwlkeW5DYWxsX2kAnwIKZHluQ2FsbF9paQCEAwtkeW5DYWxsX2lpaQCDAwxkeW5DYWxsX2lpaWkAggMNZHluQ2FsbF9paWlpaQCBAw5keW5DYWxsX2lpaWlpaQCAAw9keW5DYWxsX2lpaWlpaWkA/wISZHluQ2FsbF9paWlpaWlpaWlpAP4CEWR5bkNhbGxfaWlpaWlpamlpAOcCC2R5bkNhbGxfaWpqAOYCCmR5bkNhbGxfamkA5QIJZHluQ2FsbF92AP0CCmR5bkNhbGxfdmkA/AILZHluQ2FsbF92aWkA+wIMZHluQ2FsbF92aWlkAPoCDGR5bkNhbGxfdmlpaQD5Ag1keW5DYWxsX3ZpaWlpAPgCDmR5bkNhbGxfdmlpaWlpAPcCD2R5bkNhbGxfdmlpaWlpaQD2AhJkeW5DYWxsX3ZpaWlpaWlpaWkA9QITZHluQ2FsbF92aWlpaWlpaWlpaQD0AgtkeW5DYWxsX3ZpagDkAgxkeW5DYWxsX3ZpamkA4wILc2V0VGVtcFJldDAA3AIIc2V0VGhyZXcA7wIKc3RhY2tBbGxvYwDTBAnKBAEAIwALvALzAtoDvgHoA+ED3QPbA/4BvgG+AYEBzQOPA44DX8YEfKkD0wOlBM0EuwKmAcoCywK4ApYC0QKWArIBcVjqA58CxwKBAYEBgQGBAYEBgQGBAaoB8QHdAu8BvgJqc5kE0gLbAs4E8AHMBLoCyQTSA9UD5APXAd8DnAKaAtcBnAKaAtcBuwOi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DiAAQThqIQ8gAEGQAWohECAAQfAAaiELIABBzABqIREgAEEIaiESIABBBGohDAJAAkADQCAERQRAIAMhAgwCCyANKAIAIQcgACwAAARAIAEgEigCACAMKAIAEFMaIAwoAgAhAiAMQQA2AgAFIAopAwAiEyAErVMhCCATpyECIAgEfyACBSAEIgILBEAgDiwAAARAIAksAAAEQCACIAIgBmpBD3FrIgNBAEoEQCADIQILIAhFBEAgBCECCwsLIAcoAgRFDQQgByAFIAIgBygCACgCDEEfcUHKAGoRAQAhAiAHQbCnAWohCCAPKAIAIgMEfyADBSAIC0GJwQBqLAAABEAgECAFIAIQqwILBSADIQILCyALIAspAwAgAqwiE3w3AwAgAiAGaiEGIAogCikDACATfSITNwMAIBNCAFEgDiwAAEEAR3FFDQEgAgRAIAZBD3FFIAksAABFcg0CCyAFIAJqIQUgBCACayEEIAcgAEEBIBEoAgAQtQEEQCACIQMMAQsLIABBAToAUkF/DwsgDSgCACIDBEAgCykDACADQYi8A2opAwB8IRQgACwAKARAIAApA1ghFSAAKQOIASITQgBRBEAgFSETBSAAKQOAASAUfCEUCyADQazzAGooAgAhAyATIBRTBH9B5AAFIBNCAFEEf0EABSAUQuQAfiATf6cLCyEFIANBzIQDaiwAAEUEQCAFIABByABqIgMoAgBHBEAgAyAFNgIACwsLCyACQX9GBEBBfyEGBSAJLAAABEAgACgCRCABIAYQ6gELCxCFASAGDwtBfwtiAQF/IABFBEBBASEACwJAAkACQANAIAAQbCIBDQJBsLwDQbC8AygCACIBNgIAIAFFDQEgAUEHcUGOAWoRCAAMAAsAC0EEEBQiAEHEJTYCACAAQdgKQQoQGwwBCyABDwtBAAtTAQF/IwQhACMEQeAgaiQEIABBgCBqIgMgAjYCACAAQYAIIAEgAxCAAhogAEGQIGoiAUEANgJEIAFBATYCSCABQUBrQQE2AgAgASAANgIAIAAkBAt6AgV/AX4gAEEYaiIDKAIAIgEgACgCFCIETwRAQgAPCyAAKAIAIQUgASEAAkADQCADIABBAWoiATYCACAFIABqLQAAIgBB/wBxrSACrYYgBnwhBiAAQYABcUUNASACQQdqIQIgASAESQRAIAEhAAwBBUIAIQYLCwsgBgsGAEENEAALGAAgACgCAEEgcUUEQCABIAIgABCNAhoLC+4CAQF/AkACQAJAAkACQCABQQFrDv8BAAIBAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMAAwsgACgCAEUEQCAAIAE2AgALDAMLIAAoAgBBC0cEQCAAQQM2AgALDAILIAAoAgBBAkkEQCAAQQI2AgALDAELIAAgATYCAAsgAEEEaiICIAIoAgBBAWo2AgALrgIBAn8gACgCLEGs8wBqKAIAIgNBpMsEaigCAARAIANBsMsEaigCACIEBEBBASADQazLBGooAgAgASACIARBD3FB6gBqEQMAQX9GBEBBrPUCQf8BEKQBCwsgA0G4ywRqKAIAIgMEQCABIAIgA0EfcUEqahEEAEUEQEGs9QJB/wEQpAELCwsgACABNgIcIAAgAjYCGCAALAAMBEAgAEEQaiIDKAIAIAJPBEAgAEEUaiIEKAIAIAEgAhBTGiAEIAQoAgAgAmo2AgAgAyADKAIAIAJrNgIACwUgACwAKUUEQAJ/IAAoAjAhA0EBIAJFDQAaIAMoAgQgASACEEMLGgsLIABB+ABqIgMgAykDACACrXw3AwAgACwAKgRAEIUBDwsgAEGoAWogASACEKsCEIUBC4ABAQF/IwQhBSMEQYACaiQEIAIgA0ogBEGAwARxRXEEQCAFIAFBGHRBGHUgAiADayIBQYACSQR/IAEFQYACCxBUGiABQf8BSwRAIAIgA2shAgNAIAAgBUGAAhBjIAFBgH5qIgFB/wFLDQALIAJB/wFxIQELIAAgBSABEGMLIAUkBAsrACAAQf8BcUEYdCAAQQh1Qf8BcUEQdHIgAEEQdUH/AXFBCHRyIABBGHZyC40JARB/IwQhByMEQYABaiQEIAIgAzYCACAHQUBrIgRCADcCACAEQgA3AgggBEIANwIQIARCADcCGCAEQgA3AiAgBEIANwIoIARCADcCMCAEQgA3AjggA0UiEwR/IARBJGohECAEQShqIRFBAAVBACEAA0AgBCABIABqLAAAQQ9xQQJ0aiIFIAUoAgBBAWo2AgAgAEEBaiIAIANHDQALIARBJGoiACEQIARBKGoiCiERIAQoAgghBiAEKAIMIQggBCgCECEJIAQoAhQhCyAEKAIYIQwgBCgCHCENIAQoAiAhDiAAKAIAIRIgCigCACEKIAQoAgQLIQUgBEEANgIAIAJBiBlqQQAgA0EBdBBUGiACQcQAaiIAQQA2AgAgAkEANgIEIAIgBUEPdDYCCCACQQA2AkggAiAGIAVBAXRqIg9BDnQ2AgwgAiAFNgJMIAIgCCAPQQF0aiIPQQ10NgIQIAIgBiAFaiIFNgJQIAIgCSAPQQF0aiIGQQx0NgIUIAIgCCAFaiIFNgJUIAIgCyAGQQF0aiIGQQt0NgIYIAIgCSAFaiIFNgJYIAIgDCAGQQF0aiIGQQp0NgIcIAIgCyAFaiIFNgJcIAIgDSAGQQF0aiIGQQl0NgIgIAIgDCAFaiIFNgJgIAIgDiAGQQF0aiIGQQh0NgIkIAIgDSAFaiIFNgJkIAIgEiAGQQF0aiIGQQd0NgIoIAIgDiAFaiIFNgJoIAIgCiAGQQF0aiIGQQZ0NgIsIAIgECgCACAFaiIFNgJsIAIgBCgCLCIIIAZBAXRqIgZBBXQ2AjAgAiARKAIAIAVqIgU2AnAgAiAEKAIwIgkgBkEBdGoiBkEEdDYCNCACIAggBWoiBTYCdCACIAQoAjQiCCAGQQF0aiIGQQN0NgI4IAIgCSAFaiIFNgJ4IAIgBCgCOCIJIAZBAXRqIgZBAnQ2AjwgAiAIIAVqIgU2AnwgAkFAayAEKAI8IAZBAXRqQQF0NgIAIAIgCSAFajYCgAEgByAAKQIANwIAIAcgACkCCDcCCCAHIAApAhA3AhAgByAAKQIYNwIYIAcgACkCIDcCICAHIAApAig3AiggByAAKQIwNwIwIAcgACkCODcCOAJAAkAgEw0AQQAhAANAIAEgAGosAABBD3EiBARAIAJBiBlqIAcgBEECdGoiBCgCACIFQQF0aiAAOwEAIAQgBUEBajYCAAsgAEEBaiIAIANHDQALAkACQAJAIANBqgJrDgkAAAEBAQEBAQABC0EKIQQMAQsMAQsMAQtBByEECyACQYQBaiIFIAQ2AgBBASAEdCEGQQAhAUEBIQADQCABQRAgBGt0IQQCQCAAQRBJBEADQCAEIAJBBGogAEECdGooAgBJDQIgAEEBaiIAQRBJDQBBECEACwsLIAJBiAFqIAFqIAA6AAAgAkGICWogAUEBdGogBCACIABBAnRqKAIAa0EQIABrdiACQcQAaiAAQQJ0aigCAGoiBCADSQR/IAJBiBlqIARBAXRqLgEABUEACyIEOwEAIAFBAWoiASAGSQRAIAUoAgAhBAwBCwsgByQEC6cDAQZ/IwQhAyMEQRBqJAQgA0EIaiEEIAFBADoAAAJAIABB/v8DEHQEQEGsIygCACgCAAR/QQQFQQELIAJGBEBBASEEBUEBIQQDQAJAAkACQANAAkAgACAHQQJ0aigCACIFQf7/A0gNAiAFQf7/A2sNACAHQQFqIQcgBiACQawjKAIAKAIABH9BBAVBAQtrSQ0BDAgLCwwBCyAFRQ0BCyAHQQFqIQcgBUGAf3FBgMEDRgR/IAEgBmogBToAACAGQQFqBSADQgA3AwAgASAGaiIIIAUgAxCRAUF/RgRAQQAhBAsgA0IANwMAIAhBrCMoAgAoAgAEf0EEBUEBCyADEIgCIgVBAUoEfyAFBUEBCyAGagsiBiACQawjKAIAKAIABH9BBAVBAQtrSQ0BDAQLCyABIAZqQQA6AAALBSADQgA3AwAgBCAANgIAAn8CQAJAAkAgASAEIAIgAxC4A0F/aw4CAAECC0EADAILIAAoAgBFDAELQQELIQQLCyACRQRAIAMkBCAEQf8BcUEARw8LIAEgAkF/ampBADoAACADJAQgBEH/AXFBAEcLNgEDfyAAIQIDQCABQQRqIQMgAkEEaiEEIAIgASgCACIBNgIAIAEEQCAEIQIgAyEBDAELCyAAC1ABAn8CfyACBH8DQCAALAAAIgMgASwAACIERgRAIABBAWohACABQQFqIQFBACACQX9qIgJFDQMaDAELCyADQf8BcSAEQf8BcWsFQQALCyIAC443AQx/AkACQAJAIwQhASMEQRBqJAQgASEKAkAgAEH1AUkEQCAAQQtqQXhxIQJBwLcDKAIAIgYgAEELSQR/QRAiAgUgAgtBA3YiAHYiAUEDcQRAIAFBAXFBAXMgAGoiAEEDdEHotwNqIgFBCGoiBSgCACICQQhqIgQoAgAiAyABRgRAQcC3AyAGQQEgAHRBf3NxNgIABSADIAE2AgwgBSADNgIACyACIABBA3QiAEEDcjYCBCACIABqQQRqIgAgACgCAEEBcjYCACAKJAQgBA8LIAJByLcDKAIAIghLBEAgAQRAIAEgAHRBAiAAdCIAQQAgAGtycSIAQQAgAGtxQX9qIgFBDHZBEHEhACABIAB2IgFBBXZBCHEiAyAAciABIAN2IgBBAnZBBHEiAXIgACABdiIAQQF2QQJxIgFyIAAgAXYiAEEBdkEBcSIBciAAIAF2aiIDQQN0Qei3A2oiAEEIaiIEKAIAIgFBCGoiBygCACIFIABGBEBBwLcDIAZBASADdEF/c3EiADYCAAUgBSAANgIMIAQgBTYCACAGIQALIAEgAkEDcjYCBCABIAJqIgQgA0EDdCIDIAJrIgVBAXI2AgQgASADaiAFNgIAIAgEQEHUtwMoAgAhAyAIQQN2IgJBA3RB6LcDaiEBIABBASACdCICcQR/IAFBCGoiAigCAAVBwLcDIAAgAnI2AgAgAUEIaiECIAELIQAgAiADNgIAIAAgAzYCDCADIAA2AgggAyABNgIMC0HItwMgBTYCAEHUtwMgBDYCACAKJAQgBw8LQcS3AygCACIMBEAgDEEAIAxrcUF/aiIBQQx2QRBxIQAgASAAdiIBQQV2QQhxIgMgAHIgASADdiIAQQJ2QQRxIgFyIAAgAXYiAEEBdkECcSIBciAAIAF2IgBBAXZBAXEiAXIgACABdmpBAnRB8LkDaigCACIDKAIEQXhxIAJrIQEgA0EQaiADKAIQRUECdGooAgAiAARAA0AgACgCBEF4cSACayIFIAFJIgQEQCAFIQELIAQEQCAAIQMLIABBEGogACgCEEVBAnRqKAIAIgANACABIQULBSABIQULIAMgAmoiCyADSwRAIAMoAhghCQJAIAMoAgwiACADRgRAIANBFGoiASgCACIARQRAIANBEGoiASgCACIARQRAQQAhAAwDCwsDQCAAQRRqIgQoAgAiBwRAIAchACAEIQEMAQsgAEEQaiIEKAIAIgcEQCAHIQAgBCEBDAELCyABQQA2AgAFIAMoAggiASAANgIMIAAgATYCCAsLAkAgCQRAIAMgAygCHCIBQQJ0QfC5A2oiBCgCAEYEQCAEIAA2AgAgAEUEQEHEtwMgDEEBIAF0QX9zcTYCAAwDCwUgCUEQaiAJKAIQIANHQQJ0aiAANgIAIABFDQILIAAgCTYCGCADKAIQIgEEQCAAIAE2AhAgASAANgIYCyADKAIUIgEEQCAAIAE2AhQgASAANgIYCwsLIAVBEEkEQCADIAUgAmoiAEEDcjYCBCADIABqQQRqIgAgACgCAEEBcjYCAAUgAyACQQNyNgIEIAsgBUEBcjYCBCALIAVqIAU2AgAgCARAQdS3AygCACEEIAhBA3YiAUEDdEHotwNqIQAgBkEBIAF0IgFxBH8gAEEIaiICKAIABUHAtwMgBiABcjYCACAAQQhqIQIgAAshASACIAQ2AgAgASAENgIMIAQgATYCCCAEIAA2AgwLQci3AyAFNgIAQdS3AyALNgIACyAKJAQgA0EIag8FIAIhAAsFIAIhAAsFIAIhAAsFIABBv39LBEBBfyEABSAAQQtqIgBBeHEhA0HEtwMoAgAiBQRAIABBCHYiAAR/IANB////B0sEf0EfBSADQQ4gACAAQYD+P2pBEHZBCHEiAHQiAUGA4B9qQRB2QQRxIgIgAHIgASACdCIAQYCAD2pBEHZBAnEiAXJrIAAgAXRBD3ZqIgBBB2p2QQFxIABBAXRyCwVBAAshCEEAIANrIQICQAJAIAhBAnRB8LkDaigCACIABEBBGSAIQQF2ayEEQQAhASADIAhBH0YEf0EABSAEC3QhB0EAIQQDQCAAKAIEQXhxIANrIgYgAkkEQCAGBEAgACEBIAYhAgVBACECIAAhAQwECwsgACgCFCIGRSAGIABBEGogB0EfdkECdGooAgAiAEZyRQRAIAYhBAsgByAARSIGQQFzdCEHIAZFDQALBUEAIQELIAQgAXIEfyAEBSAFQQIgCHQiAEEAIABrcnEiAEUEQCADIQAMBwsgAEEAIABrcUF/aiIEQQx2QRBxIQBBACEBIAQgAHYiBEEFdkEIcSIHIAByIAQgB3YiAEECdkEEcSIEciAAIAR2IgBBAXZBAnEiBHIgACAEdiIAQQF2QQFxIgRyIAAgBHZqQQJ0QfC5A2ooAgALIgANACABIQQMAQsDQCAAKAIEQXhxIANrIgQgAkkiBwRAIAQhAgsgBwRAIAAhAQsgAEEQaiAAKAIQRUECdGooAgAiAA0AIAEhBAsLIAQEQCACQci3AygCACADa0kEQCAEIANqIgggBE0NBiAEKAIYIQkCQCAEKAIMIgAgBEYEQCAEQRRqIgEoAgAiAEUEQCAEQRBqIgEoAgAiAEUEQEEAIQAMAwsLA0AgAEEUaiIHKAIAIgYEQCAGIQAgByEBDAELIABBEGoiBygCACIGBEAgBiEAIAchAQwBCwsgAUEANgIABSAEKAIIIgEgADYCDCAAIAE2AggLCwJAIAkEQCAEIAQoAhwiAUECdEHwuQNqIgcoAgBGBEAgByAANgIAIABFBEBBxLcDIAVBASABdEF/c3EiADYCAAwDCwUgCUEQaiAJKAIQIARHQQJ0aiAANgIAIABFBEAgBSEADAMLCyAAIAk2AhggBCgCECIBBEAgACABNgIQIAEgADYCGAsgBCgCFCIBBEAgACABNgIUIAEgADYCGAsLIAUhAAsCQCACQRBJBEAgBCACIANqIgBBA3I2AgQgBCAAakEEaiIAIAAoAgBBAXI2AgAFIAQgA0EDcjYCBCAIIAJBAXI2AgQgCCACaiACNgIAIAJBA3YhASACQYACSQRAIAFBA3RB6LcDaiEAQcC3AygCACICQQEgAXQiAXEEfyAAQQhqIgIoAgAFQcC3AyACIAFyNgIAIABBCGohAiAACyEBIAIgCDYCACABIAg2AgwgCCABNgIIIAggADYCDAwCCyACQQh2IgEEfyACQf///wdLBH9BHwUgAkEOIAEgAUGA/j9qQRB2QQhxIgF0IgNBgOAfakEQdkEEcSIFIAFyIAMgBXQiAUGAgA9qQRB2QQJxIgNyayABIAN0QQ92aiIBQQdqdkEBcSABQQF0cgsFQQALIgFBAnRB8LkDaiEDIAggATYCHCAIQRBqIgVBADYCBCAFQQA2AgAgAEEBIAF0IgVxRQRAQcS3AyAAIAVyNgIAIAMgCDYCACAIIAM2AhggCCAINgIMIAggCDYCCAwCCyADKAIAIQBBGSABQQF2ayEDIAIgAUEfRgR/QQAFIAMLdCEBAkADQCAAKAIEQXhxIAJGDQEgAUEBdCEDIABBEGogAUEfdkECdGoiASgCACIFBEAgAyEBIAUhAAwBCwsgASAINgIAIAggADYCGCAIIAg2AgwgCCAINgIIDAILIABBCGoiASgCACICIAg2AgwgASAINgIAIAggAjYCCCAIIAA2AgwgCEEANgIYCwsgCiQEIARBCGoPBSADIQALBSADIQALBSADIQALCwsLQci3AygCACICIABPBEBB1LcDKAIAIQEgAiAAayIDQQ9LBEBB1LcDIAEgAGoiBTYCAEHItwMgAzYCACAFIANBAXI2AgQgASACaiADNgIAIAEgAEEDcjYCBAVByLcDQQA2AgBB1LcDQQA2AgAgASACQQNyNgIEIAEgAmpBBGoiACAAKAIAQQFyNgIACwwDC0HMtwMoAgAiAiAASwRAQcy3AyACIABrIgI2AgAMAgtBmLsDKAIABH9BoLsDKAIABUGguwNBgCA2AgBBnLsDQYAgNgIAQaS7A0F/NgIAQai7A0F/NgIAQay7A0EANgIAQfy6A0EANgIAQZi7AyAKQXBxQdiq1aoFczYCAEGAIAsiASAAQS9qIgRqIgdBACABayIGcSIFIABNDQBB+LoDKAIAIgEEQEHwugMoAgAiAyAFaiIIIANNIAggAUtyDQELIABBMGohCAJAAkBB/LoDKAIAQQRxBEBBACECBQJAAkACQEHYtwMoAgAiAUUNAEGAuwMhAwNAAkAgAygCACIJIAFNBEAgCSADQQRqIgkoAgBqIAFLDQELIAMoAggiAw0BDAILCyAHIAJrIAZxIgJB/////wdJBEAgAhCHASIBIAMoAgAgCSgCAGpGBEAgAUF/Rw0GBQwDCwVBACECCwwCC0EAEIcBIgFBf0YEQEEAIQIFQZy7AygCACICQX9qIgMgAWpBACACa3EgAWshAiADIAFxBH8gAgVBAAsgBWoiAkHwugMoAgAiB2ohAyACIABLIAJB/////wdJcQRAQfi6AygCACIGBEAgAyAHTSADIAZLcgRAQQAhAgwFCwsgAhCHASIDIAFGDQUgAyEBDAIFQQAhAgsLDAELIAggAksgAkH/////B0kgAUF/R3FxRQRAIAFBf0YEQEEAIQIMAgUMBAsACyAEIAJrQaC7AygCACIDakEAIANrcSIDQf////8HTw0CQQAgAmshBCADEIcBQX9GBEAgBBCHARpBACECBSADIAJqIQIMAwsLQfy6A0H8ugMoAgBBBHI2AgALIAVB/////wdJBEAgBRCHASIBQQAQhwEiA0kgAUF/RyADQX9HcXEhBSADIAFrIgMgAEEoaksiBARAIAMhAgsgAUF/RiAEQQFzciAFQQFzckUNAQsMAQtB8LoDQfC6AygCACACaiIDNgIAIANB9LoDKAIASwRAQfS6AyADNgIACwJAQdi3AygCACIEBEBBgLsDIQMCQAJAA0AgASADKAIAIgUgA0EEaiIHKAIAIgZqRg0BIAMoAggiAw0ACwwBCyADKAIMQQhxRQRAIAEgBEsgBSAETXEEQCAHIAYgAmo2AgBBzLcDKAIAIAJqIQJBACAEQQhqIgNrQQdxIQFB2LcDIAQgA0EHcQR/IAEFQQAiAQtqIgM2AgBBzLcDIAIgAWsiATYCACADIAFBAXI2AgQgBCACakEoNgIEQdy3A0GouwMoAgA2AgAMBAsLCyABQdC3AygCAEkEQEHQtwMgATYCAAsgASACaiEFQYC7AyEDAkACQANAIAMoAgAgBUYNASADKAIIIgMNAEGAuwMhAwsMAQsgAygCDEEIcQRAQYC7AyEDBSADIAE2AgAgA0EEaiIDIAMoAgAgAmo2AgBBACABQQhqIgJrQQdxIQNBACAFQQhqIgdrQQdxIQkgASACQQdxBH8gAwVBAAtqIgggAGohBiAFIAdBB3EEfyAJBUEAC2oiBSAIayAAayEHIAggAEEDcjYCBAJAIAQgBUYEQEHMtwNBzLcDKAIAIAdqIgA2AgBB2LcDIAY2AgAgBiAAQQFyNgIEBUHUtwMoAgAgBUYEQEHItwNByLcDKAIAIAdqIgA2AgBB1LcDIAY2AgAgBiAAQQFyNgIEIAYgAGogADYCAAwCCyAFKAIEIgBBA3FBAUYEfyAAQXhxIQkgAEEDdiECAkAgAEGAAkkEQCAFKAIMIgAgBSgCCCIBRgRAQcC3A0HAtwMoAgBBASACdEF/c3E2AgAFIAEgADYCDCAAIAE2AggLBSAFKAIYIQQCQCAFKAIMIgAgBUYEQCAFQRBqIgFBBGoiAigCACIABEAgAiEBBSABKAIAIgBFBEBBACEADAMLCwNAIABBFGoiAigCACIDBEAgAyEAIAIhAQwBCyAAQRBqIgIoAgAiAwRAIAMhACACIQEMAQsLIAFBADYCAAUgBSgCCCIBIAA2AgwgACABNgIICwsgBEUNAQJAIAUoAhwiAUECdEHwuQNqIgIoAgAgBUYEQCACIAA2AgAgAA0BQcS3A0HEtwMoAgBBASABdEF/c3E2AgAMAwUgBEEQaiAEKAIQIAVHQQJ0aiAANgIAIABFDQMLCyAAIAQ2AhggBUEQaiICKAIAIgEEQCAAIAE2AhAgASAANgIYCyACKAIEIgFFDQEgACABNgIUIAEgADYCGAsLIAUgCWohACAJIAdqBSAFIQAgBwshBSAAQQRqIgAgACgCAEF+cTYCACAGIAVBAXI2AgQgBiAFaiAFNgIAIAVBA3YhASAFQYACSQRAIAFBA3RB6LcDaiEAQcC3AygCACICQQEgAXQiAXEEfyAAQQhqIgIoAgAFQcC3AyACIAFyNgIAIABBCGohAiAACyEBIAIgBjYCACABIAY2AgwgBiABNgIIIAYgADYCDAwCCwJ/IAVBCHYiAAR/QR8gBUH///8HSw0BGiAFQQ4gACAAQYD+P2pBEHZBCHEiAHQiAUGA4B9qQRB2QQRxIgIgAHIgASACdCIAQYCAD2pBEHZBAnEiAXJrIAAgAXRBD3ZqIgBBB2p2QQFxIABBAXRyBUEACwsiAUECdEHwuQNqIQAgBiABNgIcIAZBEGoiAkEANgIEIAJBADYCAEHEtwMoAgAiAkEBIAF0IgNxRQRAQcS3AyACIANyNgIAIAAgBjYCACAGIAA2AhggBiAGNgIMIAYgBjYCCAwCCyAAKAIAIQBBGSABQQF2ayECIAUgAUEfRgR/QQAFIAILdCEBAkADQCAAKAIEQXhxIAVGDQEgAUEBdCECIABBEGogAUEfdkECdGoiASgCACIDBEAgAiEBIAMhAAwBCwsgASAGNgIAIAYgADYCGCAGIAY2AgwgBiAGNgIIDAILIABBCGoiASgCACICIAY2AgwgASAGNgIAIAYgAjYCCCAGIAA2AgwgBkEANgIYCwsgCiQEIAhBCGoPCwsDQAJAIAMoAgAiBSAETQRAIAUgAygCBGoiCCAESw0BCyADKAIIIQMMAQsLQQAgCEFRaiIDQQhqIgVrQQdxIQcgAyAFQQdxBH8gBwVBAAtqIgMgBEEQaiIMSQR/IAQiAwUgAwtBCGohBiADQRhqIQUgAkFYaiEJQQAgAUEIaiILa0EHcSEHQdi3AyABIAtBB3EEfyAHBUEAIgcLaiILNgIAQcy3AyAJIAdrIgc2AgAgCyAHQQFyNgIEIAEgCWpBKDYCBEHctwNBqLsDKAIANgIAIANBBGoiB0EbNgIAIAZBgLsDKQIANwIAIAZBiLsDKQIANwIIQYC7AyABNgIAQYS7AyACNgIAQYy7A0EANgIAQYi7AyAGNgIAIAUhAQNAIAFBBGoiAkEHNgIAIAFBCGogCEkEQCACIQEMAQsLIAMgBEcEQCAHIAcoAgBBfnE2AgAgBCADIARrIgdBAXI2AgQgAyAHNgIAIAdBA3YhAiAHQYACSQRAIAJBA3RB6LcDaiEBQcC3AygCACIDQQEgAnQiAnEEfyABQQhqIgMoAgAFQcC3AyADIAJyNgIAIAFBCGohAyABCyECIAMgBDYCACACIAQ2AgwgBCACNgIIIAQgATYCDAwDCyAHQQh2IgEEfyAHQf///wdLBH9BHwUgB0EOIAEgAUGA/j9qQRB2QQhxIgF0IgJBgOAfakEQdkEEcSIDIAFyIAIgA3QiAUGAgA9qQRB2QQJxIgJyayABIAJ0QQ92aiIBQQdqdkEBcSABQQF0cgsFQQALIgJBAnRB8LkDaiEBIAQgAjYCHCAEQQA2AhQgDEEANgIAQcS3AygCACIDQQEgAnQiBXFFBEBBxLcDIAMgBXI2AgAgASAENgIAIAQgATYCGCAEIAQ2AgwgBCAENgIIDAMLIAEoAgAhAUEZIAJBAXZrIQMgByACQR9GBH9BAAUgAwt0IQICQANAIAEoAgRBeHEgB0YNASACQQF0IQMgAUEQaiACQR92QQJ0aiICKAIAIgUEQCADIQIgBSEBDAELCyACIAQ2AgAgBCABNgIYIAQgBDYCDCAEIAQ2AggMAwsgAUEIaiICKAIAIgMgBDYCDCACIAQ2AgAgBCADNgIIIAQgATYCDCAEQQA2AhgLBUHQtwMoAgAiA0UgASADSXIEQEHQtwMgATYCAAtBgLsDIAE2AgBBhLsDIAI2AgBBjLsDQQA2AgBB5LcDQZi7AygCADYCAEHgtwNBfzYCAEH0twNB6LcDNgIAQfC3A0HotwM2AgBB/LcDQfC3AzYCAEH4twNB8LcDNgIAQYS4A0H4twM2AgBBgLgDQfi3AzYCAEGMuANBgLgDNgIAQYi4A0GAuAM2AgBBlLgDQYi4AzYCAEGQuANBiLgDNgIAQZy4A0GQuAM2AgBBmLgDQZC4AzYCAEGkuANBmLgDNgIAQaC4A0GYuAM2AgBBrLgDQaC4AzYCAEGouANBoLgDNgIAQbS4A0GouAM2AgBBsLgDQai4AzYCAEG8uANBsLgDNgIAQbi4A0GwuAM2AgBBxLgDQbi4AzYCAEHAuANBuLgDNgIAQcy4A0HAuAM2AgBByLgDQcC4AzYCAEHUuANByLgDNgIAQdC4A0HIuAM2AgBB3LgDQdC4AzYCAEHYuANB0LgDNgIAQeS4A0HYuAM2AgBB4LgDQdi4AzYCAEHsuANB4LgDNgIAQei4A0HguAM2AgBB9LgDQei4AzYCAEHwuANB6LgDNgIAQfy4A0HwuAM2AgBB+LgDQfC4AzYCAEGEuQNB+LgDNgIAQYC5A0H4uAM2AgBBjLkDQYC5AzYCAEGIuQNBgLkDNgIAQZS5A0GIuQM2AgBBkLkDQYi5AzYCAEGcuQNBkLkDNgIAQZi5A0GQuQM2AgBBpLkDQZi5AzYCAEGguQNBmLkDNgIAQay5A0GguQM2AgBBqLkDQaC5AzYCAEG0uQNBqLkDNgIAQbC5A0GouQM2AgBBvLkDQbC5AzYCAEG4uQNBsLkDNgIAQcS5A0G4uQM2AgBBwLkDQbi5AzYCAEHMuQNBwLkDNgIAQci5A0HAuQM2AgBB1LkDQci5AzYCAEHQuQNByLkDNgIAQdy5A0HQuQM2AgBB2LkDQdC5AzYCAEHkuQNB2LkDNgIAQeC5A0HYuQM2AgBB7LkDQeC5AzYCAEHouQNB4LkDNgIAIAJBWGohA0EAIAFBCGoiBWtBB3EhAkHYtwMgASAFQQdxBH8gAgVBACICC2oiBTYCAEHMtwMgAyACayICNgIAIAUgAkEBcjYCBCABIANqQSg2AgRB3LcDQai7AygCADYCAAsLQcy3AygCACIBIABLBEBBzLcDIAEgAGsiAjYCAAwDCwtBiLwDQQw2AgAgCiQEQQAPCyAKJARBAA8LQdi3A0HYtwMoAgAiASAAaiIDNgIAIAMgAkEBcjYCBCABIABBA3I2AgQLIAokBCABQQhqC8ESASd/IwQhAiMEQYABaiQEIAJBQGsiAyABLQABQQh0IAEtAAByIAEtAAJBEHRyIAEtAANBGHRyNgIAIAMgAS0ABUEIdCABLQAEciABLQAGQRB0ciABLQAHQRh0cjYCBCADIAEtAAlBCHQgAS0ACHIgAS0ACkEQdHIgAS0AC0EYdHI2AgggAyABLQANQQh0IAEtAAxyIAEtAA5BEHRyIAEtAA9BGHRyNgIMIAMgAS0AEUEIdCABLQAQciABLQASQRB0ciABLQATQRh0cjYCECADIAEtABVBCHQgAS0AFHIgAS0AFkEQdHIgAS0AF0EYdHI2AhQgAyABLQAZQQh0IAEtABhyIAEtABpBEHRyIAEtABtBGHRyNgIYIAMgAS0AHUEIdCABLQAcciABLQAeQRB0ciABLQAfQRh0cjYCHCADIAEtACFBCHQgAS0AIHIgAS0AIkEQdHIgAS0AI0EYdHI2AiAgAyABLQAlQQh0IAEtACRyIAEtACZBEHRyIAEtACdBGHRyNgIkIAMgAS0AKUEIdCABLQAociABLQAqQRB0ciABLQArQRh0cjYCKCADIAEtAC1BCHQgAS0ALHIgAS0ALkEQdHIgAS0AL0EYdHI2AiwgAyABLQAxQQh0IAEtADByIAEtADJBEHRyIAEtADNBGHRyNgIwIAMgAS0ANUEIdCABLQA0ciABLQA2QRB0ciABLQA3QRh0cjYCNCADIAEtADlBCHQgAS0AOHIgAS0AOkEQdHIgAS0AO0EYdHI2AjggAyABLQA9QQh0IAEtADxyIAEtAD5BEHRyIAEtAD9BGHRyNgI8IAIiBSAAQfQBaiIjKAIAIgIoAgAiDDYCACAFQQRqIhUgAigCBCIKNgIAIAVBCGoiFiACKAIIIgY2AgAgBUEMaiIXIAIoAgwiATYCACAFQRBqIhggAigCECILNgIAIAVBFGoiGSACKAIUIg82AgAgBUEYaiIkIAIoAhgiDTYCACAFQRxqIiUgAigCHCIINgIAIAVBIGoiJkHnzKfQBjYCACAFQSRqIhpBhd2e23s2AgAgBUEoaiIbQfLmu+MDNgIAIAVBLGoiHEG66r+qejYCACAFQTBqIh0gACgC+AEiAigCAEH/pLmIBXMiBzYCACAFQTRqIh4gAigCBEGM0ZXYeXMiCTYCACAFQThqIicgACgC/AEiACgCAEGrs4/8AXMiAjYCACAFQTxqIiggACgCBEGZmoPfBXMiADYCAEHnzKfQBiEQQYXdntt7IRJB8ua74wMhE0G66r+qeiEUA0AgCyAHIAsgDGogAyAEQQR0Qfcuai0AAEECdGooAgBqIg5zIgdBEHQgB0EQdnIiCyAQaiIMcyIHQRR0IAdBDHZyIgcgDmogAyAEQQR0Qfguai0AAEECdGooAgBqIREgByALIBFzIgdBGHQgB0EIdnIiDiAMaiIQcyIHQRl0IAdBB3ZyIR8gDyAJIA8gCmogAyAEQQR0Qfkuai0AAEECdGooAgBqIgpzIglBEHQgCUEQdnIiCyASaiIPcyIJQRR0IAlBDHZyIgwgCmogAyAEQQR0Qfouai0AAEECdGooAgBqISAgDSACIA0gBmogAyAEQQR0Qfsuai0AAEECdGooAgBqIgpzIgJBEHQgAkEQdnIiCSATaiIGcyICQRR0IAJBDHZyIgIgCmogAyAEQQR0Qfwuai0AAEECdGooAgBqISEgAiAJICFzIgJBGHQgAkEIdnIiEiAGaiIHcyICQRl0IAJBB3ZyIQ0gCCAAIAggAWogAyAEQQR0Qf0uai0AAEECdGooAgBqIgZzIgBBEHQgAEEQdnIiASAUaiICcyIAQRR0IABBDHZyIgAgBmogAyAEQQR0Qf4uai0AAEECdGooAgBqISIgACABICJzIgBBGHQgAEEIdnIiASACaiIKcyIAQRl0IABBB3ZyIQggASAMIAsgIHMiAEEYdCAAQQh2ciIJIA9qIgtzIgBBGXQgAEEHdnIiASARaiADIARBBHRB/y5qLQAAQQJ0aigCAGoiAnMiAEEQdCAAQRB2ciIAIAdqIQYgACABIAZzIgBBFHQgAEEMdnIiASACaiADIARBBHRBgC9qLQAAQQJ0aigCAGoiDHMiAEEYdCAAQQh2ciIRIAZqIRMgASATcyIAQRl0IABBB3ZyIQ8gDSAOIA0gIGogAyAEQQR0QYEvai0AAEECdGooAgBqIgZzIgBBEHQgAEEQdnIiAiAKaiIBcyIAQRR0IABBDHZyIgAgBmogAyAEQQR0QYIvai0AAEECdGooAgBqIQogACACIApzIgBBGHQgAEEIdnIiByABaiIUcyIAQRl0IABBB3ZyIQ0gCCAJIAggIWogAyAEQQR0QYMvai0AAEECdGooAgBqIgZzIgBBEHQgAEEQdnIiAiAQaiIBcyIAQRR0IABBDHZyIgAgBmogAyAEQQR0QYQvai0AAEECdGooAgBqIQYgACACIAZzIgBBGHQgAEEIdnIiCSABaiIQcyIAQRl0IABBB3ZyIQ4gHyASIB8gImogAyAEQQR0QYUvai0AAEECdGooAgBqIghzIgBBEHQgAEEQdnIiAiALaiIBcyIAQRR0IABBDHZyIgAgCGogAyAEQQR0QYYvai0AAEECdGooAgBqIQggACACIAhzIgBBGHQgAEEIdnIiAiABaiIBcyIAQRl0IABBB3ZyIQsgBEEBaiIAQQpHBEAgACEEIAEhEiAIIQEgDiEIIBEhAAwBCwsgBSAMNgIAIBggCzYCACAdIAc2AgAgJiAQNgIAIBUgCjYCACAZIA82AgAgHiAJNgIAIBogATYCACAWIAY2AgAgJCANNgIAICcgAjYCACAbIBM2AgAgFyAINgIAICUgDjYCACAoIBE2AgAgHCAUNgIAICMoAgAiASAMIAEoAgBzIBBzNgIAIAFBBGoiACAVKAIAIAAoAgBzIBooAgBzNgIAIAFBCGoiACAWKAIAIAAoAgBzIBsoAgBzNgIAIAFBDGoiACAXKAIAIAAoAgBzIBwoAgBzNgIAIAFBEGoiACAYKAIAIAAoAgBzIB0oAgBzNgIAIAFBFGoiACAZKAIAIAAoAgBzIB4oAgBzNgIAIAFBGGoiACANIAAoAgBzIAJzNgIAIAFBHGoiACAOIAAoAgBzIBFzNgIAIAUkBAuBAQEDfwJAIAAiAkEDcQRAIAIhAQNAIAEsAABFDQIgAUEBaiIBIgBBA3ENACABIQALCwNAIABBBGohASAAKAIAIgNBgIGChHhxQYCBgoR4cyADQf/9+3dqcUUEQCABIQAMAQsLIANB/wFxBEADQCAAQQFqIgAsAAANAAsLCyAAIAJrCysBAX8gAkUEQCAADwsgACABIAJBf2oiAxCuARogACADQQJ0akEANgIAIAALdwECfyAAQcQdNgIAIABBBGoiAigCACIBRQRADwsgACwAEARADwsgACwAEgRAQQAkBSMFIQBBACQFIABBAXFFBEAPCwVBACQFQSwgARAMIwUhAUEAJAUgAUEBcUUEQCACQQA2AgAgAEEANgIMDwsLQQAQGCIAEFoLhQsBFn8gAEHglwFqIhQoAgAiAyAAQcgMaiIPKAIAIgRPBEBBfw8LIABB6JcBaiIFKAIAIgIgBEkEQEF/DwsgBC4BAEEBRgRAIAQgABCJBAUgBCgCCCIBIANNIAEgAktyBEBBfw8LIAQgABCKBEUEQEF/DwsLIABB9JQBaiIIKAIAIABBgJUBaiIJKAIAIgIgAEH8lAFqIgYoAgAiAWxqIQMgCCADNgIAIAYgAEGElQFqIgwoAgAgAmsgAWwiAjYCAAJAIABB1AxqIhAoAgAiAQRAIABB4AxqIQMFIABB+JQBaiEVIABBjJUBaiERIABB4AxqIQQgAEHYDGohByADIQECQAJAA0ACQANAAkAgAiABaiABc0GAgIAITwRAIAJBgIACTw0BIAZBACABa0H//wFxNgIACyAVKAIAIRMgESgCACIKQQRqIhIoAgAiAUHi/wFKBEAgCkHoAGoiCygCACABayINQQBOBEAgCkHwAGoiFiAKQfgAaiIOKAIAIAFrIBYoAgBqNgIAAkACQCANBEAgCkEQaiICKAIAIgMgAyABaiANEF0aIBJBADYCACALIA02AgAgDUGAgAJHDQFBgIACIQEFIBJBADYCACALQQA2AgAgCkEQaiECDAELDAELIAooAgAgAigCACANakGAgAIgDWsQXiEDIAsoAgAiASADaiECIANBAEoEQCALIAI2AgAgAiEBCwsgCkHsAGoiAyABQWJqIgs2AgAgDiASKAIAIgE2AgAgAUF/aiAWKAIAIgJqIQ4gAkF/RwRAIAMgCyAOSAR/IAsFIA4LNgIACwsLIAooAhAhAiASIAFBAWo2AgAgFSATQQh0IAIgAWotAAByNgIAIAYgBigCAEEIdCICNgIAIAggCCgCAEEIdCIBNgIADAELCyAUKAIAIQMgBCgCACECIA8oAgAhAQNAIAJBAWohAiADIAEoAgwiAU8NASAFKAIAIAFJDQEgBygCACABLwEARg0ACyAEIAI2AgAgDyABNgIAIAEgABCIBEUEQEF/IQIMAwsgCCAIKAIAIAkoAgAiAyAGKAIAIgJsaiIBNgIAIAYgDCgCACADayACbCICNgIAIBAoAgAiA0UNASADIQEgBCEDDAULCwwBC0F/DwsgBCACNgIAIA8gATYCAEF/DwsLIAEtAAAhAgJAAkAgAygCAA0AIBQoAgAgASgCBCIBTw0AIABB0AxqIAE2AgAgDyABNgIADAELIAAQhwQgAEHwFGoiASwAAEUEQCABQQE6AAAgAEHwDGpBAEGAAhBUGgsLIABB+JQBaiEQIABBjJUBaiETIAgoAgAhACAGKAIAIQEDQAJAIAEgAGogAHNBgICACE8EQCABQYCAAk8NASAGQQAgAGtB//8BcTYCAAsgECgCACEOIBMoAgAiBUEEaiIMKAIAIgBB4v8BSgRAIAVB6ABqIgcoAgAgAGsiCUEATgRAIAVB8ABqIhEgBUH4AGoiBCgCACAAayARKAIAajYCAAJAAkAgCQRAIAVBEGoiASgCACIDIAMgAGogCRBdGiAMQQA2AgAgByAJNgIAIAlBgIACRw0BQYCAAiEABSAMQQA2AgAgB0EANgIAIAVBEGohAQwBCwwBCyAFKAIAIAEoAgAgCWpBgIACIAlrEF4hAyAHKAIAIgAgA2ohASADQQBKBEAgByABNgIAIAEhAAsLIAVB7ABqIgMgAEFiaiIHNgIAIAQgDCgCACIANgIAIABBf2ogESgCACIBaiEEIAFBf0cEQCADIAcgBEgEfyAHBSAECzYCAAsLCyAFKAIQIQEgDCAAQQFqNgIAIBAgDkEIdCABIABqLQAAcjYCACAGIAYoAgBBCHQiATYCACAIIAgoAgBBCHQiADYCAAwBCwsgAgvKAQECfwJAIAAQWCIBQYCAA3EiAkEQdEEQdUEASARAIAJBEHRBEHVBgIB+aw0BIABBAhBVIAAQWCEBIABBEBBVIAEPBSACQRB0QRB1QYCAAUgEQCACDQIgAEEGEFUgAUEKdkEPcQ8LIAJBEHRBEHVBgIABaw0BIAFBgPgAcQRAIABBChBVIAFBBnZB/wFxDwUgAEEOEFUgAUECdkGAfnIPCwALAAsgAEECEFUgABBYQRB0IQEgAEEQEFUgABBYIAFyIQEgAEEQEFUgAQteAQJ/IAEoAgAiAkUgACgCACIDRSADIAJHcnIEQCACIQAgAyEBBQNAIAFBBGoiASgCACICRSAAQQRqIgAoAgAiA0UgAyACR3JyBEAgAiEAIAMhAQUMAQsLCyABIABrC0QBAn8gAQRAA0AgAEEEaiEDIAAoAgAiAkUgAiABRnJFBEAgAyEADAELCyACRQRAQQAhAAsFIAAgABBZQQJ0aiEACyAAC9gEAQF/IAAoAoABIAFLBEAgACgCACABag8LAkAgACgChAEgAUsEQEEBIQIFIAAoAogBIAFLBEBBAiECBSAAKAKMASABSwRAQQMhAgUgACgCkAEgAUsEQEEEIQIFIAAoApQBIAFLBEBBBSECBSAAKAKYASABSwRAQQYhAgUgACgCnAEgAUsEQEEHIQIFIAAoAqABIAFLBEBBCCECBSAAKAKkASABSwRAQQkhAgUgACgCqAEgAUsEQEEKIQIFIAAoAqwBIAFLBEBBCyECBSAAKAKwASABSwRAQQwhAgUgACgCtAEgAUsEQEENIQIFIAAoArgBIAFLBEBBDiECBSAAKAK8ASABSwRAQQ8hAgUgACgCwAEgAUsEQEEQIQIFIAAoAsQBIAFLBEBBESECBSAAKALIASABSwRAQRIhAgUgACgCzAEgAUsEQEETIQIMEwsgACgC0AEgAUsEQEEUIQIMEwsgACgC1AEgAUsEQEEVIQIMEwsgACgC2AEgAUsEQEEWIQIMEwsgACgC3AEgAUsEQEEXIQIMEwsgACgC4AEgAUsEQEEYIQIMEwsgACgC5AEgAUsEQEEZIQIMEwsgACgC6AEgAUsEQEEaIQIMEwsgACgC7AEgAUsEQEEbIQIMEwsgACgC8AEgAUsEQEEcIQIMEwsgACgC9AEgAUsEQEEdIQIMEwsgACgC+AEgAUsEQEEeIQIMEwsgACgC/AEgAUsEQEEfIQIMEwsgACgCAA8LCwsLCwsLCwsLCwsLCwsLCwsLIAAgAkECdGooAgAgASAAIAJBAnRqKAJ8a2oL7QMBB38gAEHgAGoiBigCACIEIAJrIgMgAEHMzQNqKAIAQf9faiIFSSAEIAVJcUUEQCABRQRADwsgAEGklgFqIQcgAyECIABB0M0DaiIIKAIAIQMgBCEAA0AgAkEBaiEEIAcoAgAiBSAAaiAFIAMgAnFqLAAAOgAAIAYgBigCAEEBaiAIKAIAIgNxIgA2AgAgAUF/aiIBBEAgBCECDAELCw8LIABBpJYBaigCACIJIANqIQMgCSAEaiEAIAYgBCABajYCACABQQdLBEAgCSAEIAFBeGoiB0F4cSIIakEIaiIFIAJraiEEIAMhAgNAIAAgAiwAADoAACAAIAIsAAE6AAEgACACLAACOgACIAAgAiwAAzoAAyAAIAIsAAQ6AAQgACACLAAFOgAFIAAgAiwABjoABiAAIAIsAAc6AAcgAkEIaiECIABBCGohACABQXhqIgFBB0sNAAsgCSAFaiEAIAQhAyAHIAhrIQELIAFFBEAPCyAAIAMsAAA6AAAgAUEBRgRADwsgACADLAABOgABIAFBAk0EQA8LIAAgAywAAjoAAiABQQNGBEAPCyAAIAMsAAM6AAMgAUEETQRADwsgACADLAAEOgAEIAFBBUYEQA8LIAAgAywABToABSABQQZNBEAPCyAAIAMsAAY6AAYLhxABBH8jBCEFIwRBgAhqJAQgBUGABGohAiAALACABAR/IAIgAEGABBBTGiMEIQAjBEEQaiQEQRQgABAlIQMgACQEIANBywBqIQRBACEAA0AgAiAAaiIDIAQgAGogAy0AAHM6AAAgAEEBaiIAQYAERw0ACyACQfwDagUgAgshAyAFIQAgA0EANgIAIAEsAIAEBH8gACABQYAEEFMaIwQhASMEQRBqJARBFCABECUhAyABJAQgA0HLAGohBEEAIQEDQCAAIAFqIgMgBCABaiADLQAAczoAACABQQFqIgFBgARHDQALIABB/ANqBSAAC0EANgIAIAIgABBzIQEgAkEAOgAAIAJBADoAASACQQA6AAIgAkEAOgADIAJBADoABCACQQA6AAUgAkEAOgAGIAJBADoAByACQQA6AAggAkEAOgAJIAJBADoACiACQQA6AAsgAkEAOgAMIAJBADoADSACQQA6AA4gAkEAOgAPIAJBADoAECACQQA6ABEgAkEAOgASIAJBADoAEyACQQA6ABQgAkEAOgAVIAJBADoAFiACQQA6ABcgAkEAOgAYIAJBADoAGSACQQA6ABogAkEAOgAbIAJBADoAHCACQQA6AB0gAkEAOgAeIAJBADoAHyACQQA6ACAgAkEAOgAhIAJBADoAIiACQQA6ACMgAkEAOgAkIAJBADoAJSACQQA6ACYgAkEAOgAnIAJBADoAKCACQQA6ACkgAkEAOgAqIAJBADoAKyACQQA6ACwgAkEAOgAtIAJBADoALiACQQA6AC8gAkEAOgAwIAJBADoAMSACQQA6ADIgAkEAOgAzIAJBADoANCACQQA6ADUgAkEAOgA2IAJBADoANyACQQA6ADggAkEAOgA5IAJBADoAOiACQQA6ADsgAkEAOgA8IAJBADoAPSACQQA6AD4gAkEAOgA/IAJBQGtBADoAACACQQA6AEEgAkEAOgBCIAJBADoAQyACQQA6AEQgAkEAOgBFIAJBADoARiACQQA6AEcgAkEAOgBIIAJBADoASSACQQA6AEogAkEAOgBLIAJBADoATCACQQA6AE0gAkEAOgBOIAJBADoATyACQQA6AFAgAkEAOgBRIAJBADoAUiACQQA6AFMgAkEAOgBUIAJBADoAVSACQQA6AFYgAkEAOgBXIAJBADoAWCACQQA6AFkgAkEAOgBaIAJBADoAWyACQQA6AFwgAkEAOgBdIAJBADoAXiACQQA6AF8gAkEAOgBgIAJBADoAYSACQQA6AGIgAkEAOgBjIAJBADoAZCACQQA6AGUgAkEAOgBmIAJBADoAZyACQQA6AGggAkEAOgBpIAJBADoAaiACQQA6AGsgAkEAOgBsIAJBADoAbSACQQA6AG4gAkEAOgBvIAJBADoAcCACQQA6AHEgAkEAOgByIAJBADoAcyACQQA6AHQgAkEAOgB1IAJBADoAdiACQQA6AHcgAkEAOgB4IAJBADoAeSACQQA6AHogAkEAOgB7IAJBADoAfCACQQA6AH0gAkEAOgB+IAJBADoAfyAAQQA6AAAgAEEAOgABIABBADoAAiAAQQA6AAMgAEEAOgAEIABBADoABSAAQQA6AAYgAEEAOgAHIABBADoACCAAQQA6AAkgAEEAOgAKIABBADoACyAAQQA6AAwgAEEAOgANIABBADoADiAAQQA6AA8gAEEAOgAQIABBADoAESAAQQA6ABIgAEEAOgATIABBADoAFCAAQQA6ABUgAEEAOgAWIABBADoAFyAAQQA6ABggAEEAOgAZIABBADoAGiAAQQA6ABsgAEEAOgAcIABBADoAHSAAQQA6AB4gAEEAOgAfIABBADoAICAAQQA6ACEgAEEAOgAiIABBADoAIyAAQQA6ACQgAEEAOgAlIABBADoAJiAAQQA6ACcgAEEAOgAoIABBADoAKSAAQQA6ACogAEEAOgArIABBADoALCAAQQA6AC0gAEEAOgAuIABBADoALyAAQQA6ADAgAEEAOgAxIABBADoAMiAAQQA6ADMgAEEAOgA0IABBADoANSAAQQA6ADYgAEEAOgA3IABBADoAOCAAQQA6ADkgAEEAOgA6IABBADoAOyAAQQA6ADwgAEEAOgA9IABBADoAPiAAQQA6AD8gAEFAa0EAOgAAIABBADoAQSAAQQA6AEIgAEEAOgBDIABBADoARCAAQQA6AEUgAEEAOgBGIABBADoARyAAQQA6AEggAEEAOgBJIABBADoASiAAQQA6AEsgAEEAOgBMIABBADoATSAAQQA6AE4gAEEAOgBPIABBADoAUCAAQQA6AFEgAEEAOgBSIABBADoAUyAAQQA6AFQgAEEAOgBVIABBADoAViAAQQA6AFcgAEEAOgBYIABBADoAWSAAQQA6AFogAEEAOgBbIABBADoAXCAAQQA6AF0gAEEAOgBeIABBADoAXyAAQQA6AGAgAEEAOgBhIABBADoAYiAAQQA6AGMgAEEAOgBkIABBADoAZSAAQQA6AGYgAEEAOgBnIABBADoAaCAAQQA6AGkgAEEAOgBqIABBADoAayAAQQA6AGwgAEEAOgBtIABBADoAbiAAQQA6AG8gAEEAOgBwIABBADoAcSAAQQA6AHIgAEEAOgBzIABBADoAdCAAQQA6AHUgAEEAOgB2IABBADoAdyAAQQA6AHggAEEAOgB5IABBADoAeiAAQQA6AHsgAEEAOgB8IABBADoAfSAAQQA6AH4gAEEAOgB/IAAkBCABRQslAQF/IAIgABBZa0F/aiIDQQBMBEAgAA8LIAAgASADELIDGiAACxYAIABBAEHAywQQVBogAEGowAJqEFwLbQEEfyAAKAIUIABBGGoiBCgCACIFayIDIAJJIgYEfyADBSACIgMLBEAgASAAKAIAIAVqIAMQUxoLIAZFBEAgBCAEKAIAIANqNgIAIAMPCyABIANqQQAgAiADaxBUGiAEIAQoAgAgA2o2AgAgAwueAwEIfyMEIQQjBEEgaiQEIARBCGohBSABQQA2AgAgBEIANwMAIARBEGoiAyAANgIAAkACQAJAAkACQAJAIAEgAyACIAQQuQNBf2sOAgABAgsMAgsgACwAAA0BQQEhAAwCC0EBIQAMAQsgAkEBSwRAQQAhAwJAAkADQCAAIAhqIgYsAABFDQEgBUIANwMAIAEgA0ECdGoiCSAGQawjKAIAKAIABH9BBAVBAQsgBRCKAkF/RgR/IAYsAAAiB0EATg0DIApFBEAgCUH+/wM2AgAgA0EBaiIDIAJPDQQgBiwAACEHCyABIANBAnRqIAdB/wFxQYDAA3I2AgBBASEKIAhBAWoFIAVCADcDACAGQawjKAIAKAIABH9BBAVBAQsgBRCIAiIHQQFKBH8gBwVBAQsgCGoLIQggA0EBaiIDIAJJDQBBACEADAULAAsgASADQQJ0akEANgIAQQEhAAwDC0EAIQAFQQAhAAwBCwwBCyACRQRAIAQkBCAAQf8BcUEARw8LCyABIAJBf2pBAnRqQQA2AgAgBCQEIABB/wFxQQBHC/EBAgN/AX4jBCEBIwRB0ABqJAQgAEGtvANqLAAABEAgASQEQQAPCyAAQYi8A2oiAyAAIAAoAgAoAhRBB3FBhgFqEQAAIgQ3AwACQAJAAkACQAJAAkAgAEGYvANqKAIAQQFrDgMAAQIDCyAAENcCIQIMAwsgABDWAiECDAILIAAQ1QIhAgwBCwwBCyACBEAgAykDACEEBSABJARBAA8LCyAAQZC8A2opAwAgBFUEQCABJAQgAg8LIAFBADYCRCABQRg2AkggAUFAa0EBNgIAIAEgAEEYajYCACAAQay8A2pBAToAAEGs9QJBAxBkIAEkBEEAC9cBAgZ/AX4jBCEDIwRBoAJqJAQgA0EgaiEGIAMhBSAAQSBqIgMpAwAhCSADIAkgAq18NwMAIAJFBEAgBUEgEFsgBkGAAhBbIAUkBA8LIABBKGohByAAQSxqIQggCadBP3EhAwNAIAJBwAAgA2siBEsEfyAEBSACIgQLQcAARgRAIAcgATYCAAUgByAINgIAIABBLGogA2ogASAEEFMaCyAEIANqIgNBwABGBEAgABDhAUEAIQMLIAEgBGohASACIARrIgINAAsgBUEgEFsgBkGAAhBbIAUkBAt4AQF/IABB9A02AgAgAEGo8wBqLAAABEAgAEGs8wBqKAIAIgEEQCABEHkgARBSCwsgAEGQ7gJqKAIAIgEEQCABEFILIABB0OcBaigCACIBBEAgARBSCyAAQdjzAGoQtQIgAEHw8QBqEIQBIABBnMAAahCOASAAEHALBgBBEBAACwgAQQUQAEEACwgAQQIQAEEACzABAX8jBCECIwRBEGokBCACIAE2AgBB8CAoAgAiASAAIAIQzgEaQQogARCrAxoQOQujAgEEfyABRQRAIABBvM0DakEANgIAIABByM0DakEANgIAIABBnM0DaiIEKAIAIgEEQCAAQZjNA2ohBQNAIAUoAgAgAkECdGooAgAiAwRAIAMoAjwiAQRAIAEQUgsgAygCLCIBBEAgARBSCyADKAIUIgEEQCABEFILIAMQUiAEKAIAIQELIAJBAWoiAiABSQ0ACwsgBEEANgIACyAAQazNA2oiAygCACICRQRAIANBADYCAA8LIABBqM0DaiEEQQAhASACIQADQCAEKAIAIAFBAnRqKAIAIgIEQCACKAI8IgAEQCAAEFILIAIoAiwiAARAIAAQUgsgAigCFCIABEAgABBSCyACEFIgAygCACEACyABQQFqIgEgAEkNAAsgA0EANgIAC0gBAX8gAEFAaygCACIBBEAgARCOASABEFILIAAoAkQiAQRAIAEQjgEgARBSCyAAQagBahCNASAAQZwBahCNASAAQZABahCNAQsYAEG39QIsAABFBEAPC0Gs9QJB/wEQ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TBogACABEKwDIgALQQEBfwJAIAAQWSICQX9KBEAgACACQQJ0aiECA0AgAigCACABRg0CIAJBfGoiAiAATw0AQQAhAgsFQQAhAgsLIAILZAEDfwJAIAIEQCABIQMgACEBA0AgAygCACIFRQ0CIANBBGohAyABQQRqIQQgASAFNgIAIAJBf2oiAgRAIAQhAQwBBSAEIQFBACECCwsFIAAhAUEAIQILCyABQQAgAhCwAxogAAvCBAEKfyMEIQYjBEGAQGskBCAAIQcDQAJAA0AgACIEKAIAIQgCQAJAA0ACQAJAAkACQCAIDjAAAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgECCyAHIQAMBwsMAQsMAgsgBEEEaiIAKAIAIghBLkYNAiAAIQQMAAsACyAEQQRqIQAMAQsgBCgCCEEuRw0ACyAEQRBqIQggBCgCDEEvRgRAIAghBwsMAQsLAkACQANAAkACQAJAAkACQCAAKAIAIgcOXQACAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAQILDAMLIAAoAgRB3ABGBEAgAEEIakHcABB0IgIEQCACQQRqQdwAEHQiA0EEaiECIAMEfyACBSAAIgILIQMFIAAiAyECCwUgACIDIQILQQ0hBQwBCyAAIgohCSAHIQsLA0AgBUENRgRAQQAhBSADIQogAiEJIAMoAgAhCwsCQAJAAkAgC0Euaw4CAAECCyAKQQRqIQMgCSECQQ0hBQwCCyAKQQRqIgIhA0ENIQUMAQsLIAkgAEYNAiAJIQAMAQsLDAELIAAoAgBBLkYEQCAAKAIEQS5GBEAgAEEIaiICKAIARQRAIAIhAAsLCwsgAUUEQCAGJAQgAA8LIAYgAEGAEBBvGiABIAYQahogBiQEIAALEwAgAAR/IAAgAUEAEJEBBUEACwvaAwMBfwF+AXwCQCABQRRNBEACQAJAAkACQAJAAkACQAJAAkACQAJAIAFBCWsOCgABAgMEBQYHCAkKCyACKAIAQQNqQXxxIgEoAgAhAyACIAFBBGo2AgAgACADNgIADAsLIAIoAgBBA2pBfHEiASgCACEDIAIgAUEE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ACEEQQAhAwNAIAAgDCADrXxBACAAKAIAKAIQQQNxQbgCahECACAIKAIAQQFGBEAgBiAJNgIACyAHLAAABEAgB0EAOgAACyAGKAIAIAEgAiADayIFQYAESQR/IAUFQYAECxBBIgVBf0YEf0GABAUgBQsgBGohBCADQYAEaiIDIAJJDQALIAQPC0Gs9QIgAxC6BEF/DwsgBAuMAgEDfyABKAIAIQIgAEIANwIAIABBADYCCCACQe////8DSwRAIAAQigELIAFBBGohBAJAIAJBAkkEQCAAIAI6AAsgAgRAIAAhAwUgACACQQJ0akEANgIADwsFIAJBBGpBfHEiAUH/////A00EQCAAIAFBAnQQXyIDNgIAIAAgAUGAgICAeHI2AgggACACNgIEDAILQQgQFCEAQQAkBUEXIABBzO4AEA0jBSEBQQAkBSABQQFxBEAQFyEBIAAQGiABEB4FIABB7CU2AgAgAEH4CkEMEBsLCwtBACQFQR0gAyAEIAIQBxojBSEAQQAkBSAAQQFxBEBBABAYIgAQWgUgAyACQQJ0akEANgIACwsPACABIAAoAgBqIAI2AgALDQAgASAAKAIAaigCAAvQBgECfyAAKAIAIgEEQCABEFIgAEEANgIACyAAQQRqIgEoAgAiAgRAIAIQUiABQQA2AgALIABBCGoiASgCACICBEAgAhBSIAFBADYCAAsgAEEMaiIBKAIAIgIEQCACEFIgAUEANgIACyAAQRBqIgEoAgAiAgRAIAIQUiABQQA2AgALIABBFGoiASgCACICBEAgAhBSIAFBADYCAAsgAEEYaiIBKAIAIgIEQCACEFIgAUEANgIACyAAQRxqIgEoAgAiAgRAIAIQUiABQQA2AgALIABBIGoiASgCACICBEAgAhBSIAFBADYCAAsgAEEkaiIBKAIAIgIEQCACEFIgAUEANgIACyAAQShqIgEoAgAiAgRAIAIQUiABQQA2AgALIABBLGoiASgCACICBEAgAhBSIAFBADYCAAsgAEEwaiIBKAIAIgIEQCACEFIgAUEANgIACyAAQTRqIgEoAgAiAgRAIAIQUiABQQA2AgALIABBOGoiASgCACICBEAgAhBSIAFBADYCAAsgAEE8aiIBKAIAIgIEQCACEFIgAUEANgIACyAAQUBrIgEoAgAiAgRAIAIQUiABQQA2AgALIABBxABqIgEoAgAiAgRAIAIQUiABQQA2AgALIABByABqIgEoAgAiAgRAIAIQUiABQQA2AgALIABBzABqIgEoAgAiAgRAIAIQUiABQQA2AgALIABB0ABqIgEoAgAiAgRAIAIQUiABQQA2AgALIABB1ABqIgEoAgAiAgRAIAIQUiABQQA2AgALIABB2ABqIgEoAgAiAgRAIAIQUiABQQA2AgALIABB3ABqIgEoAgAiAgRAIAIQUiABQQA2AgALIABB4ABqIgEoAgAiAgRAIAIQUiABQQA2AgALIABB5ABqIgEoAgAiAgRAIAIQUiABQQA2AgALIABB6ABqIgEoAgAiAgRAIAIQUiABQQA2AgALIABB7ABqIgEoAgAiAgRAIAIQUiABQQA2AgALIABB8ABqIgEoAgAiAgRAIAIQUiABQQA2AgALIABB9ABqIgEoAgAiAgRAIAIQUiABQQA2AgALIABB+ABqIgEoAgAiAgRAIAIQUiABQQA2AgALIABB/ABqIgAoAgAiAUUEQA8LIAEQUiAAQQA2AgAL6AoBGn8jBCECIwRBEGokBCACQQhqIRIgAiEJIABB4ABqIgooAgAgAEHkAGoiDCgCACICayAAQdDNA2oiDSgCACIDcSETIABBNGohBwJAAkAgAEE4aiILKAIARQ0AIABBHGohDiAAQRhqIRQgAEEgaiEXIABBFGohDyAAQczNA2ohGCAAQaiYAWohFSAAQaSWAWohECAAQaiWAWohESAAQbqYAWohGSAAQcCYAWohFiATIQECQAJAAkACQANAAkAgBygCACIGIAVBBHRqIhosAABBCEcEQCAGIAVBBHRqKAIEIQQgBiAFQQR0akENaiIILAAABEAgBCAMKAIAayADcSATSw0CIAhBADoAAAwCCyAGIAVBBHRqKAIIIQYgAyAEIAJrcSABSQRAIAQgAkcEQCAAIAIgBBCzASAEIQIgCigCACAEayANKAIAIgNxIQELIAYgAUsNBCAGBEAgDigCACEBIBQgBjYCACABIAZJBEAgFygCACICQQBHIAYgAktxBH8gCSACNgIAQaz1AkHYGyAJEGBBrPUCEFYgDigCACEBIBQoAgAFIAYLIQIgDygCACACIAFBIGogAUECdmoiAUsEfyACBSABIgILEFciAUUEQEGs9QIQVgsgDyABNgIAIA4gAjYCAAsgDygCACEBAkAgAyAGIARqcSIDQX9qIARJBEAgGCgCACAEayEIIBUsAABFBEAgASAQKAIAIARqIAgQUxogASAIaiAQKAIAIAMQUxoMAgsgCARAQQAhAgNAIAEgAmogESACIARqEHUsAAA6AAAgAkEBaiICIAhHDQALIANFDQILIAEgCGohBEEAIQIDQCAEIAJqIBEgAhB1LAAAOgAAIAJBAWoiAiADRw0ACwUgFSwAAARAQQAhAgNAIAEgAmogESACIARqEHUsAAA6AAAgAkEBaiICIAZHDQALBSABIBAoAgAgBGogBhBTGgsLCyAAIAEgBiAaEPgDIQIgBygCACAFQQR0akEIOgAAIAIEQCAAKAIAIAIgBhBlCyAZQQE6AAAgFiAWKQMAIAatfDcDACAKKAIAIAMiAmsgDSgCACIDcSEBCwsLCyAFQQFqIgUgCygCACIESQ0AQQAhASAEIQMMAgsACyAMIAI2AgAgBSALKAIAIgNJBEAgBygCACEBA0AgASAFQQR0aiwAAEEIRwRAIAEgBUEEdGpBADoADQsgBUEBaiIFIANJDQBBASEGDAMLAAVBASEBCwsgAwRAIAEhBgwBBSABRQ0DCwwBC0EAIQVBACEBQQEhBANAIARFBEAgBygCACIDIAEgBWtBBHRqIgQgAyABQQR0aiIDKQIANwIAIAQgAykCCDcCCCALKAIAIQMLIAUgBygCACABQQR0aiwAAEEIRmoiBUUhBCABQQFqIgEgA0kNAAsgBEUEQCAAQTxqIgQoAgAhASALIAMgBWsiAzYCACABIANJBEAgAEFAaygCACIFQQBHIAMgBUtxBEAgEiAFNgIAQaz1AkHYGyASEGBBrPUCEFYgBCgCACEBIAsoAgAhAwsgBygCACADIAFBIGogAUECdmoiAUsEfyADBSABIgMLQQR0EFciAUUEQEGs9QIQVgsgByABNgIAIAQgAzYCACAGDQIMAwsLIAZFDQELIAooAgAhAgwBCyAAIAIgCigCABCzASAMIAooAgAiAjYCAAsgDSgCACEDIABBoJYBaiIFIABBzM0DaigCACIAQYCAgAJJBH8gAAVBgICAAgsgAmogA3EiATYCACAMKAIAIQAgASACRwRAIAAgAkYEQCAJJAQPCyADIAAgAmtxIAMgASACa3FPBEAgCSQEDwsLIAUgADYCACAJJAQLQQECfyAAQRBqIgQoAgAiAyAAKAIETwRAQQAPCyAEIANBAWogACgCACADQQJ0aiIAEFlqNgIAIAEgACACEG8aQQELvQwBEH8CQCMEIQYjBEGwA2okBCAGQZQDaiEJAkAgAEEEaiIFKAIAIgQgAEHoAGoiCCgCACIBQWdqSgRAIAEgBGsiAkEASA0CIABBBGohAyAEQYCAAUoEQCACQQBKBEAgACgCECIBIAEgBGogAhBdGgsgA0EANgIAIAggAjYCAAUgASECCyAAKAIAIAAoAhAgAmpBgIACIAJrEF4hAiAIKAIAIgQgAmohASACQQBKBEAgCCABNgIAIAAgAUFiajYCbAwCCyAAIARBYmo2AmwgAkF/Rg0CCwsgBUEAIABBCGoiCygCAGtBB3EQVSAAQcjMA2ohAiAFEFgiAUGAgAJxBEAgAkEBNgIAIABBwLECaiAAIABBsMkDahCMBCEAIAYkBCAADwsgAkEANgIAIABBuLECakEANgIAIABBvLECakEANgIAIAFBgIABcUUEQCAAQbTJA2pBAEGUAxBUGgsgBUECEFVBACECA0AgBRBYQQx2IQEgBUEEEFUCQAJAIAFB/wFxQQ9GBEAgBRBYQQx2Qf8BcSEEIAVBBBBVIAQEQCAEQQJqIQEgCSACakEAQQBBfiAEayIEIAJBbGoiA0sEfyAEBSADC2sQVBoDQCABQX9qIQQgAkEBaiIDQRRJIAFBAUpxBEAgBCEBIAMhAgwBCwsFQQ8hAQwCCwUgAUH/AXEhAQwBCwwBCyAJIAJqIAE6AAALIAJBAWoiAkEUSQ0AC0EAIAkgAEG0+ABqIg1BFBBoIABBBGohDiAAQRBqIQkgAEHsAGohDCAAQbj5AGohDyAGQX9qIRBBACECQQAhBAJAAkADQAJAAkACQAJAA0AgBSgCACIHIAgoAgAiA0F7akoEQCADIAdrIgFBAEgNCCAHQYCAAUoEQCABQQBKBEAgCSgCACIDIAMgB2ogARBdGgsgDkEANgIAIAggATYCAAUgAyEBCyAAKAIAIAkoAgAgAWpBgIACIAFrEF4hASAIKAIAIgcgAWohAyABQQBKBEAgCCADNgIAIAwgA0FiajYCAAUgDCAHQWJqNgIAIAFBf0YNCQsLIAkoAgAiASAFKAIAIgNBAWpqLQAAQQh0IAEgA2otAABBEHRyIAEgA0ECamotAAByQQggCygCACIKa3ZB/v8DcSIHIABBuPgAaiAPKAIAIgFBAnRqKAIASQR/IAUgCiAAQbz5AGogB0EQIAFrdiIBai0AAGoiB0EDdiADajYCACALIAdBB3E2AgAgAEG8gQFqIAFBAXRqBQNAAkAgAUEBaiIBQQ9PBEBBDyEBDAELIAcgAEG4+ABqIAFBAnRqKAIATw0BCwsgBSABIApqIgpBA3YgA2o2AgAgCyAKQQdxNgIAIABBvJEBaiAHIAAgAUECdGpBtPgAaigCAGtBECABa3YgAEH4+ABqIAFBAnRqKAIAaiIBIA0oAgBPBH9BAAUgAQtBAXRqCyIBLgEAIgFB//8DcUEQSA0BIAFB//8DcUESTg0DIAUQWCEDIAFBEEYEfyAFQQMQVSADQQ12QQNqBSAFQQcQVSADQQl2QQtqCyEBIARFDQAMAgsACyAGIAJqIABBtMkDaiACai0AACABQf//A3FqQQ9xOgAAIAJBAWohAgwCCyACQZQDTg0DIBAgAmosAAAhBwNAIAFBf2ohAyAGIAJqIAc6AAAgAkEBaiEEIAJBkwNIIAFBAUpxBEAgBCECIAMhAQwBBSAEIQILCwwBCyAFEFghBCABQRJGBH8gBUEDEFUgBEENdkEDagUgBUEHEFUgBEEJdkELagshASACQZQDTg0CIAYgAmpBAEEAIAJB7HxqIgRBfiABayABQX9zIgNBfkoEfyADBUF+C2siA0sEfyAEBSADC2sQVBoDQCABQX9qIQMgAkEBaiEEIAJBkwNIIAFBAUpxBEAgAyEBIAQhAgwBBSAEIQILCwsgAkEASiEEIAJBlANIDQALCyAAQczMA2pBAToAACAFKAIAIAgoAgBKDQFBACAGIABBhAFqQasCEGhBACAGQasCaiAAQfAeakE8EGhBACAGQecCaiAAQdw8akEREGhBACAGQfgCaiAAQcjaAGpBHBBoIABBtMkDaiAGQZQDEFMaIAYkBEEBDwtBACEAIAYkBEEADwsgBiQEQQALpAsBB38gAEEEaiIDEFghBgJ/IABB0K4BaiIHKAIAIgFB/+sBSwR/QYD+AyAGQfD/A3EiBEsEfyADQQgQVUEIIQFBAAVBCCEBA0AgAUEBaiEBIAJBAWoiBUECdEGwGGooAgAgBE0EQCAFIQIMAQsLIAMgARBVIAJBAnRBsBhqKAIACyECIAQgAmtBECABa3YhAiABQQJ0QcgYagUgAUH/uwFLBEBBgBAgBkHw/wNxIgRLBH8gA0EGEFVBBiEBQQAFQQYhAQNAIAFBAWohASACQQFqIgVBAnRB/BhqKAIAIARNBEAgBSECDAELCyADIAEQVSACQQJ0QfwYaigCAAshAiAEIAJrQRAgAWt2IQIgAUECdEGYGWoMAgsgAUH/6wBLBEBBgCAgBkHw/wNxIgRLBH8gA0EFEFVBBSEBQQAFQQUhAQNAIAFBAWohASACQQFqIgVBAnRBsBZqKAIAIARNBEAgBSECDAELCyADIAEQVSACQQJ0QbAWaigCAAshAiAEIAJrQRAgAWt2IQIgAUECdEHQFmoMAgsgBkHw/wNxIQQgAUH/G0sEfyAEQYDAACAESwR/IANBBRBVQQUhAUEABUEFIQEDQCABQQFqIQEgAkEBaiIFQQJ0QYQXaigCACAETQRAIAUhAgwBCwsgAyABEFUgAkECdEGEF2ooAgALIgJrQRAgAWt2IQIgAUECdEGkF2oFIARBgIACIARLBH8gA0EEEFVBBCEBQQAFQQQhAQNAIAFBAWohASACQQFqIgVBAnRB2BdqKAIAIARNBEAgBSECDAELCyADIAEQVSACQQJ0QdgXaigCAAsiAmtBECABa3YhAiABQQJ0QfwXagsLCyIBKAIAIAJqQf8BcSEBIABB7K4BaiIFKAIABEAgBkH/H0sgAUVxBH9BgAIiAQUgAQtBf2ohAiABBEAgAiEBBSADEFghBCADQQEQVSAEQYCAAnEEQCAFQQA2AgAgAEHorgFqQQA2AgAPCyADQQEQVUGAICADEFhB8P8DcSIGSwR/IANBBRBVQQUhAUEABUEFIQFBACECA0AgAUEBaiEBIAJBAWoiBUECdEGwFmooAgAgBk0EQCAFIQIMAQsLIAMgARBVIAJBAnRBsBZqKAIACyECIAYgAmtBECABa3YgAUECdEHQFmooAgBqQQV0IAMQWEELdnIhBiADQQUQVSAAQbCYAWoiASABKQMAIARBDnZBAXFBA2oiAa19NwMAIABBpJYBaiEDIABB4ABqIgUoAgAhAiAAQdDNA2oiBCgCACEAA0AgAygCACIHIAJqIAcgAiAGayAAcWosAAA6AAAgBSAFKAIAQQFqIAQoAgAiAHEiAjYCACABQX9qIgENAAsPCwUgAEHorgFqIgMoAgAhAiADIAJBAWo2AgAgAkEPSgRAIABB9K4BaigCAEUEQCAFQQE2AgALCwsgByAHKAIAIAFqIgIgAkEIdms2AgAgAEH4rgFqIgIoAgBBEGohBSACIAU2AgAgBUH/AUsEQCACQZABNgIAIABB/K4BaiICIAIoAgBBAXY2AgALIABBypgBaiABQQF0aiIFLwEAQQh2IQIgAEGklgFqKAIAIQMgAEHgAGoiBCgCACEBIAQgAUEBajYCACADIAFqIAI6AAAgAEGwmAFqIgEgASkDAEJ/fDcDACAAQcqoAWogBS4BACIDQf//A3EiAkH/AXFqIgQsAAAhASAEIAFBAWo6AAAgA0EBakEQdEEQdUH+AXFBoQFKBEAgAEHKmAFqIQMgAEHKqAFqIQQDQEEAIAMgBBCfASAAQcqoAWogBS4BACIGQf//A3EiAkH/AXFqIgcsAAAhASAHIAFBAWo6AAAgBkEBakEQdEEQdUH+AXFBoQFKDQALCyAFIABBypgBaiABQf8BcUEBdGoiAC4BADsBACAAIAJBAWo7AQAL7wIBCH9BgCAgAEEEaiIEEFhB8P8DcSIDSwR/IARBBRBVQQUhAUEABUEFIQEDQCABQQFqIQEgAkEBaiIFQQJ0QbAWaigCACADTQRAIAUhAgwBCwsgBCABEFUgAkECdEGwFmooAgALIQIgAyACa0EQIAFrdiABQQJ0QdAWaigCAGoiAUH/AUsEQA8LIABBzK4BaiIEIABByqQBaiABQQF0aiIFLgEAIgNB//8DcSICQQh2NgIAIABByqwBaiACQf8BcWoiBiwAACEBIAYgAUEBajoAACADQQFqQRB0QRB1Qf8BcUUEQCAAQcqkAWohAyAAQcqsAWohBgNAQQAgAyAGEJ8BIAQgBS4BACIHQf//A3EiAkEIdjYCACAAQcqsAWogAkH/AXFqIggsAAAhASAIIAFBAWo6AAAgB0EBakEQdEEQdUH/AXFFDQALCyAFIABByqQBaiABQf8BcUEBdGoiAC4BADsBACAAIAJBAWo7AQAL6QgCEH8BfiMEIQYjBEEQaiQEIAAvAQAhAiABQdQMaiINKAIAIgMgAEEIaiIKKAIARwRAIAMpAgAhEgNAIAMgA0F4aiIDKQIANwIAIAMgEjcCACADIAooAgBHDQALCyACQf//A3EiDEF/aiEOIANBAWoiAiACLQAAQQRqOgAAIABBBGoiBy4BACECIAcgAkH//wNxQQRqOwEAIAFB4AxqKAIAQQBHIg8gA0EBaiIFLQAAIghqQQF2IQQgBSAEOgAAIAcgBEH/AXE7AQAgAyAMQQN0aiEQIA4hCSACQQRqQRB0QRB1Qf//A3EgCGshBSADIQIDQCACQQhqIQQgBSACQQlqIggtAAAiC2shBSAIIAsgD2pBAXYiCzoAACAHIAsgBy8BAGo7AQAgCCwAACILQf8BcSACLQABSgRAIAQsAAAhESAGIARBAmoiAigBADYBACAGIAIuAQQ7AQQgBCECA0ACQCACIAJBeGoiCCkCADcCACAIIAooAgBGDQAgC0H/AXEgAkFxai0AAEoEQCAIIQIMAgsLCyAIIBE6AAAgAkF5aiALOgAAIAhBAmoiAiAGKAEANgEAIAIgBi4BBDsBBAsgCUF/aiIJBEAgBCECDAELCyAQQXlqLAAABEAgAC4BACEABUEAIQIgAyAOQQN0aiEDA0AgAkEBaiECIANBeGohBCADQXlqLAAARQRAIAQhAwwBCwsgAiAFaiEDIAAgAC8BACACayIEQf//A3EiAjsBACAEQf//A3FBAUYEQCAKKAIAIgQsAAAhBSAELAABIQIgBiAEQQJqIgkoAQA2AQAgBiAJLgEEOwEEA0AgAkH/AXEiAiACQQF2a0H/AXEhAiADQQF1IgNBAUoNAAsgBCABQciWAWogASAMQQFqQQF2akG5lQFqLQAAQQJ0aiIBKAIANgIAIAEgBDYCACANIAc2AgAgByAFOgAAIAcgAjoAASAAQQZqIgAgBigBADYBACAAIAYuAQQ7AQQgBiQEDwUgAyEFIAIhAAsLIAcgBSAFQQF2ayAHLwEAajsBACAMQQFqQQF2IgIgAEH//wNxQQFqQQF2IgNGBEAgCigCACEABSAKKAIAIQAgASACakG5lQFqLAAAIgJB/wFxIQQgASADakG5lQFqLAAAIglB/wFxIQUgAiAJRwRAIAFByJYBaiAFQQJ0aiIJKAIAIgIEQCAJIAIoAgA2AgAgAiAAIANBBHQQUxogACEDIAIhAAUgAUGUlQFqIARqLQAAIAFBlJUBaiAFai0AACIDayECIAAgA0EEdGohAyACIAFBlJUBaiABIAJqQbmVAWotAAAiBGotAABHBEAgAyABQciWAWogBEF/aiIEQQJ0aiIFKAIANgIAIAUgAzYCACADIAFBlJUBaiAEai0AACIEQQR0aiEDIAIgBGshAgsgASACakG5lQFqLQAAIQQLIAMgAUHIlgFqIARBAnRqIgEoAgA2AgAgASADNgIACyAKIAA2AgALIA0gADYCACAGJAQLuxIBCX8gAEHwDGpBAEGAAhBUGiAAQZCVAWoiBhCOBCAAQewMaiIIIABB5AxqIgUoAgAiA0F/cyIBQXNKBH8gAQVBcws2AgAgAEHElgFqIgcoAgAiASAAQcCWAWoiAigCAEYEQCAAQciWAWoiBCgCACIBBEAgBCABKAIANgIABSAGQQAQoAEhASAFKAIAIQMLBSAHIAFBcGoiATYCAAsgAEHQDGogATYCACAAQcgMaiIFIAE2AgAgAUEANgIMIABB4AxqIAM2AgAgAUGAAjsBACABQYECOwEEIABByJYBaiAAQbmWAWotAAAiA0ECdGoiBCgCACIBBEAgBCABKAIANgIABSACIAIoAgAiASAAQZSVAWogA2oiCS0AAEEEdGoiBDYCACAEIAcoAgBLBEAgAiAEIAktAABBBHRrNgIAIAYgAxCgASEBCwsgBSgCACABNgIIIABB1AxqIAE2AgAgAEHoDGogCCgCADYCACAAQfEUakEAOgAAIAUoAgBBCGohA0EAIQEDQCADKAIAIAFBA3RqIAE6AAAgAygCACABQQN0akEBOgABIAMoAgAgAUEDdGpBADYCBCABQQFqIgFBgAJHDQBBACEBCwNAIABB9BRqIAFBB3RqQYCAAUHd+QAgAUECaiIDbmtB//8DcSICOwEAIAAgAUEHdGpBhBVqIAI7AQAgACABQQd0akGUFWogAjsBACAAIAFBB3RqQaQVaiACOwEAIAAgAUEHdGpBtBVqIAI7AQAgACABQQd0akHEFWogAjsBACAAIAFBB3RqQdQVaiACOwEAIAAgAUEHdGpB5BVqIAI7AQAgACABQQd0akH2FGpBgIABQb8+IANua0H//wNxIgI7AQAgACABQQd0akGGFWogAjsBACAAIAFBB3RqQZYVaiACOwEAIAAgAUEHdGpBphVqIAI7AQAgACABQQd0akG2FWogAjsBACAAIAFBB3RqQcYVaiACOwEAIAAgAUEHdGpB1hVqIAI7AQAgACABQQd0akHmFWogAjsBACAAIAFBB3RqQfgUakGAgAFBv7MBIANua0H//wNxIgI7AQAgACABQQd0akGIFWogAjsBACAAIAFBB3RqQZgVaiACOwEAIAAgAUEHdGpBqBVqIAI7AQAgACABQQd0akG4FWogAjsBACAAIAFBB3RqQcgVaiACOwEAIAAgAUEHdGpB2BVqIAI7AQAgACABQQd0akHoFWogAjsBACAAIAFBB3RqQfoUakGAgAFB85EBIANua0H//wNxIgI7AQAgACABQQd0akGKFWogAjsBACAAIAFBB3RqQZoVaiACOwEAIAAgAUEHdGpBqhVqIAI7AQAgACABQQd0akG6FWogAjsBACAAIAFBB3RqQcoVaiACOwEAIAAgAUEHdGpB2hVqIAI7AQAgACABQQd0akHqFWogAjsBACAAIAFBB3RqQfwUakGAgAFBockBIANua0H//wNxIgI7AQAgACABQQd0akGMFWogAjsBACAAIAFBB3RqQZwVaiACOwEAIAAgAUEHdGpBrBVqIAI7AQAgACABQQd0akG8FWogAjsBACAAIAFBB3RqQcwVaiACOwEAIAAgAUEHdGpB3BVqIAI7AQAgACABQQd0akHsFWogAjsBACAAIAFBB3RqQf4UakGAgAFBvLUBIANua0H//wNxIgI7AQAgACABQQd0akGOFWogAjsBACAAIAFBB3RqQZ4VaiACOwEAIAAgAUEHdGpBrhVqIAI7AQAgACABQQd0akG+FWogAjsBACAAIAFBB3RqQc4VaiACOwEAIAAgAUEHdGpB3hVqIAI7AQAgACABQQd0akHuFWogAjsBACAAIAFBB3RqQYAVakGAgAFBsswBIANua0H//wNxIgI7AQAgACABQQd0akGQFWogAjsBACAAIAFBB3RqQaAVaiACOwEAIAAgAUEHdGpBsBVqIAI7AQAgACABQQd0akHAFWogAjsBACAAIAFBB3RqQdAVaiACOwEAIAAgAUEHdGpB4BVqIAI7AQAgACABQQd0akHwFWogAjsBACAAIAFBB3RqQYIVakGAgAFB0cABIANua0H//wNxIgM7AQAgACABQQd0akGSFWogAzsBACAAIAFBB3RqQaIVaiADOwEAIAAgAUEHdGpBshVqIAM7AQAgACABQQd0akHCFWogAzsBACAAIAFBB3RqQdIVaiADOwEAIAAgAUEHdGpB4hVqIAM7AQAgACABQQd0akHyFWogAzsBACABQQFqIgFBgAFHDQBB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QEEAEBgQWgUgBhAeCwsgByAZNwMAIAMgGjcDACACIAo2AgAgACgCACgCECECQQAkBSACIAAgF6cgF0IgiKdBABBQIwUhAkEAJAUgAkEBcQRAQQAQGBBaBSABIQ8LCyAPLAAABEAgAEGhvANqLAAARQRAIAUkBEEBDwsLIABB5LwDaiAAQRhqEGoaIAUkBEEBDwsgBSQEQQALBgBBFxAACwYAQRYQAAsGAEEREAALCABBBxAAQQALLQEBfyAAQTsQrQEiAgRAIAJBBGoQyQIhACABBEAgAkEANgIACwVBACEACyAAC9YBAQJ/IwQhAyMEQYAQaiQEAkAgAARAAkACQAJAAkAgACgCAA4wAAICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIBAgsMBAsgAUEANgIADAELIANBgBAQtgNFBEAgA0EAOgAACyADIAEgAhB7GiABEFkiBARAIARBAWogAkkgASAEQX9qQQJ0aigCAEEvR3EEQCABQfwMEIYCGgsLCyABIAAgAhB4GiADJAQPCwsgAkUEQCADJAQPCyABQQA2AgAgAyQEC78BAQJ/AkAgAkF/aiIEBEBBACECA0ACQAJAAkAgACACQQJ0aigCACIDDl0AAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgECCwwEC0EvIQMLIAEgAkECdGogAzYCACACQQFqIgIgBEkNAAsFQQAhAgsLIAEgAkECdGpBADYCAAtWAQN/IAAoAgQiBUEIdSEEIAVBAXEEQCACKAIAIARqKAIAIQQLIAAoAgAiACgCACgCHCEGIAAgASACIARqIAVBAnEEfyADBUECCyAGQQdxQZgCahEKAAsHACAAIAFGCwsAIAAQ/AEgABBSCxIAIABB2CU2AgAgAEEEahCNAwuDAQEBfyMEIQEjBEEQaiQEQQAkBSAAEAsjBSEAQQAkBSAAQQFxRQRAQQAkBUEZQbvyACABEA1BACQFC0EAEBgiABAVGkEAJAVBGUHj8gAgAUEIahANQQAkBUEAEBghAUEAJAVBBBALIwUhAEEAJAUgAEEBcQRAQQAQGCIAEFoFIAEQWgsLOAEC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IAQQyAEgBSgCACEACwJAIABBqIACahBZIgYEQCACIAYgAhBZIgFJBH8gBgUgAQtBAnRqIQIDQAJAAkACQAJAAkAgAigCAA4wAAICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIBAgsMAwsMAQsMBAsgAkEEaiECDAELCyADQQA2AgAPCwsCQAJAIABByMsEaigCACIBQdgARiAAQeCEA2ooAgBBBEZxBEBBACEBBSABQcUARgRAQQAhAQwCBUEAIQELCyAFKAIAQeCEA2ooAgBBAUYNACADIAIgBBB4GgwBCyADIAIQmwEgBBB4GgsgAygCABCTASEADwv4AQEDfyMEIQMjBEHwFmokBCADQSRqIQQgAyAAKAIAIgU2AgACQAJAAkACQCAFQQFrDgMAAQIDCyADIAAoAgQ2AgQMAgsgAyAAKAIEQX9zNgIEDAELIAQgACgCCBCmBCAEIANBBGoQqQQLIAIEQCADIAIQvwILIAMoAgAiAkUEQCADJARBAQ8LIAEoAgAiAEUEQCADJARBAQ8LIAJBAUYgAEEBRnFFBEAgAkECRiAAQQJGcUUEQCACQQNGIABBA0ZxRQRAIAMkBEEADwsgA0EEaiABQQRqQSAQa0UhACADJAQgAA8LCyADKAIEIAEoAgRGIQAgAyQEIAALcgEBfyAAKAIAIgNBAUYEQCAAQQRqIgMgAygCAEH//wNxIAEgAhDQBEH//wNxNgIAIAAoAgAhAwsgA0ECRgRAIABBBGoiAyADKAIAIAEgAhCZATYCACAAKAIAIQMLIANBA0cEQA8LIAAoAgggASACEKsEC74FAQJ/IABBCGoiBCgCACICRQRAQQBBzBYQXyICIgNrQT9xIANqIQMgAiADNgLwASACIANBgAFqNgL0ASACIANBoAFqNgL4ASACIANBqAFqNgL8ASACQQAgAkGIAmoiA2tBP3EgA2oiAzYC+AMgAiADQYABajYC/AMgAiADQaABajYCgAQgAiADQagBajYChAQgAkEAIAJBkARqIgNrQT9xIANqIgM2AoAGIAIgA0GAAWo2AoQGIAIgA0GgAWo2AogGIAIgA0GoAWo2AowGIAJBiAhqQQAgAkGYBmoiA2tBP3EgA2oiAzYCACACQYwIaiADQYABajYCACACQZAIaiADQaABajYCACAC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AUGg0ABqIAIEfyADBSAECzYAACABQZjQAGogAEHstwdqIgIoAgA2AABBACQFQQUgAEG4twdqEAUhAyMFIQRBACQFIARBAXFFBEAgAUGc0ABqIAM2AAAgAUGk0ABqIABBovcGai0AAEEwajYAACABQajQAGogAEGk9wZqKAIANgAAIAFBtNAAakEANgAAIAFBuNAAakEANgAAIAFBvNAAaiAAQey4B2ooAgBBCnY2AAACQAJAAkACQCAAQei3B2ooAgBBAWsOAwAAAQILIAFBwNAAakEBNgAADAILIAFBwNAAakECNgAAIAFBxNAAaiIDIAIpAAA3AAAgAyACKQAINwAIIAMgAikAEDcAECADIAIpABg3ABgMAQsgAUHA0ABqQQA2AAALIAFB5NAAaiAAQfi4B2ooAgAiAjYAACACBEAgAUHo0ABqKAAAIgIEQCABQezQAGooAAAiA0F/akGfjQZJBEBBACQFQRAgAiAAQfy4B2ogAxAHGiMFIQJBACQFIAJBAXENCQsLCyABQfDQAGogAEH8+AdqLQAANgAAQQAPCwsLCwsLC0GACBAYIQEjB0GACBBERwRAIAEQHgsgARAVIQECQCAAQajLBGooAgAiAEUEQAJAAkACQAJAAkACQAJAAkACQCABKAIADgwHCAABCAIDCAUECAYIC0ESIQAMCQtBDCEADAgLQRMhAAwHC0EPIQAMBgtBECEADAULQQshAAwEC0EYIQAMAwtBACEADAILQRUhAAsLEBYgAAvEAwEEfyMEIQIjBEFAayQEIAJBIGohAyAAKAIAIgRBAkYEQCADIABBBGoiBSgCACIEOgAAIAMgBEEIdjoAASADIARBEHY6AAIgAyAEQRh2OgADIAFBICADQQQgAhCnASAFQQA2AgAgBSACLQAfQRh0IAItAB5BEHQgAi0AHUEIdCACLQAbQRh0IAItABpBEHQgAi0AGUEIdCACLQAXQRh0IAItABZBEHQgAi0AFUEIdCACLQATQRh0IAItABJBEHQgAi0AEUEIdCACLQAPQRh0IAItAA5BEHQgAi0ADUEIdCACLQALQRh0IAItAApBEHQgAi0ACUEIdCACLQAHQRh0IAItAAZBEHQgAi0ABUEIdCACLQADQRh0IAItAAJBEHQgAi0AAUEIdCACLQAAcnJyIAItAARzc3NzIAItAAhzc3NzIAIt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IBwgAa18NwMAAkACQAJAAkACQAJAAkACQAJAAkAgFCgCACIBQQFrDnkAAQEIAggICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAMFBwYECAtBACQFQRsgAEG4pgFqIgEQDCMFIQJBACQFIAJBAXENDSABIAcpAgA3AgAgASAHKQIINwIIIAEgBygCEDYCEEEAJAVBCiAEEAUhASMFIQJBACQFIAJBAXENDSAAQcymAWoiAyABOwEAQQAkBUEMIAQQBSECIwUhAUEAJAUgAUEBcQ0NIABB0KYBaiACNgIAIABBnbwDaiAAQcCmAWooAgAiAUEBcToAACAAQZy8A2ogAUEDdkEBcToAACAAQZ+8A2ogAUECdkEBcToAACAAQaO8A2ogAUEGdkEBcToAACAIIAFBB3ZBAXE6AAAgAEGgvANqIAIEf0EBBSADLgEAQQBHC0EBcToAACAAQdSmAWogAUEBdkEBcToAACAAQaG8A2ogAUEIdkEBcToAACAAQaK8A2ogAUEEdkEBcToAAAwICyAAQbCnAWohAyAAQfCtAmohAkEAJAVBCCABQQJGIg8EfyADBSACIgMLQQAQDSMFIQFBACQFIAFBAXFFBEAgAyAHKQIANwIAIAMgBykCCDcCCCADIAcoAhA2AhAgA0GIwQBqIANBCGoiCSgCACIBQQFxOgAAIANBicEAaiABQQF2QQFxOgAAIANBi8EAaiIGIAFBAnZBAXE6AAAgA0GQwQBqIAFBCnZBAXE6AAAgA0HgwQBqIA8Ef0EAIQUgAUEEdkEBcQUgAUEQcUEARyEFQQALOgAAIANB6sEAaiAFQQFxOgAAIANB4cEAaiIMIAFB4AFxQeABRiICOgAAIANB5MEAaiACBH9BAAVBgIAEIAFBBXZBB3F0CzYCACADQeLBAGoiGSABQQN2QQFxOgAAIANB48EAaiABQQt2QQFxOgAAQQAkBUEMIAQQBSEBIwUhAkEAJAUgAkEBcUUEQCADQRRqIhogATYCAEEAJAVBDCAEEAUhAiMFIQFBACQFAkAgAUEBcUUEQEEAJAVBCyAEEAUhASMFIQVBACQFIAVBAXFF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AGoiBxAMIwUhAkEAJAUCQCACQQFxBEAQFyECBSAAQdDnAWoiAkIANwIAIAJCADcCCCACQgA3AhAgAkIANwIYIAJCADcCICAAQZDuAmoiAkIANwIAIAJCADcCCCACQgA3AhAgAkIANwIYIAJCADcCICAAQazzAGoiCEEANgIAIABBqPMAaiABRSICOgAAAkAgAgRAQQAkBUEEQcDLBBAFIQMjBSEBQQAkBSABQQFxBEAQFyECBUEAJAVBGiADEAwjBSEBQQAkBSABQQFxRQRAIAMhAQwDCxAXIQIgAxBSIABBkO4CaigCACIDBEAgAxBSCwsgAEHQ5wFqKAIAIgMEQCADEFILIAcQtQIMAwsLIAggATYCACAAIAFBnYUDaiwAADoAFSAAQZi8A2pBAjYCACAAQai8A2pBADYCACAGQgA3AwAgAEGtvANqQQA6AAAgAEGsvANqQQA6AAAgAEHI8wBqQQA2AgAgAEGIvANqIgFCADcDACABQgA3AwggAEGcvANqIgFCADcCACABQQA6AAggAEGw8wBqQn83AwAgAEG48wBqQX82AgAgAEGwrQJqIgFCADcDACABQgA3AwggAUIANwMQIAFCADcDGCAAQcC8A2pBADYCACAAQeS8A2pBADYCACAAQb68A2pBADoAACAAQdDzAGpBADoAACAAQbimAWoiAUIANwMAIAFCADcDCCABQgA3AxAgAUIANwMYIAFCADcDICABQgA3AyggAUIANwMwIAFCADcDOCABQUBrQgA3AwAgAUIANwNIIAFCADcDUCABQgA3A1ggAUIANwNgIAFCADcDaCABQQA2AnAgAEHIvANqIgBCADcDACAAQgA3AwggAEIANwMQIABBADoAGA8LCyAFEIQBCyAEEI4BIAAQcCACEB4LjwgBC38jBCECIwRBMGokBCACQRBqIQogAkEIaiEHIAIiCUEYaiIFQgA3AgAgBUIANwIIQQAkBUEUIAAgBUEAEAchAiMFIQNBACQFAkAgA0EBcUUEQCACBH8gBUEEaiIGKAIAIgtBAWohAiAGIAI2AgAgAiAFQQhqIggoAgAiBEsEfyAFKAIMIgNBAEcgAiADS3EEf0EAJAUgCSADNgIAQQJBrPUCQdgbIAkQDiMFIQNBACQFIANBAXENBEEAJAVBFEGs9QIQDCMFIQNBACQFIANBAXENBCAIKAIA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IABBwJgBaiIaQgA3AwAgAEHoAGoiA0IANwMAIANCADcDCCADQgA3AxAgA0EANgIYIABB8ABqIgZBfzYCACABRQRAIABBwK4CakEANgIAIABBxK4CakEANgIAIABBuK4CakEANgIAIABBvK4CakEBNgIAIABByK4CakEAQfACEFQaIABBhK8BakEAQbT/ABBUGiAAQczMA2pBADoAACAAQbTJA2pBAEGUAxBUGiAAQbDJA2pBAjYCACAAQcjMA2pBADYCAAsgACABEIMBIAMoAgAiAiAFKAIAIghrIgFBAEgNASAGIABB+ABqIhIoAgAgCGsgBigCAGo2AgAgCEGAgAFKBEAgAUEASgRAIAAoAhAiAiACIAhqIAEQXRoLIAVBADYCACADIAE2AgAFIAIhAQsgAUGAgAJGBEBBACEBQYCAAiECBSAAKAIAIAAoAhAgAWpBgIACIAFrEF4hASADKAIAIgggAWohAiABQQBKBEAgAyACNgIABSAIIQILCyAAQewAaiIOIAJBYmoiAjYCACASIAUoAgAiCDYCACAIQX9qIAYoAgAiDGohCCAMQX9HBEAgDiACIAhIBH8gAgUgCAs2AgALIAFBf0YNASAAIABBBGoiDCAAQfAAaiITEKQCRQ0BIAAgDCATIABBhAFqIhsQowJFDQECQCADIQggBSEXIAYhGAsLIAQhDyAAQdDNA2ohECAAQeAAaiEJIABBBGohCiAAQaCWAWohICAAQRBqIRQgAEGIAmohISAAQaiYAWohFSAAQaSWAWohIiAAQaiWAWohDSAAQfQfaiEjIABBzABqIRwgAEHQAGohJCAAQcgAaiEdIABBxABqIRYgAEHYAGohGSAAQeA9aiElIABB3DxqISYgAEHwHmohJyAAQczbAGohKCAAQcjaAGohKSAAQYQBaiEqIABBsJgBaiErIABB8ABqISwgAEH0AGohLSAAQYABaiEuAkACQAJAA0ACQCAJIAkoAgAgECgCACIEcSICNgIAIAooAgAiASAOKAIATgRAA0ACQCABICwoAgAiAyASKAIAIgVqIgJIBEAgASACQX9qRw0BIAcoAgAgLSgCAEgNAQsgLiwAAA0DIAAgDCATEKQCRQ0GIAAgDCATIBsQowJFDQYgCigCACEBDAELCyAIKAIAIgQgAWsiAkEASA0BIBggBSABayADajYCACAB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NwIIIAJCADcCECACQgA3AhggAkEANgIgIABBoJYBaiAAQczNA2ooAgAiAkGAgIACSQR/IAIFQYCAgAILIABB0M0DaigCAHE2AgALIABBADYCOCAAQQhqIghBADYCACAAQQRqIgdBADYCACAAQcCYAWoiGkIANwMAIABB6ABqIgJCADcDACACQgA3AwggAkIANwMQIAJBADYCGCAAQX82AnAgAUUEQCAAQcCuAmpBADYCACAAQcSuAmpBADYCACAAQbiuAmpBADYCACAAQbyuAmpBATYCACAAQciuAmpBAEHwAhBUGiAAQYSvAWpBAEG0/wAQVBogAEHMzANqQQA6AAAgAEG0yQNqQQBBlAMQVBogAEGwyQNqQQI2AgAgAEHIzANqQQA2AgALIAAgARCDASACKAIAIgogBygCACIJayIDQQBIBEAPCyAJQYCAAUoEQCADQQBKBEAgACgCECIKIAogCWogAxBdGgsgB0EANgIAIAIgAzYCAAUgCiEDCyAAKAIAIABBEGoiDigCACADakGAgAIgA2sQXiEDIAIoAgAiCSADaiEKIANBAEoEQCACIAo2AgAgACAKQWJqNgJsBSAAIAlBYmo2AmwgA0F/RgRADwsLIAEEQCAAQczMA2osAAAEQCACIQkgACEKDAMLCyAAENsBBEAgAiEJIAAhCgUPCwsLIABB0M0DaiERIABB4ABqIQsgAEHsAGohFyAAQeQAaiEfIABByMwDaiESIABBwLECaiEMIABBsMkDaiEgIABBpJYBaiETIABBiAJqISEgAEH0H2ohIiAAQcwAaiEUIABB0ABqIRsgAEHIAGohFSAAQcQAaiEPIABB2ABqIRYgAEG8sQJqIRggAEG4sQJqIRkgAEHgPWohIyAAQdw8aiEkIABB8B5qISUgAEHM2wBqISYgAEHI2gBqIScgAEHMzQNqISggAEHMzANqIRwgAEGEAWohKSAAQbCYAWohKkEAIQECQAJAAkACQAJAAkACQAJAA0ACQCALIAsoAgAgESgCAHE2AgAgBygCACIEIBcoAgBKBEAgCSgCACIDIARrIgJBAEgNASAEQYCAAUoEQCACQQBKBEAgDigCACIDIAMgBGogAhBdGgsgB0EANgIAIAkgAjYCAAUgAyECCyAKKAIAIA4oAgAgAmpBgIACIAJrEF4hAiAJKAIAIgQgAmohAyAC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wQBqEJsECwwBCyABQcytAmosAABFDQEgASAAQRBqQQAgDRC1AQRAIAEgAUGIvANqKQMAQQAgASgCACgCEEEDcUG4AmoRAgAgBiQEQQEPBUGs9QJBARBkDAILAAsgASABQZC8A2opAwBBACABKAIAKAIQQQNxQbgCahECACAGJARBAQ8LIAYkBEEAC5oBAQJ/IABCADcDACAAQRBqIgMQtwIgACABNgIIIABBADYC3AEgAEHgwQBqQQA2AgAgAEEANgLMAUEAJAVBBEHYzQMQBSEBIwUhAkEAJAUgAkEBcQRAEBchAiADEIQBIAIQHgtBACQFQQcgASADEA0jBSECQQAkBSACQQFxRQRAIAAgATYCyAEPCxAXIQAgARBSIAMQhAEgABAeC4IDAgd/AX4gAEGQMmohBkGAgAQgAEGUMmoiAygCACICa0GAAkkEQCAAKAIQIgUgBSACaiAGKAIAIAJrIgIQUxogA0EANgIAIAYgAjYCACAAEOIBGiADKAIAIQILIAJBB2ogBigCAEsEQEEADwsgASAAQRBqIgcoAgAgAmpBBxDpASADIAMoAgBBB2o2AgAgARCmASEIIAFBBBC6AiICQX1qIAEQYSIJp2ohBCAJQgBRIAJFIARBAEhycgRAIABB6DFqQQA6AABBAA8LIAYoAgAgAygCACICayEFAkAgBEEASgRAIAEgBygCACACaiAFIARJBH8gBQUgBAsiAhDpASADIAMoAgAgAmo2AgAgBCACayICQQBKBEADQAJAIANBADYCACAGQQA2AgAgABDiAUUEQEEAIQAMAQsgASAHKAIAIAMoAgBqIAUgAkkEfyAFBSACCyIEEOkBIAMgAygCACAEajYCACACIARrIgJBAEoNAQwECwtBAA8LCwsgCCABELgCRgtOAQF/AkACQAJAIAJBmLwDaigCAEECaw4CAAECCyMEIQQjBEGAEGokBCACQcynAWooAgAaIAQkBEEADwsgACADIAJBsKcBahCdBA8LQQALRwAgAEHJiQNqLAAABEAPCyAAQZCFA2osAABFBEAPCyABQZi8A2ooAgBBAkcEQA8LIAFBkK4CakHMERBzBEAPCyABIAIQoQQLOAAgAEHJiQNqLAAABEAPCyABQeitAmouAQBBgQJHBEAPCyAAQZCFA2osAABFBEAPCyABIAIQogQLrQEBAn8jBCED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IABBpA5qIAJBgAFqNgIAIABBqA5qIAJBoAFqNgIAIABBrA5qIAJBqAFqNgIAIABBqBBqQQAgAEG4DmoiAmtBP3EgAmoiAjYCACAAQawQaiACQYABajYCACAAQbAQaiACQaABajYCACAAQbQQaiACQagBajYCAAUgAiABKALwAUGwARBTGiAAIAEoAoACNgKAAiAAIAEsAIQCOgCEAiAAQQAgAEGIAmoiAmtBP3EgAmoiAjYC+AMgACACQYABajYC/AMgACACQaABajYCgAQgACACQagBajYChAQgAiABKAL4A0GwARBTGiAAIAEoAogENgKIBCAAIAEsAIwEOgCMBCAAQQAgAEGQBGoiAmtBP3EgAmoiAjYCgAYgACACQYABajYChAYgACACQaABajYCiAYgACACQagBajYCjAYgAiABKAKABkGwARBTGiAAIAEoApAGNgKQBiAAIAEsAJQGOgCUBiAAQYgIakEAIABBmAZqIgJrQT9xIAJqIgI2AgAgAEGMCGogAkGAAWo2AgAgAEGQCGogAkGgAWo2AgAgAEGUCGogAkGoAWo2AgAgAiABQYgIaigCAEGwARBTGiAAQZgIaiABQZgIaigCADYCACAAQZwIaiABQZwIaiwAADoAACAAQZAKakEAIABBoAhqIgJrQT9xIAJqIgI2AgAgAEGUCmogAkGAAWo2AgAgAEGYCmogAkGgAWo2AgAgAEGcCmogAkGoAWo2AgAgAiABQZAKaigCAEGwARBTGiAAQaAKaiABQaAKaigCADYCACAAQaQKaiABQaQKaiwAADoAACAAQZgMakEAIABBqApqIgJrQT9xIAJqIgI2AgAgAEGcDGogAkGAAWo2AgAgAEGgDGogAkGgAWo2AgAgAEGkDGogAkGoAWo2AgAgAiABQZgMaigCAEGwARBTGiAAQagMaiABQagMaigCADYCACAAQawMaiABQawMaiwAADoAACAAQaAOakEAIABBsAxqIgJrQT9xIAJqIgI2AgAgAEGkDmogAkGAAWo2AgAgAEGoDmogAkGgAWo2AgAgAEGsDmogAkGoAWo2AgAgAiABQaAOaigCAEGwARBTGiAAQbAOaiABQbAOaigCADYCACAAQbQOaiABQbQOaiwAADoAACAAQagQakEAIABBuA5qIgJrQT9xIAJqIgI2AgAgAEGsEGogAkGAAWo2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ABggACACKQAgNwAgIAAgAikAKDcAKCAAIAIpADA3ADAgACACKQA4NwA4IAQgBCgCAEFAaiIANgIAIAMgBmohAyAFIAZrIgUNAAsMAQsgAiADIAUQUxogBCAEKAIAIAVqIgA2AgALQSAhBSAKQYABaiEDAkACQANAIAcoAgAgAGohAiAFQYABIABrIgZNDQEgAiADIAYQUxogBCAEKAIAIAZqNgIAIAkoAgAiACgCACECIAAgAkFAazYCACAAQQRqIgAgACgCACACQb9/S2o2AgAgCCAHKAIAEG0gBygCACIAQUBrIQIgACACKQAANwAAIAAgAikACDcACCAAIAIpABA3ABAgACACKQAYNwAYIAAgAikAIDcAICAAIAIpACg3ACggACACKQAwNwAwIAAgAikAODcAOCAEIAQoAgBBQGoiADYCACADIAZqIQMgBSAGayIFDQALDAELIAIgAyAFEFMaIAQgBCgCACAFaiIANgIAC0EgIQUgCkGgAWohAwJAAkADQCAHKAIAIABqIQIgBUGAASAAayIGTQ0BIAIgAyAGEFMaIAQgBCgCACAGajYCACAJKAIAIgAoAgAhAiAAIAJBQGs2AgAgAEEEaiIAIAAoAgAgAkG/f0tqNgIAIAggBygCABBtIAcoAgAiAEFAayECIAAgAikAADcAACAAIAIpAAg3AAggACACKQAQNwAQIAAgAikAGDcAGCAAIAIpACA3ACAgACACKQAoNwAoIAAgAikAMDcAMCAAIAIpADg3ADggBCAEKAIAQUBqIgA2AgAgAyAGaiEDIAUgBmsiBQ0ACwwBCyACIAMgBRBTGiAEIAQoAgAgBWoiADYCAAtBICEFIApBwAFqIQMCQAJAA0AgBygCACAAaiECIAVBgAEgAGsiBk0NASACIAMgBhBTGiAEIAQoAgAgBmo2AgAgCSgCACIAKAIAIQIgACACQUBrNgIAIABBBGoiACAAKAIAIAJBv39LajYCACAIIAcoAgAQbSAHKAIAIgBBQGshAiAAIAIpAAA3AAAgACACKQAINwAIIAAgAikAEDcAECAAIAIpABg3ABggACACKQAgNwAgIAAgAikAKDcAKCAAIAIpADA3ADAgACACKQA4NwA4IAQgBCgCAEFAaiIANgIAIAMgBmohAyAFIAZrIgUNAAsMAQsgAiADIAUQUxogBCAEKAIAIAVqIgA2AgALQSAhBSAKQeABaiEKAkACQANAAkAgBygCACAAaiEDIAVBgAEgAGsiAk0NACADIAogAhBTGiAEIAQoAgAgAmo2AgAgCSgCACIAKAIAIQMgACADQUBrNgIAIABBBGoiACAAKAIAIANBv39LajYCACAIIAcoAgAQbSAHKAIAIgBBQGshAyAAIAMpAAA3AAAgACADKQAINwAIIAAgAykAEDcAECAAIAMpABg3ABggACADKQAgNwAgIAAgAykAKDcAKCAAIAMpADA3ADAgACADKQA4NwA4IAQgBCgCAEFAaiIANgIAIAUgAmsiBUUNAiAKIAJqIQoMAQsLDAELIAggARDgASALJAQPCyADIAogBRBTGiAEIAQoAgAgBWo2AgAgCCABEOABIAskBAuwAgIEfwN+IABB6DFqIgYsAABFBEBBAA8LIABBqDJqIQUgAEGcMmohByAAQbAyaiEEA0AgBSkDACAHKAIArXwgBCkDAFgEQCAAEKQEDQELCyAGLAAARQRAIABBuDJqLAAARQRAQQAPCyAAKAIAIAQpAwBBABCcAUEADwsgBCkDACIIIAUpAwAiCVoEQCAIIAKtIgp8IAkgBygCAK18WARAIAEgAEGYMmooAgAgCCAJfadqIAIQUxogAyACNgIAIAQgBCkDACAKfDcDACAAQbgyakEBOgAAQQEPCwsgAEG4MmoiBSwAAARAIAAoAgAgCEEAEJwBIAVBADoAAAsgACgCACABIAIQ1AEiAEEASAR/IAZBADoAAEEABSADIAA2AgAgBCAEKQMAIACsfDcDAEEBCwv2BgEPf0GABCAAQcgWaiIOKAIAIgdrIQYgB0UgBiACS3IEfyABIQkgAgUgAEHIEmogB2ogASAGEFMaA0AgACADQYgCbGohDCAAIANBiAJsakHwAWohCCAAIANBiAJsakH4AWohDUHAACEKIABByBJqIANBBnRqIQsgACADQYgCbGpBgAJqIgcoAgAhBAJAAkADQCAIKAIAIARqIQUgCkGAASAEayIJTQ0BIAUgCyAJEFMaIAcgBygCACAJajYCACANKAIAIgQoAgAhBSAEIAVBQGs2AgAgBEEEaiIEIAQoAgAgBUG/f0tqNgIAIAwgCCgCABBtIAgoAgAiBEFAayEFIAQgBSkAADcAACAEIAUpAAg3AAggBCAFKQAQNwAQIAQgBSkAGDcAGCAEIAUpACA3ACAgBCAFKQAoNwAoIAQgBSkAMDcAMCAEIAUpADg3ADggByAHKAIAQUBqIgQ2AgAgCyAJaiELIAogCWsiCg0ACwwBCyAFIAsgChBTGiAHIAcoAgAgCmo2AgALIANBAWoiA0EIRw0ACyABIAZqIQlBACEHIAIgBmsLIgtB/wNLIQ9BACEEA0AgACAEQYgCbGohECAPBEAgACAEQYgCbGpB8AFqIQ0gACAEQYgCbGpB+AFqIREgCSAEQQZ0aiECIAshCiAAIARBiAJsakGAAmoiCCgCACEDA0BBwAAhBSACIQECQAJAA0AgDSgCACADaiEGIAVBgAEgA2siDE0NASAGIAEgDBBTGiAIIAgoAgAgDGo2AgAgESgCACIDKAIAIQYgAyAGQUBrNgIAIANBBGoiAyADKAIAIAZBv39LajYCACAQIA0oAgAQbSANKAIAIgNBQGshBiADIAYpAAA3AAAgAyAGKQAINwAIIAMgBikAEDcAECADIAYpABg3ABggAyAGKQAgNwAgIAMgBikAKDcAKCADIAYpADA3ADAgAyAGKQA4NwA4IAggCCgCAEFAaiIDNgIAIAEgDGohASAFIAxrIgUNACADIQELDAELIAYgASAFEFMaIAggCCgCACAFaiIBNgIACyACQYAEaiECIApBgHxqIgpB/wNLBEAgASEDDAELCwsgBEEBaiIEQQhJDQALIAtB/wNxIgFFBEAgDiABIAdqNgIADwsgAEHIEmogB2ogCSALIAFraiABEFMaIA4gASAHajYCAAu5CgEDfyAAQcAQakEAQfABEFQaIABBwBJqQQA2AgAgAEHEEmoiA0EAOgAAIABByBJqQQBBhAQQVBogAEG0EmoiAigCACIBQawRKQIANwIAIAFBtBEpAgA3AgggAUG8ESkCADcCECABQcQRKQIANwIYIAIoAgAiASABKAIAQaCAoBBzNgIAIAFBDGoiASABKAIAQYCAhIACczYCACAAQQBB8AEQVBogAEEANgKAAiAAQQA6AIQCIABB9AFqIgIoAgAiAUGsESkCADcCACABQbQRKQIANwIIIAFBvBEpAgA3AhAgAUHEESkCADcCGCACKAIAIgEgASgCAEGggKAQczYCACABQQxqIgEgASgCAEGAgICAAnM2AgAgAEGIAmpBAEHwARBUGiAAQQA2AogEIABBADoAjAQgAEH8A2oiAigCACIBQawRKQIANwIAIAFBtBEpAgA3AgggAUG8ESkCADcCECABQcQRKQIANwIYIAIoAgAiASABKAIAQaCAoBBzNgIAIAFBCGoiAiACKAIAQQFzNgIAIAFBDGoiASABKAIAQYCAgIACczYCACAAQZAEakEAQfABEFQaIABBADYCkAYgAEEAOgCUBiAAQYQGaiICKAIAIgFBrBEpAgA3AgAgAUG0ESkCADcCCCABQbwRKQIANwIQIAFBxBEpAgA3AhggAigCACIBIAEoAgBBoICgEHM2AgAgAUEIaiICIAIoAgBBAnM2AgAgAUEMaiIBIAEoAgBBgICAgAJzNgIAIABBmAZqQQBB8AEQVBogAEGYCGpBADYCACAAQZwIakEAOgAAIABBjAhqIgIoAgAiAUGsESkCADcCACABQbQRKQIANwIIIAFBvBEpAgA3AhAgAUHEESkCADcCGCACKAIAIgEgASgCAEGggKAQczYCACABQQhqIgIgAigCAEEDczYCACABQQxqIgEgASgCAEGAgICAAnM2AgAgAEGgCGpBAEHwARBUGiAAQaAKakEANgIAIABBpApqQQA6AAAgAEGUCmoiAigCACIBQawRKQIANwIAIAFBtBEpAgA3AgggAUG8ESkCADcCECABQcQRKQIANwIYIAIoAgAiASABKAIAQaCAoBBzNgIAIAFBCGoiAiACKAIAQQRzNgIAIAFBDGoiASABKAIAQYCAgIACczYCACAAQagKakEAQfABEFQaIABBqAxqQQA2AgAgAEGsDGpBADoAACAAQZwMaiICKAIAIgFBrBEpAgA3AgAgAUG0ESkCADcCCCABQbwRKQIANwIQIAFBxBEpAgA3AhggAigCACIBIAEoAgBBoICgEHM2AgAgAUEIaiICIAIoAgBBBXM2AgAgAUEMaiIBIAEoAgBBgICAgAJzNgIAIABBsAxqQQBB8AEQVBogAEGwDmpBADYCACAAQbQOakEAOgAAIABBpA5qIgIoAgAiAUGsESkCADcCACABQbQRKQIANwIIIAFBvBEpAgA3AhAgAUHEESkCADcCGCACKAIAIgEgASgCAEGggKAQczYCACABQQhqIgIgAigCAEEGczYCACABQQxqIgEgASgCAEGAgICAAnM2AgAgAEG4DmpBAEHwARBUGiAAQbgQakEANgIA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BgYGaWkAdgBSYXJBcmNoaXZlAHZpAG9wZW4AaWlpaWlpAGdldEZpbGVIZWFkZXIAaWlpAHJlYWRGaWxlAGlpaWkAU3RhdGUAaQBlcnJDb2RlAHZpaWkAZXJyVHlwZQBBcmNIZWFkZXIAc3RhdGUAY29tbWVudABmbGFncwBBcmNGaWxlSGVhZGVyAG5hbWUAcGFja1NpemUAZGlpAHZpaWQAdW5wU2l6ZQBob3N0T1MAY3JjAHRpbWUAdW5wVmVyAG1ldGhvZABmaWxlQXR0cgAxM0FyY0ZpbGVIZWFkZXIATlN0M19fMjEyYmFzaWNfc3RyaW5nSXdOU18xMWNoYXJfdHJhaXRzSXdFRU5TXzlhbGxvY2F0b3JJd0VFRUUATlN0M19fMjIxX19iYXNpY19zdHJpbmdfY29tbW9uSUxiMUVFRQA5QXJjSGVhZGVyAE5TdDNfXzIxMmJhc2ljX3N0cmluZ0ljTlNfMTFjaGFyX3RyYWl0c0ljRUVOU185YWxsb2NhdG9ySWNFRUVFADVTdGF0ZQBFUlJfUFJPQ0VTUwBFUlJfUkVBRABFUlJfT1BFTgBQSzEwUmFyQXJjaGl2ZQBQMTBSYXJBcmNoaXZlADEwUmFyQXJjaGl2ZQBTRVQARU5EAENVUgA0RmlsZQB2b2lkAGJvb2wAY2hhcgBzaWduZWQgY2hhcgB1bnNpZ25lZCBjaGFyAHNob3J0AHVuc2lnbmVkIHNob3J0AGludAB1bnNpZ25lZCBpbnQAbG9uZwB1bnNpZ25lZCBsb25nAGZsb2F0AGRvdWJsZQBzdGQ6OnN0cmluZwBzdGQ6OmJhc2ljX3N0cmluZzx1bnNpZ25lZCBjaGFyPgBzdGQ6OndzdHJpbmcAZW1zY3JpcHRlbjo6dmFsAGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PGNoYXI+AGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PHNpZ25lZCBjaGFyPgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzx1bnNpZ25lZCBjaGFyPgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzxzaG9ydD4AZW1zY3JpcHRlbjo6bWVtb3J5X3ZpZXc8dW5zaWduZWQgc2hvcnQ+AGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PGludD4AZW1zY3JpcHRlbjo6bWVtb3J5X3ZpZXc8dW5zaWduZWQgaW50PgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzxsb25nPgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzx1bnNpZ25lZCBsb25nPgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzxpbnQ4X3Q+AGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PHVpbnQ4X3Q+AGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PGludDE2X3Q+AGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PHVpbnQxNl90PgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzxpbnQzMl90PgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzx1aW50MzJfdD4AZW1zY3JpcHRlbjo6bWVtb3J5X3ZpZXc8ZmxvYXQ+AGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PGRvdWJsZT4AZW1zY3JpcHRlbjo6bWVtb3J5X3ZpZXc8bG9uZyBkb3VibGU+AE4xMGVtc2NyaXB0ZW4xMW1lbW9yeV92aWV3SWVFRQBOMTBlbXNjcmlwdGVuMTFtZW1vcnlfdmlld0lkRUUATjEwZW1zY3JpcHRlbjExbWVtb3J5X3ZpZXdJZkVFAE4xMGVtc2NyaXB0ZW4xMW1lbW9yeV92aWV3SW1FRQBOMTBlbXNjcmlwdGVuMTFtZW1vcnlfdmlld0lsRUUATjEwZW1zY3JpcHRlbjExbWVtb3J5X3ZpZXdJakVFAE4xMGVtc2NyaXB0ZW4xMW1lbW9yeV92aWV3SWlFRQBOMTBlbXNjcmlwdGVuMTFtZW1vcnlfdmlld0l0RUUATjEwZW1zY3JpcHRlbjExbWVtb3J5X3ZpZXdJc0VFAE4xMGVtc2NyaXB0ZW4xMW1lbW9yeV92aWV3SWhFRQBOMTBlbXNjcmlwdGVuMTFtZW1vcnlfdmlld0lhRUUATjEwZW1zY3JpcHRlbjExbWVtb3J5X3ZpZXdJY0VFAE4xMGVtc2NyaXB0ZW4zdmFsRQBOU3QzX18yMTJiYXNpY19zdHJpbmdJaE5TXzExY2hhcl90cmFpdHNJaEVFTlNfOWFsbG9jYXRvckloRUVFRQASERMUFRYXGBkaGxwdHh8gIREiIyQRJSYnKCkqKywRLS4vEBAwEBAQEBAQEDEyMxA0NRAQERERERERERERERERERERERERERERERERETYRERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE3ERERETgROTo7PD0+ERERERERERERERERERERERERERERERERERERERERERERERERERERERERET8QEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBARQEERQkNERUZHSEkQEBBKS0xNThAQEE9QEBAQEFEQEBAQEBAQEBARERFSUxAQEBAQEBAQEBAQEREREVQQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAREVUQEBAQVhAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBBXEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBBYWVpbEBAQEBAQEBAQEBAQEBAQEBAQEBAQEFwQEBAQEBAQEBAQEBAQEBAQEABBusMACyD//////////////////////////////////////////wBB4sMACzb+//8H/v//BwAAAAAABCAE//9/////f//////////////////////////////////D/wMAH1AAQaLEAAukASAAAAAAAN88QNf///v///////////+///////////////////////8D/P////////////////////////8A/v///38C/v////8AAAAAAP+/tgD///8HBwAAAP8H//////////7/w////////////////+8f/uH/nwAA////////AOD///////////////8DAP//////BzAE/////P8fAAD///8BAEHOxQAL5AH9HwAAAAAAAPAD/3//////////7//f4f/P//7+7p/5///9xeOfWYCwz/8DAO6H+f///W3DhxkCXsD/PwDuv/v///3t478bAQDP/wAA7p/5///97eOfGcCwz/8CAOzHPdYYx//Dxx2BAMD/AADu3/3///3v498dYAPP/wAA7N/9///97+PfHWBAz/8GAOzf/f/////n312AAM//APzs/3/8///7L3+AX/8AAAwA/v////9//wc/IP8DAAAAAJYl8P6u7P87XyD/8wAAAAABAAAA/wMAAP/+////H/7/A////v///x8AQbrHAAuVAv///////3/5/wP//+fB//9/QP8z/////78g///////3////////////PX89//////89/////z1/Pf9//////////z3//////////4cAAAAA//8AAP////////////8fAP7//////////////////////////////////////////////////////////5////7//wf////////////HAQD/3w8A//8PAP//DwD/3w0A////////z///AYAQ/wMAAAAA/wP//////////////wD//////wf//////////z8A////H/8P/wHA/////z8fAP//////D////wP/AwAAAAD///8P/////////3/+/x8A/wP/A4AAQdrJAAsw////////7//vD/8DAAAAAP//////8////////7//AwD///////8/AP/j//////8/AEGXygALG95vAP///////////////////////////////wBBusoACyD//z8//////z8//6r///8/////////31/cH88P/x/cHwBB6MoACwYCgAAA/x8AQfrKAAsShPwvPlC9//PgQwAA//////8BAEGwywALUMD///////8DAAD//////3///////3//////////////////////H3gMAP////+/IP////////+AAAD//38Af39/f39/f3//////AAAAAACAAEGazAALV+AAAAD+Az4f/v///////////3/g/v/////////////34P////8//v////////////9/AAD///8HAAAAAAAA////////////////////////////////PwBB+swACzL/////////////////////////////////HwAAAAAAAP//////////////////////HwBBtM0ACzz//////z//H////w8AAP//////f/CP////gP////////////8AAAAAgP/8////////////////eQ8A/wcAQfnNAAtn/7v3////AAAA////////DwD//////////w8A/wMAAPwI//////8H/////wcA////H/////////f/AID/AwAAAAD///////9/AP8//wP//38E/////////38FAAA4//88AH5+fgB/fwBB8s4AC4gB//////8H/wP//////////////////////////w8A//9/+P//////D/////////////////8//////////////////wMAAAAAfwD44P/9f1/b/////////////////wMAAAD4////////////////PwAA///////////8////////AAAAAAD/DwBBiNAAC1Lf/////////////////////x8AAP8D/v//B/7//wfA/////////////3/8/PwcAAAAAP/v//9///+3/z//PwAAAAD///////////////////8HAEHi0AALB////////x8AQYrRAAtG////H////////wEAAAAAAP///38AAP///wcAAAAAAAD///8//////w//PgAAAAAA/////////////////////////z//AwBB2tEACws//f////+/kf//PwBB+tEACwj//z8A////AwBBitIACwj/////////wABBmtIACxBv8O/+//8PAAAAAAD///8fAEG60gALD////////z8A//8/AP//BwBB2tIACwr///////////8BAEH60gALKP//////////PwAAAMD/AAD8////////AQAA////Af8D////////x/8AQarTAAsM//////////8eAP8DAEHK0wALHv///////z8A/wMAAAAAAAD/////////////////fwBB+tMACw3///////////////8HAEGa1AALBv//////fwBButQACwj/////////AQBB2tQACxT//////////x8A//////9/AAD4/wBB+tQACwEDAEGa1QALmAH/////////////3///////////32Te/+vv/////////7/n39////97X/z9//////////////////////////////////////////////////////8//////f//9/////f//9/////f//9/////f/////3////9///3z////////+////+W/vcKhOqWqpb3917/+/8P7vv/DwBButYAC+sPVCEiGQ0BAgMRSxwMEAQLHRIeJ2hub3BxYiAFBg8TFBUaCBYHKCQXGAkKDhsfJSODgn0mKis8PT4/Q0dKTVhZWltcXV5fYGFjZGVmZ2lqa2xyc3R5ent8AElsbGVnYWwgYnl0ZSBzZXF1ZW5jZQBEb21haW4gZXJyb3IAUmVzdWx0IG5vdCByZXByZXNlbnRhYmxlAE5vdCBhIHR0eQBQZXJtaXNzaW9uIGRlbmllZABPcGVyYXRpb24gbm90IHBlcm1pdHRlZABObyBzdWNoIGZpbGUgb3IgZGlyZWN0b3J5AE5vIHN1Y2ggcHJvY2VzcwBGaWxlIGV4aXN0cwBWYWx1ZSB0b28gbGFyZ2UgZm9yIGRhdGEgdHlwZQBObyBzcGFjZSBsZWZ0IG9uIGRldmljZQBPdXQgb2YgbWVtb3J5AFJlc291cmNlIGJ1c3kASW50ZXJydXB0ZWQgc3lzdGVtIGNhbGwAUmVzb3VyY2UgdGVtcG9yYXJpbHkgdW5hdmFpbGFibGUASW52YWxpZCBzZWVrAENyb3NzLWRldmljZSBsaW5rAFJlYWQtb25seSBmaWxlIHN5c3RlbQBEaXJlY3Rvcnkgbm90IGVtcHR5AENvbm5lY3Rpb24gcmVzZXQgYnkgcGVlcgBPcGVyYXRpb24gdGltZWQgb3V0AENvbm5lY3Rpb24gcmVmdXNlZABIb3N0IGlzIGRvd24ASG9zdCBpcyB1bnJlYWNoYWJsZQBBZGRyZXNzIGluIHVzZQBCcm9rZW4gcGlwZQBJL08gZXJyb3IATm8gc3VjaCBkZXZpY2Ugb3IgYWRkcmVzcwBCbG9jayBkZXZpY2UgcmVxdWlyZWQATm8gc3VjaCBkZXZpY2UATm90IGEgZGlyZWN0b3J5AElzIGEgZGlyZWN0b3J5AFRleHQgZmlsZSBidXN5AEV4ZWMgZm9ybWF0IGVycm9yAEludmFsaWQgYXJndW1lbnQAQXJndW1lbnQgbGlzdCB0b28gbG9uZwBTeW1ib2xpYyBsaW5rIGxvb3AARmlsZW5hbWUgdG9vIGxvbmcAVG9vIG1hbnkgb3BlbiBmaWxlcyBpbiBzeXN0ZW0ATm8gZmlsZSBkZXNjcmlwdG9ycyBhdmFpbGFibGUAQmFkIGZpbGUgZGVzY3JpcHRvcgBObyBjaGlsZCBwcm9jZXNzAEJhZCBhZGRyZXNzAEZpbGUgdG9vIGxhcmdlAFRvbyBtYW55IGxpbmtzAE5vIGxvY2tzIGF2YWlsYWJsZQBSZXNvdXJjZSBkZWFkbG9jayB3b3VsZCBvY2N1cgBTdGF0ZSBub3QgcmVjb3ZlcmFibGUAUHJldmlvdXMgb3duZXIgZGllZABPcGVyYXRpb24gY2FuY2VsZWQARnVuY3Rpb24gbm90IGltcGxlbWVudGVkAE5vIG1lc3NhZ2Ugb2YgZGVzaXJlZCB0eXBlAElkZW50aWZpZXIgcmVtb3ZlZABEZXZpY2Ugbm90IGEgc3RyZWFtAE5vIGRhdGEgYXZhaWxhYmxlAERldmljZSB0aW1lb3V0AE91dCBvZiBzdHJlYW1zIHJlc291cmNlcwBMaW5rIGhhcyBiZWVuIHNldmVyZWQAUHJvdG9jb2wgZXJyb3IAQmFkIG1lc3NhZ2UARmlsZSBkZXNjcmlwdG9yIGluIGJhZCBzdGF0ZQBOb3QgYSBzb2NrZXQARGVzdGluYXRpb24gYWRkcmVzcyByZXF1aXJlZABNZXNzYWdlIHRvbyBsYXJnZQBQcm90b2NvbCB3cm9uZyB0eXBlIGZvciBzb2NrZXQAUHJvdG9jb2wgbm90IGF2YWlsYWJsZQBQcm90b2NvbCBub3Qgc3VwcG9ydGVkAFNvY2tldCB0eXBlIG5vdCBzdXBwb3J0ZWQATm90IHN1cHBvcnRlZABQcm90b2NvbCBmYW1pbHkgbm90IHN1cHBvcnRlZABBZGRyZXNzIGZhbWlseSBub3Qgc3VwcG9ydGVkIGJ5IHByb3RvY29sAEFkZHJlc3Mgbm90IGF2YWlsYWJsZQBOZXR3b3JrIGlzIGRvd24ATmV0d29yayB1bnJlYWNoYWJsZQBDb25uZWN0aW9uIHJlc2V0IGJ5IG5ldHdvcmsAQ29ubmVjdGlvbiBhYm9ydGVkAE5vIGJ1ZmZlciBzcGFjZSBhdmFpbGFibGUAU29ja2V0IGlzIGNvbm5lY3RlZABTb2NrZXQgbm90IGNvbm5lY3RlZABDYW5ub3Qgc2VuZCBhZnRlciBzb2NrZXQgc2h1dGRvd24AT3BlcmF0aW9uIGFscmVhZHkgaW4gcHJvZ3Jlc3MAT3BlcmF0aW9uIGluIHByb2dyZXNzAFN0YWxlIGZpbGUgaGFuZGxlAFJlbW90ZSBJL08gZXJyb3IAUXVvdGEgZXhjZWVkZWQATm8gbWVkaXVtIGZvdW5kAFdyb25nIG1lZGl1bSB0eXBlAE5vIGVycm9yIGluZm9ybWF0aW9uAABMQ19BTEwATENfQ1RZUEUAAAAATENfTlVNRVJJQwAATENfVElNRQAAAAAATENfQ09MTEFURQAATENfTU9ORVRBUlkATENfTUVTU0FHRVMATEFORwBDLlVURi04AFBPU0lYAE1VU0xfTE9DUEFUSAARAAoAERERAAAAAAUAAAAAAAAJAAAAAAsAQa3mAAshEQAPChEREQMKBwABEwkLCwAACQYLAAALAAYRAAAAERERAEHe5gALAQsAQefmAAsYEQAKChEREQAKAAACAAkLAAAACQALAAALAEGY5wALAQwAQaTnAAsVDAAAAAAMAAAAAAkMAAAAAAAMAAAMAEHS5wALAQ4AQd7nAAsVDQAAAAQNAAAAAAkOAAAAAAAOAAAOAEGM6AALARAAQZjoAAseDwAAAAAPAAAAAAkQAAAAAAAQAAAQAAASAAAAEhISAEHP6AALDhIAAAASEhIAAAAAAAAJAEGA6QALAQsAQYzpAAsVCgAAAAAKAAAAAAkLAAAAAAALAAALAEG66QALAQwAQcbpAAtdDAAAAAAMAAAAAAkMAAAAAAAMAAAMAAAtKyAgIDBYMHgALTBYKzBYIDBYLTB4KzB4IDB4AGluZgBJTkYAbmFuAE5BTgAwMTIzNDU2Nzg5QUJDREVGLgBDLlVURi04AEGs6gALGkMAEQAKABEREQAAAAAFAAAAAAAACQAAAAALAEHO6gALGhEADwoREREDCgcAARMJCwsAAAkGCwAACwAGAEH/6gALAQsAQYrrAAsWCgoAAAAACgAAAgAJCwAAAAkACwAACwBBuesACwEMAEHF6wALFQwAAAAADAAAAAAJDAAAAAAADAAADABB8+sACwEOAEH/6wALFQ0AAAAEDQAAAAAJDgAAAAAADgAADgBBrewACwEQAEG57AALHg8AAAAADwAAAAAJEAAAAAAAEAAAEAAAEgAAABISEgBB8OwACw4SAAAAEhISAAAAAAAACQBBoe0ACwELAEGt7QALFQoAAAAACgAAAAAJCwAAAAAACwAACwBB2+0ACwEMAEHn7QALvAcMAAAAAAwAAAAACQwAAAAAAAwAAAwAACUqcwAobnVsbCkAIwArAC0AIAAwAEwAAGpMTEwAagAAAAAAamoAAAAAagAAaiUlJXMlcyVzJXMlcyouKiVjJWMAYmFzaWNfc3RyaW5nAGFsbG9jYXRvcjxUPjo6YWxsb2NhdGUoc2l6ZV90IG4pICduJyBleGNlZWRzIG1heGltdW0gc3VwcG9ydGVkIHNpemUAdGVybWluYXRpbmcgd2l0aCAlcyBleGNlcHRpb24gb2YgdHlwZSAlczogJXMAdGVybWluYXRpbmcgd2l0aCAlcyBleGNlcHRpb24gb2YgdHlwZSAlcwB0ZXJtaW5hdGluZyB3aXRoICVzIGZvcmVpZ24gZXhjZXB0aW9uAHRlcm1pbmF0aW5nAHVuY2F1Z2h0AFN0OWV4Y2VwdGlvbgBOMTBfX2N4eGFiaXYxMTZfX3NoaW1fdHlwZV9pbmZvRQBTdDl0eXBlX2luZm8ATjEwX19jeHhhYml2MTIwX19zaV9jbGFzc190eXBlX2luZm9FAE4xMF9fY3h4YWJpdjExN19fY2xhc3NfdHlwZV9pbmZvRQBwdGhyZWFkX29uY2UgZmFpbHVyZSBpbiBfX2N4YV9nZXRfZ2xvYmFsc19mYXN0KCkAY2Fubm90IGNyZWF0ZSBwdGhyZWFkIGtleSBmb3IgX19jeGFfZ2V0X2dsb2JhbHMoKQBjYW5ub3QgemVybyBvdXQgdGhyZWFkIHZhbHVlIGZvciBfX2N4YV9nZXRfZ2xvYmFscygpAHRlcm1pbmF0ZV9oYW5kbGVyIHVuZXhwZWN0ZWRseSByZXR1cm5lZAB0ZXJtaW5hdGVfaGFuZGxlciB1bmV4cGVjdGVkbHkgdGhyZXcgYW4gZXhjZXB0aW9uAHN0ZDo6YmFkX2FsbG9jAFN0OWJhZF9hbGxvYwBTdDExbG9naWNfZXJyb3IAU3QxMmxlbmd0aF9lcnJvcgBOMTBfX2N4eGFiaXYxMTlfX3BvaW50ZXJfdHlwZV9pbmZvRQBOMTBfX2N4eGFiaXYxMTdfX3BiYXNlX3R5cGVfaW5mb0UATjEwX19jeHhhYml2MTIzX19mdW5kYW1lbnRhbF90eXBlX2luZm9FAHYARG4AYgBjAGgAYQBzAHQAaQBqAGwAbQBmAGQATjEwX19jeHhhYml2MTE2X19lbnVtX3R5cGVfaW5mb0UATjEwX19jeHhhYml2MTIxX192bWlfY2xhc3NfdHlwZV9pbmZvRQ==\";\n\nclass ResourceLoaderPlugin {\n    /**\n     * The type of file this plugin handles.\n     * @return The type of file.\n     */\n    getType() {\n        return 'none';\n    }\n    async loadFile(url) {\n        return null;\n    }\n}\n\n// <!-- prettier-ignore-start -->\n/* eslint-disable require-jsdoc */\n\nconst Module = {};\n\nconst WorkerScope = {};\n\n//--------------------unpackBridge.js----------------------------\n!(function (t, e) {\n  // The following code has been _carefully_ modified by hand.\n  // There were various cases for in what context the code might\n  // be run, and I removed all but the webworker case.\n  // There was code to handle loading in a nodeJS context, that tried to import(\"fs\")\n  // WebPack kepts tripping up on that code in its static analysis of the code, so\n  // I carefully removed it.\n  t.unpackBridge = e(t.fs);\n})(WorkerScope, function (t) {\n  return (function (t) {\n    var e = {};\n    function r(n) {\n      if (e[n]) return e[n].exports\n      var i = (e[n] = { i: n, l: !1, exports: {} });\n      return t[n].call(i.exports, i, i.exports, r), (i.l = !0), i.exports\n    }\n    return (\n      (r.m = t),\n      (r.c = e),\n      (r.d = function (t, e, n) {\n        r.o(t, e) || Object.defineProperty(t, e, { enumerable: !0, get: n });\n      }),\n      (r.r = function (t) {\n        'undefined' != typeof Symbol &&\n          Symbol.toStringTag &&\n          Object.defineProperty(t, Symbol.toStringTag, { value: 'Module' }),\n          Object.defineProperty(t, '__esModule', { value: !0 });\n      }),\n      (r.t = function (t, e) {\n        if ((1 & e && (t = r(t)), 8 & e)) return t\n        if (4 & e && 'object' == typeof t && t && t.__esModule) return t\n        var n = Object.create(null);\n        if ((r.r(n), Object.defineProperty(n, 'default', { enumerable: !0, value: t }), 2 & e && 'string' != typeof t))\n          for (var i in t)\n            r.d(\n              n,\n              i,\n              function (e) {\n                return t[e]\n              }.bind(null, i)\n            );\n        return n\n      }),\n      (r.n = function (t) {\n        var e =\n          t && t.__esModule\n            ? function () {\n                return t.default\n              }\n            : function () {\n                return t\n              };\n        return r.d(e, 'a', e), e\n      }),\n      (r.o = function (t, e) {\n        return Object.prototype.hasOwnProperty.call(t, e)\n      }),\n      (r.p = ''),\n      r((r.s = 2))\n    )\n  })([\n    function (t, e, r) {\n      Object.defineProperty(e, '__esModule', { value: !0 });\n      const n = r(1),\n        i = {\n          0: 'ERAR_SUCCESS',\n          10: 'ERAR_END_ARCHIVE',\n          11: 'ERAR_NO_MEMORY',\n          12: 'ERAR_BAD_DATA',\n          13: 'ERAR_BAD_ARCHIVE',\n          14: 'ERAR_UNKNOWN_FORMAT',\n          15: 'ERAR_EOPEN',\n          16: 'ERAR_ECREATE',\n          17: 'ERAR_ECLOSE',\n          18: 'ERAR_EREAD',\n          19: 'ERAR_EWRITE',\n          20: 'ERAR_SMALL_BUF',\n          21: 'ERAR_UNKNOWN',\n          22: 'ERAR_MISSING_PASSWORD',\n          23: 'ERAR_EREFERENCE',\n          24: 'ERAR_BAD_PASSWORD',\n        },\n        o = {\n          0: 'Success',\n          11: 'Not enough memory',\n          12: 'Archive header or data are damaged',\n          13: 'File is not RAR archive',\n          14: 'Unknown archive format',\n          15: 'File open error',\n          16: 'File create error',\n          17: 'File close error',\n          18: 'File read error',\n          19: 'File write error',\n          20: 'Buffer for archive comment is too small, comment truncated',\n          21: 'Unknown error',\n          22: 'Password for encrypted file or header is not specified',\n          23: 'Cannot open file source for reference record',\n          24: 'Wrong password is specified',\n        };\n      class s {\n        constructor(t = '') {\n(this._password = t), (this._archive = null);\n        }\n        getFileList() {\n          let t,\n            [e, r] = this.openArc(!0);\n          if ('SUCCESS' !== e.state) t = [e, null];\n          else {\n            let e,\n              n,\n              i = [];\n            for (; ([e, n] = this.processNextFile(() => !0)), 'SUCCESS' === e.state; ) i.push(n.fileHeader);\n            t = 'ERAR_END_ARCHIVE' !== e.reason ? [e, null] : [{ state: 'SUCCESS' }, { arcHeader: r, fileHeaders: i }];\n          }\n          return this.closeArc(), t\n        }\n        extractAll() {\n          let t,\n            [e, r] = this.openArc(!1);\n          if ('SUCCESS' !== e.state) t = [e, null];\n          else {\n            let e,\n              n,\n              i = [];\n            for (; ([e, n] = this.processNextFile(() => !1)), 'SUCCESS' === e.state; ) i.push(n);\n            t = 'ERAR_END_ARCHIVE' !== e.reason ? [e, null] : [{ state: 'SUCCESS' }, { arcHeader: r, files: i }];\n          }\n          return this.closeArc(), t\n        }\n        extractFiles(t, e) {\n          let r,\n            [n, i] = this.openArc(!1, e),\n            o = {};\n          for (let e = 0; e < t.length; ++e) o[t[e]] = e;\n          if ('SUCCESS' !== n.state) r = [n, null];\n          else {\n            let e,\n              n,\n              s = Array(t.length).fill(null),\n              u = 0;\n            for (;;) {\n              let r = !1,\n                i = null;\n              if (\n                (([e, n] = this.processNextFile((t) => (t in o ? ((i = o[t]), !1) : ((r = !0), !0)))),\n                'SUCCESS' !== e.state)\n              )\n                break\n              if (!r && ((s[i] = n), ++u === t.length)) {\n                e.reason = 'ERAR_END_ARCHIVE';\n                break\n              }\n            }\n            r = 'ERAR_END_ARCHIVE' !== e.reason ? [e, null] : [{ state: 'SUCCESS' }, { arcHeader: i, files: s }];\n          }\n          return this.closeArc(), r\n        }\n        fileCreated(t) {}\n        close(t) {\n          this._lastFileContent = this.closeFile(t);\n        }\n        openArc(t, e) {\n(n.Ext.current = this), (this._archive = new unpack.RarArchive());\n          let r,\n            i = this._archive.open(this._filePath, e || this._password, t);\n          return (\n            (r =\n              0 !== i.state.errCode\n                ? [this.getFailInfo(i.state.errCode, i.state.errType), null]\n                : [\n                    { state: 'SUCCESS' },\n                    {\n                      comment: i.comment,\n                      flags: {\n                        volume: 0 != (1 & i.flags),\n                        lock: 0 != (4 & i.flags),\n                        solid: 0 != (8 & i.flags),\n                        authInfo: 0 != (32 & i.flags),\n                        recoveryRecord: 0 != (64 & i.flags),\n                        headerEncrypted: 0 != (128 & i.flags),\n                      },\n                    },\n                  ]),\n            (n.Ext.current = null),\n            r\n          )\n        }\n        processNextFile(t) {\n          let e;\n          n.Ext.current = this;\n          let r = this._archive.getFileHeader(),\n            i = [{ state: 'SUCCESS' }, null];\n          if (0 === r.state.errCode) {\n            let e = t(r.name);\n            this._lastFileContent = null;\n            let n = this._archive.readFile(e);\n            0 === n.errCode ||\n              e ||\n              ((i[0] = this.getFailInfo(n.errCode, n.errType)),\n              22 === n.errCode ? (n = this._archive.readFile(!0)) : (n.errCode = 0)),\n              0 === n.errCode\n                ? (i[1] = this._lastFileContent)\n                : ((r.state.errCode = n.errCode), (r.state.errType = n.errType)),\n              (this._lastFileContent = null);\n          }\n          return (\n            (e =\n              0 !== r.state.errCode\n                ? [this.getFailInfo(r.state.errCode, r.state.errType), null]\n                : [\n                    { state: 'SUCCESS' },\n                    {\n                      fileHeader: {\n                        name: r.name,\n                        flags: {\n                          encrypted: 0 != (4 & r.flags),\n                          solid: 0 != (16 & r.flags),\n                          directory: 0 != (32 & r.flags),\n                        },\n                        packSize: r.packSize,\n                        unpSize: r.unpSize,\n                        crc: r.crc,\n                        time: (function (t) {\n                          const e = [5, 6, 5, 5, 4, 7];\n                          let r = [];\n                          for (let n of e) r.push(t & ((1 << n) - 1)), (t >>= n);\n                          let n = (t) => (t < 10 ? '0' + t : '' + t);\n                          return (\n                            `${1980 + (r = r.reverse())[0]}-${n(r[1])}-${n(r[2])}` +\n                            `T${n(r[3])}:${n(r[4])}:${n(2 * r[5])}.000`\n                          )\n                        })(r.time),\n                        unpVer: `${Math.floor(r.unpVer / 10)}.${r.unpVer % 10}`,\n                        method: (function (t) {\n                          return (\n                            { 48: 'Storing', 49: 'Fastest', 50: 'Fast', 51: 'Normal', 52: 'Good', 53: 'Best' }[t] ||\n                            'Unknown'\n                          )\n                        })(r.method),\n                      },\n                      extract: i,\n                    },\n                  ]),\n            (n.Ext.current = null),\n            e\n          )\n        }\n        closeArc() {\n(n.Ext.current = this), this._archive.delete(), (n.Ext.current = null), (this._archive = null);\n        }\n        getFailInfo(t, e) {\n          return { state: 'FAIL', reason: i[t], msg: o[t] }\n        }\n      }\n(s._current = null), (e.Extractor = s);\n    },\n    function (t, e, r) {\n      Object.defineProperty(e, '__esModule', { value: !0 }), (e.Ext = { current: null });\n    },\n    function (t, e, r) {\n      Object.defineProperty(e, '__esModule', { value: !0 }),\n        (function (t) {\n          for (var r in t) e.hasOwnProperty(r) || (e[r] = t[r]);\n        })(r(3));\n      var n = r(1);\n      e.Ext = n.Ext;\n    },\n    function (t, e, r) {\n      Object.defineProperty(e, '__esModule', { value: !0 });\n      const n = r(4),\n        i = r(6)\n      ;(e.createExtractorFromData = function (t, e = '') {\n        return new n.DataExtractor(t, e)\n      }),\n        (e.createExtractorFromFile = function (t, e = '', r = '') {\n          return new i.FileExtractor(t, e, r)\n        });\n    },\n    function (t, e, r) {\n      Object.defineProperty(e, '__esModule', { value: !0 });\n      const n = r(5),\n        i = r(0);\n      e.DataExtractor = class extends i.Extractor {\n        constructor(t, e) {\n          super(e), (this.dataFiles = {}), (this.dataFileMap = {}), (this.currentFd = 1);\n          let r = { file: new n.DataFile(new Uint8Array(t)), fd: this.currentFd++ }\n          ;(this._filePath = '_defaultUnrarJS_.rar'),\n            (this.dataFiles[this._filePath] = r),\n            (this.dataFileMap[r.fd] = this._filePath);\n        }\n        open(t) {\n          let e = this.dataFiles[t];\n          return e ? e.fd : 0\n        }\n        create(t) {\n          let e = this.currentFd++;\n          return (this.dataFiles[t] = { file: new n.DataFile(), fd: this.currentFd++ }), (this.dataFileMap[e] = t), e\n        }\n        closeFile(t) {\n          let e = this.dataFiles[this.dataFileMap[t]];\n          if (!e) return null\n          let r = e.file.readAll();\n          return (\n            1 !== t ? (delete this.dataFiles[this.dataFileMap[t]], delete this.dataFileMap[t]) : e.file.seek(0, 'SET'),\n            r\n          )\n        }\n        read(t, e, r) {\n          let n = this.dataFiles[this.dataFileMap[t]];\n          if (!n) return -1\n          let i = n.file.read(r);\n          return null === i ? -1 : (unpack.HEAPU8.set(i, e), i.byteLength)\n        }\n        write(t, e, r) {\n          let n = this.dataFiles[this.dataFileMap[t]];\n          return !!n && (n.file.write(unpack.HEAPU8.slice(e, e + r)), !0)\n        }\n        tell(t) {\n          let e = this.dataFiles[this.dataFileMap[t]];\n          return e ? e.file.tell() : -1\n        }\n        seek(t, e, r) {\n          let n = this.dataFiles[this.dataFileMap[t]];\n          return !!n && n.file.seek(e, r)\n        }\n      };\n    },\n    function (t, e, r) {\n      Object.defineProperty(e, '__esModule', { value: !0 });\n      e.DataFile = class {\n        constructor(t) {\n(this.buffers = []),\n            (this.pos = 0),\n            (this.size = 0),\n            t && (this.buffers.push(t), (this.size = t.byteLength), (this.pos = 0));\n        }\n        read(t) {\n          if ((this.flatten(), t + this.pos > this.size)) return null\n          let e = this.pos;\n          return (this.pos += t), this.buffers[0].slice(e, this.pos)\n        }\n        readAll() {\n          return this.flatten(), this.buffers[0]\n        }\n        write(t) {\n          return this.buffers.push(t), (this.size += t.byteLength), (this.pos += t.byteLength), !0\n        }\n        tell() {\n          return this.pos\n        }\n        seek(t, e) {\n          let r = this.pos;\n          return (\n            'SET' === e ? (r = t) : 'CUR' === e ? (r += t) : (r = this.size - t),\n            !(r < 0 || r > this.size || ((this.pos = r), 0))\n          )\n        }\n        flatten() {\n          if (this.buffers.length <= 1) return\n          let t = new Uint8Array(this.size),\n            e = 0;\n          for (let r of this.buffers) t.set(r, e), (e += r.byteLength);\n          this.buffers = [t];\n        }\n      };\n    },\n    function (t, e, r) {\n(function (t) {\n        Object.defineProperty(e, '__esModule', { value: !0 });\n        const n = r(12),\n          i = r(13),\n          o = r(0);\n        e.FileExtractor = class extends o.Extractor {\n          constructor(t, e, r) {\n            super(r), (this._filePath = t), (this.fileMap = {}), (this._target = e);\n          }\n          open(t) {\n            let e = n.openSync(t, 'r');\n            return (this.fileMap[e] = { size: n.fstatSync(e).size, pos: 0, name: t }), e\n          }\n          create(t) {\n            let e = i.join(this._target, t);\n            i.parse(e)\n              .dir.split('/')\n              .reduce((t, e) => ((t += e + '/'), n.existsSync(t) || n.mkdirSync(t), t), '');\n            let r = n.openSync(e, 'w');\n            return (this.fileMap[r] = { size: 0, pos: 0, name: t }), r\n          }\n          closeFile(t) {\n            return delete this.fileMap[t], n.closeSync(t), null\n          }\n          read(e, r, i) {\n            let o = this.fileMap[e],\n              s = new t(i),\n              u = n.readSync(e, s, 0, i, o.pos);\n            return unpack.HEAPU8.set(s, r), (o.pos += u), u\n          }\n          write(e, r, i) {\n            let o = this.fileMap[e],\n              s = n.writeSync(e, new t(unpack.HEAPU8.subarray(r, r + i)), 0, i);\n            return (o.pos += s), (o.size += s), s === i\n          }\n          tell(t) {\n            return this.fileMap[t].pos\n          }\n          seek(t, e, r) {\n            let n = this.fileMap[t],\n              i = n.pos;\n            return (\n              'SET' === r ? (i = 0) : 'END' === r && (i = n.size), !((i += e) < 0 || i > n.size || ((n.pos = i), 0))\n            )\n          }\n        };\n      }.call(this, r(7).Buffer));\n    },\n    function (t, e, r) {\n(function (t) {\n        /*!\n         * The buffer module from node.js, for the browser.\n         *\n         * @author   Feross Aboukhadijeh <feross@feross.org> <http://feross.org>\n         * @license  MIT\n         */\n        var n = r(9),\n          i = r(10),\n          o = r(11);\n        function s() {\n          return a.TYPED_ARRAY_SUPPORT ? 2147483647 : 1073741823\n        }\n        function u(t, e) {\n          if (s() < e) throw new RangeError('Invalid typed array length')\n          return (\n            a.TYPED_ARRAY_SUPPORT\n              ? ((t = new Uint8Array(e)).__proto__ = a.prototype)\n              : (null === t && (t = new a(e)), (t.length = e)),\n            t\n          )\n        }\n        function a(t, e, r) {\n          if (!(a.TYPED_ARRAY_SUPPORT || this instanceof a)) return new a(t, e, r)\n          if ('number' == typeof t) {\n            if ('string' == typeof e)\n              throw new Error('If encoding is specified then the first argument must be a string')\n            return l(this, t)\n          }\n          return f(this, t, e, r)\n        }\n        function f(t, e, r, n) {\n          if ('number' == typeof e) throw new TypeError('\"value\" argument must not be a number')\n          return 'undefined' != typeof ArrayBuffer && e instanceof ArrayBuffer\n            ? (function (t, e, r, n) {\n                if ((e.byteLength, r < 0 || e.byteLength < r)) throw new RangeError(\"'offset' is out of bounds\")\n                if (e.byteLength < r + (n || 0)) throw new RangeError(\"'length' is out of bounds\")\n                e =\n                  void 0 === r && void 0 === n\n                    ? new Uint8Array(e)\n                    : void 0 === n\n                    ? new Uint8Array(e, r)\n                    : new Uint8Array(e, r, n);\n                a.TYPED_ARRAY_SUPPORT ? ((t = e).__proto__ = a.prototype) : (t = c(t, e));\n                return t\n              })(t, e, r, n)\n            : 'string' == typeof e\n            ? (function (t, e, r) {\n('string' == typeof r && '' !== r) || (r = 'utf8');\n                if (!a.isEncoding(r)) throw new TypeError('\"encoding\" must be a valid string encoding')\n                var n = 0 | g(e, r),\n                  i = (t = u(t, n)).write(e, r);\n                i !== n && (t = t.slice(0, i));\n                return t\n              })(t, e, r)\n            : (function (t, e) {\n                if (a.isBuffer(e)) {\n                  var r = 0 | p(e.length);\n                  return 0 === (t = u(t, r)).length ? t : (e.copy(t, 0, 0, r), t)\n                }\n                if (e) {\n                  if (('undefined' != typeof ArrayBuffer && e.buffer instanceof ArrayBuffer) || 'length' in e)\n                    return 'number' != typeof e.length ||\n                      (function (t) {\n                        return t != t\n                      })(e.length)\n                      ? u(t, 0)\n                      : c(t, e)\n                  if ('Buffer' === e.type && o(e.data)) return c(t, e.data)\n                }\n                throw new TypeError(\n                  'First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.'\n                )\n              })(t, e)\n        }\n        function h(t) {\n          if ('number' != typeof t) throw new TypeError('\"size\" argument must be a number')\n          if (t < 0) throw new RangeError('\"size\" argument must not be negative')\n        }\n        function l(t, e) {\n          if ((h(e), (t = u(t, e < 0 ? 0 : 0 | p(e))), !a.TYPED_ARRAY_SUPPORT)) for (var r = 0; r < e; ++r) t[r] = 0;\n          return t\n        }\n        function c(t, e) {\n          var r = e.length < 0 ? 0 : 0 | p(e.length);\n          t = u(t, r);\n          for (var n = 0; n < r; n += 1) t[n] = 255 & e[n];\n          return t\n        }\n        function p(t) {\n          if (t >= s())\n            throw new RangeError(\n              'Attempt to allocate Buffer larger than maximum size: 0x' + s().toString(16) + ' bytes'\n            )\n          return 0 | t\n        }\n        function g(t, e) {\n          if (a.isBuffer(t)) return t.length\n          if (\n            'undefined' != typeof ArrayBuffer &&\n            'function' == typeof ArrayBuffer.isView &&\n            (ArrayBuffer.isView(t) || t instanceof ArrayBuffer)\n          )\n            return t.byteLength\n          'string' != typeof t && (t = '' + t);\n          var r = t.length;\n          if (0 === r) return 0\n          for (var n = !1; ; )\n            switch (e) {\n              case 'ascii':\n              case 'latin1':\n              case 'binary':\n                return r\n              case 'utf8':\n              case 'utf-8':\n              case void 0:\n                return k(t).length\n              case 'ucs2':\n              case 'ucs-2':\n              case 'utf16le':\n              case 'utf-16le':\n                return 2 * r\n              case 'hex':\n                return r >>> 1\n              case 'base64':\n                return j(t).length\n              default:\n                if (n) return k(t).length\n                ;(e = ('' + e).toLowerCase()), (n = !0);\n            }\n        }\n        function d(t, e, r) {\n          var n = t[e]\n          ;(t[e] = t[r]), (t[r] = n);\n        }\n        function y(t, e, r, n, i) {\n          if (0 === t.length) return -1\n          if (\n            ('string' == typeof r\n              ? ((n = r), (r = 0))\n              : r > 2147483647\n              ? (r = 2147483647)\n              : r < -2147483648 && (r = -2147483648),\n            (r = +r),\n            isNaN(r) && (r = i ? 0 : t.length - 1),\n            r < 0 && (r = t.length + r),\n            r >= t.length)\n          ) {\n            if (i) return -1\n            r = t.length - 1;\n          } else if (r < 0) {\n            if (!i) return -1\n            r = 0;\n          }\n          if (('string' == typeof e && (e = a.from(e, n)), a.isBuffer(e))) return 0 === e.length ? -1 : w(t, e, r, n, i)\n          if ('number' == typeof e)\n            return (\n              (e &= 255),\n              a.TYPED_ARRAY_SUPPORT && 'function' == typeof Uint8Array.prototype.indexOf\n                ? i\n                  ? Uint8Array.prototype.indexOf.call(t, e, r)\n                  : Uint8Array.prototype.lastIndexOf.call(t, e, r)\n                : w(t, [e], r, n, i)\n            )\n          throw new TypeError('val must be string, number or Buffer')\n        }\n        function w(t, e, r, n, i) {\n          var o,\n            s = 1,\n            u = t.length,\n            a = e.length;\n          if (\n            void 0 !== n &&\n            ('ucs2' === (n = String(n).toLowerCase()) || 'ucs-2' === n || 'utf16le' === n || 'utf-16le' === n)\n          ) {\n            if (t.length < 2 || e.length < 2) return -1\n            ;(s = 2), (u /= 2), (a /= 2), (r /= 2);\n          }\n          function f(t, e) {\n            return 1 === s ? t[e] : t.readUInt16BE(e * s)\n          }\n          if (i) {\n            var h = -1;\n            for (o = r; o < u; o++)\n              if (f(t, o) === f(e, -1 === h ? 0 : o - h)) {\n                if ((-1 === h && (h = o), o - h + 1 === a)) return h * s\n              } else -1 !== h && (o -= o - h), (h = -1);\n          } else\n            for (r + a > u && (r = u - a), o = r; o >= 0; o--) {\n              for (var l = !0, c = 0; c < a; c++)\n                if (f(t, o + c) !== f(e, c)) {\n                  l = !1;\n                  break\n                }\n              if (l) return o\n            }\n          return -1\n        }\n        function E(t, e, r, n) {\n          r = Number(r) || 0;\n          var i = t.length - r;\n          n ? (n = Number(n)) > i && (n = i) : (n = i);\n          var o = e.length;\n          if (o % 2 != 0) throw new TypeError('Invalid hex string')\n          n > o / 2 && (n = o / 2);\n          for (var s = 0; s < n; ++s) {\n            var u = parseInt(e.substr(2 * s, 2), 16);\n            if (isNaN(u)) return s\n            t[r + s] = u;\n          }\n          return s\n        }\n        function v(t, e, r, n) {\n          return z(k(e, t.length - r), t, r, n)\n        }\n        function A(t, e, r, n) {\n          return z(\n            (function (t) {\n              for (var e = [], r = 0; r < t.length; ++r) e.push(255 & t.charCodeAt(r));\n              return e\n            })(e),\n            t,\n            r,\n            n\n          )\n        }\n        function _(t, e, r, n) {\n          return A(t, e, r, n)\n        }\n        function b(t, e, r, n) {\n          return z(j(e), t, r, n)\n        }\n        function m(t, e, r, n) {\n          return z(\n            (function (t, e) {\n              for (var r, n, i, o = [], s = 0; s < t.length && !((e -= 2) < 0); ++s)\n                (r = t.charCodeAt(s)), (n = r >> 8), (i = r % 256), o.push(i), o.push(n);\n              return o\n            })(e, t.length - r),\n            t,\n            r,\n            n\n          )\n        }\n        function R(t, e, r) {\n          return 0 === e && r === t.length ? n.fromByteArray(t) : n.fromByteArray(t.slice(e, r))\n        }\n        function S(t, e, r) {\n          r = Math.min(t.length, r);\n          for (var n = [], i = e; i < r; ) {\n            var o,\n              s,\n              u,\n              a,\n              f = t[i],\n              h = null,\n              l = f > 239 ? 4 : f > 223 ? 3 : f > 191 ? 2 : 1;\n            if (i + l <= r)\n              switch (l) {\n                case 1:\n                  f < 128 && (h = f);\n                  break\n                case 2:\n                  128 == (192 & (o = t[i + 1])) && (a = ((31 & f) << 6) | (63 & o)) > 127 && (h = a);\n                  break\n                case 3:\n(o = t[i + 1]),\n                    (s = t[i + 2]),\n                    128 == (192 & o) &&\n                      128 == (192 & s) &&\n                      (a = ((15 & f) << 12) | ((63 & o) << 6) | (63 & s)) > 2047 &&\n                      (a < 55296 || a > 57343) &&\n                      (h = a);\n                  break\n                case 4:\n(o = t[i + 1]),\n                    (s = t[i + 2]),\n                    (u = t[i + 3]),\n                    128 == (192 & o) &&\n                      128 == (192 & s) &&\n                      128 == (192 & u) &&\n                      (a = ((15 & f) << 18) | ((63 & o) << 12) | ((63 & s) << 6) | (63 & u)) > 65535 &&\n                      a < 1114112 &&\n                      (h = a);\n              }\n            null === h\n              ? ((h = 65533), (l = 1))\n              : h > 65535 && ((h -= 65536), n.push(((h >>> 10) & 1023) | 55296), (h = 56320 | (1023 & h))),\n              n.push(h),\n              (i += l);\n          }\n          return (function (t) {\n            var e = t.length;\n            if (e <= T) return String.fromCharCode.apply(String, t)\n            var r = '',\n              n = 0;\n            for (; n < e; ) r += String.fromCharCode.apply(String, t.slice(n, (n += T)));\n            return r\n          })(n)\n        }\n(e.Buffer = a),\n          (e.SlowBuffer = function (t) {\n+t != t && (t = 0);\n            return a.alloc(+t)\n          }),\n          (e.INSPECT_MAX_BYTES = 50),\n          (a.TYPED_ARRAY_SUPPORT =\n            void 0 !== t.TYPED_ARRAY_SUPPORT\n              ? t.TYPED_ARRAY_SUPPORT\n              : (function () {\n                  try {\n                    var t = new Uint8Array(1);\n                    return (\n                      (t.__proto__ = {\n                        __proto__: Uint8Array.prototype,\n                        foo: function () {\n                          return 42\n                        },\n                      }),\n                      42 === t.foo() && 'function' == typeof t.subarray && 0 === t.subarray(1, 1).byteLength\n                    )\n                  } catch (t) {\n                    return !1\n                  }\n                })()),\n          (e.kMaxLength = s()),\n          (a.poolSize = 8192),\n          (a._augment = function (t) {\n            return (t.__proto__ = a.prototype), t\n          }),\n          (a.from = function (t, e, r) {\n            return f(null, t, e, r)\n          }),\n          a.TYPED_ARRAY_SUPPORT &&\n            ((a.prototype.__proto__ = Uint8Array.prototype),\n            (a.__proto__ = Uint8Array),\n            'undefined' != typeof Symbol &&\n              Symbol.species &&\n              a[Symbol.species] === a &&\n              Object.defineProperty(a, Symbol.species, { value: null, configurable: !0 })),\n          (a.alloc = function (t, e, r) {\n            return (function (t, e, r, n) {\n              return (\n                h(e),\n                e <= 0\n                  ? u(t, e)\n                  : void 0 !== r\n                  ? 'string' == typeof n\n                    ? u(t, e).fill(r, n)\n                    : u(t, e).fill(r)\n                  : u(t, e)\n              )\n            })(null, t, e, r)\n          }),\n          (a.allocUnsafe = function (t) {\n            return l(null, t)\n          }),\n          (a.allocUnsafeSlow = function (t) {\n            return l(null, t)\n          }),\n          (a.isBuffer = function (t) {\n            return !(null == t || !t._isBuffer)\n          }),\n          (a.compare = function (t, e) {\n            if (!a.isBuffer(t) || !a.isBuffer(e)) throw new TypeError('Arguments must be Buffers')\n            if (t === e) return 0\n            for (var r = t.length, n = e.length, i = 0, o = Math.min(r, n); i < o; ++i)\n              if (t[i] !== e[i]) {\n(r = t[i]), (n = e[i]);\n                break\n              }\n            return r < n ? -1 : n < r ? 1 : 0\n          }),\n          (a.isEncoding = function (t) {\n            switch (String(t).toLowerCase()) {\n              case 'hex':\n              case 'utf8':\n              case 'utf-8':\n              case 'ascii':\n              case 'latin1':\n              case 'binary':\n              case 'base64':\n              case 'ucs2':\n              case 'ucs-2':\n              case 'utf16le':\n              case 'utf-16le':\n                return !0\n              default:\n                return !1\n            }\n          }),\n          (a.concat = function (t, e) {\n            if (!o(t)) throw new TypeError('\"list\" argument must be an Array of Buffers')\n            if (0 === t.length) return a.alloc(0)\n            var r;\n            if (void 0 === e) for (e = 0, r = 0; r < t.length; ++r) e += t[r].length;\n            var n = a.allocUnsafe(e),\n              i = 0;\n            for (r = 0; r < t.length; ++r) {\n              var s = t[r];\n              if (!a.isBuffer(s)) throw new TypeError('\"list\" argument must be an Array of Buffers')\n              s.copy(n, i), (i += s.length);\n            }\n            return n\n          }),\n          (a.byteLength = g),\n          (a.prototype._isBuffer = !0),\n          (a.prototype.swap16 = function () {\n            var t = this.length;\n            if (t % 2 != 0) throw new RangeError('Buffer size must be a multiple of 16-bits')\n            for (var e = 0; e < t; e += 2) d(this, e, e + 1);\n            return this\n          }),\n          (a.prototype.swap32 = function () {\n            var t = this.length;\n            if (t % 4 != 0) throw new RangeError('Buffer size must be a multiple of 32-bits')\n            for (var e = 0; e < t; e += 4) d(this, e, e + 3), d(this, e + 1, e + 2);\n            return this\n          }),\n          (a.prototype.swap64 = function () {\n            var t = this.length;\n            if (t % 8 != 0) throw new RangeError('Buffer size must be a multiple of 64-bits')\n            for (var e = 0; e < t; e += 8)\n              d(this, e, e + 7), d(this, e + 1, e + 6), d(this, e + 2, e + 5), d(this, e + 3, e + 4);\n            return this\n          }),\n          (a.prototype.toString = function () {\n            var t = 0 | this.length;\n            return 0 === t\n              ? ''\n              : 0 === arguments.length\n              ? S(this, 0, t)\n              : function (t, e, r) {\n                  var n = !1;\n                  if (((void 0 === e || e < 0) && (e = 0), e > this.length)) return ''\n                  if (((void 0 === r || r > this.length) && (r = this.length), r <= 0)) return ''\n                  if ((r >>>= 0) <= (e >>>= 0)) return ''\n                  for (t || (t = 'utf8'); ; )\n                    switch (t) {\n                      case 'hex':\n                        return U(this, e, r)\n                      case 'utf8':\n                      case 'utf-8':\n                        return S(this, e, r)\n                      case 'ascii':\n                        return P(this, e, r)\n                      case 'latin1':\n                      case 'binary':\n                        return C(this, e, r)\n                      case 'base64':\n                        return R(this, e, r)\n                      case 'ucs2':\n                      case 'ucs-2':\n                      case 'utf16le':\n                      case 'utf-16le':\n                        return B(this, e, r)\n                      default:\n                        if (n) throw new TypeError('Unknown encoding: ' + t)\n                        ;(t = (t + '').toLowerCase()), (n = !0);\n                    }\n                }.apply(this, arguments)\n          }),\n          (a.prototype.equals = function (t) {\n            if (!a.isBuffer(t)) throw new TypeError('Argument must be a Buffer')\n            return this === t || 0 === a.compare(this, t)\n          }),\n          (a.prototype.inspect = function () {\n            var t = '',\n              r = e.INSPECT_MAX_BYTES;\n            return (\n              this.length > 0 &&\n                ((t = this.toString('hex', 0, r).match(/.{2}/g).join(' ')), this.length > r && (t += ' ... ')),\n              '<Buffer ' + t + '>'\n            )\n          }),\n          (a.prototype.compare = function (t, e, r, n, i) {\n            if (!a.isBuffer(t)) throw new TypeError('Argument must be a Buffer')\n            if (\n              (void 0 === e && (e = 0),\n              void 0 === r && (r = t ? t.length : 0),\n              void 0 === n && (n = 0),\n              void 0 === i && (i = this.length),\n              e < 0 || r > t.length || n < 0 || i > this.length)\n            )\n              throw new RangeError('out of range index')\n            if (n >= i && e >= r) return 0\n            if (n >= i) return -1\n            if (e >= r) return 1\n            if (((e >>>= 0), (r >>>= 0), (n >>>= 0), (i >>>= 0), this === t)) return 0\n            for (\n              var o = i - n, s = r - e, u = Math.min(o, s), f = this.slice(n, i), h = t.slice(e, r), l = 0;\n              l < u;\n              ++l\n            )\n              if (f[l] !== h[l]) {\n(o = f[l]), (s = h[l]);\n                break\n              }\n            return o < s ? -1 : s < o ? 1 : 0\n          }),\n          (a.prototype.includes = function (t, e, r) {\n            return -1 !== this.indexOf(t, e, r)\n          }),\n          (a.prototype.indexOf = function (t, e, r) {\n            return y(this, t, e, r, !0)\n          }),\n          (a.prototype.lastIndexOf = function (t, e, r) {\n            return y(this, t, e, r, !1)\n          }),\n          (a.prototype.write = function (t, e, r, n) {\n            if (void 0 === e) (n = 'utf8'), (r = this.length), (e = 0);\n            else if (void 0 === r && 'string' == typeof e) (n = e), (r = this.length), (e = 0);\n            else {\n              if (!isFinite(e))\n                throw new Error('Buffer.write(string, encoding, offset[, length]) is no longer supported')\n              ;(e |= 0), isFinite(r) ? ((r |= 0), void 0 === n && (n = 'utf8')) : ((n = r), (r = void 0));\n            }\n            var i = this.length - e;\n            if (((void 0 === r || r > i) && (r = i), (t.length > 0 && (r < 0 || e < 0)) || e > this.length))\n              throw new RangeError('Attempt to write outside buffer bounds')\n            n || (n = 'utf8');\n            for (var o = !1; ; )\n              switch (n) {\n                case 'hex':\n                  return E(this, t, e, r)\n                case 'utf8':\n                case 'utf-8':\n                  return v(this, t, e, r)\n                case 'ascii':\n                  return A(this, t, e, r)\n                case 'latin1':\n                case 'binary':\n                  return _(this, t, e, r)\n                case 'base64':\n                  return b(this, t, e, r)\n                case 'ucs2':\n                case 'ucs-2':\n                case 'utf16le':\n                case 'utf-16le':\n                  return m(this, t, e, r)\n                default:\n                  if (o) throw new TypeError('Unknown encoding: ' + n)\n                  ;(n = ('' + n).toLowerCase()), (o = !0);\n              }\n          }),\n          (a.prototype.toJSON = function () {\n            return { type: 'Buffer', data: Array.prototype.slice.call(this._arr || this, 0) }\n          });\n        var T = 4096;\n        function P(t, e, r) {\n          var n = '';\n          r = Math.min(t.length, r);\n          for (var i = e; i < r; ++i) n += String.fromCharCode(127 & t[i]);\n          return n\n        }\n        function C(t, e, r) {\n          var n = '';\n          r = Math.min(t.length, r);\n          for (var i = e; i < r; ++i) n += String.fromCharCode(t[i]);\n          return n\n        }\n        function U(t, e, r) {\n          var n = t.length\n          ;(!e || e < 0) && (e = 0), (!r || r < 0 || r > n) && (r = n);\n          for (var i = '', o = e; o < r; ++o) i += N(t[o]);\n          return i\n        }\n        function B(t, e, r) {\n          for (var n = t.slice(e, r), i = '', o = 0; o < n.length; o += 2)\n            i += String.fromCharCode(n[o] + 256 * n[o + 1]);\n          return i\n        }\n        function F(t, e, r) {\n          if (t % 1 != 0 || t < 0) throw new RangeError('offset is not uint')\n          if (t + e > r) throw new RangeError('Trying to access beyond buffer length')\n        }\n        function M(t, e, r, n, i, o) {\n          if (!a.isBuffer(t)) throw new TypeError('\"buffer\" argument must be a Buffer instance')\n          if (e > i || e < o) throw new RangeError('\"value\" argument is out of bounds')\n          if (r + n > t.length) throw new RangeError('Index out of range')\n        }\n        function x(t, e, r, n) {\n          e < 0 && (e = 65535 + e + 1);\n          for (var i = 0, o = Math.min(t.length - r, 2); i < o; ++i)\n            t[r + i] = (e & (255 << (8 * (n ? i : 1 - i)))) >>> (8 * (n ? i : 1 - i));\n        }\n        function I(t, e, r, n) {\n          e < 0 && (e = 4294967295 + e + 1);\n          for (var i = 0, o = Math.min(t.length - r, 4); i < o; ++i) t[r + i] = (e >>> (8 * (n ? i : 3 - i))) & 255;\n        }\n        function O(t, e, r, n, i, o) {\n          if (r + n > t.length) throw new RangeError('Index out of range')\n          if (r < 0) throw new RangeError('Index out of range')\n        }\n        function Y(t, e, r, n, o) {\n          return o || O(t, 0, r, 4), i.write(t, e, r, n, 23, 4), r + 4\n        }\n        function L(t, e, r, n, o) {\n          return o || O(t, 0, r, 8), i.write(t, e, r, n, 52, 8), r + 8\n        }\n(a.prototype.slice = function (t, e) {\n          var r,\n            n = this.length;\n          if (\n            ((t = ~~t),\n            (e = void 0 === e ? n : ~~e),\n            t < 0 ? (t += n) < 0 && (t = 0) : t > n && (t = n),\n            e < 0 ? (e += n) < 0 && (e = 0) : e > n && (e = n),\n            e < t && (e = t),\n            a.TYPED_ARRAY_SUPPORT)\n          )\n            (r = this.subarray(t, e)).__proto__ = a.prototype;\n          else {\n            var i = e - t;\n            r = new a(i, void 0);\n            for (var o = 0; o < i; ++o) r[o] = this[o + t];\n          }\n          return r\n        }),\n          (a.prototype.readUIntLE = function (t, e, r) {\n(t |= 0), (e |= 0), r || F(t, e, this.length);\n            for (var n = this[t], i = 1, o = 0; ++o < e && (i *= 256); ) n += this[t + o] * i;\n            return n\n          }),\n          (a.prototype.readUIntBE = function (t, e, r) {\n(t |= 0), (e |= 0), r || F(t, e, this.length);\n            for (var n = this[t + --e], i = 1; e > 0 && (i *= 256); ) n += this[t + --e] * i;\n            return n\n          }),\n          (a.prototype.readUInt8 = function (t, e) {\n            return e || F(t, 1, this.length), this[t]\n          }),\n          (a.prototype.readUInt16LE = function (t, e) {\n            return e || F(t, 2, this.length), this[t] | (this[t + 1] << 8)\n          }),\n          (a.prototype.readUInt16BE = function (t, e) {\n            return e || F(t, 2, this.length), (this[t] << 8) | this[t + 1]\n          }),\n          (a.prototype.readUInt32LE = function (t, e) {\n            return (\n              e || F(t, 4, this.length), (this[t] | (this[t + 1] << 8) | (this[t + 2] << 16)) + 16777216 * this[t + 3]\n            )\n          }),\n          (a.prototype.readUInt32BE = function (t, e) {\n            return (\n              e || F(t, 4, this.length), 16777216 * this[t] + ((this[t + 1] << 16) | (this[t + 2] << 8) | this[t + 3])\n            )\n          }),\n          (a.prototype.readIntLE = function (t, e, r) {\n(t |= 0), (e |= 0), r || F(t, e, this.length);\n            for (var n = this[t], i = 1, o = 0; ++o < e && (i *= 256); ) n += this[t + o] * i;\n            return n >= (i *= 128) && (n -= Math.pow(2, 8 * e)), n\n          }),\n          (a.prototype.readIntBE = function (t, e, r) {\n(t |= 0), (e |= 0), r || F(t, e, this.length);\n            for (var n = e, i = 1, o = this[t + --n]; n > 0 && (i *= 256); ) o += this[t + --n] * i;\n            return o >= (i *= 128) && (o -= Math.pow(2, 8 * e)), o\n          }),\n          (a.prototype.readInt8 = function (t, e) {\n            return e || F(t, 1, this.length), 128 & this[t] ? -1 * (255 - this[t] + 1) : this[t]\n          }),\n          (a.prototype.readInt16LE = function (t, e) {\n            e || F(t, 2, this.length);\n            var r = this[t] | (this[t + 1] << 8);\n            return 32768 & r ? 4294901760 | r : r\n          }),\n          (a.prototype.readInt16BE = function (t, e) {\n            e || F(t, 2, this.length);\n            var r = this[t + 1] | (this[t] << 8);\n            return 32768 & r ? 4294901760 | r : r\n          }),\n          (a.prototype.readInt32LE = function (t, e) {\n            return e || F(t, 4, this.length), this[t] | (this[t + 1] << 8) | (this[t + 2] << 16) | (this[t + 3] << 24)\n          }),\n          (a.prototype.readInt32BE = function (t, e) {\n            return e || F(t, 4, this.length), (this[t] << 24) | (this[t + 1] << 16) | (this[t + 2] << 8) | this[t + 3]\n          }),\n          (a.prototype.readFloatLE = function (t, e) {\n            return e || F(t, 4, this.length), i.read(this, t, !0, 23, 4)\n          }),\n          (a.prototype.readFloatBE = function (t, e) {\n            return e || F(t, 4, this.length), i.read(this, t, !1, 23, 4)\n          }),\n          (a.prototype.readDoubleLE = function (t, e) {\n            return e || F(t, 8, this.length), i.read(this, t, !0, 52, 8)\n          }),\n          (a.prototype.readDoubleBE = function (t, e) {\n            return e || F(t, 8, this.length), i.read(this, t, !1, 52, 8)\n          }),\n          (a.prototype.writeUIntLE = function (t, e, r, n) {\n((t = +t), (e |= 0), (r |= 0), n) || M(this, t, e, r, Math.pow(2, 8 * r) - 1, 0);\n            var i = 1,\n              o = 0;\n            for (this[e] = 255 & t; ++o < r && (i *= 256); ) this[e + o] = (t / i) & 255;\n            return e + r\n          }),\n          (a.prototype.writeUIntBE = function (t, e, r, n) {\n((t = +t), (e |= 0), (r |= 0), n) || M(this, t, e, r, Math.pow(2, 8 * r) - 1, 0);\n            var i = r - 1,\n              o = 1;\n            for (this[e + i] = 255 & t; --i >= 0 && (o *= 256); ) this[e + i] = (t / o) & 255;\n            return e + r\n          }),\n          (a.prototype.writeUInt8 = function (t, e, r) {\n            return (\n              (t = +t),\n              (e |= 0),\n              r || M(this, t, e, 1, 255, 0),\n              a.TYPED_ARRAY_SUPPORT || (t = Math.floor(t)),\n              (this[e] = 255 & t),\n              e + 1\n            )\n          }),\n          (a.prototype.writeUInt16LE = function (t, e, r) {\n            return (\n              (t = +t),\n              (e |= 0),\n              r || M(this, t, e, 2, 65535, 0),\n              a.TYPED_ARRAY_SUPPORT ? ((this[e] = 255 & t), (this[e + 1] = t >>> 8)) : x(this, t, e, !0),\n              e + 2\n            )\n          }),\n          (a.prototype.writeUInt16BE = function (t, e, r) {\n            return (\n              (t = +t),\n              (e |= 0),\n              r || M(this, t, e, 2, 65535, 0),\n              a.TYPED_ARRAY_SUPPORT ? ((this[e] = t >>> 8), (this[e + 1] = 255 & t)) : x(this, t, e, !1),\n              e + 2\n            )\n          }),\n          (a.prototype.writeUInt32LE = function (t, e, r) {\n            return (\n              (t = +t),\n              (e |= 0),\n              r || M(this, t, e, 4, 4294967295, 0),\n              a.TYPED_ARRAY_SUPPORT\n                ? ((this[e + 3] = t >>> 24), (this[e + 2] = t >>> 16), (this[e + 1] = t >>> 8), (this[e] = 255 & t))\n                : I(this, t, e, !0),\n              e + 4\n            )\n          }),\n          (a.prototype.writeUInt32BE = function (t, e, r) {\n            return (\n              (t = +t),\n              (e |= 0),\n              r || M(this, t, e, 4, 4294967295, 0),\n              a.TYPED_ARRAY_SUPPORT\n                ? ((this[e] = t >>> 24), (this[e + 1] = t >>> 16), (this[e + 2] = t >>> 8), (this[e + 3] = 255 & t))\n                : I(this, t, e, !1),\n              e + 4\n            )\n          }),\n          (a.prototype.writeIntLE = function (t, e, r, n) {\n            if (((t = +t), (e |= 0), !n)) {\n              var i = Math.pow(2, 8 * r - 1);\n              M(this, t, e, r, i - 1, -i);\n            }\n            var o = 0,\n              s = 1,\n              u = 0;\n            for (this[e] = 255 & t; ++o < r && (s *= 256); )\n              t < 0 && 0 === u && 0 !== this[e + o - 1] && (u = 1), (this[e + o] = (((t / s) >> 0) - u) & 255);\n            return e + r\n          }),\n          (a.prototype.writeIntBE = function (t, e, r, n) {\n            if (((t = +t), (e |= 0), !n)) {\n              var i = Math.pow(2, 8 * r - 1);\n              M(this, t, e, r, i - 1, -i);\n            }\n            var o = r - 1,\n              s = 1,\n              u = 0;\n            for (this[e + o] = 255 & t; --o >= 0 && (s *= 256); )\n              t < 0 && 0 === u && 0 !== this[e + o + 1] && (u = 1), (this[e + o] = (((t / s) >> 0) - u) & 255);\n            return e + r\n          }),\n          (a.prototype.writeInt8 = function (t, e, r) {\n            return (\n              (t = +t),\n              (e |= 0),\n              r || M(this, t, e, 1, 127, -128),\n              a.TYPED_ARRAY_SUPPORT || (t = Math.floor(t)),\n              t < 0 && (t = 255 + t + 1),\n              (this[e] = 255 & t),\n              e + 1\n            )\n          }),\n          (a.prototype.writeInt16LE = function (t, e, r) {\n            return (\n              (t = +t),\n              (e |= 0),\n              r || M(this, t, e, 2, 32767, -32768),\n              a.TYPED_ARRAY_SUPPORT ? ((this[e] = 255 & t), (this[e + 1] = t >>> 8)) : x(this, t, e, !0),\n              e + 2\n            )\n          }),\n          (a.prototype.writeInt16BE = function (t, e, r) {\n            return (\n              (t = +t),\n              (e |= 0),\n              r || M(this, t, e, 2, 32767, -32768),\n              a.TYPED_ARRAY_SUPPORT ? ((this[e] = t >>> 8), (this[e + 1] = 255 & t)) : x(this, t, e, !1),\n              e + 2\n            )\n          }),\n          (a.prototype.writeInt32LE = function (t, e, r) {\n            return (\n              (t = +t),\n              (e |= 0),\n              r || M(this, t, e, 4, 2147483647, -2147483648),\n              a.TYPED_ARRAY_SUPPORT\n                ? ((this[e] = 255 & t), (this[e + 1] = t >>> 8), (this[e + 2] = t >>> 16), (this[e + 3] = t >>> 24))\n                : I(this, t, e, !0),\n              e + 4\n            )\n          }),\n          (a.prototype.writeInt32BE = function (t, e, r) {\n            return (\n              (t = +t),\n              (e |= 0),\n              r || M(this, t, e, 4, 2147483647, -2147483648),\n              t < 0 && (t = 4294967295 + t + 1),\n              a.TYPED_ARRAY_SUPPORT\n                ? ((this[e] = t >>> 24), (this[e + 1] = t >>> 16), (this[e + 2] = t >>> 8), (this[e + 3] = 255 & t))\n                : I(this, t, e, !1),\n              e + 4\n            )\n          }),\n          (a.prototype.writeFloatLE = function (t, e, r) {\n            return Y(this, t, e, !0, r)\n          }),\n          (a.prototype.writeFloatBE = function (t, e, r) {\n            return Y(this, t, e, !1, r)\n          }),\n          (a.prototype.writeDoubleLE = function (t, e, r) {\n            return L(this, t, e, !0, r)\n          }),\n          (a.prototype.writeDoubleBE = function (t, e, r) {\n            return L(this, t, e, !1, r)\n          }),\n          (a.prototype.copy = function (t, e, r, n) {\n            if (\n              (r || (r = 0),\n              n || 0 === n || (n = this.length),\n              e >= t.length && (e = t.length),\n              e || (e = 0),\n              n > 0 && n < r && (n = r),\n              n === r)\n            )\n              return 0\n            if (0 === t.length || 0 === this.length) return 0\n            if (e < 0) throw new RangeError('targetStart out of bounds')\n            if (r < 0 || r >= this.length) throw new RangeError('sourceStart out of bounds')\n            if (n < 0) throw new RangeError('sourceEnd out of bounds')\n            n > this.length && (n = this.length), t.length - e < n - r && (n = t.length - e + r);\n            var i,\n              o = n - r;\n            if (this === t && r < e && e < n) for (i = o - 1; i >= 0; --i) t[i + e] = this[i + r];\n            else if (o < 1e3 || !a.TYPED_ARRAY_SUPPORT) for (i = 0; i < o; ++i) t[i + e] = this[i + r];\n            else Uint8Array.prototype.set.call(t, this.subarray(r, r + o), e);\n            return o\n          }),\n          (a.prototype.fill = function (t, e, r, n) {\n            if ('string' == typeof t) {\n              if (\n                ('string' == typeof e\n                  ? ((n = e), (e = 0), (r = this.length))\n                  : 'string' == typeof r && ((n = r), (r = this.length)),\n                1 === t.length)\n              ) {\n                var i = t.charCodeAt(0);\n                i < 256 && (t = i);\n              }\n              if (void 0 !== n && 'string' != typeof n) throw new TypeError('encoding must be a string')\n              if ('string' == typeof n && !a.isEncoding(n)) throw new TypeError('Unknown encoding: ' + n)\n            } else 'number' == typeof t && (t &= 255);\n            if (e < 0 || this.length < e || this.length < r) throw new RangeError('Out of range index')\n            if (r <= e) return this\n            var o;\n            if (((e >>>= 0), (r = void 0 === r ? this.length : r >>> 0), t || (t = 0), 'number' == typeof t))\n              for (o = e; o < r; ++o) this[o] = t;\n            else {\n              var s = a.isBuffer(t) ? t : k(new a(t, n).toString()),\n                u = s.length;\n              for (o = 0; o < r - e; ++o) this[o + e] = s[o % u];\n            }\n            return this\n          });\n        var D = /[^+\\/0-9A-Za-z-_]/g;\n        function N(t) {\n          return t < 16 ? '0' + t.toString(16) : t.toString(16)\n        }\n        function k(t, e) {\n          var r;\n          e = e || 1 / 0;\n          for (var n = t.length, i = null, o = [], s = 0; s < n; ++s) {\n            if ((r = t.charCodeAt(s)) > 55295 && r < 57344) {\n              if (!i) {\n                if (r > 56319) {\n(e -= 3) > -1 && o.push(239, 191, 189);\n                  continue\n                }\n                if (s + 1 === n) {\n(e -= 3) > -1 && o.push(239, 191, 189);\n                  continue\n                }\n                i = r;\n                continue\n              }\n              if (r < 56320) {\n(e -= 3) > -1 && o.push(239, 191, 189), (i = r);\n                continue\n              }\n              r = 65536 + (((i - 55296) << 10) | (r - 56320));\n            } else i && (e -= 3) > -1 && o.push(239, 191, 189);\n            if (((i = null), r < 128)) {\n              if ((e -= 1) < 0) break\n              o.push(r);\n            } else if (r < 2048) {\n              if ((e -= 2) < 0) break\n              o.push((r >> 6) | 192, (63 & r) | 128);\n            } else if (r < 65536) {\n              if ((e -= 3) < 0) break\n              o.push((r >> 12) | 224, ((r >> 6) & 63) | 128, (63 & r) | 128);\n            } else {\n              if (!(r < 1114112)) throw new Error('Invalid code point')\n              if ((e -= 4) < 0) break\n              o.push((r >> 18) | 240, ((r >> 12) & 63) | 128, ((r >> 6) & 63) | 128, (63 & r) | 128);\n            }\n          }\n          return o\n        }\n        function j(t) {\n          return n.toByteArray(\n            (function (t) {\n              if (\n                (t = (function (t) {\n                  return t.trim ? t.trim() : t.replace(/^\\s+|\\s+$/g, '')\n                })(t).replace(D, '')).length < 2\n              )\n                return ''\n              for (; t.length % 4 != 0; ) t += '=';\n              return t\n            })(t)\n          )\n        }\n        function z(t, e, r, n) {\n          for (var i = 0; i < n && !(i + r >= e.length || i >= t.length); ++i) e[i + r] = t[i];\n          return i\n        }\n      }.call(this, r(8)));\n    },\n    function (t, e) {\n      var r;\n      r = (function () {\n        return this\n      })();\n      try {\n        r = r || Function('return this')() || (0, eval)('this');\n      } catch (t) {\n        'object' == typeof window && (r = window);\n      }\n      t.exports = r;\n    },\n    function (t, e, r) {\n(e.byteLength = function (t) {\n        var e = f(t),\n          r = e[0],\n          n = e[1];\n        return (3 * (r + n)) / 4 - n\n      }),\n        (e.toByteArray = function (t) {\n          for (\n            var e,\n              r = f(t),\n              n = r[0],\n              s = r[1],\n              u = new o(\n                (function (t, e, r) {\n                  return (3 * (e + r)) / 4 - r\n                })(0, n, s)\n              ),\n              a = 0,\n              h = s > 0 ? n - 4 : n,\n              l = 0;\n            l < h;\n            l += 4\n          )\n            (e =\n              (i[t.charCodeAt(l)] << 18) |\n              (i[t.charCodeAt(l + 1)] << 12) |\n              (i[t.charCodeAt(l + 2)] << 6) |\n              i[t.charCodeAt(l + 3)]),\n              (u[a++] = (e >> 16) & 255),\n              (u[a++] = (e >> 8) & 255),\n              (u[a++] = 255 & e);\n          2 === s && ((e = (i[t.charCodeAt(l)] << 2) | (i[t.charCodeAt(l + 1)] >> 4)), (u[a++] = 255 & e));\n          1 === s &&\n            ((e = (i[t.charCodeAt(l)] << 10) | (i[t.charCodeAt(l + 1)] << 4) | (i[t.charCodeAt(l + 2)] >> 2)),\n            (u[a++] = (e >> 8) & 255),\n            (u[a++] = 255 & e));\n          return u\n        }),\n        (e.fromByteArray = function (t) {\n          for (var e, r = t.length, i = r % 3, o = [], s = 0, u = r - i; s < u; s += 16383)\n            o.push(l(t, s, s + 16383 > u ? u : s + 16383));\n          1 === i\n            ? ((e = t[r - 1]), o.push(n[e >> 2] + n[(e << 4) & 63] + '=='))\n            : 2 === i &&\n              ((e = (t[r - 2] << 8) + t[r - 1]), o.push(n[e >> 10] + n[(e >> 4) & 63] + n[(e << 2) & 63] + '='));\n          return o.join('')\n        });\n      for (\n        var n = [],\n          i = [],\n          o = 'undefined' != typeof Uint8Array ? Uint8Array : Array,\n          s = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',\n          u = 0,\n          a = s.length;\n        u < a;\n        ++u\n      )\n        (n[u] = s[u]), (i[s.charCodeAt(u)] = u);\n      function f(t) {\n        var e = t.length;\n        if (e % 4 > 0) throw new Error('Invalid string. Length must be a multiple of 4')\n        var r = t.indexOf('=');\n        return -1 === r && (r = e), [r, r === e ? 0 : 4 - (r % 4)]\n      }\n      function h(t) {\n        return n[(t >> 18) & 63] + n[(t >> 12) & 63] + n[(t >> 6) & 63] + n[63 & t]\n      }\n      function l(t, e, r) {\n        for (var n, i = [], o = e; o < r; o += 3)\n          (n = ((t[o] << 16) & 16711680) + ((t[o + 1] << 8) & 65280) + (255 & t[o + 2])), i.push(h(n));\n        return i.join('')\n      }\n(i['-'.charCodeAt(0)] = 62), (i['_'.charCodeAt(0)] = 63);\n    },\n    function (t, e) {\n(e.read = function (t, e, r, n, i) {\n        var o,\n          s,\n          u = 8 * i - n - 1,\n          a = (1 << u) - 1,\n          f = a >> 1,\n          h = -7,\n          l = r ? i - 1 : 0,\n          c = r ? -1 : 1,\n          p = t[e + l];\n        for (l += c, o = p & ((1 << -h) - 1), p >>= -h, h += u; h > 0; o = 256 * o + t[e + l], l += c, h -= 8);\n        for (s = o & ((1 << -h) - 1), o >>= -h, h += n; h > 0; s = 256 * s + t[e + l], l += c, h -= 8);\n        if (0 === o) o = 1 - f;\n        else {\n          if (o === a) return s ? NaN : (1 / 0) * (p ? -1 : 1)\n          ;(s += Math.pow(2, n)), (o -= f);\n        }\n        return (p ? -1 : 1) * s * Math.pow(2, o - n)\n      }),\n        (e.write = function (t, e, r, n, i, o) {\n          var s,\n            u,\n            a,\n            f = 8 * o - i - 1,\n            h = (1 << f) - 1,\n            l = h >> 1,\n            c = 23 === i ? Math.pow(2, -24) - Math.pow(2, -77) : 0,\n            p = n ? 0 : o - 1,\n            g = n ? 1 : -1,\n            d = e < 0 || (0 === e && 1 / e < 0) ? 1 : 0;\n          for (\n            e = Math.abs(e),\n              isNaN(e) || e === 1 / 0\n                ? ((u = isNaN(e) ? 1 : 0), (s = h))\n                : ((s = Math.floor(Math.log(e) / Math.LN2)),\n                  e * (a = Math.pow(2, -s)) < 1 && (s--, (a *= 2)),\n                  (e += s + l >= 1 ? c / a : c * Math.pow(2, 1 - l)) * a >= 2 && (s++, (a /= 2)),\n                  s + l >= h\n                    ? ((u = 0), (s = h))\n                    : s + l >= 1\n                    ? ((u = (e * a - 1) * Math.pow(2, i)), (s += l))\n                    : ((u = e * Math.pow(2, l - 1) * Math.pow(2, i)), (s = 0)));\n            i >= 8;\n            t[r + p] = 255 & u, p += g, u /= 256, i -= 8\n          );\n          for (s = (s << i) | u, f += i; f > 0; t[r + p] = 255 & s, p += g, s /= 256, f -= 8);\n          t[r + p - g] |= 128 * d;\n        });\n    },\n    function (t, e) {\n      var r = {}.toString;\n      t.exports =\n        Array.isArray ||\n        function (t) {\n          return '[object Array]' == r.call(t)\n        };\n    },\n    function (e, r) {\n      e.exports = t;\n    },\n    function (t, e, r) {\n(function (t) {\n        function r(t, e) {\n          for (var r = 0, n = t.length - 1; n >= 0; n--) {\n            var i = t[n];\n            '.' === i ? t.splice(n, 1) : '..' === i ? (t.splice(n, 1), r++) : r && (t.splice(n, 1), r--);\n          }\n          if (e) for (; r--; r) t.unshift('..');\n          return t\n        }\n        var n = /^(\\/?|)([\\s\\S]*?)((?:\\.{1,2}|[^\\/]+?|)(\\.[^.\\/]*|))(?:[\\/]*)$/,\n          i = function (t) {\n            return n.exec(t).slice(1)\n          };\n        function o(t, e) {\n          if (t.filter) return t.filter(e)\n          for (var r = [], n = 0; n < t.length; n++) e(t[n], n, t) && r.push(t[n]);\n          return r\n        }\n(e.resolve = function () {\n          for (var e = '', n = !1, i = arguments.length - 1; i >= -1 && !n; i--) {\n            var s = i >= 0 ? arguments[i] : t.cwd();\n            if ('string' != typeof s) throw new TypeError('Arguments to path.resolve must be strings')\n            s && ((e = s + '/' + e), (n = '/' === s.charAt(0)));\n          }\n          return (\n            (e = r(\n              o(e.split('/'), function (t) {\n                return !!t\n              }),\n              !n\n            ).join('/')),\n            (n ? '/' : '') + e || '.'\n          )\n        }),\n          (e.normalize = function (t) {\n            var n = e.isAbsolute(t),\n              i = '/' === s(t, -1);\n            return (\n              (t = r(\n                o(t.split('/'), function (t) {\n                  return !!t\n                }),\n                !n\n              ).join('/')) ||\n                n ||\n                (t = '.'),\n              t && i && (t += '/'),\n              (n ? '/' : '') + t\n            )\n          }),\n          (e.isAbsolute = function (t) {\n            return '/' === t.charAt(0)\n          }),\n          (e.join = function () {\n            var t = Array.prototype.slice.call(arguments, 0);\n            return e.normalize(\n              o(t, function (t, e) {\n                if ('string' != typeof t) throw new TypeError('Arguments to path.join must be strings')\n                return t\n              }).join('/')\n            )\n          }),\n          (e.relative = function (t, r) {\n            function n(t) {\n              for (var e = 0; e < t.length && '' === t[e]; e++);\n              for (var r = t.length - 1; r >= 0 && '' === t[r]; r--);\n              return e > r ? [] : t.slice(e, r - e + 1)\n            }\n(t = e.resolve(t).substr(1)), (r = e.resolve(r).substr(1));\n            for (\n              var i = n(t.split('/')), o = n(r.split('/')), s = Math.min(i.length, o.length), u = s, a = 0;\n              a < s;\n              a++\n            )\n              if (i[a] !== o[a]) {\n                u = a;\n                break\n              }\n            var f = [];\n            for (a = u; a < i.length; a++) f.push('..');\n            return (f = f.concat(o.slice(u))).join('/')\n          }),\n          (e.sep = '/'),\n          (e.delimiter = ':'),\n          (e.dirname = function (t) {\n            var e = i(t),\n              r = e[0],\n              n = e[1];\n            return r || n ? (n && (n = n.substr(0, n.length - 1)), r + n) : '.'\n          }),\n          (e.basename = function (t, e) {\n            var r = i(t)[2];\n            return e && r.substr(-1 * e.length) === e && (r = r.substr(0, r.length - e.length)), r\n          }),\n          (e.extname = function (t) {\n            return i(t)[3]\n          });\n        var s =\n          'b' === 'ab'.substr(-1)\n            ? function (t, e, r) {\n                return t.substr(e, r)\n              }\n            : function (t, e, r) {\n                return e < 0 && (e = t.length + e), t.substr(e, r)\n              };\n      }.call(this, r(14)));\n    },\n    function (t, e) {\n      var r,\n        n,\n        i = (t.exports = {});\n      function o() {\n        throw new Error('setTimeout has not been defined')\n      }\n      function s() {\n        throw new Error('clearTimeout has not been defined')\n      }\n      function u(t) {\n        if (r === setTimeout) return setTimeout(t, 0)\n        if ((r === o || !r) && setTimeout) return (r = setTimeout), setTimeout(t, 0)\n        try {\n          return r(t, 0)\n        } catch (e) {\n          try {\n            return r.call(null, t, 0)\n          } catch (e) {\n            return r.call(this, t, 0)\n          }\n        }\n      }\n      !(function () {\n        try {\n          r = 'function' == typeof setTimeout ? setTimeout : o;\n        } catch (t) {\n          r = o;\n        }\n        try {\n          n = 'function' == typeof clearTimeout ? clearTimeout : s;\n        } catch (t) {\n          n = s;\n        }\n      })();\n      var a,\n        f = [],\n        h = !1,\n        l = -1;\n      function c() {\n        h && a && ((h = !1), a.length ? (f = a.concat(f)) : (l = -1), f.length && p());\n      }\n      function p() {\n        if (!h) {\n          var t = u(c);\n          h = !0;\n          for (var e = f.length; e; ) {\n            for (a = f, f = []; ++l < e; ) a && a[l].run()\n            ;(l = -1), (e = f.length);\n          }\n(a = null),\n            (h = !1),\n            (function (t) {\n              if (n === clearTimeout) return clearTimeout(t)\n              if ((n === s || !n) && clearTimeout) return (n = clearTimeout), clearTimeout(t)\n              try {\n                n(t);\n              } catch (e) {\n                try {\n                  return n.call(null, t)\n                } catch (e) {\n                  return n.call(this, t)\n                }\n              }\n            })(t);\n        }\n      }\n      function g(t, e) {\n(this.fun = t), (this.array = e);\n      }\n      function d() {}\n(i.nextTick = function (t) {\n        var e = new Array(arguments.length - 1);\n        if (arguments.length > 1) for (var r = 1; r < arguments.length; r++) e[r - 1] = arguments[r];\n        f.push(new g(t, e)), 1 !== f.length || h || u(p);\n      }),\n        (g.prototype.run = function () {\n          this.fun.apply(null, this.array);\n        }),\n        (i.title = 'browser'),\n        (i.browser = !0),\n        (i.env = {}),\n        (i.argv = []),\n        (i.version = ''),\n        (i.versions = {}),\n        (i.on = d),\n        (i.addListener = d),\n        (i.once = d),\n        (i.off = d),\n        (i.removeListener = d),\n        (i.removeAllListeners = d),\n        (i.emit = d),\n        (i.prependListener = d),\n        (i.prependOnceListener = d),\n        (i.listeners = function (t) {\n          return []\n        }),\n        (i.binding = function (t) {\n          throw new Error('process.binding is not supported')\n        }),\n        (i.cwd = function () {\n          return '/'\n        }),\n        (i.chdir = function (t) {\n          throw new Error('process.chdir is not supported')\n        }),\n        (i.umask = function () {\n          return 0\n        });\n    },\n  ])\n});\n//-------------------------------------------------------------\n\nconst unpackBridge = WorkerScope.unpackBridge;\n\nlet unpack;\n\n//-------------------------unpack--------------------------\nvar initunpack = function (buffer) {\n  // The following code has been _carefully_ modified by hand.\n  // Due to WebPack embedding this script into the Zea engine\n  // build, certain features broke.\n  // There was code to handle loading in a nodeJS context, that tried to import(\"fs\")\n  // WebPack kepts tripping up on that code in its static analysis of the code, so\n  // I carefully removed it.\n  // The global scope of the script seems to be different, so unpackBridge was not available.\n  // The unpackBridge code assigns unpackBridge to the passed in scope, which is 'this', but that\n  // scope isn't available inside this 'unpack' function.\n  const unpack = Module;\n\n  // Note: the following is the URL of the unpack.wasm file in our ZeaEngine project on our\n  // server. Ideally we could use a relative path from the ZeaEngine file, but\n  // that isn't possible yet. (TODO: Ask Mauro about this)\n  const credentials = 'omit';\n\n  var Ext = unpackBridge.Ext;\n  var jsAPI = {\n    open: function () {\n      return Ext.current.open.apply(Ext.current, arguments)\n    },\n    close: function () {\n      return Ext.current.close.apply(Ext.current, arguments)\n    },\n    read: function () {\n      return Ext.current.read.apply(Ext.current, arguments)\n    },\n    write: function () {\n      return Ext.current.write.apply(Ext.current, arguments)\n    },\n    tell: function () {\n      return Ext.current.tell.apply(Ext.current, arguments)\n    },\n    seek: function () {\n      return Ext.current.seek.apply(Ext.current, arguments)\n    },\n    create: function () {\n      return Ext.current.create.apply(Ext.current, arguments)\n    },\n  };\n  var moduleOverrides = {};\n  var key;\n  for (key in Module) {\n    if (Module.hasOwnProperty(key)) {\n      moduleOverrides[key] = Module[key];\n    }\n  }\n  Module['wasmBinary'] = buffer;\n  Module['arguments'] = [];\n  Module['thisProgram'] = './this.program';\n  Module['quit'] = function (status, toThrow) {\n    throw toThrow\n  };\n  Module['preRun'] = [];\n  Module['postRun'] = [];\n  var ENVIRONMENT_IS_WEB = false;\n  var ENVIRONMENT_IS_WORKER = false;\n  var ENVIRONMENT_IS_NODE = false;\n  if (Module['ENVIRONMENT']) {\n    if (Module['ENVIRONMENT'] === 'WEB') {\n      ENVIRONMENT_IS_WEB = true;\n    } else if (Module['ENVIRONMENT'] === 'WORKER') {\n      ENVIRONMENT_IS_WORKER = true;\n    } else if (Module['ENVIRONMENT'] === 'NODE') {\n      ENVIRONMENT_IS_NODE = true;\n    } else if (Module['ENVIRONMENT'] === 'SHELL') ; else {\n      throw new Error(\"Module['ENVIRONMENT'] value is not valid. must be one of: WEB|WORKER|NODE|SHELL.\")\n    }\n  } else {\n    ENVIRONMENT_IS_WEB = typeof window === 'object';\n    ENVIRONMENT_IS_WORKER = typeof importScripts === 'function';\n    ENVIRONMENT_IS_NODE =\n      typeof process === 'object' && typeof require === 'function' && !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_WORKER;\n  }\n  if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {\n    Module['read'] = function shell_read(url) {\n      var xhr = new XMLHttpRequest();\n      xhr.open('GET', url, false);\n      xhr.send(null);\n      return xhr.responseText\n    };\n    if (ENVIRONMENT_IS_WORKER) {\n      Module['readBinary'] = function readBinary(url) {\n        var xhr = new XMLHttpRequest();\n        xhr.open('GET', url, false);\n        xhr.responseType = 'arraybuffer';\n        xhr.send(null);\n        return new Uint8Array(xhr.response)\n      };\n    }\n    Module['readAsync'] = function readAsync(url, onload, onerror) {\n      var xhr = new XMLHttpRequest();\n      xhr.open('GET', url, true);\n      xhr.responseType = 'arraybuffer';\n      xhr.onload = function xhr_onload() {\n        if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) {\n          onload(xhr.response);\n          return\n        }\n        onerror();\n      };\n      xhr.onerror = onerror;\n      xhr.send(null);\n    };\n    Module['setWindowTitle'] = function (title) {\n      document.title = title;\n    };\n  }\n  Module['print'] =\n    typeof console !== 'undefined' ? console.log.bind(console) : typeof print !== 'undefined' ? print : null;\n  Module['printErr'] =\n    typeof printErr !== 'undefined'\n      ? printErr\n      : (typeof console !== 'undefined' && console.warn.bind(console)) || Module['print'];\n  Module.print = Module['print'];\n  Module.printErr = Module['printErr'];\n  for (key in moduleOverrides) {\n    if (moduleOverrides.hasOwnProperty(key)) {\n      Module[key] = moduleOverrides[key];\n    }\n  }\n  moduleOverrides = undefined;\n  var STACK_ALIGN = 16;\n  function staticAlloc(size) {\n    assert(!staticSealed);\n    var ret = STATICTOP;\n    STATICTOP = (STATICTOP + size + 15) & -16;\n    return ret\n  }\n  function dynamicAlloc(size) {\n    assert(DYNAMICTOP_PTR);\n    var ret = HEAP32[DYNAMICTOP_PTR >> 2];\n    var end = (ret + size + 15) & -16;\n    HEAP32[DYNAMICTOP_PTR >> 2] = end;\n    if (end >= TOTAL_MEMORY) {\n      var success = enlargeMemory();\n      if (!success) {\n        HEAP32[DYNAMICTOP_PTR >> 2] = ret;\n        return 0\n      }\n    }\n    return ret\n  }\n  function alignMemory(size, factor) {\n    if (!factor) factor = STACK_ALIGN;\n    var ret = (size = Math.ceil(size / factor) * factor);\n    return ret\n  }\n  function getNativeTypeSize(type) {\n    switch (type) {\n      case 'i1':\n      case 'i8':\n        return 1\n      case 'i16':\n        return 2\n      case 'i32':\n        return 4\n      case 'i64':\n        return 8\n      case 'float':\n        return 4\n      case 'double':\n        return 8\n      default: {\n        if (type[type.length - 1] === '*') {\n          return 4\n        } else if (type[0] === 'i') {\n          var bits = parseInt(type.substr(1));\n          assert(bits % 8 === 0);\n          return bits / 8\n        } else {\n          return 0\n        }\n      }\n    }\n  }\n  new Array(0);\n  var GLOBAL_BASE = 1024;\n  var ABORT = 0;\n  function assert(condition, text) {\n    if (!condition) {\n      abort('Assertion failed: ' + text);\n    }\n  }\n  function setValue(ptr, value, type, noSafe) {\n    type = type || 'i8';\n    if (type.charAt(type.length - 1) === '*') type = 'i32';\n    switch (type) {\n      case 'i1':\n        HEAP8[ptr >> 0] = value;\n        break\n      case 'i8':\n        HEAP8[ptr >> 0] = value;\n        break\n      case 'i16':\n        HEAP16[ptr >> 1] = value;\n        break\n      case 'i32':\n        HEAP32[ptr >> 2] = value;\n        break\n      case 'i64':\n(tempI64 = [\n          value >>> 0,\n          ((tempDouble = value),\n          +Math_abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math_min(+Math_floor(tempDouble / 4294967296), 4294967295) | 0) >>> 0\n              : ~~+Math_ceil((tempDouble - +(~~tempDouble >>> 0)) / 4294967296) >>> 0\n            : 0),\n        ]),\n          (HEAP32[ptr >> 2] = tempI64[0]),\n          (HEAP32[(ptr + 4) >> 2] = tempI64[1]);\n        break\n      case 'float':\n        HEAPF32[ptr >> 2] = value;\n        break\n      case 'double':\n        HEAPF64[ptr >> 3] = value;\n        break\n      default:\n        abort('invalid type for setValue: ' + type);\n    }\n  }\n  var ALLOC_NORMAL = 0;\n  var ALLOC_STATIC = 2;\n  var ALLOC_NONE = 4;\n  function allocate(slab, types, allocator, ptr) {\n    var zeroinit, size;\n    if (typeof slab === 'number') {\n      zeroinit = true;\n      size = slab;\n    } else {\n      zeroinit = false;\n      size = slab.length;\n    }\n    var singleType = typeof types === 'string' ? types : null;\n    var ret;\n    if (allocator == ALLOC_NONE) {\n      ret = ptr;\n    } else {\n      ret = [typeof _malloc === 'function' ? _malloc : staticAlloc, stackAlloc, staticAlloc, dynamicAlloc][\n        allocator === undefined ? ALLOC_STATIC : allocator\n      ](Math.max(size, singleType ? 1 : types.length));\n    }\n    if (zeroinit) {\n      var stop;\n      ptr = ret;\n      assert((ret & 3) == 0);\n      stop = ret + (size & ~3);\n      for (; ptr < stop; ptr += 4) {\n        HEAP32[ptr >> 2] = 0;\n      }\n      stop = ret + size;\n      while (ptr < stop) {\n        HEAP8[ptr++ >> 0] = 0;\n      }\n      return ret\n    }\n    if (singleType === 'i8') {\n      if (slab.subarray || slab.slice) {\n        HEAPU8.set(slab, ret);\n      } else {\n        HEAPU8.set(new Uint8Array(slab), ret);\n      }\n      return ret\n    }\n    var i = 0,\n      type,\n      typeSize,\n      previousType;\n    while (i < size) {\n      var curr = slab[i];\n      type = singleType || types[i];\n      if (type === 0) {\n        i++;\n        continue\n      }\n      if (type == 'i64') type = 'i32';\n      setValue(ret + i, curr, type);\n      if (previousType !== type) {\n        typeSize = getNativeTypeSize(type);\n        previousType = type;\n      }\n      i += typeSize;\n    }\n    return ret\n  }\n  function Pointer_stringify(ptr, length) {\n    if (length === 0 || !ptr) return ''\n    var hasUtf = 0;\n    var t;\n    var i = 0;\n    while (1) {\n      t = HEAPU8[(ptr + i) >> 0];\n      hasUtf |= t;\n      if (t == 0 && !length) break\n      i++;\n      if (length && i == length) break\n    }\n    if (!length) length = i;\n    var ret = '';\n    if (hasUtf < 128) {\n      var MAX_CHUNK = 1024;\n      var curr;\n      while (length > 0) {\n        curr = String.fromCharCode.apply(String, HEAPU8.subarray(ptr, ptr + Math.min(length, MAX_CHUNK)));\n        ret = ret ? ret + curr : curr;\n        ptr += MAX_CHUNK;\n        length -= MAX_CHUNK;\n      }\n      return ret\n    }\n    return UTF8ToString(ptr)\n  }\n  var UTF8Decoder = typeof TextDecoder !== 'undefined' ? new TextDecoder('utf8') : undefined;\n  function UTF8ArrayToString(u8Array, idx) {\n    var endPtr = idx;\n    while (u8Array[endPtr]) ++endPtr;\n    if (endPtr - idx > 16 && u8Array.subarray && UTF8Decoder) {\n      return UTF8Decoder.decode(u8Array.subarray(idx, endPtr))\n    } else {\n      var u0, u1, u2, u3, u4, u5;\n      var str = '';\n      while (1) {\n        u0 = u8Array[idx++];\n        if (!u0) return str\n        if (!(u0 & 128)) {\n          str += String.fromCharCode(u0);\n          continue\n        }\n        u1 = u8Array[idx++] & 63;\n        if ((u0 & 224) == 192) {\n          str += String.fromCharCode(((u0 & 31) << 6) | u1);\n          continue\n        }\n        u2 = u8Array[idx++] & 63;\n        if ((u0 & 240) == 224) {\n          u0 = ((u0 & 15) << 12) | (u1 << 6) | u2;\n        } else {\n          u3 = u8Array[idx++] & 63;\n          if ((u0 & 248) == 240) {\n            u0 = ((u0 & 7) << 18) | (u1 << 12) | (u2 << 6) | u3;\n          } else {\n            u4 = u8Array[idx++] & 63;\n            if ((u0 & 252) == 248) {\n              u0 = ((u0 & 3) << 24) | (u1 << 18) | (u2 << 12) | (u3 << 6) | u4;\n            } else {\n              u5 = u8Array[idx++] & 63;\n              u0 = ((u0 & 1) << 30) | (u1 << 24) | (u2 << 18) | (u3 << 12) | (u4 << 6) | u5;\n            }\n          }\n        }\n        if (u0 < 65536) {\n          str += String.fromCharCode(u0);\n        } else {\n          var ch = u0 - 65536;\n          str += String.fromCharCode(55296 | (ch >> 10), 56320 | (ch & 1023));\n        }\n      }\n    }\n  }\n  function UTF8ToString(ptr) {\n    return UTF8ArrayToString(HEAPU8, ptr)\n  }\n  function stringToUTF8Array(str, outU8Array, outIdx, maxBytesToWrite) {\n    if (!(maxBytesToWrite > 0)) return 0\n    var startIdx = outIdx;\n    var endIdx = outIdx + maxBytesToWrite - 1;\n    for (var i = 0; i < str.length; ++i) {\n      var u = str.charCodeAt(i);\n      if (u >= 55296 && u <= 57343) u = (65536 + ((u & 1023) << 10)) | (str.charCodeAt(++i) & 1023);\n      if (u <= 127) {\n        if (outIdx >= endIdx) break\n        outU8Array[outIdx++] = u;\n      } else if (u <= 2047) {\n        if (outIdx + 1 >= endIdx) break\n        outU8Array[outIdx++] = 192 | (u >> 6);\n        outU8Array[outIdx++] = 128 | (u & 63);\n      } else if (u <= 65535) {\n        if (outIdx + 2 >= endIdx) break\n        outU8Array[outIdx++] = 224 | (u >> 12);\n        outU8Array[outIdx++] = 128 | ((u >> 6) & 63);\n        outU8Array[outIdx++] = 128 | (u & 63);\n      } else if (u <= 2097151) {\n        if (outIdx + 3 >= endIdx) break\n        outU8Array[outIdx++] = 240 | (u >> 18);\n        outU8Array[outIdx++] = 128 | ((u >> 12) & 63);\n        outU8Array[outIdx++] = 128 | ((u >> 6) & 63);\n        outU8Array[outIdx++] = 128 | (u & 63);\n      } else if (u <= 67108863) {\n        if (outIdx + 4 >= endIdx) break\n        outU8Array[outIdx++] = 248 | (u >> 24);\n        outU8Array[outIdx++] = 128 | ((u >> 18) & 63);\n        outU8Array[outIdx++] = 128 | ((u >> 12) & 63);\n        outU8Array[outIdx++] = 128 | ((u >> 6) & 63);\n        outU8Array[outIdx++] = 128 | (u & 63);\n      } else {\n        if (outIdx + 5 >= endIdx) break\n        outU8Array[outIdx++] = 252 | (u >> 30);\n        outU8Array[outIdx++] = 128 | ((u >> 24) & 63);\n        outU8Array[outIdx++] = 128 | ((u >> 18) & 63);\n        outU8Array[outIdx++] = 128 | ((u >> 12) & 63);\n        outU8Array[outIdx++] = 128 | ((u >> 6) & 63);\n        outU8Array[outIdx++] = 128 | (u & 63);\n      }\n    }\n    outU8Array[outIdx] = 0;\n    return outIdx - startIdx\n  }\n  function stringToUTF8(str, outPtr, maxBytesToWrite) {\n    return stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite)\n  }\n  function lengthBytesUTF8(str) {\n    var len = 0;\n    for (var i = 0; i < str.length; ++i) {\n      var u = str.charCodeAt(i);\n      if (u >= 55296 && u <= 57343) u = (65536 + ((u & 1023) << 10)) | (str.charCodeAt(++i) & 1023);\n      if (u <= 127) {\n        ++len;\n      } else if (u <= 2047) {\n        len += 2;\n      } else if (u <= 65535) {\n        len += 3;\n      } else if (u <= 2097151) {\n        len += 4;\n      } else if (u <= 67108863) {\n        len += 5;\n      } else {\n        len += 6;\n      }\n    }\n    return len\n  }\n  typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-16le') : undefined;\n  function UTF32ToString(ptr) {\n    var i = 0;\n    var str = '';\n    while (1) {\n      var utf32 = HEAP32[(ptr + i * 4) >> 2];\n      if (utf32 == 0) return str\n      ++i;\n      if (utf32 >= 65536) {\n        var ch = utf32 - 65536;\n        str += String.fromCharCode(55296 | (ch >> 10), 56320 | (ch & 1023));\n      } else {\n        str += String.fromCharCode(utf32);\n      }\n    }\n  }\n  function allocateUTF8(str) {\n    var size = lengthBytesUTF8(str) + 1;\n    var ret = _malloc(size);\n    if (ret) stringToUTF8Array(str, HEAP8, ret, size);\n    return ret\n  }\n  function demangle(func) {\n    return func\n  }\n  function demangleAll(text) {\n    var regex = /__Z[\\w\\d_]+/g;\n    return text.replace(regex, function (x) {\n      var y = demangle(x);\n      return x === y ? x : x + ' [' + y + ']'\n    })\n  }\n  function jsStackTrace() {\n    var err = new Error();\n    if (!err.stack) {\n      try {\n        throw new Error(0)\n      } catch (e) {\n        err = e;\n      }\n      if (!err.stack) {\n        return '(no stack trace available)'\n      }\n    }\n    return err.stack.toString()\n  }\n  function stackTrace() {\n    var js = jsStackTrace();\n    if (Module['extraStackTrace']) js += '\\n' + Module['extraStackTrace']();\n    return demangleAll(js)\n  }\n  var WASM_PAGE_SIZE = 65536;\n  var ASMJS_PAGE_SIZE = 16777216;\n  var MIN_TOTAL_MEMORY = 16777216;\n  function alignUp(x, multiple) {\n    if (x % multiple > 0) {\n      x += multiple - (x % multiple);\n    }\n    return x\n  }\n  var buffer, HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64;\n  function updateGlobalBuffer(buf) {\n    Module['buffer'] = buffer = buf;\n  }\n  function updateGlobalBufferViews() {\n    Module['HEAP8'] = HEAP8 = new Int8Array(buffer);\n    Module['HEAP16'] = HEAP16 = new Int16Array(buffer);\n    Module['HEAP32'] = HEAP32 = new Int32Array(buffer);\n    Module['HEAPU8'] = HEAPU8 = new Uint8Array(buffer);\n    Module['HEAPU16'] = HEAPU16 = new Uint16Array(buffer);\n    Module['HEAPU32'] = HEAPU32 = new Uint32Array(buffer);\n    Module['HEAPF32'] = HEAPF32 = new Float32Array(buffer);\n    Module['HEAPF64'] = HEAPF64 = new Float64Array(buffer);\n  }\n  var STATIC_BASE, STATICTOP, staticSealed;\n  var STACK_BASE, STACKTOP, STACK_MAX;\n  var DYNAMIC_BASE, DYNAMICTOP_PTR;\n  STATIC_BASE = STATICTOP = STACK_BASE = STACKTOP = STACK_MAX = DYNAMIC_BASE = DYNAMICTOP_PTR = 0;\n  staticSealed = false;\n  function abortOnCannotGrowMemory() {\n    abort(\n      'Cannot enlarge memory arrays. Either (1) compile with  -s TOTAL_MEMORY=X  with X higher than the current value ' +\n        TOTAL_MEMORY +\n        ', (2) compile with  -s ALLOW_MEMORY_GROWTH=1  which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with  -s ABORTING_MALLOC=0 '\n    );\n  }\n  if (!Module['reallocBuffer'])\n    Module['reallocBuffer'] = function (size) {\n      var ret;\n      try {\n        if (ArrayBuffer.transfer) {\n          ret = ArrayBuffer.transfer(buffer, size);\n        } else {\n          var oldHEAP8 = HEAP8;\n          ret = new ArrayBuffer(size);\n          var temp = new Int8Array(ret);\n          temp.set(oldHEAP8);\n        }\n      } catch (e) {\n        return false\n      }\n      var success = _emscripten_replace_memory(ret);\n      if (!success) return false\n      return ret\n    };\n  function enlargeMemory() {\n    var PAGE_MULTIPLE = Module['usingWasm'] ? WASM_PAGE_SIZE : ASMJS_PAGE_SIZE;\n    var LIMIT = 2147483648 - PAGE_MULTIPLE;\n    if (HEAP32[DYNAMICTOP_PTR >> 2] > LIMIT) {\n      return false\n    }\n    var OLD_TOTAL_MEMORY = TOTAL_MEMORY;\n    TOTAL_MEMORY = Math.max(TOTAL_MEMORY, MIN_TOTAL_MEMORY);\n    while (TOTAL_MEMORY < HEAP32[DYNAMICTOP_PTR >> 2]) {\n      if (TOTAL_MEMORY <= 536870912) {\n        TOTAL_MEMORY = alignUp(2 * TOTAL_MEMORY, PAGE_MULTIPLE);\n      } else {\n        TOTAL_MEMORY = Math.min(alignUp((3 * TOTAL_MEMORY + 2147483648) / 4, PAGE_MULTIPLE), LIMIT);\n      }\n    }\n    var replacement = Module['reallocBuffer'](TOTAL_MEMORY);\n    if (!replacement || replacement.byteLength != TOTAL_MEMORY) {\n      TOTAL_MEMORY = OLD_TOTAL_MEMORY;\n      return false\n    }\n    updateGlobalBuffer(replacement);\n    updateGlobalBufferViews();\n    return true\n  }\n  var byteLength;\n  try {\n    byteLength = Function.prototype.call.bind(Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, 'byteLength').get);\n    byteLength(new ArrayBuffer(4));\n  } catch (e) {\n    byteLength = function (buffer) {\n      return buffer.byteLength\n    };\n  }\n  var TOTAL_STACK = Module['TOTAL_STACK'] || 5242880;\n  var TOTAL_MEMORY = Module['TOTAL_MEMORY'] || 16777216;\n  if (TOTAL_MEMORY < TOTAL_STACK)\n    Module.printErr(\n      'TOTAL_MEMORY should be larger than TOTAL_STACK, was ' + TOTAL_MEMORY + '! (TOTAL_STACK=' + TOTAL_STACK + ')'\n    );\n  if (Module['buffer']) {\n    buffer = Module['buffer'];\n  } else {\n    if (typeof WebAssembly === 'object' && typeof WebAssembly.Memory === 'function') {\n      Module['wasmMemory'] = new WebAssembly.Memory({ initial: TOTAL_MEMORY / WASM_PAGE_SIZE });\n      buffer = Module['wasmMemory'].buffer;\n    } else {\n      buffer = new ArrayBuffer(TOTAL_MEMORY);\n    }\n    Module['buffer'] = buffer;\n  }\n  updateGlobalBufferViews();\n  function getTotalMemory() {\n    return TOTAL_MEMORY\n  }\n  HEAP32[0] = 1668509029;\n  HEAP16[1] = 25459;\n  if (HEAPU8[2] !== 115 || HEAPU8[3] !== 99) throw 'Runtime error: expected the system to be little-endian!'\n  function callRuntimeCallbacks(callbacks) {\n    while (callbacks.length > 0) {\n      var callback = callbacks.shift();\n      if (typeof callback == 'function') {\n        callback();\n        continue\n      }\n      var func = callback.func;\n      if (typeof func === 'number') {\n        if (callback.arg === undefined) {\n          Module['dynCall_v'](func);\n        } else {\n          Module['dynCall_vi'](func, callback.arg);\n        }\n      } else {\n        func(callback.arg === undefined ? null : callback.arg);\n      }\n    }\n  }\n  var __ATPRERUN__ = [];\n  var __ATINIT__ = [];\n  var __ATMAIN__ = [];\n  var __ATEXIT__ = [];\n  var __ATPOSTRUN__ = [];\n  var runtimeInitialized = false;\n  function preRun() {\n    if (Module['preRun']) {\n      if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']];\n      while (Module['preRun'].length) {\n        addOnPreRun(Module['preRun'].shift());\n      }\n    }\n    callRuntimeCallbacks(__ATPRERUN__);\n  }\n  function ensureInitRuntime() {\n    if (runtimeInitialized) return\n    runtimeInitialized = true;\n    callRuntimeCallbacks(__ATINIT__);\n  }\n  function preMain() {\n    callRuntimeCallbacks(__ATMAIN__);\n  }\n  function exitRuntime() {\n    callRuntimeCallbacks(__ATEXIT__);\n  }\n  function postRun() {\n    if (Module['postRun']) {\n      if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']];\n      while (Module['postRun'].length) {\n        addOnPostRun(Module['postRun'].shift());\n      }\n    }\n    callRuntimeCallbacks(__ATPOSTRUN__);\n  }\n  function addOnPreRun(cb) {\n    __ATPRERUN__.unshift(cb);\n  }\n  function addOnPostRun(cb) {\n    __ATPOSTRUN__.unshift(cb);\n  }\n  function writeAsciiToMemory(str, buffer, dontAddNull) {\n    for (var i = 0; i < str.length; ++i) {\n      HEAP8[buffer++ >> 0] = str.charCodeAt(i);\n    }\n    if (!dontAddNull) HEAP8[buffer >> 0] = 0;\n  }\n  var Math_abs = Math.abs;\n  var Math_ceil = Math.ceil;\n  var Math_floor = Math.floor;\n  var Math_min = Math.min;\n  var runDependencies = 0;\n  var dependenciesFulfilled = null;\n  function addRunDependency(id) {\n    runDependencies++;\n    if (Module['monitorRunDependencies']) {\n      Module['monitorRunDependencies'](runDependencies);\n    }\n  }\n  function removeRunDependency(id) {\n    runDependencies--;\n    if (Module['monitorRunDependencies']) {\n      Module['monitorRunDependencies'](runDependencies);\n    }\n    if (runDependencies == 0) {\n      if (dependenciesFulfilled) {\n        var callback = dependenciesFulfilled;\n        dependenciesFulfilled = null;\n        callback();\n      }\n    }\n  }\n  Module['preloadedImages'] = {};\n  Module['preloadedAudios'] = {};\n  var dataURIPrefix = 'data:application/octet-stream;base64,';\n  function isDataURI(filename) {\n    return String.prototype.startsWith ? filename.startsWith(dataURIPrefix) : filename.indexOf(dataURIPrefix) === 0\n  }\n  function integrateWasmJS() {\n    var wasmTextFile = 'unpack.wast';\n    var asmjsCodeFile = 'unpack.temp.asm.js';\n    if (typeof Module['locateFile'] === 'function') {\n      if (!isDataURI(wasmTextFile)) {\n        wasmTextFile = Module['locateFile'](wasmTextFile);\n      }\n      if (!isDataURI(wasmBinaryFile)) {\n        wasmBinaryFile = Module['locateFile'](wasmBinaryFile);\n      }\n      if (!isDataURI(asmjsCodeFile)) {\n        asmjsCodeFile = Module['locateFile'](asmjsCodeFile);\n      }\n    }\n    const wasmPageSize = 64 * 1024;\n    const info = {\n      asm2wasm: {\n        'f64-rem': function (x, y) {\n          return x % y\n        },\n        debugger: function () {\n          debugger\n        },\n      },\n      parent: Module,\n    };\n    var exports = null;\n    function mergeMemory(newBuffer) {\n      var oldBuffer = Module['buffer'];\n      if (newBuffer.byteLength < oldBuffer.byteLength) {\n        Module['printErr'](\n          'the new buffer in mergeMemory is smaller than the previous one. in native wasm, we should grow memory here'\n        );\n      }\n      var oldView = new Int8Array(oldBuffer);\n      var newView = new Int8Array(newBuffer);\n      newView.set(oldView);\n      updateGlobalBuffer(newBuffer);\n      updateGlobalBufferViews();\n    }\n    function fixImports(imports) {\n      return imports\n    }\n    function getBinary() {\n      try {\n        if (Module['wasmBinary']) {\n          return new Uint8Array(Module['wasmBinary'])\n        }\n        if (Module['readBinary']) {\n          return Module['readBinary'](wasmBinaryFile)\n        } else {\n          throw \"on the web, we need the wasm binary to be preloaded and set on Module['wasmBinary']. emcc.py will do that for you when generating HTML (but not JS)\"\n        }\n      } catch (err) {\n        abort(err);\n      }\n    }\n    function getBinaryPromise() {\n      if (!Module['wasmBinary'] && (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) && typeof fetch === 'function') {\n        return fetch(wasmBinaryFile, { credentials })\n          .then(function (response) {\n            if (!response['ok']) {\n              throw \"failed to load wasm binary file at '\" + wasmBinaryFile + \"'\"\n            }\n            return response['arrayBuffer']()\n          })\n          .catch(function () {\n            return getBinary()\n          })\n      }\n      return new Promise(function (resolve, reject) {\n        resolve(getBinary());\n      })\n    }\n    function doNativeWasm(global, env, providedBuffer) {\n      if (typeof WebAssembly !== 'object') {\n        Module['printErr']('no native wasm support detected');\n        return false\n      }\n      if (!(Module['wasmMemory'] instanceof WebAssembly.Memory)) {\n        Module['printErr']('no native wasm Memory in use');\n        return false\n      }\n      env['memory'] = Module['wasmMemory'];\n      info['global'] = { NaN: NaN, Infinity: Infinity };\n      info['global.Math'] = Math;\n      info['env'] = env;\n      function receiveInstance(instance, module) {\n        exports = instance.exports;\n        if (exports.memory) mergeMemory(exports.memory);\n        Module['asm'] = exports;\n        Module['usingWasm'] = true;\n        removeRunDependency();\n      }\n      addRunDependency();\n      if (Module['instantiateWasm']) {\n        try {\n          return Module['instantiateWasm'](info, receiveInstance)\n        } catch (e) {\n          Module['printErr']('Module.instantiateWasm callback failed with error: ' + e);\n          return false\n        }\n      }\n      function receiveInstantiatedSource(output) {\n        receiveInstance(output['instance'], output['module']);\n      }\n      function instantiateArrayBuffer(receiver) {\n        getBinaryPromise()\n          .then(function (binary) {\n            return WebAssembly.instantiate(binary, info)\n          })\n          .then(receiver)\n          .catch(function (reason) {\n            Module['printErr']('failed to asynchronously prepare wasm: ' + reason);\n            abort(reason);\n          });\n      }\n      if (\n        !Module['wasmBinary'] &&\n        typeof WebAssembly.instantiateStreaming === 'function' &&\n        !isDataURI(wasmBinaryFile) &&\n        typeof fetch === 'function'\n      ) {\n        WebAssembly.instantiateStreaming(fetch(wasmBinaryFile, { credentials }), info)\n          .then(receiveInstantiatedSource)\n          .catch(function (reason) {\n            Module['printErr']('wasm streaming compile failed: ' + reason);\n            Module['printErr']('falling back to ArrayBuffer instantiation');\n            instantiateArrayBuffer(receiveInstantiatedSource);\n          });\n      } else {\n        instantiateArrayBuffer(receiveInstantiatedSource);\n      }\n      return {}\n    }\n    Module['asmPreload'] = Module['asm'];\n    var asmjsReallocBuffer = Module['reallocBuffer'];\n    var wasmReallocBuffer = function (size) {\n      var PAGE_MULTIPLE = Module['usingWasm'] ? WASM_PAGE_SIZE : ASMJS_PAGE_SIZE;\n      size = alignUp(size, PAGE_MULTIPLE);\n      var old = Module['buffer'];\n      var oldSize = old.byteLength;\n      if (Module['usingWasm']) {\n        try {\n          var result = Module['wasmMemory'].grow((size - oldSize) / wasmPageSize);\n          if (result !== (-1 | 0)) {\n            return (Module['buffer'] = Module['wasmMemory'].buffer)\n          } else {\n            return null\n          }\n        } catch (e) {\n          return null\n        }\n      }\n    };\n    Module['reallocBuffer'] = function (size) {\n      if (finalMethod === 'asmjs') {\n        return asmjsReallocBuffer(size)\n      } else {\n        return wasmReallocBuffer(size)\n      }\n    };\n    var finalMethod = '';\n    Module['asm'] = function (global, env, providedBuffer) {\n      env = fixImports(env);\n      if (!env['table']) {\n        var TABLE_SIZE = Module['wasmTableSize'];\n        if (TABLE_SIZE === undefined) TABLE_SIZE = 1024;\n        var MAX_TABLE_SIZE = Module['wasmMaxTableSize'];\n        if (typeof WebAssembly === 'object' && typeof WebAssembly.Table === 'function') {\n          if (MAX_TABLE_SIZE !== undefined) {\n            env['table'] = new WebAssembly.Table({ initial: TABLE_SIZE, maximum: MAX_TABLE_SIZE, element: 'anyfunc' });\n          } else {\n            env['table'] = new WebAssembly.Table({ initial: TABLE_SIZE, element: 'anyfunc' });\n          }\n        } else {\n          env['table'] = new Array(TABLE_SIZE);\n        }\n        Module['wasmTable'] = env['table'];\n      }\n      if (!env['memoryBase']) {\n        env['memoryBase'] = Module['STATIC_BASE'];\n      }\n      if (!env['tableBase']) {\n        env['tableBase'] = 0;\n      }\n      var exports;\n      exports = doNativeWasm(global, env);\n      if (!exports)\n        abort(\n          'no binaryen method succeeded. consider enabling more options, like interpreting, if you want that: https://github.com/kripken/emscripten/wiki/WebAssembly#binaryen-methods'\n        );\n      return exports\n    };\n  }\n  integrateWasmJS();\n  STATIC_BASE = GLOBAL_BASE;\n  STATICTOP = STATIC_BASE + 66960;\n  __ATINIT__.push(\n    {\n      func: function () {\n        __GLOBAL__sub_I_global_cpp();\n      },\n    },\n    {\n      func: function () {\n        __GLOBAL__sub_I_crc_cpp();\n      },\n    },\n    {\n      func: function () {\n        __GLOBAL__sub_I_bridge_cpp();\n      },\n    },\n    {\n      func: function () {\n        __GLOBAL__sub_I_bind_cpp();\n      },\n    }\n  );\n  var STATIC_BUMP = 66960;\n  Module['STATIC_BASE'] = STATIC_BASE;\n  Module['STATIC_BUMP'] = STATIC_BUMP;\n  STATICTOP += 16;\n  function ___cxa_allocate_exception(size) {\n    return _malloc(size)\n  }\n  function __ZSt18uncaught_exceptionv() {\n    return !!__ZSt18uncaught_exceptionv.uncaught_exception\n  }\n  var EXCEPTIONS = {\n    last: 0,\n    caught: [],\n    infos: {},\n    deAdjust: function (adjusted) {\n      if (!adjusted || EXCEPTIONS.infos[adjusted]) return adjusted\n      for (var key in EXCEPTIONS.infos) {\n        var ptr = +key;\n        var info = EXCEPTIONS.infos[ptr];\n        if (info.adjusted === adjusted) {\n          return ptr\n        }\n      }\n      return adjusted\n    },\n    addRef: function (ptr) {\n      if (!ptr) return\n      var info = EXCEPTIONS.infos[ptr];\n      info.refcount++;\n    },\n    decRef: function (ptr) {\n      if (!ptr) return\n      var info = EXCEPTIONS.infos[ptr];\n      assert(info.refcount > 0);\n      info.refcount--;\n      if (info.refcount === 0 && !info.rethrown) {\n        if (info.destructor) {\n          Module['dynCall_vi'](info.destructor, ptr);\n        }\n        delete EXCEPTIONS.infos[ptr];\n        ___cxa_free_exception(ptr);\n      }\n    },\n    clearRef: function (ptr) {\n      if (!ptr) return\n      var info = EXCEPTIONS.infos[ptr];\n      info.refcount = 0;\n    },\n  };\n  function ___cxa_begin_catch(ptr) {\n    var info = EXCEPTIONS.infos[ptr];\n    if (info && !info.caught) {\n      info.caught = true;\n      __ZSt18uncaught_exceptionv.uncaught_exception--;\n    }\n    if (info) info.rethrown = false;\n    EXCEPTIONS.caught.push(ptr);\n    EXCEPTIONS.addRef(EXCEPTIONS.deAdjust(ptr));\n    return ptr\n  }\n  function ___cxa_free_exception(ptr) {\n    try {\n      return _free(ptr)\n    } catch (e) {}\n  }\n  function ___cxa_end_catch() {\n    Module['setThrew'](0);\n    var ptr = EXCEPTIONS.caught.pop();\n    if (ptr) {\n      EXCEPTIONS.decRef(EXCEPTIONS.deAdjust(ptr));\n      EXCEPTIONS.last = 0;\n    }\n  }\n  function ___cxa_find_matching_catch_2() {\n    return ___cxa_find_matching_catch.apply(null, arguments)\n  }\n  function ___cxa_find_matching_catch_3() {\n    return ___cxa_find_matching_catch.apply(null, arguments)\n  }\n  function ___cxa_find_matching_catch_4() {\n    return ___cxa_find_matching_catch.apply(null, arguments)\n  }\n  function ___resumeException(ptr) {\n    if (!EXCEPTIONS.last) {\n      EXCEPTIONS.last = ptr;\n    }\n    throw ptr\n  }\n  function ___cxa_find_matching_catch() {\n    var thrown = EXCEPTIONS.last;\n    if (!thrown) {\n      return (setTempRet0(0), 0) | 0\n    }\n    var info = EXCEPTIONS.infos[thrown];\n    var throwntype = info.type;\n    if (!throwntype) {\n      return (setTempRet0(0), thrown) | 0\n    }\n    var typeArray = Array.prototype.slice.call(arguments);\n    Module['___cxa_is_pointer_type'](throwntype);\n    if (!___cxa_find_matching_catch.buffer) ___cxa_find_matching_catch.buffer = _malloc(4);\n    HEAP32[___cxa_find_matching_catch.buffer >> 2] = thrown;\n    thrown = ___cxa_find_matching_catch.buffer;\n    for (var i = 0; i < typeArray.length; i++) {\n      if (typeArray[i] && Module['___cxa_can_catch'](typeArray[i], throwntype, thrown)) {\n        thrown = HEAP32[thrown >> 2];\n        info.adjusted = thrown;\n        return (setTempRet0(typeArray[i]), thrown) | 0\n      }\n    }\n    thrown = HEAP32[thrown >> 2];\n    return (setTempRet0(throwntype), thrown) | 0\n  }\n  function ___cxa_throw(ptr, type, destructor) {\n    EXCEPTIONS.infos[ptr] = {\n      ptr: ptr,\n      adjusted: ptr,\n      type: type,\n      destructor: destructor,\n      refcount: 0,\n      caught: false,\n      rethrown: false,\n    };\n    EXCEPTIONS.last = ptr;\n    if (!('uncaught_exception' in __ZSt18uncaught_exceptionv)) {\n      __ZSt18uncaught_exceptionv.uncaught_exception = 1;\n    } else {\n      __ZSt18uncaught_exceptionv.uncaught_exception++;\n    }\n    throw ptr\n  }\n  function ___lock() {}\n  var ERRNO_CODES = {\n    EPERM: 1,\n    ENOENT: 2,\n    ESRCH: 3,\n    EINTR: 4,\n    EIO: 5,\n    ENXIO: 6,\n    E2BIG: 7,\n    ENOEXEC: 8,\n    EBADF: 9,\n    ECHILD: 10,\n    EAGAIN: 11,\n    EWOULDBLOCK: 11,\n    ENOMEM: 12,\n    EACCES: 13,\n    EFAULT: 14,\n    ENOTBLK: 15,\n    EBUSY: 16,\n    EEXIST: 17,\n    EXDEV: 18,\n    ENODEV: 19,\n    ENOTDIR: 20,\n    EISDIR: 21,\n    EINVAL: 22,\n    ENFILE: 23,\n    EMFILE: 24,\n    ENOTTY: 25,\n    ETXTBSY: 26,\n    EFBIG: 27,\n    ENOSPC: 28,\n    ESPIPE: 29,\n    EROFS: 30,\n    EMLINK: 31,\n    EPIPE: 32,\n    EDOM: 33,\n    ERANGE: 34,\n    ENOMSG: 42,\n    EIDRM: 43,\n    ECHRNG: 44,\n    EL2NSYNC: 45,\n    EL3HLT: 46,\n    EL3RST: 47,\n    ELNRNG: 48,\n    EUNATCH: 49,\n    ENOCSI: 50,\n    EL2HLT: 51,\n    EDEADLK: 35,\n    ENOLCK: 37,\n    EBADE: 52,\n    EBADR: 53,\n    EXFULL: 54,\n    ENOANO: 55,\n    EBADRQC: 56,\n    EBADSLT: 57,\n    EDEADLOCK: 35,\n    EBFONT: 59,\n    ENOSTR: 60,\n    ENODATA: 61,\n    ETIME: 62,\n    ENOSR: 63,\n    ENONET: 64,\n    ENOPKG: 65,\n    EREMOTE: 66,\n    ENOLINK: 67,\n    EADV: 68,\n    ESRMNT: 69,\n    ECOMM: 70,\n    EPROTO: 71,\n    EMULTIHOP: 72,\n    EDOTDOT: 73,\n    EBADMSG: 74,\n    ENOTUNIQ: 76,\n    EBADFD: 77,\n    EREMCHG: 78,\n    ELIBACC: 79,\n    ELIBBAD: 80,\n    ELIBSCN: 81,\n    ELIBMAX: 82,\n    ELIBEXEC: 83,\n    ENOSYS: 38,\n    ENOTEMPTY: 39,\n    ENAMETOOLONG: 36,\n    ELOOP: 40,\n    EOPNOTSUPP: 95,\n    EPFNOSUPPORT: 96,\n    ECONNRESET: 104,\n    ENOBUFS: 105,\n    EAFNOSUPPORT: 97,\n    EPROTOTYPE: 91,\n    ENOTSOCK: 88,\n    ENOPROTOOPT: 92,\n    ESHUTDOWN: 108,\n    ECONNREFUSED: 111,\n    EADDRINUSE: 98,\n    ECONNABORTED: 103,\n    ENETUNREACH: 101,\n    ENETDOWN: 100,\n    ETIMEDOUT: 110,\n    EHOSTDOWN: 112,\n    EHOSTUNREACH: 113,\n    EINPROGRESS: 115,\n    EALREADY: 114,\n    EDESTADDRREQ: 89,\n    EMSGSIZE: 90,\n    EPROTONOSUPPORT: 93,\n    ESOCKTNOSUPPORT: 94,\n    EADDRNOTAVAIL: 99,\n    ENETRESET: 102,\n    EISCONN: 106,\n    ENOTCONN: 107,\n    ETOOMANYREFS: 109,\n    EUSERS: 87,\n    EDQUOT: 122,\n    ESTALE: 116,\n    ENOTSUP: 95,\n    ENOMEDIUM: 123,\n    EILSEQ: 84,\n    EOVERFLOW: 75,\n    ECANCELED: 125,\n    ENOTRECOVERABLE: 131,\n    EOWNERDEAD: 130,\n    ESTRPIPE: 86,\n  };\n  function ___setErrNo(value) {\n    if (Module['___errno_location']) HEAP32[Module['___errno_location']() >> 2] = value;\n    return value\n  }\n  function ___map_file(pathname, size) {\n    ___setErrNo(ERRNO_CODES.EPERM);\n    return -1\n  }\n  var ERRNO_MESSAGES = {\n    0: 'Success',\n    1: 'Not super-user',\n    2: 'No such file or directory',\n    3: 'No such process',\n    4: 'Interrupted system call',\n    5: 'I/O error',\n    6: 'No such device or address',\n    7: 'Arg list too long',\n    8: 'Exec format error',\n    9: 'Bad file number',\n    10: 'No children',\n    11: 'No more processes',\n    12: 'Not enough core',\n    13: 'Permission denied',\n    14: 'Bad address',\n    15: 'Block device required',\n    16: 'Mount device busy',\n    17: 'File exists',\n    18: 'Cross-device link',\n    19: 'No such device',\n    20: 'Not a directory',\n    21: 'Is a directory',\n    22: 'Invalid argument',\n    23: 'Too many open files in system',\n    24: 'Too many open files',\n    25: 'Not a typewriter',\n    26: 'Text file busy',\n    27: 'File too large',\n    28: 'No space left on device',\n    29: 'Illegal seek',\n    30: 'Read only file system',\n    31: 'Too many links',\n    32: 'Broken pipe',\n    33: 'Math arg out of domain of func',\n    34: 'Math result not representable',\n    35: 'File locking deadlock error',\n    36: 'File or path name too long',\n    37: 'No record locks available',\n    38: 'Function not implemented',\n    39: 'Directory not empty',\n    40: 'Too many symbolic links',\n    42: 'No message of desired type',\n    43: 'Identifier removed',\n    44: 'Channel number out of range',\n    45: 'Level 2 not synchronized',\n    46: 'Level 3 halted',\n    47: 'Level 3 reset',\n    48: 'Link number out of range',\n    49: 'Protocol driver not attached',\n    50: 'No CSI structure available',\n    51: 'Level 2 halted',\n    52: 'Invalid exchange',\n    53: 'Invalid request descriptor',\n    54: 'Exchange full',\n    55: 'No anode',\n    56: 'Invalid request code',\n    57: 'Invalid slot',\n    59: 'Bad font file fmt',\n    60: 'Device not a stream',\n    61: 'No data (for no delay io)',\n    62: 'Timer expired',\n    63: 'Out of streams resources',\n    64: 'Machine is not on the network',\n    65: 'Package not installed',\n    66: 'The object is remote',\n    67: 'The link has been severed',\n    68: 'Advertise error',\n    69: 'Srmount error',\n    70: 'Communication error on send',\n    71: 'Protocol error',\n    72: 'Multihop attempted',\n    73: 'Cross mount point (not really error)',\n    74: 'Trying to read unreadable message',\n    75: 'Value too large for defined data type',\n    76: 'Given log. name not unique',\n    77: 'f.d. invalid for this operation',\n    78: 'Remote address changed',\n    79: 'Can   access a needed shared lib',\n    80: 'Accessing a corrupted shared lib',\n    81: '.lib section in a.out corrupted',\n    82: 'Attempting to link in too many libs',\n    83: 'Attempting to exec a shared library',\n    84: 'Illegal byte sequence',\n    86: 'Streams pipe error',\n    87: 'Too many users',\n    88: 'Socket operation on non-socket',\n    89: 'Destination address required',\n    90: 'Message too long',\n    91: 'Protocol wrong type for socket',\n    92: 'Protocol not available',\n    93: 'Unknown protocol',\n    94: 'Socket type not supported',\n    95: 'Not supported',\n    96: 'Protocol family not supported',\n    97: 'Address family not supported by protocol family',\n    98: 'Address already in use',\n    99: 'Address not available',\n    100: 'Network interface is not configured',\n    101: 'Network is unreachable',\n    102: 'Connection reset by network',\n    103: 'Connection aborted',\n    104: 'Connection reset by peer',\n    105: 'No buffer space available',\n    106: 'Socket is already connected',\n    107: 'Socket is not connected',\n    108: \"Can't send after socket shutdown\",\n    109: 'Too many references',\n    110: 'Connection timed out',\n    111: 'Connection refused',\n    112: 'Host is down',\n    113: 'Host is unreachable',\n    114: 'Socket already connected',\n    115: 'Connection already in progress',\n    116: 'Stale file handle',\n    122: 'Quota exceeded',\n    123: 'No medium (in tape drive)',\n    125: 'Operation canceled',\n    130: 'Previous owner died',\n    131: 'State not recoverable',\n  };\n  var PATH = {\n    splitPath: function (filename) {\n      var splitPathRe = /^(\\/?|)([\\s\\S]*?)((?:\\.{1,2}|[^\\/]+?|)(\\.[^.\\/]*|))(?:[\\/]*)$/;\n      return splitPathRe.exec(filename).slice(1)\n    },\n    normalizeArray: function (parts, allowAboveRoot) {\n      var up = 0;\n      for (var i = parts.length - 1; i >= 0; i--) {\n        var last = parts[i];\n        if (last === '.') {\n          parts.splice(i, 1);\n        } else if (last === '..') {\n          parts.splice(i, 1);\n          up++;\n        } else if (up) {\n          parts.splice(i, 1);\n          up--;\n        }\n      }\n      if (allowAboveRoot) {\n        for (; up; up--) {\n          parts.unshift('..');\n        }\n      }\n      return parts\n    },\n    normalize: function (path) {\n      var isAbsolute = path.charAt(0) === '/',\n        trailingSlash = path.substr(-1) === '/';\n      path = PATH.normalizeArray(\n        path.split('/').filter(function (p) {\n          return !!p\n        }),\n        !isAbsolute\n      ).join('/');\n      if (!path && !isAbsolute) {\n        path = '.';\n      }\n      if (path && trailingSlash) {\n        path += '/';\n      }\n      return (isAbsolute ? '/' : '') + path\n    },\n    dirname: function (path) {\n      var result = PATH.splitPath(path),\n        root = result[0],\n        dir = result[1];\n      if (!root && !dir) {\n        return '.'\n      }\n      if (dir) {\n        dir = dir.substr(0, dir.length - 1);\n      }\n      return root + dir\n    },\n    basename: function (path) {\n      if (path === '/') return '/'\n      var lastSlash = path.lastIndexOf('/');\n      if (lastSlash === -1) return path\n      return path.substr(lastSlash + 1)\n    },\n    extname: function (path) {\n      return PATH.splitPath(path)[3]\n    },\n    join: function () {\n      var paths = Array.prototype.slice.call(arguments, 0);\n      return PATH.normalize(paths.join('/'))\n    },\n    join2: function (l, r) {\n      return PATH.normalize(l + '/' + r)\n    },\n    resolve: function () {\n      var resolvedPath = '',\n        resolvedAbsolute = false;\n      for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {\n        var path = i >= 0 ? arguments[i] : FS.cwd();\n        if (typeof path !== 'string') {\n          throw new TypeError('Arguments to path.resolve must be strings')\n        } else if (!path) {\n          return ''\n        }\n        resolvedPath = path + '/' + resolvedPath;\n        resolvedAbsolute = path.charAt(0) === '/';\n      }\n      resolvedPath = PATH.normalizeArray(\n        resolvedPath.split('/').filter(function (p) {\n          return !!p\n        }),\n        !resolvedAbsolute\n      ).join('/');\n      return (resolvedAbsolute ? '/' : '') + resolvedPath || '.'\n    },\n    relative: function (from, to) {\n      from = PATH.resolve(from).substr(1);\n      to = PATH.resolve(to).substr(1);\n      function trim(arr) {\n        var start = 0;\n        for (; start < arr.length; start++) {\n          if (arr[start] !== '') break\n        }\n        var end = arr.length - 1;\n        for (; end >= 0; end--) {\n          if (arr[end] !== '') break\n        }\n        if (start > end) return []\n        return arr.slice(start, end - start + 1)\n      }\n      var fromParts = trim(from.split('/'));\n      var toParts = trim(to.split('/'));\n      var length = Math.min(fromParts.length, toParts.length);\n      var samePartsLength = length;\n      for (var i = 0; i < length; i++) {\n        if (fromParts[i] !== toParts[i]) {\n          samePartsLength = i;\n          break\n        }\n      }\n      var outputParts = [];\n      for (var i = samePartsLength; i < fromParts.length; i++) {\n        outputParts.push('..');\n      }\n      outputParts = outputParts.concat(toParts.slice(samePartsLength));\n      return outputParts.join('/')\n    },\n  };\n  var TTY = {\n    ttys: [],\n    init: function () {},\n    shutdown: function () {},\n    register: function (dev, ops) {\n      TTY.ttys[dev] = { input: [], output: [], ops: ops };\n      FS.registerDevice(dev, TTY.stream_ops);\n    },\n    stream_ops: {\n      open: function (stream) {\n        var tty = TTY.ttys[stream.node.rdev];\n        if (!tty) {\n          throw new FS.ErrnoError(ERRNO_CODES.ENODEV)\n        }\n        stream.tty = tty;\n        stream.seekable = false;\n      },\n      close: function (stream) {\n        stream.tty.ops.flush(stream.tty);\n      },\n      flush: function (stream) {\n        stream.tty.ops.flush(stream.tty);\n      },\n      read: function (stream, buffer, offset, length, pos) {\n        if (!stream.tty || !stream.tty.ops.get_char) {\n          throw new FS.ErrnoError(ERRNO_CODES.ENXIO)\n        }\n        var bytesRead = 0;\n        for (var i = 0; i < length; i++) {\n          var result;\n          try {\n            result = stream.tty.ops.get_char(stream.tty);\n          } catch (e) {\n            throw new FS.ErrnoError(ERRNO_CODES.EIO)\n          }\n          if (result === undefined && bytesRead === 0) {\n            throw new FS.ErrnoError(ERRNO_CODES.EAGAIN)\n          }\n          if (result === null || result === undefined) break\n          bytesRead++;\n          buffer[offset + i] = result;\n        }\n        if (bytesRead) {\n          stream.node.timestamp = Date.now();\n        }\n        return bytesRead\n      },\n      write: function (stream, buffer, offset, length, pos) {\n        if (!stream.tty || !stream.tty.ops.put_char) {\n          throw new FS.ErrnoError(ERRNO_CODES.ENXIO)\n        }\n        for (var i = 0; i < length; i++) {\n          try {\n            stream.tty.ops.put_char(stream.tty, buffer[offset + i]);\n          } catch (e) {\n            throw new FS.ErrnoError(ERRNO_CODES.EIO)\n          }\n        }\n        if (length) {\n          stream.node.timestamp = Date.now();\n        }\n        return i\n      },\n    },\n    default_tty_ops: {\n      get_char: function (tty) {\n        if (!tty.input.length) {\n          var result = null;\n          if (ENVIRONMENT_IS_NODE) {\n            var BUFSIZE = 256;\n            var buf = new Buffer(BUFSIZE);\n            var bytesRead = 0;\n            var isPosixPlatform = process.platform != 'win32';\n            var fd = process.stdin.fd;\n            if (isPosixPlatform) {\n              var usingDevice = false;\n              try {\n                fd = fs.openSync('/dev/stdin', 'r');\n                usingDevice = true;\n              } catch (e) {}\n            }\n            try {\n              bytesRead = fs.readSync(fd, buf, 0, BUFSIZE, null);\n            } catch (e) {\n              if (e.toString().indexOf('EOF') != -1) bytesRead = 0;\n              else throw e\n            }\n            if (usingDevice) {\n              fs.closeSync(fd);\n            }\n            if (bytesRead > 0) {\n              result = buf.slice(0, bytesRead).toString('utf-8');\n            } else {\n              result = null;\n            }\n          } else if (typeof window != 'undefined' && typeof window.prompt == 'function') {\n            result = window.prompt('Input: ');\n            if (result !== null) {\n              result += '\\n';\n            }\n          } else if (typeof readline == 'function') {\n            result = readline();\n            if (result !== null) {\n              result += '\\n';\n            }\n          }\n          if (!result) {\n            return null\n          }\n          tty.input = intArrayFromString(result, true);\n        }\n        return tty.input.shift()\n      },\n      put_char: function (tty, val) {\n        if (val === null || val === 10) {\n          Module['print'](UTF8ArrayToString(tty.output, 0));\n          tty.output = [];\n        } else {\n          if (val != 0) tty.output.push(val);\n        }\n      },\n      flush: function (tty) {\n        if (tty.output && tty.output.length > 0) {\n          Module['print'](UTF8ArrayToString(tty.output, 0));\n          tty.output = [];\n        }\n      },\n    },\n    default_tty1_ops: {\n      put_char: function (tty, val) {\n        if (val === null || val === 10) {\n          Module['printErr'](UTF8ArrayToString(tty.output, 0));\n          tty.output = [];\n        } else {\n          if (val != 0) tty.output.push(val);\n        }\n      },\n      flush: function (tty) {\n        if (tty.output && tty.output.length > 0) {\n          Module['printErr'](UTF8ArrayToString(tty.output, 0));\n          tty.output = [];\n        }\n      },\n    },\n  };\n  var MEMFS = {\n    ops_table: null,\n    mount: function (mount) {\n      return MEMFS.createNode(null, '/', 16384 | 511, 0)\n    },\n    createNode: function (parent, name, mode, dev) {\n      if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {\n        throw new FS.ErrnoError(ERRNO_CODES.EPERM)\n      }\n      if (!MEMFS.ops_table) {\n        MEMFS.ops_table = {\n          dir: {\n            node: {\n              getattr: MEMFS.node_ops.getattr,\n              setattr: MEMFS.node_ops.setattr,\n              lookup: MEMFS.node_ops.lookup,\n              mknod: MEMFS.node_ops.mknod,\n              rename: MEMFS.node_ops.rename,\n              unlink: MEMFS.node_ops.unlink,\n              rmdir: MEMFS.node_ops.rmdir,\n              readdir: MEMFS.node_ops.readdir,\n              symlink: MEMFS.node_ops.symlink,\n            },\n            stream: { llseek: MEMFS.stream_ops.llseek },\n          },\n          file: {\n            node: { getattr: MEMFS.node_ops.getattr, setattr: MEMFS.node_ops.setattr },\n            stream: {\n              llseek: MEMFS.stream_ops.llseek,\n              read: MEMFS.stream_ops.read,\n              write: MEMFS.stream_ops.write,\n              allocate: MEMFS.stream_ops.allocate,\n              mmap: MEMFS.stream_ops.mmap,\n              msync: MEMFS.stream_ops.msync,\n            },\n          },\n          link: {\n            node: {\n              getattr: MEMFS.node_ops.getattr,\n              setattr: MEMFS.node_ops.setattr,\n              readlink: MEMFS.node_ops.readlink,\n            },\n            stream: {},\n          },\n          chrdev: {\n            node: { getattr: MEMFS.node_ops.getattr, setattr: MEMFS.node_ops.setattr },\n            stream: FS.chrdev_stream_ops,\n          },\n        };\n      }\n      var node = FS.createNode(parent, name, mode, dev);\n      if (FS.isDir(node.mode)) {\n        node.node_ops = MEMFS.ops_table.dir.node;\n        node.stream_ops = MEMFS.ops_table.dir.stream;\n        node.contents = {};\n      } else if (FS.isFile(node.mode)) {\n        node.node_ops = MEMFS.ops_table.file.node;\n        node.stream_ops = MEMFS.ops_table.file.stream;\n        node.usedBytes = 0;\n        node.contents = null;\n      } else if (FS.isLink(node.mode)) {\n        node.node_ops = MEMFS.ops_table.link.node;\n        node.stream_ops = MEMFS.ops_table.link.stream;\n      } else if (FS.isChrdev(node.mode)) {\n        node.node_ops = MEMFS.ops_table.chrdev.node;\n        node.stream_ops = MEMFS.ops_table.chrdev.stream;\n      }\n      node.timestamp = Date.now();\n      if (parent) {\n        parent.contents[name] = node;\n      }\n      return node\n    },\n    getFileDataAsRegularArray: function (node) {\n      if (node.contents && node.contents.subarray) {\n        var arr = [];\n        for (var i = 0; i < node.usedBytes; ++i) arr.push(node.contents[i]);\n        return arr\n      }\n      return node.contents\n    },\n    getFileDataAsTypedArray: function (node) {\n      if (!node.contents) return new Uint8Array()\n      if (node.contents.subarray) return node.contents.subarray(0, node.usedBytes)\n      return new Uint8Array(node.contents)\n    },\n    expandFileStorage: function (node, newCapacity) {\n      if (node.contents && node.contents.subarray && newCapacity > node.contents.length) {\n        node.contents = MEMFS.getFileDataAsRegularArray(node);\n        node.usedBytes = node.contents.length;\n      }\n      if (!node.contents || node.contents.subarray) {\n        var prevCapacity = node.contents ? node.contents.length : 0;\n        if (prevCapacity >= newCapacity) return\n        var CAPACITY_DOUBLING_MAX = 1024 * 1024;\n        newCapacity = Math.max(newCapacity, (prevCapacity * (prevCapacity < CAPACITY_DOUBLING_MAX ? 2 : 1.125)) | 0);\n        if (prevCapacity != 0) newCapacity = Math.max(newCapacity, 256);\n        var oldContents = node.contents;\n        node.contents = new Uint8Array(newCapacity);\n        if (node.usedBytes > 0) node.contents.set(oldContents.subarray(0, node.usedBytes), 0);\n        return\n      }\n      if (!node.contents && newCapacity > 0) node.contents = [];\n      while (node.contents.length < newCapacity) node.contents.push(0);\n    },\n    resizeFileStorage: function (node, newSize) {\n      if (node.usedBytes == newSize) return\n      if (newSize == 0) {\n        node.contents = null;\n        node.usedBytes = 0;\n        return\n      }\n      if (!node.contents || node.contents.subarray) {\n        var oldContents = node.contents;\n        node.contents = new Uint8Array(new ArrayBuffer(newSize));\n        if (oldContents) {\n          node.contents.set(oldContents.subarray(0, Math.min(newSize, node.usedBytes)));\n        }\n        node.usedBytes = newSize;\n        return\n      }\n      if (!node.contents) node.contents = [];\n      if (node.contents.length > newSize) node.contents.length = newSize;\n      else while (node.contents.length < newSize) node.contents.push(0);\n      node.usedBytes = newSize;\n    },\n    node_ops: {\n      getattr: function (node) {\n        var attr = {};\n        attr.dev = FS.isChrdev(node.mode) ? node.id : 1;\n        attr.ino = node.id;\n        attr.mode = node.mode;\n        attr.nlink = 1;\n        attr.uid = 0;\n        attr.gid = 0;\n        attr.rdev = node.rdev;\n        if (FS.isDir(node.mode)) {\n          attr.size = 4096;\n        } else if (FS.isFile(node.mode)) {\n          attr.size = node.usedBytes;\n        } else if (FS.isLink(node.mode)) {\n          attr.size = node.link.length;\n        } else {\n          attr.size = 0;\n        }\n        attr.atime = new Date(node.timestamp);\n        attr.mtime = new Date(node.timestamp);\n        attr.ctime = new Date(node.timestamp);\n        attr.blksize = 4096;\n        attr.blocks = Math.ceil(attr.size / attr.blksize);\n        return attr\n      },\n      setattr: function (node, attr) {\n        if (attr.mode !== undefined) {\n          node.mode = attr.mode;\n        }\n        if (attr.timestamp !== undefined) {\n          node.timestamp = attr.timestamp;\n        }\n        if (attr.size !== undefined) {\n          MEMFS.resizeFileStorage(node, attr.size);\n        }\n      },\n      lookup: function (parent, name) {\n        throw FS.genericErrors[ERRNO_CODES.ENOENT]\n      },\n      mknod: function (parent, name, mode, dev) {\n        return MEMFS.createNode(parent, name, mode, dev)\n      },\n      rename: function (old_node, new_dir, new_name) {\n        if (FS.isDir(old_node.mode)) {\n          var new_node;\n          try {\n            new_node = FS.lookupNode(new_dir, new_name);\n          } catch (e) {}\n          if (new_node) {\n            for (var i in new_node.contents) {\n              throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY)\n            }\n          }\n        }\n        delete old_node.parent.contents[old_node.name];\n        old_node.name = new_name;\n        new_dir.contents[new_name] = old_node;\n        old_node.parent = new_dir;\n      },\n      unlink: function (parent, name) {\n        delete parent.contents[name];\n      },\n      rmdir: function (parent, name) {\n        var node = FS.lookupNode(parent, name);\n        for (var i in node.contents) {\n          throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY)\n        }\n        delete parent.contents[name];\n      },\n      readdir: function (node) {\n        var entries = ['.', '..'];\n        for (var key in node.contents) {\n          if (!node.contents.hasOwnProperty(key)) {\n            continue\n          }\n          entries.push(key);\n        }\n        return entries\n      },\n      symlink: function (parent, newname, oldpath) {\n        var node = MEMFS.createNode(parent, newname, 511 | 40960, 0);\n        node.link = oldpath;\n        return node\n      },\n      readlink: function (node) {\n        if (!FS.isLink(node.mode)) {\n          throw new FS.ErrnoError(ERRNO_CODES.EINVAL)\n        }\n        return node.link\n      },\n    },\n    stream_ops: {\n      read: function (stream, buffer, offset, length, position) {\n        var contents = stream.node.contents;\n        if (position >= stream.node.usedBytes) return 0\n        var size = Math.min(stream.node.usedBytes - position, length);\n        assert(size >= 0);\n        if (size > 8 && contents.subarray) {\n          buffer.set(contents.subarray(position, position + size), offset);\n        } else {\n          for (var i = 0; i < size; i++) buffer[offset + i] = contents[position + i];\n        }\n        return size\n      },\n      write: function (stream, buffer, offset, length, position, canOwn) {\n        if (!length) return 0\n        var node = stream.node;\n        node.timestamp = Date.now();\n        if (buffer.subarray && (!node.contents || node.contents.subarray)) {\n          if (canOwn) {\n            node.contents = buffer.subarray(offset, offset + length);\n            node.usedBytes = length;\n            return length\n          } else if (node.usedBytes === 0 && position === 0) {\n            node.contents = new Uint8Array(buffer.subarray(offset, offset + length));\n            node.usedBytes = length;\n            return length\n          } else if (position + length <= node.usedBytes) {\n            node.contents.set(buffer.subarray(offset, offset + length), position);\n            return length\n          }\n        }\n        MEMFS.expandFileStorage(node, position + length);\n        if (node.contents.subarray && buffer.subarray)\n          node.contents.set(buffer.subarray(offset, offset + length), position);\n        else {\n          for (var i = 0; i < length; i++) {\n            node.contents[position + i] = buffer[offset + i];\n          }\n        }\n        node.usedBytes = Math.max(node.usedBytes, position + length);\n        return length\n      },\n      llseek: function (stream, offset, whence) {\n        var position = offset;\n        if (whence === 1) {\n          position += stream.position;\n        } else if (whence === 2) {\n          if (FS.isFile(stream.node.mode)) {\n            position += stream.node.usedBytes;\n          }\n        }\n        if (position < 0) {\n          throw new FS.ErrnoError(ERRNO_CODES.EINVAL)\n        }\n        return position\n      },\n      allocate: function (stream, offset, length) {\n        MEMFS.expandFileStorage(stream.node, offset + length);\n        stream.node.usedBytes = Math.max(stream.node.usedBytes, offset + length);\n      },\n      mmap: function (stream, buffer, offset, length, position, prot, flags) {\n        if (!FS.isFile(stream.node.mode)) {\n          throw new FS.ErrnoError(ERRNO_CODES.ENODEV)\n        }\n        var ptr;\n        var allocated;\n        var contents = stream.node.contents;\n        if (!(flags & 2) && (contents.buffer === buffer || contents.buffer === buffer.buffer)) {\n          allocated = false;\n          ptr = contents.byteOffset;\n        } else {\n          if (position > 0 || position + length < stream.node.usedBytes) {\n            if (contents.subarray) {\n              contents = contents.subarray(position, position + length);\n            } else {\n              contents = Array.prototype.slice.call(contents, position, position + length);\n            }\n          }\n          allocated = true;\n          ptr = _malloc(length);\n          if (!ptr) {\n            throw new FS.ErrnoError(ERRNO_CODES.ENOMEM)\n          }\n          buffer.set(contents, ptr);\n        }\n        return { ptr: ptr, allocated: allocated }\n      },\n      msync: function (stream, buffer, offset, length, mmapFlags) {\n        if (!FS.isFile(stream.node.mode)) {\n          throw new FS.ErrnoError(ERRNO_CODES.ENODEV)\n        }\n        if (mmapFlags & 2) {\n          return 0\n        }\n        MEMFS.stream_ops.write(stream, buffer, 0, length, offset, false);\n        return 0\n      },\n    },\n  };\n  var IDBFS = {\n    dbs: {},\n    indexedDB: function () {\n      if (typeof indexedDB !== 'undefined') return indexedDB\n      var ret = null;\n      if (typeof window === 'object')\n        ret = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;\n      assert(ret, 'IDBFS used, but indexedDB not supported');\n      return ret\n    },\n    DB_VERSION: 21,\n    DB_STORE_NAME: 'FILE_DATA',\n    mount: function (mount) {\n      return MEMFS.mount.apply(null, arguments)\n    },\n    syncfs: function (mount, populate, callback) {\n      IDBFS.getLocalSet(mount, function (err, local) {\n        if (err) return callback(err)\n        IDBFS.getRemoteSet(mount, function (err, remote) {\n          if (err) return callback(err)\n          var src = populate ? remote : local;\n          var dst = populate ? local : remote;\n          IDBFS.reconcile(src, dst, callback);\n        });\n      });\n    },\n    getDB: function (name, callback) {\n      var db = IDBFS.dbs[name];\n      if (db) {\n        return callback(null, db)\n      }\n      var req;\n      try {\n        req = IDBFS.indexedDB().open(name, IDBFS.DB_VERSION);\n      } catch (e) {\n        return callback(e)\n      }\n      if (!req) {\n        return callback('Unable to connect to IndexedDB')\n      }\n      req.onupgradeneeded = function (e) {\n        var db = e.target.result;\n        var transaction = e.target.transaction;\n        var fileStore;\n        if (db.objectStoreNames.contains(IDBFS.DB_STORE_NAME)) {\n          fileStore = transaction.objectStore(IDBFS.DB_STORE_NAME);\n        } else {\n          fileStore = db.createObjectStore(IDBFS.DB_STORE_NAME);\n        }\n        if (!fileStore.indexNames.contains('timestamp')) {\n          fileStore.createIndex('timestamp', 'timestamp', { unique: false });\n        }\n      };\n      req.onsuccess = function () {\n        db = req.result;\n        IDBFS.dbs[name] = db;\n        callback(null, db);\n      };\n      req.onerror = function (e) {\n        callback(this.error);\n        e.preventDefault();\n      };\n    },\n    getLocalSet: function (mount, callback) {\n      var entries = {};\n      function isRealDir(p) {\n        return p !== '.' && p !== '..'\n      }\n      function toAbsolute(root) {\n        return function (p) {\n          return PATH.join2(root, p)\n        }\n      }\n      var check = FS.readdir(mount.mountpoint).filter(isRealDir).map(toAbsolute(mount.mountpoint));\n      while (check.length) {\n        var path = check.pop();\n        var stat;\n        try {\n          stat = FS.stat(path);\n        } catch (e) {\n          return callback(e)\n        }\n        if (FS.isDir(stat.mode)) {\n          check.push.apply(check, FS.readdir(path).filter(isRealDir).map(toAbsolute(path)));\n        }\n        entries[path] = { timestamp: stat.mtime };\n      }\n      return callback(null, { type: 'local', entries: entries })\n    },\n    getRemoteSet: function (mount, callback) {\n      var entries = {};\n      IDBFS.getDB(mount.mountpoint, function (err, db) {\n        if (err) return callback(err)\n        try {\n          var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readonly');\n          transaction.onerror = function (e) {\n            callback(this.error);\n            e.preventDefault();\n          };\n          var store = transaction.objectStore(IDBFS.DB_STORE_NAME);\n          var index = store.index('timestamp');\n          index.openKeyCursor().onsuccess = function (event) {\n            var cursor = event.target.result;\n            if (!cursor) {\n              return callback(null, { type: 'remote', db: db, entries: entries })\n            }\n            entries[cursor.primaryKey] = { timestamp: cursor.key };\n            cursor.continue();\n          };\n        } catch (e) {\n          return callback(e)\n        }\n      });\n    },\n    loadLocalEntry: function (path, callback) {\n      var stat, node;\n      try {\n        var lookup = FS.lookupPath(path);\n        node = lookup.node;\n        stat = FS.stat(path);\n      } catch (e) {\n        return callback(e)\n      }\n      if (FS.isDir(stat.mode)) {\n        return callback(null, { timestamp: stat.mtime, mode: stat.mode })\n      } else if (FS.isFile(stat.mode)) {\n        node.contents = MEMFS.getFileDataAsTypedArray(node);\n        return callback(null, { timestamp: stat.mtime, mode: stat.mode, contents: node.contents })\n      } else {\n        return callback(new Error('node type not supported'))\n      }\n    },\n    storeLocalEntry: function (path, entry, callback) {\n      try {\n        if (FS.isDir(entry.mode)) {\n          FS.mkdir(path, entry.mode);\n        } else if (FS.isFile(entry.mode)) {\n          FS.writeFile(path, entry.contents, { canOwn: true });\n        } else {\n          return callback(new Error('node type not supported'))\n        }\n        FS.chmod(path, entry.mode);\n        FS.utime(path, entry.timestamp, entry.timestamp);\n      } catch (e) {\n        return callback(e)\n      }\n      callback(null);\n    },\n    removeLocalEntry: function (path, callback) {\n      try {\n        var lookup = FS.lookupPath(path);\n        var stat = FS.stat(path);\n        if (FS.isDir(stat.mode)) {\n          FS.rmdir(path);\n        } else if (FS.isFile(stat.mode)) {\n          FS.unlink(path);\n        }\n      } catch (e) {\n        return callback(e)\n      }\n      callback(null);\n    },\n    loadRemoteEntry: function (store, path, callback) {\n      var req = store.get(path);\n      req.onsuccess = function (event) {\n        callback(null, event.target.result);\n      };\n      req.onerror = function (e) {\n        callback(this.error);\n        e.preventDefault();\n      };\n    },\n    storeRemoteEntry: function (store, path, entry, callback) {\n      var req = store.put(entry, path);\n      req.onsuccess = function () {\n        callback(null);\n      };\n      req.onerror = function (e) {\n        callback(this.error);\n        e.preventDefault();\n      };\n    },\n    removeRemoteEntry: function (store, path, callback) {\n      var req = store.delete(path);\n      req.onsuccess = function () {\n        callback(null);\n      };\n      req.onerror = function (e) {\n        callback(this.error);\n        e.preventDefault();\n      };\n    },\n    reconcile: function (src, dst, callback) {\n      var total = 0;\n      var create = [];\n      Object.keys(src.entries).forEach(function (key) {\n        var e = src.entries[key];\n        var e2 = dst.entries[key];\n        if (!e2 || e.timestamp > e2.timestamp) {\n          create.push(key);\n          total++;\n        }\n      });\n      var remove = [];\n      Object.keys(dst.entries).forEach(function (key) {\n        dst.entries[key];\n        var e2 = src.entries[key];\n        if (!e2) {\n          remove.push(key);\n          total++;\n        }\n      });\n      if (!total) {\n        return callback(null)\n      }\n      var completed = 0;\n      var db = src.type === 'remote' ? src.db : dst.db;\n      var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readwrite');\n      var store = transaction.objectStore(IDBFS.DB_STORE_NAME);\n      function done(err) {\n        if (err) {\n          if (!done.errored) {\n            done.errored = true;\n            return callback(err)\n          }\n          return\n        }\n        if (++completed >= total) {\n          return callback(null)\n        }\n      }\n      transaction.onerror = function (e) {\n        done(this.error);\n        e.preventDefault();\n      };\n      create.sort().forEach(function (path) {\n        if (dst.type === 'local') {\n          IDBFS.loadRemoteEntry(store, path, function (err, entry) {\n            if (err) return done(err)\n            IDBFS.storeLocalEntry(path, entry, done);\n          });\n        } else {\n          IDBFS.loadLocalEntry(path, function (err, entry) {\n            if (err) return done(err)\n            IDBFS.storeRemoteEntry(store, path, entry, done);\n          });\n        }\n      });\n      remove\n        .sort()\n        .reverse()\n        .forEach(function (path) {\n          if (dst.type === 'local') {\n            IDBFS.removeLocalEntry(path, done);\n          } else {\n            IDBFS.removeRemoteEntry(store, path, done);\n          }\n        });\n    },\n  };\n  var NODEFS = {\n    isWindows: false,\n    staticInit: function () {\n      NODEFS.isWindows = !!process.platform.match(/^win/);\n      var flags = process['binding']('constants');\n      if (flags['fs']) {\n        flags = flags['fs'];\n      }\n      NODEFS.flagsForNodeMap = {\n        1024: flags['O_APPEND'],\n        64: flags['O_CREAT'],\n        128: flags['O_EXCL'],\n        0: flags['O_RDONLY'],\n        2: flags['O_RDWR'],\n        4096: flags['O_SYNC'],\n        512: flags['O_TRUNC'],\n        1: flags['O_WRONLY'],\n      };\n    },\n    bufferFrom: function (arrayBuffer) {\n      return Buffer.alloc ? Buffer.from(arrayBuffer) : new Buffer(arrayBuffer)\n    },\n    mount: function (mount) {\n      assert(ENVIRONMENT_IS_NODE);\n      return NODEFS.createNode(null, '/', NODEFS.getMode(mount.opts.root), 0)\n    },\n    createNode: function (parent, name, mode, dev) {\n      if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) {\n        throw new FS.ErrnoError(ERRNO_CODES.EINVAL)\n      }\n      var node = FS.createNode(parent, name, mode);\n      node.node_ops = NODEFS.node_ops;\n      node.stream_ops = NODEFS.stream_ops;\n      return node\n    },\n    getMode: function (path) {\n      var stat;\n      try {\n        stat = fs.lstatSync(path);\n        if (NODEFS.isWindows) {\n          stat.mode = stat.mode | ((stat.mode & 292) >> 2);\n        }\n      } catch (e) {\n        if (!e.code) throw e\n        throw new FS.ErrnoError(ERRNO_CODES[e.code])\n      }\n      return stat.mode\n    },\n    realPath: function (node) {\n      var parts = [];\n      while (node.parent !== node) {\n        parts.push(node.name);\n        node = node.parent;\n      }\n      parts.push(node.mount.opts.root);\n      parts.reverse();\n      return PATH.join.apply(null, parts)\n    },\n    flagsForNode: function (flags) {\n      flags &= ~2097152;\n      flags &= ~2048;\n      flags &= ~32768;\n      flags &= ~524288;\n      var newFlags = 0;\n      for (var k in NODEFS.flagsForNodeMap) {\n        if (flags & k) {\n          newFlags |= NODEFS.flagsForNodeMap[k];\n          flags ^= k;\n        }\n      }\n      if (!flags) {\n        return newFlags\n      } else {\n        throw new FS.ErrnoError(ERRNO_CODES.EINVAL)\n      }\n    },\n    node_ops: {\n      getattr: function (node) {\n        var path = NODEFS.realPath(node);\n        var stat;\n        try {\n          stat = fs.lstatSync(path);\n        } catch (e) {\n          if (!e.code) throw e\n          throw new FS.ErrnoError(ERRNO_CODES[e.code])\n        }\n        if (NODEFS.isWindows && !stat.blksize) {\n          stat.blksize = 4096;\n        }\n        if (NODEFS.isWindows && !stat.blocks) {\n          stat.blocks = ((stat.size + stat.blksize - 1) / stat.blksize) | 0;\n        }\n        return {\n          dev: stat.dev,\n          ino: stat.ino,\n          mode: stat.mode,\n          nlink: stat.nlink,\n          uid: stat.uid,\n          gid: stat.gid,\n          rdev: stat.rdev,\n          size: stat.size,\n          atime: stat.atime,\n          mtime: stat.mtime,\n          ctime: stat.ctime,\n          blksize: stat.blksize,\n          blocks: stat.blocks,\n        }\n      },\n      setattr: function (node, attr) {\n        var path = NODEFS.realPath(node);\n        try {\n          if (attr.mode !== undefined) {\n            fs.chmodSync(path, attr.mode);\n            node.mode = attr.mode;\n          }\n          if (attr.timestamp !== undefined) {\n            var date = new Date(attr.timestamp);\n            fs.utimesSync(path, date, date);\n          }\n          if (attr.size !== undefined) {\n            fs.truncateSync(path, attr.size);\n          }\n        } catch (e) {\n          if (!e.code) throw e\n          throw new FS.ErrnoError(ERRNO_CODES[e.code])\n        }\n      },\n      lookup: function (parent, name) {\n        var path = PATH.join2(NODEFS.realPath(parent), name);\n        var mode = NODEFS.getMode(path);\n        return NODEFS.createNode(parent, name, mode)\n      },\n      mknod: function (parent, name, mode, dev) {\n        var node = NODEFS.createNode(parent, name, mode, dev);\n        var path = NODEFS.realPath(node);\n        try {\n          if (FS.isDir(node.mode)) {\n            fs.mkdirSync(path, node.mode);\n          } else {\n            fs.writeFileSync(path, '', { mode: node.mode });\n          }\n        } catch (e) {\n          if (!e.code) throw e\n          throw new FS.ErrnoError(ERRNO_CODES[e.code])\n        }\n        return node\n      },\n      rename: function (oldNode, newDir, newName) {\n        var oldPath = NODEFS.realPath(oldNode);\n        var newPath = PATH.join2(NODEFS.realPath(newDir), newName);\n        try {\n          fs.renameSync(oldPath, newPath);\n        } catch (e) {\n          if (!e.code) throw e\n          throw new FS.ErrnoError(ERRNO_CODES[e.code])\n        }\n      },\n      unlink: function (parent, name) {\n        var path = PATH.join2(NODEFS.realPath(parent), name);\n        try {\n          fs.unlinkSync(path);\n        } catch (e) {\n          if (!e.code) throw e\n          throw new FS.ErrnoError(ERRNO_CODES[e.code])\n        }\n      },\n      rmdir: function (parent, name) {\n        var path = PATH.join2(NODEFS.realPath(parent), name);\n        try {\n          fs.rmdirSync(path);\n        } catch (e) {\n          if (!e.code) throw e\n          throw new FS.ErrnoError(ERRNO_CODES[e.code])\n        }\n      },\n      readdir: function (node) {\n        var path = NODEFS.realPath(node);\n        try {\n          return fs.readdirSync(path)\n        } catch (e) {\n          if (!e.code) throw e\n          throw new FS.ErrnoError(ERRNO_CODES[e.code])\n        }\n      },\n      symlink: function (parent, newName, oldPath) {\n        var newPath = PATH.join2(NODEFS.realPath(parent), newName);\n        try {\n          fs.symlinkSync(oldPath, newPath);\n        } catch (e) {\n          if (!e.code) throw e\n          throw new FS.ErrnoError(ERRNO_CODES[e.code])\n        }\n      },\n      readlink: function (node) {\n        var path = NODEFS.realPath(node);\n        try {\n          path = fs.readlinkSync(path);\n          path = NODEJS_PATH.relative(NODEJS_PATH.resolve(node.mount.opts.root), path);\n          return path\n        } catch (e) {\n          if (!e.code) throw e\n          throw new FS.ErrnoError(ERRNO_CODES[e.code])\n        }\n      },\n    },\n    stream_ops: {\n      open: function (stream) {\n        var path = NODEFS.realPath(stream.node);\n        try {\n          if (FS.isFile(stream.node.mode)) {\n            stream.nfd = fs.openSync(path, NODEFS.flagsForNode(stream.flags));\n          }\n        } catch (e) {\n          if (!e.code) throw e\n          throw new FS.ErrnoError(ERRNO_CODES[e.code])\n        }\n      },\n      close: function (stream) {\n        try {\n          if (FS.isFile(stream.node.mode) && stream.nfd) {\n            fs.closeSync(stream.nfd);\n          }\n        } catch (e) {\n          if (!e.code) throw e\n          throw new FS.ErrnoError(ERRNO_CODES[e.code])\n        }\n      },\n      read: function (stream, buffer, offset, length, position) {\n        if (length === 0) return 0\n        try {\n          return fs.readSync(stream.nfd, NODEFS.bufferFrom(buffer.buffer), offset, length, position)\n        } catch (e) {\n          throw new FS.ErrnoError(ERRNO_CODES[e.code])\n        }\n      },\n      write: function (stream, buffer, offset, length, position) {\n        try {\n          return fs.writeSync(stream.nfd, NODEFS.bufferFrom(buffer.buffer), offset, length, position)\n        } catch (e) {\n          throw new FS.ErrnoError(ERRNO_CODES[e.code])\n        }\n      },\n      llseek: function (stream, offset, whence) {\n        var position = offset;\n        if (whence === 1) {\n          position += stream.position;\n        } else if (whence === 2) {\n          if (FS.isFile(stream.node.mode)) {\n            try {\n              var stat = fs.fstatSync(stream.nfd);\n              position += stat.size;\n            } catch (e) {\n              throw new FS.ErrnoError(ERRNO_CODES[e.code])\n            }\n          }\n        }\n        if (position < 0) {\n          throw new FS.ErrnoError(ERRNO_CODES.EINVAL)\n        }\n        return position\n      },\n    },\n  };\n  var WORKERFS = {\n    DIR_MODE: 16895,\n    FILE_MODE: 33279,\n    reader: null,\n    mount: function (mount) {\n      assert(ENVIRONMENT_IS_WORKER);\n      if (!WORKERFS.reader) WORKERFS.reader = new FileReaderSync();\n      var root = WORKERFS.createNode(null, '/', WORKERFS.DIR_MODE, 0);\n      var createdParents = {};\n      function ensureParent(path) {\n        var parts = path.split('/');\n        var parent = root;\n        for (var i = 0; i < parts.length - 1; i++) {\n          var curr = parts.slice(0, i + 1).join('/');\n          if (!createdParents[curr]) {\n            createdParents[curr] = WORKERFS.createNode(parent, parts[i], WORKERFS.DIR_MODE, 0);\n          }\n          parent = createdParents[curr];\n        }\n        return parent\n      }\n      function base(path) {\n        var parts = path.split('/');\n        return parts[parts.length - 1]\n      }\n      Array.prototype.forEach.call(mount.opts['files'] || [], function (file) {\n        WORKERFS.createNode(\n          ensureParent(file.name),\n          base(file.name),\n          WORKERFS.FILE_MODE,\n          0,\n          file,\n          file.lastModifiedDate\n        );\n      })\n      ;(mount.opts['blobs'] || []).forEach(function (obj) {\n        WORKERFS.createNode(ensureParent(obj['name']), base(obj['name']), WORKERFS.FILE_MODE, 0, obj['data']);\n      })\n      ;(mount.opts['packages'] || []).forEach(function (pack) {\n        pack['metadata'].files.forEach(function (file) {\n          var name = file.filename.substr(1);\n          WORKERFS.createNode(\n            ensureParent(name),\n            base(name),\n            WORKERFS.FILE_MODE,\n            0,\n            pack['blob'].slice(file.start, file.end)\n          );\n        });\n      });\n      return root\n    },\n    createNode: function (parent, name, mode, dev, contents, mtime) {\n      var node = FS.createNode(parent, name, mode);\n      node.mode = mode;\n      node.node_ops = WORKERFS.node_ops;\n      node.stream_ops = WORKERFS.stream_ops;\n      node.timestamp = (mtime || new Date()).getTime();\n      assert(WORKERFS.FILE_MODE !== WORKERFS.DIR_MODE);\n      if (mode === WORKERFS.FILE_MODE) {\n        node.size = contents.size;\n        node.contents = contents;\n      } else {\n        node.size = 4096;\n        node.contents = {};\n      }\n      if (parent) {\n        parent.contents[name] = node;\n      }\n      return node\n    },\n    node_ops: {\n      getattr: function (node) {\n        return {\n          dev: 1,\n          ino: undefined,\n          mode: node.mode,\n          nlink: 1,\n          uid: 0,\n          gid: 0,\n          rdev: undefined,\n          size: node.size,\n          atime: new Date(node.timestamp),\n          mtime: new Date(node.timestamp),\n          ctime: new Date(node.timestamp),\n          blksize: 4096,\n          blocks: Math.ceil(node.size / 4096),\n        }\n      },\n      setattr: function (node, attr) {\n        if (attr.mode !== undefined) {\n          node.mode = attr.mode;\n        }\n        if (attr.timestamp !== undefined) {\n          node.timestamp = attr.timestamp;\n        }\n      },\n      lookup: function (parent, name) {\n        throw new FS.ErrnoError(ERRNO_CODES.ENOENT)\n      },\n      mknod: function (parent, name, mode, dev) {\n        throw new FS.ErrnoError(ERRNO_CODES.EPERM)\n      },\n      rename: function (oldNode, newDir, newName) {\n        throw new FS.ErrnoError(ERRNO_CODES.EPERM)\n      },\n      unlink: function (parent, name) {\n        throw new FS.ErrnoError(ERRNO_CODES.EPERM)\n      },\n      rmdir: function (parent, name) {\n        throw new FS.ErrnoError(ERRNO_CODES.EPERM)\n      },\n      readdir: function (node) {\n        var entries = ['.', '..'];\n        for (var key in node.contents) {\n          if (!node.contents.hasOwnProperty(key)) {\n            continue\n          }\n          entries.push(key);\n        }\n        return entries\n      },\n      symlink: function (parent, newName, oldPath) {\n        throw new FS.ErrnoError(ERRNO_CODES.EPERM)\n      },\n      readlink: function (node) {\n        throw new FS.ErrnoError(ERRNO_CODES.EPERM)\n      },\n    },\n    stream_ops: {\n      read: function (stream, buffer, offset, length, position) {\n        if (position >= stream.node.size) return 0\n        var chunk = stream.node.contents.slice(position, position + length);\n        var ab = WORKERFS.reader.readAsArrayBuffer(chunk);\n        buffer.set(new Uint8Array(ab), offset);\n        return chunk.size\n      },\n      write: function (stream, buffer, offset, length, position) {\n        throw new FS.ErrnoError(ERRNO_CODES.EIO)\n      },\n      llseek: function (stream, offset, whence) {\n        var position = offset;\n        if (whence === 1) {\n          position += stream.position;\n        } else if (whence === 2) {\n          if (FS.isFile(stream.node.mode)) {\n            position += stream.node.size;\n          }\n        }\n        if (position < 0) {\n          throw new FS.ErrnoError(ERRNO_CODES.EINVAL)\n        }\n        return position\n      },\n    },\n  };\n  STATICTOP += 16;\n  STATICTOP += 16;\n  STATICTOP += 16;\n  var FS = {\n    root: null,\n    mounts: [],\n    devices: {},\n    streams: [],\n    nextInode: 1,\n    nameTable: null,\n    currentPath: '/',\n    initialized: false,\n    ignorePermissions: true,\n    trackingDelegate: {},\n    tracking: { openFlags: { READ: 1, WRITE: 2 } },\n    ErrnoError: null,\n    genericErrors: {},\n    filesystems: null,\n    syncFSRequests: 0,\n    handleFSError: function (e) {\n      if (!(e instanceof FS.ErrnoError)) throw e + ' : ' + stackTrace()\n      return ___setErrNo(e.errno)\n    },\n    lookupPath: function (path, opts) {\n      path = PATH.resolve(FS.cwd(), path);\n      opts = opts || {};\n      if (!path) return { path: '', node: null }\n      var defaults = { follow_mount: true, recurse_count: 0 };\n      for (var key in defaults) {\n        if (opts[key] === undefined) {\n          opts[key] = defaults[key];\n        }\n      }\n      if (opts.recurse_count > 8) {\n        throw new FS.ErrnoError(ERRNO_CODES.ELOOP)\n      }\n      var parts = PATH.normalizeArray(\n        path.split('/').filter(function (p) {\n          return !!p\n        }),\n        false\n      );\n      var current = FS.root;\n      var current_path = '/';\n      for (var i = 0; i < parts.length; i++) {\n        var islast = i === parts.length - 1;\n        if (islast && opts.parent) {\n          break\n        }\n        current = FS.lookupNode(current, parts[i]);\n        current_path = PATH.join2(current_path, parts[i]);\n        if (FS.isMountpoint(current)) {\n          if (!islast || (islast && opts.follow_mount)) {\n            current = current.mounted.root;\n          }\n        }\n        if (!islast || opts.follow) {\n          var count = 0;\n          while (FS.isLink(current.mode)) {\n            var link = FS.readlink(current_path);\n            current_path = PATH.resolve(PATH.dirname(current_path), link);\n            var lookup = FS.lookupPath(current_path, { recurse_count: opts.recurse_count });\n            current = lookup.node;\n            if (count++ > 40) {\n              throw new FS.ErrnoError(ERRNO_CODES.ELOOP)\n            }\n          }\n        }\n      }\n      return { path: current_path, node: current }\n    },\n    getPath: function (node) {\n      var path;\n      while (true) {\n        if (FS.isRoot(node)) {\n          var mount = node.mount.mountpoint;\n          if (!path) return mount\n          return mount[mount.length - 1] !== '/' ? mount + '/' + path : mount + path\n        }\n        path = path ? node.name + '/' + path : node.name;\n        node = node.parent;\n      }\n    },\n    hashName: function (parentid, name) {\n      var hash = 0;\n      for (var i = 0; i < name.length; i++) {\n        hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0;\n      }\n      return ((parentid + hash) >>> 0) % FS.nameTable.length\n    },\n    hashAddNode: function (node) {\n      var hash = FS.hashName(node.parent.id, node.name);\n      node.name_next = FS.nameTable[hash];\n      FS.nameTable[hash] = node;\n    },\n    hashRemoveNode: function (node) {\n      var hash = FS.hashName(node.parent.id, node.name);\n      if (FS.nameTable[hash] === node) {\n        FS.nameTable[hash] = node.name_next;\n      } else {\n        var current = FS.nameTable[hash];\n        while (current) {\n          if (current.name_next === node) {\n            current.name_next = node.name_next;\n            break\n          }\n          current = current.name_next;\n        }\n      }\n    },\n    lookupNode: function (parent, name) {\n      var err = FS.mayLookup(parent);\n      if (err) {\n        throw new FS.ErrnoError(err, parent)\n      }\n      var hash = FS.hashName(parent.id, name);\n      for (var node = FS.nameTable[hash]; node; node = node.name_next) {\n        var nodeName = node.name;\n        if (node.parent.id === parent.id && nodeName === name) {\n          return node\n        }\n      }\n      return FS.lookup(parent, name)\n    },\n    createNode: function (parent, name, mode, rdev) {\n      if (!FS.FSNode) {\n        FS.FSNode = function (parent, name, mode, rdev) {\n          if (!parent) {\n            parent = this;\n          }\n          this.parent = parent;\n          this.mount = parent.mount;\n          this.mounted = null;\n          this.id = FS.nextInode++;\n          this.name = name;\n          this.mode = mode;\n          this.node_ops = {};\n          this.stream_ops = {};\n          this.rdev = rdev;\n        };\n        FS.FSNode.prototype = {};\n        var readMode = 292 | 73;\n        var writeMode = 146;\n        Object.defineProperties(FS.FSNode.prototype, {\n          read: {\n            get: function () {\n              return (this.mode & readMode) === readMode\n            },\n            set: function (val) {\n              val ? (this.mode |= readMode) : (this.mode &= ~readMode);\n            },\n          },\n          write: {\n            get: function () {\n              return (this.mode & writeMode) === writeMode\n            },\n            set: function (val) {\n              val ? (this.mode |= writeMode) : (this.mode &= ~writeMode);\n            },\n          },\n          isFolder: {\n            get: function () {\n              return FS.isDir(this.mode)\n            },\n          },\n          isDevice: {\n            get: function () {\n              return FS.isChrdev(this.mode)\n            },\n          },\n        });\n      }\n      var node = new FS.FSNode(parent, name, mode, rdev);\n      FS.hashAddNode(node);\n      return node\n    },\n    destroyNode: function (node) {\n      FS.hashRemoveNode(node);\n    },\n    isRoot: function (node) {\n      return node === node.parent\n    },\n    isMountpoint: function (node) {\n      return !!node.mounted\n    },\n    isFile: function (mode) {\n      return (mode & 61440) === 32768\n    },\n    isDir: function (mode) {\n      return (mode & 61440) === 16384\n    },\n    isLink: function (mode) {\n      return (mode & 61440) === 40960\n    },\n    isChrdev: function (mode) {\n      return (mode & 61440) === 8192\n    },\n    isBlkdev: function (mode) {\n      return (mode & 61440) === 24576\n    },\n    isFIFO: function (mode) {\n      return (mode & 61440) === 4096\n    },\n    isSocket: function (mode) {\n      return (mode & 49152) === 49152\n    },\n    flagModes: {\n      r: 0,\n      rs: 1052672,\n      'r+': 2,\n      w: 577,\n      wx: 705,\n      xw: 705,\n      'w+': 578,\n      'wx+': 706,\n      'xw+': 706,\n      a: 1089,\n      ax: 1217,\n      xa: 1217,\n      'a+': 1090,\n      'ax+': 1218,\n      'xa+': 1218,\n    },\n    modeStringToFlags: function (str) {\n      var flags = FS.flagModes[str];\n      if (typeof flags === 'undefined') {\n        throw new Error('Unknown file open mode: ' + str)\n      }\n      return flags\n    },\n    flagsToPermissionString: function (flag) {\n      var perms = ['r', 'w', 'rw'][flag & 3];\n      if (flag & 512) {\n        perms += 'w';\n      }\n      return perms\n    },\n    nodePermissions: function (node, perms) {\n      if (FS.ignorePermissions) {\n        return 0\n      }\n      if (perms.indexOf('r') !== -1 && !(node.mode & 292)) {\n        return ERRNO_CODES.EACCES\n      } else if (perms.indexOf('w') !== -1 && !(node.mode & 146)) {\n        return ERRNO_CODES.EACCES\n      } else if (perms.indexOf('x') !== -1 && !(node.mode & 73)) {\n        return ERRNO_CODES.EACCES\n      }\n      return 0\n    },\n    mayLookup: function (dir) {\n      var err = FS.nodePermissions(dir, 'x');\n      if (err) return err\n      if (!dir.node_ops.lookup) return ERRNO_CODES.EACCES\n      return 0\n    },\n    mayCreate: function (dir, name) {\n      try {\n        var node = FS.lookupNode(dir, name);\n        return ERRNO_CODES.EEXIST\n      } catch (e) {}\n      return FS.nodePermissions(dir, 'wx')\n    },\n    mayDelete: function (dir, name, isdir) {\n      var node;\n      try {\n        node = FS.lookupNode(dir, name);\n      } catch (e) {\n        return e.errno\n      }\n      var err = FS.nodePermissions(dir, 'wx');\n      if (err) {\n        return err\n      }\n      if (isdir) {\n        if (!FS.isDir(node.mode)) {\n          return ERRNO_CODES.ENOTDIR\n        }\n        if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) {\n          return ERRNO_CODES.EBUSY\n        }\n      } else {\n        if (FS.isDir(node.mode)) {\n          return ERRNO_CODES.EISDIR\n        }\n      }\n      return 0\n    },\n    mayOpen: function (node, flags) {\n      if (!node) {\n        return ERRNO_CODES.ENOENT\n      }\n      if (FS.isLink(node.mode)) {\n        return ERRNO_CODES.ELOOP\n      } else if (FS.isDir(node.mode)) {\n        if (FS.flagsToPermissionString(flags) !== 'r' || flags & 512) {\n          return ERRNO_CODES.EISDIR\n        }\n      }\n      return FS.nodePermissions(node, FS.flagsToPermissionString(flags))\n    },\n    MAX_OPEN_FDS: 4096,\n    nextfd: function (fd_start, fd_end) {\n      fd_start = fd_start || 0;\n      fd_end = fd_end || FS.MAX_OPEN_FDS;\n      for (var fd = fd_start; fd <= fd_end; fd++) {\n        if (!FS.streams[fd]) {\n          return fd\n        }\n      }\n      throw new FS.ErrnoError(ERRNO_CODES.EMFILE)\n    },\n    getStream: function (fd) {\n      return FS.streams[fd]\n    },\n    createStream: function (stream, fd_start, fd_end) {\n      if (!FS.FSStream) {\n        FS.FSStream = function () {};\n        FS.FSStream.prototype = {};\n        Object.defineProperties(FS.FSStream.prototype, {\n          object: {\n            get: function () {\n              return this.node\n            },\n            set: function (val) {\n              this.node = val;\n            },\n          },\n          isRead: {\n            get: function () {\n              return (this.flags & 2097155) !== 1\n            },\n          },\n          isWrite: {\n            get: function () {\n              return (this.flags & 2097155) !== 0\n            },\n          },\n          isAppend: {\n            get: function () {\n              return this.flags & 1024\n            },\n          },\n        });\n      }\n      var newStream = new FS.FSStream();\n      for (var p in stream) {\n        newStream[p] = stream[p];\n      }\n      stream = newStream;\n      var fd = FS.nextfd(fd_start, fd_end);\n      stream.fd = fd;\n      FS.streams[fd] = stream;\n      return stream\n    },\n    closeStream: function (fd) {\n      FS.streams[fd] = null;\n    },\n    chrdev_stream_ops: {\n      open: function (stream) {\n        var device = FS.getDevice(stream.node.rdev);\n        stream.stream_ops = device.stream_ops;\n        if (stream.stream_ops.open) {\n          stream.stream_ops.open(stream);\n        }\n      },\n      llseek: function () {\n        throw new FS.ErrnoError(ERRNO_CODES.ESPIPE)\n      },\n    },\n    major: function (dev) {\n      return dev >> 8\n    },\n    minor: function (dev) {\n      return dev & 255\n    },\n    makedev: function (ma, mi) {\n      return (ma << 8) | mi\n    },\n    registerDevice: function (dev, ops) {\n      FS.devices[dev] = { stream_ops: ops };\n    },\n    getDevice: function (dev) {\n      return FS.devices[dev]\n    },\n    getMounts: function (mount) {\n      var mounts = [];\n      var check = [mount];\n      while (check.length) {\n        var m = check.pop();\n        mounts.push(m);\n        check.push.apply(check, m.mounts);\n      }\n      return mounts\n    },\n    syncfs: function (populate, callback) {\n      if (typeof populate === 'function') {\n        callback = populate;\n        populate = false;\n      }\n      FS.syncFSRequests++;\n      if (FS.syncFSRequests > 1) {\n        console.log(\n          'warning: ' + FS.syncFSRequests + ' FS.syncfs operations in flight at once, probably just doing extra work'\n        );\n      }\n      var mounts = FS.getMounts(FS.root.mount);\n      var completed = 0;\n      function doCallback(err) {\n        assert(FS.syncFSRequests > 0);\n        FS.syncFSRequests--;\n        return callback(err)\n      }\n      function done(err) {\n        if (err) {\n          if (!done.errored) {\n            done.errored = true;\n            return doCallback(err)\n          }\n          return\n        }\n        if (++completed >= mounts.length) {\n          doCallback(null);\n        }\n      }\n      mounts.forEach(function (mount) {\n        if (!mount.type.syncfs) {\n          return done(null)\n        }\n        mount.type.syncfs(mount, populate, done);\n      });\n    },\n    mount: function (type, opts, mountpoint) {\n      var root = mountpoint === '/';\n      var pseudo = !mountpoint;\n      var node;\n      if (root && FS.root) {\n        throw new FS.ErrnoError(ERRNO_CODES.EBUSY)\n      } else if (!root && !pseudo) {\n        var lookup = FS.lookupPath(mountpoint, { follow_mount: false });\n        mountpoint = lookup.path;\n        node = lookup.node;\n        if (FS.isMountpoint(node)) {\n          throw new FS.ErrnoError(ERRNO_CODES.EBUSY)\n        }\n        if (!FS.isDir(node.mode)) {\n          throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR)\n        }\n      }\n      var mount = { type: type, opts: opts, mountpoint: mountpoint, mounts: [] };\n      var mountRoot = type.mount(mount);\n      mountRoot.mount = mount;\n      mount.root = mountRoot;\n      if (root) {\n        FS.root = mountRoot;\n      } else if (node) {\n        node.mounted = mount;\n        if (node.mount) {\n          node.mount.mounts.push(mount);\n        }\n      }\n      return mountRoot\n    },\n    unmount: function (mountpoint) {\n      var lookup = FS.lookupPath(mountpoint, { follow_mount: false });\n      if (!FS.isMountpoint(lookup.node)) {\n        throw new FS.ErrnoError(ERRNO_CODES.EINVAL)\n      }\n      var node = lookup.node;\n      var mount = node.mounted;\n      var mounts = FS.getMounts(mount);\n      Object.keys(FS.nameTable).forEach(function (hash) {\n        var current = FS.nameTable[hash];\n        while (current) {\n          var next = current.name_next;\n          if (mounts.indexOf(current.mount) !== -1) {\n            FS.destroyNode(current);\n          }\n          current = next;\n        }\n      });\n      node.mounted = null;\n      var idx = node.mount.mounts.indexOf(mount);\n      assert(idx !== -1);\n      node.mount.mounts.splice(idx, 1);\n    },\n    lookup: function (parent, name) {\n      return parent.node_ops.lookup(parent, name)\n    },\n    mknod: function (path, mode, dev) {\n      var lookup = FS.lookupPath(path, { parent: true });\n      var parent = lookup.node;\n      var name = PATH.basename(path);\n      if (!name || name === '.' || name === '..') {\n        throw new FS.ErrnoError(ERRNO_CODES.EINVAL)\n      }\n      var err = FS.mayCreate(parent, name);\n      if (err) {\n        throw new FS.ErrnoError(err)\n      }\n      if (!parent.node_ops.mknod) {\n        throw new FS.ErrnoError(ERRNO_CODES.EPERM)\n      }\n      return parent.node_ops.mknod(parent, name, mode, dev)\n    },\n    create: function (path, mode) {\n      mode = mode !== undefined ? mode : 438;\n      mode &= 4095;\n      mode |= 32768;\n      return FS.mknod(path, mode, 0)\n    },\n    mkdir: function (path, mode) {\n      mode = mode !== undefined ? mode : 511;\n      mode &= 511 | 512;\n      mode |= 16384;\n      return FS.mknod(path, mode, 0)\n    },\n    mkdirTree: function (path, mode) {\n      var dirs = path.split('/');\n      var d = '';\n      for (var i = 0; i < dirs.length; ++i) {\n        if (!dirs[i]) continue\n        d += '/' + dirs[i];\n        try {\n          FS.mkdir(d, mode);\n        } catch (e) {\n          if (e.errno != ERRNO_CODES.EEXIST) throw e\n        }\n      }\n    },\n    mkdev: function (path, mode, dev) {\n      if (typeof dev === 'undefined') {\n        dev = mode;\n        mode = 438;\n      }\n      mode |= 8192;\n      return FS.mknod(path, mode, dev)\n    },\n    symlink: function (oldpath, newpath) {\n      if (!PATH.resolve(oldpath)) {\n        throw new FS.ErrnoError(ERRNO_CODES.ENOENT)\n      }\n      var lookup = FS.lookupPath(newpath, { parent: true });\n      var parent = lookup.node;\n      if (!parent) {\n        throw new FS.ErrnoError(ERRNO_CODES.ENOENT)\n      }\n      var newname = PATH.basename(newpath);\n      var err = FS.mayCreate(parent, newname);\n      if (err) {\n        throw new FS.ErrnoError(err)\n      }\n      if (!parent.node_ops.symlink) {\n        throw new FS.ErrnoError(ERRNO_CODES.EPERM)\n      }\n      return parent.node_ops.symlink(parent, newname, oldpath)\n    },\n    rename: function (old_path, new_path) {\n      var old_dirname = PATH.dirname(old_path);\n      var new_dirname = PATH.dirname(new_path);\n      var old_name = PATH.basename(old_path);\n      var new_name = PATH.basename(new_path);\n      var lookup, old_dir, new_dir;\n      try {\n        lookup = FS.lookupPath(old_path, { parent: true });\n        old_dir = lookup.node;\n        lookup = FS.lookupPath(new_path, { parent: true });\n        new_dir = lookup.node;\n      } catch (e) {\n        throw new FS.ErrnoError(ERRNO_CODES.EBUSY)\n      }\n      if (!old_dir || !new_dir) throw new FS.ErrnoError(ERRNO_CODES.ENOENT)\n      if (old_dir.mount !== new_dir.mount) {\n        throw new FS.ErrnoError(ERRNO_CODES.EXDEV)\n      }\n      var old_node = FS.lookupNode(old_dir, old_name);\n      var relative = PATH.relative(old_path, new_dirname);\n      if (relative.charAt(0) !== '.') {\n        throw new FS.ErrnoError(ERRNO_CODES.EINVAL)\n      }\n      relative = PATH.relative(new_path, old_dirname);\n      if (relative.charAt(0) !== '.') {\n        throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY)\n      }\n      var new_node;\n      try {\n        new_node = FS.lookupNode(new_dir, new_name);\n      } catch (e) {}\n      if (old_node === new_node) {\n        return\n      }\n      var isdir = FS.isDir(old_node.mode);\n      var err = FS.mayDelete(old_dir, old_name, isdir);\n      if (err) {\n        throw new FS.ErrnoError(err)\n      }\n      err = new_node ? FS.mayDelete(new_dir, new_name, isdir) : FS.mayCreate(new_dir, new_name);\n      if (err) {\n        throw new FS.ErrnoError(err)\n      }\n      if (!old_dir.node_ops.rename) {\n        throw new FS.ErrnoError(ERRNO_CODES.EPERM)\n      }\n      if (FS.isMountpoint(old_node) || (new_node && FS.isMountpoint(new_node))) {\n        throw new FS.ErrnoError(ERRNO_CODES.EBUSY)\n      }\n      if (new_dir !== old_dir) {\n        err = FS.nodePermissions(old_dir, 'w');\n        if (err) {\n          throw new FS.ErrnoError(err)\n        }\n      }\n      try {\n        if (FS.trackingDelegate['willMovePath']) {\n          FS.trackingDelegate['willMovePath'](old_path, new_path);\n        }\n      } catch (e) {\n        console.log(\n          \"FS.trackingDelegate['willMovePath']('\" + old_path + \"', '\" + new_path + \"') threw an exception: \" + e.message\n        );\n      }\n      FS.hashRemoveNode(old_node);\n      try {\n        old_dir.node_ops.rename(old_node, new_dir, new_name);\n      } catch (e) {\n        throw e\n      } finally {\n        FS.hashAddNode(old_node);\n      }\n      try {\n        if (FS.trackingDelegate['onMovePath']) FS.trackingDelegate['onMovePath'](old_path, new_path);\n      } catch (e) {\n        console.log(\n          \"FS.trackingDelegate['onMovePath']('\" + old_path + \"', '\" + new_path + \"') threw an exception: \" + e.message\n        );\n      }\n    },\n    rmdir: function (path) {\n      var lookup = FS.lookupPath(path, { parent: true });\n      var parent = lookup.node;\n      var name = PATH.basename(path);\n      var node = FS.lookupNode(parent, name);\n      var err = FS.mayDelete(parent, name, true);\n      if (err) {\n        throw new FS.ErrnoError(err)\n      }\n      if (!parent.node_ops.rmdir) {\n        throw new FS.ErrnoError(ERRNO_CODES.EPERM)\n      }\n      if (FS.isMountpoint(node)) {\n        throw new FS.ErrnoError(ERRNO_CODES.EBUSY)\n      }\n      try {\n        if (FS.trackingDelegate['willDeletePath']) {\n          FS.trackingDelegate['willDeletePath'](path);\n        }\n      } catch (e) {\n        console.log(\"FS.trackingDelegate['willDeletePath']('\" + path + \"') threw an exception: \" + e.message);\n      }\n      parent.node_ops.rmdir(parent, name);\n      FS.destroyNode(node);\n      try {\n        if (FS.trackingDelegate['onDeletePath']) FS.trackingDelegate['onDeletePath'](path);\n      } catch (e) {\n        console.log(\"FS.trackingDelegate['onDeletePath']('\" + path + \"') threw an exception: \" + e.message);\n      }\n    },\n    readdir: function (path) {\n      var lookup = FS.lookupPath(path, { follow: true });\n      var node = lookup.node;\n      if (!node.node_ops.readdir) {\n        throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR)\n      }\n      return node.node_ops.readdir(node)\n    },\n    unlink: function (path) {\n      var lookup = FS.lookupPath(path, { parent: true });\n      var parent = lookup.node;\n      var name = PATH.basename(path);\n      var node = FS.lookupNode(parent, name);\n      var err = FS.mayDelete(parent, name, false);\n      if (err) {\n        throw new FS.ErrnoError(err)\n      }\n      if (!parent.node_ops.unlink) {\n        throw new FS.ErrnoError(ERRNO_CODES.EPERM)\n      }\n      if (FS.isMountpoint(node)) {\n        throw new FS.ErrnoError(ERRNO_CODES.EBUSY)\n      }\n      try {\n        if (FS.trackingDelegate['willDeletePath']) {\n          FS.trackingDelegate['willDeletePath'](path);\n        }\n      } catch (e) {\n        console.log(\"FS.trackingDelegate['willDeletePath']('\" + path + \"') threw an exception: \" + e.message);\n      }\n      parent.node_ops.unlink(parent, name);\n      FS.destroyNode(node);\n      try {\n        if (FS.trackingDelegate['onDeletePath']) FS.trackingDelegate['onDeletePath'](path);\n      } catch (e) {\n        console.log(\"FS.trackingDelegate['onDeletePath']('\" + path + \"') threw an exception: \" + e.message);\n      }\n    },\n    readlink: function (path) {\n      var lookup = FS.lookupPath(path);\n      var link = lookup.node;\n      if (!link) {\n        throw new FS.ErrnoError(ERRNO_CODES.ENOENT)\n      }\n      if (!link.node_ops.readlink) {\n        throw new FS.ErrnoError(ERRNO_CODES.EINVAL)\n      }\n      return PATH.resolve(FS.getPath(link.parent), link.node_ops.readlink(link))\n    },\n    stat: function (path, dontFollow) {\n      var lookup = FS.lookupPath(path, { follow: !dontFollow });\n      var node = lookup.node;\n      if (!node) {\n        throw new FS.ErrnoError(ERRNO_CODES.ENOENT)\n      }\n      if (!node.node_ops.getattr) {\n        throw new FS.ErrnoError(ERRNO_CODES.EPERM)\n      }\n      return node.node_ops.getattr(node)\n    },\n    lstat: function (path) {\n      return FS.stat(path, true)\n    },\n    chmod: function (path, mode, dontFollow) {\n      var node;\n      if (typeof path === 'string') {\n        var lookup = FS.lookupPath(path, { follow: !dontFollow });\n        node = lookup.node;\n      } else {\n        node = path;\n      }\n      if (!node.node_ops.setattr) {\n        throw new FS.ErrnoError(ERRNO_CODES.EPERM)\n      }\n      node.node_ops.setattr(node, { mode: (mode & 4095) | (node.mode & ~4095), timestamp: Date.now() });\n    },\n    lchmod: function (path, mode) {\n      FS.chmod(path, mode, true);\n    },\n    fchmod: function (fd, mode) {\n      var stream = FS.getStream(fd);\n      if (!stream) {\n        throw new FS.ErrnoError(ERRNO_CODES.EBADF)\n      }\n      FS.chmod(stream.node, mode);\n    },\n    chown: function (path, uid, gid, dontFollow) {\n      var node;\n      if (typeof path === 'string') {\n        var lookup = FS.lookupPath(path, { follow: !dontFollow });\n        node = lookup.node;\n      } else {\n        node = path;\n      }\n      if (!node.node_ops.setattr) {\n        throw new FS.ErrnoError(ERRNO_CODES.EPERM)\n      }\n      node.node_ops.setattr(node, { timestamp: Date.now() });\n    },\n    lchown: function (path, uid, gid) {\n      FS.chown(path, uid, gid, true);\n    },\n    fchown: function (fd, uid, gid) {\n      var stream = FS.getStream(fd);\n      if (!stream) {\n        throw new FS.ErrnoError(ERRNO_CODES.EBADF)\n      }\n      FS.chown(stream.node, uid, gid);\n    },\n    truncate: function (path, len) {\n      if (len < 0) {\n        throw new FS.ErrnoError(ERRNO_CODES.EINVAL)\n      }\n      var node;\n      if (typeof path === 'string') {\n        var lookup = FS.lookupPath(path, { follow: true });\n        node = lookup.node;\n      } else {\n        node = path;\n      }\n      if (!node.node_ops.setattr) {\n        throw new FS.ErrnoError(ERRNO_CODES.EPERM)\n      }\n      if (FS.isDir(node.mode)) {\n        throw new FS.ErrnoError(ERRNO_CODES.EISDIR)\n      }\n      if (!FS.isFile(node.mode)) {\n        throw new FS.ErrnoError(ERRNO_CODES.EINVAL)\n      }\n      var err = FS.nodePermissions(node, 'w');\n      if (err) {\n        throw new FS.ErrnoError(err)\n      }\n      node.node_ops.setattr(node, { size: len, timestamp: Date.now() });\n    },\n    ftruncate: function (fd, len) {\n      var stream = FS.getStream(fd);\n      if (!stream) {\n        throw new FS.ErrnoError(ERRNO_CODES.EBADF)\n      }\n      if ((stream.flags & 2097155) === 0) {\n        throw new FS.ErrnoError(ERRNO_CODES.EINVAL)\n      }\n      FS.truncate(stream.node, len);\n    },\n    utime: function (path, atime, mtime) {\n      var lookup = FS.lookupPath(path, { follow: true });\n      var node = lookup.node;\n      node.node_ops.setattr(node, { timestamp: Math.max(atime, mtime) });\n    },\n    open: function (path, flags, mode, fd_start, fd_end) {\n      if (path === '') {\n        throw new FS.ErrnoError(ERRNO_CODES.ENOENT)\n      }\n      flags = typeof flags === 'string' ? FS.modeStringToFlags(flags) : flags;\n      mode = typeof mode === 'undefined' ? 438 : mode;\n      if (flags & 64) {\n        mode = (mode & 4095) | 32768;\n      } else {\n        mode = 0;\n      }\n      var node;\n      if (typeof path === 'object') {\n        node = path;\n      } else {\n        path = PATH.normalize(path);\n        try {\n          var lookup = FS.lookupPath(path, { follow: !(flags & 131072) });\n          node = lookup.node;\n        } catch (e) {}\n      }\n      var created = false;\n      if (flags & 64) {\n        if (node) {\n          if (flags & 128) {\n            throw new FS.ErrnoError(ERRNO_CODES.EEXIST)\n          }\n        } else {\n          node = FS.mknod(path, mode, 0);\n          created = true;\n        }\n      }\n      if (!node) {\n        throw new FS.ErrnoError(ERRNO_CODES.ENOENT)\n      }\n      if (FS.isChrdev(node.mode)) {\n        flags &= ~512;\n      }\n      if (flags & 65536 && !FS.isDir(node.mode)) {\n        throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR)\n      }\n      if (!created) {\n        var err = FS.mayOpen(node, flags);\n        if (err) {\n          throw new FS.ErrnoError(err)\n        }\n      }\n      if (flags & 512) {\n        FS.truncate(node, 0);\n      }\n      flags &= ~(128 | 512);\n      var stream = FS.createStream(\n        {\n          node: node,\n          path: FS.getPath(node),\n          flags: flags,\n          seekable: true,\n          position: 0,\n          stream_ops: node.stream_ops,\n          ungotten: [],\n          error: false,\n        },\n        fd_start,\n        fd_end\n      );\n      if (stream.stream_ops.open) {\n        stream.stream_ops.open(stream);\n      }\n      if (Module['logReadFiles'] && !(flags & 1)) {\n        if (!FS.readFiles) FS.readFiles = {};\n        if (!(path in FS.readFiles)) {\n          FS.readFiles[path] = 1;\n          Module['printErr']('read file: ' + path);\n        }\n      }\n      try {\n        if (FS.trackingDelegate['onOpenFile']) {\n          var trackingFlags = 0;\n          if ((flags & 2097155) !== 1) {\n            trackingFlags |= FS.tracking.openFlags.READ;\n          }\n          if ((flags & 2097155) !== 0) {\n            trackingFlags |= FS.tracking.openFlags.WRITE;\n          }\n          FS.trackingDelegate['onOpenFile'](path, trackingFlags);\n        }\n      } catch (e) {\n        console.log(\"FS.trackingDelegate['onOpenFile']('\" + path + \"', flags) threw an exception: \" + e.message);\n      }\n      return stream\n    },\n    close: function (stream) {\n      if (FS.isClosed(stream)) {\n        throw new FS.ErrnoError(ERRNO_CODES.EBADF)\n      }\n      if (stream.getdents) stream.getdents = null;\n      try {\n        if (stream.stream_ops.close) {\n          stream.stream_ops.close(stream);\n        }\n      } catch (e) {\n        throw e\n      } finally {\n        FS.closeStream(stream.fd);\n      }\n      stream.fd = null;\n    },\n    isClosed: function (stream) {\n      return stream.fd === null\n    },\n    llseek: function (stream, offset, whence) {\n      if (FS.isClosed(stream)) {\n        throw new FS.ErrnoError(ERRNO_CODES.EBADF)\n      }\n      if (!stream.seekable || !stream.stream_ops.llseek) {\n        throw new FS.ErrnoError(ERRNO_CODES.ESPIPE)\n      }\n      stream.position = stream.stream_ops.llseek(stream, offset, whence);\n      stream.ungotten = [];\n      return stream.position\n    },\n    read: function (stream, buffer, offset, length, position) {\n      if (length < 0 || position < 0) {\n        throw new FS.ErrnoError(ERRNO_CODES.EINVAL)\n      }\n      if (FS.isClosed(stream)) {\n        throw new FS.ErrnoError(ERRNO_CODES.EBADF)\n      }\n      if ((stream.flags & 2097155) === 1) {\n        throw new FS.ErrnoError(ERRNO_CODES.EBADF)\n      }\n      if (FS.isDir(stream.node.mode)) {\n        throw new FS.ErrnoError(ERRNO_CODES.EISDIR)\n      }\n      if (!stream.stream_ops.read) {\n        throw new FS.ErrnoError(ERRNO_CODES.EINVAL)\n      }\n      var seeking = typeof position !== 'undefined';\n      if (!seeking) {\n        position = stream.position;\n      } else if (!stream.seekable) {\n        throw new FS.ErrnoError(ERRNO_CODES.ESPIPE)\n      }\n      var bytesRead = stream.stream_ops.read(stream, buffer, offset, length, position);\n      if (!seeking) stream.position += bytesRead;\n      return bytesRead\n    },\n    write: function (stream, buffer, offset, length, position, canOwn) {\n      if (length < 0 || position < 0) {\n        throw new FS.ErrnoError(ERRNO_CODES.EINVAL)\n      }\n      if (FS.isClosed(stream)) {\n        throw new FS.ErrnoError(ERRNO_CODES.EBADF)\n      }\n      if ((stream.flags & 2097155) === 0) {\n        throw new FS.ErrnoError(ERRNO_CODES.EBADF)\n      }\n      if (FS.isDir(stream.node.mode)) {\n        throw new FS.ErrnoError(ERRNO_CODES.EISDIR)\n      }\n      if (!stream.stream_ops.write) {\n        throw new FS.ErrnoError(ERRNO_CODES.EINVAL)\n      }\n      if (stream.flags & 1024) {\n        FS.llseek(stream, 0, 2);\n      }\n      var seeking = typeof position !== 'undefined';\n      if (!seeking) {\n        position = stream.position;\n      } else if (!stream.seekable) {\n        throw new FS.ErrnoError(ERRNO_CODES.ESPIPE)\n      }\n      var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn);\n      if (!seeking) stream.position += bytesWritten;\n      try {\n        if (stream.path && FS.trackingDelegate['onWriteToFile']) FS.trackingDelegate['onWriteToFile'](stream.path);\n      } catch (e) {\n        console.log(\"FS.trackingDelegate['onWriteToFile']('\" + path + \"') threw an exception: \" + e.message);\n      }\n      return bytesWritten\n    },\n    allocate: function (stream, offset, length) {\n      if (FS.isClosed(stream)) {\n        throw new FS.ErrnoError(ERRNO_CODES.EBADF)\n      }\n      if (offset < 0 || length <= 0) {\n        throw new FS.ErrnoError(ERRNO_CODES.EINVAL)\n      }\n      if ((stream.flags & 2097155) === 0) {\n        throw new FS.ErrnoError(ERRNO_CODES.EBADF)\n      }\n      if (!FS.isFile(stream.node.mode) && !FS.isDir(stream.node.mode)) {\n        throw new FS.ErrnoError(ERRNO_CODES.ENODEV)\n      }\n      if (!stream.stream_ops.allocate) {\n        throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP)\n      }\n      stream.stream_ops.allocate(stream, offset, length);\n    },\n    mmap: function (stream, buffer, offset, length, position, prot, flags) {\n      if ((stream.flags & 2097155) === 1) {\n        throw new FS.ErrnoError(ERRNO_CODES.EACCES)\n      }\n      if (!stream.stream_ops.mmap) {\n        throw new FS.ErrnoError(ERRNO_CODES.ENODEV)\n      }\n      return stream.stream_ops.mmap(stream, buffer, offset, length, position, prot, flags)\n    },\n    msync: function (stream, buffer, offset, length, mmapFlags) {\n      if (!stream || !stream.stream_ops.msync) {\n        return 0\n      }\n      return stream.stream_ops.msync(stream, buffer, offset, length, mmapFlags)\n    },\n    munmap: function (stream) {\n      return 0\n    },\n    ioctl: function (stream, cmd, arg) {\n      if (!stream.stream_ops.ioctl) {\n        throw new FS.ErrnoError(ERRNO_CODES.ENOTTY)\n      }\n      return stream.stream_ops.ioctl(stream, cmd, arg)\n    },\n    readFile: function (path, opts) {\n      opts = opts || {};\n      opts.flags = opts.flags || 'r';\n      opts.encoding = opts.encoding || 'binary';\n      if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {\n        throw new Error('Invalid encoding type \"' + opts.encoding + '\"')\n      }\n      var ret;\n      var stream = FS.open(path, opts.flags);\n      var stat = FS.stat(path);\n      var length = stat.size;\n      var buf = new Uint8Array(length);\n      FS.read(stream, buf, 0, length, 0);\n      if (opts.encoding === 'utf8') {\n        ret = UTF8ArrayToString(buf, 0);\n      } else if (opts.encoding === 'binary') {\n        ret = buf;\n      }\n      FS.close(stream);\n      return ret\n    },\n    writeFile: function (path, data, opts) {\n      opts = opts || {};\n      opts.flags = opts.flags || 'w';\n      var stream = FS.open(path, opts.flags, opts.mode);\n      if (typeof data === 'string') {\n        var buf = new Uint8Array(lengthBytesUTF8(data) + 1);\n        var actualNumBytes = stringToUTF8Array(data, buf, 0, buf.length);\n        FS.write(stream, buf, 0, actualNumBytes, undefined, opts.canOwn);\n      } else if (ArrayBuffer.isView(data)) {\n        FS.write(stream, data, 0, data.byteLength, undefined, opts.canOwn);\n      } else {\n        throw new Error('Unsupported data type')\n      }\n      FS.close(stream);\n    },\n    cwd: function () {\n      return FS.currentPath\n    },\n    chdir: function (path) {\n      var lookup = FS.lookupPath(path, { follow: true });\n      if (lookup.node === null) {\n        throw new FS.ErrnoError(ERRNO_CODES.ENOENT)\n      }\n      if (!FS.isDir(lookup.node.mode)) {\n        throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR)\n      }\n      var err = FS.nodePermissions(lookup.node, 'x');\n      if (err) {\n        throw new FS.ErrnoError(err)\n      }\n      FS.currentPath = lookup.path;\n    },\n    createDefaultDirectories: function () {\n      FS.mkdir('/tmp');\n      FS.mkdir('/home');\n      FS.mkdir('/home/web_user');\n    },\n    createDefaultDevices: function () {\n      FS.mkdir('/dev');\n      FS.registerDevice(FS.makedev(1, 3), {\n        read: function () {\n          return 0\n        },\n        write: function (stream, buffer, offset, length, pos) {\n          return length\n        },\n      });\n      FS.mkdev('/dev/null', FS.makedev(1, 3));\n      TTY.register(FS.makedev(5, 0), TTY.default_tty_ops);\n      TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops);\n      FS.mkdev('/dev/tty', FS.makedev(5, 0));\n      FS.mkdev('/dev/tty1', FS.makedev(6, 0));\n      var random_device;\n      if (typeof crypto !== 'undefined') {\n        var randomBuffer = new Uint8Array(1);\n        random_device = function () {\n          crypto.getRandomValues(randomBuffer);\n          return randomBuffer[0]\n        };\n      } else if (ENVIRONMENT_IS_NODE) {\n        random_device = function () {\n          return require('crypto')['randomBytes'](1)[0]\n        };\n      } else {\n        random_device = function () {\n          return (Math.random() * 256) | 0\n        };\n      }\n      FS.createDevice('/dev', 'random', random_device);\n      FS.createDevice('/dev', 'urandom', random_device);\n      FS.mkdir('/dev/shm');\n      FS.mkdir('/dev/shm/tmp');\n    },\n    createSpecialDirectories: function () {\n      FS.mkdir('/proc');\n      FS.mkdir('/proc/self');\n      FS.mkdir('/proc/self/fd');\n      FS.mount(\n        {\n          mount: function () {\n            var node = FS.createNode('/proc/self', 'fd', 16384 | 511, 73);\n            node.node_ops = {\n              lookup: function (parent, name) {\n                var fd = +name;\n                var stream = FS.getStream(fd);\n                if (!stream) throw new FS.ErrnoError(ERRNO_CODES.EBADF)\n                var ret = {\n                  parent: null,\n                  mount: { mountpoint: 'fake' },\n                  node_ops: {\n                    readlink: function () {\n                      return stream.path\n                    },\n                  },\n                };\n                ret.parent = ret;\n                return ret\n              },\n            };\n            return node\n          },\n        },\n        {},\n        '/proc/self/fd'\n      );\n    },\n    createStandardStreams: function () {\n      if (Module['stdin']) {\n        FS.createDevice('/dev', 'stdin', Module['stdin']);\n      } else {\n        FS.symlink('/dev/tty', '/dev/stdin');\n      }\n      if (Module['stdout']) {\n        FS.createDevice('/dev', 'stdout', null, Module['stdout']);\n      } else {\n        FS.symlink('/dev/tty', '/dev/stdout');\n      }\n      if (Module['stderr']) {\n        FS.createDevice('/dev', 'stderr', null, Module['stderr']);\n      } else {\n        FS.symlink('/dev/tty1', '/dev/stderr');\n      }\n      var stdin = FS.open('/dev/stdin', 'r');\n      assert(stdin.fd === 0, 'invalid handle for stdin (' + stdin.fd + ')');\n      var stdout = FS.open('/dev/stdout', 'w');\n      assert(stdout.fd === 1, 'invalid handle for stdout (' + stdout.fd + ')');\n      var stderr = FS.open('/dev/stderr', 'w');\n      assert(stderr.fd === 2, 'invalid handle for stderr (' + stderr.fd + ')');\n    },\n    ensureErrnoError: function () {\n      if (FS.ErrnoError) return\n      FS.ErrnoError = function ErrnoError(errno, node) {\n        this.node = node;\n        this.setErrno = function (errno) {\n          this.errno = errno;\n          for (var key in ERRNO_CODES) {\n            if (ERRNO_CODES[key] === errno) {\n              this.code = key;\n              break\n            }\n          }\n        };\n        this.setErrno(errno);\n        this.message = ERRNO_MESSAGES[errno];\n        if (this.stack) Object.defineProperty(this, 'stack', { value: new Error().stack, writable: true });\n      };\n      FS.ErrnoError.prototype = new Error();\n      FS.ErrnoError.prototype.constructor = FS.ErrnoError\n      ;[ERRNO_CODES.ENOENT].forEach(function (code) {\n        FS.genericErrors[code] = new FS.ErrnoError(code);\n        FS.genericErrors[code].stack = '<generic error, no stack>';\n      });\n    },\n    staticInit: function () {\n      FS.ensureErrnoError();\n      FS.nameTable = new Array(4096);\n      FS.mount(MEMFS, {}, '/');\n      FS.createDefaultDirectories();\n      FS.createDefaultDevices();\n      FS.createSpecialDirectories();\n      FS.filesystems = { MEMFS: MEMFS, IDBFS: IDBFS, NODEFS: NODEFS, WORKERFS: WORKERFS };\n    },\n    init: function (input, output, error) {\n      assert(\n        !FS.init.initialized,\n        'FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)'\n      );\n      FS.init.initialized = true;\n      FS.ensureErrnoError();\n      Module['stdin'] = input || Module['stdin'];\n      Module['stdout'] = output || Module['stdout'];\n      Module['stderr'] = error || Module['stderr'];\n      FS.createStandardStreams();\n    },\n    quit: function () {\n      FS.init.initialized = false;\n      var fflush = Module['_fflush'];\n      if (fflush) fflush(0);\n      for (var i = 0; i < FS.streams.length; i++) {\n        var stream = FS.streams[i];\n        if (!stream) {\n          continue\n        }\n        FS.close(stream);\n      }\n    },\n    getMode: function (canRead, canWrite) {\n      var mode = 0;\n      if (canRead) mode |= 292 | 73;\n      if (canWrite) mode |= 146;\n      return mode\n    },\n    joinPath: function (parts, forceRelative) {\n      var path = PATH.join.apply(null, parts);\n      if (forceRelative && path[0] == '/') path = path.substr(1);\n      return path\n    },\n    absolutePath: function (relative, base) {\n      return PATH.resolve(base, relative)\n    },\n    standardizePath: function (path) {\n      return PATH.normalize(path)\n    },\n    findObject: function (path, dontResolveLastLink) {\n      var ret = FS.analyzePath(path, dontResolveLastLink);\n      if (ret.exists) {\n        return ret.object\n      } else {\n        ___setErrNo(ret.error);\n        return null\n      }\n    },\n    analyzePath: function (path, dontResolveLastLink) {\n      try {\n        var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });\n        path = lookup.path;\n      } catch (e) {}\n      var ret = {\n        isRoot: false,\n        exists: false,\n        error: 0,\n        name: null,\n        path: null,\n        object: null,\n        parentExists: false,\n        parentPath: null,\n        parentObject: null,\n      };\n      try {\n        var lookup = FS.lookupPath(path, { parent: true });\n        ret.parentExists = true;\n        ret.parentPath = lookup.path;\n        ret.parentObject = lookup.node;\n        ret.name = PATH.basename(path);\n        lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });\n        ret.exists = true;\n        ret.path = lookup.path;\n        ret.object = lookup.node;\n        ret.name = lookup.node.name;\n        ret.isRoot = lookup.path === '/';\n      } catch (e) {\n        ret.error = e.errno;\n      }\n      return ret\n    },\n    createFolder: function (parent, name, canRead, canWrite) {\n      var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);\n      var mode = FS.getMode(canRead, canWrite);\n      return FS.mkdir(path, mode)\n    },\n    createPath: function (parent, path, canRead, canWrite) {\n      parent = typeof parent === 'string' ? parent : FS.getPath(parent);\n      var parts = path.split('/').reverse();\n      while (parts.length) {\n        var part = parts.pop();\n        if (!part) continue\n        var current = PATH.join2(parent, part);\n        try {\n          FS.mkdir(current);\n        } catch (e) {}\n        parent = current;\n      }\n      return current\n    },\n    createFile: function (parent, name, properties, canRead, canWrite) {\n      var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);\n      var mode = FS.getMode(canRead, canWrite);\n      return FS.create(path, mode)\n    },\n    createDataFile: function (parent, name, data, canRead, canWrite, canOwn) {\n      var path = name ? PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name) : parent;\n      var mode = FS.getMode(canRead, canWrite);\n      var node = FS.create(path, mode);\n      if (data) {\n        if (typeof data === 'string') {\n          var arr = new Array(data.length);\n          for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i);\n          data = arr;\n        }\n        FS.chmod(node, mode | 146);\n        var stream = FS.open(node, 'w');\n        FS.write(stream, data, 0, data.length, 0, canOwn);\n        FS.close(stream);\n        FS.chmod(node, mode);\n      }\n      return node\n    },\n    createDevice: function (parent, name, input, output) {\n      var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);\n      var mode = FS.getMode(!!input, !!output);\n      if (!FS.createDevice.major) FS.createDevice.major = 64;\n      var dev = FS.makedev(FS.createDevice.major++, 0);\n      FS.registerDevice(dev, {\n        open: function (stream) {\n          stream.seekable = false;\n        },\n        close: function (stream) {\n          if (output && output.buffer && output.buffer.length) {\n            output(10);\n          }\n        },\n        read: function (stream, buffer, offset, length, pos) {\n          var bytesRead = 0;\n          for (var i = 0; i < length; i++) {\n            var result;\n            try {\n              result = input();\n            } catch (e) {\n              throw new FS.ErrnoError(ERRNO_CODES.EIO)\n            }\n            if (result === undefined && bytesRead === 0) {\n              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN)\n            }\n            if (result === null || result === undefined) break\n            bytesRead++;\n            buffer[offset + i] = result;\n          }\n          if (bytesRead) {\n            stream.node.timestamp = Date.now();\n          }\n          return bytesRead\n        },\n        write: function (stream, buffer, offset, length, pos) {\n          for (var i = 0; i < length; i++) {\n            try {\n              output(buffer[offset + i]);\n            } catch (e) {\n              throw new FS.ErrnoError(ERRNO_CODES.EIO)\n            }\n          }\n          if (length) {\n            stream.node.timestamp = Date.now();\n          }\n          return i\n        },\n      });\n      return FS.mkdev(path, mode, dev)\n    },\n    createLink: function (parent, name, target, canRead, canWrite) {\n      var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);\n      return FS.symlink(target, path)\n    },\n    forceLoadFile: function (obj) {\n      if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true\n      var success = true;\n      if (typeof XMLHttpRequest !== 'undefined') {\n        throw new Error(\n          'Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.'\n        )\n      } else if (Module['read']) {\n        try {\n          obj.contents = intArrayFromString(Module['read'](obj.url), true);\n          obj.usedBytes = obj.contents.length;\n        } catch (e) {\n          success = false;\n        }\n      } else {\n        throw new Error('Cannot load without read() or XMLHttpRequest.')\n      }\n      if (!success) ___setErrNo(ERRNO_CODES.EIO);\n      return success\n    },\n    createLazyFile: function (parent, name, url, canRead, canWrite) {\n      function LazyUint8Array() {\n        this.lengthKnown = false;\n        this.chunks = [];\n      }\n      LazyUint8Array.prototype.get = function LazyUint8Array_get(idx) {\n        if (idx > this.length - 1 || idx < 0) {\n          return undefined\n        }\n        var chunkOffset = idx % this.chunkSize;\n        var chunkNum = (idx / this.chunkSize) | 0;\n        return this.getter(chunkNum)[chunkOffset]\n      };\n      LazyUint8Array.prototype.setDataGetter = function LazyUint8Array_setDataGetter(getter) {\n        this.getter = getter;\n      };\n      LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() {\n        var xhr = new XMLHttpRequest();\n        xhr.open('HEAD', url, false);\n        xhr.send(null);\n        if (!((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304))\n          throw new Error(\"Couldn't load \" + url + '. Status: ' + xhr.status)\n        var datalength = Number(xhr.getResponseHeader('Content-length'));\n        var header;\n        var hasByteServing = (header = xhr.getResponseHeader('Accept-Ranges')) && header === 'bytes';\n        var usesGzip = (header = xhr.getResponseHeader('Content-Encoding')) && header === 'gzip';\n        var chunkSize = 1024 * 1024;\n        if (!hasByteServing) chunkSize = datalength;\n        var doXHR = function (from, to) {\n          if (from > to) throw new Error('invalid range (' + from + ', ' + to + ') or no bytes requested!')\n          if (to > datalength - 1) throw new Error('only ' + datalength + ' bytes available! programmer error!')\n          var xhr = new XMLHttpRequest();\n          xhr.open('GET', url, false);\n          if (datalength !== chunkSize) xhr.setRequestHeader('Range', 'bytes=' + from + '-' + to);\n          if (typeof Uint8Array != 'undefined') xhr.responseType = 'arraybuffer';\n          if (xhr.overrideMimeType) {\n            xhr.overrideMimeType('text/plain; charset=x-user-defined');\n          }\n          xhr.send(null);\n          if (!((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304))\n            throw new Error(\"Couldn't load \" + url + '. Status: ' + xhr.status)\n          if (xhr.response !== undefined) {\n            return new Uint8Array(xhr.response || [])\n          } else {\n            return intArrayFromString(xhr.responseText || '', true)\n          }\n        };\n        var lazyArray = this;\n        lazyArray.setDataGetter(function (chunkNum) {\n          var start = chunkNum * chunkSize;\n          var end = (chunkNum + 1) * chunkSize - 1;\n          end = Math.min(end, datalength - 1);\n          if (typeof lazyArray.chunks[chunkNum] === 'undefined') {\n            lazyArray.chunks[chunkNum] = doXHR(start, end);\n          }\n          if (typeof lazyArray.chunks[chunkNum] === 'undefined') throw new Error('doXHR failed!')\n          return lazyArray.chunks[chunkNum]\n        });\n        if (usesGzip || !datalength) {\n          chunkSize = datalength = 1;\n          datalength = this.getter(0).length;\n          chunkSize = datalength;\n          console.log('LazyFiles on gzip forces download of the whole file when length is accessed');\n        }\n        this._length = datalength;\n        this._chunkSize = chunkSize;\n        this.lengthKnown = true;\n      };\n      if (typeof XMLHttpRequest !== 'undefined') {\n        if (!ENVIRONMENT_IS_WORKER)\n          throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc'\n        var lazyArray = new LazyUint8Array();\n        Object.defineProperties(lazyArray, {\n          length: {\n            get: function () {\n              if (!this.lengthKnown) {\n                this.cacheLength();\n              }\n              return this._length\n            },\n          },\n          chunkSize: {\n            get: function () {\n              if (!this.lengthKnown) {\n                this.cacheLength();\n              }\n              return this._chunkSize\n            },\n          },\n        });\n        var properties = { isDevice: false, contents: lazyArray };\n      } else {\n        var properties = { isDevice: false, url: url };\n      }\n      var node = FS.createFile(parent, name, properties, canRead, canWrite);\n      if (properties.contents) {\n        node.contents = properties.contents;\n      } else if (properties.url) {\n        node.contents = null;\n        node.url = properties.url;\n      }\n      Object.defineProperties(node, {\n        usedBytes: {\n          get: function () {\n            return this.contents.length\n          },\n        },\n      });\n      var stream_ops = {};\n      var keys = Object.keys(node.stream_ops);\n      keys.forEach(function (key) {\n        var fn = node.stream_ops[key];\n        stream_ops[key] = function forceLoadLazyFile() {\n          if (!FS.forceLoadFile(node)) {\n            throw new FS.ErrnoError(ERRNO_CODES.EIO)\n          }\n          return fn.apply(null, arguments)\n        };\n      });\n      stream_ops.read = function stream_ops_read(stream, buffer, offset, length, position) {\n        if (!FS.forceLoadFile(node)) {\n          throw new FS.ErrnoError(ERRNO_CODES.EIO)\n        }\n        var contents = stream.node.contents;\n        if (position >= contents.length) return 0\n        var size = Math.min(contents.length - position, length);\n        assert(size >= 0);\n        if (contents.slice) {\n          for (var i = 0; i < size; i++) {\n            buffer[offset + i] = contents[position + i];\n          }\n        } else {\n          for (var i = 0; i < size; i++) {\n            buffer[offset + i] = contents.get(position + i);\n          }\n        }\n        return size\n      };\n      node.stream_ops = stream_ops;\n      return node\n    },\n    createPreloadedFile: function (\n      parent,\n      name,\n      url,\n      canRead,\n      canWrite,\n      onload,\n      onerror,\n      dontCreateFile,\n      canOwn,\n      preFinish\n    ) {\n      Browser.init();\n      var fullname = name ? PATH.resolve(PATH.join2(parent, name)) : parent;\n      function processData(byteArray) {\n        function finish(byteArray) {\n          if (preFinish) preFinish();\n          if (!dontCreateFile) {\n            FS.createDataFile(parent, name, byteArray, canRead, canWrite, canOwn);\n          }\n          if (onload) onload();\n          removeRunDependency();\n        }\n        var handled = false;\n        Module['preloadPlugins'].forEach(function (plugin) {\n          if (handled) return\n          if (plugin['canHandle'](fullname)) {\n            plugin['handle'](byteArray, fullname, finish, function () {\n              if (onerror) onerror();\n              removeRunDependency();\n            });\n            handled = true;\n          }\n        });\n        if (!handled) finish(byteArray);\n      }\n      addRunDependency();\n      if (typeof url == 'string') {\n        Browser.asyncLoad(\n          url,\n          function (byteArray) {\n            processData(byteArray);\n          },\n          onerror\n        );\n      } else {\n        processData(url);\n      }\n    },\n    indexedDB: function () {\n      return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB\n    },\n    DB_NAME: function () {\n      return 'EM_FS_' + window.location.pathname\n    },\n    DB_VERSION: 20,\n    DB_STORE_NAME: 'FILE_DATA',\n    saveFilesToDB: function (paths, onload, onerror) {\n      onload = onload || function () {};\n      onerror = onerror || function () {};\n      var indexedDB = FS.indexedDB();\n      try {\n        var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);\n      } catch (e) {\n        return onerror(e)\n      }\n      openRequest.onupgradeneeded = function openRequest_onupgradeneeded() {\n        console.log('creating db');\n        var db = openRequest.result;\n        db.createObjectStore(FS.DB_STORE_NAME);\n      };\n      openRequest.onsuccess = function openRequest_onsuccess() {\n        var db = openRequest.result;\n        var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite');\n        var files = transaction.objectStore(FS.DB_STORE_NAME);\n        var ok = 0,\n          fail = 0,\n          total = paths.length;\n        function finish() {\n          if (fail == 0) onload();\n          else onerror();\n        }\n        paths.forEach(function (path) {\n          var putRequest = files.put(FS.analyzePath(path).object.contents, path);\n          putRequest.onsuccess = function putRequest_onsuccess() {\n            ok++;\n            if (ok + fail == total) finish();\n          };\n          putRequest.onerror = function putRequest_onerror() {\n            fail++;\n            if (ok + fail == total) finish();\n          };\n        });\n        transaction.onerror = onerror;\n      };\n      openRequest.onerror = onerror;\n    },\n    loadFilesFromDB: function (paths, onload, onerror) {\n      onload = onload || function () {};\n      onerror = onerror || function () {};\n      var indexedDB = FS.indexedDB();\n      try {\n        var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);\n      } catch (e) {\n        return onerror(e)\n      }\n      openRequest.onupgradeneeded = onerror;\n      openRequest.onsuccess = function openRequest_onsuccess() {\n        var db = openRequest.result;\n        try {\n          var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly');\n        } catch (e) {\n          onerror(e);\n          return\n        }\n        var files = transaction.objectStore(FS.DB_STORE_NAME);\n        var ok = 0,\n          fail = 0,\n          total = paths.length;\n        function finish() {\n          if (fail == 0) onload();\n          else onerror();\n        }\n        paths.forEach(function (path) {\n          var getRequest = files.get(path);\n          getRequest.onsuccess = function getRequest_onsuccess() {\n            if (FS.analyzePath(path).exists) {\n              FS.unlink(path);\n            }\n            FS.createDataFile(PATH.dirname(path), PATH.basename(path), getRequest.result, true, true, true);\n            ok++;\n            if (ok + fail == total) finish();\n          };\n          getRequest.onerror = function getRequest_onerror() {\n            fail++;\n            if (ok + fail == total) finish();\n          };\n        });\n        transaction.onerror = onerror;\n      };\n      openRequest.onerror = onerror;\n    },\n  };\n  var SYSCALLS = {\n    DEFAULT_POLLMASK: 5,\n    mappings: {},\n    umask: 511,\n    calculateAt: function (dirfd, path) {\n      if (path[0] !== '/') {\n        var dir;\n        if (dirfd === -100) {\n          dir = FS.cwd();\n        } else {\n          var dirstream = FS.getStream(dirfd);\n          if (!dirstream) throw new FS.ErrnoError(ERRNO_CODES.EBADF)\n          dir = dirstream.path;\n        }\n        path = PATH.join2(dir, path);\n      }\n      return path\n    },\n    doStat: function (func, path, buf) {\n      try {\n        var stat = func(path);\n      } catch (e) {\n        if (e && e.node && PATH.normalize(path) !== PATH.normalize(FS.getPath(e.node))) {\n          return -ERRNO_CODES.ENOTDIR\n        }\n        throw e\n      }\n      HEAP32[buf >> 2] = stat.dev;\n      HEAP32[(buf + 4) >> 2] = 0;\n      HEAP32[(buf + 8) >> 2] = stat.ino;\n      HEAP32[(buf + 12) >> 2] = stat.mode;\n      HEAP32[(buf + 16) >> 2] = stat.nlink;\n      HEAP32[(buf + 20) >> 2] = stat.uid;\n      HEAP32[(buf + 24) >> 2] = stat.gid;\n      HEAP32[(buf + 28) >> 2] = stat.rdev;\n      HEAP32[(buf + 32) >> 2] = 0;\n      HEAP32[(buf + 36) >> 2] = stat.size;\n      HEAP32[(buf + 40) >> 2] = 4096;\n      HEAP32[(buf + 44) >> 2] = stat.blocks;\n      HEAP32[(buf + 48) >> 2] = (stat.atime.getTime() / 1e3) | 0;\n      HEAP32[(buf + 52) >> 2] = 0;\n      HEAP32[(buf + 56) >> 2] = (stat.mtime.getTime() / 1e3) | 0;\n      HEAP32[(buf + 60) >> 2] = 0;\n      HEAP32[(buf + 64) >> 2] = (stat.ctime.getTime() / 1e3) | 0;\n      HEAP32[(buf + 68) >> 2] = 0;\n      HEAP32[(buf + 72) >> 2] = stat.ino;\n      return 0\n    },\n    doMsync: function (addr, stream, len, flags) {\n      var buffer = new Uint8Array(HEAPU8.subarray(addr, addr + len));\n      FS.msync(stream, buffer, 0, len, flags);\n    },\n    doMkdir: function (path, mode) {\n      path = PATH.normalize(path);\n      if (path[path.length - 1] === '/') path = path.substr(0, path.length - 1);\n      FS.mkdir(path, mode, 0);\n      return 0\n    },\n    doMknod: function (path, mode, dev) {\n      switch (mode & 61440) {\n        case 32768:\n        case 8192:\n        case 24576:\n        case 4096:\n        case 49152:\n          break\n        default:\n          return -ERRNO_CODES.EINVAL\n      }\n      FS.mknod(path, mode, dev);\n      return 0\n    },\n    doReadlink: function (path, buf, bufsize) {\n      if (bufsize <= 0) return -ERRNO_CODES.EINVAL\n      var ret = FS.readlink(path);\n      var len = Math.min(bufsize, lengthBytesUTF8(ret));\n      var endChar = HEAP8[buf + len];\n      stringToUTF8(ret, buf, bufsize + 1);\n      HEAP8[buf + len] = endChar;\n      return len\n    },\n    doAccess: function (path, amode) {\n      if (amode & ~7) {\n        return -ERRNO_CODES.EINVAL\n      }\n      var node;\n      var lookup = FS.lookupPath(path, { follow: true });\n      node = lookup.node;\n      var perms = '';\n      if (amode & 4) perms += 'r';\n      if (amode & 2) perms += 'w';\n      if (amode & 1) perms += 'x';\n      if (perms && FS.nodePermissions(node, perms)) {\n        return -ERRNO_CODES.EACCES\n      }\n      return 0\n    },\n    doDup: function (path, flags, suggestFD) {\n      var suggest = FS.getStream(suggestFD);\n      if (suggest) FS.close(suggest);\n      return FS.open(path, flags, 0, suggestFD, suggestFD).fd\n    },\n    doReadv: function (stream, iov, iovcnt, offset) {\n      var ret = 0;\n      for (var i = 0; i < iovcnt; i++) {\n        var ptr = HEAP32[(iov + i * 8) >> 2];\n        var len = HEAP32[(iov + (i * 8 + 4)) >> 2];\n        var curr = FS.read(stream, HEAP8, ptr, len, offset);\n        if (curr < 0) return -1\n        ret += curr;\n        if (curr < len) break\n      }\n      return ret\n    },\n    doWritev: function (stream, iov, iovcnt, offset) {\n      var ret = 0;\n      for (var i = 0; i < iovcnt; i++) {\n        var ptr = HEAP32[(iov + i * 8) >> 2];\n        var len = HEAP32[(iov + (i * 8 + 4)) >> 2];\n        var curr = FS.write(stream, HEAP8, ptr, len, offset);\n        if (curr < 0) return -1\n        ret += curr;\n      }\n      return ret\n    },\n    varargs: 0,\n    get: function (varargs) {\n      SYSCALLS.varargs += 4;\n      var ret = HEAP32[(SYSCALLS.varargs - 4) >> 2];\n      return ret\n    },\n    getStr: function () {\n      var ret = Pointer_stringify(SYSCALLS.get());\n      return ret\n    },\n    getStreamFromFD: function () {\n      var stream = FS.getStream(SYSCALLS.get());\n      if (!stream) throw new FS.ErrnoError(ERRNO_CODES.EBADF)\n      return stream\n    },\n    getSocketFromFD: function () {\n      var socket = SOCKFS.getSocket(SYSCALLS.get());\n      if (!socket) throw new FS.ErrnoError(ERRNO_CODES.EBADF)\n      return socket\n    },\n    getSocketAddress: function (allowNull) {\n      var addrp = SYSCALLS.get(),\n        addrlen = SYSCALLS.get();\n      if (allowNull && addrp === 0) return null\n      var info = __read_sockaddr(addrp, addrlen);\n      if (info.errno) throw new FS.ErrnoError(info.errno)\n      info.addr = DNS.lookup_addr(info.addr) || info.addr;\n      return info\n    },\n    get64: function () {\n      var low = SYSCALLS.get(),\n        high = SYSCALLS.get();\n      if (low >= 0) assert(high === 0);\n      else assert(high === -1);\n      return low\n    },\n    getZero: function () {\n      assert(SYSCALLS.get() === 0);\n    },\n  };\n  function ___syscall140(which, varargs) {\n    SYSCALLS.varargs = varargs;\n    try {\n      var stream = SYSCALLS.getStreamFromFD(),\n        offset_high = SYSCALLS.get(),\n        offset_low = SYSCALLS.get(),\n        result = SYSCALLS.get(),\n        whence = SYSCALLS.get();\n      var offset = offset_low;\n      FS.llseek(stream, offset, whence);\n      HEAP32[result >> 2] = stream.position;\n      if (stream.getdents && offset === 0 && whence === 0) stream.getdents = null;\n      return 0\n    } catch (e) {\n      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);\n      return -e.errno\n    }\n  }\n  function ___syscall145(which, varargs) {\n    SYSCALLS.varargs = varargs;\n    try {\n      var stream = SYSCALLS.getStreamFromFD(),\n        iov = SYSCALLS.get(),\n        iovcnt = SYSCALLS.get();\n      return SYSCALLS.doReadv(stream, iov, iovcnt)\n    } catch (e) {\n      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);\n      return -e.errno\n    }\n  }\n  function ___syscall146(which, varargs) {\n    SYSCALLS.varargs = varargs;\n    try {\n      var stream = SYSCALLS.getStreamFromFD(),\n        iov = SYSCALLS.get(),\n        iovcnt = SYSCALLS.get();\n      return SYSCALLS.doWritev(stream, iov, iovcnt)\n    } catch (e) {\n      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);\n      return -e.errno\n    }\n  }\n  function ___syscall183(which, varargs) {\n    SYSCALLS.varargs = varargs;\n    try {\n      var buf = SYSCALLS.get(),\n        size = SYSCALLS.get();\n      if (size === 0) return -ERRNO_CODES.EINVAL\n      var cwd = FS.cwd();\n      var cwdLengthInBytes = lengthBytesUTF8(cwd);\n      if (size < cwdLengthInBytes + 1) return -ERRNO_CODES.ERANGE\n      stringToUTF8(cwd, buf, size);\n      return buf\n    } catch (e) {\n      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);\n      return -e.errno\n    }\n  }\n  function ___syscall198(which, varargs) {\n    SYSCALLS.varargs = varargs;\n    try {\n      var path = SYSCALLS.getStr(),\n        owner = SYSCALLS.get(),\n        group = SYSCALLS.get();\n      FS.chown(path, owner, group);\n      return 0\n    } catch (e) {\n      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);\n      return -e.errno\n    }\n  }\n  var PROCINFO = { ppid: 1, pid: 42, sid: 42, pgid: 42 };\n  function ___syscall20(which, varargs) {\n    SYSCALLS.varargs = varargs;\n    try {\n      return PROCINFO.pid\n    } catch (e) {\n      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);\n      return -e.errno\n    }\n  }\n  function ___syscall6(which, varargs) {\n    SYSCALLS.varargs = varargs;\n    try {\n      var stream = SYSCALLS.getStreamFromFD();\n      FS.close(stream);\n      return 0\n    } catch (e) {\n      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);\n      return -e.errno\n    }\n  }\n  function ___syscall60(which, varargs) {\n    SYSCALLS.varargs = varargs;\n    try {\n      var mask = SYSCALLS.get();\n      var old = SYSCALLS.umask;\n      SYSCALLS.umask = mask;\n      return old\n    } catch (e) {\n      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);\n      return -e.errno\n    }\n  }\n  function ___syscall83(which, varargs) {\n    SYSCALLS.varargs = varargs;\n    try {\n      var target = SYSCALLS.getStr(),\n        linkpath = SYSCALLS.getStr();\n      FS.symlink(target, linkpath);\n      return 0\n    } catch (e) {\n      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);\n      return -e.errno\n    }\n  }\n  function ___syscall91(which, varargs) {\n    SYSCALLS.varargs = varargs;\n    try {\n      var addr = SYSCALLS.get(),\n        len = SYSCALLS.get();\n      var info = SYSCALLS.mappings[addr];\n      if (!info) return 0\n      if (len === info.len) {\n        var stream = FS.getStream(info.fd);\n        SYSCALLS.doMsync(addr, stream, len, info.flags);\n        FS.munmap(stream);\n        SYSCALLS.mappings[addr] = null;\n        if (info.allocated) {\n          _free(info.malloc);\n        }\n      }\n      return 0\n    } catch (e) {\n      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);\n      return -e.errno\n    }\n  }\n  function ___unlock() {}\n  var structRegistrations = {};\n  function runDestructors(destructors) {\n    while (destructors.length) {\n      var ptr = destructors.pop();\n      var del = destructors.pop();\n      del(ptr);\n    }\n  }\n  function simpleReadValueFromPointer(pointer) {\n    return this['fromWireType'](HEAPU32[pointer >> 2])\n  }\n  var awaitingDependencies = {};\n  var registeredTypes = {};\n  var typeDependencies = {};\n  var char_0 = 48;\n  var char_9 = 57;\n  function makeLegalFunctionName(name) {\n    if (undefined === name) {\n      return '_unknown'\n    }\n    name = name.replace(/[^a-zA-Z0-9_]/g, '$');\n    var f = name.charCodeAt(0);\n    if (f >= char_0 && f <= char_9) {\n      return '_' + name\n    } else {\n      return name\n    }\n  }\n  function createNamedFunction(name, body) {\n    name = makeLegalFunctionName(name);\n    return new Function(\n      'body',\n      'return function ' + name + '() {\\n' + '    \"use strict\";' + '    return body.apply(this, arguments);\\n' + '};\\n'\n    )(body)\n  }\n  function extendError(baseErrorType, errorName) {\n    var errorClass = createNamedFunction(errorName, function (message) {\n      this.name = errorName;\n      this.message = message;\n      var stack = new Error(message).stack;\n      if (stack !== undefined) {\n        this.stack = this.toString() + '\\n' + stack.replace(/^Error(:[^\\n]*)?\\n/, '');\n      }\n    });\n    errorClass.prototype = Object.create(baseErrorType.prototype);\n    errorClass.prototype.constructor = errorClass;\n    errorClass.prototype.toString = function () {\n      if (this.message === undefined) {\n        return this.name\n      } else {\n        return this.name + ': ' + this.message\n      }\n    };\n    return errorClass\n  }\n  var InternalError = undefined;\n  function throwInternalError(message) {\n    throw new InternalError(message)\n  }\n  function whenDependentTypesAreResolved(myTypes, dependentTypes, getTypeConverters) {\n    myTypes.forEach(function (type) {\n      typeDependencies[type] = dependentTypes;\n    });\n    function onComplete(typeConverters) {\n      var myTypeConverters = getTypeConverters(typeConverters);\n      if (myTypeConverters.length !== myTypes.length) {\n        throwInternalError('Mismatched type converter count');\n      }\n      for (var i = 0; i < myTypes.length; ++i) {\n        registerType(myTypes[i], myTypeConverters[i]);\n      }\n    }\n    var typeConverters = new Array(dependentTypes.length);\n    var unregisteredTypes = [];\n    var registered = 0;\n    dependentTypes.forEach(function (dt, i) {\n      if (registeredTypes.hasOwnProperty(dt)) {\n        typeConverters[i] = registeredTypes[dt];\n      } else {\n        unregisteredTypes.push(dt);\n        if (!awaitingDependencies.hasOwnProperty(dt)) {\n          awaitingDependencies[dt] = [];\n        }\n        awaitingDependencies[dt].push(function () {\n          typeConverters[i] = registeredTypes[dt];\n          ++registered;\n          if (registered === unregisteredTypes.length) {\n            onComplete(typeConverters);\n          }\n        });\n      }\n    });\n    if (0 === unregisteredTypes.length) {\n      onComplete(typeConverters);\n    }\n  }\n  function __embind_finalize_value_object(structType) {\n    var reg = structRegistrations[structType];\n    delete structRegistrations[structType];\n    var rawConstructor = reg.rawConstructor;\n    var rawDestructor = reg.rawDestructor;\n    var fieldRecords = reg.fields;\n    var fieldTypes = fieldRecords\n      .map(function (field) {\n        return field.getterReturnType\n      })\n      .concat(\n        fieldRecords.map(function (field) {\n          return field.setterArgumentType\n        })\n      );\n    whenDependentTypesAreResolved([structType], fieldTypes, function (fieldTypes) {\n      var fields = {};\n      fieldRecords.forEach(function (field, i) {\n        var fieldName = field.fieldName;\n        var getterReturnType = fieldTypes[i];\n        var getter = field.getter;\n        var getterContext = field.getterContext;\n        var setterArgumentType = fieldTypes[i + fieldRecords.length];\n        var setter = field.setter;\n        var setterContext = field.setterContext;\n        fields[fieldName] = {\n          read: function (ptr) {\n            return getterReturnType['fromWireType'](getter(getterContext, ptr))\n          },\n          write: function (ptr, o) {\n            var destructors = [];\n            setter(setterContext, ptr, setterArgumentType['toWireType'](destructors, o));\n            runDestructors(destructors);\n          },\n        };\n      });\n      return [\n        {\n          name: reg.name,\n          fromWireType: function (ptr) {\n            var rv = {};\n            for (var i in fields) {\n              rv[i] = fields[i].read(ptr);\n            }\n            rawDestructor(ptr);\n            return rv\n          },\n          toWireType: function (destructors, o) {\n            for (var fieldName in fields) {\n              if (!(fieldName in o)) {\n                throw new TypeError('Missing field')\n              }\n            }\n            var ptr = rawConstructor();\n            for (fieldName in fields) {\n              fields[fieldName].write(ptr, o[fieldName]);\n            }\n            if (destructors !== null) {\n              destructors.push(rawDestructor, ptr);\n            }\n            return ptr\n          },\n          argPackAdvance: 8,\n          readValueFromPointer: simpleReadValueFromPointer,\n          destructorFunction: rawDestructor,\n        },\n      ]\n    });\n  }\n  function getShiftFromSize(size) {\n    switch (size) {\n      case 1:\n        return 0\n      case 2:\n        return 1\n      case 4:\n        return 2\n      case 8:\n        return 3\n      default:\n        throw new TypeError('Unknown type size: ' + size)\n    }\n  }\n  function embind_init_charCodes() {\n    var codes = new Array(256);\n    for (var i = 0; i < 256; ++i) {\n      codes[i] = String.fromCharCode(i);\n    }\n    embind_charCodes = codes;\n  }\n  var embind_charCodes = undefined;\n  function readLatin1String(ptr) {\n    var ret = '';\n    var c = ptr;\n    while (HEAPU8[c]) {\n      ret += embind_charCodes[HEAPU8[c++]];\n    }\n    return ret\n  }\n  var BindingError = undefined;\n  function throwBindingError(message) {\n    throw new BindingError(message)\n  }\n  function registerType(rawType, registeredInstance, options) {\n    options = options || {};\n    if (!('argPackAdvance' in registeredInstance)) {\n      throw new TypeError('registerType registeredInstance requires argPackAdvance')\n    }\n    var name = registeredInstance.name;\n    if (!rawType) {\n      throwBindingError('type \"' + name + '\" must have a positive integer typeid pointer');\n    }\n    if (registeredTypes.hasOwnProperty(rawType)) {\n      if (options.ignoreDuplicateRegistrations) {\n        return\n      } else {\n        throwBindingError(\"Cannot register type '\" + name + \"' twice\");\n      }\n    }\n    registeredTypes[rawType] = registeredInstance;\n    delete typeDependencies[rawType];\n    if (awaitingDependencies.hasOwnProperty(rawType)) {\n      var callbacks = awaitingDependencies[rawType];\n      delete awaitingDependencies[rawType];\n      callbacks.forEach(function (cb) {\n        cb();\n      });\n    }\n  }\n  function __embind_register_bool(rawType, name, size, trueValue, falseValue) {\n    var shift = getShiftFromSize(size);\n    name = readLatin1String(name);\n    registerType(rawType, {\n      name: name,\n      fromWireType: function (wt) {\n        return !!wt\n      },\n      toWireType: function (destructors, o) {\n        return o ? trueValue : falseValue\n      },\n      argPackAdvance: 8,\n      readValueFromPointer: function (pointer) {\n        var heap;\n        if (size === 1) {\n          heap = HEAP8;\n        } else if (size === 2) {\n          heap = HEAP16;\n        } else if (size === 4) {\n          heap = HEAP32;\n        } else {\n          throw new TypeError('Unknown boolean type size: ' + name)\n        }\n        return this['fromWireType'](heap[pointer >> shift])\n      },\n      destructorFunction: null,\n    });\n  }\n  function ClassHandle_isAliasOf(other) {\n    if (!(this instanceof ClassHandle)) {\n      return false\n    }\n    if (!(other instanceof ClassHandle)) {\n      return false\n    }\n    var leftClass = this.$$.ptrType.registeredClass;\n    var left = this.$$.ptr;\n    var rightClass = other.$$.ptrType.registeredClass;\n    var right = other.$$.ptr;\n    while (leftClass.baseClass) {\n      left = leftClass.upcast(left);\n      leftClass = leftClass.baseClass;\n    }\n    while (rightClass.baseClass) {\n      right = rightClass.upcast(right);\n      rightClass = rightClass.baseClass;\n    }\n    return leftClass === rightClass && left === right\n  }\n  function shallowCopyInternalPointer(o) {\n    return {\n      count: o.count,\n      deleteScheduled: o.deleteScheduled,\n      preservePointerOnDelete: o.preservePointerOnDelete,\n      ptr: o.ptr,\n      ptrType: o.ptrType,\n      smartPtr: o.smartPtr,\n      smartPtrType: o.smartPtrType,\n    }\n  }\n  function throwInstanceAlreadyDeleted(obj) {\n    function getInstanceTypeName(handle) {\n      return handle.$$.ptrType.registeredClass.name\n    }\n    throwBindingError(getInstanceTypeName(obj) + ' instance already deleted');\n  }\n  function ClassHandle_clone() {\n    if (!this.$$.ptr) {\n      throwInstanceAlreadyDeleted(this);\n    }\n    if (this.$$.preservePointerOnDelete) {\n      this.$$.count.value += 1;\n      return this\n    } else {\n      var clone = Object.create(Object.getPrototypeOf(this), { $$: { value: shallowCopyInternalPointer(this.$$) } });\n      clone.$$.count.value += 1;\n      clone.$$.deleteScheduled = false;\n      return clone\n    }\n  }\n  function runDestructor(handle) {\n    var $$ = handle.$$;\n    if ($$.smartPtr) {\n      $$.smartPtrType.rawDestructor($$.smartPtr);\n    } else {\n      $$.ptrType.registeredClass.rawDestructor($$.ptr);\n    }\n  }\n  function ClassHandle_delete() {\n    if (!this.$$.ptr) {\n      throwInstanceAlreadyDeleted(this);\n    }\n    if (this.$$.deleteScheduled && !this.$$.preservePointerOnDelete) {\n      throwBindingError('Object already scheduled for deletion');\n    }\n    this.$$.count.value -= 1;\n    var toDelete = 0 === this.$$.count.value;\n    if (toDelete) {\n      runDestructor(this);\n    }\n    if (!this.$$.preservePointerOnDelete) {\n      this.$$.smartPtr = undefined;\n      this.$$.ptr = undefined;\n    }\n  }\n  function ClassHandle_isDeleted() {\n    return !this.$$.ptr\n  }\n  var delayFunction = undefined;\n  var deletionQueue = [];\n  function flushPendingDeletes() {\n    while (deletionQueue.length) {\n      var obj = deletionQueue.pop();\n      obj.$$.deleteScheduled = false;\n      obj['delete']();\n    }\n  }\n  function ClassHandle_deleteLater() {\n    if (!this.$$.ptr) {\n      throwInstanceAlreadyDeleted(this);\n    }\n    if (this.$$.deleteScheduled && !this.$$.preservePointerOnDelete) {\n      throwBindingError('Object already scheduled for deletion');\n    }\n    deletionQueue.push(this);\n    if (deletionQueue.length === 1 && delayFunction) {\n      delayFunction(flushPendingDeletes);\n    }\n    this.$$.deleteScheduled = true;\n    return this\n  }\n  function init_ClassHandle() {\n    ClassHandle.prototype['isAliasOf'] = ClassHandle_isAliasOf;\n    ClassHandle.prototype['clone'] = ClassHandle_clone;\n    ClassHandle.prototype['delete'] = ClassHandle_delete;\n    ClassHandle.prototype['isDeleted'] = ClassHandle_isDeleted;\n    ClassHandle.prototype['deleteLater'] = ClassHandle_deleteLater;\n  }\n  function ClassHandle() {}\n  var registeredPointers = {};\n  function ensureOverloadTable(proto, methodName, humanName) {\n    if (undefined === proto[methodName].overloadTable) {\n      var prevFunc = proto[methodName];\n      proto[methodName] = function () {\n        if (!proto[methodName].overloadTable.hasOwnProperty(arguments.length)) {\n          throwBindingError(\n            \"Function '\" +\n              humanName +\n              \"' called with an invalid number of arguments (\" +\n              arguments.length +\n              ') - expects one of (' +\n              proto[methodName].overloadTable +\n              ')!'\n          );\n        }\n        return proto[methodName].overloadTable[arguments.length].apply(this, arguments)\n      };\n      proto[methodName].overloadTable = [];\n      proto[methodName].overloadTable[prevFunc.argCount] = prevFunc;\n    }\n  }\n  function exposePublicSymbol(name, value, numArguments) {\n    if (Module.hasOwnProperty(name)) {\n      if (\n        undefined === numArguments ||\n        (undefined !== Module[name].overloadTable && undefined !== Module[name].overloadTable[numArguments])\n      ) {\n        throwBindingError(\"Cannot register public name '\" + name + \"' twice\");\n      }\n      ensureOverloadTable(Module, name, name);\n      if (Module.hasOwnProperty(numArguments)) {\n        throwBindingError(\n          'Cannot register multiple overloads of a function with the same number of arguments (' + numArguments + ')!'\n        );\n      }\n      Module[name].overloadTable[numArguments] = value;\n    } else {\n      Module[name] = value;\n      if (undefined !== numArguments) {\n        Module[name].numArguments = numArguments;\n      }\n    }\n  }\n  function RegisteredClass(\n    name,\n    constructor,\n    instancePrototype,\n    rawDestructor,\n    baseClass,\n    getActualType,\n    upcast,\n    downcast\n  ) {\n    this.name = name;\n    this.constructor = constructor;\n    this.instancePrototype = instancePrototype;\n    this.rawDestructor = rawDestructor;\n    this.baseClass = baseClass;\n    this.getActualType = getActualType;\n    this.upcast = upcast;\n    this.downcast = downcast;\n    this.pureVirtualFunctions = [];\n  }\n  function upcastPointer(ptr, ptrClass, desiredClass) {\n    while (ptrClass !== desiredClass) {\n      if (!ptrClass.upcast) {\n        throwBindingError('Expected null or instance of ' + desiredClass.name + ', got an instance of ' + ptrClass.name);\n      }\n      ptr = ptrClass.upcast(ptr);\n      ptrClass = ptrClass.baseClass;\n    }\n    return ptr\n  }\n  function constNoSmartPtrRawPointerToWireType(destructors, handle) {\n    if (handle === null) {\n      if (this.isReference) {\n        throwBindingError('null is not a valid ' + this.name);\n      }\n      return 0\n    }\n    if (!handle.$$) {\n      throwBindingError('Cannot pass \"' + _embind_repr(handle) + '\" as a ' + this.name);\n    }\n    if (!handle.$$.ptr) {\n      throwBindingError('Cannot pass deleted object as a pointer of type ' + this.name);\n    }\n    var handleClass = handle.$$.ptrType.registeredClass;\n    var ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass);\n    return ptr\n  }\n  function genericPointerToWireType(destructors, handle) {\n    var ptr;\n    if (handle === null) {\n      if (this.isReference) {\n        throwBindingError('null is not a valid ' + this.name);\n      }\n      if (this.isSmartPointer) {\n        ptr = this.rawConstructor();\n        if (destructors !== null) {\n          destructors.push(this.rawDestructor, ptr);\n        }\n        return ptr\n      } else {\n        return 0\n      }\n    }\n    if (!handle.$$) {\n      throwBindingError('Cannot pass \"' + _embind_repr(handle) + '\" as a ' + this.name);\n    }\n    if (!handle.$$.ptr) {\n      throwBindingError('Cannot pass deleted object as a pointer of type ' + this.name);\n    }\n    if (!this.isConst && handle.$$.ptrType.isConst) {\n      throwBindingError(\n        'Cannot convert argument of type ' +\n          (handle.$$.smartPtrType ? handle.$$.smartPtrType.name : handle.$$.ptrType.name) +\n          ' to parameter type ' +\n          this.name\n      );\n    }\n    var handleClass = handle.$$.ptrType.registeredClass;\n    ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass);\n    if (this.isSmartPointer) {\n      if (undefined === handle.$$.smartPtr) {\n        throwBindingError('Passing raw pointer to smart pointer is illegal');\n      }\n      switch (this.sharingPolicy) {\n        case 0:\n          if (handle.$$.smartPtrType === this) {\n            ptr = handle.$$.smartPtr;\n          } else {\n            throwBindingError(\n              'Cannot convert argument of type ' +\n                (handle.$$.smartPtrType ? handle.$$.smartPtrType.name : handle.$$.ptrType.name) +\n                ' to parameter type ' +\n                this.name\n            );\n          }\n          break\n        case 1:\n          ptr = handle.$$.smartPtr;\n          break\n        case 2:\n          if (handle.$$.smartPtrType === this) {\n            ptr = handle.$$.smartPtr;\n          } else {\n            var clonedHandle = handle['clone']();\n            ptr = this.rawShare(\n              ptr,\n              __emval_register(function () {\n                clonedHandle['delete']();\n              })\n            );\n            if (destructors !== null) {\n              destructors.push(this.rawDestructor, ptr);\n            }\n          }\n          break\n        default:\n          throwBindingError('Unsupporting sharing policy');\n      }\n    }\n    return ptr\n  }\n  function nonConstNoSmartPtrRawPointerToWireType(destructors, handle) {\n    if (handle === null) {\n      if (this.isReference) {\n        throwBindingError('null is not a valid ' + this.name);\n      }\n      return 0\n    }\n    if (!handle.$$) {\n      throwBindingError('Cannot pass \"' + _embind_repr(handle) + '\" as a ' + this.name);\n    }\n    if (!handle.$$.ptr) {\n      throwBindingError('Cannot pass deleted object as a pointer of type ' + this.name);\n    }\n    if (handle.$$.ptrType.isConst) {\n      throwBindingError('Cannot convert argument of type ' + handle.$$.ptrType.name + ' to parameter type ' + this.name);\n    }\n    var handleClass = handle.$$.ptrType.registeredClass;\n    var ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass);\n    return ptr\n  }\n  function RegisteredPointer_getPointee(ptr) {\n    if (this.rawGetPointee) {\n      ptr = this.rawGetPointee(ptr);\n    }\n    return ptr\n  }\n  function RegisteredPointer_destructor(ptr) {\n    if (this.rawDestructor) {\n      this.rawDestructor(ptr);\n    }\n  }\n  function RegisteredPointer_deleteObject(handle) {\n    if (handle !== null) {\n      handle['delete']();\n    }\n  }\n  function downcastPointer(ptr, ptrClass, desiredClass) {\n    if (ptrClass === desiredClass) {\n      return ptr\n    }\n    if (undefined === desiredClass.baseClass) {\n      return null\n    }\n    var rv = downcastPointer(ptr, ptrClass, desiredClass.baseClass);\n    if (rv === null) {\n      return null\n    }\n    return desiredClass.downcast(rv)\n  }\n  function getInheritedInstanceCount() {\n    return Object.keys(registeredInstances).length\n  }\n  function getLiveInheritedInstances() {\n    var rv = [];\n    for (var k in registeredInstances) {\n      if (registeredInstances.hasOwnProperty(k)) {\n        rv.push(registeredInstances[k]);\n      }\n    }\n    return rv\n  }\n  function setDelayFunction(fn) {\n    delayFunction = fn;\n    if (deletionQueue.length && delayFunction) {\n      delayFunction(flushPendingDeletes);\n    }\n  }\n  function init_embind() {\n    Module['getInheritedInstanceCount'] = getInheritedInstanceCount;\n    Module['getLiveInheritedInstances'] = getLiveInheritedInstances;\n    Module['flushPendingDeletes'] = flushPendingDeletes;\n    Module['setDelayFunction'] = setDelayFunction;\n  }\n  var registeredInstances = {};\n  function getBasestPointer(class_, ptr) {\n    if (ptr === undefined) {\n      throwBindingError('ptr should not be undefined');\n    }\n    while (class_.baseClass) {\n      ptr = class_.upcast(ptr);\n      class_ = class_.baseClass;\n    }\n    return ptr\n  }\n  function getInheritedInstance(class_, ptr) {\n    ptr = getBasestPointer(class_, ptr);\n    return registeredInstances[ptr]\n  }\n  function makeClassHandle(prototype, record) {\n    if (!record.ptrType || !record.ptr) {\n      throwInternalError('makeClassHandle requires ptr and ptrType');\n    }\n    var hasSmartPtrType = !!record.smartPtrType;\n    var hasSmartPtr = !!record.smartPtr;\n    if (hasSmartPtrType !== hasSmartPtr) {\n      throwInternalError('Both smartPtrType and smartPtr must be specified');\n    }\n    record.count = { value: 1 };\n    return Object.create(prototype, { $$: { value: record } })\n  }\n  function RegisteredPointer_fromWireType(ptr) {\n    var rawPointer = this.getPointee(ptr);\n    if (!rawPointer) {\n      this.destructor(ptr);\n      return null\n    }\n    var registeredInstance = getInheritedInstance(this.registeredClass, rawPointer);\n    if (undefined !== registeredInstance) {\n      if (0 === registeredInstance.$$.count.value) {\n        registeredInstance.$$.ptr = rawPointer;\n        registeredInstance.$$.smartPtr = ptr;\n        return registeredInstance['clone']()\n      } else {\n        var rv = registeredInstance['clone']();\n        this.destructor(ptr);\n        return rv\n      }\n    }\n    function makeDefaultHandle() {\n      if (this.isSmartPointer) {\n        return makeClassHandle(this.registeredClass.instancePrototype, {\n          ptrType: this.pointeeType,\n          ptr: rawPointer,\n          smartPtrType: this,\n          smartPtr: ptr,\n        })\n      } else {\n        return makeClassHandle(this.registeredClass.instancePrototype, { ptrType: this, ptr: ptr })\n      }\n    }\n    var actualType = this.registeredClass.getActualType(rawPointer);\n    var registeredPointerRecord = registeredPointers[actualType];\n    if (!registeredPointerRecord) {\n      return makeDefaultHandle.call(this)\n    }\n    var toType;\n    if (this.isConst) {\n      toType = registeredPointerRecord.constPointerType;\n    } else {\n      toType = registeredPointerRecord.pointerType;\n    }\n    var dp = downcastPointer(rawPointer, this.registeredClass, toType.registeredClass);\n    if (dp === null) {\n      return makeDefaultHandle.call(this)\n    }\n    if (this.isSmartPointer) {\n      return makeClassHandle(toType.registeredClass.instancePrototype, {\n        ptrType: toType,\n        ptr: dp,\n        smartPtrType: this,\n        smartPtr: ptr,\n      })\n    } else {\n      return makeClassHandle(toType.registeredClass.instancePrototype, { ptrType: toType, ptr: dp })\n    }\n  }\n  function init_RegisteredPointer() {\n    RegisteredPointer.prototype.getPointee = RegisteredPointer_getPointee;\n    RegisteredPointer.prototype.destructor = RegisteredPointer_destructor;\n    RegisteredPointer.prototype['argPackAdvance'] = 8;\n    RegisteredPointer.prototype['readValueFromPointer'] = simpleReadValueFromPointer;\n    RegisteredPointer.prototype['deleteObject'] = RegisteredPointer_deleteObject;\n    RegisteredPointer.prototype['fromWireType'] = RegisteredPointer_fromWireType;\n  }\n  function RegisteredPointer(\n    name,\n    registeredClass,\n    isReference,\n    isConst,\n    isSmartPointer,\n    pointeeType,\n    sharingPolicy,\n    rawGetPointee,\n    rawConstructor,\n    rawShare,\n    rawDestructor\n  ) {\n    this.name = name;\n    this.registeredClass = registeredClass;\n    this.isReference = isReference;\n    this.isConst = isConst;\n    this.isSmartPointer = isSmartPointer;\n    this.pointeeType = pointeeType;\n    this.sharingPolicy = sharingPolicy;\n    this.rawGetPointee = rawGetPointee;\n    this.rawConstructor = rawConstructor;\n    this.rawShare = rawShare;\n    this.rawDestructor = rawDestructor;\n    if (!isSmartPointer && registeredClass.baseClass === undefined) {\n      if (isConst) {\n        this['toWireType'] = constNoSmartPtrRawPointerToWireType;\n        this.destructorFunction = null;\n      } else {\n        this['toWireType'] = nonConstNoSmartPtrRawPointerToWireType;\n        this.destructorFunction = null;\n      }\n    } else {\n      this['toWireType'] = genericPointerToWireType;\n    }\n  }\n  function replacePublicSymbol(name, value, numArguments) {\n    if (!Module.hasOwnProperty(name)) {\n      throwInternalError('Replacing nonexistant public symbol');\n    }\n    if (undefined !== Module[name].overloadTable && undefined !== numArguments) {\n      Module[name].overloadTable[numArguments] = value;\n    } else {\n      Module[name] = value;\n      Module[name].argCount = numArguments;\n    }\n  }\n  function embind__requireFunction(signature, rawFunction) {\n    signature = readLatin1String(signature);\n    function makeDynCaller(dynCall) {\n      var args = [];\n      for (var i = 1; i < signature.length; ++i) {\n        args.push('a' + i);\n      }\n      var name = 'dynCall_' + signature + '_' + rawFunction;\n      var body = 'return function ' + name + '(' + args.join(', ') + ') {\\n';\n      body += '    return dynCall(rawFunction' + (args.length ? ', ' : '') + args.join(', ') + ');\\n';\n      body += '};\\n';\n      return new Function('dynCall', 'rawFunction', body)(dynCall, rawFunction)\n    }\n    var fp;\n    if (Module['FUNCTION_TABLE_' + signature] !== undefined) {\n      fp = Module['FUNCTION_TABLE_' + signature][rawFunction];\n    } else if (typeof FUNCTION_TABLE !== 'undefined') {\n      fp = FUNCTION_TABLE[rawFunction];\n    } else {\n      var dc = Module['asm']['dynCall_' + signature];\n      if (dc === undefined) {\n        dc = Module['asm']['dynCall_' + signature.replace(/f/g, 'd')];\n        if (dc === undefined) {\n          throwBindingError('No dynCall invoker for signature: ' + signature);\n        }\n      }\n      fp = makeDynCaller(dc);\n    }\n    if (typeof fp !== 'function') {\n      throwBindingError('unknown function pointer with signature ' + signature + ': ' + rawFunction);\n    }\n    return fp\n  }\n  var UnboundTypeError = undefined;\n  function getTypeName(type) {\n    var ptr = ___getTypeName(type);\n    var rv = readLatin1String(ptr);\n    _free(ptr);\n    return rv\n  }\n  function throwUnboundTypeError(message, types) {\n    var unboundTypes = [];\n    var seen = {};\n    function visit(type) {\n      if (seen[type]) {\n        return\n      }\n      if (registeredTypes[type]) {\n        return\n      }\n      if (typeDependencies[type]) {\n        typeDependencies[type].forEach(visit);\n        return\n      }\n      unboundTypes.push(type);\n      seen[type] = true;\n    }\n    types.forEach(visit);\n    throw new UnboundTypeError(message + ': ' + unboundTypes.map(getTypeName).join([', ']))\n  }\n  function __embind_register_class(\n    rawType,\n    rawPointerType,\n    rawConstPointerType,\n    baseClassRawType,\n    getActualTypeSignature,\n    getActualType,\n    upcastSignature,\n    upcast,\n    downcastSignature,\n    downcast,\n    name,\n    destructorSignature,\n    rawDestructor\n  ) {\n    name = readLatin1String(name);\n    getActualType = embind__requireFunction(getActualTypeSignature, getActualType);\n    if (upcast) {\n      upcast = embind__requireFunction(upcastSignature, upcast);\n    }\n    if (downcast) {\n      downcast = embind__requireFunction(downcastSignature, downcast);\n    }\n    rawDestructor = embind__requireFunction(destructorSignature, rawDestructor);\n    var legalFunctionName = makeLegalFunctionName(name);\n    exposePublicSymbol(legalFunctionName, function () {\n      throwUnboundTypeError('Cannot construct ' + name + ' due to unbound types', [baseClassRawType]);\n    });\n    whenDependentTypesAreResolved(\n      [rawType, rawPointerType, rawConstPointerType],\n      baseClassRawType ? [baseClassRawType] : [],\n      function (base) {\n        base = base[0];\n        var baseClass;\n        var basePrototype;\n        if (baseClassRawType) {\n          baseClass = base.registeredClass;\n          basePrototype = baseClass.instancePrototype;\n        } else {\n          basePrototype = ClassHandle.prototype;\n        }\n        var constructor = createNamedFunction(legalFunctionName, function () {\n          if (Object.getPrototypeOf(this) !== instancePrototype) {\n            throw new BindingError(\"Use 'new' to construct \" + name)\n          }\n          if (undefined === registeredClass.constructor_body) {\n            throw new BindingError(name + ' has no accessible constructor')\n          }\n          var body = registeredClass.constructor_body[arguments.length];\n          if (undefined === body) {\n            throw new BindingError(\n              'Tried to invoke ctor of ' +\n                name +\n                ' with invalid number of parameters (' +\n                arguments.length +\n                ') - expected (' +\n                Object.keys(registeredClass.constructor_body).toString() +\n                ') parameters instead!'\n            )\n          }\n          return body.apply(this, arguments)\n        });\n        var instancePrototype = Object.create(basePrototype, { constructor: { value: constructor } });\n        constructor.prototype = instancePrototype;\n        var registeredClass = new RegisteredClass(\n          name,\n          constructor,\n          instancePrototype,\n          rawDestructor,\n          baseClass,\n          getActualType,\n          upcast,\n          downcast\n        );\n        var referenceConverter = new RegisteredPointer(name, registeredClass, true, false, false);\n        var pointerConverter = new RegisteredPointer(name + '*', registeredClass, false, false, false);\n        var constPointerConverter = new RegisteredPointer(name + ' const*', registeredClass, false, true, false);\n        registeredPointers[rawType] = { pointerType: pointerConverter, constPointerType: constPointerConverter };\n        replacePublicSymbol(legalFunctionName, constructor);\n        return [referenceConverter, pointerConverter, constPointerConverter]\n      }\n    );\n  }\n  function heap32VectorToArray(count, firstElement) {\n    var array = [];\n    for (var i = 0; i < count; i++) {\n      array.push(HEAP32[(firstElement >> 2) + i]);\n    }\n    return array\n  }\n  function __embind_register_class_constructor(\n    rawClassType,\n    argCount,\n    rawArgTypesAddr,\n    invokerSignature,\n    invoker,\n    rawConstructor\n  ) {\n    var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr);\n    invoker = embind__requireFunction(invokerSignature, invoker);\n    whenDependentTypesAreResolved([], [rawClassType], function (classType) {\n      classType = classType[0];\n      var humanName = 'constructor ' + classType.name;\n      if (undefined === classType.registeredClass.constructor_body) {\n        classType.registeredClass.constructor_body = [];\n      }\n      if (undefined !== classType.registeredClass.constructor_body[argCount - 1]) {\n        throw new BindingError(\n          'Cannot register multiple constructors with identical number of parameters (' +\n            (argCount - 1) +\n            \") for class '\" +\n            classType.name +\n            \"'! Overload resolution is currently only performed using the parameter count, not actual type info!\"\n        )\n      }\n      classType.registeredClass.constructor_body[argCount - 1] = function unboundTypeHandler() {\n        throwUnboundTypeError('Cannot construct ' + classType.name + ' due to unbound types', rawArgTypes);\n      };\n      whenDependentTypesAreResolved([], rawArgTypes, function (argTypes) {\n        classType.registeredClass.constructor_body[argCount - 1] = function constructor_body() {\n          if (arguments.length !== argCount - 1) {\n            throwBindingError(humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount - 1));\n          }\n          var destructors = [];\n          var args = new Array(argCount);\n          args[0] = rawConstructor;\n          for (var i = 1; i < argCount; ++i) {\n            args[i] = argTypes[i]['toWireType'](destructors, arguments[i - 1]);\n          }\n          var ptr = invoker.apply(null, args);\n          runDestructors(destructors);\n          return argTypes[0]['fromWireType'](ptr)\n        };\n        return []\n      });\n      return []\n    });\n  }\n  function new_(constructor, argumentList) {\n    if (!(constructor instanceof Function)) {\n      throw new TypeError('new_ called with constructor type ' + typeof constructor + ' which is not a function')\n    }\n    var dummy = createNamedFunction(constructor.name || 'unknownFunctionName', function () {});\n    dummy.prototype = constructor.prototype;\n    var obj = new dummy();\n    var r = constructor.apply(obj, argumentList);\n    return r instanceof Object ? r : obj\n  }\n  function craftInvokerFunction(humanName, argTypes, classType, cppInvokerFunc, cppTargetFunc) {\n    var argCount = argTypes.length;\n    if (argCount < 2) {\n      throwBindingError(\"argTypes array size mismatch! Must at least get return value and 'this' types!\");\n    }\n    var isClassMethodFunc = argTypes[1] !== null && classType !== null;\n    var needsDestructorStack = false;\n    for (var i = 1; i < argTypes.length; ++i) {\n      if (argTypes[i] !== null && argTypes[i].destructorFunction === undefined) {\n        needsDestructorStack = true;\n        break\n      }\n    }\n    var returns = argTypes[0].name !== 'void';\n    var argsList = '';\n    var argsListWired = '';\n    for (var i = 0; i < argCount - 2; ++i) {\n      argsList += (i !== 0 ? ', ' : '') + 'arg' + i;\n      argsListWired += (i !== 0 ? ', ' : '') + 'arg' + i + 'Wired';\n    }\n    var invokerFnBody =\n      'return function ' +\n      makeLegalFunctionName(humanName) +\n      '(' +\n      argsList +\n      ') {\\n' +\n      'if (arguments.length !== ' +\n      (argCount - 2) +\n      ') {\\n' +\n      \"throwBindingError('function \" +\n      humanName +\n      \" called with ' + arguments.length + ' arguments, expected \" +\n      (argCount - 2) +\n      \" args!');\\n\" +\n      '}\\n';\n    if (needsDestructorStack) {\n      invokerFnBody += 'var destructors = [];\\n';\n    }\n    var dtorStack = needsDestructorStack ? 'destructors' : 'null';\n    var args1 = ['throwBindingError', 'invoker', 'fn', 'runDestructors', 'retType', 'classParam'];\n    var args2 = [throwBindingError, cppInvokerFunc, cppTargetFunc, runDestructors, argTypes[0], argTypes[1]];\n    if (isClassMethodFunc) {\n      invokerFnBody += 'var thisWired = classParam.toWireType(' + dtorStack + ', this);\\n';\n    }\n    for (var i = 0; i < argCount - 2; ++i) {\n      invokerFnBody +=\n        'var arg' +\n        i +\n        'Wired = argType' +\n        i +\n        '.toWireType(' +\n        dtorStack +\n        ', arg' +\n        i +\n        '); // ' +\n        argTypes[i + 2].name +\n        '\\n';\n      args1.push('argType' + i);\n      args2.push(argTypes[i + 2]);\n    }\n    if (isClassMethodFunc) {\n      argsListWired = 'thisWired' + (argsListWired.length > 0 ? ', ' : '') + argsListWired;\n    }\n    invokerFnBody +=\n      (returns ? 'var rv = ' : '') + 'invoker(fn' + (argsListWired.length > 0 ? ', ' : '') + argsListWired + ');\\n';\n    if (needsDestructorStack) {\n      invokerFnBody += 'runDestructors(destructors);\\n';\n    } else {\n      for (var i = isClassMethodFunc ? 1 : 2; i < argTypes.length; ++i) {\n        var paramName = i === 1 ? 'thisWired' : 'arg' + (i - 2) + 'Wired';\n        if (argTypes[i].destructorFunction !== null) {\n          invokerFnBody += paramName + '_dtor(' + paramName + '); // ' + argTypes[i].name + '\\n';\n          args1.push(paramName + '_dtor');\n          args2.push(argTypes[i].destructorFunction);\n        }\n      }\n    }\n    if (returns) {\n      invokerFnBody += 'var ret = retType.fromWireType(rv);\\n' + 'return ret;\\n';\n    }\n    invokerFnBody += '}\\n';\n    args1.push(invokerFnBody);\n    var invokerFunction = new_(Function, args1).apply(null, args2);\n    return invokerFunction\n  }\n  function __embind_register_class_function(\n    rawClassType,\n    methodName,\n    argCount,\n    rawArgTypesAddr,\n    invokerSignature,\n    rawInvoker,\n    context,\n    isPureVirtual\n  ) {\n    var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr);\n    methodName = readLatin1String(methodName);\n    rawInvoker = embind__requireFunction(invokerSignature, rawInvoker);\n    whenDependentTypesAreResolved([], [rawClassType], function (classType) {\n      classType = classType[0];\n      var humanName = classType.name + '.' + methodName;\n      if (isPureVirtual) {\n        classType.registeredClass.pureVirtualFunctions.push(methodName);\n      }\n      function unboundTypesHandler() {\n        throwUnboundTypeError('Cannot call ' + humanName + ' due to unbound types', rawArgTypes);\n      }\n      var proto = classType.registeredClass.instancePrototype;\n      var method = proto[methodName];\n      if (\n        undefined === method ||\n        (undefined === method.overloadTable && method.className !== classType.name && method.argCount === argCount - 2)\n      ) {\n        unboundTypesHandler.argCount = argCount - 2;\n        unboundTypesHandler.className = classType.name;\n        proto[methodName] = unboundTypesHandler;\n      } else {\n        ensureOverloadTable(proto, methodName, humanName);\n        proto[methodName].overloadTable[argCount - 2] = unboundTypesHandler;\n      }\n      whenDependentTypesAreResolved([], rawArgTypes, function (argTypes) {\n        var memberFunction = craftInvokerFunction(humanName, argTypes, classType, rawInvoker, context);\n        if (undefined === proto[methodName].overloadTable) {\n          memberFunction.argCount = argCount - 2;\n          proto[methodName] = memberFunction;\n        } else {\n          proto[methodName].overloadTable[argCount - 2] = memberFunction;\n        }\n        return []\n      });\n      return []\n    });\n  }\n  var emval_free_list = [];\n  var emval_handle_array = [{}, { value: undefined }, { value: null }, { value: true }, { value: false }];\n  function __emval_decref(handle) {\n    if (handle > 4 && 0 === --emval_handle_array[handle].refcount) {\n      emval_handle_array[handle] = undefined;\n      emval_free_list.push(handle);\n    }\n  }\n  function count_emval_handles() {\n    var count = 0;\n    for (var i = 5; i < emval_handle_array.length; ++i) {\n      if (emval_handle_array[i] !== undefined) {\n        ++count;\n      }\n    }\n    return count\n  }\n  function get_first_emval() {\n    for (var i = 5; i < emval_handle_array.length; ++i) {\n      if (emval_handle_array[i] !== undefined) {\n        return emval_handle_array[i]\n      }\n    }\n    return null\n  }\n  function init_emval() {\n    Module['count_emval_handles'] = count_emval_handles;\n    Module['get_first_emval'] = get_first_emval;\n  }\n  function __emval_register(value) {\n    switch (value) {\n      case undefined: {\n        return 1\n      }\n      case null: {\n        return 2\n      }\n      case true: {\n        return 3\n      }\n      case false: {\n        return 4\n      }\n      default: {\n        var handle = emval_free_list.length ? emval_free_list.pop() : emval_handle_array.length;\n        emval_handle_array[handle] = { refcount: 1, value: value };\n        return handle\n      }\n    }\n  }\n  function __embind_register_emval(rawType, name) {\n    name = readLatin1String(name);\n    registerType(rawType, {\n      name: name,\n      fromWireType: function (handle) {\n        var rv = emval_handle_array[handle].value;\n        __emval_decref(handle);\n        return rv\n      },\n      toWireType: function (destructors, value) {\n        return __emval_register(value)\n      },\n      argPackAdvance: 8,\n      readValueFromPointer: simpleReadValueFromPointer,\n      destructorFunction: null,\n    });\n  }\n  function _embind_repr(v) {\n    if (v === null) {\n      return 'null'\n    }\n    var t = typeof v;\n    if (t === 'object' || t === 'array' || t === 'function') {\n      return v.toString()\n    } else {\n      return '' + v\n    }\n  }\n  function floatReadValueFromPointer(name, shift) {\n    switch (shift) {\n      case 2:\n        return function (pointer) {\n          return this['fromWireType'](HEAPF32[pointer >> 2])\n        }\n      case 3:\n        return function (pointer) {\n          return this['fromWireType'](HEAPF64[pointer >> 3])\n        }\n      default:\n        throw new TypeError('Unknown float type: ' + name)\n    }\n  }\n  function __embind_register_float(rawType, name, size) {\n    var shift = getShiftFromSize(size);\n    name = readLatin1String(name);\n    registerType(rawType, {\n      name: name,\n      fromWireType: function (value) {\n        return value\n      },\n      toWireType: function (destructors, value) {\n        if (typeof value !== 'number' && typeof value !== 'boolean') {\n          throw new TypeError('Cannot convert \"' + _embind_repr(value) + '\" to ' + this.name)\n        }\n        return value\n      },\n      argPackAdvance: 8,\n      readValueFromPointer: floatReadValueFromPointer(name, shift),\n      destructorFunction: null,\n    });\n  }\n  function integerReadValueFromPointer(name, shift, signed) {\n    switch (shift) {\n      case 0:\n        return signed\n          ? function readS8FromPointer(pointer) {\n              return HEAP8[pointer]\n            }\n          : function readU8FromPointer(pointer) {\n              return HEAPU8[pointer]\n            }\n      case 1:\n        return signed\n          ? function readS16FromPointer(pointer) {\n              return HEAP16[pointer >> 1]\n            }\n          : function readU16FromPointer(pointer) {\n              return HEAPU16[pointer >> 1]\n            }\n      case 2:\n        return signed\n          ? function readS32FromPointer(pointer) {\n              return HEAP32[pointer >> 2]\n            }\n          : function readU32FromPointer(pointer) {\n              return HEAPU32[pointer >> 2]\n            }\n      default:\n        throw new TypeError('Unknown integer type: ' + name)\n    }\n  }\n  function __embind_register_integer(primitiveType, name, size, minRange, maxRange) {\n    name = readLatin1String(name);\n    if (maxRange === -1) {\n      maxRange = 4294967295;\n    }\n    var shift = getShiftFromSize(size);\n    var fromWireType = function (value) {\n      return value\n    };\n    if (minRange === 0) {\n      var bitshift = 32 - 8 * size;\n      fromWireType = function (value) {\n        return (value << bitshift) >>> bitshift\n      };\n    }\n    var isUnsignedType = name.indexOf('unsigned') != -1;\n    registerType(primitiveType, {\n      name: name,\n      fromWireType: fromWireType,\n      toWireType: function (destructors, value) {\n        if (typeof value !== 'number' && typeof value !== 'boolean') {\n          throw new TypeError('Cannot convert \"' + _embind_repr(value) + '\" to ' + this.name)\n        }\n        if (value < minRange || value > maxRange) {\n          throw new TypeError(\n            'Passing a number \"' +\n              _embind_repr(value) +\n              '\" from JS side to C/C++ side to an argument of type \"' +\n              name +\n              '\", which is outside the valid range [' +\n              minRange +\n              ', ' +\n              maxRange +\n              ']!'\n          )\n        }\n        return isUnsignedType ? value >>> 0 : value | 0\n      },\n      argPackAdvance: 8,\n      readValueFromPointer: integerReadValueFromPointer(name, shift, minRange !== 0),\n      destructorFunction: null,\n    });\n  }\n  function __embind_register_memory_view(rawType, dataTypeIndex, name) {\n    var typeMapping = [\n      Int8Array,\n      Uint8Array,\n      Int16Array,\n      Uint16Array,\n      Int32Array,\n      Uint32Array,\n      Float32Array,\n      Float64Array,\n    ];\n    var TA = typeMapping[dataTypeIndex];\n    function decodeMemoryView(handle) {\n      handle = handle >> 2;\n      var heap = HEAPU32;\n      var size = heap[handle];\n      var data = heap[handle + 1];\n      return new TA(heap['buffer'], data, size)\n    }\n    name = readLatin1String(name);\n    registerType(\n      rawType,\n      { name: name, fromWireType: decodeMemoryView, argPackAdvance: 8, readValueFromPointer: decodeMemoryView },\n      { ignoreDuplicateRegistrations: true }\n    );\n  }\n  function __embind_register_std_string(rawType, name) {\n    name = readLatin1String(name);\n    registerType(rawType, {\n      name: name,\n      fromWireType: function (value) {\n        var length = HEAPU32[value >> 2];\n        var a = new Array(length);\n        for (var i = 0; i < length; ++i) {\n          a[i] = String.fromCharCode(HEAPU8[value + 4 + i]);\n        }\n        _free(value);\n        return a.join('')\n      },\n      toWireType: function (destructors, value) {\n        if (value instanceof ArrayBuffer) {\n          value = new Uint8Array(value);\n        }\n        function getTAElement(ta, index) {\n          return ta[index]\n        }\n        function getStringElement(string, index) {\n          return string.charCodeAt(index)\n        }\n        var getElement;\n        if (value instanceof Uint8Array) {\n          getElement = getTAElement;\n        } else if (value instanceof Uint8ClampedArray) {\n          getElement = getTAElement;\n        } else if (value instanceof Int8Array) {\n          getElement = getTAElement;\n        } else if (typeof value === 'string') {\n          getElement = getStringElement;\n        } else {\n          throwBindingError('Cannot pass non-string to std::string');\n        }\n        var length = value.length;\n        var ptr = _malloc(4 + length);\n        HEAPU32[ptr >> 2] = length;\n        for (var i = 0; i < length; ++i) {\n          var charCode = getElement(value, i);\n          if (charCode > 255) {\n            _free(ptr);\n            throwBindingError('String has UTF-16 code units that do not fit in 8 bits');\n          }\n          HEAPU8[ptr + 4 + i] = charCode;\n        }\n        if (destructors !== null) {\n          destructors.push(_free, ptr);\n        }\n        return ptr\n      },\n      argPackAdvance: 8,\n      readValueFromPointer: simpleReadValueFromPointer,\n      destructorFunction: function (ptr) {\n        _free(ptr);\n      },\n    });\n  }\n  function __embind_register_std_wstring(rawType, charSize, name) {\n    name = readLatin1String(name);\n    var getHeap, shift;\n    if (charSize === 2) {\n      getHeap = function () {\n        return HEAPU16\n      };\n      shift = 1;\n    } else if (charSize === 4) {\n      getHeap = function () {\n        return HEAPU32\n      };\n      shift = 2;\n    }\n    registerType(rawType, {\n      name: name,\n      fromWireType: function (value) {\n        var HEAP = getHeap();\n        var length = HEAPU32[value >> 2];\n        var a = new Array(length);\n        var start = (value + 4) >> shift;\n        for (var i = 0; i < length; ++i) {\n          a[i] = String.fromCharCode(HEAP[start + i]);\n        }\n        _free(value);\n        return a.join('')\n      },\n      toWireType: function (destructors, value) {\n        var HEAP = getHeap();\n        var length = value.length;\n        var ptr = _malloc(4 + length * charSize);\n        HEAPU32[ptr >> 2] = length;\n        var start = (ptr + 4) >> shift;\n        for (var i = 0; i < length; ++i) {\n          HEAP[start + i] = value.charCodeAt(i);\n        }\n        if (destructors !== null) {\n          destructors.push(_free, ptr);\n        }\n        return ptr\n      },\n      argPackAdvance: 8,\n      readValueFromPointer: simpleReadValueFromPointer,\n      destructorFunction: function (ptr) {\n        _free(ptr);\n      },\n    });\n  }\n  function __embind_register_value_object(\n    rawType,\n    name,\n    constructorSignature,\n    rawConstructor,\n    destructorSignature,\n    rawDestructor\n  ) {\n    structRegistrations[rawType] = {\n      name: readLatin1String(name),\n      rawConstructor: embind__requireFunction(constructorSignature, rawConstructor),\n      rawDestructor: embind__requireFunction(destructorSignature, rawDestructor),\n      fields: [],\n    };\n  }\n  function __embind_register_value_object_field(\n    structType,\n    fieldName,\n    getterReturnType,\n    getterSignature,\n    getter,\n    getterContext,\n    setterArgumentType,\n    setterSignature,\n    setter,\n    setterContext\n  ) {\n    structRegistrations[structType].fields.push({\n      fieldName: readLatin1String(fieldName),\n      getterReturnType: getterReturnType,\n      getter: embind__requireFunction(getterSignature, getter),\n      getterContext: getterContext,\n      setterArgumentType: setterArgumentType,\n      setter: embind__requireFunction(setterSignature, setter),\n      setterContext: setterContext,\n    });\n  }\n  function __embind_register_void(rawType, name) {\n    name = readLatin1String(name);\n    registerType(rawType, {\n      isVoid: true,\n      name: name,\n      argPackAdvance: 0,\n      fromWireType: function () {\n        return undefined\n      },\n      toWireType: function (destructors, o) {\n        return undefined\n      },\n    });\n  }\n  function _abort() {\n    Module['abort']();\n  }\n  var _environ = STATICTOP;\n  STATICTOP += 16;\n  function ___buildEnvironment(env) {\n    var MAX_ENV_VALUES = 64;\n    var TOTAL_ENV_SIZE = 1024;\n    var poolPtr;\n    var envPtr;\n    if (!___buildEnvironment.called) {\n      ___buildEnvironment.called = true;\n      ENV['USER'] = ENV['LOGNAME'] = 'web_user';\n      ENV['PATH'] = '/';\n      ENV['PWD'] = '/';\n      ENV['HOME'] = '/home/web_user';\n      ENV['LANG'] = 'C.UTF-8';\n      ENV['_'] = Module['thisProgram'];\n      poolPtr = staticAlloc(TOTAL_ENV_SIZE);\n      envPtr = staticAlloc(MAX_ENV_VALUES * 4);\n      HEAP32[envPtr >> 2] = poolPtr;\n      HEAP32[_environ >> 2] = envPtr;\n    } else {\n      envPtr = HEAP32[_environ >> 2];\n      poolPtr = HEAP32[envPtr >> 2];\n    }\n    var strings = [];\n    var totalSize = 0;\n    for (var key in env) {\n      if (typeof env[key] === 'string') {\n        var line = key + '=' + env[key];\n        strings.push(line);\n        totalSize += line.length;\n      }\n    }\n    if (totalSize > TOTAL_ENV_SIZE) {\n      throw new Error('Environment size exceeded TOTAL_ENV_SIZE!')\n    }\n    var ptrSize = 4;\n    for (var i = 0; i < strings.length; i++) {\n      var line = strings[i];\n      writeAsciiToMemory(line, poolPtr);\n      HEAP32[(envPtr + i * ptrSize) >> 2] = poolPtr;\n      poolPtr += line.length + 1;\n    }\n    HEAP32[(envPtr + strings.length * ptrSize) >> 2] = 0;\n  }\n  var ENV = {};\n  function _getenv(name) {\n    if (name === 0) return 0\n    name = Pointer_stringify(name);\n    if (!ENV.hasOwnProperty(name)) return 0\n    if (_getenv.ret) _free(_getenv.ret);\n    _getenv.ret = allocateUTF8(ENV[name]);\n    return _getenv.ret\n  }\n  function _getgrnam() {\n    Module['printErr']('missing function: getgrnam');\n    abort(-1);\n  }\n  function _getpwnam() {\n    throw 'getpwnam: TODO'\n  }\n  function _jsClose() {\n    return jsAPI.close.apply(null, arguments)\n  }\n  function _jsCreate(filename) {\n    return jsAPI.create.call(null, UTF32ToString(filename))\n  }\n  function _jsOpen(filename) {\n    return jsAPI.open.call(null, UTF32ToString(filename))\n  }\n  function _jsRead() {\n    return jsAPI.read.apply(null, arguments)\n  }\n  function _jsSeek(fd, offset, method) {\n    return jsAPI.seek.call(null, fd, offset, UTF8ToString(method))\n  }\n  function _jsTell() {\n    return jsAPI.tell.apply(null, arguments)\n  }\n  function _jsWrite() {\n    return jsAPI.write.apply(null, arguments)\n  }\n  function _llvm_eh_typeid_for(type) {\n    return type\n  }\n  var ___tm_current = STATICTOP;\n  STATICTOP += 48;\n  allocate(intArrayFromString('GMT'), 'i8', ALLOC_STATIC);\n  var _tzname = STATICTOP;\n  STATICTOP += 16;\n  var _daylight = STATICTOP;\n  STATICTOP += 16;\n  var _timezone = STATICTOP;\n  STATICTOP += 16;\n  function _tzset() {\n    if (_tzset.called) return\n    _tzset.called = true;\n    HEAP32[_timezone >> 2] = new Date().getTimezoneOffset() * 60;\n    var winter = new Date(2e3, 0, 1);\n    var summer = new Date(2e3, 6, 1);\n    HEAP32[_daylight >> 2] = Number(winter.getTimezoneOffset() != summer.getTimezoneOffset());\n    function extractZone(date) {\n      var match = date.toTimeString().match(/\\(([A-Za-z ]+)\\)$/);\n      return match ? match[1] : 'GMT'\n    }\n    var winterName = extractZone(winter);\n    var summerName = extractZone(summer);\n    var winterNamePtr = allocate(intArrayFromString(winterName), 'i8', ALLOC_NORMAL);\n    var summerNamePtr = allocate(intArrayFromString(summerName), 'i8', ALLOC_NORMAL);\n    if (summer.getTimezoneOffset() < winter.getTimezoneOffset()) {\n      HEAP32[_tzname >> 2] = winterNamePtr;\n      HEAP32[(_tzname + 4) >> 2] = summerNamePtr;\n    } else {\n      HEAP32[_tzname >> 2] = summerNamePtr;\n      HEAP32[(_tzname + 4) >> 2] = winterNamePtr;\n    }\n  }\n  function _localtime_r(time, tmPtr) {\n    _tzset();\n    var date = new Date(HEAP32[time >> 2] * 1e3);\n    HEAP32[tmPtr >> 2] = date.getSeconds();\n    HEAP32[(tmPtr + 4) >> 2] = date.getMinutes();\n    HEAP32[(tmPtr + 8) >> 2] = date.getHours();\n    HEAP32[(tmPtr + 12) >> 2] = date.getDate();\n    HEAP32[(tmPtr + 16) >> 2] = date.getMonth();\n    HEAP32[(tmPtr + 20) >> 2] = date.getFullYear() - 1900;\n    HEAP32[(tmPtr + 24) >> 2] = date.getDay();\n    var start = new Date(date.getFullYear(), 0, 1);\n    var yday = ((date.getTime() - start.getTime()) / (1e3 * 60 * 60 * 24)) | 0;\n    HEAP32[(tmPtr + 28) >> 2] = yday;\n    HEAP32[(tmPtr + 36) >> 2] = -(date.getTimezoneOffset() * 60);\n    var summerOffset = new Date(2e3, 6, 1).getTimezoneOffset();\n    var winterOffset = start.getTimezoneOffset();\n    var dst = (summerOffset != winterOffset && date.getTimezoneOffset() == Math.min(winterOffset, summerOffset)) | 0;\n    HEAP32[(tmPtr + 32) >> 2] = dst;\n    var zonePtr = HEAP32[(_tzname + (dst ? 4 : 0)) >> 2];\n    HEAP32[(tmPtr + 40) >> 2] = zonePtr;\n    return tmPtr\n  }\n  function _localtime(time) {\n    return _localtime_r(time, ___tm_current)\n  }\n  function _emscripten_memcpy_big(dest, src, num) {\n    HEAPU8.set(HEAPU8.subarray(src, src + num), dest);\n    return dest\n  }\n  function _mktime(tmPtr) {\n    _tzset();\n    var date = new Date(\n      HEAP32[(tmPtr + 20) >> 2] + 1900,\n      HEAP32[(tmPtr + 16) >> 2],\n      HEAP32[(tmPtr + 12) >> 2],\n      HEAP32[(tmPtr + 8) >> 2],\n      HEAP32[(tmPtr + 4) >> 2],\n      HEAP32[tmPtr >> 2],\n      0\n    );\n    var dst = HEAP32[(tmPtr + 32) >> 2];\n    var guessedOffset = date.getTimezoneOffset();\n    var start = new Date(date.getFullYear(), 0, 1);\n    var summerOffset = new Date(2e3, 6, 1).getTimezoneOffset();\n    var winterOffset = start.getTimezoneOffset();\n    var dstOffset = Math.min(winterOffset, summerOffset);\n    if (dst < 0) {\n      HEAP32[(tmPtr + 32) >> 2] = Number(summerOffset != winterOffset && dstOffset == guessedOffset);\n    } else if (dst > 0 != (dstOffset == guessedOffset)) {\n      var nonDstOffset = Math.max(winterOffset, summerOffset);\n      var trueOffset = dst > 0 ? dstOffset : nonDstOffset;\n      date.setTime(date.getTime() + (trueOffset - guessedOffset) * 6e4);\n    }\n    HEAP32[(tmPtr + 24) >> 2] = date.getDay();\n    var yday = ((date.getTime() - start.getTime()) / (1e3 * 60 * 60 * 24)) | 0;\n    HEAP32[(tmPtr + 28) >> 2] = yday;\n    return (date.getTime() / 1e3) | 0\n  }\n  var PTHREAD_SPECIFIC = {};\n  function _pthread_getspecific(key) {\n    return PTHREAD_SPECIFIC[key] || 0\n  }\n  var PTHREAD_SPECIFIC_NEXT_KEY = 1;\n  function _pthread_key_create(key, destructor) {\n    if (key == 0) {\n      return ERRNO_CODES.EINVAL\n    }\n    HEAP32[key >> 2] = PTHREAD_SPECIFIC_NEXT_KEY;\n    PTHREAD_SPECIFIC[PTHREAD_SPECIFIC_NEXT_KEY] = 0;\n    PTHREAD_SPECIFIC_NEXT_KEY++;\n    return 0\n  }\n  function _pthread_once(ptr, func) {\n    if (!_pthread_once.seen) _pthread_once.seen = {};\n    if (ptr in _pthread_once.seen) return\n    Module['dynCall_v'](func);\n    _pthread_once.seen[ptr] = 1;\n  }\n  function _pthread_setspecific(key, value) {\n    if (!(key in PTHREAD_SPECIFIC)) {\n      return ERRNO_CODES.EINVAL\n    }\n    PTHREAD_SPECIFIC[key] = value;\n    return 0\n  }\n  function _time(ptr) {\n    var ret = (Date.now() / 1e3) | 0;\n    if (ptr) {\n      HEAP32[ptr >> 2] = ret;\n    }\n    return ret\n  }\n  FS.staticInit();\n  __ATINIT__.unshift(function () {\n    if (!Module['noFSInit'] && !FS.init.initialized) FS.init();\n  });\n  __ATMAIN__.push(function () {\n    FS.ignorePermissions = false;\n  });\n  __ATEXIT__.push(function () {\n    FS.quit();\n  });\n  __ATINIT__.unshift(function () {\n  });\n  __ATEXIT__.push(function () {\n  });\n  InternalError = Module['InternalError'] = extendError(Error, 'InternalError');\n  embind_init_charCodes();\n  BindingError = Module['BindingError'] = extendError(Error, 'BindingError');\n  init_ClassHandle();\n  init_RegisteredPointer();\n  init_embind();\n  UnboundTypeError = Module['UnboundTypeError'] = extendError(Error, 'UnboundTypeError');\n  init_emval();\n  ___buildEnvironment(ENV);\n  DYNAMICTOP_PTR = staticAlloc(4);\n  STACK_BASE = STACKTOP = alignMemory(STATICTOP);\n  STACK_MAX = STACK_BASE + TOTAL_STACK;\n  DYNAMIC_BASE = alignMemory(STACK_MAX);\n  HEAP32[DYNAMICTOP_PTR >> 2] = DYNAMIC_BASE;\n  staticSealed = true;\n  function intArrayFromString(stringy, dontAddNull, length) {\n    var len = length > 0 ? length : lengthBytesUTF8(stringy) + 1;\n    var u8array = new Array(len);\n    var numBytesWritten = stringToUTF8Array(stringy, u8array, 0, u8array.length);\n    if (dontAddNull) u8array.length = numBytesWritten;\n    return u8array\n  }\n  Module['wasmTableSize'] = 316;\n  Module['wasmMaxTableSize'] = 316;\n  function invoke_i(index) {\n    try {\n      return Module['dynCall_i'](index)\n    } catch (e) {\n      if (typeof e !== 'number' && e !== 'longjmp') throw e\n      Module['setThrew'](1, 0);\n    }\n  }\n  function invoke_ii(index, a1) {\n    try {\n      return Module['dynCall_ii'](index, a1)\n    } catch (e) {\n      if (typeof e !== 'number' && e !== 'longjmp') throw e\n      Module['setThrew'](1, 0);\n    }\n  }\n  function invoke_iii(index, a1, a2) {\n    try {\n      return Module['dynCall_iii'](index, a1, a2)\n    } catch (e) {\n      if (typeof e !== 'number' && e !== 'longjmp') throw e\n      Module['setThrew'](1, 0);\n    }\n  }\n  function invoke_iiii(index, a1, a2, a3) {\n    try {\n      return Module['dynCall_iiii'](index, a1, a2, a3)\n    } catch (e) {\n      if (typeof e !== 'number' && e !== 'longjmp') throw e\n      Module['setThrew'](1, 0);\n    }\n  }\n  function invoke_iiiii(index, a1, a2, a3, a4) {\n    try {\n      return Module['dynCall_iiiii'](index, a1, a2, a3, a4)\n    } catch (e) {\n      if (typeof e !== 'number' && e !== 'longjmp') throw e\n      Module['setThrew'](1, 0);\n    }\n  }\n  function invoke_iiiiiii(index, a1, a2, a3, a4, a5, a6) {\n    try {\n      return Module['dynCall_iiiiiii'](index, a1, a2, a3, a4, a5, a6)\n    } catch (e) {\n      if (typeof e !== 'number' && e !== 'longjmp') throw e\n      Module['setThrew'](1, 0);\n    }\n  }\n  function invoke_iiiiiiiiii(index, a1, a2, a3, a4, a5, a6, a7, a8, a9) {\n    try {\n      return Module['dynCall_iiiiiiiiii'](index, a1, a2, a3, a4, a5, a6, a7, a8, a9)\n    } catch (e) {\n      if (typeof e !== 'number' && e !== 'longjmp') throw e\n      Module['setThrew'](1, 0);\n    }\n  }\n  function invoke_iiiiiijii(index, a1, a2, a3, a4, a5, a6, a7, a8, a9) {\n    try {\n      return Module['dynCall_iiiiiijii'](index, a1, a2, a3, a4, a5, a6, a7, a8, a9)\n    } catch (e) {\n      if (typeof e !== 'number' && e !== 'longjmp') throw e\n      Module['setThrew'](1, 0);\n    }\n  }\n  function invoke_ijj(index, a1, a2, a3, a4) {\n    try {\n      return Module['dynCall_ijj'](index, a1, a2, a3, a4)\n    } catch (e) {\n      if (typeof e !== 'number' && e !== 'longjmp') throw e\n      Module['setThrew'](1, 0);\n    }\n  }\n  function invoke_ji(index, a1) {\n    try {\n      return Module['dynCall_ji'](index, a1)\n    } catch (e) {\n      if (typeof e !== 'number' && e !== 'longjmp') throw e\n      Module['setThrew'](1, 0);\n    }\n  }\n  function invoke_v(index) {\n    try {\n      Module['dynCall_v'](index);\n    } catch (e) {\n      if (typeof e !== 'number' && e !== 'longjmp') throw e\n      Module['setThrew'](1, 0);\n    }\n  }\n  function invoke_vi(index, a1) {\n    try {\n      Module['dynCall_vi'](index, a1);\n    } catch (e) {\n      if (typeof e !== 'number' && e !== 'longjmp') throw e\n      Module['setThrew'](1, 0);\n    }\n  }\n  function invoke_vii(index, a1, a2) {\n    try {\n      Module['dynCall_vii'](index, a1, a2);\n    } catch (e) {\n      if (typeof e !== 'number' && e !== 'longjmp') throw e\n      Module['setThrew'](1, 0);\n    }\n  }\n  function invoke_viii(index, a1, a2, a3) {\n    try {\n      Module['dynCall_viii'](index, a1, a2, a3);\n    } catch (e) {\n      if (typeof e !== 'number' && e !== 'longjmp') throw e\n      Module['setThrew'](1, 0);\n    }\n  }\n  function invoke_viiii(index, a1, a2, a3, a4) {\n    try {\n      Module['dynCall_viiii'](index, a1, a2, a3, a4);\n    } catch (e) {\n      if (typeof e !== 'number' && e !== 'longjmp') throw e\n      Module['setThrew'](1, 0);\n    }\n  }\n  function invoke_viiiii(index, a1, a2, a3, a4, a5) {\n    try {\n      Module['dynCall_viiiii'](index, a1, a2, a3, a4, a5);\n    } catch (e) {\n      if (typeof e !== 'number' && e !== 'longjmp') throw e\n      Module['setThrew'](1, 0);\n    }\n  }\n  function invoke_viiiiii(index, a1, a2, a3, a4, a5, a6) {\n    try {\n      Module['dynCall_viiiiii'](index, a1, a2, a3, a4, a5, a6);\n    } catch (e) {\n      if (typeof e !== 'number' && e !== 'longjmp') throw e\n      Module['setThrew'](1, 0);\n    }\n  }\n  function invoke_viiiiiiiii(index, a1, a2, a3, a4, a5, a6, a7, a8, a9) {\n    try {\n      Module['dynCall_viiiiiiiii'](index, a1, a2, a3, a4, a5, a6, a7, a8, a9);\n    } catch (e) {\n      if (typeof e !== 'number' && e !== 'longjmp') throw e\n      Module['setThrew'](1, 0);\n    }\n  }\n  function invoke_viiiiiiiiii(index, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) {\n    try {\n      Module['dynCall_viiiiiiiiii'](index, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);\n    } catch (e) {\n      if (typeof e !== 'number' && e !== 'longjmp') throw e\n      Module['setThrew'](1, 0);\n    }\n  }\n  function invoke_vij(index, a1, a2, a3) {\n    try {\n      Module['dynCall_vij'](index, a1, a2, a3);\n    } catch (e) {\n      if (typeof e !== 'number' && e !== 'longjmp') throw e\n      Module['setThrew'](1, 0);\n    }\n  }\n  function invoke_viji(index, a1, a2, a3, a4) {\n    try {\n      Module['dynCall_viji'](index, a1, a2, a3, a4);\n    } catch (e) {\n      if (typeof e !== 'number' && e !== 'longjmp') throw e\n      Module['setThrew'](1, 0);\n    }\n  }\n  Module.asmGlobalArg = {};\n  Module.asmLibraryArg = {\n    abort: abort,\n    enlargeMemory: enlargeMemory,\n    getTotalMemory: getTotalMemory,\n    abortOnCannotGrowMemory: abortOnCannotGrowMemory,\n    invoke_i: invoke_i,\n    invoke_ii: invoke_ii,\n    invoke_iii: invoke_iii,\n    invoke_iiii: invoke_iiii,\n    invoke_iiiii: invoke_iiiii,\n    invoke_iiiiiii: invoke_iiiiiii,\n    invoke_iiiiiiiiii: invoke_iiiiiiiiii,\n    invoke_iiiiiijii: invoke_iiiiiijii,\n    invoke_ijj: invoke_ijj,\n    invoke_ji: invoke_ji,\n    invoke_v: invoke_v,\n    invoke_vi: invoke_vi,\n    invoke_vii: invoke_vii,\n    invoke_viii: invoke_viii,\n    invoke_viiii: invoke_viiii,\n    invoke_viiiii: invoke_viiiii,\n    invoke_viiiiii: invoke_viiiiii,\n    invoke_viiiiiiiii: invoke_viiiiiiiii,\n    invoke_viiiiiiiiii: invoke_viiiiiiiiii,\n    invoke_vij: invoke_vij,\n    invoke_viji: invoke_viji,\n    ___cxa_allocate_exception: ___cxa_allocate_exception,\n    ___cxa_begin_catch: ___cxa_begin_catch,\n    ___cxa_end_catch: ___cxa_end_catch,\n    ___cxa_find_matching_catch_2: ___cxa_find_matching_catch_2,\n    ___cxa_find_matching_catch_3: ___cxa_find_matching_catch_3,\n    ___cxa_find_matching_catch_4: ___cxa_find_matching_catch_4,\n    ___cxa_free_exception: ___cxa_free_exception,\n    ___cxa_throw: ___cxa_throw,\n    ___lock: ___lock,\n    ___map_file: ___map_file,\n    ___resumeException: ___resumeException,\n    ___setErrNo: ___setErrNo,\n    ___syscall140: ___syscall140,\n    ___syscall145: ___syscall145,\n    ___syscall146: ___syscall146,\n    ___syscall183: ___syscall183,\n    ___syscall198: ___syscall198,\n    ___syscall20: ___syscall20,\n    ___syscall6: ___syscall6,\n    ___syscall60: ___syscall60,\n    ___syscall83: ___syscall83,\n    ___syscall91: ___syscall91,\n    ___unlock: ___unlock,\n    __embind_finalize_value_object: __embind_finalize_value_object,\n    __embind_register_bool: __embind_register_bool,\n    __embind_register_class: __embind_register_class,\n    __embind_register_class_constructor: __embind_register_class_constructor,\n    __embind_register_class_function: __embind_register_class_function,\n    __embind_register_emval: __embind_register_emval,\n    __embind_register_float: __embind_register_float,\n    __embind_register_integer: __embind_register_integer,\n    __embind_register_memory_view: __embind_register_memory_view,\n    __embind_register_std_string: __embind_register_std_string,\n    __embind_register_std_wstring: __embind_register_std_wstring,\n    __embind_register_value_object: __embind_register_value_object,\n    __embind_register_value_object_field: __embind_register_value_object_field,\n    __embind_register_void: __embind_register_void,\n    _abort: _abort,\n    _emscripten_memcpy_big: _emscripten_memcpy_big,\n    _getenv: _getenv,\n    _getgrnam: _getgrnam,\n    _getpwnam: _getpwnam,\n    _jsClose: _jsClose,\n    _jsCreate: _jsCreate,\n    _jsOpen: _jsOpen,\n    _jsRead: _jsRead,\n    _jsSeek: _jsSeek,\n    _jsTell: _jsTell,\n    _jsWrite: _jsWrite,\n    _llvm_eh_typeid_for: _llvm_eh_typeid_for,\n    _localtime: _localtime,\n    _mktime: _mktime,\n    _pthread_getspecific: _pthread_getspecific,\n    _pthread_key_create: _pthread_key_create,\n    _pthread_once: _pthread_once,\n    _pthread_setspecific: _pthread_setspecific,\n    _time: _time,\n    DYNAMICTOP_PTR: DYNAMICTOP_PTR,\n    STACKTOP: STACKTOP,\n  };\n  var asm = Module['asm'](Module.asmGlobalArg, Module.asmLibraryArg, buffer);\n  Module['asm'] = asm;\n  var __GLOBAL__sub_I_bind_cpp = (Module['__GLOBAL__sub_I_bind_cpp'] = function () {\n    return Module['asm']['__GLOBAL__sub_I_bind_cpp'].apply(null, arguments)\n  });\n  var __GLOBAL__sub_I_bridge_cpp = (Module['__GLOBAL__sub_I_bridge_cpp'] = function () {\n    return Module['asm']['__GLOBAL__sub_I_bridge_cpp'].apply(null, arguments)\n  });\n  var __GLOBAL__sub_I_crc_cpp = (Module['__GLOBAL__sub_I_crc_cpp'] = function () {\n    return Module['asm']['__GLOBAL__sub_I_crc_cpp'].apply(null, arguments)\n  });\n  var __GLOBAL__sub_I_global_cpp = (Module['__GLOBAL__sub_I_global_cpp'] = function () {\n    return Module['asm']['__GLOBAL__sub_I_global_cpp'].apply(null, arguments)\n  });\n  (Module['___cxa_can_catch'] = function () {\n    return Module['asm']['___cxa_can_catch'].apply(null, arguments)\n  });\n  (Module['___cxa_is_pointer_type'] = function () {\n    return Module['asm']['___cxa_is_pointer_type'].apply(null, arguments)\n  });\n  (Module['___errno_location'] = function () {\n    return Module['asm']['___errno_location'].apply(null, arguments)\n  });\n  var ___getTypeName = (Module['___getTypeName'] = function () {\n    return Module['asm']['___getTypeName'].apply(null, arguments)\n  });\n  var _emscripten_replace_memory = (Module['_emscripten_replace_memory'] = function () {\n    return Module['asm']['_emscripten_replace_memory'].apply(null, arguments)\n  });\n  var _free = (Module['_free'] = function () {\n    return Module['asm']['_free'].apply(null, arguments)\n  });\n  var _malloc = (Module['_malloc'] = function () {\n    return Module['asm']['_malloc'].apply(null, arguments)\n  });\n  var setTempRet0 = (Module['setTempRet0'] = function () {\n    return Module['asm']['setTempRet0'].apply(null, arguments)\n  });\n  (Module['setThrew'] = function () {\n    return Module['asm']['setThrew'].apply(null, arguments)\n  });\n  var stackAlloc = (Module['stackAlloc'] = function () {\n    return Module['asm']['stackAlloc'].apply(null, arguments)\n  });\n  (Module['dynCall_dii'] = function () {\n    return Module['asm']['dynCall_dii'].apply(null, arguments)\n  });\n  (Module['dynCall_i'] = function () {\n    return Module['asm']['dynCall_i'].apply(null, arguments)\n  });\n  (Module['dynCall_ii'] = function () {\n    return Module['asm']['dynCall_ii'].apply(null, arguments)\n  });\n  (Module['dynCall_iii'] = function () {\n    return Module['asm']['dynCall_iii'].apply(null, arguments)\n  });\n  (Module['dynCall_iiii'] = function () {\n    return Module['asm']['dynCall_iiii'].apply(null, arguments)\n  });\n  (Module['dynCall_iiiii'] = function () {\n    return Module['asm']['dynCall_iiiii'].apply(null, arguments)\n  });\n  (Module['dynCall_iiiiii'] = function () {\n    return Module['asm']['dynCall_iiiiii'].apply(null, arguments)\n  });\n  (Module['dynCall_iiiiiii'] = function () {\n    return Module['asm']['dynCall_iiiiiii'].apply(null, arguments)\n  });\n  (Module['dynCall_iiiiiiiiii'] = function () {\n    return Module['asm']['dynCall_iiiiiiiiii'].apply(null, arguments)\n  });\n  (Module['dynCall_iiiiiijii'] = function () {\n    return Module['asm']['dynCall_iiiiiijii'].apply(null, arguments)\n  });\n  (Module['dynCall_ijj'] = function () {\n    return Module['asm']['dynCall_ijj'].apply(null, arguments)\n  });\n  (Module['dynCall_ji'] = function () {\n    return Module['asm']['dynCall_ji'].apply(null, arguments)\n  });\n  (Module['dynCall_v'] = function () {\n    return Module['asm']['dynCall_v'].apply(null, arguments)\n  });\n  (Module['dynCall_vi'] = function () {\n    return Module['asm']['dynCall_vi'].apply(null, arguments)\n  });\n  (Module['dynCall_vii'] = function () {\n    return Module['asm']['dynCall_vii'].apply(null, arguments)\n  });\n  (Module['dynCall_viid'] = function () {\n    return Module['asm']['dynCall_viid'].apply(null, arguments)\n  });\n  (Module['dynCall_viii'] = function () {\n    return Module['asm']['dynCall_viii'].apply(null, arguments)\n  });\n  (Module['dynCall_viiii'] = function () {\n    return Module['asm']['dynCall_viiii'].apply(null, arguments)\n  });\n  (Module['dynCall_viiiii'] = function () {\n    return Module['asm']['dynCall_viiiii'].apply(null, arguments)\n  });\n  (Module['dynCall_viiiiii'] = function () {\n    return Module['asm']['dynCall_viiiiii'].apply(null, arguments)\n  });\n  (Module['dynCall_viiiiiiiii'] = function () {\n    return Module['asm']['dynCall_viiiiiiiii'].apply(null, arguments)\n  });\n  (Module['dynCall_viiiiiiiiii'] = function () {\n    return Module['asm']['dynCall_viiiiiiiiii'].apply(null, arguments)\n  });\n  (Module['dynCall_vij'] = function () {\n    return Module['asm']['dynCall_vij'].apply(null, arguments)\n  });\n  (Module['dynCall_viji'] = function () {\n    return Module['asm']['dynCall_viji'].apply(null, arguments)\n  });\n  Module['asm'] = asm;\n  function ExitStatus(status) {\n    this.name = 'ExitStatus';\n    this.message = 'Program terminated with exit(' + status + ')';\n    this.status = status;\n  }\n  ExitStatus.prototype = new Error();\n  ExitStatus.prototype.constructor = ExitStatus;\n  var initialStackTop;\n  dependenciesFulfilled = function runCaller() {\n    if (!Module['calledRun']) run();\n    if (!Module['calledRun']) dependenciesFulfilled = runCaller;\n  };\n  function run(args) {\n    args = args || Module['arguments'];\n    if (runDependencies > 0) {\n      return\n    }\n    preRun();\n    if (runDependencies > 0) return\n    if (Module['calledRun']) return\n    function doRun() {\n      if (Module['calledRun']) return\n      Module['calledRun'] = true;\n      if (ABORT) return\n      ensureInitRuntime();\n      preMain();\n      if (Module['onRuntimeInitialized']) Module['onRuntimeInitialized']();\n      postRun();\n    }\n    if (Module['setStatus']) {\n      Module['setStatus']('Running...');\n      setTimeout(function () {\n        setTimeout(function () {\n          Module['setStatus']('');\n        }, 1);\n        doRun();\n      }, 1);\n    } else {\n      doRun();\n    }\n  }\n  Module['run'] = run;\n  function exit(status, implicit) {\n    if (implicit && Module['noExitRuntime'] && status === 0) {\n      return\n    }\n    if (Module['noExitRuntime']) ; else {\n      ABORT = true;\n      STACKTOP = initialStackTop;\n      exitRuntime();\n      if (Module['onExit']) Module['onExit'](status);\n    }\n    if (ENVIRONMENT_IS_NODE) {\n      process['exit'](status);\n    }\n    Module['quit'](status, new ExitStatus(status));\n  }\n  Module['exit'] = exit;\n  function abort(what) {\n    if (Module['onAbort']) {\n      Module['onAbort'](what);\n    }\n    if (what !== undefined) {\n      Module.print(what);\n      Module.printErr(what);\n      what = JSON.stringify(what);\n    } else {\n      what = '';\n    }\n    ABORT = true;\n    throw 'abort(' + what + '). Build with -s ASSERTIONS=1 for more info.'\n  }\n  Module['abort'] = abort;\n  if (Module['preInit']) {\n    if (typeof Module['preInit'] == 'function') Module['preInit'] = [Module['preInit']];\n    while (Module['preInit'].length > 0) {\n      Module['preInit'].pop()();\n    }\n  }\n  Module['noExitRuntime'] = true;\n  run();\n\n  return unpack\n};\n//-------------------------------------------------------------\n\n/**\n * Returns a Promise containing the rar extractor for the given filename.\n * @private\n */\nfunction getExtractor(url) {\n  return fetch(new Request(url))\n    .then((response) => {\n      if (response.ok) return response.arrayBuffer()\n      else {\n        throw new Error('404 Error: File not found.')\n      }\n    })\n    .then((buffer) => unpackBridge.createExtractorFromData(buffer))\n}\n\n/**\n *  Returns a string representing the formatted contents of the given file.\n * @private\n */\nfunction extract({ resourceId, url }) {\n  return new Promise(function (resolve, reject) {\n    if (!unpackBridge) {\n      throw new Error('unpackBridge not detected')\n    }\n    if (!unpack) {\n      throw new Error('unpack not detected')\n    }\n\n    getExtractor(url).then(\n      (extractor) => {\n        // return extractor.extractAll();\n        resolve(extractor.extractAll());\n      },\n      (err) => {\n        reject(err);\n      }\n    );\n  })\n}\n\n/**\n * Listen for messages sent to the worker.\n * @private\n */\nfunction handleMessage$1(data, postMessage) {\n  if (data.type == 'init') {\n    unpack = initunpack(data.buffer);\n    unpack.onRuntimeInitialized = () => {\n      postMessage({ type: 'WASM_LOADED' });\n    };\n  } else if (data.type == 'fetch') {\n    extract(data).then(\n      (unpacked) => {\n        returnData(data, unpacked, postMessage);\n      },\n      (err) => {\n        const result = {\n          taskId: data.taskId,\n          type: 'ERROR',\n          resourceId: data.resourceId,\n          url: data.url,\n        };\n        postMessage(result);\n      }\n    );\n  } else if (data.type == 'unpack') {\n    const { buffer } = data;\n\n    if (!unpackBridge) {\n      throw new Error('unpackBridge not detected')\n    }\n    if (!unpack) {\n      throw new Error('unpack not detected')\n    }\n\n    const extractor = unpackBridge.createExtractorFromData(buffer);\n    const unpacked = extractor.extractAll();\n    returnData(data, unpacked, postMessage);\n  }\n}\n\nfunction returnData(data, unpacked, postMessage) {\n  const [state, list] = unpacked;\n  if (state.state == 'FAIL') {\n    const result = {\n      taskId: data.taskId,\n      type: 'ERROR',\n      reason: state.reason,\n      msg: state.msg,\n      resourceId: data.resourceId,\n      url: data.url,\n    };\n    postMessage(result);\n    return\n  }\n  const result = {\n    taskId: data.taskId,\n    type: 'FINISHED',\n    resourceId: data.resourceId,\n    entries: {},\n  };\n\n  const transferables = [];\n  if (list && list.files) {\n    for (const file of list.files) {\n      result.entries[file.fileHeader.name] = file.extract[1];\n      transferables.push(file.extract[1].buffer);\n    }\n  }\n  postMessage(result, transferables);\n}\n\nglobalThis.onmessage = function (event) {\n  handleMessage$1(event.data, self.postMessage);\n};\n\n/**\n * When the WASM runtime has been initialized on the unpack.js module, send a message indicating\n * that the library is ready.\n */\n// <!-- prettier-ignore-end -->\n\nlet taskCounter = 0;\nclass WorkerPool extends EventEmitter {\n    poolSize = Math.max(1, SystemDesc.hardwareConcurrency - 1); // always leave one main thread code spare.\n    workers = [];\n    workerTaskCount = [];\n    taskPromiseResolves = {};\n    taskQueue = [];\n    availableWorkers = [];\n    terminationTimeouts = [];\n    terminateWorkersWhenFree = true;\n    terminationLatency = 2000;\n    constructor(terminateWorkersWhenFree) {\n        super();\n        this.terminateWorkersWhenFree = terminateWorkersWhenFree;\n    }\n    addTask(taskData, transferables) {\n        return this.addTaskCallback(() => {\n            return {\n                taskData,\n                transferables,\n            };\n        });\n    }\n    addTaskCallback(dataFactory) {\n        taskCounter++;\n        const taskId = taskCounter;\n        return new Promise(async (resolve) => {\n            this.taskPromiseResolves[taskId] = resolve;\n            // @ts-ignore\n            this.taskQueue.push({\n                taskId,\n                dataFactory,\n            });\n            if (this.availableWorkers.length > 0) {\n                this.consumeTask();\n            }\n            else if (this.workers.length < this.poolSize) {\n                await this.addWorker();\n                this.consumeTask();\n            }\n        });\n    }\n    async consumeTask() {\n        const workerId = this.availableWorkers.pop();\n        if (this.workerTaskCount[workerId] > 0) {\n            return;\n        }\n        if (this.taskQueue.length == 0) {\n            // Multiple consumeTask were issued, and all tasks have been consumed.\n            if (this.terminateWorkersWhenFree) {\n                this.scheduleWorkerTermination(workerId);\n            }\n            return;\n        }\n        if (this.terminationTimeouts[workerId] != -1) {\n            clearTimeout(this.terminationTimeouts[workerId]);\n            this.terminationTimeouts[workerId] = -1;\n        }\n        else if (!this.workers[workerId]) {\n            // Workers get terminated, and we need to restart them.\n            await this.allocWorker(workerId);\n        }\n        if (this.taskQueue.length == 0) {\n            // Multiple consumeTask were issued, and all tasks have been consumed.\n            if (this.terminateWorkersWhenFree) {\n                this.scheduleWorkerTermination(workerId);\n            }\n            return;\n        }\n        const task = this.taskQueue.pop();\n        const { taskData, transferables } = task.dataFactory(workerId);\n        // @ts-ignore\n        taskData.taskId = task.taskId;\n        this.workerTaskCount[workerId]++;\n        // @ts-ignore\n        this.workers[workerId].postMessage(taskData, transferables);\n    }\n    addWorker() {\n        const workerId = this.workers.length;\n        this.workers.push(null);\n        return this.allocWorker(workerId);\n    }\n    allocWorker(workerId) {\n        // Note: This function immediately adds the worker to the list\n        // and then asynchronously creates it.\n        return new Promise((resolve) => {\n            this.constructWorker().then((worker) => {\n                // @ts-ignore\n                worker.onmessage = (event) => {\n                    if (event.data.taskId in this.taskPromiseResolves) {\n                        const taskId = event.data.taskId;\n                        delete event.data.taskId;\n                        this.taskPromiseResolves[taskId](event.data);\n                        delete this.taskPromiseResolves[taskId];\n                        this.workerTaskCount[workerId]--;\n                        if (this.workerTaskCount[workerId] > 0) {\n                            // Another task is already sent to this worker.\n                            // Let it complete.\n                            return;\n                        }\n                        // Check that we are not already on the available list.\n                        // This happens if multiple tasks get issued to the same worker.\n                        if (this.availableWorkers.indexOf(workerId) == -1) {\n                            this.availableWorkers.push(workerId);\n                        }\n                        if (this.taskQueue.length > 0) {\n                            this.consumeTask();\n                        }\n                        else {\n                            if (this.terminateWorkersWhenFree) {\n                                this.scheduleWorkerTermination(workerId);\n                            }\n                        }\n                    }\n                    else if (event.data.eventName) {\n                        event.data.workerId = workerId;\n                        this.emit(event.data.eventName, event.data);\n                    }\n                };\n                this.workers[workerId] = worker;\n                this.terminationTimeouts[workerId] = -1;\n                this.workerTaskCount[workerId] = 0;\n                this.availableWorkers.push(workerId);\n                resolve();\n            });\n        });\n    }\n    scheduleWorkerTermination(workerId) {\n        // @ts-ignore\n        this.terminationTimeouts[workerId] = setTimeout(() => {\n            this.terminateWorker(workerId);\n            this.terminationTimeouts[workerId] = -1;\n        }, this.terminationLatency);\n    }\n    terminateWorker(workerId) {\n        // @ts-ignore\n        this.workers[workerId].terminate();\n        this.workers[workerId] = null;\n    }\n    messageWorker(workerId, message) {\n        taskCounter++;\n        const taskId = taskCounter;\n        // console.log('addTask:', taskId)\n        return new Promise((resolve) => {\n            this.taskPromiseResolves[taskId] = resolve;\n            // @ts-ignore\n            message.taskId = taskId;\n            // @ts-ignore\n            this.workers[workerId].postMessage(message);\n        });\n    }\n}\n\nfunction decodeBase64(base64, enableUnicode) {\n    var binaryString = atob(base64);\n    if (enableUnicode) {\n        var binaryView = new Uint8Array(binaryString.length);\n        for (var i = 0, n = binaryString.length; i < n; ++i) {\n            binaryView[i] = binaryString.charCodeAt(i);\n        }\n        return String.fromCharCode.apply(null, new Uint16Array(binaryView.buffer));\n    }\n    return binaryString;\n}\n\nfunction createURL(base64, sourcemapArg, enableUnicodeArg) {\n    var sourcemap = sourcemapArg === undefined ? null : sourcemapArg;\n    var enableUnicode = enableUnicodeArg === undefined ? false : enableUnicodeArg;\n    var source = decodeBase64(base64, enableUnicode);\n    var start = source.indexOf('\\n', 10) + 1;\n    var body = source.substring(start) + (sourcemap ? '\\/\\/# sourceMappingURL=' + sourcemap : '');\n    var blob = new Blob([body], { type: 'application/javascript' });\n    return URL.createObjectURL(blob);\n}\n\nfunction createBase64WorkerFactory(base64, sourcemapArg, enableUnicodeArg) {\n    var url;\n    return function WorkerFactory(options) {\n        url = url || createURL(base64, sourcemapArg, enableUnicodeArg);\n        return new Worker(url, options);\n    };\n}\n\nvar WorkerFactory$2 = createBase64WorkerFactory('Lyogcm9sbHVwLXBsdWdpbi13ZWItd29ya2VyLWxvYWRlciAqLwp2YXIgd29ya2VyX2NvZGUgPSAoZnVuY3Rpb24gKGV4cG9ydHMpIHsKICAndXNlIHN0cmljdCc7CgogIC8vIDwhLS0gcHJldHRpZXItaWdub3JlLXN0YXJ0IC0tPgogIC8qIGVzbGludC1kaXNhYmxlIHJlcXVpcmUtanNkb2MgKi8KCiAgY29uc3QgTW9kdWxlID0ge307CgogIGNvbnN0IFdvcmtlclNjb3BlID0ge307CgogIC8vLS0tLS0tLS0tLS0tLS0tLS0tLS11bnBhY2tCcmlkZ2UuanMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAgIShmdW5jdGlvbiAodCwgZSkgewogICAgLy8gVGhlIGZvbGxvd2luZyBjb2RlIGhhcyBiZWVuIF9jYXJlZnVsbHlfIG1vZGlmaWVkIGJ5IGhhbmQuCiAgICAvLyBUaGVyZSB3ZXJlIHZhcmlvdXMgY2FzZXMgZm9yIGluIHdoYXQgY29udGV4dCB0aGUgY29kZSBtaWdodAogICAgLy8gYmUgcnVuLCBhbmQgSSByZW1vdmVkIGFsbCBidXQgdGhlIHdlYndvcmtlciBjYXNlLgogICAgLy8gVGhlcmUgd2FzIGNvZGUgdG8gaGFuZGxlIGxvYWRpbmcgaW4gYSBub2RlSlMgY29udGV4dCwgdGhhdCB0cmllZCB0byBpbXBvcnQoImZzIikKICAgIC8vIFdlYlBhY2sga2VwdHMgdHJpcHBpbmcgdXAgb24gdGhhdCBjb2RlIGluIGl0cyBzdGF0aWMgYW5hbHlzaXMgb2YgdGhlIGNvZGUsIHNvCiAgICAvLyBJIGNhcmVmdWxseSByZW1vdmVkIGl0LgogICAgdC51bnBhY2tCcmlkZ2UgPSBlKHQuZnMpOwogIH0pKFdvcmtlclNjb3BlLCBmdW5jdGlvbiAodCkgewogICAgcmV0dXJuIChmdW5jdGlvbiAodCkgewogICAgICB2YXIgZSA9IHt9OwogICAgICBmdW5jdGlvbiByKG4pIHsKICAgICAgICBpZiAoZVtuXSkgcmV0dXJuIGVbbl0uZXhwb3J0cwogICAgICAgIHZhciBpID0gKGVbbl0gPSB7IGk6IG4sIGw6ICExLCBleHBvcnRzOiB7fSB9KTsKICAgICAgICByZXR1cm4gdFtuXS5jYWxsKGkuZXhwb3J0cywgaSwgaS5leHBvcnRzLCByKSwgKGkubCA9ICEwKSwgaS5leHBvcnRzCiAgICAgIH0KICAgICAgcmV0dXJuICgKICAgICAgICAoci5tID0gdCksCiAgICAgICAgKHIuYyA9IGUpLAogICAgICAgIChyLmQgPSBmdW5jdGlvbiAodCwgZSwgbikgewogICAgICAgICAgci5vKHQsIGUpIHx8IE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCBlLCB7IGVudW1lcmFibGU6ICEwLCBnZXQ6IG4gfSk7CiAgICAgICAgfSksCiAgICAgICAgKHIuciA9IGZ1bmN0aW9uICh0KSB7CiAgICAgICAgICAndW5kZWZpbmVkJyAhPSB0eXBlb2YgU3ltYm9sICYmCiAgICAgICAgICAgIFN5bWJvbC50b1N0cmluZ1RhZyAmJgogICAgICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkodCwgU3ltYm9sLnRvU3RyaW5nVGFnLCB7IHZhbHVlOiAnTW9kdWxlJyB9KSwKICAgICAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsICdfX2VzTW9kdWxlJywgeyB2YWx1ZTogITAgfSk7CiAgICAgICAgfSksCiAgICAgICAgKHIudCA9IGZ1bmN0aW9uICh0LCBlKSB7CiAgICAgICAgICBpZiAoKDEgJiBlICYmICh0ID0gcih0KSksIDggJiBlKSkgcmV0dXJuIHQKICAgICAgICAgIGlmICg0ICYgZSAmJiAnb2JqZWN0JyA9PSB0eXBlb2YgdCAmJiB0ICYmIHQuX19lc01vZHVsZSkgcmV0dXJuIHQKICAgICAgICAgIHZhciBuID0gT2JqZWN0LmNyZWF0ZShudWxsKTsKICAgICAgICAgIGlmICgoci5yKG4pLCBPYmplY3QuZGVmaW5lUHJvcGVydHkobiwgJ2RlZmF1bHQnLCB7IGVudW1lcmFibGU6ICEwLCB2YWx1ZTogdCB9KSwgMiAmIGUgJiYgJ3N0cmluZycgIT0gdHlwZW9mIHQpKQogICAgICAgICAgICBmb3IgKHZhciBpIGluIHQpCiAgICAgICAgICAgICAgci5kKAogICAgICAgICAgICAgICAgbiwKICAgICAgICAgICAgICAgIGksCiAgICAgICAgICAgICAgICBmdW5jdGlvbiAoZSkgewogICAgICAgICAgICAgICAgICByZXR1cm4gdFtlXQogICAgICAgICAgICAgICAgfS5iaW5kKG51bGwsIGkpCiAgICAgICAgICAgICAgKTsKICAgICAgICAgIHJldHVybiBuCiAgICAgICAgfSksCiAgICAgICAgKHIubiA9IGZ1bmN0aW9uICh0KSB7CiAgICAgICAgICB2YXIgZSA9CiAgICAgICAgICAgIHQgJiYgdC5fX2VzTW9kdWxlCiAgICAgICAgICAgICAgPyBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgICAgICAgIHJldHVybiB0LmRlZmF1bHQKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICA6IGZ1bmN0aW9uICgpIHsKICAgICAgICAgICAgICAgICAgcmV0dXJuIHQKICAgICAgICAgICAgICAgIH07CiAgICAgICAgICByZXR1cm4gci5kKGUsICdhJywgZSksIGUKICAgICAgICB9KSwKICAgICAgICAoci5vID0gZnVuY3Rpb24gKHQsIGUpIHsKICAgICAgICAgIHJldHVybiBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwodCwgZSkKICAgICAgICB9KSwKICAgICAgICAoci5wID0gJycpLAogICAgICAgIHIoKHIucyA9IDIpKQogICAgICApCiAgICB9KShbCiAgICAgIGZ1bmN0aW9uICh0LCBlLCByKSB7CiAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KGUsICdfX2VzTW9kdWxlJywgeyB2YWx1ZTogITAgfSk7CiAgICAgICAgY29uc3QgbiA9IHIoMSksCiAgICAgICAgICBpID0gewogICAgICAgICAgICAwOiAnRVJBUl9TVUNDRVNTJywKICAgICAgICAgICAgMTA6ICdFUkFSX0VORF9BUkNISVZFJywKICAgICAgICAgICAgMTE6ICdFUkFSX05PX01FTU9SWScsCiAgICAgICAgICAgIDEyOiAnRVJBUl9CQURfREFUQScsCiAgICAgICAgICAgIDEzOiAnRVJBUl9CQURfQVJDSElWRScsCiAgICAgICAgICAgIDE0OiAnRVJBUl9VTktOT1dOX0ZPUk1BVCcsCiAgICAgICAgICAgIDE1OiAnRVJBUl9FT1BFTicsCiAgICAgICAgICAgIDE2OiAnRVJBUl9FQ1JFQVRFJywKICAgICAgICAgICAgMTc6ICdFUkFSX0VDTE9TRScsCiAgICAgICAgICAgIDE4OiAnRVJBUl9FUkVBRCcsCiAgICAgICAgICAgIDE5OiAnRVJBUl9FV1JJVEUnLAogICAgICAgICAgICAyMDogJ0VSQVJfU01BTExfQlVGJywKICAgICAgICAgICAgMjE6ICdFUkFSX1VOS05PV04nLAogICAgICAgICAgICAyMjogJ0VSQVJfTUlTU0lOR19QQVNTV09SRCcsCiAgICAgICAgICAgIDIzOiAnRVJBUl9FUkVGRVJFTkNFJywKICAgICAgICAgICAgMjQ6ICdFUkFSX0JBRF9QQVNTV09SRCcsCiAgICAgICAgICB9LAogICAgICAgICAgbyA9IHsKICAgICAgICAgICAgMDogJ1N1Y2Nlc3MnLAogICAgICAgICAgICAxMTogJ05vdCBlbm91Z2ggbWVtb3J5JywKICAgICAgICAgICAgMTI6ICdBcmNoaXZlIGhlYWRlciBvciBkYXRhIGFyZSBkYW1hZ2VkJywKICAgICAgICAgICAgMTM6ICdGaWxlIGlzIG5vdCBSQVIgYXJjaGl2ZScsCiAgICAgICAgICAgIDE0OiAnVW5rbm93biBhcmNoaXZlIGZvcm1hdCcsCiAgICAgICAgICAgIDE1OiAnRmlsZSBvcGVuIGVycm9yJywKICAgICAgICAgICAgMTY6ICdGaWxlIGNyZWF0ZSBlcnJvcicsCiAgICAgICAgICAgIDE3OiAnRmlsZSBjbG9zZSBlcnJvcicsCiAgICAgICAgICAgIDE4OiAnRmlsZSByZWFkIGVycm9yJywKICAgICAgICAgICAgMTk6ICdGaWxlIHdyaXRlIGVycm9yJywKICAgICAgICAgICAgMjA6ICdCdWZmZXIgZm9yIGFyY2hpdmUgY29tbWVudCBpcyB0b28gc21hbGwsIGNvbW1lbnQgdHJ1bmNhdGVkJywKICAgICAgICAgICAgMjE6ICdVbmtub3duIGVycm9yJywKICAgICAgICAgICAgMjI6ICdQYXNzd29yZCBmb3IgZW5jcnlwdGVkIGZpbGUgb3IgaGVhZGVyIGlzIG5vdCBzcGVjaWZpZWQnLAogICAgICAgICAgICAyMzogJ0Nhbm5vdCBvcGVuIGZpbGUgc291cmNlIGZvciByZWZlcmVuY2UgcmVjb3JkJywKICAgICAgICAgICAgMjQ6ICdXcm9uZyBwYXNzd29yZCBpcyBzcGVjaWZpZWQnLAogICAgICAgICAgfTsKICAgICAgICBjbGFzcyBzIHsKICAgICAgICAgIGNvbnN0cnVjdG9yKHQgPSAnJykgewogICh0aGlzLl9wYXNzd29yZCA9IHQpLCAodGhpcy5fYXJjaGl2ZSA9IG51bGwpOwogICAgICAgICAgfQogICAgICAgICAgZ2V0RmlsZUxpc3QoKSB7CiAgICAgICAgICAgIGxldCB0LAogICAgICAgICAgICAgIFtlLCByXSA9IHRoaXMub3BlbkFyYyghMCk7CiAgICAgICAgICAgIGlmICgnU1VDQ0VTUycgIT09IGUuc3RhdGUpIHQgPSBbZSwgbnVsbF07CiAgICAgICAgICAgIGVsc2UgewogICAgICAgICAgICAgIGxldCBlLAogICAgICAgICAgICAgICAgbiwKICAgICAgICAgICAgICAgIGkgPSBbXTsKICAgICAgICAgICAgICBmb3IgKDsgKFtlLCBuXSA9IHRoaXMucHJvY2Vzc05leHRGaWxlKCgpID0+ICEwKSksICdTVUNDRVNTJyA9PT0gZS5zdGF0ZTsgKSBpLnB1c2gobi5maWxlSGVhZGVyKTsKICAgICAgICAgICAgICB0ID0gJ0VSQVJfRU5EX0FSQ0hJVkUnICE9PSBlLnJlYXNvbiA/IFtlLCBudWxsXSA6IFt7IHN0YXRlOiAnU1VDQ0VTUycgfSwgeyBhcmNIZWFkZXI6IHIsIGZpbGVIZWFkZXJzOiBpIH1dOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiB0aGlzLmNsb3NlQXJjKCksIHQKICAgICAgICAgIH0KICAgICAgICAgIGV4dHJhY3RBbGwoKSB7CiAgICAgICAgICAgIGxldCB0LAogICAgICAgICAgICAgIFtlLCByXSA9IHRoaXMub3BlbkFyYyghMSk7CiAgICAgICAgICAgIGlmICgnU1VDQ0VTUycgIT09IGUuc3RhdGUpIHQgPSBbZSwgbnVsbF07CiAgICAgICAgICAgIGVsc2UgewogICAgICAgICAgICAgIGxldCBlLAogICAgICAgICAgICAgICAgbiwKICAgICAgICAgICAgICAgIGkgPSBbXTsKICAgICAgICAgICAgICBmb3IgKDsgKFtlLCBuXSA9IHRoaXMucHJvY2Vzc05leHRGaWxlKCgpID0+ICExKSksICdTVUNDRVNTJyA9PT0gZS5zdGF0ZTsgKSBpLnB1c2gobik7CiAgICAgICAgICAgICAgdCA9ICdFUkFSX0VORF9BUkNISVZFJyAhPT0gZS5yZWFzb24gPyBbZSwgbnVsbF0gOiBbeyBzdGF0ZTogJ1NVQ0NFU1MnIH0sIHsgYXJjSGVhZGVyOiByLCBmaWxlczogaSB9XTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gdGhpcy5jbG9zZUFyYygpLCB0CiAgICAgICAgICB9CiAgICAgICAgICBleHRyYWN0RmlsZXModCwgZSkgewogICAgICAgICAgICBsZXQgciwKICAgICAgICAgICAgICBbbiwgaV0gPSB0aGlzLm9wZW5BcmMoITEsIGUpLAogICAgICAgICAgICAgIG8gPSB7fTsKICAgICAgICAgICAgZm9yIChsZXQgZSA9IDA7IGUgPCB0Lmxlbmd0aDsgKytlKSBvW3RbZV1dID0gZTsKICAgICAgICAgICAgaWYgKCdTVUNDRVNTJyAhPT0gbi5zdGF0ZSkgciA9IFtuLCBudWxsXTsKICAgICAgICAgICAgZWxzZSB7CiAgICAgICAgICAgICAgbGV0IGUsCiAgICAgICAgICAgICAgICBuLAogICAgICAgICAgICAgICAgcyA9IEFycmF5KHQubGVuZ3RoKS5maWxsKG51bGwpLAogICAgICAgICAgICAgICAgdSA9IDA7CiAgICAgICAgICAgICAgZm9yICg7OykgewogICAgICAgICAgICAgICAgbGV0IHIgPSAhMSwKICAgICAgICAgICAgICAgICAgaSA9IG51bGw7CiAgICAgICAgICAgICAgICBpZiAoCiAgICAgICAgICAgICAgICAgICgoW2UsIG5dID0gdGhpcy5wcm9jZXNzTmV4dEZpbGUoKHQpID0+ICh0IGluIG8gPyAoKGkgPSBvW3RdKSwgITEpIDogKChyID0gITApLCAhMCkpKSksCiAgICAgICAgICAgICAgICAgICdTVUNDRVNTJyAhPT0gZS5zdGF0ZSkKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgYnJlYWsKICAgICAgICAgICAgICAgIGlmICghciAmJiAoKHNbaV0gPSBuKSwgKyt1ID09PSB0Lmxlbmd0aCkpIHsKICAgICAgICAgICAgICAgICAgZS5yZWFzb24gPSAnRVJBUl9FTkRfQVJDSElWRSc7CiAgICAgICAgICAgICAgICAgIGJyZWFrCiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHIgPSAnRVJBUl9FTkRfQVJDSElWRScgIT09IGUucmVhc29uID8gW2UsIG51bGxdIDogW3sgc3RhdGU6ICdTVUNDRVNTJyB9LCB7IGFyY0hlYWRlcjogaSwgZmlsZXM6IHMgfV07CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIHRoaXMuY2xvc2VBcmMoKSwgcgogICAgICAgICAgfQogICAgICAgICAgZmlsZUNyZWF0ZWQodCkge30KICAgICAgICAgIGNsb3NlKHQpIHsKICAgICAgICAgICAgdGhpcy5fbGFzdEZpbGVDb250ZW50ID0gdGhpcy5jbG9zZUZpbGUodCk7CiAgICAgICAgICB9CiAgICAgICAgICBvcGVuQXJjKHQsIGUpIHsKICAobi5FeHQuY3VycmVudCA9IHRoaXMpLCAodGhpcy5fYXJjaGl2ZSA9IG5ldyB1bnBhY2suUmFyQXJjaGl2ZSgpKTsKICAgICAgICAgICAgbGV0IHIsCiAgICAgICAgICAgICAgaSA9IHRoaXMuX2FyY2hpdmUub3Blbih0aGlzLl9maWxlUGF0aCwgZSB8fCB0aGlzLl9wYXNzd29yZCwgdCk7CiAgICAgICAgICAgIHJldHVybiAoCiAgICAgICAgICAgICAgKHIgPQogICAgICAgICAgICAgICAgMCAhPT0gaS5zdGF0ZS5lcnJDb2RlCiAgICAgICAgICAgICAgICAgID8gW3RoaXMuZ2V0RmFpbEluZm8oaS5zdGF0ZS5lcnJDb2RlLCBpLnN0YXRlLmVyclR5cGUpLCBudWxsXQogICAgICAgICAgICAgICAgICA6IFsKICAgICAgICAgICAgICAgICAgICAgIHsgc3RhdGU6ICdTVUNDRVNTJyB9LAogICAgICAgICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgICAgICBjb21tZW50OiBpLmNvbW1lbnQsCiAgICAgICAgICAgICAgICAgICAgICAgIGZsYWdzOiB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgdm9sdW1lOiAwICE9ICgxICYgaS5mbGFncyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgbG9jazogMCAhPSAoNCAmIGkuZmxhZ3MpLAogICAgICAgICAgICAgICAgICAgICAgICAgIHNvbGlkOiAwICE9ICg4ICYgaS5mbGFncyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgYXV0aEluZm86IDAgIT0gKDMyICYgaS5mbGFncyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgcmVjb3ZlcnlSZWNvcmQ6IDAgIT0gKDY0ICYgaS5mbGFncyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgaGVhZGVyRW5jcnlwdGVkOiAwICE9ICgxMjggJiBpLmZsYWdzKSwKICAgICAgICAgICAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICAgICAgXSksCiAgICAgICAgICAgICAgKG4uRXh0LmN1cnJlbnQgPSBudWxsKSwKICAgICAgICAgICAgICByCiAgICAgICAgICAgICkKICAgICAgICAgIH0KICAgICAgICAgIHByb2Nlc3NOZXh0RmlsZSh0KSB7CiAgICAgICAgICAgIGxldCBlOwogICAgICAgICAgICBuLkV4dC5jdXJyZW50ID0gdGhpczsKICAgICAgICAgICAgbGV0IHIgPSB0aGlzLl9hcmNoaXZlLmdldEZpbGVIZWFkZXIoKSwKICAgICAgICAgICAgICBpID0gW3sgc3RhdGU6ICdTVUNDRVNTJyB9LCBudWxsXTsKICAgICAgICAgICAgaWYgKDAgPT09IHIuc3RhdGUuZXJyQ29kZSkgewogICAgICAgICAgICAgIGxldCBlID0gdChyLm5hbWUpOwogICAgICAgICAgICAgIHRoaXMuX2xhc3RGaWxlQ29udGVudCA9IG51bGw7CiAgICAgICAgICAgICAgbGV0IG4gPSB0aGlzLl9hcmNoaXZlLnJlYWRGaWxlKGUpOwogICAgICAgICAgICAgIDAgPT09IG4uZXJyQ29kZSB8fAogICAgICAgICAgICAgICAgZSB8fAogICAgICAgICAgICAgICAgKChpWzBdID0gdGhpcy5nZXRGYWlsSW5mbyhuLmVyckNvZGUsIG4uZXJyVHlwZSkpLAogICAgICAgICAgICAgICAgMjIgPT09IG4uZXJyQ29kZSA/IChuID0gdGhpcy5fYXJjaGl2ZS5yZWFkRmlsZSghMCkpIDogKG4uZXJyQ29kZSA9IDApKSwKICAgICAgICAgICAgICAgIDAgPT09IG4uZXJyQ29kZQogICAgICAgICAgICAgICAgICA/IChpWzFdID0gdGhpcy5fbGFzdEZpbGVDb250ZW50KQogICAgICAgICAgICAgICAgICA6ICgoci5zdGF0ZS5lcnJDb2RlID0gbi5lcnJDb2RlKSwgKHIuc3RhdGUuZXJyVHlwZSA9IG4uZXJyVHlwZSkpLAogICAgICAgICAgICAgICAgKHRoaXMuX2xhc3RGaWxlQ29udGVudCA9IG51bGwpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiAoCiAgICAgICAgICAgICAgKGUgPQogICAgICAgICAgICAgICAgMCAhPT0gci5zdGF0ZS5lcnJDb2RlCiAgICAgICAgICAgICAgICAgID8gW3RoaXMuZ2V0RmFpbEluZm8oci5zdGF0ZS5lcnJDb2RlLCByLnN0YXRlLmVyclR5cGUpLCBudWxsXQogICAgICAgICAgICAgICAgICA6IFsKICAgICAgICAgICAgICAgICAgICAgIHsgc3RhdGU6ICdTVUNDRVNTJyB9LAogICAgICAgICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgICAgICBmaWxlSGVhZGVyOiB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZTogci5uYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgIGZsYWdzOiB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmNyeXB0ZWQ6IDAgIT0gKDQgJiByLmZsYWdzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNvbGlkOiAwICE9ICgxNiAmIHIuZmxhZ3MpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlyZWN0b3J5OiAwICE9ICgzMiAmIHIuZmxhZ3MpLAogICAgICAgICAgICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgcGFja1NpemU6IHIucGFja1NpemUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgdW5wU2l6ZTogci51bnBTaXplLAogICAgICAgICAgICAgICAgICAgICAgICAgIGNyYzogci5jcmMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgdGltZTogKGZ1bmN0aW9uICh0KSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBlID0gWzUsIDYsIDUsIDUsIDQsIDddOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV0IHIgPSBbXTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvciAobGV0IG4gb2YgZSkgci5wdXNoKHQgJiAoKDEgPDwgbikgLSAxKSksICh0ID4+PSBuKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldCBuID0gKHQpID0+ICh0IDwgMTAgPyAnMCcgKyB0IDogJycgKyB0KTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiAoCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGAkezE5ODAgKyAociA9IHIucmV2ZXJzZSgpKVswXX0tJHtuKHJbMV0pfS0ke24oclsyXSl9YCArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBUJHtuKHJbM10pfToke24ocls0XSl9OiR7bigyICogcls1XSl9LjAwMGAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgICB9KShyLnRpbWUpLAogICAgICAgICAgICAgICAgICAgICAgICAgIHVucFZlcjogYCR7TWF0aC5mbG9vcihyLnVucFZlciAvIDEwKX0uJHtyLnVucFZlciAlIDEwfWAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kOiAoZnVuY3Rpb24gKHQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiAoCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHsgNDg6ICdTdG9yaW5nJywgNDk6ICdGYXN0ZXN0JywgNTA6ICdGYXN0JywgNTE6ICdOb3JtYWwnLCA1MjogJ0dvb2QnLCA1MzogJ0Jlc3QnIH1bdF0gfHwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1Vua25vd24nCiAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgICAgfSkoci5tZXRob2QpLAogICAgICAgICAgICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICAgICAgICAgICBleHRyYWN0OiBpLAogICAgICAgICAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAgICAgICBdKSwKICAgICAgICAgICAgICAobi5FeHQuY3VycmVudCA9IG51bGwpLAogICAgICAgICAgICAgIGUKICAgICAgICAgICAgKQogICAgICAgICAgfQogICAgICAgICAgY2xvc2VBcmMoKSB7CiAgKG4uRXh0LmN1cnJlbnQgPSB0aGlzKSwgdGhpcy5fYXJjaGl2ZS5kZWxldGUoKSwgKG4uRXh0LmN1cnJlbnQgPSBudWxsKSwgKHRoaXMuX2FyY2hpdmUgPSBudWxsKTsKICAgICAgICAgIH0KICAgICAgICAgIGdldEZhaWxJbmZvKHQsIGUpIHsKICAgICAgICAgICAgcmV0dXJuIHsgc3RhdGU6ICdGQUlMJywgcmVhc29uOiBpW3RdLCBtc2c6IG9bdF0gfQogICAgICAgICAgfQogICAgICAgIH0KICAocy5fY3VycmVudCA9IG51bGwpLCAoZS5FeHRyYWN0b3IgPSBzKTsKICAgICAgfSwKICAgICAgZnVuY3Rpb24gKHQsIGUsIHIpIHsKICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkoZSwgJ19fZXNNb2R1bGUnLCB7IHZhbHVlOiAhMCB9KSwgKGUuRXh0ID0geyBjdXJyZW50OiBudWxsIH0pOwogICAgICB9LAogICAgICBmdW5jdGlvbiAodCwgZSwgcikgewogICAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShlLCAnX19lc01vZHVsZScsIHsgdmFsdWU6ICEwIH0pLAogICAgICAgICAgKGZ1bmN0aW9uICh0KSB7CiAgICAgICAgICAgIGZvciAodmFyIHIgaW4gdCkgZS5oYXNPd25Qcm9wZXJ0eShyKSB8fCAoZVtyXSA9IHRbcl0pOwogICAgICAgICAgfSkocigzKSk7CiAgICAgICAgdmFyIG4gPSByKDEpOwogICAgICAgIGUuRXh0ID0gbi5FeHQ7CiAgICAgIH0sCiAgICAgIGZ1bmN0aW9uICh0LCBlLCByKSB7CiAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KGUsICdfX2VzTW9kdWxlJywgeyB2YWx1ZTogITAgfSk7CiAgICAgICAgY29uc3QgbiA9IHIoNCksCiAgICAgICAgICBpID0gcig2KQogICAgICAgIDsoZS5jcmVhdGVFeHRyYWN0b3JGcm9tRGF0YSA9IGZ1bmN0aW9uICh0LCBlID0gJycpIHsKICAgICAgICAgIHJldHVybiBuZXcgbi5EYXRhRXh0cmFjdG9yKHQsIGUpCiAgICAgICAgfSksCiAgICAgICAgICAoZS5jcmVhdGVFeHRyYWN0b3JGcm9tRmlsZSA9IGZ1bmN0aW9uICh0LCBlID0gJycsIHIgPSAnJykgewogICAgICAgICAgICByZXR1cm4gbmV3IGkuRmlsZUV4dHJhY3Rvcih0LCBlLCByKQogICAgICAgICAgfSk7CiAgICAgIH0sCiAgICAgIGZ1bmN0aW9uICh0LCBlLCByKSB7CiAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KGUsICdfX2VzTW9kdWxlJywgeyB2YWx1ZTogITAgfSk7CiAgICAgICAgY29uc3QgbiA9IHIoNSksCiAgICAgICAgICBpID0gcigwKTsKICAgICAgICBlLkRhdGFFeHRyYWN0b3IgPSBjbGFzcyBleHRlbmRzIGkuRXh0cmFjdG9yIHsKICAgICAgICAgIGNvbnN0cnVjdG9yKHQsIGUpIHsKICAgICAgICAgICAgc3VwZXIoZSksICh0aGlzLmRhdGFGaWxlcyA9IHt9KSwgKHRoaXMuZGF0YUZpbGVNYXAgPSB7fSksICh0aGlzLmN1cnJlbnRGZCA9IDEpOwogICAgICAgICAgICBsZXQgciA9IHsgZmlsZTogbmV3IG4uRGF0YUZpbGUobmV3IFVpbnQ4QXJyYXkodCkpLCBmZDogdGhpcy5jdXJyZW50RmQrKyB9CiAgICAgICAgICAgIDsodGhpcy5fZmlsZVBhdGggPSAnX2RlZmF1bHRVbnJhckpTXy5yYXInKSwKICAgICAgICAgICAgICAodGhpcy5kYXRhRmlsZXNbdGhpcy5fZmlsZVBhdGhdID0gciksCiAgICAgICAgICAgICAgKHRoaXMuZGF0YUZpbGVNYXBbci5mZF0gPSB0aGlzLl9maWxlUGF0aCk7CiAgICAgICAgICB9CiAgICAgICAgICBvcGVuKHQpIHsKICAgICAgICAgICAgbGV0IGUgPSB0aGlzLmRhdGFGaWxlc1t0XTsKICAgICAgICAgICAgcmV0dXJuIGUgPyBlLmZkIDogMAogICAgICAgICAgfQogICAgICAgICAgY3JlYXRlKHQpIHsKICAgICAgICAgICAgbGV0IGUgPSB0aGlzLmN1cnJlbnRGZCsrOwogICAgICAgICAgICByZXR1cm4gKHRoaXMuZGF0YUZpbGVzW3RdID0geyBmaWxlOiBuZXcgbi5EYXRhRmlsZSgpLCBmZDogdGhpcy5jdXJyZW50RmQrKyB9KSwgKHRoaXMuZGF0YUZpbGVNYXBbZV0gPSB0KSwgZQogICAgICAgICAgfQogICAgICAgICAgY2xvc2VGaWxlKHQpIHsKICAgICAgICAgICAgbGV0IGUgPSB0aGlzLmRhdGFGaWxlc1t0aGlzLmRhdGFGaWxlTWFwW3RdXTsKICAgICAgICAgICAgaWYgKCFlKSByZXR1cm4gbnVsbAogICAgICAgICAgICBsZXQgciA9IGUuZmlsZS5yZWFkQWxsKCk7CiAgICAgICAgICAgIHJldHVybiAoCiAgICAgICAgICAgICAgMSAhPT0gdCA/IChkZWxldGUgdGhpcy5kYXRhRmlsZXNbdGhpcy5kYXRhRmlsZU1hcFt0XV0sIGRlbGV0ZSB0aGlzLmRhdGFGaWxlTWFwW3RdKSA6IGUuZmlsZS5zZWVrKDAsICdTRVQnKSwKICAgICAgICAgICAgICByCiAgICAgICAgICAgICkKICAgICAgICAgIH0KICAgICAgICAgIHJlYWQodCwgZSwgcikgewogICAgICAgICAgICBsZXQgbiA9IHRoaXMuZGF0YUZpbGVzW3RoaXMuZGF0YUZpbGVNYXBbdF1dOwogICAgICAgICAgICBpZiAoIW4pIHJldHVybiAtMQogICAgICAgICAgICBsZXQgaSA9IG4uZmlsZS5yZWFkKHIpOwogICAgICAgICAgICByZXR1cm4gbnVsbCA9PT0gaSA/IC0xIDogKHVucGFjay5IRUFQVTguc2V0KGksIGUpLCBpLmJ5dGVMZW5ndGgpCiAgICAgICAgICB9CiAgICAgICAgICB3cml0ZSh0LCBlLCByKSB7CiAgICAgICAgICAgIGxldCBuID0gdGhpcy5kYXRhRmlsZXNbdGhpcy5kYXRhRmlsZU1hcFt0XV07CiAgICAgICAgICAgIHJldHVybiAhIW4gJiYgKG4uZmlsZS53cml0ZSh1bnBhY2suSEVBUFU4LnNsaWNlKGUsIGUgKyByKSksICEwKQogICAgICAgICAgfQogICAgICAgICAgdGVsbCh0KSB7CiAgICAgICAgICAgIGxldCBlID0gdGhpcy5kYXRhRmlsZXNbdGhpcy5kYXRhRmlsZU1hcFt0XV07CiAgICAgICAgICAgIHJldHVybiBlID8gZS5maWxlLnRlbGwoKSA6IC0xCiAgICAgICAgICB9CiAgICAgICAgICBzZWVrKHQsIGUsIHIpIHsKICAgICAgICAgICAgbGV0IG4gPSB0aGlzLmRhdGFGaWxlc1t0aGlzLmRhdGFGaWxlTWFwW3RdXTsKICAgICAgICAgICAgcmV0dXJuICEhbiAmJiBuLmZpbGUuc2VlayhlLCByKQogICAgICAgICAgfQogICAgICAgIH07CiAgICAgIH0sCiAgICAgIGZ1bmN0aW9uICh0LCBlLCByKSB7CiAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KGUsICdfX2VzTW9kdWxlJywgeyB2YWx1ZTogITAgfSk7CiAgICAgICAgZS5EYXRhRmlsZSA9IGNsYXNzIHsKICAgICAgICAgIGNvbnN0cnVjdG9yKHQpIHsKICAodGhpcy5idWZmZXJzID0gW10pLAogICAgICAgICAgICAgICh0aGlzLnBvcyA9IDApLAogICAgICAgICAgICAgICh0aGlzLnNpemUgPSAwKSwKICAgICAgICAgICAgICB0ICYmICh0aGlzLmJ1ZmZlcnMucHVzaCh0KSwgKHRoaXMuc2l6ZSA9IHQuYnl0ZUxlbmd0aCksICh0aGlzLnBvcyA9IDApKTsKICAgICAgICAgIH0KICAgICAgICAgIHJlYWQodCkgewogICAgICAgICAgICBpZiAoKHRoaXMuZmxhdHRlbigpLCB0ICsgdGhpcy5wb3MgPiB0aGlzLnNpemUpKSByZXR1cm4gbnVsbAogICAgICAgICAgICBsZXQgZSA9IHRoaXMucG9zOwogICAgICAgICAgICByZXR1cm4gKHRoaXMucG9zICs9IHQpLCB0aGlzLmJ1ZmZlcnNbMF0uc2xpY2UoZSwgdGhpcy5wb3MpCiAgICAgICAgICB9CiAgICAgICAgICByZWFkQWxsKCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy5mbGF0dGVuKCksIHRoaXMuYnVmZmVyc1swXQogICAgICAgICAgfQogICAgICAgICAgd3JpdGUodCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy5idWZmZXJzLnB1c2godCksICh0aGlzLnNpemUgKz0gdC5ieXRlTGVuZ3RoKSwgKHRoaXMucG9zICs9IHQuYnl0ZUxlbmd0aCksICEwCiAgICAgICAgICB9CiAgICAgICAgICB0ZWxsKCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy5wb3MKICAgICAgICAgIH0KICAgICAgICAgIHNlZWsodCwgZSkgewogICAgICAgICAgICBsZXQgciA9IHRoaXMucG9zOwogICAgICAgICAgICByZXR1cm4gKAogICAgICAgICAgICAgICdTRVQnID09PSBlID8gKHIgPSB0KSA6ICdDVVInID09PSBlID8gKHIgKz0gdCkgOiAociA9IHRoaXMuc2l6ZSAtIHQpLAogICAgICAgICAgICAgICEociA8IDAgfHwgciA+IHRoaXMuc2l6ZSB8fCAoKHRoaXMucG9zID0gciksIDApKQogICAgICAgICAgICApCiAgICAgICAgICB9CiAgICAgICAgICBmbGF0dGVuKCkgewogICAgICAgICAgICBpZiAodGhpcy5idWZmZXJzLmxlbmd0aCA8PSAxKSByZXR1cm4KICAgICAgICAgICAgbGV0IHQgPSBuZXcgVWludDhBcnJheSh0aGlzLnNpemUpLAogICAgICAgICAgICAgIGUgPSAwOwogICAgICAgICAgICBmb3IgKGxldCByIG9mIHRoaXMuYnVmZmVycykgdC5zZXQociwgZSksIChlICs9IHIuYnl0ZUxlbmd0aCk7CiAgICAgICAgICAgIHRoaXMuYnVmZmVycyA9IFt0XTsKICAgICAgICAgIH0KICAgICAgICB9OwogICAgICB9LAogICAgICBmdW5jdGlvbiAodCwgZSwgcikgewogIChmdW5jdGlvbiAodCkgewogICAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KGUsICdfX2VzTW9kdWxlJywgeyB2YWx1ZTogITAgfSk7CiAgICAgICAgICBjb25zdCBuID0gcigxMiksCiAgICAgICAgICAgIGkgPSByKDEzKSwKICAgICAgICAgICAgbyA9IHIoMCk7CiAgICAgICAgICBlLkZpbGVFeHRyYWN0b3IgPSBjbGFzcyBleHRlbmRzIG8uRXh0cmFjdG9yIHsKICAgICAgICAgICAgY29uc3RydWN0b3IodCwgZSwgcikgewogICAgICAgICAgICAgIHN1cGVyKHIpLCAodGhpcy5fZmlsZVBhdGggPSB0KSwgKHRoaXMuZmlsZU1hcCA9IHt9KSwgKHRoaXMuX3RhcmdldCA9IGUpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIG9wZW4odCkgewogICAgICAgICAgICAgIGxldCBlID0gbi5vcGVuU3luYyh0LCAncicpOwogICAgICAgICAgICAgIHJldHVybiAodGhpcy5maWxlTWFwW2VdID0geyBzaXplOiBuLmZzdGF0U3luYyhlKS5zaXplLCBwb3M6IDAsIG5hbWU6IHQgfSksIGUKICAgICAgICAgICAgfQogICAgICAgICAgICBjcmVhdGUodCkgewogICAgICAgICAgICAgIGxldCBlID0gaS5qb2luKHRoaXMuX3RhcmdldCwgdCk7CiAgICAgICAgICAgICAgaS5wYXJzZShlKQogICAgICAgICAgICAgICAgLmRpci5zcGxpdCgnLycpCiAgICAgICAgICAgICAgICAucmVkdWNlKCh0LCBlKSA9PiAoKHQgKz0gZSArICcvJyksIG4uZXhpc3RzU3luYyh0KSB8fCBuLm1rZGlyU3luYyh0KSwgdCksICcnKTsKICAgICAgICAgICAgICBsZXQgciA9IG4ub3BlblN5bmMoZSwgJ3cnKTsKICAgICAgICAgICAgICByZXR1cm4gKHRoaXMuZmlsZU1hcFtyXSA9IHsgc2l6ZTogMCwgcG9zOiAwLCBuYW1lOiB0IH0pLCByCiAgICAgICAgICAgIH0KICAgICAgICAgICAgY2xvc2VGaWxlKHQpIHsKICAgICAgICAgICAgICByZXR1cm4gZGVsZXRlIHRoaXMuZmlsZU1hcFt0XSwgbi5jbG9zZVN5bmModCksIG51bGwKICAgICAgICAgICAgfQogICAgICAgICAgICByZWFkKGUsIHIsIGkpIHsKICAgICAgICAgICAgICBsZXQgbyA9IHRoaXMuZmlsZU1hcFtlXSwKICAgICAgICAgICAgICAgIHMgPSBuZXcgdChpKSwKICAgICAgICAgICAgICAgIHUgPSBuLnJlYWRTeW5jKGUsIHMsIDAsIGksIG8ucG9zKTsKICAgICAgICAgICAgICByZXR1cm4gdW5wYWNrLkhFQVBVOC5zZXQocywgciksIChvLnBvcyArPSB1KSwgdQogICAgICAgICAgICB9CiAgICAgICAgICAgIHdyaXRlKGUsIHIsIGkpIHsKICAgICAgICAgICAgICBsZXQgbyA9IHRoaXMuZmlsZU1hcFtlXSwKICAgICAgICAgICAgICAgIHMgPSBuLndyaXRlU3luYyhlLCBuZXcgdCh1bnBhY2suSEVBUFU4LnN1YmFycmF5KHIsIHIgKyBpKSksIDAsIGkpOwogICAgICAgICAgICAgIHJldHVybiAoby5wb3MgKz0gcyksIChvLnNpemUgKz0gcyksIHMgPT09IGkKICAgICAgICAgICAgfQogICAgICAgICAgICB0ZWxsKHQpIHsKICAgICAgICAgICAgICByZXR1cm4gdGhpcy5maWxlTWFwW3RdLnBvcwogICAgICAgICAgICB9CiAgICAgICAgICAgIHNlZWsodCwgZSwgcikgewogICAgICAgICAgICAgIGxldCBuID0gdGhpcy5maWxlTWFwW3RdLAogICAgICAgICAgICAgICAgaSA9IG4ucG9zOwogICAgICAgICAgICAgIHJldHVybiAoCiAgICAgICAgICAgICAgICAnU0VUJyA9PT0gciA/IChpID0gMCkgOiAnRU5EJyA9PT0gciAmJiAoaSA9IG4uc2l6ZSksICEoKGkgKz0gZSkgPCAwIHx8IGkgPiBuLnNpemUgfHwgKChuLnBvcyA9IGkpLCAwKSkKICAgICAgICAgICAgICApCiAgICAgICAgICAgIH0KICAgICAgICAgIH07CiAgICAgICAgfS5jYWxsKHRoaXMsIHIoNykuQnVmZmVyKSk7CiAgICAgIH0sCiAgICAgIGZ1bmN0aW9uICh0LCBlLCByKSB7CiAgKGZ1bmN0aW9uICh0KSB7CiAgICAgICAgICAvKiEKICAgICAgICAgICAqIFRoZSBidWZmZXIgbW9kdWxlIGZyb20gbm9kZS5qcywgZm9yIHRoZSBicm93c2VyLgogICAgICAgICAgICoKICAgICAgICAgICAqIEBhdXRob3IgICBGZXJvc3MgQWJvdWtoYWRpamVoIDxmZXJvc3NAZmVyb3NzLm9yZz4gPGh0dHA6Ly9mZXJvc3Mub3JnPgogICAgICAgICAgICogQGxpY2Vuc2UgIE1JVAogICAgICAgICAgICovCiAgICAgICAgICB2YXIgbiA9IHIoOSksCiAgICAgICAgICAgIGkgPSByKDEwKSwKICAgICAgICAgICAgbyA9IHIoMTEpOwogICAgICAgICAgZnVuY3Rpb24gcygpIHsKICAgICAgICAgICAgcmV0dXJuIGEuVFlQRURfQVJSQVlfU1VQUE9SVCA/IDIxNDc0ODM2NDcgOiAxMDczNzQxODIzCiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiB1KHQsIGUpIHsKICAgICAgICAgICAgaWYgKHMoKSA8IGUpIHRocm93IG5ldyBSYW5nZUVycm9yKCdJbnZhbGlkIHR5cGVkIGFycmF5IGxlbmd0aCcpCiAgICAgICAgICAgIHJldHVybiAoCiAgICAgICAgICAgICAgYS5UWVBFRF9BUlJBWV9TVVBQT1JUCiAgICAgICAgICAgICAgICA/ICgodCA9IG5ldyBVaW50OEFycmF5KGUpKS5fX3Byb3RvX18gPSBhLnByb3RvdHlwZSkKICAgICAgICAgICAgICAgIDogKG51bGwgPT09IHQgJiYgKHQgPSBuZXcgYShlKSksICh0Lmxlbmd0aCA9IGUpKSwKICAgICAgICAgICAgICB0CiAgICAgICAgICAgICkKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIGEodCwgZSwgcikgewogICAgICAgICAgICBpZiAoIShhLlRZUEVEX0FSUkFZX1NVUFBPUlQgfHwgdGhpcyBpbnN0YW5jZW9mIGEpKSByZXR1cm4gbmV3IGEodCwgZSwgcikKICAgICAgICAgICAgaWYgKCdudW1iZXInID09IHR5cGVvZiB0KSB7CiAgICAgICAgICAgICAgaWYgKCdzdHJpbmcnID09IHR5cGVvZiBlKQogICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJZiBlbmNvZGluZyBpcyBzcGVjaWZpZWQgdGhlbiB0aGUgZmlyc3QgYXJndW1lbnQgbXVzdCBiZSBhIHN0cmluZycpCiAgICAgICAgICAgICAgcmV0dXJuIGwodGhpcywgdCkKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gZih0aGlzLCB0LCBlLCByKQogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gZih0LCBlLCByLCBuKSB7CiAgICAgICAgICAgIGlmICgnbnVtYmVyJyA9PSB0eXBlb2YgZSkgdGhyb3cgbmV3IFR5cGVFcnJvcignInZhbHVlIiBhcmd1bWVudCBtdXN0IG5vdCBiZSBhIG51bWJlcicpCiAgICAgICAgICAgIHJldHVybiAndW5kZWZpbmVkJyAhPSB0eXBlb2YgQXJyYXlCdWZmZXIgJiYgZSBpbnN0YW5jZW9mIEFycmF5QnVmZmVyCiAgICAgICAgICAgICAgPyAoZnVuY3Rpb24gKHQsIGUsIHIsIG4pIHsKICAgICAgICAgICAgICAgICAgaWYgKChlLmJ5dGVMZW5ndGgsIHIgPCAwIHx8IGUuYnl0ZUxlbmd0aCA8IHIpKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcigiJ29mZnNldCcgaXMgb3V0IG9mIGJvdW5kcyIpCiAgICAgICAgICAgICAgICAgIGlmIChlLmJ5dGVMZW5ndGggPCByICsgKG4gfHwgMCkpIHRocm93IG5ldyBSYW5nZUVycm9yKCInbGVuZ3RoJyBpcyBvdXQgb2YgYm91bmRzIikKICAgICAgICAgICAgICAgICAgZSA9CiAgICAgICAgICAgICAgICAgICAgdm9pZCAwID09PSByICYmIHZvaWQgMCA9PT0gbgogICAgICAgICAgICAgICAgICAgICAgPyBuZXcgVWludDhBcnJheShlKQogICAgICAgICAgICAgICAgICAgICAgOiB2b2lkIDAgPT09IG4KICAgICAgICAgICAgICAgICAgICAgID8gbmV3IFVpbnQ4QXJyYXkoZSwgcikKICAgICAgICAgICAgICAgICAgICAgIDogbmV3IFVpbnQ4QXJyYXkoZSwgciwgbik7CiAgICAgICAgICAgICAgICAgIGEuVFlQRURfQVJSQVlfU1VQUE9SVCA/ICgodCA9IGUpLl9fcHJvdG9fXyA9IGEucHJvdG90eXBlKSA6ICh0ID0gYyh0LCBlKSk7CiAgICAgICAgICAgICAgICAgIHJldHVybiB0CiAgICAgICAgICAgICAgICB9KSh0LCBlLCByLCBuKQogICAgICAgICAgICAgIDogJ3N0cmluZycgPT0gdHlwZW9mIGUKICAgICAgICAgICAgICA/IChmdW5jdGlvbiAodCwgZSwgcikgewogICgnc3RyaW5nJyA9PSB0eXBlb2YgciAmJiAnJyAhPT0gcikgfHwgKHIgPSAndXRmOCcpOwogICAgICAgICAgICAgICAgICBpZiAoIWEuaXNFbmNvZGluZyhyKSkgdGhyb3cgbmV3IFR5cGVFcnJvcignImVuY29kaW5nIiBtdXN0IGJlIGEgdmFsaWQgc3RyaW5nIGVuY29kaW5nJykKICAgICAgICAgICAgICAgICAgdmFyIG4gPSAwIHwgZyhlLCByKSwKICAgICAgICAgICAgICAgICAgICBpID0gKHQgPSB1KHQsIG4pKS53cml0ZShlLCByKTsKICAgICAgICAgICAgICAgICAgaSAhPT0gbiAmJiAodCA9IHQuc2xpY2UoMCwgaSkpOwogICAgICAgICAgICAgICAgICByZXR1cm4gdAogICAgICAgICAgICAgICAgfSkodCwgZSwgcikKICAgICAgICAgICAgICA6IChmdW5jdGlvbiAodCwgZSkgewogICAgICAgICAgICAgICAgICBpZiAoYS5pc0J1ZmZlcihlKSkgewogICAgICAgICAgICAgICAgICAgIHZhciByID0gMCB8IHAoZS5sZW5ndGgpOwogICAgICAgICAgICAgICAgICAgIHJldHVybiAwID09PSAodCA9IHUodCwgcikpLmxlbmd0aCA/IHQgOiAoZS5jb3B5KHQsIDAsIDAsIHIpLCB0KQogICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgIGlmIChlKSB7CiAgICAgICAgICAgICAgICAgICAgaWYgKCgndW5kZWZpbmVkJyAhPSB0eXBlb2YgQXJyYXlCdWZmZXIgJiYgZS5idWZmZXIgaW5zdGFuY2VvZiBBcnJheUJ1ZmZlcikgfHwgJ2xlbmd0aCcgaW4gZSkKICAgICAgICAgICAgICAgICAgICAgIHJldHVybiAnbnVtYmVyJyAhPSB0eXBlb2YgZS5sZW5ndGggfHwKICAgICAgICAgICAgICAgICAgICAgICAgKGZ1bmN0aW9uICh0KSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHQgIT0gdAogICAgICAgICAgICAgICAgICAgICAgICB9KShlLmxlbmd0aCkKICAgICAgICAgICAgICAgICAgICAgICAgPyB1KHQsIDApCiAgICAgICAgICAgICAgICAgICAgICAgIDogYyh0LCBlKQogICAgICAgICAgICAgICAgICAgIGlmICgnQnVmZmVyJyA9PT0gZS50eXBlICYmIG8oZS5kYXRhKSkgcmV0dXJuIGModCwgZS5kYXRhKQogICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoCiAgICAgICAgICAgICAgICAgICAgJ0ZpcnN0IGFyZ3VtZW50IG11c3QgYmUgYSBzdHJpbmcsIEJ1ZmZlciwgQXJyYXlCdWZmZXIsIEFycmF5LCBvciBhcnJheS1saWtlIG9iamVjdC4nCiAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIH0pKHQsIGUpCiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBoKHQpIHsKICAgICAgICAgICAgaWYgKCdudW1iZXInICE9IHR5cGVvZiB0KSB0aHJvdyBuZXcgVHlwZUVycm9yKCcic2l6ZSIgYXJndW1lbnQgbXVzdCBiZSBhIG51bWJlcicpCiAgICAgICAgICAgIGlmICh0IDwgMCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJyJzaXplIiBhcmd1bWVudCBtdXN0IG5vdCBiZSBuZWdhdGl2ZScpCiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBsKHQsIGUpIHsKICAgICAgICAgICAgaWYgKChoKGUpLCAodCA9IHUodCwgZSA8IDAgPyAwIDogMCB8IHAoZSkpKSwgIWEuVFlQRURfQVJSQVlfU1VQUE9SVCkpIGZvciAodmFyIHIgPSAwOyByIDwgZTsgKytyKSB0W3JdID0gMDsKICAgICAgICAgICAgcmV0dXJuIHQKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIGModCwgZSkgewogICAgICAgICAgICB2YXIgciA9IGUubGVuZ3RoIDwgMCA/IDAgOiAwIHwgcChlLmxlbmd0aCk7CiAgICAgICAgICAgIHQgPSB1KHQsIHIpOwogICAgICAgICAgICBmb3IgKHZhciBuID0gMDsgbiA8IHI7IG4gKz0gMSkgdFtuXSA9IDI1NSAmIGVbbl07CiAgICAgICAgICAgIHJldHVybiB0CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBwKHQpIHsKICAgICAgICAgICAgaWYgKHQgPj0gcygpKQogICAgICAgICAgICAgIHRocm93IG5ldyBSYW5nZUVycm9yKAogICAgICAgICAgICAgICAgJ0F0dGVtcHQgdG8gYWxsb2NhdGUgQnVmZmVyIGxhcmdlciB0aGFuIG1heGltdW0gc2l6ZTogMHgnICsgcygpLnRvU3RyaW5nKDE2KSArICcgYnl0ZXMnCiAgICAgICAgICAgICAgKQogICAgICAgICAgICByZXR1cm4gMCB8IHQKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIGcodCwgZSkgewogICAgICAgICAgICBpZiAoYS5pc0J1ZmZlcih0KSkgcmV0dXJuIHQubGVuZ3RoCiAgICAgICAgICAgIGlmICgKICAgICAgICAgICAgICAndW5kZWZpbmVkJyAhPSB0eXBlb2YgQXJyYXlCdWZmZXIgJiYKICAgICAgICAgICAgICAnZnVuY3Rpb24nID09IHR5cGVvZiBBcnJheUJ1ZmZlci5pc1ZpZXcgJiYKICAgICAgICAgICAgICAoQXJyYXlCdWZmZXIuaXNWaWV3KHQpIHx8IHQgaW5zdGFuY2VvZiBBcnJheUJ1ZmZlcikKICAgICAgICAgICAgKQogICAgICAgICAgICAgIHJldHVybiB0LmJ5dGVMZW5ndGgKICAgICAgICAgICAgJ3N0cmluZycgIT0gdHlwZW9mIHQgJiYgKHQgPSAnJyArIHQpOwogICAgICAgICAgICB2YXIgciA9IHQubGVuZ3RoOwogICAgICAgICAgICBpZiAoMCA9PT0gcikgcmV0dXJuIDAKICAgICAgICAgICAgZm9yICh2YXIgbiA9ICExOyA7ICkKICAgICAgICAgICAgICBzd2l0Y2ggKGUpIHsKICAgICAgICAgICAgICAgIGNhc2UgJ2FzY2lpJzoKICAgICAgICAgICAgICAgIGNhc2UgJ2xhdGluMSc6CiAgICAgICAgICAgICAgICBjYXNlICdiaW5hcnknOgogICAgICAgICAgICAgICAgICByZXR1cm4gcgogICAgICAgICAgICAgICAgY2FzZSAndXRmOCc6CiAgICAgICAgICAgICAgICBjYXNlICd1dGYtOCc6CiAgICAgICAgICAgICAgICBjYXNlIHZvaWQgMDoKICAgICAgICAgICAgICAgICAgcmV0dXJuIGsodCkubGVuZ3RoCiAgICAgICAgICAgICAgICBjYXNlICd1Y3MyJzoKICAgICAgICAgICAgICAgIGNhc2UgJ3Vjcy0yJzoKICAgICAgICAgICAgICAgIGNhc2UgJ3V0ZjE2bGUnOgogICAgICAgICAgICAgICAgY2FzZSAndXRmLTE2bGUnOgogICAgICAgICAgICAgICAgICByZXR1cm4gMiAqIHIKICAgICAgICAgICAgICAgIGNhc2UgJ2hleCc6CiAgICAgICAgICAgICAgICAgIHJldHVybiByID4+PiAxCiAgICAgICAgICAgICAgICBjYXNlICdiYXNlNjQnOgogICAgICAgICAgICAgICAgICByZXR1cm4gaih0KS5sZW5ndGgKICAgICAgICAgICAgICAgIGRlZmF1bHQ6CiAgICAgICAgICAgICAgICAgIGlmIChuKSByZXR1cm4gayh0KS5sZW5ndGgKICAgICAgICAgICAgICAgICAgOyhlID0gKCcnICsgZSkudG9Mb3dlckNhc2UoKSksIChuID0gITApOwogICAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIGQodCwgZSwgcikgewogICAgICAgICAgICB2YXIgbiA9IHRbZV0KICAgICAgICAgICAgOyh0W2VdID0gdFtyXSksICh0W3JdID0gbik7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiB5KHQsIGUsIHIsIG4sIGkpIHsKICAgICAgICAgICAgaWYgKDAgPT09IHQubGVuZ3RoKSByZXR1cm4gLTEKICAgICAgICAgICAgaWYgKAogICAgICAgICAgICAgICgnc3RyaW5nJyA9PSB0eXBlb2YgcgogICAgICAgICAgICAgICAgPyAoKG4gPSByKSwgKHIgPSAwKSkKICAgICAgICAgICAgICAgIDogciA+IDIxNDc0ODM2NDcKICAgICAgICAgICAgICAgID8gKHIgPSAyMTQ3NDgzNjQ3KQogICAgICAgICAgICAgICAgOiByIDwgLTIxNDc0ODM2NDggJiYgKHIgPSAtMjE0NzQ4MzY0OCksCiAgICAgICAgICAgICAgKHIgPSArciksCiAgICAgICAgICAgICAgaXNOYU4ocikgJiYgKHIgPSBpID8gMCA6IHQubGVuZ3RoIC0gMSksCiAgICAgICAgICAgICAgciA8IDAgJiYgKHIgPSB0Lmxlbmd0aCArIHIpLAogICAgICAgICAgICAgIHIgPj0gdC5sZW5ndGgpCiAgICAgICAgICAgICkgewogICAgICAgICAgICAgIGlmIChpKSByZXR1cm4gLTEKICAgICAgICAgICAgICByID0gdC5sZW5ndGggLSAxOwogICAgICAgICAgICB9IGVsc2UgaWYgKHIgPCAwKSB7CiAgICAgICAgICAgICAgaWYgKCFpKSByZXR1cm4gLTEKICAgICAgICAgICAgICByID0gMDsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoKCdzdHJpbmcnID09IHR5cGVvZiBlICYmIChlID0gYS5mcm9tKGUsIG4pKSwgYS5pc0J1ZmZlcihlKSkpIHJldHVybiAwID09PSBlLmxlbmd0aCA/IC0xIDogdyh0LCBlLCByLCBuLCBpKQogICAgICAgICAgICBpZiAoJ251bWJlcicgPT0gdHlwZW9mIGUpCiAgICAgICAgICAgICAgcmV0dXJuICgKICAgICAgICAgICAgICAgIChlICY9IDI1NSksCiAgICAgICAgICAgICAgICBhLlRZUEVEX0FSUkFZX1NVUFBPUlQgJiYgJ2Z1bmN0aW9uJyA9PSB0eXBlb2YgVWludDhBcnJheS5wcm90b3R5cGUuaW5kZXhPZgogICAgICAgICAgICAgICAgICA/IGkKICAgICAgICAgICAgICAgICAgICA/IFVpbnQ4QXJyYXkucHJvdG90eXBlLmluZGV4T2YuY2FsbCh0LCBlLCByKQogICAgICAgICAgICAgICAgICAgIDogVWludDhBcnJheS5wcm90b3R5cGUubGFzdEluZGV4T2YuY2FsbCh0LCBlLCByKQogICAgICAgICAgICAgICAgICA6IHcodCwgW2VdLCByLCBuLCBpKQogICAgICAgICAgICAgICkKICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcigndmFsIG11c3QgYmUgc3RyaW5nLCBudW1iZXIgb3IgQnVmZmVyJykKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIHcodCwgZSwgciwgbiwgaSkgewogICAgICAgICAgICB2YXIgbywKICAgICAgICAgICAgICBzID0gMSwKICAgICAgICAgICAgICB1ID0gdC5sZW5ndGgsCiAgICAgICAgICAgICAgYSA9IGUubGVuZ3RoOwogICAgICAgICAgICBpZiAoCiAgICAgICAgICAgICAgdm9pZCAwICE9PSBuICYmCiAgICAgICAgICAgICAgKCd1Y3MyJyA9PT0gKG4gPSBTdHJpbmcobikudG9Mb3dlckNhc2UoKSkgfHwgJ3Vjcy0yJyA9PT0gbiB8fCAndXRmMTZsZScgPT09IG4gfHwgJ3V0Zi0xNmxlJyA9PT0gbikKICAgICAgICAgICAgKSB7CiAgICAgICAgICAgICAgaWYgKHQubGVuZ3RoIDwgMiB8fCBlLmxlbmd0aCA8IDIpIHJldHVybiAtMQogICAgICAgICAgICAgIDsocyA9IDIpLCAodSAvPSAyKSwgKGEgLz0gMiksIChyIC89IDIpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGZ1bmN0aW9uIGYodCwgZSkgewogICAgICAgICAgICAgIHJldHVybiAxID09PSBzID8gdFtlXSA6IHQucmVhZFVJbnQxNkJFKGUgKiBzKQogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIChpKSB7CiAgICAgICAgICAgICAgdmFyIGggPSAtMTsKICAgICAgICAgICAgICBmb3IgKG8gPSByOyBvIDwgdTsgbysrKQogICAgICAgICAgICAgICAgaWYgKGYodCwgbykgPT09IGYoZSwgLTEgPT09IGggPyAwIDogbyAtIGgpKSB7CiAgICAgICAgICAgICAgICAgIGlmICgoLTEgPT09IGggJiYgKGggPSBvKSwgbyAtIGggKyAxID09PSBhKSkgcmV0dXJuIGggKiBzCiAgICAgICAgICAgICAgICB9IGVsc2UgLTEgIT09IGggJiYgKG8gLT0gbyAtIGgpLCAoaCA9IC0xKTsKICAgICAgICAgICAgfSBlbHNlCiAgICAgICAgICAgICAgZm9yIChyICsgYSA+IHUgJiYgKHIgPSB1IC0gYSksIG8gPSByOyBvID49IDA7IG8tLSkgewogICAgICAgICAgICAgICAgZm9yICh2YXIgbCA9ICEwLCBjID0gMDsgYyA8IGE7IGMrKykKICAgICAgICAgICAgICAgICAgaWYgKGYodCwgbyArIGMpICE9PSBmKGUsIGMpKSB7CiAgICAgICAgICAgICAgICAgICAgbCA9ICExOwogICAgICAgICAgICAgICAgICAgIGJyZWFrCiAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGlmIChsKSByZXR1cm4gbwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIC0xCiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBFKHQsIGUsIHIsIG4pIHsKICAgICAgICAgICAgciA9IE51bWJlcihyKSB8fCAwOwogICAgICAgICAgICB2YXIgaSA9IHQubGVuZ3RoIC0gcjsKICAgICAgICAgICAgbiA/IChuID0gTnVtYmVyKG4pKSA+IGkgJiYgKG4gPSBpKSA6IChuID0gaSk7CiAgICAgICAgICAgIHZhciBvID0gZS5sZW5ndGg7CiAgICAgICAgICAgIGlmIChvICUgMiAhPSAwKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdJbnZhbGlkIGhleCBzdHJpbmcnKQogICAgICAgICAgICBuID4gbyAvIDIgJiYgKG4gPSBvIC8gMik7CiAgICAgICAgICAgIGZvciAodmFyIHMgPSAwOyBzIDwgbjsgKytzKSB7CiAgICAgICAgICAgICAgdmFyIHUgPSBwYXJzZUludChlLnN1YnN0cigyICogcywgMiksIDE2KTsKICAgICAgICAgICAgICBpZiAoaXNOYU4odSkpIHJldHVybiBzCiAgICAgICAgICAgICAgdFtyICsgc10gPSB1OwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBzCiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiB2KHQsIGUsIHIsIG4pIHsKICAgICAgICAgICAgcmV0dXJuIHooayhlLCB0Lmxlbmd0aCAtIHIpLCB0LCByLCBuKQogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gQSh0LCBlLCByLCBuKSB7CiAgICAgICAgICAgIHJldHVybiB6KAogICAgICAgICAgICAgIChmdW5jdGlvbiAodCkgewogICAgICAgICAgICAgICAgZm9yICh2YXIgZSA9IFtdLCByID0gMDsgciA8IHQubGVuZ3RoOyArK3IpIGUucHVzaCgyNTUgJiB0LmNoYXJDb2RlQXQocikpOwogICAgICAgICAgICAgICAgcmV0dXJuIGUKICAgICAgICAgICAgICB9KShlKSwKICAgICAgICAgICAgICB0LAogICAgICAgICAgICAgIHIsCiAgICAgICAgICAgICAgbgogICAgICAgICAgICApCiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBfKHQsIGUsIHIsIG4pIHsKICAgICAgICAgICAgcmV0dXJuIEEodCwgZSwgciwgbikKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIGIodCwgZSwgciwgbikgewogICAgICAgICAgICByZXR1cm4geihqKGUpLCB0LCByLCBuKQogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gbSh0LCBlLCByLCBuKSB7CiAgICAgICAgICAgIHJldHVybiB6KAogICAgICAgICAgICAgIChmdW5jdGlvbiAodCwgZSkgewogICAgICAgICAgICAgICAgZm9yICh2YXIgciwgbiwgaSwgbyA9IFtdLCBzID0gMDsgcyA8IHQubGVuZ3RoICYmICEoKGUgLT0gMikgPCAwKTsgKytzKQogICAgICAgICAgICAgICAgICAociA9IHQuY2hhckNvZGVBdChzKSksIChuID0gciA+PiA4KSwgKGkgPSByICUgMjU2KSwgby5wdXNoKGkpLCBvLnB1c2gobik7CiAgICAgICAgICAgICAgICByZXR1cm4gbwogICAgICAgICAgICAgIH0pKGUsIHQubGVuZ3RoIC0gciksCiAgICAgICAgICAgICAgdCwKICAgICAgICAgICAgICByLAogICAgICAgICAgICAgIG4KICAgICAgICAgICAgKQogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gUih0LCBlLCByKSB7CiAgICAgICAgICAgIHJldHVybiAwID09PSBlICYmIHIgPT09IHQubGVuZ3RoID8gbi5mcm9tQnl0ZUFycmF5KHQpIDogbi5mcm9tQnl0ZUFycmF5KHQuc2xpY2UoZSwgcikpCiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBTKHQsIGUsIHIpIHsKICAgICAgICAgICAgciA9IE1hdGgubWluKHQubGVuZ3RoLCByKTsKICAgICAgICAgICAgZm9yICh2YXIgbiA9IFtdLCBpID0gZTsgaSA8IHI7ICkgewogICAgICAgICAgICAgIHZhciBvLAogICAgICAgICAgICAgICAgcywKICAgICAgICAgICAgICAgIHUsCiAgICAgICAgICAgICAgICBhLAogICAgICAgICAgICAgICAgZiA9IHRbaV0sCiAgICAgICAgICAgICAgICBoID0gbnVsbCwKICAgICAgICAgICAgICAgIGwgPSBmID4gMjM5ID8gNCA6IGYgPiAyMjMgPyAzIDogZiA+IDE5MSA/IDIgOiAxOwogICAgICAgICAgICAgIGlmIChpICsgbCA8PSByKQogICAgICAgICAgICAgICAgc3dpdGNoIChsKSB7CiAgICAgICAgICAgICAgICAgIGNhc2UgMToKICAgICAgICAgICAgICAgICAgICBmIDwgMTI4ICYmIChoID0gZik7CiAgICAgICAgICAgICAgICAgICAgYnJlYWsKICAgICAgICAgICAgICAgICAgY2FzZSAyOgogICAgICAgICAgICAgICAgICAgIDEyOCA9PSAoMTkyICYgKG8gPSB0W2kgKyAxXSkpICYmIChhID0gKCgzMSAmIGYpIDw8IDYpIHwgKDYzICYgbykpID4gMTI3ICYmIChoID0gYSk7CiAgICAgICAgICAgICAgICAgICAgYnJlYWsKICAgICAgICAgICAgICAgICAgY2FzZSAzOgogIChvID0gdFtpICsgMV0pLAogICAgICAgICAgICAgICAgICAgICAgKHMgPSB0W2kgKyAyXSksCiAgICAgICAgICAgICAgICAgICAgICAxMjggPT0gKDE5MiAmIG8pICYmCiAgICAgICAgICAgICAgICAgICAgICAgIDEyOCA9PSAoMTkyICYgcykgJiYKICAgICAgICAgICAgICAgICAgICAgICAgKGEgPSAoKDE1ICYgZikgPDwgMTIpIHwgKCg2MyAmIG8pIDw8IDYpIHwgKDYzICYgcykpID4gMjA0NyAmJgogICAgICAgICAgICAgICAgICAgICAgICAoYSA8IDU1Mjk2IHx8IGEgPiA1NzM0MykgJiYKICAgICAgICAgICAgICAgICAgICAgICAgKGggPSBhKTsKICAgICAgICAgICAgICAgICAgICBicmVhawogICAgICAgICAgICAgICAgICBjYXNlIDQ6CiAgKG8gPSB0W2kgKyAxXSksCiAgICAgICAgICAgICAgICAgICAgICAocyA9IHRbaSArIDJdKSwKICAgICAgICAgICAgICAgICAgICAgICh1ID0gdFtpICsgM10pLAogICAgICAgICAgICAgICAgICAgICAgMTI4ID09ICgxOTIgJiBvKSAmJgogICAgICAgICAgICAgICAgICAgICAgICAxMjggPT0gKDE5MiAmIHMpICYmCiAgICAgICAgICAgICAgICAgICAgICAgIDEyOCA9PSAoMTkyICYgdSkgJiYKICAgICAgICAgICAgICAgICAgICAgICAgKGEgPSAoKDE1ICYgZikgPDwgMTgpIHwgKCg2MyAmIG8pIDw8IDEyKSB8ICgoNjMgJiBzKSA8PCA2KSB8ICg2MyAmIHUpKSA+IDY1NTM1ICYmCiAgICAgICAgICAgICAgICAgICAgICAgIGEgPCAxMTE0MTEyICYmCiAgICAgICAgICAgICAgICAgICAgICAgIChoID0gYSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgbnVsbCA9PT0gaAogICAgICAgICAgICAgICAgPyAoKGggPSA2NTUzMyksIChsID0gMSkpCiAgICAgICAgICAgICAgICA6IGggPiA2NTUzNSAmJiAoKGggLT0gNjU1MzYpLCBuLnB1c2goKChoID4+PiAxMCkgJiAxMDIzKSB8IDU1Mjk2KSwgKGggPSA1NjMyMCB8ICgxMDIzICYgaCkpKSwKICAgICAgICAgICAgICAgIG4ucHVzaChoKSwKICAgICAgICAgICAgICAgIChpICs9IGwpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiAoZnVuY3Rpb24gKHQpIHsKICAgICAgICAgICAgICB2YXIgZSA9IHQubGVuZ3RoOwogICAgICAgICAgICAgIGlmIChlIDw9IFQpIHJldHVybiBTdHJpbmcuZnJvbUNoYXJDb2RlLmFwcGx5KFN0cmluZywgdCkKICAgICAgICAgICAgICB2YXIgciA9ICcnLAogICAgICAgICAgICAgICAgbiA9IDA7CiAgICAgICAgICAgICAgZm9yICg7IG4gPCBlOyApIHIgKz0gU3RyaW5nLmZyb21DaGFyQ29kZS5hcHBseShTdHJpbmcsIHQuc2xpY2UobiwgKG4gKz0gVCkpKTsKICAgICAgICAgICAgICByZXR1cm4gcgogICAgICAgICAgICB9KShuKQogICAgICAgICAgfQogIChlLkJ1ZmZlciA9IGEpLAogICAgICAgICAgICAoZS5TbG93QnVmZmVyID0gZnVuY3Rpb24gKHQpIHsKICArdCAhPSB0ICYmICh0ID0gMCk7CiAgICAgICAgICAgICAgcmV0dXJuIGEuYWxsb2MoK3QpCiAgICAgICAgICAgIH0pLAogICAgICAgICAgICAoZS5JTlNQRUNUX01BWF9CWVRFUyA9IDUwKSwKICAgICAgICAgICAgKGEuVFlQRURfQVJSQVlfU1VQUE9SVCA9CiAgICAgICAgICAgICAgdm9pZCAwICE9PSB0LlRZUEVEX0FSUkFZX1NVUFBPUlQKICAgICAgICAgICAgICAgID8gdC5UWVBFRF9BUlJBWV9TVVBQT1JUCiAgICAgICAgICAgICAgICA6IChmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgICAgICAgICAgdHJ5IHsKICAgICAgICAgICAgICAgICAgICAgIHZhciB0ID0gbmV3IFVpbnQ4QXJyYXkoMSk7CiAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gKAogICAgICAgICAgICAgICAgICAgICAgICAodC5fX3Byb3RvX18gPSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgX19wcm90b19fOiBVaW50OEFycmF5LnByb3RvdHlwZSwKICAgICAgICAgICAgICAgICAgICAgICAgICBmb286IGZ1bmN0aW9uICgpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiA0MgogICAgICAgICAgICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICAgICAgICAgIH0pLAogICAgICAgICAgICAgICAgICAgICAgICA0MiA9PT0gdC5mb28oKSAmJiAnZnVuY3Rpb24nID09IHR5cGVvZiB0LnN1YmFycmF5ICYmIDAgPT09IHQuc3ViYXJyYXkoMSwgMSkuYnl0ZUxlbmd0aAogICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgIH0gY2F0Y2ggKHQpIHsKICAgICAgICAgICAgICAgICAgICAgIHJldHVybiAhMQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgfSkoKSksCiAgICAgICAgICAgIChlLmtNYXhMZW5ndGggPSBzKCkpLAogICAgICAgICAgICAoYS5wb29sU2l6ZSA9IDgxOTIpLAogICAgICAgICAgICAoYS5fYXVnbWVudCA9IGZ1bmN0aW9uICh0KSB7CiAgICAgICAgICAgICAgcmV0dXJuICh0Ll9fcHJvdG9fXyA9IGEucHJvdG90eXBlKSwgdAogICAgICAgICAgICB9KSwKICAgICAgICAgICAgKGEuZnJvbSA9IGZ1bmN0aW9uICh0LCBlLCByKSB7CiAgICAgICAgICAgICAgcmV0dXJuIGYobnVsbCwgdCwgZSwgcikKICAgICAgICAgICAgfSksCiAgICAgICAgICAgIGEuVFlQRURfQVJSQVlfU1VQUE9SVCAmJgogICAgICAgICAgICAgICgoYS5wcm90b3R5cGUuX19wcm90b19fID0gVWludDhBcnJheS5wcm90b3R5cGUpLAogICAgICAgICAgICAgIChhLl9fcHJvdG9fXyA9IFVpbnQ4QXJyYXkpLAogICAgICAgICAgICAgICd1bmRlZmluZWQnICE9IHR5cGVvZiBTeW1ib2wgJiYKICAgICAgICAgICAgICAgIFN5bWJvbC5zcGVjaWVzICYmCiAgICAgICAgICAgICAgICBhW1N5bWJvbC5zcGVjaWVzXSA9PT0gYSAmJgogICAgICAgICAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KGEsIFN5bWJvbC5zcGVjaWVzLCB7IHZhbHVlOiBudWxsLCBjb25maWd1cmFibGU6ICEwIH0pKSwKICAgICAgICAgICAgKGEuYWxsb2MgPSBmdW5jdGlvbiAodCwgZSwgcikgewogICAgICAgICAgICAgIHJldHVybiAoZnVuY3Rpb24gKHQsIGUsIHIsIG4pIHsKICAgICAgICAgICAgICAgIHJldHVybiAoCiAgICAgICAgICAgICAgICAgIGgoZSksCiAgICAgICAgICAgICAgICAgIGUgPD0gMAogICAgICAgICAgICAgICAgICAgID8gdSh0LCBlKQogICAgICAgICAgICAgICAgICAgIDogdm9pZCAwICE9PSByCiAgICAgICAgICAgICAgICAgICAgPyAnc3RyaW5nJyA9PSB0eXBlb2YgbgogICAgICAgICAgICAgICAgICAgICAgPyB1KHQsIGUpLmZpbGwociwgbikKICAgICAgICAgICAgICAgICAgICAgIDogdSh0LCBlKS5maWxsKHIpCiAgICAgICAgICAgICAgICAgICAgOiB1KHQsIGUpCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgfSkobnVsbCwgdCwgZSwgcikKICAgICAgICAgICAgfSksCiAgICAgICAgICAgIChhLmFsbG9jVW5zYWZlID0gZnVuY3Rpb24gKHQpIHsKICAgICAgICAgICAgICByZXR1cm4gbChudWxsLCB0KQogICAgICAgICAgICB9KSwKICAgICAgICAgICAgKGEuYWxsb2NVbnNhZmVTbG93ID0gZnVuY3Rpb24gKHQpIHsKICAgICAgICAgICAgICByZXR1cm4gbChudWxsLCB0KQogICAgICAgICAgICB9KSwKICAgICAgICAgICAgKGEuaXNCdWZmZXIgPSBmdW5jdGlvbiAodCkgewogICAgICAgICAgICAgIHJldHVybiAhKG51bGwgPT0gdCB8fCAhdC5faXNCdWZmZXIpCiAgICAgICAgICAgIH0pLAogICAgICAgICAgICAoYS5jb21wYXJlID0gZnVuY3Rpb24gKHQsIGUpIHsKICAgICAgICAgICAgICBpZiAoIWEuaXNCdWZmZXIodCkgfHwgIWEuaXNCdWZmZXIoZSkpIHRocm93IG5ldyBUeXBlRXJyb3IoJ0FyZ3VtZW50cyBtdXN0IGJlIEJ1ZmZlcnMnKQogICAgICAgICAgICAgIGlmICh0ID09PSBlKSByZXR1cm4gMAogICAgICAgICAgICAgIGZvciAodmFyIHIgPSB0Lmxlbmd0aCwgbiA9IGUubGVuZ3RoLCBpID0gMCwgbyA9IE1hdGgubWluKHIsIG4pOyBpIDwgbzsgKytpKQogICAgICAgICAgICAgICAgaWYgKHRbaV0gIT09IGVbaV0pIHsKICAociA9IHRbaV0pLCAobiA9IGVbaV0pOwogICAgICAgICAgICAgICAgICBicmVhawogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHJldHVybiByIDwgbiA/IC0xIDogbiA8IHIgPyAxIDogMAogICAgICAgICAgICB9KSwKICAgICAgICAgICAgKGEuaXNFbmNvZGluZyA9IGZ1bmN0aW9uICh0KSB7CiAgICAgICAgICAgICAgc3dpdGNoIChTdHJpbmcodCkudG9Mb3dlckNhc2UoKSkgewogICAgICAgICAgICAgICAgY2FzZSAnaGV4JzoKICAgICAgICAgICAgICAgIGNhc2UgJ3V0ZjgnOgogICAgICAgICAgICAgICAgY2FzZSAndXRmLTgnOgogICAgICAgICAgICAgICAgY2FzZSAnYXNjaWknOgogICAgICAgICAgICAgICAgY2FzZSAnbGF0aW4xJzoKICAgICAgICAgICAgICAgIGNhc2UgJ2JpbmFyeSc6CiAgICAgICAgICAgICAgICBjYXNlICdiYXNlNjQnOgogICAgICAgICAgICAgICAgY2FzZSAndWNzMic6CiAgICAgICAgICAgICAgICBjYXNlICd1Y3MtMic6CiAgICAgICAgICAgICAgICBjYXNlICd1dGYxNmxlJzoKICAgICAgICAgICAgICAgIGNhc2UgJ3V0Zi0xNmxlJzoKICAgICAgICAgICAgICAgICAgcmV0dXJuICEwCiAgICAgICAgICAgICAgICBkZWZhdWx0OgogICAgICAgICAgICAgICAgICByZXR1cm4gITEKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0pLAogICAgICAgICAgICAoYS5jb25jYXQgPSBmdW5jdGlvbiAodCwgZSkgewogICAgICAgICAgICAgIGlmICghbyh0KSkgdGhyb3cgbmV3IFR5cGVFcnJvcignImxpc3QiIGFyZ3VtZW50IG11c3QgYmUgYW4gQXJyYXkgb2YgQnVmZmVycycpCiAgICAgICAgICAgICAgaWYgKDAgPT09IHQubGVuZ3RoKSByZXR1cm4gYS5hbGxvYygwKQogICAgICAgICAgICAgIHZhciByOwogICAgICAgICAgICAgIGlmICh2b2lkIDAgPT09IGUpIGZvciAoZSA9IDAsIHIgPSAwOyByIDwgdC5sZW5ndGg7ICsrcikgZSArPSB0W3JdLmxlbmd0aDsKICAgICAgICAgICAgICB2YXIgbiA9IGEuYWxsb2NVbnNhZmUoZSksCiAgICAgICAgICAgICAgICBpID0gMDsKICAgICAgICAgICAgICBmb3IgKHIgPSAwOyByIDwgdC5sZW5ndGg7ICsrcikgewogICAgICAgICAgICAgICAgdmFyIHMgPSB0W3JdOwogICAgICAgICAgICAgICAgaWYgKCFhLmlzQnVmZmVyKHMpKSB0aHJvdyBuZXcgVHlwZUVycm9yKCcibGlzdCIgYXJndW1lbnQgbXVzdCBiZSBhbiBBcnJheSBvZiBCdWZmZXJzJykKICAgICAgICAgICAgICAgIHMuY29weShuLCBpKSwgKGkgKz0gcy5sZW5ndGgpOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICByZXR1cm4gbgogICAgICAgICAgICB9KSwKICAgICAgICAgICAgKGEuYnl0ZUxlbmd0aCA9IGcpLAogICAgICAgICAgICAoYS5wcm90b3R5cGUuX2lzQnVmZmVyID0gITApLAogICAgICAgICAgICAoYS5wcm90b3R5cGUuc3dhcDE2ID0gZnVuY3Rpb24gKCkgewogICAgICAgICAgICAgIHZhciB0ID0gdGhpcy5sZW5ndGg7CiAgICAgICAgICAgICAgaWYgKHQgJSAyICE9IDApIHRocm93IG5ldyBSYW5nZUVycm9yKCdCdWZmZXIgc2l6ZSBtdXN0IGJlIGEgbXVsdGlwbGUgb2YgMTYtYml0cycpCiAgICAgICAgICAgICAgZm9yICh2YXIgZSA9IDA7IGUgPCB0OyBlICs9IDIpIGQodGhpcywgZSwgZSArIDEpOwogICAgICAgICAgICAgIHJldHVybiB0aGlzCiAgICAgICAgICAgIH0pLAogICAgICAgICAgICAoYS5wcm90b3R5cGUuc3dhcDMyID0gZnVuY3Rpb24gKCkgewogICAgICAgICAgICAgIHZhciB0ID0gdGhpcy5sZW5ndGg7CiAgICAgICAgICAgICAgaWYgKHQgJSA0ICE9IDApIHRocm93IG5ldyBSYW5nZUVycm9yKCdCdWZmZXIgc2l6ZSBtdXN0IGJlIGEgbXVsdGlwbGUgb2YgMzItYml0cycpCiAgICAgICAgICAgICAgZm9yICh2YXIgZSA9IDA7IGUgPCB0OyBlICs9IDQpIGQodGhpcywgZSwgZSArIDMpLCBkKHRoaXMsIGUgKyAxLCBlICsgMik7CiAgICAgICAgICAgICAgcmV0dXJuIHRoaXMKICAgICAgICAgICAgfSksCiAgICAgICAgICAgIChhLnByb3RvdHlwZS5zd2FwNjQgPSBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgICAgdmFyIHQgPSB0aGlzLmxlbmd0aDsKICAgICAgICAgICAgICBpZiAodCAlIDggIT0gMCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ0J1ZmZlciBzaXplIG11c3QgYmUgYSBtdWx0aXBsZSBvZiA2NC1iaXRzJykKICAgICAgICAgICAgICBmb3IgKHZhciBlID0gMDsgZSA8IHQ7IGUgKz0gOCkKICAgICAgICAgICAgICAgIGQodGhpcywgZSwgZSArIDcpLCBkKHRoaXMsIGUgKyAxLCBlICsgNiksIGQodGhpcywgZSArIDIsIGUgKyA1KSwgZCh0aGlzLCBlICsgMywgZSArIDQpOwogICAgICAgICAgICAgIHJldHVybiB0aGlzCiAgICAgICAgICAgIH0pLAogICAgICAgICAgICAoYS5wcm90b3R5cGUudG9TdHJpbmcgPSBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgICAgdmFyIHQgPSAwIHwgdGhpcy5sZW5ndGg7CiAgICAgICAgICAgICAgcmV0dXJuIDAgPT09IHQKICAgICAgICAgICAgICAgID8gJycKICAgICAgICAgICAgICAgIDogMCA9PT0gYXJndW1lbnRzLmxlbmd0aAogICAgICAgICAgICAgICAgPyBTKHRoaXMsIDAsIHQpCiAgICAgICAgICAgICAgICA6IGZ1bmN0aW9uICh0LCBlLCByKSB7CiAgICAgICAgICAgICAgICAgICAgdmFyIG4gPSAhMTsKICAgICAgICAgICAgICAgICAgICBpZiAoKCh2b2lkIDAgPT09IGUgfHwgZSA8IDApICYmIChlID0gMCksIGUgPiB0aGlzLmxlbmd0aCkpIHJldHVybiAnJwogICAgICAgICAgICAgICAgICAgIGlmICgoKHZvaWQgMCA9PT0gciB8fCByID4gdGhpcy5sZW5ndGgpICYmIChyID0gdGhpcy5sZW5ndGgpLCByIDw9IDApKSByZXR1cm4gJycKICAgICAgICAgICAgICAgICAgICBpZiAoKHIgPj4+PSAwKSA8PSAoZSA+Pj49IDApKSByZXR1cm4gJycKICAgICAgICAgICAgICAgICAgICBmb3IgKHQgfHwgKHQgPSAndXRmOCcpOyA7ICkKICAgICAgICAgICAgICAgICAgICAgIHN3aXRjaCAodCkgewogICAgICAgICAgICAgICAgICAgICAgICBjYXNlICdoZXgnOgogICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBVKHRoaXMsIGUsIHIpCiAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgJ3V0ZjgnOgogICAgICAgICAgICAgICAgICAgICAgICBjYXNlICd1dGYtOCc6CiAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIFModGhpcywgZSwgcikKICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSAnYXNjaWknOgogICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBQKHRoaXMsIGUsIHIpCiAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgJ2xhdGluMSc6CiAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgJ2JpbmFyeSc6CiAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIEModGhpcywgZSwgcikKICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSAnYmFzZTY0JzoKICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gUih0aGlzLCBlLCByKQogICAgICAgICAgICAgICAgICAgICAgICBjYXNlICd1Y3MyJzoKICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSAndWNzLTInOgogICAgICAgICAgICAgICAgICAgICAgICBjYXNlICd1dGYxNmxlJzoKICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSAndXRmLTE2bGUnOgogICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBCKHRoaXMsIGUsIHIpCiAgICAgICAgICAgICAgICAgICAgICAgIGRlZmF1bHQ6CiAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG4pIHRocm93IG5ldyBUeXBlRXJyb3IoJ1Vua25vd24gZW5jb2Rpbmc6ICcgKyB0KQogICAgICAgICAgICAgICAgICAgICAgICAgIDsodCA9ICh0ICsgJycpLnRvTG93ZXJDYXNlKCkpLCAobiA9ICEwKTsKICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgfS5hcHBseSh0aGlzLCBhcmd1bWVudHMpCiAgICAgICAgICAgIH0pLAogICAgICAgICAgICAoYS5wcm90b3R5cGUuZXF1YWxzID0gZnVuY3Rpb24gKHQpIHsKICAgICAgICAgICAgICBpZiAoIWEuaXNCdWZmZXIodCkpIHRocm93IG5ldyBUeXBlRXJyb3IoJ0FyZ3VtZW50IG11c3QgYmUgYSBCdWZmZXInKQogICAgICAgICAgICAgIHJldHVybiB0aGlzID09PSB0IHx8IDAgPT09IGEuY29tcGFyZSh0aGlzLCB0KQogICAgICAgICAgICB9KSwKICAgICAgICAgICAgKGEucHJvdG90eXBlLmluc3BlY3QgPSBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgICAgdmFyIHQgPSAnJywKICAgICAgICAgICAgICAgIHIgPSBlLklOU1BFQ1RfTUFYX0JZVEVTOwogICAgICAgICAgICAgIHJldHVybiAoCiAgICAgICAgICAgICAgICB0aGlzLmxlbmd0aCA+IDAgJiYKICAgICAgICAgICAgICAgICAgKCh0ID0gdGhpcy50b1N0cmluZygnaGV4JywgMCwgcikubWF0Y2goLy57Mn0vZykuam9pbignICcpKSwgdGhpcy5sZW5ndGggPiByICYmICh0ICs9ICcgLi4uICcpKSwKICAgICAgICAgICAgICAgICc8QnVmZmVyICcgKyB0ICsgJz4nCiAgICAgICAgICAgICAgKQogICAgICAgICAgICB9KSwKICAgICAgICAgICAgKGEucHJvdG90eXBlLmNvbXBhcmUgPSBmdW5jdGlvbiAodCwgZSwgciwgbiwgaSkgewogICAgICAgICAgICAgIGlmICghYS5pc0J1ZmZlcih0KSkgdGhyb3cgbmV3IFR5cGVFcnJvcignQXJndW1lbnQgbXVzdCBiZSBhIEJ1ZmZlcicpCiAgICAgICAgICAgICAgaWYgKAogICAgICAgICAgICAgICAgKHZvaWQgMCA9PT0gZSAmJiAoZSA9IDApLAogICAgICAgICAgICAgICAgdm9pZCAwID09PSByICYmIChyID0gdCA/IHQubGVuZ3RoIDogMCksCiAgICAgICAgICAgICAgICB2b2lkIDAgPT09IG4gJiYgKG4gPSAwKSwKICAgICAgICAgICAgICAgIHZvaWQgMCA9PT0gaSAmJiAoaSA9IHRoaXMubGVuZ3RoKSwKICAgICAgICAgICAgICAgIGUgPCAwIHx8IHIgPiB0Lmxlbmd0aCB8fCBuIDwgMCB8fCBpID4gdGhpcy5sZW5ndGgpCiAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ291dCBvZiByYW5nZSBpbmRleCcpCiAgICAgICAgICAgICAgaWYgKG4gPj0gaSAmJiBlID49IHIpIHJldHVybiAwCiAgICAgICAgICAgICAgaWYgKG4gPj0gaSkgcmV0dXJuIC0xCiAgICAgICAgICAgICAgaWYgKGUgPj0gcikgcmV0dXJuIDEKICAgICAgICAgICAgICBpZiAoKChlID4+Pj0gMCksIChyID4+Pj0gMCksIChuID4+Pj0gMCksIChpID4+Pj0gMCksIHRoaXMgPT09IHQpKSByZXR1cm4gMAogICAgICAgICAgICAgIGZvciAoCiAgICAgICAgICAgICAgICB2YXIgbyA9IGkgLSBuLCBzID0gciAtIGUsIHUgPSBNYXRoLm1pbihvLCBzKSwgZiA9IHRoaXMuc2xpY2UobiwgaSksIGggPSB0LnNsaWNlKGUsIHIpLCBsID0gMDsKICAgICAgICAgICAgICAgIGwgPCB1OwogICAgICAgICAgICAgICAgKytsCiAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgaWYgKGZbbF0gIT09IGhbbF0pIHsKICAobyA9IGZbbF0pLCAocyA9IGhbbF0pOwogICAgICAgICAgICAgICAgICBicmVhawogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHJldHVybiBvIDwgcyA/IC0xIDogcyA8IG8gPyAxIDogMAogICAgICAgICAgICB9KSwKICAgICAgICAgICAgKGEucHJvdG90eXBlLmluY2x1ZGVzID0gZnVuY3Rpb24gKHQsIGUsIHIpIHsKICAgICAgICAgICAgICByZXR1cm4gLTEgIT09IHRoaXMuaW5kZXhPZih0LCBlLCByKQogICAgICAgICAgICB9KSwKICAgICAgICAgICAgKGEucHJvdG90eXBlLmluZGV4T2YgPSBmdW5jdGlvbiAodCwgZSwgcikgewogICAgICAgICAgICAgIHJldHVybiB5KHRoaXMsIHQsIGUsIHIsICEwKQogICAgICAgICAgICB9KSwKICAgICAgICAgICAgKGEucHJvdG90eXBlLmxhc3RJbmRleE9mID0gZnVuY3Rpb24gKHQsIGUsIHIpIHsKICAgICAgICAgICAgICByZXR1cm4geSh0aGlzLCB0LCBlLCByLCAhMSkKICAgICAgICAgICAgfSksCiAgICAgICAgICAgIChhLnByb3RvdHlwZS53cml0ZSA9IGZ1bmN0aW9uICh0LCBlLCByLCBuKSB7CiAgICAgICAgICAgICAgaWYgKHZvaWQgMCA9PT0gZSkgKG4gPSAndXRmOCcpLCAociA9IHRoaXMubGVuZ3RoKSwgKGUgPSAwKTsKICAgICAgICAgICAgICBlbHNlIGlmICh2b2lkIDAgPT09IHIgJiYgJ3N0cmluZycgPT0gdHlwZW9mIGUpIChuID0gZSksIChyID0gdGhpcy5sZW5ndGgpLCAoZSA9IDApOwogICAgICAgICAgICAgIGVsc2UgewogICAgICAgICAgICAgICAgaWYgKCFpc0Zpbml0ZShlKSkKICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdCdWZmZXIud3JpdGUoc3RyaW5nLCBlbmNvZGluZywgb2Zmc2V0WywgbGVuZ3RoXSkgaXMgbm8gbG9uZ2VyIHN1cHBvcnRlZCcpCiAgICAgICAgICAgICAgICA7KGUgfD0gMCksIGlzRmluaXRlKHIpID8gKChyIHw9IDApLCB2b2lkIDAgPT09IG4gJiYgKG4gPSAndXRmOCcpKSA6ICgobiA9IHIpLCAociA9IHZvaWQgMCkpOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB2YXIgaSA9IHRoaXMubGVuZ3RoIC0gZTsKICAgICAgICAgICAgICBpZiAoKCh2b2lkIDAgPT09IHIgfHwgciA+IGkpICYmIChyID0gaSksICh0Lmxlbmd0aCA+IDAgJiYgKHIgPCAwIHx8IGUgPCAwKSkgfHwgZSA+IHRoaXMubGVuZ3RoKSkKICAgICAgICAgICAgICAgIHRocm93IG5ldyBSYW5nZUVycm9yKCdBdHRlbXB0IHRvIHdyaXRlIG91dHNpZGUgYnVmZmVyIGJvdW5kcycpCiAgICAgICAgICAgICAgbiB8fCAobiA9ICd1dGY4Jyk7CiAgICAgICAgICAgICAgZm9yICh2YXIgbyA9ICExOyA7ICkKICAgICAgICAgICAgICAgIHN3aXRjaCAobikgewogICAgICAgICAgICAgICAgICBjYXNlICdoZXgnOgogICAgICAgICAgICAgICAgICAgIHJldHVybiBFKHRoaXMsIHQsIGUsIHIpCiAgICAgICAgICAgICAgICAgIGNhc2UgJ3V0ZjgnOgogICAgICAgICAgICAgICAgICBjYXNlICd1dGYtOCc6CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHYodGhpcywgdCwgZSwgcikKICAgICAgICAgICAgICAgICAgY2FzZSAnYXNjaWknOgogICAgICAgICAgICAgICAgICAgIHJldHVybiBBKHRoaXMsIHQsIGUsIHIpCiAgICAgICAgICAgICAgICAgIGNhc2UgJ2xhdGluMSc6CiAgICAgICAgICAgICAgICAgIGNhc2UgJ2JpbmFyeSc6CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIF8odGhpcywgdCwgZSwgcikKICAgICAgICAgICAgICAgICAgY2FzZSAnYmFzZTY0JzoKICAgICAgICAgICAgICAgICAgICByZXR1cm4gYih0aGlzLCB0LCBlLCByKQogICAgICAgICAgICAgICAgICBjYXNlICd1Y3MyJzoKICAgICAgICAgICAgICAgICAgY2FzZSAndWNzLTInOgogICAgICAgICAgICAgICAgICBjYXNlICd1dGYxNmxlJzoKICAgICAgICAgICAgICAgICAgY2FzZSAndXRmLTE2bGUnOgogICAgICAgICAgICAgICAgICAgIHJldHVybiBtKHRoaXMsIHQsIGUsIHIpCiAgICAgICAgICAgICAgICAgIGRlZmF1bHQ6CiAgICAgICAgICAgICAgICAgICAgaWYgKG8pIHRocm93IG5ldyBUeXBlRXJyb3IoJ1Vua25vd24gZW5jb2Rpbmc6ICcgKyBuKQogICAgICAgICAgICAgICAgICAgIDsobiA9ICgnJyArIG4pLnRvTG93ZXJDYXNlKCkpLCAobyA9ICEwKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSksCiAgICAgICAgICAgIChhLnByb3RvdHlwZS50b0pTT04gPSBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgICAgcmV0dXJuIHsgdHlwZTogJ0J1ZmZlcicsIGRhdGE6IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKHRoaXMuX2FyciB8fCB0aGlzLCAwKSB9CiAgICAgICAgICAgIH0pOwogICAgICAgICAgdmFyIFQgPSA0MDk2OwogICAgICAgICAgZnVuY3Rpb24gUCh0LCBlLCByKSB7CiAgICAgICAgICAgIHZhciBuID0gJyc7CiAgICAgICAgICAgIHIgPSBNYXRoLm1pbih0Lmxlbmd0aCwgcik7CiAgICAgICAgICAgIGZvciAodmFyIGkgPSBlOyBpIDwgcjsgKytpKSBuICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoMTI3ICYgdFtpXSk7CiAgICAgICAgICAgIHJldHVybiBuCiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBDKHQsIGUsIHIpIHsKICAgICAgICAgICAgdmFyIG4gPSAnJzsKICAgICAgICAgICAgciA9IE1hdGgubWluKHQubGVuZ3RoLCByKTsKICAgICAgICAgICAgZm9yICh2YXIgaSA9IGU7IGkgPCByOyArK2kpIG4gKz0gU3RyaW5nLmZyb21DaGFyQ29kZSh0W2ldKTsKICAgICAgICAgICAgcmV0dXJuIG4KICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIFUodCwgZSwgcikgewogICAgICAgICAgICB2YXIgbiA9IHQubGVuZ3RoCiAgICAgICAgICAgIDsoIWUgfHwgZSA8IDApICYmIChlID0gMCksICghciB8fCByIDwgMCB8fCByID4gbikgJiYgKHIgPSBuKTsKICAgICAgICAgICAgZm9yICh2YXIgaSA9ICcnLCBvID0gZTsgbyA8IHI7ICsrbykgaSArPSBOKHRbb10pOwogICAgICAgICAgICByZXR1cm4gaQogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gQih0LCBlLCByKSB7CiAgICAgICAgICAgIGZvciAodmFyIG4gPSB0LnNsaWNlKGUsIHIpLCBpID0gJycsIG8gPSAwOyBvIDwgbi5sZW5ndGg7IG8gKz0gMikKICAgICAgICAgICAgICBpICs9IFN0cmluZy5mcm9tQ2hhckNvZGUobltvXSArIDI1NiAqIG5bbyArIDFdKTsKICAgICAgICAgICAgcmV0dXJuIGkKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIEYodCwgZSwgcikgewogICAgICAgICAgICBpZiAodCAlIDEgIT0gMCB8fCB0IDwgMCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ29mZnNldCBpcyBub3QgdWludCcpCiAgICAgICAgICAgIGlmICh0ICsgZSA+IHIpIHRocm93IG5ldyBSYW5nZUVycm9yKCdUcnlpbmcgdG8gYWNjZXNzIGJleW9uZCBidWZmZXIgbGVuZ3RoJykKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIE0odCwgZSwgciwgbiwgaSwgbykgewogICAgICAgICAgICBpZiAoIWEuaXNCdWZmZXIodCkpIHRocm93IG5ldyBUeXBlRXJyb3IoJyJidWZmZXIiIGFyZ3VtZW50IG11c3QgYmUgYSBCdWZmZXIgaW5zdGFuY2UnKQogICAgICAgICAgICBpZiAoZSA+IGkgfHwgZSA8IG8pIHRocm93IG5ldyBSYW5nZUVycm9yKCcidmFsdWUiIGFyZ3VtZW50IGlzIG91dCBvZiBib3VuZHMnKQogICAgICAgICAgICBpZiAociArIG4gPiB0Lmxlbmd0aCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ0luZGV4IG91dCBvZiByYW5nZScpCiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiB4KHQsIGUsIHIsIG4pIHsKICAgICAgICAgICAgZSA8IDAgJiYgKGUgPSA2NTUzNSArIGUgKyAxKTsKICAgICAgICAgICAgZm9yICh2YXIgaSA9IDAsIG8gPSBNYXRoLm1pbih0Lmxlbmd0aCAtIHIsIDIpOyBpIDwgbzsgKytpKQogICAgICAgICAgICAgIHRbciArIGldID0gKGUgJiAoMjU1IDw8ICg4ICogKG4gPyBpIDogMSAtIGkpKSkpID4+PiAoOCAqIChuID8gaSA6IDEgLSBpKSk7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBJKHQsIGUsIHIsIG4pIHsKICAgICAgICAgICAgZSA8IDAgJiYgKGUgPSA0Mjk0OTY3Mjk1ICsgZSArIDEpOwogICAgICAgICAgICBmb3IgKHZhciBpID0gMCwgbyA9IE1hdGgubWluKHQubGVuZ3RoIC0gciwgNCk7IGkgPCBvOyArK2kpIHRbciArIGldID0gKGUgPj4+ICg4ICogKG4gPyBpIDogMyAtIGkpKSkgJiAyNTU7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBPKHQsIGUsIHIsIG4sIGksIG8pIHsKICAgICAgICAgICAgaWYgKHIgKyBuID4gdC5sZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdJbmRleCBvdXQgb2YgcmFuZ2UnKQogICAgICAgICAgICBpZiAociA8IDApIHRocm93IG5ldyBSYW5nZUVycm9yKCdJbmRleCBvdXQgb2YgcmFuZ2UnKQogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gWSh0LCBlLCByLCBuLCBvKSB7CiAgICAgICAgICAgIHJldHVybiBvIHx8IE8odCwgMCwgciwgNCksIGkud3JpdGUodCwgZSwgciwgbiwgMjMsIDQpLCByICsgNAogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gTCh0LCBlLCByLCBuLCBvKSB7CiAgICAgICAgICAgIHJldHVybiBvIHx8IE8odCwgMCwgciwgOCksIGkud3JpdGUodCwgZSwgciwgbiwgNTIsIDgpLCByICsgOAogICAgICAgICAgfQogIChhLnByb3RvdHlwZS5zbGljZSA9IGZ1bmN0aW9uICh0LCBlKSB7CiAgICAgICAgICAgIHZhciByLAogICAgICAgICAgICAgIG4gPSB0aGlzLmxlbmd0aDsKICAgICAgICAgICAgaWYgKAogICAgICAgICAgICAgICgodCA9IH5+dCksCiAgICAgICAgICAgICAgKGUgPSB2b2lkIDAgPT09IGUgPyBuIDogfn5lKSwKICAgICAgICAgICAgICB0IDwgMCA/ICh0ICs9IG4pIDwgMCAmJiAodCA9IDApIDogdCA+IG4gJiYgKHQgPSBuKSwKICAgICAgICAgICAgICBlIDwgMCA/IChlICs9IG4pIDwgMCAmJiAoZSA9IDApIDogZSA+IG4gJiYgKGUgPSBuKSwKICAgICAgICAgICAgICBlIDwgdCAmJiAoZSA9IHQpLAogICAgICAgICAgICAgIGEuVFlQRURfQVJSQVlfU1VQUE9SVCkKICAgICAgICAgICAgKQogICAgICAgICAgICAgIChyID0gdGhpcy5zdWJhcnJheSh0LCBlKSkuX19wcm90b19fID0gYS5wcm90b3R5cGU7CiAgICAgICAgICAgIGVsc2UgewogICAgICAgICAgICAgIHZhciBpID0gZSAtIHQ7CiAgICAgICAgICAgICAgciA9IG5ldyBhKGksIHZvaWQgMCk7CiAgICAgICAgICAgICAgZm9yICh2YXIgbyA9IDA7IG8gPCBpOyArK28pIHJbb10gPSB0aGlzW28gKyB0XTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gcgogICAgICAgICAgfSksCiAgICAgICAgICAgIChhLnByb3RvdHlwZS5yZWFkVUludExFID0gZnVuY3Rpb24gKHQsIGUsIHIpIHsKICAodCB8PSAwKSwgKGUgfD0gMCksIHIgfHwgRih0LCBlLCB0aGlzLmxlbmd0aCk7CiAgICAgICAgICAgICAgZm9yICh2YXIgbiA9IHRoaXNbdF0sIGkgPSAxLCBvID0gMDsgKytvIDwgZSAmJiAoaSAqPSAyNTYpOyApIG4gKz0gdGhpc1t0ICsgb10gKiBpOwogICAgICAgICAgICAgIHJldHVybiBuCiAgICAgICAgICAgIH0pLAogICAgICAgICAgICAoYS5wcm90b3R5cGUucmVhZFVJbnRCRSA9IGZ1bmN0aW9uICh0LCBlLCByKSB7CiAgKHQgfD0gMCksIChlIHw9IDApLCByIHx8IEYodCwgZSwgdGhpcy5sZW5ndGgpOwogICAgICAgICAgICAgIGZvciAodmFyIG4gPSB0aGlzW3QgKyAtLWVdLCBpID0gMTsgZSA+IDAgJiYgKGkgKj0gMjU2KTsgKSBuICs9IHRoaXNbdCArIC0tZV0gKiBpOwogICAgICAgICAgICAgIHJldHVybiBuCiAgICAgICAgICAgIH0pLAogICAgICAgICAgICAoYS5wcm90b3R5cGUucmVhZFVJbnQ4ID0gZnVuY3Rpb24gKHQsIGUpIHsKICAgICAgICAgICAgICByZXR1cm4gZSB8fCBGKHQsIDEsIHRoaXMubGVuZ3RoKSwgdGhpc1t0XQogICAgICAgICAgICB9KSwKICAgICAgICAgICAgKGEucHJvdG90eXBlLnJlYWRVSW50MTZMRSA9IGZ1bmN0aW9uICh0LCBlKSB7CiAgICAgICAgICAgICAgcmV0dXJuIGUgfHwgRih0LCAyLCB0aGlzLmxlbmd0aCksIHRoaXNbdF0gfCAodGhpc1t0ICsgMV0gPDwgOCkKICAgICAgICAgICAgfSksCiAgICAgICAgICAgIChhLnByb3RvdHlwZS5yZWFkVUludDE2QkUgPSBmdW5jdGlvbiAodCwgZSkgewogICAgICAgICAgICAgIHJldHVybiBlIHx8IEYodCwgMiwgdGhpcy5sZW5ndGgpLCAodGhpc1t0XSA8PCA4KSB8IHRoaXNbdCArIDFdCiAgICAgICAgICAgIH0pLAogICAgICAgICAgICAoYS5wcm90b3R5cGUucmVhZFVJbnQzMkxFID0gZnVuY3Rpb24gKHQsIGUpIHsKICAgICAgICAgICAgICByZXR1cm4gKAogICAgICAgICAgICAgICAgZSB8fCBGKHQsIDQsIHRoaXMubGVuZ3RoKSwgKHRoaXNbdF0gfCAodGhpc1t0ICsgMV0gPDwgOCkgfCAodGhpc1t0ICsgMl0gPDwgMTYpKSArIDE2Nzc3MjE2ICogdGhpc1t0ICsgM10KICAgICAgICAgICAgICApCiAgICAgICAgICAgIH0pLAogICAgICAgICAgICAoYS5wcm90b3R5cGUucmVhZFVJbnQzMkJFID0gZnVuY3Rpb24gKHQsIGUpIHsKICAgICAgICAgICAgICByZXR1cm4gKAogICAgICAgICAgICAgICAgZSB8fCBGKHQsIDQsIHRoaXMubGVuZ3RoKSwgMTY3NzcyMTYgKiB0aGlzW3RdICsgKCh0aGlzW3QgKyAxXSA8PCAxNikgfCAodGhpc1t0ICsgMl0gPDwgOCkgfCB0aGlzW3QgKyAzXSkKICAgICAgICAgICAgICApCiAgICAgICAgICAgIH0pLAogICAgICAgICAgICAoYS5wcm90b3R5cGUucmVhZEludExFID0gZnVuY3Rpb24gKHQsIGUsIHIpIHsKICAodCB8PSAwKSwgKGUgfD0gMCksIHIgfHwgRih0LCBlLCB0aGlzLmxlbmd0aCk7CiAgICAgICAgICAgICAgZm9yICh2YXIgbiA9IHRoaXNbdF0sIGkgPSAxLCBvID0gMDsgKytvIDwgZSAmJiAoaSAqPSAyNTYpOyApIG4gKz0gdGhpc1t0ICsgb10gKiBpOwogICAgICAgICAgICAgIHJldHVybiBuID49IChpICo9IDEyOCkgJiYgKG4gLT0gTWF0aC5wb3coMiwgOCAqIGUpKSwgbgogICAgICAgICAgICB9KSwKICAgICAgICAgICAgKGEucHJvdG90eXBlLnJlYWRJbnRCRSA9IGZ1bmN0aW9uICh0LCBlLCByKSB7CiAgKHQgfD0gMCksIChlIHw9IDApLCByIHx8IEYodCwgZSwgdGhpcy5sZW5ndGgpOwogICAgICAgICAgICAgIGZvciAodmFyIG4gPSBlLCBpID0gMSwgbyA9IHRoaXNbdCArIC0tbl07IG4gPiAwICYmIChpICo9IDI1Nik7ICkgbyArPSB0aGlzW3QgKyAtLW5dICogaTsKICAgICAgICAgICAgICByZXR1cm4gbyA+PSAoaSAqPSAxMjgpICYmIChvIC09IE1hdGgucG93KDIsIDggKiBlKSksIG8KICAgICAgICAgICAgfSksCiAgICAgICAgICAgIChhLnByb3RvdHlwZS5yZWFkSW50OCA9IGZ1bmN0aW9uICh0LCBlKSB7CiAgICAgICAgICAgICAgcmV0dXJuIGUgfHwgRih0LCAxLCB0aGlzLmxlbmd0aCksIDEyOCAmIHRoaXNbdF0gPyAtMSAqICgyNTUgLSB0aGlzW3RdICsgMSkgOiB0aGlzW3RdCiAgICAgICAgICAgIH0pLAogICAgICAgICAgICAoYS5wcm90b3R5cGUucmVhZEludDE2TEUgPSBmdW5jdGlvbiAodCwgZSkgewogICAgICAgICAgICAgIGUgfHwgRih0LCAyLCB0aGlzLmxlbmd0aCk7CiAgICAgICAgICAgICAgdmFyIHIgPSB0aGlzW3RdIHwgKHRoaXNbdCArIDFdIDw8IDgpOwogICAgICAgICAgICAgIHJldHVybiAzMjc2OCAmIHIgPyA0Mjk0OTAxNzYwIHwgciA6IHIKICAgICAgICAgICAgfSksCiAgICAgICAgICAgIChhLnByb3RvdHlwZS5yZWFkSW50MTZCRSA9IGZ1bmN0aW9uICh0LCBlKSB7CiAgICAgICAgICAgICAgZSB8fCBGKHQsIDIsIHRoaXMubGVuZ3RoKTsKICAgICAgICAgICAgICB2YXIgciA9IHRoaXNbdCArIDFdIHwgKHRoaXNbdF0gPDwgOCk7CiAgICAgICAgICAgICAgcmV0dXJuIDMyNzY4ICYgciA/IDQyOTQ5MDE3NjAgfCByIDogcgogICAgICAgICAgICB9KSwKICAgICAgICAgICAgKGEucHJvdG90eXBlLnJlYWRJbnQzMkxFID0gZnVuY3Rpb24gKHQsIGUpIHsKICAgICAgICAgICAgICByZXR1cm4gZSB8fCBGKHQsIDQsIHRoaXMubGVuZ3RoKSwgdGhpc1t0XSB8ICh0aGlzW3QgKyAxXSA8PCA4KSB8ICh0aGlzW3QgKyAyXSA8PCAxNikgfCAodGhpc1t0ICsgM10gPDwgMjQpCiAgICAgICAgICAgIH0pLAogICAgICAgICAgICAoYS5wcm90b3R5cGUucmVhZEludDMyQkUgPSBmdW5jdGlvbiAodCwgZSkgewogICAgICAgICAgICAgIHJldHVybiBlIHx8IEYodCwgNCwgdGhpcy5sZW5ndGgpLCAodGhpc1t0XSA8PCAyNCkgfCAodGhpc1t0ICsgMV0gPDwgMTYpIHwgKHRoaXNbdCArIDJdIDw8IDgpIHwgdGhpc1t0ICsgM10KICAgICAgICAgICAgfSksCiAgICAgICAgICAgIChhLnByb3RvdHlwZS5yZWFkRmxvYXRMRSA9IGZ1bmN0aW9uICh0LCBlKSB7CiAgICAgICAgICAgICAgcmV0dXJuIGUgfHwgRih0LCA0LCB0aGlzLmxlbmd0aCksIGkucmVhZCh0aGlzLCB0LCAhMCwgMjMsIDQpCiAgICAgICAgICAgIH0pLAogICAgICAgICAgICAoYS5wcm90b3R5cGUucmVhZEZsb2F0QkUgPSBmdW5jdGlvbiAodCwgZSkgewogICAgICAgICAgICAgIHJldHVybiBlIHx8IEYodCwgNCwgdGhpcy5sZW5ndGgpLCBpLnJlYWQodGhpcywgdCwgITEsIDIzLCA0KQogICAgICAgICAgICB9KSwKICAgICAgICAgICAgKGEucHJvdG90eXBlLnJlYWREb3VibGVMRSA9IGZ1bmN0aW9uICh0LCBlKSB7CiAgICAgICAgICAgICAgcmV0dXJuIGUgfHwgRih0LCA4LCB0aGlzLmxlbmd0aCksIGkucmVhZCh0aGlzLCB0LCAhMCwgNTIsIDgpCiAgICAgICAgICAgIH0pLAogICAgICAgICAgICAoYS5wcm90b3R5cGUucmVhZERvdWJsZUJFID0gZnVuY3Rpb24gKHQsIGUpIHsKICAgICAgICAgICAgICByZXR1cm4gZSB8fCBGKHQsIDgsIHRoaXMubGVuZ3RoKSwgaS5yZWFkKHRoaXMsIHQsICExLCA1MiwgOCkKICAgICAgICAgICAgfSksCiAgICAgICAgICAgIChhLnByb3RvdHlwZS53cml0ZVVJbnRMRSA9IGZ1bmN0aW9uICh0LCBlLCByLCBuKSB7CiAgKCh0ID0gK3QpLCAoZSB8PSAwKSwgKHIgfD0gMCksIG4pIHx8IE0odGhpcywgdCwgZSwgciwgTWF0aC5wb3coMiwgOCAqIHIpIC0gMSwgMCk7CiAgICAgICAgICAgICAgdmFyIGkgPSAxLAogICAgICAgICAgICAgICAgbyA9IDA7CiAgICAgICAgICAgICAgZm9yICh0aGlzW2VdID0gMjU1ICYgdDsgKytvIDwgciAmJiAoaSAqPSAyNTYpOyApIHRoaXNbZSArIG9dID0gKHQgLyBpKSAmIDI1NTsKICAgICAgICAgICAgICByZXR1cm4gZSArIHIKICAgICAgICAgICAgfSksCiAgICAgICAgICAgIChhLnByb3RvdHlwZS53cml0ZVVJbnRCRSA9IGZ1bmN0aW9uICh0LCBlLCByLCBuKSB7CiAgKCh0ID0gK3QpLCAoZSB8PSAwKSwgKHIgfD0gMCksIG4pIHx8IE0odGhpcywgdCwgZSwgciwgTWF0aC5wb3coMiwgOCAqIHIpIC0gMSwgMCk7CiAgICAgICAgICAgICAgdmFyIGkgPSByIC0gMSwKICAgICAgICAgICAgICAgIG8gPSAxOwogICAgICAgICAgICAgIGZvciAodGhpc1tlICsgaV0gPSAyNTUgJiB0OyAtLWkgPj0gMCAmJiAobyAqPSAyNTYpOyApIHRoaXNbZSArIGldID0gKHQgLyBvKSAmIDI1NTsKICAgICAgICAgICAgICByZXR1cm4gZSArIHIKICAgICAgICAgICAgfSksCiAgICAgICAgICAgIChhLnByb3RvdHlwZS53cml0ZVVJbnQ4ID0gZnVuY3Rpb24gKHQsIGUsIHIpIHsKICAgICAgICAgICAgICByZXR1cm4gKAogICAgICAgICAgICAgICAgKHQgPSArdCksCiAgICAgICAgICAgICAgICAoZSB8PSAwKSwKICAgICAgICAgICAgICAgIHIgfHwgTSh0aGlzLCB0LCBlLCAxLCAyNTUsIDApLAogICAgICAgICAgICAgICAgYS5UWVBFRF9BUlJBWV9TVVBQT1JUIHx8ICh0ID0gTWF0aC5mbG9vcih0KSksCiAgICAgICAgICAgICAgICAodGhpc1tlXSA9IDI1NSAmIHQpLAogICAgICAgICAgICAgICAgZSArIDEKICAgICAgICAgICAgICApCiAgICAgICAgICAgIH0pLAogICAgICAgICAgICAoYS5wcm90b3R5cGUud3JpdGVVSW50MTZMRSA9IGZ1bmN0aW9uICh0LCBlLCByKSB7CiAgICAgICAgICAgICAgcmV0dXJuICgKICAgICAgICAgICAgICAgICh0ID0gK3QpLAogICAgICAgICAgICAgICAgKGUgfD0gMCksCiAgICAgICAgICAgICAgICByIHx8IE0odGhpcywgdCwgZSwgMiwgNjU1MzUsIDApLAogICAgICAgICAgICAgICAgYS5UWVBFRF9BUlJBWV9TVVBQT1JUID8gKCh0aGlzW2VdID0gMjU1ICYgdCksICh0aGlzW2UgKyAxXSA9IHQgPj4+IDgpKSA6IHgodGhpcywgdCwgZSwgITApLAogICAgICAgICAgICAgICAgZSArIDIKICAgICAgICAgICAgICApCiAgICAgICAgICAgIH0pLAogICAgICAgICAgICAoYS5wcm90b3R5cGUud3JpdGVVSW50MTZCRSA9IGZ1bmN0aW9uICh0LCBlLCByKSB7CiAgICAgICAgICAgICAgcmV0dXJuICgKICAgICAgICAgICAgICAgICh0ID0gK3QpLAogICAgICAgICAgICAgICAgKGUgfD0gMCksCiAgICAgICAgICAgICAgICByIHx8IE0odGhpcywgdCwgZSwgMiwgNjU1MzUsIDApLAogICAgICAgICAgICAgICAgYS5UWVBFRF9BUlJBWV9TVVBQT1JUID8gKCh0aGlzW2VdID0gdCA+Pj4gOCksICh0aGlzW2UgKyAxXSA9IDI1NSAmIHQpKSA6IHgodGhpcywgdCwgZSwgITEpLAogICAgICAgICAgICAgICAgZSArIDIKICAgICAgICAgICAgICApCiAgICAgICAgICAgIH0pLAogICAgICAgICAgICAoYS5wcm90b3R5cGUud3JpdGVVSW50MzJMRSA9IGZ1bmN0aW9uICh0LCBlLCByKSB7CiAgICAgICAgICAgICAgcmV0dXJuICgKICAgICAgICAgICAgICAgICh0ID0gK3QpLAogICAgICAgICAgICAgICAgKGUgfD0gMCksCiAgICAgICAgICAgICAgICByIHx8IE0odGhpcywgdCwgZSwgNCwgNDI5NDk2NzI5NSwgMCksCiAgICAgICAgICAgICAgICBhLlRZUEVEX0FSUkFZX1NVUFBPUlQKICAgICAgICAgICAgICAgICAgPyAoKHRoaXNbZSArIDNdID0gdCA+Pj4gMjQpLCAodGhpc1tlICsgMl0gPSB0ID4+PiAxNiksICh0aGlzW2UgKyAxXSA9IHQgPj4+IDgpLCAodGhpc1tlXSA9IDI1NSAmIHQpKQogICAgICAgICAgICAgICAgICA6IEkodGhpcywgdCwgZSwgITApLAogICAgICAgICAgICAgICAgZSArIDQKICAgICAgICAgICAgICApCiAgICAgICAgICAgIH0pLAogICAgICAgICAgICAoYS5wcm90b3R5cGUud3JpdGVVSW50MzJCRSA9IGZ1bmN0aW9uICh0LCBlLCByKSB7CiAgICAgICAgICAgICAgcmV0dXJuICgKICAgICAgICAgICAgICAgICh0ID0gK3QpLAogICAgICAgICAgICAgICAgKGUgfD0gMCksCiAgICAgICAgICAgICAgICByIHx8IE0odGhpcywgdCwgZSwgNCwgNDI5NDk2NzI5NSwgMCksCiAgICAgICAgICAgICAgICBhLlRZUEVEX0FSUkFZX1NVUFBPUlQKICAgICAgICAgICAgICAgICAgPyAoKHRoaXNbZV0gPSB0ID4+PiAyNCksICh0aGlzW2UgKyAxXSA9IHQgPj4+IDE2KSwgKHRoaXNbZSArIDJdID0gdCA+Pj4gOCksICh0aGlzW2UgKyAzXSA9IDI1NSAmIHQpKQogICAgICAgICAgICAgICAgICA6IEkodGhpcywgdCwgZSwgITEpLAogICAgICAgICAgICAgICAgZSArIDQKICAgICAgICAgICAgICApCiAgICAgICAgICAgIH0pLAogICAgICAgICAgICAoYS5wcm90b3R5cGUud3JpdGVJbnRMRSA9IGZ1bmN0aW9uICh0LCBlLCByLCBuKSB7CiAgICAgICAgICAgICAgaWYgKCgodCA9ICt0KSwgKGUgfD0gMCksICFuKSkgewogICAgICAgICAgICAgICAgdmFyIGkgPSBNYXRoLnBvdygyLCA4ICogciAtIDEpOwogICAgICAgICAgICAgICAgTSh0aGlzLCB0LCBlLCByLCBpIC0gMSwgLWkpOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB2YXIgbyA9IDAsCiAgICAgICAgICAgICAgICBzID0gMSwKICAgICAgICAgICAgICAgIHUgPSAwOwogICAgICAgICAgICAgIGZvciAodGhpc1tlXSA9IDI1NSAmIHQ7ICsrbyA8IHIgJiYgKHMgKj0gMjU2KTsgKQogICAgICAgICAgICAgICAgdCA8IDAgJiYgMCA9PT0gdSAmJiAwICE9PSB0aGlzW2UgKyBvIC0gMV0gJiYgKHUgPSAxKSwgKHRoaXNbZSArIG9dID0gKCgodCAvIHMpID4+IDApIC0gdSkgJiAyNTUpOwogICAgICAgICAgICAgIHJldHVybiBlICsgcgogICAgICAgICAgICB9KSwKICAgICAgICAgICAgKGEucHJvdG90eXBlLndyaXRlSW50QkUgPSBmdW5jdGlvbiAodCwgZSwgciwgbikgewogICAgICAgICAgICAgIGlmICgoKHQgPSArdCksIChlIHw9IDApLCAhbikpIHsKICAgICAgICAgICAgICAgIHZhciBpID0gTWF0aC5wb3coMiwgOCAqIHIgLSAxKTsKICAgICAgICAgICAgICAgIE0odGhpcywgdCwgZSwgciwgaSAtIDEsIC1pKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgdmFyIG8gPSByIC0gMSwKICAgICAgICAgICAgICAgIHMgPSAxLAogICAgICAgICAgICAgICAgdSA9IDA7CiAgICAgICAgICAgICAgZm9yICh0aGlzW2UgKyBvXSA9IDI1NSAmIHQ7IC0tbyA+PSAwICYmIChzICo9IDI1Nik7ICkKICAgICAgICAgICAgICAgIHQgPCAwICYmIDAgPT09IHUgJiYgMCAhPT0gdGhpc1tlICsgbyArIDFdICYmICh1ID0gMSksICh0aGlzW2UgKyBvXSA9ICgoKHQgLyBzKSA+PiAwKSAtIHUpICYgMjU1KTsKICAgICAgICAgICAgICByZXR1cm4gZSArIHIKICAgICAgICAgICAgfSksCiAgICAgICAgICAgIChhLnByb3RvdHlwZS53cml0ZUludDggPSBmdW5jdGlvbiAodCwgZSwgcikgewogICAgICAgICAgICAgIHJldHVybiAoCiAgICAgICAgICAgICAgICAodCA9ICt0KSwKICAgICAgICAgICAgICAgIChlIHw9IDApLAogICAgICAgICAgICAgICAgciB8fCBNKHRoaXMsIHQsIGUsIDEsIDEyNywgLTEyOCksCiAgICAgICAgICAgICAgICBhLlRZUEVEX0FSUkFZX1NVUFBPUlQgfHwgKHQgPSBNYXRoLmZsb29yKHQpKSwKICAgICAgICAgICAgICAgIHQgPCAwICYmICh0ID0gMjU1ICsgdCArIDEpLAogICAgICAgICAgICAgICAgKHRoaXNbZV0gPSAyNTUgJiB0KSwKICAgICAgICAgICAgICAgIGUgKyAxCiAgICAgICAgICAgICAgKQogICAgICAgICAgICB9KSwKICAgICAgICAgICAgKGEucHJvdG90eXBlLndyaXRlSW50MTZMRSA9IGZ1bmN0aW9uICh0LCBlLCByKSB7CiAgICAgICAgICAgICAgcmV0dXJuICgKICAgICAgICAgICAgICAgICh0ID0gK3QpLAogICAgICAgICAgICAgICAgKGUgfD0gMCksCiAgICAgICAgICAgICAgICByIHx8IE0odGhpcywgdCwgZSwgMiwgMzI3NjcsIC0zMjc2OCksCiAgICAgICAgICAgICAgICBhLlRZUEVEX0FSUkFZX1NVUFBPUlQgPyAoKHRoaXNbZV0gPSAyNTUgJiB0KSwgKHRoaXNbZSArIDFdID0gdCA+Pj4gOCkpIDogeCh0aGlzLCB0LCBlLCAhMCksCiAgICAgICAgICAgICAgICBlICsgMgogICAgICAgICAgICAgICkKICAgICAgICAgICAgfSksCiAgICAgICAgICAgIChhLnByb3RvdHlwZS53cml0ZUludDE2QkUgPSBmdW5jdGlvbiAodCwgZSwgcikgewogICAgICAgICAgICAgIHJldHVybiAoCiAgICAgICAgICAgICAgICAodCA9ICt0KSwKICAgICAgICAgICAgICAgIChlIHw9IDApLAogICAgICAgICAgICAgICAgciB8fCBNKHRoaXMsIHQsIGUsIDIsIDMyNzY3LCAtMzI3NjgpLAogICAgICAgICAgICAgICAgYS5UWVBFRF9BUlJBWV9TVVBQT1JUID8gKCh0aGlzW2VdID0gdCA+Pj4gOCksICh0aGlzW2UgKyAxXSA9IDI1NSAmIHQpKSA6IHgodGhpcywgdCwgZSwgITEpLAogICAgICAgICAgICAgICAgZSArIDIKICAgICAgICAgICAgICApCiAgICAgICAgICAgIH0pLAogICAgICAgICAgICAoYS5wcm90b3R5cGUud3JpdGVJbnQzMkxFID0gZnVuY3Rpb24gKHQsIGUsIHIpIHsKICAgICAgICAgICAgICByZXR1cm4gKAogICAgICAgICAgICAgICAgKHQgPSArdCksCiAgICAgICAgICAgICAgICAoZSB8PSAwKSwKICAgICAgICAgICAgICAgIHIgfHwgTSh0aGlzLCB0LCBlLCA0LCAyMTQ3NDgzNjQ3LCAtMjE0NzQ4MzY0OCksCiAgICAgICAgICAgICAgICBhLlRZUEVEX0FSUkFZX1NVUFBPUlQKICAgICAgICAgICAgICAgICAgPyAoKHRoaXNbZV0gPSAyNTUgJiB0KSwgKHRoaXNbZSArIDFdID0gdCA+Pj4gOCksICh0aGlzW2UgKyAyXSA9IHQgPj4+IDE2KSwgKHRoaXNbZSArIDNdID0gdCA+Pj4gMjQpKQogICAgICAgICAgICAgICAgICA6IEkodGhpcywgdCwgZSwgITApLAogICAgICAgICAgICAgICAgZSArIDQKICAgICAgICAgICAgICApCiAgICAgICAgICAgIH0pLAogICAgICAgICAgICAoYS5wcm90b3R5cGUud3JpdGVJbnQzMkJFID0gZnVuY3Rpb24gKHQsIGUsIHIpIHsKICAgICAgICAgICAgICByZXR1cm4gKAogICAgICAgICAgICAgICAgKHQgPSArdCksCiAgICAgICAgICAgICAgICAoZSB8PSAwKSwKICAgICAgICAgICAgICAgIHIgfHwgTSh0aGlzLCB0LCBlLCA0LCAyMTQ3NDgzNjQ3LCAtMjE0NzQ4MzY0OCksCiAgICAgICAgICAgICAgICB0IDwgMCAmJiAodCA9IDQyOTQ5NjcyOTUgKyB0ICsgMSksCiAgICAgICAgICAgICAgICBhLlRZUEVEX0FSUkFZX1NVUFBPUlQKICAgICAgICAgICAgICAgICAgPyAoKHRoaXNbZV0gPSB0ID4+PiAyNCksICh0aGlzW2UgKyAxXSA9IHQgPj4+IDE2KSwgKHRoaXNbZSArIDJdID0gdCA+Pj4gOCksICh0aGlzW2UgKyAzXSA9IDI1NSAmIHQpKQogICAgICAgICAgICAgICAgICA6IEkodGhpcywgdCwgZSwgITEpLAogICAgICAgICAgICAgICAgZSArIDQKICAgICAgICAgICAgICApCiAgICAgICAgICAgIH0pLAogICAgICAgICAgICAoYS5wcm90b3R5cGUud3JpdGVGbG9hdExFID0gZnVuY3Rpb24gKHQsIGUsIHIpIHsKICAgICAgICAgICAgICByZXR1cm4gWSh0aGlzLCB0LCBlLCAhMCwgcikKICAgICAgICAgICAgfSksCiAgICAgICAgICAgIChhLnByb3RvdHlwZS53cml0ZUZsb2F0QkUgPSBmdW5jdGlvbiAodCwgZSwgcikgewogICAgICAgICAgICAgIHJldHVybiBZKHRoaXMsIHQsIGUsICExLCByKQogICAgICAgICAgICB9KSwKICAgICAgICAgICAgKGEucHJvdG90eXBlLndyaXRlRG91YmxlTEUgPSBmdW5jdGlvbiAodCwgZSwgcikgewogICAgICAgICAgICAgIHJldHVybiBMKHRoaXMsIHQsIGUsICEwLCByKQogICAgICAgICAgICB9KSwKICAgICAgICAgICAgKGEucHJvdG90eXBlLndyaXRlRG91YmxlQkUgPSBmdW5jdGlvbiAodCwgZSwgcikgewogICAgICAgICAgICAgIHJldHVybiBMKHRoaXMsIHQsIGUsICExLCByKQogICAgICAgICAgICB9KSwKICAgICAgICAgICAgKGEucHJvdG90eXBlLmNvcHkgPSBmdW5jdGlvbiAodCwgZSwgciwgbikgewogICAgICAgICAgICAgIGlmICgKICAgICAgICAgICAgICAgIChyIHx8IChyID0gMCksCiAgICAgICAgICAgICAgICBuIHx8IDAgPT09IG4gfHwgKG4gPSB0aGlzLmxlbmd0aCksCiAgICAgICAgICAgICAgICBlID49IHQubGVuZ3RoICYmIChlID0gdC5sZW5ndGgpLAogICAgICAgICAgICAgICAgZSB8fCAoZSA9IDApLAogICAgICAgICAgICAgICAgbiA+IDAgJiYgbiA8IHIgJiYgKG4gPSByKSwKICAgICAgICAgICAgICAgIG4gPT09IHIpCiAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgcmV0dXJuIDAKICAgICAgICAgICAgICBpZiAoMCA9PT0gdC5sZW5ndGggfHwgMCA9PT0gdGhpcy5sZW5ndGgpIHJldHVybiAwCiAgICAgICAgICAgICAgaWYgKGUgPCAwKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcigndGFyZ2V0U3RhcnQgb3V0IG9mIGJvdW5kcycpCiAgICAgICAgICAgICAgaWYgKHIgPCAwIHx8IHIgPj0gdGhpcy5sZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdzb3VyY2VTdGFydCBvdXQgb2YgYm91bmRzJykKICAgICAgICAgICAgICBpZiAobiA8IDApIHRocm93IG5ldyBSYW5nZUVycm9yKCdzb3VyY2VFbmQgb3V0IG9mIGJvdW5kcycpCiAgICAgICAgICAgICAgbiA+IHRoaXMubGVuZ3RoICYmIChuID0gdGhpcy5sZW5ndGgpLCB0Lmxlbmd0aCAtIGUgPCBuIC0gciAmJiAobiA9IHQubGVuZ3RoIC0gZSArIHIpOwogICAgICAgICAgICAgIHZhciBpLAogICAgICAgICAgICAgICAgbyA9IG4gLSByOwogICAgICAgICAgICAgIGlmICh0aGlzID09PSB0ICYmIHIgPCBlICYmIGUgPCBuKSBmb3IgKGkgPSBvIC0gMTsgaSA+PSAwOyAtLWkpIHRbaSArIGVdID0gdGhpc1tpICsgcl07CiAgICAgICAgICAgICAgZWxzZSBpZiAobyA8IDFlMyB8fCAhYS5UWVBFRF9BUlJBWV9TVVBQT1JUKSBmb3IgKGkgPSAwOyBpIDwgbzsgKytpKSB0W2kgKyBlXSA9IHRoaXNbaSArIHJdOwogICAgICAgICAgICAgIGVsc2UgVWludDhBcnJheS5wcm90b3R5cGUuc2V0LmNhbGwodCwgdGhpcy5zdWJhcnJheShyLCByICsgbyksIGUpOwogICAgICAgICAgICAgIHJldHVybiBvCiAgICAgICAgICAgIH0pLAogICAgICAgICAgICAoYS5wcm90b3R5cGUuZmlsbCA9IGZ1bmN0aW9uICh0LCBlLCByLCBuKSB7CiAgICAgICAgICAgICAgaWYgKCdzdHJpbmcnID09IHR5cGVvZiB0KSB7CiAgICAgICAgICAgICAgICBpZiAoCiAgICAgICAgICAgICAgICAgICgnc3RyaW5nJyA9PSB0eXBlb2YgZQogICAgICAgICAgICAgICAgICAgID8gKChuID0gZSksIChlID0gMCksIChyID0gdGhpcy5sZW5ndGgpKQogICAgICAgICAgICAgICAgICAgIDogJ3N0cmluZycgPT0gdHlwZW9mIHIgJiYgKChuID0gciksIChyID0gdGhpcy5sZW5ndGgpKSwKICAgICAgICAgICAgICAgICAgMSA9PT0gdC5sZW5ndGgpCiAgICAgICAgICAgICAgICApIHsKICAgICAgICAgICAgICAgICAgdmFyIGkgPSB0LmNoYXJDb2RlQXQoMCk7CiAgICAgICAgICAgICAgICAgIGkgPCAyNTYgJiYgKHQgPSBpKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGlmICh2b2lkIDAgIT09IG4gJiYgJ3N0cmluZycgIT0gdHlwZW9mIG4pIHRocm93IG5ldyBUeXBlRXJyb3IoJ2VuY29kaW5nIG11c3QgYmUgYSBzdHJpbmcnKQogICAgICAgICAgICAgICAgaWYgKCdzdHJpbmcnID09IHR5cGVvZiBuICYmICFhLmlzRW5jb2RpbmcobikpIHRocm93IG5ldyBUeXBlRXJyb3IoJ1Vua25vd24gZW5jb2Rpbmc6ICcgKyBuKQogICAgICAgICAgICAgIH0gZWxzZSAnbnVtYmVyJyA9PSB0eXBlb2YgdCAmJiAodCAmPSAyNTUpOwogICAgICAgICAgICAgIGlmIChlIDwgMCB8fCB0aGlzLmxlbmd0aCA8IGUgfHwgdGhpcy5sZW5ndGggPCByKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignT3V0IG9mIHJhbmdlIGluZGV4JykKICAgICAgICAgICAgICBpZiAociA8PSBlKSByZXR1cm4gdGhpcwogICAgICAgICAgICAgIHZhciBvOwogICAgICAgICAgICAgIGlmICgoKGUgPj4+PSAwKSwgKHIgPSB2b2lkIDAgPT09IHIgPyB0aGlzLmxlbmd0aCA6IHIgPj4+IDApLCB0IHx8ICh0ID0gMCksICdudW1iZXInID09IHR5cGVvZiB0KSkKICAgICAgICAgICAgICAgIGZvciAobyA9IGU7IG8gPCByOyArK28pIHRoaXNbb10gPSB0OwogICAgICAgICAgICAgIGVsc2UgewogICAgICAgICAgICAgICAgdmFyIHMgPSBhLmlzQnVmZmVyKHQpID8gdCA6IGsobmV3IGEodCwgbikudG9TdHJpbmcoKSksCiAgICAgICAgICAgICAgICAgIHUgPSBzLmxlbmd0aDsKICAgICAgICAgICAgICAgIGZvciAobyA9IDA7IG8gPCByIC0gZTsgKytvKSB0aGlzW28gKyBlXSA9IHNbbyAlIHVdOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICByZXR1cm4gdGhpcwogICAgICAgICAgICB9KTsKICAgICAgICAgIHZhciBEID0gL1teK1wvMC05QS1aYS16LV9dL2c7CiAgICAgICAgICBmdW5jdGlvbiBOKHQpIHsKICAgICAgICAgICAgcmV0dXJuIHQgPCAxNiA/ICcwJyArIHQudG9TdHJpbmcoMTYpIDogdC50b1N0cmluZygxNikKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIGsodCwgZSkgewogICAgICAgICAgICB2YXIgcjsKICAgICAgICAgICAgZSA9IGUgfHwgMSAvIDA7CiAgICAgICAgICAgIGZvciAodmFyIG4gPSB0Lmxlbmd0aCwgaSA9IG51bGwsIG8gPSBbXSwgcyA9IDA7IHMgPCBuOyArK3MpIHsKICAgICAgICAgICAgICBpZiAoKHIgPSB0LmNoYXJDb2RlQXQocykpID4gNTUyOTUgJiYgciA8IDU3MzQ0KSB7CiAgICAgICAgICAgICAgICBpZiAoIWkpIHsKICAgICAgICAgICAgICAgICAgaWYgKHIgPiA1NjMxOSkgewogIChlIC09IDMpID4gLTEgJiYgby5wdXNoKDIzOSwgMTkxLCAxODkpOwogICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgaWYgKHMgKyAxID09PSBuKSB7CiAgKGUgLT0gMykgPiAtMSAmJiBvLnB1c2goMjM5LCAxOTEsIDE4OSk7CiAgICAgICAgICAgICAgICAgICAgY29udGludWUKICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICBpID0gcjsKICAgICAgICAgICAgICAgICAgY29udGludWUKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGlmIChyIDwgNTYzMjApIHsKICAoZSAtPSAzKSA+IC0xICYmIG8ucHVzaCgyMzksIDE5MSwgMTg5KSwgKGkgPSByKTsKICAgICAgICAgICAgICAgICAgY29udGludWUKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIHIgPSA2NTUzNiArICgoKGkgLSA1NTI5NikgPDwgMTApIHwgKHIgLSA1NjMyMCkpOwogICAgICAgICAgICAgIH0gZWxzZSBpICYmIChlIC09IDMpID4gLTEgJiYgby5wdXNoKDIzOSwgMTkxLCAxODkpOwogICAgICAgICAgICAgIGlmICgoKGkgPSBudWxsKSwgciA8IDEyOCkpIHsKICAgICAgICAgICAgICAgIGlmICgoZSAtPSAxKSA8IDApIGJyZWFrCiAgICAgICAgICAgICAgICBvLnB1c2gocik7CiAgICAgICAgICAgICAgfSBlbHNlIGlmIChyIDwgMjA0OCkgewogICAgICAgICAgICAgICAgaWYgKChlIC09IDIpIDwgMCkgYnJlYWsKICAgICAgICAgICAgICAgIG8ucHVzaCgociA+PiA2KSB8IDE5MiwgKDYzICYgcikgfCAxMjgpOwogICAgICAgICAgICAgIH0gZWxzZSBpZiAociA8IDY1NTM2KSB7CiAgICAgICAgICAgICAgICBpZiAoKGUgLT0gMykgPCAwKSBicmVhawogICAgICAgICAgICAgICAgby5wdXNoKChyID4+IDEyKSB8IDIyNCwgKChyID4+IDYpICYgNjMpIHwgMTI4LCAoNjMgJiByKSB8IDEyOCk7CiAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIGlmICghKHIgPCAxMTE0MTEyKSkgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGNvZGUgcG9pbnQnKQogICAgICAgICAgICAgICAgaWYgKChlIC09IDQpIDwgMCkgYnJlYWsKICAgICAgICAgICAgICAgIG8ucHVzaCgociA+PiAxOCkgfCAyNDAsICgociA+PiAxMikgJiA2MykgfCAxMjgsICgociA+PiA2KSAmIDYzKSB8IDEyOCwgKDYzICYgcikgfCAxMjgpOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gbwogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gaih0KSB7CiAgICAgICAgICAgIHJldHVybiBuLnRvQnl0ZUFycmF5KAogICAgICAgICAgICAgIChmdW5jdGlvbiAodCkgewogICAgICAgICAgICAgICAgaWYgKAogICAgICAgICAgICAgICAgICAodCA9IChmdW5jdGlvbiAodCkgewogICAgICAgICAgICAgICAgICAgIHJldHVybiB0LnRyaW0gPyB0LnRyaW0oKSA6IHQucmVwbGFjZSgvXlxzK3xccyskL2csICcnKQogICAgICAgICAgICAgICAgICB9KSh0KS5yZXBsYWNlKEQsICcnKSkubGVuZ3RoIDwgMgogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICByZXR1cm4gJycKICAgICAgICAgICAgICAgIGZvciAoOyB0Lmxlbmd0aCAlIDQgIT0gMDsgKSB0ICs9ICc9JzsKICAgICAgICAgICAgICAgIHJldHVybiB0CiAgICAgICAgICAgICAgfSkodCkKICAgICAgICAgICAgKQogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24geih0LCBlLCByLCBuKSB7CiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbiAmJiAhKGkgKyByID49IGUubGVuZ3RoIHx8IGkgPj0gdC5sZW5ndGgpOyArK2kpIGVbaSArIHJdID0gdFtpXTsKICAgICAgICAgICAgcmV0dXJuIGkKICAgICAgICAgIH0KICAgICAgICB9LmNhbGwodGhpcywgcig4KSkpOwogICAgICB9LAogICAgICBmdW5jdGlvbiAodCwgZSkgewogICAgICAgIHZhciByOwogICAgICAgIHIgPSAoZnVuY3Rpb24gKCkgewogICAgICAgICAgcmV0dXJuIHRoaXMKICAgICAgICB9KSgpOwogICAgICAgIHRyeSB7CiAgICAgICAgICByID0gciB8fCBGdW5jdGlvbigncmV0dXJuIHRoaXMnKSgpIHx8ICgwLCBldmFsKSgndGhpcycpOwogICAgICAgIH0gY2F0Y2ggKHQpIHsKICAgICAgICAgICdvYmplY3QnID09IHR5cGVvZiB3aW5kb3cgJiYgKHIgPSB3aW5kb3cpOwogICAgICAgIH0KICAgICAgICB0LmV4cG9ydHMgPSByOwogICAgICB9LAogICAgICBmdW5jdGlvbiAodCwgZSwgcikgewogIChlLmJ5dGVMZW5ndGggPSBmdW5jdGlvbiAodCkgewogICAgICAgICAgdmFyIGUgPSBmKHQpLAogICAgICAgICAgICByID0gZVswXSwKICAgICAgICAgICAgbiA9IGVbMV07CiAgICAgICAgICByZXR1cm4gKDMgKiAociArIG4pKSAvIDQgLSBuCiAgICAgICAgfSksCiAgICAgICAgICAoZS50b0J5dGVBcnJheSA9IGZ1bmN0aW9uICh0KSB7CiAgICAgICAgICAgIGZvciAoCiAgICAgICAgICAgICAgdmFyIGUsCiAgICAgICAgICAgICAgICByID0gZih0KSwKICAgICAgICAgICAgICAgIG4gPSByWzBdLAogICAgICAgICAgICAgICAgcyA9IHJbMV0sCiAgICAgICAgICAgICAgICB1ID0gbmV3IG8oCiAgICAgICAgICAgICAgICAgIChmdW5jdGlvbiAodCwgZSwgcikgewogICAgICAgICAgICAgICAgICAgIHJldHVybiAoMyAqIChlICsgcikpIC8gNCAtIHIKICAgICAgICAgICAgICAgICAgfSkoMCwgbiwgcykKICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICBhID0gMCwKICAgICAgICAgICAgICAgIGggPSBzID4gMCA/IG4gLSA0IDogbiwKICAgICAgICAgICAgICAgIGwgPSAwOwogICAgICAgICAgICAgIGwgPCBoOwogICAgICAgICAgICAgIGwgKz0gNAogICAgICAgICAgICApCiAgICAgICAgICAgICAgKGUgPQogICAgICAgICAgICAgICAgKGlbdC5jaGFyQ29kZUF0KGwpXSA8PCAxOCkgfAogICAgICAgICAgICAgICAgKGlbdC5jaGFyQ29kZUF0KGwgKyAxKV0gPDwgMTIpIHwKICAgICAgICAgICAgICAgIChpW3QuY2hhckNvZGVBdChsICsgMildIDw8IDYpIHwKICAgICAgICAgICAgICAgIGlbdC5jaGFyQ29kZUF0KGwgKyAzKV0pLAogICAgICAgICAgICAgICAgKHVbYSsrXSA9IChlID4+IDE2KSAmIDI1NSksCiAgICAgICAgICAgICAgICAodVthKytdID0gKGUgPj4gOCkgJiAyNTUpLAogICAgICAgICAgICAgICAgKHVbYSsrXSA9IDI1NSAmIGUpOwogICAgICAgICAgICAyID09PSBzICYmICgoZSA9IChpW3QuY2hhckNvZGVBdChsKV0gPDwgMikgfCAoaVt0LmNoYXJDb2RlQXQobCArIDEpXSA+PiA0KSksICh1W2ErK10gPSAyNTUgJiBlKSk7CiAgICAgICAgICAgIDEgPT09IHMgJiYKICAgICAgICAgICAgICAoKGUgPSAoaVt0LmNoYXJDb2RlQXQobCldIDw8IDEwKSB8IChpW3QuY2hhckNvZGVBdChsICsgMSldIDw8IDQpIHwgKGlbdC5jaGFyQ29kZUF0KGwgKyAyKV0gPj4gMikpLAogICAgICAgICAgICAgICh1W2ErK10gPSAoZSA+PiA4KSAmIDI1NSksCiAgICAgICAgICAgICAgKHVbYSsrXSA9IDI1NSAmIGUpKTsKICAgICAgICAgICAgcmV0dXJuIHUKICAgICAgICAgIH0pLAogICAgICAgICAgKGUuZnJvbUJ5dGVBcnJheSA9IGZ1bmN0aW9uICh0KSB7CiAgICAgICAgICAgIGZvciAodmFyIGUsIHIgPSB0Lmxlbmd0aCwgaSA9IHIgJSAzLCBvID0gW10sIHMgPSAwLCB1ID0gciAtIGk7IHMgPCB1OyBzICs9IDE2MzgzKQogICAgICAgICAgICAgIG8ucHVzaChsKHQsIHMsIHMgKyAxNjM4MyA+IHUgPyB1IDogcyArIDE2MzgzKSk7CiAgICAgICAgICAgIDEgPT09IGkKICAgICAgICAgICAgICA/ICgoZSA9IHRbciAtIDFdKSwgby5wdXNoKG5bZSA+PiAyXSArIG5bKGUgPDwgNCkgJiA2M10gKyAnPT0nKSkKICAgICAgICAgICAgICA6IDIgPT09IGkgJiYKICAgICAgICAgICAgICAgICgoZSA9ICh0W3IgLSAyXSA8PCA4KSArIHRbciAtIDFdKSwgby5wdXNoKG5bZSA+PiAxMF0gKyBuWyhlID4+IDQpICYgNjNdICsgblsoZSA8PCAyKSAmIDYzXSArICc9JykpOwogICAgICAgICAgICByZXR1cm4gby5qb2luKCcnKQogICAgICAgICAgfSk7CiAgICAgICAgZm9yICgKICAgICAgICAgIHZhciBuID0gW10sCiAgICAgICAgICAgIGkgPSBbXSwKICAgICAgICAgICAgbyA9ICd1bmRlZmluZWQnICE9IHR5cGVvZiBVaW50OEFycmF5ID8gVWludDhBcnJheSA6IEFycmF5LAogICAgICAgICAgICBzID0gJ0FCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5Ky8nLAogICAgICAgICAgICB1ID0gMCwKICAgICAgICAgICAgYSA9IHMubGVuZ3RoOwogICAgICAgICAgdSA8IGE7CiAgICAgICAgICArK3UKICAgICAgICApCiAgICAgICAgICAoblt1XSA9IHNbdV0pLCAoaVtzLmNoYXJDb2RlQXQodSldID0gdSk7CiAgICAgICAgZnVuY3Rpb24gZih0KSB7CiAgICAgICAgICB2YXIgZSA9IHQubGVuZ3RoOwogICAgICAgICAgaWYgKGUgJSA0ID4gMCkgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIHN0cmluZy4gTGVuZ3RoIG11c3QgYmUgYSBtdWx0aXBsZSBvZiA0JykKICAgICAgICAgIHZhciByID0gdC5pbmRleE9mKCc9Jyk7CiAgICAgICAgICByZXR1cm4gLTEgPT09IHIgJiYgKHIgPSBlKSwgW3IsIHIgPT09IGUgPyAwIDogNCAtIChyICUgNCldCiAgICAgICAgfQogICAgICAgIGZ1bmN0aW9uIGgodCkgewogICAgICAgICAgcmV0dXJuIG5bKHQgPj4gMTgpICYgNjNdICsgblsodCA+PiAxMikgJiA2M10gKyBuWyh0ID4+IDYpICYgNjNdICsgbls2MyAmIHRdCiAgICAgICAgfQogICAgICAgIGZ1bmN0aW9uIGwodCwgZSwgcikgewogICAgICAgICAgZm9yICh2YXIgbiwgaSA9IFtdLCBvID0gZTsgbyA8IHI7IG8gKz0gMykKICAgICAgICAgICAgKG4gPSAoKHRbb10gPDwgMTYpICYgMTY3MTE2ODApICsgKCh0W28gKyAxXSA8PCA4KSAmIDY1MjgwKSArICgyNTUgJiB0W28gKyAyXSkpLCBpLnB1c2goaChuKSk7CiAgICAgICAgICByZXR1cm4gaS5qb2luKCcnKQogICAgICAgIH0KICAoaVsnLScuY2hhckNvZGVBdCgwKV0gPSA2MiksIChpWydfJy5jaGFyQ29kZUF0KDApXSA9IDYzKTsKICAgICAgfSwKICAgICAgZnVuY3Rpb24gKHQsIGUpIHsKICAoZS5yZWFkID0gZnVuY3Rpb24gKHQsIGUsIHIsIG4sIGkpIHsKICAgICAgICAgIHZhciBvLAogICAgICAgICAgICBzLAogICAgICAgICAgICB1ID0gOCAqIGkgLSBuIC0gMSwKICAgICAgICAgICAgYSA9ICgxIDw8IHUpIC0gMSwKICAgICAgICAgICAgZiA9IGEgPj4gMSwKICAgICAgICAgICAgaCA9IC03LAogICAgICAgICAgICBsID0gciA/IGkgLSAxIDogMCwKICAgICAgICAgICAgYyA9IHIgPyAtMSA6IDEsCiAgICAgICAgICAgIHAgPSB0W2UgKyBsXTsKICAgICAgICAgIGZvciAobCArPSBjLCBvID0gcCAmICgoMSA8PCAtaCkgLSAxKSwgcCA+Pj0gLWgsIGggKz0gdTsgaCA+IDA7IG8gPSAyNTYgKiBvICsgdFtlICsgbF0sIGwgKz0gYywgaCAtPSA4KTsKICAgICAgICAgIGZvciAocyA9IG8gJiAoKDEgPDwgLWgpIC0gMSksIG8gPj49IC1oLCBoICs9IG47IGggPiAwOyBzID0gMjU2ICogcyArIHRbZSArIGxdLCBsICs9IGMsIGggLT0gOCk7CiAgICAgICAgICBpZiAoMCA9PT0gbykgbyA9IDEgLSBmOwogICAgICAgICAgZWxzZSB7CiAgICAgICAgICAgIGlmIChvID09PSBhKSByZXR1cm4gcyA/IE5hTiA6ICgxIC8gMCkgKiAocCA/IC0xIDogMSkKICAgICAgICAgICAgOyhzICs9IE1hdGgucG93KDIsIG4pKSwgKG8gLT0gZik7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gKHAgPyAtMSA6IDEpICogcyAqIE1hdGgucG93KDIsIG8gLSBuKQogICAgICAgIH0pLAogICAgICAgICAgKGUud3JpdGUgPSBmdW5jdGlvbiAodCwgZSwgciwgbiwgaSwgbykgewogICAgICAgICAgICB2YXIgcywKICAgICAgICAgICAgICB1LAogICAgICAgICAgICAgIGEsCiAgICAgICAgICAgICAgZiA9IDggKiBvIC0gaSAtIDEsCiAgICAgICAgICAgICAgaCA9ICgxIDw8IGYpIC0gMSwKICAgICAgICAgICAgICBsID0gaCA+PiAxLAogICAgICAgICAgICAgIGMgPSAyMyA9PT0gaSA/IE1hdGgucG93KDIsIC0yNCkgLSBNYXRoLnBvdygyLCAtNzcpIDogMCwKICAgICAgICAgICAgICBwID0gbiA/IDAgOiBvIC0gMSwKICAgICAgICAgICAgICBnID0gbiA/IDEgOiAtMSwKICAgICAgICAgICAgICBkID0gZSA8IDAgfHwgKDAgPT09IGUgJiYgMSAvIGUgPCAwKSA/IDEgOiAwOwogICAgICAgICAgICBmb3IgKAogICAgICAgICAgICAgIGUgPSBNYXRoLmFicyhlKSwKICAgICAgICAgICAgICAgIGlzTmFOKGUpIHx8IGUgPT09IDEgLyAwCiAgICAgICAgICAgICAgICAgID8gKCh1ID0gaXNOYU4oZSkgPyAxIDogMCksIChzID0gaCkpCiAgICAgICAgICAgICAgICAgIDogKChzID0gTWF0aC5mbG9vcihNYXRoLmxvZyhlKSAvIE1hdGguTE4yKSksCiAgICAgICAgICAgICAgICAgICAgZSAqIChhID0gTWF0aC5wb3coMiwgLXMpKSA8IDEgJiYgKHMtLSwgKGEgKj0gMikpLAogICAgICAgICAgICAgICAgICAgIChlICs9IHMgKyBsID49IDEgPyBjIC8gYSA6IGMgKiBNYXRoLnBvdygyLCAxIC0gbCkpICogYSA+PSAyICYmIChzKyssIChhIC89IDIpKSwKICAgICAgICAgICAgICAgICAgICBzICsgbCA+PSBoCiAgICAgICAgICAgICAgICAgICAgICA/ICgodSA9IDApLCAocyA9IGgpKQogICAgICAgICAgICAgICAgICAgICAgOiBzICsgbCA+PSAxCiAgICAgICAgICAgICAgICAgICAgICA/ICgodSA9IChlICogYSAtIDEpICogTWF0aC5wb3coMiwgaSkpLCAocyArPSBsKSkKICAgICAgICAgICAgICAgICAgICAgIDogKCh1ID0gZSAqIE1hdGgucG93KDIsIGwgLSAxKSAqIE1hdGgucG93KDIsIGkpKSwgKHMgPSAwKSkpOwogICAgICAgICAgICAgIGkgPj0gODsKICAgICAgICAgICAgICB0W3IgKyBwXSA9IDI1NSAmIHUsIHAgKz0gZywgdSAvPSAyNTYsIGkgLT0gOAogICAgICAgICAgICApOwogICAgICAgICAgICBmb3IgKHMgPSAocyA8PCBpKSB8IHUsIGYgKz0gaTsgZiA+IDA7IHRbciArIHBdID0gMjU1ICYgcywgcCArPSBnLCBzIC89IDI1NiwgZiAtPSA4KTsKICAgICAgICAgICAgdFtyICsgcCAtIGddIHw9IDEyOCAqIGQ7CiAgICAgICAgICB9KTsKICAgICAgfSwKICAgICAgZnVuY3Rpb24gKHQsIGUpIHsKICAgICAgICB2YXIgciA9IHt9LnRvU3RyaW5nOwogICAgICAgIHQuZXhwb3J0cyA9CiAgICAgICAgICBBcnJheS5pc0FycmF5IHx8CiAgICAgICAgICBmdW5jdGlvbiAodCkgewogICAgICAgICAgICByZXR1cm4gJ1tvYmplY3QgQXJyYXldJyA9PSByLmNhbGwodCkKICAgICAgICAgIH07CiAgICAgIH0sCiAgICAgIGZ1bmN0aW9uIChlLCByKSB7CiAgICAgICAgZS5leHBvcnRzID0gdDsKICAgICAgfSwKICAgICAgZnVuY3Rpb24gKHQsIGUsIHIpIHsKICAoZnVuY3Rpb24gKHQpIHsKICAgICAgICAgIGZ1bmN0aW9uIHIodCwgZSkgewogICAgICAgICAgICBmb3IgKHZhciByID0gMCwgbiA9IHQubGVuZ3RoIC0gMTsgbiA+PSAwOyBuLS0pIHsKICAgICAgICAgICAgICB2YXIgaSA9IHRbbl07CiAgICAgICAgICAgICAgJy4nID09PSBpID8gdC5zcGxpY2UobiwgMSkgOiAnLi4nID09PSBpID8gKHQuc3BsaWNlKG4sIDEpLCByKyspIDogciAmJiAodC5zcGxpY2UobiwgMSksIHItLSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKGUpIGZvciAoOyByLS07IHIpIHQudW5zaGlmdCgnLi4nKTsKICAgICAgICAgICAgcmV0dXJuIHQKICAgICAgICAgIH0KICAgICAgICAgIHZhciBuID0gL14oXC8/fCkoW1xzXFNdKj8pKCg/OlwuezEsMn18W15cL10rP3wpKFwuW14uXC9dKnwpKSg/OltcL10qKSQvLAogICAgICAgICAgICBpID0gZnVuY3Rpb24gKHQpIHsKICAgICAgICAgICAgICByZXR1cm4gbi5leGVjKHQpLnNsaWNlKDEpCiAgICAgICAgICAgIH07CiAgICAgICAgICBmdW5jdGlvbiBvKHQsIGUpIHsKICAgICAgICAgICAgaWYgKHQuZmlsdGVyKSByZXR1cm4gdC5maWx0ZXIoZSkKICAgICAgICAgICAgZm9yICh2YXIgciA9IFtdLCBuID0gMDsgbiA8IHQubGVuZ3RoOyBuKyspIGUodFtuXSwgbiwgdCkgJiYgci5wdXNoKHRbbl0pOwogICAgICAgICAgICByZXR1cm4gcgogICAgICAgICAgfQogIChlLnJlc29sdmUgPSBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgIGZvciAodmFyIGUgPSAnJywgbiA9ICExLCBpID0gYXJndW1lbnRzLmxlbmd0aCAtIDE7IGkgPj0gLTEgJiYgIW47IGktLSkgewogICAgICAgICAgICAgIHZhciBzID0gaSA+PSAwID8gYXJndW1lbnRzW2ldIDogdC5jd2QoKTsKICAgICAgICAgICAgICBpZiAoJ3N0cmluZycgIT0gdHlwZW9mIHMpIHRocm93IG5ldyBUeXBlRXJyb3IoJ0FyZ3VtZW50cyB0byBwYXRoLnJlc29sdmUgbXVzdCBiZSBzdHJpbmdzJykKICAgICAgICAgICAgICBzICYmICgoZSA9IHMgKyAnLycgKyBlKSwgKG4gPSAnLycgPT09IHMuY2hhckF0KDApKSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuICgKICAgICAgICAgICAgICAoZSA9IHIoCiAgICAgICAgICAgICAgICBvKGUuc3BsaXQoJy8nKSwgZnVuY3Rpb24gKHQpIHsKICAgICAgICAgICAgICAgICAgcmV0dXJuICEhdAogICAgICAgICAgICAgICAgfSksCiAgICAgICAgICAgICAgICAhbgogICAgICAgICAgICAgICkuam9pbignLycpKSwKICAgICAgICAgICAgICAobiA/ICcvJyA6ICcnKSArIGUgfHwgJy4nCiAgICAgICAgICAgICkKICAgICAgICAgIH0pLAogICAgICAgICAgICAoZS5ub3JtYWxpemUgPSBmdW5jdGlvbiAodCkgewogICAgICAgICAgICAgIHZhciBuID0gZS5pc0Fic29sdXRlKHQpLAogICAgICAgICAgICAgICAgaSA9ICcvJyA9PT0gcyh0LCAtMSk7CiAgICAgICAgICAgICAgcmV0dXJuICgKICAgICAgICAgICAgICAgICh0ID0gcigKICAgICAgICAgICAgICAgICAgbyh0LnNwbGl0KCcvJyksIGZ1bmN0aW9uICh0KSB7CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuICEhdAogICAgICAgICAgICAgICAgICB9KSwKICAgICAgICAgICAgICAgICAgIW4KICAgICAgICAgICAgICAgICkuam9pbignLycpKSB8fAogICAgICAgICAgICAgICAgICBuIHx8CiAgICAgICAgICAgICAgICAgICh0ID0gJy4nKSwKICAgICAgICAgICAgICAgIHQgJiYgaSAmJiAodCArPSAnLycpLAogICAgICAgICAgICAgICAgKG4gPyAnLycgOiAnJykgKyB0CiAgICAgICAgICAgICAgKQogICAgICAgICAgICB9KSwKICAgICAgICAgICAgKGUuaXNBYnNvbHV0ZSA9IGZ1bmN0aW9uICh0KSB7CiAgICAgICAgICAgICAgcmV0dXJuICcvJyA9PT0gdC5jaGFyQXQoMCkKICAgICAgICAgICAgfSksCiAgICAgICAgICAgIChlLmpvaW4gPSBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgICAgdmFyIHQgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsIDApOwogICAgICAgICAgICAgIHJldHVybiBlLm5vcm1hbGl6ZSgKICAgICAgICAgICAgICAgIG8odCwgZnVuY3Rpb24gKHQsIGUpIHsKICAgICAgICAgICAgICAgICAgaWYgKCdzdHJpbmcnICE9IHR5cGVvZiB0KSB0aHJvdyBuZXcgVHlwZUVycm9yKCdBcmd1bWVudHMgdG8gcGF0aC5qb2luIG11c3QgYmUgc3RyaW5ncycpCiAgICAgICAgICAgICAgICAgIHJldHVybiB0CiAgICAgICAgICAgICAgICB9KS5qb2luKCcvJykKICAgICAgICAgICAgICApCiAgICAgICAgICAgIH0pLAogICAgICAgICAgICAoZS5yZWxhdGl2ZSA9IGZ1bmN0aW9uICh0LCByKSB7CiAgICAgICAgICAgICAgZnVuY3Rpb24gbih0KSB7CiAgICAgICAgICAgICAgICBmb3IgKHZhciBlID0gMDsgZSA8IHQubGVuZ3RoICYmICcnID09PSB0W2VdOyBlKyspOwogICAgICAgICAgICAgICAgZm9yICh2YXIgciA9IHQubGVuZ3RoIC0gMTsgciA+PSAwICYmICcnID09PSB0W3JdOyByLS0pOwogICAgICAgICAgICAgICAgcmV0dXJuIGUgPiByID8gW10gOiB0LnNsaWNlKGUsIHIgLSBlICsgMSkKICAgICAgICAgICAgICB9CiAgKHQgPSBlLnJlc29sdmUodCkuc3Vic3RyKDEpKSwgKHIgPSBlLnJlc29sdmUocikuc3Vic3RyKDEpKTsKICAgICAgICAgICAgICBmb3IgKAogICAgICAgICAgICAgICAgdmFyIGkgPSBuKHQuc3BsaXQoJy8nKSksIG8gPSBuKHIuc3BsaXQoJy8nKSksIHMgPSBNYXRoLm1pbihpLmxlbmd0aCwgby5sZW5ndGgpLCB1ID0gcywgYSA9IDA7CiAgICAgICAgICAgICAgICBhIDwgczsKICAgICAgICAgICAgICAgIGErKwogICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIGlmIChpW2FdICE9PSBvW2FdKSB7CiAgICAgICAgICAgICAgICAgIHUgPSBhOwogICAgICAgICAgICAgICAgICBicmVhawogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHZhciBmID0gW107CiAgICAgICAgICAgICAgZm9yIChhID0gdTsgYSA8IGkubGVuZ3RoOyBhKyspIGYucHVzaCgnLi4nKTsKICAgICAgICAgICAgICByZXR1cm4gKGYgPSBmLmNvbmNhdChvLnNsaWNlKHUpKSkuam9pbignLycpCiAgICAgICAgICAgIH0pLAogICAgICAgICAgICAoZS5zZXAgPSAnLycpLAogICAgICAgICAgICAoZS5kZWxpbWl0ZXIgPSAnOicpLAogICAgICAgICAgICAoZS5kaXJuYW1lID0gZnVuY3Rpb24gKHQpIHsKICAgICAgICAgICAgICB2YXIgZSA9IGkodCksCiAgICAgICAgICAgICAgICByID0gZVswXSwKICAgICAgICAgICAgICAgIG4gPSBlWzFdOwogICAgICAgICAgICAgIHJldHVybiByIHx8IG4gPyAobiAmJiAobiA9IG4uc3Vic3RyKDAsIG4ubGVuZ3RoIC0gMSkpLCByICsgbikgOiAnLicKICAgICAgICAgICAgfSksCiAgICAgICAgICAgIChlLmJhc2VuYW1lID0gZnVuY3Rpb24gKHQsIGUpIHsKICAgICAgICAgICAgICB2YXIgciA9IGkodClbMl07CiAgICAgICAgICAgICAgcmV0dXJuIGUgJiYgci5zdWJzdHIoLTEgKiBlLmxlbmd0aCkgPT09IGUgJiYgKHIgPSByLnN1YnN0cigwLCByLmxlbmd0aCAtIGUubGVuZ3RoKSksIHIKICAgICAgICAgICAgfSksCiAgICAgICAgICAgIChlLmV4dG5hbWUgPSBmdW5jdGlvbiAodCkgewogICAgICAgICAgICAgIHJldHVybiBpKHQpWzNdCiAgICAgICAgICAgIH0pOwogICAgICAgICAgdmFyIHMgPQogICAgICAgICAgICAnYicgPT09ICdhYicuc3Vic3RyKC0xKQogICAgICAgICAgICAgID8gZnVuY3Rpb24gKHQsIGUsIHIpIHsKICAgICAgICAgICAgICAgICAgcmV0dXJuIHQuc3Vic3RyKGUsIHIpCiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgOiBmdW5jdGlvbiAodCwgZSwgcikgewogICAgICAgICAgICAgICAgICByZXR1cm4gZSA8IDAgJiYgKGUgPSB0Lmxlbmd0aCArIGUpLCB0LnN1YnN0cihlLCByKQogICAgICAgICAgICAgICAgfTsKICAgICAgICB9LmNhbGwodGhpcywgcigxNCkpKTsKICAgICAgfSwKICAgICAgZnVuY3Rpb24gKHQsIGUpIHsKICAgICAgICB2YXIgciwKICAgICAgICAgIG4sCiAgICAgICAgICBpID0gKHQuZXhwb3J0cyA9IHt9KTsKICAgICAgICBmdW5jdGlvbiBvKCkgewogICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdzZXRUaW1lb3V0IGhhcyBub3QgYmVlbiBkZWZpbmVkJykKICAgICAgICB9CiAgICAgICAgZnVuY3Rpb24gcygpIHsKICAgICAgICAgIHRocm93IG5ldyBFcnJvcignY2xlYXJUaW1lb3V0IGhhcyBub3QgYmVlbiBkZWZpbmVkJykKICAgICAgICB9CiAgICAgICAgZnVuY3Rpb24gdSh0KSB7CiAgICAgICAgICBpZiAociA9PT0gc2V0VGltZW91dCkgcmV0dXJuIHNldFRpbWVvdXQodCwgMCkKICAgICAgICAgIGlmICgociA9PT0gbyB8fCAhcikgJiYgc2V0VGltZW91dCkgcmV0dXJuIChyID0gc2V0VGltZW91dCksIHNldFRpbWVvdXQodCwgMCkKICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgIHJldHVybiByKHQsIDApCiAgICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgICAgcmV0dXJuIHIuY2FsbChudWxsLCB0LCAwKQogICAgICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICAgICAgcmV0dXJuIHIuY2FsbCh0aGlzLCB0LCAwKQogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgICEoZnVuY3Rpb24gKCkgewogICAgICAgICAgdHJ5IHsKICAgICAgICAgICAgciA9ICdmdW5jdGlvbicgPT0gdHlwZW9mIHNldFRpbWVvdXQgPyBzZXRUaW1lb3V0IDogbzsKICAgICAgICAgIH0gY2F0Y2ggKHQpIHsKICAgICAgICAgICAgciA9IG87CiAgICAgICAgICB9CiAgICAgICAgICB0cnkgewogICAgICAgICAgICBuID0gJ2Z1bmN0aW9uJyA9PSB0eXBlb2YgY2xlYXJUaW1lb3V0ID8gY2xlYXJUaW1lb3V0IDogczsKICAgICAgICAgIH0gY2F0Y2ggKHQpIHsKICAgICAgICAgICAgbiA9IHM7CiAgICAgICAgICB9CiAgICAgICAgfSkoKTsKICAgICAgICB2YXIgYSwKICAgICAgICAgIGYgPSBbXSwKICAgICAgICAgIGggPSAhMSwKICAgICAgICAgIGwgPSAtMTsKICAgICAgICBmdW5jdGlvbiBjKCkgewogICAgICAgICAgaCAmJiBhICYmICgoaCA9ICExKSwgYS5sZW5ndGggPyAoZiA9IGEuY29uY2F0KGYpKSA6IChsID0gLTEpLCBmLmxlbmd0aCAmJiBwKCkpOwogICAgICAgIH0KICAgICAgICBmdW5jdGlvbiBwKCkgewogICAgICAgICAgaWYgKCFoKSB7CiAgICAgICAgICAgIHZhciB0ID0gdShjKTsKICAgICAgICAgICAgaCA9ICEwOwogICAgICAgICAgICBmb3IgKHZhciBlID0gZi5sZW5ndGg7IGU7ICkgewogICAgICAgICAgICAgIGZvciAoYSA9IGYsIGYgPSBbXTsgKytsIDwgZTsgKSBhICYmIGFbbF0ucnVuKCkKICAgICAgICAgICAgICA7KGwgPSAtMSksIChlID0gZi5sZW5ndGgpOwogICAgICAgICAgICB9CiAgKGEgPSBudWxsKSwKICAgICAgICAgICAgICAoaCA9ICExKSwKICAgICAgICAgICAgICAoZnVuY3Rpb24gKHQpIHsKICAgICAgICAgICAgICAgIGlmIChuID09PSBjbGVhclRpbWVvdXQpIHJldHVybiBjbGVhclRpbWVvdXQodCkKICAgICAgICAgICAgICAgIGlmICgobiA9PT0gcyB8fCAhbikgJiYgY2xlYXJUaW1lb3V0KSByZXR1cm4gKG4gPSBjbGVhclRpbWVvdXQpLCBjbGVhclRpbWVvdXQodCkKICAgICAgICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgICAgICAgIG4odCk7CiAgICAgICAgICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG4uY2FsbChudWxsLCB0KQogICAgICAgICAgICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG4uY2FsbCh0aGlzLCB0KQogICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgfSkodCk7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGZ1bmN0aW9uIGcodCwgZSkgewogICh0aGlzLmZ1biA9IHQpLCAodGhpcy5hcnJheSA9IGUpOwogICAgICAgIH0KICAgICAgICBmdW5jdGlvbiBkKCkge30KICAoaS5uZXh0VGljayA9IGZ1bmN0aW9uICh0KSB7CiAgICAgICAgICB2YXIgZSA9IG5ldyBBcnJheShhcmd1bWVudHMubGVuZ3RoIC0gMSk7CiAgICAgICAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA+IDEpIGZvciAodmFyIHIgPSAxOyByIDwgYXJndW1lbnRzLmxlbmd0aDsgcisrKSBlW3IgLSAxXSA9IGFyZ3VtZW50c1tyXTsKICAgICAgICAgIGYucHVzaChuZXcgZyh0LCBlKSksIDEgIT09IGYubGVuZ3RoIHx8IGggfHwgdShwKTsKICAgICAgICB9KSwKICAgICAgICAgIChnLnByb3RvdHlwZS5ydW4gPSBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgIHRoaXMuZnVuLmFwcGx5KG51bGwsIHRoaXMuYXJyYXkpOwogICAgICAgICAgfSksCiAgICAgICAgICAoaS50aXRsZSA9ICdicm93c2VyJyksCiAgICAgICAgICAoaS5icm93c2VyID0gITApLAogICAgICAgICAgKGkuZW52ID0ge30pLAogICAgICAgICAgKGkuYXJndiA9IFtdKSwKICAgICAgICAgIChpLnZlcnNpb24gPSAnJyksCiAgICAgICAgICAoaS52ZXJzaW9ucyA9IHt9KSwKICAgICAgICAgIChpLm9uID0gZCksCiAgICAgICAgICAoaS5hZGRMaXN0ZW5lciA9IGQpLAogICAgICAgICAgKGkub25jZSA9IGQpLAogICAgICAgICAgKGkub2ZmID0gZCksCiAgICAgICAgICAoaS5yZW1vdmVMaXN0ZW5lciA9IGQpLAogICAgICAgICAgKGkucmVtb3ZlQWxsTGlzdGVuZXJzID0gZCksCiAgICAgICAgICAoaS5lbWl0ID0gZCksCiAgICAgICAgICAoaS5wcmVwZW5kTGlzdGVuZXIgPSBkKSwKICAgICAgICAgIChpLnByZXBlbmRPbmNlTGlzdGVuZXIgPSBkKSwKICAgICAgICAgIChpLmxpc3RlbmVycyA9IGZ1bmN0aW9uICh0KSB7CiAgICAgICAgICAgIHJldHVybiBbXQogICAgICAgICAgfSksCiAgICAgICAgICAoaS5iaW5kaW5nID0gZnVuY3Rpb24gKHQpIHsKICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdwcm9jZXNzLmJpbmRpbmcgaXMgbm90IHN1cHBvcnRlZCcpCiAgICAgICAgICB9KSwKICAgICAgICAgIChpLmN3ZCA9IGZ1bmN0aW9uICgpIHsKICAgICAgICAgICAgcmV0dXJuICcvJwogICAgICAgICAgfSksCiAgICAgICAgICAoaS5jaGRpciA9IGZ1bmN0aW9uICh0KSB7CiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcigncHJvY2Vzcy5jaGRpciBpcyBub3Qgc3VwcG9ydGVkJykKICAgICAgICAgIH0pLAogICAgICAgICAgKGkudW1hc2sgPSBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgIHJldHVybiAwCiAgICAgICAgICB9KTsKICAgICAgfSwKICAgIF0pCiAgfSk7CiAgLy8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgogIGNvbnN0IHVucGFja0JyaWRnZSA9IFdvcmtlclNjb3BlLnVucGFja0JyaWRnZTsKCiAgbGV0IHVucGFjazsKCiAgLy8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tdW5wYWNrLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KICB2YXIgaW5pdHVucGFjayA9IGZ1bmN0aW9uIChidWZmZXIpIHsKICAgIC8vIFRoZSBmb2xsb3dpbmcgY29kZSBoYXMgYmVlbiBfY2FyZWZ1bGx5XyBtb2RpZmllZCBieSBoYW5kLgogICAgLy8gRHVlIHRvIFdlYlBhY2sgZW1iZWRkaW5nIHRoaXMgc2NyaXB0IGludG8gdGhlIFplYSBlbmdpbmUKICAgIC8vIGJ1aWxkLCBjZXJ0YWluIGZlYXR1cmVzIGJyb2tlLgogICAgLy8gVGhlcmUgd2FzIGNvZGUgdG8gaGFuZGxlIGxvYWRpbmcgaW4gYSBub2RlSlMgY29udGV4dCwgdGhhdCB0cmllZCB0byBpbXBvcnQoImZzIikKICAgIC8vIFdlYlBhY2sga2VwdHMgdHJpcHBpbmcgdXAgb24gdGhhdCBjb2RlIGluIGl0cyBzdGF0aWMgYW5hbHlzaXMgb2YgdGhlIGNvZGUsIHNvCiAgICAvLyBJIGNhcmVmdWxseSByZW1vdmVkIGl0LgogICAgLy8gVGhlIGdsb2JhbCBzY29wZSBvZiB0aGUgc2NyaXB0IHNlZW1zIHRvIGJlIGRpZmZlcmVudCwgc28gdW5wYWNrQnJpZGdlIHdhcyBub3QgYXZhaWxhYmxlLgogICAgLy8gVGhlIHVucGFja0JyaWRnZSBjb2RlIGFzc2lnbnMgdW5wYWNrQnJpZGdlIHRvIHRoZSBwYXNzZWQgaW4gc2NvcGUsIHdoaWNoIGlzICd0aGlzJywgYnV0IHRoYXQKICAgIC8vIHNjb3BlIGlzbid0IGF2YWlsYWJsZSBpbnNpZGUgdGhpcyAndW5wYWNrJyBmdW5jdGlvbi4KICAgIGNvbnN0IHVucGFjayA9IE1vZHVsZTsKCiAgICAvLyBOb3RlOiB0aGUgZm9sbG93aW5nIGlzIHRoZSBVUkwgb2YgdGhlIHVucGFjay53YXNtIGZpbGUgaW4gb3VyIFplYUVuZ2luZSBwcm9qZWN0IG9uIG91cgogICAgLy8gc2VydmVyLiBJZGVhbGx5IHdlIGNvdWxkIHVzZSBhIHJlbGF0aXZlIHBhdGggZnJvbSB0aGUgWmVhRW5naW5lIGZpbGUsIGJ1dAogICAgLy8gdGhhdCBpc24ndCBwb3NzaWJsZSB5ZXQuIChUT0RPOiBBc2sgTWF1cm8gYWJvdXQgdGhpcykKICAgIGNvbnN0IGNyZWRlbnRpYWxzID0gJ29taXQnOwoKICAgIHZhciBFeHQgPSB1bnBhY2tCcmlkZ2UuRXh0OwogICAgdmFyIGpzQVBJID0gewogICAgICBvcGVuOiBmdW5jdGlvbiAoKSB7CiAgICAgICAgcmV0dXJuIEV4dC5jdXJyZW50Lm9wZW4uYXBwbHkoRXh0LmN1cnJlbnQsIGFyZ3VtZW50cykKICAgICAgfSwKICAgICAgY2xvc2U6IGZ1bmN0aW9uICgpIHsKICAgICAgICByZXR1cm4gRXh0LmN1cnJlbnQuY2xvc2UuYXBwbHkoRXh0LmN1cnJlbnQsIGFyZ3VtZW50cykKICAgICAgfSwKICAgICAgcmVhZDogZnVuY3Rpb24gKCkgewogICAgICAgIHJldHVybiBFeHQuY3VycmVudC5yZWFkLmFwcGx5KEV4dC5jdXJyZW50LCBhcmd1bWVudHMpCiAgICAgIH0sCiAgICAgIHdyaXRlOiBmdW5jdGlvbiAoKSB7CiAgICAgICAgcmV0dXJuIEV4dC5jdXJyZW50LndyaXRlLmFwcGx5KEV4dC5jdXJyZW50LCBhcmd1bWVudHMpCiAgICAgIH0sCiAgICAgIHRlbGw6IGZ1bmN0aW9uICgpIHsKICAgICAgICByZXR1cm4gRXh0LmN1cnJlbnQudGVsbC5hcHBseShFeHQuY3VycmVudCwgYXJndW1lbnRzKQogICAgICB9LAogICAgICBzZWVrOiBmdW5jdGlvbiAoKSB7CiAgICAgICAgcmV0dXJuIEV4dC5jdXJyZW50LnNlZWsuYXBwbHkoRXh0LmN1cnJlbnQsIGFyZ3VtZW50cykKICAgICAgfSwKICAgICAgY3JlYXRlOiBmdW5jdGlvbiAoKSB7CiAgICAgICAgcmV0dXJuIEV4dC5jdXJyZW50LmNyZWF0ZS5hcHBseShFeHQuY3VycmVudCwgYXJndW1lbnRzKQogICAgICB9LAogICAgfTsKICAgIHZhciBtb2R1bGVPdmVycmlkZXMgPSB7fTsKICAgIHZhciBrZXk7CiAgICBmb3IgKGtleSBpbiBNb2R1bGUpIHsKICAgICAgaWYgKE1vZHVsZS5oYXNPd25Qcm9wZXJ0eShrZXkpKSB7CiAgICAgICAgbW9kdWxlT3ZlcnJpZGVzW2tleV0gPSBNb2R1bGVba2V5XTsKICAgICAgfQogICAgfQogICAgTW9kdWxlWyd3YXNtQmluYXJ5J10gPSBidWZmZXI7CiAgICBNb2R1bGVbJ2FyZ3VtZW50cyddID0gW107CiAgICBNb2R1bGVbJ3RoaXNQcm9ncmFtJ10gPSAnLi90aGlzLnByb2dyYW0nOwogICAgTW9kdWxlWydxdWl0J10gPSBmdW5jdGlvbiAoc3RhdHVzLCB0b1Rocm93KSB7CiAgICAgIHRocm93IHRvVGhyb3cKICAgIH07CiAgICBNb2R1bGVbJ3ByZVJ1biddID0gW107CiAgICBNb2R1bGVbJ3Bvc3RSdW4nXSA9IFtdOwogICAgdmFyIEVOVklST05NRU5UX0lTX1dFQiA9IGZhbHNlOwogICAgdmFyIEVOVklST05NRU5UX0lTX1dPUktFUiA9IGZhbHNlOwogICAgdmFyIEVOVklST05NRU5UX0lTX05PREUgPSBmYWxzZTsKICAgIGlmIChNb2R1bGVbJ0VOVklST05NRU5UJ10pIHsKICAgICAgaWYgKE1vZHVsZVsnRU5WSVJPTk1FTlQnXSA9PT0gJ1dFQicpIHsKICAgICAgICBFTlZJUk9OTUVOVF9JU19XRUIgPSB0cnVlOwogICAgICB9IGVsc2UgaWYgKE1vZHVsZVsnRU5WSVJPTk1FTlQnXSA9PT0gJ1dPUktFUicpIHsKICAgICAgICBFTlZJUk9OTUVOVF9JU19XT1JLRVIgPSB0cnVlOwogICAgICB9IGVsc2UgaWYgKE1vZHVsZVsnRU5WSVJPTk1FTlQnXSA9PT0gJ05PREUnKSB7CiAgICAgICAgRU5WSVJPTk1FTlRfSVNfTk9ERSA9IHRydWU7CiAgICAgIH0gZWxzZSBpZiAoTW9kdWxlWydFTlZJUk9OTUVOVCddID09PSAnU0hFTEwnKSA7IGVsc2UgewogICAgICAgIHRocm93IG5ldyBFcnJvcigiTW9kdWxlWydFTlZJUk9OTUVOVCddIHZhbHVlIGlzIG5vdCB2YWxpZC4gbXVzdCBiZSBvbmUgb2Y6IFdFQnxXT1JLRVJ8Tk9ERXxTSEVMTC4iKQogICAgICB9CiAgICB9IGVsc2UgewogICAgICBFTlZJUk9OTUVOVF9JU19XRUIgPSB0eXBlb2Ygd2luZG93ID09PSAnb2JqZWN0JzsKICAgICAgRU5WSVJPTk1FTlRfSVNfV09SS0VSID0gdHlwZW9mIGltcG9ydFNjcmlwdHMgPT09ICdmdW5jdGlvbic7CiAgICAgIEVOVklST05NRU5UX0lTX05PREUgPQogICAgICAgIHR5cGVvZiBwcm9jZXNzID09PSAnb2JqZWN0JyAmJiB0eXBlb2YgcmVxdWlyZSA9PT0gJ2Z1bmN0aW9uJyAmJiAhRU5WSVJPTk1FTlRfSVNfV0VCICYmICFFTlZJUk9OTUVOVF9JU19XT1JLRVI7CiAgICB9CiAgICBpZiAoRU5WSVJPTk1FTlRfSVNfV0VCIHx8IEVOVklST05NRU5UX0lTX1dPUktFUikgewogICAgICBNb2R1bGVbJ3JlYWQnXSA9IGZ1bmN0aW9uIHNoZWxsX3JlYWQodXJsKSB7CiAgICAgICAgdmFyIHhociA9IG5ldyBYTUxIdHRwUmVxdWVzdCgpOwogICAgICAgIHhoci5vcGVuKCdHRVQnLCB1cmwsIGZhbHNlKTsKICAgICAgICB4aHIuc2VuZChudWxsKTsKICAgICAgICByZXR1cm4geGhyLnJlc3BvbnNlVGV4dAogICAgICB9OwogICAgICBpZiAoRU5WSVJPTk1FTlRfSVNfV09SS0VSKSB7CiAgICAgICAgTW9kdWxlWydyZWFkQmluYXJ5J10gPSBmdW5jdGlvbiByZWFkQmluYXJ5KHVybCkgewogICAgICAgICAgdmFyIHhociA9IG5ldyBYTUxIdHRwUmVxdWVzdCgpOwogICAgICAgICAgeGhyLm9wZW4oJ0dFVCcsIHVybCwgZmFsc2UpOwogICAgICAgICAgeGhyLnJlc3BvbnNlVHlwZSA9ICdhcnJheWJ1ZmZlcic7CiAgICAgICAgICB4aHIuc2VuZChudWxsKTsKICAgICAgICAgIHJldHVybiBuZXcgVWludDhBcnJheSh4aHIucmVzcG9uc2UpCiAgICAgICAgfTsKICAgICAgfQogICAgICBNb2R1bGVbJ3JlYWRBc3luYyddID0gZnVuY3Rpb24gcmVhZEFzeW5jKHVybCwgb25sb2FkLCBvbmVycm9yKSB7CiAgICAgICAgdmFyIHhociA9IG5ldyBYTUxIdHRwUmVxdWVzdCgpOwogICAgICAgIHhoci5vcGVuKCdHRVQnLCB1cmwsIHRydWUpOwogICAgICAgIHhoci5yZXNwb25zZVR5cGUgPSAnYXJyYXlidWZmZXInOwogICAgICAgIHhoci5vbmxvYWQgPSBmdW5jdGlvbiB4aHJfb25sb2FkKCkgewogICAgICAgICAgaWYgKHhoci5zdGF0dXMgPT0gMjAwIHx8ICh4aHIuc3RhdHVzID09IDAgJiYgeGhyLnJlc3BvbnNlKSkgewogICAgICAgICAgICBvbmxvYWQoeGhyLnJlc3BvbnNlKTsKICAgICAgICAgICAgcmV0dXJuCiAgICAgICAgICB9CiAgICAgICAgICBvbmVycm9yKCk7CiAgICAgICAgfTsKICAgICAgICB4aHIub25lcnJvciA9IG9uZXJyb3I7CiAgICAgICAgeGhyLnNlbmQobnVsbCk7CiAgICAgIH07CiAgICAgIE1vZHVsZVsnc2V0V2luZG93VGl0bGUnXSA9IGZ1bmN0aW9uICh0aXRsZSkgewogICAgICAgIGRvY3VtZW50LnRpdGxlID0gdGl0bGU7CiAgICAgIH07CiAgICB9CiAgICBNb2R1bGVbJ3ByaW50J10gPQogICAgICB0eXBlb2YgY29uc29sZSAhPT0gJ3VuZGVmaW5lZCcgPyBjb25zb2xlLmxvZy5iaW5kKGNvbnNvbGUpIDogdHlwZW9mIHByaW50ICE9PSAndW5kZWZpbmVkJyA/IHByaW50IDogbnVsbDsKICAgIE1vZHVsZVsncHJpbnRFcnInXSA9CiAgICAgIHR5cGVvZiBwcmludEVyciAhPT0gJ3VuZGVmaW5lZCcKICAgICAgICA/IHByaW50RXJyCiAgICAgICAgOiAodHlwZW9mIGNvbnNvbGUgIT09ICd1bmRlZmluZWQnICYmIGNvbnNvbGUud2Fybi5iaW5kKGNvbnNvbGUpKSB8fCBNb2R1bGVbJ3ByaW50J107CiAgICBNb2R1bGUucHJpbnQgPSBNb2R1bGVbJ3ByaW50J107CiAgICBNb2R1bGUucHJpbnRFcnIgPSBNb2R1bGVbJ3ByaW50RXJyJ107CiAgICBmb3IgKGtleSBpbiBtb2R1bGVPdmVycmlkZXMpIHsKICAgICAgaWYgKG1vZHVsZU92ZXJyaWRlcy5oYXNPd25Qcm9wZXJ0eShrZXkpKSB7CiAgICAgICAgTW9kdWxlW2tleV0gPSBtb2R1bGVPdmVycmlkZXNba2V5XTsKICAgICAgfQogICAgfQogICAgbW9kdWxlT3ZlcnJpZGVzID0gdW5kZWZpbmVkOwogICAgdmFyIFNUQUNLX0FMSUdOID0gMTY7CiAgICBmdW5jdGlvbiBzdGF0aWNBbGxvYyhzaXplKSB7CiAgICAgIGFzc2VydCghc3RhdGljU2VhbGVkKTsKICAgICAgdmFyIHJldCA9IFNUQVRJQ1RPUDsKICAgICAgU1RBVElDVE9QID0gKFNUQVRJQ1RPUCArIHNpemUgKyAxNSkgJiAtMTY7CiAgICAgIHJldHVybiByZXQKICAgIH0KICAgIGZ1bmN0aW9uIGR5bmFtaWNBbGxvYyhzaXplKSB7CiAgICAgIGFzc2VydChEWU5BTUlDVE9QX1BUUik7CiAgICAgIHZhciByZXQgPSBIRUFQMzJbRFlOQU1JQ1RPUF9QVFIgPj4gMl07CiAgICAgIHZhciBlbmQgPSAocmV0ICsgc2l6ZSArIDE1KSAmIC0xNjsKICAgICAgSEVBUDMyW0RZTkFNSUNUT1BfUFRSID4+IDJdID0gZW5kOwogICAgICBpZiAoZW5kID49IFRPVEFMX01FTU9SWSkgewogICAgICAgIHZhciBzdWNjZXNzID0gZW5sYXJnZU1lbW9yeSgpOwogICAgICAgIGlmICghc3VjY2VzcykgewogICAgICAgICAgSEVBUDMyW0RZTkFNSUNUT1BfUFRSID4+IDJdID0gcmV0OwogICAgICAgICAgcmV0dXJuIDAKICAgICAgICB9CiAgICAgIH0KICAgICAgcmV0dXJuIHJldAogICAgfQogICAgZnVuY3Rpb24gYWxpZ25NZW1vcnkoc2l6ZSwgZmFjdG9yKSB7CiAgICAgIGlmICghZmFjdG9yKSBmYWN0b3IgPSBTVEFDS19BTElHTjsKICAgICAgdmFyIHJldCA9IChzaXplID0gTWF0aC5jZWlsKHNpemUgLyBmYWN0b3IpICogZmFjdG9yKTsKICAgICAgcmV0dXJuIHJldAogICAgfQogICAgZnVuY3Rpb24gZ2V0TmF0aXZlVHlwZVNpemUodHlwZSkgewogICAgICBzd2l0Y2ggKHR5cGUpIHsKICAgICAgICBjYXNlICdpMSc6CiAgICAgICAgY2FzZSAnaTgnOgogICAgICAgICAgcmV0dXJuIDEKICAgICAgICBjYXNlICdpMTYnOgogICAgICAgICAgcmV0dXJuIDIKICAgICAgICBjYXNlICdpMzInOgogICAgICAgICAgcmV0dXJuIDQKICAgICAgICBjYXNlICdpNjQnOgogICAgICAgICAgcmV0dXJuIDgKICAgICAgICBjYXNlICdmbG9hdCc6CiAgICAgICAgICByZXR1cm4gNAogICAgICAgIGNhc2UgJ2RvdWJsZSc6CiAgICAgICAgICByZXR1cm4gOAogICAgICAgIGRlZmF1bHQ6IHsKICAgICAgICAgIGlmICh0eXBlW3R5cGUubGVuZ3RoIC0gMV0gPT09ICcqJykgewogICAgICAgICAgICByZXR1cm4gNAogICAgICAgICAgfSBlbHNlIGlmICh0eXBlWzBdID09PSAnaScpIHsKICAgICAgICAgICAgdmFyIGJpdHMgPSBwYXJzZUludCh0eXBlLnN1YnN0cigxKSk7CiAgICAgICAgICAgIGFzc2VydChiaXRzICUgOCA9PT0gMCk7CiAgICAgICAgICAgIHJldHVybiBiaXRzIC8gOAogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgcmV0dXJuIDAKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0KICAgIH0KICAgIG5ldyBBcnJheSgwKTsKICAgIHZhciBHTE9CQUxfQkFTRSA9IDEwMjQ7CiAgICB2YXIgQUJPUlQgPSAwOwogICAgZnVuY3Rpb24gYXNzZXJ0KGNvbmRpdGlvbiwgdGV4dCkgewogICAgICBpZiAoIWNvbmRpdGlvbikgewogICAgICAgIGFib3J0KCdBc3NlcnRpb24gZmFpbGVkOiAnICsgdGV4dCk7CiAgICAgIH0KICAgIH0KICAgIGZ1bmN0aW9uIHNldFZhbHVlKHB0ciwgdmFsdWUsIHR5cGUsIG5vU2FmZSkgewogICAgICB0eXBlID0gdHlwZSB8fCAnaTgnOwogICAgICBpZiAodHlwZS5jaGFyQXQodHlwZS5sZW5ndGggLSAxKSA9PT0gJyonKSB0eXBlID0gJ2kzMic7CiAgICAgIHN3aXRjaCAodHlwZSkgewogICAgICAgIGNhc2UgJ2kxJzoKICAgICAgICAgIEhFQVA4W3B0ciA+PiAwXSA9IHZhbHVlOwogICAgICAgICAgYnJlYWsKICAgICAgICBjYXNlICdpOCc6CiAgICAgICAgICBIRUFQOFtwdHIgPj4gMF0gPSB2YWx1ZTsKICAgICAgICAgIGJyZWFrCiAgICAgICAgY2FzZSAnaTE2JzoKICAgICAgICAgIEhFQVAxNltwdHIgPj4gMV0gPSB2YWx1ZTsKICAgICAgICAgIGJyZWFrCiAgICAgICAgY2FzZSAnaTMyJzoKICAgICAgICAgIEhFQVAzMltwdHIgPj4gMl0gPSB2YWx1ZTsKICAgICAgICAgIGJyZWFrCiAgICAgICAgY2FzZSAnaTY0JzoKICAodGVtcEk2NCA9IFsKICAgICAgICAgICAgdmFsdWUgPj4+IDAsCiAgICAgICAgICAgICgodGVtcERvdWJsZSA9IHZhbHVlKSwKICAgICAgICAgICAgK01hdGhfYWJzKHRlbXBEb3VibGUpID49IDEKICAgICAgICAgICAgICA/IHRlbXBEb3VibGUgPiAwCiAgICAgICAgICAgICAgICA/IChNYXRoX21pbigrTWF0aF9mbG9vcih0ZW1wRG91YmxlIC8gNDI5NDk2NzI5NiksIDQyOTQ5NjcyOTUpIHwgMCkgPj4+IDAKICAgICAgICAgICAgICAgIDogfn4rTWF0aF9jZWlsKCh0ZW1wRG91YmxlIC0gKyh+fnRlbXBEb3VibGUgPj4+IDApKSAvIDQyOTQ5NjcyOTYpID4+PiAwCiAgICAgICAgICAgICAgOiAwKSwKICAgICAgICAgIF0pLAogICAgICAgICAgICAoSEVBUDMyW3B0ciA+PiAyXSA9IHRlbXBJNjRbMF0pLAogICAgICAgICAgICAoSEVBUDMyWyhwdHIgKyA0KSA+PiAyXSA9IHRlbXBJNjRbMV0pOwogICAgICAgICAgYnJlYWsKICAgICAgICBjYXNlICdmbG9hdCc6CiAgICAgICAgICBIRUFQRjMyW3B0ciA+PiAyXSA9IHZhbHVlOwogICAgICAgICAgYnJlYWsKICAgICAgICBjYXNlICdkb3VibGUnOgogICAgICAgICAgSEVBUEY2NFtwdHIgPj4gM10gPSB2YWx1ZTsKICAgICAgICAgIGJyZWFrCiAgICAgICAgZGVmYXVsdDoKICAgICAgICAgIGFib3J0KCdpbnZhbGlkIHR5cGUgZm9yIHNldFZhbHVlOiAnICsgdHlwZSk7CiAgICAgIH0KICAgIH0KICAgIHZhciBBTExPQ19OT1JNQUwgPSAwOwogICAgdmFyIEFMTE9DX1NUQVRJQyA9IDI7CiAgICB2YXIgQUxMT0NfTk9ORSA9IDQ7CiAgICBmdW5jdGlvbiBhbGxvY2F0ZShzbGFiLCB0eXBlcywgYWxsb2NhdG9yLCBwdHIpIHsKICAgICAgdmFyIHplcm9pbml0LCBzaXplOwogICAgICBpZiAodHlwZW9mIHNsYWIgPT09ICdudW1iZXInKSB7CiAgICAgICAgemVyb2luaXQgPSB0cnVlOwogICAgICAgIHNpemUgPSBzbGFiOwogICAgICB9IGVsc2UgewogICAgICAgIHplcm9pbml0ID0gZmFsc2U7CiAgICAgICAgc2l6ZSA9IHNsYWIubGVuZ3RoOwogICAgICB9CiAgICAgIHZhciBzaW5nbGVUeXBlID0gdHlwZW9mIHR5cGVzID09PSAnc3RyaW5nJyA/IHR5cGVzIDogbnVsbDsKICAgICAgdmFyIHJldDsKICAgICAgaWYgKGFsbG9jYXRvciA9PSBBTExPQ19OT05FKSB7CiAgICAgICAgcmV0ID0gcHRyOwogICAgICB9IGVsc2UgewogICAgICAgIHJldCA9IFt0eXBlb2YgX21hbGxvYyA9PT0gJ2Z1bmN0aW9uJyA/IF9tYWxsb2MgOiBzdGF0aWNBbGxvYywgc3RhY2tBbGxvYywgc3RhdGljQWxsb2MsIGR5bmFtaWNBbGxvY11bCiAgICAgICAgICBhbGxvY2F0b3IgPT09IHVuZGVmaW5lZCA/IEFMTE9DX1NUQVRJQyA6IGFsbG9jYXRvcgogICAgICAgIF0oTWF0aC5tYXgoc2l6ZSwgc2luZ2xlVHlwZSA/IDEgOiB0eXBlcy5sZW5ndGgpKTsKICAgICAgfQogICAgICBpZiAoemVyb2luaXQpIHsKICAgICAgICB2YXIgc3RvcDsKICAgICAgICBwdHIgPSByZXQ7CiAgICAgICAgYXNzZXJ0KChyZXQgJiAzKSA9PSAwKTsKICAgICAgICBzdG9wID0gcmV0ICsgKHNpemUgJiB+Myk7CiAgICAgICAgZm9yICg7IHB0ciA8IHN0b3A7IHB0ciArPSA0KSB7CiAgICAgICAgICBIRUFQMzJbcHRyID4+IDJdID0gMDsKICAgICAgICB9CiAgICAgICAgc3RvcCA9IHJldCArIHNpemU7CiAgICAgICAgd2hpbGUgKHB0ciA8IHN0b3ApIHsKICAgICAgICAgIEhFQVA4W3B0cisrID4+IDBdID0gMDsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHJldAogICAgICB9CiAgICAgIGlmIChzaW5nbGVUeXBlID09PSAnaTgnKSB7CiAgICAgICAgaWYgKHNsYWIuc3ViYXJyYXkgfHwgc2xhYi5zbGljZSkgewogICAgICAgICAgSEVBUFU4LnNldChzbGFiLCByZXQpOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBIRUFQVTguc2V0KG5ldyBVaW50OEFycmF5KHNsYWIpLCByZXQpOwogICAgICAgIH0KICAgICAgICByZXR1cm4gcmV0CiAgICAgIH0KICAgICAgdmFyIGkgPSAwLAogICAgICAgIHR5cGUsCiAgICAgICAgdHlwZVNpemUsCiAgICAgICAgcHJldmlvdXNUeXBlOwogICAgICB3aGlsZSAoaSA8IHNpemUpIHsKICAgICAgICB2YXIgY3VyciA9IHNsYWJbaV07CiAgICAgICAgdHlwZSA9IHNpbmdsZVR5cGUgfHwgdHlwZXNbaV07CiAgICAgICAgaWYgKHR5cGUgPT09IDApIHsKICAgICAgICAgIGkrKzsKICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgfQogICAgICAgIGlmICh0eXBlID09ICdpNjQnKSB0eXBlID0gJ2kzMic7CiAgICAgICAgc2V0VmFsdWUocmV0ICsgaSwgY3VyciwgdHlwZSk7CiAgICAgICAgaWYgKHByZXZpb3VzVHlwZSAhPT0gdHlwZSkgewogICAgICAgICAgdHlwZVNpemUgPSBnZXROYXRpdmVUeXBlU2l6ZSh0eXBlKTsKICAgICAgICAgIHByZXZpb3VzVHlwZSA9IHR5cGU7CiAgICAgICAgfQogICAgICAgIGkgKz0gdHlwZVNpemU7CiAgICAgIH0KICAgICAgcmV0dXJuIHJldAogICAgfQogICAgZnVuY3Rpb24gUG9pbnRlcl9zdHJpbmdpZnkocHRyLCBsZW5ndGgpIHsKICAgICAgaWYgKGxlbmd0aCA9PT0gMCB8fCAhcHRyKSByZXR1cm4gJycKICAgICAgdmFyIGhhc1V0ZiA9IDA7CiAgICAgIHZhciB0OwogICAgICB2YXIgaSA9IDA7CiAgICAgIHdoaWxlICgxKSB7CiAgICAgICAgdCA9IEhFQVBVOFsocHRyICsgaSkgPj4gMF07CiAgICAgICAgaGFzVXRmIHw9IHQ7CiAgICAgICAgaWYgKHQgPT0gMCAmJiAhbGVuZ3RoKSBicmVhawogICAgICAgIGkrKzsKICAgICAgICBpZiAobGVuZ3RoICYmIGkgPT0gbGVuZ3RoKSBicmVhawogICAgICB9CiAgICAgIGlmICghbGVuZ3RoKSBsZW5ndGggPSBpOwogICAgICB2YXIgcmV0ID0gJyc7CiAgICAgIGlmIChoYXNVdGYgPCAxMjgpIHsKICAgICAgICB2YXIgTUFYX0NIVU5LID0gMTAyNDsKICAgICAgICB2YXIgY3VycjsKICAgICAgICB3aGlsZSAobGVuZ3RoID4gMCkgewogICAgICAgICAgY3VyciA9IFN0cmluZy5mcm9tQ2hhckNvZGUuYXBwbHkoU3RyaW5nLCBIRUFQVTguc3ViYXJyYXkocHRyLCBwdHIgKyBNYXRoLm1pbihsZW5ndGgsIE1BWF9DSFVOSykpKTsKICAgICAgICAgIHJldCA9IHJldCA/IHJldCArIGN1cnIgOiBjdXJyOwogICAgICAgICAgcHRyICs9IE1BWF9DSFVOSzsKICAgICAgICAgIGxlbmd0aCAtPSBNQVhfQ0hVTks7CiAgICAgICAgfQogICAgICAgIHJldHVybiByZXQKICAgICAgfQogICAgICByZXR1cm4gVVRGOFRvU3RyaW5nKHB0cikKICAgIH0KICAgIHZhciBVVEY4RGVjb2RlciA9IHR5cGVvZiBUZXh0RGVjb2RlciAhPT0gJ3VuZGVmaW5lZCcgPyBuZXcgVGV4dERlY29kZXIoJ3V0ZjgnKSA6IHVuZGVmaW5lZDsKICAgIGZ1bmN0aW9uIFVURjhBcnJheVRvU3RyaW5nKHU4QXJyYXksIGlkeCkgewogICAgICB2YXIgZW5kUHRyID0gaWR4OwogICAgICB3aGlsZSAodThBcnJheVtlbmRQdHJdKSArK2VuZFB0cjsKICAgICAgaWYgKGVuZFB0ciAtIGlkeCA+IDE2ICYmIHU4QXJyYXkuc3ViYXJyYXkgJiYgVVRGOERlY29kZXIpIHsKICAgICAgICByZXR1cm4gVVRGOERlY29kZXIuZGVjb2RlKHU4QXJyYXkuc3ViYXJyYXkoaWR4LCBlbmRQdHIpKQogICAgICB9IGVsc2UgewogICAgICAgIHZhciB1MCwgdTEsIHUyLCB1MywgdTQsIHU1OwogICAgICAgIHZhciBzdHIgPSAnJzsKICAgICAgICB3aGlsZSAoMSkgewogICAgICAgICAgdTAgPSB1OEFycmF5W2lkeCsrXTsKICAgICAgICAgIGlmICghdTApIHJldHVybiBzdHIKICAgICAgICAgIGlmICghKHUwICYgMTI4KSkgewogICAgICAgICAgICBzdHIgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSh1MCk7CiAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgICB9CiAgICAgICAgICB1MSA9IHU4QXJyYXlbaWR4KytdICYgNjM7CiAgICAgICAgICBpZiAoKHUwICYgMjI0KSA9PSAxOTIpIHsKICAgICAgICAgICAgc3RyICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoKCh1MCAmIDMxKSA8PCA2KSB8IHUxKTsKICAgICAgICAgICAgY29udGludWUKICAgICAgICAgIH0KICAgICAgICAgIHUyID0gdThBcnJheVtpZHgrK10gJiA2MzsKICAgICAgICAgIGlmICgodTAgJiAyNDApID09IDIyNCkgewogICAgICAgICAgICB1MCA9ICgodTAgJiAxNSkgPDwgMTIpIHwgKHUxIDw8IDYpIHwgdTI7CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICB1MyA9IHU4QXJyYXlbaWR4KytdICYgNjM7CiAgICAgICAgICAgIGlmICgodTAgJiAyNDgpID09IDI0MCkgewogICAgICAgICAgICAgIHUwID0gKCh1MCAmIDcpIDw8IDE4KSB8ICh1MSA8PCAxMikgfCAodTIgPDwgNikgfCB1MzsKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICB1NCA9IHU4QXJyYXlbaWR4KytdICYgNjM7CiAgICAgICAgICAgICAgaWYgKCh1MCAmIDI1MikgPT0gMjQ4KSB7CiAgICAgICAgICAgICAgICB1MCA9ICgodTAgJiAzKSA8PCAyNCkgfCAodTEgPDwgMTgpIHwgKHUyIDw8IDEyKSB8ICh1MyA8PCA2KSB8IHU0OwogICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICB1NSA9IHU4QXJyYXlbaWR4KytdICYgNjM7CiAgICAgICAgICAgICAgICB1MCA9ICgodTAgJiAxKSA8PCAzMCkgfCAodTEgPDwgMjQpIHwgKHUyIDw8IDE4KSB8ICh1MyA8PCAxMikgfCAodTQgPDwgNikgfCB1NTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIGlmICh1MCA8IDY1NTM2KSB7CiAgICAgICAgICAgIHN0ciArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKHUwKTsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHZhciBjaCA9IHUwIC0gNjU1MzY7CiAgICAgICAgICAgIHN0ciArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKDU1Mjk2IHwgKGNoID4+IDEwKSwgNTYzMjAgfCAoY2ggJiAxMDIzKSk7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgICBmdW5jdGlvbiBVVEY4VG9TdHJpbmcocHRyKSB7CiAgICAgIHJldHVybiBVVEY4QXJyYXlUb1N0cmluZyhIRUFQVTgsIHB0cikKICAgIH0KICAgIGZ1bmN0aW9uIHN0cmluZ1RvVVRGOEFycmF5KHN0ciwgb3V0VThBcnJheSwgb3V0SWR4LCBtYXhCeXRlc1RvV3JpdGUpIHsKICAgICAgaWYgKCEobWF4Qnl0ZXNUb1dyaXRlID4gMCkpIHJldHVybiAwCiAgICAgIHZhciBzdGFydElkeCA9IG91dElkeDsKICAgICAgdmFyIGVuZElkeCA9IG91dElkeCArIG1heEJ5dGVzVG9Xcml0ZSAtIDE7CiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgc3RyLmxlbmd0aDsgKytpKSB7CiAgICAgICAgdmFyIHUgPSBzdHIuY2hhckNvZGVBdChpKTsKICAgICAgICBpZiAodSA+PSA1NTI5NiAmJiB1IDw9IDU3MzQzKSB1ID0gKDY1NTM2ICsgKCh1ICYgMTAyMykgPDwgMTApKSB8IChzdHIuY2hhckNvZGVBdCgrK2kpICYgMTAyMyk7CiAgICAgICAgaWYgKHUgPD0gMTI3KSB7CiAgICAgICAgICBpZiAob3V0SWR4ID49IGVuZElkeCkgYnJlYWsKICAgICAgICAgIG91dFU4QXJyYXlbb3V0SWR4KytdID0gdTsKICAgICAgICB9IGVsc2UgaWYgKHUgPD0gMjA0NykgewogICAgICAgICAgaWYgKG91dElkeCArIDEgPj0gZW5kSWR4KSBicmVhawogICAgICAgICAgb3V0VThBcnJheVtvdXRJZHgrK10gPSAxOTIgfCAodSA+PiA2KTsKICAgICAgICAgIG91dFU4QXJyYXlbb3V0SWR4KytdID0gMTI4IHwgKHUgJiA2Myk7CiAgICAgICAgfSBlbHNlIGlmICh1IDw9IDY1NTM1KSB7CiAgICAgICAgICBpZiAob3V0SWR4ICsgMiA+PSBlbmRJZHgpIGJyZWFrCiAgICAgICAgICBvdXRVOEFycmF5W291dElkeCsrXSA9IDIyNCB8ICh1ID4+IDEyKTsKICAgICAgICAgIG91dFU4QXJyYXlbb3V0SWR4KytdID0gMTI4IHwgKCh1ID4+IDYpICYgNjMpOwogICAgICAgICAgb3V0VThBcnJheVtvdXRJZHgrK10gPSAxMjggfCAodSAmIDYzKTsKICAgICAgICB9IGVsc2UgaWYgKHUgPD0gMjA5NzE1MSkgewogICAgICAgICAgaWYgKG91dElkeCArIDMgPj0gZW5kSWR4KSBicmVhawogICAgICAgICAgb3V0VThBcnJheVtvdXRJZHgrK10gPSAyNDAgfCAodSA+PiAxOCk7CiAgICAgICAgICBvdXRVOEFycmF5W291dElkeCsrXSA9IDEyOCB8ICgodSA+PiAxMikgJiA2Myk7CiAgICAgICAgICBvdXRVOEFycmF5W291dElkeCsrXSA9IDEyOCB8ICgodSA+PiA2KSAmIDYzKTsKICAgICAgICAgIG91dFU4QXJyYXlbb3V0SWR4KytdID0gMTI4IHwgKHUgJiA2Myk7CiAgICAgICAgfSBlbHNlIGlmICh1IDw9IDY3MTA4ODYzKSB7CiAgICAgICAgICBpZiAob3V0SWR4ICsgNCA+PSBlbmRJZHgpIGJyZWFrCiAgICAgICAgICBvdXRVOEFycmF5W291dElkeCsrXSA9IDI0OCB8ICh1ID4+IDI0KTsKICAgICAgICAgIG91dFU4QXJyYXlbb3V0SWR4KytdID0gMTI4IHwgKCh1ID4+IDE4KSAmIDYzKTsKICAgICAgICAgIG91dFU4QXJyYXlbb3V0SWR4KytdID0gMTI4IHwgKCh1ID4+IDEyKSAmIDYzKTsKICAgICAgICAgIG91dFU4QXJyYXlbb3V0SWR4KytdID0gMTI4IHwgKCh1ID4+IDYpICYgNjMpOwogICAgICAgICAgb3V0VThBcnJheVtvdXRJZHgrK10gPSAxMjggfCAodSAmIDYzKTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgaWYgKG91dElkeCArIDUgPj0gZW5kSWR4KSBicmVhawogICAgICAgICAgb3V0VThBcnJheVtvdXRJZHgrK10gPSAyNTIgfCAodSA+PiAzMCk7CiAgICAgICAgICBvdXRVOEFycmF5W291dElkeCsrXSA9IDEyOCB8ICgodSA+PiAyNCkgJiA2Myk7CiAgICAgICAgICBvdXRVOEFycmF5W291dElkeCsrXSA9IDEyOCB8ICgodSA+PiAxOCkgJiA2Myk7CiAgICAgICAgICBvdXRVOEFycmF5W291dElkeCsrXSA9IDEyOCB8ICgodSA+PiAxMikgJiA2Myk7CiAgICAgICAgICBvdXRVOEFycmF5W291dElkeCsrXSA9IDEyOCB8ICgodSA+PiA2KSAmIDYzKTsKICAgICAgICAgIG91dFU4QXJyYXlbb3V0SWR4KytdID0gMTI4IHwgKHUgJiA2Myk7CiAgICAgICAgfQogICAgICB9CiAgICAgIG91dFU4QXJyYXlbb3V0SWR4XSA9IDA7CiAgICAgIHJldHVybiBvdXRJZHggLSBzdGFydElkeAogICAgfQogICAgZnVuY3Rpb24gc3RyaW5nVG9VVEY4KHN0ciwgb3V0UHRyLCBtYXhCeXRlc1RvV3JpdGUpIHsKICAgICAgcmV0dXJuIHN0cmluZ1RvVVRGOEFycmF5KHN0ciwgSEVBUFU4LCBvdXRQdHIsIG1heEJ5dGVzVG9Xcml0ZSkKICAgIH0KICAgIGZ1bmN0aW9uIGxlbmd0aEJ5dGVzVVRGOChzdHIpIHsKICAgICAgdmFyIGxlbiA9IDA7CiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgc3RyLmxlbmd0aDsgKytpKSB7CiAgICAgICAgdmFyIHUgPSBzdHIuY2hhckNvZGVBdChpKTsKICAgICAgICBpZiAodSA+PSA1NTI5NiAmJiB1IDw9IDU3MzQzKSB1ID0gKDY1NTM2ICsgKCh1ICYgMTAyMykgPDwgMTApKSB8IChzdHIuY2hhckNvZGVBdCgrK2kpICYgMTAyMyk7CiAgICAgICAgaWYgKHUgPD0gMTI3KSB7CiAgICAgICAgICArK2xlbjsKICAgICAgICB9IGVsc2UgaWYgKHUgPD0gMjA0NykgewogICAgICAgICAgbGVuICs9IDI7CiAgICAgICAgfSBlbHNlIGlmICh1IDw9IDY1NTM1KSB7CiAgICAgICAgICBsZW4gKz0gMzsKICAgICAgICB9IGVsc2UgaWYgKHUgPD0gMjA5NzE1MSkgewogICAgICAgICAgbGVuICs9IDQ7CiAgICAgICAgfSBlbHNlIGlmICh1IDw9IDY3MTA4ODYzKSB7CiAgICAgICAgICBsZW4gKz0gNTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgbGVuICs9IDY7CiAgICAgICAgfQogICAgICB9CiAgICAgIHJldHVybiBsZW4KICAgIH0KICAgIHR5cGVvZiBUZXh0RGVjb2RlciAhPT0gJ3VuZGVmaW5lZCcgPyBuZXcgVGV4dERlY29kZXIoJ3V0Zi0xNmxlJykgOiB1bmRlZmluZWQ7CiAgICBmdW5jdGlvbiBVVEYzMlRvU3RyaW5nKHB0cikgewogICAgICB2YXIgaSA9IDA7CiAgICAgIHZhciBzdHIgPSAnJzsKICAgICAgd2hpbGUgKDEpIHsKICAgICAgICB2YXIgdXRmMzIgPSBIRUFQMzJbKHB0ciArIGkgKiA0KSA+PiAyXTsKICAgICAgICBpZiAodXRmMzIgPT0gMCkgcmV0dXJuIHN0cgogICAgICAgICsraTsKICAgICAgICBpZiAodXRmMzIgPj0gNjU1MzYpIHsKICAgICAgICAgIHZhciBjaCA9IHV0ZjMyIC0gNjU1MzY7CiAgICAgICAgICBzdHIgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSg1NTI5NiB8IChjaCA+PiAxMCksIDU2MzIwIHwgKGNoICYgMTAyMykpOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBzdHIgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSh1dGYzMik7CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgICBmdW5jdGlvbiBhbGxvY2F0ZVVURjgoc3RyKSB7CiAgICAgIHZhciBzaXplID0gbGVuZ3RoQnl0ZXNVVEY4KHN0cikgKyAxOwogICAgICB2YXIgcmV0ID0gX21hbGxvYyhzaXplKTsKICAgICAgaWYgKHJldCkgc3RyaW5nVG9VVEY4QXJyYXkoc3RyLCBIRUFQOCwgcmV0LCBzaXplKTsKICAgICAgcmV0dXJuIHJldAogICAgfQogICAgZnVuY3Rpb24gZGVtYW5nbGUoZnVuYykgewogICAgICByZXR1cm4gZnVuYwogICAgfQogICAgZnVuY3Rpb24gZGVtYW5nbGVBbGwodGV4dCkgewogICAgICB2YXIgcmVnZXggPSAvX19aW1x3XGRfXSsvZzsKICAgICAgcmV0dXJuIHRleHQucmVwbGFjZShyZWdleCwgZnVuY3Rpb24gKHgpIHsKICAgICAgICB2YXIgeSA9IGRlbWFuZ2xlKHgpOwogICAgICAgIHJldHVybiB4ID09PSB5ID8geCA6IHggKyAnIFsnICsgeSArICddJwogICAgICB9KQogICAgfQogICAgZnVuY3Rpb24ganNTdGFja1RyYWNlKCkgewogICAgICB2YXIgZXJyID0gbmV3IEVycm9yKCk7CiAgICAgIGlmICghZXJyLnN0YWNrKSB7CiAgICAgICAgdHJ5IHsKICAgICAgICAgIHRocm93IG5ldyBFcnJvcigwKQogICAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICAgIGVyciA9IGU7CiAgICAgICAgfQogICAgICAgIGlmICghZXJyLnN0YWNrKSB7CiAgICAgICAgICByZXR1cm4gJyhubyBzdGFjayB0cmFjZSBhdmFpbGFibGUpJwogICAgICAgIH0KICAgICAgfQogICAgICByZXR1cm4gZXJyLnN0YWNrLnRvU3RyaW5nKCkKICAgIH0KICAgIGZ1bmN0aW9uIHN0YWNrVHJhY2UoKSB7CiAgICAgIHZhciBqcyA9IGpzU3RhY2tUcmFjZSgpOwogICAgICBpZiAoTW9kdWxlWydleHRyYVN0YWNrVHJhY2UnXSkganMgKz0gJ1xuJyArIE1vZHVsZVsnZXh0cmFTdGFja1RyYWNlJ10oKTsKICAgICAgcmV0dXJuIGRlbWFuZ2xlQWxsKGpzKQogICAgfQogICAgdmFyIFdBU01fUEFHRV9TSVpFID0gNjU1MzY7CiAgICB2YXIgQVNNSlNfUEFHRV9TSVpFID0gMTY3NzcyMTY7CiAgICB2YXIgTUlOX1RPVEFMX01FTU9SWSA9IDE2Nzc3MjE2OwogICAgZnVuY3Rpb24gYWxpZ25VcCh4LCBtdWx0aXBsZSkgewogICAgICBpZiAoeCAlIG11bHRpcGxlID4gMCkgewogICAgICAgIHggKz0gbXVsdGlwbGUgLSAoeCAlIG11bHRpcGxlKTsKICAgICAgfQogICAgICByZXR1cm4geAogICAgfQogICAgdmFyIGJ1ZmZlciwgSEVBUDgsIEhFQVBVOCwgSEVBUDE2LCBIRUFQVTE2LCBIRUFQMzIsIEhFQVBVMzIsIEhFQVBGMzIsIEhFQVBGNjQ7CiAgICBmdW5jdGlvbiB1cGRhdGVHbG9iYWxCdWZmZXIoYnVmKSB7CiAgICAgIE1vZHVsZVsnYnVmZmVyJ10gPSBidWZmZXIgPSBidWY7CiAgICB9CiAgICBmdW5jdGlvbiB1cGRhdGVHbG9iYWxCdWZmZXJWaWV3cygpIHsKICAgICAgTW9kdWxlWydIRUFQOCddID0gSEVBUDggPSBuZXcgSW50OEFycmF5KGJ1ZmZlcik7CiAgICAgIE1vZHVsZVsnSEVBUDE2J10gPSBIRUFQMTYgPSBuZXcgSW50MTZBcnJheShidWZmZXIpOwogICAgICBNb2R1bGVbJ0hFQVAzMiddID0gSEVBUDMyID0gbmV3IEludDMyQXJyYXkoYnVmZmVyKTsKICAgICAgTW9kdWxlWydIRUFQVTgnXSA9IEhFQVBVOCA9IG5ldyBVaW50OEFycmF5KGJ1ZmZlcik7CiAgICAgIE1vZHVsZVsnSEVBUFUxNiddID0gSEVBUFUxNiA9IG5ldyBVaW50MTZBcnJheShidWZmZXIpOwogICAgICBNb2R1bGVbJ0hFQVBVMzInXSA9IEhFQVBVMzIgPSBuZXcgVWludDMyQXJyYXkoYnVmZmVyKTsKICAgICAgTW9kdWxlWydIRUFQRjMyJ10gPSBIRUFQRjMyID0gbmV3IEZsb2F0MzJBcnJheShidWZmZXIpOwogICAgICBNb2R1bGVbJ0hFQVBGNjQnXSA9IEhFQVBGNjQgPSBuZXcgRmxvYXQ2NEFycmF5KGJ1ZmZlcik7CiAgICB9CiAgICB2YXIgU1RBVElDX0JBU0UsIFNUQVRJQ1RPUCwgc3RhdGljU2VhbGVkOwogICAgdmFyIFNUQUNLX0JBU0UsIFNUQUNLVE9QLCBTVEFDS19NQVg7CiAgICB2YXIgRFlOQU1JQ19CQVNFLCBEWU5BTUlDVE9QX1BUUjsKICAgIFNUQVRJQ19CQVNFID0gU1RBVElDVE9QID0gU1RBQ0tfQkFTRSA9IFNUQUNLVE9QID0gU1RBQ0tfTUFYID0gRFlOQU1JQ19CQVNFID0gRFlOQU1JQ1RPUF9QVFIgPSAwOwogICAgc3RhdGljU2VhbGVkID0gZmFsc2U7CiAgICBmdW5jdGlvbiBhYm9ydE9uQ2Fubm90R3Jvd01lbW9yeSgpIHsKICAgICAgYWJvcnQoCiAgICAgICAgJ0Nhbm5vdCBlbmxhcmdlIG1lbW9yeSBhcnJheXMuIEVpdGhlciAoMSkgY29tcGlsZSB3aXRoICAtcyBUT1RBTF9NRU1PUlk9WCAgd2l0aCBYIGhpZ2hlciB0aGFuIHRoZSBjdXJyZW50IHZhbHVlICcgKwogICAgICAgICAgVE9UQUxfTUVNT1JZICsKICAgICAgICAgICcsICgyKSBjb21waWxlIHdpdGggIC1zIEFMTE9XX01FTU9SWV9HUk9XVEg9MSAgd2hpY2ggYWxsb3dzIGluY3JlYXNpbmcgdGhlIHNpemUgYXQgcnVudGltZSwgb3IgKDMpIGlmIHlvdSB3YW50IG1hbGxvYyB0byByZXR1cm4gTlVMTCAoMCkgaW5zdGVhZCBvZiB0aGlzIGFib3J0LCBjb21waWxlIHdpdGggIC1zIEFCT1JUSU5HX01BTExPQz0wICcKICAgICAgKTsKICAgIH0KICAgIGlmICghTW9kdWxlWydyZWFsbG9jQnVmZmVyJ10pCiAgICAgIE1vZHVsZVsncmVhbGxvY0J1ZmZlciddID0gZnVuY3Rpb24gKHNpemUpIHsKICAgICAgICB2YXIgcmV0OwogICAgICAgIHRyeSB7CiAgICAgICAgICBpZiAoQXJyYXlCdWZmZXIudHJhbnNmZXIpIHsKICAgICAgICAgICAgcmV0ID0gQXJyYXlCdWZmZXIudHJhbnNmZXIoYnVmZmVyLCBzaXplKTsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHZhciBvbGRIRUFQOCA9IEhFQVA4OwogICAgICAgICAgICByZXQgPSBuZXcgQXJyYXlCdWZmZXIoc2l6ZSk7CiAgICAgICAgICAgIHZhciB0ZW1wID0gbmV3IEludDhBcnJheShyZXQpOwogICAgICAgICAgICB0ZW1wLnNldChvbGRIRUFQOCk7CiAgICAgICAgICB9CiAgICAgICAgfSBjYXRjaCAoZSkgewogICAgICAgICAgcmV0dXJuIGZhbHNlCiAgICAgICAgfQogICAgICAgIHZhciBzdWNjZXNzID0gX2Vtc2NyaXB0ZW5fcmVwbGFjZV9tZW1vcnkocmV0KTsKICAgICAgICBpZiAoIXN1Y2Nlc3MpIHJldHVybiBmYWxzZQogICAgICAgIHJldHVybiByZXQKICAgICAgfTsKICAgIGZ1bmN0aW9uIGVubGFyZ2VNZW1vcnkoKSB7CiAgICAgIHZhciBQQUdFX01VTFRJUExFID0gTW9kdWxlWyd1c2luZ1dhc20nXSA/IFdBU01fUEFHRV9TSVpFIDogQVNNSlNfUEFHRV9TSVpFOwogICAgICB2YXIgTElNSVQgPSAyMTQ3NDgzNjQ4IC0gUEFHRV9NVUxUSVBMRTsKICAgICAgaWYgKEhFQVAzMltEWU5BTUlDVE9QX1BUUiA+PiAyXSA+IExJTUlUKSB7CiAgICAgICAgcmV0dXJuIGZhbHNlCiAgICAgIH0KICAgICAgdmFyIE9MRF9UT1RBTF9NRU1PUlkgPSBUT1RBTF9NRU1PUlk7CiAgICAgIFRPVEFMX01FTU9SWSA9IE1hdGgubWF4KFRPVEFMX01FTU9SWSwgTUlOX1RPVEFMX01FTU9SWSk7CiAgICAgIHdoaWxlIChUT1RBTF9NRU1PUlkgPCBIRUFQMzJbRFlOQU1JQ1RPUF9QVFIgPj4gMl0pIHsKICAgICAgICBpZiAoVE9UQUxfTUVNT1JZIDw9IDUzNjg3MDkxMikgewogICAgICAgICAgVE9UQUxfTUVNT1JZID0gYWxpZ25VcCgyICogVE9UQUxfTUVNT1JZLCBQQUdFX01VTFRJUExFKTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgVE9UQUxfTUVNT1JZID0gTWF0aC5taW4oYWxpZ25VcCgoMyAqIFRPVEFMX01FTU9SWSArIDIxNDc0ODM2NDgpIC8gNCwgUEFHRV9NVUxUSVBMRSksIExJTUlUKTsKICAgICAgICB9CiAgICAgIH0KICAgICAgdmFyIHJlcGxhY2VtZW50ID0gTW9kdWxlWydyZWFsbG9jQnVmZmVyJ10oVE9UQUxfTUVNT1JZKTsKICAgICAgaWYgKCFyZXBsYWNlbWVudCB8fCByZXBsYWNlbWVudC5ieXRlTGVuZ3RoICE9IFRPVEFMX01FTU9SWSkgewogICAgICAgIFRPVEFMX01FTU9SWSA9IE9MRF9UT1RBTF9NRU1PUlk7CiAgICAgICAgcmV0dXJuIGZhbHNlCiAgICAgIH0KICAgICAgdXBkYXRlR2xvYmFsQnVmZmVyKHJlcGxhY2VtZW50KTsKICAgICAgdXBkYXRlR2xvYmFsQnVmZmVyVmlld3MoKTsKICAgICAgcmV0dXJuIHRydWUKICAgIH0KICAgIHZhciBieXRlTGVuZ3RoOwogICAgdHJ5IHsKICAgICAgYnl0ZUxlbmd0aCA9IEZ1bmN0aW9uLnByb3RvdHlwZS5jYWxsLmJpbmQoT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcihBcnJheUJ1ZmZlci5wcm90b3R5cGUsICdieXRlTGVuZ3RoJykuZ2V0KTsKICAgICAgYnl0ZUxlbmd0aChuZXcgQXJyYXlCdWZmZXIoNCkpOwogICAgfSBjYXRjaCAoZSkgewogICAgICBieXRlTGVuZ3RoID0gZnVuY3Rpb24gKGJ1ZmZlcikgewogICAgICAgIHJldHVybiBidWZmZXIuYnl0ZUxlbmd0aAogICAgICB9OwogICAgfQogICAgdmFyIFRPVEFMX1NUQUNLID0gTW9kdWxlWydUT1RBTF9TVEFDSyddIHx8IDUyNDI4ODA7CiAgICB2YXIgVE9UQUxfTUVNT1JZID0gTW9kdWxlWydUT1RBTF9NRU1PUlknXSB8fCAxNjc3NzIxNjsKICAgIGlmIChUT1RBTF9NRU1PUlkgPCBUT1RBTF9TVEFDSykKICAgICAgTW9kdWxlLnByaW50RXJyKAogICAgICAgICdUT1RBTF9NRU1PUlkgc2hvdWxkIGJlIGxhcmdlciB0aGFuIFRPVEFMX1NUQUNLLCB3YXMgJyArIFRPVEFMX01FTU9SWSArICchIChUT1RBTF9TVEFDSz0nICsgVE9UQUxfU1RBQ0sgKyAnKScKICAgICAgKTsKICAgIGlmIChNb2R1bGVbJ2J1ZmZlciddKSB7CiAgICAgIGJ1ZmZlciA9IE1vZHVsZVsnYnVmZmVyJ107CiAgICB9IGVsc2UgewogICAgICBpZiAodHlwZW9mIFdlYkFzc2VtYmx5ID09PSAnb2JqZWN0JyAmJiB0eXBlb2YgV2ViQXNzZW1ibHkuTWVtb3J5ID09PSAnZnVuY3Rpb24nKSB7CiAgICAgICAgTW9kdWxlWyd3YXNtTWVtb3J5J10gPSBuZXcgV2ViQXNzZW1ibHkuTWVtb3J5KHsgaW5pdGlhbDogVE9UQUxfTUVNT1JZIC8gV0FTTV9QQUdFX1NJWkUgfSk7CiAgICAgICAgYnVmZmVyID0gTW9kdWxlWyd3YXNtTWVtb3J5J10uYnVmZmVyOwogICAgICB9IGVsc2UgewogICAgICAgIGJ1ZmZlciA9IG5ldyBBcnJheUJ1ZmZlcihUT1RBTF9NRU1PUlkpOwogICAgICB9CiAgICAgIE1vZHVsZVsnYnVmZmVyJ10gPSBidWZmZXI7CiAgICB9CiAgICB1cGRhdGVHbG9iYWxCdWZmZXJWaWV3cygpOwogICAgZnVuY3Rpb24gZ2V0VG90YWxNZW1vcnkoKSB7CiAgICAgIHJldHVybiBUT1RBTF9NRU1PUlkKICAgIH0KICAgIEhFQVAzMlswXSA9IDE2Njg1MDkwMjk7CiAgICBIRUFQMTZbMV0gPSAyNTQ1OTsKICAgIGlmIChIRUFQVThbMl0gIT09IDExNSB8fCBIRUFQVThbM10gIT09IDk5KSB0aHJvdyAnUnVudGltZSBlcnJvcjogZXhwZWN0ZWQgdGhlIHN5c3RlbSB0byBiZSBsaXR0bGUtZW5kaWFuIScKICAgIGZ1bmN0aW9uIGNhbGxSdW50aW1lQ2FsbGJhY2tzKGNhbGxiYWNrcykgewogICAgICB3aGlsZSAoY2FsbGJhY2tzLmxlbmd0aCA+IDApIHsKICAgICAgICB2YXIgY2FsbGJhY2sgPSBjYWxsYmFja3Muc2hpZnQoKTsKICAgICAgICBpZiAodHlwZW9mIGNhbGxiYWNrID09ICdmdW5jdGlvbicpIHsKICAgICAgICAgIGNhbGxiYWNrKCk7CiAgICAgICAgICBjb250aW51ZQogICAgICAgIH0KICAgICAgICB2YXIgZnVuYyA9IGNhbGxiYWNrLmZ1bmM7CiAgICAgICAgaWYgKHR5cGVvZiBmdW5jID09PSAnbnVtYmVyJykgewogICAgICAgICAgaWYgKGNhbGxiYWNrLmFyZyA9PT0gdW5kZWZpbmVkKSB7CiAgICAgICAgICAgIE1vZHVsZVsnZHluQ2FsbF92J10oZnVuYyk7CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBNb2R1bGVbJ2R5bkNhbGxfdmknXShmdW5jLCBjYWxsYmFjay5hcmcpOwogICAgICAgICAgfQogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBmdW5jKGNhbGxiYWNrLmFyZyA9PT0gdW5kZWZpbmVkID8gbnVsbCA6IGNhbGxiYWNrLmFyZyk7CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgICB2YXIgX19BVFBSRVJVTl9fID0gW107CiAgICB2YXIgX19BVElOSVRfXyA9IFtdOwogICAgdmFyIF9fQVRNQUlOX18gPSBbXTsKICAgIHZhciBfX0FURVhJVF9fID0gW107CiAgICB2YXIgX19BVFBPU1RSVU5fXyA9IFtdOwogICAgdmFyIHJ1bnRpbWVJbml0aWFsaXplZCA9IGZhbHNlOwogICAgZnVuY3Rpb24gcHJlUnVuKCkgewogICAgICBpZiAoTW9kdWxlWydwcmVSdW4nXSkgewogICAgICAgIGlmICh0eXBlb2YgTW9kdWxlWydwcmVSdW4nXSA9PSAnZnVuY3Rpb24nKSBNb2R1bGVbJ3ByZVJ1biddID0gW01vZHVsZVsncHJlUnVuJ11dOwogICAgICAgIHdoaWxlIChNb2R1bGVbJ3ByZVJ1biddLmxlbmd0aCkgewogICAgICAgICAgYWRkT25QcmVSdW4oTW9kdWxlWydwcmVSdW4nXS5zaGlmdCgpKTsKICAgICAgICB9CiAgICAgIH0KICAgICAgY2FsbFJ1bnRpbWVDYWxsYmFja3MoX19BVFBSRVJVTl9fKTsKICAgIH0KICAgIGZ1bmN0aW9uIGVuc3VyZUluaXRSdW50aW1lKCkgewogICAgICBpZiAocnVudGltZUluaXRpYWxpemVkKSByZXR1cm4KICAgICAgcnVudGltZUluaXRpYWxpemVkID0gdHJ1ZTsKICAgICAgY2FsbFJ1bnRpbWVDYWxsYmFja3MoX19BVElOSVRfXyk7CiAgICB9CiAgICBmdW5jdGlvbiBwcmVNYWluKCkgewogICAgICBjYWxsUnVudGltZUNhbGxiYWNrcyhfX0FUTUFJTl9fKTsKICAgIH0KICAgIGZ1bmN0aW9uIGV4aXRSdW50aW1lKCkgewogICAgICBjYWxsUnVudGltZUNhbGxiYWNrcyhfX0FURVhJVF9fKTsKICAgIH0KICAgIGZ1bmN0aW9uIHBvc3RSdW4oKSB7CiAgICAgIGlmIChNb2R1bGVbJ3Bvc3RSdW4nXSkgewogICAgICAgIGlmICh0eXBlb2YgTW9kdWxlWydwb3N0UnVuJ10gPT0gJ2Z1bmN0aW9uJykgTW9kdWxlWydwb3N0UnVuJ10gPSBbTW9kdWxlWydwb3N0UnVuJ11dOwogICAgICAgIHdoaWxlIChNb2R1bGVbJ3Bvc3RSdW4nXS5sZW5ndGgpIHsKICAgICAgICAgIGFkZE9uUG9zdFJ1bihNb2R1bGVbJ3Bvc3RSdW4nXS5zaGlmdCgpKTsKICAgICAgICB9CiAgICAgIH0KICAgICAgY2FsbFJ1bnRpbWVDYWxsYmFja3MoX19BVFBPU1RSVU5fXyk7CiAgICB9CiAgICBmdW5jdGlvbiBhZGRPblByZVJ1bihjYikgewogICAgICBfX0FUUFJFUlVOX18udW5zaGlmdChjYik7CiAgICB9CiAgICBmdW5jdGlvbiBhZGRPblBvc3RSdW4oY2IpIHsKICAgICAgX19BVFBPU1RSVU5fXy51bnNoaWZ0KGNiKTsKICAgIH0KICAgIGZ1bmN0aW9uIHdyaXRlQXNjaWlUb01lbW9yeShzdHIsIGJ1ZmZlciwgZG9udEFkZE51bGwpIHsKICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBzdHIubGVuZ3RoOyArK2kpIHsKICAgICAgICBIRUFQOFtidWZmZXIrKyA+PiAwXSA9IHN0ci5jaGFyQ29kZUF0KGkpOwogICAgICB9CiAgICAgIGlmICghZG9udEFkZE51bGwpIEhFQVA4W2J1ZmZlciA+PiAwXSA9IDA7CiAgICB9CiAgICB2YXIgTWF0aF9hYnMgPSBNYXRoLmFiczsKICAgIHZhciBNYXRoX2NlaWwgPSBNYXRoLmNlaWw7CiAgICB2YXIgTWF0aF9mbG9vciA9IE1hdGguZmxvb3I7CiAgICB2YXIgTWF0aF9taW4gPSBNYXRoLm1pbjsKICAgIHZhciBydW5EZXBlbmRlbmNpZXMgPSAwOwogICAgdmFyIGRlcGVuZGVuY2llc0Z1bGZpbGxlZCA9IG51bGw7CiAgICBmdW5jdGlvbiBhZGRSdW5EZXBlbmRlbmN5KGlkKSB7CiAgICAgIHJ1bkRlcGVuZGVuY2llcysrOwogICAgICBpZiAoTW9kdWxlWydtb25pdG9yUnVuRGVwZW5kZW5jaWVzJ10pIHsKICAgICAgICBNb2R1bGVbJ21vbml0b3JSdW5EZXBlbmRlbmNpZXMnXShydW5EZXBlbmRlbmNpZXMpOwogICAgICB9CiAgICB9CiAgICBmdW5jdGlvbiByZW1vdmVSdW5EZXBlbmRlbmN5KGlkKSB7CiAgICAgIHJ1bkRlcGVuZGVuY2llcy0tOwogICAgICBpZiAoTW9kdWxlWydtb25pdG9yUnVuRGVwZW5kZW5jaWVzJ10pIHsKICAgICAgICBNb2R1bGVbJ21vbml0b3JSdW5EZXBlbmRlbmNpZXMnXShydW5EZXBlbmRlbmNpZXMpOwogICAgICB9CiAgICAgIGlmIChydW5EZXBlbmRlbmNpZXMgPT0gMCkgewogICAgICAgIGlmIChkZXBlbmRlbmNpZXNGdWxmaWxsZWQpIHsKICAgICAgICAgIHZhciBjYWxsYmFjayA9IGRlcGVuZGVuY2llc0Z1bGZpbGxlZDsKICAgICAgICAgIGRlcGVuZGVuY2llc0Z1bGZpbGxlZCA9IG51bGw7CiAgICAgICAgICBjYWxsYmFjaygpOwogICAgICAgIH0KICAgICAgfQogICAgfQogICAgTW9kdWxlWydwcmVsb2FkZWRJbWFnZXMnXSA9IHt9OwogICAgTW9kdWxlWydwcmVsb2FkZWRBdWRpb3MnXSA9IHt9OwogICAgdmFyIGRhdGFVUklQcmVmaXggPSAnZGF0YTphcHBsaWNhdGlvbi9vY3RldC1zdHJlYW07YmFzZTY0LCc7CiAgICBmdW5jdGlvbiBpc0RhdGFVUkkoZmlsZW5hbWUpIHsKICAgICAgcmV0dXJuIFN0cmluZy5wcm90b3R5cGUuc3RhcnRzV2l0aCA/IGZpbGVuYW1lLnN0YXJ0c1dpdGgoZGF0YVVSSVByZWZpeCkgOiBmaWxlbmFtZS5pbmRleE9mKGRhdGFVUklQcmVmaXgpID09PSAwCiAgICB9CiAgICBmdW5jdGlvbiBpbnRlZ3JhdGVXYXNtSlMoKSB7CiAgICAgIHZhciB3YXNtVGV4dEZpbGUgPSAndW5wYWNrLndhc3QnOwogICAgICB2YXIgYXNtanNDb2RlRmlsZSA9ICd1bnBhY2sudGVtcC5hc20uanMnOwogICAgICBpZiAodHlwZW9mIE1vZHVsZVsnbG9jYXRlRmlsZSddID09PSAnZnVuY3Rpb24nKSB7CiAgICAgICAgaWYgKCFpc0RhdGFVUkkod2FzbVRleHRGaWxlKSkgewogICAgICAgICAgd2FzbVRleHRGaWxlID0gTW9kdWxlWydsb2NhdGVGaWxlJ10od2FzbVRleHRGaWxlKTsKICAgICAgICB9CiAgICAgICAgaWYgKCFpc0RhdGFVUkkod2FzbUJpbmFyeUZpbGUpKSB7CiAgICAgICAgICB3YXNtQmluYXJ5RmlsZSA9IE1vZHVsZVsnbG9jYXRlRmlsZSddKHdhc21CaW5hcnlGaWxlKTsKICAgICAgICB9CiAgICAgICAgaWYgKCFpc0RhdGFVUkkoYXNtanNDb2RlRmlsZSkpIHsKICAgICAgICAgIGFzbWpzQ29kZUZpbGUgPSBNb2R1bGVbJ2xvY2F0ZUZpbGUnXShhc21qc0NvZGVGaWxlKTsKICAgICAgICB9CiAgICAgIH0KICAgICAgY29uc3Qgd2FzbVBhZ2VTaXplID0gNjQgKiAxMDI0OwogICAgICBjb25zdCBpbmZvID0gewogICAgICAgIGFzbTJ3YXNtOiB7CiAgICAgICAgICAnZjY0LXJlbSc6IGZ1bmN0aW9uICh4LCB5KSB7CiAgICAgICAgICAgIHJldHVybiB4ICUgeQogICAgICAgICAgfSwKICAgICAgICAgIGRlYnVnZ2VyOiBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgIGRlYnVnZ2VyCiAgICAgICAgICB9LAogICAgICAgIH0sCiAgICAgICAgcGFyZW50OiBNb2R1bGUsCiAgICAgIH07CiAgICAgIHZhciBleHBvcnRzID0gbnVsbDsKICAgICAgZnVuY3Rpb24gbWVyZ2VNZW1vcnkobmV3QnVmZmVyKSB7CiAgICAgICAgdmFyIG9sZEJ1ZmZlciA9IE1vZHVsZVsnYnVmZmVyJ107CiAgICAgICAgaWYgKG5ld0J1ZmZlci5ieXRlTGVuZ3RoIDwgb2xkQnVmZmVyLmJ5dGVMZW5ndGgpIHsKICAgICAgICAgIE1vZHVsZVsncHJpbnRFcnInXSgKICAgICAgICAgICAgJ3RoZSBuZXcgYnVmZmVyIGluIG1lcmdlTWVtb3J5IGlzIHNtYWxsZXIgdGhhbiB0aGUgcHJldmlvdXMgb25lLiBpbiBuYXRpdmUgd2FzbSwgd2Ugc2hvdWxkIGdyb3cgbWVtb3J5IGhlcmUnCiAgICAgICAgICApOwogICAgICAgIH0KICAgICAgICB2YXIgb2xkVmlldyA9IG5ldyBJbnQ4QXJyYXkob2xkQnVmZmVyKTsKICAgICAgICB2YXIgbmV3VmlldyA9IG5ldyBJbnQ4QXJyYXkobmV3QnVmZmVyKTsKICAgICAgICBuZXdWaWV3LnNldChvbGRWaWV3KTsKICAgICAgICB1cGRhdGVHbG9iYWxCdWZmZXIobmV3QnVmZmVyKTsKICAgICAgICB1cGRhdGVHbG9iYWxCdWZmZXJWaWV3cygpOwogICAgICB9CiAgICAgIGZ1bmN0aW9uIGZpeEltcG9ydHMoaW1wb3J0cykgewogICAgICAgIHJldHVybiBpbXBvcnRzCiAgICAgIH0KICAgICAgZnVuY3Rpb24gZ2V0QmluYXJ5KCkgewogICAgICAgIHRyeSB7CiAgICAgICAgICBpZiAoTW9kdWxlWyd3YXNtQmluYXJ5J10pIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBVaW50OEFycmF5KE1vZHVsZVsnd2FzbUJpbmFyeSddKQogICAgICAgICAgfQogICAgICAgICAgaWYgKE1vZHVsZVsncmVhZEJpbmFyeSddKSB7CiAgICAgICAgICAgIHJldHVybiBNb2R1bGVbJ3JlYWRCaW5hcnknXSh3YXNtQmluYXJ5RmlsZSkKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHRocm93ICJvbiB0aGUgd2ViLCB3ZSBuZWVkIHRoZSB3YXNtIGJpbmFyeSB0byBiZSBwcmVsb2FkZWQgYW5kIHNldCBvbiBNb2R1bGVbJ3dhc21CaW5hcnknXS4gZW1jYy5weSB3aWxsIGRvIHRoYXQgZm9yIHlvdSB3aGVuIGdlbmVyYXRpbmcgSFRNTCAoYnV0IG5vdCBKUykiCiAgICAgICAgICB9CiAgICAgICAgfSBjYXRjaCAoZXJyKSB7CiAgICAgICAgICBhYm9ydChlcnIpOwogICAgICAgIH0KICAgICAgfQogICAgICBmdW5jdGlvbiBnZXRCaW5hcnlQcm9taXNlKCkgewogICAgICAgIGlmICghTW9kdWxlWyd3YXNtQmluYXJ5J10gJiYgKEVOVklST05NRU5UX0lTX1dFQiB8fCBFTlZJUk9OTUVOVF9JU19XT1JLRVIpICYmIHR5cGVvZiBmZXRjaCA9PT0gJ2Z1bmN0aW9uJykgewogICAgICAgICAgcmV0dXJuIGZldGNoKHdhc21CaW5hcnlGaWxlLCB7IGNyZWRlbnRpYWxzIH0pCiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChyZXNwb25zZSkgewogICAgICAgICAgICAgIGlmICghcmVzcG9uc2VbJ29rJ10pIHsKICAgICAgICAgICAgICAgIHRocm93ICJmYWlsZWQgdG8gbG9hZCB3YXNtIGJpbmFyeSBmaWxlIGF0ICciICsgd2FzbUJpbmFyeUZpbGUgKyAiJyIKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgcmV0dXJuIHJlc3BvbnNlWydhcnJheUJ1ZmZlciddKCkKICAgICAgICAgICAgfSkKICAgICAgICAgICAgLmNhdGNoKGZ1bmN0aW9uICgpIHsKICAgICAgICAgICAgICByZXR1cm4gZ2V0QmluYXJ5KCkKICAgICAgICAgICAgfSkKICAgICAgICB9CiAgICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uIChyZXNvbHZlLCByZWplY3QpIHsKICAgICAgICAgIHJlc29sdmUoZ2V0QmluYXJ5KCkpOwogICAgICAgIH0pCiAgICAgIH0KICAgICAgZnVuY3Rpb24gZG9OYXRpdmVXYXNtKGdsb2JhbCwgZW52LCBwcm92aWRlZEJ1ZmZlcikgewogICAgICAgIGlmICh0eXBlb2YgV2ViQXNzZW1ibHkgIT09ICdvYmplY3QnKSB7CiAgICAgICAgICBNb2R1bGVbJ3ByaW50RXJyJ10oJ25vIG5hdGl2ZSB3YXNtIHN1cHBvcnQgZGV0ZWN0ZWQnKTsKICAgICAgICAgIHJldHVybiBmYWxzZQogICAgICAgIH0KICAgICAgICBpZiAoIShNb2R1bGVbJ3dhc21NZW1vcnknXSBpbnN0YW5jZW9mIFdlYkFzc2VtYmx5Lk1lbW9yeSkpIHsKICAgICAgICAgIE1vZHVsZVsncHJpbnRFcnInXSgnbm8gbmF0aXZlIHdhc20gTWVtb3J5IGluIHVzZScpOwogICAgICAgICAgcmV0dXJuIGZhbHNlCiAgICAgICAgfQogICAgICAgIGVudlsnbWVtb3J5J10gPSBNb2R1bGVbJ3dhc21NZW1vcnknXTsKICAgICAgICBpbmZvWydnbG9iYWwnXSA9IHsgTmFOOiBOYU4sIEluZmluaXR5OiBJbmZpbml0eSB9OwogICAgICAgIGluZm9bJ2dsb2JhbC5NYXRoJ10gPSBNYXRoOwogICAgICAgIGluZm9bJ2VudiddID0gZW52OwogICAgICAgIGZ1bmN0aW9uIHJlY2VpdmVJbnN0YW5jZShpbnN0YW5jZSwgbW9kdWxlKSB7CiAgICAgICAgICBleHBvcnRzID0gaW5zdGFuY2UuZXhwb3J0czsKICAgICAgICAgIGlmIChleHBvcnRzLm1lbW9yeSkgbWVyZ2VNZW1vcnkoZXhwb3J0cy5tZW1vcnkpOwogICAgICAgICAgTW9kdWxlWydhc20nXSA9IGV4cG9ydHM7CiAgICAgICAgICBNb2R1bGVbJ3VzaW5nV2FzbSddID0gdHJ1ZTsKICAgICAgICAgIHJlbW92ZVJ1bkRlcGVuZGVuY3koKTsKICAgICAgICB9CiAgICAgICAgYWRkUnVuRGVwZW5kZW5jeSgpOwogICAgICAgIGlmIChNb2R1bGVbJ2luc3RhbnRpYXRlV2FzbSddKSB7CiAgICAgICAgICB0cnkgewogICAgICAgICAgICByZXR1cm4gTW9kdWxlWydpbnN0YW50aWF0ZVdhc20nXShpbmZvLCByZWNlaXZlSW5zdGFuY2UpCiAgICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICAgIE1vZHVsZVsncHJpbnRFcnInXSgnTW9kdWxlLmluc3RhbnRpYXRlV2FzbSBjYWxsYmFjayBmYWlsZWQgd2l0aCBlcnJvcjogJyArIGUpOwogICAgICAgICAgICByZXR1cm4gZmFsc2UKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgZnVuY3Rpb24gcmVjZWl2ZUluc3RhbnRpYXRlZFNvdXJjZShvdXRwdXQpIHsKICAgICAgICAgIHJlY2VpdmVJbnN0YW5jZShvdXRwdXRbJ2luc3RhbmNlJ10sIG91dHB1dFsnbW9kdWxlJ10pOwogICAgICAgIH0KICAgICAgICBmdW5jdGlvbiBpbnN0YW50aWF0ZUFycmF5QnVmZmVyKHJlY2VpdmVyKSB7CiAgICAgICAgICBnZXRCaW5hcnlQcm9taXNlKCkKICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKGJpbmFyeSkgewogICAgICAgICAgICAgIHJldHVybiBXZWJBc3NlbWJseS5pbnN0YW50aWF0ZShiaW5hcnksIGluZm8pCiAgICAgICAgICAgIH0pCiAgICAgICAgICAgIC50aGVuKHJlY2VpdmVyKQogICAgICAgICAgICAuY2F0Y2goZnVuY3Rpb24gKHJlYXNvbikgewogICAgICAgICAgICAgIE1vZHVsZVsncHJpbnRFcnInXSgnZmFpbGVkIHRvIGFzeW5jaHJvbm91c2x5IHByZXBhcmUgd2FzbTogJyArIHJlYXNvbik7CiAgICAgICAgICAgICAgYWJvcnQocmVhc29uKTsKICAgICAgICAgICAgfSk7CiAgICAgICAgfQogICAgICAgIGlmICgKICAgICAgICAgICFNb2R1bGVbJ3dhc21CaW5hcnknXSAmJgogICAgICAgICAgdHlwZW9mIFdlYkFzc2VtYmx5Lmluc3RhbnRpYXRlU3RyZWFtaW5nID09PSAnZnVuY3Rpb24nICYmCiAgICAgICAgICAhaXNEYXRhVVJJKHdhc21CaW5hcnlGaWxlKSAmJgogICAgICAgICAgdHlwZW9mIGZldGNoID09PSAnZnVuY3Rpb24nCiAgICAgICAgKSB7CiAgICAgICAgICBXZWJBc3NlbWJseS5pbnN0YW50aWF0ZVN0cmVhbWluZyhmZXRjaCh3YXNtQmluYXJ5RmlsZSwgeyBjcmVkZW50aWFscyB9KSwgaW5mbykKICAgICAgICAgICAgLnRoZW4ocmVjZWl2ZUluc3RhbnRpYXRlZFNvdXJjZSkKICAgICAgICAgICAgLmNhdGNoKGZ1bmN0aW9uIChyZWFzb24pIHsKICAgICAgICAgICAgICBNb2R1bGVbJ3ByaW50RXJyJ10oJ3dhc20gc3RyZWFtaW5nIGNvbXBpbGUgZmFpbGVkOiAnICsgcmVhc29uKTsKICAgICAgICAgICAgICBNb2R1bGVbJ3ByaW50RXJyJ10oJ2ZhbGxpbmcgYmFjayB0byBBcnJheUJ1ZmZlciBpbnN0YW50aWF0aW9uJyk7CiAgICAgICAgICAgICAgaW5zdGFudGlhdGVBcnJheUJ1ZmZlcihyZWNlaXZlSW5zdGFudGlhdGVkU291cmNlKTsKICAgICAgICAgICAgfSk7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIGluc3RhbnRpYXRlQXJyYXlCdWZmZXIocmVjZWl2ZUluc3RhbnRpYXRlZFNvdXJjZSk7CiAgICAgICAgfQogICAgICAgIHJldHVybiB7fQogICAgICB9CiAgICAgIE1vZHVsZVsnYXNtUHJlbG9hZCddID0gTW9kdWxlWydhc20nXTsKICAgICAgdmFyIGFzbWpzUmVhbGxvY0J1ZmZlciA9IE1vZHVsZVsncmVhbGxvY0J1ZmZlciddOwogICAgICB2YXIgd2FzbVJlYWxsb2NCdWZmZXIgPSBmdW5jdGlvbiAoc2l6ZSkgewogICAgICAgIHZhciBQQUdFX01VTFRJUExFID0gTW9kdWxlWyd1c2luZ1dhc20nXSA/IFdBU01fUEFHRV9TSVpFIDogQVNNSlNfUEFHRV9TSVpFOwogICAgICAgIHNpemUgPSBhbGlnblVwKHNpemUsIFBBR0VfTVVMVElQTEUpOwogICAgICAgIHZhciBvbGQgPSBNb2R1bGVbJ2J1ZmZlciddOwogICAgICAgIHZhciBvbGRTaXplID0gb2xkLmJ5dGVMZW5ndGg7CiAgICAgICAgaWYgKE1vZHVsZVsndXNpbmdXYXNtJ10pIHsKICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgIHZhciByZXN1bHQgPSBNb2R1bGVbJ3dhc21NZW1vcnknXS5ncm93KChzaXplIC0gb2xkU2l6ZSkgLyB3YXNtUGFnZVNpemUpOwogICAgICAgICAgICBpZiAocmVzdWx0ICE9PSAoLTEgfCAwKSkgewogICAgICAgICAgICAgIHJldHVybiAoTW9kdWxlWydidWZmZXInXSA9IE1vZHVsZVsnd2FzbU1lbW9yeSddLmJ1ZmZlcikKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICByZXR1cm4gbnVsbAogICAgICAgICAgICB9CiAgICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICAgIHJldHVybiBudWxsCiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9OwogICAgICBNb2R1bGVbJ3JlYWxsb2NCdWZmZXInXSA9IGZ1bmN0aW9uIChzaXplKSB7CiAgICAgICAgaWYgKGZpbmFsTWV0aG9kID09PSAnYXNtanMnKSB7CiAgICAgICAgICByZXR1cm4gYXNtanNSZWFsbG9jQnVmZmVyKHNpemUpCiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIHJldHVybiB3YXNtUmVhbGxvY0J1ZmZlcihzaXplKQogICAgICAgIH0KICAgICAgfTsKICAgICAgdmFyIGZpbmFsTWV0aG9kID0gJyc7CiAgICAgIE1vZHVsZVsnYXNtJ10gPSBmdW5jdGlvbiAoZ2xvYmFsLCBlbnYsIHByb3ZpZGVkQnVmZmVyKSB7CiAgICAgICAgZW52ID0gZml4SW1wb3J0cyhlbnYpOwogICAgICAgIGlmICghZW52Wyd0YWJsZSddKSB7CiAgICAgICAgICB2YXIgVEFCTEVfU0laRSA9IE1vZHVsZVsnd2FzbVRhYmxlU2l6ZSddOwogICAgICAgICAgaWYgKFRBQkxFX1NJWkUgPT09IHVuZGVmaW5lZCkgVEFCTEVfU0laRSA9IDEwMjQ7CiAgICAgICAgICB2YXIgTUFYX1RBQkxFX1NJWkUgPSBNb2R1bGVbJ3dhc21NYXhUYWJsZVNpemUnXTsKICAgICAgICAgIGlmICh0eXBlb2YgV2ViQXNzZW1ibHkgPT09ICdvYmplY3QnICYmIHR5cGVvZiBXZWJBc3NlbWJseS5UYWJsZSA9PT0gJ2Z1bmN0aW9uJykgewogICAgICAgICAgICBpZiAoTUFYX1RBQkxFX1NJWkUgIT09IHVuZGVmaW5lZCkgewogICAgICAgICAgICAgIGVudlsndGFibGUnXSA9IG5ldyBXZWJBc3NlbWJseS5UYWJsZSh7IGluaXRpYWw6IFRBQkxFX1NJWkUsIG1heGltdW06IE1BWF9UQUJMRV9TSVpFLCBlbGVtZW50OiAnYW55ZnVuYycgfSk7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgZW52Wyd0YWJsZSddID0gbmV3IFdlYkFzc2VtYmx5LlRhYmxlKHsgaW5pdGlhbDogVEFCTEVfU0laRSwgZWxlbWVudDogJ2FueWZ1bmMnIH0pOwogICAgICAgICAgICB9CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBlbnZbJ3RhYmxlJ10gPSBuZXcgQXJyYXkoVEFCTEVfU0laRSk7CiAgICAgICAgICB9CiAgICAgICAgICBNb2R1bGVbJ3dhc21UYWJsZSddID0gZW52Wyd0YWJsZSddOwogICAgICAgIH0KICAgICAgICBpZiAoIWVudlsnbWVtb3J5QmFzZSddKSB7CiAgICAgICAgICBlbnZbJ21lbW9yeUJhc2UnXSA9IE1vZHVsZVsnU1RBVElDX0JBU0UnXTsKICAgICAgICB9CiAgICAgICAgaWYgKCFlbnZbJ3RhYmxlQmFzZSddKSB7CiAgICAgICAgICBlbnZbJ3RhYmxlQmFzZSddID0gMDsKICAgICAgICB9CiAgICAgICAgdmFyIGV4cG9ydHM7CiAgICAgICAgZXhwb3J0cyA9IGRvTmF0aXZlV2FzbShnbG9iYWwsIGVudik7CiAgICAgICAgaWYgKCFleHBvcnRzKQogICAgICAgICAgYWJvcnQoCiAgICAgICAgICAgICdubyBiaW5hcnllbiBtZXRob2Qgc3VjY2VlZGVkLiBjb25zaWRlciBlbmFibGluZyBtb3JlIG9wdGlvbnMsIGxpa2UgaW50ZXJwcmV0aW5nLCBpZiB5b3Ugd2FudCB0aGF0OiBodHRwczovL2dpdGh1Yi5jb20va3JpcGtlbi9lbXNjcmlwdGVuL3dpa2kvV2ViQXNzZW1ibHkjYmluYXJ5ZW4tbWV0aG9kcycKICAgICAgICAgICk7CiAgICAgICAgcmV0dXJuIGV4cG9ydHMKICAgICAgfTsKICAgIH0KICAgIGludGVncmF0ZVdhc21KUygpOwogICAgU1RBVElDX0JBU0UgPSBHTE9CQUxfQkFTRTsKICAgIFNUQVRJQ1RPUCA9IFNUQVRJQ19CQVNFICsgNjY5NjA7CiAgICBfX0FUSU5JVF9fLnB1c2goCiAgICAgIHsKICAgICAgICBmdW5jOiBmdW5jdGlvbiAoKSB7CiAgICAgICAgICBfX0dMT0JBTF9fc3ViX0lfZ2xvYmFsX2NwcCgpOwogICAgICAgIH0sCiAgICAgIH0sCiAgICAgIHsKICAgICAgICBmdW5jOiBmdW5jdGlvbiAoKSB7CiAgICAgICAgICBfX0dMT0JBTF9fc3ViX0lfY3JjX2NwcCgpOwogICAgICAgIH0sCiAgICAgIH0sCiAgICAgIHsKICAgICAgICBmdW5jOiBmdW5jdGlvbiAoKSB7CiAgICAgICAgICBfX0dMT0JBTF9fc3ViX0lfYnJpZGdlX2NwcCgpOwogICAgICAgIH0sCiAgICAgIH0sCiAgICAgIHsKICAgICAgICBmdW5jOiBmdW5jdGlvbiAoKSB7CiAgICAgICAgICBfX0dMT0JBTF9fc3ViX0lfYmluZF9jcHAoKTsKICAgICAgICB9LAogICAgICB9CiAgICApOwogICAgdmFyIFNUQVRJQ19CVU1QID0gNjY5NjA7CiAgICBNb2R1bGVbJ1NUQVRJQ19CQVNFJ10gPSBTVEFUSUNfQkFTRTsKICAgIE1vZHVsZVsnU1RBVElDX0JVTVAnXSA9IFNUQVRJQ19CVU1QOwogICAgU1RBVElDVE9QICs9IDE2OwogICAgZnVuY3Rpb24gX19fY3hhX2FsbG9jYXRlX2V4Y2VwdGlvbihzaXplKSB7CiAgICAgIHJldHVybiBfbWFsbG9jKHNpemUpCiAgICB9CiAgICBmdW5jdGlvbiBfX1pTdDE4dW5jYXVnaHRfZXhjZXB0aW9udigpIHsKICAgICAgcmV0dXJuICEhX19aU3QxOHVuY2F1Z2h0X2V4Y2VwdGlvbnYudW5jYXVnaHRfZXhjZXB0aW9uCiAgICB9CiAgICB2YXIgRVhDRVBUSU9OUyA9IHsKICAgICAgbGFzdDogMCwKICAgICAgY2F1Z2h0OiBbXSwKICAgICAgaW5mb3M6IHt9LAogICAgICBkZUFkanVzdDogZnVuY3Rpb24gKGFkanVzdGVkKSB7CiAgICAgICAgaWYgKCFhZGp1c3RlZCB8fCBFWENFUFRJT05TLmluZm9zW2FkanVzdGVkXSkgcmV0dXJuIGFkanVzdGVkCiAgICAgICAgZm9yICh2YXIga2V5IGluIEVYQ0VQVElPTlMuaW5mb3MpIHsKICAgICAgICAgIHZhciBwdHIgPSAra2V5OwogICAgICAgICAgdmFyIGluZm8gPSBFWENFUFRJT05TLmluZm9zW3B0cl07CiAgICAgICAgICBpZiAoaW5mby5hZGp1c3RlZCA9PT0gYWRqdXN0ZWQpIHsKICAgICAgICAgICAgcmV0dXJuIHB0cgogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZXR1cm4gYWRqdXN0ZWQKICAgICAgfSwKICAgICAgYWRkUmVmOiBmdW5jdGlvbiAocHRyKSB7CiAgICAgICAgaWYgKCFwdHIpIHJldHVybgogICAgICAgIHZhciBpbmZvID0gRVhDRVBUSU9OUy5pbmZvc1twdHJdOwogICAgICAgIGluZm8ucmVmY291bnQrKzsKICAgICAgfSwKICAgICAgZGVjUmVmOiBmdW5jdGlvbiAocHRyKSB7CiAgICAgICAgaWYgKCFwdHIpIHJldHVybgogICAgICAgIHZhciBpbmZvID0gRVhDRVBUSU9OUy5pbmZvc1twdHJdOwogICAgICAgIGFzc2VydChpbmZvLnJlZmNvdW50ID4gMCk7CiAgICAgICAgaW5mby5yZWZjb3VudC0tOwogICAgICAgIGlmIChpbmZvLnJlZmNvdW50ID09PSAwICYmICFpbmZvLnJldGhyb3duKSB7CiAgICAgICAgICBpZiAoaW5mby5kZXN0cnVjdG9yKSB7CiAgICAgICAgICAgIE1vZHVsZVsnZHluQ2FsbF92aSddKGluZm8uZGVzdHJ1Y3RvciwgcHRyKTsKICAgICAgICAgIH0KICAgICAgICAgIGRlbGV0ZSBFWENFUFRJT05TLmluZm9zW3B0cl07CiAgICAgICAgICBfX19jeGFfZnJlZV9leGNlcHRpb24ocHRyKTsKICAgICAgICB9CiAgICAgIH0sCiAgICAgIGNsZWFyUmVmOiBmdW5jdGlvbiAocHRyKSB7CiAgICAgICAgaWYgKCFwdHIpIHJldHVybgogICAgICAgIHZhciBpbmZvID0gRVhDRVBUSU9OUy5pbmZvc1twdHJdOwogICAgICAgIGluZm8ucmVmY291bnQgPSAwOwogICAgICB9LAogICAgfTsKICAgIGZ1bmN0aW9uIF9fX2N4YV9iZWdpbl9jYXRjaChwdHIpIHsKICAgICAgdmFyIGluZm8gPSBFWENFUFRJT05TLmluZm9zW3B0cl07CiAgICAgIGlmIChpbmZvICYmICFpbmZvLmNhdWdodCkgewogICAgICAgIGluZm8uY2F1Z2h0ID0gdHJ1ZTsKICAgICAgICBfX1pTdDE4dW5jYXVnaHRfZXhjZXB0aW9udi51bmNhdWdodF9leGNlcHRpb24tLTsKICAgICAgfQogICAgICBpZiAoaW5mbykgaW5mby5yZXRocm93biA9IGZhbHNlOwogICAgICBFWENFUFRJT05TLmNhdWdodC5wdXNoKHB0cik7CiAgICAgIEVYQ0VQVElPTlMuYWRkUmVmKEVYQ0VQVElPTlMuZGVBZGp1c3QocHRyKSk7CiAgICAgIHJldHVybiBwdHIKICAgIH0KICAgIGZ1bmN0aW9uIF9fX2N4YV9mcmVlX2V4Y2VwdGlvbihwdHIpIHsKICAgICAgdHJ5IHsKICAgICAgICByZXR1cm4gX2ZyZWUocHRyKQogICAgICB9IGNhdGNoIChlKSB7fQogICAgfQogICAgZnVuY3Rpb24gX19fY3hhX2VuZF9jYXRjaCgpIHsKICAgICAgTW9kdWxlWydzZXRUaHJldyddKDApOwogICAgICB2YXIgcHRyID0gRVhDRVBUSU9OUy5jYXVnaHQucG9wKCk7CiAgICAgIGlmIChwdHIpIHsKICAgICAgICBFWENFUFRJT05TLmRlY1JlZihFWENFUFRJT05TLmRlQWRqdXN0KHB0cikpOwogICAgICAgIEVYQ0VQVElPTlMubGFzdCA9IDA7CiAgICAgIH0KICAgIH0KICAgIGZ1bmN0aW9uIF9fX2N4YV9maW5kX21hdGNoaW5nX2NhdGNoXzIoKSB7CiAgICAgIHJldHVybiBfX19jeGFfZmluZF9tYXRjaGluZ19jYXRjaC5hcHBseShudWxsLCBhcmd1bWVudHMpCiAgICB9CiAgICBmdW5jdGlvbiBfX19jeGFfZmluZF9tYXRjaGluZ19jYXRjaF8zKCkgewogICAgICByZXR1cm4gX19fY3hhX2ZpbmRfbWF0Y2hpbmdfY2F0Y2guYXBwbHkobnVsbCwgYXJndW1lbnRzKQogICAgfQogICAgZnVuY3Rpb24gX19fY3hhX2ZpbmRfbWF0Y2hpbmdfY2F0Y2hfNCgpIHsKICAgICAgcmV0dXJuIF9fX2N4YV9maW5kX21hdGNoaW5nX2NhdGNoLmFwcGx5KG51bGwsIGFyZ3VtZW50cykKICAgIH0KICAgIGZ1bmN0aW9uIF9fX3Jlc3VtZUV4Y2VwdGlvbihwdHIpIHsKICAgICAgaWYgKCFFWENFUFRJT05TLmxhc3QpIHsKICAgICAgICBFWENFUFRJT05TLmxhc3QgPSBwdHI7CiAgICAgIH0KICAgICAgdGhyb3cgcHRyCiAgICB9CiAgICBmdW5jdGlvbiBfX19jeGFfZmluZF9tYXRjaGluZ19jYXRjaCgpIHsKICAgICAgdmFyIHRocm93biA9IEVYQ0VQVElPTlMubGFzdDsKICAgICAgaWYgKCF0aHJvd24pIHsKICAgICAgICByZXR1cm4gKHNldFRlbXBSZXQwKDApLCAwKSB8IDAKICAgICAgfQogICAgICB2YXIgaW5mbyA9IEVYQ0VQVElPTlMuaW5mb3NbdGhyb3duXTsKICAgICAgdmFyIHRocm93bnR5cGUgPSBpbmZvLnR5cGU7CiAgICAgIGlmICghdGhyb3dudHlwZSkgewogICAgICAgIHJldHVybiAoc2V0VGVtcFJldDAoMCksIHRocm93bikgfCAwCiAgICAgIH0KICAgICAgdmFyIHR5cGVBcnJheSA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cyk7CiAgICAgIE1vZHVsZVsnX19fY3hhX2lzX3BvaW50ZXJfdHlwZSddKHRocm93bnR5cGUpOwogICAgICBpZiAoIV9fX2N4YV9maW5kX21hdGNoaW5nX2NhdGNoLmJ1ZmZlcikgX19fY3hhX2ZpbmRfbWF0Y2hpbmdfY2F0Y2guYnVmZmVyID0gX21hbGxvYyg0KTsKICAgICAgSEVBUDMyW19fX2N4YV9maW5kX21hdGNoaW5nX2NhdGNoLmJ1ZmZlciA+PiAyXSA9IHRocm93bjsKICAgICAgdGhyb3duID0gX19fY3hhX2ZpbmRfbWF0Y2hpbmdfY2F0Y2guYnVmZmVyOwogICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHR5cGVBcnJheS5sZW5ndGg7IGkrKykgewogICAgICAgIGlmICh0eXBlQXJyYXlbaV0gJiYgTW9kdWxlWydfX19jeGFfY2FuX2NhdGNoJ10odHlwZUFycmF5W2ldLCB0aHJvd250eXBlLCB0aHJvd24pKSB7CiAgICAgICAgICB0aHJvd24gPSBIRUFQMzJbdGhyb3duID4+IDJdOwogICAgICAgICAgaW5mby5hZGp1c3RlZCA9IHRocm93bjsKICAgICAgICAgIHJldHVybiAoc2V0VGVtcFJldDAodHlwZUFycmF5W2ldKSwgdGhyb3duKSB8IDAKICAgICAgICB9CiAgICAgIH0KICAgICAgdGhyb3duID0gSEVBUDMyW3Rocm93biA+PiAyXTsKICAgICAgcmV0dXJuIChzZXRUZW1wUmV0MCh0aHJvd250eXBlKSwgdGhyb3duKSB8IDAKICAgIH0KICAgIGZ1bmN0aW9uIF9fX2N4YV90aHJvdyhwdHIsIHR5cGUsIGRlc3RydWN0b3IpIHsKICAgICAgRVhDRVBUSU9OUy5pbmZvc1twdHJdID0gewogICAgICAgIHB0cjogcHRyLAogICAgICAgIGFkanVzdGVkOiBwdHIsCiAgICAgICAgdHlwZTogdHlwZSwKICAgICAgICBkZXN0cnVjdG9yOiBkZXN0cnVjdG9yLAogICAgICAgIHJlZmNvdW50OiAwLAogICAgICAgIGNhdWdodDogZmFsc2UsCiAgICAgICAgcmV0aHJvd246IGZhbHNlLAogICAgICB9OwogICAgICBFWENFUFRJT05TLmxhc3QgPSBwdHI7CiAgICAgIGlmICghKCd1bmNhdWdodF9leGNlcHRpb24nIGluIF9fWlN0MTh1bmNhdWdodF9leGNlcHRpb252KSkgewogICAgICAgIF9fWlN0MTh1bmNhdWdodF9leGNlcHRpb252LnVuY2F1Z2h0X2V4Y2VwdGlvbiA9IDE7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgX19aU3QxOHVuY2F1Z2h0X2V4Y2VwdGlvbnYudW5jYXVnaHRfZXhjZXB0aW9uKys7CiAgICAgIH0KICAgICAgdGhyb3cgcHRyCiAgICB9CiAgICBmdW5jdGlvbiBfX19sb2NrKCkge30KICAgIHZhciBFUlJOT19DT0RFUyA9IHsKICAgICAgRVBFUk06IDEsCiAgICAgIEVOT0VOVDogMiwKICAgICAgRVNSQ0g6IDMsCiAgICAgIEVJTlRSOiA0LAogICAgICBFSU86IDUsCiAgICAgIEVOWElPOiA2LAogICAgICBFMkJJRzogNywKICAgICAgRU5PRVhFQzogOCwKICAgICAgRUJBREY6IDksCiAgICAgIEVDSElMRDogMTAsCiAgICAgIEVBR0FJTjogMTEsCiAgICAgIEVXT1VMREJMT0NLOiAxMSwKICAgICAgRU5PTUVNOiAxMiwKICAgICAgRUFDQ0VTOiAxMywKICAgICAgRUZBVUxUOiAxNCwKICAgICAgRU5PVEJMSzogMTUsCiAgICAgIEVCVVNZOiAxNiwKICAgICAgRUVYSVNUOiAxNywKICAgICAgRVhERVY6IDE4LAogICAgICBFTk9ERVY6IDE5LAogICAgICBFTk9URElSOiAyMCwKICAgICAgRUlTRElSOiAyMSwKICAgICAgRUlOVkFMOiAyMiwKICAgICAgRU5GSUxFOiAyMywKICAgICAgRU1GSUxFOiAyNCwKICAgICAgRU5PVFRZOiAyNSwKICAgICAgRVRYVEJTWTogMjYsCiAgICAgIEVGQklHOiAyNywKICAgICAgRU5PU1BDOiAyOCwKICAgICAgRVNQSVBFOiAyOSwKICAgICAgRVJPRlM6IDMwLAogICAgICBFTUxJTks6IDMxLAogICAgICBFUElQRTogMzIsCiAgICAgIEVET006IDMzLAogICAgICBFUkFOR0U6IDM0LAogICAgICBFTk9NU0c6IDQyLAogICAgICBFSURSTTogNDMsCiAgICAgIEVDSFJORzogNDQsCiAgICAgIEVMMk5TWU5DOiA0NSwKICAgICAgRUwzSExUOiA0NiwKICAgICAgRUwzUlNUOiA0NywKICAgICAgRUxOUk5HOiA0OCwKICAgICAgRVVOQVRDSDogNDksCiAgICAgIEVOT0NTSTogNTAsCiAgICAgIEVMMkhMVDogNTEsCiAgICAgIEVERUFETEs6IDM1LAogICAgICBFTk9MQ0s6IDM3LAogICAgICBFQkFERTogNTIsCiAgICAgIEVCQURSOiA1MywKICAgICAgRVhGVUxMOiA1NCwKICAgICAgRU5PQU5POiA1NSwKICAgICAgRUJBRFJRQzogNTYsCiAgICAgIEVCQURTTFQ6IDU3LAogICAgICBFREVBRExPQ0s6IDM1LAogICAgICBFQkZPTlQ6IDU5LAogICAgICBFTk9TVFI6IDYwLAogICAgICBFTk9EQVRBOiA2MSwKICAgICAgRVRJTUU6IDYyLAogICAgICBFTk9TUjogNjMsCiAgICAgIEVOT05FVDogNjQsCiAgICAgIEVOT1BLRzogNjUsCiAgICAgIEVSRU1PVEU6IDY2LAogICAgICBFTk9MSU5LOiA2NywKICAgICAgRUFEVjogNjgsCiAgICAgIEVTUk1OVDogNjksCiAgICAgIEVDT01NOiA3MCwKICAgICAgRVBST1RPOiA3MSwKICAgICAgRU1VTFRJSE9QOiA3MiwKICAgICAgRURPVERPVDogNzMsCiAgICAgIEVCQURNU0c6IDc0LAogICAgICBFTk9UVU5JUTogNzYsCiAgICAgIEVCQURGRDogNzcsCiAgICAgIEVSRU1DSEc6IDc4LAogICAgICBFTElCQUNDOiA3OSwKICAgICAgRUxJQkJBRDogODAsCiAgICAgIEVMSUJTQ046IDgxLAogICAgICBFTElCTUFYOiA4MiwKICAgICAgRUxJQkVYRUM6IDgzLAogICAgICBFTk9TWVM6IDM4LAogICAgICBFTk9URU1QVFk6IDM5LAogICAgICBFTkFNRVRPT0xPTkc6IDM2LAogICAgICBFTE9PUDogNDAsCiAgICAgIEVPUE5PVFNVUFA6IDk1LAogICAgICBFUEZOT1NVUFBPUlQ6IDk2LAogICAgICBFQ09OTlJFU0VUOiAxMDQsCiAgICAgIEVOT0JVRlM6IDEwNSwKICAgICAgRUFGTk9TVVBQT1JUOiA5NywKICAgICAgRVBST1RPVFlQRTogOTEsCiAgICAgIEVOT1RTT0NLOiA4OCwKICAgICAgRU5PUFJPVE9PUFQ6IDkyLAogICAgICBFU0hVVERPV046IDEwOCwKICAgICAgRUNPTk5SRUZVU0VEOiAxMTEsCiAgICAgIEVBRERSSU5VU0U6IDk4LAogICAgICBFQ09OTkFCT1JURUQ6IDEwMywKICAgICAgRU5FVFVOUkVBQ0g6IDEwMSwKICAgICAgRU5FVERPV046IDEwMCwKICAgICAgRVRJTUVET1VUOiAxMTAsCiAgICAgIEVIT1NURE9XTjogMTEyLAogICAgICBFSE9TVFVOUkVBQ0g6IDExMywKICAgICAgRUlOUFJPR1JFU1M6IDExNSwKICAgICAgRUFMUkVBRFk6IDExNCwKICAgICAgRURFU1RBRERSUkVROiA4OSwKICAgICAgRU1TR1NJWkU6IDkwLAogICAgICBFUFJPVE9OT1NVUFBPUlQ6IDkzLAogICAgICBFU09DS1ROT1NVUFBPUlQ6IDk0LAogICAgICBFQUREUk5PVEFWQUlMOiA5OSwKICAgICAgRU5FVFJFU0VUOiAxMDIsCiAgICAgIEVJU0NPTk46IDEwNiwKICAgICAgRU5PVENPTk46IDEwNywKICAgICAgRVRPT01BTllSRUZTOiAxMDksCiAgICAgIEVVU0VSUzogODcsCiAgICAgIEVEUVVPVDogMTIyLAogICAgICBFU1RBTEU6IDExNiwKICAgICAgRU5PVFNVUDogOTUsCiAgICAgIEVOT01FRElVTTogMTIzLAogICAgICBFSUxTRVE6IDg0LAogICAgICBFT1ZFUkZMT1c6IDc1LAogICAgICBFQ0FOQ0VMRUQ6IDEyNSwKICAgICAgRU5PVFJFQ09WRVJBQkxFOiAxMzEsCiAgICAgIEVPV05FUkRFQUQ6IDEzMCwKICAgICAgRVNUUlBJUEU6IDg2LAogICAgfTsKICAgIGZ1bmN0aW9uIF9fX3NldEVyck5vKHZhbHVlKSB7CiAgICAgIGlmIChNb2R1bGVbJ19fX2Vycm5vX2xvY2F0aW9uJ10pIEhFQVAzMltNb2R1bGVbJ19fX2Vycm5vX2xvY2F0aW9uJ10oKSA+PiAyXSA9IHZhbHVlOwogICAgICByZXR1cm4gdmFsdWUKICAgIH0KICAgIGZ1bmN0aW9uIF9fX21hcF9maWxlKHBhdGhuYW1lLCBzaXplKSB7CiAgICAgIF9fX3NldEVyck5vKEVSUk5PX0NPREVTLkVQRVJNKTsKICAgICAgcmV0dXJuIC0xCiAgICB9CiAgICB2YXIgRVJSTk9fTUVTU0FHRVMgPSB7CiAgICAgIDA6ICdTdWNjZXNzJywKICAgICAgMTogJ05vdCBzdXBlci11c2VyJywKICAgICAgMjogJ05vIHN1Y2ggZmlsZSBvciBkaXJlY3RvcnknLAogICAgICAzOiAnTm8gc3VjaCBwcm9jZXNzJywKICAgICAgNDogJ0ludGVycnVwdGVkIHN5c3RlbSBjYWxsJywKICAgICAgNTogJ0kvTyBlcnJvcicsCiAgICAgIDY6ICdObyBzdWNoIGRldmljZSBvciBhZGRyZXNzJywKICAgICAgNzogJ0FyZyBsaXN0IHRvbyBsb25nJywKICAgICAgODogJ0V4ZWMgZm9ybWF0IGVycm9yJywKICAgICAgOTogJ0JhZCBmaWxlIG51bWJlcicsCiAgICAgIDEwOiAnTm8gY2hpbGRyZW4nLAogICAgICAxMTogJ05vIG1vcmUgcHJvY2Vzc2VzJywKICAgICAgMTI6ICdOb3QgZW5vdWdoIGNvcmUnLAogICAgICAxMzogJ1Blcm1pc3Npb24gZGVuaWVkJywKICAgICAgMTQ6ICdCYWQgYWRkcmVzcycsCiAgICAgIDE1OiAnQmxvY2sgZGV2aWNlIHJlcXVpcmVkJywKICAgICAgMTY6ICdNb3VudCBkZXZpY2UgYnVzeScsCiAgICAgIDE3OiAnRmlsZSBleGlzdHMnLAogICAgICAxODogJ0Nyb3NzLWRldmljZSBsaW5rJywKICAgICAgMTk6ICdObyBzdWNoIGRldmljZScsCiAgICAgIDIwOiAnTm90IGEgZGlyZWN0b3J5JywKICAgICAgMjE6ICdJcyBhIGRpcmVjdG9yeScsCiAgICAgIDIyOiAnSW52YWxpZCBhcmd1bWVudCcsCiAgICAgIDIzOiAnVG9vIG1hbnkgb3BlbiBmaWxlcyBpbiBzeXN0ZW0nLAogICAgICAyNDogJ1RvbyBtYW55IG9wZW4gZmlsZXMnLAogICAgICAyNTogJ05vdCBhIHR5cGV3cml0ZXInLAogICAgICAyNjogJ1RleHQgZmlsZSBidXN5JywKICAgICAgMjc6ICdGaWxlIHRvbyBsYXJnZScsCiAgICAgIDI4OiAnTm8gc3BhY2UgbGVmdCBvbiBkZXZpY2UnLAogICAgICAyOTogJ0lsbGVnYWwgc2VlaycsCiAgICAgIDMwOiAnUmVhZCBvbmx5IGZpbGUgc3lzdGVtJywKICAgICAgMzE6ICdUb28gbWFueSBsaW5rcycsCiAgICAgIDMyOiAnQnJva2VuIHBpcGUnLAogICAgICAzMzogJ01hdGggYXJnIG91dCBvZiBkb21haW4gb2YgZnVuYycsCiAgICAgIDM0OiAnTWF0aCByZXN1bHQgbm90IHJlcHJlc2VudGFibGUnLAogICAgICAzNTogJ0ZpbGUgbG9ja2luZyBkZWFkbG9jayBlcnJvcicsCiAgICAgIDM2OiAnRmlsZSBvciBwYXRoIG5hbWUgdG9vIGxvbmcnLAogICAgICAzNzogJ05vIHJlY29yZCBsb2NrcyBhdmFpbGFibGUnLAogICAgICAzODogJ0Z1bmN0aW9uIG5vdCBpbXBsZW1lbnRlZCcsCiAgICAgIDM5OiAnRGlyZWN0b3J5IG5vdCBlbXB0eScsCiAgICAgIDQwOiAnVG9vIG1hbnkgc3ltYm9saWMgbGlua3MnLAogICAgICA0MjogJ05vIG1lc3NhZ2Ugb2YgZGVzaXJlZCB0eXBlJywKICAgICAgNDM6ICdJZGVudGlmaWVyIHJlbW92ZWQnLAogICAgICA0NDogJ0NoYW5uZWwgbnVtYmVyIG91dCBvZiByYW5nZScsCiAgICAgIDQ1OiAnTGV2ZWwgMiBub3Qgc3luY2hyb25pemVkJywKICAgICAgNDY6ICdMZXZlbCAzIGhhbHRlZCcsCiAgICAgIDQ3OiAnTGV2ZWwgMyByZXNldCcsCiAgICAgIDQ4OiAnTGluayBudW1iZXIgb3V0IG9mIHJhbmdlJywKICAgICAgNDk6ICdQcm90b2NvbCBkcml2ZXIgbm90IGF0dGFjaGVkJywKICAgICAgNTA6ICdObyBDU0kgc3RydWN0dXJlIGF2YWlsYWJsZScsCiAgICAgIDUxOiAnTGV2ZWwgMiBoYWx0ZWQnLAogICAgICA1MjogJ0ludmFsaWQgZXhjaGFuZ2UnLAogICAgICA1MzogJ0ludmFsaWQgcmVxdWVzdCBkZXNjcmlwdG9yJywKICAgICAgNTQ6ICdFeGNoYW5nZSBmdWxsJywKICAgICAgNTU6ICdObyBhbm9kZScsCiAgICAgIDU2OiAnSW52YWxpZCByZXF1ZXN0IGNvZGUnLAogICAgICA1NzogJ0ludmFsaWQgc2xvdCcsCiAgICAgIDU5OiAnQmFkIGZvbnQgZmlsZSBmbXQnLAogICAgICA2MDogJ0RldmljZSBub3QgYSBzdHJlYW0nLAogICAgICA2MTogJ05vIGRhdGEgKGZvciBubyBkZWxheSBpbyknLAogICAgICA2MjogJ1RpbWVyIGV4cGlyZWQnLAogICAgICA2MzogJ091dCBvZiBzdHJlYW1zIHJlc291cmNlcycsCiAgICAgIDY0OiAnTWFjaGluZSBpcyBub3Qgb24gdGhlIG5ldHdvcmsnLAogICAgICA2NTogJ1BhY2thZ2Ugbm90IGluc3RhbGxlZCcsCiAgICAgIDY2OiAnVGhlIG9iamVjdCBpcyByZW1vdGUnLAogICAgICA2NzogJ1RoZSBsaW5rIGhhcyBiZWVuIHNldmVyZWQnLAogICAgICA2ODogJ0FkdmVydGlzZSBlcnJvcicsCiAgICAgIDY5OiAnU3Jtb3VudCBlcnJvcicsCiAgICAgIDcwOiAnQ29tbXVuaWNhdGlvbiBlcnJvciBvbiBzZW5kJywKICAgICAgNzE6ICdQcm90b2NvbCBlcnJvcicsCiAgICAgIDcyOiAnTXVsdGlob3AgYXR0ZW1wdGVkJywKICAgICAgNzM6ICdDcm9zcyBtb3VudCBwb2ludCAobm90IHJlYWxseSBlcnJvciknLAogICAgICA3NDogJ1RyeWluZyB0byByZWFkIHVucmVhZGFibGUgbWVzc2FnZScsCiAgICAgIDc1OiAnVmFsdWUgdG9vIGxhcmdlIGZvciBkZWZpbmVkIGRhdGEgdHlwZScsCiAgICAgIDc2OiAnR2l2ZW4gbG9nLiBuYW1lIG5vdCB1bmlxdWUnLAogICAgICA3NzogJ2YuZC4gaW52YWxpZCBmb3IgdGhpcyBvcGVyYXRpb24nLAogICAgICA3ODogJ1JlbW90ZSBhZGRyZXNzIGNoYW5nZWQnLAogICAgICA3OTogJ0NhbiAgIGFjY2VzcyBhIG5lZWRlZCBzaGFyZWQgbGliJywKICAgICAgODA6ICdBY2Nlc3NpbmcgYSBjb3JydXB0ZWQgc2hhcmVkIGxpYicsCiAgICAgIDgxOiAnLmxpYiBzZWN0aW9uIGluIGEub3V0IGNvcnJ1cHRlZCcsCiAgICAgIDgyOiAnQXR0ZW1wdGluZyB0byBsaW5rIGluIHRvbyBtYW55IGxpYnMnLAogICAgICA4MzogJ0F0dGVtcHRpbmcgdG8gZXhlYyBhIHNoYXJlZCBsaWJyYXJ5JywKICAgICAgODQ6ICdJbGxlZ2FsIGJ5dGUgc2VxdWVuY2UnLAogICAgICA4NjogJ1N0cmVhbXMgcGlwZSBlcnJvcicsCiAgICAgIDg3OiAnVG9vIG1hbnkgdXNlcnMnLAogICAgICA4ODogJ1NvY2tldCBvcGVyYXRpb24gb24gbm9uLXNvY2tldCcsCiAgICAgIDg5OiAnRGVzdGluYXRpb24gYWRkcmVzcyByZXF1aXJlZCcsCiAgICAgIDkwOiAnTWVzc2FnZSB0b28gbG9uZycsCiAgICAgIDkxOiAnUHJvdG9jb2wgd3JvbmcgdHlwZSBmb3Igc29ja2V0JywKICAgICAgOTI6ICdQcm90b2NvbCBub3QgYXZhaWxhYmxlJywKICAgICAgOTM6ICdVbmtub3duIHByb3RvY29sJywKICAgICAgOTQ6ICdTb2NrZXQgdHlwZSBub3Qgc3VwcG9ydGVkJywKICAgICAgOTU6ICdOb3Qgc3VwcG9ydGVkJywKICAgICAgOTY6ICdQcm90b2NvbCBmYW1pbHkgbm90IHN1cHBvcnRlZCcsCiAgICAgIDk3OiAnQWRkcmVzcyBmYW1pbHkgbm90IHN1cHBvcnRlZCBieSBwcm90b2NvbCBmYW1pbHknLAogICAgICA5ODogJ0FkZHJlc3MgYWxyZWFkeSBpbiB1c2UnLAogICAgICA5OTogJ0FkZHJlc3Mgbm90IGF2YWlsYWJsZScsCiAgICAgIDEwMDogJ05ldHdvcmsgaW50ZXJmYWNlIGlzIG5vdCBjb25maWd1cmVkJywKICAgICAgMTAxOiAnTmV0d29yayBpcyB1bnJlYWNoYWJsZScsCiAgICAgIDEwMjogJ0Nvbm5lY3Rpb24gcmVzZXQgYnkgbmV0d29yaycsCiAgICAgIDEwMzogJ0Nvbm5lY3Rpb24gYWJvcnRlZCcsCiAgICAgIDEwNDogJ0Nvbm5lY3Rpb24gcmVzZXQgYnkgcGVlcicsCiAgICAgIDEwNTogJ05vIGJ1ZmZlciBzcGFjZSBhdmFpbGFibGUnLAogICAgICAxMDY6ICdTb2NrZXQgaXMgYWxyZWFkeSBjb25uZWN0ZWQnLAogICAgICAxMDc6ICdTb2NrZXQgaXMgbm90IGNvbm5lY3RlZCcsCiAgICAgIDEwODogIkNhbid0IHNlbmQgYWZ0ZXIgc29ja2V0IHNodXRkb3duIiwKICAgICAgMTA5OiAnVG9vIG1hbnkgcmVmZXJlbmNlcycsCiAgICAgIDExMDogJ0Nvbm5lY3Rpb24gdGltZWQgb3V0JywKICAgICAgMTExOiAnQ29ubmVjdGlvbiByZWZ1c2VkJywKICAgICAgMTEyOiAnSG9zdCBpcyBkb3duJywKICAgICAgMTEzOiAnSG9zdCBpcyB1bnJlYWNoYWJsZScsCiAgICAgIDExNDogJ1NvY2tldCBhbHJlYWR5IGNvbm5lY3RlZCcsCiAgICAgIDExNTogJ0Nvbm5lY3Rpb24gYWxyZWFkeSBpbiBwcm9ncmVzcycsCiAgICAgIDExNjogJ1N0YWxlIGZpbGUgaGFuZGxlJywKICAgICAgMTIyOiAnUXVvdGEgZXhjZWVkZWQnLAogICAgICAxMjM6ICdObyBtZWRpdW0gKGluIHRhcGUgZHJpdmUpJywKICAgICAgMTI1OiAnT3BlcmF0aW9uIGNhbmNlbGVkJywKICAgICAgMTMwOiAnUHJldmlvdXMgb3duZXIgZGllZCcsCiAgICAgIDEzMTogJ1N0YXRlIG5vdCByZWNvdmVyYWJsZScsCiAgICB9OwogICAgdmFyIFBBVEggPSB7CiAgICAgIHNwbGl0UGF0aDogZnVuY3Rpb24gKGZpbGVuYW1lKSB7CiAgICAgICAgdmFyIHNwbGl0UGF0aFJlID0gL14oXC8/fCkoW1xzXFNdKj8pKCg/OlwuezEsMn18W15cL10rP3wpKFwuW14uXC9dKnwpKSg/OltcL10qKSQvOwogICAgICAgIHJldHVybiBzcGxpdFBhdGhSZS5leGVjKGZpbGVuYW1lKS5zbGljZSgxKQogICAgICB9LAogICAgICBub3JtYWxpemVBcnJheTogZnVuY3Rpb24gKHBhcnRzLCBhbGxvd0Fib3ZlUm9vdCkgewogICAgICAgIHZhciB1cCA9IDA7CiAgICAgICAgZm9yICh2YXIgaSA9IHBhcnRzLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSB7CiAgICAgICAgICB2YXIgbGFzdCA9IHBhcnRzW2ldOwogICAgICAgICAgaWYgKGxhc3QgPT09ICcuJykgewogICAgICAgICAgICBwYXJ0cy5zcGxpY2UoaSwgMSk7CiAgICAgICAgICB9IGVsc2UgaWYgKGxhc3QgPT09ICcuLicpIHsKICAgICAgICAgICAgcGFydHMuc3BsaWNlKGksIDEpOwogICAgICAgICAgICB1cCsrOwogICAgICAgICAgfSBlbHNlIGlmICh1cCkgewogICAgICAgICAgICBwYXJ0cy5zcGxpY2UoaSwgMSk7CiAgICAgICAgICAgIHVwLS07CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGlmIChhbGxvd0Fib3ZlUm9vdCkgewogICAgICAgICAgZm9yICg7IHVwOyB1cC0tKSB7CiAgICAgICAgICAgIHBhcnRzLnVuc2hpZnQoJy4uJyk7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHJldHVybiBwYXJ0cwogICAgICB9LAogICAgICBub3JtYWxpemU6IGZ1bmN0aW9uIChwYXRoKSB7CiAgICAgICAgdmFyIGlzQWJzb2x1dGUgPSBwYXRoLmNoYXJBdCgwKSA9PT0gJy8nLAogICAgICAgICAgdHJhaWxpbmdTbGFzaCA9IHBhdGguc3Vic3RyKC0xKSA9PT0gJy8nOwogICAgICAgIHBhdGggPSBQQVRILm5vcm1hbGl6ZUFycmF5KAogICAgICAgICAgcGF0aC5zcGxpdCgnLycpLmZpbHRlcihmdW5jdGlvbiAocCkgewogICAgICAgICAgICByZXR1cm4gISFwCiAgICAgICAgICB9KSwKICAgICAgICAgICFpc0Fic29sdXRlCiAgICAgICAgKS5qb2luKCcvJyk7CiAgICAgICAgaWYgKCFwYXRoICYmICFpc0Fic29sdXRlKSB7CiAgICAgICAgICBwYXRoID0gJy4nOwogICAgICAgIH0KICAgICAgICBpZiAocGF0aCAmJiB0cmFpbGluZ1NsYXNoKSB7CiAgICAgICAgICBwYXRoICs9ICcvJzsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIChpc0Fic29sdXRlID8gJy8nIDogJycpICsgcGF0aAogICAgICB9LAogICAgICBkaXJuYW1lOiBmdW5jdGlvbiAocGF0aCkgewogICAgICAgIHZhciByZXN1bHQgPSBQQVRILnNwbGl0UGF0aChwYXRoKSwKICAgICAgICAgIHJvb3QgPSByZXN1bHRbMF0sCiAgICAgICAgICBkaXIgPSByZXN1bHRbMV07CiAgICAgICAgaWYgKCFyb290ICYmICFkaXIpIHsKICAgICAgICAgIHJldHVybiAnLicKICAgICAgICB9CiAgICAgICAgaWYgKGRpcikgewogICAgICAgICAgZGlyID0gZGlyLnN1YnN0cigwLCBkaXIubGVuZ3RoIC0gMSk7CiAgICAgICAgfQogICAgICAgIHJldHVybiByb290ICsgZGlyCiAgICAgIH0sCiAgICAgIGJhc2VuYW1lOiBmdW5jdGlvbiAocGF0aCkgewogICAgICAgIGlmIChwYXRoID09PSAnLycpIHJldHVybiAnLycKICAgICAgICB2YXIgbGFzdFNsYXNoID0gcGF0aC5sYXN0SW5kZXhPZignLycpOwogICAgICAgIGlmIChsYXN0U2xhc2ggPT09IC0xKSByZXR1cm4gcGF0aAogICAgICAgIHJldHVybiBwYXRoLnN1YnN0cihsYXN0U2xhc2ggKyAxKQogICAgICB9LAogICAgICBleHRuYW1lOiBmdW5jdGlvbiAocGF0aCkgewogICAgICAgIHJldHVybiBQQVRILnNwbGl0UGF0aChwYXRoKVszXQogICAgICB9LAogICAgICBqb2luOiBmdW5jdGlvbiAoKSB7CiAgICAgICAgdmFyIHBhdGhzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAwKTsKICAgICAgICByZXR1cm4gUEFUSC5ub3JtYWxpemUocGF0aHMuam9pbignLycpKQogICAgICB9LAogICAgICBqb2luMjogZnVuY3Rpb24gKGwsIHIpIHsKICAgICAgICByZXR1cm4gUEFUSC5ub3JtYWxpemUobCArICcvJyArIHIpCiAgICAgIH0sCiAgICAgIHJlc29sdmU6IGZ1bmN0aW9uICgpIHsKICAgICAgICB2YXIgcmVzb2x2ZWRQYXRoID0gJycsCiAgICAgICAgICByZXNvbHZlZEFic29sdXRlID0gZmFsc2U7CiAgICAgICAgZm9yICh2YXIgaSA9IGFyZ3VtZW50cy5sZW5ndGggLSAxOyBpID49IC0xICYmICFyZXNvbHZlZEFic29sdXRlOyBpLS0pIHsKICAgICAgICAgIHZhciBwYXRoID0gaSA+PSAwID8gYXJndW1lbnRzW2ldIDogRlMuY3dkKCk7CiAgICAgICAgICBpZiAodHlwZW9mIHBhdGggIT09ICdzdHJpbmcnKSB7CiAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ0FyZ3VtZW50cyB0byBwYXRoLnJlc29sdmUgbXVzdCBiZSBzdHJpbmdzJykKICAgICAgICAgIH0gZWxzZSBpZiAoIXBhdGgpIHsKICAgICAgICAgICAgcmV0dXJuICcnCiAgICAgICAgICB9CiAgICAgICAgICByZXNvbHZlZFBhdGggPSBwYXRoICsgJy8nICsgcmVzb2x2ZWRQYXRoOwogICAgICAgICAgcmVzb2x2ZWRBYnNvbHV0ZSA9IHBhdGguY2hhckF0KDApID09PSAnLyc7CiAgICAgICAgfQogICAgICAgIHJlc29sdmVkUGF0aCA9IFBBVEgubm9ybWFsaXplQXJyYXkoCiAgICAgICAgICByZXNvbHZlZFBhdGguc3BsaXQoJy8nKS5maWx0ZXIoZnVuY3Rpb24gKHApIHsKICAgICAgICAgICAgcmV0dXJuICEhcAogICAgICAgICAgfSksCiAgICAgICAgICAhcmVzb2x2ZWRBYnNvbHV0ZQogICAgICAgICkuam9pbignLycpOwogICAgICAgIHJldHVybiAocmVzb2x2ZWRBYnNvbHV0ZSA/ICcvJyA6ICcnKSArIHJlc29sdmVkUGF0aCB8fCAnLicKICAgICAgfSwKICAgICAgcmVsYXRpdmU6IGZ1bmN0aW9uIChmcm9tLCB0bykgewogICAgICAgIGZyb20gPSBQQVRILnJlc29sdmUoZnJvbSkuc3Vic3RyKDEpOwogICAgICAgIHRvID0gUEFUSC5yZXNvbHZlKHRvKS5zdWJzdHIoMSk7CiAgICAgICAgZnVuY3Rpb24gdHJpbShhcnIpIHsKICAgICAgICAgIHZhciBzdGFydCA9IDA7CiAgICAgICAgICBmb3IgKDsgc3RhcnQgPCBhcnIubGVuZ3RoOyBzdGFydCsrKSB7CiAgICAgICAgICAgIGlmIChhcnJbc3RhcnRdICE9PSAnJykgYnJlYWsKICAgICAgICAgIH0KICAgICAgICAgIHZhciBlbmQgPSBhcnIubGVuZ3RoIC0gMTsKICAgICAgICAgIGZvciAoOyBlbmQgPj0gMDsgZW5kLS0pIHsKICAgICAgICAgICAgaWYgKGFycltlbmRdICE9PSAnJykgYnJlYWsKICAgICAgICAgIH0KICAgICAgICAgIGlmIChzdGFydCA+IGVuZCkgcmV0dXJuIFtdCiAgICAgICAgICByZXR1cm4gYXJyLnNsaWNlKHN0YXJ0LCBlbmQgLSBzdGFydCArIDEpCiAgICAgICAgfQogICAgICAgIHZhciBmcm9tUGFydHMgPSB0cmltKGZyb20uc3BsaXQoJy8nKSk7CiAgICAgICAgdmFyIHRvUGFydHMgPSB0cmltKHRvLnNwbGl0KCcvJykpOwogICAgICAgIHZhciBsZW5ndGggPSBNYXRoLm1pbihmcm9tUGFydHMubGVuZ3RoLCB0b1BhcnRzLmxlbmd0aCk7CiAgICAgICAgdmFyIHNhbWVQYXJ0c0xlbmd0aCA9IGxlbmd0aDsKICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7CiAgICAgICAgICBpZiAoZnJvbVBhcnRzW2ldICE9PSB0b1BhcnRzW2ldKSB7CiAgICAgICAgICAgIHNhbWVQYXJ0c0xlbmd0aCA9IGk7CiAgICAgICAgICAgIGJyZWFrCiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHZhciBvdXRwdXRQYXJ0cyA9IFtdOwogICAgICAgIGZvciAodmFyIGkgPSBzYW1lUGFydHNMZW5ndGg7IGkgPCBmcm9tUGFydHMubGVuZ3RoOyBpKyspIHsKICAgICAgICAgIG91dHB1dFBhcnRzLnB1c2goJy4uJyk7CiAgICAgICAgfQogICAgICAgIG91dHB1dFBhcnRzID0gb3V0cHV0UGFydHMuY29uY2F0KHRvUGFydHMuc2xpY2Uoc2FtZVBhcnRzTGVuZ3RoKSk7CiAgICAgICAgcmV0dXJuIG91dHB1dFBhcnRzLmpvaW4oJy8nKQogICAgICB9LAogICAgfTsKICAgIHZhciBUVFkgPSB7CiAgICAgIHR0eXM6IFtdLAogICAgICBpbml0OiBmdW5jdGlvbiAoKSB7fSwKICAgICAgc2h1dGRvd246IGZ1bmN0aW9uICgpIHt9LAogICAgICByZWdpc3RlcjogZnVuY3Rpb24gKGRldiwgb3BzKSB7CiAgICAgICAgVFRZLnR0eXNbZGV2XSA9IHsgaW5wdXQ6IFtdLCBvdXRwdXQ6IFtdLCBvcHM6IG9wcyB9OwogICAgICAgIEZTLnJlZ2lzdGVyRGV2aWNlKGRldiwgVFRZLnN0cmVhbV9vcHMpOwogICAgICB9LAogICAgICBzdHJlYW1fb3BzOiB7CiAgICAgICAgb3BlbjogZnVuY3Rpb24gKHN0cmVhbSkgewogICAgICAgICAgdmFyIHR0eSA9IFRUWS50dHlzW3N0cmVhbS5ub2RlLnJkZXZdOwogICAgICAgICAgaWYgKCF0dHkpIHsKICAgICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoRVJSTk9fQ09ERVMuRU5PREVWKQogICAgICAgICAgfQogICAgICAgICAgc3RyZWFtLnR0eSA9IHR0eTsKICAgICAgICAgIHN0cmVhbS5zZWVrYWJsZSA9IGZhbHNlOwogICAgICAgIH0sCiAgICAgICAgY2xvc2U6IGZ1bmN0aW9uIChzdHJlYW0pIHsKICAgICAgICAgIHN0cmVhbS50dHkub3BzLmZsdXNoKHN0cmVhbS50dHkpOwogICAgICAgIH0sCiAgICAgICAgZmx1c2g6IGZ1bmN0aW9uIChzdHJlYW0pIHsKICAgICAgICAgIHN0cmVhbS50dHkub3BzLmZsdXNoKHN0cmVhbS50dHkpOwogICAgICAgIH0sCiAgICAgICAgcmVhZDogZnVuY3Rpb24gKHN0cmVhbSwgYnVmZmVyLCBvZmZzZXQsIGxlbmd0aCwgcG9zKSB7CiAgICAgICAgICBpZiAoIXN0cmVhbS50dHkgfHwgIXN0cmVhbS50dHkub3BzLmdldF9jaGFyKSB7CiAgICAgICAgICAgIHRocm93IG5ldyBGUy5FcnJub0Vycm9yKEVSUk5PX0NPREVTLkVOWElPKQogICAgICAgICAgfQogICAgICAgICAgdmFyIGJ5dGVzUmVhZCA9IDA7CiAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7CiAgICAgICAgICAgIHZhciByZXN1bHQ7CiAgICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgICAgcmVzdWx0ID0gc3RyZWFtLnR0eS5vcHMuZ2V0X2NoYXIoc3RyZWFtLnR0eSk7CiAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FSU8pCiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKHJlc3VsdCA9PT0gdW5kZWZpbmVkICYmIGJ5dGVzUmVhZCA9PT0gMCkgewogICAgICAgICAgICAgIHRocm93IG5ldyBGUy5FcnJub0Vycm9yKEVSUk5PX0NPREVTLkVBR0FJTikKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAocmVzdWx0ID09PSBudWxsIHx8IHJlc3VsdCA9PT0gdW5kZWZpbmVkKSBicmVhawogICAgICAgICAgICBieXRlc1JlYWQrKzsKICAgICAgICAgICAgYnVmZmVyW29mZnNldCArIGldID0gcmVzdWx0OwogICAgICAgICAgfQogICAgICAgICAgaWYgKGJ5dGVzUmVhZCkgewogICAgICAgICAgICBzdHJlYW0ubm9kZS50aW1lc3RhbXAgPSBEYXRlLm5vdygpOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIGJ5dGVzUmVhZAogICAgICAgIH0sCiAgICAgICAgd3JpdGU6IGZ1bmN0aW9uIChzdHJlYW0sIGJ1ZmZlciwgb2Zmc2V0LCBsZW5ndGgsIHBvcykgewogICAgICAgICAgaWYgKCFzdHJlYW0udHR5IHx8ICFzdHJlYW0udHR5Lm9wcy5wdXRfY2hhcikgewogICAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FTlhJTykKICAgICAgICAgIH0KICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspIHsKICAgICAgICAgICAgdHJ5IHsKICAgICAgICAgICAgICBzdHJlYW0udHR5Lm9wcy5wdXRfY2hhcihzdHJlYW0udHR5LCBidWZmZXJbb2Zmc2V0ICsgaV0pOwogICAgICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoRVJSTk9fQ09ERVMuRUlPKQogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBpZiAobGVuZ3RoKSB7CiAgICAgICAgICAgIHN0cmVhbS5ub2RlLnRpbWVzdGFtcCA9IERhdGUubm93KCk7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gaQogICAgICAgIH0sCiAgICAgIH0sCiAgICAgIGRlZmF1bHRfdHR5X29wczogewogICAgICAgIGdldF9jaGFyOiBmdW5jdGlvbiAodHR5KSB7CiAgICAgICAgICBpZiAoIXR0eS5pbnB1dC5sZW5ndGgpIHsKICAgICAgICAgICAgdmFyIHJlc3VsdCA9IG51bGw7CiAgICAgICAgICAgIGlmIChFTlZJUk9OTUVOVF9JU19OT0RFKSB7CiAgICAgICAgICAgICAgdmFyIEJVRlNJWkUgPSAyNTY7CiAgICAgICAgICAgICAgdmFyIGJ1ZiA9IG5ldyBCdWZmZXIoQlVGU0laRSk7CiAgICAgICAgICAgICAgdmFyIGJ5dGVzUmVhZCA9IDA7CiAgICAgICAgICAgICAgdmFyIGlzUG9zaXhQbGF0Zm9ybSA9IHByb2Nlc3MucGxhdGZvcm0gIT0gJ3dpbjMyJzsKICAgICAgICAgICAgICB2YXIgZmQgPSBwcm9jZXNzLnN0ZGluLmZkOwogICAgICAgICAgICAgIGlmIChpc1Bvc2l4UGxhdGZvcm0pIHsKICAgICAgICAgICAgICAgIHZhciB1c2luZ0RldmljZSA9IGZhbHNlOwogICAgICAgICAgICAgICAgdHJ5IHsKICAgICAgICAgICAgICAgICAgZmQgPSBmcy5vcGVuU3luYygnL2Rldi9zdGRpbicsICdyJyk7CiAgICAgICAgICAgICAgICAgIHVzaW5nRGV2aWNlID0gdHJ1ZTsKICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHt9CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgICAgICBieXRlc1JlYWQgPSBmcy5yZWFkU3luYyhmZCwgYnVmLCAwLCBCVUZTSVpFLCBudWxsKTsKICAgICAgICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICAgICAgICBpZiAoZS50b1N0cmluZygpLmluZGV4T2YoJ0VPRicpICE9IC0xKSBieXRlc1JlYWQgPSAwOwogICAgICAgICAgICAgICAgZWxzZSB0aHJvdyBlCiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGlmICh1c2luZ0RldmljZSkgewogICAgICAgICAgICAgICAgZnMuY2xvc2VTeW5jKGZkKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgaWYgKGJ5dGVzUmVhZCA+IDApIHsKICAgICAgICAgICAgICAgIHJlc3VsdCA9IGJ1Zi5zbGljZSgwLCBieXRlc1JlYWQpLnRvU3RyaW5nKCd1dGYtOCcpOwogICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICByZXN1bHQgPSBudWxsOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSBlbHNlIGlmICh0eXBlb2Ygd2luZG93ICE9ICd1bmRlZmluZWQnICYmIHR5cGVvZiB3aW5kb3cucHJvbXB0ID09ICdmdW5jdGlvbicpIHsKICAgICAgICAgICAgICByZXN1bHQgPSB3aW5kb3cucHJvbXB0KCdJbnB1dDogJyk7CiAgICAgICAgICAgICAgaWYgKHJlc3VsdCAhPT0gbnVsbCkgewogICAgICAgICAgICAgICAgcmVzdWx0ICs9ICdcbic7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9IGVsc2UgaWYgKHR5cGVvZiByZWFkbGluZSA9PSAnZnVuY3Rpb24nKSB7CiAgICAgICAgICAgICAgcmVzdWx0ID0gcmVhZGxpbmUoKTsKICAgICAgICAgICAgICBpZiAocmVzdWx0ICE9PSBudWxsKSB7CiAgICAgICAgICAgICAgICByZXN1bHQgKz0gJ1xuJzsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKCFyZXN1bHQpIHsKICAgICAgICAgICAgICByZXR1cm4gbnVsbAogICAgICAgICAgICB9CiAgICAgICAgICAgIHR0eS5pbnB1dCA9IGludEFycmF5RnJvbVN0cmluZyhyZXN1bHQsIHRydWUpOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIHR0eS5pbnB1dC5zaGlmdCgpCiAgICAgICAgfSwKICAgICAgICBwdXRfY2hhcjogZnVuY3Rpb24gKHR0eSwgdmFsKSB7CiAgICAgICAgICBpZiAodmFsID09PSBudWxsIHx8IHZhbCA9PT0gMTApIHsKICAgICAgICAgICAgTW9kdWxlWydwcmludCddKFVURjhBcnJheVRvU3RyaW5nKHR0eS5vdXRwdXQsIDApKTsKICAgICAgICAgICAgdHR5Lm91dHB1dCA9IFtdOwogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgaWYgKHZhbCAhPSAwKSB0dHkub3V0cHV0LnB1c2godmFsKTsKICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIGZsdXNoOiBmdW5jdGlvbiAodHR5KSB7CiAgICAgICAgICBpZiAodHR5Lm91dHB1dCAmJiB0dHkub3V0cHV0Lmxlbmd0aCA+IDApIHsKICAgICAgICAgICAgTW9kdWxlWydwcmludCddKFVURjhBcnJheVRvU3RyaW5nKHR0eS5vdXRwdXQsIDApKTsKICAgICAgICAgICAgdHR5Lm91dHB1dCA9IFtdOwogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgIH0sCiAgICAgIGRlZmF1bHRfdHR5MV9vcHM6IHsKICAgICAgICBwdXRfY2hhcjogZnVuY3Rpb24gKHR0eSwgdmFsKSB7CiAgICAgICAgICBpZiAodmFsID09PSBudWxsIHx8IHZhbCA9PT0gMTApIHsKICAgICAgICAgICAgTW9kdWxlWydwcmludEVyciddKFVURjhBcnJheVRvU3RyaW5nKHR0eS5vdXRwdXQsIDApKTsKICAgICAgICAgICAgdHR5Lm91dHB1dCA9IFtdOwogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgaWYgKHZhbCAhPSAwKSB0dHkub3V0cHV0LnB1c2godmFsKTsKICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIGZsdXNoOiBmdW5jdGlvbiAodHR5KSB7CiAgICAgICAgICBpZiAodHR5Lm91dHB1dCAmJiB0dHkub3V0cHV0Lmxlbmd0aCA+IDApIHsKICAgICAgICAgICAgTW9kdWxlWydwcmludEVyciddKFVURjhBcnJheVRvU3RyaW5nKHR0eS5vdXRwdXQsIDApKTsKICAgICAgICAgICAgdHR5Lm91dHB1dCA9IFtdOwogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgIH0sCiAgICB9OwogICAgdmFyIE1FTUZTID0gewogICAgICBvcHNfdGFibGU6IG51bGwsCiAgICAgIG1vdW50OiBmdW5jdGlvbiAobW91bnQpIHsKICAgICAgICByZXR1cm4gTUVNRlMuY3JlYXRlTm9kZShudWxsLCAnLycsIDE2Mzg0IHwgNTExLCAwKQogICAgICB9LAogICAgICBjcmVhdGVOb2RlOiBmdW5jdGlvbiAocGFyZW50LCBuYW1lLCBtb2RlLCBkZXYpIHsKICAgICAgICBpZiAoRlMuaXNCbGtkZXYobW9kZSkgfHwgRlMuaXNGSUZPKG1vZGUpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FUEVSTSkKICAgICAgICB9CiAgICAgICAgaWYgKCFNRU1GUy5vcHNfdGFibGUpIHsKICAgICAgICAgIE1FTUZTLm9wc190YWJsZSA9IHsKICAgICAgICAgICAgZGlyOiB7CiAgICAgICAgICAgICAgbm9kZTogewogICAgICAgICAgICAgICAgZ2V0YXR0cjogTUVNRlMubm9kZV9vcHMuZ2V0YXR0ciwKICAgICAgICAgICAgICAgIHNldGF0dHI6IE1FTUZTLm5vZGVfb3BzLnNldGF0dHIsCiAgICAgICAgICAgICAgICBsb29rdXA6IE1FTUZTLm5vZGVfb3BzLmxvb2t1cCwKICAgICAgICAgICAgICAgIG1rbm9kOiBNRU1GUy5ub2RlX29wcy5ta25vZCwKICAgICAgICAgICAgICAgIHJlbmFtZTogTUVNRlMubm9kZV9vcHMucmVuYW1lLAogICAgICAgICAgICAgICAgdW5saW5rOiBNRU1GUy5ub2RlX29wcy51bmxpbmssCiAgICAgICAgICAgICAgICBybWRpcjogTUVNRlMubm9kZV9vcHMucm1kaXIsCiAgICAgICAgICAgICAgICByZWFkZGlyOiBNRU1GUy5ub2RlX29wcy5yZWFkZGlyLAogICAgICAgICAgICAgICAgc3ltbGluazogTUVNRlMubm9kZV9vcHMuc3ltbGluaywKICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgIHN0cmVhbTogeyBsbHNlZWs6IE1FTUZTLnN0cmVhbV9vcHMubGxzZWVrIH0sCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIGZpbGU6IHsKICAgICAgICAgICAgICBub2RlOiB7IGdldGF0dHI6IE1FTUZTLm5vZGVfb3BzLmdldGF0dHIsIHNldGF0dHI6IE1FTUZTLm5vZGVfb3BzLnNldGF0dHIgfSwKICAgICAgICAgICAgICBzdHJlYW06IHsKICAgICAgICAgICAgICAgIGxsc2VlazogTUVNRlMuc3RyZWFtX29wcy5sbHNlZWssCiAgICAgICAgICAgICAgICByZWFkOiBNRU1GUy5zdHJlYW1fb3BzLnJlYWQsCiAgICAgICAgICAgICAgICB3cml0ZTogTUVNRlMuc3RyZWFtX29wcy53cml0ZSwKICAgICAgICAgICAgICAgIGFsbG9jYXRlOiBNRU1GUy5zdHJlYW1fb3BzLmFsbG9jYXRlLAogICAgICAgICAgICAgICAgbW1hcDogTUVNRlMuc3RyZWFtX29wcy5tbWFwLAogICAgICAgICAgICAgICAgbXN5bmM6IE1FTUZTLnN0cmVhbV9vcHMubXN5bmMsCiAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgfSwKICAgICAgICAgICAgbGluazogewogICAgICAgICAgICAgIG5vZGU6IHsKICAgICAgICAgICAgICAgIGdldGF0dHI6IE1FTUZTLm5vZGVfb3BzLmdldGF0dHIsCiAgICAgICAgICAgICAgICBzZXRhdHRyOiBNRU1GUy5ub2RlX29wcy5zZXRhdHRyLAogICAgICAgICAgICAgICAgcmVhZGxpbms6IE1FTUZTLm5vZGVfb3BzLnJlYWRsaW5rLAogICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgc3RyZWFtOiB7fSwKICAgICAgICAgICAgfSwKICAgICAgICAgICAgY2hyZGV2OiB7CiAgICAgICAgICAgICAgbm9kZTogeyBnZXRhdHRyOiBNRU1GUy5ub2RlX29wcy5nZXRhdHRyLCBzZXRhdHRyOiBNRU1GUy5ub2RlX29wcy5zZXRhdHRyIH0sCiAgICAgICAgICAgICAgc3RyZWFtOiBGUy5jaHJkZXZfc3RyZWFtX29wcywKICAgICAgICAgICAgfSwKICAgICAgICAgIH07CiAgICAgICAgfQogICAgICAgIHZhciBub2RlID0gRlMuY3JlYXRlTm9kZShwYXJlbnQsIG5hbWUsIG1vZGUsIGRldik7CiAgICAgICAgaWYgKEZTLmlzRGlyKG5vZGUubW9kZSkpIHsKICAgICAgICAgIG5vZGUubm9kZV9vcHMgPSBNRU1GUy5vcHNfdGFibGUuZGlyLm5vZGU7CiAgICAgICAgICBub2RlLnN0cmVhbV9vcHMgPSBNRU1GUy5vcHNfdGFibGUuZGlyLnN0cmVhbTsKICAgICAgICAgIG5vZGUuY29udGVudHMgPSB7fTsKICAgICAgICB9IGVsc2UgaWYgKEZTLmlzRmlsZShub2RlLm1vZGUpKSB7CiAgICAgICAgICBub2RlLm5vZGVfb3BzID0gTUVNRlMub3BzX3RhYmxlLmZpbGUubm9kZTsKICAgICAgICAgIG5vZGUuc3RyZWFtX29wcyA9IE1FTUZTLm9wc190YWJsZS5maWxlLnN0cmVhbTsKICAgICAgICAgIG5vZGUudXNlZEJ5dGVzID0gMDsKICAgICAgICAgIG5vZGUuY29udGVudHMgPSBudWxsOwogICAgICAgIH0gZWxzZSBpZiAoRlMuaXNMaW5rKG5vZGUubW9kZSkpIHsKICAgICAgICAgIG5vZGUubm9kZV9vcHMgPSBNRU1GUy5vcHNfdGFibGUubGluay5ub2RlOwogICAgICAgICAgbm9kZS5zdHJlYW1fb3BzID0gTUVNRlMub3BzX3RhYmxlLmxpbmsuc3RyZWFtOwogICAgICAgIH0gZWxzZSBpZiAoRlMuaXNDaHJkZXYobm9kZS5tb2RlKSkgewogICAgICAgICAgbm9kZS5ub2RlX29wcyA9IE1FTUZTLm9wc190YWJsZS5jaHJkZXYubm9kZTsKICAgICAgICAgIG5vZGUuc3RyZWFtX29wcyA9IE1FTUZTLm9wc190YWJsZS5jaHJkZXYuc3RyZWFtOwogICAgICAgIH0KICAgICAgICBub2RlLnRpbWVzdGFtcCA9IERhdGUubm93KCk7CiAgICAgICAgaWYgKHBhcmVudCkgewogICAgICAgICAgcGFyZW50LmNvbnRlbnRzW25hbWVdID0gbm9kZTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIG5vZGUKICAgICAgfSwKICAgICAgZ2V0RmlsZURhdGFBc1JlZ3VsYXJBcnJheTogZnVuY3Rpb24gKG5vZGUpIHsKICAgICAgICBpZiAobm9kZS5jb250ZW50cyAmJiBub2RlLmNvbnRlbnRzLnN1YmFycmF5KSB7CiAgICAgICAgICB2YXIgYXJyID0gW107CiAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IG5vZGUudXNlZEJ5dGVzOyArK2kpIGFyci5wdXNoKG5vZGUuY29udGVudHNbaV0pOwogICAgICAgICAgcmV0dXJuIGFycgogICAgICAgIH0KICAgICAgICByZXR1cm4gbm9kZS5jb250ZW50cwogICAgICB9LAogICAgICBnZXRGaWxlRGF0YUFzVHlwZWRBcnJheTogZnVuY3Rpb24gKG5vZGUpIHsKICAgICAgICBpZiAoIW5vZGUuY29udGVudHMpIHJldHVybiBuZXcgVWludDhBcnJheSgpCiAgICAgICAgaWYgKG5vZGUuY29udGVudHMuc3ViYXJyYXkpIHJldHVybiBub2RlLmNvbnRlbnRzLnN1YmFycmF5KDAsIG5vZGUudXNlZEJ5dGVzKQogICAgICAgIHJldHVybiBuZXcgVWludDhBcnJheShub2RlLmNvbnRlbnRzKQogICAgICB9LAogICAgICBleHBhbmRGaWxlU3RvcmFnZTogZnVuY3Rpb24gKG5vZGUsIG5ld0NhcGFjaXR5KSB7CiAgICAgICAgaWYgKG5vZGUuY29udGVudHMgJiYgbm9kZS5jb250ZW50cy5zdWJhcnJheSAmJiBuZXdDYXBhY2l0eSA+IG5vZGUuY29udGVudHMubGVuZ3RoKSB7CiAgICAgICAgICBub2RlLmNvbnRlbnRzID0gTUVNRlMuZ2V0RmlsZURhdGFBc1JlZ3VsYXJBcnJheShub2RlKTsKICAgICAgICAgIG5vZGUudXNlZEJ5dGVzID0gbm9kZS5jb250ZW50cy5sZW5ndGg7CiAgICAgICAgfQogICAgICAgIGlmICghbm9kZS5jb250ZW50cyB8fCBub2RlLmNvbnRlbnRzLnN1YmFycmF5KSB7CiAgICAgICAgICB2YXIgcHJldkNhcGFjaXR5ID0gbm9kZS5jb250ZW50cyA/IG5vZGUuY29udGVudHMubGVuZ3RoIDogMDsKICAgICAgICAgIGlmIChwcmV2Q2FwYWNpdHkgPj0gbmV3Q2FwYWNpdHkpIHJldHVybgogICAgICAgICAgdmFyIENBUEFDSVRZX0RPVUJMSU5HX01BWCA9IDEwMjQgKiAxMDI0OwogICAgICAgICAgbmV3Q2FwYWNpdHkgPSBNYXRoLm1heChuZXdDYXBhY2l0eSwgKHByZXZDYXBhY2l0eSAqIChwcmV2Q2FwYWNpdHkgPCBDQVBBQ0lUWV9ET1VCTElOR19NQVggPyAyIDogMS4xMjUpKSB8IDApOwogICAgICAgICAgaWYgKHByZXZDYXBhY2l0eSAhPSAwKSBuZXdDYXBhY2l0eSA9IE1hdGgubWF4KG5ld0NhcGFjaXR5LCAyNTYpOwogICAgICAgICAgdmFyIG9sZENvbnRlbnRzID0gbm9kZS5jb250ZW50czsKICAgICAgICAgIG5vZGUuY29udGVudHMgPSBuZXcgVWludDhBcnJheShuZXdDYXBhY2l0eSk7CiAgICAgICAgICBpZiAobm9kZS51c2VkQnl0ZXMgPiAwKSBub2RlLmNvbnRlbnRzLnNldChvbGRDb250ZW50cy5zdWJhcnJheSgwLCBub2RlLnVzZWRCeXRlcyksIDApOwogICAgICAgICAgcmV0dXJuCiAgICAgICAgfQogICAgICAgIGlmICghbm9kZS5jb250ZW50cyAmJiBuZXdDYXBhY2l0eSA+IDApIG5vZGUuY29udGVudHMgPSBbXTsKICAgICAgICB3aGlsZSAobm9kZS5jb250ZW50cy5sZW5ndGggPCBuZXdDYXBhY2l0eSkgbm9kZS5jb250ZW50cy5wdXNoKDApOwogICAgICB9LAogICAgICByZXNpemVGaWxlU3RvcmFnZTogZnVuY3Rpb24gKG5vZGUsIG5ld1NpemUpIHsKICAgICAgICBpZiAobm9kZS51c2VkQnl0ZXMgPT0gbmV3U2l6ZSkgcmV0dXJuCiAgICAgICAgaWYgKG5ld1NpemUgPT0gMCkgewogICAgICAgICAgbm9kZS5jb250ZW50cyA9IG51bGw7CiAgICAgICAgICBub2RlLnVzZWRCeXRlcyA9IDA7CiAgICAgICAgICByZXR1cm4KICAgICAgICB9CiAgICAgICAgaWYgKCFub2RlLmNvbnRlbnRzIHx8IG5vZGUuY29udGVudHMuc3ViYXJyYXkpIHsKICAgICAgICAgIHZhciBvbGRDb250ZW50cyA9IG5vZGUuY29udGVudHM7CiAgICAgICAgICBub2RlLmNvbnRlbnRzID0gbmV3IFVpbnQ4QXJyYXkobmV3IEFycmF5QnVmZmVyKG5ld1NpemUpKTsKICAgICAgICAgIGlmIChvbGRDb250ZW50cykgewogICAgICAgICAgICBub2RlLmNvbnRlbnRzLnNldChvbGRDb250ZW50cy5zdWJhcnJheSgwLCBNYXRoLm1pbihuZXdTaXplLCBub2RlLnVzZWRCeXRlcykpKTsKICAgICAgICAgIH0KICAgICAgICAgIG5vZGUudXNlZEJ5dGVzID0gbmV3U2l6ZTsKICAgICAgICAgIHJldHVybgogICAgICAgIH0KICAgICAgICBpZiAoIW5vZGUuY29udGVudHMpIG5vZGUuY29udGVudHMgPSBbXTsKICAgICAgICBpZiAobm9kZS5jb250ZW50cy5sZW5ndGggPiBuZXdTaXplKSBub2RlLmNvbnRlbnRzLmxlbmd0aCA9IG5ld1NpemU7CiAgICAgICAgZWxzZSB3aGlsZSAobm9kZS5jb250ZW50cy5sZW5ndGggPCBuZXdTaXplKSBub2RlLmNvbnRlbnRzLnB1c2goMCk7CiAgICAgICAgbm9kZS51c2VkQnl0ZXMgPSBuZXdTaXplOwogICAgICB9LAogICAgICBub2RlX29wczogewogICAgICAgIGdldGF0dHI6IGZ1bmN0aW9uIChub2RlKSB7CiAgICAgICAgICB2YXIgYXR0ciA9IHt9OwogICAgICAgICAgYXR0ci5kZXYgPSBGUy5pc0NocmRldihub2RlLm1vZGUpID8gbm9kZS5pZCA6IDE7CiAgICAgICAgICBhdHRyLmlubyA9IG5vZGUuaWQ7CiAgICAgICAgICBhdHRyLm1vZGUgPSBub2RlLm1vZGU7CiAgICAgICAgICBhdHRyLm5saW5rID0gMTsKICAgICAgICAgIGF0dHIudWlkID0gMDsKICAgICAgICAgIGF0dHIuZ2lkID0gMDsKICAgICAgICAgIGF0dHIucmRldiA9IG5vZGUucmRldjsKICAgICAgICAgIGlmIChGUy5pc0Rpcihub2RlLm1vZGUpKSB7CiAgICAgICAgICAgIGF0dHIuc2l6ZSA9IDQwOTY7CiAgICAgICAgICB9IGVsc2UgaWYgKEZTLmlzRmlsZShub2RlLm1vZGUpKSB7CiAgICAgICAgICAgIGF0dHIuc2l6ZSA9IG5vZGUudXNlZEJ5dGVzOwogICAgICAgICAgfSBlbHNlIGlmIChGUy5pc0xpbmsobm9kZS5tb2RlKSkgewogICAgICAgICAgICBhdHRyLnNpemUgPSBub2RlLmxpbmsubGVuZ3RoOwogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgYXR0ci5zaXplID0gMDsKICAgICAgICAgIH0KICAgICAgICAgIGF0dHIuYXRpbWUgPSBuZXcgRGF0ZShub2RlLnRpbWVzdGFtcCk7CiAgICAgICAgICBhdHRyLm10aW1lID0gbmV3IERhdGUobm9kZS50aW1lc3RhbXApOwogICAgICAgICAgYXR0ci5jdGltZSA9IG5ldyBEYXRlKG5vZGUudGltZXN0YW1wKTsKICAgICAgICAgIGF0dHIuYmxrc2l6ZSA9IDQwOTY7CiAgICAgICAgICBhdHRyLmJsb2NrcyA9IE1hdGguY2VpbChhdHRyLnNpemUgLyBhdHRyLmJsa3NpemUpOwogICAgICAgICAgcmV0dXJuIGF0dHIKICAgICAgICB9LAogICAgICAgIHNldGF0dHI6IGZ1bmN0aW9uIChub2RlLCBhdHRyKSB7CiAgICAgICAgICBpZiAoYXR0ci5tb2RlICE9PSB1bmRlZmluZWQpIHsKICAgICAgICAgICAgbm9kZS5tb2RlID0gYXR0ci5tb2RlOwogICAgICAgICAgfQogICAgICAgICAgaWYgKGF0dHIudGltZXN0YW1wICE9PSB1bmRlZmluZWQpIHsKICAgICAgICAgICAgbm9kZS50aW1lc3RhbXAgPSBhdHRyLnRpbWVzdGFtcDsKICAgICAgICAgIH0KICAgICAgICAgIGlmIChhdHRyLnNpemUgIT09IHVuZGVmaW5lZCkgewogICAgICAgICAgICBNRU1GUy5yZXNpemVGaWxlU3RvcmFnZShub2RlLCBhdHRyLnNpemUpOwogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgbG9va3VwOiBmdW5jdGlvbiAocGFyZW50LCBuYW1lKSB7CiAgICAgICAgICB0aHJvdyBGUy5nZW5lcmljRXJyb3JzW0VSUk5PX0NPREVTLkVOT0VOVF0KICAgICAgICB9LAogICAgICAgIG1rbm9kOiBmdW5jdGlvbiAocGFyZW50LCBuYW1lLCBtb2RlLCBkZXYpIHsKICAgICAgICAgIHJldHVybiBNRU1GUy5jcmVhdGVOb2RlKHBhcmVudCwgbmFtZSwgbW9kZSwgZGV2KQogICAgICAgIH0sCiAgICAgICAgcmVuYW1lOiBmdW5jdGlvbiAob2xkX25vZGUsIG5ld19kaXIsIG5ld19uYW1lKSB7CiAgICAgICAgICBpZiAoRlMuaXNEaXIob2xkX25vZGUubW9kZSkpIHsKICAgICAgICAgICAgdmFyIG5ld19ub2RlOwogICAgICAgICAgICB0cnkgewogICAgICAgICAgICAgIG5ld19ub2RlID0gRlMubG9va3VwTm9kZShuZXdfZGlyLCBuZXdfbmFtZSk7CiAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHt9CiAgICAgICAgICAgIGlmIChuZXdfbm9kZSkgewogICAgICAgICAgICAgIGZvciAodmFyIGkgaW4gbmV3X25vZGUuY29udGVudHMpIHsKICAgICAgICAgICAgICAgIHRocm93IG5ldyBGUy5FcnJub0Vycm9yKEVSUk5PX0NPREVTLkVOT1RFTVBUWSkKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIGRlbGV0ZSBvbGRfbm9kZS5wYXJlbnQuY29udGVudHNbb2xkX25vZGUubmFtZV07CiAgICAgICAgICBvbGRfbm9kZS5uYW1lID0gbmV3X25hbWU7CiAgICAgICAgICBuZXdfZGlyLmNvbnRlbnRzW25ld19uYW1lXSA9IG9sZF9ub2RlOwogICAgICAgICAgb2xkX25vZGUucGFyZW50ID0gbmV3X2RpcjsKICAgICAgICB9LAogICAgICAgIHVubGluazogZnVuY3Rpb24gKHBhcmVudCwgbmFtZSkgewogICAgICAgICAgZGVsZXRlIHBhcmVudC5jb250ZW50c1tuYW1lXTsKICAgICAgICB9LAogICAgICAgIHJtZGlyOiBmdW5jdGlvbiAocGFyZW50LCBuYW1lKSB7CiAgICAgICAgICB2YXIgbm9kZSA9IEZTLmxvb2t1cE5vZGUocGFyZW50LCBuYW1lKTsKICAgICAgICAgIGZvciAodmFyIGkgaW4gbm9kZS5jb250ZW50cykgewogICAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FTk9URU1QVFkpCiAgICAgICAgICB9CiAgICAgICAgICBkZWxldGUgcGFyZW50LmNvbnRlbnRzW25hbWVdOwogICAgICAgIH0sCiAgICAgICAgcmVhZGRpcjogZnVuY3Rpb24gKG5vZGUpIHsKICAgICAgICAgIHZhciBlbnRyaWVzID0gWycuJywgJy4uJ107CiAgICAgICAgICBmb3IgKHZhciBrZXkgaW4gbm9kZS5jb250ZW50cykgewogICAgICAgICAgICBpZiAoIW5vZGUuY29udGVudHMuaGFzT3duUHJvcGVydHkoa2V5KSkgewogICAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgICAgIH0KICAgICAgICAgICAgZW50cmllcy5wdXNoKGtleSk7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gZW50cmllcwogICAgICAgIH0sCiAgICAgICAgc3ltbGluazogZnVuY3Rpb24gKHBhcmVudCwgbmV3bmFtZSwgb2xkcGF0aCkgewogICAgICAgICAgdmFyIG5vZGUgPSBNRU1GUy5jcmVhdGVOb2RlKHBhcmVudCwgbmV3bmFtZSwgNTExIHwgNDA5NjAsIDApOwogICAgICAgICAgbm9kZS5saW5rID0gb2xkcGF0aDsKICAgICAgICAgIHJldHVybiBub2RlCiAgICAgICAgfSwKICAgICAgICByZWFkbGluazogZnVuY3Rpb24gKG5vZGUpIHsKICAgICAgICAgIGlmICghRlMuaXNMaW5rKG5vZGUubW9kZSkpIHsKICAgICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoRVJSTk9fQ09ERVMuRUlOVkFMKQogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIG5vZGUubGluawogICAgICAgIH0sCiAgICAgIH0sCiAgICAgIHN0cmVhbV9vcHM6IHsKICAgICAgICByZWFkOiBmdW5jdGlvbiAoc3RyZWFtLCBidWZmZXIsIG9mZnNldCwgbGVuZ3RoLCBwb3NpdGlvbikgewogICAgICAgICAgdmFyIGNvbnRlbnRzID0gc3RyZWFtLm5vZGUuY29udGVudHM7CiAgICAgICAgICBpZiAocG9zaXRpb24gPj0gc3RyZWFtLm5vZGUudXNlZEJ5dGVzKSByZXR1cm4gMAogICAgICAgICAgdmFyIHNpemUgPSBNYXRoLm1pbihzdHJlYW0ubm9kZS51c2VkQnl0ZXMgLSBwb3NpdGlvbiwgbGVuZ3RoKTsKICAgICAgICAgIGFzc2VydChzaXplID49IDApOwogICAgICAgICAgaWYgKHNpemUgPiA4ICYmIGNvbnRlbnRzLnN1YmFycmF5KSB7CiAgICAgICAgICAgIGJ1ZmZlci5zZXQoY29udGVudHMuc3ViYXJyYXkocG9zaXRpb24sIHBvc2l0aW9uICsgc2l6ZSksIG9mZnNldCk7CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHNpemU7IGkrKykgYnVmZmVyW29mZnNldCArIGldID0gY29udGVudHNbcG9zaXRpb24gKyBpXTsKICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiBzaXplCiAgICAgICAgfSwKICAgICAgICB3cml0ZTogZnVuY3Rpb24gKHN0cmVhbSwgYnVmZmVyLCBvZmZzZXQsIGxlbmd0aCwgcG9zaXRpb24sIGNhbk93bikgewogICAgICAgICAgaWYgKCFsZW5ndGgpIHJldHVybiAwCiAgICAgICAgICB2YXIgbm9kZSA9IHN0cmVhbS5ub2RlOwogICAgICAgICAgbm9kZS50aW1lc3RhbXAgPSBEYXRlLm5vdygpOwogICAgICAgICAgaWYgKGJ1ZmZlci5zdWJhcnJheSAmJiAoIW5vZGUuY29udGVudHMgfHwgbm9kZS5jb250ZW50cy5zdWJhcnJheSkpIHsKICAgICAgICAgICAgaWYgKGNhbk93bikgewogICAgICAgICAgICAgIG5vZGUuY29udGVudHMgPSBidWZmZXIuc3ViYXJyYXkob2Zmc2V0LCBvZmZzZXQgKyBsZW5ndGgpOwogICAgICAgICAgICAgIG5vZGUudXNlZEJ5dGVzID0gbGVuZ3RoOwogICAgICAgICAgICAgIHJldHVybiBsZW5ndGgKICAgICAgICAgICAgfSBlbHNlIGlmIChub2RlLnVzZWRCeXRlcyA9PT0gMCAmJiBwb3NpdGlvbiA9PT0gMCkgewogICAgICAgICAgICAgIG5vZGUuY29udGVudHMgPSBuZXcgVWludDhBcnJheShidWZmZXIuc3ViYXJyYXkob2Zmc2V0LCBvZmZzZXQgKyBsZW5ndGgpKTsKICAgICAgICAgICAgICBub2RlLnVzZWRCeXRlcyA9IGxlbmd0aDsKICAgICAgICAgICAgICByZXR1cm4gbGVuZ3RoCiAgICAgICAgICAgIH0gZWxzZSBpZiAocG9zaXRpb24gKyBsZW5ndGggPD0gbm9kZS51c2VkQnl0ZXMpIHsKICAgICAgICAgICAgICBub2RlLmNvbnRlbnRzLnNldChidWZmZXIuc3ViYXJyYXkob2Zmc2V0LCBvZmZzZXQgKyBsZW5ndGgpLCBwb3NpdGlvbik7CiAgICAgICAgICAgICAgcmV0dXJuIGxlbmd0aAogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBNRU1GUy5leHBhbmRGaWxlU3RvcmFnZShub2RlLCBwb3NpdGlvbiArIGxlbmd0aCk7CiAgICAgICAgICBpZiAobm9kZS5jb250ZW50cy5zdWJhcnJheSAmJiBidWZmZXIuc3ViYXJyYXkpCiAgICAgICAgICAgIG5vZGUuY29udGVudHMuc2V0KGJ1ZmZlci5zdWJhcnJheShvZmZzZXQsIG9mZnNldCArIGxlbmd0aCksIHBvc2l0aW9uKTsKICAgICAgICAgIGVsc2UgewogICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7CiAgICAgICAgICAgICAgbm9kZS5jb250ZW50c1twb3NpdGlvbiArIGldID0gYnVmZmVyW29mZnNldCArIGldOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBub2RlLnVzZWRCeXRlcyA9IE1hdGgubWF4KG5vZGUudXNlZEJ5dGVzLCBwb3NpdGlvbiArIGxlbmd0aCk7CiAgICAgICAgICByZXR1cm4gbGVuZ3RoCiAgICAgICAgfSwKICAgICAgICBsbHNlZWs6IGZ1bmN0aW9uIChzdHJlYW0sIG9mZnNldCwgd2hlbmNlKSB7CiAgICAgICAgICB2YXIgcG9zaXRpb24gPSBvZmZzZXQ7CiAgICAgICAgICBpZiAod2hlbmNlID09PSAxKSB7CiAgICAgICAgICAgIHBvc2l0aW9uICs9IHN0cmVhbS5wb3NpdGlvbjsKICAgICAgICAgIH0gZWxzZSBpZiAod2hlbmNlID09PSAyKSB7CiAgICAgICAgICAgIGlmIChGUy5pc0ZpbGUoc3RyZWFtLm5vZGUubW9kZSkpIHsKICAgICAgICAgICAgICBwb3NpdGlvbiArPSBzdHJlYW0ubm9kZS51c2VkQnl0ZXM7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIGlmIChwb3NpdGlvbiA8IDApIHsKICAgICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoRVJSTk9fQ09ERVMuRUlOVkFMKQogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIHBvc2l0aW9uCiAgICAgICAgfSwKICAgICAgICBhbGxvY2F0ZTogZnVuY3Rpb24gKHN0cmVhbSwgb2Zmc2V0LCBsZW5ndGgpIHsKICAgICAgICAgIE1FTUZTLmV4cGFuZEZpbGVTdG9yYWdlKHN0cmVhbS5ub2RlLCBvZmZzZXQgKyBsZW5ndGgpOwogICAgICAgICAgc3RyZWFtLm5vZGUudXNlZEJ5dGVzID0gTWF0aC5tYXgoc3RyZWFtLm5vZGUudXNlZEJ5dGVzLCBvZmZzZXQgKyBsZW5ndGgpOwogICAgICAgIH0sCiAgICAgICAgbW1hcDogZnVuY3Rpb24gKHN0cmVhbSwgYnVmZmVyLCBvZmZzZXQsIGxlbmd0aCwgcG9zaXRpb24sIHByb3QsIGZsYWdzKSB7CiAgICAgICAgICBpZiAoIUZTLmlzRmlsZShzdHJlYW0ubm9kZS5tb2RlKSkgewogICAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FTk9ERVYpCiAgICAgICAgICB9CiAgICAgICAgICB2YXIgcHRyOwogICAgICAgICAgdmFyIGFsbG9jYXRlZDsKICAgICAgICAgIHZhciBjb250ZW50cyA9IHN0cmVhbS5ub2RlLmNvbnRlbnRzOwogICAgICAgICAgaWYgKCEoZmxhZ3MgJiAyKSAmJiAoY29udGVudHMuYnVmZmVyID09PSBidWZmZXIgfHwgY29udGVudHMuYnVmZmVyID09PSBidWZmZXIuYnVmZmVyKSkgewogICAgICAgICAgICBhbGxvY2F0ZWQgPSBmYWxzZTsKICAgICAgICAgICAgcHRyID0gY29udGVudHMuYnl0ZU9mZnNldDsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIGlmIChwb3NpdGlvbiA+IDAgfHwgcG9zaXRpb24gKyBsZW5ndGggPCBzdHJlYW0ubm9kZS51c2VkQnl0ZXMpIHsKICAgICAgICAgICAgICBpZiAoY29udGVudHMuc3ViYXJyYXkpIHsKICAgICAgICAgICAgICAgIGNvbnRlbnRzID0gY29udGVudHMuc3ViYXJyYXkocG9zaXRpb24sIHBvc2l0aW9uICsgbGVuZ3RoKTsKICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgY29udGVudHMgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChjb250ZW50cywgcG9zaXRpb24sIHBvc2l0aW9uICsgbGVuZ3RoKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgYWxsb2NhdGVkID0gdHJ1ZTsKICAgICAgICAgICAgcHRyID0gX21hbGxvYyhsZW5ndGgpOwogICAgICAgICAgICBpZiAoIXB0cikgewogICAgICAgICAgICAgIHRocm93IG5ldyBGUy5FcnJub0Vycm9yKEVSUk5PX0NPREVTLkVOT01FTSkKICAgICAgICAgICAgfQogICAgICAgICAgICBidWZmZXIuc2V0KGNvbnRlbnRzLCBwdHIpOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIHsgcHRyOiBwdHIsIGFsbG9jYXRlZDogYWxsb2NhdGVkIH0KICAgICAgICB9LAogICAgICAgIG1zeW5jOiBmdW5jdGlvbiAoc3RyZWFtLCBidWZmZXIsIG9mZnNldCwgbGVuZ3RoLCBtbWFwRmxhZ3MpIHsKICAgICAgICAgIGlmICghRlMuaXNGaWxlKHN0cmVhbS5ub2RlLm1vZGUpKSB7CiAgICAgICAgICAgIHRocm93IG5ldyBGUy5FcnJub0Vycm9yKEVSUk5PX0NPREVTLkVOT0RFVikKICAgICAgICAgIH0KICAgICAgICAgIGlmIChtbWFwRmxhZ3MgJiAyKSB7CiAgICAgICAgICAgIHJldHVybiAwCiAgICAgICAgICB9CiAgICAgICAgICBNRU1GUy5zdHJlYW1fb3BzLndyaXRlKHN0cmVhbSwgYnVmZmVyLCAwLCBsZW5ndGgsIG9mZnNldCwgZmFsc2UpOwogICAgICAgICAgcmV0dXJuIDAKICAgICAgICB9LAogICAgICB9LAogICAgfTsKICAgIHZhciBJREJGUyA9IHsKICAgICAgZGJzOiB7fSwKICAgICAgaW5kZXhlZERCOiBmdW5jdGlvbiAoKSB7CiAgICAgICAgaWYgKHR5cGVvZiBpbmRleGVkREIgIT09ICd1bmRlZmluZWQnKSByZXR1cm4gaW5kZXhlZERCCiAgICAgICAgdmFyIHJldCA9IG51bGw7CiAgICAgICAgaWYgKHR5cGVvZiB3aW5kb3cgPT09ICdvYmplY3QnKQogICAgICAgICAgcmV0ID0gd2luZG93LmluZGV4ZWREQiB8fCB3aW5kb3cubW96SW5kZXhlZERCIHx8IHdpbmRvdy53ZWJraXRJbmRleGVkREIgfHwgd2luZG93Lm1zSW5kZXhlZERCOwogICAgICAgIGFzc2VydChyZXQsICdJREJGUyB1c2VkLCBidXQgaW5kZXhlZERCIG5vdCBzdXBwb3J0ZWQnKTsKICAgICAgICByZXR1cm4gcmV0CiAgICAgIH0sCiAgICAgIERCX1ZFUlNJT046IDIxLAogICAgICBEQl9TVE9SRV9OQU1FOiAnRklMRV9EQVRBJywKICAgICAgbW91bnQ6IGZ1bmN0aW9uIChtb3VudCkgewogICAgICAgIHJldHVybiBNRU1GUy5tb3VudC5hcHBseShudWxsLCBhcmd1bWVudHMpCiAgICAgIH0sCiAgICAgIHN5bmNmczogZnVuY3Rpb24gKG1vdW50LCBwb3B1bGF0ZSwgY2FsbGJhY2spIHsKICAgICAgICBJREJGUy5nZXRMb2NhbFNldChtb3VudCwgZnVuY3Rpb24gKGVyciwgbG9jYWwpIHsKICAgICAgICAgIGlmIChlcnIpIHJldHVybiBjYWxsYmFjayhlcnIpCiAgICAgICAgICBJREJGUy5nZXRSZW1vdGVTZXQobW91bnQsIGZ1bmN0aW9uIChlcnIsIHJlbW90ZSkgewogICAgICAgICAgICBpZiAoZXJyKSByZXR1cm4gY2FsbGJhY2soZXJyKQogICAgICAgICAgICB2YXIgc3JjID0gcG9wdWxhdGUgPyByZW1vdGUgOiBsb2NhbDsKICAgICAgICAgICAgdmFyIGRzdCA9IHBvcHVsYXRlID8gbG9jYWwgOiByZW1vdGU7CiAgICAgICAgICAgIElEQkZTLnJlY29uY2lsZShzcmMsIGRzdCwgY2FsbGJhY2spOwogICAgICAgICAgfSk7CiAgICAgICAgfSk7CiAgICAgIH0sCiAgICAgIGdldERCOiBmdW5jdGlvbiAobmFtZSwgY2FsbGJhY2spIHsKICAgICAgICB2YXIgZGIgPSBJREJGUy5kYnNbbmFtZV07CiAgICAgICAgaWYgKGRiKSB7CiAgICAgICAgICByZXR1cm4gY2FsbGJhY2sobnVsbCwgZGIpCiAgICAgICAgfQogICAgICAgIHZhciByZXE7CiAgICAgICAgdHJ5IHsKICAgICAgICAgIHJlcSA9IElEQkZTLmluZGV4ZWREQigpLm9wZW4obmFtZSwgSURCRlMuREJfVkVSU0lPTik7CiAgICAgICAgfSBjYXRjaCAoZSkgewogICAgICAgICAgcmV0dXJuIGNhbGxiYWNrKGUpCiAgICAgICAgfQogICAgICAgIGlmICghcmVxKSB7CiAgICAgICAgICByZXR1cm4gY2FsbGJhY2soJ1VuYWJsZSB0byBjb25uZWN0IHRvIEluZGV4ZWREQicpCiAgICAgICAgfQogICAgICAgIHJlcS5vbnVwZ3JhZGVuZWVkZWQgPSBmdW5jdGlvbiAoZSkgewogICAgICAgICAgdmFyIGRiID0gZS50YXJnZXQucmVzdWx0OwogICAgICAgICAgdmFyIHRyYW5zYWN0aW9uID0gZS50YXJnZXQudHJhbnNhY3Rpb247CiAgICAgICAgICB2YXIgZmlsZVN0b3JlOwogICAgICAgICAgaWYgKGRiLm9iamVjdFN0b3JlTmFtZXMuY29udGFpbnMoSURCRlMuREJfU1RPUkVfTkFNRSkpIHsKICAgICAgICAgICAgZmlsZVN0b3JlID0gdHJhbnNhY3Rpb24ub2JqZWN0U3RvcmUoSURCRlMuREJfU1RPUkVfTkFNRSk7CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBmaWxlU3RvcmUgPSBkYi5jcmVhdGVPYmplY3RTdG9yZShJREJGUy5EQl9TVE9SRV9OQU1FKTsKICAgICAgICAgIH0KICAgICAgICAgIGlmICghZmlsZVN0b3JlLmluZGV4TmFtZXMuY29udGFpbnMoJ3RpbWVzdGFtcCcpKSB7CiAgICAgICAgICAgIGZpbGVTdG9yZS5jcmVhdGVJbmRleCgndGltZXN0YW1wJywgJ3RpbWVzdGFtcCcsIHsgdW5pcXVlOiBmYWxzZSB9KTsKICAgICAgICAgIH0KICAgICAgICB9OwogICAgICAgIHJlcS5vbnN1Y2Nlc3MgPSBmdW5jdGlvbiAoKSB7CiAgICAgICAgICBkYiA9IHJlcS5yZXN1bHQ7CiAgICAgICAgICBJREJGUy5kYnNbbmFtZV0gPSBkYjsKICAgICAgICAgIGNhbGxiYWNrKG51bGwsIGRiKTsKICAgICAgICB9OwogICAgICAgIHJlcS5vbmVycm9yID0gZnVuY3Rpb24gKGUpIHsKICAgICAgICAgIGNhbGxiYWNrKHRoaXMuZXJyb3IpOwogICAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpOwogICAgICAgIH07CiAgICAgIH0sCiAgICAgIGdldExvY2FsU2V0OiBmdW5jdGlvbiAobW91bnQsIGNhbGxiYWNrKSB7CiAgICAgICAgdmFyIGVudHJpZXMgPSB7fTsKICAgICAgICBmdW5jdGlvbiBpc1JlYWxEaXIocCkgewogICAgICAgICAgcmV0dXJuIHAgIT09ICcuJyAmJiBwICE9PSAnLi4nCiAgICAgICAgfQogICAgICAgIGZ1bmN0aW9uIHRvQWJzb2x1dGUocm9vdCkgewogICAgICAgICAgcmV0dXJuIGZ1bmN0aW9uIChwKSB7CiAgICAgICAgICAgIHJldHVybiBQQVRILmpvaW4yKHJvb3QsIHApCiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHZhciBjaGVjayA9IEZTLnJlYWRkaXIobW91bnQubW91bnRwb2ludCkuZmlsdGVyKGlzUmVhbERpcikubWFwKHRvQWJzb2x1dGUobW91bnQubW91bnRwb2ludCkpOwogICAgICAgIHdoaWxlIChjaGVjay5sZW5ndGgpIHsKICAgICAgICAgIHZhciBwYXRoID0gY2hlY2sucG9wKCk7CiAgICAgICAgICB2YXIgc3RhdDsKICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgIHN0YXQgPSBGUy5zdGF0KHBhdGgpOwogICAgICAgICAgfSBjYXRjaCAoZSkgewogICAgICAgICAgICByZXR1cm4gY2FsbGJhY2soZSkKICAgICAgICAgIH0KICAgICAgICAgIGlmIChGUy5pc0RpcihzdGF0Lm1vZGUpKSB7CiAgICAgICAgICAgIGNoZWNrLnB1c2guYXBwbHkoY2hlY2ssIEZTLnJlYWRkaXIocGF0aCkuZmlsdGVyKGlzUmVhbERpcikubWFwKHRvQWJzb2x1dGUocGF0aCkpKTsKICAgICAgICAgIH0KICAgICAgICAgIGVudHJpZXNbcGF0aF0gPSB7IHRpbWVzdGFtcDogc3RhdC5tdGltZSB9OwogICAgICAgIH0KICAgICAgICByZXR1cm4gY2FsbGJhY2sobnVsbCwgeyB0eXBlOiAnbG9jYWwnLCBlbnRyaWVzOiBlbnRyaWVzIH0pCiAgICAgIH0sCiAgICAgIGdldFJlbW90ZVNldDogZnVuY3Rpb24gKG1vdW50LCBjYWxsYmFjaykgewogICAgICAgIHZhciBlbnRyaWVzID0ge307CiAgICAgICAgSURCRlMuZ2V0REIobW91bnQubW91bnRwb2ludCwgZnVuY3Rpb24gKGVyciwgZGIpIHsKICAgICAgICAgIGlmIChlcnIpIHJldHVybiBjYWxsYmFjayhlcnIpCiAgICAgICAgICB0cnkgewogICAgICAgICAgICB2YXIgdHJhbnNhY3Rpb24gPSBkYi50cmFuc2FjdGlvbihbSURCRlMuREJfU1RPUkVfTkFNRV0sICdyZWFkb25seScpOwogICAgICAgICAgICB0cmFuc2FjdGlvbi5vbmVycm9yID0gZnVuY3Rpb24gKGUpIHsKICAgICAgICAgICAgICBjYWxsYmFjayh0aGlzLmVycm9yKTsKICAgICAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7CiAgICAgICAgICAgIH07CiAgICAgICAgICAgIHZhciBzdG9yZSA9IHRyYW5zYWN0aW9uLm9iamVjdFN0b3JlKElEQkZTLkRCX1NUT1JFX05BTUUpOwogICAgICAgICAgICB2YXIgaW5kZXggPSBzdG9yZS5pbmRleCgndGltZXN0YW1wJyk7CiAgICAgICAgICAgIGluZGV4Lm9wZW5LZXlDdXJzb3IoKS5vbnN1Y2Nlc3MgPSBmdW5jdGlvbiAoZXZlbnQpIHsKICAgICAgICAgICAgICB2YXIgY3Vyc29yID0gZXZlbnQudGFyZ2V0LnJlc3VsdDsKICAgICAgICAgICAgICBpZiAoIWN1cnNvcikgewogICAgICAgICAgICAgICAgcmV0dXJuIGNhbGxiYWNrKG51bGwsIHsgdHlwZTogJ3JlbW90ZScsIGRiOiBkYiwgZW50cmllczogZW50cmllcyB9KQogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBlbnRyaWVzW2N1cnNvci5wcmltYXJ5S2V5XSA9IHsgdGltZXN0YW1wOiBjdXJzb3Iua2V5IH07CiAgICAgICAgICAgICAgY3Vyc29yLmNvbnRpbnVlKCk7CiAgICAgICAgICAgIH07CiAgICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICAgIHJldHVybiBjYWxsYmFjayhlKQogICAgICAgICAgfQogICAgICAgIH0pOwogICAgICB9LAogICAgICBsb2FkTG9jYWxFbnRyeTogZnVuY3Rpb24gKHBhdGgsIGNhbGxiYWNrKSB7CiAgICAgICAgdmFyIHN0YXQsIG5vZGU7CiAgICAgICAgdHJ5IHsKICAgICAgICAgIHZhciBsb29rdXAgPSBGUy5sb29rdXBQYXRoKHBhdGgpOwogICAgICAgICAgbm9kZSA9IGxvb2t1cC5ub2RlOwogICAgICAgICAgc3RhdCA9IEZTLnN0YXQocGF0aCk7CiAgICAgICAgfSBjYXRjaCAoZSkgewogICAgICAgICAgcmV0dXJuIGNhbGxiYWNrKGUpCiAgICAgICAgfQogICAgICAgIGlmIChGUy5pc0RpcihzdGF0Lm1vZGUpKSB7CiAgICAgICAgICByZXR1cm4gY2FsbGJhY2sobnVsbCwgeyB0aW1lc3RhbXA6IHN0YXQubXRpbWUsIG1vZGU6IHN0YXQubW9kZSB9KQogICAgICAgIH0gZWxzZSBpZiAoRlMuaXNGaWxlKHN0YXQubW9kZSkpIHsKICAgICAgICAgIG5vZGUuY29udGVudHMgPSBNRU1GUy5nZXRGaWxlRGF0YUFzVHlwZWRBcnJheShub2RlKTsKICAgICAgICAgIHJldHVybiBjYWxsYmFjayhudWxsLCB7IHRpbWVzdGFtcDogc3RhdC5tdGltZSwgbW9kZTogc3RhdC5tb2RlLCBjb250ZW50czogbm9kZS5jb250ZW50cyB9KQogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICByZXR1cm4gY2FsbGJhY2sobmV3IEVycm9yKCdub2RlIHR5cGUgbm90IHN1cHBvcnRlZCcpKQogICAgICAgIH0KICAgICAgfSwKICAgICAgc3RvcmVMb2NhbEVudHJ5OiBmdW5jdGlvbiAocGF0aCwgZW50cnksIGNhbGxiYWNrKSB7CiAgICAgICAgdHJ5IHsKICAgICAgICAgIGlmIChGUy5pc0RpcihlbnRyeS5tb2RlKSkgewogICAgICAgICAgICBGUy5ta2RpcihwYXRoLCBlbnRyeS5tb2RlKTsKICAgICAgICAgIH0gZWxzZSBpZiAoRlMuaXNGaWxlKGVudHJ5Lm1vZGUpKSB7CiAgICAgICAgICAgIEZTLndyaXRlRmlsZShwYXRoLCBlbnRyeS5jb250ZW50cywgeyBjYW5Pd246IHRydWUgfSk7CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICByZXR1cm4gY2FsbGJhY2sobmV3IEVycm9yKCdub2RlIHR5cGUgbm90IHN1cHBvcnRlZCcpKQogICAgICAgICAgfQogICAgICAgICAgRlMuY2htb2QocGF0aCwgZW50cnkubW9kZSk7CiAgICAgICAgICBGUy51dGltZShwYXRoLCBlbnRyeS50aW1lc3RhbXAsIGVudHJ5LnRpbWVzdGFtcCk7CiAgICAgICAgfSBjYXRjaCAoZSkgewogICAgICAgICAgcmV0dXJuIGNhbGxiYWNrKGUpCiAgICAgICAgfQogICAgICAgIGNhbGxiYWNrKG51bGwpOwogICAgICB9LAogICAgICByZW1vdmVMb2NhbEVudHJ5OiBmdW5jdGlvbiAocGF0aCwgY2FsbGJhY2spIHsKICAgICAgICB0cnkgewogICAgICAgICAgdmFyIGxvb2t1cCA9IEZTLmxvb2t1cFBhdGgocGF0aCk7CiAgICAgICAgICB2YXIgc3RhdCA9IEZTLnN0YXQocGF0aCk7CiAgICAgICAgICBpZiAoRlMuaXNEaXIoc3RhdC5tb2RlKSkgewogICAgICAgICAgICBGUy5ybWRpcihwYXRoKTsKICAgICAgICAgIH0gZWxzZSBpZiAoRlMuaXNGaWxlKHN0YXQubW9kZSkpIHsKICAgICAgICAgICAgRlMudW5saW5rKHBhdGgpOwogICAgICAgICAgfQogICAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICAgIHJldHVybiBjYWxsYmFjayhlKQogICAgICAgIH0KICAgICAgICBjYWxsYmFjayhudWxsKTsKICAgICAgfSwKICAgICAgbG9hZFJlbW90ZUVudHJ5OiBmdW5jdGlvbiAoc3RvcmUsIHBhdGgsIGNhbGxiYWNrKSB7CiAgICAgICAgdmFyIHJlcSA9IHN0b3JlLmdldChwYXRoKTsKICAgICAgICByZXEub25zdWNjZXNzID0gZnVuY3Rpb24gKGV2ZW50KSB7CiAgICAgICAgICBjYWxsYmFjayhudWxsLCBldmVudC50YXJnZXQucmVzdWx0KTsKICAgICAgICB9OwogICAgICAgIHJlcS5vbmVycm9yID0gZnVuY3Rpb24gKGUpIHsKICAgICAgICAgIGNhbGxiYWNrKHRoaXMuZXJyb3IpOwogICAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpOwogICAgICAgIH07CiAgICAgIH0sCiAgICAgIHN0b3JlUmVtb3RlRW50cnk6IGZ1bmN0aW9uIChzdG9yZSwgcGF0aCwgZW50cnksIGNhbGxiYWNrKSB7CiAgICAgICAgdmFyIHJlcSA9IHN0b3JlLnB1dChlbnRyeSwgcGF0aCk7CiAgICAgICAgcmVxLm9uc3VjY2VzcyA9IGZ1bmN0aW9uICgpIHsKICAgICAgICAgIGNhbGxiYWNrKG51bGwpOwogICAgICAgIH07CiAgICAgICAgcmVxLm9uZXJyb3IgPSBmdW5jdGlvbiAoZSkgewogICAgICAgICAgY2FsbGJhY2sodGhpcy5lcnJvcik7CiAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7CiAgICAgICAgfTsKICAgICAgfSwKICAgICAgcmVtb3ZlUmVtb3RlRW50cnk6IGZ1bmN0aW9uIChzdG9yZSwgcGF0aCwgY2FsbGJhY2spIHsKICAgICAgICB2YXIgcmVxID0gc3RvcmUuZGVsZXRlKHBhdGgpOwogICAgICAgIHJlcS5vbnN1Y2Nlc3MgPSBmdW5jdGlvbiAoKSB7CiAgICAgICAgICBjYWxsYmFjayhudWxsKTsKICAgICAgICB9OwogICAgICAgIHJlcS5vbmVycm9yID0gZnVuY3Rpb24gKGUpIHsKICAgICAgICAgIGNhbGxiYWNrKHRoaXMuZXJyb3IpOwogICAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpOwogICAgICAgIH07CiAgICAgIH0sCiAgICAgIHJlY29uY2lsZTogZnVuY3Rpb24gKHNyYywgZHN0LCBjYWxsYmFjaykgewogICAgICAgIHZhciB0b3RhbCA9IDA7CiAgICAgICAgdmFyIGNyZWF0ZSA9IFtdOwogICAgICAgIE9iamVjdC5rZXlzKHNyYy5lbnRyaWVzKS5mb3JFYWNoKGZ1bmN0aW9uIChrZXkpIHsKICAgICAgICAgIHZhciBlID0gc3JjLmVudHJpZXNba2V5XTsKICAgICAgICAgIHZhciBlMiA9IGRzdC5lbnRyaWVzW2tleV07CiAgICAgICAgICBpZiAoIWUyIHx8IGUudGltZXN0YW1wID4gZTIudGltZXN0YW1wKSB7CiAgICAgICAgICAgIGNyZWF0ZS5wdXNoKGtleSk7CiAgICAgICAgICAgIHRvdGFsKys7CiAgICAgICAgICB9CiAgICAgICAgfSk7CiAgICAgICAgdmFyIHJlbW92ZSA9IFtdOwogICAgICAgIE9iamVjdC5rZXlzKGRzdC5lbnRyaWVzKS5mb3JFYWNoKGZ1bmN0aW9uIChrZXkpIHsKICAgICAgICAgIGRzdC5lbnRyaWVzW2tleV07CiAgICAgICAgICB2YXIgZTIgPSBzcmMuZW50cmllc1trZXldOwogICAgICAgICAgaWYgKCFlMikgewogICAgICAgICAgICByZW1vdmUucHVzaChrZXkpOwogICAgICAgICAgICB0b3RhbCsrOwogICAgICAgICAgfQogICAgICAgIH0pOwogICAgICAgIGlmICghdG90YWwpIHsKICAgICAgICAgIHJldHVybiBjYWxsYmFjayhudWxsKQogICAgICAgIH0KICAgICAgICB2YXIgY29tcGxldGVkID0gMDsKICAgICAgICB2YXIgZGIgPSBzcmMudHlwZSA9PT0gJ3JlbW90ZScgPyBzcmMuZGIgOiBkc3QuZGI7CiAgICAgICAgdmFyIHRyYW5zYWN0aW9uID0gZGIudHJhbnNhY3Rpb24oW0lEQkZTLkRCX1NUT1JFX05BTUVdLCAncmVhZHdyaXRlJyk7CiAgICAgICAgdmFyIHN0b3JlID0gdHJhbnNhY3Rpb24ub2JqZWN0U3RvcmUoSURCRlMuREJfU1RPUkVfTkFNRSk7CiAgICAgICAgZnVuY3Rpb24gZG9uZShlcnIpIHsKICAgICAgICAgIGlmIChlcnIpIHsKICAgICAgICAgICAgaWYgKCFkb25lLmVycm9yZWQpIHsKICAgICAgICAgICAgICBkb25lLmVycm9yZWQgPSB0cnVlOwogICAgICAgICAgICAgIHJldHVybiBjYWxsYmFjayhlcnIpCiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuCiAgICAgICAgICB9CiAgICAgICAgICBpZiAoKytjb21wbGV0ZWQgPj0gdG90YWwpIHsKICAgICAgICAgICAgcmV0dXJuIGNhbGxiYWNrKG51bGwpCiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHRyYW5zYWN0aW9uLm9uZXJyb3IgPSBmdW5jdGlvbiAoZSkgewogICAgICAgICAgZG9uZSh0aGlzLmVycm9yKTsKICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTsKICAgICAgICB9OwogICAgICAgIGNyZWF0ZS5zb3J0KCkuZm9yRWFjaChmdW5jdGlvbiAocGF0aCkgewogICAgICAgICAgaWYgKGRzdC50eXBlID09PSAnbG9jYWwnKSB7CiAgICAgICAgICAgIElEQkZTLmxvYWRSZW1vdGVFbnRyeShzdG9yZSwgcGF0aCwgZnVuY3Rpb24gKGVyciwgZW50cnkpIHsKICAgICAgICAgICAgICBpZiAoZXJyKSByZXR1cm4gZG9uZShlcnIpCiAgICAgICAgICAgICAgSURCRlMuc3RvcmVMb2NhbEVudHJ5KHBhdGgsIGVudHJ5LCBkb25lKTsKICAgICAgICAgICAgfSk7CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBJREJGUy5sb2FkTG9jYWxFbnRyeShwYXRoLCBmdW5jdGlvbiAoZXJyLCBlbnRyeSkgewogICAgICAgICAgICAgIGlmIChlcnIpIHJldHVybiBkb25lKGVycikKICAgICAgICAgICAgICBJREJGUy5zdG9yZVJlbW90ZUVudHJ5KHN0b3JlLCBwYXRoLCBlbnRyeSwgZG9uZSk7CiAgICAgICAgICAgIH0pOwogICAgICAgICAgfQogICAgICAgIH0pOwogICAgICAgIHJlbW92ZQogICAgICAgICAgLnNvcnQoKQogICAgICAgICAgLnJldmVyc2UoKQogICAgICAgICAgLmZvckVhY2goZnVuY3Rpb24gKHBhdGgpIHsKICAgICAgICAgICAgaWYgKGRzdC50eXBlID09PSAnbG9jYWwnKSB7CiAgICAgICAgICAgICAgSURCRlMucmVtb3ZlTG9jYWxFbnRyeShwYXRoLCBkb25lKTsKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICBJREJGUy5yZW1vdmVSZW1vdGVFbnRyeShzdG9yZSwgcGF0aCwgZG9uZSk7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0pOwogICAgICB9LAogICAgfTsKICAgIHZhciBOT0RFRlMgPSB7CiAgICAgIGlzV2luZG93czogZmFsc2UsCiAgICAgIHN0YXRpY0luaXQ6IGZ1bmN0aW9uICgpIHsKICAgICAgICBOT0RFRlMuaXNXaW5kb3dzID0gISFwcm9jZXNzLnBsYXRmb3JtLm1hdGNoKC9ed2luLyk7CiAgICAgICAgdmFyIGZsYWdzID0gcHJvY2Vzc1snYmluZGluZyddKCdjb25zdGFudHMnKTsKICAgICAgICBpZiAoZmxhZ3NbJ2ZzJ10pIHsKICAgICAgICAgIGZsYWdzID0gZmxhZ3NbJ2ZzJ107CiAgICAgICAgfQogICAgICAgIE5PREVGUy5mbGFnc0Zvck5vZGVNYXAgPSB7CiAgICAgICAgICAxMDI0OiBmbGFnc1snT19BUFBFTkQnXSwKICAgICAgICAgIDY0OiBmbGFnc1snT19DUkVBVCddLAogICAgICAgICAgMTI4OiBmbGFnc1snT19FWENMJ10sCiAgICAgICAgICAwOiBmbGFnc1snT19SRE9OTFknXSwKICAgICAgICAgIDI6IGZsYWdzWydPX1JEV1InXSwKICAgICAgICAgIDQwOTY6IGZsYWdzWydPX1NZTkMnXSwKICAgICAgICAgIDUxMjogZmxhZ3NbJ09fVFJVTkMnXSwKICAgICAgICAgIDE6IGZsYWdzWydPX1dST05MWSddLAogICAgICAgIH07CiAgICAgIH0sCiAgICAgIGJ1ZmZlckZyb206IGZ1bmN0aW9uIChhcnJheUJ1ZmZlcikgewogICAgICAgIHJldHVybiBCdWZmZXIuYWxsb2MgPyBCdWZmZXIuZnJvbShhcnJheUJ1ZmZlcikgOiBuZXcgQnVmZmVyKGFycmF5QnVmZmVyKQogICAgICB9LAogICAgICBtb3VudDogZnVuY3Rpb24gKG1vdW50KSB7CiAgICAgICAgYXNzZXJ0KEVOVklST05NRU5UX0lTX05PREUpOwogICAgICAgIHJldHVybiBOT0RFRlMuY3JlYXRlTm9kZShudWxsLCAnLycsIE5PREVGUy5nZXRNb2RlKG1vdW50Lm9wdHMucm9vdCksIDApCiAgICAgIH0sCiAgICAgIGNyZWF0ZU5vZGU6IGZ1bmN0aW9uIChwYXJlbnQsIG5hbWUsIG1vZGUsIGRldikgewogICAgICAgIGlmICghRlMuaXNEaXIobW9kZSkgJiYgIUZTLmlzRmlsZShtb2RlKSAmJiAhRlMuaXNMaW5rKG1vZGUpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FSU5WQUwpCiAgICAgICAgfQogICAgICAgIHZhciBub2RlID0gRlMuY3JlYXRlTm9kZShwYXJlbnQsIG5hbWUsIG1vZGUpOwogICAgICAgIG5vZGUubm9kZV9vcHMgPSBOT0RFRlMubm9kZV9vcHM7CiAgICAgICAgbm9kZS5zdHJlYW1fb3BzID0gTk9ERUZTLnN0cmVhbV9vcHM7CiAgICAgICAgcmV0dXJuIG5vZGUKICAgICAgfSwKICAgICAgZ2V0TW9kZTogZnVuY3Rpb24gKHBhdGgpIHsKICAgICAgICB2YXIgc3RhdDsKICAgICAgICB0cnkgewogICAgICAgICAgc3RhdCA9IGZzLmxzdGF0U3luYyhwYXRoKTsKICAgICAgICAgIGlmIChOT0RFRlMuaXNXaW5kb3dzKSB7CiAgICAgICAgICAgIHN0YXQubW9kZSA9IHN0YXQubW9kZSB8ICgoc3RhdC5tb2RlICYgMjkyKSA+PiAyKTsKICAgICAgICAgIH0KICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICBpZiAoIWUuY29kZSkgdGhyb3cgZQogICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoRVJSTk9fQ09ERVNbZS5jb2RlXSkKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHN0YXQubW9kZQogICAgICB9LAogICAgICByZWFsUGF0aDogZnVuY3Rpb24gKG5vZGUpIHsKICAgICAgICB2YXIgcGFydHMgPSBbXTsKICAgICAgICB3aGlsZSAobm9kZS5wYXJlbnQgIT09IG5vZGUpIHsKICAgICAgICAgIHBhcnRzLnB1c2gobm9kZS5uYW1lKTsKICAgICAgICAgIG5vZGUgPSBub2RlLnBhcmVudDsKICAgICAgICB9CiAgICAgICAgcGFydHMucHVzaChub2RlLm1vdW50Lm9wdHMucm9vdCk7CiAgICAgICAgcGFydHMucmV2ZXJzZSgpOwogICAgICAgIHJldHVybiBQQVRILmpvaW4uYXBwbHkobnVsbCwgcGFydHMpCiAgICAgIH0sCiAgICAgIGZsYWdzRm9yTm9kZTogZnVuY3Rpb24gKGZsYWdzKSB7CiAgICAgICAgZmxhZ3MgJj0gfjIwOTcxNTI7CiAgICAgICAgZmxhZ3MgJj0gfjIwNDg7CiAgICAgICAgZmxhZ3MgJj0gfjMyNzY4OwogICAgICAgIGZsYWdzICY9IH41MjQyODg7CiAgICAgICAgdmFyIG5ld0ZsYWdzID0gMDsKICAgICAgICBmb3IgKHZhciBrIGluIE5PREVGUy5mbGFnc0Zvck5vZGVNYXApIHsKICAgICAgICAgIGlmIChmbGFncyAmIGspIHsKICAgICAgICAgICAgbmV3RmxhZ3MgfD0gTk9ERUZTLmZsYWdzRm9yTm9kZU1hcFtrXTsKICAgICAgICAgICAgZmxhZ3MgXj0gazsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgaWYgKCFmbGFncykgewogICAgICAgICAgcmV0dXJuIG5ld0ZsYWdzCiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIHRocm93IG5ldyBGUy5FcnJub0Vycm9yKEVSUk5PX0NPREVTLkVJTlZBTCkKICAgICAgICB9CiAgICAgIH0sCiAgICAgIG5vZGVfb3BzOiB7CiAgICAgICAgZ2V0YXR0cjogZnVuY3Rpb24gKG5vZGUpIHsKICAgICAgICAgIHZhciBwYXRoID0gTk9ERUZTLnJlYWxQYXRoKG5vZGUpOwogICAgICAgICAgdmFyIHN0YXQ7CiAgICAgICAgICB0cnkgewogICAgICAgICAgICBzdGF0ID0gZnMubHN0YXRTeW5jKHBhdGgpOwogICAgICAgICAgfSBjYXRjaCAoZSkgewogICAgICAgICAgICBpZiAoIWUuY29kZSkgdGhyb3cgZQogICAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFU1tlLmNvZGVdKQogICAgICAgICAgfQogICAgICAgICAgaWYgKE5PREVGUy5pc1dpbmRvd3MgJiYgIXN0YXQuYmxrc2l6ZSkgewogICAgICAgICAgICBzdGF0LmJsa3NpemUgPSA0MDk2OwogICAgICAgICAgfQogICAgICAgICAgaWYgKE5PREVGUy5pc1dpbmRvd3MgJiYgIXN0YXQuYmxvY2tzKSB7CiAgICAgICAgICAgIHN0YXQuYmxvY2tzID0gKChzdGF0LnNpemUgKyBzdGF0LmJsa3NpemUgLSAxKSAvIHN0YXQuYmxrc2l6ZSkgfCAwOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIHsKICAgICAgICAgICAgZGV2OiBzdGF0LmRldiwKICAgICAgICAgICAgaW5vOiBzdGF0LmlubywKICAgICAgICAgICAgbW9kZTogc3RhdC5tb2RlLAogICAgICAgICAgICBubGluazogc3RhdC5ubGluaywKICAgICAgICAgICAgdWlkOiBzdGF0LnVpZCwKICAgICAgICAgICAgZ2lkOiBzdGF0LmdpZCwKICAgICAgICAgICAgcmRldjogc3RhdC5yZGV2LAogICAgICAgICAgICBzaXplOiBzdGF0LnNpemUsCiAgICAgICAgICAgIGF0aW1lOiBzdGF0LmF0aW1lLAogICAgICAgICAgICBtdGltZTogc3RhdC5tdGltZSwKICAgICAgICAgICAgY3RpbWU6IHN0YXQuY3RpbWUsCiAgICAgICAgICAgIGJsa3NpemU6IHN0YXQuYmxrc2l6ZSwKICAgICAgICAgICAgYmxvY2tzOiBzdGF0LmJsb2NrcywKICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIHNldGF0dHI6IGZ1bmN0aW9uIChub2RlLCBhdHRyKSB7CiAgICAgICAgICB2YXIgcGF0aCA9IE5PREVGUy5yZWFsUGF0aChub2RlKTsKICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgIGlmIChhdHRyLm1vZGUgIT09IHVuZGVmaW5lZCkgewogICAgICAgICAgICAgIGZzLmNobW9kU3luYyhwYXRoLCBhdHRyLm1vZGUpOwogICAgICAgICAgICAgIG5vZGUubW9kZSA9IGF0dHIubW9kZTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoYXR0ci50aW1lc3RhbXAgIT09IHVuZGVmaW5lZCkgewogICAgICAgICAgICAgIHZhciBkYXRlID0gbmV3IERhdGUoYXR0ci50aW1lc3RhbXApOwogICAgICAgICAgICAgIGZzLnV0aW1lc1N5bmMocGF0aCwgZGF0ZSwgZGF0ZSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKGF0dHIuc2l6ZSAhPT0gdW5kZWZpbmVkKSB7CiAgICAgICAgICAgICAgZnMudHJ1bmNhdGVTeW5jKHBhdGgsIGF0dHIuc2l6ZSk7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICAgICAgaWYgKCFlLmNvZGUpIHRocm93IGUKICAgICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoRVJSTk9fQ09ERVNbZS5jb2RlXSkKICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIGxvb2t1cDogZnVuY3Rpb24gKHBhcmVudCwgbmFtZSkgewogICAgICAgICAgdmFyIHBhdGggPSBQQVRILmpvaW4yKE5PREVGUy5yZWFsUGF0aChwYXJlbnQpLCBuYW1lKTsKICAgICAgICAgIHZhciBtb2RlID0gTk9ERUZTLmdldE1vZGUocGF0aCk7CiAgICAgICAgICByZXR1cm4gTk9ERUZTLmNyZWF0ZU5vZGUocGFyZW50LCBuYW1lLCBtb2RlKQogICAgICAgIH0sCiAgICAgICAgbWtub2Q6IGZ1bmN0aW9uIChwYXJlbnQsIG5hbWUsIG1vZGUsIGRldikgewogICAgICAgICAgdmFyIG5vZGUgPSBOT0RFRlMuY3JlYXRlTm9kZShwYXJlbnQsIG5hbWUsIG1vZGUsIGRldik7CiAgICAgICAgICB2YXIgcGF0aCA9IE5PREVGUy5yZWFsUGF0aChub2RlKTsKICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgIGlmIChGUy5pc0Rpcihub2RlLm1vZGUpKSB7CiAgICAgICAgICAgICAgZnMubWtkaXJTeW5jKHBhdGgsIG5vZGUubW9kZSk7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgZnMud3JpdGVGaWxlU3luYyhwYXRoLCAnJywgeyBtb2RlOiBub2RlLm1vZGUgfSk7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICAgICAgaWYgKCFlLmNvZGUpIHRocm93IGUKICAgICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoRVJSTk9fQ09ERVNbZS5jb2RlXSkKICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiBub2RlCiAgICAgICAgfSwKICAgICAgICByZW5hbWU6IGZ1bmN0aW9uIChvbGROb2RlLCBuZXdEaXIsIG5ld05hbWUpIHsKICAgICAgICAgIHZhciBvbGRQYXRoID0gTk9ERUZTLnJlYWxQYXRoKG9sZE5vZGUpOwogICAgICAgICAgdmFyIG5ld1BhdGggPSBQQVRILmpvaW4yKE5PREVGUy5yZWFsUGF0aChuZXdEaXIpLCBuZXdOYW1lKTsKICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgIGZzLnJlbmFtZVN5bmMob2xkUGF0aCwgbmV3UGF0aCk7CiAgICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICAgIGlmICghZS5jb2RlKSB0aHJvdyBlCiAgICAgICAgICAgIHRocm93IG5ldyBGUy5FcnJub0Vycm9yKEVSUk5PX0NPREVTW2UuY29kZV0pCiAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgICB1bmxpbms6IGZ1bmN0aW9uIChwYXJlbnQsIG5hbWUpIHsKICAgICAgICAgIHZhciBwYXRoID0gUEFUSC5qb2luMihOT0RFRlMucmVhbFBhdGgocGFyZW50KSwgbmFtZSk7CiAgICAgICAgICB0cnkgewogICAgICAgICAgICBmcy51bmxpbmtTeW5jKHBhdGgpOwogICAgICAgICAgfSBjYXRjaCAoZSkgewogICAgICAgICAgICBpZiAoIWUuY29kZSkgdGhyb3cgZQogICAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFU1tlLmNvZGVdKQogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgcm1kaXI6IGZ1bmN0aW9uIChwYXJlbnQsIG5hbWUpIHsKICAgICAgICAgIHZhciBwYXRoID0gUEFUSC5qb2luMihOT0RFRlMucmVhbFBhdGgocGFyZW50KSwgbmFtZSk7CiAgICAgICAgICB0cnkgewogICAgICAgICAgICBmcy5ybWRpclN5bmMocGF0aCk7CiAgICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICAgIGlmICghZS5jb2RlKSB0aHJvdyBlCiAgICAgICAgICAgIHRocm93IG5ldyBGUy5FcnJub0Vycm9yKEVSUk5PX0NPREVTW2UuY29kZV0pCiAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgICByZWFkZGlyOiBmdW5jdGlvbiAobm9kZSkgewogICAgICAgICAgdmFyIHBhdGggPSBOT0RFRlMucmVhbFBhdGgobm9kZSk7CiAgICAgICAgICB0cnkgewogICAgICAgICAgICByZXR1cm4gZnMucmVhZGRpclN5bmMocGF0aCkKICAgICAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICAgICAgaWYgKCFlLmNvZGUpIHRocm93IGUKICAgICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoRVJSTk9fQ09ERVNbZS5jb2RlXSkKICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIHN5bWxpbms6IGZ1bmN0aW9uIChwYXJlbnQsIG5ld05hbWUsIG9sZFBhdGgpIHsKICAgICAgICAgIHZhciBuZXdQYXRoID0gUEFUSC5qb2luMihOT0RFRlMucmVhbFBhdGgocGFyZW50KSwgbmV3TmFtZSk7CiAgICAgICAgICB0cnkgewogICAgICAgICAgICBmcy5zeW1saW5rU3luYyhvbGRQYXRoLCBuZXdQYXRoKTsKICAgICAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICAgICAgaWYgKCFlLmNvZGUpIHRocm93IGUKICAgICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoRVJSTk9fQ09ERVNbZS5jb2RlXSkKICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIHJlYWRsaW5rOiBmdW5jdGlvbiAobm9kZSkgewogICAgICAgICAgdmFyIHBhdGggPSBOT0RFRlMucmVhbFBhdGgobm9kZSk7CiAgICAgICAgICB0cnkgewogICAgICAgICAgICBwYXRoID0gZnMucmVhZGxpbmtTeW5jKHBhdGgpOwogICAgICAgICAgICBwYXRoID0gTk9ERUpTX1BBVEgucmVsYXRpdmUoTk9ERUpTX1BBVEgucmVzb2x2ZShub2RlLm1vdW50Lm9wdHMucm9vdCksIHBhdGgpOwogICAgICAgICAgICByZXR1cm4gcGF0aAogICAgICAgICAgfSBjYXRjaCAoZSkgewogICAgICAgICAgICBpZiAoIWUuY29kZSkgdGhyb3cgZQogICAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFU1tlLmNvZGVdKQogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgIH0sCiAgICAgIHN0cmVhbV9vcHM6IHsKICAgICAgICBvcGVuOiBmdW5jdGlvbiAoc3RyZWFtKSB7CiAgICAgICAgICB2YXIgcGF0aCA9IE5PREVGUy5yZWFsUGF0aChzdHJlYW0ubm9kZSk7CiAgICAgICAgICB0cnkgewogICAgICAgICAgICBpZiAoRlMuaXNGaWxlKHN0cmVhbS5ub2RlLm1vZGUpKSB7CiAgICAgICAgICAgICAgc3RyZWFtLm5mZCA9IGZzLm9wZW5TeW5jKHBhdGgsIE5PREVGUy5mbGFnc0Zvck5vZGUoc3RyZWFtLmZsYWdzKSk7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICAgICAgaWYgKCFlLmNvZGUpIHRocm93IGUKICAgICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoRVJSTk9fQ09ERVNbZS5jb2RlXSkKICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIGNsb3NlOiBmdW5jdGlvbiAoc3RyZWFtKSB7CiAgICAgICAgICB0cnkgewogICAgICAgICAgICBpZiAoRlMuaXNGaWxlKHN0cmVhbS5ub2RlLm1vZGUpICYmIHN0cmVhbS5uZmQpIHsKICAgICAgICAgICAgICBmcy5jbG9zZVN5bmMoc3RyZWFtLm5mZCk7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICAgICAgaWYgKCFlLmNvZGUpIHRocm93IGUKICAgICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoRVJSTk9fQ09ERVNbZS5jb2RlXSkKICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIHJlYWQ6IGZ1bmN0aW9uIChzdHJlYW0sIGJ1ZmZlciwgb2Zmc2V0LCBsZW5ndGgsIHBvc2l0aW9uKSB7CiAgICAgICAgICBpZiAobGVuZ3RoID09PSAwKSByZXR1cm4gMAogICAgICAgICAgdHJ5IHsKICAgICAgICAgICAgcmV0dXJuIGZzLnJlYWRTeW5jKHN0cmVhbS5uZmQsIE5PREVGUy5idWZmZXJGcm9tKGJ1ZmZlci5idWZmZXIpLCBvZmZzZXQsIGxlbmd0aCwgcG9zaXRpb24pCiAgICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICAgIHRocm93IG5ldyBGUy5FcnJub0Vycm9yKEVSUk5PX0NPREVTW2UuY29kZV0pCiAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgICB3cml0ZTogZnVuY3Rpb24gKHN0cmVhbSwgYnVmZmVyLCBvZmZzZXQsIGxlbmd0aCwgcG9zaXRpb24pIHsKICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgIHJldHVybiBmcy53cml0ZVN5bmMoc3RyZWFtLm5mZCwgTk9ERUZTLmJ1ZmZlckZyb20oYnVmZmVyLmJ1ZmZlciksIG9mZnNldCwgbGVuZ3RoLCBwb3NpdGlvbikKICAgICAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoRVJSTk9fQ09ERVNbZS5jb2RlXSkKICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIGxsc2VlazogZnVuY3Rpb24gKHN0cmVhbSwgb2Zmc2V0LCB3aGVuY2UpIHsKICAgICAgICAgIHZhciBwb3NpdGlvbiA9IG9mZnNldDsKICAgICAgICAgIGlmICh3aGVuY2UgPT09IDEpIHsKICAgICAgICAgICAgcG9zaXRpb24gKz0gc3RyZWFtLnBvc2l0aW9uOwogICAgICAgICAgfSBlbHNlIGlmICh3aGVuY2UgPT09IDIpIHsKICAgICAgICAgICAgaWYgKEZTLmlzRmlsZShzdHJlYW0ubm9kZS5tb2RlKSkgewogICAgICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgICAgICB2YXIgc3RhdCA9IGZzLmZzdGF0U3luYyhzdHJlYW0ubmZkKTsKICAgICAgICAgICAgICAgIHBvc2l0aW9uICs9IHN0YXQuc2l6ZTsKICAgICAgICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFU1tlLmNvZGVdKQogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgaWYgKHBvc2l0aW9uIDwgMCkgewogICAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FSU5WQUwpCiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gcG9zaXRpb24KICAgICAgICB9LAogICAgICB9LAogICAgfTsKICAgIHZhciBXT1JLRVJGUyA9IHsKICAgICAgRElSX01PREU6IDE2ODk1LAogICAgICBGSUxFX01PREU6IDMzMjc5LAogICAgICByZWFkZXI6IG51bGwsCiAgICAgIG1vdW50OiBmdW5jdGlvbiAobW91bnQpIHsKICAgICAgICBhc3NlcnQoRU5WSVJPTk1FTlRfSVNfV09SS0VSKTsKICAgICAgICBpZiAoIVdPUktFUkZTLnJlYWRlcikgV09SS0VSRlMucmVhZGVyID0gbmV3IEZpbGVSZWFkZXJTeW5jKCk7CiAgICAgICAgdmFyIHJvb3QgPSBXT1JLRVJGUy5jcmVhdGVOb2RlKG51bGwsICcvJywgV09SS0VSRlMuRElSX01PREUsIDApOwogICAgICAgIHZhciBjcmVhdGVkUGFyZW50cyA9IHt9OwogICAgICAgIGZ1bmN0aW9uIGVuc3VyZVBhcmVudChwYXRoKSB7CiAgICAgICAgICB2YXIgcGFydHMgPSBwYXRoLnNwbGl0KCcvJyk7CiAgICAgICAgICB2YXIgcGFyZW50ID0gcm9vdDsKICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcGFydHMubGVuZ3RoIC0gMTsgaSsrKSB7CiAgICAgICAgICAgIHZhciBjdXJyID0gcGFydHMuc2xpY2UoMCwgaSArIDEpLmpvaW4oJy8nKTsKICAgICAgICAgICAgaWYgKCFjcmVhdGVkUGFyZW50c1tjdXJyXSkgewogICAgICAgICAgICAgIGNyZWF0ZWRQYXJlbnRzW2N1cnJdID0gV09SS0VSRlMuY3JlYXRlTm9kZShwYXJlbnQsIHBhcnRzW2ldLCBXT1JLRVJGUy5ESVJfTU9ERSwgMCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcGFyZW50ID0gY3JlYXRlZFBhcmVudHNbY3Vycl07CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gcGFyZW50CiAgICAgICAgfQogICAgICAgIGZ1bmN0aW9uIGJhc2UocGF0aCkgewogICAgICAgICAgdmFyIHBhcnRzID0gcGF0aC5zcGxpdCgnLycpOwogICAgICAgICAgcmV0dXJuIHBhcnRzW3BhcnRzLmxlbmd0aCAtIDFdCiAgICAgICAgfQogICAgICAgIEFycmF5LnByb3RvdHlwZS5mb3JFYWNoLmNhbGwobW91bnQub3B0c1snZmlsZXMnXSB8fCBbXSwgZnVuY3Rpb24gKGZpbGUpIHsKICAgICAgICAgIFdPUktFUkZTLmNyZWF0ZU5vZGUoCiAgICAgICAgICAgIGVuc3VyZVBhcmVudChmaWxlLm5hbWUpLAogICAgICAgICAgICBiYXNlKGZpbGUubmFtZSksCiAgICAgICAgICAgIFdPUktFUkZTLkZJTEVfTU9ERSwKICAgICAgICAgICAgMCwKICAgICAgICAgICAgZmlsZSwKICAgICAgICAgICAgZmlsZS5sYXN0TW9kaWZpZWREYXRlCiAgICAgICAgICApOwogICAgICAgIH0pCiAgICAgICAgOyhtb3VudC5vcHRzWydibG9icyddIHx8IFtdKS5mb3JFYWNoKGZ1bmN0aW9uIChvYmopIHsKICAgICAgICAgIFdPUktFUkZTLmNyZWF0ZU5vZGUoZW5zdXJlUGFyZW50KG9ialsnbmFtZSddKSwgYmFzZShvYmpbJ25hbWUnXSksIFdPUktFUkZTLkZJTEVfTU9ERSwgMCwgb2JqWydkYXRhJ10pOwogICAgICAgIH0pCiAgICAgICAgOyhtb3VudC5vcHRzWydwYWNrYWdlcyddIHx8IFtdKS5mb3JFYWNoKGZ1bmN0aW9uIChwYWNrKSB7CiAgICAgICAgICBwYWNrWydtZXRhZGF0YSddLmZpbGVzLmZvckVhY2goZnVuY3Rpb24gKGZpbGUpIHsKICAgICAgICAgICAgdmFyIG5hbWUgPSBmaWxlLmZpbGVuYW1lLnN1YnN0cigxKTsKICAgICAgICAgICAgV09SS0VSRlMuY3JlYXRlTm9kZSgKICAgICAgICAgICAgICBlbnN1cmVQYXJlbnQobmFtZSksCiAgICAgICAgICAgICAgYmFzZShuYW1lKSwKICAgICAgICAgICAgICBXT1JLRVJGUy5GSUxFX01PREUsCiAgICAgICAgICAgICAgMCwKICAgICAgICAgICAgICBwYWNrWydibG9iJ10uc2xpY2UoZmlsZS5zdGFydCwgZmlsZS5lbmQpCiAgICAgICAgICAgICk7CiAgICAgICAgICB9KTsKICAgICAgICB9KTsKICAgICAgICByZXR1cm4gcm9vdAogICAgICB9LAogICAgICBjcmVhdGVOb2RlOiBmdW5jdGlvbiAocGFyZW50LCBuYW1lLCBtb2RlLCBkZXYsIGNvbnRlbnRzLCBtdGltZSkgewogICAgICAgIHZhciBub2RlID0gRlMuY3JlYXRlTm9kZShwYXJlbnQsIG5hbWUsIG1vZGUpOwogICAgICAgIG5vZGUubW9kZSA9IG1vZGU7CiAgICAgICAgbm9kZS5ub2RlX29wcyA9IFdPUktFUkZTLm5vZGVfb3BzOwogICAgICAgIG5vZGUuc3RyZWFtX29wcyA9IFdPUktFUkZTLnN0cmVhbV9vcHM7CiAgICAgICAgbm9kZS50aW1lc3RhbXAgPSAobXRpbWUgfHwgbmV3IERhdGUoKSkuZ2V0VGltZSgpOwogICAgICAgIGFzc2VydChXT1JLRVJGUy5GSUxFX01PREUgIT09IFdPUktFUkZTLkRJUl9NT0RFKTsKICAgICAgICBpZiAobW9kZSA9PT0gV09SS0VSRlMuRklMRV9NT0RFKSB7CiAgICAgICAgICBub2RlLnNpemUgPSBjb250ZW50cy5zaXplOwogICAgICAgICAgbm9kZS5jb250ZW50cyA9IGNvbnRlbnRzOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBub2RlLnNpemUgPSA0MDk2OwogICAgICAgICAgbm9kZS5jb250ZW50cyA9IHt9OwogICAgICAgIH0KICAgICAgICBpZiAocGFyZW50KSB7CiAgICAgICAgICBwYXJlbnQuY29udGVudHNbbmFtZV0gPSBub2RlOwogICAgICAgIH0KICAgICAgICByZXR1cm4gbm9kZQogICAgICB9LAogICAgICBub2RlX29wczogewogICAgICAgIGdldGF0dHI6IGZ1bmN0aW9uIChub2RlKSB7CiAgICAgICAgICByZXR1cm4gewogICAgICAgICAgICBkZXY6IDEsCiAgICAgICAgICAgIGlubzogdW5kZWZpbmVkLAogICAgICAgICAgICBtb2RlOiBub2RlLm1vZGUsCiAgICAgICAgICAgIG5saW5rOiAxLAogICAgICAgICAgICB1aWQ6IDAsCiAgICAgICAgICAgIGdpZDogMCwKICAgICAgICAgICAgcmRldjogdW5kZWZpbmVkLAogICAgICAgICAgICBzaXplOiBub2RlLnNpemUsCiAgICAgICAgICAgIGF0aW1lOiBuZXcgRGF0ZShub2RlLnRpbWVzdGFtcCksCiAgICAgICAgICAgIG10aW1lOiBuZXcgRGF0ZShub2RlLnRpbWVzdGFtcCksCiAgICAgICAgICAgIGN0aW1lOiBuZXcgRGF0ZShub2RlLnRpbWVzdGFtcCksCiAgICAgICAgICAgIGJsa3NpemU6IDQwOTYsCiAgICAgICAgICAgIGJsb2NrczogTWF0aC5jZWlsKG5vZGUuc2l6ZSAvIDQwOTYpLAogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgc2V0YXR0cjogZnVuY3Rpb24gKG5vZGUsIGF0dHIpIHsKICAgICAgICAgIGlmIChhdHRyLm1vZGUgIT09IHVuZGVmaW5lZCkgewogICAgICAgICAgICBub2RlLm1vZGUgPSBhdHRyLm1vZGU7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAoYXR0ci50aW1lc3RhbXAgIT09IHVuZGVmaW5lZCkgewogICAgICAgICAgICBub2RlLnRpbWVzdGFtcCA9IGF0dHIudGltZXN0YW1wOwogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgbG9va3VwOiBmdW5jdGlvbiAocGFyZW50LCBuYW1lKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FTk9FTlQpCiAgICAgICAgfSwKICAgICAgICBta25vZDogZnVuY3Rpb24gKHBhcmVudCwgbmFtZSwgbW9kZSwgZGV2KSB7CiAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FUEVSTSkKICAgICAgICB9LAogICAgICAgIHJlbmFtZTogZnVuY3Rpb24gKG9sZE5vZGUsIG5ld0RpciwgbmV3TmFtZSkgewogICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoRVJSTk9fQ09ERVMuRVBFUk0pCiAgICAgICAgfSwKICAgICAgICB1bmxpbms6IGZ1bmN0aW9uIChwYXJlbnQsIG5hbWUpIHsKICAgICAgICAgIHRocm93IG5ldyBGUy5FcnJub0Vycm9yKEVSUk5PX0NPREVTLkVQRVJNKQogICAgICAgIH0sCiAgICAgICAgcm1kaXI6IGZ1bmN0aW9uIChwYXJlbnQsIG5hbWUpIHsKICAgICAgICAgIHRocm93IG5ldyBGUy5FcnJub0Vycm9yKEVSUk5PX0NPREVTLkVQRVJNKQogICAgICAgIH0sCiAgICAgICAgcmVhZGRpcjogZnVuY3Rpb24gKG5vZGUpIHsKICAgICAgICAgIHZhciBlbnRyaWVzID0gWycuJywgJy4uJ107CiAgICAgICAgICBmb3IgKHZhciBrZXkgaW4gbm9kZS5jb250ZW50cykgewogICAgICAgICAgICBpZiAoIW5vZGUuY29udGVudHMuaGFzT3duUHJvcGVydHkoa2V5KSkgewogICAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgICAgIH0KICAgICAgICAgICAgZW50cmllcy5wdXNoKGtleSk7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gZW50cmllcwogICAgICAgIH0sCiAgICAgICAgc3ltbGluazogZnVuY3Rpb24gKHBhcmVudCwgbmV3TmFtZSwgb2xkUGF0aCkgewogICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoRVJSTk9fQ09ERVMuRVBFUk0pCiAgICAgICAgfSwKICAgICAgICByZWFkbGluazogZnVuY3Rpb24gKG5vZGUpIHsKICAgICAgICAgIHRocm93IG5ldyBGUy5FcnJub0Vycm9yKEVSUk5PX0NPREVTLkVQRVJNKQogICAgICAgIH0sCiAgICAgIH0sCiAgICAgIHN0cmVhbV9vcHM6IHsKICAgICAgICByZWFkOiBmdW5jdGlvbiAoc3RyZWFtLCBidWZmZXIsIG9mZnNldCwgbGVuZ3RoLCBwb3NpdGlvbikgewogICAgICAgICAgaWYgKHBvc2l0aW9uID49IHN0cmVhbS5ub2RlLnNpemUpIHJldHVybiAwCiAgICAgICAgICB2YXIgY2h1bmsgPSBzdHJlYW0ubm9kZS5jb250ZW50cy5zbGljZShwb3NpdGlvbiwgcG9zaXRpb24gKyBsZW5ndGgpOwogICAgICAgICAgdmFyIGFiID0gV09SS0VSRlMucmVhZGVyLnJlYWRBc0FycmF5QnVmZmVyKGNodW5rKTsKICAgICAgICAgIGJ1ZmZlci5zZXQobmV3IFVpbnQ4QXJyYXkoYWIpLCBvZmZzZXQpOwogICAgICAgICAgcmV0dXJuIGNodW5rLnNpemUKICAgICAgICB9LAogICAgICAgIHdyaXRlOiBmdW5jdGlvbiAoc3RyZWFtLCBidWZmZXIsIG9mZnNldCwgbGVuZ3RoLCBwb3NpdGlvbikgewogICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoRVJSTk9fQ09ERVMuRUlPKQogICAgICAgIH0sCiAgICAgICAgbGxzZWVrOiBmdW5jdGlvbiAoc3RyZWFtLCBvZmZzZXQsIHdoZW5jZSkgewogICAgICAgICAgdmFyIHBvc2l0aW9uID0gb2Zmc2V0OwogICAgICAgICAgaWYgKHdoZW5jZSA9PT0gMSkgewogICAgICAgICAgICBwb3NpdGlvbiArPSBzdHJlYW0ucG9zaXRpb247CiAgICAgICAgICB9IGVsc2UgaWYgKHdoZW5jZSA9PT0gMikgewogICAgICAgICAgICBpZiAoRlMuaXNGaWxlKHN0cmVhbS5ub2RlLm1vZGUpKSB7CiAgICAgICAgICAgICAgcG9zaXRpb24gKz0gc3RyZWFtLm5vZGUuc2l6ZTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgaWYgKHBvc2l0aW9uIDwgMCkgewogICAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FSU5WQUwpCiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gcG9zaXRpb24KICAgICAgICB9LAogICAgICB9LAogICAgfTsKICAgIFNUQVRJQ1RPUCArPSAxNjsKICAgIFNUQVRJQ1RPUCArPSAxNjsKICAgIFNUQVRJQ1RPUCArPSAxNjsKICAgIHZhciBGUyA9IHsKICAgICAgcm9vdDogbnVsbCwKICAgICAgbW91bnRzOiBbXSwKICAgICAgZGV2aWNlczoge30sCiAgICAgIHN0cmVhbXM6IFtdLAogICAgICBuZXh0SW5vZGU6IDEsCiAgICAgIG5hbWVUYWJsZTogbnVsbCwKICAgICAgY3VycmVudFBhdGg6ICcvJywKICAgICAgaW5pdGlhbGl6ZWQ6IGZhbHNlLAogICAgICBpZ25vcmVQZXJtaXNzaW9uczogdHJ1ZSwKICAgICAgdHJhY2tpbmdEZWxlZ2F0ZToge30sCiAgICAgIHRyYWNraW5nOiB7IG9wZW5GbGFnczogeyBSRUFEOiAxLCBXUklURTogMiB9IH0sCiAgICAgIEVycm5vRXJyb3I6IG51bGwsCiAgICAgIGdlbmVyaWNFcnJvcnM6IHt9LAogICAgICBmaWxlc3lzdGVtczogbnVsbCwKICAgICAgc3luY0ZTUmVxdWVzdHM6IDAsCiAgICAgIGhhbmRsZUZTRXJyb3I6IGZ1bmN0aW9uIChlKSB7CiAgICAgICAgaWYgKCEoZSBpbnN0YW5jZW9mIEZTLkVycm5vRXJyb3IpKSB0aHJvdyBlICsgJyA6ICcgKyBzdGFja1RyYWNlKCkKICAgICAgICByZXR1cm4gX19fc2V0RXJyTm8oZS5lcnJubykKICAgICAgfSwKICAgICAgbG9va3VwUGF0aDogZnVuY3Rpb24gKHBhdGgsIG9wdHMpIHsKICAgICAgICBwYXRoID0gUEFUSC5yZXNvbHZlKEZTLmN3ZCgpLCBwYXRoKTsKICAgICAgICBvcHRzID0gb3B0cyB8fCB7fTsKICAgICAgICBpZiAoIXBhdGgpIHJldHVybiB7IHBhdGg6ICcnLCBub2RlOiBudWxsIH0KICAgICAgICB2YXIgZGVmYXVsdHMgPSB7IGZvbGxvd19tb3VudDogdHJ1ZSwgcmVjdXJzZV9jb3VudDogMCB9OwogICAgICAgIGZvciAodmFyIGtleSBpbiBkZWZhdWx0cykgewogICAgICAgICAgaWYgKG9wdHNba2V5XSA9PT0gdW5kZWZpbmVkKSB7CiAgICAgICAgICAgIG9wdHNba2V5XSA9IGRlZmF1bHRzW2tleV07CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGlmIChvcHRzLnJlY3Vyc2VfY291bnQgPiA4KSB7CiAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FTE9PUCkKICAgICAgICB9CiAgICAgICAgdmFyIHBhcnRzID0gUEFUSC5ub3JtYWxpemVBcnJheSgKICAgICAgICAgIHBhdGguc3BsaXQoJy8nKS5maWx0ZXIoZnVuY3Rpb24gKHApIHsKICAgICAgICAgICAgcmV0dXJuICEhcAogICAgICAgICAgfSksCiAgICAgICAgICBmYWxzZQogICAgICAgICk7CiAgICAgICAgdmFyIGN1cnJlbnQgPSBGUy5yb290OwogICAgICAgIHZhciBjdXJyZW50X3BhdGggPSAnLyc7CiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBwYXJ0cy5sZW5ndGg7IGkrKykgewogICAgICAgICAgdmFyIGlzbGFzdCA9IGkgPT09IHBhcnRzLmxlbmd0aCAtIDE7CiAgICAgICAgICBpZiAoaXNsYXN0ICYmIG9wdHMucGFyZW50KSB7CiAgICAgICAgICAgIGJyZWFrCiAgICAgICAgICB9CiAgICAgICAgICBjdXJyZW50ID0gRlMubG9va3VwTm9kZShjdXJyZW50LCBwYXJ0c1tpXSk7CiAgICAgICAgICBjdXJyZW50X3BhdGggPSBQQVRILmpvaW4yKGN1cnJlbnRfcGF0aCwgcGFydHNbaV0pOwogICAgICAgICAgaWYgKEZTLmlzTW91bnRwb2ludChjdXJyZW50KSkgewogICAgICAgICAgICBpZiAoIWlzbGFzdCB8fCAoaXNsYXN0ICYmIG9wdHMuZm9sbG93X21vdW50KSkgewogICAgICAgICAgICAgIGN1cnJlbnQgPSBjdXJyZW50Lm1vdW50ZWQucm9vdDsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgaWYgKCFpc2xhc3QgfHwgb3B0cy5mb2xsb3cpIHsKICAgICAgICAgICAgdmFyIGNvdW50ID0gMDsKICAgICAgICAgICAgd2hpbGUgKEZTLmlzTGluayhjdXJyZW50Lm1vZGUpKSB7CiAgICAgICAgICAgICAgdmFyIGxpbmsgPSBGUy5yZWFkbGluayhjdXJyZW50X3BhdGgpOwogICAgICAgICAgICAgIGN1cnJlbnRfcGF0aCA9IFBBVEgucmVzb2x2ZShQQVRILmRpcm5hbWUoY3VycmVudF9wYXRoKSwgbGluayk7CiAgICAgICAgICAgICAgdmFyIGxvb2t1cCA9IEZTLmxvb2t1cFBhdGgoY3VycmVudF9wYXRoLCB7IHJlY3Vyc2VfY291bnQ6IG9wdHMucmVjdXJzZV9jb3VudCB9KTsKICAgICAgICAgICAgICBjdXJyZW50ID0gbG9va3VwLm5vZGU7CiAgICAgICAgICAgICAgaWYgKGNvdW50KysgPiA0MCkgewogICAgICAgICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoRVJSTk9fQ09ERVMuRUxPT1ApCiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHJldHVybiB7IHBhdGg6IGN1cnJlbnRfcGF0aCwgbm9kZTogY3VycmVudCB9CiAgICAgIH0sCiAgICAgIGdldFBhdGg6IGZ1bmN0aW9uIChub2RlKSB7CiAgICAgICAgdmFyIHBhdGg7CiAgICAgICAgd2hpbGUgKHRydWUpIHsKICAgICAgICAgIGlmIChGUy5pc1Jvb3Qobm9kZSkpIHsKICAgICAgICAgICAgdmFyIG1vdW50ID0gbm9kZS5tb3VudC5tb3VudHBvaW50OwogICAgICAgICAgICBpZiAoIXBhdGgpIHJldHVybiBtb3VudAogICAgICAgICAgICByZXR1cm4gbW91bnRbbW91bnQubGVuZ3RoIC0gMV0gIT09ICcvJyA/IG1vdW50ICsgJy8nICsgcGF0aCA6IG1vdW50ICsgcGF0aAogICAgICAgICAgfQogICAgICAgICAgcGF0aCA9IHBhdGggPyBub2RlLm5hbWUgKyAnLycgKyBwYXRoIDogbm9kZS5uYW1lOwogICAgICAgICAgbm9kZSA9IG5vZGUucGFyZW50OwogICAgICAgIH0KICAgICAgfSwKICAgICAgaGFzaE5hbWU6IGZ1bmN0aW9uIChwYXJlbnRpZCwgbmFtZSkgewogICAgICAgIHZhciBoYXNoID0gMDsKICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IG5hbWUubGVuZ3RoOyBpKyspIHsKICAgICAgICAgIGhhc2ggPSAoKGhhc2ggPDwgNSkgLSBoYXNoICsgbmFtZS5jaGFyQ29kZUF0KGkpKSB8IDA7CiAgICAgICAgfQogICAgICAgIHJldHVybiAoKHBhcmVudGlkICsgaGFzaCkgPj4+IDApICUgRlMubmFtZVRhYmxlLmxlbmd0aAogICAgICB9LAogICAgICBoYXNoQWRkTm9kZTogZnVuY3Rpb24gKG5vZGUpIHsKICAgICAgICB2YXIgaGFzaCA9IEZTLmhhc2hOYW1lKG5vZGUucGFyZW50LmlkLCBub2RlLm5hbWUpOwogICAgICAgIG5vZGUubmFtZV9uZXh0ID0gRlMubmFtZVRhYmxlW2hhc2hdOwogICAgICAgIEZTLm5hbWVUYWJsZVtoYXNoXSA9IG5vZGU7CiAgICAgIH0sCiAgICAgIGhhc2hSZW1vdmVOb2RlOiBmdW5jdGlvbiAobm9kZSkgewogICAgICAgIHZhciBoYXNoID0gRlMuaGFzaE5hbWUobm9kZS5wYXJlbnQuaWQsIG5vZGUubmFtZSk7CiAgICAgICAgaWYgKEZTLm5hbWVUYWJsZVtoYXNoXSA9PT0gbm9kZSkgewogICAgICAgICAgRlMubmFtZVRhYmxlW2hhc2hdID0gbm9kZS5uYW1lX25leHQ7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIHZhciBjdXJyZW50ID0gRlMubmFtZVRhYmxlW2hhc2hdOwogICAgICAgICAgd2hpbGUgKGN1cnJlbnQpIHsKICAgICAgICAgICAgaWYgKGN1cnJlbnQubmFtZV9uZXh0ID09PSBub2RlKSB7CiAgICAgICAgICAgICAgY3VycmVudC5uYW1lX25leHQgPSBub2RlLm5hbWVfbmV4dDsKICAgICAgICAgICAgICBicmVhawogICAgICAgICAgICB9CiAgICAgICAgICAgIGN1cnJlbnQgPSBjdXJyZW50Lm5hbWVfbmV4dDsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0sCiAgICAgIGxvb2t1cE5vZGU6IGZ1bmN0aW9uIChwYXJlbnQsIG5hbWUpIHsKICAgICAgICB2YXIgZXJyID0gRlMubWF5TG9va3VwKHBhcmVudCk7CiAgICAgICAgaWYgKGVycikgewogICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoZXJyLCBwYXJlbnQpCiAgICAgICAgfQogICAgICAgIHZhciBoYXNoID0gRlMuaGFzaE5hbWUocGFyZW50LmlkLCBuYW1lKTsKICAgICAgICBmb3IgKHZhciBub2RlID0gRlMubmFtZVRhYmxlW2hhc2hdOyBub2RlOyBub2RlID0gbm9kZS5uYW1lX25leHQpIHsKICAgICAgICAgIHZhciBub2RlTmFtZSA9IG5vZGUubmFtZTsKICAgICAgICAgIGlmIChub2RlLnBhcmVudC5pZCA9PT0gcGFyZW50LmlkICYmIG5vZGVOYW1lID09PSBuYW1lKSB7CiAgICAgICAgICAgIHJldHVybiBub2RlCiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHJldHVybiBGUy5sb29rdXAocGFyZW50LCBuYW1lKQogICAgICB9LAogICAgICBjcmVhdGVOb2RlOiBmdW5jdGlvbiAocGFyZW50LCBuYW1lLCBtb2RlLCByZGV2KSB7CiAgICAgICAgaWYgKCFGUy5GU05vZGUpIHsKICAgICAgICAgIEZTLkZTTm9kZSA9IGZ1bmN0aW9uIChwYXJlbnQsIG5hbWUsIG1vZGUsIHJkZXYpIHsKICAgICAgICAgICAgaWYgKCFwYXJlbnQpIHsKICAgICAgICAgICAgICBwYXJlbnQgPSB0aGlzOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHRoaXMucGFyZW50ID0gcGFyZW50OwogICAgICAgICAgICB0aGlzLm1vdW50ID0gcGFyZW50Lm1vdW50OwogICAgICAgICAgICB0aGlzLm1vdW50ZWQgPSBudWxsOwogICAgICAgICAgICB0aGlzLmlkID0gRlMubmV4dElub2RlKys7CiAgICAgICAgICAgIHRoaXMubmFtZSA9IG5hbWU7CiAgICAgICAgICAgIHRoaXMubW9kZSA9IG1vZGU7CiAgICAgICAgICAgIHRoaXMubm9kZV9vcHMgPSB7fTsKICAgICAgICAgICAgdGhpcy5zdHJlYW1fb3BzID0ge307CiAgICAgICAgICAgIHRoaXMucmRldiA9IHJkZXY7CiAgICAgICAgICB9OwogICAgICAgICAgRlMuRlNOb2RlLnByb3RvdHlwZSA9IHt9OwogICAgICAgICAgdmFyIHJlYWRNb2RlID0gMjkyIHwgNzM7CiAgICAgICAgICB2YXIgd3JpdGVNb2RlID0gMTQ2OwogICAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoRlMuRlNOb2RlLnByb3RvdHlwZSwgewogICAgICAgICAgICByZWFkOiB7CiAgICAgICAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgICAgICByZXR1cm4gKHRoaXMubW9kZSAmIHJlYWRNb2RlKSA9PT0gcmVhZE1vZGUKICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgIHNldDogZnVuY3Rpb24gKHZhbCkgewogICAgICAgICAgICAgICAgdmFsID8gKHRoaXMubW9kZSB8PSByZWFkTW9kZSkgOiAodGhpcy5tb2RlICY9IH5yZWFkTW9kZSk7CiAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgfSwKICAgICAgICAgICAgd3JpdGU6IHsKICAgICAgICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHsKICAgICAgICAgICAgICAgIHJldHVybiAodGhpcy5tb2RlICYgd3JpdGVNb2RlKSA9PT0gd3JpdGVNb2RlCiAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICBzZXQ6IGZ1bmN0aW9uICh2YWwpIHsKICAgICAgICAgICAgICAgIHZhbCA/ICh0aGlzLm1vZGUgfD0gd3JpdGVNb2RlKSA6ICh0aGlzLm1vZGUgJj0gfndyaXRlTW9kZSk7CiAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgfSwKICAgICAgICAgICAgaXNGb2xkZXI6IHsKICAgICAgICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHsKICAgICAgICAgICAgICAgIHJldHVybiBGUy5pc0Rpcih0aGlzLm1vZGUpCiAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgfSwKICAgICAgICAgICAgaXNEZXZpY2U6IHsKICAgICAgICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHsKICAgICAgICAgICAgICAgIHJldHVybiBGUy5pc0NocmRldih0aGlzLm1vZGUpCiAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgfSwKICAgICAgICAgIH0pOwogICAgICAgIH0KICAgICAgICB2YXIgbm9kZSA9IG5ldyBGUy5GU05vZGUocGFyZW50LCBuYW1lLCBtb2RlLCByZGV2KTsKICAgICAgICBGUy5oYXNoQWRkTm9kZShub2RlKTsKICAgICAgICByZXR1cm4gbm9kZQogICAgICB9LAogICAgICBkZXN0cm95Tm9kZTogZnVuY3Rpb24gKG5vZGUpIHsKICAgICAgICBGUy5oYXNoUmVtb3ZlTm9kZShub2RlKTsKICAgICAgfSwKICAgICAgaXNSb290OiBmdW5jdGlvbiAobm9kZSkgewogICAgICAgIHJldHVybiBub2RlID09PSBub2RlLnBhcmVudAogICAgICB9LAogICAgICBpc01vdW50cG9pbnQ6IGZ1bmN0aW9uIChub2RlKSB7CiAgICAgICAgcmV0dXJuICEhbm9kZS5tb3VudGVkCiAgICAgIH0sCiAgICAgIGlzRmlsZTogZnVuY3Rpb24gKG1vZGUpIHsKICAgICAgICByZXR1cm4gKG1vZGUgJiA2MTQ0MCkgPT09IDMyNzY4CiAgICAgIH0sCiAgICAgIGlzRGlyOiBmdW5jdGlvbiAobW9kZSkgewogICAgICAgIHJldHVybiAobW9kZSAmIDYxNDQwKSA9PT0gMTYzODQKICAgICAgfSwKICAgICAgaXNMaW5rOiBmdW5jdGlvbiAobW9kZSkgewogICAgICAgIHJldHVybiAobW9kZSAmIDYxNDQwKSA9PT0gNDA5NjAKICAgICAgfSwKICAgICAgaXNDaHJkZXY6IGZ1bmN0aW9uIChtb2RlKSB7CiAgICAgICAgcmV0dXJuIChtb2RlICYgNjE0NDApID09PSA4MTkyCiAgICAgIH0sCiAgICAgIGlzQmxrZGV2OiBmdW5jdGlvbiAobW9kZSkgewogICAgICAgIHJldHVybiAobW9kZSAmIDYxNDQwKSA9PT0gMjQ1NzYKICAgICAgfSwKICAgICAgaXNGSUZPOiBmdW5jdGlvbiAobW9kZSkgewogICAgICAgIHJldHVybiAobW9kZSAmIDYxNDQwKSA9PT0gNDA5NgogICAgICB9LAogICAgICBpc1NvY2tldDogZnVuY3Rpb24gKG1vZGUpIHsKICAgICAgICByZXR1cm4gKG1vZGUgJiA0OTE1MikgPT09IDQ5MTUyCiAgICAgIH0sCiAgICAgIGZsYWdNb2RlczogewogICAgICAgIHI6IDAsCiAgICAgICAgcnM6IDEwNTI2NzIsCiAgICAgICAgJ3IrJzogMiwKICAgICAgICB3OiA1NzcsCiAgICAgICAgd3g6IDcwNSwKICAgICAgICB4dzogNzA1LAogICAgICAgICd3Kyc6IDU3OCwKICAgICAgICAnd3grJzogNzA2LAogICAgICAgICd4dysnOiA3MDYsCiAgICAgICAgYTogMTA4OSwKICAgICAgICBheDogMTIxNywKICAgICAgICB4YTogMTIxNywKICAgICAgICAnYSsnOiAxMDkwLAogICAgICAgICdheCsnOiAxMjE4LAogICAgICAgICd4YSsnOiAxMjE4LAogICAgICB9LAogICAgICBtb2RlU3RyaW5nVG9GbGFnczogZnVuY3Rpb24gKHN0cikgewogICAgICAgIHZhciBmbGFncyA9IEZTLmZsYWdNb2Rlc1tzdHJdOwogICAgICAgIGlmICh0eXBlb2YgZmxhZ3MgPT09ICd1bmRlZmluZWQnKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1Vua25vd24gZmlsZSBvcGVuIG1vZGU6ICcgKyBzdHIpCiAgICAgICAgfQogICAgICAgIHJldHVybiBmbGFncwogICAgICB9LAogICAgICBmbGFnc1RvUGVybWlzc2lvblN0cmluZzogZnVuY3Rpb24gKGZsYWcpIHsKICAgICAgICB2YXIgcGVybXMgPSBbJ3InLCAndycsICdydyddW2ZsYWcgJiAzXTsKICAgICAgICBpZiAoZmxhZyAmIDUxMikgewogICAgICAgICAgcGVybXMgKz0gJ3cnOwogICAgICAgIH0KICAgICAgICByZXR1cm4gcGVybXMKICAgICAgfSwKICAgICAgbm9kZVBlcm1pc3Npb25zOiBmdW5jdGlvbiAobm9kZSwgcGVybXMpIHsKICAgICAgICBpZiAoRlMuaWdub3JlUGVybWlzc2lvbnMpIHsKICAgICAgICAgIHJldHVybiAwCiAgICAgICAgfQogICAgICAgIGlmIChwZXJtcy5pbmRleE9mKCdyJykgIT09IC0xICYmICEobm9kZS5tb2RlICYgMjkyKSkgewogICAgICAgICAgcmV0dXJuIEVSUk5PX0NPREVTLkVBQ0NFUwogICAgICAgIH0gZWxzZSBpZiAocGVybXMuaW5kZXhPZigndycpICE9PSAtMSAmJiAhKG5vZGUubW9kZSAmIDE0NikpIHsKICAgICAgICAgIHJldHVybiBFUlJOT19DT0RFUy5FQUNDRVMKICAgICAgICB9IGVsc2UgaWYgKHBlcm1zLmluZGV4T2YoJ3gnKSAhPT0gLTEgJiYgIShub2RlLm1vZGUgJiA3MykpIHsKICAgICAgICAgIHJldHVybiBFUlJOT19DT0RFUy5FQUNDRVMKICAgICAgICB9CiAgICAgICAgcmV0dXJuIDAKICAgICAgfSwKICAgICAgbWF5TG9va3VwOiBmdW5jdGlvbiAoZGlyKSB7CiAgICAgICAgdmFyIGVyciA9IEZTLm5vZGVQZXJtaXNzaW9ucyhkaXIsICd4Jyk7CiAgICAgICAgaWYgKGVycikgcmV0dXJuIGVycgogICAgICAgIGlmICghZGlyLm5vZGVfb3BzLmxvb2t1cCkgcmV0dXJuIEVSUk5PX0NPREVTLkVBQ0NFUwogICAgICAgIHJldHVybiAwCiAgICAgIH0sCiAgICAgIG1heUNyZWF0ZTogZnVuY3Rpb24gKGRpciwgbmFtZSkgewogICAgICAgIHRyeSB7CiAgICAgICAgICB2YXIgbm9kZSA9IEZTLmxvb2t1cE5vZGUoZGlyLCBuYW1lKTsKICAgICAgICAgIHJldHVybiBFUlJOT19DT0RFUy5FRVhJU1QKICAgICAgICB9IGNhdGNoIChlKSB7fQogICAgICAgIHJldHVybiBGUy5ub2RlUGVybWlzc2lvbnMoZGlyLCAnd3gnKQogICAgICB9LAogICAgICBtYXlEZWxldGU6IGZ1bmN0aW9uIChkaXIsIG5hbWUsIGlzZGlyKSB7CiAgICAgICAgdmFyIG5vZGU7CiAgICAgICAgdHJ5IHsKICAgICAgICAgIG5vZGUgPSBGUy5sb29rdXBOb2RlKGRpciwgbmFtZSk7CiAgICAgICAgfSBjYXRjaCAoZSkgewogICAgICAgICAgcmV0dXJuIGUuZXJybm8KICAgICAgICB9CiAgICAgICAgdmFyIGVyciA9IEZTLm5vZGVQZXJtaXNzaW9ucyhkaXIsICd3eCcpOwogICAgICAgIGlmIChlcnIpIHsKICAgICAgICAgIHJldHVybiBlcnIKICAgICAgICB9CiAgICAgICAgaWYgKGlzZGlyKSB7CiAgICAgICAgICBpZiAoIUZTLmlzRGlyKG5vZGUubW9kZSkpIHsKICAgICAgICAgICAgcmV0dXJuIEVSUk5PX0NPREVTLkVOT1RESVIKICAgICAgICAgIH0KICAgICAgICAgIGlmIChGUy5pc1Jvb3Qobm9kZSkgfHwgRlMuZ2V0UGF0aChub2RlKSA9PT0gRlMuY3dkKCkpIHsKICAgICAgICAgICAgcmV0dXJuIEVSUk5PX0NPREVTLkVCVVNZCiAgICAgICAgICB9CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIGlmIChGUy5pc0Rpcihub2RlLm1vZGUpKSB7CiAgICAgICAgICAgIHJldHVybiBFUlJOT19DT0RFUy5FSVNESVIKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgcmV0dXJuIDAKICAgICAgfSwKICAgICAgbWF5T3BlbjogZnVuY3Rpb24gKG5vZGUsIGZsYWdzKSB7CiAgICAgICAgaWYgKCFub2RlKSB7CiAgICAgICAgICByZXR1cm4gRVJSTk9fQ09ERVMuRU5PRU5UCiAgICAgICAgfQogICAgICAgIGlmIChGUy5pc0xpbmsobm9kZS5tb2RlKSkgewogICAgICAgICAgcmV0dXJuIEVSUk5PX0NPREVTLkVMT09QCiAgICAgICAgfSBlbHNlIGlmIChGUy5pc0Rpcihub2RlLm1vZGUpKSB7CiAgICAgICAgICBpZiAoRlMuZmxhZ3NUb1Blcm1pc3Npb25TdHJpbmcoZmxhZ3MpICE9PSAncicgfHwgZmxhZ3MgJiA1MTIpIHsKICAgICAgICAgICAgcmV0dXJuIEVSUk5PX0NPREVTLkVJU0RJUgogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZXR1cm4gRlMubm9kZVBlcm1pc3Npb25zKG5vZGUsIEZTLmZsYWdzVG9QZXJtaXNzaW9uU3RyaW5nKGZsYWdzKSkKICAgICAgfSwKICAgICAgTUFYX09QRU5fRkRTOiA0MDk2LAogICAgICBuZXh0ZmQ6IGZ1bmN0aW9uIChmZF9zdGFydCwgZmRfZW5kKSB7CiAgICAgICAgZmRfc3RhcnQgPSBmZF9zdGFydCB8fCAwOwogICAgICAgIGZkX2VuZCA9IGZkX2VuZCB8fCBGUy5NQVhfT1BFTl9GRFM7CiAgICAgICAgZm9yICh2YXIgZmQgPSBmZF9zdGFydDsgZmQgPD0gZmRfZW5kOyBmZCsrKSB7CiAgICAgICAgICBpZiAoIUZTLnN0cmVhbXNbZmRdKSB7CiAgICAgICAgICAgIHJldHVybiBmZAogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FTUZJTEUpCiAgICAgIH0sCiAgICAgIGdldFN0cmVhbTogZnVuY3Rpb24gKGZkKSB7CiAgICAgICAgcmV0dXJuIEZTLnN0cmVhbXNbZmRdCiAgICAgIH0sCiAgICAgIGNyZWF0ZVN0cmVhbTogZnVuY3Rpb24gKHN0cmVhbSwgZmRfc3RhcnQsIGZkX2VuZCkgewogICAgICAgIGlmICghRlMuRlNTdHJlYW0pIHsKICAgICAgICAgIEZTLkZTU3RyZWFtID0gZnVuY3Rpb24gKCkge307CiAgICAgICAgICBGUy5GU1N0cmVhbS5wcm90b3R5cGUgPSB7fTsKICAgICAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKEZTLkZTU3RyZWFtLnByb3RvdHlwZSwgewogICAgICAgICAgICBvYmplY3Q6IHsKICAgICAgICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHsKICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLm5vZGUKICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgIHNldDogZnVuY3Rpb24gKHZhbCkgewogICAgICAgICAgICAgICAgdGhpcy5ub2RlID0gdmFsOwogICAgICAgICAgICAgIH0sCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIGlzUmVhZDogewogICAgICAgICAgICAgIGdldDogZnVuY3Rpb24gKCkgewogICAgICAgICAgICAgICAgcmV0dXJuICh0aGlzLmZsYWdzICYgMjA5NzE1NSkgIT09IDEKICAgICAgICAgICAgICB9LAogICAgICAgICAgICB9LAogICAgICAgICAgICBpc1dyaXRlOiB7CiAgICAgICAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgICAgICByZXR1cm4gKHRoaXMuZmxhZ3MgJiAyMDk3MTU1KSAhPT0gMAogICAgICAgICAgICAgIH0sCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIGlzQXBwZW5kOiB7CiAgICAgICAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5mbGFncyAmIDEwMjQKICAgICAgICAgICAgICB9LAogICAgICAgICAgICB9LAogICAgICAgICAgfSk7CiAgICAgICAgfQogICAgICAgIHZhciBuZXdTdHJlYW0gPSBuZXcgRlMuRlNTdHJlYW0oKTsKICAgICAgICBmb3IgKHZhciBwIGluIHN0cmVhbSkgewogICAgICAgICAgbmV3U3RyZWFtW3BdID0gc3RyZWFtW3BdOwogICAgICAgIH0KICAgICAgICBzdHJlYW0gPSBuZXdTdHJlYW07CiAgICAgICAgdmFyIGZkID0gRlMubmV4dGZkKGZkX3N0YXJ0LCBmZF9lbmQpOwogICAgICAgIHN0cmVhbS5mZCA9IGZkOwogICAgICAgIEZTLnN0cmVhbXNbZmRdID0gc3RyZWFtOwogICAgICAgIHJldHVybiBzdHJlYW0KICAgICAgfSwKICAgICAgY2xvc2VTdHJlYW06IGZ1bmN0aW9uIChmZCkgewogICAgICAgIEZTLnN0cmVhbXNbZmRdID0gbnVsbDsKICAgICAgfSwKICAgICAgY2hyZGV2X3N0cmVhbV9vcHM6IHsKICAgICAgICBvcGVuOiBmdW5jdGlvbiAoc3RyZWFtKSB7CiAgICAgICAgICB2YXIgZGV2aWNlID0gRlMuZ2V0RGV2aWNlKHN0cmVhbS5ub2RlLnJkZXYpOwogICAgICAgICAgc3RyZWFtLnN0cmVhbV9vcHMgPSBkZXZpY2Uuc3RyZWFtX29wczsKICAgICAgICAgIGlmIChzdHJlYW0uc3RyZWFtX29wcy5vcGVuKSB7CiAgICAgICAgICAgIHN0cmVhbS5zdHJlYW1fb3BzLm9wZW4oc3RyZWFtKTsKICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIGxsc2VlazogZnVuY3Rpb24gKCkgewogICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoRVJSTk9fQ09ERVMuRVNQSVBFKQogICAgICAgIH0sCiAgICAgIH0sCiAgICAgIG1ham9yOiBmdW5jdGlvbiAoZGV2KSB7CiAgICAgICAgcmV0dXJuIGRldiA+PiA4CiAgICAgIH0sCiAgICAgIG1pbm9yOiBmdW5jdGlvbiAoZGV2KSB7CiAgICAgICAgcmV0dXJuIGRldiAmIDI1NQogICAgICB9LAogICAgICBtYWtlZGV2OiBmdW5jdGlvbiAobWEsIG1pKSB7CiAgICAgICAgcmV0dXJuIChtYSA8PCA4KSB8IG1pCiAgICAgIH0sCiAgICAgIHJlZ2lzdGVyRGV2aWNlOiBmdW5jdGlvbiAoZGV2LCBvcHMpIHsKICAgICAgICBGUy5kZXZpY2VzW2Rldl0gPSB7IHN0cmVhbV9vcHM6IG9wcyB9OwogICAgICB9LAogICAgICBnZXREZXZpY2U6IGZ1bmN0aW9uIChkZXYpIHsKICAgICAgICByZXR1cm4gRlMuZGV2aWNlc1tkZXZdCiAgICAgIH0sCiAgICAgIGdldE1vdW50czogZnVuY3Rpb24gKG1vdW50KSB7CiAgICAgICAgdmFyIG1vdW50cyA9IFtdOwogICAgICAgIHZhciBjaGVjayA9IFttb3VudF07CiAgICAgICAgd2hpbGUgKGNoZWNrLmxlbmd0aCkgewogICAgICAgICAgdmFyIG0gPSBjaGVjay5wb3AoKTsKICAgICAgICAgIG1vdW50cy5wdXNoKG0pOwogICAgICAgICAgY2hlY2sucHVzaC5hcHBseShjaGVjaywgbS5tb3VudHMpOwogICAgICAgIH0KICAgICAgICByZXR1cm4gbW91bnRzCiAgICAgIH0sCiAgICAgIHN5bmNmczogZnVuY3Rpb24gKHBvcHVsYXRlLCBjYWxsYmFjaykgewogICAgICAgIGlmICh0eXBlb2YgcG9wdWxhdGUgPT09ICdmdW5jdGlvbicpIHsKICAgICAgICAgIGNhbGxiYWNrID0gcG9wdWxhdGU7CiAgICAgICAgICBwb3B1bGF0ZSA9IGZhbHNlOwogICAgICAgIH0KICAgICAgICBGUy5zeW5jRlNSZXF1ZXN0cysrOwogICAgICAgIGlmIChGUy5zeW5jRlNSZXF1ZXN0cyA+IDEpIHsKICAgICAgICAgIGNvbnNvbGUubG9nKAogICAgICAgICAgICAnd2FybmluZzogJyArIEZTLnN5bmNGU1JlcXVlc3RzICsgJyBGUy5zeW5jZnMgb3BlcmF0aW9ucyBpbiBmbGlnaHQgYXQgb25jZSwgcHJvYmFibHkganVzdCBkb2luZyBleHRyYSB3b3JrJwogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgICAgdmFyIG1vdW50cyA9IEZTLmdldE1vdW50cyhGUy5yb290Lm1vdW50KTsKICAgICAgICB2YXIgY29tcGxldGVkID0gMDsKICAgICAgICBmdW5jdGlvbiBkb0NhbGxiYWNrKGVycikgewogICAgICAgICAgYXNzZXJ0KEZTLnN5bmNGU1JlcXVlc3RzID4gMCk7CiAgICAgICAgICBGUy5zeW5jRlNSZXF1ZXN0cy0tOwogICAgICAgICAgcmV0dXJuIGNhbGxiYWNrKGVycikKICAgICAgICB9CiAgICAgICAgZnVuY3Rpb24gZG9uZShlcnIpIHsKICAgICAgICAgIGlmIChlcnIpIHsKICAgICAgICAgICAgaWYgKCFkb25lLmVycm9yZWQpIHsKICAgICAgICAgICAgICBkb25lLmVycm9yZWQgPSB0cnVlOwogICAgICAgICAgICAgIHJldHVybiBkb0NhbGxiYWNrKGVycikKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4KICAgICAgICAgIH0KICAgICAgICAgIGlmICgrK2NvbXBsZXRlZCA+PSBtb3VudHMubGVuZ3RoKSB7CiAgICAgICAgICAgIGRvQ2FsbGJhY2sobnVsbCk7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIG1vdW50cy5mb3JFYWNoKGZ1bmN0aW9uIChtb3VudCkgewogICAgICAgICAgaWYgKCFtb3VudC50eXBlLnN5bmNmcykgewogICAgICAgICAgICByZXR1cm4gZG9uZShudWxsKQogICAgICAgICAgfQogICAgICAgICAgbW91bnQudHlwZS5zeW5jZnMobW91bnQsIHBvcHVsYXRlLCBkb25lKTsKICAgICAgICB9KTsKICAgICAgfSwKICAgICAgbW91bnQ6IGZ1bmN0aW9uICh0eXBlLCBvcHRzLCBtb3VudHBvaW50KSB7CiAgICAgICAgdmFyIHJvb3QgPSBtb3VudHBvaW50ID09PSAnLyc7CiAgICAgICAgdmFyIHBzZXVkbyA9ICFtb3VudHBvaW50OwogICAgICAgIHZhciBub2RlOwogICAgICAgIGlmIChyb290ICYmIEZTLnJvb3QpIHsKICAgICAgICAgIHRocm93IG5ldyBGUy5FcnJub0Vycm9yKEVSUk5PX0NPREVTLkVCVVNZKQogICAgICAgIH0gZWxzZSBpZiAoIXJvb3QgJiYgIXBzZXVkbykgewogICAgICAgICAgdmFyIGxvb2t1cCA9IEZTLmxvb2t1cFBhdGgobW91bnRwb2ludCwgeyBmb2xsb3dfbW91bnQ6IGZhbHNlIH0pOwogICAgICAgICAgbW91bnRwb2ludCA9IGxvb2t1cC5wYXRoOwogICAgICAgICAgbm9kZSA9IGxvb2t1cC5ub2RlOwogICAgICAgICAgaWYgKEZTLmlzTW91bnRwb2ludChub2RlKSkgewogICAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FQlVTWSkKICAgICAgICAgIH0KICAgICAgICAgIGlmICghRlMuaXNEaXIobm9kZS5tb2RlKSkgewogICAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FTk9URElSKQogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICB2YXIgbW91bnQgPSB7IHR5cGU6IHR5cGUsIG9wdHM6IG9wdHMsIG1vdW50cG9pbnQ6IG1vdW50cG9pbnQsIG1vdW50czogW10gfTsKICAgICAgICB2YXIgbW91bnRSb290ID0gdHlwZS5tb3VudChtb3VudCk7CiAgICAgICAgbW91bnRSb290Lm1vdW50ID0gbW91bnQ7CiAgICAgICAgbW91bnQucm9vdCA9IG1vdW50Um9vdDsKICAgICAgICBpZiAocm9vdCkgewogICAgICAgICAgRlMucm9vdCA9IG1vdW50Um9vdDsKICAgICAgICB9IGVsc2UgaWYgKG5vZGUpIHsKICAgICAgICAgIG5vZGUubW91bnRlZCA9IG1vdW50OwogICAgICAgICAgaWYgKG5vZGUubW91bnQpIHsKICAgICAgICAgICAgbm9kZS5tb3VudC5tb3VudHMucHVzaChtb3VudCk7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHJldHVybiBtb3VudFJvb3QKICAgICAgfSwKICAgICAgdW5tb3VudDogZnVuY3Rpb24gKG1vdW50cG9pbnQpIHsKICAgICAgICB2YXIgbG9va3VwID0gRlMubG9va3VwUGF0aChtb3VudHBvaW50LCB7IGZvbGxvd19tb3VudDogZmFsc2UgfSk7CiAgICAgICAgaWYgKCFGUy5pc01vdW50cG9pbnQobG9va3VwLm5vZGUpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FSU5WQUwpCiAgICAgICAgfQogICAgICAgIHZhciBub2RlID0gbG9va3VwLm5vZGU7CiAgICAgICAgdmFyIG1vdW50ID0gbm9kZS5tb3VudGVkOwogICAgICAgIHZhciBtb3VudHMgPSBGUy5nZXRNb3VudHMobW91bnQpOwogICAgICAgIE9iamVjdC5rZXlzKEZTLm5hbWVUYWJsZSkuZm9yRWFjaChmdW5jdGlvbiAoaGFzaCkgewogICAgICAgICAgdmFyIGN1cnJlbnQgPSBGUy5uYW1lVGFibGVbaGFzaF07CiAgICAgICAgICB3aGlsZSAoY3VycmVudCkgewogICAgICAgICAgICB2YXIgbmV4dCA9IGN1cnJlbnQubmFtZV9uZXh0OwogICAgICAgICAgICBpZiAobW91bnRzLmluZGV4T2YoY3VycmVudC5tb3VudCkgIT09IC0xKSB7CiAgICAgICAgICAgICAgRlMuZGVzdHJveU5vZGUoY3VycmVudCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgY3VycmVudCA9IG5leHQ7CiAgICAgICAgICB9CiAgICAgICAgfSk7CiAgICAgICAgbm9kZS5tb3VudGVkID0gbnVsbDsKICAgICAgICB2YXIgaWR4ID0gbm9kZS5tb3VudC5tb3VudHMuaW5kZXhPZihtb3VudCk7CiAgICAgICAgYXNzZXJ0KGlkeCAhPT0gLTEpOwogICAgICAgIG5vZGUubW91bnQubW91bnRzLnNwbGljZShpZHgsIDEpOwogICAgICB9LAogICAgICBsb29rdXA6IGZ1bmN0aW9uIChwYXJlbnQsIG5hbWUpIHsKICAgICAgICByZXR1cm4gcGFyZW50Lm5vZGVfb3BzLmxvb2t1cChwYXJlbnQsIG5hbWUpCiAgICAgIH0sCiAgICAgIG1rbm9kOiBmdW5jdGlvbiAocGF0aCwgbW9kZSwgZGV2KSB7CiAgICAgICAgdmFyIGxvb2t1cCA9IEZTLmxvb2t1cFBhdGgocGF0aCwgeyBwYXJlbnQ6IHRydWUgfSk7CiAgICAgICAgdmFyIHBhcmVudCA9IGxvb2t1cC5ub2RlOwogICAgICAgIHZhciBuYW1lID0gUEFUSC5iYXNlbmFtZShwYXRoKTsKICAgICAgICBpZiAoIW5hbWUgfHwgbmFtZSA9PT0gJy4nIHx8IG5hbWUgPT09ICcuLicpIHsKICAgICAgICAgIHRocm93IG5ldyBGUy5FcnJub0Vycm9yKEVSUk5PX0NPREVTLkVJTlZBTCkKICAgICAgICB9CiAgICAgICAgdmFyIGVyciA9IEZTLm1heUNyZWF0ZShwYXJlbnQsIG5hbWUpOwogICAgICAgIGlmIChlcnIpIHsKICAgICAgICAgIHRocm93IG5ldyBGUy5FcnJub0Vycm9yKGVycikKICAgICAgICB9CiAgICAgICAgaWYgKCFwYXJlbnQubm9kZV9vcHMubWtub2QpIHsKICAgICAgICAgIHRocm93IG5ldyBGUy5FcnJub0Vycm9yKEVSUk5PX0NPREVTLkVQRVJNKQogICAgICAgIH0KICAgICAgICByZXR1cm4gcGFyZW50Lm5vZGVfb3BzLm1rbm9kKHBhcmVudCwgbmFtZSwgbW9kZSwgZGV2KQogICAgICB9LAogICAgICBjcmVhdGU6IGZ1bmN0aW9uIChwYXRoLCBtb2RlKSB7CiAgICAgICAgbW9kZSA9IG1vZGUgIT09IHVuZGVmaW5lZCA/IG1vZGUgOiA0Mzg7CiAgICAgICAgbW9kZSAmPSA0MDk1OwogICAgICAgIG1vZGUgfD0gMzI3Njg7CiAgICAgICAgcmV0dXJuIEZTLm1rbm9kKHBhdGgsIG1vZGUsIDApCiAgICAgIH0sCiAgICAgIG1rZGlyOiBmdW5jdGlvbiAocGF0aCwgbW9kZSkgewogICAgICAgIG1vZGUgPSBtb2RlICE9PSB1bmRlZmluZWQgPyBtb2RlIDogNTExOwogICAgICAgIG1vZGUgJj0gNTExIHwgNTEyOwogICAgICAgIG1vZGUgfD0gMTYzODQ7CiAgICAgICAgcmV0dXJuIEZTLm1rbm9kKHBhdGgsIG1vZGUsIDApCiAgICAgIH0sCiAgICAgIG1rZGlyVHJlZTogZnVuY3Rpb24gKHBhdGgsIG1vZGUpIHsKICAgICAgICB2YXIgZGlycyA9IHBhdGguc3BsaXQoJy8nKTsKICAgICAgICB2YXIgZCA9ICcnOwogICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgZGlycy5sZW5ndGg7ICsraSkgewogICAgICAgICAgaWYgKCFkaXJzW2ldKSBjb250aW51ZQogICAgICAgICAgZCArPSAnLycgKyBkaXJzW2ldOwogICAgICAgICAgdHJ5IHsKICAgICAgICAgICAgRlMubWtkaXIoZCwgbW9kZSk7CiAgICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICAgIGlmIChlLmVycm5vICE9IEVSUk5PX0NPREVTLkVFWElTVCkgdGhyb3cgZQogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfSwKICAgICAgbWtkZXY6IGZ1bmN0aW9uIChwYXRoLCBtb2RlLCBkZXYpIHsKICAgICAgICBpZiAodHlwZW9mIGRldiA9PT0gJ3VuZGVmaW5lZCcpIHsKICAgICAgICAgIGRldiA9IG1vZGU7CiAgICAgICAgICBtb2RlID0gNDM4OwogICAgICAgIH0KICAgICAgICBtb2RlIHw9IDgxOTI7CiAgICAgICAgcmV0dXJuIEZTLm1rbm9kKHBhdGgsIG1vZGUsIGRldikKICAgICAgfSwKICAgICAgc3ltbGluazogZnVuY3Rpb24gKG9sZHBhdGgsIG5ld3BhdGgpIHsKICAgICAgICBpZiAoIVBBVEgucmVzb2x2ZShvbGRwYXRoKSkgewogICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoRVJSTk9fQ09ERVMuRU5PRU5UKQogICAgICAgIH0KICAgICAgICB2YXIgbG9va3VwID0gRlMubG9va3VwUGF0aChuZXdwYXRoLCB7IHBhcmVudDogdHJ1ZSB9KTsKICAgICAgICB2YXIgcGFyZW50ID0gbG9va3VwLm5vZGU7CiAgICAgICAgaWYgKCFwYXJlbnQpIHsKICAgICAgICAgIHRocm93IG5ldyBGUy5FcnJub0Vycm9yKEVSUk5PX0NPREVTLkVOT0VOVCkKICAgICAgICB9CiAgICAgICAgdmFyIG5ld25hbWUgPSBQQVRILmJhc2VuYW1lKG5ld3BhdGgpOwogICAgICAgIHZhciBlcnIgPSBGUy5tYXlDcmVhdGUocGFyZW50LCBuZXduYW1lKTsKICAgICAgICBpZiAoZXJyKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihlcnIpCiAgICAgICAgfQogICAgICAgIGlmICghcGFyZW50Lm5vZGVfb3BzLnN5bWxpbmspIHsKICAgICAgICAgIHRocm93IG5ldyBGUy5FcnJub0Vycm9yKEVSUk5PX0NPREVTLkVQRVJNKQogICAgICAgIH0KICAgICAgICByZXR1cm4gcGFyZW50Lm5vZGVfb3BzLnN5bWxpbmsocGFyZW50LCBuZXduYW1lLCBvbGRwYXRoKQogICAgICB9LAogICAgICByZW5hbWU6IGZ1bmN0aW9uIChvbGRfcGF0aCwgbmV3X3BhdGgpIHsKICAgICAgICB2YXIgb2xkX2Rpcm5hbWUgPSBQQVRILmRpcm5hbWUob2xkX3BhdGgpOwogICAgICAgIHZhciBuZXdfZGlybmFtZSA9IFBBVEguZGlybmFtZShuZXdfcGF0aCk7CiAgICAgICAgdmFyIG9sZF9uYW1lID0gUEFUSC5iYXNlbmFtZShvbGRfcGF0aCk7CiAgICAgICAgdmFyIG5ld19uYW1lID0gUEFUSC5iYXNlbmFtZShuZXdfcGF0aCk7CiAgICAgICAgdmFyIGxvb2t1cCwgb2xkX2RpciwgbmV3X2RpcjsKICAgICAgICB0cnkgewogICAgICAgICAgbG9va3VwID0gRlMubG9va3VwUGF0aChvbGRfcGF0aCwgeyBwYXJlbnQ6IHRydWUgfSk7CiAgICAgICAgICBvbGRfZGlyID0gbG9va3VwLm5vZGU7CiAgICAgICAgICBsb29rdXAgPSBGUy5sb29rdXBQYXRoKG5ld19wYXRoLCB7IHBhcmVudDogdHJ1ZSB9KTsKICAgICAgICAgIG5ld19kaXIgPSBsb29rdXAubm9kZTsKICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FQlVTWSkKICAgICAgICB9CiAgICAgICAgaWYgKCFvbGRfZGlyIHx8ICFuZXdfZGlyKSB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FTk9FTlQpCiAgICAgICAgaWYgKG9sZF9kaXIubW91bnQgIT09IG5ld19kaXIubW91bnQpIHsKICAgICAgICAgIHRocm93IG5ldyBGUy5FcnJub0Vycm9yKEVSUk5PX0NPREVTLkVYREVWKQogICAgICAgIH0KICAgICAgICB2YXIgb2xkX25vZGUgPSBGUy5sb29rdXBOb2RlKG9sZF9kaXIsIG9sZF9uYW1lKTsKICAgICAgICB2YXIgcmVsYXRpdmUgPSBQQVRILnJlbGF0aXZlKG9sZF9wYXRoLCBuZXdfZGlybmFtZSk7CiAgICAgICAgaWYgKHJlbGF0aXZlLmNoYXJBdCgwKSAhPT0gJy4nKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FSU5WQUwpCiAgICAgICAgfQogICAgICAgIHJlbGF0aXZlID0gUEFUSC5yZWxhdGl2ZShuZXdfcGF0aCwgb2xkX2Rpcm5hbWUpOwogICAgICAgIGlmIChyZWxhdGl2ZS5jaGFyQXQoMCkgIT09ICcuJykgewogICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoRVJSTk9fQ09ERVMuRU5PVEVNUFRZKQogICAgICAgIH0KICAgICAgICB2YXIgbmV3X25vZGU7CiAgICAgICAgdHJ5IHsKICAgICAgICAgIG5ld19ub2RlID0gRlMubG9va3VwTm9kZShuZXdfZGlyLCBuZXdfbmFtZSk7CiAgICAgICAgfSBjYXRjaCAoZSkge30KICAgICAgICBpZiAob2xkX25vZGUgPT09IG5ld19ub2RlKSB7CiAgICAgICAgICByZXR1cm4KICAgICAgICB9CiAgICAgICAgdmFyIGlzZGlyID0gRlMuaXNEaXIob2xkX25vZGUubW9kZSk7CiAgICAgICAgdmFyIGVyciA9IEZTLm1heURlbGV0ZShvbGRfZGlyLCBvbGRfbmFtZSwgaXNkaXIpOwogICAgICAgIGlmIChlcnIpIHsKICAgICAgICAgIHRocm93IG5ldyBGUy5FcnJub0Vycm9yKGVycikKICAgICAgICB9CiAgICAgICAgZXJyID0gbmV3X25vZGUgPyBGUy5tYXlEZWxldGUobmV3X2RpciwgbmV3X25hbWUsIGlzZGlyKSA6IEZTLm1heUNyZWF0ZShuZXdfZGlyLCBuZXdfbmFtZSk7CiAgICAgICAgaWYgKGVycikgewogICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoZXJyKQogICAgICAgIH0KICAgICAgICBpZiAoIW9sZF9kaXIubm9kZV9vcHMucmVuYW1lKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FUEVSTSkKICAgICAgICB9CiAgICAgICAgaWYgKEZTLmlzTW91bnRwb2ludChvbGRfbm9kZSkgfHwgKG5ld19ub2RlICYmIEZTLmlzTW91bnRwb2ludChuZXdfbm9kZSkpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FQlVTWSkKICAgICAgICB9CiAgICAgICAgaWYgKG5ld19kaXIgIT09IG9sZF9kaXIpIHsKICAgICAgICAgIGVyciA9IEZTLm5vZGVQZXJtaXNzaW9ucyhvbGRfZGlyLCAndycpOwogICAgICAgICAgaWYgKGVycikgewogICAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihlcnIpCiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHRyeSB7CiAgICAgICAgICBpZiAoRlMudHJhY2tpbmdEZWxlZ2F0ZVsnd2lsbE1vdmVQYXRoJ10pIHsKICAgICAgICAgICAgRlMudHJhY2tpbmdEZWxlZ2F0ZVsnd2lsbE1vdmVQYXRoJ10ob2xkX3BhdGgsIG5ld19wYXRoKTsKICAgICAgICAgIH0KICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICBjb25zb2xlLmxvZygKICAgICAgICAgICAgIkZTLnRyYWNraW5nRGVsZWdhdGVbJ3dpbGxNb3ZlUGF0aCddKCciICsgb2xkX3BhdGggKyAiJywgJyIgKyBuZXdfcGF0aCArICInKSB0aHJldyBhbiBleGNlcHRpb246ICIgKyBlLm1lc3NhZ2UKICAgICAgICAgICk7CiAgICAgICAgfQogICAgICAgIEZTLmhhc2hSZW1vdmVOb2RlKG9sZF9ub2RlKTsKICAgICAgICB0cnkgewogICAgICAgICAgb2xkX2Rpci5ub2RlX29wcy5yZW5hbWUob2xkX25vZGUsIG5ld19kaXIsIG5ld19uYW1lKTsKICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICB0aHJvdyBlCiAgICAgICAgfSBmaW5hbGx5IHsKICAgICAgICAgIEZTLmhhc2hBZGROb2RlKG9sZF9ub2RlKTsKICAgICAgICB9CiAgICAgICAgdHJ5IHsKICAgICAgICAgIGlmIChGUy50cmFja2luZ0RlbGVnYXRlWydvbk1vdmVQYXRoJ10pIEZTLnRyYWNraW5nRGVsZWdhdGVbJ29uTW92ZVBhdGgnXShvbGRfcGF0aCwgbmV3X3BhdGgpOwogICAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICAgIGNvbnNvbGUubG9nKAogICAgICAgICAgICAiRlMudHJhY2tpbmdEZWxlZ2F0ZVsnb25Nb3ZlUGF0aCddKCciICsgb2xkX3BhdGggKyAiJywgJyIgKyBuZXdfcGF0aCArICInKSB0aHJldyBhbiBleGNlcHRpb246ICIgKyBlLm1lc3NhZ2UKICAgICAgICAgICk7CiAgICAgICAgfQogICAgICB9LAogICAgICBybWRpcjogZnVuY3Rpb24gKHBhdGgpIHsKICAgICAgICB2YXIgbG9va3VwID0gRlMubG9va3VwUGF0aChwYXRoLCB7IHBhcmVudDogdHJ1ZSB9KTsKICAgICAgICB2YXIgcGFyZW50ID0gbG9va3VwLm5vZGU7CiAgICAgICAgdmFyIG5hbWUgPSBQQVRILmJhc2VuYW1lKHBhdGgpOwogICAgICAgIHZhciBub2RlID0gRlMubG9va3VwTm9kZShwYXJlbnQsIG5hbWUpOwogICAgICAgIHZhciBlcnIgPSBGUy5tYXlEZWxldGUocGFyZW50LCBuYW1lLCB0cnVlKTsKICAgICAgICBpZiAoZXJyKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihlcnIpCiAgICAgICAgfQogICAgICAgIGlmICghcGFyZW50Lm5vZGVfb3BzLnJtZGlyKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FUEVSTSkKICAgICAgICB9CiAgICAgICAgaWYgKEZTLmlzTW91bnRwb2ludChub2RlKSkgewogICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoRVJSTk9fQ09ERVMuRUJVU1kpCiAgICAgICAgfQogICAgICAgIHRyeSB7CiAgICAgICAgICBpZiAoRlMudHJhY2tpbmdEZWxlZ2F0ZVsnd2lsbERlbGV0ZVBhdGgnXSkgewogICAgICAgICAgICBGUy50cmFja2luZ0RlbGVnYXRlWyd3aWxsRGVsZXRlUGF0aCddKHBhdGgpOwogICAgICAgICAgfQogICAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICAgIGNvbnNvbGUubG9nKCJGUy50cmFja2luZ0RlbGVnYXRlWyd3aWxsRGVsZXRlUGF0aCddKCciICsgcGF0aCArICInKSB0aHJldyBhbiBleGNlcHRpb246ICIgKyBlLm1lc3NhZ2UpOwogICAgICAgIH0KICAgICAgICBwYXJlbnQubm9kZV9vcHMucm1kaXIocGFyZW50LCBuYW1lKTsKICAgICAgICBGUy5kZXN0cm95Tm9kZShub2RlKTsKICAgICAgICB0cnkgewogICAgICAgICAgaWYgKEZTLnRyYWNraW5nRGVsZWdhdGVbJ29uRGVsZXRlUGF0aCddKSBGUy50cmFja2luZ0RlbGVnYXRlWydvbkRlbGV0ZVBhdGgnXShwYXRoKTsKICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICBjb25zb2xlLmxvZygiRlMudHJhY2tpbmdEZWxlZ2F0ZVsnb25EZWxldGVQYXRoJ10oJyIgKyBwYXRoICsgIicpIHRocmV3IGFuIGV4Y2VwdGlvbjogIiArIGUubWVzc2FnZSk7CiAgICAgICAgfQogICAgICB9LAogICAgICByZWFkZGlyOiBmdW5jdGlvbiAocGF0aCkgewogICAgICAgIHZhciBsb29rdXAgPSBGUy5sb29rdXBQYXRoKHBhdGgsIHsgZm9sbG93OiB0cnVlIH0pOwogICAgICAgIHZhciBub2RlID0gbG9va3VwLm5vZGU7CiAgICAgICAgaWYgKCFub2RlLm5vZGVfb3BzLnJlYWRkaXIpIHsKICAgICAgICAgIHRocm93IG5ldyBGUy5FcnJub0Vycm9yKEVSUk5PX0NPREVTLkVOT1RESVIpCiAgICAgICAgfQogICAgICAgIHJldHVybiBub2RlLm5vZGVfb3BzLnJlYWRkaXIobm9kZSkKICAgICAgfSwKICAgICAgdW5saW5rOiBmdW5jdGlvbiAocGF0aCkgewogICAgICAgIHZhciBsb29rdXAgPSBGUy5sb29rdXBQYXRoKHBhdGgsIHsgcGFyZW50OiB0cnVlIH0pOwogICAgICAgIHZhciBwYXJlbnQgPSBsb29rdXAubm9kZTsKICAgICAgICB2YXIgbmFtZSA9IFBBVEguYmFzZW5hbWUocGF0aCk7CiAgICAgICAgdmFyIG5vZGUgPSBGUy5sb29rdXBOb2RlKHBhcmVudCwgbmFtZSk7CiAgICAgICAgdmFyIGVyciA9IEZTLm1heURlbGV0ZShwYXJlbnQsIG5hbWUsIGZhbHNlKTsKICAgICAgICBpZiAoZXJyKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihlcnIpCiAgICAgICAgfQogICAgICAgIGlmICghcGFyZW50Lm5vZGVfb3BzLnVubGluaykgewogICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoRVJSTk9fQ09ERVMuRVBFUk0pCiAgICAgICAgfQogICAgICAgIGlmIChGUy5pc01vdW50cG9pbnQobm9kZSkpIHsKICAgICAgICAgIHRocm93IG5ldyBGUy5FcnJub0Vycm9yKEVSUk5PX0NPREVTLkVCVVNZKQogICAgICAgIH0KICAgICAgICB0cnkgewogICAgICAgICAgaWYgKEZTLnRyYWNraW5nRGVsZWdhdGVbJ3dpbGxEZWxldGVQYXRoJ10pIHsKICAgICAgICAgICAgRlMudHJhY2tpbmdEZWxlZ2F0ZVsnd2lsbERlbGV0ZVBhdGgnXShwYXRoKTsKICAgICAgICAgIH0KICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICBjb25zb2xlLmxvZygiRlMudHJhY2tpbmdEZWxlZ2F0ZVsnd2lsbERlbGV0ZVBhdGgnXSgnIiArIHBhdGggKyAiJykgdGhyZXcgYW4gZXhjZXB0aW9uOiAiICsgZS5tZXNzYWdlKTsKICAgICAgICB9CiAgICAgICAgcGFyZW50Lm5vZGVfb3BzLnVubGluayhwYXJlbnQsIG5hbWUpOwogICAgICAgIEZTLmRlc3Ryb3lOb2RlKG5vZGUpOwogICAgICAgIHRyeSB7CiAgICAgICAgICBpZiAoRlMudHJhY2tpbmdEZWxlZ2F0ZVsnb25EZWxldGVQYXRoJ10pIEZTLnRyYWNraW5nRGVsZWdhdGVbJ29uRGVsZXRlUGF0aCddKHBhdGgpOwogICAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICAgIGNvbnNvbGUubG9nKCJGUy50cmFja2luZ0RlbGVnYXRlWydvbkRlbGV0ZVBhdGgnXSgnIiArIHBhdGggKyAiJykgdGhyZXcgYW4gZXhjZXB0aW9uOiAiICsgZS5tZXNzYWdlKTsKICAgICAgICB9CiAgICAgIH0sCiAgICAgIHJlYWRsaW5rOiBmdW5jdGlvbiAocGF0aCkgewogICAgICAgIHZhciBsb29rdXAgPSBGUy5sb29rdXBQYXRoKHBhdGgpOwogICAgICAgIHZhciBsaW5rID0gbG9va3VwLm5vZGU7CiAgICAgICAgaWYgKCFsaW5rKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FTk9FTlQpCiAgICAgICAgfQogICAgICAgIGlmICghbGluay5ub2RlX29wcy5yZWFkbGluaykgewogICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoRVJSTk9fQ09ERVMuRUlOVkFMKQogICAgICAgIH0KICAgICAgICByZXR1cm4gUEFUSC5yZXNvbHZlKEZTLmdldFBhdGgobGluay5wYXJlbnQpLCBsaW5rLm5vZGVfb3BzLnJlYWRsaW5rKGxpbmspKQogICAgICB9LAogICAgICBzdGF0OiBmdW5jdGlvbiAocGF0aCwgZG9udEZvbGxvdykgewogICAgICAgIHZhciBsb29rdXAgPSBGUy5sb29rdXBQYXRoKHBhdGgsIHsgZm9sbG93OiAhZG9udEZvbGxvdyB9KTsKICAgICAgICB2YXIgbm9kZSA9IGxvb2t1cC5ub2RlOwogICAgICAgIGlmICghbm9kZSkgewogICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoRVJSTk9fQ09ERVMuRU5PRU5UKQogICAgICAgIH0KICAgICAgICBpZiAoIW5vZGUubm9kZV9vcHMuZ2V0YXR0cikgewogICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoRVJSTk9fQ09ERVMuRVBFUk0pCiAgICAgICAgfQogICAgICAgIHJldHVybiBub2RlLm5vZGVfb3BzLmdldGF0dHIobm9kZSkKICAgICAgfSwKICAgICAgbHN0YXQ6IGZ1bmN0aW9uIChwYXRoKSB7CiAgICAgICAgcmV0dXJuIEZTLnN0YXQocGF0aCwgdHJ1ZSkKICAgICAgfSwKICAgICAgY2htb2Q6IGZ1bmN0aW9uIChwYXRoLCBtb2RlLCBkb250Rm9sbG93KSB7CiAgICAgICAgdmFyIG5vZGU7CiAgICAgICAgaWYgKHR5cGVvZiBwYXRoID09PSAnc3RyaW5nJykgewogICAgICAgICAgdmFyIGxvb2t1cCA9IEZTLmxvb2t1cFBhdGgocGF0aCwgeyBmb2xsb3c6ICFkb250Rm9sbG93IH0pOwogICAgICAgICAgbm9kZSA9IGxvb2t1cC5ub2RlOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBub2RlID0gcGF0aDsKICAgICAgICB9CiAgICAgICAgaWYgKCFub2RlLm5vZGVfb3BzLnNldGF0dHIpIHsKICAgICAgICAgIHRocm93IG5ldyBGUy5FcnJub0Vycm9yKEVSUk5PX0NPREVTLkVQRVJNKQogICAgICAgIH0KICAgICAgICBub2RlLm5vZGVfb3BzLnNldGF0dHIobm9kZSwgeyBtb2RlOiAobW9kZSAmIDQwOTUpIHwgKG5vZGUubW9kZSAmIH40MDk1KSwgdGltZXN0YW1wOiBEYXRlLm5vdygpIH0pOwogICAgICB9LAogICAgICBsY2htb2Q6IGZ1bmN0aW9uIChwYXRoLCBtb2RlKSB7CiAgICAgICAgRlMuY2htb2QocGF0aCwgbW9kZSwgdHJ1ZSk7CiAgICAgIH0sCiAgICAgIGZjaG1vZDogZnVuY3Rpb24gKGZkLCBtb2RlKSB7CiAgICAgICAgdmFyIHN0cmVhbSA9IEZTLmdldFN0cmVhbShmZCk7CiAgICAgICAgaWYgKCFzdHJlYW0pIHsKICAgICAgICAgIHRocm93IG5ldyBGUy5FcnJub0Vycm9yKEVSUk5PX0NPREVTLkVCQURGKQogICAgICAgIH0KICAgICAgICBGUy5jaG1vZChzdHJlYW0ubm9kZSwgbW9kZSk7CiAgICAgIH0sCiAgICAgIGNob3duOiBmdW5jdGlvbiAocGF0aCwgdWlkLCBnaWQsIGRvbnRGb2xsb3cpIHsKICAgICAgICB2YXIgbm9kZTsKICAgICAgICBpZiAodHlwZW9mIHBhdGggPT09ICdzdHJpbmcnKSB7CiAgICAgICAgICB2YXIgbG9va3VwID0gRlMubG9va3VwUGF0aChwYXRoLCB7IGZvbGxvdzogIWRvbnRGb2xsb3cgfSk7CiAgICAgICAgICBub2RlID0gbG9va3VwLm5vZGU7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIG5vZGUgPSBwYXRoOwogICAgICAgIH0KICAgICAgICBpZiAoIW5vZGUubm9kZV9vcHMuc2V0YXR0cikgewogICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoRVJSTk9fQ09ERVMuRVBFUk0pCiAgICAgICAgfQogICAgICAgIG5vZGUubm9kZV9vcHMuc2V0YXR0cihub2RlLCB7IHRpbWVzdGFtcDogRGF0ZS5ub3coKSB9KTsKICAgICAgfSwKICAgICAgbGNob3duOiBmdW5jdGlvbiAocGF0aCwgdWlkLCBnaWQpIHsKICAgICAgICBGUy5jaG93bihwYXRoLCB1aWQsIGdpZCwgdHJ1ZSk7CiAgICAgIH0sCiAgICAgIGZjaG93bjogZnVuY3Rpb24gKGZkLCB1aWQsIGdpZCkgewogICAgICAgIHZhciBzdHJlYW0gPSBGUy5nZXRTdHJlYW0oZmQpOwogICAgICAgIGlmICghc3RyZWFtKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FQkFERikKICAgICAgICB9CiAgICAgICAgRlMuY2hvd24oc3RyZWFtLm5vZGUsIHVpZCwgZ2lkKTsKICAgICAgfSwKICAgICAgdHJ1bmNhdGU6IGZ1bmN0aW9uIChwYXRoLCBsZW4pIHsKICAgICAgICBpZiAobGVuIDwgMCkgewogICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoRVJSTk9fQ09ERVMuRUlOVkFMKQogICAgICAgIH0KICAgICAgICB2YXIgbm9kZTsKICAgICAgICBpZiAodHlwZW9mIHBhdGggPT09ICdzdHJpbmcnKSB7CiAgICAgICAgICB2YXIgbG9va3VwID0gRlMubG9va3VwUGF0aChwYXRoLCB7IGZvbGxvdzogdHJ1ZSB9KTsKICAgICAgICAgIG5vZGUgPSBsb29rdXAubm9kZTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgbm9kZSA9IHBhdGg7CiAgICAgICAgfQogICAgICAgIGlmICghbm9kZS5ub2RlX29wcy5zZXRhdHRyKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FUEVSTSkKICAgICAgICB9CiAgICAgICAgaWYgKEZTLmlzRGlyKG5vZGUubW9kZSkpIHsKICAgICAgICAgIHRocm93IG5ldyBGUy5FcnJub0Vycm9yKEVSUk5PX0NPREVTLkVJU0RJUikKICAgICAgICB9CiAgICAgICAgaWYgKCFGUy5pc0ZpbGUobm9kZS5tb2RlKSkgewogICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoRVJSTk9fQ09ERVMuRUlOVkFMKQogICAgICAgIH0KICAgICAgICB2YXIgZXJyID0gRlMubm9kZVBlcm1pc3Npb25zKG5vZGUsICd3Jyk7CiAgICAgICAgaWYgKGVycikgewogICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoZXJyKQogICAgICAgIH0KICAgICAgICBub2RlLm5vZGVfb3BzLnNldGF0dHIobm9kZSwgeyBzaXplOiBsZW4sIHRpbWVzdGFtcDogRGF0ZS5ub3coKSB9KTsKICAgICAgfSwKICAgICAgZnRydW5jYXRlOiBmdW5jdGlvbiAoZmQsIGxlbikgewogICAgICAgIHZhciBzdHJlYW0gPSBGUy5nZXRTdHJlYW0oZmQpOwogICAgICAgIGlmICghc3RyZWFtKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FQkFERikKICAgICAgICB9CiAgICAgICAgaWYgKChzdHJlYW0uZmxhZ3MgJiAyMDk3MTU1KSA9PT0gMCkgewogICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoRVJSTk9fQ09ERVMuRUlOVkFMKQogICAgICAgIH0KICAgICAgICBGUy50cnVuY2F0ZShzdHJlYW0ubm9kZSwgbGVuKTsKICAgICAgfSwKICAgICAgdXRpbWU6IGZ1bmN0aW9uIChwYXRoLCBhdGltZSwgbXRpbWUpIHsKICAgICAgICB2YXIgbG9va3VwID0gRlMubG9va3VwUGF0aChwYXRoLCB7IGZvbGxvdzogdHJ1ZSB9KTsKICAgICAgICB2YXIgbm9kZSA9IGxvb2t1cC5ub2RlOwogICAgICAgIG5vZGUubm9kZV9vcHMuc2V0YXR0cihub2RlLCB7IHRpbWVzdGFtcDogTWF0aC5tYXgoYXRpbWUsIG10aW1lKSB9KTsKICAgICAgfSwKICAgICAgb3BlbjogZnVuY3Rpb24gKHBhdGgsIGZsYWdzLCBtb2RlLCBmZF9zdGFydCwgZmRfZW5kKSB7CiAgICAgICAgaWYgKHBhdGggPT09ICcnKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FTk9FTlQpCiAgICAgICAgfQogICAgICAgIGZsYWdzID0gdHlwZW9mIGZsYWdzID09PSAnc3RyaW5nJyA/IEZTLm1vZGVTdHJpbmdUb0ZsYWdzKGZsYWdzKSA6IGZsYWdzOwogICAgICAgIG1vZGUgPSB0eXBlb2YgbW9kZSA9PT0gJ3VuZGVmaW5lZCcgPyA0MzggOiBtb2RlOwogICAgICAgIGlmIChmbGFncyAmIDY0KSB7CiAgICAgICAgICBtb2RlID0gKG1vZGUgJiA0MDk1KSB8IDMyNzY4OwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBtb2RlID0gMDsKICAgICAgICB9CiAgICAgICAgdmFyIG5vZGU7CiAgICAgICAgaWYgKHR5cGVvZiBwYXRoID09PSAnb2JqZWN0JykgewogICAgICAgICAgbm9kZSA9IHBhdGg7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIHBhdGggPSBQQVRILm5vcm1hbGl6ZShwYXRoKTsKICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgIHZhciBsb29rdXAgPSBGUy5sb29rdXBQYXRoKHBhdGgsIHsgZm9sbG93OiAhKGZsYWdzICYgMTMxMDcyKSB9KTsKICAgICAgICAgICAgbm9kZSA9IGxvb2t1cC5ub2RlOwogICAgICAgICAgfSBjYXRjaCAoZSkge30KICAgICAgICB9CiAgICAgICAgdmFyIGNyZWF0ZWQgPSBmYWxzZTsKICAgICAgICBpZiAoZmxhZ3MgJiA2NCkgewogICAgICAgICAgaWYgKG5vZGUpIHsKICAgICAgICAgICAgaWYgKGZsYWdzICYgMTI4KSB7CiAgICAgICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoRVJSTk9fQ09ERVMuRUVYSVNUKQogICAgICAgICAgICB9CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBub2RlID0gRlMubWtub2QocGF0aCwgbW9kZSwgMCk7CiAgICAgICAgICAgIGNyZWF0ZWQgPSB0cnVlOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBpZiAoIW5vZGUpIHsKICAgICAgICAgIHRocm93IG5ldyBGUy5FcnJub0Vycm9yKEVSUk5PX0NPREVTLkVOT0VOVCkKICAgICAgICB9CiAgICAgICAgaWYgKEZTLmlzQ2hyZGV2KG5vZGUubW9kZSkpIHsKICAgICAgICAgIGZsYWdzICY9IH41MTI7CiAgICAgICAgfQogICAgICAgIGlmIChmbGFncyAmIDY1NTM2ICYmICFGUy5pc0Rpcihub2RlLm1vZGUpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FTk9URElSKQogICAgICAgIH0KICAgICAgICBpZiAoIWNyZWF0ZWQpIHsKICAgICAgICAgIHZhciBlcnIgPSBGUy5tYXlPcGVuKG5vZGUsIGZsYWdzKTsKICAgICAgICAgIGlmIChlcnIpIHsKICAgICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoZXJyKQogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBpZiAoZmxhZ3MgJiA1MTIpIHsKICAgICAgICAgIEZTLnRydW5jYXRlKG5vZGUsIDApOwogICAgICAgIH0KICAgICAgICBmbGFncyAmPSB+KDEyOCB8IDUxMik7CiAgICAgICAgdmFyIHN0cmVhbSA9IEZTLmNyZWF0ZVN0cmVhbSgKICAgICAgICAgIHsKICAgICAgICAgICAgbm9kZTogbm9kZSwKICAgICAgICAgICAgcGF0aDogRlMuZ2V0UGF0aChub2RlKSwKICAgICAgICAgICAgZmxhZ3M6IGZsYWdzLAogICAgICAgICAgICBzZWVrYWJsZTogdHJ1ZSwKICAgICAgICAgICAgcG9zaXRpb246IDAsCiAgICAgICAgICAgIHN0cmVhbV9vcHM6IG5vZGUuc3RyZWFtX29wcywKICAgICAgICAgICAgdW5nb3R0ZW46IFtdLAogICAgICAgICAgICBlcnJvcjogZmFsc2UsCiAgICAgICAgICB9LAogICAgICAgICAgZmRfc3RhcnQsCiAgICAgICAgICBmZF9lbmQKICAgICAgICApOwogICAgICAgIGlmIChzdHJlYW0uc3RyZWFtX29wcy5vcGVuKSB7CiAgICAgICAgICBzdHJlYW0uc3RyZWFtX29wcy5vcGVuKHN0cmVhbSk7CiAgICAgICAgfQogICAgICAgIGlmIChNb2R1bGVbJ2xvZ1JlYWRGaWxlcyddICYmICEoZmxhZ3MgJiAxKSkgewogICAgICAgICAgaWYgKCFGUy5yZWFkRmlsZXMpIEZTLnJlYWRGaWxlcyA9IHt9OwogICAgICAgICAgaWYgKCEocGF0aCBpbiBGUy5yZWFkRmlsZXMpKSB7CiAgICAgICAgICAgIEZTLnJlYWRGaWxlc1twYXRoXSA9IDE7CiAgICAgICAgICAgIE1vZHVsZVsncHJpbnRFcnInXSgncmVhZCBmaWxlOiAnICsgcGF0aCk7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHRyeSB7CiAgICAgICAgICBpZiAoRlMudHJhY2tpbmdEZWxlZ2F0ZVsnb25PcGVuRmlsZSddKSB7CiAgICAgICAgICAgIHZhciB0cmFja2luZ0ZsYWdzID0gMDsKICAgICAgICAgICAgaWYgKChmbGFncyAmIDIwOTcxNTUpICE9PSAxKSB7CiAgICAgICAgICAgICAgdHJhY2tpbmdGbGFncyB8PSBGUy50cmFja2luZy5vcGVuRmxhZ3MuUkVBRDsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoKGZsYWdzICYgMjA5NzE1NSkgIT09IDApIHsKICAgICAgICAgICAgICB0cmFja2luZ0ZsYWdzIHw9IEZTLnRyYWNraW5nLm9wZW5GbGFncy5XUklURTsKICAgICAgICAgICAgfQogICAgICAgICAgICBGUy50cmFja2luZ0RlbGVnYXRlWydvbk9wZW5GaWxlJ10ocGF0aCwgdHJhY2tpbmdGbGFncyk7CiAgICAgICAgICB9CiAgICAgICAgfSBjYXRjaCAoZSkgewogICAgICAgICAgY29uc29sZS5sb2coIkZTLnRyYWNraW5nRGVsZWdhdGVbJ29uT3BlbkZpbGUnXSgnIiArIHBhdGggKyAiJywgZmxhZ3MpIHRocmV3IGFuIGV4Y2VwdGlvbjogIiArIGUubWVzc2FnZSk7CiAgICAgICAgfQogICAgICAgIHJldHVybiBzdHJlYW0KICAgICAgfSwKICAgICAgY2xvc2U6IGZ1bmN0aW9uIChzdHJlYW0pIHsKICAgICAgICBpZiAoRlMuaXNDbG9zZWQoc3RyZWFtKSkgewogICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoRVJSTk9fQ09ERVMuRUJBREYpCiAgICAgICAgfQogICAgICAgIGlmIChzdHJlYW0uZ2V0ZGVudHMpIHN0cmVhbS5nZXRkZW50cyA9IG51bGw7CiAgICAgICAgdHJ5IHsKICAgICAgICAgIGlmIChzdHJlYW0uc3RyZWFtX29wcy5jbG9zZSkgewogICAgICAgICAgICBzdHJlYW0uc3RyZWFtX29wcy5jbG9zZShzdHJlYW0pOwogICAgICAgICAgfQogICAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICAgIHRocm93IGUKICAgICAgICB9IGZpbmFsbHkgewogICAgICAgICAgRlMuY2xvc2VTdHJlYW0oc3RyZWFtLmZkKTsKICAgICAgICB9CiAgICAgICAgc3RyZWFtLmZkID0gbnVsbDsKICAgICAgfSwKICAgICAgaXNDbG9zZWQ6IGZ1bmN0aW9uIChzdHJlYW0pIHsKICAgICAgICByZXR1cm4gc3RyZWFtLmZkID09PSBudWxsCiAgICAgIH0sCiAgICAgIGxsc2VlazogZnVuY3Rpb24gKHN0cmVhbSwgb2Zmc2V0LCB3aGVuY2UpIHsKICAgICAgICBpZiAoRlMuaXNDbG9zZWQoc3RyZWFtKSkgewogICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoRVJSTk9fQ09ERVMuRUJBREYpCiAgICAgICAgfQogICAgICAgIGlmICghc3RyZWFtLnNlZWthYmxlIHx8ICFzdHJlYW0uc3RyZWFtX29wcy5sbHNlZWspIHsKICAgICAgICAgIHRocm93IG5ldyBGUy5FcnJub0Vycm9yKEVSUk5PX0NPREVTLkVTUElQRSkKICAgICAgICB9CiAgICAgICAgc3RyZWFtLnBvc2l0aW9uID0gc3RyZWFtLnN0cmVhbV9vcHMubGxzZWVrKHN0cmVhbSwgb2Zmc2V0LCB3aGVuY2UpOwogICAgICAgIHN0cmVhbS51bmdvdHRlbiA9IFtdOwogICAgICAgIHJldHVybiBzdHJlYW0ucG9zaXRpb24KICAgICAgfSwKICAgICAgcmVhZDogZnVuY3Rpb24gKHN0cmVhbSwgYnVmZmVyLCBvZmZzZXQsIGxlbmd0aCwgcG9zaXRpb24pIHsKICAgICAgICBpZiAobGVuZ3RoIDwgMCB8fCBwb3NpdGlvbiA8IDApIHsKICAgICAgICAgIHRocm93IG5ldyBGUy5FcnJub0Vycm9yKEVSUk5PX0NPREVTLkVJTlZBTCkKICAgICAgICB9CiAgICAgICAgaWYgKEZTLmlzQ2xvc2VkKHN0cmVhbSkpIHsKICAgICAgICAgIHRocm93IG5ldyBGUy5FcnJub0Vycm9yKEVSUk5PX0NPREVTLkVCQURGKQogICAgICAgIH0KICAgICAgICBpZiAoKHN0cmVhbS5mbGFncyAmIDIwOTcxNTUpID09PSAxKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FQkFERikKICAgICAgICB9CiAgICAgICAgaWYgKEZTLmlzRGlyKHN0cmVhbS5ub2RlLm1vZGUpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FSVNESVIpCiAgICAgICAgfQogICAgICAgIGlmICghc3RyZWFtLnN0cmVhbV9vcHMucmVhZCkgewogICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoRVJSTk9fQ09ERVMuRUlOVkFMKQogICAgICAgIH0KICAgICAgICB2YXIgc2Vla2luZyA9IHR5cGVvZiBwb3NpdGlvbiAhPT0gJ3VuZGVmaW5lZCc7CiAgICAgICAgaWYgKCFzZWVraW5nKSB7CiAgICAgICAgICBwb3NpdGlvbiA9IHN0cmVhbS5wb3NpdGlvbjsKICAgICAgICB9IGVsc2UgaWYgKCFzdHJlYW0uc2Vla2FibGUpIHsKICAgICAgICAgIHRocm93IG5ldyBGUy5FcnJub0Vycm9yKEVSUk5PX0NPREVTLkVTUElQRSkKICAgICAgICB9CiAgICAgICAgdmFyIGJ5dGVzUmVhZCA9IHN0cmVhbS5zdHJlYW1fb3BzLnJlYWQoc3RyZWFtLCBidWZmZXIsIG9mZnNldCwgbGVuZ3RoLCBwb3NpdGlvbik7CiAgICAgICAgaWYgKCFzZWVraW5nKSBzdHJlYW0ucG9zaXRpb24gKz0gYnl0ZXNSZWFkOwogICAgICAgIHJldHVybiBieXRlc1JlYWQKICAgICAgfSwKICAgICAgd3JpdGU6IGZ1bmN0aW9uIChzdHJlYW0sIGJ1ZmZlciwgb2Zmc2V0LCBsZW5ndGgsIHBvc2l0aW9uLCBjYW5Pd24pIHsKICAgICAgICBpZiAobGVuZ3RoIDwgMCB8fCBwb3NpdGlvbiA8IDApIHsKICAgICAgICAgIHRocm93IG5ldyBGUy5FcnJub0Vycm9yKEVSUk5PX0NPREVTLkVJTlZBTCkKICAgICAgICB9CiAgICAgICAgaWYgKEZTLmlzQ2xvc2VkKHN0cmVhbSkpIHsKICAgICAgICAgIHRocm93IG5ldyBGUy5FcnJub0Vycm9yKEVSUk5PX0NPREVTLkVCQURGKQogICAgICAgIH0KICAgICAgICBpZiAoKHN0cmVhbS5mbGFncyAmIDIwOTcxNTUpID09PSAwKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FQkFERikKICAgICAgICB9CiAgICAgICAgaWYgKEZTLmlzRGlyKHN0cmVhbS5ub2RlLm1vZGUpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FSVNESVIpCiAgICAgICAgfQogICAgICAgIGlmICghc3RyZWFtLnN0cmVhbV9vcHMud3JpdGUpIHsKICAgICAgICAgIHRocm93IG5ldyBGUy5FcnJub0Vycm9yKEVSUk5PX0NPREVTLkVJTlZBTCkKICAgICAgICB9CiAgICAgICAgaWYgKHN0cmVhbS5mbGFncyAmIDEwMjQpIHsKICAgICAgICAgIEZTLmxsc2VlayhzdHJlYW0sIDAsIDIpOwogICAgICAgIH0KICAgICAgICB2YXIgc2Vla2luZyA9IHR5cGVvZiBwb3NpdGlvbiAhPT0gJ3VuZGVmaW5lZCc7CiAgICAgICAgaWYgKCFzZWVraW5nKSB7CiAgICAgICAgICBwb3NpdGlvbiA9IHN0cmVhbS5wb3NpdGlvbjsKICAgICAgICB9IGVsc2UgaWYgKCFzdHJlYW0uc2Vla2FibGUpIHsKICAgICAgICAgIHRocm93IG5ldyBGUy5FcnJub0Vycm9yKEVSUk5PX0NPREVTLkVTUElQRSkKICAgICAgICB9CiAgICAgICAgdmFyIGJ5dGVzV3JpdHRlbiA9IHN0cmVhbS5zdHJlYW1fb3BzLndyaXRlKHN0cmVhbSwgYnVmZmVyLCBvZmZzZXQsIGxlbmd0aCwgcG9zaXRpb24sIGNhbk93bik7CiAgICAgICAgaWYgKCFzZWVraW5nKSBzdHJlYW0ucG9zaXRpb24gKz0gYnl0ZXNXcml0dGVuOwogICAgICAgIHRyeSB7CiAgICAgICAgICBpZiAoc3RyZWFtLnBhdGggJiYgRlMudHJhY2tpbmdEZWxlZ2F0ZVsnb25Xcml0ZVRvRmlsZSddKSBGUy50cmFja2luZ0RlbGVnYXRlWydvbldyaXRlVG9GaWxlJ10oc3RyZWFtLnBhdGgpOwogICAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICAgIGNvbnNvbGUubG9nKCJGUy50cmFja2luZ0RlbGVnYXRlWydvbldyaXRlVG9GaWxlJ10oJyIgKyBwYXRoICsgIicpIHRocmV3IGFuIGV4Y2VwdGlvbjogIiArIGUubWVzc2FnZSk7CiAgICAgICAgfQogICAgICAgIHJldHVybiBieXRlc1dyaXR0ZW4KICAgICAgfSwKICAgICAgYWxsb2NhdGU6IGZ1bmN0aW9uIChzdHJlYW0sIG9mZnNldCwgbGVuZ3RoKSB7CiAgICAgICAgaWYgKEZTLmlzQ2xvc2VkKHN0cmVhbSkpIHsKICAgICAgICAgIHRocm93IG5ldyBGUy5FcnJub0Vycm9yKEVSUk5PX0NPREVTLkVCQURGKQogICAgICAgIH0KICAgICAgICBpZiAob2Zmc2V0IDwgMCB8fCBsZW5ndGggPD0gMCkgewogICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoRVJSTk9fQ09ERVMuRUlOVkFMKQogICAgICAgIH0KICAgICAgICBpZiAoKHN0cmVhbS5mbGFncyAmIDIwOTcxNTUpID09PSAwKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FQkFERikKICAgICAgICB9CiAgICAgICAgaWYgKCFGUy5pc0ZpbGUoc3RyZWFtLm5vZGUubW9kZSkgJiYgIUZTLmlzRGlyKHN0cmVhbS5ub2RlLm1vZGUpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FTk9ERVYpCiAgICAgICAgfQogICAgICAgIGlmICghc3RyZWFtLnN0cmVhbV9vcHMuYWxsb2NhdGUpIHsKICAgICAgICAgIHRocm93IG5ldyBGUy5FcnJub0Vycm9yKEVSUk5PX0NPREVTLkVPUE5PVFNVUFApCiAgICAgICAgfQogICAgICAgIHN0cmVhbS5zdHJlYW1fb3BzLmFsbG9jYXRlKHN0cmVhbSwgb2Zmc2V0LCBsZW5ndGgpOwogICAgICB9LAogICAgICBtbWFwOiBmdW5jdGlvbiAoc3RyZWFtLCBidWZmZXIsIG9mZnNldCwgbGVuZ3RoLCBwb3NpdGlvbiwgcHJvdCwgZmxhZ3MpIHsKICAgICAgICBpZiAoKHN0cmVhbS5mbGFncyAmIDIwOTcxNTUpID09PSAxKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FQUNDRVMpCiAgICAgICAgfQogICAgICAgIGlmICghc3RyZWFtLnN0cmVhbV9vcHMubW1hcCkgewogICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoRVJSTk9fQ09ERVMuRU5PREVWKQogICAgICAgIH0KICAgICAgICByZXR1cm4gc3RyZWFtLnN0cmVhbV9vcHMubW1hcChzdHJlYW0sIGJ1ZmZlciwgb2Zmc2V0LCBsZW5ndGgsIHBvc2l0aW9uLCBwcm90LCBmbGFncykKICAgICAgfSwKICAgICAgbXN5bmM6IGZ1bmN0aW9uIChzdHJlYW0sIGJ1ZmZlciwgb2Zmc2V0LCBsZW5ndGgsIG1tYXBGbGFncykgewogICAgICAgIGlmICghc3RyZWFtIHx8ICFzdHJlYW0uc3RyZWFtX29wcy5tc3luYykgewogICAgICAgICAgcmV0dXJuIDAKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHN0cmVhbS5zdHJlYW1fb3BzLm1zeW5jKHN0cmVhbSwgYnVmZmVyLCBvZmZzZXQsIGxlbmd0aCwgbW1hcEZsYWdzKQogICAgICB9LAogICAgICBtdW5tYXA6IGZ1bmN0aW9uIChzdHJlYW0pIHsKICAgICAgICByZXR1cm4gMAogICAgICB9LAogICAgICBpb2N0bDogZnVuY3Rpb24gKHN0cmVhbSwgY21kLCBhcmcpIHsKICAgICAgICBpZiAoIXN0cmVhbS5zdHJlYW1fb3BzLmlvY3RsKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FTk9UVFkpCiAgICAgICAgfQogICAgICAgIHJldHVybiBzdHJlYW0uc3RyZWFtX29wcy5pb2N0bChzdHJlYW0sIGNtZCwgYXJnKQogICAgICB9LAogICAgICByZWFkRmlsZTogZnVuY3Rpb24gKHBhdGgsIG9wdHMpIHsKICAgICAgICBvcHRzID0gb3B0cyB8fCB7fTsKICAgICAgICBvcHRzLmZsYWdzID0gb3B0cy5mbGFncyB8fCAncic7CiAgICAgICAgb3B0cy5lbmNvZGluZyA9IG9wdHMuZW5jb2RpbmcgfHwgJ2JpbmFyeSc7CiAgICAgICAgaWYgKG9wdHMuZW5jb2RpbmcgIT09ICd1dGY4JyAmJiBvcHRzLmVuY29kaW5nICE9PSAnYmluYXJ5JykgewogICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGVuY29kaW5nIHR5cGUgIicgKyBvcHRzLmVuY29kaW5nICsgJyInKQogICAgICAgIH0KICAgICAgICB2YXIgcmV0OwogICAgICAgIHZhciBzdHJlYW0gPSBGUy5vcGVuKHBhdGgsIG9wdHMuZmxhZ3MpOwogICAgICAgIHZhciBzdGF0ID0gRlMuc3RhdChwYXRoKTsKICAgICAgICB2YXIgbGVuZ3RoID0gc3RhdC5zaXplOwogICAgICAgIHZhciBidWYgPSBuZXcgVWludDhBcnJheShsZW5ndGgpOwogICAgICAgIEZTLnJlYWQoc3RyZWFtLCBidWYsIDAsIGxlbmd0aCwgMCk7CiAgICAgICAgaWYgKG9wdHMuZW5jb2RpbmcgPT09ICd1dGY4JykgewogICAgICAgICAgcmV0ID0gVVRGOEFycmF5VG9TdHJpbmcoYnVmLCAwKTsKICAgICAgICB9IGVsc2UgaWYgKG9wdHMuZW5jb2RpbmcgPT09ICdiaW5hcnknKSB7CiAgICAgICAgICByZXQgPSBidWY7CiAgICAgICAgfQogICAgICAgIEZTLmNsb3NlKHN0cmVhbSk7CiAgICAgICAgcmV0dXJuIHJldAogICAgICB9LAogICAgICB3cml0ZUZpbGU6IGZ1bmN0aW9uIChwYXRoLCBkYXRhLCBvcHRzKSB7CiAgICAgICAgb3B0cyA9IG9wdHMgfHwge307CiAgICAgICAgb3B0cy5mbGFncyA9IG9wdHMuZmxhZ3MgfHwgJ3cnOwogICAgICAgIHZhciBzdHJlYW0gPSBGUy5vcGVuKHBhdGgsIG9wdHMuZmxhZ3MsIG9wdHMubW9kZSk7CiAgICAgICAgaWYgKHR5cGVvZiBkYXRhID09PSAnc3RyaW5nJykgewogICAgICAgICAgdmFyIGJ1ZiA9IG5ldyBVaW50OEFycmF5KGxlbmd0aEJ5dGVzVVRGOChkYXRhKSArIDEpOwogICAgICAgICAgdmFyIGFjdHVhbE51bUJ5dGVzID0gc3RyaW5nVG9VVEY4QXJyYXkoZGF0YSwgYnVmLCAwLCBidWYubGVuZ3RoKTsKICAgICAgICAgIEZTLndyaXRlKHN0cmVhbSwgYnVmLCAwLCBhY3R1YWxOdW1CeXRlcywgdW5kZWZpbmVkLCBvcHRzLmNhbk93bik7CiAgICAgICAgfSBlbHNlIGlmIChBcnJheUJ1ZmZlci5pc1ZpZXcoZGF0YSkpIHsKICAgICAgICAgIEZTLndyaXRlKHN0cmVhbSwgZGF0YSwgMCwgZGF0YS5ieXRlTGVuZ3RoLCB1bmRlZmluZWQsIG9wdHMuY2FuT3duKTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdVbnN1cHBvcnRlZCBkYXRhIHR5cGUnKQogICAgICAgIH0KICAgICAgICBGUy5jbG9zZShzdHJlYW0pOwogICAgICB9LAogICAgICBjd2Q6IGZ1bmN0aW9uICgpIHsKICAgICAgICByZXR1cm4gRlMuY3VycmVudFBhdGgKICAgICAgfSwKICAgICAgY2hkaXI6IGZ1bmN0aW9uIChwYXRoKSB7CiAgICAgICAgdmFyIGxvb2t1cCA9IEZTLmxvb2t1cFBhdGgocGF0aCwgeyBmb2xsb3c6IHRydWUgfSk7CiAgICAgICAgaWYgKGxvb2t1cC5ub2RlID09PSBudWxsKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FTk9FTlQpCiAgICAgICAgfQogICAgICAgIGlmICghRlMuaXNEaXIobG9va3VwLm5vZGUubW9kZSkpIHsKICAgICAgICAgIHRocm93IG5ldyBGUy5FcnJub0Vycm9yKEVSUk5PX0NPREVTLkVOT1RESVIpCiAgICAgICAgfQogICAgICAgIHZhciBlcnIgPSBGUy5ub2RlUGVybWlzc2lvbnMobG9va3VwLm5vZGUsICd4Jyk7CiAgICAgICAgaWYgKGVycikgewogICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoZXJyKQogICAgICAgIH0KICAgICAgICBGUy5jdXJyZW50UGF0aCA9IGxvb2t1cC5wYXRoOwogICAgICB9LAogICAgICBjcmVhdGVEZWZhdWx0RGlyZWN0b3JpZXM6IGZ1bmN0aW9uICgpIHsKICAgICAgICBGUy5ta2RpcignL3RtcCcpOwogICAgICAgIEZTLm1rZGlyKCcvaG9tZScpOwogICAgICAgIEZTLm1rZGlyKCcvaG9tZS93ZWJfdXNlcicpOwogICAgICB9LAogICAgICBjcmVhdGVEZWZhdWx0RGV2aWNlczogZnVuY3Rpb24gKCkgewogICAgICAgIEZTLm1rZGlyKCcvZGV2Jyk7CiAgICAgICAgRlMucmVnaXN0ZXJEZXZpY2UoRlMubWFrZWRldigxLCAzKSwgewogICAgICAgICAgcmVhZDogZnVuY3Rpb24gKCkgewogICAgICAgICAgICByZXR1cm4gMAogICAgICAgICAgfSwKICAgICAgICAgIHdyaXRlOiBmdW5jdGlvbiAoc3RyZWFtLCBidWZmZXIsIG9mZnNldCwgbGVuZ3RoLCBwb3MpIHsKICAgICAgICAgICAgcmV0dXJuIGxlbmd0aAogICAgICAgICAgfSwKICAgICAgICB9KTsKICAgICAgICBGUy5ta2RldignL2Rldi9udWxsJywgRlMubWFrZWRldigxLCAzKSk7CiAgICAgICAgVFRZLnJlZ2lzdGVyKEZTLm1ha2VkZXYoNSwgMCksIFRUWS5kZWZhdWx0X3R0eV9vcHMpOwogICAgICAgIFRUWS5yZWdpc3RlcihGUy5tYWtlZGV2KDYsIDApLCBUVFkuZGVmYXVsdF90dHkxX29wcyk7CiAgICAgICAgRlMubWtkZXYoJy9kZXYvdHR5JywgRlMubWFrZWRldig1LCAwKSk7CiAgICAgICAgRlMubWtkZXYoJy9kZXYvdHR5MScsIEZTLm1ha2VkZXYoNiwgMCkpOwogICAgICAgIHZhciByYW5kb21fZGV2aWNlOwogICAgICAgIGlmICh0eXBlb2YgY3J5cHRvICE9PSAndW5kZWZpbmVkJykgewogICAgICAgICAgdmFyIHJhbmRvbUJ1ZmZlciA9IG5ldyBVaW50OEFycmF5KDEpOwogICAgICAgICAgcmFuZG9tX2RldmljZSA9IGZ1bmN0aW9uICgpIHsKICAgICAgICAgICAgY3J5cHRvLmdldFJhbmRvbVZhbHVlcyhyYW5kb21CdWZmZXIpOwogICAgICAgICAgICByZXR1cm4gcmFuZG9tQnVmZmVyWzBdCiAgICAgICAgICB9OwogICAgICAgIH0gZWxzZSBpZiAoRU5WSVJPTk1FTlRfSVNfTk9ERSkgewogICAgICAgICAgcmFuZG9tX2RldmljZSA9IGZ1bmN0aW9uICgpIHsKICAgICAgICAgICAgcmV0dXJuIHJlcXVpcmUoJ2NyeXB0bycpWydyYW5kb21CeXRlcyddKDEpWzBdCiAgICAgICAgICB9OwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICByYW5kb21fZGV2aWNlID0gZnVuY3Rpb24gKCkgewogICAgICAgICAgICByZXR1cm4gKE1hdGgucmFuZG9tKCkgKiAyNTYpIHwgMAogICAgICAgICAgfTsKICAgICAgICB9CiAgICAgICAgRlMuY3JlYXRlRGV2aWNlKCcvZGV2JywgJ3JhbmRvbScsIHJhbmRvbV9kZXZpY2UpOwogICAgICAgIEZTLmNyZWF0ZURldmljZSgnL2RldicsICd1cmFuZG9tJywgcmFuZG9tX2RldmljZSk7CiAgICAgICAgRlMubWtkaXIoJy9kZXYvc2htJyk7CiAgICAgICAgRlMubWtkaXIoJy9kZXYvc2htL3RtcCcpOwogICAgICB9LAogICAgICBjcmVhdGVTcGVjaWFsRGlyZWN0b3JpZXM6IGZ1bmN0aW9uICgpIHsKICAgICAgICBGUy5ta2RpcignL3Byb2MnKTsKICAgICAgICBGUy5ta2RpcignL3Byb2Mvc2VsZicpOwogICAgICAgIEZTLm1rZGlyKCcvcHJvYy9zZWxmL2ZkJyk7CiAgICAgICAgRlMubW91bnQoCiAgICAgICAgICB7CiAgICAgICAgICAgIG1vdW50OiBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgICAgdmFyIG5vZGUgPSBGUy5jcmVhdGVOb2RlKCcvcHJvYy9zZWxmJywgJ2ZkJywgMTYzODQgfCA1MTEsIDczKTsKICAgICAgICAgICAgICBub2RlLm5vZGVfb3BzID0gewogICAgICAgICAgICAgICAgbG9va3VwOiBmdW5jdGlvbiAocGFyZW50LCBuYW1lKSB7CiAgICAgICAgICAgICAgICAgIHZhciBmZCA9ICtuYW1lOwogICAgICAgICAgICAgICAgICB2YXIgc3RyZWFtID0gRlMuZ2V0U3RyZWFtKGZkKTsKICAgICAgICAgICAgICAgICAgaWYgKCFzdHJlYW0pIHRocm93IG5ldyBGUy5FcnJub0Vycm9yKEVSUk5PX0NPREVTLkVCQURGKQogICAgICAgICAgICAgICAgICB2YXIgcmV0ID0gewogICAgICAgICAgICAgICAgICAgIHBhcmVudDogbnVsbCwKICAgICAgICAgICAgICAgICAgICBtb3VudDogeyBtb3VudHBvaW50OiAnZmFrZScgfSwKICAgICAgICAgICAgICAgICAgICBub2RlX29wczogewogICAgICAgICAgICAgICAgICAgICAgcmVhZGxpbms6IGZ1bmN0aW9uICgpIHsKICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHN0cmVhbS5wYXRoCiAgICAgICAgICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICAgIH07CiAgICAgICAgICAgICAgICAgIHJldC5wYXJlbnQgPSByZXQ7CiAgICAgICAgICAgICAgICAgIHJldHVybiByZXQKICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgfTsKICAgICAgICAgICAgICByZXR1cm4gbm9kZQogICAgICAgICAgICB9LAogICAgICAgICAgfSwKICAgICAgICAgIHt9LAogICAgICAgICAgJy9wcm9jL3NlbGYvZmQnCiAgICAgICAgKTsKICAgICAgfSwKICAgICAgY3JlYXRlU3RhbmRhcmRTdHJlYW1zOiBmdW5jdGlvbiAoKSB7CiAgICAgICAgaWYgKE1vZHVsZVsnc3RkaW4nXSkgewogICAgICAgICAgRlMuY3JlYXRlRGV2aWNlKCcvZGV2JywgJ3N0ZGluJywgTW9kdWxlWydzdGRpbiddKTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgRlMuc3ltbGluaygnL2Rldi90dHknLCAnL2Rldi9zdGRpbicpOwogICAgICAgIH0KICAgICAgICBpZiAoTW9kdWxlWydzdGRvdXQnXSkgewogICAgICAgICAgRlMuY3JlYXRlRGV2aWNlKCcvZGV2JywgJ3N0ZG91dCcsIG51bGwsIE1vZHVsZVsnc3Rkb3V0J10pOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBGUy5zeW1saW5rKCcvZGV2L3R0eScsICcvZGV2L3N0ZG91dCcpOwogICAgICAgIH0KICAgICAgICBpZiAoTW9kdWxlWydzdGRlcnInXSkgewogICAgICAgICAgRlMuY3JlYXRlRGV2aWNlKCcvZGV2JywgJ3N0ZGVycicsIG51bGwsIE1vZHVsZVsnc3RkZXJyJ10pOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBGUy5zeW1saW5rKCcvZGV2L3R0eTEnLCAnL2Rldi9zdGRlcnInKTsKICAgICAgICB9CiAgICAgICAgdmFyIHN0ZGluID0gRlMub3BlbignL2Rldi9zdGRpbicsICdyJyk7CiAgICAgICAgYXNzZXJ0KHN0ZGluLmZkID09PSAwLCAnaW52YWxpZCBoYW5kbGUgZm9yIHN0ZGluICgnICsgc3RkaW4uZmQgKyAnKScpOwogICAgICAgIHZhciBzdGRvdXQgPSBGUy5vcGVuKCcvZGV2L3N0ZG91dCcsICd3Jyk7CiAgICAgICAgYXNzZXJ0KHN0ZG91dC5mZCA9PT0gMSwgJ2ludmFsaWQgaGFuZGxlIGZvciBzdGRvdXQgKCcgKyBzdGRvdXQuZmQgKyAnKScpOwogICAgICAgIHZhciBzdGRlcnIgPSBGUy5vcGVuKCcvZGV2L3N0ZGVycicsICd3Jyk7CiAgICAgICAgYXNzZXJ0KHN0ZGVyci5mZCA9PT0gMiwgJ2ludmFsaWQgaGFuZGxlIGZvciBzdGRlcnIgKCcgKyBzdGRlcnIuZmQgKyAnKScpOwogICAgICB9LAogICAgICBlbnN1cmVFcnJub0Vycm9yOiBmdW5jdGlvbiAoKSB7CiAgICAgICAgaWYgKEZTLkVycm5vRXJyb3IpIHJldHVybgogICAgICAgIEZTLkVycm5vRXJyb3IgPSBmdW5jdGlvbiBFcnJub0Vycm9yKGVycm5vLCBub2RlKSB7CiAgICAgICAgICB0aGlzLm5vZGUgPSBub2RlOwogICAgICAgICAgdGhpcy5zZXRFcnJubyA9IGZ1bmN0aW9uIChlcnJubykgewogICAgICAgICAgICB0aGlzLmVycm5vID0gZXJybm87CiAgICAgICAgICAgIGZvciAodmFyIGtleSBpbiBFUlJOT19DT0RFUykgewogICAgICAgICAgICAgIGlmIChFUlJOT19DT0RFU1trZXldID09PSBlcnJubykgewogICAgICAgICAgICAgICAgdGhpcy5jb2RlID0ga2V5OwogICAgICAgICAgICAgICAgYnJlYWsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgIH07CiAgICAgICAgICB0aGlzLnNldEVycm5vKGVycm5vKTsKICAgICAgICAgIHRoaXMubWVzc2FnZSA9IEVSUk5PX01FU1NBR0VTW2Vycm5vXTsKICAgICAgICAgIGlmICh0aGlzLnN0YWNrKSBPYmplY3QuZGVmaW5lUHJvcGVydHkodGhpcywgJ3N0YWNrJywgeyB2YWx1ZTogbmV3IEVycm9yKCkuc3RhY2ssIHdyaXRhYmxlOiB0cnVlIH0pOwogICAgICAgIH07CiAgICAgICAgRlMuRXJybm9FcnJvci5wcm90b3R5cGUgPSBuZXcgRXJyb3IoKTsKICAgICAgICBGUy5FcnJub0Vycm9yLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IEZTLkVycm5vRXJyb3IKICAgICAgICA7W0VSUk5PX0NPREVTLkVOT0VOVF0uZm9yRWFjaChmdW5jdGlvbiAoY29kZSkgewogICAgICAgICAgRlMuZ2VuZXJpY0Vycm9yc1tjb2RlXSA9IG5ldyBGUy5FcnJub0Vycm9yKGNvZGUpOwogICAgICAgICAgRlMuZ2VuZXJpY0Vycm9yc1tjb2RlXS5zdGFjayA9ICc8Z2VuZXJpYyBlcnJvciwgbm8gc3RhY2s+JzsKICAgICAgICB9KTsKICAgICAgfSwKICAgICAgc3RhdGljSW5pdDogZnVuY3Rpb24gKCkgewogICAgICAgIEZTLmVuc3VyZUVycm5vRXJyb3IoKTsKICAgICAgICBGUy5uYW1lVGFibGUgPSBuZXcgQXJyYXkoNDA5Nik7CiAgICAgICAgRlMubW91bnQoTUVNRlMsIHt9LCAnLycpOwogICAgICAgIEZTLmNyZWF0ZURlZmF1bHREaXJlY3RvcmllcygpOwogICAgICAgIEZTLmNyZWF0ZURlZmF1bHREZXZpY2VzKCk7CiAgICAgICAgRlMuY3JlYXRlU3BlY2lhbERpcmVjdG9yaWVzKCk7CiAgICAgICAgRlMuZmlsZXN5c3RlbXMgPSB7IE1FTUZTOiBNRU1GUywgSURCRlM6IElEQkZTLCBOT0RFRlM6IE5PREVGUywgV09SS0VSRlM6IFdPUktFUkZTIH07CiAgICAgIH0sCiAgICAgIGluaXQ6IGZ1bmN0aW9uIChpbnB1dCwgb3V0cHV0LCBlcnJvcikgewogICAgICAgIGFzc2VydCgKICAgICAgICAgICFGUy5pbml0LmluaXRpYWxpemVkLAogICAgICAgICAgJ0ZTLmluaXQgd2FzIHByZXZpb3VzbHkgY2FsbGVkLiBJZiB5b3Ugd2FudCB0byBpbml0aWFsaXplIGxhdGVyIHdpdGggY3VzdG9tIHBhcmFtZXRlcnMsIHJlbW92ZSBhbnkgZWFybGllciBjYWxscyAobm90ZSB0aGF0IG9uZSBpcyBhdXRvbWF0aWNhbGx5IGFkZGVkIHRvIHRoZSBnZW5lcmF0ZWQgY29kZSknCiAgICAgICAgKTsKICAgICAgICBGUy5pbml0LmluaXRpYWxpemVkID0gdHJ1ZTsKICAgICAgICBGUy5lbnN1cmVFcnJub0Vycm9yKCk7CiAgICAgICAgTW9kdWxlWydzdGRpbiddID0gaW5wdXQgfHwgTW9kdWxlWydzdGRpbiddOwogICAgICAgIE1vZHVsZVsnc3Rkb3V0J10gPSBvdXRwdXQgfHwgTW9kdWxlWydzdGRvdXQnXTsKICAgICAgICBNb2R1bGVbJ3N0ZGVyciddID0gZXJyb3IgfHwgTW9kdWxlWydzdGRlcnInXTsKICAgICAgICBGUy5jcmVhdGVTdGFuZGFyZFN0cmVhbXMoKTsKICAgICAgfSwKICAgICAgcXVpdDogZnVuY3Rpb24gKCkgewogICAgICAgIEZTLmluaXQuaW5pdGlhbGl6ZWQgPSBmYWxzZTsKICAgICAgICB2YXIgZmZsdXNoID0gTW9kdWxlWydfZmZsdXNoJ107CiAgICAgICAgaWYgKGZmbHVzaCkgZmZsdXNoKDApOwogICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgRlMuc3RyZWFtcy5sZW5ndGg7IGkrKykgewogICAgICAgICAgdmFyIHN0cmVhbSA9IEZTLnN0cmVhbXNbaV07CiAgICAgICAgICBpZiAoIXN0cmVhbSkgewogICAgICAgICAgICBjb250aW51ZQogICAgICAgICAgfQogICAgICAgICAgRlMuY2xvc2Uoc3RyZWFtKTsKICAgICAgICB9CiAgICAgIH0sCiAgICAgIGdldE1vZGU6IGZ1bmN0aW9uIChjYW5SZWFkLCBjYW5Xcml0ZSkgewogICAgICAgIHZhciBtb2RlID0gMDsKICAgICAgICBpZiAoY2FuUmVhZCkgbW9kZSB8PSAyOTIgfCA3MzsKICAgICAgICBpZiAoY2FuV3JpdGUpIG1vZGUgfD0gMTQ2OwogICAgICAgIHJldHVybiBtb2RlCiAgICAgIH0sCiAgICAgIGpvaW5QYXRoOiBmdW5jdGlvbiAocGFydHMsIGZvcmNlUmVsYXRpdmUpIHsKICAgICAgICB2YXIgcGF0aCA9IFBBVEguam9pbi5hcHBseShudWxsLCBwYXJ0cyk7CiAgICAgICAgaWYgKGZvcmNlUmVsYXRpdmUgJiYgcGF0aFswXSA9PSAnLycpIHBhdGggPSBwYXRoLnN1YnN0cigxKTsKICAgICAgICByZXR1cm4gcGF0aAogICAgICB9LAogICAgICBhYnNvbHV0ZVBhdGg6IGZ1bmN0aW9uIChyZWxhdGl2ZSwgYmFzZSkgewogICAgICAgIHJldHVybiBQQVRILnJlc29sdmUoYmFzZSwgcmVsYXRpdmUpCiAgICAgIH0sCiAgICAgIHN0YW5kYXJkaXplUGF0aDogZnVuY3Rpb24gKHBhdGgpIHsKICAgICAgICByZXR1cm4gUEFUSC5ub3JtYWxpemUocGF0aCkKICAgICAgfSwKICAgICAgZmluZE9iamVjdDogZnVuY3Rpb24gKHBhdGgsIGRvbnRSZXNvbHZlTGFzdExpbmspIHsKICAgICAgICB2YXIgcmV0ID0gRlMuYW5hbHl6ZVBhdGgocGF0aCwgZG9udFJlc29sdmVMYXN0TGluayk7CiAgICAgICAgaWYgKHJldC5leGlzdHMpIHsKICAgICAgICAgIHJldHVybiByZXQub2JqZWN0CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIF9fX3NldEVyck5vKHJldC5lcnJvcik7CiAgICAgICAgICByZXR1cm4gbnVsbAogICAgICAgIH0KICAgICAgfSwKICAgICAgYW5hbHl6ZVBhdGg6IGZ1bmN0aW9uIChwYXRoLCBkb250UmVzb2x2ZUxhc3RMaW5rKSB7CiAgICAgICAgdHJ5IHsKICAgICAgICAgIHZhciBsb29rdXAgPSBGUy5sb29rdXBQYXRoKHBhdGgsIHsgZm9sbG93OiAhZG9udFJlc29sdmVMYXN0TGluayB9KTsKICAgICAgICAgIHBhdGggPSBsb29rdXAucGF0aDsKICAgICAgICB9IGNhdGNoIChlKSB7fQogICAgICAgIHZhciByZXQgPSB7CiAgICAgICAgICBpc1Jvb3Q6IGZhbHNlLAogICAgICAgICAgZXhpc3RzOiBmYWxzZSwKICAgICAgICAgIGVycm9yOiAwLAogICAgICAgICAgbmFtZTogbnVsbCwKICAgICAgICAgIHBhdGg6IG51bGwsCiAgICAgICAgICBvYmplY3Q6IG51bGwsCiAgICAgICAgICBwYXJlbnRFeGlzdHM6IGZhbHNlLAogICAgICAgICAgcGFyZW50UGF0aDogbnVsbCwKICAgICAgICAgIHBhcmVudE9iamVjdDogbnVsbCwKICAgICAgICB9OwogICAgICAgIHRyeSB7CiAgICAgICAgICB2YXIgbG9va3VwID0gRlMubG9va3VwUGF0aChwYXRoLCB7IHBhcmVudDogdHJ1ZSB9KTsKICAgICAgICAgIHJldC5wYXJlbnRFeGlzdHMgPSB0cnVlOwogICAgICAgICAgcmV0LnBhcmVudFBhdGggPSBsb29rdXAucGF0aDsKICAgICAgICAgIHJldC5wYXJlbnRPYmplY3QgPSBsb29rdXAubm9kZTsKICAgICAgICAgIHJldC5uYW1lID0gUEFUSC5iYXNlbmFtZShwYXRoKTsKICAgICAgICAgIGxvb2t1cCA9IEZTLmxvb2t1cFBhdGgocGF0aCwgeyBmb2xsb3c6ICFkb250UmVzb2x2ZUxhc3RMaW5rIH0pOwogICAgICAgICAgcmV0LmV4aXN0cyA9IHRydWU7CiAgICAgICAgICByZXQucGF0aCA9IGxvb2t1cC5wYXRoOwogICAgICAgICAgcmV0Lm9iamVjdCA9IGxvb2t1cC5ub2RlOwogICAgICAgICAgcmV0Lm5hbWUgPSBsb29rdXAubm9kZS5uYW1lOwogICAgICAgICAgcmV0LmlzUm9vdCA9IGxvb2t1cC5wYXRoID09PSAnLyc7CiAgICAgICAgfSBjYXRjaCAoZSkgewogICAgICAgICAgcmV0LmVycm9yID0gZS5lcnJubzsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHJldAogICAgICB9LAogICAgICBjcmVhdGVGb2xkZXI6IGZ1bmN0aW9uIChwYXJlbnQsIG5hbWUsIGNhblJlYWQsIGNhbldyaXRlKSB7CiAgICAgICAgdmFyIHBhdGggPSBQQVRILmpvaW4yKHR5cGVvZiBwYXJlbnQgPT09ICdzdHJpbmcnID8gcGFyZW50IDogRlMuZ2V0UGF0aChwYXJlbnQpLCBuYW1lKTsKICAgICAgICB2YXIgbW9kZSA9IEZTLmdldE1vZGUoY2FuUmVhZCwgY2FuV3JpdGUpOwogICAgICAgIHJldHVybiBGUy5ta2RpcihwYXRoLCBtb2RlKQogICAgICB9LAogICAgICBjcmVhdGVQYXRoOiBmdW5jdGlvbiAocGFyZW50LCBwYXRoLCBjYW5SZWFkLCBjYW5Xcml0ZSkgewogICAgICAgIHBhcmVudCA9IHR5cGVvZiBwYXJlbnQgPT09ICdzdHJpbmcnID8gcGFyZW50IDogRlMuZ2V0UGF0aChwYXJlbnQpOwogICAgICAgIHZhciBwYXJ0cyA9IHBhdGguc3BsaXQoJy8nKS5yZXZlcnNlKCk7CiAgICAgICAgd2hpbGUgKHBhcnRzLmxlbmd0aCkgewogICAgICAgICAgdmFyIHBhcnQgPSBwYXJ0cy5wb3AoKTsKICAgICAgICAgIGlmICghcGFydCkgY29udGludWUKICAgICAgICAgIHZhciBjdXJyZW50ID0gUEFUSC5qb2luMihwYXJlbnQsIHBhcnQpOwogICAgICAgICAgdHJ5IHsKICAgICAgICAgICAgRlMubWtkaXIoY3VycmVudCk7CiAgICAgICAgICB9IGNhdGNoIChlKSB7fQogICAgICAgICAgcGFyZW50ID0gY3VycmVudDsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIGN1cnJlbnQKICAgICAgfSwKICAgICAgY3JlYXRlRmlsZTogZnVuY3Rpb24gKHBhcmVudCwgbmFtZSwgcHJvcGVydGllcywgY2FuUmVhZCwgY2FuV3JpdGUpIHsKICAgICAgICB2YXIgcGF0aCA9IFBBVEguam9pbjIodHlwZW9mIHBhcmVudCA9PT0gJ3N0cmluZycgPyBwYXJlbnQgOiBGUy5nZXRQYXRoKHBhcmVudCksIG5hbWUpOwogICAgICAgIHZhciBtb2RlID0gRlMuZ2V0TW9kZShjYW5SZWFkLCBjYW5Xcml0ZSk7CiAgICAgICAgcmV0dXJuIEZTLmNyZWF0ZShwYXRoLCBtb2RlKQogICAgICB9LAogICAgICBjcmVhdGVEYXRhRmlsZTogZnVuY3Rpb24gKHBhcmVudCwgbmFtZSwgZGF0YSwgY2FuUmVhZCwgY2FuV3JpdGUsIGNhbk93bikgewogICAgICAgIHZhciBwYXRoID0gbmFtZSA/IFBBVEguam9pbjIodHlwZW9mIHBhcmVudCA9PT0gJ3N0cmluZycgPyBwYXJlbnQgOiBGUy5nZXRQYXRoKHBhcmVudCksIG5hbWUpIDogcGFyZW50OwogICAgICAgIHZhciBtb2RlID0gRlMuZ2V0TW9kZShjYW5SZWFkLCBjYW5Xcml0ZSk7CiAgICAgICAgdmFyIG5vZGUgPSBGUy5jcmVhdGUocGF0aCwgbW9kZSk7CiAgICAgICAgaWYgKGRhdGEpIHsKICAgICAgICAgIGlmICh0eXBlb2YgZGF0YSA9PT0gJ3N0cmluZycpIHsKICAgICAgICAgICAgdmFyIGFyciA9IG5ldyBBcnJheShkYXRhLmxlbmd0aCk7CiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwLCBsZW4gPSBkYXRhLmxlbmd0aDsgaSA8IGxlbjsgKytpKSBhcnJbaV0gPSBkYXRhLmNoYXJDb2RlQXQoaSk7CiAgICAgICAgICAgIGRhdGEgPSBhcnI7CiAgICAgICAgICB9CiAgICAgICAgICBGUy5jaG1vZChub2RlLCBtb2RlIHwgMTQ2KTsKICAgICAgICAgIHZhciBzdHJlYW0gPSBGUy5vcGVuKG5vZGUsICd3Jyk7CiAgICAgICAgICBGUy53cml0ZShzdHJlYW0sIGRhdGEsIDAsIGRhdGEubGVuZ3RoLCAwLCBjYW5Pd24pOwogICAgICAgICAgRlMuY2xvc2Uoc3RyZWFtKTsKICAgICAgICAgIEZTLmNobW9kKG5vZGUsIG1vZGUpOwogICAgICAgIH0KICAgICAgICByZXR1cm4gbm9kZQogICAgICB9LAogICAgICBjcmVhdGVEZXZpY2U6IGZ1bmN0aW9uIChwYXJlbnQsIG5hbWUsIGlucHV0LCBvdXRwdXQpIHsKICAgICAgICB2YXIgcGF0aCA9IFBBVEguam9pbjIodHlwZW9mIHBhcmVudCA9PT0gJ3N0cmluZycgPyBwYXJlbnQgOiBGUy5nZXRQYXRoKHBhcmVudCksIG5hbWUpOwogICAgICAgIHZhciBtb2RlID0gRlMuZ2V0TW9kZSghIWlucHV0LCAhIW91dHB1dCk7CiAgICAgICAgaWYgKCFGUy5jcmVhdGVEZXZpY2UubWFqb3IpIEZTLmNyZWF0ZURldmljZS5tYWpvciA9IDY0OwogICAgICAgIHZhciBkZXYgPSBGUy5tYWtlZGV2KEZTLmNyZWF0ZURldmljZS5tYWpvcisrLCAwKTsKICAgICAgICBGUy5yZWdpc3RlckRldmljZShkZXYsIHsKICAgICAgICAgIG9wZW46IGZ1bmN0aW9uIChzdHJlYW0pIHsKICAgICAgICAgICAgc3RyZWFtLnNlZWthYmxlID0gZmFsc2U7CiAgICAgICAgICB9LAogICAgICAgICAgY2xvc2U6IGZ1bmN0aW9uIChzdHJlYW0pIHsKICAgICAgICAgICAgaWYgKG91dHB1dCAmJiBvdXRwdXQuYnVmZmVyICYmIG91dHB1dC5idWZmZXIubGVuZ3RoKSB7CiAgICAgICAgICAgICAgb3V0cHV0KDEwKTsKICAgICAgICAgICAgfQogICAgICAgICAgfSwKICAgICAgICAgIHJlYWQ6IGZ1bmN0aW9uIChzdHJlYW0sIGJ1ZmZlciwgb2Zmc2V0LCBsZW5ndGgsIHBvcykgewogICAgICAgICAgICB2YXIgYnl0ZXNSZWFkID0gMDsKICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkrKykgewogICAgICAgICAgICAgIHZhciByZXN1bHQ7CiAgICAgICAgICAgICAgdHJ5IHsKICAgICAgICAgICAgICAgIHJlc3VsdCA9IGlucHV0KCk7CiAgICAgICAgICAgICAgfSBjYXRjaCAoZSkgewogICAgICAgICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoRVJSTk9fQ09ERVMuRUlPKQogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBpZiAocmVzdWx0ID09PSB1bmRlZmluZWQgJiYgYnl0ZXNSZWFkID09PSAwKSB7CiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FQUdBSU4pCiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGlmIChyZXN1bHQgPT09IG51bGwgfHwgcmVzdWx0ID09PSB1bmRlZmluZWQpIGJyZWFrCiAgICAgICAgICAgICAgYnl0ZXNSZWFkKys7CiAgICAgICAgICAgICAgYnVmZmVyW29mZnNldCArIGldID0gcmVzdWx0OwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIChieXRlc1JlYWQpIHsKICAgICAgICAgICAgICBzdHJlYW0ubm9kZS50aW1lc3RhbXAgPSBEYXRlLm5vdygpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBieXRlc1JlYWQKICAgICAgICAgIH0sCiAgICAgICAgICB3cml0ZTogZnVuY3Rpb24gKHN0cmVhbSwgYnVmZmVyLCBvZmZzZXQsIGxlbmd0aCwgcG9zKSB7CiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspIHsKICAgICAgICAgICAgICB0cnkgewogICAgICAgICAgICAgICAgb3V0cHV0KGJ1ZmZlcltvZmZzZXQgKyBpXSk7CiAgICAgICAgICAgICAgfSBjYXRjaCAoZSkgewogICAgICAgICAgICAgICAgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoRVJSTk9fQ09ERVMuRUlPKQogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAobGVuZ3RoKSB7CiAgICAgICAgICAgICAgc3RyZWFtLm5vZGUudGltZXN0YW1wID0gRGF0ZS5ub3coKTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gaQogICAgICAgICAgfSwKICAgICAgICB9KTsKICAgICAgICByZXR1cm4gRlMubWtkZXYocGF0aCwgbW9kZSwgZGV2KQogICAgICB9LAogICAgICBjcmVhdGVMaW5rOiBmdW5jdGlvbiAocGFyZW50LCBuYW1lLCB0YXJnZXQsIGNhblJlYWQsIGNhbldyaXRlKSB7CiAgICAgICAgdmFyIHBhdGggPSBQQVRILmpvaW4yKHR5cGVvZiBwYXJlbnQgPT09ICdzdHJpbmcnID8gcGFyZW50IDogRlMuZ2V0UGF0aChwYXJlbnQpLCBuYW1lKTsKICAgICAgICByZXR1cm4gRlMuc3ltbGluayh0YXJnZXQsIHBhdGgpCiAgICAgIH0sCiAgICAgIGZvcmNlTG9hZEZpbGU6IGZ1bmN0aW9uIChvYmopIHsKICAgICAgICBpZiAob2JqLmlzRGV2aWNlIHx8IG9iai5pc0ZvbGRlciB8fCBvYmoubGluayB8fCBvYmouY29udGVudHMpIHJldHVybiB0cnVlCiAgICAgICAgdmFyIHN1Y2Nlc3MgPSB0cnVlOwogICAgICAgIGlmICh0eXBlb2YgWE1MSHR0cFJlcXVlc3QgIT09ICd1bmRlZmluZWQnKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoCiAgICAgICAgICAgICdMYXp5IGxvYWRpbmcgc2hvdWxkIGhhdmUgYmVlbiBwZXJmb3JtZWQgKGNvbnRlbnRzIHNldCkgaW4gY3JlYXRlTGF6eUZpbGUsIGJ1dCBpdCB3YXMgbm90LiBMYXp5IGxvYWRpbmcgb25seSB3b3JrcyBpbiB3ZWIgd29ya2Vycy4gVXNlIC0tZW1iZWQtZmlsZSBvciAtLXByZWxvYWQtZmlsZSBpbiBlbWNjIG9uIHRoZSBtYWluIHRocmVhZC4nCiAgICAgICAgICApCiAgICAgICAgfSBlbHNlIGlmIChNb2R1bGVbJ3JlYWQnXSkgewogICAgICAgICAgdHJ5IHsKICAgICAgICAgICAgb2JqLmNvbnRlbnRzID0gaW50QXJyYXlGcm9tU3RyaW5nKE1vZHVsZVsncmVhZCddKG9iai51cmwpLCB0cnVlKTsKICAgICAgICAgICAgb2JqLnVzZWRCeXRlcyA9IG9iai5jb250ZW50cy5sZW5ndGg7CiAgICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICAgIHN1Y2Nlc3MgPSBmYWxzZTsKICAgICAgICAgIH0KICAgICAgICB9IGVsc2UgewogICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdDYW5ub3QgbG9hZCB3aXRob3V0IHJlYWQoKSBvciBYTUxIdHRwUmVxdWVzdC4nKQogICAgICAgIH0KICAgICAgICBpZiAoIXN1Y2Nlc3MpIF9fX3NldEVyck5vKEVSUk5PX0NPREVTLkVJTyk7CiAgICAgICAgcmV0dXJuIHN1Y2Nlc3MKICAgICAgfSwKICAgICAgY3JlYXRlTGF6eUZpbGU6IGZ1bmN0aW9uIChwYXJlbnQsIG5hbWUsIHVybCwgY2FuUmVhZCwgY2FuV3JpdGUpIHsKICAgICAgICBmdW5jdGlvbiBMYXp5VWludDhBcnJheSgpIHsKICAgICAgICAgIHRoaXMubGVuZ3RoS25vd24gPSBmYWxzZTsKICAgICAgICAgIHRoaXMuY2h1bmtzID0gW107CiAgICAgICAgfQogICAgICAgIExhenlVaW50OEFycmF5LnByb3RvdHlwZS5nZXQgPSBmdW5jdGlvbiBMYXp5VWludDhBcnJheV9nZXQoaWR4KSB7CiAgICAgICAgICBpZiAoaWR4ID4gdGhpcy5sZW5ndGggLSAxIHx8IGlkeCA8IDApIHsKICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZAogICAgICAgICAgfQogICAgICAgICAgdmFyIGNodW5rT2Zmc2V0ID0gaWR4ICUgdGhpcy5jaHVua1NpemU7CiAgICAgICAgICB2YXIgY2h1bmtOdW0gPSAoaWR4IC8gdGhpcy5jaHVua1NpemUpIHwgMDsKICAgICAgICAgIHJldHVybiB0aGlzLmdldHRlcihjaHVua051bSlbY2h1bmtPZmZzZXRdCiAgICAgICAgfTsKICAgICAgICBMYXp5VWludDhBcnJheS5wcm90b3R5cGUuc2V0RGF0YUdldHRlciA9IGZ1bmN0aW9uIExhenlVaW50OEFycmF5X3NldERhdGFHZXR0ZXIoZ2V0dGVyKSB7CiAgICAgICAgICB0aGlzLmdldHRlciA9IGdldHRlcjsKICAgICAgICB9OwogICAgICAgIExhenlVaW50OEFycmF5LnByb3RvdHlwZS5jYWNoZUxlbmd0aCA9IGZ1bmN0aW9uIExhenlVaW50OEFycmF5X2NhY2hlTGVuZ3RoKCkgewogICAgICAgICAgdmFyIHhociA9IG5ldyBYTUxIdHRwUmVxdWVzdCgpOwogICAgICAgICAgeGhyLm9wZW4oJ0hFQUQnLCB1cmwsIGZhbHNlKTsKICAgICAgICAgIHhoci5zZW5kKG51bGwpOwogICAgICAgICAgaWYgKCEoKHhoci5zdGF0dXMgPj0gMjAwICYmIHhoci5zdGF0dXMgPCAzMDApIHx8IHhoci5zdGF0dXMgPT09IDMwNCkpCiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcigiQ291bGRuJ3QgbG9hZCAiICsgdXJsICsgJy4gU3RhdHVzOiAnICsgeGhyLnN0YXR1cykKICAgICAgICAgIHZhciBkYXRhbGVuZ3RoID0gTnVtYmVyKHhoci5nZXRSZXNwb25zZUhlYWRlcignQ29udGVudC1sZW5ndGgnKSk7CiAgICAgICAgICB2YXIgaGVhZGVyOwogICAgICAgICAgdmFyIGhhc0J5dGVTZXJ2aW5nID0gKGhlYWRlciA9IHhoci5nZXRSZXNwb25zZUhlYWRlcignQWNjZXB0LVJhbmdlcycpKSAmJiBoZWFkZXIgPT09ICdieXRlcyc7CiAgICAgICAgICB2YXIgdXNlc0d6aXAgPSAoaGVhZGVyID0geGhyLmdldFJlc3BvbnNlSGVhZGVyKCdDb250ZW50LUVuY29kaW5nJykpICYmIGhlYWRlciA9PT0gJ2d6aXAnOwogICAgICAgICAgdmFyIGNodW5rU2l6ZSA9IDEwMjQgKiAxMDI0OwogICAgICAgICAgaWYgKCFoYXNCeXRlU2VydmluZykgY2h1bmtTaXplID0gZGF0YWxlbmd0aDsKICAgICAgICAgIHZhciBkb1hIUiA9IGZ1bmN0aW9uIChmcm9tLCB0bykgewogICAgICAgICAgICBpZiAoZnJvbSA+IHRvKSB0aHJvdyBuZXcgRXJyb3IoJ2ludmFsaWQgcmFuZ2UgKCcgKyBmcm9tICsgJywgJyArIHRvICsgJykgb3Igbm8gYnl0ZXMgcmVxdWVzdGVkIScpCiAgICAgICAgICAgIGlmICh0byA+IGRhdGFsZW5ndGggLSAxKSB0aHJvdyBuZXcgRXJyb3IoJ29ubHkgJyArIGRhdGFsZW5ndGggKyAnIGJ5dGVzIGF2YWlsYWJsZSEgcHJvZ3JhbW1lciBlcnJvciEnKQogICAgICAgICAgICB2YXIgeGhyID0gbmV3IFhNTEh0dHBSZXF1ZXN0KCk7CiAgICAgICAgICAgIHhoci5vcGVuKCdHRVQnLCB1cmwsIGZhbHNlKTsKICAgICAgICAgICAgaWYgKGRhdGFsZW5ndGggIT09IGNodW5rU2l6ZSkgeGhyLnNldFJlcXVlc3RIZWFkZXIoJ1JhbmdlJywgJ2J5dGVzPScgKyBmcm9tICsgJy0nICsgdG8pOwogICAgICAgICAgICBpZiAodHlwZW9mIFVpbnQ4QXJyYXkgIT0gJ3VuZGVmaW5lZCcpIHhoci5yZXNwb25zZVR5cGUgPSAnYXJyYXlidWZmZXInOwogICAgICAgICAgICBpZiAoeGhyLm92ZXJyaWRlTWltZVR5cGUpIHsKICAgICAgICAgICAgICB4aHIub3ZlcnJpZGVNaW1lVHlwZSgndGV4dC9wbGFpbjsgY2hhcnNldD14LXVzZXItZGVmaW5lZCcpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHhoci5zZW5kKG51bGwpOwogICAgICAgICAgICBpZiAoISgoeGhyLnN0YXR1cyA+PSAyMDAgJiYgeGhyLnN0YXR1cyA8IDMwMCkgfHwgeGhyLnN0YXR1cyA9PT0gMzA0KSkKICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoIkNvdWxkbid0IGxvYWQgIiArIHVybCArICcuIFN0YXR1czogJyArIHhoci5zdGF0dXMpCiAgICAgICAgICAgIGlmICh4aHIucmVzcG9uc2UgIT09IHVuZGVmaW5lZCkgewogICAgICAgICAgICAgIHJldHVybiBuZXcgVWludDhBcnJheSh4aHIucmVzcG9uc2UgfHwgW10pCiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgcmV0dXJuIGludEFycmF5RnJvbVN0cmluZyh4aHIucmVzcG9uc2VUZXh0IHx8ICcnLCB0cnVlKQogICAgICAgICAgICB9CiAgICAgICAgICB9OwogICAgICAgICAgdmFyIGxhenlBcnJheSA9IHRoaXM7CiAgICAgICAgICBsYXp5QXJyYXkuc2V0RGF0YUdldHRlcihmdW5jdGlvbiAoY2h1bmtOdW0pIHsKICAgICAgICAgICAgdmFyIHN0YXJ0ID0gY2h1bmtOdW0gKiBjaHVua1NpemU7CiAgICAgICAgICAgIHZhciBlbmQgPSAoY2h1bmtOdW0gKyAxKSAqIGNodW5rU2l6ZSAtIDE7CiAgICAgICAgICAgIGVuZCA9IE1hdGgubWluKGVuZCwgZGF0YWxlbmd0aCAtIDEpOwogICAgICAgICAgICBpZiAodHlwZW9mIGxhenlBcnJheS5jaHVua3NbY2h1bmtOdW1dID09PSAndW5kZWZpbmVkJykgewogICAgICAgICAgICAgIGxhenlBcnJheS5jaHVua3NbY2h1bmtOdW1dID0gZG9YSFIoc3RhcnQsIGVuZCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKHR5cGVvZiBsYXp5QXJyYXkuY2h1bmtzW2NodW5rTnVtXSA9PT0gJ3VuZGVmaW5lZCcpIHRocm93IG5ldyBFcnJvcignZG9YSFIgZmFpbGVkIScpCiAgICAgICAgICAgIHJldHVybiBsYXp5QXJyYXkuY2h1bmtzW2NodW5rTnVtXQogICAgICAgICAgfSk7CiAgICAgICAgICBpZiAodXNlc0d6aXAgfHwgIWRhdGFsZW5ndGgpIHsKICAgICAgICAgICAgY2h1bmtTaXplID0gZGF0YWxlbmd0aCA9IDE7CiAgICAgICAgICAgIGRhdGFsZW5ndGggPSB0aGlzLmdldHRlcigwKS5sZW5ndGg7CiAgICAgICAgICAgIGNodW5rU2l6ZSA9IGRhdGFsZW5ndGg7CiAgICAgICAgICAgIGNvbnNvbGUubG9nKCdMYXp5RmlsZXMgb24gZ3ppcCBmb3JjZXMgZG93bmxvYWQgb2YgdGhlIHdob2xlIGZpbGUgd2hlbiBsZW5ndGggaXMgYWNjZXNzZWQnKTsKICAgICAgICAgIH0KICAgICAgICAgIHRoaXMuX2xlbmd0aCA9IGRhdGFsZW5ndGg7CiAgICAgICAgICB0aGlzLl9jaHVua1NpemUgPSBjaHVua1NpemU7CiAgICAgICAgICB0aGlzLmxlbmd0aEtub3duID0gdHJ1ZTsKICAgICAgICB9OwogICAgICAgIGlmICh0eXBlb2YgWE1MSHR0cFJlcXVlc3QgIT09ICd1bmRlZmluZWQnKSB7CiAgICAgICAgICBpZiAoIUVOVklST05NRU5UX0lTX1dPUktFUikKICAgICAgICAgICAgdGhyb3cgJ0Nhbm5vdCBkbyBzeW5jaHJvbm91cyBiaW5hcnkgWEhScyBvdXRzaWRlIHdlYndvcmtlcnMgaW4gbW9kZXJuIGJyb3dzZXJzLiBVc2UgLS1lbWJlZC1maWxlIG9yIC0tcHJlbG9hZC1maWxlIGluIGVtY2MnCiAgICAgICAgICB2YXIgbGF6eUFycmF5ID0gbmV3IExhenlVaW50OEFycmF5KCk7CiAgICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydGllcyhsYXp5QXJyYXksIHsKICAgICAgICAgICAgbGVuZ3RoOiB7CiAgICAgICAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgICAgICBpZiAoIXRoaXMubGVuZ3RoS25vd24pIHsKICAgICAgICAgICAgICAgICAgdGhpcy5jYWNoZUxlbmd0aCgpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2xlbmd0aAogICAgICAgICAgICAgIH0sCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIGNodW5rU2l6ZTogewogICAgICAgICAgICAgIGdldDogZnVuY3Rpb24gKCkgewogICAgICAgICAgICAgICAgaWYgKCF0aGlzLmxlbmd0aEtub3duKSB7CiAgICAgICAgICAgICAgICAgIHRoaXMuY2FjaGVMZW5ndGgoKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLl9jaHVua1NpemUKICAgICAgICAgICAgICB9LAogICAgICAgICAgICB9LAogICAgICAgICAgfSk7CiAgICAgICAgICB2YXIgcHJvcGVydGllcyA9IHsgaXNEZXZpY2U6IGZhbHNlLCBjb250ZW50czogbGF6eUFycmF5IH07CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIHZhciBwcm9wZXJ0aWVzID0geyBpc0RldmljZTogZmFsc2UsIHVybDogdXJsIH07CiAgICAgICAgfQogICAgICAgIHZhciBub2RlID0gRlMuY3JlYXRlRmlsZShwYXJlbnQsIG5hbWUsIHByb3BlcnRpZXMsIGNhblJlYWQsIGNhbldyaXRlKTsKICAgICAgICBpZiAocHJvcGVydGllcy5jb250ZW50cykgewogICAgICAgICAgbm9kZS5jb250ZW50cyA9IHByb3BlcnRpZXMuY29udGVudHM7CiAgICAgICAgfSBlbHNlIGlmIChwcm9wZXJ0aWVzLnVybCkgewogICAgICAgICAgbm9kZS5jb250ZW50cyA9IG51bGw7CiAgICAgICAgICBub2RlLnVybCA9IHByb3BlcnRpZXMudXJsOwogICAgICAgIH0KICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydGllcyhub2RlLCB7CiAgICAgICAgICB1c2VkQnl0ZXM6IHsKICAgICAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuY29udGVudHMubGVuZ3RoCiAgICAgICAgICAgIH0sCiAgICAgICAgICB9LAogICAgICAgIH0pOwogICAgICAgIHZhciBzdHJlYW1fb3BzID0ge307CiAgICAgICAgdmFyIGtleXMgPSBPYmplY3Qua2V5cyhub2RlLnN0cmVhbV9vcHMpOwogICAgICAgIGtleXMuZm9yRWFjaChmdW5jdGlvbiAoa2V5KSB7CiAgICAgICAgICB2YXIgZm4gPSBub2RlLnN0cmVhbV9vcHNba2V5XTsKICAgICAgICAgIHN0cmVhbV9vcHNba2V5XSA9IGZ1bmN0aW9uIGZvcmNlTG9hZExhenlGaWxlKCkgewogICAgICAgICAgICBpZiAoIUZTLmZvcmNlTG9hZEZpbGUobm9kZSkpIHsKICAgICAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FSU8pCiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIGZuLmFwcGx5KG51bGwsIGFyZ3VtZW50cykKICAgICAgICAgIH07CiAgICAgICAgfSk7CiAgICAgICAgc3RyZWFtX29wcy5yZWFkID0gZnVuY3Rpb24gc3RyZWFtX29wc19yZWFkKHN0cmVhbSwgYnVmZmVyLCBvZmZzZXQsIGxlbmd0aCwgcG9zaXRpb24pIHsKICAgICAgICAgIGlmICghRlMuZm9yY2VMb2FkRmlsZShub2RlKSkgewogICAgICAgICAgICB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FSU8pCiAgICAgICAgICB9CiAgICAgICAgICB2YXIgY29udGVudHMgPSBzdHJlYW0ubm9kZS5jb250ZW50czsKICAgICAgICAgIGlmIChwb3NpdGlvbiA+PSBjb250ZW50cy5sZW5ndGgpIHJldHVybiAwCiAgICAgICAgICB2YXIgc2l6ZSA9IE1hdGgubWluKGNvbnRlbnRzLmxlbmd0aCAtIHBvc2l0aW9uLCBsZW5ndGgpOwogICAgICAgICAgYXNzZXJ0KHNpemUgPj0gMCk7CiAgICAgICAgICBpZiAoY29udGVudHMuc2xpY2UpIHsKICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBzaXplOyBpKyspIHsKICAgICAgICAgICAgICBidWZmZXJbb2Zmc2V0ICsgaV0gPSBjb250ZW50c1twb3NpdGlvbiArIGldOwogICAgICAgICAgICB9CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHNpemU7IGkrKykgewogICAgICAgICAgICAgIGJ1ZmZlcltvZmZzZXQgKyBpXSA9IGNvbnRlbnRzLmdldChwb3NpdGlvbiArIGkpOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gc2l6ZQogICAgICAgIH07CiAgICAgICAgbm9kZS5zdHJlYW1fb3BzID0gc3RyZWFtX29wczsKICAgICAgICByZXR1cm4gbm9kZQogICAgICB9LAogICAgICBjcmVhdGVQcmVsb2FkZWRGaWxlOiBmdW5jdGlvbiAoCiAgICAgICAgcGFyZW50LAogICAgICAgIG5hbWUsCiAgICAgICAgdXJsLAogICAgICAgIGNhblJlYWQsCiAgICAgICAgY2FuV3JpdGUsCiAgICAgICAgb25sb2FkLAogICAgICAgIG9uZXJyb3IsCiAgICAgICAgZG9udENyZWF0ZUZpbGUsCiAgICAgICAgY2FuT3duLAogICAgICAgIHByZUZpbmlzaAogICAgICApIHsKICAgICAgICBCcm93c2VyLmluaXQoKTsKICAgICAgICB2YXIgZnVsbG5hbWUgPSBuYW1lID8gUEFUSC5yZXNvbHZlKFBBVEguam9pbjIocGFyZW50LCBuYW1lKSkgOiBwYXJlbnQ7CiAgICAgICAgZnVuY3Rpb24gcHJvY2Vzc0RhdGEoYnl0ZUFycmF5KSB7CiAgICAgICAgICBmdW5jdGlvbiBmaW5pc2goYnl0ZUFycmF5KSB7CiAgICAgICAgICAgIGlmIChwcmVGaW5pc2gpIHByZUZpbmlzaCgpOwogICAgICAgICAgICBpZiAoIWRvbnRDcmVhdGVGaWxlKSB7CiAgICAgICAgICAgICAgRlMuY3JlYXRlRGF0YUZpbGUocGFyZW50LCBuYW1lLCBieXRlQXJyYXksIGNhblJlYWQsIGNhbldyaXRlLCBjYW5Pd24pOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIChvbmxvYWQpIG9ubG9hZCgpOwogICAgICAgICAgICByZW1vdmVSdW5EZXBlbmRlbmN5KCk7CiAgICAgICAgICB9CiAgICAgICAgICB2YXIgaGFuZGxlZCA9IGZhbHNlOwogICAgICAgICAgTW9kdWxlWydwcmVsb2FkUGx1Z2lucyddLmZvckVhY2goZnVuY3Rpb24gKHBsdWdpbikgewogICAgICAgICAgICBpZiAoaGFuZGxlZCkgcmV0dXJuCiAgICAgICAgICAgIGlmIChwbHVnaW5bJ2NhbkhhbmRsZSddKGZ1bGxuYW1lKSkgewogICAgICAgICAgICAgIHBsdWdpblsnaGFuZGxlJ10oYnl0ZUFycmF5LCBmdWxsbmFtZSwgZmluaXNoLCBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgICAgICBpZiAob25lcnJvcikgb25lcnJvcigpOwogICAgICAgICAgICAgICAgcmVtb3ZlUnVuRGVwZW5kZW5jeSgpOwogICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgIGhhbmRsZWQgPSB0cnVlOwogICAgICAgICAgICB9CiAgICAgICAgICB9KTsKICAgICAgICAgIGlmICghaGFuZGxlZCkgZmluaXNoKGJ5dGVBcnJheSk7CiAgICAgICAgfQogICAgICAgIGFkZFJ1bkRlcGVuZGVuY3koKTsKICAgICAgICBpZiAodHlwZW9mIHVybCA9PSAnc3RyaW5nJykgewogICAgICAgICAgQnJvd3Nlci5hc3luY0xvYWQoCiAgICAgICAgICAgIHVybCwKICAgICAgICAgICAgZnVuY3Rpb24gKGJ5dGVBcnJheSkgewogICAgICAgICAgICAgIHByb2Nlc3NEYXRhKGJ5dGVBcnJheSk7CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIG9uZXJyb3IKICAgICAgICAgICk7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIHByb2Nlc3NEYXRhKHVybCk7CiAgICAgICAgfQogICAgICB9LAogICAgICBpbmRleGVkREI6IGZ1bmN0aW9uICgpIHsKICAgICAgICByZXR1cm4gd2luZG93LmluZGV4ZWREQiB8fCB3aW5kb3cubW96SW5kZXhlZERCIHx8IHdpbmRvdy53ZWJraXRJbmRleGVkREIgfHwgd2luZG93Lm1zSW5kZXhlZERCCiAgICAgIH0sCiAgICAgIERCX05BTUU6IGZ1bmN0aW9uICgpIHsKICAgICAgICByZXR1cm4gJ0VNX0ZTXycgKyB3aW5kb3cubG9jYXRpb24ucGF0aG5hbWUKICAgICAgfSwKICAgICAgREJfVkVSU0lPTjogMjAsCiAgICAgIERCX1NUT1JFX05BTUU6ICdGSUxFX0RBVEEnLAogICAgICBzYXZlRmlsZXNUb0RCOiBmdW5jdGlvbiAocGF0aHMsIG9ubG9hZCwgb25lcnJvcikgewogICAgICAgIG9ubG9hZCA9IG9ubG9hZCB8fCBmdW5jdGlvbiAoKSB7fTsKICAgICAgICBvbmVycm9yID0gb25lcnJvciB8fCBmdW5jdGlvbiAoKSB7fTsKICAgICAgICB2YXIgaW5kZXhlZERCID0gRlMuaW5kZXhlZERCKCk7CiAgICAgICAgdHJ5IHsKICAgICAgICAgIHZhciBvcGVuUmVxdWVzdCA9IGluZGV4ZWREQi5vcGVuKEZTLkRCX05BTUUoKSwgRlMuREJfVkVSU0lPTik7CiAgICAgICAgfSBjYXRjaCAoZSkgewogICAgICAgICAgcmV0dXJuIG9uZXJyb3IoZSkKICAgICAgICB9CiAgICAgICAgb3BlblJlcXVlc3Qub251cGdyYWRlbmVlZGVkID0gZnVuY3Rpb24gb3BlblJlcXVlc3Rfb251cGdyYWRlbmVlZGVkKCkgewogICAgICAgICAgY29uc29sZS5sb2coJ2NyZWF0aW5nIGRiJyk7CiAgICAgICAgICB2YXIgZGIgPSBvcGVuUmVxdWVzdC5yZXN1bHQ7CiAgICAgICAgICBkYi5jcmVhdGVPYmplY3RTdG9yZShGUy5EQl9TVE9SRV9OQU1FKTsKICAgICAgICB9OwogICAgICAgIG9wZW5SZXF1ZXN0Lm9uc3VjY2VzcyA9IGZ1bmN0aW9uIG9wZW5SZXF1ZXN0X29uc3VjY2VzcygpIHsKICAgICAgICAgIHZhciBkYiA9IG9wZW5SZXF1ZXN0LnJlc3VsdDsKICAgICAgICAgIHZhciB0cmFuc2FjdGlvbiA9IGRiLnRyYW5zYWN0aW9uKFtGUy5EQl9TVE9SRV9OQU1FXSwgJ3JlYWR3cml0ZScpOwogICAgICAgICAgdmFyIGZpbGVzID0gdHJhbnNhY3Rpb24ub2JqZWN0U3RvcmUoRlMuREJfU1RPUkVfTkFNRSk7CiAgICAgICAgICB2YXIgb2sgPSAwLAogICAgICAgICAgICBmYWlsID0gMCwKICAgICAgICAgICAgdG90YWwgPSBwYXRocy5sZW5ndGg7CiAgICAgICAgICBmdW5jdGlvbiBmaW5pc2goKSB7CiAgICAgICAgICAgIGlmIChmYWlsID09IDApIG9ubG9hZCgpOwogICAgICAgICAgICBlbHNlIG9uZXJyb3IoKTsKICAgICAgICAgIH0KICAgICAgICAgIHBhdGhzLmZvckVhY2goZnVuY3Rpb24gKHBhdGgpIHsKICAgICAgICAgICAgdmFyIHB1dFJlcXVlc3QgPSBmaWxlcy5wdXQoRlMuYW5hbHl6ZVBhdGgocGF0aCkub2JqZWN0LmNvbnRlbnRzLCBwYXRoKTsKICAgICAgICAgICAgcHV0UmVxdWVzdC5vbnN1Y2Nlc3MgPSBmdW5jdGlvbiBwdXRSZXF1ZXN0X29uc3VjY2VzcygpIHsKICAgICAgICAgICAgICBvaysrOwogICAgICAgICAgICAgIGlmIChvayArIGZhaWwgPT0gdG90YWwpIGZpbmlzaCgpOwogICAgICAgICAgICB9OwogICAgICAgICAgICBwdXRSZXF1ZXN0Lm9uZXJyb3IgPSBmdW5jdGlvbiBwdXRSZXF1ZXN0X29uZXJyb3IoKSB7CiAgICAgICAgICAgICAgZmFpbCsrOwogICAgICAgICAgICAgIGlmIChvayArIGZhaWwgPT0gdG90YWwpIGZpbmlzaCgpOwogICAgICAgICAgICB9OwogICAgICAgICAgfSk7CiAgICAgICAgICB0cmFuc2FjdGlvbi5vbmVycm9yID0gb25lcnJvcjsKICAgICAgICB9OwogICAgICAgIG9wZW5SZXF1ZXN0Lm9uZXJyb3IgPSBvbmVycm9yOwogICAgICB9LAogICAgICBsb2FkRmlsZXNGcm9tREI6IGZ1bmN0aW9uIChwYXRocywgb25sb2FkLCBvbmVycm9yKSB7CiAgICAgICAgb25sb2FkID0gb25sb2FkIHx8IGZ1bmN0aW9uICgpIHt9OwogICAgICAgIG9uZXJyb3IgPSBvbmVycm9yIHx8IGZ1bmN0aW9uICgpIHt9OwogICAgICAgIHZhciBpbmRleGVkREIgPSBGUy5pbmRleGVkREIoKTsKICAgICAgICB0cnkgewogICAgICAgICAgdmFyIG9wZW5SZXF1ZXN0ID0gaW5kZXhlZERCLm9wZW4oRlMuREJfTkFNRSgpLCBGUy5EQl9WRVJTSU9OKTsKICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICByZXR1cm4gb25lcnJvcihlKQogICAgICAgIH0KICAgICAgICBvcGVuUmVxdWVzdC5vbnVwZ3JhZGVuZWVkZWQgPSBvbmVycm9yOwogICAgICAgIG9wZW5SZXF1ZXN0Lm9uc3VjY2VzcyA9IGZ1bmN0aW9uIG9wZW5SZXF1ZXN0X29uc3VjY2VzcygpIHsKICAgICAgICAgIHZhciBkYiA9IG9wZW5SZXF1ZXN0LnJlc3VsdDsKICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgIHZhciB0cmFuc2FjdGlvbiA9IGRiLnRyYW5zYWN0aW9uKFtGUy5EQl9TVE9SRV9OQU1FXSwgJ3JlYWRvbmx5Jyk7CiAgICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICAgIG9uZXJyb3IoZSk7CiAgICAgICAgICAgIHJldHVybgogICAgICAgICAgfQogICAgICAgICAgdmFyIGZpbGVzID0gdHJhbnNhY3Rpb24ub2JqZWN0U3RvcmUoRlMuREJfU1RPUkVfTkFNRSk7CiAgICAgICAgICB2YXIgb2sgPSAwLAogICAgICAgICAgICBmYWlsID0gMCwKICAgICAgICAgICAgdG90YWwgPSBwYXRocy5sZW5ndGg7CiAgICAgICAgICBmdW5jdGlvbiBmaW5pc2goKSB7CiAgICAgICAgICAgIGlmIChmYWlsID09IDApIG9ubG9hZCgpOwogICAgICAgICAgICBlbHNlIG9uZXJyb3IoKTsKICAgICAgICAgIH0KICAgICAgICAgIHBhdGhzLmZvckVhY2goZnVuY3Rpb24gKHBhdGgpIHsKICAgICAgICAgICAgdmFyIGdldFJlcXVlc3QgPSBmaWxlcy5nZXQocGF0aCk7CiAgICAgICAgICAgIGdldFJlcXVlc3Qub25zdWNjZXNzID0gZnVuY3Rpb24gZ2V0UmVxdWVzdF9vbnN1Y2Nlc3MoKSB7CiAgICAgICAgICAgICAgaWYgKEZTLmFuYWx5emVQYXRoKHBhdGgpLmV4aXN0cykgewogICAgICAgICAgICAgICAgRlMudW5saW5rKHBhdGgpOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBGUy5jcmVhdGVEYXRhRmlsZShQQVRILmRpcm5hbWUocGF0aCksIFBBVEguYmFzZW5hbWUocGF0aCksIGdldFJlcXVlc3QucmVzdWx0LCB0cnVlLCB0cnVlLCB0cnVlKTsKICAgICAgICAgICAgICBvaysrOwogICAgICAgICAgICAgIGlmIChvayArIGZhaWwgPT0gdG90YWwpIGZpbmlzaCgpOwogICAgICAgICAgICB9OwogICAgICAgICAgICBnZXRSZXF1ZXN0Lm9uZXJyb3IgPSBmdW5jdGlvbiBnZXRSZXF1ZXN0X29uZXJyb3IoKSB7CiAgICAgICAgICAgICAgZmFpbCsrOwogICAgICAgICAgICAgIGlmIChvayArIGZhaWwgPT0gdG90YWwpIGZpbmlzaCgpOwogICAgICAgICAgICB9OwogICAgICAgICAgfSk7CiAgICAgICAgICB0cmFuc2FjdGlvbi5vbmVycm9yID0gb25lcnJvcjsKICAgICAgICB9OwogICAgICAgIG9wZW5SZXF1ZXN0Lm9uZXJyb3IgPSBvbmVycm9yOwogICAgICB9LAogICAgfTsKICAgIHZhciBTWVNDQUxMUyA9IHsKICAgICAgREVGQVVMVF9QT0xMTUFTSzogNSwKICAgICAgbWFwcGluZ3M6IHt9LAogICAgICB1bWFzazogNTExLAogICAgICBjYWxjdWxhdGVBdDogZnVuY3Rpb24gKGRpcmZkLCBwYXRoKSB7CiAgICAgICAgaWYgKHBhdGhbMF0gIT09ICcvJykgewogICAgICAgICAgdmFyIGRpcjsKICAgICAgICAgIGlmIChkaXJmZCA9PT0gLTEwMCkgewogICAgICAgICAgICBkaXIgPSBGUy5jd2QoKTsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHZhciBkaXJzdHJlYW0gPSBGUy5nZXRTdHJlYW0oZGlyZmQpOwogICAgICAgICAgICBpZiAoIWRpcnN0cmVhbSkgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoRVJSTk9fQ09ERVMuRUJBREYpCiAgICAgICAgICAgIGRpciA9IGRpcnN0cmVhbS5wYXRoOwogICAgICAgICAgfQogICAgICAgICAgcGF0aCA9IFBBVEguam9pbjIoZGlyLCBwYXRoKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHBhdGgKICAgICAgfSwKICAgICAgZG9TdGF0OiBmdW5jdGlvbiAoZnVuYywgcGF0aCwgYnVmKSB7CiAgICAgICAgdHJ5IHsKICAgICAgICAgIHZhciBzdGF0ID0gZnVuYyhwYXRoKTsKICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICBpZiAoZSAmJiBlLm5vZGUgJiYgUEFUSC5ub3JtYWxpemUocGF0aCkgIT09IFBBVEgubm9ybWFsaXplKEZTLmdldFBhdGgoZS5ub2RlKSkpIHsKICAgICAgICAgICAgcmV0dXJuIC1FUlJOT19DT0RFUy5FTk9URElSCiAgICAgICAgICB9CiAgICAgICAgICB0aHJvdyBlCiAgICAgICAgfQogICAgICAgIEhFQVAzMltidWYgPj4gMl0gPSBzdGF0LmRldjsKICAgICAgICBIRUFQMzJbKGJ1ZiArIDQpID4+IDJdID0gMDsKICAgICAgICBIRUFQMzJbKGJ1ZiArIDgpID4+IDJdID0gc3RhdC5pbm87CiAgICAgICAgSEVBUDMyWyhidWYgKyAxMikgPj4gMl0gPSBzdGF0Lm1vZGU7CiAgICAgICAgSEVBUDMyWyhidWYgKyAxNikgPj4gMl0gPSBzdGF0Lm5saW5rOwogICAgICAgIEhFQVAzMlsoYnVmICsgMjApID4+IDJdID0gc3RhdC51aWQ7CiAgICAgICAgSEVBUDMyWyhidWYgKyAyNCkgPj4gMl0gPSBzdGF0LmdpZDsKICAgICAgICBIRUFQMzJbKGJ1ZiArIDI4KSA+PiAyXSA9IHN0YXQucmRldjsKICAgICAgICBIRUFQMzJbKGJ1ZiArIDMyKSA+PiAyXSA9IDA7CiAgICAgICAgSEVBUDMyWyhidWYgKyAzNikgPj4gMl0gPSBzdGF0LnNpemU7CiAgICAgICAgSEVBUDMyWyhidWYgKyA0MCkgPj4gMl0gPSA0MDk2OwogICAgICAgIEhFQVAzMlsoYnVmICsgNDQpID4+IDJdID0gc3RhdC5ibG9ja3M7CiAgICAgICAgSEVBUDMyWyhidWYgKyA0OCkgPj4gMl0gPSAoc3RhdC5hdGltZS5nZXRUaW1lKCkgLyAxZTMpIHwgMDsKICAgICAgICBIRUFQMzJbKGJ1ZiArIDUyKSA+PiAyXSA9IDA7CiAgICAgICAgSEVBUDMyWyhidWYgKyA1NikgPj4gMl0gPSAoc3RhdC5tdGltZS5nZXRUaW1lKCkgLyAxZTMpIHwgMDsKICAgICAgICBIRUFQMzJbKGJ1ZiArIDYwKSA+PiAyXSA9IDA7CiAgICAgICAgSEVBUDMyWyhidWYgKyA2NCkgPj4gMl0gPSAoc3RhdC5jdGltZS5nZXRUaW1lKCkgLyAxZTMpIHwgMDsKICAgICAgICBIRUFQMzJbKGJ1ZiArIDY4KSA+PiAyXSA9IDA7CiAgICAgICAgSEVBUDMyWyhidWYgKyA3MikgPj4gMl0gPSBzdGF0LmlubzsKICAgICAgICByZXR1cm4gMAogICAgICB9LAogICAgICBkb01zeW5jOiBmdW5jdGlvbiAoYWRkciwgc3RyZWFtLCBsZW4sIGZsYWdzKSB7CiAgICAgICAgdmFyIGJ1ZmZlciA9IG5ldyBVaW50OEFycmF5KEhFQVBVOC5zdWJhcnJheShhZGRyLCBhZGRyICsgbGVuKSk7CiAgICAgICAgRlMubXN5bmMoc3RyZWFtLCBidWZmZXIsIDAsIGxlbiwgZmxhZ3MpOwogICAgICB9LAogICAgICBkb01rZGlyOiBmdW5jdGlvbiAocGF0aCwgbW9kZSkgewogICAgICAgIHBhdGggPSBQQVRILm5vcm1hbGl6ZShwYXRoKTsKICAgICAgICBpZiAocGF0aFtwYXRoLmxlbmd0aCAtIDFdID09PSAnLycpIHBhdGggPSBwYXRoLnN1YnN0cigwLCBwYXRoLmxlbmd0aCAtIDEpOwogICAgICAgIEZTLm1rZGlyKHBhdGgsIG1vZGUsIDApOwogICAgICAgIHJldHVybiAwCiAgICAgIH0sCiAgICAgIGRvTWtub2Q6IGZ1bmN0aW9uIChwYXRoLCBtb2RlLCBkZXYpIHsKICAgICAgICBzd2l0Y2ggKG1vZGUgJiA2MTQ0MCkgewogICAgICAgICAgY2FzZSAzMjc2ODoKICAgICAgICAgIGNhc2UgODE5MjoKICAgICAgICAgIGNhc2UgMjQ1NzY6CiAgICAgICAgICBjYXNlIDQwOTY6CiAgICAgICAgICBjYXNlIDQ5MTUyOgogICAgICAgICAgICBicmVhawogICAgICAgICAgZGVmYXVsdDoKICAgICAgICAgICAgcmV0dXJuIC1FUlJOT19DT0RFUy5FSU5WQUwKICAgICAgICB9CiAgICAgICAgRlMubWtub2QocGF0aCwgbW9kZSwgZGV2KTsKICAgICAgICByZXR1cm4gMAogICAgICB9LAogICAgICBkb1JlYWRsaW5rOiBmdW5jdGlvbiAocGF0aCwgYnVmLCBidWZzaXplKSB7CiAgICAgICAgaWYgKGJ1ZnNpemUgPD0gMCkgcmV0dXJuIC1FUlJOT19DT0RFUy5FSU5WQUwKICAgICAgICB2YXIgcmV0ID0gRlMucmVhZGxpbmsocGF0aCk7CiAgICAgICAgdmFyIGxlbiA9IE1hdGgubWluKGJ1ZnNpemUsIGxlbmd0aEJ5dGVzVVRGOChyZXQpKTsKICAgICAgICB2YXIgZW5kQ2hhciA9IEhFQVA4W2J1ZiArIGxlbl07CiAgICAgICAgc3RyaW5nVG9VVEY4KHJldCwgYnVmLCBidWZzaXplICsgMSk7CiAgICAgICAgSEVBUDhbYnVmICsgbGVuXSA9IGVuZENoYXI7CiAgICAgICAgcmV0dXJuIGxlbgogICAgICB9LAogICAgICBkb0FjY2VzczogZnVuY3Rpb24gKHBhdGgsIGFtb2RlKSB7CiAgICAgICAgaWYgKGFtb2RlICYgfjcpIHsKICAgICAgICAgIHJldHVybiAtRVJSTk9fQ09ERVMuRUlOVkFMCiAgICAgICAgfQogICAgICAgIHZhciBub2RlOwogICAgICAgIHZhciBsb29rdXAgPSBGUy5sb29rdXBQYXRoKHBhdGgsIHsgZm9sbG93OiB0cnVlIH0pOwogICAgICAgIG5vZGUgPSBsb29rdXAubm9kZTsKICAgICAgICB2YXIgcGVybXMgPSAnJzsKICAgICAgICBpZiAoYW1vZGUgJiA0KSBwZXJtcyArPSAncic7CiAgICAgICAgaWYgKGFtb2RlICYgMikgcGVybXMgKz0gJ3cnOwogICAgICAgIGlmIChhbW9kZSAmIDEpIHBlcm1zICs9ICd4JzsKICAgICAgICBpZiAocGVybXMgJiYgRlMubm9kZVBlcm1pc3Npb25zKG5vZGUsIHBlcm1zKSkgewogICAgICAgICAgcmV0dXJuIC1FUlJOT19DT0RFUy5FQUNDRVMKICAgICAgICB9CiAgICAgICAgcmV0dXJuIDAKICAgICAgfSwKICAgICAgZG9EdXA6IGZ1bmN0aW9uIChwYXRoLCBmbGFncywgc3VnZ2VzdEZEKSB7CiAgICAgICAgdmFyIHN1Z2dlc3QgPSBGUy5nZXRTdHJlYW0oc3VnZ2VzdEZEKTsKICAgICAgICBpZiAoc3VnZ2VzdCkgRlMuY2xvc2Uoc3VnZ2VzdCk7CiAgICAgICAgcmV0dXJuIEZTLm9wZW4ocGF0aCwgZmxhZ3MsIDAsIHN1Z2dlc3RGRCwgc3VnZ2VzdEZEKS5mZAogICAgICB9LAogICAgICBkb1JlYWR2OiBmdW5jdGlvbiAoc3RyZWFtLCBpb3YsIGlvdmNudCwgb2Zmc2V0KSB7CiAgICAgICAgdmFyIHJldCA9IDA7CiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBpb3ZjbnQ7IGkrKykgewogICAgICAgICAgdmFyIHB0ciA9IEhFQVAzMlsoaW92ICsgaSAqIDgpID4+IDJdOwogICAgICAgICAgdmFyIGxlbiA9IEhFQVAzMlsoaW92ICsgKGkgKiA4ICsgNCkpID4+IDJdOwogICAgICAgICAgdmFyIGN1cnIgPSBGUy5yZWFkKHN0cmVhbSwgSEVBUDgsIHB0ciwgbGVuLCBvZmZzZXQpOwogICAgICAgICAgaWYgKGN1cnIgPCAwKSByZXR1cm4gLTEKICAgICAgICAgIHJldCArPSBjdXJyOwogICAgICAgICAgaWYgKGN1cnIgPCBsZW4pIGJyZWFrCiAgICAgICAgfQogICAgICAgIHJldHVybiByZXQKICAgICAgfSwKICAgICAgZG9Xcml0ZXY6IGZ1bmN0aW9uIChzdHJlYW0sIGlvdiwgaW92Y250LCBvZmZzZXQpIHsKICAgICAgICB2YXIgcmV0ID0gMDsKICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGlvdmNudDsgaSsrKSB7CiAgICAgICAgICB2YXIgcHRyID0gSEVBUDMyWyhpb3YgKyBpICogOCkgPj4gMl07CiAgICAgICAgICB2YXIgbGVuID0gSEVBUDMyWyhpb3YgKyAoaSAqIDggKyA0KSkgPj4gMl07CiAgICAgICAgICB2YXIgY3VyciA9IEZTLndyaXRlKHN0cmVhbSwgSEVBUDgsIHB0ciwgbGVuLCBvZmZzZXQpOwogICAgICAgICAgaWYgKGN1cnIgPCAwKSByZXR1cm4gLTEKICAgICAgICAgIHJldCArPSBjdXJyOwogICAgICAgIH0KICAgICAgICByZXR1cm4gcmV0CiAgICAgIH0sCiAgICAgIHZhcmFyZ3M6IDAsCiAgICAgIGdldDogZnVuY3Rpb24gKHZhcmFyZ3MpIHsKICAgICAgICBTWVNDQUxMUy52YXJhcmdzICs9IDQ7CiAgICAgICAgdmFyIHJldCA9IEhFQVAzMlsoU1lTQ0FMTFMudmFyYXJncyAtIDQpID4+IDJdOwogICAgICAgIHJldHVybiByZXQKICAgICAgfSwKICAgICAgZ2V0U3RyOiBmdW5jdGlvbiAoKSB7CiAgICAgICAgdmFyIHJldCA9IFBvaW50ZXJfc3RyaW5naWZ5KFNZU0NBTExTLmdldCgpKTsKICAgICAgICByZXR1cm4gcmV0CiAgICAgIH0sCiAgICAgIGdldFN0cmVhbUZyb21GRDogZnVuY3Rpb24gKCkgewogICAgICAgIHZhciBzdHJlYW0gPSBGUy5nZXRTdHJlYW0oU1lTQ0FMTFMuZ2V0KCkpOwogICAgICAgIGlmICghc3RyZWFtKSB0aHJvdyBuZXcgRlMuRXJybm9FcnJvcihFUlJOT19DT0RFUy5FQkFERikKICAgICAgICByZXR1cm4gc3RyZWFtCiAgICAgIH0sCiAgICAgIGdldFNvY2tldEZyb21GRDogZnVuY3Rpb24gKCkgewogICAgICAgIHZhciBzb2NrZXQgPSBTT0NLRlMuZ2V0U29ja2V0KFNZU0NBTExTLmdldCgpKTsKICAgICAgICBpZiAoIXNvY2tldCkgdGhyb3cgbmV3IEZTLkVycm5vRXJyb3IoRVJSTk9fQ09ERVMuRUJBREYpCiAgICAgICAgcmV0dXJuIHNvY2tldAogICAgICB9LAogICAgICBnZXRTb2NrZXRBZGRyZXNzOiBmdW5jdGlvbiAoYWxsb3dOdWxsKSB7CiAgICAgICAgdmFyIGFkZHJwID0gU1lTQ0FMTFMuZ2V0KCksCiAgICAgICAgICBhZGRybGVuID0gU1lTQ0FMTFMuZ2V0KCk7CiAgICAgICAgaWYgKGFsbG93TnVsbCAmJiBhZGRycCA9PT0gMCkgcmV0dXJuIG51bGwKICAgICAgICB2YXIgaW5mbyA9IF9fcmVhZF9zb2NrYWRkcihhZGRycCwgYWRkcmxlbik7CiAgICAgICAgaWYgKGluZm8uZXJybm8pIHRocm93IG5ldyBGUy5FcnJub0Vycm9yKGluZm8uZXJybm8pCiAgICAgICAgaW5mby5hZGRyID0gRE5TLmxvb2t1cF9hZGRyKGluZm8uYWRkcikgfHwgaW5mby5hZGRyOwogICAgICAgIHJldHVybiBpbmZvCiAgICAgIH0sCiAgICAgIGdldDY0OiBmdW5jdGlvbiAoKSB7CiAgICAgICAgdmFyIGxvdyA9IFNZU0NBTExTLmdldCgpLAogICAgICAgICAgaGlnaCA9IFNZU0NBTExTLmdldCgpOwogICAgICAgIGlmIChsb3cgPj0gMCkgYXNzZXJ0KGhpZ2ggPT09IDApOwogICAgICAgIGVsc2UgYXNzZXJ0KGhpZ2ggPT09IC0xKTsKICAgICAgICByZXR1cm4gbG93CiAgICAgIH0sCiAgICAgIGdldFplcm86IGZ1bmN0aW9uICgpIHsKICAgICAgICBhc3NlcnQoU1lTQ0FMTFMuZ2V0KCkgPT09IDApOwogICAgICB9LAogICAgfTsKICAgIGZ1bmN0aW9uIF9fX3N5c2NhbGwxNDAod2hpY2gsIHZhcmFyZ3MpIHsKICAgICAgU1lTQ0FMTFMudmFyYXJncyA9IHZhcmFyZ3M7CiAgICAgIHRyeSB7CiAgICAgICAgdmFyIHN0cmVhbSA9IFNZU0NBTExTLmdldFN0cmVhbUZyb21GRCgpLAogICAgICAgICAgb2Zmc2V0X2hpZ2ggPSBTWVNDQUxMUy5nZXQoKSwKICAgICAgICAgIG9mZnNldF9sb3cgPSBTWVNDQUxMUy5nZXQoKSwKICAgICAgICAgIHJlc3VsdCA9IFNZU0NBTExTLmdldCgpLAogICAgICAgICAgd2hlbmNlID0gU1lTQ0FMTFMuZ2V0KCk7CiAgICAgICAgdmFyIG9mZnNldCA9IG9mZnNldF9sb3c7CiAgICAgICAgRlMubGxzZWVrKHN0cmVhbSwgb2Zmc2V0LCB3aGVuY2UpOwogICAgICAgIEhFQVAzMltyZXN1bHQgPj4gMl0gPSBzdHJlYW0ucG9zaXRpb247CiAgICAgICAgaWYgKHN0cmVhbS5nZXRkZW50cyAmJiBvZmZzZXQgPT09IDAgJiYgd2hlbmNlID09PSAwKSBzdHJlYW0uZ2V0ZGVudHMgPSBudWxsOwogICAgICAgIHJldHVybiAwCiAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICBpZiAodHlwZW9mIEZTID09PSAndW5kZWZpbmVkJyB8fCAhKGUgaW5zdGFuY2VvZiBGUy5FcnJub0Vycm9yKSkgYWJvcnQoZSk7CiAgICAgICAgcmV0dXJuIC1lLmVycm5vCiAgICAgIH0KICAgIH0KICAgIGZ1bmN0aW9uIF9fX3N5c2NhbGwxNDUod2hpY2gsIHZhcmFyZ3MpIHsKICAgICAgU1lTQ0FMTFMudmFyYXJncyA9IHZhcmFyZ3M7CiAgICAgIHRyeSB7CiAgICAgICAgdmFyIHN0cmVhbSA9IFNZU0NBTExTLmdldFN0cmVhbUZyb21GRCgpLAogICAgICAgICAgaW92ID0gU1lTQ0FMTFMuZ2V0KCksCiAgICAgICAgICBpb3ZjbnQgPSBTWVNDQUxMUy5nZXQoKTsKICAgICAgICByZXR1cm4gU1lTQ0FMTFMuZG9SZWFkdihzdHJlYW0sIGlvdiwgaW92Y250KQogICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgaWYgKHR5cGVvZiBGUyA9PT0gJ3VuZGVmaW5lZCcgfHwgIShlIGluc3RhbmNlb2YgRlMuRXJybm9FcnJvcikpIGFib3J0KGUpOwogICAgICAgIHJldHVybiAtZS5lcnJubwogICAgICB9CiAgICB9CiAgICBmdW5jdGlvbiBfX19zeXNjYWxsMTQ2KHdoaWNoLCB2YXJhcmdzKSB7CiAgICAgIFNZU0NBTExTLnZhcmFyZ3MgPSB2YXJhcmdzOwogICAgICB0cnkgewogICAgICAgIHZhciBzdHJlYW0gPSBTWVNDQUxMUy5nZXRTdHJlYW1Gcm9tRkQoKSwKICAgICAgICAgIGlvdiA9IFNZU0NBTExTLmdldCgpLAogICAgICAgICAgaW92Y250ID0gU1lTQ0FMTFMuZ2V0KCk7CiAgICAgICAgcmV0dXJuIFNZU0NBTExTLmRvV3JpdGV2KHN0cmVhbSwgaW92LCBpb3ZjbnQpCiAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICBpZiAodHlwZW9mIEZTID09PSAndW5kZWZpbmVkJyB8fCAhKGUgaW5zdGFuY2VvZiBGUy5FcnJub0Vycm9yKSkgYWJvcnQoZSk7CiAgICAgICAgcmV0dXJuIC1lLmVycm5vCiAgICAgIH0KICAgIH0KICAgIGZ1bmN0aW9uIF9fX3N5c2NhbGwxODMod2hpY2gsIHZhcmFyZ3MpIHsKICAgICAgU1lTQ0FMTFMudmFyYXJncyA9IHZhcmFyZ3M7CiAgICAgIHRyeSB7CiAgICAgICAgdmFyIGJ1ZiA9IFNZU0NBTExTLmdldCgpLAogICAgICAgICAgc2l6ZSA9IFNZU0NBTExTLmdldCgpOwogICAgICAgIGlmIChzaXplID09PSAwKSByZXR1cm4gLUVSUk5PX0NPREVTLkVJTlZBTAogICAgICAgIHZhciBjd2QgPSBGUy5jd2QoKTsKICAgICAgICB2YXIgY3dkTGVuZ3RoSW5CeXRlcyA9IGxlbmd0aEJ5dGVzVVRGOChjd2QpOwogICAgICAgIGlmIChzaXplIDwgY3dkTGVuZ3RoSW5CeXRlcyArIDEpIHJldHVybiAtRVJSTk9fQ09ERVMuRVJBTkdFCiAgICAgICAgc3RyaW5nVG9VVEY4KGN3ZCwgYnVmLCBzaXplKTsKICAgICAgICByZXR1cm4gYnVmCiAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICBpZiAodHlwZW9mIEZTID09PSAndW5kZWZpbmVkJyB8fCAhKGUgaW5zdGFuY2VvZiBGUy5FcnJub0Vycm9yKSkgYWJvcnQoZSk7CiAgICAgICAgcmV0dXJuIC1lLmVycm5vCiAgICAgIH0KICAgIH0KICAgIGZ1bmN0aW9uIF9fX3N5c2NhbGwxOTgod2hpY2gsIHZhcmFyZ3MpIHsKICAgICAgU1lTQ0FMTFMudmFyYXJncyA9IHZhcmFyZ3M7CiAgICAgIHRyeSB7CiAgICAgICAgdmFyIHBhdGggPSBTWVNDQUxMUy5nZXRTdHIoKSwKICAgICAgICAgIG93bmVyID0gU1lTQ0FMTFMuZ2V0KCksCiAgICAgICAgICBncm91cCA9IFNZU0NBTExTLmdldCgpOwogICAgICAgIEZTLmNob3duKHBhdGgsIG93bmVyLCBncm91cCk7CiAgICAgICAgcmV0dXJuIDAKICAgICAgfSBjYXRjaCAoZSkgewogICAgICAgIGlmICh0eXBlb2YgRlMgPT09ICd1bmRlZmluZWQnIHx8ICEoZSBpbnN0YW5jZW9mIEZTLkVycm5vRXJyb3IpKSBhYm9ydChlKTsKICAgICAgICByZXR1cm4gLWUuZXJybm8KICAgICAgfQogICAgfQogICAgdmFyIFBST0NJTkZPID0geyBwcGlkOiAxLCBwaWQ6IDQyLCBzaWQ6IDQyLCBwZ2lkOiA0MiB9OwogICAgZnVuY3Rpb24gX19fc3lzY2FsbDIwKHdoaWNoLCB2YXJhcmdzKSB7CiAgICAgIFNZU0NBTExTLnZhcmFyZ3MgPSB2YXJhcmdzOwogICAgICB0cnkgewogICAgICAgIHJldHVybiBQUk9DSU5GTy5waWQKICAgICAgfSBjYXRjaCAoZSkgewogICAgICAgIGlmICh0eXBlb2YgRlMgPT09ICd1bmRlZmluZWQnIHx8ICEoZSBpbnN0YW5jZW9mIEZTLkVycm5vRXJyb3IpKSBhYm9ydChlKTsKICAgICAgICByZXR1cm4gLWUuZXJybm8KICAgICAgfQogICAgfQogICAgZnVuY3Rpb24gX19fc3lzY2FsbDYod2hpY2gsIHZhcmFyZ3MpIHsKICAgICAgU1lTQ0FMTFMudmFyYXJncyA9IHZhcmFyZ3M7CiAgICAgIHRyeSB7CiAgICAgICAgdmFyIHN0cmVhbSA9IFNZU0NBTExTLmdldFN0cmVhbUZyb21GRCgpOwogICAgICAgIEZTLmNsb3NlKHN0cmVhbSk7CiAgICAgICAgcmV0dXJuIDAKICAgICAgfSBjYXRjaCAoZSkgewogICAgICAgIGlmICh0eXBlb2YgRlMgPT09ICd1bmRlZmluZWQnIHx8ICEoZSBpbnN0YW5jZW9mIEZTLkVycm5vRXJyb3IpKSBhYm9ydChlKTsKICAgICAgICByZXR1cm4gLWUuZXJybm8KICAgICAgfQogICAgfQogICAgZnVuY3Rpb24gX19fc3lzY2FsbDYwKHdoaWNoLCB2YXJhcmdzKSB7CiAgICAgIFNZU0NBTExTLnZhcmFyZ3MgPSB2YXJhcmdzOwogICAgICB0cnkgewogICAgICAgIHZhciBtYXNrID0gU1lTQ0FMTFMuZ2V0KCk7CiAgICAgICAgdmFyIG9sZCA9IFNZU0NBTExTLnVtYXNrOwogICAgICAgIFNZU0NBTExTLnVtYXNrID0gbWFzazsKICAgICAgICByZXR1cm4gb2xkCiAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICBpZiAodHlwZW9mIEZTID09PSAndW5kZWZpbmVkJyB8fCAhKGUgaW5zdGFuY2VvZiBGUy5FcnJub0Vycm9yKSkgYWJvcnQoZSk7CiAgICAgICAgcmV0dXJuIC1lLmVycm5vCiAgICAgIH0KICAgIH0KICAgIGZ1bmN0aW9uIF9fX3N5c2NhbGw4Myh3aGljaCwgdmFyYXJncykgewogICAgICBTWVNDQUxMUy52YXJhcmdzID0gdmFyYXJnczsKICAgICAgdHJ5IHsKICAgICAgICB2YXIgdGFyZ2V0ID0gU1lTQ0FMTFMuZ2V0U3RyKCksCiAgICAgICAgICBsaW5rcGF0aCA9IFNZU0NBTExTLmdldFN0cigpOwogICAgICAgIEZTLnN5bWxpbmsodGFyZ2V0LCBsaW5rcGF0aCk7CiAgICAgICAgcmV0dXJuIDAKICAgICAgfSBjYXRjaCAoZSkgewogICAgICAgIGlmICh0eXBlb2YgRlMgPT09ICd1bmRlZmluZWQnIHx8ICEoZSBpbnN0YW5jZW9mIEZTLkVycm5vRXJyb3IpKSBhYm9ydChlKTsKICAgICAgICByZXR1cm4gLWUuZXJybm8KICAgICAgfQogICAgfQogICAgZnVuY3Rpb24gX19fc3lzY2FsbDkxKHdoaWNoLCB2YXJhcmdzKSB7CiAgICAgIFNZU0NBTExTLnZhcmFyZ3MgPSB2YXJhcmdzOwogICAgICB0cnkgewogICAgICAgIHZhciBhZGRyID0gU1lTQ0FMTFMuZ2V0KCksCiAgICAgICAgICBsZW4gPSBTWVNDQUxMUy5nZXQoKTsKICAgICAgICB2YXIgaW5mbyA9IFNZU0NBTExTLm1hcHBpbmdzW2FkZHJdOwogICAgICAgIGlmICghaW5mbykgcmV0dXJuIDAKICAgICAgICBpZiAobGVuID09PSBpbmZvLmxlbikgewogICAgICAgICAgdmFyIHN0cmVhbSA9IEZTLmdldFN0cmVhbShpbmZvLmZkKTsKICAgICAgICAgIFNZU0NBTExTLmRvTXN5bmMoYWRkciwgc3RyZWFtLCBsZW4sIGluZm8uZmxhZ3MpOwogICAgICAgICAgRlMubXVubWFwKHN0cmVhbSk7CiAgICAgICAgICBTWVNDQUxMUy5tYXBwaW5nc1thZGRyXSA9IG51bGw7CiAgICAgICAgICBpZiAoaW5mby5hbGxvY2F0ZWQpIHsKICAgICAgICAgICAgX2ZyZWUoaW5mby5tYWxsb2MpOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZXR1cm4gMAogICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgaWYgKHR5cGVvZiBGUyA9PT0gJ3VuZGVmaW5lZCcgfHwgIShlIGluc3RhbmNlb2YgRlMuRXJybm9FcnJvcikpIGFib3J0KGUpOwogICAgICAgIHJldHVybiAtZS5lcnJubwogICAgICB9CiAgICB9CiAgICBmdW5jdGlvbiBfX191bmxvY2soKSB7fQogICAgdmFyIHN0cnVjdFJlZ2lzdHJhdGlvbnMgPSB7fTsKICAgIGZ1bmN0aW9uIHJ1bkRlc3RydWN0b3JzKGRlc3RydWN0b3JzKSB7CiAgICAgIHdoaWxlIChkZXN0cnVjdG9ycy5sZW5ndGgpIHsKICAgICAgICB2YXIgcHRyID0gZGVzdHJ1Y3RvcnMucG9wKCk7CiAgICAgICAgdmFyIGRlbCA9IGRlc3RydWN0b3JzLnBvcCgpOwogICAgICAgIGRlbChwdHIpOwogICAgICB9CiAgICB9CiAgICBmdW5jdGlvbiBzaW1wbGVSZWFkVmFsdWVGcm9tUG9pbnRlcihwb2ludGVyKSB7CiAgICAgIHJldHVybiB0aGlzWydmcm9tV2lyZVR5cGUnXShIRUFQVTMyW3BvaW50ZXIgPj4gMl0pCiAgICB9CiAgICB2YXIgYXdhaXRpbmdEZXBlbmRlbmNpZXMgPSB7fTsKICAgIHZhciByZWdpc3RlcmVkVHlwZXMgPSB7fTsKICAgIHZhciB0eXBlRGVwZW5kZW5jaWVzID0ge307CiAgICB2YXIgY2hhcl8wID0gNDg7CiAgICB2YXIgY2hhcl85ID0gNTc7CiAgICBmdW5jdGlvbiBtYWtlTGVnYWxGdW5jdGlvbk5hbWUobmFtZSkgewogICAgICBpZiAodW5kZWZpbmVkID09PSBuYW1lKSB7CiAgICAgICAgcmV0dXJuICdfdW5rbm93bicKICAgICAgfQogICAgICBuYW1lID0gbmFtZS5yZXBsYWNlKC9bXmEtekEtWjAtOV9dL2csICckJyk7CiAgICAgIHZhciBmID0gbmFtZS5jaGFyQ29kZUF0KDApOwogICAgICBpZiAoZiA+PSBjaGFyXzAgJiYgZiA8PSBjaGFyXzkpIHsKICAgICAgICByZXR1cm4gJ18nICsgbmFtZQogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBuYW1lCiAgICAgIH0KICAgIH0KICAgIGZ1bmN0aW9uIGNyZWF0ZU5hbWVkRnVuY3Rpb24obmFtZSwgYm9keSkgewogICAgICBuYW1lID0gbWFrZUxlZ2FsRnVuY3Rpb25OYW1lKG5hbWUpOwogICAgICByZXR1cm4gbmV3IEZ1bmN0aW9uKAogICAgICAgICdib2R5JywKICAgICAgICAncmV0dXJuIGZ1bmN0aW9uICcgKyBuYW1lICsgJygpIHtcbicgKyAnICAgICJ1c2Ugc3RyaWN0IjsnICsgJyAgICByZXR1cm4gYm9keS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuJyArICd9O1xuJwogICAgICApKGJvZHkpCiAgICB9CiAgICBmdW5jdGlvbiBleHRlbmRFcnJvcihiYXNlRXJyb3JUeXBlLCBlcnJvck5hbWUpIHsKICAgICAgdmFyIGVycm9yQ2xhc3MgPSBjcmVhdGVOYW1lZEZ1bmN0aW9uKGVycm9yTmFtZSwgZnVuY3Rpb24gKG1lc3NhZ2UpIHsKICAgICAgICB0aGlzLm5hbWUgPSBlcnJvck5hbWU7CiAgICAgICAgdGhpcy5tZXNzYWdlID0gbWVzc2FnZTsKICAgICAgICB2YXIgc3RhY2sgPSBuZXcgRXJyb3IobWVzc2FnZSkuc3RhY2s7CiAgICAgICAgaWYgKHN0YWNrICE9PSB1bmRlZmluZWQpIHsKICAgICAgICAgIHRoaXMuc3RhY2sgPSB0aGlzLnRvU3RyaW5nKCkgKyAnXG4nICsgc3RhY2sucmVwbGFjZSgvXkVycm9yKDpbXlxuXSopP1xuLywgJycpOwogICAgICAgIH0KICAgICAgfSk7CiAgICAgIGVycm9yQ2xhc3MucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShiYXNlRXJyb3JUeXBlLnByb3RvdHlwZSk7CiAgICAgIGVycm9yQ2xhc3MucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gZXJyb3JDbGFzczsKICAgICAgZXJyb3JDbGFzcy5wcm90b3R5cGUudG9TdHJpbmcgPSBmdW5jdGlvbiAoKSB7CiAgICAgICAgaWYgKHRoaXMubWVzc2FnZSA9PT0gdW5kZWZpbmVkKSB7CiAgICAgICAgICByZXR1cm4gdGhpcy5uYW1lCiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIHJldHVybiB0aGlzLm5hbWUgKyAnOiAnICsgdGhpcy5tZXNzYWdlCiAgICAgICAgfQogICAgICB9OwogICAgICByZXR1cm4gZXJyb3JDbGFzcwogICAgfQogICAgdmFyIEludGVybmFsRXJyb3IgPSB1bmRlZmluZWQ7CiAgICBmdW5jdGlvbiB0aHJvd0ludGVybmFsRXJyb3IobWVzc2FnZSkgewogICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihtZXNzYWdlKQogICAgfQogICAgZnVuY3Rpb24gd2hlbkRlcGVuZGVudFR5cGVzQXJlUmVzb2x2ZWQobXlUeXBlcywgZGVwZW5kZW50VHlwZXMsIGdldFR5cGVDb252ZXJ0ZXJzKSB7CiAgICAgIG15VHlwZXMuZm9yRWFjaChmdW5jdGlvbiAodHlwZSkgewogICAgICAgIHR5cGVEZXBlbmRlbmNpZXNbdHlwZV0gPSBkZXBlbmRlbnRUeXBlczsKICAgICAgfSk7CiAgICAgIGZ1bmN0aW9uIG9uQ29tcGxldGUodHlwZUNvbnZlcnRlcnMpIHsKICAgICAgICB2YXIgbXlUeXBlQ29udmVydGVycyA9IGdldFR5cGVDb252ZXJ0ZXJzKHR5cGVDb252ZXJ0ZXJzKTsKICAgICAgICBpZiAobXlUeXBlQ29udmVydGVycy5sZW5ndGggIT09IG15VHlwZXMubGVuZ3RoKSB7CiAgICAgICAgICB0aHJvd0ludGVybmFsRXJyb3IoJ01pc21hdGNoZWQgdHlwZSBjb252ZXJ0ZXIgY291bnQnKTsKICAgICAgICB9CiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBteVR5cGVzLmxlbmd0aDsgKytpKSB7CiAgICAgICAgICByZWdpc3RlclR5cGUobXlUeXBlc1tpXSwgbXlUeXBlQ29udmVydGVyc1tpXSk7CiAgICAgICAgfQogICAgICB9CiAgICAgIHZhciB0eXBlQ29udmVydGVycyA9IG5ldyBBcnJheShkZXBlbmRlbnRUeXBlcy5sZW5ndGgpOwogICAgICB2YXIgdW5yZWdpc3RlcmVkVHlwZXMgPSBbXTsKICAgICAgdmFyIHJlZ2lzdGVyZWQgPSAwOwogICAgICBkZXBlbmRlbnRUeXBlcy5mb3JFYWNoKGZ1bmN0aW9uIChkdCwgaSkgewogICAgICAgIGlmIChyZWdpc3RlcmVkVHlwZXMuaGFzT3duUHJvcGVydHkoZHQpKSB7CiAgICAgICAgICB0eXBlQ29udmVydGVyc1tpXSA9IHJlZ2lzdGVyZWRUeXBlc1tkdF07CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIHVucmVnaXN0ZXJlZFR5cGVzLnB1c2goZHQpOwogICAgICAgICAgaWYgKCFhd2FpdGluZ0RlcGVuZGVuY2llcy5oYXNPd25Qcm9wZXJ0eShkdCkpIHsKICAgICAgICAgICAgYXdhaXRpbmdEZXBlbmRlbmNpZXNbZHRdID0gW107CiAgICAgICAgICB9CiAgICAgICAgICBhd2FpdGluZ0RlcGVuZGVuY2llc1tkdF0ucHVzaChmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgIHR5cGVDb252ZXJ0ZXJzW2ldID0gcmVnaXN0ZXJlZFR5cGVzW2R0XTsKICAgICAgICAgICAgKytyZWdpc3RlcmVkOwogICAgICAgICAgICBpZiAocmVnaXN0ZXJlZCA9PT0gdW5yZWdpc3RlcmVkVHlwZXMubGVuZ3RoKSB7CiAgICAgICAgICAgICAgb25Db21wbGV0ZSh0eXBlQ29udmVydGVycyk7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0pOwogICAgICAgIH0KICAgICAgfSk7CiAgICAgIGlmICgwID09PSB1bnJlZ2lzdGVyZWRUeXBlcy5sZW5ndGgpIHsKICAgICAgICBvbkNvbXBsZXRlKHR5cGVDb252ZXJ0ZXJzKTsKICAgICAgfQogICAgfQogICAgZnVuY3Rpb24gX19lbWJpbmRfZmluYWxpemVfdmFsdWVfb2JqZWN0KHN0cnVjdFR5cGUpIHsKICAgICAgdmFyIHJlZyA9IHN0cnVjdFJlZ2lzdHJhdGlvbnNbc3RydWN0VHlwZV07CiAgICAgIGRlbGV0ZSBzdHJ1Y3RSZWdpc3RyYXRpb25zW3N0cnVjdFR5cGVdOwogICAgICB2YXIgcmF3Q29uc3RydWN0b3IgPSByZWcucmF3Q29uc3RydWN0b3I7CiAgICAgIHZhciByYXdEZXN0cnVjdG9yID0gcmVnLnJhd0Rlc3RydWN0b3I7CiAgICAgIHZhciBmaWVsZFJlY29yZHMgPSByZWcuZmllbGRzOwogICAgICB2YXIgZmllbGRUeXBlcyA9IGZpZWxkUmVjb3JkcwogICAgICAgIC5tYXAoZnVuY3Rpb24gKGZpZWxkKSB7CiAgICAgICAgICByZXR1cm4gZmllbGQuZ2V0dGVyUmV0dXJuVHlwZQogICAgICAgIH0pCiAgICAgICAgLmNvbmNhdCgKICAgICAgICAgIGZpZWxkUmVjb3Jkcy5tYXAoZnVuY3Rpb24gKGZpZWxkKSB7CiAgICAgICAgICAgIHJldHVybiBmaWVsZC5zZXR0ZXJBcmd1bWVudFR5cGUKICAgICAgICAgIH0pCiAgICAgICAgKTsKICAgICAgd2hlbkRlcGVuZGVudFR5cGVzQXJlUmVzb2x2ZWQoW3N0cnVjdFR5cGVdLCBmaWVsZFR5cGVzLCBmdW5jdGlvbiAoZmllbGRUeXBlcykgewogICAgICAgIHZhciBmaWVsZHMgPSB7fTsKICAgICAgICBmaWVsZFJlY29yZHMuZm9yRWFjaChmdW5jdGlvbiAoZmllbGQsIGkpIHsKICAgICAgICAgIHZhciBmaWVsZE5hbWUgPSBmaWVsZC5maWVsZE5hbWU7CiAgICAgICAgICB2YXIgZ2V0dGVyUmV0dXJuVHlwZSA9IGZpZWxkVHlwZXNbaV07CiAgICAgICAgICB2YXIgZ2V0dGVyID0gZmllbGQuZ2V0dGVyOwogICAgICAgICAgdmFyIGdldHRlckNvbnRleHQgPSBmaWVsZC5nZXR0ZXJDb250ZXh0OwogICAgICAgICAgdmFyIHNldHRlckFyZ3VtZW50VHlwZSA9IGZpZWxkVHlwZXNbaSArIGZpZWxkUmVjb3Jkcy5sZW5ndGhdOwogICAgICAgICAgdmFyIHNldHRlciA9IGZpZWxkLnNldHRlcjsKICAgICAgICAgIHZhciBzZXR0ZXJDb250ZXh0ID0gZmllbGQuc2V0dGVyQ29udGV4dDsKICAgICAgICAgIGZpZWxkc1tmaWVsZE5hbWVdID0gewogICAgICAgICAgICByZWFkOiBmdW5jdGlvbiAocHRyKSB7CiAgICAgICAgICAgICAgcmV0dXJuIGdldHRlclJldHVyblR5cGVbJ2Zyb21XaXJlVHlwZSddKGdldHRlcihnZXR0ZXJDb250ZXh0LCBwdHIpKQogICAgICAgICAgICB9LAogICAgICAgICAgICB3cml0ZTogZnVuY3Rpb24gKHB0ciwgbykgewogICAgICAgICAgICAgIHZhciBkZXN0cnVjdG9ycyA9IFtdOwogICAgICAgICAgICAgIHNldHRlcihzZXR0ZXJDb250ZXh0LCBwdHIsIHNldHRlckFyZ3VtZW50VHlwZVsndG9XaXJlVHlwZSddKGRlc3RydWN0b3JzLCBvKSk7CiAgICAgICAgICAgICAgcnVuRGVzdHJ1Y3RvcnMoZGVzdHJ1Y3RvcnMpOwogICAgICAgICAgICB9LAogICAgICAgICAgfTsKICAgICAgICB9KTsKICAgICAgICByZXR1cm4gWwogICAgICAgICAgewogICAgICAgICAgICBuYW1lOiByZWcubmFtZSwKICAgICAgICAgICAgZnJvbVdpcmVUeXBlOiBmdW5jdGlvbiAocHRyKSB7CiAgICAgICAgICAgICAgdmFyIHJ2ID0ge307CiAgICAgICAgICAgICAgZm9yICh2YXIgaSBpbiBmaWVsZHMpIHsKICAgICAgICAgICAgICAgIHJ2W2ldID0gZmllbGRzW2ldLnJlYWQocHRyKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgcmF3RGVzdHJ1Y3RvcihwdHIpOwogICAgICAgICAgICAgIHJldHVybiBydgogICAgICAgICAgICB9LAogICAgICAgICAgICB0b1dpcmVUeXBlOiBmdW5jdGlvbiAoZGVzdHJ1Y3RvcnMsIG8pIHsKICAgICAgICAgICAgICBmb3IgKHZhciBmaWVsZE5hbWUgaW4gZmllbGRzKSB7CiAgICAgICAgICAgICAgICBpZiAoIShmaWVsZE5hbWUgaW4gbykpIHsKICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcignTWlzc2luZyBmaWVsZCcpCiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHZhciBwdHIgPSByYXdDb25zdHJ1Y3RvcigpOwogICAgICAgICAgICAgIGZvciAoZmllbGROYW1lIGluIGZpZWxkcykgewogICAgICAgICAgICAgICAgZmllbGRzW2ZpZWxkTmFtZV0ud3JpdGUocHRyLCBvW2ZpZWxkTmFtZV0pOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBpZiAoZGVzdHJ1Y3RvcnMgIT09IG51bGwpIHsKICAgICAgICAgICAgICAgIGRlc3RydWN0b3JzLnB1c2gocmF3RGVzdHJ1Y3RvciwgcHRyKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgcmV0dXJuIHB0cgogICAgICAgICAgICB9LAogICAgICAgICAgICBhcmdQYWNrQWR2YW5jZTogOCwKICAgICAgICAgICAgcmVhZFZhbHVlRnJvbVBvaW50ZXI6IHNpbXBsZVJlYWRWYWx1ZUZyb21Qb2ludGVyLAogICAgICAgICAgICBkZXN0cnVjdG9yRnVuY3Rpb246IHJhd0Rlc3RydWN0b3IsCiAgICAgICAgICB9LAogICAgICAgIF0KICAgICAgfSk7CiAgICB9CiAgICBmdW5jdGlvbiBnZXRTaGlmdEZyb21TaXplKHNpemUpIHsKICAgICAgc3dpdGNoIChzaXplKSB7CiAgICAgICAgY2FzZSAxOgogICAgICAgICAgcmV0dXJuIDAKICAgICAgICBjYXNlIDI6CiAgICAgICAgICByZXR1cm4gMQogICAgICAgIGNhc2UgNDoKICAgICAgICAgIHJldHVybiAyCiAgICAgICAgY2FzZSA4OgogICAgICAgICAgcmV0dXJuIDMKICAgICAgICBkZWZhdWx0OgogICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcignVW5rbm93biB0eXBlIHNpemU6ICcgKyBzaXplKQogICAgICB9CiAgICB9CiAgICBmdW5jdGlvbiBlbWJpbmRfaW5pdF9jaGFyQ29kZXMoKSB7CiAgICAgIHZhciBjb2RlcyA9IG5ldyBBcnJheSgyNTYpOwogICAgICBmb3IgKHZhciBpID0gMDsgaSA8IDI1NjsgKytpKSB7CiAgICAgICAgY29kZXNbaV0gPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGkpOwogICAgICB9CiAgICAgIGVtYmluZF9jaGFyQ29kZXMgPSBjb2RlczsKICAgIH0KICAgIHZhciBlbWJpbmRfY2hhckNvZGVzID0gdW5kZWZpbmVkOwogICAgZnVuY3Rpb24gcmVhZExhdGluMVN0cmluZyhwdHIpIHsKICAgICAgdmFyIHJldCA9ICcnOwogICAgICB2YXIgYyA9IHB0cjsKICAgICAgd2hpbGUgKEhFQVBVOFtjXSkgewogICAgICAgIHJldCArPSBlbWJpbmRfY2hhckNvZGVzW0hFQVBVOFtjKytdXTsKICAgICAgfQogICAgICByZXR1cm4gcmV0CiAgICB9CiAgICB2YXIgQmluZGluZ0Vycm9yID0gdW5kZWZpbmVkOwogICAgZnVuY3Rpb24gdGhyb3dCaW5kaW5nRXJyb3IobWVzc2FnZSkgewogICAgICB0aHJvdyBuZXcgQmluZGluZ0Vycm9yKG1lc3NhZ2UpCiAgICB9CiAgICBmdW5jdGlvbiByZWdpc3RlclR5cGUocmF3VHlwZSwgcmVnaXN0ZXJlZEluc3RhbmNlLCBvcHRpb25zKSB7CiAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9OwogICAgICBpZiAoISgnYXJnUGFja0FkdmFuY2UnIGluIHJlZ2lzdGVyZWRJbnN0YW5jZSkpIHsKICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdyZWdpc3RlclR5cGUgcmVnaXN0ZXJlZEluc3RhbmNlIHJlcXVpcmVzIGFyZ1BhY2tBZHZhbmNlJykKICAgICAgfQogICAgICB2YXIgbmFtZSA9IHJlZ2lzdGVyZWRJbnN0YW5jZS5uYW1lOwogICAgICBpZiAoIXJhd1R5cGUpIHsKICAgICAgICB0aHJvd0JpbmRpbmdFcnJvcigndHlwZSAiJyArIG5hbWUgKyAnIiBtdXN0IGhhdmUgYSBwb3NpdGl2ZSBpbnRlZ2VyIHR5cGVpZCBwb2ludGVyJyk7CiAgICAgIH0KICAgICAgaWYgKHJlZ2lzdGVyZWRUeXBlcy5oYXNPd25Qcm9wZXJ0eShyYXdUeXBlKSkgewogICAgICAgIGlmIChvcHRpb25zLmlnbm9yZUR1cGxpY2F0ZVJlZ2lzdHJhdGlvbnMpIHsKICAgICAgICAgIHJldHVybgogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICB0aHJvd0JpbmRpbmdFcnJvcigiQ2Fubm90IHJlZ2lzdGVyIHR5cGUgJyIgKyBuYW1lICsgIicgdHdpY2UiKTsKICAgICAgICB9CiAgICAgIH0KICAgICAgcmVnaXN0ZXJlZFR5cGVzW3Jhd1R5cGVdID0gcmVnaXN0ZXJlZEluc3RhbmNlOwogICAgICBkZWxldGUgdHlwZURlcGVuZGVuY2llc1tyYXdUeXBlXTsKICAgICAgaWYgKGF3YWl0aW5nRGVwZW5kZW5jaWVzLmhhc093blByb3BlcnR5KHJhd1R5cGUpKSB7CiAgICAgICAgdmFyIGNhbGxiYWNrcyA9IGF3YWl0aW5nRGVwZW5kZW5jaWVzW3Jhd1R5cGVdOwogICAgICAgIGRlbGV0ZSBhd2FpdGluZ0RlcGVuZGVuY2llc1tyYXdUeXBlXTsKICAgICAgICBjYWxsYmFja3MuZm9yRWFjaChmdW5jdGlvbiAoY2IpIHsKICAgICAgICAgIGNiKCk7CiAgICAgICAgfSk7CiAgICAgIH0KICAgIH0KICAgIGZ1bmN0aW9uIF9fZW1iaW5kX3JlZ2lzdGVyX2Jvb2wocmF3VHlwZSwgbmFtZSwgc2l6ZSwgdHJ1ZVZhbHVlLCBmYWxzZVZhbHVlKSB7CiAgICAgIHZhciBzaGlmdCA9IGdldFNoaWZ0RnJvbVNpemUoc2l6ZSk7CiAgICAgIG5hbWUgPSByZWFkTGF0aW4xU3RyaW5nKG5hbWUpOwogICAgICByZWdpc3RlclR5cGUocmF3VHlwZSwgewogICAgICAgIG5hbWU6IG5hbWUsCiAgICAgICAgZnJvbVdpcmVUeXBlOiBmdW5jdGlvbiAod3QpIHsKICAgICAgICAgIHJldHVybiAhIXd0CiAgICAgICAgfSwKICAgICAgICB0b1dpcmVUeXBlOiBmdW5jdGlvbiAoZGVzdHJ1Y3RvcnMsIG8pIHsKICAgICAgICAgIHJldHVybiBvID8gdHJ1ZVZhbHVlIDogZmFsc2VWYWx1ZQogICAgICAgIH0sCiAgICAgICAgYXJnUGFja0FkdmFuY2U6IDgsCiAgICAgICAgcmVhZFZhbHVlRnJvbVBvaW50ZXI6IGZ1bmN0aW9uIChwb2ludGVyKSB7CiAgICAgICAgICB2YXIgaGVhcDsKICAgICAgICAgIGlmIChzaXplID09PSAxKSB7CiAgICAgICAgICAgIGhlYXAgPSBIRUFQODsKICAgICAgICAgIH0gZWxzZSBpZiAoc2l6ZSA9PT0gMikgewogICAgICAgICAgICBoZWFwID0gSEVBUDE2OwogICAgICAgICAgfSBlbHNlIGlmIChzaXplID09PSA0KSB7CiAgICAgICAgICAgIGhlYXAgPSBIRUFQMzI7CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdVbmtub3duIGJvb2xlYW4gdHlwZSBzaXplOiAnICsgbmFtZSkKICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiB0aGlzWydmcm9tV2lyZVR5cGUnXShoZWFwW3BvaW50ZXIgPj4gc2hpZnRdKQogICAgICAgIH0sCiAgICAgICAgZGVzdHJ1Y3RvckZ1bmN0aW9uOiBudWxsLAogICAgICB9KTsKICAgIH0KICAgIGZ1bmN0aW9uIENsYXNzSGFuZGxlX2lzQWxpYXNPZihvdGhlcikgewogICAgICBpZiAoISh0aGlzIGluc3RhbmNlb2YgQ2xhc3NIYW5kbGUpKSB7CiAgICAgICAgcmV0dXJuIGZhbHNlCiAgICAgIH0KICAgICAgaWYgKCEob3RoZXIgaW5zdGFuY2VvZiBDbGFzc0hhbmRsZSkpIHsKICAgICAgICByZXR1cm4gZmFsc2UKICAgICAgfQogICAgICB2YXIgbGVmdENsYXNzID0gdGhpcy4kJC5wdHJUeXBlLnJlZ2lzdGVyZWRDbGFzczsKICAgICAgdmFyIGxlZnQgPSB0aGlzLiQkLnB0cjsKICAgICAgdmFyIHJpZ2h0Q2xhc3MgPSBvdGhlci4kJC5wdHJUeXBlLnJlZ2lzdGVyZWRDbGFzczsKICAgICAgdmFyIHJpZ2h0ID0gb3RoZXIuJCQucHRyOwogICAgICB3aGlsZSAobGVmdENsYXNzLmJhc2VDbGFzcykgewogICAgICAgIGxlZnQgPSBsZWZ0Q2xhc3MudXBjYXN0KGxlZnQpOwogICAgICAgIGxlZnRDbGFzcyA9IGxlZnRDbGFzcy5iYXNlQ2xhc3M7CiAgICAgIH0KICAgICAgd2hpbGUgKHJpZ2h0Q2xhc3MuYmFzZUNsYXNzKSB7CiAgICAgICAgcmlnaHQgPSByaWdodENsYXNzLnVwY2FzdChyaWdodCk7CiAgICAgICAgcmlnaHRDbGFzcyA9IHJpZ2h0Q2xhc3MuYmFzZUNsYXNzOwogICAgICB9CiAgICAgIHJldHVybiBsZWZ0Q2xhc3MgPT09IHJpZ2h0Q2xhc3MgJiYgbGVmdCA9PT0gcmlnaHQKICAgIH0KICAgIGZ1bmN0aW9uIHNoYWxsb3dDb3B5SW50ZXJuYWxQb2ludGVyKG8pIHsKICAgICAgcmV0dXJuIHsKICAgICAgICBjb3VudDogby5jb3VudCwKICAgICAgICBkZWxldGVTY2hlZHVsZWQ6IG8uZGVsZXRlU2NoZWR1bGVkLAogICAgICAgIHByZXNlcnZlUG9pbnRlck9uRGVsZXRlOiBvLnByZXNlcnZlUG9pbnRlck9uRGVsZXRlLAogICAgICAgIHB0cjogby5wdHIsCiAgICAgICAgcHRyVHlwZTogby5wdHJUeXBlLAogICAgICAgIHNtYXJ0UHRyOiBvLnNtYXJ0UHRyLAogICAgICAgIHNtYXJ0UHRyVHlwZTogby5zbWFydFB0clR5cGUsCiAgICAgIH0KICAgIH0KICAgIGZ1bmN0aW9uIHRocm93SW5zdGFuY2VBbHJlYWR5RGVsZXRlZChvYmopIHsKICAgICAgZnVuY3Rpb24gZ2V0SW5zdGFuY2VUeXBlTmFtZShoYW5kbGUpIHsKICAgICAgICByZXR1cm4gaGFuZGxlLiQkLnB0clR5cGUucmVnaXN0ZXJlZENsYXNzLm5hbWUKICAgICAgfQogICAgICB0aHJvd0JpbmRpbmdFcnJvcihnZXRJbnN0YW5jZVR5cGVOYW1lKG9iaikgKyAnIGluc3RhbmNlIGFscmVhZHkgZGVsZXRlZCcpOwogICAgfQogICAgZnVuY3Rpb24gQ2xhc3NIYW5kbGVfY2xvbmUoKSB7CiAgICAgIGlmICghdGhpcy4kJC5wdHIpIHsKICAgICAgICB0aHJvd0luc3RhbmNlQWxyZWFkeURlbGV0ZWQodGhpcyk7CiAgICAgIH0KICAgICAgaWYgKHRoaXMuJCQucHJlc2VydmVQb2ludGVyT25EZWxldGUpIHsKICAgICAgICB0aGlzLiQkLmNvdW50LnZhbHVlICs9IDE7CiAgICAgICAgcmV0dXJuIHRoaXMKICAgICAgfSBlbHNlIHsKICAgICAgICB2YXIgY2xvbmUgPSBPYmplY3QuY3JlYXRlKE9iamVjdC5nZXRQcm90b3R5cGVPZih0aGlzKSwgeyAkJDogeyB2YWx1ZTogc2hhbGxvd0NvcHlJbnRlcm5hbFBvaW50ZXIodGhpcy4kJCkgfSB9KTsKICAgICAgICBjbG9uZS4kJC5jb3VudC52YWx1ZSArPSAxOwogICAgICAgIGNsb25lLiQkLmRlbGV0ZVNjaGVkdWxlZCA9IGZhbHNlOwogICAgICAgIHJldHVybiBjbG9uZQogICAgICB9CiAgICB9CiAgICBmdW5jdGlvbiBydW5EZXN0cnVjdG9yKGhhbmRsZSkgewogICAgICB2YXIgJCQgPSBoYW5kbGUuJCQ7CiAgICAgIGlmICgkJC5zbWFydFB0cikgewogICAgICAgICQkLnNtYXJ0UHRyVHlwZS5yYXdEZXN0cnVjdG9yKCQkLnNtYXJ0UHRyKTsKICAgICAgfSBlbHNlIHsKICAgICAgICAkJC5wdHJUeXBlLnJlZ2lzdGVyZWRDbGFzcy5yYXdEZXN0cnVjdG9yKCQkLnB0cik7CiAgICAgIH0KICAgIH0KICAgIGZ1bmN0aW9uIENsYXNzSGFuZGxlX2RlbGV0ZSgpIHsKICAgICAgaWYgKCF0aGlzLiQkLnB0cikgewogICAgICAgIHRocm93SW5zdGFuY2VBbHJlYWR5RGVsZXRlZCh0aGlzKTsKICAgICAgfQogICAgICBpZiAodGhpcy4kJC5kZWxldGVTY2hlZHVsZWQgJiYgIXRoaXMuJCQucHJlc2VydmVQb2ludGVyT25EZWxldGUpIHsKICAgICAgICB0aHJvd0JpbmRpbmdFcnJvcignT2JqZWN0IGFscmVhZHkgc2NoZWR1bGVkIGZvciBkZWxldGlvbicpOwogICAgICB9CiAgICAgIHRoaXMuJCQuY291bnQudmFsdWUgLT0gMTsKICAgICAgdmFyIHRvRGVsZXRlID0gMCA9PT0gdGhpcy4kJC5jb3VudC52YWx1ZTsKICAgICAgaWYgKHRvRGVsZXRlKSB7CiAgICAgICAgcnVuRGVzdHJ1Y3Rvcih0aGlzKTsKICAgICAgfQogICAgICBpZiAoIXRoaXMuJCQucHJlc2VydmVQb2ludGVyT25EZWxldGUpIHsKICAgICAgICB0aGlzLiQkLnNtYXJ0UHRyID0gdW5kZWZpbmVkOwogICAgICAgIHRoaXMuJCQucHRyID0gdW5kZWZpbmVkOwogICAgICB9CiAgICB9CiAgICBmdW5jdGlvbiBDbGFzc0hhbmRsZV9pc0RlbGV0ZWQoKSB7CiAgICAgIHJldHVybiAhdGhpcy4kJC5wdHIKICAgIH0KICAgIHZhciBkZWxheUZ1bmN0aW9uID0gdW5kZWZpbmVkOwogICAgdmFyIGRlbGV0aW9uUXVldWUgPSBbXTsKICAgIGZ1bmN0aW9uIGZsdXNoUGVuZGluZ0RlbGV0ZXMoKSB7CiAgICAgIHdoaWxlIChkZWxldGlvblF1ZXVlLmxlbmd0aCkgewogICAgICAgIHZhciBvYmogPSBkZWxldGlvblF1ZXVlLnBvcCgpOwogICAgICAgIG9iai4kJC5kZWxldGVTY2hlZHVsZWQgPSBmYWxzZTsKICAgICAgICBvYmpbJ2RlbGV0ZSddKCk7CiAgICAgIH0KICAgIH0KICAgIGZ1bmN0aW9uIENsYXNzSGFuZGxlX2RlbGV0ZUxhdGVyKCkgewogICAgICBpZiAoIXRoaXMuJCQucHRyKSB7CiAgICAgICAgdGhyb3dJbnN0YW5jZUFscmVhZHlEZWxldGVkKHRoaXMpOwogICAgICB9CiAgICAgIGlmICh0aGlzLiQkLmRlbGV0ZVNjaGVkdWxlZCAmJiAhdGhpcy4kJC5wcmVzZXJ2ZVBvaW50ZXJPbkRlbGV0ZSkgewogICAgICAgIHRocm93QmluZGluZ0Vycm9yKCdPYmplY3QgYWxyZWFkeSBzY2hlZHVsZWQgZm9yIGRlbGV0aW9uJyk7CiAgICAgIH0KICAgICAgZGVsZXRpb25RdWV1ZS5wdXNoKHRoaXMpOwogICAgICBpZiAoZGVsZXRpb25RdWV1ZS5sZW5ndGggPT09IDEgJiYgZGVsYXlGdW5jdGlvbikgewogICAgICAgIGRlbGF5RnVuY3Rpb24oZmx1c2hQZW5kaW5nRGVsZXRlcyk7CiAgICAgIH0KICAgICAgdGhpcy4kJC5kZWxldGVTY2hlZHVsZWQgPSB0cnVlOwogICAgICByZXR1cm4gdGhpcwogICAgfQogICAgZnVuY3Rpb24gaW5pdF9DbGFzc0hhbmRsZSgpIHsKICAgICAgQ2xhc3NIYW5kbGUucHJvdG90eXBlWydpc0FsaWFzT2YnXSA9IENsYXNzSGFuZGxlX2lzQWxpYXNPZjsKICAgICAgQ2xhc3NIYW5kbGUucHJvdG90eXBlWydjbG9uZSddID0gQ2xhc3NIYW5kbGVfY2xvbmU7CiAgICAgIENsYXNzSGFuZGxlLnByb3RvdHlwZVsnZGVsZXRlJ10gPSBDbGFzc0hhbmRsZV9kZWxldGU7CiAgICAgIENsYXNzSGFuZGxlLnByb3RvdHlwZVsnaXNEZWxldGVkJ10gPSBDbGFzc0hhbmRsZV9pc0RlbGV0ZWQ7CiAgICAgIENsYXNzSGFuZGxlLnByb3RvdHlwZVsnZGVsZXRlTGF0ZXInXSA9IENsYXNzSGFuZGxlX2RlbGV0ZUxhdGVyOwogICAgfQogICAgZnVuY3Rpb24gQ2xhc3NIYW5kbGUoKSB7fQogICAgdmFyIHJlZ2lzdGVyZWRQb2ludGVycyA9IHt9OwogICAgZnVuY3Rpb24gZW5zdXJlT3ZlcmxvYWRUYWJsZShwcm90bywgbWV0aG9kTmFtZSwgaHVtYW5OYW1lKSB7CiAgICAgIGlmICh1bmRlZmluZWQgPT09IHByb3RvW21ldGhvZE5hbWVdLm92ZXJsb2FkVGFibGUpIHsKICAgICAgICB2YXIgcHJldkZ1bmMgPSBwcm90b1ttZXRob2ROYW1lXTsKICAgICAgICBwcm90b1ttZXRob2ROYW1lXSA9IGZ1bmN0aW9uICgpIHsKICAgICAgICAgIGlmICghcHJvdG9bbWV0aG9kTmFtZV0ub3ZlcmxvYWRUYWJsZS5oYXNPd25Qcm9wZXJ0eShhcmd1bWVudHMubGVuZ3RoKSkgewogICAgICAgICAgICB0aHJvd0JpbmRpbmdFcnJvcigKICAgICAgICAgICAgICAiRnVuY3Rpb24gJyIgKwogICAgICAgICAgICAgICAgaHVtYW5OYW1lICsKICAgICAgICAgICAgICAgICInIGNhbGxlZCB3aXRoIGFuIGludmFsaWQgbnVtYmVyIG9mIGFyZ3VtZW50cyAoIiArCiAgICAgICAgICAgICAgICBhcmd1bWVudHMubGVuZ3RoICsKICAgICAgICAgICAgICAgICcpIC0gZXhwZWN0cyBvbmUgb2YgKCcgKwogICAgICAgICAgICAgICAgcHJvdG9bbWV0aG9kTmFtZV0ub3ZlcmxvYWRUYWJsZSArCiAgICAgICAgICAgICAgICAnKSEnCiAgICAgICAgICAgICk7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gcHJvdG9bbWV0aG9kTmFtZV0ub3ZlcmxvYWRUYWJsZVthcmd1bWVudHMubGVuZ3RoXS5hcHBseSh0aGlzLCBhcmd1bWVudHMpCiAgICAgICAgfTsKICAgICAgICBwcm90b1ttZXRob2ROYW1lXS5vdmVybG9hZFRhYmxlID0gW107CiAgICAgICAgcHJvdG9bbWV0aG9kTmFtZV0ub3ZlcmxvYWRUYWJsZVtwcmV2RnVuYy5hcmdDb3VudF0gPSBwcmV2RnVuYzsKICAgICAgfQogICAgfQogICAgZnVuY3Rpb24gZXhwb3NlUHVibGljU3ltYm9sKG5hbWUsIHZhbHVlLCBudW1Bcmd1bWVudHMpIHsKICAgICAgaWYgKE1vZHVsZS5oYXNPd25Qcm9wZXJ0eShuYW1lKSkgewogICAgICAgIGlmICgKICAgICAgICAgIHVuZGVmaW5lZCA9PT0gbnVtQXJndW1lbnRzIHx8CiAgICAgICAgICAodW5kZWZpbmVkICE9PSBNb2R1bGVbbmFtZV0ub3ZlcmxvYWRUYWJsZSAmJiB1bmRlZmluZWQgIT09IE1vZHVsZVtuYW1lXS5vdmVybG9hZFRhYmxlW251bUFyZ3VtZW50c10pCiAgICAgICAgKSB7CiAgICAgICAgICB0aHJvd0JpbmRpbmdFcnJvcigiQ2Fubm90IHJlZ2lzdGVyIHB1YmxpYyBuYW1lICciICsgbmFtZSArICInIHR3aWNlIik7CiAgICAgICAgfQogICAgICAgIGVuc3VyZU92ZXJsb2FkVGFibGUoTW9kdWxlLCBuYW1lLCBuYW1lKTsKICAgICAgICBpZiAoTW9kdWxlLmhhc093blByb3BlcnR5KG51bUFyZ3VtZW50cykpIHsKICAgICAgICAgIHRocm93QmluZGluZ0Vycm9yKAogICAgICAgICAgICAnQ2Fubm90IHJlZ2lzdGVyIG11bHRpcGxlIG92ZXJsb2FkcyBvZiBhIGZ1bmN0aW9uIHdpdGggdGhlIHNhbWUgbnVtYmVyIG9mIGFyZ3VtZW50cyAoJyArIG51bUFyZ3VtZW50cyArICcpIScKICAgICAgICAgICk7CiAgICAgICAgfQogICAgICAgIE1vZHVsZVtuYW1lXS5vdmVybG9hZFRhYmxlW251bUFyZ3VtZW50c10gPSB2YWx1ZTsKICAgICAgfSBlbHNlIHsKICAgICAgICBNb2R1bGVbbmFtZV0gPSB2YWx1ZTsKICAgICAgICBpZiAodW5kZWZpbmVkICE9PSBudW1Bcmd1bWVudHMpIHsKICAgICAgICAgIE1vZHVsZVtuYW1lXS5udW1Bcmd1bWVudHMgPSBudW1Bcmd1bWVudHM7CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgICBmdW5jdGlvbiBSZWdpc3RlcmVkQ2xhc3MoCiAgICAgIG5hbWUsCiAgICAgIGNvbnN0cnVjdG9yLAogICAgICBpbnN0YW5jZVByb3RvdHlwZSwKICAgICAgcmF3RGVzdHJ1Y3RvciwKICAgICAgYmFzZUNsYXNzLAogICAgICBnZXRBY3R1YWxUeXBlLAogICAgICB1cGNhc3QsCiAgICAgIGRvd25jYXN0CiAgICApIHsKICAgICAgdGhpcy5uYW1lID0gbmFtZTsKICAgICAgdGhpcy5jb25zdHJ1Y3RvciA9IGNvbnN0cnVjdG9yOwogICAgICB0aGlzLmluc3RhbmNlUHJvdG90eXBlID0gaW5zdGFuY2VQcm90b3R5cGU7CiAgICAgIHRoaXMucmF3RGVzdHJ1Y3RvciA9IHJhd0Rlc3RydWN0b3I7CiAgICAgIHRoaXMuYmFzZUNsYXNzID0gYmFzZUNsYXNzOwogICAgICB0aGlzLmdldEFjdHVhbFR5cGUgPSBnZXRBY3R1YWxUeXBlOwogICAgICB0aGlzLnVwY2FzdCA9IHVwY2FzdDsKICAgICAgdGhpcy5kb3duY2FzdCA9IGRvd25jYXN0OwogICAgICB0aGlzLnB1cmVWaXJ0dWFsRnVuY3Rpb25zID0gW107CiAgICB9CiAgICBmdW5jdGlvbiB1cGNhc3RQb2ludGVyKHB0ciwgcHRyQ2xhc3MsIGRlc2lyZWRDbGFzcykgewogICAgICB3aGlsZSAocHRyQ2xhc3MgIT09IGRlc2lyZWRDbGFzcykgewogICAgICAgIGlmICghcHRyQ2xhc3MudXBjYXN0KSB7CiAgICAgICAgICB0aHJvd0JpbmRpbmdFcnJvcignRXhwZWN0ZWQgbnVsbCBvciBpbnN0YW5jZSBvZiAnICsgZGVzaXJlZENsYXNzLm5hbWUgKyAnLCBnb3QgYW4gaW5zdGFuY2Ugb2YgJyArIHB0ckNsYXNzLm5hbWUpOwogICAgICAgIH0KICAgICAgICBwdHIgPSBwdHJDbGFzcy51cGNhc3QocHRyKTsKICAgICAgICBwdHJDbGFzcyA9IHB0ckNsYXNzLmJhc2VDbGFzczsKICAgICAgfQogICAgICByZXR1cm4gcHRyCiAgICB9CiAgICBmdW5jdGlvbiBjb25zdE5vU21hcnRQdHJSYXdQb2ludGVyVG9XaXJlVHlwZShkZXN0cnVjdG9ycywgaGFuZGxlKSB7CiAgICAgIGlmIChoYW5kbGUgPT09IG51bGwpIHsKICAgICAgICBpZiAodGhpcy5pc1JlZmVyZW5jZSkgewogICAgICAgICAgdGhyb3dCaW5kaW5nRXJyb3IoJ251bGwgaXMgbm90IGEgdmFsaWQgJyArIHRoaXMubmFtZSk7CiAgICAgICAgfQogICAgICAgIHJldHVybiAwCiAgICAgIH0KICAgICAgaWYgKCFoYW5kbGUuJCQpIHsKICAgICAgICB0aHJvd0JpbmRpbmdFcnJvcignQ2Fubm90IHBhc3MgIicgKyBfZW1iaW5kX3JlcHIoaGFuZGxlKSArICciIGFzIGEgJyArIHRoaXMubmFtZSk7CiAgICAgIH0KICAgICAgaWYgKCFoYW5kbGUuJCQucHRyKSB7CiAgICAgICAgdGhyb3dCaW5kaW5nRXJyb3IoJ0Nhbm5vdCBwYXNzIGRlbGV0ZWQgb2JqZWN0IGFzIGEgcG9pbnRlciBvZiB0eXBlICcgKyB0aGlzLm5hbWUpOwogICAgICB9CiAgICAgIHZhciBoYW5kbGVDbGFzcyA9IGhhbmRsZS4kJC5wdHJUeXBlLnJlZ2lzdGVyZWRDbGFzczsKICAgICAgdmFyIHB0ciA9IHVwY2FzdFBvaW50ZXIoaGFuZGxlLiQkLnB0ciwgaGFuZGxlQ2xhc3MsIHRoaXMucmVnaXN0ZXJlZENsYXNzKTsKICAgICAgcmV0dXJuIHB0cgogICAgfQogICAgZnVuY3Rpb24gZ2VuZXJpY1BvaW50ZXJUb1dpcmVUeXBlKGRlc3RydWN0b3JzLCBoYW5kbGUpIHsKICAgICAgdmFyIHB0cjsKICAgICAgaWYgKGhhbmRsZSA9PT0gbnVsbCkgewogICAgICAgIGlmICh0aGlzLmlzUmVmZXJlbmNlKSB7CiAgICAgICAgICB0aHJvd0JpbmRpbmdFcnJvcignbnVsbCBpcyBub3QgYSB2YWxpZCAnICsgdGhpcy5uYW1lKTsKICAgICAgICB9CiAgICAgICAgaWYgKHRoaXMuaXNTbWFydFBvaW50ZXIpIHsKICAgICAgICAgIHB0ciA9IHRoaXMucmF3Q29uc3RydWN0b3IoKTsKICAgICAgICAgIGlmIChkZXN0cnVjdG9ycyAhPT0gbnVsbCkgewogICAgICAgICAgICBkZXN0cnVjdG9ycy5wdXNoKHRoaXMucmF3RGVzdHJ1Y3RvciwgcHRyKTsKICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiBwdHIKICAgICAgICB9IGVsc2UgewogICAgICAgICAgcmV0dXJuIDAKICAgICAgICB9CiAgICAgIH0KICAgICAgaWYgKCFoYW5kbGUuJCQpIHsKICAgICAgICB0aHJvd0JpbmRpbmdFcnJvcignQ2Fubm90IHBhc3MgIicgKyBfZW1iaW5kX3JlcHIoaGFuZGxlKSArICciIGFzIGEgJyArIHRoaXMubmFtZSk7CiAgICAgIH0KICAgICAgaWYgKCFoYW5kbGUuJCQucHRyKSB7CiAgICAgICAgdGhyb3dCaW5kaW5nRXJyb3IoJ0Nhbm5vdCBwYXNzIGRlbGV0ZWQgb2JqZWN0IGFzIGEgcG9pbnRlciBvZiB0eXBlICcgKyB0aGlzLm5hbWUpOwogICAgICB9CiAgICAgIGlmICghdGhpcy5pc0NvbnN0ICYmIGhhbmRsZS4kJC5wdHJUeXBlLmlzQ29uc3QpIHsKICAgICAgICB0aHJvd0JpbmRpbmdFcnJvcigKICAgICAgICAgICdDYW5ub3QgY29udmVydCBhcmd1bWVudCBvZiB0eXBlICcgKwogICAgICAgICAgICAoaGFuZGxlLiQkLnNtYXJ0UHRyVHlwZSA/IGhhbmRsZS4kJC5zbWFydFB0clR5cGUubmFtZSA6IGhhbmRsZS4kJC5wdHJUeXBlLm5hbWUpICsKICAgICAgICAgICAgJyB0byBwYXJhbWV0ZXIgdHlwZSAnICsKICAgICAgICAgICAgdGhpcy5uYW1lCiAgICAgICAgKTsKICAgICAgfQogICAgICB2YXIgaGFuZGxlQ2xhc3MgPSBoYW5kbGUuJCQucHRyVHlwZS5yZWdpc3RlcmVkQ2xhc3M7CiAgICAgIHB0ciA9IHVwY2FzdFBvaW50ZXIoaGFuZGxlLiQkLnB0ciwgaGFuZGxlQ2xhc3MsIHRoaXMucmVnaXN0ZXJlZENsYXNzKTsKICAgICAgaWYgKHRoaXMuaXNTbWFydFBvaW50ZXIpIHsKICAgICAgICBpZiAodW5kZWZpbmVkID09PSBoYW5kbGUuJCQuc21hcnRQdHIpIHsKICAgICAgICAgIHRocm93QmluZGluZ0Vycm9yKCdQYXNzaW5nIHJhdyBwb2ludGVyIHRvIHNtYXJ0IHBvaW50ZXIgaXMgaWxsZWdhbCcpOwogICAgICAgIH0KICAgICAgICBzd2l0Y2ggKHRoaXMuc2hhcmluZ1BvbGljeSkgewogICAgICAgICAgY2FzZSAwOgogICAgICAgICAgICBpZiAoaGFuZGxlLiQkLnNtYXJ0UHRyVHlwZSA9PT0gdGhpcykgewogICAgICAgICAgICAgIHB0ciA9IGhhbmRsZS4kJC5zbWFydFB0cjsKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICB0aHJvd0JpbmRpbmdFcnJvcigKICAgICAgICAgICAgICAgICdDYW5ub3QgY29udmVydCBhcmd1bWVudCBvZiB0eXBlICcgKwogICAgICAgICAgICAgICAgICAoaGFuZGxlLiQkLnNtYXJ0UHRyVHlwZSA/IGhhbmRsZS4kJC5zbWFydFB0clR5cGUubmFtZSA6IGhhbmRsZS4kJC5wdHJUeXBlLm5hbWUpICsKICAgICAgICAgICAgICAgICAgJyB0byBwYXJhbWV0ZXIgdHlwZSAnICsKICAgICAgICAgICAgICAgICAgdGhpcy5uYW1lCiAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBicmVhawogICAgICAgICAgY2FzZSAxOgogICAgICAgICAgICBwdHIgPSBoYW5kbGUuJCQuc21hcnRQdHI7CiAgICAgICAgICAgIGJyZWFrCiAgICAgICAgICBjYXNlIDI6CiAgICAgICAgICAgIGlmIChoYW5kbGUuJCQuc21hcnRQdHJUeXBlID09PSB0aGlzKSB7CiAgICAgICAgICAgICAgcHRyID0gaGFuZGxlLiQkLnNtYXJ0UHRyOwogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgIHZhciBjbG9uZWRIYW5kbGUgPSBoYW5kbGVbJ2Nsb25lJ10oKTsKICAgICAgICAgICAgICBwdHIgPSB0aGlzLnJhd1NoYXJlKAogICAgICAgICAgICAgICAgcHRyLAogICAgICAgICAgICAgICAgX19lbXZhbF9yZWdpc3RlcihmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgICAgICAgIGNsb25lZEhhbmRsZVsnZGVsZXRlJ10oKTsKICAgICAgICAgICAgICAgIH0pCiAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICBpZiAoZGVzdHJ1Y3RvcnMgIT09IG51bGwpIHsKICAgICAgICAgICAgICAgIGRlc3RydWN0b3JzLnB1c2godGhpcy5yYXdEZXN0cnVjdG9yLCBwdHIpOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBicmVhawogICAgICAgICAgZGVmYXVsdDoKICAgICAgICAgICAgdGhyb3dCaW5kaW5nRXJyb3IoJ1Vuc3VwcG9ydGluZyBzaGFyaW5nIHBvbGljeScpOwogICAgICAgIH0KICAgICAgfQogICAgICByZXR1cm4gcHRyCiAgICB9CiAgICBmdW5jdGlvbiBub25Db25zdE5vU21hcnRQdHJSYXdQb2ludGVyVG9XaXJlVHlwZShkZXN0cnVjdG9ycywgaGFuZGxlKSB7CiAgICAgIGlmIChoYW5kbGUgPT09IG51bGwpIHsKICAgICAgICBpZiAodGhpcy5pc1JlZmVyZW5jZSkgewogICAgICAgICAgdGhyb3dCaW5kaW5nRXJyb3IoJ251bGwgaXMgbm90IGEgdmFsaWQgJyArIHRoaXMubmFtZSk7CiAgICAgICAgfQogICAgICAgIHJldHVybiAwCiAgICAgIH0KICAgICAgaWYgKCFoYW5kbGUuJCQpIHsKICAgICAgICB0aHJvd0JpbmRpbmdFcnJvcignQ2Fubm90IHBhc3MgIicgKyBfZW1iaW5kX3JlcHIoaGFuZGxlKSArICciIGFzIGEgJyArIHRoaXMubmFtZSk7CiAgICAgIH0KICAgICAgaWYgKCFoYW5kbGUuJCQucHRyKSB7CiAgICAgICAgdGhyb3dCaW5kaW5nRXJyb3IoJ0Nhbm5vdCBwYXNzIGRlbGV0ZWQgb2JqZWN0IGFzIGEgcG9pbnRlciBvZiB0eXBlICcgKyB0aGlzLm5hbWUpOwogICAgICB9CiAgICAgIGlmIChoYW5kbGUuJCQucHRyVHlwZS5pc0NvbnN0KSB7CiAgICAgICAgdGhyb3dCaW5kaW5nRXJyb3IoJ0Nhbm5vdCBjb252ZXJ0IGFyZ3VtZW50IG9mIHR5cGUgJyArIGhhbmRsZS4kJC5wdHJUeXBlLm5hbWUgKyAnIHRvIHBhcmFtZXRlciB0eXBlICcgKyB0aGlzLm5hbWUpOwogICAgICB9CiAgICAgIHZhciBoYW5kbGVDbGFzcyA9IGhhbmRsZS4kJC5wdHJUeXBlLnJlZ2lzdGVyZWRDbGFzczsKICAgICAgdmFyIHB0ciA9IHVwY2FzdFBvaW50ZXIoaGFuZGxlLiQkLnB0ciwgaGFuZGxlQ2xhc3MsIHRoaXMucmVnaXN0ZXJlZENsYXNzKTsKICAgICAgcmV0dXJuIHB0cgogICAgfQogICAgZnVuY3Rpb24gUmVnaXN0ZXJlZFBvaW50ZXJfZ2V0UG9pbnRlZShwdHIpIHsKICAgICAgaWYgKHRoaXMucmF3R2V0UG9pbnRlZSkgewogICAgICAgIHB0ciA9IHRoaXMucmF3R2V0UG9pbnRlZShwdHIpOwogICAgICB9CiAgICAgIHJldHVybiBwdHIKICAgIH0KICAgIGZ1bmN0aW9uIFJlZ2lzdGVyZWRQb2ludGVyX2Rlc3RydWN0b3IocHRyKSB7CiAgICAgIGlmICh0aGlzLnJhd0Rlc3RydWN0b3IpIHsKICAgICAgICB0aGlzLnJhd0Rlc3RydWN0b3IocHRyKTsKICAgICAgfQogICAgfQogICAgZnVuY3Rpb24gUmVnaXN0ZXJlZFBvaW50ZXJfZGVsZXRlT2JqZWN0KGhhbmRsZSkgewogICAgICBpZiAoaGFuZGxlICE9PSBudWxsKSB7CiAgICAgICAgaGFuZGxlWydkZWxldGUnXSgpOwogICAgICB9CiAgICB9CiAgICBmdW5jdGlvbiBkb3duY2FzdFBvaW50ZXIocHRyLCBwdHJDbGFzcywgZGVzaXJlZENsYXNzKSB7CiAgICAgIGlmIChwdHJDbGFzcyA9PT0gZGVzaXJlZENsYXNzKSB7CiAgICAgICAgcmV0dXJuIHB0cgogICAgICB9CiAgICAgIGlmICh1bmRlZmluZWQgPT09IGRlc2lyZWRDbGFzcy5iYXNlQ2xhc3MpIHsKICAgICAgICByZXR1cm4gbnVsbAogICAgICB9CiAgICAgIHZhciBydiA9IGRvd25jYXN0UG9pbnRlcihwdHIsIHB0ckNsYXNzLCBkZXNpcmVkQ2xhc3MuYmFzZUNsYXNzKTsKICAgICAgaWYgKHJ2ID09PSBudWxsKSB7CiAgICAgICAgcmV0dXJuIG51bGwKICAgICAgfQogICAgICByZXR1cm4gZGVzaXJlZENsYXNzLmRvd25jYXN0KHJ2KQogICAgfQogICAgZnVuY3Rpb24gZ2V0SW5oZXJpdGVkSW5zdGFuY2VDb3VudCgpIHsKICAgICAgcmV0dXJuIE9iamVjdC5rZXlzKHJlZ2lzdGVyZWRJbnN0YW5jZXMpLmxlbmd0aAogICAgfQogICAgZnVuY3Rpb24gZ2V0TGl2ZUluaGVyaXRlZEluc3RhbmNlcygpIHsKICAgICAgdmFyIHJ2ID0gW107CiAgICAgIGZvciAodmFyIGsgaW4gcmVnaXN0ZXJlZEluc3RhbmNlcykgewogICAgICAgIGlmIChyZWdpc3RlcmVkSW5zdGFuY2VzLmhhc093blByb3BlcnR5KGspKSB7CiAgICAgICAgICBydi5wdXNoKHJlZ2lzdGVyZWRJbnN0YW5jZXNba10pOwogICAgICAgIH0KICAgICAgfQogICAgICByZXR1cm4gcnYKICAgIH0KICAgIGZ1bmN0aW9uIHNldERlbGF5RnVuY3Rpb24oZm4pIHsKICAgICAgZGVsYXlGdW5jdGlvbiA9IGZuOwogICAgICBpZiAoZGVsZXRpb25RdWV1ZS5sZW5ndGggJiYgZGVsYXlGdW5jdGlvbikgewogICAgICAgIGRlbGF5RnVuY3Rpb24oZmx1c2hQZW5kaW5nRGVsZXRlcyk7CiAgICAgIH0KICAgIH0KICAgIGZ1bmN0aW9uIGluaXRfZW1iaW5kKCkgewogICAgICBNb2R1bGVbJ2dldEluaGVyaXRlZEluc3RhbmNlQ291bnQnXSA9IGdldEluaGVyaXRlZEluc3RhbmNlQ291bnQ7CiAgICAgIE1vZHVsZVsnZ2V0TGl2ZUluaGVyaXRlZEluc3RhbmNlcyddID0gZ2V0TGl2ZUluaGVyaXRlZEluc3RhbmNlczsKICAgICAgTW9kdWxlWydmbHVzaFBlbmRpbmdEZWxldGVzJ10gPSBmbHVzaFBlbmRpbmdEZWxldGVzOwogICAgICBNb2R1bGVbJ3NldERlbGF5RnVuY3Rpb24nXSA9IHNldERlbGF5RnVuY3Rpb247CiAgICB9CiAgICB2YXIgcmVnaXN0ZXJlZEluc3RhbmNlcyA9IHt9OwogICAgZnVuY3Rpb24gZ2V0QmFzZXN0UG9pbnRlcihjbGFzc18sIHB0cikgewogICAgICBpZiAocHRyID09PSB1bmRlZmluZWQpIHsKICAgICAgICB0aHJvd0JpbmRpbmdFcnJvcigncHRyIHNob3VsZCBub3QgYmUgdW5kZWZpbmVkJyk7CiAgICAgIH0KICAgICAgd2hpbGUgKGNsYXNzXy5iYXNlQ2xhc3MpIHsKICAgICAgICBwdHIgPSBjbGFzc18udXBjYXN0KHB0cik7CiAgICAgICAgY2xhc3NfID0gY2xhc3NfLmJhc2VDbGFzczsKICAgICAgfQogICAgICByZXR1cm4gcHRyCiAgICB9CiAgICBmdW5jdGlvbiBnZXRJbmhlcml0ZWRJbnN0YW5jZShjbGFzc18sIHB0cikgewogICAgICBwdHIgPSBnZXRCYXNlc3RQb2ludGVyKGNsYXNzXywgcHRyKTsKICAgICAgcmV0dXJuIHJlZ2lzdGVyZWRJbnN0YW5jZXNbcHRyXQogICAgfQogICAgZnVuY3Rpb24gbWFrZUNsYXNzSGFuZGxlKHByb3RvdHlwZSwgcmVjb3JkKSB7CiAgICAgIGlmICghcmVjb3JkLnB0clR5cGUgfHwgIXJlY29yZC5wdHIpIHsKICAgICAgICB0aHJvd0ludGVybmFsRXJyb3IoJ21ha2VDbGFzc0hhbmRsZSByZXF1aXJlcyBwdHIgYW5kIHB0clR5cGUnKTsKICAgICAgfQogICAgICB2YXIgaGFzU21hcnRQdHJUeXBlID0gISFyZWNvcmQuc21hcnRQdHJUeXBlOwogICAgICB2YXIgaGFzU21hcnRQdHIgPSAhIXJlY29yZC5zbWFydFB0cjsKICAgICAgaWYgKGhhc1NtYXJ0UHRyVHlwZSAhPT0gaGFzU21hcnRQdHIpIHsKICAgICAgICB0aHJvd0ludGVybmFsRXJyb3IoJ0JvdGggc21hcnRQdHJUeXBlIGFuZCBzbWFydFB0ciBtdXN0IGJlIHNwZWNpZmllZCcpOwogICAgICB9CiAgICAgIHJlY29yZC5jb3VudCA9IHsgdmFsdWU6IDEgfTsKICAgICAgcmV0dXJuIE9iamVjdC5jcmVhdGUocHJvdG90eXBlLCB7ICQkOiB7IHZhbHVlOiByZWNvcmQgfSB9KQogICAgfQogICAgZnVuY3Rpb24gUmVnaXN0ZXJlZFBvaW50ZXJfZnJvbVdpcmVUeXBlKHB0cikgewogICAgICB2YXIgcmF3UG9pbnRlciA9IHRoaXMuZ2V0UG9pbnRlZShwdHIpOwogICAgICBpZiAoIXJhd1BvaW50ZXIpIHsKICAgICAgICB0aGlzLmRlc3RydWN0b3IocHRyKTsKICAgICAgICByZXR1cm4gbnVsbAogICAgICB9CiAgICAgIHZhciByZWdpc3RlcmVkSW5zdGFuY2UgPSBnZXRJbmhlcml0ZWRJbnN0YW5jZSh0aGlzLnJlZ2lzdGVyZWRDbGFzcywgcmF3UG9pbnRlcik7CiAgICAgIGlmICh1bmRlZmluZWQgIT09IHJlZ2lzdGVyZWRJbnN0YW5jZSkgewogICAgICAgIGlmICgwID09PSByZWdpc3RlcmVkSW5zdGFuY2UuJCQuY291bnQudmFsdWUpIHsKICAgICAgICAgIHJlZ2lzdGVyZWRJbnN0YW5jZS4kJC5wdHIgPSByYXdQb2ludGVyOwogICAgICAgICAgcmVnaXN0ZXJlZEluc3RhbmNlLiQkLnNtYXJ0UHRyID0gcHRyOwogICAgICAgICAgcmV0dXJuIHJlZ2lzdGVyZWRJbnN0YW5jZVsnY2xvbmUnXSgpCiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIHZhciBydiA9IHJlZ2lzdGVyZWRJbnN0YW5jZVsnY2xvbmUnXSgpOwogICAgICAgICAgdGhpcy5kZXN0cnVjdG9yKHB0cik7CiAgICAgICAgICByZXR1cm4gcnYKICAgICAgICB9CiAgICAgIH0KICAgICAgZnVuY3Rpb24gbWFrZURlZmF1bHRIYW5kbGUoKSB7CiAgICAgICAgaWYgKHRoaXMuaXNTbWFydFBvaW50ZXIpIHsKICAgICAgICAgIHJldHVybiBtYWtlQ2xhc3NIYW5kbGUodGhpcy5yZWdpc3RlcmVkQ2xhc3MuaW5zdGFuY2VQcm90b3R5cGUsIHsKICAgICAgICAgICAgcHRyVHlwZTogdGhpcy5wb2ludGVlVHlwZSwKICAgICAgICAgICAgcHRyOiByYXdQb2ludGVyLAogICAgICAgICAgICBzbWFydFB0clR5cGU6IHRoaXMsCiAgICAgICAgICAgIHNtYXJ0UHRyOiBwdHIsCiAgICAgICAgICB9KQogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICByZXR1cm4gbWFrZUNsYXNzSGFuZGxlKHRoaXMucmVnaXN0ZXJlZENsYXNzLmluc3RhbmNlUHJvdG90eXBlLCB7IHB0clR5cGU6IHRoaXMsIHB0cjogcHRyIH0pCiAgICAgICAgfQogICAgICB9CiAgICAgIHZhciBhY3R1YWxUeXBlID0gdGhpcy5yZWdpc3RlcmVkQ2xhc3MuZ2V0QWN0dWFsVHlwZShyYXdQb2ludGVyKTsKICAgICAgdmFyIHJlZ2lzdGVyZWRQb2ludGVyUmVjb3JkID0gcmVnaXN0ZXJlZFBvaW50ZXJzW2FjdHVhbFR5cGVdOwogICAgICBpZiAoIXJlZ2lzdGVyZWRQb2ludGVyUmVjb3JkKSB7CiAgICAgICAgcmV0dXJuIG1ha2VEZWZhdWx0SGFuZGxlLmNhbGwodGhpcykKICAgICAgfQogICAgICB2YXIgdG9UeXBlOwogICAgICBpZiAodGhpcy5pc0NvbnN0KSB7CiAgICAgICAgdG9UeXBlID0gcmVnaXN0ZXJlZFBvaW50ZXJSZWNvcmQuY29uc3RQb2ludGVyVHlwZTsKICAgICAgfSBlbHNlIHsKICAgICAgICB0b1R5cGUgPSByZWdpc3RlcmVkUG9pbnRlclJlY29yZC5wb2ludGVyVHlwZTsKICAgICAgfQogICAgICB2YXIgZHAgPSBkb3duY2FzdFBvaW50ZXIocmF3UG9pbnRlciwgdGhpcy5yZWdpc3RlcmVkQ2xhc3MsIHRvVHlwZS5yZWdpc3RlcmVkQ2xhc3MpOwogICAgICBpZiAoZHAgPT09IG51bGwpIHsKICAgICAgICByZXR1cm4gbWFrZURlZmF1bHRIYW5kbGUuY2FsbCh0aGlzKQogICAgICB9CiAgICAgIGlmICh0aGlzLmlzU21hcnRQb2ludGVyKSB7CiAgICAgICAgcmV0dXJuIG1ha2VDbGFzc0hhbmRsZSh0b1R5cGUucmVnaXN0ZXJlZENsYXNzLmluc3RhbmNlUHJvdG90eXBlLCB7CiAgICAgICAgICBwdHJUeXBlOiB0b1R5cGUsCiAgICAgICAgICBwdHI6IGRwLAogICAgICAgICAgc21hcnRQdHJUeXBlOiB0aGlzLAogICAgICAgICAgc21hcnRQdHI6IHB0ciwKICAgICAgICB9KQogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBtYWtlQ2xhc3NIYW5kbGUodG9UeXBlLnJlZ2lzdGVyZWRDbGFzcy5pbnN0YW5jZVByb3RvdHlwZSwgeyBwdHJUeXBlOiB0b1R5cGUsIHB0cjogZHAgfSkKICAgICAgfQogICAgfQogICAgZnVuY3Rpb24gaW5pdF9SZWdpc3RlcmVkUG9pbnRlcigpIHsKICAgICAgUmVnaXN0ZXJlZFBvaW50ZXIucHJvdG90eXBlLmdldFBvaW50ZWUgPSBSZWdpc3RlcmVkUG9pbnRlcl9nZXRQb2ludGVlOwogICAgICBSZWdpc3RlcmVkUG9pbnRlci5wcm90b3R5cGUuZGVzdHJ1Y3RvciA9IFJlZ2lzdGVyZWRQb2ludGVyX2Rlc3RydWN0b3I7CiAgICAgIFJlZ2lzdGVyZWRQb2ludGVyLnByb3RvdHlwZVsnYXJnUGFja0FkdmFuY2UnXSA9IDg7CiAgICAgIFJlZ2lzdGVyZWRQb2ludGVyLnByb3RvdHlwZVsncmVhZFZhbHVlRnJvbVBvaW50ZXInXSA9IHNpbXBsZVJlYWRWYWx1ZUZyb21Qb2ludGVyOwogICAgICBSZWdpc3RlcmVkUG9pbnRlci5wcm90b3R5cGVbJ2RlbGV0ZU9iamVjdCddID0gUmVnaXN0ZXJlZFBvaW50ZXJfZGVsZXRlT2JqZWN0OwogICAgICBSZWdpc3RlcmVkUG9pbnRlci5wcm90b3R5cGVbJ2Zyb21XaXJlVHlwZSddID0gUmVnaXN0ZXJlZFBvaW50ZXJfZnJvbVdpcmVUeXBlOwogICAgfQogICAgZnVuY3Rpb24gUmVnaXN0ZXJlZFBvaW50ZXIoCiAgICAgIG5hbWUsCiAgICAgIHJlZ2lzdGVyZWRDbGFzcywKICAgICAgaXNSZWZlcmVuY2UsCiAgICAgIGlzQ29uc3QsCiAgICAgIGlzU21hcnRQb2ludGVyLAogICAgICBwb2ludGVlVHlwZSwKICAgICAgc2hhcmluZ1BvbGljeSwKICAgICAgcmF3R2V0UG9pbnRlZSwKICAgICAgcmF3Q29uc3RydWN0b3IsCiAgICAgIHJhd1NoYXJlLAogICAgICByYXdEZXN0cnVjdG9yCiAgICApIHsKICAgICAgdGhpcy5uYW1lID0gbmFtZTsKICAgICAgdGhpcy5yZWdpc3RlcmVkQ2xhc3MgPSByZWdpc3RlcmVkQ2xhc3M7CiAgICAgIHRoaXMuaXNSZWZlcmVuY2UgPSBpc1JlZmVyZW5jZTsKICAgICAgdGhpcy5pc0NvbnN0ID0gaXNDb25zdDsKICAgICAgdGhpcy5pc1NtYXJ0UG9pbnRlciA9IGlzU21hcnRQb2ludGVyOwogICAgICB0aGlzLnBvaW50ZWVUeXBlID0gcG9pbnRlZVR5cGU7CiAgICAgIHRoaXMuc2hhcmluZ1BvbGljeSA9IHNoYXJpbmdQb2xpY3k7CiAgICAgIHRoaXMucmF3R2V0UG9pbnRlZSA9IHJhd0dldFBvaW50ZWU7CiAgICAgIHRoaXMucmF3Q29uc3RydWN0b3IgPSByYXdDb25zdHJ1Y3RvcjsKICAgICAgdGhpcy5yYXdTaGFyZSA9IHJhd1NoYXJlOwogICAgICB0aGlzLnJhd0Rlc3RydWN0b3IgPSByYXdEZXN0cnVjdG9yOwogICAgICBpZiAoIWlzU21hcnRQb2ludGVyICYmIHJlZ2lzdGVyZWRDbGFzcy5iYXNlQ2xhc3MgPT09IHVuZGVmaW5lZCkgewogICAgICAgIGlmIChpc0NvbnN0KSB7CiAgICAgICAgICB0aGlzWyd0b1dpcmVUeXBlJ10gPSBjb25zdE5vU21hcnRQdHJSYXdQb2ludGVyVG9XaXJlVHlwZTsKICAgICAgICAgIHRoaXMuZGVzdHJ1Y3RvckZ1bmN0aW9uID0gbnVsbDsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgdGhpc1sndG9XaXJlVHlwZSddID0gbm9uQ29uc3ROb1NtYXJ0UHRyUmF3UG9pbnRlclRvV2lyZVR5cGU7CiAgICAgICAgICB0aGlzLmRlc3RydWN0b3JGdW5jdGlvbiA9IG51bGw7CiAgICAgICAgfQogICAgICB9IGVsc2UgewogICAgICAgIHRoaXNbJ3RvV2lyZVR5cGUnXSA9IGdlbmVyaWNQb2ludGVyVG9XaXJlVHlwZTsKICAgICAgfQogICAgfQogICAgZnVuY3Rpb24gcmVwbGFjZVB1YmxpY1N5bWJvbChuYW1lLCB2YWx1ZSwgbnVtQXJndW1lbnRzKSB7CiAgICAgIGlmICghTW9kdWxlLmhhc093blByb3BlcnR5KG5hbWUpKSB7CiAgICAgICAgdGhyb3dJbnRlcm5hbEVycm9yKCdSZXBsYWNpbmcgbm9uZXhpc3RhbnQgcHVibGljIHN5bWJvbCcpOwogICAgICB9CiAgICAgIGlmICh1bmRlZmluZWQgIT09IE1vZHVsZVtuYW1lXS5vdmVybG9hZFRhYmxlICYmIHVuZGVmaW5lZCAhPT0gbnVtQXJndW1lbnRzKSB7CiAgICAgICAgTW9kdWxlW25hbWVdLm92ZXJsb2FkVGFibGVbbnVtQXJndW1lbnRzXSA9IHZhbHVlOwogICAgICB9IGVsc2UgewogICAgICAgIE1vZHVsZVtuYW1lXSA9IHZhbHVlOwogICAgICAgIE1vZHVsZVtuYW1lXS5hcmdDb3VudCA9IG51bUFyZ3VtZW50czsKICAgICAgfQogICAgfQogICAgZnVuY3Rpb24gZW1iaW5kX19yZXF1aXJlRnVuY3Rpb24oc2lnbmF0dXJlLCByYXdGdW5jdGlvbikgewogICAgICBzaWduYXR1cmUgPSByZWFkTGF0aW4xU3RyaW5nKHNpZ25hdHVyZSk7CiAgICAgIGZ1bmN0aW9uIG1ha2VEeW5DYWxsZXIoZHluQ2FsbCkgewogICAgICAgIHZhciBhcmdzID0gW107CiAgICAgICAgZm9yICh2YXIgaSA9IDE7IGkgPCBzaWduYXR1cmUubGVuZ3RoOyArK2kpIHsKICAgICAgICAgIGFyZ3MucHVzaCgnYScgKyBpKTsKICAgICAgICB9CiAgICAgICAgdmFyIG5hbWUgPSAnZHluQ2FsbF8nICsgc2lnbmF0dXJlICsgJ18nICsgcmF3RnVuY3Rpb247CiAgICAgICAgdmFyIGJvZHkgPSAncmV0dXJuIGZ1bmN0aW9uICcgKyBuYW1lICsgJygnICsgYXJncy5qb2luKCcsICcpICsgJykge1xuJzsKICAgICAgICBib2R5ICs9ICcgICAgcmV0dXJuIGR5bkNhbGwocmF3RnVuY3Rpb24nICsgKGFyZ3MubGVuZ3RoID8gJywgJyA6ICcnKSArIGFyZ3Muam9pbignLCAnKSArICcpO1xuJzsKICAgICAgICBib2R5ICs9ICd9O1xuJzsKICAgICAgICByZXR1cm4gbmV3IEZ1bmN0aW9uKCdkeW5DYWxsJywgJ3Jhd0Z1bmN0aW9uJywgYm9keSkoZHluQ2FsbCwgcmF3RnVuY3Rpb24pCiAgICAgIH0KICAgICAgdmFyIGZwOwogICAgICBpZiAoTW9kdWxlWydGVU5DVElPTl9UQUJMRV8nICsgc2lnbmF0dXJlXSAhPT0gdW5kZWZpbmVkKSB7CiAgICAgICAgZnAgPSBNb2R1bGVbJ0ZVTkNUSU9OX1RBQkxFXycgKyBzaWduYXR1cmVdW3Jhd0Z1bmN0aW9uXTsKICAgICAgfSBlbHNlIGlmICh0eXBlb2YgRlVOQ1RJT05fVEFCTEUgIT09ICd1bmRlZmluZWQnKSB7CiAgICAgICAgZnAgPSBGVU5DVElPTl9UQUJMRVtyYXdGdW5jdGlvbl07CiAgICAgIH0gZWxzZSB7CiAgICAgICAgdmFyIGRjID0gTW9kdWxlWydhc20nXVsnZHluQ2FsbF8nICsgc2lnbmF0dXJlXTsKICAgICAgICBpZiAoZGMgPT09IHVuZGVmaW5lZCkgewogICAgICAgICAgZGMgPSBNb2R1bGVbJ2FzbSddWydkeW5DYWxsXycgKyBzaWduYXR1cmUucmVwbGFjZSgvZi9nLCAnZCcpXTsKICAgICAgICAgIGlmIChkYyA9PT0gdW5kZWZpbmVkKSB7CiAgICAgICAgICAgIHRocm93QmluZGluZ0Vycm9yKCdObyBkeW5DYWxsIGludm9rZXIgZm9yIHNpZ25hdHVyZTogJyArIHNpZ25hdHVyZSk7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGZwID0gbWFrZUR5bkNhbGxlcihkYyk7CiAgICAgIH0KICAgICAgaWYgKHR5cGVvZiBmcCAhPT0gJ2Z1bmN0aW9uJykgewogICAgICAgIHRocm93QmluZGluZ0Vycm9yKCd1bmtub3duIGZ1bmN0aW9uIHBvaW50ZXIgd2l0aCBzaWduYXR1cmUgJyArIHNpZ25hdHVyZSArICc6ICcgKyByYXdGdW5jdGlvbik7CiAgICAgIH0KICAgICAgcmV0dXJuIGZwCiAgICB9CiAgICB2YXIgVW5ib3VuZFR5cGVFcnJvciA9IHVuZGVmaW5lZDsKICAgIGZ1bmN0aW9uIGdldFR5cGVOYW1lKHR5cGUpIHsKICAgICAgdmFyIHB0ciA9IF9fX2dldFR5cGVOYW1lKHR5cGUpOwogICAgICB2YXIgcnYgPSByZWFkTGF0aW4xU3RyaW5nKHB0cik7CiAgICAgIF9mcmVlKHB0cik7CiAgICAgIHJldHVybiBydgogICAgfQogICAgZnVuY3Rpb24gdGhyb3dVbmJvdW5kVHlwZUVycm9yKG1lc3NhZ2UsIHR5cGVzKSB7CiAgICAgIHZhciB1bmJvdW5kVHlwZXMgPSBbXTsKICAgICAgdmFyIHNlZW4gPSB7fTsKICAgICAgZnVuY3Rpb24gdmlzaXQodHlwZSkgewogICAgICAgIGlmIChzZWVuW3R5cGVdKSB7CiAgICAgICAgICByZXR1cm4KICAgICAgICB9CiAgICAgICAgaWYgKHJlZ2lzdGVyZWRUeXBlc1t0eXBlXSkgewogICAgICAgICAgcmV0dXJuCiAgICAgICAgfQogICAgICAgIGlmICh0eXBlRGVwZW5kZW5jaWVzW3R5cGVdKSB7CiAgICAgICAgICB0eXBlRGVwZW5kZW5jaWVzW3R5cGVdLmZvckVhY2godmlzaXQpOwogICAgICAgICAgcmV0dXJuCiAgICAgICAgfQogICAgICAgIHVuYm91bmRUeXBlcy5wdXNoKHR5cGUpOwogICAgICAgIHNlZW5bdHlwZV0gPSB0cnVlOwogICAgICB9CiAgICAgIHR5cGVzLmZvckVhY2godmlzaXQpOwogICAgICB0aHJvdyBuZXcgVW5ib3VuZFR5cGVFcnJvcihtZXNzYWdlICsgJzogJyArIHVuYm91bmRUeXBlcy5tYXAoZ2V0VHlwZU5hbWUpLmpvaW4oWycsICddKSkKICAgIH0KICAgIGZ1bmN0aW9uIF9fZW1iaW5kX3JlZ2lzdGVyX2NsYXNzKAogICAgICByYXdUeXBlLAogICAgICByYXdQb2ludGVyVHlwZSwKICAgICAgcmF3Q29uc3RQb2ludGVyVHlwZSwKICAgICAgYmFzZUNsYXNzUmF3VHlwZSwKICAgICAgZ2V0QWN0dWFsVHlwZVNpZ25hdHVyZSwKICAgICAgZ2V0QWN0dWFsVHlwZSwKICAgICAgdXBjYXN0U2lnbmF0dXJlLAogICAgICB1cGNhc3QsCiAgICAgIGRvd25jYXN0U2lnbmF0dXJlLAogICAgICBkb3duY2FzdCwKICAgICAgbmFtZSwKICAgICAgZGVzdHJ1Y3RvclNpZ25hdHVyZSwKICAgICAgcmF3RGVzdHJ1Y3RvcgogICAgKSB7CiAgICAgIG5hbWUgPSByZWFkTGF0aW4xU3RyaW5nKG5hbWUpOwogICAgICBnZXRBY3R1YWxUeXBlID0gZW1iaW5kX19yZXF1aXJlRnVuY3Rpb24oZ2V0QWN0dWFsVHlwZVNpZ25hdHVyZSwgZ2V0QWN0dWFsVHlwZSk7CiAgICAgIGlmICh1cGNhc3QpIHsKICAgICAgICB1cGNhc3QgPSBlbWJpbmRfX3JlcXVpcmVGdW5jdGlvbih1cGNhc3RTaWduYXR1cmUsIHVwY2FzdCk7CiAgICAgIH0KICAgICAgaWYgKGRvd25jYXN0KSB7CiAgICAgICAgZG93bmNhc3QgPSBlbWJpbmRfX3JlcXVpcmVGdW5jdGlvbihkb3duY2FzdFNpZ25hdHVyZSwgZG93bmNhc3QpOwogICAgICB9CiAgICAgIHJhd0Rlc3RydWN0b3IgPSBlbWJpbmRfX3JlcXVpcmVGdW5jdGlvbihkZXN0cnVjdG9yU2lnbmF0dXJlLCByYXdEZXN0cnVjdG9yKTsKICAgICAgdmFyIGxlZ2FsRnVuY3Rpb25OYW1lID0gbWFrZUxlZ2FsRnVuY3Rpb25OYW1lKG5hbWUpOwogICAgICBleHBvc2VQdWJsaWNTeW1ib2wobGVnYWxGdW5jdGlvbk5hbWUsIGZ1bmN0aW9uICgpIHsKICAgICAgICB0aHJvd1VuYm91bmRUeXBlRXJyb3IoJ0Nhbm5vdCBjb25zdHJ1Y3QgJyArIG5hbWUgKyAnIGR1ZSB0byB1bmJvdW5kIHR5cGVzJywgW2Jhc2VDbGFzc1Jhd1R5cGVdKTsKICAgICAgfSk7CiAgICAgIHdoZW5EZXBlbmRlbnRUeXBlc0FyZVJlc29sdmVkKAogICAgICAgIFtyYXdUeXBlLCByYXdQb2ludGVyVHlwZSwgcmF3Q29uc3RQb2ludGVyVHlwZV0sCiAgICAgICAgYmFzZUNsYXNzUmF3VHlwZSA/IFtiYXNlQ2xhc3NSYXdUeXBlXSA6IFtdLAogICAgICAgIGZ1bmN0aW9uIChiYXNlKSB7CiAgICAgICAgICBiYXNlID0gYmFzZVswXTsKICAgICAgICAgIHZhciBiYXNlQ2xhc3M7CiAgICAgICAgICB2YXIgYmFzZVByb3RvdHlwZTsKICAgICAgICAgIGlmIChiYXNlQ2xhc3NSYXdUeXBlKSB7CiAgICAgICAgICAgIGJhc2VDbGFzcyA9IGJhc2UucmVnaXN0ZXJlZENsYXNzOwogICAgICAgICAgICBiYXNlUHJvdG90eXBlID0gYmFzZUNsYXNzLmluc3RhbmNlUHJvdG90eXBlOwogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgYmFzZVByb3RvdHlwZSA9IENsYXNzSGFuZGxlLnByb3RvdHlwZTsKICAgICAgICAgIH0KICAgICAgICAgIHZhciBjb25zdHJ1Y3RvciA9IGNyZWF0ZU5hbWVkRnVuY3Rpb24obGVnYWxGdW5jdGlvbk5hbWUsIGZ1bmN0aW9uICgpIHsKICAgICAgICAgICAgaWYgKE9iamVjdC5nZXRQcm90b3R5cGVPZih0aGlzKSAhPT0gaW5zdGFuY2VQcm90b3R5cGUpIHsKICAgICAgICAgICAgICB0aHJvdyBuZXcgQmluZGluZ0Vycm9yKCJVc2UgJ25ldycgdG8gY29uc3RydWN0ICIgKyBuYW1lKQogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmICh1bmRlZmluZWQgPT09IHJlZ2lzdGVyZWRDbGFzcy5jb25zdHJ1Y3Rvcl9ib2R5KSB7CiAgICAgICAgICAgICAgdGhyb3cgbmV3IEJpbmRpbmdFcnJvcihuYW1lICsgJyBoYXMgbm8gYWNjZXNzaWJsZSBjb25zdHJ1Y3RvcicpCiAgICAgICAgICAgIH0KICAgICAgICAgICAgdmFyIGJvZHkgPSByZWdpc3RlcmVkQ2xhc3MuY29uc3RydWN0b3JfYm9keVthcmd1bWVudHMubGVuZ3RoXTsKICAgICAgICAgICAgaWYgKHVuZGVmaW5lZCA9PT0gYm9keSkgewogICAgICAgICAgICAgIHRocm93IG5ldyBCaW5kaW5nRXJyb3IoCiAgICAgICAgICAgICAgICAnVHJpZWQgdG8gaW52b2tlIGN0b3Igb2YgJyArCiAgICAgICAgICAgICAgICAgIG5hbWUgKwogICAgICAgICAgICAgICAgICAnIHdpdGggaW52YWxpZCBudW1iZXIgb2YgcGFyYW1ldGVycyAoJyArCiAgICAgICAgICAgICAgICAgIGFyZ3VtZW50cy5sZW5ndGggKwogICAgICAgICAgICAgICAgICAnKSAtIGV4cGVjdGVkICgnICsKICAgICAgICAgICAgICAgICAgT2JqZWN0LmtleXMocmVnaXN0ZXJlZENsYXNzLmNvbnN0cnVjdG9yX2JvZHkpLnRvU3RyaW5nKCkgKwogICAgICAgICAgICAgICAgICAnKSBwYXJhbWV0ZXJzIGluc3RlYWQhJwogICAgICAgICAgICAgICkKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gYm9keS5hcHBseSh0aGlzLCBhcmd1bWVudHMpCiAgICAgICAgICB9KTsKICAgICAgICAgIHZhciBpbnN0YW5jZVByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoYmFzZVByb3RvdHlwZSwgeyBjb25zdHJ1Y3RvcjogeyB2YWx1ZTogY29uc3RydWN0b3IgfSB9KTsKICAgICAgICAgIGNvbnN0cnVjdG9yLnByb3RvdHlwZSA9IGluc3RhbmNlUHJvdG90eXBlOwogICAgICAgICAgdmFyIHJlZ2lzdGVyZWRDbGFzcyA9IG5ldyBSZWdpc3RlcmVkQ2xhc3MoCiAgICAgICAgICAgIG5hbWUsCiAgICAgICAgICAgIGNvbnN0cnVjdG9yLAogICAgICAgICAgICBpbnN0YW5jZVByb3RvdHlwZSwKICAgICAgICAgICAgcmF3RGVzdHJ1Y3RvciwKICAgICAgICAgICAgYmFzZUNsYXNzLAogICAgICAgICAgICBnZXRBY3R1YWxUeXBlLAogICAgICAgICAgICB1cGNhc3QsCiAgICAgICAgICAgIGRvd25jYXN0CiAgICAgICAgICApOwogICAgICAgICAgdmFyIHJlZmVyZW5jZUNvbnZlcnRlciA9IG5ldyBSZWdpc3RlcmVkUG9pbnRlcihuYW1lLCByZWdpc3RlcmVkQ2xhc3MsIHRydWUsIGZhbHNlLCBmYWxzZSk7CiAgICAgICAgICB2YXIgcG9pbnRlckNvbnZlcnRlciA9IG5ldyBSZWdpc3RlcmVkUG9pbnRlcihuYW1lICsgJyonLCByZWdpc3RlcmVkQ2xhc3MsIGZhbHNlLCBmYWxzZSwgZmFsc2UpOwogICAgICAgICAgdmFyIGNvbnN0UG9pbnRlckNvbnZlcnRlciA9IG5ldyBSZWdpc3RlcmVkUG9pbnRlcihuYW1lICsgJyBjb25zdConLCByZWdpc3RlcmVkQ2xhc3MsIGZhbHNlLCB0cnVlLCBmYWxzZSk7CiAgICAgICAgICByZWdpc3RlcmVkUG9pbnRlcnNbcmF3VHlwZV0gPSB7IHBvaW50ZXJUeXBlOiBwb2ludGVyQ29udmVydGVyLCBjb25zdFBvaW50ZXJUeXBlOiBjb25zdFBvaW50ZXJDb252ZXJ0ZXIgfTsKICAgICAgICAgIHJlcGxhY2VQdWJsaWNTeW1ib2wobGVnYWxGdW5jdGlvbk5hbWUsIGNvbnN0cnVjdG9yKTsKICAgICAgICAgIHJldHVybiBbcmVmZXJlbmNlQ29udmVydGVyLCBwb2ludGVyQ29udmVydGVyLCBjb25zdFBvaW50ZXJDb252ZXJ0ZXJdCiAgICAgICAgfQogICAgICApOwogICAgfQogICAgZnVuY3Rpb24gaGVhcDMyVmVjdG9yVG9BcnJheShjb3VudCwgZmlyc3RFbGVtZW50KSB7CiAgICAgIHZhciBhcnJheSA9IFtdOwogICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGNvdW50OyBpKyspIHsKICAgICAgICBhcnJheS5wdXNoKEhFQVAzMlsoZmlyc3RFbGVtZW50ID4+IDIpICsgaV0pOwogICAgICB9CiAgICAgIHJldHVybiBhcnJheQogICAgfQogICAgZnVuY3Rpb24gX19lbWJpbmRfcmVnaXN0ZXJfY2xhc3NfY29uc3RydWN0b3IoCiAgICAgIHJhd0NsYXNzVHlwZSwKICAgICAgYXJnQ291bnQsCiAgICAgIHJhd0FyZ1R5cGVzQWRkciwKICAgICAgaW52b2tlclNpZ25hdHVyZSwKICAgICAgaW52b2tlciwKICAgICAgcmF3Q29uc3RydWN0b3IKICAgICkgewogICAgICB2YXIgcmF3QXJnVHlwZXMgPSBoZWFwMzJWZWN0b3JUb0FycmF5KGFyZ0NvdW50LCByYXdBcmdUeXBlc0FkZHIpOwogICAgICBpbnZva2VyID0gZW1iaW5kX19yZXF1aXJlRnVuY3Rpb24oaW52b2tlclNpZ25hdHVyZSwgaW52b2tlcik7CiAgICAgIHdoZW5EZXBlbmRlbnRUeXBlc0FyZVJlc29sdmVkKFtdLCBbcmF3Q2xhc3NUeXBlXSwgZnVuY3Rpb24gKGNsYXNzVHlwZSkgewogICAgICAgIGNsYXNzVHlwZSA9IGNsYXNzVHlwZVswXTsKICAgICAgICB2YXIgaHVtYW5OYW1lID0gJ2NvbnN0cnVjdG9yICcgKyBjbGFzc1R5cGUubmFtZTsKICAgICAgICBpZiAodW5kZWZpbmVkID09PSBjbGFzc1R5cGUucmVnaXN0ZXJlZENsYXNzLmNvbnN0cnVjdG9yX2JvZHkpIHsKICAgICAgICAgIGNsYXNzVHlwZS5yZWdpc3RlcmVkQ2xhc3MuY29uc3RydWN0b3JfYm9keSA9IFtdOwogICAgICAgIH0KICAgICAgICBpZiAodW5kZWZpbmVkICE9PSBjbGFzc1R5cGUucmVnaXN0ZXJlZENsYXNzLmNvbnN0cnVjdG9yX2JvZHlbYXJnQ291bnQgLSAxXSkgewogICAgICAgICAgdGhyb3cgbmV3IEJpbmRpbmdFcnJvcigKICAgICAgICAgICAgJ0Nhbm5vdCByZWdpc3RlciBtdWx0aXBsZSBjb25zdHJ1Y3RvcnMgd2l0aCBpZGVudGljYWwgbnVtYmVyIG9mIHBhcmFtZXRlcnMgKCcgKwogICAgICAgICAgICAgIChhcmdDb3VudCAtIDEpICsKICAgICAgICAgICAgICAiKSBmb3IgY2xhc3MgJyIgKwogICAgICAgICAgICAgIGNsYXNzVHlwZS5uYW1lICsKICAgICAgICAgICAgICAiJyEgT3ZlcmxvYWQgcmVzb2x1dGlvbiBpcyBjdXJyZW50bHkgb25seSBwZXJmb3JtZWQgdXNpbmcgdGhlIHBhcmFtZXRlciBjb3VudCwgbm90IGFjdHVhbCB0eXBlIGluZm8hIgogICAgICAgICAgKQogICAgICAgIH0KICAgICAgICBjbGFzc1R5cGUucmVnaXN0ZXJlZENsYXNzLmNvbnN0cnVjdG9yX2JvZHlbYXJnQ291bnQgLSAxXSA9IGZ1bmN0aW9uIHVuYm91bmRUeXBlSGFuZGxlcigpIHsKICAgICAgICAgIHRocm93VW5ib3VuZFR5cGVFcnJvcignQ2Fubm90IGNvbnN0cnVjdCAnICsgY2xhc3NUeXBlLm5hbWUgKyAnIGR1ZSB0byB1bmJvdW5kIHR5cGVzJywgcmF3QXJnVHlwZXMpOwogICAgICAgIH07CiAgICAgICAgd2hlbkRlcGVuZGVudFR5cGVzQXJlUmVzb2x2ZWQoW10sIHJhd0FyZ1R5cGVzLCBmdW5jdGlvbiAoYXJnVHlwZXMpIHsKICAgICAgICAgIGNsYXNzVHlwZS5yZWdpc3RlcmVkQ2xhc3MuY29uc3RydWN0b3JfYm9keVthcmdDb3VudCAtIDFdID0gZnVuY3Rpb24gY29uc3RydWN0b3JfYm9keSgpIHsKICAgICAgICAgICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggIT09IGFyZ0NvdW50IC0gMSkgewogICAgICAgICAgICAgIHRocm93QmluZGluZ0Vycm9yKGh1bWFuTmFtZSArICcgY2FsbGVkIHdpdGggJyArIGFyZ3VtZW50cy5sZW5ndGggKyAnIGFyZ3VtZW50cywgZXhwZWN0ZWQgJyArIChhcmdDb3VudCAtIDEpKTsKICAgICAgICAgICAgfQogICAgICAgICAgICB2YXIgZGVzdHJ1Y3RvcnMgPSBbXTsKICAgICAgICAgICAgdmFyIGFyZ3MgPSBuZXcgQXJyYXkoYXJnQ291bnQpOwogICAgICAgICAgICBhcmdzWzBdID0gcmF3Q29uc3RydWN0b3I7CiAgICAgICAgICAgIGZvciAodmFyIGkgPSAxOyBpIDwgYXJnQ291bnQ7ICsraSkgewogICAgICAgICAgICAgIGFyZ3NbaV0gPSBhcmdUeXBlc1tpXVsndG9XaXJlVHlwZSddKGRlc3RydWN0b3JzLCBhcmd1bWVudHNbaSAtIDFdKTsKICAgICAgICAgICAgfQogICAgICAgICAgICB2YXIgcHRyID0gaW52b2tlci5hcHBseShudWxsLCBhcmdzKTsKICAgICAgICAgICAgcnVuRGVzdHJ1Y3RvcnMoZGVzdHJ1Y3RvcnMpOwogICAgICAgICAgICByZXR1cm4gYXJnVHlwZXNbMF1bJ2Zyb21XaXJlVHlwZSddKHB0cikKICAgICAgICAgIH07CiAgICAgICAgICByZXR1cm4gW10KICAgICAgICB9KTsKICAgICAgICByZXR1cm4gW10KICAgICAgfSk7CiAgICB9CiAgICBmdW5jdGlvbiBuZXdfKGNvbnN0cnVjdG9yLCBhcmd1bWVudExpc3QpIHsKICAgICAgaWYgKCEoY29uc3RydWN0b3IgaW5zdGFuY2VvZiBGdW5jdGlvbikpIHsKICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCduZXdfIGNhbGxlZCB3aXRoIGNvbnN0cnVjdG9yIHR5cGUgJyArIHR5cGVvZiBjb25zdHJ1Y3RvciArICcgd2hpY2ggaXMgbm90IGEgZnVuY3Rpb24nKQogICAgICB9CiAgICAgIHZhciBkdW1teSA9IGNyZWF0ZU5hbWVkRnVuY3Rpb24oY29uc3RydWN0b3IubmFtZSB8fCAndW5rbm93bkZ1bmN0aW9uTmFtZScsIGZ1bmN0aW9uICgpIHt9KTsKICAgICAgZHVtbXkucHJvdG90eXBlID0gY29uc3RydWN0b3IucHJvdG90eXBlOwogICAgICB2YXIgb2JqID0gbmV3IGR1bW15KCk7CiAgICAgIHZhciByID0gY29uc3RydWN0b3IuYXBwbHkob2JqLCBhcmd1bWVudExpc3QpOwogICAgICByZXR1cm4gciBpbnN0YW5jZW9mIE9iamVjdCA/IHIgOiBvYmoKICAgIH0KICAgIGZ1bmN0aW9uIGNyYWZ0SW52b2tlckZ1bmN0aW9uKGh1bWFuTmFtZSwgYXJnVHlwZXMsIGNsYXNzVHlwZSwgY3BwSW52b2tlckZ1bmMsIGNwcFRhcmdldEZ1bmMpIHsKICAgICAgdmFyIGFyZ0NvdW50ID0gYXJnVHlwZXMubGVuZ3RoOwogICAgICBpZiAoYXJnQ291bnQgPCAyKSB7CiAgICAgICAgdGhyb3dCaW5kaW5nRXJyb3IoImFyZ1R5cGVzIGFycmF5IHNpemUgbWlzbWF0Y2ghIE11c3QgYXQgbGVhc3QgZ2V0IHJldHVybiB2YWx1ZSBhbmQgJ3RoaXMnIHR5cGVzISIpOwogICAgICB9CiAgICAgIHZhciBpc0NsYXNzTWV0aG9kRnVuYyA9IGFyZ1R5cGVzWzFdICE9PSBudWxsICYmIGNsYXNzVHlwZSAhPT0gbnVsbDsKICAgICAgdmFyIG5lZWRzRGVzdHJ1Y3RvclN0YWNrID0gZmFsc2U7CiAgICAgIGZvciAodmFyIGkgPSAxOyBpIDwgYXJnVHlwZXMubGVuZ3RoOyArK2kpIHsKICAgICAgICBpZiAoYXJnVHlwZXNbaV0gIT09IG51bGwgJiYgYXJnVHlwZXNbaV0uZGVzdHJ1Y3RvckZ1bmN0aW9uID09PSB1bmRlZmluZWQpIHsKICAgICAgICAgIG5lZWRzRGVzdHJ1Y3RvclN0YWNrID0gdHJ1ZTsKICAgICAgICAgIGJyZWFrCiAgICAgICAgfQogICAgICB9CiAgICAgIHZhciByZXR1cm5zID0gYXJnVHlwZXNbMF0ubmFtZSAhPT0gJ3ZvaWQnOwogICAgICB2YXIgYXJnc0xpc3QgPSAnJzsKICAgICAgdmFyIGFyZ3NMaXN0V2lyZWQgPSAnJzsKICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBhcmdDb3VudCAtIDI7ICsraSkgewogICAgICAgIGFyZ3NMaXN0ICs9IChpICE9PSAwID8gJywgJyA6ICcnKSArICdhcmcnICsgaTsKICAgICAgICBhcmdzTGlzdFdpcmVkICs9IChpICE9PSAwID8gJywgJyA6ICcnKSArICdhcmcnICsgaSArICdXaXJlZCc7CiAgICAgIH0KICAgICAgdmFyIGludm9rZXJGbkJvZHkgPQogICAgICAgICdyZXR1cm4gZnVuY3Rpb24gJyArCiAgICAgICAgbWFrZUxlZ2FsRnVuY3Rpb25OYW1lKGh1bWFuTmFtZSkgKwogICAgICAgICcoJyArCiAgICAgICAgYXJnc0xpc3QgKwogICAgICAgICcpIHtcbicgKwogICAgICAgICdpZiAoYXJndW1lbnRzLmxlbmd0aCAhPT0gJyArCiAgICAgICAgKGFyZ0NvdW50IC0gMikgKwogICAgICAgICcpIHtcbicgKwogICAgICAgICJ0aHJvd0JpbmRpbmdFcnJvcignZnVuY3Rpb24gIiArCiAgICAgICAgaHVtYW5OYW1lICsKICAgICAgICAiIGNhbGxlZCB3aXRoICcgKyBhcmd1bWVudHMubGVuZ3RoICsgJyBhcmd1bWVudHMsIGV4cGVjdGVkICIgKwogICAgICAgIChhcmdDb3VudCAtIDIpICsKICAgICAgICAiIGFyZ3MhJyk7XG4iICsKICAgICAgICAnfVxuJzsKICAgICAgaWYgKG5lZWRzRGVzdHJ1Y3RvclN0YWNrKSB7CiAgICAgICAgaW52b2tlckZuQm9keSArPSAndmFyIGRlc3RydWN0b3JzID0gW107XG4nOwogICAgICB9CiAgICAgIHZhciBkdG9yU3RhY2sgPSBuZWVkc0Rlc3RydWN0b3JTdGFjayA/ICdkZXN0cnVjdG9ycycgOiAnbnVsbCc7CiAgICAgIHZhciBhcmdzMSA9IFsndGhyb3dCaW5kaW5nRXJyb3InLCAnaW52b2tlcicsICdmbicsICdydW5EZXN0cnVjdG9ycycsICdyZXRUeXBlJywgJ2NsYXNzUGFyYW0nXTsKICAgICAgdmFyIGFyZ3MyID0gW3Rocm93QmluZGluZ0Vycm9yLCBjcHBJbnZva2VyRnVuYywgY3BwVGFyZ2V0RnVuYywgcnVuRGVzdHJ1Y3RvcnMsIGFyZ1R5cGVzWzBdLCBhcmdUeXBlc1sxXV07CiAgICAgIGlmIChpc0NsYXNzTWV0aG9kRnVuYykgewogICAgICAgIGludm9rZXJGbkJvZHkgKz0gJ3ZhciB0aGlzV2lyZWQgPSBjbGFzc1BhcmFtLnRvV2lyZVR5cGUoJyArIGR0b3JTdGFjayArICcsIHRoaXMpO1xuJzsKICAgICAgfQogICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGFyZ0NvdW50IC0gMjsgKytpKSB7CiAgICAgICAgaW52b2tlckZuQm9keSArPQogICAgICAgICAgJ3ZhciBhcmcnICsKICAgICAgICAgIGkgKwogICAgICAgICAgJ1dpcmVkID0gYXJnVHlwZScgKwogICAgICAgICAgaSArCiAgICAgICAgICAnLnRvV2lyZVR5cGUoJyArCiAgICAgICAgICBkdG9yU3RhY2sgKwogICAgICAgICAgJywgYXJnJyArCiAgICAgICAgICBpICsKICAgICAgICAgICcpOyAvLyAnICsKICAgICAgICAgIGFyZ1R5cGVzW2kgKyAyXS5uYW1lICsKICAgICAgICAgICdcbic7CiAgICAgICAgYXJnczEucHVzaCgnYXJnVHlwZScgKyBpKTsKICAgICAgICBhcmdzMi5wdXNoKGFyZ1R5cGVzW2kgKyAyXSk7CiAgICAgIH0KICAgICAgaWYgKGlzQ2xhc3NNZXRob2RGdW5jKSB7CiAgICAgICAgYXJnc0xpc3RXaXJlZCA9ICd0aGlzV2lyZWQnICsgKGFyZ3NMaXN0V2lyZWQubGVuZ3RoID4gMCA/ICcsICcgOiAnJykgKyBhcmdzTGlzdFdpcmVkOwogICAgICB9CiAgICAgIGludm9rZXJGbkJvZHkgKz0KICAgICAgICAocmV0dXJucyA/ICd2YXIgcnYgPSAnIDogJycpICsgJ2ludm9rZXIoZm4nICsgKGFyZ3NMaXN0V2lyZWQubGVuZ3RoID4gMCA/ICcsICcgOiAnJykgKyBhcmdzTGlzdFdpcmVkICsgJyk7XG4nOwogICAgICBpZiAobmVlZHNEZXN0cnVjdG9yU3RhY2spIHsKICAgICAgICBpbnZva2VyRm5Cb2R5ICs9ICdydW5EZXN0cnVjdG9ycyhkZXN0cnVjdG9ycyk7XG4nOwogICAgICB9IGVsc2UgewogICAgICAgIGZvciAodmFyIGkgPSBpc0NsYXNzTWV0aG9kRnVuYyA/IDEgOiAyOyBpIDwgYXJnVHlwZXMubGVuZ3RoOyArK2kpIHsKICAgICAgICAgIHZhciBwYXJhbU5hbWUgPSBpID09PSAxID8gJ3RoaXNXaXJlZCcgOiAnYXJnJyArIChpIC0gMikgKyAnV2lyZWQnOwogICAgICAgICAgaWYgKGFyZ1R5cGVzW2ldLmRlc3RydWN0b3JGdW5jdGlvbiAhPT0gbnVsbCkgewogICAgICAgICAgICBpbnZva2VyRm5Cb2R5ICs9IHBhcmFtTmFtZSArICdfZHRvcignICsgcGFyYW1OYW1lICsgJyk7IC8vICcgKyBhcmdUeXBlc1tpXS5uYW1lICsgJ1xuJzsKICAgICAgICAgICAgYXJnczEucHVzaChwYXJhbU5hbWUgKyAnX2R0b3InKTsKICAgICAgICAgICAgYXJnczIucHVzaChhcmdUeXBlc1tpXS5kZXN0cnVjdG9yRnVuY3Rpb24pOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfQogICAgICBpZiAocmV0dXJucykgewogICAgICAgIGludm9rZXJGbkJvZHkgKz0gJ3ZhciByZXQgPSByZXRUeXBlLmZyb21XaXJlVHlwZShydik7XG4nICsgJ3JldHVybiByZXQ7XG4nOwogICAgICB9CiAgICAgIGludm9rZXJGbkJvZHkgKz0gJ31cbic7CiAgICAgIGFyZ3MxLnB1c2goaW52b2tlckZuQm9keSk7CiAgICAgIHZhciBpbnZva2VyRnVuY3Rpb24gPSBuZXdfKEZ1bmN0aW9uLCBhcmdzMSkuYXBwbHkobnVsbCwgYXJnczIpOwogICAgICByZXR1cm4gaW52b2tlckZ1bmN0aW9uCiAgICB9CiAgICBmdW5jdGlvbiBfX2VtYmluZF9yZWdpc3Rlcl9jbGFzc19mdW5jdGlvbigKICAgICAgcmF3Q2xhc3NUeXBlLAogICAgICBtZXRob2ROYW1lLAogICAgICBhcmdDb3VudCwKICAgICAgcmF3QXJnVHlwZXNBZGRyLAogICAgICBpbnZva2VyU2lnbmF0dXJlLAogICAgICByYXdJbnZva2VyLAogICAgICBjb250ZXh0LAogICAgICBpc1B1cmVWaXJ0dWFsCiAgICApIHsKICAgICAgdmFyIHJhd0FyZ1R5cGVzID0gaGVhcDMyVmVjdG9yVG9BcnJheShhcmdDb3VudCwgcmF3QXJnVHlwZXNBZGRyKTsKICAgICAgbWV0aG9kTmFtZSA9IHJlYWRMYXRpbjFTdHJpbmcobWV0aG9kTmFtZSk7CiAgICAgIHJhd0ludm9rZXIgPSBlbWJpbmRfX3JlcXVpcmVGdW5jdGlvbihpbnZva2VyU2lnbmF0dXJlLCByYXdJbnZva2VyKTsKICAgICAgd2hlbkRlcGVuZGVudFR5cGVzQXJlUmVzb2x2ZWQoW10sIFtyYXdDbGFzc1R5cGVdLCBmdW5jdGlvbiAoY2xhc3NUeXBlKSB7CiAgICAgICAgY2xhc3NUeXBlID0gY2xhc3NUeXBlWzBdOwogICAgICAgIHZhciBodW1hbk5hbWUgPSBjbGFzc1R5cGUubmFtZSArICcuJyArIG1ldGhvZE5hbWU7CiAgICAgICAgaWYgKGlzUHVyZVZpcnR1YWwpIHsKICAgICAgICAgIGNsYXNzVHlwZS5yZWdpc3RlcmVkQ2xhc3MucHVyZVZpcnR1YWxGdW5jdGlvbnMucHVzaChtZXRob2ROYW1lKTsKICAgICAgICB9CiAgICAgICAgZnVuY3Rpb24gdW5ib3VuZFR5cGVzSGFuZGxlcigpIHsKICAgICAgICAgIHRocm93VW5ib3VuZFR5cGVFcnJvcignQ2Fubm90IGNhbGwgJyArIGh1bWFuTmFtZSArICcgZHVlIHRvIHVuYm91bmQgdHlwZXMnLCByYXdBcmdUeXBlcyk7CiAgICAgICAgfQogICAgICAgIHZhciBwcm90byA9IGNsYXNzVHlwZS5yZWdpc3RlcmVkQ2xhc3MuaW5zdGFuY2VQcm90b3R5cGU7CiAgICAgICAgdmFyIG1ldGhvZCA9IHByb3RvW21ldGhvZE5hbWVdOwogICAgICAgIGlmICgKICAgICAgICAgIHVuZGVmaW5lZCA9PT0gbWV0aG9kIHx8CiAgICAgICAgICAodW5kZWZpbmVkID09PSBtZXRob2Qub3ZlcmxvYWRUYWJsZSAmJiBtZXRob2QuY2xhc3NOYW1lICE9PSBjbGFzc1R5cGUubmFtZSAmJiBtZXRob2QuYXJnQ291bnQgPT09IGFyZ0NvdW50IC0gMikKICAgICAgICApIHsKICAgICAgICAgIHVuYm91bmRUeXBlc0hhbmRsZXIuYXJnQ291bnQgPSBhcmdDb3VudCAtIDI7CiAgICAgICAgICB1bmJvdW5kVHlwZXNIYW5kbGVyLmNsYXNzTmFtZSA9IGNsYXNzVHlwZS5uYW1lOwogICAgICAgICAgcHJvdG9bbWV0aG9kTmFtZV0gPSB1bmJvdW5kVHlwZXNIYW5kbGVyOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBlbnN1cmVPdmVybG9hZFRhYmxlKHByb3RvLCBtZXRob2ROYW1lLCBodW1hbk5hbWUpOwogICAgICAgICAgcHJvdG9bbWV0aG9kTmFtZV0ub3ZlcmxvYWRUYWJsZVthcmdDb3VudCAtIDJdID0gdW5ib3VuZFR5cGVzSGFuZGxlcjsKICAgICAgICB9CiAgICAgICAgd2hlbkRlcGVuZGVudFR5cGVzQXJlUmVzb2x2ZWQoW10sIHJhd0FyZ1R5cGVzLCBmdW5jdGlvbiAoYXJnVHlwZXMpIHsKICAgICAgICAgIHZhciBtZW1iZXJGdW5jdGlvbiA9IGNyYWZ0SW52b2tlckZ1bmN0aW9uKGh1bWFuTmFtZSwgYXJnVHlwZXMsIGNsYXNzVHlwZSwgcmF3SW52b2tlciwgY29udGV4dCk7CiAgICAgICAgICBpZiAodW5kZWZpbmVkID09PSBwcm90b1ttZXRob2ROYW1lXS5vdmVybG9hZFRhYmxlKSB7CiAgICAgICAgICAgIG1lbWJlckZ1bmN0aW9uLmFyZ0NvdW50ID0gYXJnQ291bnQgLSAyOwogICAgICAgICAgICBwcm90b1ttZXRob2ROYW1lXSA9IG1lbWJlckZ1bmN0aW9uOwogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgcHJvdG9bbWV0aG9kTmFtZV0ub3ZlcmxvYWRUYWJsZVthcmdDb3VudCAtIDJdID0gbWVtYmVyRnVuY3Rpb247CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gW10KICAgICAgICB9KTsKICAgICAgICByZXR1cm4gW10KICAgICAgfSk7CiAgICB9CiAgICB2YXIgZW12YWxfZnJlZV9saXN0ID0gW107CiAgICB2YXIgZW12YWxfaGFuZGxlX2FycmF5ID0gW3t9LCB7IHZhbHVlOiB1bmRlZmluZWQgfSwgeyB2YWx1ZTogbnVsbCB9LCB7IHZhbHVlOiB0cnVlIH0sIHsgdmFsdWU6IGZhbHNlIH1dOwogICAgZnVuY3Rpb24gX19lbXZhbF9kZWNyZWYoaGFuZGxlKSB7CiAgICAgIGlmIChoYW5kbGUgPiA0ICYmIDAgPT09IC0tZW12YWxfaGFuZGxlX2FycmF5W2hhbmRsZV0ucmVmY291bnQpIHsKICAgICAgICBlbXZhbF9oYW5kbGVfYXJyYXlbaGFuZGxlXSA9IHVuZGVmaW5lZDsKICAgICAgICBlbXZhbF9mcmVlX2xpc3QucHVzaChoYW5kbGUpOwogICAgICB9CiAgICB9CiAgICBmdW5jdGlvbiBjb3VudF9lbXZhbF9oYW5kbGVzKCkgewogICAgICB2YXIgY291bnQgPSAwOwogICAgICBmb3IgKHZhciBpID0gNTsgaSA8IGVtdmFsX2hhbmRsZV9hcnJheS5sZW5ndGg7ICsraSkgewogICAgICAgIGlmIChlbXZhbF9oYW5kbGVfYXJyYXlbaV0gIT09IHVuZGVmaW5lZCkgewogICAgICAgICAgKytjb3VudDsKICAgICAgICB9CiAgICAgIH0KICAgICAgcmV0dXJuIGNvdW50CiAgICB9CiAgICBmdW5jdGlvbiBnZXRfZmlyc3RfZW12YWwoKSB7CiAgICAgIGZvciAodmFyIGkgPSA1OyBpIDwgZW12YWxfaGFuZGxlX2FycmF5Lmxlbmd0aDsgKytpKSB7CiAgICAgICAgaWYgKGVtdmFsX2hhbmRsZV9hcnJheVtpXSAhPT0gdW5kZWZpbmVkKSB7CiAgICAgICAgICByZXR1cm4gZW12YWxfaGFuZGxlX2FycmF5W2ldCiAgICAgICAgfQogICAgICB9CiAgICAgIHJldHVybiBudWxsCiAgICB9CiAgICBmdW5jdGlvbiBpbml0X2VtdmFsKCkgewogICAgICBNb2R1bGVbJ2NvdW50X2VtdmFsX2hhbmRsZXMnXSA9IGNvdW50X2VtdmFsX2hhbmRsZXM7CiAgICAgIE1vZHVsZVsnZ2V0X2ZpcnN0X2VtdmFsJ10gPSBnZXRfZmlyc3RfZW12YWw7CiAgICB9CiAgICBmdW5jdGlvbiBfX2VtdmFsX3JlZ2lzdGVyKHZhbHVlKSB7CiAgICAgIHN3aXRjaCAodmFsdWUpIHsKICAgICAgICBjYXNlIHVuZGVmaW5lZDogewogICAgICAgICAgcmV0dXJuIDEKICAgICAgICB9CiAgICAgICAgY2FzZSBudWxsOiB7CiAgICAgICAgICByZXR1cm4gMgogICAgICAgIH0KICAgICAgICBjYXNlIHRydWU6IHsKICAgICAgICAgIHJldHVybiAzCiAgICAgICAgfQogICAgICAgIGNhc2UgZmFsc2U6IHsKICAgICAgICAgIHJldHVybiA0CiAgICAgICAgfQogICAgICAgIGRlZmF1bHQ6IHsKICAgICAgICAgIHZhciBoYW5kbGUgPSBlbXZhbF9mcmVlX2xpc3QubGVuZ3RoID8gZW12YWxfZnJlZV9saXN0LnBvcCgpIDogZW12YWxfaGFuZGxlX2FycmF5Lmxlbmd0aDsKICAgICAgICAgIGVtdmFsX2hhbmRsZV9hcnJheVtoYW5kbGVdID0geyByZWZjb3VudDogMSwgdmFsdWU6IHZhbHVlIH07CiAgICAgICAgICByZXR1cm4gaGFuZGxlCiAgICAgICAgfQogICAgICB9CiAgICB9CiAgICBmdW5jdGlvbiBfX2VtYmluZF9yZWdpc3Rlcl9lbXZhbChyYXdUeXBlLCBuYW1lKSB7CiAgICAgIG5hbWUgPSByZWFkTGF0aW4xU3RyaW5nKG5hbWUpOwogICAgICByZWdpc3RlclR5cGUocmF3VHlwZSwgewogICAgICAgIG5hbWU6IG5hbWUsCiAgICAgICAgZnJvbVdpcmVUeXBlOiBmdW5jdGlvbiAoaGFuZGxlKSB7CiAgICAgICAgICB2YXIgcnYgPSBlbXZhbF9oYW5kbGVfYXJyYXlbaGFuZGxlXS52YWx1ZTsKICAgICAgICAgIF9fZW12YWxfZGVjcmVmKGhhbmRsZSk7CiAgICAgICAgICByZXR1cm4gcnYKICAgICAgICB9LAogICAgICAgIHRvV2lyZVR5cGU6IGZ1bmN0aW9uIChkZXN0cnVjdG9ycywgdmFsdWUpIHsKICAgICAgICAgIHJldHVybiBfX2VtdmFsX3JlZ2lzdGVyKHZhbHVlKQogICAgICAgIH0sCiAgICAgICAgYXJnUGFja0FkdmFuY2U6IDgsCiAgICAgICAgcmVhZFZhbHVlRnJvbVBvaW50ZXI6IHNpbXBsZVJlYWRWYWx1ZUZyb21Qb2ludGVyLAogICAgICAgIGRlc3RydWN0b3JGdW5jdGlvbjogbnVsbCwKICAgICAgfSk7CiAgICB9CiAgICBmdW5jdGlvbiBfZW1iaW5kX3JlcHIodikgewogICAgICBpZiAodiA9PT0gbnVsbCkgewogICAgICAgIHJldHVybiAnbnVsbCcKICAgICAgfQogICAgICB2YXIgdCA9IHR5cGVvZiB2OwogICAgICBpZiAodCA9PT0gJ29iamVjdCcgfHwgdCA9PT0gJ2FycmF5JyB8fCB0ID09PSAnZnVuY3Rpb24nKSB7CiAgICAgICAgcmV0dXJuIHYudG9TdHJpbmcoKQogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiAnJyArIHYKICAgICAgfQogICAgfQogICAgZnVuY3Rpb24gZmxvYXRSZWFkVmFsdWVGcm9tUG9pbnRlcihuYW1lLCBzaGlmdCkgewogICAgICBzd2l0Y2ggKHNoaWZ0KSB7CiAgICAgICAgY2FzZSAyOgogICAgICAgICAgcmV0dXJuIGZ1bmN0aW9uIChwb2ludGVyKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzWydmcm9tV2lyZVR5cGUnXShIRUFQRjMyW3BvaW50ZXIgPj4gMl0pCiAgICAgICAgICB9CiAgICAgICAgY2FzZSAzOgogICAgICAgICAgcmV0dXJuIGZ1bmN0aW9uIChwb2ludGVyKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzWydmcm9tV2lyZVR5cGUnXShIRUFQRjY0W3BvaW50ZXIgPj4gM10pCiAgICAgICAgICB9CiAgICAgICAgZGVmYXVsdDoKICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ1Vua25vd24gZmxvYXQgdHlwZTogJyArIG5hbWUpCiAgICAgIH0KICAgIH0KICAgIGZ1bmN0aW9uIF9fZW1iaW5kX3JlZ2lzdGVyX2Zsb2F0KHJhd1R5cGUsIG5hbWUsIHNpemUpIHsKICAgICAgdmFyIHNoaWZ0ID0gZ2V0U2hpZnRGcm9tU2l6ZShzaXplKTsKICAgICAgbmFtZSA9IHJlYWRMYXRpbjFTdHJpbmcobmFtZSk7CiAgICAgIHJlZ2lzdGVyVHlwZShyYXdUeXBlLCB7CiAgICAgICAgbmFtZTogbmFtZSwKICAgICAgICBmcm9tV2lyZVR5cGU6IGZ1bmN0aW9uICh2YWx1ZSkgewogICAgICAgICAgcmV0dXJuIHZhbHVlCiAgICAgICAgfSwKICAgICAgICB0b1dpcmVUeXBlOiBmdW5jdGlvbiAoZGVzdHJ1Y3RvcnMsIHZhbHVlKSB7CiAgICAgICAgICBpZiAodHlwZW9mIHZhbHVlICE9PSAnbnVtYmVyJyAmJiB0eXBlb2YgdmFsdWUgIT09ICdib29sZWFuJykgewogICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdDYW5ub3QgY29udmVydCAiJyArIF9lbWJpbmRfcmVwcih2YWx1ZSkgKyAnIiB0byAnICsgdGhpcy5uYW1lKQogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIHZhbHVlCiAgICAgICAgfSwKICAgICAgICBhcmdQYWNrQWR2YW5jZTogOCwKICAgICAgICByZWFkVmFsdWVGcm9tUG9pbnRlcjogZmxvYXRSZWFkVmFsdWVGcm9tUG9pbnRlcihuYW1lLCBzaGlmdCksCiAgICAgICAgZGVzdHJ1Y3RvckZ1bmN0aW9uOiBudWxsLAogICAgICB9KTsKICAgIH0KICAgIGZ1bmN0aW9uIGludGVnZXJSZWFkVmFsdWVGcm9tUG9pbnRlcihuYW1lLCBzaGlmdCwgc2lnbmVkKSB7CiAgICAgIHN3aXRjaCAoc2hpZnQpIHsKICAgICAgICBjYXNlIDA6CiAgICAgICAgICByZXR1cm4gc2lnbmVkCiAgICAgICAgICAgID8gZnVuY3Rpb24gcmVhZFM4RnJvbVBvaW50ZXIocG9pbnRlcikgewogICAgICAgICAgICAgICAgcmV0dXJuIEhFQVA4W3BvaW50ZXJdCiAgICAgICAgICAgICAgfQogICAgICAgICAgICA6IGZ1bmN0aW9uIHJlYWRVOEZyb21Qb2ludGVyKHBvaW50ZXIpIHsKICAgICAgICAgICAgICAgIHJldHVybiBIRUFQVThbcG9pbnRlcl0KICAgICAgICAgICAgICB9CiAgICAgICAgY2FzZSAxOgogICAgICAgICAgcmV0dXJuIHNpZ25lZAogICAgICAgICAgICA/IGZ1bmN0aW9uIHJlYWRTMTZGcm9tUG9pbnRlcihwb2ludGVyKSB7CiAgICAgICAgICAgICAgICByZXR1cm4gSEVBUDE2W3BvaW50ZXIgPj4gMV0KICAgICAgICAgICAgICB9CiAgICAgICAgICAgIDogZnVuY3Rpb24gcmVhZFUxNkZyb21Qb2ludGVyKHBvaW50ZXIpIHsKICAgICAgICAgICAgICAgIHJldHVybiBIRUFQVTE2W3BvaW50ZXIgPj4gMV0KICAgICAgICAgICAgICB9CiAgICAgICAgY2FzZSAyOgogICAgICAgICAgcmV0dXJuIHNpZ25lZAogICAgICAgICAgICA/IGZ1bmN0aW9uIHJlYWRTMzJGcm9tUG9pbnRlcihwb2ludGVyKSB7CiAgICAgICAgICAgICAgICByZXR1cm4gSEVBUDMyW3BvaW50ZXIgPj4gMl0KICAgICAgICAgICAgICB9CiAgICAgICAgICAgIDogZnVuY3Rpb24gcmVhZFUzMkZyb21Qb2ludGVyKHBvaW50ZXIpIHsKICAgICAgICAgICAgICAgIHJldHVybiBIRUFQVTMyW3BvaW50ZXIgPj4gMl0KICAgICAgICAgICAgICB9CiAgICAgICAgZGVmYXVsdDoKICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ1Vua25vd24gaW50ZWdlciB0eXBlOiAnICsgbmFtZSkKICAgICAgfQogICAgfQogICAgZnVuY3Rpb24gX19lbWJpbmRfcmVnaXN0ZXJfaW50ZWdlcihwcmltaXRpdmVUeXBlLCBuYW1lLCBzaXplLCBtaW5SYW5nZSwgbWF4UmFuZ2UpIHsKICAgICAgbmFtZSA9IHJlYWRMYXRpbjFTdHJpbmcobmFtZSk7CiAgICAgIGlmIChtYXhSYW5nZSA9PT0gLTEpIHsKICAgICAgICBtYXhSYW5nZSA9IDQyOTQ5NjcyOTU7CiAgICAgIH0KICAgICAgdmFyIHNoaWZ0ID0gZ2V0U2hpZnRGcm9tU2l6ZShzaXplKTsKICAgICAgdmFyIGZyb21XaXJlVHlwZSA9IGZ1bmN0aW9uICh2YWx1ZSkgewogICAgICAgIHJldHVybiB2YWx1ZQogICAgICB9OwogICAgICBpZiAobWluUmFuZ2UgPT09IDApIHsKICAgICAgICB2YXIgYml0c2hpZnQgPSAzMiAtIDggKiBzaXplOwogICAgICAgIGZyb21XaXJlVHlwZSA9IGZ1bmN0aW9uICh2YWx1ZSkgewogICAgICAgICAgcmV0dXJuICh2YWx1ZSA8PCBiaXRzaGlmdCkgPj4+IGJpdHNoaWZ0CiAgICAgICAgfTsKICAgICAgfQogICAgICB2YXIgaXNVbnNpZ25lZFR5cGUgPSBuYW1lLmluZGV4T2YoJ3Vuc2lnbmVkJykgIT0gLTE7CiAgICAgIHJlZ2lzdGVyVHlwZShwcmltaXRpdmVUeXBlLCB7CiAgICAgICAgbmFtZTogbmFtZSwKICAgICAgICBmcm9tV2lyZVR5cGU6IGZyb21XaXJlVHlwZSwKICAgICAgICB0b1dpcmVUeXBlOiBmdW5jdGlvbiAoZGVzdHJ1Y3RvcnMsIHZhbHVlKSB7CiAgICAgICAgICBpZiAodHlwZW9mIHZhbHVlICE9PSAnbnVtYmVyJyAmJiB0eXBlb2YgdmFsdWUgIT09ICdib29sZWFuJykgewogICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdDYW5ub3QgY29udmVydCAiJyArIF9lbWJpbmRfcmVwcih2YWx1ZSkgKyAnIiB0byAnICsgdGhpcy5uYW1lKQogICAgICAgICAgfQogICAgICAgICAgaWYgKHZhbHVlIDwgbWluUmFuZ2UgfHwgdmFsdWUgPiBtYXhSYW5nZSkgewogICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKAogICAgICAgICAgICAgICdQYXNzaW5nIGEgbnVtYmVyICInICsKICAgICAgICAgICAgICAgIF9lbWJpbmRfcmVwcih2YWx1ZSkgKwogICAgICAgICAgICAgICAgJyIgZnJvbSBKUyBzaWRlIHRvIEMvQysrIHNpZGUgdG8gYW4gYXJndW1lbnQgb2YgdHlwZSAiJyArCiAgICAgICAgICAgICAgICBuYW1lICsKICAgICAgICAgICAgICAgICciLCB3aGljaCBpcyBvdXRzaWRlIHRoZSB2YWxpZCByYW5nZSBbJyArCiAgICAgICAgICAgICAgICBtaW5SYW5nZSArCiAgICAgICAgICAgICAgICAnLCAnICsKICAgICAgICAgICAgICAgIG1heFJhbmdlICsKICAgICAgICAgICAgICAgICddIScKICAgICAgICAgICAgKQogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIGlzVW5zaWduZWRUeXBlID8gdmFsdWUgPj4+IDAgOiB2YWx1ZSB8IDAKICAgICAgICB9LAogICAgICAgIGFyZ1BhY2tBZHZhbmNlOiA4LAogICAgICAgIHJlYWRWYWx1ZUZyb21Qb2ludGVyOiBpbnRlZ2VyUmVhZFZhbHVlRnJvbVBvaW50ZXIobmFtZSwgc2hpZnQsIG1pblJhbmdlICE9PSAwKSwKICAgICAgICBkZXN0cnVjdG9yRnVuY3Rpb246IG51bGwsCiAgICAgIH0pOwogICAgfQogICAgZnVuY3Rpb24gX19lbWJpbmRfcmVnaXN0ZXJfbWVtb3J5X3ZpZXcocmF3VHlwZSwgZGF0YVR5cGVJbmRleCwgbmFtZSkgewogICAgICB2YXIgdHlwZU1hcHBpbmcgPSBbCiAgICAgICAgSW50OEFycmF5LAogICAgICAgIFVpbnQ4QXJyYXksCiAgICAgICAgSW50MTZBcnJheSwKICAgICAgICBVaW50MTZBcnJheSwKICAgICAgICBJbnQzMkFycmF5LAogICAgICAgIFVpbnQzMkFycmF5LAogICAgICAgIEZsb2F0MzJBcnJheSwKICAgICAgICBGbG9hdDY0QXJyYXksCiAgICAgIF07CiAgICAgIHZhciBUQSA9IHR5cGVNYXBwaW5nW2RhdGFUeXBlSW5kZXhdOwogICAgICBmdW5jdGlvbiBkZWNvZGVNZW1vcnlWaWV3KGhhbmRsZSkgewogICAgICAgIGhhbmRsZSA9IGhhbmRsZSA+PiAyOwogICAgICAgIHZhciBoZWFwID0gSEVBUFUzMjsKICAgICAgICB2YXIgc2l6ZSA9IGhlYXBbaGFuZGxlXTsKICAgICAgICB2YXIgZGF0YSA9IGhlYXBbaGFuZGxlICsgMV07CiAgICAgICAgcmV0dXJuIG5ldyBUQShoZWFwWydidWZmZXInXSwgZGF0YSwgc2l6ZSkKICAgICAgfQogICAgICBuYW1lID0gcmVhZExhdGluMVN0cmluZyhuYW1lKTsKICAgICAgcmVnaXN0ZXJUeXBlKAogICAgICAgIHJhd1R5cGUsCiAgICAgICAgeyBuYW1lOiBuYW1lLCBmcm9tV2lyZVR5cGU6IGRlY29kZU1lbW9yeVZpZXcsIGFyZ1BhY2tBZHZhbmNlOiA4LCByZWFkVmFsdWVGcm9tUG9pbnRlcjogZGVjb2RlTWVtb3J5VmlldyB9LAogICAgICAgIHsgaWdub3JlRHVwbGljYXRlUmVnaXN0cmF0aW9uczogdHJ1ZSB9CiAgICAgICk7CiAgICB9CiAgICBmdW5jdGlvbiBfX2VtYmluZF9yZWdpc3Rlcl9zdGRfc3RyaW5nKHJhd1R5cGUsIG5hbWUpIHsKICAgICAgbmFtZSA9IHJlYWRMYXRpbjFTdHJpbmcobmFtZSk7CiAgICAgIHJlZ2lzdGVyVHlwZShyYXdUeXBlLCB7CiAgICAgICAgbmFtZTogbmFtZSwKICAgICAgICBmcm9tV2lyZVR5cGU6IGZ1bmN0aW9uICh2YWx1ZSkgewogICAgICAgICAgdmFyIGxlbmd0aCA9IEhFQVBVMzJbdmFsdWUgPj4gMl07CiAgICAgICAgICB2YXIgYSA9IG5ldyBBcnJheShsZW5ndGgpOwogICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7ICsraSkgewogICAgICAgICAgICBhW2ldID0gU3RyaW5nLmZyb21DaGFyQ29kZShIRUFQVThbdmFsdWUgKyA0ICsgaV0pOwogICAgICAgICAgfQogICAgICAgICAgX2ZyZWUodmFsdWUpOwogICAgICAgICAgcmV0dXJuIGEuam9pbignJykKICAgICAgICB9LAogICAgICAgIHRvV2lyZVR5cGU6IGZ1bmN0aW9uIChkZXN0cnVjdG9ycywgdmFsdWUpIHsKICAgICAgICAgIGlmICh2YWx1ZSBpbnN0YW5jZW9mIEFycmF5QnVmZmVyKSB7CiAgICAgICAgICAgIHZhbHVlID0gbmV3IFVpbnQ4QXJyYXkodmFsdWUpOwogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gZ2V0VEFFbGVtZW50KHRhLCBpbmRleCkgewogICAgICAgICAgICByZXR1cm4gdGFbaW5kZXhdCiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBnZXRTdHJpbmdFbGVtZW50KHN0cmluZywgaW5kZXgpIHsKICAgICAgICAgICAgcmV0dXJuIHN0cmluZy5jaGFyQ29kZUF0KGluZGV4KQogICAgICAgICAgfQogICAgICAgICAgdmFyIGdldEVsZW1lbnQ7CiAgICAgICAgICBpZiAodmFsdWUgaW5zdGFuY2VvZiBVaW50OEFycmF5KSB7CiAgICAgICAgICAgIGdldEVsZW1lbnQgPSBnZXRUQUVsZW1lbnQ7CiAgICAgICAgICB9IGVsc2UgaWYgKHZhbHVlIGluc3RhbmNlb2YgVWludDhDbGFtcGVkQXJyYXkpIHsKICAgICAgICAgICAgZ2V0RWxlbWVudCA9IGdldFRBRWxlbWVudDsKICAgICAgICAgIH0gZWxzZSBpZiAodmFsdWUgaW5zdGFuY2VvZiBJbnQ4QXJyYXkpIHsKICAgICAgICAgICAgZ2V0RWxlbWVudCA9IGdldFRBRWxlbWVudDsKICAgICAgICAgIH0gZWxzZSBpZiAodHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJykgewogICAgICAgICAgICBnZXRFbGVtZW50ID0gZ2V0U3RyaW5nRWxlbWVudDsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHRocm93QmluZGluZ0Vycm9yKCdDYW5ub3QgcGFzcyBub24tc3RyaW5nIHRvIHN0ZDo6c3RyaW5nJyk7CiAgICAgICAgICB9CiAgICAgICAgICB2YXIgbGVuZ3RoID0gdmFsdWUubGVuZ3RoOwogICAgICAgICAgdmFyIHB0ciA9IF9tYWxsb2MoNCArIGxlbmd0aCk7CiAgICAgICAgICBIRUFQVTMyW3B0ciA+PiAyXSA9IGxlbmd0aDsKICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyArK2kpIHsKICAgICAgICAgICAgdmFyIGNoYXJDb2RlID0gZ2V0RWxlbWVudCh2YWx1ZSwgaSk7CiAgICAgICAgICAgIGlmIChjaGFyQ29kZSA+IDI1NSkgewogICAgICAgICAgICAgIF9mcmVlKHB0cik7CiAgICAgICAgICAgICAgdGhyb3dCaW5kaW5nRXJyb3IoJ1N0cmluZyBoYXMgVVRGLTE2IGNvZGUgdW5pdHMgdGhhdCBkbyBub3QgZml0IGluIDggYml0cycpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIEhFQVBVOFtwdHIgKyA0ICsgaV0gPSBjaGFyQ29kZTsKICAgICAgICAgIH0KICAgICAgICAgIGlmIChkZXN0cnVjdG9ycyAhPT0gbnVsbCkgewogICAgICAgICAgICBkZXN0cnVjdG9ycy5wdXNoKF9mcmVlLCBwdHIpOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIHB0cgogICAgICAgIH0sCiAgICAgICAgYXJnUGFja0FkdmFuY2U6IDgsCiAgICAgICAgcmVhZFZhbHVlRnJvbVBvaW50ZXI6IHNpbXBsZVJlYWRWYWx1ZUZyb21Qb2ludGVyLAogICAgICAgIGRlc3RydWN0b3JGdW5jdGlvbjogZnVuY3Rpb24gKHB0cikgewogICAgICAgICAgX2ZyZWUocHRyKTsKICAgICAgICB9LAogICAgICB9KTsKICAgIH0KICAgIGZ1bmN0aW9uIF9fZW1iaW5kX3JlZ2lzdGVyX3N0ZF93c3RyaW5nKHJhd1R5cGUsIGNoYXJTaXplLCBuYW1lKSB7CiAgICAgIG5hbWUgPSByZWFkTGF0aW4xU3RyaW5nKG5hbWUpOwogICAgICB2YXIgZ2V0SGVhcCwgc2hpZnQ7CiAgICAgIGlmIChjaGFyU2l6ZSA9PT0gMikgewogICAgICAgIGdldEhlYXAgPSBmdW5jdGlvbiAoKSB7CiAgICAgICAgICByZXR1cm4gSEVBUFUxNgogICAgICAgIH07CiAgICAgICAgc2hpZnQgPSAxOwogICAgICB9IGVsc2UgaWYgKGNoYXJTaXplID09PSA0KSB7CiAgICAgICAgZ2V0SGVhcCA9IGZ1bmN0aW9uICgpIHsKICAgICAgICAgIHJldHVybiBIRUFQVTMyCiAgICAgICAgfTsKICAgICAgICBzaGlmdCA9IDI7CiAgICAgIH0KICAgICAgcmVnaXN0ZXJUeXBlKHJhd1R5cGUsIHsKICAgICAgICBuYW1lOiBuYW1lLAogICAgICAgIGZyb21XaXJlVHlwZTogZnVuY3Rpb24gKHZhbHVlKSB7CiAgICAgICAgICB2YXIgSEVBUCA9IGdldEhlYXAoKTsKICAgICAgICAgIHZhciBsZW5ndGggPSBIRUFQVTMyW3ZhbHVlID4+IDJdOwogICAgICAgICAgdmFyIGEgPSBuZXcgQXJyYXkobGVuZ3RoKTsKICAgICAgICAgIHZhciBzdGFydCA9ICh2YWx1ZSArIDQpID4+IHNoaWZ0OwogICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7ICsraSkgewogICAgICAgICAgICBhW2ldID0gU3RyaW5nLmZyb21DaGFyQ29kZShIRUFQW3N0YXJ0ICsgaV0pOwogICAgICAgICAgfQogICAgICAgICAgX2ZyZWUodmFsdWUpOwogICAgICAgICAgcmV0dXJuIGEuam9pbignJykKICAgICAgICB9LAogICAgICAgIHRvV2lyZVR5cGU6IGZ1bmN0aW9uIChkZXN0cnVjdG9ycywgdmFsdWUpIHsKICAgICAgICAgIHZhciBIRUFQID0gZ2V0SGVhcCgpOwogICAgICAgICAgdmFyIGxlbmd0aCA9IHZhbHVlLmxlbmd0aDsKICAgICAgICAgIHZhciBwdHIgPSBfbWFsbG9jKDQgKyBsZW5ndGggKiBjaGFyU2l6ZSk7CiAgICAgICAgICBIRUFQVTMyW3B0ciA+PiAyXSA9IGxlbmd0aDsKICAgICAgICAgIHZhciBzdGFydCA9IChwdHIgKyA0KSA+PiBzaGlmdDsKICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyArK2kpIHsKICAgICAgICAgICAgSEVBUFtzdGFydCArIGldID0gdmFsdWUuY2hhckNvZGVBdChpKTsKICAgICAgICAgIH0KICAgICAgICAgIGlmIChkZXN0cnVjdG9ycyAhPT0gbnVsbCkgewogICAgICAgICAgICBkZXN0cnVjdG9ycy5wdXNoKF9mcmVlLCBwdHIpOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIHB0cgogICAgICAgIH0sCiAgICAgICAgYXJnUGFja0FkdmFuY2U6IDgsCiAgICAgICAgcmVhZFZhbHVlRnJvbVBvaW50ZXI6IHNpbXBsZVJlYWRWYWx1ZUZyb21Qb2ludGVyLAogICAgICAgIGRlc3RydWN0b3JGdW5jdGlvbjogZnVuY3Rpb24gKHB0cikgewogICAgICAgICAgX2ZyZWUocHRyKTsKICAgICAgICB9LAogICAgICB9KTsKICAgIH0KICAgIGZ1bmN0aW9uIF9fZW1iaW5kX3JlZ2lzdGVyX3ZhbHVlX29iamVjdCgKICAgICAgcmF3VHlwZSwKICAgICAgbmFtZSwKICAgICAgY29uc3RydWN0b3JTaWduYXR1cmUsCiAgICAgIHJhd0NvbnN0cnVjdG9yLAogICAgICBkZXN0cnVjdG9yU2lnbmF0dXJlLAogICAgICByYXdEZXN0cnVjdG9yCiAgICApIHsKICAgICAgc3RydWN0UmVnaXN0cmF0aW9uc1tyYXdUeXBlXSA9IHsKICAgICAgICBuYW1lOiByZWFkTGF0aW4xU3RyaW5nKG5hbWUpLAogICAgICAgIHJhd0NvbnN0cnVjdG9yOiBlbWJpbmRfX3JlcXVpcmVGdW5jdGlvbihjb25zdHJ1Y3RvclNpZ25hdHVyZSwgcmF3Q29uc3RydWN0b3IpLAogICAgICAgIHJhd0Rlc3RydWN0b3I6IGVtYmluZF9fcmVxdWlyZUZ1bmN0aW9uKGRlc3RydWN0b3JTaWduYXR1cmUsIHJhd0Rlc3RydWN0b3IpLAogICAgICAgIGZpZWxkczogW10sCiAgICAgIH07CiAgICB9CiAgICBmdW5jdGlvbiBfX2VtYmluZF9yZWdpc3Rlcl92YWx1ZV9vYmplY3RfZmllbGQoCiAgICAgIHN0cnVjdFR5cGUsCiAgICAgIGZpZWxkTmFtZSwKICAgICAgZ2V0dGVyUmV0dXJuVHlwZSwKICAgICAgZ2V0dGVyU2lnbmF0dXJlLAogICAgICBnZXR0ZXIsCiAgICAgIGdldHRlckNvbnRleHQsCiAgICAgIHNldHRlckFyZ3VtZW50VHlwZSwKICAgICAgc2V0dGVyU2lnbmF0dXJlLAogICAgICBzZXR0ZXIsCiAgICAgIHNldHRlckNvbnRleHQKICAgICkgewogICAgICBzdHJ1Y3RSZWdpc3RyYXRpb25zW3N0cnVjdFR5cGVdLmZpZWxkcy5wdXNoKHsKICAgICAgICBmaWVsZE5hbWU6IHJlYWRMYXRpbjFTdHJpbmcoZmllbGROYW1lKSwKICAgICAgICBnZXR0ZXJSZXR1cm5UeXBlOiBnZXR0ZXJSZXR1cm5UeXBlLAogICAgICAgIGdldHRlcjogZW1iaW5kX19yZXF1aXJlRnVuY3Rpb24oZ2V0dGVyU2lnbmF0dXJlLCBnZXR0ZXIpLAogICAgICAgIGdldHRlckNvbnRleHQ6IGdldHRlckNvbnRleHQsCiAgICAgICAgc2V0dGVyQXJndW1lbnRUeXBlOiBzZXR0ZXJBcmd1bWVudFR5cGUsCiAgICAgICAgc2V0dGVyOiBlbWJpbmRfX3JlcXVpcmVGdW5jdGlvbihzZXR0ZXJTaWduYXR1cmUsIHNldHRlciksCiAgICAgICAgc2V0dGVyQ29udGV4dDogc2V0dGVyQ29udGV4dCwKICAgICAgfSk7CiAgICB9CiAgICBmdW5jdGlvbiBfX2VtYmluZF9yZWdpc3Rlcl92b2lkKHJhd1R5cGUsIG5hbWUpIHsKICAgICAgbmFtZSA9IHJlYWRMYXRpbjFTdHJpbmcobmFtZSk7CiAgICAgIHJlZ2lzdGVyVHlwZShyYXdUeXBlLCB7CiAgICAgICAgaXNWb2lkOiB0cnVlLAogICAgICAgIG5hbWU6IG5hbWUsCiAgICAgICAgYXJnUGFja0FkdmFuY2U6IDAsCiAgICAgICAgZnJvbVdpcmVUeXBlOiBmdW5jdGlvbiAoKSB7CiAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkCiAgICAgICAgfSwKICAgICAgICB0b1dpcmVUeXBlOiBmdW5jdGlvbiAoZGVzdHJ1Y3RvcnMsIG8pIHsKICAgICAgICAgIHJldHVybiB1bmRlZmluZWQKICAgICAgICB9LAogICAgICB9KTsKICAgIH0KICAgIGZ1bmN0aW9uIF9hYm9ydCgpIHsKICAgICAgTW9kdWxlWydhYm9ydCddKCk7CiAgICB9CiAgICB2YXIgX2Vudmlyb24gPSBTVEFUSUNUT1A7CiAgICBTVEFUSUNUT1AgKz0gMTY7CiAgICBmdW5jdGlvbiBfX19idWlsZEVudmlyb25tZW50KGVudikgewogICAgICB2YXIgTUFYX0VOVl9WQUxVRVMgPSA2NDsKICAgICAgdmFyIFRPVEFMX0VOVl9TSVpFID0gMTAyNDsKICAgICAgdmFyIHBvb2xQdHI7CiAgICAgIHZhciBlbnZQdHI7CiAgICAgIGlmICghX19fYnVpbGRFbnZpcm9ubWVudC5jYWxsZWQpIHsKICAgICAgICBfX19idWlsZEVudmlyb25tZW50LmNhbGxlZCA9IHRydWU7CiAgICAgICAgRU5WWydVU0VSJ10gPSBFTlZbJ0xPR05BTUUnXSA9ICd3ZWJfdXNlcic7CiAgICAgICAgRU5WWydQQVRIJ10gPSAnLyc7CiAgICAgICAgRU5WWydQV0QnXSA9ICcvJzsKICAgICAgICBFTlZbJ0hPTUUnXSA9ICcvaG9tZS93ZWJfdXNlcic7CiAgICAgICAgRU5WWydMQU5HJ10gPSAnQy5VVEYtOCc7CiAgICAgICAgRU5WWydfJ10gPSBNb2R1bGVbJ3RoaXNQcm9ncmFtJ107CiAgICAgICAgcG9vbFB0ciA9IHN0YXRpY0FsbG9jKFRPVEFMX0VOVl9TSVpFKTsKICAgICAgICBlbnZQdHIgPSBzdGF0aWNBbGxvYyhNQVhfRU5WX1ZBTFVFUyAqIDQpOwogICAgICAgIEhFQVAzMltlbnZQdHIgPj4gMl0gPSBwb29sUHRyOwogICAgICAgIEhFQVAzMltfZW52aXJvbiA+PiAyXSA9IGVudlB0cjsKICAgICAgfSBlbHNlIHsKICAgICAgICBlbnZQdHIgPSBIRUFQMzJbX2Vudmlyb24gPj4gMl07CiAgICAgICAgcG9vbFB0ciA9IEhFQVAzMltlbnZQdHIgPj4gMl07CiAgICAgIH0KICAgICAgdmFyIHN0cmluZ3MgPSBbXTsKICAgICAgdmFyIHRvdGFsU2l6ZSA9IDA7CiAgICAgIGZvciAodmFyIGtleSBpbiBlbnYpIHsKICAgICAgICBpZiAodHlwZW9mIGVudltrZXldID09PSAnc3RyaW5nJykgewogICAgICAgICAgdmFyIGxpbmUgPSBrZXkgKyAnPScgKyBlbnZba2V5XTsKICAgICAgICAgIHN0cmluZ3MucHVzaChsaW5lKTsKICAgICAgICAgIHRvdGFsU2l6ZSArPSBsaW5lLmxlbmd0aDsKICAgICAgICB9CiAgICAgIH0KICAgICAgaWYgKHRvdGFsU2l6ZSA+IFRPVEFMX0VOVl9TSVpFKSB7CiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdFbnZpcm9ubWVudCBzaXplIGV4Y2VlZGVkIFRPVEFMX0VOVl9TSVpFIScpCiAgICAgIH0KICAgICAgdmFyIHB0clNpemUgPSA0OwogICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHN0cmluZ3MubGVuZ3RoOyBpKyspIHsKICAgICAgICB2YXIgbGluZSA9IHN0cmluZ3NbaV07CiAgICAgICAgd3JpdGVBc2NpaVRvTWVtb3J5KGxpbmUsIHBvb2xQdHIpOwogICAgICAgIEhFQVAzMlsoZW52UHRyICsgaSAqIHB0clNpemUpID4+IDJdID0gcG9vbFB0cjsKICAgICAgICBwb29sUHRyICs9IGxpbmUubGVuZ3RoICsgMTsKICAgICAgfQogICAgICBIRUFQMzJbKGVudlB0ciArIHN0cmluZ3MubGVuZ3RoICogcHRyU2l6ZSkgPj4gMl0gPSAwOwogICAgfQogICAgdmFyIEVOViA9IHt9OwogICAgZnVuY3Rpb24gX2dldGVudihuYW1lKSB7CiAgICAgIGlmIChuYW1lID09PSAwKSByZXR1cm4gMAogICAgICBuYW1lID0gUG9pbnRlcl9zdHJpbmdpZnkobmFtZSk7CiAgICAgIGlmICghRU5WLmhhc093blByb3BlcnR5KG5hbWUpKSByZXR1cm4gMAogICAgICBpZiAoX2dldGVudi5yZXQpIF9mcmVlKF9nZXRlbnYucmV0KTsKICAgICAgX2dldGVudi5yZXQgPSBhbGxvY2F0ZVVURjgoRU5WW25hbWVdKTsKICAgICAgcmV0dXJuIF9nZXRlbnYucmV0CiAgICB9CiAgICBmdW5jdGlvbiBfZ2V0Z3JuYW0oKSB7CiAgICAgIE1vZHVsZVsncHJpbnRFcnInXSgnbWlzc2luZyBmdW5jdGlvbjogZ2V0Z3JuYW0nKTsKICAgICAgYWJvcnQoLTEpOwogICAgfQogICAgZnVuY3Rpb24gX2dldHB3bmFtKCkgewogICAgICB0aHJvdyAnZ2V0cHduYW06IFRPRE8nCiAgICB9CiAgICBmdW5jdGlvbiBfanNDbG9zZSgpIHsKICAgICAgcmV0dXJuIGpzQVBJLmNsb3NlLmFwcGx5KG51bGwsIGFyZ3VtZW50cykKICAgIH0KICAgIGZ1bmN0aW9uIF9qc0NyZWF0ZShmaWxlbmFtZSkgewogICAgICByZXR1cm4ganNBUEkuY3JlYXRlLmNhbGwobnVsbCwgVVRGMzJUb1N0cmluZyhmaWxlbmFtZSkpCiAgICB9CiAgICBmdW5jdGlvbiBfanNPcGVuKGZpbGVuYW1lKSB7CiAgICAgIHJldHVybiBqc0FQSS5vcGVuLmNhbGwobnVsbCwgVVRGMzJUb1N0cmluZyhmaWxlbmFtZSkpCiAgICB9CiAgICBmdW5jdGlvbiBfanNSZWFkKCkgewogICAgICByZXR1cm4ganNBUEkucmVhZC5hcHBseShudWxsLCBhcmd1bWVudHMpCiAgICB9CiAgICBmdW5jdGlvbiBfanNTZWVrKGZkLCBvZmZzZXQsIG1ldGhvZCkgewogICAgICByZXR1cm4ganNBUEkuc2Vlay5jYWxsKG51bGwsIGZkLCBvZmZzZXQsIFVURjhUb1N0cmluZyhtZXRob2QpKQogICAgfQogICAgZnVuY3Rpb24gX2pzVGVsbCgpIHsKICAgICAgcmV0dXJuIGpzQVBJLnRlbGwuYXBwbHkobnVsbCwgYXJndW1lbnRzKQogICAgfQogICAgZnVuY3Rpb24gX2pzV3JpdGUoKSB7CiAgICAgIHJldHVybiBqc0FQSS53cml0ZS5hcHBseShudWxsLCBhcmd1bWVudHMpCiAgICB9CiAgICBmdW5jdGlvbiBfbGx2bV9laF90eXBlaWRfZm9yKHR5cGUpIHsKICAgICAgcmV0dXJuIHR5cGUKICAgIH0KICAgIHZhciBfX190bV9jdXJyZW50ID0gU1RBVElDVE9QOwogICAgU1RBVElDVE9QICs9IDQ4OwogICAgYWxsb2NhdGUoaW50QXJyYXlGcm9tU3RyaW5nKCdHTVQnKSwgJ2k4JywgQUxMT0NfU1RBVElDKTsKICAgIHZhciBfdHpuYW1lID0gU1RBVElDVE9QOwogICAgU1RBVElDVE9QICs9IDE2OwogICAgdmFyIF9kYXlsaWdodCA9IFNUQVRJQ1RPUDsKICAgIFNUQVRJQ1RPUCArPSAxNjsKICAgIHZhciBfdGltZXpvbmUgPSBTVEFUSUNUT1A7CiAgICBTVEFUSUNUT1AgKz0gMTY7CiAgICBmdW5jdGlvbiBfdHpzZXQoKSB7CiAgICAgIGlmIChfdHpzZXQuY2FsbGVkKSByZXR1cm4KICAgICAgX3R6c2V0LmNhbGxlZCA9IHRydWU7CiAgICAgIEhFQVAzMltfdGltZXpvbmUgPj4gMl0gPSBuZXcgRGF0ZSgpLmdldFRpbWV6b25lT2Zmc2V0KCkgKiA2MDsKICAgICAgdmFyIHdpbnRlciA9IG5ldyBEYXRlKDJlMywgMCwgMSk7CiAgICAgIHZhciBzdW1tZXIgPSBuZXcgRGF0ZSgyZTMsIDYsIDEpOwogICAgICBIRUFQMzJbX2RheWxpZ2h0ID4+IDJdID0gTnVtYmVyKHdpbnRlci5nZXRUaW1lem9uZU9mZnNldCgpICE9IHN1bW1lci5nZXRUaW1lem9uZU9mZnNldCgpKTsKICAgICAgZnVuY3Rpb24gZXh0cmFjdFpvbmUoZGF0ZSkgewogICAgICAgIHZhciBtYXRjaCA9IGRhdGUudG9UaW1lU3RyaW5nKCkubWF0Y2goL1woKFtBLVphLXogXSspXCkkLyk7CiAgICAgICAgcmV0dXJuIG1hdGNoID8gbWF0Y2hbMV0gOiAnR01UJwogICAgICB9CiAgICAgIHZhciB3aW50ZXJOYW1lID0gZXh0cmFjdFpvbmUod2ludGVyKTsKICAgICAgdmFyIHN1bW1lck5hbWUgPSBleHRyYWN0Wm9uZShzdW1tZXIpOwogICAgICB2YXIgd2ludGVyTmFtZVB0ciA9IGFsbG9jYXRlKGludEFycmF5RnJvbVN0cmluZyh3aW50ZXJOYW1lKSwgJ2k4JywgQUxMT0NfTk9STUFMKTsKICAgICAgdmFyIHN1bW1lck5hbWVQdHIgPSBhbGxvY2F0ZShpbnRBcnJheUZyb21TdHJpbmcoc3VtbWVyTmFtZSksICdpOCcsIEFMTE9DX05PUk1BTCk7CiAgICAgIGlmIChzdW1tZXIuZ2V0VGltZXpvbmVPZmZzZXQoKSA8IHdpbnRlci5nZXRUaW1lem9uZU9mZnNldCgpKSB7CiAgICAgICAgSEVBUDMyW190em5hbWUgPj4gMl0gPSB3aW50ZXJOYW1lUHRyOwogICAgICAgIEhFQVAzMlsoX3R6bmFtZSArIDQpID4+IDJdID0gc3VtbWVyTmFtZVB0cjsKICAgICAgfSBlbHNlIHsKICAgICAgICBIRUFQMzJbX3R6bmFtZSA+PiAyXSA9IHN1bW1lck5hbWVQdHI7CiAgICAgICAgSEVBUDMyWyhfdHpuYW1lICsgNCkgPj4gMl0gPSB3aW50ZXJOYW1lUHRyOwogICAgICB9CiAgICB9CiAgICBmdW5jdGlvbiBfbG9jYWx0aW1lX3IodGltZSwgdG1QdHIpIHsKICAgICAgX3R6c2V0KCk7CiAgICAgIHZhciBkYXRlID0gbmV3IERhdGUoSEVBUDMyW3RpbWUgPj4gMl0gKiAxZTMpOwogICAgICBIRUFQMzJbdG1QdHIgPj4gMl0gPSBkYXRlLmdldFNlY29uZHMoKTsKICAgICAgSEVBUDMyWyh0bVB0ciArIDQpID4+IDJdID0gZGF0ZS5nZXRNaW51dGVzKCk7CiAgICAgIEhFQVAzMlsodG1QdHIgKyA4KSA+PiAyXSA9IGRhdGUuZ2V0SG91cnMoKTsKICAgICAgSEVBUDMyWyh0bVB0ciArIDEyKSA+PiAyXSA9IGRhdGUuZ2V0RGF0ZSgpOwogICAgICBIRUFQMzJbKHRtUHRyICsgMTYpID4+IDJdID0gZGF0ZS5nZXRNb250aCgpOwogICAgICBIRUFQMzJbKHRtUHRyICsgMjApID4+IDJdID0gZGF0ZS5nZXRGdWxsWWVhcigpIC0gMTkwMDsKICAgICAgSEVBUDMyWyh0bVB0ciArIDI0KSA+PiAyXSA9IGRhdGUuZ2V0RGF5KCk7CiAgICAgIHZhciBzdGFydCA9IG5ldyBEYXRlKGRhdGUuZ2V0RnVsbFllYXIoKSwgMCwgMSk7CiAgICAgIHZhciB5ZGF5ID0gKChkYXRlLmdldFRpbWUoKSAtIHN0YXJ0LmdldFRpbWUoKSkgLyAoMWUzICogNjAgKiA2MCAqIDI0KSkgfCAwOwogICAgICBIRUFQMzJbKHRtUHRyICsgMjgpID4+IDJdID0geWRheTsKICAgICAgSEVBUDMyWyh0bVB0ciArIDM2KSA+PiAyXSA9IC0oZGF0ZS5nZXRUaW1lem9uZU9mZnNldCgpICogNjApOwogICAgICB2YXIgc3VtbWVyT2Zmc2V0ID0gbmV3IERhdGUoMmUzLCA2LCAxKS5nZXRUaW1lem9uZU9mZnNldCgpOwogICAgICB2YXIgd2ludGVyT2Zmc2V0ID0gc3RhcnQuZ2V0VGltZXpvbmVPZmZzZXQoKTsKICAgICAgdmFyIGRzdCA9IChzdW1tZXJPZmZzZXQgIT0gd2ludGVyT2Zmc2V0ICYmIGRhdGUuZ2V0VGltZXpvbmVPZmZzZXQoKSA9PSBNYXRoLm1pbih3aW50ZXJPZmZzZXQsIHN1bW1lck9mZnNldCkpIHwgMDsKICAgICAgSEVBUDMyWyh0bVB0ciArIDMyKSA+PiAyXSA9IGRzdDsKICAgICAgdmFyIHpvbmVQdHIgPSBIRUFQMzJbKF90em5hbWUgKyAoZHN0ID8gNCA6IDApKSA+PiAyXTsKICAgICAgSEVBUDMyWyh0bVB0ciArIDQwKSA+PiAyXSA9IHpvbmVQdHI7CiAgICAgIHJldHVybiB0bVB0cgogICAgfQogICAgZnVuY3Rpb24gX2xvY2FsdGltZSh0aW1lKSB7CiAgICAgIHJldHVybiBfbG9jYWx0aW1lX3IodGltZSwgX19fdG1fY3VycmVudCkKICAgIH0KICAgIGZ1bmN0aW9uIF9lbXNjcmlwdGVuX21lbWNweV9iaWcoZGVzdCwgc3JjLCBudW0pIHsKICAgICAgSEVBUFU4LnNldChIRUFQVTguc3ViYXJyYXkoc3JjLCBzcmMgKyBudW0pLCBkZXN0KTsKICAgICAgcmV0dXJuIGRlc3QKICAgIH0KICAgIGZ1bmN0aW9uIF9ta3RpbWUodG1QdHIpIHsKICAgICAgX3R6c2V0KCk7CiAgICAgIHZhciBkYXRlID0gbmV3IERhdGUoCiAgICAgICAgSEVBUDMyWyh0bVB0ciArIDIwKSA+PiAyXSArIDE5MDAsCiAgICAgICAgSEVBUDMyWyh0bVB0ciArIDE2KSA+PiAyXSwKICAgICAgICBIRUFQMzJbKHRtUHRyICsgMTIpID4+IDJdLAogICAgICAgIEhFQVAzMlsodG1QdHIgKyA4KSA+PiAyXSwKICAgICAgICBIRUFQMzJbKHRtUHRyICsgNCkgPj4gMl0sCiAgICAgICAgSEVBUDMyW3RtUHRyID4+IDJdLAogICAgICAgIDAKICAgICAgKTsKICAgICAgdmFyIGRzdCA9IEhFQVAzMlsodG1QdHIgKyAzMikgPj4gMl07CiAgICAgIHZhciBndWVzc2VkT2Zmc2V0ID0gZGF0ZS5nZXRUaW1lem9uZU9mZnNldCgpOwogICAgICB2YXIgc3RhcnQgPSBuZXcgRGF0ZShkYXRlLmdldEZ1bGxZZWFyKCksIDAsIDEpOwogICAgICB2YXIgc3VtbWVyT2Zmc2V0ID0gbmV3IERhdGUoMmUzLCA2LCAxKS5nZXRUaW1lem9uZU9mZnNldCgpOwogICAgICB2YXIgd2ludGVyT2Zmc2V0ID0gc3RhcnQuZ2V0VGltZXpvbmVPZmZzZXQoKTsKICAgICAgdmFyIGRzdE9mZnNldCA9IE1hdGgubWluKHdpbnRlck9mZnNldCwgc3VtbWVyT2Zmc2V0KTsKICAgICAgaWYgKGRzdCA8IDApIHsKICAgICAgICBIRUFQMzJbKHRtUHRyICsgMzIpID4+IDJdID0gTnVtYmVyKHN1bW1lck9mZnNldCAhPSB3aW50ZXJPZmZzZXQgJiYgZHN0T2Zmc2V0ID09IGd1ZXNzZWRPZmZzZXQpOwogICAgICB9IGVsc2UgaWYgKGRzdCA+IDAgIT0gKGRzdE9mZnNldCA9PSBndWVzc2VkT2Zmc2V0KSkgewogICAgICAgIHZhciBub25Ec3RPZmZzZXQgPSBNYXRoLm1heCh3aW50ZXJPZmZzZXQsIHN1bW1lck9mZnNldCk7CiAgICAgICAgdmFyIHRydWVPZmZzZXQgPSBkc3QgPiAwID8gZHN0T2Zmc2V0IDogbm9uRHN0T2Zmc2V0OwogICAgICAgIGRhdGUuc2V0VGltZShkYXRlLmdldFRpbWUoKSArICh0cnVlT2Zmc2V0IC0gZ3Vlc3NlZE9mZnNldCkgKiA2ZTQpOwogICAgICB9CiAgICAgIEhFQVAzMlsodG1QdHIgKyAyNCkgPj4gMl0gPSBkYXRlLmdldERheSgpOwogICAgICB2YXIgeWRheSA9ICgoZGF0ZS5nZXRUaW1lKCkgLSBzdGFydC5nZXRUaW1lKCkpIC8gKDFlMyAqIDYwICogNjAgKiAyNCkpIHwgMDsKICAgICAgSEVBUDMyWyh0bVB0ciArIDI4KSA+PiAyXSA9IHlkYXk7CiAgICAgIHJldHVybiAoZGF0ZS5nZXRUaW1lKCkgLyAxZTMpIHwgMAogICAgfQogICAgdmFyIFBUSFJFQURfU1BFQ0lGSUMgPSB7fTsKICAgIGZ1bmN0aW9uIF9wdGhyZWFkX2dldHNwZWNpZmljKGtleSkgewogICAgICByZXR1cm4gUFRIUkVBRF9TUEVDSUZJQ1trZXldIHx8IDAKICAgIH0KICAgIHZhciBQVEhSRUFEX1NQRUNJRklDX05FWFRfS0VZID0gMTsKICAgIGZ1bmN0aW9uIF9wdGhyZWFkX2tleV9jcmVhdGUoa2V5LCBkZXN0cnVjdG9yKSB7CiAgICAgIGlmIChrZXkgPT0gMCkgewogICAgICAgIHJldHVybiBFUlJOT19DT0RFUy5FSU5WQUwKICAgICAgfQogICAgICBIRUFQMzJba2V5ID4+IDJdID0gUFRIUkVBRF9TUEVDSUZJQ19ORVhUX0tFWTsKICAgICAgUFRIUkVBRF9TUEVDSUZJQ1tQVEhSRUFEX1NQRUNJRklDX05FWFRfS0VZXSA9IDA7CiAgICAgIFBUSFJFQURfU1BFQ0lGSUNfTkVYVF9LRVkrKzsKICAgICAgcmV0dXJuIDAKICAgIH0KICAgIGZ1bmN0aW9uIF9wdGhyZWFkX29uY2UocHRyLCBmdW5jKSB7CiAgICAgIGlmICghX3B0aHJlYWRfb25jZS5zZWVuKSBfcHRocmVhZF9vbmNlLnNlZW4gPSB7fTsKICAgICAgaWYgKHB0ciBpbiBfcHRocmVhZF9vbmNlLnNlZW4pIHJldHVybgogICAgICBNb2R1bGVbJ2R5bkNhbGxfdiddKGZ1bmMpOwogICAgICBfcHRocmVhZF9vbmNlLnNlZW5bcHRyXSA9IDE7CiAgICB9CiAgICBmdW5jdGlvbiBfcHRocmVhZF9zZXRzcGVjaWZpYyhrZXksIHZhbHVlKSB7CiAgICAgIGlmICghKGtleSBpbiBQVEhSRUFEX1NQRUNJRklDKSkgewogICAgICAgIHJldHVybiBFUlJOT19DT0RFUy5FSU5WQUwKICAgICAgfQogICAgICBQVEhSRUFEX1NQRUNJRklDW2tleV0gPSB2YWx1ZTsKICAgICAgcmV0dXJuIDAKICAgIH0KICAgIGZ1bmN0aW9uIF90aW1lKHB0cikgewogICAgICB2YXIgcmV0ID0gKERhdGUubm93KCkgLyAxZTMpIHwgMDsKICAgICAgaWYgKHB0cikgewogICAgICAgIEhFQVAzMltwdHIgPj4gMl0gPSByZXQ7CiAgICAgIH0KICAgICAgcmV0dXJuIHJldAogICAgfQogICAgRlMuc3RhdGljSW5pdCgpOwogICAgX19BVElOSVRfXy51bnNoaWZ0KGZ1bmN0aW9uICgpIHsKICAgICAgaWYgKCFNb2R1bGVbJ25vRlNJbml0J10gJiYgIUZTLmluaXQuaW5pdGlhbGl6ZWQpIEZTLmluaXQoKTsKICAgIH0pOwogICAgX19BVE1BSU5fXy5wdXNoKGZ1bmN0aW9uICgpIHsKICAgICAgRlMuaWdub3JlUGVybWlzc2lvbnMgPSBmYWxzZTsKICAgIH0pOwogICAgX19BVEVYSVRfXy5wdXNoKGZ1bmN0aW9uICgpIHsKICAgICAgRlMucXVpdCgpOwogICAgfSk7CiAgICBfX0FUSU5JVF9fLnVuc2hpZnQoZnVuY3Rpb24gKCkgewogICAgfSk7CiAgICBfX0FURVhJVF9fLnB1c2goZnVuY3Rpb24gKCkgewogICAgfSk7CiAgICBJbnRlcm5hbEVycm9yID0gTW9kdWxlWydJbnRlcm5hbEVycm9yJ10gPSBleHRlbmRFcnJvcihFcnJvciwgJ0ludGVybmFsRXJyb3InKTsKICAgIGVtYmluZF9pbml0X2NoYXJDb2RlcygpOwogICAgQmluZGluZ0Vycm9yID0gTW9kdWxlWydCaW5kaW5nRXJyb3InXSA9IGV4dGVuZEVycm9yKEVycm9yLCAnQmluZGluZ0Vycm9yJyk7CiAgICBpbml0X0NsYXNzSGFuZGxlKCk7CiAgICBpbml0X1JlZ2lzdGVyZWRQb2ludGVyKCk7CiAgICBpbml0X2VtYmluZCgpOwogICAgVW5ib3VuZFR5cGVFcnJvciA9IE1vZHVsZVsnVW5ib3VuZFR5cGVFcnJvciddID0gZXh0ZW5kRXJyb3IoRXJyb3IsICdVbmJvdW5kVHlwZUVycm9yJyk7CiAgICBpbml0X2VtdmFsKCk7CiAgICBfX19idWlsZEVudmlyb25tZW50KEVOVik7CiAgICBEWU5BTUlDVE9QX1BUUiA9IHN0YXRpY0FsbG9jKDQpOwogICAgU1RBQ0tfQkFTRSA9IFNUQUNLVE9QID0gYWxpZ25NZW1vcnkoU1RBVElDVE9QKTsKICAgIFNUQUNLX01BWCA9IFNUQUNLX0JBU0UgKyBUT1RBTF9TVEFDSzsKICAgIERZTkFNSUNfQkFTRSA9IGFsaWduTWVtb3J5KFNUQUNLX01BWCk7CiAgICBIRUFQMzJbRFlOQU1JQ1RPUF9QVFIgPj4gMl0gPSBEWU5BTUlDX0JBU0U7CiAgICBzdGF0aWNTZWFsZWQgPSB0cnVlOwogICAgZnVuY3Rpb24gaW50QXJyYXlGcm9tU3RyaW5nKHN0cmluZ3ksIGRvbnRBZGROdWxsLCBsZW5ndGgpIHsKICAgICAgdmFyIGxlbiA9IGxlbmd0aCA+IDAgPyBsZW5ndGggOiBsZW5ndGhCeXRlc1VURjgoc3RyaW5neSkgKyAxOwogICAgICB2YXIgdThhcnJheSA9IG5ldyBBcnJheShsZW4pOwogICAgICB2YXIgbnVtQnl0ZXNXcml0dGVuID0gc3RyaW5nVG9VVEY4QXJyYXkoc3RyaW5neSwgdThhcnJheSwgMCwgdThhcnJheS5sZW5ndGgpOwogICAgICBpZiAoZG9udEFkZE51bGwpIHU4YXJyYXkubGVuZ3RoID0gbnVtQnl0ZXNXcml0dGVuOwogICAgICByZXR1cm4gdThhcnJheQogICAgfQogICAgTW9kdWxlWyd3YXNtVGFibGVTaXplJ10gPSAzMTY7CiAgICBNb2R1bGVbJ3dhc21NYXhUYWJsZVNpemUnXSA9IDMxNjsKICAgIGZ1bmN0aW9uIGludm9rZV9pKGluZGV4KSB7CiAgICAgIHRyeSB7CiAgICAgICAgcmV0dXJuIE1vZHVsZVsnZHluQ2FsbF9pJ10oaW5kZXgpCiAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICBpZiAodHlwZW9mIGUgIT09ICdudW1iZXInICYmIGUgIT09ICdsb25nam1wJykgdGhyb3cgZQogICAgICAgIE1vZHVsZVsnc2V0VGhyZXcnXSgxLCAwKTsKICAgICAgfQogICAgfQogICAgZnVuY3Rpb24gaW52b2tlX2lpKGluZGV4LCBhMSkgewogICAgICB0cnkgewogICAgICAgIHJldHVybiBNb2R1bGVbJ2R5bkNhbGxfaWknXShpbmRleCwgYTEpCiAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICBpZiAodHlwZW9mIGUgIT09ICdudW1iZXInICYmIGUgIT09ICdsb25nam1wJykgdGhyb3cgZQogICAgICAgIE1vZHVsZVsnc2V0VGhyZXcnXSgxLCAwKTsKICAgICAgfQogICAgfQogICAgZnVuY3Rpb24gaW52b2tlX2lpaShpbmRleCwgYTEsIGEyKSB7CiAgICAgIHRyeSB7CiAgICAgICAgcmV0dXJuIE1vZHVsZVsnZHluQ2FsbF9paWknXShpbmRleCwgYTEsIGEyKQogICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgaWYgKHR5cGVvZiBlICE9PSAnbnVtYmVyJyAmJiBlICE9PSAnbG9uZ2ptcCcpIHRocm93IGUKICAgICAgICBNb2R1bGVbJ3NldFRocmV3J10oMSwgMCk7CiAgICAgIH0KICAgIH0KICAgIGZ1bmN0aW9uIGludm9rZV9paWlpKGluZGV4LCBhMSwgYTIsIGEzKSB7CiAgICAgIHRyeSB7CiAgICAgICAgcmV0dXJuIE1vZHVsZVsnZHluQ2FsbF9paWlpJ10oaW5kZXgsIGExLCBhMiwgYTMpCiAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICBpZiAodHlwZW9mIGUgIT09ICdudW1iZXInICYmIGUgIT09ICdsb25nam1wJykgdGhyb3cgZQogICAgICAgIE1vZHVsZVsnc2V0VGhyZXcnXSgxLCAwKTsKICAgICAgfQogICAgfQogICAgZnVuY3Rpb24gaW52b2tlX2lpaWlpKGluZGV4LCBhMSwgYTIsIGEzLCBhNCkgewogICAgICB0cnkgewogICAgICAgIHJldHVybiBNb2R1bGVbJ2R5bkNhbGxfaWlpaWknXShpbmRleCwgYTEsIGEyLCBhMywgYTQpCiAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICBpZiAodHlwZW9mIGUgIT09ICdudW1iZXInICYmIGUgIT09ICdsb25nam1wJykgdGhyb3cgZQogICAgICAgIE1vZHVsZVsnc2V0VGhyZXcnXSgxLCAwKTsKICAgICAgfQogICAgfQogICAgZnVuY3Rpb24gaW52b2tlX2lpaWlpaWkoaW5kZXgsIGExLCBhMiwgYTMsIGE0LCBhNSwgYTYpIHsKICAgICAgdHJ5IHsKICAgICAgICByZXR1cm4gTW9kdWxlWydkeW5DYWxsX2lpaWlpaWknXShpbmRleCwgYTEsIGEyLCBhMywgYTQsIGE1LCBhNikKICAgICAgfSBjYXRjaCAoZSkgewogICAgICAgIGlmICh0eXBlb2YgZSAhPT0gJ251bWJlcicgJiYgZSAhPT0gJ2xvbmdqbXAnKSB0aHJvdyBlCiAgICAgICAgTW9kdWxlWydzZXRUaHJldyddKDEsIDApOwogICAgICB9CiAgICB9CiAgICBmdW5jdGlvbiBpbnZva2VfaWlpaWlpaWlpaShpbmRleCwgYTEsIGEyLCBhMywgYTQsIGE1LCBhNiwgYTcsIGE4LCBhOSkgewogICAgICB0cnkgewogICAgICAgIHJldHVybiBNb2R1bGVbJ2R5bkNhbGxfaWlpaWlpaWlpaSddKGluZGV4LCBhMSwgYTIsIGEzLCBhNCwgYTUsIGE2LCBhNywgYTgsIGE5KQogICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgaWYgKHR5cGVvZiBlICE9PSAnbnVtYmVyJyAmJiBlICE9PSAnbG9uZ2ptcCcpIHRocm93IGUKICAgICAgICBNb2R1bGVbJ3NldFRocmV3J10oMSwgMCk7CiAgICAgIH0KICAgIH0KICAgIGZ1bmN0aW9uIGludm9rZV9paWlpaWlqaWkoaW5kZXgsIGExLCBhMiwgYTMsIGE0LCBhNSwgYTYsIGE3LCBhOCwgYTkpIHsKICAgICAgdHJ5IHsKICAgICAgICByZXR1cm4gTW9kdWxlWydkeW5DYWxsX2lpaWlpaWppaSddKGluZGV4LCBhMSwgYTIsIGEzLCBhNCwgYTUsIGE2LCBhNywgYTgsIGE5KQogICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgaWYgKHR5cGVvZiBlICE9PSAnbnVtYmVyJyAmJiBlICE9PSAnbG9uZ2ptcCcpIHRocm93IGUKICAgICAgICBNb2R1bGVbJ3NldFRocmV3J10oMSwgMCk7CiAgICAgIH0KICAgIH0KICAgIGZ1bmN0aW9uIGludm9rZV9pamooaW5kZXgsIGExLCBhMiwgYTMsIGE0KSB7CiAgICAgIHRyeSB7CiAgICAgICAgcmV0dXJuIE1vZHVsZVsnZHluQ2FsbF9pamonXShpbmRleCwgYTEsIGEyLCBhMywgYTQpCiAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICBpZiAodHlwZW9mIGUgIT09ICdudW1iZXInICYmIGUgIT09ICdsb25nam1wJykgdGhyb3cgZQogICAgICAgIE1vZHVsZVsnc2V0VGhyZXcnXSgxLCAwKTsKICAgICAgfQogICAgfQogICAgZnVuY3Rpb24gaW52b2tlX2ppKGluZGV4LCBhMSkgewogICAgICB0cnkgewogICAgICAgIHJldHVybiBNb2R1bGVbJ2R5bkNhbGxfamknXShpbmRleCwgYTEpCiAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICBpZiAodHlwZW9mIGUgIT09ICdudW1iZXInICYmIGUgIT09ICdsb25nam1wJykgdGhyb3cgZQogICAgICAgIE1vZHVsZVsnc2V0VGhyZXcnXSgxLCAwKTsKICAgICAgfQogICAgfQogICAgZnVuY3Rpb24gaW52b2tlX3YoaW5kZXgpIHsKICAgICAgdHJ5IHsKICAgICAgICBNb2R1bGVbJ2R5bkNhbGxfdiddKGluZGV4KTsKICAgICAgfSBjYXRjaCAoZSkgewogICAgICAgIGlmICh0eXBlb2YgZSAhPT0gJ251bWJlcicgJiYgZSAhPT0gJ2xvbmdqbXAnKSB0aHJvdyBlCiAgICAgICAgTW9kdWxlWydzZXRUaHJldyddKDEsIDApOwogICAgICB9CiAgICB9CiAgICBmdW5jdGlvbiBpbnZva2VfdmkoaW5kZXgsIGExKSB7CiAgICAgIHRyeSB7CiAgICAgICAgTW9kdWxlWydkeW5DYWxsX3ZpJ10oaW5kZXgsIGExKTsKICAgICAgfSBjYXRjaCAoZSkgewogICAgICAgIGlmICh0eXBlb2YgZSAhPT0gJ251bWJlcicgJiYgZSAhPT0gJ2xvbmdqbXAnKSB0aHJvdyBlCiAgICAgICAgTW9kdWxlWydzZXRUaHJldyddKDEsIDApOwogICAgICB9CiAgICB9CiAgICBmdW5jdGlvbiBpbnZva2VfdmlpKGluZGV4LCBhMSwgYTIpIHsKICAgICAgdHJ5IHsKICAgICAgICBNb2R1bGVbJ2R5bkNhbGxfdmlpJ10oaW5kZXgsIGExLCBhMik7CiAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICBpZiAodHlwZW9mIGUgIT09ICdudW1iZXInICYmIGUgIT09ICdsb25nam1wJykgdGhyb3cgZQogICAgICAgIE1vZHVsZVsnc2V0VGhyZXcnXSgxLCAwKTsKICAgICAgfQogICAgfQogICAgZnVuY3Rpb24gaW52b2tlX3ZpaWkoaW5kZXgsIGExLCBhMiwgYTMpIHsKICAgICAgdHJ5IHsKICAgICAgICBNb2R1bGVbJ2R5bkNhbGxfdmlpaSddKGluZGV4LCBhMSwgYTIsIGEzKTsKICAgICAgfSBjYXRjaCAoZSkgewogICAgICAgIGlmICh0eXBlb2YgZSAhPT0gJ251bWJlcicgJiYgZSAhPT0gJ2xvbmdqbXAnKSB0aHJvdyBlCiAgICAgICAgTW9kdWxlWydzZXRUaHJldyddKDEsIDApOwogICAgICB9CiAgICB9CiAgICBmdW5jdGlvbiBpbnZva2VfdmlpaWkoaW5kZXgsIGExLCBhMiwgYTMsIGE0KSB7CiAgICAgIHRyeSB7CiAgICAgICAgTW9kdWxlWydkeW5DYWxsX3ZpaWlpJ10oaW5kZXgsIGExLCBhMiwgYTMsIGE0KTsKICAgICAgfSBjYXRjaCAoZSkgewogICAgICAgIGlmICh0eXBlb2YgZSAhPT0gJ251bWJlcicgJiYgZSAhPT0gJ2xvbmdqbXAnKSB0aHJvdyBlCiAgICAgICAgTW9kdWxlWydzZXRUaHJldyddKDEsIDApOwogICAgICB9CiAgICB9CiAgICBmdW5jdGlvbiBpbnZva2VfdmlpaWlpKGluZGV4LCBhMSwgYTIsIGEzLCBhNCwgYTUpIHsKICAgICAgdHJ5IHsKICAgICAgICBNb2R1bGVbJ2R5bkNhbGxfdmlpaWlpJ10oaW5kZXgsIGExLCBhMiwgYTMsIGE0LCBhNSk7CiAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICBpZiAodHlwZW9mIGUgIT09ICdudW1iZXInICYmIGUgIT09ICdsb25nam1wJykgdGhyb3cgZQogICAgICAgIE1vZHVsZVsnc2V0VGhyZXcnXSgxLCAwKTsKICAgICAgfQogICAgfQogICAgZnVuY3Rpb24gaW52b2tlX3ZpaWlpaWkoaW5kZXgsIGExLCBhMiwgYTMsIGE0LCBhNSwgYTYpIHsKICAgICAgdHJ5IHsKICAgICAgICBNb2R1bGVbJ2R5bkNhbGxfdmlpaWlpaSddKGluZGV4LCBhMSwgYTIsIGEzLCBhNCwgYTUsIGE2KTsKICAgICAgfSBjYXRjaCAoZSkgewogICAgICAgIGlmICh0eXBlb2YgZSAhPT0gJ251bWJlcicgJiYgZSAhPT0gJ2xvbmdqbXAnKSB0aHJvdyBlCiAgICAgICAgTW9kdWxlWydzZXRUaHJldyddKDEsIDApOwogICAgICB9CiAgICB9CiAgICBmdW5jdGlvbiBpbnZva2VfdmlpaWlpaWlpaShpbmRleCwgYTEsIGEyLCBhMywgYTQsIGE1LCBhNiwgYTcsIGE4LCBhOSkgewogICAgICB0cnkgewogICAgICAgIE1vZHVsZVsnZHluQ2FsbF92aWlpaWlpaWlpJ10oaW5kZXgsIGExLCBhMiwgYTMsIGE0LCBhNSwgYTYsIGE3LCBhOCwgYTkpOwogICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgaWYgKHR5cGVvZiBlICE9PSAnbnVtYmVyJyAmJiBlICE9PSAnbG9uZ2ptcCcpIHRocm93IGUKICAgICAgICBNb2R1bGVbJ3NldFRocmV3J10oMSwgMCk7CiAgICAgIH0KICAgIH0KICAgIGZ1bmN0aW9uIGludm9rZV92aWlpaWlpaWlpaShpbmRleCwgYTEsIGEyLCBhMywgYTQsIGE1LCBhNiwgYTcsIGE4LCBhOSwgYTEwKSB7CiAgICAgIHRyeSB7CiAgICAgICAgTW9kdWxlWydkeW5DYWxsX3ZpaWlpaWlpaWlpJ10oaW5kZXgsIGExLCBhMiwgYTMsIGE0LCBhNSwgYTYsIGE3LCBhOCwgYTksIGExMCk7CiAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICBpZiAodHlwZW9mIGUgIT09ICdudW1iZXInICYmIGUgIT09ICdsb25nam1wJykgdGhyb3cgZQogICAgICAgIE1vZHVsZVsnc2V0VGhyZXcnXSgxLCAwKTsKICAgICAgfQogICAgfQogICAgZnVuY3Rpb24gaW52b2tlX3ZpaihpbmRleCwgYTEsIGEyLCBhMykgewogICAgICB0cnkgewogICAgICAgIE1vZHVsZVsnZHluQ2FsbF92aWonXShpbmRleCwgYTEsIGEyLCBhMyk7CiAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICBpZiAodHlwZW9mIGUgIT09ICdudW1iZXInICYmIGUgIT09ICdsb25nam1wJykgdGhyb3cgZQogICAgICAgIE1vZHVsZVsnc2V0VGhyZXcnXSgxLCAwKTsKICAgICAgfQogICAgfQogICAgZnVuY3Rpb24gaW52b2tlX3ZpamkoaW5kZXgsIGExLCBhMiwgYTMsIGE0KSB7CiAgICAgIHRyeSB7CiAgICAgICAgTW9kdWxlWydkeW5DYWxsX3ZpamknXShpbmRleCwgYTEsIGEyLCBhMywgYTQpOwogICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgaWYgKHR5cGVvZiBlICE9PSAnbnVtYmVyJyAmJiBlICE9PSAnbG9uZ2ptcCcpIHRocm93IGUKICAgICAgICBNb2R1bGVbJ3NldFRocmV3J10oMSwgMCk7CiAgICAgIH0KICAgIH0KICAgIE1vZHVsZS5hc21HbG9iYWxBcmcgPSB7fTsKICAgIE1vZHVsZS5hc21MaWJyYXJ5QXJnID0gewogICAgICBhYm9ydDogYWJvcnQsCiAgICAgIGVubGFyZ2VNZW1vcnk6IGVubGFyZ2VNZW1vcnksCiAgICAgIGdldFRvdGFsTWVtb3J5OiBnZXRUb3RhbE1lbW9yeSwKICAgICAgYWJvcnRPbkNhbm5vdEdyb3dNZW1vcnk6IGFib3J0T25DYW5ub3RHcm93TWVtb3J5LAogICAgICBpbnZva2VfaTogaW52b2tlX2ksCiAgICAgIGludm9rZV9paTogaW52b2tlX2lpLAogICAgICBpbnZva2VfaWlpOiBpbnZva2VfaWlpLAogICAgICBpbnZva2VfaWlpaTogaW52b2tlX2lpaWksCiAgICAgIGludm9rZV9paWlpaTogaW52b2tlX2lpaWlpLAogICAgICBpbnZva2VfaWlpaWlpaTogaW52b2tlX2lpaWlpaWksCiAgICAgIGludm9rZV9paWlpaWlpaWlpOiBpbnZva2VfaWlpaWlpaWlpaSwKICAgICAgaW52b2tlX2lpaWlpaWppaTogaW52b2tlX2lpaWlpaWppaSwKICAgICAgaW52b2tlX2lqajogaW52b2tlX2lqaiwKICAgICAgaW52b2tlX2ppOiBpbnZva2VfamksCiAgICAgIGludm9rZV92OiBpbnZva2VfdiwKICAgICAgaW52b2tlX3ZpOiBpbnZva2VfdmksCiAgICAgIGludm9rZV92aWk6IGludm9rZV92aWksCiAgICAgIGludm9rZV92aWlpOiBpbnZva2VfdmlpaSwKICAgICAgaW52b2tlX3ZpaWlpOiBpbnZva2VfdmlpaWksCiAgICAgIGludm9rZV92aWlpaWk6IGludm9rZV92aWlpaWksCiAgICAgIGludm9rZV92aWlpaWlpOiBpbnZva2VfdmlpaWlpaSwKICAgICAgaW52b2tlX3ZpaWlpaWlpaWk6IGludm9rZV92aWlpaWlpaWlpLAogICAgICBpbnZva2VfdmlpaWlpaWlpaWk6IGludm9rZV92aWlpaWlpaWlpaSwKICAgICAgaW52b2tlX3ZpajogaW52b2tlX3ZpaiwKICAgICAgaW52b2tlX3Zpamk6IGludm9rZV92aWppLAogICAgICBfX19jeGFfYWxsb2NhdGVfZXhjZXB0aW9uOiBfX19jeGFfYWxsb2NhdGVfZXhjZXB0aW9uLAogICAgICBfX19jeGFfYmVnaW5fY2F0Y2g6IF9fX2N4YV9iZWdpbl9jYXRjaCwKICAgICAgX19fY3hhX2VuZF9jYXRjaDogX19fY3hhX2VuZF9jYXRjaCwKICAgICAgX19fY3hhX2ZpbmRfbWF0Y2hpbmdfY2F0Y2hfMjogX19fY3hhX2ZpbmRfbWF0Y2hpbmdfY2F0Y2hfMiwKICAgICAgX19fY3hhX2ZpbmRfbWF0Y2hpbmdfY2F0Y2hfMzogX19fY3hhX2ZpbmRfbWF0Y2hpbmdfY2F0Y2hfMywKICAgICAgX19fY3hhX2ZpbmRfbWF0Y2hpbmdfY2F0Y2hfNDogX19fY3hhX2ZpbmRfbWF0Y2hpbmdfY2F0Y2hfNCwKICAgICAgX19fY3hhX2ZyZWVfZXhjZXB0aW9uOiBfX19jeGFfZnJlZV9leGNlcHRpb24sCiAgICAgIF9fX2N4YV90aHJvdzogX19fY3hhX3Rocm93LAogICAgICBfX19sb2NrOiBfX19sb2NrLAogICAgICBfX19tYXBfZmlsZTogX19fbWFwX2ZpbGUsCiAgICAgIF9fX3Jlc3VtZUV4Y2VwdGlvbjogX19fcmVzdW1lRXhjZXB0aW9uLAogICAgICBfX19zZXRFcnJObzogX19fc2V0RXJyTm8sCiAgICAgIF9fX3N5c2NhbGwxNDA6IF9fX3N5c2NhbGwxNDAsCiAgICAgIF9fX3N5c2NhbGwxNDU6IF9fX3N5c2NhbGwxNDUsCiAgICAgIF9fX3N5c2NhbGwxNDY6IF9fX3N5c2NhbGwxNDYsCiAgICAgIF9fX3N5c2NhbGwxODM6IF9fX3N5c2NhbGwxODMsCiAgICAgIF9fX3N5c2NhbGwxOTg6IF9fX3N5c2NhbGwxOTgsCiAgICAgIF9fX3N5c2NhbGwyMDogX19fc3lzY2FsbDIwLAogICAgICBfX19zeXNjYWxsNjogX19fc3lzY2FsbDYsCiAgICAgIF9fX3N5c2NhbGw2MDogX19fc3lzY2FsbDYwLAogICAgICBfX19zeXNjYWxsODM6IF9fX3N5c2NhbGw4MywKICAgICAgX19fc3lzY2FsbDkxOiBfX19zeXNjYWxsOTEsCiAgICAgIF9fX3VubG9jazogX19fdW5sb2NrLAogICAgICBfX2VtYmluZF9maW5hbGl6ZV92YWx1ZV9vYmplY3Q6IF9fZW1iaW5kX2ZpbmFsaXplX3ZhbHVlX29iamVjdCwKICAgICAgX19lbWJpbmRfcmVnaXN0ZXJfYm9vbDogX19lbWJpbmRfcmVnaXN0ZXJfYm9vbCwKICAgICAgX19lbWJpbmRfcmVnaXN0ZXJfY2xhc3M6IF9fZW1iaW5kX3JlZ2lzdGVyX2NsYXNzLAogICAgICBfX2VtYmluZF9yZWdpc3Rlcl9jbGFzc19jb25zdHJ1Y3RvcjogX19lbWJpbmRfcmVnaXN0ZXJfY2xhc3NfY29uc3RydWN0b3IsCiAgICAgIF9fZW1iaW5kX3JlZ2lzdGVyX2NsYXNzX2Z1bmN0aW9uOiBfX2VtYmluZF9yZWdpc3Rlcl9jbGFzc19mdW5jdGlvbiwKICAgICAgX19lbWJpbmRfcmVnaXN0ZXJfZW12YWw6IF9fZW1iaW5kX3JlZ2lzdGVyX2VtdmFsLAogICAgICBfX2VtYmluZF9yZWdpc3Rlcl9mbG9hdDogX19lbWJpbmRfcmVnaXN0ZXJfZmxvYXQsCiAgICAgIF9fZW1iaW5kX3JlZ2lzdGVyX2ludGVnZXI6IF9fZW1iaW5kX3JlZ2lzdGVyX2ludGVnZXIsCiAgICAgIF9fZW1iaW5kX3JlZ2lzdGVyX21lbW9yeV92aWV3OiBfX2VtYmluZF9yZWdpc3Rlcl9tZW1vcnlfdmlldywKICAgICAgX19lbWJpbmRfcmVnaXN0ZXJfc3RkX3N0cmluZzogX19lbWJpbmRfcmVnaXN0ZXJfc3RkX3N0cmluZywKICAgICAgX19lbWJpbmRfcmVnaXN0ZXJfc3RkX3dzdHJpbmc6IF9fZW1iaW5kX3JlZ2lzdGVyX3N0ZF93c3RyaW5nLAogICAgICBfX2VtYmluZF9yZWdpc3Rlcl92YWx1ZV9vYmplY3Q6IF9fZW1iaW5kX3JlZ2lzdGVyX3ZhbHVlX29iamVjdCwKICAgICAgX19lbWJpbmRfcmVnaXN0ZXJfdmFsdWVfb2JqZWN0X2ZpZWxkOiBfX2VtYmluZF9yZWdpc3Rlcl92YWx1ZV9vYmplY3RfZmllbGQsCiAgICAgIF9fZW1iaW5kX3JlZ2lzdGVyX3ZvaWQ6IF9fZW1iaW5kX3JlZ2lzdGVyX3ZvaWQsCiAgICAgIF9hYm9ydDogX2Fib3J0LAogICAgICBfZW1zY3JpcHRlbl9tZW1jcHlfYmlnOiBfZW1zY3JpcHRlbl9tZW1jcHlfYmlnLAogICAgICBfZ2V0ZW52OiBfZ2V0ZW52LAogICAgICBfZ2V0Z3JuYW06IF9nZXRncm5hbSwKICAgICAgX2dldHB3bmFtOiBfZ2V0cHduYW0sCiAgICAgIF9qc0Nsb3NlOiBfanNDbG9zZSwKICAgICAgX2pzQ3JlYXRlOiBfanNDcmVhdGUsCiAgICAgIF9qc09wZW46IF9qc09wZW4sCiAgICAgIF9qc1JlYWQ6IF9qc1JlYWQsCiAgICAgIF9qc1NlZWs6IF9qc1NlZWssCiAgICAgIF9qc1RlbGw6IF9qc1RlbGwsCiAgICAgIF9qc1dyaXRlOiBfanNXcml0ZSwKICAgICAgX2xsdm1fZWhfdHlwZWlkX2ZvcjogX2xsdm1fZWhfdHlwZWlkX2ZvciwKICAgICAgX2xvY2FsdGltZTogX2xvY2FsdGltZSwKICAgICAgX21rdGltZTogX21rdGltZSwKICAgICAgX3B0aHJlYWRfZ2V0c3BlY2lmaWM6IF9wdGhyZWFkX2dldHNwZWNpZmljLAogICAgICBfcHRocmVhZF9rZXlfY3JlYXRlOiBfcHRocmVhZF9rZXlfY3JlYXRlLAogICAgICBfcHRocmVhZF9vbmNlOiBfcHRocmVhZF9vbmNlLAogICAgICBfcHRocmVhZF9zZXRzcGVjaWZpYzogX3B0aHJlYWRfc2V0c3BlY2lmaWMsCiAgICAgIF90aW1lOiBfdGltZSwKICAgICAgRFlOQU1JQ1RPUF9QVFI6IERZTkFNSUNUT1BfUFRSLAogICAgICBTVEFDS1RPUDogU1RBQ0tUT1AsCiAgICB9OwogICAgdmFyIGFzbSA9IE1vZHVsZVsnYXNtJ10oTW9kdWxlLmFzbUdsb2JhbEFyZywgTW9kdWxlLmFzbUxpYnJhcnlBcmcsIGJ1ZmZlcik7CiAgICBNb2R1bGVbJ2FzbSddID0gYXNtOwogICAgdmFyIF9fR0xPQkFMX19zdWJfSV9iaW5kX2NwcCA9IChNb2R1bGVbJ19fR0xPQkFMX19zdWJfSV9iaW5kX2NwcCddID0gZnVuY3Rpb24gKCkgewogICAgICByZXR1cm4gTW9kdWxlWydhc20nXVsnX19HTE9CQUxfX3N1Yl9JX2JpbmRfY3BwJ10uYXBwbHkobnVsbCwgYXJndW1lbnRzKQogICAgfSk7CiAgICB2YXIgX19HTE9CQUxfX3N1Yl9JX2JyaWRnZV9jcHAgPSAoTW9kdWxlWydfX0dMT0JBTF9fc3ViX0lfYnJpZGdlX2NwcCddID0gZnVuY3Rpb24gKCkgewogICAgICByZXR1cm4gTW9kdWxlWydhc20nXVsnX19HTE9CQUxfX3N1Yl9JX2JyaWRnZV9jcHAnXS5hcHBseShudWxsLCBhcmd1bWVudHMpCiAgICB9KTsKICAgIHZhciBfX0dMT0JBTF9fc3ViX0lfY3JjX2NwcCA9IChNb2R1bGVbJ19fR0xPQkFMX19zdWJfSV9jcmNfY3BwJ10gPSBmdW5jdGlvbiAoKSB7CiAgICAgIHJldHVybiBNb2R1bGVbJ2FzbSddWydfX0dMT0JBTF9fc3ViX0lfY3JjX2NwcCddLmFwcGx5KG51bGwsIGFyZ3VtZW50cykKICAgIH0pOwogICAgdmFyIF9fR0xPQkFMX19zdWJfSV9nbG9iYWxfY3BwID0gKE1vZHVsZVsnX19HTE9CQUxfX3N1Yl9JX2dsb2JhbF9jcHAnXSA9IGZ1bmN0aW9uICgpIHsKICAgICAgcmV0dXJuIE1vZHVsZVsnYXNtJ11bJ19fR0xPQkFMX19zdWJfSV9nbG9iYWxfY3BwJ10uYXBwbHkobnVsbCwgYXJndW1lbnRzKQogICAgfSk7CiAgICAoTW9kdWxlWydfX19jeGFfY2FuX2NhdGNoJ10gPSBmdW5jdGlvbiAoKSB7CiAgICAgIHJldHVybiBNb2R1bGVbJ2FzbSddWydfX19jeGFfY2FuX2NhdGNoJ10uYXBwbHkobnVsbCwgYXJndW1lbnRzKQogICAgfSk7CiAgICAoTW9kdWxlWydfX19jeGFfaXNfcG9pbnRlcl90eXBlJ10gPSBmdW5jdGlvbiAoKSB7CiAgICAgIHJldHVybiBNb2R1bGVbJ2FzbSddWydfX19jeGFfaXNfcG9pbnRlcl90eXBlJ10uYXBwbHkobnVsbCwgYXJndW1lbnRzKQogICAgfSk7CiAgICAoTW9kdWxlWydfX19lcnJub19sb2NhdGlvbiddID0gZnVuY3Rpb24gKCkgewogICAgICByZXR1cm4gTW9kdWxlWydhc20nXVsnX19fZXJybm9fbG9jYXRpb24nXS5hcHBseShudWxsLCBhcmd1bWVudHMpCiAgICB9KTsKICAgIHZhciBfX19nZXRUeXBlTmFtZSA9IChNb2R1bGVbJ19fX2dldFR5cGVOYW1lJ10gPSBmdW5jdGlvbiAoKSB7CiAgICAgIHJldHVybiBNb2R1bGVbJ2FzbSddWydfX19nZXRUeXBlTmFtZSddLmFwcGx5KG51bGwsIGFyZ3VtZW50cykKICAgIH0pOwogICAgdmFyIF9lbXNjcmlwdGVuX3JlcGxhY2VfbWVtb3J5ID0gKE1vZHVsZVsnX2Vtc2NyaXB0ZW5fcmVwbGFjZV9tZW1vcnknXSA9IGZ1bmN0aW9uICgpIHsKICAgICAgcmV0dXJuIE1vZHVsZVsnYXNtJ11bJ19lbXNjcmlwdGVuX3JlcGxhY2VfbWVtb3J5J10uYXBwbHkobnVsbCwgYXJndW1lbnRzKQogICAgfSk7CiAgICB2YXIgX2ZyZWUgPSAoTW9kdWxlWydfZnJlZSddID0gZnVuY3Rpb24gKCkgewogICAgICByZXR1cm4gTW9kdWxlWydhc20nXVsnX2ZyZWUnXS5hcHBseShudWxsLCBhcmd1bWVudHMpCiAgICB9KTsKICAgIHZhciBfbWFsbG9jID0gKE1vZHVsZVsnX21hbGxvYyddID0gZnVuY3Rpb24gKCkgewogICAgICByZXR1cm4gTW9kdWxlWydhc20nXVsnX21hbGxvYyddLmFwcGx5KG51bGwsIGFyZ3VtZW50cykKICAgIH0pOwogICAgdmFyIHNldFRlbXBSZXQwID0gKE1vZHVsZVsnc2V0VGVtcFJldDAnXSA9IGZ1bmN0aW9uICgpIHsKICAgICAgcmV0dXJuIE1vZHVsZVsnYXNtJ11bJ3NldFRlbXBSZXQwJ10uYXBwbHkobnVsbCwgYXJndW1lbnRzKQogICAgfSk7CiAgICAoTW9kdWxlWydzZXRUaHJldyddID0gZnVuY3Rpb24gKCkgewogICAgICByZXR1cm4gTW9kdWxlWydhc20nXVsnc2V0VGhyZXcnXS5hcHBseShudWxsLCBhcmd1bWVudHMpCiAgICB9KTsKICAgIHZhciBzdGFja0FsbG9jID0gKE1vZHVsZVsnc3RhY2tBbGxvYyddID0gZnVuY3Rpb24gKCkgewogICAgICByZXR1cm4gTW9kdWxlWydhc20nXVsnc3RhY2tBbGxvYyddLmFwcGx5KG51bGwsIGFyZ3VtZW50cykKICAgIH0pOwogICAgKE1vZHVsZVsnZHluQ2FsbF9kaWknXSA9IGZ1bmN0aW9uICgpIHsKICAgICAgcmV0dXJuIE1vZHVsZVsnYXNtJ11bJ2R5bkNhbGxfZGlpJ10uYXBwbHkobnVsbCwgYXJndW1lbnRzKQogICAgfSk7CiAgICAoTW9kdWxlWydkeW5DYWxsX2knXSA9IGZ1bmN0aW9uICgpIHsKICAgICAgcmV0dXJuIE1vZHVsZVsnYXNtJ11bJ2R5bkNhbGxfaSddLmFwcGx5KG51bGwsIGFyZ3VtZW50cykKICAgIH0pOwogICAgKE1vZHVsZVsnZHluQ2FsbF9paSddID0gZnVuY3Rpb24gKCkgewogICAgICByZXR1cm4gTW9kdWxlWydhc20nXVsnZHluQ2FsbF9paSddLmFwcGx5KG51bGwsIGFyZ3VtZW50cykKICAgIH0pOwogICAgKE1vZHVsZVsnZHluQ2FsbF9paWknXSA9IGZ1bmN0aW9uICgpIHsKICAgICAgcmV0dXJuIE1vZHVsZVsnYXNtJ11bJ2R5bkNhbGxfaWlpJ10uYXBwbHkobnVsbCwgYXJndW1lbnRzKQogICAgfSk7CiAgICAoTW9kdWxlWydkeW5DYWxsX2lpaWknXSA9IGZ1bmN0aW9uICgpIHsKICAgICAgcmV0dXJuIE1vZHVsZVsnYXNtJ11bJ2R5bkNhbGxfaWlpaSddLmFwcGx5KG51bGwsIGFyZ3VtZW50cykKICAgIH0pOwogICAgKE1vZHVsZVsnZHluQ2FsbF9paWlpaSddID0gZnVuY3Rpb24gKCkgewogICAgICByZXR1cm4gTW9kdWxlWydhc20nXVsnZHluQ2FsbF9paWlpaSddLmFwcGx5KG51bGwsIGFyZ3VtZW50cykKICAgIH0pOwogICAgKE1vZHVsZVsnZHluQ2FsbF9paWlpaWknXSA9IGZ1bmN0aW9uICgpIHsKICAgICAgcmV0dXJuIE1vZHVsZVsnYXNtJ11bJ2R5bkNhbGxfaWlpaWlpJ10uYXBwbHkobnVsbCwgYXJndW1lbnRzKQogICAgfSk7CiAgICAoTW9kdWxlWydkeW5DYWxsX2lpaWlpaWknXSA9IGZ1bmN0aW9uICgpIHsKICAgICAgcmV0dXJuIE1vZHVsZVsnYXNtJ11bJ2R5bkNhbGxfaWlpaWlpaSddLmFwcGx5KG51bGwsIGFyZ3VtZW50cykKICAgIH0pOwogICAgKE1vZHVsZVsnZHluQ2FsbF9paWlpaWlpaWlpJ10gPSBmdW5jdGlvbiAoKSB7CiAgICAgIHJldHVybiBNb2R1bGVbJ2FzbSddWydkeW5DYWxsX2lpaWlpaWlpaWknXS5hcHBseShudWxsLCBhcmd1bWVudHMpCiAgICB9KTsKICAgIChNb2R1bGVbJ2R5bkNhbGxfaWlpaWlpamlpJ10gPSBmdW5jdGlvbiAoKSB7CiAgICAgIHJldHVybiBNb2R1bGVbJ2FzbSddWydkeW5DYWxsX2lpaWlpaWppaSddLmFwcGx5KG51bGwsIGFyZ3VtZW50cykKICAgIH0pOwogICAgKE1vZHVsZVsnZHluQ2FsbF9pamonXSA9IGZ1bmN0aW9uICgpIHsKICAgICAgcmV0dXJuIE1vZHVsZVsnYXNtJ11bJ2R5bkNhbGxfaWpqJ10uYXBwbHkobnVsbCwgYXJndW1lbnRzKQogICAgfSk7CiAgICAoTW9kdWxlWydkeW5DYWxsX2ppJ10gPSBmdW5jdGlvbiAoKSB7CiAgICAgIHJldHVybiBNb2R1bGVbJ2FzbSddWydkeW5DYWxsX2ppJ10uYXBwbHkobnVsbCwgYXJndW1lbnRzKQogICAgfSk7CiAgICAoTW9kdWxlWydkeW5DYWxsX3YnXSA9IGZ1bmN0aW9uICgpIHsKICAgICAgcmV0dXJuIE1vZHVsZVsnYXNtJ11bJ2R5bkNhbGxfdiddLmFwcGx5KG51bGwsIGFyZ3VtZW50cykKICAgIH0pOwogICAgKE1vZHVsZVsnZHluQ2FsbF92aSddID0gZnVuY3Rpb24gKCkgewogICAgICByZXR1cm4gTW9kdWxlWydhc20nXVsnZHluQ2FsbF92aSddLmFwcGx5KG51bGwsIGFyZ3VtZW50cykKICAgIH0pOwogICAgKE1vZHVsZVsnZHluQ2FsbF92aWknXSA9IGZ1bmN0aW9uICgpIHsKICAgICAgcmV0dXJuIE1vZHVsZVsnYXNtJ11bJ2R5bkNhbGxfdmlpJ10uYXBwbHkobnVsbCwgYXJndW1lbnRzKQogICAgfSk7CiAgICAoTW9kdWxlWydkeW5DYWxsX3ZpaWQnXSA9IGZ1bmN0aW9uICgpIHsKICAgICAgcmV0dXJuIE1vZHVsZVsnYXNtJ11bJ2R5bkNhbGxfdmlpZCddLmFwcGx5KG51bGwsIGFyZ3VtZW50cykKICAgIH0pOwogICAgKE1vZHVsZVsnZHluQ2FsbF92aWlpJ10gPSBmdW5jdGlvbiAoKSB7CiAgICAgIHJldHVybiBNb2R1bGVbJ2FzbSddWydkeW5DYWxsX3ZpaWknXS5hcHBseShudWxsLCBhcmd1bWVudHMpCiAgICB9KTsKICAgIChNb2R1bGVbJ2R5bkNhbGxfdmlpaWknXSA9IGZ1bmN0aW9uICgpIHsKICAgICAgcmV0dXJuIE1vZHVsZVsnYXNtJ11bJ2R5bkNhbGxfdmlpaWknXS5hcHBseShudWxsLCBhcmd1bWVudHMpCiAgICB9KTsKICAgIChNb2R1bGVbJ2R5bkNhbGxfdmlpaWlpJ10gPSBmdW5jdGlvbiAoKSB7CiAgICAgIHJldHVybiBNb2R1bGVbJ2FzbSddWydkeW5DYWxsX3ZpaWlpaSddLmFwcGx5KG51bGwsIGFyZ3VtZW50cykKICAgIH0pOwogICAgKE1vZHVsZVsnZHluQ2FsbF92aWlpaWlpJ10gPSBmdW5jdGlvbiAoKSB7CiAgICAgIHJldHVybiBNb2R1bGVbJ2FzbSddWydkeW5DYWxsX3ZpaWlpaWknXS5hcHBseShudWxsLCBhcmd1bWVudHMpCiAgICB9KTsKICAgIChNb2R1bGVbJ2R5bkNhbGxfdmlpaWlpaWlpaSddID0gZnVuY3Rpb24gKCkgewogICAgICByZXR1cm4gTW9kdWxlWydhc20nXVsnZHluQ2FsbF92aWlpaWlpaWlpJ10uYXBwbHkobnVsbCwgYXJndW1lbnRzKQogICAgfSk7CiAgICAoTW9kdWxlWydkeW5DYWxsX3ZpaWlpaWlpaWlpJ10gPSBmdW5jdGlvbiAoKSB7CiAgICAgIHJldHVybiBNb2R1bGVbJ2FzbSddWydkeW5DYWxsX3ZpaWlpaWlpaWlpJ10uYXBwbHkobnVsbCwgYXJndW1lbnRzKQogICAgfSk7CiAgICAoTW9kdWxlWydkeW5DYWxsX3ZpaiddID0gZnVuY3Rpb24gKCkgewogICAgICByZXR1cm4gTW9kdWxlWydhc20nXVsnZHluQ2FsbF92aWonXS5hcHBseShudWxsLCBhcmd1bWVudHMpCiAgICB9KTsKICAgIChNb2R1bGVbJ2R5bkNhbGxfdmlqaSddID0gZnVuY3Rpb24gKCkgewogICAgICByZXR1cm4gTW9kdWxlWydhc20nXVsnZHluQ2FsbF92aWppJ10uYXBwbHkobnVsbCwgYXJndW1lbnRzKQogICAgfSk7CiAgICBNb2R1bGVbJ2FzbSddID0gYXNtOwogICAgZnVuY3Rpb24gRXhpdFN0YXR1cyhzdGF0dXMpIHsKICAgICAgdGhpcy5uYW1lID0gJ0V4aXRTdGF0dXMnOwogICAgICB0aGlzLm1lc3NhZ2UgPSAnUHJvZ3JhbSB0ZXJtaW5hdGVkIHdpdGggZXhpdCgnICsgc3RhdHVzICsgJyknOwogICAgICB0aGlzLnN0YXR1cyA9IHN0YXR1czsKICAgIH0KICAgIEV4aXRTdGF0dXMucHJvdG90eXBlID0gbmV3IEVycm9yKCk7CiAgICBFeGl0U3RhdHVzLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IEV4aXRTdGF0dXM7CiAgICB2YXIgaW5pdGlhbFN0YWNrVG9wOwogICAgZGVwZW5kZW5jaWVzRnVsZmlsbGVkID0gZnVuY3Rpb24gcnVuQ2FsbGVyKCkgewogICAgICBpZiAoIU1vZHVsZVsnY2FsbGVkUnVuJ10pIHJ1bigpOwogICAgICBpZiAoIU1vZHVsZVsnY2FsbGVkUnVuJ10pIGRlcGVuZGVuY2llc0Z1bGZpbGxlZCA9IHJ1bkNhbGxlcjsKICAgIH07CiAgICBmdW5jdGlvbiBydW4oYXJncykgewogICAgICBhcmdzID0gYXJncyB8fCBNb2R1bGVbJ2FyZ3VtZW50cyddOwogICAgICBpZiAocnVuRGVwZW5kZW5jaWVzID4gMCkgewogICAgICAgIHJldHVybgogICAgICB9CiAgICAgIHByZVJ1bigpOwogICAgICBpZiAocnVuRGVwZW5kZW5jaWVzID4gMCkgcmV0dXJuCiAgICAgIGlmIChNb2R1bGVbJ2NhbGxlZFJ1biddKSByZXR1cm4KICAgICAgZnVuY3Rpb24gZG9SdW4oKSB7CiAgICAgICAgaWYgKE1vZHVsZVsnY2FsbGVkUnVuJ10pIHJldHVybgogICAgICAgIE1vZHVsZVsnY2FsbGVkUnVuJ10gPSB0cnVlOwogICAgICAgIGlmIChBQk9SVCkgcmV0dXJuCiAgICAgICAgZW5zdXJlSW5pdFJ1bnRpbWUoKTsKICAgICAgICBwcmVNYWluKCk7CiAgICAgICAgaWYgKE1vZHVsZVsnb25SdW50aW1lSW5pdGlhbGl6ZWQnXSkgTW9kdWxlWydvblJ1bnRpbWVJbml0aWFsaXplZCddKCk7CiAgICAgICAgcG9zdFJ1bigpOwogICAgICB9CiAgICAgIGlmIChNb2R1bGVbJ3NldFN0YXR1cyddKSB7CiAgICAgICAgTW9kdWxlWydzZXRTdGF0dXMnXSgnUnVubmluZy4uLicpOwogICAgICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gKCkgewogICAgICAgICAgc2V0VGltZW91dChmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgIE1vZHVsZVsnc2V0U3RhdHVzJ10oJycpOwogICAgICAgICAgfSwgMSk7CiAgICAgICAgICBkb1J1bigpOwogICAgICAgIH0sIDEpOwogICAgICB9IGVsc2UgewogICAgICAgIGRvUnVuKCk7CiAgICAgIH0KICAgIH0KICAgIE1vZHVsZVsncnVuJ10gPSBydW47CiAgICBmdW5jdGlvbiBleGl0KHN0YXR1cywgaW1wbGljaXQpIHsKICAgICAgaWYgKGltcGxpY2l0ICYmIE1vZHVsZVsnbm9FeGl0UnVudGltZSddICYmIHN0YXR1cyA9PT0gMCkgewogICAgICAgIHJldHVybgogICAgICB9CiAgICAgIGlmIChNb2R1bGVbJ25vRXhpdFJ1bnRpbWUnXSkgOyBlbHNlIHsKICAgICAgICBBQk9SVCA9IHRydWU7CiAgICAgICAgU1RBQ0tUT1AgPSBpbml0aWFsU3RhY2tUb3A7CiAgICAgICAgZXhpdFJ1bnRpbWUoKTsKICAgICAgICBpZiAoTW9kdWxlWydvbkV4aXQnXSkgTW9kdWxlWydvbkV4aXQnXShzdGF0dXMpOwogICAgICB9CiAgICAgIGlmIChFTlZJUk9OTUVOVF9JU19OT0RFKSB7CiAgICAgICAgcHJvY2Vzc1snZXhpdCddKHN0YXR1cyk7CiAgICAgIH0KICAgICAgTW9kdWxlWydxdWl0J10oc3RhdHVzLCBuZXcgRXhpdFN0YXR1cyhzdGF0dXMpKTsKICAgIH0KICAgIE1vZHVsZVsnZXhpdCddID0gZXhpdDsKICAgIGZ1bmN0aW9uIGFib3J0KHdoYXQpIHsKICAgICAgaWYgKE1vZHVsZVsnb25BYm9ydCddKSB7CiAgICAgICAgTW9kdWxlWydvbkFib3J0J10od2hhdCk7CiAgICAgIH0KICAgICAgaWYgKHdoYXQgIT09IHVuZGVmaW5lZCkgewogICAgICAgIE1vZHVsZS5wcmludCh3aGF0KTsKICAgICAgICBNb2R1bGUucHJpbnRFcnIod2hhdCk7CiAgICAgICAgd2hhdCA9IEpTT04uc3RyaW5naWZ5KHdoYXQpOwogICAgICB9IGVsc2UgewogICAgICAgIHdoYXQgPSAnJzsKICAgICAgfQogICAgICBBQk9SVCA9IHRydWU7CiAgICAgIHRocm93ICdhYm9ydCgnICsgd2hhdCArICcpLiBCdWlsZCB3aXRoIC1zIEFTU0VSVElPTlM9MSBmb3IgbW9yZSBpbmZvLicKICAgIH0KICAgIE1vZHVsZVsnYWJvcnQnXSA9IGFib3J0OwogICAgaWYgKE1vZHVsZVsncHJlSW5pdCddKSB7CiAgICAgIGlmICh0eXBlb2YgTW9kdWxlWydwcmVJbml0J10gPT0gJ2Z1bmN0aW9uJykgTW9kdWxlWydwcmVJbml0J10gPSBbTW9kdWxlWydwcmVJbml0J11dOwogICAgICB3aGlsZSAoTW9kdWxlWydwcmVJbml0J10ubGVuZ3RoID4gMCkgewogICAgICAgIE1vZHVsZVsncHJlSW5pdCddLnBvcCgpKCk7CiAgICAgIH0KICAgIH0KICAgIE1vZHVsZVsnbm9FeGl0UnVudGltZSddID0gdHJ1ZTsKICAgIHJ1bigpOwoKICAgIHJldHVybiB1bnBhY2sKICB9OwogIC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKICAvKioKICAgKiBSZXR1cm5zIGEgUHJvbWlzZSBjb250YWluaW5nIHRoZSByYXIgZXh0cmFjdG9yIGZvciB0aGUgZ2l2ZW4gZmlsZW5hbWUuCiAgICogQHByaXZhdGUKICAgKi8KICBmdW5jdGlvbiBnZXRFeHRyYWN0b3IodXJsKSB7CiAgICByZXR1cm4gZmV0Y2gobmV3IFJlcXVlc3QodXJsKSkKICAgICAgLnRoZW4oKHJlc3BvbnNlKSA9PiB7CiAgICAgICAgaWYgKHJlc3BvbnNlLm9rKSByZXR1cm4gcmVzcG9uc2UuYXJyYXlCdWZmZXIoKQogICAgICAgIGVsc2UgewogICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCc0MDQgRXJyb3I6IEZpbGUgbm90IGZvdW5kLicpCiAgICAgICAgfQogICAgICB9KQogICAgICAudGhlbigoYnVmZmVyKSA9PiB1bnBhY2tCcmlkZ2UuY3JlYXRlRXh0cmFjdG9yRnJvbURhdGEoYnVmZmVyKSkKICB9CgogIC8qKgogICAqICBSZXR1cm5zIGEgc3RyaW5nIHJlcHJlc2VudGluZyB0aGUgZm9ybWF0dGVkIGNvbnRlbnRzIG9mIHRoZSBnaXZlbiBmaWxlLgogICAqIEBwcml2YXRlCiAgICovCiAgZnVuY3Rpb24gZXh0cmFjdCh7IHJlc291cmNlSWQsIHVybCB9KSB7CiAgICByZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24gKHJlc29sdmUsIHJlamVjdCkgewogICAgICBpZiAoIXVucGFja0JyaWRnZSkgewogICAgICAgIHRocm93IG5ldyBFcnJvcigndW5wYWNrQnJpZGdlIG5vdCBkZXRlY3RlZCcpCiAgICAgIH0KICAgICAgaWYgKCF1bnBhY2spIHsKICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3VucGFjayBub3QgZGV0ZWN0ZWQnKQogICAgICB9CgogICAgICBnZXRFeHRyYWN0b3IodXJsKS50aGVuKAogICAgICAgIChleHRyYWN0b3IpID0+IHsKICAgICAgICAgIC8vIHJldHVybiBleHRyYWN0b3IuZXh0cmFjdEFsbCgpOwogICAgICAgICAgcmVzb2x2ZShleHRyYWN0b3IuZXh0cmFjdEFsbCgpKTsKICAgICAgICB9LAogICAgICAgIChlcnIpID0+IHsKICAgICAgICAgIHJlamVjdChlcnIpOwogICAgICAgIH0KICAgICAgKTsKICAgIH0pCiAgfQoKICAvKioKICAgKiBMaXN0ZW4gZm9yIG1lc3NhZ2VzIHNlbnQgdG8gdGhlIHdvcmtlci4KICAgKiBAcHJpdmF0ZQogICAqLwogIGZ1bmN0aW9uIGhhbmRsZU1lc3NhZ2UoZGF0YSwgcG9zdE1lc3NhZ2UpIHsKICAgIGlmIChkYXRhLnR5cGUgPT0gJ2luaXQnKSB7CiAgICAgIHVucGFjayA9IGluaXR1bnBhY2soZGF0YS5idWZmZXIpOwogICAgICB1bnBhY2sub25SdW50aW1lSW5pdGlhbGl6ZWQgPSAoKSA9PiB7CiAgICAgICAgcG9zdE1lc3NhZ2UoeyB0eXBlOiAnV0FTTV9MT0FERUQnIH0pOwogICAgICB9OwogICAgfSBlbHNlIGlmIChkYXRhLnR5cGUgPT0gJ2ZldGNoJykgewogICAgICBleHRyYWN0KGRhdGEpLnRoZW4oCiAgICAgICAgKHVucGFja2VkKSA9PiB7CiAgICAgICAgICByZXR1cm5EYXRhKGRhdGEsIHVucGFja2VkLCBwb3N0TWVzc2FnZSk7CiAgICAgICAgfSwKICAgICAgICAoZXJyKSA9PiB7CiAgICAgICAgICBjb25zdCByZXN1bHQgPSB7CiAgICAgICAgICAgIHRhc2tJZDogZGF0YS50YXNrSWQsCiAgICAgICAgICAgIHR5cGU6ICdFUlJPUicsCiAgICAgICAgICAgIHJlc291cmNlSWQ6IGRhdGEucmVzb3VyY2VJZCwKICAgICAgICAgICAgdXJsOiBkYXRhLnVybCwKICAgICAgICAgIH07CiAgICAgICAgICBwb3N0TWVzc2FnZShyZXN1bHQpOwogICAgICAgIH0KICAgICAgKTsKICAgIH0gZWxzZSBpZiAoZGF0YS50eXBlID09ICd1bnBhY2snKSB7CiAgICAgIGNvbnN0IHsgYnVmZmVyIH0gPSBkYXRhOwoKICAgICAgaWYgKCF1bnBhY2tCcmlkZ2UpIHsKICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3VucGFja0JyaWRnZSBub3QgZGV0ZWN0ZWQnKQogICAgICB9CiAgICAgIGlmICghdW5wYWNrKSB7CiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCd1bnBhY2sgbm90IGRldGVjdGVkJykKICAgICAgfQoKICAgICAgY29uc3QgZXh0cmFjdG9yID0gdW5wYWNrQnJpZGdlLmNyZWF0ZUV4dHJhY3RvckZyb21EYXRhKGJ1ZmZlcik7CiAgICAgIGNvbnN0IHVucGFja2VkID0gZXh0cmFjdG9yLmV4dHJhY3RBbGwoKTsKICAgICAgcmV0dXJuRGF0YShkYXRhLCB1bnBhY2tlZCwgcG9zdE1lc3NhZ2UpOwogICAgfQogIH0KCiAgZnVuY3Rpb24gcmV0dXJuRGF0YShkYXRhLCB1bnBhY2tlZCwgcG9zdE1lc3NhZ2UpIHsKICAgIGNvbnN0IFtzdGF0ZSwgbGlzdF0gPSB1bnBhY2tlZDsKICAgIGlmIChzdGF0ZS5zdGF0ZSA9PSAnRkFJTCcpIHsKICAgICAgY29uc3QgcmVzdWx0ID0gewogICAgICAgIHRhc2tJZDogZGF0YS50YXNrSWQsCiAgICAgICAgdHlwZTogJ0VSUk9SJywKICAgICAgICByZWFzb246IHN0YXRlLnJlYXNvbiwKICAgICAgICBtc2c6IHN0YXRlLm1zZywKICAgICAgICByZXNvdXJjZUlkOiBkYXRhLnJlc291cmNlSWQsCiAgICAgICAgdXJsOiBkYXRhLnVybCwKICAgICAgfTsKICAgICAgcG9zdE1lc3NhZ2UocmVzdWx0KTsKICAgICAgcmV0dXJuCiAgICB9CiAgICBjb25zdCByZXN1bHQgPSB7CiAgICAgIHRhc2tJZDogZGF0YS50YXNrSWQsCiAgICAgIHR5cGU6ICdGSU5JU0hFRCcsCiAgICAgIHJlc291cmNlSWQ6IGRhdGEucmVzb3VyY2VJZCwKICAgICAgZW50cmllczoge30sCiAgICB9OwoKICAgIGNvbnN0IHRyYW5zZmVyYWJsZXMgPSBbXTsKICAgIGlmIChsaXN0ICYmIGxpc3QuZmlsZXMpIHsKICAgICAgZm9yIChjb25zdCBmaWxlIG9mIGxpc3QuZmlsZXMpIHsKICAgICAgICByZXN1bHQuZW50cmllc1tmaWxlLmZpbGVIZWFkZXIubmFtZV0gPSBmaWxlLmV4dHJhY3RbMV07CiAgICAgICAgdHJhbnNmZXJhYmxlcy5wdXNoKGZpbGUuZXh0cmFjdFsxXS5idWZmZXIpOwogICAgICB9CiAgICB9CiAgICBwb3N0TWVzc2FnZShyZXN1bHQsIHRyYW5zZmVyYWJsZXMpOwogIH0KCiAgZ2xvYmFsVGhpcy5vbm1lc3NhZ2UgPSBmdW5jdGlvbiAoZXZlbnQpIHsKICAgIGhhbmRsZU1lc3NhZ2UoZXZlbnQuZGF0YSwgc2VsZi5wb3N0TWVzc2FnZSk7CiAgfTsKCiAgLyoqCiAgICogV2hlbiB0aGUgV0FTTSBydW50aW1lIGhhcyBiZWVuIGluaXRpYWxpemVkIG9uIHRoZSB1bnBhY2suanMgbW9kdWxlLCBzZW5kIGEgbWVzc2FnZSBpbmRpY2F0aW5nCiAgICogdGhhdCB0aGUgbGlicmFyeSBpcyByZWFkeS4KICAgKi8KICAvLyA8IS0tIHByZXR0aWVyLWlnbm9yZS1lbmQgLS0+CgogIGV4cG9ydHMuaGFuZGxlTWVzc2FnZSA9IGhhbmRsZU1lc3NhZ2U7CgogIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCAnX19lc01vZHVsZScsIHsgdmFsdWU6IHRydWUgfSk7CgogIHJldHVybiBleHBvcnRzOwoKfSkoe30pOwoK', null, false);\n/* eslint-enable */\n\n// @ts-ignore\nclass ArchiveUnpackerMainThread {\n    constructor() {\n        const buffer = Buffer.from(unpackBase64Str, 'base64');\n        // This is a hack to get WebAssembly.instatiate to work.\n        // WebAssembly.instatiate in the ArchiveUnpacker-worker.js\n        // file started silently failing. i found if I pre-compile\n        // then it would then succeed. I beleive we have some\n        // kind of race condition on NodeJS.\n        WebAssembly.compile(buffer).then((res) => {\n            console.log('WebAssembly.compile', res);\n        });\n        handleMessage$1({\n            type: 'init',\n            buffer,\n        }, () => {\n            // console.log(results)\n        });\n    }\n    addTask(taskData, transerables) {\n        return new Promise((resolve) => {\n            handleMessage$1(taskData, (results) => {\n                resolve(results);\n            });\n        });\n    }\n    terminate() { }\n}\nclass ArchiveUnpackerWorkerPool extends WorkerPool {\n    uint8Array;\n    constructor() {\n        super(true);\n        this.uint8Array = Uint8Array.from(atob(unpackBase64Str), (c) => c.charCodeAt(0));\n    }\n    constructWorker() {\n        return new Promise((resolve) => {\n            const worker = new WorkerFactory$2();\n            worker.onmessage = (event) => {\n                if (event.data.type == 'WASM_LOADED')\n                    resolve(worker);\n            };\n            worker.postMessage({\n                type: 'init',\n                buffer: this.uint8Array.buffer,\n            });\n        });\n    }\n}\nlet archiveUnpackerWorkerPool;\n// In NodeJS, we don't use the workers to parse data.\nif (SystemDesc.OS == 'Node') {\n    archiveUnpackerWorkerPool = new ArchiveUnpackerMainThread();\n}\nelse {\n    archiveUnpackerWorkerPool = new ArchiveUnpackerWorkerPool();\n}\n/**\n * Archive unpacker plugin.\n */\nclass ArchiveUnpackerPlugin extends ResourceLoaderPlugin {\n    /**\n     * The type of file this plugin handles.\n     * @return The type of file.\n     */\n    getType() {\n        return 'archive';\n    }\n    /**\n     * Loads an archive file, returning a promise that resolves to the JSON data value.\n     * Note: using the resource loader to centralize data loading enables progress to be tracked and displayed\n     * @param url - The url of the data to load.\n     * @return - The promise value.\n     */\n    async loadFile(url) {\n        // const start = performance.now()\n        try {\n            const response = await fetch(url);\n            if (!response?.ok) {\n                // make the promise be rejected if we didn't get a 2xx response\n                throw new Error(`ArchiveUnpackerPlugin.loadFile: ${response.status} - ${response.statusText} : ${url}`);\n            }\n            const buffer = await response.arrayBuffer();\n            if (!buffer) {\n                throw new Error('Buffer is null');\n            }\n            // const start = performance.now()\n            const result = await this.extractFile(buffer);\n            // console.log('ArchiveUnpackerPlugin.extractFile:' + url, performance.now() - start)\n            return result;\n        }\n        catch (err) {\n            // Network error failed. (Not the same as a 404.)\n            throw err;\n        }\n    }\n    async extractFile(buffer) {\n        const promise = new Promise((resolve, reject) => {\n            const resourceId = buffer.byteLength;\n            archiveUnpackerWorkerPool\n                .addTask({\n                type: 'unpack',\n                resourceId,\n                buffer,\n            }, [buffer])\n                .then((data) => {\n                // @ts-ignore\n                // if (data.type == 'FINISHED') resolve(data.entries)\n                // else resolve(null)\n                if (data.type === 'FINISHED') {\n                    // const data = data\n                    // const text = [\n                    //   '==================== ArchiveUnpackerWorker.js ====================',\n                    //   `Filename: ${data.resourceId}`,\n                    //   '------------------------------------------------------',\n                    // ];\n                    // for(const file in data.entries) {\n                    //   text.push(`${file}:${data.entries[file].byteLength}`);\n                    // }\n                    // console.log(text.join('\\n'))\n                    // @ts-ignore\n                    resolve(data.entries);\n                    // @ts-ignore\n                }\n                else if (data.type === 'ERROR') {\n                    // @ts-ignore\n                    reject(new Error(`Unable to open archive. The file may be corrupt: ${resourceId}`));\n                }\n            });\n        });\n        return promise;\n    }\n}\n\n/**\n * JSON loader plugin.\n */\nclass JsonLoaderPlugin extends ResourceLoaderPlugin {\n    /**\n     * The type of file this plugin handles.\n     * @return The type of file.\n     */\n    getType() {\n        return 'json';\n    }\n    async loadFile(url) {\n        try {\n            const response = await fetch(url);\n            if (!response?.ok) {\n                // make the promise be rejected if we didn't get a 2xx response\n                throw new Error(`JsonLoaderPlugin.loadFile: ${response.status} - ${response.statusText} : ${url}`);\n            }\n            const json = await response.json();\n            return json;\n        }\n        catch (err) {\n            // Network error failed. (Not the same as a 404.)\n            throw err;\n        }\n    }\n}\n\n/**\n * Text loader plugin.\n */\nclass TextLoaderPlugin extends ResourceLoaderPlugin {\n    /**\n     * The type of file this plugin handles.\n     * @return The type of file.\n     */\n    getType() {\n        return 'text';\n    }\n    async loadFile(url) {\n        try {\n            const response = await fetch(url);\n            if (!response?.ok) {\n                // make the promise be rejected if we didn't get a 2xx response\n                throw new Error(`TextLoaderPlugin.loadFile: ${response.status} - ${response.statusText} : ${url}`);\n            }\n            const text = await response.text();\n            return text;\n        }\n        catch (err) {\n            // Network error failed. (Not the same as a 404.)\n            throw err;\n        }\n    }\n}\n\n/**\n * Binary loader plugin.\n */\nclass BinaryLoaderPlugin extends ResourceLoaderPlugin {\n    /**\n     * The type of file this plugin handles.\n     * @return The type of file.\n     */\n    getType() {\n        return 'binary';\n    }\n    async loadFile(url) {\n        try {\n            const response = await fetch(url);\n            if (!response?.ok) {\n                // make the promise be rejected if we didn't get a 2xx response\n                throw new Error(`BinaryLoaderPlugin.loadFile: ${response.status} - ${response.statusText} : ${url}`);\n            }\n            const arrayBuffer = await response.arrayBuffer();\n            return arrayBuffer;\n        }\n        catch (err) {\n            // Network error failed. (Not the same as a 404.)\n            throw err;\n        }\n    }\n}\n\n/* eslint-disable require-jsdoc */\n// Note: browsers have a maximum number of resources they can load at once\n// before they start throwing errors.\n// The error from Chrome is: Failed to load resource: net::ERR_INSUFFICIENT_RESOURCES\n// We limit the number of concurrent resource loads here\n// by pushing loads into a queue.\nconst MAX_LOAD_COUNT = 1000;\n/**\n * Class for delegating resource loading, enabling an abstraction of a cloud file system to be implemented.\n *\n * The resource loader can be used to load data, where it provides central tracking of loading progress and functionality to load various file types, including compressed archives.\n * The plugins script must be loaded along with the engine\n *\n * ```html\n *  <script crossorigin src=\"libs/zea-engine/dist/plugins.umd.js\"></script>\n * ```\n *\n * To load a 'text' file.\n * ```javascript\n *   resourceLoader.loadFile('text', url).then((txt) =>{\n *      console.log(txt)\n *   })\n * ```\n *\n * To load a 'JSON' file.\n * ```javascript\n *   resourceLoader.loadFile('json', url).then((txt) =>{\n *      console.log(json)\n *   })\n * ```\n *\n * To load a 'binary' file.\n * ```javascript\n *   resourceLoader.loadFile('binary', url).then((arrayBuffer) =>{\n *      console.log(arrayBuffer.length)\n *   })\n * ```\n *\n * To load an 'archive' file that is a compressed archive containing multiple sub-files.\n * ```javascript\n *   resourceLoader.loadFile('archive', url).then((entries) =>{\n *      console.log(entries)\n *   })\n * ```\n * **Events**\n * * **loaded:** emitted when a file has finished loading\n * * **progressIncremented:** emitted when a loading of processing task has been incremented\n * * **allResourcesLoaded:** emitted when all outstanding resources are loaded. This event can be used to signal the completion of load.\n */\nclass ResourceLoader extends EventEmitter {\n    totalWork = 0;\n    doneWork = 0;\n    baseUrl = '';\n    plugins = {};\n    systemUrls = {};\n    // Common resources are used by systems such at the renderer and VR controllers.\n    // Any asset that will probably be used my multiple different independent objects\n    // should be loaded here. (For now, it is being used to load VR Controller assets.)\n    commonResources = {};\n    loadCount = 0;\n    queue = [];\n    cache;\n    /**\n     * Create a resource loader.\n     */\n    constructor() {\n        super();\n        const baseUrl = 'https://storage.googleapis.com/zea-engine-resources';\n        this.systemUrls['ZeaEngine/Vive.vla'] = baseUrl + '/Vive.vla';\n        this.systemUrls['ZeaEngine/Oculus.vla'] = baseUrl + '/Oculus.vla';\n    }\n    // /////////////////////////////////////////////////\n    // Register plugins.\n    registerPlugin(plugin) {\n        this.plugins[plugin.getType()] = plugin;\n    }\n    /**\n     * Loads a file, returning a promise that resolves to the JSON data value.\n     * Note: using the resource loader to centralize data loading enables progress to be tracked and displayed\n     * @param url - The url of the data to load.\n     * @return - The promise value.\n     */\n    async loadFile(type, url, incrementWorkload = true) {\n        const plugin = this.plugins[type];\n        if (!plugin) {\n            throw new Error(`There's no plugin registered for the type of file \"${type}\". Did you add the plugins script? See: https://docs.zea.live/zea-engine/#/adding-default-plugins`);\n        }\n        if (incrementWorkload)\n            this.incrementWorkload();\n        if (this.cache) {\n            const result = await this.cache.get(url);\n            if (result) {\n                if (incrementWorkload)\n                    this.incrementWorkDone();\n                return result;\n            }\n        }\n        if (this.loadCount < MAX_LOAD_COUNT) {\n            this.loadCount++;\n            try {\n                const loadFilePromise = plugin.loadFile(url);\n                loadFilePromise.then((result) => {\n                    if (this.cache)\n                        this.cache.set(url, result);\n                    this.loadCount--;\n                    if (incrementWorkload)\n                        this.incrementWorkDone();\n                    this.emit('loaded', { url });\n                    while (this.loadCount < MAX_LOAD_COUNT && this.queue.length > 0) {\n                        const callback = this.queue.pop();\n                        callback();\n                    }\n                }, () => {\n                    if (incrementWorkload)\n                        this.incrementWorkDone();\n                });\n                return loadFilePromise;\n            }\n            catch (e) {\n                // Error\n                if (incrementWorkload)\n                    this.incrementWorkDone();\n                throw e;\n            }\n        }\n        else {\n            const promise = new Promise((resolve, reject) => {\n                this.queue.push(() => {\n                    this.loadCount++;\n                    const loadFilePromise = plugin.loadFile(url);\n                    loadFilePromise.then((data) => {\n                        this.loadCount--;\n                        if (incrementWorkload)\n                            this.incrementWorkDone();\n                        this.emit('loaded', { url });\n                        while (this.loadCount < MAX_LOAD_COUNT && this.queue.length > 0) {\n                            const callback = this.queue.pop();\n                            callback();\n                        }\n                        resolve(data);\n                    }, (e) => {\n                        // Error\n                        if (incrementWorkload)\n                            this.incrementWorkDone();\n                        reject(e);\n                    });\n                });\n            });\n            return promise;\n        }\n    }\n    /**\n     * Returns a previously stored common resource. Typically this would be a VR asset.\n     *\n     * @param resourceId - The resourceId value.\n     * @return - The common resource if it exists\n     */\n    getCommonResource(resourceId) {\n        return this.commonResources[resourceId];\n    }\n    /**\n     * Saves a common resource for reuse by other tools. Typically this would be a VR asset.\n     *\n     * @param resourceId - The resourceId value.\n     * @param resource - The common resource to store\n     */\n    setCommonResource(resourceId, resource) {\n        this.commonResources[resourceId] = resource;\n    }\n    // /////////////////////////////////////////////////\n    // Work\n    /**\n     * Resets the progress counters back to zero. This must be done if a new asset needs to be\n     * loaded after some preivous asset has already been loaded and a new load sequence is starting\n     *\n     * @param amount - The amount value.\n     */\n    resetProgress() {\n        this.totalWork = 0;\n        this.doneWork = 0;\n    }\n    /**\n     * Increments the amount of work to be done causing a 'progressIncremented' event to be emitted.\n     *\n     * The progress bar is based on how much work there is to do Vs how much work has been done.\n     * Before loading starts, we don't know how much work is coming because we don't know how many files\n     * will be loaded, and how big those files will be. Big files are decompressed as a steam, which\n     * involves many small increments.\n     * Add we laod files, the work load is incrementened, and then as the work is done, we increment\n     * the work done.\n     * The ratio between work load and work done determines the percentage of load.\n     *\n     * @param amount - The amount value.\n     */\n    incrementWorkload(amount = 1) {\n        this.totalWork += amount;\n        const percent = (this.doneWork / this.totalWork) * 100;\n        this.emit('progressIncremented', new ProgressEvent(percent));\n    }\n    /**\n     * Increments the amount of work done causing a 'progressIncremented' event to be emitted.\n     * If 5 items of work have been added using #incrementWorkload, and subsequently 3 items have\n     * been completed and #incrementWorkDone called. The progress will be at 3/5, or 60%\n     *\n     * @param amount - The amount value.\n     */\n    incrementWorkDone(amount = 1) {\n        this.doneWork += amount;\n        const percent = (this.doneWork / this.totalWork) * 100;\n        this.emit('progressIncremented', new ProgressEvent(percent));\n        if (this.doneWork > this.totalWork) {\n            console.warn('Mismatch between work loaded and work done.');\n        }\n    }\n}\nconst resourceLoader = new ResourceLoader();\nconst archiveUnpackerPlugin = new ArchiveUnpackerPlugin();\nresourceLoader.registerPlugin(archiveUnpackerPlugin);\nconst jsonLoaderPlugin = new JsonLoaderPlugin();\nresourceLoader.registerPlugin(jsonLoaderPlugin);\nconst textLoaderPlugin = new TextLoaderPlugin();\nresourceLoader.registerPlugin(textLoaderPlugin);\nconst binaryLoaderPlugin = new BinaryLoaderPlugin();\nresourceLoader.registerPlugin(binaryLoaderPlugin);\n\nclass IndexDBCache {\n    name;\n    objStoreName;\n    version;\n    db;\n    constructor(name, objStoreName, version) {\n        this.name = name;\n        this.objStoreName = objStoreName;\n        this.version = version;\n    }\n    async init() {\n        return new Promise((resolve) => {\n            const request = globalThis.indexedDB.open(this.name, this.version);\n            request.onerror = () => {\n                console.error('IndexedDB Failed');\n            };\n            request.onsuccess = () => {\n                this.db = request.result;\n                resolve();\n            };\n            request.onupgradeneeded = (event) => {\n                this.db = request.result;\n                if (event.oldVersion && event.oldVersion != event.newVersion) {\n                    this.db.deleteObjectStore(this.objStoreName);\n                }\n                this.db.createObjectStore(this.objStoreName, {\n                    keyPath: 'key',\n                });\n            };\n        });\n    }\n    /**\n     * Gets a value from the Cache.\n     * @param key the unique key to use. This is typically the URL\n     * @returns the cached value, or null if the value is not in the Cache\n     */\n    get(key) {\n        return new Promise((resolve, reject) => {\n            const tx = this.db.transaction(this.objStoreName, 'readonly');\n            const store = tx.objectStore(this.objStoreName);\n            const request = store.get(key);\n            request.onerror = (event) => {\n                reject(event);\n            };\n            request.onsuccess = () => {\n                if (request.result)\n                    resolve(request.result.value);\n                else\n                    resolve(null);\n            };\n        });\n    }\n    /**\n     * Stores a value in the Cache.\n     * @param key the unique key to use. This is typically the URL\n     * @param value this can be any object or value.\n     */\n    set(key, value) {\n        return new Promise((resolve, reject) => {\n            const tx = this.db.transaction(this.objStoreName, 'readwrite');\n            const store = tx.objectStore(this.objStoreName);\n            const request = store.put({ key, value });\n            request.onsuccess = () => {\n                resolve();\n            };\n            request.onerror = (event) => {\n                reject(event);\n            };\n        });\n    }\n}\n\n/**\n * Class designed to store version data. Widely used in the zea engine for backwards compatibility.\n */\nclass Version {\n    major = 0;\n    minor = 0;\n    patch = 0;\n    branch = '';\n    /**\n     * Creates a version.\n     * The version string should have the following structure:\n     * major, minor and patch separated by a dot(`.`) and parts separated by a dash(`-`).\n     *\n     * @param arg - The version string value, or an array of version numbers.\n     */\n    constructor(arg) {\n        if (typeof arg == 'string') {\n            const parts = arg.split('-');\n            const numbers = parts[0].split('.');\n            this.major = parseInt(numbers[0]);\n            this.minor = numbers.length > 1 ? parseInt(numbers[1]) : 0;\n            this.patch = numbers.length > 2 ? parseInt(numbers[2]) : 0;\n            if (parts.length == 2)\n                this.branch = parts[1];\n        }\n        else if (Array.isArray(arg)) {\n            const numbers = arg;\n            this.major = numbers[0];\n            this.minor = numbers.length > 1 ? numbers[1] : 0;\n            this.patch = numbers.length > 2 ? numbers[2] : 0;\n        }\n    }\n    /**\n     * Compare a version object against a version numbers array.\n     *\n     * @param numbers - An array containing 3 version numbers. [Major, Minor, Patch]\n     * @return - return positive: v1 > v2, zero:v1 == v2, negative: v1 < v2\n     */\n    compare(numbers) {\n        // https://stackoverflow.com/questions/6832596/how-to-compare-software-version-number-using-js-only-number\n        // 2nd answer.\n        const v1 = [this.major, this.minor, this.patch];\n        for (let i = 0; i < 3; i++) {\n            if (v1[i] !== numbers[i])\n                return v1[i] - numbers[i];\n        }\n        return 0;\n    }\n    /**\n     * Converts the Version class instance back to an array for comparisons with other version class instances.\n     * e.g.\n     * ```\n     *   const version1 = new Version([1, 2, 3])\n     *   const version2 = new Version([1, 2, 4])\n     *   const res = version1.compare(version2.asArray())\n     * ```\n     * @returns an array containing the major, minor and patch version numbers.\n     */\n    asArray() {\n        return [this.major, this.minor, this.patch];\n    }\n    toString() {\n        return `v${this.major}.${this.minor}.${this.patch}` + (this.branch != '' ? `-${this.branch}` : '');\n    }\n}\n\n/* eslint-disable no-unused-vars */\n/**\n * Reads binary data in a specific encoding. Used in loading binary data such as zcad files.\n */\nclass BinReader {\n    __data;\n    __byteOffset;\n    __dataView;\n    __isMobileDevice;\n    utf8decoder;\n    /**\n     * Create a bin reader.\n     *\n     * @param data - The data buffer.\n     * @param byteOffset - The byte offset value to start reading the buffer.\n     * @param isMobileDevice - The isMobileDevice value.\n     */\n    constructor(data, byteOffset = 0, isMobileDevice = true) {\n        this.__data = data;\n        this.__byteOffset = byteOffset;\n        this.__dataView = new DataView(this.__data);\n        this.__isMobileDevice = isMobileDevice;\n        this.utf8decoder = new TextDecoder();\n    }\n    /**\n     * Returns state of whether or not the `BinReader` object was instantiated from a mobile device.\n     *\n     * @return - Returns true is a mobile device is detected.\n     */\n    get isMobileDevice() {\n        return this.__isMobileDevice;\n    }\n    /**\n     * Returns the data buffer we're reading from.\n     *\n     * @return - The data buffer we are reading from,\n     */\n    get data() {\n        return this.__data;\n    }\n    /**\n     * Returns the length of the buffer.\n     *\n     * @return - The total length of the buffer\n     */\n    get byteLength() {\n        return this.__dataView.byteLength;\n    }\n    /**\n     * Returns remaining length of the buffer to read.\n     *\n     * @return - The remaining length of the buffer to read.\n     */\n    get remainingByteLength() {\n        return this.__dataView.byteLength - this.__byteOffset;\n    }\n    /**\n     * Returns current byte offset in the buffer.\n     * @return - The current offset in the binary buffer\n     */\n    pos() {\n        return this.__byteOffset;\n    }\n    /**\n     * Sets the byte offset value.\n     * @param byteOffset - The byteOffset param.\n     */\n    seek(byteOffset) {\n        this.__byteOffset = byteOffset;\n    }\n    /**\n     * Adds offset bytes to current offset value.\n     *\n     * @param byteOffset - The byte Offset amount.\n     */\n    advance(byteOffset) {\n        this.__byteOffset += byteOffset;\n    }\n    /**\n     * Returns the unsigned Uint8 value at current byte offset position,\n     * and adds one byte to the offset.\n     *\n     * @return - The return value.\n     */\n    loadUInt8() {\n        const result = this.__dataView.getUint8(this.__byteOffset);\n        this.__byteOffset += 1;\n        return result;\n    }\n    /**\n     * Returns the unsigned Uint16 value at current byte offset position,\n     * and adds two bytes to the offset.\n     *\n     * @return - The return value.\n     */\n    loadUInt16() {\n        const result = this.__dataView.getUint16(this.__byteOffset, true);\n        this.__byteOffset += 2;\n        return result;\n    }\n    /**\n     * Returns the unsigned Uint32 value at current byte offset position,\n     * and adds four bytes to the offset.\n     *\n     * @return - The return value.\n     */\n    loadUInt32() {\n        const result = this.__dataView.getUint32(this.__byteOffset, true);\n        this.__byteOffset += 4;\n        return result;\n    }\n    /**\n     * Returns the signed Int32 value at current byte offset position,\n     * and adds four bytes to the offset.\n     *\n     * @return - The return value.\n     */\n    loadSInt32() {\n        const result = this.__dataView.getInt32(this.__byteOffset, true);\n        this.__byteOffset += 4;\n        return result;\n    }\n    /**\n     * Returns the Float16 value at current byte offset position,\n     * and adds four bytes to the offset.\n     *\n     * @return - The return value.\n     */\n    loadFloat16() {\n        const uint16 = this.loadUInt16();\n        return MathFunctions.decode16BitFloat(uint16);\n    }\n    /**\n     * Returns the Float16 value at current byte offset position,\n     * and adds two bytes to the offset.\n     *\n     * @return - The return value.\n     */\n    loadUFloat16() {\n        const result = this.loadFloat16();\n        if (result < 0.0) {\n            return 2048.0 - result; // Note: subtract a negative number to add it.\n        }\n        else {\n            return result;\n        }\n    }\n    /**\n     * Returns a single signed Float16 value at current byte offset position from 2 unsigned Int8 values,\n     * and adds two bytes to the offset.\n     *\n     * @return - The return value.\n     */\n    loadFloat16From2xUInt8() {\n        throw Error('loadFloat16From2xUInt8 not implemented!');\n        // const result = this.__dataView.getFloat16(this.__byteOffset, true)\n        // const uint8s = this.loadUInt8Array(2);\n        // return Math.decode16BitFloat(uint8s);\n        // this.__byteOffset += 2\n        // return result\n    }\n    /**\n     * Loads and returns a single Signed integer value from 2 Unsigned Float16 values.\n     * @return - The return value.\n     */\n    loadUInt32From2xUFloat16() {\n        const partA = this.loadUFloat16();\n        const partB = this.loadUFloat16();\n        return partA + partB * 4096;\n    }\n    /**\n     * Loads and returns a single Signed integer value from 2 signed Float16 values.\n     * @return - The return value.\n     */\n    loadSInt32From2xFloat16() {\n        const partA = this.loadFloat16();\n        const partB = this.loadFloat16();\n        return partA + partB * 2048;\n    }\n    /**\n     * Returns the Float32 value at current byte offset position,\n     * and adds four bytes to the offset.\n     *\n     * @return - The return value.\n     */\n    loadFloat32() {\n        const result = this.__dataView.getFloat32(this.__byteOffset, true);\n        this.__byteOffset += 4;\n        return result;\n    }\n    /**\n     * Reads buffer and return a signed Int8 array with the specified size,\n     * starting from current byte offset.\n     * Byte offset is increased by the specified byte size.\n     *\n     * @param size - The size param.\n     * @param clone - The clone param.\n     * @return - The return value.\n     */\n    loadInt8Array(size, clone = true) {\n        if (size == undefined)\n            size = this.loadUInt32();\n        let result;\n        if (clone) {\n            result = new Int8Array(this.__data.slice(this.__byteOffset, this.__byteOffset + size));\n            if (result.length != size)\n                console.log('broken');\n        }\n        else {\n            result = new Int8Array(this.__data, this.__byteOffset, size);\n        }\n        this.__byteOffset += size;\n        return result;\n    }\n    /**\n     * Reads buffer and return an unsigned Int8 array with the specified size,\n     * starting from current byte offset.\n     * Byte offset is increased by the specified byte size.\n     *\n     * @param size - The size param.\n     * @param clone - The clone param.\n     * @return - The return value.\n     */\n    loadUInt8Array(size, clone = true) {\n        if (size == undefined)\n            size = this.loadUInt32();\n        let result;\n        if (clone) {\n            result = new Uint8Array(this.__data.slice(this.__byteOffset, this.__byteOffset + size));\n            if (result.length != size)\n                console.log('broken');\n        }\n        else {\n            result = new Uint8Array(this.__data, this.__byteOffset, size);\n        }\n        this.__byteOffset += size;\n        return result;\n    }\n    /**\n     * Reads buffer and return an unsigned Int16 array with the specified size,\n     * starting from current byte offset.\n     * Byte offset is increased by the specified byte size x 2.\n     *\n     * @param size - The size param.\n     * @param clone - The clone param.\n     * @return - The return value.\n     */\n    loadUInt16Array(size, clone = true) {\n        if (size == undefined)\n            size = this.loadUInt32();\n        if (size == 0)\n            return new Uint16Array();\n        this.readPad(2);\n        let result;\n        if (this.__isMobileDevice) {\n            result = new Uint16Array(size);\n            for (let i = 0; i < size; i++) {\n                result[i] = this.__dataView.getUint16(this.__byteOffset, true);\n                this.__byteOffset += 2;\n            }\n        }\n        else {\n            if (clone) {\n                result = new Uint16Array(this.__data.slice(this.__byteOffset, this.__byteOffset + size * 2));\n                if (result.length != size)\n                    console.log('broken');\n            }\n            else {\n                result = new Uint16Array(this.__data, this.__byteOffset, size);\n            }\n            this.__byteOffset += size * 2;\n        }\n        return result;\n    }\n    /**\n     * Reads buffer and return an unsigned Int32 array with the specified size,\n     * starting from current byte offset.\n     * Byte offset is increased by the specified byte size x 4.\n     *\n     * @param size - The size param.\n     * @param clone - The clone param.\n     * @return - The return value.\n     */\n    loadUInt32Array(size, clone = true) {\n        if (size == undefined)\n            size = this.loadUInt32();\n        if (size == 0)\n            return new Uint32Array();\n        this.readPad(4);\n        let result;\n        if (this.__isMobileDevice) {\n            result = new Uint32Array(size);\n            for (let i = 0; i < size; i++) {\n                result[i] = this.__dataView.getUint32(this.__byteOffset, true);\n                this.__byteOffset += 4;\n            }\n        }\n        else {\n            if (clone) {\n                result = new Uint32Array(this.__data.slice(this.__byteOffset, this.__byteOffset + size * 4));\n                if (result.length != size)\n                    console.log('broken');\n            }\n            else {\n                result = new Uint32Array(this.__data, this.__byteOffset, size);\n            }\n            this.__byteOffset += size * 4;\n        }\n        return result;\n    }\n    /**\n     * Reads buffer and return a Float32 array with the specified size,\n     * starting from current byte offset.\n     * Byte offset is increased by the specified byte size x 4.\n     *\n     * @param size - The size param.\n     * @param clone - The clone param.\n     * @return - The return value.\n     */\n    loadFloat32Array(size, clone = true) {\n        if (size == undefined)\n            size = this.loadUInt32();\n        if (size == 0)\n            return new Float32Array();\n        this.readPad(4);\n        let result;\n        if (this.__isMobileDevice) {\n            result = new Float32Array(size);\n            for (let i = 0; i < size; i++) {\n                result[i] = this.__dataView.getFloat32(this.__byteOffset, true);\n                this.__byteOffset += 4;\n            }\n        }\n        else {\n            if (clone) {\n                result = new Float32Array(this.__data.slice(this.__byteOffset, this.__byteOffset + size * 4));\n            }\n            else {\n                result = new Float32Array(this.__data, this.__byteOffset, size);\n            }\n            this.__byteOffset += size * 4;\n        }\n        return result;\n    }\n    /**\n     * Returns next string.\n     * First looks for the string length description in the next four bytes in the buffer(Starting from byte offset).\n     *\n     * @return - The return value.\n     */\n    loadStr() {\n        const numChars = this.loadUInt32();\n        const chars = new Uint8Array(this.__data, this.__byteOffset, numChars);\n        this.__byteOffset += numChars;\n        return this.utf8decoder.decode(chars);\n    }\n    /**\n     * Returns an array of strings.\n     * First reading the size of the array then reading each string.\n     *\n     * @return - The return value.\n     */\n    loadStrArray() {\n        const size = this.loadUInt32();\n        const result = [];\n        for (let i = 0; i < size; i++) {\n            result[i] = this.loadStr();\n        }\n        return result;\n    }\n    /**\n     * Creates and returns a `Vec2` object with the next two signed Int32 values in the buffer.\n     *\n     * @return - Returns a Vec2.\n     */\n    loadSInt32Vec2() {\n        const x = this.loadSInt32();\n        const y = this.loadSInt32();\n        return new Vec2(x, y);\n    }\n    /**\n     * Creates and returns a `Vec2` object with the next two unsigned Int32 values in the buffer.\n     * @return - Returns a Vec2.\n     */\n    loadUInt32Vec2() {\n        const x = this.loadUInt32();\n        const y = this.loadUInt32();\n        return new Vec2(x, y);\n    }\n    /**\n     * Creates and returns a `Vec2` object with the next two Float16 values in the buffer.\n     *\n     * @return - Returns a Vec2.\n     */\n    loadFloat16Vec2() {\n        const x = this.loadFloat16();\n        const y = this.loadFloat16();\n        return new Vec2(x, y);\n    }\n    /**\n     * Creates and returns a `Vec2` object with the next two Float32 values in the buffer.\n     * @return - Returns a Vec2.\n     */\n    loadFloat32Vec2() {\n        const x = this.loadFloat32();\n        const y = this.loadFloat32();\n        return new Vec2(x, y);\n    }\n    /**\n     * Creates and returns a `Vec3` object with the next three Float16 values in the buffer.\n     *\n     * @return - Returns a Vec3.\n     */\n    loadFloat16Vec3() {\n        const x = this.loadFloat16();\n        const y = this.loadFloat16();\n        const z = this.loadFloat16();\n        return new Vec3(x, y, z);\n    }\n    /**\n     * Creates and returns a `Vec3` object with the next three Float32 values in the buffer.\n     *\n     * @return - Returns a Vec3.\n     */\n    loadFloat32Vec3() {\n        const x = this.loadFloat32();\n        const y = this.loadFloat32();\n        const z = this.loadFloat32();\n        return new Vec3(x, y, z);\n    }\n    /**\n     * Creates and returns a `Quat` object with the next four Float16 values in the buffer.\n     *\n     * @return - Returns a Quat.\n     */\n    loadFloat16Quat() {\n        const x = this.loadFloat16();\n        const y = this.loadFloat16();\n        const z = this.loadFloat16();\n        const w = this.loadFloat16();\n        return new Quat(x, y, z, w);\n    }\n    /**\n     * Creates and returns a `Quat` object with the next four Float32 values in the buffer.\n     * @return - Returns a Quat.\n     */\n    loadFloat32Quat() {\n        const x = this.loadFloat32();\n        const y = this.loadFloat32();\n        const z = this.loadFloat32();\n        const w = this.loadFloat32();\n        return new Quat(x, y, z, w);\n    }\n    /**\n     * Creates and returns a `Color` object with the next three Float32 values in the buffer.\n     *\n     * @return - Returns a Color.\n     */\n    loadRGBFloat32Color() {\n        const r = this.loadFloat32();\n        const g = this.loadFloat32();\n        const b = this.loadFloat32();\n        return new Color(r, g, b);\n    }\n    /**\n     * Creates and returns a RGBA `Color` object with the next four Float32 values in the buffer.\n     * @return - Returns a Color.\n     */\n    loadRGBAFloat32Color() {\n        const r = this.loadFloat32();\n        const g = this.loadFloat32();\n        const b = this.loadFloat32();\n        const a = this.loadFloat32();\n        return new Color(r, g, b, a);\n    }\n    /**\n     * Creates and returns a `Color` object with the next three unsigned Int8 values in the buffer.\n     * @return - Returns a Color.\n     */\n    loadRGBUInt8Color() {\n        const r = this.loadUInt8();\n        const g = this.loadUInt8();\n        const b = this.loadUInt8();\n        return new Color(r / 255, g / 255, b / 255);\n    }\n    /**\n     * Creates and returns a RGBA `Color` object with the next four unsigned Int8 values in the buffer.\n     * @return - Returns a Color.\n     */\n    loadRGBAUInt8Color() {\n        const r = this.loadUInt8();\n        const g = this.loadUInt8();\n        const b = this.loadUInt8();\n        const a = this.loadUInt8();\n        return new Color(r / 255, g / 255, b / 255, a / 255);\n    }\n    /**\n     * Creates and returns a `Box2` object with the next four Float32 values in the buffer.\n     * Next four because it creates two Vec2.\n     *\n     * @return - Returns a Box2.\n     */\n    loadBox2() {\n        return new Box2(this.loadFloat32Vec2(), this.loadFloat32Vec2());\n    }\n    /**\n     * Creates and returns a `Box2` object with the next six Float32 values in the buffer.\n     * Next four because it creates two Vec3.\n     *\n     * @return - Returns a Box3.\n     */\n    loadBox3() {\n        return new Box3(this.loadFloat32Vec3(), this.loadFloat32Vec3());\n    }\n    /**\n     * Given a stridee value, advance the pointer to the end of the current stride.\n     * @param stride - The stride param.\n     */\n    readPad(stride) {\n        const pad = this.__byteOffset % stride;\n        if (pad != 0)\n            this.__byteOffset += stride - pad;\n    }\n}\n\n/**\n * Writes `TypedArray` types in binary using a specific encoding.\n */\nclass BinWriter {\n    __data;\n    __byteOffset;\n    __reserved;\n    __dataView;\n    /**\n     * Create a bin writer.\n     * @param dataSize - The dataSize value.\n     */\n    constructor(dataSize = 0) {\n        this.__data = new ArrayBuffer(dataSize);\n        this.__byteOffset = 0;\n        this.__reserved = dataSize;\n        this.__dataView = new DataView(this.__data);\n    }\n    /**\n     * Returns the byte offset position.\n     *\n     * @return - The return value.\n     */\n    pos() {\n        return this.__byteOffset;\n    }\n    /**\n     * Sets byte offset value.\n     *\n     * @param byteOffset - The byteOffset value.\n     */\n    seek(byteOffset) {\n        this.__byteOffset = byteOffset;\n    }\n    /**\n     * The seekEnd method.\n     */\n    seekEnd() {\n        this.__byteOffset = this.__reserved;\n    }\n    /**\n     * Returns written buffer data to current point.\n     *\n     * @return - Returns an array buffer.\n     */\n    getBuffer() {\n        if (this.__data.byteLength == this.__byteOffset) {\n            return this.__data;\n        }\n        else {\n            const unit8Array = new Uint8Array(this.__data);\n            return unit8Array.slice(0, this.__byteOffset).buffer;\n        }\n    }\n    /**\n     * The __grow method.\n     * @private\n     */\n    __grow() {\n        const newSize = (this.__reserved > 0 ? this.__reserved : 1) * 2;\n        const data = new ArrayBuffer(newSize);\n        const unit8Array = new Uint8Array(data);\n        const old_unit8Array = new Uint8Array(this.__data);\n        unit8Array.set(old_unit8Array);\n        this.__data = data;\n        this.__dataView = new DataView(this.__data);\n        this.__reserved = newSize;\n    }\n    /**\n     * The __reserve method.\n     * @param offset - The offset value.\n     * @private\n     */\n    __reserve(offset) {\n        if (this.__byteOffset + offset > this.__reserved) {\n            this.__grow();\n        }\n    }\n    /**\n     * The __offset method.\n     * @param byteCount - The byteCount value.\n     * @private\n     */\n    __offset(byteCount) {\n        this.__byteOffset += byteCount;\n        if (this.__byteOffset > this.__reserved) {\n            this.__grow();\n        }\n    }\n    /**\n     * Writes an unsigned Int8 value in current byte offset.\n     *\n     * @param value - The value param.\n     */\n    writeUInt8(value) {\n        this.__reserve(1);\n        this.__dataView.setUint8(this.__byteOffset, value);\n        this.__offset(1);\n    }\n    /**\n     * Writes an unsigned Int16 value in current byte offset.\n     * @param value - The value param.\n     */\n    writeUInt16(value) {\n        this.__reserve(2);\n        this.__dataView.setUint16(this.__byteOffset, value, true);\n        this.__offset(2);\n    }\n    /**\n     * Writes an unsigned Int32 value in current byte offset.\n     * @param value - The value param.\n     */\n    writeUInt32(value) {\n        this.__reserve(4);\n        this.__dataView.setUint32(this.__byteOffset, value, true);\n        this.__offset(4);\n    }\n    /**\n     * Writes a signed Int32 value in current byte offset.\n     * @param value - The value param.\n     */\n    writeSInt32(value) {\n        this.__reserve(4);\n        this.__dataView.setInt32(this.__byteOffset, value, true);\n        this.__offset(4);\n    }\n    /**\n     * Writes a Float16 value in current byte offset.\n     *\n     * @param value - The value param.\n     */\n    writeFloat16(value) {\n        const uint16 = MathFunctions.encode16BitFloat(value);\n        this.writeUInt16(uint16);\n    }\n    /**\n     * Writes a Float32 value in current byte offset.\n     *\n     * @param value - The value param.\n     */\n    writeFloat32(value) {\n        this.__reserve(4);\n        this.__dataView.setFloat32(this.__byteOffset, value, true);\n        this.__offset(4);\n    }\n    /**\n     * Writes an unsigned Int8 array value from current byte offset.\n     *\n     * @param value - The value param.\n     * @param writeSize - The writeSize value.\n     */\n    writeUInt8Array(value, writeSize = true) {\n        const count = value.length ? value.length : value.length;\n        this.__reserve(count + (writeSize ? 4 : 0));\n        if (writeSize)\n            this.writeUInt32(count);\n        for (let i = 0; i < count; i++) {\n            this.writeUInt8(value[i]);\n        }\n    }\n    /**\n     * Writes an unsigned Int16 array value from current byte offset.\n     *\n     * @param value - The value param.\n     * @param writeSize - The writeSize value.\n     */\n    writeUInt16Array(value, writeSize = true) {\n        const count = value.length ? value.length : value.length;\n        this.__reserve(count * 2 + (writeSize ? 4 : 0));\n        if (writeSize)\n            this.writeUInt32(count);\n        for (let i = 0; i < count; i++) {\n            this.writeUInt16(value[i]);\n        }\n    }\n    /**\n     * Writes an unsigned Int32 array value from current byte offset.\n     *\n     * @param value - The value param.\n     * @param writeSize - The writeSize value.\n     */\n    writeUInt32Array(value, writeSize = true) {\n        const count = value.length ? value.length : value.length;\n        this.__reserve(count * 4 + (writeSize ? 4 : 0));\n        if (writeSize)\n            this.writeUInt32(count);\n        for (let i = 0; i < count; i++) {\n            this.writeUInt32(value[i]);\n        }\n    }\n    /**\n     * Writes a Float32 array value from current byte offset.\n     *\n     * @param value - The value param.\n     * @param writeSize - The writeSize value.\n     */\n    writeFloat32Array(value, writeSize = true) {\n        const count = value.length ? value.length : value.length;\n        this.__reserve(count * 4 + (writeSize ? 4 : 0));\n        if (writeSize)\n            this.writeUInt32(count);\n        for (let i = 0; i < count; i++) {\n            this.writeFloat32(value[i]);\n        }\n    }\n    /**\n     * Writes string value in current position, first writing an unsigned Int32 describing its length, then adding the string in Float32 values.\n     *\n     * @param str - The str value.\n     * @param writeSize - The writeSize value.\n     */\n    writeStr(str, writeSize = true) {\n        const count = str.length;\n        this.__reserve(count * 4 + (writeSize ? 4 : 0));\n        if (writeSize)\n            this.writeUInt32(count);\n        for (let i = 0; i < count; i++) {\n            this.writeFloat32(str.charCodeAt(i));\n        }\n    }\n    /**\n     * Writes a `Vec2` in the buffer using signed Int32 values(In `x,y` order).\n     * @param value - The Vec2 to write.\n     */\n    writeSInt32Vec2(value) {\n        this.writeSInt32(value.x);\n        this.writeSInt32(value.y);\n    }\n    /**\n     * Writes a `Vec2` in the buffer using unsigned Int32 values(In `x,y` order).\n     *\n     * @param value - The Vec2 to write.\n     */\n    writeUInt32Vec2(value) {\n        this.writeUInt32(value.x);\n        this.writeUInt32(value.y);\n    }\n    /**\n     * Writes a `Vec2` in the buffer using Float16 values(In `x,y` order).\n     * @param value - The Vec2 to write.\n     */\n    writeFloat16Vec2(value) {\n        this.writeFloat16(value.x);\n        this.writeFloat16(value.y);\n    }\n    /**\n     * Writes a `Vec2` in the buffer using Float32 values(In `x,y` order).\n     *\n     * @param value - The Vec2 to write.\n     */\n    writeFloat32Vec2(value) {\n        this.writeFloat32(value.x);\n        this.writeFloat32(value.y);\n    }\n    /**\n     * Writes a `Vec3` in the buffer using Float16 values(In `x,y,z` order).\n     *\n     * @param value - The Vec3 to write.\n     */\n    writeFloat16Vec3(value) {\n        this.writeFloat16(value.x);\n        this.writeFloat16(value.y);\n        this.writeFloat16(value.z);\n    }\n    /**\n     * Writes a `Vec3` in the buffer using Float32 values(In `x,y,z` order).\n     * @param value - The Vec3 to write.\n     */\n    writeFloat32Vec3(value) {\n        this.writeFloat32(value.x);\n        this.writeFloat32(value.y);\n        this.writeFloat32(value.z);\n    }\n    /**\n     * Writes a `Quat` in the buffer using Float16 values(In `x,y,z,w` order).\n     *\n     * @param value - The Quat to write.\n     */\n    writeFloat16Quat(value) {\n        this.writeFloat16(value.x);\n        this.writeFloat16(value.y);\n        this.writeFloat16(value.z);\n        this.writeFloat16(value.w);\n    }\n    /**\n     * Writes a `Quat` in the buffer using Float32 values(In `x,y,z,w` order).\n     *\n     * @param value - The Quat to write.\n     */\n    writeFloat32Quat(value) {\n        this.writeFloat32(value.x);\n        this.writeFloat32(value.y);\n        this.writeFloat32(value.z);\n        this.writeFloat32(value.w);\n    }\n    /**\n     * Writes a RGB `Color` in the buffer using Float32 values(In `r,g,b` order).\n     *\n     * @param value - The Color to write.\n     */\n    writeRGBFloat32Color(value) {\n        this.writeFloat32(value.r);\n        this.writeFloat32(value.g);\n        this.writeFloat32(value.b);\n    }\n    /**\n     * Writes a RGBA `Color` in the buffer using Float32 values(In `r,g,b,a` order).\n     *\n     * @param value - The Color to write.\n     */\n    writeRGBAFloat32Color(value) {\n        this.writeFloat32(value.r);\n        this.writeFloat32(value.g);\n        this.writeFloat32(value.b);\n        this.writeFloat32(value.a);\n    }\n    /**\n     * Writes a RGB `Color` in the buffer using unsigned Int8 values(In `r,g,b` order).\n     *\n     * @param value - The Color to write.\n     */\n    writeRGBUInt8Color(value) {\n        this.writeUInt8(value.r);\n        this.writeUInt8(value.g);\n        this.writeUInt8(value.b);\n    }\n    /**\n     * Writes a RGBA `Color` in the buffer using unsigned Int8 values(In `r,g,b,a` order).\n     *\n     * @param value - The Color to write.\n     */\n    writeRGBAUInt8Color(value) {\n        this.writeUInt8(value.r);\n        this.writeUInt8(value.g);\n        this.writeUInt8(value.b);\n        this.writeUInt8(value.a);\n    }\n    /**\n     * Writes a `Box2` in the buffer using Floar32 values(In `p0,p1` order).\n     *\n     * @param value - The Box2 to write.\n     */\n    writeBox2(value) {\n        this.writeFloat32Vec2(value.p0);\n        this.writeFloat32Vec2(value.p1);\n    }\n    /**\n     * Writes a `Box3` in the buffer using Floar32 values(In `p0,p1` order).\n     *\n     * @param value - The Box3 to write.\n     */\n    writeBox3(value) {\n        this.writeFloat32Vec3(value.p0);\n        this.writeFloat32Vec3(value.p1);\n    }\n    /**\n     * The writePadd method.\n     * @param size - The size value.\n     */\n    writePadd(size) {\n        const bytes = size - this.__byteOffset;\n        this.__reserve(bytes);\n        this.__offset(bytes);\n    }\n    /**\n     * The writeAlignment method.\n     * @param numBytes - The numBytes value.\n     */\n    writeAlignment(numBytes) {\n        const bytes = this.__byteOffset % numBytes;\n        if (bytes != 0) {\n            this.__reserve(numBytes - bytes);\n            this.__offset(numBytes - bytes);\n        }\n    }\n}\n\n/**\n * Provides a context for loading assets. This context can provide the units of the loading scene.\n * E.g. you can specify the scene units as 'millimeters' in the context object.\n * To load external references, you can also provide a dictionary that maps filenames to URLs that are used\n * to resolve the URL of an external reference that a given asset is expecting to find.\n */\nclass CloneContext {\n    assetItem;\n    /**\n     * Create a AssetLoadContext\n     * @param context The source context to base this context on.\n     */\n    constructor() {\n        this.assetItem = null;\n    }\n}\n\nvar OperatorOutputMode;\n(function (OperatorOutputMode) {\n    OperatorOutputMode[OperatorOutputMode[\"OP_WRITE\"] = 0] = \"OP_WRITE\";\n    OperatorOutputMode[OperatorOutputMode[\"OP_READ_WRITE\"] = 1] = \"OP_READ_WRITE\";\n})(OperatorOutputMode || (OperatorOutputMode = {}));\n\n/**\n * Represents a reactive type of attribute that can be owned by a `ParameterOwner` class.\n *\n * **Events**\n * * **nameChanged:** Triggered when the name of the parameter changes.\n * * **valueChanged:** Triggered when the value of the parameter changes.\n */\nclass Parameter extends BaseItem {\n    #value;\n    dirty = false;\n    boundInputs = [];\n    boundOutputs = [];\n    cleaning = false;\n    dirtyOpIndex = 0;\n    firstOP_WRITE = 0;\n    dataType;\n    /**\n     * When initializing a new parameter, the passed in value could be anything.\n     * If it is a new type of value, just ensure you register it in the `Registry`.\n     *\n     * How to use it:\n     *\n     * ```javascript\n     *  // Creating a parameter object\n     *  const param = new Parameter('Title', 'Awesome Parameter Value', 'String')\n     *\n     *   // Capturing events\n     *  param.on('valueChanged', (...params) => console.log('Value changed!'))\n     *\n     *  // Changing parameter's value will cause `valueChanged` event to trigger.\n     *  param.setValue('A New Awesome Parameter Value')\n     *  // As result the console log code will execute: Value Changed!\n     * ```\n     *\n     * @param name - The name of the parameter.\n     * @param value - The value of the parameter.\n     * @param dataType - The data type of the parameter.\n     */\n    constructor(name = '', value, dataType) {\n        super(name);\n        this.#value = value;\n        this.dataType = dataType;\n    }\n    /**\n     * Returns parameter's data type.\n     *\n     * @return - The return value.\n     */\n    getDataType() {\n        return this.dataType;\n    }\n    // ////////////////////////////////////////////////\n    // Operator bindings\n    /**\n     * When an Operator is reading from a parameter, it must be dirtied when the parameter value\n     * changes. The Parameter maintains a list of bound inputs and will propagate dirty to\n     * them explicitly.\n     *\n     * @param operatorInput - The output that we are unbinding from the Parameter\n     * @param index - The index(optional) that the output is being bound at.\n     * @return - The index of the bound output.\n     */\n    bindOperatorInput(operatorInput) {\n        this.boundInputs.push(operatorInput);\n    }\n    /**\n     * When an operator is being removed from reading from a Parameter, the Input is removed\n     * This means the operator will no longer receive updates when the operator changes.\n     *\n     * @param operatorInput - The output that we are unbinding from the Parameter\n     * @return - The return value.\n     */\n    unbindOperatorInput(operatorInput) {\n        const index = this.boundInputs.indexOf(operatorInput);\n        this.boundInputs.splice(index, 1);\n    }\n    /**\n     * When an Operator writes to a parameter, it binds its outputs to the parameter at a given\n     * index. Then when the operator is dirtied by one of its inputs, it explicitly dirties\n     * the output parameters.\n     *\n     * @param operatorOutput - The output that we are unbinding from the Parameter\n     * @param index - The index(optional) that the output is being bound at.\n     * @return - The index of the bound output.\n     */\n    bindOperatorOutput(operatorOutput, index = -1) {\n        if (index == -1)\n            index = this.boundOutputs.length;\n        this.boundOutputs.splice(index, 0, operatorOutput);\n        // Update the remaining binding indices\n        for (let i = index; i < this.boundOutputs.length; i++) {\n            this.boundOutputs[i].setParamBindIndex(i);\n        }\n        // If we weren't already dirty, make sure to emit a 'valueChanged' anyway.\n        this.__findFirstOP_WRITE();\n        // This ensures that the operator stack is considered 'clean'\n        // and then we call set dirty to force it to become dirty from the insertion point down.\n        // Without this line, the operator is considered already 'dirty', and so won't propagate.\n        this.dirtyOpIndex = this.boundOutputs.length;\n        this.setDirty(index);\n        return index;\n    }\n    /**\n     * When an operator is unbinding from a parameter, it removes its self from the list maintained\n     * by the parameter.\n     *\n     * @param operatorOutput - The output that we are unbinding from the Parameter\n     * @return - The return value.\n     */\n    unbindOperatorOutput(operatorOutput) {\n        const index = operatorOutput.getParamBindIndex();\n        this.boundOutputs.splice(index, 1);\n        // Update the remaining binding indices\n        for (let i = index; i < this.boundOutputs.length; i++) {\n            this.boundOutputs[i].setParamBindIndex(i);\n        }\n        this.__findFirstOP_WRITE();\n        this.dirtyOpIndex = this.boundOutputs.length;\n        this.setDirty(Math.max(0, index - 1));\n        return index;\n    }\n    /**\n     * Find the first operator in our stack which writes using an OP_WRITE connection.\n     * All operators before this op can be ignored during dirty propagation.\n     * @private\n     */\n    __findFirstOP_WRITE() {\n        this.firstOP_WRITE = this.boundOutputs.length;\n        if (this.boundOutputs.length > 0) {\n            for (this.firstOP_WRITE--; this.firstOP_WRITE > 0; this.firstOP_WRITE--) {\n                // Find the first OP_WRITE binding. (Note: we could cache this)\n                if (this.boundOutputs[this.firstOP_WRITE].getMode() == OperatorOutputMode.OP_WRITE)\n                    break;\n            }\n        }\n    }\n    isDrivenByOperator() {\n        return this.firstOP_WRITE == 0 && this.boundOutputs.length > 0;\n    }\n    /**\n     * Dirties this Parameter so subsequent calls to `getValue` will cause an evaluation of its bound operators.\n     *\n     * @param index - Index of the operator\n     * @return - `true` if the Parameter was made dirty, else `false` if it was already dirty.\n     */\n    setDirty(index) {\n        // Determine the first operator in the stack that must evaluate to clean the parameter.\n        // Note: if a READ_WRITE op is becoming dirty, then we dirty back up to that op.\n        if (index < this.dirtyOpIndex) {\n            // If we must dirty all operators in the stack from the last OP_WRITE to the end.\n            // Note: If a setDirty call comes from an op that precedes an OP_WRITE operator, we\n            // can safely discard it, as its output will have no effect on the value of this parameter.\n            let newDirtyIndex = this.firstOP_WRITE;\n            if (newDirtyIndex <= index) {\n                this.dirtyOpIndex = newDirtyIndex;\n                for (newDirtyIndex++; newDirtyIndex < this.boundOutputs.length; newDirtyIndex++) {\n                    // Dirty all the other bound ops from the OP_WRITE to the top of the stack.\n                    if (newDirtyIndex != index) {\n                        // This will cause the other outputs of the operator to become dirty.\n                        this.boundOutputs[newDirtyIndex].getOperator().setDirty();\n                    }\n                }\n                for (let i = 0; i < this.boundInputs.length; i++) {\n                    this.boundInputs[i].setDirty();\n                }\n                this.emit('valueChanged');\n                return true;\n            }\n        }\n        return false;\n    }\n    /**\n     * Returns true if this parameter is currently dirty and will evaluate its bound\n     * operators if its value is requested by a call to getValue.\n     *\n     * @return - Returns a boolean.\n     */\n    isDirty() {\n        return this.dirtyOpIndex < this.boundOutputs.length;\n    }\n    /**\n     * Returns the index of the first 'dirty' binding in the stack. This will be the index of the\n     * first operator that will evaluate when the parameter needs to be cleaned.\n     *\n     * @return - The index of the dirty binding in the binding stack.\n     */\n    getDirtyBindingIndex() {\n        return this.dirtyOpIndex;\n    }\n    /**\n     * The setCleanFromOp method.\n     * @param value - The computed value to be stored in the Parameter.\n     * @param index - The index of the bound OperatorOutput.\n     */\n    setCleanFromOp(value, index) {\n        if (index != this.dirtyOpIndex) {\n            if (index < this.dirtyOpIndex) {\n                // This can happen when an operator in the following case.\n                // ParamA [OpC, OpB, OpA]\n                // ParamB [OpC, OpA]\n                // When OpB dirties ParamA, and is evaluated, ParamB is considered clean because OpA was never dirtied\n                // We see this message when parameters are evaluated as soon as a change is detected instead of\n                // in batches. Now that all rendering code is pulling data only during the render cycle, we ara\n                // not seeing it anymore. However, maybe with a UI open, it will start emitting this warning.\n                // Note: this would be caused, if a Parameter is already cleaned by an Operator, and yet the Operator\n                // is re-evaluating. I am not sure how this can occur.\n                // const op = operatorOutput.getOperator()\n                // console.log(\n                //   `Operator:: ${\n                //     op.constructor.name\n                //   } with name: ${op.name} is being cleaned immediately, instead of lazily.`\n                // )\n                console.log(`Parameter is cleaned when it was already clean to that point in the stack:`, this.getPath());\n            }\n            else if (this.boundOutputs[index].getMode() != OperatorOutputMode.OP_WRITE) {\n                // A parameter can become dirty (so __dirtyOpIndex == 0), and then another operator bound on top.\n                // if the next op is a WRITE op, then we can fast forward the dirty index.\n                const thisClassName = this.getClassName();\n                const op = this.boundOutputs[index].getOperator();\n                const opClassName = op.constructor.name;\n                throw new Error(`Parameter: ${thisClassName} with name: ${this.getName()} is not cleaning all outputs during evaluation of op: ${opClassName} with name: ${op.name}`);\n            }\n        }\n        this.#value = value;\n        // As each operator writes its value, the dirty value is incremented\n        this.dirtyOpIndex = index + 1;\n    }\n    /**\n     * During operator evaluation, operators can use this method to retrieve the existing\n     * value of one of their outputs.\n     * @param index - The index of the bound OperatorOutput to evaluate up to.\n     * @return - The return value.\n     */\n    getValueFromOp(index) {\n        // Note: during evaluation of an Operator that writes to multiple outputs,\n        // it can write to an output with an IO setting, which means it retrieves\n        // the previous value while calculating the next.\n        if (this.dirtyOpIndex < index) {\n            this._clean(index);\n        }\n        return this.#value;\n    }\n    /**\n     * Cleans the parameter up tp the index of the specified index of the bound OperatorOutput\n     *\n     * @param index - The index of the bound OperatorOutput to evaluate up to.\n     */\n    _clean(index) {\n        if (this.cleaning) {\n            throw new Error(`Cycle detected when cleaning: ${this.getPath()}. Operators need to be rebound to fix errors`);\n        }\n        this.cleaning = true;\n        while (this.dirtyOpIndex < index) {\n            const tmp = this.dirtyOpIndex;\n            const operatorOutput = this.boundOutputs[this.dirtyOpIndex];\n            // The op can get the current value and modify it in place\n            // and set the output to clean.\n            operatorOutput.getOperator().evaluate();\n            if (tmp == this.dirtyOpIndex) {\n                // During initial configuration of an operator, cleaning outputs might be disabled.\n                const op = this.boundOutputs[this.dirtyOpIndex].getOperator();\n                const opClassName = op.constructor.name;\n                console.warn(`Operator: ${opClassName} with name: ${op.name} is not cleaning its outputs during evaluation`);\n                this.dirtyOpIndex++;\n            }\n        }\n        this.cleaning = false;\n    }\n    /**\n     * Returns parameter's value.\n     * @return - The return value.\n     */\n    getValue() {\n        if (this.dirtyOpIndex < this.boundOutputs.length) {\n            this._clean(this.boundOutputs.length);\n        }\n        return this.#value;\n    }\n    /**\n     * Sets value of the parameter.\n     *\n     * @param value - The value param.\n     */\n    setValue(value) {\n        if (value === undefined) {\n            // eslint-disable-next-line no-throw-literal\n            throw 'undefined was passed into the set value for param:' + this.getName();\n        }\n        if (this.boundOutputs.length > 0) {\n            for (let i = this.boundOutputs.length - 1; i >= 0; i--) {\n                const operatorOutput = this.boundOutputs[i];\n                value = operatorOutput.backPropagateValue(value);\n                if (operatorOutput.getMode() == 0 /* OP_WRITE */)\n                    return;\n            }\n        }\n        if (typeof value !== 'object') {\n            // Note: equality tests on anything but simple values is going to be super expensive.\n            if (this.#value == value)\n                return;\n        }\n        this.#value = value;\n        // Note: only users call 'setValue'. Operators call 'setCleanFromOp'\n        for (let i = 0; i < this.boundInputs.length; i++) {\n            this.boundInputs[i].paramValueChanged();\n        }\n        this.emit('valueChanged');\n    }\n    get value() {\n        return this.getValue();\n    }\n    set value(value) {\n        this.setValue(value);\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * The loadValue is used to change the value of a parameter, without triggering a\n     * valueChanges.\n     *\n     * @param value - The context value.\n     */\n    loadValue(value) {\n        this.#value = value;\n    }\n    copyFrom(src, context) {\n        this.loadValue(src.value);\n    }\n    /**\n     * The readBinary method.\n     *\n     * @param reader - The reader value.\n     * @param context - The context value.\n     */\n    readBinary(reader, context) {\n        console.warn(`TODO: Parameter: ${this.constructor.name} with name: ${this.name} does not implement readBinary`);\n    }\n    /**\n     * Returns the parameter's path as an array of strings.\n     * Includes owner's path in case it is owned by a `ParameterOwner`.\n     *\n     * @return - The return value.\n     */\n    getPath() {\n        if (this.ownerItem instanceof BaseItem) {\n            return [...this.ownerItem.getPath(), this.name];\n        }\n        else {\n            return [this.name];\n        }\n    }\n    resolvePath(path, index = 0) {\n        if (index == 0) {\n            if (path[0] == '.' || path[0] == this.name)\n                index++;\n        }\n        if (path[index] == '..') {\n            if (this.ownerItem) {\n                return this.ownerItem.resolvePath(path, index + 1);\n            }\n            else {\n                throw Error('this.ownerItem is undefined');\n            }\n        }\n        if (index == path.length) {\n            return this;\n        }\n        if (path[index] == 'value') {\n            // The path to the parameter, assumes that the next item will be a sub-param\n            // of the value of the parameter.\n            if (this.#value instanceof BaseItem)\n                return this.#value.resolvePath(path, index + 1);\n        }\n        throw new Error('Invalid path:' + path + '[' + index + ']. Path does not resolve to a BaseItem');\n    }\n    /**\n     * The readBinary method.\n     *\n     * @param reader - The reader value.\n     * @param context - The context value.\n     */\n    destroy() {\n        console.warn('nothing destroyed. This method was not overwritten in subclass');\n    }\n}\n\n/**\n * Represents a specific type of parameter, that only stores numeric values.\n *\n * ```javascript\n * const numberParam = new NumberParameter('MyNumber', 15)\n * //'myParameterOwnerItem' is an instance of a 'ParameterOwner' class.\n * // Remember that only 'ParameterOwner' and classes that extend from it can host 'Parameter' objects.\n * myParameterOwnerItem.addParameter(numberParam)\n * ```\n *\n * @extends Parameter\n */\nclass NumberParameter extends Parameter {\n    range; // TODO: should create type with two fields for range. Must change how range is used.\n    step;\n    /**\n     * Create a number parameter.\n     * @param name - The name of the number parameter.\n     * @param value - The value of the parameter.\n     * @param range - An array with two numbers. If defined, the parameter value will be clamped.\n     * @param step - The step value. If defined, the parameter value will be rounded to the nearest integer.\n     */\n    constructor(name = '', value = 0, range, step) {\n        super(name, value, 'Number');\n        this.range = range;\n        this.step = step;\n    }\n    /**\n     * Returns the range to which the parameter is restrained.\n     *\n     * @return - The return value.\n     */\n    getRange() {\n        return this.range;\n    }\n    /**\n     * Sets the range to which the parameter is restrained.\n     *\n     * @param range - The range value.\n     */\n    setRange(range) {\n        this.range = range;\n    }\n    /**\n     * Returns the step number, which is the one used for rounding.\n     *\n     * @return - The return value.\n     */\n    getStep() {\n        return this.step;\n    }\n    /**\n     * Returns step value.\n     *\n     * @param step - The step value.\n     */\n    setStep(step) {\n        this.step = step;\n    }\n    setValue(value) {\n        if (typeof value != 'number') {\n            throw new Error(`value provided is not a number. Check the source of this value`);\n        }\n        super.setValue(value);\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * The toJSON method encodes this type as a json object for persistence.\n     *\n     * @param context - The context value.\n     * @return - Returns the json object.\n     */\n    toJSON(context) {\n        return { type: this.getClassName(), name: this.name, value: this.value };\n    }\n    /**\n     * The fromJSON method decodes a json object for this type.\n     *\n     * @param j - The json object this item must decode.\n     * @param context - The context value.\n     */\n    fromJSON(j, context) {\n        this.value = j.value;\n    }\n    /**\n     * Extracts a number value from a buffer, updating current parameter state.\n     *\n     * @param reader - The reader value.\n     * @param context - The context value.\n     */\n    readBinary(reader, context) {\n        this.value = reader.loadFloat32();\n    }\n    // ////////////////////////////////////////\n    // Clone\n    /**\n     * The clone method constructs a new number parameter, copies its values\n     * from this parameter and returns it.\n     *\n     * @return - Returns a new number parameter.\n     */\n    clone() {\n        return new NumberParameter(this.name, this.value, this.range, this.step);\n    }\n}\n// eslint-disable-next-line require-jsdoc\nclass Float32Parameter extends NumberParameter {\n    // eslint-disable-next-line require-jsdoc\n    readBinary(reader, context) {\n        this.value = reader.loadFloat32();\n    }\n}\n// eslint-disable-next-line require-jsdoc\nclass SInt32Parameter extends NumberParameter {\n    // eslint-disable-next-line require-jsdoc\n    readBinary(reader, context) {\n        this.value = reader.loadSInt32();\n    }\n}\n// eslint-disable-next-line require-jsdoc\nclass UInt32Parameter extends NumberParameter {\n    // eslint-disable-next-line require-jsdoc\n    readBinary(reader, context) {\n        this.value = reader.loadUInt32();\n    }\n}\n// eslint-disable-next-line require-jsdoc\nclass AngleParameter extends Float32Parameter {\n}\nRegistry.register('NumberParameter', NumberParameter);\nRegistry.register('Property_SInt32', SInt32Parameter);\nRegistry.register('Property_UInt32', UInt32Parameter);\nRegistry.register('Property_Float32', Float32Parameter);\nRegistry.register('AngleParameter', AngleParameter);\n\n/**\n * Represents a specific type of parameter, that stores multiple choice(array) values.\n *\n * i.e.:\n * ```javascript\n * const multiChoiceParameter =  new MultiChoiceParameter('InitialXfoMode', GROUP_INITIAL_XFO_MODES.average, [\n *                                  'manual',\n *                                  'first',\n *                                  'average',\n *                                  'global',\n *                                ])\n * //'myParameterOwnerItem' is an instance of a 'ParameterOwner' class.\n * // Remember that only 'ParameterOwner' and classes that extend from it can host 'Parameter' objects.\n * myParameterOwnerItem.addParameter(multiChoiceParameter)\n * ```\n * @extends NumberParameter\n */\nclass MultiChoiceParameter extends NumberParameter {\n    choices;\n    /**\n     * Create a multi choice parameter.\n     * @param name - The name of the multi choice parameter.\n     * @param index - The index value.\n     * @param choices - The choices value.\n     */\n    constructor(name, index, choices = []) {\n        super(name, index, [0, choices.length], 1);\n        this.choices = choices;\n    }\n    /**\n     * Returns choices array.\n     *\n     * @return - The return value.\n     */\n    getChoices() {\n        return this.choices;\n    }\n    /**\n     * Sets parameter index value.\n     *\n     * @param value - The value param.\n     */\n    setValue(value) {\n        if (typeof value === 'string') {\n            const index = this.choices.indexOf(value);\n            if (index === -1) {\n                console.error(`Invalid value for MultiChoiceParameter: ${value}. choices are: ${this.choices}.`);\n            }\n            else {\n                super.setValue(index);\n            }\n        }\n        else {\n            super.setValue(value);\n        }\n    }\n    clone() {\n        return new MultiChoiceParameter(this.name, this.value, this.choices);\n    }\n}\nRegistry.register('MultiChoiceParameter', MultiChoiceParameter);\n\n/* eslint-disable @typescript-eslint/no-unused-vars */\n/**\n * Represents a specific type of parameter, that only stores `boolean` values.\n *\n * i.e.:\n * ```javascript\n * const booleanParam = new BooleanParameter('MyBoolean', true)\n * //'myParameterOwnerItem' is an instance of a 'ParameterOwner' class.\n * // Remember that only 'ParameterOwner' and classes that extend from it can host 'Parameter' objects.\n * myParameterOwnerItem.addParameter(booleanParam)\n * ```\n * @extends Parameter\n */\nclass BooleanParameter extends Parameter {\n    /**\n     * Creates a new parameter with `Boolean` data type.\n     *\n     * @param name - The name of the boolean parameter.\n     * @param value - The value of the parameter.\n     */\n    constructor(name = '', value) {\n        super(name, value != undefined ? value : false, 'Boolean');\n    }\n    setValue(value) {\n        if (typeof value != 'boolean') {\n            throw new Error(`value provided is not a boolean. Check the source of this value`);\n        }\n        super.setValue(value);\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * Loads the boolean values from the binary buffer.\n     *\n     * @param reader - The reader value.\n     * @param context - The context value.\n     */\n    readBinary(reader, context) {\n        this.value = reader.loadUInt8() != 0;\n    }\n    /**\n     * The toJSON method serializes this instance as a JSON.\n     * It can be used for persistence, data transfer, etc.\n     *\n     * @param context - The context value.\n     * @return - Returns the json object.\n     */\n    toJSON(context) {\n        return { type: this.getClassName(), name: this.name, value: this.value };\n    }\n    /**\n     * The fromJSON method takes a JSON and deserializes into an instance of this type.\n     *\n     * @param j - The json object this item must decode.\n     * @param context - The context value.\n     */\n    fromJSON(j, context) {\n        this.value = j.value;\n    }\n    /**\n     * The clone method constructs a new parameter, copies its values\n     * from this parameter and returns it.\n     *\n     * @return - Returns a new cloned parameter.\n     */\n    clone() {\n        return new BooleanParameter(this.name, this.value);\n    }\n}\nRegistry.register('BooleanParameter', BooleanParameter);\nRegistry.register('Property_Boolean', BooleanParameter);\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/**\n * Represents a specific type of parameter, that only stores Vec2(two-dimensional coordinate) values.\n *\n * i.e.:\n * ```javascript\n * const vec2Param = new Vec2Parameter('MyVec2', new Vec2(1.2, 3.4))\n * //'myParameterOwnerItem' is an instance of a 'ParameterOwner' class.\n * // Remember that only 'ParameterOwner' and classes that extend from it can host 'Parameter' objects.\n * myParameterOwnerItem.addParameter(vec2Param)\n * ```\n *\n * **Events**\n * * **rangeChanged:** Triggered when rage array changes.\n *\n * @extends Parameter\n */\nclass Vec2Parameter extends Parameter {\n    range;\n    /**\n     * Create a Vec2 parameter.\n     *\n     * @param name - The name of the Vec2 parameter.\n     * @param value - The value of the parameter.\n     * @param range - The range value is an array of two `Vec2` objects.\n     */\n    constructor(name = '', value, range) {\n        super(name, value ? value : new Vec2(), 'Vec2');\n        this.range = range;\n    }\n    /**\n     * Returns the range of values in which current parameter can be.\n     *\n     * @return - The return value.\n     */\n    getRange() {\n        // Range should be an array of 2 vec2s. [min(x,y), max(x,y)]\n        return this.range;\n    }\n    /**\n     * The __setRange method.\n     * @param range - The range value.\n     * @private\n     */\n    setRange(range) {\n        // Should be an array [0, 20]\n        this.range = range;\n        this.emit('rangeChanged', { range });\n    }\n    setValue(value) {\n        if (!(value instanceof Vec2)) {\n            throw new Error(`value provided is not an instance of a 'Vec2' class. Check the source of this value`);\n        }\n        super.setValue(value);\n    }\n    /**\n     * Extracts a number value from a buffer, updating current parameter state.\n     *\n     * @param reader - The reader value.\n     * @param context - The context value.\n     */\n    readBinary(reader, context) {\n        this.value?.readBinary(reader);\n    }\n    toJSON(context) {\n        return {\n            type: this.getClassName(),\n            name: this.name,\n            value: this.value?.toJSON(),\n        };\n    }\n    fromJSON(j, context) {\n        const vec2 = new Vec2();\n        vec2.fromJSON(j.value);\n        this.value = vec2;\n        if (j.name)\n            this.name = j.name;\n    }\n    /**\n     * The clone method constructs a new Vec2 parameter, copies its values\n     * from this parameter and returns it.\n     *\n     * @return - Returns a new Vec2 parameter.\n     */\n    clone() {\n        const clonedParam = new Vec2Parameter(this.name, this.value?.clone());\n        if (this.range)\n            clonedParam.setRange(this.range);\n        return clonedParam;\n    }\n}\nRegistry.register('Vec2Parameter', Vec2Parameter);\nRegistry.register('Property_Vec2_32f', Vec2Parameter);\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/**\n * Represents a specific type of parameter, that only stores Vec3(three-dimensional coordinate) values.\n *\n * i.e.:\n * ```javascript\n * const vec3Param = new Vec3Parameter('MyVec3', new Vec3(1.2, 3.4, 1))\n * //'myParameterOwnerItem' is an instance of a 'ParameterOwner' class.\n * // Remember that only 'ParameterOwner' and classes that extend from it can host 'Parameter' objects.\n * myParameterOwnerItem.addParameter(vec3Param)\n * ```\n * @extends Parameter\n */\nclass Vec3Parameter extends Parameter {\n    range;\n    /**\n     * Create a Vec3 parameter.\n     *\n     * @param name - The name of the Vec3 parameter.\n     * @param value - The value of the parameter.\n     * @param range - The range value is an array of two `Vec3` objects.\n     */\n    constructor(name = '', value, range) {\n        super(name, value ? value : new Vec3(), 'Vec3');\n        this.range = range;\n    }\n    setValue(value) {\n        if (!(value instanceof Vec3)) {\n            throw new Error(`value provided is not an instance of a 'Vec2' class. Check the source of this value`);\n        }\n        super.setValue(value);\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * Extracts a number value from a buffer, updating current parameter state.\n     *\n     * @param reader - The reader value.\n     * @param context - The context value.\n     */\n    readBinary(reader, context) {\n        this.value?.readBinary(reader);\n    }\n    toJSON(context) {\n        return {\n            type: this.getClassName(),\n            name: this.name,\n            value: this.value?.toJSON(),\n        };\n    }\n    fromJSON(j, context) {\n        const vec4 = new Vec3();\n        vec4.fromJSON(j.value);\n        this.value = vec4;\n        if (j.name)\n            this.name = j.name;\n    }\n    /**\n     * The clone method constructs a new Vec3 parameter, copies its values\n     * from this parameter and returns it.\n     *\n     * @return - Returns a new Vec3 parameter.\n     */\n    clone() {\n        const clonedParam = new Vec3Parameter(this.name, this.value?.clone());\n        return clonedParam;\n    }\n}\nRegistry.register('Vec3Parameter', Vec3Parameter);\nRegistry.register('Property_Vec3_32f', Vec3Parameter);\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/**\n * Represents a specific type of parameter, that only stores Vec4(four-dimensional coordinate) values.\n *\n * i.e.:\n * ```javascript\n * const vec4Param = new Vec4Parameter('MyVec4', new Vec4(1.2, 3.4, 1, 4.2))\n * //'myParameterOwnerItem' is an instance of a 'ParameterOwner' class.\n * // Remember that only 'ParameterOwner' and classes that extend from it can host 'Parameter' objects.\n * myParameterOwnerItem.addParameter(vec4Param)\n * ```\n *\n * @extends Parameter\n */\nclass Vec4Parameter extends Parameter {\n    /**\n     * Create a Vec4 parameter.\n     * @param name - The name of the Vec4 parameter.\n     * @param value - The value of the parameter.\n     */\n    constructor(name = '', value) {\n        super(name, value ? value : new Vec4(), 'Vec4');\n    }\n    setValue(value) {\n        if (!(value instanceof Vec4)) {\n            throw new Error(`value provided is not an instance of a 'Vec4' class. Check the source of this value`);\n        }\n        super.setValue(value);\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * Extracts a number value from a buffer, updating current parameter state.\n     *\n     * @param reader - The reader value.\n     * @param context - The context value.\n     */\n    readBinary(reader, context) {\n        this.value?.readBinary(reader);\n    }\n    toJSON(context) {\n        return { type: this.getClassName(), name: this.name, value: this.value?.toJSON() };\n    }\n    fromJSON(j, context) {\n        const vec4 = new Vec4();\n        vec4.fromJSON(j.value);\n        this.value = vec4;\n        if (j.name)\n            this.name = j.name;\n    }\n    // ////////////////////////////////////////\n    // Clone\n    /**\n     * The clone method constructs a new Vec4 parameter, copies its values\n     * from this parameter and returns it.\n     *\n     * @return - Returns a new Vec4 parameter.\n     */\n    clone() {\n        const clonedParam = new Vec4Parameter(this.name, this.value?.clone());\n        return clonedParam;\n    }\n}\nRegistry.register('Vec4Parameter', Vec4Parameter);\nRegistry.register('Property_Vec4_32f', Vec4Parameter);\n\n/* eslint-disable @typescript-eslint/no-unused-vars */\n/**\n * @extends Parameter\n */\nclass Box2Parameter extends Parameter {\n    /**\n     * Create a Box2 parameter.\n     * @param name - The name of the Box2 parameter.\n     * @param value - The value of the parameter.\n     */\n    constructor(name = '', value) {\n        super(name, value ? value : new Box2(), 'Box2');\n    }\n    setValue(value) {\n        if (!(value instanceof Box2)) {\n            throw new Error(`value provided is not an instance of a 'Box2' class. Check the source of this value`);\n        }\n        super.setValue(value);\n    }\n    /**\n     * Extracts a number value from a buffer, updating current parameter state.\n     *\n     * @param reader - The reader value.\n     * @param context - The context value.\n     */\n    readBinary(reader, context) {\n        this.value.p0.readBinary(reader);\n        this.value.p1.readBinary(reader);\n    }\n    toJSON(context) {\n        return {\n            type: this.getClassName(),\n            name: this.name,\n            value: {\n                p0: this.value.p0.toJSON(),\n                p1: this.value.p1.toJSON(),\n            },\n        };\n    }\n    fromJSON(j, context) {\n        this.value.p0.fromJSON(j.p0);\n        this.value.p1.fromJSON(j.p1);\n    }\n    /**\n     * The clone method constructs a new Box2 parameter,\n     * copies its values from this parameter and returns it.\n     *\n     * @return - Returns a new cloned Box2 parameter.\n     */\n    clone() {\n        const clonedParam = new Box2Parameter(this.name, this.value?.clone());\n        return clonedParam;\n    }\n}\nRegistry.register('Box2Parameter', Box2Parameter);\nRegistry.register('Property_Box2_32f', Box2Parameter);\n\n/* eslint-disable @typescript-eslint/no-unused-vars */\n/**\n * @extends Parameter\n */\nclass Box3Parameter extends Parameter {\n    /**\n     * Create a Box3 parameter.\n     * @param name - The name of the Box3 parameter.\n     * @param value - The value of the parameter.\n     */\n    constructor(name = '', value) {\n        super(name, value ? value : new Box3(), 'Box3');\n    }\n    setValue(value) {\n        if (!(value instanceof Box3)) {\n            throw new Error(`value provided is not an instance of a 'Box3' class. Check the source of this value`);\n        }\n        super.setValue(value);\n    }\n    /**\n     * Extracts a number value from a buffer, updating current parameter state.\n     *\n     * @param reader - The reader value.\n     * @param context - The context value.\n     */\n    readBinary(reader, context) {\n        this.value.p0.readBinary(reader);\n        this.value.p1.readBinary(reader);\n    }\n    toJSON(context) {\n        return {\n            type: this.getClassName(),\n            name: this.name,\n            value: this.value.toJSON(),\n        };\n    }\n    fromJSON(j, context) {\n        if (j.value) {\n            // @ts-ignore\n            this.value.fromJSON(j.value);\n        }\n    }\n    /**\n     * The clone method constructs a new Box3 parameter,\n     * copies its values from this parameter and returns it.\n     *\n     * @return - Returns a new cloned Box3 parameter.\n     */\n    clone() {\n        const clonedParam = new Box3Parameter(this.name, this.value?.clone());\n        return clonedParam;\n    }\n}\nRegistry.register('Box3Parameter', Box3Parameter);\nRegistry.register('Property_Box3_32f', Box3Parameter);\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/**\n * Represents a specific type of parameter, that only stores `Color` values.\n *\n * i.e.:\n * ```javascript\n * const colorParam = new ColorParameter('MyColor', new Color(0, 254, 2))\n * //'myParameterOwnerItem' is an instance of a 'ParameterOwner' class.\n * // Remember that only 'ParameterOwner' and classes that extend from it can host 'Parameter' objects.\n * myParameterOwnerItem.addParameter(colorParam)\n * ```\n *\n * @extends Parameter\n */\nclass ColorParameter extends Parameter {\n    /**\n     * Create a color parameter.\n     * @param name - The name of the color parameter.\n     * @param value - The value of the parameter.\n     */\n    constructor(name = '', value) {\n        super(name, value ? value : new Color(), 'Color');\n    }\n    setValue(value) {\n        if (!(value instanceof Color)) {\n            throw new Error(`value provided is not an instance of a 'Color' class. Check the source of this value`);\n        }\n        super.setValue(value);\n    }\n    /**\n     * Extracts `Color` values from a buffer, updating current parameter state.\n     *\n     * @param reader - The reader value.\n     * @param context - The context value.\n     */\n    readBinary(reader, context) {\n        const value = reader.loadRGBAFloat32Color();\n        // If the value is in linear space, then we should convert it to gamma space.\n        // Note: !! this should always be done in preprocessing...\n        value.applyGamma(2.2);\n        this.value = value;\n    }\n    toJSON(context) {\n        return {\n            type: this.getClassName(),\n            name: this.name,\n            value: this.value?.toJSON(),\n        };\n    }\n    fromJSON(j, context) {\n        // if (j.value.type) this.value = Registry.constructClass('Color') as Color // TODO: commented out Registry.constructClass\n        this.value?.fromJSON(j.value);\n    }\n    /**\n     * The clone method constructs a new color parameter,\n     * copies its values from this parameter and returns it.\n     *\n     * @return - Returns a new cloned color parameter.\n     */\n    clone() {\n        const clonedParam = new ColorParameter(this.name, this.value?.clone());\n        return clonedParam;\n    }\n}\nRegistry.register('ColorParameter', ColorParameter);\nRegistry.register('Property_Color_32f', ColorParameter);\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/**\n * Represents a specific type of parameter, that only stores Vec3(four-dimensional coordinate) values.\n *\n * i.e.:\n * ```javascript\n * const quatParam = new QuatParameter('MyQuat', new Quat(1.2, 3.4, 1, 4.2))\n * //'myParameterOwnerItem' is an instance of a 'ParameterOwner' class.\n * // Remember that only 'ParameterOwner' and classes that extend from it can host 'Parameter' objects.\n * myParameterOwnerItem.addParameter(quatParam)\n * ```\n *\n * @extends Parameter\n */\nclass QuatParameter extends Parameter {\n    /**\n     * Create a Quat parameter.\n     * @param name - The name of the Quat parameter.\n     * @param value - The value of the parameter.\n     */\n    constructor(name = '', value) {\n        super(name, value ? value : new Quat(), 'Quat');\n    }\n    setValue(value) {\n        if (!(value instanceof Quat)) {\n            throw new Error(`value provided is not an instance of a 'Quat' class. Check the source of this value`);\n        }\n        super.setValue(value);\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * Extracts a number value from a buffer, updating current parameter state.\n     *\n     * @param reader - The reader value.\n     * @param context - The context value.\n     */\n    readBinary(reader, context) {\n        this.value?.readBinary(reader);\n    }\n    toJSON(context) {\n        return {\n            type: this.getClassName(),\n            name: this.name,\n            value: this.value?.toJSON(),\n        };\n    }\n    fromJSON(j, context) {\n        const quat = new Quat();\n        quat.fromJSON(j.value);\n        this.value = quat;\n    }\n    // ////////////////////////////////////////\n    // Clone\n    /**\n     * The clone method constructs a new Quat parameter, copies its values\n     * from this parameter and returns it.\n     *\n     * @return - Returns a new Quat parameter.\n     */\n    clone() {\n        const clonedParam = new QuatParameter(this.name, this.value?.clone());\n        return clonedParam;\n    }\n}\nRegistry.register('QuatParameter', QuatParameter);\nRegistry.register('Property_Quat_32f', QuatParameter);\n\n/* eslint-disable @typescript-eslint/no-unused-vars */\n/**\n * Represents a specific type of parameter, that only stores Mat3(3x3 matrix) values.\n *\n * i.e.:\n * ```javascript\n * const mat3Param = new Ma3Parameter('MyMat3', new Mat3(...args))\n * //'myParameterOwnerItem' is an instance of a 'ParameterOwner' class.\n * // Remember that only 'ParameterOwner' and classes that extend from it can host 'Parameter' objects.\n * myParameterOwnerItem.addParameter(mat3Param)\n * ```\n *\n * @extends Parameter\n */\nclass Mat3Parameter extends Parameter {\n    /**\n     * Create a Mat3 parameter.\n     * @param name - The name of the Mat3 parameter.\n     * @param value - The value of the parameter.\n     */\n    constructor(name = '', value) {\n        super(name, value ? value : new Mat3(), 'Mat3');\n    }\n    setValue(value) {\n        if (!(value instanceof Mat3)) {\n            throw new Error(`value provided is not an instance of a 'Mat3' class. Check the source of this value`);\n        }\n        super.setValue(value);\n    }\n    /**\n     * Extracts a number value from a buffer, updating current parameter state.\n     *\n     * @param reader - The reader value.\n     * @param context - The context value.\n     */\n    readBinary(reader, context) {\n        this.value?.readBinary(reader);\n    }\n    toJSON(context) {\n        return {\n            type: this.getClassName(),\n            name: this.name,\n            value: this.value?.toJSON(),\n        };\n    }\n    fromJSON(j, context) {\n        const mat3 = new Mat3();\n        mat3.fromJSON(j.value);\n        this.value = mat3;\n    }\n    /**\n     * The clone method constructs a new Mat3 parameter,\n     * copies its values from this parameter and returns it.\n     *\n     * @return - Returns a new cloned Mat3 parameter.\n     */\n    clone() {\n        const clonedParam = new Mat3Parameter(this.name, this.value?.clone());\n        return clonedParam;\n    }\n}\nRegistry.register('Mat3Parameter', Mat3Parameter);\nRegistry.register('Property_Mat3_32f', Mat3Parameter);\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/**\n * Represents a specific type of parameter, that only stores Mat4(4x4 matrix) values.\n *\n * i.e.:\n * ```javascript\n * const mat4Param = new Ma3Parameter('MyMat4', new Mat4(...args))\n * //'myParameterOwnerItem' is an instance of a 'ParameterOwner' class.\n * // Remember that only 'ParameterOwner' and classes that extend from it can host 'Parameter' objects.\n * myParameterOwnerItem.addParameter(mat4Param)\n * ```\n *\n * @extends Parameter\n */\nclass Mat4Parameter extends Parameter {\n    /**\n     * Create a Mat4 parameter.\n     *\n     * @param name - The name of the Mat4 parameter.\n     * @param value - The value of the parameter.\n     */\n    constructor(name = '', value) {\n        super(name, value ? value : new Mat4(), 'Mat4');\n    }\n    setValue(value) {\n        if (!(value instanceof Mat4)) {\n            throw new Error(`value provided is not an instance of a 'Mat4' class. Check the source of this value`);\n        }\n        super.setValue(value);\n    }\n    /**\n     * Extracts a number value from a buffer, updating current parameter state.\n     *\n     * @param reader - The reader value.\n     * @param context - The context value.\n     */\n    readBinary(reader, context) {\n        this.value?.readBinary(reader);\n    }\n    toJSON(context) {\n        return {\n            type: this.getClassName(),\n            value: this.value?.toJSON(),\n        };\n    }\n    fromJSON(j, context) {\n        const mat4 = new Mat4();\n        mat4.fromJSON(j.value);\n        this.value = mat4;\n    }\n    /**\n     * The clone method constructs a new Mat4 parameter,\n     * copies its values from this parameter and returns it.\n     *\n     * @return - Returns a new cloned Mat4 parameter.\n     */\n    clone() {\n        const clonedParam = new Mat4Parameter(this.name, this.value?.clone());\n        return clonedParam;\n    }\n}\nRegistry.register('Mat4Parameter', Mat4Parameter);\nRegistry.register('Property_Mat4_32f', Mat4Parameter);\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/**\n * Represents a specific type of parameter, that only stores `Xfo` transform values.\n *\n * ```javascript\n * const xfoParam = new XfoParameter('MyXfo', new Xfo(new Vec3(1.2, 3.4, 1)))\n * //'myParameterOwnerItem' is an instance of a 'ParameterOwner' class.\n * // Remember that only 'ParameterOwner' and classes that extend from it can host 'Parameter' objects.\n * myParameterOwnerItem.addParameter(xfoParam)\n * ```\n *\n * @extends Parameter\n */\nclass XfoParameter extends Parameter {\n    /**\n     * Create a Xfo parameter.\n     * @param name - The name of the Xfo parameter.\n     * @param value - The value of the parameter.\n     */\n    constructor(name = '', value) {\n        super(name, value ? value : new Xfo(), 'Xfo');\n    }\n    setValue(value) {\n        if (!(value instanceof Xfo)) {\n            throw new Error(`value provided is not an instance of a 'Xfo' class. Check the source of this value`);\n        }\n        super.setValue(value);\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * Extracts a number value from a buffer, updating current parameter state.\n     *\n     * @param reader - The reader value.\n     * @param context - The context value.\n     */\n    readBinary(reader, context) {\n        this.value.readBinary(reader);\n    }\n    toJSON(context) {\n        return { type: this.getClassName(), name: this.name, value: this.value.toJSON() };\n    }\n    fromJSON(j, context) {\n        const xfo = new Xfo();\n        xfo.fromJSON(j.value);\n        this.value = xfo;\n        if (j.name)\n            this.name = j.name;\n    }\n    // ////////////////////////////////////////\n    // Clone\n    /**\n     * The clone method constructs a new Xfo parameter, copies its values\n     * from this parameter and returns it.\n     *\n     * @return - Returns a new Xfo parameter.\n     */\n    clone() {\n        const clonedParam = new XfoParameter(this.name, this.value.clone());\n        return clonedParam;\n    }\n}\nRegistry.register('XfoParameter', XfoParameter);\nRegistry.register('Property_Xfo_32f', XfoParameter);\n\n/**\n * Represents a 2D image item, containing width and height.\n *\n * **Events**\n * * **updated:** Triggered when the value of any of the parameters listed above changes.\n *\n * @extends ParameterOwner\n */\nclass BaseImage extends ParameterOwner {\n    width = 0;\n    height = 0;\n    format = 'RGB';\n    type = 'UNSIGNED_BYTE';\n    loaded = false;\n    mipMapped = true;\n    wrapS = 'REPEAT';\n    wrapT = 'REPEAT';\n    minFilter = 'LINEAR';\n    magFilter = 'LINEAR';\n    /**\n     * Creates an instance of BaseImage.\n     * @param name - name of the item\n     */\n    constructor(name = 'Image') {\n        super(name);\n        this.on('parameterValueChanged', () => {\n            this.emit('updated');\n        });\n    }\n    /**\n     * Returns true if loaded.\n     * @private\n     * @return - Returns a boolean.\n     */\n    isLoaded() {\n        return this.loaded;\n    }\n    /**\n     * Returns all parameters and class state values.\n     *\n     * @return - The return value.\n     */\n    getParams() {\n        return {\n            type: this.type,\n            format: this.format,\n            width: this.width,\n            height: this.height,\n            wrapS: this.wrapS,\n            wrapT: this.wrapT,\n            minFilter: this.minFilter,\n            magFilter: this.magFilter,\n            mipMapped: this.mipMapped,\n        };\n    }\n}\n\n/* eslint-disable @typescript-eslint/no-unused-vars */\n/**\n * Represents a specific type of parameter, that only stores `BaseImage` values.\n *\n * i.e.:\n * ```javascript\n * // Since `Label` is a `BaseImage` implementation, it helps us with the example.\n * const label = new Label('My awesome label', 'LabelPack')\n * const imageParam = new ImageParameter('MyImage', label)\n * //'myParameterOwnerItem' is an instance of a 'ParameterOwner' class.\n * // Remember that only 'ParameterOwner' and classes that extend from it can host 'Parameter' objects.\n * myParameterOwnerItem.addParameter(imageParam)\n * ```\n *\n * @extends Parameter\n */\nclass ImageParameter extends Parameter {\n    /**\n     * Create an image parameter.\n     *\n     * @param name - The name of the image parameter.\n     * @param value - The value of the parameter.\n     */\n    constructor(name = '', value) {\n        super(name, value, 'BaseImage');\n    }\n    setValue(value) {\n        if (!(value instanceof BaseImage)) {\n            throw new Error(`value provided is not an instance of 'BaseImage' class. Check the source of this value`);\n        }\n        super.setValue(value);\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * The toJSON method encodes this type as a json object for persistence.\n     *\n     * @param context - The context value.\n     * @return - Returns the json object.\n     */\n    toJSON(context) {\n        const j = {\n            type: this.getClassName(),\n            name: this.name,\n        };\n        if (this.value) {\n            j.imageType = this.value.getClassName();\n            j.value = this.value.toJSON();\n        }\n        return j;\n    }\n    /**\n     * The fromJSON method decodes a json object for this type.\n     *\n     * @param j - The json object this item must decode.\n     * @param context - The context value.\n     * @return - Returns the json object.\n     */\n    fromJSON(j, context) {\n        if (j.imageType) {\n            this.value = Registry.constructClass(j.imageType);\n            if (j.value)\n                this.value?.fromJSON(j.value, context);\n        }\n    }\n    // ////////////////////////////////////////\n    // Clone\n    /**\n     * The clone method constructs a new image parameter,\n     * copies its values from this parameter and returns it.\n     *\n     * @return - Returns a new cloned image parameter.\n     */\n    clone() {\n        const clonedParam = new ImageParameter(this.name, this.value);\n        return clonedParam;\n    }\n}\nRegistry.register('ImageParameter', ImageParameter);\n\n/* eslint-disable @typescript-eslint/no-unused-vars */\n/**\n * Represents a specific type of parameter, that only stores Mat4(4x4 matrix) values.\n *\n * i.e.:\n * ```javascript\n * const stringParam = new StringParameter('MyString', 'A String value goes here')\n * //'myParameterOwnerItem' is an instance of a 'ParameterOwner' class.\n * // Remember that only 'ParameterOwner' and classes that extend from it can host 'Parameter' objects.\n * myParameterOwnerItem.addParameter(stringParam)\n * ```\n *\n * @extends Parameter\n */\nclass StringParameter extends Parameter {\n    multiLine;\n    /**\n     * Create a string parameter.\n     * @param name - The name of the material color parameter.\n     * @param value - The value of the parameter.\n     */\n    constructor(name = '', value = '') {\n        super(name, value, 'String');\n        this.multiLine = false;\n    }\n    /**\n     * Sets flag that indicates if the string contains new line feeds.\n     *\n     * @param multiLine - The multiLine value.\n     */\n    setMultiLine(multiLine) {\n        this.multiLine = multiLine;\n    }\n    /**\n     * Returns multi-line flag value.\n     *\n     * @return - The return value.\n     */\n    getMultiLine() {\n        return this.multiLine;\n    }\n    setValue(value) {\n        if (typeof value != 'string') {\n            throw new Error(`value provided is not a string. Check the source of this value`);\n        }\n        super.setValue(value);\n    }\n    /**\n     * Extracts the string value from a buffer, updating current parameter state.\n     *\n     * @param reader - The reader value.\n     * @param context - The context value.\n     */\n    readBinary(reader, context) {\n        this.value = reader.loadStr();\n    }\n    /**\n     * The toJSON method serializes this instance as a JSON.\n     * It can be used for persistence, data transfer, etc.\n     *\n     * @param context - The context value.\n     * @return - Returns the json object.\n     */\n    toJSON(context) {\n        return { type: this.getClassName(), name: this.name, value: this.value };\n    }\n    /**\n     * The fromJSON method takes a JSON and deserializes into an instance of this type.\n     *\n     * @param j - The json object this item must decode.\n     * @param context - The context value.\n     */\n    fromJSON(j, context) {\n        const newValue = j.value ?? '';\n        if (this.value != newValue) {\n            this.value = newValue;\n        }\n    }\n    /**\n     * The clone method constructs a new string parameter, copies its values\n     * from this parameter and returns it.\n     *\n     * @return - Returns a new string parameter.\n     */\n    clone() {\n        return new StringParameter(this.name, this.value);\n    }\n}\nRegistry.register('StringParameter', StringParameter);\nRegistry.register('Property_String', StringParameter);\n\n/**\n * A parameter for storing an array of string values.\n *\n * @extends Parameter\n */\nclass StringListParameter extends Parameter {\n    /**\n     * Create a string parameter.\n     * @param {string} name - The name of the material color parameter.\n     * @param {string} value - The value of the parameter.\n     */\n    constructor(name = '', value = []) {\n        super(name, value, 'String[]');\n    }\n    setValue(value) {\n        if (!Array.isArray(value)) {\n            throw new Error(`value provided is not an array. Check the source of this value`);\n        }\n        super.setValue(value);\n    }\n    /**\n     * Extracts the string value from a buffer, updating current parameter state.\n     *\n     * @param {BinReader} reader - The reader value.\n     * @param {object} context - The context value.\n     */\n    readBinary(reader, context) {\n        this.value = reader.loadStrArray();\n    }\n    /**\n     * The toJSON method serializes this instance as a JSON.\n     * It can be used for persistence, data transfer, etc.\n     *\n     * @param {Record<string, unknown>} context - The context value.\n     * @return {Record<string, boolean | undefined>} - Returns the json object.\n     */\n    toJSON(context) {\n        return { type: this.getClassName(), name: this.name, value: this.value };\n    }\n    /**\n     * The fromJSON method takes a JSON and deserializes into an instance of this type.\n     *\n     * @param {Record<string, boolean | undefined>} j - The json object this item must decode.\n     * @param {Record<string, unknown>} context - The context value.\n     */\n    fromJSON(j, context) {\n        this.value = j.value;\n    }\n    /**\n     * The clone method constructs a new string parameter, copies its values\n     * from this parameter and returns it.\n     *\n     * @return {StringListParameter} - Returns a new string parameter.\n     */\n    clone() {\n        const clonedParam = new StringListParameter(this.name, this.value);\n        return clonedParam;\n    }\n}\nRegistry.register('StringListParameter', StringListParameter);\nRegistry.register('Property_StringList', StringListParameter);\n\n/**\n * A parameter for storing an array of string values.\n *\n * @extends Parameter\n */\nclass Float32ArrayParameter extends Parameter {\n    /**\n     * Create a string parameter.\n     * @param {string} name - The name of the material color parameter.\n     * @param {string} value - The value of the parameter.\n     */\n    constructor(name = '', value = new Float32Array()) {\n        super(name, value, 'Float[]');\n    }\n    /**\n     * Extracts the string value from a buffer, updating current parameter state.\n     *\n     * @param {BinReader} reader - The reader value.\n     * @param {object} context - The context value.\n     */\n    readBinary(reader, context) {\n        this.value = reader.loadFloat32Array();\n    }\n    /**\n     * The toJSON method serializes this instance as a JSON.\n     * It can be used for persistence, data transfer, etc.\n     *\n     * @param {Record<string, unknown>} context - The context value.\n     * @return {Record<string, boolean | undefined>} - Returns the json object.\n     */\n    toJSON(context) {\n        return { type: this.getClassName(), name: this.name, value: this.value };\n    }\n    /**\n     * The fromJSON method takes a JSON and deserializes into an instance of this type.\n     *\n     * @param {Record<string, boolean | undefined>} j - The json object this item must decode.\n     * @param {Record<string, unknown>} context - The context value.\n     */\n    fromJSON(j, context) {\n        this.value = j.value;\n    }\n    /**\n     * The clone method constructs a new string parameter, copies its values\n     * from this parameter and returns it.\n     *\n     * @return {Float32ArrayParameter} - Returns a new string parameter.\n     */\n    clone() {\n        const clonedParam = new Float32ArrayParameter(this.name, this.value);\n        return clonedParam;\n    }\n}\nRegistry.register('Float32ArrayParameter', Float32ArrayParameter);\nRegistry.register('Property_Float32Array', Float32ArrayParameter);\n\n/* eslint-disable @typescript-eslint/no-unused-vars */\n/**\n * A Parameter for storing list(array) values.\n *\n * i.e.:\n * ```javascript\n * const listParam = new ListParameter('MyList', GearParameter)\n * //'myParameterOwnerItem' is an instance of a 'ParameterOwner' class.\n * // Remember that only 'ParameterOwner' and classes that extend from it can host 'Parameter' objects.\n * myParameterOwnerItem.addParameter(listParam)\n * ```\n *\n * **Events**\n * * **valueChanged:** Triggered when setting a value changes in the array(insert, add, remove).\n * * **elementAdded:** Triggered when an element is added to the array(add, insert).\n * * **elementRemoved:** Triggered when an element is removed from the array\n *\n * @extends Parameter\n */\nclass ListParameter extends Parameter {\n    /**\n     * Create a list parameter.\n     * @param name - The name of the list parameter.\n     * @param dataType - The dataType value.\n     */\n    constructor(name = '', dataType) {\n        super(name, [], dataType);\n    }\n    /**\n     * The filter method.\n     * @param item - The item value.\n     * @return - The return value.\n     *\n     * @private\n     */\n    filter(item) {\n        return true;\n    }\n    /**\n     * Returns the count of items in the array.\n     *\n     * @return - The return value.\n     */\n    getCount() {\n        return this.value?.length || 0;\n    }\n    /**\n     * Returns value from the array in the specified index.\n     *\n     * @param index - The index value.\n     * @return - The return value.\n     */\n    getElement(index) {\n        if (!this.value)\n            return;\n        return this.value[index];\n    }\n    /**\n     * Sets a value in the specified array's index.\n     *\n     * @param index - The index value.\n     * @param value - The value value.\n     */\n    setElement(index, value) {\n        if (!this.value)\n            this.value = [];\n        this.value[index] = value;\n        this.emit('valueChanged');\n    }\n    /**\n     * Adds a new element at the end of the array pile.\n     *\n     * @param elem - The elem value.\n     * @return - The return value.\n     */\n    addElement(elem) {\n        if ((!elem && elem != 0) || !this.filter(elem))\n            return;\n        if (!this.value)\n            this.value = [];\n        this.value.push(elem);\n        this.emit('elementAdded', { elem, index: this.value.length - 1 });\n        this.emit('valueChanged');\n        return elem;\n    }\n    /**\n     * Removes an array element from the specified index\n     *\n     * @param index - The index value.\n     */\n    removeElement(index) {\n        if (!this.value)\n            this.value = [];\n        const elem = this.value[index];\n        this.value.splice(index, 1);\n        this.emit('elementRemoved', { elem, index });\n        this.emit('valueChanged');\n    }\n    /**\n     * Inserts a new element in the specified index.\n     *\n     * @param index - The index value.\n     * @param elem - The elem value.\n     */\n    insertElement(index, elem) {\n        if (!this.value || !this.filter(elem))\n            return;\n        this.value.splice(index, 0, elem);\n        this.emit('elementAdded', { elem, index });\n        this.emit('valueChanged');\n    }\n    setValue(value) {\n        if (!Array.isArray(value)) {\n            throw new Error(`value provided is not an array. Check the source of this value`);\n        }\n        super.setValue(value);\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * The toJSON method encodes this type as a json object for persistence.\n     *\n     * @param context - The context value.\n     * @return - Returns the json object.\n     */\n    toJSON(context) {\n        const items = [];\n        if (this.value) {\n            for (const p of this.value) {\n                if (typeof this.dataType === 'string')\n                    items.push(p);\n                else\n                    items.push(p.toJSON(context));\n            }\n        }\n        return {\n            type: this.getClassName(),\n            name: this.name,\n            value: items,\n        };\n    }\n    /**\n     * The fromJSON method decodes a json object for this type.\n     *\n     * @param j - The json object this item must decode.\n     * @param context - The context value.\n     */\n    fromJSON(j, context) {\n        if (j.items == undefined) {\n            console.warn('Invalid Parameter JSON');\n            return;\n        }\n        const value = [];\n        for (let i = 0; i < j.items.length; i++) {\n            let elem;\n            if (typeof this.dataType === 'string') {\n                elem = j.items[i];\n            }\n            else {\n                if (!this.dataType)\n                    throw 'No DataType';\n                elem = Registry.constructClass(this.dataType);\n                elem.fromJSON(j.items[i], context);\n            }\n            value.push(elem);\n            this.emit('elementAdded', { elem, index: this.value.length - 1 });\n        }\n        this.value = value;\n    }\n    // ////////////////////////////////////////\n    // Clone and Destroy\n    /**\n     * The clone method constructs a new list parameter, copies its values\n     * from this parameter and returns it.\n     *\n     * @return - Returns a new list parameter.\n     */\n    clone() {\n        const clonedValue = this.value ? this.value.slice(0) : [];\n        if (!this.dataType)\n            throw 'This parameter does not have a DataType';\n        const clonedParam = new ListParameter(this.name, this.dataType);\n        clonedParam.setValue(clonedValue);\n        return clonedParam;\n    }\n    /**\n     * The destroy is called by the system to cause explicit resources cleanup.\n     * Users should never need to call this method directly.\n     */\n    destroy() {\n        if (!this.value)\n            return;\n        for (let i = 0; i < this.value.length; i++) {\n            if (this.value[i] instanceof Parameter)\n                this.value[i].destroy();\n            this.removeElement(i);\n        }\n    }\n}\nRegistry.register('ListParameter', ListParameter);\n\n/* eslint-disable @typescript-eslint/explicit-module-boundary-types */\n/**\n * Represents a specific type of parameter, that stores multiple parameters in object format.\n *\n * i.e.:\n * ```javascript\n * const structParam = new StructParameter('MyStructParam')\n * //'myParameterOwnerItem' is an instance of a 'ParameterOwner' class.\n * // Remember that only 'ParameterOwner' and classes that extend from it can host 'Parameter' objects.\n * myParameterOwnerItem.addParameter(structParam)\n * ```\n *\n * **Events**\n * * **valueChanged:** Triggered whenever parameter's value changes.\n *\n * @extends Parameter\n */\nclass StructParameter extends Parameter {\n    members;\n    /**\n     * Create a struct parameter.\n     * @param name - The name of the struct parameter.\n     */\n    constructor(name) {\n        super(name, {}, 'Struct');\n        this.members = [];\n    }\n    /**\n     * The _addMember method.\n     * @param parameter - The parameter value.\n     * @return - The return value.\n     * @private\n     */\n    addMember(parameter) {\n        if (this.value)\n            this.value[parameter.getName()] = parameter.value;\n        parameter.on('valueChanged', () => {\n            if (this.value)\n                this.value[parameter.getName()] = parameter.value;\n        });\n        this.members.push(parameter);\n        this.emit('valueChanged');\n        return parameter;\n    }\n    /**\n     * The getParameter method.\n     *\n     * @private\n     * @param name - The parameter name.\n     * @return - The return value.\n     */\n    getParameter(name) {\n        for (const p of this.members) {\n            if (p.getName() == name)\n                return p;\n        }\n        return undefined;\n    }\n    /**\n     * Looks for a member parameter with the specified name and returns it.\n     *\n     * @param name - The parameter name.\n     * @return - The return value.\n     */\n    getMember(name) {\n        return this.getParameter(name);\n    }\n    /**\n     * Returns the name of all parameters in StructParameter.\n     *\n     * @return - The return value.\n     */\n    getMemberNames() {\n        const names = [];\n        for (let i = 0; i < this.members.length; i++) {\n            const member = this.members[i];\n            if (member != null)\n                names[i] = member.getName();\n        }\n        return names;\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * The toJSON method encodes this type as a json object for persistence.\n     *\n     * @param context - The context value.\n     * @return - Returns the json object.\n     */\n    toJSON(context) {\n        const members = [];\n        for (const p of this.members)\n            members.push(p.toJSON(context));\n        return { type: this.getClassName(), name: this.name, members };\n    }\n    /**\n     * The fromJSON method decodes a json object for this type.\n     *\n     * @param j - The json object this item must decode.\n     * @param context - The context value.\n     */\n    fromJSON(j, context) {\n        if (j.members == undefined) {\n            console.warn('Invalid Parameter JSON');\n            return;\n        }\n        for (let i = 0; i < j.members.length; i++) {\n            if (j.members[i]) {\n                this.members[i].fromJSON(j.members[i], context);\n            }\n        }\n        this.name = j.name;\n    }\n    clone() {\n        const clonedParam = new StructParameter(this.name);\n        return clonedParam;\n    }\n    // ////////////////////////////////////////\n    // Destroy\n    /**\n     * The destroy is called by the system to cause explicit resources cleanup.\n     * Users should never need to call this method directly.\n     */\n    destroy() {\n        for (const p of this.members) {\n            // TODO: not sure about this. I added a do-nothing destroy method in Parameter<T> to be overwritten\n            // since only some subclasses use destroy.\n            p.destroy();\n        }\n    }\n}\nRegistry.register('StructParameter', StructParameter);\n\n/** Class representing an operator output.\n * @extends EventEmitter\n */\nclass OperatorOutput {\n    name;\n    mode;\n    op = null;\n    param;\n    paramBindIndex;\n    detached;\n    /**\n     * Create an operator output.\n     * @param name - The name value.\n     * @param operatorOutputMode - The mode which the OperatorOutput uses to bind to its target parameter.\n     */\n    constructor(name, operatorOutputMode = OperatorOutputMode.OP_WRITE) {\n        this.name = name;\n        this.mode = operatorOutputMode;\n        this.param = undefined;\n        this.paramBindIndex = -1;\n        this.detached = false;\n    }\n    /**\n     * Sets operator that owns this output. Called by the operator when adding outputs\n     * @param op - The operator object.\n     */\n    setOperator(op) {\n        this.op = op;\n    }\n    /**\n     * Returns operator that owns this output.\n     * @return - The operator object.\n     */\n    getOperator() {\n        return this.op;\n    }\n    /**\n     * Returns mode that the output writes to be parameter. Must be a number from OperatorOutputMode\n     * @return - The mode value.\n     */\n    getMode() {\n        return this.mode;\n    }\n    /**\n     * Returns true if this output is connected to a parameter.\n     * @return - The return value.\n     */\n    isConnected() {\n        return this.param != undefined;\n    }\n    /**\n     * The getParam method.\n     * @return - The return value.\n     */\n    getParam() {\n        return this.param;\n    }\n    /**\n     * Sets the Parameter for this output to write to.\n     * @param param - The param value.\n     * @param index - The index to bind at in the Parameter.\n     */\n    setParam(param, index = -1) {\n        if (this.param) {\n            this.param.unbindOperatorOutput(this);\n        }\n        this.param = param;\n        if (this.param) {\n            this.paramBindIndex = this.param.bindOperatorOutput(this, index);\n        }\n    }\n    /**\n     * Returns the index of the binding on the parameter of this OperatorOutput\n     * up to date.\n     * @return index - The index of the binding on the parameter.\n     */\n    getParamBindIndex() {\n        return this.paramBindIndex;\n    }\n    /**\n     * If bindings change on a Parameter, it will call this method to ensure the output index is\n     * up to date.\n     * @param index - The index of the binding on the parameter.\n     */\n    setParamBindIndex(index) {\n        this.paramBindIndex = index;\n    }\n    /**\n     * Propagates dirty to the connected parameter.\n     */\n    setDirty() {\n        if (this.param) {\n            this.param.setDirty(this.paramBindIndex);\n        }\n    }\n    /**\n     * The getValue method.\n     * @return - The return value.\n     */\n    getValue() {\n        if (this.param) {\n            return this.param.getValueFromOp(this.paramBindIndex);\n        }\n        else {\n            // @ts-expect-error ts-migrate(2554) FIXME: Expected 0-1 arguments, but got 2.\n            throw new Error('Cannot call getValue on OperatorOutput that is not connected:', this.name);\n        }\n    }\n    /**\n     * When the value on a Parameter is modified by a user by calling 'setValue,\n     * then if any operators are bound, the value of the Parameter cannot be modified\n     * directly as it is the result of a computation. Instead, the Parameter calls\n     * 'backPropagateValue' on the Operator to cause the Operator to handle propagating\n     * the value to one or more of its inputs.\n     * to its inputs.\n     * @param value - The value param.\n     * @return - The modified value.\n     */\n    backPropagateValue(value) {\n        if (this.op) {\n            value = this.op.backPropagateValue(value);\n        }\n        return value;\n    }\n    /**\n     * The setClean method.\n     * @param value - The value param.\n     */\n    setClean(value) {\n        if (this.param) {\n            this.param.setCleanFromOp(value, this.paramBindIndex);\n        }\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * The toJSON method encodes this type as a json object for persistence.\n     * @param context - The context value.\n     * @return - Returns the json object.\n     */\n    toJSON(context) {\n        const paramPath = this.param ? this.param.getPath() : '';\n        return {\n            name: this.name,\n            paramPath: context && context.makeRelative ? context.makeRelative(paramPath) : paramPath,\n            paramBindIndex: this.paramBindIndex,\n        };\n    }\n    /**\n     * The fromJSON method decodes a json object for this type.\n     * @param j - The json object this item must decode.\n     * @param context - The context value.\n     */\n    fromJSON(j, context) {\n        if (j.paramPath) {\n            // Note: the tree should have fully loaded by the time we are loading operators\n            // even new items and groups should have been created. Operators and state machines\n            // are loaded last.\n            context?.resolvePath(j.paramPath, (param) => {\n                this.setParam(param, j.paramBindIndex);\n            }, (reason) => {\n                console.warn(\"OperatorOutput: '\" + this.name + \"'. Unable to connect to:\" + j.paramPath);\n            });\n        }\n    }\n    /**\n     * The detach method is called when an operator is being removed from the scene tree.\n     * It removes all connections to parameters in the scene.\n     */\n    detach() {\n        // This function is called when we want to suspend an operator\n        // from functioning because it is deleted and on the undo stack.\n        // Once operators have persistent connections,\n        // we will simply uninstall the output from the parameter.\n        this.detached = true;\n        this.paramBindIndex = this.param ? this.param.unbindOperatorOutput(this) : -1;\n    }\n    /**\n     * The reattach method can be called when re-instating an operator in the scene.\n     */\n    reattach() {\n        this.detached = false;\n        if (this.param) {\n            this.paramBindIndex = this.param.bindOperatorOutput(this, this.paramBindIndex);\n        }\n    }\n    /**\n     * The rebind rebinds the outputs to be at the top of the stack for its parameter.\n     */\n    rebind() {\n        if (this.param) {\n            this.param.unbindOperatorOutput(this);\n            this.paramBindIndex = this.param.bindOperatorOutput(this);\n        }\n    }\n}\nclass BooleanOperatorOutput extends OperatorOutput {\n}\nclass NumberOperatorOutput extends OperatorOutput {\n}\nclass Vec2OperatorOutput extends OperatorOutput {\n}\nclass Vec3OperatorOutput extends OperatorOutput {\n}\nclass Vec4OperatorOutput extends OperatorOutput {\n}\nclass ColorOperatorOutput extends OperatorOutput {\n}\nclass QuatOperatorOutput extends OperatorOutput {\n}\nclass XfoOperatorOutput extends OperatorOutput {\n}\nclass Mat3OperatorOutput extends OperatorOutput {\n}\nclass Mat4OperatorOutput extends OperatorOutput {\n}\n\n/**\n * Class representing an operator.\n *\n */\nclass Operator {\n    name;\n    inputs;\n    outputs;\n    /**\n     * Create an operator.\n     * @param name - The name value.\n     */\n    constructor(name = '') {\n        this.name = name;\n        this.inputs = new Map();\n        this.outputs = new Map();\n    }\n    /**\n     * This method sets the state of the operator to dirty which propagates\n     * to the outputs of this operator, and which may then propagate to other\n     * operators. When the scene is cleaned, which usually is caused by rendering\n     * then the chain of operators are cleaned by triggering evaluation.\n     * @private\n     */\n    setDirty() {\n        this.outputs.forEach((output) => output.setDirty());\n    }\n    /**\n     * The addInput method.\n     * @param input - The name of the input, or the input object\n     * @return - The return value.\n     */\n    addInput(input) {\n        input.setOperator(this);\n        this.inputs.set(input.name, input);\n        this.setDirty();\n        return input;\n    }\n    /**\n     * The removeInput method.\n     * @param input - The name of the input, or the input object\n     */\n    removeInput(input) {\n        if (typeof input == 'string')\n            input = this.getInput(input);\n        if (input.getParam())\n            input.setParam(undefined);\n        this.inputs.delete(input.name);\n    }\n    /**\n     * Getter for the number of inputs in this operator.\n     * @return - Returns the number of inputs.\n     */\n    getNumInputs() {\n        return this.inputs.size;\n    }\n    /**\n     * The getInputByIndex method.\n     * @param index - The index value.\n     * @return - The return value.\n     */\n    getInputByIndex(index) {\n        return Array.from(this.inputs.values())[index];\n    }\n    /**\n     * The getInput method.\n     * @param name - The name value.\n     * @return - The return value.\n     */\n    getInput(name) {\n        const input = this.inputs.get(name);\n        if (!input)\n            throw `Couldn't find an Input with the name of '${name}'`;\n        return input;\n    }\n    /**\n     * The addOutput method.\n     * @param output - The name of the output, or the output object\n     * @return - The return value.\n     */\n    addOutput(output) {\n        output.setOperator(this);\n        // if (this.getOutput(output.name)) throw new Error(`Operator output already exists ${output.name}`)\n        this.outputs.set(output.name, output);\n        this.setDirty();\n        return output;\n    }\n    /**\n     * The removeOutput method.\n     * @param output - The name of the output, or the output object\n     */\n    removeOutput(output) {\n        if (typeof output == 'string')\n            output = this.getOutput(output);\n        if (!(output instanceof OperatorOutput)) {\n            throw new Error(`removeOutput only accepts string or OperatorInput`);\n        }\n        if (output.getParam())\n            output.setParam();\n        this.outputs.delete(output.name);\n    }\n    /**\n     * Getter for the number of outputs in this operator.\n     * @return - Returns the number of outputs.\n     */\n    getNumOutputs() {\n        return this.outputs.size;\n    }\n    /**\n     * The getOutputByIndex method.\n     * @param index - The index value.\n     * @return - The return value.\n     */\n    getOutputByIndex(index) {\n        return Array.from(this.outputs.values())[index];\n    }\n    /**\n     * The getOutput method.\n     * @param name - The name value.\n     * @return - The return value.\n     */\n    getOutput(name) {\n        const output = this.outputs.get(name);\n        if (!output)\n            throw new Error(`Couldn't find an Output with the name of '${name}'`);\n        return output;\n    }\n    /**\n     * The evaluate method.\n     * Computes the values of each of the outputs based on the values of the inputs\n     * and the values of outputs with mode OP_READ_WRITE.\n     * This method must be implemented by all Operators.\n     */\n    evaluate() {\n        throw new Error('Not yet implemented');\n    }\n    /**\n     * When the value on a Parameter is modified by a user by calling 'setValue,\n     * then if any operators are bound, the value of the Parameter cannot be modified\n     * directly as it is the result of a computation. Instead, the Parameter calls\n     * 'backPropagateValue' on the Operator to cause the Operator to handle propagating\n     * the value to one or more of its inputs.\n     * to its inputs.\n     * @param value - The value param.\n     * @return - The modified value.\n     */\n    backPropagateValue(value) {\n        // TODO: Implement me for custom manipulations.\n        return value;\n    }\n    /**\n     * The detach method.\n     */\n    detach() {\n        this.inputs.forEach((input) => input.detach());\n        this.outputs.forEach((output) => output.detach());\n    }\n    /**\n     * The reattach method.\n     */\n    reattach() {\n        this.inputs.forEach((input) => input.reattach());\n        this.outputs.forEach((output) => output.reattach());\n    }\n    /**\n     * The rebind method.\n     */\n    rebind() {\n        this.outputs.forEach((output) => output.rebind());\n    }\n}\n\n/** Class representing an operator input.\n * @extends EventEmitter\n */\nclass OperatorInput {\n    name;\n    op;\n    param;\n    detached = false;\n    /**\n     * Create an operator input.\n     * @param name - The name value.\n     */\n    constructor(name) {\n        this.name = name;\n    }\n    /**\n     * Sets operator that owns this input. Called by the operator when adding inputs\n     * @param op - The operator object.\n     */\n    setOperator(op) {\n        this.op = op;\n    }\n    /**\n     * Returns operator that owns this input.\n     * @return - The operator object.\n     */\n    getOperator() {\n        return this.op;\n    }\n    /**\n     * Returns true if this input is connected to a parameter.\n     * @return - The return value.\n     */\n    isConnected() {\n        return this.param != null;\n    }\n    /**\n     * The getParam method.\n     * @return - The return value.\n     */\n    getParam() {\n        return this.param;\n    }\n    /**\n     * @private\n     * The handler function for when the input paramter changes.\n     * @param event - The event object.\n     */\n    paramValueChanged() {\n        if (this.op)\n            this.op.setDirty();\n    }\n    /**\n     * Assigns the Paramter to be used to provide the input value.\n     * @param param - The param value.\n     */\n    setParam(param) {\n        if (this.param) {\n            this.param.unbindOperatorInput(this);\n        }\n        this.param = param;\n        if (this.param) {\n            this.param.bindOperatorInput(this);\n        }\n        // When an input param is assigned, the op should\n        // propagate dirty to its outputs.\n        if (this.op)\n            this.op.setDirty();\n    }\n    /**\n     * The getValue method.\n     * @return - The return value.\n     */\n    getValue() {\n        if (this.param)\n            return this.param.value;\n        throw new Error('Unable to getValue');\n    }\n    /**\n     * The setValue method.\n     * @param value - The value param.\n     */\n    setValue(value) {\n        if (this.param) {\n            this.param.setValue(value);\n        }\n    }\n    /**\n     * Propagates from the upstream parameter to the connected operator.\n     */\n    setDirty() {\n        if (this.op) {\n            this.op.setDirty();\n        }\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * The toJSON method encodes this type as a json object for persistence.\n     *\n     * @param context - The context value.\n     * @return - Returns the json object.\n     */\n    toJSON(context) {\n        const absPath = this.param ? this.param.getPath() : [];\n        const paramPath = (context && context.makeRelative ? context.makeRelative(absPath) : absPath);\n        return {\n            name: this.name,\n            paramPath: paramPath,\n        };\n    }\n    /**\n     * The fromJSON method decodes a json object for this type.\n     * @param j - The json object this item must decode.\n     * @param context - The context value.\n     */\n    fromJSON(j, context) {\n        if (j.paramPath) {\n            // Note: the tree should have fully loaded by the time we are loading operators\n            // even new items and groups should have been created. Operators and state machines\n            // are loaded last.\n            context?.resolvePath(j.paramPath, (param) => {\n                this.setParam(param);\n            }, () => {\n                console.warn(\"OperatorInput: '\" + this.name + \"'. Unable to connect to:\" + j.paramPath);\n            });\n        }\n    }\n    /**\n     * The detach method is called when an operator is being removed from the scene tree.\n     * It removes all connections to parameters in the scene.\n     */\n    detach() {\n        // This function is called when we want to suspend an operator\n        // from functioning because it is deleted and on the undo stack.\n        // Once operators have persistent connections,\n        // we will simply uninstall the output from the parameter.\n        if (this.param) {\n            this.param.unbindOperatorInput(this);\n        }\n    }\n    /**\n     * The reattach method can be called when re-instating an operator in the scene.\n     */\n    reattach() {\n        this.detached = false;\n        if (this.param) {\n            this.param.bindOperatorInput(this);\n        }\n    }\n}\nclass BooleanOperatorInput extends OperatorInput {\n}\nclass NumberOperatorInput extends OperatorInput {\n}\nclass Vec2OperatorInput extends OperatorInput {\n}\nclass Vec3OperatorInput extends OperatorInput {\n}\nclass Vec4OperatorInput extends OperatorInput {\n}\nclass ColorOperatorInput extends OperatorInput {\n}\nclass QuatOperatorInput extends OperatorInput {\n}\nclass XfoOperatorInput extends OperatorInput {\n}\nclass Mat3OperatorInput extends OperatorInput {\n}\nclass Mat4OperatorInput extends OperatorInput {\n}\n\n/** The operator the calculates the global Xfo of a TreeItem based on its parents GlobalXfo and its own LocalXfo\n * @extends Operator\n * @private\n */\nclass CalcGlobalXfoOperator extends Operator {\n    parentGlobal = new XfoOperatorInput('ParentGlobal');\n    localXfo = new XfoOperatorInput('LocalXfo');\n    globalXfo = new XfoOperatorOutput('GlobalXfo');\n    /**\n     * Create a CalcGlobalXfoOperator operator.\n     *\n     * @param groupGlobalXfoParam - The GlobalXfo param found on the Group.\n     * @param cuttingPlaneParam - The parameter on the Group which defines the displacement to apply to the members.\n     */\n    // TODO: adding new XfoP... to make inheritence work\n    constructor(globalXfoParam, localXfoParam) {\n        super('CalcGlobalXfoOperator');\n        this.localXfo.setParam(localXfoParam);\n        this.globalXfo.setParam(globalXfoParam);\n        this.addInput(this.parentGlobal);\n        this.addInput(this.localXfo);\n        this.addOutput(this.globalXfo);\n    }\n    /**\n     * The backPropagateValue method inverts the mathematics of the 'evaluate'\n     * method so it can propagate the value backwards to its inputs.\n     * @param value - the new value being set on the output GlobalXfo\n     */\n    backPropagateValue(value) {\n        if (this.parentGlobal.isConnected()) {\n            const parentGlobalXfo = this.parentGlobal.getValue();\n            this.localXfo.setValue(parentGlobalXfo.inverse().multiply(value));\n        }\n        else {\n            this.localXfo.setValue(value);\n        }\n    }\n    /**\n     * The evaluate method calculates a new global Xfo based on the parents Global Xfo,\n     * and the local Xfo value.\n     */\n    evaluate() {\n        const localXfo = this.localXfo.getValue();\n        if (this.parentGlobal.isConnected()) {\n            const parentGlobalXfo = this.parentGlobal.getValue();\n            this.globalXfo.setClean(parentGlobalXfo.multiply(localXfo));\n        }\n        else {\n            this.globalXfo.setClean(localXfo);\n        }\n    }\n}\n\n/**\n * Represents a specific type of parameter, that only stores `Box3` values.\n *\n * i.e.:\n * ```javascript\n * const boundingBox = new BoundingBoxParameter('MyBBox', new TreeItem())\n * //'myParameterOwnerItem' is an instance of a 'ParameterOwner' class.\n * // Remember that only 'ParameterOwner' and classes that extend from it can host 'Parameter' objects.\n * myParameterOwnerItem.addParameter(boundingBox)\n * ```\n * @extends Parameter\n */\nclass BoundingBoxParameter extends Box3Parameter {\n    // protected dirty: boolean, value, name\n    treeItem;\n    dirty = true;\n    /**\n     * Creates an instance of BoundingBoxParameter.\n     * @param name - Name of the parameter\n     * @param treeItem - `TreeItem` that contains `Box3` representing the Bounding Box\n     */\n    constructor(name = '', treeItem) {\n        super(name);\n        this.treeItem = treeItem;\n    }\n    /**\n     * Makes parameter value be dirty, so when `getValue` is called,\n     * an evaluation is then executed to re-calculate the BoundingBox\n     *\n     * @memberof BoundingBoxParameter\n     */\n    setDirty(index) {\n        if (!this.dirty) {\n            this.dirty = true;\n            this.emit('valueChanged');\n        }\n        return true;\n    }\n    getValue() {\n        if (this.dirty) {\n            //@ts-ignore\n            this.value = this.treeItem.cleanBoundingBox();\n            this.dirty = false;\n        }\n        return super.getValue();\n    }\n    clone() {\n        const bBox3Clone = new BoundingBoxParameter(this.name, this.treeItem);\n        bBox3Clone.value = this.value?.clone();\n        return bBox3Clone;\n    }\n    /**\n     * We do not want this parameter serialized.\n     */\n    isDrivenByOperator() {\n        return true;\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * The loadValue is used to change the value of a parameter, without triggering a\n     * valueChanges, or setting the USER_EDITED state.\n     *\n     * @param value - The context value.\n     */\n    loadValue(value) {\n        this.value = value.clone();\n    }\n}\nRegistry.register('BoundingBoxParameter', BoundingBoxParameter);\n\n/**\n * Class representing an Item in the scene tree with hierarchy capabilities (has children).\n * It has the capability to add and remove children.\n * **Parameters**\n * * **Visible(`BooleanParameter`):** Shows/Hides the item.\n * * **LocalXfo(`XfoParameter`):** Specifies the offset of this tree item from its parent.\n * * **GlobalXfo(`XfoParameter`):** Provides the computed world Xfo of this tree item.\n * * **BoundingBox(`BoundingBox`):** Provides the bounding box for the tree item and all of its children in the 3d scene.\n *\n * **Events**\n * * **globalXfoChanged:** Emitted when the value of GlobalXfo parameter changes.\n * * **visibilityChanged:** Emitted when the visibility on the tree item changes.\n * * **highlightChanged:** Emitted when the highlight on the tree item changes.\n * * **childAdded:** Emitted when a item is added as a child.\n * * **childRemoved:** Emitted when an item is removed from the child nodes.\n * * **pointerDown:** Emitted when a pointerDown event happens in an item.\n * * **pointerUp:** Emitted when a pointerUp event happens in an item.\n * * **pointerMove:** Emitted when a pointerMove event happens in an item.\n * * **pointerEnter:** Emitted when a pointerEnter event happens in an item.\n * * **pointerClick:** Emitted when a pointer is clicked on an item.\n * * **pointerDoubleClick:** Emitted when a pointer is double-clicked on an item.\n * * **pointerLongPress:** Emitted when a pointer is clicked and held on an item for a long time.\n *\n *\n * @extends {ParameterOwner}\n */\nclass TreeItem extends ParameterOwner {\n    // Controls if this TreeItem or its children contribute to the bounding boxes\n    // in the scene. If set to false, Camera framing will ignore this item,\n    disableBoundingBox = false;\n    __childItems = [];\n    __childItemsEventHandlers = [];\n    childItemsMapping = {};\n    childItemsMappingCorrupt = false;\n    /**\n     * @member globalXfoParam - Stores the global Xfo for this tree item.\n     * global xfos are calculated from the localXfo and parentXfo.\n     */\n    globalXfoParam = new XfoParameter('GlobalXfo', new Xfo());\n    /**\n     * @member localXfoParam - Stores the local Xfo for this tree item.\n     * local Xfos are the offset from the parent's coordinate frame.\n     */\n    localXfoParam = new XfoParameter('LocalXfo', new Xfo());\n    /**\n     * @member boundingBoxParam - Stores the bounding box for this tree item\n     */\n    boundingBoxParam = new BoundingBoxParameter('BoundingBox', this);\n    /**\n     * @member visibleParam - Whether this tree item is visible or not.\n     * Any given tree item is also is affected by parent's visibility.\n     */\n    visibleParam = new BooleanParameter('Visible', true);\n    /**\n     * @member pickableParam - Whether this tree item ic pickable in the viewport or not.\n     * Any given tree item is also is affected by parent's pick-ablility.\n     */\n    pickableParam = new BooleanParameter('Pickable', true);\n    /**\n     * @member opacityParam - Controls, in combination with Material transparency,\n     * the opacity of this item and its children.\n     */\n    opacityParam = new NumberParameter('Opacity', 1, [0, 1]);\n    highlightMapping = {};\n    highlights = [];\n    #visible = true;\n    #pickable = true;\n    visibleCounter = 1; // Visible by Default.\n    pickableCounter = 1; // Pickable by Default.\n    opacity = 1; // Opaque by Default.\n    inheritedOpacityValues = new Map();\n    globalXfoOp;\n    /**\n     * Creates a tree item with the specified name.\n     *\n     * @param name - The name of the tree item. It's the identifier of the tree item.\n     * It's an identifier intended to be human readable.\n     * It's included in the path that we use to access a particular item.\n     * It's used to display it in the tree.\n     */\n    constructor(name) {\n        super(name);\n        // /////////////////////////////////////\n        // Add parameters.\n        this.addParameter(this.visibleParam);\n        this.addParameter(this.pickableParam);\n        this.addParameter(this.opacityParam);\n        this.addParameter(this.localXfoParam);\n        this.addParameter(this.globalXfoParam);\n        this.addParameter(this.boundingBoxParam);\n        this.globalXfoOp = new CalcGlobalXfoOperator(this.globalXfoParam, this.localXfoParam);\n        this.globalXfoParam.on('valueChanged', (event) => {\n            this.setBoundingBoxDirty();\n            // Note: deprecate this event.\n            this.emit('globalXfoChanged', event);\n        });\n        this.visibleParam.on('valueChanged', () => {\n            this.visibleCounter += this.visibleParam.value ? 1 : -1;\n            this.updateVisibility();\n        });\n        this.pickableParam.on('valueChanged', () => {\n            this.pickableCounter += this.pickableParam.value ? 1 : -1;\n            this.updatePickable();\n        });\n        this.opacityParam.on('valueChanged', () => {\n            this.updateOpacity();\n        });\n    }\n    setOwner(ownerItem) {\n        if (ownerItem && !(ownerItem instanceof TreeItem)) {\n            throw new Error('cannot setOwner');\n        }\n        if (this.ownerItem) {\n            if (this.ownerItem instanceof TreeItem) {\n                // The effect of the invisible owner is removed.\n                if (!this.ownerItem.isVisible())\n                    this.visibleCounter++;\n                if (!this.ownerItem.isPickable())\n                    this.pickableCounter++;\n                const index = this.ownerItem.getChildIndex(this);\n                if (index >= 0)\n                    this.ownerItem.unbindChild(index, this);\n            }\n        }\n        super.setOwner(ownerItem);\n        if (this.ownerItem) {\n            if (this.ownerItem instanceof TreeItem) {\n                // The effect of the invisible owner is added.\n                if (!this.ownerItem.isVisible())\n                    this.visibleCounter--;\n                if (!this.ownerItem.isPickable())\n                    this.pickableCounter--;\n                this.globalXfoOp.getInput('ParentGlobal').setParam(this.ownerItem.globalXfoParam);\n            }\n        }\n        else {\n            this.globalXfoOp.getInput('ParentGlobal').setParam(undefined);\n        }\n        this.updateVisibility();\n    }\n    /**\n     * Returns the parent of current TreeItem.\n     *\n     * @return - Returns the parent item.\n     */\n    getParentItem() {\n        return this.getOwner();\n    }\n    /**\n     * Sets the parent of current TreeItem.\n     *\n     * @param parentItem - The parent item.\n     */\n    setParentItem(parentItem) {\n        this.setOwner(parentItem);\n    }\n    get parent() {\n        return this.getOwner();\n    }\n    set parent(treeItem) {\n        this.setOwner(treeItem);\n    }\n    // ////////////////////////////////////////\n    // Visibility\n    /**\n     * Returns visible parameter value for current TreeItem.\n     *\n     * @return - The visible param value.\n     */\n    isVisible() {\n        // Should never be more than 1, but can be less than 0.\n        return this.visibleCounter > 0;\n    }\n    /**\n     * Sets visible parameter value.\n     *\n     * @param val - The val param.\n     */\n    setVisible(visible) {\n        this.visibleParam.value = visible;\n    }\n    /**\n     * Updates current TreeItem visible state and propagates its value to children elements.\n     *\n     * @param val - The val param.\n     */\n    propagateVisibility(val) {\n        this.visibleCounter += val;\n        this.updateVisibility();\n    }\n    /**\n     * The updateVisibility method.\n     * @return - Returns a boolean.\n     */\n    updateVisibility() {\n        const visible = this.visibleCounter > 0;\n        if (visible != this.#visible) {\n            this.#visible = visible;\n            for (const childItem of this.__childItems) {\n                childItem.propagateVisibility(this.#visible ? 1 : -1);\n            }\n            this.emit('visibilityChanged', new StateChangedEvent(visible));\n            // Note: we used to handle this by listening to a 'valueChanged' event on the\n            // parameter.\n            if (this.ownerItem instanceof TreeItem) {\n                this.ownerItem.setBoundingBoxDirty();\n            }\n            return true;\n        }\n        return false;\n    }\n    // ////////////////////////////////////////\n    // Pickable\n    /**\n     * Returns visible parameter value for current TreeItem.\n     *\n     * @return - The visible param value.\n     */\n    isPickable() {\n        // Should never be more than 1, but can be less than 0.\n        return this.pickableCounter > 0;\n    }\n    /**\n     * Updates current TreeItem visible state and propagates its value to children elements.\n     *\n     * @param val - The val param.\n     */\n    propagatePickable(val) {\n        this.pickableCounter += val;\n        this.updatePickable();\n    }\n    /**\n     * The updatePickable method.\n     * @return - Returns a boolean.\n     */\n    updatePickable() {\n        const pickable = this.pickableCounter > 0;\n        if (pickable != this.#pickable) {\n            this.#pickable = pickable;\n            for (const childItem of this.__childItems) {\n                childItem.propagatePickable(this.#pickable ? 1 : -1);\n            }\n            this.emit('pickabilityChanged', new StateChangedEvent(pickable));\n            return true;\n        }\n        return false;\n    }\n    // ////////////////////////////////////////\n    // Opacity\n    /**\n     * Returns the current status of the opacity value.\n     *\n     * @return - Returns true if the opacity value is less than 1.\n     */\n    isOpaque() {\n        return this.opacity > 0.999;\n    }\n    /**\n     * Set the value of opacity inherited by a given tree item.\n     */\n    setInheritedOpacity(parent, value) {\n        this.inheritedOpacityValues.set(parent, value);\n        this.updateOpacity();\n    }\n    /**\n     * Calculates the new opacity value based on the opacityParam value\n     * and the lowest of the inherited opacity values.\n     */\n    updateOpacity() {\n        let inheritedOpacityValue = 1;\n        this.inheritedOpacityValues.forEach((value) => {\n            if (value < inheritedOpacityValue)\n                inheritedOpacityValue = value;\n        });\n        const wasOpaque = this.opacity > 0.999;\n        this.opacity = this.opacityParam.value * inheritedOpacityValue;\n        // else this.opacity = this.opacityParam.value\n        for (const childItem of this.__childItems) {\n            childItem.setInheritedOpacity(this, this.opacity);\n        }\n        const isOpaque = this.opacity > 0.999;\n        this.emit('opacityChanged', new OpacityStateChangedEvent(isOpaque, wasOpaque != isOpaque));\n    }\n    // ////////////////////////////////////////\n    // Highlights\n    /**\n     * Adds a highlight to the tree item.\n     *\n     * @param name - The name of the tree item.\n     * @param color - The color of the highlight.\n     * @param propagateToChildren - A boolean indicating whether to propagate to children.\n     */\n    addHighlight(name, color, propagateToChildren = true) {\n        // If the highlight was already in the list,\n        // remove it and put it at the top.\n        if (name in this.highlightMapping) {\n            if (this.highlights[this.highlights.length - 1] != name) {\n                // The highlight was already in the list, but not at the top. Move it to the top.\n                const id = this.highlights.indexOf(name);\n                this.highlights.splice(id, 1);\n                this.highlights.push(name);\n                this.emit('highlightChanged', { name, color });\n            }\n            else {\n                // This item is already highlighted with this highlight\n                if (!this.highlightMapping[name].isEqual(color)) {\n                    this.highlightMapping[name] = color;\n                    this.emit('highlightChanged', { name, color });\n                }\n            }\n        }\n        else {\n            this.highlights.push(name);\n            this.highlightMapping[name] = color;\n            this.emit('highlightChanged', { name, color });\n        }\n        if (propagateToChildren) {\n            this.__childItems.forEach((childItem) => {\n                childItem.addHighlight(name, color, propagateToChildren);\n            });\n        }\n    }\n    /**\n     * Removes a highlight to the tree item.\n     *\n     * @param name - The name of the tree item.\n     * @param propagateToChildren - A boolean indicating whether to propagate to children.\n     */\n    removeHighlight(name, propagateToChildren = true) {\n        if (name in this.highlightMapping) {\n            if (this.highlights[this.highlights.length - 1] == name) {\n                this.highlights.pop();\n                delete this.highlightMapping[name];\n                if (this.highlights.length > 0) {\n                    const nextName = this.highlights[this.highlights.length - 1];\n                    const nextColor = this.highlightMapping[nextName];\n                    this.emit('highlightChanged', { name: nextName, color: nextColor });\n                }\n                else {\n                    // The last highlight was removed, so emit an event saying we are no longer highlighted.\n                    this.emit('highlightChanged');\n                }\n            }\n            else {\n                // The removed highlight was not the current highlight, so no change needs to be shown.\n                const id = this.highlights.indexOf(name);\n                this.highlights.splice(id, 1);\n                delete this.highlightMapping[name];\n            }\n            if (propagateToChildren) {\n                this.__childItems.forEach((childItem) => {\n                    childItem.removeHighlight(name, propagateToChildren);\n                });\n            }\n        }\n    }\n    /**\n     * Returns the color of the current highlight.\n     *\n     * @return - The color value.\n     */\n    getHighlight() {\n        if (this.highlights.length == 0) {\n            return null;\n        }\n        return this.highlightMapping[this.highlights[this.highlights.length - 1]];\n    }\n    /**\n     * Returns the name of the current highlight.\n     *\n     * @return - The color value.\n     */\n    getHighlightName() {\n        if (this.highlights.length == 0) {\n            return null;\n        }\n        return this.highlights[this.highlights.length - 1];\n    }\n    /**\n     * Returns `true` if this items has a highlight color assigned.\n     *\n     * @return - `True` if this item is highlighted.\n     */\n    isHighlighted() {\n        return this.highlights.length > 0;\n    }\n    // ////////////////////////////////////////\n    // Bounding Box\n    cleanBoundingBox() {\n        const bbox = new Box3();\n        this.__childItems.forEach((childItem) => {\n            if (childItem.isVisible() && childItem.isPickable()) {\n                // console.log(\" - \", childItem.constructor.name, childItem.getName(), childItem.globalXfoParam.value.sc.x, childItem.getBoundingBox().toString())\n                const box3 = childItem.boundingBoxParam.value;\n                if (box3)\n                    bbox.addBox3(box3);\n            }\n        });\n        // console.log(this.getName(), bbox.toString())\n        return bbox;\n    }\n    setBoundingBoxDirty() {\n        if (this.boundingBoxParam) {\n            // Will cause boundingChanged to emit\n            this.boundingBoxParam.setDirty(-1);\n        }\n        // Note: we used to handle this by listening to a 'valueChanged' event on the\n        // parameter.\n        if (this.ownerItem instanceof TreeItem) {\n            this.ownerItem.setBoundingBoxDirty();\n        }\n    }\n    // ////////////////////////////////////////\n    // Children\n    /**\n     * Returns children list, but children are not required to have hierarchy structure(`TreeItem`).\n     * Meaning that it could be another kind of item than `TreeItem`.\n     *\n     * i.e. **BaseImage**\n     *\n     * @return - List of `TreeItem` owned by current TreeItem.\n     */\n    getChildren() {\n        return this.__childItems;\n    }\n    /**\n     * Returns the number of child tree items.\n     */\n    getNumChildren() {\n        return this.__childItems.length;\n    }\n    /**\n     * Returns the number of child tree items.\n     */\n    get numChildren() {\n        return this.__childItems.length;\n    }\n    /**\n     * Apply an index to the name if name exists within this item's children.\n     *\n     * @param name - The name value.\n     * @return - Returns a unique name.\n     */\n    generateUniqueName(name) {\n        while (this.childItemsMapping[name.toLocaleLowerCase()] != undefined) {\n            const indexRegexp = /(\\d+)$/i;\n            const indexMatches = name.match(indexRegexp);\n            let newIndex = 1;\n            if (indexMatches) {\n                newIndex = parseInt(indexMatches[1]) + 1;\n                name = name.replace(indexRegexp, ''); // remove old index\n            }\n            name += `${newIndex}`.padStart(2, '0');\n        }\n        return name;\n    }\n    /**\n     * Updates the internal acceleration structure that speeds up looking up children by name.\n     * @param start - The start value.\n     * @private\n     */\n    updateChildNameMapping(start) {\n        // If a child has been added or removed from the\n        // tree item, we need to update the acceleration structure.\n        for (let i = start; i < this.__childItems.length; i++) {\n            const name = this.__childItems[i].name.toLocaleLowerCase();\n            this.childItemsMapping[name] = i;\n        }\n    }\n    /**\n     * When a child's name changed, we update our acceleration structure.\n     * @param event - The start value.\n     * @private\n     */\n    childNameChanged(event) {\n        // Update the acceleration structure.\n        if (this.childItemsMappingCorrupt) {\n            this.updateChildNameMapping(0);\n            this.childItemsMappingCorrupt = false;\n        }\n        else {\n            const oldName = event.oldName.toLocaleLowerCase();\n            const newName = event.newName.toLocaleLowerCase();\n            const index = this.childItemsMapping[oldName];\n            if (this.childItemsMapping[newName] != undefined)\n                this.childItemsMappingCorrupt = true;\n            delete this.childItemsMapping[oldName];\n            this.childItemsMapping[newName] = index;\n        }\n    }\n    /**\n     * Inserts a child. It accepts all kind of `TreeItem`, not only `TreeItem`.\n     *\n     * @param childItem - The child TreeItem to insert.\n     * @param index - The index to add the child item.\n     * @param maintainXfo - Boolean that determines if the Xfo value is maintained.\n     * @param fixCollisions - Modify the name of the item to avoid name collisions.\n     * If false, an exception wll be thrown instead if a name collision occurs.\n     * @return - The index of the child item in this items children array.\n     */\n    insertChild(childItem, index, maintainXfo = false, fixCollisions = true) {\n        let name = childItem.name;\n        let nameLc = name.toLocaleLowerCase();\n        if (nameLc in this.childItemsMapping) {\n            if (fixCollisions) {\n                name = this.generateUniqueName(name);\n                nameLc = name.toLocaleLowerCase();\n                childItem.setName(name);\n            }\n            else {\n                throw new Error(\"Item '\" + name + \"' is already a child of :\" + this.getPath());\n            }\n        }\n        if (!(childItem instanceof TreeItem)) {\n            throw new Error('Object is is not a tree item :' + childItem); // TODO: need better output here+ childItem.constructor.name)\n        }\n        const listenerIDs = {};\n        listenerIDs['nameChanged'] = childItem.on('nameChanged', (event) => {\n            this.childNameChanged(event);\n        });\n        let prevGlobal;\n        if (maintainXfo) {\n            prevGlobal = childItem.globalXfoParam.value;\n        }\n        this.setBoundingBoxDirty();\n        this.highlights.forEach((name) => {\n            childItem.addHighlight(name, this.highlightMapping[name], true);\n        });\n        childItem.setInheritedOpacity(this, this.opacity);\n        this.__childItems.splice(index, 0, childItem);\n        this.__childItemsEventHandlers.splice(index, 0, listenerIDs);\n        // If we have non-unique names, we need to regenerate this mapping.\n        if (this.childItemsMapping[nameLc])\n            this.childItemsMappingCorrupt = true;\n        this.childItemsMapping[nameLc] = index;\n        this.updateChildNameMapping(index + 1);\n        childItem.setOwner(this);\n        if (maintainXfo) {\n            // Mainain the previous global Xfo.\n            childItem.globalXfoParam.value = prevGlobal;\n        }\n        this.emit('childAdded', new ChildAddedEvent(index, childItem));\n        return childItem;\n    }\n    /**\n     * Adds a child.\n     *\n     * @param childItem - The child TreeItem to add.\n     * @param maintainXfo - Boolean that determines if\n     * the Global Xfo value is maintained. If true, when moving\n     * items in the hierarchy from one parent to another, the local Xfo\n     * of the item will be modified to maintain and the Global Xfo.\n     * Note: this option defaults to false because we expect that is the\n     * behavior users would expect when manipulating the tree in code.\n     * To be safe and unambiguous, always try to specify this value.\n     * @param fixCollisions - Modify the name of the item to avoid\n     * name collisions with other children of the same parent.\n     * If false, an exception wll be thrown instead if a name collision occurs.\n     * @return childItem - The child TreeItem that was added.\n     */\n    addChild(childItem, maintainXfo = true, fixCollisions = true) {\n        const index = this.__childItems.length;\n        this.insertChild(childItem, index, maintainXfo, fixCollisions);\n        return childItem;\n    }\n    /**\n     * Returns child element in the specified index.\n     *\n     * @param index - The index to remove the child TreeItem.\n     * @return - Return the child TreeItem.\n     */\n    getChild(index) {\n        return this.__childItems[index];\n    }\n    /**\n     * Returns child element with the specified name.\n     *\n     * @param name - The name value.\n     * @return - Return the child TreeItem.\n     */\n    getChildByName(name) {\n        const index = this.childItemsMapping[name.toLocaleLowerCase()];\n        if (index != undefined) {\n            return this.__childItems[index];\n        }\n        return null;\n    }\n    /**\n     * Returns children names as an array of strings.\n     *\n     * @return - An array of names for each child.\n     */\n    getChildNames() {\n        const names = [];\n        for (let i = 0; i < this.__childItems.length; i++) {\n            const childItem = this.__childItems[i];\n            if (childItem != null)\n                names[i] = childItem.getName();\n        }\n        return names;\n    }\n    /**\n     * UnBind an item from the group. This method is called\n     * automatically when an item is removed from the group.\n     * @param index - The index value.\n     * @param childItem - item to unbind.\n     * @private\n     */\n    unbindChild(index, childItem) {\n        const listenerIDs = this.__childItemsEventHandlers[index];\n        childItem.off('nameChanged', listenerIDs['nameChanged']);\n        this.__childItems.splice(index, 1);\n        this.__childItemsEventHandlers.splice(index, 1);\n        delete this.childItemsMapping[childItem.name.toLocaleLowerCase()];\n        this.updateChildNameMapping(index);\n        this.setBoundingBoxDirty();\n        this.emit('childRemoved', { childItem, index });\n    }\n    /**\n     * Removes a child TreeItem by specifying its index.\n     *\n     * @param index - The index value.\n     */\n    removeChild(index) {\n        const childItem = this.__childItems[index];\n        if (!childItem) {\n            return;\n        }\n        this.unbindChild(index, childItem);\n        childItem.setOwner(undefined);\n    }\n    /**\n     * Removes a child TreeItem by specifying its name.\n     *\n     * @param name - The name param.\n     * @return - Return the child TreeItem.\n     */\n    removeChildByName(name) {\n        const index = this.childItemsMapping[name.toLocaleLowerCase()];\n        if (index != undefined) {\n            return this.removeChild(index);\n        }\n    }\n    /**\n     * Removes the provided item from this TreeItem if it is one of its children.\n     * An exception is thrown if the item is not a child of this tree item.\n     *\n     * @param childItem - The child TreeItem to remove.\n     */\n    removeChildByHandle(childItem) {\n        const index = this.__childItems.indexOf(childItem);\n        if (index == -1)\n            throw new Error('Error in removeChildByHandle. Child not found:' + childItem.getName());\n        this.removeChild(index);\n    }\n    /**\n     * Removes all children Items.\n     */\n    removeAllChildren() {\n        let index = this.__childItems.length;\n        while (index--) {\n            this.removeChild(index);\n        }\n        this.setBoundingBoxDirty();\n    }\n    /**\n     * Returns index position of the specified item.\n     *\n     * @param childItem - The child TreeItem value.\n     * @return - Child index in children array.\n     */\n    getChildIndex(childItem) {\n        return this.__childItems.indexOf(childItem);\n    }\n    // ////////////////////////////////////////\n    // Path Traversal\n    // Note: Path resolution starts at the root of the\n    // tree the path was generated from (so index=1, because we don't resolve root).\n    // Note: When a path is made relative to an item in its tree, the path\n    // starts with the child elements.\n    /**\n     * The resolvePath method traverses the subtree from this item down\n     * matching each name in the path with a child until it reaches the\n     * end of the path.\n     *\n     * @param path - The path value.\n     * @param index - The index value.\n     * @return - The return value.\n     */\n    resolvePath(path, index = 0) {\n        if (index == 0) {\n            if (path[0] == '.' || path[0] == this.name)\n                index++;\n        }\n        if (path[index] == '..') {\n            if (this.ownerItem) {\n                return this.ownerItem.resolvePath(path, index + 1);\n            }\n            else {\n                throw Error('this.ownerItem is undefined');\n            }\n        }\n        if (index == path.length) {\n            return this;\n        }\n        const childName = path[index];\n        const childItem = this.getChildByName(childName);\n        if (childItem) {\n            return childItem.resolvePath(path, index + 1);\n        }\n        return super.resolvePath(path, index);\n    }\n    /**\n     * Traverse the tree structure from this point down\n     * and fire the callback for each visited item.\n     * Note: Depth only used by selection sets for now.\n     *\n     * @param callback - The callback value.\n     * @param includeThis - Fire the callback for this item.\n     */\n    traverse(callback, includeThis = true) {\n        const __c = (treeItem, depth) => {\n            const children = treeItem.getChildren();\n            for (const childItem of children) {\n                if (childItem)\n                    __t(childItem, depth);\n            }\n        };\n        const __t = (treeItem, depth) => {\n            if (callback(treeItem, depth) == false)\n                return;\n            __c(treeItem, depth + 1);\n        };\n        if (includeThis) {\n            __t(this, 1);\n        }\n        else {\n            __c(this, 0);\n        }\n    }\n    // ///////////////////////\n    // Events\n    /**\n     * Called by the Viewport when events are received by the canvas element.\n     * The event is propagated to a TreeItem if it is under the pointer at the time.\n     * The ZeaPointerEvent abstracts the Mouse, touch and our custom XR events.\n     * This method emits the ZeaPointerEvent with the key 'pointerDown', and\n     * propagates it up to the TreeItem's owner.\n     *\n     * @param event - The event value\n     */\n    onPointerDown(event) {\n        this.emit('pointerDown', event);\n        if (event.propagating && this.ownerItem instanceof TreeItem) {\n            this.ownerItem.onPointerDown(event);\n        }\n    }\n    /**\n     * Called by the Viewport when events are received by the canvas element.\n     * The event is propagated to a TreeItem if it is under the pointer at the time.\n     * The ZeaPointerEvent abstracts the Mouse, touch and our custom XR events.\n     * This method emits the ZeaPointerEvent with the key 'pointerDown', and\n     * propagates it up to the TreeItem's owner.\n     *\n     * @param event - The pointer event that was generated from the user interaction\n     */\n    onPointerUp(event) {\n        this.emit('pointerUp', event);\n        if (event.propagating && this.ownerItem instanceof TreeItem) {\n            this.ownerItem.onPointerUp(event);\n        }\n    }\n    /**\n     * Called by the Viewport when events are received by the canvas element.\n     * The event is propagated to a TreeItem if it is under the pointer at the time.\n     * The ZeaPointerEvent abstracts the Mouse, touch and our custom XR events.\n     * This method emits the ZeaPointerEvent with the key 'pointerMove', and\n     * propagates it up to the TreeItem's owner.\n     *\n     * @param event - The pointer event that was generated from the user interaction\n     */\n    onPointerMove(event) {\n        this.emit('pointerMove', event);\n        if (event.propagating && this.ownerItem instanceof TreeItem) {\n            this.ownerItem.onPointerMove(event);\n        }\n    }\n    /**\n     * Called by the Viewport when the mouse or other pointer enters the canvas element.\n     * The event is propagated to a TreeItem if it is under the pointer at the time.\n     * The ZeaPointerEvent abstracts the Mouse, touch and our custom XR events.\n     * This method emits the ZeaPointerEvent with the key 'pointerEnter', and\n     * propagates it up to the TreeItem's owner.\n     *\n     * @param event - The pointer event that was generated from the user interaction\n     */\n    onPointerEnter(event) {\n        this.emit('pointerEnter', event);\n        if (event.propagating && this.ownerItem instanceof TreeItem) {\n            this.ownerItem.onPointerEnter(event);\n        }\n    }\n    /**\n     * Called by the Viewport when the mouse or other pointer leaves the canvas element.\n     * The event is propagated to a TreeItem if it is under the pointer at the time.\n     * The ZeaPointerEvent abstracts the Mouse, touch and our custom XR events.\n     * This method emits the ZeaPointerEvent with the key 'pointerLeave', and\n     * propagates it up to the TreeItem's owner.\n     *\n     * @param event - The pointer event that was generated from the user interaction\n     */\n    onPointerLeave(event) {\n        this.emit('pointerLeave', event);\n        if (event.propagating && this.ownerItem instanceof TreeItem) {\n            this.ownerItem.onPointerLeave(event);\n        }\n    }\n    /**\n     * Called by the Viewport when the mouse or other pointer is clicked on this item.\n     *\n     * @param event - The pointer event that was generated from the user interaction\n     */\n    onPointerClick(event) {\n        this.emit('pointerClick', event);\n        if (event.propagating && this.ownerItem instanceof TreeItem) {\n            this.ownerItem.onPointerClick(event);\n        }\n    }\n    /**\n     * Called by the Viewport when the mouse or other pointer is double-clicked on this item.\n     *\n     * @param event - The pointer event that was generated from the user interaction\n     */\n    onPointerDoubleClick(event) {\n        this.emit('pointerDoubleClick', event);\n        if (event.propagating && this.ownerItem instanceof TreeItem) {\n            this.ownerItem.onPointerDoubleClick(event);\n        }\n    }\n    /**\n     * Called by the Viewport when the mouse or other pointer is double-clicked on this item.\n     *\n     * @param event - The pointer event that was generated from the user interaction\n     */\n    onPointerLongPress(event) {\n        this.emit('pointerLongPress', event);\n        if (event.propagating && this.ownerItem instanceof TreeItem) {\n            this.ownerItem.onPointerLongPress(event);\n        }\n    }\n    /**\n     * Called by the Viewport when the mouse wheel event is received by the canvas element.\n     * Emits the ZeaWheelEvent with the key 'mouseWheel', and Propagates is up to the TreeItem's owner.\n     *\n     * @param event - The wheel event that occurs.\n     */\n    onWheel(event) {\n        this.emit('mouseWheel', event);\n        if (event.propagating && this.ownerItem instanceof TreeItem) {\n            this.ownerItem.onWheel(event);\n        }\n    }\n    /**\n     * Called by the Viewport when the touch cancel event is received by the canvas element.\n     * Emits the ZeaTouchEvent with the key 'touchCancel', and Propagates is up to the TreeItem's owner.\n     *\n     * @param event - The wheel event that occurs.\n     */\n    onTouchCancel(event) {\n        this.emit('touchCancel', event);\n        if (event.propagating && this.ownerItem instanceof TreeItem) {\n            this.ownerItem.onTouchCancel(event);\n        }\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * The toJSON method serializes this instance as a JSON.\n     * It can be used for persistence, data transfer, etc.\n     *\n     * @param context - The context value.\n     * @return - Returns the json object.\n     */\n    toJSON(context) {\n        let j = super.toJSON(context);\n        // Some Items, such as the SliderSceneWidget do not need their children\n        // to be saved.\n        const childItemsJSON = {};\n        for (const childItem of this.__childItems) {\n            if (childItem) {\n                const childJSON = childItem.toJSON(context);\n                if (childJSON)\n                    childItemsJSON[childItem.getName()] = childJSON;\n            }\n        }\n        if (Object.keys(childItemsJSON).length > 0) {\n            if (j) {\n                j.children = childItemsJSON;\n            }\n            else {\n                j = {\n                    name: this.name,\n                    children: childItemsJSON,\n                };\n            }\n        }\n        return j;\n    }\n    /**\n     * The fromJSON method takes a JSON and deserializes into an instance of this type.\n     *\n     * @param j - The json object this item must decode.\n     * @param context - The context value.\n     */\n    fromJSON(j, context, onDone) {\n        super.fromJSON(j, context);\n        // if ('bbox' in j){\n        //     let box = new Box3();\n        //     box.fromJSON(j.bbox);\n        //     this.boundingBoxParam.value = box)\n        // }\n        if (j.children != null) {\n            const childrenJson = j.children;\n            if (Array.isArray(childrenJson)) {\n                for (const childJson of childrenJson) {\n                    // Note: During loading of asset trees, we have an\n                    // existing tree generated by loading a bin data file.\n                    let childItem = this.getChildByName(childJson.name);\n                    if (childItem) {\n                        childItem.fromJSON(childJson, context);\n                    }\n                    else {\n                        if (childJson.type) {\n                            childItem = Registry.constructClass(childJson.type);\n                            if (childItem) {\n                                // Note: we should load the json first, as it\n                                // may contain the unique name of the item.\n                                childItem.fromJSON(childJson, context);\n                                this.addChild(childItem, false, false);\n                            }\n                        }\n                    }\n                }\n            }\n            else {\n                // eslint-disable-next-line guard-for-in\n                for (const childName in childrenJson) {\n                    const childJson = childrenJson[childName];\n                    // Note: During loading of asset trees, we have an\n                    // existing tree generated by loading a bin data file.\n                    let childItem = this.getChildByName(childName);\n                    if (childItem) {\n                        childItem.fromJSON(childJson, context);\n                    }\n                    else if (childJson.type) {\n                        childItem = Registry.constructClass(childJson.type);\n                        if (childItem) {\n                            // Note: we add the child now before loading.\n                            // This is because certain items. (e.g. Groups)\n                            // Calculate their global Xfo, and use it to modify\n                            // the transform of their members.\n                            // Note: Groups bind to items in the scene which are\n                            // already added as children, and so have global Xfos.\n                            // We prefer to add a child after its loaded, because sometimes\n                            // In the tree is asset items, who will only toggled as\n                            // unloaded once they are loaded(else they are considered inline assets.)\n                            childItem.fromJSON(childJson, context);\n                            this.addChild(childItem, false, false);\n                        }\n                    }\n                    else ;\n                }\n            }\n        }\n        // if (j.components) {\n        //   for (const cj of j.components) {\n        //     const component = Registry.constructClass(cj.type ? cj.type : cj.name)\n        //     if (component) {\n        //       component.fromJSON(cj, context)\n        //       this.addComponent(component)\n        //     }\n        //   }\n        // }\n    }\n    /**\n     * Sets state of current Item(Including parameters & children) using a binary reader object.\n     *\n     * @param reader - The reader value.\n     * @param context - The context value.\n     */\n    readBinary(reader, context) {\n        super.readBinary(reader, context);\n        const itemFlags = reader.loadUInt8();\n        const visibilityFlag = 1 << 1;\n        // Note: XRef loads a visiblity setting for itself when loading in the parent assembly tree,\n        // then it loads the zcad file which contains a visibility setting for the CADAssset. This\n        // visibility setting would override the XRef. Ideally the zcad file would not store a visiblity\n        // setting for the CADAsset, as that should be set by the loading context.\n        // Visible is true by default, so only set it to false. This is to work around the above conflict.\n        if ((itemFlags & visibilityFlag) == 0)\n            this.setVisible(false);\n        // Note: to save space, some values are skipped if they are identity values\n        const localXfoFlag = 1 << 2;\n        const localXfoIndependentScFlag = 1 << 5;\n        if (itemFlags & localXfoFlag) {\n            const xfo = new Xfo();\n            xfo.tr = reader.loadFloat32Vec3();\n            xfo.ori = reader.loadFloat32Quat();\n            if (itemFlags & localXfoIndependentScFlag) {\n                xfo.sc = reader.loadFloat32Vec3();\n            }\n            else {\n                const sc = reader.loadFloat32();\n                xfo.sc.set(sc, sc, sc);\n            }\n            this.localXfoParam.value = xfo;\n        }\n        const bboxFlag = 1 << 3;\n        if (itemFlags & bboxFlag) {\n            this.boundingBoxParam.loadValue(new Box3(reader.loadFloat32Vec3(), reader.loadFloat32Vec3()));\n        }\n        const numChildren = reader.loadUInt32();\n        if (numChildren > 0) {\n            const toc = reader.loadUInt32Array(numChildren);\n            for (let i = 0; i < numChildren; i++) {\n                try {\n                    reader.seek(toc[i]); // Reset the pointer to the start of the item data.\n                    let childType = reader.loadStr();\n                    const childItem = Registry.constructClass(childType);\n                    if (!childItem) {\n                        const childName = reader.loadStr();\n                        console.warn('Unable to construct child:' + childName + ' of type:' + childType);\n                        continue;\n                    }\n                    reader.seek(toc[i]); // Reset the pointer to the start of the item data.\n                    childItem.readBinary(reader, context);\n                    this.addChild(childItem, false, true);\n                }\n                catch (e) {\n                    console.warn('Error loading tree item: ', e);\n                }\n            }\n        }\n    }\n    // ////////////////////////////////////////\n    // Clone and Destroy\n    clone(context) {\n        const cloned = new TreeItem('');\n        cloned.copyFrom(this, context);\n        return cloned;\n    }\n    /**\n     * Copies current TreeItem with all its children.\n     *\n     * @param src - The tree item to copy from.\n     * @param context - The context value.\n     */\n    copyFrom(src, context) {\n        if (!(src instanceof TreeItem)) {\n            throw new Error('cannot copy from src');\n        }\n        super.copyFrom(src, context);\n        // Note: configure visiblity and opacity before adding children. They will\n        // inherit these settings as they are added.\n        this.visibleCounter = this.visibleParam.value ? 1 : 0;\n        this.updateVisibility();\n        this.updateOpacity();\n        // Note: If a tree item already had children, we must clear them before adding from the src.\n        // An XRef stored in an assembly may contain a cache of its subtree.\n        // If the XRef url does resolve to a file, we must clear this cache before loading the actual data.\n        this.removeAllChildren();\n        src.getChildren().forEach((srcChildItem) => {\n            if (srcChildItem)\n                this.addChild(srcChildItem.clone(context), false, false);\n        });\n    }\n}\nRegistry.register('TreeItem', TreeItem);\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/**\n * Represents a specific type of parameter, that only stores `TreeItem` values.\n *\n * i.e.:\n * ```javascript\n * const treeItem = new TreeItem('tree1')\n * const treeItemParam = new TreeItemParameter('MyTreeItem', treeItem)\n * //'myParameterOwnerItem' is an instance of a 'ParameterOwner' class.\n * // Remember that only 'ParameterOwner' and classes that extend from it can host 'Parameter' objects.\n * myParameterOwnerItem.addParameter(treeItemParam)\n * ```\n *\n * **Events**\n * * **treeItemGlobalXfoChanged:** Triggered when computed world Xfo of parameter's `TreeItem` changes.\n * * **valueChanged:** Triggered when parameter's value changes.\n *\n * @extends Parameter\n */\nclass TreeItemParameter extends Parameter {\n    filterFn;\n    listenerIDs = {};\n    /**\n     * Create a tree item parameter.\n     * @param name - The name of the tree item parameter.\n     * @param filterFn - The filterFn value.\n     */\n    constructor(name = '', filterFn) {\n        super(name, null, 'TreeItem');\n        this.filterFn = filterFn;\n    }\n    emitTreeItemGlobalXfoChanged(event) {\n        this.emit('treeItemGlobalXfoChanged', event);\n    }\n    /**\n     * The setFilterFn method.\n     * @param filterFn - The filterFn value.\n     */\n    setFilterFn(filterFn) {\n        this.filterFn = filterFn;\n    }\n    /**\n     * The getFilterFn method.\n     * @return - The return value.\n     */\n    getFilterFn() {\n        return this.filterFn;\n    }\n    /**\n     * Sets parameter's `TreeItem` value.\n     *\n     * @param value - The treeItem value\n     * @return - The return value.\n     */\n    setValue(value) {\n        if (!(value instanceof TreeItem)) {\n            throw new Error(`value provided is not an instance of a 'TreeItem' class. Check the source of this value`);\n        }\n        // 0 == normal set. 1 = changed via cleaner fn, 2=change by loading/cloning code.\n        if (this.filterFn && !this.filterFn(value))\n            return;\n        if (this.value !== value) {\n            if (this.value) {\n                this.value.off('globalXfoChanged', this.listenerIDs['globalXfoChanged']);\n            }\n            super.setValue(value);\n            if (this.value) {\n                this.listenerIDs['globalXfoChanged'] = this.value.on('globalXfoChanged', (event) => {\n                    this.emitTreeItemGlobalXfoChanged(event);\n                });\n            }\n        }\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * The toJSON method encodes this type as a json object for persistence.\n     *\n     * @param context - The context value.\n     * @return - Returns the json object.\n     */\n    toJSON(context) {\n        return {\n            type: this.getClassName(),\n            name: this.name,\n            value: context.makeRelative(this.value?.getPath()),\n        };\n    }\n    /**\n     * The fromJSON method decodes a json object for this type.\n     *\n     * @param j - The json object this item must decode.\n     * @param context - The context value.\n     */\n    fromJSON(j, context) {\n        if (j.value == null) {\n            console.warn('Invalid Parameter JSON');\n            return;\n        }\n        context.resolvePath(j.value, (treeItem) => {\n            this.setValue(treeItem);\n        }, () => {\n            console.warn('Unable to resolve tree item parameter value:' + j.paramPath);\n        });\n    }\n    // ////////////////////////////////////////\n    // Clone and Destroy\n    /**\n     * The clone method constructs a new tree item parameter, copies its values\n     * from this parameter and returns it.\n     *\n     * @return - Returns a new tree item parameter.\n     */\n    clone(context) {\n        const clonedParam = new TreeItemParameter(this.name, this.filterFn);\n        if (this.value)\n            clonedParam.setValue(this.value.clone(context));\n        return clonedParam;\n    }\n}\nRegistry.register('TreeItemParameter', TreeItemParameter);\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\nclass ItemEvent extends BaseEvent {\n    item;\n    index;\n    constructor(item, index) {\n        super();\n        this.index = index;\n        this.item = item;\n    }\n}\n/** Class representing an item set parameter.\n * @extends Parameter\n * @private\n */\nclass ItemSetParameter extends Parameter {\n    filterFn;\n    /**\n     * Create an item set parameter.\n     * @param name - The name of the item set parameter.\n     * @param filterFn - The filterFn value.\n     */\n    constructor(name = '', filterFn) {\n        super(name, new Set(), 'TreeItem');\n        this.filterFn = filterFn; // Note: the filter Fn indicates that users will edit the set.\n    }\n    /**\n     * The setFilterFn method.\n     * @param filterFn - The filterFn value.\n     */\n    setFilterFn(filterFn) {\n        this.filterFn = filterFn;\n    }\n    /**\n     * The getFilterFn method.\n     * @return - The return value.\n     */\n    getFilterFn() {\n        return this.filterFn;\n    }\n    /**\n     * The getItem method.\n     * @param index - The index param.\n     * @return - The return value.\n     */\n    getItem(index) {\n        // if (!this.__items) return undefined\n        return Array.from(this.value)[index];\n    }\n    /**\n     * The addItem method.\n     * @param item - The item value.\n     * @param emitValueChanged - The emit value.\n     * @return - The return value.\n     */\n    addItem(item, emitValueChanged = true) {\n        if (this.filterFn && !this.filterFn(item)) {\n            console.warn('ItemSet __filterFn rejecting item:', item.getPath());\n            return;\n        }\n        if (!this.value.has(item)) {\n            this.value.add(item);\n            const index = Array.from(this.value).indexOf(item);\n            this.emit('itemAdded', new ItemEvent(item, index));\n            if (emitValueChanged)\n                this.emit('valueChanged');\n            return index;\n        }\n        else {\n            return -1;\n        }\n    }\n    /**\n     * Adds items to the parameter value\n     *\n     * @param items - list of items to add to the parameter\n     * @param emitValueChanged\n     * @memberof ItemSetParameter\n     */\n    addItems(items, emitValueChanged = true) {\n        items.forEach((item) => this.addItem(item, false));\n        if (emitValueChanged)\n            this.emit('valueChanged');\n    }\n    /**\n     * The removeItem method.\n     * @param index - The index value.\n     * @param emitValueChanged - The emit param.\n     * @return - The return value.\n     */\n    removeItem(index, emitValueChanged = true) {\n        const item = Array.from(this.value)[index];\n        this.value.delete(item);\n        this.emit('itemRemoved', new ItemEvent(item, index));\n        if (emitValueChanged)\n            this.emit('valueChanged');\n        return item;\n    }\n    /**\n     * The setItems method.\n     * @param items - The item param.\n     * @param emit - The emit param.\n     */\n    setItems(items, emit = true) {\n        const values = Array.from(this.value);\n        for (let i = values.length - 1; i >= 0; i--) {\n            const item = values[i];\n            if (!items.has(item)) {\n                this.removeItem(i, false);\n            }\n        }\n        for (const item of items) {\n            if (!this.value.has(item)) {\n                this.addItem(item, false);\n            }\n        }\n        if (emit)\n            this.emit('valueChanged');\n    }\n    /**\n     * The clearItems method.\n     * @param emit - The emit value.\n     */\n    clearItems(emitValueChanged = true) {\n        this.value.clear();\n        if (emitValueChanged)\n            this.emit('valueChanged');\n    }\n    /**\n     * The getNumItems method.\n     * @return - The return value.\n     */\n    getNumItems() {\n        return this.value.size; // might be faster\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * The toJSON method encodes this type as a json object for persistence.\n     * @param context - The context value.\n     * @return - The return value.\n     */\n    toJSON(context) {\n        if (!this.value)\n            this.value = new Set();\n        const paths = [];\n        for (const item of this.value) {\n            const path = item.getPath();\n            paths.push(context && context.makeRelative ? context.makeRelative(path) : path);\n        }\n        return {\n            type: this.getClassName(),\n            name: this.name,\n            value: paths,\n        };\n    }\n    /**\n     * The fromJSON method decodes a json object for this type.\n     * @param j - The json object this item must decode.\n     * @param context - The context value.\n     */\n    fromJSON(j, context) {\n        if (!context || !context.resolvePath) {\n            throw new Error('Unable to load JSON on a ItemSetParameter without a load context');\n        }\n        const paths = j.value;\n        paths.forEach((path) => {\n            context.resolvePath(path, (treeItem) => {\n                this.addItem(treeItem, false);\n            }, () => {\n                console.warn(\"BaseGroup: '\" + this.getName() + \"'. Unable to load item:\" + path);\n            });\n        });\n    }\n    // ////////////////////////////////////////\n    // Clone\n    /**\n     * The clone method constructs a item set new parameter, copies its values\n     * from this parameter and returns it.\n     *\n     * @return - Returns a new item set parameter.\n     */\n    clone() {\n        const clonedParam = new ItemSetParameter(this.name, this.filterFn);\n        return clonedParam;\n    }\n}\nRegistry.register('ItemSetParameter', ItemSetParameter);\n\n/**\n * Represents a specific type of parameter, that stores `number` and `BaseImage` texture values.\n *\n * i.e.:\n * ```javascript\n * const image = new LDRImage();\n * image.load(\"https://storage.googleapis.com/zea-playground-assets/zea-engine/texture.png\")\n *\n * const numberParam = new MaterialFloatParam('MyMaterialFloat', 15.5)\n * numberParam.setImage(image)\n * //'myParameterOwnerItem' is an instance of a 'ParameterOwner' class.\n * // Remember that only 'ParameterOwner' and classes that extend from it can host 'Parameter' objects.\n * myParameterOwnerItem.addParameter(numberParam)\n * ```\n *\n * * **Events**\n * * **valueChanged:** Triggered every time the Image value changes\n * * **textureDisconnected:** Triggered when Image value is cleaned/removed.\n * * **textureConnected:** Triggered when the Image value is set.\n *\n * @extends NumberParameter\n */\nclass MaterialFloatParam extends NumberParameter {\n    image;\n    /**\n     * Create a material float parameter.\n     * @param name - The name of the material color parameter.\n     * @param value - The value of the parameter.\n     * @param range - An array with two numbers. If defined, the parameter value will be clamped.\n     */\n    constructor(name = '', value, range) {\n        super(name, value, range);\n    }\n    /**\n     * Returns `BaseImage` texture of the Material.\n     *\n     * @return - The return value.\n     */\n    getImage() {\n        return this.image;\n    }\n    /**\n     * Sets `BaseImage` texture value in parameter.\n     *\n     * @param value - The value value.\n     */\n    setImage(value) {\n        const disconnectImage = () => {\n            this.emit('textureDisconnected');\n        };\n        if (value) {\n            if (this.image != undefined && this.image !== value) {\n                disconnectImage();\n            }\n            this.image = value;\n            this.emit('textureConnected');\n            this.emit('valueChanged');\n        }\n        else {\n            if (this.image != undefined) {\n                disconnectImage();\n                this.image = undefined;\n                this.emit('textureDisconnected');\n            }\n        }\n    }\n    /**\n     * Sets `number` or the `BaseImage` texture value in parameter.\n     *\n     * @param value - The value param.\n     */\n    setValue(value) {\n        if (typeof value != 'number' && !(value instanceof BaseImage)) {\n            throw new Error(`value provided is not of type number of an instance of 'BaseImage' class. Check the source of this value`);\n        }\n        if (value instanceof BaseImage) {\n            this.setImage(value);\n        }\n        else {\n            super.setValue(value);\n        }\n    }\n    /**\n     * Extracts `number` and `Image` values from a buffer, updating current parameter state.\n     *\n     * @param reader - The reader value.\n     * @param context - The context value.\n     */\n    readBinary(reader, context) {\n        super.readBinary(reader, context);\n        const textureName = reader.loadStr();\n        if (textureName != '') {\n            console.log('Load Texture');\n            this.setImage(context.assetItem.materialLibrary.getImage(textureName));\n        }\n    }\n    /**\n     * The clone method constructs a new material float parameter,\n     * copies its values from this parameter and returns it.\n     *\n     * @return - Returns a new cloned material float parameter.\n     */\n    clone() {\n        const clonedParam = new MaterialFloatParam(this.name, this.value, this.range);\n        return clonedParam;\n    }\n}\nRegistry.register('MaterialFloatParam', MaterialFloatParam);\n\nvar ColorSpace;\n(function (ColorSpace) {\n    ColorSpace[\"Gamma\"] = \"Gamma\";\n    ColorSpace[\"Linear\"] = \"Linear\";\n})(ColorSpace || (ColorSpace = {}));\n/**\n * Represents a specific type of parameter, that stores `Color` and `BaseImage` texture values.\n *\n * i.e.:\n * ```javascript\n * const image = new LDRImage();\n * image.load(\"https://storage.googleapis.com/zea-playground-assets/zea-engine/texture.png\")\n *\n * const matColorParam = new MaterialColorParam('MyMaterialColor', new Color(0, 254, 2))\n * matColorParam.setImage(image)\n * //'myParameterOwnerItem' is an instance of a 'ParameterOwner' class.\n * // Remember that only 'ParameterOwner' and classes that extend from it can host 'Parameter' objects.\n * myParameterOwnerItem.addParameter(matColorParam)\n * ```\n *\n * **Events**\n * * **valueChanged:** Triggered every time the Image value changes\n * * **textureDisconnected:** Triggered when Image value is cleaned/removed.\n * * **textureConnected:** Triggered when the Image value is set.\n *\n * @extends ColorParameter\n */\n// TODO: should MaterialColorParam have these parameters below? I'm assuming no.\n// class MaterialColorParam extends Parameter {\n//   constructor() {\n//     super()\n//     this.__shaderName = 'StandardSurfaceShader'\n//     this.addParameter('BaseColor', new MaterialColorParam(1.0, 1, 0.5))\n//     this.addParameter('AmbientOcclusion', new MaterialFloatParam(1, [0, 1]))\n//     this.addParameter('Metallic', new MaterialFloatParam(0.5, [0, 1]))\n//     this.addParameter('Reflectance', new NumberParameter(0.5, [0, 1]))\n//     this.addParameter('Normal', new MaterialColorParam(1.0, 1, 0.5))\n//     this.addParameter('EmissiveStrength', new NumberParameter(0.5, [0, 1]))\n//     this.addParameter('Opacity', new MaterialFloatParam(0.5, [0, 1]))\n//   }\n//   get value() : Color {\n//     return this.value\n//   }\n//   set value() : Color {\n//     return this.value\n//   }\n// }\nclass MaterialColorParam extends ColorParameter {\n    listenerIDs = {};\n    image;\n    // Color values default to gamma space, but when loaded\n    // from a file such as zcad or GLTF, we set this value to ColorSpace.Linear\n    colorSpace = ColorSpace.Gamma;\n    /**\n     * Create a material color parameter.\n     * @param name - The name of the material color parameter.\n     * @param value - The value of the parameter.\n     */\n    constructor(name, value) {\n        super(name, value);\n    }\n    /**\n     * Returns `BaseImage` texture of the Material.\n     *\n     * @return - The return value.\n     */\n    getImage() {\n        return this.image;\n    }\n    /**\n     * The imageUpdated method.\n     * @private\n     */\n    imageUpdated() {\n        this.emit('valueChanged');\n    }\n    /**\n     * Sets `BaseImage` texture value in parameter.\n     *\n     * @param value - The value param.\n     */\n    setImage(value) {\n        const disconnectImage = () => {\n            if (this.image) {\n                this.image.off('updated', this.listenerIDs['updated']);\n                this.image = undefined;\n            }\n            this.emit('textureDisconnected');\n        };\n        if (value) {\n            if (this.image != undefined && this.image !== value) {\n                disconnectImage();\n            }\n            this.image = value;\n            this.listenerIDs['updated'] = this.image.on('updated', () => {\n                this.imageUpdated();\n            });\n            this.emit('textureConnected');\n            this.emit('valueChanged');\n        }\n        else {\n            if (this.image != undefined) {\n                disconnectImage();\n                this.image = undefined;\n                this.emit('textureDisconnected');\n            }\n        }\n    }\n    /**\n     * Sets `Color` or the `BaseImage` texture value in parameter.\n     *\n     * @param value - The value param.\n     */\n    setValue(value) {\n        if (!(value instanceof BaseImage) && !(value instanceof Color)) {\n            throw new Error(`value provided is not an instance of a 'Color' or 'BaseImage' class. Check the source of this value`);\n        }\n        if (value instanceof BaseImage) {\n            this.setImage(value);\n        }\n        else {\n            super.setValue(value);\n        }\n    }\n    /**\n     * Retrieves `Color` and `Image` values from a buffer, updating current parameter state.\n     *\n     * @param reader - The reader value.\n     * @param context - The context value.\n     */\n    readBinary(reader, context) {\n        super.readBinary(reader, context);\n        const textureName = reader.loadStr();\n        if (textureName != '') {\n            this.setImage(context.assetItem.materialLibrary.getImage(textureName));\n        }\n        this.colorSpace = ColorSpace.Linear;\n    }\n    toJSON(context) {\n        const j = super.toJSON(context);\n        j.colorSpace = this.colorSpace;\n        return j;\n    }\n    fromJSON(j, context) {\n        super.fromJSON(j, context);\n        this.colorSpace = ColorSpace[j.colorSpace] ?? ColorSpace.Gamma;\n    }\n    /**\n     * The clone method constructs a new material color parameter,\n     * copies its values from this parameter and returns it.\n     *\n     * @return - Returns a new cloned material color parameter.\n     */\n    clone() {\n        const clonedParam = new MaterialColorParam(this.name, this.value?.clone());\n        clonedParam.colorSpace = this.colorSpace;\n        return clonedParam;\n    }\n}\nRegistry.register('MaterialColorParam', MaterialColorParam);\n\n/* eslint-disable require-jsdoc */\n/**\n * Represents a type of `ParameterOwner` class that holds material configuration.\n * Use this to apply materials to your assets or item parts.\n *\n * **Events**\n * * **shaderNameChanged:** Triggered when the shader's name is set through `setShaderName` method.\n *\n * @extends ParameterOwner\n */\nclass Material extends ParameterOwner {\n    __isOpaque = true;\n    __isTextured = false;\n    __shaderName = '';\n    libraryIndex = -1;\n    /**\n     * Create a material\n     * @param name - The name of the material.\n     * @param shaderName - Shader's class name.\n     */\n    constructor(name, shaderName) {\n        super(name);\n        if (shaderName)\n            this.setShaderName(shaderName);\n    }\n    /**\n     * Getter for the shader name.\n     * @return - Returns the shader name.\n     */\n    getShaderName() {\n        return this.__shaderName;\n    }\n    /**\n     * Sets shader by using the name of the class with the script.\n     * It is important that the shader is registered in `Registry`, otherwise it will error.\n     * See all classes that extend from `GLShader`.\n     *\n     * @param shaderName - The shader name.\n     */\n    setShaderName(shaderName) {\n        if (this.__shaderName == shaderName)\n            return;\n        this.__shaderName = shaderName;\n        const shaderClass = Registry.getClassDefinition(shaderName);\n        const materialTemplate = shaderClass.getMaterialTemplate();\n        if (!materialTemplate)\n            throw new Error('Error setting Shader. Material template not registered found:' + shaderName);\n        const paramMap = {};\n        let i = materialTemplate.getNumParameters();\n        while (i--) {\n            const srcParam = materialTemplate.getParameterByIndex(i);\n            const param = this.getParameter(srcParam.getName());\n            if (param) ;\n            else {\n                this.addParameter(srcParam.clone());\n            }\n            paramMap[srcParam.getName()] = true;\n        }\n        // Remove redundant Params.\n        for (const param of this.params) {\n            if (!paramMap[param.getName()]) {\n                this.removeParameter(param.getName());\n            }\n        }\n        this.__shaderName = shaderName;\n        this.__checkOpacity({});\n        const event = new ShaderNameChangedEvent(shaderName);\n        this.emit('shaderNameChanged', event);\n    }\n    /**\n     * Remove all textures from Material's parameters.\n     */\n    removeAllTextures() {\n        for (const param of this.params) {\n            if (param instanceof MaterialColorParam) {\n                if (param.getImage())\n                    param.setImage(null);\n            }\n            else if (param instanceof MaterialFloatParam) {\n                if (param.getImage())\n                    param.setImage(null);\n            }\n        }\n    }\n    // /////////////////////////////\n    // Parameters\n    /**\n     * Returns the current path of the item in the tree as an array of names.\n     *\n     * @return - Returns an array.\n     */\n    getPath() {\n        if (this.ownerItem == undefined)\n            return [this.name];\n        else if (this.ownerItem instanceof Parameter) {\n            return [...this.ownerItem.getPath(), 'value'];\n        }\n        else {\n            return [...this.ownerItem.getPath(), this.name];\n        }\n    }\n    /**\n     * Returns all texture parameters in current Material.\n     *\n     * @return - The return value.\n     */\n    getParamTextures() {\n        const textures = {};\n        for (const param of this.params) {\n            if (param instanceof MaterialColorParam) {\n                if (param.getImage())\n                    textures[param.getName()] = param.getImage();\n            }\n            else if (param instanceof MaterialFloatParam) {\n                if (param.getImage())\n                    textures[param.getName()] = param.getImage();\n            }\n        }\n        return textures;\n    }\n    /**\n     * Checks if the material is transparent by checking the `Opacity` parameter.\n     *\n     * @return - Returns true if the material is transparent.\n     */\n    isOpaque() {\n        return this.__isOpaque;\n    }\n    __checkOpacity(event) {\n        let isOpaque = true;\n        try {\n            const shaderClass = this.getShaderClass();\n            if (!shaderClass.isOpaque()) {\n                isOpaque = false;\n            }\n        }\n        catch (e) { }\n        if (isOpaque) {\n            const opacity = this.getParameter('Opacity');\n            if (opacity && (opacity.value < 0.99 || (opacity instanceof MaterialFloatParam && opacity.getImage()))) {\n                isOpaque = false;\n            }\n            else {\n                const baseColorParam = this.getParameter('BaseColor');\n                if (baseColorParam) {\n                    if (baseColorParam instanceof MaterialColorParam) {\n                        const image = baseColorParam.getImage();\n                        if (image && image.format == 'RGBA') {\n                            isOpaque = false;\n                        }\n                    }\n                    if (isOpaque && baseColorParam.value) {\n                        const color_val = baseColorParam.value;\n                        if (color_val.a < 1)\n                            isOpaque = false;\n                    }\n                }\n            }\n        }\n        if (isOpaque != this.__isOpaque) {\n            this.__isOpaque = isOpaque;\n            const event = new OpacityStateChangedEvent(isOpaque, true);\n            this.emit('opacityChanged', event);\n            this.emit('transparencyChanged', event); // For legacy listeners\n        }\n    }\n    /**\n     * Checks if the material has a texture applied. The renderer can use this to optimize rendering of non-textured objects\n     *\n     * @return - Returns true if the material is textured.\n     */\n    isTextured() {\n        return this.__isTextured;\n    }\n    __checkTextures(event) {\n        // console.log('__checkTextures')\n        const param = event ? event : {};\n        let isTextured = false;\n        for (const param of this.params) {\n            if (param instanceof MaterialColorParam) {\n                if (param.getImage()) {\n                    isTextured = true;\n                    break;\n                }\n            }\n            else if (param instanceof MaterialFloatParam) {\n                if (param.getImage()) {\n                    isTextured = true;\n                    break;\n                }\n            }\n        }\n        if (isTextured != this.__isTextured) {\n            this.__isTextured = isTextured;\n            let event = new TexturedChangedEvent(isTextured, param);\n            this.emit('texturedChanged', event);\n        }\n    }\n    /**\n     * This method can be overridden in derived classes\n     * to perform general updates (see GLPass or BaseItem).\n     * @param event - The event object emitted by the parameter.\n     * @private\n     */\n    parameterValueChanged(event) {\n        this.__checkOpacity(event);\n        this.__checkTextures(event);\n        super.parameterValueChanged(event);\n    }\n    /**\n     * Returns shaders class of current material, if set. Otherwise it returns `undefined`\n     *\n     * @return - The return value.\n     */\n    getShaderClass() {\n        return Registry.getClassDefinition(this.getShaderName());\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * The toJSON method encodes the current object as a json object.\n     *\n     * @param context - The context value.\n     * @return - Returns the json object.\n     */\n    toJSON(context) {\n        const j = super.toJSON(context);\n        j.shader = this.__shaderName;\n        return j;\n    }\n    /**\n     * The fromJSON method decodes a json object for this type.\n     *\n     * @param j - The json object this item must decode.\n     * @param context - The context value.\n     */\n    fromJSON(j, context = {}) {\n        if (!j.shader) {\n            console.warn('Invalid Material JSON');\n            return;\n        }\n        this.setShaderName(j.shader);\n        super.fromJSON(j, context);\n        this.__checkOpacity();\n        this.__checkTextures();\n    }\n    /**\n     * Sets state of current Item(Including Shaders and Materials) using a binary reader object.\n     *\n     * @param reader - The reader value.\n     * @param context - The context value.\n     */\n    readBinary(reader, context) {\n        let shaderName = reader.loadStr();\n        if (shaderName == 'StandardMaterial') {\n            shaderName = 'StandardSurfaceShader';\n        }\n        if (shaderName == 'TransparentMaterial') {\n            shaderName = 'StandardSurfaceShader';\n        }\n        this.setShaderName(shaderName);\n        super.readBinary(reader, context);\n        this.__checkOpacity();\n        this.__checkTextures();\n    }\n    // ////////////////////////////////////////\n    // Clone and Destroy\n    /**\n     * The clone method constructs a new material, copies its values\n     * from this material and returns it.\n     *\n     * @param context - The context value.\n     * @return - Returns a new cloned material.\n     */\n    clone(context) {\n        const cloned = new Material('clone', ''); // TODO: what should the arguemnts be here?\n        cloned.copyFrom(this, context);\n        return cloned;\n    }\n    /**\n     * When a Material is copied, first runs `BaseItem` copyFrom method, then sets shader.\n     *\n     * @param src - The material to copy from.\n     * @param context - The context value.\n     */\n    copyFrom(src, context) {\n        if (!(src instanceof Material)) {\n            throw new Error('cannot copy from src');\n        }\n        this.setShaderName(src.getShaderName());\n        super.copyFrom(src, context);\n    }\n}\nRegistry.register('Material', Material);\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/**\n * Represents a specific type of parameter, that only stores `Material` values.\n *\n * i.e.:\n * ```javascript\n * const material = new Material('itemMaterial', 'SimpleSurfaceShader')\n * material.getParameter('BaseColor').setValue(new Color(89 / 255, 182 / 255, 92 / 255))\n *\n * const materialParam = new MaterialParameter('MyMaterial', material)\n * //'myParameterOwnerItem' is an instance of a 'ParameterOwner' class.\n * // Remember that only 'ParameterOwner' and classes that extend from it can host 'Parameter' objects.\n * myParameterOwnerItem.addParameter(materialParam)\n * ```\n * **Events**\n * * **valueParameterValueChanged:** Triggered when parameter's value changes.\n * * **valueChanged:** Triggered when parameter's value changes, except on cleaning processes.\n *\n * @extends Parameter\n */\nclass MaterialParameter extends Parameter {\n    listenerIDs = {};\n    /**\n     * Create a material parameter.\n     * @param name - The name of the material parameter.\n     * @param value - The value of the parameter.\n     */\n    constructor(name = '', value = null) {\n        super(name, null, 'Material');\n        if (value)\n            this.setValue(value);\n    }\n    valueParameterValueChanged(event) {\n        this.emit('valueParameterValueChanged', event);\n    }\n    /**\n     * Sets `Material` value of the parameter.\n     *\n     * @param value - The material value.\n     */\n    setValue(value) {\n        if (value != null && !(value instanceof Material)) {\n            throw new Error(`value provided is not an instance of a 'Material' class. Check the source of this value`);\n        }\n        // 0 == normal set. 1 = changed via cleaner fn, 2 = change by loading/cloning code.\n        if (this.value !== value) {\n            if (this.value) {\n                this.value.setOwner(null);\n                this.value.off('parameterValueChanged', this.listenerIDs['parameterValueChanged']);\n            }\n            super.setValue(value);\n            if (this.value) {\n                this.value.setOwner(this);\n                this.listenerIDs['parameterValueChanged'] = this.value.on('parameterValueChanged', (event) => {\n                    this.valueParameterValueChanged(event);\n                });\n            }\n        }\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * The loadValue is used to change the value of a parameter, without triggering a\n     * valueChanges.\n     *\n     * @param value - The context value.\n     */\n    loadValue(value) {\n        if (this.value) {\n            this.value.setOwner(null);\n            this.value.off('parameterValueChanged', this.listenerIDs['parameterValueChanged']);\n        }\n        super.loadValue(value);\n        if (this.value) {\n            this.value.setOwner(this);\n            this.listenerIDs['parameterValueChanged'] = this.value.on('parameterValueChanged', (event) => {\n                this.valueParameterValueChanged(event);\n            });\n        }\n    }\n    /**\n     * The toJSON method encodes this type as a json object for persistence.\n     *\n     * @param context - The context value.\n     * @return - Returns the json object.\n     */\n    toJSON(context) {\n        const j = {\n            type: this.getClassName(),\n            name: this.name,\n        };\n        if (this.value) {\n            if (this.value.libraryIndex >= 0) {\n                j.libraryIndex = this.value.libraryIndex;\n            }\n            else {\n                j.value = this.value.toJSON(context);\n            }\n        }\n        return j;\n    }\n    /**\n     * The fromJSON method decodes a json object for this type.\n     *\n     * @param j - The json object this item must decode.\n     * @param context - The context value.\n     */\n    fromJSON(j, context) {\n        if (j.libraryIndex != undefined) {\n            if (context && context.assetItem) {\n                const materialLibrary = context.assetItem.getMaterialLibrary();\n                const material = materialLibrary.getMaterial(j.libraryIndex);\n                if (material) {\n                    this.setValue(material);\n                }\n            }\n        }\n        else if (j.value) {\n            if (this.value && this.value.getClassName() == j.value.type) {\n                this.value.fromJSON(j.value);\n            }\n            else {\n                const material = Registry.constructClass(j.value.type);\n                if (j.value)\n                    material.fromJSON(j.value, context);\n                this.setValue(material);\n            }\n        }\n    }\n    // ////////////////////////////////////////\n    // Clone and Destroy\n    /**\n     * The clone method constructs a new material parameter, copies its values\n     * from this parameter and returns it.\n     *\n     * @return - Returns a new material parameter.\n     */\n    clone() {\n        const clonedParam = new MaterialParameter(this.name, this.value);\n        return clonedParam;\n    }\n}\nRegistry.register('MaterialParameter', MaterialParameter);\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\nfunction approxEqual(a, b) {\n    for (let i = 0; i < a.length; i++) {\n        if (Math.abs(b[i] - a[i]) > 0.001)\n            return false;\n    }\n    return true;\n}\nconst resizeArray = (inArray, newSize) => {\n    if (inArray instanceof Uint8Array) {\n        const newArray = new Uint8Array(newSize);\n        newArray.set(inArray);\n        return newArray;\n    }\n    else if (inArray instanceof Int8Array) {\n        const newArray = new Int8Array(newSize);\n        newArray.set(inArray);\n        return newArray;\n    }\n    else if (inArray instanceof Uint16Array) {\n        const newArray = new Uint16Array(newSize);\n        newArray.set(inArray);\n        return newArray;\n    }\n    else {\n        const newArray = new Float32Array(newSize);\n        newArray.set(inArray);\n        return newArray;\n    }\n};\nclass Attribute extends BaseClass {\n    dataTypeName;\n    stride;\n    initValue = Number.NaN;\n    normalized;\n    data;\n    mesh;\n    splitValues = [];\n    splits = {};\n    constructor(dataTypeName, stride, initValue = Number.NaN) {\n        super();\n        this.dataTypeName = dataTypeName;\n        this.stride = stride;\n        this.initValue = initValue;\n        this.init();\n    }\n    init() {\n        this.data = new Float32Array(0);\n        this.initRange(0);\n    }\n    /**\n     * Sets the Mesh reference to the VertexAttribute. This is needed for attributes\n     * assigned to meshes, and is used to calculate face vertex indices.\n     * > Note: the mesh automatically calls this method when a vertex attribute is assigned.\n     *\n     * @param mesh - The mesh object\n     */\n    setMesh(mesh) {\n        this.mesh = mesh;\n    }\n    /**\n     * Returns the backing array for this attribute\n     *\n     * @return - The return value.\n     */\n    asArray() {\n        return this.data;\n    }\n    /**\n     * Returns the name of the math type this attribute stores.\n     *\n     * @return - The return value.\n     */\n    getDataTypeName() {\n        return this.dataTypeName;\n    }\n    /**\n     * Returns the count of attribute values in the data.\n     *\n     * @return - The return value.\n     */\n    getCount() {\n        return this.data.length / this.stride;\n    }\n    /**\n     * Returns the count of attribute values in the data.\n     *\n     * @return - The return value.\n     */\n    get count() {\n        return this.data.length / this.stride;\n    }\n    /**\n     * Sets the count of attribute values in the data.\n     *\n     * @param size - The size value.\n     */\n    setCount(count) {\n        const prevLength = this.data.length;\n        const newLength = count * this.stride;\n        if (newLength > prevLength) {\n            this.data = resizeArray(this.data, newLength);\n            this.initRange(prevLength);\n        }\n        else if (newLength < prevLength) {\n            this.data = this.data.slice(0, newLength);\n        }\n        else ;\n        this.splits = {};\n        this.splitValues = [];\n    }\n    /**\n     * Fills up data values with default ones starting from the specified index.\n     *\n     * @param start - The start value.\n     */\n    initRange(start) {\n        // Initialize the values to invalid values.\n        for (let i = start; i < this.data.length; i++) {\n            this.data[i] = this.initValue;\n        }\n    }\n    isInitialized(a) {\n        for (let i = 0; i < a.length; i++) {\n            if (a[i] != this.initValue)\n                return true;\n        }\n        return false;\n    }\n    /**\n     * Returns the number of elements stored in each `T`.\n     *\n     * @return - The return value.\n     */\n    get numElements() {\n        return this.stride;\n    }\n    /**\n     * Returns data value of the specified index.\n     *\n     * @param index - The index value.\n     * @return - The return value.\n     */\n    getFloat32Value(index) {\n        return this.data[index];\n    }\n    /**\n     * Sets data value in the specified index.\n     *\n     * @param index - The index value.\n     * @param value - The value param.\n     */\n    setFloat32Value(index, value) {\n        this.data[index] = value;\n    }\n    /**\n     * Sets data values in the specified index.\n     */\n    getValues(index) {\n        if (index >= this.data.length / this.stride)\n            throw new Error('Invalid vertex index:' + index + '. Num Vertices:' + this.data.length / this.stride);\n        const offset = index * this.stride;\n        return this.data.subarray(offset, offset + this.stride);\n    }\n    /**\n     * Sets data values in the specified index.\n     */\n    setValues(index, values) {\n        if (index >= this.data.length / this.stride)\n            throw new Error('Invalid vertex index:' + index + '. Num Vertices:' + this.data.length / this.stride);\n        const offset = index * this.stride;\n        this.data.set(values, offset);\n    }\n    merge(other, xfo = new Xfo()) {\n        const prevNumValues = this.data.length;\n        const addedValues = other.data.length;\n        const newLength = prevNumValues + addedValues;\n        const data = new Float32Array(newLength);\n        data.set(this.data, 0);\n        for (let i = 0; i < addedValues; i++) {\n            data[prevNumValues + i] = other.data[i];\n        }\n        this.data = data;\n        this.splitValues = [...this.splitValues, ...other.splitValues];\n    }\n    // //////////////////////////////////////////////////\n    // Face Vertex Values\n    /**\n     * The getSplits method.\n     * @return - The return value.\n     */\n    getSplits() {\n        return this.splits;\n    }\n    /**\n     * Gets the value of a corner vertex of a face.\n     * @param face - The face index.\n     * @param faceVertex - The index of vertex within the face. [0... num face vertices]\n     * @return - The return value.\n     */\n    getFaceVertexValue_array(face, faceVertex) {\n        const vertex = this.mesh.getFaceVertexIndex(face, faceVertex);\n        if (vertex in this.splits && face in this.splits[vertex]) {\n            return this.splitValues[this.splits[vertex][face]];\n        }\n        return this.data.subarray(vertex * this.stride, (vertex + 1) * this.stride);\n    }\n    /**\n     * Sets the value of a corner vertex of a face.\n     * @param face - The face index.\n     * @param faceVertex - The index of vertex within the face. [0... num face vertices]\n     * @param value - The value value.\n     */\n    setFaceVertexValue_array(face, faceVertex, value) {\n        const vertex = this.mesh.getFaceVertexIndex(face, faceVertex);\n        this.setFaceVertexValue_ByVertexIndex(face, vertex, value);\n    }\n    /**\n     * The setFaceVertexValue_ByVertexIndex method.\n     * @param face - The face index.\n     * @param vertex - The vertex value.\n     * @param value - The value value.\n     */\n    setFaceVertexValue_ByVertexIndex(face, vertex, value) {\n        const currValue = this.data.subarray(vertex * this.stride, (vertex + 1) * this.stride);\n        if (!this.isInitialized(currValue)) {\n            // the value is uninitialized. Initialize it.\n            currValue.set(value);\n        }\n        else if (approxEqual(currValue, value)) ;\n        else {\n            // The new value is different from the existing value\n            if (vertex in this.splits) {\n                // Now check if any existing splits for this vertex match the value being set.\n                // i.e. for faces around a vertex, there will often be a seam along 2 edges\n                // where the values differ. On each side of the seam, all faces can use the same\n                // value. We should see then only one split value for the vertex.\n                const vertexSplitIds = this.splits[vertex];\n                for (const fid in vertexSplitIds) {\n                    const splitId = vertexSplitIds[fid];\n                    if (approxEqual(this.splitValues[splitId], value)) {\n                        // re-use this split value\n                        vertexSplitIds[face] = splitId;\n                        return;\n                    }\n                }\n                // If a split already exists for this face, re-use it.\n                if (face in this.splits[vertex]) {\n                    this.splitValues[this.splits[vertex][face]] = value;\n                    return;\n                }\n            }\n            else {\n                this.splits[vertex] = {};\n            }\n            this.splits[vertex][face] = this.splitValues.length;\n            this.splitValues.push(value);\n        }\n    }\n    /**\n     * The setSplitVertexValue method.\n     * @param vertex - The vertex value.\n     * @param face - The face index.\n     * @param value - The value value.\n     */\n    setSplitVertexValue_array(vertex, face, value) {\n        if (!(vertex in this.splits))\n            this.splits[vertex] = {};\n        if (face in this.splits[vertex]) {\n            const currValue = this.splitValues[this.splits[vertex][face]];\n            if (approxEqual(currValue, value))\n                return;\n            console.warn('Face Vertex Already Split with different value');\n        }\n        this.splits[vertex][face] = this.splitValues.length;\n        this.splitValues.push(value);\n    }\n    /**\n     * The setSplitVertexValues method.\n     * @param vertex - The vertex value.\n     * @param faceGroup - The faceGroup value.\n     * @param value - The value value.\n     */\n    setSplitVertexValues(vertex, faceGroup, values) {\n        if (!(vertex in this.splits))\n            this.splits[vertex] = {};\n        const splitIndex = this.splitValues.length;\n        this.splitValues.push(values);\n        for (const face of faceGroup) {\n            // if (face in this.splits[vertex]) {\n            //     let currValue = this.splitValues[this.splits[vertex][face]];\n            //     if (currValue.approxEqual(value))\n            //         return;\n            //     console.warn(\"Face Vertex Already Split with different value\");\n            // }\n            this.splits[vertex][face] = splitIndex;\n        }\n    }\n    /**\n     * The generateSplitValues method.\n     * @param splitIndices - The splitIndices value.\n     * @param splitCount - The splitCount value.\n     * @return - The return value.\n     */\n    generateSplitValues(splitIndices, splitCount) {\n        if (splitCount == 0)\n            return this.data;\n        const numUnSplitValues = this.getCount();\n        const data = resizeArray(this.data, (numUnSplitValues + splitCount) * this.stride);\n        // Now duplicate the split values to generate an attributes array\n        // using the shared splits across all attributes.\n        // eslint-disable-next-line guard-for-in\n        for (const vertex in splitIndices) {\n            const faces = splitIndices[vertex];\n            // eslint-disable-next-line guard-for-in\n            for (const face in faces) {\n                const tgt = numUnSplitValues + faces[face];\n                if (vertex in this.splits && face in this.splits[vertex]) {\n                    // this attribute has a split value in its array.\n                    // we must use that value...\n                    const src = this.splits[vertex][face];\n                    const srcArray = this.splitValues[src];\n                    for (let i = 0; i < srcArray.length; i++) {\n                        data[tgt * this.stride + i] = srcArray[i];\n                    }\n                }\n                else {\n                    // Copy each scalar value to the new place in the array.\n                    const src = parseInt(vertex);\n                    for (let e = 0; e < this.stride; e++) {\n                        data[tgt * this.stride + e] = this.data[src * this.stride + e];\n                    }\n                }\n            }\n        }\n        return data;\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * The toJSON method encodes this type as a json object for persistence.\n     *\n     * @param context - The context value.\n     * @return - Returns the json object.\n     */\n    toJSON(context) {\n        return {\n            data: Array.from(this.data),\n            dataType: this.dataTypeName,\n            length: this.data.length / this.stride,\n        };\n    }\n    /**\n     * The fromJSON method decodes a json object for this type.\n     *\n     * @param j - The json object this item must decode.\n     */\n    fromJSON(j) {\n        const data = j.data;\n        for (let i = 0; i < data.length; i++) {\n            this.data[i] = data[i];\n        }\n    }\n    /**\n     * The loadSplitValues method.\n     * @param reader - The reader value.\n     */\n    loadSplitValues(reader) {\n        const splitIndices = reader.loadUInt32Array();\n        if (splitIndices.length == 0)\n            return;\n        let offset = 0;\n        let numSplitValues = 0;\n        while (true) {\n            const vertexId = splitIndices[offset++];\n            const numSplits = splitIndices[offset++];\n            const splits = {};\n            for (let i = 0; i < numSplits; i++) {\n                const faceId = splitIndices[offset++];\n                const splitId = splitIndices[offset++];\n                splits[faceId] = splitId;\n                if (splitId >= numSplitValues)\n                    numSplitValues = splitId + 1;\n            }\n            this.splits[vertexId] = splits;\n            if (offset >= splitIndices.length)\n                break;\n        }\n        const dim = this.stride;\n        const splitValues = reader.loadFloat32Array(numSplitValues * dim);\n        this.splitValues = [];\n        for (let i = 0; i < numSplitValues; i++) {\n            const val = splitValues.slice(i * dim, i * dim + dim);\n            this.splitValues.push(val);\n        }\n    }\n    /**\n     * Returns the string representation of the object's state.\n     *\n     * @return - The return value.\n     */\n    toString() {\n        return JSON.stringify(this.toJSON(), null, 2);\n    }\n    // ////////////////////////////////////////\n    // Memory\n    /**\n     * Returns vertex attributes buffers and its count.\n     *\n     * @return - The return value.\n     */\n    genBuffer() {\n        return {\n            values: this.data,\n            count: this.getCount(),\n            dimension: this.stride,\n            dataType: this.dataTypeName,\n            normalized: this.normalized,\n        };\n    }\n}\n\n/**\n * Class representing an attribute.\n */\nclass Vec2Attribute extends Attribute {\n    /**\n     * Create a Vec2Attribute.\n     */\n    constructor(dataTypeName = 'Vec2') {\n        super(dataTypeName, 2);\n        this.normalized = false;\n    }\n    /**\n     * Returns the Vec2 from the specified index.\n     *\n     * @param index - The index value.\n     * @return Vec2 - The return value.\n     */\n    getValue(index) {\n        if (index >= this.data.length / this.stride)\n            throw new Error('Invalid vertex index:' + index + '. Num Vertices:' + this.data.length / 3);\n        const offset = index * this.stride;\n        return new Vec2(this.data[offset], this.data[offset + 1]);\n    }\n    /**\n     * Sets Vec2 at the specified index.\n     *\n     * @param index - The index value.\n     * @param value - The value param.\n     */\n    setValue(index, value) {\n        if (index >= this.data.length / this.stride)\n            throw new Error('Invalid vertex index:' + index + '. Num Vertices:' + this.data.length / 3);\n        const offset = index * this.stride;\n        this.data.set(value.asArray(), offset);\n    }\n    /**\n     * Gets the value of a corner vertex of a face.\n     * > Note: 'Ref' means that the value contains a reference to the data in the attribute.\n     * > The components of the value can be changed causing the attributes data is changed.\n     * > No need to call 'setFaceVertexValue'.\n     * @param face - The face index.\n     * @param faceVertex - The index of vertex within the face. [0... num face vertices]\n     * @return - The return value.\n     */\n    getFaceVertexValue(face, faceVertex) {\n        const array = this.getFaceVertexValue_array(face, faceVertex);\n        return new Vec2(array[0], array[1]);\n    }\n    /**\n     * Sets the value of a corner vertex of a face.\n     * @param face - The face index.\n     * @param faceVertex - The index of vertex within the face. [0... num face vertices]\n     * @param value - The value value.\n     */\n    setFaceVertexValue(face, faceVertex, value) {\n        this.setFaceVertexValue_array(face, faceVertex, Float32Array.from(value.asArray()));\n    }\n    /**\n     * The setSplitVertexValue method.\n     * @param vertex - The vertex value.\n     * @param face - The face index.\n     * @param value - The value value.\n     */\n    setSplitVertexValue(vertex, face, value) {\n        this.setSplitVertexValue_array(vertex, face, Float32Array.from(value.asArray()));\n    }\n    merge(other, xfo = new Xfo()) {\n        const prevNumValues = this.getCount();\n        const addedValues = other.getCount();\n        this.setCount(prevNumValues + addedValues);\n        for (let i = 0; i < addedValues; i++) {\n            this.setValue(prevNumValues + i, other.getValue(i));\n        }\n        this.splitValues = [...this.splitValues, ...other.splitValues];\n    }\n}\nRegistry.register('Vec2Attribute', Vec2Attribute);\n\nconst mapIn$2 = (value) => {\n    return MathFunctions.encode16BitFloat(value);\n};\nconst mapOut$2 = (value) => {\n    return MathFunctions.decode16BitFloat(value);\n};\n/**\n * Class representing an attribute.\n */\nclass Vec2f16Attribute extends Vec2Attribute {\n    /**\n     * Create a Vec3f8Attribute.\n     */\n    constructor() {\n        super('Vec2f16');\n    }\n    init() {\n        this.data = new Uint16Array(0);\n        this.initRange(0);\n    }\n    initRange(start) {\n        // Initialize the values to invalid values.\n        for (let i = start; i < this.data.length; i++) {\n            this.data[i] = mapIn$2(Number.NaN);\n        }\n    }\n    isInitialized(a) {\n        for (let i = 0; i < a.length; i++) {\n            if (Number.isFinite(mapOut$2(a[i])))\n                return true;\n        }\n        return false;\n    }\n    /**\n     * Returns a copy of the Vec2 value at the specified index.\n     *\n     * @param index - The index value.\n     * @return Vec2 - The value at the specified index.\n     */\n    getValue(index) {\n        if (index >= this.data.length / this.stride)\n            throw new Error('Invalid vertex index:' + index + '. Num Vertices:' + this.data.length / 3);\n        const offset = index * this.stride;\n        const valueData = this.data.subarray(offset, offset + this.stride);\n        return new Vec2(mapOut$2(valueData[0]), mapOut$2(valueData[1]));\n    }\n    /**\n     * Sets Vec2 at the specified index.\n     *\n     * @param index - The index value.\n     * @param value - The value param.\n     */\n    setValue(index, value) {\n        if (index >= this.data.length / this.stride)\n            throw new Error('Invalid vertex index:' + index + '. Num Vertices:' + this.data.length / 3);\n        const offset = index * this.stride;\n        const valueData = this.data.subarray(offset, offset + this.stride);\n        valueData[0] = mapIn$2(value.x);\n        valueData[1] = mapIn$2(value.y);\n    }\n    /**\n     * Gets the value of a corner vertex of a face.\n     * > Note: 'Ref' means that the value contains a reference to the data in the attribute.\n     * > The components of the value can be changed causing the attributes data is changed.\n     * > No need to call 'setFaceVertexValue'.\n     * @param face - The face index.\n     * @param faceVertex - The index of vertex within the face. [0... num face vertices]\n     * @return - The return value.\n     */\n    getFaceVertexValue(face, faceVertex) {\n        const array = this.getFaceVertexValue_array(face, faceVertex);\n        return new Vec2(mapOut$2(array[0]), mapOut$2(array[1]));\n    }\n    /**\n     * Sets the value of a corner vertex of a face.\n     * @param face - The face index.\n     * @param faceVertex - The index of vertex within the face. [0... num face vertices]\n     * @param value - The value value.\n     */\n    setFaceVertexValue(face, faceVertex, value) {\n        const valueData = new Uint16Array(2);\n        valueData[0] = mapIn$2(value.x);\n        valueData[1] = mapIn$2(value.y);\n        this.setFaceVertexValue_array(face, faceVertex, valueData);\n    }\n}\n\nclass Vec3Ref {\n    data;\n    constructor(data) {\n        this.data = data;\n    }\n    get x() {\n        return this.data[0];\n    }\n    set x(value) {\n        this.data[0] = value;\n    }\n    get y() {\n        return this.data[1];\n    }\n    set y(value) {\n        this.data[1] = value;\n    }\n    get z() {\n        return this.data[2];\n    }\n    set z(value) {\n        this.data[2] = value;\n    }\n    set(x, y, z) {\n        this.data[0] = x;\n        this.data[1] = y;\n        this.data[2] = z;\n    }\n}\n/**\n * Class representing an attribute.\n */\nclass Vec3Attribute extends Attribute {\n    /**\n     * Create a Vec3Attribute.\n     */\n    constructor(dataTypeName = 'Vec3') {\n        super(dataTypeName, 3);\n        this.normalized = false;\n    }\n    /**\n     * Returns a copy of the Vec3 value at the specified index.\n     *\n     * @param index - The index value.\n     * @return Vec3 - The value at the specified index.\n     */\n    getValue(index) {\n        if (index >= this.data.length / this.stride)\n            throw new Error('Invalid vertex index:' + index + '. Num Vertices:' + this.data.length / 3);\n        const offset = index * this.stride;\n        return new Vec3(this.data[offset + 0], this.data[offset + 1], this.data[offset + 2]);\n    }\n    /**\n     * Returns a copy of the Vec3 value at the specified index.\n     *\n     * @deprecated - This method will soon be removed.\n     * @return Vec3 - The value at the specified index.\n     */\n    getValueRef(index) {\n        if (index >= this.data.length / this.stride)\n            throw new Error('Invalid vertex index:' + index + '. Num Vertices:' + this.data.length / 3);\n        const offset = index * this.stride;\n        return new Vec3Ref(this.data.subarray(offset, offset + 3));\n    }\n    /**\n     * Sets Vec3 at the specified index.\n     *\n     * @param index - The index value.\n     * @param value - The value param.\n     */\n    setValue(index, value) {\n        this.setValues(index, value.asArray());\n    }\n    /**\n     * Gets the value of a corner vertex of a face.\n     * > Note: 'Ref' means that the value contains a reference to the data in the attribute.\n     * > The components of the value can be changed causing the attributes data is changed.\n     * > No need to call 'setFaceVertexValue'.\n     * @param face - The face index.\n     * @param faceVertex - The index of vertex within the face. [0... num face vertices]\n     * @return - The return value.\n     */\n    getFaceVertexValue(face, faceVertex) {\n        const array = this.getFaceVertexValue_array(face, faceVertex);\n        return new Vec3(array[0], array[1], array[2]);\n    }\n    /**\n     * Sets the value of a corner vertex of a face.\n     * @param face - The face index.\n     * @param faceVertex - The index of vertex within the face. [0... num face vertices]\n     * @param value - The value value.\n     */\n    setFaceVertexValue(face, faceVertex, value) {\n        this.setFaceVertexValue_array(face, faceVertex, Float32Array.from(value.asArray()));\n    }\n    /**\n     * The setSplitVertexValue method.\n     * @param vertex - The vertex value.\n     * @param face - The face index.\n     * @param value - The value value.\n     */\n    setSplitVertexValue(vertex, face, value) {\n        this.setSplitVertexValue_array(vertex, face, Float32Array.from(value.asArray()));\n    }\n    merge(other, xfo = new Xfo()) {\n        const prevNumValues = this.getCount();\n        const addedValues = other.getCount();\n        // We cached these values before calling 'setCount'.\n        // Maybe 'setCount' shoulnd't clear the splits. It seems heavy, but I don't want to change anything.\n        // We should just re-write the system without splits anyway.\n        // const splitValues = [...this.splitValues, ...other.splitValues]\n        // const splits = [...this.splits, ...other.splits]\n        this.setCount(prevNumValues + addedValues);\n        for (let i = 0; i < addedValues; i++) {\n            this.setValue(prevNumValues + i, xfo.transformVec3(other.getValue(i)));\n        }\n        // this.splitValues = [...this.splitValues, ...other.splitValues]\n    }\n}\nRegistry.register('Vec3Attribute', Vec3Attribute);\n\nclass Vec3f8Ref {\n    data;\n    constructor(data) {\n        this.data = data;\n    }\n    get x() {\n        return MathFunctions.decode16BitFloat(this.data[0]);\n    }\n    set x(value) {\n        this.data[0] = MathFunctions.encode16BitFloat(value);\n    }\n    get y() {\n        return MathFunctions.decode16BitFloat(this.data[1]);\n    }\n    set y(value) {\n        this.data[1] = MathFunctions.encode16BitFloat(value);\n    }\n    get z() {\n        return MathFunctions.decode16BitFloat(this.data[2]);\n    }\n    set z(value) {\n        this.data[2] = MathFunctions.encode16BitFloat(value);\n    }\n    set(x, y, z) {\n        this.data[0] = MathFunctions.encode16BitFloat(x);\n        this.data[1] = MathFunctions.encode16BitFloat(y);\n        this.data[2] = MathFunctions.encode16BitFloat(z);\n    }\n}\nconst mapIn$1 = (value, valueRange) => {\n    return MathFunctions.remap(value, valueRange[0], valueRange[1], -127, 127);\n};\nconst mapOut$1 = (value, valueRange) => {\n    return MathFunctions.remap(value, -127, 127, valueRange[0], valueRange[1]);\n};\n/**\n * Class representing an attribute.\n */\nclass Vec3f8Attribute extends Vec3Attribute {\n    valueRange;\n    /**\n     * Create a Vec3f8Attribute.\n     */\n    constructor(valueRange = [-1, 1]) {\n        super('Vec3f8');\n        this.valueRange = valueRange;\n    }\n    init() {\n        this.data = new Int8Array(0);\n        this.initRange(0);\n    }\n    initRange(start) {\n        // Initialize the values to invalid values.\n        for (let i = start; i < this.data.length; i++) {\n            this.data[i] = mapIn$1(Number.NaN, this.valueRange);\n        }\n    }\n    isInitialized(a) {\n        for (let i = 0; i < a.length; i++) {\n            if (Number.isFinite(mapOut$1(a[i], this.valueRange)))\n                return true;\n        }\n        return false;\n    }\n    /**\n     * Returns a copy of the Vec3 value at the specified index.\n     *\n     * @param index - The index value.\n     * @return Vec3 - The value at the specified index.\n     */\n    getValue(index) {\n        if (index >= this.data.length / this.stride)\n            throw new Error('Invalid vertex index:' + index + '. Num Vertices:' + this.data.length / 3);\n        const offset = index * this.stride;\n        const valueData = this.data.subarray(offset, offset + this.stride);\n        return new Vec3(mapOut$1(valueData[0], this.valueRange), mapOut$1(valueData[1], this.valueRange), mapOut$1(valueData[2], this.valueRange));\n    }\n    /**\n     * Returns a copy of the Vec3 value at the specified index.\n     *\n     * @deprecated - This method will soon be removed.\n     * @return Vec3 - The value at the specified index.\n     */\n    getValueRef(index) {\n        if (index >= this.data.length / this.stride)\n            throw new Error('Invalid vertex index:' + index + '. Num Vertices:' + this.data.length / 3);\n        const offset = index * this.stride;\n        return new Vec3f8Ref(this.data.subarray(offset, offset + 3));\n    }\n    /**\n     * Sets Vec3 at the specified index.\n     *\n     * @param index - The index value.\n     * @param value - The value param.\n     */\n    setValue(index, value) {\n        if (index >= this.data.length / this.stride)\n            throw new Error('Invalid vertex index:' + index + '. Num Vertices:' + this.data.length / 3);\n        const offset = index * this.stride;\n        const valueData = this.data.subarray(offset, offset + this.stride);\n        valueData[0] = mapIn$1(value.x, this.valueRange);\n        valueData[1] = mapIn$1(value.y, this.valueRange);\n        valueData[2] = mapIn$1(value.z, this.valueRange);\n    }\n    /**\n     * Gets the value of a corner vertex of a face.\n     * > Note: 'Ref' means that the value contains a reference to the data in the attribute.\n     * > The components of the value can be changed causing the attributes data is changed.\n     * > No need to call 'setFaceVertexValue'.\n     * @param face - The face index.\n     * @param faceVertex - The index of vertex within the face. [0... num face vertices]\n     * @return - The return value.\n     */\n    getFaceVertexValue(face, faceVertex) {\n        const array = this.getFaceVertexValue_array(face, faceVertex);\n        return new Vec3(mapOut$1(array[0], this.valueRange), mapOut$1(array[1], this.valueRange), mapOut$1(array[2], this.valueRange));\n    }\n    /**\n     * Sets the value of a corner vertex of a face.\n     * @param face - The face index.\n     * @param faceVertex - The index of vertex within the face. [0... num face vertices]\n     * @param value - The value value.\n     */\n    setFaceVertexValue(face, faceVertex, value) {\n        const valueData = new Int8Array(3);\n        valueData[0] = mapIn$1(value.x, this.valueRange);\n        valueData[1] = mapIn$1(value.y, this.valueRange);\n        valueData[2] = mapIn$1(value.z, this.valueRange);\n        this.setFaceVertexValue_array(face, faceVertex, valueData);\n    }\n    /**\n     * The setSplitVertexValues method.\n     * @param vertex - The vertex value.\n     * @param faceGroup - The faceGroup value.\n     * @param value - The value value.\n     */\n    setSplitVertexValues(vertex, faceGroup, values) {\n        super.setSplitVertexValues(vertex, faceGroup, values.map((v) => mapIn$1(v, this.valueRange), this.valueRange));\n    }\n}\n\nconst mapIn = (value) => {\n    return MathFunctions.encode16BitFloat(value);\n};\nconst mapOut = (value) => {\n    return MathFunctions.decode16BitFloat(value);\n};\nclass Vec3f16Ref {\n    data;\n    constructor(data) {\n        this.data = data;\n    }\n    get x() {\n        return mapOut(this.data[0]);\n    }\n    set x(value) {\n        this.data[0] = mapIn(value);\n    }\n    get y() {\n        return mapOut(this.data[1]);\n    }\n    set y(value) {\n        this.data[1] = mapIn(value);\n    }\n    get z() {\n        return mapOut(this.data[2]);\n    }\n    set z(value) {\n        this.data[2] = mapIn(value);\n    }\n    set(x, y, z) {\n        this.data[0] = mapIn(x);\n        this.data[1] = mapIn(y);\n        this.data[2] = mapIn(z);\n    }\n}\n/**\n * Class representing an attribute.\n */\nclass Vec3f16Attribute extends Vec3Attribute {\n    /**\n     * Create a Vec3f8Attribute.\n     */\n    constructor() {\n        super('Vec3f16');\n    }\n    init() {\n        this.data = new Uint16Array(0);\n        this.initRange(0);\n    }\n    initRange(start) {\n        // Initialize the values to invalid values.\n        for (let i = start; i < this.data.length; i++) {\n            this.data[i] = mapIn(Number.NaN);\n        }\n    }\n    isInitialized(a) {\n        for (let i = 0; i < a.length; i++) {\n            if (Number.isFinite(mapOut(a[i])))\n                return true;\n        }\n        return false;\n    }\n    /**\n     * Returns a copy of the Vec3 value at the specified index.\n     *\n     * @param index - The index value.\n     * @return Vec3 - The value at the specified index.\n     */\n    getValue(index) {\n        if (index >= this.data.length / this.stride)\n            throw new Error('Invalid vertex index:' + index + '. Num Vertices:' + this.data.length / 3);\n        const offset = index * this.stride;\n        const valueData = this.data.subarray(offset, offset + this.stride);\n        return new Vec3(mapOut(valueData[0]), mapOut(valueData[1]), mapOut(valueData[2]));\n    }\n    /**\n     * Returns a copy of the Vec3 value at the specified index.\n     *\n     * @deprecated - This method will soon be removed.\n     * @return Vec3 - The value at the specified index.\n     */\n    getValueRef(index) {\n        if (index >= this.data.length / this.stride)\n            throw new Error('Invalid vertex index:' + index + '. Num Vertices:' + this.data.length / 3);\n        const offset = index * this.stride;\n        return new Vec3f16Ref(this.data.subarray(offset, offset + 3));\n    }\n    /**\n     * Sets Vec3 at the specified index.\n     *\n     * @param index - The index value.\n     * @param value - The value param.\n     */\n    setValue(index, value) {\n        if (index >= this.data.length / this.stride)\n            throw new Error('Invalid vertex index:' + index + '. Num Vertices:' + this.data.length / 3);\n        const offset = index * this.stride;\n        const valueData = this.data.subarray(offset, offset + this.stride);\n        valueData[0] = mapIn(value.x);\n        valueData[1] = mapIn(value.y);\n        valueData[2] = mapIn(value.z);\n    }\n    /**\n     * Gets the value of a corner vertex of a face.\n     * > Note: 'Ref' means that the value contains a reference to the data in the attribute.\n     * > The components of the value can be changed causing the attributes data is changed.\n     * > No need to call 'setFaceVertexValue'.\n     * @param face - The face index.\n     * @param faceVertex - The index of vertex within the face. [0... num face vertices]\n     * @return - The return value.\n     */\n    getFaceVertexValue(face, faceVertex) {\n        const array = this.getFaceVertexValue_array(face, faceVertex);\n        return new Vec3(mapOut(array[0]), mapOut(array[1]), mapOut(array[2]));\n    }\n    /**\n     * Sets the value of a corner vertex of a face.\n     * @param face - The face index.\n     * @param faceVertex - The index of vertex within the face. [0... num face vertices]\n     * @param value - The value value.\n     */\n    setFaceVertexValue(face, faceVertex, value) {\n        const valueData = new Uint16Array(3);\n        valueData[0] = mapIn(value.x);\n        valueData[1] = mapIn(value.y);\n        valueData[2] = mapIn(value.z);\n        this.setFaceVertexValue_array(face, faceVertex, valueData);\n    }\n    /**\n     * The setSplitVertexValues method.\n     * @param vertex - The vertex value.\n     * @param faceGroup - The faceGroup value.\n     * @param value - The value value.\n     */\n    setSplitVertexValues(vertex, faceGroup, values) {\n        super.setSplitVertexValues(vertex, faceGroup, values.map((v) => mapIn(v)));\n    }\n}\n\n/**\n * Class representing an attribute.\n */\nclass ColorAttribute extends Attribute {\n    /**\n     * Create a ColorAttribute.\n     */\n    constructor() {\n        super('Color', 4);\n        this.normalized = false;\n    }\n    /**\n     * Returns a copy of the Color value at the specified index.\n     *\n     * @param index - The index value.\n     * @return Color - The return value.\n     */\n    getValue(index) {\n        if (index >= this.data.length / this.stride)\n            throw new Error('Invalid vertex index:' + index + '. Num Vertices:' + this.data.length / 3);\n        const offset = index * this.stride;\n        return new Color(this.data[offset + 0], this.data[offset + 1], this.data[offset + 2], this.data[offset + 3]);\n    }\n    /**\n     * Sets Color at the specified index.\n     *\n     * @param index - The index value.\n     * @param value - The value param.\n     */\n    setValue(index, value) {\n        this.setValues(index, value.asArray());\n    }\n    /**\n     * Gets the value of a corner vertex of a face.\n     * > Note: 'Ref' means that the value contains a reference to the data in the attribute.\n     * > The components of the value can be changed causing the attributes data is changed.\n     * > No need to call 'setFaceVertexValue'.\n     * @param face - The face index.\n     * @param faceVertex - The index of vertex within the face. [0... num face vertices]\n     * @return - The return value.\n     */\n    getFaceVertexValue(face, faceVertex) {\n        const array = this.getFaceVertexValue_array(face, faceVertex);\n        return new Color(array[0], array[1], array[2], array[3]);\n    }\n    /**\n     * Sets the value of a corner vertex of a face.\n     * @param face - The face index.\n     * @param faceVertex - The index of vertex within the face. [0... num face vertices]\n     * @param value - The value value.\n     */\n    setFaceVertexValue(face, faceVertex, value) {\n        this.setFaceVertexValue_array(face, faceVertex, Float32Array.from(value.asArray()));\n    }\n    /**\n     * The setSplitVertexValue method.\n     * @param vertex - The vertex value.\n     * @param face - The face index.\n     * @param value - The value value.\n     */\n    setSplitVertexValue(vertex, face, value) {\n        this.setSplitVertexValue_array(vertex, face, Float32Array.from(value.asArray()));\n    }\n    merge(other, xfo = new Xfo()) {\n        const prevNumValues = this.getCount();\n        const addedValues = other.getCount();\n        this.setCount(prevNumValues + addedValues);\n        for (let i = 0; i < addedValues; i++) {\n            this.setValue(prevNumValues + i, other.getValue(i));\n        }\n        this.splitValues = [...this.splitValues, ...other.splitValues];\n    }\n}\nRegistry.register('ColorAttribute', ColorAttribute);\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\nconst parse8BitPositionsArray = (range, offset, sclVec, positions_quantized, positionsAttr) => {\n    for (let i = range[0]; i < range[1]; i++) {\n        const pos = new Vec3(positions_quantized[i * 3 + 0] / 255.0, positions_quantized[i * 3 + 1] / 255.0, positions_quantized[i * 3 + 2] / 255.0);\n        pos.multiplyInPlace(sclVec);\n        pos.addInPlace(offset);\n        positionsAttr.setValue(i, pos);\n    }\n};\nconst parse16BitPositionsArray = (range, offset, sclVec, positions_quantized, positionsAttr) => {\n    for (let i = range[0]; i < range[1]; i++) {\n        const pos = new Vec3(positions_quantized[i * 3 + 0] / 65535.0, positions_quantized[i * 3 + 1] / 65535.0, positions_quantized[i * 3 + 2] / 65535.0);\n        pos.multiplyInPlace(sclVec);\n        pos.addInPlace(offset);\n        positionsAttr.setValue(i, pos);\n    }\n};\nconst parse8BitNormalsArray = (range, offset, sclVec, normals_quantized, normalsAttr) => {\n    if (sclVec.isNull())\n        sclVec.set(1, 1, 1);\n    for (let i = range[0]; i < range[1]; i++) {\n        const normal = new Vec3(normals_quantized[i * 3 + 0] / 255.0, normals_quantized[i * 3 + 1] / 255.0, normals_quantized[i * 3 + 2] / 255.0);\n        normal.multiplyInPlace(sclVec);\n        normal.addInPlace(offset);\n        normal.normalizeInPlace();\n        normalsAttr.setValue(i, normal);\n    }\n};\nconst parse8BitTextureCoordsArray = (range, offset, sclVec, texCoords_quantized, texCoordsAttr) => {\n    // if (sclVec.isNull())\n    //     sclVec.set(1, 1, 1);\n    for (let i = range[0]; i < range[1]; i++) {\n        const textureCoord = new Vec2(texCoords_quantized[i * 2 + 0] / 255.0, texCoords_quantized[i * 2 + 1] / 255.0);\n        textureCoord.multiplyInPlace(sclVec);\n        textureCoord.addInPlace(offset);\n        texCoordsAttr.setValue(i, textureCoord);\n    }\n};\nconst parse16BitTextureCoordsArray = (range, offset, sclVec, texCoords_quantized, texCoordsAttr) => {\n    // if (sclVec.isNull())\n    //     sclVec.set(1, 1, 1);\n    for (let i = range[0]; i < range[1]; i++) {\n        const textureCoord = new Vec2(texCoords_quantized[i * 2 + 0] / 65535.0, texCoords_quantized[i * 2 + 1] / 65535.0);\n        textureCoord.multiplyInPlace(sclVec);\n        textureCoord.addInPlace(offset);\n        texCoordsAttr.setValue(i, textureCoord);\n    }\n};\n/**\n * Represents a base class for 3D geometry items.\n *\n * **Events**\n * * **boundingBoxChanged:** Triggered when the bounding box changes.\n * * **geomDataChanged:** Emitted when the geometry attributes have changed. The topology did not change. The Renderer will upload the new attributes to the GPU.\n * * **geomDataTopologyChanged:** Emitted when the geometry attributes and topology have changed.  The Renderer will upload the new attributes and topology to the GPU.\n *\n * @extends ParameterOwner\n */\nclass BaseGeom extends ParameterOwner {\n    boundingBox = new Box3();\n    boundingBoxDirty = true;\n    __metaData = new Map();\n    #numVertices = 0;\n    __vertexAttributes = new Map();\n    debugColor = new Color(1, 0, 0, 1);\n    /**\n     * Create a base geom.\n     */\n    constructor() {\n        super();\n        this.addVertexAttribute('positions', new Vec3f16Attribute());\n    }\n    /**\n     * Returns the current path of the item in the tree as an array of names.\n     *\n     * @return - Returns an array.\n     */\n    getPath() {\n        if (this.ownerItem == undefined)\n            return [this.name];\n        else if (this.ownerItem instanceof Parameter) {\n            return [...this.ownerItem.getPath(), 'value'];\n        }\n        else {\n            return [...this.ownerItem.getPath(), this.name];\n        }\n    }\n    /**\n     * The clear method.\n     */\n    clear() {\n        this.setNumVertices(0);\n    }\n    /**\n     * Adds a new vertex attribute to the geometry.\n     *\n     * @param name - The name of the vertex attribute.\n     * @param dataType - The dataType value. // TODO: is any ok vs. AttrValue | number. Unsure about how dataType is used\n     * @return - Returns an attribute.\n     */\n    addVertexAttribute(name, attr) {\n        attr.setCount(this.#numVertices);\n        this.__vertexAttributes.set(name, attr);\n    }\n    /**\n     * Checks if the the geometry has an attribute with the specified name.\n     *\n     * @param name - The name of the vertex attribute.\n     * @return - The return value.\n     */\n    hasVertexAttribute(name) {\n        return this.__vertexAttributes.has(name);\n    }\n    /**\n     * Returns vertex attribute with the specified name.\n     *\n     * @param name - The name of the vertex attribute.\n     * @return - The return value.\n     */\n    getVertexAttribute(name) {\n        return this.__vertexAttributes.get(name);\n    }\n    /**\n     * Returns all vertex attributes in an object with their names.\n     *\n     * @return - The return value.\n     */\n    getVertexAttributes() {\n        const vertexAttributes = {};\n        for (const [key, attr] of this.__vertexAttributes.entries())\n            vertexAttributes[key] = attr;\n        return vertexAttributes;\n    }\n    /**\n     * Returns 'positions' vertex attribute.\n     */\n    get positions() {\n        return this.__vertexAttributes.get('positions');\n    }\n    /**\n     * Returns the number of vertex attributes.\n     *\n     * @return - The return value.\n     */\n    numVertices() {\n        return this.#numVertices;\n    }\n    /**\n     * Returns the number of vertex attributes.\n     *\n     * @return - The return value.\n     */\n    getNumVertices() {\n        return this.#numVertices;\n    }\n    /**\n     * Sets the number of vertices the geometry has.\n     *\n     * @param count - The count value.\n     */\n    setNumVertices(count) {\n        this.#numVertices = count;\n        // Resizes each of the vertex attributes to match the new count.\n        this.__vertexAttributes.forEach((attr) => attr.setCount(this.#numVertices));\n        this.setBoundingBoxDirty();\n    }\n    // ////////////////////////////////////////\n    // BoundingBox\n    /**\n     * Returns the bounding box for geometry.\n     * @return - The return value.\n     */\n    getBoundingBox() {\n        if (this.boundingBoxDirty)\n            this.updateBoundingBox();\n        return this.boundingBox;\n    }\n    /**\n     * The setBoundingBoxDirty method.\n     */\n    setBoundingBoxDirty() {\n        this.boundingBoxDirty = true;\n        this.emit('boundingBoxChanged');\n    }\n    /**\n     * The updateBoundingBox method.\n     */\n    updateBoundingBox() {\n        const positions = this.positions;\n        const bbox = new Box3();\n        if (positions) {\n            const numVerts = positions.getCount();\n            for (let i = 0; i < numVerts; i++)\n                bbox.addPoint(positions.getValue(i));\n        }\n        this.boundingBox = bbox;\n        this.boundingBoxDirty = false;\n    }\n    /**\n     * Merges a separate geometry into this one. Similar to a 'union' boolean operation.\n     * @param other the other geom that will be merged into this one\n     * @param xfo the transformation to be applied to the other geom as it is merged in.\n     */\n    merge(other, xfo = new Xfo()) {\n        const prevNumVerts = this.getNumVertices();\n        const addedVerts = other.getNumVertices();\n        for (const [attrName, attr] of this.__vertexAttributes) {\n            const otherAttr = other.getVertexAttribute(attrName);\n            if (otherAttr) {\n                if (attrName == 'positions')\n                    attr.merge(otherAttr, xfo);\n                else if (attrName == 'normals')\n                    attr.merge(otherAttr, new Xfo(new Vec3(), xfo.ori));\n            }\n        }\n        // Note: all the attributes have already been resized, so\n        // this is just a final check.\n        this.setNumVertices(prevNumVerts + addedVerts);\n        this.updateBoundingBox();\n    }\n    // ////////////////////////////////////////\n    // Memory\n    /**\n     * Returns vertex attributes buffers and its count.\n     * @return - The return value.\n     */\n    genBuffers(opts) {\n        const attrBuffers = {};\n        for (const [attrName, attr] of this.__vertexAttributes) {\n            attrBuffers[attrName] = attr.genBuffer();\n        }\n        return {\n            numVertices: this.numVertices(),\n            attrBuffers,\n        };\n    }\n    /**\n     * Once the buffers have been uploaded to the GPU, we are free to release them.\n     * The GLGeomLibrary may call this function to let the geometry know it can release any handles.\n     */\n    freeBuffers() { }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * Sets state of current Geometry(Including Vertices and Bounding Box) using a binary reader object.\n     *\n     * @param reader - The reader value.\n     */\n    loadBaseGeomBinary(reader, context) {\n        this.name = reader.loadStr();\n        const flags = reader.loadUInt8();\n        this.debugColor = reader.loadRGBFloat32Color();\n        const numVerts = reader.loadUInt32();\n        this.boundingBox.set(reader.loadFloat32Vec3(), reader.loadFloat32Vec3());\n        let normalsAttr;\n        let texCoordsAttr;\n        if (flags & (1 << 1)) {\n            normalsAttr = this.getVertexAttribute('normals');\n            if (!normalsAttr) {\n                normalsAttr = new Vec3f8Attribute();\n                this.addVertexAttribute('normals', normalsAttr);\n            }\n        }\n        if (flags & (1 << 2)) {\n            texCoordsAttr = this.getVertexAttribute('texCoords');\n            if (!texCoordsAttr) {\n                texCoordsAttr = new Vec2f16Attribute();\n                this.addVertexAttribute('texCoords', texCoordsAttr);\n            }\n        }\n        const numClusters = reader.loadUInt32();\n        if (numClusters == 0) {\n            const positionsAttr = this.positions;\n            // From 3.12.0, vertex data is a mix of 16bit and 8 bit quanitization\n            // without any k-means clustering.\n            // @ts-ignore\n            positionsAttr.data = reader.loadUInt16Array(numVerts * 3);\n            if (normalsAttr) {\n                // @ts-ignore\n                normalsAttr.data = reader.loadInt8Array(numVerts * 3);\n            }\n            if (texCoordsAttr) {\n                // @ts-ignore\n                texCoordsAttr.data = reader.loadUInt16Array(numVerts * 2);\n            }\n            // This should be a no-op in each of the attributes as they already have\n            // arrays of the appropriate size..\n            this.setNumVertices(numVerts);\n        }\n        else if (numClusters == 1) {\n            // Older zcad files store 32 bit floats. The renderer may convert these to 16bit.\n            this.addVertexAttribute('positions', new Vec3Attribute());\n            this.setNumVertices(numVerts);\n            const positionsAttr = this.positions;\n            {\n                const box3 = this.boundingBox;\n                // From 3.9.1, vertex data is a mix of 16bit and 8 bit quanitization\n                if (context.versions['zea-engine'].compare([3, 9, 1]) >= 0) {\n                    const positions_quantized = reader.loadUInt16Array(numVerts * 3, false);\n                    parse16BitPositionsArray([0, numVerts], box3.p0, box3.diagonal(), positions_quantized, positionsAttr);\n                }\n                else {\n                    const positions_quantized = reader.loadUInt8Array(numVerts * 3, false);\n                    parse8BitPositionsArray([0, numVerts], box3.p0, box3.diagonal(), positions_quantized, positionsAttr);\n                }\n            }\n            if (normalsAttr) {\n                const box3 = new Box3(reader.loadFloat32Vec3(), reader.loadFloat32Vec3());\n                const normals_quantized = reader.loadUInt8Array(numVerts * 3, false);\n                parse8BitNormalsArray([0, numVerts], box3.p0, box3.diagonal(), normals_quantized, normalsAttr);\n                normalsAttr.loadSplitValues(reader);\n            }\n            if (texCoordsAttr) {\n                const box2 = new Box2(reader.loadFloat32Vec2(), reader.loadFloat32Vec2());\n                // From 3.9.1, vertex data is a mix of 16bit and 8 bit quanitization\n                if (context.versions['zea-engine'].compare([3, 9, 1]) >= 0) {\n                    const texCoords_quantized = reader.loadUInt16Array(numVerts * 2, false);\n                    parse16BitTextureCoordsArray([0, numVerts], box2.p0, box2.diagonal(), texCoords_quantized, texCoordsAttr);\n                }\n                else {\n                    const texCoords_quantized = reader.loadUInt8Array(numVerts * 2, false);\n                    parse8BitTextureCoordsArray([0, numVerts], box2.p0, box2.diagonal(), texCoords_quantized, texCoordsAttr);\n                }\n                texCoordsAttr.loadSplitValues(reader);\n            }\n        }\n        else {\n            // Older zcad files store 32 bit floats. The renderer may convert these to 16bit.\n            this.addVertexAttribute('positions', new Vec3Attribute());\n            this.setNumVertices(numVerts);\n            const positionsAttr = this.positions;\n            const clusters = [];\n            let offset = 0;\n            for (let i = 0; i < numClusters; i++) {\n                const count = reader.loadUInt32();\n                const clusterData = {\n                    range: [offset, offset + count],\n                    bbox: new Box3(reader.loadFloat32Vec3(), reader.loadFloat32Vec3()),\n                    normalsRange: new Box3(),\n                    texCoordsRange: new Box2(),\n                };\n                if (normalsAttr) {\n                    clusterData.normalsRange.set(reader.loadFloat32Vec3(), reader.loadFloat32Vec3());\n                }\n                if (texCoordsAttr) {\n                    clusterData.texCoordsRange.set(reader.loadFloat32Vec2(), reader.loadFloat32Vec2());\n                }\n                clusters.push(clusterData);\n                offset += count;\n            }\n            // From 3.9.1, vertex data is a mix of 16bit and 8 bit quanitization\n            let positions_quantized;\n            if (context.versions['zea-engine'].compare([3, 9, 1]) >= 0) {\n                positions_quantized = reader.loadUInt16Array(numVerts * 3, false);\n            }\n            else {\n                positions_quantized = reader.loadUInt8Array(numVerts * 3, false);\n            }\n            let normals_quantized = null;\n            let texCoords_quantized = null;\n            if (normalsAttr) {\n                normals_quantized = reader.loadUInt8Array(numVerts * 3, false);\n            }\n            if (texCoordsAttr) {\n                texCoords_quantized = reader.loadUInt8Array(numVerts * 2, false);\n            }\n            for (let i = 0; i < numClusters; i++) {\n                {\n                    const box3 = clusters[i].bbox;\n                    // From 3.9.1, vertex data is a mix of 16bit and 8 bit quanitization\n                    if (context.versions['zea-engine'].compare([3, 9, 1]) >= 0) {\n                        parse16BitPositionsArray(clusters[i].range, box3.p0, box3.diagonal(), positions_quantized, positionsAttr);\n                    }\n                    else {\n                        parse8BitPositionsArray(clusters[i].range, box3.p0, box3.diagonal(), positions_quantized, positionsAttr);\n                    }\n                }\n                if (normals_quantized) {\n                    const box3 = clusters[i].normalsRange;\n                    parse8BitNormalsArray(clusters[i].range, box3.p0, box3.diagonal(), normals_quantized, normalsAttr);\n                }\n                if (texCoords_quantized) {\n                    const box2 = clusters[i].texCoordsRange;\n                    if (context.versions['zea-engine'].compare([3, 9, 1]) >= 0) {\n                        parse16BitTextureCoordsArray([0, numVerts], box2.p0, box2.diagonal(), texCoords_quantized, texCoordsAttr);\n                    }\n                    else {\n                        parse8BitTextureCoordsArray(clusters[i].range, box2.p0, box2.diagonal(), texCoords_quantized, texCoordsAttr);\n                    }\n                }\n            }\n            if (normalsAttr) {\n                normalsAttr.loadSplitValues(reader);\n            }\n            if (texCoordsAttr) {\n                texCoordsAttr.loadSplitValues(reader);\n            }\n        }\n        // Loading the attributes may have dirtied the bounding box.\n        // we konw we already loaded the bbox, so force it to be valid.\n        this.boundingBoxDirty = false;\n    }\n    /**\n     * The toJSON method encodes this type as a json object for persistence.\n     *\n     * @param context - The context value.\n     * @return - Returns the json object.\n     */\n    toJSON(context) {\n        const json = super.toJSON(context);\n        if (!context || !context.skipTopology) {\n            json.numVertices = this.#numVertices || 0;\n        }\n        const vertexAttributes = {};\n        for (const [key, attr] of this.__vertexAttributes.entries()) {\n            if (!context || !('skipAttributes' in context) || !context.skipAttributes.includes(key))\n                vertexAttributes[key] = attr.toJSON(context);\n        }\n        json.vertexAttributes = vertexAttributes;\n        return json;\n    }\n    /**\n     * The fromJSON method decodes a json object for this type.\n     *\n     * @param json - The json object this item must decode.\n     * @param context - The context value.\n     */\n    fromJSON(json, context) {\n        this.clear();\n        super.fromJSON(json, context);\n        this.setNumVertices(json.numVertices);\n        for (const name in json.vertexAttributes) {\n            let attr = this.__vertexAttributes.get(name);\n            const attrJSON = json.vertexAttributes[name];\n            if (!attr || attr.dataTypeName != attrJSON.dataType) {\n                switch (attrJSON.dataType) {\n                    case 'Vec2':\n                        attr = new Vec2Attribute();\n                        break;\n                    case 'Vec2f16':\n                        attr = new Vec2f16Attribute();\n                        break;\n                    case 'Vec3':\n                        attr = new Vec3Attribute();\n                        break;\n                    case 'Vec3f16':\n                        attr = new Vec3f16Attribute();\n                        break;\n                    case 'Vec3f8':\n                        attr = new Vec3f8Attribute();\n                        break;\n                    case 'Color':\n                        attr = new ColorAttribute();\n                        break;\n                    default:\n                        throw 'Invalid Vectex Type: ' + attr.dataTypeName;\n                }\n                attr.setCount(this.#numVertices);\n                this.addVertexAttribute(name, attr);\n            }\n            if (attr) {\n                attr.fromJSON(attrJSON);\n            }\n            else {\n                console.warn('attr undefined, cannot execute fromJSON()');\n            }\n        }\n        this.emit('geomDataTopologyChanged');\n    }\n    /**\n     * Returns geometry data value in json format.\n     *\n     * @return - The return value.\n     */\n    toString() {\n        return JSON.stringify(this.toJSON(), null, 2);\n    }\n}\n\n/**\n * Class representing an attribute.\n */\nclass Vec4Attribute extends Attribute {\n    /**\n     * Create a Vec4Attribute.\n     */\n    constructor() {\n        super('Vec4', 4);\n        this.normalized = false;\n    }\n    /**\n     * Returns a copy of the Vec4 value at the specified index.\n     *\n     * @param index - The index value.\n     * @return Vec4 - The value at the specified index.\n     */\n    getValue(index) {\n        if (index >= this.data.length / this.stride)\n            throw new Error('Invalid vertex index:' + index + '. Num Vertices:' + this.data.length / 3);\n        const offset = index * this.stride;\n        return new Vec4(this.data[offset + 0], this.data[offset + 1], this.data[offset + 2], this.data[offset + 3]);\n    }\n    /**\n     * Sets Vec4 at the specified index.\n     *\n     * @param index - The index value.\n     * @param value - The value param.\n     */\n    setValue(index, value) {\n        this.setValues(index, value.asArray());\n    }\n    /**\n     * Gets the value of a corner vertex of a face.\n     * > Note: 'Ref' means that the value contains a reference to the data in the attribute.\n     * > The components of the value can be changed causing the attributes data is changed.\n     * > No need to call 'setFaceVertexValue'.\n     * @param face - The face index.\n     * @param faceVertex - The index of vertex within the face. [0... num face vertices]\n     * @return - The return value.\n     */\n    getFaceVertexValue(face, faceVertex) {\n        const array = this.getFaceVertexValue_array(face, faceVertex);\n        return new Vec4(array[0], array[1], array[2], array[3]);\n    }\n    /**\n     * Sets the value of a corner vertex of a face.\n     * @param face - The face index.\n     * @param faceVertex - The index of vertex within the face. [0... num face vertices]\n     * @param value - The value value.\n     */\n    setFaceVertexValue(face, faceVertex, value) {\n        this.setFaceVertexValue_array(face, faceVertex, Float32Array.from(value.asArray()));\n    }\n    /**\n     * The setSplitVertexValue method.\n     * @param vertex - The vertex value.\n     * @param face - The face index.\n     * @param value - The value value.\n     */\n    setSplitVertexValue(vertex, face, value) {\n        this.setSplitVertexValue_array(vertex, face, Float32Array.from(value.asArray()));\n    }\n    merge(other, xfo = new Xfo()) {\n        const prevNumValues = this.getCount();\n        const addedValues = other.getCount();\n        this.setCount(prevNumValues + addedValues);\n        for (let i = 0; i < addedValues; i++) {\n            this.setValue(prevNumValues + i, other.getValue(i));\n        }\n        this.splitValues = [...this.splitValues, ...other.splitValues];\n    }\n}\nRegistry.register('Vec4Attribute', Vec4Attribute);\n\n/**\n * Class representing a point primitive drawing type, every vertex specified is a point.\n *\n * ```\n * const points = new Points()\n * ```\n *\n * * **Events**\n * * **boundingBoxChanged:** Triggered when the bounding box changes.\n *\n * @extends BaseGeom\n */\nclass Points extends BaseGeom {\n    /**\n     * Create points.\n     */\n    constructor() {\n        super();\n    }\n    /**\n     * The clear method.\n     */\n    clear() {\n        this.setNumVertices(0);\n        this.emit('geomDataTopologyChanged');\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * Sets state of current geometry(Including line segments) using a binary reader object.\n     *\n     * @param reader - The reader value.\n     * @param context - The context value.\n     */\n    readBinary(reader, context) {\n        super.loadBaseGeomBinary(reader, context);\n        // this.computeVertexNormals();\n        this.emit('geomDataChanged');\n    }\n}\nRegistry.register('Points', Points);\n\n/* eslint-disable @typescript-eslint/no-unused-vars */\nclass ImageArrayParameter extends Parameter {\n    constructor(name = '', value = []) {\n        super(name, value, 'BaseImage[]');\n    }\n    /**\n     * The toJSON method encodes this type as a json object for persistence.\n     *\n     * @param context - The context value.\n     * @return - Returns the json object.\n     */\n    toJSON(context) {\n        const j = {\n            type: this.getClassName(),\n            name: this.name,\n            images: this.value.map((image) => {\n                return {\n                    imageType: image?.getClassName(),\n                    value: image?.toJSON(),\n                };\n            }),\n        };\n        return j;\n    }\n    /**\n     * The fromJSON method decodes a json object for this type.\n     *\n     * @param j - The json object this item must decode.\n     * @param context - The context value.\n     * @return - Returns the json object.\n     */\n    fromJSON(j, context) {\n        if (j.images) {\n            const images = j.images;\n            this.value = images.map((imageJson) => {\n                const image = Registry.constructClass(imageJson.imageType);\n                if (image && imageJson.value)\n                    image.fromJSON(imageJson.value, context);\n                return image;\n            });\n        }\n    }\n    clone() {\n        const clonedParam = new ImageArrayParameter(this.name, this.value);\n        return clonedParam;\n    }\n}\nRegistry.register('ImageArrayParameter', ImageArrayParameter);\n\n/**\n * @extends Points\n */\nclass FatPoints extends Points {\n    sprites = new ImageArrayParameter('Sprites');\n    /**\n     * Create points.\n     */\n    constructor() {\n        super();\n        this.addVertexAttribute('sizes', new Attribute('Float32', 1, 1));\n        this.addVertexAttribute('colors', new ColorAttribute());\n        this.addVertexAttribute('spriteIndices', new Attribute('Float32', 1, -1));\n        this.addParameter(this.sprites);\n    }\n}\nRegistry.register('FatPoints', FatPoints);\n\n/* eslint-disable @typescript-eslint/no-unused-vars */\n/**\n *\n * Class representing lines primitive drawing type, connecting vertices using the specified indices.\n * i.e. We have 4 points(vertices) but we don't know how they connect to each other,\n * and that's why we need indices(Numbers indicating which vertex connects to which).\n * In this case if we say that `indices` is `[0,1,2,3]`, it would connect the first vertex to the second,\n * and the third to the fourth.\n *\n * ```\n * const lines = new Lines()\n * ```\n *\n * **Events**\n * * **geomDataChanged:** Triggered when the data value of the geometry is set(This includes reading binary)\n *\n * @extends BaseGeom\n */\nclass Lines extends BaseGeom {\n    __indices;\n    /**\n     * Create lines.\n     */\n    constructor() {\n        super();\n        this.__indices = new Uint32Array();\n    }\n    /**\n     * The clear method.\n     */\n    clear() {\n        this.setNumSegments(0);\n        this.setNumVertices(0);\n        this.emit('geomDataTopologyChanged');\n    }\n    /**\n     * Returns the specified indices(Vertex connectors)\n     *\n     * @return - The indices index array.\n     */\n    getIndices() {\n        return this.__indices;\n    }\n    /**\n     * Returns the number of line segments.\n     *\n     * @return - Returns the number of segments.\n     */\n    getNumSegments() {\n        return this.__indices.length / 2;\n    }\n    /**\n     * Returns the number of line segments.\n     *\n     * @return - Returns the number of segments.\n     */\n    getNumLineSegments() {\n        return this.__indices.length / 2;\n    }\n    /**\n     * Sets the number of line segments in the lines geometry.\n     * **Important:** It resets indices values.\n     *\n     * @param numOfSegments - The count value.\n     */\n    setNumSegments(numOfSegments) {\n        if (numOfSegments > this.getNumSegments()) {\n            const indices = new Uint32Array(numOfSegments * 2);\n            indices.set(this.__indices);\n            this.__indices = indices;\n        }\n        else {\n            this.__indices = this.__indices.slice(0, numOfSegments * 2);\n        }\n    }\n    /**\n     * Sets segment values in the specified index.\n     *\n     * @param index - The index value.\n     * @param p0 - The p0 value.\n     * @param p1 - The p1 value.\n     */\n    setSegmentVertexIndices(index, p0, p1) {\n        if (index >= this.__indices.length / 2)\n            throw new Error('Invalid line index:' + index + '. Num Segments:' + this.__indices.length / 2);\n        this.__indices[index * 2 + 0] = p0;\n        this.__indices[index * 2 + 1] = p1;\n    }\n    /**\n     * The getSegmentVertexIndex method.\n     *\n     * @param line - The line value.\n     * @param lineVertex - The lineVertex value.\n     * @return - The return value.\n     * @private\n     */\n    getSegmentVertexIndex(line, lineVertex) {\n        const numSegments = this.getNumSegments();\n        if (line < numSegments)\n            return this.__indices[line * 2 + lineVertex];\n        return -1;\n    }\n    /**\n     * Merges a separate geometry into this one. Similar to a 'union' boolean operation.\n     * @param other the other geom that will be merged into this one\n     * @param xfo the transformation to be applied to the other geom as it is merged in.\n     */\n    merge(other, xfo = new Xfo()) {\n        const prevNumVerts = this.getNumVertices();\n        super.merge(other, xfo);\n        const otheIndices = other.__indices;\n        const indices = new Uint32Array(this.__indices.length + otheIndices.length);\n        indices.set(this.__indices, 0);\n        indices.set(otheIndices.map((index) => index + prevNumVerts), this.__indices.length);\n        this.__indices = indices;\n    }\n    // ////////////////////////////////////////\n    // Memory\n    /**\n     * Returns vertex attributes buffers and its count.\n     *\n     * @return - The return value.\n     */\n    genBuffers(opts) {\n        const buffers = super.genBuffers();\n        let indices;\n        if (buffers.numVertices < Math.pow(2, 8)) {\n            indices = new Uint8Array(this.__indices);\n        }\n        else if (buffers.numVertices < Math.pow(2, 16)) {\n            indices = new Uint16Array(this.__indices);\n        }\n        else {\n            indices = this.__indices;\n        }\n        buffers.indices = indices;\n        return buffers;\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * Sets state of current geometry(Including line segments) using a binary reader object.\n     *\n     * @param reader - The reader value.\n     * @param context - The context value.\n     */\n    readBinary(reader, context) {\n        super.loadBaseGeomBinary(reader, context);\n        this.setNumSegments(reader.loadUInt32());\n        const bytes = reader.loadUInt8();\n        if (bytes == 1)\n            this.__indices = reader.loadUInt8Array();\n        else if (bytes == 2)\n            this.__indices = reader.loadUInt16Array();\n        else if (bytes == 4)\n            this.__indices = reader.loadUInt32Array();\n        this.emit('geomDataChanged');\n    }\n    /**\n     * The toJSON method encodes this type as a json object for persistence.\n     *\n     * @param context - The context value.\n     * @return - Returns the json object.\n     */\n    toJSON(context) {\n        const j = super.toJSON(context);\n        if (!context || !context.skipTopology)\n            j.indices = Array.from(this.__indices);\n        return j;\n    }\n    /**\n     * The fromJSON method decodes a json object for this type.\n     *\n     * @param j - The json object this item must decode.\n     * @param context - The context value.\n     */\n    fromJSON(j, context) {\n        super.fromJSON(j, context);\n        if (j.indices)\n            this.__indices = Uint32Array.from(j.indices);\n    }\n}\nRegistry.register('Lines', Lines);\n\n/* eslint-disable prefer-rest-params */\n/**\n * The Mesh class provides a flexible and fast polygon mesh representation. It supports polygons of arbitrary complexity,\n * from basic triangles and quads to pentagons more.\n * It supports storing per face attributes, and per edge attributes.\n * The Mesh class handles converting its internal representation of polygons into a simpler triangles representation for rendering.\n *\n * ```\n * const mesh = new Mesh()\n * ```\n *\n * **Events**\n * * **geomDataTopologyChanged:** Triggered when the topology of the mesh has been changed.\n * * **geomDataChanged:** Triggered when the vertices of the mesh have changed, but not necessarily the topology.\n *\n * @extends BaseGeom\n */\nclass Mesh extends BaseGeom {\n    faceCounts;\n    faceVertexIndices;\n    __logTopologyWarnings;\n    __edgeAttributes;\n    __faceAttributes;\n    numEdges;\n    edgeVerts;\n    edgeAngles;\n    edgeVecs;\n    edgeFaces;\n    faceEdges;\n    vertexEdges;\n    /**\n     * Creates an instance of Mesh.\n     */\n    constructor() {\n        super();\n        this.edgeFaces = [];\n        this.faceEdges = [[]];\n        this.faceCounts = [];\n        this.faceVertexIndices = new Uint32Array();\n        this.__logTopologyWarnings = false;\n        this.__edgeAttributes = new Map();\n        this.__faceAttributes = new Map();\n        this.numEdges = 0;\n        this.edgeVerts = [];\n        this.vertexEdges = [];\n        this.edgeAngles = new Float32Array();\n        this.edgeVecs = [];\n    }\n    /**\n     * The clear method.\n     */\n    clear() {\n        super.clear();\n        //this.init()\n        //this.setNumVertices(0)\n        // clear edge and face normals.\n        this.edgeVerts = [];\n        this.vertexEdges = [];\n        this.numEdges = 0;\n        this.edgeAngles = new Float32Array();\n        this.emit('geomDataTopologyChanged');\n    }\n    /**\n     * Adds a new vertex attribute to the geometry.\n     *\n     * @param name - The name of the vertex attribute.\n     * @param attr - The attribute to add to the geometry\n     */\n    addVertexAttribute(name, attr) {\n        super.addVertexAttribute(name, attr);\n        attr.setMesh(this);\n    }\n    /**\n     * The getFaceCounts method.\n     * @return - The return value.\n     */\n    getFaceCounts() {\n        return this.faceCounts;\n    }\n    /**\n     * The getNumFaces method.\n     * @return - The return value.\n     */\n    getNumFaces() {\n        return this.faceCounts.length == 0 ? 0 : this.faceCounts.reduce((numFaces, fc) => (numFaces += fc));\n    }\n    /**\n     * The getNumTriangles method.\n     * @return {number} - The return value.\n     */\n    getNumTriangles() {\n        let numTriangles = 0;\n        let numTrisPerFace = 1;\n        for (const fc of this.faceCounts) {\n            numTriangles += fc * numTrisPerFace;\n            numTrisPerFace++;\n        }\n        return numTriangles;\n    }\n    /**\n     * Sets the number of faces on the mesh using an array specifying the counts per polygon size.\n     * The first item in the array specifies the number of triangles, the second, the number of quads, the 3rd, the number of 5 sided polygons etc..\n     * e.g. to specify 2 triangles, and 7 quads, we would pass [2, 7]\n     * @param faceCounts - The faceCounts value.\n     */\n    setFaceCounts(faceCounts) {\n        // let numFaces = 0\n        let numFacesVertices = 0;\n        let numVertsPerFace = 3;\n        for (const fc of faceCounts) {\n            // numFaces += fc\n            numFacesVertices += fc * numVertsPerFace;\n            numVertsPerFace++;\n        }\n        const prevNumFaces = this.getNumFaces();\n        if (prevNumFaces == 0) {\n            this.faceVertexIndices = new Uint32Array(numFacesVertices);\n        }\n        else {\n            const faceVertexIndices = new Uint32Array(numFacesVertices);\n            // Now we preserve the existing indices if they fit within the new faceVertexIndices array.\n            let startSrc = 0;\n            let startTgt = 0;\n            numFacesVertices = 0;\n            numVertsPerFace = 3;\n            faceCounts.forEach((fc, index) => {\n                const endSrc = startSrc + Math.min(fc, this.faceCounts[index]) * numVertsPerFace;\n                faceVertexIndices.set(this.faceVertexIndices.slice(startSrc, endSrc), startTgt);\n                startSrc += this.faceCounts[index] * numVertsPerFace;\n                startTgt += fc * numVertsPerFace;\n                numVertsPerFace++;\n            });\n            this.faceVertexIndices = faceVertexIndices;\n        }\n        this.faceCounts = faceCounts;\n    }\n    /**\n     * Returns the number of face vertices\n     * @return - The return value.\n     */\n    getNumFaceVertices() {\n        let numFaceVerts = 0;\n        this.faceCounts.forEach((fc, index) => {\n            numFaceVerts += fc * (index + 3);\n        });\n        return numFaceVerts;\n    }\n    /**\n     * Returns the number of vertices indexed by this face\n     * @param faceIndex - The faceIndex value.\n     * @return - The return value.\n     */\n    getFaceVertexCount(faceIndex) {\n        let idx = 0;\n        let count = 0;\n        this.faceCounts.some((fc, index) => {\n            idx += fc;\n            if (idx > faceIndex) {\n                count = index + 3;\n                return true;\n            }\n            return false;\n        });\n        return count;\n    }\n    getFaceVertexOffset(faceIndex) {\n        let idx = 0;\n        let offset = 0;\n        this.faceCounts.some((fc, index) => {\n            if (idx + fc > faceIndex) {\n                offset += (faceIndex - idx) * (index + 3);\n                return true;\n            }\n            idx += fc;\n            offset += fc * (index + 3);\n            return false;\n        });\n        return offset;\n    }\n    /**\n     * The setFaceVertexIndices method.\n     * @param faceIndex - The faceIndex value.\n     * @param vertexIndices - The array of vertex indices for this face value.\n     */\n    setFaceVertexIndices(faceIndex, vertexIndices) {\n        const faceVertexCount = this.getFaceVertexCount(faceIndex);\n        if (vertexIndices.length != faceVertexCount) {\n            throw new Error(`Invalid indices for face:${faceIndex} vertexIndices:${vertexIndices}. Expected ${faceVertexCount} indices`);\n        }\n        const offset = this.getFaceVertexOffset(faceIndex);\n        this.faceVertexIndices.set(vertexIndices, offset);\n    }\n    /**\n     * Adds a new face to the mesh\n     * @param vertexIndices - The vertex indices of the face.\n     * @return - The index of the face in the mesh.\n     */\n    addFace(vertexIndices) {\n        const faceCounts = [...this.faceCounts];\n        if (faceCounts.length <= vertexIndices.length - 3) {\n            for (let i = faceCounts.length; i < vertexIndices.length - 3; i++)\n                faceCounts[i] = 0;\n            faceCounts[vertexIndices.length - 3] = 1;\n        }\n        else {\n            faceCounts[vertexIndices.length - 3]++;\n        }\n        this.setFaceCounts(faceCounts);\n        // Calculate the offset in the faceVertexIndices of this new face.\n        let faceIndex = 0;\n        let offset = 0;\n        this.faceCounts.some((fc, index) => {\n            if (index + 3 == vertexIndices.length) {\n                faceIndex += fc - 1;\n                offset += (fc - 1) * (index + 3);\n                return true;\n            }\n            faceIndex += fc;\n            offset += fc * (index + 3);\n            return false;\n        });\n        this.faceVertexIndices.set(vertexIndices, offset);\n        return faceIndex;\n    }\n    /**\n     * Returns the vertex indices of the specified face.\n     * @param faceIndex - The index of the specified face\n     * @return - An array of indices into the vertex attributes\n     */\n    getFaceVertexIndices(faceIndex) {\n        const vertexIndices = [];\n        const offset = this.getFaceVertexOffset(faceIndex);\n        const count = this.getFaceVertexCount(faceIndex);\n        for (let i = 0; i < count; i++) {\n            vertexIndices.push(this.faceVertexIndices[offset + i]);\n        }\n        return vertexIndices;\n    }\n    /**\n     * Returns a single vertex index for a given face and faceVertex.\n     * @param faceIndex - The faceIndex value.\n     * @param faceVertex - The face vertex is the index within the face. So the first vertex index is 0.\n     * @return - The vertex index\n     */\n    getFaceVertexIndex(faceIndex, faceVertex) {\n        const offset = this.getFaceVertexOffset(faceIndex);\n        return this.faceVertexIndices[offset + faceVertex];\n    }\n    // ///////////////////////////\n    // Face Attributes\n    /**\n     * The addFaceAttribute method.\n     * @param name - The name of the face attribute to add.\n     * @param attr - The attr value\n     */\n    addFaceAttribute(name, attr) {\n        attr.setCount(this.getNumFaces());\n        this.__faceAttributes.set(name, attr);\n        return attr;\n    }\n    /**\n     * The hasFaceAttribute method.\n     * @param name - The name of the face attribute.\n     * @return - The return value.\n     */\n    hasFaceAttribute(name) {\n        return this.__faceAttributes.has(name);\n    }\n    /**\n     * The getFaceAttribute method.\n     * @param name - The name of the face attribute.\n     * @return - The return value.\n     */\n    getFaceAttribute(name) {\n        return this.__faceAttributes.get(name);\n    }\n    // /////////////////////////\n    // Edge Attributes\n    /**\n     * The addEdgeAttribute method.\n     * @param name - The name of the edge attribute to add.\n     * @param attr - The attr value\n     */\n    addEdgeAttribute(name, attr) {\n        attr.setCount(this.numEdges);\n        this.__edgeAttributes.set(name, attr);\n    }\n    /**\n     * The hasEdgeAttribute method.\n     * @param name - The name of the edge attribute.\n     * @return - The return value.\n     */\n    hasEdgeAttribute(name) {\n        return this.__edgeAttributes.has(name);\n    }\n    /**\n     * The getEdgeAttribute method.\n     * @param name - The name of the edge attribute.\n     * @return - The return value.\n     */\n    getEdgeAttribute(name) {\n        return this.__edgeAttributes.get(name);\n    }\n    // ///////////////////////////\n    /**\n     * The genTopologyInfo method.\n     */\n    genTopologyInfo() {\n        let connectedVertices = {}; // acceleration structure.\n        this.vertexEdges = []; // 2d array of vertex to edges.\n        // this.vertexFaces = []; // 2d array of vertex to faces.\n        this.edgeFaces = []; // flat array of 2 face indices per edge\n        this.edgeVerts = []; // flat array of 2 vert indices per edge\n        this.faceEdges = []; // the edges bordering each face.\n        this.numEdges = 0;\n        const positions = this.positions;\n        const getEdgeIndex = (v0, v1) => {\n            let tmp0 = v0;\n            let tmp1 = v1;\n            if (tmp1 < tmp0) {\n                const tmp = tmp0;\n                tmp0 = tmp1;\n                tmp1 = tmp;\n            }\n            const key = tmp0 + '>' + tmp1;\n            if (key in connectedVertices) {\n                // console.log(key + ':' + connectedVertices[key] + \" face:\" + ( v0 < v1 ? 0 : 1) );\n                return connectedVertices[key];\n            }\n            const p0 = positions.getValue(tmp0);\n            const p1 = positions.getValue(tmp1);\n            const edgeVec = p1.subtract(p0);\n            const edgeIndex = this.edgeFaces.length / 2;\n            const edgeData = {\n                edgeIndex: edgeIndex,\n                edgeVec: edgeVec,\n            };\n            connectedVertices[key] = edgeData;\n            this.edgeFaces.push(-1);\n            this.edgeFaces.push(-1);\n            this.edgeVerts.push(tmp0);\n            this.edgeVerts.push(tmp1);\n            // console.log(key + ':' + connectedVertices[key] + \" face:\" + ( v0 < v1 ? 0 : 1));\n            this.numEdges++;\n            return edgeData;\n        };\n        const addEdge = (v0, v1, faceIndex) => {\n            // console.log('addEdge:' + v0 + \" :\" + v1 + \" faceIndex:\" + faceIndex );\n            const edgeData = getEdgeIndex(v0, v1);\n            const edgeIndex = edgeData.edgeIndex;\n            if (v1 < v0) {\n                const edgeFaceIndex = edgeIndex * 2 + 0;\n                if (this.__logTopologyWarnings && this.edgeFaces[edgeFaceIndex] != -1)\n                    console.warn('Edge poly 0 already set. Mesh is non-manifold.');\n                this.edgeFaces[edgeFaceIndex] = faceIndex;\n            }\n            else {\n                const edgeFaceIndex = edgeIndex * 2 + 1;\n                if (this.__logTopologyWarnings && this.edgeFaces[edgeFaceIndex] != -1)\n                    console.warn('Edge poly 1 already set. Mesh is non-manifold.');\n                this.edgeFaces[edgeFaceIndex] = faceIndex;\n            }\n            if (!(faceIndex in this.faceEdges))\n                this.faceEdges[faceIndex] = [];\n            this.faceEdges[faceIndex].push(edgeIndex);\n            // Push the edge index onto both vertex edge lists.\n            // We use Sets to avoid adding the same edge 2x to the same vertex.\n            if (this.vertexEdges[v0] == undefined) {\n                this.vertexEdges[v0] = new Set();\n            }\n            if (this.vertexEdges[v1] == undefined) {\n                this.vertexEdges[v1] = new Set();\n            }\n            this.vertexEdges[v0].add(edgeIndex);\n            this.vertexEdges[v1].add(edgeIndex);\n            // if (this.vertexFaces[v0] == undefined) {\n            //     this.vertexFaces[v0] = [];\n            // }\n            // this.vertexFaces[v0].push(faceIndex);\n        };\n        const numFaces = this.getNumFaces();\n        for (let faceIndex = 0; faceIndex < numFaces; faceIndex++) {\n            const faceVerts = this.getFaceVertexIndices(faceIndex);\n            for (let j = 0; j < faceVerts.length; j++) {\n                const v0 = faceVerts[j];\n                const v1 = faceVerts[(j + 1) % faceVerts.length];\n                addEdge(v0, v1, faceIndex);\n            }\n        }\n    }\n    /**\n     * Computes a normal value per face by averaging the triangle normals of the face.\n     */\n    computeFaceNormals() {\n        const positions = this.positions;\n        const faceNormals = new Vec3f8Attribute();\n        this.addFaceAttribute('normals', faceNormals);\n        const numFaces = this.getNumFaces();\n        for (let faceIndex = 0; faceIndex < numFaces; faceIndex++) {\n            const faceVerts = this.getFaceVertexIndices(faceIndex);\n            const p0 = positions.getValue(faceVerts[0]);\n            const p1 = positions.getValue(faceVerts[1]);\n            let prev = p1;\n            const faceNormal = new Vec3();\n            for (let j = 2; j < faceVerts.length; j++) {\n                const pn = positions.getValue(faceVerts[j]);\n                const v0 = prev.subtract(p0);\n                const v1 = pn.subtract(p0);\n                faceNormal.addInPlace(v0.cross(v1).normalize());\n                prev = pn;\n            }\n            if (faceNormal.lengthSquared() < Number.EPSILON) ;\n            else {\n                faceNormals.setValue(faceIndex, faceNormal.normalize());\n            }\n        }\n    }\n    /**\n     * Calculates the angles at each edge between the adjoining faces\n     */\n    calculateEdgeAngles() {\n        if (this.vertexEdges.length == 0)\n            this.genTopologyInfo();\n        this.computeFaceNormals();\n        const positions = this.positions;\n        const faceNormals = this.getFaceAttribute('normals');\n        this.edgeVecs = [];\n        this.edgeAngles = new Float32Array(this.numEdges);\n        for (let i = 0; i < this.edgeFaces.length; i += 2) {\n            const v0 = this.edgeVerts[i];\n            const v1 = this.edgeVerts[i + 1];\n            const edgeVec = positions.getValue(v1).subtract(positions.getValue(v0));\n            edgeVec.normalizeInPlace();\n            this.edgeVecs.push(edgeVec);\n            const p0 = this.edgeFaces[i];\n            const p1 = this.edgeFaces[i + 1];\n            if (p0 == -1 || p1 == -1) {\n                // Flag the edge as a border edge....\n                this.edgeAngles[i / 2] = Math.PI * 2.0;\n                continue;\n            }\n            const n0 = faceNormals.getValue(p0);\n            const n1 = faceNormals.getValue(p1);\n            this.edgeAngles[i / 2] = n0.angleTo(n1);\n        }\n    }\n    /**\n     * Compute vertex normals.\n     * @param hardAngle - The hardAngle value in radians.\n     * @return - The return value.\n     */\n    computeVertexNormals(hardAngle = 1.0 /* radians */) {\n        this.calculateEdgeAngles();\n        const faceNormals = this.getFaceAttribute('normals');\n        const normalsAttr = new Vec3f8Attribute();\n        this.addVertexAttribute('normals', normalsAttr);\n        // these methods are faster versions than using the methods\n        // provided on the attributes. We cache values and use hard coded constants.\n        // const faceNormalsBuffer = faceNormals.data.buffer\n        const getFaceNormal = (index) => {\n            return faceNormals.getValue(index);\n        };\n        const setVertexNormal = (index, value) => {\n            normalsAttr.setValue(index, value);\n        };\n        const getConnectedEdgeVecs = (faceIndex, vertexIndex) => {\n            let e0;\n            let e1;\n            const faceEdges = this.faceEdges[faceIndex];\n            for (const e of faceEdges) {\n                if (this.edgeVerts[e * 2] == vertexIndex) {\n                    if (!e0)\n                        e0 = this.edgeVecs[e];\n                    else\n                        e1 = this.edgeVecs[e];\n                }\n                else if (this.edgeVerts[e * 2 + 1] == vertexIndex) {\n                    if (!e0)\n                        e0 = this.edgeVecs[e];\n                    else\n                        e1 = this.edgeVecs[e];\n                }\n            }\n            return [e0, e1];\n        };\n        for (let i = 0; i < this.vertexEdges.length; i++) {\n            // If this face indexing doesn't start at 0, then the vertexEdges don't either.\n            if (this.vertexEdges[i] == undefined)\n                continue;\n            const edges = this.vertexEdges[i];\n            // Groups of faces having a smooth normal at the current vertex.\n            const faceGroups = [];\n            const addFaceToGroup = (face) => {\n                let inGroup = false;\n                for (const faceGroup of faceGroups) {\n                    inGroup = faceGroup.includes(face);\n                    if (inGroup)\n                        break;\n                }\n                if (!inGroup)\n                    faceGroups.push([face]);\n            };\n            for (const e of edges) {\n                const f0 = this.edgeFaces[e * 2];\n                const f1 = this.edgeFaces[e * 2 + 1];\n                if (f0 != -1 && f1 != -1 && this.edgeAngles[e] < hardAngle) {\n                    // if (f0 != -1 && f1 == -1 && this.edgeAngles[e] < hardAngle) {\n                    let f0groupIndex = -1;\n                    let f1groupIndex = -1;\n                    for (let groupIndex = 0; groupIndex < faceGroups.length; groupIndex++) {\n                        if (f0groupIndex == -1 && faceGroups[groupIndex].includes(f0))\n                            f0groupIndex = groupIndex;\n                        if (f1groupIndex == -1 && faceGroups[groupIndex].includes(f1))\n                            f1groupIndex = groupIndex;\n                    }\n                    if (f0groupIndex == -1 && f1groupIndex == -1) {\n                        faceGroups.push([f0, f1]);\n                    }\n                    else if (f0groupIndex != -1 && f1groupIndex != -1) {\n                        if (f0groupIndex != f1groupIndex) {\n                            // Merge the 2 groups that the smooth edge joins.\n                            faceGroups[f0groupIndex] = faceGroups[f0groupIndex].concat(faceGroups[f1groupIndex]);\n                            faceGroups.splice(f1groupIndex, 1);\n                        }\n                    }\n                    else {\n                        if (f0groupIndex == -1) {\n                            faceGroups[f1groupIndex].push(f0);\n                        }\n                        if (f1groupIndex == -1) {\n                            faceGroups[f0groupIndex].push(f1);\n                        }\n                    }\n                    continue;\n                }\n                // This is a hard edge or a border edge... Add faces separately group.\n                if (f0 != -1)\n                    addFaceToGroup(f0);\n                if (f1 != -1)\n                    addFaceToGroup(f1);\n            }\n            // Sort the groups to have the biggest group first.\n            faceGroups.sort((a, b) => (a.length < b.length ? 1 : a.length > b.length ? -1 : 0));\n            let firstVertex = true;\n            for (const faceGroup of faceGroups) {\n                const normal = new Vec3();\n                for (const faceIndex of faceGroup) {\n                    const faceEdges = getConnectedEdgeVecs(faceIndex, i);\n                    let weight;\n                    if (faceEdges[0] && faceEdges[1]) {\n                        weight = faceEdges[0].angleTo(faceEdges[1]);\n                        normal.addInPlace(getFaceNormal(faceIndex).scale(weight));\n                    }\n                    else {\n                        console.warn('variable weight is undefined because faceEdges[0] or faceEdges[1] is undefined');\n                    }\n                    // if (i == 1)\n                    //     console.log(\"FaceNormal:\" + faceIndex + \":\" + getFaceNormal(faceIndex).toString());\n                }\n                normal.normalizeInPlace();\n                if (firstVertex) {\n                    setVertexNormal(i, normal);\n                    firstVertex = false;\n                }\n                else {\n                    normalsAttr.setSplitVertexValues(i, faceGroup, normal.asArray());\n                }\n            }\n        }\n        return normalsAttr;\n    }\n    /**\n     * The computeHardEdgesIndices method.\n     * @param hardAngle - The hardAngle value in radians.\n     * @return - The return value.\n     */\n    computeHardEdgesIndices(hardAngle = 1.0) {\n        if (this.edgeVerts.length == 0)\n            this.calculateEdgeAngles();\n        const hardEdges = [];\n        const addEdge = (index) => {\n            hardEdges.push(this.edgeVerts[index]);\n            hardEdges.push(this.edgeVerts[index + 1]);\n        };\n        for (let i = 0; i < this.edgeAngles.length; i++) {\n            if (this.edgeAngles[i] > hardAngle) {\n                addEdge(i * 2);\n            }\n        }\n        return Uint32Array.from(hardEdges);\n    }\n    /**\n     * Merges a separate geometry into this one. Similar to a 'union' boolean operation.\n     * @param other the other geom that will be merged into this one\n     * @param xfo the transformation to be applied to the other geom as it is merged in.\n     */\n    merge(other, xfo = new Xfo()) {\n        const prevNumVerts = this.getNumVertices();\n        super.merge(other, xfo);\n        const otherFaceVertexIndices = other.faceVertexIndices;\n        const faceVertexIndices = new Uint32Array(this.faceVertexIndices.length + otherFaceVertexIndices.length);\n        const otherFaceCounts = other.getFaceCounts();\n        let indexOffset = 0;\n        let otherIndexOffset = 0;\n        let mergedIndexOffset = 0;\n        const numCounts = Math.max(this.faceCounts.length, otherFaceCounts.length);\n        for (let i = 0; i < numCounts; i++) {\n            if (this.faceCounts.length > i) {\n                // Add 'this' indices\n                const numIndicesThis = this.faceCounts[i] * (i + 3);\n                faceVertexIndices.set(this.faceVertexIndices.slice(indexOffset, indexOffset + numIndicesThis), mergedIndexOffset);\n                indexOffset += numIndicesThis;\n                mergedIndexOffset += numIndicesThis;\n            }\n            if (otherFaceCounts.length > i) {\n                // Add the 'other' indices\n                const numIndicesOther = otherFaceCounts[i] * (i + 3);\n                faceVertexIndices.set(otherFaceVertexIndices\n                    .slice(otherIndexOffset, otherIndexOffset + numIndicesOther)\n                    .map((index) => index + prevNumVerts), mergedIndexOffset);\n                otherIndexOffset += numIndicesOther;\n                mergedIndexOffset += numIndicesOther;\n                if (this.faceCounts.length == i)\n                    this.faceCounts[i] = 0;\n                this.faceCounts[i] += otherFaceCounts[i];\n            }\n        }\n        this.faceVertexIndices = faceVertexIndices;\n        // Note: the merge does not correctly merge split values, as it is quite complex\n        // and we don't have time now. We can come back to this, but the splits system is overly complex\n        // and we can probably re-write.\n        // for (const [attrName, attr] of this.__vertexAttributes) {\n        //   const otherAttr = other.getVertexAttribute(attrName)\n        //   if (otherAttr) {\n        //     const thisSplits = attr.getSplits()\n        //     const otherSplits = otherAttr.getSplits()\n        //     // for (let key in otherSplits) {\n        //     //   thisSplits[key] = otherSplits[key]\n        //     // }\n        //   }\n        // }\n    }\n    // ////////////////////////////////////////\n    // Rendering\n    /**\n     * The genBuffers method.\n     * @param opts - The opts value.\n     * @return - The return value.\n     */\n    genBuffers(opts) {\n        // Compute the normals on demand.\n        // if (!('normals' in this.__vertexAttributes)) {\n        //     // this.geom.computeVertexNormals();\n        //     this.addVertexAttribute(\"normals\", Vec3, 0.0);\n        // }\n        const splitIndices = {};\n        let splitCount = 0;\n        for (const [, attr] of this.__vertexAttributes) {\n            const attrSplits = attr.getSplits();\n            for (const polygon in attrSplits) {\n                if (!(polygon in splitIndices))\n                    splitIndices[polygon] = {};\n                const vertices = attrSplits[polygon];\n                for (const v in vertices) {\n                    const vertex = parseInt(v);\n                    if (!(vertex in splitIndices[polygon])) {\n                        splitIndices[polygon][vertex] = splitCount;\n                        splitCount++;\n                    }\n                }\n            }\n        }\n        const positions = this.positions;\n        const numUnSplitVertices = positions.getCount();\n        const totalNumVertices = numUnSplitVertices + splitCount;\n        let indices;\n        if (!opts || opts.includeIndices != false) {\n            indices = this.generateTriangulatedIndices(totalNumVertices, numUnSplitVertices, splitIndices);\n        }\n        // let maxIndex;\n        // if (debugAttrValues)\n        //     maxIndex = Math.max(...indices);\n        const attrBuffers = {};\n        for (const [attrName, attr] of this.__vertexAttributes) {\n            let values;\n            if (splitCount == 0)\n                values = attr.asArray();\n            else\n                values = attr.generateSplitValues(splitIndices, splitCount);\n            const dimension = attr.stride;\n            const count = values.length / dimension;\n            // if (debugAttrValues) {\n            //     if (count <= maxIndex)\n            //         console.warn(\"Invalid indexing. Attr value is insufficient for indexing:\" + attrName + \". Max Index:\" + maxIndex + \" Attr Size:\" + count);\n            // }\n            attrBuffers[attrName] = {\n                values: values,\n                count: count,\n                dimension: dimension,\n                normalized: attrName == 'normals',\n                dataType: attr.getDataTypeName(),\n            };\n        }\n        const result = {\n            numVertices: this.numVertices(),\n            numRenderVerts: totalNumVertices,\n            indices,\n            attrBuffers,\n        };\n        /* Disabled during TS migration.\n        if (opts && opts.includeVertexNeighbors) {\n          if (this.vertexEdges == undefined) this.genTopologyInfo()\n    \n          let count = 0\n          for (let i = 0; i < this.vertexEdges.length; i++) {\n            // If this face indexing doesn't start at 0, then the vertexEdges don't either.\n            if (this.vertexEdges[i]) count += this.vertexEdges[i].size\n          }\n          // The array will be structured as a start+offset for each vertex, followed\n          // by a 2d array of neighbor indices.\n          const vertexNeighbors = new Uint32Array(this.vertexEdges.length * 2 + count)\n          const sortFanEdges = (fanEdges: any) => {\n            for (let i = 0; i < fanEdges.length; i++) {\n              const feA = fanEdges[i]\n              for (let j = 0; j < i; j++) {\n                const feB = fanEdges[j]\n                if (feA[0] != -1 && feA[0] == feB[1]) {\n                  //  move feA after feB;\n                  if (i != j + 1) {\n                    fanEdges.splice(i, 1)\n                    fanEdges.splice(j + 1, 0, feA)\n                  }\n                  break\n                }\n                if (feA[1] != -1 && feA[1] == feB[0]) {\n                  //  move feA before feB;\n                  fanEdges.splice(i, 1)\n                  fanEdges.splice(j, 0, feA)\n                  break\n                }\n              }\n            }\n          }\n          const checkFanEdges = (fanEdges: any) => {\n            // now check that the faces all build a fan. Maybe starting and ending with -1\n            if (fanEdges[0][0] == -1 || fanEdges[fanEdges.length - 1][1] == -1) {\n              if (fanEdges[0][0] != -1 || fanEdges[fanEdges.length - 1][1] != -1) {\n                throw new Error('If fan starts with -1, it must also end with -1')\n              }\n            }\n            for (let i = 0; i < fanEdges.length; i++) {\n              const fe = fanEdges[i]\n              if (fe[0] == -1 || fe[1] == -1) {\n                if (i != 0 && i != fanEdges.length - 1) {\n                  throw new Error('-1 only allowed at the beginning and end of a fan.')\n                }\n              }\n              if (fe[0] != -1) {\n                let prev = i - 1\n                if (prev < 0) prev += fanEdges.length\n                if (fe[0] != fanEdges[prev][1]) {\n                  throw new Error('Faces are not sequential')\n                }\n              }\n              if (fe[1] != -1) {\n                const next = (i + 1) % fanEdges.length\n                if (fe[1] != fanEdges[next][0]) {\n                  throw new Error('Faces are not sequential')\n                }\n              }\n            }\n          }\n    \n          // Populate the start and offset values.\n          let offset = this.vertexEdges.length * 2\n          for (let i = 0; i < this.vertexEdges.length; i++) {\n            if (this.vertexEdges[i] == undefined) continue\n            const edges = this.vertexEdges[i]\n    \n            // Build a sorted list of faces based on a fan around\n            // the vertex.\n            const fanEdges = []\n            for (const e of edges) {\n              const v0 = this.edgeVerts[e * 2]\n              const v1 = this.edgeVerts[e * 2 + 1]\n              let f0 = this.edgeFaces[e * 2]\n              let f1 = this.edgeFaces[e * 2 + 1]\n              let neigVert\n              if (v0 == i) {\n                neigVert = v1\n              } else if (v1 == i) {\n                neigVert = v0\n                // swap the faces\n                const tmp = f0\n                f0 = f1\n                f1 = tmp\n              } else {\n                throw new Error('Invalid topology')\n              }\n              fanEdges.push([f0, f1, neigVert])\n            }\n            sortFanEdges(fanEdges)\n            checkFanEdges(fanEdges)\n            const closed = fanEdges[0][0] != -1 || fanEdges[fanEdges.length - 1][1] != -1\n            let flags = 0\n            if (closed) flags += 1\n            vertexNeighbors[i * 2] = offset\n            vertexNeighbors[i * 2 + 1] = edges.size + (flags << 8)\n            for (const fe of fanEdges) {\n              vertexNeighbors[offset] = fe[2]\n              offset++\n            }\n          }\n          ;(result as any).vertexNeighbors = vertexNeighbors\n        }\n        */\n        return result;\n    }\n    /**\n     * Compute the number of triangles. For higher degree polygons, they are divided into multiple triangles for rendering.\n     * @return - Returns the number of triangles.\n     */\n    computeNumTriangles() {\n        let numVertsPerFace = 3;\n        let trisCount = 0;\n        for (const fc of this.faceCounts) {\n            trisCount += fc * (numVertsPerFace - 2);\n            numVertsPerFace++;\n        }\n        return trisCount;\n    }\n    /**\n     * To prepare data for rendering, the indices for the polygons is used to compute a new index buffer based on\n     * only triangles. This is used during rendering and the resulting indices uploaded ot the GPU  by GLMesh class.\n     *\n     * @param totalNumVertices - The total number of vertices.\n     * @param numUnSplitVertices - The total number of un-split vertices.\n     * @param splitIndices - The splitIndices value.\n     * @return - Returns a typed array containing the triangulated indices.\n     */\n    generateTriangulatedIndices(totalNumVertices, numUnSplitVertices, splitIndices) {\n        const trisCount = this.computeNumTriangles();\n        let triangulatedIndices;\n        if (totalNumVertices < Math.pow(2, 8))\n            triangulatedIndices = new Uint8Array(trisCount * 3);\n        else if (totalNumVertices < Math.pow(2, 16))\n            triangulatedIndices = new Uint16Array(trisCount * 3);\n        else\n            triangulatedIndices = new Uint32Array(trisCount * 3);\n        let triangleVertex = 0;\n        const addTriangleVertexIndex = function (vertex, faceIndex) {\n            if (vertex in splitIndices && faceIndex in splitIndices[vertex])\n                vertex = numUnSplitVertices + splitIndices[vertex][faceIndex];\n            triangulatedIndices[triangleVertex] = vertex;\n            triangleVertex++;\n        };\n        const numFaces = this.getNumFaces();\n        for (let faceIndex = 0; faceIndex < numFaces; faceIndex++) {\n            const faceVerts = this.getFaceVertexIndices(faceIndex);\n            for (let j = 0; j < faceVerts.length; j++) {\n                if (j >= 3) {\n                    // For each additional triangle, we have to add 2 indices.\n                    addTriangleVertexIndex(faceVerts[0], faceIndex);\n                    addTriangleVertexIndex(faceVerts[j - 1], faceIndex);\n                }\n                addTriangleVertexIndex(faceVerts[j], faceIndex);\n            }\n        }\n        return triangulatedIndices;\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * Restores mesh properties from a binary reader.\n     *\n     * @param reader - The reader value.\n     * @param context - The context value.\n     */\n    readBinary(reader, context) {\n        super.loadBaseGeomBinary(reader, context);\n        this.setFaceCounts(Array.from(reader.loadUInt32Array()));\n        const numFaces = this.getNumFaces();\n        // Note: we can remove this. We can infer this from the above faceCounts array.\n        // Do not clone the data, as its 'scratch memory' in any case.\n        // We can avoid a lot of unnecessary temporary allocaiton by using shared buffers.\n        const faceVertexCounts = reader.loadUInt8Array(numFaces, false);\n        const offsetRange = reader.loadSInt32Vec2();\n        const bytes = reader.loadUInt8();\n        let faceVertexIndexDeltas;\n        if (bytes == 1)\n            faceVertexIndexDeltas = reader.loadUInt8Array(undefined, false);\n        else if (bytes == 2)\n            faceVertexIndexDeltas = reader.loadUInt16Array(undefined, false);\n        else if (bytes == 4)\n            faceVertexIndexDeltas = reader.loadUInt32Array(undefined, false);\n        else {\n            throw Error('faceVertexIndexDeltas undefined');\n        }\n        // ///////////////////////////////////////////////////\n        // Note: The Mesh compression system needs a thorough review.\n        // The C++ classes are not storing face indices in a sorted manner.\n        // So quads precede triangles in the indexing, which isn't supposed to happen.\n        // We should force the C++ code to store quads and triangles in order.\n        // e.g. implement the 'addFace' method in C++ so it automatically does this.\n        let numFaceVerts = 3;\n        let offset = 0;\n        const faceOffsetsByCount = this.faceCounts.map((fc, index) => {\n            const result = offset;\n            offset += fc * numFaceVerts;\n            numFaceVerts++;\n            return result;\n        });\n        let srcOffset = 0;\n        let prevCount = 0;\n        const faceOffsets = [];\n        for (let faceIndex = 0; faceIndex < numFaces; faceIndex++) {\n            const fc = faceVertexCounts[faceIndex];\n            const offset = faceOffsetsByCount[fc];\n            const count = fc + 3;\n            faceOffsets[faceIndex] = offset;\n            for (let j = 0; j < count; j++) {\n                const srcFaceVertex = srcOffset + j;\n                const faceVertex = offset + j;\n                const delta = faceVertexIndexDeltas[srcFaceVertex] + offsetRange.x;\n                if (faceIndex == 0)\n                    this.faceVertexIndices[faceVertex] = delta;\n                else {\n                    let prevFaceVertex = faceOffsets[faceIndex - 1];\n                    prevFaceVertex += j < prevCount ? j : prevCount - 1;\n                    this.faceVertexIndices[faceVertex] = this.faceVertexIndices[prevFaceVertex] + delta;\n                }\n            }\n            srcOffset += count;\n            faceOffsetsByCount[fc] += count;\n            prevCount = count;\n        }\n        if (!this.hasVertexAttribute('normals')) {\n            this.computeVertexNormals();\n        }\n        // this.computeVertexNormals();\n        this.emit('geomDataChanged');\n    }\n    /**\n     * The toJSON method encodes this type as a json object for persistence.\n     *\n     * @param context - The context value.\n     * @return - Returns the json object.\n     */\n    toJSON(context) {\n        const j = super.toJSON(context);\n        if (!context || !context.skipTopology) {\n            j.faceCounts = Array.from(this.faceCounts);\n            j.faceVertexIndices = Array.from(this.faceVertexIndices);\n        }\n        return j;\n    }\n    /**\n     * The fromJSON method decodes a json object for this type.\n     *\n     * e.g. to load data into the mesh class, provide a json structure similar to the following.\n     * Note: faceCounts is an array of count values, starting with the number of triangles, then the number of quads. See #setFaceCounts\n     * The faceVertexIndices array should also be sorted to contain all the triangles first, followed by the quads, and then the pentagons etc..\n     * ```json\n     * // This code will define a mesh made up of 2 triangles and then a quad.\n     * const mesh = new Mesh()\n     * mesh.fromJSON({\n     *   faceCounts:[2, 1],\n     *   faceVertexIndices: [0, 1, 2, 0, 2, 3, 3, 2, 4, 5],\n     *   numVertices: 6,\n     *   vertexAttributes: {\n     *     positions: {\n     *       dataType: 'Vec3'\n     *       defaultScalarValue: 0.0,\n     *       data: [0,0,0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 2, 1, 0, 2, 0, 0]\n     *     }\n     *   }\n     * }\n     * ```\n     *\n     * @param j - The json object this item must decode.\n     * @param context - The context value.\n     */\n    fromJSON(j, context) {\n        super.fromJSON(j, context);\n        if (j.faceCounts)\n            this.faceCounts = j.faceCounts;\n        if (j.faceVertexIndices)\n            this.faceVertexIndices = Uint32Array.from(j.faceVertexIndices);\n    }\n}\nRegistry.register('Mesh', Mesh);\n\n/** ProxyGeometries are pupulated from data unpacked using a webworker while loading zcad files.\n * These geometries represent readonly geometries with very basic topologies.\n * @private\n */\nclass BaseProxy extends RefCounted {\n    name;\n    buffers;\n    boundingBox;\n    numVertices = 0;\n    libraryIndex = -1;\n    /**\n     * Create a base proxy.\n     * @param data - The data value.\n     */\n    constructor(data) {\n        super();\n        if (data) {\n            this.name = data.name;\n            this.buffers = data.geomBuffers;\n            this.boundingBox = new Box3();\n            this.boundingBox.p0.fromJSON(data.bbox.p0);\n            this.boundingBox.p1.fromJSON(data.bbox.p1);\n            this.numVertices = this.buffers.numVertices;\n        }\n    }\n    get positions() {\n        return this.buffers.attrBuffers['positions'];\n    }\n    /**\n     * Returns the number of vertex attributes.\n     *\n     * @return - The return value.\n     */\n    getNumVertices() {\n        return this.numVertices;\n    }\n    /**\n     * Returns the bounding box for geometry.\n     * @return - The return value.\n     */\n    getBoundingBox() {\n        return this.boundingBox;\n    }\n    /**\n     * The genBuffers method.\n     * @return - The return value.\n     */\n    genBuffers() {\n        return this.buffers;\n    }\n    /**\n     * Once the buffers have been uploaded to the GPU, we are free to release them.\n     * The GLGeomLibrary may call this function to let the geometry know it can release any handles.\n     */\n    freeBuffers() {\n        for (const attrName in this.buffers.attrBuffers) {\n            const attrData = this.buffers.attrBuffers[attrName];\n            attrData.values = null;\n        }\n        if (this.buffers.indices) {\n            this.buffers.indices = null;\n        }\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * The toJSON method encodes this type as a json object for persistence.\n     *\n     * @param context - The context value.\n     * @return - Returns the json object.\n     */\n    toJSON(context) {\n        const json = {\n            geomBuffers: this.buffers,\n        };\n        return json;\n    }\n    /**\n     * The fromJSON method decodes a json object for this type.\n     *\n     * @param json - The json object this item must decode.\n     * @param context - The context value.\n     */\n    fromJSON(json, context) {\n        this.buffers = json.geomBuffers;\n    }\n    copyFrom(src, context) {\n        this.buffers = { ...src.buffers };\n        this.name = src.name;\n        this.boundingBox = src.boundingBox;\n        this.numVertices = this.buffers.numVertices;\n    }\n}\n/** Class representing a points proxy.\n * @extends BaseProxy\n * @private\n */\nclass PointsProxy extends BaseProxy {\n    /**\n     * Create a points proxy.\n     * @param data - The data value.\n     */\n    constructor(data) {\n        super(data);\n    }\n}\n/** Class representing a lines proxy.\n * @extends BaseProxy\n * @private\n */\nclass LinesProxy extends BaseProxy {\n    numLineSegments = 0;\n    /**\n     * Create a lines proxy.\n     * @param data - The data value.\n     */\n    constructor(data) {\n        super(data);\n        if (data) {\n            this.numLineSegments = this.buffers.indices.length / 2;\n        }\n    }\n    /**\n     * Returns the number line segments in this lines proxy geometry\n     *\n     * @return - The return value.\n     */\n    getNumLineSegments() {\n        return this.numLineSegments;\n    }\n    /**\n     * The clone method constructs a new LinesProxy, copies its values\n     * from this item and returns it.\n     *\n     * @param context - The CloneContext param.\n     * @return - The cloned instance.\n     */\n    clone(context) {\n        const cloned = new LinesProxy();\n        cloned.copyFrom(this, context);\n        return cloned;\n    }\n    copyFrom(src, context) {\n        super.copyFrom(src, context);\n        this.numLineSegments = this.buffers.indices.length / 2;\n    }\n}\n/** Class representing a mesh proxy.\n * @extends BaseProxy\n * @private\n */\nclass MeshProxy extends BaseProxy {\n    numTriangles = 0;\n    /**\n     * Create a mesh proxy.\n     * @param data - The data value.\n     */\n    constructor(data) {\n        super(data);\n        if (data) {\n            this.numTriangles = this.buffers.indices.length / 3;\n        }\n    }\n    /**\n     * Returns the number of triangles in this mesh proxy geometry.\n     *\n     * @return - The return value.\n     */\n    getNumTriangles() {\n        return this.numTriangles;\n    }\n    /**\n     * The clone method constructs a new MeshProxy, copies its values\n     * from this item and returns it.\n     *\n     * @param context - The CloneContext param.\n     * @return - The cloned instance.\n     */\n    clone(context) {\n        const cloned = new MeshProxy();\n        cloned.copyFrom(this, context);\n        return cloned;\n    }\n    copyFrom(src, context) {\n        super.copyFrom(src, context);\n        this.numTriangles = this.buffers.indices.length / 3;\n    }\n}\n\nclass SubGeom extends ParameterOwner {\n}\nRegistry.register('SubGeom', SubGeom);\n/**\n * Class representing a compound geom made up of multiple sub geometries that all share a common vertex buffer.\n *\n * ```\n * const compoundGeom = new CompoundGeom()\n * ```\n */\nclass CompoundGeom extends BaseProxy {\n    materials = [];\n    subGeoms = [];\n    counts;\n    materialGroupsDirty = false;\n    /**\n     * Create points.\n     */\n    constructor(data, materialLibrary) {\n        super(data);\n        if (data) {\n            this.counts = data.geomBuffers.counts;\n            // Now use the indices in the geom to look up the actual materials\n            // that will be used in rendering.\n            const materials = materialLibrary.getMaterials();\n            data.geomBuffers.materialLibraryIndices.forEach((materialIndex, index) => {\n                this.materials[index] = materials[materialIndex];\n            });\n            delete data.geomBuffers.materialLibraryIndices;\n            this.buffers.materials = this.materials;\n        }\n    }\n    /**\n     * Returns the number of faces, edges and point sub-geoms in this compound geom.\n     *\n     * @return - The return value.\n     */\n    getNumSubGeoms() {\n        return this.buffers.numSubGeoms;\n    }\n    /**\n     * Returns the number of Face sub-geoms in this compound geom.\n     *\n     * @return - The return value.\n     */\n    getNumFaces() {\n        return this.buffers.subGeomCounts['TRIANGLES'].length;\n    }\n    /**\n     * Returns the number of Edge sub-geoms in this compound geom.\n     *\n     * @return - The return value.\n     */\n    getNumEdges() {\n        return this.buffers.subGeomCounts['LINES'].length;\n    }\n    /**\n     * Returns the number of triangles in this compound geom.\n     *\n     * @return - The return value.\n     */\n    getNumTriangles() {\n        return this.counts['TRIANGLES'] / 3;\n    }\n    /**\n     * Returns the number line segments in this lines proxy geometry\n     *\n     * @return - The return value.\n     */\n    getNumLineSegments() {\n        return this.counts['LINES'] / 2;\n    }\n    /**\n     * Returns the number line segments in this lines proxy geometry\n     *\n     * @return - The return value.\n     */\n    getNumPoints() {\n        return this.counts['POINTS'];\n    }\n    // ////////////////////////////////////////\n    // Materials\n    getSubGeomMaterial(subGeomId) {\n        // Note: subGeomMaterialIndices is Uint8Array, and 0 means no custom\n        // material is assigned to the subGeom.\n        // Subtract 1 to get the actual material id.\n        const materialIndex = this.buffers.subGeomMaterialIndices[subGeomId] - 1;\n        if (materialIndex == -1)\n            return undefined;\n        return this.materials[materialIndex];\n    }\n    /**\n     * Assigns a material to a sub-geom by ID;\n     * @param subGeomId - The ID of the sub-geom to assign the material.\n     * @param material - The material to assign.\n     */\n    setSubGeomMaterial(subGeomId, material) {\n        if (!material) {\n            if (this.buffers.subGeomMaterialIndices && this.buffers.subGeomMaterialIndices[subGeomId])\n                this.buffers.subGeomMaterialIndices[subGeomId] = 0;\n        }\n        else {\n            let materialIndex = this.materials.indexOf(material);\n            if (materialIndex == -1) {\n                materialIndex = this.materials.length;\n                this.materials[materialIndex] = material;\n            }\n            if (this.buffers.subGeomMaterialIndices.length == 0) {\n                this.buffers.subGeomMaterialIndices = new Uint8Array(this.buffers.numSubGeoms);\n            }\n            // Note: Zero 4 started assigning many material to compound geom faces. (More than 256)\n            // We must upgrade to 16 bit indices.\n            if (this.materials.length > 255 && this.buffers.subGeomMaterialIndices instanceof Uint8Array) {\n                const subGeomMaterialIndices = new Uint16Array(this.buffers.numSubGeoms);\n                for (let i = 0; i < this.buffers.subGeomMaterialIndices.length; i++) {\n                    subGeomMaterialIndices[i] = this.buffers.subGeomMaterialIndices[i];\n                }\n                this.buffers.subGeomMaterialIndices = subGeomMaterialIndices;\n            }\n            // Note: subGeomMaterialIndices is Uint8Array, and 0 means no custom\n            // material is assigned to the subGeom.\n            // Subtract 1 to get the actual material id.\n            this.buffers.subGeomMaterialIndices[subGeomId] = materialIndex + 1;\n        }\n        this.materialGroupsDirty = true;\n        this.emit('materialsChanged');\n    }\n    /**\n     * Assigns a material to a sub-geom by ID;\n     * @deprecated\n     * Please use: setSubGeomMaterial\n     * @param subGeomId - The ID of the sub-geom to assign the material.\n     * @param material - The material to assign.\n     */\n    assignSubGeomMaterial(subGeomId, material) {\n        this.setSubGeomMaterial(subGeomId, material);\n    }\n    /**\n     * Clears all sub--geom material assignments. This means the geometry will be drawn\n     * using only the material of the GeomItem or CADBody.\n     */\n    clearMaterials() {\n        this.materials.splice(0, this.materials.length);\n        this.buffers.subGeomMaterialIndices = this.buffers.subGeomMaterialIndices.map(() => 0);\n        this.emit('materialsChanged');\n    }\n    /**\n     * Each subgeom may be a assigned a different material.\n     *\n     * We calculate groups that enable multiple subgeoms to\n     * be rendered at once using the same material id.\n     * Note: this is an optimization that only applies when\n     * rendering geoms in non-shattered mode.\n     */\n    calcMaterialGroups() {\n        const materialSubGeoms = {};\n        if (this.buffers.subGeomMaterialIndices.length == 0) {\n            this.buffers.materialSubGeoms = {};\n            let offset = 0;\n            for (let key in this.buffers.counts) {\n                const count = this.buffers.counts[key];\n                if (count > 0) {\n                    this.buffers.materialSubGeoms[key] = [\n                        {\n                            materialId: -1,\n                            offset,\n                            count,\n                        },\n                    ];\n                }\n                offset += count;\n            }\n            return;\n        }\n        // /////////////////////////////////\n        // Material Groups\n        let offset = 0;\n        let currMaterial = -99;\n        let currMaterialSubGeom = null;\n        for (let i = 0; i < this.buffers.numSubGeoms; i++) {\n            let key;\n            let subGeomOffset = 0;\n            if (i < this.buffers.subGeomCounts.TRIANGLES.length) {\n                if (!materialSubGeoms.TRIANGLES)\n                    materialSubGeoms.TRIANGLES = [];\n                key = 'TRIANGLES';\n            }\n            else if (i < this.buffers.subGeomCounts.TRIANGLES.length + this.buffers.subGeomCounts.LINES.length) {\n                subGeomOffset = this.buffers.subGeomCounts.TRIANGLES.length;\n                key = 'LINES';\n                if (!materialSubGeoms.LINES)\n                    materialSubGeoms.LINES = [];\n            }\n            else {\n                subGeomOffset = this.buffers.subGeomCounts.TRIANGLES.length + this.buffers.subGeomCounts.LINES.length;\n                key = 'POINTS';\n                if (!materialSubGeoms.POINTS)\n                    materialSubGeoms.POINTS = [];\n            }\n            const materialId = this.buffers.subGeomMaterialIndices[i];\n            if (currMaterial != materialId) {\n                currMaterial = materialId;\n                // Note: subGeomMaterialIndices is Uint8Array, and 0 means no custom\n                // material is assigned to the subGeom.\n                // Subtract 1 to get the actual material id.\n                currMaterialSubGeom = {\n                    materialId: materialId - 1,\n                    offset,\n                    count: 0,\n                };\n                for (; i < this.buffers.numSubGeoms; i++) {\n                    if (currMaterial != this.buffers.subGeomMaterialIndices[i]) {\n                        break;\n                    }\n                    // When we get to the end og this geom type (e.g .TRIANGLES)\n                    // start a new subgeom.\n                    if (i - subGeomOffset == this.buffers.subGeomCounts[key].length) {\n                        // Force the material index to be reset on line 162 above.\n                        currMaterial = -99;\n                        break;\n                    }\n                    currMaterialSubGeom.count += this.buffers.subGeomCounts[key][i - subGeomOffset];\n                }\n                offset += currMaterialSubGeom.count;\n                materialSubGeoms[key].push(currMaterialSubGeom);\n                i--;\n            }\n        }\n        this.buffers.materialSubGeoms = materialSubGeoms;\n    }\n    /**\n     * The genBuffers method.\n     * @return - The return value.\n     */\n    genBuffers() {\n        if (this.materialGroupsDirty)\n            this.calcMaterialGroups();\n        return this.buffers;\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * The toJSON method encodes this type as a json object for persistence.\n     *\n     * @param context - The context value.\n     * @return - Returns the json object.\n     */\n    toJSON(context) {\n        const json = {\n            // geomBuffers: this.buffers,\n            materialPaths: this.materials.map((material) => material.path),\n        };\n        return json;\n    }\n    /**\n     * The fromJSON method decodes a json object for this type.\n     *\n     * @param json - The json object this item must decode.\n     * @param context - The context value.\n     */\n    fromJSON(json, context) {\n        this.counts = json.geomBuffers.counts;\n        // this.buffers = json.geomBuffers\n        if (json.materialPaths && context) {\n            const materialPaths = json.materialPaths;\n            this.materials = [];\n            materialPaths.forEach((path, index) => {\n                context.resolvePath(path, (result) => {\n                    if (result instanceof Material)\n                        this.materials[index] = result;\n                }, () => { });\n            });\n        }\n        this.buffers.materials = this.materials;\n        this.materialGroupsDirty = true;\n    }\n    /**\n     * Sets state of current geometry(Including line segments) using a binary reader object.\n     *\n     * @param reader - The reader value.\n     * @param context - The context value.\n     */\n    loadMetadata(metadataReader, context) {\n        const toc = metadataReader.loadUInt32Array();\n        toc.forEach((offset, index) => {\n            const subGeom = new SubGeom();\n            metadataReader.seek(offset);\n            subGeom.readBinary(metadataReader, context);\n            this.subGeoms[index] = subGeom;\n        });\n    }\n    /**\n     * The clone method constructs a new CompoundGeom, copies its values\n     * from this item and returns it.\n     *\n     * @param context - The CloneContext param.\n     * @return - The cloned instance.\n     */\n    clone(context) {\n        const cloned = new CompoundGeom();\n        cloned.copyFrom(this, context);\n        return cloned;\n    }\n    /**\n     * Copies current TreeItem with all its children.\n     *\n     * @param src - The tree item to copy from.\n     * @param context - The context value.\n     */\n    copyFrom(src, context) {\n        super.copyFrom(src, context);\n        this.buffers = { ...src.buffers };\n        if (this.buffers.subGeomMaterialIndices) {\n            this.buffers.subGeomMaterialIndices = new Uint8Array(this.buffers.numSubGeoms);\n            this.buffers.subGeomMaterialIndices.set(src.buffers.subGeomMaterialIndices);\n        }\n        this.counts = src.counts;\n        this.materials = src.materials;\n        this.buffers.materials = this.materials;\n        this.subGeoms = src.subGeoms;\n        this.libraryIndex = src.libraryIndex;\n    }\n}\nRegistry.register('CompoundGeom', CompoundGeom);\n\n/**\n * Base Class for procedural points generated by mathematical functions.\n *\n * @extends {Points}\n */\nclass ProceduralPoints extends Points {\n    dirtyTopology;\n    dirtyVertices;\n    topologyParams;\n    /**\n     * Creates an instance of ProceduralPoints.\n     */\n    constructor() {\n        super();\n        this.dirtyTopology = true;\n        this.dirtyVertices = true;\n        // Parameters that specify topology settings.\n        // Add parameters to this list to ensure the topology is recomputed.\n        // All other param changes will only trigger a resize\n        this.topologyParams = [];\n    }\n    /**\n     * This method can be overridden in derived classes\n     * to perform general updates (see GLPass or BaseItem).\n     * @param event - The event object emitted by the parameter.\n     * @private\n     */\n    parameterValueChanged(event) {\n        this.setBoundingBoxDirty();\n        if (this.topologyParams.includes(event.param.getName())) {\n            this.dirtyTopology = true;\n            this.emit('geomDataTopologyChanged');\n        }\n        else {\n            this.dirtyVertices = true;\n            this.setBoundingBoxDirty();\n            // Let the renderer know that the geometry has changed and must be re-uploaded to the GPU.\n            this.emit('geomDataChanged');\n        }\n        super.parameterValueChanged(event);\n    }\n    /**\n     * If the Procedural geometry is out of date, for example if a parameter has been changed,\n     * this method explicitly forces the geometry to be recomputed.\n     */\n    update() {\n        if (this.dirtyTopology) {\n            this.rebuild();\n            this.dirtyTopology = false;\n            this.dirtyVertices = false;\n            this.rebuild();\n        }\n        else if (this.dirtyVertices) {\n            this.dirtyVertices = false;\n            this.resize();\n            this.dirtyVertices = false;\n        }\n    }\n    /**\n     * Returns the bounding box for geometry.\n     * @return - The return value.\n     */\n    getBoundingBox() {\n        this.update();\n        return super.getBoundingBox();\n    }\n    /**\n     * Returns the number of vertex attributes.\n     *\n     * @return - The return value.\n     */\n    getNumVertices() {\n        this.update();\n        return super.getNumVertices();\n    }\n    // ////////////////////////////////////////\n    // Rendering\n    /**\n     * The genBuffers method.\n     * @param opts - The opts value.\n     * @return - The return value.\n     */\n    genBuffers(opts) {\n        this.update();\n        return super.genBuffers(opts);\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * The toJSON method encodes this type as a json object for persistence.\n     *\n     * @param context - The context value.\n     * @return - Returns the json object.\n     */\n    toJSON(context) {\n        if (!context)\n            context = {};\n        context.skipTopology = true;\n        context.skipAttributes = ['positions', 'normals', 'texCoords'];\n        const j = super.toJSON(context);\n        context.skipTopology = false;\n        context.skipAttributes = [];\n        return j;\n    }\n}\n\n/**\n * Base Class for procedural lines generated by mathematical functions.\n *\n * @extends {Lines}\n */\nclass ProceduralLines extends Lines {\n    dirtyTopology;\n    dirtyVertices;\n    topologyParams;\n    /**\n     * Creates an instance of ProceduralLines.\n     */\n    constructor() {\n        super();\n        this.dirtyTopology = true;\n        this.dirtyVertices = true;\n        // Parameters that specify topology settings.\n        // Add parameters to this list to ensure the topology is recomputed.\n        // All other param changes will only trigger a resize\n        this.topologyParams = [];\n    }\n    /**\n     * This method can be overridden in derived classes\n     * to perform general updates (see GLPass or BaseItem).\n     * @param event - The event object emitted by the parameter.\n     * @private\n     */\n    parameterValueChanged(event) {\n        this.setBoundingBoxDirty();\n        if (this.topologyParams.includes(event.param.getName())) {\n            this.dirtyTopology = true;\n            this.emit('geomDataTopologyChanged');\n        }\n        else {\n            this.dirtyVertices = true;\n            this.setBoundingBoxDirty();\n            // Let the renderer know that the geometry has changed and must be re-uploaded to the GPU.\n            this.emit('geomDataChanged');\n        }\n        super.parameterValueChanged(event);\n    }\n    /**\n     * If the Procedural geometry is out of date, for example if a parameter has been changed,\n     * this method explicitly forces the geometry to be recomputed.\n     */\n    update() {\n        if (this.dirtyTopology) {\n            this.rebuild();\n            this.dirtyTopology = false;\n            this.dirtyVertices = false;\n            this.rebuild();\n        }\n        else if (this.dirtyVertices) {\n            this.resize();\n            this.dirtyVertices = false;\n            this.resize();\n        }\n    }\n    /**\n     * Returns the bounding box for geometry.\n     * @return - The return value.\n     */\n    getBoundingBox() {\n        this.update();\n        return super.getBoundingBox();\n    }\n    /**\n     * Returns the number of vertex attributes.\n     *\n     * @return - The return value.\n     */\n    getNumVertices() {\n        this.update();\n        return super.getNumVertices();\n    }\n    // ////////////////////////////////////////\n    // Rendering\n    /**\n     * The genBuffers method.\n     * @param opts - The opts value.\n     * @return - The return value.\n     */\n    genBuffers(opts) {\n        this.update();\n        return super.genBuffers();\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * The toJSON method encodes this type as a json object for persistence.\n     *\n     * @param context - The context value.\n     * @return - Returns the json object.\n     */\n    toJSON(context) {\n        if (!context)\n            context = {};\n        context.skipTopology = true;\n        context.skipAttributes = ['positions', 'normals', 'texCoords'];\n        const j = super.toJSON(context);\n        context.skipTopology = false;\n        context.skipAttributes = [];\n        return j;\n    }\n}\n\n/**\n * Base Class for procedural meshes generated by mathematical functions.\n *\n * @extends {Mesh}\n */\nclass ProceduralMesh extends Mesh {\n    dirtyTopology;\n    dirtyVertices;\n    topologyParams;\n    /**\n     * Creates an instance of ProceduralMesh.\n     */\n    constructor() {\n        super();\n        this.dirtyTopology = true;\n        this.dirtyVertices = true;\n        // Parameters that specify topology settings.\n        // Add parameters to this list to ensure the topology is recomputed.\n        // All other param changes will only trigger a resize\n        this.topologyParams = [];\n    }\n    /**\n     * This method can be overridden in derived classes\n     * to perform general updates (see GLPass or BaseItem).\n     * @param event - The event object emitted by the parameter.\n     * @private\n     */\n    parameterValueChanged(event) {\n        this.setBoundingBoxDirty();\n        if (this.topologyParams.includes(event.param.getName())) {\n            this.dirtyTopology = true;\n            this.emit('geomDataTopologyChanged');\n        }\n        else {\n            this.dirtyVertices = true;\n            this.setBoundingBoxDirty();\n            // Let the renderer know that the geometry has changed and must be re-uploaded to the GPU.\n            this.emit('geomDataChanged');\n        }\n        super.parameterValueChanged(event);\n    }\n    /**\n     * If the Procedural geometry is out of date, for example if a parameter has been changed,\n     * this method explicitly forces the geometry to be recomputed.\n     */\n    update() {\n        if (this.dirtyTopology) {\n            // Clear the topology so that vertex normals can be recomputed.\n            this.vertexEdges = [];\n            this.dirtyTopology = false;\n            this.dirtyVertices = false;\n            this.rebuild();\n        }\n        else if (this.dirtyVertices) {\n            this.dirtyVertices = false;\n            this.resize();\n        }\n    }\n    /**\n     * Returns the bounding box for geometry.\n     * @return - The return value.\n     */\n    getBoundingBox() {\n        this.update();\n        return super.getBoundingBox();\n    }\n    /**\n     * Returns the number of vertex attributes.\n     *\n     * @return - The return value.\n     */\n    getNumVertices() {\n        this.update();\n        return super.getNumVertices();\n    }\n    /**\n     * Compute vertex normals.\n     * @param hardAngle - The hardAngle value in radians.\n     * @return - The return value.\n     */\n    computeVertexNormals(hardAngle = 1.0 /* radians */) {\n        this.update();\n        return super.computeVertexNormals(hardAngle);\n    }\n    /**\n     * The computeHardEdgesIndices method.\n     * @param hardAngle - The hardAngle value in radians.\n     * @return - The return value.\n     */\n    computeHardEdgesIndices(hardAngle = 1.0) {\n        this.update();\n        return super.computeHardEdgesIndices(hardAngle);\n    }\n    // ////////////////////////////////////////\n    // Rendering\n    /**\n     * The genBuffers method.\n     * @param opts - The opts value.\n     * @return - The return value.\n     */\n    genBuffers(opts) {\n        this.update();\n        return super.genBuffers(opts);\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * The toJSON method encodes this type as a json object for persistence.\n     *\n     * @param context - The context value.\n     * @return - Returns the json object.\n     */\n    toJSON(context) {\n        if (!context)\n            context = {};\n        context.skipTopology = true;\n        context.skipAttributes = ['positions', 'normals', 'texCoords'];\n        const j = super.toJSON(context);\n        context.skipTopology = false;\n        context.skipAttributes = [];\n        return j;\n    }\n}\n\n/**\n * Represents an ordered grid of points along `X` and `Y` axes.\n *\n * ```\n * const pointGrid = new PointGrid(2.2, 1.5, 12, 12)\n * ```\n *\n * **Parameters**\n * * **X(`NumberParameter`):** Length of the grid along the `X` axis.\n * * **Y(`NumberParameter`):** Length of the grid along the `Y` axis.\n * * **XDivisions(`NumberParameter`):** Number of divisions along `X` axis\n * * **YDivisions(`NumberParameter`):** Number of divisions along `Y` axis\n * @extends {ProceduralPoints}\n */\nclass PointGrid extends ProceduralPoints {\n    /**\n     * @member sizeXParam - Length of the grid along the `X` axis.\n     */\n    sizeXParam = new NumberParameter('SizeX', 1.0, [0, Number.MAX_VALUE]);\n    /**\n     * @member sizeYParam - Length of the grid along the `Y` axis.\n     */\n    sizeYParam = new NumberParameter('SizeY', 1.0, [0, Number.MAX_VALUE]);\n    /**\n     * @member divisionsXParam - Number of divisions along `X` axis\n     */\n    divisionsXParam = new NumberParameter('XDivisions', 1, [0, Number.MAX_VALUE], 1);\n    /**\n     * @member divisionsYParam - Number of divisions along `Y` axis\n     */\n    divisionsYParam = new NumberParameter('YDivisions', 1, [0, Number.MAX_VALUE], 1);\n    /**\n     * Creates an instance of PointGrid.\n     *\n     * @param x - The length of the point grid along the X axis.\n     * @param y - The length of the point grid along the Y axis.\n     * @param xDivisions - The number of divisions along the X axis.\n     * @param yDivisions - The number of divisions along the Y axis.\n     * @param addTextureCoords - The addTextureCoords value.\n     */\n    constructor(x = 1.0, y = 1.0, xDivisions = 1, yDivisions = 1) {\n        super();\n        this.topologyParams = [];\n        if (isNaN(x) || isNaN(y) || isNaN(xDivisions) || isNaN(yDivisions))\n            throw new Error('Invalid geom args');\n        this.addParameter(this.sizeXParam);\n        this.addParameter(this.sizeYParam);\n        this.addParameter(this.divisionsXParam);\n        this.addParameter(this.divisionsYParam);\n        this.sizeXParam.value = x;\n        this.sizeYParam.value = y;\n        this.divisionsXParam.value = xDivisions;\n        this.divisionsYParam.value = yDivisions;\n        this.topologyParams.push('XDivisions');\n        this.topologyParams.push('YDivisions');\n    }\n    /**\n     * The rebuild method.\n     * @private\n     */\n    rebuild() {\n        const xDivisions = Math.round(this.divisionsXParam.value);\n        const yDivisions = Math.round(this.divisionsYParam.value);\n        this.setNumVertices(xDivisions * yDivisions);\n        const texCoords = this.getVertexAttribute('texCoords');\n        if (texCoords) {\n            for (let i = 0; i < yDivisions; i++) {\n                const y = i / (yDivisions - 1);\n                for (let j = 0; j < xDivisions; j++) {\n                    const x = j / (xDivisions - 1);\n                    texCoords.setValue(i * xDivisions + j, new Vec2(x, y));\n                }\n            }\n        }\n        this.resize();\n    }\n    /**\n     * The resize method.\n     * @private\n     */\n    resize() {\n        const xDivisions = Math.round(this.divisionsXParam.value);\n        const yDivisions = Math.round(this.divisionsYParam.value);\n        const x = this.sizeXParam.value;\n        const y = this.sizeYParam.value;\n        const positions = this.positions;\n        if (!positions)\n            return;\n        for (let i = 0; i < yDivisions; i++) {\n            const newY = (i / (yDivisions - 1) - 0.5) * y;\n            for (let j = 0; j < xDivisions; j++) {\n                const newX = (j / (xDivisions - 1) - 0.5) * x;\n                positions.setValue(i * xDivisions + j, new Vec3(newX, newY, 0.0));\n            }\n        }\n    }\n}\nRegistry.register('PointGrid', PointGrid);\n\n/**\n * A class for generating a rectangle shape.\n *\n * ```\n * const rect = new Rect(1.5, 2.0)\n * ```\n *\n * **Parameters**\n * * **X(`NumberParameter`):** Length of the rectangle along the `X` axis.\n * * **Y(`NumberParameter`):** Length of the rectangle along the `Y` axis.\n *\n *\n * @extends {ProceduralLines}\n */\nclass Rect extends ProceduralLines {\n    /**\n     * @member sizeXParam - Length of the rectangle along the `X` axis.\n     */\n    sizeXParam = new NumberParameter('SizeX', 1.0, [0, Number.MAX_VALUE]);\n    /**\n     * @member sizeYParam - Length of the rectangle along the `Y` axis.\n     */\n    sizeYParam = new NumberParameter('SizeY', 1.0, [0, Number.MAX_VALUE]);\n    /**\n     * Create a rect.\n     * @param x - The length of the rect along the `X` axis.\n     * @param y - The length of the rect along the `Y` axis.\n     */\n    constructor(x = 1.0, y = 1.0) {\n        super();\n        if (isNaN(x) || isNaN(y))\n            throw new Error('Invalid geom args');\n        this.addParameter(this.sizeXParam);\n        this.addParameter(this.sizeYParam);\n        this.sizeXParam.value = x;\n        this.sizeYParam.value = y;\n        this.rebuild();\n    }\n    /**\n     * The rebuild method.\n     * @private\n     */\n    rebuild() {\n        this.setNumVertices(4);\n        this.setNumSegments(4);\n        this.setSegmentVertexIndices(0, 0, 1);\n        this.setSegmentVertexIndices(1, 1, 2);\n        this.setSegmentVertexIndices(2, 2, 3);\n        this.setSegmentVertexIndices(3, 3, 0);\n        // @ts-expect-error ts-migrate(2554) FIXME: Expected 0 arguments, but got 1.\n        this.resize(false);\n    }\n    /**\n     * The resize method.\n     * @private\n     */\n    resize() {\n        const x = this.sizeXParam.value;\n        const y = this.sizeYParam.value;\n        const positions = this.positions;\n        if (!positions)\n            return;\n        positions.setValue(0, new Vec3(-0.5 * x, -0.5 * y, 0.0));\n        positions.setValue(1, new Vec3(0.5 * x, -0.5 * y, 0.0));\n        positions.setValue(2, new Vec3(0.5 * x, 0.5 * y, 0.0));\n        positions.setValue(3, new Vec3(-0.5 * x, 0.5 * y, 0.0));\n    }\n}\nRegistry.register('Rect', Rect);\n\n/**\n * A class for generating a circle shape using line segments.\n *\n * ```\n * const circle = new Circle(2.2, 12)\n * ```\n *\n * **Parameters**\n * * **Radius(`NumberParameter`):** Radius of the circle.\n * * **Angle(`NumberParameter`):** Number of segments used to build the circle.\n * * **Sides(`NumberParameter`):** Segments angle in radiants.\n *\n * @extends {ProceduralLines}\n */\nclass Circle extends ProceduralLines {\n    /**\n     * @member angleParam - TODO\n     */\n    angleParam = new AngleParameter('Angle', Math.PI * 2, [0, Math.PI * 2]);\n    /**\n     * @member sidesParam - The number of sides that compose the circle (e.g. 3 creates a triangle)\n     */\n    sidesParam = new NumberParameter('Sides', 6, [0, Number.MAX_VALUE], 1);\n    /**\n     * @member radiusParam - The radius of the circle\n     */\n    radiusParam = new NumberParameter('Radius', 1, [0, Number.MAX_VALUE]);\n    /**\n     * Creates an instance of Circle.\n     * @param radius - The radius of the circle.\n     * @param sides - The number of segments.\n     * @param angle - Arc segments angle(radians)\n     */\n    constructor(radius = 1.0, sides = 32, angle = Math.PI * 2) {\n        super();\n        this.topologyParams = [];\n        if (isNaN(radius) || isNaN(sides))\n            throw new Error('Invalid geom args');\n        this.radiusParam.value = radius;\n        this.sidesParam.value = sides;\n        this.angleParam.value = angle;\n        this.addParameter(this.radiusParam);\n        this.addParameter(this.angleParam);\n        this.addParameter(this.sidesParam);\n        // Note: Changes in Angle can cause the Topoloty to become closed/unclosed.\n        this.topologyParams.push('Angle');\n        this.topologyParams.push('Sides');\n    }\n    /**\n     * The rebuild method.\n     * @private\n     */\n    rebuild() {\n        const angle = this.angleParam.value;\n        const sides = Math.round(this.sidesParam.value);\n        const arc = angle < Math.PI * 2;\n        const numVerts = arc ? sides + 1 : sides;\n        this.setNumVertices(numVerts);\n        this.setNumSegments(sides);\n        for (let i = 0; i < sides; i++)\n            this.setSegmentVertexIndices(i, i, (i + 1) % numVerts);\n        this.resize();\n    }\n    /**\n     * The resize method.\n     * @private\n     */\n    resize() {\n        const radius = this.radiusParam.value;\n        const angle = this.angleParam.value;\n        const arc = angle < Math.PI * 2;\n        const step = angle / (arc ? this.positions.count - 1 : this.positions.count);\n        for (let i = 0; i < this.positions.count; i++) {\n            this.positions.setValue(i, new Vec3(Math.cos(step * i) * radius, Math.sin(step * i) * radius, 0.0));\n        }\n    }\n}\nRegistry.register('Circle', Circle);\n\n/**\n * A class for generating a cross shape, drawing a line on the `X,Y,Z` axes.\n * The axis line length is the `size` you specify, but the middle of the line is positioned in the coordinate `(0, 0, 0)` .\n * Meaning that half of the line goes negative and half goes positive.\n *\n * ```\n * const cross = new Cross(1.5)\n * ```\n *\n * **Parameters**\n * * **Size(`NumberParameter`):** Specifies the size of the cross.\n *\n * @extends {ProceduralLines}\n */\nclass Cross extends ProceduralLines {\n    /**\n     * @member sizeParam - Specifies the size of the cross.\n     */\n    sizeParam = new NumberParameter('Size', 1.0, [0, Number.MAX_VALUE]);\n    /**\n     * Create a cross.\n     * @param size - The size of the cross.\n     */\n    constructor(size = 1.0) {\n        super();\n        if (isNaN(size))\n            throw new Error('Invalid geom args');\n        this.addParameter(this.sizeParam);\n        this.sizeParam.value = size;\n    }\n    /**\n     * The rebuild method.\n     * @private\n     */\n    rebuild() {\n        this.setNumVertices(6);\n        this.setNumSegments(3);\n        this.setSegmentVertexIndices(0, 0, 1);\n        this.setSegmentVertexIndices(1, 2, 3);\n        this.setSegmentVertexIndices(2, 4, 5);\n        this.resize();\n    }\n    /**\n     * The resize method.\n     * @private\n     */\n    resize() {\n        const size = this.sizeParam.value;\n        const positions = this.positions;\n        if (!positions)\n            return;\n        positions.setValue(0, new Vec3(-0.5 * size, 0, 0));\n        positions.setValue(1, new Vec3(0.5 * size, 0, 0));\n        positions.setValue(2, new Vec3(0, 0.5 * size, 0));\n        positions.setValue(3, new Vec3(0, -0.5 * size, 0));\n        positions.setValue(4, new Vec3(0, 0, 0.5 * size));\n        positions.setValue(5, new Vec3(0, 0, -0.5 * size));\n    }\n}\nRegistry.register('Cross', Cross);\n\n/**\n * A class for generating a lines cuboid shape(Without faces).\n *\n * **Parameters**\n * * **X(`NumberParameter`):** Length of the line cuboid along the `X` axis\n * * **Y(`NumberParameter`):** Length of the line cuboid along the `Y` axis\n * * **Z(`NumberParameter`):** Length of the line cuboid along the `Z` axis\n * * **BaseZAtZero(`NumberParameter`):** Property to start or not `Z` axis from position `0.\n *\n * @extends {ProceduralLines}\n */\nclass LinesCuboid extends ProceduralLines {\n    /**\n     * @member baseZAtZeroParam - Property to start or not `Z` axis from position `0.\n     */\n    baseZAtZeroParam = new BooleanParameter('BaseZAtZero', false);\n    /**\n     * @member sizeXParam - Length of the line cuboid along the `X` axis\n     */\n    sizeXParam = new NumberParameter('SizeX', 1, [0, Number.MAX_VALUE]);\n    /**\n     * @member sizeYParam - Length of the line cuboid along the `Y` axis\n     */\n    sizeYParam = new NumberParameter('SizeY', 1, [0, Number.MAX_VALUE]);\n    /**\n     * @member sizeZParam - Length of the line cuboid along the `Z` axis\n     */\n    sizeZParam = new NumberParameter('SizeZ', 1, [0, Number.MAX_VALUE]);\n    /**\n     * Create a lines cuboid.\n     * @param x - The length of the line cuboid along the X axis.\n     * @param y - The length of the line cuboid along the Y axis.\n     * @param z - The length of the line cuboid along the Z axis.\n     * @param baseZAtZero - The baseZAtZero value.\n     */\n    constructor(x = 1.0, y = 1.0, z = 1.0, baseZAtZero = false) {\n        super();\n        this.addParameter(this.sizeXParam);\n        this.addParameter(this.sizeYParam);\n        this.addParameter(this.sizeZParam);\n        this.addParameter(this.baseZAtZeroParam);\n        this.sizeXParam.value = x;\n        this.sizeYParam.value = y;\n        this.sizeZParam.value = z;\n        this.baseZAtZeroParam.value = baseZAtZero;\n    }\n    /**\n     * The rebuild method.\n     * @private\n     */\n    rebuild() {\n        this.setNumVertices(8);\n        this.setNumSegments(12);\n        this.setSegmentVertexIndices(0, 0, 1);\n        this.setSegmentVertexIndices(1, 1, 2);\n        this.setSegmentVertexIndices(2, 2, 3);\n        this.setSegmentVertexIndices(3, 3, 0);\n        this.setSegmentVertexIndices(4, 4, 5);\n        this.setSegmentVertexIndices(5, 5, 6);\n        this.setSegmentVertexIndices(6, 6, 7);\n        this.setSegmentVertexIndices(7, 7, 4);\n        this.setSegmentVertexIndices(8, 0, 4);\n        this.setSegmentVertexIndices(9, 1, 5);\n        this.setSegmentVertexIndices(10, 2, 6);\n        this.setSegmentVertexIndices(11, 3, 7);\n        this.resize();\n    }\n    /**\n     * The resize method.\n     *\n     * @private\n     */\n    resize() {\n        const x = this.sizeXParam.value;\n        const y = this.sizeYParam.value;\n        const z = this.sizeZParam.value;\n        const baseZAtZero = this.baseZAtZeroParam.value;\n        const positions = this.positions;\n        if (positions) {\n            let zoff = 0.5;\n            if (baseZAtZero)\n                zoff = 1.0;\n            positions.setValue(0, new Vec3(0.5 * x, -0.5 * y, zoff * z));\n            positions.setValue(1, new Vec3(0.5 * x, 0.5 * y, zoff * z));\n            positions.setValue(2, new Vec3(-0.5 * x, 0.5 * y, zoff * z));\n            positions.setValue(3, new Vec3(-0.5 * x, -0.5 * y, zoff * z));\n            zoff = -0.5;\n            if (baseZAtZero)\n                zoff = 0.0;\n            positions.setValue(4, new Vec3(0.5 * x, -0.5 * y, zoff * z));\n            positions.setValue(5, new Vec3(0.5 * x, 0.5 * y, zoff * z));\n            positions.setValue(6, new Vec3(-0.5 * x, 0.5 * y, zoff * z));\n            positions.setValue(7, new Vec3(-0.5 * x, -0.5 * y, zoff * z));\n        }\n    }\n}\nRegistry.register('LinesCuboid', LinesCuboid);\n\n/**\n * A class for generating a sphere made up of 3 circles, one on each plane: XY, YZ, XZ.\n *\n * ```\n * const linesSphere = new LinesSphere(2.2, 12)\n * ```\n *\n * **Parameters**\n * * **Radius(`NumberParameter`):** Radius of the circle.\n * * **Sides(`NumberParameter`):** Segments angle in radiants.\n *\n * @extends {ProceduralLines}\n */\nclass LinesSphere extends ProceduralLines {\n    /**\n     * @member radiusParam - The radius of the circle\n     */\n    radiusParam = new NumberParameter('Radius', 6, [0, Number.MAX_VALUE]);\n    /**\n     * @member sidesParam - The number of sides that compose the circle (e.g. 3 creates a triangle)\n     */\n    sidesParam = new NumberParameter('Sides', 12, [0, Number.MAX_VALUE], 1);\n    /**\n     * Creates an instance of LinesSphere.\n     * @param radius - The radius of the circle.\n     * @param sides - The number of segments.\n     * @param angle - Arc segments angle(radians)\n     */\n    constructor(radius = 1.0, sides = 32) {\n        super();\n        this.topologyParams = [];\n        if (isNaN(radius) || isNaN(sides))\n            throw new Error('Invalid geom args');\n        this.addParameter(this.radiusParam);\n        this.addParameter(this.sidesParam);\n        this.radiusParam.value = radius;\n        this.sidesParam.value = sides;\n        this.topologyParams.push('Sides');\n    }\n    /**\n     * The rebuild method.\n     * @private\n     */\n    rebuild() {\n        const segs = this.sidesParam.value;\n        const numCirces = 3;\n        this.setNumVertices(segs * numCirces);\n        this.setNumSegments(segs * numCirces);\n        const addSegments = (off) => {\n            for (let i = 0; i < segs; i++)\n                this.setSegmentVertexIndices(i + off, i + off, ((i + 1) % segs) + off);\n        };\n        addSegments(0);\n        addSegments(segs);\n        addSegments(segs * 2);\n        this.resize();\n    }\n    /**\n     * The resize method.\n     * @private\n     */\n    resize() {\n        const radius = this.radiusParam.value;\n        const segs = this.sidesParam.value;\n        const angle = Math.PI * 2;\n        const step = angle / segs;\n        const positions = this.positions;\n        if (positions) {\n            for (let i = 0; i < segs; i++) {\n                positions.setValue(i, new Vec3(Math.cos(step * i) * radius, Math.sin(step * i) * radius, 0.0));\n                positions.setValue(i + segs, new Vec3(Math.cos(step * i) * radius, 0.0, Math.sin(step * i) * radius));\n                positions.setValue(i + segs * 2, new Vec3(0.0, Math.cos(step * i) * radius, Math.sin(step * i) * radius));\n            }\n        }\n    }\n}\nRegistry.register('LinesSphere', LinesSphere);\n\n/**\n * A class for generating a cylinder geometry. It is very much like a cuboid but with `N` number of sides.\n *\n * ```\n * const cylinder = new LinesCylinder(1.5, 2.0, 6)\n * ```\n *\n * **Parameters**\n * * **Radius(`NumberParameter`):** Specifies the radius of the cylinder.\n * * **Height(`NumberParameter`):** Specifies the height of the cone.\n * * **Sides(`NumberParameter`):** Specifies the number of subdivisions around the `Z` axis.\n * * **Loops(`NumberParameter`):** Specifies the number of subdivisions(stacks) on the `Z` axis.\n * * **Caps(`BooleanParameter`):** Specifies whether the ends of the cylinder are capped or open.\n * * **BaseZAtZero(`BooleanParameter`):** Property to start or not `Z` axis from position `0.\n *\n * @extends {ProceduralLines}\n */\nclass LinesCylinder extends ProceduralLines {\n    /**\n     * @member baseZAtZeroParam - Property to start or not `Z` axis from position `0.\n     */\n    baseZAtZeroParam = new BooleanParameter('BaseZAtZero', true);\n    /**\n     * @member heightParam - Specifies the height of the cone.\n     */\n    heightParam = new NumberParameter('Height', 1, [0, Number.MAX_VALUE]);\n    /**\n     * @member radiusParam - Specifies the radius of the cylinder.\n     */\n    radiusParam = new NumberParameter('Radius', 6, [0, Number.MAX_VALUE]);\n    /**\n     * @member loopsParam - Specifies the number of subdivisions(stacks) on the `Z` axis.\n     */\n    loopsParam = new NumberParameter('Loops', 6, [0, Number.MAX_VALUE], 1);\n    /**\n     * @member sidesParam - Specifies the number of subdivisions around the `Z` axis.\n     */\n    sidesParam = new NumberParameter('Sides', 12, [0, Number.MAX_VALUE], 1);\n    /**\n     * Create a cylinder.\n     * @param radius - The radius of the cylinder.\n     * @param height - The height of the cylinder.\n     * @param sides - The number of sides.\n     * @param loops - The number of loops.\n     * @param caps - A boolean indicating whether the ends of the cylinder are capped or open.\n     * @param baseZAtZero - The baseZAtZero value.\n     */\n    constructor(radius = 0.5, height = 1.0, sides = 32, loops = 2, baseZAtZero = false) {\n        super();\n        this.topologyParams = [];\n        if (isNaN(radius) || isNaN(height) || isNaN(sides) || isNaN(loops))\n            throw new Error('Invalid geom args');\n        this.radiusParam.value = radius;\n        this.heightParam.value = height;\n        this.sidesParam.value = sides >= 3 ? sides : 3;\n        this.loopsParam.value = loops >= 2 ? loops : 2;\n        this.baseZAtZeroParam.value = baseZAtZero;\n        this.addParameter(this.radiusParam);\n        this.addParameter(this.heightParam);\n        this.addParameter(this.sidesParam);\n        this.addParameter(this.loopsParam);\n        this.addParameter(this.baseZAtZeroParam);\n        this.topologyParams.push('Sides');\n        this.topologyParams.push('Loops');\n    }\n    /**\n     * The rebuild method.\n     * @private\n     */\n    rebuild() {\n        const nbSides = Math.round(this.sidesParam.value);\n        const nbLoops = Math.round(this.loopsParam.value);\n        let numVertices = nbSides * nbLoops;\n        let numSegments = nbSides * nbLoops + nbLoops; // (verticel lines)\n        this.setNumVertices(numVertices);\n        this.setNumSegments(numSegments);\n        // ////////////////////////////\n        // Build the topology\n        let segIndex = 0;\n        // build the topology for the body of the cylinder\n        for (let i = 0; i < nbLoops; i++) {\n            for (let j = 0; j < nbSides; j++) {\n                const v0 = nbSides * i + j;\n                const v1 = nbSides * i + ((j + 1) % nbSides);\n                this.setSegmentVertexIndices(segIndex++, v0, v1);\n            }\n            // add the line segment that connects this circle to the previous.\n            if (i > 0) {\n                {\n                    const v0 = (i - 1) * nbSides;\n                    const v1 = i * nbSides;\n                    this.setSegmentVertexIndices(segIndex++, v0, v1);\n                }\n                {\n                    const v0 = (i - 1) * nbSides + Math.floor(nbSides * 0.5);\n                    const v1 = i * nbSides + Math.floor(nbSides * 0.5);\n                    this.setSegmentVertexIndices(segIndex++, v0, v1);\n                }\n            }\n        }\n        this.resize();\n    }\n    /**\n     * The resize method.\n     * @private\n     */\n    resize() {\n        const nbSides = Math.round(this.sidesParam.value);\n        const nbLoops = Math.round(this.loopsParam.value);\n        const radius = this.radiusParam.value;\n        const height = this.heightParam.value;\n        const baseZAtZero = this.baseZAtZeroParam.value;\n        let vertex = 0;\n        let zoff = 0.5;\n        if (baseZAtZero)\n            zoff = 0.0;\n        const positions = this.positions;\n        if (positions) {\n            for (let i = 0; i < nbLoops; i++) {\n                const z = (i / (nbLoops - 1)) * height - height * zoff;\n                for (let j = 0; j < nbSides; j++) {\n                    const phi = (j / nbSides) * 2.0 * Math.PI;\n                    positions.setValue(vertex, new Vec3(Math.sin(phi) * radius, Math.cos(phi) * radius, z));\n                    vertex++;\n                }\n            }\n        }\n        this.dirtyTopology = false;\n        this.dirtyVertices = false;\n    }\n}\nRegistry.register('LinesCylinder', LinesCylinder);\n\n/**\n * Represents a network of lines that cross each other to form a series of squares or rectangles.\n *\n * ```\n * const grid = new Grid(5, 5, 50, 50, true)\n * ```\n *\n * **Parameters**\n * * **X(`NumberParameter`):** Length of the grid along the `X` axis.\n * * **Y(`NumberParameter`):** Length of the grid along the `Y` axis.\n * * **XDivisions(`NumberParameter`):** Number of divisions along `X` axis\n * * **YDivisions(`NumberParameter`):** Number of divisions along `Y` axis\n * * **SkipCenterLines(`BooleanParameter`):** Property that indicates whether to display the center grid lines or not\n *\n * @extends {ProceduralLines}\n */\nclass Grid extends ProceduralLines {\n    /**\n     * @member sizeXParam - Length of the grid along the `X` axis.\n     */\n    sizeXParam = new NumberParameter('SizeX', 1.0, [0, Number.MAX_VALUE]);\n    /**\n     * @member sizeYParam - Length of the grid along the `Y` axis.\n     */\n    sizeYParam = new NumberParameter('SizeY', 1.0, [0, Number.MAX_VALUE]);\n    /**\n     * @member divisionsXParam - Number of divisions along `X` axis\n     */\n    divisionsXParam = new NumberParameter('XDivisions', 1, [0, Number.MAX_VALUE], 1);\n    /**\n     * @member divisionsYParam - Number of divisions along `Y` axis\n     */\n    divisionsYParam = new NumberParameter('YDivisions', 1, [0, Number.MAX_VALUE], 1);\n    /**\n     * @member skipCenterLinesParam - Property that indicates whether to display the center grid lines or not\n     */\n    skipCenterLinesParam = new BooleanParameter('SkipCenterLines', false);\n    /**\n     * Create a grid.\n     * @param x - The length of the grid along the `X` axis.\n     * @param y - The length of the grid along the `Y` axis.\n     * @param xDivisions - The number of divisions along `X` axis.\n     * @param yDivisions - The number of divisions along `Y` axis.\n     * @param skipCenterLines - A boolean indicating whether to display the center grid lines or not.\n     */\n    constructor(x = 1.0, y = 1.0, xDivisions = 10, yDivisions = 10, skipCenterLines = false) {\n        super();\n        this.topologyParams = [];\n        if (isNaN(x) || isNaN(y) || isNaN(xDivisions) || isNaN(yDivisions))\n            throw new Error('Invalid geom args');\n        this.addParameter(this.sizeXParam);\n        this.addParameter(this.sizeYParam);\n        this.addParameter(this.divisionsXParam);\n        this.addParameter(this.divisionsYParam);\n        this.addParameter(this.skipCenterLinesParam);\n        this.sizeXParam.value = x;\n        this.sizeYParam.value = y;\n        this.divisionsXParam.value = xDivisions;\n        this.divisionsYParam.value = yDivisions;\n        this.skipCenterLinesParam.value = skipCenterLines;\n        this.topologyParams.push('XDivisions');\n        this.topologyParams.push('YDivisions');\n        this.topologyParams.push('SkipCenterLines');\n    }\n    /**\n     * The rebuild method.\n     * @private\n     */\n    rebuild() {\n        const xDivisions = this.divisionsXParam.value;\n        const yDivisions = this.divisionsYParam.value;\n        const skipCenterLines = this.skipCenterLinesParam.value && xDivisions % 2 == 0 && yDivisions % 2 == 0;\n        this.setNumVertices((xDivisions + yDivisions + 2 - (skipCenterLines ? 1 : 0)) * 2);\n        this.setNumSegments(xDivisions + yDivisions + 2 - (skipCenterLines ? 1 : 0));\n        let idx = 0;\n        for (let i = 0; i <= xDivisions; i++) {\n            if (skipCenterLines && i == xDivisions / 2)\n                continue;\n            const v0 = idx * 2;\n            const v1 = idx * 2 + 1;\n            this.setSegmentVertexIndices(idx, v0, v1);\n            idx++;\n        }\n        for (let i = 0; i <= yDivisions; i++) {\n            if (skipCenterLines && i == xDivisions / 2)\n                continue;\n            const v0 = idx * 2;\n            const v1 = idx * 2 + 1;\n            this.setSegmentVertexIndices(idx, v0, v1);\n            idx++;\n        }\n        this.resize();\n    }\n    /**\n     * The resize method.\n     * @private\n     */\n    resize() {\n        const positions = this.positions;\n        const xDivisions = this.divisionsXParam.value;\n        const yDivisions = this.divisionsYParam.value;\n        const xSize = this.sizeXParam.value;\n        const ySize = this.sizeYParam.value;\n        const skipCenterLines = this.skipCenterLinesParam.value && xDivisions % 2 == 0 && yDivisions % 2 == 0;\n        let idx = 0;\n        for (let i = 0; i <= xDivisions; i++) {\n            if (skipCenterLines && i == xDivisions / 2)\n                continue;\n            const v0 = idx * 2;\n            const v1 = idx * 2 + 1;\n            const x = (i / xDivisions - 0.5) * xSize;\n            if (positions) {\n                positions.setValue(v0, new Vec3(x, -0.5 * ySize, 0.0));\n                positions.setValue(v1, new Vec3(x, 0.5 * ySize, 0.0));\n            }\n            idx++;\n        }\n        for (let i = 0; i <= yDivisions; i++) {\n            if (skipCenterLines && i == xDivisions / 2)\n                continue;\n            const v0 = idx * 2;\n            const v1 = idx * 2 + 1;\n            const y = (i / yDivisions - 0.5) * ySize;\n            if (positions) {\n                positions.setValue(v0, new Vec3(-0.5 * xSize, y, 0.0));\n                positions.setValue(v1, new Vec3(0.5 * xSize, y, 0.0));\n            }\n            idx++;\n        }\n    }\n}\nRegistry.register('Grid', Grid);\n\n/* eslint-disable no-unused-vars */\n/**\n * Represents a cone geometry.\n *\n * ```\n * const cone = new Cone(1.2, 4.0)\n * ```\n *\n * **Parameters**\n * * **Radius(`NumberParameter`):** Specifies the radius of the base of the cone.\n * * **Height(`NumberParameter`):** Specifies the height of the cone.\n * * **Detail(`NumberParameter`):** Specifies the number of subdivisions around the `Z` axis.\n * * **Cap(`BooleanParameter`):** Specifies whether the base of the cone is capped or open.\n *\n * @extends {ProceduralMesh}\n */\nclass Cone extends ProceduralMesh {\n    /**\n     * @member capParam - Specifies whether the base of the cone is capped or open.\n     */\n    capParam = new BooleanParameter('Cap', true);\n    /**\n     * @member detailParam - Specifies the number of subdivisions around the `Z` axis.\n     */\n    detailParam = new NumberParameter('Detail', 6, [0, Number.MAX_VALUE], 1);\n    /**\n     * @member heightParam - Specifies the height of the cone.\n     */\n    heightParam = new NumberParameter('Height', 1, [0, Number.MAX_VALUE]);\n    /**\n     * @member radiusParam - Specifies the radius of the base of the cone.\n     */\n    radiusParam = new NumberParameter('Radius', 6, [0, Number.MAX_VALUE]);\n    /**\n     * Create a cone.\n     * @param radius - The radius of the base of the cone.\n     * @param height - The height of the cone.\n     * @param detail - The detail of the cone.\n     * @param cap -  A boolean indicating whether the base of the cone is capped or open.\n     * @param addNormals - Compute vertex normals for the geometry\n     * @param addTextureCoords - Compute texture coordinates for the geometry\n     */\n    constructor(radius = 0.5, height = 1.0, detail = 32, cap = true, addNormals = true, addTextureCoords = true) {\n        super();\n        this.topologyParams = [];\n        if (isNaN(radius) || isNaN(height) || isNaN(detail))\n            throw new Error('Invalid geom args');\n        this.radiusParam.value = radius;\n        this.heightParam.value = height;\n        this.detailParam.value = detail;\n        this.capParam.value = cap;\n        this.addParameter(this.radiusParam);\n        this.addParameter(this.heightParam);\n        this.addParameter(this.detailParam);\n        this.addParameter(this.capParam);\n        if (addNormals)\n            this.addVertexAttribute('normals', new Vec3f8Attribute());\n        if (addTextureCoords)\n            this.addVertexAttribute('texCoords', new Vec2f16Attribute());\n        this.topologyParams.push('Detail');\n        this.topologyParams.push('Cap');\n    }\n    /**\n     * The rebuild method.\n     * @private\n     */\n    rebuild() {\n        const nbSides = Math.round(this.detailParam.value);\n        const radius = this.radiusParam.value;\n        const height = this.heightParam.value;\n        const cap = this.capParam.value;\n        let numVertices = nbSides + 1;\n        if (cap) {\n            numVertices += 1;\n        }\n        this.setNumVertices(numVertices);\n        const tipPoint = nbSides;\n        const basePoint = nbSides + 1;\n        // ////////////////////////////\n        // Set Vertex Positions\n        const positions = this.positions;\n        if (positions) {\n            positions.setValue(tipPoint, new Vec3(0.0, 0.0, height));\n            for (let i = 0; i < nbSides; i++) {\n                const theta = -((i / nbSides) * 2.0 * Math.PI);\n                positions.setValue(i, new Vec3(radius * Math.cos(theta), radius * Math.sin(theta), 0.0));\n            }\n            if (cap) {\n                positions.setValue(basePoint, new Vec3(0.0, 0.0, 0.0));\n            }\n        }\n        // ////////////////////////////\n        // Build the topology\n        this.setFaceCounts([nbSides + (cap ? nbSides : 0)]);\n        for (let i = 0; i < nbSides; i++) {\n            const j = (i + 1) % nbSides;\n            this.setFaceVertexIndices(i, [j, i, tipPoint]);\n        }\n        if (cap) {\n            for (let i = 0; i < nbSides; i++) {\n                const j = (i + 1) % nbSides;\n                this.setFaceVertexIndices(nbSides + i, [i, j, basePoint]);\n            }\n        }\n        // ////////////////////////////\n        // setUVs\n        const texCoords = this.getVertexAttribute('texCoords');\n        if (texCoords) {\n            // Now set the attrbute values\n            let tri = 0;\n            for (let i = 0; i < nbSides; i++) {\n                if ('setFaceVertexValue' in texCoords) {\n                    texCoords.setFaceVertexValue(tri, 0, new Vec2((i + 1) / nbSides, 0.0));\n                    texCoords.setFaceVertexValue(tri, 1, new Vec2(i / nbSides, 0.0));\n                    texCoords.setFaceVertexValue(tri, 2, new Vec2((i + 0.5) / nbSides, 1.0));\n                }\n            }\n            if (cap) {\n                for (let i = 0; i < nbSides; i++) {\n                    texCoords.setFaceVertexValue(tri, 0, new Vec2(i / nbSides, 0.0));\n                    texCoords.setFaceVertexValue(tri, 1, new Vec2((i + 1) / nbSides, 0.0));\n                    texCoords.setFaceVertexValue(tri, 2, new Vec2((i + 0.5) / nbSides, 1.0));\n                    tri++;\n                }\n            }\n        }\n        this.resize();\n    }\n    /**\n     * The resize method.\n     * @private\n     */\n    resize() {\n        const nbSides = Math.round(this.detailParam.value);\n        const radius = this.radiusParam.value;\n        const height = this.heightParam.value;\n        const tipPoint = nbSides;\n        const basePoint = nbSides + 1;\n        const positions = this.positions;\n        if (positions) {\n            positions.setValue(tipPoint, new Vec3(0.0, 0.0, height));\n            for (let i = 0; i < nbSides; i++) {\n                const theta = -((i / nbSides) * 2.0 * Math.PI);\n                positions.setValue(i, new Vec3(radius * Math.cos(theta), radius * Math.sin(theta), 0.0));\n            }\n            if (this.capParam.value) {\n                positions.setValue(basePoint, new Vec3(0.0, 0.0, 0.0));\n            }\n        }\n        // Note: this breaks an infinite loop where computeVertexNormals calls update which calls rebuild.\n        this.dirtyTopology = false;\n        this.dirtyVertices = false;\n        const normals = this.getVertexAttribute('normals');\n        if (normals) {\n            this.computeVertexNormals();\n        }\n    }\n}\nRegistry.register('Cone', Cone);\n\n// import { Vec2 } from '../../../Math/Vec2'\n// import { Vec2Attribute } from '../Vec2Attribute'\n/**\n * A class for generating a cuboid geometry.\n *\n * **Parameters**\n * * **x(`NumberParameter`):** Length of the line cuboid along the `X` axis\n * * **y(`NumberParameter`):** Length of the line cuboid along the `Y` axis\n * * **z(`NumberParameter`):** Length of the line cuboid along the `Z` axis\n * * **BaseZAtZero(`NumberParameter`):** Property to start or not `Z` axis from position `0.\n *\n * @extends {ProceduralMesh}\n */\nclass Cuboid extends ProceduralMesh {\n    /**\n     * @member baseZAtZeroParam - Property to start or not `Z` axis from position `0.\n     */\n    baseZAtZeroParam = new BooleanParameter('BaseZAtZero', false);\n    /**\n     * @member sizeXParam - Length of the line cuboid along the `X` axis\n     */\n    sizeXParam = new NumberParameter('SizeX', 1.0, [0, Number.MAX_VALUE]);\n    /**\n     * @member sizeYParam - Length of the line cuboid along the `Y` axis\n     */\n    sizeYParam = new NumberParameter('SizeY', 1.0, [0, Number.MAX_VALUE]);\n    /**\n     * @member sizeZParam - Length of the line cuboid along the `Z` axis\n     */\n    sizeZParam = new NumberParameter('SizeZ', 1.0, [0, Number.MAX_VALUE]);\n    /**\n     * Create a cuboid.\n     * @param x - The length of the cuboid along the X axis.\n     * @param y - The length of the cuboid along the Y axis.\n     * @param z - The length of the cuboid along the Z axis.\n     * @param baseZAtZero - The baseZAtZero value.\n     */\n    constructor(x = 1.0, y = 1.0, z = 1.0, baseZAtZero = false) {\n        super();\n        if (isNaN(x) || isNaN(y) || isNaN(z))\n            throw new Error('Invalid geom args');\n        this.addParameter(this.sizeXParam);\n        this.addParameter(this.sizeYParam);\n        this.addParameter(this.sizeZParam);\n        this.addParameter(this.baseZAtZeroParam);\n        this.sizeXParam.value = x;\n        this.sizeYParam.value = y;\n        this.sizeZParam.value = z;\n        this.baseZAtZeroParam.value = baseZAtZero;\n        this.setFaceCounts([0, 6]);\n        this.setFaceVertexIndices(0, [0, 1, 2, 3]);\n        this.setFaceVertexIndices(1, [7, 6, 5, 4]);\n        this.setFaceVertexIndices(2, [1, 0, 4, 5]);\n        this.setFaceVertexIndices(3, [3, 2, 6, 7]);\n        this.setFaceVertexIndices(4, [0, 3, 7, 4]);\n        this.setFaceVertexIndices(5, [2, 1, 5, 6]);\n        this.setNumVertices(8);\n        this.addVertexAttribute('normals', new Vec3f8Attribute());\n        // this.addVertexAttribute('texCoords', new Vec2f16Attribute())\n    }\n    /**\n     * The rebuild method.\n     * @private\n     */\n    rebuild() {\n        const normals = this.getVertexAttribute('normals');\n        if (normals) {\n            for (let i = 0; i < 6; i++) {\n                let normal;\n                switch (i) {\n                    case 0:\n                        normal = new Vec3(0, 0, 1);\n                        break;\n                    case 1:\n                        normal = new Vec3(0, 0, -1);\n                        break;\n                    case 2:\n                        normal = new Vec3(1, 0, 0);\n                        break;\n                    case 3:\n                        normal = new Vec3(-1, 0, 0);\n                        break;\n                    case 4:\n                        normal = new Vec3(0, -1, 0);\n                        break;\n                    //case 5:\n                    default:\n                        normal = new Vec3(0, 1, 0);\n                        break;\n                }\n                normals.setFaceVertexValue(i, 0, normal);\n                normals.setFaceVertexValue(i, 1, normal);\n                normals.setFaceVertexValue(i, 2, normal);\n                normals.setFaceVertexValue(i, 3, normal);\n            }\n        } /*\n        const texCoords = <Vec2Attribute>this.getVertexAttribute('texCoords')\n        if (texCoords) {\n          for (let i = 0; i < 6; i++) {\n            texCoords.setFaceVertexValue(i, 0, new Vec2(0, 0))\n            texCoords.setFaceVertexValue(i, 1, new Vec2(1, 0))\n            texCoords.setFaceVertexValue(i, 2, new Vec2(1, 1))\n            texCoords.setFaceVertexValue(i, 3, new Vec2(0, 1))\n          }\n        }\n        */\n        this.resize();\n    }\n    /**\n     * The resize method.\n     * @private\n     */\n    resize() {\n        const x = this.sizeXParam.value;\n        const y = this.sizeYParam.value;\n        const z = this.sizeZParam.value;\n        const baseZAtZero = this.baseZAtZeroParam.value;\n        let zoff = 0.5;\n        const positions = this.positions;\n        if (baseZAtZero)\n            zoff = 1.0;\n        if (!positions)\n            return;\n        positions.setValue(0, new Vec3(0.5 * x, -0.5 * y, zoff * z));\n        positions.setValue(1, new Vec3(0.5 * x, 0.5 * y, zoff * z));\n        positions.setValue(2, new Vec3(-0.5 * x, 0.5 * y, zoff * z));\n        positions.setValue(3, new Vec3(-0.5 * x, -0.5 * y, zoff * z));\n        zoff = -0.5;\n        if (baseZAtZero)\n            zoff = 0.0;\n        positions.setValue(4, new Vec3(0.5 * x, -0.5 * y, zoff * z));\n        positions.setValue(5, new Vec3(0.5 * x, 0.5 * y, zoff * z));\n        positions.setValue(6, new Vec3(-0.5 * x, 0.5 * y, zoff * z));\n        positions.setValue(7, new Vec3(-0.5 * x, -0.5 * y, zoff * z));\n    }\n}\nRegistry.register('Cuboid', Cuboid);\n\n/**\n * A class for generating a cylinder geometry. It is very much like a cuboid but with `N` number of sides.\n *\n * ```\n * const cylinder = new Cylinder(1.5, 2.0, 6)\n * ```\n *\n * **Parameters**\n * * **Radius(`NumberParameter`):** Specifies the radius of the cylinder.\n * * **Height(`NumberParameter`):** Specifies the height of the cone.\n * * **Sides(`NumberParameter`):** Specifies the number of subdivisions around the `Z` axis.\n * * **Loops(`NumberParameter`):** Specifies the number of subdivisions(stacks) on the `Z` axis.\n * * **Caps(`BooleanParameter`):** Specifies whether the ends of the cylinder are capped or open.\n * * **BaseZAtZero(`BooleanParameter`):** Property to start or not `Z` axis from position `0.\n *\n * @extends {ProceduralMesh}\n */\nclass Cylinder extends ProceduralMesh {\n    /**\n     * @member baseZAtZeroParam - Property to start or not `Z` axis from position `0.\n     */\n    baseZAtZeroParam = new BooleanParameter('BaseZAtZero', true);\n    /**\n     * @member capsParam - Specifies whether the ends of the cylinder are capped or open.\n     */\n    capsParam = new BooleanParameter('Caps', true);\n    /**\n     * @member heightParam - Specifies the height of the cone.\n     */\n    heightParam = new NumberParameter('Height', 1, [0, Number.MAX_VALUE]);\n    /**\n     * @member radiusParam - Specifies the radius of the cylinder.\n     */\n    radiusParam = new NumberParameter('Radius', 6, [0, Number.MAX_VALUE]);\n    /**\n     * @member loopsParam - Specifies the number of subdivisions(stacks) on the `Z` axis.\n     */\n    loopsParam = new NumberParameter('Loops', 6, [0, Number.MAX_VALUE], 1);\n    /**\n     * @member sidesParam - Specifies the number of subdivisions around the `Z` axis.\n     */\n    sidesParam = new NumberParameter('Sides', 12, [0, Number.MAX_VALUE], 1);\n    /**\n     * Create a cylinder.\n     * @param radius - The radius of the cylinder.\n     * @param height - The height of the cylinder.\n     * @param sides - The number of sides.\n     * @param loops - The number of loops.\n     * @param caps - A boolean indicating whether the ends of the cylinder are capped or open.\n     * @param baseZAtZero - The baseZAtZero value.\n     */\n    constructor(radius = 0.5, height = 1.0, sides = 32, loops = 2, caps = true, baseZAtZero = false, addNormals = true, addTextureCoords = true) {\n        super();\n        this.topologyParams = [];\n        if (isNaN(radius) || isNaN(height) || isNaN(sides) || isNaN(loops))\n            throw new Error('Invalid geom args');\n        this.radiusParam.value = radius;\n        this.heightParam.value = height;\n        this.sidesParam.value = sides >= 3 ? sides : 3;\n        this.loopsParam.value = loops >= 2 ? loops : 2;\n        this.capsParam.value = caps;\n        this.baseZAtZeroParam.value = baseZAtZero;\n        this.addParameter(this.radiusParam);\n        this.addParameter(this.heightParam);\n        this.addParameter(this.sidesParam);\n        this.addParameter(this.loopsParam);\n        this.addParameter(this.capsParam);\n        this.addParameter(this.baseZAtZeroParam);\n        if (addNormals)\n            this.addVertexAttribute('normals', new Vec2f16Attribute()); // TODO: review args/params.\n        if (addTextureCoords)\n            this.addVertexAttribute('texCoords', new Vec3f8Attribute());\n        this.topologyParams.push('Sides');\n        this.topologyParams.push('Loops');\n        this.topologyParams.push('Caps');\n    }\n    /**\n     * The rebuild method.\n     * @private\n     */\n    rebuild() {\n        const nbSides = Math.round(this.sidesParam.value);\n        const nbLoops = Math.round(this.loopsParam.value);\n        const caps = this.capsParam.value;\n        let numVertices = nbSides * nbLoops;\n        if (caps) {\n            numVertices += 2;\n        }\n        this.setNumVertices(numVertices);\n        if (caps)\n            this.setFaceCounts([nbSides * 2, nbSides]);\n        else\n            this.setFaceCounts([0, nbSides]);\n        // ////////////////////////////\n        // Build the topology\n        let faceIndex = 0;\n        if (caps) {\n            // Bottom caps topology\n            for (let j = 0; j < nbSides; j++) {\n                const v0 = numVertices - 1;\n                const v1 = j;\n                const v2 = (j + 1) % nbSides;\n                this.setFaceVertexIndices(faceIndex++, [v0, v1, v2]);\n            }\n            // Top caps topology\n            for (let j = 0; j < nbSides; j++) {\n                const v0 = nbSides * (nbLoops - 1) + j;\n                const v1 = numVertices - 2;\n                const v2 = nbSides * (nbLoops - 1) + ((j + 1) % nbSides);\n                this.setFaceVertexIndices(faceIndex++, [v0, v1, v2]);\n            }\n        }\n        // build the topology for the body of the cylinder\n        for (let i = 0; i < nbLoops - 1; i++) {\n            for (let j = 0; j < nbSides; j++) {\n                const v0 = nbSides * i + ((j + 1) % nbSides);\n                const v1 = nbSides * i + j;\n                const v2 = nbSides * (i + 1) + j;\n                const v3 = nbSides * (i + 1) + ((j + 1) % nbSides);\n                this.setFaceVertexIndices(faceIndex++, [v0, v1, v2, v3]);\n            }\n        }\n        // ////////////////////////////\n        // setNormals\n        const normals = this.getVertexAttribute('normals');\n        if (normals) {\n            // Now set the attribute values\n            faceIndex = 0;\n            if (caps) {\n                const normal = new Vec3(0.0, 0.0, -1.0);\n                for (let i = 0; i < nbSides; i++) {\n                    normals.setFaceVertexValue(faceIndex, 0, normal);\n                    normals.setFaceVertexValue(faceIndex, 1, normal);\n                    normals.setFaceVertexValue(faceIndex, 2, normal);\n                    faceIndex++;\n                }\n                normal.set(0.0, 0.0, 1.0);\n                for (let i = 0; i < nbSides; i++) {\n                    normals.setFaceVertexValue(faceIndex, 0, normal);\n                    normals.setFaceVertexValue(faceIndex, 1, normal);\n                    normals.setFaceVertexValue(faceIndex, 2, normal);\n                    faceIndex++;\n                }\n            }\n            for (let i = 0; i < nbLoops - 1; i++) {\n                for (let j = 0; j < nbSides; j++) {\n                    let phi = (j / nbSides) * 2.0 * Math.PI;\n                    const normal1 = new Vec3(Math.sin(phi), Math.cos(phi), 0.0);\n                    normals.setFaceVertexValue(faceIndex, 0, normal1);\n                    normals.setFaceVertexValue(faceIndex, 1, normal1);\n                    phi = ((j + 1) / nbSides) * 2.0 * Math.PI;\n                    const normal2 = new Vec3(Math.sin(phi), Math.cos(phi), 0.0);\n                    normals.setFaceVertexValue(faceIndex, 2, normal2);\n                    normals.setFaceVertexValue(faceIndex, 3, normal2);\n                    faceIndex++;\n                }\n            }\n        }\n        // ////////////////////////////\n        // setUVs\n        const texCoords = this.getVertexAttribute('texCoords');\n        if (texCoords) {\n            // Now set the attrbute values\n            faceIndex = 0;\n            if (caps) {\n                for (let i = 0; i < nbSides; i++) {\n                    texCoords.setFaceVertexValue(faceIndex, 0, new Vec2(i / nbSides, 0.0));\n                    texCoords.setFaceVertexValue(faceIndex, 1, new Vec2((i + 1) / nbSides, 0.0));\n                    texCoords.setFaceVertexValue(faceIndex, 2, new Vec2((i + 0.5) / nbSides, 1.0));\n                    faceIndex++;\n                }\n                for (let i = 0; i < nbSides; i++) {\n                    texCoords.setFaceVertexValue(faceIndex, 0, new Vec2(i / nbSides, 0.0));\n                    texCoords.setFaceVertexValue(faceIndex, 1, new Vec2((i + 1) / nbSides, 0.0));\n                    texCoords.setFaceVertexValue(faceIndex, 2, new Vec2((i + 0.5) / nbSides, 1.0));\n                    faceIndex++;\n                }\n            }\n            for (let i = 0; i < nbSides; i++) {\n                texCoords.setFaceVertexValue(faceIndex, 0, new Vec2((i + 1) / nbSides, 0.0));\n                texCoords.setFaceVertexValue(faceIndex, 2, new Vec2((i + 1) / nbSides, 1.0));\n                texCoords.setFaceVertexValue(faceIndex, 1, new Vec2(i / nbSides, 0.0));\n                texCoords.setFaceVertexValue(faceIndex, 3, new Vec2(i / nbSides, 1.0));\n                faceIndex++;\n            }\n        }\n        this.resize();\n    }\n    /**\n     * The resize method.\n     * @private\n     */\n    resize() {\n        const nbSides = Math.round(this.sidesParam.value);\n        const nbLoops = Math.round(this.loopsParam.value);\n        const radius = this.radiusParam.value;\n        const height = this.heightParam.value;\n        const caps = this.capsParam.value;\n        const baseZAtZero = this.baseZAtZeroParam.value;\n        let numVertices = nbSides * nbLoops;\n        if (caps) {\n            numVertices += 2;\n        }\n        let vertex = 0;\n        let zoff = 0.5;\n        if (baseZAtZero)\n            zoff = 0.0;\n        const positions = this.positions;\n        if (positions) {\n            for (let i = 0; i < nbLoops; i++) {\n                const z = (i / (nbLoops - 1)) * height - height * zoff;\n                for (let j = 0; j < nbSides; j++) {\n                    const phi = (j / nbSides) * 2.0 * Math.PI;\n                    positions.setValue(vertex, new Vec3(Math.sin(phi) * radius, Math.cos(phi) * radius, z));\n                    vertex++;\n                }\n            }\n            if (caps) {\n                positions.setValue(numVertices - 1, new Vec3(0.0, 0.0, height * (baseZAtZero ? 0.0 : -0.5)));\n                positions.setValue(numVertices - 2, new Vec3(0.0, 0.0, height * (baseZAtZero ? 1.0 : 0.5)));\n            }\n        }\n        this.dirtyTopology = false;\n        this.dirtyVertices = false;\n        const normals = this.getVertexAttribute('normals');\n        if (normals) {\n            this.computeVertexNormals();\n        }\n    }\n}\nRegistry.register('Cylinder', Cylinder);\n\n/**\n * A class for generating a disc geometry.\n *\n * ```\n * const disc = new Disc(2.0, 22)\n * ```\n *\n * **Parameters**\n * * **Radius(`NumberParameter`):** Specifies the radius of the disc.\n * * **Sides(`NumberParameter`):** Specifies the resolution, or the disc subdivisions around `Z` axis.\n *\n * @extends {ProceduralMesh}\n */\nclass Disc extends ProceduralMesh {\n    /**\n     * @member radiusParam - Specifies the radius of the disc.\n     */\n    radiusParam = new NumberParameter('Radius', 6, [0, Number.MAX_VALUE]);\n    /**\n     * @member sidesParam - Specifies the resolution, or the disc subdivisions around `Z` axis.\n     */\n    sidesParam = new NumberParameter('Sides', 12, [0, Number.MAX_VALUE], 1);\n    /**\n     * Creates an instance of Disc.\n     *\n     * @param radius - The radius of the disc.\n     * @param sides - The number of sides.\n     */\n    constructor(radius = 0.5, sides = 32) {\n        super();\n        this.topologyParams = [];\n        if (isNaN(radius) || isNaN(sides))\n            throw new Error('Invalid geom args');\n        this.addParameter(this.radiusParam);\n        this.addParameter(this.sidesParam);\n        this.radiusParam.value = radius;\n        this.sidesParam.value = sides;\n        this.addVertexAttribute('texCoords', new Vec2f16Attribute());\n        this.addVertexAttribute('normals', new Vec3f8Attribute());\n        this.topologyParams.push('Sides');\n    }\n    /**\n     * The rebuild method.\n     * @private\n     */\n    rebuild() {\n        const nbSides = Math.round(this.sidesParam.value);\n        this.setNumVertices(nbSides + 1);\n        this.setFaceCounts([nbSides]);\n        // ////////////////////////////\n        // Set Vertex Positions\n        const positions = this.positions;\n        if (positions)\n            positions.setValue(0, new Vec3(0.0, 0.0, 0.0));\n        // ////////////////////////////\n        // Build the topology\n        for (let j = 0; j < nbSides; j++) {\n            const v1 = (j % nbSides) + 1;\n            const v2 = ((j + 1) % nbSides) + 1;\n            this.setFaceVertexIndices(j, [0, v1, v2]);\n        }\n        // ////////////////////////////\n        // setNormals\n        const normals = this.getVertexAttribute('normals');\n        if (normals) {\n            // Now set the attrbute values\n            const normal = new Vec3(0, 0, 1);\n            normals.setValue(0, normal);\n            for (let i = 0; i < nbSides; i++) {\n                normals.setValue(i + 1, normal);\n            }\n        }\n        // ////////////////////////////\n        // setUVs\n        const texCoords = this.getVertexAttribute('texCoords');\n        if (texCoords) {\n            texCoords.setValue(0, new Vec2(0.5, 0.5));\n            for (let i = 0; i < nbSides; i++) {\n                const phi = (i / nbSides) * 2.0 * Math.PI;\n                texCoords.setValue(i + 1, new Vec2(Math.sin(phi) * 0.5 + 0.5, Math.cos(phi) * 0.5 + 0.5));\n            }\n        }\n        this.resize();\n    }\n    /**\n     * The resize method.\n     * @private\n     */\n    resize() {\n        const nbSides = Math.round(this.sidesParam.value);\n        const radius = this.radiusParam.value;\n        const positions = this.positions;\n        if (positions) {\n            for (let i = 0; i < nbSides; i++) {\n                const phi = (i / nbSides) * 2.0 * Math.PI;\n                positions.setValue(i + 1, new Vec3(Math.sin(phi) * radius, Math.cos(phi) * radius, 0.0));\n            }\n        }\n    }\n}\nRegistry.register('Disc', Disc);\n\n/**\n * A class for generating a plane geometry.\n *\n * ```\n * const plane = new Plane(2.0, 1.5, 10, 10)\n * ```\n *\n * **Parameters**\n * * **SizeX(`NumberParameter`):** Length of the plane along `X` axis.\n * * **SizeY(`NumberParameter`):** Length of the plane along `Y` axis.\n * * **DetailX(`NumberParameter`):** Number of divisions along `X`axis.\n * * **DetailY(`NumberParameter`):** Number of divisions along `Y`axis.\n *\n * @extends {ProceduralMesh}\n */\nclass Plane extends ProceduralMesh {\n    /**\n     * @member sizeXParam - Number of divisions along `X`axis.\n     */\n    sizeXParam = new NumberParameter('SizeX', 1.0, [0, Number.MAX_VALUE]);\n    /**\n     * @member sizeYParam - Number of divisions along `Y`axis.\n     */\n    sizeYParam = new NumberParameter('SizeY', 1.0, [0, Number.MAX_VALUE]);\n    /**\n     * @member detailXParam - Length of the plane along `X` axis.\n     */\n    detailXParam = new NumberParameter('DetailX', 1, [0, Number.MAX_VALUE], 1);\n    /**\n     * @member detailYParam - Length of the plane along `Y` axis.\n     */\n    detailYParam = new NumberParameter('DetailY', 1, [0, Number.MAX_VALUE], 1);\n    /**\n     * Create a plane.\n     * @param SizeX - The length of the plane along the X axis.\n     * @param SizeY - The length of the plane along the Y axis.\n     * @param DetailX - The number of divisions along the X axis.\n     * @param DetailY - The number of divisions along the Y axis.\n     * @param addNormals - The addNormals value.\n     * @param addTextureCoords - The addTextureCoords value.\n     */\n    constructor(SizeX = 1.0, SizeY = 1.0, DetailX = 1, DetailY = 1, addNormals = true, addTextureCoords = true) {\n        super();\n        this.topologyParams = [];\n        if (isNaN(SizeX) || isNaN(SizeY) || isNaN(DetailX) || isNaN(DetailY))\n            throw new Error('Invalid geom args');\n        this.addParameter(this.sizeXParam);\n        this.addParameter(this.sizeYParam);\n        this.addParameter(this.detailXParam);\n        this.addParameter(this.detailYParam);\n        this.sizeXParam.value = SizeX;\n        this.sizeYParam.value = SizeY;\n        this.detailXParam.value = DetailX;\n        this.detailYParam.value = DetailY;\n        if (addNormals)\n            this.addVertexAttribute('normals', new Vec3f8Attribute());\n        if (addTextureCoords)\n            this.addVertexAttribute('texCoords', new Vec2f16Attribute());\n        this.topologyParams.push('DetailX');\n        this.topologyParams.push('DetailY');\n    }\n    /**\n     * The rebuild method.\n     * @private\n     */\n    rebuild() {\n        const detailX = this.detailXParam.value;\n        const detailY = this.detailYParam.value;\n        this.setNumVertices((detailX + 1) * (detailY + 1));\n        this.setFaceCounts([0, detailX * detailY]);\n        let quadId = 0;\n        for (let i = 0; i < detailY; i++) {\n            for (let j = 0; j < detailX; j++) {\n                const v0 = (detailX + 1) * (i + 1) + j;\n                const v1 = (detailX + 1) * i + j;\n                const v2 = (detailX + 1) * i + (j + 1);\n                const v3 = (detailX + 1) * (i + 1) + (j + 1);\n                this.setFaceVertexIndices(quadId, [v0, v1, v2, v3]);\n                quadId = quadId + 1;\n            }\n        }\n        let voff = 0;\n        const normals = this.getVertexAttribute('normals');\n        if (normals) {\n            for (let i = 0; i <= detailY; i++) {\n                for (let j = 0; j <= detailX; j++) {\n                    normals.setValue(voff, new Vec3(0, 0, 1));\n                    voff++;\n                }\n            }\n        }\n        voff = 0;\n        const texCoords = this.getVertexAttribute('texCoords');\n        if (texCoords) {\n            for (let i = 0; i <= detailY; i++) {\n                const y = i / detailY;\n                for (let j = 0; j <= detailX; j++) {\n                    const x = j / detailX;\n                    texCoords.setValue(voff, new Vec2(x, y));\n                    voff++;\n                }\n            }\n        }\n        this.resize();\n    }\n    /**\n     * The resize method.\n     *\n     * @private\n     */\n    resize() {\n        const sizeX = this.sizeXParam.value;\n        const sizeY = this.sizeYParam.value;\n        const detailX = this.detailXParam.value;\n        const detailY = this.detailYParam.value;\n        const positions = this.positions;\n        if (!positions)\n            return;\n        let voff = 0;\n        for (let i = 0; i <= detailY; i++) {\n            const y = (i / detailY - 0.5) * sizeY;\n            for (let j = 0; j <= detailX; j++) {\n                const x = (j / detailX - 0.5) * sizeX;\n                positions.setValue(voff, new Vec3(x, y, 0.0));\n                voff++;\n            }\n        }\n    }\n}\nRegistry.register('Plane', Plane);\n\n/**\n * A class for generating a sphere geometry.\n *\n * ```\n * const sphere = new Sphere(1.4, 13)\n * ```\n *\n * **Parameters**\n * * **Radius(`NumberParameter`):** Radius of the sphere.\n * * **Sides(`NumberParameter`):** Specifies the number of subdivisions around the `Z` axis.\n * * **Loops(`NumberParameter`):** Specifies the number of subdivisions(stacks) along the `Z` axis.\n *\n * @extends {ProceduralMesh}\n */\nclass Sphere extends ProceduralMesh {\n    /**\n     * @member radiusParam - Radius of the sphere.\n     */\n    radiusParam = new NumberParameter('Radius', 1.0, [0, Number.MAX_VALUE]);\n    /**\n     * @member sidesParam - Specifies the number of subdivisions around the `Z` axis.\n     */\n    sidesParam = new NumberParameter('Sides', 12, [0, Number.MAX_VALUE], 1);\n    /**\n     * @member loopsParam - Specifies the number of subdivisions(stacks) along the `Z` axis.\n     */\n    loopsParam = new NumberParameter('Loops', 6, [0, Number.MAX_VALUE], 1);\n    /**\n     * Creates an instance of Sphere.\n     * @param radius - The radius of the sphere.\n     * @param sides - The number of sides.\n     * @param loops - The number of loops.\n     * @param addNormals - Compute vertex normals for the geometry\n     * @param addTextureCoords - Compute texture coordinates for the geometry\n     */\n    constructor(radius = 1.0, sides = 12, loops = 12, addNormals = true, addTextureCoords = true) {\n        super();\n        if (isNaN(radius) || isNaN(sides) || isNaN(loops))\n            throw new Error('Invalid geom args');\n        this.addParameter(this.radiusParam);\n        this.addParameter(this.sidesParam);\n        this.addParameter(this.loopsParam);\n        this.radiusParam.value = radius;\n        this.sidesParam.value = sides;\n        this.loopsParam.value = loops;\n        if (addNormals)\n            this.addVertexAttribute('normals', new Vec3f8Attribute());\n        if (addTextureCoords)\n            this.addVertexAttribute('texCoords', new Vec2f16Attribute());\n        this.topologyParams.push('Sides');\n        this.topologyParams.push('Loops');\n    }\n    /**\n     * The rebuild method.\n     * @private\n     */\n    rebuild() {\n        const radius = this.radiusParam.value;\n        const nbSides = Math.round(this.sidesParam.value);\n        const nbLoops = Math.round(this.loopsParam.value);\n        const numVertices = 2 + nbSides * nbLoops;\n        const numTris = nbSides * 2;\n        const numQuads = nbSides * nbLoops;\n        this.setNumVertices(numVertices);\n        this.setFaceCounts([numTris, numQuads]);\n        // ////////////////////////////\n        // Set Vertex Positions\n        const positions = this.positions;\n        const normals = this.getVertexAttribute('normals');\n        const normal = new Vec3(0.0, 0.0, 1.0);\n        let vertex = 0;\n        if (!positions)\n            return;\n        positions.setValue(vertex, new Vec3(0.0, 0.0, radius));\n        if (normals)\n            normals.setValue(vertex, new Vec3(0.0, 0.0, 1.0));\n        vertex++;\n        for (let i = 0; i < nbLoops; i++) {\n            const theta = ((i + 1) / (nbLoops + 1)) * Math.PI;\n            for (let j = 0; j < nbSides; j++) {\n                const phi = -((j / nbSides) * 2.0 * Math.PI);\n                normal.set(Math.sin(theta) * Math.cos(phi), Math.sin(theta) * Math.sin(phi), Math.cos(theta));\n                // Set positions and normals at the same time.\n                positions.setValue(vertex, normal.scale(radius));\n                if (normals)\n                    normals.setValue(vertex, normal);\n                vertex++;\n            }\n        }\n        positions.setValue(vertex, new Vec3(0.0, 0.0, -radius));\n        if (normals)\n            normals.setValue(vertex, new Vec3(0.0, 0.0, -1.0));\n        vertex++;\n        // ////////////////////////////\n        // Build the topology\n        const texCoords = this.getVertexAttribute('texCoords');\n        // build the fan at the first pole.\n        let faceIndex = 0;\n        for (let j = 0; j < nbSides; j++) {\n            const v0 = 0;\n            const v1 = ((j + 1) % nbSides) + 1;\n            const v2 = j + 1;\n            this.setFaceVertexIndices(faceIndex, [v0, v1, v2]);\n            if (texCoords) {\n                const uv0 = new Vec2(0.5, 0.0);\n                const uv1 = new Vec2((j + 1) / (nbSides - 1), 1 / (nbLoops + 1));\n                const uv2 = new Vec2(j / (nbSides - 1), 1 / (nbLoops + 1));\n                texCoords.setFaceVertexValue(faceIndex, 0, uv0);\n                texCoords.setFaceVertexValue(faceIndex, 1, uv1);\n                texCoords.setFaceVertexValue(faceIndex, 2, uv2);\n            }\n            faceIndex++;\n        }\n        // Build the fan at the second pole.\n        for (let j = 0; j < nbSides; j++) {\n            const v0 = numVertices - 1;\n            const v2 = nbSides * (nbLoops - 1) + ((j + 1) % nbSides) + 1;\n            const v1 = nbSides * (nbLoops - 1) + j + 1;\n            this.setFaceVertexIndices(faceIndex, [v0, v1, v2]);\n            if (texCoords) {\n                const uv0 = new Vec2(0.5, 1.0);\n                const uv1 = new Vec2((j + 1) / (nbSides - 1), 1 - 1 / (nbLoops + 1));\n                const uv2 = new Vec2(j / (nbSides - 1), 1 - 1 / (nbLoops + 1));\n                texCoords.setFaceVertexValue(faceIndex, 0, uv0);\n                texCoords.setFaceVertexValue(faceIndex, 1, uv1);\n                texCoords.setFaceVertexValue(faceIndex, 2, uv2);\n            }\n            faceIndex++;\n        }\n        for (let i = 0; i < nbLoops - 1; i++) {\n            for (let j = 0; j < nbSides; j++) {\n                const v0 = nbSides * i + j + 1;\n                const v1 = nbSides * i + ((j + 1) % nbSides) + 1;\n                const v2 = nbSides * (i + 1) + ((j + 1) % nbSides) + 1;\n                const v3 = nbSides * (i + 1) + j + 1;\n                this.setFaceVertexIndices(faceIndex, [v0, v1, v2, v3]);\n                if (texCoords) {\n                    texCoords.setFaceVertexValue(faceIndex, 0, new Vec2(j / nbSides, (i + 1) / nbLoops));\n                    texCoords.setFaceVertexValue(faceIndex, 1, new Vec2((j + 1) / nbSides, (i + 1) / nbLoops));\n                    texCoords.setFaceVertexValue(faceIndex, 2, new Vec2((j + 1) / nbSides, (i + 2) / nbLoops));\n                    texCoords.setFaceVertexValue(faceIndex, 3, new Vec2(j / nbSides, (i + 2) / nbLoops));\n                }\n                faceIndex++;\n            }\n        }\n    }\n    /**\n     * The resize method.\n     * @private\n     */\n    resize() {\n        const radius = this.radiusParam.value;\n        const nbSides = Math.round(this.sidesParam.value);\n        const nbLoops = Math.round(this.loopsParam.value);\n        if (!nbSides || !nbLoops) {\n            console.warn('resize() failed');\n            return;\n        }\n        // ////////////////////////////\n        // Set Vertex Positions\n        const positions = this.positions;\n        const normals = this.getVertexAttribute('normals');\n        let vertex = 0;\n        const normal = new Vec3(0.0, 0.0, 1.0);\n        positions.setValue(vertex, new Vec3(0.0, 0.0, radius));\n        if (normals)\n            normals.setValue(vertex, new Vec3(0.0, 0.0, 1.0));\n        vertex++;\n        for (let i = 0; i < nbLoops; i++) {\n            const theta = ((i + 1) / (nbLoops + 1)) * Math.PI;\n            for (let j = 0; j < nbSides; j++) {\n                const phi = -((j / nbSides) * 2.0 * Math.PI);\n                normal.set(Math.sin(theta) * Math.cos(phi), Math.sin(theta) * Math.sin(phi), Math.cos(theta));\n                // Set positions and normals at the same time.\n                positions.setValue(vertex, normal.scale(radius));\n                if (normals)\n                    normals.setValue(vertex, normal);\n                vertex++;\n            }\n        }\n        positions.setValue(vertex, new Vec3(0.0, 0.0, -radius));\n        if (normals)\n            normals.setValue(vertex, new Vec3(0.0, 0.0, -1.0));\n        vertex++;\n    }\n}\nRegistry.register('Sphere', Sphere);\n\n/**\n * A class for generating a torus geometry.\n *\n * ```\n * const torus = new Torus(0.4, 1.3)\n * ```\n *\n * @extends ProceduralMesh\n */\nclass Torus extends ProceduralMesh {\n    innerRadiusParam = new NumberParameter('InnerRadius', 1, [0, Number.MAX_VALUE]);\n    outerRadiusParam = new NumberParameter('OuterRadius', 1, [0, Number.MAX_VALUE]);\n    arcAngleParam = new AngleParameter('ArcAngle', Math.PI * 2, [0, Math.PI * 2]);\n    detailParam = new NumberParameter('Detail', 12, [0, Number.MAX_VALUE], 1);\n    /**\n     * Creates an instance of Torus.\n     *\n     * @param innerRadius - The inner radius of the torus.\n     * @param outerRadius - The outer radius of the torus.\n     * @param detail - The detail of the cone.\n     * @param arcAngle - The angle of the arc.\n     */\n    constructor(innerRadius = 0.5, outerRadius = 3, detail = 32, arcAngle = Math.PI * 2.0) {\n        super();\n        if (isNaN(innerRadius) || isNaN(outerRadius) || isNaN(detail))\n            throw new Error('Invalid geom args');\n        this.addParameter(this.innerRadiusParam);\n        this.addParameter(this.outerRadiusParam);\n        this.addParameter(this.arcAngleParam);\n        this.addParameter(this.detailParam);\n        this.innerRadiusParam.value = innerRadius;\n        this.outerRadiusParam.value = outerRadius;\n        this.detailParam.value = detail >= 3 ? detail : 33;\n        this.arcAngleParam.value = arcAngle;\n        this.addVertexAttribute('texCoords', new Vec2f16Attribute());\n        this.addVertexAttribute('normals', new Vec3f8Attribute());\n        this.topologyParams.push('Detail');\n        this.topologyParams.push('ArcAngle');\n    }\n    /**\n     * The rebuild method.\n     * @private\n     */\n    rebuild() {\n        const arcAngle = this.arcAngleParam.value;\n        const open = arcAngle < 2.0 * Math.PI;\n        const detail = Math.round(this.detailParam.value);\n        const nbSlices = detail;\n        const nbLoops = detail * 2 + (open ? 1 : 0);\n        const numVertices = nbSlices * nbLoops;\n        this.setNumVertices(numVertices);\n        this.setFaceCounts([0, nbSlices * nbLoops]);\n        // ////////////////////////////\n        // Build the topology and texCoords\n        const texCoords = this.getVertexAttribute('texCoords');\n        if (texCoords) {\n            let faceIndex = 0;\n            for (let i = 0; i < (open ? nbLoops - 1 : nbLoops); i++) {\n                for (let j = 0; j < nbSlices; j++) {\n                    const ip = (i + 1) % nbLoops;\n                    const jp = (j + 1) % nbSlices;\n                    const v0 = nbSlices * i + j;\n                    const v1 = nbSlices * i + jp;\n                    const v2 = nbSlices * ip + jp;\n                    const v3 = nbSlices * ip + j;\n                    this.setFaceVertexIndices(faceIndex, [v0, v1, v2, v3]);\n                    texCoords.setFaceVertexValue(faceIndex, 0, new Vec2(i / nbLoops, j / nbLoops));\n                    texCoords.setFaceVertexValue(faceIndex, 1, new Vec2(i / nbLoops, (j + 1) / nbLoops));\n                    texCoords.setFaceVertexValue(faceIndex, 2, new Vec2((i + 1) / nbLoops, (j + 1) / nbLoops));\n                    texCoords.setFaceVertexValue(faceIndex, 3, new Vec2((i + 1) / nbLoops, j / nbLoops));\n                    faceIndex++;\n                }\n            }\n        }\n        this.resize();\n    }\n    /**\n     * The resize method.\n     * @private\n     */\n    resize() {\n        const innerRadius = this.innerRadiusParam.value;\n        const outerRadius = this.outerRadiusParam.value;\n        const arcAngle = this.arcAngleParam.value;\n        const detail = Math.round(this.detailParam.value);\n        const open = arcAngle < 2.0 * Math.PI;\n        const nbSlices = detail;\n        const nbLoops = detail * 2 + (open ? 1 : 0);\n        const positions = this.positions;\n        const normals = this.getVertexAttribute('normals');\n        if (!positions || !normals)\n            return;\n        let vertex = 0;\n        for (let i = 0; i < nbLoops; i++) {\n            // const theta = (i / nbLoops) * arcAngle\n            const theta = -((i / (open ? nbLoops - 1 : nbLoops)) * arcAngle);\n            const ctheta = Math.cos(theta);\n            const stheta = Math.sin(theta);\n            for (let j = 0; j < nbSlices; j++) {\n                const phi = (j / nbSlices) * 2.0 * Math.PI;\n                const sphi = Math.sin(phi);\n                const cphi = Math.cos(phi);\n                const d = outerRadius + cphi * innerRadius;\n                // Set positions and normals at the same time.\n                positions.setValue(vertex, new Vec3(ctheta * d, stheta * d, innerRadius * sphi));\n                normals.setValue(vertex, new Vec3(ctheta * cphi, stheta * cphi, sphi));\n                vertex++;\n            }\n        }\n    }\n}\nRegistry.register('Torus', Torus);\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/** Class representing a geometry parameter.\n * @extends Parameter\n * @private\n */\nclass GeometryParameter extends Parameter {\n    listenerIDs = {};\n    /**\n     * Create a geometry parameter.\n     * @param name - The name of the color parameter.\n     * @param value - The value of the parameter.\n     */\n    constructor(name = '', value = null) {\n        super(name, null, 'Geometry');\n        if (value)\n            this.setValue(value);\n    }\n    emitBoundingBoxDirtied(event) {\n        this.emit('boundingBoxChanged', event);\n    }\n    /**\n     * The setValue method.\n     * @param value - The geom value.\n     */\n    setValue(value) {\n        if (value != null && !(value instanceof BaseGeom) && !(value instanceof BaseProxy)) {\n            throw new Error(`value provided is not an instance of a 'BaseGeom' or 'BaseProxy' class. Check the source of this value`);\n        }\n        // 0 == normal set. 1 = changed via cleaner fn, 2 = change by loading/cloning code.\n        if (this.value !== value) {\n            if (this.value) {\n                if (this.value instanceof BaseGeom)\n                    this.value.setOwner(null);\n                else if (this.value instanceof BaseProxy)\n                    this.value.removeRef(this);\n                this.value.off('boundingBoxChanged', this.listenerIDs['boundingBoxChanged']);\n            }\n            super.setValue(value);\n            if (this.value instanceof BaseGeom)\n                this.value.setOwner(this);\n            else if (this.value instanceof BaseProxy)\n                this.value.addRef(this);\n            this.listenerIDs['boundingBoxChanged'] = this.value.on('boundingBoxChanged', (event) => {\n                this.emitBoundingBoxDirtied(event);\n            });\n        }\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * The loadValue is used to change the value of a parameter, without triggering a\n     * valueChanges, or setting the USER_EDITED state.\n     *\n     * @param value - The context value.\n     */\n    loadValue(value) {\n        this.setValue(value);\n    }\n    /**\n     * The toJSON method encodes this type as a json object for persistence.\n     * @param context - The context value.\n     * @return - Returns the json object.\n     */\n    toJSON(context) {\n        const j = {\n            type: this.getClassName(),\n            name: this.name,\n        };\n        const geom = this.value;\n        if (geom instanceof BaseProxy) {\n            j.libraryIndex = geom.libraryIndex;\n        }\n        else {\n            j.value = geom?.toJSON(context);\n        }\n        return j;\n    }\n    /**\n     * The fromJSON method decodes a json object for this type.\n     * @param j - The json object this item must decode.\n     * @param context - The context value.\n     */\n    fromJSON(j, context) {\n        if (j.name)\n            this.name = j.name;\n        if (j.libraryIndex != undefined) {\n            const geomLibrary = context.assetItem.geomLibrary;\n            const newGeom = geomLibrary.getGeom(j.libraryIndex);\n            this.setValue(newGeom);\n        }\n        else if (j.value != undefined) {\n            if (!this.value || this.value.getClassName() != j.value.type) {\n                const newGeom = Registry.constructClass(j.value.type);\n                newGeom.fromJSON(j.value, context);\n                this.setValue(newGeom);\n            }\n            else {\n                this.value.fromJSON(j.value, context);\n                this.emit('valueChanged');\n            }\n        }\n    }\n    // ////////////////////////////////////////\n    // Clone and Destroy\n    /**\n     * The clone method constructs a new geometry parameter, copies its values\n     * from this parameter and returns it.\n     * @return - Returns a new geometry parameter.\n     */\n    clone() {\n        const clonedParam = new GeometryParameter(this.name, this.value);\n        return clonedParam;\n    }\n}\nRegistry.register('GeometryParameter', GeometryParameter);\n\n// let ResourceLoaderWorker = require(\"worker-loader?inline!./ResourceLoaderWorker.js\");\n/**\n * Represents a BaseImage with the ability to load data.\n *\n * **Events**\n * * **loaded:** Triggered when the data is loaded.\n * * **updated:** Triggered when the data is updated.\n * @extends BaseImage\n */\nclass DataImage extends BaseImage {\n    __data = new Uint8Array(4);\n    /**\n     * Create a data image.\n     * @param name - The name value.\n     */\n    constructor(name) {\n        super(name);\n        this.format = 'RGBA';\n        this.type = 'UNSIGNED_BYTE';\n        // this.__data = new Uint8Array(4);\n        this.width = 1;\n        this.height = 1;\n    }\n    /**\n     * Returns an indicator of current item's loaded state.\n     * @return - `true` if bytes data is fully loaded, `false` otherwise.\n     */\n    isLoaded() {\n        return this.loaded;\n    }\n    // TODO: video / webcam will return true.\n    /**\n     * Images are static content, so the value for this method is always going to be `false`\n     *\n     * @return - The return value.\n     */\n    isStream() {\n        return false;\n    }\n    /**\n     * Sets Image's data by recieving an bytes array.\n     *\n     * @param width - The width value.\n     * @param height - The height value.\n     * @param data - The data value.\n     */\n    setData(width, height, data) {\n        if (this.__data == data)\n            return;\n        this.width = width;\n        this.height = height;\n        this.__data = data;\n        if (!this.loaded) {\n            this.loaded = true;\n            this.emit('loaded');\n        }\n        else\n            this.emit('updated');\n    }\n    /**\n     * Returns all parameters and class state values(Including data).\n     *\n     * @return - The return value.\n     */\n    getParams() {\n        const params = super.getParams();\n        params['data'] = this.__data;\n        return params;\n    }\n}\nRegistry.register('DataImage2D', DataImage);\nRegistry.register('DataImage', DataImage);\n\n// Cache of any images already loaded.\nconst imageDataLibrary$1 = {};\n/** Class representing a file image.\n * @extends BaseImage\n */\nclass FileImage extends BaseImage {\n    crossOrigin;\n    url;\n    __data = null;\n    /**\n     * Create a file image.\n     * @param name - The name value.\n     * @param filePath - The filePath value.\n     * @param params - The params value.\n     */\n    constructor(name, filePath = '', params = {}) {\n        super(name);\n        this.type = 'UNSIGNED_BYTE';\n        this.crossOrigin = 'anonymous';\n        if (filePath && filePath != '')\n            this.load(filePath);\n    }\n    /**\n     * Defines how to handle cross origin request.\n     *\n     * **Possible values:**\n     * * **anonymous** - CORS requests for this element will have the credentials flag set to 'same-origin'.\n     * * **use-credentials** - CORS requests for this element will have the credentials flag set to 'include'.\n     * * **\"\"** - Setting the attribute name to an empty value, like crossorigin or crossorigin=\"\", is the same as anonymous.\n     *\n     * @default anonymous\n     * @param crossOrigin - The crossOrigin value.\n     */\n    setCrossOrigin(crossOrigin) {\n        this.crossOrigin = crossOrigin;\n    }\n    /**\n     * Returns the HTML DOM element used to load the image file.\n     * Be\n     * @returns { HTMLImageElement | null }\n     */\n    getDOMElement() {\n        return this.__data;\n    }\n    /**\n     * Uses the specify url to load an Image element and adds it to the data library.\n     * Sets the state of the current object.\n     *\n     * @param url - The url value.\n     * @param format - The format value.\n     * @return Returns a promise that resolves once the image is loaded.\n     */\n    load(url, format = 'RGB') {\n        return new Promise((resolve, reject) => {\n            if (!format) {\n                // Try to guess the format from the\n                const suffixSt = url.lastIndexOf('.');\n                if (suffixSt != -1) {\n                    const ext = url.substring(suffixSt).toLowerCase();\n                    if (ext == '.png') {\n                        // TODO: Check webp for alpha channel..\n                        format = 'RGBA';\n                    }\n                }\n            }\n            this.format = format;\n            this.loaded = false;\n            const loaded = () => {\n                this.url = url;\n                this.width = this.__data.width;\n                this.height = this.__data.height;\n                this.loaded = true;\n                this.emit('loaded');\n                resolve();\n            };\n            if (url in imageDataLibrary$1) {\n                this.__data = imageDataLibrary$1[url];\n                if (this.__data.complete) {\n                    loaded();\n                }\n                else {\n                    this.__data.addEventListener('load', loaded);\n                    this.__data.addEventListener('error', reject);\n                }\n            }\n            else {\n                this.__data = new Image();\n                this.__data.crossOrigin = this.crossOrigin;\n                this.__data.src = url;\n                this.__data.addEventListener('load', loaded);\n                this.__data.addEventListener('error', reject);\n                imageDataLibrary$1[url] = this.__data;\n            }\n        });\n    }\n    /**\n     * Loads in Image file using the given URL\n     *\n     * @param url - The url value.\n     * @param format - The format value. Can be 'RGB' or 'RGBA' for files that contain an alpha channel. This will cause objects to be drawn using the Transparent pass.\n     */\n    setImageURL(url, format = 'RGB') {\n        this.load(url, format);\n    }\n    /**\n     * The getParams method.\n     * @return - The return value.\n     */\n    getParams() {\n        const params = super.getParams();\n        if (this.loaded) {\n            params['data'] = this.__data;\n        }\n        return params;\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * The readBinary method.\n     * @param reader - The reader param.\n     * @param context - The context param.\n     */\n    readBinary(reader, context) {\n        // super.readBinary(reader, context);\n        this.setName(reader.loadStr());\n        const filePath = reader.loadStr();\n        if (typeof filePath === 'string' && filePath != '') {\n            const basePath = context.url.substring(0, context.url.lastIndexOf('/'));\n            this.load(basePath + '/' + filePath);\n        }\n    }\n}\n/** Class representing a 2D file image.\n * @extends FileImage\n */\nclass FileImage2D extends FileImage {\n    /**\n     * Create a file image 2D.\n     * @param filePath - The filePath value.\n     * @param params - The params value.\n     */\n    constructor(filePath, params = {}) {\n        console.warn('FileImage2D is becoming deprecated in favor of simple FileImage');\n        super(filePath, params);\n    }\n}\nRegistry.register('FileImage2D', FileImage);\nRegistry.register('FileImage', FileImage);\n\n/* eslint-disable require-jsdoc */\n/**\n * Class representing a LDR (low dynamic range) image.\n *\n * ```\n * const image = new LDRImage()\n * image.load(\"https://storage.googleapis.com/zea-playground-assets/zea-engine/texture.png\")\n * ```\n *\n * **Parameters**\n * * **PreferredSize(`NumberParameter`):** _todo_\n *\n * **Events:**\n * * **loaded:** Triggered when image data is loaded.\n *\n * **File Types:** jpg, jpeg, png\n *\n * @extends FileImage\n */\nclass LDRImage extends FileImage {\n    /**\n     * Create a LDR image.\n     * @param name - The name value.\n     * @param filePath - The filePath value.\n     * @param params - The params value.\n     */\n    constructor(name, filePath, params) {\n        super(name, filePath, params);\n    }\n}\nRegistry.register('LDRImage', LDRImage);\n\n/**\n * Class representing a VLH image.\n *\n * **Events**\n * * **loaded:** Triggered when image data is loaded.\n * * **updated:** Triggered when image data is updated.\n *\n * @extends BaseImage\n */\nclass HDRImage extends BaseImage {\n    exposure = 1.0;\n    hdrTint = new Color(1, 1, 1, 1);\n    __data;\n    /**\n     * Create a VLH image.\n     * @param name - The name value.\n     * @param params - The params value.\n     */\n    constructor(name, params = {}) {\n        super(name); // TODO: used to be: super(name, params)\n        let filepath;\n        if (name != undefined && name.includes('.')) {\n            filepath = name;\n            this.setName(name.substring(name.lastIndexOf('/') + 1, name.lastIndexOf('.')));\n        }\n        this.type = 'HDR';\n        if (filepath) {\n            this.load(filepath);\n        }\n    }\n    /**\n     * The __decodeData method.\n     * @param entries - The entries value.\n     * @private\n     */\n    __decodeData(entries) {\n        return new Promise((resolve, reject) => {\n            const ldr = entries.ldr;\n            const cdm = entries.cdm;\n            // ///////////////////////////////\n            // Parse the data.\n            const blob = new Blob([ldr.buffer]);\n            const ldrPic = new Image();\n            ldrPic.onload = () => {\n                this.width = ldrPic.width;\n                this.height = ldrPic.height;\n                // console.log(resourcePath + \": [\" + this.width + \", \" + this.height + \"]\");\n                this.__data = {\n                    ldr: ldrPic,\n                    cdm: cdm,\n                };\n                if (!this.loaded) {\n                    this.loaded = true;\n                    this.emit('loaded');\n                }\n                else {\n                    this.emit('updated');\n                }\n                resolve();\n            };\n            ldrPic.src = URL.createObjectURL(blob);\n        });\n    }\n    /**\n     * Loads a vlh file given a URL.\n     * @param url - The URL of the vlh file to load\n     * @return - Returns a promise that resolves once the initial load is complete\n     */\n    load(url) {\n        this.loaded = false;\n        return new Promise((resolve, reject) => {\n            const filename = url.lastIndexOf('/') > -1 ? url.substring(url.lastIndexOf('/') + 1) : '';\n            const stem = filename.substring(0, filename.lastIndexOf('.'));\n            if (this.getName() == '') {\n                this.setName(stem);\n            }\n            this.type = 'FLOAT';\n            resourceLoader.loadFile('archive', url).then((entries) => {\n                if (!entries.ldr || !entries.cdm) {\n                    for (const name in entries) {\n                        if (name.endsWith('.jpg')) {\n                            entries.ldr = entries[name];\n                            delete entries[name];\n                        }\n                        else if (name.endsWith('.bin')) {\n                            entries.cdm = entries[name];\n                            delete entries[name];\n                        }\n                    }\n                }\n                this.__decodeData(entries).then(() => {\n                    resolve();\n                });\n            }, (error) => {\n                this.emit('error', error);\n                reject(error);\n            });\n        });\n    }\n    /**\n     * Returns if the data is a stream or not.\n     *\n     * @return - The return value.\n     */\n    isStream() {\n        return false;\n    }\n    /**\n     * Returns all parameters and class state values.\n     *\n     * @return - The return value.\n     */\n    getParams() {\n        const params = super.getParams();\n        if (this.loaded) {\n            params['data'] = this.__data;\n            params['exposure'] = this.exposure;\n        }\n        return params;\n    }\n    /**\n     * The setHDRTint method.\n     * @private\n     * @param hdrTint - The hdrTint value.\n     */\n    setHDRTint(hdrTint) {\n        this.hdrTint = hdrTint;\n    }\n    /**\n     * The getHDRTint method.\n     * @private\n     * @return - The return value.\n     */\n    getHDRTint() {\n        return this.hdrTint;\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * Sets state of current Image using a binary reader object, and adds it to the resource loader.\n     *\n     * @param reader - The reader value.\n     * @param context - The context value.\n     */\n    readBinary(reader, context) {\n        // super.readBinary(reader, context);\n        this.setName(reader.loadStr());\n        let url = reader.loadStr();\n        if (typeof url === 'string' && url != '') {\n            this.load(url);\n        }\n    }\n}\nRegistry.register('HDRImage', HDRImage);\n\n/**\n * Class representing a LDR (low dynamic range) video.\n *\n * ```\n * const video = new LDRVideo()\n * video.load(\"https://storage.googleapis.com/zea-playground-assets/zea-engine/video.mp4\")\n * ```\n *\n * **Parameters**\n * * **Mute(`BooleanParameter`):** Mutes video volume.\n * * **Loop(`BooleanParameter`):** Repeats video over and over again.\n * * **Gain(`NumberParameter`):** Sets loudness of the video before going through any processing.\n * * **SpatializeAudio(`BooleanParameter`):** Enables/Disables spatial(Surrounding) audio.\n * * **refDistance(`NumberParameter`):** _todo_\n * * **maxDistance(`NumberParameter`):** _todo_\n * * **rolloffFactor(`NumberParameter`):** _todo_\n * * **coneInnerAngle(`NumberParameter`):** _todo_\n * * **coneOuterAngle(`NumberParameter`):** _todo_\n * * **coneOuterGain(`NumberParameter`):** _todo_\n *\n * **File Types:** mp4, ogg\n *\n * @extends FileImage\n */\nclass LDRVideo extends FileImage {\n    videoElem = new HTMLVideoElement();\n    muteParam = new BooleanParameter('Mute', false);\n    loopParam = new BooleanParameter('Loop', true);\n    spatializeAudioParam = new BooleanParameter('SpatializeAudio', true);\n    refDistanceParam = new NumberParameter('refDistance', 2);\n    maxDistanceParam = new NumberParameter('maxDistance', 10000);\n    rolloffFactorParam = new NumberParameter('rolloffFactor', 1);\n    coneInnerAngleParam = new NumberParameter('coneInnerAngle', 360);\n    coneOuterAngleParam = new NumberParameter('coneOuterAngle', 0);\n    coneOuterGainParam = new NumberParameter('coneOuterGain', 1);\n    gainParam = new NumberParameter('Gain', 2.0);\n    /**\n     * Create a LDR video.\n     * @param name - The name value.\n     * @param filePath - The filePath value.\n     * @param params - The params value.\n     */\n    constructor(name, filePath, params) {\n        super(name, filePath, params);\n        this.format = 'RGB';\n        this.type = 'UNSIGNED_BYTE';\n        this.addParameter(this.muteParam);\n        this.addParameter(this.loopParam);\n        this.addParameter(this.spatializeAudioParam);\n        this.addParameter(this.refDistanceParam);\n        this.addParameter(this.maxDistanceParam);\n        this.addParameter(this.rolloffFactorParam);\n        this.addParameter(this.coneInnerAngleParam);\n        this.addParameter(this.coneOuterAngleParam);\n        this.addParameter(this.coneOuterGainParam);\n        this.addParameter(this.gainParam).setRange([0, 5]);\n    }\n    getAudioSource() {\n        return this.videoElem;\n    }\n    /**\n     * Uses the specify url to load an Image element and adds it to the data library.\n     * Sets the state of the current object.\n     *\n     * @param url - The url value.\n     * @param format - The format value.\n     * @return Returns a promise that resolves once the image is loaded.\n     */\n    load(url, format = 'RGB') {\n        return new Promise((resolve, reject) => {\n            resourceLoader.incrementWorkload(1);\n            // TODO - confirm its necessary to add to DOM\n            this.videoElem.style.display = 'none';\n            this.videoElem.preload = 'auto';\n            this.videoElem.crossOrigin = 'anonymous';\n            // videoElem.crossorigin = true;\n            document.body.appendChild(this.videoElem);\n            this.videoElem.addEventListener('loadedmetadata', () => {\n                // videoElem.play();\n                this.videoElem.muted = this.muteParam.value;\n                this.muteParam.on('valueChanged', () => {\n                    this.videoElem.muted = this.muteParam.value;\n                });\n                this.videoElem.loop = this.loopParam.value;\n                this.loopParam.on('valueChanged', () => {\n                    this.videoElem.loop = this.loopParam.value;\n                });\n                this.width = this.videoElem.videoHeight;\n                this.height = this.videoElem.videoWidth;\n                this.loaded = true;\n                resourceLoader.incrementWorkDone(1);\n                this.emit('loaded');\n                resolve(promise);\n                let prevFrame = 0;\n                const frameRate = 29.97;\n                const timerCallback = () => {\n                    if (this.videoElem.paused || this.videoElem.ended) {\n                        return;\n                    }\n                    // Check to see if the video has progressed to the next frame.\n                    // If so, then we emit and update, which will cause a redraw.\n                    const currentFrame = Math.floor(this.videoElem.currentTime * frameRate);\n                    if (prevFrame != currentFrame) {\n                        this.emit('updated');\n                        prevFrame = currentFrame;\n                    }\n                    setTimeout(timerCallback, 20); // Sample at 50fps.\n                };\n                timerCallback();\n            }, false);\n            this.videoElem.src = url;\n            // this.videoElem.load();\n            const promise = this.videoElem.play();\n            if (promise !== undefined) {\n                promise\n                    .then((_) => {\n                    console.log('Autoplay started!');\n                    // Autoplay started!\n                })\n                    .catch(() => {\n                    console.log('Autoplay was prevented.');\n                    // Autoplay was prevented.\n                    // Show a \"Play\" button so that user can start playback.\n                });\n            }\n        });\n    }\n    /**\n     * The getParams method.\n     * @return - The return value.\n     */\n    getParams() {\n        const params = super.getParams();\n        if (this.loaded) {\n            params['data'] = this.videoElem;\n        }\n        return params;\n    }\n}\nRegistry.register('LDRVideo', LDRVideo);\n\n//@ts-nocheck\n// Stream object for reading off bytes from a byte array\nfunction ByteStream(data) {\n    this.data = data;\n    this.pos = 0;\n}\n// read the next byte off the stream\nByteStream.prototype.readByte = function () {\n    return this.data[this.pos++];\n};\n// look at the next byte in the stream without updating the stream position\nByteStream.prototype.peekByte = function () {\n    return this.data[this.pos];\n};\n// read an array of bytes\nByteStream.prototype.readBytes = function (n) {\n    var bytes = new Array(n);\n    for (var i = 0; i < n; i++) {\n        bytes[i] = this.readByte();\n    }\n    return bytes;\n};\n// peek at an array of bytes without updating the stream position\nByteStream.prototype.peekBytes = function (n) {\n    var bytes = new Array(n);\n    for (var i = 0; i < n; i++) {\n        bytes[i] = this.data[this.pos + i];\n    }\n    return bytes;\n};\n// read a string from a byte set\nByteStream.prototype.readString = function (len) {\n    var str = '';\n    for (var i = 0; i < len; i++) {\n        str += String.fromCharCode(this.readByte());\n    }\n    return str;\n};\n// read a single byte and return an array of bit booleans\nByteStream.prototype.readBitArray = function () {\n    var arr = [];\n    var bite = this.readByte();\n    for (var i = 7; i >= 0; i--) {\n        arr.push(!!(bite & (1 << i)));\n    }\n    return arr;\n};\n// read an unsigned int with endian option\nByteStream.prototype.readUnsigned = function (littleEndian) {\n    var a = this.readBytes(2);\n    if (littleEndian) {\n        return (a[1] << 8) + a[0];\n    }\n    else {\n        return (a[0] << 8) + a[1];\n    }\n};\nfunction DataParser(data) {\n    //@ts-ignore\n    this.stream = new ByteStream(data);\n    // the final parsed object from the data\n    this.output = {};\n}\nDataParser.prototype.parse = function (schema) {\n    // the top level schema is just the top level parts array\n    this.parseParts(this.output, schema);\n    return this.output;\n};\n// parse a set of hierarchy parts providing the parent object, and the subschema\nDataParser.prototype.parseParts = function (obj, schema) {\n    for (var i = 0; i < schema.length; i++) {\n        var part = schema[i];\n        this.parsePart(obj, part);\n    }\n};\nDataParser.prototype.parsePart = function (obj, part) {\n    var name = part.label;\n    var value;\n    // make sure the part meets any parse requirements\n    if (part.requires && !part.requires(this.stream, this.output, obj)) {\n        return;\n    }\n    if (part.loop) {\n        // create a parse loop over the parts\n        var items = [];\n        while (part.loop(this.stream)) {\n            var item = {};\n            this.parseParts(item, part.parts);\n            items.push(item);\n        }\n        obj[name] = items;\n    }\n    else if (part.parts) {\n        // process any child parts\n        value = {};\n        this.parseParts(value, part.parts);\n        obj[name] = value;\n    }\n    else if (part.parser) {\n        // parse the value using a parser\n        value = part.parser(this.stream, this.output, obj);\n        if (!part.skip) {\n            obj[name] = value;\n        }\n    }\n    else if (part.bits) {\n        // convert the next byte to a set of bit fields\n        obj[name] = this.parseBits(part.bits);\n    }\n};\n// combine bits to calculate value\nfunction bitsToNum(bitArray) {\n    return bitArray.reduce(function (s, n) {\n        return s * 2 + n;\n    }, 0);\n}\n// parse a byte as a bit set (flags and values)\nDataParser.prototype.parseBits = function (details) {\n    var out = {};\n    var bits = this.stream.readBitArray();\n    for (var key in details) {\n        var item = details[key];\n        if (item.length) {\n            // convert the bit set to value\n            out[key] = bitsToNum(bits.slice(item.index, item.index + item.length));\n        }\n        else {\n            out[key] = bits[item.index];\n        }\n    }\n    return out;\n};\n// a set of common parsers used with DataParser\nvar Parsers = {\n    // read a byte\n    readByte: function () {\n        return function (stream) {\n            return stream.readByte();\n        };\n    },\n    // read an array of bytes\n    readBytes: function (length) {\n        return function (stream) {\n            return stream.readBytes(length);\n        };\n    },\n    // read a string from bytes\n    readString: function (length) {\n        return function (stream) {\n            return stream.readString(length);\n        };\n    },\n    // read an unsigned int (with endian)\n    readUnsigned: function (littleEndian) {\n        return function (stream) {\n            return stream.readUnsigned(littleEndian);\n        };\n    },\n    // read an array of byte sets\n    readArray: function (size, countFunc) {\n        return function (stream, obj, parent) {\n            var count = countFunc(stream, obj, parent);\n            var arr = new Array(count);\n            for (var i = 0; i < count; i++) {\n                arr[i] = stream.readBytes(size);\n            }\n            return arr;\n        };\n    },\n};\n// object used to represent array buffer data for a gif file\n// a set of 0x00 terminated subblocks\nvar subBlocks = {\n    label: 'blocks',\n    parser: function (stream) {\n        var out = [];\n        var terminator = 0x00;\n        for (var size = stream.readByte(); size !== terminator; size = stream.readByte()) {\n            out = out.concat(stream.readBytes(size));\n        }\n        return out;\n    },\n};\n// global control extension\nvar gce = {\n    label: 'gce',\n    requires: function (stream) {\n        // just peek at the top two bytes, and if true do this\n        var codes = stream.peekBytes(2);\n        return codes[0] === 0x21 && codes[1] === 0xf9;\n    },\n    parts: [\n        { label: 'codes', parser: Parsers.readBytes(2), skip: true },\n        { label: 'byteSize', parser: Parsers.readByte() },\n        {\n            label: 'extras',\n            bits: {\n                future: { index: 0, length: 3 },\n                disposal: { index: 3, length: 3 },\n                userInput: { index: 6 },\n                transparentColorGiven: { index: 7 },\n            },\n        },\n        { label: 'delay', parser: Parsers.readUnsigned(true) },\n        { label: 'transparentColorIndex', parser: Parsers.readByte() },\n        { label: 'terminator', parser: Parsers.readByte(), skip: true },\n    ],\n};\n// image pipeline block\nvar image = {\n    label: 'image',\n    requires: function (stream) {\n        // peek at the next byte\n        var code = stream.peekByte();\n        return code === 0x2c;\n    },\n    parts: [\n        { label: 'code', parser: Parsers.readByte(), skip: true },\n        {\n            label: 'descriptor', // image descriptor\n            parts: [\n                { label: 'left', parser: Parsers.readUnsigned(true) },\n                { label: 'top', parser: Parsers.readUnsigned(true) },\n                { label: 'width', parser: Parsers.readUnsigned(true) },\n                { label: 'height', parser: Parsers.readUnsigned(true) },\n                {\n                    label: 'lct',\n                    bits: {\n                        exists: { index: 0 },\n                        interlaced: { index: 1 },\n                        sort: { index: 2 },\n                        future: { index: 3, length: 2 },\n                        size: { index: 5, length: 3 },\n                    },\n                },\n            ],\n        },\n        {\n            label: 'lct', // optional local color table\n            requires: function (stream, obj, parent) {\n                return parent.descriptor.lct.exists;\n            },\n            parser: Parsers.readArray(3, function (stream, obj, parent) {\n                return Math.pow(2, parent.descriptor.lct.size + 1);\n            }),\n        },\n        {\n            label: 'data', // the image data blocks\n            parts: [{ label: 'minCodeSize', parser: Parsers.readByte() }, subBlocks],\n        },\n    ],\n};\n// plain text block\nvar text = {\n    label: 'text',\n    requires: function (stream) {\n        // just peek at the top two bytes, and if true do this\n        var codes = stream.peekBytes(2);\n        return codes[0] === 0x21 && codes[1] === 0x01;\n    },\n    parts: [\n        { label: 'codes', parser: Parsers.readBytes(2), skip: true },\n        { label: 'blockSize', parser: Parsers.readByte() },\n        {\n            label: 'preData',\n            parser: function (stream, obj, parent) {\n                return stream.readBytes(parent.text.blockSize);\n            },\n        },\n        subBlocks,\n    ],\n};\n// application block\nvar application = {\n    label: 'application',\n    requires: function (stream, obj, parent) {\n        // make sure this frame doesn't already have a gce, text, comment, or image\n        // as that means this block should be attached to the next frame\n        //if(parent.gce || parent.text || parent.image || parent.comment){ return false; }\n        // peek at the top two bytes\n        var codes = stream.peekBytes(2);\n        return codes[0] === 0x21 && codes[1] === 0xff;\n    },\n    parts: [\n        { label: 'codes', parser: Parsers.readBytes(2), skip: true },\n        { label: 'blockSize', parser: Parsers.readByte() },\n        {\n            label: 'id',\n            parser: function (stream, obj, parent) {\n                return stream.readString(parent.blockSize);\n            },\n        },\n        subBlocks,\n    ],\n};\n// comment block\nvar comment = {\n    label: 'comment',\n    requires: function (stream, obj, parent) {\n        // make sure this frame doesn't already have a gce, text, comment, or image\n        // as that means this block should be attached to the next frame\n        //if(parent.gce || parent.text || parent.image || parent.comment){ return false; }\n        // peek at the top two bytes\n        var codes = stream.peekBytes(2);\n        return codes[0] === 0x21 && codes[1] === 0xfe;\n    },\n    parts: [{ label: 'codes', parser: Parsers.readBytes(2), skip: true }, subBlocks],\n};\n// frames of ext and image data\nvar frames = {\n    label: 'frames',\n    parts: [gce, application, comment, image, text],\n    loop: function (stream) {\n        var nextCode = stream.peekByte();\n        // rather than check for a terminator, we should check for the existence\n        // of an ext or image block to avoid infinite loops\n        //var terminator = 0x3B;\n        //return nextCode !== terminator;\n        return nextCode === 0x21 || nextCode === 0x2c;\n    },\n};\n// main GIF schema\nvar schemaGIF = [\n    {\n        label: 'header', // gif header\n        parts: [\n            { label: 'signature', parser: Parsers.readString(3) },\n            { label: 'version', parser: Parsers.readString(3) },\n        ],\n    },\n    {\n        label: 'lsd', // local screen descriptor\n        parts: [\n            { label: 'width', parser: Parsers.readUnsigned(true) },\n            { label: 'height', parser: Parsers.readUnsigned(true) },\n            {\n                label: 'gct',\n                bits: {\n                    exists: { index: 0 },\n                    resolution: { index: 1, length: 3 },\n                    sort: { index: 4 },\n                    size: { index: 5, length: 3 },\n                },\n            },\n            { label: 'backgroundColorIndex', parser: Parsers.readByte() },\n            { label: 'pixelAspectRatio', parser: Parsers.readByte() },\n        ],\n    },\n    {\n        label: 'gct', // global color table\n        requires: function (stream, obj) {\n            return obj.lsd.gct.exists;\n        },\n        parser: Parsers.readArray(3, function (stream, obj) {\n            return Math.pow(2, obj.lsd.gct.size + 1);\n        }),\n    },\n    frames, // content frames\n];\nvar gifSchema = schemaGIF;\nfunction GIF(arrayBuffer) {\n    // convert to byte array\n    var byteData = new Uint8Array(arrayBuffer);\n    //@ts-ignore\n    var parser = new DataParser(byteData);\n    // parse the data\n    this.raw = parser.parse(gifSchema);\n    // set a flag to make sure the gif contains at least one image\n    this.raw.hasImages = false;\n    for (var f = 0; f < this.raw.frames.length; f++) {\n        if (this.raw.frames[f].image) {\n            this.raw.hasImages = true;\n            break;\n        }\n    }\n}\n// process a single gif image frames data, decompressing it using LZW\n// if buildPatch is true, the returned image will be a clamped 8 bit image patch\n// for use directly with a canvas.\nGIF.prototype.decompressFrame = function (index, buildPatch) {\n    // make sure a valid frame is requested\n    if (index >= this.raw.frames.length) {\n        return null;\n    }\n    var frame = this.raw.frames[index];\n    if (frame.image) {\n        // get the number of pixels\n        var totalPixels = frame.image.descriptor.width * frame.image.descriptor.height;\n        // do lzw decompression\n        var pixels = lzw(frame.image.data.minCodeSize, frame.image.data.blocks, totalPixels);\n        // deal with interlacing if necessary\n        if (frame.image.descriptor.lct.interlaced) {\n            pixels = deinterlace(pixels, frame.image.descriptor.width);\n        }\n        // setup usable image object\n        var image = {\n            pixels: pixels,\n            dims: {\n                top: frame.image.descriptor.top,\n                left: frame.image.descriptor.left,\n                width: frame.image.descriptor.width,\n                height: frame.image.descriptor.height,\n            },\n        };\n        // color table\n        if (frame.image.descriptor.lct && frame.image.descriptor.lct.exists) {\n            image.colorTable = frame.image.lct;\n        }\n        else {\n            image.colorTable = this.raw.gct;\n        }\n        // add per frame relevant gce information\n        if (frame.gce) {\n            image.delay = (frame.gce.delay || 10) * 10; // convert to ms\n            image.disposalType = frame.gce.extras.disposal;\n            // transparency\n            if (frame.gce.extras.transparentColorGiven) {\n                image.transparentIndex = frame.gce.transparentColorIndex;\n            }\n        }\n        // create canvas usable imagedata if desired\n        if (buildPatch) {\n            image.patch = generatePatch(image);\n        }\n        return image;\n    }\n    // frame does not contains image\n    return null;\n    /**\n     * javascript port of java LZW decompression\n     * Original java author url: https://gist.github.com/devunwired/4479231\n     */\n    function lzw(minCodeSize, data, pixelCount) {\n        var MAX_STACK_SIZE = 4096;\n        var nullCode = -1;\n        var npix = pixelCount;\n        var available, clear, code_mask, code_size, end_of_information, in_code, old_code, bits, code, i, datum, data_size, first, top, bi, pi;\n        var dstPixels = new Array(pixelCount);\n        var prefix = new Array(MAX_STACK_SIZE);\n        var suffix = new Array(MAX_STACK_SIZE);\n        var pixelStack = new Array(MAX_STACK_SIZE + 1);\n        // Initialize GIF data stream decoder.\n        data_size = minCodeSize;\n        clear = 1 << data_size;\n        end_of_information = clear + 1;\n        available = clear + 2;\n        old_code = nullCode;\n        code_size = data_size + 1;\n        code_mask = (1 << code_size) - 1;\n        for (code = 0; code < clear; code++) {\n            prefix[code] = 0;\n            suffix[code] = code;\n        }\n        // Decode GIF pixel stream.\n        datum = bits = first = top = pi = bi = 0;\n        for (i = 0; i < npix;) {\n            if (top === 0) {\n                if (bits < code_size) {\n                    // get the next byte\n                    datum += data[bi] << bits;\n                    bits += 8;\n                    bi++;\n                    continue;\n                }\n                // Get the next code.\n                code = datum & code_mask;\n                datum >>= code_size;\n                bits -= code_size;\n                // Interpret the code\n                if (code > available || code == end_of_information) {\n                    break;\n                }\n                if (code == clear) {\n                    // Reset decoder.\n                    code_size = data_size + 1;\n                    code_mask = (1 << code_size) - 1;\n                    available = clear + 2;\n                    old_code = nullCode;\n                    continue;\n                }\n                if (old_code == nullCode) {\n                    pixelStack[top++] = suffix[code];\n                    old_code = code;\n                    first = code;\n                    continue;\n                }\n                in_code = code;\n                if (code == available) {\n                    pixelStack[top++] = first;\n                    code = old_code;\n                }\n                while (code > clear) {\n                    pixelStack[top++] = suffix[code];\n                    code = prefix[code];\n                }\n                first = suffix[code] & 0xff;\n                pixelStack[top++] = first;\n                // add a new string to the table, but only if space is available\n                // if not, just continue with current table until a clear code is found\n                // (deferred clear code implementation as per GIF spec)\n                if (available < MAX_STACK_SIZE) {\n                    prefix[available] = old_code;\n                    suffix[available] = first;\n                    available++;\n                    if ((available & code_mask) === 0 && available < MAX_STACK_SIZE) {\n                        code_size++;\n                        code_mask += available;\n                    }\n                }\n                old_code = in_code;\n            }\n            // Pop a pixel off the pixel stack.\n            top--;\n            dstPixels[pi++] = pixelStack[top];\n            i++;\n        }\n        for (i = pi; i < npix; i++) {\n            dstPixels[i] = 0; // clear missing pixels\n        }\n        return dstPixels;\n    }\n    // deinterlace function from https://github.com/shachaf/jsgif\n    function deinterlace(pixels, width) {\n        var newPixels = new Array(pixels.length);\n        var rows = pixels.length / width;\n        var cpRow = function (toRow, fromRow) {\n            var fromPixels = pixels.slice(fromRow * width, (fromRow + 1) * width);\n            newPixels.splice.apply(newPixels, [toRow * width, width].concat(fromPixels));\n        };\n        // See appendix E.\n        var offsets = [0, 4, 2, 1];\n        var steps = [8, 8, 4, 2];\n        var fromRow = 0;\n        for (var pass = 0; pass < 4; pass++) {\n            for (var toRow = offsets[pass]; toRow < rows; toRow += steps[pass]) {\n                cpRow(toRow, fromRow);\n                fromRow++;\n            }\n        }\n        return newPixels;\n    }\n    // create a clamped byte array patch for the frame image to be used directly with a canvas\n    // TODO: could potentially squeeze some performance by doing a direct 32bit write per iteration\n    function generatePatch(image) {\n        var totalPixels = image.pixels.length;\n        var patchData = new Uint8ClampedArray(totalPixels * 4);\n        for (var i = 0; i < totalPixels; i++) {\n            var pos = i * 4;\n            var colorIndex = image.pixels[i];\n            var color = image.colorTable[colorIndex];\n            patchData[pos] = color[0];\n            patchData[pos + 1] = color[1];\n            patchData[pos + 2] = color[2];\n            patchData[pos + 3] = colorIndex !== image.transparentIndex ? 255 : 0;\n        }\n        return patchData;\n    }\n};\n// returns all frames decompressed\nGIF.prototype.decompressFrames = function (buildPatch) {\n    var frames = [];\n    for (var i = 0; i < this.raw.frames.length; i++) {\n        var frame = this.raw.frames[i];\n        if (frame.image) {\n            frames.push(this.decompressFrame(i, buildPatch));\n        }\n    }\n    return frames;\n};\n\n/* eslint-disable prefer-promise-reject-errors */\nconst imageDataLibrary = {};\n/**\n * Class representing a GIF image.\n *\n * ```\n * const image = new GIFImage()\n * image.load(\"https://storage.googleapis.com/zea-playground-assets/zea-engine/texture.gif\")\n * ```\n *\n * **Parameters**\n * * **StreamAtlasDesc:**\n * * **StreamAtlasIndex:**\n *\n * **Events**\n * * **loaded:** Triggered when the gif data is loaded.\n *\n * **File Types:** gif\n *\n * @extends FileImage\n */\nclass GIFImage extends FileImage {\n    __streamAtlas;\n    play;\n    stop;\n    __resourcePromise;\n    __unpackedData;\n    streamAtlasDescParam = new Vec4Parameter('StreamAtlasDesc');\n    streamAtlasIndexParam = new NumberParameter('StreamAtlasIndex', 0);\n    /**\n     * Create a GIF image.\n     * @param name - The name value.\n     * @param filePath - The filePath value.\n     * @param params - The params value.\n     */\n    constructor(name, filePath = '', params = {}) {\n        super(name, filePath, params);\n        this.format = 'RGBA';\n        this.type = 'UNSIGNED_BYTE';\n        this.__streamAtlas = true;\n        this.addParameter(this.streamAtlasDescParam);\n        this.addParameter(this.streamAtlasIndexParam);\n        const frameParam = this.streamAtlasIndexParam;\n        frameParam.setRange([0, 1]);\n        let playing;\n        let frame = 0;\n        const incrementFrame = (numFrames) => {\n            frameParam.value = frame;\n            if (playing)\n                setTimeout(() => incrementFrame(numFrames), this.getFrameDelay(frame));\n            frame = (frame + 1) % numFrames;\n        };\n        this.play = () => {\n            this.__resourcePromise.then(() => {\n                playing = true;\n                let frameParam_check = frameParam.getRange();\n                if (!frameParam_check) {\n                    // should range be always be intialized?\n                    console.warn('numFrames is null');\n                    return;\n                }\n                const numFrames = frameParam_check[1];\n                incrementFrame(numFrames);\n            });\n        };\n        this.stop = () => {\n            playing = false;\n        };\n    }\n    /**\n     * The getFrameDelay method.\n     * @param index - The index value.\n     * @return - The return value.\n     */\n    getFrameDelay(index) {\n        // Note: Frame delays are in centisecs (not millisecs which the timers will require.)\n        return this.__unpackedData.frameDelays[index] * 10;\n    }\n    /**\n     * Uses the specify url to load an Image element and adds it to the data library.\n     * Sets the state of the current object.\n     *\n     * @param url - The url value.\n     * @param format - The format value.\n     * @return Returns a promise that resolves once the image is loaded.\n     */\n    load(url, format = 'RGB') {\n        // this.__streamAtlasDesc = new Vec4();\n        if (url in imageDataLibrary) {\n            this.__resourcePromise = imageDataLibrary[url];\n            return this.__resourcePromise;\n        }\n        else {\n            this.__resourcePromise = new Promise((resolve, reject) => {\n                resourceLoader.incrementWorkload(1);\n                // if (fileDesc.assets && fileDesc.assets.atlas) {\n                //   const imageElem = new Image()\n                //   imageElem.crossOrigin = 'anonymous'\n                //   imageElem.src = fileDesc.assets.atlas.url\n                //   imageElem.addEventListener('load', () => {\n                //     resolve({\n                //       width: fileDesc.assets.atlas.width,\n                //       height: fileDesc.assets.atlas.height,\n                //       atlasSize: fileDesc.assets.atlas.atlasSize,\n                //       frameDelays: fileDesc.assets.atlas.frameDelays,\n                //       frameRange: [0, fileDesc.assets.atlas.frameDelays.length],\n                //       imageData: imageElem,\n                //     })\n                //     resourceLoader.incrementWorkDone(1)\n                //   })\n                //   return\n                // }\n                loadBinfile(url, (data) => {\n                    console.warn('Unpacking Gif client side:' + url);\n                    const start = performance.now();\n                    // Decompressing using: https://github.com/matt-way/gifuct-js\n                    //@ts-ignore\n                    const gif = new GIF(data);\n                    const frames = gif.decompressFrames(true);\n                    // do something with the frame data\n                    const sideLength = Math.sqrt(frames.length);\n                    const atlasSize = [sideLength, sideLength];\n                    if (MathFunctions.fract(sideLength) > 0.0) {\n                        atlasSize[0] = Math.floor(atlasSize[0] + 1);\n                        if (MathFunctions.fract(sideLength) > 0.5) {\n                            atlasSize[1] = Math.floor(atlasSize[1] + 1);\n                        }\n                        else {\n                            atlasSize[1] = Math.floor(atlasSize[1]);\n                        }\n                    }\n                    const width = frames[0].dims.width;\n                    const height = frames[0].dims.height;\n                    // gif patch canvas\n                    const tempCanvas = document.createElement('canvas');\n                    const tempCtx = tempCanvas.getContext('2d');\n                    // full gif canvas\n                    const gifCanvas = document.createElement('canvas');\n                    const gifCtx = gifCanvas.getContext('2d');\n                    gifCanvas.width = width;\n                    gifCanvas.height = height;\n                    // The atlas for all the frames.\n                    const atlasCanvas = document.createElement('canvas');\n                    const atlasCtx = atlasCanvas.getContext('2d');\n                    atlasCanvas.width = atlasSize[0] * width;\n                    atlasCanvas.height = atlasSize[1] * height;\n                    let frameImageData;\n                    const frameDelays = [];\n                    const renderFrame = (frame, index) => {\n                        const dims = frame.dims;\n                        // Note: the server side library returns centisecs (1/100 second) for\n                        // frame delays, so normalize here so that client and servers\n                        // valueus are in the\n                        frameDelays.push(frame.delay / 10);\n                        if (!frameImageData || dims.width != frameImageData.width || dims.height != frameImageData.height) {\n                            tempCanvas.width = dims.width;\n                            tempCanvas.height = dims.height;\n                            frameImageData = tempCtx?.createImageData(dims.width, dims.height);\n                        }\n                        // set the patch data as an override\n                        frameImageData.data.set(frame.patch);\n                        tempCtx?.putImageData(frameImageData, 0, 0);\n                        // Note: undocumented disposal method.\n                        // See Ids here: https://github.com/theturtle32/Flash-Animated-GIF-Library/blob/master/AS3GifPlayer/src/com/worlize/gif/constants/DisposalType.as\n                        // From what I can gather, 2 means we should clear the background first.\n                        // this seems to work with Gifs featuring moving transparency.\n                        // For fully opaque gifs, we should avoid this.\n                        if (frame.disposalType == 2)\n                            gifCtx?.clearRect(0, 0, gifCanvas.width, gifCanvas.height);\n                        gifCtx?.drawImage(tempCanvas, dims.left, dims.top);\n                        atlasCtx?.drawImage(gifCanvas, (index % atlasSize[0]) * width, Math.floor(index / atlasSize[0]) * height);\n                    };\n                    for (let i = 0; i < frames.length; i++) {\n                        // console.log(frame);\n                        renderFrame(frames[i], i);\n                    }\n                    resourceLoader.incrementWorkDone(1);\n                    const imageData = atlasCtx?.getImageData(0, 0, atlasCanvas.width, atlasCanvas.height);\n                    const ms = performance.now() - start;\n                    console.log(`Decode GIF '${url}' time:` + ms);\n                    resolve({\n                        width: atlasCanvas.width,\n                        height: atlasCanvas.height,\n                        atlasSize,\n                        frameRange: [0, frames.length],\n                        frameDelays,\n                        imageData,\n                    });\n                }, (statusText) => {\n                    const msg = 'Unable to Load URL:' + statusText + ':' + url;\n                    console.warn(msg);\n                    reject(msg);\n                });\n            });\n            imageDataLibrary[url] = this.__resourcePromise;\n        }\n        this.__resourcePromise.then((unpackedData) => {\n            this.width = unpackedData.width;\n            this.height = unpackedData.height;\n            this.streamAtlasDescParam.value = new Vec4(unpackedData.atlasSize[0], unpackedData.atlasSize[1], 0, 0);\n            this.streamAtlasIndexParam.setRange(unpackedData.frameRange);\n            this.__unpackedData = unpackedData;\n            this.__data = unpackedData.imageData;\n            // ////////////////////////\n            // Playback\n            this.loaded = true;\n            this.emit('loaded');\n        });\n        return this.__resourcePromise;\n    }\n}\nRegistry.register('GIFImage', GIFImage);\n\n/* eslint-disable new-cap */\n/**\n * An EnvMap can load High Dynamic Range environment map images, necessary for high quality PBR lighting.\n *\n *\n * **Parameters**\n * * **HeadLightMode(`BooleanParameter`):** Enables Headlight mode so that the environment lighting is aligned with the camera.\n * With Headlight mode on, the top of the env map is aligned with the direction of the camera, so a the view is generally well lit.\n *\n * @extends HDRImage\n */\nclass EnvMap extends HDRImage {\n    utf8decoder;\n    shCoeffs;\n    luminanceData;\n    headlightModeParam = new BooleanParameter('HeadLightMode', false);\n    /**\n     * Create an env map.\n     * @param name - The name value.\n     * @param params - The params value.\n     */\n    constructor(name, params = {}) {\n        super(name, params);\n        this.addParameter(this.headlightModeParam);\n        this.utf8decoder = new TextDecoder();\n        this.shCoeffs = [];\n    }\n    /**\n     * The __decodeData method.\n     * @param entries - The entries value.\n     * @return\n     * @private\n     */\n    __decodeData(entries) {\n        const samples = entries.samples;\n        if (samples) {\n            this.luminanceData = JSON.parse(this.utf8decoder.decode(samples));\n            if (this.luminanceData.shCoeffs) {\n                for (let i = 0; i < 9; i++) {\n                    this.shCoeffs[i] = new Color(this.luminanceData.shCoeffs[i * 3 + 0], this.luminanceData.shCoeffs[i * 3 + 1], this.luminanceData.shCoeffs[i * 3 + 2]);\n                }\n            }\n        }\n        return super.__decodeData(entries);\n    }\n    /**\n     * Calculate the luminance of the Environment in the direction.\n     *\n     * @param dir - The dir value.\n     * @return - The return value.\n     */\n    dirToLuminance(dir) {\n        // normal is assumed to have unit length\n        const x = dir.x;\n        const y = dir.y;\n        const z = dir.z;\n        // band 0\n        const result = this.shCoeffs[0].scale(0.886227);\n        // band 1\n        result.addInPlace(this.shCoeffs[1].scale(2.0 * 0.511664 * y));\n        result.addInPlace(this.shCoeffs[2].scale(2.0 * 0.511664 * z));\n        result.addInPlace(this.shCoeffs[3].scale(2.0 * 0.511664 * x));\n        // band 2\n        result.addInPlace(this.shCoeffs[4].scale(2.0 * 0.429043 * x * y));\n        result.addInPlace(this.shCoeffs[5].scale(2.0 * 0.429043 * y * z));\n        result.addInPlace(this.shCoeffs[6].scale(0.743125 * z * z - 0.247708));\n        result.addInPlace(this.shCoeffs[7].scale(2.0 * 0.429043 * x * z));\n        result.addInPlace(this.shCoeffs[8].scale(0.429043 * (x * x - y * y)));\n        return result.luminance();\n    }\n}\nRegistry.register('EnvMap', EnvMap);\n\n// eslint-disable-next-line require-jsdoc\nfunction getLanguage() {\n    if (SystemDesc.OS == 'Node')\n        return 'en';\n    // Check if a language is explicitly selected.\n    const searchParams = new URLSearchParams(globalThis.location.search);\n    if (searchParams.has('lang'))\n        return searchParams.get('lang');\n    const nav = globalThis.navigator;\n    let i;\n    let language;\n    const clean = (language) => {\n        if (language.startsWith('en'))\n            return 'En';\n        else if (language.startsWith('es'))\n            return 'Es';\n        else if (language.startsWith('fr'))\n            return 'Fr';\n        else if (language.startsWith('gb') || language.startsWith('de'))\n            return 'Gb';\n        return language;\n    };\n    // support for HTML 5.1 \"navigator.languages\"\n    if (Array.isArray(nav.languages)) {\n        for (i = 0; i < nav.languages.length; i++) {\n            language = nav.languages[i];\n            if (language && language.length) {\n                return clean(language);\n            }\n        }\n    }\n    // support for other well known properties in browsers\n    // const browserLanguagePropertyKeys = ['language', 'browserLanguage', 'systemLanguage', 'userLanguage']\n    // for (i = 0; i < browserLanguagePropertyKeys.length; i++) {\n    //   language = nav[browserLanguagePropertyKeys[i]]\n    //   if (language && language.length) {\n    //     return clean(language)\n    //   }\n    // }\n    return null;\n}\n/** Class representing a label manager.\n * @private\n */\nclass LabelManager extends EventEmitter {\n    __language;\n    __foundLabelLibraries;\n    __labelLibraries;\n    /**\n     * Create a label manager.\n     */\n    constructor() {\n        super();\n        this.__labelLibraries = {};\n        this.__language = getLanguage();\n        this.__foundLabelLibraries = {};\n    }\n    /**\n     * Load a label library into the manager.\n     * @param name - The name of the library.\n     * @param url- The json data of of the library.\n     */\n    loadLibrary(name, url) {\n        const stem = name.substring(0, name.lastIndexOf('.'));\n        this.__foundLabelLibraries[stem] = url;\n        if (name.endsWith('.labels')) {\n            loadTextfile(url, (text) => {\n                this.__labelLibraries[stem] = JSON.parse(text);\n                this.emit('labelLibraryLoaded', { library: stem });\n            });\n        }\n        else if (name.endsWith('.xlsx')) {\n            // @ts-ignore\n            const XLSX = globalThis.XLSX;\n            // Note: example taken from here..\n            // https://stackoverflow.com/questions/8238407/how-to-parse-excel-file-in-javascript-html5\n            // and here:\n            // https://github.com/SheetJS/js-xlsx/tree/master/demos/xhr\n            loadBinfile(url, (data) => {\n                const unit8array = new Uint8Array(data);\n                // @ts-ignore\n                const workbook = XLSX.read(unit8array, {\n                    type: 'array',\n                });\n                const json = {};\n                workbook.SheetNames.forEach(function (sheetName) {\n                    // Here is your object\n                    // @ts-ignore\n                    const rows = XLSX.utils.sheet_to_json(workbook.Sheets[sheetName], {});\n                    // @ts-ignore\n                    rows.forEach(function (row) {\n                        const identifier = row.Identifier;\n                        delete row.Identifier;\n                        json[identifier] = row;\n                    });\n                });\n                this.__labelLibraries[stem] = json;\n                this.emit('labelLibraryLoaded', { library: stem });\n            });\n        }\n    }\n    /**\n     * Checks if the library is found.\n     * @param name - The name of the library.\n     * @return - Returns true if the library is found.\n     */\n    isLibraryFound(name) {\n        return name in this.__foundLabelLibraries;\n    }\n    /**\n     * Checks if the library is loaded.\n     * @param name - The name of the library.\n     * @return - Returns true if the library is loaded.\n     */\n    isLibraryLoaded(name) {\n        return name in this.__labelLibraries;\n    }\n    /**\n     * The getLabelText method.\n     * @param libraryName - The name of the library.\n     * @param labelName - The name of the label.\n     * @return - The return value.\n     */\n    getLabelText(libraryName, labelName) {\n        const library = this.__labelLibraries[libraryName];\n        if (!library) {\n            throw new Error(\"LabelLibrary: '\" +\n                libraryName +\n                \"' not found in LabelManager. Found: [\" +\n                Object.keys(this.__labelLibraries) +\n                ']');\n        }\n        const label = library[labelName];\n        if (!label) {\n            throw new Error(\"Label: '\" +\n                labelName +\n                \"' not found in LabelLibrary: '\" +\n                libraryName +\n                \"'. Found: [\" +\n                Object.keys(library) +\n                ']');\n        }\n        const labelText = label[this.__language];\n        if (!labelText) {\n            if (label['En'])\n                return label['En'];\n            throw new Error(\"labelText: '\" + this.__language + \"' not found in Label. Found: [\" + Object.keys(label) + ']');\n        }\n        return labelText;\n    }\n    /**\n     * The setLabelText method.\n     * @param libraryName - The name of the library.\n     * @param labelName - The name of the label.\n     * @param labelText - The text of the label.\n     */\n    setLabelText(libraryName, labelName, labelText) {\n        let library = this.__labelLibraries[libraryName];\n        if (!library) {\n            library = {};\n            this.__labelLibraries[libraryName] = library;\n        }\n        let label = library[labelName];\n        if (!label) {\n            label = {};\n            library[labelName] = label;\n        }\n        label[this.__language] = labelText;\n        // TODO: Push to server.\n    }\n    setLanguage(ln) {\n        this.__language = ln;\n    }\n}\nconst labelManager = new LabelManager();\n\n/* eslint-disable guard-for-in */\n// http://stackoverflow.com/questions/1255512/how-to-draw-a-rounded-rectangle-on-html-canvas\n/**\n * Draws a rounded rectangle using the current state of the canvas.\n * If you omit the last three params, it will draw a rectangle\n * outline with a 5 pixel border radius\n * @param ctx\n * @param x - The top left x coordinate\n * @param y - The top left y coordinate\n * @param width - The width of the rectangle\n * @param height - The height of the rectangle\n *\n * @param radius - The corner radius; It can also be an object to specify different radii for corners\n * @param radius.tl - Top left\n * @param radius.tr - Top right\n * @param radius.br - Bottom right\n * @param radius.bl - Bottom left\n *\n * @param fill - Whether to fill the rectangle.\n * @param stroke - Whether to stroke the rectangle.\n * @param strokeWidth - The strokeWidth param.\n * @private\n */\nfunction roundRect(ctx, x, y, width, height, radius, fill = false, stroke = true, strokeWidth) {\n    if (typeof stroke == 'undefined') {\n        stroke = true;\n    }\n    if (typeof radius === 'undefined') {\n        radius = 5;\n    }\n    if (typeof radius === 'number') {\n        radius = {\n            tl: radius,\n            tr: radius,\n            br: radius,\n            bl: radius,\n        };\n    }\n    else {\n        const defaultRadius = {\n            tl: 0,\n            tr: 0,\n            br: 0,\n            bl: 0,\n        };\n        for (const side in defaultRadius) {\n            radius[side] = radius[side] || defaultRadius[side];\n        }\n    }\n    ctx.beginPath();\n    ctx.moveTo(x + radius.tl, y);\n    ctx.lineTo(x + width - radius.tr, y);\n    ctx.quadraticCurveTo(x + width, y, x + width, y + radius.tr);\n    ctx.lineTo(x + width, y + height - radius.br);\n    ctx.quadraticCurveTo(x + width, y + height, x + width - radius.br, y + height);\n    ctx.lineTo(x + radius.bl, y + height);\n    ctx.quadraticCurveTo(x, y + height, x, y + height - radius.bl);\n    ctx.lineTo(x, y + radius.tl);\n    ctx.quadraticCurveTo(x, y, x + radius.tl, y);\n    ctx.closePath();\n    if (fill) {\n        ctx.fill();\n    }\n    if (stroke) {\n        ctx.lineWidth = strokeWidth;\n        ctx.stroke();\n    }\n}\n// TODO: rewrite\n/**\n * Represents a 2D label item the scene.\n * Since displaying text in the scene is not an easy task,\n * we've abstracted the complicated logic behind this class, transforming any text into a 2D image(`DataImage`).\n *\n * **Library List**\n * * LabelPack\n *\n * **Parameters**\n * * **Library(`StringParameter`):** Library you wan to use for your label, see **Library List** above.\n * * **Text(`StringParameter`):**\n * * **FontColor(`ColorParameter`):**\n * * **Margin(`NumberParameter`):**\n * * **BorderWidth(`NumberParameter`):**\n * * **BorderRadius(`NumberParameter`):**\n * * **Outline(`BooleanParameter`):**\n * * **OutlineColor(`BooleanParameter`):**\n * * **Background(`BooleanParameter`):**\n * * **ColorParameter(`BackgroundColor`):**\n * * **FillBackground(`BooleanParameter`):**\n * * **StrokeBackgroundOutline(`BooleanParameter`):**\n * * **FontSize(`NumberParameter`):** Represents FontSize of the label\n * * **Font(`StringParameter`):**\n *\n * **Events**\n * * **loaded:** Triggered when label's data is loaded.\n * * **updated:** Triggered when label's data changes.\n * * **labelRendered:** Triggered when the text image is rendered. Contains `width`, `height` and data of the image.\n *\n * @extends DataImage\n */\nclass Label extends DataImage {\n    needsRender;\n    canvasElem;\n    requestedReRender = false;\n    /**\n     * Creates a label instance. Creating a canvas element that hosts the specified text.\n     *\n     * @param name - The name value.\n     * @param library - The library value.\n     */\n    marginParam;\n    borderRadiusParam;\n    /**\n     * @member libraryParam - Library you wan to use for your label, see **Library List** above.\n     */\n    libraryParam = new StringParameter('Library');\n    /**\n     * @member textParam - text to display on the label\n     */\n    textParam = new StringParameter('Text', '');\n    /**\n     * @member fontColorParam - TODO\n     */\n    fontColorParam = new ColorParameter('FontColor', new Color(0, 0, 0));\n    /**\n     * @member - Controls the size of the font (in pixels) that is rendered to the canvas.\n     */\n    fontSizeParam = new NumberParameter('FontSize', 22);\n    /**\n     * @member fontParam - Controls the font of the font that is rendered to the canvas.\n     */\n    fontParam = new StringParameter('Font', 'Helvetica');\n    /**\n     * @member borderWidthParam - Border around the label\n     */\n    borderWidthParam = new NumberParameter('BorderWidth', 2);\n    /**\n     * @member outlineParam - TODO\n     */\n    outlineParam = new BooleanParameter('Outline', false);\n    /**\n     * @member outlineColorParam - TODO\n     */\n    outlineColorParam = new ColorParameter('OutlineColor', new Color(0, 0, 0));\n    /**\n     * @member backgroundParam - TODO\n     */\n    backgroundParam = new BooleanParameter('Background', true);\n    /**\n     * @member backgroundColorParam - TODO\n     */\n    backgroundColorParam = new ColorParameter('BackgroundColor', new Color('#FBC02D'));\n    /**\n     * @member fillBackgroundParam - TODO\n     */\n    fillBackgroundParam = new BooleanParameter('FillBackground', true);\n    /**\n     * @member strokeBackgroundOutlineParam - TODO\n     */\n    strokeBackgroundOutlineParam = new BooleanParameter('StrokeBackgroundOutline', true);\n    constructor(name, library) {\n        super(name);\n        this.canvasElem = document.createElement('canvas');\n        const fontSize = 22;\n        this.marginParam = new NumberParameter('Margin', fontSize * 0.5);\n        this.borderRadiusParam = new NumberParameter('BorderRadius', fontSize * 0.5);\n        this.addParameter(this.marginParam);\n        this.addParameter(this.borderRadiusParam);\n        this.addParameter(this.libraryParam);\n        this.addParameter(this.textParam);\n        this.addParameter(this.fontColorParam);\n        this.addParameter(this.fontSizeParam);\n        this.addParameter(this.fontParam);\n        this.addParameter(this.borderWidthParam);\n        this.addParameter(this.outlineParam);\n        this.addParameter(this.outlineColorParam);\n        this.addParameter(this.backgroundParam);\n        this.addParameter(this.backgroundColorParam);\n        this.addParameter(this.fillBackgroundParam);\n        this.addParameter(this.strokeBackgroundOutlineParam);\n        const reload = () => {\n            this.loadLabelData();\n        };\n        this.on('nameChanged', reload);\n        if (library)\n            this.libraryParam.value = library;\n        this.requestedReRender = false;\n        this.needsRender = false;\n        this.loadLabelData();\n    }\n    /**\n     * This method can be overridden in derived classes\n     * to perform general updates (see GLPass or BaseItem).\n     *\n     * @param event - The event object.\n     * @private\n     */\n    __parameterValueChanged(event) {\n        super.parameterValueChanged(event);\n        if (!this.requestedReRender) {\n            this.requestedReRender = true;\n            this.loadLabelData();\n        }\n    }\n    /**\n     * Method in charge of basically do everything, set text, load/update it, get the library, load the font, etc.\n     */\n    loadLabelData() {\n        const onLoaded = () => {\n            this.requestedReRender = false;\n            this.needsRender = true;\n            if (!this.loaded) {\n                this.loaded = true;\n                this.emit('loaded');\n            }\n            else {\n                this.emit('updated');\n            }\n        };\n        const loadText = () => {\n            return new Promise((resolve) => {\n                const library = this.libraryParam.value;\n                if (library == '') {\n                    resolve();\n                    return;\n                }\n                if (!labelManager.isLibraryFound(library)) {\n                    console.warn('Label Library not found:', library);\n                    resolve();\n                    return;\n                }\n                const getLibraryText = () => {\n                    try {\n                        const name = this.getName();\n                        // console.log(\"Text Loaded:\" + name);\n                        const text = labelManager.getLabelText(library, name);\n                        this.textParam.value = text;\n                    }\n                    catch (e) {\n                        // Note: if the text is not found in the labels pack\n                        // an exception is thrown, and we catch it here.\n                        console.warn(e);\n                    }\n                    resolve();\n                };\n                if (!labelManager.isLibraryLoaded(library)) {\n                    labelManager.on('labelLibraryLoaded', (event) => {\n                        const loadedLibrary = event.library;\n                        if (loadedLibrary == library)\n                            getLibraryText();\n                    });\n                }\n                else {\n                    getLibraryText();\n                }\n            });\n        };\n        const loadFont = () => {\n            return new Promise((resolve) => {\n                if (document.fonts != undefined) {\n                    const font = this.fontParam.value;\n                    const fontSize = this.fontSizeParam.value;\n                    document.fonts.load(fontSize + 'px \"' + font + '\"').then(() => {\n                        // console.log(\"Font Loaded:\" + font);\n                        resolve();\n                    });\n                }\n                else {\n                    resolve();\n                }\n            });\n        };\n        Promise.all([loadText(), loadFont()]).then(onLoaded);\n    }\n    /**\n     * Renders the label text to a canvas element ready to display.\n     * Here is where all parameters are applied to the canvas containing the text,\n     * then the image data is extracted from the canvas context.\n     */\n    renderLabelToImage() {\n        // console.log(\"renderLabelToImage\")\n        const ctx2d = this.canvasElem.getContext('2d', {\n            alpha: true,\n        });\n        let text = this.textParam.value;\n        if (text == '')\n            text = this.getName();\n        const font = this.fontParam.value;\n        const fontColor = this.fontColorParam.value;\n        const textAlign = 'left'; // this.textAlignParam.value\n        const fontSize = this.fontSizeParam.value;\n        const margin = this.marginParam.value;\n        const borderWidth = this.borderWidthParam.value;\n        const borderRadius = this.borderRadiusParam.value;\n        const outline = this.outlineParam.value;\n        const outlineColor = this.outlineColorParam.value;\n        const background = this.backgroundParam.value;\n        const backgroundColor = this.backgroundColorParam.value;\n        const fillBackground = this.fillBackgroundParam.value;\n        const strokeBackgroundOutline = this.strokeBackgroundOutlineParam.value;\n        // let ratio = devicePixelRatio / backingStoreRatio;\n        const marginAndBorder = margin + borderWidth;\n        const lines = text.split('\\n');\n        ctx2d.font = fontSize + 'px \"' + font + '\"';\n        // console.log(\"renderLabelToImage:\" + ctx2d.font);\n        let width = 0;\n        lines.forEach((line) => {\n            width = Math.max(ctx2d.measureText(line).width, width);\n        });\n        const fontHeight = fontSize; // parseInt(fontSize)\n        this.width = Math.ceil(width + marginAndBorder * 2);\n        this.height = Math.ceil(fontHeight * lines.length + marginAndBorder * 2);\n        ctx2d.canvas.width = this.width;\n        ctx2d.canvas.height = this.height;\n        this.canvasElem.width = this.width;\n        this.canvasElem.height = this.height;\n        // ctx2d.clearRect(0, 0, this.width, this.height);\n        ctx2d.fillStyle = 'rgba(0, 0, 0, 0.0)';\n        ctx2d.fillRect(0, 0, this.width, this.height);\n        if (background) {\n            ctx2d.fillStyle = backgroundColor.toHex();\n            ctx2d.strokeStyle = outlineColor.toHex();\n            roundRect(ctx2d, borderWidth, borderWidth, this.width - borderWidth * 2, this.height - borderWidth * 2, borderRadius, fillBackground, strokeBackgroundOutline, borderWidth);\n        }\n        ctx2d.font = fontSize + 'px \"' + font + '\"';\n        ctx2d.textAlign = textAlign;\n        ctx2d.fillStyle = fontColor.toHex();\n        ctx2d.textBaseline = 'hanging';\n        lines.forEach((line, index) => {\n            ctx2d.fillText(line, marginAndBorder, marginAndBorder + index * fontHeight);\n        });\n        if (outline) {\n            ctx2d.strokeStyle = outlineColor.toHex();\n            ctx2d.lineWidth = 1.5;\n            ctx2d.strokeText(text, marginAndBorder, marginAndBorder);\n        }\n        this.__data = ctx2d.getImageData(0, 0, this.width, this.height);\n        this.needsRender = false;\n        this.emit('labelRendered', {\n            width: this.width,\n            height: this.height,\n            data: this.__data,\n        });\n    }\n    /**\n     *  Returns all parameters and class state values(Including data).\n     *\n     * @return - The return value.\n     */\n    getParams() {\n        if (this.needsRender)\n            this.renderLabelToImage();\n        return super.getParams();\n    }\n}\nRegistry.register('Label', Label);\n\n/** Class representing a 2D video stream image.\n * @private\n * @extends BaseImage\n */\nclass VideoStreamImage2D extends BaseImage {\n    __data;\n    __intervalId;\n    /**\n     * Create a 2D video stream image.\n     */\n    constructor() {\n        super('');\n    }\n    /**\n     * The connectWebcam method.\n     * @param width - The width of the video.\n     * @param height - The height of the video.\n     * @param rearCamera - Boolean determining if it is a rear camera or not.\n     */\n    connectWebcam(width, height, rearCamera = false) {\n        const video = {\n            width,\n            height,\n            frameRate: {\n                ideal: 60,\n                max: 60,\n            },\n        };\n        if (rearCamera) {\n            video.facingMode = {\n                exact: 'environment',\n            };\n        }\n        else {\n            video.facingMode = {\n                facingMode: 'user',\n            };\n        }\n        const domElement = document.createElement('video');\n        // TODO - confirm its necessary to add to DOM\n        domElement.style.display = 'none';\n        domElement.preload = 'auto';\n        domElement.crossOrigin = 'anonymous';\n        // domElement.crossorigin = true;\n        document.body.appendChild(domElement);\n        // List cameras and microphones.\n        // navigator.mediaDevices.enumerateDevices()\n        //     .then((devices)=>{\n        //         // devices.forEach((device)=>{\n        //         //     if (device.kind == \"videoinput\") {\n        //         //         console.log(device.kind + \": \" + device.label + \" id = \" + device.deviceId);\n        //         //         videoinputs.push(device);\n        //         //     }\n        //         // });\n        //     })\n        //     .catch(function(err) {\n        //         console.log(err.name + \": \" + err.message);\n        //     });\n        navigator.mediaDevices\n            .getUserMedia({\n            audio: false,\n            video,\n        })\n            .then((mediaStream) => {\n            domElement.srcObject = mediaStream;\n            domElement.onloadedmetadata = (e) => {\n                domElement.play();\n                this.width = domElement.videoWidth;\n                this.height = domElement.videoHeight;\n                console.log('Webcam:[' + this.width + ', ' + this.height + ']');\n                this.__data = domElement;\n                this.loaded = true;\n                this.emit('loaded');\n                let prevFrame = 0;\n                const frameRate = 60;\n                const timerCallback = () => {\n                    if (domElement.paused || domElement.ended) {\n                        return;\n                    }\n                    // Check to see if the video has progressed to the next frame.\n                    // If so, then we emit and update, which will cause a redraw.\n                    const currentFrame = Math.floor(domElement.currentTime * frameRate);\n                    if (prevFrame != currentFrame) {\n                        this.emit('updated');\n                        prevFrame = currentFrame;\n                    }\n                    setTimeout(timerCallback, 20); // Sample at 50fps.\n                };\n                timerCallback();\n            };\n        })\n            .catch(function (err) {\n            /* handle the error */\n        });\n    }\n    /**\n     * The setVideoStream method.\n     * @param video - The video value.\n     */\n    setVideoStream(video) {\n        this.loaded = false;\n        this.width = video.videoWidth;\n        this.height = video.videoHeight;\n        this.start();\n        this.__data = video;\n        this.loaded = true;\n        this.emit('loaded');\n    }\n    // getAudioSource() {\n    //     return this.__data;\n    // }\n    /**\n     * The stop method.\n     */\n    stop() {\n        clearInterval(this.__intervalId);\n    }\n    /**\n     * The start method.\n     */\n    start() {\n        // @ts-ignore\n        this.__intervalId = setInterval(() => {\n            this.emit('updated');\n        }, 20); // Sample at 50fps.\n    }\n    /**\n     * The isLoaded method.\n     * @return - The return value.\n     */\n    isLoaded() {\n        return this.loaded;\n    }\n    /**\n     * The getParams method.\n     * @return - The return value.\n     */\n    getParams() {\n        return {\n            type: this.type,\n            format: this.format,\n            width: this.width,\n            height: this.height,\n            data: this.__data,\n        };\n    }\n}\nRegistry.register('VideoStreamImage2D', VideoStreamImage2D);\n\nclass FatLinesMaterial extends Material {\n    baseColorParam = new MaterialColorParam('BaseColor', new Color(1.0, 1, 0.5));\n    opacityParam = new NumberParameter('Opacity', 1.0);\n    lineThicknessParam = new NumberParameter('LineThickness', 0.01);\n    overlayParam = new NumberParameter('Overlay', 0.0);\n    constructor(name) {\n        super(name);\n        this.__shaderName = 'FatLinesShader';\n        this.addParameter(this.baseColorParam);\n        this.addParameter(this.opacityParam);\n        this.addParameter(this.overlayParam);\n        this.addParameter(this.lineThicknessParam);\n    }\n    isTextured() {\n        // Note: this is to force the generation of the MaterialShaderBinding\n        // see GLShaderMaterials.addGLGeomItem\n        return true;\n    }\n}\nRegistry.register('FatLinesMaterial', FatLinesMaterial);\n\nclass FatPointsMaterial extends Material {\n    baseColorParam = new MaterialColorParam('BaseColor', new Color(1, 1, 1));\n    pointSizeParam = new NumberParameter('PointSize', 1);\n    borderWidthParam = new NumberParameter('BorderWidth', 0.2);\n    overlayParam = new NumberParameter('Overlay', 0.0);\n    constructor(name) {\n        super(name);\n        this.__shaderName = 'FatPointsShader';\n        this.addParameter(this.baseColorParam);\n        this.addParameter(this.pointSizeParam);\n        this.addParameter(this.borderWidthParam);\n        this.addParameter(this.overlayParam);\n    }\n    /**\n     * The clone method constructs a new material, copies its values\n     * from this item and returns it.\n     *\n     * @param context - The context value.\n     * @return - Returns a new cloned material.\n     */\n    clone(context) {\n        const cloned = new FatPointsMaterial();\n        cloned.copyFrom(this, context);\n        return cloned;\n    }\n}\nRegistry.register('FatPointsMaterial', FatPointsMaterial);\n\nclass FlatSurfaceMaterial extends Material {\n    baseColorParam = new MaterialColorParam('BaseColor', new Color(1.0, 1, 0.5));\n    overlayParam = new MaterialFloatParam('Overlay', 0.0);\n    constructor(name) {\n        super(name);\n        this.__shaderName = 'FlatSurfaceShader';\n        this.addParameter(this.baseColorParam);\n        this.addParameter(this.overlayParam);\n    }\n    /**\n     * The clone method constructs a new material, copies its values\n     * from this item and returns it.\n     *\n     * @param context - The context value.\n     * @return - Returns a new cloned material.\n     */\n    clone(context) {\n        const cloned = new FlatSurfaceMaterial();\n        cloned.copyFrom(this, context);\n        return cloned;\n    }\n}\nRegistry.register('FlatSurfaceMaterial', FlatSurfaceMaterial);\n\nclass LinesMaterial extends Material {\n    baseColorParam = new MaterialColorParam('BaseColor', new Color(1.0, 1, 0.5));\n    opacityParam = new MaterialFloatParam('Opacity', 0.7, [0, 1]);\n    overlayParam = new MaterialFloatParam('Overlay', 0.000001); // Provide a slight overlay so lines draw over meshes\n    constructor(name) {\n        super(name);\n        this.__shaderName = 'LinesShader';\n        this.addParameter(this.baseColorParam);\n        this.addParameter(this.opacityParam);\n        this.addParameter(this.overlayParam);\n    }\n    /**\n     * The clone method constructs a new material, copies its values\n     * from this item and returns it.\n     *\n     * @param context - The context value.\n     * @return - Returns a new cloned material.\n     */\n    clone(context) {\n        const cloned = new LinesMaterial();\n        cloned.copyFrom(this, context);\n        return cloned;\n    }\n}\nRegistry.register('LinesMaterial', LinesMaterial);\n\nclass PointsMaterial extends Material {\n    baseColorParam = new MaterialColorParam('BaseColor', new Color(1.0, 1, 0.5));\n    pointSizeParam = new MaterialFloatParam('PointSize', 2);\n    overlayParam = new MaterialFloatParam('Overlay', 0.00002); // Provide a slight overlay so lines draw over meshes\n    constructor(name) {\n        super(name);\n        this.__shaderName = 'PointsShader';\n        this.addParameter(this.baseColorParam);\n        this.addParameter(this.pointSizeParam);\n        this.addParameter(this.overlayParam);\n    }\n    /**\n     * The clone method constructs a new material, copies its values\n     * from this item and returns it.\n     *\n     * @param context - The context value.\n     * @return - Returns a new cloned material.\n     */\n    clone(context) {\n        const cloned = new PointsMaterial();\n        cloned.copyFrom(this, context);\n        return cloned;\n    }\n}\nRegistry.register('PointsMaterial', PointsMaterial);\n\nclass ScreenSpaceMaterial extends Material {\n    baseColorParam = new MaterialColorParam('BaseColor', new Color(1.0, 1, 0.5));\n    constructor(name) {\n        super(name);\n        this.__shaderName = 'ScreenSpaceShader';\n        this.addParameter(this.baseColorParam);\n    }\n    /**\n     * The clone method constructs a new material, copies its values\n     * from this item and returns it.\n     *\n     * @param context - The context value.\n     * @return - Returns a new cloned material.\n     */\n    clone(context) {\n        const cloned = new ScreenSpaceMaterial();\n        cloned.copyFrom(this, context);\n        return cloned;\n    }\n}\nRegistry.register('ScreenSpaceMaterial', ScreenSpaceMaterial);\n\nclass SimpleSurfaceMaterial extends Material {\n    baseColorParam = new MaterialColorParam('BaseColor', new Color(1.0, 1, 0.5));\n    opacityParam = new MaterialFloatParam('Opacity', 1, [0, 1]);\n    emissiveStrengthParam = new MaterialFloatParam('EmissiveStrength', 0, [0, 1]);\n    constructor(name) {\n        super(name);\n        this.__shaderName = 'SimpleSurfaceShader';\n        this.addParameter(this.baseColorParam);\n        this.addParameter(this.opacityParam);\n        this.addParameter(this.emissiveStrengthParam);\n    }\n    /**\n     * The clone method constructs a new material, copies its values\n     * from this item and returns it.\n     *\n     * @param context - The context value.\n     * @return - Returns a new cloned material.\n     */\n    clone(context) {\n        const cloned = new SimpleSurfaceMaterial();\n        cloned.copyFrom(this, context);\n        return cloned;\n    }\n}\nRegistry.register('SimpleSurfaceMaterial', SimpleSurfaceMaterial);\n\n/**\n * The Standard  Surface Material is the default material applied to CAD surfaces contained in zcad files\n * It is a material that specifies color information for the various kinds of geometry found in a CADBody.\n * The 'BaseColor' specifies the color for the faces of the Body.\n * The 'EdgeColor' specifies the color for the edges of the Body.\n * The 'PointColor' specifies the color for the points of the Body.\n * Note: is is possible to assign materials directly to each face or edge, and in this case,\n * the 'BaseColor' value is used to color the element. For example, if you assign a StandardSurfaceMaterial\n * directly to an edge, its color will be speicifed by the base color, rather than the 'EdgeColor'\n * So if you assign the body material to all the faces and edges and points, they will all become the same\n * color. This is because, when the material was assigned to the body, the shader code would read the 'EdgeColor' value for edges, when the same material is assigned to the edge, the 'BaseColor'value is used.\n * > Hint: An edge can be colored using a simple material like the LinesMaterial that has very few parameters.\n * Note: materials are shared by default. You can assign the same material to many edges or faces. To assign a\n * unique color to a face or edge, simply construct a new material, set its base color, and assign it to the face.\n *\n * Example of assigning a face material when the user clicks in the 3d viewport.\n * ```\n *    const asset = new CADAsset()\n      asset.load('urlto.zcad').then(() => {\n        asset.traverse((item) => {\n          if (item instanceof CADBody) {\n            item.setShatterState(true)\n          }\n        })\n      })\n *    renderer.getViewport().on('pointerClick', (event) => {\n        if (event.intersectionData) {\n          if (event.intersectionData.componentId >= 0) {\n            const subGeomId = event.intersectionData.componentId\n            const geomItem = event.intersectionData.geomItem\n            geomItem.geomParam.value.setSubGeomMaterial(subGeomId, standardMaterial)\n\n          }\n        }\n      })\n  ```\n */\nclass StandardSurfaceMaterial extends Material {\n    baseColorParam = new MaterialColorParam('BaseColor', new Color(1.0, 1, 0.5));\n    normalParam = new MaterialColorParam('Normal', new Color(1.0, 1, 0.5));\n    ambientOcclusion = new MaterialFloatParam('AmbientOcclusion', 1, [0, 1]);\n    metallicParam = new MaterialFloatParam('Metallic', 0.05, [0, 1]);\n    roughnessParam = new MaterialFloatParam('Roughness', 0.5, [0, 1]);\n    reflectanceParam = new MaterialFloatParam('Reflectance', 0.5, [0, 1]);\n    emissiveStrengthParam = new MaterialFloatParam('EmissiveStrength', 0, [0, 1]);\n    opacityParam = new MaterialFloatParam('Opacity', 1, [0, 1]);\n    edgeWeightParam = new MaterialFloatParam('EdgeWeight', 0.7, [0, 1]);\n    overlayParam = new MaterialFloatParam('Overlay', 0, [0, 1]);\n    edgeColorParam = new MaterialColorParam('EdgeColor', new Color(0.1, 0.1, 0.1, 0.8));\n    pointColorParam = new MaterialColorParam('PointColor', new Color(0.1, 0.1, 0.1));\n    pointSizeParam = new MaterialFloatParam('PointSize', 4, [0, Number.MAX_VALUE]);\n    constructor(name) {\n        super(name);\n        this.__shaderName = 'StandardSurfaceShader';\n        this.addParameter(this.baseColorParam);\n        this.addParameter(this.normalParam);\n        this.addParameter(this.ambientOcclusion);\n        this.addParameter(this.metallicParam);\n        this.addParameter(this.roughnessParam);\n        this.addParameter(this.reflectanceParam);\n        this.addParameter(this.emissiveStrengthParam);\n        this.addParameter(this.opacityParam);\n        this.addParameter(this.edgeWeightParam);\n        this.addParameter(this.overlayParam);\n        this.addParameter(this.edgeColorParam);\n        this.addParameter(this.pointColorParam);\n        this.addParameter(this.pointSizeParam);\n    }\n    /**\n     * The clone method constructs a new material, copies its values\n     * from this item and returns it.\n     *\n     * @param context - The context value.\n     * @return - Returns a new cloned material.\n     */\n    clone(context) {\n        const cloned = new StandardSurfaceMaterial();\n        cloned.copyFrom(this, context);\n        return cloned;\n    }\n}\nRegistry.register('StandardSurfaceMaterial', StandardSurfaceMaterial);\n\nclass VertexColorMaterial extends Material {\n    constructor(name) {\n        super(name);\n        this.__shaderName = 'VertexColorShader';\n    }\n    /**\n     * The clone method constructs a new material, copies its values\n     * from this item and returns it.\n     *\n     * @param context - The context value.\n     * @return - Returns a new cloned material.\n     */\n    clone(context) {\n        const cloned = new VertexColorMaterial();\n        cloned.copyFrom(this, context);\n        return cloned;\n    }\n    /**\n     * The supportsInstancing method.\n     * @return - return false for shaders that cannot be rendered in instanced mode.\n     */\n    static supportsInstancing() {\n        return false;\n    }\n}\nRegistry.register('VertexColorMaterial', VertexColorMaterial);\n\nclass MaskMaterial extends SimpleSurfaceMaterial {\n    constructor(name) {\n        super(name);\n        this.baseColorParam.value = new Color(1.0, 0.0, 0.0, 0.2);\n    }\n    clone(context) {\n        const cloned = new MaskMaterial();\n        cloned.copyFrom(this, context);\n        return cloned;\n    }\n}\nRegistry.register('MaskMaterial', MaskMaterial);\n\nclass EnvProjectionMaterial extends Material {\n    projectionCenter = new Vec3Parameter('projectionCenter', new Vec3(0.0, 0, 1.7));\n    constructor(name) {\n        super(name);\n        this.__shaderName = 'EnvProjectionShader';\n        this.addParameter(this.projectionCenter);\n    }\n    clone(context) {\n        const cloned = new EnvProjectionMaterial();\n        cloned.copyFrom(this, context);\n        return cloned;\n    }\n    isTextured() {\n        // Note: this is to force the generation of the MaterialShaderBinding\n        // see GLShaderMaterials.addGLGeomItem\n        return true;\n    }\n}\nRegistry.register('EnvProjectionMaterial', EnvProjectionMaterial);\n\n/* eslint-disable no-unused-vars */\n/**\n * TreeItem type of class designed for making duplications of parts of the tree.\n *\n * @extends {TreeItem}\n */\nclass InstanceItem extends TreeItem {\n    srcTreePath = [];\n    srcTree = null;\n    /**\n     * Create an instance item.\n     * @param name - The name of the instance item.\n     */\n    constructor(name) {\n        super(name);\n    }\n    /**\n     * Clones passed in `TreeItem` all the way down and adds it as a child of current item.\n     *\n     * @param treeItem - The treeItem value.\n     */\n    setSrcTree(treeItem) {\n        this.srcTree = treeItem;\n        const clonedContext = new CloneContext();\n        const clonedTree = this.srcTree.clone(clonedContext);\n        clonedTree.localXfoParam.value = new Xfo();\n        this.addChild(clonedTree, false, false);\n    }\n    /**\n     * Returns the last `TreeItem` cloned.\n     *\n     * @return - The return value.\n     */\n    getSrcTree() {\n        return this.srcTree;\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * Sets state of current Item(Including cloned item) using a binary reader object.\n     *\n     * @param reader - The reader value.\n     * @param context - The context value.\n     */\n    readBinary(reader, context) {\n        super.readBinary(reader, context);\n        this.srcTreePath = reader.loadStrArray();\n        if (this.srcTreePath.length > 0) {\n            context.resolvePath(this.srcTreePath, (treeItem) => {\n                this.setSrcTree(treeItem);\n            }, (error) => {\n                console.warn(`Error loading InstanceItem: ${this.getPath()}, unable to resolve: ${this.srcTreePath}. ` + error.message);\n            });\n        }\n    }\n    // ////////////////////////////////////////\n    // Clone and Destroy\n    /**\n     * The clone method constructs a new instance item, copies its values\n     * from this item and returns it.\n     *\n     * @param context - The context value.\n     * @return - Returns a new cloned geom item.\n     */\n    clone(context) {\n        const cloned = new InstanceItem();\n        cloned.copyFrom(this, context);\n        return cloned;\n    }\n    /**\n     * Copies current TreeItem with all its children.\n     *\n     * @param src - The tree item to copy from.\n     * @param context - The context value.\n     */\n    copyFrom(src, context) {\n        if (!(src instanceof InstanceItem)) {\n            throw new Error('cannot copy from src');\n        }\n        super.copyFrom(src, context);\n        this.srcTreePath = src.srcTreePath;\n        if (this.srcTreePath.length > 0 && this.getNumChildren() == 0) {\n            src.once('childAdded', (event) => {\n                const childAddedEvent = event;\n                const childItem = childAddedEvent.childItem;\n                this.setSrcTree(childItem);\n            });\n        }\n    }\n}\nRegistry.register('InstanceItem', InstanceItem);\n\n/**\n * Base class that represents geometry items with layering, overlaying and cut away features.\n *\n * **Events**\n * * **cutAwayChanged:** Triggered when the cutaway variables change(if enabled or not, the vector and the distance).\n * @extends TreeItem\n */\nclass BaseGeomItem extends TreeItem {\n    overlay;\n    cutAway;\n    cutAwayVector;\n    cutAwayDist;\n    layers;\n    /**\n     * @member materialParam - The Material to use when rendering this GeomItem\n     */\n    materialParam = new MaterialParameter('Material');\n    /**\n     * Create a base geometry item.\n     * @param name - The name of the base geom item.\n     */\n    constructor(name) {\n        super(name);\n        this.addParameter(this.materialParam);\n        this.overlay = false;\n        this.cutAway = false;\n        this.cutAwayVector = new Vec3(0, 0, 0);\n        this.cutAwayDist = 0;\n        this.layers = [];\n    }\n    /**\n     * Sets overlay value.\n     *\n     * @todo Need to find the layer and add this item to it.\n     * @param val - `true` to enable it.\n     */\n    setOverlay(val) {\n        // TODO: need to find the layer and add this item to it.\n        this.overlay = val;\n    }\n    /**\n     * Returns `true` if overlay is enabled for current item.\n     *\n     * @return - The return value.\n     */\n    isOverlay() {\n        return this.overlay;\n    }\n    /**\n     * Adds a layer to current item.\n     *\n     * @todo Need to find the layer and add this item to it.\n     * @param name - The name of the layer.\n     */\n    addLayer(name) {\n        // TODO: need to find the layer and add this item to it.\n        this.layers.push(name);\n    }\n    /**\n     * Returns all layers in current item.\n     *\n     * @return - The return value.\n     */\n    getLayers() {\n        return this.layers;\n    }\n    // ////////////////////////////////////////\n    // Cutaways\n    /**\n     * Checks if cutaway is enabled.\n     *\n     * @return - Returns `true` if enabled.\n     */\n    isCutawayEnabled() {\n        return this.cutAway;\n    }\n    /**\n     * Sets cutaway state.\n     *\n     * @param state - `true` to enable it, otherwise `false`.\n     */\n    setCutawayEnabled(state) {\n        this.cutAway = state;\n        this.emit('cutAwayChanged');\n    }\n    /**\n     * Returns cutaway vector value.\n     *\n     * @return - `Vec3` when it is set, `false` on default.\n     */\n    getCutVector() {\n        return this.cutAwayVector;\n    }\n    /**\n     * Sets cutaway vector value.\n     *\n     * @param cutAwayVector - The cutAwayVector value.\n     */\n    setCutVector(cutAwayVector) {\n        this.cutAwayVector = cutAwayVector;\n        this.emit('cutAwayChanged');\n    }\n    /**\n     * Getter for the cutaway distance.\n     *\n     * @return - The return value.\n     */\n    getCutDist() {\n        return this.cutAwayDist;\n    }\n    /**\n     * Sets cutaway distance value.\n     *\n     * @param cutAwayDist - The cutAwayDist value.\n     */\n    setCutDist(cutAwayDist) {\n        this.cutAwayDist = cutAwayDist;\n        this.emit('cutAwayChanged');\n    }\n    // ///////////////////////////\n    // Persistence\n    /**\n     * Sets state of current Item(Including layers & material) using a binary reader object.\n     *\n     * @param reader - The reader value.\n     * @param context - The context value.\n     */\n    readBinary(reader, context) {\n        super.readBinary(reader, context);\n        if (context.versions['zea-engine'].compare([0, 0, 4]) >= 0) {\n            const materialName = reader.loadStr();\n            // const materialName = 'Material' + this.__bodyDescId;\n            const materialLibrary = context.assetItem.getMaterialLibrary();\n            let material = materialLibrary.getMaterial(materialName);\n            if (!material) {\n                // console.warn(\"BaseGeomItem :'\" + this.name + \"' Material not found:\" + materialName);\n                // material = materialLibrary.getMaterial('DefaultMaterial');\n                material = new Material(materialName, 'SimpleSurfaceShader');\n                material.getParameter('BaseColor').loadValue(Color.random(0.25));\n                context.assetItem.getMaterialLibrary().addMaterial(material);\n            }\n            this.materialParam.loadValue(material);\n            this.layers = reader.loadStrArray();\n            if (this.layers.length > 0) {\n                // console.log(\"Layers:\", this.layers)\n                for (const layer of this.layers)\n                    context.addGeomToLayer(this, layer);\n            }\n        }\n    }\n}\n\nlet calculatePreciseBoundingBoxes = false;\n/** The operator the calculates the global Xfo of a TreeItem based on its parents GlobalXfo and its own LocalXfo\n * @extends Operator\n * @private\n */\nclass CalcGeomMatOperator extends Operator {\n    globalXfo = new XfoOperatorInput('GlobalXfo');\n    geomOffsetXfo = new XfoOperatorInput('GeomOffsetXfo');\n    geomMat = new Mat4OperatorOutput('GeomMat');\n    /**\n     *Creates an instance of CalcGeomMatOperator.\n     *\n     * @param globalXfoParam\n     * @param geomOffsetXfoParam\n     * @param geomMatParam\n     * @memberof CalcGeomMatOperator\n     */\n    constructor(globalXfoParam, geomOffsetXfoParam, geomMatParam) {\n        super('CalcGeomMatOperator');\n        this.globalXfo.setParam(globalXfoParam);\n        this.geomOffsetXfo.setParam(geomOffsetXfoParam);\n        this.geomMat.setParam(geomMatParam);\n        this.addInput(this.globalXfo);\n        this.addInput(this.geomOffsetXfo);\n        this.addOutput(this.geomMat);\n    }\n    /**\n     * The evaluate method.\n     */\n    evaluate() {\n        const globalMat4 = this.globalXfo.getValue().toMat4();\n        const geomOffsetMat4 = this.geomOffsetXfo.getValue().toMat4();\n        this.geomMat.setClean(globalMat4.multiply(geomOffsetMat4));\n    }\n}\n/**\n * Class representing a geometry item in a scene tree.\n *\n * **Parameters**\n * * **Geometry(`GeometryParameter`):** The geometry to be rendered for this GeomItem\n * * **Material(`MaterialParameter`):** The Material to use when rendering this GeomItem\n * * **GeomOffsetXfo(`XfoParameter`):** Provides an offset transformation that is applied only to the geometry and not inherited by child items.\n * * **GeomMat(`Mat4Parameter`):** Calculated from the GlobalXfo and the GeomOffsetXfo, this matrix is provided to the renderer for rendering.\n *\n * @extends BaseGeomItem\n */\nclass GeomItem extends BaseGeomItem {\n    listenerIDs = {};\n    geomBBox;\n    geomIndex = -1;\n    assetItem = null;\n    calcGeomMatOperator;\n    cullable = true;\n    /**\n     * @member geomOffsetXfoParam - Provides an offset transformation that is applied only to the geometry and not inherited by child items.\n     */\n    geomOffsetXfoParam = new XfoParameter('GeomOffsetXfo');\n    /**\n     * @member geomParam - The geometry to be rendered for this GeomItem\n     */\n    geomParam = new GeometryParameter('Geometry');\n    /**\n     * @member geomMatParam - Calculated from the GlobalXfo and the GeomOffsetXfo, this matrix is provided to the renderer for rendering.\n     */\n    geomMatParam = new Mat4Parameter('GeomMat');\n    /**\n     * Creates a geometry item.\n     * @param name - The name of the geom item.\n     * @param geometry - The geometry value.\n     * @param material - The material value.\n     * @param xfo - The initial Xfo of the new GeomItem.\n     */\n    constructor(name, geometry, material, xfo) {\n        super(name);\n        this.addParameter(this.geomParam);\n        this.addParameter(this.geomOffsetXfoParam);\n        this.addParameter(this.geomMatParam);\n        const geomChanged = () => {\n            this.setBoundingBoxDirty();\n        };\n        this.geomParam.on('valueChanged', geomChanged);\n        this.geomParam.on('boundingBoxChanged', geomChanged);\n        this.calcGeomMatOperator = new CalcGeomMatOperator(this.globalXfoParam, this.geomOffsetXfoParam, this.geomMatParam);\n        if (geometry)\n            this.geomParam.loadValue(geometry);\n        if (material)\n            this.materialParam.loadValue(material);\n        if (xfo)\n            this.localXfoParam.value = xfo;\n    }\n    cleanBoundingBox() {\n        if (this.disableBoundingBox)\n            return new Box3();\n        const bbox = super.cleanBoundingBox();\n        if (this.geomBBox) {\n            // Note: this bbox is the global bounding box of the geomItem\n            // transformed into the space of the geometry. We reapply\n            // the geom matrix to get back the points in global space.\n            const mat4 = this.geomMatParam.value;\n            bbox.addPoint(mat4.transformVec3(this.geomBBox.p0));\n            bbox.addPoint(mat4.transformVec3(this.geomBBox.p1));\n        }\n        else {\n            const geom = this.geomParam.value;\n            if (geom) {\n                if (calculatePreciseBoundingBoxes) {\n                    // Note: compting the precise bounding box is much slower and\n                    // can make loading big scenes take a bit longer.\n                    const mat4 = this.geomMatParam.value;\n                    const buffers = geom.genBuffers();\n                    if (geom instanceof BaseProxy) {\n                        const positions = buffers.attrBuffers['positions'].values;\n                        const getVertex = (index) => {\n                            const start = index * 3;\n                            const value = new Vec3();\n                            value.fromArray(positions.subarray(start, start + 3));\n                            return value;\n                        };\n                        for (let i = 0; i < geom.getNumVertices(); i++) {\n                            bbox.addPoint(mat4.transformVec3(getVertex(i)));\n                        }\n                    }\n                    else {\n                        const positions = geom.getVertexAttribute('positions');\n                        for (let i = 0; i < geom.getNumVertices(); i++) {\n                            bbox.addPoint(mat4.transformVec3(positions.getValue(i)));\n                        }\n                    }\n                }\n                else {\n                    bbox.addBox3(geom.getBoundingBox(), this.geomMatParam.value);\n                }\n            }\n        }\n        return bbox;\n    }\n    // ///////////////////////////\n    // Debugging\n    /**\n     * The fromJSON method decodes a json object for this type.\n     *\n     * @param json - The json object this item must decode.\n     * @param context - The context value.\n     */\n    fromJSON(json, context) {\n        super.fromJSON(json, context);\n    }\n    /**\n     * Loads state of the Item from a binary object.\n     *\n     * @param reader - The reader value.\n     * @param context - The context value.\n     */\n    readBinary(reader, context) {\n        super.readBinary(reader, context);\n        const itemFlags = reader.loadUInt8();\n        const geomIndex = reader.loadUInt32();\n        const geomLibrary = context.assetItem.getGeometryLibrary();\n        this.geomIndex = geomIndex;\n        this.assetItem = context.assetItem;\n        const geom = geomLibrary.getGeom(geomIndex);\n        if (geom) {\n            this.geomParam.loadValue(geom);\n        }\n        else {\n            const onGeomLoaded = (event) => {\n                const { range } = event;\n                if (geomIndex >= range[0] && geomIndex < range[1]) {\n                    const geom = geomLibrary.getGeom(geomIndex);\n                    if (geom)\n                        this.geomParam.value = geom;\n                    else\n                        console.warn('Geom not loaded:', this.getName());\n                    geomLibrary.off('rangeLoaded', onGeomLoadedListenerID);\n                }\n            };\n            const onGeomLoadedListenerID = geomLibrary.on('rangeLoaded', onGeomLoaded);\n        }\n        // this.setVisibility(j.visibility);\n        // Note: to save space, some values are skipped if they are identity values\n        const geomOffsetXfoFlag = 1 << 2;\n        if (itemFlags & geomOffsetXfoFlag) {\n            this.geomOffsetXfoParam.value = new Xfo(reader.loadFloat32Vec3(), reader.loadFloat32Quat(), reader.loadFloat32Vec3());\n        }\n        // BaseGeomItem now handles loading materials.\n        if (context.versions['zea-engine'].compare([0, 0, 4]) < 0) {\n            const materialFlag = 1 << 3;\n            if (itemFlags & materialFlag) {\n                const materialLibrary = context.assetItem.getMaterialLibrary();\n                const materialName = reader.loadStr();\n                let material = materialLibrary.getMaterial(materialName);\n                if (!material) {\n                    console.warn(\"Geom :'\" + this.name + \"' Material not found:\" + materialName);\n                    material = materialLibrary.getMaterial('Default');\n                }\n                this.materialParam.loadValue(material);\n            }\n            else {\n                // Force nodes to have a material so we can see them.\n                this.materialParam.loadValue(context.assetItem.getMaterialLibrary().getMaterial('Default'));\n            }\n        }\n        // Note: deprecated value. Not sure if we need to load this here.\n        // I think not, but need to test first.\n        if (context.versions['zea-engine'].compare([3, 0, 0]) < 0) {\n            // Load the 'lightmapCoordOffset' value which we no longer use.\n            // Note: we need to load it to increment the file pointer.\n            reader.loadFloat32Vec2();\n        }\n        else {\n            this.geomBBox = new Box3(reader.loadFloat32Vec3(), reader.loadFloat32Vec3());\n        }\n    }\n    /**\n     * Returns string representation of current object's state.\n     * @param context\n     * @return - The return value.\n     */\n    toString(context) {\n        return JSON.stringify(this.toJSON(context), null, 2);\n    }\n    // ////////////////////////////////////////\n    // Clone and Destroy\n    /**\n     * The clone method constructs a new geom item, copies its values\n     * from this item and returns it.\n     *\n     * @param context - The context value.\n     * @return - Returns a new cloned geom item.\n     */\n    clone(context) {\n        const cloned = new GeomItem();\n        cloned.copyFrom(this, context);\n        return cloned;\n    }\n    /**\n     * Copies current GeomItem with all its children.\n     *\n     * @param src - The geom item to copy from.\n     * @param context - The context value.\n     */\n    copyFrom(src, context) {\n        if (!(src instanceof GeomItem)) {\n            throw new Error('cannot copy from src');\n        }\n        super.copyFrom(src, context);\n        this.geomOffsetXfoParam.value = src.geomOffsetXfoParam.value;\n        if (!src.geomParam.value && src.geomIndex != -1) {\n            const geomLibrary = src.assetItem.getGeometryLibrary();\n            this.assetItem = src.assetItem;\n            this.geomIndex = src.geomIndex;\n            this.geomBBox = src.geomBBox;\n            const onGeomLoaded = (event) => {\n                const { range } = event;\n                if (this.geomIndex >= range[0] && this.geomIndex < range[1]) {\n                    const geom = geomLibrary.getGeom(this.geomIndex);\n                    // Note: we need the 'valueChanged' event to be received by the\n                    // renderer to then load the geometry into the GPU.\n                    // @ts-ignore\n                    if (geom)\n                        this.geomParam.value = geom;\n                    else\n                        console.warn('Geom not loaded:', this.getName());\n                    geomLibrary.off('rangeLoaded', this.listenerIDs['rangeLoaded']);\n                }\n            };\n            this.listenerIDs['rangeLoaded'] = geomLibrary.on('rangeLoaded', onGeomLoaded);\n        }\n        // Geom Xfo should be dirty after cloning.\n        // Note: this might not be necessary. It should\n        // always be dirty after cloning.\n        this.geomMatParam.setDirty(0);\n    }\n    /**\n     * Sets the global boolean that controls if GeomItems calculate precise bounding boxes\n     * or use the approximate bounding boxes that are much faster to generate.\n     * Note: computing the precise bounding box is much slower and can make loading\n     * big scenes take a bit longer. This setting is only relevant to geometries loaded\n     * from zcad files.\n     * @deprecated\n     * zcad files from version 3.11.0 contain precise bounding boxes by default.\n     * @param value - true for precise bounding boxes, else false for faster approximate bounding boxes.\n     */\n    static setCalculatePreciseBoundingBoxes(value) {\n        calculatePreciseBoundingBoxes = value;\n    }\n}\nRegistry.register('GeomItem', GeomItem);\n\n/**\n * @private\n * @extends BaseGeom\n */\nclass CompoundGeomLoader extends BaseGeom {\n    numSubGeoms = 0;\n    indices = new Uint8Array(0);\n    offsets = {};\n    counts = {};\n    // For each type of geom (TRIANGLES, LINES)\n    // A material id, and each start and end of the block\n    materialSubGeoms = {};\n    subGeomOffsets = {};\n    subGeomCounts = {};\n    materialLibraryIndices = new Uint32Array(0);\n    subGeomMaterialIndices = new Uint8Array(0);\n    /**\n     * Create points.\n     */\n    constructor() {\n        super();\n    }\n    genBuffers() {\n        const attrBuffers = {};\n        for (const [attrName, attr] of this.__vertexAttributes) {\n            attrBuffers[attrName] = attr.genBuffer();\n        }\n        const numVertices = this.numVertices();\n        const result = {\n            numVertices,\n            numRenderVerts: numVertices,\n            indices: this.indices,\n            attrBuffers,\n            offsets: this.offsets,\n            counts: this.counts,\n            numSubGeoms: this.numSubGeoms,\n            subGeomOffsets: this.subGeomOffsets,\n            subGeomCounts: this.subGeomCounts,\n            materialLibraryIndices: this.materialLibraryIndices,\n            subGeomMaterialIndices: this.subGeomMaterialIndices,\n            materialSubGeoms: this.materialSubGeoms,\n        };\n        return result;\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * Sets state of current geometry(Including line segments) using a binary reader object.\n     *\n     * @param {BinReader} reader - The reader value.\n     * @param {Record<string, unknown>} context - The context value.\n     */\n    readBinary(reader, context) {\n        super.loadBaseGeomBinary(reader, context);\n        const geomCountsByType = reader.loadUInt32Array(3);\n        this.offsets['TRIANGLES'] = 0;\n        this.counts['TRIANGLES'] = geomCountsByType[0];\n        this.offsets['LINES'] = geomCountsByType[0];\n        this.counts['LINES'] = geomCountsByType[1];\n        this.offsets['POINTS'] = geomCountsByType[0] + geomCountsByType[1];\n        this.counts['POINTS'] = geomCountsByType[2];\n        const bytes = reader.loadUInt8();\n        // Note: do not clone the source arrays as we will transfer the\n        // entire buffer back to the main thread where it will be freed once\n        // the data is uploaded to the GPU.\n        if (bytes == 1)\n            this.indices = reader.loadUInt8Array();\n        else if (bytes == 2)\n            this.indices = reader.loadUInt16Array();\n        else if (bytes == 4)\n            this.indices = reader.loadUInt32Array();\n        // /////////////////////////////////\n        // TRIANGLES subgeoms\n        const bytesMeshSubGeoms = reader.loadUInt8();\n        let subGeomCountsMesh;\n        if (bytesMeshSubGeoms == 1)\n            subGeomCountsMesh = reader.loadUInt8Array();\n        else if (bytesMeshSubGeoms == 2)\n            subGeomCountsMesh = reader.loadUInt16Array();\n        else if (bytesMeshSubGeoms == 4)\n            subGeomCountsMesh = reader.loadUInt32Array();\n        else {\n            throw Error('subGeomOffsets undefined');\n        }\n        const subGeomOffsetsMesh = new Uint32Array(subGeomCountsMesh.length);\n        let offset = 0;\n        for (let i = 0; i < subGeomCountsMesh.length; i++) {\n            subGeomOffsetsMesh[i] = offset;\n            offset += subGeomCountsMesh[i];\n        }\n        this.subGeomOffsets['TRIANGLES'] = subGeomOffsetsMesh;\n        this.subGeomCounts['TRIANGLES'] = subGeomCountsMesh;\n        // /////////////////////////////////\n        // LINES subgeoms\n        const bytesLinesSubGeoms = reader.loadUInt8();\n        let subGeomCountsLines;\n        if (bytesLinesSubGeoms == 1)\n            subGeomCountsLines = reader.loadUInt8Array();\n        else if (bytesLinesSubGeoms == 2)\n            subGeomCountsLines = reader.loadUInt16Array();\n        else if (bytesLinesSubGeoms == 4)\n            subGeomCountsLines = reader.loadUInt32Array();\n        else {\n            throw Error('subGeomOffsets undefined');\n        }\n        const subGeomOffsetsLines = new Uint32Array(subGeomCountsLines.length);\n        for (let i = 0; i < subGeomCountsLines.length; i++) {\n            subGeomOffsetsLines[i] = offset;\n            offset += subGeomCountsLines[i];\n        }\n        this.subGeomOffsets['LINES'] = subGeomOffsetsLines;\n        this.subGeomCounts['LINES'] = subGeomCountsLines;\n        // /////////////////////////////////\n        // POINTS subgeoms\n        const numPointsSubGeoms = reader.loadUInt32();\n        const subGeomOffsetsPoints = new Uint32Array(numPointsSubGeoms);\n        const subGeomCountsPoints = new Uint8Array(numPointsSubGeoms);\n        for (let i = 0; i < numPointsSubGeoms; i++) {\n            subGeomOffsetsPoints[i] = offset;\n            subGeomCountsPoints[i] = 1;\n            offset++;\n        }\n        this.subGeomOffsets['POINTS'] = subGeomOffsetsPoints;\n        this.subGeomCounts['POINTS'] = subGeomCountsPoints;\n        if (context.versions['zea-engine'].compare([3, 11, 0]) > 0) {\n            // Points sub-geoms were not being exported before this release.\n            this.numSubGeoms = subGeomCountsMesh.length + subGeomCountsLines.length + numPointsSubGeoms;\n        }\n        else {\n            this.numSubGeoms = subGeomCountsMesh.length + subGeomCountsLines.length;\n        }\n        // /////////////////////////////////\n        // Materials\n        const numMaterials = reader.loadUInt32();\n        if (numMaterials > 0) {\n            this.materialLibraryIndices = reader.loadUInt32Array(numMaterials);\n            this.subGeomMaterialIndices = reader.loadUInt8Array(this.numSubGeoms);\n            // /////////////////////////////////\n            // Material Groups\n            let offset = 0;\n            let currMaterial = -99;\n            let currMaterialSubGeom = null;\n            for (let i = 0; i < this.numSubGeoms; i++) {\n                let key;\n                let subGeomOffset = 0;\n                if (i < this.subGeomCounts.TRIANGLES.length) {\n                    if (!this.materialSubGeoms.TRIANGLES)\n                        this.materialSubGeoms.TRIANGLES = [];\n                    key = 'TRIANGLES';\n                }\n                else if (i < this.subGeomCounts.TRIANGLES.length + this.subGeomCounts.LINES.length) {\n                    subGeomOffset = this.subGeomCounts.TRIANGLES.length;\n                    key = 'LINES';\n                    if (!this.materialSubGeoms.LINES)\n                        this.materialSubGeoms.LINES = [];\n                }\n                else {\n                    subGeomOffset = this.subGeomCounts.TRIANGLES.length + this.subGeomCounts.LINES.length;\n                    key = 'POINTS';\n                    if (!this.materialSubGeoms.POINTS)\n                        this.materialSubGeoms.POINTS = [];\n                }\n                const materialId = this.subGeomMaterialIndices[i];\n                if (currMaterial != materialId) {\n                    currMaterial = materialId;\n                    // Note: subGeomMaterialIndices is Uint8Array, and 0 means no custom\n                    // material is assigned to the subGeom.\n                    // Subtract 1 to get the actual material id.\n                    currMaterialSubGeom = {\n                        materialId: materialId - 1,\n                        offset,\n                        count: 0,\n                    };\n                    for (; i < this.numSubGeoms; i++) {\n                        if (currMaterial != this.subGeomMaterialIndices[i]) {\n                            break;\n                        }\n                        // When we get to the end og this geom type (e.g .TRIANGLES)\n                        // start a new subgeom.\n                        if (i - subGeomOffset == this.subGeomCounts[key].length) {\n                            // Force the material index to be reset on line 162 above.\n                            currMaterial = -99;\n                            break;\n                        }\n                        currMaterialSubGeom.count += this.subGeomCounts[key][i - subGeomOffset];\n                    }\n                    offset += currMaterialSubGeom.count;\n                    this.materialSubGeoms[key].push(currMaterialSubGeom);\n                    i--;\n                }\n            }\n            // Note: older version of zcad files would list materials for TRIANGLES and LINES,\n            // but not points, leaving the points unrendered.\n            if (this.subGeomCounts.POINTS.length > 0 && !this.materialSubGeoms.POINTS) {\n                this.materialSubGeoms.POINTS = [\n                    {\n                        materialId: -1,\n                        offset,\n                        count: this.subGeomCounts.POINTS.length,\n                    },\n                ];\n            }\n        }\n        else {\n            this.materialSubGeoms = {};\n            let offset = 0;\n            for (let key in this.counts) {\n                const count = this.counts[key];\n                if (count > 0) {\n                    this.materialSubGeoms[key] = [\n                        {\n                            materialId: -1,\n                            offset,\n                            count,\n                        },\n                    ];\n                }\n                offset += count;\n            }\n        }\n        this.emit('geomDataChanged', {});\n    }\n}\n\n/* eslint-disable guard-for-in */\n// key, toc, geomIndexOffset, geomsRange, isMobileDevice, bufferSlice, genBuffersOpts, context\nconst parseGeomsBinary = (data, callback) => {\n    // eslint-disable-next-line guard-for-in\n    for (const key in data.context.versions) {\n        const v = data.context.versions[key];\n        const version = new Version('');\n        version.major = v.major;\n        version.minor = v.minor;\n        version.patch = v.patch;\n        version.branch = v.branch;\n        data.context.versions[key] = version;\n    }\n    const geomDatas = [];\n    const byteOffset = data.byteOffset;\n    // console.log('byteOffset:' + byteOffset, ' geomsRange:', data.geomsRange)\n    const transferables = [];\n    for (let i = data.geomsRange[0]; i < data.geomsRange[1]; i++) {\n        const reader = new BinReader(data.bufferSlice, data.toc[i] - byteOffset, data.isMobileDevice);\n        const className = reader.loadStr();\n        const pos = reader.pos();\n        // const name = reader.loadStr()\n        // console.log(\n        //   i +\n        //     ':' +\n        //     byteOffset +\n        //     ' className:' +\n        //     className +\n        //     ' name:' +\n        //     name /* + \" pos:\" + (data.toc[i] - byteOffset) + \" bufferSlice.byteLength:\" +  bufferSlice.byteLength*/\n        // )\n        let geom;\n        switch (className) {\n            case 'Points':\n                geom = new Points();\n                break;\n            case 'Lines':\n                geom = new Lines();\n                break;\n            case 'Mesh':\n                geom = new Mesh();\n                break;\n            case 'CompoundGeom':\n                geom = new CompoundGeomLoader();\n                break;\n            default:\n                throw new Error('Unsupported Geom type:' + className);\n        }\n        try {\n            reader.seek(pos); // Reset the pointer to the start of the item data.\n            geom.readBinary(reader, data.context);\n        }\n        catch (e) {\n            console.warn('Error loading:' + geom.name + '\\n:' + e);\n            geomDatas.push({});\n            continue;\n        }\n        const geomBuffers = geom.genBuffers(data.genBuffersOpts);\n        // /////////////////////////////////\n        // Transferables\n        // Transfer all the attributes and indices back to the main thread.\n        if (geomBuffers.indices)\n            transferables.push(geomBuffers.indices.buffer);\n        for (const attrName in geomBuffers.attrBuffers) {\n            // Note: The type value assigned to the attribute can\n            // not be transferred back to the main thread. Convert to\n            // the type name here and send back as a string.\n            const attrData = geomBuffers.attrBuffers[attrName];\n            transferables.push(attrData.values.buffer);\n        }\n        // Compoound Geom buffers\n        if (geomBuffers.materialLibraryIndices) {\n            transferables.push(geomBuffers.materialLibraryIndices.buffer);\n        }\n        if (geomBuffers.subGeomMaterialIndices) {\n            transferables.push(geomBuffers.subGeomMaterialIndices.buffer);\n        }\n        if (geomBuffers.subGeomOffsets) {\n            for (let key in geomBuffers.subGeomOffsets) {\n                transferables.push(geomBuffers.subGeomOffsets[key].buffer);\n            }\n        }\n        // if (geomBuffers.vertexNeighbors) {\n        //   transferables.push(geomBuffers.vertexNeighbors.buffer)\n        // }\n        // /////////////////////////////////\n        geomDatas.push({\n            name: geom.name,\n            type: className,\n            geomBuffers,\n            bbox: geom.getBoundingBox(),\n        });\n    }\n    callback({\n        taskId: data.taskId,\n        geomLibraryId: data.geomLibraryId,\n        geomFileID: data.geomFileID,\n        geomIndexOffset: data.geomIndexOffset,\n        geomsRange: data.geomsRange,\n        geomDatas,\n    }, transferables);\n};\n\nconst handleMessage = function (srcData, postMessage) {\n  parseGeomsBinary(srcData, (resultData, transferables) => {\n    postMessage(resultData, transferables);\n  });\n};\n\n// Check to see if we are running in the Worker before assigning onmessage\nif (globalThis.document === undefined) {\n  globalThis.onmessage = function (event) {\n    if (!event.data) {\n      // Note: we see this occur when loading one large asset many times.\n      // Like when loading the portafil.\n      // It may be due to memory issues, but its not clear.\n      console.warn('GeomLibrary worker.postMessage failed. data was lost on the way to the web worker.');\n      return\n    }\n    // Our worker gets triggered\n    if (!event.data.context) {\n      return\n    }\n    handleMessage(event.data, self.postMessage);\n  };\n}\n\nvar WorkerFactory$1 = createBase64WorkerFactory('Lyogcm9sbHVwLXBsdWdpbi13ZWItd29ya2VyLWxvYWRlciAqLwp2YXIgd29ya2VyX2NvZGUgPSAoZnVuY3Rpb24gKGV4cG9ydHMpIHsKICAgICd1c2Ugc3RyaWN0JzsKCiAgICAvKioKICAgICAqIFN0cmluZyBmdW5jdGlvbnMKICAgICAqCiAgICAgKi8KICAgIGNsYXNzIFN0cmluZ0Z1bmN0aW9ucyB7CiAgICAgICAgLyoqCiAgICAgICAgICogUmVwbGFjZXMgYWxsIG1hdGNoZXMgaW4gYSBzdHJpbmcuCiAgICAgICAgICoKICAgICAgICAgKiBAc3RhdGljCiAgICAgICAgICogQHBhcmFtIHN0ciAtCiAgICAgICAgICogQHBhcmFtIHBhdHRlcm4gLQogICAgICAgICAqIEBwYXJhbSByZXBsYWNlbWVudCAtCiAgICAgICAgICogQHJldHVybiAtCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIHJlcGxhY2VBbGwoc3RyLCBwYXR0ZXJuLCByZXBsYWNlbWVudCkgewogICAgICAgICAgICByZXR1cm4gc3RyLnJlcGxhY2UobmV3IFJlZ0V4cChwYXR0ZXJuLCAnZycpLCByZXBsYWNlbWVudCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgSlNPTiBvYmplY3QgYXMgYSBmb3JtYXR0ZWQgc3RyaW5nLCBidXQgdGhlIG51bWVyaWMgdmFsdWVzIGFyZSBmaXhlZCB0byB0aGUgc3BlY2lmaWVkIHByZWNpc2lvbi4KICAgICAgICAgKgogICAgICAgICAqIEBzdGF0aWMKICAgICAgICAgKiBAcGFyYW0gdmFsIC0KICAgICAgICAgKiBAcGFyYW0gc3BhY2UgLQogICAgICAgICAqIEBwYXJhbSBwcmVjaXNpb24gLQogICAgICAgICAqIEByZXR1cm4gLQogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBzdHJpbmdpZnlKU09OV2l0aEZpeGVkUHJlY2lzaW9uKHZhbCwgc3BhY2UgPSAwLCBwcmVjaXNpb24gPSA1KSB7CiAgICAgICAgICAgIHJldHVybiBKU09OLnN0cmluZ2lmeSh2YWwsIChfLCB2YWwpID0+IHsKICAgICAgICAgICAgICAgIHJldHVybiB2YWwgPyAodmFsLnRvRml4ZWQgPyBOdW1iZXIodmFsLnRvRml4ZWQocHJlY2lzaW9uKSkgOiB2YWwpIDogdmFsOwogICAgICAgICAgICB9LCBzcGFjZSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRyYW5zZm9ybXMgdGhlIGdpdmVuIHN0cmluZyBpbnRvIGEgbnVtZXJpYyB2YWx1ZS4KICAgICAgICAgKgogICAgICAgICAqIEBzdGF0aWMKICAgICAgICAgKiBAcGFyYW0gc3RyIC0KICAgICAgICAgKiBAcmV0dXJuIC0KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgaGFzaFN0cihzdHIpIHsKICAgICAgICAgICAgbGV0IGhhc2ggPSAwOwogICAgICAgICAgICBsZXQgaTsKICAgICAgICAgICAgbGV0IGNocjsKICAgICAgICAgICAgbGV0IGxlbjsKICAgICAgICAgICAgaWYgKHN0ci5sZW5ndGggPT09IDApCiAgICAgICAgICAgICAgICByZXR1cm4gaGFzaDsKICAgICAgICAgICAgZm9yIChpID0gMCwgbGVuID0gc3RyLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7CiAgICAgICAgICAgICAgICBjaHIgPSBzdHIuY2hhckNvZGVBdChpKTsKICAgICAgICAgICAgICAgIGhhc2ggPSAoaGFzaCA8PCA1KSAtIGhhc2ggKyBjaHI7CiAgICAgICAgICAgICAgICBoYXNoIHw9IDA7IC8vIENvbnZlcnQgdG8gMzJiaXQgaW50ZWdlcgogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBNYXRoLmFicyhoYXNoKTsKICAgICAgICB9CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXByZXNlbnRpbmcgYSBWZWMyKHR3by1kaW1lbnNpb25hbCBmbG9hdGluZyBwb2ludCB2ZWN0b3IpLiBBIFZlYzIgaXMgZm9yIHJlcHJlc2VudGluZyAyIGRpbWVuc2lvbmFsIHZhbHVlcywgc3VjaCBhcyBzY3JlZW4gY29vcmRpbmF0ZXMgb3IgcGl4ZWwgY29vcmRpbmF0ZXMgd2l0aGluIGFuIGltYWdlLgogICAgICoKICAgICAqIE1hdGggdHlwZXMgaW50ZXJuYWxseSBzdG9yZSB2YWx1ZXMgaW4ge0BsaW5rIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0phdmFTY3JpcHQvUmVmZXJlbmNlL0dsb2JhbF9PYmplY3RzL0Zsb2F0MzJBcnJheXxGbG9hdDMyQXJyYXl9IGFuZAogICAgICogZXhwb3NlIGdldHRlcnMgYW5kIHNldHRlcnMgZm9yIHRoZSBjb21wb25lbnQgdmFsdWVzLgogICAgICoKICAgICAqLwogICAgY2xhc3MgVmVjMiB7CiAgICAgICAgeDsKICAgICAgICB5OwogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgYSBWZWMyLgogICAgICAgICAqCiAgICAgICAgICogYGBgamF2YXNjcmlwdAogICAgICAgICAqICBjb25zdCBteVZlYzIgPSBuZXcgVmVjMigxLjIsIDMuNCkKICAgICAgICAgKiBgYGAKICAgICAgICAgKgogICAgICAgICAqLwogICAgICAgIGNvbnN0cnVjdG9yKHggPSAwLCB5ID0gMCkgewogICAgICAgICAgICB0aGlzLnggPSB4OwogICAgICAgICAgICB0aGlzLnkgPSB5OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTZXR0ZXIgZnJvbSBzY2FsYXIgY29tcG9uZW50cy4KICAgICAgICAgKiBAcGFyYW0geCAtIFRoZSB4IGNvbXBvbmVudC4KICAgICAgICAgKiBAcGFyYW0geSAgLSBUaGUgeSBjb21wb25lbnQuCiAgICAgICAgICovCiAgICAgICAgc2V0KHgsIHkpIHsKICAgICAgICAgICAgdGhpcy54ID0geDsKICAgICAgICAgICAgdGhpcy55ID0geTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmVwbGFjZXMgdGhpcyBWZWMyIGRhdGEgd2l0aCB0aGUgVmVjMiBkYXRhIHBhc3NlZCBhcyBwYXJhbWV0ZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gb3RoZXIgLSBUaGUgb3RoZXIgVmVjMiB0byBzZXQgZnJvbS4KICAgICAgICAgKi8KICAgICAgICBzZXRGcm9tT3RoZXIob3RoZXIpIHsKICAgICAgICAgICAgdGhpcy54ID0gb3RoZXIueDsKICAgICAgICAgICAgdGhpcy55ID0gb3RoZXIueTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ2hlY2tzIGlmIHRoaXMgVmVjMiBjb250YWlucyB0aGUgc2FtZSB2YWx1ZXMgYXMgdGhlIG90aGVyIFZlYzIuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gb3RoZXIgLSBUaGUgb3RoZXIgVmVjMiB0byBjb21wYXJlIHdpdGguCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgYHRydWVgIGlmIGFyZSB0aGUgc2FtZSBWZWN0b3IsIG90aGVyd2lzZSwgYGZhbHNlYC4KICAgICAgICAgKi8KICAgICAgICBpc0VxdWFsKG90aGVyKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLnggPT0gb3RoZXIueCAmJiB0aGlzLnkgPT0gb3RoZXIueTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ2hlY2tzIGlmIHRoaXMgVmVjMiBpcyBkaWZmZXJlbnQgZnJvbSBhbm90aGVyIFZlYzIuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gb3RoZXIgLSBUaGUgb3RoZXIgVmVjMiB0byBjb21wYXJlIHdpdGguCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgYHRydWVgIGlmIHRoZSBWZWMycyBhcmUgZGlmZmVyZW50LCBvdGhlcndpc2UsIGBmYWxzZWAuCiAgICAgICAgICovCiAgICAgICAgbm90RXF1YWwob3RoZXIpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMueCAhPSBvdGhlci54ICYmIHRoaXMueSAhPSBvdGhlci55OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIHRydWUgaWYgdGhpcyBWZWMyIGlzIGFwcHJveGltYXRlbHkgdGhlIHNhbWUgYXMgb3RoZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gb3RoZXIgLSBUaGUgb3RoZXIgVmVjMiB0byBjb21wYXJlIHdpdGguCiAgICAgICAgICogQHBhcmFtIHByZWNpc2lvbiAtIFRoZSBwcmVjaXNpb24gdG8gd2hpY2ggdGhlIHZhbHVlcyBtdXN0IG1hdGNoLgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIHRydWUgb3IgZmFsc2UuCiAgICAgICAgICovCiAgICAgICAgYXBwcm94RXF1YWwob3RoZXIsIHByZWNpc2lvbiA9IE51bWJlci5FUFNJTE9OKSB7CiAgICAgICAgICAgIHJldHVybiBNYXRoLmFicyh0aGlzLnggLSBvdGhlci54KSA8IHByZWNpc2lvbiAmJiBNYXRoLmFicyh0aGlzLnkgLSBvdGhlci55KSA8IHByZWNpc2lvbjsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQWRkcyBvdGhlciB0byB0aGlzIFZlYzIgYW5kIHJldHVybnMgdGhlIHJlc3VsdCBhcyBhIG5ldyBWZWMyLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIG90aGVyIC0gVGhlIG90aGVyIFZlYzIgdG8gYWRkLgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGEgbmV3IFZlYzIuCiAgICAgICAgICovCiAgICAgICAgYWRkKG90aGVyKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgVmVjMih0aGlzLnggKyBvdGhlci54LCB0aGlzLnkgKyBvdGhlci55KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQWRkcyBhIFZlYzIgdG8gdGhpcyBWZWMyLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIG90aGVyIC0gVGhlIG90aGVyIFZlYzIgdG8gYWRkLgogICAgICAgICAqLwogICAgICAgIGFkZEluUGxhY2Uob3RoZXIpIHsKICAgICAgICAgICAgdGhpcy54ICs9IG90aGVyLng7CiAgICAgICAgICAgIHRoaXMueSArPSBvdGhlci55OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTdWJ0cmFjdHMgYSBWZWMyIGZyb20gdGhpcyBWZWMyIGFuZCByZXR1cm5zIHRoZSByZXN1bHQgYXMgYSBuZXcgVmVjMi4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBvdGhlciAtIFRoZSBvdGhlciBWZWMyIHRvIHN1YnRyYWN0LgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGEgbmV3IFZlYzIuCiAgICAgICAgICovCiAgICAgICAgc3VidHJhY3Qob3RoZXIpIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBWZWMyKHRoaXMueCAtIG90aGVyLngsIHRoaXMueSAtIG90aGVyLnkpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTdWJ0cmFjdHMgYSBWZWMyIGZyb20gdGhpcyBWZWMyLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIG90aGVyIC0gVGhlIG90aGVyIFZlYzIgdG8gc3VidHJhY3QuCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgYSBuZXcgVmVjMi4KICAgICAgICAgKi8KICAgICAgICBzdWJ0cmFjdEluUGxhY2Uob3RoZXIpIHsKICAgICAgICAgICAgdGhpcy54IC09IG90aGVyLng7CiAgICAgICAgICAgIHRoaXMueSAtPSBvdGhlci55OwogICAgICAgICAgICByZXR1cm4gdGhpczsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU2NhbGVzIHRoaXMgVmVjMiBieSBzY2FsYXIgYW5kIHJldHVybnMgdGhlIHJlc3VsdCBhcyBhIG5ldyBWZWMyLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHNjYWxhciAtIFRoZSBzY2FsYXIgdmFsdWUuCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgYSBuZXcgVmVjMi4KICAgICAgICAgKi8KICAgICAgICBzY2FsZShzY2FsYXIpIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBWZWMyKHRoaXMueCAqIHNjYWxhciwgdGhpcy55ICogc2NhbGFyKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU2NhbGVzIHRoaXMgVmVjMiBieSBzY2FsYXIuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gc2NhbGFyIC0gVGhlIHNjYWxhciB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBzY2FsZUluUGxhY2Uoc2NhbGFyKSB7CiAgICAgICAgICAgIHRoaXMueCAqPSBzY2FsYXI7CiAgICAgICAgICAgIHRoaXMueSAqPSBzY2FsYXI7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEludmVydHMgdGhpcyBWZWMyIGFuZCByZXR1cm5zIHRoZSByZXN1bHQgYXMgYSBuZXcgVmVjMi4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGEgbmV3IFZlYzIuCiAgICAgICAgICovCiAgICAgICAgaW52ZXJ0KCkgewogICAgICAgICAgICByZXR1cm4gbmV3IFZlYzIoMS4wIC8gdGhpcy54LCAxLjAgLyB0aGlzLnkpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBJbnZlcnRzIHRoaXMgVmVjMi4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGludmVydEluUGxhY2UoKSB7CiAgICAgICAgICAgIHRoaXMueCA9IDEuMCAvIHRoaXMueDsKICAgICAgICAgICAgdGhpcy55ID0gMS4wIC8gdGhpcy55OwogICAgICAgICAgICByZXR1cm4gdGhpczsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogTXVsdGlwbGllcyBhIFZlYzIgd2l0aCB0aGlzIFZlYzIgYW5kIHJldHVybnMgdGhlIHJlc3VsdCBhcyBhIG5ldyBWZWMyLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIG90aGVyIC0gVGhlIG90aGVyIFZlYzIgdG8gbXVsdGlwbHkgd2l0aC4KICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyBhIG5ldyBWZWMyLgogICAgICAgICAqLwogICAgICAgIG11bHRpcGx5KG90aGVyKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgVmVjMih0aGlzLnggKiBvdGhlci54LCB0aGlzLnkgKiBvdGhlci55KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogTXVsdGlwbGllcyBhIFZlYzIgd2l0aCB0aGlzIFZlYzIuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gb3RoZXIgLSBUaGUgb3RoZXIgVmVjMiB0byBtdWx0aXBseSB3aXRoLgogICAgICAgICAqLwogICAgICAgIG11bHRpcGx5SW5QbGFjZShvdGhlcikgewogICAgICAgICAgICB0aGlzLnggKj0gb3RoZXIueDsKICAgICAgICAgICAgdGhpcy55ICo9IG90aGVyLnk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENhbGN1bGF0ZXMgdGhlIHNxdWFyZWQgbGVuZ3RoIG9mIHRoaXMgVmVjMi4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIHRoZSBsZW5ndGggc3F1YXJlZC4KICAgICAgICAgKi8KICAgICAgICBsZW5ndGhTcXVhcmVkKCkgewogICAgICAgICAgICBjb25zdCB4ID0gdGhpcy54OwogICAgICAgICAgICBjb25zdCB5ID0gdGhpcy55OwogICAgICAgICAgICByZXR1cm4geCAqIHggKyB5ICogeTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ2FsY3VsYXRlcyB0aGUgbGVuZ3RoIG9mIHRoaXMgVmVjMi4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIHRoZSBsZW5ndGguCiAgICAgICAgICovCiAgICAgICAgbGVuZ3RoKCkgewogICAgICAgICAgICByZXR1cm4gTWF0aC5zcXJ0KHRoaXMubGVuZ3RoU3F1YXJlZCgpKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ2FsY3VsYXRlcyB0aGUgZGlzdGFuY2UgdG8gYW5vdGhlciB2ZWN0b3IuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gb3RoZXIgLSBUaGUgb3RoZXIgdmFsdWUuCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgdGhlIGRpc3RhbmNlIGJldHdlZW4gdmVjdG9ycy4KICAgICAgICAgKi8KICAgICAgICBkaXN0YW5jZVRvKG90aGVyKSB7CiAgICAgICAgICAgIGNvbnN0IHggPSB0aGlzLnggLSBvdGhlci54OwogICAgICAgICAgICBjb25zdCB5ID0gdGhpcy55IC0gb3RoZXIueTsKICAgICAgICAgICAgcmV0dXJuIE1hdGguc3FydCh4ICogeCArIHkgKiB5KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogTm9ybWFsaXplcyB0aGUgVmVjMiBhbmQgcmV0dXJucyBpdCBhcyBhIG5ldyBWZWMyLgogICAgICAgICAqIE11bHRpcGxpZXMgY29vcmRpbmF0ZXMgdmFsdWUgYnkgdGhlIGludmVyc2Ugb2YgdGhlIHZlY3RvciBsZW5ndGguCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyB0aGUgVmVjMiBub3JtYWxpemVkLgogICAgICAgICAqLwogICAgICAgIG5vcm1hbGl6ZSgpIHsKICAgICAgICAgICAgY29uc3QgeCA9IHRoaXMueDsKICAgICAgICAgICAgY29uc3QgeSA9IHRoaXMueTsKICAgICAgICAgICAgbGV0IGxlbiA9IHggKiB4ICsgeSAqIHk7CiAgICAgICAgICAgIGlmIChsZW4gPCBOdW1iZXIuRVBTSUxPTikgewogICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBWZWMyKCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLy8gVE9ETzogZXZhbHVhdGUgdXNlIG9mIGdsbV9pbnZzcXJ0IGhlcmU/CiAgICAgICAgICAgIGxlbiA9IDEgLyBNYXRoLnNxcnQobGVuKTsKICAgICAgICAgICAgcmV0dXJuIG5ldyBWZWMyKHggKiBsZW4sIHkgKiBsZW4pOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBOb3JtYWxpemVzIHRoaXMgVmVjMiBtdWx0aXBseWluZyBjb29yZGluYXRlIHZhbHVlcyBieSB0aGUgaW52ZXJzZSBvZiB0aGUgdmVjdG9yIGxlbmd0aC4KICAgICAgICAgKi8KICAgICAgICBub3JtYWxpemVJblBsYWNlKCkgewogICAgICAgICAgICBjb25zdCB4ID0gdGhpcy54OwogICAgICAgICAgICBjb25zdCB5ID0gdGhpcy55OwogICAgICAgICAgICBsZXQgbGVuID0geCAqIHggKyB5ICogeTsKICAgICAgICAgICAgaWYgKGxlbiA8IE51bWJlci5FUFNJTE9OKSB7CiAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgIH0KICAgICAgICAgICAgbGVuID0gMSAvIE1hdGguc3FydChsZW4pOwogICAgICAgICAgICB0aGlzLnNldCh4ICogbGVuLCB5ICogbGVuKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ2FsY3VsYXRlcyB0aGUgZG90IHByb2R1Y3Qgb2YgdGhpcyBWZWMyIGFnYWluc3QgYW5vdGhlciBWZWMyLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIG90aGVyIC0gVGhlIG90aGVyIFZlYzIgdG8gY29tcGFyZSB3aXRoLgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIHRoZSBkb3QgcHJvZHVjdC4KICAgICAgICAgKi8KICAgICAgICBkb3Qob3RoZXIpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMueCAqIG90aGVyLnggKyB0aGlzLnkgKiBvdGhlci55OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDYWxjdWxhdGVzIHRoZSBjcm9zcyBwcm9kdWN0IG9mIHRoaXMgVmVjMiBhZ2FpbnN0IGFub3RoZXIgVmVjMi4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBvdGhlciAtIFRoZSBvdGhlciBWZWMyIHRvIGNvbXBhcmUgd2l0aC4KICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyB0aGUgY3Jvc3MgcHJvZHVjdC4KICAgICAgICAgKi8KICAgICAgICBjcm9zcyhvdGhlcikgewogICAgICAgICAgICAvLyBqdXN0IGNhbGN1bGF0ZSB0aGUgei1jb21wb25lbnQKICAgICAgICAgICAgcmV0dXJuIHRoaXMueCAqIG90aGVyLnkgLSB0aGlzLnkgKiBvdGhlci54OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBHZXRzIHRoZSBhbmdsZSBiZXR3ZWVuIHRoaXMgVmVjMiBhbmQgb3RoZXIgYXNzdW1pbmcgYm90aCBhcmUgbm9ybWFsaXplZCB2ZWN0b3JzLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIG90aGVyIC0gVGhlIG90aGVyIFZlYzIgdG8gY29tcGFyZSB3aXRoLgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIHRoZSBhbmdsZSBpbiByYWRpYW5zLgogICAgICAgICAqLwogICAgICAgIGFuZ2xlVG8ob3RoZXIpIHsKICAgICAgICAgICAgY29uc3QgY29zaW5lID0gdGhpcy5ub3JtYWxpemUoKS5kb3Qob3RoZXIubm9ybWFsaXplKCkpOwogICAgICAgICAgICBpZiAoY29zaW5lID4gMS4wKQogICAgICAgICAgICAgICAgcmV0dXJuIDAuMDsKICAgICAgICAgICAgZWxzZSBpZiAoY29zaW5lIDwgLTEuMCkKICAgICAgICAgICAgICAgIHJldHVybiBNYXRoLlBJOwogICAgICAgICAgICBlbHNlCiAgICAgICAgICAgICAgICByZXR1cm4gTWF0aC5hY29zKGNvc2luZSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEdldHMgdGhlIGFuZ2xlIGJldHdlZW4gdGhpcyBWZWMyIGFuZCBvdGhlci4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBvdGhlciAtIFRoZSBvdGhlciBWZWMyIHRvIGNvbXBhcmUgd2l0aC4KICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyB0aGUgYW5nbGUgaW4gcmFkaWFucy4KICAgICAgICAgKi8KICAgICAgICBzaWduZWRBbmdsZVRvKG90aGVyKSB7CiAgICAgICAgICAgIGNvbnN0IGFuZ2xlID0gdGhpcy5hbmdsZVRvKG90aGVyKTsKICAgICAgICAgICAgaWYgKHRoaXMuY3Jvc3Mob3RoZXIpIDwgMC4wKQogICAgICAgICAgICAgICAgcmV0dXJuIC1hbmdsZTsKICAgICAgICAgICAgZWxzZQogICAgICAgICAgICAgICAgcmV0dXJuIGFuZ2xlOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSb3RhdGVzIGEgVmVjMiBpbiBhIGNsb2Nrd2lzZSBkaXJlY3Rpb24gYW5kIHJldHVybnMgYSBuZXcgcm90YXRlZCBWZWMyLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGFuZ2xlIC0gVGhlIGFuZ2xlIG9mIHJvdGF0aW9uLgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIHRoZSByb3RhdGVkIHZlY3Rvci4KICAgICAgICAgKi8KICAgICAgICByb3RhdGUoYW5nbGUpIHsKICAgICAgICAgICAgY29uc3QgY29zQSA9IE1hdGguY29zKGFuZ2xlKTsKICAgICAgICAgICAgY29uc3Qgc2luQSA9IE1hdGguc2luKGFuZ2xlKTsKICAgICAgICAgICAgcmV0dXJuIG5ldyBWZWMyKHRoaXMueCAqIGNvc0EgLSB0aGlzLnkgKiBzaW5BLCB0aGlzLnggKiBzaW5BICsgdGhpcy55ICogY29zQSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFBlcmZvcm1zIGEgbGluZWFyIGludGVycG9sYXRpb24gYmV0d2VlbiB0aGlzIFZlYzIgYW5kIG90aGVyIFZlYzIuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gb3RoZXIgLSBUaGUgb3RoZXIgVmVjMiB0byBpbnRlcnBvbGF0ZSBiZXR3ZWVuLgogICAgICAgICAqIEBwYXJhbSB0IC0gSW50ZXJwb2xhdGlvbiBhbW91bnQgYmV0d2VlbiB0aGUgdHdvIGlucHV0cy4KICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyBhIG5ldyBWZWMyLgogICAgICAgICAqLwogICAgICAgIGxlcnAob3RoZXIsIHQpIHsKICAgICAgICAgICAgY29uc3QgYXggPSB0aGlzLng7CiAgICAgICAgICAgIGNvbnN0IGF5ID0gdGhpcy55OwogICAgICAgICAgICByZXR1cm4gbmV3IFZlYzIoYXggKyB0ICogKG90aGVyLnggLSBheCksIGF5ICsgdCAqIChvdGhlci55IC0gYXkpKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogR2VuZXJhdGVzIGEgcmFuZG9tIHZlY3RvciB3aXRoIHRoZSBnaXZlbiBzY2FsZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBzY2FsZSAtIExlbmd0aCBvZiB0aGUgcmVzdWx0aW5nIHZlY3Rvci4gSWYgb21pdHRlZCwgYSB1bml0IHZlY3RvciB3aWxsIGJlIHJldHVybmVkLgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHNldFJhbmRvbURpcihzY2FsZSA9IDEuMCkgewogICAgICAgICAgICBjb25zdCByID0gTWF0aC5yYW5kb20oKSAqIDIuMCAqIE1hdGguUEk7CiAgICAgICAgICAgIHRoaXMueCA9IE1hdGguY29zKHIpICogc2NhbGU7CiAgICAgICAgICAgIHRoaXMueSA9IE1hdGguc2luKHIpICogc2NhbGU7CiAgICAgICAgICAgIHJldHVybiB0aGlzOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSYW5kb21pemVzIHRoZSBzY2FsZSBvZiB0aGlzIFZlYzIgY29vcmRpbmF0ZXMuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gc2NhbGUgLSBUaGUgc2NhbGUgdmFsdWUuCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgc2V0UmFuZG9tKHNjYWxlID0gMS4wKSB7CiAgICAgICAgICAgIHRoaXMueCA9IE1hdGgucmFuZG9tKCkgKiBzY2FsZTsKICAgICAgICAgICAgdGhpcy55ID0gTWF0aC5yYW5kb20oKSAqIHNjYWxlOwogICAgICAgICAgICByZXR1cm4gdGhpczsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ2xvbmVzIHRoaXMgVmVjMiBhbmQgcmV0dXJucyBhIG5ldyBWZWMyLgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgYSBuZXcgVmVjMi4KICAgICAgICAgKi8KICAgICAgICBjbG9uZSgpIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBWZWMyKHRoaXMueCwgdGhpcy55KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyBjdXJyZW50IFZlYzIgZGF0YSBhcyBhcnJheS4gT2Z0ZW4gdXNlZCB0byBwYXNzIHR5cGVzIHRvIHRoZSBHUFUuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyBhcyBhbiBhcnJheS4KICAgICAgICAgKi8KICAgICAgICBhc0FycmF5KCkgewogICAgICAgICAgICByZXR1cm4gW3RoaXMueCwgdGhpcy55XTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU2V0dGVyIGZyb20gYW4gYXJyYXkuCiAgICAgICAgICovCiAgICAgICAgZnJvbUFycmF5KHZhbHMpIHsKICAgICAgICAgICAgdGhpcy54ID0gdmFsc1swXTsKICAgICAgICAgICAgdGhpcy55ID0gdmFsc1sxXTsKICAgICAgICB9CiAgICAgICAgLy8gLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCiAgICAgICAgLy8gUGVyc2lzdGVuY2UKICAgICAgICAvKioKICAgICAgICAgKiBDb252ZXJ0cyB0aGlzIFZlYzMgdG8gYSBzdHJpbmcgaW4gSlNPTiBmb3JtYXQuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICB0b1N0cmluZygpIHsKICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5ldy1jYXAKICAgICAgICAgICAgcmV0dXJuIFN0cmluZ0Z1bmN0aW9ucy5zdHJpbmdpZnlKU09OV2l0aEZpeGVkUHJlY2lzaW9uKHRoaXMudG9KU09OKCkpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBFbmNvZGVzIFZlYzIgQ2xhc3MgYXMgYSBKU09OIG9iamVjdCBmb3IgcGVyc2lzdGVuY2UuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIGpzb24gb2JqZWN0LgogICAgICAgICAqLwogICAgICAgIHRvSlNPTigpIHsKICAgICAgICAgICAgcmV0dXJuIHsKICAgICAgICAgICAgICAgIHg6IHRoaXMueCwKICAgICAgICAgICAgICAgIHk6IHRoaXMueSwKICAgICAgICAgICAgfTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogRGVjb2RlcyBhIEpTT04gb2JqZWN0IHRvIHNldCB0aGUgc3RhdGUgb2YgdGhpcyBjbGFzcy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBqIC0gVGhlIGpzb24gb2JqZWN0LgogICAgICAgICAqLwogICAgICAgIGZyb21KU09OKGopIHsKICAgICAgICAgICAgdGhpcy54ID0gai54OwogICAgICAgICAgICB0aGlzLnkgPSBqLnk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIExvYWRzIHRoZSBzdGF0ZSBvZiB0aGUgdmFsdWUgZnJvbSBhIGJpbmFyeSByZWFkZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gcmVhZGVyIC0gVGhlIHJlYWRlciB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICByZWFkQmluYXJ5KHJlYWRlcikgewogICAgICAgICAgICB0aGlzLnggPSByZWFkZXIubG9hZEZsb2F0MzIoKTsKICAgICAgICAgICAgdGhpcy55ID0gcmVhZGVyLmxvYWRGbG9hdDMyKCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENhbGN1bGF0ZSB0aGUgaW50ZXJzZWN0aW9uIHBvaW50IG9mIDIgMmQgbGluZXMsIHJldHVybmluZyB0aGUgcGFyYW1ldGVycyB2YWx1ZXMgZm9yIGVhY2ggbGluZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBwMCAtIFRoZSBwb2ludCBvZiB0aGUgZmlyc3QgbGluZQogICAgICAgICAqIEBwYXJhbSBkMCAtIFRoZSBkaXJlY3Rpb24gb2YgdGhlIGZpcnN0IGxpbmUKICAgICAgICAgKiBAcGFyYW0gcDEgLSBUaGUgcG9pbnQgb2YgdGhlIHNlY29uZCBsaW5lCiAgICAgICAgICogQHBhcmFtIGQxIC0gVGhlIGRpcmVjdGlvbiBvZiB0aGUgc2Vjb25kIGxpbmUKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyBhbiBhcnJheSBjb250YWluaW5nIDIgcGFyYW1ldGVyIHZhbHVlcyBmb3IgdGhlIDIgbGluZXMuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGludGVyc2VjdGlvbk9mTGluZXMocDEsIHAyLCBwMywgcDQpIHsKICAgICAgICAgICAgLy8gaHR0cHM6Ly9kaXJhc2suY29tL3Bvc3RzL0phdmFTY3JpcHQtaG93LXRvLWNhbGN1bGF0ZS1pbnRlcnNlY3Rpb24tcG9pbnQtb2YtdHdvLWxpbmVzLWZvci1naXZlbi00LXBvaW50cy1WanZuQWoKICAgICAgICAgICAgLy8gZG93biBwYXJ0IG9mIGludGVyc2VjdGlvbiBwb2ludCBmb3JtdWxhCiAgICAgICAgICAgIGNvbnN0IGQxID0gKHAxLnggLSBwMi54KSAqIChwMy55IC0gcDQueSk7IC8vICh4MSAtIHgyKSAqICh5MyAtIHk0KQogICAgICAgICAgICBjb25zdCBkMiA9IChwMS55IC0gcDIueSkgKiAocDMueCAtIHA0LngpOyAvLyAoeTEgLSB5MikgKiAoeDMgLSB4NCkKICAgICAgICAgICAgY29uc3QgZCA9IGQxIC0gZDI7CiAgICAgICAgICAgIGlmIChkID09IDApIHsKICAgICAgICAgICAgICAgIHJldHVybiBudWxsOwogICAgICAgICAgICB9CiAgICAgICAgICAgIC8vIHVwcGVyIHBhcnQgb2YgaW50ZXJzZWN0aW9uIHBvaW50IGZvcm11bGEKICAgICAgICAgICAgY29uc3QgdTEgPSBwMS54ICogcDIueSAtIHAxLnkgKiBwMi54OyAvLyAoeDEgKiB5MiAtIHkxICogeDIpCiAgICAgICAgICAgIGNvbnN0IHU0ID0gcDMueCAqIHA0LnkgLSBwMy55ICogcDQueDsgLy8gKHgzICogeTQgLSB5MyAqIHg0KQogICAgICAgICAgICBjb25zdCB1MnggPSBwMy54IC0gcDQueDsgLy8gKHgzIC0geDQpCiAgICAgICAgICAgIGNvbnN0IHUzeCA9IHAxLnggLSBwMi54OyAvLyAoeDEgLSB4MikKICAgICAgICAgICAgY29uc3QgdTJ5ID0gcDMueSAtIHA0Lnk7IC8vICh5MyAtIHk0KQogICAgICAgICAgICBjb25zdCB1M3kgPSBwMS55IC0gcDIueTsgLy8gKHkxIC0geTIpCiAgICAgICAgICAgIC8vIGludGVyc2VjdGlvbiBwb2ludCBmb3JtdWxhCiAgICAgICAgICAgIGNvbnN0IHB4ID0gKHUxICogdTJ4IC0gdTN4ICogdTQpIC8gZDsKICAgICAgICAgICAgY29uc3QgcHkgPSAodTEgKiB1MnkgLSB1M3kgKiB1NCkgLyBkOwogICAgICAgICAgICByZXR1cm4gbmV3IFZlYzIocHgsIHB5KTsKICAgICAgICB9CiAgICAgICAgaXNWYWxpZCgpIHsKICAgICAgICAgICAgZm9yIChjb25zdCB2IG9mIHRoaXMuYXNBcnJheSgpKSB7CiAgICAgICAgICAgICAgICBpZiAodiA9PSBJbmZpbml0eSB8fCBpc05hTih2KSkKICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIHRydWU7CiAgICAgICAgfQogICAgfQoKICAgIC8qKgogICAgICogUmVwcmVzZW50cyBhIHRocmVlIGRpbWVuc2lvbmFsIGNvb3JkaW5hdGUsIHN1Y2ggYXMgM0Qgc2NlbmUgdmFsdWVzLCBvciBtZXNoIHZlcnRleCBwb3NpdGlvbnMuCiAgICAgKi8KICAgIGNsYXNzIFZlYzMgewogICAgICAgIHg7CiAgICAgICAgeTsKICAgICAgICB6OwogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgYSBWZWMzLgogICAgICAgICAqLwogICAgICAgIGNvbnN0cnVjdG9yKHggPSAwLCB5ID0gMCwgeiA9IDApIHsKICAgICAgICAgICAgdGhpcy54ID0geDsKICAgICAgICAgICAgdGhpcy55ID0geTsKICAgICAgICAgICAgdGhpcy56ID0gejsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogR2V0dGVyIGZvciBgeHlgIHN3aXp6ZWwuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyB0aGUgeHkgY29tcG9uZW50cyBhcyBhIFZlYzIuCiAgICAgICAgICovCiAgICAgICAgZ2V0IHh5KCkgewogICAgICAgICAgICByZXR1cm4gbmV3IFZlYzIodGhpcy54LCB0aGlzLnkpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBHZXR0ZXIgZm9yIGB5emAgc3dpenplbC4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIHRoZSB5eiBjb21wb25lbnRzIGFzIGEgVmVjMi4KICAgICAgICAgKi8KICAgICAgICBnZXQgeXooKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgVmVjMih0aGlzLnksIHRoaXMueik7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFNldHRlciBmcm9tIHNjYWxhciBjb21wb25lbnRzLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHggLSBUaGUgeCBjb21wb25lbnQuCiAgICAgICAgICogQHBhcmFtIHkgLSBUaGUgeSBjb21wb25lbnQuCiAgICAgICAgICogQHBhcmFtIHogLSBUaGUgeSBjb21wb25lbnQuCiAgICAgICAgICovCiAgICAgICAgc2V0KHgsIHksIHopIHsKICAgICAgICAgICAgdGhpcy54ID0geDsKICAgICAgICAgICAgdGhpcy55ID0geSAhPT0gdW5kZWZpbmVkID8geSA6IHg7CiAgICAgICAgICAgIHRoaXMueiA9IHogIT09IHVuZGVmaW5lZCA/IHogOiB4OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTZXRzIHRoZSBzdGF0ZSBvZiBhIFZlYzMgT2JqZWN0IGZyb20gYW5vdGhlciBWZWMzLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIG90aGVyIC0gVGhlIG90aGVyIFZlYzMgdG8gc2V0IGZyb20uCiAgICAgICAgICovCiAgICAgICAgc2V0RnJvbU90aGVyKG90aGVyKSB7CiAgICAgICAgICAgIHRoaXMueCA9IG90aGVyLng7CiAgICAgICAgICAgIHRoaXMueSA9IG90aGVyLnk7CiAgICAgICAgICAgIHRoaXMueiA9IG90aGVyLno7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENoZWNrcyBpZiB0aGUgY29vcmRpbmF0ZXMgb2YgdGhpcyBWZWMzIGFyZSAwIDAgMC4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgY29vcmRpbmF0ZXMgYXJlKDAsIDAsIDApLCBvdGhlcndpc2UsIGBmYWxzZWAuCiAgICAgICAgICovCiAgICAgICAgaXNOdWxsKCkgewogICAgICAgICAgICByZXR1cm4gTWF0aC5hYnModGhpcy54KSA8IE51bWJlci5FUFNJTE9OICYmIE1hdGguYWJzKHRoaXMueSkgPCBOdW1iZXIuRVBTSUxPTiAmJiBNYXRoLmFicyh0aGlzLnopIDwgTnVtYmVyLkVQU0lMT047CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENoZWNrcyBpZiB0aGUgY29vcmRpbmF0ZXMgb2YgdGhpcyBWZWMzIGFyZSAxIDEgMS4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgY29vcmRpbmF0ZXMgYXJlKDEsIDEsIDEpLCBvdGhlcndpc2UsIGBmYWxzZWAuCiAgICAgICAgICovCiAgICAgICAgaXMxMTEoKSB7CiAgICAgICAgICAgIHJldHVybiAoTWF0aC5hYnMoMS4wIC0gdGhpcy54KSA8IE51bWJlci5FUFNJTE9OICYmCiAgICAgICAgICAgICAgICBNYXRoLmFicygxLjAgLSB0aGlzLnkpIDwgTnVtYmVyLkVQU0lMT04gJiYKICAgICAgICAgICAgICAgIE1hdGguYWJzKDEuMCAtIHRoaXMueikgPCBOdW1iZXIuRVBTSUxPTik7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENoZWNrcyBpZiB0aGlzIFZlYzMgY29udGFpbnMgdGhlIHNhbWUgdmFsdWVzIGFzIHRoZSBvdGhlciBWZWMzLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIG90aGVyIC0gVGhlIG90aGVyIFZlYzMgdG8gY29tcGFyZSB3aXRoLgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgdmFsdWVzIGFyZSB0aGUgc2FtZSwgb3RoZXJ3aXNlLCBgZmFsc2VgLgogICAgICAgICAqLwogICAgICAgIGlzRXF1YWwob3RoZXIpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMueCA9PSBvdGhlci54ICYmIHRoaXMueSA9PSBvdGhlci55ICYmIHRoaXMueiA9PSBvdGhlci56OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDaGVja3MgaWYgdGhpcyBWZWMyIGlzIGRpZmZlcmVudCBmcm9tIGFub3RoZXIgVmVjMi4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBvdGhlciAtIFRoZSBvdGhlciBWZWMzIHRvIGNvbXBhcmUgd2l0aC4KICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyBgdHJ1ZWAgaWYgdGhlIFZlYzNzIGFyZSBkaWZmZXJlbnQsIG90aGVyd2lzZSwgYGZhbHNlYC4KICAgICAgICAgKi8KICAgICAgICBub3RFcXVhbChvdGhlcikgewogICAgICAgICAgICByZXR1cm4gdGhpcy54ICE9IG90aGVyLnggJiYgdGhpcy55ICE9IG90aGVyLnkgJiYgdGhpcy56ICE9IG90aGVyLno7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgdHJ1ZSBpZiB0aGlzIFZlYzIgaXMgYXBwcm94aW1hdGVseSB0aGUgc2FtZSBhcyBvdGhlci4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBvdGhlciAtIFRoZSBvdGhlciBWZWMzIHRvIGNvbXBhcmUgd2l0aC4KICAgICAgICAgKiBAcGFyYW0gcHJlY2lzaW9uIC0gVGhlIHByZWNpc2lvbiB0byB3aGljaCB0aGUgdmFsdWVzIG11c3QgbWF0Y2guCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgdHJ1ZSBvciBmYWxzZS4KICAgICAgICAgKi8KICAgICAgICBhcHByb3hFcXVhbChvdGhlciwgcHJlY2lzaW9uID0gTnVtYmVyLkVQU0lMT04pIHsKICAgICAgICAgICAgcmV0dXJuIChNYXRoLmFicyh0aGlzLnggLSBvdGhlci54KSA8IHByZWNpc2lvbiAmJgogICAgICAgICAgICAgICAgTWF0aC5hYnModGhpcy55IC0gb3RoZXIueSkgPCBwcmVjaXNpb24gJiYKICAgICAgICAgICAgICAgIE1hdGguYWJzKHRoaXMueiAtIG90aGVyLnopIDwgcHJlY2lzaW9uKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQWRkcyBvdGhlciB0byB0aGlzIFZlYzMgYW5kIHJldHVybiB0aGUgcmVzdWx0IGFzIGEgbmV3IFZlYzMuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gb3RoZXIgLSBUaGUgb3RoZXIgVmVjMyB0byBhZGQuCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgYSBuZXcgVmVjMy4KICAgICAgICAgKi8KICAgICAgICBhZGQob3RoZXIpIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBWZWMzKHRoaXMueCArIG90aGVyLngsIHRoaXMueSArIG90aGVyLnksIHRoaXMueiArIG90aGVyLnopOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBBZGRzIG90aGVyIHRvIHRoaXMgVmVjMy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBvdGhlciAtIFRoZSBvdGhlciBWZWMzIHRvIGFkZC4KICAgICAgICAgKi8KICAgICAgICBhZGRJblBsYWNlKG90aGVyKSB7CiAgICAgICAgICAgIHRoaXMueCArPSBvdGhlci54OwogICAgICAgICAgICB0aGlzLnkgKz0gb3RoZXIueTsKICAgICAgICAgICAgdGhpcy56ICs9IG90aGVyLno7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFN1YnRyYWN0cyBvdGhlciBmcm9tIHRoaXMgVmVjMyBhbmQgcmV0dXJucyB0aGUgcmVzdWx0IGFzIGEgbmV3IFZlYzMuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gb3RoZXIgLSBUaGUgb3RoZXIgVmVjMyB0byBzdWJ0cmFjdC4KICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyBhIG5ldyBWZWMzLgogICAgICAgICAqLwogICAgICAgIHN1YnRyYWN0KG90aGVyKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgVmVjMyh0aGlzLnggLSBvdGhlci54LCB0aGlzLnkgLSBvdGhlci55LCB0aGlzLnogLSBvdGhlci56KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU3VidHJhY3RzIG90aGVyIGZyb20gdGhpcyBWZWMzLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIG90aGVyIC0gVGhlIG90aGVyIFZlYzMgdG8gc3VidHJhY3QuCiAgICAgICAgICovCiAgICAgICAgc3VidHJhY3RJblBsYWNlKG90aGVyKSB7CiAgICAgICAgICAgIHRoaXMueCAtPSBvdGhlci54OwogICAgICAgICAgICB0aGlzLnkgLT0gb3RoZXIueTsKICAgICAgICAgICAgdGhpcy56IC09IG90aGVyLno7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIE11bHRpcGxpZXMgdHdvIFZlYzNzIGFuZCByZXR1cm5zIHRoZSByZXN1bHQgYXMgYSBuZXcgVmVjMy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBvdGhlciAtIFRoZSBvdGhlciBWZWMzIHRvIG11bHRpcGx5IHdpdGguCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgYSBuZXcgVmVjMy4KICAgICAgICAgKi8KICAgICAgICBtdWx0aXBseShvdGhlcikgewogICAgICAgICAgICByZXR1cm4gbmV3IFZlYzModGhpcy54ICogb3RoZXIueCwgdGhpcy55ICogb3RoZXIueSwgdGhpcy56ICogb3RoZXIueik7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIE11bHRpcGxpZXMgdHdvIFZlYzNzLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIG90aGVyIC0gVGhlIG90aGVyIFZlYzMgdG8gbXVsdGlwbHkgd2l0aC4KICAgICAgICAgKi8KICAgICAgICBtdWx0aXBseUluUGxhY2Uob3RoZXIpIHsKICAgICAgICAgICAgdGhpcy54ICo9IG90aGVyLng7CiAgICAgICAgICAgIHRoaXMueSAqPSBvdGhlci55OwogICAgICAgICAgICB0aGlzLnogKj0gb3RoZXIuejsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogRGl2aWRlcyB0d28gVmVjM3MgYW5kIHJldHVybnMgdGhlIHJlc3VsdCBhcyBhIG5ldyBWZWMzLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHZlYzMgLSBUaGUgb3RoZXIgVmVjMyB0byBkaXZpZGUgYnkuCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgYSBuZXcgVmVjMy4KICAgICAgICAgKi8KICAgICAgICBkaXZpZGUodmVjMykgewogICAgICAgICAgICByZXR1cm4gbmV3IFZlYzModGhpcy54IC8gdmVjMy54LCB0aGlzLnkgLyB2ZWMzLnksIHRoaXMueiAvIHZlYzMueik7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIERpdmlkZXMgdHdvIFZlYzNzLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHZlYzMgLSBUaGUgb3RoZXIgVmVjMyB0byBkaXZpZGUgYnkuCiAgICAgICAgICovCiAgICAgICAgZGl2aWRlSW5QbGFjZSh2ZWMzKSB7CiAgICAgICAgICAgIHRoaXMueCAvPSB2ZWMzLng7CiAgICAgICAgICAgIHRoaXMueSAvPSB2ZWMzLnk7CiAgICAgICAgICAgIHRoaXMueiAvPSB2ZWMzLno7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFNjYWxlcyB0aGlzIFZlYzMgYnkgc2NhbGFyIGFuZCByZXR1cm5zIHRoZSByZXN1bHQgYXMgYSBuZXcgVmVjMy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBzY2FsYXIgLSBUaGUgc2NhbGFyIHZhbHVlLgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGEgbmV3IFZlYzMuCiAgICAgICAgICovCiAgICAgICAgc2NhbGUoc2NhbGFyKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgVmVjMyh0aGlzLnggKiBzY2FsYXIsIHRoaXMueSAqIHNjYWxhciwgdGhpcy56ICogc2NhbGFyKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU2NhbGVzIHRoaXMgVmVjMyBieSBzY2FsYXIuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gc2NhbGFyIC0gVGhlIHNjYWxhciB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBzY2FsZUluUGxhY2Uoc2NhbGFyKSB7CiAgICAgICAgICAgIHRoaXMueCAqPSBzY2FsYXI7CiAgICAgICAgICAgIHRoaXMueSAqPSBzY2FsYXI7CiAgICAgICAgICAgIHRoaXMueiAqPSBzY2FsYXI7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIE5lZ2F0ZXMgdGhpcyBWZWMzICh4ID0gLXgsIHkgPSAteSBhbmQgeiA9IC16KSwgYnV0IHJldHVybnMgdGhlIHJlc3VsdCBhcyBhIG5ldyBWZWMzLgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgYSBuZXcgVmVjMy4KICAgICAgICAgKi8KICAgICAgICBuZWdhdGUoKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgVmVjMygtdGhpcy54LCAtdGhpcy55LCAtdGhpcy56KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyB0aGUgaW52ZXJzZSBvZiB0aGlzIFZlYzMsIGJ1dCByZXR1cm5zLiB0aGUgcmVzdWx0IGFzIGEgbmV3IFZlYzMKICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGEgbmV3IFZlYzMuCiAgICAgICAgICovCiAgICAgICAgaW52ZXJzZSgpIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBWZWMzKDEuMCAvIHRoaXMueCwgMS4wIC8gdGhpcy55LCAxLjAgLyB0aGlzLnopOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDYWxjdWxhdGVzIHRoZSBzcXVhcmVkIGxlbmd0aCBvZiB0aGlzIFZlYzMuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyB0aGUgbGVuZ3RoLgogICAgICAgICAqLwogICAgICAgIGxlbmd0aFNxdWFyZWQoKSB7CiAgICAgICAgICAgIGNvbnN0IHggPSB0aGlzLng7CiAgICAgICAgICAgIGNvbnN0IHkgPSB0aGlzLnk7CiAgICAgICAgICAgIGNvbnN0IHogPSB0aGlzLno7CiAgICAgICAgICAgIHJldHVybiB4ICogeCArIHkgKiB5ICsgeiAqIHo7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENhbGN1bGF0ZXMgdGhlIGxlbmd0aCBvZiB0aGlzIFZlYzMuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyB0aGUgbGVuZ3RoLgogICAgICAgICAqLwogICAgICAgIGxlbmd0aCgpIHsKICAgICAgICAgICAgcmV0dXJuIE1hdGguc3FydCh0aGlzLmxlbmd0aFNxdWFyZWQoKSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENhbGN1bGF0ZXMgdGhlIGRpc3RhbmNlIHRvIGFub3RoZXIgVmVjMy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBvdGhlciAtIFRoZSBvdGhlciBWZWMzIHRvIGNhbGN1bGF0ZSB0aGUgZGlzdGFuY2UgdG8uCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgdGhlIGRpc3RhbmNlIGJldHdlZW4gdmVjdG9ycy4KICAgICAgICAgKi8KICAgICAgICBkaXN0YW5jZVRvKG90aGVyKSB7CiAgICAgICAgICAgIGNvbnN0IHggPSB0aGlzLnggLSBvdGhlci54OwogICAgICAgICAgICBjb25zdCB5ID0gdGhpcy55IC0gb3RoZXIueTsKICAgICAgICAgICAgY29uc3QgeiA9IHRoaXMueiAtIG90aGVyLno7CiAgICAgICAgICAgIHJldHVybiBNYXRoLnNxcnQoeCAqIHggKyB5ICogeSArIHogKiB6KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogTm9ybWFsaXplcyB0aGUgVmVjMyBhbmQgcmV0dXJucyBpdCBhcyBhIG5ldyBWZWMzLgogICAgICAgICAqIE11bHRpcGxpZXMgY29vcmRpbmF0ZXMgdmFsdWUgYnkgdGhlIGludmVyc2Ugb2YgdGhlIHZlY3RvciBsZW5ndGguCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyB0aGUgVmVjMyBub3JtYWxpemVkLgogICAgICAgICAqLwogICAgICAgIG5vcm1hbGl6ZSgpIHsKICAgICAgICAgICAgbGV0IGxlbiA9IHRoaXMueCAqIHRoaXMueCArIHRoaXMueSAqIHRoaXMueSArIHRoaXMueiAqIHRoaXMuejsKICAgICAgICAgICAgaWYgKGxlbiA8IE51bWJlci5FUFNJTE9OKSB7CiAgICAgICAgICAgICAgICByZXR1cm4gbmV3IFZlYzMoKTsKICAgICAgICAgICAgfQogICAgICAgICAgICAvLyBUT0RPOiBldmFsdWF0ZSB1c2Ugb2YgZ2xtX2ludnNxcnQgaGVyZT8KICAgICAgICAgICAgbGVuID0gMS4wIC8gTWF0aC5zcXJ0KGxlbik7CiAgICAgICAgICAgIHJldHVybiBuZXcgVmVjMyh0aGlzLnggKiBsZW4sIHRoaXMueSAqIGxlbiwgdGhpcy56ICogbGVuKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogTm9ybWFsaXplcyB0aGlzIFZlYzMgbXVsdGlwbHlpbmcgY29vcmRpbmF0ZSB2YWx1ZXMgYnkgdGhlIGludmVyc2Ugb2YgdGhlIHZlY3RvciBsZW5ndGguCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBub3JtYWxpemVJblBsYWNlKCkgewogICAgICAgICAgICBsZXQgbGVuID0gdGhpcy54ICogdGhpcy54ICsgdGhpcy55ICogdGhpcy55ICsgdGhpcy56ICogdGhpcy56OwogICAgICAgICAgICBpZiAobGVuIDwgTnVtYmVyLkVQU0lMT04pIHsKICAgICAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgICAgfQogICAgICAgICAgICBsZW4gPSBNYXRoLnNxcnQobGVuKTsKICAgICAgICAgICAgY29uc3QgdG1wID0gMS4wIC8gbGVuOwogICAgICAgICAgICB0aGlzLnggKj0gdG1wOwogICAgICAgICAgICB0aGlzLnkgKj0gdG1wOwogICAgICAgICAgICB0aGlzLnogKj0gdG1wOwogICAgICAgICAgICByZXR1cm4gbGVuOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGVzIGFuZCByZXR1cm5zIGEgbmV3IFZlYzMgd2l0aCB0aGUgbmV3IGNvb3JkaW5hdGVzKGNhbGN1bGF0ZWQgd2l0aCB0aGlzIFZlYzMgY29vcmRpbmF0ZXMgYW5kIHRoZSBzcGVjaWZpZWQgbGVuZ3RoKS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBsZW5ndGggLSBUaGUgbGVuZ3RoIHZhbHVlLgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHJlc2l6ZShsZW5ndGgpIHsKICAgICAgICAgICAgY29uc3QgY3VyckxlbiA9IHRoaXMueCAqIHRoaXMueCArIHRoaXMueSAqIHRoaXMueSArIHRoaXMueiAqIHRoaXMuejsKICAgICAgICAgICAgaWYgKGN1cnJMZW4gPCBOdW1iZXIuRVBTSUxPTikgewogICAgICAgICAgICAgICAgcmV0dXJuOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGNvbnN0IHNjbCA9IGxlbmd0aCAvIE1hdGguc3FydChjdXJyTGVuKTsKICAgICAgICAgICAgcmV0dXJuIG5ldyBWZWMzKHRoaXMueCAqIHNjbCwgdGhpcy55ICogc2NsLCB0aGlzLnogKiBzY2wpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBNb2RpZmllcyBjdXJyZW50IGNvb3JkaW5hdGVzIHVzaW5nIHRoZSBzcGVjaWZpZWQgbGVuZ3RoLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGxlbmd0aCAtIFRoZSBsZW5ndGggdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgcmVzaXplSW5QbGFjZShsZW5ndGgpIHsKICAgICAgICAgICAgY29uc3QgY3VyckxlbiA9IHRoaXMueCAqIHRoaXMueCArIHRoaXMueSAqIHRoaXMueSArIHRoaXMueiAqIHRoaXMuejsKICAgICAgICAgICAgaWYgKGN1cnJMZW4gPCBOdW1iZXIuRVBTSUxPTikgewogICAgICAgICAgICAgICAgcmV0dXJuOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGNvbnN0IHNjbCA9IGxlbmd0aCAvIE1hdGguc3FydChjdXJyTGVuKTsKICAgICAgICAgICAgdGhpcy54ICo9IHNjbDsKICAgICAgICAgICAgdGhpcy55ICo9IHNjbDsKICAgICAgICAgICAgdGhpcy56ICo9IHNjbDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ2FsY3VsYXRlcyB0aGUgZG90IHByb2R1Y3Qgb2YgdGhpcyBWZWMzIGFnYWluc3QgYW5vdGhlciBWZWMzLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIG90aGVyIC0gVGhlIG90aGVyIFZlYzMgdG8gY29tcGFyZSB3aXRoLgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIHRoZSBkb3QgcHJvZHVjdC4KICAgICAgICAgKi8KICAgICAgICBkb3Qob3RoZXIpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMueCAqIG90aGVyLnggKyB0aGlzLnkgKiBvdGhlci55ICsgdGhpcy56ICogb3RoZXIuejsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ2FsY3VsYXRlcyB0aGUgY3Jvc3MgcHJvZHVjdCBvZiB0d28gVmVjM3MgYW5kIHJldHVybnMgdGhlIHJlc3VsdCBhcyBhIG5ldyBWZWMzLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIG90aGVyIC0gVGhlIG90aGVyIFZlYzMgdG8gY2FsY3VsYXRlIHdpdGguCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgdGhlIGNyb3NzIHByb2R1Y3QgYXMgYSBuZXcgVmVjMy4KICAgICAgICAgKi8KICAgICAgICBjcm9zcyhvdGhlcikgewogICAgICAgICAgICBjb25zdCBheCA9IHRoaXMueDsKICAgICAgICAgICAgY29uc3QgYXkgPSB0aGlzLnk7CiAgICAgICAgICAgIGNvbnN0IGF6ID0gdGhpcy56OwogICAgICAgICAgICBjb25zdCBieCA9IG90aGVyLng7CiAgICAgICAgICAgIGNvbnN0IGJ5ID0gb3RoZXIueTsKICAgICAgICAgICAgY29uc3QgYnogPSBvdGhlci56OwogICAgICAgICAgICByZXR1cm4gbmV3IFZlYzMoYXkgKiBieiAtIGF6ICogYnksIGF6ICogYnggLSBheCAqIGJ6LCBheCAqIGJ5IC0gYXkgKiBieCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEdldHMgdGhlIGFuZ2xlIGJldHdlZW4gdGhpcyBWZWMzIGFuZCBiLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIG90aGVyIC0gVGhlIG90aGVyIFZlYzMgdG8gY29tcGFyZSB3aXRoLgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIHRoZSBhbmdsZSBpbiByYWRpYW5zLgogICAgICAgICAqLwogICAgICAgIGFuZ2xlVG8ob3RoZXIpIHsKICAgICAgICAgICAgY29uc3QgY29zaW5lID0gdGhpcy5kb3Qob3RoZXIpOwogICAgICAgICAgICBpZiAoY29zaW5lID4gMS4wKSB7CiAgICAgICAgICAgICAgICByZXR1cm4gMDsKICAgICAgICAgICAgfQogICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgIHJldHVybiBNYXRoLmFjb3MoY29zaW5lKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBQZXJmb3JtcyBhIGxpbmVhciBpbnRlcnBvbGF0aW9uIGJldHdlZW4gdGhpcyBWZWMzIGFuZCBvdGhlci4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBvdGhlciAtIFRoZSBvdGhlciBWZWMzIHRvIGludGVycG9sYXRlIHRvd2FyZHMuCiAgICAgICAgICogQHBhcmFtIHQgLSBJbnRlcnBvbGF0aW9uIHJhdGlvLgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGEgbmV3IFZlYzMuCiAgICAgICAgICovCiAgICAgICAgbGVycChvdGhlciwgdCkgewogICAgICAgICAgICBjb25zdCBheCA9IHRoaXMueDsKICAgICAgICAgICAgY29uc3QgYXkgPSB0aGlzLnk7CiAgICAgICAgICAgIGNvbnN0IGF6ID0gdGhpcy56OwogICAgICAgICAgICByZXR1cm4gbmV3IFZlYzMoYXggKyB0ICogKG90aGVyLnggLSBheCksIGF5ICsgdCAqIChvdGhlci55IC0gYXkpLCBheiArIHQgKiAob3RoZXIueiAtIGF6KSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgYSBuZXcgVmVjMyB3aG9zZSBjb21wb25lbnQgdmFsdWVzIGFyZSB0aGUgYWJzIG9mIHRoaXMgVmVjM3MgY29tcG9uZW50IHZhbHVlcy4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGEgbmV3IFZlYzMuCiAgICAgICAgICovCiAgICAgICAgYWJzKCkgewogICAgICAgICAgICByZXR1cm4gbmV3IFZlYzMoTWF0aC5hYnModGhpcy54KSwgTWF0aC5hYnModGhpcy55KSwgTWF0aC5hYnModGhpcy56KSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFNldHMgdGhlIHZlY3RvciBhIHJhbmRvbSB2ZWN0b3Igb24gdGhlIHN1cmZhY2Ugb2YgYSBzcGhlcmUgd2l0aCB0aGUgcmFkaXVzIG9mIHRoZSBnaXZlbiBzY2FsZSB2YWx1ZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBzY2FsZSAtIFRoZSByYWRpdXMgb2YgdGhlIHN1cmZhY2Ugc3BoZXJlLgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmFuZG9tIFZlYzMuCiAgICAgICAgICovCiAgICAgICAgc2V0UmFuZG9tRGlyKHNjYWxlID0gMS4wKSB7CiAgICAgICAgICAgIGNvbnN0IHIgPSBNYXRoLnJhbmRvbSgpICogMi4wICogTWF0aC5QSTsKICAgICAgICAgICAgY29uc3QgeiA9IE1hdGgucmFuZG9tKCkgKiAyLjAgLSAxLjA7CiAgICAgICAgICAgIGNvbnN0IHpTY2FsZSA9IE1hdGguc3FydCgxLjAgLSB6ICogeikgKiBzY2FsZTsKICAgICAgICAgICAgdGhpcy54ID0gTWF0aC5jb3MocikgKiB6U2NhbGU7CiAgICAgICAgICAgIHRoaXMueSA9IE1hdGguc2luKHIpICogelNjYWxlOwogICAgICAgICAgICB0aGlzLnogPSB6ICogc2NhbGU7CiAgICAgICAgICAgIHJldHVybiB0aGlzOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBHZW5lcmF0ZXMgYSByYW5kb20gdmVjdG9yIGFueXdoZXJlIGluIHRoZSBzcGhlcmUgZGVmaW5lZCBieSB0aGUgcHJvdmlkZWQgc2NhbGUgdmFsdWUuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gc2NhbGUgLSBUaGUgcmFkaXVzIG9mIHRoZSBib3VuZGluZyBzcGhlcmUuCiAgICAgICAgICogQHJldHVybiAtIFRoZSByYW5kb20gVmVjMy4KICAgICAgICAgKi8KICAgICAgICBzZXRSYW5kb20oc2NhbGUgPSAxLjApIHsKICAgICAgICAgICAgdGhpcy54ID0gKE1hdGgucmFuZG9tKCkgLSAwLjUpICogc2NhbGU7CiAgICAgICAgICAgIHRoaXMueSA9IChNYXRoLnJhbmRvbSgpIC0gMC41KSAqIHNjYWxlOwogICAgICAgICAgICB0aGlzLnogPSAoTWF0aC5yYW5kb20oKSAtIDAuNSkgKiBzY2FsZTsKICAgICAgICAgICAgcmV0dXJuIHRoaXM7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENsb25lcyB0aGlzIFZlYzMgYW5kIHJldHVybnMgYSBuZXcgVmVjMy4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGEgbmV3IFZlYzMuCiAgICAgICAgICovCiAgICAgICAgY2xvbmUoKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgVmVjMyh0aGlzLngsIHRoaXMueSwgdGhpcy56KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyB0aGUgdHlwZSBhcyBhbiBhcnJheS4gT2Z0ZW4gdXNlZCB0byBwYXNzIHR5cGVzIHRvIHRoZSBHUFUuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyBhcyBhbiBhcnJheS4KICAgICAgICAgKi8KICAgICAgICBhc0FycmF5KCkgewogICAgICAgICAgICByZXR1cm4gW3RoaXMueCwgdGhpcy55LCB0aGlzLnpdOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTZXR0ZXIgZnJvbSBhbiBhcnJheS4KICAgICAgICAgKi8KICAgICAgICBmcm9tQXJyYXkodmFscykgewogICAgICAgICAgICB0aGlzLnggPSB2YWxzWzBdOwogICAgICAgICAgICB0aGlzLnkgPSB2YWxzWzFdOwogICAgICAgICAgICB0aGlzLnogPSB2YWxzWzFdOwogICAgICAgIH0KICAgICAgICAvLyAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KICAgICAgICAvLyBQZXJzaXN0ZW5jZQogICAgICAgIC8qKgogICAgICAgICAqIENvbnZlcnRzIHRoaXMgVmVjMyB0byBhIHN0cmluZyBpbiBKU09OIGZvcm1hdC4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHRvU3RyaW5nKCkgewogICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbmV3LWNhcAogICAgICAgICAgICByZXR1cm4gU3RyaW5nRnVuY3Rpb25zLnN0cmluZ2lmeUpTT05XaXRoRml4ZWRQcmVjaXNpb24odGhpcy50b0pTT04oKSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEVuY29kZXMgVmVjMyBDbGFzcyBhcyBhIEpTT04gb2JqZWN0IGZvciBwZXJzaXN0ZW5jZS4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBUaGUganNvbiBvYmplY3QuCiAgICAgICAgICovCiAgICAgICAgdG9KU09OKCkgewogICAgICAgICAgICByZXR1cm4gewogICAgICAgICAgICAgICAgeDogdGhpcy54LAogICAgICAgICAgICAgICAgeTogdGhpcy55LAogICAgICAgICAgICAgICAgejogdGhpcy56LAogICAgICAgICAgICB9OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBEZWNvZGVzIGEgSlNPTiBvYmplY3QgdG8gc2V0IHRoZSBzdGF0ZSBvZiB0aGlzIGNsYXNzLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGogLSBUaGUganNvbiBvYmplY3QuCiAgICAgICAgICovCiAgICAgICAgZnJvbUpTT04oaikgewogICAgICAgICAgICB0aGlzLnggPSBqLng7CiAgICAgICAgICAgIHRoaXMueSA9IGoueTsKICAgICAgICAgICAgdGhpcy56ID0gai56OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBMb2FkcyB0aGUgc3RhdGUgb2YgdGhlIHZhbHVlIGZyb20gYSBiaW5hcnkgcmVhZGVyLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHJlYWRlciAtIFRoZSByZWFkZXIgdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgcmVhZEJpbmFyeShyZWFkZXIpIHsKICAgICAgICAgICAgdGhpcy54ID0gcmVhZGVyLmxvYWRGbG9hdDMyKCk7CiAgICAgICAgICAgIHRoaXMueSA9IHJlYWRlci5sb2FkRmxvYXQzMigpOwogICAgICAgICAgICB0aGlzLnogPSByZWFkZXIubG9hZEZsb2F0MzIoKTsKICAgICAgICB9CiAgICAgICAgaXNWYWxpZCgpIHsKICAgICAgICAgICAgZm9yIChjb25zdCB2IG9mIHRoaXMuYXNBcnJheSgpKSB7CiAgICAgICAgICAgICAgICBpZiAodiA9PSBJbmZpbml0eSB8fCBpc05hTih2KSkKICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIHRydWU7CiAgICAgICAgfQogICAgfQoKICAgIC8qIGVzbGludC1kaXNhYmxlIG5ldy1jYXAgKi8KICAgIC8qKgogICAgICogUmVwcmVzZW50cyBhIGZvdXItZGltZW5zaW9uYWwgY29vcmRpbmF0ZS4KICAgICAqIE1hdGggdHlwZXMgaW50ZXJuYWxseSBzdG9yZSB2YWx1ZXMgaW4ge0BsaW5rIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0phdmFTY3JpcHQvUmVmZXJlbmNlL0dsb2JhbF9PYmplY3RzL0Zsb2F0MzJBcnJheXxGbG9hdDMyQXJyYXl9IGFuZAogICAgICogZXhwb3NlIGdldHRlcnMgYW5kIHNldHRlcnMgZm9yIHRoZSBjb21wb25lbnQgdmFsdWVzLgogICAgICoKICAgICAqLwogICAgY2xhc3MgVmVjNCB7CiAgICAgICAgeDsKICAgICAgICB5OwogICAgICAgIHo7CiAgICAgICAgdzsKICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGVzIGEgVmVjNC4KICAgICAgICAgKgogICAgICAgICAqLwogICAgICAgIGNvbnN0cnVjdG9yKHggPSAwLCB5ID0gMCwgeiA9IDAsIHcgPSAwKSB7CiAgICAgICAgICAgIHRoaXMueCA9IHg7CiAgICAgICAgICAgIHRoaXMueSA9IHk7CiAgICAgICAgICAgIHRoaXMueiA9IHo7CiAgICAgICAgICAgIHRoaXMudyA9IHc7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEdldHRlciBmb3IgYHh5emAgc3dpenplbC4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIHRoZSB6IHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGdldCB4eXooKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgVmVjMyh0aGlzLngsIHRoaXMueSwgdGhpcy56KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU2V0dGVyIGZyb20gc2NhbGFyIGNvbXBvbmVudHMuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0geCAtIFRoZSB4IHZhbHVlLgogICAgICAgICAqIEBwYXJhbSB5ICAtIFRoZSB5IHZhbHVlLgogICAgICAgICAqIEBwYXJhbSB6ICAtIFRoZSB5IHZhbHVlLgogICAgICAgICAqIEBwYXJhbSB3ICAtIFRoZSB3IHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHNldCh4LCB5LCB6LCB3KSB7CiAgICAgICAgICAgIHRoaXMueCA9IHg7CiAgICAgICAgICAgIHRoaXMueSA9IHk7CiAgICAgICAgICAgIHRoaXMueiA9IHo7CiAgICAgICAgICAgIHRoaXMudyA9IHc7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFNldHMgdGhlIHN0YXRlIG9mIGEgVmVjNCBPYmplY3QgZnJvbSBhbm90aGVyIFZlYzQuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gb3RoZXIgLSBUaGUgb3RoZXIgVmVjNCB0byBzZXQgZnJvbS4KICAgICAgICAgKi8KICAgICAgICBzZXRGcm9tT3RoZXIob3RoZXIpIHsKICAgICAgICAgICAgdGhpcy54ID0gb3RoZXIueDsKICAgICAgICAgICAgdGhpcy55ID0gb3RoZXIueTsKICAgICAgICAgICAgdGhpcy56ID0gb3RoZXIuejsKICAgICAgICAgICAgdGhpcy53ID0gb3RoZXIudzsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ2hlY2tzIGlmIHRoaXMgVmVjNCBjb250YWlucyB0aGUgc2FtZSB2YWx1ZXMgYXMgdGhlIG90aGVyIFZlYzQuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gb3RoZXIgLSBUaGUgb3RoZXIgVmVjNCB0byBjb21wYXJlIHdpdGguCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgdHJ1ZSBvciBmYWxzZS4KICAgICAgICAgKi8KICAgICAgICBpc0VxdWFsKG90aGVyKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLnggPT0gb3RoZXIueCAmJiB0aGlzLnkgPT0gb3RoZXIueSAmJiB0aGlzLnogPT0gb3RoZXIueiAmJiB0aGlzLncgPT0gb3RoZXIudzsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ2hlY2tzIGlmIHRoaXMgVmVjNCBpcyBkaWZmZXJlbnQgZnJvbSBhbm90aGVyIFZlYzQuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gb3RoZXIgLSBUaGUgb3RoZXIgVmVjNCB0byBjb21wYXJlIHdpdGguCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgdHJ1ZSBvciBmYWxzZS4KICAgICAgICAgKi8KICAgICAgICBub3RFcXVhbChvdGhlcikgewogICAgICAgICAgICByZXR1cm4gdGhpcy54ICE9IG90aGVyLnggJiYgdGhpcy55ICE9IG90aGVyLnkgJiYgdGhpcy56ICE9IG90aGVyLnogJiYgdGhpcy53ICE9IG90aGVyLnc7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgdHJ1ZSBpZiB0aGlzIFZlYzQgaXMgYXBwcm94aW1hdGVseSB0aGUgc2FtZSBhcyBvdGhlci4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBvdGhlciAtIFRoZSBvdGhlciBWZWM0IHRvIGNvbXBhcmUgd2l0aC4KICAgICAgICAgKiBAcGFyYW0gcHJlY2lzaW9uIC0gVGhlIHByZWNpc2lvbiB0byB3aGljaCB0aGUgdmFsdWVzIG11c3QgbWF0Y2guCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgYXBwcm94RXF1YWwob3RoZXIsIHByZWNpc2lvbiA9IE51bWJlci5FUFNJTE9OKSB7CiAgICAgICAgICAgIHJldHVybiAoTWF0aC5hYnModGhpcy54IC0gb3RoZXIueCkgPCBwcmVjaXNpb24gJiYKICAgICAgICAgICAgICAgIE1hdGguYWJzKHRoaXMueSAtIG90aGVyLnkpIDwgcHJlY2lzaW9uICYmCiAgICAgICAgICAgICAgICBNYXRoLmFicyh0aGlzLnogLSBvdGhlci56KSA8IHByZWNpc2lvbiAmJgogICAgICAgICAgICAgICAgTWF0aC5hYnModGhpcy53IC0gb3RoZXIudykgPCBwcmVjaXNpb24pOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBBZGRzIG90aGVyIHRvIHRoaXMgVmVjNCBhbmQgcmV0dXJucyB0aGUgcmVzdWx0IGFzIGEgbmV3IFZlYzQuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gb3RoZXIgLSBUaGUgb3RoZXIgVmVjNCB0byBhZGQuCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgYSBuZXcgVmVjNC4KICAgICAgICAgKi8KICAgICAgICBhZGQob3RoZXIpIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBWZWM0KHRoaXMueCArIG90aGVyLngsIHRoaXMueSArIG90aGVyLnksIHRoaXMueiArIG90aGVyLnosIHRoaXMudyArIG90aGVyLncpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBBZGRzIG90aGVyIHRvIHRoaXMgVmVjNCBtdXRhdGluZyB0aGUgdmFsdWVzIG9mIHRoaXMgaW5zdGFuY2UKICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBvdGhlciAtIFRoZSBvdGhlciBWZWM0IHRvIGFkZC4KICAgICAgICAgKi8KICAgICAgICBhZGRJblBsYWNlKG90aGVyKSB7CiAgICAgICAgICAgIHRoaXMueCArPSBvdGhlci54OwogICAgICAgICAgICB0aGlzLnkgKz0gb3RoZXIueTsKICAgICAgICAgICAgdGhpcy56ICs9IG90aGVyLno7CiAgICAgICAgICAgIHRoaXMudyArPSBvdGhlci53OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTdWJ0cmFjdHMgb3RoZXIgZnJvbSB0aGlzIFZlYzQgYW5kIHJldHVybnMgdGhlbiByZXN1bHQgYXMgYSBuZXcgVmVjNC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBvdGhlciAtIFRoZSBvdGhlciBWZWM0IHRvIHN1YnRyYWN0LgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGEgbmV3IFZlYzQuCiAgICAgICAgICovCiAgICAgICAgc3VidHJhY3Qob3RoZXIpIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBWZWM0KHRoaXMueCAtIG90aGVyLngsIHRoaXMueSAtIG90aGVyLnksIHRoaXMueiAtIG90aGVyLnosIHRoaXMudyAtIG90aGVyLncpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTdWJ0cmFjdHMgb3RoZXIgZnJvbSB0aGlzIFZlYzQgbXV0YXRpbmcgdGhlIHZhbHVlcyBvZiB0aGlzIGluc3RhbmNlCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gb3RoZXIgLSBUaGUgb3RoZXIgVmVjNCB0byBzdWJ0cmFjdC4KICAgICAgICAgKi8KICAgICAgICBzdWJ0cmFjdEluUGxhY2Uob3RoZXIpIHsKICAgICAgICAgICAgdGhpcy54IC09IG90aGVyLng7CiAgICAgICAgICAgIHRoaXMueSAtPSBvdGhlci55OwogICAgICAgICAgICB0aGlzLnogLT0gb3RoZXIuejsKICAgICAgICAgICAgdGhpcy53IC09IG90aGVyLnc7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIE11bHRpcGxpZXMgdHdvIFZlYzRzIGFuZCByZXR1cm5zIHRoZSByZXN1bHQgYXMgYSBuZXcgVmVjNC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBvdGhlciAtIFRoZSBvdGhlciBWZWM0IHRvIG11bHRpcGx5IHdpdGguCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgYSBuZXcgVmVjNC4KICAgICAgICAgKi8KICAgICAgICBtdWx0aXBseShvdGhlcikgewogICAgICAgICAgICByZXR1cm4gbmV3IFZlYzQodGhpcy54ICogb3RoZXIueCwgdGhpcy55ICogb3RoZXIueSwgdGhpcy56ICogb3RoZXIueiwgdGhpcy53ICogb3RoZXIudyk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIE11bHRpcGxpZXMgdHdvIFZlYzRzIG11dGF0aW5nIHRoZSB2YWx1ZXMgb2YgdGhpcyBpbnN0YW5jZQogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIG90aGVyIC0gVGhlIG90aGVyIFZlYzQgdG8gbXVsdGlwbHkgd2l0aC4KICAgICAgICAgKi8KICAgICAgICBtdWx0aXBseUluUGxhY2Uob3RoZXIpIHsKICAgICAgICAgICAgdGhpcy54ICo9IG90aGVyLng7CiAgICAgICAgICAgIHRoaXMueSAqPSBvdGhlci55OwogICAgICAgICAgICB0aGlzLnogKj0gb3RoZXIuejsKICAgICAgICAgICAgdGhpcy53ICo9IG90aGVyLnc7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIERpdmlkZXMgdHdvIFZlYzRzIGFuZCByZXR1cm5zIHRoZSByZXN1bHQgYXMgYSBuZXcgVmVjNC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBvdGhlciAtIFRoZSBvdGhlciBWZWM0IHRvIGRpdmlkZSBieS4KICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyBhIG5ldyBWZWM0LgogICAgICAgICAqLwogICAgICAgIGRpdmlkZShvdGhlcikgewogICAgICAgICAgICByZXR1cm4gbmV3IFZlYzQodGhpcy54IC8gb3RoZXIueCwgdGhpcy55IC8gb3RoZXIueSwgdGhpcy56IC8gb3RoZXIueiwgdGhpcy53IC8gb3RoZXIudyk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIERpdmlkZXMgdHdvIFZlYzRzLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIG90aGVyIC0gVGhlIG90aGVyIFZlYzQgdG8gZGl2aWRlIGJ5LgogICAgICAgICAqLwogICAgICAgIGRpdmlkZUluUGxhY2Uob3RoZXIpIHsKICAgICAgICAgICAgdGhpcy54IC89IG90aGVyLng7CiAgICAgICAgICAgIHRoaXMueSAvPSBvdGhlci55OwogICAgICAgICAgICB0aGlzLnogLz0gb3RoZXIuejsKICAgICAgICAgICAgdGhpcy53IC89IG90aGVyLnc7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFNjYWxlcyB0aGlzIFZlYzQgYnkgc2NhbGFyIGFuZCByZXR1cm5zIHRoZSByZXN1bHQgYXMgYSBuZXcgVmVjNC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBzY2FsYXIgLSBUaGUgc2NhbGFyIHZhbHVlLgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHNjYWxlKHNjYWxhcikgewogICAgICAgICAgICByZXR1cm4gbmV3IFZlYzQodGhpcy54ICogc2NhbGFyLCB0aGlzLnkgKiBzY2FsYXIsIHRoaXMueiAqIHNjYWxhciwgdGhpcy53ICogc2NhbGFyKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU2NhbGVzIHRoaXMgVmVjNCBieSBzY2FsYXIuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gc2NhbGFyIC0gVGhlIHNjYWxhciB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBzY2FsZUluUGxhY2Uoc2NhbGFyKSB7CiAgICAgICAgICAgIHRoaXMuc2V0KHRoaXMueCAqIHNjYWxhciwgdGhpcy55ICogc2NhbGFyLCB0aGlzLnogKiBzY2FsYXIsIHRoaXMudyAqIHNjYWxhcik7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENhbGN1bGF0ZXMgdGhlIGxlbmd0aCBvZiB0aGlzIFZlYzQuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyB0aGUgbGVuZ3RoLgogICAgICAgICAqLwogICAgICAgIGxlbmd0aCgpIHsKICAgICAgICAgICAgY29uc3QgeCA9IHRoaXMueDsKICAgICAgICAgICAgY29uc3QgeSA9IHRoaXMueTsKICAgICAgICAgICAgY29uc3QgeiA9IHRoaXMuejsKICAgICAgICAgICAgY29uc3QgdyA9IHRoaXMudzsKICAgICAgICAgICAgcmV0dXJuIE1hdGguc3FydCh4ICogeCArIHkgKiB5ICsgeiAqIHogKyB3ICogdyk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENhbGN1bGF0ZXMgdGhlIHNxdWFyZWQgbGVuZ3RoIG9mIHRoaXMgVmVjNC4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIHRoZSBsZW5ndGguCiAgICAgICAgICovCiAgICAgICAgbGVuZ3RoU3F1YXJlZCgpIHsKICAgICAgICAgICAgY29uc3QgeCA9IHRoaXMueDsKICAgICAgICAgICAgY29uc3QgeSA9IHRoaXMueTsKICAgICAgICAgICAgY29uc3QgeiA9IHRoaXMuejsKICAgICAgICAgICAgY29uc3QgdyA9IHRoaXMudzsKICAgICAgICAgICAgcmV0dXJuIHggKiB4ICsgeSAqIHkgKyB6ICogeiArIHcgKiB3OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBOb3JtYWxpemVzIHRoZSBWZWM0IGFuZCByZXR1cm5zIGl0IGFzIGEgbmV3IFZlYzQuCiAgICAgICAgICogTXVsdGlwbGllcyBjb29yZGluYXRlcyB2YWx1ZSBieSB0aGUgaW52ZXJzZSBvZiB0aGUgdmVjdG9yIGxlbmd0aC4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIHRoZSBWZWM0IG5vcm1hbGl6ZWQuCiAgICAgICAgICovCiAgICAgICAgbm9ybWFsaXplKCkgewogICAgICAgICAgICBjb25zdCB4ID0gdGhpcy54OwogICAgICAgICAgICBjb25zdCB5ID0gdGhpcy55OwogICAgICAgICAgICBjb25zdCB6ID0gdGhpcy56OwogICAgICAgICAgICBjb25zdCB3ID0gdGhpcy53OwogICAgICAgICAgICBsZXQgbGVuID0geCAqIHggKyB5ICogeSArIHogKiB6ICsgdyAqIHc7CiAgICAgICAgICAgIGlmIChsZW4gPCBOdW1iZXIuRVBTSUxPTikgewogICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBWZWM0KCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLy8gVE9ETzogZXZhbHVhdGUgdXNlIG9mIGdsbV9pbnZzcXJ0IGhlcmU/CiAgICAgICAgICAgIGxlbiA9IDEgLyBNYXRoLnNxcnQobGVuKTsKICAgICAgICAgICAgcmV0dXJuIG5ldyBWZWM0KHggKiBsZW4sIHkgKiBsZW4sIHogKiBsZW4pOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBOb3JtYWxpemVzIHRoaXMgVmVjNCBtdWx0aXBseWluZyBjb29yZGluYXRlIHZhbHVlcyBieSB0aGUgaW52ZXJzZSBvZiB0aGUgdmVjdG9yIGxlbmd0aC4KICAgICAgICAgKi8KICAgICAgICBub3JtYWxpemVJblBsYWNlKCkgewogICAgICAgICAgICBjb25zdCB4ID0gdGhpcy54OwogICAgICAgICAgICBjb25zdCB5ID0gdGhpcy55OwogICAgICAgICAgICBjb25zdCB6ID0gdGhpcy56OwogICAgICAgICAgICBjb25zdCB3ID0gdGhpcy53OwogICAgICAgICAgICBsZXQgbGVuID0geCAqIHggKyB5ICogeSArIHogKiB6ICsgdyAqIHc7CiAgICAgICAgICAgIGlmIChsZW4gPCBOdW1iZXIuRVBTSUxPTikgewogICAgICAgICAgICAgICAgcmV0dXJuOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGxlbiA9IDEgLyBNYXRoLnNxcnQobGVuKTsKICAgICAgICAgICAgdGhpcy5zZXQoeCAqIGxlbiwgeSAqIGxlbiwgeiAqIGxlbiwgdyAqIGxlbik7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENhbGN1bGF0ZXMgdGhlIGRvdCBwcm9kdWN0IG9mIHRoaXMgVmVjNCBhZ2FpbnN0IGFub3RoZXIgVmVjNC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBvdGhlciAtIFRoZSBvdGhlciBWZWM0IHRvIGNvbXBhcmUgd2l0aC4KICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyB0aGUgZG90IHByb2R1Y3QuCiAgICAgICAgICovCiAgICAgICAgZG90KG90aGVyKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLnggKiBvdGhlci54ICsgdGhpcy55ICogb3RoZXIueSArIHRoaXMueiAqIG90aGVyLnogKyB0aGlzLncgKiBvdGhlci53OyAvLyBUT0RPOiBvdGhlci53IHVzZWQgdG8gYmUgYi53PwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDYWxjdWxhdGVzIHRoZSBjcm9zcyBwcm9kdWN0IG9mIHR3byBWZWM0cyBhbmQgcmV0dXJucyB0aGUgcmVzdWx0IGFzIGEgbmV3IFZlYzQuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gb3RoZXIgLSBUaGUgb3RoZXIgVmVjNCB0byBjYWxjdWxhdGUgd2l0aC4KICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyB0aGUgY3Jvc3MgcHJvZHVjdCBhcyBhIG5ldyBWZWM0LgogICAgICAgICAqLwogICAgICAgIGNyb3NzKG90aGVyKSB7CiAgICAgICAgICAgIGNvbnN0IGF4ID0gdGhpcy54OwogICAgICAgICAgICBjb25zdCBheSA9IHRoaXMueTsKICAgICAgICAgICAgY29uc3QgYXogPSB0aGlzLno7CiAgICAgICAgICAgIGNvbnN0IGF0ID0gdGhpcy53OwogICAgICAgICAgICBjb25zdCBieCA9IG90aGVyLng7CiAgICAgICAgICAgIGNvbnN0IGJ5ID0gb3RoZXIueTsKICAgICAgICAgICAgY29uc3QgYnogPSBvdGhlci56OwogICAgICAgICAgICBjb25zdCBidCA9IG90aGVyLnc7CiAgICAgICAgICAgIHJldHVybiBuZXcgVmVjNChheSAqIGJ6IC0gYXogKiBieSwgYXogKiBidCAtIGF0ICogYnosIGF0ICogYnggLSBheCAqIGJ0LCBheCAqIGJ5IC0gYXkgKiBieCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEdldHMgdGhlIGFuZ2xlIGJldHdlZW4gdGhpcyBWZWM0IGFuZCBiLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIG90aGVyIC0gVGhlIG90aGVyIFZlYzQgdG8gY29tcGFyZSB3aXRoLgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIHRoZSBhbmdsZSBpbiByYWRpYW5zLgogICAgICAgICAqLwogICAgICAgIGFuZ2xlVG8ob3RoZXIpIHsKICAgICAgICAgICAgY29uc3QgdGVtcEEgPSB0aGlzLm5vcm1hbGl6ZSgpOwogICAgICAgICAgICBjb25zdCB0ZW1wQiA9IG90aGVyLm5vcm1hbGl6ZSgpOwogICAgICAgICAgICBjb25zdCBjb3NpbmUgPSB0ZW1wQS5kb3QodGVtcEIpOwogICAgICAgICAgICBpZiAoY29zaW5lID4gMS4wKSB7CiAgICAgICAgICAgICAgICByZXR1cm4gMDsKICAgICAgICAgICAgfQogICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgIHJldHVybiBNYXRoLmFjb3MoY29zaW5lKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBQZXJmb3JtcyBhIGxpbmVhciBpbnRlcnBvbGF0aW9uIGJldHdlZW4gdGhpcyBWZWM0IGFuZCBvdGhlci4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBvdGhlciAtIFRoZSBvdGhlciBWZWM0IHRvIGludGVycG9sYXRlIGJldHdlZW4uCiAgICAgICAgICogQHBhcmFtIHcgLSBJbnRlcnBvbGF0aW9uIGFtb3VudCBiZXR3ZWVuIHRoZSB0d28gaW5wdXRzLgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGEgbmV3IFZlYzQuCiAgICAgICAgICovCiAgICAgICAgbGVycChvdGhlciwgdCkgewogICAgICAgICAgICBjb25zdCBheCA9IHRoaXMueDsKICAgICAgICAgICAgY29uc3QgYXkgPSB0aGlzLnk7CiAgICAgICAgICAgIGNvbnN0IGF6ID0gdGhpcy56OwogICAgICAgICAgICBjb25zdCBhdCA9IHRoaXMudzsKICAgICAgICAgICAgcmV0dXJuIG5ldyBWZWM0KGF4ICsgdCAqIChvdGhlci54IC0gYXgpLCBheSArIHQgKiAob3RoZXIueSAtIGF5KSwgYXogKyB0ICogKG90aGVyLnogLSBheiksIGF0ICsgdCAqIChvdGhlci53IC0gYXQpKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogR2VuZXJhdGVzIGEgcmFuZG9tIHZlY3RvciB3aXRoIHRoZSBnaXZlbiBzY2FsZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBzY2FsZSAtIExlbmd0aCBvZiB0aGUgcmVzdWx0aW5nIHZlY3Rvci4gSWYgb21pdHRlZCwgYSB1bml0IHZlY3RvciB3aWxsIGJlIHJldHVybmVkLgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIC8vIHJhbmRvbShzY2FsZSA9IDEuMCkgewogICAgICAgIC8vICAgY29uc3QgciA9IGdsTWF0cml4LlJBTkRPTSgpICogMi4wICogTWF0aC5QSQogICAgICAgIC8vICAgY29uc3QgeiA9IGdsTWF0cml4LlJBTkRPTSgpICogMi4wIC0gMS4wCiAgICAgICAgLy8gICBjb25zdCB6U2NhbGUgPSBNYXRoLnNxcnQoMS4wIC0geiAqIHopICogc2NhbGUKICAgICAgICAvLyAgIG91dFswXSA9IE1hdGguY29zKHIpICogelNjYWxlCiAgICAgICAgLy8gICBvdXRbMV0gPSBNYXRoLnNpbihyKSAqIHpTY2FsZQogICAgICAgIC8vICAgb3V0WzJdID0geiAqIHNjYWxlCiAgICAgICAgLy8gICByZXR1cm4gb3V0CiAgICAgICAgLy8gfQogICAgICAgIC8qKgogICAgICAgICAqIENsb25lcyB0aGlzIFZlYzQgYW5kIHJldHVybnMgYSBuZXcgVmVjNC4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGEgbmV3IFZlYzQuCiAgICAgICAgICovCiAgICAgICAgY2xvbmUoKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgVmVjNCh0aGlzLngsIHRoaXMueSwgdGhpcy56LCB0aGlzLncpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb252ZXJ0cyB0aGlzIFZlYzQgaW50byBhIFZlYzMuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyB0aGUgdmFsdWUgYXMgYSBuZXcgVmVjMy4KICAgICAgICAgKi8KICAgICAgICB0b1ZlYzMoKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgVmVjMyh0aGlzLngsIHRoaXMueSwgdGhpcy56KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyB0aGUgdHlwZSBhcyBhbiBhcnJheS4gT2Z0ZW4gdXNlZCB0byBwYXNzIHR5cGVzIHRvIHRoZSBHUFUuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyBhcyBhbiBhcnJheS4KICAgICAgICAgKi8KICAgICAgICBhc0FycmF5KCkgewogICAgICAgICAgICByZXR1cm4gW3RoaXMueCwgdGhpcy55LCB0aGlzLnosIHRoaXMud107CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFNldHRlciBmcm9tIGFuIGFycmF5LgogICAgICAgICAqLwogICAgICAgIGZyb21BcnJheSh2YWxzKSB7CiAgICAgICAgICAgIHRoaXMueCA9IHZhbHNbMF07CiAgICAgICAgICAgIHRoaXMueSA9IHZhbHNbMV07CiAgICAgICAgICAgIHRoaXMueiA9IHZhbHNbMV07CiAgICAgICAgICAgIHRoaXMudyA9IHZhbHNbMV07CiAgICAgICAgfQogICAgICAgIC8vIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwogICAgICAgIC8vIFBlcnNpc3RlbmNlCiAgICAgICAgLyoqCiAgICAgICAgICogQ29udmVydHMgdGhpcyBWZWMzIHRvIGEgc3RyaW5nIGluIEpTT04gZm9ybWF0LgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgdG9TdHJpbmcoKSB7CiAgICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuZXctY2FwCiAgICAgICAgICAgIHJldHVybiBTdHJpbmdGdW5jdGlvbnMuc3RyaW5naWZ5SlNPTldpdGhGaXhlZFByZWNpc2lvbih0aGlzLnRvSlNPTigpKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIHRvSlNPTiBtZXRob2QgZW5jb2RlcyB0aGlzIHR5cGUgYXMgYSBqc29uIG9iamVjdCBmb3IgcGVyc2lzdGVuY2UuCiAgICAgICAgICogQHJldHVybiAtIFRoZSBqc29uIG9iamVjdC4KICAgICAgICAgKi8KICAgICAgICB0b0pTT04oKSB7CiAgICAgICAgICAgIHJldHVybiB7CiAgICAgICAgICAgICAgICB4OiB0aGlzLngsCiAgICAgICAgICAgICAgICB5OiB0aGlzLnksCiAgICAgICAgICAgICAgICB6OiB0aGlzLnosCiAgICAgICAgICAgICAgICB3OiB0aGlzLncsCiAgICAgICAgICAgIH07CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIERlY29kZXMgYSBKU09OIG9iamVjdCB0byBzZXQgdGhlIHN0YXRlIG9mIHRoaXMgY2xhc3MuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gaiAtIFRoZSBqc29uIG9iamVjdC4KICAgICAgICAgKi8KICAgICAgICBmcm9tSlNPTihqKSB7CiAgICAgICAgICAgIHRoaXMueCA9IGoueDsKICAgICAgICAgICAgdGhpcy55ID0gai55OwogICAgICAgICAgICB0aGlzLnogPSBqLno7CiAgICAgICAgICAgIHRoaXMudyA9IGoudzsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogTG9hZHMgdGhlIHN0YXRlIG9mIHRoZSB2YWx1ZSBmcm9tIGEgYmluYXJ5IHJlYWRlci4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSByZWFkZXIgLSBUaGUgcmVhZGVyIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHJlYWRCaW5hcnkocmVhZGVyKSB7CiAgICAgICAgICAgIHRoaXMueCA9IHJlYWRlci5sb2FkRmxvYXQzMigpOwogICAgICAgICAgICB0aGlzLnkgPSByZWFkZXIubG9hZEZsb2F0MzIoKTsKICAgICAgICAgICAgdGhpcy56ID0gcmVhZGVyLmxvYWRGbG9hdDMyKCk7CiAgICAgICAgICAgIHRoaXMudyA9IHJlYWRlci5sb2FkRmxvYXQzMigpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBWZXJpZmllcyBpZiB0aGUgdmFsdWVzIHN0b3JlZCBpbiB0aGlzIE1hdGggdHlwZSBhcmUgdmFsaWQgbnVtZXJpYyB2YWx1ZXMuCiAgICAgICAgICogUmV0dXJucyBgZmFsc2VgIElmIGF0IGxlYXN0IG9uZSBvZiB0aGUgdmFsdWVzIGlzIGVpdGhlciB7QGxpbmsgaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvSmF2YVNjcmlwdC9SZWZlcmVuY2lhL09iamV0b3NfZ2xvYmFsZXMvSW5maW5pdHl8SW5maW5pdHl9IG9yCiAgICAgICAgICoge0BsaW5rIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0phdmFTY3JpcHQvUmVmZXJlbmNpYS9PYmpldG9zX2dsb2JhbGVzL05hTnxOYU59LgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgdGhlIHJlc3VsdCBhcyBhIGJvb2xlYW4uCiAgICAgICAgICovCiAgICAgICAgaXNWYWxpZCgpIHsKICAgICAgICAgICAgZm9yIChjb25zdCB2IG9mIHRoaXMuYXNBcnJheSgpKSB7CiAgICAgICAgICAgICAgICBpZiAodiA9PSBJbmZpbml0eSB8fCBpc05hTih2KSkKICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIHRydWU7CiAgICAgICAgfQogICAgfQoKICAgIGxldCByZWdpc3RlcmVkQ2xhc3NlcyA9IHt9OwogICAgbGV0IGNsYXNzTmFtZXMgPSB7fTsKICAgIGxldCBjbGFzc0RlZmluaXRpb25zID0gW107CiAgICAvKioKICAgICAqIFJlZ2lzdHJ5IGlzIGEgc3RhdGljIGZhY3RvcnkgdGhhdCBoYW5kbGVzIHJlZ2lzdHJhdGlvbi9yZWNvbnN0cnVjdGlvbiBvZgogICAgICogY2xhc3NlcyBiYXNlcyBvbiBCYXNlQ2xhc3MuIFJlZ2lzdGVyZWQgY2xhc3NlcyBjYW4gdGhlbiBiZSBjb25zdHJ1Y3RlZCBieSB0aGUgUmVnaXN0cnkgYnkgbmFtZS4KICAgICAqCiAgICAgKiBOb3RlOiBjbGFzc05hbWUgaXMgcmVxdWlyZWQgYmVjYXVzZSBvbiBtaW5pZmljYXRpb24gcHJvY2VzcwogICAgICogdGhlIG5hbWUgb2YgY2xhc3NlcyBjaGFuZ2UgYW5kIHdlIGNhbid0IHNpbXBseSB1c2UgJy4uLi5jb25zdHJ1Y3Rvci5uYW1lJy4KICAgICAqIFNvLCB3ZSBuZWVkIGEgd2F5IG9mIHJlbGF0aW5nIG1pbmlmaWVkIGNsYXNzIG5hbWVzIHRvIHRoZSBvbmUgc3RvcmVkIGZvciBwZXJzaXN0ZW5jeS4KICAgICAqCiAgICAgKiBpLmUuCiAgICAgKiBgYGBqYXZhc2NyaXB0CiAgICAgKiAvLyBJbXBvcnQgcmVnaXN0cnkgY2xhc3MKICAgICAqIGNsYXNzIEZvbygpIGV4dGVuZHMgQmFzZUNsYXNzIHt9CiAgICAgKgogICAgICogUmVnaXN0cnkucmVnaXN0ZXIoJ0ZvbycsIEZvbykKICAgICAqIC8vIEluIGNhc2UgJ0ZvbycgY2xhc3MgZ2V0cyBpdHMgbmFtZSBjaGFuZ2VkIHRvICdjJyBvbiBtaW5pZmljYXRpb24sCiAgICAgKiAvLyBhbmQgdGhlIHBlcnNpc3RlZCBkYXRhIHR5cGUgaXMgJ0ZvbycsIHdlIHdvdWxkIGtub3cgaG93IHRvIHJlbGF0ZSB0aGVtLgogICAgICogYGBgCiAgICAgKgogICAgICogQHN0YXRpYwogICAgICogQGNsYXNzIFJlZ2lzdHJ5CiAgICAgKi8KICAgIGNsYXNzIFJlZ2lzdHJ5IHsKICAgICAgICAvKioKICAgICAgICAgKiBSZWdpc3RlcnMgYSBuZXcgY2xhc3MgdG8gdGhlIGZhY3RvcnkuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gY2xhc3NOYW1lIC0gTmFtZSBvZiB0aGUgcmVnaXN0ZXJlZCBjbGFzcwogICAgICAgICAqIEBwYXJhbSBjbGFzc0RlZiAtIENsYXNzIHJlcHJlc2VudGF0aW9uKENsYXNzIGZ1bmN0aW9uLCB0eXBlKQogICAgICAgICAqLwogICAgICAgIHN0YXRpYyByZWdpc3RlcihjbGFzc05hbWUsIGNsYXNzRGVmKSB7CiAgICAgICAgICAgIGlmIChjbGFzc05hbWUgaW4gcmVnaXN0ZXJlZENsYXNzZXMpIHsKICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybihgVGhlcmUncyBhIGNsYXNzIHJlZ2lzdGVyZWQgd2l0aCAnJHtjbGFzc05hbWV9JyBuYW1lLiBTZWNvbmQgcmVnaXN0cmF0aW9uIGZhaWxlZC5gKTsKICAgICAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgICAgfQogICAgICAgICAgICAvLyBOb3RlOiBUbyBwcm92aWRlIGJhY2t3YXJkcyBjb21wYXRpYmlsaXR5LCBzYW1lIGNsYXNzRGVmIGNhbiBiZSBzdG9yZWQgdW5kZXIgbXVsdGlwbGUgbmFtZXMuCiAgICAgICAgICAgIC8vIFRoYXRzIHRoZSByZWFzb24gYmVoaW5kIHVzaW5nIGluZGV4ZXMgaW5zdGVhZCBvZiB0aGUgY2xhc3NEZWYuCiAgICAgICAgICAgIGNvbnN0IGluZGV4ID0gY2xhc3NEZWZpbml0aW9ucy5sZW5ndGg7CiAgICAgICAgICAgIGNsYXNzRGVmaW5pdGlvbnMucHVzaChjbGFzc0RlZik7CiAgICAgICAgICAgIGNsYXNzTmFtZXNbaW5kZXhdID0gY2xhc3NOYW1lOwogICAgICAgICAgICByZWdpc3RlcmVkQ2xhc3Nlc1tjbGFzc05hbWVdID0gaW5kZXg7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgY2xhc3MgZGVmaW5pdGlvbiB1c2luZyB0aGUgbmFtZSBpdCB3YXMgcmVnaXN0ZXJlZCB3aXRoLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGNsYXNzTmFtZSAtIE5hbWUgb2YgdGhlIHJlZ2lzdGVyZWQgY2xhc3MKICAgICAgICAgKiBAcmV0dXJuIC0gQ2xhc3MgcmVwcmVzZW50YXRpb24oQ2xhc3MgZnVuY3Rpb24sIHR5cGUpCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGdldENsYXNzRGVmaW5pdGlvbihjbGFzc05hbWUpIHsKICAgICAgICAgICAgaWYgKCEoY2xhc3NOYW1lIGluIHJlZ2lzdGVyZWRDbGFzc2VzKSkKICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgJHtjbGFzc05hbWV9IGNsYXNzIGlzIG5vdCByZWdpc3RlcmVkYCk7CiAgICAgICAgICAgIHJldHVybiBjbGFzc0RlZmluaXRpb25zW3JlZ2lzdGVyZWRDbGFzc2VzW2NsYXNzTmFtZV1dOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIGNsYXNzIG5hbWUgcmVnaXN0ZXJlZCBmb3IgdGhlIGluc3RhbnRpYXRlZCBvYmplY3QuCiAgICAgICAgICogQHBhcmFtIGNsYXNzRGVmaW5pdGlvbiAtIENsYXNzIHR5cGUgZGVmaW5pdGlvbi4KICAgICAgICAgKiBAcmV0dXJuIC0gTmFtZSBvZiB0aGUgcmVnaXN0ZXJlZCBjbGFzcwogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBnZXRDbGFzc05hbWUoY2xhc3NEZWZpbml0aW9uKSB7CiAgICAgICAgICAgIGNvbnN0IGNsYXNzSWQgPSBjbGFzc0RlZmluaXRpb25zLmluZGV4T2YoY2xhc3NEZWZpbml0aW9uKTsKICAgICAgICAgICAgaWYgKGNsYXNzSWQgPj0gMCAmJiBjbGFzc05hbWVzW2NsYXNzSWRdKQogICAgICAgICAgICAgICAgcmV0dXJuIGNsYXNzTmFtZXNbY2xhc3NJZF07CiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgY2xhc3MgaXMgbm90IHJlZ2lzdGVyZWRgKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGZhY3RvcnkgZnVuY3Rpb24gdGhhdCBjb25zdHJ1Y3QgdGhlIGNsYXNzIHJlZ2lzdGVyZWQgdW5kZXIgdGhlIGdpdmVuIG5hbWUuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gY2xhc3NOYW1lIC0gTmFtZSBvZiB0aGUgcmVnaXN0ZXJlZCBjbGFzcwogICAgICAgICAqIEByZXR1cm4gLSBJbnN0YW50aWF0ZWQgb2JqZWN0IG9mIHRoZSBzcGVjaWZpZWQgY2xhc3MKICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgY29uc3RydWN0Q2xhc3MoY2xhc3NOYW1lKSB7CiAgICAgICAgICAgIGNvbnN0IGNsYXNzRGVmaW5pdGlvbiA9IGNsYXNzRGVmaW5pdGlvbnNbcmVnaXN0ZXJlZENsYXNzZXNbY2xhc3NOYW1lXV07CiAgICAgICAgICAgIGlmICghY2xhc3NEZWZpbml0aW9uKQogICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGAke2NsYXNzTmFtZX0gY2xhc3MgaXMgbm90IHJlZ2lzdGVyZWRgKTsKICAgICAgICAgICAgcmV0dXJuIG5ldyBjbGFzc0RlZmluaXRpb24oKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogRm9yIHRlc3RpbmcgcHVycG9zZSBvbmx5LCBuZXZlciBjYWxsIHRoaXMgb3V0c2lkZSBvZiB0aGUgdGVzdCBzY29wZS4KICAgICAgICAgKgogICAgICAgICAqIEBwcml2YXRlCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGZsdXNoKCkgewogICAgICAgICAgICByZWdpc3RlcmVkQ2xhc3NlcyA9IHt9OwogICAgICAgICAgICBjbGFzc05hbWVzID0ge307CiAgICAgICAgICAgIGNsYXNzRGVmaW5pdGlvbnMgPSBbXTsKICAgICAgICB9CiAgICB9CgogICAgLyogZXNsaW50LWRpc2FibGUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWV4cGxpY2l0LWFueSAqLwogICAgbGV0IGNvdW50ZXIgPSAwOwogICAgLyoqCiAgICAgKiBDbGFzcyByZXByZXNlbnRpbmcgYSBCYXNlQ2xhc3MuCiAgICAgKiBUaGUgQmFzZUNsYXNzIGlzIHRoZSBmb3VuZGF0aW9uIGNsYXNzIG9mIHRoZSBTY2VuZVRyZWUsIGFzIGFsbW9zdCBhbGwgY2xhc3NlcyBkZXJpdmUgZnJvbSBpdC4KICAgICAqLwogICAgY2xhc3MgQmFzZUNsYXNzIHsKICAgICAgICBfX2lkOwogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZSBhbiBCYXNlQ2xhc3MuCiAgICAgICAgICovCiAgICAgICAgY29uc3RydWN0b3IoKSB7CiAgICAgICAgICAgIHRoaXMuX19pZCA9ICsrY291bnRlcjsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogRXZlcnkgaW5zdGFuY2Ugb2YgZWFjaCBjbGFzcyBiYXNlZCBvbiBCYXNlQ2xhc3MgaXMgYXNzaWduZWQgYSB1bmlxdWUgbnVtYmVyLgogICAgICAgICAqIFRoaXMgbnVtYmVyIGlzIG5vdCBwZXJzaXN0ZW50IGluIGJldHdlZW4gZGlmZmVyZW50IGxvYWRzIG9mIGEgc2NlbmUuCiAgICAgICAgICogUmV0dXJucyB0aGUgdW5pcXVlIGlkIG9mIHRoZSBvYmplY3QuCiAgICAgICAgICogQHJldHVybiAtIFRoZSBJZCBvZiB0aGUgb2JqZWN0LgogICAgICAgICAqLwogICAgICAgIGdldElkKCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy5fX2lkOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIHRoZSB1bm1hbmdsZWQgbmFtZSBvZiB0aGUgY2xhc3MuCiAgICAgICAgICogQHJldHVybiAtIFRoZSBuYW1lIG9mIHRoZSBjbGFzcyBkZWZpbml0aW9uLgogICAgICAgICAqLwogICAgICAgIGdldENsYXNzTmFtZSgpIHsKICAgICAgICAgICAgcmV0dXJuIFJlZ2lzdHJ5LmdldENsYXNzTmFtZShPYmplY3QuZ2V0UHJvdG90eXBlT2YodGhpcykuY29uc3RydWN0b3IpOwogICAgICAgIH0KICAgIH0KCiAgICAvKiogQ2xhc3MgcmVwcmVzZW50aW5nIGEgQmFzZUV2ZW50LiAqLwogICAgY2xhc3MgQmFzZUV2ZW50IHsKICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGUgYW4gQmFzZUV2ZW50LgogICAgICAgICAqLwogICAgICAgIGNvbnN0cnVjdG9yKCkgeyB9CiAgICB9CgogICAgLyogZXNsaW50LWRpc2FibGUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWV4cGxpY2l0LWFueSAqLwogICAgLyoqCiAgICAgKiBQcm92aWRlcyBhbiBpbnRlcmZhY2UgZm9yIGVtaXR0aW5nIGV2ZW50cyB1bmRlciBnaXZlbiBuYW1lcywgYW5kIHJlZ2lzdGVyaW5nIGxpc3RlbmVycyB0byB0aG9zZSBldmVudHMuCiAgICAgKiBUaGlzIGlzIGEgYmFzZSBjbGFzcyBmb3IgbW9zdCBjbGFzc2VzIGluIHRoZSBTY2VuZSBUcmVlIGFuZCBSZW5kZXJlciwgZW5hYmxpbmcgb2JzZXJ2ZXJzIHRvIGxpc3RlbiB0byBjaGFuZ2VzIHRocm91Z2hvdXQgdGhlIHN5c3RlbS4KICAgICAqIFRoZSBpbnRlcmZhY2UgZXhwb3NlZCBpcyBzaW1pbGFyIHRvIFtFdmVudEVtaXR0ZXJdKGh0dHBzOi8vbm9kZWpzLm9yZy9hcGkvZXZlbnRzLmh0bWwjZXZlbnRzX2NsYXNzX2V2ZW50ZW1pdHRlcikgaW4gTm9kZS4KICAgICAqCiAgICAgKiBTaW1pbGFyIHRvIGhvdyB0aGUgRE9NIGV2ZW50IHN5c3RlbSBpbiB0aGUgYnJvd3NlciB3b3JrcywgZXZlbnRzIGFyZSByZWdpc3RlcmVkIGJ5IG5hbWUuCiAgICAgKiBFeGFtcGxlOiBSZWdpc3RlcmluZyBhIGxpc3RlbmVyIGZvciBhIGN1c3RvbSBldmVudCwgYW5kIHRoZW4gZW1pdHRpbmcgdGhhdCBldmVudC4KICAgICAqIGBgYGphdmFzY3JpcHQKICAgICAqICBjb25zdCBlZSA9IG5ldyBFdmVudEVtaXR0ZXIoKQogICAgICoKICAgICAqICBjb25zdCBldmVudElEID0gZWUub24oJ215RXZlbnQnLCAoZXZlbnQpID0+IHsKICAgICAqICAgIGNvbnNvbGUubG9nKCdNeSBFdmVudCB3YXMgZW1pdHRlZDonLCBldmVudCkKICAgICAqICB9KQogICAgICoKICAgICAqICBlZS5lbWl0KCdteUV2ZW50JywgeyBkYXRhOiA0MiB9KQogICAgICogIC8vIFdlIG5vIGxvbmdlciB3YW50IHRvIGxpc3RlbiB0byB0aGlzIGV2ZW50LCBzbyBsZXQncyByZW1vdmUgdGhlIGxpc3RlbmVyLgogICAgICogIGVlLm9mZignbXlFdmVudCcsIGV2ZW50SUQpCiAgICAgKiBgYGAKICAgICAqCiAgICAgKgogICAgICovCiAgICBjbGFzcyBFdmVudEVtaXR0ZXIgZXh0ZW5kcyBCYXNlQ2xhc3MgewogICAgICAgIGxpc3RlbmVycyA9IHt9OwogICAgICAgIC8qKgogICAgICAgICAqIEluaXRpYWxpemVzIGFuIGVtcHR5IGBsaXN0ZW5lcnNgIG1hcCB0aGF0IHdpbGwgaG9zdCBhbGwgdGhlIGV2ZW50cywKICAgICAgICAgKiB3aGljaCBpbXBsaWVzIHRoYXQgaXQgZG9lc24ndCBhbGxvdyBtdWx0aXBsZSBldmVudHMgd2l0aCB0aGUgc2FtZSBuYW1lLgogICAgICAgICAqCiAgICAgICAgICovCiAgICAgICAgY29uc3RydWN0b3IoKSB7CiAgICAgICAgICAgIHN1cGVyKCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEFkZHMgYSBsaXN0ZW5lciBmdW5jdGlvbiBmb3IgYSBnaXZlbiBldmVudCBuYW1lLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGV2ZW50TmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBldmVudC4KICAgICAgICAgKiBAcGFyYW0gbGlzdGVuZXIgLSBUaGUgbGlzdGVuZXIgZnVuY3Rpb24oY2FsbGJhY2spLgogICAgICAgICAqIEByZXR1cm4gLSB0aGUgaWQgdGhhdCBjYW4gYmUgdXNlZCB0byByZW1vdmUgdGhlIGxpc3RlbmVyLgogICAgICAgICAqLwogICAgICAgIG9uKGV2ZW50TmFtZSwgbGlzdGVuZXIpIHsKICAgICAgICAgICAgaWYgKCFsaXN0ZW5lcikgewogICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdNaXNzaW5nIGxpc3RlbmVyLicpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmICghdGhpcy5saXN0ZW5lcnNbZXZlbnROYW1lXSkgewogICAgICAgICAgICAgICAgdGhpcy5saXN0ZW5lcnNbZXZlbnROYW1lXSA9IFtdOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGNvbnN0IGxpc3RlbmVycyA9IHRoaXMubGlzdGVuZXJzW2V2ZW50TmFtZV07CiAgICAgICAgICAgIGlmIChsaXN0ZW5lcnMuaW5jbHVkZXMobGlzdGVuZXIpKSB7CiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYExpc3RlbmVyICIke2xpc3RlbmVyLm5hbWV9IiBhbHJlYWR5IGNvbm5lY3RlZCB0byBldmVudCAiJHtldmVudE5hbWV9Ii5gKTsKICAgICAgICAgICAgfQogICAgICAgICAgICAvLyBUT0RPOiBEZXByZWNhdGUgYWxvbmdzaWRlICNhZGRMaXN0ZW5lci4KICAgICAgICAgICAgY29uc3QgaWQgPSBsaXN0ZW5lcnMubGVuZ3RoOwogICAgICAgICAgICBsaXN0ZW5lcnNbaWRdID0gbGlzdGVuZXI7CiAgICAgICAgICAgIHJldHVybiBpZDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU2ltaWxhciB0byB0aGUgYG9uYCBtZXRob2Qgd2l0aCB0aGUgZGlmZmVyZW5jZSB0aGF0IHdoZW4gdGhlIGV2ZW50IGlzIHRyaWdnZXJlZCwKICAgICAgICAgKiBpdCBpcyBhdXRvbWF0aWNhbGx5IHVucmVnaXN0ZXJlZCBtZWFuaW5nIHRoYXQgdGhlIGV2ZW50IGxpc3RlbmVyIHdpbGwgYmUgdHJpZ2dlcmVkIGF0IG1vc3Qgb25lIHRpbWUuCiAgICAgICAgICoKICAgICAgICAgKiBVc2VmdWwgZm9yIGV2ZW50cyB0aGF0IHdlIGV4cGVjdCB0byB0cmlnZ2VyIG9uZSB0aW1lLCBzdWNoIGFzIHdoZW4gYXNzZXRzIGxvYWQuCiAgICAgICAgICogYGBgamF2YXNjcmlwdAogICAgICAgICAqIGNvbnN0IGFzc2V0ID0gbmV3IEFzc2V0KCk7CiAgICAgICAgICogYXNzZXQub25jZSgnbG9hZGVkJywgKCkgPT4gewogICAgICAgICAqICAgY29uc29sZS5sb2coIllheSEgdGhlIGFzc2V0IGlzIGxvYWRlZCIpCiAgICAgICAgICogfSkKICAgICAgICAgKiBgYGAKICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBldmVudE5hbWUgLSBUaGUgZXZlbnROYW1lIHZhbHVlCiAgICAgICAgICogQHBhcmFtIGxpc3RlbmVyIC0gVGhlIGxpc3RlbmVyIHZhbHVlCiAgICAgICAgICogQHJldHVybiAtIHRoZSBpZCB0aGF0IGNhbiBiZSB1c2VkIHRvIHJlbW92ZSB0aGUgbGlzdGVuZXIuCiAgICAgICAgICovCiAgICAgICAgb25jZShldmVudE5hbWUsIGxpc3RlbmVyKSB7CiAgICAgICAgICAgIGNvbnN0IGNiID0gKGV2ZW50KSA9PiB7CiAgICAgICAgICAgICAgICB0aGlzLm9mZihldmVudE5hbWUsIGNiKTsKICAgICAgICAgICAgICAgIGxpc3RlbmVyKGV2ZW50KTsKICAgICAgICAgICAgfTsKICAgICAgICAgICAgcmV0dXJuIHRoaXMub24oZXZlbnROYW1lLCBjYik7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJlbW92ZXMgYSBsaXN0ZW5lciBmcm9tIHRoZSBzcGVjaWZpZWQgZXZlbnQsIHVzaW5nIGVpdGhlciB0aGUgZnVuY3Rpb24gb3IgdGhlIGluZGV4IGlkLiBEZXBlbmRzIG9uIHdoYXQgaXMgcGFzc2VkIGluLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGV2ZW50TmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBldmVudC4KICAgICAgICAgKiBAcGFyYW0gbGlzdGVuZXJPcklkIC0gVGhlIGxpc3RlbmVyIGZ1bmN0aW9uIG9yIHRoZSBpZCBudW1iZXIgcmV0dXJuZWQgYnkgJ29uJy4KICAgICAgICAgKi8KICAgICAgICBvZmYoZXZlbnROYW1lLCBsaXN0ZW5lck9ySWQpIHsKICAgICAgICAgICAgaWYgKGxpc3RlbmVyT3JJZCA9PSB1bmRlZmluZWQpIHsKICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTWlzc2luZyBjYWxsYmFjayBmdW5jdGlvbiAobGlzdGVuZXIpLicpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGNvbnN0IGxpc3RlbmVycyA9IHRoaXMubGlzdGVuZXJzW2V2ZW50TmFtZV0gfHwgW107CiAgICAgICAgICAgIGlmICh0eXBlb2YgbGlzdGVuZXJPcklkID09ICdudW1iZXInKSB7CiAgICAgICAgICAgICAgICBjb25zdCBpZCA9IGxpc3RlbmVyT3JJZDsKICAgICAgICAgICAgICAgIC8vIE5vdGU6IGRvIG5vdCBzcGxpY2UgdGhlIGFycmF5IGFzIHRoYXQgd291bGQgY2hhbmdlIHRoZSBpbmRleGVzIG9mIGV4aXN0aW5nIGxpc3RlbmVycy4KICAgICAgICAgICAgICAgIGxpc3RlbmVyc1tpZF0gPSBudWxsOwogICAgICAgICAgICAgICAgcmV0dXJuOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGNvbnN0IGxpc3RlbmVyID0gbGlzdGVuZXJPcklkOwogICAgICAgICAgICBsaXN0ZW5lcnMuZm9yRWFjaCgoZSwgaSkgPT4gewogICAgICAgICAgICAgICAgaWYgKGUgPT09IGxpc3RlbmVyKSB7CiAgICAgICAgICAgICAgICAgICAgLy8gTm90ZTogZG8gbm90IHNwbGljZSB0aGUgYXJyYXkgYXMgdGhhdCB3b3VsZCBjaGFuZ2UgdGhlIGluZGV4ZXMgb2YgZXhpc3RpbmcgbGlzdGVuZXJzLgogICAgICAgICAgICAgICAgICAgIGxpc3RlbmVyc1tpXSA9IG51bGw7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0pOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiByZW1vdmUgbGlzdGVuZXIgYnkgSUQgcmV0dXJuZWQgZnJvbSAjb24KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBldmVudE5hbWUgLSBUaGUgbmFtZSBvZiB0aGUgZXZlbnQuCiAgICAgICAgICogQHBhcmFtIGlkIC0gVGhlIGlkIHJldHVybmVkIGJ5IGFkZExpc3RlbmVyCiAgICAgICAgICovCiAgICAgICAgcmVtb3ZlTGlzdGVuZXJCeUlkKGV2ZW50TmFtZSwgaWQpIHsKICAgICAgICAgICAgdGhpcy5vZmYoZXZlbnROYW1lLCBpZCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRyaWdnZXJzIGFsbCBsaXN0ZW5lciBmdW5jdGlvbnMgaW4gYW4gZXZlbnQuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gZXZlbnROYW1lIC0gVGhlIG5hbWUgb2YgdGhlIGV2ZW50LgogICAgICAgICAqIEBwYXJhbSBldmVudCAtIFRoZSBkYXRhIHlvdSB3YW50IHRvIHBhc3MgZG93biB0byBhbGwgbGlzdGVuZXIgZnVuY3Rpb25zIGFzIHBhcmFtZXRlci4KICAgICAgICAgKgogICAgICAgICAqLwogICAgICAgIGVtaXQoZXZlbnROYW1lLCBldmVudCA9IG5ldyBCYXNlRXZlbnQoKSkgewogICAgICAgICAgICBjb25zdCBsaXN0ZW5lcnMgPSB0aGlzLmxpc3RlbmVyc1tldmVudE5hbWVdIHx8IFtdOwogICAgICAgICAgICBsaXN0ZW5lcnMuZm9yRWFjaCgoZm4pID0+IHsKICAgICAgICAgICAgICAgIC8vIFNraXAgZGlzY29ubmVjdGVkIGxpc3RlbmVycy4KICAgICAgICAgICAgICAgIGlmIChmbikgewogICAgICAgICAgICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGZuKGV2ZW50KTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgY2F0Y2ggKGUpIHsKICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS53YXJuKGUpOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSk7CiAgICAgICAgfQogICAgfQoKICAgIC8qIGVzbGludC1kaXNhYmxlIEB0eXBlc2NyaXB0LWVzbGludC9uby1leHBsaWNpdC1hbnkgKi8KICAgIC8qKgogICAgICogTWF0aCBGdW5jdGlvbnMKICAgICAqLwogICAgY2xhc3MgTWF0aEZ1bmN0aW9ucyB7CiAgICAgICAgLyoqCiAgICAgICAgICogQ29udmVydHMgUmFkaWFucyB0byBEZWdyZWVzCiAgICAgICAgICoKICAgICAgICAgKiBAc3RhdGljCiAgICAgICAgICogQHBhcmFtIHJhZCAtIFJhZGlhbnMgdmFsdWUKICAgICAgICAgKiBAcmV0dXJuIC0gRGVncmVlcyBlcXVpdmFsZW50CiAgICAgICAgICovCiAgICAgICAgc3RhdGljIHJhZFRvRGVnKHJhZCkgewogICAgICAgICAgICByZXR1cm4gcmFkIC8gKE1hdGguUEkgLyAxODApOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb252ZXJ0cyBEZWdyZWVzIHRvIFJhZGlhbnRzCiAgICAgICAgICoKICAgICAgICAgKiBAc3RhdGljCiAgICAgICAgICogQHBhcmFtIGRlZyAtIERlZ3JlZXMgdmFsdWUKICAgICAgICAgKiBAcmV0dXJuIC0gIFJhZGlhbnMgZXF1aXZhbGVudAogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBkZWdUb1JhZChkZWcpIHsKICAgICAgICAgICAgcmV0dXJuIGRlZyAqIChNYXRoLlBJIC8gMTgwKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVmVyaWZpZXMgaWYgdGhlIHNwZWNpZmllZCBwYXJhbWV0ZXIgaXMgbnVtZXJpYy4KICAgICAgICAgKgogICAgICAgICAqIEBzdGF0aWMKICAgICAgICAgKiBAcGFyYW0gbnVtYmVyIC0gTnVtYmVyIHRvIHRlc3QKICAgICAgICAgKiBAcmV0dXJuIC0gYHRydWVgIHdoZW4gaXMgYSB2YWxpZCBudW1iZXIKICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgaXNOdW1lcmljKG51bWJlcikgewogICAgICAgICAgICByZXR1cm4gIWlzTmFOKHBhcnNlRmxvYXQobnVtYmVyKSkgJiYgaXNGaW5pdGUobnVtYmVyKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogR2VuZXJhdGVzIGFuZCByZXR1cm5zIGEgcmFuZG9tIGludGVnZXIgd2l0aGluIHRoZSBzcGVjaWZpZWQgcmFuZ2UuCiAgICAgICAgICoKICAgICAgICAgKiBAc3RhdGljCiAgICAgICAgICogQHBhcmFtIG1pbiAtIExvd2VyIHZhbHVlIHJhbmRvbSBpbnQgY2FuIGJlLgogICAgICAgICAqIEBwYXJhbSBtYXggLSBIaWdoZXN0IHZhbHVlIHJhbmRvbSBpbnQgY2FuIGJlLgogICAgICAgICAqIEByZXR1cm4gLSBSYW5kb20gbnVtYmVyIGluc2lkZSByYW5nZS4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgcmFuZG9tSW50KG1pbiwgbWF4KSB7CiAgICAgICAgICAgIG1pbiA9IE1hdGguY2VpbChtaW4pOwogICAgICAgICAgICBtYXggPSBNYXRoLmZsb29yKG1heCk7CiAgICAgICAgICAgIHJldHVybiBNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiAobWF4IC0gbWluKSkgKyBtaW47CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENhbGN1bGF0ZXMgYSBsaW5lYWwgaW50ZXJwb2xhdGlvbiBiZXR3ZWVuIHR3byBpbnB1dHMgZm9yIHRoZSBzcGVjaWZpZWQgcGFyYW1ldGVyKHQpLgogICAgICAgICAqCiAgICAgICAgICogQHN0YXRpYwogICAgICAgICAqIEBwYXJhbSB2MCAtCiAgICAgICAgICogQHBhcmFtIHYxIC0KICAgICAgICAgKiBAcGFyYW0gdCAtCiAgICAgICAgICogQHJldHVybiAtCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGxlcnAodjAsIHYxLCB0KSB7CiAgICAgICAgICAgIHJldHVybiB2MCArIHQgKiAodjEgLSB2MCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJlc3RyaWN0cyB0aGUgc3BlY2lmaWVkIHZhbHVlIGJldHdlZW4gdHdvIG51bWJlcnMKICAgICAgICAgKgogICAgICAgICAqIEBzdGF0aWMKICAgICAgICAgKiBAcGFyYW0gdmFsdWUKICAgICAgICAgKiBAcGFyYW0gbWluCiAgICAgICAgICogQHBhcmFtIG1heAogICAgICAgICAqIEByZXR1cm4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgY2xhbXAodmFsdWUsIG1pbiwgbWF4KSB7CiAgICAgICAgICAgIHJldHVybiBNYXRoLm1pbihNYXRoLm1heCh2YWx1ZSwgbWluKSwgbWF4KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyB0aGUgbmVhcmVzdCBwb3cgb2YgdHdvIHZhbHVlIG9mIHRoZSBzcGVjaWZpZWQgbnVtYmVyLgogICAgICAgICAqCiAgICAgICAgICogQHN0YXRpYwogICAgICAgICAqIEBwYXJhbSB2YWx1ZSAtCiAgICAgICAgICogQHJldHVybiAtCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIG5lYXJlc3RQb3cyKHZhbHVlKSB7CiAgICAgICAgICAgIHJldHVybiBNYXRoLnBvdygyLCBNYXRoLnJvdW5kKE1hdGgubG9nKHZhbHVlKSAvIE1hdGgubG9nKDIpKSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgdGhlIG5lYXJlc3QgcG93IG9mIHRlbiB2YWx1ZSBvZiB0aGUgc3BlY2lmaWVkIG51bWJlci4KICAgICAgICAgKgogICAgICAgICAqIEBzdGF0aWMKICAgICAgICAgKiBAcGFyYW0gdmFsdWUgLQogICAgICAgICAqIEByZXR1cm4gLQogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBuZWFyZXN0UG93MTAodmFsdWUpIHsKICAgICAgICAgICAgcmV0dXJuIE1hdGgucG93KDEwLCBNYXRoLnJvdW5kKE1hdGgubG9nMTAodmFsdWUpIC8gTWF0aC5sb2cxMCgxMCkpKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyB0aGUgbmV4dCBwb3cgb2YgdHdvIHZhbHVlIG9mIHRoZSBzcGVjaWZpZWQgbnVtYmVyLgogICAgICAgICAqCiAgICAgICAgICogQHN0YXRpYwogICAgICAgICAqIEBwYXJhbSB2YWx1ZSAtCiAgICAgICAgICogQHJldHVybiAtCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIG5leHRQb3cyKHZhbHVlKSB7CiAgICAgICAgICAgIGlmICh0aGlzLmZyYWN0KE1hdGgubG9nMih2YWx1ZSkpID09IDApIHsKICAgICAgICAgICAgICAgIHJldHVybiB2YWx1ZTsKICAgICAgICAgICAgfQogICAgICAgICAgICBsZXQgZXhwID0gMDsKICAgICAgICAgICAgd2hpbGUgKHZhbHVlID4gMCkgewogICAgICAgICAgICAgICAgZXhwKys7CiAgICAgICAgICAgICAgICB2YWx1ZSA9IHZhbHVlID4+IDE7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIDEgPDwgZXhwOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIHRoZSBmcmFjdGlvbmFsIGNvbXBvbmVudCBvZiBhIG51bWJlcgogICAgICAgICAqCiAgICAgICAgICogQHN0YXRpYwogICAgICAgICAqIEBwYXJhbSB2YWx1ZSAtCiAgICAgICAgICogQHJldHVybiAtCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGZyYWN0KHZhbHVlKSB7CiAgICAgICAgICAgIGlmICh2YWx1ZSA9PSAwKQogICAgICAgICAgICAgICAgcmV0dXJuIDA7CiAgICAgICAgICAgIGlmICh2YWx1ZSA8IDApIHsKICAgICAgICAgICAgICAgIGlmICh2YWx1ZSA+IC0xLjApCiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIC12YWx1ZTsKICAgICAgICAgICAgICAgIHJldHVybiAtdmFsdWUgJSBNYXRoLmZsb29yKC12YWx1ZSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKHZhbHVlIDwgMS4wKQogICAgICAgICAgICAgICAgcmV0dXJuIHZhbHVlOwogICAgICAgICAgICByZXR1cm4gdmFsdWUgJSBNYXRoLmZsb29yKHZhbHVlKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogTW92ZXMgdGhlIHNwZWNpZmllZCB2YWx1ZSBmcm9tIG9uZSBudW1lcmljIGRvbWFpbihyYW5nZSkgdG8gYW5vdGhlci4KICAgICAgICAgKgogICAgICAgICAqIEBzdGF0aWMKICAgICAgICAgKiBAcGFyYW0gdmFsdWUgLQogICAgICAgICAqIEBwYXJhbSBzdGFydDEgLQogICAgICAgICAqIEBwYXJhbSBlbmQxIC0KICAgICAgICAgKiBAcGFyYW0gc3RhcnQyIC0KICAgICAgICAgKiBAcGFyYW0gZW5kMiAtCiAgICAgICAgICogQHJldHVybiAtCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIHJlbWFwKHZhbHVlLCBzdGFydDEsIGVuZDEsIHN0YXJ0MiwgZW5kMikgewogICAgICAgICAgICByZXR1cm4gc3RhcnQyICsgKGVuZDIgLSBzdGFydDIpICogKCh2YWx1ZSAtIHN0YXJ0MSkgLyAoZW5kMSAtIHN0YXJ0MSkpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBQZXJmb3JtIEhlcm1pdGUgaW50ZXJwb2xhdGlvbiBiZXR3ZWVuIHR3byB2YWx1ZXMKICAgICAgICAgKgogICAgICAgICAqIEBzdGF0aWMKICAgICAgICAgKiBAcGFyYW0gZWRnZTAgLQogICAgICAgICAqIEBwYXJhbSBlZGdlMSAtCiAgICAgICAgICogQHBhcmFtIHggLQogICAgICAgICAqIEByZXR1cm4gLQogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBzbW9vdGhTdGVwKGVkZ2UwLCBlZGdlMSwgeCkgewogICAgICAgICAgICBjb25zdCB0ID0gdGhpcy5jbGFtcCgoeCAtIGVkZ2UwKSAvIChlZGdlMSAtIGVkZ2UwKSwgMC4wLCAxLjApOwogICAgICAgICAgICByZXR1cm4gdCAqIHQgKiAoMy4wIC0gMi4wICogdCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFBlcmZvcm1zIC0gaW50ZXJwb2xhdGlvbiBiZXR3ZWVuIHR3byB2YWx1ZXMKICAgICAgICAgKgogICAgICAgICAqIEBzdGF0aWMKICAgICAgICAgKiBAcGFyYW0gZWRnZTAgLQogICAgICAgICAqIEBwYXJhbSBlZGdlMSAtCiAgICAgICAgICogQHBhcmFtIHggLQogICAgICAgICAqIEByZXR1cm4gLQogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBsaW5TdGVwKGVkZ2UwLCBlZGdlMSwgeCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy5jbGFtcCgoeCAtIGVkZ2UwKSAvIChlZGdlMSAtIGVkZ2UwKSwgMC4wLCAxLjApOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBEZWNvZGVzIGEgRmxvYXQxNiBmcm9tIHR3byB1bnNpZ25lZCBJbnQ4CiAgICAgICAgICoKICAgICAgICAgKiBAc3RhdGljCiAgICAgICAgICogQHBhcmFtIGMgLSBBcnJheSB3aXRoIHRoZSB0d28gVUludDgKICAgICAgICAgKiBAcmV0dXJuIC0gRGVjb2RlZCBGbG9hdDE2CiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGRlY29kZTE2Qml0RmxvYXRGcm9tMnhVSW50OChjKSB7CiAgICAgICAgICAgIGNvbnN0IGl4ID0gY1swXTsgLy8gMXN0IGJ5dGU6IDEgYml0IHNpZ25lZCBudW0sIDQgYml0cyBleHBvbmVudCwgMyBiaXRzIG1hbnRpc3NhIChNU0IpCiAgICAgICAgICAgIGNvbnN0IGl5ID0gY1sxXTsgLy8gMm5kIGJ5dGU6IDggYml0IG1hbnRpc3NhIChMU0IpCiAgICAgICAgICAgIGNvbnN0IHMgPSBpeCAmIDB4ODAgPyAxIDogLTE7IC8vIGdldCBiaXQgOAogICAgICAgICAgICBjb25zdCBpZXhwID0gKGl4ICYgMHg3OCkgPj4gMzsgLy8gbWFzayBiaXRzIDctNAogICAgICAgICAgICBjb25zdCBtc2IgPSBpeCAmIDB4NzsgLy8gbWFzayBiaXRzIDMtMQogICAgICAgICAgICBsZXQgbm9ybSA9IGlleHAgPT0gMCA/IDAgOiAyMDQ4OyAvLyBkaXN0aW5ndWlzaCBiZXR3ZWVuIG5vcm1hbGl6ZWQgYW5kIHN1Yi1ub3JtYWxpemVkIG51bWJlcnMKICAgICAgICAgICAgY29uc3QgbWFudGlzc2EgPSBub3JtICsgKG1zYiA8PCA4KSArIGl5OyAvLyBpbXBsaWNpdCBwcmVjZWRpbmcgMSBvciAwIGFkZGVkIGhlcmUKICAgICAgICAgICAgbm9ybSA9IGlleHAgPT0gMCA/IDEgOiAwOyAvLyBub3JtYWxpemF0aW9uIHRvZ2dsZQogICAgICAgICAgICBjb25zdCBleHBvbmVudCA9IE1hdGgucG93KDIsIGlleHAgKyBub3JtIC0gMTYpOyAvLyAtNSBmb3IgdGhlIHRoZSBleHBvbmVudCBiaWFzIGZyb20gMl4tNSB0byAyXjEwIHBsdXMgYW5vdGhlciAtMTEgZm9yIHRoZSBub3JtYWxpemVkIDEyIGJpdCBtYW50aXNzYQogICAgICAgICAgICBjb25zdCB2ID0gcyAqIG1hbnRpc3NhICogZXhwb25lbnQ7CiAgICAgICAgICAgIHJldHVybiB2OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBFbmNvZGVzIGFuIGFycmF5IG9mIHR3byB1bnNpZ25lZCBJbnQ4IHRvIGEgRmxvYXQxNgogICAgICAgICAqCiAgICAgICAgICogQHN0YXRpYwogICAgICAgICAqIEBwYXJhbSB2IC0gRmxvYXQxNiBudW1iZXIKICAgICAgICAgKiBAcmV0dXJuIC0gRW5jb2RlZCBVbnNpZ25lZCBJbnQ4IGFycmF5CiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGVuY29kZTE2Qml0RmxvYXRJbnRvMnhVSW50OCh2KSB7CiAgICAgICAgICAgIGNvbnN0IGMgPSBuZXcgVWludDhBcnJheSgyKTsKICAgICAgICAgICAgLy8gY29uc3QgYyA9IFswLCAwXTsKICAgICAgICAgICAgY29uc3Qgc2lnbnVtID0gdiA+PSAwID8gMTI4IDogMDsKICAgICAgICAgICAgdiA9IE1hdGguYWJzKHYpOwogICAgICAgICAgICBsZXQgZXhwb25lbnQgPSAxNTsKICAgICAgICAgICAgbGV0IGxpbWl0ID0gMTAyNDsgLy8gY29uc2lkZXJpbmcgdGhlIGJpYXMgZnJvbSAyXi01IHRvIDJeMTAgKD09MTAyNCkKICAgICAgICAgICAgZm9yIChsZXQgZXhwID0gMTU7IGV4cCA+IDA7IGV4cC0tKSB7CiAgICAgICAgICAgICAgICBpZiAodiA8IGxpbWl0KSB7CiAgICAgICAgICAgICAgICAgICAgbGltaXQgLz0gMjsKICAgICAgICAgICAgICAgICAgICBleHBvbmVudC0tOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIGxldCByZXN0OwogICAgICAgICAgICBpZiAoZXhwb25lbnQgPT0gMCkgewogICAgICAgICAgICAgICAgcmVzdCA9IHYgLyBsaW1pdCAvIDI7IC8vICJzdWItbm9ybWFsaXplIiBpbXBsaWNpdCBwcmVjZWRpbmcgMC4KICAgICAgICAgICAgfQogICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgIHJlc3QgPSAodiAtIGxpbWl0KSAvIGxpbWl0OyAvLyBub3JtYWxpemUgYWNjb3JkaW5nbHkgdG8gaW1wbGljaXQgcHJlY2VkaW5nIDEuCiAgICAgICAgICAgIH0KICAgICAgICAgICAgY29uc3QgbWFudGlzc2EgPSBNYXRoLnJvdW5kKHJlc3QgKiAyMDQ4KTsgLy8gMjA0OCA9IDJeMTEgZm9yIHRoZSAoc3BsaXQpIDExIGJpdCBtYW50aXNzYQogICAgICAgICAgICBjb25zdCBtc2IgPSBtYW50aXNzYSAvIDI1NjsgLy8gdGhlIG1vc3Qgc2lnbmlmaWNhbnQgMyBiaXRzIGdvIGludG8gdGhlIGxvd2VyIHBhcnQgb2YgdGhlIGZpcnN0IGJ5dGUKICAgICAgICAgICAgY29uc3QgbHNiID0gbWFudGlzc2EgLSBtc2IgKiAyNTY7IC8vIHRoZXJlIGdvIHRoZSBvdGhlciA4IGJpdCBvZiB0aGUgbG93ZXIgc2lnbmlmaWNhbmNlCiAgICAgICAgICAgIGNbMF0gPSBzaWdudW0gKyBleHBvbmVudCAqIDggKyBtc2I7IC8vIGNvbG9yIG5vcm1hbGl6YXRpb24gZm9yIHRleHR1cmUyRAogICAgICAgICAgICBjWzFdID0gbHNiOwogICAgICAgICAgICBpZiAodiA+PSAyMDQ4KSB7CiAgICAgICAgICAgICAgICBjWzBdID0gMjU1OwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBjOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUcmFuc2Zvcm1zIGEgMTYgYml0IGZsb2F0IHRvIGFuIGVuY29kZWQgaW50ZWdlci4KICAgICAgICAgKgogICAgICAgICAqIEBzdGF0aWMKICAgICAgICAgKiBAcGFyYW0gdiAtIEZsb2F0MTYgbnVtYmVyIHRvIGVuY29kZQogICAgICAgICAqIEByZXR1cm4gLSBFbmNvZGVkIG51bWJlcgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBlbmNvZGUxNkJpdEZsb2F0KHYpIHsKICAgICAgICAgICAgY29uc3QgZmxvYXQzMkFycmF5ID0gbmV3IEZsb2F0MzJBcnJheSgxKTsKICAgICAgICAgICAgZmxvYXQzMkFycmF5WzBdID0gdjsKICAgICAgICAgICAgY29uc3QgaW50MzJWaWV3ID0gbmV3IEludDMyQXJyYXkoZmxvYXQzMkFycmF5LmJ1ZmZlcik7CiAgICAgICAgICAgIGNvbnN0IHRvVUludDE2ID0gKHgpID0+IHsKICAgICAgICAgICAgICAgIGxldCBiaXRzID0gKHggPj4gMTYpICYgMHg4MDAwOyAvKiBHZXQgdGhlIHNpZ24gKi8KICAgICAgICAgICAgICAgIGxldCBtID0gKHggPj4gMTIpICYgMHgwN2ZmOyAvKiBLZWVwIG9uZSBleHRyYSBiaXQgZm9yIHJvdW5kaW5nICovCiAgICAgICAgICAgICAgICBjb25zdCBlID0gKHggPj4gMjMpICYgMHhmZjsgLyogVXNpbmcgaW50IGlzIGZhc3RlciBoZXJlICovCiAgICAgICAgICAgICAgICAvKiBJZiB6ZXJvLCBvciBkZS1ub3JtYWwsIG9yIGV4cG9uZW50IHVuZGVyZmxvd3MgdG9vIG11Y2ggZm9yIGEgZGUtbm9ybWFsCiAgICAgICAgICAgICAgICAgKiBoYWxmLCByZXR1cm4gc2lnbmVkIHplcm8uICovCiAgICAgICAgICAgICAgICBpZiAoZSA8IDEwMykgewogICAgICAgICAgICAgICAgICAgIHJldHVybiBiaXRzOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgLyogSWYgTmFOLCByZXR1cm4gTmFOLiBJZiBJbmYgb3IgZXhwb25lbnQgb3ZlcmZsb3csIHJldHVybiBJbmYuICovCiAgICAgICAgICAgICAgICBpZiAoZSA+IDE0MikgewogICAgICAgICAgICAgICAgICAgIGJpdHMgfD0gMHg3YzAwOwogICAgICAgICAgICAgICAgICAgIC8qIElmIGV4cG9uZW50IHdhcyAweGZmIGFuZCBvbmUgbWFudGlzc2EgYml0IHdhcyBzZXQsIGl0IG1lYW5zIE5hTiwKICAgICAgICAgICAgICAgICAgICAgKiBub3QgSW5mLCBzbyBtYWtlIHN1cmUgd2Ugc2V0IG9uZSBtYW50aXNzYSBiaXQgdG9vLiAqLwogICAgICAgICAgICAgICAgICAgIGJpdHMgfD0gKGUgPT0gMjU1ID8gMCA6IDEpICYmIHggJiAweDAwN2ZmZmZmOwogICAgICAgICAgICAgICAgICAgIHJldHVybiBiaXRzOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgLyogSWYgZXhwb25lbnQgdW5kZXJmbG93cyBidXQgbm90IHRvbyBtdWNoLCByZXR1cm4gYSBkZS1ub3JtYWwgKi8KICAgICAgICAgICAgICAgIGlmIChlIDwgMTEzKSB7CiAgICAgICAgICAgICAgICAgICAgbSB8PSAweDA4MDA7CiAgICAgICAgICAgICAgICAgICAgLyogRXh0cmEgcm91bmRpbmcgbWF5IG92ZXJmbG93IGFuZCBzZXQgbWFudGlzc2EgdG8gMCBhbmQgZXhwb25lbnQKICAgICAgICAgICAgICAgICAgICAgKiB0byAxLCB3aGljaCBpcyBPSy4gKi8KICAgICAgICAgICAgICAgICAgICBiaXRzIHw9IChtID4+ICgxMTQgLSBlKSkgKyAoKG0gPj4gKDExMyAtIGUpKSAmIDEpOwogICAgICAgICAgICAgICAgICAgIHJldHVybiBiaXRzOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgYml0cyB8PSAoKGUgLSAxMTIpIDw8IDEwKSB8IChtID4+IDEpOwogICAgICAgICAgICAgICAgLyogRXh0cmEgcm91bmRpbmcuIEFuIG92ZXJmbG93IHdpbGwgc2V0IG1hbnRpc3NhIHRvIDAgYW5kIGluY3JlbWVudAogICAgICAgICAgICAgICAgICogdGhlIGV4cG9uZW50LCB3aGljaCBpcyBPSy4gKi8KICAgICAgICAgICAgICAgIGJpdHMgKz0gbSAmIDE7CiAgICAgICAgICAgICAgICByZXR1cm4gYml0czsKICAgICAgICAgICAgfTsKICAgICAgICAgICAgcmV0dXJuIHRvVUludDE2KGludDMyVmlld1swXSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEFzIG9wcG9zaXRlIG9mIHRoZSBgZW5jb2RlMTZCaXRGbG9hdGAgbWV0aG9kLCB0aGlzIHRha2VzIGFuIGVuY29kZWQgaW50ZWdlciB2YWx1ZSwKICAgICAgICAgKiBhbmQgcmV0dXJucyB0aGUgMTYgYml0IGZsb2F0LgogICAgICAgICAqCiAgICAgICAgICogQHN0YXRpYwogICAgICAgICAqIEBwYXJhbSBoIC0gRW5jb2RlZCBpbnRlZ2VyCiAgICAgICAgICogQHJldHVybiAtIERlY29kZWQgMTYgYml0IGZsb2F0LgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBkZWNvZGUxNkJpdEZsb2F0KGgpIHsKICAgICAgICAgICAgY29uc3QgcyA9IChoICYgMHg4MDAwKSA+PiAxNTsKICAgICAgICAgICAgY29uc3QgZSA9IChoICYgMHg3YzAwKSA+PiAxMDsKICAgICAgICAgICAgY29uc3QgZiA9IGggJiAweDAzZmY7CiAgICAgICAgICAgIGlmIChlID09IDApIHsKICAgICAgICAgICAgICAgIHJldHVybiAocyA/IC0xIDogMSkgKiBNYXRoLnBvdygyLCAtMTQpICogKGYgLyBNYXRoLnBvdygyLCAxMCkpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGVsc2UgaWYgKGUgPT0gMHgxZikgewogICAgICAgICAgICAgICAgcmV0dXJuIGYgPyBOYU4gOiAocyA/IC0xIDogMSkgKiBJbmZpbml0eTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gKHMgPyAtMSA6IDEpICogTWF0aC5wb3coMiwgZSAtIDE1KSAqICgxICsgZiAvIE1hdGgucG93KDIsIDEwKSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRyYW5zZm9ybXMgYW4gYXJyYXkgb2YgRmxvYXQgMzIgdG8gYW4gYXJyYXkgb2YgdW5zaWduZWQgSW50MTYuCiAgICAgICAgICoKICAgICAgICAgKiBAc3RhdGljCiAgICAgICAgICogQHBhcmFtIGZsb2F0MzJBcnJheSAtCiAgICAgICAgICogQHJldHVybiAtIFVuc2lnbmVkIEludDE2IGFycmF5IHJlcHJlc2VudGF0aXZlIG9mIHRoZSBGbG9hdDMyQXJyYXkKICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgY29udmVydEZsb2F0MzJBcnJheVRvVUludDE2QXJyYXkoZmxvYXQzMkFycmF5KSB7CiAgICAgICAgICAgIGNvbnN0IHVuaXQxNnMgPSBuZXcgVWludDE2QXJyYXkoZmxvYXQzMkFycmF5Lmxlbmd0aCk7CiAgICAgICAgICAgIGNvbnN0IGludDMyVmlldyA9IG5ldyBJbnQzMkFycmF5KGZsb2F0MzJBcnJheS5idWZmZXIpOwogICAgICAgICAgICBjb25zdCB0b1VJbnQxNiA9ICh4KSA9PiB7CiAgICAgICAgICAgICAgICBsZXQgYml0cyA9ICh4ID4+IDE2KSAmIDB4ODAwMDsgLyogR2V0IHRoZSBzaWduICovCiAgICAgICAgICAgICAgICBsZXQgbSA9ICh4ID4+IDEyKSAmIDB4MDdmZjsgLyogS2VlcCBvbmUgZXh0cmEgYml0IGZvciByb3VuZGluZyAqLwogICAgICAgICAgICAgICAgY29uc3QgZSA9ICh4ID4+IDIzKSAmIDB4ZmY7IC8qIFVzaW5nIGludCBpcyBmYXN0ZXIgaGVyZSAqLwogICAgICAgICAgICAgICAgLyogSWYgemVybywgb3IgZGUtbm9ybWFsLCBvciBleHBvbmVudCB1bmRlcmZsb3dzIHRvbyBtdWNoIGZvciBhIGRlLW5vcm1hbAogICAgICAgICAgICAgICAgICogaGFsZiwgcmV0dXJuIHNpZ25lZCB6ZXJvLiAqLwogICAgICAgICAgICAgICAgaWYgKGUgPCAxMDMpIHsKICAgICAgICAgICAgICAgICAgICByZXR1cm4gYml0czsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIC8qIElmIE5hTiwgcmV0dXJuIE5hTi4gSWYgSW5mIG9yIGV4cG9uZW50IG92ZXJmbG93LCByZXR1cm4gSW5mLiAqLwogICAgICAgICAgICAgICAgaWYgKGUgPiAxNDIpIHsKICAgICAgICAgICAgICAgICAgICBiaXRzIHw9IDB4N2MwMDsKICAgICAgICAgICAgICAgICAgICAvKiBJZiBleHBvbmVudCB3YXMgMHhmZiBhbmQgb25lIG1hbnRpc3NhIGJpdCB3YXMgc2V0LCBpdCBtZWFucyBOYU4sCiAgICAgICAgICAgICAgICAgICAgICogbm90IEluZiwgc28gbWFrZSBzdXJlIHdlIHNldCBvbmUgbWFudGlzc2EgYml0IHRvby4gKi8KICAgICAgICAgICAgICAgICAgICBiaXRzIHw9IChlID09IDI1NSA/IDAgOiAxKSAmJiB4ICYgMHgwMDdmZmZmZjsKICAgICAgICAgICAgICAgICAgICByZXR1cm4gYml0czsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIC8qIElmIGV4cG9uZW50IHVuZGVyZmxvd3MgYnV0IG5vdCB0b28gbXVjaCwgcmV0dXJuIGEgZGUtbm9ybWFsICovCiAgICAgICAgICAgICAgICBpZiAoZSA8IDExMykgewogICAgICAgICAgICAgICAgICAgIG0gfD0gMHgwODAwOwogICAgICAgICAgICAgICAgICAgIC8qIEV4dHJhIHJvdW5kaW5nIG1heSBvdmVyZmxvdyBhbmQgc2V0IG1hbnRpc3NhIHRvIDAgYW5kIGV4cG9uZW50CiAgICAgICAgICAgICAgICAgICAgICogdG8gMSwgd2hpY2ggaXMgT0suICovCiAgICAgICAgICAgICAgICAgICAgYml0cyB8PSAobSA+PiAoMTE0IC0gZSkpICsgKChtID4+ICgxMTMgLSBlKSkgJiAxKTsKICAgICAgICAgICAgICAgICAgICByZXR1cm4gYml0czsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGJpdHMgfD0gKChlIC0gMTEyKSA8PCAxMCkgfCAobSA+PiAxKTsKICAgICAgICAgICAgICAgIC8qIEV4dHJhIHJvdW5kaW5nLiBBbiBvdmVyZmxvdyB3aWxsIHNldCBtYW50aXNzYSB0byAwIGFuZCBpbmNyZW1lbnQKICAgICAgICAgICAgICAgICAqIHRoZSBleHBvbmVudCwgd2hpY2ggaXMgT0suICovCiAgICAgICAgICAgICAgICBiaXRzICs9IG0gJiAxOwogICAgICAgICAgICAgICAgcmV0dXJuIGJpdHM7CiAgICAgICAgICAgIH07CiAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgZmxvYXQzMkFycmF5Lmxlbmd0aDsgaSsrKSB7CiAgICAgICAgICAgICAgICB1bml0MTZzW2ldID0gdG9VSW50MTYoaW50MzJWaWV3W2ldKTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gdW5pdDE2czsKICAgICAgICB9CiAgICB9CgogICAgY2xhc3MgQ2hpbGRBZGRlZEV2ZW50IGV4dGVuZHMgQmFzZUV2ZW50IHsKICAgICAgICBpbmRleDsKICAgICAgICBjaGlsZEl0ZW07CiAgICAgICAgY29uc3RydWN0b3IoaW5kZXgsIGNoaWxkSXRlbSkgewogICAgICAgICAgICBzdXBlcigpOwogICAgICAgICAgICB0aGlzLmluZGV4ID0gaW5kZXg7CiAgICAgICAgICAgIHRoaXMuY2hpbGRJdGVtID0gY2hpbGRJdGVtOwogICAgICAgIH0KICAgIH0KCiAgICBjbGFzcyBOYW1lQ2hhbmdlZEV2ZW50IGV4dGVuZHMgQmFzZUV2ZW50IHsKICAgICAgICBvbGROYW1lOwogICAgICAgIG5ld05hbWU7CiAgICAgICAgY29uc3RydWN0b3Iob2xkTmFtZSwgbmV3TmFtZSkgewogICAgICAgICAgICBzdXBlcigpOwogICAgICAgICAgICB0aGlzLm9sZE5hbWUgPSBvbGROYW1lOwogICAgICAgICAgICB0aGlzLm5ld05hbWUgPSBuZXdOYW1lOwogICAgICAgIH0KICAgIH0KCiAgICBjbGFzcyBPcGFjaXR5U3RhdGVDaGFuZ2VkRXZlbnQgZXh0ZW5kcyBCYXNlRXZlbnQgewogICAgICAgIGlzT3BhcXVlOwogICAgICAgIGlzT3BhcXVlU3RhdGVDaGFuZ2VkOwogICAgICAgIGNvbnN0cnVjdG9yKGlzT3BhcXVlLCBpc09wYXF1ZVN0YXRlQ2hhbmdlZCkgewogICAgICAgICAgICBzdXBlcigpOwogICAgICAgICAgICB0aGlzLmlzT3BhcXVlID0gaXNPcGFxdWU7CiAgICAgICAgICAgIHRoaXMuaXNPcGFxdWVTdGF0ZUNoYW5nZWQgPSBpc09wYXF1ZVN0YXRlQ2hhbmdlZDsKICAgICAgICB9CiAgICB9CgogICAgY2xhc3MgUGFyYW1ldGVyQWRkZWRFdmVudCBleHRlbmRzIEJhc2VFdmVudCB7CiAgICAgICAgbmFtZTsKICAgICAgICBjb25zdHJ1Y3RvcihuYW1lKSB7CiAgICAgICAgICAgIHN1cGVyKCk7CiAgICAgICAgICAgIHRoaXMubmFtZSA9IG5hbWU7CiAgICAgICAgfQogICAgfQoKICAgIGNsYXNzIFBhcmFtZXRlclJlbW92ZWRFdmVudCBleHRlbmRzIEJhc2VFdmVudCB7CiAgICAgICAgbmFtZTsKICAgICAgICBjb25zdHJ1Y3RvcihuYW1lKSB7CiAgICAgICAgICAgIHN1cGVyKCk7CiAgICAgICAgICAgIHRoaXMubmFtZSA9IG5hbWU7CiAgICAgICAgfQogICAgfQoKICAgIGNsYXNzIFNlbGVjdGVkRXZlbnQgZXh0ZW5kcyBCYXNlRXZlbnQgewogICAgICAgIHNlbGVjdGVkOwogICAgICAgIGNvbnN0cnVjdG9yKHNlbGVjdGVkKSB7CiAgICAgICAgICAgIHN1cGVyKCk7CiAgICAgICAgICAgIHRoaXMuc2VsZWN0ZWQgPSBzZWxlY3RlZDsKICAgICAgICB9CiAgICB9CgogICAgY2xhc3MgU3RhdGVDaGFuZ2VkRXZlbnQgZXh0ZW5kcyBCYXNlRXZlbnQgewogICAgICAgIHN0YXRlOwogICAgICAgIGNvbnN0cnVjdG9yKHN0YXRlKSB7CiAgICAgICAgICAgIHN1cGVyKCk7CiAgICAgICAgICAgIHRoaXMuc3RhdGUgPSBzdGF0ZTsKICAgICAgICB9CiAgICB9CgogICAgLyoqCiAgICAgKiBDbGFzcyByZXByZXNlbnRpbmcgYSBjb2xvciBhcyA0IGZsb2F0aW5nIHBvaW50IHZhbHVlcy4KICAgICAqLwogICAgY2xhc3MgQ29sb3IgewogICAgICAgIHIgPSAwOwogICAgICAgIGcgPSAwOwogICAgICAgIGIgPSAwOwogICAgICAgIGEgPSAyNTU7CiAgICAgICAgLyoqCiAgICAgICAgICogQ3JlYXRlcyBhIGBDb2xvcmAgb2JqZWN0IHdpdGggYW4gUkdCQSBzdHJ1Y3R1cmUuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gciAtIFRoZSByZWQgY2hhbm5lbCBvZiBhIGNvbG9yLgogICAgICAgICAqIEBwYXJhbSBnIC0gVGhlIGdyZWVuIGNoYW5uZWwgb2YgYSBjb2xvci4KICAgICAgICAgKiBAcGFyYW0gYiAtIFRoZSBibHVlIGNoYW5uZWwgb2YgYSBjb2xvci4KICAgICAgICAgKiBAcGFyYW0gYSAtIFRoZSBhbHBoYSAodHJhbnNwYXJlbmN5KSBjaGFubmVsIG9mIGEgY29sb3IuCiAgICAgICAgICovCiAgICAgICAgY29uc3RydWN0b3IociA9IDAsIGcgPSAwLCBiID0gMCwgYSA9IDEuMCkgewogICAgICAgICAgICBpZiAodHlwZW9mIHIgPT0gJ3N0cmluZycpIHsKICAgICAgICAgICAgICAgIGlmIChyLnN0YXJ0c1dpdGgoJyMnKSkgewogICAgICAgICAgICAgICAgICAgIHRoaXMuc2V0RnJvbUhleChyKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGVsc2UgewogICAgICAgICAgICAgICAgICAgIHRoaXMuc2V0RnJvbUNTU0NvbG9yTmFtZShyKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgIHRoaXMuciA9IHI7CiAgICAgICAgICAgICAgICB0aGlzLmcgPSBnOwogICAgICAgICAgICAgICAgdGhpcy5iID0gYjsKICAgICAgICAgICAgICAgIHRoaXMuYSA9IGE7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU2V0dGVyIGZyb20gc2NhbGFyIGNvbXBvbmVudHMuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gciAtIFRoZSByZWQgY2hhbm5lbC4KICAgICAgICAgKiBAcGFyYW0gZyAgLSBUaGUgZ3JlZW4gY2hhbm5lbC4KICAgICAgICAgKiBAcGFyYW0gYiAgLSBUaGUgYmx1ZSBjaGFubmVsLgogICAgICAgICAqIEBwYXJhbSBhICAtIFRoZSBhbHBoYSBjaGFubmVsLgogICAgICAgICAqLwogICAgICAgIHNldChyLCBnLCBiLCBhID0gMS4wKSB7CiAgICAgICAgICAgIHRoaXMuciA9IHI7CiAgICAgICAgICAgIHRoaXMuZyA9IGc7CiAgICAgICAgICAgIHRoaXMuYiA9IGI7CiAgICAgICAgICAgIHRoaXMuYSA9IGE7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFNldHMgY3VycmVudCBjb2xvciBzdGF0ZSB3aXRoIGFub3RoZXIgYENvbG9yYCBvYmplY3QuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gb3RoZXIgLSBUaGUgb3RoZXIgY29sb3IgdG8gc2V0IGZyb20uCiAgICAgICAgICovCiAgICAgICAgc2V0RnJvbU90aGVyKG90aGVyKSB7CiAgICAgICAgICAgIHRoaXMuciA9IG90aGVyLnI7CiAgICAgICAgICAgIHRoaXMuZyA9IG90aGVyLmc7CiAgICAgICAgICAgIHRoaXMuYiA9IG90aGVyLmI7CiAgICAgICAgICAgIHRoaXMuYSA9IG90aGVyLmE7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEdldHRlciBmcm9tIGFuIFJHQiBhcnJheS4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGdldEFzUkdCQXJyYXkoKSB7CiAgICAgICAgICAgIHJldHVybiBbdGhpcy5yICogMjU1LCB0aGlzLmcgKiAyNTUsIHRoaXMuYiAqIDI1NV07CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEdldHRlciBmcm9tIGFuIFJHQiBkaWN0LgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgZ2V0QXNSR0JEaWN0KCkgewogICAgICAgICAgICByZXR1cm4gewogICAgICAgICAgICAgICAgcjogdGhpcy5yICogMjU1LAogICAgICAgICAgICAgICAgZzogdGhpcy5nICogMjU1LAogICAgICAgICAgICAgICAgYjogdGhpcy5iICogMjU1LAogICAgICAgICAgICB9OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTZXR0ZXIgZnJvbSBhIFJHQiB2YWx1ZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSByIC0gVGhlIHJlZCBjaGFubmVsLgogICAgICAgICAqIEBwYXJhbSBnICAtIFRoZSBncmVlbiBjaGFubmVsLgogICAgICAgICAqIEBwYXJhbSBiICAtIFRoZSBibHVlIGNoYW5uZWwuCiAgICAgICAgICogQHBhcmFtIGEgIC0gVGhlIGFscGhhIGNoYW5uZWwuCiAgICAgICAgICovCiAgICAgICAgc2V0RnJvbVJHQihyLCBnLCBiLCBhKSB7CiAgICAgICAgICAgIHRoaXMuciA9IHIgLyAyNTU7CiAgICAgICAgICAgIHRoaXMuZyA9IGcgLyAyNTU7CiAgICAgICAgICAgIHRoaXMuYiA9IGIgLyAyNTU7CiAgICAgICAgICAgIHRoaXMuYSA9IGEgPyBhIC8gMjU1IDogMS4wOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTZXR0ZXIgZnJvbSBhbiBSR0IgZGljdC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB2YWxzIC0gVGhlIHZhbHMgcGFyYW0uCiAgICAgICAgICovCiAgICAgICAgc2V0RnJvbVJHQkRpY3QodmFscykgewogICAgICAgICAgICB0aGlzLnIgPSB2YWxzLnIgLyAyNTU7CiAgICAgICAgICAgIHRoaXMuZyA9IHZhbHMuZyAvIDI1NTsKICAgICAgICAgICAgdGhpcy5iID0gdmFscy5iIC8gMjU1OwogICAgICAgICAgICB0aGlzLmEgPSB2YWxzLmEgPT0gNCA/IHZhbHMuYSAvIDI1NSA6IDEuMDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU2V0dGVyIGZyb20gYSBoZXhhZGVjaW1hbCB2YWx1ZS4KICAgICAgICAgKiBFLmcuICNmZjAwMDAKICAgICAgICAgKiBAcGFyYW0gaGV4IC0gVGhlIGhleCB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBzZXRGcm9tSGV4KGhleCkgewogICAgICAgICAgICBmdW5jdGlvbiBoZXhUb1JnYihoZXgpIHsKICAgICAgICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IC9eIz8oW2EtZlxkXXsyfSkoW2EtZlxkXXsyfSkoW2EtZlxkXXsyfSkkL2kuZXhlYyhoZXgpOwogICAgICAgICAgICAgICAgcmV0dXJuIHJlc3VsdAogICAgICAgICAgICAgICAgICAgID8gewogICAgICAgICAgICAgICAgICAgICAgICByOiBwYXJzZUludChyZXN1bHRbMV0sIDE2KSwKICAgICAgICAgICAgICAgICAgICAgICAgZzogcGFyc2VJbnQocmVzdWx0WzJdLCAxNiksCiAgICAgICAgICAgICAgICAgICAgICAgIGI6IHBhcnNlSW50KHJlc3VsdFszXSwgMTYpLAogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICA6IG51bGw7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgY29uc3QgcmdiID0gaGV4VG9SZ2IoaGV4KTsKICAgICAgICAgICAgaWYgKCFyZ2IpIHsKICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybignSW52YWxpZCBoZXggY29kZTonICsgaGV4KTsKICAgICAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgICAgfQogICAgICAgICAgICB0aGlzLnNldEZyb21SR0IocmdiLnIsIHJnYi5nLCByZ2IuYik7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFNldHMgdGhlIENvbG9yIHZhbHVlcyBmcm9tIGEgQ1NTIGNvbG9yIG5hbWUuCiAgICAgICAgICogRS5nLiAicmVkIgogICAgICAgICAqIEBwYXJhbSBuYW1lIC0gVGhlIENTUyBjb2xvciBuYW1lLgogICAgICAgICAqLwogICAgICAgIHNldEZyb21DU1NDb2xvck5hbWUobmFtZSkgewogICAgICAgICAgICBjb25zdCBjb2xvdXJOYW1lVG9IZXggPSAoY29sb3VyKSA9PiB7CiAgICAgICAgICAgICAgICBjb25zdCBjb2xvcnMgPSB7CiAgICAgICAgICAgICAgICAgICAgYWxpY2VibHVlOiAnI2YwZjhmZicsCiAgICAgICAgICAgICAgICAgICAgYW50aXF1ZXdoaXRlOiAnI2ZhZWJkNycsCiAgICAgICAgICAgICAgICAgICAgYXF1YTogJyMwMGZmZmYnLAogICAgICAgICAgICAgICAgICAgIGFxdWFtYXJpbmU6ICcjN2ZmZmQ0JywKICAgICAgICAgICAgICAgICAgICBhenVyZTogJyNmMGZmZmYnLAogICAgICAgICAgICAgICAgICAgIGJlaWdlOiAnI2Y1ZjVkYycsCiAgICAgICAgICAgICAgICAgICAgYmlzcXVlOiAnI2ZmZTRjNCcsCiAgICAgICAgICAgICAgICAgICAgYmxhY2s6ICcjMDAwMDAwJywKICAgICAgICAgICAgICAgICAgICBibGFuY2hlZGFsbW9uZDogJyNmZmViY2QnLAogICAgICAgICAgICAgICAgICAgIGJsdWU6ICcjMDAwMGZmJywKICAgICAgICAgICAgICAgICAgICBibHVldmlvbGV0OiAnIzhhMmJlMicsCiAgICAgICAgICAgICAgICAgICAgYnJvd246ICcjYTUyYTJhJywKICAgICAgICAgICAgICAgICAgICBidXJseXdvb2Q6ICcjZGViODg3JywKICAgICAgICAgICAgICAgICAgICBjYWRldGJsdWU6ICcjNWY5ZWEwJywKICAgICAgICAgICAgICAgICAgICBjaGFydHJldXNlOiAnIzdmZmYwMCcsCiAgICAgICAgICAgICAgICAgICAgY2hvY29sYXRlOiAnI2QyNjkxZScsCiAgICAgICAgICAgICAgICAgICAgY29yYWw6ICcjZmY3ZjUwJywKICAgICAgICAgICAgICAgICAgICBjb3JuZmxvd2VyYmx1ZTogJyM2NDk1ZWQnLAogICAgICAgICAgICAgICAgICAgIGNvcm5zaWxrOiAnI2ZmZjhkYycsCiAgICAgICAgICAgICAgICAgICAgY3JpbXNvbjogJyNkYzE0M2MnLAogICAgICAgICAgICAgICAgICAgIGN5YW46ICcjMDBmZmZmJywKICAgICAgICAgICAgICAgICAgICBkYXJrYmx1ZTogJyMwMDAwOGInLAogICAgICAgICAgICAgICAgICAgIGRhcmtjeWFuOiAnIzAwOGI4YicsCiAgICAgICAgICAgICAgICAgICAgZGFya2dvbGRlbnJvZDogJyNiODg2MGInLAogICAgICAgICAgICAgICAgICAgIGRhcmtncmF5OiAnI2E5YTlhOScsCiAgICAgICAgICAgICAgICAgICAgZGFya2dyZWVuOiAnIzAwNjQwMCcsCiAgICAgICAgICAgICAgICAgICAgZGFya2toYWtpOiAnI2JkYjc2YicsCiAgICAgICAgICAgICAgICAgICAgZGFya21hZ2VudGE6ICcjOGIwMDhiJywKICAgICAgICAgICAgICAgICAgICBkYXJrb2xpdmVncmVlbjogJyM1NTZiMmYnLAogICAgICAgICAgICAgICAgICAgIGRhcmtvcmFuZ2U6ICcjZmY4YzAwJywKICAgICAgICAgICAgICAgICAgICBkYXJrb3JjaGlkOiAnIzk5MzJjYycsCiAgICAgICAgICAgICAgICAgICAgZGFya3JlZDogJyM4YjAwMDAnLAogICAgICAgICAgICAgICAgICAgIGRhcmtzYWxtb246ICcjZTk5NjdhJywKICAgICAgICAgICAgICAgICAgICBkYXJrc2VhZ3JlZW46ICcjOGZiYzhmJywKICAgICAgICAgICAgICAgICAgICBkYXJrc2xhdGVibHVlOiAnIzQ4M2Q4YicsCiAgICAgICAgICAgICAgICAgICAgZGFya3NsYXRlZ3JheTogJyMyZjRmNGYnLAogICAgICAgICAgICAgICAgICAgIGRhcmt0dXJxdW9pc2U6ICcjMDBjZWQxJywKICAgICAgICAgICAgICAgICAgICBkYXJrdmlvbGV0OiAnIzk0MDBkMycsCiAgICAgICAgICAgICAgICAgICAgZGVlcHBpbms6ICcjZmYxNDkzJywKICAgICAgICAgICAgICAgICAgICBkZWVwc2t5Ymx1ZTogJyMwMGJmZmYnLAogICAgICAgICAgICAgICAgICAgIGRpbWdyYXk6ICcjNjk2OTY5JywKICAgICAgICAgICAgICAgICAgICBkb2RnZXJibHVlOiAnIzFlOTBmZicsCiAgICAgICAgICAgICAgICAgICAgZmlyZWJyaWNrOiAnI2IyMjIyMicsCiAgICAgICAgICAgICAgICAgICAgZmxvcmFsd2hpdGU6ICcjZmZmYWYwJywKICAgICAgICAgICAgICAgICAgICBmb3Jlc3RncmVlbjogJyMyMjhiMjInLAogICAgICAgICAgICAgICAgICAgIGZ1Y2hzaWE6ICcjZmYwMGZmJywKICAgICAgICAgICAgICAgICAgICBnYWluc2Jvcm86ICcjZGNkY2RjJywKICAgICAgICAgICAgICAgICAgICBnaG9zdHdoaXRlOiAnI2Y4ZjhmZicsCiAgICAgICAgICAgICAgICAgICAgZ29sZDogJyNmZmQ3MDAnLAogICAgICAgICAgICAgICAgICAgIGdvbGRlbnJvZDogJyNkYWE1MjAnLAogICAgICAgICAgICAgICAgICAgIGdyYXk6ICcjODA4MDgwJywKICAgICAgICAgICAgICAgICAgICBncmVlbjogJyMwMDgwMDAnLAogICAgICAgICAgICAgICAgICAgIGdyZWVueWVsbG93OiAnI2FkZmYyZicsCiAgICAgICAgICAgICAgICAgICAgaG9uZXlkZXc6ICcjZjBmZmYwJywKICAgICAgICAgICAgICAgICAgICBob3RwaW5rOiAnI2ZmNjliNCcsCiAgICAgICAgICAgICAgICAgICAgJ2luZGlhbnJlZCAnOiAnI2NkNWM1YycsCiAgICAgICAgICAgICAgICAgICAgaW5kaWdvOiAnIzRiMDA4MicsCiAgICAgICAgICAgICAgICAgICAgaXZvcnk6ICcjZmZmZmYwJywKICAgICAgICAgICAgICAgICAgICBraGFraTogJyNmMGU2OGMnLAogICAgICAgICAgICAgICAgICAgIGxhdmVuZGVyOiAnI2U2ZTZmYScsCiAgICAgICAgICAgICAgICAgICAgbGF2ZW5kZXJibHVzaDogJyNmZmYwZjUnLAogICAgICAgICAgICAgICAgICAgIGxhd25ncmVlbjogJyM3Y2ZjMDAnLAogICAgICAgICAgICAgICAgICAgIGxlbW9uY2hpZmZvbjogJyNmZmZhY2QnLAogICAgICAgICAgICAgICAgICAgIGxpZ2h0Ymx1ZTogJyNhZGQ4ZTYnLAogICAgICAgICAgICAgICAgICAgIGxpZ2h0Y29yYWw6ICcjZjA4MDgwJywKICAgICAgICAgICAgICAgICAgICBsaWdodGN5YW46ICcjZTBmZmZmJywKICAgICAgICAgICAgICAgICAgICBsaWdodGdvbGRlbnJvZHllbGxvdzogJyNmYWZhZDInLAogICAgICAgICAgICAgICAgICAgIGxpZ2h0Z3JleTogJyNkM2QzZDMnLAogICAgICAgICAgICAgICAgICAgIGxpZ2h0Z3JlZW46ICcjOTBlZTkwJywKICAgICAgICAgICAgICAgICAgICBsaWdodHBpbms6ICcjZmZiNmMxJywKICAgICAgICAgICAgICAgICAgICBsaWdodHNhbG1vbjogJyNmZmEwN2EnLAogICAgICAgICAgICAgICAgICAgIGxpZ2h0c2VhZ3JlZW46ICcjMjBiMmFhJywKICAgICAgICAgICAgICAgICAgICBsaWdodHNreWJsdWU6ICcjODdjZWZhJywKICAgICAgICAgICAgICAgICAgICBsaWdodHNsYXRlZ3JheTogJyM3Nzg4OTknLAogICAgICAgICAgICAgICAgICAgIGxpZ2h0c3RlZWxibHVlOiAnI2IwYzRkZScsCiAgICAgICAgICAgICAgICAgICAgbGlnaHR5ZWxsb3c6ICcjZmZmZmUwJywKICAgICAgICAgICAgICAgICAgICBsaW1lOiAnIzAwZmYwMCcsCiAgICAgICAgICAgICAgICAgICAgbGltZWdyZWVuOiAnIzMyY2QzMicsCiAgICAgICAgICAgICAgICAgICAgbGluZW46ICcjZmFmMGU2JywKICAgICAgICAgICAgICAgICAgICBtYWdlbnRhOiAnI2ZmMDBmZicsCiAgICAgICAgICAgICAgICAgICAgbWFyb29uOiAnIzgwMDAwMCcsCiAgICAgICAgICAgICAgICAgICAgbWVkaXVtYXF1YW1hcmluZTogJyM2NmNkYWEnLAogICAgICAgICAgICAgICAgICAgIG1lZGl1bWJsdWU6ICcjMDAwMGNkJywKICAgICAgICAgICAgICAgICAgICBtZWRpdW1vcmNoaWQ6ICcjYmE1NWQzJywKICAgICAgICAgICAgICAgICAgICBtZWRpdW1wdXJwbGU6ICcjOTM3MGQ4JywKICAgICAgICAgICAgICAgICAgICBtZWRpdW1zZWFncmVlbjogJyMzY2IzNzEnLAogICAgICAgICAgICAgICAgICAgIG1lZGl1bXNsYXRlYmx1ZTogJyM3YjY4ZWUnLAogICAgICAgICAgICAgICAgICAgIG1lZGl1bXNwcmluZ2dyZWVuOiAnIzAwZmE5YScsCiAgICAgICAgICAgICAgICAgICAgbWVkaXVtdHVycXVvaXNlOiAnIzQ4ZDFjYycsCiAgICAgICAgICAgICAgICAgICAgbWVkaXVtdmlvbGV0cmVkOiAnI2M3MTU4NScsCiAgICAgICAgICAgICAgICAgICAgbWlkbmlnaHRibHVlOiAnIzE5MTk3MCcsCiAgICAgICAgICAgICAgICAgICAgbWludGNyZWFtOiAnI2Y1ZmZmYScsCiAgICAgICAgICAgICAgICAgICAgbWlzdHlyb3NlOiAnI2ZmZTRlMScsCiAgICAgICAgICAgICAgICAgICAgbW9jY2FzaW46ICcjZmZlNGI1JywKICAgICAgICAgICAgICAgICAgICBuYXZham93aGl0ZTogJyNmZmRlYWQnLAogICAgICAgICAgICAgICAgICAgIG5hdnk6ICcjMDAwMDgwJywKICAgICAgICAgICAgICAgICAgICBvbGRsYWNlOiAnI2ZkZjVlNicsCiAgICAgICAgICAgICAgICAgICAgb2xpdmU6ICcjODA4MDAwJywKICAgICAgICAgICAgICAgICAgICBvbGl2ZWRyYWI6ICcjNmI4ZTIzJywKICAgICAgICAgICAgICAgICAgICBvcmFuZ2U6ICcjZmZhNTAwJywKICAgICAgICAgICAgICAgICAgICBvcmFuZ2VyZWQ6ICcjZmY0NTAwJywKICAgICAgICAgICAgICAgICAgICBvcmNoaWQ6ICcjZGE3MGQ2JywKICAgICAgICAgICAgICAgICAgICBwYWxlZ29sZGVucm9kOiAnI2VlZThhYScsCiAgICAgICAgICAgICAgICAgICAgcGFsZWdyZWVuOiAnIzk4ZmI5OCcsCiAgICAgICAgICAgICAgICAgICAgcGFsZXR1cnF1b2lzZTogJyNhZmVlZWUnLAogICAgICAgICAgICAgICAgICAgIHBhbGV2aW9sZXRyZWQ6ICcjZDg3MDkzJywKICAgICAgICAgICAgICAgICAgICBwYXBheWF3aGlwOiAnI2ZmZWZkNScsCiAgICAgICAgICAgICAgICAgICAgcGVhY2hwdWZmOiAnI2ZmZGFiOScsCiAgICAgICAgICAgICAgICAgICAgcGVydTogJyNjZDg1M2YnLAogICAgICAgICAgICAgICAgICAgIHBpbms6ICcjZmZjMGNiJywKICAgICAgICAgICAgICAgICAgICBwbHVtOiAnI2RkYTBkZCcsCiAgICAgICAgICAgICAgICAgICAgcG93ZGVyYmx1ZTogJyNiMGUwZTYnLAogICAgICAgICAgICAgICAgICAgIHB1cnBsZTogJyM4MDAwODAnLAogICAgICAgICAgICAgICAgICAgIHJlYmVjY2FwdXJwbGU6ICcjNjYzMzk5JywKICAgICAgICAgICAgICAgICAgICByZWQ6ICcjZmYwMDAwJywKICAgICAgICAgICAgICAgICAgICByb3N5YnJvd246ICcjYmM4ZjhmJywKICAgICAgICAgICAgICAgICAgICByb3lhbGJsdWU6ICcjNDE2OWUxJywKICAgICAgICAgICAgICAgICAgICBzYWRkbGVicm93bjogJyM4YjQ1MTMnLAogICAgICAgICAgICAgICAgICAgIHNhbG1vbjogJyNmYTgwNzInLAogICAgICAgICAgICAgICAgICAgIHNhbmR5YnJvd246ICcjZjRhNDYwJywKICAgICAgICAgICAgICAgICAgICBzZWFncmVlbjogJyMyZThiNTcnLAogICAgICAgICAgICAgICAgICAgIHNlYXNoZWxsOiAnI2ZmZjVlZScsCiAgICAgICAgICAgICAgICAgICAgc2llbm5hOiAnI2EwNTIyZCcsCiAgICAgICAgICAgICAgICAgICAgc2lsdmVyOiAnI2MwYzBjMCcsCiAgICAgICAgICAgICAgICAgICAgc2t5Ymx1ZTogJyM4N2NlZWInLAogICAgICAgICAgICAgICAgICAgIHNsYXRlYmx1ZTogJyM2YTVhY2QnLAogICAgICAgICAgICAgICAgICAgIHNsYXRlZ3JheTogJyM3MDgwOTAnLAogICAgICAgICAgICAgICAgICAgIHNub3c6ICcjZmZmYWZhJywKICAgICAgICAgICAgICAgICAgICBzcHJpbmdncmVlbjogJyMwMGZmN2YnLAogICAgICAgICAgICAgICAgICAgIHN0ZWVsYmx1ZTogJyM0NjgyYjQnLAogICAgICAgICAgICAgICAgICAgIHRhbjogJyNkMmI0OGMnLAogICAgICAgICAgICAgICAgICAgIHRlYWw6ICcjMDA4MDgwJywKICAgICAgICAgICAgICAgICAgICB0aGlzdGxlOiAnI2Q4YmZkOCcsCiAgICAgICAgICAgICAgICAgICAgdG9tYXRvOiAnI2ZmNjM0NycsCiAgICAgICAgICAgICAgICAgICAgdHVycXVvaXNlOiAnIzQwZTBkMCcsCiAgICAgICAgICAgICAgICAgICAgdmlvbGV0OiAnI2VlODJlZScsCiAgICAgICAgICAgICAgICAgICAgd2hlYXQ6ICcjZjVkZWIzJywKICAgICAgICAgICAgICAgICAgICB3aGl0ZTogJyNmZmZmZmYnLAogICAgICAgICAgICAgICAgICAgIHdoaXRlc21va2U6ICcjZjVmNWY1JywKICAgICAgICAgICAgICAgICAgICB5ZWxsb3c6ICcjZmZmZjAwJywKICAgICAgICAgICAgICAgICAgICB5ZWxsb3dncmVlbjogJyM5YWNkMzInLAogICAgICAgICAgICAgICAgfTsKICAgICAgICAgICAgICAgIHJldHVybiBjb2xvcnNbY29sb3VyLnRvTG93ZXJDYXNlKCldOwogICAgICAgICAgICAgICAgLy8gIGlmICh0eXBlb2YgY29sb3JzW2NvbG91ci50b0xvd2VyQ2FzZSgpXSAhPSAndW5kZWZpbmVkJykgcmV0dXJuIGNvbG9yc1tjb2xvdXIudG9Mb3dlckNhc2UoKV0KICAgICAgICAgICAgICAgIC8vIHJldHVybiBmYWxzZQogICAgICAgICAgICB9OwogICAgICAgICAgICBpZiAobmFtZS5zdGFydHNXaXRoKCcjJykpIHsKICAgICAgICAgICAgICAgIHRoaXMuc2V0RnJvbUhleChuYW1lKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgIGNvbnN0IGhleENvbG9yID0gY29sb3VyTmFtZVRvSGV4KG5hbWUpOwogICAgICAgICAgICAgICAgaWYgKGhleENvbG9yKQogICAgICAgICAgICAgICAgICAgIHRoaXMuc2V0RnJvbUhleChoZXhDb2xvcik7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyB0aGUgaGV4YWRlY2ltYWwgdmFsdWUgb2YgdGhpcyBjb2xvciwgaW5jbHVkaW5nIHRoZSBsZWFkaW5nICIjIiBjaGFyYWN0ZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyB0aGUgaGV4IHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHRvSGV4KCkgewogICAgICAgICAgICBmdW5jdGlvbiBjb21wb25lbnRUb0hleChjKSB7CiAgICAgICAgICAgICAgICBjb25zdCBpbnQgPSBNYXRoLnJvdW5kKGMgKiAyNTUpOwogICAgICAgICAgICAgICAgY29uc3QgaGV4ID0gaW50LnRvU3RyaW5nKDE2KTsKICAgICAgICAgICAgICAgIHJldHVybiBoZXgubGVuZ3RoID09IDEgPyAnMCcgKyBoZXggOiBoZXg7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuICcjJyArIGNvbXBvbmVudFRvSGV4KHRoaXMucikgKyBjb21wb25lbnRUb0hleCh0aGlzLmcpICsgY29tcG9uZW50VG9IZXgodGhpcy5iKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ2hlY2tzIGlmIHRoaXMgQ29sb3IgIGNvbnRhaW5zIHRoZSBzYW1lIHZhbHVlcyBhcyB0aGUgb3RoZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gb3RoZXIgLSBUaGUgb3RoZXIgQ29sb3IgdG8gY29tcGFyZSB3aXRoLgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgdmFsdWVzIGFyZSB0aGUgc2FtZSwgb3RoZXJ3aXNlLCBgZmFsc2VgLgogICAgICAgICAqLwogICAgICAgIGlzRXF1YWwob3RoZXIpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuciA9PSBvdGhlci5yICYmIHRoaXMuZyA9PSBvdGhlci5nICYmIHRoaXMuYiA9PSBvdGhlci5iICYmIHRoaXMuYSA9PSBvdGhlci5hOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIHRydWUgaWYgdGhpcyBjb2xvciBpcyBOT1QgZXhhY3RseSB0aGUgc2FtZSBhcyBvdGhlci4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBvdGhlciAtIFRoZSBvdGhlciBjb2xvciB0byBjb21wYXJlIHdpdGguCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgdHJ1ZSBvciBmYWxzZS4KICAgICAgICAgKi8KICAgICAgICBub3RFcXVhbHMob3RoZXIpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuciAhPSBvdGhlci5yICYmIHRoaXMuZyAhPSBvdGhlci5nICYmIHRoaXMuYiAhPSBvdGhlci5iICYmIHRoaXMuYSAhPSBvdGhlci5hOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIHRydWUgaWYgdGhpcyBjb2xvciBpcyBhcHByb3hpbWF0ZWx5IHRoZSBzYW1lIGFzIG90aGVyLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIG90aGVyIC0gVGhlIG90aGVyIGNvbG9yIHRvIGNvbXBhcmUgd2l0aC4KICAgICAgICAgKiBAcGFyYW0gcHJlY2lzaW9uIC0gVGhlIHByZWNpc2lvbiB0byB3aGljaCB0aGUgdmFsdWVzIG11c3QgbWF0Y2guCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgdHJ1ZSBvciBmYWxzZS4KICAgICAgICAgKi8KICAgICAgICBhcHByb3hFcXVhbChvdGhlciwgcHJlY2lzaW9uID0gTnVtYmVyLkVQU0lMT04pIHsKICAgICAgICAgICAgcmV0dXJuIChNYXRoLmFicyh0aGlzLnIgLSBvdGhlci5yKSA8IHByZWNpc2lvbiAmJgogICAgICAgICAgICAgICAgTWF0aC5hYnModGhpcy5nIC0gb3RoZXIuZykgPCBwcmVjaXNpb24gJiYKICAgICAgICAgICAgICAgIE1hdGguYWJzKHRoaXMuYiAtIG90aGVyLmIpIDwgcHJlY2lzaW9uICYmCiAgICAgICAgICAgICAgICBNYXRoLmFicyh0aGlzLmEgLSBvdGhlci5hKSA8IHByZWNpc2lvbik7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgYSBuZXcgQ29sb3Igd2hpY2ggaXMgdGhpcyBDb2xvciBhZGRlZCB0byBvdGhlci4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBvdGhlciAtIFRoZSBvdGhlciBjb2xvciB0byBhZGQuCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgYSBuZXcgY29sb3IuCiAgICAgICAgICovCiAgICAgICAgYWRkKG90aGVyKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgQ29sb3IodGhpcy5yICsgb3RoZXIuciwgdGhpcy5nICsgb3RoZXIuZywgdGhpcy5iICsgb3RoZXIuYiwgdGhpcy5hICsgb3RoZXIuYSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFVwZGF0ZXMgdGhpcyBDb2xvciBieSBhZGRpbmcgdGhlIHZhbHVlcyBmcm9tIHRoZSBvdGhlciBjb2xvci4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBvdGhlciAtIFRoZSBvdGhlciBjb2xvciB0byBhZGQuCiAgICAgICAgICovCiAgICAgICAgYWRkSW5QbGFjZShvdGhlcikgewogICAgICAgICAgICB0aGlzLnIgKz0gb3RoZXIucjsKICAgICAgICAgICAgdGhpcy5nICs9IG90aGVyLmc7CiAgICAgICAgICAgIHRoaXMuYiArPSBvdGhlci5iOwogICAgICAgICAgICB0aGlzLmEgKz0gb3RoZXIuYTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyBhIG5ldyBjb2xvciB3aGljaCBpcyB0aGlzIGNvbG9yIHN1YnRyYWN0ZWQgZnJvbSBvdGhlci4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBvdGhlciAtIFRoZSBvdGhlciBjb2xvciB0byBzdWJ0cmFjdC4KICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyBhIG5ldyBjb2xvci4KICAgICAgICAgKi8KICAgICAgICBzdWJ0cmFjdChvdGhlcikgewogICAgICAgICAgICByZXR1cm4gbmV3IENvbG9yKHRoaXMuciAtIG90aGVyLnIsIHRoaXMuZyAtIG90aGVyLmcsIHRoaXMuYiAtIG90aGVyLmIsIHRoaXMuYSAtIG90aGVyLmEpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTY2FsZXMgdGhpcyBjb2xvciBieSBzY2FsYXIgYW5kIHJldHVybiB0aGUgcmVzdWx0IGFzIGEgbmV3IFZlYzQuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gc2NhbGFyIC0gVGhlIHNjYWxhciB2YWx1ZS4KICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyBhIG5ldyBjb2xvci4KICAgICAgICAgKi8KICAgICAgICBzY2FsZShzY2FsYXIpIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBDb2xvcih0aGlzLnIgKiBzY2FsYXIsIHRoaXMuZyAqIHNjYWxhciwgdGhpcy5iICogc2NhbGFyLCB0aGlzLmEgKiBzY2FsYXIpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTY2FsZXMgdGhpcyBjb2xvciBieSBzY2FsYXIuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gc2NhbGFyIC0gVGhlIHNjYWxhciB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBzY2FsZUluUGxhY2Uoc2NhbGFyKSB7CiAgICAgICAgICAgIHRoaXMuciAqPSBzY2FsYXI7CiAgICAgICAgICAgIHRoaXMuZyAqPSBzY2FsYXI7CiAgICAgICAgICAgIHRoaXMuYiAqPSBzY2FsYXI7CiAgICAgICAgICAgIHRoaXMuYSAqPSBzY2FsYXI7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEFwcGx5IGdhbW1hIGNvcnJlY3Rpb24gdG8gdGhpcyBjb2xvcgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGdhbW1hIC0gVGhlIGdhbW1hIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGFwcGx5R2FtbWEoZ2FtbWEpIHsKICAgICAgICAgICAgdGhpcy5zZXQoTWF0aC5wb3codGhpcy5yLCBnYW1tYSksIE1hdGgucG93KHRoaXMuZywgZ2FtbWEpLCBNYXRoLnBvdyh0aGlzLmIsIGdhbW1hKSwgdGhpcy5hKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29udmVydHMgdG8gbGluZWFyIGNvbG9yIHNwYWNlIGFuZCByZXR1cm5zIGEgbmV3IGNvbG9yCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gZ2FtbWEgLSBUaGUgZ2FtbWEgdmFsdWUuCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgYSBuZXcgY29sb3IuCiAgICAgICAgICovCiAgICAgICAgdG9MaW5lYXIoZ2FtbWEgPSAyLjIpIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBDb2xvcihNYXRoLnBvdyh0aGlzLnIsIGdhbW1hKSwgTWF0aC5wb3codGhpcy5nLCBnYW1tYSksIE1hdGgucG93KHRoaXMuYiwgZ2FtbWEpLCB0aGlzLmEpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiByZXR1cm5zIGEgbmV3IGNvbG9yIHZhbHVlIHZhbHVlIGlzIG1hcHBlZCBpbnRvIGEgZ2FtbWEgY3VydmUKICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBnYW1tYSAtIFRoZSBnYW1tYSB2YWx1ZS4KICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyBhIG5ldyBjb2xvci4KICAgICAgICAgKi8KICAgICAgICB0b0dhbW1hKGdhbW1hID0gMi4yKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgQ29sb3IoTWF0aC5wb3codGhpcy5yLCAxLjAgLyBnYW1tYSksIE1hdGgucG93KHRoaXMuZywgMS4wIC8gZ2FtbWEpLCBNYXRoLnBvdyh0aGlzLmIsIDEuMCAvIGdhbW1hKSwgdGhpcy5hKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ2FsY3VsYXRlcyBhbmQgcmV0dXJucyB0aGUgbHVtaW5hbmNlIG9mIHRoZSBsaW5lYXIgUkdCIGNvbXBvbmVudHMuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBsdW1pbmFuY2UoKSB7CiAgICAgICAgICAgIHJldHVybiAwLjIxMjYgKiB0aGlzLnIgKyAwLjcxNTIgKiB0aGlzLmcgKyAwLjA3MjIgKiB0aGlzLmI7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFBlcmZvcm1zIGEgbGluZWFyIGludGVycG9sYXRpb24gYmV0d2VlbiB0aGlzIGNvbG9yIGFuZCBvdGhlci4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBvdGhlciAtIFRoZSBvdGhlciBjb2xvciB0byBpbnRlcnBvbGF0ZSBiZXR3ZWVuLgogICAgICAgICAqIEBwYXJhbSB0IC0gSW50ZXJwb2xhdGlvbiBhbW91bnQgYmV0d2VlbiB0aGUgdHdvIGlucHV0cy4KICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyBhIG5ldyBjb2xvci4KICAgICAgICAgKi8KICAgICAgICBsZXJwKG90aGVyLCB0KSB7CiAgICAgICAgICAgIGNvbnN0IGFyID0gdGhpcy5yOwogICAgICAgICAgICBjb25zdCBhZyA9IHRoaXMuZzsKICAgICAgICAgICAgY29uc3QgYWIgPSB0aGlzLmI7CiAgICAgICAgICAgIGNvbnN0IGFhID0gdGhpcy5hOwogICAgICAgICAgICByZXR1cm4gbmV3IENvbG9yKGFyICsgdCAqIChvdGhlci5yIC0gYXIpLCBhZyArIHQgKiAob3RoZXIuZyAtIGFnKSwgYWIgKyB0ICogKG90aGVyLmIgLSBhYiksIGFhICsgdCAqIChvdGhlci5hIC0gYWEpKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ3JlYXRlcyBhIHJhbmRvbSBjb2xvci4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBnYW1tYU9mZnNldCAtIFRoZSBnYW1tYSBvZmZzZXQuIFZhbHVlcyBiZXR3ZWVuIDAgYW5kIDEgaW5jcmVhc2UgdGhlIGF2ZXJhZ2UgYnJpZ2h0bmVzcyBvZiB0aGUgZ2VuZXJhdGVkIGNvbG9yLiBWYWx1ZXMgYmV0d2VlbiAwIGFuZCAtMSBkYXJrZW4gdGhlIGdlbmVyYXRlZCBjb2xvciB2YWx1ZXMuCiAgICAgICAgICogQHBhcmFtIHJhbmRvbUFscGhhIC0gRGV0ZXJtaW5lcyB3aGV0aGVyIHRoZSBhbHBoYSBjaGFubmVsIGlzIHJhbmRvbS4gSWYgbm90LCB0aGUgYWxwaGEgdmFsdWVzIHdpbGwgYmUgMS4wLgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgbmV3IHJhbmRvbSBjb2xvci4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgcmFuZG9tKGdhbW1hT2Zmc2V0ID0gMC4wLCByYW5kb21BbHBoYSA9IGZhbHNlKSB7CiAgICAgICAgICAgIGlmIChnYW1tYU9mZnNldCA+IDAuMCkgewogICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBDb2xvcihnYW1tYU9mZnNldCArIE1hdGgucmFuZG9tKCkgKiAoMS4wIC0gZ2FtbWFPZmZzZXQpLCBnYW1tYU9mZnNldCArIE1hdGgucmFuZG9tKCkgKiAoMS4wIC0gZ2FtbWFPZmZzZXQpLCBnYW1tYU9mZnNldCArIE1hdGgucmFuZG9tKCkgKiAoMS4wIC0gZ2FtbWFPZmZzZXQpLCByYW5kb21BbHBoYSA/IGdhbW1hT2Zmc2V0ICsgTWF0aC5yYW5kb20oKSAqICgxLjAgLSBnYW1tYU9mZnNldCkgOiAxLjApOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIChnYW1tYU9mZnNldCA8IDAuMCkgewogICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBDb2xvcihNYXRoLnJhbmRvbSgpICogKDEuMCArIGdhbW1hT2Zmc2V0KSwgTWF0aC5yYW5kb20oKSAqICgxLjAgKyBnYW1tYU9mZnNldCksIE1hdGgucmFuZG9tKCkgKiAoMS4wICsgZ2FtbWFPZmZzZXQpLCByYW5kb21BbHBoYSA/IE1hdGgucmFuZG9tKCkgKiAoMS4wICsgZ2FtbWFPZmZzZXQpIDogMS4wKTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gbmV3IENvbG9yKE1hdGgucmFuZG9tKCksIE1hdGgucmFuZG9tKCksIE1hdGgucmFuZG9tKCksIHJhbmRvbUFscGhhID8gTWF0aC5yYW5kb20oKSA6IDEuMCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENsb25lcyB0aGlzIGNvbG9yIGFuZCByZXR1cm5zIGEgbmV3IGNvbG9yLgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgYSBuZXcgY29sb3IuCiAgICAgICAgICovCiAgICAgICAgY2xvbmUoKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgQ29sb3IodGhpcy5yLCB0aGlzLmcsIHRoaXMuYiwgdGhpcy5hKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyB0aGUgdHlwZSBhcyBhbiBhcnJheS4gT2Z0ZW4gdXNlZCB0byBwYXNzIHR5cGVzIHRvIHRoZSBHUFUuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyBhcyBhbiBhcnJheS4KICAgICAgICAgKi8KICAgICAgICBhc0FycmF5KCkgewogICAgICAgICAgICByZXR1cm4gW3RoaXMuciwgdGhpcy5nLCB0aGlzLmIsIHRoaXMuYV07CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFNldHRlciBmcm9tIGFuIFJHQiBhcnJheS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB2YWxzIC0gVGhlIHZhbHMgcGFyYW0uCiAgICAgICAgICovCiAgICAgICAgZnJvbUFycmF5KHZhbHMpIHsKICAgICAgICAgICAgdGhpcy5yID0gdmFsc1swXSAvIDI1NTsKICAgICAgICAgICAgdGhpcy5nID0gdmFsc1sxXSAvIDI1NTsKICAgICAgICAgICAgdGhpcy5iID0gdmFsc1syXSAvIDI1NTsKICAgICAgICAgICAgdGhpcy5hID0gdmFscy5sZW5ndGggPT0gNCA/IHZhbHNbM10gLyAyNTUgOiAxLjA7CiAgICAgICAgfQogICAgICAgIC8vIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KICAgICAgICAvLyBQZXJzaXN0ZW5jZQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSB0b0pTT04gbWV0aG9kIGVuY29kZXMgdGhpcyB0eXBlIGFzIGEganNvbiBvYmplY3QgZm9yIHBlcnNpc3RlbmNlLgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFRoZSBqc29uIG9iamVjdC4KICAgICAgICAgKi8KICAgICAgICB0b0pTT04oKSB7CiAgICAgICAgICAgIHJldHVybiB7CiAgICAgICAgICAgICAgICByOiB0aGlzLnIsCiAgICAgICAgICAgICAgICBnOiB0aGlzLmcsCiAgICAgICAgICAgICAgICBiOiB0aGlzLmIsCiAgICAgICAgICAgICAgICBhOiB0aGlzLmEsCiAgICAgICAgICAgIH07CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBmcm9tSlNPTiBtZXRob2QgZGVjb2RlcyBhIGpzb24gb2JqZWN0IGZvciB0aGlzIHR5cGUuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gaiAtIFRoZSBqc29uIG9iamVjdC4KICAgICAgICAgKi8KICAgICAgICBmcm9tSlNPTihqKSB7CiAgICAgICAgICAgIHRoaXMuciA9IGoucjsKICAgICAgICAgICAgdGhpcy5nID0gai5nOwogICAgICAgICAgICB0aGlzLmIgPSBqLmI7CiAgICAgICAgICAgIHRoaXMuYSA9IGouYTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogTG9hZHMgdGhlIHN0YXRlIG9mIHRoZSB2YWx1ZSBmcm9tIGEgYmluYXJ5IHJlYWRlci4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSByZWFkZXIgLSBUaGUgcmVhZGVyIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHJlYWRCaW5hcnkocmVhZGVyKSB7CiAgICAgICAgICAgIHRoaXMuciA9IHJlYWRlci5sb2FkRmxvYXQzMigpOwogICAgICAgICAgICB0aGlzLmcgPSByZWFkZXIubG9hZEZsb2F0MzIoKTsKICAgICAgICAgICAgdGhpcy5iID0gcmVhZGVyLmxvYWRGbG9hdDMyKCk7CiAgICAgICAgICAgIHRoaXMuYSA9IHJlYWRlci5sb2FkRmxvYXQzMigpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIHRoZSBDU1MgcmdiYSBzdHJpbmcuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICB0b0NTU1N0cmluZygpIHsKICAgICAgICAgICAgcmV0dXJuICgncmdiYSgnICsKICAgICAgICAgICAgICAgIE1hdGgucm91bmQodGhpcy5yICogMjU1KSArCiAgICAgICAgICAgICAgICAnLCAnICsKICAgICAgICAgICAgICAgIE1hdGgucm91bmQodGhpcy5nICogMjU1KSArCiAgICAgICAgICAgICAgICAnLCAnICsKICAgICAgICAgICAgICAgIE1hdGgucm91bmQodGhpcy5iICogMjU1KSArCiAgICAgICAgICAgICAgICAnLCAnICsKICAgICAgICAgICAgICAgIHRoaXMuYSArCiAgICAgICAgICAgICAgICAnKScpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb252ZXJ0cyB0aGlzIFZlYzMgdG8gYSBzdHJpbmcgaW4gSlNPTiBmb3JtYXQuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICB0b1N0cmluZygpIHsKICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5ldy1jYXAKICAgICAgICAgICAgcmV0dXJuIFN0cmluZ0Z1bmN0aW9ucy5zdHJpbmdpZnlKU09OV2l0aEZpeGVkUHJlY2lzaW9uKHRoaXMudG9KU09OKCkpOwogICAgICAgIH0KICAgIH0KCiAgICB2YXIgRXVsZXJBbmdsZXNBeGlzT3JkZXI7CiAgICAoZnVuY3Rpb24gKEV1bGVyQW5nbGVzQXhpc09yZGVyKSB7CiAgICAgICAgRXVsZXJBbmdsZXNBeGlzT3JkZXJbRXVsZXJBbmdsZXNBeGlzT3JkZXJbIlhZWiJdID0gMF0gPSAiWFlaIjsKICAgICAgICBFdWxlckFuZ2xlc0F4aXNPcmRlcltFdWxlckFuZ2xlc0F4aXNPcmRlclsiWVpYIl0gPSAxXSA9ICJZWlgiOwogICAgICAgIEV1bGVyQW5nbGVzQXhpc09yZGVyW0V1bGVyQW5nbGVzQXhpc09yZGVyWyJaWFkiXSA9IDJdID0gIlpYWSI7CiAgICAgICAgRXVsZXJBbmdsZXNBeGlzT3JkZXJbRXVsZXJBbmdsZXNBeGlzT3JkZXJbIlhaWSJdID0gM10gPSAiWFpZIjsKICAgICAgICBFdWxlckFuZ2xlc0F4aXNPcmRlcltFdWxlckFuZ2xlc0F4aXNPcmRlclsiWllYIl0gPSA0XSA9ICJaWVgiOwogICAgICAgIEV1bGVyQW5nbGVzQXhpc09yZGVyW0V1bGVyQW5nbGVzQXhpc09yZGVyWyJZWFoiXSA9IDVdID0gIllYWiI7CiAgICB9KShFdWxlckFuZ2xlc0F4aXNPcmRlciB8fCAoRXVsZXJBbmdsZXNBeGlzT3JkZXIgPSB7fSkpOwogICAgLyoqCiAgICAgKiBDbGFzcyByZXByZXNlbnRpbmcgZXVsZXIgYW5nbGVzLiBFdWxlciBhbmdsZXMgZGVzY3JpYmUgcm90YXRpbmcgYW4gb2JqZWN0CiAgICAgKiBhcm91bmQgaXRzIHZhcmlvdXMgYXhpcyBpbiBhIHNwZWNpZmllZCBheGlzIG9yZGVyLgogICAgICoKICAgICAqLwogICAgY2xhc3MgRXVsZXJBbmdsZXMgewogICAgICAgIHg7CiAgICAgICAgeTsKICAgICAgICB6OwogICAgICAgIG9yZGVyOwogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZSBhIGV1bGVyIGFuZ2xlLiBSZWNlaXZlcyB0aGUgeHl6IHZhbHVlcyBpbiByYWRpYW5zIGFuZCB0aGUgb3JkZXIgdGhhdCB0aGUgcm90YXRpb25zIGFyZSBhcHBsaWVkLgogICAgICAgICAqCiAgICAgICAgICogT3JkZXIgcGFyYW1ldGVyIHZhbHVlczogYFhZWjogMGAsIGBZWlg6IDFgLCBgWlhZOiAyYCwgYFhaWTogM2AsIGBaWVg6IDRgLCBgWVhaOiA1YAogICAgICAgICAqCiAgICAgICAgICogSXQgY291bGQgYmUgZWl0aGVyIHRoZSBgc3RyaW5nYCBvciB0aGUgYG51bWJlcmAgdmFsdWUuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0geCAtIFRoZSBhbmdsZSBvZiB0aGUgeCBheGlzIGluIHJhZGlhbnMuIERlZmF1bHQgaXMgMC4KICAgICAgICAgKiBAcGFyYW0geSAtIFRoZSBhbmdsZSBvZiB0aGUgeSBheGlzIGluIHJhZGlhbnMuIERlZmF1bHQgaXMgMC4KICAgICAgICAgKiBAcGFyYW0geiAtIFRoZSBhbmdsZSBvZiB0aGUgeiBheGlzIGluIHJhZGlhbnMuIERlZmF1bHQgaXMgMC4KICAgICAgICAgKiBAcGFyYW0gb3JkZXIgLSBUaGUgb3JkZXIgaW4gd2hpY2ggdGhlIHJvdGF0aW9ucyBhcmUgYXBwbGllZC4KICAgICAgICAgKi8KICAgICAgICBjb25zdHJ1Y3Rvcih4ID0gMCwgeSA9IDAsIHogPSAwLCBvcmRlciA9IDApIHsKICAgICAgICAgICAgdGhpcy54ID0geDsKICAgICAgICAgICAgdGhpcy55ID0geTsKICAgICAgICAgICAgdGhpcy56ID0gejsKICAgICAgICAgICAgaWYgKHR5cGVvZiBvcmRlciA9PT0gJ251bWJlcicgJiYgIWlzTmFOKG9yZGVyKSkKICAgICAgICAgICAgICAgIHRoaXMub3JkZXIgPSBvcmRlcjsKICAgICAgICAgICAgZWxzZSB7CiAgICAgICAgICAgICAgICBzd2l0Y2ggKG9yZGVyKSB7CiAgICAgICAgICAgICAgICAgICAgY2FzZSAnWFlaJzoKICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5vcmRlciA9IDA7CiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgICAgIGNhc2UgJ1laWCc6CiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMub3JkZXIgPSAxOwogICAgICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgICAgICBjYXNlICdaWFknOgogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLm9yZGVyID0gMjsKICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICAgICAgY2FzZSAnWFpZJzoKICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5vcmRlciA9IDM7CiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgICAgIGNhc2UgJ1pZWCc6CiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMub3JkZXIgPSA0OwogICAgICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgICAgICBjYXNlICdZWFonOgogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLm9yZGVyID0gNTsKICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICAgICAgZGVmYXVsdDoKICAgICAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIEV1bGVyIEFuZ2xlcyBPcmRlcjonICsgb3JkZXIpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFNldHMgdGhlIEV1bGVyQW5nbGVzCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0geCAtIFRoZSB4IGF4aXMgcm90YXRpb24gaW4gcmFkaWFucy4KICAgICAgICAgKiBAcGFyYW0geSAtIFRoZSB5IGF4aXMgcm90YXRpb24gaW4gcmFkaWFucy4KICAgICAgICAgKiBAcGFyYW0geiAtIFRoZSB6IGF4aXMgcm90YXRpb24gaW4gcmFkaWFucy4KICAgICAgICAgKi8KICAgICAgICBzZXQoeCwgeSwgeikgewogICAgICAgICAgICB0aGlzLnggPSB4OwogICAgICAgICAgICB0aGlzLnkgPSB5OwogICAgICAgICAgICB0aGlzLnogPSB6OwogICAgICAgIH0KICAgICAgICAvLyAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KICAgICAgICAvLyBQZXJzaXN0ZW5jZQogICAgICAgIC8qKgogICAgICAgICAqIENvbnZlcnRzIHRoaXMgVmVjMyB0byBhIHN0cmluZyBpbiBKU09OIGZvcm1hdC4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHRvU3RyaW5nKCkgewogICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbmV3LWNhcAogICAgICAgICAgICByZXR1cm4gU3RyaW5nRnVuY3Rpb25zLnN0cmluZ2lmeUpTT05XaXRoRml4ZWRQcmVjaXNpb24odGhpcy50b0pTT04oKSk7CiAgICAgICAgfQogICAgICAgIHRvSlNPTigpIHsKICAgICAgICAgICAgcmV0dXJuIHsKICAgICAgICAgICAgICAgIHg6IHRoaXMueCwKICAgICAgICAgICAgICAgIHk6IHRoaXMueSwKICAgICAgICAgICAgICAgIHo6IHRoaXMueiwKICAgICAgICAgICAgICAgIG9yZGVyOiB0aGlzLm9yZGVyLAogICAgICAgICAgICB9OwogICAgICAgIH0KICAgICAgICBmcm9tSlNPTihqc29uKSB7CiAgICAgICAgICAgIHRoaXMueCA9IGpzb24ueDsKICAgICAgICAgICAgdGhpcy55ID0ganNvbi55OwogICAgICAgICAgICB0aGlzLnogPSBqc29uLno7CiAgICAgICAgICAgIHRoaXMub3JkZXIgPSBqc29uLm9yZGVyOwogICAgICAgIH0KICAgIH0KCiAgICAvKiBlc2xpbnQtZGlzYWJsZSBuZXctY2FwICovCiAgICAvKioKICAgICAqIEEgY2xhc3MgcmVwcmVzZW50aW5nIGEgM3gzIG1hdHJpeC4KICAgICAqIFRoaXMgbWF0cml4IGNsYXNzIGlzIGJhc2VkIG9uIEdMTSwgYW5kIGlzIGNvbHVtbiBtYWpvci4KICAgICAqCiAgICAgKi8KICAgIGNsYXNzIE1hdDMgewogICAgICAgIG0wMCA9IDE7CiAgICAgICAgbTAxID0gMDsKICAgICAgICBtMDIgPSAwOwogICAgICAgIG0xMCA9IDA7CiAgICAgICAgbTExID0gMTsKICAgICAgICBtMTIgPSAwOwogICAgICAgIG0yMCA9IDA7CiAgICAgICAgbTIxID0gMDsKICAgICAgICBtMjIgPSAxOwogICAgICAgIC8qKgogICAgICAgICAqIEluaXRpYWxpemVzIHRoZSBNYXQzIGNsYXNzIHdpdGggZ2l2ZW4gZGF0YS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBtMDAgLSBSb3cgMCwgY29sdW1uIDAuCiAgICAgICAgICogQHBhcmFtIG0wMSAtIFJvdyAwLCBjb2x1bW4gMS4KICAgICAgICAgKiBAcGFyYW0gbTAyIC0gUm93IDAsIGNvbHVtbiAyLgogICAgICAgICAqIEBwYXJhbSBtMTAgLSBSb3cgMSwgY29sdW1uIDAuCiAgICAgICAgICogQHBhcmFtIG0xMSAtIFJvdyAxLCBjb2x1bW4gMS4KICAgICAgICAgKiBAcGFyYW0gbTEyIC0gUm93IDEsIGNvbHVtbiAyLgogICAgICAgICAqIEBwYXJhbSBtMjAgLSBSb3cgMiwgY29sdW1uIDAuCiAgICAgICAgICogQHBhcmFtIG0yMSAtIFJvdyAyLCBjb2x1bW4gMS4KICAgICAgICAgKiBAcGFyYW0gbTIyIC0gUm93IDIsIGNvbHVtbiAyLgogICAgICAgICAqLwogICAgICAgIGNvbnN0cnVjdG9yKG0wMCA9IDEsIG0wMSA9IDAsIG0wMiA9IDAsIG0xMCA9IDAsIG0xMSA9IDEsIG0xMiA9IDAsIG0yMCA9IDAsIG0yMSA9IDAsIG0yMiA9IDEpIHsKICAgICAgICAgICAgaWYgKG0wMCBpbnN0YW5jZW9mIFZlYzMgJiYgbTAxIGluc3RhbmNlb2YgVmVjMyAmJiBtMDIgaW5zdGFuY2VvZiBWZWMzKSB7CiAgICAgICAgICAgICAgICB0aGlzLnNldChtMDAueCwgbTAwLnksIG0wMC56LCBtMDEueCwgbTAxLnksIG0wMS56LCBtMDIueCwgbTAyLnksIG0wMi56KTsKICAgICAgICAgICAgfQogICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgIHRoaXMuc2V0KG0wMCwgbTAxLCBtMDIsIG0xMCwgbTExLCBtMTIsIG0yMCwgbTIxLCBtMjIpOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEdldHRlciBmb3IgdGhlIGB4YCBheGlzLgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgdGhlIGB4YCBheGlzIGFzIGEgVmVjMy4KICAgICAgICAgKi8KICAgICAgICBnZXQgeEF4aXMoKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgVmVjMyh0aGlzLm0wMCwgdGhpcy5tMDEsIHRoaXMubTAyKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU2V0dGVyIGZvciB0aGUgYHhgIGF4aXMuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gdmVjMyAtIFRoZSB2ZWMzIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHNldCB4QXhpcyh2ZWMzKSB7CiAgICAgICAgICAgIHRoaXMueEF4aXMuc2V0KHZlYzMueCwgdmVjMy55LCB2ZWMzLnopOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBHZXR0ZXIgZm9yIHRoZSBgeWAgYXhpcy4KICAgICAgICAgKiAqIEByZXR1cm4gLSBSZXR1cm5zIHRoZSBgeWAgYXhpcyBhcyBhIFZlYzMuCiAgICAgICAgICovCiAgICAgICAgZ2V0IHlBeGlzKCkgewogICAgICAgICAgICByZXR1cm4gbmV3IFZlYzModGhpcy5tMTAsIHRoaXMubTExLCB0aGlzLm0xMik7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFNldHRlciBmb3IgdGhlIGB5YCBheGlzLgogICAgICAgICAqIEBwYXJhbSB2ZWMzIC0gVGhlIHZlYzMgdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgc2V0IHlBeGlzKHZlYzMpIHsKICAgICAgICAgICAgdGhpcy55QXhpcy5zZXQodmVjMy54LCB2ZWMzLnksIHZlYzMueik7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEdldHRlciBmb3IgdGhlIGB6YCBheGlzLgogICAgICAgICAqICogQHJldHVybiAtIFJldHVybnMgdGhlIGB6YCBheGlzIGFzIGEgVmVjMy4KICAgICAgICAgKi8KICAgICAgICBnZXQgekF4aXMoKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgVmVjMyh0aGlzLm0yMCwgdGhpcy5tMjEsIHRoaXMubTIyKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU2V0dGVyIGZvciB0aGUgYHpgIGF4aXMuCiAgICAgICAgICogQHBhcmFtIHZlYzMgLSBUaGUgdmVjMyB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBzZXQgekF4aXModmVjMykgewogICAgICAgICAgICB0aGlzLnpBeGlzLnNldCh2ZWMzLngsIHZlYzMueSwgdmVjMy56KTsKICAgICAgICB9CiAgICAgICAgLy8gLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KICAgICAgICAvLyBTZXR0ZXJzCiAgICAgICAgLyoqCiAgICAgICAgICogU2V0cyB0aGUgc3RhdGUgb2YgdGhlIE1hdDMgY2xhc3MKICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBtMDAgLSBSb3cgMCwgY29sdW1uIDAuCiAgICAgICAgICogQHBhcmFtIG0wMSAtIFJvdyAwLCBjb2x1bW4gMS4KICAgICAgICAgKiBAcGFyYW0gbTAyIC0gUm93IDAsIGNvbHVtbiAyLgogICAgICAgICAqIEBwYXJhbSBtMTAgLSBSb3cgMSwgY29sdW1uIDAuCiAgICAgICAgICogQHBhcmFtIG0xMSAtIFJvdyAxLCBjb2x1bW4gMS4KICAgICAgICAgKiBAcGFyYW0gbTEyIC0gUm93IDEsIGNvbHVtbiAyLgogICAgICAgICAqIEBwYXJhbSBtMjAgLSBSb3cgMiwgY29sdW1uIDAuCiAgICAgICAgICogQHBhcmFtIG0yMSAtIFJvdyAyLCBjb2x1bW4gMS4KICAgICAgICAgKiBAcGFyYW0gbTIyIC0gUm93IDIsIGNvbHVtbiAyLgogICAgICAgICAqLwogICAgICAgIHNldChtMDAgPSAxLCBtMDEgPSAwLCBtMDIgPSAwLCBtMTAgPSAwLCBtMTEgPSAxLCBtMTIgPSAwLCBtMjAgPSAwLCBtMjEgPSAwLCBtMjIgPSAxKSB7CiAgICAgICAgICAgIHRoaXMubTAwID0gbTAwOwogICAgICAgICAgICB0aGlzLm0wMSA9IG0wMTsKICAgICAgICAgICAgdGhpcy5tMDIgPSBtMDI7CiAgICAgICAgICAgIHRoaXMubTEwID0gbTEwOwogICAgICAgICAgICB0aGlzLm0xMSA9IG0xMTsKICAgICAgICAgICAgdGhpcy5tMTIgPSBtMTI7CiAgICAgICAgICAgIHRoaXMubTIwID0gbTIwOwogICAgICAgICAgICB0aGlzLm0yMSA9IG0yMTsKICAgICAgICAgICAgdGhpcy5tMjIgPSBtMjI7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFNldHMgc3RhdGUgb2YgdGhlIE1hdDMgd2l0aCB0aGUgaWRlbnRpdHkgIE1hdHJpeAogICAgICAgICAqLwogICAgICAgIHNldElkZW50aXR5KCkgewogICAgICAgICAgICB0aGlzLnNldCgpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTZXRzIHN0YXRlIG9mIHRoZSBNYXQzIGZyb20gYW5vdGhlciBNYXQzCiAgICAgICAgICoKICAgICAgICAgKiBOb3RlOiB3b3JrcyB3aXRoIGVpdGhlciBNYXQzIG9yIE1hdDQuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gbWF0IC0gVGhlIG1hdCB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBzZXRGcm9tTWF0KG1hdCkgewogICAgICAgICAgICB0aGlzLm0wMCA9IG1hdC5tMDA7CiAgICAgICAgICAgIHRoaXMubTAxID0gbWF0Lm0wMTsKICAgICAgICAgICAgdGhpcy5tMDIgPSBtYXQubTAyOwogICAgICAgICAgICB0aGlzLm0xMCA9IG1hdC5tMTA7CiAgICAgICAgICAgIHRoaXMubTExID0gbWF0Lm0xMTsKICAgICAgICAgICAgdGhpcy5tMTIgPSBtYXQubTEyOwogICAgICAgICAgICB0aGlzLm0yMCA9IG1hdC5tMjA7CiAgICAgICAgICAgIHRoaXMubTIxID0gbWF0Lm0yMTsKICAgICAgICAgICAgdGhpcy5tMjIgPSBtYXQubTIyOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTY2FsZXMgYW5kIGNhbGN1bGF0ZXMgdGhlIGNyb3NzIHByb2R1Y3Qgb2YgdGhlIGBWZWMzYCBhbmQgc2V0cyB0aGUgcmVzdWx0IGluIHRoZSBNYXQzCiAgICAgICAgICogTm90ZTogdGhlIHJlc3VsdGluZyBtYXRyaXggK1ogYXhpcyBpcyBhbGlnbmVkIHdpdGggdGhlIHByb3ZpZGVkIGRpcmVjdGlvbiB2YWx1ZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBkaXIgLSBUaGUgZGlyIHZhbHVlLgogICAgICAgICAqIEBwYXJhbSB1cCAtIFRoZSB1cCB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBzZXRGcm9tRGlyZWN0aW9uQW5kVXB2ZWN0b3IoZGlyLCB1cCkgewogICAgICAgICAgICBjb25zdCB6QXhpcyA9IGRpcjsKICAgICAgICAgICAgY29uc3QgekxlbiA9IHpBeGlzLmxlbmd0aCgpOwogICAgICAgICAgICBpZiAoekxlbiA8IE51bWJlci5FUFNJTE9OKSB7CiAgICAgICAgICAgICAgICB0aGlzLnNldElkZW50aXR5KCk7CiAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgIH0KICAgICAgICAgICAgekF4aXMuc2NhbGVJblBsYWNlKDEgLyB6TGVuKTsKICAgICAgICAgICAgY29uc3QgeEF4aXMgPSB1cC5jcm9zcyh6QXhpcyk7CiAgICAgICAgICAgIGNvbnN0IHhMZW4gPSB4QXhpcy5sZW5ndGgoKTsKICAgICAgICAgICAgaWYgKHhMZW4gPiBOdW1iZXIuRVBTSUxPTikKICAgICAgICAgICAgICAgIHhBeGlzLnNjYWxlSW5QbGFjZSgxIC8geExlbik7CiAgICAgICAgICAgIGNvbnN0IHlBeGlzID0gekF4aXMuY3Jvc3MoeEF4aXMpOwogICAgICAgICAgICBjb25zdCB5TGVuID0geUF4aXMubGVuZ3RoKCk7CiAgICAgICAgICAgIGlmICh5TGVuID4gTnVtYmVyLkVQU0lMT04pCiAgICAgICAgICAgICAgICB5QXhpcy5zY2FsZUluUGxhY2UoMSAvIHlMZW4pOwogICAgICAgICAgICB0aGlzLnNldCh4QXhpcy54LCB4QXhpcy55LCB4QXhpcy56LCB5QXhpcy54LCB5QXhpcy55LCB5QXhpcy56LCB6QXhpcy54LCB6QXhpcy55LCB6QXhpcy56KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogSW52ZXJ0cyBhIE1hdDMgYW5kIHJldHVybnMgdGhlIHJlc3VsdCBhcyBhIG5ldyBpbnN0YW5jZS4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGEgbmV3IE1hdDMuCiAgICAgICAgICovCiAgICAgICAgaW52ZXJzZSgpIHsKICAgICAgICAgICAgY29uc3QgYTAwID0gdGhpcy5tMDA7CiAgICAgICAgICAgIGNvbnN0IGEwMSA9IHRoaXMubTAxOwogICAgICAgICAgICBjb25zdCBhMDIgPSB0aGlzLm0wMjsKICAgICAgICAgICAgY29uc3QgYTEwID0gdGhpcy5tMTA7CiAgICAgICAgICAgIGNvbnN0IGExMSA9IHRoaXMubTExOwogICAgICAgICAgICBjb25zdCBhMTIgPSB0aGlzLm0xMjsKICAgICAgICAgICAgY29uc3QgYTIwID0gdGhpcy5tMjA7CiAgICAgICAgICAgIGNvbnN0IGEyMSA9IHRoaXMubTIxOwogICAgICAgICAgICBjb25zdCBhMjIgPSB0aGlzLm0yMjsKICAgICAgICAgICAgY29uc3QgYjAxID0gYTIyICogYTExIC0gYTEyICogYTIxOwogICAgICAgICAgICBjb25zdCBiMTEgPSAtYTIyICogYTEwICsgYTEyICogYTIwOwogICAgICAgICAgICBjb25zdCBiMjEgPSBhMjEgKiBhMTAgLSBhMTEgKiBhMjA7CiAgICAgICAgICAgIC8vIENhbGN1bGF0ZSB0aGUgZGV0ZXJtaW5hbnQKICAgICAgICAgICAgbGV0IGRldCA9IGEwMCAqIGIwMSArIGEwMSAqIGIxMSArIGEwMiAqIGIyMTsKICAgICAgICAgICAgaWYgKCFkZXQpIHsKICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybignVW5hYmxlIHRvIGludmVydCBNYXQzJyk7CiAgICAgICAgICAgICAgICByZXR1cm4gbmV3IE1hdDMoKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBkZXQgPSAxLjAgLyBkZXQ7CiAgICAgICAgICAgIHJldHVybiBuZXcgTWF0MyhiMDEgKiBkZXQsICgtYTIyICogYTAxICsgYTAyICogYTIxKSAqIGRldCwgKGExMiAqIGEwMSAtIGEwMiAqIGExMSkgKiBkZXQsIGIxMSAqIGRldCwgKGEyMiAqIGEwMCAtIGEwMiAqIGEyMCkgKiBkZXQsICgtYTEyICogYTAwICsgYTAyICogYTEwKSAqIGRldCwgYjIxICogZGV0LCAoLWEyMSAqIGEwMCArIGEwMSAqIGEyMCkgKiBkZXQsIChhMTEgKiBhMDAgLSBhMDEgKiBhMTApICogZGV0KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogSW52ZXJ0cyBhIE1hdDMgaW4gcGxhY2UgbW9kaWZ5aW5nIGl0cyB2YWx1ZXMuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBpbnZlcnRJblBsYWNlKCkgewogICAgICAgICAgICBjb25zdCBhMDAgPSB0aGlzLm0wMDsKICAgICAgICAgICAgY29uc3QgYTAxID0gdGhpcy5tMDE7CiAgICAgICAgICAgIGNvbnN0IGEwMiA9IHRoaXMubTAyOwogICAgICAgICAgICBjb25zdCBhMTAgPSB0aGlzLm0xMDsKICAgICAgICAgICAgY29uc3QgYTExID0gdGhpcy5tMTE7CiAgICAgICAgICAgIGNvbnN0IGExMiA9IHRoaXMubTEyOwogICAgICAgICAgICBjb25zdCBhMjAgPSB0aGlzLm0yMDsKICAgICAgICAgICAgY29uc3QgYTIxID0gdGhpcy5tMjE7CiAgICAgICAgICAgIGNvbnN0IGEyMiA9IHRoaXMubTIyOwogICAgICAgICAgICBjb25zdCBiMDEgPSBhMjIgKiBhMTEgLSBhMTIgKiBhMjE7CiAgICAgICAgICAgIGNvbnN0IGIxMSA9IC1hMjIgKiBhMTAgKyBhMTIgKiBhMjA7CiAgICAgICAgICAgIGNvbnN0IGIyMSA9IGEyMSAqIGExMCAtIGExMSAqIGEyMDsKICAgICAgICAgICAgLy8gQ2FsY3VsYXRlIHRoZSBkZXRlcm1pbmFudAogICAgICAgICAgICBsZXQgZGV0ID0gYTAwICogYjAxICsgYTAxICogYjExICsgYTAyICogYjIxOwogICAgICAgICAgICBpZiAoIWRldCkgewogICAgICAgICAgICAgICAgY29uc29sZS53YXJuKCdVbmFibGUgdG8gaW52ZXJ0IE1hdDMnKTsKICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsKICAgICAgICAgICAgfQogICAgICAgICAgICBkZXQgPSAxLjAgLyBkZXQ7CiAgICAgICAgICAgIHRoaXMuc2V0KGIwMSAqIGRldCwgKC1hMjIgKiBhMDEgKyBhMDIgKiBhMjEpICogZGV0LCAoYTEyICogYTAxIC0gYTAyICogYTExKSAqIGRldCwgYjExICogZGV0LCAoYTIyICogYTAwIC0gYTAyICogYTIwKSAqIGRldCwgKC1hMTIgKiBhMDAgKyBhMDIgKiBhMTApICogZGV0LCBiMjEgKiBkZXQsICgtYTIxICogYTAwICsgYTAxICogYTIwKSAqIGRldCwgKGExMSAqIGEwMCAtIGEwMSAqIGExMCkgKiBkZXQpOwogICAgICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVHJhbnNwb3NlcyAoZXhjaGFuZ2VzIGNvbHVtbnMgd2l0aCByb3dzKSB0aGlzIG1hdHJpeAogICAgICAgICAqIGFuZCByZXR1cm5zIHRoZSByZXN1bHQgYXMgYSBuZXcgaW5zdGFuY2UuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJuIGEgbmV3IHRyYW5zcG9zZWQgTWF0My4KICAgICAgICAgKi8KICAgICAgICB0cmFuc3Bvc2UoKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgTWF0Myh0aGlzLm0wMCwgdGhpcy5tMTAsIHRoaXMubTIwLCB0aGlzLm0wMSwgdGhpcy5tMTEsIHRoaXMubTIxLCB0aGlzLm0wMiwgdGhpcy5tMTIsIHRoaXMubTIyKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVHJhbnNwb3NlcyAoZXhjaGFuZ2VzIGNvbHVtbnMgd2l0aCByb3dzKSB0aGlzIG1hdHJpeCBtb2RpZnlpbmcgaXRzIHZhbHVlcy4KICAgICAgICAgKi8KICAgICAgICB0cmFuc3Bvc2VJblBsYWNlKCkgewogICAgICAgICAgICAvLyBJZiB3ZSBhcmUgdHJhbnNwb3Npbmcgb3Vyc2VsdmVzIHdlIGNhbiBza2lwIGEgZmV3IHN0ZXBzIGJ1dCBoYXZlIHRvIGNhY2hlIHNvbWUgdmFsdWVzCiAgICAgICAgICAgIGNvbnN0IGEwMSA9IHRoaXMubTAxOwogICAgICAgICAgICBjb25zdCBhMDIgPSB0aGlzLm0wMjsKICAgICAgICAgICAgY29uc3QgYTEyID0gdGhpcy5tMTI7CiAgICAgICAgICAgIHRoaXMubTAxID0gdGhpcy5tMTA7CiAgICAgICAgICAgIHRoaXMubTAyID0gdGhpcy5tMjA7CiAgICAgICAgICAgIHRoaXMubTEwID0gYTAxOwogICAgICAgICAgICB0aGlzLm0xMiA9IHRoaXMubTIxOwogICAgICAgICAgICB0aGlzLm0yMCA9IGEwMjsKICAgICAgICAgICAgdGhpcy5tMjEgPSBhMTI7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRyYW5zZm9ybXMgdGhlIFZlYzMgd2l0aCBhIE1hdDMuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gdmVjMyAtIFRoZSB2ZWMzIHZhbHVlLgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm4gdGhlIHJlc3VsdCBhcyBhIG5ldyBWZWMzLgogICAgICAgICAqLwogICAgICAgIHRyYW5zZm9ybVZlYzModmVjMykgewogICAgICAgICAgICByZXR1cm4gbmV3IFZlYzModGhpcy5tMDAgKiB2ZWMzLnggKyB0aGlzLm0wMSAqIHZlYzMueSArIHRoaXMubTAyICogdmVjMy56LCB0aGlzLm0xMCAqIHZlYzMueCArIHRoaXMubTExICogdmVjMy55ICsgdGhpcy5tMTIgKiB2ZWMzLnosIHRoaXMubTIwICogdmVjMy54ICsgdGhpcy5tMjEgKiB2ZWMzLnkgKyB0aGlzLm0yMiAqIHZlYzMueik7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENsb25lcyB0aGlzIE1hdDMgcmV0dXJuaW5nIGEgbmV3IGluc3RhbmNlLgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgYSBuZXcgTWF0My4KICAgICAgICAgKi8KICAgICAgICBjbG9uZSgpIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBNYXQzKHRoaXMubTAwLCB0aGlzLm0wMSwgdGhpcy5tMDIsIHRoaXMubTEwLCB0aGlzLm0xMSwgdGhpcy5tMTIsIHRoaXMubTIwLCB0aGlzLm0yMSwgdGhpcy5tMjIpOwogICAgICAgIH0KICAgICAgICAvLyAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KICAgICAgICAvLyBQZXJzaXN0ZW5jZQogICAgICAgIC8qKgogICAgICAgICAqIExvYWRzIHRoZSBzdGF0ZSBvZiB0aGUgdmFsdWUgZnJvbSBhIGJpbmFyeSByZWFkZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gcmVhZGVyIC0gVGhlIHJlYWRlciB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICByZWFkQmluYXJ5KHJlYWRlcikgewogICAgICAgICAgICBjb25zdCBkYXRhID0gcmVhZGVyLmxvYWRGbG9hdDMyQXJyYXkoOSk7CiAgICAgICAgICAgIHRoaXMuZnJvbUFycmF5KGRhdGEpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgdG9KU09OIG1ldGhvZCBlbmNvZGVzIHRoaXMgdHlwZSBhcyBhIGpzb24gb2JqZWN0IGZvciBwZXJzaXN0ZW5jZS4KICAgICAgICAgKi8KICAgICAgICB0b0pTT04oKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLmFzQXJyYXkoKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGZyb21KU09OIG1ldGhvZCBkZWNvZGVzIGEganNvbiBvYmplY3QgZm9yIHRoaXMgdHlwZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBqc29uIC0gVGhlIGpzb24gcGFyYW0uCiAgICAgICAgICovCiAgICAgICAgZnJvbUpTT04oanNvbikgewogICAgICAgICAgICB0aGlzLmZyb21BcnJheShqc29uKTsKICAgICAgICB9CiAgICAgICAgLy8gLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCiAgICAgICAgLy8gRGVidWdnaW5nCiAgICAgICAgLyoqCiAgICAgICAgICogQ29udmVydHMgdGhpcyBWZWMzIHRvIGEgc3RyaW5nIGluIEpTT04gZm9ybWF0LgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgdG9TdHJpbmcoKSB7CiAgICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuZXctY2FwCiAgICAgICAgICAgIHJldHVybiBTdHJpbmdGdW5jdGlvbnMuc3RyaW5naWZ5SlNPTldpdGhGaXhlZFByZWNpc2lvbih0aGlzLnRvSlNPTigpKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyBjdXJyZW50IE1hdGggdHlwZSBkYXRhIGFzIGFycmF5LiBPZnRlbiB1c2VkIHRvIHBhc3MgdHlwZXMgdG8gdGhlIEdQVS4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIHRoZSByZXN1bHQgYXMgYW4gYXJyYXkuCiAgICAgICAgICovCiAgICAgICAgYXNBcnJheSgpIHsKICAgICAgICAgICAgcmV0dXJuIFt0aGlzLm0wMCwgdGhpcy5tMDEsIHRoaXMubTAyLCB0aGlzLm0xMCwgdGhpcy5tMTEsIHRoaXMubTEyLCB0aGlzLm0yMCwgdGhpcy5tMjEsIHRoaXMubTIyXTsKICAgICAgICB9CiAgICAgICAgZnJvbUFycmF5KGFycmF5KSB7CiAgICAgICAgICAgIHRoaXMubTAwID0gYXJyYXlbMF07CiAgICAgICAgICAgIHRoaXMubTAxID0gYXJyYXlbMV07CiAgICAgICAgICAgIHRoaXMubTAyID0gYXJyYXlbMl07CiAgICAgICAgICAgIHRoaXMubTEwID0gYXJyYXlbM107CiAgICAgICAgICAgIHRoaXMubTExID0gYXJyYXlbNF07CiAgICAgICAgICAgIHRoaXMubTEyID0gYXJyYXlbNV07CiAgICAgICAgICAgIHRoaXMubTIwID0gYXJyYXlbNl07CiAgICAgICAgICAgIHRoaXMubTIxID0gYXJyYXlbN107CiAgICAgICAgICAgIHRoaXMubTIyID0gYXJyYXlbOF07CiAgICAgICAgfQogICAgfQoKICAgIC8qKgogICAgICogQSBjbGFzcyByZXByZXNlbnRpbmcgYSA0eDQgbWF0cml4LgogICAgICogVGhpcyBtYXRyaXggY2xhc3MgaXMgYmFzZWQgb24gR0xNLCBhbmQgaXMgY29sdW1uIG1ham9yLgogICAgICoKICAgICAqLwogICAgY2xhc3MgTWF0NCB7CiAgICAgICAgbTAwOwogICAgICAgIG0wMTsKICAgICAgICBtMDI7CiAgICAgICAgbTAzOwogICAgICAgIG0xMDsKICAgICAgICBtMTE7CiAgICAgICAgbTEyOwogICAgICAgIG0xMzsKICAgICAgICBtMjA7CiAgICAgICAgbTIxOwogICAgICAgIG0yMjsKICAgICAgICBtMjM7CiAgICAgICAgbTMwOwogICAgICAgIG0zMTsKICAgICAgICBtMzI7CiAgICAgICAgbTMzOwogICAgICAgIGNvbnN0cnVjdG9yKG0wMCA9IDEsIG0wMSA9IDAsIG0wMiA9IDAsIG0wMyA9IDAsIG0xMCA9IDAsIG0xMSA9IDEsIG0xMiA9IDAsIG0xMyA9IDAsIG0yMCA9IDAsIG0yMSA9IDAsIG0yMiA9IDEsIG0yMyA9IDAsIG0zMCA9IDAsIG0zMSA9IDAsIG0zMiA9IDAsIG0zMyA9IDEpIHsKICAgICAgICAgICAgdGhpcy5tMDAgPSBtMDA7CiAgICAgICAgICAgIHRoaXMubTAxID0gbTAxOwogICAgICAgICAgICB0aGlzLm0wMiA9IG0wMjsKICAgICAgICAgICAgdGhpcy5tMDMgPSBtMDM7CiAgICAgICAgICAgIHRoaXMubTEwID0gbTEwOwogICAgICAgICAgICB0aGlzLm0xMSA9IG0xMTsKICAgICAgICAgICAgdGhpcy5tMTIgPSBtMTI7CiAgICAgICAgICAgIHRoaXMubTEzID0gbTEzOwogICAgICAgICAgICB0aGlzLm0yMCA9IG0yMDsKICAgICAgICAgICAgdGhpcy5tMjEgPSBtMjE7CiAgICAgICAgICAgIHRoaXMubTIyID0gbTIyOwogICAgICAgICAgICB0aGlzLm0yMyA9IG0yMzsKICAgICAgICAgICAgdGhpcy5tMzAgPSBtMzA7CiAgICAgICAgICAgIHRoaXMubTMxID0gbTMxOwogICAgICAgICAgICB0aGlzLm0zMiA9IG0zMjsKICAgICAgICAgICAgdGhpcy5tMzMgPSBtMzM7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEdldHRlciBmb3IgdGhlIGB4YCBheGlzLgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgdGhlIGB4YCBheGlzIGFzIGEgVmVjMy4KICAgICAgICAgKi8KICAgICAgICBnZXQgeEF4aXMoKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgVmVjMyh0aGlzLm0wMCwgdGhpcy5tMDEsIHRoaXMubTAyKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU2V0dGVyIGZvciB0aGUgYHhgIGF4aXMuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gdmVjMyAtIFRoZSB2ZWMzIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHNldCB4QXhpcyh2ZWMzKSB7CiAgICAgICAgICAgIHRoaXMueEF4aXMuc2V0KHZlYzMueCwgdmVjMy55LCB2ZWMzLnopOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBHZXR0ZXIgZm9yIHRoZSBgeWAgYXhpcy4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIHRoZSBgeWAgYXhpcyBhcyBhIFZlYzMuCiAgICAgICAgICovCiAgICAgICAgZ2V0IHlBeGlzKCkgewogICAgICAgICAgICByZXR1cm4gbmV3IFZlYzModGhpcy5tMTAsIHRoaXMubTExLCB0aGlzLm0xMik7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFNldHRlciBmb3IgdGhlIGB5YCBheGlzLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHZlYzMgLSBUaGUgdmVjMyB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBzZXQgeUF4aXModmVjMykgewogICAgICAgICAgICB0aGlzLnlBeGlzLnNldCh2ZWMzLngsIHZlYzMueSwgdmVjMy56KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogR2V0dGVyIGZvciB0aGUgYHpgIGF4aXMuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyB0aGUgYHpgIGF4aXMgYXMgYSBWZWMzLgogICAgICAgICAqLwogICAgICAgIGdldCB6QXhpcygpIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBWZWMzKHRoaXMubTIwLCB0aGlzLm0yMSwgdGhpcy5tMjIpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTZXR0ZXIgZm9yIHRoZSBgemAgYXhpcy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB2ZWMzIC0gVGhlIHZlYzMgdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgc2V0IHpBeGlzKHZlYzMpIHsKICAgICAgICAgICAgdGhpcy56QXhpcy5zZXQodmVjMy54LCB2ZWMzLnksIHZlYzMueik7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEdldHRlciBmb3IgdGhlIHRyYW5zbGF0aW9uIG9mIHRoZSBtYXRyaXguIEFzc3VtZXMgdGhlIHRyYW5zbGF0aW9uIHZhbHVlcyBhcmUgMTIsIDEzLCAmIDE0LgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgdGhlIHRyYW5zbGF0aW9uLgogICAgICAgICAqLwogICAgICAgIGdldCB0cmFuc2xhdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBWZWMzKHRoaXMubTMwLCB0aGlzLm0zMSwgdGhpcy5tMzIpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTZXR0ZXIgZm9yIHRoZSB0cmFuc2xhdGlvbiBvZiB0aGUgbWF0cml4LiBBc3N1bWVzIHRoZSB0cmFuc2xhdGlvbiB2YWx1ZXMgYXJlIDEyLCAxMywgJiAxNC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB2ZWMzIC0gVGhlIHRyYW5zbGF0aW9uLgogICAgICAgICAqLwogICAgICAgIHNldCB0cmFuc2xhdGlvbih2ZWMzKSB7CiAgICAgICAgICAgIHRoaXMubTMwID0gdmVjMy54OwogICAgICAgICAgICB0aGlzLm0zMSA9IHZlYzMueTsKICAgICAgICAgICAgdGhpcy5tMzIgPSB2ZWMzLno7CiAgICAgICAgfQogICAgICAgIC8vIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCiAgICAgICAgLy8gU2V0dGVycwogICAgICAgIC8qKgogICAgICAgICAqIFNldHMgdGhlIHN0YXRlIG9mIHRoZSBNYXQ0IGNsYXNzCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gbTAwIC0gUm93IDAsIGNvbHVtbiAwLgogICAgICAgICAqIEBwYXJhbSBtMDEgLSBSb3cgMCwgY29sdW1uIDEuCiAgICAgICAgICogQHBhcmFtIG0wMiAtIFJvdyAwLCBjb2x1bW4gMi4KICAgICAgICAgKiBAcGFyYW0gbTAzIC0gUm93IDAsIGNvbHVtbiAzLgogICAgICAgICAqIEBwYXJhbSBtMTAgLSBSb3cgMSwgY29sdW1uIDAuCiAgICAgICAgICogQHBhcmFtIG0xMSAtIFJvdyAxLCBjb2x1bW4gMS4KICAgICAgICAgKiBAcGFyYW0gbTEyIC0gUm93IDEsIGNvbHVtbiAyLgogICAgICAgICAqIEBwYXJhbSBtMTMgLSBSb3cgMSwgY29sdW1uIDMuCiAgICAgICAgICogQHBhcmFtIG0yMCAtIFJvdyAyLCBjb2x1bW4gMC4KICAgICAgICAgKiBAcGFyYW0gbTIxIC0gUm93IDIsIGNvbHVtbiAxLgogICAgICAgICAqIEBwYXJhbSBtMjIgLSBSb3cgMiwgY29sdW1uIDIuCiAgICAgICAgICogQHBhcmFtIG0yMyAtIFJvdyAyLCBjb2x1bW4gMy4KICAgICAgICAgKiBAcGFyYW0gbTMwIC0gUm93IDMsIGNvbHVtbiAwLgogICAgICAgICAqIEBwYXJhbSBtMzEgLSBSb3cgMywgY29sdW1uIDEuCiAgICAgICAgICogQHBhcmFtIG0zMiAtIFJvdyAzLCBjb2x1bW4gMi4KICAgICAgICAgKiBAcGFyYW0gbTMzIC0gUm93IDMsIGNvbHVtbiAzLgogICAgICAgICAqLwogICAgICAgIHNldChtMDAgPSAxLCBtMDEgPSAwLCBtMDIgPSAwLCBtMDMgPSAwLCBtMTAgPSAwLCBtMTEgPSAxLCBtMTIgPSAwLCBtMTMgPSAwLCBtMjAgPSAwLCBtMjEgPSAwLCBtMjIgPSAxLCBtMjMgPSAwLCBtMzAgPSAwLCBtMzEgPSAwLCBtMzIgPSAwLCBtMzMgPSAxKSB7CiAgICAgICAgICAgIHRoaXMubTAwID0gbTAwOwogICAgICAgICAgICB0aGlzLm0wMSA9IG0wMTsKICAgICAgICAgICAgdGhpcy5tMDIgPSBtMDI7CiAgICAgICAgICAgIHRoaXMubTAzID0gbTAzOwogICAgICAgICAgICB0aGlzLm0xMCA9IG0xMDsKICAgICAgICAgICAgdGhpcy5tMTEgPSBtMTE7CiAgICAgICAgICAgIHRoaXMubTEyID0gbTEyOwogICAgICAgICAgICB0aGlzLm0xMyA9IG0xMzsKICAgICAgICAgICAgdGhpcy5tMjAgPSBtMjA7CiAgICAgICAgICAgIHRoaXMubTIxID0gbTIxOwogICAgICAgICAgICB0aGlzLm0yMiA9IG0yMjsKICAgICAgICAgICAgdGhpcy5tMjMgPSBtMjM7CiAgICAgICAgICAgIHRoaXMubTMwID0gbTMwOwogICAgICAgICAgICB0aGlzLm0zMSA9IG0zMTsKICAgICAgICAgICAgdGhpcy5tMzIgPSBtMzI7CiAgICAgICAgICAgIHRoaXMubTMzID0gbTMzOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTZXRzIHN0YXRlIG9mIHRoZSBNYXQ0IHdpdGggdGhlIGlkZW50aXR5ICBNYXRyaXgKICAgICAgICAgKi8KICAgICAgICBzZXRJZGVudGl0eSgpIHsKICAgICAgICAgICAgdGhpcy5zZXQoKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU2V0cyBzdGF0ZSBvZiB0aGUgTWF0NCBmcm9tIGFub3RoZXIgTWF0NAogICAgICAgICAqCiAgICAgICAgICogTm90ZTogd29ya3Mgd2l0aCBlaXRoZXIgTWF0MyBvciBNYXQ0LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIG1hdDQgLSBUaGUgbWF0NCB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBzZXRGcm9tTWF0NChtYXQ0KSB7CiAgICAgICAgICAgIHRoaXMubTAwID0gbWF0NC5tMDA7CiAgICAgICAgICAgIHRoaXMubTAxID0gbWF0NC5tMDE7CiAgICAgICAgICAgIHRoaXMubTAyID0gbWF0NC5tMDI7CiAgICAgICAgICAgIHRoaXMubTAzID0gbWF0NC5tMDM7CiAgICAgICAgICAgIHRoaXMubTEwID0gbWF0NC5tMTA7CiAgICAgICAgICAgIHRoaXMubTExID0gbWF0NC5tMTE7CiAgICAgICAgICAgIHRoaXMubTEyID0gbWF0NC5tMTI7CiAgICAgICAgICAgIHRoaXMubTEzID0gbWF0NC5tMTM7CiAgICAgICAgICAgIHRoaXMubTIwID0gbWF0NC5tMjA7CiAgICAgICAgICAgIHRoaXMubTIxID0gbWF0NC5tMjE7CiAgICAgICAgICAgIHRoaXMubTIyID0gbWF0NC5tMjI7CiAgICAgICAgICAgIHRoaXMubTIzID0gbWF0NC5tMjM7CiAgICAgICAgICAgIHRoaXMubTMwID0gbWF0NC5tMzA7CiAgICAgICAgICAgIHRoaXMubTMxID0gbWF0NC5tMzE7CiAgICAgICAgICAgIHRoaXMubTMyID0gbWF0NC5tMzI7CiAgICAgICAgICAgIHRoaXMubTMzID0gbWF0NC5tMzM7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbnZlcnRzIGEgTWF0NCB0byBhIE1hdDMuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyBhIG5ldyBNYXQzLgogICAgICAgICAqLwogICAgICAgIHRvTWF0MygpIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBNYXQzKHRoaXMubTAwLCB0aGlzLm0wMSwgdGhpcy5tMDIsIHRoaXMubTEwLCB0aGlzLm0xMSwgdGhpcy5tMTIsIHRoaXMubTIwLCB0aGlzLm0yMSwgdGhpcy5tMjIpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUcmFuc3Bvc2VzIChleGNoYW5nZXMgY29sdW1ucyB3aXRoIHJvd3MpIHRoaXMgbWF0cml4LgogICAgICAgICAqLwogICAgICAgIHRyYW5zcG9zZUluUGxhY2UoKSB7CiAgICAgICAgICAgIC8vIElmIHdlIGFyZSB0cmFuc3Bvc2luZyBvdXJzZWx2ZXMgd2UgY2FuIHNraXAgYSBmZXcgc3RlcHMgYnV0IGhhdmUgdG8gY2FjaGUgc29tZSB2YWx1ZXMKICAgICAgICAgICAgY29uc3QgYTAxID0gdGhpcy5tMDE7CiAgICAgICAgICAgIGNvbnN0IGEwMiA9IHRoaXMubTAyOwogICAgICAgICAgICBjb25zdCBhMDMgPSB0aGlzLm0wMzsKICAgICAgICAgICAgY29uc3QgYTEyID0gdGhpcy5tMTI7CiAgICAgICAgICAgIGNvbnN0IGExMyA9IHRoaXMubTEzOwogICAgICAgICAgICBjb25zdCBhMjMgPSB0aGlzLm0yMzsKICAgICAgICAgICAgdGhpcy5tMDEgPSB0aGlzLm0xMDsKICAgICAgICAgICAgdGhpcy5tMDIgPSB0aGlzLm0yMDsKICAgICAgICAgICAgdGhpcy5tMDMgPSB0aGlzLm0zMDsKICAgICAgICAgICAgdGhpcy5tMTAgPSBhMDE7CiAgICAgICAgICAgIHRoaXMubTEyID0gdGhpcy5tMjE7CiAgICAgICAgICAgIHRoaXMubTEzID0gdGhpcy5tMzE7CiAgICAgICAgICAgIHRoaXMubTIwID0gYTAyOwogICAgICAgICAgICB0aGlzLm0yMSA9IGExMjsKICAgICAgICAgICAgdGhpcy5tMjMgPSB0aGlzLm0zMjsKICAgICAgICAgICAgdGhpcy5tMzAgPSBhMDM7CiAgICAgICAgICAgIHRoaXMubTMxID0gYTEzOwogICAgICAgICAgICB0aGlzLm0zMiA9IGEyMzsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVHJhbnNwb3NlcyAoZXhjaGFuZ2VzIGNvbHVtbnMgd2l0aCByb3dzKSB0aGlzIG1hdHJpeAogICAgICAgICAqIGFuZCByZXR1cm5zIHRoZSByZXN1bHQgYXMgYSBuZXcgaW5zdGFuY2UuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJuIGEgbmV3IHRyYW5zcG9zZWQgTWF0NC4KICAgICAgICAgKi8KICAgICAgICB0cmFuc3Bvc2UoKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgTWF0NCh0aGlzLm0wMCwgdGhpcy5tMTAsIHRoaXMubTIwLCB0aGlzLm0zMCwgdGhpcy5tMDEsIHRoaXMubTExLCB0aGlzLm0yMSwgdGhpcy5tMzEsIHRoaXMubTAyLCB0aGlzLm0xMiwgdGhpcy5tMjIsIHRoaXMubTMyLCB0aGlzLm0wMywgdGhpcy5tMTMsIHRoaXMubTIzLCB0aGlzLm0zMyk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEludmVydHMgYSBNYXQ0IGFuZCByZXR1cm5zIHRoZSByZXN1bHQgYXMgYSBuZXcgaW5zdGFuY2UuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyBhIG5ldyBNYXQ0LgogICAgICAgICAqLwogICAgICAgIGludmVyc2UoKSB7CiAgICAgICAgICAgIGNvbnN0IGEwMCA9IHRoaXMubTAwOwogICAgICAgICAgICBjb25zdCBhMDEgPSB0aGlzLm0wMTsKICAgICAgICAgICAgY29uc3QgYTAyID0gdGhpcy5tMDI7CiAgICAgICAgICAgIGNvbnN0IGEwMyA9IHRoaXMubTAzOwogICAgICAgICAgICBjb25zdCBhMTAgPSB0aGlzLm0xMDsKICAgICAgICAgICAgY29uc3QgYTExID0gdGhpcy5tMTE7CiAgICAgICAgICAgIGNvbnN0IGExMiA9IHRoaXMubTEyOwogICAgICAgICAgICBjb25zdCBhMTMgPSB0aGlzLm0xMzsKICAgICAgICAgICAgY29uc3QgYTIwID0gdGhpcy5tMjA7CiAgICAgICAgICAgIGNvbnN0IGEyMSA9IHRoaXMubTIxOwogICAgICAgICAgICBjb25zdCBhMjIgPSB0aGlzLm0yMjsKICAgICAgICAgICAgY29uc3QgYTIzID0gdGhpcy5tMjM7CiAgICAgICAgICAgIGNvbnN0IGEzMCA9IHRoaXMubTMwOwogICAgICAgICAgICBjb25zdCBhMzEgPSB0aGlzLm0zMTsKICAgICAgICAgICAgY29uc3QgYTMyID0gdGhpcy5tMzI7CiAgICAgICAgICAgIGNvbnN0IGEzMyA9IHRoaXMubTMzOwogICAgICAgICAgICBjb25zdCBiMDAgPSBhMDAgKiBhMTEgLSBhMDEgKiBhMTA7CiAgICAgICAgICAgIGNvbnN0IGIwMSA9IGEwMCAqIGExMiAtIGEwMiAqIGExMDsKICAgICAgICAgICAgY29uc3QgYjAyID0gYTAwICogYTEzIC0gYTAzICogYTEwOwogICAgICAgICAgICBjb25zdCBiMDMgPSBhMDEgKiBhMTIgLSBhMDIgKiBhMTE7CiAgICAgICAgICAgIGNvbnN0IGIwNCA9IGEwMSAqIGExMyAtIGEwMyAqIGExMTsKICAgICAgICAgICAgY29uc3QgYjA1ID0gYTAyICogYTEzIC0gYTAzICogYTEyOwogICAgICAgICAgICBjb25zdCBiMDYgPSBhMjAgKiBhMzEgLSBhMjEgKiBhMzA7CiAgICAgICAgICAgIGNvbnN0IGIwNyA9IGEyMCAqIGEzMiAtIGEyMiAqIGEzMDsKICAgICAgICAgICAgY29uc3QgYjA4ID0gYTIwICogYTMzIC0gYTIzICogYTMwOwogICAgICAgICAgICBjb25zdCBiMDkgPSBhMjEgKiBhMzIgLSBhMjIgKiBhMzE7CiAgICAgICAgICAgIGNvbnN0IGIxMCA9IGEyMSAqIGEzMyAtIGEyMyAqIGEzMTsKICAgICAgICAgICAgY29uc3QgYjExID0gYTIyICogYTMzIC0gYTIzICogYTMyOwogICAgICAgICAgICAvLyBDYWxjdWxhdGUgdGhlIGRldGVybWluYW50CiAgICAgICAgICAgIGxldCBkZXQgPSBiMDAgKiBiMTEgLSBiMDEgKiBiMTAgKyBiMDIgKiBiMDkgKyBiMDMgKiBiMDggLSBiMDQgKiBiMDcgKyBiMDUgKiBiMDY7CiAgICAgICAgICAgIGlmICghZGV0KSB7CiAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oJ1VuYWJsZSB0byBpbnZlcnQgTWF0NCcpOwogICAgICAgICAgICAgICAgcmV0dXJuIHRoaXM7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZGV0ID0gMS4wIC8gZGV0OwogICAgICAgICAgICByZXR1cm4gbmV3IE1hdDQoKGExMSAqIGIxMSAtIGExMiAqIGIxMCArIGExMyAqIGIwOSkgKiBkZXQsIChhMDIgKiBiMTAgLSBhMDEgKiBiMTEgLSBhMDMgKiBiMDkpICogZGV0LCAoYTMxICogYjA1IC0gYTMyICogYjA0ICsgYTMzICogYjAzKSAqIGRldCwgKGEyMiAqIGIwNCAtIGEyMSAqIGIwNSAtIGEyMyAqIGIwMykgKiBkZXQsIChhMTIgKiBiMDggLSBhMTAgKiBiMTEgLSBhMTMgKiBiMDcpICogZGV0LCAoYTAwICogYjExIC0gYTAyICogYjA4ICsgYTAzICogYjA3KSAqIGRldCwgKGEzMiAqIGIwMiAtIGEzMCAqIGIwNSAtIGEzMyAqIGIwMSkgKiBkZXQsIChhMjAgKiBiMDUgLSBhMjIgKiBiMDIgKyBhMjMgKiBiMDEpICogZGV0LCAoYTEwICogYjEwIC0gYTExICogYjA4ICsgYTEzICogYjA2KSAqIGRldCwgKGEwMSAqIGIwOCAtIGEwMCAqIGIxMCAtIGEwMyAqIGIwNikgKiBkZXQsIChhMzAgKiBiMDQgLSBhMzEgKiBiMDIgKyBhMzMgKiBiMDApICogZGV0LCAoYTIxICogYjAyIC0gYTIwICogYjA0IC0gYTIzICogYjAwKSAqIGRldCwgKGExMSAqIGIwNyAtIGExMCAqIGIwOSAtIGExMiAqIGIwNikgKiBkZXQsIChhMDAgKiBiMDkgLSBhMDEgKiBiMDcgKyBhMDIgKiBiMDYpICogZGV0LCAoYTMxICogYjAxIC0gYTMwICogYjAzIC0gYTMyICogYjAwKSAqIGRldCwgKGEyMCAqIGIwMyAtIGEyMSAqIGIwMSArIGEyMiAqIGIwMCkgKiBkZXQpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBJbnZlcnRzIGEgTWF0NC4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGludmVydEluUGxhY2UoKSB7CiAgICAgICAgICAgIGNvbnN0IGEwMCA9IHRoaXMubTAwOwogICAgICAgICAgICBjb25zdCBhMDEgPSB0aGlzLm0wMTsKICAgICAgICAgICAgY29uc3QgYTAyID0gdGhpcy5tMDI7CiAgICAgICAgICAgIGNvbnN0IGEwMyA9IHRoaXMubTAzOwogICAgICAgICAgICBjb25zdCBhMTAgPSB0aGlzLm0xMDsKICAgICAgICAgICAgY29uc3QgYTExID0gdGhpcy5tMTE7CiAgICAgICAgICAgIGNvbnN0IGExMiA9IHRoaXMubTEyOwogICAgICAgICAgICBjb25zdCBhMTMgPSB0aGlzLm0xMzsKICAgICAgICAgICAgY29uc3QgYTIwID0gdGhpcy5tMjA7CiAgICAgICAgICAgIGNvbnN0IGEyMSA9IHRoaXMubTIxOwogICAgICAgICAgICBjb25zdCBhMjIgPSB0aGlzLm0yMjsKICAgICAgICAgICAgY29uc3QgYTIzID0gdGhpcy5tMjM7CiAgICAgICAgICAgIGNvbnN0IGEzMCA9IHRoaXMubTMwOwogICAgICAgICAgICBjb25zdCBhMzEgPSB0aGlzLm0zMTsKICAgICAgICAgICAgY29uc3QgYTMyID0gdGhpcy5tMzI7CiAgICAgICAgICAgIGNvbnN0IGEzMyA9IHRoaXMubTMzOwogICAgICAgICAgICBjb25zdCBiMDAgPSBhMDAgKiBhMTEgLSBhMDEgKiBhMTA7CiAgICAgICAgICAgIGNvbnN0IGIwMSA9IGEwMCAqIGExMiAtIGEwMiAqIGExMDsKICAgICAgICAgICAgY29uc3QgYjAyID0gYTAwICogYTEzIC0gYTAzICogYTEwOwogICAgICAgICAgICBjb25zdCBiMDMgPSBhMDEgKiBhMTIgLSBhMDIgKiBhMTE7CiAgICAgICAgICAgIGNvbnN0IGIwNCA9IGEwMSAqIGExMyAtIGEwMyAqIGExMTsKICAgICAgICAgICAgY29uc3QgYjA1ID0gYTAyICogYTEzIC0gYTAzICogYTEyOwogICAgICAgICAgICBjb25zdCBiMDYgPSBhMjAgKiBhMzEgLSBhMjEgKiBhMzA7CiAgICAgICAgICAgIGNvbnN0IGIwNyA9IGEyMCAqIGEzMiAtIGEyMiAqIGEzMDsKICAgICAgICAgICAgY29uc3QgYjA4ID0gYTIwICogYTMzIC0gYTIzICogYTMwOwogICAgICAgICAgICBjb25zdCBiMDkgPSBhMjEgKiBhMzIgLSBhMjIgKiBhMzE7CiAgICAgICAgICAgIGNvbnN0IGIxMCA9IGEyMSAqIGEzMyAtIGEyMyAqIGEzMTsKICAgICAgICAgICAgY29uc3QgYjExID0gYTIyICogYTMzIC0gYTIzICogYTMyOwogICAgICAgICAgICAvLyBDYWxjdWxhdGUgdGhlIGRldGVybWluYW50CiAgICAgICAgICAgIGxldCBkZXQgPSBiMDAgKiBiMTEgLSBiMDEgKiBiMTAgKyBiMDIgKiBiMDkgKyBiMDMgKiBiMDggLSBiMDQgKiBiMDcgKyBiMDUgKiBiMDY7CiAgICAgICAgICAgIGlmICghZGV0KSB7CiAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oJ1VuYWJsZSB0byBpbnZlcnQgTWF0NCcpOwogICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGRldCA9IDEuMCAvIGRldDsKICAgICAgICAgICAgdGhpcy5zZXQoKGExMSAqIGIxMSAtIGExMiAqIGIxMCArIGExMyAqIGIwOSkgKiBkZXQsIChhMDIgKiBiMTAgLSBhMDEgKiBiMTEgLSBhMDMgKiBiMDkpICogZGV0LCAoYTMxICogYjA1IC0gYTMyICogYjA0ICsgYTMzICogYjAzKSAqIGRldCwgKGEyMiAqIGIwNCAtIGEyMSAqIGIwNSAtIGEyMyAqIGIwMykgKiBkZXQsIChhMTIgKiBiMDggLSBhMTAgKiBiMTEgLSBhMTMgKiBiMDcpICogZGV0LCAoYTAwICogYjExIC0gYTAyICogYjA4ICsgYTAzICogYjA3KSAqIGRldCwgKGEzMiAqIGIwMiAtIGEzMCAqIGIwNSAtIGEzMyAqIGIwMSkgKiBkZXQsIChhMjAgKiBiMDUgLSBhMjIgKiBiMDIgKyBhMjMgKiBiMDEpICogZGV0LCAoYTEwICogYjEwIC0gYTExICogYjA4ICsgYTEzICogYjA2KSAqIGRldCwgKGEwMSAqIGIwOCAtIGEwMCAqIGIxMCAtIGEwMyAqIGIwNikgKiBkZXQsIChhMzAgKiBiMDQgLSBhMzEgKiBiMDIgKyBhMzMgKiBiMDApICogZGV0LCAoYTIxICogYjAyIC0gYTIwICogYjA0IC0gYTIzICogYjAwKSAqIGRldCwgKGExMSAqIGIwNyAtIGExMCAqIGIwOSAtIGExMiAqIGIwNikgKiBkZXQsIChhMDAgKiBiMDkgLSBhMDEgKiBiMDcgKyBhMDIgKiBiMDYpICogZGV0LCAoYTMxICogYjAxIC0gYTMwICogYjAzIC0gYTMyICogYjAwKSAqIGRldCwgKGEyMCAqIGIwMyAtIGEyMSAqIGIwMSArIGEyMiAqIGIwMCkgKiBkZXQpOwogICAgICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU2V0cyB0aGlzIG1hdHJpeCBhcyB0aGUgaW52ZXJzZSBvZiB0aGUgZ2l2ZW4gTWF0NC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBtYXQ0IC0gVGhlIG1hdDQgdmFsdWUuCiAgICAgICAgICogQHJldHVybiAtIEluIGNhc2UgdGhlIGBkZXRlcm1pbmFudGAgY2FuJ3QgYmUgY2FsY3VsYXRlZCwgYSBgbnVsbGAgd2lsbCBiZSByZXR1cm5lZCwgb3RoZXJ3aXNlLCBub3RoaW5nIGlzIHJldHVybmVkCiAgICAgICAgICovCiAgICAgICAgc2V0SW52ZXJzZShtYXQ0KSB7CiAgICAgICAgICAgIGNvbnN0IGEwMCA9IG1hdDQubTAwOwogICAgICAgICAgICBjb25zdCBhMDEgPSBtYXQ0Lm0wMTsKICAgICAgICAgICAgY29uc3QgYTAyID0gbWF0NC5tMDI7CiAgICAgICAgICAgIGNvbnN0IGEwMyA9IG1hdDQubTAzOwogICAgICAgICAgICBjb25zdCBhMTAgPSBtYXQ0Lm0xMDsKICAgICAgICAgICAgY29uc3QgYTExID0gbWF0NC5tMTE7CiAgICAgICAgICAgIGNvbnN0IGExMiA9IG1hdDQubTEyOwogICAgICAgICAgICBjb25zdCBhMTMgPSBtYXQ0Lm0xMzsKICAgICAgICAgICAgY29uc3QgYTIwID0gbWF0NC5tMjA7CiAgICAgICAgICAgIGNvbnN0IGEyMSA9IG1hdDQubTIxOwogICAgICAgICAgICBjb25zdCBhMjIgPSBtYXQ0Lm0yMjsKICAgICAgICAgICAgY29uc3QgYTIzID0gbWF0NC5tMjM7CiAgICAgICAgICAgIGNvbnN0IGEzMCA9IG1hdDQubTMwOwogICAgICAgICAgICBjb25zdCBhMzEgPSBtYXQ0Lm0zMTsKICAgICAgICAgICAgY29uc3QgYTMyID0gbWF0NC5tMzI7CiAgICAgICAgICAgIGNvbnN0IGEzMyA9IG1hdDQubTMzOwogICAgICAgICAgICBjb25zdCBiMDAgPSBhMDAgKiBhMTEgLSBhMDEgKiBhMTA7CiAgICAgICAgICAgIGNvbnN0IGIwMSA9IGEwMCAqIGExMiAtIGEwMiAqIGExMDsKICAgICAgICAgICAgY29uc3QgYjAyID0gYTAwICogYTEzIC0gYTAzICogYTEwOwogICAgICAgICAgICBjb25zdCBiMDMgPSBhMDEgKiBhMTIgLSBhMDIgKiBhMTE7CiAgICAgICAgICAgIGNvbnN0IGIwNCA9IGEwMSAqIGExMyAtIGEwMyAqIGExMTsKICAgICAgICAgICAgY29uc3QgYjA1ID0gYTAyICogYTEzIC0gYTAzICogYTEyOwogICAgICAgICAgICBjb25zdCBiMDYgPSBhMjAgKiBhMzEgLSBhMjEgKiBhMzA7CiAgICAgICAgICAgIGNvbnN0IGIwNyA9IGEyMCAqIGEzMiAtIGEyMiAqIGEzMDsKICAgICAgICAgICAgY29uc3QgYjA4ID0gYTIwICogYTMzIC0gYTIzICogYTMwOwogICAgICAgICAgICBjb25zdCBiMDkgPSBhMjEgKiBhMzIgLSBhMjIgKiBhMzE7CiAgICAgICAgICAgIGNvbnN0IGIxMCA9IGEyMSAqIGEzMyAtIGEyMyAqIGEzMTsKICAgICAgICAgICAgY29uc3QgYjExID0gYTIyICogYTMzIC0gYTIzICogYTMyOwogICAgICAgICAgICAvLyBDYWxjdWxhdGUgdGhlIGRldGVybWluYW50CiAgICAgICAgICAgIGxldCBkZXQgPSBiMDAgKiBiMTEgLSBiMDEgKiBiMTAgKyBiMDIgKiBiMDkgKyBiMDMgKiBiMDggLSBiMDQgKiBiMDcgKyBiMDUgKiBiMDY7CiAgICAgICAgICAgIGlmICghZGV0KSB7CiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1VuYWJsZSB0byBpbnZlcnQgTWF0NCcpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGRldCA9IDEuMCAvIGRldDsKICAgICAgICAgICAgdGhpcy5zZXQoKGExMSAqIGIxMSAtIGExMiAqIGIxMCArIGExMyAqIGIwOSkgKiBkZXQsIChhMDIgKiBiMTAgLSBhMDEgKiBiMTEgLSBhMDMgKiBiMDkpICogZGV0LCAoYTMxICogYjA1IC0gYTMyICogYjA0ICsgYTMzICogYjAzKSAqIGRldCwgKGEyMiAqIGIwNCAtIGEyMSAqIGIwNSAtIGEyMyAqIGIwMykgKiBkZXQsIChhMTIgKiBiMDggLSBhMTAgKiBiMTEgLSBhMTMgKiBiMDcpICogZGV0LCAoYTAwICogYjExIC0gYTAyICogYjA4ICsgYTAzICogYjA3KSAqIGRldCwgKGEzMiAqIGIwMiAtIGEzMCAqIGIwNSAtIGEzMyAqIGIwMSkgKiBkZXQsIChhMjAgKiBiMDUgLSBhMjIgKiBiMDIgKyBhMjMgKiBiMDEpICogZGV0LCAoYTEwICogYjEwIC0gYTExICogYjA4ICsgYTEzICogYjA2KSAqIGRldCwgKGEwMSAqIGIwOCAtIGEwMCAqIGIxMCAtIGEwMyAqIGIwNikgKiBkZXQsIChhMzAgKiBiMDQgLSBhMzEgKiBiMDIgKyBhMzMgKiBiMDApICogZGV0LCAoYTIxICogYjAyIC0gYTIwICogYjA0IC0gYTIzICogYjAwKSAqIGRldCwgKGExMSAqIGIwNyAtIGExMCAqIGIwOSAtIGExMiAqIGIwNikgKiBkZXQsIChhMDAgKiBiMDkgLSBhMDEgKiBiMDcgKyBhMDIgKiBiMDYpICogZGV0LCAoYTMxICogYjAxIC0gYTMwICogYjAzIC0gYTMyICogYjAwKSAqIGRldCwgKGEyMCAqIGIwMyAtIGEyMSAqIGIwMSArIGEyMiAqIGIwMCkgKiBkZXQpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBNdWx0aXBsaWVzIHR3byBNYXQ0cyBhbmQgcmV0dXJucyB0aGUgcmVzdWx0IGFzIGEgbmV3IGluc3RhbmNlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIG90aGVyIC0gVGhlIG90aGVyIE1hdDQgdG8gbXVsdGlwbHkgd2l0aC4KICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyBhIG5ldyBNYXQ0LgogICAgICAgICAqLwogICAgICAgIG11bHRpcGx5KG90aGVyKSB7CiAgICAgICAgICAgIGNvbnN0IGEwMCA9IHRoaXMubTAwOwogICAgICAgICAgICBjb25zdCBhMDEgPSB0aGlzLm0wMTsKICAgICAgICAgICAgY29uc3QgYTAyID0gdGhpcy5tMDI7CiAgICAgICAgICAgIGNvbnN0IGEwMyA9IHRoaXMubTAzOwogICAgICAgICAgICBjb25zdCBhMTAgPSB0aGlzLm0xMDsKICAgICAgICAgICAgY29uc3QgYTExID0gdGhpcy5tMTE7CiAgICAgICAgICAgIGNvbnN0IGExMiA9IHRoaXMubTEyOwogICAgICAgICAgICBjb25zdCBhMTMgPSB0aGlzLm0xMzsKICAgICAgICAgICAgY29uc3QgYTIwID0gdGhpcy5tMjA7CiAgICAgICAgICAgIGNvbnN0IGEyMSA9IHRoaXMubTIxOwogICAgICAgICAgICBjb25zdCBhMjIgPSB0aGlzLm0yMjsKICAgICAgICAgICAgY29uc3QgYTIzID0gdGhpcy5tMjM7CiAgICAgICAgICAgIGNvbnN0IGEzMCA9IHRoaXMubTMwOwogICAgICAgICAgICBjb25zdCBhMzEgPSB0aGlzLm0zMTsKICAgICAgICAgICAgY29uc3QgYTMyID0gdGhpcy5tMzI7CiAgICAgICAgICAgIGNvbnN0IGEzMyA9IHRoaXMubTMzOwogICAgICAgICAgICAvLyBDYWNoZSBvbmx5IHRoZSBjdXJyZW50IGxpbmUgb2YgdGhlIHNlY29uZCBtYXRyaXgKICAgICAgICAgICAgY29uc3QgYiA9IG90aGVyLmFzQXJyYXkoKTsKICAgICAgICAgICAgbGV0IGIwID0gYlswXTsKICAgICAgICAgICAgbGV0IGIxID0gYlsxXTsKICAgICAgICAgICAgbGV0IGIyID0gYlsyXTsKICAgICAgICAgICAgbGV0IGIzID0gYlszXTsKICAgICAgICAgICAgY29uc3QgcmVzdWx0ID0gbmV3IE1hdDQoKTsKICAgICAgICAgICAgcmVzdWx0Lm0wMCA9IGIwICogYTAwICsgYjEgKiBhMTAgKyBiMiAqIGEyMCArIGIzICogYTMwOwogICAgICAgICAgICByZXN1bHQubTAxID0gYjAgKiBhMDEgKyBiMSAqIGExMSArIGIyICogYTIxICsgYjMgKiBhMzE7CiAgICAgICAgICAgIHJlc3VsdC5tMDIgPSBiMCAqIGEwMiArIGIxICogYTEyICsgYjIgKiBhMjIgKyBiMyAqIGEzMjsKICAgICAgICAgICAgcmVzdWx0Lm0wMyA9IGIwICogYTAzICsgYjEgKiBhMTMgKyBiMiAqIGEyMyArIGIzICogYTMzOwogICAgICAgICAgICBiMCA9IGJbNF07CiAgICAgICAgICAgIGIxID0gYls1XTsKICAgICAgICAgICAgYjIgPSBiWzZdOwogICAgICAgICAgICBiMyA9IGJbN107CiAgICAgICAgICAgIHJlc3VsdC5tMTAgPSBiMCAqIGEwMCArIGIxICogYTEwICsgYjIgKiBhMjAgKyBiMyAqIGEzMDsKICAgICAgICAgICAgcmVzdWx0Lm0xMSA9IGIwICogYTAxICsgYjEgKiBhMTEgKyBiMiAqIGEyMSArIGIzICogYTMxOwogICAgICAgICAgICByZXN1bHQubTEyID0gYjAgKiBhMDIgKyBiMSAqIGExMiArIGIyICogYTIyICsgYjMgKiBhMzI7CiAgICAgICAgICAgIHJlc3VsdC5tMTMgPSBiMCAqIGEwMyArIGIxICogYTEzICsgYjIgKiBhMjMgKyBiMyAqIGEzMzsKICAgICAgICAgICAgYjAgPSBiWzhdOwogICAgICAgICAgICBiMSA9IGJbOV07CiAgICAgICAgICAgIGIyID0gYlsxMF07CiAgICAgICAgICAgIGIzID0gYlsxMV07CiAgICAgICAgICAgIHJlc3VsdC5tMjAgPSBiMCAqIGEwMCArIGIxICogYTEwICsgYjIgKiBhMjAgKyBiMyAqIGEzMDsKICAgICAgICAgICAgcmVzdWx0Lm0yMSA9IGIwICogYTAxICsgYjEgKiBhMTEgKyBiMiAqIGEyMSArIGIzICogYTMxOwogICAgICAgICAgICByZXN1bHQubTIyID0gYjAgKiBhMDIgKyBiMSAqIGExMiArIGIyICogYTIyICsgYjMgKiBhMzI7CiAgICAgICAgICAgIHJlc3VsdC5tMjMgPSBiMCAqIGEwMyArIGIxICogYTEzICsgYjIgKiBhMjMgKyBiMyAqIGEzMzsKICAgICAgICAgICAgYjAgPSBiWzEyXTsKICAgICAgICAgICAgYjEgPSBiWzEzXTsKICAgICAgICAgICAgYjIgPSBiWzE0XTsKICAgICAgICAgICAgYjMgPSBiWzE1XTsKICAgICAgICAgICAgcmVzdWx0Lm0zMCA9IGIwICogYTAwICsgYjEgKiBhMTAgKyBiMiAqIGEyMCArIGIzICogYTMwOwogICAgICAgICAgICByZXN1bHQubTMxID0gYjAgKiBhMDEgKyBiMSAqIGExMSArIGIyICogYTIxICsgYjMgKiBhMzE7CiAgICAgICAgICAgIHJlc3VsdC5tMzIgPSBiMCAqIGEwMiArIGIxICogYTEyICsgYjIgKiBhMjIgKyBiMyAqIGEzMjsKICAgICAgICAgICAgcmVzdWx0Lm0zMyA9IGIwICogYTAzICsgYjEgKiBhMTMgKyBiMiAqIGEyMyArIGIzICogYTMzOwogICAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBNdWx0aXBsaWVzIHR3byBNYXQ0cyBpbiBwbGFjZSBleHBsaWNpdGx5IG5vdCB1c2luZyBTSU1ELgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIG90aGVyIC0gVGhlIG90aGVyIE1hdDQgdG8gbXVsdGlwbHkgd2l0aC4KICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyBhIG5ldyBNYXQ0LgogICAgICAgICAqLwogICAgICAgIG11bHRpcGx5SW5QbGFjZShvdGhlcikgewogICAgICAgICAgICBjb25zdCBhID0gdGhpcy5hc0FycmF5KCk7CiAgICAgICAgICAgIGNvbnN0IGEwMCA9IGFbMF07CiAgICAgICAgICAgIGNvbnN0IGEwMSA9IGFbMV07CiAgICAgICAgICAgIGNvbnN0IGEwMiA9IGFbMl07CiAgICAgICAgICAgIGNvbnN0IGEwMyA9IGFbM107CiAgICAgICAgICAgIGNvbnN0IGExMCA9IGFbNF07CiAgICAgICAgICAgIGNvbnN0IGExMSA9IGFbNV07CiAgICAgICAgICAgIGNvbnN0IGExMiA9IGFbNl07CiAgICAgICAgICAgIGNvbnN0IGExMyA9IGFbN107CiAgICAgICAgICAgIGNvbnN0IGEyMCA9IGFbOF07CiAgICAgICAgICAgIGNvbnN0IGEyMSA9IGFbOV07CiAgICAgICAgICAgIGNvbnN0IGEyMiA9IGFbMTBdOwogICAgICAgICAgICBjb25zdCBhMjMgPSBhWzExXTsKICAgICAgICAgICAgY29uc3QgYTMwID0gYVsxMl07CiAgICAgICAgICAgIGNvbnN0IGEzMSA9IGFbMTNdOwogICAgICAgICAgICBjb25zdCBhMzIgPSBhWzE0XTsKICAgICAgICAgICAgY29uc3QgYTMzID0gYVsxNV07CiAgICAgICAgICAgIC8vIENhY2hlIG9ubHkgdGhlIGN1cnJlbnQgbGluZSBvZiB0aGUgc2Vjb25kIG1hdHJpeAogICAgICAgICAgICBjb25zdCBiID0gb3RoZXIuYXNBcnJheSgpOwogICAgICAgICAgICBsZXQgYjAgPSBiWzBdOwogICAgICAgICAgICBsZXQgYjEgPSBiWzFdOwogICAgICAgICAgICBsZXQgYjIgPSBiWzJdOwogICAgICAgICAgICBsZXQgYjMgPSBiWzNdOwogICAgICAgICAgICB0aGlzLm0wMCA9IGIwICogYTAwICsgYjEgKiBhMTAgKyBiMiAqIGEyMCArIGIzICogYTMwOwogICAgICAgICAgICB0aGlzLm0wMSA9IGIwICogYTAxICsgYjEgKiBhMTEgKyBiMiAqIGEyMSArIGIzICogYTMxOwogICAgICAgICAgICB0aGlzLm0wMiA9IGIwICogYTAyICsgYjEgKiBhMTIgKyBiMiAqIGEyMiArIGIzICogYTMyOwogICAgICAgICAgICB0aGlzLm0wMyA9IGIwICogYTAzICsgYjEgKiBhMTMgKyBiMiAqIGEyMyArIGIzICogYTMzOwogICAgICAgICAgICBiMCA9IGJbNF07CiAgICAgICAgICAgIGIxID0gYls1XTsKICAgICAgICAgICAgYjIgPSBiWzZdOwogICAgICAgICAgICBiMyA9IGJbN107CiAgICAgICAgICAgIHRoaXMubTEwID0gYjAgKiBhMDAgKyBiMSAqIGExMCArIGIyICogYTIwICsgYjMgKiBhMzA7CiAgICAgICAgICAgIHRoaXMubTExID0gYjAgKiBhMDEgKyBiMSAqIGExMSArIGIyICogYTIxICsgYjMgKiBhMzE7CiAgICAgICAgICAgIHRoaXMubTEyID0gYjAgKiBhMDIgKyBiMSAqIGExMiArIGIyICogYTIyICsgYjMgKiBhMzI7CiAgICAgICAgICAgIHRoaXMubTEzID0gYjAgKiBhMDMgKyBiMSAqIGExMyArIGIyICogYTIzICsgYjMgKiBhMzM7CiAgICAgICAgICAgIGIwID0gYls4XTsKICAgICAgICAgICAgYjEgPSBiWzldOwogICAgICAgICAgICBiMiA9IGJbMTBdOwogICAgICAgICAgICBiMyA9IGJbMTFdOwogICAgICAgICAgICB0aGlzLm0yMCA9IGIwICogYTAwICsgYjEgKiBhMTAgKyBiMiAqIGEyMCArIGIzICogYTMwOwogICAgICAgICAgICB0aGlzLm0yMSA9IGIwICogYTAxICsgYjEgKiBhMTEgKyBiMiAqIGEyMSArIGIzICogYTMxOwogICAgICAgICAgICB0aGlzLm0yMiA9IGIwICogYTAyICsgYjEgKiBhMTIgKyBiMiAqIGEyMiArIGIzICogYTMyOwogICAgICAgICAgICB0aGlzLm0yMyA9IGIwICogYTAzICsgYjEgKiBhMTMgKyBiMiAqIGEyMyArIGIzICogYTMzOwogICAgICAgICAgICBiMCA9IGJbMTJdOwogICAgICAgICAgICBiMSA9IGJbMTNdOwogICAgICAgICAgICBiMiA9IGJbMTRdOwogICAgICAgICAgICBiMyA9IGJbMTVdOwogICAgICAgICAgICB0aGlzLm0zMCA9IGIwICogYTAwICsgYjEgKiBhMTAgKyBiMiAqIGEyMCArIGIzICogYTMwOwogICAgICAgICAgICB0aGlzLm0zMSA9IGIwICogYTAxICsgYjEgKiBhMTEgKyBiMiAqIGEyMSArIGIzICogYTMxOwogICAgICAgICAgICB0aGlzLm0zMiA9IGIwICogYTAyICsgYjEgKiBhMTIgKyBiMiAqIGEyMiArIGIzICogYTMyOwogICAgICAgICAgICB0aGlzLm0zMyA9IGIwICogYTAzICsgYjEgKiBhMTMgKyBiMiAqIGEyMyArIGIzICogYTMzOwogICAgICAgICAgICByZXR1cm4gdGhpczsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUG9zdCBtdWx0aXBsaWVzIHR3byBNYXQ0cyBpbiBwbGFjZSBleHBsaWNpdGx5IG5vdCB1c2luZyBTSU1ELgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIG90aGVyIC0gVGhlIG90aGVyIE1hdDQgdG8gbXVsdGlwbHkgd2l0aC4KICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyB0aGUgcmVzdWx0IGFzIGEgbmV3IE1hdDQuCiAgICAgICAgICovCiAgICAgICAgcG9zdE11bHRpcGx5SW5QbGFjZShvdGhlcikgewogICAgICAgICAgICBjb25zdCBhID0gb3RoZXIuYXNBcnJheSgpOwogICAgICAgICAgICBjb25zdCBhMDAgPSBhWzBdOwogICAgICAgICAgICBjb25zdCBhMDEgPSBhWzFdOwogICAgICAgICAgICBjb25zdCBhMDIgPSBhWzJdOwogICAgICAgICAgICBjb25zdCBhMDMgPSBhWzNdOwogICAgICAgICAgICBjb25zdCBhMTAgPSBhWzRdOwogICAgICAgICAgICBjb25zdCBhMTEgPSBhWzVdOwogICAgICAgICAgICBjb25zdCBhMTIgPSBhWzZdOwogICAgICAgICAgICBjb25zdCBhMTMgPSBhWzddOwogICAgICAgICAgICBjb25zdCBhMjAgPSBhWzhdOwogICAgICAgICAgICBjb25zdCBhMjEgPSBhWzldOwogICAgICAgICAgICBjb25zdCBhMjIgPSBhWzEwXTsKICAgICAgICAgICAgY29uc3QgYTIzID0gYVsxMV07CiAgICAgICAgICAgIGNvbnN0IGEzMCA9IGFbMTJdOwogICAgICAgICAgICBjb25zdCBhMzEgPSBhWzEzXTsKICAgICAgICAgICAgY29uc3QgYTMyID0gYVsxNF07CiAgICAgICAgICAgIGNvbnN0IGEzMyA9IGFbMTVdOwogICAgICAgICAgICAvLyBDYWNoZSBvbmx5IHRoZSBjdXJyZW50IGxpbmUgb2YgdGhlIHNlY29uZCBtYXRyaXgKICAgICAgICAgICAgY29uc3QgYiA9IHRoaXMuYXNBcnJheSgpOwogICAgICAgICAgICBsZXQgYjAgPSBiWzBdOwogICAgICAgICAgICBsZXQgYjEgPSBiWzFdOwogICAgICAgICAgICBsZXQgYjIgPSBiWzJdOwogICAgICAgICAgICBsZXQgYjMgPSBiWzNdOwogICAgICAgICAgICB0aGlzLm0wMCA9IGIwICogYTAwICsgYjEgKiBhMTAgKyBiMiAqIGEyMCArIGIzICogYTMwOwogICAgICAgICAgICB0aGlzLm0wMSA9IGIwICogYTAxICsgYjEgKiBhMTEgKyBiMiAqIGEyMSArIGIzICogYTMxOwogICAgICAgICAgICB0aGlzLm0wMiA9IGIwICogYTAyICsgYjEgKiBhMTIgKyBiMiAqIGEyMiArIGIzICogYTMyOwogICAgICAgICAgICB0aGlzLm0wMyA9IGIwICogYTAzICsgYjEgKiBhMTMgKyBiMiAqIGEyMyArIGIzICogYTMzOwogICAgICAgICAgICBiMCA9IGJbNF07CiAgICAgICAgICAgIGIxID0gYls1XTsKICAgICAgICAgICAgYjIgPSBiWzZdOwogICAgICAgICAgICBiMyA9IGJbN107CiAgICAgICAgICAgIHRoaXMubTEwID0gYjAgKiBhMDAgKyBiMSAqIGExMCArIGIyICogYTIwICsgYjMgKiBhMzA7CiAgICAgICAgICAgIHRoaXMubTExID0gYjAgKiBhMDEgKyBiMSAqIGExMSArIGIyICogYTIxICsgYjMgKiBhMzE7CiAgICAgICAgICAgIHRoaXMubTEyID0gYjAgKiBhMDIgKyBiMSAqIGExMiArIGIyICogYTIyICsgYjMgKiBhMzI7CiAgICAgICAgICAgIHRoaXMubTEzID0gYjAgKiBhMDMgKyBiMSAqIGExMyArIGIyICogYTIzICsgYjMgKiBhMzM7CiAgICAgICAgICAgIGIwID0gYls4XTsKICAgICAgICAgICAgYjEgPSBiWzldOwogICAgICAgICAgICBiMiA9IGJbMTBdOwogICAgICAgICAgICBiMyA9IGJbMTFdOwogICAgICAgICAgICB0aGlzLm0yMCA9IGIwICogYTAwICsgYjEgKiBhMTAgKyBiMiAqIGEyMCArIGIzICogYTMwOwogICAgICAgICAgICB0aGlzLm0yMSA9IGIwICogYTAxICsgYjEgKiBhMTEgKyBiMiAqIGEyMSArIGIzICogYTMxOwogICAgICAgICAgICB0aGlzLm0yMiA9IGIwICogYTAyICsgYjEgKiBhMTIgKyBiMiAqIGEyMiArIGIzICogYTMyOwogICAgICAgICAgICB0aGlzLm0yMyA9IGIwICogYTAzICsgYjEgKiBhMTMgKyBiMiAqIGEyMyArIGIzICogYTMzOwogICAgICAgICAgICBiMCA9IGJbMTJdOwogICAgICAgICAgICBiMSA9IGJbMTNdOwogICAgICAgICAgICBiMiA9IGJbMTRdOwogICAgICAgICAgICBiMyA9IGJbMTVdOwogICAgICAgICAgICB0aGlzLm0zMCA9IGIwICogYTAwICsgYjEgKiBhMTAgKyBiMiAqIGEyMCArIGIzICogYTMwOwogICAgICAgICAgICB0aGlzLm0zMSA9IGIwICogYTAxICsgYjEgKiBhMTEgKyBiMiAqIGEyMSArIGIzICogYTMxOwogICAgICAgICAgICB0aGlzLm0zMiA9IGIwICogYTAyICsgYjEgKiBhMTIgKyBiMiAqIGEyMiArIGIzICogYTMyOwogICAgICAgICAgICB0aGlzLm0zMyA9IGIwICogYTAzICsgYjEgKiBhMTMgKyBiMiAqIGEyMyArIGIzICogYTMzOwogICAgICAgICAgICByZXR1cm4gdGhpczsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVHJhbnNsYXRlIGEgTWF0NCBieSB0aGUgZ2l2ZW4gdmVjdG9yIG5vdCB1c2luZyBTSU1ELgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHYzIC0gVGhlIGdpdmVuIHZlY3RvciB0byB0cmFuc2xhdGUgYWxvbmcuCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgdHJhbnNsYXRlSW5QbGFjZSh2MykgewogICAgICAgICAgICBjb25zdCBhID0gdGhpcy5hc0FycmF5KCk7CiAgICAgICAgICAgIGNvbnN0IHggPSB2My54OwogICAgICAgICAgICBjb25zdCB5ID0gdjMueTsKICAgICAgICAgICAgY29uc3QgeiA9IHYzLno7CiAgICAgICAgICAgIGFbMTJdID0gYVswXSAqIHggKyBhWzRdICogeSArIGFbOF0gKiB6ICsgYVsxMl07CiAgICAgICAgICAgIGFbMTNdID0gYVsxXSAqIHggKyBhWzVdICogeSArIGFbOV0gKiB6ICsgYVsxM107CiAgICAgICAgICAgIGFbMTRdID0gYVsyXSAqIHggKyBhWzZdICogeSArIGFbMTBdICogeiArIGFbMTRdOwogICAgICAgICAgICBhWzE1XSA9IGFbM10gKiB4ICsgYVs3XSAqIHkgKyBhWzExXSAqIHogKyBhWzE1XTsKICAgICAgICAgICAgcmV0dXJuIHRoaXM7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEdlbmVyYXRlcyBhIGxvb2stYXQgbWF0cml4IHdpdGggdGhlIGdpdmVuIHBvc2l0aW9uLCBmb2NhbCBwb2ludCwgYW5kIHVwIGF4aXMuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gcG9zIC0gUG9zaXRpb24gb2YgdGhlIHZpZXdlci4KICAgICAgICAgKiBAcGFyYW0gdGFyZ2V0IC0gUG9pbnQgdGhlIHZpZXdlciBpcyBsb29raW5nIGF0LgogICAgICAgICAqIEBwYXJhbSB1cCAtIFZlYzMgcG9pbnRpbmcgdXAuCiAgICAgICAgICovCiAgICAgICAgc2V0TG9va0F0KHBvcywgdGFyZ2V0LCB1cCkgewogICAgICAgICAgICBjb25zdCB6QXhpcyA9IHBvcy5zdWJ0cmFjdCh0YXJnZXQpOwogICAgICAgICAgICBjb25zdCB6TGVuID0gekF4aXMubGVuZ3RoKCk7CiAgICAgICAgICAgIGlmICh6TGVuIDwgTnVtYmVyLkVQU0lMT04pIHsKICAgICAgICAgICAgICAgIHRoaXMuc2V0SWRlbnRpdHkoKTsKICAgICAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgICAgfQogICAgICAgICAgICB6QXhpcy5zY2FsZUluUGxhY2UoMS4wIC8gekxlbik7CiAgICAgICAgICAgIGNvbnN0IHhBeGlzID0gdXAuY3Jvc3MoekF4aXMpOwogICAgICAgICAgICBjb25zdCB4TGVuID0geEF4aXMubGVuZ3RoKCk7CiAgICAgICAgICAgIGlmICh4TGVuID4gTnVtYmVyLkVQU0lMT04pCiAgICAgICAgICAgICAgICB4QXhpcy5zY2FsZUluUGxhY2UoMS4wIC8geExlbik7CiAgICAgICAgICAgIGNvbnN0IHlBeGlzID0gekF4aXMuY3Jvc3MoeEF4aXMpOwogICAgICAgICAgICBjb25zdCB5TGVuID0geUF4aXMubGVuZ3RoKCk7CiAgICAgICAgICAgIGlmICh5TGVuID4gTnVtYmVyLkVQU0lMT04pCiAgICAgICAgICAgICAgICB5QXhpcy5zY2FsZUluUGxhY2UoMS4wIC8geUxlbik7CiAgICAgICAgICAgIC8qIGVzbGludC1kaXNhYmxlIHByZXR0aWVyL3ByZXR0aWVyKi8KICAgICAgICAgICAgdGhpcy5zZXQoeEF4aXMueCwgeEF4aXMueSwgeEF4aXMueiwgMCwgeUF4aXMueCwgeUF4aXMueSwgeUF4aXMueiwgMCwgekF4aXMueCwgekF4aXMueSwgekF4aXMueiwgMCwgcG9zLngsIHBvcy55LCBwb3MueiwgMSk7CiAgICAgICAgICAgIC8qIGVzbGludC1lbmFibGUgcHJldHRpZXIvcHJldHRpZXIqLwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGVzIGEgbWF0cml4IGZyb20gYSBnaXZlbiBhbmdsZSBhcm91bmQgYSBnaXZlbiBheGlzLgogICAgICAgICAqIFRoaXMgaXMgZXF1aXZhbGVudCB0byAoYnV0IG11Y2ggZmFzdGVyIHRoYW4pOgogICAgICAgICAqCiAgICAgICAgICogICAgIG1hdDQuaWRlbnRpdHkoZGVzdCk7CiAgICAgICAgICogICAgIG1hdDQucm90YXRlKGRlc3QsIGRlc3QsIHJhZCwgYXhpcyk7CiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gYXhpcyAtIFRoZSBheGlzIHRvIHJvdGF0ZSBhcm91bmQuCiAgICAgICAgICogQHBhcmFtIHJhZCAtIFRoZSBhbmdsZSB0byByb3RhdGUgdGhlIG1hdHJpeCBieS4KICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBzZXRSb3RhdGlvbihheGlzLCByYWQpIHsKICAgICAgICAgICAgY29uc3QgbGVuID0gYXhpcy5sZW5ndGgoKTsKICAgICAgICAgICAgaWYgKE1hdGguYWJzKGxlbikgPCBOdW1iZXIuRVBTSUxPTikgewogICAgICAgICAgICAgICAgcmV0dXJuIG51bGw7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgY29uc3QgeCA9IGF4aXMueCAvIGxlbjsKICAgICAgICAgICAgY29uc3QgeSA9IGF4aXMueSAvIGxlbjsKICAgICAgICAgICAgY29uc3QgeiA9IGF4aXMueiAvIGxlbjsKICAgICAgICAgICAgY29uc3QgcyA9IE1hdGguc2luKHJhZCk7CiAgICAgICAgICAgIGNvbnN0IGMgPSBNYXRoLmNvcyhyYWQpOwogICAgICAgICAgICBjb25zdCB0ID0gMSAtIGM7CiAgICAgICAgICAgIC8vIFBlcmZvcm0gcm90YXRpb24tc3BlY2lmaWMgbWF0cml4IG11bHRpcGxpY2F0aW9uCiAgICAgICAgICAgIGNvbnN0IGEgPSB0aGlzLmFzQXJyYXkoKTsKICAgICAgICAgICAgYVswXSA9IHggKiB4ICogdCArIGM7CiAgICAgICAgICAgIGFbMV0gPSB5ICogeCAqIHQgKyB6ICogczsKICAgICAgICAgICAgYVsyXSA9IHogKiB4ICogdCAtIHkgKiBzOwogICAgICAgICAgICBhWzNdID0gMDsKICAgICAgICAgICAgYVs0XSA9IHggKiB5ICogdCAtIHogKiBzOwogICAgICAgICAgICBhWzVdID0geSAqIHkgKiB0ICsgYzsKICAgICAgICAgICAgYVs2XSA9IHogKiB5ICogdCArIHggKiBzOwogICAgICAgICAgICBhWzddID0gMDsKICAgICAgICAgICAgYVs4XSA9IHggKiB6ICogdCArIHkgKiBzOwogICAgICAgICAgICBhWzldID0geSAqIHogKiB0IC0geCAqIHM7CiAgICAgICAgICAgIGFbMTBdID0geiAqIHogKiB0ICsgYzsKICAgICAgICAgICAgYVsxMV0gPSAwOwogICAgICAgICAgICBhWzEyXSA9IDA7CiAgICAgICAgICAgIGFbMTNdID0gMDsKICAgICAgICAgICAgYVsxNF0gPSAwOwogICAgICAgICAgICBhWzE1XSA9IDE7CiAgICAgICAgICAgIHJldHVybiB0aGlzOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGVzIGEgbWF0cml4IGZyb20gdGhlIGdpdmVuIGFuZ2xlIGFyb3VuZCB0aGUgWCBheGlzLgogICAgICAgICAqIFRoaXMgaXMgZXF1aXZhbGVudCB0byAoYnV0IG11Y2ggZmFzdGVyIHRoYW4pOgogICAgICAgICAqCiAgICAgICAgICogICAgIG1hdDQuaWRlbnRpdHkoZGVzdCk7CiAgICAgICAgICogICAgIG1hdDQucm90YXRlWChkZXN0LCBkZXN0LCByYWQpOwogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHJhZCAtIFRoZSBhbmdsZSB0byByb3RhdGUgdGhlIG1hdHJpeCBieS4KICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBzZXRYUm90YXRpb24ocmFkKSB7CiAgICAgICAgICAgIGNvbnN0IHMgPSBNYXRoLnNpbihyYWQpOwogICAgICAgICAgICBjb25zdCBjID0gTWF0aC5jb3MocmFkKTsKICAgICAgICAgICAgLy8gUGVyZm9ybSBheGlzLXNwZWNpZmljIG1hdHJpeCBtdWx0aXBsaWNhdGlvbgogICAgICAgICAgICBjb25zdCBhID0gdGhpcy5hc0FycmF5KCk7CiAgICAgICAgICAgIC8qIGVzbGludC1kaXNhYmxlIHByZXR0aWVyL3ByZXR0aWVyKi8KICAgICAgICAgICAgYVswXSA9IDE7CiAgICAgICAgICAgIGFbMV0gPSAwOwogICAgICAgICAgICBhWzJdID0gMDsKICAgICAgICAgICAgYVszXSA9IDA7CiAgICAgICAgICAgIGFbNF0gPSAwOwogICAgICAgICAgICBhWzVdID0gYzsKICAgICAgICAgICAgYVs2XSA9IHM7CiAgICAgICAgICAgIGFbN10gPSAwOwogICAgICAgICAgICBhWzhdID0gMDsKICAgICAgICAgICAgYVs5XSA9IC1zOwogICAgICAgICAgICBhWzEwXSA9IGM7CiAgICAgICAgICAgIGFbMTFdID0gMDsKICAgICAgICAgICAgYVsxMl0gPSAwOwogICAgICAgICAgICBhWzEzXSA9IDA7CiAgICAgICAgICAgIGFbMTRdID0gMDsKICAgICAgICAgICAgYVsxNV0gPSAxOwogICAgICAgICAgICAvKiBlc2xpbnQtZW5hYmxlIHByZXR0aWVyL3ByZXR0aWVyKi8KICAgICAgICAgICAgcmV0dXJuIHRoaXM7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgYSBtYXRyaXggZnJvbSB0aGUgZ2l2ZW4gYW5nbGUgYXJvdW5kIHRoZSBZIGF4aXMuCiAgICAgICAgICogVGhpcyBpcyBlcXVpdmFsZW50IHRvIChidXQgbXVjaCBmYXN0ZXIgdGhhbik6CiAgICAgICAgICoKICAgICAgICAgKiAgICAgbWF0NC5pZGVudGl0eShkZXN0KTsKICAgICAgICAgKiAgICAgbWF0NC5yb3RhdGVZKGRlc3QsIGRlc3QsIHJhZCk7CiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gcmFkIC0gVGhlIGFuZ2xlIHRvIHJvdGF0ZSB0aGUgbWF0cml4IGJ5LgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHNldFlSb3RhdGlvbihyYWQpIHsKICAgICAgICAgICAgY29uc3QgcyA9IE1hdGguc2luKHJhZCk7CiAgICAgICAgICAgIGNvbnN0IGMgPSBNYXRoLmNvcyhyYWQpOwogICAgICAgICAgICAvLyBQZXJmb3JtIGF4aXMtc3BlY2lmaWMgbWF0cml4IG11bHRpcGxpY2F0aW9uCiAgICAgICAgICAgIGNvbnN0IGEgPSB0aGlzLmFzQXJyYXkoKTsKICAgICAgICAgICAgLyogZXNsaW50LWRpc2FibGUgcHJldHRpZXIvcHJldHRpZXIqLwogICAgICAgICAgICBhWzBdID0gYzsKICAgICAgICAgICAgYVsxXSA9IDA7CiAgICAgICAgICAgIGFbMl0gPSAtczsKICAgICAgICAgICAgYVszXSA9IDA7CiAgICAgICAgICAgIGFbNF0gPSAwOwogICAgICAgICAgICBhWzVdID0gMTsKICAgICAgICAgICAgYVs2XSA9IDA7CiAgICAgICAgICAgIGFbN10gPSAwOwogICAgICAgICAgICBhWzhdID0gczsKICAgICAgICAgICAgYVs5XSA9IDA7CiAgICAgICAgICAgIGFbMTBdID0gYzsKICAgICAgICAgICAgYVsxMV0gPSAwOwogICAgICAgICAgICBhWzEyXSA9IDA7CiAgICAgICAgICAgIGFbMTNdID0gMDsKICAgICAgICAgICAgYVsxNF0gPSAwOwogICAgICAgICAgICBhWzE1XSA9IDE7CiAgICAgICAgICAgIC8qIGVzbGludC1lbmFibGUgcHJldHRpZXIvcHJldHRpZXIqLwogICAgICAgICAgICByZXR1cm4gdGhpczsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ3JlYXRlcyBhIG1hdHJpeCBmcm9tIHRoZSBnaXZlbiBhbmdsZSBhcm91bmQgdGhlIFogYXhpcy4KICAgICAgICAgKiBUaGlzIGlzIGVxdWl2YWxlbnQgdG8gKGJ1dCBtdWNoIGZhc3RlciB0aGFuKToKICAgICAgICAgKgogICAgICAgICAqICAgICBtYXQ0LmlkZW50aXR5KGRlc3QpOwogICAgICAgICAqICAgICBtYXQ0LnJvdGF0ZVooZGVzdCwgZGVzdCwgcmFkKTsKICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSByYWQgLSBUaGUgYW5nbGUgdG8gcm90YXRlIHRoZSBtYXRyaXggYnkuCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgc2V0WlJvdGF0aW9uKHJhZCkgewogICAgICAgICAgICBjb25zdCBzID0gTWF0aC5zaW4ocmFkKTsKICAgICAgICAgICAgY29uc3QgYyA9IE1hdGguY29zKHJhZCk7CiAgICAgICAgICAgIC8vIFBlcmZvcm0gYXhpcy1zcGVjaWZpYyBtYXRyaXggbXVsdGlwbGljYXRpb24KICAgICAgICAgICAgY29uc3QgYSA9IHRoaXMuYXNBcnJheSgpOwogICAgICAgICAgICAvKiBlc2xpbnQtZGlzYWJsZSBwcmV0dGllci9wcmV0dGllciovCiAgICAgICAgICAgIGFbMF0gPSBjOwogICAgICAgICAgICBhWzFdID0gczsKICAgICAgICAgICAgYVsyXSA9IDA7CiAgICAgICAgICAgIGFbM10gPSAwOwogICAgICAgICAgICBhWzRdID0gLXM7CiAgICAgICAgICAgIGFbNV0gPSBjOwogICAgICAgICAgICBhWzZdID0gMDsKICAgICAgICAgICAgYVs3XSA9IDA7CiAgICAgICAgICAgIGFbOF0gPSAwOwogICAgICAgICAgICBhWzldID0gMDsKICAgICAgICAgICAgYVsxMF0gPSAxOwogICAgICAgICAgICBhWzExXSA9IDA7CiAgICAgICAgICAgIGFbMTJdID0gMDsKICAgICAgICAgICAgYVsxM10gPSAwOwogICAgICAgICAgICBhWzE0XSA9IDA7CiAgICAgICAgICAgIGFbMTVdID0gMTsKICAgICAgICAgICAgLyogZXNsaW50LWVuYWJsZSBwcmV0dGllci9wcmV0dGllciovCiAgICAgICAgICAgIHJldHVybiB0aGlzOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUcmFuc2Zvcm1zIHRoZSBWZWM0IHdpdGggYSBNYXQ0LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHZlYyAtIFRoZSB2ZWMgdmFsdWUuCiAgICAgICAgICogQHJldHVybiAtIFJldHVybiB0aGUgcmVzdWx0IGFzIGEgbmV3IFZlYzQuCiAgICAgICAgICovCiAgICAgICAgdHJhbnNmb3JtVmVjNCh2ZWMpIHsKICAgICAgICAgICAgY29uc3QgYSA9IHRoaXMuYXNBcnJheSgpOwogICAgICAgICAgICBjb25zdCB4ID0gdmVjLng7CiAgICAgICAgICAgIGNvbnN0IHkgPSB2ZWMueTsKICAgICAgICAgICAgY29uc3QgeiA9IHZlYy56OwogICAgICAgICAgICBjb25zdCB3ID0gdmVjLnc7CiAgICAgICAgICAgIHJldHVybiBuZXcgVmVjNChhWzBdICogeCArIGFbNF0gKiB5ICsgYVs4XSAqIHogKyBhWzEyXSAqIHcsIGFbMV0gKiB4ICsgYVs1XSAqIHkgKyBhWzldICogeiArIGFbMTNdICogdywgYVsyXSAqIHggKyBhWzZdICogeSArIGFbMTBdICogeiArIGFbMTRdICogdywgYVszXSAqIHggKyBhWzddICogeSArIGFbMTFdICogeiArIGFbMTVdICogdyk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRyYW5zZm9ybXMgdGhlIFZlYzMgd2l0aCBhIE1hdDQuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gdmVjIC0gVGhlIHZlYyB2YWx1ZS4KICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJuIHRoZSByZXN1bHQgYXMgYSBuZXcgVmVjMy4KICAgICAgICAgKi8KICAgICAgICB0cmFuc2Zvcm1WZWMzKHZlYykgewogICAgICAgICAgICBjb25zdCBhID0gdGhpcy5hc0FycmF5KCk7CiAgICAgICAgICAgIGNvbnN0IHggPSB2ZWMueDsKICAgICAgICAgICAgY29uc3QgeSA9IHZlYy55OwogICAgICAgICAgICBjb25zdCB6ID0gdmVjLno7CiAgICAgICAgICAgIHJldHVybiBuZXcgVmVjMyhhWzBdICogeCArIGFbNF0gKiB5ICsgYVs4XSAqIHogKyBhWzEyXSwgYVsxXSAqIHggKyBhWzVdICogeSArIGFbOV0gKiB6ICsgYVsxM10sIGFbMl0gKiB4ICsgYVs2XSAqIHkgKyBhWzEwXSAqIHogKyBhWzE0XSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJvdGF0ZXMgYSBnaXZlbiBgVmVjM2AgYW5kIHRoZSByZXN1bHQgaXMgcmV0dXJuZWQgYXMgYSBuZXcgYFZlYzNgLCBhcHBseWluZyBvbmx5IHRoZSB0b3AgbGVmdCBjb21wb25lbnRzIG9mIHRoZSBtYXRyaXgsIHNvIG5vdCBhcHBseWluZyBhbnkgdHJhbnNsYXRpb24uCiAgICAgICAgICogQHBhcmFtIHZlYyAtIFRoZSB2ZWMgdmFsdWUuCiAgICAgICAgICogQHJldHVybiAtIFJldHVybiB0aGUgcmVzdWx0IGFzIGEgbmV3IFZlYzMuCiAgICAgICAgICovCiAgICAgICAgcm90YXRlVmVjMyh2ZWMpIHsKICAgICAgICAgICAgY29uc3QgYSA9IHRoaXMuYXNBcnJheSgpOwogICAgICAgICAgICBjb25zdCB4ID0gdmVjLng7CiAgICAgICAgICAgIGNvbnN0IHkgPSB2ZWMueTsKICAgICAgICAgICAgY29uc3QgeiA9IHZlYy56OwogICAgICAgICAgICByZXR1cm4gbmV3IFZlYzMoYVswXSAqIHggKyBhWzRdICogeSArIGFbOF0gKiB6LCBhWzFdICogeCArIGFbNV0gKiB5ICsgYVs5XSAqIHosIGFbMl0gKiB4ICsgYVs2XSAqIHkgKyBhWzEwXSAqIHopOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTZXQgdGhlIHBlcnNwZWN0aXZlIGZyb20gYSBNYXQ0LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGZvdlkgLSBUaGUgZm92WSB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0gYXNwZWN0IC0gVGhlIGFzcGVjdCB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0gbmVhciAtIFRoZSBuZWFyIHZhbHVlLgogICAgICAgICAqIEBwYXJhbSBmYXIgLSBUaGUgZmFyIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHNldFBlcnNwZWN0aXZlTWF0cml4KGZvdnksIGFzcGVjdCwgbmVhciwgZmFyKSB7CiAgICAgICAgICAgIGNvbnN0IGYgPSBNYXRoLnRhbihNYXRoLlBJICogMC41IC0gMC41ICogZm92eSk7CiAgICAgICAgICAgIGNvbnN0IHJhbmdlSW52ID0gMS4wIC8gKG5lYXIgLSBmYXIpOwogICAgICAgICAgICAvKiBlc2xpbnQtZGlzYWJsZSBwcmV0dGllci9wcmV0dGllciovCiAgICAgICAgICAgIHRoaXMuc2V0KGYgLyBhc3BlY3QsIDAsIDAsIDAsIDAsIGYsIDAsIDAsIDAsIDAsIChuZWFyICsgZmFyKSAqIHJhbmdlSW52LCAtMSwgMCwgMCwgbmVhciAqIGZhciAqIHJhbmdlSW52ICogMiwgMCk7CiAgICAgICAgICAgIC8qIGVzbGludC1lbmFibGUgcHJldHRpZXIvcHJldHRpZXIqLwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDYWxjdWxhdGVzIHRoZSBvcnRob2dyYXBoaWMgbWF0cml4IGFuZCBzZXRzIHRoZSBzdGF0ZSBvZiB0aGUgTWF0NCBjbGFzcwogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGxlZnQgLSBUaGUgbGVmdCB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0gcmlnaHQgLSBUaGUgcmlnaHQgdmFsdWUuCiAgICAgICAgICogQHBhcmFtIGJvdHRvbSAtIFRoZSBib3R0b20gdmFsdWUuCiAgICAgICAgICogQHBhcmFtIHRvcCAtIFRoZSB0b3AgdmFsdWUuCiAgICAgICAgICogQHBhcmFtIG5lYXIgLSBUaGUgbmVhciB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0gZmFyIC0gVGhlIGZhciB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBzZXRPcnRob2dyYXBoaWNNYXRyaXgobGVmdCwgcmlnaHQsIGJvdHRvbSwgdG9wLCBuZWFyLCBmYXIpIHsKICAgICAgICAgICAgY29uc3QgbHIgPSAxIC8gKGxlZnQgLSByaWdodCk7CiAgICAgICAgICAgIGNvbnN0IGJ0ID0gMSAvIChib3R0b20gLSB0b3ApOwogICAgICAgICAgICBjb25zdCBuZiA9IDEgLyAobmVhciAtIGZhcik7CiAgICAgICAgICAgIC8qIGVzbGludC1kaXNhYmxlIHByZXR0aWVyL3ByZXR0aWVyKi8KICAgICAgICAgICAgdGhpcy5zZXQoLTIgKiBsciwgMCwgMCwgMCwgMCwgLTIgKiBidCwgMCwgMCwgMCwgMCwgMiAqIG5mLCAwLCAobGVmdCArIHJpZ2h0KSAqIGxyLCAodG9wICsgYm90dG9tKSAqIGJ0LCAoZmFyICsgbmVhcikgKiBuZiwgMSk7CiAgICAgICAgICAgIC8qIGVzbGludC1lbmFibGUgcHJldHRpZXIvcHJldHRpZXIqLwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTZXQgdGhlIE1hdHJpeCB0byBiZSBhIHNjYWxlIG1hdHJpeC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB4IC0gVGhlIHggdmFsdWUuCiAgICAgICAgICogQHBhcmFtIHkgLSBUaGUgeSB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0geiAtIFRoZSB6IHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHNldFNjYWxlKHgsIHksIHopIHsKICAgICAgICAgICAgLyogZXNsaW50LWRpc2FibGUgcHJldHRpZXIvcHJldHRpZXIqLwogICAgICAgICAgICBpZiAoeCBpbnN0YW5jZW9mIFZlYzMpIHsKICAgICAgICAgICAgICAgIHRoaXMuc2V0KHgueCwgMCwgMCwgMCwgMCwgeC55LCAwLCAwLCAwLCAwLCB4LnosIDAsIDAsIDAsIDAsIDEpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGVsc2UgewogICAgICAgICAgICAgICAgdGhpcy5zZXQoeCwgMCwgMCwgMCwgMCwgeSwgMCwgMCwgMCwgMCwgeiwgMCwgMCwgMCwgMCwgMSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLyogZXNsaW50LWVuYWJsZSBwcmV0dGllci9wcmV0dGllciovCiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRyYW5zZm9ybXMgYSAzeDQgbWF0cml4IGludG8gYSA0eDQgbWF0cml4IGFuZCBzZXQgdGhlIHJlc3VsdCB0byB0aGUgTWF0aDQgc3RhdGUuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gbTN4NCAtIFRoZSBtM3g0IHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHNldEZyb21NYXQzeDRBcnJheShtM3g0KSB7CiAgICAgICAgICAgIC8qIGVzbGludC1kaXNhYmxlIHByZXR0aWVyL3ByZXR0aWVyKi8KICAgICAgICAgICAgdGhpcy5zZXQobTN4NFswXSwgbTN4NFsxXSwgbTN4NFsyXSwgMCwgbTN4NFszXSwgbTN4NFs0XSwgbTN4NFs1XSwgMCwgbTN4NFs2XSwgbTN4NFs3XSwgbTN4NFs4XSwgMCwgbTN4NFs5XSwgbTN4NFsxMF0sIG0zeDRbMTFdLCAxKTsKICAgICAgICAgICAgLyogZXNsaW50LWVuYWJsZSBwcmV0dGllci9wcmV0dGllciovCiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENsb25lcyB0aGlzIE1hdDQgcmV0dXJuaW5nIGEgbmV3IGluc3RhbmNlLgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgYSBuZXcgTWF0NC4KICAgICAgICAgKi8KICAgICAgICBjbG9uZSgpIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBNYXQ0KHRoaXMubTAwLCB0aGlzLm0wMSwgdGhpcy5tMDIsIHRoaXMubTAzLCB0aGlzLm0xMCwgdGhpcy5tMTEsIHRoaXMubTEyLCB0aGlzLm0xMywgdGhpcy5tMjAsIHRoaXMubTIxLCB0aGlzLm0yMiwgdGhpcy5tMjMsIHRoaXMubTMwLCB0aGlzLm0zMSwgdGhpcy5tMzIsIHRoaXMubTMzKTsKICAgICAgICB9CiAgICAgICAgLy8gLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCiAgICAgICAgLy8gUGVyc2lzdGVuY2UKICAgICAgICAvKioKICAgICAgICAgKiBDb252ZXJ0cyB0aGlzIFZlYzMgdG8gYSBzdHJpbmcgaW4gSlNPTiBmb3JtYXQuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICB0b1N0cmluZygpIHsKICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5ldy1jYXAKICAgICAgICAgICAgcmV0dXJuIFN0cmluZ0Z1bmN0aW9ucy5zdHJpbmdpZnlKU09OV2l0aEZpeGVkUHJlY2lzaW9uKHRoaXMudG9KU09OKCkpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgdG9KU09OIG1ldGhvZCBlbmNvZGVzIHRoaXMgdHlwZSBhcyBhIGpzb24gb2JqZWN0IGZvciBwZXJzaXN0ZW5jZS4KICAgICAgICAgKgogICAgICAgICAqLwogICAgICAgIHRvSlNPTigpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuYXNBcnJheSgpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgZnJvbUpTT04gbWV0aG9kIGRlY29kZXMgYSBqc29uIG9iamVjdCBmb3IgdGhpcyB0eXBlLgogICAgICAgICAqCiAgICAgICAgICovCiAgICAgICAgZnJvbUpTT04oanNvbikgewogICAgICAgICAgICB0aGlzLmZyb21BcnJheShqc29uKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogTG9hZHMgdGhlIHN0YXRlIG9mIHRoZSB2YWx1ZSBmcm9tIGEgYmluYXJ5IHJlYWRlci4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSByZWFkZXIgLSBUaGUgcmVhZGVyIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHJlYWRCaW5hcnkocmVhZGVyKSB7CiAgICAgICAgICAgIHRoaXMuZnJvbUFycmF5KHJlYWRlci5sb2FkRmxvYXQzMkFycmF5KDE2KSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgY3VycmVudCBNYXRoIHR5cGUgZGF0YSBhcyBhcnJheS4gT2Z0ZW4gdXNlZCB0byBwYXNzIHR5cGVzIHRvIHRoZSBHUFUuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyB0aGUgcmVzdWx0IGFzIGFuIGFycmF5LgogICAgICAgICAqLwogICAgICAgIGFzQXJyYXkoKSB7CiAgICAgICAgICAgIHJldHVybiBbCiAgICAgICAgICAgICAgICB0aGlzLm0wMCwKICAgICAgICAgICAgICAgIHRoaXMubTAxLAogICAgICAgICAgICAgICAgdGhpcy5tMDIsCiAgICAgICAgICAgICAgICB0aGlzLm0wMywKICAgICAgICAgICAgICAgIHRoaXMubTEwLAogICAgICAgICAgICAgICAgdGhpcy5tMTEsCiAgICAgICAgICAgICAgICB0aGlzLm0xMiwKICAgICAgICAgICAgICAgIHRoaXMubTEzLAogICAgICAgICAgICAgICAgdGhpcy5tMjAsCiAgICAgICAgICAgICAgICB0aGlzLm0yMSwKICAgICAgICAgICAgICAgIHRoaXMubTIyLAogICAgICAgICAgICAgICAgdGhpcy5tMjMsCiAgICAgICAgICAgICAgICB0aGlzLm0zMCwKICAgICAgICAgICAgICAgIHRoaXMubTMxLAogICAgICAgICAgICAgICAgdGhpcy5tMzIsCiAgICAgICAgICAgICAgICB0aGlzLm0zMywKICAgICAgICAgICAgXTsKICAgICAgICB9CiAgICAgICAgZnJvbUFycmF5KGFycmF5KSB7CiAgICAgICAgICAgIHRoaXMubTAwID0gYXJyYXlbMF07CiAgICAgICAgICAgIHRoaXMubTAxID0gYXJyYXlbMV07CiAgICAgICAgICAgIHRoaXMubTAyID0gYXJyYXlbMl07CiAgICAgICAgICAgIHRoaXMubTAzID0gYXJyYXlbM107CiAgICAgICAgICAgIHRoaXMubTEwID0gYXJyYXlbNF07CiAgICAgICAgICAgIHRoaXMubTExID0gYXJyYXlbNV07CiAgICAgICAgICAgIHRoaXMubTEyID0gYXJyYXlbNl07CiAgICAgICAgICAgIHRoaXMubTEzID0gYXJyYXlbN107CiAgICAgICAgICAgIHRoaXMubTIwID0gYXJyYXlbOF07CiAgICAgICAgICAgIHRoaXMubTIxID0gYXJyYXlbOV07CiAgICAgICAgICAgIHRoaXMubTIyID0gYXJyYXlbMTBdOwogICAgICAgICAgICB0aGlzLm0yMyA9IGFycmF5WzExXTsKICAgICAgICAgICAgdGhpcy5tMzAgPSBhcnJheVsxMl07CiAgICAgICAgICAgIHRoaXMubTMxID0gYXJyYXlbMTNdOwogICAgICAgICAgICB0aGlzLm0zMiA9IGFycmF5WzE0XTsKICAgICAgICAgICAgdGhpcy5tMzMgPSBhcnJheVsxNV07CiAgICAgICAgfQogICAgfQoKICAgIC8qIGVzbGludC1kaXNhYmxlIG5vLXVudXNlZC12YXJzICovCiAgICAvKioKICAgICAqIENsYXNzIHJlcHJlc2VudGluZyBhIHF1YXRlcm5pb24uIFF1YXRlcm5pb25zIGFyZSB1c2VkIHRvIHJlcHJlc2VudCAzIGRpbWVuc2lvbmFsIHJvdGF0aW9ucy4KICAgICAqCiAgICAgKiBXaGlsZSBRdWF0ZXJuaW9ucyBhcmUgZGlmZmljdWx0IHRvIHVuZGVyc3RhbmQgdGhleSBoYXZlIGltcG9ydGFudCBtYXRoZW1hdGljYWwgcHJvcGVydGllcyB0aGF0IG1ha2UgdGhlbSB2ZXJ5IHVzZWZ1bCBpbiAzZCBlbmdpbmVzLgogICAgICogVGhleSBjYW4gYmUgZGlyZWN0bHkgbXVsdGlwbGllZCB0b2dldGhlciBpbiB0aGUgc2FtZSB3YXMgYXMgbWF0cmljZXMuCiAgICAgKiBUaGV5IGNhbiBiZSBpbnRlcnBvbGF0ZWQgZnJvbSBvbmUgdmFsdWUgdG8gYW5vdGhlciB3aGlsZSBtYWludGFpbmluZyBjb25zdGFudCBhbmd1bGFyIHZlbG9jaXR5LgogICAgICogVGhleSBjYW4gYmUgY29udmVydGVkIHRvIG90aGVyIG1vcmUgZWFzaWx5IHVuZGVyc3Rvb2QgcmVwcmVzZW50YXRpb25zIHN1Y2ggYXMgRXVsZXJBbmdsZXMgb3IgTWF0cmljZXMuCiAgICAgKgoKICAgICAqLwogICAgY2xhc3MgUXVhdCB7CiAgICAgICAgeDsKICAgICAgICB5OwogICAgICAgIHo7CiAgICAgICAgdzsKICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGVzIGEgcXVhdGVybmlvbi4KICAgICAgICAgKi8KICAgICAgICBjb25zdHJ1Y3Rvcih4ID0gMCwgeSA9IDAsIHogPSAwLCB3ID0gMSkgewogICAgICAgICAgICB0aGlzLnggPSB4OwogICAgICAgICAgICB0aGlzLnkgPSB5OwogICAgICAgICAgICB0aGlzLnogPSB6OwogICAgICAgICAgICB0aGlzLncgPSB3OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTZXR0ZXIgZnJvbSBzY2FsYXIgY29tcG9uZW50cy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB4IC0gVGhlIHggYXhpcyByb3RhdGlvbi4KICAgICAgICAgKiBAcGFyYW0geSAgLSBUaGUgeSBheGlzIHJvdGF0aW9uLgogICAgICAgICAqIEBwYXJhbSB6ICAtIFRoZSB6IGF4aXMgcm90YXRpb24uCiAgICAgICAgICogQHBhcmFtIHcgIC0gVGhlIHcgdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgc2V0KHgsIHksIHosIHcpIHsKICAgICAgICAgICAgdGhpcy54ID0geDsKICAgICAgICAgICAgdGhpcy55ID0geTsKICAgICAgICAgICAgdGhpcy56ID0gejsKICAgICAgICAgICAgdGhpcy53ID0gdzsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU2V0dGVyIGZyb20gYW5vdGhlciB2ZWN0b3IuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gb3RoZXIgLSBUaGUgb3RoZXIgdmVjdG9yIHRvIHNldCBmcm9tLgogICAgICAgICAqLwogICAgICAgIHNldEZyb21PdGhlcihvdGhlcikgewogICAgICAgICAgICB0aGlzLnggPSBvdGhlci54OwogICAgICAgICAgICB0aGlzLnkgPSBvdGhlci55OwogICAgICAgICAgICB0aGlzLnogPSBvdGhlci56OwogICAgICAgICAgICB0aGlzLncgPSBvdGhlci53OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTZXQgdGhpcyBRdWF0IGZyb20gYSBldWxlciByb3RhdGlvbi4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBldWxlckFuZ2xlcyAtIFRoZSBldWxlciBhbmdsZXMgcm90YXRpb24uCiAgICAgICAgICovCiAgICAgICAgc2V0RnJvbUV1bGVyQW5nbGVzKGV1bGVyQW5nbGVzKSB7CiAgICAgICAgICAgIGNvbnN0IG9yZGVyZWQgPSBuZXcgVmVjMygpOwogICAgICAgICAgICBzd2l0Y2ggKGV1bGVyQW5nbGVzLm9yZGVyKSB7CiAgICAgICAgICAgICAgICBjYXNlIEV1bGVyQW5nbGVzQXhpc09yZGVyLlhZWjoKICAgICAgICAgICAgICAgICAgICBvcmRlcmVkLnNldChldWxlckFuZ2xlcy54LCAtZXVsZXJBbmdsZXMueSwgZXVsZXJBbmdsZXMueik7CiAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICBjYXNlIEV1bGVyQW5nbGVzQXhpc09yZGVyLllaWDoKICAgICAgICAgICAgICAgICAgICBvcmRlcmVkLnNldChldWxlckFuZ2xlcy55LCAtZXVsZXJBbmdsZXMueiwgZXVsZXJBbmdsZXMueCk7CiAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICBjYXNlIEV1bGVyQW5nbGVzQXhpc09yZGVyLlpYWToKICAgICAgICAgICAgICAgICAgICBvcmRlcmVkLnNldChldWxlckFuZ2xlcy56LCAtZXVsZXJBbmdsZXMueCwgZXVsZXJBbmdsZXMueSk7CiAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICBjYXNlIEV1bGVyQW5nbGVzQXhpc09yZGVyLlhaWToKICAgICAgICAgICAgICAgICAgICBvcmRlcmVkLnNldChldWxlckFuZ2xlcy54LCBldWxlckFuZ2xlcy56LCBldWxlckFuZ2xlcy55KTsKICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIGNhc2UgRXVsZXJBbmdsZXNBeGlzT3JkZXIuWllYOgogICAgICAgICAgICAgICAgICAgIG9yZGVyZWQuc2V0KGV1bGVyQW5nbGVzLnosIGV1bGVyQW5nbGVzLnksIGV1bGVyQW5nbGVzLngpOwogICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgY2FzZSBFdWxlckFuZ2xlc0F4aXNPcmRlci5ZWFo6CiAgICAgICAgICAgICAgICAgICAgb3JkZXJlZC5zZXQoZXVsZXJBbmdsZXMueSwgZXVsZXJBbmdsZXMueCwgZXVsZXJBbmdsZXMueik7CiAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICBkZWZhdWx0OgogICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCBFdWxlckFuZ2xlcyBvcmRlcjogJHtldWxlckFuZ2xlcy5vcmRlcn1gKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBjb25zdCB0aSA9IG9yZGVyZWQueCAqIDAuNTsKICAgICAgICAgICAgY29uc3QgdGogPSBvcmRlcmVkLnkgKiAwLjU7CiAgICAgICAgICAgIGNvbnN0IHRrID0gb3JkZXJlZC56ICogMC41OwogICAgICAgICAgICBjb25zdCBjaSA9IE1hdGguY29zKHRpKTsKICAgICAgICAgICAgY29uc3QgY2ogPSBNYXRoLmNvcyh0aik7CiAgICAgICAgICAgIGNvbnN0IGNrID0gTWF0aC5jb3ModGspOwogICAgICAgICAgICBjb25zdCBzaSA9IE1hdGguc2luKHRpKTsKICAgICAgICAgICAgY29uc3Qgc2ogPSBNYXRoLnNpbih0aik7CiAgICAgICAgICAgIGNvbnN0IHNrID0gTWF0aC5zaW4odGspOwogICAgICAgICAgICBjb25zdCBjYyA9IGNpICogY2s7CiAgICAgICAgICAgIGNvbnN0IGNzID0gY2kgKiBzazsKICAgICAgICAgICAgY29uc3Qgc2MgPSBzaSAqIGNrOwogICAgICAgICAgICBjb25zdCBzcyA9IHNpICogc2s7CiAgICAgICAgICAgIGNvbnN0IGFpID0gY2ogKiBzYyAtIHNqICogY3M7CiAgICAgICAgICAgIGNvbnN0IGFqID0gY2ogKiBzcyArIHNqICogY2M7CiAgICAgICAgICAgIGNvbnN0IGFrID0gY2ogKiBjcyAtIHNqICogc2M7CiAgICAgICAgICAgIHRoaXMudyA9IGNqICogY2MgKyBzaiAqIHNzOwogICAgICAgICAgICBzd2l0Y2ggKGV1bGVyQW5nbGVzLm9yZGVyKSB7CiAgICAgICAgICAgICAgICBjYXNlIDA6CiAgICAgICAgICAgICAgICAgICAgLy8gJyBYWVonCiAgICAgICAgICAgICAgICAgICAgdGhpcy54ID0gYWk7CiAgICAgICAgICAgICAgICAgICAgdGhpcy55ID0gLWFqOwogICAgICAgICAgICAgICAgICAgIHRoaXMueiA9IGFrOwogICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgY2FzZSAxOgogICAgICAgICAgICAgICAgICAgIC8vICdZWlgnCiAgICAgICAgICAgICAgICAgICAgdGhpcy54ID0gYWs7CiAgICAgICAgICAgICAgICAgICAgdGhpcy55ID0gYWk7CiAgICAgICAgICAgICAgICAgICAgdGhpcy56ID0gLWFqOwogICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgY2FzZSAyOgogICAgICAgICAgICAgICAgICAgIC8vICdaWFknCiAgICAgICAgICAgICAgICAgICAgdGhpcy54ID0gLWFqOwogICAgICAgICAgICAgICAgICAgIHRoaXMueSA9IGFrOwogICAgICAgICAgICAgICAgICAgIHRoaXMueiA9IGFpOwogICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgY2FzZSAzOgogICAgICAgICAgICAgICAgICAgIC8vICdYWlknCiAgICAgICAgICAgICAgICAgICAgdGhpcy54ID0gYWk7CiAgICAgICAgICAgICAgICAgICAgdGhpcy55ID0gYWs7CiAgICAgICAgICAgICAgICAgICAgdGhpcy56ID0gYWo7CiAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICBjYXNlIDQ6CiAgICAgICAgICAgICAgICAgICAgLy8gJ1pZWCcKICAgICAgICAgICAgICAgICAgICB0aGlzLnggPSBhazsKICAgICAgICAgICAgICAgICAgICB0aGlzLnkgPSBhajsKICAgICAgICAgICAgICAgICAgICB0aGlzLnogPSBhaTsKICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIGNhc2UgNToKICAgICAgICAgICAgICAgICAgICAvLyAnWVhaJwogICAgICAgICAgICAgICAgICAgIHRoaXMueCA9IGFqOwogICAgICAgICAgICAgICAgICAgIHRoaXMueSA9IGFpOwogICAgICAgICAgICAgICAgICAgIHRoaXMueiA9IGFrOwogICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgZGVmYXVsdDoKICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgRXVsZXJBbmdsZXMgb3JkZXI6ICR7ZXVsZXJBbmdsZXMub3JkZXJ9YCk7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29udmVydHMgUXVhdCB0byBhbiBFdWxlckFuZ2xlcwogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHJvdGF0aW9uT3JkZXIgLSBUaGUgb3JkZXIgaW4gd2hpY2ggdGhlIHJvdGF0aW9ucyBhcmUgYXBwbGllZC4KICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICB0b0V1bGVyQW5nbGVzKHJvdGF0aW9uT3JkZXIpIHsKICAgICAgICAgICAgY29uc3Qgb3JkZXJlZCA9IG5ldyBWZWMzKCk7CiAgICAgICAgICAgIHN3aXRjaCAocm90YXRpb25PcmRlcikgewogICAgICAgICAgICAgICAgY2FzZSBFdWxlckFuZ2xlc0F4aXNPcmRlci5YWVo6CiAgICAgICAgICAgICAgICBjYXNlICdYWVonOgogICAgICAgICAgICAgICAgICAgIG9yZGVyZWQuc2V0KHRoaXMueiwgdGhpcy54LCB0aGlzLnkpOwogICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgY2FzZSBFdWxlckFuZ2xlc0F4aXNPcmRlci5ZWlg6CiAgICAgICAgICAgICAgICBjYXNlICdZWlgnOgogICAgICAgICAgICAgICAgICAgIG9yZGVyZWQuc2V0KHRoaXMueCwgdGhpcy55LCB0aGlzLnopOwogICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgY2FzZSBFdWxlckFuZ2xlc0F4aXNPcmRlci5aWFk6CiAgICAgICAgICAgICAgICBjYXNlICdaWFknOgogICAgICAgICAgICAgICAgICAgIG9yZGVyZWQuc2V0KHRoaXMueSwgdGhpcy56LCB0aGlzLngpOwogICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgY2FzZSBFdWxlckFuZ2xlc0F4aXNPcmRlci5YWlk6CiAgICAgICAgICAgICAgICBjYXNlICdYWlknOgogICAgICAgICAgICAgICAgICAgIG9yZGVyZWQuc2V0KHRoaXMueSwgLXRoaXMueCwgdGhpcy56KTsKICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIGNhc2UgRXVsZXJBbmdsZXNBeGlzT3JkZXIuWllYOgogICAgICAgICAgICAgICAgY2FzZSAnWllYJzoKICAgICAgICAgICAgICAgICAgICBvcmRlcmVkLnNldCh0aGlzLngsIC10aGlzLnosIHRoaXMueSk7CiAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICBjYXNlIEV1bGVyQW5nbGVzQXhpc09yZGVyLllYWjoKICAgICAgICAgICAgICAgIGNhc2UgJ1lYWic6CiAgICAgICAgICAgICAgICAgICAgb3JkZXJlZC5zZXQodGhpcy56LCAtdGhpcy55LCB0aGlzLngpOwogICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgZGVmYXVsdDoKICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgcm90YXRpb24gb3JkZXI6JyArIHJvdGF0aW9uT3JkZXIpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGNvbnN0IGV1bGVyID0gbmV3IFZlYzMoKTsKICAgICAgICAgICAgY29uc3QgdGVzdCA9IG9yZGVyZWQueCAqIG9yZGVyZWQueSArIG9yZGVyZWQueiAqIHRoaXMudzsKICAgICAgICAgICAgaWYgKHRlc3QgPiAwLjQ5OTk5KSB7CiAgICAgICAgICAgICAgICAvLyBzaW5ndWxhcml0eSBhdCBub3J0aCBwb2xlCiAgICAgICAgICAgICAgICBldWxlci55ID0gMi4wICogTWF0aC5hdGFuMihvcmRlcmVkLngsIHRoaXMudyk7CiAgICAgICAgICAgICAgICBldWxlci56ID0gTWF0aC5QSSAqIDAuNTsKICAgICAgICAgICAgICAgIGV1bGVyLnggPSAwLjA7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZWxzZSBpZiAodGVzdCA8IC0wLjQ5OTk5KSB7CiAgICAgICAgICAgICAgICAvLyBzaW5ndWxhcml0eSBhdCBzb3V0aCBwb2xlCiAgICAgICAgICAgICAgICBldWxlci55ID0gLTIuMCAqIE1hdGguYXRhbjIob3JkZXJlZC54LCB0aGlzLncpOwogICAgICAgICAgICAgICAgZXVsZXIueiA9IE1hdGguUEkgKiAtMC41OwogICAgICAgICAgICAgICAgZXVsZXIueCA9IDAuMDsKICAgICAgICAgICAgfQogICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgIGNvbnN0IHNxeCA9IG9yZGVyZWQueCAqIG9yZGVyZWQueDsKICAgICAgICAgICAgICAgIGNvbnN0IHNxeSA9IG9yZGVyZWQueSAqIG9yZGVyZWQueTsKICAgICAgICAgICAgICAgIGNvbnN0IHNxeiA9IG9yZGVyZWQueiAqIG9yZGVyZWQuejsKICAgICAgICAgICAgICAgIGV1bGVyLnkgPSBNYXRoLmF0YW4yKDIuMCAqIG9yZGVyZWQueSAqIHRoaXMudyAtIDIuMCAqIG9yZGVyZWQueCAqIG9yZGVyZWQueiwgMS4wIC0gMi4wICogc3F5IC0gMi4wICogc3F6KTsKICAgICAgICAgICAgICAgIGV1bGVyLnogPSBNYXRoLmFzaW4oMi4wICogdGVzdCk7CiAgICAgICAgICAgICAgICBldWxlci54ID0gTWF0aC5hdGFuMigyLjAgKiBvcmRlcmVkLnggKiB0aGlzLncgLSAyLjAgKiBvcmRlcmVkLnkgKiBvcmRlcmVkLnosIDEuMCAtIDIuMCAqIHNxeCAtIDIuMCAqIHNxeik7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgc3dpdGNoIChyb3RhdGlvbk9yZGVyKSB7CiAgICAgICAgICAgICAgICBjYXNlIEV1bGVyQW5nbGVzQXhpc09yZGVyLlhZWjoKICAgICAgICAgICAgICAgIGNhc2UgJ1hZWic6CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBFdWxlckFuZ2xlcyhldWxlci55LCBldWxlci56LCBldWxlci54LCByb3RhdGlvbk9yZGVyKTsKICAgICAgICAgICAgICAgIGNhc2UgRXVsZXJBbmdsZXNBeGlzT3JkZXIuWVpYOgogICAgICAgICAgICAgICAgY2FzZSAnWVpYJzoKICAgICAgICAgICAgICAgICAgICByZXR1cm4gbmV3IEV1bGVyQW5nbGVzKGV1bGVyLngsIGV1bGVyLnksIGV1bGVyLnosIHJvdGF0aW9uT3JkZXIpOwogICAgICAgICAgICAgICAgY2FzZSBFdWxlckFuZ2xlc0F4aXNPcmRlci5aWFk6CiAgICAgICAgICAgICAgICBjYXNlICdaWFknOgogICAgICAgICAgICAgICAgICAgIHJldHVybiBuZXcgRXVsZXJBbmdsZXMoZXVsZXIueiwgZXVsZXIueCwgZXVsZXIueSwgcm90YXRpb25PcmRlcik7CiAgICAgICAgICAgICAgICBjYXNlIEV1bGVyQW5nbGVzQXhpc09yZGVyLlhaWToKICAgICAgICAgICAgICAgIGNhc2UgJ1haWSc6CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBFdWxlckFuZ2xlcygtZXVsZXIueSwgZXVsZXIueCwgZXVsZXIueiwgcm90YXRpb25PcmRlcik7CiAgICAgICAgICAgICAgICBjYXNlIEV1bGVyQW5nbGVzQXhpc09yZGVyLlpZWDoKICAgICAgICAgICAgICAgIGNhc2UgJ1pZWCc6CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBFdWxlckFuZ2xlcyhldWxlci54LCBldWxlci56LCAtZXVsZXIueSwgcm90YXRpb25PcmRlcik7CiAgICAgICAgICAgICAgICBjYXNlIEV1bGVyQW5nbGVzQXhpc09yZGVyLllYWjoKICAgICAgICAgICAgICAgIGNhc2UgJ1lYWic6CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBFdWxlckFuZ2xlcyhldWxlci56LCAtZXVsZXIueSwgZXVsZXIueCwgcm90YXRpb25PcmRlcik7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU2V0IHRoaXMgUXVhdCB0byBhIHJvdGF0aW9uIGRlZmluZWQgYnkgYW4gYXhpcyBhbmQgYW4gYW5nbGUgKGluIHJhZGlhbnMpLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGF4aXMgLSBUaGUgYXhpcyBhcm91bmQgd2hpY2ggdG8gcm90YXRlLgogICAgICAgICAqIEBwYXJhbSBhbmdsZSAtIFRoZSBhbmdsZSB0byByb3RhdGUKICAgICAgICAgKi8KICAgICAgICBzZXRGcm9tQXhpc0FuZEFuZ2xlKGF4aXMsIGFuZ2xlKSB7CiAgICAgICAgICAgIGNvbnN0IGhhbGZBbmdsZSA9IGFuZ2xlIC8gMi4wOwogICAgICAgICAgICBjb25zdCB2ZWMgPSBheGlzLm5vcm1hbGl6ZSgpLnNjYWxlKE1hdGguc2luKGhhbGZBbmdsZSkpOwogICAgICAgICAgICB0aGlzLnNldCh2ZWMueCwgdmVjLnksIHZlYy56LCBNYXRoLmNvcyhoYWxmQW5nbGUpKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU2V0cyB0aGUgc3RhdGUgb2YgdGhlIFF1YXQgdG8gbG9vayBpbiBhIHBhcnRpY3VsYXIgZGlyZWN0aW9uIGFsb25nIHRoZSB6IGF4aXMuCiAgICAgICAgICogPiBUaGUgY2FtZXJhIGxvb2tzIGRvd24gdGhlIG5lZ2F0aXZlIHogYXhpcywgc28gdG8gc2V0IGEgcm90YXRpb24gdmFsdWUKICAgICAgICAgKiA+IGZvciB0aGUgY2FtZXJhLCByZW1lbWJlciB0byBuZWdhdGUgdGhlIGRpcmVjdGlvbiB2ZWN0b3IuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gZGlyIC0gVGhlIGRpcmVjdGlvbiB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0gdXAgLSBUaGUgdXAgdmVjdG9yLgogICAgICAgICAqLwogICAgICAgIHNldEZyb21EaXJlY3Rpb25BbmRVcHZlY3RvcihkaXIsIHVwKSB7CiAgICAgICAgICAgIGNvbnN0IG1hdDMgPSBuZXcgTWF0MygpOwogICAgICAgICAgICBtYXQzLnNldEZyb21EaXJlY3Rpb25BbmRVcHZlY3RvcihkaXIsIHVwKTsKICAgICAgICAgICAgdGhpcy5zZXRGcm9tTWF0MyhtYXQzKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU2V0cyB0aGUgc3RhdGUgb2YgdGhlIGBRdWF0YCBmcm9tIHR3byBgVmVjM2AuIFRoZSBxdWF0ZXJuaW9uIHdvdWxkIHRoZW4gcmVwcmVzZW50IHRoZSByb3RhdGlvbiBmcm9tIHYwIHRvIHYxIGluIDNkIHNwYWNlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHYwIC0gVGhlIHYwIHVuaXQgdmVjdG9yLgogICAgICAgICAqIEBwYXJhbSB2MSAtIFRoZSB2MSB1bml0IHZlY3Rvci4KICAgICAgICAgKi8KICAgICAgICBzZXRGcm9tMlZlY3RvcnModjAsIHYxKSB7CiAgICAgICAgICAgIGNvbnN0IGMgPSB2MC5jcm9zcyh2MSk7CiAgICAgICAgICAgIGNvbnN0IGQgPSB2MC5kb3QodjEpOwogICAgICAgICAgICBjb25zdCBzID0gTWF0aC5zcXJ0KCgxICsgZCkgKiAyKTsKICAgICAgICAgICAgLy8gdGhpcy5zZXQoIHMvMiwgYy54IC8gcywgYy55IC8gcywgYy56IC8gcyApOwogICAgICAgICAgICB0aGlzLnNldChjLnggLyBzLCBjLnkgLyBzLCBjLnogLyBzLCBzIC8gMik7CiAgICAgICAgICAgIHRoaXMubm9ybWFsaXplSW5QbGFjZSgpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTZXQgdGhlIFF1YXQgZnJvbSBhIE1hdDMuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gbWF0MyAtIFRoZSBtYXQzIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHNldEZyb21NYXQzKG1hdDMpIHsKICAgICAgICAgICAgLy8gQWxnb3JpdGhtIGluIEtlbiBTaG9lbWFrZSdzIGFydGljbGUgaW4gMTk4NyBTSUdHUkFQSCBjb3Vyc2Ugbm90ZXMKICAgICAgICAgICAgLy8gYXJ0aWNsZSAiUXVhdGVybmlvbiBDYWxjdWx1cyBhbmQgRmFzdCBBbmltYXRpb24iLgogICAgICAgICAgICBjb25zdCBkYXRhID0gbWF0My5hc0FycmF5KCk7CiAgICAgICAgICAgIGNvbnN0IGZUcmFjZSA9IGRhdGFbMF0gKyBkYXRhWzRdICsgZGF0YVs4XTsKICAgICAgICAgICAgbGV0IGZSb290OwogICAgICAgICAgICBpZiAoZlRyYWNlID4gMC4wKSB7CiAgICAgICAgICAgICAgICAvLyB8d3wgPiAxLzIsIG1heSBhcyB3ZWxsIGNob29zZSB3ID4gMS8yCiAgICAgICAgICAgICAgICBmUm9vdCA9IE1hdGguc3FydChmVHJhY2UgKyAxKTsgLy8gMncKICAgICAgICAgICAgICAgIHRoaXMudyA9IDAuNSAqIGZSb290OwogICAgICAgICAgICAgICAgZlJvb3QgPSAwLjUgLyBmUm9vdDsgLy8gMS8oNHcpCiAgICAgICAgICAgICAgICB0aGlzLnggPSAoZGF0YVs1XSAtIGRhdGFbN10pICogZlJvb3Q7CiAgICAgICAgICAgICAgICB0aGlzLnkgPSAoZGF0YVs2XSAtIGRhdGFbMl0pICogZlJvb3Q7CiAgICAgICAgICAgICAgICB0aGlzLnogPSAoZGF0YVsxXSAtIGRhdGFbM10pICogZlJvb3Q7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZWxzZSB7CiAgICAgICAgICAgICAgICAvLyB8d3wgPD0gMS8yCiAgICAgICAgICAgICAgICBsZXQgaSA9IDA7CiAgICAgICAgICAgICAgICBpZiAoZGF0YVs0XSA+IGRhdGFbMF0pCiAgICAgICAgICAgICAgICAgICAgaSA9IDE7CiAgICAgICAgICAgICAgICBpZiAoZGF0YVs4XSA+IGRhdGFbaSAqIDMgKyBpXSkKICAgICAgICAgICAgICAgICAgICBpID0gMjsKICAgICAgICAgICAgICAgIGNvbnN0IGogPSAoaSArIDEpICUgMzsKICAgICAgICAgICAgICAgIGNvbnN0IGsgPSAoaSArIDIpICUgMzsKICAgICAgICAgICAgICAgIGZSb290ID0gTWF0aC5zcXJ0KGRhdGFbaSAqIDMgKyBpXSAtIGRhdGFbaiAqIDMgKyBqXSAtIGRhdGFbayAqIDMgKyBrXSArIDEuMCk7CiAgICAgICAgICAgICAgICBjb25zdCBhcnJheSA9IFswLCAwLCAwLCAwXTsKICAgICAgICAgICAgICAgIGFycmF5W2ldID0gMC41ICogZlJvb3Q7CiAgICAgICAgICAgICAgICBmUm9vdCA9IDAuNSAvIGZSb290OwogICAgICAgICAgICAgICAgYXJyYXlbM10gPSAoZGF0YVtqICogMyArIGtdIC0gZGF0YVtrICogMyArIGpdKSAqIGZSb290OwogICAgICAgICAgICAgICAgYXJyYXlbal0gPSAoZGF0YVtqICogMyArIGldICsgZGF0YVtpICogMyArIGpdKSAqIGZSb290OwogICAgICAgICAgICAgICAgYXJyYXlba10gPSAoZGF0YVtrICogMyArIGldICsgZGF0YVtpICogMyArIGtdKSAqIGZSb290OwogICAgICAgICAgICAgICAgdGhpcy5mcm9tQXJyYXkoYXJyYXkpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHRoaXMubm9ybWFsaXplSW5QbGFjZSgpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTZXQgdGhlIFF1YXQgZnJvbSBhIE1hdDQuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gbWF0NCAtIFRoZSBtYXQ0IHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHNldEZyb21NYXQ0KG1hdDQpIHsKICAgICAgICAgICAgLy8gQWxnb3JpdGhtIGluIEtlbiBTaG9lbWFrZSdzIGFydGljbGUgaW4gMTk4NyBTSUdHUkFQSCBjb3Vyc2Ugbm90ZXMKICAgICAgICAgICAgLy8gYXJ0aWNsZSAiUXVhdGVybmlvbiBDYWxjdWx1cyBhbmQgRmFzdCBBbmltYXRpb24iLgogICAgICAgICAgICBjb25zdCBkYXRhID0gbWF0NC5hc0FycmF5KCk7CiAgICAgICAgICAgIGNvbnN0IGZUcmFjZSA9IGRhdGFbMF0gKyBkYXRhWzVdICsgZGF0YVsxMF07CiAgICAgICAgICAgIGxldCBmUm9vdDsKICAgICAgICAgICAgaWYgKGZUcmFjZSA+IDAuMCkgewogICAgICAgICAgICAgICAgLy8gfHd8ID4gMS8yLCBtYXkgYXMgd2VsbCBjaG9vc2UgdyA+IDEvMgogICAgICAgICAgICAgICAgZlJvb3QgPSBNYXRoLnNxcnQoZlRyYWNlICsgMSk7IC8vIDJ3CiAgICAgICAgICAgICAgICB0aGlzLncgPSAwLjUgKiBmUm9vdDsKICAgICAgICAgICAgICAgIGZSb290ID0gMC41IC8gZlJvb3Q7IC8vIDEvKDR3KQogICAgICAgICAgICAgICAgdGhpcy54ID0gKGRhdGFbNl0gLSBkYXRhWzldKSAqIGZSb290OwogICAgICAgICAgICAgICAgdGhpcy55ID0gKGRhdGFbOF0gLSBkYXRhWzJdKSAqIGZSb290OwogICAgICAgICAgICAgICAgdGhpcy56ID0gKGRhdGFbMV0gLSBkYXRhWzRdKSAqIGZSb290OwogICAgICAgICAgICB9CiAgICAgICAgICAgIGVsc2UgewogICAgICAgICAgICAgICAgLy8gfHd8IDw9IDEvMgogICAgICAgICAgICAgICAgbGV0IGkgPSAwOwogICAgICAgICAgICAgICAgaWYgKGRhdGFbNV0gPiBkYXRhWzBdKQogICAgICAgICAgICAgICAgICAgIGkgPSAxOwogICAgICAgICAgICAgICAgaWYgKGRhdGFbMTBdID4gZGF0YVtpICogNCArIGldKQogICAgICAgICAgICAgICAgICAgIGkgPSAyOwogICAgICAgICAgICAgICAgY29uc3QgaiA9IChpICsgMSkgJSAzOwogICAgICAgICAgICAgICAgY29uc3QgayA9IChpICsgMikgJSAzOwogICAgICAgICAgICAgICAgZlJvb3QgPSBNYXRoLnNxcnQoZGF0YVtpICogNCArIGldIC0gZGF0YVtqICogNCArIGpdIC0gZGF0YVtrICogNCArIGtdICsgMS4wKTsKICAgICAgICAgICAgICAgIGNvbnN0IGFycmF5ID0gWzAsIDAsIDAsIDBdOwogICAgICAgICAgICAgICAgYXJyYXlbaV0gPSAwLjUgKiBmUm9vdDsKICAgICAgICAgICAgICAgIGZSb290ID0gMC41IC8gZlJvb3Q7CiAgICAgICAgICAgICAgICBhcnJheVszXSA9IChkYXRhW2ogKiA0ICsga10gLSBkYXRhW2sgKiA0ICsgal0pICogZlJvb3Q7CiAgICAgICAgICAgICAgICBhcnJheVtqXSA9IChkYXRhW2ogKiA0ICsgaV0gKyBkYXRhW2kgKiA0ICsgal0pICogZlJvb3Q7CiAgICAgICAgICAgICAgICBhcnJheVtrXSA9IChkYXRhW2sgKiA0ICsgaV0gKyBkYXRhW2kgKiA0ICsga10pICogZlJvb3Q7CiAgICAgICAgICAgICAgICB0aGlzLmZyb21BcnJheShhcnJheSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdGhpcy5ub3JtYWxpemVJblBsYWNlKCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENoZWNrcyBpZiB0aGUgYW5nbGUgb2YgdGhlIFF1YXQgaXMgbGVzcyB0aGF0IGAgTnVtYmVyLkVQU0lMT05gCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyB0cnVlIG9yIGZhbHNlLgogICAgICAgICAqLwogICAgICAgIGlzSWRlbnRpdHkoKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLmdldEFuZ2xlKCkgPCBOdW1iZXIuRVBTSUxPTjsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJuIHRoZSBhbmdsZSBvZiB0aGUgUXVhdC4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGdldEFuZ2xlKCkgewogICAgICAgICAgICByZXR1cm4gTWF0aC5hY29zKHRoaXMudykgKiAyLjA7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENoZWNrcyBpZiB0aGlzIFF1YXQgY29udGFpbnMgdGhlIHNhbWUgdmFsdWVzIGFzIHRoZSBvdGhlciBRdWF0LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIG90aGVyIC0gVGhlIG90aGVyIFF1YXQgdG8gY29tcGFyZSB3aXRoLgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGB0cnVlYCBpZiBhcmUgdGhlIHNhbWUgVmVjdG9yLCBvdGhlcndpc2UsIGBmYWxzZWAuCiAgICAgICAgICovCiAgICAgICAgaXNFcXVhbChvdGhlcikgewogICAgICAgICAgICByZXR1cm4gdGhpcy54ID09IG90aGVyLnggJiYgdGhpcy55ID09IG90aGVyLnkgJiYgdGhpcy56ID09IG90aGVyLnogJiYgdGhpcy53ID09IG90aGVyLnc7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgdHJ1ZSBpZiB0aGlzIFF1YXQgaXMgTk9UIGV4YWN0bHkgdGhlIHNhbWUgb3RoZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gb3RoZXIgLSBUaGUgb3RoZXIgUXVhdCB0byBjb21wYXJlIHdpdGguCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgdHJ1ZSBvciBmYWxzZS4KICAgICAgICAgKi8KICAgICAgICBub3RFcXVhbHMob3RoZXIpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMueCAhPSBvdGhlci54ICYmIHRoaXMueSAhPSBvdGhlci55ICYmIHRoaXMueiAhPSBvdGhlci56ICYmIHRoaXMudyAhPSBvdGhlci53OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIHRydWUgaWYgdGhpcyBRdWF0IGlzIGFwcHJveGltYXRlbHkgdGhlIHNhbWUgYXMgb3RoZXIKICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBvdGhlciAtIFRoZSBvdGhlciBRdWF0IHRvIGNvbXBhcmUgd2l0aC4KICAgICAgICAgKiBAcGFyYW0gcHJlY2lzaW9uIC0gVGhlIHByZWNpc2lvbiB0byB3aGljaCB0aGUgdmFsdWVzIG11c3QgbWF0Y2guCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgdHJ1ZSBvciBmYWxzZS4KICAgICAgICAgKi8KICAgICAgICBhcHByb3hFcXVhbChvdGhlciwgcHJlY2lzaW9uID0gTnVtYmVyLkVQU0lMT04pIHsKICAgICAgICAgICAgcmV0dXJuIChNYXRoLmFicyh0aGlzLnggLSBvdGhlci54KSA8IHByZWNpc2lvbiAmJgogICAgICAgICAgICAgICAgTWF0aC5hYnModGhpcy55IC0gb3RoZXIueSkgPCBwcmVjaXNpb24gJiYKICAgICAgICAgICAgICAgIE1hdGguYWJzKHRoaXMueiAtIG90aGVyLnopIDwgcHJlY2lzaW9uICYmCiAgICAgICAgICAgICAgICBNYXRoLmFicyh0aGlzLncgLSBvdGhlci53KSA8IHByZWNpc2lvbik7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEFkZHMgb3RoZXIgdG8gdGhpcyBRdWF0IGFuZCByZXR1cm4gdGhlIHJlc3VsdCBhcyBhIG5ldyBRdWF0LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIG90aGVyIC0gVGhlIG90aGVyIFF1YXQgdG8gYWRkLgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGEgbmV3IFF1YXQuCiAgICAgICAgICovCiAgICAgICAgYWRkKG90aGVyKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgUXVhdCh0aGlzLnggKyBvdGhlci54LCB0aGlzLnkgKyBvdGhlci55LCB0aGlzLnogKyBvdGhlci56LCB0aGlzLncgKyBvdGhlci53KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQWRkcyBvdGhlciB0byB0aGlzIFF1YXQuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gb3RoZXIgLSBUaGUgb3RoZXIgUXVhdCB0byBhZGQuCiAgICAgICAgICovCiAgICAgICAgYWRkSW5QbGFjZShvdGhlcikgewogICAgICAgICAgICB0aGlzLnggKz0gb3RoZXIueDsKICAgICAgICAgICAgdGhpcy55ICs9IG90aGVyLnk7CiAgICAgICAgICAgIHRoaXMueiArPSBvdGhlci56OwogICAgICAgICAgICB0aGlzLncgKz0gb3RoZXIudzsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU3VidHJhY3RzIG90aGVyIGZyb20gdGhpcyBRdWF0IGFuZCByZXR1cm5zIHRoZSByZXN1bHQgYXMgYSBuZXcgUXVhdC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBvdGhlciAtIFRoZSBvdGhlciBRdWF0IHRvIHN1YnRyYWN0LgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGEgbmV3IFF1YXQuCiAgICAgICAgICovCiAgICAgICAgc3VidHJhY3Qob3RoZXIpIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBRdWF0KHRoaXMueCAtIG90aGVyLngsIHRoaXMueSAtIG90aGVyLnksIHRoaXMueiAtIG90aGVyLnosIHRoaXMudyAtIG90aGVyLncpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTY2FsZXMgdGhpcyBRdWF0IGJ5IHNjYWxhciBhbmQgcmV0dXJucyB0aGUgcmVzdWx0IGFzIGEgbmV3IFF1YXQuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gc2NhbGFyIC0gVGhlIHNjYWxhciB2YWx1ZS4KICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyBhIG5ldyBWZWMzLgogICAgICAgICAqLwogICAgICAgIHNjYWxlKHNjYWxhcikgewogICAgICAgICAgICByZXR1cm4gbmV3IFF1YXQodGhpcy54ICogc2NhbGFyLCB0aGlzLnkgKiBzY2FsYXIsIHRoaXMueiAqIHNjYWxhciwgdGhpcy53ICogc2NhbGFyKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU2NhbGVzIHRoaXMgUXVhdCBieSBzY2FsYXIuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gc2NhbGFyIC0gVGhlIHNjYWxhciB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBzY2FsZUluUGxhY2Uoc2NhbGFyKSB7CiAgICAgICAgICAgIHRoaXMueCAqPSBzY2FsYXI7CiAgICAgICAgICAgIHRoaXMueSAqPSBzY2FsYXI7CiAgICAgICAgICAgIHRoaXMueiAqPSBzY2FsYXI7CiAgICAgICAgICAgIHRoaXMudyAqPSBzY2FsYXI7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENhbGN1bGF0ZXMgdGhlIGxlbmd0aCBvZiB0aGlzIFF1YXQuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyB0aGUgbGVuZ3RoLgogICAgICAgICAqLwogICAgICAgIGxlbmd0aCgpIHsKICAgICAgICAgICAgY29uc3QgeCA9IHRoaXMueDsKICAgICAgICAgICAgY29uc3QgeSA9IHRoaXMueTsKICAgICAgICAgICAgY29uc3QgeiA9IHRoaXMuejsKICAgICAgICAgICAgY29uc3QgdyA9IHRoaXMudzsKICAgICAgICAgICAgcmV0dXJuIE1hdGguc3FydCh4ICogeCArIHkgKiB5ICsgeiAqIHogKyB3ICogdyk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENhbGN1bGF0ZXMgdGhlIHNxdWFyZWQgbGVuZ3RoIG9mIHRoaXMgUXVhdC4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIHRoZSBsZW5ndGguCiAgICAgICAgICovCiAgICAgICAgbGVuZ3RoU3F1YXJlZCgpIHsKICAgICAgICAgICAgY29uc3QgeCA9IHRoaXMueDsKICAgICAgICAgICAgY29uc3QgeSA9IHRoaXMueTsKICAgICAgICAgICAgY29uc3QgeiA9IHRoaXMuejsKICAgICAgICAgICAgY29uc3QgdyA9IHRoaXMudzsKICAgICAgICAgICAgcmV0dXJuIHggKiB4ICsgeSAqIHkgKyB6ICogeiArIHcgKiB3OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBOb3JtYWxpemVzIHRoZSBRdWF0IGFuZCByZXR1cm5zIGl0IGFzIGEgbmV3IFF1YXQuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyB0aGUgUXVhdCBub3JtYWxpemVkLgogICAgICAgICAqLwogICAgICAgIG5vcm1hbGl6ZSgpIHsKICAgICAgICAgICAgY29uc3QgeCA9IHRoaXMueDsKICAgICAgICAgICAgY29uc3QgeSA9IHRoaXMueTsKICAgICAgICAgICAgY29uc3QgeiA9IHRoaXMuejsKICAgICAgICAgICAgY29uc3QgdyA9IHRoaXMudzsKICAgICAgICAgICAgbGV0IGxlbiA9IHggKiB4ICsgeSAqIHkgKyB6ICogeiArIHcgKiB3OwogICAgICAgICAgICBpZiAobGVuIDwgTnVtYmVyLkVQU0lMT04pIHsKICAgICAgICAgICAgICAgIHJldHVybiBuZXcgUXVhdCgpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIC8vIFRPRE86IGV2YWx1YXRlIHVzZSBvZiBnbG1faW52c3FydCBoZXJlPwogICAgICAgICAgICBsZW4gPSAxIC8gTWF0aC5zcXJ0KGxlbik7CiAgICAgICAgICAgIHJldHVybiBuZXcgUXVhdCh4ICogbGVuLCB5ICogbGVuLCB6ICogbGVuLCB3ICogbGVuKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogTm9ybWFsaXplcyB0aGUgUXVhdCwgbW9kaWZ5aW5nIGl0cyB2YWx1ZXMgaW4gcGxhY2UuCiAgICAgICAgICovCiAgICAgICAgbm9ybWFsaXplSW5QbGFjZSgpIHsKICAgICAgICAgICAgY29uc3QgeCA9IHRoaXMueDsKICAgICAgICAgICAgY29uc3QgeSA9IHRoaXMueTsKICAgICAgICAgICAgY29uc3QgeiA9IHRoaXMuejsKICAgICAgICAgICAgY29uc3QgdyA9IHRoaXMudzsKICAgICAgICAgICAgbGV0IGxlbiA9IHggKiB4ICsgeSAqIHkgKyB6ICogeiArIHcgKiB3OwogICAgICAgICAgICBpZiAobGVuIDwgTnVtYmVyLkVQU0lMT04pIHsKICAgICAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgICAgfQogICAgICAgICAgICBsZW4gPSAxIC8gTWF0aC5zcXJ0KGxlbik7CiAgICAgICAgICAgIHRoaXMuc2V0KHggKiBsZW4sIHkgKiBsZW4sIHogKiBsZW4sIHcgKiBsZW4pOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDYWxjdWxhdGVzIHRoZSBkb3QgcHJvZHVjdCBvZiB0aGlzIHF1YXQgYWdhaW5zdCBhbm90aGVyLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIG90aGVyIC0gVGhlIG90aGVyIFF1YXQgdG8gY29tcGFyZSB3aXRoLgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIHRoZSBkb3QgcHJvZHVjdC4KICAgICAgICAgKi8KICAgICAgICBkb3Qob3RoZXIpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMueCAqIG90aGVyLnggKyB0aGlzLnkgKiBvdGhlci55ICsgdGhpcy56ICogb3RoZXIueiArIHRoaXMudyAqIG90aGVyLnc7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENhbGN1bGF0ZXMgdGhlIGNyb3NzIHByb2R1Y3Qgb2YgdHdvIFF1YXRzIGFuZCByZXR1cm5zIHRoZSByZXN1bHQgYXMgYSBuZXcgUXVhdC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBvdGhlciAtIFRoZSBvdGhlciBRdWF0IHRvIGNhbGN1bGF0ZSB3aXRoLgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIHRoZSBjcm9zcyBwcm9kdWN0IGFzIGEgbmV3IFF1YXQuCiAgICAgICAgICovCiAgICAgICAgY3Jvc3Mob3RoZXIpIHsKICAgICAgICAgICAgY29uc3QgYXggPSB0aGlzLng7CiAgICAgICAgICAgIGNvbnN0IGF5ID0gdGhpcy55OwogICAgICAgICAgICBjb25zdCBheiA9IHRoaXMuejsKICAgICAgICAgICAgY29uc3QgYXQgPSB0aGlzLnc7CiAgICAgICAgICAgIGNvbnN0IGJ4ID0gb3RoZXIueDsKICAgICAgICAgICAgY29uc3QgYnkgPSBvdGhlci55OwogICAgICAgICAgICBjb25zdCBieiA9IG90aGVyLno7CiAgICAgICAgICAgIGNvbnN0IGJ0ID0gb3RoZXIudzsKICAgICAgICAgICAgcmV0dXJuIG5ldyBRdWF0KGF5ICogYnogLSBheiAqIGJ5LCBheiAqIGJ0IC0gYXQgKiBieiwgYXQgKiBieCAtIGF4ICogYnQsIGF4ICogYnkgLSBheSAqIGJ4KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyB0aGUgcm90YXRpb25hbCBjb25qdWdhdGUgb2YgdGhpcyBRdWF0LgogICAgICAgICAqIENvbmp1Z2F0aW9uIHJlcHJlc2VudHMgdGhlIHNhbWUgcm90YXRpb24gb2YgdGhlIFF1YXQgYnV0CiAgICAgICAgICogaW4gdGhlIG9wcG9zaXRlIGRpcmVjdGlvbiBhcm91bmQgdGhlIHJvdGF0aW9uYWwgYXhpcy4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSB0aGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGNvbmp1Z2F0ZSgpIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBRdWF0KC10aGlzLngsIC10aGlzLnksIC10aGlzLnosIHRoaXMudyk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybiB0aGUgaW52ZXJzZSBvZiB0aGUgYFF1YXRgCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyBhIG5ldyBRdWF0LgogICAgICAgICAqLwogICAgICAgIGludmVyc2UoKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLmNvbmp1Z2F0ZSgpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBBbGlnbnMgdGhpcyBxdWF0ZXJuaW9uIHdpdGggYW5vdGhlciBvbmUgZW5zdXJpbmcgdGhhdCB0aGUgZGVsdGEgYmV0d2VlbgogICAgICAgICAqIHRoZSBRdWF0IHZhbHVlcyBpcyB0aGUgc2hvcnRlc3QgcGF0aCBvdmVyIHRoZSBoeXBlci1zcGhlcmUuCiAgICAgICAgICoKICAgICAgICAgKiAgQHBhcmFtIG90aGVyIC0gVGhlIG90aGVyIFF1YXQgdG8gZGl2aWRlIGJ5LgogICAgICAgICAqLwogICAgICAgIGFsaWduV2l0aChvdGhlcikgewogICAgICAgICAgICBpZiAodGhpcy5kb3Qob3RoZXIpIDwgMC4wKSB7CiAgICAgICAgICAgICAgICB0aGlzLnNldCgtdGhpcy54LCAtdGhpcy55LCAtdGhpcy56LCAtdGhpcy53KTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBNdWx0aXBsaWVzIHR3byB0aGlzIHF1YXQgYnkgYW5vdGhlciByZXR1cm5pbmcgdGhlIHJlc3VsdCBhcyBhIG5ldyBRdWF0LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIG90aGVyIC0gVGhlIG90aGVyIFF1YXQgdG8gbXVsdGlwbHkuCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgYSBuZXcgUXVhdC4KICAgICAgICAgKi8KICAgICAgICBtdWx0aXBseShvdGhlcikgewogICAgICAgICAgICBjb25zdCBheCA9IHRoaXMueDsKICAgICAgICAgICAgY29uc3QgYXkgPSB0aGlzLnk7CiAgICAgICAgICAgIGNvbnN0IGF6ID0gdGhpcy56OwogICAgICAgICAgICBjb25zdCBhdyA9IHRoaXMudzsKICAgICAgICAgICAgY29uc3QgYnggPSBvdGhlci54OwogICAgICAgICAgICBjb25zdCBieSA9IG90aGVyLnk7CiAgICAgICAgICAgIGNvbnN0IGJ6ID0gb3RoZXIuejsKICAgICAgICAgICAgY29uc3QgYncgPSBvdGhlci53OwogICAgICAgICAgICByZXR1cm4gbmV3IFF1YXQoYXggKiBidyArIGF3ICogYnggKyBheSAqIGJ6IC0gYXogKiBieSwgYXkgKiBidyArIGF3ICogYnkgKyBheiAqIGJ4IC0gYXggKiBieiwgYXogKiBidyArIGF3ICogYnogKyBheCAqIGJ5IC0gYXkgKiBieCwgYXcgKiBidyAtIGF4ICogYnggLSBheSAqIGJ5IC0gYXogKiBieik7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIE11bHRpcGxpZXMgdGhpcyBxdWF0IGJ5IGFub3RoZXIsIG1vZGlmeWluZyBpdHMgdmFsdWVzIGluIHBsYWNlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIG90aGVyIC0gVGhlIG90aGVyIFF1YXQgdG8gbXVsdGlwbHkuCiAgICAgICAgICovCiAgICAgICAgbXVsdGlwbHlJblBsYWNlKG90aGVyKSB7CiAgICAgICAgICAgIGNvbnN0IGF4ID0gdGhpcy54OwogICAgICAgICAgICBjb25zdCBheSA9IHRoaXMueTsKICAgICAgICAgICAgY29uc3QgYXogPSB0aGlzLno7CiAgICAgICAgICAgIGNvbnN0IGF3ID0gdGhpcy53OwogICAgICAgICAgICBjb25zdCBieCA9IG90aGVyLng7CiAgICAgICAgICAgIGNvbnN0IGJ5ID0gb3RoZXIueTsKICAgICAgICAgICAgY29uc3QgYnogPSBvdGhlci56OwogICAgICAgICAgICBjb25zdCBidyA9IG90aGVyLnc7CiAgICAgICAgICAgIHRoaXMuc2V0KGF4ICogYncgKyBhdyAqIGJ4ICsgYXkgKiBieiAtIGF6ICogYnksIGF5ICogYncgKyBhdyAqIGJ5ICsgYXogKiBieCAtIGF4ICogYnosIGF6ICogYncgKyBhdyAqIGJ6ICsgYXggKiBieSAtIGF5ICogYngsIGF3ICogYncgLSBheCAqIGJ4IC0gYXkgKiBieSAtIGF6ICogYnopOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSb3RhdGVzIGEgdmVjdG9yIGJ5IHRoaXMgcXVhdGVybmlvbi4KICAgICAgICAgKiBEb24ndCBmb3JnZXQgdG8gbm9ybWFsaXplIHRoZSBxdWF0ZXJuaW9uIHVubGVzcwogICAgICAgICAqIHlvdSB3YW50IGF4aWFsIHRyYW5zbGF0aW9uIGFzIHdlbGwgYXMgcm90YXRpb24uCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gdmVjMyAtIFRoZSB2ZWMzIHZhbHVlLgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGEgbmV3IFZlYzMuCiAgICAgICAgICovCiAgICAgICAgcm90YXRlVmVjMyh2ZWMzKSB7CiAgICAgICAgICAgIGNvbnN0IHZxID0gbmV3IFF1YXQodmVjMy54LCB2ZWMzLnksIHZlYzMueiwgMC4wKTsKICAgICAgICAgICAgY29uc3QgcHEgPSB0aGlzLm11bHRpcGx5KHZxKS5tdWx0aXBseSh0aGlzLmNvbmp1Z2F0ZSgpKTsKICAgICAgICAgICAgcmV0dXJuIG5ldyBWZWMzKHBxLngsIHBxLnksIHBxLnopOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTZXRzIHRoaXMgcXVhdGVybmlvbiB0byBhIHJvdGF0aW9uIGJ5IHRoZSBnaXZlbiBhbmdsZSBhYm91dCB0aGUgWCBheGlzLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHJhZCAtIEFuZ2xlIChpbiByYWRpYW5zKSB0byByb3RhdGUuCiAgICAgICAgICovCiAgICAgICAgcm90YXRlWChyYWQpIHsKICAgICAgICAgICAgcmFkICo9IDAuNTsKICAgICAgICAgICAgY29uc3QgYXggPSB0aGlzLng7CiAgICAgICAgICAgIGNvbnN0IGF5ID0gdGhpcy55OwogICAgICAgICAgICBjb25zdCBheiA9IHRoaXMuejsKICAgICAgICAgICAgY29uc3QgYXcgPSB0aGlzLnc7CiAgICAgICAgICAgIGNvbnN0IGJ4ID0gTWF0aC5zaW4ocmFkKTsKICAgICAgICAgICAgY29uc3QgYncgPSBNYXRoLmNvcyhyYWQpOwogICAgICAgICAgICB0aGlzLnggPSBheCAqIGJ3ICsgYXcgKiBieDsKICAgICAgICAgICAgdGhpcy55ID0gYXkgKiBidyArIGF6ICogYng7CiAgICAgICAgICAgIHRoaXMueiA9IGF6ICogYncgLSBheSAqIGJ4OwogICAgICAgICAgICB0aGlzLncgPSBhdyAqIGJ3IC0gYXggKiBieDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU2V0cyB0aGlzIHF1YXRlcm5pb24gdG8gYSByb3RhdGlvbiBieSB0aGUgZ2l2ZW4gYW5nbGUgYWJvdXQgdGhlIFkgYXhpcy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSByYWQgLSBBbmdsZSAoaW4gcmFkaWFucykgdG8gcm90YXRlLgogICAgICAgICAqLwogICAgICAgIHJvdGF0ZVkocmFkKSB7CiAgICAgICAgICAgIHJhZCAqPSAwLjU7CiAgICAgICAgICAgIGNvbnN0IGF4ID0gdGhpcy54OwogICAgICAgICAgICBjb25zdCBheSA9IHRoaXMueTsKICAgICAgICAgICAgY29uc3QgYXogPSB0aGlzLno7CiAgICAgICAgICAgIGNvbnN0IGF3ID0gdGhpcy53OwogICAgICAgICAgICBjb25zdCBieSA9IE1hdGguc2luKHJhZCk7CiAgICAgICAgICAgIGNvbnN0IGJ3ID0gTWF0aC5jb3MocmFkKTsKICAgICAgICAgICAgdGhpcy54ID0gYXggKiBidyAtIGF6ICogYnk7CiAgICAgICAgICAgIHRoaXMueSA9IGF5ICogYncgKyBhdyAqIGJ5OwogICAgICAgICAgICB0aGlzLnogPSBheiAqIGJ3ICsgYXggKiBieTsKICAgICAgICAgICAgdGhpcy53ID0gYXcgKiBidyAtIGF5ICogYnk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFNldHMgdGhpcyBxdWF0ZXJuaW9uIHRvIGEgcm90YXRpb24gYnkgdGhlIGdpdmVuIGFuZ2xlIGFib3V0IHRoZSBaIGF4aXMuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gcmFkIC0gQW5nbGUgKGluIHJhZGlhbnMpIHRvIHJvdGF0ZS4KICAgICAgICAgKi8KICAgICAgICByb3RhdGVaKHJhZCkgewogICAgICAgICAgICByYWQgKj0gMC41OwogICAgICAgICAgICBjb25zdCBheCA9IHRoaXMueDsKICAgICAgICAgICAgY29uc3QgYXkgPSB0aGlzLnk7CiAgICAgICAgICAgIGNvbnN0IGF6ID0gdGhpcy56OwogICAgICAgICAgICBjb25zdCBhdyA9IHRoaXMudzsKICAgICAgICAgICAgY29uc3QgYnogPSBNYXRoLnNpbihyYWQpOwogICAgICAgICAgICBjb25zdCBidyA9IE1hdGguY29zKHJhZCk7CiAgICAgICAgICAgIHRoaXMueCA9IGF4ICogYncgKyBheSAqIGJ6OwogICAgICAgICAgICB0aGlzLnkgPSBheSAqIGJ3IC0gYXggKiBiejsKICAgICAgICAgICAgdGhpcy56ID0gYXogKiBidyArIGF3ICogYno7CiAgICAgICAgICAgIHRoaXMudyA9IGF3ICogYncgLSBheiAqIGJ6OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb252ZXJ0cyB0aGlzIFF1YXQgdG8gYSBNYXQzIChhIDN4MyBtYXRyaXgpLgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFRSZXR1cm5zIGEgbmV3IE1hdDMuCiAgICAgICAgICovCiAgICAgICAgdG9NYXQzKCkgewogICAgICAgICAgICBjb25zdCB4ID0gdGhpcy54OwogICAgICAgICAgICBjb25zdCB5ID0gdGhpcy55OwogICAgICAgICAgICBjb25zdCB6ID0gdGhpcy56OwogICAgICAgICAgICBjb25zdCB3ID0gdGhpcy53OwogICAgICAgICAgICBjb25zdCB4MiA9IHggKyB4OwogICAgICAgICAgICBjb25zdCB5MiA9IHkgKyB5OwogICAgICAgICAgICBjb25zdCB6MiA9IHogKyB6OwogICAgICAgICAgICBjb25zdCB4eCA9IHggKiB4MjsKICAgICAgICAgICAgY29uc3QgeXggPSB5ICogeDI7CiAgICAgICAgICAgIGNvbnN0IHl5ID0geSAqIHkyOwogICAgICAgICAgICBjb25zdCB6eCA9IHogKiB4MjsKICAgICAgICAgICAgY29uc3QgenkgPSB6ICogeTI7CiAgICAgICAgICAgIGNvbnN0IHp6ID0geiAqIHoyOwogICAgICAgICAgICBjb25zdCB3eCA9IHcgKiB4MjsKICAgICAgICAgICAgY29uc3Qgd3kgPSB3ICogeTI7CiAgICAgICAgICAgIGNvbnN0IHd6ID0gdyAqIHoyOwogICAgICAgICAgICBjb25zdCBtYXQzID0gbmV3IE1hdDMoKTsKICAgICAgICAgICAgbWF0My5tMDAgPSAxIC0geXkgLSB6ejsKICAgICAgICAgICAgbWF0My5tMTAgPSB5eCAtIHd6OwogICAgICAgICAgICBtYXQzLm0yMCA9IHp4ICsgd3k7CiAgICAgICAgICAgIG1hdDMubTAxID0geXggKyB3ejsKICAgICAgICAgICAgbWF0My5tMTEgPSAxIC0geHggLSB6ejsKICAgICAgICAgICAgbWF0My5tMjEgPSB6eSAtIHd4OwogICAgICAgICAgICBtYXQzLm0wMiA9IHp4IC0gd3k7CiAgICAgICAgICAgIG1hdDMubTEyID0genkgKyB3eDsKICAgICAgICAgICAgbWF0My5tMjIgPSAxIC0geHggLSB5eTsKICAgICAgICAgICAgcmV0dXJuIG1hdDM7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENhbGN1bGF0ZXMgYSBWZWMzIHZhbHVlIGFsaWduZWQgd2l0aCB0aGUgWCBheGlzIG9mIHRoaXMgcXVhdGVybmlvbi4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmVzdWx0aW5nIFZlYzMgdmFsdWUKICAgICAgICAgKi8KICAgICAgICBnZXRYYXhpcygpIHsKICAgICAgICAgICAgY29uc3QgeHkgPSB0aGlzLnggKiB0aGlzLnk7CiAgICAgICAgICAgIGNvbnN0IHh6ID0gdGhpcy54ICogdGhpcy56OwogICAgICAgICAgICBjb25zdCB5eSA9IHRoaXMueSAqIHRoaXMueTsKICAgICAgICAgICAgY29uc3QgeXcgPSB0aGlzLnkgKiB0aGlzLnc7CiAgICAgICAgICAgIGNvbnN0IHp6ID0gdGhpcy56ICogdGhpcy56OwogICAgICAgICAgICBjb25zdCB6dyA9IHRoaXMueiAqIHRoaXMudzsKICAgICAgICAgICAgcmV0dXJuIG5ldyBWZWMzKDEuMCAtIDIuMCAqICh6eiArIHl5KSwgMi4wICogKHh5ICsgencpLCAyLjAgKiAoeHogLSB5dykpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDYWxjdWxhdGVzIGEgVmVjMyB2YWx1ZSBhbGlnbmVkIHdpdGggdGhlIFkgYXhpcyBvZiB0aGlzIHF1YXRlcm5pb24uCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJlc3VsdGluZyBWZWMzIHZhbHVlCiAgICAgICAgICovCiAgICAgICAgZ2V0WWF4aXMoKSB7CiAgICAgICAgICAgIGNvbnN0IHh4ID0gdGhpcy54ICogdGhpcy54OwogICAgICAgICAgICBjb25zdCB4eSA9IHRoaXMueCAqIHRoaXMueTsKICAgICAgICAgICAgY29uc3QgeHcgPSB0aGlzLnggKiB0aGlzLnc7CiAgICAgICAgICAgIGNvbnN0IHl6ID0gdGhpcy55ICogdGhpcy56OwogICAgICAgICAgICBjb25zdCB6eiA9IHRoaXMueiAqIHRoaXMuejsKICAgICAgICAgICAgY29uc3QgencgPSB0aGlzLnogKiB0aGlzLnc7CiAgICAgICAgICAgIHJldHVybiBuZXcgVmVjMygyLjAgKiAoeHkgLSB6dyksIDEuMCAtIDIuMCAqICh6eiArIHh4KSwgMi4wICogKHl6ICsgeHcpKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ2FsY3VsYXRlcyBhIFZlYzMgdmFsdWUgYWxpZ25lZCB3aXRoIHRoZSBaIGF4aXMgb2YgdGhpcyBxdWF0ZXJuaW9uLgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXN1bHRpbmcgVmVjMyB2YWx1ZQogICAgICAgICAqLwogICAgICAgIGdldFpheGlzKCkgewogICAgICAgICAgICBjb25zdCB4eCA9IHRoaXMueCAqIHRoaXMueDsKICAgICAgICAgICAgY29uc3QgeHogPSB0aGlzLnggKiB0aGlzLno7CiAgICAgICAgICAgIGNvbnN0IHh3ID0gdGhpcy54ICogdGhpcy53OwogICAgICAgICAgICBjb25zdCB5eSA9IHRoaXMueSAqIHRoaXMueTsKICAgICAgICAgICAgY29uc3QgeXogPSB0aGlzLnkgKiB0aGlzLno7CiAgICAgICAgICAgIGNvbnN0IHl3ID0gdGhpcy55ICogdGhpcy53OwogICAgICAgICAgICAvLyBjb25zdCB0ZW1wID0gbmV3IFZlYzMoKQogICAgICAgICAgICByZXR1cm4gbmV3IFZlYzMoMi4wICogKHl3ICsgeHopLCAyLjAgKiAoeXogLSB4dyksIDEuMCAtIDIuMCAqICh5eSArIHh4KSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJlZmxlY3RzIHRoaXMgcXVhdGVybmlvbiBhY2NvcmRpbmcgdG8gdGhlIGF4aXMgcHJvdmlkZWQuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gYXhpc0luZGV4IC0gQW4gaW50ZWdlciB3aXRoIHZhbHVlIG9mIDAgZm9yIHRoZSBYIGF4aXMsIDEgZm9yIHRoZSBZIGF4aXMsIGFuZCAyIGZvciB0aGUgWiBheGlzLgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGEgbmV3IFF1YXQuCiAgICAgICAgICovCiAgICAgICAgbWlycm9yKGF4aXNJbmRleCkgewogICAgICAgICAgICBzd2l0Y2ggKGF4aXNJbmRleCkgewogICAgICAgICAgICAgICAgY2FzZSAwOgogICAgICAgICAgICAgICAgICAgIHJldHVybiBuZXcgUXVhdCh0aGlzLnosIHRoaXMudywgdGhpcy54LCB0aGlzLnkpOwogICAgICAgICAgICAgICAgY2FzZSAxOgogICAgICAgICAgICAgICAgICAgIHJldHVybiBuZXcgUXVhdCgtdGhpcy53LCB0aGlzLnosIHRoaXMueSwgLXRoaXMueCk7CiAgICAgICAgICAgICAgICBjYXNlIDI6CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBRdWF0KHRoaXMueCwgdGhpcy55LCB0aGlzLnosIC10aGlzLncpOwogICAgICAgICAgICAgICAgY2FzZSAwOgogICAgICAgICAgICAgICAgZGVmYXVsdDoKICAgICAgICAgICAgICAgICAgICByZXR1cm4gbmV3IFF1YXQodGhpcy56LCB0aGlzLncsIHRoaXMueCwgdGhpcy55KTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb252ZXJ0cyB0aGlzIFF1YXQgdG8gYSBNYXQ0IChhIDR4NCBtYXRyaXgpLgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgYSBuZXcgTWF0NC4KICAgICAgICAgKi8KICAgICAgICB0b01hdDQoKSB7CiAgICAgICAgICAgIGNvbnN0IHggPSB0aGlzLng7CiAgICAgICAgICAgIGNvbnN0IHkgPSB0aGlzLnk7CiAgICAgICAgICAgIGNvbnN0IHogPSB0aGlzLno7CiAgICAgICAgICAgIGNvbnN0IHcgPSB0aGlzLnc7CiAgICAgICAgICAgIGNvbnN0IHgyID0geCArIHg7CiAgICAgICAgICAgIGNvbnN0IHkyID0geSArIHk7CiAgICAgICAgICAgIGNvbnN0IHoyID0geiArIHo7CiAgICAgICAgICAgIGNvbnN0IHh4ID0geCAqIHgyOwogICAgICAgICAgICBjb25zdCB5eCA9IHkgKiB4MjsKICAgICAgICAgICAgY29uc3QgeXkgPSB5ICogeTI7CiAgICAgICAgICAgIGNvbnN0IHp4ID0geiAqIHgyOwogICAgICAgICAgICBjb25zdCB6eSA9IHogKiB5MjsKICAgICAgICAgICAgY29uc3QgenogPSB6ICogejI7CiAgICAgICAgICAgIGNvbnN0IHd4ID0gdyAqIHgyOwogICAgICAgICAgICBjb25zdCB3eSA9IHcgKiB5MjsKICAgICAgICAgICAgY29uc3Qgd3ogPSB3ICogejI7CiAgICAgICAgICAgIC8vIFNldCB0aGUgY29sdW1ucwogICAgICAgICAgICBjb25zdCBtYXQ0ID0gbmV3IE1hdDQoKTsKICAgICAgICAgICAgbWF0NC5tMDAgPSAxIC0geXkgLSB6ejsKICAgICAgICAgICAgbWF0NC5tMTAgPSB5eCAtIHd6OwogICAgICAgICAgICBtYXQ0Lm0yMCA9IHp4ICsgd3k7CiAgICAgICAgICAgIG1hdDQubTAxID0geXggKyB3ejsKICAgICAgICAgICAgbWF0NC5tMTEgPSAxIC0geHggLSB6ejsKICAgICAgICAgICAgbWF0NC5tMjEgPSB6eSAtIHd4OwogICAgICAgICAgICBtYXQ0Lm0wMiA9IHp4IC0gd3k7CiAgICAgICAgICAgIG1hdDQubTEyID0genkgKyB3eDsKICAgICAgICAgICAgbWF0NC5tMjIgPSAxIC0geHggLSB5eTsKICAgICAgICAgICAgcmV0dXJuIG1hdDQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFBlcmZvcm1zIGEgbGluZWFyIGludGVycG9sYXRpb24gb2YgdGhpcyBRdWF0IHRvd2FyZHMgYW5vdGhlciBRdWF0LCByZXR1cm5pbmcgdGhlIHJlc3VsdCBhcyBhIG5ldyBRdWF0LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIG90aGVyICAtIFRoZSBvdGhlciBRdWF0IHRvIGludGVycG9sYXRlIHRvd2FyZHMuCiAgICAgICAgICogQHBhcmFtIHQgLSBJbnRlcnBvbGF0aW9uIHJhdGlvLgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGEgbmV3IFF1YXQuCiAgICAgICAgICovCiAgICAgICAgbGVycChvdGhlciwgdCkgewogICAgICAgICAgICBjb25zdCByZXN1bHQgPSBuZXcgUXVhdCh0aGlzLnggKyB0ICogKG90aGVyLnggLSB0aGlzLngpLCB0aGlzLnkgKyB0ICogKG90aGVyLnkgLSB0aGlzLnkpLCB0aGlzLnogKyB0ICogKG90aGVyLnogLSB0aGlzLnopLCB0aGlzLncgKyB0ICogKG90aGVyLncgLSB0aGlzLncpKTsKICAgICAgICAgICAgcmVzdWx0Lm5vcm1hbGl6ZUluUGxhY2UoKTsKICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUGVyZm9ybXMgYSBzcGhlcmljYWwgbGluZWFyIGludGVycG9sYXRpb24gb2YgdGhpcyBRdWF0IHRvd2FyZHMgYW5vdGhlciBRdWF0LCByZXR1cm5pbmcgdGhlIHJlc3VsdCBhcyBhIG5ldyBRdWF0LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIG90aGVyIC0gVGhlIG90aGVyIFF1YXQgdG8gaW50ZXJwb2xhdGUgdG93YXJkcy4KICAgICAgICAgKiBAcGFyYW0gdCAtIEludGVycG9sYXRpb24gYW1vdW50IGJldHdlZW4gdGhlIHR3byBpbnB1dHMuCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgYSBuZXcgUXVhdC4KICAgICAgICAgKi8KICAgICAgICBzbGVycChvdGhlciwgbGFtYmRhKSB7CiAgICAgICAgICAgIC8vLyBodHRwczovL3d3dy5nZW9tZXRyaWN0b29scy5jb20vRG9jdW1lbnRhdGlvbi9GYXN0QW5kQWNjdXJhdGVTbGVycC5wZGYKICAgICAgICAgICAgY29uc3QgZG90UHJvZHVjdCA9IHRoaXMuZG90KG90aGVyKTsKICAgICAgICAgICAgaWYgKGRvdFByb2R1Y3QgPiAwLjk5OSkKICAgICAgICAgICAgICAgIHJldHVybiB0aGlzOwogICAgICAgICAgICAvLyBhbGdvcml0aG0gYWRhcHRlZCBmcm9tIFNob2VtYWtlJ3MgcGFwZXIKICAgICAgICAgICAgLy8gbGFtYmRhIGlzIGluICgwLCDPgC8yXQogICAgICAgICAgICBjb25zdCB0aGV0YSA9IE1hdGguYWNvcyhkb3RQcm9kdWN0KTsKICAgICAgICAgICAgY29uc3Qgc3QgPSBNYXRoLnNpbih0aGV0YSk7CiAgICAgICAgICAgIGNvbnN0IHN1dCA9IE1hdGguc2luKGxhbWJkYSAqIHRoZXRhKTsKICAgICAgICAgICAgY29uc3Qgc291dCA9IE1hdGguc2luKCgxIC0gbGFtYmRhKSAqIHRoZXRhKTsKICAgICAgICAgICAgY29uc3QgY29lZmYxID0gc291dCAvIHN0OwogICAgICAgICAgICBjb25zdCBjb2VmZjIgPSBzdXQgLyBzdDsKICAgICAgICAgICAgY29uc3QgcmVzdWx0ID0gbmV3IFF1YXQoY29lZmYxICogdGhpcy54ICsgY29lZmYyICogb3RoZXIueCwgY29lZmYxICogdGhpcy55ICsgY29lZmYyICogb3RoZXIueSwgY29lZmYxICogdGhpcy56ICsgY29lZmYyICogb3RoZXIueiwgY29lZmYxICogdGhpcy53ICsgY29lZmYyICogb3RoZXIudyk7CiAgICAgICAgICAgIHJlc3VsdC5ub3JtYWxpemVJblBsYWNlKCk7CiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENsb25lcyB0aGlzIFF1YXQgYW5kIHJldHVybnMgYSBuZXcgUXVhdC4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGEgbmV3IFF1YXQuCiAgICAgICAgICovCiAgICAgICAgY2xvbmUoKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgUXVhdCh0aGlzLngsIHRoaXMueSwgdGhpcy56LCB0aGlzLncpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIHRoZSB0eXBlIGFzIGFuIGFycmF5LiBPZnRlbiB1c2VkIHRvIHBhc3MgdHlwZXMgdG8gdGhlIEdQVS4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGFzIGFuIGFycmF5LgogICAgICAgICAqLwogICAgICAgIGFzQXJyYXkoKSB7CiAgICAgICAgICAgIHJldHVybiBbdGhpcy54LCB0aGlzLnksIHRoaXMueiwgdGhpcy53XTsKICAgICAgICB9CiAgICAgICAgZnJvbUFycmF5KGFycmF5KSB7CiAgICAgICAgICAgIHRoaXMueCA9IGFycmF5WzBdOwogICAgICAgICAgICB0aGlzLnkgPSBhcnJheVsxXTsKICAgICAgICAgICAgdGhpcy56ID0gYXJyYXlbMl07CiAgICAgICAgICAgIHRoaXMudyA9IGFycmF5WzNdOwogICAgICAgIH0KICAgICAgICAvLyAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KICAgICAgICAvLyBQZXJzaXN0ZW5jZQogICAgICAgIC8qKgogICAgICAgICAqIENvbnZlcnRzIHRoaXMgVmVjMyB0byBhIHN0cmluZyBpbiBKU09OIGZvcm1hdC4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHRvU3RyaW5nKCkgewogICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbmV3LWNhcAogICAgICAgICAgICByZXR1cm4gU3RyaW5nRnVuY3Rpb25zLnN0cmluZ2lmeUpTT05XaXRoRml4ZWRQcmVjaXNpb24odGhpcy50b0pTT04oKSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSB0b0pTT04gbWV0aG9kIGVuY29kZXMgdGhpcyB0eXBlIGFzIGEganNvbiBvYmplY3QgZm9yIHBlcnNpc3RlbmNlLgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFRoZSBqc29uIG9iamVjdC4KICAgICAgICAgKi8KICAgICAgICB0b0pTT04oKSB7CiAgICAgICAgICAgIHJldHVybiB7CiAgICAgICAgICAgICAgICB4OiB0aGlzLngsCiAgICAgICAgICAgICAgICB5OiB0aGlzLnksCiAgICAgICAgICAgICAgICB6OiB0aGlzLnosCiAgICAgICAgICAgICAgICB3OiB0aGlzLncsCiAgICAgICAgICAgIH07CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBmcm9tSlNPTiBtZXRob2QgZGVjb2RlcyBhIGpzb24gb2JqZWN0IGZvciB0aGlzIHR5cGUuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gaiAtIFRoZSBqc29uIG9iamVjdC4KICAgICAgICAgKi8KICAgICAgICBmcm9tSlNPTihqKSB7CiAgICAgICAgICAgIHRoaXMueCA9IGoueDsKICAgICAgICAgICAgdGhpcy55ID0gai55OwogICAgICAgICAgICB0aGlzLnogPSBqLno7CiAgICAgICAgICAgIHRoaXMudyA9IGoudzsKICAgICAgICAgICAgdGhpcy5ub3JtYWxpemVJblBsYWNlKCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIExvYWRzIHRoZSBzdGF0ZSBvZiB0aGUgdmFsdWUgZnJvbSBhIGJpbmFyeSByZWFkZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gcmVhZGVyIC0gVGhlIHJlYWRlciB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICByZWFkQmluYXJ5KHJlYWRlcikgewogICAgICAgICAgICB0aGlzLnggPSByZWFkZXIubG9hZEZsb2F0MzIoKTsKICAgICAgICAgICAgdGhpcy55ID0gcmVhZGVyLmxvYWRGbG9hdDMyKCk7CiAgICAgICAgICAgIHRoaXMueiA9IHJlYWRlci5sb2FkRmxvYXQzMigpOwogICAgICAgICAgICB0aGlzLncgPSByZWFkZXIubG9hZEZsb2F0MzIoKTsKICAgICAgICB9CiAgICB9CgogICAgLyogZXNsaW50LWRpc2FibGUgbm8tdW51c2VkLXZhcnMgKi8KICAgIC8qKgogICAgICogQ2xhc3MgcmVwcmVzZW50aW5nIGFuIFhmbyB0cmFuc2Zvcm0sIHdoaWNoIGlzIGEgdHJhbnNmb3JtYXRpb24gZGVjb21wb3NlZCBpbnRvIDMgY29tcG9uZW50IHZhbHVlcy4gVHJhbnNsYXRpb24sIE9yaWVudGF0aW9uLCBhbmQgU2NhbGluZy4KICAgICAqLwogICAgY2xhc3MgWGZvIHsKICAgICAgICB0cjsKICAgICAgICBvcmk7CiAgICAgICAgc2M7CiAgICAgICAgLyoqCiAgICAgICAgICogSW5pdGlhbGl6ZXMgdGhlIFhmbyBvYmplY3QuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gdHIgLSBUaGUgdHJhbnNsYXRpb24gdmFsdWUuCiAgICAgICAgICogQHBhcmFtIG9yaSAtIFRoZSBvcmllbnRhdGlvbiB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0gc2MgLSBUaGUgc2NhbGluZyB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBjb25zdHJ1Y3Rvcih0ciA9IG5ldyBWZWMzKCksIG9yaSA9IG5ldyBRdWF0KCksIHNjID0gbmV3IFZlYzMoMSwgMSwgMSkpIHsKICAgICAgICAgICAgdGhpcy50ciA9IHRyOwogICAgICAgICAgICB0aGlzLm9yaSA9IG9yaTsKICAgICAgICAgICAgdGhpcy5zYyA9IHNjOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTZXRzIHRoZSBzdGF0ZSBvZiB0aGUgWGZvIG9iamVjdC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB0ciAtIFRoZSB0cmFuc2xhdGlvbiB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0gb3JpIC0gVGhlIG9yaWVudGF0aW9uIHZhbHVlLgogICAgICAgICAqIEBwYXJhbSBzYyAtIFRoZSBzY2FsaW5nIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHNldCh0ciwgb3JpLCBzYykgewogICAgICAgICAgICB0aGlzLnRyID0gdHI7CiAgICAgICAgICAgIHRoaXMub3JpID0gb3JpOwogICAgICAgICAgICBpZiAoc2MgaW5zdGFuY2VvZiBWZWMzKQogICAgICAgICAgICAgICAgdGhpcy5zYyA9IHNjOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTZXRzIHRoZSBzdGF0ZSBvZiB0aGUgWGZvIG9iamVjdCB1c2luZyBhbm90aGVyIFhmbyBvYmplY3QuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gb3RoZXIgLSBUaGUgb3RoZXIgWGZvIHRvIHNldCBmcm9tLgogICAgICAgICAqLwogICAgICAgIHNldEZyb21PdGhlcihvdGhlcikgewogICAgICAgICAgICB0aGlzLnRyID0gb3RoZXIudHI7CiAgICAgICAgICAgIHRoaXMub3JpID0gb3RoZXIub3JpOwogICAgICAgICAgICB0aGlzLnNjID0gb3RoZXIuc2M7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFZlcmlmaWVzIHRoYXQgdGhlIFhmbyBvYmplY3QgaXMgYW4gYGlkZW50aXR5YCwgY2hlY2tpbmcgdGhhdCB0aGUgdHJhbnNsYXRpb24sIG9yaWVudGF0aW9uIGFuZCBzY2FsaW5nIGF0dHJpYnV0ZXMgYXJlIGluIHRoZWlyIGluaXRpYWwgc3RhdGUuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBpc0lkZW50aXR5KCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy50ci5pc051bGwoKSAmJiB0aGlzLm9yaS5pc0lkZW50aXR5KCkgJiYgdGhpcy5zYy5pczExMSgpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDaGVja3MgaWYgdGhpcyBWZWMzIGNvbnRhaW5zIHRoZSBzYW1lIHZhbHVlcyBhcyB0aGUgb3RoZXIgVmVjMy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBvdGhlciAtIFRoZSBvdGhlciBWZWMzIHRvIGNvbXBhcmUgd2l0aC4KICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyBgdHJ1ZWAgaWYgYXJlIHRoZSBzYW1lIFZlY3Rvciwgb3RoZXJ3aXNlLCBgZmFsc2VgLgogICAgICAgICAqLwogICAgICAgIGlzRXF1YWwob3RoZXIpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMudHIuaXNFcXVhbChvdGhlci50cikgJiYgdGhpcy5vcmkuaXNFcXVhbChvdGhlci5vcmkpICYmIHRoaXMuc2MuaXNFcXVhbChvdGhlci5zYyk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgdHJ1ZSBpZiB0aGlzIFZlYzIgaXMgYXBwcm94aW1hdGVseSB0aGUgc2FtZSBhcyBvdGhlci4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBvdGhlciAtIFRoZSBvdGhlciBWZWMzIHRvIGNvbXBhcmUgd2l0aC4KICAgICAgICAgKiBAcGFyYW0gcHJlY2lzaW9uIC0gVGhlIHByZWNpc2lvbiB0byB3aGljaCB0aGUgdmFsdWVzIG11c3QgbWF0Y2guCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgdHJ1ZSBvciBmYWxzZS4KICAgICAgICAgKi8KICAgICAgICBhcHByb3hFcXVhbChvdGhlciwgcHJlY2lzaW9uID0gTnVtYmVyLkVQU0lMT04pIHsKICAgICAgICAgICAgcmV0dXJuICgob3RoZXIudHIgPyB0aGlzLnRyLmFwcHJveEVxdWFsKG90aGVyLnRyLCBwcmVjaXNpb24pIDogdHJ1ZSkgJiYKICAgICAgICAgICAgICAgIChvdGhlci5vcmkgPyB0aGlzLm9yaS5hcHByb3hFcXVhbChvdGhlci5vcmksIHByZWNpc2lvbikgOiB0cnVlKSAmJgogICAgICAgICAgICAgICAgKG90aGVyLnNjID8gdGhpcy5zYy5hcHByb3hFcXVhbChvdGhlci5zYywgcHJlY2lzaW9uKSA6IHRydWUpKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIHNldExvb2tBdCBtZXRob2QuCiAgICAgICAgICogQHBhcmFtIHBvcyAtIFRoZSBwb3NpdGlvbiB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0gdGFyZ2V0IC0gVGhlIHRhcmdldCB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0gdXAgLSBUaGUgdXAgdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgc2V0TG9va0F0KHBvcywgdGFyZ2V0LCB1cCkgewogICAgICAgICAgICAvLyBOb3RlOiBXZSBsb29rIGFsb25nIHRoZSAteiBheGlzLiBOZWdhdGUgdGhlIGRpcmVjdGlvbi4KICAgICAgICAgICAgY29uc3QgZGlyID0gcG9zLnN1YnRyYWN0KHRhcmdldCk7CiAgICAgICAgICAgIGNvbnN0IGRpckxlbiA9IGRpci5sZW5ndGgoKTsKICAgICAgICAgICAgaWYgKGRpckxlbiA8IE51bWJlci5FUFNJTE9OKSB7CiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgZGlyJyk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdGhpcy5vcmkuc2V0RnJvbURpcmVjdGlvbkFuZFVwdmVjdG9yKGRpciwgdXApOwogICAgICAgICAgICB0aGlzLnRyID0gcG9zOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBNdWx0aXBsaWVzIHR3byBYZm8gdHJhbnNmb3Jtcy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB4Zm8gLSBUaGUgeGZvIHRvIG11bHRpcGx5IHdpdGguCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgYW4gWGZvLgogICAgICAgICAqLwogICAgICAgIG11bHRpcGx5KHhmbykgewogICAgICAgICAgICBsZXQgdGhpc19zYyA9IHRoaXMuc2M7CiAgICAgICAgICAgIC8vIGNoZWNrIGZvciBub24tdW5pZm9ybSBzY2FsZS4KICAgICAgICAgICAgaWYgKE1hdGguYWJzKHRoaXMuc2MueSAtIHRoaXMuc2MueCkgPiAwLjAwMSB8fAogICAgICAgICAgICAgICAgTWF0aC5hYnModGhpcy5zYy56IC0gdGhpcy5zYy54KSA+IDAuMDAxIHx8CiAgICAgICAgICAgICAgICBNYXRoLmFicyh0aGlzLnNjLnogLSB0aGlzLnNjLnkpID4gMC4wMDEpIHsKICAgICAgICAgICAgICAgIGNvbnN0IHRoaXNfbWF0NCA9IHRoaXMudG9NYXQ0KCk7CiAgICAgICAgICAgICAgICBjb25zdCBvdGhlcl9tYXQ0ID0geGZvLm9yaS50b01hdDQoKTsKICAgICAgICAgICAgICAgIGNvbnN0IHJlc000ID0gdGhpc19tYXQ0Lm11bHRpcGx5KG90aGVyX21hdDQpOwogICAgICAgICAgICAgICAgdGhpc19zYyA9IG5ldyBWZWMzKHJlc000LnhBeGlzLmxlbmd0aCgpLCByZXNNNC55QXhpcy5sZW5ndGgoKSwgcmVzTTQuekF4aXMubGVuZ3RoKCkpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IG5ldyBYZm8odGhpcy50ci5hZGQodGhpcy5vcmkucm90YXRlVmVjMyh0aGlzLnNjLm11bHRpcGx5KHhmby50cikpKSwgdGhpcy5vcmkubXVsdGlwbHkoeGZvLm9yaSksIHRoaXNfc2MubXVsdGlwbHkoeGZvLnNjKSk7CiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgdGhlIGludmVyc2Ugb2YgdGhlIFhmbyBvYmplY3QsIGJ1dCByZXR1cm5zLiB0aGUgcmVzdWx0IGFzIGEgbmV3IFhmby4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGEgbmV3IFhmby4KICAgICAgICAgKi8KICAgICAgICBpbnZlcnNlKCkgewogICAgICAgICAgICBjb25zdCByZXN1bHQgPSBuZXcgWGZvKCk7CiAgICAgICAgICAgIHJlc3VsdC5vcmkgPSB0aGlzLm9yaS5pbnZlcnNlKCk7CiAgICAgICAgICAgIC8vIGNoZWNrIGZvciBub24tdW5pZm9ybSBzY2FsZS4KICAgICAgICAgICAgaWYgKE1hdGguYWJzKHRoaXMuc2MueSAtIHRoaXMuc2MueCkgPiAwLjAwMSB8fAogICAgICAgICAgICAgICAgTWF0aC5hYnModGhpcy5zYy56IC0gdGhpcy5zYy54KSA+IDAuMDAxIHx8CiAgICAgICAgICAgICAgICBNYXRoLmFicyh0aGlzLnNjLnogLSB0aGlzLnNjLnkpID4gMC4wMDEpIHsKICAgICAgICAgICAgICAgIGNvbnN0IHRoaXNfbWF0NCA9IHRoaXMudG9NYXQ0KCkuaW52ZXJzZSgpOwogICAgICAgICAgICAgICAgcmVzdWx0LnNjID0gbmV3IFZlYzModGhpc19tYXQ0LnhBeGlzLmxlbmd0aCgpLCB0aGlzX21hdDQueUF4aXMubGVuZ3RoKCksIHRoaXNfbWF0NC56QXhpcy5sZW5ndGgoKSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZWxzZSB7CiAgICAgICAgICAgICAgICByZXN1bHQuc2MgPSB0aGlzLnNjLmludmVyc2UoKTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXN1bHQudHIgPSByZXN1bHQub3JpLnJvdGF0ZVZlYzModGhpcy50ci5uZWdhdGUoKS5tdWx0aXBseShyZXN1bHQuc2MpKTsKICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVHJhbnNmb3JtcyBYZm8gb2JqZWN0IHVzaW5nIGEgYFZlYzNgIG9iamVjdC4gRmlyc3Qgc2NhbGluZyBpdCwgdGhlbiByb3RhdGluZyBhbmQgZmluYWxseSBhZGRpbmcgdGhlIHJlc3VsdCB0byBjdXJyZW50IHRyYW5zbGF0aW9uIG9iamVjdC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB2ZWMzIC0gVGhlIHZlYzMgdmFsdWUuCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgdHJhbnNmb3JtVmVjMyh2ZWMzKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLnRyLmFkZCh0aGlzLm9yaS5yb3RhdGVWZWMzKHRoaXMuc2MubXVsdGlwbHkodmVjMykpKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUGVyZm9ybXMgYSBsaW5lYXIgaW50ZXJwb2xhdGlvbiBiZXR3ZWVuIHRoaXMgWGZvIGFuZCBvdGhlci4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBvdGhlciAtIFRoZSBvdGhlciBYZm8gdG8gaW50ZXJwb2xhdGUgdG93YXJkcy4KICAgICAgICAgKiBAcGFyYW0gdCAtIEludGVycG9sYXRpb24gcmF0aW8uCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgYSBuZXcgWGZvLgogICAgICAgICAqLwogICAgICAgIGxlcnAob3RoZXIsIHQpIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBYZm8odGhpcy50ci5sZXJwKG90aGVyLnRyLCB0KSwgdGhpcy5vcmkuc2xlcnAob3RoZXIub3JpLCB0KSwgdGhpcy5zYy5sZXJwKG90aGVyLnNjLCB0KSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbnZlcnRzIHRoaXMgWGZvIHRvIGEgTWF0NCAoYSA0eDQgbWF0cml4KS4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGEgbmV3IE1hdDQuCiAgICAgICAgICovCiAgICAgICAgdG9NYXQ0KCkgewogICAgICAgICAgICBjb25zdCBzY2wgPSBuZXcgTWF0NCh0aGlzLnNjLngsIDAsIDAsIDAsIDAsIHRoaXMuc2MueSwgMCwgMCwgMCwgMCwgdGhpcy5zYy56LCAwLCAwLCAwLCAwLCAxLjApOwogICAgICAgICAgICBjb25zdCByb3QgPSB0aGlzLm9yaS50b01hdDQoKTsKICAgICAgICAgICAgY29uc3QgdHJuID0gbmV3IE1hdDQoKTsKICAgICAgICAgICAgdHJuLnRyYW5zbGF0aW9uID0gdGhpcy50cjsKICAgICAgICAgICAgcmV0dXJuIHRybi5tdWx0aXBseShyb3QpLm11bHRpcGx5KHNjbCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFNldHMgdGhlIHN0YXRlIG9mIHRoZSBYZm8gb2JqZWN0IHVzaW5nIE1hdDQuCiAgICAgICAgICogQHBhcmFtIG1hdDQgLSBUaGUgbWF0NCB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBzZXRGcm9tTWF0NChtYXQ0KSB7CiAgICAgICAgICAgIHRoaXMudHIgPSBtYXQ0LnRyYW5zbGF0aW9uOwogICAgICAgICAgICB0aGlzLm9yaS5zZXRGcm9tTWF0NChtYXQ0KTsKICAgICAgICAgICAgdGhpcy5zYy5zZXQobWF0NC54QXhpcy5sZW5ndGgoKSwgbWF0NC55QXhpcy5sZW5ndGgoKSwgbWF0NC56QXhpcy5sZW5ndGgoKSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENsb25lcyB0aGlzIFhmbyBhbmQgcmV0dXJucyBhIG5ldyBYZm8uCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyBhIG5ldyBYZm8uCiAgICAgICAgICovCiAgICAgICAgY2xvbmUoKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgWGZvKHRoaXMudHIuY2xvbmUoKSwgdGhpcy5vcmkuY2xvbmUoKSwgdGhpcy5zYy5jbG9uZSgpKTsKICAgICAgICB9CiAgICAgICAgLy8gLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCiAgICAgICAgLy8gUGVyc2lzdGVuY2UKICAgICAgICAvKioKICAgICAgICAgKiBUaGUgdG9KU09OIG1ldGhvZCBlbmNvZGVzIHRoaXMgdHlwZSBhcyBhIGpzb24gb2JqZWN0IGZvciBwZXJzaXN0ZW5jZS4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBUaGUganNvbiBvYmplY3QuCiAgICAgICAgICovCiAgICAgICAgdG9KU09OKCkgewogICAgICAgICAgICBjb25zdCBqID0gewogICAgICAgICAgICAgICAgdHI6IHRoaXMudHIudG9KU09OKCksCiAgICAgICAgICAgICAgICBvcmk6IHRoaXMub3JpLnRvSlNPTigpLAogICAgICAgICAgICAgICAgc2M6IHRoaXMuc2MudG9KU09OKCksCiAgICAgICAgICAgIH07CiAgICAgICAgICAgIHJldHVybiBqOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgZnJvbUpTT04gbWV0aG9kIGRlY29kZXMgYSBqc29uIG9iamVjdCBmb3IgdGhpcyB0eXBlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGogLSBUaGUganNvbiBvYmplY3QuCiAgICAgICAgICovCiAgICAgICAgZnJvbUpTT04oaikgewogICAgICAgICAgICB0aGlzLnRyLmZyb21KU09OKGoudHIpOwogICAgICAgICAgICB0aGlzLm9yaS5mcm9tSlNPTihqLm9yaSk7CiAgICAgICAgICAgIGlmIChqLnNjKSB7CiAgICAgICAgICAgICAgICB0aGlzLnNjLmZyb21KU09OKGouc2MpOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIExvYWRzIHRoZSBzdGF0ZSBvZiB0aGUgdmFsdWUgZnJvbSBhIGJpbmFyeSByZWFkZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gcmVhZGVyIC0gVGhlIHJlYWRlciB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICByZWFkQmluYXJ5KHJlYWRlcikgewogICAgICAgICAgICB0aGlzLnRyLnJlYWRCaW5hcnkocmVhZGVyKTsKICAgICAgICAgICAgdGhpcy5vcmkucmVhZEJpbmFyeShyZWFkZXIpOwogICAgICAgICAgICB0aGlzLnNjLnJlYWRCaW5hcnkocmVhZGVyKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGZyb21KU09OIG1ldGhvZCBkZWNvZGVzIGEganNvbiBvYmplY3QgZm9yIHRoaXMgdHlwZS4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHRvU3RyaW5nKCkgewogICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbmV3LWNhcAogICAgICAgICAgICByZXR1cm4gU3RyaW5nRnVuY3Rpb25zLnN0cmluZ2lmeUpTT05XaXRoRml4ZWRQcmVjaXNpb24odGhpcy50b0pTT04oKSk7CiAgICAgICAgfQogICAgfQoKICAgIC8qKgogICAgICogUmVwcmVzZW50cyBhIGJveCBpbiAyRCBzcGFjZS4gTmVlZGluZyB0d28gVmVjMiB2ZWN0b3JzIGRlc2NyaWJpbmcgdGhlIGNvcm5lcnMKICAgICAqLwogICAgY2xhc3MgQm94MiB7CiAgICAgICAgcDA7CiAgICAgICAgcDE7CiAgICAgICAgLyoqCiAgICAgICAgICogQ3JlYXRlcyBhIEJveDIgb2JqZWN0IHVzaW5nIFZlYzJzLgogICAgICAgICAqIEluIGNhc2UgdGhlIHBhcmFtZXRlcnMgYXJlIG5vdCBwYXNzZWQgYnksIHRoZWlyIHZhbHVlcyBhcmUgcHJlLWRlZmluZWQ6CiAgICAgICAgICoKICAgICAgICAgKiBwMCBpcyBhIFZlYzIgd2l0aCB7QGxpbmsgaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvSmF2YVNjcmlwdC9SZWZlcmVuY2UvR2xvYmFsX09iamVjdHMvTnVtYmVyL1BPU0lUSVZFX0lORklOSVRZfGBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFlgfQogICAgICAgICAqCiAgICAgICAgICogcDEgaXMgYSBWZWMyIHdpdGgge0BsaW5rIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0phdmFTY3JpcHQvUmVmZXJlbmNlL0dsb2JhbF9PYmplY3RzL051bWJlci9ORUdBVElWRV9JTkZJTklUWXxgTnVtYmVyLk5FR0FUSVZFX0lORklOSVRZYH0KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBwMCAtIEEgcG9pbnQgcmVwcmVzZW50aW5nIHRoZSBjb3JuZXJzIG9mIGEgMkQgYm94LgogICAgICAgICAqIEBwYXJhbSBwMSAtIEEgcG9pbnQgcmVwcmVzZW50aW5nIHRoZSBjb3JuZXJzIG9mIGEgMkQgYm94LgogICAgICAgICAqLwogICAgICAgIGNvbnN0cnVjdG9yKHAwLCBwMSkgewogICAgICAgICAgICBpZiAocDAgaW5zdGFuY2VvZiBWZWMyKSB7CiAgICAgICAgICAgICAgICB0aGlzLnAwID0gcDA7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZWxzZSB7CiAgICAgICAgICAgICAgICB0aGlzLnAwID0gbmV3IFZlYzIoTnVtYmVyLlBPU0lUSVZFX0lORklOSVRZLCBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFkpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIChwMSBpbnN0YW5jZW9mIFZlYzIpIHsKICAgICAgICAgICAgICAgIHRoaXMucDEgPSBwMTsKICAgICAgICAgICAgfQogICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgIHRoaXMucDEgPSBuZXcgVmVjMihOdW1iZXIuTkVHQVRJVkVfSU5GSU5JVFksIE51bWJlci5ORUdBVElWRV9JTkZJTklUWSk7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU2V0cyBib3RoIFZlYzIgcG9pbnRzCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gcDAgLSBBIHBvaW50IHJlcHJlc2VudGluZyB0aGUgY29ybmVycyBvZiBhIDJEIGJveC4KICAgICAgICAgKiBAcGFyYW0gcDEgLSBBIHBvaW50IHJlcHJlc2VudGluZyB0aGUgY29ybmVycyBvZiBhIDJEIGJveC4KICAgICAgICAgKi8KICAgICAgICBzZXQocDAsIHAxKSB7CiAgICAgICAgICAgIHRoaXMucDAgPSBwMDsKICAgICAgICAgICAgdGhpcy5wMSA9IHAxOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXNldHMgdGhlIGJveDIgYmFjayB0byBhbiB1bmluaXRpYWxpemVkIHN0YXRlLgogICAgICAgICAqCiAgICAgICAgICogQHNlZSB7QGxpbmsgaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvSmF2YVNjcmlwdC9SZWZlcmVuY2UvR2xvYmFsX09iamVjdHMvTnVtYmVyL1BPU0lUSVZFX0lORklOSVRZfGBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFlgfQogICAgICAgICAqIGFuZCB7QGxpbmsgaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvSmF2YVNjcmlwdC9SZWZlcmVuY2UvR2xvYmFsX09iamVjdHMvTnVtYmVyL05FR0FUSVZFX0lORklOSVRZfGBOdW1iZXIuTkVHQVRJVkVfSU5GSU5JVFlgfQogICAgICAgICAqLwogICAgICAgIHJlc2V0KCkgewogICAgICAgICAgICB0aGlzLnAwLnggPSBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFk7CiAgICAgICAgICAgIHRoaXMucDEueCA9IE51bWJlci5ORUdBVElWRV9JTkZJTklUWTsKICAgICAgICAgICAgdGhpcy5wMC55ID0gTnVtYmVyLlBPU0lUSVZFX0lORklOSVRZOwogICAgICAgICAgICB0aGlzLnAxLnkgPSBOdW1iZXIuTkVHQVRJVkVfSU5GSU5JVFk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgYHRydWVgIGlmIHRoZSBib3ggaGFzIGJlZW4gZXhwYW5kZWQgdG8gY29udGFpbiBhIHBvaW50LgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgaXNWYWxpZCgpIHsKICAgICAgICAgICAgcmV0dXJuICh0aGlzLnAwLnggIT0gTnVtYmVyLlBPU0lUSVZFX0lORklOSVRZICYmCiAgICAgICAgICAgICAgICB0aGlzLnAxLnggIT0gTnVtYmVyLk5FR0FUSVZFX0lORklOSVRZICYmCiAgICAgICAgICAgICAgICB0aGlzLnAwLnkgIT0gTnVtYmVyLlBPU0lUSVZFX0lORklOSVRZICYmCiAgICAgICAgICAgICAgICB0aGlzLnAxLnkgIT0gTnVtYmVyLk5FR0FUSVZFX0lORklOSVRZKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogRXhwYW5kcyB0aGUgQm94MiB0byBjb250YWluIHRoZSBuZXcgcG9pbnQuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gcG9pbnQgLSBBIHBvaW50IHJlcHJlc2VudHMgdGhlIGNvcm5lcnMgb2YgYSAyRCBib3guCiAgICAgICAgICovCiAgICAgICAgYWRkUG9pbnQocG9pbnQpIHsKICAgICAgICAgICAgaWYgKHRoaXMucDAueCA9PSBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFkgfHwgcG9pbnQueCA8IHRoaXMucDAueCkKICAgICAgICAgICAgICAgIHRoaXMucDAueCA9IHBvaW50Lng7CiAgICAgICAgICAgIGlmICh0aGlzLnAwLnkgPT0gTnVtYmVyLlBPU0lUSVZFX0lORklOSVRZIHx8IHBvaW50LnkgPCB0aGlzLnAwLnkpCiAgICAgICAgICAgICAgICB0aGlzLnAwLnkgPSBwb2ludC55OwogICAgICAgICAgICBpZiAodGhpcy5wMS55ID09IE51bWJlci5ORUdBVElWRV9JTkZJTklUWSB8fCBwb2ludC54ID4gdGhpcy5wMS54KQogICAgICAgICAgICAgICAgdGhpcy5wMS54ID0gcG9pbnQueDsKICAgICAgICAgICAgaWYgKHRoaXMucDEueSA9PSBOdW1iZXIuTkVHQVRJVkVfSU5GSU5JVFkgfHwgcG9pbnQueSA+IHRoaXMucDEueSkKICAgICAgICAgICAgICAgIHRoaXMucDEueSA9IHBvaW50Lnk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgdGhlIGxlbmd0aCBvZiB0aGUgZGlhZ29uYWwgb2YgdGhlIGJveC4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIHRoZSBkaXN0YW5jZS4KICAgICAgICAgKi8KICAgICAgICBzaXplKCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy5wMS5kaXN0YW5jZVRvKHRoaXMucDApOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIHRoZSBzaXplIG9mIGEgQm94MiAtIHRoZSBzYW1lIGFzIHNpemUoKS4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGEgVmVjMi4KICAgICAgICAgKi8KICAgICAgICBkaWFnb25hbCgpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMucDEuc3VidHJhY3QodGhpcy5wMCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgdGhlIGNlbnRlciBwb2ludCBvZiBhIEJveDIuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyBhIFZlYzIuCiAgICAgICAgICovCiAgICAgICAgY2VudGVyKCkgewogICAgICAgICAgICBjb25zdCByZXN1bHQgPSB0aGlzLnAxLnN1YnRyYWN0KHRoaXMucDApOwogICAgICAgICAgICByZXN1bHQuc2NhbGVJblBsYWNlKDAuNSk7CiAgICAgICAgICAgIHJlc3VsdC5hZGRJblBsYWNlKHRoaXMucDApOwogICAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDbG9uZXMgdGhpcyBWZWMyIGFuZCByZXR1cm5zIGEgbmV3IFZlYzIuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyBhIG5ldyBWZWMyLgogICAgICAgICAqLwogICAgICAgIGNsb25lKCkgewogICAgICAgICAgICByZXR1cm4gbmV3IEJveDIodGhpcy5wMC5jbG9uZSgpLCB0aGlzLnAxLmNsb25lKCkpOwogICAgICAgIH0KICAgICAgICAvLyAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCiAgICAgICAgLy8gUGVyc2lzdGVuY2UKICAgICAgICAvKioKICAgICAgICAgKiBFbmNvZGVzIGBCb3gyYCBDbGFzcyBhcyBhIEpTT04gb2JqZWN0IGZvciBwZXJzaXN0ZW5jZS4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBUaGUganNvbiBvYmplY3QuCiAgICAgICAgICovCiAgICAgICAgdG9KU09OKCkgewogICAgICAgICAgICByZXR1cm4gewogICAgICAgICAgICAgICAgcDA6IHRoaXMucDAudG9KU09OKCksCiAgICAgICAgICAgICAgICBwMTogdGhpcy5wMS50b0pTT04oKSwKICAgICAgICAgICAgfTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogRGVjb2RlcyBhIEpTT04gb2JqZWN0IHRvIHNldCB0aGUgc3RhdGUgb2YgdGhpcyBjbGFzcy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBqIC0gVGhlIGpzb24gb2JqZWN0LgogICAgICAgICAqLwogICAgICAgIGZyb21KU09OKGopIHsKICAgICAgICAgICAgLy8gV2UgbmVlZCB0byB2ZXJpZnkgdGhhdCBwMCBhbmQgcDEgYXhlcyBhcmUgbnVtZXJpYywgc28gaW4gY2FzZSB0aGV5IGFyZSBub3QsIHdlIHJlc3RvcmUgdGhlbSB0byB0aGVpciBkZWZhdWx0IHZhbHVlcy4KICAgICAgICAgICAgLy8gVGhpcywgYmVjYXVzZSAnSW5maW5pdHknIGFuZCAnLUluZmluaXR5JyBhcmUgc3RyaW5naWZpZWQgYXMgJ251bGwnLgogICAgICAgICAgICBjb25zdCBwMCA9IHsKICAgICAgICAgICAgICAgIHg6IE1hdGhGdW5jdGlvbnMuaXNOdW1lcmljKGoucDAueCkgPyBqLnAwLnggOiBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFksCiAgICAgICAgICAgICAgICB5OiBNYXRoRnVuY3Rpb25zLmlzTnVtZXJpYyhqLnAwLnkpID8gai5wMC55IDogTnVtYmVyLlBPU0lUSVZFX0lORklOSVRZLAogICAgICAgICAgICB9OwogICAgICAgICAgICBjb25zdCBwMSA9IHsKICAgICAgICAgICAgICAgIHg6IE1hdGhGdW5jdGlvbnMuaXNOdW1lcmljKGoucDEueCkgPyBqLnAxLnggOiBOdW1iZXIuTkVHQVRJVkVfSU5GSU5JVFksCiAgICAgICAgICAgICAgICB5OiBNYXRoRnVuY3Rpb25zLmlzTnVtZXJpYyhqLnAxLnkpID8gai5wMS55IDogTnVtYmVyLk5FR0FUSVZFX0lORklOSVRZLAogICAgICAgICAgICB9OwogICAgICAgICAgICB0aGlzLnAwLmZyb21KU09OKHAwKTsKICAgICAgICAgICAgdGhpcy5wMS5mcm9tSlNPTihwMSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENhbGxzIGB0b0pTT05gIG1ldGhvZCBhbmQgc3RyaW5naWZpZXMgaXQuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICB0b1N0cmluZygpIHsKICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5ldy1jYXAKICAgICAgICAgICAgcmV0dXJuIFN0cmluZ0Z1bmN0aW9ucy5zdHJpbmdpZnlKU09OV2l0aEZpeGVkUHJlY2lzaW9uKHRoaXMudG9KU09OKCkpOwogICAgICAgIH0KICAgIH0KCiAgICAvKiBlc2xpbnQtZGlzYWJsZSBuZXctY2FwICovCiAgICAvKioKICAgICAqIENsYXNzIHJlcHJlc2VudGluZyBhIG1hdGhlbWF0aWNhbCBzcGhlcmUsIGFzIG9wcG9zZWQgdG8gdGhlIFNwaGVyZSBjbGFzcyBkZXJpdmVkIGZyb20gUHJvY2VkdXJhbE1lc2guCiAgICAgKgogICAgICovCiAgICBjbGFzcyBTcGhlcmVUeXBlIHsKICAgICAgICBwb3M7CiAgICAgICAgcmFkaXVzOwogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZSBhIHNwaGVyZS4KICAgICAgICAgKiBAcGFyYW0gcG9zIC0gVGhlIHBvc2l0aW9uIG9mIHRoZSBzcGhlcmUuCiAgICAgICAgICogQHBhcmFtIHJhZGl1cyAtIFRoZSByYWRpdXMgb2YgdGhlIHNwaGVyZS4KICAgICAgICAgKi8KICAgICAgICBjb25zdHJ1Y3Rvcihwb3MgPSBuZXcgVmVjMygpLCByYWRpdXMgPSAwKSB7CiAgICAgICAgICAgIGlmIChwb3MgaW5zdGFuY2VvZiBWZWMzKSB7CiAgICAgICAgICAgICAgICB0aGlzLnBvcyA9IHBvczsKICAgICAgICAgICAgfQogICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgIHRoaXMucG9zID0gbmV3IFZlYzMoKTsKICAgICAgICAgICAgfQogICAgICAgICAgICB0aGlzLnJhZGl1cyA9IHJhZGl1czsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ2xvbmVzIHRoaXMgc3BoZXJlIGFuZCByZXR1cm5zIGEgbmV3IHNwaGVyZS4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGEgbmV3IHNwaGVyZS4KICAgICAgICAgKi8KICAgICAgICBjbG9uZSgpIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBTcGhlcmVUeXBlKHRoaXMucG9zLmNsb25lKCksIHRoaXMucmFkaXVzKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ2hlY2tzIGlmIHRoaXMgc3BoZXJlIGludGVyc2VjdHMgYSBib3guCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gYm94IC0gVGhlIGJveCB2YWx1ZS4KICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBpbnRlcnNlY3RzQm94KGJveCkgewogICAgICAgICAgICByZXR1cm4gYm94LmludGVyc2VjdHNTcGhlcmUodGhpcyk7CiAgICAgICAgfQogICAgICAgIC8vIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwogICAgICAgIC8vIFBlcnNpc3RlbmNlCiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIHRvSlNPTiBtZXRob2QgZW5jb2RlcyB0aGlzIHR5cGUgYXMgYSBqc29uIG9iamVjdCBmb3IgcGVyc2lzdGVuY2UuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIGpzb24gb2JqZWN0LgogICAgICAgICAqLwogICAgICAgIHRvSlNPTigpIHsKICAgICAgICAgICAgcmV0dXJuIHsKICAgICAgICAgICAgICAgIHBvczogdGhpcy5wb3MudG9KU09OKCksCiAgICAgICAgICAgICAgICByYWRpdXM6IHRoaXMucmFkaXVzLAogICAgICAgICAgICB9OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDYWxscyBgdG9KU09OYCBtZXRob2QgYW5kIHN0cmluZ2lmaWVzIGl0LgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgdG9TdHJpbmcoKSB7CiAgICAgICAgICAgIHJldHVybiBTdHJpbmdGdW5jdGlvbnMuc3RyaW5naWZ5SlNPTldpdGhGaXhlZFByZWNpc2lvbih0aGlzLnRvSlNPTigpKTsKICAgICAgICB9CiAgICB9CgogICAgLyoqCiAgICAgKiBDbGFzcyByZXByZXNlbnRpbmcgYSBib3ggaW4gM0Qgc3BhY2UuCiAgICAgKiBSZXByZXNlbnRzIGEgYm94IGluIDNEIHNwYWNlIGRlZmluZWQgYnkgdHdvIFZlYzMgdmFsdWVzIHdoaWNoIGRlZmluZSBvcHBvc2luZyBjb3JuZXJzIG9mIHRoZSBib3guCiAgICAgKi8KICAgIGNsYXNzIEJveDMgewogICAgICAgIHAwOwogICAgICAgIHAxOwogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgYSBCb3gzIG9iamVjdCB1c2luZyBWZWMzcy4KICAgICAgICAgKiBJbiBjYXNlIHRoZSBwYXJhbWV0ZXJzIGFyZSBub3QgcGFzc2VkIGJ5LCB0aGVpciB2YWx1ZXMgYXJlIHByZS1kZWZpbmVkOgogICAgICAgICAqCiAgICAgICAgICogcDAgaXMgYSBWZWMyIHdpdGgge0BsaW5rIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0phdmFTY3JpcHQvUmVmZXJlbmNlL0dsb2JhbF9PYmplY3RzL051bWJlci9QT1NJVElWRV9JTkZJTklUWXxgTnVtYmVyLlBPU0lUSVZFX0lORklOSVRZYH0KICAgICAgICAgKgogICAgICAgICAqIHAxIGlzIGEgVmVjMiB3aXRoIHtAbGluayBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9KYXZhU2NyaXB0L1JlZmVyZW5jZS9HbG9iYWxfT2JqZWN0cy9OdW1iZXIvTkVHQVRJVkVfSU5GSU5JVFl8YE51bWJlci5ORUdBVElWRV9JTkZJTklUWWB9CiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gcDAgLSBBIHBvaW50IHJlcHJlc2VudGluZyB0aGUgY29ybmVycyBvZiBhIDNEIGJveC4KICAgICAgICAgKiBAcGFyYW0gcDEgLSBBIHBvaW50IHJlcHJlc2VudGluZyB0aGUgY29ybmVycyBvZiBhIDNEIGJveC4KICAgICAgICAgKi8KICAgICAgICBjb25zdHJ1Y3RvcihwMCA9IG5ldyBWZWMzKE51bWJlci5QT1NJVElWRV9JTkZJTklUWSwgTnVtYmVyLlBPU0lUSVZFX0lORklOSVRZLCBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFkpLCBwMSA9IG5ldyBWZWMzKE51bWJlci5ORUdBVElWRV9JTkZJTklUWSwgTnVtYmVyLk5FR0FUSVZFX0lORklOSVRZLCBOdW1iZXIuTkVHQVRJVkVfSU5GSU5JVFkpKSB7CiAgICAgICAgICAgIHRoaXMucDAgPSBwMDsKICAgICAgICAgICAgdGhpcy5wMSA9IHAxOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBHZXR0ZXIgZm9yIHRoZSBsb3dlciAoeCwgeSwgeikgYm91bmRhcnkgb2YgdGhlIGJveC4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIHRoZSBtaW5pbXVtIFZlYzMuCiAgICAgICAgICovCiAgICAgICAgZ2V0IG1pbigpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMucDA7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEdldHRlciBmb3IgdGhlIHVwcGVyICh4LCB5LCB6KSBib3VuZGFyeSBvZiB0aGUgYm94LgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgdGhlIG1heGltdW0gVmVjMy4KICAgICAgICAgKi8KICAgICAgICBnZXQgbWF4KCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy5wMTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU2V0cyBib3RoIFZlYzMgcG9pbnRzCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gcDAgLSBBIHBvaW50IHJlcHJlc2VudGluZyB0aGUgY29ybmVycyBvZiBhIDNEIGJveC4KICAgICAgICAgKiBAcGFyYW0gcDEgLSBBIHBvaW50IHJlcHJlc2VudGluZyB0aGUgY29ybmVycyBvZiBhIDNEIGJveC4KICAgICAgICAgKi8KICAgICAgICBzZXQocDAsIHAxKSB7CiAgICAgICAgICAgIHRoaXMucDAgPSBwMDsKICAgICAgICAgICAgdGhpcy5wMSA9IHAxOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXNldHMgdGhlIGJveDMgYmFjayB0byBhbiB1bmluaXRpYWxpemVkIHN0YXRlLgogICAgICAgICAqLwogICAgICAgIHJlc2V0KCkgewogICAgICAgICAgICB0aGlzLnAwLnggPSBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFk7CiAgICAgICAgICAgIHRoaXMucDAueSA9IE51bWJlci5QT1NJVElWRV9JTkZJTklUWTsKICAgICAgICAgICAgdGhpcy5wMC56ID0gTnVtYmVyLlBPU0lUSVZFX0lORklOSVRZOwogICAgICAgICAgICB0aGlzLnAxLnggPSBOdW1iZXIuTkVHQVRJVkVfSU5GSU5JVFk7CiAgICAgICAgICAgIHRoaXMucDEueSA9IE51bWJlci5ORUdBVElWRV9JTkZJTklUWTsKICAgICAgICAgICAgdGhpcy5wMS56ID0gTnVtYmVyLk5FR0FUSVZFX0lORklOSVRZOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgYm94IGhhcyBiZWVuIGV4cGFuZGVkIHRvIGNvbnRhaW4gYSBwb2ludC4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGlzVmFsaWQoKSB7CiAgICAgICAgICAgIHJldHVybiAodGhpcy5wMC54ICE9IE51bWJlci5QT1NJVElWRV9JTkZJTklUWSAmJgogICAgICAgICAgICAgICAgdGhpcy5wMS54ICE9IE51bWJlci5ORUdBVElWRV9JTkZJTklUWSAmJgogICAgICAgICAgICAgICAgdGhpcy5wMC55ICE9IE51bWJlci5QT1NJVElWRV9JTkZJTklUWSAmJgogICAgICAgICAgICAgICAgdGhpcy5wMS55ICE9IE51bWJlci5ORUdBVElWRV9JTkZJTklUWSAmJgogICAgICAgICAgICAgICAgdGhpcy5wMC56ICE9IE51bWJlci5QT1NJVElWRV9JTkZJTklUWSAmJgogICAgICAgICAgICAgICAgdGhpcy5wMS56ICE9IE51bWJlci5ORUdBVElWRV9JTkZJTklUWSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEV4cGFuZHMgdGhlIEJveDMgdG8gY29udGFpbiB0aGUgbmV3IHBvaW50LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHBvaW50IC0gQSBwb2ludCByZXByZXNlbnRzIHRoZSBjb3JuZXJzIG9mIGEgM0QgYm94LgogICAgICAgICAqLwogICAgICAgIGFkZFBvaW50KHBvaW50KSB7CiAgICAgICAgICAgIGlmIChwb2ludC54ICE9IE51bWJlci5QT1NJVElWRV9JTkZJTklUWSAmJiBwb2ludC54ICE9IE51bWJlci5ORUdBVElWRV9JTkZJTklUWSkgewogICAgICAgICAgICAgICAgaWYgKHBvaW50LnggPCB0aGlzLnAwLngpCiAgICAgICAgICAgICAgICAgICAgdGhpcy5wMC54ID0gcG9pbnQueDsKICAgICAgICAgICAgICAgIGlmIChwb2ludC54ID4gdGhpcy5wMS54KQogICAgICAgICAgICAgICAgICAgIHRoaXMucDEueCA9IHBvaW50Lng7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKHBvaW50LnkgIT0gTnVtYmVyLlBPU0lUSVZFX0lORklOSVRZICYmIHBvaW50LnkgIT0gTnVtYmVyLk5FR0FUSVZFX0lORklOSVRZKSB7CiAgICAgICAgICAgICAgICBpZiAocG9pbnQueSA8IHRoaXMucDAueSkKICAgICAgICAgICAgICAgICAgICB0aGlzLnAwLnkgPSBwb2ludC55OwogICAgICAgICAgICAgICAgaWYgKHBvaW50LnkgPiB0aGlzLnAxLnkpCiAgICAgICAgICAgICAgICAgICAgdGhpcy5wMS55ID0gcG9pbnQueTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAocG9pbnQueiAhPSBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFkgJiYgcG9pbnQueiAhPSBOdW1iZXIuTkVHQVRJVkVfSU5GSU5JVFkpIHsKICAgICAgICAgICAgICAgIGlmIChwb2ludC56IDwgdGhpcy5wMC56KQogICAgICAgICAgICAgICAgICAgIHRoaXMucDAueiA9IHBvaW50Lno7CiAgICAgICAgICAgICAgICBpZiAocG9pbnQueiA+IHRoaXMucDEueikKICAgICAgICAgICAgICAgICAgICB0aGlzLnAxLnogPSBwb2ludC56OwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEFkZHMgYEJveDNgIHRvIHRoaXMgYEJveDNgLCBvZiB0aGUgWGZvIGluc3RhbmNlIGlzIHBhc3NlZCBpbiB0aGUgcGFyYW1ldGVycwogICAgICAgICAqIGl0IHByb2NlZWRzIHRvIGFwcGx5IHRoZSB0cmFuc2Zvcm0gZm9yIHRoZSBWZWMzLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGJveDMgLSBBIDNEIGJveC4KICAgICAgICAgKiBAcGFyYW0geGZvIC0gQSAzRCB0cmFuc2Zvcm0uCiAgICAgICAgICovCiAgICAgICAgYWRkQm94Myhib3gzLCB0cmFuc2Zvcm0pIHsKICAgICAgICAgICAgaWYgKHRyYW5zZm9ybSkgewogICAgICAgICAgICAgICAgLy8gVHJhbnNmb3JtIGVhY2ggY29ybmVyIG9mIHRoZSBCb3gzIGludG8gdGhlIG5ldyBjb29yZGluYXRlIHN5c3RlbS4KICAgICAgICAgICAgICAgIHRoaXMuYWRkUG9pbnQodHJhbnNmb3JtLnRyYW5zZm9ybVZlYzMoYm94My5wMCkpOwogICAgICAgICAgICAgICAgdGhpcy5hZGRQb2ludCh0cmFuc2Zvcm0udHJhbnNmb3JtVmVjMyhuZXcgVmVjMyhib3gzLnAwLngsIGJveDMucDAueSwgYm94My5wMS56KSkpOwogICAgICAgICAgICAgICAgdGhpcy5hZGRQb2ludCh0cmFuc2Zvcm0udHJhbnNmb3JtVmVjMyhuZXcgVmVjMyhib3gzLnAwLngsIGJveDMucDEueSwgYm94My5wMC56KSkpOwogICAgICAgICAgICAgICAgdGhpcy5hZGRQb2ludCh0cmFuc2Zvcm0udHJhbnNmb3JtVmVjMyhuZXcgVmVjMyhib3gzLnAxLngsIGJveDMucDAueSwgYm94My5wMC56KSkpOwogICAgICAgICAgICAgICAgdGhpcy5hZGRQb2ludCh0cmFuc2Zvcm0udHJhbnNmb3JtVmVjMyhuZXcgVmVjMyhib3gzLnAwLngsIGJveDMucDEueSwgYm94My5wMS56KSkpOwogICAgICAgICAgICAgICAgdGhpcy5hZGRQb2ludCh0cmFuc2Zvcm0udHJhbnNmb3JtVmVjMyhuZXcgVmVjMyhib3gzLnAxLngsIGJveDMucDAueSwgYm94My5wMS56KSkpOwogICAgICAgICAgICAgICAgdGhpcy5hZGRQb2ludCh0cmFuc2Zvcm0udHJhbnNmb3JtVmVjMyhuZXcgVmVjMyhib3gzLnAxLngsIGJveDMucDEueSwgYm94My5wMC56KSkpOwogICAgICAgICAgICAgICAgdGhpcy5hZGRQb2ludCh0cmFuc2Zvcm0udHJhbnNmb3JtVmVjMyhib3gzLnAxKSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZWxzZSB7CiAgICAgICAgICAgICAgICB0aGlzLmFkZFBvaW50KGJveDMucDApOwogICAgICAgICAgICAgICAgdGhpcy5hZGRQb2ludChib3gzLnAxKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIHRoZSBsZW5ndGggb2YgdGhlIGRpYWdvbmFsIG9mIHRoZSBib3guCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyB0aGUgZGlzdGFuY2UuCiAgICAgICAgICovCiAgICAgICAgc2l6ZSgpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMucDEuZGlzdGFuY2VUbyh0aGlzLnAwKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyB0aGUgZGlhZ29uYWwgdmVjdG9yIG9mIHRoZSBCPWJveCBmcm9tIHAwIHRvIHAxLgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgYSBCb3gzLgogICAgICAgICAqLwogICAgICAgIGRpYWdvbmFsKCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy5wMS5zdWJ0cmFjdCh0aGlzLnAwKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyB0aGUgY2VudGVyIHBvaW50IG9mIGEgQm94My4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGEgVmVjMy4KICAgICAgICAgKi8KICAgICAgICBjZW50ZXIoKSB7CiAgICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IHRoaXMucDEuc3VidHJhY3QodGhpcy5wMCk7CiAgICAgICAgICAgIHJlc3VsdC5zY2FsZUluUGxhY2UoMC41KTsKICAgICAgICAgICAgcmVzdWx0LmFkZEluUGxhY2UodGhpcy5wMCk7CiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbnZlcnRzIHRoaXMgQm94MyB0byBhIE1hdDQgKGEgNHg0IG1hdHJpeCkuIFRoZSByZXR1cm5lZCBtYXQ0IHdvdWxkIHRyYW5zZm9ybSBhIHVuaXQgY3ViZSBpbnRvIHRoZSBzaGFwZSBvZiB0aGUgQm91bmRpbmcgYm94LgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgYSBuZXcgTWF0NC4KICAgICAgICAgKi8KICAgICAgICB0b01hdDQoKSB7CiAgICAgICAgICAgIGNvbnN0IHNjeCA9IHRoaXMucDEueCAtIHRoaXMucDAueDsKICAgICAgICAgICAgY29uc3Qgc2N5ID0gdGhpcy5wMS55IC0gdGhpcy5wMC55OwogICAgICAgICAgICBjb25zdCBzY3ogPSB0aGlzLnAxLnogLSB0aGlzLnAwLno7CiAgICAgICAgICAgIHJldHVybiBuZXcgTWF0NChzY3gsIDAsIDAsIDAsIDAsIHNjeSwgMCwgMCwgMCwgMCwgc2N6LCAwLCB0aGlzLnAwLngsIHRoaXMucDAueSwgdGhpcy5wMC56LCAxLjApOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDYWxjdWxhdGVzIGFuZCByZXR1cm5zIHRoZSBib3VuZGluZyBTcGhlcmUgb2YgdGhlIEJveDMKICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGdldEJvdW5kaW5nU3BoZXJlKCkgewogICAgICAgICAgICByZXR1cm4gbmV3IFNwaGVyZVR5cGUodGhpcy5jZW50ZXIoKSwgdGhpcy5kaWFnb25hbCgpLmxlbmd0aCgpICogMC41KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogRGV0ZXJtaW5lcyBpZiB0aGlzIEJveDMgaW50ZXJzZWN0cyBhIGdpdmVuIGJveCB2YWx1ZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBib3ggLSBUaGUgYm94IHRvIGNoZWNrIGZvciBpbnRlcnNlY3Rpb24gYWdhaW5zdC4KICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyB0cnVlIGlmIHRoZSBzaGFwZXMgaW50ZXJzZWN0LgogICAgICAgICAqLwogICAgICAgIGludGVyc2VjdHNCb3goYm94KSB7CiAgICAgICAgICAgIC8vIFVzaW5nIDYgc3BsaXR0aW5nIHBsYW5lcyB0byBydWxlIG91dCBpbnRlcnNlY3Rpb25zLgogICAgICAgICAgICByZXR1cm4gYm94Lm1heC54IDwgdGhpcy5taW4ueCB8fAogICAgICAgICAgICAgICAgYm94Lm1pbi54ID4gdGhpcy5tYXgueCB8fAogICAgICAgICAgICAgICAgYm94Lm1heC55IDwgdGhpcy5taW4ueSB8fAogICAgICAgICAgICAgICAgYm94Lm1pbi55ID4gdGhpcy5tYXgueSB8fAogICAgICAgICAgICAgICAgYm94Lm1heC56IDwgdGhpcy5taW4ueiB8fAogICAgICAgICAgICAgICAgYm94Lm1pbi56ID4gdGhpcy5tYXguegogICAgICAgICAgICAgICAgPyBmYWxzZQogICAgICAgICAgICAgICAgOiB0cnVlOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBEZXRlcm1pbmVzIGlmIHRoaXMgQm94MyBpbnRlcnNlY3RzIGEgc3BoZXJlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHNwaGVyZSAtIFRoZSBzcGhlcmUgdG8gY2hlY2sgZm9yIGludGVyc2VjdGlvbiBhZ2FpbnN0LgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIHRydWUgaWYgdGhlIHNoYXBlcyBpbnRlcnNlY3QuCiAgICAgICAgICovCiAgICAgICAgaW50ZXJzZWN0c1NwaGVyZShzcGhlcmUpIHsKICAgICAgICAgICAgbGV0IGNsb3Nlc3RQb2ludCA9IG5ldyBWZWMzKCk7CiAgICAgICAgICAgIC8vIEZpbmQgdGhlIHBvaW50IG9uIHRoZSBBQUJCIGNsb3Nlc3QgdG8gdGhlIHNwaGVyZSBjZW50ZXIuCiAgICAgICAgICAgIC8vIHRoaXMuY2xhbXBQb2ludCggc3BoZXJlLmNlbnRlciwgY2xvc2VzdFBvaW50ICk7CiAgICAgICAgICAgIC8vIElmIHRoYXQgcG9pbnQgaXMgaW5zaWRlIHRoZSBzcGhlcmUsIHRoZSBBQUJCIGFuZCBzcGhlcmUgaW50ZXJzZWN0LgogICAgICAgICAgICByZXR1cm4gY2xvc2VzdFBvaW50LmRpc3RhbmNlVG8oc3BoZXJlLnBvcykgPD0gc3BoZXJlLnJhZGl1cyAqIHNwaGVyZS5yYWRpdXM7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIERldGVybWluZXMgaWYgdGhpcyBCb3gzIGludGVyc2VjdHMgYSBwbGFuZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBwbGFuZSAtIFRoZSBwbGFuZSB0byBjaGVjayBmb3IgaW50ZXJzZWN0aW9uIGFnYWluc3QuCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgaW50ZXJzZWN0c1BsYW5lKHBsYW5lKSB7CiAgICAgICAgICAgIC8vIFdlIGNvbXB1dGUgdGhlIG1pbmltdW0gYW5kIG1heGltdW0gZG90IHByb2R1Y3QgdmFsdWVzLiBJZiB0aG9zZSB2YWx1ZXMKICAgICAgICAgICAgLy8gYXJlIG9uIHRoZSBzYW1lIHNpZGUgKGJhY2sgb3IgZnJvbnQpIG9mIHRoZSBwbGFuZSwgdGhlbiB0aGVyZSBpcyBubyBpbnRlcnNlY3Rpb24uCiAgICAgICAgICAgIGxldCBtaW47CiAgICAgICAgICAgIGxldCBtYXg7CiAgICAgICAgICAgIGlmIChwbGFuZS5ub3JtYWwueCA+IDApIHsKICAgICAgICAgICAgICAgIG1pbiA9IHBsYW5lLm5vcm1hbC54ICogdGhpcy5taW4ueDsKICAgICAgICAgICAgICAgIG1heCA9IHBsYW5lLm5vcm1hbC54ICogdGhpcy5tYXgueDsKICAgICAgICAgICAgfQogICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgIG1pbiA9IHBsYW5lLm5vcm1hbC54ICogdGhpcy5tYXgueDsKICAgICAgICAgICAgICAgIG1heCA9IHBsYW5lLm5vcm1hbC54ICogdGhpcy5taW4ueDsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAocGxhbmUubm9ybWFsLnkgPiAwKSB7CiAgICAgICAgICAgICAgICBtaW4gKz0gcGxhbmUubm9ybWFsLnkgKiB0aGlzLm1pbi55OwogICAgICAgICAgICAgICAgbWF4ICs9IHBsYW5lLm5vcm1hbC55ICogdGhpcy5tYXgueTsKICAgICAgICAgICAgfQogICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgIG1pbiArPSBwbGFuZS5ub3JtYWwueSAqIHRoaXMubWF4Lnk7CiAgICAgICAgICAgICAgICBtYXggKz0gcGxhbmUubm9ybWFsLnkgKiB0aGlzLm1pbi55OwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIChwbGFuZS5ub3JtYWwueiA+IDApIHsKICAgICAgICAgICAgICAgIG1pbiArPSBwbGFuZS5ub3JtYWwueiAqIHRoaXMubWluLno7CiAgICAgICAgICAgICAgICBtYXggKz0gcGxhbmUubm9ybWFsLnogKiB0aGlzLm1heC56OwogICAgICAgICAgICB9CiAgICAgICAgICAgIGVsc2UgewogICAgICAgICAgICAgICAgbWluICs9IHBsYW5lLm5vcm1hbC56ICogdGhpcy5tYXguejsKICAgICAgICAgICAgICAgIG1heCArPSBwbGFuZS5ub3JtYWwueiAqIHRoaXMubWluLno7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIG1pbiA8PSAtcGxhbmUudyAmJiBtYXggPj0gLXBsYW5lLnc7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENsb25lcyB0aGlzIEJveDMgYW5kIHJldHVybnMgYSBuZXcgQm94My4KICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyBhIG5ldyBCb3gzLgogICAgICAgICAqLwogICAgICAgIGNsb25lKCkgewogICAgICAgICAgICByZXR1cm4gbmV3IEJveDModGhpcy5wMC5jbG9uZSgpLCB0aGlzLnAxLmNsb25lKCkpOwogICAgICAgIH0KICAgICAgICAvLyAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCiAgICAgICAgLy8gUGVyc2lzdGVuY2UKICAgICAgICAvKioKICAgICAgICAgKiBFbmNvZGVzIGBCb3gzYCBDbGFzcyBhcyBhIEpTT04gb2JqZWN0IGZvciBwZXJzaXN0ZW5jZS4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBUaGUganNvbiBvYmplY3QuCiAgICAgICAgICovCiAgICAgICAgdG9KU09OKCkgewogICAgICAgICAgICByZXR1cm4gewogICAgICAgICAgICAgICAgcDA6IHRoaXMucDAudG9KU09OKCksCiAgICAgICAgICAgICAgICBwMTogdGhpcy5wMS50b0pTT04oKSwKICAgICAgICAgICAgfTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogRGVjb2RlcyBhIEpTT04gb2JqZWN0IHRvIHNldCB0aGUgc3RhdGUgb2YgdGhpcyBjbGFzcy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBqIC0gVGhlIGpzb24gb2JqZWN0LgogICAgICAgICAqLwogICAgICAgIGZyb21KU09OKGopIHsKICAgICAgICAgICAgLy8gV2UgbmVlZCB0byB2ZXJpZnkgdGhhdCBwMCBhbmQgcDEgYXhlcyBhcmUgbnVtZXJpYywgc28gaW4gY2FzZSB0aGV5IGFyZSBub3QsIHdlIHJlc3RvcmUgdGhlbSB0byB0aGVpciBkZWZhdWx0IHZhbHVlcy4KICAgICAgICAgICAgLy8gVGhpcywgYmVjYXVzZSAnSW5maW5pdHknIGFuZCAnLUluZmluaXR5JyBhcmUgc3RyaW5naWZpZWQgYXMgJ251bGwnLgogICAgICAgICAgICBjb25zdCBwMCA9IHsKICAgICAgICAgICAgICAgIHg6IE1hdGhGdW5jdGlvbnMuaXNOdW1lcmljKGoucDAueCkgPyBqLnAwLnggOiBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFksCiAgICAgICAgICAgICAgICB5OiBNYXRoRnVuY3Rpb25zLmlzTnVtZXJpYyhqLnAwLnkpID8gai5wMC55IDogTnVtYmVyLlBPU0lUSVZFX0lORklOSVRZLAogICAgICAgICAgICAgICAgejogTWF0aEZ1bmN0aW9ucy5pc051bWVyaWMoai5wMC56KSA/IGoucDAueiA6IE51bWJlci5QT1NJVElWRV9JTkZJTklUWSwKICAgICAgICAgICAgfTsKICAgICAgICAgICAgY29uc3QgcDEgPSB7CiAgICAgICAgICAgICAgICB4OiBNYXRoRnVuY3Rpb25zLmlzTnVtZXJpYyhqLnAxLngpID8gai5wMS54IDogTnVtYmVyLk5FR0FUSVZFX0lORklOSVRZLAogICAgICAgICAgICAgICAgeTogTWF0aEZ1bmN0aW9ucy5pc051bWVyaWMoai5wMS55KSA/IGoucDEueSA6IE51bWJlci5ORUdBVElWRV9JTkZJTklUWSwKICAgICAgICAgICAgICAgIHo6IE1hdGhGdW5jdGlvbnMuaXNOdW1lcmljKGoucDEueikgPyBqLnAxLnogOiBOdW1iZXIuTkVHQVRJVkVfSU5GSU5JVFksCiAgICAgICAgICAgIH07CiAgICAgICAgICAgIHRoaXMucDAuZnJvbUpTT04ocDApOwogICAgICAgICAgICB0aGlzLnAxLmZyb21KU09OKHAxKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ2FsbHMgYHRvSlNPTmAgbWV0aG9kIGFuZCBzdHJpbmdpZmllcyBpdC4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHRvU3RyaW5nKCkgewogICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbmV3LWNhcAogICAgICAgICAgICByZXR1cm4gU3RyaW5nRnVuY3Rpb25zLnN0cmluZ2lmeUpTT05XaXRoRml4ZWRQcmVjaXNpb24odGhpcy50b0pTT04oKSk7CiAgICAgICAgfQogICAgfQoKICAgIGxldCBudW1CYXNlSXRlbXMgPSAwOwogICAgLyoqCiAgICAgKiBCYXNlIGNsYXNzIGZvciBJdGVtcyBpbiB0aGUgc2NlbmUuIEl0IGNhbiBiZSBwYXJhbWV0ZXJpemVkIGFuZCBjYW4gZW1pdCBldmVudHMuCiAgICAgKgogICAgICogKipFdmVudHMqKgogICAgICogKiAqKm5hbWVDaGFuZ2VkOioqIEVtaXR0ZWQgZXZlcnkgdGltZSB0aGUgSXRlbSdzIG5hbWUgaXMgY2hhbmdlLiBtb3N0bHkgaW4gYHNldE5hbWVgIG1ldGhvZC4KICAgICAqICogKipzZWxlY3RlZENoYW5nZWQ6KiogRW1pdHRlZCBgc2VsZWN0ZWRgIHN0YXR1cyBjaGFuZ2VzLCBtb3N0bHkgaW4gYHNldFNlbGVjdGVkYCBtZXRob2QuCiAgICAgKgogICAgICogQGV4dGVuZHMge0V2ZW50RW1pdHRlcn0KICAgICAqLwogICAgY2xhc3MgQmFzZUl0ZW0gZXh0ZW5kcyBFdmVudEVtaXR0ZXIgewogICAgICAgICNuYW1lOwogICAgICAgICNvd25lckl0ZW0gPSB1bmRlZmluZWQ7CiAgICAgICAgc2VsZWN0ZWQgPSBmYWxzZTsKICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGUgYSBiYXNlIGl0ZW0gYnkgZGVmaW5pbmcgaXRzIG5hbWUuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gbmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBiYXNlIGl0ZW0uCiAgICAgICAgICovCiAgICAgICAgY29uc3RydWN0b3IobmFtZSA9ICcnKSB7CiAgICAgICAgICAgIHN1cGVyKCk7CiAgICAgICAgICAgIHRoaXMuI25hbWUgPSBuYW1lOwogICAgICAgICAgICBudW1CYXNlSXRlbXMrKzsKICAgICAgICB9CiAgICAgICAgLy8gLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwogICAgICAgIC8vIFN0YXRpYyBNZXRob2RzCiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGdldE51bUJhc2VJdGVtcyBtZXRob2QgcmV0dXJucyB0aGUgdG90YWwgbnVtYmVyIG9mIGJhc2UgaXRlbXMgY3JlYXRlZC4KICAgICAgICAgKiBUaGlzIG1ldGhvZCBpcyB1c2VkIGluIGRlYnVnZ2luZyBtZW1vcnkgY29uc3VtcHRpb24uCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyB0aGUgdG90YWwgbnVtYmVyIG9mIGJhc2UgaXRlbXMgY3JlYXRlZC4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZ2V0TnVtQmFzZUl0ZW1zKCkgewogICAgICAgICAgICByZXR1cm4gbnVtQmFzZUl0ZW1zOwogICAgICAgIH0KICAgICAgICAvLyAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCiAgICAgICAgLy8gTmFtZSBhbmQgUGF0aAogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgdGhlIG5hbWUgb2YgdGhlIGJhc2UgaXRlbS4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIHRoZSBiYXNlIGl0ZW0gbmFtZS4KICAgICAgICAgKi8KICAgICAgICBnZXQgbmFtZSgpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuI25hbWU7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFNldHMgdGhlIG5hbWUgb2YgdGhlIGJhc2UgaXRlbShVcGRhdGVzIHBhdGgpLgogICAgICAgICAqCiAgICAgICAgICogQGVtaXRzIGBuYW1lQ2hhbmdlZGAgd2l0aCBgbmV3TmFtZWAgYW5kIGBvbGROYW1lYCBkYXRhLgogICAgICAgICAqIEBwYXJhbSBuYW1lIC0gVGhlIGJhc2UgaXRlbSBuYW1lLgogICAgICAgICAqLwogICAgICAgIHNldCBuYW1lKHZhbHVlKSB7CiAgICAgICAgICAgIGlmICh0aGlzLiNuYW1lICE9IHZhbHVlKSB7CiAgICAgICAgICAgICAgICBjb25zdCBvbGROYW1lID0gdGhpcy4jbmFtZTsKICAgICAgICAgICAgICAgIHRoaXMuI25hbWUgPSB2YWx1ZTsKICAgICAgICAgICAgICAgIGNvbnN0IGV2ZW50ID0gbmV3IE5hbWVDaGFuZ2VkRXZlbnQob2xkTmFtZSwgdmFsdWUpOwogICAgICAgICAgICAgICAgdGhpcy5lbWl0KCduYW1lQ2hhbmdlZCcsIGV2ZW50KTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIHRoZSBjdXJyZW50IHBhdGggb2YgdGhlIGl0ZW0gaW4gdGhlIHRyZWUgYXMgYW4gYXJyYXkgb2YgbmFtZXMuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyBhbiBhcnJheS4KICAgICAgICAgKi8KICAgICAgICBnZXQgcGF0aCgpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuZ2V0UGF0aCgpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIHRoZSBjdXJyZW50IHBhdGggb2YgdGhlIGl0ZW0gaW4gdGhlIHRyZWUgYXMgYW4gYXJyYXkgb2YgbmFtZXMuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyBhbiBhcnJheS4KICAgICAgICAgKi8KICAgICAgICBnZXQgb3duZXJJdGVtKCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy4jb3duZXJJdGVtOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIHRoZSBuYW1lIG9mIHRoZSBiYXNlIGl0ZW0uCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyB0aGUgYmFzZSBpdGVtIG5hbWUuCiAgICAgICAgICovCiAgICAgICAgZ2V0TmFtZSgpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuI25hbWU7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFNldHMgdGhlIG5hbWUgb2YgdGhlIGJhc2UgaXRlbShVcGRhdGVzIHBhdGgpLgogICAgICAgICAqCiAgICAgICAgICogQGVtaXRzIGBuYW1lQ2hhbmdlZGAgd2l0aCBgbmV3TmFtZWAgYW5kIGBvbGROYW1lYCBkYXRhLgogICAgICAgICAqIEBwYXJhbSBuYW1lIC0gVGhlIGJhc2UgaXRlbSBuYW1lLgogICAgICAgICAqLwogICAgICAgIHNldE5hbWUobmFtZSkgewogICAgICAgICAgICB0aGlzLm5hbWUgPSBuYW1lOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIHRoZSBjdXJyZW50IHBhdGggb2YgdGhlIGl0ZW0gaW4gdGhlIHRyZWUgYXMgYW4gYXJyYXkgb2YgbmFtZXMuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyBhbiBhcnJheS4KICAgICAgICAgKi8KICAgICAgICBnZXRQYXRoKCkgewogICAgICAgICAgICBpZiAodGhpcy4jb3duZXJJdGVtID09IHVuZGVmaW5lZCkKICAgICAgICAgICAgICAgIHJldHVybiBbdGhpcy4jbmFtZV07CiAgICAgICAgICAgIHJldHVybiBbLi4udGhpcy4jb3duZXJJdGVtLmdldFBhdGgoKSwgdGhpcy4jbmFtZV07CiAgICAgICAgfQogICAgICAgIC8vIFBhdGggVHJhdmVyc2FsCiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIHJlc29sdmVQYXRoIG1ldGhvZCB0cmF2ZXJzZXMgdGhlIHN1YnRyZWUgZnJvbSB0aGlzIGl0ZW0gZG93bgogICAgICAgICAqIG1hdGNoaW5nIGVhY2ggbmFtZSBpbiB0aGUgcGF0aCB3aXRoIGEgY2hpbGQgdW50aWwgaXQgcmVhY2hlcyB0aGUKICAgICAgICAgKiBlbmQgb2YgdGhlIHBhdGguCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gcGF0aCAtIFRoZSBwYXRoIHZhbHVlLgogICAgICAgICAqIEBwYXJhbSBpbmRleCAtIFRoZSBpbmRleCB2YWx1ZS4KICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICByZXNvbHZlUGF0aChwYXRoLCBpbmRleCA9IDApIHsKICAgICAgICAgICAgaWYgKGluZGV4ID09IDApIHsKICAgICAgICAgICAgICAgIGlmIChwYXRoWzBdID09ICcuJyB8fCBwYXRoWzBdID09IHRoaXMuI25hbWUpCiAgICAgICAgICAgICAgICAgICAgaW5kZXgrKzsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAocGF0aFtpbmRleF0gPT0gJy4uJykgewogICAgICAgICAgICAgICAgaWYgKHRoaXMuI293bmVySXRlbSkgewogICAgICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLiNvd25lckl0ZW0ucmVzb2x2ZVBhdGgocGF0aCwgaW5kZXggKyAxKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGVsc2UgewogICAgICAgICAgICAgICAgICAgIHRocm93IEVycm9yKCd0aGlzLiNvd25lckl0ZW0gaXMgdW5kZWZpbmVkJyk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKGluZGV4ID09IHBhdGgubGVuZ3RoKSB7CiAgICAgICAgICAgICAgICByZXR1cm4gdGhpczsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICAvLyAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCiAgICAgICAgLy8gT3duZXIgSXRlbQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBnZXRPd25lciBtZXRob2QgcmV0dXJucyB0aGUgY3VycmVudCBvd25lciBvZiB0aGUgaXRlbS4KICAgICAgICAgKiBUaGUgaXRlbSBpcyBhIGNoaWxkIG9mIHRoZSBjdXJyZW50IG93bmVyLgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgdGhlIGN1cnJlbnQgb3duZXIuCiAgICAgICAgICovCiAgICAgICAgZ2V0T3duZXIoKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLiNvd25lckl0ZW07CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBzZXRPd25lciBtZXRob2QgYXNzaWducyBhIG5ldyBvd25lciB0byB0aGUgaXRlbS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBvd25lckl0ZW0gLSBUaGUgbmV3IG93bmVyIGl0ZW0uCiAgICAgICAgICovCiAgICAgICAgc2V0T3duZXIob3duZXJJdGVtKSB7CiAgICAgICAgICAgIHRoaXMuI293bmVySXRlbSA9IG93bmVySXRlbTsKICAgICAgICB9CiAgICAgICAgLy8gLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwogICAgICAgIC8vIFNlbGVjdGlvbgogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBpc1NlbGVjdGVkIG1ldGhvZC4KICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBpc1NlbGVjdGVkKCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy5zZWxlY3RlZDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ2hhbmdlcyB0aGUgY3VycmVudCBzdGF0ZSBvZiB0aGUgc2VsZWN0aW9uIG9mIHRoaXMgaXRlbS4KICAgICAgICAgKgogICAgICAgICAqIEBlbWl0cyBgc2VsZWN0ZWRDaGFuZ2VkYCB3aXRoIHNlbGVjdGVkIHN0YXRlCiAgICAgICAgICogQHBhcmFtIHNlbCAtIEJvb2xlYW4gaW5kaWNhdGluZyB0aGUgbmV3IHNlbGVjdGlvbiBzdGF0ZS4KICAgICAgICAgKi8KICAgICAgICBzZXRTZWxlY3RlZChzZWwpIHsKICAgICAgICAgICAgdGhpcy5zZWxlY3RlZCA9IHNlbDsKICAgICAgICAgICAgbGV0IGV2ZW50ID0gbmV3IFNlbGVjdGVkRXZlbnQodGhpcy5zZWxlY3RlZCk7CiAgICAgICAgICAgIHRoaXMuZW1pdCgnc2VsZWN0ZWRDaGFuZ2VkJywgZXZlbnQpOwogICAgICAgIH0KICAgICAgICAvLyAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCiAgICAgICAgLy8gUGVyc2lzdGVuY2UKICAgICAgICAvKioKICAgICAgICAgKiBFbmNvZGVzIHRoZSBjdXJyZW50IG9iamVjdCBhcyBhIGpzb24gb2JqZWN0LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGNvbnRleHQgLSBUaGUgY29udGV4dCB2YWx1ZS4KICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyB0aGUganNvbiBvYmplY3QuCiAgICAgICAgICovCiAgICAgICAgdG9KU09OKGNvbnRleHQpIHsKICAgICAgICAgICAgY29uc3QganNvbiA9IHsKICAgICAgICAgICAgICAgIHR5cGU6IHRoaXMuZ2V0Q2xhc3NOYW1lKCksCiAgICAgICAgICAgICAgICBuYW1lOiB0aGlzLiNuYW1lLAogICAgICAgICAgICB9OwogICAgICAgICAgICByZXR1cm4ganNvbjsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogRGVjb2RlcyBhIGpzb24gb2JqZWN0IGZvciB0aGlzIHR5cGUuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ganNvbiAtIFRoZSBqc29uIG9iamVjdCB0aGlzIGl0ZW0gbXVzdCBkZWNvZGUuCiAgICAgICAgICogQHBhcmFtIGNvbnRleHQgLSBUaGUgY29udGV4dCB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBmcm9tSlNPTihqc29uLCBjb250ZXh0KSB7CiAgICAgICAgICAgIGlmIChqc29uLm5hbWUpCiAgICAgICAgICAgICAgICB0aGlzLiNuYW1lID0ganNvbi5uYW1lOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTZXRzIHN0YXRlIG9mIGN1cnJlbnQgSXRlbShJbmNsdWRpbmcgcGFyYW1ldGVycykgdXNpbmcgYSBiaW5hcnkgcmVhZGVyIG9iamVjdC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSByZWFkZXIgLSBUaGUgcmVhZGVyIHZhbHVlLgogICAgICAgICAqIEBwYXJhbSBjb250ZXh0IC0gVGhlIGNvbnRleHQgdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgcmVhZEJpbmFyeShyZWFkZXIsIGNvbnRleHQpIHsKICAgICAgICAgICAgLy8gcmVhZCB0aGUgdHlwZSwgYnV0IGRvbid0IHVzZSBpdC4gVGhpcyBsaW5lIG11c3Qgbm90IGJlIHJlbW92ZWQuCiAgICAgICAgICAgIC8vIGFzIHRoZSBiaW5hcnkgcG9pbnRlciBpcyBpbmNyZW1lbnRlZC4KICAgICAgICAgICAgLypjb25zdCB0eXBlID0gKi8gcmVhZGVyLmxvYWRTdHIoKTsKICAgICAgICAgICAgdGhpcy5zZXROYW1lKHJlYWRlci5sb2FkU3RyKCkpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb252ZXJ0cyBvYmplY3QncyBKU09OIHZhbHVlIGFuZCBjb252ZXJ0cyBpdCB0byBhIHN0cmluZy4KICAgICAgICAgKiBAcGFyYW0gY29udGV4dAogICAgICAgICAqIEByZXR1cm4gLSBTdHJpbmcgb2Ygb2JqZWN0J3MgcGFyYW1ldGVyIGxpc3Qgc3RhdGUuCiAgICAgICAgICovCiAgICAgICAgdG9TdHJpbmcoY29udGV4dCkgewogICAgICAgICAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkodGhpcy50b0pTT04oKSwgbnVsbCwgMik7CiAgICAgICAgfQogICAgICAgIC8vIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KICAgICAgICAvLyBDbG9uZSBhbmQgRGVzdHJveQogICAgICAgIC8qKgogICAgICAgICAqIENsb25lcyB0aGlzIGJhc2UgaXRlbSBhbmQgcmV0dXJucyBhIG5ldyBiYXNlIGl0ZW0uCiAgICAgICAgICoKICAgICAgICAgKiAqKk5vdGU6KiogRWFjaCBjbGFzcyBzaG91bGQgaW1wbGVtZW50IGNsb25lIHRvIGJlIGNsb25hYmxlLgogICAgICAgICAqIEBwYXJhbSBjb250ZXh0IC0gVGhlIGNvbnRleHQgdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgY2xvbmUoY29udGV4dCkgewogICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IodGhpcy5jb25zdHJ1Y3Rvci5uYW1lICsgJyBkb2VzIG5vdCBpbXBsZW1lbnQgaXRzIGNsb25lIG1ldGhvZCcpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBXaGVuIGEgQmFzZUl0ZW0gaXMgY2xvbmVkLCBpbml0aWFsbHkgdGhlIGNvbnN0cnVjdG9yIGlzCiAgICAgICAgICogY2FsbGVkIHRvIGdlbmVyYXRlIGEgbmV3IGluc3RhbmNlLiBUaGlzIGluc3RhbmNlIHRoZW4gY29waWVzCiAgICAgICAgICogaXRzIHZhbHVlcyBmcm9tIHRoZSBzb3VyY2UgdXNpbmcgdGhpcyBtZXRob2QuCiAgICAgICAgICogVGhpcyBtZXRob2QgY29waWVzIGFueSByZWxldmFudCBkYXRhIGZyb20gdGhlIHNvdXJjZSBvYmplY3QgdG8KICAgICAgICAgKiBlbnN1cmUgdGhhdCBpdCByZXByZXNlbnRzIGEgdmFsaWQgY2xvbmUuCiAgICAgICAgICogRGVyaXZlZCBjbGFzc2VzIG92ZXJyaWRlIHRoaXMgbWV0aG9kIHRvIGNvcHkgYW55IHJlbGV2YW50CiAgICAgICAgICogZGF0YSBmcm9tIHRoZSBzb3VyY2Ugb2JqZWN0LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHNyYyAtIFRoZSBCYXNlSXRlbSB0byBjb3B5IGZyb20uCiAgICAgICAgICogQHBhcmFtIGNvbnRleHQgLSBUaGUgY29udGV4dCB2YWx1ZQogICAgICAgICAqLwogICAgICAgIGNvcHlGcm9tKHNyYywgY29udGV4dCkgewogICAgICAgICAgICB0aGlzLnNldE5hbWUoc3JjLmdldE5hbWUoKSk7CiAgICAgICAgfQogICAgfQoKICAgIC8qKgogICAgICogQ2xhc3MgdGhhdCBhbGxvd3Mgb3RoZXIgY2xhc3NlcyB0byBiZSBwYXJhbWV0ZXJpemVkIGJ5IGBQYXJhbWV0ZXJgIHR5cGUgb2Ygb2JqZWN0cy4KICAgICAqIE5vdCBvbmx5IGhvc3RpbmcgcGFyYW1ldGVycywgYnV0IHRoZWlyIGV2ZW50cy4KICAgICAqCiAgICAgKiBAZXh0ZW5kcyB7QmFzZUl0ZW19CiAgICAgKi8KICAgIGNsYXNzIFBhcmFtZXRlck93bmVyIGV4dGVuZHMgQmFzZUl0ZW0gewogICAgICAgIHBhcmFtRXZlbnRMaXN0ZW5lcklEcyA9IHt9OwogICAgICAgIHBhcmFtTWFwcGluZyA9IHt9OwogICAgICAgIHBhcmFtcyA9IFtdOwogICAgICAgIGRlcHJlY2F0ZWRQYXJhbU1hcHBpbmcgPSB7fTsKICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGVzIGFuIGluc3RhbmNlIG9mIFBhcmFtZXRlck93bmVyIGJ5IGluaXRpYWxpemluZyBwYXJhbWV0ZXIgaG9zdGluZyBtYXBwaW5ncyBhbmQgZXZlbnRzLgogICAgICAgICAqCiAgICAgICAgICogRXZlcnkgT2JqZWN0IGhhcyBhIHVuaXF1ZSBpZGVudGlmaWVyIHdoaWNoIGlzIGJhc2VkIG9uIGEgY291bnRlciB0aGF0IGlzIGluY3JlbWVudGVkLgogICAgICAgICAqLwogICAgICAgIGNvbnN0cnVjdG9yKG5hbWUpIHsKICAgICAgICAgICAgc3VwZXIobmFtZSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgdGhlIG51bWJlciBvZiBwYXJhbWV0ZXJzIGN1cnJlbnQgb2JqZWN0IGhhcy4KICAgICAgICAgKi8KICAgICAgICBnZXROdW1QYXJhbWV0ZXJzKCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy5wYXJhbXMubGVuZ3RoOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIHRoZSBudW1iZXIgb2YgcGFyYW1ldGVycyBjdXJyZW50IG9iamVjdCBoYXMuCiAgICAgICAgICovCiAgICAgICAgZ2V0IG51bVBhcmFtZXRlcnMoKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLnBhcmFtcy5sZW5ndGg7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgYWxsIHRoZSBwYXJhbWV0ZXJzIG9mIHRoZSBvYmplY3QuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUGFyYW1ldGVyIExpc3QKICAgICAgICAgKi8KICAgICAgICBnZXRQYXJhbWV0ZXJzKCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy5wYXJhbXM7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgdGhlIGluZGV4IG9mIGEgcGFyYW1ldGVyIGluIHBhcmFtZXRlciBsaXN0LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHBhcmFtTmFtZSAtIE5hbWUgb2YgdGhlIHBhcmFtZXRlci4KICAgICAgICAgKiBAcmV0dXJuIC0gUG9zaXRpb24gaW4gdGhlIGFycmF5CiAgICAgICAgICovCiAgICAgICAgZ2V0UGFyYW1ldGVySW5kZXgocGFyYW1OYW1lKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLnBhcmFtTWFwcGluZ1twYXJhbU5hbWVdOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIGBQYXJhbWV0ZXJgIG9iamVjdCBpbiBhIGdpdmVuIGluZGV4CiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gaW5kZXggLSBQb3NpdGlvbiBvZiB0aGUgcGFyYW1ldGVyIGluIHRoZSBhcnJheQogICAgICAgICAqIEByZXR1cm4gLSBQYXJhbWV0ZXIgb2JqZWN0IHZhbHVlCiAgICAgICAgICovCiAgICAgICAgZ2V0UGFyYW1ldGVyQnlJbmRleChpbmRleCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy5wYXJhbXNbaW5kZXhdOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBWYWxpZGF0ZXMgaWYgdGhlIHNwZWNpZmllZCBwYXJhbWV0ZXIgZXhpc3RzIGluIHRoZSBvYmplY3QuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gcGFyYW1OYW1lIC0gVGhlIHBhcmFtZXRlciBuYW1lLgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGhhc1BhcmFtZXRlcihwYXJhbU5hbWUpIHsKICAgICAgICAgICAgcmV0dXJuIHBhcmFtTmFtZSBpbiB0aGlzLnBhcmFtTWFwcGluZzsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQWRkIGEgbWFwcGluZyBmcm9tIG9uZSBuYW1lIHRvIGEgbmV3IHBhcmFtZXRlci4KICAgICAgICAgKiBUaGlzIGlzIHVzZWQgdG8gaGFuZGxlIG1pZ3JhdGluZyBwYXJhbWV0ZXJzIHRvIG5ldyBuYW1lcy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBrZXkgLSBUaGUgcGFyYW1ldGVyIG5hbWUuCiAgICAgICAgICogQHBhcmFtIHBhcmFtTmFtZSAtIFRoZSBwYXJhbWV0ZXIgbmFtZS4KICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBhZGRQYXJhbWV0ZXJEZXByZWNhdGlvbk1hcHBpbmcoa2V5LCBwYXJhbU5hbWUpIHsKICAgICAgICAgICAgdGhpcy5kZXByZWNhdGVkUGFyYW1NYXBwaW5nW2tleV0gPSBwYXJhbU5hbWU7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgYFBhcmFtZXRlcmAgb2JqZWN0IHVzaW5nIHRoZSBnaXZlbiBuYW1lCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gcGFyYW1OYW1lIC0gVGhlIHBhcmFtZXRlciBuYW1lLgogICAgICAgICAqIEByZXR1cm4gLSBQYXJhbWV0ZXIgb2JqZWN0IHZhbHVlCiAgICAgICAgICovCiAgICAgICAgZ2V0UGFyYW1ldGVyKHBhcmFtTmFtZSkgewogICAgICAgICAgICBsZXQgaW5kZXggPSB0aGlzLnBhcmFtTWFwcGluZ1twYXJhbU5hbWVdOwogICAgICAgICAgICBpZiAoaW5kZXggPT0gdW5kZWZpbmVkKSB7CiAgICAgICAgICAgICAgICBjb25zdCBuZXdQYXJhbU5hbWUgPSB0aGlzLmRlcHJlY2F0ZWRQYXJhbU1hcHBpbmdbcGFyYW1OYW1lXTsKICAgICAgICAgICAgICAgIGlmICghbmV3UGFyYW1OYW1lKSB7CiAgICAgICAgICAgICAgICAgICAgLy8gVE9ETzogU2hvdWxkIHRoaXMgbWV0aG9kIG5vdCByZXR1cm4gbnVsbD8KICAgICAgICAgICAgICAgICAgICByZXR1cm4gbnVsbDsKICAgICAgICAgICAgICAgICAgICAvLyB0aHJvdyBFcnJvcihgTm8gUGFyYW1ldGVyIHdpdGggdGhhdCBuYW1lIGV4aXN0czogJHtwYXJhbU5hbWV9IGApCiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oYFBhcmFtZXRlciBuYW1lICR7cGFyYW1OYW1lfSBpcyBub3cgZGVwcmVjYXRlZC4gUGxlYXNlIHVzZSAke25ld1BhcmFtTmFtZX0gaW5zdGVhZC5gKTsKICAgICAgICAgICAgICAgICAgICBpbmRleCA9IHRoaXMucGFyYW1NYXBwaW5nW25ld1BhcmFtTmFtZV07CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIHRoaXMucGFyYW1zW2luZGV4XTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVGhpcyBtZXRob2QgY2FuIGJlIG92ZXJyaWRkZW4gaW4gZGVyaXZlZCBjbGFzc2VzCiAgICAgICAgICogdG8gcGVyZm9ybSBnZW5lcmFsIHVwZGF0ZXMgKHNlZSBHTFBhc3Mgb3IgQmFzZUl0ZW0pLgogICAgICAgICAqIEBwYXJhbSBldmVudCAtIFRoZSBldmVudCBvYmplY3QgZW1pdHRlZCBieSB0aGUgcGFyYW1ldGVyLgogICAgICAgICAqIEBwcml2YXRlCiAgICAgICAgICovCiAgICAgICAgcGFyYW1ldGVyVmFsdWVDaGFuZ2VkKGV2ZW50KSB7CiAgICAgICAgICAgIHRoaXMuZW1pdCgncGFyYW1ldGVyVmFsdWVDaGFuZ2VkJywgZXZlbnQpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBBZGRzIGBQYXJhbWV0ZXJgIG9iamVjdCB0byB0aGUgb3duZXIncyBwYXJhbWV0ZXIgbGlzdC4KICAgICAgICAgKgogICAgICAgICAqIEBlbWl0cyBgcGFyYW1ldGVyQWRkZWRgIHdpdGggdGhlIG5hbWUgb2YgdGhlIHBhcmFtLgogICAgICAgICAqIEBwYXJhbSBwYXJhbSAtIFRoZSBwYXJhbWV0ZXIgdG8gYWRkLgogICAgICAgICAqIEByZXR1cm4gLSBXaXRoIGBvd25lcmAgYW5kIGB2YWx1ZUNoYW5nZWRgIGV2ZW50IHNldC4KICAgICAgICAgKi8KICAgICAgICBhZGRQYXJhbWV0ZXIocGFyYW0pIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuaW5zZXJ0UGFyYW1ldGVyKHBhcmFtLCB0aGlzLnBhcmFtcy5sZW5ndGgpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBBZGRzIGBQYXJhbWV0ZXJgIG9iamVjdCB0byB0aGUgb3duZXIncyBwYXJhbWV0ZXIgbGlzdCB1c2luZyB0aGUgaW5kZXguCiAgICAgICAgICogSXQgcmVwbGFjZXMgdGhlIGV2ZW50IGluIHRoZSBzcGVjaWZpZWQgaW5kZXguCiAgICAgICAgICoKICAgICAgICAgKgogICAgICAgICAqIEBlbWl0cyBgcGFyYW1ldGVyQWRkZWRgIHdpdGggdGhlIG5hbWUgb2YgdGhlIHBhcmFtLgogICAgICAgICAqIEBwYXJhbSBwYXJhbSAtIFRoZSBwYXJhbWV0ZXIgdG8gaW5zZXJ0LgogICAgICAgICAqIEBwYXJhbSBpbmRleCAtIFRoZSBpbmRleCB2YWx1ZS4KICAgICAgICAgKiBAcmV0dXJuIC0gV2l0aCBgb3duZXJgIGFuZCBgdmFsdWVDaGFuZ2VkYCBldmVudCBzZXQuCiAgICAgICAgICovCiAgICAgICAgaW5zZXJ0UGFyYW1ldGVyKHBhcmFtLCBpbmRleCkgewogICAgICAgICAgICBjb25zdCBuYW1lID0gcGFyYW0uZ2V0TmFtZSgpOwogICAgICAgICAgICBpZiAodGhpcy5wYXJhbU1hcHBpbmdbbmFtZV0gIT0gdW5kZWZpbmVkKSB7CiAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oJ1JlcGxhY2luZyBQYXJhbWV0ZXI6JyArIG5hbWUpOwogICAgICAgICAgICAgICAgdGhpcy5yZW1vdmVQYXJhbWV0ZXIobmFtZSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcGFyYW0uc2V0T3duZXIodGhpcyk7CiAgICAgICAgICAgIHRoaXMucGFyYW1FdmVudExpc3RlbmVySURzW25hbWVdID0gcGFyYW0ub24oJ3ZhbHVlQ2hhbmdlZCcsIChldmVudCkgPT4gewogICAgICAgICAgICAgICAgLy8gTm90ZTogc3ByZWFkIG9wZXJhdG9ycyBjYXVzZSBlcnJvcnMgb24gaU9TIDExLgogICAgICAgICAgICAgICAgY29uc3QgbmV3RXZlbnQgPSB7IHBhcmFtIH07CiAgICAgICAgICAgICAgICBmb3IgKGNvbnN0IGtleSBpbiBldmVudCkKICAgICAgICAgICAgICAgICAgICBuZXdFdmVudFtrZXldID0gZXZlbnRba2V5XTsKICAgICAgICAgICAgICAgIHRoaXMucGFyYW1ldGVyVmFsdWVDaGFuZ2VkKG5ld0V2ZW50KTsKICAgICAgICAgICAgfSk7CiAgICAgICAgICAgIHRoaXMucGFyYW1zLnNwbGljZShpbmRleCwgMCwgcGFyYW0pOwogICAgICAgICAgICBmb3IgKGxldCBpID0gaW5kZXg7IGkgPCB0aGlzLnBhcmFtcy5sZW5ndGg7IGkrKykgewogICAgICAgICAgICAgICAgdGhpcy5wYXJhbU1hcHBpbmdbdGhpcy5wYXJhbXNbaV0uZ2V0TmFtZSgpXSA9IGk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgY29uc3QgZXZlbnQgPSBuZXcgUGFyYW1ldGVyQWRkZWRFdmVudChuYW1lKTsKICAgICAgICAgICAgdGhpcy5lbWl0KCdwYXJhbWV0ZXJBZGRlZCcsIGV2ZW50KTsKICAgICAgICAgICAgcmV0dXJuIHBhcmFtOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZW1vdmVzIGBQYXJhbWV0ZXJgIGZyb20gb3duZXIsIGJ5IHVzaW5nIHBhcmFtZXRlcidzIG5hbWUuCiAgICAgICAgICogQGVtaXRzIGBwYXJhbWV0ZXJSZW1vdmVkYCB3aXRoIHRoZSBuYW1lIG9mIHRoZSBwYXJhbS4KICAgICAgICAgKiBAcGFyYW0gbmFtZSAtIFRoZSBwYXJhbWV0ZXIgbmFtZS4KICAgICAgICAgKi8KICAgICAgICByZW1vdmVQYXJhbWV0ZXIobmFtZSkgewogICAgICAgICAgICBpZiAodGhpcy5wYXJhbU1hcHBpbmdbbmFtZV0gPT0gdW5kZWZpbmVkKSB7CiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1VuYWJsZSB0byByZW1vdmUgUGFyYW1ldGVyOicgKyBuYW1lKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBjb25zdCBpbmRleCA9IHRoaXMucGFyYW1NYXBwaW5nW25hbWVdOwogICAgICAgICAgICBjb25zdCBwYXJhbSA9IHRoaXMucGFyYW1zW3RoaXMucGFyYW1NYXBwaW5nW25hbWVdXTsKICAgICAgICAgICAgcGFyYW0ub2ZmKCd2YWx1ZUNoYW5nZWQnLCB0aGlzLnBhcmFtRXZlbnRMaXN0ZW5lcklEc1tuYW1lXSk7CiAgICAgICAgICAgIHRoaXMucGFyYW1zLnNwbGljZShpbmRleCwgMSk7CiAgICAgICAgICAgIGRlbGV0ZSB0aGlzLnBhcmFtTWFwcGluZ1tuYW1lXTsKICAgICAgICAgICAgZm9yIChsZXQgaSA9IGluZGV4OyBpIDwgdGhpcy5wYXJhbXMubGVuZ3RoOyBpKyspIHsKICAgICAgICAgICAgICAgIHRoaXMucGFyYW1NYXBwaW5nW3RoaXMucGFyYW1zW2ldLmdldE5hbWUoKV0gPSBpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGNvbnN0IGV2ZW50ID0gbmV3IFBhcmFtZXRlclJlbW92ZWRFdmVudChuYW1lKTsKICAgICAgICAgICAgdGhpcy5lbWl0KCdwYXJhbWV0ZXJSZW1vdmVkJywgZXZlbnQpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXBsYWNlcyBvbGQgYFBhcmFtZXRlcmAgYnkgcGFzc2luZyBhIG5ldyBvbmUgd2l0aCB0aGUgc2FtZSBuYW1lLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHBhcmFtIC0gVGhlIHBhcmFtZXRlciB0byByZXBsYWNlLgogICAgICAgICAqIEByZXR1cm4gLSBgUGFyYW1ldGVyYCB3aXRoIGB2YWx1ZUNoYW5nZWRgIGV2ZW50IHNldC4KICAgICAgICAgKi8KICAgICAgICByZXBsYWNlUGFyYW1ldGVyKHBhcmFtKSB7CiAgICAgICAgICAgIGNvbnN0IG5hbWUgPSBwYXJhbS5nZXROYW1lKCk7CiAgICAgICAgICAgIGlmICh0aGlzLnBhcmFtTWFwcGluZ1tuYW1lXSA9PSB1bmRlZmluZWQpIHsKICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignVW5hYmxlIHRvIHJlcGxhY2UgUGFyYW1ldGVyOicgKyBuYW1lKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBjb25zdCBpbmRleCA9IHRoaXMucGFyYW1NYXBwaW5nW25hbWVdOwogICAgICAgICAgICB0aGlzLnJlbW92ZVBhcmFtZXRlcihuYW1lKTsKICAgICAgICAgICAgdGhpcy5pbnNlcnRQYXJhbWV0ZXIocGFyYW0sIGluZGV4KTsKICAgICAgICAgICAgcmV0dXJuIHBhcmFtOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgcmVzb2x2ZVBhdGggbWV0aG9kIHRyYXZlcnNlcyB0aGUgc3VidHJlZSBmcm9tIHRoaXMgaXRlbSBkb3duCiAgICAgICAgICogbWF0Y2hpbmcgZWFjaCBuYW1lIGluIHRoZSBwYXRoIHdpdGggYSBjaGlsZCB1bnRpbCBpdCByZWFjaGVzIHRoZQogICAgICAgICAqIGVuZCBvZiB0aGUgcGF0aC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBwYXRoIC0gVGhlIHBhdGggdmFsdWUuCiAgICAgICAgICogQHBhcmFtIGluZGV4IC0gVGhlIGluZGV4IHZhbHVlLgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHJlc29sdmVQYXRoKHBhdGgsIGluZGV4ID0gMCkgewogICAgICAgICAgICBpZiAoaW5kZXggPT0gMCkgewogICAgICAgICAgICAgICAgaWYgKHBhdGhbMF0gPT0gJy4nIHx8IHBhdGhbMF0gPT0gdGhpcy5uYW1lKQogICAgICAgICAgICAgICAgICAgIGluZGV4Kys7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKHBhdGhbaW5kZXhdID09ICcuLicpIHsKICAgICAgICAgICAgICAgIGlmICh0aGlzLm93bmVySXRlbSkgewogICAgICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLm93bmVySXRlbS5yZXNvbHZlUGF0aChwYXRoLCBpbmRleCArIDEpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgdGhyb3cgRXJyb3IoJ3RoaXMub3duZXJJdGVtIGlzIHVuZGVmaW5lZCcpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIChpbmRleCA9PSBwYXRoLmxlbmd0aCkgewogICAgICAgICAgICAgICAgcmV0dXJuIHRoaXM7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLy8gTWF5YmUgdGhlIG5hbWUgaXMgYSBwYXJhbWV0ZXIgbmFtZS4KICAgICAgICAgICAgY29uc3QgcGFyYW0gPSB0aGlzLmdldFBhcmFtZXRlcihwYXRoW2luZGV4XSk7CiAgICAgICAgICAgIGlmIChwYXJhbSkgewogICAgICAgICAgICAgICAgaWYgKGluZGV4IDwgcGF0aC5sZW5ndGgpIHsKICAgICAgICAgICAgICAgICAgICByZXR1cm4gcGFyYW0ucmVzb2x2ZVBhdGgocGF0aCwgaW5kZXggKyAxKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIHJldHVybiBwYXJhbTsKICAgICAgICAgICAgfQogICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFVuYWJsZSB0byByZXNvbHZlIHBhdGggOiBbJHtwYXRoLnRvU3RyaW5nKCl9XSBhZnRlcjogJHt0aGlzLmdldE5hbWUoKX0gXG5ObyBjaGlsZCBvciBwYXJhbWV0ZXIgY2FsbGVkIDogIiR7cGF0aFtpbmRleF19ImApOwogICAgICAgIH0KICAgICAgICAvLyAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCiAgICAgICAgLy8gUGVyc2lzdGVuY2UKICAgICAgICAvKioKICAgICAgICAgKiBUaGUgdG9KU09OIG1ldGhvZCBlbmNvZGVzIHRoaXMgdHlwZSBhcyBhIGpzb24gb2JqZWN0IGZvciBwZXJzaXN0ZW5jZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBjb250ZXh0IC0gVGhlIGNvbnRleHQgdmFsdWUuCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgdGhlIGpzb24gb2JqZWN0LgogICAgICAgICAqLwogICAgICAgIHRvSlNPTihjb250ZXh0KSB7CiAgICAgICAgICAgIGNvbnN0IGpzb24gPSBzdXBlci50b0pTT04oY29udGV4dCk7CiAgICAgICAgICAgIGNvbnN0IHBhcmFtc0pTT04gPSB7fTsKICAgICAgICAgICAgbGV0IHNhdmVkUGFyYW1zID0gMDsKICAgICAgICAgICAgZm9yIChjb25zdCBwYXJhbSBvZiB0aGlzLnBhcmFtcykgewogICAgICAgICAgICAgICAgaWYgKHBhcmFtLmlzRHJpdmVuQnlPcGVyYXRvcigpKQogICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgICAgICAgY29uc3QgcGFyYW1KU09OID0gcGFyYW0udG9KU09OKGNvbnRleHQpOwogICAgICAgICAgICAgICAgaWYgKHBhcmFtSlNPTikgewogICAgICAgICAgICAgICAgICAgIHBhcmFtc0pTT05bcGFyYW0uZ2V0TmFtZSgpXSA9IHBhcmFtSlNPTjsKICAgICAgICAgICAgICAgICAgICBzYXZlZFBhcmFtcysrOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIChzYXZlZFBhcmFtcyA+IDApCiAgICAgICAgICAgICAgICBqc29uLnBhcmFtcyA9IHBhcmFtc0pTT047CiAgICAgICAgICAgIHJldHVybiBqc29uOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgZnJvbUpTT04gbWV0aG9kIGRlY29kZXMgYSBqc29uIG9iamVjdCBmb3IgdGhpcyB0eXBlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGpzb24gLSBUaGUganNvbiBvYmplY3QgdGhpcyBpdGVtIG11c3QgZGVjb2RlLgogICAgICAgICAqIEBwYXJhbSBjb250ZXh0IC0gVGhlIGNvbnRleHQgdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgZnJvbUpTT04oanNvbiwgY29udGV4dCkgewogICAgICAgICAgICBzdXBlci5mcm9tSlNPTihqc29uLCBjb250ZXh0KTsKICAgICAgICAgICAgaWYgKGpzb24ucGFyYW1zKSB7CiAgICAgICAgICAgICAgICBmb3IgKGNvbnN0IGtleSBpbiBqc29uLnBhcmFtcykgewogICAgICAgICAgICAgICAgICAgIGNvbnN0IHBqID0ganNvbi5wYXJhbXNba2V5XTsKICAgICAgICAgICAgICAgICAgICBpZiAocGoucGFyYW1QYXRoKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRleHQ/LnJlc29sdmVQYXRoKHBqLnBhcmFtUGF0aCwgKHBhcmFtKSA9PiB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnJlcGxhY2VQYXJhbWV0ZXIocGFyYW0pOwogICAgICAgICAgICAgICAgICAgICAgICB9LCAoKSA9PiB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oJ1VuYWJsZSB0byByZXNvbHZlIHNoYXJlZCBwYXJhbWV0ZXI6JyArIHBqLnBhcmFtUGF0aCk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAgICAgbGV0IHBhcmFtID0gdGhpcy5nZXRQYXJhbWV0ZXIoa2V5KTsKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFwYXJhbSAmJiBwai50eXBlICYmIHBqLm5hbWUpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFtID0gUmVnaXN0cnkuY29uc3RydWN0Q2xhc3MocGoudHlwZSk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoIXBhcmFtKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcignVW5hYmxlIHRvIGNvbnN0cnVjdCBwcm9wOicgKyBwai5uYW1lICsgJyBvZiB0eXBlOicgKyBwai50eXBlKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFtLnNldE5hbWUocGoubmFtZSk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmFkZFBhcmFtZXRlcihwYXJhbSk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHBhcmFtKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW0uZnJvbUpTT04ocGosIGNvbnRleHQpOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBVc2VzIHBhc3NlZCBpbiBCaW5SZWFkZXIgb2JqZWN0KGNvbnRhaW5pbmcgYW4gSW50MzIgYXJyYXkgd2l0aCBhbGwgdGhlIHBhcmFtZXRlcnMpIHRvIHJlY29uc3RydWN0IGFsbCBwYXJhbWV0ZXJzIHN0YXRlLgogICAgICAgICAqCiAgICAgICAgICogSW4gZWFjaCBpdGVyYXRpb24gb2YgdGhlIGFycmF5LCBwcm9wVHlwZSBhbmQgcHJvcE5hbWUgYXJlIGV4dHJhY3RlZCBhbmQKICAgICAgICAgKiB1c2VkIHRvIGJ1aWxkIHRoZSByaWdodCBgUGFyYW1ldGVyYCBjbGFzcy4gVGhlbiBhbGwgb2YgdGhlbSBhcmUgYWRkZWQgdG8gdGhlIG9iamVjdC4KICAgICAgICAgKgogICAgICAgICAqIEBlbWl0cyBgcGFyYW1ldGVyQWRkZWRgIHdpdGggdGhlIG5hbWUgb2YgdGhlIHBhcmFtLgogICAgICAgICAqIEBwYXJhbSByZWFkZXIgLSBUaGUgcmVhZGVyIHZhbHVlLgogICAgICAgICAqIEBwYXJhbSBjb250ZXh0IC0gVGhlIGNvbnRleHQgdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgcmVhZEJpbmFyeShyZWFkZXIsIGNvbnRleHQpIHsKICAgICAgICAgICAgc3VwZXIucmVhZEJpbmFyeShyZWFkZXIsIGNvbnRleHQpOwogICAgICAgICAgICB0aGlzLnJlYWRCaW5hcnlQYXJhbXMocmVhZGVyLCBjb250ZXh0KTsKICAgICAgICB9CiAgICAgICAgcmVhZEJpbmFyeVBhcmFtcyhyZWFkZXIsIGNvbnRleHQpIHsKICAgICAgICAgICAgaWYgKGNvbnRleHQ/LnZlcnNpb25zWyd6ZWEtZW5naW5lJ10uY29tcGFyZShbMCwgMCwgM10pID49IDApIHsKICAgICAgICAgICAgICAgIGNvbnN0IG51bVByb3BzID0gcmVhZGVyLmxvYWRVSW50MzIoKTsKICAgICAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbnVtUHJvcHM7IGkrKykgewogICAgICAgICAgICAgICAgICAgIGNvbnN0IHByb3BUeXBlID0gcmVhZGVyLmxvYWRTdHIoKTsKICAgICAgICAgICAgICAgICAgICBjb25zdCBwcm9wTmFtZSA9IHJlYWRlci5sb2FkU3RyKCk7CiAgICAgICAgICAgICAgICAgICAgbGV0IHBhcmFtID0gdGhpcy5nZXRQYXJhbWV0ZXIocHJvcE5hbWUpOwogICAgICAgICAgICAgICAgICAgIGlmICghcGFyYW0pIHsKICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW0gPSBSZWdpc3RyeS5jb25zdHJ1Y3RDbGFzcyhwcm9wVHlwZSk7CiAgICAgICAgICAgICAgICAgICAgICAgIGlmICghcGFyYW0pIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ1VuYWJsZSB0byBjb25zdHJ1Y3QgcHJvcDonICsgcHJvcE5hbWUgKyAnIG9mIHR5cGU6JyArIHByb3BUeXBlKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFtLnNldE5hbWUocHJvcE5hbWUpOwogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmFkZFBhcmFtZXRlcihwYXJhbSk7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIHBhcmFtLnJlYWRCaW5hcnkocmVhZGVyLCBjb250ZXh0KTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICAvLyAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCiAgICAgICAgLy8gQ2xvbmUgYW5kIERlc3Ryb3kKICAgICAgICAvKioKICAgICAgICAgKiBDbG9uZXMgdGhpcyBiYXNlIGl0ZW0gYW5kIHJldHVybnMgYSBuZXcgYmFzZSBpdGVtLgogICAgICAgICAqCiAgICAgICAgICogKipOb3RlOioqIEVhY2ggY2xhc3Mgc2hvdWxkIGltcGxlbWVudCBjbG9uZSB0byBiZSBjbG9uYWJsZS4KICAgICAgICAgKiBAcGFyYW0gY29udGV4dCAtIFRoZSBjb250ZXh0IHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGNsb25lKGNvbnRleHQpIHsKICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKHRoaXMuY29uc3RydWN0b3IubmFtZSArICcgZG9lcyBub3QgaW1wbGVtZW50IGl0cyBjbG9uZSBtZXRob2QnKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29waWVzIFBhcmFtZXRlcnMgZnJvbSBhbm90aGVyIGBQYXJhbWV0ZXJPd25lcmAgdG8gY3VycmVudCBvYmplY3QuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gc3JjIC0gVGhlIFBhcmFtZXRlck93bmVyIGNvcHkgZnJvbS4KICAgICAgICAgKiBAcGFyYW0gY29udGV4dCAtIFRoZSBjb250ZXh0IHZhbHVlCiAgICAgICAgICovCiAgICAgICAgY29weUZyb20oc3JjLCBjb250ZXh0KSB7CiAgICAgICAgICAgIGlmICghKHNyYyBpbnN0YW5jZW9mIFBhcmFtZXRlck93bmVyKSkgewogICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdjYW5ub3QgY29weSBmcm9tIHNyYycpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHN1cGVyLmNvcHlGcm9tKHNyYywgY29udGV4dCk7CiAgICAgICAgICAgIC8vIE5vdGU6IExvb3Agb3ZlciB0aGUgcGFyYW1ldGVycyBpbiByZXZlcnNlIG9yZGVyLAogICAgICAgICAgICAvLyB0aGlzIGlzIGJlY2F1c2Ugb2Z0ZW4sIHBhcmFtZXRlciBkZXBlbmRlbmNpZXMKICAgICAgICAgICAgLy8gYXJlIGJvdHRvbSB0byB0b3AgKGJvdHRvbSBwYXJhbXMgZGVwZW5kZW50IG9uIGhpZ2hlciBwYXJhbXMpLgogICAgICAgICAgICAvLyBUaGlzIG1lYW5zIHRoYXQgYXMgYSBwYXJhbWV0ZXIgaXMgc2V0IHdpdGggYSBuZXcgdmFsdWUKICAgICAgICAgICAgLy8gaXQgd2lsbCBkaXJ0eSB0aGUgcGFyYW1zIGJlbG93IGl0LgogICAgICAgICAgICBsZXQgaSA9IHNyYy5nZXROdW1QYXJhbWV0ZXJzKCk7CiAgICAgICAgICAgIHdoaWxlIChpLS0pIHsKICAgICAgICAgICAgICAgIGNvbnN0IHNyY1BhcmFtID0gc3JjLmdldFBhcmFtZXRlckJ5SW5kZXgoaSk7CiAgICAgICAgICAgICAgICBjb25zdCBwYXJhbSA9IHRoaXMuZ2V0UGFyYW1ldGVyKHNyY1BhcmFtLmdldE5hbWUoKSk7CiAgICAgICAgICAgICAgICBpZiAocGFyYW0pIHsKICAgICAgICAgICAgICAgICAgICAvLyBOb3RlOiB3ZSBhcmUgbm90IGNsb25pbmcgdGhlIHZhbHVlcy4KICAgICAgICAgICAgICAgICAgICBwYXJhbS5jb3B5RnJvbShzcmNQYXJhbSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgICAgICB0aGlzLmFkZFBhcmFtZXRlcihzcmNQYXJhbS5jbG9uZSgpKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KCiAgICAvKiBlc2xpbnQtZGlzYWJsZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tZXhwbGljaXQtYW55ICovCiAgICBmdW5jdGlvbiBhcHByb3hFcXVhbChhLCBiKSB7CiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBhLmxlbmd0aDsgaSsrKSB7CiAgICAgICAgICAgIGlmIChNYXRoLmFicyhiW2ldIC0gYVtpXSkgPiAwLjAwMSkKICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHRydWU7CiAgICB9CiAgICBjb25zdCByZXNpemVBcnJheSA9IChpbkFycmF5LCBuZXdTaXplKSA9PiB7CiAgICAgICAgaWYgKGluQXJyYXkgaW5zdGFuY2VvZiBVaW50OEFycmF5KSB7CiAgICAgICAgICAgIGNvbnN0IG5ld0FycmF5ID0gbmV3IFVpbnQ4QXJyYXkobmV3U2l6ZSk7CiAgICAgICAgICAgIG5ld0FycmF5LnNldChpbkFycmF5KTsKICAgICAgICAgICAgcmV0dXJuIG5ld0FycmF5OwogICAgICAgIH0KICAgICAgICBlbHNlIGlmIChpbkFycmF5IGluc3RhbmNlb2YgSW50OEFycmF5KSB7CiAgICAgICAgICAgIGNvbnN0IG5ld0FycmF5ID0gbmV3IEludDhBcnJheShuZXdTaXplKTsKICAgICAgICAgICAgbmV3QXJyYXkuc2V0KGluQXJyYXkpOwogICAgICAgICAgICByZXR1cm4gbmV3QXJyYXk7CiAgICAgICAgfQogICAgICAgIGVsc2UgaWYgKGluQXJyYXkgaW5zdGFuY2VvZiBVaW50MTZBcnJheSkgewogICAgICAgICAgICBjb25zdCBuZXdBcnJheSA9IG5ldyBVaW50MTZBcnJheShuZXdTaXplKTsKICAgICAgICAgICAgbmV3QXJyYXkuc2V0KGluQXJyYXkpOwogICAgICAgICAgICByZXR1cm4gbmV3QXJyYXk7CiAgICAgICAgfQogICAgICAgIGVsc2UgewogICAgICAgICAgICBjb25zdCBuZXdBcnJheSA9IG5ldyBGbG9hdDMyQXJyYXkobmV3U2l6ZSk7CiAgICAgICAgICAgIG5ld0FycmF5LnNldChpbkFycmF5KTsKICAgICAgICAgICAgcmV0dXJuIG5ld0FycmF5OwogICAgICAgIH0KICAgIH07CiAgICBjbGFzcyBBdHRyaWJ1dGUgZXh0ZW5kcyBCYXNlQ2xhc3MgewogICAgICAgIGRhdGFUeXBlTmFtZTsKICAgICAgICBzdHJpZGU7CiAgICAgICAgaW5pdFZhbHVlID0gTnVtYmVyLk5hTjsKICAgICAgICBub3JtYWxpemVkOwogICAgICAgIGRhdGE7CiAgICAgICAgbWVzaDsKICAgICAgICBzcGxpdFZhbHVlcyA9IFtdOwogICAgICAgIHNwbGl0cyA9IHt9OwogICAgICAgIGNvbnN0cnVjdG9yKGRhdGFUeXBlTmFtZSwgc3RyaWRlLCBpbml0VmFsdWUgPSBOdW1iZXIuTmFOKSB7CiAgICAgICAgICAgIHN1cGVyKCk7CiAgICAgICAgICAgIHRoaXMuZGF0YVR5cGVOYW1lID0gZGF0YVR5cGVOYW1lOwogICAgICAgICAgICB0aGlzLnN0cmlkZSA9IHN0cmlkZTsKICAgICAgICAgICAgdGhpcy5pbml0VmFsdWUgPSBpbml0VmFsdWU7CiAgICAgICAgICAgIHRoaXMuaW5pdCgpOwogICAgICAgIH0KICAgICAgICBpbml0KCkgewogICAgICAgICAgICB0aGlzLmRhdGEgPSBuZXcgRmxvYXQzMkFycmF5KDApOwogICAgICAgICAgICB0aGlzLmluaXRSYW5nZSgwKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU2V0cyB0aGUgTWVzaCByZWZlcmVuY2UgdG8gdGhlIFZlcnRleEF0dHJpYnV0ZS4gVGhpcyBpcyBuZWVkZWQgZm9yIGF0dHJpYnV0ZXMKICAgICAgICAgKiBhc3NpZ25lZCB0byBtZXNoZXMsIGFuZCBpcyB1c2VkIHRvIGNhbGN1bGF0ZSBmYWNlIHZlcnRleCBpbmRpY2VzLgogICAgICAgICAqID4gTm90ZTogdGhlIG1lc2ggYXV0b21hdGljYWxseSBjYWxscyB0aGlzIG1ldGhvZCB3aGVuIGEgdmVydGV4IGF0dHJpYnV0ZSBpcyBhc3NpZ25lZC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBtZXNoIC0gVGhlIG1lc2ggb2JqZWN0CiAgICAgICAgICovCiAgICAgICAgc2V0TWVzaChtZXNoKSB7CiAgICAgICAgICAgIHRoaXMubWVzaCA9IG1lc2g7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgdGhlIGJhY2tpbmcgYXJyYXkgZm9yIHRoaXMgYXR0cmlidXRlCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBhc0FycmF5KCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy5kYXRhOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIHRoZSBuYW1lIG9mIHRoZSBtYXRoIHR5cGUgdGhpcyBhdHRyaWJ1dGUgc3RvcmVzLgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgZ2V0RGF0YVR5cGVOYW1lKCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy5kYXRhVHlwZU5hbWU7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgdGhlIGNvdW50IG9mIGF0dHJpYnV0ZSB2YWx1ZXMgaW4gdGhlIGRhdGEuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBnZXRDb3VudCgpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuZGF0YS5sZW5ndGggLyB0aGlzLnN0cmlkZTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyB0aGUgY291bnQgb2YgYXR0cmlidXRlIHZhbHVlcyBpbiB0aGUgZGF0YS4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGdldCBjb3VudCgpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuZGF0YS5sZW5ndGggLyB0aGlzLnN0cmlkZTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU2V0cyB0aGUgY291bnQgb2YgYXR0cmlidXRlIHZhbHVlcyBpbiB0aGUgZGF0YS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBzaXplIC0gVGhlIHNpemUgdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgc2V0Q291bnQoY291bnQpIHsKICAgICAgICAgICAgY29uc3QgcHJldkxlbmd0aCA9IHRoaXMuZGF0YS5sZW5ndGg7CiAgICAgICAgICAgIGNvbnN0IG5ld0xlbmd0aCA9IGNvdW50ICogdGhpcy5zdHJpZGU7CiAgICAgICAgICAgIGlmIChuZXdMZW5ndGggPiBwcmV2TGVuZ3RoKSB7CiAgICAgICAgICAgICAgICB0aGlzLmRhdGEgPSByZXNpemVBcnJheSh0aGlzLmRhdGEsIG5ld0xlbmd0aCk7CiAgICAgICAgICAgICAgICB0aGlzLmluaXRSYW5nZShwcmV2TGVuZ3RoKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBlbHNlIGlmIChuZXdMZW5ndGggPCBwcmV2TGVuZ3RoKSB7CiAgICAgICAgICAgICAgICB0aGlzLmRhdGEgPSB0aGlzLmRhdGEuc2xpY2UoMCwgbmV3TGVuZ3RoKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBlbHNlIDsKICAgICAgICAgICAgdGhpcy5zcGxpdHMgPSB7fTsKICAgICAgICAgICAgdGhpcy5zcGxpdFZhbHVlcyA9IFtdOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBGaWxscyB1cCBkYXRhIHZhbHVlcyB3aXRoIGRlZmF1bHQgb25lcyBzdGFydGluZyBmcm9tIHRoZSBzcGVjaWZpZWQgaW5kZXguCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gc3RhcnQgLSBUaGUgc3RhcnQgdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgaW5pdFJhbmdlKHN0YXJ0KSB7CiAgICAgICAgICAgIC8vIEluaXRpYWxpemUgdGhlIHZhbHVlcyB0byBpbnZhbGlkIHZhbHVlcy4KICAgICAgICAgICAgZm9yIChsZXQgaSA9IHN0YXJ0OyBpIDwgdGhpcy5kYXRhLmxlbmd0aDsgaSsrKSB7CiAgICAgICAgICAgICAgICB0aGlzLmRhdGFbaV0gPSB0aGlzLmluaXRWYWx1ZTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBpc0luaXRpYWxpemVkKGEpIHsKICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBhLmxlbmd0aDsgaSsrKSB7CiAgICAgICAgICAgICAgICBpZiAoYVtpXSAhPSB0aGlzLmluaXRWYWx1ZSkKICAgICAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgdGhlIG51bWJlciBvZiBlbGVtZW50cyBzdG9yZWQgaW4gZWFjaCBgVGAuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBnZXQgbnVtRWxlbWVudHMoKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLnN0cmlkZTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyBkYXRhIHZhbHVlIG9mIHRoZSBzcGVjaWZpZWQgaW5kZXguCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gaW5kZXggLSBUaGUgaW5kZXggdmFsdWUuCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgZ2V0RmxvYXQzMlZhbHVlKGluZGV4KSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLmRhdGFbaW5kZXhdOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTZXRzIGRhdGEgdmFsdWUgaW4gdGhlIHNwZWNpZmllZCBpbmRleC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBpbmRleCAtIFRoZSBpbmRleCB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0gdmFsdWUgLSBUaGUgdmFsdWUgcGFyYW0uCiAgICAgICAgICovCiAgICAgICAgc2V0RmxvYXQzMlZhbHVlKGluZGV4LCB2YWx1ZSkgewogICAgICAgICAgICB0aGlzLmRhdGFbaW5kZXhdID0gdmFsdWU7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFNldHMgZGF0YSB2YWx1ZXMgaW4gdGhlIHNwZWNpZmllZCBpbmRleC4KICAgICAgICAgKi8KICAgICAgICBnZXRWYWx1ZXMoaW5kZXgpIHsKICAgICAgICAgICAgaWYgKGluZGV4ID49IHRoaXMuZGF0YS5sZW5ndGggLyB0aGlzLnN0cmlkZSkKICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCB2ZXJ0ZXggaW5kZXg6JyArIGluZGV4ICsgJy4gTnVtIFZlcnRpY2VzOicgKyB0aGlzLmRhdGEubGVuZ3RoIC8gdGhpcy5zdHJpZGUpOwogICAgICAgICAgICBjb25zdCBvZmZzZXQgPSBpbmRleCAqIHRoaXMuc3RyaWRlOwogICAgICAgICAgICByZXR1cm4gdGhpcy5kYXRhLnN1YmFycmF5KG9mZnNldCwgb2Zmc2V0ICsgdGhpcy5zdHJpZGUpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTZXRzIGRhdGEgdmFsdWVzIGluIHRoZSBzcGVjaWZpZWQgaW5kZXguCiAgICAgICAgICovCiAgICAgICAgc2V0VmFsdWVzKGluZGV4LCB2YWx1ZXMpIHsKICAgICAgICAgICAgaWYgKGluZGV4ID49IHRoaXMuZGF0YS5sZW5ndGggLyB0aGlzLnN0cmlkZSkKICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCB2ZXJ0ZXggaW5kZXg6JyArIGluZGV4ICsgJy4gTnVtIFZlcnRpY2VzOicgKyB0aGlzLmRhdGEubGVuZ3RoIC8gdGhpcy5zdHJpZGUpOwogICAgICAgICAgICBjb25zdCBvZmZzZXQgPSBpbmRleCAqIHRoaXMuc3RyaWRlOwogICAgICAgICAgICB0aGlzLmRhdGEuc2V0KHZhbHVlcywgb2Zmc2V0KTsKICAgICAgICB9CiAgICAgICAgbWVyZ2Uob3RoZXIsIHhmbyA9IG5ldyBYZm8oKSkgewogICAgICAgICAgICBjb25zdCBwcmV2TnVtVmFsdWVzID0gdGhpcy5kYXRhLmxlbmd0aDsKICAgICAgICAgICAgY29uc3QgYWRkZWRWYWx1ZXMgPSBvdGhlci5kYXRhLmxlbmd0aDsKICAgICAgICAgICAgY29uc3QgbmV3TGVuZ3RoID0gcHJldk51bVZhbHVlcyArIGFkZGVkVmFsdWVzOwogICAgICAgICAgICBjb25zdCBkYXRhID0gbmV3IEZsb2F0MzJBcnJheShuZXdMZW5ndGgpOwogICAgICAgICAgICBkYXRhLnNldCh0aGlzLmRhdGEsIDApOwogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGFkZGVkVmFsdWVzOyBpKyspIHsKICAgICAgICAgICAgICAgIGRhdGFbcHJldk51bVZhbHVlcyArIGldID0gb3RoZXIuZGF0YVtpXTsKICAgICAgICAgICAgfQogICAgICAgICAgICB0aGlzLmRhdGEgPSBkYXRhOwogICAgICAgICAgICB0aGlzLnNwbGl0VmFsdWVzID0gWy4uLnRoaXMuc3BsaXRWYWx1ZXMsIC4uLm90aGVyLnNwbGl0VmFsdWVzXTsKICAgICAgICB9CiAgICAgICAgLy8gLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KICAgICAgICAvLyBGYWNlIFZlcnRleCBWYWx1ZXMKICAgICAgICAvKioKICAgICAgICAgKiBUaGUgZ2V0U3BsaXRzIG1ldGhvZC4KICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBnZXRTcGxpdHMoKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLnNwbGl0czsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogR2V0cyB0aGUgdmFsdWUgb2YgYSBjb3JuZXIgdmVydGV4IG9mIGEgZmFjZS4KICAgICAgICAgKiBAcGFyYW0gZmFjZSAtIFRoZSBmYWNlIGluZGV4LgogICAgICAgICAqIEBwYXJhbSBmYWNlVmVydGV4IC0gVGhlIGluZGV4IG9mIHZlcnRleCB3aXRoaW4gdGhlIGZhY2UuIFswLi4uIG51bSBmYWNlIHZlcnRpY2VzXQogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGdldEZhY2VWZXJ0ZXhWYWx1ZV9hcnJheShmYWNlLCBmYWNlVmVydGV4KSB7CiAgICAgICAgICAgIGNvbnN0IHZlcnRleCA9IHRoaXMubWVzaC5nZXRGYWNlVmVydGV4SW5kZXgoZmFjZSwgZmFjZVZlcnRleCk7CiAgICAgICAgICAgIGlmICh2ZXJ0ZXggaW4gdGhpcy5zcGxpdHMgJiYgZmFjZSBpbiB0aGlzLnNwbGl0c1t2ZXJ0ZXhdKSB7CiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5zcGxpdFZhbHVlc1t0aGlzLnNwbGl0c1t2ZXJ0ZXhdW2ZhY2VdXTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gdGhpcy5kYXRhLnN1YmFycmF5KHZlcnRleCAqIHRoaXMuc3RyaWRlLCAodmVydGV4ICsgMSkgKiB0aGlzLnN0cmlkZSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFNldHMgdGhlIHZhbHVlIG9mIGEgY29ybmVyIHZlcnRleCBvZiBhIGZhY2UuCiAgICAgICAgICogQHBhcmFtIGZhY2UgLSBUaGUgZmFjZSBpbmRleC4KICAgICAgICAgKiBAcGFyYW0gZmFjZVZlcnRleCAtIFRoZSBpbmRleCBvZiB2ZXJ0ZXggd2l0aGluIHRoZSBmYWNlLiBbMC4uLiBudW0gZmFjZSB2ZXJ0aWNlc10KICAgICAgICAgKiBAcGFyYW0gdmFsdWUgLSBUaGUgdmFsdWUgdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgc2V0RmFjZVZlcnRleFZhbHVlX2FycmF5KGZhY2UsIGZhY2VWZXJ0ZXgsIHZhbHVlKSB7CiAgICAgICAgICAgIGNvbnN0IHZlcnRleCA9IHRoaXMubWVzaC5nZXRGYWNlVmVydGV4SW5kZXgoZmFjZSwgZmFjZVZlcnRleCk7CiAgICAgICAgICAgIHRoaXMuc2V0RmFjZVZlcnRleFZhbHVlX0J5VmVydGV4SW5kZXgoZmFjZSwgdmVydGV4LCB2YWx1ZSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBzZXRGYWNlVmVydGV4VmFsdWVfQnlWZXJ0ZXhJbmRleCBtZXRob2QuCiAgICAgICAgICogQHBhcmFtIGZhY2UgLSBUaGUgZmFjZSBpbmRleC4KICAgICAgICAgKiBAcGFyYW0gdmVydGV4IC0gVGhlIHZlcnRleCB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0gdmFsdWUgLSBUaGUgdmFsdWUgdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgc2V0RmFjZVZlcnRleFZhbHVlX0J5VmVydGV4SW5kZXgoZmFjZSwgdmVydGV4LCB2YWx1ZSkgewogICAgICAgICAgICBjb25zdCBjdXJyVmFsdWUgPSB0aGlzLmRhdGEuc3ViYXJyYXkodmVydGV4ICogdGhpcy5zdHJpZGUsICh2ZXJ0ZXggKyAxKSAqIHRoaXMuc3RyaWRlKTsKICAgICAgICAgICAgaWYgKCF0aGlzLmlzSW5pdGlhbGl6ZWQoY3VyclZhbHVlKSkgewogICAgICAgICAgICAgICAgLy8gdGhlIHZhbHVlIGlzIHVuaW5pdGlhbGl6ZWQuIEluaXRpYWxpemUgaXQuCiAgICAgICAgICAgICAgICBjdXJyVmFsdWUuc2V0KHZhbHVlKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBlbHNlIGlmIChhcHByb3hFcXVhbChjdXJyVmFsdWUsIHZhbHVlKSkgOwogICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgIC8vIFRoZSBuZXcgdmFsdWUgaXMgZGlmZmVyZW50IGZyb20gdGhlIGV4aXN0aW5nIHZhbHVlCiAgICAgICAgICAgICAgICBpZiAodmVydGV4IGluIHRoaXMuc3BsaXRzKSB7CiAgICAgICAgICAgICAgICAgICAgLy8gTm93IGNoZWNrIGlmIGFueSBleGlzdGluZyBzcGxpdHMgZm9yIHRoaXMgdmVydGV4IG1hdGNoIHRoZSB2YWx1ZSBiZWluZyBzZXQuCiAgICAgICAgICAgICAgICAgICAgLy8gaS5lLiBmb3IgZmFjZXMgYXJvdW5kIGEgdmVydGV4LCB0aGVyZSB3aWxsIG9mdGVuIGJlIGEgc2VhbSBhbG9uZyAyIGVkZ2VzCiAgICAgICAgICAgICAgICAgICAgLy8gd2hlcmUgdGhlIHZhbHVlcyBkaWZmZXIuIE9uIGVhY2ggc2lkZSBvZiB0aGUgc2VhbSwgYWxsIGZhY2VzIGNhbiB1c2UgdGhlIHNhbWUKICAgICAgICAgICAgICAgICAgICAvLyB2YWx1ZS4gV2Ugc2hvdWxkIHNlZSB0aGVuIG9ubHkgb25lIHNwbGl0IHZhbHVlIGZvciB0aGUgdmVydGV4LgogICAgICAgICAgICAgICAgICAgIGNvbnN0IHZlcnRleFNwbGl0SWRzID0gdGhpcy5zcGxpdHNbdmVydGV4XTsKICAgICAgICAgICAgICAgICAgICBmb3IgKGNvbnN0IGZpZCBpbiB2ZXJ0ZXhTcGxpdElkcykgewogICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBzcGxpdElkID0gdmVydGV4U3BsaXRJZHNbZmlkXTsKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGFwcHJveEVxdWFsKHRoaXMuc3BsaXRWYWx1ZXNbc3BsaXRJZF0sIHZhbHVlKSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gcmUtdXNlIHRoaXMgc3BsaXQgdmFsdWUKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlcnRleFNwbGl0SWRzW2ZhY2VdID0gc3BsaXRJZDsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAvLyBJZiBhIHNwbGl0IGFscmVhZHkgZXhpc3RzIGZvciB0aGlzIGZhY2UsIHJlLXVzZSBpdC4KICAgICAgICAgICAgICAgICAgICBpZiAoZmFjZSBpbiB0aGlzLnNwbGl0c1t2ZXJ0ZXhdKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuc3BsaXRWYWx1ZXNbdGhpcy5zcGxpdHNbdmVydGV4XVtmYWNlXV0gPSB2YWx1ZTsKICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGVsc2UgewogICAgICAgICAgICAgICAgICAgIHRoaXMuc3BsaXRzW3ZlcnRleF0gPSB7fTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIHRoaXMuc3BsaXRzW3ZlcnRleF1bZmFjZV0gPSB0aGlzLnNwbGl0VmFsdWVzLmxlbmd0aDsKICAgICAgICAgICAgICAgIHRoaXMuc3BsaXRWYWx1ZXMucHVzaCh2YWx1ZSk7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIHNldFNwbGl0VmVydGV4VmFsdWUgbWV0aG9kLgogICAgICAgICAqIEBwYXJhbSB2ZXJ0ZXggLSBUaGUgdmVydGV4IHZhbHVlLgogICAgICAgICAqIEBwYXJhbSBmYWNlIC0gVGhlIGZhY2UgaW5kZXguCiAgICAgICAgICogQHBhcmFtIHZhbHVlIC0gVGhlIHZhbHVlIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHNldFNwbGl0VmVydGV4VmFsdWVfYXJyYXkodmVydGV4LCBmYWNlLCB2YWx1ZSkgewogICAgICAgICAgICBpZiAoISh2ZXJ0ZXggaW4gdGhpcy5zcGxpdHMpKQogICAgICAgICAgICAgICAgdGhpcy5zcGxpdHNbdmVydGV4XSA9IHt9OwogICAgICAgICAgICBpZiAoZmFjZSBpbiB0aGlzLnNwbGl0c1t2ZXJ0ZXhdKSB7CiAgICAgICAgICAgICAgICBjb25zdCBjdXJyVmFsdWUgPSB0aGlzLnNwbGl0VmFsdWVzW3RoaXMuc3BsaXRzW3ZlcnRleF1bZmFjZV1dOwogICAgICAgICAgICAgICAgaWYgKGFwcHJveEVxdWFsKGN1cnJWYWx1ZSwgdmFsdWUpKQogICAgICAgICAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybignRmFjZSBWZXJ0ZXggQWxyZWFkeSBTcGxpdCB3aXRoIGRpZmZlcmVudCB2YWx1ZScpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHRoaXMuc3BsaXRzW3ZlcnRleF1bZmFjZV0gPSB0aGlzLnNwbGl0VmFsdWVzLmxlbmd0aDsKICAgICAgICAgICAgdGhpcy5zcGxpdFZhbHVlcy5wdXNoKHZhbHVlKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIHNldFNwbGl0VmVydGV4VmFsdWVzIG1ldGhvZC4KICAgICAgICAgKiBAcGFyYW0gdmVydGV4IC0gVGhlIHZlcnRleCB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0gZmFjZUdyb3VwIC0gVGhlIGZhY2VHcm91cCB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0gdmFsdWUgLSBUaGUgdmFsdWUgdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgc2V0U3BsaXRWZXJ0ZXhWYWx1ZXModmVydGV4LCBmYWNlR3JvdXAsIHZhbHVlcykgewogICAgICAgICAgICBpZiAoISh2ZXJ0ZXggaW4gdGhpcy5zcGxpdHMpKQogICAgICAgICAgICAgICAgdGhpcy5zcGxpdHNbdmVydGV4XSA9IHt9OwogICAgICAgICAgICBjb25zdCBzcGxpdEluZGV4ID0gdGhpcy5zcGxpdFZhbHVlcy5sZW5ndGg7CiAgICAgICAgICAgIHRoaXMuc3BsaXRWYWx1ZXMucHVzaCh2YWx1ZXMpOwogICAgICAgICAgICBmb3IgKGNvbnN0IGZhY2Ugb2YgZmFjZUdyb3VwKSB7CiAgICAgICAgICAgICAgICAvLyBpZiAoZmFjZSBpbiB0aGlzLnNwbGl0c1t2ZXJ0ZXhdKSB7CiAgICAgICAgICAgICAgICAvLyAgICAgbGV0IGN1cnJWYWx1ZSA9IHRoaXMuc3BsaXRWYWx1ZXNbdGhpcy5zcGxpdHNbdmVydGV4XVtmYWNlXV07CiAgICAgICAgICAgICAgICAvLyAgICAgaWYgKGN1cnJWYWx1ZS5hcHByb3hFcXVhbCh2YWx1ZSkpCiAgICAgICAgICAgICAgICAvLyAgICAgICAgIHJldHVybjsKICAgICAgICAgICAgICAgIC8vICAgICBjb25zb2xlLndhcm4oIkZhY2UgVmVydGV4IEFscmVhZHkgU3BsaXQgd2l0aCBkaWZmZXJlbnQgdmFsdWUiKTsKICAgICAgICAgICAgICAgIC8vIH0KICAgICAgICAgICAgICAgIHRoaXMuc3BsaXRzW3ZlcnRleF1bZmFjZV0gPSBzcGxpdEluZGV4OwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBnZW5lcmF0ZVNwbGl0VmFsdWVzIG1ldGhvZC4KICAgICAgICAgKiBAcGFyYW0gc3BsaXRJbmRpY2VzIC0gVGhlIHNwbGl0SW5kaWNlcyB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0gc3BsaXRDb3VudCAtIFRoZSBzcGxpdENvdW50IHZhbHVlLgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGdlbmVyYXRlU3BsaXRWYWx1ZXMoc3BsaXRJbmRpY2VzLCBzcGxpdENvdW50KSB7CiAgICAgICAgICAgIGlmIChzcGxpdENvdW50ID09IDApCiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5kYXRhOwogICAgICAgICAgICBjb25zdCBudW1VblNwbGl0VmFsdWVzID0gdGhpcy5nZXRDb3VudCgpOwogICAgICAgICAgICBjb25zdCBkYXRhID0gcmVzaXplQXJyYXkodGhpcy5kYXRhLCAobnVtVW5TcGxpdFZhbHVlcyArIHNwbGl0Q291bnQpICogdGhpcy5zdHJpZGUpOwogICAgICAgICAgICAvLyBOb3cgZHVwbGljYXRlIHRoZSBzcGxpdCB2YWx1ZXMgdG8gZ2VuZXJhdGUgYW4gYXR0cmlidXRlcyBhcnJheQogICAgICAgICAgICAvLyB1c2luZyB0aGUgc2hhcmVkIHNwbGl0cyBhY3Jvc3MgYWxsIGF0dHJpYnV0ZXMuCiAgICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBndWFyZC1mb3ItaW4KICAgICAgICAgICAgZm9yIChjb25zdCB2ZXJ0ZXggaW4gc3BsaXRJbmRpY2VzKSB7CiAgICAgICAgICAgICAgICBjb25zdCBmYWNlcyA9IHNwbGl0SW5kaWNlc1t2ZXJ0ZXhdOwogICAgICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGd1YXJkLWZvci1pbgogICAgICAgICAgICAgICAgZm9yIChjb25zdCBmYWNlIGluIGZhY2VzKSB7CiAgICAgICAgICAgICAgICAgICAgY29uc3QgdGd0ID0gbnVtVW5TcGxpdFZhbHVlcyArIGZhY2VzW2ZhY2VdOwogICAgICAgICAgICAgICAgICAgIGlmICh2ZXJ0ZXggaW4gdGhpcy5zcGxpdHMgJiYgZmFjZSBpbiB0aGlzLnNwbGl0c1t2ZXJ0ZXhdKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHRoaXMgYXR0cmlidXRlIGhhcyBhIHNwbGl0IHZhbHVlIGluIGl0cyBhcnJheS4KICAgICAgICAgICAgICAgICAgICAgICAgLy8gd2UgbXVzdCB1c2UgdGhhdCB2YWx1ZS4uLgogICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBzcmMgPSB0aGlzLnNwbGl0c1t2ZXJ0ZXhdW2ZhY2VdOwogICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBzcmNBcnJheSA9IHRoaXMuc3BsaXRWYWx1ZXNbc3JjXTsKICAgICAgICAgICAgICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzcmNBcnJheS5sZW5ndGg7IGkrKykgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YVt0Z3QgKiB0aGlzLnN0cmlkZSArIGldID0gc3JjQXJyYXlbaV07CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgICAgIC8vIENvcHkgZWFjaCBzY2FsYXIgdmFsdWUgdG8gdGhlIG5ldyBwbGFjZSBpbiB0aGUgYXJyYXkuCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHNyYyA9IHBhcnNlSW50KHZlcnRleCk7CiAgICAgICAgICAgICAgICAgICAgICAgIGZvciAobGV0IGUgPSAwOyBlIDwgdGhpcy5zdHJpZGU7IGUrKykgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YVt0Z3QgKiB0aGlzLnN0cmlkZSArIGVdID0gdGhpcy5kYXRhW3NyYyAqIHRoaXMuc3RyaWRlICsgZV07CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIGRhdGE7CiAgICAgICAgfQogICAgICAgIC8vIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KICAgICAgICAvLyBQZXJzaXN0ZW5jZQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSB0b0pTT04gbWV0aG9kIGVuY29kZXMgdGhpcyB0eXBlIGFzIGEganNvbiBvYmplY3QgZm9yIHBlcnNpc3RlbmNlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGNvbnRleHQgLSBUaGUgY29udGV4dCB2YWx1ZS4KICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyB0aGUganNvbiBvYmplY3QuCiAgICAgICAgICovCiAgICAgICAgdG9KU09OKGNvbnRleHQpIHsKICAgICAgICAgICAgcmV0dXJuIHsKICAgICAgICAgICAgICAgIGRhdGE6IEFycmF5LmZyb20odGhpcy5kYXRhKSwKICAgICAgICAgICAgICAgIGRhdGFUeXBlOiB0aGlzLmRhdGFUeXBlTmFtZSwKICAgICAgICAgICAgICAgIGxlbmd0aDogdGhpcy5kYXRhLmxlbmd0aCAvIHRoaXMuc3RyaWRlLAogICAgICAgICAgICB9OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgZnJvbUpTT04gbWV0aG9kIGRlY29kZXMgYSBqc29uIG9iamVjdCBmb3IgdGhpcyB0eXBlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGogLSBUaGUganNvbiBvYmplY3QgdGhpcyBpdGVtIG11c3QgZGVjb2RlLgogICAgICAgICAqLwogICAgICAgIGZyb21KU09OKGopIHsKICAgICAgICAgICAgY29uc3QgZGF0YSA9IGouZGF0YTsKICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBkYXRhLmxlbmd0aDsgaSsrKSB7CiAgICAgICAgICAgICAgICB0aGlzLmRhdGFbaV0gPSBkYXRhW2ldOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBsb2FkU3BsaXRWYWx1ZXMgbWV0aG9kLgogICAgICAgICAqIEBwYXJhbSByZWFkZXIgLSBUaGUgcmVhZGVyIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGxvYWRTcGxpdFZhbHVlcyhyZWFkZXIpIHsKICAgICAgICAgICAgY29uc3Qgc3BsaXRJbmRpY2VzID0gcmVhZGVyLmxvYWRVSW50MzJBcnJheSgpOwogICAgICAgICAgICBpZiAoc3BsaXRJbmRpY2VzLmxlbmd0aCA9PSAwKQogICAgICAgICAgICAgICAgcmV0dXJuOwogICAgICAgICAgICBsZXQgb2Zmc2V0ID0gMDsKICAgICAgICAgICAgbGV0IG51bVNwbGl0VmFsdWVzID0gMDsKICAgICAgICAgICAgd2hpbGUgKHRydWUpIHsKICAgICAgICAgICAgICAgIGNvbnN0IHZlcnRleElkID0gc3BsaXRJbmRpY2VzW29mZnNldCsrXTsKICAgICAgICAgICAgICAgIGNvbnN0IG51bVNwbGl0cyA9IHNwbGl0SW5kaWNlc1tvZmZzZXQrK107CiAgICAgICAgICAgICAgICBjb25zdCBzcGxpdHMgPSB7fTsKICAgICAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbnVtU3BsaXRzOyBpKyspIHsKICAgICAgICAgICAgICAgICAgICBjb25zdCBmYWNlSWQgPSBzcGxpdEluZGljZXNbb2Zmc2V0KytdOwogICAgICAgICAgICAgICAgICAgIGNvbnN0IHNwbGl0SWQgPSBzcGxpdEluZGljZXNbb2Zmc2V0KytdOwogICAgICAgICAgICAgICAgICAgIHNwbGl0c1tmYWNlSWRdID0gc3BsaXRJZDsKICAgICAgICAgICAgICAgICAgICBpZiAoc3BsaXRJZCA+PSBudW1TcGxpdFZhbHVlcykKICAgICAgICAgICAgICAgICAgICAgICAgbnVtU3BsaXRWYWx1ZXMgPSBzcGxpdElkICsgMTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIHRoaXMuc3BsaXRzW3ZlcnRleElkXSA9IHNwbGl0czsKICAgICAgICAgICAgICAgIGlmIChvZmZzZXQgPj0gc3BsaXRJbmRpY2VzLmxlbmd0aCkKICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgfQogICAgICAgICAgICBjb25zdCBkaW0gPSB0aGlzLnN0cmlkZTsKICAgICAgICAgICAgY29uc3Qgc3BsaXRWYWx1ZXMgPSByZWFkZXIubG9hZEZsb2F0MzJBcnJheShudW1TcGxpdFZhbHVlcyAqIGRpbSk7CiAgICAgICAgICAgIHRoaXMuc3BsaXRWYWx1ZXMgPSBbXTsKICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBudW1TcGxpdFZhbHVlczsgaSsrKSB7CiAgICAgICAgICAgICAgICBjb25zdCB2YWwgPSBzcGxpdFZhbHVlcy5zbGljZShpICogZGltLCBpICogZGltICsgZGltKTsKICAgICAgICAgICAgICAgIHRoaXMuc3BsaXRWYWx1ZXMucHVzaCh2YWwpOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgdGhlIHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiB0aGUgb2JqZWN0J3Mgc3RhdGUuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICB0b1N0cmluZygpIHsKICAgICAgICAgICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KHRoaXMudG9KU09OKCksIG51bGwsIDIpOwogICAgICAgIH0KICAgICAgICAvLyAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCiAgICAgICAgLy8gTWVtb3J5CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyB2ZXJ0ZXggYXR0cmlidXRlcyBidWZmZXJzIGFuZCBpdHMgY291bnQuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBnZW5CdWZmZXIoKSB7CiAgICAgICAgICAgIHJldHVybiB7CiAgICAgICAgICAgICAgICB2YWx1ZXM6IHRoaXMuZGF0YSwKICAgICAgICAgICAgICAgIGNvdW50OiB0aGlzLmdldENvdW50KCksCiAgICAgICAgICAgICAgICBkaW1lbnNpb246IHRoaXMuc3RyaWRlLAogICAgICAgICAgICAgICAgZGF0YVR5cGU6IHRoaXMuZGF0YVR5cGVOYW1lLAogICAgICAgICAgICAgICAgbm9ybWFsaXplZDogdGhpcy5ub3JtYWxpemVkLAogICAgICAgICAgICB9OwogICAgICAgIH0KICAgIH0KCiAgICAvKioKICAgICAqIENsYXNzIHJlcHJlc2VudGluZyBhbiBhdHRyaWJ1dGUuCiAgICAgKi8KICAgIGNsYXNzIFZlYzJBdHRyaWJ1dGUgZXh0ZW5kcyBBdHRyaWJ1dGUgewogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZSBhIFZlYzJBdHRyaWJ1dGUuCiAgICAgICAgICovCiAgICAgICAgY29uc3RydWN0b3IoZGF0YVR5cGVOYW1lID0gJ1ZlYzInKSB7CiAgICAgICAgICAgIHN1cGVyKGRhdGFUeXBlTmFtZSwgMik7CiAgICAgICAgICAgIHRoaXMubm9ybWFsaXplZCA9IGZhbHNlOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIHRoZSBWZWMyIGZyb20gdGhlIHNwZWNpZmllZCBpbmRleC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBpbmRleCAtIFRoZSBpbmRleCB2YWx1ZS4KICAgICAgICAgKiBAcmV0dXJuIFZlYzIgLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGdldFZhbHVlKGluZGV4KSB7CiAgICAgICAgICAgIGlmIChpbmRleCA+PSB0aGlzLmRhdGEubGVuZ3RoIC8gdGhpcy5zdHJpZGUpCiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgdmVydGV4IGluZGV4OicgKyBpbmRleCArICcuIE51bSBWZXJ0aWNlczonICsgdGhpcy5kYXRhLmxlbmd0aCAvIDMpOwogICAgICAgICAgICBjb25zdCBvZmZzZXQgPSBpbmRleCAqIHRoaXMuc3RyaWRlOwogICAgICAgICAgICByZXR1cm4gbmV3IFZlYzIodGhpcy5kYXRhW29mZnNldF0sIHRoaXMuZGF0YVtvZmZzZXQgKyAxXSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFNldHMgVmVjMiBhdCB0aGUgc3BlY2lmaWVkIGluZGV4LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGluZGV4IC0gVGhlIGluZGV4IHZhbHVlLgogICAgICAgICAqIEBwYXJhbSB2YWx1ZSAtIFRoZSB2YWx1ZSBwYXJhbS4KICAgICAgICAgKi8KICAgICAgICBzZXRWYWx1ZShpbmRleCwgdmFsdWUpIHsKICAgICAgICAgICAgaWYgKGluZGV4ID49IHRoaXMuZGF0YS5sZW5ndGggLyB0aGlzLnN0cmlkZSkKICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCB2ZXJ0ZXggaW5kZXg6JyArIGluZGV4ICsgJy4gTnVtIFZlcnRpY2VzOicgKyB0aGlzLmRhdGEubGVuZ3RoIC8gMyk7CiAgICAgICAgICAgIGNvbnN0IG9mZnNldCA9IGluZGV4ICogdGhpcy5zdHJpZGU7CiAgICAgICAgICAgIHRoaXMuZGF0YS5zZXQodmFsdWUuYXNBcnJheSgpLCBvZmZzZXQpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBHZXRzIHRoZSB2YWx1ZSBvZiBhIGNvcm5lciB2ZXJ0ZXggb2YgYSBmYWNlLgogICAgICAgICAqID4gTm90ZTogJ1JlZicgbWVhbnMgdGhhdCB0aGUgdmFsdWUgY29udGFpbnMgYSByZWZlcmVuY2UgdG8gdGhlIGRhdGEgaW4gdGhlIGF0dHJpYnV0ZS4KICAgICAgICAgKiA+IFRoZSBjb21wb25lbnRzIG9mIHRoZSB2YWx1ZSBjYW4gYmUgY2hhbmdlZCBjYXVzaW5nIHRoZSBhdHRyaWJ1dGVzIGRhdGEgaXMgY2hhbmdlZC4KICAgICAgICAgKiA+IE5vIG5lZWQgdG8gY2FsbCAnc2V0RmFjZVZlcnRleFZhbHVlJy4KICAgICAgICAgKiBAcGFyYW0gZmFjZSAtIFRoZSBmYWNlIGluZGV4LgogICAgICAgICAqIEBwYXJhbSBmYWNlVmVydGV4IC0gVGhlIGluZGV4IG9mIHZlcnRleCB3aXRoaW4gdGhlIGZhY2UuIFswLi4uIG51bSBmYWNlIHZlcnRpY2VzXQogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGdldEZhY2VWZXJ0ZXhWYWx1ZShmYWNlLCBmYWNlVmVydGV4KSB7CiAgICAgICAgICAgIGNvbnN0IGFycmF5ID0gdGhpcy5nZXRGYWNlVmVydGV4VmFsdWVfYXJyYXkoZmFjZSwgZmFjZVZlcnRleCk7CiAgICAgICAgICAgIHJldHVybiBuZXcgVmVjMihhcnJheVswXSwgYXJyYXlbMV0pOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTZXRzIHRoZSB2YWx1ZSBvZiBhIGNvcm5lciB2ZXJ0ZXggb2YgYSBmYWNlLgogICAgICAgICAqIEBwYXJhbSBmYWNlIC0gVGhlIGZhY2UgaW5kZXguCiAgICAgICAgICogQHBhcmFtIGZhY2VWZXJ0ZXggLSBUaGUgaW5kZXggb2YgdmVydGV4IHdpdGhpbiB0aGUgZmFjZS4gWzAuLi4gbnVtIGZhY2UgdmVydGljZXNdCiAgICAgICAgICogQHBhcmFtIHZhbHVlIC0gVGhlIHZhbHVlIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHNldEZhY2VWZXJ0ZXhWYWx1ZShmYWNlLCBmYWNlVmVydGV4LCB2YWx1ZSkgewogICAgICAgICAgICB0aGlzLnNldEZhY2VWZXJ0ZXhWYWx1ZV9hcnJheShmYWNlLCBmYWNlVmVydGV4LCBGbG9hdDMyQXJyYXkuZnJvbSh2YWx1ZS5hc0FycmF5KCkpKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIHNldFNwbGl0VmVydGV4VmFsdWUgbWV0aG9kLgogICAgICAgICAqIEBwYXJhbSB2ZXJ0ZXggLSBUaGUgdmVydGV4IHZhbHVlLgogICAgICAgICAqIEBwYXJhbSBmYWNlIC0gVGhlIGZhY2UgaW5kZXguCiAgICAgICAgICogQHBhcmFtIHZhbHVlIC0gVGhlIHZhbHVlIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHNldFNwbGl0VmVydGV4VmFsdWUodmVydGV4LCBmYWNlLCB2YWx1ZSkgewogICAgICAgICAgICB0aGlzLnNldFNwbGl0VmVydGV4VmFsdWVfYXJyYXkodmVydGV4LCBmYWNlLCBGbG9hdDMyQXJyYXkuZnJvbSh2YWx1ZS5hc0FycmF5KCkpKTsKICAgICAgICB9CiAgICAgICAgbWVyZ2Uob3RoZXIsIHhmbyA9IG5ldyBYZm8oKSkgewogICAgICAgICAgICBjb25zdCBwcmV2TnVtVmFsdWVzID0gdGhpcy5nZXRDb3VudCgpOwogICAgICAgICAgICBjb25zdCBhZGRlZFZhbHVlcyA9IG90aGVyLmdldENvdW50KCk7CiAgICAgICAgICAgIHRoaXMuc2V0Q291bnQocHJldk51bVZhbHVlcyArIGFkZGVkVmFsdWVzKTsKICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBhZGRlZFZhbHVlczsgaSsrKSB7CiAgICAgICAgICAgICAgICB0aGlzLnNldFZhbHVlKHByZXZOdW1WYWx1ZXMgKyBpLCBvdGhlci5nZXRWYWx1ZShpKSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdGhpcy5zcGxpdFZhbHVlcyA9IFsuLi50aGlzLnNwbGl0VmFsdWVzLCAuLi5vdGhlci5zcGxpdFZhbHVlc107CiAgICAgICAgfQogICAgfQogICAgUmVnaXN0cnkucmVnaXN0ZXIoJ1ZlYzJBdHRyaWJ1dGUnLCBWZWMyQXR0cmlidXRlKTsKCiAgICBjb25zdCBtYXBJbiQyID0gKHZhbHVlKSA9PiB7CiAgICAgICAgcmV0dXJuIE1hdGhGdW5jdGlvbnMuZW5jb2RlMTZCaXRGbG9hdCh2YWx1ZSk7CiAgICB9OwogICAgY29uc3QgbWFwT3V0JDIgPSAodmFsdWUpID0+IHsKICAgICAgICByZXR1cm4gTWF0aEZ1bmN0aW9ucy5kZWNvZGUxNkJpdEZsb2F0KHZhbHVlKTsKICAgIH07CiAgICAvKioKICAgICAqIENsYXNzIHJlcHJlc2VudGluZyBhbiBhdHRyaWJ1dGUuCiAgICAgKi8KICAgIGNsYXNzIFZlYzJmMTZBdHRyaWJ1dGUgZXh0ZW5kcyBWZWMyQXR0cmlidXRlIHsKICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGUgYSBWZWMzZjhBdHRyaWJ1dGUuCiAgICAgICAgICovCiAgICAgICAgY29uc3RydWN0b3IoKSB7CiAgICAgICAgICAgIHN1cGVyKCdWZWMyZjE2Jyk7CiAgICAgICAgfQogICAgICAgIGluaXQoKSB7CiAgICAgICAgICAgIHRoaXMuZGF0YSA9IG5ldyBVaW50MTZBcnJheSgwKTsKICAgICAgICAgICAgdGhpcy5pbml0UmFuZ2UoMCk7CiAgICAgICAgfQogICAgICAgIGluaXRSYW5nZShzdGFydCkgewogICAgICAgICAgICAvLyBJbml0aWFsaXplIHRoZSB2YWx1ZXMgdG8gaW52YWxpZCB2YWx1ZXMuCiAgICAgICAgICAgIGZvciAobGV0IGkgPSBzdGFydDsgaSA8IHRoaXMuZGF0YS5sZW5ndGg7IGkrKykgewogICAgICAgICAgICAgICAgdGhpcy5kYXRhW2ldID0gbWFwSW4kMihOdW1iZXIuTmFOKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBpc0luaXRpYWxpemVkKGEpIHsKICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBhLmxlbmd0aDsgaSsrKSB7CiAgICAgICAgICAgICAgICBpZiAoTnVtYmVyLmlzRmluaXRlKG1hcE91dCQyKGFbaV0pKSkKICAgICAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgYSBjb3B5IG9mIHRoZSBWZWMyIHZhbHVlIGF0IHRoZSBzcGVjaWZpZWQgaW5kZXguCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gaW5kZXggLSBUaGUgaW5kZXggdmFsdWUuCiAgICAgICAgICogQHJldHVybiBWZWMyIC0gVGhlIHZhbHVlIGF0IHRoZSBzcGVjaWZpZWQgaW5kZXguCiAgICAgICAgICovCiAgICAgICAgZ2V0VmFsdWUoaW5kZXgpIHsKICAgICAgICAgICAgaWYgKGluZGV4ID49IHRoaXMuZGF0YS5sZW5ndGggLyB0aGlzLnN0cmlkZSkKICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCB2ZXJ0ZXggaW5kZXg6JyArIGluZGV4ICsgJy4gTnVtIFZlcnRpY2VzOicgKyB0aGlzLmRhdGEubGVuZ3RoIC8gMyk7CiAgICAgICAgICAgIGNvbnN0IG9mZnNldCA9IGluZGV4ICogdGhpcy5zdHJpZGU7CiAgICAgICAgICAgIGNvbnN0IHZhbHVlRGF0YSA9IHRoaXMuZGF0YS5zdWJhcnJheShvZmZzZXQsIG9mZnNldCArIHRoaXMuc3RyaWRlKTsKICAgICAgICAgICAgcmV0dXJuIG5ldyBWZWMyKG1hcE91dCQyKHZhbHVlRGF0YVswXSksIG1hcE91dCQyKHZhbHVlRGF0YVsxXSkpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTZXRzIFZlYzIgYXQgdGhlIHNwZWNpZmllZCBpbmRleC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBpbmRleCAtIFRoZSBpbmRleCB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0gdmFsdWUgLSBUaGUgdmFsdWUgcGFyYW0uCiAgICAgICAgICovCiAgICAgICAgc2V0VmFsdWUoaW5kZXgsIHZhbHVlKSB7CiAgICAgICAgICAgIGlmIChpbmRleCA+PSB0aGlzLmRhdGEubGVuZ3RoIC8gdGhpcy5zdHJpZGUpCiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgdmVydGV4IGluZGV4OicgKyBpbmRleCArICcuIE51bSBWZXJ0aWNlczonICsgdGhpcy5kYXRhLmxlbmd0aCAvIDMpOwogICAgICAgICAgICBjb25zdCBvZmZzZXQgPSBpbmRleCAqIHRoaXMuc3RyaWRlOwogICAgICAgICAgICBjb25zdCB2YWx1ZURhdGEgPSB0aGlzLmRhdGEuc3ViYXJyYXkob2Zmc2V0LCBvZmZzZXQgKyB0aGlzLnN0cmlkZSk7CiAgICAgICAgICAgIHZhbHVlRGF0YVswXSA9IG1hcEluJDIodmFsdWUueCk7CiAgICAgICAgICAgIHZhbHVlRGF0YVsxXSA9IG1hcEluJDIodmFsdWUueSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEdldHMgdGhlIHZhbHVlIG9mIGEgY29ybmVyIHZlcnRleCBvZiBhIGZhY2UuCiAgICAgICAgICogPiBOb3RlOiAnUmVmJyBtZWFucyB0aGF0IHRoZSB2YWx1ZSBjb250YWlucyBhIHJlZmVyZW5jZSB0byB0aGUgZGF0YSBpbiB0aGUgYXR0cmlidXRlLgogICAgICAgICAqID4gVGhlIGNvbXBvbmVudHMgb2YgdGhlIHZhbHVlIGNhbiBiZSBjaGFuZ2VkIGNhdXNpbmcgdGhlIGF0dHJpYnV0ZXMgZGF0YSBpcyBjaGFuZ2VkLgogICAgICAgICAqID4gTm8gbmVlZCB0byBjYWxsICdzZXRGYWNlVmVydGV4VmFsdWUnLgogICAgICAgICAqIEBwYXJhbSBmYWNlIC0gVGhlIGZhY2UgaW5kZXguCiAgICAgICAgICogQHBhcmFtIGZhY2VWZXJ0ZXggLSBUaGUgaW5kZXggb2YgdmVydGV4IHdpdGhpbiB0aGUgZmFjZS4gWzAuLi4gbnVtIGZhY2UgdmVydGljZXNdCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgZ2V0RmFjZVZlcnRleFZhbHVlKGZhY2UsIGZhY2VWZXJ0ZXgpIHsKICAgICAgICAgICAgY29uc3QgYXJyYXkgPSB0aGlzLmdldEZhY2VWZXJ0ZXhWYWx1ZV9hcnJheShmYWNlLCBmYWNlVmVydGV4KTsKICAgICAgICAgICAgcmV0dXJuIG5ldyBWZWMyKG1hcE91dCQyKGFycmF5WzBdKSwgbWFwT3V0JDIoYXJyYXlbMV0pKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU2V0cyB0aGUgdmFsdWUgb2YgYSBjb3JuZXIgdmVydGV4IG9mIGEgZmFjZS4KICAgICAgICAgKiBAcGFyYW0gZmFjZSAtIFRoZSBmYWNlIGluZGV4LgogICAgICAgICAqIEBwYXJhbSBmYWNlVmVydGV4IC0gVGhlIGluZGV4IG9mIHZlcnRleCB3aXRoaW4gdGhlIGZhY2UuIFswLi4uIG51bSBmYWNlIHZlcnRpY2VzXQogICAgICAgICAqIEBwYXJhbSB2YWx1ZSAtIFRoZSB2YWx1ZSB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBzZXRGYWNlVmVydGV4VmFsdWUoZmFjZSwgZmFjZVZlcnRleCwgdmFsdWUpIHsKICAgICAgICAgICAgY29uc3QgdmFsdWVEYXRhID0gbmV3IFVpbnQxNkFycmF5KDIpOwogICAgICAgICAgICB2YWx1ZURhdGFbMF0gPSBtYXBJbiQyKHZhbHVlLngpOwogICAgICAgICAgICB2YWx1ZURhdGFbMV0gPSBtYXBJbiQyKHZhbHVlLnkpOwogICAgICAgICAgICB0aGlzLnNldEZhY2VWZXJ0ZXhWYWx1ZV9hcnJheShmYWNlLCBmYWNlVmVydGV4LCB2YWx1ZURhdGEpOwogICAgICAgIH0KICAgIH0KCiAgICBjbGFzcyBWZWMzUmVmIHsKICAgICAgICBkYXRhOwogICAgICAgIGNvbnN0cnVjdG9yKGRhdGEpIHsKICAgICAgICAgICAgdGhpcy5kYXRhID0gZGF0YTsKICAgICAgICB9CiAgICAgICAgZ2V0IHgoKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLmRhdGFbMF07CiAgICAgICAgfQogICAgICAgIHNldCB4KHZhbHVlKSB7CiAgICAgICAgICAgIHRoaXMuZGF0YVswXSA9IHZhbHVlOwogICAgICAgIH0KICAgICAgICBnZXQgeSgpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuZGF0YVsxXTsKICAgICAgICB9CiAgICAgICAgc2V0IHkodmFsdWUpIHsKICAgICAgICAgICAgdGhpcy5kYXRhWzFdID0gdmFsdWU7CiAgICAgICAgfQogICAgICAgIGdldCB6KCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy5kYXRhWzJdOwogICAgICAgIH0KICAgICAgICBzZXQgeih2YWx1ZSkgewogICAgICAgICAgICB0aGlzLmRhdGFbMl0gPSB2YWx1ZTsKICAgICAgICB9CiAgICAgICAgc2V0KHgsIHksIHopIHsKICAgICAgICAgICAgdGhpcy5kYXRhWzBdID0geDsKICAgICAgICAgICAgdGhpcy5kYXRhWzFdID0geTsKICAgICAgICAgICAgdGhpcy5kYXRhWzJdID0gejsKICAgICAgICB9CiAgICB9CiAgICAvKioKICAgICAqIENsYXNzIHJlcHJlc2VudGluZyBhbiBhdHRyaWJ1dGUuCiAgICAgKi8KICAgIGNsYXNzIFZlYzNBdHRyaWJ1dGUgZXh0ZW5kcyBBdHRyaWJ1dGUgewogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZSBhIFZlYzNBdHRyaWJ1dGUuCiAgICAgICAgICovCiAgICAgICAgY29uc3RydWN0b3IoZGF0YVR5cGVOYW1lID0gJ1ZlYzMnKSB7CiAgICAgICAgICAgIHN1cGVyKGRhdGFUeXBlTmFtZSwgMyk7CiAgICAgICAgICAgIHRoaXMubm9ybWFsaXplZCA9IGZhbHNlOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIGEgY29weSBvZiB0aGUgVmVjMyB2YWx1ZSBhdCB0aGUgc3BlY2lmaWVkIGluZGV4LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGluZGV4IC0gVGhlIGluZGV4IHZhbHVlLgogICAgICAgICAqIEByZXR1cm4gVmVjMyAtIFRoZSB2YWx1ZSBhdCB0aGUgc3BlY2lmaWVkIGluZGV4LgogICAgICAgICAqLwogICAgICAgIGdldFZhbHVlKGluZGV4KSB7CiAgICAgICAgICAgIGlmIChpbmRleCA+PSB0aGlzLmRhdGEubGVuZ3RoIC8gdGhpcy5zdHJpZGUpCiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgdmVydGV4IGluZGV4OicgKyBpbmRleCArICcuIE51bSBWZXJ0aWNlczonICsgdGhpcy5kYXRhLmxlbmd0aCAvIDMpOwogICAgICAgICAgICBjb25zdCBvZmZzZXQgPSBpbmRleCAqIHRoaXMuc3RyaWRlOwogICAgICAgICAgICByZXR1cm4gbmV3IFZlYzModGhpcy5kYXRhW29mZnNldCArIDBdLCB0aGlzLmRhdGFbb2Zmc2V0ICsgMV0sIHRoaXMuZGF0YVtvZmZzZXQgKyAyXSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgYSBjb3B5IG9mIHRoZSBWZWMzIHZhbHVlIGF0IHRoZSBzcGVjaWZpZWQgaW5kZXguCiAgICAgICAgICoKICAgICAgICAgKiBAZGVwcmVjYXRlZCAtIFRoaXMgbWV0aG9kIHdpbGwgc29vbiBiZSByZW1vdmVkLgogICAgICAgICAqIEByZXR1cm4gVmVjMyAtIFRoZSB2YWx1ZSBhdCB0aGUgc3BlY2lmaWVkIGluZGV4LgogICAgICAgICAqLwogICAgICAgIGdldFZhbHVlUmVmKGluZGV4KSB7CiAgICAgICAgICAgIGlmIChpbmRleCA+PSB0aGlzLmRhdGEubGVuZ3RoIC8gdGhpcy5zdHJpZGUpCiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgdmVydGV4IGluZGV4OicgKyBpbmRleCArICcuIE51bSBWZXJ0aWNlczonICsgdGhpcy5kYXRhLmxlbmd0aCAvIDMpOwogICAgICAgICAgICBjb25zdCBvZmZzZXQgPSBpbmRleCAqIHRoaXMuc3RyaWRlOwogICAgICAgICAgICByZXR1cm4gbmV3IFZlYzNSZWYodGhpcy5kYXRhLnN1YmFycmF5KG9mZnNldCwgb2Zmc2V0ICsgMykpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTZXRzIFZlYzMgYXQgdGhlIHNwZWNpZmllZCBpbmRleC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBpbmRleCAtIFRoZSBpbmRleCB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0gdmFsdWUgLSBUaGUgdmFsdWUgcGFyYW0uCiAgICAgICAgICovCiAgICAgICAgc2V0VmFsdWUoaW5kZXgsIHZhbHVlKSB7CiAgICAgICAgICAgIHRoaXMuc2V0VmFsdWVzKGluZGV4LCB2YWx1ZS5hc0FycmF5KCkpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBHZXRzIHRoZSB2YWx1ZSBvZiBhIGNvcm5lciB2ZXJ0ZXggb2YgYSBmYWNlLgogICAgICAgICAqID4gTm90ZTogJ1JlZicgbWVhbnMgdGhhdCB0aGUgdmFsdWUgY29udGFpbnMgYSByZWZlcmVuY2UgdG8gdGhlIGRhdGEgaW4gdGhlIGF0dHJpYnV0ZS4KICAgICAgICAgKiA+IFRoZSBjb21wb25lbnRzIG9mIHRoZSB2YWx1ZSBjYW4gYmUgY2hhbmdlZCBjYXVzaW5nIHRoZSBhdHRyaWJ1dGVzIGRhdGEgaXMgY2hhbmdlZC4KICAgICAgICAgKiA+IE5vIG5lZWQgdG8gY2FsbCAnc2V0RmFjZVZlcnRleFZhbHVlJy4KICAgICAgICAgKiBAcGFyYW0gZmFjZSAtIFRoZSBmYWNlIGluZGV4LgogICAgICAgICAqIEBwYXJhbSBmYWNlVmVydGV4IC0gVGhlIGluZGV4IG9mIHZlcnRleCB3aXRoaW4gdGhlIGZhY2UuIFswLi4uIG51bSBmYWNlIHZlcnRpY2VzXQogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGdldEZhY2VWZXJ0ZXhWYWx1ZShmYWNlLCBmYWNlVmVydGV4KSB7CiAgICAgICAgICAgIGNvbnN0IGFycmF5ID0gdGhpcy5nZXRGYWNlVmVydGV4VmFsdWVfYXJyYXkoZmFjZSwgZmFjZVZlcnRleCk7CiAgICAgICAgICAgIHJldHVybiBuZXcgVmVjMyhhcnJheVswXSwgYXJyYXlbMV0sIGFycmF5WzJdKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU2V0cyB0aGUgdmFsdWUgb2YgYSBjb3JuZXIgdmVydGV4IG9mIGEgZmFjZS4KICAgICAgICAgKiBAcGFyYW0gZmFjZSAtIFRoZSBmYWNlIGluZGV4LgogICAgICAgICAqIEBwYXJhbSBmYWNlVmVydGV4IC0gVGhlIGluZGV4IG9mIHZlcnRleCB3aXRoaW4gdGhlIGZhY2UuIFswLi4uIG51bSBmYWNlIHZlcnRpY2VzXQogICAgICAgICAqIEBwYXJhbSB2YWx1ZSAtIFRoZSB2YWx1ZSB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBzZXRGYWNlVmVydGV4VmFsdWUoZmFjZSwgZmFjZVZlcnRleCwgdmFsdWUpIHsKICAgICAgICAgICAgdGhpcy5zZXRGYWNlVmVydGV4VmFsdWVfYXJyYXkoZmFjZSwgZmFjZVZlcnRleCwgRmxvYXQzMkFycmF5LmZyb20odmFsdWUuYXNBcnJheSgpKSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBzZXRTcGxpdFZlcnRleFZhbHVlIG1ldGhvZC4KICAgICAgICAgKiBAcGFyYW0gdmVydGV4IC0gVGhlIHZlcnRleCB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0gZmFjZSAtIFRoZSBmYWNlIGluZGV4LgogICAgICAgICAqIEBwYXJhbSB2YWx1ZSAtIFRoZSB2YWx1ZSB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBzZXRTcGxpdFZlcnRleFZhbHVlKHZlcnRleCwgZmFjZSwgdmFsdWUpIHsKICAgICAgICAgICAgdGhpcy5zZXRTcGxpdFZlcnRleFZhbHVlX2FycmF5KHZlcnRleCwgZmFjZSwgRmxvYXQzMkFycmF5LmZyb20odmFsdWUuYXNBcnJheSgpKSk7CiAgICAgICAgfQogICAgICAgIG1lcmdlKG90aGVyLCB4Zm8gPSBuZXcgWGZvKCkpIHsKICAgICAgICAgICAgY29uc3QgcHJldk51bVZhbHVlcyA9IHRoaXMuZ2V0Q291bnQoKTsKICAgICAgICAgICAgY29uc3QgYWRkZWRWYWx1ZXMgPSBvdGhlci5nZXRDb3VudCgpOwogICAgICAgICAgICAvLyBXZSBjYWNoZWQgdGhlc2UgdmFsdWVzIGJlZm9yZSBjYWxsaW5nICdzZXRDb3VudCcuCiAgICAgICAgICAgIC8vIE1heWJlICdzZXRDb3VudCcgc2hvdWxuZCd0IGNsZWFyIHRoZSBzcGxpdHMuIEl0IHNlZW1zIGhlYXZ5LCBidXQgSSBkb24ndCB3YW50IHRvIGNoYW5nZSBhbnl0aGluZy4KICAgICAgICAgICAgLy8gV2Ugc2hvdWxkIGp1c3QgcmUtd3JpdGUgdGhlIHN5c3RlbSB3aXRob3V0IHNwbGl0cyBhbnl3YXkuCiAgICAgICAgICAgIC8vIGNvbnN0IHNwbGl0VmFsdWVzID0gWy4uLnRoaXMuc3BsaXRWYWx1ZXMsIC4uLm90aGVyLnNwbGl0VmFsdWVzXQogICAgICAgICAgICAvLyBjb25zdCBzcGxpdHMgPSBbLi4udGhpcy5zcGxpdHMsIC4uLm90aGVyLnNwbGl0c10KICAgICAgICAgICAgdGhpcy5zZXRDb3VudChwcmV2TnVtVmFsdWVzICsgYWRkZWRWYWx1ZXMpOwogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGFkZGVkVmFsdWVzOyBpKyspIHsKICAgICAgICAgICAgICAgIHRoaXMuc2V0VmFsdWUocHJldk51bVZhbHVlcyArIGksIHhmby50cmFuc2Zvcm1WZWMzKG90aGVyLmdldFZhbHVlKGkpKSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLy8gdGhpcy5zcGxpdFZhbHVlcyA9IFsuLi50aGlzLnNwbGl0VmFsdWVzLCAuLi5vdGhlci5zcGxpdFZhbHVlc10KICAgICAgICB9CiAgICB9CiAgICBSZWdpc3RyeS5yZWdpc3RlcignVmVjM0F0dHJpYnV0ZScsIFZlYzNBdHRyaWJ1dGUpOwoKICAgIGNsYXNzIFZlYzNmOFJlZiB7CiAgICAgICAgZGF0YTsKICAgICAgICBjb25zdHJ1Y3RvcihkYXRhKSB7CiAgICAgICAgICAgIHRoaXMuZGF0YSA9IGRhdGE7CiAgICAgICAgfQogICAgICAgIGdldCB4KCkgewogICAgICAgICAgICByZXR1cm4gTWF0aEZ1bmN0aW9ucy5kZWNvZGUxNkJpdEZsb2F0KHRoaXMuZGF0YVswXSk7CiAgICAgICAgfQogICAgICAgIHNldCB4KHZhbHVlKSB7CiAgICAgICAgICAgIHRoaXMuZGF0YVswXSA9IE1hdGhGdW5jdGlvbnMuZW5jb2RlMTZCaXRGbG9hdCh2YWx1ZSk7CiAgICAgICAgfQogICAgICAgIGdldCB5KCkgewogICAgICAgICAgICByZXR1cm4gTWF0aEZ1bmN0aW9ucy5kZWNvZGUxNkJpdEZsb2F0KHRoaXMuZGF0YVsxXSk7CiAgICAgICAgfQogICAgICAgIHNldCB5KHZhbHVlKSB7CiAgICAgICAgICAgIHRoaXMuZGF0YVsxXSA9IE1hdGhGdW5jdGlvbnMuZW5jb2RlMTZCaXRGbG9hdCh2YWx1ZSk7CiAgICAgICAgfQogICAgICAgIGdldCB6KCkgewogICAgICAgICAgICByZXR1cm4gTWF0aEZ1bmN0aW9ucy5kZWNvZGUxNkJpdEZsb2F0KHRoaXMuZGF0YVsyXSk7CiAgICAgICAgfQogICAgICAgIHNldCB6KHZhbHVlKSB7CiAgICAgICAgICAgIHRoaXMuZGF0YVsyXSA9IE1hdGhGdW5jdGlvbnMuZW5jb2RlMTZCaXRGbG9hdCh2YWx1ZSk7CiAgICAgICAgfQogICAgICAgIHNldCh4LCB5LCB6KSB7CiAgICAgICAgICAgIHRoaXMuZGF0YVswXSA9IE1hdGhGdW5jdGlvbnMuZW5jb2RlMTZCaXRGbG9hdCh4KTsKICAgICAgICAgICAgdGhpcy5kYXRhWzFdID0gTWF0aEZ1bmN0aW9ucy5lbmNvZGUxNkJpdEZsb2F0KHkpOwogICAgICAgICAgICB0aGlzLmRhdGFbMl0gPSBNYXRoRnVuY3Rpb25zLmVuY29kZTE2Qml0RmxvYXQoeik7CiAgICAgICAgfQogICAgfQogICAgY29uc3QgbWFwSW4kMSA9ICh2YWx1ZSwgdmFsdWVSYW5nZSkgPT4gewogICAgICAgIHJldHVybiBNYXRoRnVuY3Rpb25zLnJlbWFwKHZhbHVlLCB2YWx1ZVJhbmdlWzBdLCB2YWx1ZVJhbmdlWzFdLCAtMTI3LCAxMjcpOwogICAgfTsKICAgIGNvbnN0IG1hcE91dCQxID0gKHZhbHVlLCB2YWx1ZVJhbmdlKSA9PiB7CiAgICAgICAgcmV0dXJuIE1hdGhGdW5jdGlvbnMucmVtYXAodmFsdWUsIC0xMjcsIDEyNywgdmFsdWVSYW5nZVswXSwgdmFsdWVSYW5nZVsxXSk7CiAgICB9OwogICAgLyoqCiAgICAgKiBDbGFzcyByZXByZXNlbnRpbmcgYW4gYXR0cmlidXRlLgogICAgICovCiAgICBjbGFzcyBWZWMzZjhBdHRyaWJ1dGUgZXh0ZW5kcyBWZWMzQXR0cmlidXRlIHsKICAgICAgICB2YWx1ZVJhbmdlOwogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZSBhIFZlYzNmOEF0dHJpYnV0ZS4KICAgICAgICAgKi8KICAgICAgICBjb25zdHJ1Y3Rvcih2YWx1ZVJhbmdlID0gWy0xLCAxXSkgewogICAgICAgICAgICBzdXBlcignVmVjM2Y4Jyk7CiAgICAgICAgICAgIHRoaXMudmFsdWVSYW5nZSA9IHZhbHVlUmFuZ2U7CiAgICAgICAgfQogICAgICAgIGluaXQoKSB7CiAgICAgICAgICAgIHRoaXMuZGF0YSA9IG5ldyBJbnQ4QXJyYXkoMCk7CiAgICAgICAgICAgIHRoaXMuaW5pdFJhbmdlKDApOwogICAgICAgIH0KICAgICAgICBpbml0UmFuZ2Uoc3RhcnQpIHsKICAgICAgICAgICAgLy8gSW5pdGlhbGl6ZSB0aGUgdmFsdWVzIHRvIGludmFsaWQgdmFsdWVzLgogICAgICAgICAgICBmb3IgKGxldCBpID0gc3RhcnQ7IGkgPCB0aGlzLmRhdGEubGVuZ3RoOyBpKyspIHsKICAgICAgICAgICAgICAgIHRoaXMuZGF0YVtpXSA9IG1hcEluJDEoTnVtYmVyLk5hTiwgdGhpcy52YWx1ZVJhbmdlKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBpc0luaXRpYWxpemVkKGEpIHsKICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBhLmxlbmd0aDsgaSsrKSB7CiAgICAgICAgICAgICAgICBpZiAoTnVtYmVyLmlzRmluaXRlKG1hcE91dCQxKGFbaV0sIHRoaXMudmFsdWVSYW5nZSkpKQogICAgICAgICAgICAgICAgICAgIHJldHVybiB0cnVlOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBmYWxzZTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyBhIGNvcHkgb2YgdGhlIFZlYzMgdmFsdWUgYXQgdGhlIHNwZWNpZmllZCBpbmRleC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBpbmRleCAtIFRoZSBpbmRleCB2YWx1ZS4KICAgICAgICAgKiBAcmV0dXJuIFZlYzMgLSBUaGUgdmFsdWUgYXQgdGhlIHNwZWNpZmllZCBpbmRleC4KICAgICAgICAgKi8KICAgICAgICBnZXRWYWx1ZShpbmRleCkgewogICAgICAgICAgICBpZiAoaW5kZXggPj0gdGhpcy5kYXRhLmxlbmd0aCAvIHRoaXMuc3RyaWRlKQogICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIHZlcnRleCBpbmRleDonICsgaW5kZXggKyAnLiBOdW0gVmVydGljZXM6JyArIHRoaXMuZGF0YS5sZW5ndGggLyAzKTsKICAgICAgICAgICAgY29uc3Qgb2Zmc2V0ID0gaW5kZXggKiB0aGlzLnN0cmlkZTsKICAgICAgICAgICAgY29uc3QgdmFsdWVEYXRhID0gdGhpcy5kYXRhLnN1YmFycmF5KG9mZnNldCwgb2Zmc2V0ICsgdGhpcy5zdHJpZGUpOwogICAgICAgICAgICByZXR1cm4gbmV3IFZlYzMobWFwT3V0JDEodmFsdWVEYXRhWzBdLCB0aGlzLnZhbHVlUmFuZ2UpLCBtYXBPdXQkMSh2YWx1ZURhdGFbMV0sIHRoaXMudmFsdWVSYW5nZSksIG1hcE91dCQxKHZhbHVlRGF0YVsyXSwgdGhpcy52YWx1ZVJhbmdlKSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgYSBjb3B5IG9mIHRoZSBWZWMzIHZhbHVlIGF0IHRoZSBzcGVjaWZpZWQgaW5kZXguCiAgICAgICAgICoKICAgICAgICAgKiBAZGVwcmVjYXRlZCAtIFRoaXMgbWV0aG9kIHdpbGwgc29vbiBiZSByZW1vdmVkLgogICAgICAgICAqIEByZXR1cm4gVmVjMyAtIFRoZSB2YWx1ZSBhdCB0aGUgc3BlY2lmaWVkIGluZGV4LgogICAgICAgICAqLwogICAgICAgIGdldFZhbHVlUmVmKGluZGV4KSB7CiAgICAgICAgICAgIGlmIChpbmRleCA+PSB0aGlzLmRhdGEubGVuZ3RoIC8gdGhpcy5zdHJpZGUpCiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgdmVydGV4IGluZGV4OicgKyBpbmRleCArICcuIE51bSBWZXJ0aWNlczonICsgdGhpcy5kYXRhLmxlbmd0aCAvIDMpOwogICAgICAgICAgICBjb25zdCBvZmZzZXQgPSBpbmRleCAqIHRoaXMuc3RyaWRlOwogICAgICAgICAgICByZXR1cm4gbmV3IFZlYzNmOFJlZih0aGlzLmRhdGEuc3ViYXJyYXkob2Zmc2V0LCBvZmZzZXQgKyAzKSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFNldHMgVmVjMyBhdCB0aGUgc3BlY2lmaWVkIGluZGV4LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGluZGV4IC0gVGhlIGluZGV4IHZhbHVlLgogICAgICAgICAqIEBwYXJhbSB2YWx1ZSAtIFRoZSB2YWx1ZSBwYXJhbS4KICAgICAgICAgKi8KICAgICAgICBzZXRWYWx1ZShpbmRleCwgdmFsdWUpIHsKICAgICAgICAgICAgaWYgKGluZGV4ID49IHRoaXMuZGF0YS5sZW5ndGggLyB0aGlzLnN0cmlkZSkKICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCB2ZXJ0ZXggaW5kZXg6JyArIGluZGV4ICsgJy4gTnVtIFZlcnRpY2VzOicgKyB0aGlzLmRhdGEubGVuZ3RoIC8gMyk7CiAgICAgICAgICAgIGNvbnN0IG9mZnNldCA9IGluZGV4ICogdGhpcy5zdHJpZGU7CiAgICAgICAgICAgIGNvbnN0IHZhbHVlRGF0YSA9IHRoaXMuZGF0YS5zdWJhcnJheShvZmZzZXQsIG9mZnNldCArIHRoaXMuc3RyaWRlKTsKICAgICAgICAgICAgdmFsdWVEYXRhWzBdID0gbWFwSW4kMSh2YWx1ZS54LCB0aGlzLnZhbHVlUmFuZ2UpOwogICAgICAgICAgICB2YWx1ZURhdGFbMV0gPSBtYXBJbiQxKHZhbHVlLnksIHRoaXMudmFsdWVSYW5nZSk7CiAgICAgICAgICAgIHZhbHVlRGF0YVsyXSA9IG1hcEluJDEodmFsdWUueiwgdGhpcy52YWx1ZVJhbmdlKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogR2V0cyB0aGUgdmFsdWUgb2YgYSBjb3JuZXIgdmVydGV4IG9mIGEgZmFjZS4KICAgICAgICAgKiA+IE5vdGU6ICdSZWYnIG1lYW5zIHRoYXQgdGhlIHZhbHVlIGNvbnRhaW5zIGEgcmVmZXJlbmNlIHRvIHRoZSBkYXRhIGluIHRoZSBhdHRyaWJ1dGUuCiAgICAgICAgICogPiBUaGUgY29tcG9uZW50cyBvZiB0aGUgdmFsdWUgY2FuIGJlIGNoYW5nZWQgY2F1c2luZyB0aGUgYXR0cmlidXRlcyBkYXRhIGlzIGNoYW5nZWQuCiAgICAgICAgICogPiBObyBuZWVkIHRvIGNhbGwgJ3NldEZhY2VWZXJ0ZXhWYWx1ZScuCiAgICAgICAgICogQHBhcmFtIGZhY2UgLSBUaGUgZmFjZSBpbmRleC4KICAgICAgICAgKiBAcGFyYW0gZmFjZVZlcnRleCAtIFRoZSBpbmRleCBvZiB2ZXJ0ZXggd2l0aGluIHRoZSBmYWNlLiBbMC4uLiBudW0gZmFjZSB2ZXJ0aWNlc10KICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBnZXRGYWNlVmVydGV4VmFsdWUoZmFjZSwgZmFjZVZlcnRleCkgewogICAgICAgICAgICBjb25zdCBhcnJheSA9IHRoaXMuZ2V0RmFjZVZlcnRleFZhbHVlX2FycmF5KGZhY2UsIGZhY2VWZXJ0ZXgpOwogICAgICAgICAgICByZXR1cm4gbmV3IFZlYzMobWFwT3V0JDEoYXJyYXlbMF0sIHRoaXMudmFsdWVSYW5nZSksIG1hcE91dCQxKGFycmF5WzFdLCB0aGlzLnZhbHVlUmFuZ2UpLCBtYXBPdXQkMShhcnJheVsyXSwgdGhpcy52YWx1ZVJhbmdlKSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFNldHMgdGhlIHZhbHVlIG9mIGEgY29ybmVyIHZlcnRleCBvZiBhIGZhY2UuCiAgICAgICAgICogQHBhcmFtIGZhY2UgLSBUaGUgZmFjZSBpbmRleC4KICAgICAgICAgKiBAcGFyYW0gZmFjZVZlcnRleCAtIFRoZSBpbmRleCBvZiB2ZXJ0ZXggd2l0aGluIHRoZSBmYWNlLiBbMC4uLiBudW0gZmFjZSB2ZXJ0aWNlc10KICAgICAgICAgKiBAcGFyYW0gdmFsdWUgLSBUaGUgdmFsdWUgdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgc2V0RmFjZVZlcnRleFZhbHVlKGZhY2UsIGZhY2VWZXJ0ZXgsIHZhbHVlKSB7CiAgICAgICAgICAgIGNvbnN0IHZhbHVlRGF0YSA9IG5ldyBJbnQ4QXJyYXkoMyk7CiAgICAgICAgICAgIHZhbHVlRGF0YVswXSA9IG1hcEluJDEodmFsdWUueCwgdGhpcy52YWx1ZVJhbmdlKTsKICAgICAgICAgICAgdmFsdWVEYXRhWzFdID0gbWFwSW4kMSh2YWx1ZS55LCB0aGlzLnZhbHVlUmFuZ2UpOwogICAgICAgICAgICB2YWx1ZURhdGFbMl0gPSBtYXBJbiQxKHZhbHVlLnosIHRoaXMudmFsdWVSYW5nZSk7CiAgICAgICAgICAgIHRoaXMuc2V0RmFjZVZlcnRleFZhbHVlX2FycmF5KGZhY2UsIGZhY2VWZXJ0ZXgsIHZhbHVlRGF0YSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBzZXRTcGxpdFZlcnRleFZhbHVlcyBtZXRob2QuCiAgICAgICAgICogQHBhcmFtIHZlcnRleCAtIFRoZSB2ZXJ0ZXggdmFsdWUuCiAgICAgICAgICogQHBhcmFtIGZhY2VHcm91cCAtIFRoZSBmYWNlR3JvdXAgdmFsdWUuCiAgICAgICAgICogQHBhcmFtIHZhbHVlIC0gVGhlIHZhbHVlIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHNldFNwbGl0VmVydGV4VmFsdWVzKHZlcnRleCwgZmFjZUdyb3VwLCB2YWx1ZXMpIHsKICAgICAgICAgICAgc3VwZXIuc2V0U3BsaXRWZXJ0ZXhWYWx1ZXModmVydGV4LCBmYWNlR3JvdXAsIHZhbHVlcy5tYXAoKHYpID0+IG1hcEluJDEodiwgdGhpcy52YWx1ZVJhbmdlKSwgdGhpcy52YWx1ZVJhbmdlKSk7CiAgICAgICAgfQogICAgfQoKICAgIGNvbnN0IG1hcEluID0gKHZhbHVlKSA9PiB7CiAgICAgICAgcmV0dXJuIE1hdGhGdW5jdGlvbnMuZW5jb2RlMTZCaXRGbG9hdCh2YWx1ZSk7CiAgICB9OwogICAgY29uc3QgbWFwT3V0ID0gKHZhbHVlKSA9PiB7CiAgICAgICAgcmV0dXJuIE1hdGhGdW5jdGlvbnMuZGVjb2RlMTZCaXRGbG9hdCh2YWx1ZSk7CiAgICB9OwogICAgY2xhc3MgVmVjM2YxNlJlZiB7CiAgICAgICAgZGF0YTsKICAgICAgICBjb25zdHJ1Y3RvcihkYXRhKSB7CiAgICAgICAgICAgIHRoaXMuZGF0YSA9IGRhdGE7CiAgICAgICAgfQogICAgICAgIGdldCB4KCkgewogICAgICAgICAgICByZXR1cm4gbWFwT3V0KHRoaXMuZGF0YVswXSk7CiAgICAgICAgfQogICAgICAgIHNldCB4KHZhbHVlKSB7CiAgICAgICAgICAgIHRoaXMuZGF0YVswXSA9IG1hcEluKHZhbHVlKTsKICAgICAgICB9CiAgICAgICAgZ2V0IHkoKSB7CiAgICAgICAgICAgIHJldHVybiBtYXBPdXQodGhpcy5kYXRhWzFdKTsKICAgICAgICB9CiAgICAgICAgc2V0IHkodmFsdWUpIHsKICAgICAgICAgICAgdGhpcy5kYXRhWzFdID0gbWFwSW4odmFsdWUpOwogICAgICAgIH0KICAgICAgICBnZXQgeigpIHsKICAgICAgICAgICAgcmV0dXJuIG1hcE91dCh0aGlzLmRhdGFbMl0pOwogICAgICAgIH0KICAgICAgICBzZXQgeih2YWx1ZSkgewogICAgICAgICAgICB0aGlzLmRhdGFbMl0gPSBtYXBJbih2YWx1ZSk7CiAgICAgICAgfQogICAgICAgIHNldCh4LCB5LCB6KSB7CiAgICAgICAgICAgIHRoaXMuZGF0YVswXSA9IG1hcEluKHgpOwogICAgICAgICAgICB0aGlzLmRhdGFbMV0gPSBtYXBJbih5KTsKICAgICAgICAgICAgdGhpcy5kYXRhWzJdID0gbWFwSW4oeik7CiAgICAgICAgfQogICAgfQogICAgLyoqCiAgICAgKiBDbGFzcyByZXByZXNlbnRpbmcgYW4gYXR0cmlidXRlLgogICAgICovCiAgICBjbGFzcyBWZWMzZjE2QXR0cmlidXRlIGV4dGVuZHMgVmVjM0F0dHJpYnV0ZSB7CiAgICAgICAgLyoqCiAgICAgICAgICogQ3JlYXRlIGEgVmVjM2Y4QXR0cmlidXRlLgogICAgICAgICAqLwogICAgICAgIGNvbnN0cnVjdG9yKCkgewogICAgICAgICAgICBzdXBlcignVmVjM2YxNicpOwogICAgICAgIH0KICAgICAgICBpbml0KCkgewogICAgICAgICAgICB0aGlzLmRhdGEgPSBuZXcgVWludDE2QXJyYXkoMCk7CiAgICAgICAgICAgIHRoaXMuaW5pdFJhbmdlKDApOwogICAgICAgIH0KICAgICAgICBpbml0UmFuZ2Uoc3RhcnQpIHsKICAgICAgICAgICAgLy8gSW5pdGlhbGl6ZSB0aGUgdmFsdWVzIHRvIGludmFsaWQgdmFsdWVzLgogICAgICAgICAgICBmb3IgKGxldCBpID0gc3RhcnQ7IGkgPCB0aGlzLmRhdGEubGVuZ3RoOyBpKyspIHsKICAgICAgICAgICAgICAgIHRoaXMuZGF0YVtpXSA9IG1hcEluKE51bWJlci5OYU4pOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGlzSW5pdGlhbGl6ZWQoYSkgewogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGEubGVuZ3RoOyBpKyspIHsKICAgICAgICAgICAgICAgIGlmIChOdW1iZXIuaXNGaW5pdGUobWFwT3V0KGFbaV0pKSkKICAgICAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgYSBjb3B5IG9mIHRoZSBWZWMzIHZhbHVlIGF0IHRoZSBzcGVjaWZpZWQgaW5kZXguCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gaW5kZXggLSBUaGUgaW5kZXggdmFsdWUuCiAgICAgICAgICogQHJldHVybiBWZWMzIC0gVGhlIHZhbHVlIGF0IHRoZSBzcGVjaWZpZWQgaW5kZXguCiAgICAgICAgICovCiAgICAgICAgZ2V0VmFsdWUoaW5kZXgpIHsKICAgICAgICAgICAgaWYgKGluZGV4ID49IHRoaXMuZGF0YS5sZW5ndGggLyB0aGlzLnN0cmlkZSkKICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCB2ZXJ0ZXggaW5kZXg6JyArIGluZGV4ICsgJy4gTnVtIFZlcnRpY2VzOicgKyB0aGlzLmRhdGEubGVuZ3RoIC8gMyk7CiAgICAgICAgICAgIGNvbnN0IG9mZnNldCA9IGluZGV4ICogdGhpcy5zdHJpZGU7CiAgICAgICAgICAgIGNvbnN0IHZhbHVlRGF0YSA9IHRoaXMuZGF0YS5zdWJhcnJheShvZmZzZXQsIG9mZnNldCArIHRoaXMuc3RyaWRlKTsKICAgICAgICAgICAgcmV0dXJuIG5ldyBWZWMzKG1hcE91dCh2YWx1ZURhdGFbMF0pLCBtYXBPdXQodmFsdWVEYXRhWzFdKSwgbWFwT3V0KHZhbHVlRGF0YVsyXSkpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIGEgY29weSBvZiB0aGUgVmVjMyB2YWx1ZSBhdCB0aGUgc3BlY2lmaWVkIGluZGV4LgogICAgICAgICAqCiAgICAgICAgICogQGRlcHJlY2F0ZWQgLSBUaGlzIG1ldGhvZCB3aWxsIHNvb24gYmUgcmVtb3ZlZC4KICAgICAgICAgKiBAcmV0dXJuIFZlYzMgLSBUaGUgdmFsdWUgYXQgdGhlIHNwZWNpZmllZCBpbmRleC4KICAgICAgICAgKi8KICAgICAgICBnZXRWYWx1ZVJlZihpbmRleCkgewogICAgICAgICAgICBpZiAoaW5kZXggPj0gdGhpcy5kYXRhLmxlbmd0aCAvIHRoaXMuc3RyaWRlKQogICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIHZlcnRleCBpbmRleDonICsgaW5kZXggKyAnLiBOdW0gVmVydGljZXM6JyArIHRoaXMuZGF0YS5sZW5ndGggLyAzKTsKICAgICAgICAgICAgY29uc3Qgb2Zmc2V0ID0gaW5kZXggKiB0aGlzLnN0cmlkZTsKICAgICAgICAgICAgcmV0dXJuIG5ldyBWZWMzZjE2UmVmKHRoaXMuZGF0YS5zdWJhcnJheShvZmZzZXQsIG9mZnNldCArIDMpKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU2V0cyBWZWMzIGF0IHRoZSBzcGVjaWZpZWQgaW5kZXguCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gaW5kZXggLSBUaGUgaW5kZXggdmFsdWUuCiAgICAgICAgICogQHBhcmFtIHZhbHVlIC0gVGhlIHZhbHVlIHBhcmFtLgogICAgICAgICAqLwogICAgICAgIHNldFZhbHVlKGluZGV4LCB2YWx1ZSkgewogICAgICAgICAgICBpZiAoaW5kZXggPj0gdGhpcy5kYXRhLmxlbmd0aCAvIHRoaXMuc3RyaWRlKQogICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIHZlcnRleCBpbmRleDonICsgaW5kZXggKyAnLiBOdW0gVmVydGljZXM6JyArIHRoaXMuZGF0YS5sZW5ndGggLyAzKTsKICAgICAgICAgICAgY29uc3Qgb2Zmc2V0ID0gaW5kZXggKiB0aGlzLnN0cmlkZTsKICAgICAgICAgICAgY29uc3QgdmFsdWVEYXRhID0gdGhpcy5kYXRhLnN1YmFycmF5KG9mZnNldCwgb2Zmc2V0ICsgdGhpcy5zdHJpZGUpOwogICAgICAgICAgICB2YWx1ZURhdGFbMF0gPSBtYXBJbih2YWx1ZS54KTsKICAgICAgICAgICAgdmFsdWVEYXRhWzFdID0gbWFwSW4odmFsdWUueSk7CiAgICAgICAgICAgIHZhbHVlRGF0YVsyXSA9IG1hcEluKHZhbHVlLnopOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBHZXRzIHRoZSB2YWx1ZSBvZiBhIGNvcm5lciB2ZXJ0ZXggb2YgYSBmYWNlLgogICAgICAgICAqID4gTm90ZTogJ1JlZicgbWVhbnMgdGhhdCB0aGUgdmFsdWUgY29udGFpbnMgYSByZWZlcmVuY2UgdG8gdGhlIGRhdGEgaW4gdGhlIGF0dHJpYnV0ZS4KICAgICAgICAgKiA+IFRoZSBjb21wb25lbnRzIG9mIHRoZSB2YWx1ZSBjYW4gYmUgY2hhbmdlZCBjYXVzaW5nIHRoZSBhdHRyaWJ1dGVzIGRhdGEgaXMgY2hhbmdlZC4KICAgICAgICAgKiA+IE5vIG5lZWQgdG8gY2FsbCAnc2V0RmFjZVZlcnRleFZhbHVlJy4KICAgICAgICAgKiBAcGFyYW0gZmFjZSAtIFRoZSBmYWNlIGluZGV4LgogICAgICAgICAqIEBwYXJhbSBmYWNlVmVydGV4IC0gVGhlIGluZGV4IG9mIHZlcnRleCB3aXRoaW4gdGhlIGZhY2UuIFswLi4uIG51bSBmYWNlIHZlcnRpY2VzXQogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGdldEZhY2VWZXJ0ZXhWYWx1ZShmYWNlLCBmYWNlVmVydGV4KSB7CiAgICAgICAgICAgIGNvbnN0IGFycmF5ID0gdGhpcy5nZXRGYWNlVmVydGV4VmFsdWVfYXJyYXkoZmFjZSwgZmFjZVZlcnRleCk7CiAgICAgICAgICAgIHJldHVybiBuZXcgVmVjMyhtYXBPdXQoYXJyYXlbMF0pLCBtYXBPdXQoYXJyYXlbMV0pLCBtYXBPdXQoYXJyYXlbMl0pKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU2V0cyB0aGUgdmFsdWUgb2YgYSBjb3JuZXIgdmVydGV4IG9mIGEgZmFjZS4KICAgICAgICAgKiBAcGFyYW0gZmFjZSAtIFRoZSBmYWNlIGluZGV4LgogICAgICAgICAqIEBwYXJhbSBmYWNlVmVydGV4IC0gVGhlIGluZGV4IG9mIHZlcnRleCB3aXRoaW4gdGhlIGZhY2UuIFswLi4uIG51bSBmYWNlIHZlcnRpY2VzXQogICAgICAgICAqIEBwYXJhbSB2YWx1ZSAtIFRoZSB2YWx1ZSB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBzZXRGYWNlVmVydGV4VmFsdWUoZmFjZSwgZmFjZVZlcnRleCwgdmFsdWUpIHsKICAgICAgICAgICAgY29uc3QgdmFsdWVEYXRhID0gbmV3IFVpbnQxNkFycmF5KDMpOwogICAgICAgICAgICB2YWx1ZURhdGFbMF0gPSBtYXBJbih2YWx1ZS54KTsKICAgICAgICAgICAgdmFsdWVEYXRhWzFdID0gbWFwSW4odmFsdWUueSk7CiAgICAgICAgICAgIHZhbHVlRGF0YVsyXSA9IG1hcEluKHZhbHVlLnopOwogICAgICAgICAgICB0aGlzLnNldEZhY2VWZXJ0ZXhWYWx1ZV9hcnJheShmYWNlLCBmYWNlVmVydGV4LCB2YWx1ZURhdGEpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgc2V0U3BsaXRWZXJ0ZXhWYWx1ZXMgbWV0aG9kLgogICAgICAgICAqIEBwYXJhbSB2ZXJ0ZXggLSBUaGUgdmVydGV4IHZhbHVlLgogICAgICAgICAqIEBwYXJhbSBmYWNlR3JvdXAgLSBUaGUgZmFjZUdyb3VwIHZhbHVlLgogICAgICAgICAqIEBwYXJhbSB2YWx1ZSAtIFRoZSB2YWx1ZSB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBzZXRTcGxpdFZlcnRleFZhbHVlcyh2ZXJ0ZXgsIGZhY2VHcm91cCwgdmFsdWVzKSB7CiAgICAgICAgICAgIHN1cGVyLnNldFNwbGl0VmVydGV4VmFsdWVzKHZlcnRleCwgZmFjZUdyb3VwLCB2YWx1ZXMubWFwKCh2KSA9PiBtYXBJbih2KSkpOwogICAgICAgIH0KICAgIH0KCiAgICAvKioKICAgICAqIENsYXNzIHJlcHJlc2VudGluZyBhbiBhdHRyaWJ1dGUuCiAgICAgKi8KICAgIGNsYXNzIENvbG9yQXR0cmlidXRlIGV4dGVuZHMgQXR0cmlidXRlIHsKICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGUgYSBDb2xvckF0dHJpYnV0ZS4KICAgICAgICAgKi8KICAgICAgICBjb25zdHJ1Y3RvcigpIHsKICAgICAgICAgICAgc3VwZXIoJ0NvbG9yJywgNCk7CiAgICAgICAgICAgIHRoaXMubm9ybWFsaXplZCA9IGZhbHNlOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIGEgY29weSBvZiB0aGUgQ29sb3IgdmFsdWUgYXQgdGhlIHNwZWNpZmllZCBpbmRleC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBpbmRleCAtIFRoZSBpbmRleCB2YWx1ZS4KICAgICAgICAgKiBAcmV0dXJuIENvbG9yIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBnZXRWYWx1ZShpbmRleCkgewogICAgICAgICAgICBpZiAoaW5kZXggPj0gdGhpcy5kYXRhLmxlbmd0aCAvIHRoaXMuc3RyaWRlKQogICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIHZlcnRleCBpbmRleDonICsgaW5kZXggKyAnLiBOdW0gVmVydGljZXM6JyArIHRoaXMuZGF0YS5sZW5ndGggLyAzKTsKICAgICAgICAgICAgY29uc3Qgb2Zmc2V0ID0gaW5kZXggKiB0aGlzLnN0cmlkZTsKICAgICAgICAgICAgcmV0dXJuIG5ldyBDb2xvcih0aGlzLmRhdGFbb2Zmc2V0ICsgMF0sIHRoaXMuZGF0YVtvZmZzZXQgKyAxXSwgdGhpcy5kYXRhW29mZnNldCArIDJdLCB0aGlzLmRhdGFbb2Zmc2V0ICsgM10pOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTZXRzIENvbG9yIGF0IHRoZSBzcGVjaWZpZWQgaW5kZXguCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gaW5kZXggLSBUaGUgaW5kZXggdmFsdWUuCiAgICAgICAgICogQHBhcmFtIHZhbHVlIC0gVGhlIHZhbHVlIHBhcmFtLgogICAgICAgICAqLwogICAgICAgIHNldFZhbHVlKGluZGV4LCB2YWx1ZSkgewogICAgICAgICAgICB0aGlzLnNldFZhbHVlcyhpbmRleCwgdmFsdWUuYXNBcnJheSgpKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogR2V0cyB0aGUgdmFsdWUgb2YgYSBjb3JuZXIgdmVydGV4IG9mIGEgZmFjZS4KICAgICAgICAgKiA+IE5vdGU6ICdSZWYnIG1lYW5zIHRoYXQgdGhlIHZhbHVlIGNvbnRhaW5zIGEgcmVmZXJlbmNlIHRvIHRoZSBkYXRhIGluIHRoZSBhdHRyaWJ1dGUuCiAgICAgICAgICogPiBUaGUgY29tcG9uZW50cyBvZiB0aGUgdmFsdWUgY2FuIGJlIGNoYW5nZWQgY2F1c2luZyB0aGUgYXR0cmlidXRlcyBkYXRhIGlzIGNoYW5nZWQuCiAgICAgICAgICogPiBObyBuZWVkIHRvIGNhbGwgJ3NldEZhY2VWZXJ0ZXhWYWx1ZScuCiAgICAgICAgICogQHBhcmFtIGZhY2UgLSBUaGUgZmFjZSBpbmRleC4KICAgICAgICAgKiBAcGFyYW0gZmFjZVZlcnRleCAtIFRoZSBpbmRleCBvZiB2ZXJ0ZXggd2l0aGluIHRoZSBmYWNlLiBbMC4uLiBudW0gZmFjZSB2ZXJ0aWNlc10KICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBnZXRGYWNlVmVydGV4VmFsdWUoZmFjZSwgZmFjZVZlcnRleCkgewogICAgICAgICAgICBjb25zdCBhcnJheSA9IHRoaXMuZ2V0RmFjZVZlcnRleFZhbHVlX2FycmF5KGZhY2UsIGZhY2VWZXJ0ZXgpOwogICAgICAgICAgICByZXR1cm4gbmV3IENvbG9yKGFycmF5WzBdLCBhcnJheVsxXSwgYXJyYXlbMl0sIGFycmF5WzNdKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU2V0cyB0aGUgdmFsdWUgb2YgYSBjb3JuZXIgdmVydGV4IG9mIGEgZmFjZS4KICAgICAgICAgKiBAcGFyYW0gZmFjZSAtIFRoZSBmYWNlIGluZGV4LgogICAgICAgICAqIEBwYXJhbSBmYWNlVmVydGV4IC0gVGhlIGluZGV4IG9mIHZlcnRleCB3aXRoaW4gdGhlIGZhY2UuIFswLi4uIG51bSBmYWNlIHZlcnRpY2VzXQogICAgICAgICAqIEBwYXJhbSB2YWx1ZSAtIFRoZSB2YWx1ZSB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBzZXRGYWNlVmVydGV4VmFsdWUoZmFjZSwgZmFjZVZlcnRleCwgdmFsdWUpIHsKICAgICAgICAgICAgdGhpcy5zZXRGYWNlVmVydGV4VmFsdWVfYXJyYXkoZmFjZSwgZmFjZVZlcnRleCwgRmxvYXQzMkFycmF5LmZyb20odmFsdWUuYXNBcnJheSgpKSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBzZXRTcGxpdFZlcnRleFZhbHVlIG1ldGhvZC4KICAgICAgICAgKiBAcGFyYW0gdmVydGV4IC0gVGhlIHZlcnRleCB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0gZmFjZSAtIFRoZSBmYWNlIGluZGV4LgogICAgICAgICAqIEBwYXJhbSB2YWx1ZSAtIFRoZSB2YWx1ZSB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBzZXRTcGxpdFZlcnRleFZhbHVlKHZlcnRleCwgZmFjZSwgdmFsdWUpIHsKICAgICAgICAgICAgdGhpcy5zZXRTcGxpdFZlcnRleFZhbHVlX2FycmF5KHZlcnRleCwgZmFjZSwgRmxvYXQzMkFycmF5LmZyb20odmFsdWUuYXNBcnJheSgpKSk7CiAgICAgICAgfQogICAgICAgIG1lcmdlKG90aGVyLCB4Zm8gPSBuZXcgWGZvKCkpIHsKICAgICAgICAgICAgY29uc3QgcHJldk51bVZhbHVlcyA9IHRoaXMuZ2V0Q291bnQoKTsKICAgICAgICAgICAgY29uc3QgYWRkZWRWYWx1ZXMgPSBvdGhlci5nZXRDb3VudCgpOwogICAgICAgICAgICB0aGlzLnNldENvdW50KHByZXZOdW1WYWx1ZXMgKyBhZGRlZFZhbHVlcyk7CiAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgYWRkZWRWYWx1ZXM7IGkrKykgewogICAgICAgICAgICAgICAgdGhpcy5zZXRWYWx1ZShwcmV2TnVtVmFsdWVzICsgaSwgb3RoZXIuZ2V0VmFsdWUoaSkpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHRoaXMuc3BsaXRWYWx1ZXMgPSBbLi4udGhpcy5zcGxpdFZhbHVlcywgLi4ub3RoZXIuc3BsaXRWYWx1ZXNdOwogICAgICAgIH0KICAgIH0KICAgIFJlZ2lzdHJ5LnJlZ2lzdGVyKCdDb2xvckF0dHJpYnV0ZScsIENvbG9yQXR0cmlidXRlKTsKCiAgICB2YXIgT3BlcmF0b3JPdXRwdXRNb2RlOwogICAgKGZ1bmN0aW9uIChPcGVyYXRvck91dHB1dE1vZGUpIHsKICAgICAgICBPcGVyYXRvck91dHB1dE1vZGVbT3BlcmF0b3JPdXRwdXRNb2RlWyJPUF9XUklURSJdID0gMF0gPSAiT1BfV1JJVEUiOwogICAgICAgIE9wZXJhdG9yT3V0cHV0TW9kZVtPcGVyYXRvck91dHB1dE1vZGVbIk9QX1JFQURfV1JJVEUiXSA9IDFdID0gIk9QX1JFQURfV1JJVEUiOwogICAgfSkoT3BlcmF0b3JPdXRwdXRNb2RlIHx8IChPcGVyYXRvck91dHB1dE1vZGUgPSB7fSkpOwoKICAgIC8qKgogICAgICogUmVwcmVzZW50cyBhIHJlYWN0aXZlIHR5cGUgb2YgYXR0cmlidXRlIHRoYXQgY2FuIGJlIG93bmVkIGJ5IGEgYFBhcmFtZXRlck93bmVyYCBjbGFzcy4KICAgICAqCiAgICAgKiAqKkV2ZW50cyoqCiAgICAgKiAqICoqbmFtZUNoYW5nZWQ6KiogVHJpZ2dlcmVkIHdoZW4gdGhlIG5hbWUgb2YgdGhlIHBhcmFtZXRlciBjaGFuZ2VzLgogICAgICogKiAqKnZhbHVlQ2hhbmdlZDoqKiBUcmlnZ2VyZWQgd2hlbiB0aGUgdmFsdWUgb2YgdGhlIHBhcmFtZXRlciBjaGFuZ2VzLgogICAgICovCiAgICBjbGFzcyBQYXJhbWV0ZXIgZXh0ZW5kcyBCYXNlSXRlbSB7CiAgICAgICAgI3ZhbHVlOwogICAgICAgIGRpcnR5ID0gZmFsc2U7CiAgICAgICAgYm91bmRJbnB1dHMgPSBbXTsKICAgICAgICBib3VuZE91dHB1dHMgPSBbXTsKICAgICAgICBjbGVhbmluZyA9IGZhbHNlOwogICAgICAgIGRpcnR5T3BJbmRleCA9IDA7CiAgICAgICAgZmlyc3RPUF9XUklURSA9IDA7CiAgICAgICAgZGF0YVR5cGU7CiAgICAgICAgLyoqCiAgICAgICAgICogV2hlbiBpbml0aWFsaXppbmcgYSBuZXcgcGFyYW1ldGVyLCB0aGUgcGFzc2VkIGluIHZhbHVlIGNvdWxkIGJlIGFueXRoaW5nLgogICAgICAgICAqIElmIGl0IGlzIGEgbmV3IHR5cGUgb2YgdmFsdWUsIGp1c3QgZW5zdXJlIHlvdSByZWdpc3RlciBpdCBpbiB0aGUgYFJlZ2lzdHJ5YC4KICAgICAgICAgKgogICAgICAgICAqIEhvdyB0byB1c2UgaXQ6CiAgICAgICAgICoKICAgICAgICAgKiBgYGBqYXZhc2NyaXB0CiAgICAgICAgICogIC8vIENyZWF0aW5nIGEgcGFyYW1ldGVyIG9iamVjdAogICAgICAgICAqICBjb25zdCBwYXJhbSA9IG5ldyBQYXJhbWV0ZXIoJ1RpdGxlJywgJ0F3ZXNvbWUgUGFyYW1ldGVyIFZhbHVlJywgJ1N0cmluZycpCiAgICAgICAgICoKICAgICAgICAgKiAgIC8vIENhcHR1cmluZyBldmVudHMKICAgICAgICAgKiAgcGFyYW0ub24oJ3ZhbHVlQ2hhbmdlZCcsICguLi5wYXJhbXMpID0+IGNvbnNvbGUubG9nKCdWYWx1ZSBjaGFuZ2VkIScpKQogICAgICAgICAqCiAgICAgICAgICogIC8vIENoYW5naW5nIHBhcmFtZXRlcidzIHZhbHVlIHdpbGwgY2F1c2UgYHZhbHVlQ2hhbmdlZGAgZXZlbnQgdG8gdHJpZ2dlci4KICAgICAgICAgKiAgcGFyYW0uc2V0VmFsdWUoJ0EgTmV3IEF3ZXNvbWUgUGFyYW1ldGVyIFZhbHVlJykKICAgICAgICAgKiAgLy8gQXMgcmVzdWx0IHRoZSBjb25zb2xlIGxvZyBjb2RlIHdpbGwgZXhlY3V0ZTogVmFsdWUgQ2hhbmdlZCEKICAgICAgICAgKiBgYGAKICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBuYW1lIC0gVGhlIG5hbWUgb2YgdGhlIHBhcmFtZXRlci4KICAgICAgICAgKiBAcGFyYW0gdmFsdWUgLSBUaGUgdmFsdWUgb2YgdGhlIHBhcmFtZXRlci4KICAgICAgICAgKiBAcGFyYW0gZGF0YVR5cGUgLSBUaGUgZGF0YSB0eXBlIG9mIHRoZSBwYXJhbWV0ZXIuCiAgICAgICAgICovCiAgICAgICAgY29uc3RydWN0b3IobmFtZSA9ICcnLCB2YWx1ZSwgZGF0YVR5cGUpIHsKICAgICAgICAgICAgc3VwZXIobmFtZSk7CiAgICAgICAgICAgIHRoaXMuI3ZhbHVlID0gdmFsdWU7CiAgICAgICAgICAgIHRoaXMuZGF0YVR5cGUgPSBkYXRhVHlwZTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyBwYXJhbWV0ZXIncyBkYXRhIHR5cGUuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBnZXREYXRhVHlwZSgpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuZGF0YVR5cGU7CiAgICAgICAgfQogICAgICAgIC8vIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwogICAgICAgIC8vIE9wZXJhdG9yIGJpbmRpbmdzCiAgICAgICAgLyoqCiAgICAgICAgICogV2hlbiBhbiBPcGVyYXRvciBpcyByZWFkaW5nIGZyb20gYSBwYXJhbWV0ZXIsIGl0IG11c3QgYmUgZGlydGllZCB3aGVuIHRoZSBwYXJhbWV0ZXIgdmFsdWUKICAgICAgICAgKiBjaGFuZ2VzLiBUaGUgUGFyYW1ldGVyIG1haW50YWlucyBhIGxpc3Qgb2YgYm91bmQgaW5wdXRzIGFuZCB3aWxsIHByb3BhZ2F0ZSBkaXJ0eSB0bwogICAgICAgICAqIHRoZW0gZXhwbGljaXRseS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBvcGVyYXRvcklucHV0IC0gVGhlIG91dHB1dCB0aGF0IHdlIGFyZSB1bmJpbmRpbmcgZnJvbSB0aGUgUGFyYW1ldGVyCiAgICAgICAgICogQHBhcmFtIGluZGV4IC0gVGhlIGluZGV4KG9wdGlvbmFsKSB0aGF0IHRoZSBvdXRwdXQgaXMgYmVpbmcgYm91bmQgYXQuCiAgICAgICAgICogQHJldHVybiAtIFRoZSBpbmRleCBvZiB0aGUgYm91bmQgb3V0cHV0LgogICAgICAgICAqLwogICAgICAgIGJpbmRPcGVyYXRvcklucHV0KG9wZXJhdG9ySW5wdXQpIHsKICAgICAgICAgICAgdGhpcy5ib3VuZElucHV0cy5wdXNoKG9wZXJhdG9ySW5wdXQpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBXaGVuIGFuIG9wZXJhdG9yIGlzIGJlaW5nIHJlbW92ZWQgZnJvbSByZWFkaW5nIGZyb20gYSBQYXJhbWV0ZXIsIHRoZSBJbnB1dCBpcyByZW1vdmVkCiAgICAgICAgICogVGhpcyBtZWFucyB0aGUgb3BlcmF0b3Igd2lsbCBubyBsb25nZXIgcmVjZWl2ZSB1cGRhdGVzIHdoZW4gdGhlIG9wZXJhdG9yIGNoYW5nZXMuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gb3BlcmF0b3JJbnB1dCAtIFRoZSBvdXRwdXQgdGhhdCB3ZSBhcmUgdW5iaW5kaW5nIGZyb20gdGhlIFBhcmFtZXRlcgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHVuYmluZE9wZXJhdG9ySW5wdXQob3BlcmF0b3JJbnB1dCkgewogICAgICAgICAgICBjb25zdCBpbmRleCA9IHRoaXMuYm91bmRJbnB1dHMuaW5kZXhPZihvcGVyYXRvcklucHV0KTsKICAgICAgICAgICAgdGhpcy5ib3VuZElucHV0cy5zcGxpY2UoaW5kZXgsIDEpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBXaGVuIGFuIE9wZXJhdG9yIHdyaXRlcyB0byBhIHBhcmFtZXRlciwgaXQgYmluZHMgaXRzIG91dHB1dHMgdG8gdGhlIHBhcmFtZXRlciBhdCBhIGdpdmVuCiAgICAgICAgICogaW5kZXguIFRoZW4gd2hlbiB0aGUgb3BlcmF0b3IgaXMgZGlydGllZCBieSBvbmUgb2YgaXRzIGlucHV0cywgaXQgZXhwbGljaXRseSBkaXJ0aWVzCiAgICAgICAgICogdGhlIG91dHB1dCBwYXJhbWV0ZXJzLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIG9wZXJhdG9yT3V0cHV0IC0gVGhlIG91dHB1dCB0aGF0IHdlIGFyZSB1bmJpbmRpbmcgZnJvbSB0aGUgUGFyYW1ldGVyCiAgICAgICAgICogQHBhcmFtIGluZGV4IC0gVGhlIGluZGV4KG9wdGlvbmFsKSB0aGF0IHRoZSBvdXRwdXQgaXMgYmVpbmcgYm91bmQgYXQuCiAgICAgICAgICogQHJldHVybiAtIFRoZSBpbmRleCBvZiB0aGUgYm91bmQgb3V0cHV0LgogICAgICAgICAqLwogICAgICAgIGJpbmRPcGVyYXRvck91dHB1dChvcGVyYXRvck91dHB1dCwgaW5kZXggPSAtMSkgewogICAgICAgICAgICBpZiAoaW5kZXggPT0gLTEpCiAgICAgICAgICAgICAgICBpbmRleCA9IHRoaXMuYm91bmRPdXRwdXRzLmxlbmd0aDsKICAgICAgICAgICAgdGhpcy5ib3VuZE91dHB1dHMuc3BsaWNlKGluZGV4LCAwLCBvcGVyYXRvck91dHB1dCk7CiAgICAgICAgICAgIC8vIFVwZGF0ZSB0aGUgcmVtYWluaW5nIGJpbmRpbmcgaW5kaWNlcwogICAgICAgICAgICBmb3IgKGxldCBpID0gaW5kZXg7IGkgPCB0aGlzLmJvdW5kT3V0cHV0cy5sZW5ndGg7IGkrKykgewogICAgICAgICAgICAgICAgdGhpcy5ib3VuZE91dHB1dHNbaV0uc2V0UGFyYW1CaW5kSW5kZXgoaSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLy8gSWYgd2Ugd2VyZW4ndCBhbHJlYWR5IGRpcnR5LCBtYWtlIHN1cmUgdG8gZW1pdCBhICd2YWx1ZUNoYW5nZWQnIGFueXdheS4KICAgICAgICAgICAgdGhpcy5fX2ZpbmRGaXJzdE9QX1dSSVRFKCk7CiAgICAgICAgICAgIC8vIFRoaXMgZW5zdXJlcyB0aGF0IHRoZSBvcGVyYXRvciBzdGFjayBpcyBjb25zaWRlcmVkICdjbGVhbicKICAgICAgICAgICAgLy8gYW5kIHRoZW4gd2UgY2FsbCBzZXQgZGlydHkgdG8gZm9yY2UgaXQgdG8gYmVjb21lIGRpcnR5IGZyb20gdGhlIGluc2VydGlvbiBwb2ludCBkb3duLgogICAgICAgICAgICAvLyBXaXRob3V0IHRoaXMgbGluZSwgdGhlIG9wZXJhdG9yIGlzIGNvbnNpZGVyZWQgYWxyZWFkeSAnZGlydHknLCBhbmQgc28gd29uJ3QgcHJvcGFnYXRlLgogICAgICAgICAgICB0aGlzLmRpcnR5T3BJbmRleCA9IHRoaXMuYm91bmRPdXRwdXRzLmxlbmd0aDsKICAgICAgICAgICAgdGhpcy5zZXREaXJ0eShpbmRleCk7CiAgICAgICAgICAgIHJldHVybiBpbmRleDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogV2hlbiBhbiBvcGVyYXRvciBpcyB1bmJpbmRpbmcgZnJvbSBhIHBhcmFtZXRlciwgaXQgcmVtb3ZlcyBpdHMgc2VsZiBmcm9tIHRoZSBsaXN0IG1haW50YWluZWQKICAgICAgICAgKiBieSB0aGUgcGFyYW1ldGVyLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIG9wZXJhdG9yT3V0cHV0IC0gVGhlIG91dHB1dCB0aGF0IHdlIGFyZSB1bmJpbmRpbmcgZnJvbSB0aGUgUGFyYW1ldGVyCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgdW5iaW5kT3BlcmF0b3JPdXRwdXQob3BlcmF0b3JPdXRwdXQpIHsKICAgICAgICAgICAgY29uc3QgaW5kZXggPSBvcGVyYXRvck91dHB1dC5nZXRQYXJhbUJpbmRJbmRleCgpOwogICAgICAgICAgICB0aGlzLmJvdW5kT3V0cHV0cy5zcGxpY2UoaW5kZXgsIDEpOwogICAgICAgICAgICAvLyBVcGRhdGUgdGhlIHJlbWFpbmluZyBiaW5kaW5nIGluZGljZXMKICAgICAgICAgICAgZm9yIChsZXQgaSA9IGluZGV4OyBpIDwgdGhpcy5ib3VuZE91dHB1dHMubGVuZ3RoOyBpKyspIHsKICAgICAgICAgICAgICAgIHRoaXMuYm91bmRPdXRwdXRzW2ldLnNldFBhcmFtQmluZEluZGV4KGkpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHRoaXMuX19maW5kRmlyc3RPUF9XUklURSgpOwogICAgICAgICAgICB0aGlzLmRpcnR5T3BJbmRleCA9IHRoaXMuYm91bmRPdXRwdXRzLmxlbmd0aDsKICAgICAgICAgICAgdGhpcy5zZXREaXJ0eShNYXRoLm1heCgwLCBpbmRleCAtIDEpKTsKICAgICAgICAgICAgcmV0dXJuIGluZGV4OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBGaW5kIHRoZSBmaXJzdCBvcGVyYXRvciBpbiBvdXIgc3RhY2sgd2hpY2ggd3JpdGVzIHVzaW5nIGFuIE9QX1dSSVRFIGNvbm5lY3Rpb24uCiAgICAgICAgICogQWxsIG9wZXJhdG9ycyBiZWZvcmUgdGhpcyBvcCBjYW4gYmUgaWdub3JlZCBkdXJpbmcgZGlydHkgcHJvcGFnYXRpb24uCiAgICAgICAgICogQHByaXZhdGUKICAgICAgICAgKi8KICAgICAgICBfX2ZpbmRGaXJzdE9QX1dSSVRFKCkgewogICAgICAgICAgICB0aGlzLmZpcnN0T1BfV1JJVEUgPSB0aGlzLmJvdW5kT3V0cHV0cy5sZW5ndGg7CiAgICAgICAgICAgIGlmICh0aGlzLmJvdW5kT3V0cHV0cy5sZW5ndGggPiAwKSB7CiAgICAgICAgICAgICAgICBmb3IgKHRoaXMuZmlyc3RPUF9XUklURS0tOyB0aGlzLmZpcnN0T1BfV1JJVEUgPiAwOyB0aGlzLmZpcnN0T1BfV1JJVEUtLSkgewogICAgICAgICAgICAgICAgICAgIC8vIEZpbmQgdGhlIGZpcnN0IE9QX1dSSVRFIGJpbmRpbmcuIChOb3RlOiB3ZSBjb3VsZCBjYWNoZSB0aGlzKQogICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLmJvdW5kT3V0cHV0c1t0aGlzLmZpcnN0T1BfV1JJVEVdLmdldE1vZGUoKSA9PSBPcGVyYXRvck91dHB1dE1vZGUuT1BfV1JJVEUpCiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGlzRHJpdmVuQnlPcGVyYXRvcigpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuZmlyc3RPUF9XUklURSA9PSAwICYmIHRoaXMuYm91bmRPdXRwdXRzLmxlbmd0aCA+IDA7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIERpcnRpZXMgdGhpcyBQYXJhbWV0ZXIgc28gc3Vic2VxdWVudCBjYWxscyB0byBgZ2V0VmFsdWVgIHdpbGwgY2F1c2UgYW4gZXZhbHVhdGlvbiBvZiBpdHMgYm91bmQgb3BlcmF0b3JzLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGluZGV4IC0gSW5kZXggb2YgdGhlIG9wZXJhdG9yCiAgICAgICAgICogQHJldHVybiAtIGB0cnVlYCBpZiB0aGUgUGFyYW1ldGVyIHdhcyBtYWRlIGRpcnR5LCBlbHNlIGBmYWxzZWAgaWYgaXQgd2FzIGFscmVhZHkgZGlydHkuCiAgICAgICAgICovCiAgICAgICAgc2V0RGlydHkoaW5kZXgpIHsKICAgICAgICAgICAgLy8gRGV0ZXJtaW5lIHRoZSBmaXJzdCBvcGVyYXRvciBpbiB0aGUgc3RhY2sgdGhhdCBtdXN0IGV2YWx1YXRlIHRvIGNsZWFuIHRoZSBwYXJhbWV0ZXIuCiAgICAgICAgICAgIC8vIE5vdGU6IGlmIGEgUkVBRF9XUklURSBvcCBpcyBiZWNvbWluZyBkaXJ0eSwgdGhlbiB3ZSBkaXJ0eSBiYWNrIHVwIHRvIHRoYXQgb3AuCiAgICAgICAgICAgIGlmIChpbmRleCA8IHRoaXMuZGlydHlPcEluZGV4KSB7CiAgICAgICAgICAgICAgICAvLyBJZiB3ZSBtdXN0IGRpcnR5IGFsbCBvcGVyYXRvcnMgaW4gdGhlIHN0YWNrIGZyb20gdGhlIGxhc3QgT1BfV1JJVEUgdG8gdGhlIGVuZC4KICAgICAgICAgICAgICAgIC8vIE5vdGU6IElmIGEgc2V0RGlydHkgY2FsbCBjb21lcyBmcm9tIGFuIG9wIHRoYXQgcHJlY2VkZXMgYW4gT1BfV1JJVEUgb3BlcmF0b3IsIHdlCiAgICAgICAgICAgICAgICAvLyBjYW4gc2FmZWx5IGRpc2NhcmQgaXQsIGFzIGl0cyBvdXRwdXQgd2lsbCBoYXZlIG5vIGVmZmVjdCBvbiB0aGUgdmFsdWUgb2YgdGhpcyBwYXJhbWV0ZXIuCiAgICAgICAgICAgICAgICBsZXQgbmV3RGlydHlJbmRleCA9IHRoaXMuZmlyc3RPUF9XUklURTsKICAgICAgICAgICAgICAgIGlmIChuZXdEaXJ0eUluZGV4IDw9IGluZGV4KSB7CiAgICAgICAgICAgICAgICAgICAgdGhpcy5kaXJ0eU9wSW5kZXggPSBuZXdEaXJ0eUluZGV4OwogICAgICAgICAgICAgICAgICAgIGZvciAobmV3RGlydHlJbmRleCsrOyBuZXdEaXJ0eUluZGV4IDwgdGhpcy5ib3VuZE91dHB1dHMubGVuZ3RoOyBuZXdEaXJ0eUluZGV4KyspIHsKICAgICAgICAgICAgICAgICAgICAgICAgLy8gRGlydHkgYWxsIHRoZSBvdGhlciBib3VuZCBvcHMgZnJvbSB0aGUgT1BfV1JJVEUgdG8gdGhlIHRvcCBvZiB0aGUgc3RhY2suCiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChuZXdEaXJ0eUluZGV4ICE9IGluZGV4KSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBUaGlzIHdpbGwgY2F1c2UgdGhlIG90aGVyIG91dHB1dHMgb2YgdGhlIG9wZXJhdG9yIHRvIGJlY29tZSBkaXJ0eS4KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuYm91bmRPdXRwdXRzW25ld0RpcnR5SW5kZXhdLmdldE9wZXJhdG9yKCkuc2V0RGlydHkoKTsKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuYm91bmRJbnB1dHMubGVuZ3RoOyBpKyspIHsKICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5ib3VuZElucHV0c1tpXS5zZXREaXJ0eSgpOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB0aGlzLmVtaXQoJ3ZhbHVlQ2hhbmdlZCcpOwogICAgICAgICAgICAgICAgICAgIHJldHVybiB0cnVlOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBmYWxzZTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyB0cnVlIGlmIHRoaXMgcGFyYW1ldGVyIGlzIGN1cnJlbnRseSBkaXJ0eSBhbmQgd2lsbCBldmFsdWF0ZSBpdHMgYm91bmQKICAgICAgICAgKiBvcGVyYXRvcnMgaWYgaXRzIHZhbHVlIGlzIHJlcXVlc3RlZCBieSBhIGNhbGwgdG8gZ2V0VmFsdWUuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyBhIGJvb2xlYW4uCiAgICAgICAgICovCiAgICAgICAgaXNEaXJ0eSgpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuZGlydHlPcEluZGV4IDwgdGhpcy5ib3VuZE91dHB1dHMubGVuZ3RoOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIHRoZSBpbmRleCBvZiB0aGUgZmlyc3QgJ2RpcnR5JyBiaW5kaW5nIGluIHRoZSBzdGFjay4gVGhpcyB3aWxsIGJlIHRoZSBpbmRleCBvZiB0aGUKICAgICAgICAgKiBmaXJzdCBvcGVyYXRvciB0aGF0IHdpbGwgZXZhbHVhdGUgd2hlbiB0aGUgcGFyYW1ldGVyIG5lZWRzIHRvIGJlIGNsZWFuZWQuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIGluZGV4IG9mIHRoZSBkaXJ0eSBiaW5kaW5nIGluIHRoZSBiaW5kaW5nIHN0YWNrLgogICAgICAgICAqLwogICAgICAgIGdldERpcnR5QmluZGluZ0luZGV4KCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy5kaXJ0eU9wSW5kZXg7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBzZXRDbGVhbkZyb21PcCBtZXRob2QuCiAgICAgICAgICogQHBhcmFtIHZhbHVlIC0gVGhlIGNvbXB1dGVkIHZhbHVlIHRvIGJlIHN0b3JlZCBpbiB0aGUgUGFyYW1ldGVyLgogICAgICAgICAqIEBwYXJhbSBpbmRleCAtIFRoZSBpbmRleCBvZiB0aGUgYm91bmQgT3BlcmF0b3JPdXRwdXQuCiAgICAgICAgICovCiAgICAgICAgc2V0Q2xlYW5Gcm9tT3AodmFsdWUsIGluZGV4KSB7CiAgICAgICAgICAgIGlmIChpbmRleCAhPSB0aGlzLmRpcnR5T3BJbmRleCkgewogICAgICAgICAgICAgICAgaWYgKGluZGV4IDwgdGhpcy5kaXJ0eU9wSW5kZXgpIHsKICAgICAgICAgICAgICAgICAgICAvLyBUaGlzIGNhbiBoYXBwZW4gd2hlbiBhbiBvcGVyYXRvciBpbiB0aGUgZm9sbG93aW5nIGNhc2UuCiAgICAgICAgICAgICAgICAgICAgLy8gUGFyYW1BIFtPcEMsIE9wQiwgT3BBXQogICAgICAgICAgICAgICAgICAgIC8vIFBhcmFtQiBbT3BDLCBPcEFdCiAgICAgICAgICAgICAgICAgICAgLy8gV2hlbiBPcEIgZGlydGllcyBQYXJhbUEsIGFuZCBpcyBldmFsdWF0ZWQsIFBhcmFtQiBpcyBjb25zaWRlcmVkIGNsZWFuIGJlY2F1c2UgT3BBIHdhcyBuZXZlciBkaXJ0aWVkCiAgICAgICAgICAgICAgICAgICAgLy8gV2Ugc2VlIHRoaXMgbWVzc2FnZSB3aGVuIHBhcmFtZXRlcnMgYXJlIGV2YWx1YXRlZCBhcyBzb29uIGFzIGEgY2hhbmdlIGlzIGRldGVjdGVkIGluc3RlYWQgb2YKICAgICAgICAgICAgICAgICAgICAvLyBpbiBiYXRjaGVzLiBOb3cgdGhhdCBhbGwgcmVuZGVyaW5nIGNvZGUgaXMgcHVsbGluZyBkYXRhIG9ubHkgZHVyaW5nIHRoZSByZW5kZXIgY3ljbGUsIHdlIGFyYQogICAgICAgICAgICAgICAgICAgIC8vIG5vdCBzZWVpbmcgaXQgYW55bW9yZS4gSG93ZXZlciwgbWF5YmUgd2l0aCBhIFVJIG9wZW4sIGl0IHdpbGwgc3RhcnQgZW1pdHRpbmcgdGhpcyB3YXJuaW5nLgogICAgICAgICAgICAgICAgICAgIC8vIE5vdGU6IHRoaXMgd291bGQgYmUgY2F1c2VkLCBpZiBhIFBhcmFtZXRlciBpcyBhbHJlYWR5IGNsZWFuZWQgYnkgYW4gT3BlcmF0b3IsIGFuZCB5ZXQgdGhlIE9wZXJhdG9yCiAgICAgICAgICAgICAgICAgICAgLy8gaXMgcmUtZXZhbHVhdGluZy4gSSBhbSBub3Qgc3VyZSBob3cgdGhpcyBjYW4gb2NjdXIuCiAgICAgICAgICAgICAgICAgICAgLy8gY29uc3Qgb3AgPSBvcGVyYXRvck91dHB1dC5nZXRPcGVyYXRvcigpCiAgICAgICAgICAgICAgICAgICAgLy8gY29uc29sZS5sb2coCiAgICAgICAgICAgICAgICAgICAgLy8gICBgT3BlcmF0b3I6OiAkewogICAgICAgICAgICAgICAgICAgIC8vICAgICBvcC5jb25zdHJ1Y3Rvci5uYW1lCiAgICAgICAgICAgICAgICAgICAgLy8gICB9IHdpdGggbmFtZTogJHtvcC5uYW1lfSBpcyBiZWluZyBjbGVhbmVkIGltbWVkaWF0ZWx5LCBpbnN0ZWFkIG9mIGxhemlseS5gCiAgICAgICAgICAgICAgICAgICAgLy8gKQogICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKGBQYXJhbWV0ZXIgaXMgY2xlYW5lZCB3aGVuIGl0IHdhcyBhbHJlYWR5IGNsZWFuIHRvIHRoYXQgcG9pbnQgaW4gdGhlIHN0YWNrOmAsIHRoaXMuZ2V0UGF0aCgpKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGVsc2UgaWYgKHRoaXMuYm91bmRPdXRwdXRzW2luZGV4XS5nZXRNb2RlKCkgIT0gT3BlcmF0b3JPdXRwdXRNb2RlLk9QX1dSSVRFKSB7CiAgICAgICAgICAgICAgICAgICAgLy8gQSBwYXJhbWV0ZXIgY2FuIGJlY29tZSBkaXJ0eSAoc28gX19kaXJ0eU9wSW5kZXggPT0gMCksIGFuZCB0aGVuIGFub3RoZXIgb3BlcmF0b3IgYm91bmQgb24gdG9wLgogICAgICAgICAgICAgICAgICAgIC8vIGlmIHRoZSBuZXh0IG9wIGlzIGEgV1JJVEUgb3AsIHRoZW4gd2UgY2FuIGZhc3QgZm9yd2FyZCB0aGUgZGlydHkgaW5kZXguCiAgICAgICAgICAgICAgICAgICAgY29uc3QgdGhpc0NsYXNzTmFtZSA9IHRoaXMuZ2V0Q2xhc3NOYW1lKCk7CiAgICAgICAgICAgICAgICAgICAgY29uc3Qgb3AgPSB0aGlzLmJvdW5kT3V0cHV0c1tpbmRleF0uZ2V0T3BlcmF0b3IoKTsKICAgICAgICAgICAgICAgICAgICBjb25zdCBvcENsYXNzTmFtZSA9IG9wLmNvbnN0cnVjdG9yLm5hbWU7CiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBQYXJhbWV0ZXI6ICR7dGhpc0NsYXNzTmFtZX0gd2l0aCBuYW1lOiAke3RoaXMuZ2V0TmFtZSgpfSBpcyBub3QgY2xlYW5pbmcgYWxsIG91dHB1dHMgZHVyaW5nIGV2YWx1YXRpb24gb2Ygb3A6ICR7b3BDbGFzc05hbWV9IHdpdGggbmFtZTogJHtvcC5uYW1lfWApOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIHRoaXMuI3ZhbHVlID0gdmFsdWU7CiAgICAgICAgICAgIC8vIEFzIGVhY2ggb3BlcmF0b3Igd3JpdGVzIGl0cyB2YWx1ZSwgdGhlIGRpcnR5IHZhbHVlIGlzIGluY3JlbWVudGVkCiAgICAgICAgICAgIHRoaXMuZGlydHlPcEluZGV4ID0gaW5kZXggKyAxOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBEdXJpbmcgb3BlcmF0b3IgZXZhbHVhdGlvbiwgb3BlcmF0b3JzIGNhbiB1c2UgdGhpcyBtZXRob2QgdG8gcmV0cmlldmUgdGhlIGV4aXN0aW5nCiAgICAgICAgICogdmFsdWUgb2Ygb25lIG9mIHRoZWlyIG91dHB1dHMuCiAgICAgICAgICogQHBhcmFtIGluZGV4IC0gVGhlIGluZGV4IG9mIHRoZSBib3VuZCBPcGVyYXRvck91dHB1dCB0byBldmFsdWF0ZSB1cCB0by4KICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBnZXRWYWx1ZUZyb21PcChpbmRleCkgewogICAgICAgICAgICAvLyBOb3RlOiBkdXJpbmcgZXZhbHVhdGlvbiBvZiBhbiBPcGVyYXRvciB0aGF0IHdyaXRlcyB0byBtdWx0aXBsZSBvdXRwdXRzLAogICAgICAgICAgICAvLyBpdCBjYW4gd3JpdGUgdG8gYW4gb3V0cHV0IHdpdGggYW4gSU8gc2V0dGluZywgd2hpY2ggbWVhbnMgaXQgcmV0cmlldmVzCiAgICAgICAgICAgIC8vIHRoZSBwcmV2aW91cyB2YWx1ZSB3aGlsZSBjYWxjdWxhdGluZyB0aGUgbmV4dC4KICAgICAgICAgICAgaWYgKHRoaXMuZGlydHlPcEluZGV4IDwgaW5kZXgpIHsKICAgICAgICAgICAgICAgIHRoaXMuX2NsZWFuKGluZGV4KTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gdGhpcy4jdmFsdWU7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENsZWFucyB0aGUgcGFyYW1ldGVyIHVwIHRwIHRoZSBpbmRleCBvZiB0aGUgc3BlY2lmaWVkIGluZGV4IG9mIHRoZSBib3VuZCBPcGVyYXRvck91dHB1dAogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGluZGV4IC0gVGhlIGluZGV4IG9mIHRoZSBib3VuZCBPcGVyYXRvck91dHB1dCB0byBldmFsdWF0ZSB1cCB0by4KICAgICAgICAgKi8KICAgICAgICBfY2xlYW4oaW5kZXgpIHsKICAgICAgICAgICAgaWYgKHRoaXMuY2xlYW5pbmcpIHsKICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgQ3ljbGUgZGV0ZWN0ZWQgd2hlbiBjbGVhbmluZzogJHt0aGlzLmdldFBhdGgoKX0uIE9wZXJhdG9ycyBuZWVkIHRvIGJlIHJlYm91bmQgdG8gZml4IGVycm9yc2ApOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHRoaXMuY2xlYW5pbmcgPSB0cnVlOwogICAgICAgICAgICB3aGlsZSAodGhpcy5kaXJ0eU9wSW5kZXggPCBpbmRleCkgewogICAgICAgICAgICAgICAgY29uc3QgdG1wID0gdGhpcy5kaXJ0eU9wSW5kZXg7CiAgICAgICAgICAgICAgICBjb25zdCBvcGVyYXRvck91dHB1dCA9IHRoaXMuYm91bmRPdXRwdXRzW3RoaXMuZGlydHlPcEluZGV4XTsKICAgICAgICAgICAgICAgIC8vIFRoZSBvcCBjYW4gZ2V0IHRoZSBjdXJyZW50IHZhbHVlIGFuZCBtb2RpZnkgaXQgaW4gcGxhY2UKICAgICAgICAgICAgICAgIC8vIGFuZCBzZXQgdGhlIG91dHB1dCB0byBjbGVhbi4KICAgICAgICAgICAgICAgIG9wZXJhdG9yT3V0cHV0LmdldE9wZXJhdG9yKCkuZXZhbHVhdGUoKTsKICAgICAgICAgICAgICAgIGlmICh0bXAgPT0gdGhpcy5kaXJ0eU9wSW5kZXgpIHsKICAgICAgICAgICAgICAgICAgICAvLyBEdXJpbmcgaW5pdGlhbCBjb25maWd1cmF0aW9uIG9mIGFuIG9wZXJhdG9yLCBjbGVhbmluZyBvdXRwdXRzIG1pZ2h0IGJlIGRpc2FibGVkLgogICAgICAgICAgICAgICAgICAgIGNvbnN0IG9wID0gdGhpcy5ib3VuZE91dHB1dHNbdGhpcy5kaXJ0eU9wSW5kZXhdLmdldE9wZXJhdG9yKCk7CiAgICAgICAgICAgICAgICAgICAgY29uc3Qgb3BDbGFzc05hbWUgPSBvcC5jb25zdHJ1Y3Rvci5uYW1lOwogICAgICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybihgT3BlcmF0b3I6ICR7b3BDbGFzc05hbWV9IHdpdGggbmFtZTogJHtvcC5uYW1lfSBpcyBub3QgY2xlYW5pbmcgaXRzIG91dHB1dHMgZHVyaW5nIGV2YWx1YXRpb25gKTsKICAgICAgICAgICAgICAgICAgICB0aGlzLmRpcnR5T3BJbmRleCsrOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIHRoaXMuY2xlYW5pbmcgPSBmYWxzZTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyBwYXJhbWV0ZXIncyB2YWx1ZS4KICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBnZXRWYWx1ZSgpIHsKICAgICAgICAgICAgaWYgKHRoaXMuZGlydHlPcEluZGV4IDwgdGhpcy5ib3VuZE91dHB1dHMubGVuZ3RoKSB7CiAgICAgICAgICAgICAgICB0aGlzLl9jbGVhbih0aGlzLmJvdW5kT3V0cHV0cy5sZW5ndGgpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiB0aGlzLiN2YWx1ZTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU2V0cyB2YWx1ZSBvZiB0aGUgcGFyYW1ldGVyLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHZhbHVlIC0gVGhlIHZhbHVlIHBhcmFtLgogICAgICAgICAqLwogICAgICAgIHNldFZhbHVlKHZhbHVlKSB7CiAgICAgICAgICAgIGlmICh2YWx1ZSA9PT0gdW5kZWZpbmVkKSB7CiAgICAgICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdGhyb3ctbGl0ZXJhbAogICAgICAgICAgICAgICAgdGhyb3cgJ3VuZGVmaW5lZCB3YXMgcGFzc2VkIGludG8gdGhlIHNldCB2YWx1ZSBmb3IgcGFyYW06JyArIHRoaXMuZ2V0TmFtZSgpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmICh0aGlzLmJvdW5kT3V0cHV0cy5sZW5ndGggPiAwKSB7CiAgICAgICAgICAgICAgICBmb3IgKGxldCBpID0gdGhpcy5ib3VuZE91dHB1dHMubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0pIHsKICAgICAgICAgICAgICAgICAgICBjb25zdCBvcGVyYXRvck91dHB1dCA9IHRoaXMuYm91bmRPdXRwdXRzW2ldOwogICAgICAgICAgICAgICAgICAgIHZhbHVlID0gb3BlcmF0b3JPdXRwdXQuYmFja1Byb3BhZ2F0ZVZhbHVlKHZhbHVlKTsKICAgICAgICAgICAgICAgICAgICBpZiAob3BlcmF0b3JPdXRwdXQuZ2V0TW9kZSgpID09IDAgLyogT1BfV1JJVEUgKi8pCiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAodHlwZW9mIHZhbHVlICE9PSAnb2JqZWN0JykgewogICAgICAgICAgICAgICAgLy8gTm90ZTogZXF1YWxpdHkgdGVzdHMgb24gYW55dGhpbmcgYnV0IHNpbXBsZSB2YWx1ZXMgaXMgZ29pbmcgdG8gYmUgc3VwZXIgZXhwZW5zaXZlLgogICAgICAgICAgICAgICAgaWYgKHRoaXMuI3ZhbHVlID09IHZhbHVlKQogICAgICAgICAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgICAgfQogICAgICAgICAgICB0aGlzLiN2YWx1ZSA9IHZhbHVlOwogICAgICAgICAgICAvLyBOb3RlOiBvbmx5IHVzZXJzIGNhbGwgJ3NldFZhbHVlJy4gT3BlcmF0b3JzIGNhbGwgJ3NldENsZWFuRnJvbU9wJwogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuYm91bmRJbnB1dHMubGVuZ3RoOyBpKyspIHsKICAgICAgICAgICAgICAgIHRoaXMuYm91bmRJbnB1dHNbaV0ucGFyYW1WYWx1ZUNoYW5nZWQoKTsKICAgICAgICAgICAgfQogICAgICAgICAgICB0aGlzLmVtaXQoJ3ZhbHVlQ2hhbmdlZCcpOwogICAgICAgIH0KICAgICAgICBnZXQgdmFsdWUoKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLmdldFZhbHVlKCk7CiAgICAgICAgfQogICAgICAgIHNldCB2YWx1ZSh2YWx1ZSkgewogICAgICAgICAgICB0aGlzLnNldFZhbHVlKHZhbHVlKTsKICAgICAgICB9CiAgICAgICAgLy8gLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwogICAgICAgIC8vIFBlcnNpc3RlbmNlCiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGxvYWRWYWx1ZSBpcyB1c2VkIHRvIGNoYW5nZSB0aGUgdmFsdWUgb2YgYSBwYXJhbWV0ZXIsIHdpdGhvdXQgdHJpZ2dlcmluZyBhCiAgICAgICAgICogdmFsdWVDaGFuZ2VzLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHZhbHVlIC0gVGhlIGNvbnRleHQgdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgbG9hZFZhbHVlKHZhbHVlKSB7CiAgICAgICAgICAgIHRoaXMuI3ZhbHVlID0gdmFsdWU7CiAgICAgICAgfQogICAgICAgIGNvcHlGcm9tKHNyYywgY29udGV4dCkgewogICAgICAgICAgICB0aGlzLmxvYWRWYWx1ZShzcmMudmFsdWUpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgcmVhZEJpbmFyeSBtZXRob2QuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gcmVhZGVyIC0gVGhlIHJlYWRlciB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0gY29udGV4dCAtIFRoZSBjb250ZXh0IHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHJlYWRCaW5hcnkocmVhZGVyLCBjb250ZXh0KSB7CiAgICAgICAgICAgIGNvbnNvbGUud2FybihgVE9ETzogUGFyYW1ldGVyOiAke3RoaXMuY29uc3RydWN0b3IubmFtZX0gd2l0aCBuYW1lOiAke3RoaXMubmFtZX0gZG9lcyBub3QgaW1wbGVtZW50IHJlYWRCaW5hcnlgKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyB0aGUgcGFyYW1ldGVyJ3MgcGF0aCBhcyBhbiBhcnJheSBvZiBzdHJpbmdzLgogICAgICAgICAqIEluY2x1ZGVzIG93bmVyJ3MgcGF0aCBpbiBjYXNlIGl0IGlzIG93bmVkIGJ5IGEgYFBhcmFtZXRlck93bmVyYC4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGdldFBhdGgoKSB7CiAgICAgICAgICAgIGlmICh0aGlzLm93bmVySXRlbSBpbnN0YW5jZW9mIEJhc2VJdGVtKSB7CiAgICAgICAgICAgICAgICByZXR1cm4gWy4uLnRoaXMub3duZXJJdGVtLmdldFBhdGgoKSwgdGhpcy5uYW1lXTsKICAgICAgICAgICAgfQogICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgIHJldHVybiBbdGhpcy5uYW1lXTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZXNvbHZlUGF0aChwYXRoLCBpbmRleCA9IDApIHsKICAgICAgICAgICAgaWYgKGluZGV4ID09IDApIHsKICAgICAgICAgICAgICAgIGlmIChwYXRoWzBdID09ICcuJyB8fCBwYXRoWzBdID09IHRoaXMubmFtZSkKICAgICAgICAgICAgICAgICAgICBpbmRleCsrOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIChwYXRoW2luZGV4XSA9PSAnLi4nKSB7CiAgICAgICAgICAgICAgICBpZiAodGhpcy5vd25lckl0ZW0pIHsKICAgICAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5vd25lckl0ZW0ucmVzb2x2ZVBhdGgocGF0aCwgaW5kZXggKyAxKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGVsc2UgewogICAgICAgICAgICAgICAgICAgIHRocm93IEVycm9yKCd0aGlzLm93bmVySXRlbSBpcyB1bmRlZmluZWQnKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoaW5kZXggPT0gcGF0aC5sZW5ndGgpIHsKICAgICAgICAgICAgICAgIHJldHVybiB0aGlzOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIChwYXRoW2luZGV4XSA9PSAndmFsdWUnKSB7CiAgICAgICAgICAgICAgICAvLyBUaGUgcGF0aCB0byB0aGUgcGFyYW1ldGVyLCBhc3N1bWVzIHRoYXQgdGhlIG5leHQgaXRlbSB3aWxsIGJlIGEgc3ViLXBhcmFtCiAgICAgICAgICAgICAgICAvLyBvZiB0aGUgdmFsdWUgb2YgdGhlIHBhcmFtZXRlci4KICAgICAgICAgICAgICAgIGlmICh0aGlzLiN2YWx1ZSBpbnN0YW5jZW9mIEJhc2VJdGVtKQogICAgICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLiN2YWx1ZS5yZXNvbHZlUGF0aChwYXRoLCBpbmRleCArIDEpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBwYXRoOicgKyBwYXRoICsgJ1snICsgaW5kZXggKyAnXS4gUGF0aCBkb2VzIG5vdCByZXNvbHZlIHRvIGEgQmFzZUl0ZW0nKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIHJlYWRCaW5hcnkgbWV0aG9kLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHJlYWRlciAtIFRoZSByZWFkZXIgdmFsdWUuCiAgICAgICAgICogQHBhcmFtIGNvbnRleHQgLSBUaGUgY29udGV4dCB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBkZXN0cm95KCkgewogICAgICAgICAgICBjb25zb2xlLndhcm4oJ25vdGhpbmcgZGVzdHJveWVkLiBUaGlzIG1ldGhvZCB3YXMgbm90IG92ZXJ3cml0dGVuIGluIHN1YmNsYXNzJyk7CiAgICAgICAgfQogICAgfQoKICAgIC8qKgogICAgICogUmVwcmVzZW50cyBhIHNwZWNpZmljIHR5cGUgb2YgcGFyYW1ldGVyLCB0aGF0IG9ubHkgc3RvcmVzIG51bWVyaWMgdmFsdWVzLgogICAgICoKICAgICAqIGBgYGphdmFzY3JpcHQKICAgICAqIGNvbnN0IG51bWJlclBhcmFtID0gbmV3IE51bWJlclBhcmFtZXRlcignTXlOdW1iZXInLCAxNSkKICAgICAqIC8vJ215UGFyYW1ldGVyT3duZXJJdGVtJyBpcyBhbiBpbnN0YW5jZSBvZiBhICdQYXJhbWV0ZXJPd25lcicgY2xhc3MuCiAgICAgKiAvLyBSZW1lbWJlciB0aGF0IG9ubHkgJ1BhcmFtZXRlck93bmVyJyBhbmQgY2xhc3NlcyB0aGF0IGV4dGVuZCBmcm9tIGl0IGNhbiBob3N0ICdQYXJhbWV0ZXInIG9iamVjdHMuCiAgICAgKiBteVBhcmFtZXRlck93bmVySXRlbS5hZGRQYXJhbWV0ZXIobnVtYmVyUGFyYW0pCiAgICAgKiBgYGAKICAgICAqCiAgICAgKiBAZXh0ZW5kcyBQYXJhbWV0ZXIKICAgICAqLwogICAgY2xhc3MgTnVtYmVyUGFyYW1ldGVyIGV4dGVuZHMgUGFyYW1ldGVyIHsKICAgICAgICByYW5nZTsgLy8gVE9ETzogc2hvdWxkIGNyZWF0ZSB0eXBlIHdpdGggdHdvIGZpZWxkcyBmb3IgcmFuZ2UuIE11c3QgY2hhbmdlIGhvdyByYW5nZSBpcyB1c2VkLgogICAgICAgIHN0ZXA7CiAgICAgICAgLyoqCiAgICAgICAgICogQ3JlYXRlIGEgbnVtYmVyIHBhcmFtZXRlci4KICAgICAgICAgKiBAcGFyYW0gbmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBudW1iZXIgcGFyYW1ldGVyLgogICAgICAgICAqIEBwYXJhbSB2YWx1ZSAtIFRoZSB2YWx1ZSBvZiB0aGUgcGFyYW1ldGVyLgogICAgICAgICAqIEBwYXJhbSByYW5nZSAtIEFuIGFycmF5IHdpdGggdHdvIG51bWJlcnMuIElmIGRlZmluZWQsIHRoZSBwYXJhbWV0ZXIgdmFsdWUgd2lsbCBiZSBjbGFtcGVkLgogICAgICAgICAqIEBwYXJhbSBzdGVwIC0gVGhlIHN0ZXAgdmFsdWUuIElmIGRlZmluZWQsIHRoZSBwYXJhbWV0ZXIgdmFsdWUgd2lsbCBiZSByb3VuZGVkIHRvIHRoZSBuZWFyZXN0IGludGVnZXIuCiAgICAgICAgICovCiAgICAgICAgY29uc3RydWN0b3IobmFtZSA9ICcnLCB2YWx1ZSA9IDAsIHJhbmdlLCBzdGVwKSB7CiAgICAgICAgICAgIHN1cGVyKG5hbWUsIHZhbHVlLCAnTnVtYmVyJyk7CiAgICAgICAgICAgIHRoaXMucmFuZ2UgPSByYW5nZTsKICAgICAgICAgICAgdGhpcy5zdGVwID0gc3RlcDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyB0aGUgcmFuZ2UgdG8gd2hpY2ggdGhlIHBhcmFtZXRlciBpcyByZXN0cmFpbmVkLgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgZ2V0UmFuZ2UoKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLnJhbmdlOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTZXRzIHRoZSByYW5nZSB0byB3aGljaCB0aGUgcGFyYW1ldGVyIGlzIHJlc3RyYWluZWQuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gcmFuZ2UgLSBUaGUgcmFuZ2UgdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgc2V0UmFuZ2UocmFuZ2UpIHsKICAgICAgICAgICAgdGhpcy5yYW5nZSA9IHJhbmdlOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIHRoZSBzdGVwIG51bWJlciwgd2hpY2ggaXMgdGhlIG9uZSB1c2VkIGZvciByb3VuZGluZy4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGdldFN0ZXAoKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLnN0ZXA7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgc3RlcCB2YWx1ZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBzdGVwIC0gVGhlIHN0ZXAgdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgc2V0U3RlcChzdGVwKSB7CiAgICAgICAgICAgIHRoaXMuc3RlcCA9IHN0ZXA7CiAgICAgICAgfQogICAgICAgIHNldFZhbHVlKHZhbHVlKSB7CiAgICAgICAgICAgIGlmICh0eXBlb2YgdmFsdWUgIT0gJ251bWJlcicpIHsKICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgdmFsdWUgcHJvdmlkZWQgaXMgbm90IGEgbnVtYmVyLiBDaGVjayB0aGUgc291cmNlIG9mIHRoaXMgdmFsdWVgKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBzdXBlci5zZXRWYWx1ZSh2YWx1ZSk7CiAgICAgICAgfQogICAgICAgIC8vIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KICAgICAgICAvLyBQZXJzaXN0ZW5jZQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSB0b0pTT04gbWV0aG9kIGVuY29kZXMgdGhpcyB0eXBlIGFzIGEganNvbiBvYmplY3QgZm9yIHBlcnNpc3RlbmNlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGNvbnRleHQgLSBUaGUgY29udGV4dCB2YWx1ZS4KICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyB0aGUganNvbiBvYmplY3QuCiAgICAgICAgICovCiAgICAgICAgdG9KU09OKGNvbnRleHQpIHsKICAgICAgICAgICAgcmV0dXJuIHsgdHlwZTogdGhpcy5nZXRDbGFzc05hbWUoKSwgbmFtZTogdGhpcy5uYW1lLCB2YWx1ZTogdGhpcy52YWx1ZSB9OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgZnJvbUpTT04gbWV0aG9kIGRlY29kZXMgYSBqc29uIG9iamVjdCBmb3IgdGhpcyB0eXBlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGogLSBUaGUganNvbiBvYmplY3QgdGhpcyBpdGVtIG11c3QgZGVjb2RlLgogICAgICAgICAqIEBwYXJhbSBjb250ZXh0IC0gVGhlIGNvbnRleHQgdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgZnJvbUpTT04oaiwgY29udGV4dCkgewogICAgICAgICAgICB0aGlzLnZhbHVlID0gai52YWx1ZTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogRXh0cmFjdHMgYSBudW1iZXIgdmFsdWUgZnJvbSBhIGJ1ZmZlciwgdXBkYXRpbmcgY3VycmVudCBwYXJhbWV0ZXIgc3RhdGUuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gcmVhZGVyIC0gVGhlIHJlYWRlciB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0gY29udGV4dCAtIFRoZSBjb250ZXh0IHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHJlYWRCaW5hcnkocmVhZGVyLCBjb250ZXh0KSB7CiAgICAgICAgICAgIHRoaXMudmFsdWUgPSByZWFkZXIubG9hZEZsb2F0MzIoKTsKICAgICAgICB9CiAgICAgICAgLy8gLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwogICAgICAgIC8vIENsb25lCiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGNsb25lIG1ldGhvZCBjb25zdHJ1Y3RzIGEgbmV3IG51bWJlciBwYXJhbWV0ZXIsIGNvcGllcyBpdHMgdmFsdWVzCiAgICAgICAgICogZnJvbSB0aGlzIHBhcmFtZXRlciBhbmQgcmV0dXJucyBpdC4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGEgbmV3IG51bWJlciBwYXJhbWV0ZXIuCiAgICAgICAgICovCiAgICAgICAgY2xvbmUoKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgTnVtYmVyUGFyYW1ldGVyKHRoaXMubmFtZSwgdGhpcy52YWx1ZSwgdGhpcy5yYW5nZSwgdGhpcy5zdGVwKTsKICAgICAgICB9CiAgICB9CiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgcmVxdWlyZS1qc2RvYwogICAgY2xhc3MgRmxvYXQzMlBhcmFtZXRlciBleHRlbmRzIE51bWJlclBhcmFtZXRlciB7CiAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIHJlcXVpcmUtanNkb2MKICAgICAgICByZWFkQmluYXJ5KHJlYWRlciwgY29udGV4dCkgewogICAgICAgICAgICB0aGlzLnZhbHVlID0gcmVhZGVyLmxvYWRGbG9hdDMyKCk7CiAgICAgICAgfQogICAgfQogICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIHJlcXVpcmUtanNkb2MKICAgIGNsYXNzIFNJbnQzMlBhcmFtZXRlciBleHRlbmRzIE51bWJlclBhcmFtZXRlciB7CiAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIHJlcXVpcmUtanNkb2MKICAgICAgICByZWFkQmluYXJ5KHJlYWRlciwgY29udGV4dCkgewogICAgICAgICAgICB0aGlzLnZhbHVlID0gcmVhZGVyLmxvYWRTSW50MzIoKTsKICAgICAgICB9CiAgICB9CiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgcmVxdWlyZS1qc2RvYwogICAgY2xhc3MgVUludDMyUGFyYW1ldGVyIGV4dGVuZHMgTnVtYmVyUGFyYW1ldGVyIHsKICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgcmVxdWlyZS1qc2RvYwogICAgICAgIHJlYWRCaW5hcnkocmVhZGVyLCBjb250ZXh0KSB7CiAgICAgICAgICAgIHRoaXMudmFsdWUgPSByZWFkZXIubG9hZFVJbnQzMigpOwogICAgICAgIH0KICAgIH0KICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSByZXF1aXJlLWpzZG9jCiAgICBjbGFzcyBBbmdsZVBhcmFtZXRlciBleHRlbmRzIEZsb2F0MzJQYXJhbWV0ZXIgewogICAgfQogICAgUmVnaXN0cnkucmVnaXN0ZXIoJ051bWJlclBhcmFtZXRlcicsIE51bWJlclBhcmFtZXRlcik7CiAgICBSZWdpc3RyeS5yZWdpc3RlcignUHJvcGVydHlfU0ludDMyJywgU0ludDMyUGFyYW1ldGVyKTsKICAgIFJlZ2lzdHJ5LnJlZ2lzdGVyKCdQcm9wZXJ0eV9VSW50MzInLCBVSW50MzJQYXJhbWV0ZXIpOwogICAgUmVnaXN0cnkucmVnaXN0ZXIoJ1Byb3BlcnR5X0Zsb2F0MzInLCBGbG9hdDMyUGFyYW1ldGVyKTsKICAgIFJlZ2lzdHJ5LnJlZ2lzdGVyKCdBbmdsZVBhcmFtZXRlcicsIEFuZ2xlUGFyYW1ldGVyKTsKCiAgICAvKioKICAgICAqIFJlcHJlc2VudHMgYSBzcGVjaWZpYyB0eXBlIG9mIHBhcmFtZXRlciwgdGhhdCBzdG9yZXMgbXVsdGlwbGUgY2hvaWNlKGFycmF5KSB2YWx1ZXMuCiAgICAgKgogICAgICogaS5lLjoKICAgICAqIGBgYGphdmFzY3JpcHQKICAgICAqIGNvbnN0IG11bHRpQ2hvaWNlUGFyYW1ldGVyID0gIG5ldyBNdWx0aUNob2ljZVBhcmFtZXRlcignSW5pdGlhbFhmb01vZGUnLCBHUk9VUF9JTklUSUFMX1hGT19NT0RFUy5hdmVyYWdlLCBbCiAgICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnbWFudWFsJywKICAgICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdmaXJzdCcsCiAgICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnYXZlcmFnZScsCiAgICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnZ2xvYmFsJywKICAgICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBdKQogICAgICogLy8nbXlQYXJhbWV0ZXJPd25lckl0ZW0nIGlzIGFuIGluc3RhbmNlIG9mIGEgJ1BhcmFtZXRlck93bmVyJyBjbGFzcy4KICAgICAqIC8vIFJlbWVtYmVyIHRoYXQgb25seSAnUGFyYW1ldGVyT3duZXInIGFuZCBjbGFzc2VzIHRoYXQgZXh0ZW5kIGZyb20gaXQgY2FuIGhvc3QgJ1BhcmFtZXRlcicgb2JqZWN0cy4KICAgICAqIG15UGFyYW1ldGVyT3duZXJJdGVtLmFkZFBhcmFtZXRlcihtdWx0aUNob2ljZVBhcmFtZXRlcikKICAgICAqIGBgYAogICAgICogQGV4dGVuZHMgTnVtYmVyUGFyYW1ldGVyCiAgICAgKi8KICAgIGNsYXNzIE11bHRpQ2hvaWNlUGFyYW1ldGVyIGV4dGVuZHMgTnVtYmVyUGFyYW1ldGVyIHsKICAgICAgICBjaG9pY2VzOwogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZSBhIG11bHRpIGNob2ljZSBwYXJhbWV0ZXIuCiAgICAgICAgICogQHBhcmFtIG5hbWUgLSBUaGUgbmFtZSBvZiB0aGUgbXVsdGkgY2hvaWNlIHBhcmFtZXRlci4KICAgICAgICAgKiBAcGFyYW0gaW5kZXggLSBUaGUgaW5kZXggdmFsdWUuCiAgICAgICAgICogQHBhcmFtIGNob2ljZXMgLSBUaGUgY2hvaWNlcyB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBjb25zdHJ1Y3RvcihuYW1lLCBpbmRleCwgY2hvaWNlcyA9IFtdKSB7CiAgICAgICAgICAgIHN1cGVyKG5hbWUsIGluZGV4LCBbMCwgY2hvaWNlcy5sZW5ndGhdLCAxKTsKICAgICAgICAgICAgdGhpcy5jaG9pY2VzID0gY2hvaWNlczsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyBjaG9pY2VzIGFycmF5LgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgZ2V0Q2hvaWNlcygpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuY2hvaWNlczsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU2V0cyBwYXJhbWV0ZXIgaW5kZXggdmFsdWUuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gdmFsdWUgLSBUaGUgdmFsdWUgcGFyYW0uCiAgICAgICAgICovCiAgICAgICAgc2V0VmFsdWUodmFsdWUpIHsKICAgICAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycpIHsKICAgICAgICAgICAgICAgIGNvbnN0IGluZGV4ID0gdGhpcy5jaG9pY2VzLmluZGV4T2YodmFsdWUpOwogICAgICAgICAgICAgICAgaWYgKGluZGV4ID09PSAtMSkgewogICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoYEludmFsaWQgdmFsdWUgZm9yIE11bHRpQ2hvaWNlUGFyYW1ldGVyOiAke3ZhbHVlfS4gY2hvaWNlcyBhcmU6ICR7dGhpcy5jaG9pY2VzfS5gKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGVsc2UgewogICAgICAgICAgICAgICAgICAgIHN1cGVyLnNldFZhbHVlKGluZGV4KTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgIHN1cGVyLnNldFZhbHVlKHZhbHVlKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBjbG9uZSgpIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBNdWx0aUNob2ljZVBhcmFtZXRlcih0aGlzLm5hbWUsIHRoaXMudmFsdWUsIHRoaXMuY2hvaWNlcyk7CiAgICAgICAgfQogICAgfQogICAgUmVnaXN0cnkucmVnaXN0ZXIoJ011bHRpQ2hvaWNlUGFyYW1ldGVyJywgTXVsdGlDaG9pY2VQYXJhbWV0ZXIpOwoKICAgIC8qIGVzbGludC1kaXNhYmxlIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFycyAqLwogICAgLyoqCiAgICAgKiBSZXByZXNlbnRzIGEgc3BlY2lmaWMgdHlwZSBvZiBwYXJhbWV0ZXIsIHRoYXQgb25seSBzdG9yZXMgYGJvb2xlYW5gIHZhbHVlcy4KICAgICAqCiAgICAgKiBpLmUuOgogICAgICogYGBgamF2YXNjcmlwdAogICAgICogY29uc3QgYm9vbGVhblBhcmFtID0gbmV3IEJvb2xlYW5QYXJhbWV0ZXIoJ015Qm9vbGVhbicsIHRydWUpCiAgICAgKiAvLydteVBhcmFtZXRlck93bmVySXRlbScgaXMgYW4gaW5zdGFuY2Ugb2YgYSAnUGFyYW1ldGVyT3duZXInIGNsYXNzLgogICAgICogLy8gUmVtZW1iZXIgdGhhdCBvbmx5ICdQYXJhbWV0ZXJPd25lcicgYW5kIGNsYXNzZXMgdGhhdCBleHRlbmQgZnJvbSBpdCBjYW4gaG9zdCAnUGFyYW1ldGVyJyBvYmplY3RzLgogICAgICogbXlQYXJhbWV0ZXJPd25lckl0ZW0uYWRkUGFyYW1ldGVyKGJvb2xlYW5QYXJhbSkKICAgICAqIGBgYAogICAgICogQGV4dGVuZHMgUGFyYW1ldGVyCiAgICAgKi8KICAgIGNsYXNzIEJvb2xlYW5QYXJhbWV0ZXIgZXh0ZW5kcyBQYXJhbWV0ZXIgewogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgYSBuZXcgcGFyYW1ldGVyIHdpdGggYEJvb2xlYW5gIGRhdGEgdHlwZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBuYW1lIC0gVGhlIG5hbWUgb2YgdGhlIGJvb2xlYW4gcGFyYW1ldGVyLgogICAgICAgICAqIEBwYXJhbSB2YWx1ZSAtIFRoZSB2YWx1ZSBvZiB0aGUgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIGNvbnN0cnVjdG9yKG5hbWUgPSAnJywgdmFsdWUpIHsKICAgICAgICAgICAgc3VwZXIobmFtZSwgdmFsdWUgIT0gdW5kZWZpbmVkID8gdmFsdWUgOiBmYWxzZSwgJ0Jvb2xlYW4nKTsKICAgICAgICB9CiAgICAgICAgc2V0VmFsdWUodmFsdWUpIHsKICAgICAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSAhPSAnYm9vbGVhbicpIHsKICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgdmFsdWUgcHJvdmlkZWQgaXMgbm90IGEgYm9vbGVhbi4gQ2hlY2sgdGhlIHNvdXJjZSBvZiB0aGlzIHZhbHVlYCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgc3VwZXIuc2V0VmFsdWUodmFsdWUpOwogICAgICAgIH0KICAgICAgICAvLyAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCiAgICAgICAgLy8gUGVyc2lzdGVuY2UKICAgICAgICAvKioKICAgICAgICAgKiBMb2FkcyB0aGUgYm9vbGVhbiB2YWx1ZXMgZnJvbSB0aGUgYmluYXJ5IGJ1ZmZlci4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSByZWFkZXIgLSBUaGUgcmVhZGVyIHZhbHVlLgogICAgICAgICAqIEBwYXJhbSBjb250ZXh0IC0gVGhlIGNvbnRleHQgdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgcmVhZEJpbmFyeShyZWFkZXIsIGNvbnRleHQpIHsKICAgICAgICAgICAgdGhpcy52YWx1ZSA9IHJlYWRlci5sb2FkVUludDgoKSAhPSAwOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgdG9KU09OIG1ldGhvZCBzZXJpYWxpemVzIHRoaXMgaW5zdGFuY2UgYXMgYSBKU09OLgogICAgICAgICAqIEl0IGNhbiBiZSB1c2VkIGZvciBwZXJzaXN0ZW5jZSwgZGF0YSB0cmFuc2ZlciwgZXRjLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGNvbnRleHQgLSBUaGUgY29udGV4dCB2YWx1ZS4KICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyB0aGUganNvbiBvYmplY3QuCiAgICAgICAgICovCiAgICAgICAgdG9KU09OKGNvbnRleHQpIHsKICAgICAgICAgICAgcmV0dXJuIHsgdHlwZTogdGhpcy5nZXRDbGFzc05hbWUoKSwgbmFtZTogdGhpcy5uYW1lLCB2YWx1ZTogdGhpcy52YWx1ZSB9OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgZnJvbUpTT04gbWV0aG9kIHRha2VzIGEgSlNPTiBhbmQgZGVzZXJpYWxpemVzIGludG8gYW4gaW5zdGFuY2Ugb2YgdGhpcyB0eXBlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGogLSBUaGUganNvbiBvYmplY3QgdGhpcyBpdGVtIG11c3QgZGVjb2RlLgogICAgICAgICAqIEBwYXJhbSBjb250ZXh0IC0gVGhlIGNvbnRleHQgdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgZnJvbUpTT04oaiwgY29udGV4dCkgewogICAgICAgICAgICB0aGlzLnZhbHVlID0gai52YWx1ZTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGNsb25lIG1ldGhvZCBjb25zdHJ1Y3RzIGEgbmV3IHBhcmFtZXRlciwgY29waWVzIGl0cyB2YWx1ZXMKICAgICAgICAgKiBmcm9tIHRoaXMgcGFyYW1ldGVyIGFuZCByZXR1cm5zIGl0LgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgYSBuZXcgY2xvbmVkIHBhcmFtZXRlci4KICAgICAgICAgKi8KICAgICAgICBjbG9uZSgpIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBCb29sZWFuUGFyYW1ldGVyKHRoaXMubmFtZSwgdGhpcy52YWx1ZSk7CiAgICAgICAgfQogICAgfQogICAgUmVnaXN0cnkucmVnaXN0ZXIoJ0Jvb2xlYW5QYXJhbWV0ZXInLCBCb29sZWFuUGFyYW1ldGVyKTsKICAgIFJlZ2lzdHJ5LnJlZ2lzdGVyKCdQcm9wZXJ0eV9Cb29sZWFuJywgQm9vbGVhblBhcmFtZXRlcik7CgogICAgLyogZXNsaW50LWRpc2FibGUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWV4cGxpY2l0LWFueSAqLwogICAgLyoqCiAgICAgKiBSZXByZXNlbnRzIGEgc3BlY2lmaWMgdHlwZSBvZiBwYXJhbWV0ZXIsIHRoYXQgb25seSBzdG9yZXMgVmVjMih0d28tZGltZW5zaW9uYWwgY29vcmRpbmF0ZSkgdmFsdWVzLgogICAgICoKICAgICAqIGkuZS46CiAgICAgKiBgYGBqYXZhc2NyaXB0CiAgICAgKiBjb25zdCB2ZWMyUGFyYW0gPSBuZXcgVmVjMlBhcmFtZXRlcignTXlWZWMyJywgbmV3IFZlYzIoMS4yLCAzLjQpKQogICAgICogLy8nbXlQYXJhbWV0ZXJPd25lckl0ZW0nIGlzIGFuIGluc3RhbmNlIG9mIGEgJ1BhcmFtZXRlck93bmVyJyBjbGFzcy4KICAgICAqIC8vIFJlbWVtYmVyIHRoYXQgb25seSAnUGFyYW1ldGVyT3duZXInIGFuZCBjbGFzc2VzIHRoYXQgZXh0ZW5kIGZyb20gaXQgY2FuIGhvc3QgJ1BhcmFtZXRlcicgb2JqZWN0cy4KICAgICAqIG15UGFyYW1ldGVyT3duZXJJdGVtLmFkZFBhcmFtZXRlcih2ZWMyUGFyYW0pCiAgICAgKiBgYGAKICAgICAqCiAgICAgKiAqKkV2ZW50cyoqCiAgICAgKiAqICoqcmFuZ2VDaGFuZ2VkOioqIFRyaWdnZXJlZCB3aGVuIHJhZ2UgYXJyYXkgY2hhbmdlcy4KICAgICAqCiAgICAgKiBAZXh0ZW5kcyBQYXJhbWV0ZXIKICAgICAqLwogICAgY2xhc3MgVmVjMlBhcmFtZXRlciBleHRlbmRzIFBhcmFtZXRlciB7CiAgICAgICAgcmFuZ2U7CiAgICAgICAgLyoqCiAgICAgICAgICogQ3JlYXRlIGEgVmVjMiBwYXJhbWV0ZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gbmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBWZWMyIHBhcmFtZXRlci4KICAgICAgICAgKiBAcGFyYW0gdmFsdWUgLSBUaGUgdmFsdWUgb2YgdGhlIHBhcmFtZXRlci4KICAgICAgICAgKiBAcGFyYW0gcmFuZ2UgLSBUaGUgcmFuZ2UgdmFsdWUgaXMgYW4gYXJyYXkgb2YgdHdvIGBWZWMyYCBvYmplY3RzLgogICAgICAgICAqLwogICAgICAgIGNvbnN0cnVjdG9yKG5hbWUgPSAnJywgdmFsdWUsIHJhbmdlKSB7CiAgICAgICAgICAgIHN1cGVyKG5hbWUsIHZhbHVlID8gdmFsdWUgOiBuZXcgVmVjMigpLCAnVmVjMicpOwogICAgICAgICAgICB0aGlzLnJhbmdlID0gcmFuZ2U7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgdGhlIHJhbmdlIG9mIHZhbHVlcyBpbiB3aGljaCBjdXJyZW50IHBhcmFtZXRlciBjYW4gYmUuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBnZXRSYW5nZSgpIHsKICAgICAgICAgICAgLy8gUmFuZ2Ugc2hvdWxkIGJlIGFuIGFycmF5IG9mIDIgdmVjMnMuIFttaW4oeCx5KSwgbWF4KHgseSldCiAgICAgICAgICAgIHJldHVybiB0aGlzLnJhbmdlOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgX19zZXRSYW5nZSBtZXRob2QuCiAgICAgICAgICogQHBhcmFtIHJhbmdlIC0gVGhlIHJhbmdlIHZhbHVlLgogICAgICAgICAqIEBwcml2YXRlCiAgICAgICAgICovCiAgICAgICAgc2V0UmFuZ2UocmFuZ2UpIHsKICAgICAgICAgICAgLy8gU2hvdWxkIGJlIGFuIGFycmF5IFswLCAyMF0KICAgICAgICAgICAgdGhpcy5yYW5nZSA9IHJhbmdlOwogICAgICAgICAgICB0aGlzLmVtaXQoJ3JhbmdlQ2hhbmdlZCcsIHsgcmFuZ2UgfSk7CiAgICAgICAgfQogICAgICAgIHNldFZhbHVlKHZhbHVlKSB7CiAgICAgICAgICAgIGlmICghKHZhbHVlIGluc3RhbmNlb2YgVmVjMikpIHsKICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgdmFsdWUgcHJvdmlkZWQgaXMgbm90IGFuIGluc3RhbmNlIG9mIGEgJ1ZlYzInIGNsYXNzLiBDaGVjayB0aGUgc291cmNlIG9mIHRoaXMgdmFsdWVgKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBzdXBlci5zZXRWYWx1ZSh2YWx1ZSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEV4dHJhY3RzIGEgbnVtYmVyIHZhbHVlIGZyb20gYSBidWZmZXIsIHVwZGF0aW5nIGN1cnJlbnQgcGFyYW1ldGVyIHN0YXRlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHJlYWRlciAtIFRoZSByZWFkZXIgdmFsdWUuCiAgICAgICAgICogQHBhcmFtIGNvbnRleHQgLSBUaGUgY29udGV4dCB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICByZWFkQmluYXJ5KHJlYWRlciwgY29udGV4dCkgewogICAgICAgICAgICB0aGlzLnZhbHVlPy5yZWFkQmluYXJ5KHJlYWRlcik7CiAgICAgICAgfQogICAgICAgIHRvSlNPTihjb250ZXh0KSB7CiAgICAgICAgICAgIHJldHVybiB7CiAgICAgICAgICAgICAgICB0eXBlOiB0aGlzLmdldENsYXNzTmFtZSgpLAogICAgICAgICAgICAgICAgbmFtZTogdGhpcy5uYW1lLAogICAgICAgICAgICAgICAgdmFsdWU6IHRoaXMudmFsdWU/LnRvSlNPTigpLAogICAgICAgICAgICB9OwogICAgICAgIH0KICAgICAgICBmcm9tSlNPTihqLCBjb250ZXh0KSB7CiAgICAgICAgICAgIGNvbnN0IHZlYzIgPSBuZXcgVmVjMigpOwogICAgICAgICAgICB2ZWMyLmZyb21KU09OKGoudmFsdWUpOwogICAgICAgICAgICB0aGlzLnZhbHVlID0gdmVjMjsKICAgICAgICAgICAgaWYgKGoubmFtZSkKICAgICAgICAgICAgICAgIHRoaXMubmFtZSA9IGoubmFtZTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGNsb25lIG1ldGhvZCBjb25zdHJ1Y3RzIGEgbmV3IFZlYzIgcGFyYW1ldGVyLCBjb3BpZXMgaXRzIHZhbHVlcwogICAgICAgICAqIGZyb20gdGhpcyBwYXJhbWV0ZXIgYW5kIHJldHVybnMgaXQuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyBhIG5ldyBWZWMyIHBhcmFtZXRlci4KICAgICAgICAgKi8KICAgICAgICBjbG9uZSgpIHsKICAgICAgICAgICAgY29uc3QgY2xvbmVkUGFyYW0gPSBuZXcgVmVjMlBhcmFtZXRlcih0aGlzLm5hbWUsIHRoaXMudmFsdWU/LmNsb25lKCkpOwogICAgICAgICAgICBpZiAodGhpcy5yYW5nZSkKICAgICAgICAgICAgICAgIGNsb25lZFBhcmFtLnNldFJhbmdlKHRoaXMucmFuZ2UpOwogICAgICAgICAgICByZXR1cm4gY2xvbmVkUGFyYW07CiAgICAgICAgfQogICAgfQogICAgUmVnaXN0cnkucmVnaXN0ZXIoJ1ZlYzJQYXJhbWV0ZXInLCBWZWMyUGFyYW1ldGVyKTsKICAgIFJlZ2lzdHJ5LnJlZ2lzdGVyKCdQcm9wZXJ0eV9WZWMyXzMyZicsIFZlYzJQYXJhbWV0ZXIpOwoKICAgIC8qIGVzbGludC1kaXNhYmxlIEB0eXBlc2NyaXB0LWVzbGludC9uby1leHBsaWNpdC1hbnkgKi8KICAgIC8qKgogICAgICogUmVwcmVzZW50cyBhIHNwZWNpZmljIHR5cGUgb2YgcGFyYW1ldGVyLCB0aGF0IG9ubHkgc3RvcmVzIFZlYzModGhyZWUtZGltZW5zaW9uYWwgY29vcmRpbmF0ZSkgdmFsdWVzLgogICAgICoKICAgICAqIGkuZS46CiAgICAgKiBgYGBqYXZhc2NyaXB0CiAgICAgKiBjb25zdCB2ZWMzUGFyYW0gPSBuZXcgVmVjM1BhcmFtZXRlcignTXlWZWMzJywgbmV3IFZlYzMoMS4yLCAzLjQsIDEpKQogICAgICogLy8nbXlQYXJhbWV0ZXJPd25lckl0ZW0nIGlzIGFuIGluc3RhbmNlIG9mIGEgJ1BhcmFtZXRlck93bmVyJyBjbGFzcy4KICAgICAqIC8vIFJlbWVtYmVyIHRoYXQgb25seSAnUGFyYW1ldGVyT3duZXInIGFuZCBjbGFzc2VzIHRoYXQgZXh0ZW5kIGZyb20gaXQgY2FuIGhvc3QgJ1BhcmFtZXRlcicgb2JqZWN0cy4KICAgICAqIG15UGFyYW1ldGVyT3duZXJJdGVtLmFkZFBhcmFtZXRlcih2ZWMzUGFyYW0pCiAgICAgKiBgYGAKICAgICAqIEBleHRlbmRzIFBhcmFtZXRlcgogICAgICovCiAgICBjbGFzcyBWZWMzUGFyYW1ldGVyIGV4dGVuZHMgUGFyYW1ldGVyIHsKICAgICAgICByYW5nZTsKICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGUgYSBWZWMzIHBhcmFtZXRlci4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBuYW1lIC0gVGhlIG5hbWUgb2YgdGhlIFZlYzMgcGFyYW1ldGVyLgogICAgICAgICAqIEBwYXJhbSB2YWx1ZSAtIFRoZSB2YWx1ZSBvZiB0aGUgcGFyYW1ldGVyLgogICAgICAgICAqIEBwYXJhbSByYW5nZSAtIFRoZSByYW5nZSB2YWx1ZSBpcyBhbiBhcnJheSBvZiB0d28gYFZlYzNgIG9iamVjdHMuCiAgICAgICAgICovCiAgICAgICAgY29uc3RydWN0b3IobmFtZSA9ICcnLCB2YWx1ZSwgcmFuZ2UpIHsKICAgICAgICAgICAgc3VwZXIobmFtZSwgdmFsdWUgPyB2YWx1ZSA6IG5ldyBWZWMzKCksICdWZWMzJyk7CiAgICAgICAgICAgIHRoaXMucmFuZ2UgPSByYW5nZTsKICAgICAgICB9CiAgICAgICAgc2V0VmFsdWUodmFsdWUpIHsKICAgICAgICAgICAgaWYgKCEodmFsdWUgaW5zdGFuY2VvZiBWZWMzKSkgewogICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGB2YWx1ZSBwcm92aWRlZCBpcyBub3QgYW4gaW5zdGFuY2Ugb2YgYSAnVmVjMicgY2xhc3MuIENoZWNrIHRoZSBzb3VyY2Ugb2YgdGhpcyB2YWx1ZWApOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHN1cGVyLnNldFZhbHVlKHZhbHVlKTsKICAgICAgICB9CiAgICAgICAgLy8gLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwogICAgICAgIC8vIFBlcnNpc3RlbmNlCiAgICAgICAgLyoqCiAgICAgICAgICogRXh0cmFjdHMgYSBudW1iZXIgdmFsdWUgZnJvbSBhIGJ1ZmZlciwgdXBkYXRpbmcgY3VycmVudCBwYXJhbWV0ZXIgc3RhdGUuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gcmVhZGVyIC0gVGhlIHJlYWRlciB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0gY29udGV4dCAtIFRoZSBjb250ZXh0IHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHJlYWRCaW5hcnkocmVhZGVyLCBjb250ZXh0KSB7CiAgICAgICAgICAgIHRoaXMudmFsdWU/LnJlYWRCaW5hcnkocmVhZGVyKTsKICAgICAgICB9CiAgICAgICAgdG9KU09OKGNvbnRleHQpIHsKICAgICAgICAgICAgcmV0dXJuIHsKICAgICAgICAgICAgICAgIHR5cGU6IHRoaXMuZ2V0Q2xhc3NOYW1lKCksCiAgICAgICAgICAgICAgICBuYW1lOiB0aGlzLm5hbWUsCiAgICAgICAgICAgICAgICB2YWx1ZTogdGhpcy52YWx1ZT8udG9KU09OKCksCiAgICAgICAgICAgIH07CiAgICAgICAgfQogICAgICAgIGZyb21KU09OKGosIGNvbnRleHQpIHsKICAgICAgICAgICAgY29uc3QgdmVjNCA9IG5ldyBWZWMzKCk7CiAgICAgICAgICAgIHZlYzQuZnJvbUpTT04oai52YWx1ZSk7CiAgICAgICAgICAgIHRoaXMudmFsdWUgPSB2ZWM0OwogICAgICAgICAgICBpZiAoai5uYW1lKQogICAgICAgICAgICAgICAgdGhpcy5uYW1lID0gai5uYW1lOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgY2xvbmUgbWV0aG9kIGNvbnN0cnVjdHMgYSBuZXcgVmVjMyBwYXJhbWV0ZXIsIGNvcGllcyBpdHMgdmFsdWVzCiAgICAgICAgICogZnJvbSB0aGlzIHBhcmFtZXRlciBhbmQgcmV0dXJucyBpdC4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGEgbmV3IFZlYzMgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIGNsb25lKCkgewogICAgICAgICAgICBjb25zdCBjbG9uZWRQYXJhbSA9IG5ldyBWZWMzUGFyYW1ldGVyKHRoaXMubmFtZSwgdGhpcy52YWx1ZT8uY2xvbmUoKSk7CiAgICAgICAgICAgIHJldHVybiBjbG9uZWRQYXJhbTsKICAgICAgICB9CiAgICB9CiAgICBSZWdpc3RyeS5yZWdpc3RlcignVmVjM1BhcmFtZXRlcicsIFZlYzNQYXJhbWV0ZXIpOwogICAgUmVnaXN0cnkucmVnaXN0ZXIoJ1Byb3BlcnR5X1ZlYzNfMzJmJywgVmVjM1BhcmFtZXRlcik7CgogICAgLyogZXNsaW50LWRpc2FibGUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWV4cGxpY2l0LWFueSAqLwogICAgLyoqCiAgICAgKiBSZXByZXNlbnRzIGEgc3BlY2lmaWMgdHlwZSBvZiBwYXJhbWV0ZXIsIHRoYXQgb25seSBzdG9yZXMgVmVjNChmb3VyLWRpbWVuc2lvbmFsIGNvb3JkaW5hdGUpIHZhbHVlcy4KICAgICAqCiAgICAgKiBpLmUuOgogICAgICogYGBgamF2YXNjcmlwdAogICAgICogY29uc3QgdmVjNFBhcmFtID0gbmV3IFZlYzRQYXJhbWV0ZXIoJ015VmVjNCcsIG5ldyBWZWM0KDEuMiwgMy40LCAxLCA0LjIpKQogICAgICogLy8nbXlQYXJhbWV0ZXJPd25lckl0ZW0nIGlzIGFuIGluc3RhbmNlIG9mIGEgJ1BhcmFtZXRlck93bmVyJyBjbGFzcy4KICAgICAqIC8vIFJlbWVtYmVyIHRoYXQgb25seSAnUGFyYW1ldGVyT3duZXInIGFuZCBjbGFzc2VzIHRoYXQgZXh0ZW5kIGZyb20gaXQgY2FuIGhvc3QgJ1BhcmFtZXRlcicgb2JqZWN0cy4KICAgICAqIG15UGFyYW1ldGVyT3duZXJJdGVtLmFkZFBhcmFtZXRlcih2ZWM0UGFyYW0pCiAgICAgKiBgYGAKICAgICAqCiAgICAgKiBAZXh0ZW5kcyBQYXJhbWV0ZXIKICAgICAqLwogICAgY2xhc3MgVmVjNFBhcmFtZXRlciBleHRlbmRzIFBhcmFtZXRlciB7CiAgICAgICAgLyoqCiAgICAgICAgICogQ3JlYXRlIGEgVmVjNCBwYXJhbWV0ZXIuCiAgICAgICAgICogQHBhcmFtIG5hbWUgLSBUaGUgbmFtZSBvZiB0aGUgVmVjNCBwYXJhbWV0ZXIuCiAgICAgICAgICogQHBhcmFtIHZhbHVlIC0gVGhlIHZhbHVlIG9mIHRoZSBwYXJhbWV0ZXIuCiAgICAgICAgICovCiAgICAgICAgY29uc3RydWN0b3IobmFtZSA9ICcnLCB2YWx1ZSkgewogICAgICAgICAgICBzdXBlcihuYW1lLCB2YWx1ZSA/IHZhbHVlIDogbmV3IFZlYzQoKSwgJ1ZlYzQnKTsKICAgICAgICB9CiAgICAgICAgc2V0VmFsdWUodmFsdWUpIHsKICAgICAgICAgICAgaWYgKCEodmFsdWUgaW5zdGFuY2VvZiBWZWM0KSkgewogICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGB2YWx1ZSBwcm92aWRlZCBpcyBub3QgYW4gaW5zdGFuY2Ugb2YgYSAnVmVjNCcgY2xhc3MuIENoZWNrIHRoZSBzb3VyY2Ugb2YgdGhpcyB2YWx1ZWApOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHN1cGVyLnNldFZhbHVlKHZhbHVlKTsKICAgICAgICB9CiAgICAgICAgLy8gLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwogICAgICAgIC8vIFBlcnNpc3RlbmNlCiAgICAgICAgLyoqCiAgICAgICAgICogRXh0cmFjdHMgYSBudW1iZXIgdmFsdWUgZnJvbSBhIGJ1ZmZlciwgdXBkYXRpbmcgY3VycmVudCBwYXJhbWV0ZXIgc3RhdGUuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gcmVhZGVyIC0gVGhlIHJlYWRlciB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0gY29udGV4dCAtIFRoZSBjb250ZXh0IHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHJlYWRCaW5hcnkocmVhZGVyLCBjb250ZXh0KSB7CiAgICAgICAgICAgIHRoaXMudmFsdWU/LnJlYWRCaW5hcnkocmVhZGVyKTsKICAgICAgICB9CiAgICAgICAgdG9KU09OKGNvbnRleHQpIHsKICAgICAgICAgICAgcmV0dXJuIHsgdHlwZTogdGhpcy5nZXRDbGFzc05hbWUoKSwgbmFtZTogdGhpcy5uYW1lLCB2YWx1ZTogdGhpcy52YWx1ZT8udG9KU09OKCkgfTsKICAgICAgICB9CiAgICAgICAgZnJvbUpTT04oaiwgY29udGV4dCkgewogICAgICAgICAgICBjb25zdCB2ZWM0ID0gbmV3IFZlYzQoKTsKICAgICAgICAgICAgdmVjNC5mcm9tSlNPTihqLnZhbHVlKTsKICAgICAgICAgICAgdGhpcy52YWx1ZSA9IHZlYzQ7CiAgICAgICAgICAgIGlmIChqLm5hbWUpCiAgICAgICAgICAgICAgICB0aGlzLm5hbWUgPSBqLm5hbWU7CiAgICAgICAgfQogICAgICAgIC8vIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KICAgICAgICAvLyBDbG9uZQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBjbG9uZSBtZXRob2QgY29uc3RydWN0cyBhIG5ldyBWZWM0IHBhcmFtZXRlciwgY29waWVzIGl0cyB2YWx1ZXMKICAgICAgICAgKiBmcm9tIHRoaXMgcGFyYW1ldGVyIGFuZCByZXR1cm5zIGl0LgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgYSBuZXcgVmVjNCBwYXJhbWV0ZXIuCiAgICAgICAgICovCiAgICAgICAgY2xvbmUoKSB7CiAgICAgICAgICAgIGNvbnN0IGNsb25lZFBhcmFtID0gbmV3IFZlYzRQYXJhbWV0ZXIodGhpcy5uYW1lLCB0aGlzLnZhbHVlPy5jbG9uZSgpKTsKICAgICAgICAgICAgcmV0dXJuIGNsb25lZFBhcmFtOwogICAgICAgIH0KICAgIH0KICAgIFJlZ2lzdHJ5LnJlZ2lzdGVyKCdWZWM0UGFyYW1ldGVyJywgVmVjNFBhcmFtZXRlcik7CiAgICBSZWdpc3RyeS5yZWdpc3RlcignUHJvcGVydHlfVmVjNF8zMmYnLCBWZWM0UGFyYW1ldGVyKTsKCiAgICAvKiBlc2xpbnQtZGlzYWJsZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnMgKi8KICAgIC8qKgogICAgICogQGV4dGVuZHMgUGFyYW1ldGVyCiAgICAgKi8KICAgIGNsYXNzIEJveDJQYXJhbWV0ZXIgZXh0ZW5kcyBQYXJhbWV0ZXIgewogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZSBhIEJveDIgcGFyYW1ldGVyLgogICAgICAgICAqIEBwYXJhbSBuYW1lIC0gVGhlIG5hbWUgb2YgdGhlIEJveDIgcGFyYW1ldGVyLgogICAgICAgICAqIEBwYXJhbSB2YWx1ZSAtIFRoZSB2YWx1ZSBvZiB0aGUgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIGNvbnN0cnVjdG9yKG5hbWUgPSAnJywgdmFsdWUpIHsKICAgICAgICAgICAgc3VwZXIobmFtZSwgdmFsdWUgPyB2YWx1ZSA6IG5ldyBCb3gyKCksICdCb3gyJyk7CiAgICAgICAgfQogICAgICAgIHNldFZhbHVlKHZhbHVlKSB7CiAgICAgICAgICAgIGlmICghKHZhbHVlIGluc3RhbmNlb2YgQm94MikpIHsKICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgdmFsdWUgcHJvdmlkZWQgaXMgbm90IGFuIGluc3RhbmNlIG9mIGEgJ0JveDInIGNsYXNzLiBDaGVjayB0aGUgc291cmNlIG9mIHRoaXMgdmFsdWVgKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBzdXBlci5zZXRWYWx1ZSh2YWx1ZSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEV4dHJhY3RzIGEgbnVtYmVyIHZhbHVlIGZyb20gYSBidWZmZXIsIHVwZGF0aW5nIGN1cnJlbnQgcGFyYW1ldGVyIHN0YXRlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHJlYWRlciAtIFRoZSByZWFkZXIgdmFsdWUuCiAgICAgICAgICogQHBhcmFtIGNvbnRleHQgLSBUaGUgY29udGV4dCB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICByZWFkQmluYXJ5KHJlYWRlciwgY29udGV4dCkgewogICAgICAgICAgICB0aGlzLnZhbHVlLnAwLnJlYWRCaW5hcnkocmVhZGVyKTsKICAgICAgICAgICAgdGhpcy52YWx1ZS5wMS5yZWFkQmluYXJ5KHJlYWRlcik7CiAgICAgICAgfQogICAgICAgIHRvSlNPTihjb250ZXh0KSB7CiAgICAgICAgICAgIHJldHVybiB7CiAgICAgICAgICAgICAgICB0eXBlOiB0aGlzLmdldENsYXNzTmFtZSgpLAogICAgICAgICAgICAgICAgbmFtZTogdGhpcy5uYW1lLAogICAgICAgICAgICAgICAgdmFsdWU6IHsKICAgICAgICAgICAgICAgICAgICBwMDogdGhpcy52YWx1ZS5wMC50b0pTT04oKSwKICAgICAgICAgICAgICAgICAgICBwMTogdGhpcy52YWx1ZS5wMS50b0pTT04oKSwKICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgIH07CiAgICAgICAgfQogICAgICAgIGZyb21KU09OKGosIGNvbnRleHQpIHsKICAgICAgICAgICAgdGhpcy52YWx1ZS5wMC5mcm9tSlNPTihqLnAwKTsKICAgICAgICAgICAgdGhpcy52YWx1ZS5wMS5mcm9tSlNPTihqLnAxKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGNsb25lIG1ldGhvZCBjb25zdHJ1Y3RzIGEgbmV3IEJveDIgcGFyYW1ldGVyLAogICAgICAgICAqIGNvcGllcyBpdHMgdmFsdWVzIGZyb20gdGhpcyBwYXJhbWV0ZXIgYW5kIHJldHVybnMgaXQuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyBhIG5ldyBjbG9uZWQgQm94MiBwYXJhbWV0ZXIuCiAgICAgICAgICovCiAgICAgICAgY2xvbmUoKSB7CiAgICAgICAgICAgIGNvbnN0IGNsb25lZFBhcmFtID0gbmV3IEJveDJQYXJhbWV0ZXIodGhpcy5uYW1lLCB0aGlzLnZhbHVlPy5jbG9uZSgpKTsKICAgICAgICAgICAgcmV0dXJuIGNsb25lZFBhcmFtOwogICAgICAgIH0KICAgIH0KICAgIFJlZ2lzdHJ5LnJlZ2lzdGVyKCdCb3gyUGFyYW1ldGVyJywgQm94MlBhcmFtZXRlcik7CiAgICBSZWdpc3RyeS5yZWdpc3RlcignUHJvcGVydHlfQm94Ml8zMmYnLCBCb3gyUGFyYW1ldGVyKTsKCiAgICAvKiBlc2xpbnQtZGlzYWJsZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnMgKi8KICAgIC8qKgogICAgICogQGV4dGVuZHMgUGFyYW1ldGVyCiAgICAgKi8KICAgIGNsYXNzIEJveDNQYXJhbWV0ZXIgZXh0ZW5kcyBQYXJhbWV0ZXIgewogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZSBhIEJveDMgcGFyYW1ldGVyLgogICAgICAgICAqIEBwYXJhbSBuYW1lIC0gVGhlIG5hbWUgb2YgdGhlIEJveDMgcGFyYW1ldGVyLgogICAgICAgICAqIEBwYXJhbSB2YWx1ZSAtIFRoZSB2YWx1ZSBvZiB0aGUgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIGNvbnN0cnVjdG9yKG5hbWUgPSAnJywgdmFsdWUpIHsKICAgICAgICAgICAgc3VwZXIobmFtZSwgdmFsdWUgPyB2YWx1ZSA6IG5ldyBCb3gzKCksICdCb3gzJyk7CiAgICAgICAgfQogICAgICAgIHNldFZhbHVlKHZhbHVlKSB7CiAgICAgICAgICAgIGlmICghKHZhbHVlIGluc3RhbmNlb2YgQm94MykpIHsKICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgdmFsdWUgcHJvdmlkZWQgaXMgbm90IGFuIGluc3RhbmNlIG9mIGEgJ0JveDMnIGNsYXNzLiBDaGVjayB0aGUgc291cmNlIG9mIHRoaXMgdmFsdWVgKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBzdXBlci5zZXRWYWx1ZSh2YWx1ZSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEV4dHJhY3RzIGEgbnVtYmVyIHZhbHVlIGZyb20gYSBidWZmZXIsIHVwZGF0aW5nIGN1cnJlbnQgcGFyYW1ldGVyIHN0YXRlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHJlYWRlciAtIFRoZSByZWFkZXIgdmFsdWUuCiAgICAgICAgICogQHBhcmFtIGNvbnRleHQgLSBUaGUgY29udGV4dCB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICByZWFkQmluYXJ5KHJlYWRlciwgY29udGV4dCkgewogICAgICAgICAgICB0aGlzLnZhbHVlLnAwLnJlYWRCaW5hcnkocmVhZGVyKTsKICAgICAgICAgICAgdGhpcy52YWx1ZS5wMS5yZWFkQmluYXJ5KHJlYWRlcik7CiAgICAgICAgfQogICAgICAgIHRvSlNPTihjb250ZXh0KSB7CiAgICAgICAgICAgIHJldHVybiB7CiAgICAgICAgICAgICAgICB0eXBlOiB0aGlzLmdldENsYXNzTmFtZSgpLAogICAgICAgICAgICAgICAgbmFtZTogdGhpcy5uYW1lLAogICAgICAgICAgICAgICAgdmFsdWU6IHRoaXMudmFsdWUudG9KU09OKCksCiAgICAgICAgICAgIH07CiAgICAgICAgfQogICAgICAgIGZyb21KU09OKGosIGNvbnRleHQpIHsKICAgICAgICAgICAgaWYgKGoudmFsdWUpIHsKICAgICAgICAgICAgICAgIC8vIEB0cy1pZ25vcmUKICAgICAgICAgICAgICAgIHRoaXMudmFsdWUuZnJvbUpTT04oai52YWx1ZSk7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGNsb25lIG1ldGhvZCBjb25zdHJ1Y3RzIGEgbmV3IEJveDMgcGFyYW1ldGVyLAogICAgICAgICAqIGNvcGllcyBpdHMgdmFsdWVzIGZyb20gdGhpcyBwYXJhbWV0ZXIgYW5kIHJldHVybnMgaXQuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyBhIG5ldyBjbG9uZWQgQm94MyBwYXJhbWV0ZXIuCiAgICAgICAgICovCiAgICAgICAgY2xvbmUoKSB7CiAgICAgICAgICAgIGNvbnN0IGNsb25lZFBhcmFtID0gbmV3IEJveDNQYXJhbWV0ZXIodGhpcy5uYW1lLCB0aGlzLnZhbHVlPy5jbG9uZSgpKTsKICAgICAgICAgICAgcmV0dXJuIGNsb25lZFBhcmFtOwogICAgICAgIH0KICAgIH0KICAgIFJlZ2lzdHJ5LnJlZ2lzdGVyKCdCb3gzUGFyYW1ldGVyJywgQm94M1BhcmFtZXRlcik7CiAgICBSZWdpc3RyeS5yZWdpc3RlcignUHJvcGVydHlfQm94M18zMmYnLCBCb3gzUGFyYW1ldGVyKTsKCiAgICAvKiBlc2xpbnQtZGlzYWJsZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tZXhwbGljaXQtYW55ICovCiAgICAvKioKICAgICAqIFJlcHJlc2VudHMgYSBzcGVjaWZpYyB0eXBlIG9mIHBhcmFtZXRlciwgdGhhdCBvbmx5IHN0b3JlcyBgQ29sb3JgIHZhbHVlcy4KICAgICAqCiAgICAgKiBpLmUuOgogICAgICogYGBgamF2YXNjcmlwdAogICAgICogY29uc3QgY29sb3JQYXJhbSA9IG5ldyBDb2xvclBhcmFtZXRlcignTXlDb2xvcicsIG5ldyBDb2xvcigwLCAyNTQsIDIpKQogICAgICogLy8nbXlQYXJhbWV0ZXJPd25lckl0ZW0nIGlzIGFuIGluc3RhbmNlIG9mIGEgJ1BhcmFtZXRlck93bmVyJyBjbGFzcy4KICAgICAqIC8vIFJlbWVtYmVyIHRoYXQgb25seSAnUGFyYW1ldGVyT3duZXInIGFuZCBjbGFzc2VzIHRoYXQgZXh0ZW5kIGZyb20gaXQgY2FuIGhvc3QgJ1BhcmFtZXRlcicgb2JqZWN0cy4KICAgICAqIG15UGFyYW1ldGVyT3duZXJJdGVtLmFkZFBhcmFtZXRlcihjb2xvclBhcmFtKQogICAgICogYGBgCiAgICAgKgogICAgICogQGV4dGVuZHMgUGFyYW1ldGVyCiAgICAgKi8KICAgIGNsYXNzIENvbG9yUGFyYW1ldGVyIGV4dGVuZHMgUGFyYW1ldGVyIHsKICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGUgYSBjb2xvciBwYXJhbWV0ZXIuCiAgICAgICAgICogQHBhcmFtIG5hbWUgLSBUaGUgbmFtZSBvZiB0aGUgY29sb3IgcGFyYW1ldGVyLgogICAgICAgICAqIEBwYXJhbSB2YWx1ZSAtIFRoZSB2YWx1ZSBvZiB0aGUgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIGNvbnN0cnVjdG9yKG5hbWUgPSAnJywgdmFsdWUpIHsKICAgICAgICAgICAgc3VwZXIobmFtZSwgdmFsdWUgPyB2YWx1ZSA6IG5ldyBDb2xvcigpLCAnQ29sb3InKTsKICAgICAgICB9CiAgICAgICAgc2V0VmFsdWUodmFsdWUpIHsKICAgICAgICAgICAgaWYgKCEodmFsdWUgaW5zdGFuY2VvZiBDb2xvcikpIHsKICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgdmFsdWUgcHJvdmlkZWQgaXMgbm90IGFuIGluc3RhbmNlIG9mIGEgJ0NvbG9yJyBjbGFzcy4gQ2hlY2sgdGhlIHNvdXJjZSBvZiB0aGlzIHZhbHVlYCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgc3VwZXIuc2V0VmFsdWUodmFsdWUpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBFeHRyYWN0cyBgQ29sb3JgIHZhbHVlcyBmcm9tIGEgYnVmZmVyLCB1cGRhdGluZyBjdXJyZW50IHBhcmFtZXRlciBzdGF0ZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSByZWFkZXIgLSBUaGUgcmVhZGVyIHZhbHVlLgogICAgICAgICAqIEBwYXJhbSBjb250ZXh0IC0gVGhlIGNvbnRleHQgdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgcmVhZEJpbmFyeShyZWFkZXIsIGNvbnRleHQpIHsKICAgICAgICAgICAgY29uc3QgdmFsdWUgPSByZWFkZXIubG9hZFJHQkFGbG9hdDMyQ29sb3IoKTsKICAgICAgICAgICAgLy8gSWYgdGhlIHZhbHVlIGlzIGluIGxpbmVhciBzcGFjZSwgdGhlbiB3ZSBzaG91bGQgY29udmVydCBpdCB0byBnYW1tYSBzcGFjZS4KICAgICAgICAgICAgLy8gTm90ZTogISEgdGhpcyBzaG91bGQgYWx3YXlzIGJlIGRvbmUgaW4gcHJlcHJvY2Vzc2luZy4uLgogICAgICAgICAgICB2YWx1ZS5hcHBseUdhbW1hKDIuMik7CiAgICAgICAgICAgIHRoaXMudmFsdWUgPSB2YWx1ZTsKICAgICAgICB9CiAgICAgICAgdG9KU09OKGNvbnRleHQpIHsKICAgICAgICAgICAgcmV0dXJuIHsKICAgICAgICAgICAgICAgIHR5cGU6IHRoaXMuZ2V0Q2xhc3NOYW1lKCksCiAgICAgICAgICAgICAgICBuYW1lOiB0aGlzLm5hbWUsCiAgICAgICAgICAgICAgICB2YWx1ZTogdGhpcy52YWx1ZT8udG9KU09OKCksCiAgICAgICAgICAgIH07CiAgICAgICAgfQogICAgICAgIGZyb21KU09OKGosIGNvbnRleHQpIHsKICAgICAgICAgICAgLy8gaWYgKGoudmFsdWUudHlwZSkgdGhpcy52YWx1ZSA9IFJlZ2lzdHJ5LmNvbnN0cnVjdENsYXNzKCdDb2xvcicpIGFzIENvbG9yIC8vIFRPRE86IGNvbW1lbnRlZCBvdXQgUmVnaXN0cnkuY29uc3RydWN0Q2xhc3MKICAgICAgICAgICAgdGhpcy52YWx1ZT8uZnJvbUpTT04oai52YWx1ZSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBjbG9uZSBtZXRob2QgY29uc3RydWN0cyBhIG5ldyBjb2xvciBwYXJhbWV0ZXIsCiAgICAgICAgICogY29waWVzIGl0cyB2YWx1ZXMgZnJvbSB0aGlzIHBhcmFtZXRlciBhbmQgcmV0dXJucyBpdC4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGEgbmV3IGNsb25lZCBjb2xvciBwYXJhbWV0ZXIuCiAgICAgICAgICovCiAgICAgICAgY2xvbmUoKSB7CiAgICAgICAgICAgIGNvbnN0IGNsb25lZFBhcmFtID0gbmV3IENvbG9yUGFyYW1ldGVyKHRoaXMubmFtZSwgdGhpcy52YWx1ZT8uY2xvbmUoKSk7CiAgICAgICAgICAgIHJldHVybiBjbG9uZWRQYXJhbTsKICAgICAgICB9CiAgICB9CiAgICBSZWdpc3RyeS5yZWdpc3RlcignQ29sb3JQYXJhbWV0ZXInLCBDb2xvclBhcmFtZXRlcik7CiAgICBSZWdpc3RyeS5yZWdpc3RlcignUHJvcGVydHlfQ29sb3JfMzJmJywgQ29sb3JQYXJhbWV0ZXIpOwoKICAgIC8qIGVzbGludC1kaXNhYmxlIEB0eXBlc2NyaXB0LWVzbGludC9uby1leHBsaWNpdC1hbnkgKi8KICAgIC8qKgogICAgICogUmVwcmVzZW50cyBhIHNwZWNpZmljIHR5cGUgb2YgcGFyYW1ldGVyLCB0aGF0IG9ubHkgc3RvcmVzIFZlYzMoZm91ci1kaW1lbnNpb25hbCBjb29yZGluYXRlKSB2YWx1ZXMuCiAgICAgKgogICAgICogaS5lLjoKICAgICAqIGBgYGphdmFzY3JpcHQKICAgICAqIGNvbnN0IHF1YXRQYXJhbSA9IG5ldyBRdWF0UGFyYW1ldGVyKCdNeVF1YXQnLCBuZXcgUXVhdCgxLjIsIDMuNCwgMSwgNC4yKSkKICAgICAqIC8vJ215UGFyYW1ldGVyT3duZXJJdGVtJyBpcyBhbiBpbnN0YW5jZSBvZiBhICdQYXJhbWV0ZXJPd25lcicgY2xhc3MuCiAgICAgKiAvLyBSZW1lbWJlciB0aGF0IG9ubHkgJ1BhcmFtZXRlck93bmVyJyBhbmQgY2xhc3NlcyB0aGF0IGV4dGVuZCBmcm9tIGl0IGNhbiBob3N0ICdQYXJhbWV0ZXInIG9iamVjdHMuCiAgICAgKiBteVBhcmFtZXRlck93bmVySXRlbS5hZGRQYXJhbWV0ZXIocXVhdFBhcmFtKQogICAgICogYGBgCiAgICAgKgogICAgICogQGV4dGVuZHMgUGFyYW1ldGVyCiAgICAgKi8KICAgIGNsYXNzIFF1YXRQYXJhbWV0ZXIgZXh0ZW5kcyBQYXJhbWV0ZXIgewogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZSBhIFF1YXQgcGFyYW1ldGVyLgogICAgICAgICAqIEBwYXJhbSBuYW1lIC0gVGhlIG5hbWUgb2YgdGhlIFF1YXQgcGFyYW1ldGVyLgogICAgICAgICAqIEBwYXJhbSB2YWx1ZSAtIFRoZSB2YWx1ZSBvZiB0aGUgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIGNvbnN0cnVjdG9yKG5hbWUgPSAnJywgdmFsdWUpIHsKICAgICAgICAgICAgc3VwZXIobmFtZSwgdmFsdWUgPyB2YWx1ZSA6IG5ldyBRdWF0KCksICdRdWF0Jyk7CiAgICAgICAgfQogICAgICAgIHNldFZhbHVlKHZhbHVlKSB7CiAgICAgICAgICAgIGlmICghKHZhbHVlIGluc3RhbmNlb2YgUXVhdCkpIHsKICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgdmFsdWUgcHJvdmlkZWQgaXMgbm90IGFuIGluc3RhbmNlIG9mIGEgJ1F1YXQnIGNsYXNzLiBDaGVjayB0aGUgc291cmNlIG9mIHRoaXMgdmFsdWVgKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBzdXBlci5zZXRWYWx1ZSh2YWx1ZSk7CiAgICAgICAgfQogICAgICAgIC8vIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KICAgICAgICAvLyBQZXJzaXN0ZW5jZQogICAgICAgIC8qKgogICAgICAgICAqIEV4dHJhY3RzIGEgbnVtYmVyIHZhbHVlIGZyb20gYSBidWZmZXIsIHVwZGF0aW5nIGN1cnJlbnQgcGFyYW1ldGVyIHN0YXRlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHJlYWRlciAtIFRoZSByZWFkZXIgdmFsdWUuCiAgICAgICAgICogQHBhcmFtIGNvbnRleHQgLSBUaGUgY29udGV4dCB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICByZWFkQmluYXJ5KHJlYWRlciwgY29udGV4dCkgewogICAgICAgICAgICB0aGlzLnZhbHVlPy5yZWFkQmluYXJ5KHJlYWRlcik7CiAgICAgICAgfQogICAgICAgIHRvSlNPTihjb250ZXh0KSB7CiAgICAgICAgICAgIHJldHVybiB7CiAgICAgICAgICAgICAgICB0eXBlOiB0aGlzLmdldENsYXNzTmFtZSgpLAogICAgICAgICAgICAgICAgbmFtZTogdGhpcy5uYW1lLAogICAgICAgICAgICAgICAgdmFsdWU6IHRoaXMudmFsdWU/LnRvSlNPTigpLAogICAgICAgICAgICB9OwogICAgICAgIH0KICAgICAgICBmcm9tSlNPTihqLCBjb250ZXh0KSB7CiAgICAgICAgICAgIGNvbnN0IHF1YXQgPSBuZXcgUXVhdCgpOwogICAgICAgICAgICBxdWF0LmZyb21KU09OKGoudmFsdWUpOwogICAgICAgICAgICB0aGlzLnZhbHVlID0gcXVhdDsKICAgICAgICB9CiAgICAgICAgLy8gLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwogICAgICAgIC8vIENsb25lCiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGNsb25lIG1ldGhvZCBjb25zdHJ1Y3RzIGEgbmV3IFF1YXQgcGFyYW1ldGVyLCBjb3BpZXMgaXRzIHZhbHVlcwogICAgICAgICAqIGZyb20gdGhpcyBwYXJhbWV0ZXIgYW5kIHJldHVybnMgaXQuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyBhIG5ldyBRdWF0IHBhcmFtZXRlci4KICAgICAgICAgKi8KICAgICAgICBjbG9uZSgpIHsKICAgICAgICAgICAgY29uc3QgY2xvbmVkUGFyYW0gPSBuZXcgUXVhdFBhcmFtZXRlcih0aGlzLm5hbWUsIHRoaXMudmFsdWU/LmNsb25lKCkpOwogICAgICAgICAgICByZXR1cm4gY2xvbmVkUGFyYW07CiAgICAgICAgfQogICAgfQogICAgUmVnaXN0cnkucmVnaXN0ZXIoJ1F1YXRQYXJhbWV0ZXInLCBRdWF0UGFyYW1ldGVyKTsKICAgIFJlZ2lzdHJ5LnJlZ2lzdGVyKCdQcm9wZXJ0eV9RdWF0XzMyZicsIFF1YXRQYXJhbWV0ZXIpOwoKICAgIC8qIGVzbGludC1kaXNhYmxlIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFycyAqLwogICAgLyoqCiAgICAgKiBSZXByZXNlbnRzIGEgc3BlY2lmaWMgdHlwZSBvZiBwYXJhbWV0ZXIsIHRoYXQgb25seSBzdG9yZXMgTWF0MygzeDMgbWF0cml4KSB2YWx1ZXMuCiAgICAgKgogICAgICogaS5lLjoKICAgICAqIGBgYGphdmFzY3JpcHQKICAgICAqIGNvbnN0IG1hdDNQYXJhbSA9IG5ldyBNYTNQYXJhbWV0ZXIoJ015TWF0MycsIG5ldyBNYXQzKC4uLmFyZ3MpKQogICAgICogLy8nbXlQYXJhbWV0ZXJPd25lckl0ZW0nIGlzIGFuIGluc3RhbmNlIG9mIGEgJ1BhcmFtZXRlck93bmVyJyBjbGFzcy4KICAgICAqIC8vIFJlbWVtYmVyIHRoYXQgb25seSAnUGFyYW1ldGVyT3duZXInIGFuZCBjbGFzc2VzIHRoYXQgZXh0ZW5kIGZyb20gaXQgY2FuIGhvc3QgJ1BhcmFtZXRlcicgb2JqZWN0cy4KICAgICAqIG15UGFyYW1ldGVyT3duZXJJdGVtLmFkZFBhcmFtZXRlcihtYXQzUGFyYW0pCiAgICAgKiBgYGAKICAgICAqCiAgICAgKiBAZXh0ZW5kcyBQYXJhbWV0ZXIKICAgICAqLwogICAgY2xhc3MgTWF0M1BhcmFtZXRlciBleHRlbmRzIFBhcmFtZXRlciB7CiAgICAgICAgLyoqCiAgICAgICAgICogQ3JlYXRlIGEgTWF0MyBwYXJhbWV0ZXIuCiAgICAgICAgICogQHBhcmFtIG5hbWUgLSBUaGUgbmFtZSBvZiB0aGUgTWF0MyBwYXJhbWV0ZXIuCiAgICAgICAgICogQHBhcmFtIHZhbHVlIC0gVGhlIHZhbHVlIG9mIHRoZSBwYXJhbWV0ZXIuCiAgICAgICAgICovCiAgICAgICAgY29uc3RydWN0b3IobmFtZSA9ICcnLCB2YWx1ZSkgewogICAgICAgICAgICBzdXBlcihuYW1lLCB2YWx1ZSA/IHZhbHVlIDogbmV3IE1hdDMoKSwgJ01hdDMnKTsKICAgICAgICB9CiAgICAgICAgc2V0VmFsdWUodmFsdWUpIHsKICAgICAgICAgICAgaWYgKCEodmFsdWUgaW5zdGFuY2VvZiBNYXQzKSkgewogICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGB2YWx1ZSBwcm92aWRlZCBpcyBub3QgYW4gaW5zdGFuY2Ugb2YgYSAnTWF0MycgY2xhc3MuIENoZWNrIHRoZSBzb3VyY2Ugb2YgdGhpcyB2YWx1ZWApOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHN1cGVyLnNldFZhbHVlKHZhbHVlKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogRXh0cmFjdHMgYSBudW1iZXIgdmFsdWUgZnJvbSBhIGJ1ZmZlciwgdXBkYXRpbmcgY3VycmVudCBwYXJhbWV0ZXIgc3RhdGUuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gcmVhZGVyIC0gVGhlIHJlYWRlciB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0gY29udGV4dCAtIFRoZSBjb250ZXh0IHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHJlYWRCaW5hcnkocmVhZGVyLCBjb250ZXh0KSB7CiAgICAgICAgICAgIHRoaXMudmFsdWU/LnJlYWRCaW5hcnkocmVhZGVyKTsKICAgICAgICB9CiAgICAgICAgdG9KU09OKGNvbnRleHQpIHsKICAgICAgICAgICAgcmV0dXJuIHsKICAgICAgICAgICAgICAgIHR5cGU6IHRoaXMuZ2V0Q2xhc3NOYW1lKCksCiAgICAgICAgICAgICAgICBuYW1lOiB0aGlzLm5hbWUsCiAgICAgICAgICAgICAgICB2YWx1ZTogdGhpcy52YWx1ZT8udG9KU09OKCksCiAgICAgICAgICAgIH07CiAgICAgICAgfQogICAgICAgIGZyb21KU09OKGosIGNvbnRleHQpIHsKICAgICAgICAgICAgY29uc3QgbWF0MyA9IG5ldyBNYXQzKCk7CiAgICAgICAgICAgIG1hdDMuZnJvbUpTT04oai52YWx1ZSk7CiAgICAgICAgICAgIHRoaXMudmFsdWUgPSBtYXQzOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgY2xvbmUgbWV0aG9kIGNvbnN0cnVjdHMgYSBuZXcgTWF0MyBwYXJhbWV0ZXIsCiAgICAgICAgICogY29waWVzIGl0cyB2YWx1ZXMgZnJvbSB0aGlzIHBhcmFtZXRlciBhbmQgcmV0dXJucyBpdC4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGEgbmV3IGNsb25lZCBNYXQzIHBhcmFtZXRlci4KICAgICAgICAgKi8KICAgICAgICBjbG9uZSgpIHsKICAgICAgICAgICAgY29uc3QgY2xvbmVkUGFyYW0gPSBuZXcgTWF0M1BhcmFtZXRlcih0aGlzLm5hbWUsIHRoaXMudmFsdWU/LmNsb25lKCkpOwogICAgICAgICAgICByZXR1cm4gY2xvbmVkUGFyYW07CiAgICAgICAgfQogICAgfQogICAgUmVnaXN0cnkucmVnaXN0ZXIoJ01hdDNQYXJhbWV0ZXInLCBNYXQzUGFyYW1ldGVyKTsKICAgIFJlZ2lzdHJ5LnJlZ2lzdGVyKCdQcm9wZXJ0eV9NYXQzXzMyZicsIE1hdDNQYXJhbWV0ZXIpOwoKICAgIC8qIGVzbGludC1kaXNhYmxlIEB0eXBlc2NyaXB0LWVzbGludC9uby1leHBsaWNpdC1hbnkgKi8KICAgIC8qKgogICAgICogUmVwcmVzZW50cyBhIHNwZWNpZmljIHR5cGUgb2YgcGFyYW1ldGVyLCB0aGF0IG9ubHkgc3RvcmVzIE1hdDQoNHg0IG1hdHJpeCkgdmFsdWVzLgogICAgICoKICAgICAqIGkuZS46CiAgICAgKiBgYGBqYXZhc2NyaXB0CiAgICAgKiBjb25zdCBtYXQ0UGFyYW0gPSBuZXcgTWEzUGFyYW1ldGVyKCdNeU1hdDQnLCBuZXcgTWF0NCguLi5hcmdzKSkKICAgICAqIC8vJ215UGFyYW1ldGVyT3duZXJJdGVtJyBpcyBhbiBpbnN0YW5jZSBvZiBhICdQYXJhbWV0ZXJPd25lcicgY2xhc3MuCiAgICAgKiAvLyBSZW1lbWJlciB0aGF0IG9ubHkgJ1BhcmFtZXRlck93bmVyJyBhbmQgY2xhc3NlcyB0aGF0IGV4dGVuZCBmcm9tIGl0IGNhbiBob3N0ICdQYXJhbWV0ZXInIG9iamVjdHMuCiAgICAgKiBteVBhcmFtZXRlck93bmVySXRlbS5hZGRQYXJhbWV0ZXIobWF0NFBhcmFtKQogICAgICogYGBgCiAgICAgKgogICAgICogQGV4dGVuZHMgUGFyYW1ldGVyCiAgICAgKi8KICAgIGNsYXNzIE1hdDRQYXJhbWV0ZXIgZXh0ZW5kcyBQYXJhbWV0ZXIgewogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZSBhIE1hdDQgcGFyYW1ldGVyLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIG5hbWUgLSBUaGUgbmFtZSBvZiB0aGUgTWF0NCBwYXJhbWV0ZXIuCiAgICAgICAgICogQHBhcmFtIHZhbHVlIC0gVGhlIHZhbHVlIG9mIHRoZSBwYXJhbWV0ZXIuCiAgICAgICAgICovCiAgICAgICAgY29uc3RydWN0b3IobmFtZSA9ICcnLCB2YWx1ZSkgewogICAgICAgICAgICBzdXBlcihuYW1lLCB2YWx1ZSA/IHZhbHVlIDogbmV3IE1hdDQoKSwgJ01hdDQnKTsKICAgICAgICB9CiAgICAgICAgc2V0VmFsdWUodmFsdWUpIHsKICAgICAgICAgICAgaWYgKCEodmFsdWUgaW5zdGFuY2VvZiBNYXQ0KSkgewogICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGB2YWx1ZSBwcm92aWRlZCBpcyBub3QgYW4gaW5zdGFuY2Ugb2YgYSAnTWF0NCcgY2xhc3MuIENoZWNrIHRoZSBzb3VyY2Ugb2YgdGhpcyB2YWx1ZWApOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHN1cGVyLnNldFZhbHVlKHZhbHVlKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogRXh0cmFjdHMgYSBudW1iZXIgdmFsdWUgZnJvbSBhIGJ1ZmZlciwgdXBkYXRpbmcgY3VycmVudCBwYXJhbWV0ZXIgc3RhdGUuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gcmVhZGVyIC0gVGhlIHJlYWRlciB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0gY29udGV4dCAtIFRoZSBjb250ZXh0IHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHJlYWRCaW5hcnkocmVhZGVyLCBjb250ZXh0KSB7CiAgICAgICAgICAgIHRoaXMudmFsdWU/LnJlYWRCaW5hcnkocmVhZGVyKTsKICAgICAgICB9CiAgICAgICAgdG9KU09OKGNvbnRleHQpIHsKICAgICAgICAgICAgcmV0dXJuIHsKICAgICAgICAgICAgICAgIHR5cGU6IHRoaXMuZ2V0Q2xhc3NOYW1lKCksCiAgICAgICAgICAgICAgICB2YWx1ZTogdGhpcy52YWx1ZT8udG9KU09OKCksCiAgICAgICAgICAgIH07CiAgICAgICAgfQogICAgICAgIGZyb21KU09OKGosIGNvbnRleHQpIHsKICAgICAgICAgICAgY29uc3QgbWF0NCA9IG5ldyBNYXQ0KCk7CiAgICAgICAgICAgIG1hdDQuZnJvbUpTT04oai52YWx1ZSk7CiAgICAgICAgICAgIHRoaXMudmFsdWUgPSBtYXQ0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgY2xvbmUgbWV0aG9kIGNvbnN0cnVjdHMgYSBuZXcgTWF0NCBwYXJhbWV0ZXIsCiAgICAgICAgICogY29waWVzIGl0cyB2YWx1ZXMgZnJvbSB0aGlzIHBhcmFtZXRlciBhbmQgcmV0dXJucyBpdC4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGEgbmV3IGNsb25lZCBNYXQ0IHBhcmFtZXRlci4KICAgICAgICAgKi8KICAgICAgICBjbG9uZSgpIHsKICAgICAgICAgICAgY29uc3QgY2xvbmVkUGFyYW0gPSBuZXcgTWF0NFBhcmFtZXRlcih0aGlzLm5hbWUsIHRoaXMudmFsdWU/LmNsb25lKCkpOwogICAgICAgICAgICByZXR1cm4gY2xvbmVkUGFyYW07CiAgICAgICAgfQogICAgfQogICAgUmVnaXN0cnkucmVnaXN0ZXIoJ01hdDRQYXJhbWV0ZXInLCBNYXQ0UGFyYW1ldGVyKTsKICAgIFJlZ2lzdHJ5LnJlZ2lzdGVyKCdQcm9wZXJ0eV9NYXQ0XzMyZicsIE1hdDRQYXJhbWV0ZXIpOwoKICAgIC8qIGVzbGludC1kaXNhYmxlIEB0eXBlc2NyaXB0LWVzbGludC9uby1leHBsaWNpdC1hbnkgKi8KICAgIC8qKgogICAgICogUmVwcmVzZW50cyBhIHNwZWNpZmljIHR5cGUgb2YgcGFyYW1ldGVyLCB0aGF0IG9ubHkgc3RvcmVzIGBYZm9gIHRyYW5zZm9ybSB2YWx1ZXMuCiAgICAgKgogICAgICogYGBgamF2YXNjcmlwdAogICAgICogY29uc3QgeGZvUGFyYW0gPSBuZXcgWGZvUGFyYW1ldGVyKCdNeVhmbycsIG5ldyBYZm8obmV3IFZlYzMoMS4yLCAzLjQsIDEpKSkKICAgICAqIC8vJ215UGFyYW1ldGVyT3duZXJJdGVtJyBpcyBhbiBpbnN0YW5jZSBvZiBhICdQYXJhbWV0ZXJPd25lcicgY2xhc3MuCiAgICAgKiAvLyBSZW1lbWJlciB0aGF0IG9ubHkgJ1BhcmFtZXRlck93bmVyJyBhbmQgY2xhc3NlcyB0aGF0IGV4dGVuZCBmcm9tIGl0IGNhbiBob3N0ICdQYXJhbWV0ZXInIG9iamVjdHMuCiAgICAgKiBteVBhcmFtZXRlck93bmVySXRlbS5hZGRQYXJhbWV0ZXIoeGZvUGFyYW0pCiAgICAgKiBgYGAKICAgICAqCiAgICAgKiBAZXh0ZW5kcyBQYXJhbWV0ZXIKICAgICAqLwogICAgY2xhc3MgWGZvUGFyYW1ldGVyIGV4dGVuZHMgUGFyYW1ldGVyIHsKICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGUgYSBYZm8gcGFyYW1ldGVyLgogICAgICAgICAqIEBwYXJhbSBuYW1lIC0gVGhlIG5hbWUgb2YgdGhlIFhmbyBwYXJhbWV0ZXIuCiAgICAgICAgICogQHBhcmFtIHZhbHVlIC0gVGhlIHZhbHVlIG9mIHRoZSBwYXJhbWV0ZXIuCiAgICAgICAgICovCiAgICAgICAgY29uc3RydWN0b3IobmFtZSA9ICcnLCB2YWx1ZSkgewogICAgICAgICAgICBzdXBlcihuYW1lLCB2YWx1ZSA/IHZhbHVlIDogbmV3IFhmbygpLCAnWGZvJyk7CiAgICAgICAgfQogICAgICAgIHNldFZhbHVlKHZhbHVlKSB7CiAgICAgICAgICAgIGlmICghKHZhbHVlIGluc3RhbmNlb2YgWGZvKSkgewogICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGB2YWx1ZSBwcm92aWRlZCBpcyBub3QgYW4gaW5zdGFuY2Ugb2YgYSAnWGZvJyBjbGFzcy4gQ2hlY2sgdGhlIHNvdXJjZSBvZiB0aGlzIHZhbHVlYCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgc3VwZXIuc2V0VmFsdWUodmFsdWUpOwogICAgICAgIH0KICAgICAgICAvLyAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCiAgICAgICAgLy8gUGVyc2lzdGVuY2UKICAgICAgICAvKioKICAgICAgICAgKiBFeHRyYWN0cyBhIG51bWJlciB2YWx1ZSBmcm9tIGEgYnVmZmVyLCB1cGRhdGluZyBjdXJyZW50IHBhcmFtZXRlciBzdGF0ZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSByZWFkZXIgLSBUaGUgcmVhZGVyIHZhbHVlLgogICAgICAgICAqIEBwYXJhbSBjb250ZXh0IC0gVGhlIGNvbnRleHQgdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgcmVhZEJpbmFyeShyZWFkZXIsIGNvbnRleHQpIHsKICAgICAgICAgICAgdGhpcy52YWx1ZS5yZWFkQmluYXJ5KHJlYWRlcik7CiAgICAgICAgfQogICAgICAgIHRvSlNPTihjb250ZXh0KSB7CiAgICAgICAgICAgIHJldHVybiB7IHR5cGU6IHRoaXMuZ2V0Q2xhc3NOYW1lKCksIG5hbWU6IHRoaXMubmFtZSwgdmFsdWU6IHRoaXMudmFsdWUudG9KU09OKCkgfTsKICAgICAgICB9CiAgICAgICAgZnJvbUpTT04oaiwgY29udGV4dCkgewogICAgICAgICAgICBjb25zdCB4Zm8gPSBuZXcgWGZvKCk7CiAgICAgICAgICAgIHhmby5mcm9tSlNPTihqLnZhbHVlKTsKICAgICAgICAgICAgdGhpcy52YWx1ZSA9IHhmbzsKICAgICAgICAgICAgaWYgKGoubmFtZSkKICAgICAgICAgICAgICAgIHRoaXMubmFtZSA9IGoubmFtZTsKICAgICAgICB9CiAgICAgICAgLy8gLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwogICAgICAgIC8vIENsb25lCiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGNsb25lIG1ldGhvZCBjb25zdHJ1Y3RzIGEgbmV3IFhmbyBwYXJhbWV0ZXIsIGNvcGllcyBpdHMgdmFsdWVzCiAgICAgICAgICogZnJvbSB0aGlzIHBhcmFtZXRlciBhbmQgcmV0dXJucyBpdC4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGEgbmV3IFhmbyBwYXJhbWV0ZXIuCiAgICAgICAgICovCiAgICAgICAgY2xvbmUoKSB7CiAgICAgICAgICAgIGNvbnN0IGNsb25lZFBhcmFtID0gbmV3IFhmb1BhcmFtZXRlcih0aGlzLm5hbWUsIHRoaXMudmFsdWUuY2xvbmUoKSk7CiAgICAgICAgICAgIHJldHVybiBjbG9uZWRQYXJhbTsKICAgICAgICB9CiAgICB9CiAgICBSZWdpc3RyeS5yZWdpc3RlcignWGZvUGFyYW1ldGVyJywgWGZvUGFyYW1ldGVyKTsKICAgIFJlZ2lzdHJ5LnJlZ2lzdGVyKCdQcm9wZXJ0eV9YZm9fMzJmJywgWGZvUGFyYW1ldGVyKTsKCiAgICAvKioKICAgICAqIFJlcHJlc2VudHMgYSAyRCBpbWFnZSBpdGVtLCBjb250YWluaW5nIHdpZHRoIGFuZCBoZWlnaHQuCiAgICAgKgogICAgICogKipFdmVudHMqKgogICAgICogKiAqKnVwZGF0ZWQ6KiogVHJpZ2dlcmVkIHdoZW4gdGhlIHZhbHVlIG9mIGFueSBvZiB0aGUgcGFyYW1ldGVycyBsaXN0ZWQgYWJvdmUgY2hhbmdlcy4KICAgICAqCiAgICAgKiBAZXh0ZW5kcyBQYXJhbWV0ZXJPd25lcgogICAgICovCiAgICBjbGFzcyBCYXNlSW1hZ2UgZXh0ZW5kcyBQYXJhbWV0ZXJPd25lciB7CiAgICAgICAgd2lkdGggPSAwOwogICAgICAgIGhlaWdodCA9IDA7CiAgICAgICAgZm9ybWF0ID0gJ1JHQic7CiAgICAgICAgdHlwZSA9ICdVTlNJR05FRF9CWVRFJzsKICAgICAgICBsb2FkZWQgPSBmYWxzZTsKICAgICAgICBtaXBNYXBwZWQgPSB0cnVlOwogICAgICAgIHdyYXBTID0gJ1JFUEVBVCc7CiAgICAgICAgd3JhcFQgPSAnUkVQRUFUJzsKICAgICAgICBtaW5GaWx0ZXIgPSAnTElORUFSJzsKICAgICAgICBtYWdGaWx0ZXIgPSAnTElORUFSJzsKICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGVzIGFuIGluc3RhbmNlIG9mIEJhc2VJbWFnZS4KICAgICAgICAgKiBAcGFyYW0gbmFtZSAtIG5hbWUgb2YgdGhlIGl0ZW0KICAgICAgICAgKi8KICAgICAgICBjb25zdHJ1Y3RvcihuYW1lID0gJ0ltYWdlJykgewogICAgICAgICAgICBzdXBlcihuYW1lKTsKICAgICAgICAgICAgdGhpcy5vbigncGFyYW1ldGVyVmFsdWVDaGFuZ2VkJywgKCkgPT4gewogICAgICAgICAgICAgICAgdGhpcy5lbWl0KCd1cGRhdGVkJyk7CiAgICAgICAgICAgIH0pOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIHRydWUgaWYgbG9hZGVkLgogICAgICAgICAqIEBwcml2YXRlCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgYSBib29sZWFuLgogICAgICAgICAqLwogICAgICAgIGlzTG9hZGVkKCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy5sb2FkZWQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgYWxsIHBhcmFtZXRlcnMgYW5kIGNsYXNzIHN0YXRlIHZhbHVlcy4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGdldFBhcmFtcygpIHsKICAgICAgICAgICAgcmV0dXJuIHsKICAgICAgICAgICAgICAgIHR5cGU6IHRoaXMudHlwZSwKICAgICAgICAgICAgICAgIGZvcm1hdDogdGhpcy5mb3JtYXQsCiAgICAgICAgICAgICAgICB3aWR0aDogdGhpcy53aWR0aCwKICAgICAgICAgICAgICAgIGhlaWdodDogdGhpcy5oZWlnaHQsCiAgICAgICAgICAgICAgICB3cmFwUzogdGhpcy53cmFwUywKICAgICAgICAgICAgICAgIHdyYXBUOiB0aGlzLndyYXBULAogICAgICAgICAgICAgICAgbWluRmlsdGVyOiB0aGlzLm1pbkZpbHRlciwKICAgICAgICAgICAgICAgIG1hZ0ZpbHRlcjogdGhpcy5tYWdGaWx0ZXIsCiAgICAgICAgICAgICAgICBtaXBNYXBwZWQ6IHRoaXMubWlwTWFwcGVkLAogICAgICAgICAgICB9OwogICAgICAgIH0KICAgIH0KCiAgICAvKiBlc2xpbnQtZGlzYWJsZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnMgKi8KICAgIC8qKgogICAgICogUmVwcmVzZW50cyBhIHNwZWNpZmljIHR5cGUgb2YgcGFyYW1ldGVyLCB0aGF0IG9ubHkgc3RvcmVzIGBCYXNlSW1hZ2VgIHZhbHVlcy4KICAgICAqCiAgICAgKiBpLmUuOgogICAgICogYGBgamF2YXNjcmlwdAogICAgICogLy8gU2luY2UgYExhYmVsYCBpcyBhIGBCYXNlSW1hZ2VgIGltcGxlbWVudGF0aW9uLCBpdCBoZWxwcyB1cyB3aXRoIHRoZSBleGFtcGxlLgogICAgICogY29uc3QgbGFiZWwgPSBuZXcgTGFiZWwoJ015IGF3ZXNvbWUgbGFiZWwnLCAnTGFiZWxQYWNrJykKICAgICAqIGNvbnN0IGltYWdlUGFyYW0gPSBuZXcgSW1hZ2VQYXJhbWV0ZXIoJ015SW1hZ2UnLCBsYWJlbCkKICAgICAqIC8vJ215UGFyYW1ldGVyT3duZXJJdGVtJyBpcyBhbiBpbnN0YW5jZSBvZiBhICdQYXJhbWV0ZXJPd25lcicgY2xhc3MuCiAgICAgKiAvLyBSZW1lbWJlciB0aGF0IG9ubHkgJ1BhcmFtZXRlck93bmVyJyBhbmQgY2xhc3NlcyB0aGF0IGV4dGVuZCBmcm9tIGl0IGNhbiBob3N0ICdQYXJhbWV0ZXInIG9iamVjdHMuCiAgICAgKiBteVBhcmFtZXRlck93bmVySXRlbS5hZGRQYXJhbWV0ZXIoaW1hZ2VQYXJhbSkKICAgICAqIGBgYAogICAgICoKICAgICAqIEBleHRlbmRzIFBhcmFtZXRlcgogICAgICovCiAgICBjbGFzcyBJbWFnZVBhcmFtZXRlciBleHRlbmRzIFBhcmFtZXRlciB7CiAgICAgICAgLyoqCiAgICAgICAgICogQ3JlYXRlIGFuIGltYWdlIHBhcmFtZXRlci4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBuYW1lIC0gVGhlIG5hbWUgb2YgdGhlIGltYWdlIHBhcmFtZXRlci4KICAgICAgICAgKiBAcGFyYW0gdmFsdWUgLSBUaGUgdmFsdWUgb2YgdGhlIHBhcmFtZXRlci4KICAgICAgICAgKi8KICAgICAgICBjb25zdHJ1Y3RvcihuYW1lID0gJycsIHZhbHVlKSB7CiAgICAgICAgICAgIHN1cGVyKG5hbWUsIHZhbHVlLCAnQmFzZUltYWdlJyk7CiAgICAgICAgfQogICAgICAgIHNldFZhbHVlKHZhbHVlKSB7CiAgICAgICAgICAgIGlmICghKHZhbHVlIGluc3RhbmNlb2YgQmFzZUltYWdlKSkgewogICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGB2YWx1ZSBwcm92aWRlZCBpcyBub3QgYW4gaW5zdGFuY2Ugb2YgJ0Jhc2VJbWFnZScgY2xhc3MuIENoZWNrIHRoZSBzb3VyY2Ugb2YgdGhpcyB2YWx1ZWApOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHN1cGVyLnNldFZhbHVlKHZhbHVlKTsKICAgICAgICB9CiAgICAgICAgLy8gLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwogICAgICAgIC8vIFBlcnNpc3RlbmNlCiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIHRvSlNPTiBtZXRob2QgZW5jb2RlcyB0aGlzIHR5cGUgYXMgYSBqc29uIG9iamVjdCBmb3IgcGVyc2lzdGVuY2UuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gY29udGV4dCAtIFRoZSBjb250ZXh0IHZhbHVlLgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIHRoZSBqc29uIG9iamVjdC4KICAgICAgICAgKi8KICAgICAgICB0b0pTT04oY29udGV4dCkgewogICAgICAgICAgICBjb25zdCBqID0gewogICAgICAgICAgICAgICAgdHlwZTogdGhpcy5nZXRDbGFzc05hbWUoKSwKICAgICAgICAgICAgICAgIG5hbWU6IHRoaXMubmFtZSwKICAgICAgICAgICAgfTsKICAgICAgICAgICAgaWYgKHRoaXMudmFsdWUpIHsKICAgICAgICAgICAgICAgIGouaW1hZ2VUeXBlID0gdGhpcy52YWx1ZS5nZXRDbGFzc05hbWUoKTsKICAgICAgICAgICAgICAgIGoudmFsdWUgPSB0aGlzLnZhbHVlLnRvSlNPTigpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBqOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgZnJvbUpTT04gbWV0aG9kIGRlY29kZXMgYSBqc29uIG9iamVjdCBmb3IgdGhpcyB0eXBlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGogLSBUaGUganNvbiBvYmplY3QgdGhpcyBpdGVtIG11c3QgZGVjb2RlLgogICAgICAgICAqIEBwYXJhbSBjb250ZXh0IC0gVGhlIGNvbnRleHQgdmFsdWUuCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgdGhlIGpzb24gb2JqZWN0LgogICAgICAgICAqLwogICAgICAgIGZyb21KU09OKGosIGNvbnRleHQpIHsKICAgICAgICAgICAgaWYgKGouaW1hZ2VUeXBlKSB7CiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlID0gUmVnaXN0cnkuY29uc3RydWN0Q2xhc3Moai5pbWFnZVR5cGUpOwogICAgICAgICAgICAgICAgaWYgKGoudmFsdWUpCiAgICAgICAgICAgICAgICAgICAgdGhpcy52YWx1ZT8uZnJvbUpTT04oai52YWx1ZSwgY29udGV4dCk7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgLy8gLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwogICAgICAgIC8vIENsb25lCiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGNsb25lIG1ldGhvZCBjb25zdHJ1Y3RzIGEgbmV3IGltYWdlIHBhcmFtZXRlciwKICAgICAgICAgKiBjb3BpZXMgaXRzIHZhbHVlcyBmcm9tIHRoaXMgcGFyYW1ldGVyIGFuZCByZXR1cm5zIGl0LgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgYSBuZXcgY2xvbmVkIGltYWdlIHBhcmFtZXRlci4KICAgICAgICAgKi8KICAgICAgICBjbG9uZSgpIHsKICAgICAgICAgICAgY29uc3QgY2xvbmVkUGFyYW0gPSBuZXcgSW1hZ2VQYXJhbWV0ZXIodGhpcy5uYW1lLCB0aGlzLnZhbHVlKTsKICAgICAgICAgICAgcmV0dXJuIGNsb25lZFBhcmFtOwogICAgICAgIH0KICAgIH0KICAgIFJlZ2lzdHJ5LnJlZ2lzdGVyKCdJbWFnZVBhcmFtZXRlcicsIEltYWdlUGFyYW1ldGVyKTsKCiAgICAvKiBlc2xpbnQtZGlzYWJsZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnMgKi8KICAgIC8qKgogICAgICogUmVwcmVzZW50cyBhIHNwZWNpZmljIHR5cGUgb2YgcGFyYW1ldGVyLCB0aGF0IG9ubHkgc3RvcmVzIE1hdDQoNHg0IG1hdHJpeCkgdmFsdWVzLgogICAgICoKICAgICAqIGkuZS46CiAgICAgKiBgYGBqYXZhc2NyaXB0CiAgICAgKiBjb25zdCBzdHJpbmdQYXJhbSA9IG5ldyBTdHJpbmdQYXJhbWV0ZXIoJ015U3RyaW5nJywgJ0EgU3RyaW5nIHZhbHVlIGdvZXMgaGVyZScpCiAgICAgKiAvLydteVBhcmFtZXRlck93bmVySXRlbScgaXMgYW4gaW5zdGFuY2Ugb2YgYSAnUGFyYW1ldGVyT3duZXInIGNsYXNzLgogICAgICogLy8gUmVtZW1iZXIgdGhhdCBvbmx5ICdQYXJhbWV0ZXJPd25lcicgYW5kIGNsYXNzZXMgdGhhdCBleHRlbmQgZnJvbSBpdCBjYW4gaG9zdCAnUGFyYW1ldGVyJyBvYmplY3RzLgogICAgICogbXlQYXJhbWV0ZXJPd25lckl0ZW0uYWRkUGFyYW1ldGVyKHN0cmluZ1BhcmFtKQogICAgICogYGBgCiAgICAgKgogICAgICogQGV4dGVuZHMgUGFyYW1ldGVyCiAgICAgKi8KICAgIGNsYXNzIFN0cmluZ1BhcmFtZXRlciBleHRlbmRzIFBhcmFtZXRlciB7CiAgICAgICAgbXVsdGlMaW5lOwogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZSBhIHN0cmluZyBwYXJhbWV0ZXIuCiAgICAgICAgICogQHBhcmFtIG5hbWUgLSBUaGUgbmFtZSBvZiB0aGUgbWF0ZXJpYWwgY29sb3IgcGFyYW1ldGVyLgogICAgICAgICAqIEBwYXJhbSB2YWx1ZSAtIFRoZSB2YWx1ZSBvZiB0aGUgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIGNvbnN0cnVjdG9yKG5hbWUgPSAnJywgdmFsdWUgPSAnJykgewogICAgICAgICAgICBzdXBlcihuYW1lLCB2YWx1ZSwgJ1N0cmluZycpOwogICAgICAgICAgICB0aGlzLm11bHRpTGluZSA9IGZhbHNlOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTZXRzIGZsYWcgdGhhdCBpbmRpY2F0ZXMgaWYgdGhlIHN0cmluZyBjb250YWlucyBuZXcgbGluZSBmZWVkcy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBtdWx0aUxpbmUgLSBUaGUgbXVsdGlMaW5lIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHNldE11bHRpTGluZShtdWx0aUxpbmUpIHsKICAgICAgICAgICAgdGhpcy5tdWx0aUxpbmUgPSBtdWx0aUxpbmU7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgbXVsdGktbGluZSBmbGFnIHZhbHVlLgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgZ2V0TXVsdGlMaW5lKCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy5tdWx0aUxpbmU7CiAgICAgICAgfQogICAgICAgIHNldFZhbHVlKHZhbHVlKSB7CiAgICAgICAgICAgIGlmICh0eXBlb2YgdmFsdWUgIT0gJ3N0cmluZycpIHsKICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgdmFsdWUgcHJvdmlkZWQgaXMgbm90IGEgc3RyaW5nLiBDaGVjayB0aGUgc291cmNlIG9mIHRoaXMgdmFsdWVgKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBzdXBlci5zZXRWYWx1ZSh2YWx1ZSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEV4dHJhY3RzIHRoZSBzdHJpbmcgdmFsdWUgZnJvbSBhIGJ1ZmZlciwgdXBkYXRpbmcgY3VycmVudCBwYXJhbWV0ZXIgc3RhdGUuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gcmVhZGVyIC0gVGhlIHJlYWRlciB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0gY29udGV4dCAtIFRoZSBjb250ZXh0IHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHJlYWRCaW5hcnkocmVhZGVyLCBjb250ZXh0KSB7CiAgICAgICAgICAgIHRoaXMudmFsdWUgPSByZWFkZXIubG9hZFN0cigpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgdG9KU09OIG1ldGhvZCBzZXJpYWxpemVzIHRoaXMgaW5zdGFuY2UgYXMgYSBKU09OLgogICAgICAgICAqIEl0IGNhbiBiZSB1c2VkIGZvciBwZXJzaXN0ZW5jZSwgZGF0YSB0cmFuc2ZlciwgZXRjLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGNvbnRleHQgLSBUaGUgY29udGV4dCB2YWx1ZS4KICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyB0aGUganNvbiBvYmplY3QuCiAgICAgICAgICovCiAgICAgICAgdG9KU09OKGNvbnRleHQpIHsKICAgICAgICAgICAgcmV0dXJuIHsgdHlwZTogdGhpcy5nZXRDbGFzc05hbWUoKSwgbmFtZTogdGhpcy5uYW1lLCB2YWx1ZTogdGhpcy52YWx1ZSB9OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgZnJvbUpTT04gbWV0aG9kIHRha2VzIGEgSlNPTiBhbmQgZGVzZXJpYWxpemVzIGludG8gYW4gaW5zdGFuY2Ugb2YgdGhpcyB0eXBlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGogLSBUaGUganNvbiBvYmplY3QgdGhpcyBpdGVtIG11c3QgZGVjb2RlLgogICAgICAgICAqIEBwYXJhbSBjb250ZXh0IC0gVGhlIGNvbnRleHQgdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgZnJvbUpTT04oaiwgY29udGV4dCkgewogICAgICAgICAgICBjb25zdCBuZXdWYWx1ZSA9IGoudmFsdWUgPz8gJyc7CiAgICAgICAgICAgIGlmICh0aGlzLnZhbHVlICE9IG5ld1ZhbHVlKSB7CiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlID0gbmV3VmFsdWU7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGNsb25lIG1ldGhvZCBjb25zdHJ1Y3RzIGEgbmV3IHN0cmluZyBwYXJhbWV0ZXIsIGNvcGllcyBpdHMgdmFsdWVzCiAgICAgICAgICogZnJvbSB0aGlzIHBhcmFtZXRlciBhbmQgcmV0dXJucyBpdC4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGEgbmV3IHN0cmluZyBwYXJhbWV0ZXIuCiAgICAgICAgICovCiAgICAgICAgY2xvbmUoKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgU3RyaW5nUGFyYW1ldGVyKHRoaXMubmFtZSwgdGhpcy52YWx1ZSk7CiAgICAgICAgfQogICAgfQogICAgUmVnaXN0cnkucmVnaXN0ZXIoJ1N0cmluZ1BhcmFtZXRlcicsIFN0cmluZ1BhcmFtZXRlcik7CiAgICBSZWdpc3RyeS5yZWdpc3RlcignUHJvcGVydHlfU3RyaW5nJywgU3RyaW5nUGFyYW1ldGVyKTsKCiAgICAvKioKICAgICAqIEEgcGFyYW1ldGVyIGZvciBzdG9yaW5nIGFuIGFycmF5IG9mIHN0cmluZyB2YWx1ZXMuCiAgICAgKgogICAgICogQGV4dGVuZHMgUGFyYW1ldGVyCiAgICAgKi8KICAgIGNsYXNzIFN0cmluZ0xpc3RQYXJhbWV0ZXIgZXh0ZW5kcyBQYXJhbWV0ZXIgewogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZSBhIHN0cmluZyBwYXJhbWV0ZXIuCiAgICAgICAgICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgLSBUaGUgbmFtZSBvZiB0aGUgbWF0ZXJpYWwgY29sb3IgcGFyYW1ldGVyLgogICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSB2YWx1ZSAtIFRoZSB2YWx1ZSBvZiB0aGUgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIGNvbnN0cnVjdG9yKG5hbWUgPSAnJywgdmFsdWUgPSBbXSkgewogICAgICAgICAgICBzdXBlcihuYW1lLCB2YWx1ZSwgJ1N0cmluZ1tdJyk7CiAgICAgICAgfQogICAgICAgIHNldFZhbHVlKHZhbHVlKSB7CiAgICAgICAgICAgIGlmICghQXJyYXkuaXNBcnJheSh2YWx1ZSkpIHsKICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgdmFsdWUgcHJvdmlkZWQgaXMgbm90IGFuIGFycmF5LiBDaGVjayB0aGUgc291cmNlIG9mIHRoaXMgdmFsdWVgKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBzdXBlci5zZXRWYWx1ZSh2YWx1ZSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEV4dHJhY3RzIHRoZSBzdHJpbmcgdmFsdWUgZnJvbSBhIGJ1ZmZlciwgdXBkYXRpbmcgY3VycmVudCBwYXJhbWV0ZXIgc3RhdGUuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0JpblJlYWRlcn0gcmVhZGVyIC0gVGhlIHJlYWRlciB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gY29udGV4dCAtIFRoZSBjb250ZXh0IHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHJlYWRCaW5hcnkocmVhZGVyLCBjb250ZXh0KSB7CiAgICAgICAgICAgIHRoaXMudmFsdWUgPSByZWFkZXIubG9hZFN0ckFycmF5KCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSB0b0pTT04gbWV0aG9kIHNlcmlhbGl6ZXMgdGhpcyBpbnN0YW5jZSBhcyBhIEpTT04uCiAgICAgICAgICogSXQgY2FuIGJlIHVzZWQgZm9yIHBlcnNpc3RlbmNlLCBkYXRhIHRyYW5zZmVyLCBldGMuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge1JlY29yZDxzdHJpbmcsIHVua25vd24+fSBjb250ZXh0IC0gVGhlIGNvbnRleHQgdmFsdWUuCiAgICAgICAgICogQHJldHVybiB7UmVjb3JkPHN0cmluZywgYm9vbGVhbiB8IHVuZGVmaW5lZD59IC0gUmV0dXJucyB0aGUganNvbiBvYmplY3QuCiAgICAgICAgICovCiAgICAgICAgdG9KU09OKGNvbnRleHQpIHsKICAgICAgICAgICAgcmV0dXJuIHsgdHlwZTogdGhpcy5nZXRDbGFzc05hbWUoKSwgbmFtZTogdGhpcy5uYW1lLCB2YWx1ZTogdGhpcy52YWx1ZSB9OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgZnJvbUpTT04gbWV0aG9kIHRha2VzIGEgSlNPTiBhbmQgZGVzZXJpYWxpemVzIGludG8gYW4gaW5zdGFuY2Ugb2YgdGhpcyB0eXBlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtSZWNvcmQ8c3RyaW5nLCBib29sZWFuIHwgdW5kZWZpbmVkPn0gaiAtIFRoZSBqc29uIG9iamVjdCB0aGlzIGl0ZW0gbXVzdCBkZWNvZGUuCiAgICAgICAgICogQHBhcmFtIHtSZWNvcmQ8c3RyaW5nLCB1bmtub3duPn0gY29udGV4dCAtIFRoZSBjb250ZXh0IHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGZyb21KU09OKGosIGNvbnRleHQpIHsKICAgICAgICAgICAgdGhpcy52YWx1ZSA9IGoudmFsdWU7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBjbG9uZSBtZXRob2QgY29uc3RydWN0cyBhIG5ldyBzdHJpbmcgcGFyYW1ldGVyLCBjb3BpZXMgaXRzIHZhbHVlcwogICAgICAgICAqIGZyb20gdGhpcyBwYXJhbWV0ZXIgYW5kIHJldHVybnMgaXQuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIHtTdHJpbmdMaXN0UGFyYW1ldGVyfSAtIFJldHVybnMgYSBuZXcgc3RyaW5nIHBhcmFtZXRlci4KICAgICAgICAgKi8KICAgICAgICBjbG9uZSgpIHsKICAgICAgICAgICAgY29uc3QgY2xvbmVkUGFyYW0gPSBuZXcgU3RyaW5nTGlzdFBhcmFtZXRlcih0aGlzLm5hbWUsIHRoaXMudmFsdWUpOwogICAgICAgICAgICByZXR1cm4gY2xvbmVkUGFyYW07CiAgICAgICAgfQogICAgfQogICAgUmVnaXN0cnkucmVnaXN0ZXIoJ1N0cmluZ0xpc3RQYXJhbWV0ZXInLCBTdHJpbmdMaXN0UGFyYW1ldGVyKTsKICAgIFJlZ2lzdHJ5LnJlZ2lzdGVyKCdQcm9wZXJ0eV9TdHJpbmdMaXN0JywgU3RyaW5nTGlzdFBhcmFtZXRlcik7CgogICAgLyoqCiAgICAgKiBBIHBhcmFtZXRlciBmb3Igc3RvcmluZyBhbiBhcnJheSBvZiBzdHJpbmcgdmFsdWVzLgogICAgICoKICAgICAqIEBleHRlbmRzIFBhcmFtZXRlcgogICAgICovCiAgICBjbGFzcyBGbG9hdDMyQXJyYXlQYXJhbWV0ZXIgZXh0ZW5kcyBQYXJhbWV0ZXIgewogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZSBhIHN0cmluZyBwYXJhbWV0ZXIuCiAgICAgICAgICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgLSBUaGUgbmFtZSBvZiB0aGUgbWF0ZXJpYWwgY29sb3IgcGFyYW1ldGVyLgogICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSB2YWx1ZSAtIFRoZSB2YWx1ZSBvZiB0aGUgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIGNvbnN0cnVjdG9yKG5hbWUgPSAnJywgdmFsdWUgPSBuZXcgRmxvYXQzMkFycmF5KCkpIHsKICAgICAgICAgICAgc3VwZXIobmFtZSwgdmFsdWUsICdGbG9hdFtdJyk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEV4dHJhY3RzIHRoZSBzdHJpbmcgdmFsdWUgZnJvbSBhIGJ1ZmZlciwgdXBkYXRpbmcgY3VycmVudCBwYXJhbWV0ZXIgc3RhdGUuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0JpblJlYWRlcn0gcmVhZGVyIC0gVGhlIHJlYWRlciB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gY29udGV4dCAtIFRoZSBjb250ZXh0IHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHJlYWRCaW5hcnkocmVhZGVyLCBjb250ZXh0KSB7CiAgICAgICAgICAgIHRoaXMudmFsdWUgPSByZWFkZXIubG9hZEZsb2F0MzJBcnJheSgpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgdG9KU09OIG1ldGhvZCBzZXJpYWxpemVzIHRoaXMgaW5zdGFuY2UgYXMgYSBKU09OLgogICAgICAgICAqIEl0IGNhbiBiZSB1c2VkIGZvciBwZXJzaXN0ZW5jZSwgZGF0YSB0cmFuc2ZlciwgZXRjLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtSZWNvcmQ8c3RyaW5nLCB1bmtub3duPn0gY29udGV4dCAtIFRoZSBjb250ZXh0IHZhbHVlLgogICAgICAgICAqIEByZXR1cm4ge1JlY29yZDxzdHJpbmcsIGJvb2xlYW4gfCB1bmRlZmluZWQ+fSAtIFJldHVybnMgdGhlIGpzb24gb2JqZWN0LgogICAgICAgICAqLwogICAgICAgIHRvSlNPTihjb250ZXh0KSB7CiAgICAgICAgICAgIHJldHVybiB7IHR5cGU6IHRoaXMuZ2V0Q2xhc3NOYW1lKCksIG5hbWU6IHRoaXMubmFtZSwgdmFsdWU6IHRoaXMudmFsdWUgfTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGZyb21KU09OIG1ldGhvZCB0YWtlcyBhIEpTT04gYW5kIGRlc2VyaWFsaXplcyBpbnRvIGFuIGluc3RhbmNlIG9mIHRoaXMgdHlwZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7UmVjb3JkPHN0cmluZywgYm9vbGVhbiB8IHVuZGVmaW5lZD59IGogLSBUaGUganNvbiBvYmplY3QgdGhpcyBpdGVtIG11c3QgZGVjb2RlLgogICAgICAgICAqIEBwYXJhbSB7UmVjb3JkPHN0cmluZywgdW5rbm93bj59IGNvbnRleHQgLSBUaGUgY29udGV4dCB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBmcm9tSlNPTihqLCBjb250ZXh0KSB7CiAgICAgICAgICAgIHRoaXMudmFsdWUgPSBqLnZhbHVlOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgY2xvbmUgbWV0aG9kIGNvbnN0cnVjdHMgYSBuZXcgc3RyaW5nIHBhcmFtZXRlciwgY29waWVzIGl0cyB2YWx1ZXMKICAgICAgICAgKiBmcm9tIHRoaXMgcGFyYW1ldGVyIGFuZCByZXR1cm5zIGl0LgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiB7RmxvYXQzMkFycmF5UGFyYW1ldGVyfSAtIFJldHVybnMgYSBuZXcgc3RyaW5nIHBhcmFtZXRlci4KICAgICAgICAgKi8KICAgICAgICBjbG9uZSgpIHsKICAgICAgICAgICAgY29uc3QgY2xvbmVkUGFyYW0gPSBuZXcgRmxvYXQzMkFycmF5UGFyYW1ldGVyKHRoaXMubmFtZSwgdGhpcy52YWx1ZSk7CiAgICAgICAgICAgIHJldHVybiBjbG9uZWRQYXJhbTsKICAgICAgICB9CiAgICB9CiAgICBSZWdpc3RyeS5yZWdpc3RlcignRmxvYXQzMkFycmF5UGFyYW1ldGVyJywgRmxvYXQzMkFycmF5UGFyYW1ldGVyKTsKICAgIFJlZ2lzdHJ5LnJlZ2lzdGVyKCdQcm9wZXJ0eV9GbG9hdDMyQXJyYXknLCBGbG9hdDMyQXJyYXlQYXJhbWV0ZXIpOwoKICAgIC8qIGVzbGludC1kaXNhYmxlIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFycyAqLwogICAgLyoqCiAgICAgKiBBIFBhcmFtZXRlciBmb3Igc3RvcmluZyBsaXN0KGFycmF5KSB2YWx1ZXMuCiAgICAgKgogICAgICogaS5lLjoKICAgICAqIGBgYGphdmFzY3JpcHQKICAgICAqIGNvbnN0IGxpc3RQYXJhbSA9IG5ldyBMaXN0UGFyYW1ldGVyKCdNeUxpc3QnLCBHZWFyUGFyYW1ldGVyKQogICAgICogLy8nbXlQYXJhbWV0ZXJPd25lckl0ZW0nIGlzIGFuIGluc3RhbmNlIG9mIGEgJ1BhcmFtZXRlck93bmVyJyBjbGFzcy4KICAgICAqIC8vIFJlbWVtYmVyIHRoYXQgb25seSAnUGFyYW1ldGVyT3duZXInIGFuZCBjbGFzc2VzIHRoYXQgZXh0ZW5kIGZyb20gaXQgY2FuIGhvc3QgJ1BhcmFtZXRlcicgb2JqZWN0cy4KICAgICAqIG15UGFyYW1ldGVyT3duZXJJdGVtLmFkZFBhcmFtZXRlcihsaXN0UGFyYW0pCiAgICAgKiBgYGAKICAgICAqCiAgICAgKiAqKkV2ZW50cyoqCiAgICAgKiAqICoqdmFsdWVDaGFuZ2VkOioqIFRyaWdnZXJlZCB3aGVuIHNldHRpbmcgYSB2YWx1ZSBjaGFuZ2VzIGluIHRoZSBhcnJheShpbnNlcnQsIGFkZCwgcmVtb3ZlKS4KICAgICAqICogKiplbGVtZW50QWRkZWQ6KiogVHJpZ2dlcmVkIHdoZW4gYW4gZWxlbWVudCBpcyBhZGRlZCB0byB0aGUgYXJyYXkoYWRkLCBpbnNlcnQpLgogICAgICogKiAqKmVsZW1lbnRSZW1vdmVkOioqIFRyaWdnZXJlZCB3aGVuIGFuIGVsZW1lbnQgaXMgcmVtb3ZlZCBmcm9tIHRoZSBhcnJheQogICAgICoKICAgICAqIEBleHRlbmRzIFBhcmFtZXRlcgogICAgICovCiAgICBjbGFzcyBMaXN0UGFyYW1ldGVyIGV4dGVuZHMgUGFyYW1ldGVyIHsKICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGUgYSBsaXN0IHBhcmFtZXRlci4KICAgICAgICAgKiBAcGFyYW0gbmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBsaXN0IHBhcmFtZXRlci4KICAgICAgICAgKiBAcGFyYW0gZGF0YVR5cGUgLSBUaGUgZGF0YVR5cGUgdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgY29uc3RydWN0b3IobmFtZSA9ICcnLCBkYXRhVHlwZSkgewogICAgICAgICAgICBzdXBlcihuYW1lLCBbXSwgZGF0YVR5cGUpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgZmlsdGVyIG1ldGhvZC4KICAgICAgICAgKiBAcGFyYW0gaXRlbSAtIFRoZSBpdGVtIHZhbHVlLgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqCiAgICAgICAgICogQHByaXZhdGUKICAgICAgICAgKi8KICAgICAgICBmaWx0ZXIoaXRlbSkgewogICAgICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyB0aGUgY291bnQgb2YgaXRlbXMgaW4gdGhlIGFycmF5LgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgZ2V0Q291bnQoKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLnZhbHVlPy5sZW5ndGggfHwgMDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyB2YWx1ZSBmcm9tIHRoZSBhcnJheSBpbiB0aGUgc3BlY2lmaWVkIGluZGV4LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGluZGV4IC0gVGhlIGluZGV4IHZhbHVlLgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGdldEVsZW1lbnQoaW5kZXgpIHsKICAgICAgICAgICAgaWYgKCF0aGlzLnZhbHVlKQogICAgICAgICAgICAgICAgcmV0dXJuOwogICAgICAgICAgICByZXR1cm4gdGhpcy52YWx1ZVtpbmRleF07CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFNldHMgYSB2YWx1ZSBpbiB0aGUgc3BlY2lmaWVkIGFycmF5J3MgaW5kZXguCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gaW5kZXggLSBUaGUgaW5kZXggdmFsdWUuCiAgICAgICAgICogQHBhcmFtIHZhbHVlIC0gVGhlIHZhbHVlIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHNldEVsZW1lbnQoaW5kZXgsIHZhbHVlKSB7CiAgICAgICAgICAgIGlmICghdGhpcy52YWx1ZSkKICAgICAgICAgICAgICAgIHRoaXMudmFsdWUgPSBbXTsKICAgICAgICAgICAgdGhpcy52YWx1ZVtpbmRleF0gPSB2YWx1ZTsKICAgICAgICAgICAgdGhpcy5lbWl0KCd2YWx1ZUNoYW5nZWQnKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQWRkcyBhIG5ldyBlbGVtZW50IGF0IHRoZSBlbmQgb2YgdGhlIGFycmF5IHBpbGUuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gZWxlbSAtIFRoZSBlbGVtIHZhbHVlLgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGFkZEVsZW1lbnQoZWxlbSkgewogICAgICAgICAgICBpZiAoKCFlbGVtICYmIGVsZW0gIT0gMCkgfHwgIXRoaXMuZmlsdGVyKGVsZW0pKQogICAgICAgICAgICAgICAgcmV0dXJuOwogICAgICAgICAgICBpZiAoIXRoaXMudmFsdWUpCiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlID0gW107CiAgICAgICAgICAgIHRoaXMudmFsdWUucHVzaChlbGVtKTsKICAgICAgICAgICAgdGhpcy5lbWl0KCdlbGVtZW50QWRkZWQnLCB7IGVsZW0sIGluZGV4OiB0aGlzLnZhbHVlLmxlbmd0aCAtIDEgfSk7CiAgICAgICAgICAgIHRoaXMuZW1pdCgndmFsdWVDaGFuZ2VkJyk7CiAgICAgICAgICAgIHJldHVybiBlbGVtOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZW1vdmVzIGFuIGFycmF5IGVsZW1lbnQgZnJvbSB0aGUgc3BlY2lmaWVkIGluZGV4CiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gaW5kZXggLSBUaGUgaW5kZXggdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgcmVtb3ZlRWxlbWVudChpbmRleCkgewogICAgICAgICAgICBpZiAoIXRoaXMudmFsdWUpCiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlID0gW107CiAgICAgICAgICAgIGNvbnN0IGVsZW0gPSB0aGlzLnZhbHVlW2luZGV4XTsKICAgICAgICAgICAgdGhpcy52YWx1ZS5zcGxpY2UoaW5kZXgsIDEpOwogICAgICAgICAgICB0aGlzLmVtaXQoJ2VsZW1lbnRSZW1vdmVkJywgeyBlbGVtLCBpbmRleCB9KTsKICAgICAgICAgICAgdGhpcy5lbWl0KCd2YWx1ZUNoYW5nZWQnKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogSW5zZXJ0cyBhIG5ldyBlbGVtZW50IGluIHRoZSBzcGVjaWZpZWQgaW5kZXguCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gaW5kZXggLSBUaGUgaW5kZXggdmFsdWUuCiAgICAgICAgICogQHBhcmFtIGVsZW0gLSBUaGUgZWxlbSB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBpbnNlcnRFbGVtZW50KGluZGV4LCBlbGVtKSB7CiAgICAgICAgICAgIGlmICghdGhpcy52YWx1ZSB8fCAhdGhpcy5maWx0ZXIoZWxlbSkpCiAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgIHRoaXMudmFsdWUuc3BsaWNlKGluZGV4LCAwLCBlbGVtKTsKICAgICAgICAgICAgdGhpcy5lbWl0KCdlbGVtZW50QWRkZWQnLCB7IGVsZW0sIGluZGV4IH0pOwogICAgICAgICAgICB0aGlzLmVtaXQoJ3ZhbHVlQ2hhbmdlZCcpOwogICAgICAgIH0KICAgICAgICBzZXRWYWx1ZSh2YWx1ZSkgewogICAgICAgICAgICBpZiAoIUFycmF5LmlzQXJyYXkodmFsdWUpKSB7CiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYHZhbHVlIHByb3ZpZGVkIGlzIG5vdCBhbiBhcnJheS4gQ2hlY2sgdGhlIHNvdXJjZSBvZiB0aGlzIHZhbHVlYCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgc3VwZXIuc2V0VmFsdWUodmFsdWUpOwogICAgICAgIH0KICAgICAgICAvLyAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCiAgICAgICAgLy8gUGVyc2lzdGVuY2UKICAgICAgICAvKioKICAgICAgICAgKiBUaGUgdG9KU09OIG1ldGhvZCBlbmNvZGVzIHRoaXMgdHlwZSBhcyBhIGpzb24gb2JqZWN0IGZvciBwZXJzaXN0ZW5jZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBjb250ZXh0IC0gVGhlIGNvbnRleHQgdmFsdWUuCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgdGhlIGpzb24gb2JqZWN0LgogICAgICAgICAqLwogICAgICAgIHRvSlNPTihjb250ZXh0KSB7CiAgICAgICAgICAgIGNvbnN0IGl0ZW1zID0gW107CiAgICAgICAgICAgIGlmICh0aGlzLnZhbHVlKSB7CiAgICAgICAgICAgICAgICBmb3IgKGNvbnN0IHAgb2YgdGhpcy52YWx1ZSkgewogICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgdGhpcy5kYXRhVHlwZSA9PT0gJ3N0cmluZycpCiAgICAgICAgICAgICAgICAgICAgICAgIGl0ZW1zLnB1c2gocCk7CiAgICAgICAgICAgICAgICAgICAgZWxzZQogICAgICAgICAgICAgICAgICAgICAgICBpdGVtcy5wdXNoKHAudG9KU09OKGNvbnRleHQpKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gewogICAgICAgICAgICAgICAgdHlwZTogdGhpcy5nZXRDbGFzc05hbWUoKSwKICAgICAgICAgICAgICAgIG5hbWU6IHRoaXMubmFtZSwKICAgICAgICAgICAgICAgIHZhbHVlOiBpdGVtcywKICAgICAgICAgICAgfTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGZyb21KU09OIG1ldGhvZCBkZWNvZGVzIGEganNvbiBvYmplY3QgZm9yIHRoaXMgdHlwZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBqIC0gVGhlIGpzb24gb2JqZWN0IHRoaXMgaXRlbSBtdXN0IGRlY29kZS4KICAgICAgICAgKiBAcGFyYW0gY29udGV4dCAtIFRoZSBjb250ZXh0IHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGZyb21KU09OKGosIGNvbnRleHQpIHsKICAgICAgICAgICAgaWYgKGouaXRlbXMgPT0gdW5kZWZpbmVkKSB7CiAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oJ0ludmFsaWQgUGFyYW1ldGVyIEpTT04nKTsKICAgICAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgICAgfQogICAgICAgICAgICBjb25zdCB2YWx1ZSA9IFtdOwogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGouaXRlbXMubGVuZ3RoOyBpKyspIHsKICAgICAgICAgICAgICAgIGxldCBlbGVtOwogICAgICAgICAgICAgICAgaWYgKHR5cGVvZiB0aGlzLmRhdGFUeXBlID09PSAnc3RyaW5nJykgewogICAgICAgICAgICAgICAgICAgIGVsZW0gPSBqLml0ZW1zW2ldOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgaWYgKCF0aGlzLmRhdGFUeXBlKQogICAgICAgICAgICAgICAgICAgICAgICB0aHJvdyAnTm8gRGF0YVR5cGUnOwogICAgICAgICAgICAgICAgICAgIGVsZW0gPSBSZWdpc3RyeS5jb25zdHJ1Y3RDbGFzcyh0aGlzLmRhdGFUeXBlKTsKICAgICAgICAgICAgICAgICAgICBlbGVtLmZyb21KU09OKGouaXRlbXNbaV0sIGNvbnRleHQpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgdmFsdWUucHVzaChlbGVtKTsKICAgICAgICAgICAgICAgIHRoaXMuZW1pdCgnZWxlbWVudEFkZGVkJywgeyBlbGVtLCBpbmRleDogdGhpcy52YWx1ZS5sZW5ndGggLSAxIH0pOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHRoaXMudmFsdWUgPSB2YWx1ZTsKICAgICAgICB9CiAgICAgICAgLy8gLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwogICAgICAgIC8vIENsb25lIGFuZCBEZXN0cm95CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGNsb25lIG1ldGhvZCBjb25zdHJ1Y3RzIGEgbmV3IGxpc3QgcGFyYW1ldGVyLCBjb3BpZXMgaXRzIHZhbHVlcwogICAgICAgICAqIGZyb20gdGhpcyBwYXJhbWV0ZXIgYW5kIHJldHVybnMgaXQuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyBhIG5ldyBsaXN0IHBhcmFtZXRlci4KICAgICAgICAgKi8KICAgICAgICBjbG9uZSgpIHsKICAgICAgICAgICAgY29uc3QgY2xvbmVkVmFsdWUgPSB0aGlzLnZhbHVlID8gdGhpcy52YWx1ZS5zbGljZSgwKSA6IFtdOwogICAgICAgICAgICBpZiAoIXRoaXMuZGF0YVR5cGUpCiAgICAgICAgICAgICAgICB0aHJvdyAnVGhpcyBwYXJhbWV0ZXIgZG9lcyBub3QgaGF2ZSBhIERhdGFUeXBlJzsKICAgICAgICAgICAgY29uc3QgY2xvbmVkUGFyYW0gPSBuZXcgTGlzdFBhcmFtZXRlcih0aGlzLm5hbWUsIHRoaXMuZGF0YVR5cGUpOwogICAgICAgICAgICBjbG9uZWRQYXJhbS5zZXRWYWx1ZShjbG9uZWRWYWx1ZSk7CiAgICAgICAgICAgIHJldHVybiBjbG9uZWRQYXJhbTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGRlc3Ryb3kgaXMgY2FsbGVkIGJ5IHRoZSBzeXN0ZW0gdG8gY2F1c2UgZXhwbGljaXQgcmVzb3VyY2VzIGNsZWFudXAuCiAgICAgICAgICogVXNlcnMgc2hvdWxkIG5ldmVyIG5lZWQgdG8gY2FsbCB0aGlzIG1ldGhvZCBkaXJlY3RseS4KICAgICAgICAgKi8KICAgICAgICBkZXN0cm95KCkgewogICAgICAgICAgICBpZiAoIXRoaXMudmFsdWUpCiAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy52YWx1ZS5sZW5ndGg7IGkrKykgewogICAgICAgICAgICAgICAgaWYgKHRoaXMudmFsdWVbaV0gaW5zdGFuY2VvZiBQYXJhbWV0ZXIpCiAgICAgICAgICAgICAgICAgICAgdGhpcy52YWx1ZVtpXS5kZXN0cm95KCk7CiAgICAgICAgICAgICAgICB0aGlzLnJlbW92ZUVsZW1lbnQoaSk7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9CiAgICBSZWdpc3RyeS5yZWdpc3RlcignTGlzdFBhcmFtZXRlcicsIExpc3RQYXJhbWV0ZXIpOwoKICAgIC8qIGVzbGludC1kaXNhYmxlIEB0eXBlc2NyaXB0LWVzbGludC9leHBsaWNpdC1tb2R1bGUtYm91bmRhcnktdHlwZXMgKi8KICAgIC8qKgogICAgICogUmVwcmVzZW50cyBhIHNwZWNpZmljIHR5cGUgb2YgcGFyYW1ldGVyLCB0aGF0IHN0b3JlcyBtdWx0aXBsZSBwYXJhbWV0ZXJzIGluIG9iamVjdCBmb3JtYXQuCiAgICAgKgogICAgICogaS5lLjoKICAgICAqIGBgYGphdmFzY3JpcHQKICAgICAqIGNvbnN0IHN0cnVjdFBhcmFtID0gbmV3IFN0cnVjdFBhcmFtZXRlcignTXlTdHJ1Y3RQYXJhbScpCiAgICAgKiAvLydteVBhcmFtZXRlck93bmVySXRlbScgaXMgYW4gaW5zdGFuY2Ugb2YgYSAnUGFyYW1ldGVyT3duZXInIGNsYXNzLgogICAgICogLy8gUmVtZW1iZXIgdGhhdCBvbmx5ICdQYXJhbWV0ZXJPd25lcicgYW5kIGNsYXNzZXMgdGhhdCBleHRlbmQgZnJvbSBpdCBjYW4gaG9zdCAnUGFyYW1ldGVyJyBvYmplY3RzLgogICAgICogbXlQYXJhbWV0ZXJPd25lckl0ZW0uYWRkUGFyYW1ldGVyKHN0cnVjdFBhcmFtKQogICAgICogYGBgCiAgICAgKgogICAgICogKipFdmVudHMqKgogICAgICogKiAqKnZhbHVlQ2hhbmdlZDoqKiBUcmlnZ2VyZWQgd2hlbmV2ZXIgcGFyYW1ldGVyJ3MgdmFsdWUgY2hhbmdlcy4KICAgICAqCiAgICAgKiBAZXh0ZW5kcyBQYXJhbWV0ZXIKICAgICAqLwogICAgY2xhc3MgU3RydWN0UGFyYW1ldGVyIGV4dGVuZHMgUGFyYW1ldGVyIHsKICAgICAgICBtZW1iZXJzOwogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZSBhIHN0cnVjdCBwYXJhbWV0ZXIuCiAgICAgICAgICogQHBhcmFtIG5hbWUgLSBUaGUgbmFtZSBvZiB0aGUgc3RydWN0IHBhcmFtZXRlci4KICAgICAgICAgKi8KICAgICAgICBjb25zdHJ1Y3RvcihuYW1lKSB7CiAgICAgICAgICAgIHN1cGVyKG5hbWUsIHt9LCAnU3RydWN0Jyk7CiAgICAgICAgICAgIHRoaXMubWVtYmVycyA9IFtdOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgX2FkZE1lbWJlciBtZXRob2QuCiAgICAgICAgICogQHBhcmFtIHBhcmFtZXRlciAtIFRoZSBwYXJhbWV0ZXIgdmFsdWUuCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICogQHByaXZhdGUKICAgICAgICAgKi8KICAgICAgICBhZGRNZW1iZXIocGFyYW1ldGVyKSB7CiAgICAgICAgICAgIGlmICh0aGlzLnZhbHVlKQogICAgICAgICAgICAgICAgdGhpcy52YWx1ZVtwYXJhbWV0ZXIuZ2V0TmFtZSgpXSA9IHBhcmFtZXRlci52YWx1ZTsKICAgICAgICAgICAgcGFyYW1ldGVyLm9uKCd2YWx1ZUNoYW5nZWQnLCAoKSA9PiB7CiAgICAgICAgICAgICAgICBpZiAodGhpcy52YWx1ZSkKICAgICAgICAgICAgICAgICAgICB0aGlzLnZhbHVlW3BhcmFtZXRlci5nZXROYW1lKCldID0gcGFyYW1ldGVyLnZhbHVlOwogICAgICAgICAgICB9KTsKICAgICAgICAgICAgdGhpcy5tZW1iZXJzLnB1c2gocGFyYW1ldGVyKTsKICAgICAgICAgICAgdGhpcy5lbWl0KCd2YWx1ZUNoYW5nZWQnKTsKICAgICAgICAgICAgcmV0dXJuIHBhcmFtZXRlcjsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGdldFBhcmFtZXRlciBtZXRob2QuCiAgICAgICAgICoKICAgICAgICAgKiBAcHJpdmF0ZQogICAgICAgICAqIEBwYXJhbSBuYW1lIC0gVGhlIHBhcmFtZXRlciBuYW1lLgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGdldFBhcmFtZXRlcihuYW1lKSB7CiAgICAgICAgICAgIGZvciAoY29uc3QgcCBvZiB0aGlzLm1lbWJlcnMpIHsKICAgICAgICAgICAgICAgIGlmIChwLmdldE5hbWUoKSA9PSBuYW1lKQogICAgICAgICAgICAgICAgICAgIHJldHVybiBwOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIExvb2tzIGZvciBhIG1lbWJlciBwYXJhbWV0ZXIgd2l0aCB0aGUgc3BlY2lmaWVkIG5hbWUgYW5kIHJldHVybnMgaXQuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gbmFtZSAtIFRoZSBwYXJhbWV0ZXIgbmFtZS4KICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBnZXRNZW1iZXIobmFtZSkgewogICAgICAgICAgICByZXR1cm4gdGhpcy5nZXRQYXJhbWV0ZXIobmFtZSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgdGhlIG5hbWUgb2YgYWxsIHBhcmFtZXRlcnMgaW4gU3RydWN0UGFyYW1ldGVyLgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgZ2V0TWVtYmVyTmFtZXMoKSB7CiAgICAgICAgICAgIGNvbnN0IG5hbWVzID0gW107CiAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5tZW1iZXJzLmxlbmd0aDsgaSsrKSB7CiAgICAgICAgICAgICAgICBjb25zdCBtZW1iZXIgPSB0aGlzLm1lbWJlcnNbaV07CiAgICAgICAgICAgICAgICBpZiAobWVtYmVyICE9IG51bGwpCiAgICAgICAgICAgICAgICAgICAgbmFtZXNbaV0gPSBtZW1iZXIuZ2V0TmFtZSgpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBuYW1lczsKICAgICAgICB9CiAgICAgICAgLy8gLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwogICAgICAgIC8vIFBlcnNpc3RlbmNlCiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIHRvSlNPTiBtZXRob2QgZW5jb2RlcyB0aGlzIHR5cGUgYXMgYSBqc29uIG9iamVjdCBmb3IgcGVyc2lzdGVuY2UuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gY29udGV4dCAtIFRoZSBjb250ZXh0IHZhbHVlLgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIHRoZSBqc29uIG9iamVjdC4KICAgICAgICAgKi8KICAgICAgICB0b0pTT04oY29udGV4dCkgewogICAgICAgICAgICBjb25zdCBtZW1iZXJzID0gW107CiAgICAgICAgICAgIGZvciAoY29uc3QgcCBvZiB0aGlzLm1lbWJlcnMpCiAgICAgICAgICAgICAgICBtZW1iZXJzLnB1c2gocC50b0pTT04oY29udGV4dCkpOwogICAgICAgICAgICByZXR1cm4geyB0eXBlOiB0aGlzLmdldENsYXNzTmFtZSgpLCBuYW1lOiB0aGlzLm5hbWUsIG1lbWJlcnMgfTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGZyb21KU09OIG1ldGhvZCBkZWNvZGVzIGEganNvbiBvYmplY3QgZm9yIHRoaXMgdHlwZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBqIC0gVGhlIGpzb24gb2JqZWN0IHRoaXMgaXRlbSBtdXN0IGRlY29kZS4KICAgICAgICAgKiBAcGFyYW0gY29udGV4dCAtIFRoZSBjb250ZXh0IHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGZyb21KU09OKGosIGNvbnRleHQpIHsKICAgICAgICAgICAgaWYgKGoubWVtYmVycyA9PSB1bmRlZmluZWQpIHsKICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybignSW52YWxpZCBQYXJhbWV0ZXIgSlNPTicpOwogICAgICAgICAgICAgICAgcmV0dXJuOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgai5tZW1iZXJzLmxlbmd0aDsgaSsrKSB7CiAgICAgICAgICAgICAgICBpZiAoai5tZW1iZXJzW2ldKSB7CiAgICAgICAgICAgICAgICAgICAgdGhpcy5tZW1iZXJzW2ldLmZyb21KU09OKGoubWVtYmVyc1tpXSwgY29udGV4dCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdGhpcy5uYW1lID0gai5uYW1lOwogICAgICAgIH0KICAgICAgICBjbG9uZSgpIHsKICAgICAgICAgICAgY29uc3QgY2xvbmVkUGFyYW0gPSBuZXcgU3RydWN0UGFyYW1ldGVyKHRoaXMubmFtZSk7CiAgICAgICAgICAgIHJldHVybiBjbG9uZWRQYXJhbTsKICAgICAgICB9CiAgICAgICAgLy8gLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwogICAgICAgIC8vIERlc3Ryb3kKICAgICAgICAvKioKICAgICAgICAgKiBUaGUgZGVzdHJveSBpcyBjYWxsZWQgYnkgdGhlIHN5c3RlbSB0byBjYXVzZSBleHBsaWNpdCByZXNvdXJjZXMgY2xlYW51cC4KICAgICAgICAgKiBVc2VycyBzaG91bGQgbmV2ZXIgbmVlZCB0byBjYWxsIHRoaXMgbWV0aG9kIGRpcmVjdGx5LgogICAgICAgICAqLwogICAgICAgIGRlc3Ryb3koKSB7CiAgICAgICAgICAgIGZvciAoY29uc3QgcCBvZiB0aGlzLm1lbWJlcnMpIHsKICAgICAgICAgICAgICAgIC8vIFRPRE86IG5vdCBzdXJlIGFib3V0IHRoaXMuIEkgYWRkZWQgYSBkby1ub3RoaW5nIGRlc3Ryb3kgbWV0aG9kIGluIFBhcmFtZXRlcjxUPiB0byBiZSBvdmVyd3JpdHRlbgogICAgICAgICAgICAgICAgLy8gc2luY2Ugb25seSBzb21lIHN1YmNsYXNzZXMgdXNlIGRlc3Ryb3kuCiAgICAgICAgICAgICAgICBwLmRlc3Ryb3koKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KICAgIFJlZ2lzdHJ5LnJlZ2lzdGVyKCdTdHJ1Y3RQYXJhbWV0ZXInLCBTdHJ1Y3RQYXJhbWV0ZXIpOwoKICAgIC8qKiBDbGFzcyByZXByZXNlbnRpbmcgYW4gb3BlcmF0b3Igb3V0cHV0LgogICAgICogQGV4dGVuZHMgRXZlbnRFbWl0dGVyCiAgICAgKi8KICAgIGNsYXNzIE9wZXJhdG9yT3V0cHV0IHsKICAgICAgICBuYW1lOwogICAgICAgIG1vZGU7CiAgICAgICAgb3AgPSBudWxsOwogICAgICAgIHBhcmFtOwogICAgICAgIHBhcmFtQmluZEluZGV4OwogICAgICAgIGRldGFjaGVkOwogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZSBhbiBvcGVyYXRvciBvdXRwdXQuCiAgICAgICAgICogQHBhcmFtIG5hbWUgLSBUaGUgbmFtZSB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0gb3BlcmF0b3JPdXRwdXRNb2RlIC0gVGhlIG1vZGUgd2hpY2ggdGhlIE9wZXJhdG9yT3V0cHV0IHVzZXMgdG8gYmluZCB0byBpdHMgdGFyZ2V0IHBhcmFtZXRlci4KICAgICAgICAgKi8KICAgICAgICBjb25zdHJ1Y3RvcihuYW1lLCBvcGVyYXRvck91dHB1dE1vZGUgPSBPcGVyYXRvck91dHB1dE1vZGUuT1BfV1JJVEUpIHsKICAgICAgICAgICAgdGhpcy5uYW1lID0gbmFtZTsKICAgICAgICAgICAgdGhpcy5tb2RlID0gb3BlcmF0b3JPdXRwdXRNb2RlOwogICAgICAgICAgICB0aGlzLnBhcmFtID0gdW5kZWZpbmVkOwogICAgICAgICAgICB0aGlzLnBhcmFtQmluZEluZGV4ID0gLTE7CiAgICAgICAgICAgIHRoaXMuZGV0YWNoZWQgPSBmYWxzZTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU2V0cyBvcGVyYXRvciB0aGF0IG93bnMgdGhpcyBvdXRwdXQuIENhbGxlZCBieSB0aGUgb3BlcmF0b3Igd2hlbiBhZGRpbmcgb3V0cHV0cwogICAgICAgICAqIEBwYXJhbSBvcCAtIFRoZSBvcGVyYXRvciBvYmplY3QuCiAgICAgICAgICovCiAgICAgICAgc2V0T3BlcmF0b3Iob3ApIHsKICAgICAgICAgICAgdGhpcy5vcCA9IG9wOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIG9wZXJhdG9yIHRoYXQgb3ducyB0aGlzIG91dHB1dC4KICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIG9wZXJhdG9yIG9iamVjdC4KICAgICAgICAgKi8KICAgICAgICBnZXRPcGVyYXRvcigpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMub3A7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgbW9kZSB0aGF0IHRoZSBvdXRwdXQgd3JpdGVzIHRvIGJlIHBhcmFtZXRlci4gTXVzdCBiZSBhIG51bWJlciBmcm9tIE9wZXJhdG9yT3V0cHV0TW9kZQogICAgICAgICAqIEByZXR1cm4gLSBUaGUgbW9kZSB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBnZXRNb2RlKCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy5tb2RlOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIHRydWUgaWYgdGhpcyBvdXRwdXQgaXMgY29ubmVjdGVkIHRvIGEgcGFyYW1ldGVyLgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGlzQ29ubmVjdGVkKCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy5wYXJhbSAhPSB1bmRlZmluZWQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBnZXRQYXJhbSBtZXRob2QuCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgZ2V0UGFyYW0oKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLnBhcmFtOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTZXRzIHRoZSBQYXJhbWV0ZXIgZm9yIHRoaXMgb3V0cHV0IHRvIHdyaXRlIHRvLgogICAgICAgICAqIEBwYXJhbSBwYXJhbSAtIFRoZSBwYXJhbSB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0gaW5kZXggLSBUaGUgaW5kZXggdG8gYmluZCBhdCBpbiB0aGUgUGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIHNldFBhcmFtKHBhcmFtLCBpbmRleCA9IC0xKSB7CiAgICAgICAgICAgIGlmICh0aGlzLnBhcmFtKSB7CiAgICAgICAgICAgICAgICB0aGlzLnBhcmFtLnVuYmluZE9wZXJhdG9yT3V0cHV0KHRoaXMpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHRoaXMucGFyYW0gPSBwYXJhbTsKICAgICAgICAgICAgaWYgKHRoaXMucGFyYW0pIHsKICAgICAgICAgICAgICAgIHRoaXMucGFyYW1CaW5kSW5kZXggPSB0aGlzLnBhcmFtLmJpbmRPcGVyYXRvck91dHB1dCh0aGlzLCBpbmRleCk7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyB0aGUgaW5kZXggb2YgdGhlIGJpbmRpbmcgb24gdGhlIHBhcmFtZXRlciBvZiB0aGlzIE9wZXJhdG9yT3V0cHV0CiAgICAgICAgICogdXAgdG8gZGF0ZS4KICAgICAgICAgKiBAcmV0dXJuIGluZGV4IC0gVGhlIGluZGV4IG9mIHRoZSBiaW5kaW5nIG9uIHRoZSBwYXJhbWV0ZXIuCiAgICAgICAgICovCiAgICAgICAgZ2V0UGFyYW1CaW5kSW5kZXgoKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLnBhcmFtQmluZEluZGV4OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBJZiBiaW5kaW5ncyBjaGFuZ2Ugb24gYSBQYXJhbWV0ZXIsIGl0IHdpbGwgY2FsbCB0aGlzIG1ldGhvZCB0byBlbnN1cmUgdGhlIG91dHB1dCBpbmRleCBpcwogICAgICAgICAqIHVwIHRvIGRhdGUuCiAgICAgICAgICogQHBhcmFtIGluZGV4IC0gVGhlIGluZGV4IG9mIHRoZSBiaW5kaW5nIG9uIHRoZSBwYXJhbWV0ZXIuCiAgICAgICAgICovCiAgICAgICAgc2V0UGFyYW1CaW5kSW5kZXgoaW5kZXgpIHsKICAgICAgICAgICAgdGhpcy5wYXJhbUJpbmRJbmRleCA9IGluZGV4OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBQcm9wYWdhdGVzIGRpcnR5IHRvIHRoZSBjb25uZWN0ZWQgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIHNldERpcnR5KCkgewogICAgICAgICAgICBpZiAodGhpcy5wYXJhbSkgewogICAgICAgICAgICAgICAgdGhpcy5wYXJhbS5zZXREaXJ0eSh0aGlzLnBhcmFtQmluZEluZGV4KTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgZ2V0VmFsdWUgbWV0aG9kLgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGdldFZhbHVlKCkgewogICAgICAgICAgICBpZiAodGhpcy5wYXJhbSkgewogICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMucGFyYW0uZ2V0VmFsdWVGcm9tT3AodGhpcy5wYXJhbUJpbmRJbmRleCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZWxzZSB7CiAgICAgICAgICAgICAgICAvLyBAdHMtZXhwZWN0LWVycm9yIHRzLW1pZ3JhdGUoMjU1NCkgRklYTUU6IEV4cGVjdGVkIDAtMSBhcmd1bWVudHMsIGJ1dCBnb3QgMi4KICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignQ2Fubm90IGNhbGwgZ2V0VmFsdWUgb24gT3BlcmF0b3JPdXRwdXQgdGhhdCBpcyBub3QgY29ubmVjdGVkOicsIHRoaXMubmFtZSk7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogV2hlbiB0aGUgdmFsdWUgb24gYSBQYXJhbWV0ZXIgaXMgbW9kaWZpZWQgYnkgYSB1c2VyIGJ5IGNhbGxpbmcgJ3NldFZhbHVlLAogICAgICAgICAqIHRoZW4gaWYgYW55IG9wZXJhdG9ycyBhcmUgYm91bmQsIHRoZSB2YWx1ZSBvZiB0aGUgUGFyYW1ldGVyIGNhbm5vdCBiZSBtb2RpZmllZAogICAgICAgICAqIGRpcmVjdGx5IGFzIGl0IGlzIHRoZSByZXN1bHQgb2YgYSBjb21wdXRhdGlvbi4gSW5zdGVhZCwgdGhlIFBhcmFtZXRlciBjYWxscwogICAgICAgICAqICdiYWNrUHJvcGFnYXRlVmFsdWUnIG9uIHRoZSBPcGVyYXRvciB0byBjYXVzZSB0aGUgT3BlcmF0b3IgdG8gaGFuZGxlIHByb3BhZ2F0aW5nCiAgICAgICAgICogdGhlIHZhbHVlIHRvIG9uZSBvciBtb3JlIG9mIGl0cyBpbnB1dHMuCiAgICAgICAgICogdG8gaXRzIGlucHV0cy4KICAgICAgICAgKiBAcGFyYW0gdmFsdWUgLSBUaGUgdmFsdWUgcGFyYW0uCiAgICAgICAgICogQHJldHVybiAtIFRoZSBtb2RpZmllZCB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBiYWNrUHJvcGFnYXRlVmFsdWUodmFsdWUpIHsKICAgICAgICAgICAgaWYgKHRoaXMub3ApIHsKICAgICAgICAgICAgICAgIHZhbHVlID0gdGhpcy5vcC5iYWNrUHJvcGFnYXRlVmFsdWUodmFsdWUpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiB2YWx1ZTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIHNldENsZWFuIG1ldGhvZC4KICAgICAgICAgKiBAcGFyYW0gdmFsdWUgLSBUaGUgdmFsdWUgcGFyYW0uCiAgICAgICAgICovCiAgICAgICAgc2V0Q2xlYW4odmFsdWUpIHsKICAgICAgICAgICAgaWYgKHRoaXMucGFyYW0pIHsKICAgICAgICAgICAgICAgIHRoaXMucGFyYW0uc2V0Q2xlYW5Gcm9tT3AodmFsdWUsIHRoaXMucGFyYW1CaW5kSW5kZXgpOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIC8vIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KICAgICAgICAvLyBQZXJzaXN0ZW5jZQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSB0b0pTT04gbWV0aG9kIGVuY29kZXMgdGhpcyB0eXBlIGFzIGEganNvbiBvYmplY3QgZm9yIHBlcnNpc3RlbmNlLgogICAgICAgICAqIEBwYXJhbSBjb250ZXh0IC0gVGhlIGNvbnRleHQgdmFsdWUuCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgdGhlIGpzb24gb2JqZWN0LgogICAgICAgICAqLwogICAgICAgIHRvSlNPTihjb250ZXh0KSB7CiAgICAgICAgICAgIGNvbnN0IHBhcmFtUGF0aCA9IHRoaXMucGFyYW0gPyB0aGlzLnBhcmFtLmdldFBhdGgoKSA6ICcnOwogICAgICAgICAgICByZXR1cm4gewogICAgICAgICAgICAgICAgbmFtZTogdGhpcy5uYW1lLAogICAgICAgICAgICAgICAgcGFyYW1QYXRoOiBjb250ZXh0ICYmIGNvbnRleHQubWFrZVJlbGF0aXZlID8gY29udGV4dC5tYWtlUmVsYXRpdmUocGFyYW1QYXRoKSA6IHBhcmFtUGF0aCwKICAgICAgICAgICAgICAgIHBhcmFtQmluZEluZGV4OiB0aGlzLnBhcmFtQmluZEluZGV4LAogICAgICAgICAgICB9OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgZnJvbUpTT04gbWV0aG9kIGRlY29kZXMgYSBqc29uIG9iamVjdCBmb3IgdGhpcyB0eXBlLgogICAgICAgICAqIEBwYXJhbSBqIC0gVGhlIGpzb24gb2JqZWN0IHRoaXMgaXRlbSBtdXN0IGRlY29kZS4KICAgICAgICAgKiBAcGFyYW0gY29udGV4dCAtIFRoZSBjb250ZXh0IHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGZyb21KU09OKGosIGNvbnRleHQpIHsKICAgICAgICAgICAgaWYgKGoucGFyYW1QYXRoKSB7CiAgICAgICAgICAgICAgICAvLyBOb3RlOiB0aGUgdHJlZSBzaG91bGQgaGF2ZSBmdWxseSBsb2FkZWQgYnkgdGhlIHRpbWUgd2UgYXJlIGxvYWRpbmcgb3BlcmF0b3JzCiAgICAgICAgICAgICAgICAvLyBldmVuIG5ldyBpdGVtcyBhbmQgZ3JvdXBzIHNob3VsZCBoYXZlIGJlZW4gY3JlYXRlZC4gT3BlcmF0b3JzIGFuZCBzdGF0ZSBtYWNoaW5lcwogICAgICAgICAgICAgICAgLy8gYXJlIGxvYWRlZCBsYXN0LgogICAgICAgICAgICAgICAgY29udGV4dD8ucmVzb2x2ZVBhdGgoai5wYXJhbVBhdGgsIChwYXJhbSkgPT4gewogICAgICAgICAgICAgICAgICAgIHRoaXMuc2V0UGFyYW0ocGFyYW0sIGoucGFyYW1CaW5kSW5kZXgpOwogICAgICAgICAgICAgICAgfSwgKHJlYXNvbikgPT4gewogICAgICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybigiT3BlcmF0b3JPdXRwdXQ6ICciICsgdGhpcy5uYW1lICsgIicuIFVuYWJsZSB0byBjb25uZWN0IHRvOiIgKyBqLnBhcmFtUGF0aCk7CiAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgZGV0YWNoIG1ldGhvZCBpcyBjYWxsZWQgd2hlbiBhbiBvcGVyYXRvciBpcyBiZWluZyByZW1vdmVkIGZyb20gdGhlIHNjZW5lIHRyZWUuCiAgICAgICAgICogSXQgcmVtb3ZlcyBhbGwgY29ubmVjdGlvbnMgdG8gcGFyYW1ldGVycyBpbiB0aGUgc2NlbmUuCiAgICAgICAgICovCiAgICAgICAgZGV0YWNoKCkgewogICAgICAgICAgICAvLyBUaGlzIGZ1bmN0aW9uIGlzIGNhbGxlZCB3aGVuIHdlIHdhbnQgdG8gc3VzcGVuZCBhbiBvcGVyYXRvcgogICAgICAgICAgICAvLyBmcm9tIGZ1bmN0aW9uaW5nIGJlY2F1c2UgaXQgaXMgZGVsZXRlZCBhbmQgb24gdGhlIHVuZG8gc3RhY2suCiAgICAgICAgICAgIC8vIE9uY2Ugb3BlcmF0b3JzIGhhdmUgcGVyc2lzdGVudCBjb25uZWN0aW9ucywKICAgICAgICAgICAgLy8gd2Ugd2lsbCBzaW1wbHkgdW5pbnN0YWxsIHRoZSBvdXRwdXQgZnJvbSB0aGUgcGFyYW1ldGVyLgogICAgICAgICAgICB0aGlzLmRldGFjaGVkID0gdHJ1ZTsKICAgICAgICAgICAgdGhpcy5wYXJhbUJpbmRJbmRleCA9IHRoaXMucGFyYW0gPyB0aGlzLnBhcmFtLnVuYmluZE9wZXJhdG9yT3V0cHV0KHRoaXMpIDogLTE7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSByZWF0dGFjaCBtZXRob2QgY2FuIGJlIGNhbGxlZCB3aGVuIHJlLWluc3RhdGluZyBhbiBvcGVyYXRvciBpbiB0aGUgc2NlbmUuCiAgICAgICAgICovCiAgICAgICAgcmVhdHRhY2goKSB7CiAgICAgICAgICAgIHRoaXMuZGV0YWNoZWQgPSBmYWxzZTsKICAgICAgICAgICAgaWYgKHRoaXMucGFyYW0pIHsKICAgICAgICAgICAgICAgIHRoaXMucGFyYW1CaW5kSW5kZXggPSB0aGlzLnBhcmFtLmJpbmRPcGVyYXRvck91dHB1dCh0aGlzLCB0aGlzLnBhcmFtQmluZEluZGV4KTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgcmViaW5kIHJlYmluZHMgdGhlIG91dHB1dHMgdG8gYmUgYXQgdGhlIHRvcCBvZiB0aGUgc3RhY2sgZm9yIGl0cyBwYXJhbWV0ZXIuCiAgICAgICAgICovCiAgICAgICAgcmViaW5kKCkgewogICAgICAgICAgICBpZiAodGhpcy5wYXJhbSkgewogICAgICAgICAgICAgICAgdGhpcy5wYXJhbS51bmJpbmRPcGVyYXRvck91dHB1dCh0aGlzKTsKICAgICAgICAgICAgICAgIHRoaXMucGFyYW1CaW5kSW5kZXggPSB0aGlzLnBhcmFtLmJpbmRPcGVyYXRvck91dHB1dCh0aGlzKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KICAgIGNsYXNzIFhmb09wZXJhdG9yT3V0cHV0IGV4dGVuZHMgT3BlcmF0b3JPdXRwdXQgewogICAgfQoKICAgIC8qKgogICAgICogQ2xhc3MgcmVwcmVzZW50aW5nIGFuIG9wZXJhdG9yLgogICAgICoKICAgICAqLwogICAgY2xhc3MgT3BlcmF0b3IgewogICAgICAgIG5hbWU7CiAgICAgICAgaW5wdXRzOwogICAgICAgIG91dHB1dHM7CiAgICAgICAgLyoqCiAgICAgICAgICogQ3JlYXRlIGFuIG9wZXJhdG9yLgogICAgICAgICAqIEBwYXJhbSBuYW1lIC0gVGhlIG5hbWUgdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgY29uc3RydWN0b3IobmFtZSA9ICcnKSB7CiAgICAgICAgICAgIHRoaXMubmFtZSA9IG5hbWU7CiAgICAgICAgICAgIHRoaXMuaW5wdXRzID0gbmV3IE1hcCgpOwogICAgICAgICAgICB0aGlzLm91dHB1dHMgPSBuZXcgTWFwKCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRoaXMgbWV0aG9kIHNldHMgdGhlIHN0YXRlIG9mIHRoZSBvcGVyYXRvciB0byBkaXJ0eSB3aGljaCBwcm9wYWdhdGVzCiAgICAgICAgICogdG8gdGhlIG91dHB1dHMgb2YgdGhpcyBvcGVyYXRvciwgYW5kIHdoaWNoIG1heSB0aGVuIHByb3BhZ2F0ZSB0byBvdGhlcgogICAgICAgICAqIG9wZXJhdG9ycy4gV2hlbiB0aGUgc2NlbmUgaXMgY2xlYW5lZCwgd2hpY2ggdXN1YWxseSBpcyBjYXVzZWQgYnkgcmVuZGVyaW5nCiAgICAgICAgICogdGhlbiB0aGUgY2hhaW4gb2Ygb3BlcmF0b3JzIGFyZSBjbGVhbmVkIGJ5IHRyaWdnZXJpbmcgZXZhbHVhdGlvbi4KICAgICAgICAgKiBAcHJpdmF0ZQogICAgICAgICAqLwogICAgICAgIHNldERpcnR5KCkgewogICAgICAgICAgICB0aGlzLm91dHB1dHMuZm9yRWFjaCgob3V0cHV0KSA9PiBvdXRwdXQuc2V0RGlydHkoKSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBhZGRJbnB1dCBtZXRob2QuCiAgICAgICAgICogQHBhcmFtIGlucHV0IC0gVGhlIG5hbWUgb2YgdGhlIGlucHV0LCBvciB0aGUgaW5wdXQgb2JqZWN0CiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgYWRkSW5wdXQoaW5wdXQpIHsKICAgICAgICAgICAgaW5wdXQuc2V0T3BlcmF0b3IodGhpcyk7CiAgICAgICAgICAgIHRoaXMuaW5wdXRzLnNldChpbnB1dC5uYW1lLCBpbnB1dCk7CiAgICAgICAgICAgIHRoaXMuc2V0RGlydHkoKTsKICAgICAgICAgICAgcmV0dXJuIGlucHV0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgcmVtb3ZlSW5wdXQgbWV0aG9kLgogICAgICAgICAqIEBwYXJhbSBpbnB1dCAtIFRoZSBuYW1lIG9mIHRoZSBpbnB1dCwgb3IgdGhlIGlucHV0IG9iamVjdAogICAgICAgICAqLwogICAgICAgIHJlbW92ZUlucHV0KGlucHV0KSB7CiAgICAgICAgICAgIGlmICh0eXBlb2YgaW5wdXQgPT0gJ3N0cmluZycpCiAgICAgICAgICAgICAgICBpbnB1dCA9IHRoaXMuZ2V0SW5wdXQoaW5wdXQpOwogICAgICAgICAgICBpZiAoaW5wdXQuZ2V0UGFyYW0oKSkKICAgICAgICAgICAgICAgIGlucHV0LnNldFBhcmFtKHVuZGVmaW5lZCk7CiAgICAgICAgICAgIHRoaXMuaW5wdXRzLmRlbGV0ZShpbnB1dC5uYW1lKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogR2V0dGVyIGZvciB0aGUgbnVtYmVyIG9mIGlucHV0cyBpbiB0aGlzIG9wZXJhdG9yLgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIHRoZSBudW1iZXIgb2YgaW5wdXRzLgogICAgICAgICAqLwogICAgICAgIGdldE51bUlucHV0cygpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuaW5wdXRzLnNpemU7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBnZXRJbnB1dEJ5SW5kZXggbWV0aG9kLgogICAgICAgICAqIEBwYXJhbSBpbmRleCAtIFRoZSBpbmRleCB2YWx1ZS4KICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBnZXRJbnB1dEJ5SW5kZXgoaW5kZXgpIHsKICAgICAgICAgICAgcmV0dXJuIEFycmF5LmZyb20odGhpcy5pbnB1dHMudmFsdWVzKCkpW2luZGV4XTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGdldElucHV0IG1ldGhvZC4KICAgICAgICAgKiBAcGFyYW0gbmFtZSAtIFRoZSBuYW1lIHZhbHVlLgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGdldElucHV0KG5hbWUpIHsKICAgICAgICAgICAgY29uc3QgaW5wdXQgPSB0aGlzLmlucHV0cy5nZXQobmFtZSk7CiAgICAgICAgICAgIGlmICghaW5wdXQpCiAgICAgICAgICAgICAgICB0aHJvdyBgQ291bGRuJ3QgZmluZCBhbiBJbnB1dCB3aXRoIHRoZSBuYW1lIG9mICcke25hbWV9J2A7CiAgICAgICAgICAgIHJldHVybiBpbnB1dDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGFkZE91dHB1dCBtZXRob2QuCiAgICAgICAgICogQHBhcmFtIG91dHB1dCAtIFRoZSBuYW1lIG9mIHRoZSBvdXRwdXQsIG9yIHRoZSBvdXRwdXQgb2JqZWN0CiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgYWRkT3V0cHV0KG91dHB1dCkgewogICAgICAgICAgICBvdXRwdXQuc2V0T3BlcmF0b3IodGhpcyk7CiAgICAgICAgICAgIC8vIGlmICh0aGlzLmdldE91dHB1dChvdXRwdXQubmFtZSkpIHRocm93IG5ldyBFcnJvcihgT3BlcmF0b3Igb3V0cHV0IGFscmVhZHkgZXhpc3RzICR7b3V0cHV0Lm5hbWV9YCkKICAgICAgICAgICAgdGhpcy5vdXRwdXRzLnNldChvdXRwdXQubmFtZSwgb3V0cHV0KTsKICAgICAgICAgICAgdGhpcy5zZXREaXJ0eSgpOwogICAgICAgICAgICByZXR1cm4gb3V0cHV0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgcmVtb3ZlT3V0cHV0IG1ldGhvZC4KICAgICAgICAgKiBAcGFyYW0gb3V0cHV0IC0gVGhlIG5hbWUgb2YgdGhlIG91dHB1dCwgb3IgdGhlIG91dHB1dCBvYmplY3QKICAgICAgICAgKi8KICAgICAgICByZW1vdmVPdXRwdXQob3V0cHV0KSB7CiAgICAgICAgICAgIGlmICh0eXBlb2Ygb3V0cHV0ID09ICdzdHJpbmcnKQogICAgICAgICAgICAgICAgb3V0cHV0ID0gdGhpcy5nZXRPdXRwdXQob3V0cHV0KTsKICAgICAgICAgICAgaWYgKCEob3V0cHV0IGluc3RhbmNlb2YgT3BlcmF0b3JPdXRwdXQpKSB7CiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYHJlbW92ZU91dHB1dCBvbmx5IGFjY2VwdHMgc3RyaW5nIG9yIE9wZXJhdG9ySW5wdXRgKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAob3V0cHV0LmdldFBhcmFtKCkpCiAgICAgICAgICAgICAgICBvdXRwdXQuc2V0UGFyYW0oKTsKICAgICAgICAgICAgdGhpcy5vdXRwdXRzLmRlbGV0ZShvdXRwdXQubmFtZSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEdldHRlciBmb3IgdGhlIG51bWJlciBvZiBvdXRwdXRzIGluIHRoaXMgb3BlcmF0b3IuCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgdGhlIG51bWJlciBvZiBvdXRwdXRzLgogICAgICAgICAqLwogICAgICAgIGdldE51bU91dHB1dHMoKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLm91dHB1dHMuc2l6ZTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGdldE91dHB1dEJ5SW5kZXggbWV0aG9kLgogICAgICAgICAqIEBwYXJhbSBpbmRleCAtIFRoZSBpbmRleCB2YWx1ZS4KICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBnZXRPdXRwdXRCeUluZGV4KGluZGV4KSB7CiAgICAgICAgICAgIHJldHVybiBBcnJheS5mcm9tKHRoaXMub3V0cHV0cy52YWx1ZXMoKSlbaW5kZXhdOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgZ2V0T3V0cHV0IG1ldGhvZC4KICAgICAgICAgKiBAcGFyYW0gbmFtZSAtIFRoZSBuYW1lIHZhbHVlLgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGdldE91dHB1dChuYW1lKSB7CiAgICAgICAgICAgIGNvbnN0IG91dHB1dCA9IHRoaXMub3V0cHV0cy5nZXQobmFtZSk7CiAgICAgICAgICAgIGlmICghb3V0cHV0KQogICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBDb3VsZG4ndCBmaW5kIGFuIE91dHB1dCB3aXRoIHRoZSBuYW1lIG9mICcke25hbWV9J2ApOwogICAgICAgICAgICByZXR1cm4gb3V0cHV0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgZXZhbHVhdGUgbWV0aG9kLgogICAgICAgICAqIENvbXB1dGVzIHRoZSB2YWx1ZXMgb2YgZWFjaCBvZiB0aGUgb3V0cHV0cyBiYXNlZCBvbiB0aGUgdmFsdWVzIG9mIHRoZSBpbnB1dHMKICAgICAgICAgKiBhbmQgdGhlIHZhbHVlcyBvZiBvdXRwdXRzIHdpdGggbW9kZSBPUF9SRUFEX1dSSVRFLgogICAgICAgICAqIFRoaXMgbWV0aG9kIG11c3QgYmUgaW1wbGVtZW50ZWQgYnkgYWxsIE9wZXJhdG9ycy4KICAgICAgICAgKi8KICAgICAgICBldmFsdWF0ZSgpIHsKICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdOb3QgeWV0IGltcGxlbWVudGVkJyk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFdoZW4gdGhlIHZhbHVlIG9uIGEgUGFyYW1ldGVyIGlzIG1vZGlmaWVkIGJ5IGEgdXNlciBieSBjYWxsaW5nICdzZXRWYWx1ZSwKICAgICAgICAgKiB0aGVuIGlmIGFueSBvcGVyYXRvcnMgYXJlIGJvdW5kLCB0aGUgdmFsdWUgb2YgdGhlIFBhcmFtZXRlciBjYW5ub3QgYmUgbW9kaWZpZWQKICAgICAgICAgKiBkaXJlY3RseSBhcyBpdCBpcyB0aGUgcmVzdWx0IG9mIGEgY29tcHV0YXRpb24uIEluc3RlYWQsIHRoZSBQYXJhbWV0ZXIgY2FsbHMKICAgICAgICAgKiAnYmFja1Byb3BhZ2F0ZVZhbHVlJyBvbiB0aGUgT3BlcmF0b3IgdG8gY2F1c2UgdGhlIE9wZXJhdG9yIHRvIGhhbmRsZSBwcm9wYWdhdGluZwogICAgICAgICAqIHRoZSB2YWx1ZSB0byBvbmUgb3IgbW9yZSBvZiBpdHMgaW5wdXRzLgogICAgICAgICAqIHRvIGl0cyBpbnB1dHMuCiAgICAgICAgICogQHBhcmFtIHZhbHVlIC0gVGhlIHZhbHVlIHBhcmFtLgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgbW9kaWZpZWQgdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgYmFja1Byb3BhZ2F0ZVZhbHVlKHZhbHVlKSB7CiAgICAgICAgICAgIC8vIFRPRE86IEltcGxlbWVudCBtZSBmb3IgY3VzdG9tIG1hbmlwdWxhdGlvbnMuCiAgICAgICAgICAgIHJldHVybiB2YWx1ZTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGRldGFjaCBtZXRob2QuCiAgICAgICAgICovCiAgICAgICAgZGV0YWNoKCkgewogICAgICAgICAgICB0aGlzLmlucHV0cy5mb3JFYWNoKChpbnB1dCkgPT4gaW5wdXQuZGV0YWNoKCkpOwogICAgICAgICAgICB0aGlzLm91dHB1dHMuZm9yRWFjaCgob3V0cHV0KSA9PiBvdXRwdXQuZGV0YWNoKCkpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgcmVhdHRhY2ggbWV0aG9kLgogICAgICAgICAqLwogICAgICAgIHJlYXR0YWNoKCkgewogICAgICAgICAgICB0aGlzLmlucHV0cy5mb3JFYWNoKChpbnB1dCkgPT4gaW5wdXQucmVhdHRhY2goKSk7CiAgICAgICAgICAgIHRoaXMub3V0cHV0cy5mb3JFYWNoKChvdXRwdXQpID0+IG91dHB1dC5yZWF0dGFjaCgpKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIHJlYmluZCBtZXRob2QuCiAgICAgICAgICovCiAgICAgICAgcmViaW5kKCkgewogICAgICAgICAgICB0aGlzLm91dHB1dHMuZm9yRWFjaCgob3V0cHV0KSA9PiBvdXRwdXQucmViaW5kKCkpOwogICAgICAgIH0KICAgIH0KCiAgICAvKiogQ2xhc3MgcmVwcmVzZW50aW5nIGFuIG9wZXJhdG9yIGlucHV0LgogICAgICogQGV4dGVuZHMgRXZlbnRFbWl0dGVyCiAgICAgKi8KICAgIGNsYXNzIE9wZXJhdG9ySW5wdXQgewogICAgICAgIG5hbWU7CiAgICAgICAgb3A7CiAgICAgICAgcGFyYW07CiAgICAgICAgZGV0YWNoZWQgPSBmYWxzZTsKICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGUgYW4gb3BlcmF0b3IgaW5wdXQuCiAgICAgICAgICogQHBhcmFtIG5hbWUgLSBUaGUgbmFtZSB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBjb25zdHJ1Y3RvcihuYW1lKSB7CiAgICAgICAgICAgIHRoaXMubmFtZSA9IG5hbWU7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFNldHMgb3BlcmF0b3IgdGhhdCBvd25zIHRoaXMgaW5wdXQuIENhbGxlZCBieSB0aGUgb3BlcmF0b3Igd2hlbiBhZGRpbmcgaW5wdXRzCiAgICAgICAgICogQHBhcmFtIG9wIC0gVGhlIG9wZXJhdG9yIG9iamVjdC4KICAgICAgICAgKi8KICAgICAgICBzZXRPcGVyYXRvcihvcCkgewogICAgICAgICAgICB0aGlzLm9wID0gb3A7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgb3BlcmF0b3IgdGhhdCBvd25zIHRoaXMgaW5wdXQuCiAgICAgICAgICogQHJldHVybiAtIFRoZSBvcGVyYXRvciBvYmplY3QuCiAgICAgICAgICovCiAgICAgICAgZ2V0T3BlcmF0b3IoKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLm9wOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIHRydWUgaWYgdGhpcyBpbnB1dCBpcyBjb25uZWN0ZWQgdG8gYSBwYXJhbWV0ZXIuCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgaXNDb25uZWN0ZWQoKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLnBhcmFtICE9IG51bGw7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBnZXRQYXJhbSBtZXRob2QuCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgZ2V0UGFyYW0oKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLnBhcmFtOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBAcHJpdmF0ZQogICAgICAgICAqIFRoZSBoYW5kbGVyIGZ1bmN0aW9uIGZvciB3aGVuIHRoZSBpbnB1dCBwYXJhbXRlciBjaGFuZ2VzLgogICAgICAgICAqIEBwYXJhbSBldmVudCAtIFRoZSBldmVudCBvYmplY3QuCiAgICAgICAgICovCiAgICAgICAgcGFyYW1WYWx1ZUNoYW5nZWQoKSB7CiAgICAgICAgICAgIGlmICh0aGlzLm9wKQogICAgICAgICAgICAgICAgdGhpcy5vcC5zZXREaXJ0eSgpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBBc3NpZ25zIHRoZSBQYXJhbXRlciB0byBiZSB1c2VkIHRvIHByb3ZpZGUgdGhlIGlucHV0IHZhbHVlLgogICAgICAgICAqIEBwYXJhbSBwYXJhbSAtIFRoZSBwYXJhbSB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBzZXRQYXJhbShwYXJhbSkgewogICAgICAgICAgICBpZiAodGhpcy5wYXJhbSkgewogICAgICAgICAgICAgICAgdGhpcy5wYXJhbS51bmJpbmRPcGVyYXRvcklucHV0KHRoaXMpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHRoaXMucGFyYW0gPSBwYXJhbTsKICAgICAgICAgICAgaWYgKHRoaXMucGFyYW0pIHsKICAgICAgICAgICAgICAgIHRoaXMucGFyYW0uYmluZE9wZXJhdG9ySW5wdXQodGhpcyk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLy8gV2hlbiBhbiBpbnB1dCBwYXJhbSBpcyBhc3NpZ25lZCwgdGhlIG9wIHNob3VsZAogICAgICAgICAgICAvLyBwcm9wYWdhdGUgZGlydHkgdG8gaXRzIG91dHB1dHMuCiAgICAgICAgICAgIGlmICh0aGlzLm9wKQogICAgICAgICAgICAgICAgdGhpcy5vcC5zZXREaXJ0eSgpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgZ2V0VmFsdWUgbWV0aG9kLgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGdldFZhbHVlKCkgewogICAgICAgICAgICBpZiAodGhpcy5wYXJhbSkKICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLnBhcmFtLnZhbHVlOwogICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1VuYWJsZSB0byBnZXRWYWx1ZScpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgc2V0VmFsdWUgbWV0aG9kLgogICAgICAgICAqIEBwYXJhbSB2YWx1ZSAtIFRoZSB2YWx1ZSBwYXJhbS4KICAgICAgICAgKi8KICAgICAgICBzZXRWYWx1ZSh2YWx1ZSkgewogICAgICAgICAgICBpZiAodGhpcy5wYXJhbSkgewogICAgICAgICAgICAgICAgdGhpcy5wYXJhbS5zZXRWYWx1ZSh2YWx1ZSk7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUHJvcGFnYXRlcyBmcm9tIHRoZSB1cHN0cmVhbSBwYXJhbWV0ZXIgdG8gdGhlIGNvbm5lY3RlZCBvcGVyYXRvci4KICAgICAgICAgKi8KICAgICAgICBzZXREaXJ0eSgpIHsKICAgICAgICAgICAgaWYgKHRoaXMub3ApIHsKICAgICAgICAgICAgICAgIHRoaXMub3Auc2V0RGlydHkoKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICAvLyAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCiAgICAgICAgLy8gUGVyc2lzdGVuY2UKICAgICAgICAvKioKICAgICAgICAgKiBUaGUgdG9KU09OIG1ldGhvZCBlbmNvZGVzIHRoaXMgdHlwZSBhcyBhIGpzb24gb2JqZWN0IGZvciBwZXJzaXN0ZW5jZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBjb250ZXh0IC0gVGhlIGNvbnRleHQgdmFsdWUuCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgdGhlIGpzb24gb2JqZWN0LgogICAgICAgICAqLwogICAgICAgIHRvSlNPTihjb250ZXh0KSB7CiAgICAgICAgICAgIGNvbnN0IGFic1BhdGggPSB0aGlzLnBhcmFtID8gdGhpcy5wYXJhbS5nZXRQYXRoKCkgOiBbXTsKICAgICAgICAgICAgY29uc3QgcGFyYW1QYXRoID0gKGNvbnRleHQgJiYgY29udGV4dC5tYWtlUmVsYXRpdmUgPyBjb250ZXh0Lm1ha2VSZWxhdGl2ZShhYnNQYXRoKSA6IGFic1BhdGgpOwogICAgICAgICAgICByZXR1cm4gewogICAgICAgICAgICAgICAgbmFtZTogdGhpcy5uYW1lLAogICAgICAgICAgICAgICAgcGFyYW1QYXRoOiBwYXJhbVBhdGgsCiAgICAgICAgICAgIH07CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBmcm9tSlNPTiBtZXRob2QgZGVjb2RlcyBhIGpzb24gb2JqZWN0IGZvciB0aGlzIHR5cGUuCiAgICAgICAgICogQHBhcmFtIGogLSBUaGUganNvbiBvYmplY3QgdGhpcyBpdGVtIG11c3QgZGVjb2RlLgogICAgICAgICAqIEBwYXJhbSBjb250ZXh0IC0gVGhlIGNvbnRleHQgdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgZnJvbUpTT04oaiwgY29udGV4dCkgewogICAgICAgICAgICBpZiAoai5wYXJhbVBhdGgpIHsKICAgICAgICAgICAgICAgIC8vIE5vdGU6IHRoZSB0cmVlIHNob3VsZCBoYXZlIGZ1bGx5IGxvYWRlZCBieSB0aGUgdGltZSB3ZSBhcmUgbG9hZGluZyBvcGVyYXRvcnMKICAgICAgICAgICAgICAgIC8vIGV2ZW4gbmV3IGl0ZW1zIGFuZCBncm91cHMgc2hvdWxkIGhhdmUgYmVlbiBjcmVhdGVkLiBPcGVyYXRvcnMgYW5kIHN0YXRlIG1hY2hpbmVzCiAgICAgICAgICAgICAgICAvLyBhcmUgbG9hZGVkIGxhc3QuCiAgICAgICAgICAgICAgICBjb250ZXh0Py5yZXNvbHZlUGF0aChqLnBhcmFtUGF0aCwgKHBhcmFtKSA9PiB7CiAgICAgICAgICAgICAgICAgICAgdGhpcy5zZXRQYXJhbShwYXJhbSk7CiAgICAgICAgICAgICAgICB9LCAoKSA9PiB7CiAgICAgICAgICAgICAgICAgICAgY29uc29sZS53YXJuKCJPcGVyYXRvcklucHV0OiAnIiArIHRoaXMubmFtZSArICInLiBVbmFibGUgdG8gY29ubmVjdCB0bzoiICsgai5wYXJhbVBhdGgpOwogICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGRldGFjaCBtZXRob2QgaXMgY2FsbGVkIHdoZW4gYW4gb3BlcmF0b3IgaXMgYmVpbmcgcmVtb3ZlZCBmcm9tIHRoZSBzY2VuZSB0cmVlLgogICAgICAgICAqIEl0IHJlbW92ZXMgYWxsIGNvbm5lY3Rpb25zIHRvIHBhcmFtZXRlcnMgaW4gdGhlIHNjZW5lLgogICAgICAgICAqLwogICAgICAgIGRldGFjaCgpIHsKICAgICAgICAgICAgLy8gVGhpcyBmdW5jdGlvbiBpcyBjYWxsZWQgd2hlbiB3ZSB3YW50IHRvIHN1c3BlbmQgYW4gb3BlcmF0b3IKICAgICAgICAgICAgLy8gZnJvbSBmdW5jdGlvbmluZyBiZWNhdXNlIGl0IGlzIGRlbGV0ZWQgYW5kIG9uIHRoZSB1bmRvIHN0YWNrLgogICAgICAgICAgICAvLyBPbmNlIG9wZXJhdG9ycyBoYXZlIHBlcnNpc3RlbnQgY29ubmVjdGlvbnMsCiAgICAgICAgICAgIC8vIHdlIHdpbGwgc2ltcGx5IHVuaW5zdGFsbCB0aGUgb3V0cHV0IGZyb20gdGhlIHBhcmFtZXRlci4KICAgICAgICAgICAgaWYgKHRoaXMucGFyYW0pIHsKICAgICAgICAgICAgICAgIHRoaXMucGFyYW0udW5iaW5kT3BlcmF0b3JJbnB1dCh0aGlzKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgcmVhdHRhY2ggbWV0aG9kIGNhbiBiZSBjYWxsZWQgd2hlbiByZS1pbnN0YXRpbmcgYW4gb3BlcmF0b3IgaW4gdGhlIHNjZW5lLgogICAgICAgICAqLwogICAgICAgIHJlYXR0YWNoKCkgewogICAgICAgICAgICB0aGlzLmRldGFjaGVkID0gZmFsc2U7CiAgICAgICAgICAgIGlmICh0aGlzLnBhcmFtKSB7CiAgICAgICAgICAgICAgICB0aGlzLnBhcmFtLmJpbmRPcGVyYXRvcklucHV0KHRoaXMpOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQogICAgY2xhc3MgWGZvT3BlcmF0b3JJbnB1dCBleHRlbmRzIE9wZXJhdG9ySW5wdXQgewogICAgfQoKICAgIC8qKiBUaGUgb3BlcmF0b3IgdGhlIGNhbGN1bGF0ZXMgdGhlIGdsb2JhbCBYZm8gb2YgYSBUcmVlSXRlbSBiYXNlZCBvbiBpdHMgcGFyZW50cyBHbG9iYWxYZm8gYW5kIGl0cyBvd24gTG9jYWxYZm8KICAgICAqIEBleHRlbmRzIE9wZXJhdG9yCiAgICAgKiBAcHJpdmF0ZQogICAgICovCiAgICBjbGFzcyBDYWxjR2xvYmFsWGZvT3BlcmF0b3IgZXh0ZW5kcyBPcGVyYXRvciB7CiAgICAgICAgcGFyZW50R2xvYmFsID0gbmV3IFhmb09wZXJhdG9ySW5wdXQoJ1BhcmVudEdsb2JhbCcpOwogICAgICAgIGxvY2FsWGZvID0gbmV3IFhmb09wZXJhdG9ySW5wdXQoJ0xvY2FsWGZvJyk7CiAgICAgICAgZ2xvYmFsWGZvID0gbmV3IFhmb09wZXJhdG9yT3V0cHV0KCdHbG9iYWxYZm8nKTsKICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGUgYSBDYWxjR2xvYmFsWGZvT3BlcmF0b3Igb3BlcmF0b3IuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gZ3JvdXBHbG9iYWxYZm9QYXJhbSAtIFRoZSBHbG9iYWxYZm8gcGFyYW0gZm91bmQgb24gdGhlIEdyb3VwLgogICAgICAgICAqIEBwYXJhbSBjdXR0aW5nUGxhbmVQYXJhbSAtIFRoZSBwYXJhbWV0ZXIgb24gdGhlIEdyb3VwIHdoaWNoIGRlZmluZXMgdGhlIGRpc3BsYWNlbWVudCB0byBhcHBseSB0byB0aGUgbWVtYmVycy4KICAgICAgICAgKi8KICAgICAgICAvLyBUT0RPOiBhZGRpbmcgbmV3IFhmb1AuLi4gdG8gbWFrZSBpbmhlcml0ZW5jZSB3b3JrCiAgICAgICAgY29uc3RydWN0b3IoZ2xvYmFsWGZvUGFyYW0sIGxvY2FsWGZvUGFyYW0pIHsKICAgICAgICAgICAgc3VwZXIoJ0NhbGNHbG9iYWxYZm9PcGVyYXRvcicpOwogICAgICAgICAgICB0aGlzLmxvY2FsWGZvLnNldFBhcmFtKGxvY2FsWGZvUGFyYW0pOwogICAgICAgICAgICB0aGlzLmdsb2JhbFhmby5zZXRQYXJhbShnbG9iYWxYZm9QYXJhbSk7CiAgICAgICAgICAgIHRoaXMuYWRkSW5wdXQodGhpcy5wYXJlbnRHbG9iYWwpOwogICAgICAgICAgICB0aGlzLmFkZElucHV0KHRoaXMubG9jYWxYZm8pOwogICAgICAgICAgICB0aGlzLmFkZE91dHB1dCh0aGlzLmdsb2JhbFhmbyk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBiYWNrUHJvcGFnYXRlVmFsdWUgbWV0aG9kIGludmVydHMgdGhlIG1hdGhlbWF0aWNzIG9mIHRoZSAnZXZhbHVhdGUnCiAgICAgICAgICogbWV0aG9kIHNvIGl0IGNhbiBwcm9wYWdhdGUgdGhlIHZhbHVlIGJhY2t3YXJkcyB0byBpdHMgaW5wdXRzLgogICAgICAgICAqIEBwYXJhbSB2YWx1ZSAtIHRoZSBuZXcgdmFsdWUgYmVpbmcgc2V0IG9uIHRoZSBvdXRwdXQgR2xvYmFsWGZvCiAgICAgICAgICovCiAgICAgICAgYmFja1Byb3BhZ2F0ZVZhbHVlKHZhbHVlKSB7CiAgICAgICAgICAgIGlmICh0aGlzLnBhcmVudEdsb2JhbC5pc0Nvbm5lY3RlZCgpKSB7CiAgICAgICAgICAgICAgICBjb25zdCBwYXJlbnRHbG9iYWxYZm8gPSB0aGlzLnBhcmVudEdsb2JhbC5nZXRWYWx1ZSgpOwogICAgICAgICAgICAgICAgdGhpcy5sb2NhbFhmby5zZXRWYWx1ZShwYXJlbnRHbG9iYWxYZm8uaW52ZXJzZSgpLm11bHRpcGx5KHZhbHVlKSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZWxzZSB7CiAgICAgICAgICAgICAgICB0aGlzLmxvY2FsWGZvLnNldFZhbHVlKHZhbHVlKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgZXZhbHVhdGUgbWV0aG9kIGNhbGN1bGF0ZXMgYSBuZXcgZ2xvYmFsIFhmbyBiYXNlZCBvbiB0aGUgcGFyZW50cyBHbG9iYWwgWGZvLAogICAgICAgICAqIGFuZCB0aGUgbG9jYWwgWGZvIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGV2YWx1YXRlKCkgewogICAgICAgICAgICBjb25zdCBsb2NhbFhmbyA9IHRoaXMubG9jYWxYZm8uZ2V0VmFsdWUoKTsKICAgICAgICAgICAgaWYgKHRoaXMucGFyZW50R2xvYmFsLmlzQ29ubmVjdGVkKCkpIHsKICAgICAgICAgICAgICAgIGNvbnN0IHBhcmVudEdsb2JhbFhmbyA9IHRoaXMucGFyZW50R2xvYmFsLmdldFZhbHVlKCk7CiAgICAgICAgICAgICAgICB0aGlzLmdsb2JhbFhmby5zZXRDbGVhbihwYXJlbnRHbG9iYWxYZm8ubXVsdGlwbHkobG9jYWxYZm8pKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgIHRoaXMuZ2xvYmFsWGZvLnNldENsZWFuKGxvY2FsWGZvKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KCiAgICAvKioKICAgICAqIFJlcHJlc2VudHMgYSBzcGVjaWZpYyB0eXBlIG9mIHBhcmFtZXRlciwgdGhhdCBvbmx5IHN0b3JlcyBgQm94M2AgdmFsdWVzLgogICAgICoKICAgICAqIGkuZS46CiAgICAgKiBgYGBqYXZhc2NyaXB0CiAgICAgKiBjb25zdCBib3VuZGluZ0JveCA9IG5ldyBCb3VuZGluZ0JveFBhcmFtZXRlcignTXlCQm94JywgbmV3IFRyZWVJdGVtKCkpCiAgICAgKiAvLydteVBhcmFtZXRlck93bmVySXRlbScgaXMgYW4gaW5zdGFuY2Ugb2YgYSAnUGFyYW1ldGVyT3duZXInIGNsYXNzLgogICAgICogLy8gUmVtZW1iZXIgdGhhdCBvbmx5ICdQYXJhbWV0ZXJPd25lcicgYW5kIGNsYXNzZXMgdGhhdCBleHRlbmQgZnJvbSBpdCBjYW4gaG9zdCAnUGFyYW1ldGVyJyBvYmplY3RzLgogICAgICogbXlQYXJhbWV0ZXJPd25lckl0ZW0uYWRkUGFyYW1ldGVyKGJvdW5kaW5nQm94KQogICAgICogYGBgCiAgICAgKiBAZXh0ZW5kcyBQYXJhbWV0ZXIKICAgICAqLwogICAgY2xhc3MgQm91bmRpbmdCb3hQYXJhbWV0ZXIgZXh0ZW5kcyBCb3gzUGFyYW1ldGVyIHsKICAgICAgICAvLyBwcm90ZWN0ZWQgZGlydHk6IGJvb2xlYW4sIHZhbHVlLCBuYW1lCiAgICAgICAgdHJlZUl0ZW07CiAgICAgICAgZGlydHkgPSB0cnVlOwogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgYW4gaW5zdGFuY2Ugb2YgQm91bmRpbmdCb3hQYXJhbWV0ZXIuCiAgICAgICAgICogQHBhcmFtIG5hbWUgLSBOYW1lIG9mIHRoZSBwYXJhbWV0ZXIKICAgICAgICAgKiBAcGFyYW0gdHJlZUl0ZW0gLSBgVHJlZUl0ZW1gIHRoYXQgY29udGFpbnMgYEJveDNgIHJlcHJlc2VudGluZyB0aGUgQm91bmRpbmcgQm94CiAgICAgICAgICovCiAgICAgICAgY29uc3RydWN0b3IobmFtZSA9ICcnLCB0cmVlSXRlbSkgewogICAgICAgICAgICBzdXBlcihuYW1lKTsKICAgICAgICAgICAgdGhpcy50cmVlSXRlbSA9IHRyZWVJdGVtOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBNYWtlcyBwYXJhbWV0ZXIgdmFsdWUgYmUgZGlydHksIHNvIHdoZW4gYGdldFZhbHVlYCBpcyBjYWxsZWQsCiAgICAgICAgICogYW4gZXZhbHVhdGlvbiBpcyB0aGVuIGV4ZWN1dGVkIHRvIHJlLWNhbGN1bGF0ZSB0aGUgQm91bmRpbmdCb3gKICAgICAgICAgKgogICAgICAgICAqIEBtZW1iZXJvZiBCb3VuZGluZ0JveFBhcmFtZXRlcgogICAgICAgICAqLwogICAgICAgIHNldERpcnR5KGluZGV4KSB7CiAgICAgICAgICAgIGlmICghdGhpcy5kaXJ0eSkgewogICAgICAgICAgICAgICAgdGhpcy5kaXJ0eSA9IHRydWU7CiAgICAgICAgICAgICAgICB0aGlzLmVtaXQoJ3ZhbHVlQ2hhbmdlZCcpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiB0cnVlOwogICAgICAgIH0KICAgICAgICBnZXRWYWx1ZSgpIHsKICAgICAgICAgICAgaWYgKHRoaXMuZGlydHkpIHsKICAgICAgICAgICAgICAgIC8vQHRzLWlnbm9yZQogICAgICAgICAgICAgICAgdGhpcy52YWx1ZSA9IHRoaXMudHJlZUl0ZW0uY2xlYW5Cb3VuZGluZ0JveCgpOwogICAgICAgICAgICAgICAgdGhpcy5kaXJ0eSA9IGZhbHNlOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBzdXBlci5nZXRWYWx1ZSgpOwogICAgICAgIH0KICAgICAgICBjbG9uZSgpIHsKICAgICAgICAgICAgY29uc3QgYkJveDNDbG9uZSA9IG5ldyBCb3VuZGluZ0JveFBhcmFtZXRlcih0aGlzLm5hbWUsIHRoaXMudHJlZUl0ZW0pOwogICAgICAgICAgICBiQm94M0Nsb25lLnZhbHVlID0gdGhpcy52YWx1ZT8uY2xvbmUoKTsKICAgICAgICAgICAgcmV0dXJuIGJCb3gzQ2xvbmU7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFdlIGRvIG5vdCB3YW50IHRoaXMgcGFyYW1ldGVyIHNlcmlhbGl6ZWQuCiAgICAgICAgICovCiAgICAgICAgaXNEcml2ZW5CeU9wZXJhdG9yKCkgewogICAgICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgICB9CiAgICAgICAgLy8gLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwogICAgICAgIC8vIFBlcnNpc3RlbmNlCiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGxvYWRWYWx1ZSBpcyB1c2VkIHRvIGNoYW5nZSB0aGUgdmFsdWUgb2YgYSBwYXJhbWV0ZXIsIHdpdGhvdXQgdHJpZ2dlcmluZyBhCiAgICAgICAgICogdmFsdWVDaGFuZ2VzLCBvciBzZXR0aW5nIHRoZSBVU0VSX0VESVRFRCBzdGF0ZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB2YWx1ZSAtIFRoZSBjb250ZXh0IHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGxvYWRWYWx1ZSh2YWx1ZSkgewogICAgICAgICAgICB0aGlzLnZhbHVlID0gdmFsdWUuY2xvbmUoKTsKICAgICAgICB9CiAgICB9CiAgICBSZWdpc3RyeS5yZWdpc3RlcignQm91bmRpbmdCb3hQYXJhbWV0ZXInLCBCb3VuZGluZ0JveFBhcmFtZXRlcik7CgogICAgLyoqCiAgICAgKiBDbGFzcyByZXByZXNlbnRpbmcgYW4gSXRlbSBpbiB0aGUgc2NlbmUgdHJlZSB3aXRoIGhpZXJhcmNoeSBjYXBhYmlsaXRpZXMgKGhhcyBjaGlsZHJlbikuCiAgICAgKiBJdCBoYXMgdGhlIGNhcGFiaWxpdHkgdG8gYWRkIGFuZCByZW1vdmUgY2hpbGRyZW4uCiAgICAgKiAqKlBhcmFtZXRlcnMqKgogICAgICogKiAqKlZpc2libGUoYEJvb2xlYW5QYXJhbWV0ZXJgKToqKiBTaG93cy9IaWRlcyB0aGUgaXRlbS4KICAgICAqICogKipMb2NhbFhmbyhgWGZvUGFyYW1ldGVyYCk6KiogU3BlY2lmaWVzIHRoZSBvZmZzZXQgb2YgdGhpcyB0cmVlIGl0ZW0gZnJvbSBpdHMgcGFyZW50LgogICAgICogKiAqKkdsb2JhbFhmbyhgWGZvUGFyYW1ldGVyYCk6KiogUHJvdmlkZXMgdGhlIGNvbXB1dGVkIHdvcmxkIFhmbyBvZiB0aGlzIHRyZWUgaXRlbS4KICAgICAqICogKipCb3VuZGluZ0JveChgQm91bmRpbmdCb3hgKToqKiBQcm92aWRlcyB0aGUgYm91bmRpbmcgYm94IGZvciB0aGUgdHJlZSBpdGVtIGFuZCBhbGwgb2YgaXRzIGNoaWxkcmVuIGluIHRoZSAzZCBzY2VuZS4KICAgICAqCiAgICAgKiAqKkV2ZW50cyoqCiAgICAgKiAqICoqZ2xvYmFsWGZvQ2hhbmdlZDoqKiBFbWl0dGVkIHdoZW4gdGhlIHZhbHVlIG9mIEdsb2JhbFhmbyBwYXJhbWV0ZXIgY2hhbmdlcy4KICAgICAqICogKip2aXNpYmlsaXR5Q2hhbmdlZDoqKiBFbWl0dGVkIHdoZW4gdGhlIHZpc2liaWxpdHkgb24gdGhlIHRyZWUgaXRlbSBjaGFuZ2VzLgogICAgICogKiAqKmhpZ2hsaWdodENoYW5nZWQ6KiogRW1pdHRlZCB3aGVuIHRoZSBoaWdobGlnaHQgb24gdGhlIHRyZWUgaXRlbSBjaGFuZ2VzLgogICAgICogKiAqKmNoaWxkQWRkZWQ6KiogRW1pdHRlZCB3aGVuIGEgaXRlbSBpcyBhZGRlZCBhcyBhIGNoaWxkLgogICAgICogKiAqKmNoaWxkUmVtb3ZlZDoqKiBFbWl0dGVkIHdoZW4gYW4gaXRlbSBpcyByZW1vdmVkIGZyb20gdGhlIGNoaWxkIG5vZGVzLgogICAgICogKiAqKnBvaW50ZXJEb3duOioqIEVtaXR0ZWQgd2hlbiBhIHBvaW50ZXJEb3duIGV2ZW50IGhhcHBlbnMgaW4gYW4gaXRlbS4KICAgICAqICogKipwb2ludGVyVXA6KiogRW1pdHRlZCB3aGVuIGEgcG9pbnRlclVwIGV2ZW50IGhhcHBlbnMgaW4gYW4gaXRlbS4KICAgICAqICogKipwb2ludGVyTW92ZToqKiBFbWl0dGVkIHdoZW4gYSBwb2ludGVyTW92ZSBldmVudCBoYXBwZW5zIGluIGFuIGl0ZW0uCiAgICAgKiAqICoqcG9pbnRlckVudGVyOioqIEVtaXR0ZWQgd2hlbiBhIHBvaW50ZXJFbnRlciBldmVudCBoYXBwZW5zIGluIGFuIGl0ZW0uCiAgICAgKiAqICoqcG9pbnRlckNsaWNrOioqIEVtaXR0ZWQgd2hlbiBhIHBvaW50ZXIgaXMgY2xpY2tlZCBvbiBhbiBpdGVtLgogICAgICogKiAqKnBvaW50ZXJEb3VibGVDbGljazoqKiBFbWl0dGVkIHdoZW4gYSBwb2ludGVyIGlzIGRvdWJsZS1jbGlja2VkIG9uIGFuIGl0ZW0uCiAgICAgKiAqICoqcG9pbnRlckxvbmdQcmVzczoqKiBFbWl0dGVkIHdoZW4gYSBwb2ludGVyIGlzIGNsaWNrZWQgYW5kIGhlbGQgb24gYW4gaXRlbSBmb3IgYSBsb25nIHRpbWUuCiAgICAgKgogICAgICoKICAgICAqIEBleHRlbmRzIHtQYXJhbWV0ZXJPd25lcn0KICAgICAqLwogICAgY2xhc3MgVHJlZUl0ZW0gZXh0ZW5kcyBQYXJhbWV0ZXJPd25lciB7CiAgICAgICAgLy8gQ29udHJvbHMgaWYgdGhpcyBUcmVlSXRlbSBvciBpdHMgY2hpbGRyZW4gY29udHJpYnV0ZSB0byB0aGUgYm91bmRpbmcgYm94ZXMKICAgICAgICAvLyBpbiB0aGUgc2NlbmUuIElmIHNldCB0byBmYWxzZSwgQ2FtZXJhIGZyYW1pbmcgd2lsbCBpZ25vcmUgdGhpcyBpdGVtLAogICAgICAgIGRpc2FibGVCb3VuZGluZ0JveCA9IGZhbHNlOwogICAgICAgIF9fY2hpbGRJdGVtcyA9IFtdOwogICAgICAgIF9fY2hpbGRJdGVtc0V2ZW50SGFuZGxlcnMgPSBbXTsKICAgICAgICBjaGlsZEl0ZW1zTWFwcGluZyA9IHt9OwogICAgICAgIGNoaWxkSXRlbXNNYXBwaW5nQ29ycnVwdCA9IGZhbHNlOwogICAgICAgIC8qKgogICAgICAgICAqIEBtZW1iZXIgZ2xvYmFsWGZvUGFyYW0gLSBTdG9yZXMgdGhlIGdsb2JhbCBYZm8gZm9yIHRoaXMgdHJlZSBpdGVtLgogICAgICAgICAqIGdsb2JhbCB4Zm9zIGFyZSBjYWxjdWxhdGVkIGZyb20gdGhlIGxvY2FsWGZvIGFuZCBwYXJlbnRYZm8uCiAgICAgICAgICovCiAgICAgICAgZ2xvYmFsWGZvUGFyYW0gPSBuZXcgWGZvUGFyYW1ldGVyKCdHbG9iYWxYZm8nLCBuZXcgWGZvKCkpOwogICAgICAgIC8qKgogICAgICAgICAqIEBtZW1iZXIgbG9jYWxYZm9QYXJhbSAtIFN0b3JlcyB0aGUgbG9jYWwgWGZvIGZvciB0aGlzIHRyZWUgaXRlbS4KICAgICAgICAgKiBsb2NhbCBYZm9zIGFyZSB0aGUgb2Zmc2V0IGZyb20gdGhlIHBhcmVudCdzIGNvb3JkaW5hdGUgZnJhbWUuCiAgICAgICAgICovCiAgICAgICAgbG9jYWxYZm9QYXJhbSA9IG5ldyBYZm9QYXJhbWV0ZXIoJ0xvY2FsWGZvJywgbmV3IFhmbygpKTsKICAgICAgICAvKioKICAgICAgICAgKiBAbWVtYmVyIGJvdW5kaW5nQm94UGFyYW0gLSBTdG9yZXMgdGhlIGJvdW5kaW5nIGJveCBmb3IgdGhpcyB0cmVlIGl0ZW0KICAgICAgICAgKi8KICAgICAgICBib3VuZGluZ0JveFBhcmFtID0gbmV3IEJvdW5kaW5nQm94UGFyYW1ldGVyKCdCb3VuZGluZ0JveCcsIHRoaXMpOwogICAgICAgIC8qKgogICAgICAgICAqIEBtZW1iZXIgdmlzaWJsZVBhcmFtIC0gV2hldGhlciB0aGlzIHRyZWUgaXRlbSBpcyB2aXNpYmxlIG9yIG5vdC4KICAgICAgICAgKiBBbnkgZ2l2ZW4gdHJlZSBpdGVtIGlzIGFsc28gaXMgYWZmZWN0ZWQgYnkgcGFyZW50J3MgdmlzaWJpbGl0eS4KICAgICAgICAgKi8KICAgICAgICB2aXNpYmxlUGFyYW0gPSBuZXcgQm9vbGVhblBhcmFtZXRlcignVmlzaWJsZScsIHRydWUpOwogICAgICAgIC8qKgogICAgICAgICAqIEBtZW1iZXIgcGlja2FibGVQYXJhbSAtIFdoZXRoZXIgdGhpcyB0cmVlIGl0ZW0gaWMgcGlja2FibGUgaW4gdGhlIHZpZXdwb3J0IG9yIG5vdC4KICAgICAgICAgKiBBbnkgZ2l2ZW4gdHJlZSBpdGVtIGlzIGFsc28gaXMgYWZmZWN0ZWQgYnkgcGFyZW50J3MgcGljay1hYmxpbGl0eS4KICAgICAgICAgKi8KICAgICAgICBwaWNrYWJsZVBhcmFtID0gbmV3IEJvb2xlYW5QYXJhbWV0ZXIoJ1BpY2thYmxlJywgdHJ1ZSk7CiAgICAgICAgLyoqCiAgICAgICAgICogQG1lbWJlciBvcGFjaXR5UGFyYW0gLSBDb250cm9scywgaW4gY29tYmluYXRpb24gd2l0aCBNYXRlcmlhbCB0cmFuc3BhcmVuY3ksCiAgICAgICAgICogdGhlIG9wYWNpdHkgb2YgdGhpcyBpdGVtIGFuZCBpdHMgY2hpbGRyZW4uCiAgICAgICAgICovCiAgICAgICAgb3BhY2l0eVBhcmFtID0gbmV3IE51bWJlclBhcmFtZXRlcignT3BhY2l0eScsIDEsIFswLCAxXSk7CiAgICAgICAgaGlnaGxpZ2h0TWFwcGluZyA9IHt9OwogICAgICAgIGhpZ2hsaWdodHMgPSBbXTsKICAgICAgICAjdmlzaWJsZSA9IHRydWU7CiAgICAgICAgI3BpY2thYmxlID0gdHJ1ZTsKICAgICAgICB2aXNpYmxlQ291bnRlciA9IDE7IC8vIFZpc2libGUgYnkgRGVmYXVsdC4KICAgICAgICBwaWNrYWJsZUNvdW50ZXIgPSAxOyAvLyBQaWNrYWJsZSBieSBEZWZhdWx0LgogICAgICAgIG9wYWNpdHkgPSAxOyAvLyBPcGFxdWUgYnkgRGVmYXVsdC4KICAgICAgICBpbmhlcml0ZWRPcGFjaXR5VmFsdWVzID0gbmV3IE1hcCgpOwogICAgICAgIGdsb2JhbFhmb09wOwogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgYSB0cmVlIGl0ZW0gd2l0aCB0aGUgc3BlY2lmaWVkIG5hbWUuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gbmFtZSAtIFRoZSBuYW1lIG9mIHRoZSB0cmVlIGl0ZW0uIEl0J3MgdGhlIGlkZW50aWZpZXIgb2YgdGhlIHRyZWUgaXRlbS4KICAgICAgICAgKiBJdCdzIGFuIGlkZW50aWZpZXIgaW50ZW5kZWQgdG8gYmUgaHVtYW4gcmVhZGFibGUuCiAgICAgICAgICogSXQncyBpbmNsdWRlZCBpbiB0aGUgcGF0aCB0aGF0IHdlIHVzZSB0byBhY2Nlc3MgYSBwYXJ0aWN1bGFyIGl0ZW0uCiAgICAgICAgICogSXQncyB1c2VkIHRvIGRpc3BsYXkgaXQgaW4gdGhlIHRyZWUuCiAgICAgICAgICovCiAgICAgICAgY29uc3RydWN0b3IobmFtZSkgewogICAgICAgICAgICBzdXBlcihuYW1lKTsKICAgICAgICAgICAgLy8gLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwogICAgICAgICAgICAvLyBBZGQgcGFyYW1ldGVycy4KICAgICAgICAgICAgdGhpcy5hZGRQYXJhbWV0ZXIodGhpcy52aXNpYmxlUGFyYW0pOwogICAgICAgICAgICB0aGlzLmFkZFBhcmFtZXRlcih0aGlzLnBpY2thYmxlUGFyYW0pOwogICAgICAgICAgICB0aGlzLmFkZFBhcmFtZXRlcih0aGlzLm9wYWNpdHlQYXJhbSk7CiAgICAgICAgICAgIHRoaXMuYWRkUGFyYW1ldGVyKHRoaXMubG9jYWxYZm9QYXJhbSk7CiAgICAgICAgICAgIHRoaXMuYWRkUGFyYW1ldGVyKHRoaXMuZ2xvYmFsWGZvUGFyYW0pOwogICAgICAgICAgICB0aGlzLmFkZFBhcmFtZXRlcih0aGlzLmJvdW5kaW5nQm94UGFyYW0pOwogICAgICAgICAgICB0aGlzLmdsb2JhbFhmb09wID0gbmV3IENhbGNHbG9iYWxYZm9PcGVyYXRvcih0aGlzLmdsb2JhbFhmb1BhcmFtLCB0aGlzLmxvY2FsWGZvUGFyYW0pOwogICAgICAgICAgICB0aGlzLmdsb2JhbFhmb1BhcmFtLm9uKCd2YWx1ZUNoYW5nZWQnLCAoZXZlbnQpID0+IHsKICAgICAgICAgICAgICAgIHRoaXMuc2V0Qm91bmRpbmdCb3hEaXJ0eSgpOwogICAgICAgICAgICAgICAgLy8gTm90ZTogZGVwcmVjYXRlIHRoaXMgZXZlbnQuCiAgICAgICAgICAgICAgICB0aGlzLmVtaXQoJ2dsb2JhbFhmb0NoYW5nZWQnLCBldmVudCk7CiAgICAgICAgICAgIH0pOwogICAgICAgICAgICB0aGlzLnZpc2libGVQYXJhbS5vbigndmFsdWVDaGFuZ2VkJywgKCkgPT4gewogICAgICAgICAgICAgICAgdGhpcy52aXNpYmxlQ291bnRlciArPSB0aGlzLnZpc2libGVQYXJhbS52YWx1ZSA/IDEgOiAtMTsKICAgICAgICAgICAgICAgIHRoaXMudXBkYXRlVmlzaWJpbGl0eSgpOwogICAgICAgICAgICB9KTsKICAgICAgICAgICAgdGhpcy5waWNrYWJsZVBhcmFtLm9uKCd2YWx1ZUNoYW5nZWQnLCAoKSA9PiB7CiAgICAgICAgICAgICAgICB0aGlzLnBpY2thYmxlQ291bnRlciArPSB0aGlzLnBpY2thYmxlUGFyYW0udmFsdWUgPyAxIDogLTE7CiAgICAgICAgICAgICAgICB0aGlzLnVwZGF0ZVBpY2thYmxlKCk7CiAgICAgICAgICAgIH0pOwogICAgICAgICAgICB0aGlzLm9wYWNpdHlQYXJhbS5vbigndmFsdWVDaGFuZ2VkJywgKCkgPT4gewogICAgICAgICAgICAgICAgdGhpcy51cGRhdGVPcGFjaXR5KCk7CiAgICAgICAgICAgIH0pOwogICAgICAgIH0KICAgICAgICBzZXRPd25lcihvd25lckl0ZW0pIHsKICAgICAgICAgICAgaWYgKG93bmVySXRlbSAmJiAhKG93bmVySXRlbSBpbnN0YW5jZW9mIFRyZWVJdGVtKSkgewogICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdjYW5ub3Qgc2V0T3duZXInKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAodGhpcy5vd25lckl0ZW0pIHsKICAgICAgICAgICAgICAgIGlmICh0aGlzLm93bmVySXRlbSBpbnN0YW5jZW9mIFRyZWVJdGVtKSB7CiAgICAgICAgICAgICAgICAgICAgLy8gVGhlIGVmZmVjdCBvZiB0aGUgaW52aXNpYmxlIG93bmVyIGlzIHJlbW92ZWQuCiAgICAgICAgICAgICAgICAgICAgaWYgKCF0aGlzLm93bmVySXRlbS5pc1Zpc2libGUoKSkKICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy52aXNpYmxlQ291bnRlcisrOwogICAgICAgICAgICAgICAgICAgIGlmICghdGhpcy5vd25lckl0ZW0uaXNQaWNrYWJsZSgpKQogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnBpY2thYmxlQ291bnRlcisrOwogICAgICAgICAgICAgICAgICAgIGNvbnN0IGluZGV4ID0gdGhpcy5vd25lckl0ZW0uZ2V0Q2hpbGRJbmRleCh0aGlzKTsKICAgICAgICAgICAgICAgICAgICBpZiAoaW5kZXggPj0gMCkKICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5vd25lckl0ZW0udW5iaW5kQ2hpbGQoaW5kZXgsIHRoaXMpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIHN1cGVyLnNldE93bmVyKG93bmVySXRlbSk7CiAgICAgICAgICAgIGlmICh0aGlzLm93bmVySXRlbSkgewogICAgICAgICAgICAgICAgaWYgKHRoaXMub3duZXJJdGVtIGluc3RhbmNlb2YgVHJlZUl0ZW0pIHsKICAgICAgICAgICAgICAgICAgICAvLyBUaGUgZWZmZWN0IG9mIHRoZSBpbnZpc2libGUgb3duZXIgaXMgYWRkZWQuCiAgICAgICAgICAgICAgICAgICAgaWYgKCF0aGlzLm93bmVySXRlbS5pc1Zpc2libGUoKSkKICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy52aXNpYmxlQ291bnRlci0tOwogICAgICAgICAgICAgICAgICAgIGlmICghdGhpcy5vd25lckl0ZW0uaXNQaWNrYWJsZSgpKQogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnBpY2thYmxlQ291bnRlci0tOwogICAgICAgICAgICAgICAgICAgIHRoaXMuZ2xvYmFsWGZvT3AuZ2V0SW5wdXQoJ1BhcmVudEdsb2JhbCcpLnNldFBhcmFtKHRoaXMub3duZXJJdGVtLmdsb2JhbFhmb1BhcmFtKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgIHRoaXMuZ2xvYmFsWGZvT3AuZ2V0SW5wdXQoJ1BhcmVudEdsb2JhbCcpLnNldFBhcmFtKHVuZGVmaW5lZCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdGhpcy51cGRhdGVWaXNpYmlsaXR5KCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgdGhlIHBhcmVudCBvZiBjdXJyZW50IFRyZWVJdGVtLgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgdGhlIHBhcmVudCBpdGVtLgogICAgICAgICAqLwogICAgICAgIGdldFBhcmVudEl0ZW0oKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLmdldE93bmVyKCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFNldHMgdGhlIHBhcmVudCBvZiBjdXJyZW50IFRyZWVJdGVtLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHBhcmVudEl0ZW0gLSBUaGUgcGFyZW50IGl0ZW0uCiAgICAgICAgICovCiAgICAgICAgc2V0UGFyZW50SXRlbShwYXJlbnRJdGVtKSB7CiAgICAgICAgICAgIHRoaXMuc2V0T3duZXIocGFyZW50SXRlbSk7CiAgICAgICAgfQogICAgICAgIGdldCBwYXJlbnQoKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLmdldE93bmVyKCk7CiAgICAgICAgfQogICAgICAgIHNldCBwYXJlbnQodHJlZUl0ZW0pIHsKICAgICAgICAgICAgdGhpcy5zZXRPd25lcih0cmVlSXRlbSk7CiAgICAgICAgfQogICAgICAgIC8vIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KICAgICAgICAvLyBWaXNpYmlsaXR5CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyB2aXNpYmxlIHBhcmFtZXRlciB2YWx1ZSBmb3IgY3VycmVudCBUcmVlSXRlbS4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgdmlzaWJsZSBwYXJhbSB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBpc1Zpc2libGUoKSB7CiAgICAgICAgICAgIC8vIFNob3VsZCBuZXZlciBiZSBtb3JlIHRoYW4gMSwgYnV0IGNhbiBiZSBsZXNzIHRoYW4gMC4KICAgICAgICAgICAgcmV0dXJuIHRoaXMudmlzaWJsZUNvdW50ZXIgPiAwOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTZXRzIHZpc2libGUgcGFyYW1ldGVyIHZhbHVlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHZhbCAtIFRoZSB2YWwgcGFyYW0uCiAgICAgICAgICovCiAgICAgICAgc2V0VmlzaWJsZSh2aXNpYmxlKSB7CiAgICAgICAgICAgIHRoaXMudmlzaWJsZVBhcmFtLnZhbHVlID0gdmlzaWJsZTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVXBkYXRlcyBjdXJyZW50IFRyZWVJdGVtIHZpc2libGUgc3RhdGUgYW5kIHByb3BhZ2F0ZXMgaXRzIHZhbHVlIHRvIGNoaWxkcmVuIGVsZW1lbnRzLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHZhbCAtIFRoZSB2YWwgcGFyYW0uCiAgICAgICAgICovCiAgICAgICAgcHJvcGFnYXRlVmlzaWJpbGl0eSh2YWwpIHsKICAgICAgICAgICAgdGhpcy52aXNpYmxlQ291bnRlciArPSB2YWw7CiAgICAgICAgICAgIHRoaXMudXBkYXRlVmlzaWJpbGl0eSgpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgdXBkYXRlVmlzaWJpbGl0eSBtZXRob2QuCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgYSBib29sZWFuLgogICAgICAgICAqLwogICAgICAgIHVwZGF0ZVZpc2liaWxpdHkoKSB7CiAgICAgICAgICAgIGNvbnN0IHZpc2libGUgPSB0aGlzLnZpc2libGVDb3VudGVyID4gMDsKICAgICAgICAgICAgaWYgKHZpc2libGUgIT0gdGhpcy4jdmlzaWJsZSkgewogICAgICAgICAgICAgICAgdGhpcy4jdmlzaWJsZSA9IHZpc2libGU7CiAgICAgICAgICAgICAgICBmb3IgKGNvbnN0IGNoaWxkSXRlbSBvZiB0aGlzLl9fY2hpbGRJdGVtcykgewogICAgICAgICAgICAgICAgICAgIGNoaWxkSXRlbS5wcm9wYWdhdGVWaXNpYmlsaXR5KHRoaXMuI3Zpc2libGUgPyAxIDogLTEpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgdGhpcy5lbWl0KCd2aXNpYmlsaXR5Q2hhbmdlZCcsIG5ldyBTdGF0ZUNoYW5nZWRFdmVudCh2aXNpYmxlKSk7CiAgICAgICAgICAgICAgICAvLyBOb3RlOiB3ZSB1c2VkIHRvIGhhbmRsZSB0aGlzIGJ5IGxpc3RlbmluZyB0byBhICd2YWx1ZUNoYW5nZWQnIGV2ZW50IG9uIHRoZQogICAgICAgICAgICAgICAgLy8gcGFyYW1ldGVyLgogICAgICAgICAgICAgICAgaWYgKHRoaXMub3duZXJJdGVtIGluc3RhbmNlb2YgVHJlZUl0ZW0pIHsKICAgICAgICAgICAgICAgICAgICB0aGlzLm93bmVySXRlbS5zZXRCb3VuZGluZ0JveERpcnR5KCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgfQogICAgICAgIC8vIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KICAgICAgICAvLyBQaWNrYWJsZQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgdmlzaWJsZSBwYXJhbWV0ZXIgdmFsdWUgZm9yIGN1cnJlbnQgVHJlZUl0ZW0uCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHZpc2libGUgcGFyYW0gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgaXNQaWNrYWJsZSgpIHsKICAgICAgICAgICAgLy8gU2hvdWxkIG5ldmVyIGJlIG1vcmUgdGhhbiAxLCBidXQgY2FuIGJlIGxlc3MgdGhhbiAwLgogICAgICAgICAgICByZXR1cm4gdGhpcy5waWNrYWJsZUNvdW50ZXIgPiAwOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBVcGRhdGVzIGN1cnJlbnQgVHJlZUl0ZW0gdmlzaWJsZSBzdGF0ZSBhbmQgcHJvcGFnYXRlcyBpdHMgdmFsdWUgdG8gY2hpbGRyZW4gZWxlbWVudHMuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gdmFsIC0gVGhlIHZhbCBwYXJhbS4KICAgICAgICAgKi8KICAgICAgICBwcm9wYWdhdGVQaWNrYWJsZSh2YWwpIHsKICAgICAgICAgICAgdGhpcy5waWNrYWJsZUNvdW50ZXIgKz0gdmFsOwogICAgICAgICAgICB0aGlzLnVwZGF0ZVBpY2thYmxlKCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSB1cGRhdGVQaWNrYWJsZSBtZXRob2QuCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgYSBib29sZWFuLgogICAgICAgICAqLwogICAgICAgIHVwZGF0ZVBpY2thYmxlKCkgewogICAgICAgICAgICBjb25zdCBwaWNrYWJsZSA9IHRoaXMucGlja2FibGVDb3VudGVyID4gMDsKICAgICAgICAgICAgaWYgKHBpY2thYmxlICE9IHRoaXMuI3BpY2thYmxlKSB7CiAgICAgICAgICAgICAgICB0aGlzLiNwaWNrYWJsZSA9IHBpY2thYmxlOwogICAgICAgICAgICAgICAgZm9yIChjb25zdCBjaGlsZEl0ZW0gb2YgdGhpcy5fX2NoaWxkSXRlbXMpIHsKICAgICAgICAgICAgICAgICAgICBjaGlsZEl0ZW0ucHJvcGFnYXRlUGlja2FibGUodGhpcy4jcGlja2FibGUgPyAxIDogLTEpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgdGhpcy5lbWl0KCdwaWNrYWJpbGl0eUNoYW5nZWQnLCBuZXcgU3RhdGVDaGFuZ2VkRXZlbnQocGlja2FibGUpKTsKICAgICAgICAgICAgICAgIHJldHVybiB0cnVlOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBmYWxzZTsKICAgICAgICB9CiAgICAgICAgLy8gLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwogICAgICAgIC8vIE9wYWNpdHkKICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIHRoZSBjdXJyZW50IHN0YXR1cyBvZiB0aGUgb3BhY2l0eSB2YWx1ZS4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIHRydWUgaWYgdGhlIG9wYWNpdHkgdmFsdWUgaXMgbGVzcyB0aGFuIDEuCiAgICAgICAgICovCiAgICAgICAgaXNPcGFxdWUoKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLm9wYWNpdHkgPiAwLjk5OTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU2V0IHRoZSB2YWx1ZSBvZiBvcGFjaXR5IGluaGVyaXRlZCBieSBhIGdpdmVuIHRyZWUgaXRlbS4KICAgICAgICAgKi8KICAgICAgICBzZXRJbmhlcml0ZWRPcGFjaXR5KHBhcmVudCwgdmFsdWUpIHsKICAgICAgICAgICAgdGhpcy5pbmhlcml0ZWRPcGFjaXR5VmFsdWVzLnNldChwYXJlbnQsIHZhbHVlKTsKICAgICAgICAgICAgdGhpcy51cGRhdGVPcGFjaXR5KCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENhbGN1bGF0ZXMgdGhlIG5ldyBvcGFjaXR5IHZhbHVlIGJhc2VkIG9uIHRoZSBvcGFjaXR5UGFyYW0gdmFsdWUKICAgICAgICAgKiBhbmQgdGhlIGxvd2VzdCBvZiB0aGUgaW5oZXJpdGVkIG9wYWNpdHkgdmFsdWVzLgogICAgICAgICAqLwogICAgICAgIHVwZGF0ZU9wYWNpdHkoKSB7CiAgICAgICAgICAgIGxldCBpbmhlcml0ZWRPcGFjaXR5VmFsdWUgPSAxOwogICAgICAgICAgICB0aGlzLmluaGVyaXRlZE9wYWNpdHlWYWx1ZXMuZm9yRWFjaCgodmFsdWUpID0+IHsKICAgICAgICAgICAgICAgIGlmICh2YWx1ZSA8IGluaGVyaXRlZE9wYWNpdHlWYWx1ZSkKICAgICAgICAgICAgICAgICAgICBpbmhlcml0ZWRPcGFjaXR5VmFsdWUgPSB2YWx1ZTsKICAgICAgICAgICAgfSk7CiAgICAgICAgICAgIGNvbnN0IHdhc09wYXF1ZSA9IHRoaXMub3BhY2l0eSA+IDAuOTk5OwogICAgICAgICAgICB0aGlzLm9wYWNpdHkgPSB0aGlzLm9wYWNpdHlQYXJhbS52YWx1ZSAqIGluaGVyaXRlZE9wYWNpdHlWYWx1ZTsKICAgICAgICAgICAgLy8gZWxzZSB0aGlzLm9wYWNpdHkgPSB0aGlzLm9wYWNpdHlQYXJhbS52YWx1ZQogICAgICAgICAgICBmb3IgKGNvbnN0IGNoaWxkSXRlbSBvZiB0aGlzLl9fY2hpbGRJdGVtcykgewogICAgICAgICAgICAgICAgY2hpbGRJdGVtLnNldEluaGVyaXRlZE9wYWNpdHkodGhpcywgdGhpcy5vcGFjaXR5KTsKICAgICAgICAgICAgfQogICAgICAgICAgICBjb25zdCBpc09wYXF1ZSA9IHRoaXMub3BhY2l0eSA+IDAuOTk5OwogICAgICAgICAgICB0aGlzLmVtaXQoJ29wYWNpdHlDaGFuZ2VkJywgbmV3IE9wYWNpdHlTdGF0ZUNoYW5nZWRFdmVudChpc09wYXF1ZSwgd2FzT3BhcXVlICE9IGlzT3BhcXVlKSk7CiAgICAgICAgfQogICAgICAgIC8vIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KICAgICAgICAvLyBIaWdobGlnaHRzCiAgICAgICAgLyoqCiAgICAgICAgICogQWRkcyBhIGhpZ2hsaWdodCB0byB0aGUgdHJlZSBpdGVtLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIG5hbWUgLSBUaGUgbmFtZSBvZiB0aGUgdHJlZSBpdGVtLgogICAgICAgICAqIEBwYXJhbSBjb2xvciAtIFRoZSBjb2xvciBvZiB0aGUgaGlnaGxpZ2h0LgogICAgICAgICAqIEBwYXJhbSBwcm9wYWdhdGVUb0NoaWxkcmVuIC0gQSBib29sZWFuIGluZGljYXRpbmcgd2hldGhlciB0byBwcm9wYWdhdGUgdG8gY2hpbGRyZW4uCiAgICAgICAgICovCiAgICAgICAgYWRkSGlnaGxpZ2h0KG5hbWUsIGNvbG9yLCBwcm9wYWdhdGVUb0NoaWxkcmVuID0gdHJ1ZSkgewogICAgICAgICAgICAvLyBJZiB0aGUgaGlnaGxpZ2h0IHdhcyBhbHJlYWR5IGluIHRoZSBsaXN0LAogICAgICAgICAgICAvLyByZW1vdmUgaXQgYW5kIHB1dCBpdCBhdCB0aGUgdG9wLgogICAgICAgICAgICBpZiAobmFtZSBpbiB0aGlzLmhpZ2hsaWdodE1hcHBpbmcpIHsKICAgICAgICAgICAgICAgIGlmICh0aGlzLmhpZ2hsaWdodHNbdGhpcy5oaWdobGlnaHRzLmxlbmd0aCAtIDFdICE9IG5hbWUpIHsKICAgICAgICAgICAgICAgICAgICAvLyBUaGUgaGlnaGxpZ2h0IHdhcyBhbHJlYWR5IGluIHRoZSBsaXN0LCBidXQgbm90IGF0IHRoZSB0b3AuIE1vdmUgaXQgdG8gdGhlIHRvcC4KICAgICAgICAgICAgICAgICAgICBjb25zdCBpZCA9IHRoaXMuaGlnaGxpZ2h0cy5pbmRleE9mKG5hbWUpOwogICAgICAgICAgICAgICAgICAgIHRoaXMuaGlnaGxpZ2h0cy5zcGxpY2UoaWQsIDEpOwogICAgICAgICAgICAgICAgICAgIHRoaXMuaGlnaGxpZ2h0cy5wdXNoKG5hbWUpOwogICAgICAgICAgICAgICAgICAgIHRoaXMuZW1pdCgnaGlnaGxpZ2h0Q2hhbmdlZCcsIHsgbmFtZSwgY29sb3IgfSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAvLyBUaGlzIGl0ZW0gaXMgYWxyZWFkeSBoaWdobGlnaHRlZCB3aXRoIHRoaXMgaGlnaGxpZ2h0CiAgICAgICAgICAgICAgICAgICAgaWYgKCF0aGlzLmhpZ2hsaWdodE1hcHBpbmdbbmFtZV0uaXNFcXVhbChjb2xvcikpIHsKICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5oaWdobGlnaHRNYXBwaW5nW25hbWVdID0gY29sb3I7CiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZW1pdCgnaGlnaGxpZ2h0Q2hhbmdlZCcsIHsgbmFtZSwgY29sb3IgfSk7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIGVsc2UgewogICAgICAgICAgICAgICAgdGhpcy5oaWdobGlnaHRzLnB1c2gobmFtZSk7CiAgICAgICAgICAgICAgICB0aGlzLmhpZ2hsaWdodE1hcHBpbmdbbmFtZV0gPSBjb2xvcjsKICAgICAgICAgICAgICAgIHRoaXMuZW1pdCgnaGlnaGxpZ2h0Q2hhbmdlZCcsIHsgbmFtZSwgY29sb3IgfSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKHByb3BhZ2F0ZVRvQ2hpbGRyZW4pIHsKICAgICAgICAgICAgICAgIHRoaXMuX19jaGlsZEl0ZW1zLmZvckVhY2goKGNoaWxkSXRlbSkgPT4gewogICAgICAgICAgICAgICAgICAgIGNoaWxkSXRlbS5hZGRIaWdobGlnaHQobmFtZSwgY29sb3IsIHByb3BhZ2F0ZVRvQ2hpbGRyZW4pOwogICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmVtb3ZlcyBhIGhpZ2hsaWdodCB0byB0aGUgdHJlZSBpdGVtLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIG5hbWUgLSBUaGUgbmFtZSBvZiB0aGUgdHJlZSBpdGVtLgogICAgICAgICAqIEBwYXJhbSBwcm9wYWdhdGVUb0NoaWxkcmVuIC0gQSBib29sZWFuIGluZGljYXRpbmcgd2hldGhlciB0byBwcm9wYWdhdGUgdG8gY2hpbGRyZW4uCiAgICAgICAgICovCiAgICAgICAgcmVtb3ZlSGlnaGxpZ2h0KG5hbWUsIHByb3BhZ2F0ZVRvQ2hpbGRyZW4gPSB0cnVlKSB7CiAgICAgICAgICAgIGlmIChuYW1lIGluIHRoaXMuaGlnaGxpZ2h0TWFwcGluZykgewogICAgICAgICAgICAgICAgaWYgKHRoaXMuaGlnaGxpZ2h0c1t0aGlzLmhpZ2hsaWdodHMubGVuZ3RoIC0gMV0gPT0gbmFtZSkgewogICAgICAgICAgICAgICAgICAgIHRoaXMuaGlnaGxpZ2h0cy5wb3AoKTsKICAgICAgICAgICAgICAgICAgICBkZWxldGUgdGhpcy5oaWdobGlnaHRNYXBwaW5nW25hbWVdOwogICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLmhpZ2hsaWdodHMubGVuZ3RoID4gMCkgewogICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBuZXh0TmFtZSA9IHRoaXMuaGlnaGxpZ2h0c1t0aGlzLmhpZ2hsaWdodHMubGVuZ3RoIC0gMV07CiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IG5leHRDb2xvciA9IHRoaXMuaGlnaGxpZ2h0TWFwcGluZ1tuZXh0TmFtZV07CiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZW1pdCgnaGlnaGxpZ2h0Q2hhbmdlZCcsIHsgbmFtZTogbmV4dE5hbWUsIGNvbG9yOiBuZXh0Q29sb3IgfSk7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIGVsc2UgewogICAgICAgICAgICAgICAgICAgICAgICAvLyBUaGUgbGFzdCBoaWdobGlnaHQgd2FzIHJlbW92ZWQsIHNvIGVtaXQgYW4gZXZlbnQgc2F5aW5nIHdlIGFyZSBubyBsb25nZXIgaGlnaGxpZ2h0ZWQuCiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZW1pdCgnaGlnaGxpZ2h0Q2hhbmdlZCcpOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGVsc2UgewogICAgICAgICAgICAgICAgICAgIC8vIFRoZSByZW1vdmVkIGhpZ2hsaWdodCB3YXMgbm90IHRoZSBjdXJyZW50IGhpZ2hsaWdodCwgc28gbm8gY2hhbmdlIG5lZWRzIHRvIGJlIHNob3duLgogICAgICAgICAgICAgICAgICAgIGNvbnN0IGlkID0gdGhpcy5oaWdobGlnaHRzLmluZGV4T2YobmFtZSk7CiAgICAgICAgICAgICAgICAgICAgdGhpcy5oaWdobGlnaHRzLnNwbGljZShpZCwgMSk7CiAgICAgICAgICAgICAgICAgICAgZGVsZXRlIHRoaXMuaGlnaGxpZ2h0TWFwcGluZ1tuYW1lXTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGlmIChwcm9wYWdhdGVUb0NoaWxkcmVuKSB7CiAgICAgICAgICAgICAgICAgICAgdGhpcy5fX2NoaWxkSXRlbXMuZm9yRWFjaCgoY2hpbGRJdGVtKSA9PiB7CiAgICAgICAgICAgICAgICAgICAgICAgIGNoaWxkSXRlbS5yZW1vdmVIaWdobGlnaHQobmFtZSwgcHJvcGFnYXRlVG9DaGlsZHJlbik7CiAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyB0aGUgY29sb3Igb2YgdGhlIGN1cnJlbnQgaGlnaGxpZ2h0LgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFRoZSBjb2xvciB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBnZXRIaWdobGlnaHQoKSB7CiAgICAgICAgICAgIGlmICh0aGlzLmhpZ2hsaWdodHMubGVuZ3RoID09IDApIHsKICAgICAgICAgICAgICAgIHJldHVybiBudWxsOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiB0aGlzLmhpZ2hsaWdodE1hcHBpbmdbdGhpcy5oaWdobGlnaHRzW3RoaXMuaGlnaGxpZ2h0cy5sZW5ndGggLSAxXV07CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgdGhlIG5hbWUgb2YgdGhlIGN1cnJlbnQgaGlnaGxpZ2h0LgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFRoZSBjb2xvciB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBnZXRIaWdobGlnaHROYW1lKCkgewogICAgICAgICAgICBpZiAodGhpcy5oaWdobGlnaHRzLmxlbmd0aCA9PSAwKSB7CiAgICAgICAgICAgICAgICByZXR1cm4gbnVsbDsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gdGhpcy5oaWdobGlnaHRzW3RoaXMuaGlnaGxpZ2h0cy5sZW5ndGggLSAxXTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyBgdHJ1ZWAgaWYgdGhpcyBpdGVtcyBoYXMgYSBoaWdobGlnaHQgY29sb3IgYXNzaWduZWQuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gYFRydWVgIGlmIHRoaXMgaXRlbSBpcyBoaWdobGlnaHRlZC4KICAgICAgICAgKi8KICAgICAgICBpc0hpZ2hsaWdodGVkKCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy5oaWdobGlnaHRzLmxlbmd0aCA+IDA7CiAgICAgICAgfQogICAgICAgIC8vIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KICAgICAgICAvLyBCb3VuZGluZyBCb3gKICAgICAgICBjbGVhbkJvdW5kaW5nQm94KCkgewogICAgICAgICAgICBjb25zdCBiYm94ID0gbmV3IEJveDMoKTsKICAgICAgICAgICAgdGhpcy5fX2NoaWxkSXRlbXMuZm9yRWFjaCgoY2hpbGRJdGVtKSA9PiB7CiAgICAgICAgICAgICAgICBpZiAoY2hpbGRJdGVtLmlzVmlzaWJsZSgpICYmIGNoaWxkSXRlbS5pc1BpY2thYmxlKCkpIHsKICAgICAgICAgICAgICAgICAgICAvLyBjb25zb2xlLmxvZygiIC0gIiwgY2hpbGRJdGVtLmNvbnN0cnVjdG9yLm5hbWUsIGNoaWxkSXRlbS5nZXROYW1lKCksIGNoaWxkSXRlbS5nbG9iYWxYZm9QYXJhbS52YWx1ZS5zYy54LCBjaGlsZEl0ZW0uZ2V0Qm91bmRpbmdCb3goKS50b1N0cmluZygpKQogICAgICAgICAgICAgICAgICAgIGNvbnN0IGJveDMgPSBjaGlsZEl0ZW0uYm91bmRpbmdCb3hQYXJhbS52YWx1ZTsKICAgICAgICAgICAgICAgICAgICBpZiAoYm94MykKICAgICAgICAgICAgICAgICAgICAgICAgYmJveC5hZGRCb3gzKGJveDMpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9KTsKICAgICAgICAgICAgLy8gY29uc29sZS5sb2codGhpcy5nZXROYW1lKCksIGJib3gudG9TdHJpbmcoKSkKICAgICAgICAgICAgcmV0dXJuIGJib3g7CiAgICAgICAgfQogICAgICAgIHNldEJvdW5kaW5nQm94RGlydHkoKSB7CiAgICAgICAgICAgIGlmICh0aGlzLmJvdW5kaW5nQm94UGFyYW0pIHsKICAgICAgICAgICAgICAgIC8vIFdpbGwgY2F1c2UgYm91bmRpbmdDaGFuZ2VkIHRvIGVtaXQKICAgICAgICAgICAgICAgIHRoaXMuYm91bmRpbmdCb3hQYXJhbS5zZXREaXJ0eSgtMSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLy8gTm90ZTogd2UgdXNlZCB0byBoYW5kbGUgdGhpcyBieSBsaXN0ZW5pbmcgdG8gYSAndmFsdWVDaGFuZ2VkJyBldmVudCBvbiB0aGUKICAgICAgICAgICAgLy8gcGFyYW1ldGVyLgogICAgICAgICAgICBpZiAodGhpcy5vd25lckl0ZW0gaW5zdGFuY2VvZiBUcmVlSXRlbSkgewogICAgICAgICAgICAgICAgdGhpcy5vd25lckl0ZW0uc2V0Qm91bmRpbmdCb3hEaXJ0eSgpOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIC8vIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KICAgICAgICAvLyBDaGlsZHJlbgogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgY2hpbGRyZW4gbGlzdCwgYnV0IGNoaWxkcmVuIGFyZSBub3QgcmVxdWlyZWQgdG8gaGF2ZSBoaWVyYXJjaHkgc3RydWN0dXJlKGBUcmVlSXRlbWApLgogICAgICAgICAqIE1lYW5pbmcgdGhhdCBpdCBjb3VsZCBiZSBhbm90aGVyIGtpbmQgb2YgaXRlbSB0aGFuIGBUcmVlSXRlbWAuCiAgICAgICAgICoKICAgICAgICAgKiBpLmUuICoqQmFzZUltYWdlKioKICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBMaXN0IG9mIGBUcmVlSXRlbWAgb3duZWQgYnkgY3VycmVudCBUcmVlSXRlbS4KICAgICAgICAgKi8KICAgICAgICBnZXRDaGlsZHJlbigpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuX19jaGlsZEl0ZW1zOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIHRoZSBudW1iZXIgb2YgY2hpbGQgdHJlZSBpdGVtcy4KICAgICAgICAgKi8KICAgICAgICBnZXROdW1DaGlsZHJlbigpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuX19jaGlsZEl0ZW1zLmxlbmd0aDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyB0aGUgbnVtYmVyIG9mIGNoaWxkIHRyZWUgaXRlbXMuCiAgICAgICAgICovCiAgICAgICAgZ2V0IG51bUNoaWxkcmVuKCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy5fX2NoaWxkSXRlbXMubGVuZ3RoOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBBcHBseSBhbiBpbmRleCB0byB0aGUgbmFtZSBpZiBuYW1lIGV4aXN0cyB3aXRoaW4gdGhpcyBpdGVtJ3MgY2hpbGRyZW4uCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gbmFtZSAtIFRoZSBuYW1lIHZhbHVlLgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGEgdW5pcXVlIG5hbWUuCiAgICAgICAgICovCiAgICAgICAgZ2VuZXJhdGVVbmlxdWVOYW1lKG5hbWUpIHsKICAgICAgICAgICAgd2hpbGUgKHRoaXMuY2hpbGRJdGVtc01hcHBpbmdbbmFtZS50b0xvY2FsZUxvd2VyQ2FzZSgpXSAhPSB1bmRlZmluZWQpIHsKICAgICAgICAgICAgICAgIGNvbnN0IGluZGV4UmVnZXhwID0gLyhcZCspJC9pOwogICAgICAgICAgICAgICAgY29uc3QgaW5kZXhNYXRjaGVzID0gbmFtZS5tYXRjaChpbmRleFJlZ2V4cCk7CiAgICAgICAgICAgICAgICBsZXQgbmV3SW5kZXggPSAxOwogICAgICAgICAgICAgICAgaWYgKGluZGV4TWF0Y2hlcykgewogICAgICAgICAgICAgICAgICAgIG5ld0luZGV4ID0gcGFyc2VJbnQoaW5kZXhNYXRjaGVzWzFdKSArIDE7CiAgICAgICAgICAgICAgICAgICAgbmFtZSA9IG5hbWUucmVwbGFjZShpbmRleFJlZ2V4cCwgJycpOyAvLyByZW1vdmUgb2xkIGluZGV4CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBuYW1lICs9IGAke25ld0luZGV4fWAucGFkU3RhcnQoMiwgJzAnKTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gbmFtZTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVXBkYXRlcyB0aGUgaW50ZXJuYWwgYWNjZWxlcmF0aW9uIHN0cnVjdHVyZSB0aGF0IHNwZWVkcyB1cCBsb29raW5nIHVwIGNoaWxkcmVuIGJ5IG5hbWUuCiAgICAgICAgICogQHBhcmFtIHN0YXJ0IC0gVGhlIHN0YXJ0IHZhbHVlLgogICAgICAgICAqIEBwcml2YXRlCiAgICAgICAgICovCiAgICAgICAgdXBkYXRlQ2hpbGROYW1lTWFwcGluZyhzdGFydCkgewogICAgICAgICAgICAvLyBJZiBhIGNoaWxkIGhhcyBiZWVuIGFkZGVkIG9yIHJlbW92ZWQgZnJvbSB0aGUKICAgICAgICAgICAgLy8gdHJlZSBpdGVtLCB3ZSBuZWVkIHRvIHVwZGF0ZSB0aGUgYWNjZWxlcmF0aW9uIHN0cnVjdHVyZS4KICAgICAgICAgICAgZm9yIChsZXQgaSA9IHN0YXJ0OyBpIDwgdGhpcy5fX2NoaWxkSXRlbXMubGVuZ3RoOyBpKyspIHsKICAgICAgICAgICAgICAgIGNvbnN0IG5hbWUgPSB0aGlzLl9fY2hpbGRJdGVtc1tpXS5uYW1lLnRvTG9jYWxlTG93ZXJDYXNlKCk7CiAgICAgICAgICAgICAgICB0aGlzLmNoaWxkSXRlbXNNYXBwaW5nW25hbWVdID0gaTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBXaGVuIGEgY2hpbGQncyBuYW1lIGNoYW5nZWQsIHdlIHVwZGF0ZSBvdXIgYWNjZWxlcmF0aW9uIHN0cnVjdHVyZS4KICAgICAgICAgKiBAcGFyYW0gZXZlbnQgLSBUaGUgc3RhcnQgdmFsdWUuCiAgICAgICAgICogQHByaXZhdGUKICAgICAgICAgKi8KICAgICAgICBjaGlsZE5hbWVDaGFuZ2VkKGV2ZW50KSB7CiAgICAgICAgICAgIC8vIFVwZGF0ZSB0aGUgYWNjZWxlcmF0aW9uIHN0cnVjdHVyZS4KICAgICAgICAgICAgaWYgKHRoaXMuY2hpbGRJdGVtc01hcHBpbmdDb3JydXB0KSB7CiAgICAgICAgICAgICAgICB0aGlzLnVwZGF0ZUNoaWxkTmFtZU1hcHBpbmcoMCk7CiAgICAgICAgICAgICAgICB0aGlzLmNoaWxkSXRlbXNNYXBwaW5nQ29ycnVwdCA9IGZhbHNlOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGVsc2UgewogICAgICAgICAgICAgICAgY29uc3Qgb2xkTmFtZSA9IGV2ZW50Lm9sZE5hbWUudG9Mb2NhbGVMb3dlckNhc2UoKTsKICAgICAgICAgICAgICAgIGNvbnN0IG5ld05hbWUgPSBldmVudC5uZXdOYW1lLnRvTG9jYWxlTG93ZXJDYXNlKCk7CiAgICAgICAgICAgICAgICBjb25zdCBpbmRleCA9IHRoaXMuY2hpbGRJdGVtc01hcHBpbmdbb2xkTmFtZV07CiAgICAgICAgICAgICAgICBpZiAodGhpcy5jaGlsZEl0ZW1zTWFwcGluZ1tuZXdOYW1lXSAhPSB1bmRlZmluZWQpCiAgICAgICAgICAgICAgICAgICAgdGhpcy5jaGlsZEl0ZW1zTWFwcGluZ0NvcnJ1cHQgPSB0cnVlOwogICAgICAgICAgICAgICAgZGVsZXRlIHRoaXMuY2hpbGRJdGVtc01hcHBpbmdbb2xkTmFtZV07CiAgICAgICAgICAgICAgICB0aGlzLmNoaWxkSXRlbXNNYXBwaW5nW25ld05hbWVdID0gaW5kZXg7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogSW5zZXJ0cyBhIGNoaWxkLiBJdCBhY2NlcHRzIGFsbCBraW5kIG9mIGBUcmVlSXRlbWAsIG5vdCBvbmx5IGBUcmVlSXRlbWAuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gY2hpbGRJdGVtIC0gVGhlIGNoaWxkIFRyZWVJdGVtIHRvIGluc2VydC4KICAgICAgICAgKiBAcGFyYW0gaW5kZXggLSBUaGUgaW5kZXggdG8gYWRkIHRoZSBjaGlsZCBpdGVtLgogICAgICAgICAqIEBwYXJhbSBtYWludGFpblhmbyAtIEJvb2xlYW4gdGhhdCBkZXRlcm1pbmVzIGlmIHRoZSBYZm8gdmFsdWUgaXMgbWFpbnRhaW5lZC4KICAgICAgICAgKiBAcGFyYW0gZml4Q29sbGlzaW9ucyAtIE1vZGlmeSB0aGUgbmFtZSBvZiB0aGUgaXRlbSB0byBhdm9pZCBuYW1lIGNvbGxpc2lvbnMuCiAgICAgICAgICogSWYgZmFsc2UsIGFuIGV4Y2VwdGlvbiB3bGwgYmUgdGhyb3duIGluc3RlYWQgaWYgYSBuYW1lIGNvbGxpc2lvbiBvY2N1cnMuCiAgICAgICAgICogQHJldHVybiAtIFRoZSBpbmRleCBvZiB0aGUgY2hpbGQgaXRlbSBpbiB0aGlzIGl0ZW1zIGNoaWxkcmVuIGFycmF5LgogICAgICAgICAqLwogICAgICAgIGluc2VydENoaWxkKGNoaWxkSXRlbSwgaW5kZXgsIG1haW50YWluWGZvID0gZmFsc2UsIGZpeENvbGxpc2lvbnMgPSB0cnVlKSB7CiAgICAgICAgICAgIGxldCBuYW1lID0gY2hpbGRJdGVtLm5hbWU7CiAgICAgICAgICAgIGxldCBuYW1lTGMgPSBuYW1lLnRvTG9jYWxlTG93ZXJDYXNlKCk7CiAgICAgICAgICAgIGlmIChuYW1lTGMgaW4gdGhpcy5jaGlsZEl0ZW1zTWFwcGluZykgewogICAgICAgICAgICAgICAgaWYgKGZpeENvbGxpc2lvbnMpIHsKICAgICAgICAgICAgICAgICAgICBuYW1lID0gdGhpcy5nZW5lcmF0ZVVuaXF1ZU5hbWUobmFtZSk7CiAgICAgICAgICAgICAgICAgICAgbmFtZUxjID0gbmFtZS50b0xvY2FsZUxvd2VyQ2FzZSgpOwogICAgICAgICAgICAgICAgICAgIGNoaWxkSXRlbS5zZXROYW1lKG5hbWUpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCJJdGVtICciICsgbmFtZSArICInIGlzIGFscmVhZHkgYSBjaGlsZCBvZiA6IiArIHRoaXMuZ2V0UGF0aCgpKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoIShjaGlsZEl0ZW0gaW5zdGFuY2VvZiBUcmVlSXRlbSkpIHsKICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignT2JqZWN0IGlzIGlzIG5vdCBhIHRyZWUgaXRlbSA6JyArIGNoaWxkSXRlbSk7IC8vIFRPRE86IG5lZWQgYmV0dGVyIG91dHB1dCBoZXJlKyBjaGlsZEl0ZW0uY29uc3RydWN0b3IubmFtZSkKICAgICAgICAgICAgfQogICAgICAgICAgICBjb25zdCBsaXN0ZW5lcklEcyA9IHt9OwogICAgICAgICAgICBsaXN0ZW5lcklEc1snbmFtZUNoYW5nZWQnXSA9IGNoaWxkSXRlbS5vbignbmFtZUNoYW5nZWQnLCAoZXZlbnQpID0+IHsKICAgICAgICAgICAgICAgIHRoaXMuY2hpbGROYW1lQ2hhbmdlZChldmVudCk7CiAgICAgICAgICAgIH0pOwogICAgICAgICAgICBsZXQgcHJldkdsb2JhbDsKICAgICAgICAgICAgaWYgKG1haW50YWluWGZvKSB7CiAgICAgICAgICAgICAgICBwcmV2R2xvYmFsID0gY2hpbGRJdGVtLmdsb2JhbFhmb1BhcmFtLnZhbHVlOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHRoaXMuc2V0Qm91bmRpbmdCb3hEaXJ0eSgpOwogICAgICAgICAgICB0aGlzLmhpZ2hsaWdodHMuZm9yRWFjaCgobmFtZSkgPT4gewogICAgICAgICAgICAgICAgY2hpbGRJdGVtLmFkZEhpZ2hsaWdodChuYW1lLCB0aGlzLmhpZ2hsaWdodE1hcHBpbmdbbmFtZV0sIHRydWUpOwogICAgICAgICAgICB9KTsKICAgICAgICAgICAgY2hpbGRJdGVtLnNldEluaGVyaXRlZE9wYWNpdHkodGhpcywgdGhpcy5vcGFjaXR5KTsKICAgICAgICAgICAgdGhpcy5fX2NoaWxkSXRlbXMuc3BsaWNlKGluZGV4LCAwLCBjaGlsZEl0ZW0pOwogICAgICAgICAgICB0aGlzLl9fY2hpbGRJdGVtc0V2ZW50SGFuZGxlcnMuc3BsaWNlKGluZGV4LCAwLCBsaXN0ZW5lcklEcyk7CiAgICAgICAgICAgIC8vIElmIHdlIGhhdmUgbm9uLXVuaXF1ZSBuYW1lcywgd2UgbmVlZCB0byByZWdlbmVyYXRlIHRoaXMgbWFwcGluZy4KICAgICAgICAgICAgaWYgKHRoaXMuY2hpbGRJdGVtc01hcHBpbmdbbmFtZUxjXSkKICAgICAgICAgICAgICAgIHRoaXMuY2hpbGRJdGVtc01hcHBpbmdDb3JydXB0ID0gdHJ1ZTsKICAgICAgICAgICAgdGhpcy5jaGlsZEl0ZW1zTWFwcGluZ1tuYW1lTGNdID0gaW5kZXg7CiAgICAgICAgICAgIHRoaXMudXBkYXRlQ2hpbGROYW1lTWFwcGluZyhpbmRleCArIDEpOwogICAgICAgICAgICBjaGlsZEl0ZW0uc2V0T3duZXIodGhpcyk7CiAgICAgICAgICAgIGlmIChtYWludGFpblhmbykgewogICAgICAgICAgICAgICAgLy8gTWFpbmFpbiB0aGUgcHJldmlvdXMgZ2xvYmFsIFhmby4KICAgICAgICAgICAgICAgIGNoaWxkSXRlbS5nbG9iYWxYZm9QYXJhbS52YWx1ZSA9IHByZXZHbG9iYWw7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdGhpcy5lbWl0KCdjaGlsZEFkZGVkJywgbmV3IENoaWxkQWRkZWRFdmVudChpbmRleCwgY2hpbGRJdGVtKSk7CiAgICAgICAgICAgIHJldHVybiBjaGlsZEl0ZW07CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEFkZHMgYSBjaGlsZC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBjaGlsZEl0ZW0gLSBUaGUgY2hpbGQgVHJlZUl0ZW0gdG8gYWRkLgogICAgICAgICAqIEBwYXJhbSBtYWludGFpblhmbyAtIEJvb2xlYW4gdGhhdCBkZXRlcm1pbmVzIGlmCiAgICAgICAgICogdGhlIEdsb2JhbCBYZm8gdmFsdWUgaXMgbWFpbnRhaW5lZC4gSWYgdHJ1ZSwgd2hlbiBtb3ZpbmcKICAgICAgICAgKiBpdGVtcyBpbiB0aGUgaGllcmFyY2h5IGZyb20gb25lIHBhcmVudCB0byBhbm90aGVyLCB0aGUgbG9jYWwgWGZvCiAgICAgICAgICogb2YgdGhlIGl0ZW0gd2lsbCBiZSBtb2RpZmllZCB0byBtYWludGFpbiBhbmQgdGhlIEdsb2JhbCBYZm8uCiAgICAgICAgICogTm90ZTogdGhpcyBvcHRpb24gZGVmYXVsdHMgdG8gZmFsc2UgYmVjYXVzZSB3ZSBleHBlY3QgdGhhdCBpcyB0aGUKICAgICAgICAgKiBiZWhhdmlvciB1c2VycyB3b3VsZCBleHBlY3Qgd2hlbiBtYW5pcHVsYXRpbmcgdGhlIHRyZWUgaW4gY29kZS4KICAgICAgICAgKiBUbyBiZSBzYWZlIGFuZCB1bmFtYmlndW91cywgYWx3YXlzIHRyeSB0byBzcGVjaWZ5IHRoaXMgdmFsdWUuCiAgICAgICAgICogQHBhcmFtIGZpeENvbGxpc2lvbnMgLSBNb2RpZnkgdGhlIG5hbWUgb2YgdGhlIGl0ZW0gdG8gYXZvaWQKICAgICAgICAgKiBuYW1lIGNvbGxpc2lvbnMgd2l0aCBvdGhlciBjaGlsZHJlbiBvZiB0aGUgc2FtZSBwYXJlbnQuCiAgICAgICAgICogSWYgZmFsc2UsIGFuIGV4Y2VwdGlvbiB3bGwgYmUgdGhyb3duIGluc3RlYWQgaWYgYSBuYW1lIGNvbGxpc2lvbiBvY2N1cnMuCiAgICAgICAgICogQHJldHVybiBjaGlsZEl0ZW0gLSBUaGUgY2hpbGQgVHJlZUl0ZW0gdGhhdCB3YXMgYWRkZWQuCiAgICAgICAgICovCiAgICAgICAgYWRkQ2hpbGQoY2hpbGRJdGVtLCBtYWludGFpblhmbyA9IHRydWUsIGZpeENvbGxpc2lvbnMgPSB0cnVlKSB7CiAgICAgICAgICAgIGNvbnN0IGluZGV4ID0gdGhpcy5fX2NoaWxkSXRlbXMubGVuZ3RoOwogICAgICAgICAgICB0aGlzLmluc2VydENoaWxkKGNoaWxkSXRlbSwgaW5kZXgsIG1haW50YWluWGZvLCBmaXhDb2xsaXNpb25zKTsKICAgICAgICAgICAgcmV0dXJuIGNoaWxkSXRlbTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyBjaGlsZCBlbGVtZW50IGluIHRoZSBzcGVjaWZpZWQgaW5kZXguCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gaW5kZXggLSBUaGUgaW5kZXggdG8gcmVtb3ZlIHRoZSBjaGlsZCBUcmVlSXRlbS4KICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJuIHRoZSBjaGlsZCBUcmVlSXRlbS4KICAgICAgICAgKi8KICAgICAgICBnZXRDaGlsZChpbmRleCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy5fX2NoaWxkSXRlbXNbaW5kZXhdOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIGNoaWxkIGVsZW1lbnQgd2l0aCB0aGUgc3BlY2lmaWVkIG5hbWUuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gbmFtZSAtIFRoZSBuYW1lIHZhbHVlLgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm4gdGhlIGNoaWxkIFRyZWVJdGVtLgogICAgICAgICAqLwogICAgICAgIGdldENoaWxkQnlOYW1lKG5hbWUpIHsKICAgICAgICAgICAgY29uc3QgaW5kZXggPSB0aGlzLmNoaWxkSXRlbXNNYXBwaW5nW25hbWUudG9Mb2NhbGVMb3dlckNhc2UoKV07CiAgICAgICAgICAgIGlmIChpbmRleCAhPSB1bmRlZmluZWQpIHsKICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLl9fY2hpbGRJdGVtc1tpbmRleF07CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIG51bGw7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgY2hpbGRyZW4gbmFtZXMgYXMgYW4gYXJyYXkgb2Ygc3RyaW5ncy4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBBbiBhcnJheSBvZiBuYW1lcyBmb3IgZWFjaCBjaGlsZC4KICAgICAgICAgKi8KICAgICAgICBnZXRDaGlsZE5hbWVzKCkgewogICAgICAgICAgICBjb25zdCBuYW1lcyA9IFtdOwogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuX19jaGlsZEl0ZW1zLmxlbmd0aDsgaSsrKSB7CiAgICAgICAgICAgICAgICBjb25zdCBjaGlsZEl0ZW0gPSB0aGlzLl9fY2hpbGRJdGVtc1tpXTsKICAgICAgICAgICAgICAgIGlmIChjaGlsZEl0ZW0gIT0gbnVsbCkKICAgICAgICAgICAgICAgICAgICBuYW1lc1tpXSA9IGNoaWxkSXRlbS5nZXROYW1lKCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIG5hbWVzOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBVbkJpbmQgYW4gaXRlbSBmcm9tIHRoZSBncm91cC4gVGhpcyBtZXRob2QgaXMgY2FsbGVkCiAgICAgICAgICogYXV0b21hdGljYWxseSB3aGVuIGFuIGl0ZW0gaXMgcmVtb3ZlZCBmcm9tIHRoZSBncm91cC4KICAgICAgICAgKiBAcGFyYW0gaW5kZXggLSBUaGUgaW5kZXggdmFsdWUuCiAgICAgICAgICogQHBhcmFtIGNoaWxkSXRlbSAtIGl0ZW0gdG8gdW5iaW5kLgogICAgICAgICAqIEBwcml2YXRlCiAgICAgICAgICovCiAgICAgICAgdW5iaW5kQ2hpbGQoaW5kZXgsIGNoaWxkSXRlbSkgewogICAgICAgICAgICBjb25zdCBsaXN0ZW5lcklEcyA9IHRoaXMuX19jaGlsZEl0ZW1zRXZlbnRIYW5kbGVyc1tpbmRleF07CiAgICAgICAgICAgIGNoaWxkSXRlbS5vZmYoJ25hbWVDaGFuZ2VkJywgbGlzdGVuZXJJRHNbJ25hbWVDaGFuZ2VkJ10pOwogICAgICAgICAgICB0aGlzLl9fY2hpbGRJdGVtcy5zcGxpY2UoaW5kZXgsIDEpOwogICAgICAgICAgICB0aGlzLl9fY2hpbGRJdGVtc0V2ZW50SGFuZGxlcnMuc3BsaWNlKGluZGV4LCAxKTsKICAgICAgICAgICAgZGVsZXRlIHRoaXMuY2hpbGRJdGVtc01hcHBpbmdbY2hpbGRJdGVtLm5hbWUudG9Mb2NhbGVMb3dlckNhc2UoKV07CiAgICAgICAgICAgIHRoaXMudXBkYXRlQ2hpbGROYW1lTWFwcGluZyhpbmRleCk7CiAgICAgICAgICAgIHRoaXMuc2V0Qm91bmRpbmdCb3hEaXJ0eSgpOwogICAgICAgICAgICB0aGlzLmVtaXQoJ2NoaWxkUmVtb3ZlZCcsIHsgY2hpbGRJdGVtLCBpbmRleCB9KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmVtb3ZlcyBhIGNoaWxkIFRyZWVJdGVtIGJ5IHNwZWNpZnlpbmcgaXRzIGluZGV4LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGluZGV4IC0gVGhlIGluZGV4IHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHJlbW92ZUNoaWxkKGluZGV4KSB7CiAgICAgICAgICAgIGNvbnN0IGNoaWxkSXRlbSA9IHRoaXMuX19jaGlsZEl0ZW1zW2luZGV4XTsKICAgICAgICAgICAgaWYgKCFjaGlsZEl0ZW0pIHsKICAgICAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgICAgfQogICAgICAgICAgICB0aGlzLnVuYmluZENoaWxkKGluZGV4LCBjaGlsZEl0ZW0pOwogICAgICAgICAgICBjaGlsZEl0ZW0uc2V0T3duZXIodW5kZWZpbmVkKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmVtb3ZlcyBhIGNoaWxkIFRyZWVJdGVtIGJ5IHNwZWNpZnlpbmcgaXRzIG5hbWUuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gbmFtZSAtIFRoZSBuYW1lIHBhcmFtLgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm4gdGhlIGNoaWxkIFRyZWVJdGVtLgogICAgICAgICAqLwogICAgICAgIHJlbW92ZUNoaWxkQnlOYW1lKG5hbWUpIHsKICAgICAgICAgICAgY29uc3QgaW5kZXggPSB0aGlzLmNoaWxkSXRlbXNNYXBwaW5nW25hbWUudG9Mb2NhbGVMb3dlckNhc2UoKV07CiAgICAgICAgICAgIGlmIChpbmRleCAhPSB1bmRlZmluZWQpIHsKICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLnJlbW92ZUNoaWxkKGluZGV4KTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZW1vdmVzIHRoZSBwcm92aWRlZCBpdGVtIGZyb20gdGhpcyBUcmVlSXRlbSBpZiBpdCBpcyBvbmUgb2YgaXRzIGNoaWxkcmVuLgogICAgICAgICAqIEFuIGV4Y2VwdGlvbiBpcyB0aHJvd24gaWYgdGhlIGl0ZW0gaXMgbm90IGEgY2hpbGQgb2YgdGhpcyB0cmVlIGl0ZW0uCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gY2hpbGRJdGVtIC0gVGhlIGNoaWxkIFRyZWVJdGVtIHRvIHJlbW92ZS4KICAgICAgICAgKi8KICAgICAgICByZW1vdmVDaGlsZEJ5SGFuZGxlKGNoaWxkSXRlbSkgewogICAgICAgICAgICBjb25zdCBpbmRleCA9IHRoaXMuX19jaGlsZEl0ZW1zLmluZGV4T2YoY2hpbGRJdGVtKTsKICAgICAgICAgICAgaWYgKGluZGV4ID09IC0xKQogICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdFcnJvciBpbiByZW1vdmVDaGlsZEJ5SGFuZGxlLiBDaGlsZCBub3QgZm91bmQ6JyArIGNoaWxkSXRlbS5nZXROYW1lKCkpOwogICAgICAgICAgICB0aGlzLnJlbW92ZUNoaWxkKGluZGV4KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmVtb3ZlcyBhbGwgY2hpbGRyZW4gSXRlbXMuCiAgICAgICAgICovCiAgICAgICAgcmVtb3ZlQWxsQ2hpbGRyZW4oKSB7CiAgICAgICAgICAgIGxldCBpbmRleCA9IHRoaXMuX19jaGlsZEl0ZW1zLmxlbmd0aDsKICAgICAgICAgICAgd2hpbGUgKGluZGV4LS0pIHsKICAgICAgICAgICAgICAgIHRoaXMucmVtb3ZlQ2hpbGQoaW5kZXgpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHRoaXMuc2V0Qm91bmRpbmdCb3hEaXJ0eSgpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIGluZGV4IHBvc2l0aW9uIG9mIHRoZSBzcGVjaWZpZWQgaXRlbS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBjaGlsZEl0ZW0gLSBUaGUgY2hpbGQgVHJlZUl0ZW0gdmFsdWUuCiAgICAgICAgICogQHJldHVybiAtIENoaWxkIGluZGV4IGluIGNoaWxkcmVuIGFycmF5LgogICAgICAgICAqLwogICAgICAgIGdldENoaWxkSW5kZXgoY2hpbGRJdGVtKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLl9fY2hpbGRJdGVtcy5pbmRleE9mKGNoaWxkSXRlbSk7CiAgICAgICAgfQogICAgICAgIC8vIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KICAgICAgICAvLyBQYXRoIFRyYXZlcnNhbAogICAgICAgIC8vIE5vdGU6IFBhdGggcmVzb2x1dGlvbiBzdGFydHMgYXQgdGhlIHJvb3Qgb2YgdGhlCiAgICAgICAgLy8gdHJlZSB0aGUgcGF0aCB3YXMgZ2VuZXJhdGVkIGZyb20gKHNvIGluZGV4PTEsIGJlY2F1c2Ugd2UgZG9uJ3QgcmVzb2x2ZSByb290KS4KICAgICAgICAvLyBOb3RlOiBXaGVuIGEgcGF0aCBpcyBtYWRlIHJlbGF0aXZlIHRvIGFuIGl0ZW0gaW4gaXRzIHRyZWUsIHRoZSBwYXRoCiAgICAgICAgLy8gc3RhcnRzIHdpdGggdGhlIGNoaWxkIGVsZW1lbnRzLgogICAgICAgIC8qKgogICAgICAgICAqIFRoZSByZXNvbHZlUGF0aCBtZXRob2QgdHJhdmVyc2VzIHRoZSBzdWJ0cmVlIGZyb20gdGhpcyBpdGVtIGRvd24KICAgICAgICAgKiBtYXRjaGluZyBlYWNoIG5hbWUgaW4gdGhlIHBhdGggd2l0aCBhIGNoaWxkIHVudGlsIGl0IHJlYWNoZXMgdGhlCiAgICAgICAgICogZW5kIG9mIHRoZSBwYXRoLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHBhdGggLSBUaGUgcGF0aCB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0gaW5kZXggLSBUaGUgaW5kZXggdmFsdWUuCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgcmVzb2x2ZVBhdGgocGF0aCwgaW5kZXggPSAwKSB7CiAgICAgICAgICAgIGlmIChpbmRleCA9PSAwKSB7CiAgICAgICAgICAgICAgICBpZiAocGF0aFswXSA9PSAnLicgfHwgcGF0aFswXSA9PSB0aGlzLm5hbWUpCiAgICAgICAgICAgICAgICAgICAgaW5kZXgrKzsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAocGF0aFtpbmRleF0gPT0gJy4uJykgewogICAgICAgICAgICAgICAgaWYgKHRoaXMub3duZXJJdGVtKSB7CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMub3duZXJJdGVtLnJlc29sdmVQYXRoKHBhdGgsIGluZGV4ICsgMSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgICAgICB0aHJvdyBFcnJvcigndGhpcy5vd25lckl0ZW0gaXMgdW5kZWZpbmVkJyk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKGluZGV4ID09IHBhdGgubGVuZ3RoKSB7CiAgICAgICAgICAgICAgICByZXR1cm4gdGhpczsKICAgICAgICAgICAgfQogICAgICAgICAgICBjb25zdCBjaGlsZE5hbWUgPSBwYXRoW2luZGV4XTsKICAgICAgICAgICAgY29uc3QgY2hpbGRJdGVtID0gdGhpcy5nZXRDaGlsZEJ5TmFtZShjaGlsZE5hbWUpOwogICAgICAgICAgICBpZiAoY2hpbGRJdGVtKSB7CiAgICAgICAgICAgICAgICByZXR1cm4gY2hpbGRJdGVtLnJlc29sdmVQYXRoKHBhdGgsIGluZGV4ICsgMSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIHN1cGVyLnJlc29sdmVQYXRoKHBhdGgsIGluZGV4KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVHJhdmVyc2UgdGhlIHRyZWUgc3RydWN0dXJlIGZyb20gdGhpcyBwb2ludCBkb3duCiAgICAgICAgICogYW5kIGZpcmUgdGhlIGNhbGxiYWNrIGZvciBlYWNoIHZpc2l0ZWQgaXRlbS4KICAgICAgICAgKiBOb3RlOiBEZXB0aCBvbmx5IHVzZWQgYnkgc2VsZWN0aW9uIHNldHMgZm9yIG5vdy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBjYWxsYmFjayAtIFRoZSBjYWxsYmFjayB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0gaW5jbHVkZVRoaXMgLSBGaXJlIHRoZSBjYWxsYmFjayBmb3IgdGhpcyBpdGVtLgogICAgICAgICAqLwogICAgICAgIHRyYXZlcnNlKGNhbGxiYWNrLCBpbmNsdWRlVGhpcyA9IHRydWUpIHsKICAgICAgICAgICAgY29uc3QgX19jID0gKHRyZWVJdGVtLCBkZXB0aCkgPT4gewogICAgICAgICAgICAgICAgY29uc3QgY2hpbGRyZW4gPSB0cmVlSXRlbS5nZXRDaGlsZHJlbigpOwogICAgICAgICAgICAgICAgZm9yIChjb25zdCBjaGlsZEl0ZW0gb2YgY2hpbGRyZW4pIHsKICAgICAgICAgICAgICAgICAgICBpZiAoY2hpbGRJdGVtKQogICAgICAgICAgICAgICAgICAgICAgICBfX3QoY2hpbGRJdGVtLCBkZXB0aCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH07CiAgICAgICAgICAgIGNvbnN0IF9fdCA9ICh0cmVlSXRlbSwgZGVwdGgpID0+IHsKICAgICAgICAgICAgICAgIGlmIChjYWxsYmFjayh0cmVlSXRlbSwgZGVwdGgpID09IGZhbHNlKQogICAgICAgICAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgICAgICAgIF9fYyh0cmVlSXRlbSwgZGVwdGggKyAxKTsKICAgICAgICAgICAgfTsKICAgICAgICAgICAgaWYgKGluY2x1ZGVUaGlzKSB7CiAgICAgICAgICAgICAgICBfX3QodGhpcywgMSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZWxzZSB7CiAgICAgICAgICAgICAgICBfX2ModGhpcywgMCk7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgLy8gLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KICAgICAgICAvLyBFdmVudHMKICAgICAgICAvKioKICAgICAgICAgKiBDYWxsZWQgYnkgdGhlIFZpZXdwb3J0IHdoZW4gZXZlbnRzIGFyZSByZWNlaXZlZCBieSB0aGUgY2FudmFzIGVsZW1lbnQuCiAgICAgICAgICogVGhlIGV2ZW50IGlzIHByb3BhZ2F0ZWQgdG8gYSBUcmVlSXRlbSBpZiBpdCBpcyB1bmRlciB0aGUgcG9pbnRlciBhdCB0aGUgdGltZS4KICAgICAgICAgKiBUaGUgWmVhUG9pbnRlckV2ZW50IGFic3RyYWN0cyB0aGUgTW91c2UsIHRvdWNoIGFuZCBvdXIgY3VzdG9tIFhSIGV2ZW50cy4KICAgICAgICAgKiBUaGlzIG1ldGhvZCBlbWl0cyB0aGUgWmVhUG9pbnRlckV2ZW50IHdpdGggdGhlIGtleSAncG9pbnRlckRvd24nLCBhbmQKICAgICAgICAgKiBwcm9wYWdhdGVzIGl0IHVwIHRvIHRoZSBUcmVlSXRlbSdzIG93bmVyLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGV2ZW50IC0gVGhlIGV2ZW50IHZhbHVlCiAgICAgICAgICovCiAgICAgICAgb25Qb2ludGVyRG93bihldmVudCkgewogICAgICAgICAgICB0aGlzLmVtaXQoJ3BvaW50ZXJEb3duJywgZXZlbnQpOwogICAgICAgICAgICBpZiAoZXZlbnQucHJvcGFnYXRpbmcgJiYgdGhpcy5vd25lckl0ZW0gaW5zdGFuY2VvZiBUcmVlSXRlbSkgewogICAgICAgICAgICAgICAgdGhpcy5vd25lckl0ZW0ub25Qb2ludGVyRG93bihldmVudCk7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ2FsbGVkIGJ5IHRoZSBWaWV3cG9ydCB3aGVuIGV2ZW50cyBhcmUgcmVjZWl2ZWQgYnkgdGhlIGNhbnZhcyBlbGVtZW50LgogICAgICAgICAqIFRoZSBldmVudCBpcyBwcm9wYWdhdGVkIHRvIGEgVHJlZUl0ZW0gaWYgaXQgaXMgdW5kZXIgdGhlIHBvaW50ZXIgYXQgdGhlIHRpbWUuCiAgICAgICAgICogVGhlIFplYVBvaW50ZXJFdmVudCBhYnN0cmFjdHMgdGhlIE1vdXNlLCB0b3VjaCBhbmQgb3VyIGN1c3RvbSBYUiBldmVudHMuCiAgICAgICAgICogVGhpcyBtZXRob2QgZW1pdHMgdGhlIFplYVBvaW50ZXJFdmVudCB3aXRoIHRoZSBrZXkgJ3BvaW50ZXJEb3duJywgYW5kCiAgICAgICAgICogcHJvcGFnYXRlcyBpdCB1cCB0byB0aGUgVHJlZUl0ZW0ncyBvd25lci4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBldmVudCAtIFRoZSBwb2ludGVyIGV2ZW50IHRoYXQgd2FzIGdlbmVyYXRlZCBmcm9tIHRoZSB1c2VyIGludGVyYWN0aW9uCiAgICAgICAgICovCiAgICAgICAgb25Qb2ludGVyVXAoZXZlbnQpIHsKICAgICAgICAgICAgdGhpcy5lbWl0KCdwb2ludGVyVXAnLCBldmVudCk7CiAgICAgICAgICAgIGlmIChldmVudC5wcm9wYWdhdGluZyAmJiB0aGlzLm93bmVySXRlbSBpbnN0YW5jZW9mIFRyZWVJdGVtKSB7CiAgICAgICAgICAgICAgICB0aGlzLm93bmVySXRlbS5vblBvaW50ZXJVcChldmVudCk7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ2FsbGVkIGJ5IHRoZSBWaWV3cG9ydCB3aGVuIGV2ZW50cyBhcmUgcmVjZWl2ZWQgYnkgdGhlIGNhbnZhcyBlbGVtZW50LgogICAgICAgICAqIFRoZSBldmVudCBpcyBwcm9wYWdhdGVkIHRvIGEgVHJlZUl0ZW0gaWYgaXQgaXMgdW5kZXIgdGhlIHBvaW50ZXIgYXQgdGhlIHRpbWUuCiAgICAgICAgICogVGhlIFplYVBvaW50ZXJFdmVudCBhYnN0cmFjdHMgdGhlIE1vdXNlLCB0b3VjaCBhbmQgb3VyIGN1c3RvbSBYUiBldmVudHMuCiAgICAgICAgICogVGhpcyBtZXRob2QgZW1pdHMgdGhlIFplYVBvaW50ZXJFdmVudCB3aXRoIHRoZSBrZXkgJ3BvaW50ZXJNb3ZlJywgYW5kCiAgICAgICAgICogcHJvcGFnYXRlcyBpdCB1cCB0byB0aGUgVHJlZUl0ZW0ncyBvd25lci4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBldmVudCAtIFRoZSBwb2ludGVyIGV2ZW50IHRoYXQgd2FzIGdlbmVyYXRlZCBmcm9tIHRoZSB1c2VyIGludGVyYWN0aW9uCiAgICAgICAgICovCiAgICAgICAgb25Qb2ludGVyTW92ZShldmVudCkgewogICAgICAgICAgICB0aGlzLmVtaXQoJ3BvaW50ZXJNb3ZlJywgZXZlbnQpOwogICAgICAgICAgICBpZiAoZXZlbnQucHJvcGFnYXRpbmcgJiYgdGhpcy5vd25lckl0ZW0gaW5zdGFuY2VvZiBUcmVlSXRlbSkgewogICAgICAgICAgICAgICAgdGhpcy5vd25lckl0ZW0ub25Qb2ludGVyTW92ZShldmVudCk7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ2FsbGVkIGJ5IHRoZSBWaWV3cG9ydCB3aGVuIHRoZSBtb3VzZSBvciBvdGhlciBwb2ludGVyIGVudGVycyB0aGUgY2FudmFzIGVsZW1lbnQuCiAgICAgICAgICogVGhlIGV2ZW50IGlzIHByb3BhZ2F0ZWQgdG8gYSBUcmVlSXRlbSBpZiBpdCBpcyB1bmRlciB0aGUgcG9pbnRlciBhdCB0aGUgdGltZS4KICAgICAgICAgKiBUaGUgWmVhUG9pbnRlckV2ZW50IGFic3RyYWN0cyB0aGUgTW91c2UsIHRvdWNoIGFuZCBvdXIgY3VzdG9tIFhSIGV2ZW50cy4KICAgICAgICAgKiBUaGlzIG1ldGhvZCBlbWl0cyB0aGUgWmVhUG9pbnRlckV2ZW50IHdpdGggdGhlIGtleSAncG9pbnRlckVudGVyJywgYW5kCiAgICAgICAgICogcHJvcGFnYXRlcyBpdCB1cCB0byB0aGUgVHJlZUl0ZW0ncyBvd25lci4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBldmVudCAtIFRoZSBwb2ludGVyIGV2ZW50IHRoYXQgd2FzIGdlbmVyYXRlZCBmcm9tIHRoZSB1c2VyIGludGVyYWN0aW9uCiAgICAgICAgICovCiAgICAgICAgb25Qb2ludGVyRW50ZXIoZXZlbnQpIHsKICAgICAgICAgICAgdGhpcy5lbWl0KCdwb2ludGVyRW50ZXInLCBldmVudCk7CiAgICAgICAgICAgIGlmIChldmVudC5wcm9wYWdhdGluZyAmJiB0aGlzLm93bmVySXRlbSBpbnN0YW5jZW9mIFRyZWVJdGVtKSB7CiAgICAgICAgICAgICAgICB0aGlzLm93bmVySXRlbS5vblBvaW50ZXJFbnRlcihldmVudCk7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ2FsbGVkIGJ5IHRoZSBWaWV3cG9ydCB3aGVuIHRoZSBtb3VzZSBvciBvdGhlciBwb2ludGVyIGxlYXZlcyB0aGUgY2FudmFzIGVsZW1lbnQuCiAgICAgICAgICogVGhlIGV2ZW50IGlzIHByb3BhZ2F0ZWQgdG8gYSBUcmVlSXRlbSBpZiBpdCBpcyB1bmRlciB0aGUgcG9pbnRlciBhdCB0aGUgdGltZS4KICAgICAgICAgKiBUaGUgWmVhUG9pbnRlckV2ZW50IGFic3RyYWN0cyB0aGUgTW91c2UsIHRvdWNoIGFuZCBvdXIgY3VzdG9tIFhSIGV2ZW50cy4KICAgICAgICAgKiBUaGlzIG1ldGhvZCBlbWl0cyB0aGUgWmVhUG9pbnRlckV2ZW50IHdpdGggdGhlIGtleSAncG9pbnRlckxlYXZlJywgYW5kCiAgICAgICAgICogcHJvcGFnYXRlcyBpdCB1cCB0byB0aGUgVHJlZUl0ZW0ncyBvd25lci4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBldmVudCAtIFRoZSBwb2ludGVyIGV2ZW50IHRoYXQgd2FzIGdlbmVyYXRlZCBmcm9tIHRoZSB1c2VyIGludGVyYWN0aW9uCiAgICAgICAgICovCiAgICAgICAgb25Qb2ludGVyTGVhdmUoZXZlbnQpIHsKICAgICAgICAgICAgdGhpcy5lbWl0KCdwb2ludGVyTGVhdmUnLCBldmVudCk7CiAgICAgICAgICAgIGlmIChldmVudC5wcm9wYWdhdGluZyAmJiB0aGlzLm93bmVySXRlbSBpbnN0YW5jZW9mIFRyZWVJdGVtKSB7CiAgICAgICAgICAgICAgICB0aGlzLm93bmVySXRlbS5vblBvaW50ZXJMZWF2ZShldmVudCk7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ2FsbGVkIGJ5IHRoZSBWaWV3cG9ydCB3aGVuIHRoZSBtb3VzZSBvciBvdGhlciBwb2ludGVyIGlzIGNsaWNrZWQgb24gdGhpcyBpdGVtLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGV2ZW50IC0gVGhlIHBvaW50ZXIgZXZlbnQgdGhhdCB3YXMgZ2VuZXJhdGVkIGZyb20gdGhlIHVzZXIgaW50ZXJhY3Rpb24KICAgICAgICAgKi8KICAgICAgICBvblBvaW50ZXJDbGljayhldmVudCkgewogICAgICAgICAgICB0aGlzLmVtaXQoJ3BvaW50ZXJDbGljaycsIGV2ZW50KTsKICAgICAgICAgICAgaWYgKGV2ZW50LnByb3BhZ2F0aW5nICYmIHRoaXMub3duZXJJdGVtIGluc3RhbmNlb2YgVHJlZUl0ZW0pIHsKICAgICAgICAgICAgICAgIHRoaXMub3duZXJJdGVtLm9uUG9pbnRlckNsaWNrKGV2ZW50KTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDYWxsZWQgYnkgdGhlIFZpZXdwb3J0IHdoZW4gdGhlIG1vdXNlIG9yIG90aGVyIHBvaW50ZXIgaXMgZG91YmxlLWNsaWNrZWQgb24gdGhpcyBpdGVtLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGV2ZW50IC0gVGhlIHBvaW50ZXIgZXZlbnQgdGhhdCB3YXMgZ2VuZXJhdGVkIGZyb20gdGhlIHVzZXIgaW50ZXJhY3Rpb24KICAgICAgICAgKi8KICAgICAgICBvblBvaW50ZXJEb3VibGVDbGljayhldmVudCkgewogICAgICAgICAgICB0aGlzLmVtaXQoJ3BvaW50ZXJEb3VibGVDbGljaycsIGV2ZW50KTsKICAgICAgICAgICAgaWYgKGV2ZW50LnByb3BhZ2F0aW5nICYmIHRoaXMub3duZXJJdGVtIGluc3RhbmNlb2YgVHJlZUl0ZW0pIHsKICAgICAgICAgICAgICAgIHRoaXMub3duZXJJdGVtLm9uUG9pbnRlckRvdWJsZUNsaWNrKGV2ZW50KTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDYWxsZWQgYnkgdGhlIFZpZXdwb3J0IHdoZW4gdGhlIG1vdXNlIG9yIG90aGVyIHBvaW50ZXIgaXMgZG91YmxlLWNsaWNrZWQgb24gdGhpcyBpdGVtLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGV2ZW50IC0gVGhlIHBvaW50ZXIgZXZlbnQgdGhhdCB3YXMgZ2VuZXJhdGVkIGZyb20gdGhlIHVzZXIgaW50ZXJhY3Rpb24KICAgICAgICAgKi8KICAgICAgICBvblBvaW50ZXJMb25nUHJlc3MoZXZlbnQpIHsKICAgICAgICAgICAgdGhpcy5lbWl0KCdwb2ludGVyTG9uZ1ByZXNzJywgZXZlbnQpOwogICAgICAgICAgICBpZiAoZXZlbnQucHJvcGFnYXRpbmcgJiYgdGhpcy5vd25lckl0ZW0gaW5zdGFuY2VvZiBUcmVlSXRlbSkgewogICAgICAgICAgICAgICAgdGhpcy5vd25lckl0ZW0ub25Qb2ludGVyTG9uZ1ByZXNzKGV2ZW50KTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDYWxsZWQgYnkgdGhlIFZpZXdwb3J0IHdoZW4gdGhlIG1vdXNlIHdoZWVsIGV2ZW50IGlzIHJlY2VpdmVkIGJ5IHRoZSBjYW52YXMgZWxlbWVudC4KICAgICAgICAgKiBFbWl0cyB0aGUgWmVhV2hlZWxFdmVudCB3aXRoIHRoZSBrZXkgJ21vdXNlV2hlZWwnLCBhbmQgUHJvcGFnYXRlcyBpcyB1cCB0byB0aGUgVHJlZUl0ZW0ncyBvd25lci4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBldmVudCAtIFRoZSB3aGVlbCBldmVudCB0aGF0IG9jY3Vycy4KICAgICAgICAgKi8KICAgICAgICBvbldoZWVsKGV2ZW50KSB7CiAgICAgICAgICAgIHRoaXMuZW1pdCgnbW91c2VXaGVlbCcsIGV2ZW50KTsKICAgICAgICAgICAgaWYgKGV2ZW50LnByb3BhZ2F0aW5nICYmIHRoaXMub3duZXJJdGVtIGluc3RhbmNlb2YgVHJlZUl0ZW0pIHsKICAgICAgICAgICAgICAgIHRoaXMub3duZXJJdGVtLm9uV2hlZWwoZXZlbnQpOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENhbGxlZCBieSB0aGUgVmlld3BvcnQgd2hlbiB0aGUgdG91Y2ggY2FuY2VsIGV2ZW50IGlzIHJlY2VpdmVkIGJ5IHRoZSBjYW52YXMgZWxlbWVudC4KICAgICAgICAgKiBFbWl0cyB0aGUgWmVhVG91Y2hFdmVudCB3aXRoIHRoZSBrZXkgJ3RvdWNoQ2FuY2VsJywgYW5kIFByb3BhZ2F0ZXMgaXMgdXAgdG8gdGhlIFRyZWVJdGVtJ3Mgb3duZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gZXZlbnQgLSBUaGUgd2hlZWwgZXZlbnQgdGhhdCBvY2N1cnMuCiAgICAgICAgICovCiAgICAgICAgb25Ub3VjaENhbmNlbChldmVudCkgewogICAgICAgICAgICB0aGlzLmVtaXQoJ3RvdWNoQ2FuY2VsJywgZXZlbnQpOwogICAgICAgICAgICBpZiAoZXZlbnQucHJvcGFnYXRpbmcgJiYgdGhpcy5vd25lckl0ZW0gaW5zdGFuY2VvZiBUcmVlSXRlbSkgewogICAgICAgICAgICAgICAgdGhpcy5vd25lckl0ZW0ub25Ub3VjaENhbmNlbChldmVudCk7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgLy8gLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwogICAgICAgIC8vIFBlcnNpc3RlbmNlCiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIHRvSlNPTiBtZXRob2Qgc2VyaWFsaXplcyB0aGlzIGluc3RhbmNlIGFzIGEgSlNPTi4KICAgICAgICAgKiBJdCBjYW4gYmUgdXNlZCBmb3IgcGVyc2lzdGVuY2UsIGRhdGEgdHJhbnNmZXIsIGV0Yy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBjb250ZXh0IC0gVGhlIGNvbnRleHQgdmFsdWUuCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgdGhlIGpzb24gb2JqZWN0LgogICAgICAgICAqLwogICAgICAgIHRvSlNPTihjb250ZXh0KSB7CiAgICAgICAgICAgIGxldCBqID0gc3VwZXIudG9KU09OKGNvbnRleHQpOwogICAgICAgICAgICAvLyBTb21lIEl0ZW1zLCBzdWNoIGFzIHRoZSBTbGlkZXJTY2VuZVdpZGdldCBkbyBub3QgbmVlZCB0aGVpciBjaGlsZHJlbgogICAgICAgICAgICAvLyB0byBiZSBzYXZlZC4KICAgICAgICAgICAgY29uc3QgY2hpbGRJdGVtc0pTT04gPSB7fTsKICAgICAgICAgICAgZm9yIChjb25zdCBjaGlsZEl0ZW0gb2YgdGhpcy5fX2NoaWxkSXRlbXMpIHsKICAgICAgICAgICAgICAgIGlmIChjaGlsZEl0ZW0pIHsKICAgICAgICAgICAgICAgICAgICBjb25zdCBjaGlsZEpTT04gPSBjaGlsZEl0ZW0udG9KU09OKGNvbnRleHQpOwogICAgICAgICAgICAgICAgICAgIGlmIChjaGlsZEpTT04pCiAgICAgICAgICAgICAgICAgICAgICAgIGNoaWxkSXRlbXNKU09OW2NoaWxkSXRlbS5nZXROYW1lKCldID0gY2hpbGRKU09OOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIChPYmplY3Qua2V5cyhjaGlsZEl0ZW1zSlNPTikubGVuZ3RoID4gMCkgewogICAgICAgICAgICAgICAgaWYgKGopIHsKICAgICAgICAgICAgICAgICAgICBqLmNoaWxkcmVuID0gY2hpbGRJdGVtc0pTT047CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgICAgICBqID0gewogICAgICAgICAgICAgICAgICAgICAgICBuYW1lOiB0aGlzLm5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgIGNoaWxkcmVuOiBjaGlsZEl0ZW1zSlNPTiwKICAgICAgICAgICAgICAgICAgICB9OwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBqOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgZnJvbUpTT04gbWV0aG9kIHRha2VzIGEgSlNPTiBhbmQgZGVzZXJpYWxpemVzIGludG8gYW4gaW5zdGFuY2Ugb2YgdGhpcyB0eXBlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGogLSBUaGUganNvbiBvYmplY3QgdGhpcyBpdGVtIG11c3QgZGVjb2RlLgogICAgICAgICAqIEBwYXJhbSBjb250ZXh0IC0gVGhlIGNvbnRleHQgdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgZnJvbUpTT04oaiwgY29udGV4dCwgb25Eb25lKSB7CiAgICAgICAgICAgIHN1cGVyLmZyb21KU09OKGosIGNvbnRleHQpOwogICAgICAgICAgICAvLyBpZiAoJ2Jib3gnIGluIGopewogICAgICAgICAgICAvLyAgICAgbGV0IGJveCA9IG5ldyBCb3gzKCk7CiAgICAgICAgICAgIC8vICAgICBib3guZnJvbUpTT04oai5iYm94KTsKICAgICAgICAgICAgLy8gICAgIHRoaXMuYm91bmRpbmdCb3hQYXJhbS52YWx1ZSA9IGJveCkKICAgICAgICAgICAgLy8gfQogICAgICAgICAgICBpZiAoai5jaGlsZHJlbiAhPSBudWxsKSB7CiAgICAgICAgICAgICAgICBjb25zdCBjaGlsZHJlbkpzb24gPSBqLmNoaWxkcmVuOwogICAgICAgICAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkoY2hpbGRyZW5Kc29uKSkgewogICAgICAgICAgICAgICAgICAgIGZvciAoY29uc3QgY2hpbGRKc29uIG9mIGNoaWxkcmVuSnNvbikgewogICAgICAgICAgICAgICAgICAgICAgICAvLyBOb3RlOiBEdXJpbmcgbG9hZGluZyBvZiBhc3NldCB0cmVlcywgd2UgaGF2ZSBhbgogICAgICAgICAgICAgICAgICAgICAgICAvLyBleGlzdGluZyB0cmVlIGdlbmVyYXRlZCBieSBsb2FkaW5nIGEgYmluIGRhdGEgZmlsZS4KICAgICAgICAgICAgICAgICAgICAgICAgbGV0IGNoaWxkSXRlbSA9IHRoaXMuZ2V0Q2hpbGRCeU5hbWUoY2hpbGRKc29uLm5hbWUpOwogICAgICAgICAgICAgICAgICAgICAgICBpZiAoY2hpbGRJdGVtKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjaGlsZEl0ZW0uZnJvbUpTT04oY2hpbGRKc29uLCBjb250ZXh0KTsKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChjaGlsZEpzb24udHlwZSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNoaWxkSXRlbSA9IFJlZ2lzdHJ5LmNvbnN0cnVjdENsYXNzKGNoaWxkSnNvbi50eXBlKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoY2hpbGRJdGVtKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIE5vdGU6IHdlIHNob3VsZCBsb2FkIHRoZSBqc29uIGZpcnN0LCBhcyBpdAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBtYXkgY29udGFpbiB0aGUgdW5pcXVlIG5hbWUgb2YgdGhlIGl0ZW0uCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNoaWxkSXRlbS5mcm9tSlNPTihjaGlsZEpzb24sIGNvbnRleHQpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmFkZENoaWxkKGNoaWxkSXRlbSwgZmFsc2UsIGZhbHNlKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZ3VhcmQtZm9yLWluCiAgICAgICAgICAgICAgICAgICAgZm9yIChjb25zdCBjaGlsZE5hbWUgaW4gY2hpbGRyZW5Kc29uKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGNoaWxkSnNvbiA9IGNoaWxkcmVuSnNvbltjaGlsZE5hbWVdOwogICAgICAgICAgICAgICAgICAgICAgICAvLyBOb3RlOiBEdXJpbmcgbG9hZGluZyBvZiBhc3NldCB0cmVlcywgd2UgaGF2ZSBhbgogICAgICAgICAgICAgICAgICAgICAgICAvLyBleGlzdGluZyB0cmVlIGdlbmVyYXRlZCBieSBsb2FkaW5nIGEgYmluIGRhdGEgZmlsZS4KICAgICAgICAgICAgICAgICAgICAgICAgbGV0IGNoaWxkSXRlbSA9IHRoaXMuZ2V0Q2hpbGRCeU5hbWUoY2hpbGROYW1lKTsKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGNoaWxkSXRlbSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgY2hpbGRJdGVtLmZyb21KU09OKGNoaWxkSnNvbiwgY29udGV4dCk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSBpZiAoY2hpbGRKc29uLnR5cGUpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNoaWxkSXRlbSA9IFJlZ2lzdHJ5LmNvbnN0cnVjdENsYXNzKGNoaWxkSnNvbi50eXBlKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChjaGlsZEl0ZW0pIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBOb3RlOiB3ZSBhZGQgdGhlIGNoaWxkIG5vdyBiZWZvcmUgbG9hZGluZy4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBUaGlzIGlzIGJlY2F1c2UgY2VydGFpbiBpdGVtcy4gKGUuZy4gR3JvdXBzKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIENhbGN1bGF0ZSB0aGVpciBnbG9iYWwgWGZvLCBhbmQgdXNlIGl0IHRvIG1vZGlmeQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHRoZSB0cmFuc2Zvcm0gb2YgdGhlaXIgbWVtYmVycy4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBOb3RlOiBHcm91cHMgYmluZCB0byBpdGVtcyBpbiB0aGUgc2NlbmUgd2hpY2ggYXJlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gYWxyZWFkeSBhZGRlZCBhcyBjaGlsZHJlbiwgYW5kIHNvIGhhdmUgZ2xvYmFsIFhmb3MuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gV2UgcHJlZmVyIHRvIGFkZCBhIGNoaWxkIGFmdGVyIGl0cyBsb2FkZWQsIGJlY2F1c2Ugc29tZXRpbWVzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gSW4gdGhlIHRyZWUgaXMgYXNzZXQgaXRlbXMsIHdobyB3aWxsIG9ubHkgdG9nZ2xlZCBhcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHVubG9hZGVkIG9uY2UgdGhleSBhcmUgbG9hZGVkKGVsc2UgdGhleSBhcmUgY29uc2lkZXJlZCBpbmxpbmUgYXNzZXRzLikKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjaGlsZEl0ZW0uZnJvbUpTT04oY2hpbGRKc29uLCBjb250ZXh0KTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmFkZENoaWxkKGNoaWxkSXRlbSwgZmFsc2UsIGZhbHNlKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICBlbHNlIDsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLy8gaWYgKGouY29tcG9uZW50cykgewogICAgICAgICAgICAvLyAgIGZvciAoY29uc3QgY2ogb2Ygai5jb21wb25lbnRzKSB7CiAgICAgICAgICAgIC8vICAgICBjb25zdCBjb21wb25lbnQgPSBSZWdpc3RyeS5jb25zdHJ1Y3RDbGFzcyhjai50eXBlID8gY2oudHlwZSA6IGNqLm5hbWUpCiAgICAgICAgICAgIC8vICAgICBpZiAoY29tcG9uZW50KSB7CiAgICAgICAgICAgIC8vICAgICAgIGNvbXBvbmVudC5mcm9tSlNPTihjaiwgY29udGV4dCkKICAgICAgICAgICAgLy8gICAgICAgdGhpcy5hZGRDb21wb25lbnQoY29tcG9uZW50KQogICAgICAgICAgICAvLyAgICAgfQogICAgICAgICAgICAvLyAgIH0KICAgICAgICAgICAgLy8gfQogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTZXRzIHN0YXRlIG9mIGN1cnJlbnQgSXRlbShJbmNsdWRpbmcgcGFyYW1ldGVycyAmIGNoaWxkcmVuKSB1c2luZyBhIGJpbmFyeSByZWFkZXIgb2JqZWN0LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHJlYWRlciAtIFRoZSByZWFkZXIgdmFsdWUuCiAgICAgICAgICogQHBhcmFtIGNvbnRleHQgLSBUaGUgY29udGV4dCB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICByZWFkQmluYXJ5KHJlYWRlciwgY29udGV4dCkgewogICAgICAgICAgICBzdXBlci5yZWFkQmluYXJ5KHJlYWRlciwgY29udGV4dCk7CiAgICAgICAgICAgIGNvbnN0IGl0ZW1GbGFncyA9IHJlYWRlci5sb2FkVUludDgoKTsKICAgICAgICAgICAgY29uc3QgdmlzaWJpbGl0eUZsYWcgPSAxIDw8IDE7CiAgICAgICAgICAgIC8vIE5vdGU6IFhSZWYgbG9hZHMgYSB2aXNpYmxpdHkgc2V0dGluZyBmb3IgaXRzZWxmIHdoZW4gbG9hZGluZyBpbiB0aGUgcGFyZW50IGFzc2VtYmx5IHRyZWUsCiAgICAgICAgICAgIC8vIHRoZW4gaXQgbG9hZHMgdGhlIHpjYWQgZmlsZSB3aGljaCBjb250YWlucyBhIHZpc2liaWxpdHkgc2V0dGluZyBmb3IgdGhlIENBREFzc3NldC4gVGhpcwogICAgICAgICAgICAvLyB2aXNpYmlsaXR5IHNldHRpbmcgd291bGQgb3ZlcnJpZGUgdGhlIFhSZWYuIElkZWFsbHkgdGhlIHpjYWQgZmlsZSB3b3VsZCBub3Qgc3RvcmUgYSB2aXNpYmxpdHkKICAgICAgICAgICAgLy8gc2V0dGluZyBmb3IgdGhlIENBREFzc2V0LCBhcyB0aGF0IHNob3VsZCBiZSBzZXQgYnkgdGhlIGxvYWRpbmcgY29udGV4dC4KICAgICAgICAgICAgLy8gVmlzaWJsZSBpcyB0cnVlIGJ5IGRlZmF1bHQsIHNvIG9ubHkgc2V0IGl0IHRvIGZhbHNlLiBUaGlzIGlzIHRvIHdvcmsgYXJvdW5kIHRoZSBhYm92ZSBjb25mbGljdC4KICAgICAgICAgICAgaWYgKChpdGVtRmxhZ3MgJiB2aXNpYmlsaXR5RmxhZykgPT0gMCkKICAgICAgICAgICAgICAgIHRoaXMuc2V0VmlzaWJsZShmYWxzZSk7CiAgICAgICAgICAgIC8vIE5vdGU6IHRvIHNhdmUgc3BhY2UsIHNvbWUgdmFsdWVzIGFyZSBza2lwcGVkIGlmIHRoZXkgYXJlIGlkZW50aXR5IHZhbHVlcwogICAgICAgICAgICBjb25zdCBsb2NhbFhmb0ZsYWcgPSAxIDw8IDI7CiAgICAgICAgICAgIGNvbnN0IGxvY2FsWGZvSW5kZXBlbmRlbnRTY0ZsYWcgPSAxIDw8IDU7CiAgICAgICAgICAgIGlmIChpdGVtRmxhZ3MgJiBsb2NhbFhmb0ZsYWcpIHsKICAgICAgICAgICAgICAgIGNvbnN0IHhmbyA9IG5ldyBYZm8oKTsKICAgICAgICAgICAgICAgIHhmby50ciA9IHJlYWRlci5sb2FkRmxvYXQzMlZlYzMoKTsKICAgICAgICAgICAgICAgIHhmby5vcmkgPSByZWFkZXIubG9hZEZsb2F0MzJRdWF0KCk7CiAgICAgICAgICAgICAgICBpZiAoaXRlbUZsYWdzICYgbG9jYWxYZm9JbmRlcGVuZGVudFNjRmxhZykgewogICAgICAgICAgICAgICAgICAgIHhmby5zYyA9IHJlYWRlci5sb2FkRmxvYXQzMlZlYzMoKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGVsc2UgewogICAgICAgICAgICAgICAgICAgIGNvbnN0IHNjID0gcmVhZGVyLmxvYWRGbG9hdDMyKCk7CiAgICAgICAgICAgICAgICAgICAgeGZvLnNjLnNldChzYywgc2MsIHNjKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIHRoaXMubG9jYWxYZm9QYXJhbS52YWx1ZSA9IHhmbzsKICAgICAgICAgICAgfQogICAgICAgICAgICBjb25zdCBiYm94RmxhZyA9IDEgPDwgMzsKICAgICAgICAgICAgaWYgKGl0ZW1GbGFncyAmIGJib3hGbGFnKSB7CiAgICAgICAgICAgICAgICB0aGlzLmJvdW5kaW5nQm94UGFyYW0ubG9hZFZhbHVlKG5ldyBCb3gzKHJlYWRlci5sb2FkRmxvYXQzMlZlYzMoKSwgcmVhZGVyLmxvYWRGbG9hdDMyVmVjMygpKSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgY29uc3QgbnVtQ2hpbGRyZW4gPSByZWFkZXIubG9hZFVJbnQzMigpOwogICAgICAgICAgICBpZiAobnVtQ2hpbGRyZW4gPiAwKSB7CiAgICAgICAgICAgICAgICBjb25zdCB0b2MgPSByZWFkZXIubG9hZFVJbnQzMkFycmF5KG51bUNoaWxkcmVuKTsKICAgICAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbnVtQ2hpbGRyZW47IGkrKykgewogICAgICAgICAgICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHJlYWRlci5zZWVrKHRvY1tpXSk7IC8vIFJlc2V0IHRoZSBwb2ludGVyIHRvIHRoZSBzdGFydCBvZiB0aGUgaXRlbSBkYXRhLgogICAgICAgICAgICAgICAgICAgICAgICBsZXQgY2hpbGRUeXBlID0gcmVhZGVyLmxvYWRTdHIoKTsKICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgY2hpbGRJdGVtID0gUmVnaXN0cnkuY29uc3RydWN0Q2xhc3MoY2hpbGRUeXBlKTsKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFjaGlsZEl0ZW0pIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGNoaWxkTmFtZSA9IHJlYWRlci5sb2FkU3RyKCk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oJ1VuYWJsZSB0byBjb25zdHJ1Y3QgY2hpbGQ6JyArIGNoaWxkTmFtZSArICcgb2YgdHlwZTonICsgY2hpbGRUeXBlKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgIHJlYWRlci5zZWVrKHRvY1tpXSk7IC8vIFJlc2V0IHRoZSBwb2ludGVyIHRvIHRoZSBzdGFydCBvZiB0aGUgaXRlbSBkYXRhLgogICAgICAgICAgICAgICAgICAgICAgICBjaGlsZEl0ZW0ucmVhZEJpbmFyeShyZWFkZXIsIGNvbnRleHQpOwogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmFkZENoaWxkKGNoaWxkSXRlbSwgZmFsc2UsIHRydWUpOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBjYXRjaCAoZSkgewogICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oJ0Vycm9yIGxvYWRpbmcgdHJlZSBpdGVtOiAnLCBlKTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgLy8gLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwogICAgICAgIC8vIENsb25lIGFuZCBEZXN0cm95CiAgICAgICAgY2xvbmUoY29udGV4dCkgewogICAgICAgICAgICBjb25zdCBjbG9uZWQgPSBuZXcgVHJlZUl0ZW0oJycpOwogICAgICAgICAgICBjbG9uZWQuY29weUZyb20odGhpcywgY29udGV4dCk7CiAgICAgICAgICAgIHJldHVybiBjbG9uZWQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvcGllcyBjdXJyZW50IFRyZWVJdGVtIHdpdGggYWxsIGl0cyBjaGlsZHJlbi4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBzcmMgLSBUaGUgdHJlZSBpdGVtIHRvIGNvcHkgZnJvbS4KICAgICAgICAgKiBAcGFyYW0gY29udGV4dCAtIFRoZSBjb250ZXh0IHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGNvcHlGcm9tKHNyYywgY29udGV4dCkgewogICAgICAgICAgICBpZiAoIShzcmMgaW5zdGFuY2VvZiBUcmVlSXRlbSkpIHsKICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignY2Fubm90IGNvcHkgZnJvbSBzcmMnKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBzdXBlci5jb3B5RnJvbShzcmMsIGNvbnRleHQpOwogICAgICAgICAgICAvLyBOb3RlOiBjb25maWd1cmUgdmlzaWJsaXR5IGFuZCBvcGFjaXR5IGJlZm9yZSBhZGRpbmcgY2hpbGRyZW4uIFRoZXkgd2lsbAogICAgICAgICAgICAvLyBpbmhlcml0IHRoZXNlIHNldHRpbmdzIGFzIHRoZXkgYXJlIGFkZGVkLgogICAgICAgICAgICB0aGlzLnZpc2libGVDb3VudGVyID0gdGhpcy52aXNpYmxlUGFyYW0udmFsdWUgPyAxIDogMDsKICAgICAgICAgICAgdGhpcy51cGRhdGVWaXNpYmlsaXR5KCk7CiAgICAgICAgICAgIHRoaXMudXBkYXRlT3BhY2l0eSgpOwogICAgICAgICAgICAvLyBOb3RlOiBJZiBhIHRyZWUgaXRlbSBhbHJlYWR5IGhhZCBjaGlsZHJlbiwgd2UgbXVzdCBjbGVhciB0aGVtIGJlZm9yZSBhZGRpbmcgZnJvbSB0aGUgc3JjLgogICAgICAgICAgICAvLyBBbiBYUmVmIHN0b3JlZCBpbiBhbiBhc3NlbWJseSBtYXkgY29udGFpbiBhIGNhY2hlIG9mIGl0cyBzdWJ0cmVlLgogICAgICAgICAgICAvLyBJZiB0aGUgWFJlZiB1cmwgZG9lcyByZXNvbHZlIHRvIGEgZmlsZSwgd2UgbXVzdCBjbGVhciB0aGlzIGNhY2hlIGJlZm9yZSBsb2FkaW5nIHRoZSBhY3R1YWwgZGF0YS4KICAgICAgICAgICAgdGhpcy5yZW1vdmVBbGxDaGlsZHJlbigpOwogICAgICAgICAgICBzcmMuZ2V0Q2hpbGRyZW4oKS5mb3JFYWNoKChzcmNDaGlsZEl0ZW0pID0+IHsKICAgICAgICAgICAgICAgIGlmIChzcmNDaGlsZEl0ZW0pCiAgICAgICAgICAgICAgICAgICAgdGhpcy5hZGRDaGlsZChzcmNDaGlsZEl0ZW0uY2xvbmUoY29udGV4dCksIGZhbHNlLCBmYWxzZSk7CiAgICAgICAgICAgIH0pOwogICAgICAgIH0KICAgIH0KICAgIFJlZ2lzdHJ5LnJlZ2lzdGVyKCdUcmVlSXRlbScsIFRyZWVJdGVtKTsKCiAgICAvKiBlc2xpbnQtZGlzYWJsZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tZXhwbGljaXQtYW55ICovCiAgICAvKioKICAgICAqIFJlcHJlc2VudHMgYSBzcGVjaWZpYyB0eXBlIG9mIHBhcmFtZXRlciwgdGhhdCBvbmx5IHN0b3JlcyBgVHJlZUl0ZW1gIHZhbHVlcy4KICAgICAqCiAgICAgKiBpLmUuOgogICAgICogYGBgamF2YXNjcmlwdAogICAgICogY29uc3QgdHJlZUl0ZW0gPSBuZXcgVHJlZUl0ZW0oJ3RyZWUxJykKICAgICAqIGNvbnN0IHRyZWVJdGVtUGFyYW0gPSBuZXcgVHJlZUl0ZW1QYXJhbWV0ZXIoJ015VHJlZUl0ZW0nLCB0cmVlSXRlbSkKICAgICAqIC8vJ215UGFyYW1ldGVyT3duZXJJdGVtJyBpcyBhbiBpbnN0YW5jZSBvZiBhICdQYXJhbWV0ZXJPd25lcicgY2xhc3MuCiAgICAgKiAvLyBSZW1lbWJlciB0aGF0IG9ubHkgJ1BhcmFtZXRlck93bmVyJyBhbmQgY2xhc3NlcyB0aGF0IGV4dGVuZCBmcm9tIGl0IGNhbiBob3N0ICdQYXJhbWV0ZXInIG9iamVjdHMuCiAgICAgKiBteVBhcmFtZXRlck93bmVySXRlbS5hZGRQYXJhbWV0ZXIodHJlZUl0ZW1QYXJhbSkKICAgICAqIGBgYAogICAgICoKICAgICAqICoqRXZlbnRzKioKICAgICAqICogKip0cmVlSXRlbUdsb2JhbFhmb0NoYW5nZWQ6KiogVHJpZ2dlcmVkIHdoZW4gY29tcHV0ZWQgd29ybGQgWGZvIG9mIHBhcmFtZXRlcidzIGBUcmVlSXRlbWAgY2hhbmdlcy4KICAgICAqICogKip2YWx1ZUNoYW5nZWQ6KiogVHJpZ2dlcmVkIHdoZW4gcGFyYW1ldGVyJ3MgdmFsdWUgY2hhbmdlcy4KICAgICAqCiAgICAgKiBAZXh0ZW5kcyBQYXJhbWV0ZXIKICAgICAqLwogICAgY2xhc3MgVHJlZUl0ZW1QYXJhbWV0ZXIgZXh0ZW5kcyBQYXJhbWV0ZXIgewogICAgICAgIGZpbHRlckZuOwogICAgICAgIGxpc3RlbmVySURzID0ge307CiAgICAgICAgLyoqCiAgICAgICAgICogQ3JlYXRlIGEgdHJlZSBpdGVtIHBhcmFtZXRlci4KICAgICAgICAgKiBAcGFyYW0gbmFtZSAtIFRoZSBuYW1lIG9mIHRoZSB0cmVlIGl0ZW0gcGFyYW1ldGVyLgogICAgICAgICAqIEBwYXJhbSBmaWx0ZXJGbiAtIFRoZSBmaWx0ZXJGbiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBjb25zdHJ1Y3RvcihuYW1lID0gJycsIGZpbHRlckZuKSB7CiAgICAgICAgICAgIHN1cGVyKG5hbWUsIG51bGwsICdUcmVlSXRlbScpOwogICAgICAgICAgICB0aGlzLmZpbHRlckZuID0gZmlsdGVyRm47CiAgICAgICAgfQogICAgICAgIGVtaXRUcmVlSXRlbUdsb2JhbFhmb0NoYW5nZWQoZXZlbnQpIHsKICAgICAgICAgICAgdGhpcy5lbWl0KCd0cmVlSXRlbUdsb2JhbFhmb0NoYW5nZWQnLCBldmVudCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBzZXRGaWx0ZXJGbiBtZXRob2QuCiAgICAgICAgICogQHBhcmFtIGZpbHRlckZuIC0gVGhlIGZpbHRlckZuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHNldEZpbHRlckZuKGZpbHRlckZuKSB7CiAgICAgICAgICAgIHRoaXMuZmlsdGVyRm4gPSBmaWx0ZXJGbjsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGdldEZpbHRlckZuIG1ldGhvZC4KICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBnZXRGaWx0ZXJGbigpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuZmlsdGVyRm47CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFNldHMgcGFyYW1ldGVyJ3MgYFRyZWVJdGVtYCB2YWx1ZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB2YWx1ZSAtIFRoZSB0cmVlSXRlbSB2YWx1ZQogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHNldFZhbHVlKHZhbHVlKSB7CiAgICAgICAgICAgIGlmICghKHZhbHVlIGluc3RhbmNlb2YgVHJlZUl0ZW0pKSB7CiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYHZhbHVlIHByb3ZpZGVkIGlzIG5vdCBhbiBpbnN0YW5jZSBvZiBhICdUcmVlSXRlbScgY2xhc3MuIENoZWNrIHRoZSBzb3VyY2Ugb2YgdGhpcyB2YWx1ZWApOwogICAgICAgICAgICB9CiAgICAgICAgICAgIC8vIDAgPT0gbm9ybWFsIHNldC4gMSA9IGNoYW5nZWQgdmlhIGNsZWFuZXIgZm4sIDI9Y2hhbmdlIGJ5IGxvYWRpbmcvY2xvbmluZyBjb2RlLgogICAgICAgICAgICBpZiAodGhpcy5maWx0ZXJGbiAmJiAhdGhpcy5maWx0ZXJGbih2YWx1ZSkpCiAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgIGlmICh0aGlzLnZhbHVlICE9PSB2YWx1ZSkgewogICAgICAgICAgICAgICAgaWYgKHRoaXMudmFsdWUpIHsKICAgICAgICAgICAgICAgICAgICB0aGlzLnZhbHVlLm9mZignZ2xvYmFsWGZvQ2hhbmdlZCcsIHRoaXMubGlzdGVuZXJJRHNbJ2dsb2JhbFhmb0NoYW5nZWQnXSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBzdXBlci5zZXRWYWx1ZSh2YWx1ZSk7CiAgICAgICAgICAgICAgICBpZiAodGhpcy52YWx1ZSkgewogICAgICAgICAgICAgICAgICAgIHRoaXMubGlzdGVuZXJJRHNbJ2dsb2JhbFhmb0NoYW5nZWQnXSA9IHRoaXMudmFsdWUub24oJ2dsb2JhbFhmb0NoYW5nZWQnLCAoZXZlbnQpID0+IHsKICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5lbWl0VHJlZUl0ZW1HbG9iYWxYZm9DaGFuZ2VkKGV2ZW50KTsKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICAvLyAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCiAgICAgICAgLy8gUGVyc2lzdGVuY2UKICAgICAgICAvKioKICAgICAgICAgKiBUaGUgdG9KU09OIG1ldGhvZCBlbmNvZGVzIHRoaXMgdHlwZSBhcyBhIGpzb24gb2JqZWN0IGZvciBwZXJzaXN0ZW5jZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBjb250ZXh0IC0gVGhlIGNvbnRleHQgdmFsdWUuCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgdGhlIGpzb24gb2JqZWN0LgogICAgICAgICAqLwogICAgICAgIHRvSlNPTihjb250ZXh0KSB7CiAgICAgICAgICAgIHJldHVybiB7CiAgICAgICAgICAgICAgICB0eXBlOiB0aGlzLmdldENsYXNzTmFtZSgpLAogICAgICAgICAgICAgICAgbmFtZTogdGhpcy5uYW1lLAogICAgICAgICAgICAgICAgdmFsdWU6IGNvbnRleHQubWFrZVJlbGF0aXZlKHRoaXMudmFsdWU/LmdldFBhdGgoKSksCiAgICAgICAgICAgIH07CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBmcm9tSlNPTiBtZXRob2QgZGVjb2RlcyBhIGpzb24gb2JqZWN0IGZvciB0aGlzIHR5cGUuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gaiAtIFRoZSBqc29uIG9iamVjdCB0aGlzIGl0ZW0gbXVzdCBkZWNvZGUuCiAgICAgICAgICogQHBhcmFtIGNvbnRleHQgLSBUaGUgY29udGV4dCB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBmcm9tSlNPTihqLCBjb250ZXh0KSB7CiAgICAgICAgICAgIGlmIChqLnZhbHVlID09IG51bGwpIHsKICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybignSW52YWxpZCBQYXJhbWV0ZXIgSlNPTicpOwogICAgICAgICAgICAgICAgcmV0dXJuOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGNvbnRleHQucmVzb2x2ZVBhdGgoai52YWx1ZSwgKHRyZWVJdGVtKSA9PiB7CiAgICAgICAgICAgICAgICB0aGlzLnNldFZhbHVlKHRyZWVJdGVtKTsKICAgICAgICAgICAgfSwgKCkgPT4gewogICAgICAgICAgICAgICAgY29uc29sZS53YXJuKCdVbmFibGUgdG8gcmVzb2x2ZSB0cmVlIGl0ZW0gcGFyYW1ldGVyIHZhbHVlOicgKyBqLnBhcmFtUGF0aCk7CiAgICAgICAgICAgIH0pOwogICAgICAgIH0KICAgICAgICAvLyAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCiAgICAgICAgLy8gQ2xvbmUgYW5kIERlc3Ryb3kKICAgICAgICAvKioKICAgICAgICAgKiBUaGUgY2xvbmUgbWV0aG9kIGNvbnN0cnVjdHMgYSBuZXcgdHJlZSBpdGVtIHBhcmFtZXRlciwgY29waWVzIGl0cyB2YWx1ZXMKICAgICAgICAgKiBmcm9tIHRoaXMgcGFyYW1ldGVyIGFuZCByZXR1cm5zIGl0LgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgYSBuZXcgdHJlZSBpdGVtIHBhcmFtZXRlci4KICAgICAgICAgKi8KICAgICAgICBjbG9uZShjb250ZXh0KSB7CiAgICAgICAgICAgIGNvbnN0IGNsb25lZFBhcmFtID0gbmV3IFRyZWVJdGVtUGFyYW1ldGVyKHRoaXMubmFtZSwgdGhpcy5maWx0ZXJGbik7CiAgICAgICAgICAgIGlmICh0aGlzLnZhbHVlKQogICAgICAgICAgICAgICAgY2xvbmVkUGFyYW0uc2V0VmFsdWUodGhpcy52YWx1ZS5jbG9uZShjb250ZXh0KSk7CiAgICAgICAgICAgIHJldHVybiBjbG9uZWRQYXJhbTsKICAgICAgICB9CiAgICB9CiAgICBSZWdpc3RyeS5yZWdpc3RlcignVHJlZUl0ZW1QYXJhbWV0ZXInLCBUcmVlSXRlbVBhcmFtZXRlcik7CgogICAgLyogZXNsaW50LWRpc2FibGUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWV4cGxpY2l0LWFueSAqLwogICAgY2xhc3MgSXRlbUV2ZW50IGV4dGVuZHMgQmFzZUV2ZW50IHsKICAgICAgICBpdGVtOwogICAgICAgIGluZGV4OwogICAgICAgIGNvbnN0cnVjdG9yKGl0ZW0sIGluZGV4KSB7CiAgICAgICAgICAgIHN1cGVyKCk7CiAgICAgICAgICAgIHRoaXMuaW5kZXggPSBpbmRleDsKICAgICAgICAgICAgdGhpcy5pdGVtID0gaXRlbTsKICAgICAgICB9CiAgICB9CiAgICAvKiogQ2xhc3MgcmVwcmVzZW50aW5nIGFuIGl0ZW0gc2V0IHBhcmFtZXRlci4KICAgICAqIEBleHRlbmRzIFBhcmFtZXRlcgogICAgICogQHByaXZhdGUKICAgICAqLwogICAgY2xhc3MgSXRlbVNldFBhcmFtZXRlciBleHRlbmRzIFBhcmFtZXRlciB7CiAgICAgICAgZmlsdGVyRm47CiAgICAgICAgLyoqCiAgICAgICAgICogQ3JlYXRlIGFuIGl0ZW0gc2V0IHBhcmFtZXRlci4KICAgICAgICAgKiBAcGFyYW0gbmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBpdGVtIHNldCBwYXJhbWV0ZXIuCiAgICAgICAgICogQHBhcmFtIGZpbHRlckZuIC0gVGhlIGZpbHRlckZuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGNvbnN0cnVjdG9yKG5hbWUgPSAnJywgZmlsdGVyRm4pIHsKICAgICAgICAgICAgc3VwZXIobmFtZSwgbmV3IFNldCgpLCAnVHJlZUl0ZW0nKTsKICAgICAgICAgICAgdGhpcy5maWx0ZXJGbiA9IGZpbHRlckZuOyAvLyBOb3RlOiB0aGUgZmlsdGVyIEZuIGluZGljYXRlcyB0aGF0IHVzZXJzIHdpbGwgZWRpdCB0aGUgc2V0LgogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgc2V0RmlsdGVyRm4gbWV0aG9kLgogICAgICAgICAqIEBwYXJhbSBmaWx0ZXJGbiAtIFRoZSBmaWx0ZXJGbiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBzZXRGaWx0ZXJGbihmaWx0ZXJGbikgewogICAgICAgICAgICB0aGlzLmZpbHRlckZuID0gZmlsdGVyRm47CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBnZXRGaWx0ZXJGbiBtZXRob2QuCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgZ2V0RmlsdGVyRm4oKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLmZpbHRlckZuOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgZ2V0SXRlbSBtZXRob2QuCiAgICAgICAgICogQHBhcmFtIGluZGV4IC0gVGhlIGluZGV4IHBhcmFtLgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGdldEl0ZW0oaW5kZXgpIHsKICAgICAgICAgICAgLy8gaWYgKCF0aGlzLl9faXRlbXMpIHJldHVybiB1bmRlZmluZWQKICAgICAgICAgICAgcmV0dXJuIEFycmF5LmZyb20odGhpcy52YWx1ZSlbaW5kZXhdOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgYWRkSXRlbSBtZXRob2QuCiAgICAgICAgICogQHBhcmFtIGl0ZW0gLSBUaGUgaXRlbSB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0gZW1pdFZhbHVlQ2hhbmdlZCAtIFRoZSBlbWl0IHZhbHVlLgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGFkZEl0ZW0oaXRlbSwgZW1pdFZhbHVlQ2hhbmdlZCA9IHRydWUpIHsKICAgICAgICAgICAgaWYgKHRoaXMuZmlsdGVyRm4gJiYgIXRoaXMuZmlsdGVyRm4oaXRlbSkpIHsKICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybignSXRlbVNldCBfX2ZpbHRlckZuIHJlamVjdGluZyBpdGVtOicsIGl0ZW0uZ2V0UGF0aCgpKTsKICAgICAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoIXRoaXMudmFsdWUuaGFzKGl0ZW0pKSB7CiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlLmFkZChpdGVtKTsKICAgICAgICAgICAgICAgIGNvbnN0IGluZGV4ID0gQXJyYXkuZnJvbSh0aGlzLnZhbHVlKS5pbmRleE9mKGl0ZW0pOwogICAgICAgICAgICAgICAgdGhpcy5lbWl0KCdpdGVtQWRkZWQnLCBuZXcgSXRlbUV2ZW50KGl0ZW0sIGluZGV4KSk7CiAgICAgICAgICAgICAgICBpZiAoZW1pdFZhbHVlQ2hhbmdlZCkKICAgICAgICAgICAgICAgICAgICB0aGlzLmVtaXQoJ3ZhbHVlQ2hhbmdlZCcpOwogICAgICAgICAgICAgICAgcmV0dXJuIGluZGV4OwogICAgICAgICAgICB9CiAgICAgICAgICAgIGVsc2UgewogICAgICAgICAgICAgICAgcmV0dXJuIC0xOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEFkZHMgaXRlbXMgdG8gdGhlIHBhcmFtZXRlciB2YWx1ZQogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGl0ZW1zIC0gbGlzdCBvZiBpdGVtcyB0byBhZGQgdG8gdGhlIHBhcmFtZXRlcgogICAgICAgICAqIEBwYXJhbSBlbWl0VmFsdWVDaGFuZ2VkCiAgICAgICAgICogQG1lbWJlcm9mIEl0ZW1TZXRQYXJhbWV0ZXIKICAgICAgICAgKi8KICAgICAgICBhZGRJdGVtcyhpdGVtcywgZW1pdFZhbHVlQ2hhbmdlZCA9IHRydWUpIHsKICAgICAgICAgICAgaXRlbXMuZm9yRWFjaCgoaXRlbSkgPT4gdGhpcy5hZGRJdGVtKGl0ZW0sIGZhbHNlKSk7CiAgICAgICAgICAgIGlmIChlbWl0VmFsdWVDaGFuZ2VkKQogICAgICAgICAgICAgICAgdGhpcy5lbWl0KCd2YWx1ZUNoYW5nZWQnKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIHJlbW92ZUl0ZW0gbWV0aG9kLgogICAgICAgICAqIEBwYXJhbSBpbmRleCAtIFRoZSBpbmRleCB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0gZW1pdFZhbHVlQ2hhbmdlZCAtIFRoZSBlbWl0IHBhcmFtLgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHJlbW92ZUl0ZW0oaW5kZXgsIGVtaXRWYWx1ZUNoYW5nZWQgPSB0cnVlKSB7CiAgICAgICAgICAgIGNvbnN0IGl0ZW0gPSBBcnJheS5mcm9tKHRoaXMudmFsdWUpW2luZGV4XTsKICAgICAgICAgICAgdGhpcy52YWx1ZS5kZWxldGUoaXRlbSk7CiAgICAgICAgICAgIHRoaXMuZW1pdCgnaXRlbVJlbW92ZWQnLCBuZXcgSXRlbUV2ZW50KGl0ZW0sIGluZGV4KSk7CiAgICAgICAgICAgIGlmIChlbWl0VmFsdWVDaGFuZ2VkKQogICAgICAgICAgICAgICAgdGhpcy5lbWl0KCd2YWx1ZUNoYW5nZWQnKTsKICAgICAgICAgICAgcmV0dXJuIGl0ZW07CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBzZXRJdGVtcyBtZXRob2QuCiAgICAgICAgICogQHBhcmFtIGl0ZW1zIC0gVGhlIGl0ZW0gcGFyYW0uCiAgICAgICAgICogQHBhcmFtIGVtaXQgLSBUaGUgZW1pdCBwYXJhbS4KICAgICAgICAgKi8KICAgICAgICBzZXRJdGVtcyhpdGVtcywgZW1pdCA9IHRydWUpIHsKICAgICAgICAgICAgY29uc3QgdmFsdWVzID0gQXJyYXkuZnJvbSh0aGlzLnZhbHVlKTsKICAgICAgICAgICAgZm9yIChsZXQgaSA9IHZhbHVlcy5sZW5ndGggLSAxOyBpID49IDA7IGktLSkgewogICAgICAgICAgICAgICAgY29uc3QgaXRlbSA9IHZhbHVlc1tpXTsKICAgICAgICAgICAgICAgIGlmICghaXRlbXMuaGFzKGl0ZW0pKSB7CiAgICAgICAgICAgICAgICAgICAgdGhpcy5yZW1vdmVJdGVtKGksIGZhbHNlKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBmb3IgKGNvbnN0IGl0ZW0gb2YgaXRlbXMpIHsKICAgICAgICAgICAgICAgIGlmICghdGhpcy52YWx1ZS5oYXMoaXRlbSkpIHsKICAgICAgICAgICAgICAgICAgICB0aGlzLmFkZEl0ZW0oaXRlbSwgZmFsc2UpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIChlbWl0KQogICAgICAgICAgICAgICAgdGhpcy5lbWl0KCd2YWx1ZUNoYW5nZWQnKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGNsZWFySXRlbXMgbWV0aG9kLgogICAgICAgICAqIEBwYXJhbSBlbWl0IC0gVGhlIGVtaXQgdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgY2xlYXJJdGVtcyhlbWl0VmFsdWVDaGFuZ2VkID0gdHJ1ZSkgewogICAgICAgICAgICB0aGlzLnZhbHVlLmNsZWFyKCk7CiAgICAgICAgICAgIGlmIChlbWl0VmFsdWVDaGFuZ2VkKQogICAgICAgICAgICAgICAgdGhpcy5lbWl0KCd2YWx1ZUNoYW5nZWQnKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGdldE51bUl0ZW1zIG1ldGhvZC4KICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBnZXROdW1JdGVtcygpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMudmFsdWUuc2l6ZTsgLy8gbWlnaHQgYmUgZmFzdGVyCiAgICAgICAgfQogICAgICAgIC8vIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KICAgICAgICAvLyBQZXJzaXN0ZW5jZQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSB0b0pTT04gbWV0aG9kIGVuY29kZXMgdGhpcyB0eXBlIGFzIGEganNvbiBvYmplY3QgZm9yIHBlcnNpc3RlbmNlLgogICAgICAgICAqIEBwYXJhbSBjb250ZXh0IC0gVGhlIGNvbnRleHQgdmFsdWUuCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgdG9KU09OKGNvbnRleHQpIHsKICAgICAgICAgICAgaWYgKCF0aGlzLnZhbHVlKQogICAgICAgICAgICAgICAgdGhpcy52YWx1ZSA9IG5ldyBTZXQoKTsKICAgICAgICAgICAgY29uc3QgcGF0aHMgPSBbXTsKICAgICAgICAgICAgZm9yIChjb25zdCBpdGVtIG9mIHRoaXMudmFsdWUpIHsKICAgICAgICAgICAgICAgIGNvbnN0IHBhdGggPSBpdGVtLmdldFBhdGgoKTsKICAgICAgICAgICAgICAgIHBhdGhzLnB1c2goY29udGV4dCAmJiBjb250ZXh0Lm1ha2VSZWxhdGl2ZSA/IGNvbnRleHQubWFrZVJlbGF0aXZlKHBhdGgpIDogcGF0aCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIHsKICAgICAgICAgICAgICAgIHR5cGU6IHRoaXMuZ2V0Q2xhc3NOYW1lKCksCiAgICAgICAgICAgICAgICBuYW1lOiB0aGlzLm5hbWUsCiAgICAgICAgICAgICAgICB2YWx1ZTogcGF0aHMsCiAgICAgICAgICAgIH07CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBmcm9tSlNPTiBtZXRob2QgZGVjb2RlcyBhIGpzb24gb2JqZWN0IGZvciB0aGlzIHR5cGUuCiAgICAgICAgICogQHBhcmFtIGogLSBUaGUganNvbiBvYmplY3QgdGhpcyBpdGVtIG11c3QgZGVjb2RlLgogICAgICAgICAqIEBwYXJhbSBjb250ZXh0IC0gVGhlIGNvbnRleHQgdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgZnJvbUpTT04oaiwgY29udGV4dCkgewogICAgICAgICAgICBpZiAoIWNvbnRleHQgfHwgIWNvbnRleHQucmVzb2x2ZVBhdGgpIHsKICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignVW5hYmxlIHRvIGxvYWQgSlNPTiBvbiBhIEl0ZW1TZXRQYXJhbWV0ZXIgd2l0aG91dCBhIGxvYWQgY29udGV4dCcpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGNvbnN0IHBhdGhzID0gai52YWx1ZTsKICAgICAgICAgICAgcGF0aHMuZm9yRWFjaCgocGF0aCkgPT4gewogICAgICAgICAgICAgICAgY29udGV4dC5yZXNvbHZlUGF0aChwYXRoLCAodHJlZUl0ZW0pID0+IHsKICAgICAgICAgICAgICAgICAgICB0aGlzLmFkZEl0ZW0odHJlZUl0ZW0sIGZhbHNlKTsKICAgICAgICAgICAgICAgIH0sICgpID0+IHsKICAgICAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oIkJhc2VHcm91cDogJyIgKyB0aGlzLmdldE5hbWUoKSArICInLiBVbmFibGUgdG8gbG9hZCBpdGVtOiIgKyBwYXRoKTsKICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICB9KTsKICAgICAgICB9CiAgICAgICAgLy8gLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwogICAgICAgIC8vIENsb25lCiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGNsb25lIG1ldGhvZCBjb25zdHJ1Y3RzIGEgaXRlbSBzZXQgbmV3IHBhcmFtZXRlciwgY29waWVzIGl0cyB2YWx1ZXMKICAgICAgICAgKiBmcm9tIHRoaXMgcGFyYW1ldGVyIGFuZCByZXR1cm5zIGl0LgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgYSBuZXcgaXRlbSBzZXQgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIGNsb25lKCkgewogICAgICAgICAgICBjb25zdCBjbG9uZWRQYXJhbSA9IG5ldyBJdGVtU2V0UGFyYW1ldGVyKHRoaXMubmFtZSwgdGhpcy5maWx0ZXJGbik7CiAgICAgICAgICAgIHJldHVybiBjbG9uZWRQYXJhbTsKICAgICAgICB9CiAgICB9CiAgICBSZWdpc3RyeS5yZWdpc3RlcignSXRlbVNldFBhcmFtZXRlcicsIEl0ZW1TZXRQYXJhbWV0ZXIpOwoKICAgIC8qIGVzbGludC1kaXNhYmxlIEB0eXBlc2NyaXB0LWVzbGludC9uby1leHBsaWNpdC1hbnkgKi8KICAgIGNvbnN0IHBhcnNlOEJpdFBvc2l0aW9uc0FycmF5ID0gKHJhbmdlLCBvZmZzZXQsIHNjbFZlYywgcG9zaXRpb25zX3F1YW50aXplZCwgcG9zaXRpb25zQXR0cikgPT4gewogICAgICAgIGZvciAobGV0IGkgPSByYW5nZVswXTsgaSA8IHJhbmdlWzFdOyBpKyspIHsKICAgICAgICAgICAgY29uc3QgcG9zID0gbmV3IFZlYzMocG9zaXRpb25zX3F1YW50aXplZFtpICogMyArIDBdIC8gMjU1LjAsIHBvc2l0aW9uc19xdWFudGl6ZWRbaSAqIDMgKyAxXSAvIDI1NS4wLCBwb3NpdGlvbnNfcXVhbnRpemVkW2kgKiAzICsgMl0gLyAyNTUuMCk7CiAgICAgICAgICAgIHBvcy5tdWx0aXBseUluUGxhY2Uoc2NsVmVjKTsKICAgICAgICAgICAgcG9zLmFkZEluUGxhY2Uob2Zmc2V0KTsKICAgICAgICAgICAgcG9zaXRpb25zQXR0ci5zZXRWYWx1ZShpLCBwb3MpOwogICAgICAgIH0KICAgIH07CiAgICBjb25zdCBwYXJzZTE2Qml0UG9zaXRpb25zQXJyYXkgPSAocmFuZ2UsIG9mZnNldCwgc2NsVmVjLCBwb3NpdGlvbnNfcXVhbnRpemVkLCBwb3NpdGlvbnNBdHRyKSA9PiB7CiAgICAgICAgZm9yIChsZXQgaSA9IHJhbmdlWzBdOyBpIDwgcmFuZ2VbMV07IGkrKykgewogICAgICAgICAgICBjb25zdCBwb3MgPSBuZXcgVmVjMyhwb3NpdGlvbnNfcXVhbnRpemVkW2kgKiAzICsgMF0gLyA2NTUzNS4wLCBwb3NpdGlvbnNfcXVhbnRpemVkW2kgKiAzICsgMV0gLyA2NTUzNS4wLCBwb3NpdGlvbnNfcXVhbnRpemVkW2kgKiAzICsgMl0gLyA2NTUzNS4wKTsKICAgICAgICAgICAgcG9zLm11bHRpcGx5SW5QbGFjZShzY2xWZWMpOwogICAgICAgICAgICBwb3MuYWRkSW5QbGFjZShvZmZzZXQpOwogICAgICAgICAgICBwb3NpdGlvbnNBdHRyLnNldFZhbHVlKGksIHBvcyk7CiAgICAgICAgfQogICAgfTsKICAgIGNvbnN0IHBhcnNlOEJpdE5vcm1hbHNBcnJheSA9IChyYW5nZSwgb2Zmc2V0LCBzY2xWZWMsIG5vcm1hbHNfcXVhbnRpemVkLCBub3JtYWxzQXR0cikgPT4gewogICAgICAgIGlmIChzY2xWZWMuaXNOdWxsKCkpCiAgICAgICAgICAgIHNjbFZlYy5zZXQoMSwgMSwgMSk7CiAgICAgICAgZm9yIChsZXQgaSA9IHJhbmdlWzBdOyBpIDwgcmFuZ2VbMV07IGkrKykgewogICAgICAgICAgICBjb25zdCBub3JtYWwgPSBuZXcgVmVjMyhub3JtYWxzX3F1YW50aXplZFtpICogMyArIDBdIC8gMjU1LjAsIG5vcm1hbHNfcXVhbnRpemVkW2kgKiAzICsgMV0gLyAyNTUuMCwgbm9ybWFsc19xdWFudGl6ZWRbaSAqIDMgKyAyXSAvIDI1NS4wKTsKICAgICAgICAgICAgbm9ybWFsLm11bHRpcGx5SW5QbGFjZShzY2xWZWMpOwogICAgICAgICAgICBub3JtYWwuYWRkSW5QbGFjZShvZmZzZXQpOwogICAgICAgICAgICBub3JtYWwubm9ybWFsaXplSW5QbGFjZSgpOwogICAgICAgICAgICBub3JtYWxzQXR0ci5zZXRWYWx1ZShpLCBub3JtYWwpOwogICAgICAgIH0KICAgIH07CiAgICBjb25zdCBwYXJzZThCaXRUZXh0dXJlQ29vcmRzQXJyYXkgPSAocmFuZ2UsIG9mZnNldCwgc2NsVmVjLCB0ZXhDb29yZHNfcXVhbnRpemVkLCB0ZXhDb29yZHNBdHRyKSA9PiB7CiAgICAgICAgLy8gaWYgKHNjbFZlYy5pc051bGwoKSkKICAgICAgICAvLyAgICAgc2NsVmVjLnNldCgxLCAxLCAxKTsKICAgICAgICBmb3IgKGxldCBpID0gcmFuZ2VbMF07IGkgPCByYW5nZVsxXTsgaSsrKSB7CiAgICAgICAgICAgIGNvbnN0IHRleHR1cmVDb29yZCA9IG5ldyBWZWMyKHRleENvb3Jkc19xdWFudGl6ZWRbaSAqIDIgKyAwXSAvIDI1NS4wLCB0ZXhDb29yZHNfcXVhbnRpemVkW2kgKiAyICsgMV0gLyAyNTUuMCk7CiAgICAgICAgICAgIHRleHR1cmVDb29yZC5tdWx0aXBseUluUGxhY2Uoc2NsVmVjKTsKICAgICAgICAgICAgdGV4dHVyZUNvb3JkLmFkZEluUGxhY2Uob2Zmc2V0KTsKICAgICAgICAgICAgdGV4Q29vcmRzQXR0ci5zZXRWYWx1ZShpLCB0ZXh0dXJlQ29vcmQpOwogICAgICAgIH0KICAgIH07CiAgICBjb25zdCBwYXJzZTE2Qml0VGV4dHVyZUNvb3Jkc0FycmF5ID0gKHJhbmdlLCBvZmZzZXQsIHNjbFZlYywgdGV4Q29vcmRzX3F1YW50aXplZCwgdGV4Q29vcmRzQXR0cikgPT4gewogICAgICAgIC8vIGlmIChzY2xWZWMuaXNOdWxsKCkpCiAgICAgICAgLy8gICAgIHNjbFZlYy5zZXQoMSwgMSwgMSk7CiAgICAgICAgZm9yIChsZXQgaSA9IHJhbmdlWzBdOyBpIDwgcmFuZ2VbMV07IGkrKykgewogICAgICAgICAgICBjb25zdCB0ZXh0dXJlQ29vcmQgPSBuZXcgVmVjMih0ZXhDb29yZHNfcXVhbnRpemVkW2kgKiAyICsgMF0gLyA2NTUzNS4wLCB0ZXhDb29yZHNfcXVhbnRpemVkW2kgKiAyICsgMV0gLyA2NTUzNS4wKTsKICAgICAgICAgICAgdGV4dHVyZUNvb3JkLm11bHRpcGx5SW5QbGFjZShzY2xWZWMpOwogICAgICAgICAgICB0ZXh0dXJlQ29vcmQuYWRkSW5QbGFjZShvZmZzZXQpOwogICAgICAgICAgICB0ZXhDb29yZHNBdHRyLnNldFZhbHVlKGksIHRleHR1cmVDb29yZCk7CiAgICAgICAgfQogICAgfTsKICAgIC8qKgogICAgICogUmVwcmVzZW50cyBhIGJhc2UgY2xhc3MgZm9yIDNEIGdlb21ldHJ5IGl0ZW1zLgogICAgICoKICAgICAqICoqRXZlbnRzKioKICAgICAqICogKipib3VuZGluZ0JveENoYW5nZWQ6KiogVHJpZ2dlcmVkIHdoZW4gdGhlIGJvdW5kaW5nIGJveCBjaGFuZ2VzLgogICAgICogKiAqKmdlb21EYXRhQ2hhbmdlZDoqKiBFbWl0dGVkIHdoZW4gdGhlIGdlb21ldHJ5IGF0dHJpYnV0ZXMgaGF2ZSBjaGFuZ2VkLiBUaGUgdG9wb2xvZ3kgZGlkIG5vdCBjaGFuZ2UuIFRoZSBSZW5kZXJlciB3aWxsIHVwbG9hZCB0aGUgbmV3IGF0dHJpYnV0ZXMgdG8gdGhlIEdQVS4KICAgICAqICogKipnZW9tRGF0YVRvcG9sb2d5Q2hhbmdlZDoqKiBFbWl0dGVkIHdoZW4gdGhlIGdlb21ldHJ5IGF0dHJpYnV0ZXMgYW5kIHRvcG9sb2d5IGhhdmUgY2hhbmdlZC4gIFRoZSBSZW5kZXJlciB3aWxsIHVwbG9hZCB0aGUgbmV3IGF0dHJpYnV0ZXMgYW5kIHRvcG9sb2d5IHRvIHRoZSBHUFUuCiAgICAgKgogICAgICogQGV4dGVuZHMgUGFyYW1ldGVyT3duZXIKICAgICAqLwogICAgY2xhc3MgQmFzZUdlb20gZXh0ZW5kcyBQYXJhbWV0ZXJPd25lciB7CiAgICAgICAgYm91bmRpbmdCb3ggPSBuZXcgQm94MygpOwogICAgICAgIGJvdW5kaW5nQm94RGlydHkgPSB0cnVlOwogICAgICAgIF9fbWV0YURhdGEgPSBuZXcgTWFwKCk7CiAgICAgICAgI251bVZlcnRpY2VzID0gMDsKICAgICAgICBfX3ZlcnRleEF0dHJpYnV0ZXMgPSBuZXcgTWFwKCk7CiAgICAgICAgZGVidWdDb2xvciA9IG5ldyBDb2xvcigxLCAwLCAwLCAxKTsKICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGUgYSBiYXNlIGdlb20uCiAgICAgICAgICovCiAgICAgICAgY29uc3RydWN0b3IoKSB7CiAgICAgICAgICAgIHN1cGVyKCk7CiAgICAgICAgICAgIHRoaXMuYWRkVmVydGV4QXR0cmlidXRlKCdwb3NpdGlvbnMnLCBuZXcgVmVjM2YxNkF0dHJpYnV0ZSgpKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyB0aGUgY3VycmVudCBwYXRoIG9mIHRoZSBpdGVtIGluIHRoZSB0cmVlIGFzIGFuIGFycmF5IG9mIG5hbWVzLgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgYW4gYXJyYXkuCiAgICAgICAgICovCiAgICAgICAgZ2V0UGF0aCgpIHsKICAgICAgICAgICAgaWYgKHRoaXMub3duZXJJdGVtID09IHVuZGVmaW5lZCkKICAgICAgICAgICAgICAgIHJldHVybiBbdGhpcy5uYW1lXTsKICAgICAgICAgICAgZWxzZSBpZiAodGhpcy5vd25lckl0ZW0gaW5zdGFuY2VvZiBQYXJhbWV0ZXIpIHsKICAgICAgICAgICAgICAgIHJldHVybiBbLi4udGhpcy5vd25lckl0ZW0uZ2V0UGF0aCgpLCAndmFsdWUnXTsKICAgICAgICAgICAgfQogICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgIHJldHVybiBbLi4udGhpcy5vd25lckl0ZW0uZ2V0UGF0aCgpLCB0aGlzLm5hbWVdOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBjbGVhciBtZXRob2QuCiAgICAgICAgICovCiAgICAgICAgY2xlYXIoKSB7CiAgICAgICAgICAgIHRoaXMuc2V0TnVtVmVydGljZXMoMCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEFkZHMgYSBuZXcgdmVydGV4IGF0dHJpYnV0ZSB0byB0aGUgZ2VvbWV0cnkuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gbmFtZSAtIFRoZSBuYW1lIG9mIHRoZSB2ZXJ0ZXggYXR0cmlidXRlLgogICAgICAgICAqIEBwYXJhbSBkYXRhVHlwZSAtIFRoZSBkYXRhVHlwZSB2YWx1ZS4gLy8gVE9ETzogaXMgYW55IG9rIHZzLiBBdHRyVmFsdWUgfCBudW1iZXIuIFVuc3VyZSBhYm91dCBob3cgZGF0YVR5cGUgaXMgdXNlZAogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGFuIGF0dHJpYnV0ZS4KICAgICAgICAgKi8KICAgICAgICBhZGRWZXJ0ZXhBdHRyaWJ1dGUobmFtZSwgYXR0cikgewogICAgICAgICAgICBhdHRyLnNldENvdW50KHRoaXMuI251bVZlcnRpY2VzKTsKICAgICAgICAgICAgdGhpcy5fX3ZlcnRleEF0dHJpYnV0ZXMuc2V0KG5hbWUsIGF0dHIpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDaGVja3MgaWYgdGhlIHRoZSBnZW9tZXRyeSBoYXMgYW4gYXR0cmlidXRlIHdpdGggdGhlIHNwZWNpZmllZCBuYW1lLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIG5hbWUgLSBUaGUgbmFtZSBvZiB0aGUgdmVydGV4IGF0dHJpYnV0ZS4KICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBoYXNWZXJ0ZXhBdHRyaWJ1dGUobmFtZSkgewogICAgICAgICAgICByZXR1cm4gdGhpcy5fX3ZlcnRleEF0dHJpYnV0ZXMuaGFzKG5hbWUpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIHZlcnRleCBhdHRyaWJ1dGUgd2l0aCB0aGUgc3BlY2lmaWVkIG5hbWUuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gbmFtZSAtIFRoZSBuYW1lIG9mIHRoZSB2ZXJ0ZXggYXR0cmlidXRlLgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGdldFZlcnRleEF0dHJpYnV0ZShuYW1lKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLl9fdmVydGV4QXR0cmlidXRlcy5nZXQobmFtZSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgYWxsIHZlcnRleCBhdHRyaWJ1dGVzIGluIGFuIG9iamVjdCB3aXRoIHRoZWlyIG5hbWVzLgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgZ2V0VmVydGV4QXR0cmlidXRlcygpIHsKICAgICAgICAgICAgY29uc3QgdmVydGV4QXR0cmlidXRlcyA9IHt9OwogICAgICAgICAgICBmb3IgKGNvbnN0IFtrZXksIGF0dHJdIG9mIHRoaXMuX192ZXJ0ZXhBdHRyaWJ1dGVzLmVudHJpZXMoKSkKICAgICAgICAgICAgICAgIHZlcnRleEF0dHJpYnV0ZXNba2V5XSA9IGF0dHI7CiAgICAgICAgICAgIHJldHVybiB2ZXJ0ZXhBdHRyaWJ1dGVzOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zICdwb3NpdGlvbnMnIHZlcnRleCBhdHRyaWJ1dGUuCiAgICAgICAgICovCiAgICAgICAgZ2V0IHBvc2l0aW9ucygpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuX192ZXJ0ZXhBdHRyaWJ1dGVzLmdldCgncG9zaXRpb25zJyk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgdGhlIG51bWJlciBvZiB2ZXJ0ZXggYXR0cmlidXRlcy4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIG51bVZlcnRpY2VzKCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy4jbnVtVmVydGljZXM7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgdGhlIG51bWJlciBvZiB2ZXJ0ZXggYXR0cmlidXRlcy4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGdldE51bVZlcnRpY2VzKCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy4jbnVtVmVydGljZXM7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFNldHMgdGhlIG51bWJlciBvZiB2ZXJ0aWNlcyB0aGUgZ2VvbWV0cnkgaGFzLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGNvdW50IC0gVGhlIGNvdW50IHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHNldE51bVZlcnRpY2VzKGNvdW50KSB7CiAgICAgICAgICAgIHRoaXMuI251bVZlcnRpY2VzID0gY291bnQ7CiAgICAgICAgICAgIC8vIFJlc2l6ZXMgZWFjaCBvZiB0aGUgdmVydGV4IGF0dHJpYnV0ZXMgdG8gbWF0Y2ggdGhlIG5ldyBjb3VudC4KICAgICAgICAgICAgdGhpcy5fX3ZlcnRleEF0dHJpYnV0ZXMuZm9yRWFjaCgoYXR0cikgPT4gYXR0ci5zZXRDb3VudCh0aGlzLiNudW1WZXJ0aWNlcykpOwogICAgICAgICAgICB0aGlzLnNldEJvdW5kaW5nQm94RGlydHkoKTsKICAgICAgICB9CiAgICAgICAgLy8gLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwogICAgICAgIC8vIEJvdW5kaW5nQm94CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyB0aGUgYm91bmRpbmcgYm94IGZvciBnZW9tZXRyeS4KICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBnZXRCb3VuZGluZ0JveCgpIHsKICAgICAgICAgICAgaWYgKHRoaXMuYm91bmRpbmdCb3hEaXJ0eSkKICAgICAgICAgICAgICAgIHRoaXMudXBkYXRlQm91bmRpbmdCb3goKTsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuYm91bmRpbmdCb3g7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBzZXRCb3VuZGluZ0JveERpcnR5IG1ldGhvZC4KICAgICAgICAgKi8KICAgICAgICBzZXRCb3VuZGluZ0JveERpcnR5KCkgewogICAgICAgICAgICB0aGlzLmJvdW5kaW5nQm94RGlydHkgPSB0cnVlOwogICAgICAgICAgICB0aGlzLmVtaXQoJ2JvdW5kaW5nQm94Q2hhbmdlZCcpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgdXBkYXRlQm91bmRpbmdCb3ggbWV0aG9kLgogICAgICAgICAqLwogICAgICAgIHVwZGF0ZUJvdW5kaW5nQm94KCkgewogICAgICAgICAgICBjb25zdCBwb3NpdGlvbnMgPSB0aGlzLnBvc2l0aW9uczsKICAgICAgICAgICAgY29uc3QgYmJveCA9IG5ldyBCb3gzKCk7CiAgICAgICAgICAgIGlmIChwb3NpdGlvbnMpIHsKICAgICAgICAgICAgICAgIGNvbnN0IG51bVZlcnRzID0gcG9zaXRpb25zLmdldENvdW50KCk7CiAgICAgICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG51bVZlcnRzOyBpKyspCiAgICAgICAgICAgICAgICAgICAgYmJveC5hZGRQb2ludChwb3NpdGlvbnMuZ2V0VmFsdWUoaSkpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHRoaXMuYm91bmRpbmdCb3ggPSBiYm94OwogICAgICAgICAgICB0aGlzLmJvdW5kaW5nQm94RGlydHkgPSBmYWxzZTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogTWVyZ2VzIGEgc2VwYXJhdGUgZ2VvbWV0cnkgaW50byB0aGlzIG9uZS4gU2ltaWxhciB0byBhICd1bmlvbicgYm9vbGVhbiBvcGVyYXRpb24uCiAgICAgICAgICogQHBhcmFtIG90aGVyIHRoZSBvdGhlciBnZW9tIHRoYXQgd2lsbCBiZSBtZXJnZWQgaW50byB0aGlzIG9uZQogICAgICAgICAqIEBwYXJhbSB4Zm8gdGhlIHRyYW5zZm9ybWF0aW9uIHRvIGJlIGFwcGxpZWQgdG8gdGhlIG90aGVyIGdlb20gYXMgaXQgaXMgbWVyZ2VkIGluLgogICAgICAgICAqLwogICAgICAgIG1lcmdlKG90aGVyLCB4Zm8gPSBuZXcgWGZvKCkpIHsKICAgICAgICAgICAgY29uc3QgcHJldk51bVZlcnRzID0gdGhpcy5nZXROdW1WZXJ0aWNlcygpOwogICAgICAgICAgICBjb25zdCBhZGRlZFZlcnRzID0gb3RoZXIuZ2V0TnVtVmVydGljZXMoKTsKICAgICAgICAgICAgZm9yIChjb25zdCBbYXR0ck5hbWUsIGF0dHJdIG9mIHRoaXMuX192ZXJ0ZXhBdHRyaWJ1dGVzKSB7CiAgICAgICAgICAgICAgICBjb25zdCBvdGhlckF0dHIgPSBvdGhlci5nZXRWZXJ0ZXhBdHRyaWJ1dGUoYXR0ck5hbWUpOwogICAgICAgICAgICAgICAgaWYgKG90aGVyQXR0cikgewogICAgICAgICAgICAgICAgICAgIGlmIChhdHRyTmFtZSA9PSAncG9zaXRpb25zJykKICAgICAgICAgICAgICAgICAgICAgICAgYXR0ci5tZXJnZShvdGhlckF0dHIsIHhmbyk7CiAgICAgICAgICAgICAgICAgICAgZWxzZSBpZiAoYXR0ck5hbWUgPT0gJ25vcm1hbHMnKQogICAgICAgICAgICAgICAgICAgICAgICBhdHRyLm1lcmdlKG90aGVyQXR0ciwgbmV3IFhmbyhuZXcgVmVjMygpLCB4Zm8ub3JpKSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLy8gTm90ZTogYWxsIHRoZSBhdHRyaWJ1dGVzIGhhdmUgYWxyZWFkeSBiZWVuIHJlc2l6ZWQsIHNvCiAgICAgICAgICAgIC8vIHRoaXMgaXMganVzdCBhIGZpbmFsIGNoZWNrLgogICAgICAgICAgICB0aGlzLnNldE51bVZlcnRpY2VzKHByZXZOdW1WZXJ0cyArIGFkZGVkVmVydHMpOwogICAgICAgICAgICB0aGlzLnVwZGF0ZUJvdW5kaW5nQm94KCk7CiAgICAgICAgfQogICAgICAgIC8vIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KICAgICAgICAvLyBNZW1vcnkKICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIHZlcnRleCBhdHRyaWJ1dGVzIGJ1ZmZlcnMgYW5kIGl0cyBjb3VudC4KICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBnZW5CdWZmZXJzKG9wdHMpIHsKICAgICAgICAgICAgY29uc3QgYXR0ckJ1ZmZlcnMgPSB7fTsKICAgICAgICAgICAgZm9yIChjb25zdCBbYXR0ck5hbWUsIGF0dHJdIG9mIHRoaXMuX192ZXJ0ZXhBdHRyaWJ1dGVzKSB7CiAgICAgICAgICAgICAgICBhdHRyQnVmZmVyc1thdHRyTmFtZV0gPSBhdHRyLmdlbkJ1ZmZlcigpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiB7CiAgICAgICAgICAgICAgICBudW1WZXJ0aWNlczogdGhpcy5udW1WZXJ0aWNlcygpLAogICAgICAgICAgICAgICAgYXR0ckJ1ZmZlcnMsCiAgICAgICAgICAgIH07CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIE9uY2UgdGhlIGJ1ZmZlcnMgaGF2ZSBiZWVuIHVwbG9hZGVkIHRvIHRoZSBHUFUsIHdlIGFyZSBmcmVlIHRvIHJlbGVhc2UgdGhlbS4KICAgICAgICAgKiBUaGUgR0xHZW9tTGlicmFyeSBtYXkgY2FsbCB0aGlzIGZ1bmN0aW9uIHRvIGxldCB0aGUgZ2VvbWV0cnkga25vdyBpdCBjYW4gcmVsZWFzZSBhbnkgaGFuZGxlcy4KICAgICAgICAgKi8KICAgICAgICBmcmVlQnVmZmVycygpIHsgfQogICAgICAgIC8vIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KICAgICAgICAvLyBQZXJzaXN0ZW5jZQogICAgICAgIC8qKgogICAgICAgICAqIFNldHMgc3RhdGUgb2YgY3VycmVudCBHZW9tZXRyeShJbmNsdWRpbmcgVmVydGljZXMgYW5kIEJvdW5kaW5nIEJveCkgdXNpbmcgYSBiaW5hcnkgcmVhZGVyIG9iamVjdC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSByZWFkZXIgLSBUaGUgcmVhZGVyIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGxvYWRCYXNlR2VvbUJpbmFyeShyZWFkZXIsIGNvbnRleHQpIHsKICAgICAgICAgICAgdGhpcy5uYW1lID0gcmVhZGVyLmxvYWRTdHIoKTsKICAgICAgICAgICAgY29uc3QgZmxhZ3MgPSByZWFkZXIubG9hZFVJbnQ4KCk7CiAgICAgICAgICAgIHRoaXMuZGVidWdDb2xvciA9IHJlYWRlci5sb2FkUkdCRmxvYXQzMkNvbG9yKCk7CiAgICAgICAgICAgIGNvbnN0IG51bVZlcnRzID0gcmVhZGVyLmxvYWRVSW50MzIoKTsKICAgICAgICAgICAgdGhpcy5ib3VuZGluZ0JveC5zZXQocmVhZGVyLmxvYWRGbG9hdDMyVmVjMygpLCByZWFkZXIubG9hZEZsb2F0MzJWZWMzKCkpOwogICAgICAgICAgICBsZXQgbm9ybWFsc0F0dHI7CiAgICAgICAgICAgIGxldCB0ZXhDb29yZHNBdHRyOwogICAgICAgICAgICBpZiAoZmxhZ3MgJiAoMSA8PCAxKSkgewogICAgICAgICAgICAgICAgbm9ybWFsc0F0dHIgPSB0aGlzLmdldFZlcnRleEF0dHJpYnV0ZSgnbm9ybWFscycpOwogICAgICAgICAgICAgICAgaWYgKCFub3JtYWxzQXR0cikgewogICAgICAgICAgICAgICAgICAgIG5vcm1hbHNBdHRyID0gbmV3IFZlYzNmOEF0dHJpYnV0ZSgpOwogICAgICAgICAgICAgICAgICAgIHRoaXMuYWRkVmVydGV4QXR0cmlidXRlKCdub3JtYWxzJywgbm9ybWFsc0F0dHIpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIChmbGFncyAmICgxIDw8IDIpKSB7CiAgICAgICAgICAgICAgICB0ZXhDb29yZHNBdHRyID0gdGhpcy5nZXRWZXJ0ZXhBdHRyaWJ1dGUoJ3RleENvb3JkcycpOwogICAgICAgICAgICAgICAgaWYgKCF0ZXhDb29yZHNBdHRyKSB7CiAgICAgICAgICAgICAgICAgICAgdGV4Q29vcmRzQXR0ciA9IG5ldyBWZWMyZjE2QXR0cmlidXRlKCk7CiAgICAgICAgICAgICAgICAgICAgdGhpcy5hZGRWZXJ0ZXhBdHRyaWJ1dGUoJ3RleENvb3JkcycsIHRleENvb3Jkc0F0dHIpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIGNvbnN0IG51bUNsdXN0ZXJzID0gcmVhZGVyLmxvYWRVSW50MzIoKTsKICAgICAgICAgICAgaWYgKG51bUNsdXN0ZXJzID09IDApIHsKICAgICAgICAgICAgICAgIGNvbnN0IHBvc2l0aW9uc0F0dHIgPSB0aGlzLnBvc2l0aW9uczsKICAgICAgICAgICAgICAgIC8vIEZyb20gMy4xMi4wLCB2ZXJ0ZXggZGF0YSBpcyBhIG1peCBvZiAxNmJpdCBhbmQgOCBiaXQgcXVhbml0aXphdGlvbgogICAgICAgICAgICAgICAgLy8gd2l0aG91dCBhbnkgay1tZWFucyBjbHVzdGVyaW5nLgogICAgICAgICAgICAgICAgLy8gQHRzLWlnbm9yZQogICAgICAgICAgICAgICAgcG9zaXRpb25zQXR0ci5kYXRhID0gcmVhZGVyLmxvYWRVSW50MTZBcnJheShudW1WZXJ0cyAqIDMpOwogICAgICAgICAgICAgICAgaWYgKG5vcm1hbHNBdHRyKSB7CiAgICAgICAgICAgICAgICAgICAgLy8gQHRzLWlnbm9yZQogICAgICAgICAgICAgICAgICAgIG5vcm1hbHNBdHRyLmRhdGEgPSByZWFkZXIubG9hZEludDhBcnJheShudW1WZXJ0cyAqIDMpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgaWYgKHRleENvb3Jkc0F0dHIpIHsKICAgICAgICAgICAgICAgICAgICAvLyBAdHMtaWdub3JlCiAgICAgICAgICAgICAgICAgICAgdGV4Q29vcmRzQXR0ci5kYXRhID0gcmVhZGVyLmxvYWRVSW50MTZBcnJheShudW1WZXJ0cyAqIDIpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgLy8gVGhpcyBzaG91bGQgYmUgYSBuby1vcCBpbiBlYWNoIG9mIHRoZSBhdHRyaWJ1dGVzIGFzIHRoZXkgYWxyZWFkeSBoYXZlCiAgICAgICAgICAgICAgICAvLyBhcnJheXMgb2YgdGhlIGFwcHJvcHJpYXRlIHNpemUuLgogICAgICAgICAgICAgICAgdGhpcy5zZXROdW1WZXJ0aWNlcyhudW1WZXJ0cyk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZWxzZSBpZiAobnVtQ2x1c3RlcnMgPT0gMSkgewogICAgICAgICAgICAgICAgLy8gT2xkZXIgemNhZCBmaWxlcyBzdG9yZSAzMiBiaXQgZmxvYXRzLiBUaGUgcmVuZGVyZXIgbWF5IGNvbnZlcnQgdGhlc2UgdG8gMTZiaXQuCiAgICAgICAgICAgICAgICB0aGlzLmFkZFZlcnRleEF0dHJpYnV0ZSgncG9zaXRpb25zJywgbmV3IFZlYzNBdHRyaWJ1dGUoKSk7CiAgICAgICAgICAgICAgICB0aGlzLnNldE51bVZlcnRpY2VzKG51bVZlcnRzKTsKICAgICAgICAgICAgICAgIGNvbnN0IHBvc2l0aW9uc0F0dHIgPSB0aGlzLnBvc2l0aW9uczsKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBjb25zdCBib3gzID0gdGhpcy5ib3VuZGluZ0JveDsKICAgICAgICAgICAgICAgICAgICAvLyBGcm9tIDMuOS4xLCB2ZXJ0ZXggZGF0YSBpcyBhIG1peCBvZiAxNmJpdCBhbmQgOCBiaXQgcXVhbml0aXphdGlvbgogICAgICAgICAgICAgICAgICAgIGlmIChjb250ZXh0LnZlcnNpb25zWyd6ZWEtZW5naW5lJ10uY29tcGFyZShbMywgOSwgMV0pID49IDApIHsKICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgcG9zaXRpb25zX3F1YW50aXplZCA9IHJlYWRlci5sb2FkVUludDE2QXJyYXkobnVtVmVydHMgKiAzLCBmYWxzZSk7CiAgICAgICAgICAgICAgICAgICAgICAgIHBhcnNlMTZCaXRQb3NpdGlvbnNBcnJheShbMCwgbnVtVmVydHNdLCBib3gzLnAwLCBib3gzLmRpYWdvbmFsKCksIHBvc2l0aW9uc19xdWFudGl6ZWQsIHBvc2l0aW9uc0F0dHIpOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgcG9zaXRpb25zX3F1YW50aXplZCA9IHJlYWRlci5sb2FkVUludDhBcnJheShudW1WZXJ0cyAqIDMsIGZhbHNlKTsKICAgICAgICAgICAgICAgICAgICAgICAgcGFyc2U4Qml0UG9zaXRpb25zQXJyYXkoWzAsIG51bVZlcnRzXSwgYm94My5wMCwgYm94My5kaWFnb25hbCgpLCBwb3NpdGlvbnNfcXVhbnRpemVkLCBwb3NpdGlvbnNBdHRyKTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBpZiAobm9ybWFsc0F0dHIpIHsKICAgICAgICAgICAgICAgICAgICBjb25zdCBib3gzID0gbmV3IEJveDMocmVhZGVyLmxvYWRGbG9hdDMyVmVjMygpLCByZWFkZXIubG9hZEZsb2F0MzJWZWMzKCkpOwogICAgICAgICAgICAgICAgICAgIGNvbnN0IG5vcm1hbHNfcXVhbnRpemVkID0gcmVhZGVyLmxvYWRVSW50OEFycmF5KG51bVZlcnRzICogMywgZmFsc2UpOwogICAgICAgICAgICAgICAgICAgIHBhcnNlOEJpdE5vcm1hbHNBcnJheShbMCwgbnVtVmVydHNdLCBib3gzLnAwLCBib3gzLmRpYWdvbmFsKCksIG5vcm1hbHNfcXVhbnRpemVkLCBub3JtYWxzQXR0cik7CiAgICAgICAgICAgICAgICAgICAgbm9ybWFsc0F0dHIubG9hZFNwbGl0VmFsdWVzKHJlYWRlcik7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBpZiAodGV4Q29vcmRzQXR0cikgewogICAgICAgICAgICAgICAgICAgIGNvbnN0IGJveDIgPSBuZXcgQm94MihyZWFkZXIubG9hZEZsb2F0MzJWZWMyKCksIHJlYWRlci5sb2FkRmxvYXQzMlZlYzIoKSk7CiAgICAgICAgICAgICAgICAgICAgLy8gRnJvbSAzLjkuMSwgdmVydGV4IGRhdGEgaXMgYSBtaXggb2YgMTZiaXQgYW5kIDggYml0IHF1YW5pdGl6YXRpb24KICAgICAgICAgICAgICAgICAgICBpZiAoY29udGV4dC52ZXJzaW9uc1snemVhLWVuZ2luZSddLmNvbXBhcmUoWzMsIDksIDFdKSA+PSAwKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHRleENvb3Jkc19xdWFudGl6ZWQgPSByZWFkZXIubG9hZFVJbnQxNkFycmF5KG51bVZlcnRzICogMiwgZmFsc2UpOwogICAgICAgICAgICAgICAgICAgICAgICBwYXJzZTE2Qml0VGV4dHVyZUNvb3Jkc0FycmF5KFswLCBudW1WZXJ0c10sIGJveDIucDAsIGJveDIuZGlhZ29uYWwoKSwgdGV4Q29vcmRzX3F1YW50aXplZCwgdGV4Q29vcmRzQXR0cik7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIGVsc2UgewogICAgICAgICAgICAgICAgICAgICAgICBjb25zdCB0ZXhDb29yZHNfcXVhbnRpemVkID0gcmVhZGVyLmxvYWRVSW50OEFycmF5KG51bVZlcnRzICogMiwgZmFsc2UpOwogICAgICAgICAgICAgICAgICAgICAgICBwYXJzZThCaXRUZXh0dXJlQ29vcmRzQXJyYXkoWzAsIG51bVZlcnRzXSwgYm94Mi5wMCwgYm94Mi5kaWFnb25hbCgpLCB0ZXhDb29yZHNfcXVhbnRpemVkLCB0ZXhDb29yZHNBdHRyKTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgdGV4Q29vcmRzQXR0ci5sb2FkU3BsaXRWYWx1ZXMocmVhZGVyKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgIC8vIE9sZGVyIHpjYWQgZmlsZXMgc3RvcmUgMzIgYml0IGZsb2F0cy4gVGhlIHJlbmRlcmVyIG1heSBjb252ZXJ0IHRoZXNlIHRvIDE2Yml0LgogICAgICAgICAgICAgICAgdGhpcy5hZGRWZXJ0ZXhBdHRyaWJ1dGUoJ3Bvc2l0aW9ucycsIG5ldyBWZWMzQXR0cmlidXRlKCkpOwogICAgICAgICAgICAgICAgdGhpcy5zZXROdW1WZXJ0aWNlcyhudW1WZXJ0cyk7CiAgICAgICAgICAgICAgICBjb25zdCBwb3NpdGlvbnNBdHRyID0gdGhpcy5wb3NpdGlvbnM7CiAgICAgICAgICAgICAgICBjb25zdCBjbHVzdGVycyA9IFtdOwogICAgICAgICAgICAgICAgbGV0IG9mZnNldCA9IDA7CiAgICAgICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG51bUNsdXN0ZXJzOyBpKyspIHsKICAgICAgICAgICAgICAgICAgICBjb25zdCBjb3VudCA9IHJlYWRlci5sb2FkVUludDMyKCk7CiAgICAgICAgICAgICAgICAgICAgY29uc3QgY2x1c3RlckRhdGEgPSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHJhbmdlOiBbb2Zmc2V0LCBvZmZzZXQgKyBjb3VudF0sCiAgICAgICAgICAgICAgICAgICAgICAgIGJib3g6IG5ldyBCb3gzKHJlYWRlci5sb2FkRmxvYXQzMlZlYzMoKSwgcmVhZGVyLmxvYWRGbG9hdDMyVmVjMygpKSwKICAgICAgICAgICAgICAgICAgICAgICAgbm9ybWFsc1JhbmdlOiBuZXcgQm94MygpLAogICAgICAgICAgICAgICAgICAgICAgICB0ZXhDb29yZHNSYW5nZTogbmV3IEJveDIoKSwKICAgICAgICAgICAgICAgICAgICB9OwogICAgICAgICAgICAgICAgICAgIGlmIChub3JtYWxzQXR0cikgewogICAgICAgICAgICAgICAgICAgICAgICBjbHVzdGVyRGF0YS5ub3JtYWxzUmFuZ2Uuc2V0KHJlYWRlci5sb2FkRmxvYXQzMlZlYzMoKSwgcmVhZGVyLmxvYWRGbG9hdDMyVmVjMygpKTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgaWYgKHRleENvb3Jkc0F0dHIpIHsKICAgICAgICAgICAgICAgICAgICAgICAgY2x1c3RlckRhdGEudGV4Q29vcmRzUmFuZ2Uuc2V0KHJlYWRlci5sb2FkRmxvYXQzMlZlYzIoKSwgcmVhZGVyLmxvYWRGbG9hdDMyVmVjMigpKTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgY2x1c3RlcnMucHVzaChjbHVzdGVyRGF0YSk7CiAgICAgICAgICAgICAgICAgICAgb2Zmc2V0ICs9IGNvdW50OwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgLy8gRnJvbSAzLjkuMSwgdmVydGV4IGRhdGEgaXMgYSBtaXggb2YgMTZiaXQgYW5kIDggYml0IHF1YW5pdGl6YXRpb24KICAgICAgICAgICAgICAgIGxldCBwb3NpdGlvbnNfcXVhbnRpemVkOwogICAgICAgICAgICAgICAgaWYgKGNvbnRleHQudmVyc2lvbnNbJ3plYS1lbmdpbmUnXS5jb21wYXJlKFszLCA5LCAxXSkgPj0gMCkgewogICAgICAgICAgICAgICAgICAgIHBvc2l0aW9uc19xdWFudGl6ZWQgPSByZWFkZXIubG9hZFVJbnQxNkFycmF5KG51bVZlcnRzICogMywgZmFsc2UpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgcG9zaXRpb25zX3F1YW50aXplZCA9IHJlYWRlci5sb2FkVUludDhBcnJheShudW1WZXJ0cyAqIDMsIGZhbHNlKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGxldCBub3JtYWxzX3F1YW50aXplZCA9IG51bGw7CiAgICAgICAgICAgICAgICBsZXQgdGV4Q29vcmRzX3F1YW50aXplZCA9IG51bGw7CiAgICAgICAgICAgICAgICBpZiAobm9ybWFsc0F0dHIpIHsKICAgICAgICAgICAgICAgICAgICBub3JtYWxzX3F1YW50aXplZCA9IHJlYWRlci5sb2FkVUludDhBcnJheShudW1WZXJ0cyAqIDMsIGZhbHNlKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGlmICh0ZXhDb29yZHNBdHRyKSB7CiAgICAgICAgICAgICAgICAgICAgdGV4Q29vcmRzX3F1YW50aXplZCA9IHJlYWRlci5sb2FkVUludDhBcnJheShudW1WZXJ0cyAqIDIsIGZhbHNlKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbnVtQ2x1c3RlcnM7IGkrKykgewogICAgICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgYm94MyA9IGNsdXN0ZXJzW2ldLmJib3g7CiAgICAgICAgICAgICAgICAgICAgICAgIC8vIEZyb20gMy45LjEsIHZlcnRleCBkYXRhIGlzIGEgbWl4IG9mIDE2Yml0IGFuZCA4IGJpdCBxdWFuaXRpemF0aW9uCiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChjb250ZXh0LnZlcnNpb25zWyd6ZWEtZW5naW5lJ10uY29tcGFyZShbMywgOSwgMV0pID49IDApIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnNlMTZCaXRQb3NpdGlvbnNBcnJheShjbHVzdGVyc1tpXS5yYW5nZSwgYm94My5wMCwgYm94My5kaWFnb25hbCgpLCBwb3NpdGlvbnNfcXVhbnRpemVkLCBwb3NpdGlvbnNBdHRyKTsKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnNlOEJpdFBvc2l0aW9uc0FycmF5KGNsdXN0ZXJzW2ldLnJhbmdlLCBib3gzLnAwLCBib3gzLmRpYWdvbmFsKCksIHBvc2l0aW9uc19xdWFudGl6ZWQsIHBvc2l0aW9uc0F0dHIpOwogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIGlmIChub3JtYWxzX3F1YW50aXplZCkgewogICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBib3gzID0gY2x1c3RlcnNbaV0ubm9ybWFsc1JhbmdlOwogICAgICAgICAgICAgICAgICAgICAgICBwYXJzZThCaXROb3JtYWxzQXJyYXkoY2x1c3RlcnNbaV0ucmFuZ2UsIGJveDMucDAsIGJveDMuZGlhZ29uYWwoKSwgbm9ybWFsc19xdWFudGl6ZWQsIG5vcm1hbHNBdHRyKTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgaWYgKHRleENvb3Jkc19xdWFudGl6ZWQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgYm94MiA9IGNsdXN0ZXJzW2ldLnRleENvb3Jkc1JhbmdlOwogICAgICAgICAgICAgICAgICAgICAgICBpZiAoY29udGV4dC52ZXJzaW9uc1snemVhLWVuZ2luZSddLmNvbXBhcmUoWzMsIDksIDFdKSA+PSAwKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzZTE2Qml0VGV4dHVyZUNvb3Jkc0FycmF5KFswLCBudW1WZXJ0c10sIGJveDIucDAsIGJveDIuZGlhZ29uYWwoKSwgdGV4Q29vcmRzX3F1YW50aXplZCwgdGV4Q29vcmRzQXR0cik7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzZThCaXRUZXh0dXJlQ29vcmRzQXJyYXkoY2x1c3RlcnNbaV0ucmFuZ2UsIGJveDIucDAsIGJveDIuZGlhZ29uYWwoKSwgdGV4Q29vcmRzX3F1YW50aXplZCwgdGV4Q29vcmRzQXR0cik7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBpZiAobm9ybWFsc0F0dHIpIHsKICAgICAgICAgICAgICAgICAgICBub3JtYWxzQXR0ci5sb2FkU3BsaXRWYWx1ZXMocmVhZGVyKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGlmICh0ZXhDb29yZHNBdHRyKSB7CiAgICAgICAgICAgICAgICAgICAgdGV4Q29vcmRzQXR0ci5sb2FkU3BsaXRWYWx1ZXMocmVhZGVyKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICAvLyBMb2FkaW5nIHRoZSBhdHRyaWJ1dGVzIG1heSBoYXZlIGRpcnRpZWQgdGhlIGJvdW5kaW5nIGJveC4KICAgICAgICAgICAgLy8gd2Uga29udyB3ZSBhbHJlYWR5IGxvYWRlZCB0aGUgYmJveCwgc28gZm9yY2UgaXQgdG8gYmUgdmFsaWQuCiAgICAgICAgICAgIHRoaXMuYm91bmRpbmdCb3hEaXJ0eSA9IGZhbHNlOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgdG9KU09OIG1ldGhvZCBlbmNvZGVzIHRoaXMgdHlwZSBhcyBhIGpzb24gb2JqZWN0IGZvciBwZXJzaXN0ZW5jZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBjb250ZXh0IC0gVGhlIGNvbnRleHQgdmFsdWUuCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgdGhlIGpzb24gb2JqZWN0LgogICAgICAgICAqLwogICAgICAgIHRvSlNPTihjb250ZXh0KSB7CiAgICAgICAgICAgIGNvbnN0IGpzb24gPSBzdXBlci50b0pTT04oY29udGV4dCk7CiAgICAgICAgICAgIGlmICghY29udGV4dCB8fCAhY29udGV4dC5za2lwVG9wb2xvZ3kpIHsKICAgICAgICAgICAgICAgIGpzb24ubnVtVmVydGljZXMgPSB0aGlzLiNudW1WZXJ0aWNlcyB8fCAwOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGNvbnN0IHZlcnRleEF0dHJpYnV0ZXMgPSB7fTsKICAgICAgICAgICAgZm9yIChjb25zdCBba2V5LCBhdHRyXSBvZiB0aGlzLl9fdmVydGV4QXR0cmlidXRlcy5lbnRyaWVzKCkpIHsKICAgICAgICAgICAgICAgIGlmICghY29udGV4dCB8fCAhKCdza2lwQXR0cmlidXRlcycgaW4gY29udGV4dCkgfHwgIWNvbnRleHQuc2tpcEF0dHJpYnV0ZXMuaW5jbHVkZXMoa2V5KSkKICAgICAgICAgICAgICAgICAgICB2ZXJ0ZXhBdHRyaWJ1dGVzW2tleV0gPSBhdHRyLnRvSlNPTihjb250ZXh0KTsKICAgICAgICAgICAgfQogICAgICAgICAgICBqc29uLnZlcnRleEF0dHJpYnV0ZXMgPSB2ZXJ0ZXhBdHRyaWJ1dGVzOwogICAgICAgICAgICByZXR1cm4ganNvbjsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGZyb21KU09OIG1ldGhvZCBkZWNvZGVzIGEganNvbiBvYmplY3QgZm9yIHRoaXMgdHlwZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBqc29uIC0gVGhlIGpzb24gb2JqZWN0IHRoaXMgaXRlbSBtdXN0IGRlY29kZS4KICAgICAgICAgKiBAcGFyYW0gY29udGV4dCAtIFRoZSBjb250ZXh0IHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGZyb21KU09OKGpzb24sIGNvbnRleHQpIHsKICAgICAgICAgICAgdGhpcy5jbGVhcigpOwogICAgICAgICAgICBzdXBlci5mcm9tSlNPTihqc29uLCBjb250ZXh0KTsKICAgICAgICAgICAgdGhpcy5zZXROdW1WZXJ0aWNlcyhqc29uLm51bVZlcnRpY2VzKTsKICAgICAgICAgICAgZm9yIChjb25zdCBuYW1lIGluIGpzb24udmVydGV4QXR0cmlidXRlcykgewogICAgICAgICAgICAgICAgbGV0IGF0dHIgPSB0aGlzLl9fdmVydGV4QXR0cmlidXRlcy5nZXQobmFtZSk7CiAgICAgICAgICAgICAgICBjb25zdCBhdHRySlNPTiA9IGpzb24udmVydGV4QXR0cmlidXRlc1tuYW1lXTsKICAgICAgICAgICAgICAgIGlmICghYXR0ciB8fCBhdHRyLmRhdGFUeXBlTmFtZSAhPSBhdHRySlNPTi5kYXRhVHlwZSkgewogICAgICAgICAgICAgICAgICAgIHN3aXRjaCAoYXR0ckpTT04uZGF0YVR5cGUpIHsKICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSAnVmVjMic6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhdHRyID0gbmV3IFZlYzJBdHRyaWJ1dGUoKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgICAgICAgICBjYXNlICdWZWMyZjE2JzoKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF0dHIgPSBuZXcgVmVjMmYxNkF0dHJpYnV0ZSgpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgJ1ZlYzMnOgogICAgICAgICAgICAgICAgICAgICAgICAgICAgYXR0ciA9IG5ldyBWZWMzQXR0cmlidXRlKCk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSAnVmVjM2YxNic6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhdHRyID0gbmV3IFZlYzNmMTZBdHRyaWJ1dGUoKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgICAgICAgICBjYXNlICdWZWMzZjgnOgogICAgICAgICAgICAgICAgICAgICAgICAgICAgYXR0ciA9IG5ldyBWZWMzZjhBdHRyaWJ1dGUoKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgICAgICAgICBjYXNlICdDb2xvcic6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhdHRyID0gbmV3IENvbG9yQXR0cmlidXRlKCk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgICAgICAgICAgZGVmYXVsdDoKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRocm93ICdJbnZhbGlkIFZlY3RleCBUeXBlOiAnICsgYXR0ci5kYXRhVHlwZU5hbWU7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIGF0dHIuc2V0Q291bnQodGhpcy4jbnVtVmVydGljZXMpOwogICAgICAgICAgICAgICAgICAgIHRoaXMuYWRkVmVydGV4QXR0cmlidXRlKG5hbWUsIGF0dHIpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgaWYgKGF0dHIpIHsKICAgICAgICAgICAgICAgICAgICBhdHRyLmZyb21KU09OKGF0dHJKU09OKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGVsc2UgewogICAgICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybignYXR0ciB1bmRlZmluZWQsIGNhbm5vdCBleGVjdXRlIGZyb21KU09OKCknKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICB0aGlzLmVtaXQoJ2dlb21EYXRhVG9wb2xvZ3lDaGFuZ2VkJyk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgZ2VvbWV0cnkgZGF0YSB2YWx1ZSBpbiBqc29uIGZvcm1hdC4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHRvU3RyaW5nKCkgewogICAgICAgICAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkodGhpcy50b0pTT04oKSwgbnVsbCwgMik7CiAgICAgICAgfQogICAgfQoKICAgIC8qKgogICAgICogQ2xhc3MgcmVwcmVzZW50aW5nIGEgcG9pbnQgcHJpbWl0aXZlIGRyYXdpbmcgdHlwZSwgZXZlcnkgdmVydGV4IHNwZWNpZmllZCBpcyBhIHBvaW50LgogICAgICoKICAgICAqIGBgYAogICAgICogY29uc3QgcG9pbnRzID0gbmV3IFBvaW50cygpCiAgICAgKiBgYGAKICAgICAqCiAgICAgKiAqICoqRXZlbnRzKioKICAgICAqICogKipib3VuZGluZ0JveENoYW5nZWQ6KiogVHJpZ2dlcmVkIHdoZW4gdGhlIGJvdW5kaW5nIGJveCBjaGFuZ2VzLgogICAgICoKICAgICAqIEBleHRlbmRzIEJhc2VHZW9tCiAgICAgKi8KICAgIGNsYXNzIFBvaW50cyBleHRlbmRzIEJhc2VHZW9tIHsKICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGUgcG9pbnRzLgogICAgICAgICAqLwogICAgICAgIGNvbnN0cnVjdG9yKCkgewogICAgICAgICAgICBzdXBlcigpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgY2xlYXIgbWV0aG9kLgogICAgICAgICAqLwogICAgICAgIGNsZWFyKCkgewogICAgICAgICAgICB0aGlzLnNldE51bVZlcnRpY2VzKDApOwogICAgICAgICAgICB0aGlzLmVtaXQoJ2dlb21EYXRhVG9wb2xvZ3lDaGFuZ2VkJyk7CiAgICAgICAgfQogICAgICAgIC8vIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KICAgICAgICAvLyBQZXJzaXN0ZW5jZQogICAgICAgIC8qKgogICAgICAgICAqIFNldHMgc3RhdGUgb2YgY3VycmVudCBnZW9tZXRyeShJbmNsdWRpbmcgbGluZSBzZWdtZW50cykgdXNpbmcgYSBiaW5hcnkgcmVhZGVyIG9iamVjdC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSByZWFkZXIgLSBUaGUgcmVhZGVyIHZhbHVlLgogICAgICAgICAqIEBwYXJhbSBjb250ZXh0IC0gVGhlIGNvbnRleHQgdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgcmVhZEJpbmFyeShyZWFkZXIsIGNvbnRleHQpIHsKICAgICAgICAgICAgc3VwZXIubG9hZEJhc2VHZW9tQmluYXJ5KHJlYWRlciwgY29udGV4dCk7CiAgICAgICAgICAgIC8vIHRoaXMuY29tcHV0ZVZlcnRleE5vcm1hbHMoKTsKICAgICAgICAgICAgdGhpcy5lbWl0KCdnZW9tRGF0YUNoYW5nZWQnKTsKICAgICAgICB9CiAgICB9CiAgICBSZWdpc3RyeS5yZWdpc3RlcignUG9pbnRzJywgUG9pbnRzKTsKCiAgICAvKiBlc2xpbnQtZGlzYWJsZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnMgKi8KICAgIC8qKgogICAgICoKICAgICAqIENsYXNzIHJlcHJlc2VudGluZyBsaW5lcyBwcmltaXRpdmUgZHJhd2luZyB0eXBlLCBjb25uZWN0aW5nIHZlcnRpY2VzIHVzaW5nIHRoZSBzcGVjaWZpZWQgaW5kaWNlcy4KICAgICAqIGkuZS4gV2UgaGF2ZSA0IHBvaW50cyh2ZXJ0aWNlcykgYnV0IHdlIGRvbid0IGtub3cgaG93IHRoZXkgY29ubmVjdCB0byBlYWNoIG90aGVyLAogICAgICogYW5kIHRoYXQncyB3aHkgd2UgbmVlZCBpbmRpY2VzKE51bWJlcnMgaW5kaWNhdGluZyB3aGljaCB2ZXJ0ZXggY29ubmVjdHMgdG8gd2hpY2gpLgogICAgICogSW4gdGhpcyBjYXNlIGlmIHdlIHNheSB0aGF0IGBpbmRpY2VzYCBpcyBgWzAsMSwyLDNdYCwgaXQgd291bGQgY29ubmVjdCB0aGUgZmlyc3QgdmVydGV4IHRvIHRoZSBzZWNvbmQsCiAgICAgKiBhbmQgdGhlIHRoaXJkIHRvIHRoZSBmb3VydGguCiAgICAgKgogICAgICogYGBgCiAgICAgKiBjb25zdCBsaW5lcyA9IG5ldyBMaW5lcygpCiAgICAgKiBgYGAKICAgICAqCiAgICAgKiAqKkV2ZW50cyoqCiAgICAgKiAqICoqZ2VvbURhdGFDaGFuZ2VkOioqIFRyaWdnZXJlZCB3aGVuIHRoZSBkYXRhIHZhbHVlIG9mIHRoZSBnZW9tZXRyeSBpcyBzZXQoVGhpcyBpbmNsdWRlcyByZWFkaW5nIGJpbmFyeSkKICAgICAqCiAgICAgKiBAZXh0ZW5kcyBCYXNlR2VvbQogICAgICovCiAgICBjbGFzcyBMaW5lcyBleHRlbmRzIEJhc2VHZW9tIHsKICAgICAgICBfX2luZGljZXM7CiAgICAgICAgLyoqCiAgICAgICAgICogQ3JlYXRlIGxpbmVzLgogICAgICAgICAqLwogICAgICAgIGNvbnN0cnVjdG9yKCkgewogICAgICAgICAgICBzdXBlcigpOwogICAgICAgICAgICB0aGlzLl9faW5kaWNlcyA9IG5ldyBVaW50MzJBcnJheSgpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgY2xlYXIgbWV0aG9kLgogICAgICAgICAqLwogICAgICAgIGNsZWFyKCkgewogICAgICAgICAgICB0aGlzLnNldE51bVNlZ21lbnRzKDApOwogICAgICAgICAgICB0aGlzLnNldE51bVZlcnRpY2VzKDApOwogICAgICAgICAgICB0aGlzLmVtaXQoJ2dlb21EYXRhVG9wb2xvZ3lDaGFuZ2VkJyk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgdGhlIHNwZWNpZmllZCBpbmRpY2VzKFZlcnRleCBjb25uZWN0b3JzKQogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFRoZSBpbmRpY2VzIGluZGV4IGFycmF5LgogICAgICAgICAqLwogICAgICAgIGdldEluZGljZXMoKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLl9faW5kaWNlczsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyB0aGUgbnVtYmVyIG9mIGxpbmUgc2VnbWVudHMuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyB0aGUgbnVtYmVyIG9mIHNlZ21lbnRzLgogICAgICAgICAqLwogICAgICAgIGdldE51bVNlZ21lbnRzKCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy5fX2luZGljZXMubGVuZ3RoIC8gMjsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyB0aGUgbnVtYmVyIG9mIGxpbmUgc2VnbWVudHMuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyB0aGUgbnVtYmVyIG9mIHNlZ21lbnRzLgogICAgICAgICAqLwogICAgICAgIGdldE51bUxpbmVTZWdtZW50cygpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuX19pbmRpY2VzLmxlbmd0aCAvIDI7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFNldHMgdGhlIG51bWJlciBvZiBsaW5lIHNlZ21lbnRzIGluIHRoZSBsaW5lcyBnZW9tZXRyeS4KICAgICAgICAgKiAqKkltcG9ydGFudDoqKiBJdCByZXNldHMgaW5kaWNlcyB2YWx1ZXMuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gbnVtT2ZTZWdtZW50cyAtIFRoZSBjb3VudCB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBzZXROdW1TZWdtZW50cyhudW1PZlNlZ21lbnRzKSB7CiAgICAgICAgICAgIGlmIChudW1PZlNlZ21lbnRzID4gdGhpcy5nZXROdW1TZWdtZW50cygpKSB7CiAgICAgICAgICAgICAgICBjb25zdCBpbmRpY2VzID0gbmV3IFVpbnQzMkFycmF5KG51bU9mU2VnbWVudHMgKiAyKTsKICAgICAgICAgICAgICAgIGluZGljZXMuc2V0KHRoaXMuX19pbmRpY2VzKTsKICAgICAgICAgICAgICAgIHRoaXMuX19pbmRpY2VzID0gaW5kaWNlczsKICAgICAgICAgICAgfQogICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgIHRoaXMuX19pbmRpY2VzID0gdGhpcy5fX2luZGljZXMuc2xpY2UoMCwgbnVtT2ZTZWdtZW50cyAqIDIpOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFNldHMgc2VnbWVudCB2YWx1ZXMgaW4gdGhlIHNwZWNpZmllZCBpbmRleC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBpbmRleCAtIFRoZSBpbmRleCB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0gcDAgLSBUaGUgcDAgdmFsdWUuCiAgICAgICAgICogQHBhcmFtIHAxIC0gVGhlIHAxIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHNldFNlZ21lbnRWZXJ0ZXhJbmRpY2VzKGluZGV4LCBwMCwgcDEpIHsKICAgICAgICAgICAgaWYgKGluZGV4ID49IHRoaXMuX19pbmRpY2VzLmxlbmd0aCAvIDIpCiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgbGluZSBpbmRleDonICsgaW5kZXggKyAnLiBOdW0gU2VnbWVudHM6JyArIHRoaXMuX19pbmRpY2VzLmxlbmd0aCAvIDIpOwogICAgICAgICAgICB0aGlzLl9faW5kaWNlc1tpbmRleCAqIDIgKyAwXSA9IHAwOwogICAgICAgICAgICB0aGlzLl9faW5kaWNlc1tpbmRleCAqIDIgKyAxXSA9IHAxOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgZ2V0U2VnbWVudFZlcnRleEluZGV4IG1ldGhvZC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBsaW5lIC0gVGhlIGxpbmUgdmFsdWUuCiAgICAgICAgICogQHBhcmFtIGxpbmVWZXJ0ZXggLSBUaGUgbGluZVZlcnRleCB2YWx1ZS4KICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKiBAcHJpdmF0ZQogICAgICAgICAqLwogICAgICAgIGdldFNlZ21lbnRWZXJ0ZXhJbmRleChsaW5lLCBsaW5lVmVydGV4KSB7CiAgICAgICAgICAgIGNvbnN0IG51bVNlZ21lbnRzID0gdGhpcy5nZXROdW1TZWdtZW50cygpOwogICAgICAgICAgICBpZiAobGluZSA8IG51bVNlZ21lbnRzKQogICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuX19pbmRpY2VzW2xpbmUgKiAyICsgbGluZVZlcnRleF07CiAgICAgICAgICAgIHJldHVybiAtMTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogTWVyZ2VzIGEgc2VwYXJhdGUgZ2VvbWV0cnkgaW50byB0aGlzIG9uZS4gU2ltaWxhciB0byBhICd1bmlvbicgYm9vbGVhbiBvcGVyYXRpb24uCiAgICAgICAgICogQHBhcmFtIG90aGVyIHRoZSBvdGhlciBnZW9tIHRoYXQgd2lsbCBiZSBtZXJnZWQgaW50byB0aGlzIG9uZQogICAgICAgICAqIEBwYXJhbSB4Zm8gdGhlIHRyYW5zZm9ybWF0aW9uIHRvIGJlIGFwcGxpZWQgdG8gdGhlIG90aGVyIGdlb20gYXMgaXQgaXMgbWVyZ2VkIGluLgogICAgICAgICAqLwogICAgICAgIG1lcmdlKG90aGVyLCB4Zm8gPSBuZXcgWGZvKCkpIHsKICAgICAgICAgICAgY29uc3QgcHJldk51bVZlcnRzID0gdGhpcy5nZXROdW1WZXJ0aWNlcygpOwogICAgICAgICAgICBzdXBlci5tZXJnZShvdGhlciwgeGZvKTsKICAgICAgICAgICAgY29uc3Qgb3RoZUluZGljZXMgPSBvdGhlci5fX2luZGljZXM7CiAgICAgICAgICAgIGNvbnN0IGluZGljZXMgPSBuZXcgVWludDMyQXJyYXkodGhpcy5fX2luZGljZXMubGVuZ3RoICsgb3RoZUluZGljZXMubGVuZ3RoKTsKICAgICAgICAgICAgaW5kaWNlcy5zZXQodGhpcy5fX2luZGljZXMsIDApOwogICAgICAgICAgICBpbmRpY2VzLnNldChvdGhlSW5kaWNlcy5tYXAoKGluZGV4KSA9PiBpbmRleCArIHByZXZOdW1WZXJ0cyksIHRoaXMuX19pbmRpY2VzLmxlbmd0aCk7CiAgICAgICAgICAgIHRoaXMuX19pbmRpY2VzID0gaW5kaWNlczsKICAgICAgICB9CiAgICAgICAgLy8gLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwogICAgICAgIC8vIE1lbW9yeQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgdmVydGV4IGF0dHJpYnV0ZXMgYnVmZmVycyBhbmQgaXRzIGNvdW50LgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgZ2VuQnVmZmVycyhvcHRzKSB7CiAgICAgICAgICAgIGNvbnN0IGJ1ZmZlcnMgPSBzdXBlci5nZW5CdWZmZXJzKCk7CiAgICAgICAgICAgIGxldCBpbmRpY2VzOwogICAgICAgICAgICBpZiAoYnVmZmVycy5udW1WZXJ0aWNlcyA8IE1hdGgucG93KDIsIDgpKSB7CiAgICAgICAgICAgICAgICBpbmRpY2VzID0gbmV3IFVpbnQ4QXJyYXkodGhpcy5fX2luZGljZXMpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGVsc2UgaWYgKGJ1ZmZlcnMubnVtVmVydGljZXMgPCBNYXRoLnBvdygyLCAxNikpIHsKICAgICAgICAgICAgICAgIGluZGljZXMgPSBuZXcgVWludDE2QXJyYXkodGhpcy5fX2luZGljZXMpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGVsc2UgewogICAgICAgICAgICAgICAgaW5kaWNlcyA9IHRoaXMuX19pbmRpY2VzOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGJ1ZmZlcnMuaW5kaWNlcyA9IGluZGljZXM7CiAgICAgICAgICAgIHJldHVybiBidWZmZXJzOwogICAgICAgIH0KICAgICAgICAvLyAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCiAgICAgICAgLy8gUGVyc2lzdGVuY2UKICAgICAgICAvKioKICAgICAgICAgKiBTZXRzIHN0YXRlIG9mIGN1cnJlbnQgZ2VvbWV0cnkoSW5jbHVkaW5nIGxpbmUgc2VnbWVudHMpIHVzaW5nIGEgYmluYXJ5IHJlYWRlciBvYmplY3QuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gcmVhZGVyIC0gVGhlIHJlYWRlciB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0gY29udGV4dCAtIFRoZSBjb250ZXh0IHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHJlYWRCaW5hcnkocmVhZGVyLCBjb250ZXh0KSB7CiAgICAgICAgICAgIHN1cGVyLmxvYWRCYXNlR2VvbUJpbmFyeShyZWFkZXIsIGNvbnRleHQpOwogICAgICAgICAgICB0aGlzLnNldE51bVNlZ21lbnRzKHJlYWRlci5sb2FkVUludDMyKCkpOwogICAgICAgICAgICBjb25zdCBieXRlcyA9IHJlYWRlci5sb2FkVUludDgoKTsKICAgICAgICAgICAgaWYgKGJ5dGVzID09IDEpCiAgICAgICAgICAgICAgICB0aGlzLl9faW5kaWNlcyA9IHJlYWRlci5sb2FkVUludDhBcnJheSgpOwogICAgICAgICAgICBlbHNlIGlmIChieXRlcyA9PSAyKQogICAgICAgICAgICAgICAgdGhpcy5fX2luZGljZXMgPSByZWFkZXIubG9hZFVJbnQxNkFycmF5KCk7CiAgICAgICAgICAgIGVsc2UgaWYgKGJ5dGVzID09IDQpCiAgICAgICAgICAgICAgICB0aGlzLl9faW5kaWNlcyA9IHJlYWRlci5sb2FkVUludDMyQXJyYXkoKTsKICAgICAgICAgICAgdGhpcy5lbWl0KCdnZW9tRGF0YUNoYW5nZWQnKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIHRvSlNPTiBtZXRob2QgZW5jb2RlcyB0aGlzIHR5cGUgYXMgYSBqc29uIG9iamVjdCBmb3IgcGVyc2lzdGVuY2UuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gY29udGV4dCAtIFRoZSBjb250ZXh0IHZhbHVlLgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIHRoZSBqc29uIG9iamVjdC4KICAgICAgICAgKi8KICAgICAgICB0b0pTT04oY29udGV4dCkgewogICAgICAgICAgICBjb25zdCBqID0gc3VwZXIudG9KU09OKGNvbnRleHQpOwogICAgICAgICAgICBpZiAoIWNvbnRleHQgfHwgIWNvbnRleHQuc2tpcFRvcG9sb2d5KQogICAgICAgICAgICAgICAgai5pbmRpY2VzID0gQXJyYXkuZnJvbSh0aGlzLl9faW5kaWNlcyk7CiAgICAgICAgICAgIHJldHVybiBqOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgZnJvbUpTT04gbWV0aG9kIGRlY29kZXMgYSBqc29uIG9iamVjdCBmb3IgdGhpcyB0eXBlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIGogLSBUaGUganNvbiBvYmplY3QgdGhpcyBpdGVtIG11c3QgZGVjb2RlLgogICAgICAgICAqIEBwYXJhbSBjb250ZXh0IC0gVGhlIGNvbnRleHQgdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgZnJvbUpTT04oaiwgY29udGV4dCkgewogICAgICAgICAgICBzdXBlci5mcm9tSlNPTihqLCBjb250ZXh0KTsKICAgICAgICAgICAgaWYgKGouaW5kaWNlcykKICAgICAgICAgICAgICAgIHRoaXMuX19pbmRpY2VzID0gVWludDMyQXJyYXkuZnJvbShqLmluZGljZXMpOwogICAgICAgIH0KICAgIH0KICAgIFJlZ2lzdHJ5LnJlZ2lzdGVyKCdMaW5lcycsIExpbmVzKTsKCiAgICAvKiBlc2xpbnQtZGlzYWJsZSBwcmVmZXItcmVzdC1wYXJhbXMgKi8KICAgIC8qKgogICAgICogVGhlIE1lc2ggY2xhc3MgcHJvdmlkZXMgYSBmbGV4aWJsZSBhbmQgZmFzdCBwb2x5Z29uIG1lc2ggcmVwcmVzZW50YXRpb24uIEl0IHN1cHBvcnRzIHBvbHlnb25zIG9mIGFyYml0cmFyeSBjb21wbGV4aXR5LAogICAgICogZnJvbSBiYXNpYyB0cmlhbmdsZXMgYW5kIHF1YWRzIHRvIHBlbnRhZ29ucyBtb3JlLgogICAgICogSXQgc3VwcG9ydHMgc3RvcmluZyBwZXIgZmFjZSBhdHRyaWJ1dGVzLCBhbmQgcGVyIGVkZ2UgYXR0cmlidXRlcy4KICAgICAqIFRoZSBNZXNoIGNsYXNzIGhhbmRsZXMgY29udmVydGluZyBpdHMgaW50ZXJuYWwgcmVwcmVzZW50YXRpb24gb2YgcG9seWdvbnMgaW50byBhIHNpbXBsZXIgdHJpYW5nbGVzIHJlcHJlc2VudGF0aW9uIGZvciByZW5kZXJpbmcuCiAgICAgKgogICAgICogYGBgCiAgICAgKiBjb25zdCBtZXNoID0gbmV3IE1lc2goKQogICAgICogYGBgCiAgICAgKgogICAgICogKipFdmVudHMqKgogICAgICogKiAqKmdlb21EYXRhVG9wb2xvZ3lDaGFuZ2VkOioqIFRyaWdnZXJlZCB3aGVuIHRoZSB0b3BvbG9neSBvZiB0aGUgbWVzaCBoYXMgYmVlbiBjaGFuZ2VkLgogICAgICogKiAqKmdlb21EYXRhQ2hhbmdlZDoqKiBUcmlnZ2VyZWQgd2hlbiB0aGUgdmVydGljZXMgb2YgdGhlIG1lc2ggaGF2ZSBjaGFuZ2VkLCBidXQgbm90IG5lY2Vzc2FyaWx5IHRoZSB0b3BvbG9neS4KICAgICAqCiAgICAgKiBAZXh0ZW5kcyBCYXNlR2VvbQogICAgICovCiAgICBjbGFzcyBNZXNoIGV4dGVuZHMgQmFzZUdlb20gewogICAgICAgIGZhY2VDb3VudHM7CiAgICAgICAgZmFjZVZlcnRleEluZGljZXM7CiAgICAgICAgX19sb2dUb3BvbG9neVdhcm5pbmdzOwogICAgICAgIF9fZWRnZUF0dHJpYnV0ZXM7CiAgICAgICAgX19mYWNlQXR0cmlidXRlczsKICAgICAgICBudW1FZGdlczsKICAgICAgICBlZGdlVmVydHM7CiAgICAgICAgZWRnZUFuZ2xlczsKICAgICAgICBlZGdlVmVjczsKICAgICAgICBlZGdlRmFjZXM7CiAgICAgICAgZmFjZUVkZ2VzOwogICAgICAgIHZlcnRleEVkZ2VzOwogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgYW4gaW5zdGFuY2Ugb2YgTWVzaC4KICAgICAgICAgKi8KICAgICAgICBjb25zdHJ1Y3RvcigpIHsKICAgICAgICAgICAgc3VwZXIoKTsKICAgICAgICAgICAgdGhpcy5lZGdlRmFjZXMgPSBbXTsKICAgICAgICAgICAgdGhpcy5mYWNlRWRnZXMgPSBbW11dOwogICAgICAgICAgICB0aGlzLmZhY2VDb3VudHMgPSBbXTsKICAgICAgICAgICAgdGhpcy5mYWNlVmVydGV4SW5kaWNlcyA9IG5ldyBVaW50MzJBcnJheSgpOwogICAgICAgICAgICB0aGlzLl9fbG9nVG9wb2xvZ3lXYXJuaW5ncyA9IGZhbHNlOwogICAgICAgICAgICB0aGlzLl9fZWRnZUF0dHJpYnV0ZXMgPSBuZXcgTWFwKCk7CiAgICAgICAgICAgIHRoaXMuX19mYWNlQXR0cmlidXRlcyA9IG5ldyBNYXAoKTsKICAgICAgICAgICAgdGhpcy5udW1FZGdlcyA9IDA7CiAgICAgICAgICAgIHRoaXMuZWRnZVZlcnRzID0gW107CiAgICAgICAgICAgIHRoaXMudmVydGV4RWRnZXMgPSBbXTsKICAgICAgICAgICAgdGhpcy5lZGdlQW5nbGVzID0gbmV3IEZsb2F0MzJBcnJheSgpOwogICAgICAgICAgICB0aGlzLmVkZ2VWZWNzID0gW107CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBjbGVhciBtZXRob2QuCiAgICAgICAgICovCiAgICAgICAgY2xlYXIoKSB7CiAgICAgICAgICAgIHN1cGVyLmNsZWFyKCk7CiAgICAgICAgICAgIC8vdGhpcy5pbml0KCkKICAgICAgICAgICAgLy90aGlzLnNldE51bVZlcnRpY2VzKDApCiAgICAgICAgICAgIC8vIGNsZWFyIGVkZ2UgYW5kIGZhY2Ugbm9ybWFscy4KICAgICAgICAgICAgdGhpcy5lZGdlVmVydHMgPSBbXTsKICAgICAgICAgICAgdGhpcy52ZXJ0ZXhFZGdlcyA9IFtdOwogICAgICAgICAgICB0aGlzLm51bUVkZ2VzID0gMDsKICAgICAgICAgICAgdGhpcy5lZGdlQW5nbGVzID0gbmV3IEZsb2F0MzJBcnJheSgpOwogICAgICAgICAgICB0aGlzLmVtaXQoJ2dlb21EYXRhVG9wb2xvZ3lDaGFuZ2VkJyk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEFkZHMgYSBuZXcgdmVydGV4IGF0dHJpYnV0ZSB0byB0aGUgZ2VvbWV0cnkuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gbmFtZSAtIFRoZSBuYW1lIG9mIHRoZSB2ZXJ0ZXggYXR0cmlidXRlLgogICAgICAgICAqIEBwYXJhbSBhdHRyIC0gVGhlIGF0dHJpYnV0ZSB0byBhZGQgdG8gdGhlIGdlb21ldHJ5CiAgICAgICAgICovCiAgICAgICAgYWRkVmVydGV4QXR0cmlidXRlKG5hbWUsIGF0dHIpIHsKICAgICAgICAgICAgc3VwZXIuYWRkVmVydGV4QXR0cmlidXRlKG5hbWUsIGF0dHIpOwogICAgICAgICAgICBhdHRyLnNldE1lc2godGhpcyk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBnZXRGYWNlQ291bnRzIG1ldGhvZC4KICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBnZXRGYWNlQ291bnRzKCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy5mYWNlQ291bnRzOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgZ2V0TnVtRmFjZXMgbWV0aG9kLgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGdldE51bUZhY2VzKCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy5mYWNlQ291bnRzLmxlbmd0aCA9PSAwID8gMCA6IHRoaXMuZmFjZUNvdW50cy5yZWR1Y2UoKG51bUZhY2VzLCBmYykgPT4gKG51bUZhY2VzICs9IGZjKSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBnZXROdW1UcmlhbmdsZXMgbWV0aG9kLgogICAgICAgICAqIEByZXR1cm4ge251bWJlcn0gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGdldE51bVRyaWFuZ2xlcygpIHsKICAgICAgICAgICAgbGV0IG51bVRyaWFuZ2xlcyA9IDA7CiAgICAgICAgICAgIGxldCBudW1UcmlzUGVyRmFjZSA9IDE7CiAgICAgICAgICAgIGZvciAoY29uc3QgZmMgb2YgdGhpcy5mYWNlQ291bnRzKSB7CiAgICAgICAgICAgICAgICBudW1UcmlhbmdsZXMgKz0gZmMgKiBudW1UcmlzUGVyRmFjZTsKICAgICAgICAgICAgICAgIG51bVRyaXNQZXJGYWNlKys7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIG51bVRyaWFuZ2xlczsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU2V0cyB0aGUgbnVtYmVyIG9mIGZhY2VzIG9uIHRoZSBtZXNoIHVzaW5nIGFuIGFycmF5IHNwZWNpZnlpbmcgdGhlIGNvdW50cyBwZXIgcG9seWdvbiBzaXplLgogICAgICAgICAqIFRoZSBmaXJzdCBpdGVtIGluIHRoZSBhcnJheSBzcGVjaWZpZXMgdGhlIG51bWJlciBvZiB0cmlhbmdsZXMsIHRoZSBzZWNvbmQsIHRoZSBudW1iZXIgb2YgcXVhZHMsIHRoZSAzcmQsIHRoZSBudW1iZXIgb2YgNSBzaWRlZCBwb2x5Z29ucyBldGMuLgogICAgICAgICAqIGUuZy4gdG8gc3BlY2lmeSAyIHRyaWFuZ2xlcywgYW5kIDcgcXVhZHMsIHdlIHdvdWxkIHBhc3MgWzIsIDddCiAgICAgICAgICogQHBhcmFtIGZhY2VDb3VudHMgLSBUaGUgZmFjZUNvdW50cyB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBzZXRGYWNlQ291bnRzKGZhY2VDb3VudHMpIHsKICAgICAgICAgICAgLy8gbGV0IG51bUZhY2VzID0gMAogICAgICAgICAgICBsZXQgbnVtRmFjZXNWZXJ0aWNlcyA9IDA7CiAgICAgICAgICAgIGxldCBudW1WZXJ0c1BlckZhY2UgPSAzOwogICAgICAgICAgICBmb3IgKGNvbnN0IGZjIG9mIGZhY2VDb3VudHMpIHsKICAgICAgICAgICAgICAgIC8vIG51bUZhY2VzICs9IGZjCiAgICAgICAgICAgICAgICBudW1GYWNlc1ZlcnRpY2VzICs9IGZjICogbnVtVmVydHNQZXJGYWNlOwogICAgICAgICAgICAgICAgbnVtVmVydHNQZXJGYWNlKys7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgY29uc3QgcHJldk51bUZhY2VzID0gdGhpcy5nZXROdW1GYWNlcygpOwogICAgICAgICAgICBpZiAocHJldk51bUZhY2VzID09IDApIHsKICAgICAgICAgICAgICAgIHRoaXMuZmFjZVZlcnRleEluZGljZXMgPSBuZXcgVWludDMyQXJyYXkobnVtRmFjZXNWZXJ0aWNlcyk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZWxzZSB7CiAgICAgICAgICAgICAgICBjb25zdCBmYWNlVmVydGV4SW5kaWNlcyA9IG5ldyBVaW50MzJBcnJheShudW1GYWNlc1ZlcnRpY2VzKTsKICAgICAgICAgICAgICAgIC8vIE5vdyB3ZSBwcmVzZXJ2ZSB0aGUgZXhpc3RpbmcgaW5kaWNlcyBpZiB0aGV5IGZpdCB3aXRoaW4gdGhlIG5ldyBmYWNlVmVydGV4SW5kaWNlcyBhcnJheS4KICAgICAgICAgICAgICAgIGxldCBzdGFydFNyYyA9IDA7CiAgICAgICAgICAgICAgICBsZXQgc3RhcnRUZ3QgPSAwOwogICAgICAgICAgICAgICAgbnVtRmFjZXNWZXJ0aWNlcyA9IDA7CiAgICAgICAgICAgICAgICBudW1WZXJ0c1BlckZhY2UgPSAzOwogICAgICAgICAgICAgICAgZmFjZUNvdW50cy5mb3JFYWNoKChmYywgaW5kZXgpID0+IHsKICAgICAgICAgICAgICAgICAgICBjb25zdCBlbmRTcmMgPSBzdGFydFNyYyArIE1hdGgubWluKGZjLCB0aGlzLmZhY2VDb3VudHNbaW5kZXhdKSAqIG51bVZlcnRzUGVyRmFjZTsKICAgICAgICAgICAgICAgICAgICBmYWNlVmVydGV4SW5kaWNlcy5zZXQodGhpcy5mYWNlVmVydGV4SW5kaWNlcy5zbGljZShzdGFydFNyYywgZW5kU3JjKSwgc3RhcnRUZ3QpOwogICAgICAgICAgICAgICAgICAgIHN0YXJ0U3JjICs9IHRoaXMuZmFjZUNvdW50c1tpbmRleF0gKiBudW1WZXJ0c1BlckZhY2U7CiAgICAgICAgICAgICAgICAgICAgc3RhcnRUZ3QgKz0gZmMgKiBudW1WZXJ0c1BlckZhY2U7CiAgICAgICAgICAgICAgICAgICAgbnVtVmVydHNQZXJGYWNlKys7CiAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIHRoaXMuZmFjZVZlcnRleEluZGljZXMgPSBmYWNlVmVydGV4SW5kaWNlczsKICAgICAgICAgICAgfQogICAgICAgICAgICB0aGlzLmZhY2VDb3VudHMgPSBmYWNlQ291bnRzOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIHRoZSBudW1iZXIgb2YgZmFjZSB2ZXJ0aWNlcwogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGdldE51bUZhY2VWZXJ0aWNlcygpIHsKICAgICAgICAgICAgbGV0IG51bUZhY2VWZXJ0cyA9IDA7CiAgICAgICAgICAgIHRoaXMuZmFjZUNvdW50cy5mb3JFYWNoKChmYywgaW5kZXgpID0+IHsKICAgICAgICAgICAgICAgIG51bUZhY2VWZXJ0cyArPSBmYyAqIChpbmRleCArIDMpOwogICAgICAgICAgICB9KTsKICAgICAgICAgICAgcmV0dXJuIG51bUZhY2VWZXJ0czsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyB0aGUgbnVtYmVyIG9mIHZlcnRpY2VzIGluZGV4ZWQgYnkgdGhpcyBmYWNlCiAgICAgICAgICogQHBhcmFtIGZhY2VJbmRleCAtIFRoZSBmYWNlSW5kZXggdmFsdWUuCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgZ2V0RmFjZVZlcnRleENvdW50KGZhY2VJbmRleCkgewogICAgICAgICAgICBsZXQgaWR4ID0gMDsKICAgICAgICAgICAgbGV0IGNvdW50ID0gMDsKICAgICAgICAgICAgdGhpcy5mYWNlQ291bnRzLnNvbWUoKGZjLCBpbmRleCkgPT4gewogICAgICAgICAgICAgICAgaWR4ICs9IGZjOwogICAgICAgICAgICAgICAgaWYgKGlkeCA+IGZhY2VJbmRleCkgewogICAgICAgICAgICAgICAgICAgIGNvdW50ID0gaW5kZXggKyAzOwogICAgICAgICAgICAgICAgICAgIHJldHVybiB0cnVlOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICAgICAgICB9KTsKICAgICAgICAgICAgcmV0dXJuIGNvdW50OwogICAgICAgIH0KICAgICAgICBnZXRGYWNlVmVydGV4T2Zmc2V0KGZhY2VJbmRleCkgewogICAgICAgICAgICBsZXQgaWR4ID0gMDsKICAgICAgICAgICAgbGV0IG9mZnNldCA9IDA7CiAgICAgICAgICAgIHRoaXMuZmFjZUNvdW50cy5zb21lKChmYywgaW5kZXgpID0+IHsKICAgICAgICAgICAgICAgIGlmIChpZHggKyBmYyA+IGZhY2VJbmRleCkgewogICAgICAgICAgICAgICAgICAgIG9mZnNldCArPSAoZmFjZUluZGV4IC0gaWR4KSAqIChpbmRleCArIDMpOwogICAgICAgICAgICAgICAgICAgIHJldHVybiB0cnVlOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgaWR4ICs9IGZjOwogICAgICAgICAgICAgICAgb2Zmc2V0ICs9IGZjICogKGluZGV4ICsgMyk7CiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgICAgIH0pOwogICAgICAgICAgICByZXR1cm4gb2Zmc2V0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgc2V0RmFjZVZlcnRleEluZGljZXMgbWV0aG9kLgogICAgICAgICAqIEBwYXJhbSBmYWNlSW5kZXggLSBUaGUgZmFjZUluZGV4IHZhbHVlLgogICAgICAgICAqIEBwYXJhbSB2ZXJ0ZXhJbmRpY2VzIC0gVGhlIGFycmF5IG9mIHZlcnRleCBpbmRpY2VzIGZvciB0aGlzIGZhY2UgdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgc2V0RmFjZVZlcnRleEluZGljZXMoZmFjZUluZGV4LCB2ZXJ0ZXhJbmRpY2VzKSB7CiAgICAgICAgICAgIGNvbnN0IGZhY2VWZXJ0ZXhDb3VudCA9IHRoaXMuZ2V0RmFjZVZlcnRleENvdW50KGZhY2VJbmRleCk7CiAgICAgICAgICAgIGlmICh2ZXJ0ZXhJbmRpY2VzLmxlbmd0aCAhPSBmYWNlVmVydGV4Q291bnQpIHsKICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCBpbmRpY2VzIGZvciBmYWNlOiR7ZmFjZUluZGV4fSB2ZXJ0ZXhJbmRpY2VzOiR7dmVydGV4SW5kaWNlc30uIEV4cGVjdGVkICR7ZmFjZVZlcnRleENvdW50fSBpbmRpY2VzYCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgY29uc3Qgb2Zmc2V0ID0gdGhpcy5nZXRGYWNlVmVydGV4T2Zmc2V0KGZhY2VJbmRleCk7CiAgICAgICAgICAgIHRoaXMuZmFjZVZlcnRleEluZGljZXMuc2V0KHZlcnRleEluZGljZXMsIG9mZnNldCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEFkZHMgYSBuZXcgZmFjZSB0byB0aGUgbWVzaAogICAgICAgICAqIEBwYXJhbSB2ZXJ0ZXhJbmRpY2VzIC0gVGhlIHZlcnRleCBpbmRpY2VzIG9mIHRoZSBmYWNlLgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgaW5kZXggb2YgdGhlIGZhY2UgaW4gdGhlIG1lc2guCiAgICAgICAgICovCiAgICAgICAgYWRkRmFjZSh2ZXJ0ZXhJbmRpY2VzKSB7CiAgICAgICAgICAgIGNvbnN0IGZhY2VDb3VudHMgPSBbLi4udGhpcy5mYWNlQ291bnRzXTsKICAgICAgICAgICAgaWYgKGZhY2VDb3VudHMubGVuZ3RoIDw9IHZlcnRleEluZGljZXMubGVuZ3RoIC0gMykgewogICAgICAgICAgICAgICAgZm9yIChsZXQgaSA9IGZhY2VDb3VudHMubGVuZ3RoOyBpIDwgdmVydGV4SW5kaWNlcy5sZW5ndGggLSAzOyBpKyspCiAgICAgICAgICAgICAgICAgICAgZmFjZUNvdW50c1tpXSA9IDA7CiAgICAgICAgICAgICAgICBmYWNlQ291bnRzW3ZlcnRleEluZGljZXMubGVuZ3RoIC0gM10gPSAxOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGVsc2UgewogICAgICAgICAgICAgICAgZmFjZUNvdW50c1t2ZXJ0ZXhJbmRpY2VzLmxlbmd0aCAtIDNdKys7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdGhpcy5zZXRGYWNlQ291bnRzKGZhY2VDb3VudHMpOwogICAgICAgICAgICAvLyBDYWxjdWxhdGUgdGhlIG9mZnNldCBpbiB0aGUgZmFjZVZlcnRleEluZGljZXMgb2YgdGhpcyBuZXcgZmFjZS4KICAgICAgICAgICAgbGV0IGZhY2VJbmRleCA9IDA7CiAgICAgICAgICAgIGxldCBvZmZzZXQgPSAwOwogICAgICAgICAgICB0aGlzLmZhY2VDb3VudHMuc29tZSgoZmMsIGluZGV4KSA9PiB7CiAgICAgICAgICAgICAgICBpZiAoaW5kZXggKyAzID09IHZlcnRleEluZGljZXMubGVuZ3RoKSB7CiAgICAgICAgICAgICAgICAgICAgZmFjZUluZGV4ICs9IGZjIC0gMTsKICAgICAgICAgICAgICAgICAgICBvZmZzZXQgKz0gKGZjIC0gMSkgKiAoaW5kZXggKyAzKTsKICAgICAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGZhY2VJbmRleCArPSBmYzsKICAgICAgICAgICAgICAgIG9mZnNldCArPSBmYyAqIChpbmRleCArIDMpOwogICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICAgICAgICB9KTsKICAgICAgICAgICAgdGhpcy5mYWNlVmVydGV4SW5kaWNlcy5zZXQodmVydGV4SW5kaWNlcywgb2Zmc2V0KTsKICAgICAgICAgICAgcmV0dXJuIGZhY2VJbmRleDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyB0aGUgdmVydGV4IGluZGljZXMgb2YgdGhlIHNwZWNpZmllZCBmYWNlLgogICAgICAgICAqIEBwYXJhbSBmYWNlSW5kZXggLSBUaGUgaW5kZXggb2YgdGhlIHNwZWNpZmllZCBmYWNlCiAgICAgICAgICogQHJldHVybiAtIEFuIGFycmF5IG9mIGluZGljZXMgaW50byB0aGUgdmVydGV4IGF0dHJpYnV0ZXMKICAgICAgICAgKi8KICAgICAgICBnZXRGYWNlVmVydGV4SW5kaWNlcyhmYWNlSW5kZXgpIHsKICAgICAgICAgICAgY29uc3QgdmVydGV4SW5kaWNlcyA9IFtdOwogICAgICAgICAgICBjb25zdCBvZmZzZXQgPSB0aGlzLmdldEZhY2VWZXJ0ZXhPZmZzZXQoZmFjZUluZGV4KTsKICAgICAgICAgICAgY29uc3QgY291bnQgPSB0aGlzLmdldEZhY2VWZXJ0ZXhDb3VudChmYWNlSW5kZXgpOwogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGNvdW50OyBpKyspIHsKICAgICAgICAgICAgICAgIHZlcnRleEluZGljZXMucHVzaCh0aGlzLmZhY2VWZXJ0ZXhJbmRpY2VzW29mZnNldCArIGldKTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gdmVydGV4SW5kaWNlczsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyBhIHNpbmdsZSB2ZXJ0ZXggaW5kZXggZm9yIGEgZ2l2ZW4gZmFjZSBhbmQgZmFjZVZlcnRleC4KICAgICAgICAgKiBAcGFyYW0gZmFjZUluZGV4IC0gVGhlIGZhY2VJbmRleCB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0gZmFjZVZlcnRleCAtIFRoZSBmYWNlIHZlcnRleCBpcyB0aGUgaW5kZXggd2l0aGluIHRoZSBmYWNlLiBTbyB0aGUgZmlyc3QgdmVydGV4IGluZGV4IGlzIDAuCiAgICAgICAgICogQHJldHVybiAtIFRoZSB2ZXJ0ZXggaW5kZXgKICAgICAgICAgKi8KICAgICAgICBnZXRGYWNlVmVydGV4SW5kZXgoZmFjZUluZGV4LCBmYWNlVmVydGV4KSB7CiAgICAgICAgICAgIGNvbnN0IG9mZnNldCA9IHRoaXMuZ2V0RmFjZVZlcnRleE9mZnNldChmYWNlSW5kZXgpOwogICAgICAgICAgICByZXR1cm4gdGhpcy5mYWNlVmVydGV4SW5kaWNlc1tvZmZzZXQgKyBmYWNlVmVydGV4XTsKICAgICAgICB9CiAgICAgICAgLy8gLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCiAgICAgICAgLy8gRmFjZSBBdHRyaWJ1dGVzCiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGFkZEZhY2VBdHRyaWJ1dGUgbWV0aG9kLgogICAgICAgICAqIEBwYXJhbSBuYW1lIC0gVGhlIG5hbWUgb2YgdGhlIGZhY2UgYXR0cmlidXRlIHRvIGFkZC4KICAgICAgICAgKiBAcGFyYW0gYXR0ciAtIFRoZSBhdHRyIHZhbHVlCiAgICAgICAgICovCiAgICAgICAgYWRkRmFjZUF0dHJpYnV0ZShuYW1lLCBhdHRyKSB7CiAgICAgICAgICAgIGF0dHIuc2V0Q291bnQodGhpcy5nZXROdW1GYWNlcygpKTsKICAgICAgICAgICAgdGhpcy5fX2ZhY2VBdHRyaWJ1dGVzLnNldChuYW1lLCBhdHRyKTsKICAgICAgICAgICAgcmV0dXJuIGF0dHI7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBoYXNGYWNlQXR0cmlidXRlIG1ldGhvZC4KICAgICAgICAgKiBAcGFyYW0gbmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBmYWNlIGF0dHJpYnV0ZS4KICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBoYXNGYWNlQXR0cmlidXRlKG5hbWUpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuX19mYWNlQXR0cmlidXRlcy5oYXMobmFtZSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBnZXRGYWNlQXR0cmlidXRlIG1ldGhvZC4KICAgICAgICAgKiBAcGFyYW0gbmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBmYWNlIGF0dHJpYnV0ZS4KICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBnZXRGYWNlQXR0cmlidXRlKG5hbWUpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuX19mYWNlQXR0cmlidXRlcy5nZXQobmFtZSk7CiAgICAgICAgfQogICAgICAgIC8vIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KICAgICAgICAvLyBFZGdlIEF0dHJpYnV0ZXMKICAgICAgICAvKioKICAgICAgICAgKiBUaGUgYWRkRWRnZUF0dHJpYnV0ZSBtZXRob2QuCiAgICAgICAgICogQHBhcmFtIG5hbWUgLSBUaGUgbmFtZSBvZiB0aGUgZWRnZSBhdHRyaWJ1dGUgdG8gYWRkLgogICAgICAgICAqIEBwYXJhbSBhdHRyIC0gVGhlIGF0dHIgdmFsdWUKICAgICAgICAgKi8KICAgICAgICBhZGRFZGdlQXR0cmlidXRlKG5hbWUsIGF0dHIpIHsKICAgICAgICAgICAgYXR0ci5zZXRDb3VudCh0aGlzLm51bUVkZ2VzKTsKICAgICAgICAgICAgdGhpcy5fX2VkZ2VBdHRyaWJ1dGVzLnNldChuYW1lLCBhdHRyKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGhhc0VkZ2VBdHRyaWJ1dGUgbWV0aG9kLgogICAgICAgICAqIEBwYXJhbSBuYW1lIC0gVGhlIG5hbWUgb2YgdGhlIGVkZ2UgYXR0cmlidXRlLgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGhhc0VkZ2VBdHRyaWJ1dGUobmFtZSkgewogICAgICAgICAgICByZXR1cm4gdGhpcy5fX2VkZ2VBdHRyaWJ1dGVzLmhhcyhuYW1lKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGdldEVkZ2VBdHRyaWJ1dGUgbWV0aG9kLgogICAgICAgICAqIEBwYXJhbSBuYW1lIC0gVGhlIG5hbWUgb2YgdGhlIGVkZ2UgYXR0cmlidXRlLgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGdldEVkZ2VBdHRyaWJ1dGUobmFtZSkgewogICAgICAgICAgICByZXR1cm4gdGhpcy5fX2VkZ2VBdHRyaWJ1dGVzLmdldChuYW1lKTsKICAgICAgICB9CiAgICAgICAgLy8gLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGdlblRvcG9sb2d5SW5mbyBtZXRob2QuCiAgICAgICAgICovCiAgICAgICAgZ2VuVG9wb2xvZ3lJbmZvKCkgewogICAgICAgICAgICBsZXQgY29ubmVjdGVkVmVydGljZXMgPSB7fTsgLy8gYWNjZWxlcmF0aW9uIHN0cnVjdHVyZS4KICAgICAgICAgICAgdGhpcy52ZXJ0ZXhFZGdlcyA9IFtdOyAvLyAyZCBhcnJheSBvZiB2ZXJ0ZXggdG8gZWRnZXMuCiAgICAgICAgICAgIC8vIHRoaXMudmVydGV4RmFjZXMgPSBbXTsgLy8gMmQgYXJyYXkgb2YgdmVydGV4IHRvIGZhY2VzLgogICAgICAgICAgICB0aGlzLmVkZ2VGYWNlcyA9IFtdOyAvLyBmbGF0IGFycmF5IG9mIDIgZmFjZSBpbmRpY2VzIHBlciBlZGdlCiAgICAgICAgICAgIHRoaXMuZWRnZVZlcnRzID0gW107IC8vIGZsYXQgYXJyYXkgb2YgMiB2ZXJ0IGluZGljZXMgcGVyIGVkZ2UKICAgICAgICAgICAgdGhpcy5mYWNlRWRnZXMgPSBbXTsgLy8gdGhlIGVkZ2VzIGJvcmRlcmluZyBlYWNoIGZhY2UuCiAgICAgICAgICAgIHRoaXMubnVtRWRnZXMgPSAwOwogICAgICAgICAgICBjb25zdCBwb3NpdGlvbnMgPSB0aGlzLnBvc2l0aW9uczsKICAgICAgICAgICAgY29uc3QgZ2V0RWRnZUluZGV4ID0gKHYwLCB2MSkgPT4gewogICAgICAgICAgICAgICAgbGV0IHRtcDAgPSB2MDsKICAgICAgICAgICAgICAgIGxldCB0bXAxID0gdjE7CiAgICAgICAgICAgICAgICBpZiAodG1wMSA8IHRtcDApIHsKICAgICAgICAgICAgICAgICAgICBjb25zdCB0bXAgPSB0bXAwOwogICAgICAgICAgICAgICAgICAgIHRtcDAgPSB0bXAxOwogICAgICAgICAgICAgICAgICAgIHRtcDEgPSB0bXA7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBjb25zdCBrZXkgPSB0bXAwICsgJz4nICsgdG1wMTsKICAgICAgICAgICAgICAgIGlmIChrZXkgaW4gY29ubmVjdGVkVmVydGljZXMpIHsKICAgICAgICAgICAgICAgICAgICAvLyBjb25zb2xlLmxvZyhrZXkgKyAnOicgKyBjb25uZWN0ZWRWZXJ0aWNlc1trZXldICsgIiBmYWNlOiIgKyAoIHYwIDwgdjEgPyAwIDogMSkgKTsKICAgICAgICAgICAgICAgICAgICByZXR1cm4gY29ubmVjdGVkVmVydGljZXNba2V5XTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGNvbnN0IHAwID0gcG9zaXRpb25zLmdldFZhbHVlKHRtcDApOwogICAgICAgICAgICAgICAgY29uc3QgcDEgPSBwb3NpdGlvbnMuZ2V0VmFsdWUodG1wMSk7CiAgICAgICAgICAgICAgICBjb25zdCBlZGdlVmVjID0gcDEuc3VidHJhY3QocDApOwogICAgICAgICAgICAgICAgY29uc3QgZWRnZUluZGV4ID0gdGhpcy5lZGdlRmFjZXMubGVuZ3RoIC8gMjsKICAgICAgICAgICAgICAgIGNvbnN0IGVkZ2VEYXRhID0gewogICAgICAgICAgICAgICAgICAgIGVkZ2VJbmRleDogZWRnZUluZGV4LAogICAgICAgICAgICAgICAgICAgIGVkZ2VWZWM6IGVkZ2VWZWMsCiAgICAgICAgICAgICAgICB9OwogICAgICAgICAgICAgICAgY29ubmVjdGVkVmVydGljZXNba2V5XSA9IGVkZ2VEYXRhOwogICAgICAgICAgICAgICAgdGhpcy5lZGdlRmFjZXMucHVzaCgtMSk7CiAgICAgICAgICAgICAgICB0aGlzLmVkZ2VGYWNlcy5wdXNoKC0xKTsKICAgICAgICAgICAgICAgIHRoaXMuZWRnZVZlcnRzLnB1c2godG1wMCk7CiAgICAgICAgICAgICAgICB0aGlzLmVkZ2VWZXJ0cy5wdXNoKHRtcDEpOwogICAgICAgICAgICAgICAgLy8gY29uc29sZS5sb2coa2V5ICsgJzonICsgY29ubmVjdGVkVmVydGljZXNba2V5XSArICIgZmFjZToiICsgKCB2MCA8IHYxID8gMCA6IDEpKTsKICAgICAgICAgICAgICAgIHRoaXMubnVtRWRnZXMrKzsKICAgICAgICAgICAgICAgIHJldHVybiBlZGdlRGF0YTsKICAgICAgICAgICAgfTsKICAgICAgICAgICAgY29uc3QgYWRkRWRnZSA9ICh2MCwgdjEsIGZhY2VJbmRleCkgPT4gewogICAgICAgICAgICAgICAgLy8gY29uc29sZS5sb2coJ2FkZEVkZ2U6JyArIHYwICsgIiA6IiArIHYxICsgIiBmYWNlSW5kZXg6IiArIGZhY2VJbmRleCApOwogICAgICAgICAgICAgICAgY29uc3QgZWRnZURhdGEgPSBnZXRFZGdlSW5kZXgodjAsIHYxKTsKICAgICAgICAgICAgICAgIGNvbnN0IGVkZ2VJbmRleCA9IGVkZ2VEYXRhLmVkZ2VJbmRleDsKICAgICAgICAgICAgICAgIGlmICh2MSA8IHYwKSB7CiAgICAgICAgICAgICAgICAgICAgY29uc3QgZWRnZUZhY2VJbmRleCA9IGVkZ2VJbmRleCAqIDIgKyAwOwogICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLl9fbG9nVG9wb2xvZ3lXYXJuaW5ncyAmJiB0aGlzLmVkZ2VGYWNlc1tlZGdlRmFjZUluZGV4XSAhPSAtMSkKICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS53YXJuKCdFZGdlIHBvbHkgMCBhbHJlYWR5IHNldC4gTWVzaCBpcyBub24tbWFuaWZvbGQuJyk7CiAgICAgICAgICAgICAgICAgICAgdGhpcy5lZGdlRmFjZXNbZWRnZUZhY2VJbmRleF0gPSBmYWNlSW5kZXg7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgICAgICBjb25zdCBlZGdlRmFjZUluZGV4ID0gZWRnZUluZGV4ICogMiArIDE7CiAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMuX19sb2dUb3BvbG9neVdhcm5pbmdzICYmIHRoaXMuZWRnZUZhY2VzW2VkZ2VGYWNlSW5kZXhdICE9IC0xKQogICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oJ0VkZ2UgcG9seSAxIGFscmVhZHkgc2V0LiBNZXNoIGlzIG5vbi1tYW5pZm9sZC4nKTsKICAgICAgICAgICAgICAgICAgICB0aGlzLmVkZ2VGYWNlc1tlZGdlRmFjZUluZGV4XSA9IGZhY2VJbmRleDsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGlmICghKGZhY2VJbmRleCBpbiB0aGlzLmZhY2VFZGdlcykpCiAgICAgICAgICAgICAgICAgICAgdGhpcy5mYWNlRWRnZXNbZmFjZUluZGV4XSA9IFtdOwogICAgICAgICAgICAgICAgdGhpcy5mYWNlRWRnZXNbZmFjZUluZGV4XS5wdXNoKGVkZ2VJbmRleCk7CiAgICAgICAgICAgICAgICAvLyBQdXNoIHRoZSBlZGdlIGluZGV4IG9udG8gYm90aCB2ZXJ0ZXggZWRnZSBsaXN0cy4KICAgICAgICAgICAgICAgIC8vIFdlIHVzZSBTZXRzIHRvIGF2b2lkIGFkZGluZyB0aGUgc2FtZSBlZGdlIDJ4IHRvIHRoZSBzYW1lIHZlcnRleC4KICAgICAgICAgICAgICAgIGlmICh0aGlzLnZlcnRleEVkZ2VzW3YwXSA9PSB1bmRlZmluZWQpIHsKICAgICAgICAgICAgICAgICAgICB0aGlzLnZlcnRleEVkZ2VzW3YwXSA9IG5ldyBTZXQoKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGlmICh0aGlzLnZlcnRleEVkZ2VzW3YxXSA9PSB1bmRlZmluZWQpIHsKICAgICAgICAgICAgICAgICAgICB0aGlzLnZlcnRleEVkZ2VzW3YxXSA9IG5ldyBTZXQoKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIHRoaXMudmVydGV4RWRnZXNbdjBdLmFkZChlZGdlSW5kZXgpOwogICAgICAgICAgICAgICAgdGhpcy52ZXJ0ZXhFZGdlc1t2MV0uYWRkKGVkZ2VJbmRleCk7CiAgICAgICAgICAgICAgICAvLyBpZiAodGhpcy52ZXJ0ZXhGYWNlc1t2MF0gPT0gdW5kZWZpbmVkKSB7CiAgICAgICAgICAgICAgICAvLyAgICAgdGhpcy52ZXJ0ZXhGYWNlc1t2MF0gPSBbXTsKICAgICAgICAgICAgICAgIC8vIH0KICAgICAgICAgICAgICAgIC8vIHRoaXMudmVydGV4RmFjZXNbdjBdLnB1c2goZmFjZUluZGV4KTsKICAgICAgICAgICAgfTsKICAgICAgICAgICAgY29uc3QgbnVtRmFjZXMgPSB0aGlzLmdldE51bUZhY2VzKCk7CiAgICAgICAgICAgIGZvciAobGV0IGZhY2VJbmRleCA9IDA7IGZhY2VJbmRleCA8IG51bUZhY2VzOyBmYWNlSW5kZXgrKykgewogICAgICAgICAgICAgICAgY29uc3QgZmFjZVZlcnRzID0gdGhpcy5nZXRGYWNlVmVydGV4SW5kaWNlcyhmYWNlSW5kZXgpOwogICAgICAgICAgICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCBmYWNlVmVydHMubGVuZ3RoOyBqKyspIHsKICAgICAgICAgICAgICAgICAgICBjb25zdCB2MCA9IGZhY2VWZXJ0c1tqXTsKICAgICAgICAgICAgICAgICAgICBjb25zdCB2MSA9IGZhY2VWZXJ0c1soaiArIDEpICUgZmFjZVZlcnRzLmxlbmd0aF07CiAgICAgICAgICAgICAgICAgICAgYWRkRWRnZSh2MCwgdjEsIGZhY2VJbmRleCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgYSBub3JtYWwgdmFsdWUgcGVyIGZhY2UgYnkgYXZlcmFnaW5nIHRoZSB0cmlhbmdsZSBub3JtYWxzIG9mIHRoZSBmYWNlLgogICAgICAgICAqLwogICAgICAgIGNvbXB1dGVGYWNlTm9ybWFscygpIHsKICAgICAgICAgICAgY29uc3QgcG9zaXRpb25zID0gdGhpcy5wb3NpdGlvbnM7CiAgICAgICAgICAgIGNvbnN0IGZhY2VOb3JtYWxzID0gbmV3IFZlYzNmOEF0dHJpYnV0ZSgpOwogICAgICAgICAgICB0aGlzLmFkZEZhY2VBdHRyaWJ1dGUoJ25vcm1hbHMnLCBmYWNlTm9ybWFscyk7CiAgICAgICAgICAgIGNvbnN0IG51bUZhY2VzID0gdGhpcy5nZXROdW1GYWNlcygpOwogICAgICAgICAgICBmb3IgKGxldCBmYWNlSW5kZXggPSAwOyBmYWNlSW5kZXggPCBudW1GYWNlczsgZmFjZUluZGV4KyspIHsKICAgICAgICAgICAgICAgIGNvbnN0IGZhY2VWZXJ0cyA9IHRoaXMuZ2V0RmFjZVZlcnRleEluZGljZXMoZmFjZUluZGV4KTsKICAgICAgICAgICAgICAgIGNvbnN0IHAwID0gcG9zaXRpb25zLmdldFZhbHVlKGZhY2VWZXJ0c1swXSk7CiAgICAgICAgICAgICAgICBjb25zdCBwMSA9IHBvc2l0aW9ucy5nZXRWYWx1ZShmYWNlVmVydHNbMV0pOwogICAgICAgICAgICAgICAgbGV0IHByZXYgPSBwMTsKICAgICAgICAgICAgICAgIGNvbnN0IGZhY2VOb3JtYWwgPSBuZXcgVmVjMygpOwogICAgICAgICAgICAgICAgZm9yIChsZXQgaiA9IDI7IGogPCBmYWNlVmVydHMubGVuZ3RoOyBqKyspIHsKICAgICAgICAgICAgICAgICAgICBjb25zdCBwbiA9IHBvc2l0aW9ucy5nZXRWYWx1ZShmYWNlVmVydHNbal0pOwogICAgICAgICAgICAgICAgICAgIGNvbnN0IHYwID0gcHJldi5zdWJ0cmFjdChwMCk7CiAgICAgICAgICAgICAgICAgICAgY29uc3QgdjEgPSBwbi5zdWJ0cmFjdChwMCk7CiAgICAgICAgICAgICAgICAgICAgZmFjZU5vcm1hbC5hZGRJblBsYWNlKHYwLmNyb3NzKHYxKS5ub3JtYWxpemUoKSk7CiAgICAgICAgICAgICAgICAgICAgcHJldiA9IHBuOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgaWYgKGZhY2VOb3JtYWwubGVuZ3RoU3F1YXJlZCgpIDwgTnVtYmVyLkVQU0lMT04pIDsKICAgICAgICAgICAgICAgIGVsc2UgewogICAgICAgICAgICAgICAgICAgIGZhY2VOb3JtYWxzLnNldFZhbHVlKGZhY2VJbmRleCwgZmFjZU5vcm1hbC5ub3JtYWxpemUoKSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ2FsY3VsYXRlcyB0aGUgYW5nbGVzIGF0IGVhY2ggZWRnZSBiZXR3ZWVuIHRoZSBhZGpvaW5pbmcgZmFjZXMKICAgICAgICAgKi8KICAgICAgICBjYWxjdWxhdGVFZGdlQW5nbGVzKCkgewogICAgICAgICAgICBpZiAodGhpcy52ZXJ0ZXhFZGdlcy5sZW5ndGggPT0gMCkKICAgICAgICAgICAgICAgIHRoaXMuZ2VuVG9wb2xvZ3lJbmZvKCk7CiAgICAgICAgICAgIHRoaXMuY29tcHV0ZUZhY2VOb3JtYWxzKCk7CiAgICAgICAgICAgIGNvbnN0IHBvc2l0aW9ucyA9IHRoaXMucG9zaXRpb25zOwogICAgICAgICAgICBjb25zdCBmYWNlTm9ybWFscyA9IHRoaXMuZ2V0RmFjZUF0dHJpYnV0ZSgnbm9ybWFscycpOwogICAgICAgICAgICB0aGlzLmVkZ2VWZWNzID0gW107CiAgICAgICAgICAgIHRoaXMuZWRnZUFuZ2xlcyA9IG5ldyBGbG9hdDMyQXJyYXkodGhpcy5udW1FZGdlcyk7CiAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5lZGdlRmFjZXMubGVuZ3RoOyBpICs9IDIpIHsKICAgICAgICAgICAgICAgIGNvbnN0IHYwID0gdGhpcy5lZGdlVmVydHNbaV07CiAgICAgICAgICAgICAgICBjb25zdCB2MSA9IHRoaXMuZWRnZVZlcnRzW2kgKyAxXTsKICAgICAgICAgICAgICAgIGNvbnN0IGVkZ2VWZWMgPSBwb3NpdGlvbnMuZ2V0VmFsdWUodjEpLnN1YnRyYWN0KHBvc2l0aW9ucy5nZXRWYWx1ZSh2MCkpOwogICAgICAgICAgICAgICAgZWRnZVZlYy5ub3JtYWxpemVJblBsYWNlKCk7CiAgICAgICAgICAgICAgICB0aGlzLmVkZ2VWZWNzLnB1c2goZWRnZVZlYyk7CiAgICAgICAgICAgICAgICBjb25zdCBwMCA9IHRoaXMuZWRnZUZhY2VzW2ldOwogICAgICAgICAgICAgICAgY29uc3QgcDEgPSB0aGlzLmVkZ2VGYWNlc1tpICsgMV07CiAgICAgICAgICAgICAgICBpZiAocDAgPT0gLTEgfHwgcDEgPT0gLTEpIHsKICAgICAgICAgICAgICAgICAgICAvLyBGbGFnIHRoZSBlZGdlIGFzIGEgYm9yZGVyIGVkZ2UuLi4uCiAgICAgICAgICAgICAgICAgICAgdGhpcy5lZGdlQW5nbGVzW2kgLyAyXSA9IE1hdGguUEkgKiAyLjA7CiAgICAgICAgICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBjb25zdCBuMCA9IGZhY2VOb3JtYWxzLmdldFZhbHVlKHAwKTsKICAgICAgICAgICAgICAgIGNvbnN0IG4xID0gZmFjZU5vcm1hbHMuZ2V0VmFsdWUocDEpOwogICAgICAgICAgICAgICAgdGhpcy5lZGdlQW5nbGVzW2kgLyAyXSA9IG4wLmFuZ2xlVG8objEpOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGUgdmVydGV4IG5vcm1hbHMuCiAgICAgICAgICogQHBhcmFtIGhhcmRBbmdsZSAtIFRoZSBoYXJkQW5nbGUgdmFsdWUgaW4gcmFkaWFucy4KICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBjb21wdXRlVmVydGV4Tm9ybWFscyhoYXJkQW5nbGUgPSAxLjAgLyogcmFkaWFucyAqLykgewogICAgICAgICAgICB0aGlzLmNhbGN1bGF0ZUVkZ2VBbmdsZXMoKTsKICAgICAgICAgICAgY29uc3QgZmFjZU5vcm1hbHMgPSB0aGlzLmdldEZhY2VBdHRyaWJ1dGUoJ25vcm1hbHMnKTsKICAgICAgICAgICAgY29uc3Qgbm9ybWFsc0F0dHIgPSBuZXcgVmVjM2Y4QXR0cmlidXRlKCk7CiAgICAgICAgICAgIHRoaXMuYWRkVmVydGV4QXR0cmlidXRlKCdub3JtYWxzJywgbm9ybWFsc0F0dHIpOwogICAgICAgICAgICAvLyB0aGVzZSBtZXRob2RzIGFyZSBmYXN0ZXIgdmVyc2lvbnMgdGhhbiB1c2luZyB0aGUgbWV0aG9kcwogICAgICAgICAgICAvLyBwcm92aWRlZCBvbiB0aGUgYXR0cmlidXRlcy4gV2UgY2FjaGUgdmFsdWVzIGFuZCB1c2UgaGFyZCBjb2RlZCBjb25zdGFudHMuCiAgICAgICAgICAgIC8vIGNvbnN0IGZhY2VOb3JtYWxzQnVmZmVyID0gZmFjZU5vcm1hbHMuZGF0YS5idWZmZXIKICAgICAgICAgICAgY29uc3QgZ2V0RmFjZU5vcm1hbCA9IChpbmRleCkgPT4gewogICAgICAgICAgICAgICAgcmV0dXJuIGZhY2VOb3JtYWxzLmdldFZhbHVlKGluZGV4KTsKICAgICAgICAgICAgfTsKICAgICAgICAgICAgY29uc3Qgc2V0VmVydGV4Tm9ybWFsID0gKGluZGV4LCB2YWx1ZSkgPT4gewogICAgICAgICAgICAgICAgbm9ybWFsc0F0dHIuc2V0VmFsdWUoaW5kZXgsIHZhbHVlKTsKICAgICAgICAgICAgfTsKICAgICAgICAgICAgY29uc3QgZ2V0Q29ubmVjdGVkRWRnZVZlY3MgPSAoZmFjZUluZGV4LCB2ZXJ0ZXhJbmRleCkgPT4gewogICAgICAgICAgICAgICAgbGV0IGUwOwogICAgICAgICAgICAgICAgbGV0IGUxOwogICAgICAgICAgICAgICAgY29uc3QgZmFjZUVkZ2VzID0gdGhpcy5mYWNlRWRnZXNbZmFjZUluZGV4XTsKICAgICAgICAgICAgICAgIGZvciAoY29uc3QgZSBvZiBmYWNlRWRnZXMpIHsKICAgICAgICAgICAgICAgICAgICBpZiAodGhpcy5lZGdlVmVydHNbZSAqIDJdID09IHZlcnRleEluZGV4KSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGlmICghZTApCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlMCA9IHRoaXMuZWRnZVZlY3NbZV07CiAgICAgICAgICAgICAgICAgICAgICAgIGVsc2UKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGUxID0gdGhpcy5lZGdlVmVjc1tlXTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgZWxzZSBpZiAodGhpcy5lZGdlVmVydHNbZSAqIDIgKyAxXSA9PSB2ZXJ0ZXhJbmRleCkgewogICAgICAgICAgICAgICAgICAgICAgICBpZiAoIWUwKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgZTAgPSB0aGlzLmVkZ2VWZWNzW2VdOwogICAgICAgICAgICAgICAgICAgICAgICBlbHNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlMSA9IHRoaXMuZWRnZVZlY3NbZV07CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgcmV0dXJuIFtlMCwgZTFdOwogICAgICAgICAgICB9OwogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMudmVydGV4RWRnZXMubGVuZ3RoOyBpKyspIHsKICAgICAgICAgICAgICAgIC8vIElmIHRoaXMgZmFjZSBpbmRleGluZyBkb2Vzbid0IHN0YXJ0IGF0IDAsIHRoZW4gdGhlIHZlcnRleEVkZ2VzIGRvbid0IGVpdGhlci4KICAgICAgICAgICAgICAgIGlmICh0aGlzLnZlcnRleEVkZ2VzW2ldID09IHVuZGVmaW5lZCkKICAgICAgICAgICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgICAgICAgIGNvbnN0IGVkZ2VzID0gdGhpcy52ZXJ0ZXhFZGdlc1tpXTsKICAgICAgICAgICAgICAgIC8vIEdyb3VwcyBvZiBmYWNlcyBoYXZpbmcgYSBzbW9vdGggbm9ybWFsIGF0IHRoZSBjdXJyZW50IHZlcnRleC4KICAgICAgICAgICAgICAgIGNvbnN0IGZhY2VHcm91cHMgPSBbXTsKICAgICAgICAgICAgICAgIGNvbnN0IGFkZEZhY2VUb0dyb3VwID0gKGZhY2UpID0+IHsKICAgICAgICAgICAgICAgICAgICBsZXQgaW5Hcm91cCA9IGZhbHNlOwogICAgICAgICAgICAgICAgICAgIGZvciAoY29uc3QgZmFjZUdyb3VwIG9mIGZhY2VHcm91cHMpIHsKICAgICAgICAgICAgICAgICAgICAgICAgaW5Hcm91cCA9IGZhY2VHcm91cC5pbmNsdWRlcyhmYWNlKTsKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGluR3JvdXApCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgaWYgKCFpbkdyb3VwKQogICAgICAgICAgICAgICAgICAgICAgICBmYWNlR3JvdXBzLnB1c2goW2ZhY2VdKTsKICAgICAgICAgICAgICAgIH07CiAgICAgICAgICAgICAgICBmb3IgKGNvbnN0IGUgb2YgZWRnZXMpIHsKICAgICAgICAgICAgICAgICAgICBjb25zdCBmMCA9IHRoaXMuZWRnZUZhY2VzW2UgKiAyXTsKICAgICAgICAgICAgICAgICAgICBjb25zdCBmMSA9IHRoaXMuZWRnZUZhY2VzW2UgKiAyICsgMV07CiAgICAgICAgICAgICAgICAgICAgaWYgKGYwICE9IC0xICYmIGYxICE9IC0xICYmIHRoaXMuZWRnZUFuZ2xlc1tlXSA8IGhhcmRBbmdsZSkgewogICAgICAgICAgICAgICAgICAgICAgICAvLyBpZiAoZjAgIT0gLTEgJiYgZjEgPT0gLTEgJiYgdGhpcy5lZGdlQW5nbGVzW2VdIDwgaGFyZEFuZ2xlKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGxldCBmMGdyb3VwSW5kZXggPSAtMTsKICAgICAgICAgICAgICAgICAgICAgICAgbGV0IGYxZ3JvdXBJbmRleCA9IC0xOwogICAgICAgICAgICAgICAgICAgICAgICBmb3IgKGxldCBncm91cEluZGV4ID0gMDsgZ3JvdXBJbmRleCA8IGZhY2VHcm91cHMubGVuZ3RoOyBncm91cEluZGV4KyspIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChmMGdyb3VwSW5kZXggPT0gLTEgJiYgZmFjZUdyb3Vwc1tncm91cEluZGV4XS5pbmNsdWRlcyhmMCkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZjBncm91cEluZGV4ID0gZ3JvdXBJbmRleDsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChmMWdyb3VwSW5kZXggPT0gLTEgJiYgZmFjZUdyb3Vwc1tncm91cEluZGV4XS5pbmNsdWRlcyhmMSkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZjFncm91cEluZGV4ID0gZ3JvdXBJbmRleDsKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICBpZiAoZjBncm91cEluZGV4ID09IC0xICYmIGYxZ3JvdXBJbmRleCA9PSAtMSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFjZUdyb3Vwcy5wdXNoKFtmMCwgZjFdKTsKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICBlbHNlIGlmIChmMGdyb3VwSW5kZXggIT0gLTEgJiYgZjFncm91cEluZGV4ICE9IC0xKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoZjBncm91cEluZGV4ICE9IGYxZ3JvdXBJbmRleCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIE1lcmdlIHRoZSAyIGdyb3VwcyB0aGF0IHRoZSBzbW9vdGggZWRnZSBqb2lucy4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWNlR3JvdXBzW2YwZ3JvdXBJbmRleF0gPSBmYWNlR3JvdXBzW2YwZ3JvdXBJbmRleF0uY29uY2F0KGZhY2VHcm91cHNbZjFncm91cEluZGV4XSk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFjZUdyb3Vwcy5zcGxpY2UoZjFncm91cEluZGV4LCAxKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChmMGdyb3VwSW5kZXggPT0gLTEpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWNlR3JvdXBzW2YxZ3JvdXBJbmRleF0ucHVzaChmMCk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoZjFncm91cEluZGV4ID09IC0xKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFjZUdyb3Vwc1tmMGdyb3VwSW5kZXhdLnB1c2goZjEpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAvLyBUaGlzIGlzIGEgaGFyZCBlZGdlIG9yIGEgYm9yZGVyIGVkZ2UuLi4gQWRkIGZhY2VzIHNlcGFyYXRlbHkgZ3JvdXAuCiAgICAgICAgICAgICAgICAgICAgaWYgKGYwICE9IC0xKQogICAgICAgICAgICAgICAgICAgICAgICBhZGRGYWNlVG9Hcm91cChmMCk7CiAgICAgICAgICAgICAgICAgICAgaWYgKGYxICE9IC0xKQogICAgICAgICAgICAgICAgICAgICAgICBhZGRGYWNlVG9Hcm91cChmMSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAvLyBTb3J0IHRoZSBncm91cHMgdG8gaGF2ZSB0aGUgYmlnZ2VzdCBncm91cCBmaXJzdC4KICAgICAgICAgICAgICAgIGZhY2VHcm91cHMuc29ydCgoYSwgYikgPT4gKGEubGVuZ3RoIDwgYi5sZW5ndGggPyAxIDogYS5sZW5ndGggPiBiLmxlbmd0aCA/IC0xIDogMCkpOwogICAgICAgICAgICAgICAgbGV0IGZpcnN0VmVydGV4ID0gdHJ1ZTsKICAgICAgICAgICAgICAgIGZvciAoY29uc3QgZmFjZUdyb3VwIG9mIGZhY2VHcm91cHMpIHsKICAgICAgICAgICAgICAgICAgICBjb25zdCBub3JtYWwgPSBuZXcgVmVjMygpOwogICAgICAgICAgICAgICAgICAgIGZvciAoY29uc3QgZmFjZUluZGV4IG9mIGZhY2VHcm91cCkgewogICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBmYWNlRWRnZXMgPSBnZXRDb25uZWN0ZWRFZGdlVmVjcyhmYWNlSW5kZXgsIGkpOwogICAgICAgICAgICAgICAgICAgICAgICBsZXQgd2VpZ2h0OwogICAgICAgICAgICAgICAgICAgICAgICBpZiAoZmFjZUVkZ2VzWzBdICYmIGZhY2VFZGdlc1sxXSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgd2VpZ2h0ID0gZmFjZUVkZ2VzWzBdLmFuZ2xlVG8oZmFjZUVkZ2VzWzFdKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vcm1hbC5hZGRJblBsYWNlKGdldEZhY2VOb3JtYWwoZmFjZUluZGV4KS5zY2FsZSh3ZWlnaHQpKTsKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybigndmFyaWFibGUgd2VpZ2h0IGlzIHVuZGVmaW5lZCBiZWNhdXNlIGZhY2VFZGdlc1swXSBvciBmYWNlRWRnZXNbMV0gaXMgdW5kZWZpbmVkJyk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgLy8gaWYgKGkgPT0gMSkKICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgIGNvbnNvbGUubG9nKCJGYWNlTm9ybWFsOiIgKyBmYWNlSW5kZXggKyAiOiIgKyBnZXRGYWNlTm9ybWFsKGZhY2VJbmRleCkudG9TdHJpbmcoKSk7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIG5vcm1hbC5ub3JtYWxpemVJblBsYWNlKCk7CiAgICAgICAgICAgICAgICAgICAgaWYgKGZpcnN0VmVydGV4KSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHNldFZlcnRleE5vcm1hbChpLCBub3JtYWwpOwogICAgICAgICAgICAgICAgICAgICAgICBmaXJzdFZlcnRleCA9IGZhbHNlOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAgICAgbm9ybWFsc0F0dHIuc2V0U3BsaXRWZXJ0ZXhWYWx1ZXMoaSwgZmFjZUdyb3VwLCBub3JtYWwuYXNBcnJheSgpKTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIG5vcm1hbHNBdHRyOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgY29tcHV0ZUhhcmRFZGdlc0luZGljZXMgbWV0aG9kLgogICAgICAgICAqIEBwYXJhbSBoYXJkQW5nbGUgLSBUaGUgaGFyZEFuZ2xlIHZhbHVlIGluIHJhZGlhbnMuCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgY29tcHV0ZUhhcmRFZGdlc0luZGljZXMoaGFyZEFuZ2xlID0gMS4wKSB7CiAgICAgICAgICAgIGlmICh0aGlzLmVkZ2VWZXJ0cy5sZW5ndGggPT0gMCkKICAgICAgICAgICAgICAgIHRoaXMuY2FsY3VsYXRlRWRnZUFuZ2xlcygpOwogICAgICAgICAgICBjb25zdCBoYXJkRWRnZXMgPSBbXTsKICAgICAgICAgICAgY29uc3QgYWRkRWRnZSA9IChpbmRleCkgPT4gewogICAgICAgICAgICAgICAgaGFyZEVkZ2VzLnB1c2godGhpcy5lZGdlVmVydHNbaW5kZXhdKTsKICAgICAgICAgICAgICAgIGhhcmRFZGdlcy5wdXNoKHRoaXMuZWRnZVZlcnRzW2luZGV4ICsgMV0pOwogICAgICAgICAgICB9OwogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuZWRnZUFuZ2xlcy5sZW5ndGg7IGkrKykgewogICAgICAgICAgICAgICAgaWYgKHRoaXMuZWRnZUFuZ2xlc1tpXSA+IGhhcmRBbmdsZSkgewogICAgICAgICAgICAgICAgICAgIGFkZEVkZ2UoaSAqIDIpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBVaW50MzJBcnJheS5mcm9tKGhhcmRFZGdlcyk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIE1lcmdlcyBhIHNlcGFyYXRlIGdlb21ldHJ5IGludG8gdGhpcyBvbmUuIFNpbWlsYXIgdG8gYSAndW5pb24nIGJvb2xlYW4gb3BlcmF0aW9uLgogICAgICAgICAqIEBwYXJhbSBvdGhlciB0aGUgb3RoZXIgZ2VvbSB0aGF0IHdpbGwgYmUgbWVyZ2VkIGludG8gdGhpcyBvbmUKICAgICAgICAgKiBAcGFyYW0geGZvIHRoZSB0cmFuc2Zvcm1hdGlvbiB0byBiZSBhcHBsaWVkIHRvIHRoZSBvdGhlciBnZW9tIGFzIGl0IGlzIG1lcmdlZCBpbi4KICAgICAgICAgKi8KICAgICAgICBtZXJnZShvdGhlciwgeGZvID0gbmV3IFhmbygpKSB7CiAgICAgICAgICAgIGNvbnN0IHByZXZOdW1WZXJ0cyA9IHRoaXMuZ2V0TnVtVmVydGljZXMoKTsKICAgICAgICAgICAgc3VwZXIubWVyZ2Uob3RoZXIsIHhmbyk7CiAgICAgICAgICAgIGNvbnN0IG90aGVyRmFjZVZlcnRleEluZGljZXMgPSBvdGhlci5mYWNlVmVydGV4SW5kaWNlczsKICAgICAgICAgICAgY29uc3QgZmFjZVZlcnRleEluZGljZXMgPSBuZXcgVWludDMyQXJyYXkodGhpcy5mYWNlVmVydGV4SW5kaWNlcy5sZW5ndGggKyBvdGhlckZhY2VWZXJ0ZXhJbmRpY2VzLmxlbmd0aCk7CiAgICAgICAgICAgIGNvbnN0IG90aGVyRmFjZUNvdW50cyA9IG90aGVyLmdldEZhY2VDb3VudHMoKTsKICAgICAgICAgICAgbGV0IGluZGV4T2Zmc2V0ID0gMDsKICAgICAgICAgICAgbGV0IG90aGVySW5kZXhPZmZzZXQgPSAwOwogICAgICAgICAgICBsZXQgbWVyZ2VkSW5kZXhPZmZzZXQgPSAwOwogICAgICAgICAgICBjb25zdCBudW1Db3VudHMgPSBNYXRoLm1heCh0aGlzLmZhY2VDb3VudHMubGVuZ3RoLCBvdGhlckZhY2VDb3VudHMubGVuZ3RoKTsKICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBudW1Db3VudHM7IGkrKykgewogICAgICAgICAgICAgICAgaWYgKHRoaXMuZmFjZUNvdW50cy5sZW5ndGggPiBpKSB7CiAgICAgICAgICAgICAgICAgICAgLy8gQWRkICd0aGlzJyBpbmRpY2VzCiAgICAgICAgICAgICAgICAgICAgY29uc3QgbnVtSW5kaWNlc1RoaXMgPSB0aGlzLmZhY2VDb3VudHNbaV0gKiAoaSArIDMpOwogICAgICAgICAgICAgICAgICAgIGZhY2VWZXJ0ZXhJbmRpY2VzLnNldCh0aGlzLmZhY2VWZXJ0ZXhJbmRpY2VzLnNsaWNlKGluZGV4T2Zmc2V0LCBpbmRleE9mZnNldCArIG51bUluZGljZXNUaGlzKSwgbWVyZ2VkSW5kZXhPZmZzZXQpOwogICAgICAgICAgICAgICAgICAgIGluZGV4T2Zmc2V0ICs9IG51bUluZGljZXNUaGlzOwogICAgICAgICAgICAgICAgICAgIG1lcmdlZEluZGV4T2Zmc2V0ICs9IG51bUluZGljZXNUaGlzOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgaWYgKG90aGVyRmFjZUNvdW50cy5sZW5ndGggPiBpKSB7CiAgICAgICAgICAgICAgICAgICAgLy8gQWRkIHRoZSAnb3RoZXInIGluZGljZXMKICAgICAgICAgICAgICAgICAgICBjb25zdCBudW1JbmRpY2VzT3RoZXIgPSBvdGhlckZhY2VDb3VudHNbaV0gKiAoaSArIDMpOwogICAgICAgICAgICAgICAgICAgIGZhY2VWZXJ0ZXhJbmRpY2VzLnNldChvdGhlckZhY2VWZXJ0ZXhJbmRpY2VzCiAgICAgICAgICAgICAgICAgICAgICAgIC5zbGljZShvdGhlckluZGV4T2Zmc2V0LCBvdGhlckluZGV4T2Zmc2V0ICsgbnVtSW5kaWNlc090aGVyKQogICAgICAgICAgICAgICAgICAgICAgICAubWFwKChpbmRleCkgPT4gaW5kZXggKyBwcmV2TnVtVmVydHMpLCBtZXJnZWRJbmRleE9mZnNldCk7CiAgICAgICAgICAgICAgICAgICAgb3RoZXJJbmRleE9mZnNldCArPSBudW1JbmRpY2VzT3RoZXI7CiAgICAgICAgICAgICAgICAgICAgbWVyZ2VkSW5kZXhPZmZzZXQgKz0gbnVtSW5kaWNlc090aGVyOwogICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLmZhY2VDb3VudHMubGVuZ3RoID09IGkpCiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZmFjZUNvdW50c1tpXSA9IDA7CiAgICAgICAgICAgICAgICAgICAgdGhpcy5mYWNlQ291bnRzW2ldICs9IG90aGVyRmFjZUNvdW50c1tpXTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICB0aGlzLmZhY2VWZXJ0ZXhJbmRpY2VzID0gZmFjZVZlcnRleEluZGljZXM7CiAgICAgICAgICAgIC8vIE5vdGU6IHRoZSBtZXJnZSBkb2VzIG5vdCBjb3JyZWN0bHkgbWVyZ2Ugc3BsaXQgdmFsdWVzLCBhcyBpdCBpcyBxdWl0ZSBjb21wbGV4CiAgICAgICAgICAgIC8vIGFuZCB3ZSBkb24ndCBoYXZlIHRpbWUgbm93LiBXZSBjYW4gY29tZSBiYWNrIHRvIHRoaXMsIGJ1dCB0aGUgc3BsaXRzIHN5c3RlbSBpcyBvdmVybHkgY29tcGxleAogICAgICAgICAgICAvLyBhbmQgd2UgY2FuIHByb2JhYmx5IHJlLXdyaXRlLgogICAgICAgICAgICAvLyBmb3IgKGNvbnN0IFthdHRyTmFtZSwgYXR0cl0gb2YgdGhpcy5fX3ZlcnRleEF0dHJpYnV0ZXMpIHsKICAgICAgICAgICAgLy8gICBjb25zdCBvdGhlckF0dHIgPSBvdGhlci5nZXRWZXJ0ZXhBdHRyaWJ1dGUoYXR0ck5hbWUpCiAgICAgICAgICAgIC8vICAgaWYgKG90aGVyQXR0cikgewogICAgICAgICAgICAvLyAgICAgY29uc3QgdGhpc1NwbGl0cyA9IGF0dHIuZ2V0U3BsaXRzKCkKICAgICAgICAgICAgLy8gICAgIGNvbnN0IG90aGVyU3BsaXRzID0gb3RoZXJBdHRyLmdldFNwbGl0cygpCiAgICAgICAgICAgIC8vICAgICAvLyBmb3IgKGxldCBrZXkgaW4gb3RoZXJTcGxpdHMpIHsKICAgICAgICAgICAgLy8gICAgIC8vICAgdGhpc1NwbGl0c1trZXldID0gb3RoZXJTcGxpdHNba2V5XQogICAgICAgICAgICAvLyAgICAgLy8gfQogICAgICAgICAgICAvLyAgIH0KICAgICAgICAgICAgLy8gfQogICAgICAgIH0KICAgICAgICAvLyAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCiAgICAgICAgLy8gUmVuZGVyaW5nCiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGdlbkJ1ZmZlcnMgbWV0aG9kLgogICAgICAgICAqIEBwYXJhbSBvcHRzIC0gVGhlIG9wdHMgdmFsdWUuCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgZ2VuQnVmZmVycyhvcHRzKSB7CiAgICAgICAgICAgIC8vIENvbXB1dGUgdGhlIG5vcm1hbHMgb24gZGVtYW5kLgogICAgICAgICAgICAvLyBpZiAoISgnbm9ybWFscycgaW4gdGhpcy5fX3ZlcnRleEF0dHJpYnV0ZXMpKSB7CiAgICAgICAgICAgIC8vICAgICAvLyB0aGlzLmdlb20uY29tcHV0ZVZlcnRleE5vcm1hbHMoKTsKICAgICAgICAgICAgLy8gICAgIHRoaXMuYWRkVmVydGV4QXR0cmlidXRlKCJub3JtYWxzIiwgVmVjMywgMC4wKTsKICAgICAgICAgICAgLy8gfQogICAgICAgICAgICBjb25zdCBzcGxpdEluZGljZXMgPSB7fTsKICAgICAgICAgICAgbGV0IHNwbGl0Q291bnQgPSAwOwogICAgICAgICAgICBmb3IgKGNvbnN0IFssIGF0dHJdIG9mIHRoaXMuX192ZXJ0ZXhBdHRyaWJ1dGVzKSB7CiAgICAgICAgICAgICAgICBjb25zdCBhdHRyU3BsaXRzID0gYXR0ci5nZXRTcGxpdHMoKTsKICAgICAgICAgICAgICAgIGZvciAoY29uc3QgcG9seWdvbiBpbiBhdHRyU3BsaXRzKSB7CiAgICAgICAgICAgICAgICAgICAgaWYgKCEocG9seWdvbiBpbiBzcGxpdEluZGljZXMpKQogICAgICAgICAgICAgICAgICAgICAgICBzcGxpdEluZGljZXNbcG9seWdvbl0gPSB7fTsKICAgICAgICAgICAgICAgICAgICBjb25zdCB2ZXJ0aWNlcyA9IGF0dHJTcGxpdHNbcG9seWdvbl07CiAgICAgICAgICAgICAgICAgICAgZm9yIChjb25zdCB2IGluIHZlcnRpY2VzKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHZlcnRleCA9IHBhcnNlSW50KHYpOwogICAgICAgICAgICAgICAgICAgICAgICBpZiAoISh2ZXJ0ZXggaW4gc3BsaXRJbmRpY2VzW3BvbHlnb25dKSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgc3BsaXRJbmRpY2VzW3BvbHlnb25dW3ZlcnRleF0gPSBzcGxpdENvdW50OwogICAgICAgICAgICAgICAgICAgICAgICAgICAgc3BsaXRDb3VudCsrOwogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIGNvbnN0IHBvc2l0aW9ucyA9IHRoaXMucG9zaXRpb25zOwogICAgICAgICAgICBjb25zdCBudW1VblNwbGl0VmVydGljZXMgPSBwb3NpdGlvbnMuZ2V0Q291bnQoKTsKICAgICAgICAgICAgY29uc3QgdG90YWxOdW1WZXJ0aWNlcyA9IG51bVVuU3BsaXRWZXJ0aWNlcyArIHNwbGl0Q291bnQ7CiAgICAgICAgICAgIGxldCBpbmRpY2VzOwogICAgICAgICAgICBpZiAoIW9wdHMgfHwgb3B0cy5pbmNsdWRlSW5kaWNlcyAhPSBmYWxzZSkgewogICAgICAgICAgICAgICAgaW5kaWNlcyA9IHRoaXMuZ2VuZXJhdGVUcmlhbmd1bGF0ZWRJbmRpY2VzKHRvdGFsTnVtVmVydGljZXMsIG51bVVuU3BsaXRWZXJ0aWNlcywgc3BsaXRJbmRpY2VzKTsKICAgICAgICAgICAgfQogICAgICAgICAgICAvLyBsZXQgbWF4SW5kZXg7CiAgICAgICAgICAgIC8vIGlmIChkZWJ1Z0F0dHJWYWx1ZXMpCiAgICAgICAgICAgIC8vICAgICBtYXhJbmRleCA9IE1hdGgubWF4KC4uLmluZGljZXMpOwogICAgICAgICAgICBjb25zdCBhdHRyQnVmZmVycyA9IHt9OwogICAgICAgICAgICBmb3IgKGNvbnN0IFthdHRyTmFtZSwgYXR0cl0gb2YgdGhpcy5fX3ZlcnRleEF0dHJpYnV0ZXMpIHsKICAgICAgICAgICAgICAgIGxldCB2YWx1ZXM7CiAgICAgICAgICAgICAgICBpZiAoc3BsaXRDb3VudCA9PSAwKQogICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGF0dHIuYXNBcnJheSgpOwogICAgICAgICAgICAgICAgZWxzZQogICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGF0dHIuZ2VuZXJhdGVTcGxpdFZhbHVlcyhzcGxpdEluZGljZXMsIHNwbGl0Q291bnQpOwogICAgICAgICAgICAgICAgY29uc3QgZGltZW5zaW9uID0gYXR0ci5zdHJpZGU7CiAgICAgICAgICAgICAgICBjb25zdCBjb3VudCA9IHZhbHVlcy5sZW5ndGggLyBkaW1lbnNpb247CiAgICAgICAgICAgICAgICAvLyBpZiAoZGVidWdBdHRyVmFsdWVzKSB7CiAgICAgICAgICAgICAgICAvLyAgICAgaWYgKGNvdW50IDw9IG1heEluZGV4KQogICAgICAgICAgICAgICAgLy8gICAgICAgICBjb25zb2xlLndhcm4oIkludmFsaWQgaW5kZXhpbmcuIEF0dHIgdmFsdWUgaXMgaW5zdWZmaWNpZW50IGZvciBpbmRleGluZzoiICsgYXR0ck5hbWUgKyAiLiBNYXggSW5kZXg6IiArIG1heEluZGV4ICsgIiBBdHRyIFNpemU6IiArIGNvdW50KTsKICAgICAgICAgICAgICAgIC8vIH0KICAgICAgICAgICAgICAgIGF0dHJCdWZmZXJzW2F0dHJOYW1lXSA9IHsKICAgICAgICAgICAgICAgICAgICB2YWx1ZXM6IHZhbHVlcywKICAgICAgICAgICAgICAgICAgICBjb3VudDogY291bnQsCiAgICAgICAgICAgICAgICAgICAgZGltZW5zaW9uOiBkaW1lbnNpb24sCiAgICAgICAgICAgICAgICAgICAgbm9ybWFsaXplZDogYXR0ck5hbWUgPT0gJ25vcm1hbHMnLAogICAgICAgICAgICAgICAgICAgIGRhdGFUeXBlOiBhdHRyLmdldERhdGFUeXBlTmFtZSgpLAogICAgICAgICAgICAgICAgfTsKICAgICAgICAgICAgfQogICAgICAgICAgICBjb25zdCByZXN1bHQgPSB7CiAgICAgICAgICAgICAgICBudW1WZXJ0aWNlczogdGhpcy5udW1WZXJ0aWNlcygpLAogICAgICAgICAgICAgICAgbnVtUmVuZGVyVmVydHM6IHRvdGFsTnVtVmVydGljZXMsCiAgICAgICAgICAgICAgICBpbmRpY2VzLAogICAgICAgICAgICAgICAgYXR0ckJ1ZmZlcnMsCiAgICAgICAgICAgIH07CiAgICAgICAgICAgIC8qIERpc2FibGVkIGR1cmluZyBUUyBtaWdyYXRpb24uCiAgICAgICAgICAgIGlmIChvcHRzICYmIG9wdHMuaW5jbHVkZVZlcnRleE5laWdoYm9ycykgewogICAgICAgICAgICAgIGlmICh0aGlzLnZlcnRleEVkZ2VzID09IHVuZGVmaW5lZCkgdGhpcy5nZW5Ub3BvbG9neUluZm8oKQogICAgICAgIAogICAgICAgICAgICAgIGxldCBjb3VudCA9IDAKICAgICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMudmVydGV4RWRnZXMubGVuZ3RoOyBpKyspIHsKICAgICAgICAgICAgICAgIC8vIElmIHRoaXMgZmFjZSBpbmRleGluZyBkb2Vzbid0IHN0YXJ0IGF0IDAsIHRoZW4gdGhlIHZlcnRleEVkZ2VzIGRvbid0IGVpdGhlci4KICAgICAgICAgICAgICAgIGlmICh0aGlzLnZlcnRleEVkZ2VzW2ldKSBjb3VudCArPSB0aGlzLnZlcnRleEVkZ2VzW2ldLnNpemUKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgLy8gVGhlIGFycmF5IHdpbGwgYmUgc3RydWN0dXJlZCBhcyBhIHN0YXJ0K29mZnNldCBmb3IgZWFjaCB2ZXJ0ZXgsIGZvbGxvd2VkCiAgICAgICAgICAgICAgLy8gYnkgYSAyZCBhcnJheSBvZiBuZWlnaGJvciBpbmRpY2VzLgogICAgICAgICAgICAgIGNvbnN0IHZlcnRleE5laWdoYm9ycyA9IG5ldyBVaW50MzJBcnJheSh0aGlzLnZlcnRleEVkZ2VzLmxlbmd0aCAqIDIgKyBjb3VudCkKICAgICAgICAgICAgICBjb25zdCBzb3J0RmFuRWRnZXMgPSAoZmFuRWRnZXM6IGFueSkgPT4gewogICAgICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBmYW5FZGdlcy5sZW5ndGg7IGkrKykgewogICAgICAgICAgICAgICAgICBjb25zdCBmZUEgPSBmYW5FZGdlc1tpXQogICAgICAgICAgICAgICAgICBmb3IgKGxldCBqID0gMDsgaiA8IGk7IGorKykgewogICAgICAgICAgICAgICAgICAgIGNvbnN0IGZlQiA9IGZhbkVkZ2VzW2pdCiAgICAgICAgICAgICAgICAgICAgaWYgKGZlQVswXSAhPSAtMSAmJiBmZUFbMF0gPT0gZmVCWzFdKSB7CiAgICAgICAgICAgICAgICAgICAgICAvLyAgbW92ZSBmZUEgYWZ0ZXIgZmVCOwogICAgICAgICAgICAgICAgICAgICAgaWYgKGkgIT0gaiArIDEpIHsKICAgICAgICAgICAgICAgICAgICAgICAgZmFuRWRnZXMuc3BsaWNlKGksIDEpCiAgICAgICAgICAgICAgICAgICAgICAgIGZhbkVkZ2VzLnNwbGljZShqICsgMSwgMCwgZmVBKQogICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgYnJlYWsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgaWYgKGZlQVsxXSAhPSAtMSAmJiBmZUFbMV0gPT0gZmVCWzBdKSB7CiAgICAgICAgICAgICAgICAgICAgICAvLyAgbW92ZSBmZUEgYmVmb3JlIGZlQjsKICAgICAgICAgICAgICAgICAgICAgIGZhbkVkZ2VzLnNwbGljZShpLCAxKQogICAgICAgICAgICAgICAgICAgICAgZmFuRWRnZXMuc3BsaWNlKGosIDAsIGZlQSkKICAgICAgICAgICAgICAgICAgICAgIGJyZWFrCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGNvbnN0IGNoZWNrRmFuRWRnZXMgPSAoZmFuRWRnZXM6IGFueSkgPT4gewogICAgICAgICAgICAgICAgLy8gbm93IGNoZWNrIHRoYXQgdGhlIGZhY2VzIGFsbCBidWlsZCBhIGZhbi4gTWF5YmUgc3RhcnRpbmcgYW5kIGVuZGluZyB3aXRoIC0xCiAgICAgICAgICAgICAgICBpZiAoZmFuRWRnZXNbMF1bMF0gPT0gLTEgfHwgZmFuRWRnZXNbZmFuRWRnZXMubGVuZ3RoIC0gMV1bMV0gPT0gLTEpIHsKICAgICAgICAgICAgICAgICAgaWYgKGZhbkVkZ2VzWzBdWzBdICE9IC0xIHx8IGZhbkVkZ2VzW2ZhbkVkZ2VzLmxlbmd0aCAtIDFdWzFdICE9IC0xKSB7CiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJZiBmYW4gc3RhcnRzIHdpdGggLTEsIGl0IG11c3QgYWxzbyBlbmQgd2l0aCAtMScpCiAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgZmFuRWRnZXMubGVuZ3RoOyBpKyspIHsKICAgICAgICAgICAgICAgICAgY29uc3QgZmUgPSBmYW5FZGdlc1tpXQogICAgICAgICAgICAgICAgICBpZiAoZmVbMF0gPT0gLTEgfHwgZmVbMV0gPT0gLTEpIHsKICAgICAgICAgICAgICAgICAgICBpZiAoaSAhPSAwICYmIGkgIT0gZmFuRWRnZXMubGVuZ3RoIC0gMSkgewogICAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCctMSBvbmx5IGFsbG93ZWQgYXQgdGhlIGJlZ2lubmluZyBhbmQgZW5kIG9mIGEgZmFuLicpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgIGlmIChmZVswXSAhPSAtMSkgewogICAgICAgICAgICAgICAgICAgIGxldCBwcmV2ID0gaSAtIDEKICAgICAgICAgICAgICAgICAgICBpZiAocHJldiA8IDApIHByZXYgKz0gZmFuRWRnZXMubGVuZ3RoCiAgICAgICAgICAgICAgICAgICAgaWYgKGZlWzBdICE9IGZhbkVkZ2VzW3ByZXZdWzFdKSB7CiAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ZhY2VzIGFyZSBub3Qgc2VxdWVudGlhbCcpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgIGlmIChmZVsxXSAhPSAtMSkgewogICAgICAgICAgICAgICAgICAgIGNvbnN0IG5leHQgPSAoaSArIDEpICUgZmFuRWRnZXMubGVuZ3RoCiAgICAgICAgICAgICAgICAgICAgaWYgKGZlWzFdICE9IGZhbkVkZ2VzW25leHRdWzBdKSB7CiAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ZhY2VzIGFyZSBub3Qgc2VxdWVudGlhbCcpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgfQogICAgICAgIAogICAgICAgICAgICAgIC8vIFBvcHVsYXRlIHRoZSBzdGFydCBhbmQgb2Zmc2V0IHZhbHVlcy4KICAgICAgICAgICAgICBsZXQgb2Zmc2V0ID0gdGhpcy52ZXJ0ZXhFZGdlcy5sZW5ndGggKiAyCiAgICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLnZlcnRleEVkZ2VzLmxlbmd0aDsgaSsrKSB7CiAgICAgICAgICAgICAgICBpZiAodGhpcy52ZXJ0ZXhFZGdlc1tpXSA9PSB1bmRlZmluZWQpIGNvbnRpbnVlCiAgICAgICAgICAgICAgICBjb25zdCBlZGdlcyA9IHRoaXMudmVydGV4RWRnZXNbaV0KICAgICAgICAKICAgICAgICAgICAgICAgIC8vIEJ1aWxkIGEgc29ydGVkIGxpc3Qgb2YgZmFjZXMgYmFzZWQgb24gYSBmYW4gYXJvdW5kCiAgICAgICAgICAgICAgICAvLyB0aGUgdmVydGV4LgogICAgICAgICAgICAgICAgY29uc3QgZmFuRWRnZXMgPSBbXQogICAgICAgICAgICAgICAgZm9yIChjb25zdCBlIG9mIGVkZ2VzKSB7CiAgICAgICAgICAgICAgICAgIGNvbnN0IHYwID0gdGhpcy5lZGdlVmVydHNbZSAqIDJdCiAgICAgICAgICAgICAgICAgIGNvbnN0IHYxID0gdGhpcy5lZGdlVmVydHNbZSAqIDIgKyAxXQogICAgICAgICAgICAgICAgICBsZXQgZjAgPSB0aGlzLmVkZ2VGYWNlc1tlICogMl0KICAgICAgICAgICAgICAgICAgbGV0IGYxID0gdGhpcy5lZGdlRmFjZXNbZSAqIDIgKyAxXQogICAgICAgICAgICAgICAgICBsZXQgbmVpZ1ZlcnQKICAgICAgICAgICAgICAgICAgaWYgKHYwID09IGkpIHsKICAgICAgICAgICAgICAgICAgICBuZWlnVmVydCA9IHYxCiAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAodjEgPT0gaSkgewogICAgICAgICAgICAgICAgICAgIG5laWdWZXJ0ID0gdjAKICAgICAgICAgICAgICAgICAgICAvLyBzd2FwIHRoZSBmYWNlcwogICAgICAgICAgICAgICAgICAgIGNvbnN0IHRtcCA9IGYwCiAgICAgICAgICAgICAgICAgICAgZjAgPSBmMQogICAgICAgICAgICAgICAgICAgIGYxID0gdG1wCiAgICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIHRvcG9sb2d5JykKICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICBmYW5FZGdlcy5wdXNoKFtmMCwgZjEsIG5laWdWZXJ0XSkKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIHNvcnRGYW5FZGdlcyhmYW5FZGdlcykKICAgICAgICAgICAgICAgIGNoZWNrRmFuRWRnZXMoZmFuRWRnZXMpCiAgICAgICAgICAgICAgICBjb25zdCBjbG9zZWQgPSBmYW5FZGdlc1swXVswXSAhPSAtMSB8fCBmYW5FZGdlc1tmYW5FZGdlcy5sZW5ndGggLSAxXVsxXSAhPSAtMQogICAgICAgICAgICAgICAgbGV0IGZsYWdzID0gMAogICAgICAgICAgICAgICAgaWYgKGNsb3NlZCkgZmxhZ3MgKz0gMQogICAgICAgICAgICAgICAgdmVydGV4TmVpZ2hib3JzW2kgKiAyXSA9IG9mZnNldAogICAgICAgICAgICAgICAgdmVydGV4TmVpZ2hib3JzW2kgKiAyICsgMV0gPSBlZGdlcy5zaXplICsgKGZsYWdzIDw8IDgpCiAgICAgICAgICAgICAgICBmb3IgKGNvbnN0IGZlIG9mIGZhbkVkZ2VzKSB7CiAgICAgICAgICAgICAgICAgIHZlcnRleE5laWdoYm9yc1tvZmZzZXRdID0gZmVbMl0KICAgICAgICAgICAgICAgICAgb2Zmc2V0KysKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgOyhyZXN1bHQgYXMgYW55KS52ZXJ0ZXhOZWlnaGJvcnMgPSB2ZXJ0ZXhOZWlnaGJvcnMKICAgICAgICAgICAgfQogICAgICAgICAgICAqLwogICAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlIHRoZSBudW1iZXIgb2YgdHJpYW5nbGVzLiBGb3IgaGlnaGVyIGRlZ3JlZSBwb2x5Z29ucywgdGhleSBhcmUgZGl2aWRlZCBpbnRvIG11bHRpcGxlIHRyaWFuZ2xlcyBmb3IgcmVuZGVyaW5nLgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIHRoZSBudW1iZXIgb2YgdHJpYW5nbGVzLgogICAgICAgICAqLwogICAgICAgIGNvbXB1dGVOdW1UcmlhbmdsZXMoKSB7CiAgICAgICAgICAgIGxldCBudW1WZXJ0c1BlckZhY2UgPSAzOwogICAgICAgICAgICBsZXQgdHJpc0NvdW50ID0gMDsKICAgICAgICAgICAgZm9yIChjb25zdCBmYyBvZiB0aGlzLmZhY2VDb3VudHMpIHsKICAgICAgICAgICAgICAgIHRyaXNDb3VudCArPSBmYyAqIChudW1WZXJ0c1BlckZhY2UgLSAyKTsKICAgICAgICAgICAgICAgIG51bVZlcnRzUGVyRmFjZSsrOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiB0cmlzQ291bnQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRvIHByZXBhcmUgZGF0YSBmb3IgcmVuZGVyaW5nLCB0aGUgaW5kaWNlcyBmb3IgdGhlIHBvbHlnb25zIGlzIHVzZWQgdG8gY29tcHV0ZSBhIG5ldyBpbmRleCBidWZmZXIgYmFzZWQgb24KICAgICAgICAgKiBvbmx5IHRyaWFuZ2xlcy4gVGhpcyBpcyB1c2VkIGR1cmluZyByZW5kZXJpbmcgYW5kIHRoZSByZXN1bHRpbmcgaW5kaWNlcyB1cGxvYWRlZCBvdCB0aGUgR1BVICBieSBHTE1lc2ggY2xhc3MuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gdG90YWxOdW1WZXJ0aWNlcyAtIFRoZSB0b3RhbCBudW1iZXIgb2YgdmVydGljZXMuCiAgICAgICAgICogQHBhcmFtIG51bVVuU3BsaXRWZXJ0aWNlcyAtIFRoZSB0b3RhbCBudW1iZXIgb2YgdW4tc3BsaXQgdmVydGljZXMuCiAgICAgICAgICogQHBhcmFtIHNwbGl0SW5kaWNlcyAtIFRoZSBzcGxpdEluZGljZXMgdmFsdWUuCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgYSB0eXBlZCBhcnJheSBjb250YWluaW5nIHRoZSB0cmlhbmd1bGF0ZWQgaW5kaWNlcy4KICAgICAgICAgKi8KICAgICAgICBnZW5lcmF0ZVRyaWFuZ3VsYXRlZEluZGljZXModG90YWxOdW1WZXJ0aWNlcywgbnVtVW5TcGxpdFZlcnRpY2VzLCBzcGxpdEluZGljZXMpIHsKICAgICAgICAgICAgY29uc3QgdHJpc0NvdW50ID0gdGhpcy5jb21wdXRlTnVtVHJpYW5nbGVzKCk7CiAgICAgICAgICAgIGxldCB0cmlhbmd1bGF0ZWRJbmRpY2VzOwogICAgICAgICAgICBpZiAodG90YWxOdW1WZXJ0aWNlcyA8IE1hdGgucG93KDIsIDgpKQogICAgICAgICAgICAgICAgdHJpYW5ndWxhdGVkSW5kaWNlcyA9IG5ldyBVaW50OEFycmF5KHRyaXNDb3VudCAqIDMpOwogICAgICAgICAgICBlbHNlIGlmICh0b3RhbE51bVZlcnRpY2VzIDwgTWF0aC5wb3coMiwgMTYpKQogICAgICAgICAgICAgICAgdHJpYW5ndWxhdGVkSW5kaWNlcyA9IG5ldyBVaW50MTZBcnJheSh0cmlzQ291bnQgKiAzKTsKICAgICAgICAgICAgZWxzZQogICAgICAgICAgICAgICAgdHJpYW5ndWxhdGVkSW5kaWNlcyA9IG5ldyBVaW50MzJBcnJheSh0cmlzQ291bnQgKiAzKTsKICAgICAgICAgICAgbGV0IHRyaWFuZ2xlVmVydGV4ID0gMDsKICAgICAgICAgICAgY29uc3QgYWRkVHJpYW5nbGVWZXJ0ZXhJbmRleCA9IGZ1bmN0aW9uICh2ZXJ0ZXgsIGZhY2VJbmRleCkgewogICAgICAgICAgICAgICAgaWYgKHZlcnRleCBpbiBzcGxpdEluZGljZXMgJiYgZmFjZUluZGV4IGluIHNwbGl0SW5kaWNlc1t2ZXJ0ZXhdKQogICAgICAgICAgICAgICAgICAgIHZlcnRleCA9IG51bVVuU3BsaXRWZXJ0aWNlcyArIHNwbGl0SW5kaWNlc1t2ZXJ0ZXhdW2ZhY2VJbmRleF07CiAgICAgICAgICAgICAgICB0cmlhbmd1bGF0ZWRJbmRpY2VzW3RyaWFuZ2xlVmVydGV4XSA9IHZlcnRleDsKICAgICAgICAgICAgICAgIHRyaWFuZ2xlVmVydGV4Kys7CiAgICAgICAgICAgIH07CiAgICAgICAgICAgIGNvbnN0IG51bUZhY2VzID0gdGhpcy5nZXROdW1GYWNlcygpOwogICAgICAgICAgICBmb3IgKGxldCBmYWNlSW5kZXggPSAwOyBmYWNlSW5kZXggPCBudW1GYWNlczsgZmFjZUluZGV4KyspIHsKICAgICAgICAgICAgICAgIGNvbnN0IGZhY2VWZXJ0cyA9IHRoaXMuZ2V0RmFjZVZlcnRleEluZGljZXMoZmFjZUluZGV4KTsKICAgICAgICAgICAgICAgIGZvciAobGV0IGogPSAwOyBqIDwgZmFjZVZlcnRzLmxlbmd0aDsgaisrKSB7CiAgICAgICAgICAgICAgICAgICAgaWYgKGogPj0gMykgewogICAgICAgICAgICAgICAgICAgICAgICAvLyBGb3IgZWFjaCBhZGRpdGlvbmFsIHRyaWFuZ2xlLCB3ZSBoYXZlIHRvIGFkZCAyIGluZGljZXMuCiAgICAgICAgICAgICAgICAgICAgICAgIGFkZFRyaWFuZ2xlVmVydGV4SW5kZXgoZmFjZVZlcnRzWzBdLCBmYWNlSW5kZXgpOwogICAgICAgICAgICAgICAgICAgICAgICBhZGRUcmlhbmdsZVZlcnRleEluZGV4KGZhY2VWZXJ0c1tqIC0gMV0sIGZhY2VJbmRleCk7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIGFkZFRyaWFuZ2xlVmVydGV4SW5kZXgoZmFjZVZlcnRzW2pdLCBmYWNlSW5kZXgpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiB0cmlhbmd1bGF0ZWRJbmRpY2VzOwogICAgICAgIH0KICAgICAgICAvLyAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCiAgICAgICAgLy8gUGVyc2lzdGVuY2UKICAgICAgICAvKioKICAgICAgICAgKiBSZXN0b3JlcyBtZXNoIHByb3BlcnRpZXMgZnJvbSBhIGJpbmFyeSByZWFkZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gcmVhZGVyIC0gVGhlIHJlYWRlciB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0gY29udGV4dCAtIFRoZSBjb250ZXh0IHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHJlYWRCaW5hcnkocmVhZGVyLCBjb250ZXh0KSB7CiAgICAgICAgICAgIHN1cGVyLmxvYWRCYXNlR2VvbUJpbmFyeShyZWFkZXIsIGNvbnRleHQpOwogICAgICAgICAgICB0aGlzLnNldEZhY2VDb3VudHMoQXJyYXkuZnJvbShyZWFkZXIubG9hZFVJbnQzMkFycmF5KCkpKTsKICAgICAgICAgICAgY29uc3QgbnVtRmFjZXMgPSB0aGlzLmdldE51bUZhY2VzKCk7CiAgICAgICAgICAgIC8vIE5vdGU6IHdlIGNhbiByZW1vdmUgdGhpcy4gV2UgY2FuIGluZmVyIHRoaXMgZnJvbSB0aGUgYWJvdmUgZmFjZUNvdW50cyBhcnJheS4KICAgICAgICAgICAgLy8gRG8gbm90IGNsb25lIHRoZSBkYXRhLCBhcyBpdHMgJ3NjcmF0Y2ggbWVtb3J5JyBpbiBhbnkgY2FzZS4KICAgICAgICAgICAgLy8gV2UgY2FuIGF2b2lkIGEgbG90IG9mIHVubmVjZXNzYXJ5IHRlbXBvcmFyeSBhbGxvY2FpdG9uIGJ5IHVzaW5nIHNoYXJlZCBidWZmZXJzLgogICAgICAgICAgICBjb25zdCBmYWNlVmVydGV4Q291bnRzID0gcmVhZGVyLmxvYWRVSW50OEFycmF5KG51bUZhY2VzLCBmYWxzZSk7CiAgICAgICAgICAgIGNvbnN0IG9mZnNldFJhbmdlID0gcmVhZGVyLmxvYWRTSW50MzJWZWMyKCk7CiAgICAgICAgICAgIGNvbnN0IGJ5dGVzID0gcmVhZGVyLmxvYWRVSW50OCgpOwogICAgICAgICAgICBsZXQgZmFjZVZlcnRleEluZGV4RGVsdGFzOwogICAgICAgICAgICBpZiAoYnl0ZXMgPT0gMSkKICAgICAgICAgICAgICAgIGZhY2VWZXJ0ZXhJbmRleERlbHRhcyA9IHJlYWRlci5sb2FkVUludDhBcnJheSh1bmRlZmluZWQsIGZhbHNlKTsKICAgICAgICAgICAgZWxzZSBpZiAoYnl0ZXMgPT0gMikKICAgICAgICAgICAgICAgIGZhY2VWZXJ0ZXhJbmRleERlbHRhcyA9IHJlYWRlci5sb2FkVUludDE2QXJyYXkodW5kZWZpbmVkLCBmYWxzZSk7CiAgICAgICAgICAgIGVsc2UgaWYgKGJ5dGVzID09IDQpCiAgICAgICAgICAgICAgICBmYWNlVmVydGV4SW5kZXhEZWx0YXMgPSByZWFkZXIubG9hZFVJbnQzMkFycmF5KHVuZGVmaW5lZCwgZmFsc2UpOwogICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgIHRocm93IEVycm9yKCdmYWNlVmVydGV4SW5kZXhEZWx0YXMgdW5kZWZpbmVkJyk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLy8gLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCiAgICAgICAgICAgIC8vIE5vdGU6IFRoZSBNZXNoIGNvbXByZXNzaW9uIHN5c3RlbSBuZWVkcyBhIHRob3JvdWdoIHJldmlldy4KICAgICAgICAgICAgLy8gVGhlIEMrKyBjbGFzc2VzIGFyZSBub3Qgc3RvcmluZyBmYWNlIGluZGljZXMgaW4gYSBzb3J0ZWQgbWFubmVyLgogICAgICAgICAgICAvLyBTbyBxdWFkcyBwcmVjZWRlIHRyaWFuZ2xlcyBpbiB0aGUgaW5kZXhpbmcsIHdoaWNoIGlzbid0IHN1cHBvc2VkIHRvIGhhcHBlbi4KICAgICAgICAgICAgLy8gV2Ugc2hvdWxkIGZvcmNlIHRoZSBDKysgY29kZSB0byBzdG9yZSBxdWFkcyBhbmQgdHJpYW5nbGVzIGluIG9yZGVyLgogICAgICAgICAgICAvLyBlLmcuIGltcGxlbWVudCB0aGUgJ2FkZEZhY2UnIG1ldGhvZCBpbiBDKysgc28gaXQgYXV0b21hdGljYWxseSBkb2VzIHRoaXMuCiAgICAgICAgICAgIGxldCBudW1GYWNlVmVydHMgPSAzOwogICAgICAgICAgICBsZXQgb2Zmc2V0ID0gMDsKICAgICAgICAgICAgY29uc3QgZmFjZU9mZnNldHNCeUNvdW50ID0gdGhpcy5mYWNlQ291bnRzLm1hcCgoZmMsIGluZGV4KSA9PiB7CiAgICAgICAgICAgICAgICBjb25zdCByZXN1bHQgPSBvZmZzZXQ7CiAgICAgICAgICAgICAgICBvZmZzZXQgKz0gZmMgKiBudW1GYWNlVmVydHM7CiAgICAgICAgICAgICAgICBudW1GYWNlVmVydHMrKzsKICAgICAgICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgICAgIH0pOwogICAgICAgICAgICBsZXQgc3JjT2Zmc2V0ID0gMDsKICAgICAgICAgICAgbGV0IHByZXZDb3VudCA9IDA7CiAgICAgICAgICAgIGNvbnN0IGZhY2VPZmZzZXRzID0gW107CiAgICAgICAgICAgIGZvciAobGV0IGZhY2VJbmRleCA9IDA7IGZhY2VJbmRleCA8IG51bUZhY2VzOyBmYWNlSW5kZXgrKykgewogICAgICAgICAgICAgICAgY29uc3QgZmMgPSBmYWNlVmVydGV4Q291bnRzW2ZhY2VJbmRleF07CiAgICAgICAgICAgICAgICBjb25zdCBvZmZzZXQgPSBmYWNlT2Zmc2V0c0J5Q291bnRbZmNdOwogICAgICAgICAgICAgICAgY29uc3QgY291bnQgPSBmYyArIDM7CiAgICAgICAgICAgICAgICBmYWNlT2Zmc2V0c1tmYWNlSW5kZXhdID0gb2Zmc2V0OwogICAgICAgICAgICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCBjb3VudDsgaisrKSB7CiAgICAgICAgICAgICAgICAgICAgY29uc3Qgc3JjRmFjZVZlcnRleCA9IHNyY09mZnNldCArIGo7CiAgICAgICAgICAgICAgICAgICAgY29uc3QgZmFjZVZlcnRleCA9IG9mZnNldCArIGo7CiAgICAgICAgICAgICAgICAgICAgY29uc3QgZGVsdGEgPSBmYWNlVmVydGV4SW5kZXhEZWx0YXNbc3JjRmFjZVZlcnRleF0gKyBvZmZzZXRSYW5nZS54OwogICAgICAgICAgICAgICAgICAgIGlmIChmYWNlSW5kZXggPT0gMCkKICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5mYWNlVmVydGV4SW5kaWNlc1tmYWNlVmVydGV4XSA9IGRlbHRhOwogICAgICAgICAgICAgICAgICAgIGVsc2UgewogICAgICAgICAgICAgICAgICAgICAgICBsZXQgcHJldkZhY2VWZXJ0ZXggPSBmYWNlT2Zmc2V0c1tmYWNlSW5kZXggLSAxXTsKICAgICAgICAgICAgICAgICAgICAgICAgcHJldkZhY2VWZXJ0ZXggKz0gaiA8IHByZXZDb3VudCA/IGogOiBwcmV2Q291bnQgLSAxOwogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmZhY2VWZXJ0ZXhJbmRpY2VzW2ZhY2VWZXJ0ZXhdID0gdGhpcy5mYWNlVmVydGV4SW5kaWNlc1twcmV2RmFjZVZlcnRleF0gKyBkZWx0YTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBzcmNPZmZzZXQgKz0gY291bnQ7CiAgICAgICAgICAgICAgICBmYWNlT2Zmc2V0c0J5Q291bnRbZmNdICs9IGNvdW50OwogICAgICAgICAgICAgICAgcHJldkNvdW50ID0gY291bnQ7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKCF0aGlzLmhhc1ZlcnRleEF0dHJpYnV0ZSgnbm9ybWFscycpKSB7CiAgICAgICAgICAgICAgICB0aGlzLmNvbXB1dGVWZXJ0ZXhOb3JtYWxzKCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLy8gdGhpcy5jb21wdXRlVmVydGV4Tm9ybWFscygpOwogICAgICAgICAgICB0aGlzLmVtaXQoJ2dlb21EYXRhQ2hhbmdlZCcpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgdG9KU09OIG1ldGhvZCBlbmNvZGVzIHRoaXMgdHlwZSBhcyBhIGpzb24gb2JqZWN0IGZvciBwZXJzaXN0ZW5jZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBjb250ZXh0IC0gVGhlIGNvbnRleHQgdmFsdWUuCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgdGhlIGpzb24gb2JqZWN0LgogICAgICAgICAqLwogICAgICAgIHRvSlNPTihjb250ZXh0KSB7CiAgICAgICAgICAgIGNvbnN0IGogPSBzdXBlci50b0pTT04oY29udGV4dCk7CiAgICAgICAgICAgIGlmICghY29udGV4dCB8fCAhY29udGV4dC5za2lwVG9wb2xvZ3kpIHsKICAgICAgICAgICAgICAgIGouZmFjZUNvdW50cyA9IEFycmF5LmZyb20odGhpcy5mYWNlQ291bnRzKTsKICAgICAgICAgICAgICAgIGouZmFjZVZlcnRleEluZGljZXMgPSBBcnJheS5mcm9tKHRoaXMuZmFjZVZlcnRleEluZGljZXMpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBqOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgZnJvbUpTT04gbWV0aG9kIGRlY29kZXMgYSBqc29uIG9iamVjdCBmb3IgdGhpcyB0eXBlLgogICAgICAgICAqCiAgICAgICAgICogZS5nLiB0byBsb2FkIGRhdGEgaW50byB0aGUgbWVzaCBjbGFzcywgcHJvdmlkZSBhIGpzb24gc3RydWN0dXJlIHNpbWlsYXIgdG8gdGhlIGZvbGxvd2luZy4KICAgICAgICAgKiBOb3RlOiBmYWNlQ291bnRzIGlzIGFuIGFycmF5IG9mIGNvdW50IHZhbHVlcywgc3RhcnRpbmcgd2l0aCB0aGUgbnVtYmVyIG9mIHRyaWFuZ2xlcywgdGhlbiB0aGUgbnVtYmVyIG9mIHF1YWRzLiBTZWUgI3NldEZhY2VDb3VudHMKICAgICAgICAgKiBUaGUgZmFjZVZlcnRleEluZGljZXMgYXJyYXkgc2hvdWxkIGFsc28gYmUgc29ydGVkIHRvIGNvbnRhaW4gYWxsIHRoZSB0cmlhbmdsZXMgZmlyc3QsIGZvbGxvd2VkIGJ5IHRoZSBxdWFkcywgYW5kIHRoZW4gdGhlIHBlbnRhZ29ucyBldGMuLgogICAgICAgICAqIGBgYGpzb24KICAgICAgICAgKiAvLyBUaGlzIGNvZGUgd2lsbCBkZWZpbmUgYSBtZXNoIG1hZGUgdXAgb2YgMiB0cmlhbmdsZXMgYW5kIHRoZW4gYSBxdWFkLgogICAgICAgICAqIGNvbnN0IG1lc2ggPSBuZXcgTWVzaCgpCiAgICAgICAgICogbWVzaC5mcm9tSlNPTih7CiAgICAgICAgICogICBmYWNlQ291bnRzOlsyLCAxXSwKICAgICAgICAgKiAgIGZhY2VWZXJ0ZXhJbmRpY2VzOiBbMCwgMSwgMiwgMCwgMiwgMywgMywgMiwgNCwgNV0sCiAgICAgICAgICogICBudW1WZXJ0aWNlczogNiwKICAgICAgICAgKiAgIHZlcnRleEF0dHJpYnV0ZXM6IHsKICAgICAgICAgKiAgICAgcG9zaXRpb25zOiB7CiAgICAgICAgICogICAgICAgZGF0YVR5cGU6ICdWZWMzJwogICAgICAgICAqICAgICAgIGRlZmF1bHRTY2FsYXJWYWx1ZTogMC4wLAogICAgICAgICAqICAgICAgIGRhdGE6IFswLDAsMCwgMCwgMSwgMCwgMSwgMSwgMCwgMSwgMCwgMCwgMiwgMSwgMCwgMiwgMCwgMF0KICAgICAgICAgKiAgICAgfQogICAgICAgICAqICAgfQogICAgICAgICAqIH0KICAgICAgICAgKiBgYGAKICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSBqIC0gVGhlIGpzb24gb2JqZWN0IHRoaXMgaXRlbSBtdXN0IGRlY29kZS4KICAgICAgICAgKiBAcGFyYW0gY29udGV4dCAtIFRoZSBjb250ZXh0IHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGZyb21KU09OKGosIGNvbnRleHQpIHsKICAgICAgICAgICAgc3VwZXIuZnJvbUpTT04oaiwgY29udGV4dCk7CiAgICAgICAgICAgIGlmIChqLmZhY2VDb3VudHMpCiAgICAgICAgICAgICAgICB0aGlzLmZhY2VDb3VudHMgPSBqLmZhY2VDb3VudHM7CiAgICAgICAgICAgIGlmIChqLmZhY2VWZXJ0ZXhJbmRpY2VzKQogICAgICAgICAgICAgICAgdGhpcy5mYWNlVmVydGV4SW5kaWNlcyA9IFVpbnQzMkFycmF5LmZyb20oai5mYWNlVmVydGV4SW5kaWNlcyk7CiAgICAgICAgfQogICAgfQogICAgUmVnaXN0cnkucmVnaXN0ZXIoJ01lc2gnLCBNZXNoKTsKCiAgICAvKiBlc2xpbnQtZGlzYWJsZSBuby11bnVzZWQtdmFycyAqLwogICAgLyoqCiAgICAgKiBSZWFkcyBiaW5hcnkgZGF0YSBpbiBhIHNwZWNpZmljIGVuY29kaW5nLiBVc2VkIGluIGxvYWRpbmcgYmluYXJ5IGRhdGEgc3VjaCBhcyB6Y2FkIGZpbGVzLgogICAgICovCiAgICBjbGFzcyBCaW5SZWFkZXIgewogICAgICAgIF9fZGF0YTsKICAgICAgICBfX2J5dGVPZmZzZXQ7CiAgICAgICAgX19kYXRhVmlldzsKICAgICAgICBfX2lzTW9iaWxlRGV2aWNlOwogICAgICAgIHV0ZjhkZWNvZGVyOwogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZSBhIGJpbiByZWFkZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gZGF0YSAtIFRoZSBkYXRhIGJ1ZmZlci4KICAgICAgICAgKiBAcGFyYW0gYnl0ZU9mZnNldCAtIFRoZSBieXRlIG9mZnNldCB2YWx1ZSB0byBzdGFydCByZWFkaW5nIHRoZSBidWZmZXIuCiAgICAgICAgICogQHBhcmFtIGlzTW9iaWxlRGV2aWNlIC0gVGhlIGlzTW9iaWxlRGV2aWNlIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGNvbnN0cnVjdG9yKGRhdGEsIGJ5dGVPZmZzZXQgPSAwLCBpc01vYmlsZURldmljZSA9IHRydWUpIHsKICAgICAgICAgICAgdGhpcy5fX2RhdGEgPSBkYXRhOwogICAgICAgICAgICB0aGlzLl9fYnl0ZU9mZnNldCA9IGJ5dGVPZmZzZXQ7CiAgICAgICAgICAgIHRoaXMuX19kYXRhVmlldyA9IG5ldyBEYXRhVmlldyh0aGlzLl9fZGF0YSk7CiAgICAgICAgICAgIHRoaXMuX19pc01vYmlsZURldmljZSA9IGlzTW9iaWxlRGV2aWNlOwogICAgICAgICAgICB0aGlzLnV0ZjhkZWNvZGVyID0gbmV3IFRleHREZWNvZGVyKCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgc3RhdGUgb2Ygd2hldGhlciBvciBub3QgdGhlIGBCaW5SZWFkZXJgIG9iamVjdCB3YXMgaW5zdGFudGlhdGVkIGZyb20gYSBtb2JpbGUgZGV2aWNlLgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgdHJ1ZSBpcyBhIG1vYmlsZSBkZXZpY2UgaXMgZGV0ZWN0ZWQuCiAgICAgICAgICovCiAgICAgICAgZ2V0IGlzTW9iaWxlRGV2aWNlKCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy5fX2lzTW9iaWxlRGV2aWNlOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIHRoZSBkYXRhIGJ1ZmZlciB3ZSdyZSByZWFkaW5nIGZyb20uCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIGRhdGEgYnVmZmVyIHdlIGFyZSByZWFkaW5nIGZyb20sCiAgICAgICAgICovCiAgICAgICAgZ2V0IGRhdGEoKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLl9fZGF0YTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyB0aGUgbGVuZ3RoIG9mIHRoZSBidWZmZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHRvdGFsIGxlbmd0aCBvZiB0aGUgYnVmZmVyCiAgICAgICAgICovCiAgICAgICAgZ2V0IGJ5dGVMZW5ndGgoKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLl9fZGF0YVZpZXcuYnl0ZUxlbmd0aDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyByZW1haW5pbmcgbGVuZ3RoIG9mIHRoZSBidWZmZXIgdG8gcmVhZC4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmVtYWluaW5nIGxlbmd0aCBvZiB0aGUgYnVmZmVyIHRvIHJlYWQuCiAgICAgICAgICovCiAgICAgICAgZ2V0IHJlbWFpbmluZ0J5dGVMZW5ndGgoKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLl9fZGF0YVZpZXcuYnl0ZUxlbmd0aCAtIHRoaXMuX19ieXRlT2Zmc2V0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIGN1cnJlbnQgYnl0ZSBvZmZzZXQgaW4gdGhlIGJ1ZmZlci4KICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIGN1cnJlbnQgb2Zmc2V0IGluIHRoZSBiaW5hcnkgYnVmZmVyCiAgICAgICAgICovCiAgICAgICAgcG9zKCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy5fX2J5dGVPZmZzZXQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFNldHMgdGhlIGJ5dGUgb2Zmc2V0IHZhbHVlLgogICAgICAgICAqIEBwYXJhbSBieXRlT2Zmc2V0IC0gVGhlIGJ5dGVPZmZzZXQgcGFyYW0uCiAgICAgICAgICovCiAgICAgICAgc2VlayhieXRlT2Zmc2V0KSB7CiAgICAgICAgICAgIHRoaXMuX19ieXRlT2Zmc2V0ID0gYnl0ZU9mZnNldDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQWRkcyBvZmZzZXQgYnl0ZXMgdG8gY3VycmVudCBvZmZzZXQgdmFsdWUuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gYnl0ZU9mZnNldCAtIFRoZSBieXRlIE9mZnNldCBhbW91bnQuCiAgICAgICAgICovCiAgICAgICAgYWR2YW5jZShieXRlT2Zmc2V0KSB7CiAgICAgICAgICAgIHRoaXMuX19ieXRlT2Zmc2V0ICs9IGJ5dGVPZmZzZXQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgdGhlIHVuc2lnbmVkIFVpbnQ4IHZhbHVlIGF0IGN1cnJlbnQgYnl0ZSBvZmZzZXQgcG9zaXRpb24sCiAgICAgICAgICogYW5kIGFkZHMgb25lIGJ5dGUgdG8gdGhlIG9mZnNldC4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGxvYWRVSW50OCgpIHsKICAgICAgICAgICAgY29uc3QgcmVzdWx0ID0gdGhpcy5fX2RhdGFWaWV3LmdldFVpbnQ4KHRoaXMuX19ieXRlT2Zmc2V0KTsKICAgICAgICAgICAgdGhpcy5fX2J5dGVPZmZzZXQgKz0gMTsKICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyB0aGUgdW5zaWduZWQgVWludDE2IHZhbHVlIGF0IGN1cnJlbnQgYnl0ZSBvZmZzZXQgcG9zaXRpb24sCiAgICAgICAgICogYW5kIGFkZHMgdHdvIGJ5dGVzIHRvIHRoZSBvZmZzZXQuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBsb2FkVUludDE2KCkgewogICAgICAgICAgICBjb25zdCByZXN1bHQgPSB0aGlzLl9fZGF0YVZpZXcuZ2V0VWludDE2KHRoaXMuX19ieXRlT2Zmc2V0LCB0cnVlKTsKICAgICAgICAgICAgdGhpcy5fX2J5dGVPZmZzZXQgKz0gMjsKICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyB0aGUgdW5zaWduZWQgVWludDMyIHZhbHVlIGF0IGN1cnJlbnQgYnl0ZSBvZmZzZXQgcG9zaXRpb24sCiAgICAgICAgICogYW5kIGFkZHMgZm91ciBieXRlcyB0byB0aGUgb2Zmc2V0LgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgbG9hZFVJbnQzMigpIHsKICAgICAgICAgICAgY29uc3QgcmVzdWx0ID0gdGhpcy5fX2RhdGFWaWV3LmdldFVpbnQzMih0aGlzLl9fYnl0ZU9mZnNldCwgdHJ1ZSk7CiAgICAgICAgICAgIHRoaXMuX19ieXRlT2Zmc2V0ICs9IDQ7CiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgdGhlIHNpZ25lZCBJbnQzMiB2YWx1ZSBhdCBjdXJyZW50IGJ5dGUgb2Zmc2V0IHBvc2l0aW9uLAogICAgICAgICAqIGFuZCBhZGRzIGZvdXIgYnl0ZXMgdG8gdGhlIG9mZnNldC4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGxvYWRTSW50MzIoKSB7CiAgICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IHRoaXMuX19kYXRhVmlldy5nZXRJbnQzMih0aGlzLl9fYnl0ZU9mZnNldCwgdHJ1ZSk7CiAgICAgICAgICAgIHRoaXMuX19ieXRlT2Zmc2V0ICs9IDQ7CiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgdGhlIEZsb2F0MTYgdmFsdWUgYXQgY3VycmVudCBieXRlIG9mZnNldCBwb3NpdGlvbiwKICAgICAgICAgKiBhbmQgYWRkcyBmb3VyIGJ5dGVzIHRvIHRoZSBvZmZzZXQuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBsb2FkRmxvYXQxNigpIHsKICAgICAgICAgICAgY29uc3QgdWludDE2ID0gdGhpcy5sb2FkVUludDE2KCk7CiAgICAgICAgICAgIHJldHVybiBNYXRoRnVuY3Rpb25zLmRlY29kZTE2Qml0RmxvYXQodWludDE2KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyB0aGUgRmxvYXQxNiB2YWx1ZSBhdCBjdXJyZW50IGJ5dGUgb2Zmc2V0IHBvc2l0aW9uLAogICAgICAgICAqIGFuZCBhZGRzIHR3byBieXRlcyB0byB0aGUgb2Zmc2V0LgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgbG9hZFVGbG9hdDE2KCkgewogICAgICAgICAgICBjb25zdCByZXN1bHQgPSB0aGlzLmxvYWRGbG9hdDE2KCk7CiAgICAgICAgICAgIGlmIChyZXN1bHQgPCAwLjApIHsKICAgICAgICAgICAgICAgIHJldHVybiAyMDQ4LjAgLSByZXN1bHQ7IC8vIE5vdGU6IHN1YnRyYWN0IGEgbmVnYXRpdmUgbnVtYmVyIHRvIGFkZCBpdC4KICAgICAgICAgICAgfQogICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyBhIHNpbmdsZSBzaWduZWQgRmxvYXQxNiB2YWx1ZSBhdCBjdXJyZW50IGJ5dGUgb2Zmc2V0IHBvc2l0aW9uIGZyb20gMiB1bnNpZ25lZCBJbnQ4IHZhbHVlcywKICAgICAgICAgKiBhbmQgYWRkcyB0d28gYnl0ZXMgdG8gdGhlIG9mZnNldC4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBUaGUgcmV0dXJuIHZhbHVlLgogICAgICAgICAqLwogICAgICAgIGxvYWRGbG9hdDE2RnJvbTJ4VUludDgoKSB7CiAgICAgICAgICAgIHRocm93IEVycm9yKCdsb2FkRmxvYXQxNkZyb20yeFVJbnQ4IG5vdCBpbXBsZW1lbnRlZCEnKTsKICAgICAgICAgICAgLy8gY29uc3QgcmVzdWx0ID0gdGhpcy5fX2RhdGFWaWV3LmdldEZsb2F0MTYodGhpcy5fX2J5dGVPZmZzZXQsIHRydWUpCiAgICAgICAgICAgIC8vIGNvbnN0IHVpbnQ4cyA9IHRoaXMubG9hZFVJbnQ4QXJyYXkoMik7CiAgICAgICAgICAgIC8vIHJldHVybiBNYXRoLmRlY29kZTE2Qml0RmxvYXQodWludDhzKTsKICAgICAgICAgICAgLy8gdGhpcy5fX2J5dGVPZmZzZXQgKz0gMgogICAgICAgICAgICAvLyByZXR1cm4gcmVzdWx0CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIExvYWRzIGFuZCByZXR1cm5zIGEgc2luZ2xlIFNpZ25lZCBpbnRlZ2VyIHZhbHVlIGZyb20gMiBVbnNpZ25lZCBGbG9hdDE2IHZhbHVlcy4KICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBsb2FkVUludDMyRnJvbTJ4VUZsb2F0MTYoKSB7CiAgICAgICAgICAgIGNvbnN0IHBhcnRBID0gdGhpcy5sb2FkVUZsb2F0MTYoKTsKICAgICAgICAgICAgY29uc3QgcGFydEIgPSB0aGlzLmxvYWRVRmxvYXQxNigpOwogICAgICAgICAgICByZXR1cm4gcGFydEEgKyBwYXJ0QiAqIDQwOTY7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIExvYWRzIGFuZCByZXR1cm5zIGEgc2luZ2xlIFNpZ25lZCBpbnRlZ2VyIHZhbHVlIGZyb20gMiBzaWduZWQgRmxvYXQxNiB2YWx1ZXMuCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgbG9hZFNJbnQzMkZyb20yeEZsb2F0MTYoKSB7CiAgICAgICAgICAgIGNvbnN0IHBhcnRBID0gdGhpcy5sb2FkRmxvYXQxNigpOwogICAgICAgICAgICBjb25zdCBwYXJ0QiA9IHRoaXMubG9hZEZsb2F0MTYoKTsKICAgICAgICAgICAgcmV0dXJuIHBhcnRBICsgcGFydEIgKiAyMDQ4OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIHRoZSBGbG9hdDMyIHZhbHVlIGF0IGN1cnJlbnQgYnl0ZSBvZmZzZXQgcG9zaXRpb24sCiAgICAgICAgICogYW5kIGFkZHMgZm91ciBieXRlcyB0byB0aGUgb2Zmc2V0LgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgbG9hZEZsb2F0MzIoKSB7CiAgICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IHRoaXMuX19kYXRhVmlldy5nZXRGbG9hdDMyKHRoaXMuX19ieXRlT2Zmc2V0LCB0cnVlKTsKICAgICAgICAgICAgdGhpcy5fX2J5dGVPZmZzZXQgKz0gNDsKICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmVhZHMgYnVmZmVyIGFuZCByZXR1cm4gYSBzaWduZWQgSW50OCBhcnJheSB3aXRoIHRoZSBzcGVjaWZpZWQgc2l6ZSwKICAgICAgICAgKiBzdGFydGluZyBmcm9tIGN1cnJlbnQgYnl0ZSBvZmZzZXQuCiAgICAgICAgICogQnl0ZSBvZmZzZXQgaXMgaW5jcmVhc2VkIGJ5IHRoZSBzcGVjaWZpZWQgYnl0ZSBzaXplLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHNpemUgLSBUaGUgc2l6ZSBwYXJhbS4KICAgICAgICAgKiBAcGFyYW0gY2xvbmUgLSBUaGUgY2xvbmUgcGFyYW0uCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgbG9hZEludDhBcnJheShzaXplLCBjbG9uZSA9IHRydWUpIHsKICAgICAgICAgICAgaWYgKHNpemUgPT0gdW5kZWZpbmVkKQogICAgICAgICAgICAgICAgc2l6ZSA9IHRoaXMubG9hZFVJbnQzMigpOwogICAgICAgICAgICBsZXQgcmVzdWx0OwogICAgICAgICAgICBpZiAoY2xvbmUpIHsKICAgICAgICAgICAgICAgIHJlc3VsdCA9IG5ldyBJbnQ4QXJyYXkodGhpcy5fX2RhdGEuc2xpY2UodGhpcy5fX2J5dGVPZmZzZXQsIHRoaXMuX19ieXRlT2Zmc2V0ICsgc2l6ZSkpOwogICAgICAgICAgICAgICAgaWYgKHJlc3VsdC5sZW5ndGggIT0gc2l6ZSkKICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZygnYnJva2VuJyk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZWxzZSB7CiAgICAgICAgICAgICAgICByZXN1bHQgPSBuZXcgSW50OEFycmF5KHRoaXMuX19kYXRhLCB0aGlzLl9fYnl0ZU9mZnNldCwgc2l6ZSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdGhpcy5fX2J5dGVPZmZzZXQgKz0gc2l6ZTsKICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmVhZHMgYnVmZmVyIGFuZCByZXR1cm4gYW4gdW5zaWduZWQgSW50OCBhcnJheSB3aXRoIHRoZSBzcGVjaWZpZWQgc2l6ZSwKICAgICAgICAgKiBzdGFydGluZyBmcm9tIGN1cnJlbnQgYnl0ZSBvZmZzZXQuCiAgICAgICAgICogQnl0ZSBvZmZzZXQgaXMgaW5jcmVhc2VkIGJ5IHRoZSBzcGVjaWZpZWQgYnl0ZSBzaXplLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHNpemUgLSBUaGUgc2l6ZSBwYXJhbS4KICAgICAgICAgKiBAcGFyYW0gY2xvbmUgLSBUaGUgY2xvbmUgcGFyYW0uCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgbG9hZFVJbnQ4QXJyYXkoc2l6ZSwgY2xvbmUgPSB0cnVlKSB7CiAgICAgICAgICAgIGlmIChzaXplID09IHVuZGVmaW5lZCkKICAgICAgICAgICAgICAgIHNpemUgPSB0aGlzLmxvYWRVSW50MzIoKTsKICAgICAgICAgICAgbGV0IHJlc3VsdDsKICAgICAgICAgICAgaWYgKGNsb25lKSB7CiAgICAgICAgICAgICAgICByZXN1bHQgPSBuZXcgVWludDhBcnJheSh0aGlzLl9fZGF0YS5zbGljZSh0aGlzLl9fYnl0ZU9mZnNldCwgdGhpcy5fX2J5dGVPZmZzZXQgKyBzaXplKSk7CiAgICAgICAgICAgICAgICBpZiAocmVzdWx0Lmxlbmd0aCAhPSBzaXplKQogICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKCdicm9rZW4nKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgIHJlc3VsdCA9IG5ldyBVaW50OEFycmF5KHRoaXMuX19kYXRhLCB0aGlzLl9fYnl0ZU9mZnNldCwgc2l6ZSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdGhpcy5fX2J5dGVPZmZzZXQgKz0gc2l6ZTsKICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmVhZHMgYnVmZmVyIGFuZCByZXR1cm4gYW4gdW5zaWduZWQgSW50MTYgYXJyYXkgd2l0aCB0aGUgc3BlY2lmaWVkIHNpemUsCiAgICAgICAgICogc3RhcnRpbmcgZnJvbSBjdXJyZW50IGJ5dGUgb2Zmc2V0LgogICAgICAgICAqIEJ5dGUgb2Zmc2V0IGlzIGluY3JlYXNlZCBieSB0aGUgc3BlY2lmaWVkIGJ5dGUgc2l6ZSB4IDIuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gc2l6ZSAtIFRoZSBzaXplIHBhcmFtLgogICAgICAgICAqIEBwYXJhbSBjbG9uZSAtIFRoZSBjbG9uZSBwYXJhbS4KICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBsb2FkVUludDE2QXJyYXkoc2l6ZSwgY2xvbmUgPSB0cnVlKSB7CiAgICAgICAgICAgIGlmIChzaXplID09IHVuZGVmaW5lZCkKICAgICAgICAgICAgICAgIHNpemUgPSB0aGlzLmxvYWRVSW50MzIoKTsKICAgICAgICAgICAgaWYgKHNpemUgPT0gMCkKICAgICAgICAgICAgICAgIHJldHVybiBuZXcgVWludDE2QXJyYXkoKTsKICAgICAgICAgICAgdGhpcy5yZWFkUGFkKDIpOwogICAgICAgICAgICBsZXQgcmVzdWx0OwogICAgICAgICAgICBpZiAodGhpcy5fX2lzTW9iaWxlRGV2aWNlKSB7CiAgICAgICAgICAgICAgICByZXN1bHQgPSBuZXcgVWludDE2QXJyYXkoc2l6ZSk7CiAgICAgICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHNpemU7IGkrKykgewogICAgICAgICAgICAgICAgICAgIHJlc3VsdFtpXSA9IHRoaXMuX19kYXRhVmlldy5nZXRVaW50MTYodGhpcy5fX2J5dGVPZmZzZXQsIHRydWUpOwogICAgICAgICAgICAgICAgICAgIHRoaXMuX19ieXRlT2Zmc2V0ICs9IDI7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZWxzZSB7CiAgICAgICAgICAgICAgICBpZiAoY2xvbmUpIHsKICAgICAgICAgICAgICAgICAgICByZXN1bHQgPSBuZXcgVWludDE2QXJyYXkodGhpcy5fX2RhdGEuc2xpY2UodGhpcy5fX2J5dGVPZmZzZXQsIHRoaXMuX19ieXRlT2Zmc2V0ICsgc2l6ZSAqIDIpKTsKICAgICAgICAgICAgICAgICAgICBpZiAocmVzdWx0Lmxlbmd0aCAhPSBzaXplKQogICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZygnYnJva2VuJyk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgICAgICByZXN1bHQgPSBuZXcgVWludDE2QXJyYXkodGhpcy5fX2RhdGEsIHRoaXMuX19ieXRlT2Zmc2V0LCBzaXplKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIHRoaXMuX19ieXRlT2Zmc2V0ICs9IHNpemUgKiAyOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJlYWRzIGJ1ZmZlciBhbmQgcmV0dXJuIGFuIHVuc2lnbmVkIEludDMyIGFycmF5IHdpdGggdGhlIHNwZWNpZmllZCBzaXplLAogICAgICAgICAqIHN0YXJ0aW5nIGZyb20gY3VycmVudCBieXRlIG9mZnNldC4KICAgICAgICAgKiBCeXRlIG9mZnNldCBpcyBpbmNyZWFzZWQgYnkgdGhlIHNwZWNpZmllZCBieXRlIHNpemUgeCA0LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHNpemUgLSBUaGUgc2l6ZSBwYXJhbS4KICAgICAgICAgKiBAcGFyYW0gY2xvbmUgLSBUaGUgY2xvbmUgcGFyYW0uCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgbG9hZFVJbnQzMkFycmF5KHNpemUsIGNsb25lID0gdHJ1ZSkgewogICAgICAgICAgICBpZiAoc2l6ZSA9PSB1bmRlZmluZWQpCiAgICAgICAgICAgICAgICBzaXplID0gdGhpcy5sb2FkVUludDMyKCk7CiAgICAgICAgICAgIGlmIChzaXplID09IDApCiAgICAgICAgICAgICAgICByZXR1cm4gbmV3IFVpbnQzMkFycmF5KCk7CiAgICAgICAgICAgIHRoaXMucmVhZFBhZCg0KTsKICAgICAgICAgICAgbGV0IHJlc3VsdDsKICAgICAgICAgICAgaWYgKHRoaXMuX19pc01vYmlsZURldmljZSkgewogICAgICAgICAgICAgICAgcmVzdWx0ID0gbmV3IFVpbnQzMkFycmF5KHNpemUpOwogICAgICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzaXplOyBpKyspIHsKICAgICAgICAgICAgICAgICAgICByZXN1bHRbaV0gPSB0aGlzLl9fZGF0YVZpZXcuZ2V0VWludDMyKHRoaXMuX19ieXRlT2Zmc2V0LCB0cnVlKTsKICAgICAgICAgICAgICAgICAgICB0aGlzLl9fYnl0ZU9mZnNldCArPSA0OwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIGVsc2UgewogICAgICAgICAgICAgICAgaWYgKGNsb25lKSB7CiAgICAgICAgICAgICAgICAgICAgcmVzdWx0ID0gbmV3IFVpbnQzMkFycmF5KHRoaXMuX19kYXRhLnNsaWNlKHRoaXMuX19ieXRlT2Zmc2V0LCB0aGlzLl9fYnl0ZU9mZnNldCArIHNpemUgKiA0KSk7CiAgICAgICAgICAgICAgICAgICAgaWYgKHJlc3VsdC5sZW5ndGggIT0gc2l6ZSkKICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coJ2Jyb2tlbicpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgcmVzdWx0ID0gbmV3IFVpbnQzMkFycmF5KHRoaXMuX19kYXRhLCB0aGlzLl9fYnl0ZU9mZnNldCwgc2l6ZSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB0aGlzLl9fYnl0ZU9mZnNldCArPSBzaXplICogNDsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZWFkcyBidWZmZXIgYW5kIHJldHVybiBhIEZsb2F0MzIgYXJyYXkgd2l0aCB0aGUgc3BlY2lmaWVkIHNpemUsCiAgICAgICAgICogc3RhcnRpbmcgZnJvbSBjdXJyZW50IGJ5dGUgb2Zmc2V0LgogICAgICAgICAqIEJ5dGUgb2Zmc2V0IGlzIGluY3JlYXNlZCBieSB0aGUgc3BlY2lmaWVkIGJ5dGUgc2l6ZSB4IDQuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gc2l6ZSAtIFRoZSBzaXplIHBhcmFtLgogICAgICAgICAqIEBwYXJhbSBjbG9uZSAtIFRoZSBjbG9uZSBwYXJhbS4KICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBsb2FkRmxvYXQzMkFycmF5KHNpemUsIGNsb25lID0gdHJ1ZSkgewogICAgICAgICAgICBpZiAoc2l6ZSA9PSB1bmRlZmluZWQpCiAgICAgICAgICAgICAgICBzaXplID0gdGhpcy5sb2FkVUludDMyKCk7CiAgICAgICAgICAgIGlmIChzaXplID09IDApCiAgICAgICAgICAgICAgICByZXR1cm4gbmV3IEZsb2F0MzJBcnJheSgpOwogICAgICAgICAgICB0aGlzLnJlYWRQYWQoNCk7CiAgICAgICAgICAgIGxldCByZXN1bHQ7CiAgICAgICAgICAgIGlmICh0aGlzLl9faXNNb2JpbGVEZXZpY2UpIHsKICAgICAgICAgICAgICAgIHJlc3VsdCA9IG5ldyBGbG9hdDMyQXJyYXkoc2l6ZSk7CiAgICAgICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHNpemU7IGkrKykgewogICAgICAgICAgICAgICAgICAgIHJlc3VsdFtpXSA9IHRoaXMuX19kYXRhVmlldy5nZXRGbG9hdDMyKHRoaXMuX19ieXRlT2Zmc2V0LCB0cnVlKTsKICAgICAgICAgICAgICAgICAgICB0aGlzLl9fYnl0ZU9mZnNldCArPSA0OwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIGVsc2UgewogICAgICAgICAgICAgICAgaWYgKGNsb25lKSB7CiAgICAgICAgICAgICAgICAgICAgcmVzdWx0ID0gbmV3IEZsb2F0MzJBcnJheSh0aGlzLl9fZGF0YS5zbGljZSh0aGlzLl9fYnl0ZU9mZnNldCwgdGhpcy5fX2J5dGVPZmZzZXQgKyBzaXplICogNCkpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgcmVzdWx0ID0gbmV3IEZsb2F0MzJBcnJheSh0aGlzLl9fZGF0YSwgdGhpcy5fX2J5dGVPZmZzZXQsIHNpemUpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgdGhpcy5fX2J5dGVPZmZzZXQgKz0gc2l6ZSAqIDQ7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyBuZXh0IHN0cmluZy4KICAgICAgICAgKiBGaXJzdCBsb29rcyBmb3IgdGhlIHN0cmluZyBsZW5ndGggZGVzY3JpcHRpb24gaW4gdGhlIG5leHQgZm91ciBieXRlcyBpbiB0aGUgYnVmZmVyKFN0YXJ0aW5nIGZyb20gYnl0ZSBvZmZzZXQpLgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFRoZSByZXR1cm4gdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgbG9hZFN0cigpIHsKICAgICAgICAgICAgY29uc3QgbnVtQ2hhcnMgPSB0aGlzLmxvYWRVSW50MzIoKTsKICAgICAgICAgICAgY29uc3QgY2hhcnMgPSBuZXcgVWludDhBcnJheSh0aGlzLl9fZGF0YSwgdGhpcy5fX2J5dGVPZmZzZXQsIG51bUNoYXJzKTsKICAgICAgICAgICAgdGhpcy5fX2J5dGVPZmZzZXQgKz0gbnVtQ2hhcnM7CiAgICAgICAgICAgIHJldHVybiB0aGlzLnV0ZjhkZWNvZGVyLmRlY29kZShjaGFycyk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgYW4gYXJyYXkgb2Ygc3RyaW5ncy4KICAgICAgICAgKiBGaXJzdCByZWFkaW5nIHRoZSBzaXplIG9mIHRoZSBhcnJheSB0aGVuIHJlYWRpbmcgZWFjaCBzdHJpbmcuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gVGhlIHJldHVybiB2YWx1ZS4KICAgICAgICAgKi8KICAgICAgICBsb2FkU3RyQXJyYXkoKSB7CiAgICAgICAgICAgIGNvbnN0IHNpemUgPSB0aGlzLmxvYWRVSW50MzIoKTsKICAgICAgICAgICAgY29uc3QgcmVzdWx0ID0gW107CiAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgc2l6ZTsgaSsrKSB7CiAgICAgICAgICAgICAgICByZXN1bHRbaV0gPSB0aGlzLmxvYWRTdHIoKTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGVzIGFuZCByZXR1cm5zIGEgYFZlYzJgIG9iamVjdCB3aXRoIHRoZSBuZXh0IHR3byBzaWduZWQgSW50MzIgdmFsdWVzIGluIHRoZSBidWZmZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyBhIFZlYzIuCiAgICAgICAgICovCiAgICAgICAgbG9hZFNJbnQzMlZlYzIoKSB7CiAgICAgICAgICAgIGNvbnN0IHggPSB0aGlzLmxvYWRTSW50MzIoKTsKICAgICAgICAgICAgY29uc3QgeSA9IHRoaXMubG9hZFNJbnQzMigpOwogICAgICAgICAgICByZXR1cm4gbmV3IFZlYzIoeCwgeSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgYW5kIHJldHVybnMgYSBgVmVjMmAgb2JqZWN0IHdpdGggdGhlIG5leHQgdHdvIHVuc2lnbmVkIEludDMyIHZhbHVlcyBpbiB0aGUgYnVmZmVyLgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGEgVmVjMi4KICAgICAgICAgKi8KICAgICAgICBsb2FkVUludDMyVmVjMigpIHsKICAgICAgICAgICAgY29uc3QgeCA9IHRoaXMubG9hZFVJbnQzMigpOwogICAgICAgICAgICBjb25zdCB5ID0gdGhpcy5sb2FkVUludDMyKCk7CiAgICAgICAgICAgIHJldHVybiBuZXcgVmVjMih4LCB5KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ3JlYXRlcyBhbmQgcmV0dXJucyBhIGBWZWMyYCBvYmplY3Qgd2l0aCB0aGUgbmV4dCB0d28gRmxvYXQxNiB2YWx1ZXMgaW4gdGhlIGJ1ZmZlci4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGEgVmVjMi4KICAgICAgICAgKi8KICAgICAgICBsb2FkRmxvYXQxNlZlYzIoKSB7CiAgICAgICAgICAgIGNvbnN0IHggPSB0aGlzLmxvYWRGbG9hdDE2KCk7CiAgICAgICAgICAgIGNvbnN0IHkgPSB0aGlzLmxvYWRGbG9hdDE2KCk7CiAgICAgICAgICAgIHJldHVybiBuZXcgVmVjMih4LCB5KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ3JlYXRlcyBhbmQgcmV0dXJucyBhIGBWZWMyYCBvYmplY3Qgd2l0aCB0aGUgbmV4dCB0d28gRmxvYXQzMiB2YWx1ZXMgaW4gdGhlIGJ1ZmZlci4KICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyBhIFZlYzIuCiAgICAgICAgICovCiAgICAgICAgbG9hZEZsb2F0MzJWZWMyKCkgewogICAgICAgICAgICBjb25zdCB4ID0gdGhpcy5sb2FkRmxvYXQzMigpOwogICAgICAgICAgICBjb25zdCB5ID0gdGhpcy5sb2FkRmxvYXQzMigpOwogICAgICAgICAgICByZXR1cm4gbmV3IFZlYzIoeCwgeSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgYW5kIHJldHVybnMgYSBgVmVjM2Agb2JqZWN0IHdpdGggdGhlIG5leHQgdGhyZWUgRmxvYXQxNiB2YWx1ZXMgaW4gdGhlIGJ1ZmZlci4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGEgVmVjMy4KICAgICAgICAgKi8KICAgICAgICBsb2FkRmxvYXQxNlZlYzMoKSB7CiAgICAgICAgICAgIGNvbnN0IHggPSB0aGlzLmxvYWRGbG9hdDE2KCk7CiAgICAgICAgICAgIGNvbnN0IHkgPSB0aGlzLmxvYWRGbG9hdDE2KCk7CiAgICAgICAgICAgIGNvbnN0IHogPSB0aGlzLmxvYWRGbG9hdDE2KCk7CiAgICAgICAgICAgIHJldHVybiBuZXcgVmVjMyh4LCB5LCB6KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ3JlYXRlcyBhbmQgcmV0dXJucyBhIGBWZWMzYCBvYmplY3Qgd2l0aCB0aGUgbmV4dCB0aHJlZSBGbG9hdDMyIHZhbHVlcyBpbiB0aGUgYnVmZmVyLgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgYSBWZWMzLgogICAgICAgICAqLwogICAgICAgIGxvYWRGbG9hdDMyVmVjMygpIHsKICAgICAgICAgICAgY29uc3QgeCA9IHRoaXMubG9hZEZsb2F0MzIoKTsKICAgICAgICAgICAgY29uc3QgeSA9IHRoaXMubG9hZEZsb2F0MzIoKTsKICAgICAgICAgICAgY29uc3QgeiA9IHRoaXMubG9hZEZsb2F0MzIoKTsKICAgICAgICAgICAgcmV0dXJuIG5ldyBWZWMzKHgsIHksIHopOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGVzIGFuZCByZXR1cm5zIGEgYFF1YXRgIG9iamVjdCB3aXRoIHRoZSBuZXh0IGZvdXIgRmxvYXQxNiB2YWx1ZXMgaW4gdGhlIGJ1ZmZlci4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGEgUXVhdC4KICAgICAgICAgKi8KICAgICAgICBsb2FkRmxvYXQxNlF1YXQoKSB7CiAgICAgICAgICAgIGNvbnN0IHggPSB0aGlzLmxvYWRGbG9hdDE2KCk7CiAgICAgICAgICAgIGNvbnN0IHkgPSB0aGlzLmxvYWRGbG9hdDE2KCk7CiAgICAgICAgICAgIGNvbnN0IHogPSB0aGlzLmxvYWRGbG9hdDE2KCk7CiAgICAgICAgICAgIGNvbnN0IHcgPSB0aGlzLmxvYWRGbG9hdDE2KCk7CiAgICAgICAgICAgIHJldHVybiBuZXcgUXVhdCh4LCB5LCB6LCB3KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ3JlYXRlcyBhbmQgcmV0dXJucyBhIGBRdWF0YCBvYmplY3Qgd2l0aCB0aGUgbmV4dCBmb3VyIEZsb2F0MzIgdmFsdWVzIGluIHRoZSBidWZmZXIuCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgYSBRdWF0LgogICAgICAgICAqLwogICAgICAgIGxvYWRGbG9hdDMyUXVhdCgpIHsKICAgICAgICAgICAgY29uc3QgeCA9IHRoaXMubG9hZEZsb2F0MzIoKTsKICAgICAgICAgICAgY29uc3QgeSA9IHRoaXMubG9hZEZsb2F0MzIoKTsKICAgICAgICAgICAgY29uc3QgeiA9IHRoaXMubG9hZEZsb2F0MzIoKTsKICAgICAgICAgICAgY29uc3QgdyA9IHRoaXMubG9hZEZsb2F0MzIoKTsKICAgICAgICAgICAgcmV0dXJuIG5ldyBRdWF0KHgsIHksIHosIHcpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGVzIGFuZCByZXR1cm5zIGEgYENvbG9yYCBvYmplY3Qgd2l0aCB0aGUgbmV4dCB0aHJlZSBGbG9hdDMyIHZhbHVlcyBpbiB0aGUgYnVmZmVyLgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiAtIFJldHVybnMgYSBDb2xvci4KICAgICAgICAgKi8KICAgICAgICBsb2FkUkdCRmxvYXQzMkNvbG9yKCkgewogICAgICAgICAgICBjb25zdCByID0gdGhpcy5sb2FkRmxvYXQzMigpOwogICAgICAgICAgICBjb25zdCBnID0gdGhpcy5sb2FkRmxvYXQzMigpOwogICAgICAgICAgICBjb25zdCBiID0gdGhpcy5sb2FkRmxvYXQzMigpOwogICAgICAgICAgICByZXR1cm4gbmV3IENvbG9yKHIsIGcsIGIpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGVzIGFuZCByZXR1cm5zIGEgUkdCQSBgQ29sb3JgIG9iamVjdCB3aXRoIHRoZSBuZXh0IGZvdXIgRmxvYXQzMiB2YWx1ZXMgaW4gdGhlIGJ1ZmZlci4KICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyBhIENvbG9yLgogICAgICAgICAqLwogICAgICAgIGxvYWRSR0JBRmxvYXQzMkNvbG9yKCkgewogICAgICAgICAgICBjb25zdCByID0gdGhpcy5sb2FkRmxvYXQzMigpOwogICAgICAgICAgICBjb25zdCBnID0gdGhpcy5sb2FkRmxvYXQzMigpOwogICAgICAgICAgICBjb25zdCBiID0gdGhpcy5sb2FkRmxvYXQzMigpOwogICAgICAgICAgICBjb25zdCBhID0gdGhpcy5sb2FkRmxvYXQzMigpOwogICAgICAgICAgICByZXR1cm4gbmV3IENvbG9yKHIsIGcsIGIsIGEpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGVzIGFuZCByZXR1cm5zIGEgYENvbG9yYCBvYmplY3Qgd2l0aCB0aGUgbmV4dCB0aHJlZSB1bnNpZ25lZCBJbnQ4IHZhbHVlcyBpbiB0aGUgYnVmZmVyLgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGEgQ29sb3IuCiAgICAgICAgICovCiAgICAgICAgbG9hZFJHQlVJbnQ4Q29sb3IoKSB7CiAgICAgICAgICAgIGNvbnN0IHIgPSB0aGlzLmxvYWRVSW50OCgpOwogICAgICAgICAgICBjb25zdCBnID0gdGhpcy5sb2FkVUludDgoKTsKICAgICAgICAgICAgY29uc3QgYiA9IHRoaXMubG9hZFVJbnQ4KCk7CiAgICAgICAgICAgIHJldHVybiBuZXcgQ29sb3IociAvIDI1NSwgZyAvIDI1NSwgYiAvIDI1NSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgYW5kIHJldHVybnMgYSBSR0JBIGBDb2xvcmAgb2JqZWN0IHdpdGggdGhlIG5leHQgZm91ciB1bnNpZ25lZCBJbnQ4IHZhbHVlcyBpbiB0aGUgYnVmZmVyLgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGEgQ29sb3IuCiAgICAgICAgICovCiAgICAgICAgbG9hZFJHQkFVSW50OENvbG9yKCkgewogICAgICAgICAgICBjb25zdCByID0gdGhpcy5sb2FkVUludDgoKTsKICAgICAgICAgICAgY29uc3QgZyA9IHRoaXMubG9hZFVJbnQ4KCk7CiAgICAgICAgICAgIGNvbnN0IGIgPSB0aGlzLmxvYWRVSW50OCgpOwogICAgICAgICAgICBjb25zdCBhID0gdGhpcy5sb2FkVUludDgoKTsKICAgICAgICAgICAgcmV0dXJuIG5ldyBDb2xvcihyIC8gMjU1LCBnIC8gMjU1LCBiIC8gMjU1LCBhIC8gMjU1KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ3JlYXRlcyBhbmQgcmV0dXJucyBhIGBCb3gyYCBvYmplY3Qgd2l0aCB0aGUgbmV4dCBmb3VyIEZsb2F0MzIgdmFsdWVzIGluIHRoZSBidWZmZXIuCiAgICAgICAgICogTmV4dCBmb3VyIGJlY2F1c2UgaXQgY3JlYXRlcyB0d28gVmVjMi4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4gLSBSZXR1cm5zIGEgQm94Mi4KICAgICAgICAgKi8KICAgICAgICBsb2FkQm94MigpIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBCb3gyKHRoaXMubG9hZEZsb2F0MzJWZWMyKCksIHRoaXMubG9hZEZsb2F0MzJWZWMyKCkpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGVzIGFuZCByZXR1cm5zIGEgYEJveDJgIG9iamVjdCB3aXRoIHRoZSBuZXh0IHNpeCBGbG9hdDMyIHZhbHVlcyBpbiB0aGUgYnVmZmVyLgogICAgICAgICAqIE5leHQgZm91ciBiZWNhdXNlIGl0IGNyZWF0ZXMgdHdvIFZlYzMuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIC0gUmV0dXJucyBhIEJveDMuCiAgICAgICAgICovCiAgICAgICAgbG9hZEJveDMoKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgQm94Myh0aGlzLmxvYWRGbG9hdDMyVmVjMygpLCB0aGlzLmxvYWRGbG9hdDMyVmVjMygpKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogR2l2ZW4gYSBzdHJpZGVlIHZhbHVlLCBhZHZhbmNlIHRoZSBwb2ludGVyIHRvIHRoZSBlbmQgb2YgdGhlIGN1cnJlbnQgc3RyaWRlLgogICAgICAgICAqIEBwYXJhbSBzdHJpZGUgLSBUaGUgc3RyaWRlIHBhcmFtLgogICAgICAgICAqLwogICAgICAgIHJlYWRQYWQoc3RyaWRlKSB7CiAgICAgICAgICAgIGNvbnN0IHBhZCA9IHRoaXMuX19ieXRlT2Zmc2V0ICUgc3RyaWRlOwogICAgICAgICAgICBpZiAocGFkICE9IDApCiAgICAgICAgICAgICAgICB0aGlzLl9fYnl0ZU9mZnNldCArPSBzdHJpZGUgLSBwYWQ7CiAgICAgICAgfQogICAgfQoKICAgIC8qKgogICAgICogQ2xhc3MgZGVzaWduZWQgdG8gc3RvcmUgdmVyc2lvbiBkYXRhLiBXaWRlbHkgdXNlZCBpbiB0aGUgemVhIGVuZ2luZSBmb3IgYmFja3dhcmRzIGNvbXBhdGliaWxpdHkuCiAgICAgKi8KICAgIGNsYXNzIFZlcnNpb24gewogICAgICAgIG1ham9yID0gMDsKICAgICAgICBtaW5vciA9IDA7CiAgICAgICAgcGF0Y2ggPSAwOwogICAgICAgIGJyYW5jaCA9ICcnOwogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgYSB2ZXJzaW9uLgogICAgICAgICAqIFRoZSB2ZXJzaW9uIHN0cmluZyBzaG91bGQgaGF2ZSB0aGUgZm9sbG93aW5nIHN0cnVjdHVyZToKICAgICAgICAgKiBtYWpvciwgbWlub3IgYW5kIHBhdGNoIHNlcGFyYXRlZCBieSBhIGRvdChgLmApIGFuZCBwYXJ0cyBzZXBhcmF0ZWQgYnkgYSBkYXNoKGAtYCkuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0gYXJnIC0gVGhlIHZlcnNpb24gc3RyaW5nIHZhbHVlLCBvciBhbiBhcnJheSBvZiB2ZXJzaW9uIG51bWJlcnMuCiAgICAgICAgICovCiAgICAgICAgY29uc3RydWN0b3IoYXJnKSB7CiAgICAgICAgICAgIGlmICh0eXBlb2YgYXJnID09ICdzdHJpbmcnKSB7CiAgICAgICAgICAgICAgICBjb25zdCBwYXJ0cyA9IGFyZy5zcGxpdCgnLScpOwogICAgICAgICAgICAgICAgY29uc3QgbnVtYmVycyA9IHBhcnRzWzBdLnNwbGl0KCcuJyk7CiAgICAgICAgICAgICAgICB0aGlzLm1ham9yID0gcGFyc2VJbnQobnVtYmVyc1swXSk7CiAgICAgICAgICAgICAgICB0aGlzLm1pbm9yID0gbnVtYmVycy5sZW5ndGggPiAxID8gcGFyc2VJbnQobnVtYmVyc1sxXSkgOiAwOwogICAgICAgICAgICAgICAgdGhpcy5wYXRjaCA9IG51bWJlcnMubGVuZ3RoID4gMiA/IHBhcnNlSW50KG51bWJlcnNbMl0pIDogMDsKICAgICAgICAgICAgICAgIGlmIChwYXJ0cy5sZW5ndGggPT0gMikKICAgICAgICAgICAgICAgICAgICB0aGlzLmJyYW5jaCA9IHBhcnRzWzFdOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGVsc2UgaWYgKEFycmF5LmlzQXJyYXkoYXJnKSkgewogICAgICAgICAgICAgICAgY29uc3QgbnVtYmVycyA9IGFyZzsKICAgICAgICAgICAgICAgIHRoaXMubWFqb3IgPSBudW1iZXJzWzBdOwogICAgICAgICAgICAgICAgdGhpcy5taW5vciA9IG51bWJlcnMubGVuZ3RoID4gMSA/IG51bWJlcnNbMV0gOiAwOwogICAgICAgICAgICAgICAgdGhpcy5wYXRjaCA9IG51bWJlcnMubGVuZ3RoID4gMiA/IG51bWJlcnNbMl0gOiAwOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXBhcmUgYSB2ZXJzaW9uIG9iamVjdCBhZ2FpbnN0IGEgdmVyc2lvbiBudW1iZXJzIGFycmF5LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIG51bWJlcnMgLSBBbiBhcnJheSBjb250YWluaW5nIDMgdmVyc2lvbiBudW1iZXJzLiBbTWFqb3IsIE1pbm9yLCBQYXRjaF0KICAgICAgICAgKiBAcmV0dXJuIC0gcmV0dXJuIHBvc2l0aXZlOiB2MSA+IHYyLCB6ZXJvOnYxID09IHYyLCBuZWdhdGl2ZTogdjEgPCB2MgogICAgICAgICAqLwogICAgICAgIGNvbXBhcmUobnVtYmVycykgewogICAgICAgICAgICAvLyBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy82ODMyNTk2L2hvdy10by1jb21wYXJlLXNvZnR3YXJlLXZlcnNpb24tbnVtYmVyLXVzaW5nLWpzLW9ubHktbnVtYmVyCiAgICAgICAgICAgIC8vIDJuZCBhbnN3ZXIuCiAgICAgICAgICAgIGNvbnN0IHYxID0gW3RoaXMubWFqb3IsIHRoaXMubWlub3IsIHRoaXMucGF0Y2hdOwogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IDM7IGkrKykgewogICAgICAgICAgICAgICAgaWYgKHYxW2ldICE9PSBudW1iZXJzW2ldKQogICAgICAgICAgICAgICAgICAgIHJldHVybiB2MVtpXSAtIG51bWJlcnNbaV07CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIDA7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbnZlcnRzIHRoZSBWZXJzaW9uIGNsYXNzIGluc3RhbmNlIGJhY2sgdG8gYW4gYXJyYXkgZm9yIGNvbXBhcmlzb25zIHdpdGggb3RoZXIgdmVyc2lvbiBjbGFzcyBpbnN0YW5jZXMuCiAgICAgICAgICogZS5nLgogICAgICAgICAqIGBgYAogICAgICAgICAqICAgY29uc3QgdmVyc2lvbjEgPSBuZXcgVmVyc2lvbihbMSwgMiwgM10pCiAgICAgICAgICogICBjb25zdCB2ZXJzaW9uMiA9IG5ldyBWZXJzaW9uKFsxLCAyLCA0XSkKICAgICAgICAgKiAgIGNvbnN0IHJlcyA9IHZlcnNpb24xLmNvbXBhcmUodmVyc2lvbjIuYXNBcnJheSgpKQogICAgICAgICAqIGBgYAogICAgICAgICAqIEByZXR1cm5zIGFuIGFycmF5IGNvbnRhaW5pbmcgdGhlIG1ham9yLCBtaW5vciBhbmQgcGF0Y2ggdmVyc2lvbiBudW1iZXJzLgogICAgICAgICAqLwogICAgICAgIGFzQXJyYXkoKSB7CiAgICAgICAgICAgIHJldHVybiBbdGhpcy5tYWpvciwgdGhpcy5taW5vciwgdGhpcy5wYXRjaF07CiAgICAgICAgfQogICAgICAgIHRvU3RyaW5nKCkgewogICAgICAgICAgICByZXR1cm4gYHYke3RoaXMubWFqb3J9LiR7dGhpcy5taW5vcn0uJHt0aGlzLnBhdGNofWAgKyAodGhpcy5icmFuY2ggIT0gJycgPyBgLSR7dGhpcy5icmFuY2h9YCA6ICcnKTsKICAgICAgICB9CiAgICB9CgogICAgLyoqCiAgICAgKiBAcHJpdmF0ZQogICAgICogQGV4dGVuZHMgQmFzZUdlb20KICAgICAqLwogICAgY2xhc3MgQ29tcG91bmRHZW9tTG9hZGVyIGV4dGVuZHMgQmFzZUdlb20gewogICAgICAgIG51bVN1Ykdlb21zID0gMDsKICAgICAgICBpbmRpY2VzID0gbmV3IFVpbnQ4QXJyYXkoMCk7CiAgICAgICAgb2Zmc2V0cyA9IHt9OwogICAgICAgIGNvdW50cyA9IHt9OwogICAgICAgIC8vIEZvciBlYWNoIHR5cGUgb2YgZ2VvbSAoVFJJQU5HTEVTLCBMSU5FUykKICAgICAgICAvLyBBIG1hdGVyaWFsIGlkLCBhbmQgZWFjaCBzdGFydCBhbmQgZW5kIG9mIHRoZSBibG9jawogICAgICAgIG1hdGVyaWFsU3ViR2VvbXMgPSB7fTsKICAgICAgICBzdWJHZW9tT2Zmc2V0cyA9IHt9OwogICAgICAgIHN1Ykdlb21Db3VudHMgPSB7fTsKICAgICAgICBtYXRlcmlhbExpYnJhcnlJbmRpY2VzID0gbmV3IFVpbnQzMkFycmF5KDApOwogICAgICAgIHN1Ykdlb21NYXRlcmlhbEluZGljZXMgPSBuZXcgVWludDhBcnJheSgwKTsKICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGUgcG9pbnRzLgogICAgICAgICAqLwogICAgICAgIGNvbnN0cnVjdG9yKCkgewogICAgICAgICAgICBzdXBlcigpOwogICAgICAgIH0KICAgICAgICBnZW5CdWZmZXJzKCkgewogICAgICAgICAgICBjb25zdCBhdHRyQnVmZmVycyA9IHt9OwogICAgICAgICAgICBmb3IgKGNvbnN0IFthdHRyTmFtZSwgYXR0cl0gb2YgdGhpcy5fX3ZlcnRleEF0dHJpYnV0ZXMpIHsKICAgICAgICAgICAgICAgIGF0dHJCdWZmZXJzW2F0dHJOYW1lXSA9IGF0dHIuZ2VuQnVmZmVyKCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgY29uc3QgbnVtVmVydGljZXMgPSB0aGlzLm51bVZlcnRpY2VzKCk7CiAgICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IHsKICAgICAgICAgICAgICAgIG51bVZlcnRpY2VzLAogICAgICAgICAgICAgICAgbnVtUmVuZGVyVmVydHM6IG51bVZlcnRpY2VzLAogICAgICAgICAgICAgICAgaW5kaWNlczogdGhpcy5pbmRpY2VzLAogICAgICAgICAgICAgICAgYXR0ckJ1ZmZlcnMsCiAgICAgICAgICAgICAgICBvZmZzZXRzOiB0aGlzLm9mZnNldHMsCiAgICAgICAgICAgICAgICBjb3VudHM6IHRoaXMuY291bnRzLAogICAgICAgICAgICAgICAgbnVtU3ViR2VvbXM6IHRoaXMubnVtU3ViR2VvbXMsCiAgICAgICAgICAgICAgICBzdWJHZW9tT2Zmc2V0czogdGhpcy5zdWJHZW9tT2Zmc2V0cywKICAgICAgICAgICAgICAgIHN1Ykdlb21Db3VudHM6IHRoaXMuc3ViR2VvbUNvdW50cywKICAgICAgICAgICAgICAgIG1hdGVyaWFsTGlicmFyeUluZGljZXM6IHRoaXMubWF0ZXJpYWxMaWJyYXJ5SW5kaWNlcywKICAgICAgICAgICAgICAgIHN1Ykdlb21NYXRlcmlhbEluZGljZXM6IHRoaXMuc3ViR2VvbU1hdGVyaWFsSW5kaWNlcywKICAgICAgICAgICAgICAgIG1hdGVyaWFsU3ViR2VvbXM6IHRoaXMubWF0ZXJpYWxTdWJHZW9tcywKICAgICAgICAgICAgfTsKICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLy8gLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwogICAgICAgIC8vIFBlcnNpc3RlbmNlCiAgICAgICAgLyoqCiAgICAgICAgICogU2V0cyBzdGF0ZSBvZiBjdXJyZW50IGdlb21ldHJ5KEluY2x1ZGluZyBsaW5lIHNlZ21lbnRzKSB1c2luZyBhIGJpbmFyeSByZWFkZXIgb2JqZWN0LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtCaW5SZWFkZXJ9IHJlYWRlciAtIFRoZSByZWFkZXIgdmFsdWUuCiAgICAgICAgICogQHBhcmFtIHtSZWNvcmQ8c3RyaW5nLCB1bmtub3duPn0gY29udGV4dCAtIFRoZSBjb250ZXh0IHZhbHVlLgogICAgICAgICAqLwogICAgICAgIHJlYWRCaW5hcnkocmVhZGVyLCBjb250ZXh0KSB7CiAgICAgICAgICAgIHN1cGVyLmxvYWRCYXNlR2VvbUJpbmFyeShyZWFkZXIsIGNvbnRleHQpOwogICAgICAgICAgICBjb25zdCBnZW9tQ291bnRzQnlUeXBlID0gcmVhZGVyLmxvYWRVSW50MzJBcnJheSgzKTsKICAgICAgICAgICAgdGhpcy5vZmZzZXRzWydUUklBTkdMRVMnXSA9IDA7CiAgICAgICAgICAgIHRoaXMuY291bnRzWydUUklBTkdMRVMnXSA9IGdlb21Db3VudHNCeVR5cGVbMF07CiAgICAgICAgICAgIHRoaXMub2Zmc2V0c1snTElORVMnXSA9IGdlb21Db3VudHNCeVR5cGVbMF07CiAgICAgICAgICAgIHRoaXMuY291bnRzWydMSU5FUyddID0gZ2VvbUNvdW50c0J5VHlwZVsxXTsKICAgICAgICAgICAgdGhpcy5vZmZzZXRzWydQT0lOVFMnXSA9IGdlb21Db3VudHNCeVR5cGVbMF0gKyBnZW9tQ291bnRzQnlUeXBlWzFdOwogICAgICAgICAgICB0aGlzLmNvdW50c1snUE9JTlRTJ10gPSBnZW9tQ291bnRzQnlUeXBlWzJdOwogICAgICAgICAgICBjb25zdCBieXRlcyA9IHJlYWRlci5sb2FkVUludDgoKTsKICAgICAgICAgICAgLy8gTm90ZTogZG8gbm90IGNsb25lIHRoZSBzb3VyY2UgYXJyYXlzIGFzIHdlIHdpbGwgdHJhbnNmZXIgdGhlCiAgICAgICAgICAgIC8vIGVudGlyZSBidWZmZXIgYmFjayB0byB0aGUgbWFpbiB0aHJlYWQgd2hlcmUgaXQgd2lsbCBiZSBmcmVlZCBvbmNlCiAgICAgICAgICAgIC8vIHRoZSBkYXRhIGlzIHVwbG9hZGVkIHRvIHRoZSBHUFUuCiAgICAgICAgICAgIGlmIChieXRlcyA9PSAxKQogICAgICAgICAgICAgICAgdGhpcy5pbmRpY2VzID0gcmVhZGVyLmxvYWRVSW50OEFycmF5KCk7CiAgICAgICAgICAgIGVsc2UgaWYgKGJ5dGVzID09IDIpCiAgICAgICAgICAgICAgICB0aGlzLmluZGljZXMgPSByZWFkZXIubG9hZFVJbnQxNkFycmF5KCk7CiAgICAgICAgICAgIGVsc2UgaWYgKGJ5dGVzID09IDQpCiAgICAgICAgICAgICAgICB0aGlzLmluZGljZXMgPSByZWFkZXIubG9hZFVJbnQzMkFycmF5KCk7CiAgICAgICAgICAgIC8vIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwogICAgICAgICAgICAvLyBUUklBTkdMRVMgc3ViZ2VvbXMKICAgICAgICAgICAgY29uc3QgYnl0ZXNNZXNoU3ViR2VvbXMgPSByZWFkZXIubG9hZFVJbnQ4KCk7CiAgICAgICAgICAgIGxldCBzdWJHZW9tQ291bnRzTWVzaDsKICAgICAgICAgICAgaWYgKGJ5dGVzTWVzaFN1Ykdlb21zID09IDEpCiAgICAgICAgICAgICAgICBzdWJHZW9tQ291bnRzTWVzaCA9IHJlYWRlci5sb2FkVUludDhBcnJheSgpOwogICAgICAgICAgICBlbHNlIGlmIChieXRlc01lc2hTdWJHZW9tcyA9PSAyKQogICAgICAgICAgICAgICAgc3ViR2VvbUNvdW50c01lc2ggPSByZWFkZXIubG9hZFVJbnQxNkFycmF5KCk7CiAgICAgICAgICAgIGVsc2UgaWYgKGJ5dGVzTWVzaFN1Ykdlb21zID09IDQpCiAgICAgICAgICAgICAgICBzdWJHZW9tQ291bnRzTWVzaCA9IHJlYWRlci5sb2FkVUludDMyQXJyYXkoKTsKICAgICAgICAgICAgZWxzZSB7CiAgICAgICAgICAgICAgICB0aHJvdyBFcnJvcignc3ViR2VvbU9mZnNldHMgdW5kZWZpbmVkJyk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgY29uc3Qgc3ViR2VvbU9mZnNldHNNZXNoID0gbmV3IFVpbnQzMkFycmF5KHN1Ykdlb21Db3VudHNNZXNoLmxlbmd0aCk7CiAgICAgICAgICAgIGxldCBvZmZzZXQgPSAwOwogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHN1Ykdlb21Db3VudHNNZXNoLmxlbmd0aDsgaSsrKSB7CiAgICAgICAgICAgICAgICBzdWJHZW9tT2Zmc2V0c01lc2hbaV0gPSBvZmZzZXQ7CiAgICAgICAgICAgICAgICBvZmZzZXQgKz0gc3ViR2VvbUNvdW50c01lc2hbaV07CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdGhpcy5zdWJHZW9tT2Zmc2V0c1snVFJJQU5HTEVTJ10gPSBzdWJHZW9tT2Zmc2V0c01lc2g7CiAgICAgICAgICAgIHRoaXMuc3ViR2VvbUNvdW50c1snVFJJQU5HTEVTJ10gPSBzdWJHZW9tQ291bnRzTWVzaDsKICAgICAgICAgICAgLy8gLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCiAgICAgICAgICAgIC8vIExJTkVTIHN1Ymdlb21zCiAgICAgICAgICAgIGNvbnN0IGJ5dGVzTGluZXNTdWJHZW9tcyA9IHJlYWRlci5sb2FkVUludDgoKTsKICAgICAgICAgICAgbGV0IHN1Ykdlb21Db3VudHNMaW5lczsKICAgICAgICAgICAgaWYgKGJ5dGVzTGluZXNTdWJHZW9tcyA9PSAxKQogICAgICAgICAgICAgICAgc3ViR2VvbUNvdW50c0xpbmVzID0gcmVhZGVyLmxvYWRVSW50OEFycmF5KCk7CiAgICAgICAgICAgIGVsc2UgaWYgKGJ5dGVzTGluZXNTdWJHZW9tcyA9PSAyKQogICAgICAgICAgICAgICAgc3ViR2VvbUNvdW50c0xpbmVzID0gcmVhZGVyLmxvYWRVSW50MTZBcnJheSgpOwogICAgICAgICAgICBlbHNlIGlmIChieXRlc0xpbmVzU3ViR2VvbXMgPT0gNCkKICAgICAgICAgICAgICAgIHN1Ykdlb21Db3VudHNMaW5lcyA9IHJlYWRlci5sb2FkVUludDMyQXJyYXkoKTsKICAgICAgICAgICAgZWxzZSB7CiAgICAgICAgICAgICAgICB0aHJvdyBFcnJvcignc3ViR2VvbU9mZnNldHMgdW5kZWZpbmVkJyk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgY29uc3Qgc3ViR2VvbU9mZnNldHNMaW5lcyA9IG5ldyBVaW50MzJBcnJheShzdWJHZW9tQ291bnRzTGluZXMubGVuZ3RoKTsKICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzdWJHZW9tQ291bnRzTGluZXMubGVuZ3RoOyBpKyspIHsKICAgICAgICAgICAgICAgIHN1Ykdlb21PZmZzZXRzTGluZXNbaV0gPSBvZmZzZXQ7CiAgICAgICAgICAgICAgICBvZmZzZXQgKz0gc3ViR2VvbUNvdW50c0xpbmVzW2ldOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHRoaXMuc3ViR2VvbU9mZnNldHNbJ0xJTkVTJ10gPSBzdWJHZW9tT2Zmc2V0c0xpbmVzOwogICAgICAgICAgICB0aGlzLnN1Ykdlb21Db3VudHNbJ0xJTkVTJ10gPSBzdWJHZW9tQ291bnRzTGluZXM7CiAgICAgICAgICAgIC8vIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwogICAgICAgICAgICAvLyBQT0lOVFMgc3ViZ2VvbXMKICAgICAgICAgICAgY29uc3QgbnVtUG9pbnRzU3ViR2VvbXMgPSByZWFkZXIubG9hZFVJbnQzMigpOwogICAgICAgICAgICBjb25zdCBzdWJHZW9tT2Zmc2V0c1BvaW50cyA9IG5ldyBVaW50MzJBcnJheShudW1Qb2ludHNTdWJHZW9tcyk7CiAgICAgICAgICAgIGNvbnN0IHN1Ykdlb21Db3VudHNQb2ludHMgPSBuZXcgVWludDhBcnJheShudW1Qb2ludHNTdWJHZW9tcyk7CiAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbnVtUG9pbnRzU3ViR2VvbXM7IGkrKykgewogICAgICAgICAgICAgICAgc3ViR2VvbU9mZnNldHNQb2ludHNbaV0gPSBvZmZzZXQ7CiAgICAgICAgICAgICAgICBzdWJHZW9tQ291bnRzUG9pbnRzW2ldID0gMTsKICAgICAgICAgICAgICAgIG9mZnNldCsrOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHRoaXMuc3ViR2VvbU9mZnNldHNbJ1BPSU5UUyddID0gc3ViR2VvbU9mZnNldHNQb2ludHM7CiAgICAgICAgICAgIHRoaXMuc3ViR2VvbUNvdW50c1snUE9JTlRTJ10gPSBzdWJHZW9tQ291bnRzUG9pbnRzOwogICAgICAgICAgICBpZiAoY29udGV4dC52ZXJzaW9uc1snemVhLWVuZ2luZSddLmNvbXBhcmUoWzMsIDExLCAwXSkgPiAwKSB7CiAgICAgICAgICAgICAgICAvLyBQb2ludHMgc3ViLWdlb21zIHdlcmUgbm90IGJlaW5nIGV4cG9ydGVkIGJlZm9yZSB0aGlzIHJlbGVhc2UuCiAgICAgICAgICAgICAgICB0aGlzLm51bVN1Ykdlb21zID0gc3ViR2VvbUNvdW50c01lc2gubGVuZ3RoICsgc3ViR2VvbUNvdW50c0xpbmVzLmxlbmd0aCArIG51bVBvaW50c1N1Ykdlb21zOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGVsc2UgewogICAgICAgICAgICAgICAgdGhpcy5udW1TdWJHZW9tcyA9IHN1Ykdlb21Db3VudHNNZXNoLmxlbmd0aCArIHN1Ykdlb21Db3VudHNMaW5lcy5sZW5ndGg7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLy8gLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCiAgICAgICAgICAgIC8vIE1hdGVyaWFscwogICAgICAgICAgICBjb25zdCBudW1NYXRlcmlhbHMgPSByZWFkZXIubG9hZFVJbnQzMigpOwogICAgICAgICAgICBpZiAobnVtTWF0ZXJpYWxzID4gMCkgewogICAgICAgICAgICAgICAgdGhpcy5tYXRlcmlhbExpYnJhcnlJbmRpY2VzID0gcmVhZGVyLmxvYWRVSW50MzJBcnJheShudW1NYXRlcmlhbHMpOwogICAgICAgICAgICAgICAgdGhpcy5zdWJHZW9tTWF0ZXJpYWxJbmRpY2VzID0gcmVhZGVyLmxvYWRVSW50OEFycmF5KHRoaXMubnVtU3ViR2VvbXMpOwogICAgICAgICAgICAgICAgLy8gLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCiAgICAgICAgICAgICAgICAvLyBNYXRlcmlhbCBHcm91cHMKICAgICAgICAgICAgICAgIGxldCBvZmZzZXQgPSAwOwogICAgICAgICAgICAgICAgbGV0IGN1cnJNYXRlcmlhbCA9IC05OTsKICAgICAgICAgICAgICAgIGxldCBjdXJyTWF0ZXJpYWxTdWJHZW9tID0gbnVsbDsKICAgICAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5udW1TdWJHZW9tczsgaSsrKSB7CiAgICAgICAgICAgICAgICAgICAgbGV0IGtleTsKICAgICAgICAgICAgICAgICAgICBsZXQgc3ViR2VvbU9mZnNldCA9IDA7CiAgICAgICAgICAgICAgICAgICAgaWYgKGkgPCB0aGlzLnN1Ykdlb21Db3VudHMuVFJJQU5HTEVTLmxlbmd0aCkgewogICAgICAgICAgICAgICAgICAgICAgICBpZiAoIXRoaXMubWF0ZXJpYWxTdWJHZW9tcy5UUklBTkdMRVMpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLm1hdGVyaWFsU3ViR2VvbXMuVFJJQU5HTEVTID0gW107CiAgICAgICAgICAgICAgICAgICAgICAgIGtleSA9ICdUUklBTkdMRVMnOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBlbHNlIGlmIChpIDwgdGhpcy5zdWJHZW9tQ291bnRzLlRSSUFOR0xFUy5sZW5ndGggKyB0aGlzLnN1Ykdlb21Db3VudHMuTElORVMubGVuZ3RoKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHN1Ykdlb21PZmZzZXQgPSB0aGlzLnN1Ykdlb21Db3VudHMuVFJJQU5HTEVTLmxlbmd0aDsKICAgICAgICAgICAgICAgICAgICAgICAga2V5ID0gJ0xJTkVTJzsKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCF0aGlzLm1hdGVyaWFsU3ViR2VvbXMuTElORVMpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLm1hdGVyaWFsU3ViR2VvbXMuTElORVMgPSBbXTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHN1Ykdlb21PZmZzZXQgPSB0aGlzLnN1Ykdlb21Db3VudHMuVFJJQU5HTEVTLmxlbmd0aCArIHRoaXMuc3ViR2VvbUNvdW50cy5MSU5FUy5sZW5ndGg7CiAgICAgICAgICAgICAgICAgICAgICAgIGtleSA9ICdQT0lOVFMnOwogICAgICAgICAgICAgICAgICAgICAgICBpZiAoIXRoaXMubWF0ZXJpYWxTdWJHZW9tcy5QT0lOVFMpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLm1hdGVyaWFsU3ViR2VvbXMuUE9JTlRTID0gW107CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIGNvbnN0IG1hdGVyaWFsSWQgPSB0aGlzLnN1Ykdlb21NYXRlcmlhbEluZGljZXNbaV07CiAgICAgICAgICAgICAgICAgICAgaWYgKGN1cnJNYXRlcmlhbCAhPSBtYXRlcmlhbElkKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJNYXRlcmlhbCA9IG1hdGVyaWFsSWQ7CiAgICAgICAgICAgICAgICAgICAgICAgIC8vIE5vdGU6IHN1Ykdlb21NYXRlcmlhbEluZGljZXMgaXMgVWludDhBcnJheSwgYW5kIDAgbWVhbnMgbm8gY3VzdG9tCiAgICAgICAgICAgICAgICAgICAgICAgIC8vIG1hdGVyaWFsIGlzIGFzc2lnbmVkIHRvIHRoZSBzdWJHZW9tLgogICAgICAgICAgICAgICAgICAgICAgICAvLyBTdWJ0cmFjdCAxIHRvIGdldCB0aGUgYWN0dWFsIG1hdGVyaWFsIGlkLgogICAgICAgICAgICAgICAgICAgICAgICBjdXJyTWF0ZXJpYWxTdWJHZW9tID0gewogICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF0ZXJpYWxJZDogbWF0ZXJpYWxJZCAtIDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvZmZzZXQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3VudDogMCwKICAgICAgICAgICAgICAgICAgICAgICAgfTsKICAgICAgICAgICAgICAgICAgICAgICAgZm9yICg7IGkgPCB0aGlzLm51bVN1Ykdlb21zOyBpKyspIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChjdXJyTWF0ZXJpYWwgIT0gdGhpcy5zdWJHZW9tTWF0ZXJpYWxJbmRpY2VzW2ldKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBXaGVuIHdlIGdldCB0byB0aGUgZW5kIG9nIHRoaXMgZ2VvbSB0eXBlIChlLmcgLlRSSUFOR0xFUykKICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHN0YXJ0IGEgbmV3IHN1Ymdlb20uCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoaSAtIHN1Ykdlb21PZmZzZXQgPT0gdGhpcy5zdWJHZW9tQ291bnRzW2tleV0ubGVuZ3RoKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gRm9yY2UgdGhlIG1hdGVyaWFsIGluZGV4IHRvIGJlIHJlc2V0IG9uIGxpbmUgMTYyIGFib3ZlLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJNYXRlcmlhbCA9IC05OTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJNYXRlcmlhbFN1Ykdlb20uY291bnQgKz0gdGhpcy5zdWJHZW9tQ291bnRzW2tleV1baSAtIHN1Ykdlb21PZmZzZXRdOwogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgIG9mZnNldCArPSBjdXJyTWF0ZXJpYWxTdWJHZW9tLmNvdW50OwogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLm1hdGVyaWFsU3ViR2VvbXNba2V5XS5wdXNoKGN1cnJNYXRlcmlhbFN1Ykdlb20pOwogICAgICAgICAgICAgICAgICAgICAgICBpLS07CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgLy8gTm90ZTogb2xkZXIgdmVyc2lvbiBvZiB6Y2FkIGZpbGVzIHdvdWxkIGxpc3QgbWF0ZXJpYWxzIGZvciBUUklBTkdMRVMgYW5kIExJTkVTLAogICAgICAgICAgICAgICAgLy8gYnV0IG5vdCBwb2ludHMsIGxlYXZpbmcgdGhlIHBvaW50cyB1bnJlbmRlcmVkLgogICAgICAgICAgICAgICAgaWYgKHRoaXMuc3ViR2VvbUNvdW50cy5QT0lOVFMubGVuZ3RoID4gMCAmJiAhdGhpcy5tYXRlcmlhbFN1Ykdlb21zLlBPSU5UUykgewogICAgICAgICAgICAgICAgICAgIHRoaXMubWF0ZXJpYWxTdWJHZW9tcy5QT0lOVFMgPSBbCiAgICAgICAgICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hdGVyaWFsSWQ6IC0xLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgb2Zmc2V0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgY291bnQ6IHRoaXMuc3ViR2VvbUNvdW50cy5QT0lOVFMubGVuZ3RoLAogICAgICAgICAgICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICAgICAgIF07CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZWxzZSB7CiAgICAgICAgICAgICAgICB0aGlzLm1hdGVyaWFsU3ViR2VvbXMgPSB7fTsKICAgICAgICAgICAgICAgIGxldCBvZmZzZXQgPSAwOwogICAgICAgICAgICAgICAgZm9yIChsZXQga2V5IGluIHRoaXMuY291bnRzKSB7CiAgICAgICAgICAgICAgICAgICAgY29uc3QgY291bnQgPSB0aGlzLmNvdW50c1trZXldOwogICAgICAgICAgICAgICAgICAgIGlmIChjb3VudCA+IDApIHsKICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5tYXRlcmlhbFN1Ykdlb21zW2tleV0gPSBbCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF0ZXJpYWxJZDogLTEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2Zmc2V0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvdW50LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAgICAgICAgICAgXTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgb2Zmc2V0ICs9IGNvdW50OwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIHRoaXMuZW1pdCgnZ2VvbURhdGFDaGFuZ2VkJywge30pOwogICAgICAgIH0KICAgIH0KCiAgICAvKiBlc2xpbnQtZGlzYWJsZSBndWFyZC1mb3ItaW4gKi8KICAgIC8vIGtleSwgdG9jLCBnZW9tSW5kZXhPZmZzZXQsIGdlb21zUmFuZ2UsIGlzTW9iaWxlRGV2aWNlLCBidWZmZXJTbGljZSwgZ2VuQnVmZmVyc09wdHMsIGNvbnRleHQKICAgIGNvbnN0IHBhcnNlR2VvbXNCaW5hcnkgPSAoZGF0YSwgY2FsbGJhY2spID0+IHsKICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZ3VhcmQtZm9yLWluCiAgICAgICAgZm9yIChjb25zdCBrZXkgaW4gZGF0YS5jb250ZXh0LnZlcnNpb25zKSB7CiAgICAgICAgICAgIGNvbnN0IHYgPSBkYXRhLmNvbnRleHQudmVyc2lvbnNba2V5XTsKICAgICAgICAgICAgY29uc3QgdmVyc2lvbiA9IG5ldyBWZXJzaW9uKCcnKTsKICAgICAgICAgICAgdmVyc2lvbi5tYWpvciA9IHYubWFqb3I7CiAgICAgICAgICAgIHZlcnNpb24ubWlub3IgPSB2Lm1pbm9yOwogICAgICAgICAgICB2ZXJzaW9uLnBhdGNoID0gdi5wYXRjaDsKICAgICAgICAgICAgdmVyc2lvbi5icmFuY2ggPSB2LmJyYW5jaDsKICAgICAgICAgICAgZGF0YS5jb250ZXh0LnZlcnNpb25zW2tleV0gPSB2ZXJzaW9uOwogICAgICAgIH0KICAgICAgICBjb25zdCBnZW9tRGF0YXMgPSBbXTsKICAgICAgICBjb25zdCBieXRlT2Zmc2V0ID0gZGF0YS5ieXRlT2Zmc2V0OwogICAgICAgIC8vIGNvbnNvbGUubG9nKCdieXRlT2Zmc2V0OicgKyBieXRlT2Zmc2V0LCAnIGdlb21zUmFuZ2U6JywgZGF0YS5nZW9tc1JhbmdlKQogICAgICAgIGNvbnN0IHRyYW5zZmVyYWJsZXMgPSBbXTsKICAgICAgICBmb3IgKGxldCBpID0gZGF0YS5nZW9tc1JhbmdlWzBdOyBpIDwgZGF0YS5nZW9tc1JhbmdlWzFdOyBpKyspIHsKICAgICAgICAgICAgY29uc3QgcmVhZGVyID0gbmV3IEJpblJlYWRlcihkYXRhLmJ1ZmZlclNsaWNlLCBkYXRhLnRvY1tpXSAtIGJ5dGVPZmZzZXQsIGRhdGEuaXNNb2JpbGVEZXZpY2UpOwogICAgICAgICAgICBjb25zdCBjbGFzc05hbWUgPSByZWFkZXIubG9hZFN0cigpOwogICAgICAgICAgICBjb25zdCBwb3MgPSByZWFkZXIucG9zKCk7CiAgICAgICAgICAgIC8vIGNvbnN0IG5hbWUgPSByZWFkZXIubG9hZFN0cigpCiAgICAgICAgICAgIC8vIGNvbnNvbGUubG9nKAogICAgICAgICAgICAvLyAgIGkgKwogICAgICAgICAgICAvLyAgICAgJzonICsKICAgICAgICAgICAgLy8gICAgIGJ5dGVPZmZzZXQgKwogICAgICAgICAgICAvLyAgICAgJyBjbGFzc05hbWU6JyArCiAgICAgICAgICAgIC8vICAgICBjbGFzc05hbWUgKwogICAgICAgICAgICAvLyAgICAgJyBuYW1lOicgKwogICAgICAgICAgICAvLyAgICAgbmFtZSAvKiArICIgcG9zOiIgKyAoZGF0YS50b2NbaV0gLSBieXRlT2Zmc2V0KSArICIgYnVmZmVyU2xpY2UuYnl0ZUxlbmd0aDoiICsgIGJ1ZmZlclNsaWNlLmJ5dGVMZW5ndGgqLwogICAgICAgICAgICAvLyApCiAgICAgICAgICAgIGxldCBnZW9tOwogICAgICAgICAgICBzd2l0Y2ggKGNsYXNzTmFtZSkgewogICAgICAgICAgICAgICAgY2FzZSAnUG9pbnRzJzoKICAgICAgICAgICAgICAgICAgICBnZW9tID0gbmV3IFBvaW50cygpOwogICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgY2FzZSAnTGluZXMnOgogICAgICAgICAgICAgICAgICAgIGdlb20gPSBuZXcgTGluZXMoKTsKICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIGNhc2UgJ01lc2gnOgogICAgICAgICAgICAgICAgICAgIGdlb20gPSBuZXcgTWVzaCgpOwogICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgY2FzZSAnQ29tcG91bmRHZW9tJzoKICAgICAgICAgICAgICAgICAgICBnZW9tID0gbmV3IENvbXBvdW5kR2VvbUxvYWRlcigpOwogICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgZGVmYXVsdDoKICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1Vuc3VwcG9ydGVkIEdlb20gdHlwZTonICsgY2xhc3NOYW1lKTsKICAgICAgICAgICAgfQogICAgICAgICAgICB0cnkgewogICAgICAgICAgICAgICAgcmVhZGVyLnNlZWsocG9zKTsgLy8gUmVzZXQgdGhlIHBvaW50ZXIgdG8gdGhlIHN0YXJ0IG9mIHRoZSBpdGVtIGRhdGEuCiAgICAgICAgICAgICAgICBnZW9tLnJlYWRCaW5hcnkocmVhZGVyLCBkYXRhLmNvbnRleHQpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGNhdGNoIChlKSB7CiAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oJ0Vycm9yIGxvYWRpbmc6JyArIGdlb20ubmFtZSArICdcbjonICsgZSk7CiAgICAgICAgICAgICAgICBnZW9tRGF0YXMucHVzaCh7fSk7CiAgICAgICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgICAgfQogICAgICAgICAgICBjb25zdCBnZW9tQnVmZmVycyA9IGdlb20uZ2VuQnVmZmVycyhkYXRhLmdlbkJ1ZmZlcnNPcHRzKTsKICAgICAgICAgICAgLy8gLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCiAgICAgICAgICAgIC8vIFRyYW5zZmVyYWJsZXMKICAgICAgICAgICAgLy8gVHJhbnNmZXIgYWxsIHRoZSBhdHRyaWJ1dGVzIGFuZCBpbmRpY2VzIGJhY2sgdG8gdGhlIG1haW4gdGhyZWFkLgogICAgICAgICAgICBpZiAoZ2VvbUJ1ZmZlcnMuaW5kaWNlcykKICAgICAgICAgICAgICAgIHRyYW5zZmVyYWJsZXMucHVzaChnZW9tQnVmZmVycy5pbmRpY2VzLmJ1ZmZlcik7CiAgICAgICAgICAgIGZvciAoY29uc3QgYXR0ck5hbWUgaW4gZ2VvbUJ1ZmZlcnMuYXR0ckJ1ZmZlcnMpIHsKICAgICAgICAgICAgICAgIC8vIE5vdGU6IFRoZSB0eXBlIHZhbHVlIGFzc2lnbmVkIHRvIHRoZSBhdHRyaWJ1dGUgY2FuCiAgICAgICAgICAgICAgICAvLyBub3QgYmUgdHJhbnNmZXJyZWQgYmFjayB0byB0aGUgbWFpbiB0aHJlYWQuIENvbnZlcnQgdG8KICAgICAgICAgICAgICAgIC8vIHRoZSB0eXBlIG5hbWUgaGVyZSBhbmQgc2VuZCBiYWNrIGFzIGEgc3RyaW5nLgogICAgICAgICAgICAgICAgY29uc3QgYXR0ckRhdGEgPSBnZW9tQnVmZmVycy5hdHRyQnVmZmVyc1thdHRyTmFtZV07CiAgICAgICAgICAgICAgICB0cmFuc2ZlcmFibGVzLnB1c2goYXR0ckRhdGEudmFsdWVzLmJ1ZmZlcik7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLy8gQ29tcG9vdW5kIEdlb20gYnVmZmVycwogICAgICAgICAgICBpZiAoZ2VvbUJ1ZmZlcnMubWF0ZXJpYWxMaWJyYXJ5SW5kaWNlcykgewogICAgICAgICAgICAgICAgdHJhbnNmZXJhYmxlcy5wdXNoKGdlb21CdWZmZXJzLm1hdGVyaWFsTGlicmFyeUluZGljZXMuYnVmZmVyKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoZ2VvbUJ1ZmZlcnMuc3ViR2VvbU1hdGVyaWFsSW5kaWNlcykgewogICAgICAgICAgICAgICAgdHJhbnNmZXJhYmxlcy5wdXNoKGdlb21CdWZmZXJzLnN1Ykdlb21NYXRlcmlhbEluZGljZXMuYnVmZmVyKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoZ2VvbUJ1ZmZlcnMuc3ViR2VvbU9mZnNldHMpIHsKICAgICAgICAgICAgICAgIGZvciAobGV0IGtleSBpbiBnZW9tQnVmZmVycy5zdWJHZW9tT2Zmc2V0cykgewogICAgICAgICAgICAgICAgICAgIHRyYW5zZmVyYWJsZXMucHVzaChnZW9tQnVmZmVycy5zdWJHZW9tT2Zmc2V0c1trZXldLmJ1ZmZlcik7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLy8gaWYgKGdlb21CdWZmZXJzLnZlcnRleE5laWdoYm9ycykgewogICAgICAgICAgICAvLyAgIHRyYW5zZmVyYWJsZXMucHVzaChnZW9tQnVmZmVycy52ZXJ0ZXhOZWlnaGJvcnMuYnVmZmVyKQogICAgICAgICAgICAvLyB9CiAgICAgICAgICAgIC8vIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwogICAgICAgICAgICBnZW9tRGF0YXMucHVzaCh7CiAgICAgICAgICAgICAgICBuYW1lOiBnZW9tLm5hbWUsCiAgICAgICAgICAgICAgICB0eXBlOiBjbGFzc05hbWUsCiAgICAgICAgICAgICAgICBnZW9tQnVmZmVycywKICAgICAgICAgICAgICAgIGJib3g6IGdlb20uZ2V0Qm91bmRpbmdCb3goKSwKICAgICAgICAgICAgfSk7CiAgICAgICAgfQogICAgICAgIGNhbGxiYWNrKHsKICAgICAgICAgICAgdGFza0lkOiBkYXRhLnRhc2tJZCwKICAgICAgICAgICAgZ2VvbUxpYnJhcnlJZDogZGF0YS5nZW9tTGlicmFyeUlkLAogICAgICAgICAgICBnZW9tRmlsZUlEOiBkYXRhLmdlb21GaWxlSUQsCiAgICAgICAgICAgIGdlb21JbmRleE9mZnNldDogZGF0YS5nZW9tSW5kZXhPZmZzZXQsCiAgICAgICAgICAgIGdlb21zUmFuZ2U6IGRhdGEuZ2VvbXNSYW5nZSwKICAgICAgICAgICAgZ2VvbURhdGFzLAogICAgICAgIH0sIHRyYW5zZmVyYWJsZXMpOwogICAgfTsKCiAgICBjb25zdCBoYW5kbGVNZXNzYWdlID0gZnVuY3Rpb24gKHNyY0RhdGEsIHBvc3RNZXNzYWdlKSB7CiAgICAgIHBhcnNlR2VvbXNCaW5hcnkoc3JjRGF0YSwgKHJlc3VsdERhdGEsIHRyYW5zZmVyYWJsZXMpID0+IHsKICAgICAgICBwb3N0TWVzc2FnZShyZXN1bHREYXRhLCB0cmFuc2ZlcmFibGVzKTsKICAgICAgfSk7CiAgICB9OwoKICAgIC8vIENoZWNrIHRvIHNlZSBpZiB3ZSBhcmUgcnVubmluZyBpbiB0aGUgV29ya2VyIGJlZm9yZSBhc3NpZ25pbmcgb25tZXNzYWdlCiAgICBpZiAoZ2xvYmFsVGhpcy5kb2N1bWVudCA9PT0gdW5kZWZpbmVkKSB7CiAgICAgIGdsb2JhbFRoaXMub25tZXNzYWdlID0gZnVuY3Rpb24gKGV2ZW50KSB7CiAgICAgICAgaWYgKCFldmVudC5kYXRhKSB7CiAgICAgICAgICAvLyBOb3RlOiB3ZSBzZWUgdGhpcyBvY2N1ciB3aGVuIGxvYWRpbmcgb25lIGxhcmdlIGFzc2V0IG1hbnkgdGltZXMuCiAgICAgICAgICAvLyBMaWtlIHdoZW4gbG9hZGluZyB0aGUgcG9ydGFmaWwuCiAgICAgICAgICAvLyBJdCBtYXkgYmUgZHVlIHRvIG1lbW9yeSBpc3N1ZXMsIGJ1dCBpdHMgbm90IGNsZWFyLgogICAgICAgICAgY29uc29sZS53YXJuKCdHZW9tTGlicmFyeSB3b3JrZXIucG9zdE1lc3NhZ2UgZmFpbGVkLiBkYXRhIHdhcyBsb3N0IG9uIHRoZSB3YXkgdG8gdGhlIHdlYiB3b3JrZXIuJyk7CiAgICAgICAgICByZXR1cm4KICAgICAgICB9CiAgICAgICAgLy8gT3VyIHdvcmtlciBnZXRzIHRyaWdnZXJlZAogICAgICAgIGlmICghZXZlbnQuZGF0YS5jb250ZXh0KSB7CiAgICAgICAgICByZXR1cm4KICAgICAgICB9CiAgICAgICAgaGFuZGxlTWVzc2FnZShldmVudC5kYXRhLCBzZWxmLnBvc3RNZXNzYWdlKTsKICAgICAgfTsKICAgIH0KCiAgICBleHBvcnRzLmhhbmRsZU1lc3NhZ2UgPSBoYW5kbGVNZXNzYWdlOwoKICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCAnX19lc01vZHVsZScsIHsgdmFsdWU6IHRydWUgfSk7CgogICAgcmV0dXJuIGV4cG9ydHM7Cgp9KSh7fSk7Cgo=', null, false);\n/* eslint-enable */\n\n/* eslint-disable require-jsdoc */\nclass GeomParserMainThread extends EventEmitter {\n    constructor() {\n        super();\n    }\n    addTask(taskData, transferables) {\n        return new Promise((resolve) => {\n            // @ts-ignore\n            handleMessage(taskData, (results) => {\n                if (results.eventName) {\n                    this.emit(results.eventName, results);\n                    return;\n                }\n                resolve(results);\n            });\n        });\n    }\n}\nclass GeomParserWorkerPool extends WorkerPool {\n    constructor() {\n        super(true);\n        // Note: we found that parsing the geoms was not the bottleneck even on huge files.\n        // An iPad now reports 8 cores. To parse 22k geometries\n        // 4 cores:  480ms\n        // 2 cores:  500ms\n        this.poolSize = Math.max(1, Math.floor(SystemDesc.hardwareConcurrency * 0.5)); // always leave one main thread code spare.\n    }\n    constructWorker() {\n        const worker = new WorkerFactory$1();\n        return Promise.resolve(worker);\n    }\n}\nlet geomParserWorkerPool;\n// In NodeJS, we don't use the workers to parse data.\nif (SystemDesc.OS == 'Node') {\n    geomParserWorkerPool = new GeomParserMainThread();\n}\nelse {\n    geomParserWorkerPool = new GeomParserWorkerPool();\n}\n// /////////////////////////////////////////////\n// GeomLibrary\nlet numGeomLibraries = 0;\n/** Class representing a geometry library.\n */\nclass GeomLibrary extends EventEmitter {\n    assetItem;\n    listenerIDs = {};\n    streamInfos = {};\n    genBuffersOpts = {};\n    loadContext;\n    numGeoms = -1;\n    numGeomFiles = 1;\n    geoms = [];\n    basePath = '';\n    loadedCount = 0;\n    /**\n     * Create a geom library.\n     */\n    constructor(assetItem) {\n        super();\n        this.assetItem = assetItem;\n        numGeomLibraries++;\n    }\n    /**\n     * The returns true if all the geometries have been loaded.\n     * @return - True if all geometries are already loaded, else false.\n     */\n    isLoaded() {\n        return this.loaded;\n    }\n    get loaded() {\n        return this.numGeoms == -1 || this.loadedCount == this.numGeoms;\n    }\n    /**\n     * Loads a single geometry file for this GeomLibrary.\n     *\n     * @private\n     *\n     * @param geomFileID - The index of the file to load\n     * @param incrementProgress - If true, the progress bar is incremented and decremented.\n     * @return the promise resolves once the file is loaded, but not parsed.\n     */\n    loadGeomFile(geomFileID, incrementProgress = false) {\n        if (incrementProgress)\n            resourceLoader.incrementWorkload(1);\n        return new Promise((resolve) => {\n            const geomFileUrl = this.basePath + geomFileID + '.zgeoms';\n            resourceLoader.loadFile('archive', geomFileUrl, false).then((entries) => {\n                const geomsData = entries[Object.keys(entries)[0]];\n                const streamFileParsedListenerID = this.on('streamFileParsed', (event) => {\n                    if (event.geomFileID == geomFileID) {\n                        if (incrementProgress)\n                            resourceLoader.incrementWorkDone(1);\n                        // console.log(`GeomFileLoaded :${geomFileID} > ${this.loadedGeomFiles}/${this.numGeomFiles}`)\n                        this.off('streamFileParsed', streamFileParsedListenerID);\n                        resolve();\n                    }\n                });\n                this.readBinaryBuffer(geomFileID, geomsData.buffer, this.loadContext);\n            });\n        });\n    }\n    /**\n     * Loads the geometry files for this GeomLibrary.\n     * @param geomLibraryJSON - The json data describing the data needed to be loaded by the geom library\n     * @param basePath - The base path of the file. (this is theURL of the zcad file without its extension.)\n     * @param context - The value param.\n     */\n    loadGeomFilesStream(geomLibraryJSON, basePath, context) {\n        this.numGeomFiles = geomLibraryJSON.numGeomFiles\n            ? geomLibraryJSON.numGeomFiles\n            : geomLibraryJSON.numGeomsPerFile.length;\n        resourceLoader.incrementWorkload(this.numGeomFiles);\n        this.numGeoms = geomLibraryJSON.numGeoms;\n        this.basePath = basePath;\n        this.loadContext = context;\n        for (let geomFileID = 0; geomFileID < this.numGeomFiles; geomFileID++) {\n            this.loadGeomFile(geomFileID, false).finally(() => resourceLoader.incrementWorkDone());\n        }\n    }\n    /**\n     * The setGenBufferOption method.\n     * @param key - The key value.\n     * @param value - The value param.\n     */\n    setGenBufferOption(key, value) {\n        this.genBuffersOpts[key] = value;\n    }\n    /**\n     * The setNumGeoms method.\n     * @param expectedNumGeoms - The expectedNumGeoms value.\n     */\n    setNumGeoms(expectedNumGeoms) {\n        this.numGeoms = expectedNumGeoms;\n    }\n    /**\n     * Returns the number of geometries the GeomLibrary has, or will have at the end of loading.\n     * @return - The number of geometries.\n     */\n    getNumGeoms() {\n        return this.numGeoms;\n    }\n    /**\n     * The getGeom method.\n     * @param index - The index value.\n     * @return - The stored geometry\n     */\n    getGeom(index) {\n        if (index >= this.geoms.length) {\n            // console.warn(\"Geom index invalid:\" + index);\n            return null;\n        }\n        return this.geoms[index];\n    }\n    /**\n     * The getGeom method.\n     * @param index - The index value.\n     * @return - The stored geometry\n     */\n    setGeom(index, geom) {\n        geom.libraryIndex = index;\n        this.geoms[index] = geom;\n    }\n    /**\n     * The readBinaryBuffer method.\n     * @param geomFileID - The key value.\n     * @param buffer - The buffer value.\n     * @param context - The context value.\n     */\n    readBinaryBuffer(geomFileID, buffer, context) {\n        const reader = new BinReader(buffer, 0, SystemDesc.isMobileDevice);\n        const numGeoms = reader.loadUInt32();\n        // Geoms within a given file are offset into the array of geometries of the library.\n        // Note: One day, the geom library should already know all the offsets for each file before loading.\n        const geomIndexOffset = reader.loadUInt32();\n        this.streamInfos[geomFileID] = {\n            total: numGeoms,\n            done: 0,\n        };\n        if (numGeoms == 0) {\n            const event = new StreamFileParsedEvent(geomFileID, 0);\n            this.emit('streamFileParsed', event);\n            return;\n        }\n        if (this.numGeoms == -1) {\n            // Note: for loading geom streams, we need to know the total number\n            // ahead of time to be able to generate accurate progress reports.\n            this.numGeoms = numGeoms;\n        }\n        const toc = reader.loadUInt32Array(numGeoms);\n        // TODO: Use SharedArrayBuffer once available.\n        // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer\n        if (numGeomLibraries > 1 || this.numGeomFiles > 1) {\n            // In scenes loading many files, we just load each file on a different worker.\n            // This has one big advantage that we don't clone the buffer using the 'slice' method\n            // potentially reducing temporary memory consumption by a lot.\n            const geomsRange = [0, numGeoms];\n            const byteOffset = 0;\n            geomParserWorkerPool\n                .addTask({\n                geomFileID,\n                toc,\n                byteOffset,\n                geomIndexOffset,\n                geomsRange,\n                isMobileDevice: reader.isMobileDevice,\n                bufferSlice: buffer,\n                genBuffersOpts: this.genBuffersOpts,\n                context: {\n                    versions: context.versions,\n                },\n            }, [buffer])\n                .then((results) => {\n                // @ts-ignore\n                this.receiveGeomDatas(results);\n            });\n        }\n        else {\n            // Often we are loading many small files, and we want as few workloads as possible.\n            // e.g. one file per worker.\n            // but sometimes we are loading one big file and we need to break the file into chunks\n            // to get it processed on all available cores.\n            const bytesPerWorkload = 2000000;\n            let offset = 0;\n            while (offset < numGeoms) {\n                const bufferSliceStart = toc[offset];\n                let byteCount = 0;\n                let offsetEnd = offset;\n                while (offsetEnd < numGeoms && byteCount < bytesPerWorkload) {\n                    offsetEnd++;\n                    byteCount = toc[offsetEnd] - bufferSliceStart;\n                }\n                let geomsRange;\n                let bufferSliceEnd;\n                if (offsetEnd >= numGeoms) {\n                    geomsRange = [offset, numGeoms];\n                    bufferSliceEnd = buffer.byteLength;\n                }\n                else {\n                    geomsRange = [offset, offsetEnd];\n                    bufferSliceEnd = toc[geomsRange[1]];\n                }\n                const passWholeBuffer = offset == 0 && offsetEnd == numGeoms;\n                const byteOffset = passWholeBuffer ? 0 : toc[geomsRange[0]];\n                const bufferSlice = passWholeBuffer ? buffer : buffer.slice(bufferSliceStart, bufferSliceEnd);\n                offset = offsetEnd;\n                // ////////////////////////////////////////////\n                // Multi Threaded Parsing\n                geomParserWorkerPool\n                    .addTask({\n                    geomFileID,\n                    toc,\n                    byteOffset,\n                    geomIndexOffset,\n                    geomsRange,\n                    isMobileDevice: reader.isMobileDevice,\n                    bufferSlice,\n                    genBuffersOpts: this.genBuffersOpts,\n                    context: {\n                        versions: context.versions,\n                    },\n                }, [bufferSlice])\n                    .then((results) => {\n                    // @ts-ignore\n                    this.receiveGeomDatas(results);\n                });\n            }\n        }\n    }\n    /**\n     * The receiveGeomDatas method.\n     * @private\n     * @param data - The data received back from the web worker\n     * @return - returns true once all data for this geom library has been loaded.\n     */\n    receiveGeomDatas(results) {\n        const { geomFileID, geomDatas, geomIndexOffset, geomsRange } = results;\n        // We are storing a subset of the geoms from a binary file\n        // which is a subset of the geoms in an asset.\n        // geomIndexOffset: the offset of the file geoms in the asset.\n        // geomsRange: the range of geoms in the bin file.\n        const offset = geomIndexOffset + geomsRange[0];\n        const storedRange = [offset, geomIndexOffset + geomsRange[1]];\n        for (let i = 0; i < geomDatas.length; i++) {\n            const geomData = geomDatas[i];\n            if (!geomData.type)\n                continue;\n            let proxy;\n            switch (geomData.type) {\n                case 'Points':\n                    proxy = new PointsProxy(geomData);\n                    break;\n                case 'Lines':\n                    proxy = new LinesProxy(geomData);\n                    break;\n                case 'Mesh':\n                case 'Plane': // TODO: Support procedural shape params\n                case 'Sphere':\n                case 'Cone':\n                    proxy = new MeshProxy(geomData);\n                    break;\n                case 'CompoundGeom':\n                    proxy = new CompoundGeom(geomData, this.assetItem.getMaterialLibrary());\n                    break;\n                default:\n                    throw new Error('Unsupported Geom type:');\n            }\n            this.setGeom(offset + i, proxy);\n        }\n        const event = new RangeLoadedEvent(storedRange);\n        this.emit('rangeLoaded', event);\n        const loaded = storedRange[1] - storedRange[0];\n        // console.log(\"GeomLibrary Loaded:\" + loaded);\n        // Each file in the stream has its own counter for the number of\n        // geoms, and once each stream file finishes parsing, we fire a signal.\n        const streamInfo = this.streamInfos[geomFileID];\n        streamInfo.done += loaded;\n        // console.log('receiveGeomDatas:', geomFileID + ' Loaded:' + streamInfo.done + ' of :' + streamInfo.total)\n        if (streamInfo.done == streamInfo.total) {\n            const event = new StreamFileParsedEvent(geomFileID, streamInfo.done);\n            this.emit('streamFileParsed', event);\n            // Emit from the resource loader so anyone can listen.\n            resourceLoader.emit('streamGeomsLoaded', event);\n        }\n        // Once all the geoms from all the files are loaded and parsed\n        // fire the loaded signal.\n        this.loadedCount += loaded;\n        // console.log('receiveGeomDatas loadedCount:', this.loadedCount, ' numGeoms:', this.numGeoms)\n        if (this.loadedCount == this.numGeoms) {\n            // console.log('GeomLibrary Loaded:', this.assetItem.path, ' loaded:', this.loadedCount)\n            this.emit('loaded');\n        }\n        // Return true if we are done loading geoms\n        // This allows the worker to be shut down and free up memory.\n        return this.loadedCount == this.numGeoms;\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * The toJSON method encodes this type as a json object for persistence.\n     * @return - Returns the json object.\n     */\n    toJSON() {\n        return {\n            numGeoms: this.geoms.length,\n        };\n    }\n    /**\n     * The toString method.\n     * @return - The return value.\n     */\n    toString() {\n        return JSON.stringify(this.toJSON(), null, 2);\n    }\n    /**\n     *\n     */\n    loadMetadata(data, context) {\n        const reader = new BinReader(data.buffer, 0, SystemDesc.isMobileDevice);\n        const toc = reader.loadUInt32Array();\n        for (let i = 0; i < toc.length; i++) {\n            try {\n                const geom = this.geoms[i];\n                if (!geom) {\n                    console.warn('Error loading metadata for geom that was not yet loaded: ', i);\n                }\n                if (geom instanceof CompoundGeom) {\n                    reader.seek(toc[i]); // Reset the pointer to the start of the item data.\n                    geom.loadMetadata(reader, context);\n                }\n            }\n            catch (e) {\n                console.warn('Error loading geom metadata: ', i);\n            }\n        }\n    }\n}\n\n/** Class representing a material library in a scene tree.\n * @private\n */\nclass MaterialLibrary extends BaseItem {\n    assetItem;\n    images = {};\n    materials = [];\n    __materialsMap = {};\n    constructor(assetItem) {\n        super();\n        this.assetItem = assetItem;\n    }\n    /**\n     * The clear method.\n     */\n    clear() {\n        this.images = {};\n        this.materials = [];\n        this.__materialsMap = {};\n    }\n    /**\n     * The getPath method.\n     * @return - The return value.\n     */\n    getPath() {\n        if (this.assetItem instanceof BaseItem) {\n            return [...this.assetItem.getPath(), 'MaterialLibrary'];\n        }\n        else {\n            return ['MaterialLibrary'];\n        }\n    }\n    /**\n     * The resolvePath method traverses the subtree from this item down\n     * matching each name in the path with a child until it reaches the\n     * end of the path.\n     *\n     * @param path - The path value.\n     * @param index - The index value.\n     * @return - The return value.\n     */\n    resolvePath(path, index = 0) {\n        if (index == 0) {\n            if (path[0] == '.' || path[0] == 'MaterialLibrary')\n                index++;\n        }\n        // Maybe the name is a parameter name.\n        const material = this.getMaterial(path[index]);\n        if (material) {\n            if (index < path.length) {\n                return material.resolvePath(path, index + 1);\n            }\n            return material;\n        }\n        throw new Error(`Unable to resolve path : [${path.toString()}] after: 'MaterialLibrary' \\nNo material called : \"${path[index]}\"`);\n    }\n    /**\n     * The getNumMaterials method.\n     * @return - The return value.\n     */\n    getNumMaterials() {\n        return this.materials.length;\n    }\n    /**\n     * The getMaterials method.\n     * @return - The return value.\n     */\n    getMaterials() {\n        return this.materials;\n    }\n    /**\n     * The getMaterialNames method.\n     * @return - The return value.\n     */\n    getMaterialNames() {\n        const names = [];\n        this.materials.forEach((material) => {\n            names.push(material.getName());\n        });\n        return names;\n    }\n    /**\n     * The hasMaterial method.\n     * @param name - The name value.\n     * @return - The return value.\n     */\n    hasMaterial(name) {\n        return name in this.__materialsMap;\n    }\n    /**\n     * Add a material.\n     * @param material - The material value.\n     */\n    addMaterial(material) {\n        material.setOwner(this);\n        material.libraryIndex = this.materials.length;\n        this.__materialsMap[material.getName()] = this.materials.length;\n        this.materials.push(material);\n    }\n    /**\n     * The getMaterial method.\n     * @param nameOrIndex - The material name or its index.\n     * @param assert - The assert value.\n     * @return - The return value.\n     */\n    getMaterial(nameOrIndex) {\n        if (typeof nameOrIndex == 'string') {\n            const index = this.__materialsMap[nameOrIndex];\n            if (index == undefined) {\n                return null;\n            }\n            return this.materials[index];\n        }\n        else if (Number.isFinite(nameOrIndex)) {\n            return this.materials[nameOrIndex];\n        }\n    }\n    /**\n     * The hasImage method.\n     * @param name - The material name.\n     * @return - The return value.\n     */\n    hasImage(name) {\n        return name in this.images;\n    }\n    /**\n     * The addImage method.\n     * @param image - The image value.\n     */\n    addImage(image) {\n        image.setOwner(this);\n        this.images[image.getName()] = image;\n    }\n    /**\n     * The getImage method.\n     * @param name - The material name.\n     * @param assert - The assert value.\n     * @return - The return value.\n     */\n    getImage(name, assert = true) {\n        const res = this.images[name];\n        if (!res && assert) {\n            throw new Error('Image:' + name + ' not found in library:' + this.getImageNames());\n        }\n        return res;\n    }\n    /**\n     * The getImageNames method.\n     * @return - The return value.\n     */\n    getImageNames() {\n        const names = [];\n        // eslint-disable-next-line guard-for-in\n        for (const name in this.images) {\n            names.push(name);\n        }\n        return names;\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * The load method.\n     * @param filePath - The file path.\n     */\n    load(filePath) {\n        const xhr = new XMLHttpRequest();\n        xhr.open('GET', filePath, true);\n        xhr.ontimeout = () => {\n            throw new Error('The request for ' + filePath + ' timed out.');\n        };\n        xhr.onload = () => {\n            if (xhr.readyState === 4) {\n                if (xhr.status === 200) {\n                    this.fromJSON(JSON.parse(xhr.responseText));\n                }\n                else {\n                    console.warn(xhr.statusText);\n                }\n            }\n        };\n        xhr.send(null);\n    }\n    /**\n     * The toJSON method encodes the current object as a json object.\n     * @param context - The context value.\n     * @return - Returns the json object.\n     */\n    toJSON(context = {}) {\n        const j = {\n            numMaterials: this.getNumMaterials(),\n            images: {},\n            materials: [],\n        };\n        for (const key in this.images) {\n            j.images[key] = this.images[key].toJSON(context);\n        }\n        // eslint-disable-next-line guard-for-in\n        for (const material of this.materials) {\n            j.materials.push(material.toJSON(context));\n        }\n        return j;\n    }\n    /**\n     * The fromJSON method decodes a json object for this type.\n     * @param j - The json object this item must decode.\n     * @param context - The context value.\n     */\n    fromJSON(j, context = {}) {\n        // eslint-disable-next-line guard-for-in\n        for (const name in j.textures) {\n            const image = new FileImage(name);\n            image.fromJSON(j.textures[name]);\n            this.images[name] = image; // TODO: texture -> image\n        }\n        // eslint-disable-next-line guard-for-in\n        for (const name in j.materials) {\n            const material = new Material(name);\n            material.fromJSON(j.materials[name]);\n            this.addMaterial(material);\n        }\n    }\n    /**\n     * The readBinary method.\n     * @param reader - The reader value.\n     * @param context - The context value.\n     */\n    readBinary(reader, context) {\n        // if (context.version == undefined) context.version = 0\n        /*const name = */ reader.loadStr();\n        const numTextures = reader.loadUInt32();\n        for (let i = 0; i < numTextures; i++) {\n            const type = reader.loadStr();\n            const texture = Registry.constructClass(type);\n            texture.readBinary(reader, context);\n            this.images[texture.getName()] = texture;\n        }\n        const numMaterials = reader.loadUInt32();\n        if (numMaterials > 0) {\n            const toc = reader.loadUInt32Array(numMaterials);\n            for (let i = 0; i < numMaterials; i++) {\n                const shaderName = reader.loadStr();\n                let material;\n                switch (shaderName) {\n                    case 'StandardMaterial':\n                    case 'TransparentMaterial':\n                    case 'StandardSurfaceShader':\n                        material = Registry.constructClass('StandardSurfaceMaterial');\n                        break;\n                    case 'SimpleSurfaceShader':\n                    case 'SimpleSurfaceMaterial':\n                        material = Registry.constructClass('SimpleSurfaceMaterial');\n                        break;\n                    case 'PointsShader':\n                    case 'PointsMaterial':\n                        material = Registry.constructClass('PointsMaterial');\n                        break;\n                    case 'FatPointsShader':\n                    case 'FatPointsMaterial':\n                        material = Registry.constructClass('FatPointsMaterial');\n                        break;\n                    case 'LinesShader':\n                    case 'LinesMaterial':\n                        material = Registry.constructClass('LinesMaterial');\n                        break;\n                    default:\n                        material = new Material('');\n                        break;\n                }\n                reader.seek(toc[i]); // Reset the pointer to the start of the item data.\n                material.readBinary(reader, context); // (reader, context, this.images)\n                // Note: the compound geom now looks up materials by indexes\n                // and so the index of the material in the zcad file must mow match\n                // the index in the MaterialLibrary. (GeomItem looks up materials by name.)\n                this.materials[i] = material;\n                material.libraryIndex = i;\n                this.__materialsMap[material.getName()] = i;\n            }\n        }\n        this.emit('loaded');\n    }\n    /**\n     * The toString method.\n     * @return - The return value.\n     */\n    toString() {\n        return JSON.stringify(this.toJSON(), null, 2);\n    }\n}\n\n/**\n * Provides a context for loading assets. This context can provide the units of the loading scene.\n * E.g. you can specify the scene units as 'millimeters' in the context object.\n * To load external references, you can also provide a dictionary that maps filenames to URLs that are used\n * to resolve the URL of an external reference that a given asset is expecting to find.\n */\nclass AssetLoadContext extends EventEmitter {\n    units = 'meters';\n    versions = {};\n    sdk = '';\n    url = '';\n    folder = '';\n    camera = null;\n    assetItem = null;\n    resources = null; // a mapping of the key to asset urls.\n    xrefs = {}; // a mapping of the xrefs that have been loaded to their paths.\n    xrefLoadCallback = null; // When XRefs load, this callback can be used to supply the URL for the zcad file\n    lazyLoading;\n    postLoadCallbacks = [];\n    promisses = [];\n    urlStack = [];\n    assetStack = [];\n    addGeomToLayer;\n    /**\n     * Create a AssetLoadContext\n     * @param context The source context to base this context on.\n     */\n    constructor(context) {\n        super();\n        if (context) {\n            this.units = context.units;\n            this.sdk = context.sdk;\n            this.camera = context.camera;\n            this.resources = context.resources;\n            this.xrefs = context.xrefs;\n            this.xrefLoadCallback = context.xrefLoadCallback;\n            this.urlStack = [...context.urlStack];\n            this.assetStack = [...context.assetStack];\n        }\n    }\n    /**\n     * During loading, asynchronous processes may be launched, and subsequently completed.\n     * These method helps the Asset track how many asynchronous loading operations may be\n     * occurring with the tree during load.\n     * As each external reference starts to load, it adds a promise, letting the owning\n     * Asset know to wait till the children promisses are resolved before emitting its own 'loaded' event.\n     */\n    addPromise(promise) {\n        this.promisses.push(promise);\n    }\n    /**\n     * Resolves a path within the loading asset. This is used to connect\n     * items within the tree to other items. e.g. a Group can find its members.\n     * or an instance can find its source tree.\n     * @param path the path within the tree relative to the loading asset\n     * @param onSucceed called with the successful result of the path resolution.\n     * @param onFail called when the path resolution fails.\n     */\n    resolvePath(path, onSucceed, onFail) {\n        // Note: Why not return a Promise here?\n        // Promise evaluation is always async, so\n        // all promises will be resolved after the current call stack\n        // has terminated. In our case, we want all paths\n        // to be resolved before the end of the function, which\n        // we can handle easily with callback functions.\n        try {\n            const item = this.assetItem.resolvePath(path);\n            onSucceed(item);\n        }\n        catch (e) {\n            // Some paths resolve to items generated during load,\n            // so push a callback to re-try after the load is complete.\n            this.postLoadCallbacks.push(() => {\n                try {\n                    const param = this.assetItem.resolvePath(path);\n                    onSucceed(param);\n                }\n                catch (e) {\n                    if (onFail) {\n                        onFail(e);\n                    }\n                    else {\n                        throw new Error(e.message);\n                    }\n                }\n            });\n        }\n    }\n    /**\n     * Adds a function to be called back once the main load call stack exists.\n     * This is used to connect parts of the tree together after loading.\n     * e.g. an instance will\n     * @param postLoadCallback\n     */\n    addPLCB(postLoadCallback) {\n        this.postLoadCallbacks.push(postLoadCallback);\n    }\n    /**\n     * Triggers the resolution of any remaining callbacks.\n     * During loading, InstanceItems, or Groups may try to resolve other\n     * Items, but they might not be available yet, which causes a Post\n     * Load Callback (PLCB) to be registered. The last step in loading\n     * should be to resolve the PLCBs.\n     */\n    resolvePLCBs() {\n        for (const cb of this.postLoadCallbacks)\n            cb();\n        this.postLoadCallbacks = [];\n    }\n    /**\n     * The clone method constructs a new AssetLoadContext, copies its values\n     * from this instance and returns it.\n     */\n    clone() {\n        return new AssetLoadContext(this);\n    }\n}\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/**\n * BaseGroup are a special type of `TreeItem` that allows you to gather/classify/organize/modify\n * multiple items contained within the group. Items can be added to the group directly, or using\n * its path.\n * All parameters set to the group are also set to the children; in other words, it's a faster way\n * to apply common things to multiple items.\n *\n * **Parameters**\n * * **Items(`ItemSetParameter`):** _todo_\n *\n * @extends TreeItem\n */\nclass BaseGroup extends TreeItem {\n    /**\n     * @member itemsParam - TODO\n     */\n    itemsParam = new ItemSetParameter('Items', (item) => item instanceof TreeItem);\n    itemsEventHandlers = [];\n    searchRoot;\n    /**\n     * Creates an instance of a group.\n     *\n     * @param name - The name of the group.\n     */\n    constructor(name) {\n        super(name);\n        this.addParameter(this.itemsParam);\n        this.itemsParam.on('itemAdded', (event) => {\n            this.bindItem(event.item, event.index);\n            this.emit('itemAdded', event);\n        });\n        this.itemsParam.on('itemRemoved', (event) => {\n            this.unbindItem(event.item, event.index);\n            this.emit('itemRemoved', event);\n        });\n    }\n    // ////////////////////////////////////////\n    // Visibility\n    /**\n     * The updateVisibility method.\n     * @return - The return value.\n     * @private\n     */\n    updateVisibility() {\n        if (super.updateVisibility()) {\n            const value = this.isVisible();\n            Array.from(this.itemsParam.value).forEach((item) => {\n                item.propagateVisibility(value ? 1 : -1);\n            });\n            return true;\n        }\n        return false;\n    }\n    /**\n     * Calculates the new opacity value based on the opacityParam value\n     * and the lowest of the inherited opacity values.\n     */\n    updateOpacity() {\n        super.updateOpacity();\n        Array.from(this.itemsParam.value).forEach((member) => {\n            member.setInheritedOpacity(this, this.opacity);\n        });\n    }\n    cleanBoundingBox() {\n        const bbox = super.cleanBoundingBox();\n        Array.from(this.itemsParam.value).forEach((item) => {\n            if (item.isVisible() && item.isPickable()) {\n                const box3 = item.boundingBoxParam.value;\n                if (box3)\n                    bbox.addBox3(box3);\n            }\n        });\n        return bbox;\n    }\n    // ////////////////////////////////////////\n    // Highlights\n    /**\n     * Adds a highlight to the tree item.\n     *\n     * @param name - The name of the tree item.\n     * @param color - The color of the highlight.\n     * @param propagateToChildren - A boolean indicating whether to propagate to children.\n     */\n    addHighlight(name, color, propagateToChildren = true) {\n        super.addHighlight(name, color, propagateToChildren);\n        if (propagateToChildren) {\n            Array.from(this.itemsParam.value).forEach((item) => {\n                item.addHighlight(name, color, true);\n            });\n        }\n    }\n    /**\n     * Removes a highlight to the tree item.\n     *\n     * @param name - The name of the tree item.\n     * @param propagateToChildren - A boolean indicating whether to propagate to children.\n     */\n    removeHighlight(name, propagateToChildren = true) {\n        super.removeHighlight(name, propagateToChildren);\n        if (propagateToChildren) {\n            Array.from(this.itemsParam.value).forEach((item) => {\n                item.removeHighlight(name, true);\n            });\n        }\n    }\n    // ////////////////////////////////////////\n    // Items\n    /**\n     *  sets the root item to be used as the search root.\n     * @param treeItem\n     */\n    setSearchRoot(treeItem) {\n        this.searchRoot = treeItem;\n    }\n    /**\n     * The setOwner method assigns a new owner to the item. The owner of a group becomes its search root unless another search root is already set.\n     *\n     * @param ownerItem - The new owner item.\n     */\n    setOwner(ownerItem) {\n        if (ownerItem && !(ownerItem instanceof TreeItem)) {\n            throw new Error('cannot setOwner');\n        }\n        if (!this.searchRoot || this.searchRoot == this.getOwner())\n            this.searchRoot = ownerItem;\n        super.setOwner(ownerItem);\n    }\n    /**\n     * The __bindItem method.\n     * @param item - The item value.\n     * @param index - The index value.\n     * @private\n     */\n    bindItem(item, index) {\n        const listenerIDs = {};\n        listenerIDs['pointerDown'] = item.on('pointerDown', (event) => {\n            this.onPointerDown(event);\n        });\n        listenerIDs['pointerUp'] = item.on('pointerUp', (event) => {\n            this.onPointerUp(event);\n        });\n        listenerIDs['pointerMove'] = item.on('pointerMove', (event) => {\n            this.onPointerMove(event);\n        });\n        listenerIDs['pointerEnter'] = item.on('pointerEnter', (event) => {\n            this.onPointerEnter(event);\n        });\n        listenerIDs['pointerLeave'] = item.on('pointerLeave', (event) => {\n            this.onPointerLeave(event);\n        });\n        listenerIDs['pointerClick'] = item.on('pointerClick', (event) => {\n            this.onPointerClick(event);\n        });\n        listenerIDs['pointerDoubleClick'] = item.on('pointerDoubleClick', (event) => {\n            this.onPointerDoubleClick(event);\n        });\n        listenerIDs['pointerLongPress'] = item.on('pointerLongPress', (event) => {\n            this.onPointerLongPress(event);\n        });\n        listenerIDs['BoundingBox.valueChanged'] = item.boundingBoxParam.on('valueChanged', () => {\n            this.setBoundingBoxDirty();\n        });\n        if (!this.isVisible()) {\n            // Decrement the visibility counter which might cause\n            // this item to become invisible. (or it might already be invisible.)\n            item.propagateVisibility(-1);\n        }\n        // ///////////////////////////////\n        // Update the highlight\n        this.highlights.forEach((name) => {\n            item.addHighlight(name, this.highlightMapping[name], true);\n        });\n        this.itemsEventHandlers.splice(index, 0, listenerIDs);\n    }\n    /**\n     * The unbindItem method.\n     * @param item - The item value.\n     * @param index - The index value.\n     * @private\n     */\n    unbindItem(item, index) {\n        const listenerIDs = this.itemsEventHandlers[index];\n        // eslint-disable-next-line guard-for-in\n        for (let key in listenerIDs) {\n            const parts = key.split('.');\n            if (parts.length > 1) {\n                const param = item.getParameter(parts[0]);\n                if (param)\n                    param.off(parts[1], listenerIDs[key]);\n            }\n            else {\n                item.off(key, listenerIDs[key]);\n            }\n        }\n        if (!this.isVisible()) {\n            // Increment the Visibility counter which might cause\n            // this item to become visible.\n            // It will stay invisible if its parent is invisible, or if\n            // multiple groups connect to it and say it is invisible.\n            item.propagateVisibility(1);\n        }\n        // ///////////////////////////////\n        // Update the highlight\n        this.highlights.forEach((name) => {\n            item.removeHighlight(name, true);\n        });\n        this.setBoundingBoxDirty();\n        this.itemsEventHandlers.splice(index, 1);\n    }\n    /**\n     * Adds an item to the group(See `Items` parameter).\n     *\n     * @param item - The item value.\n     * @param emit - The emit value.\n     */\n    addItem(item, emit = true) {\n        if (!item) {\n            console.warn('Error adding item to group. Item is null');\n            return;\n        }\n        this.itemsParam.addItem(item, emit);\n    }\n    /**\n     * Removes an item from the group(See `Items` parameter).\n     *\n     * @param item - The item value.\n     * @param emit - The emit value.\n     */\n    removeItem(item, emit = true) {\n        const paramItems = this.itemsParam.value;\n        if (!paramItems)\n            return;\n        const itemIndex = Array.from(paramItems).indexOf(item);\n        if (itemIndex != -1)\n            this.itemsParam.removeItem(itemIndex, emit);\n    }\n    /**\n     * Removes all items from the group.\n     *\n     * @param emit - `true` triggers `valueChanged` event.\n     */\n    clearItems(emit = true) {\n        // Note: Unbind reversed so that indices\n        // do not get changed during the unbind.\n        const paramItems = this.itemsParam.value;\n        if (!paramItems)\n            return;\n        const items = Array.from(paramItems);\n        for (let i = items.length - 1; i >= 0; i--) {\n            this.unbindItem(items[i], i);\n        }\n        this.itemsParam.clearItems(emit);\n    }\n    /**\n     * Returns the list of `TreeItem` objects owned by the group.\n     *\n     * @return - The return value.\n     */\n    getItems() {\n        return this.itemsParam.value;\n    }\n    /**\n     * Sets an entire new array of items to the BaseGroup replacing any previous items.\n     *\n     * @param items - List of `TreeItem` you want to add to the group\n     */\n    setItems(items) {\n        this.clearItems(false);\n        this.itemsParam.setItems(items);\n    }\n}\n\n/* eslint-disable no-unused-vars */\n// TODO:  SelectionGroup in the zea-ux should extend this class.\n/**\n * @extends BaseGroup\n */\nclass SelectionSet extends BaseGroup {\n    #highlightUpdateRequested = false;\n    /**\n     * @member highlightedParam - Whether or not the TreeItem should be highlighted.\n     */\n    highlightedParam = new BooleanParameter('Highlighted', false);\n    /**\n     * @member highlightColorParam - The color of the highlight.\n     */\n    highlightColorParam = new ColorParameter('HighlightColor', new Color(0.5, 0.5, 1));\n    /**\n     * @member highlightFillParam - TODO\n     */\n    highlightFillParam = new NumberParameter('HighlightFill', 0.0, [0, 1]);\n    /**\n     * Creates an instance of a group.\n     *\n     * @param name - The name of the group.\n     */\n    constructor(name) {\n        super(name);\n        this.addParameter(this.highlightedParam);\n        this.highlightedParam.on('valueChanged', () => {\n            this.updateHighlight();\n        });\n        this.addParameter(this.highlightColorParam);\n        this.highlightColorParam.on('valueChanged', () => {\n            this.updateHighlight();\n        });\n        this.addParameter(this.highlightFillParam);\n        this.highlightFillParam.on('valueChanged', () => {\n            this.updateHighlight();\n        });\n    }\n    // /////////////////////////////\n    /**\n     * The updateHighlight method.\n     * @private\n     */\n    updateHighlight() {\n        // Make this function async so that we don't pull on the\n        // graph immediately when we receive a notification.\n        // Note: propagating using an operator would be much better.\n        if (!this.#highlightUpdateRequested) {\n            this.#highlightUpdateRequested = true;\n            setTimeout(() => {\n                this.#updateHighlightHelper();\n                this.#highlightUpdateRequested = false;\n            }, 0);\n        }\n    }\n    /**\n     * The updateHighlight method.\n     * @private\n     */\n    #updateHighlightHelper() {\n        let highlighted = this.highlightedParam.value;\n        let color;\n        if (highlighted) {\n            color = this.highlightColorParam.value.clone();\n            color.a = this.highlightFillParam.value;\n        }\n        const key = 'groupItemHighlight' + this.getId();\n        Array.from(this.itemsParam.value).forEach((item) => {\n            if (highlighted)\n                item.addHighlight(key, color, true);\n            else\n                item.removeHighlight(key, true);\n        });\n    }\n    /**\n     * Changes selection's state of the group with all items it owns.\n     *\n     * @param sel - Boolean indicating the new selection state.\n     */\n    setSelected(sel) {\n        super.setSelected(sel);\n        this.updateHighlight();\n    }\n    // ////////////////////////////////////////\n    // Items\n    /**\n     * The __bindItem method.\n     * @param item - The item value.\n     * @param index - The index value.\n     * @private\n     */\n    bindItem(item, index) {\n        super.bindItem(item, index);\n        // ///////////////////////////////\n        // Update the highlight\n        if (this.highlightedParam.value) {\n            const color = this.highlightColorParam.value;\n            color.a = this.highlightFillParam.value;\n            item.addHighlight('groupItemHighlight' + this.getId(), color, true);\n        }\n    }\n    /**\n     * The unbindItem method.\n     * @param item - The item value.\n     * @param index - The index value.\n     * @private\n     */\n    unbindItem(item, index) {\n        super.unbindItem(item, index);\n        if (this.highlightedParam.value) {\n            item.removeHighlight('groupItemHighlight' + this.getId(), true);\n        }\n    }\n    // ////////////////////////////////////////\n    // Clone\n    /**\n     * The clone method constructs a new group,\n     * copies its values and returns it.\n     *\n     * @param context - The context value.\n     * @return - Returns a new cloned group.\n     */\n    clone(context) {\n        const cloned = new SelectionSet(this.name + ' clone');\n        cloned.copyFrom(this, context);\n        return cloned;\n    }\n}\nRegistry.register('SelectionSet', SelectionSet); // TODO\n\nclass GroupGlobalXfoOperator extends CalcGlobalXfoOperator {\n    offsetXfo = new Xfo();\n    bindXfo = new Xfo();\n    invBindXfo = new Xfo();\n    #editingPivot = false;\n    groupTransformXfo = new XfoOperatorOutput('GroupTransformXfo');\n    constructor(globalXfoParam, localXfoParam, groupTransformXfoParam) {\n        super(globalXfoParam, localXfoParam);\n        this.groupTransformXfo.setParam(groupTransformXfoParam);\n        this.addOutput(this.groupTransformXfo);\n    }\n    set editingPivot(value) {\n        this.#editingPivot = value;\n        // During pivot editing, the group global does not include the\n        // Local Offset Xfo. So we need to make sure it is recalcuated when\n        // changing modes.\n        this.setDirty();\n    }\n    get editingPivot() {\n        return this.#editingPivot;\n    }\n    /**\n     * Create a GroupMemberXfoOperator operator.\n     * @param bindXfo - The Bind Xfo calculated from the initial Transforms of the Group Members.\n     */\n    setBindXfo(bindXfo) {\n        this.bindXfo = bindXfo;\n        this.invBindXfo = bindXfo.inverse();\n        this.setDirty();\n    }\n    /**\n     * The backPropagateValue method inverts the mathematics of the 'evaluate'\n     * method so it can propagate the value backwards to its inputs.\n     * @param value - the new value being set on the output GlobalXfo\n     */\n    backPropagateValue(value) {\n        let parentGlobalXfo;\n        if (this.parentGlobal.isConnected()) {\n            parentGlobalXfo = this.parentGlobal.getValue();\n        }\n        else {\n            parentGlobalXfo = new Xfo();\n        }\n        if (this.editingPivot) {\n            this.bindXfo = value;\n            this.invBindXfo = this.bindXfo.inverse();\n            this.offsetXfo = parentGlobalXfo.inverse().multiply(this.bindXfo);\n            this.setDirty();\n        }\n        else {\n            const parentGlobalWithOffsetXfo = parentGlobalXfo.multiply(this.offsetXfo);\n            this.localXfo.setValue(parentGlobalWithOffsetXfo.inverse().multiply(value));\n        }\n    }\n    /**\n     * The evaluate method calculates a new global Xfo based on the parents Global Xfo,\n     * and the local Xfo value.\n     */\n    evaluate() {\n        let parentGlobalWithOffsetXfo;\n        if (this.parentGlobal.isConnected()) {\n            const parentGlobalXfo = this.parentGlobal.getValue();\n            parentGlobalWithOffsetXfo = parentGlobalXfo.multiply(this.offsetXfo);\n        }\n        else {\n            parentGlobalWithOffsetXfo = this.offsetXfo;\n        }\n        if (this.editingPivot) {\n            const globalXfo = parentGlobalWithOffsetXfo;\n            this.globalXfo.setClean(globalXfo);\n            const groupTransformXfo = globalXfo.multiply(this.localXfo.getValue()).multiply(this.invBindXfo);\n            this.groupTransformXfo.setClean(groupTransformXfo);\n        }\n        else {\n            const globalXfo = parentGlobalWithOffsetXfo.multiply(this.localXfo.getValue());\n            this.globalXfo.setClean(globalXfo);\n            const groupTransformXfo = globalXfo.multiply(this.invBindXfo);\n            this.groupTransformXfo.setClean(groupTransformXfo);\n        }\n    }\n}\n/** An operator for modifying group members by the groups Xfo\n * @private\n * @extends Operator\n *\n */\nclass GroupMemberXfoOperator extends Operator {\n    #enabled;\n    groupTransformXfo = new XfoOperatorInput('GroupTransformXfo');\n    memberGlobalXfo = new XfoOperatorOutput('MemberGlobalXfo', OperatorOutputMode.OP_READ_WRITE);\n    /**\n     * Create a GroupMemberXfoOperator operator.\n     * @param groupTransformXfoParam - The parameter on the Group which defines the displacement to apply to the members.\n     * @param memberXfoGlobalParam - The GlobalXfo param found on the Member.\n     */\n    constructor(groupTransformXfoParam, memberXfoGlobalParam) {\n        super();\n        this.groupTransformXfo.setParam(groupTransformXfoParam);\n        this.memberGlobalXfo.setParam(memberXfoGlobalParam);\n        this.addInput(this.groupTransformXfo);\n        this.addOutput(this.memberGlobalXfo);\n        this.#enabled = true;\n    }\n    /**\n     * used to temporarily disable/enable the operator when the Group bind Xfo is being calculated\n     */\n    disable() {\n        this.#enabled = false;\n        this.setDirty();\n    }\n    /**\n     * used to temporarily disable/enable the operator when the Group bind Xfo is being calculated\n     */\n    enable() {\n        this.#enabled = true;\n        this.setDirty();\n    }\n    /**\n     * The evaluate method.\n     */\n    evaluate() {\n        const memberGlobalXfo = this.memberGlobalXfo.getValue();\n        if (this.#enabled) {\n            const groupTransformXfo = this.groupTransformXfo.getValue();\n            this.memberGlobalXfo.setClean(groupTransformXfo.multiply(memberGlobalXfo));\n        }\n        else {\n            this.memberGlobalXfo.setClean(memberGlobalXfo);\n        }\n    }\n    /**\n     * When the value on a Parameter is modified by a user by calling 'setValue,\n     * then if any operators are bound, the value of the Parameter cannot be modified\n     * directly as it is the result of a computation. Instead, the Parameter calls\n     * 'backPropagateValue' on the Operator to cause the Operator to handle propagating\n     * the value to one or more of its inputs.\n     * to its inputs.\n     * @param value - The value param.\n     * @return - The modified value.\n     */\n    backPropagateValue(value) {\n        if (this.#enabled) {\n            const invGroupTransformXfo = this.groupTransformXfo.getValue();\n            return invGroupTransformXfo.inverse().multiply(value);\n        }\n        return value;\n    }\n}\n\n/* eslint-disable no-unused-vars */\nconst GROUP_XFO_MODES = {\n    disabled: 0,\n    manual: 1,\n    first: 2,\n    average: 3,\n    globalOri: 4,\n};\n/**\n * The KinematicGroup is used to control the transform of a collection of objects int eh scene.\n * Objects can be added to a kinematic group and then the group can be transformed, causing each\n * of the members to be transformed as one.\n *\n **Parameters**\n * **InitialXfoMode(`MultiChoiceParameter`):** _todo_\n * **GroupTransform(`XfoParameter`):** _todo_\n *\n * @extends BaseGroup\n */\nclass KinematicGroup extends BaseGroup {\n    calculatingGroupXfo;\n    memberXfoOps;\n    #highlightUpdateRequested = false;\n    /**\n     * @member initialXfoModeParam - TODO\n     */\n    initialXfoModeParam = new MultiChoiceParameter('InitialXfoMode', GROUP_XFO_MODES.average, [\n        'manual',\n        'first',\n        'average',\n        'global',\n    ]);\n    /**\n     * @member groupTransformParam - Provides the transformation Xfo that is applied to each Group Member.\n     */\n    groupTransformParam = new XfoParameter('GroupTransform', new Xfo());\n    /**\n     * @member highlightedParam - Whether or not the TreeItem should be highlighted.\n     */\n    highlightedParam = new BooleanParameter('Highlighted', false);\n    /**\n     * @member highlightColorParam - The color of the highlight.\n     */\n    highlightColorParam = new ColorParameter('HighlightColor', new Color(1, 1, 0));\n    /**\n     * @member highlightFillParam - TODO\n     */\n    highlightFillParam = new NumberParameter('HighlightFill', 0.0, [0, 1]);\n    /**\n     * Creates an instance of a group.\n     *\n     * @param name - The name of the group.\n     */\n    constructor(name = '') {\n        super(name);\n        // Items which can be constructed by a user (not loaded in binary data.)\n        this.calculatingGroupXfo = false;\n        this.memberXfoOps = [];\n        this.addParameter(this.initialXfoModeParam);\n        this.initialXfoModeParam.on('valueChanged', () => {\n            this.calcGroupXfo();\n        });\n        this.addParameter(this.groupTransformParam);\n        this.addParameter(this.highlightedParam);\n        this.highlightedParam.on('valueChanged', () => {\n            this.#updateHighlight();\n        });\n        this.addParameter(this.highlightColorParam);\n        this.highlightColorParam.on('valueChanged', () => {\n            this.#updateHighlight();\n        });\n        this.addParameter(this.highlightFillParam);\n        this.highlightFillParam.on('valueChanged', () => {\n            this.#updateHighlight();\n        });\n        this.globalXfoOp = new GroupGlobalXfoOperator(this.globalXfoParam, this.localXfoParam, this.groupTransformParam);\n    }\n    /**\n     * Returns enum of available xfo modes.\n     *\n     * | Name | Default |\n     * | --- | --- |\n     * | manual | <code>0</code> |\n     * | first | <code>1</code> |\n     * | average | <code>2</code> |\n     * | globalOri | <code>3</code> |\n     */\n    static get INITIAL_XFO_MODES() {\n        return GROUP_XFO_MODES;\n    }\n    /**\n     * Returns bind Xfo that is used to compute the groupTransform\n     * Note: The Bind Xfo is determined by the 'GROUP_XFO_MODES' value.\n     */\n    get bindXfo() {\n        return this.globalXfoOp.bindXfo;\n    }\n    /**\n     * The updateHighlight method.\n     * @private\n     */\n    #updateHighlight() {\n        // Make this function async so that we don't pull on the\n        // graph immediately when we receive a notification.\n        // Note: propagating using an operator would be much better.\n        if (!this.#highlightUpdateRequested) {\n            this.#highlightUpdateRequested = true;\n            setTimeout(() => {\n                this.#updateHighlightHelper();\n                this.#highlightUpdateRequested = false;\n            }, 0);\n        }\n    }\n    #updateHighlightHelper() {\n        let highlighted = this.highlightedParam.value;\n        let color;\n        if (highlighted) {\n            color = this.highlightColorParam.value.clone();\n            color.a = this.highlightFillParam.value;\n        }\n        const key = 'groupItemHighlight' + this.getId();\n        Array.from(this.itemsParam.value).forEach((item) => {\n            if (highlighted)\n                item.addHighlight(key, color, true);\n            else\n                item.removeHighlight(key, true);\n        });\n    }\n    // ////////////////////////////////////////\n    // Global Xfo\n    /**\n     * Calculate the group Xfo translate.\n     * @private\n     * @return - Returns a new Xfo.\n     */\n    calcGroupXfo() {\n        const items = Array.from(this.itemsParam.value);\n        if (items.length == 0)\n            return;\n        this.editingPivot = true;\n        // TODO: Disable the group operator?\n        const initialXfoMode = this.initialXfoModeParam.value;\n        let xfo;\n        if (initialXfoMode == GROUP_XFO_MODES.manual) {\n            // The xfo is manually set by the current global xfo.\n            xfo = this.globalXfoParam.value;\n        }\n        else if (initialXfoMode == GROUP_XFO_MODES.first && items[0]) {\n            xfo = items[0].globalXfoParam.value;\n        }\n        else if (initialXfoMode == GROUP_XFO_MODES.average) {\n            xfo = new Xfo();\n            xfo.ori.set(0, 0, 0, 0);\n            let numTreeItems = 0;\n            items.forEach((item, index) => {\n                const itemXfo = item.globalXfoParam.value;\n                xfo.tr.addInPlace(itemXfo.tr);\n                // Note: Averaging rotations causes weird and confusing orientation.\n                // This also matches the behavior of the SelectionGroupXfoOperator in zea-ux.\n                if (index == 0)\n                    xfo.ori = itemXfo.ori;\n                numTreeItems++;\n            });\n            xfo.tr.scaleInPlace(1 / numTreeItems);\n            xfo.ori.normalizeInPlace();\n            // xfo.sc.scaleInPlace(1/ numTreeItems);\n        }\n        else if (initialXfoMode == GROUP_XFO_MODES.globalOri) {\n            xfo = new Xfo();\n            let numTreeItems = 0;\n            items.forEach((item, index) => {\n                const itemXfo = item.globalXfoParam.value;\n                xfo.tr.addInPlace(itemXfo.tr);\n                numTreeItems++;\n            });\n            xfo.tr.scaleInPlace(1 / numTreeItems);\n        }\n        else {\n            throw new Error('Invalid GROUP_XFO_MODES.');\n        }\n        this.globalXfoParam.value = xfo;\n        this.editingPivot = false;\n    }\n    get editingPivot() {\n        return this.globalXfoOp.editingPivot;\n    }\n    set editingPivot(value) {\n        this.globalXfoOp.editingPivot = value;\n    }\n    // ////////////////////////////////////////\n    // Items\n    bindItem(item, index) {\n        super.bindItem(item, index);\n        const memberGlobalXfoParam = item.globalXfoParam;\n        const memberXfoOp = new GroupMemberXfoOperator(this.groupTransformParam, memberGlobalXfoParam);\n        this.memberXfoOps.splice(index, 0, memberXfoOp);\n        if (this.highlightedParam.value) {\n            const color = this.highlightColorParam.value;\n            color.a = this.highlightFillParam.value;\n            item.addHighlight('groupItemHighlight' + this.getId(), color, true);\n        }\n    }\n    /**\n     * The unbindItem method.\n     * @param item - The item value.\n     * @param index - The index value.\n     * @private\n     */\n    unbindItem(item, index) {\n        super.unbindItem(item, index);\n        this.memberXfoOps[index].detach();\n        this.memberXfoOps.splice(index, 1);\n        if (this.highlightedParam.value) {\n            item.removeHighlight('groupItemHighlight' + this.getId(), true);\n        }\n    }\n    /**\n     * Adds an item to the group(See `Items` parameter).\n     *\n     * @param item - The item value.\n     * @param emit - The emit value.\n     */\n    addItem(item, emit = true) {\n        super.addItem(item, emit);\n        if (emit) {\n            this.calcGroupXfo();\n        }\n    }\n    /**\n     * Removes an item from the group(See `Items` parameter).\n     *\n     * @param item - The item value.\n     * @param emit - The emit value.\n     */\n    removeItem(item, emit = true) {\n        super.removeItem(item, emit);\n        if (emit) {\n            this.calcGroupXfo();\n        }\n    }\n    /**\n     * Sets an entire new array of items to the BaseGroup replacing any previous items.\n     *\n     * @param items - List of `TreeItem` you want to add to the group\n     */\n    setItems(items) {\n        super.setItems(items); // TODO: originally: super.setItems(emit) -- should emit be done here?\n        this.calcGroupXfo();\n    }\n    /**\n     * Removes all items from the group.\n     *\n     * @param emit - `true` triggers `valueChanged` event.\n     */\n    clearItems(emit = true) {\n        super.clearItems(emit);\n        this.memberXfoOps = [];\n        if (emit) {\n            this.calcGroupXfo();\n        }\n    }\n    // ////////////////////////////////////////\n    // Clone\n    /**\n     * The clone method constructs a new group,\n     * copies its values and returns it.\n     *\n     * @param context - The context value.\n     * @return - Returns a new cloned group.\n     */\n    clone(context) {\n        const cloned = new KinematicGroup();\n        cloned.copyFrom(this, context);\n        return cloned;\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * Encodes the current object as a json object.\n     *\n     * @param context - The context value.\n     * @return - Returns the json object.\n     */\n    toJSON(context) {\n        const json = super.toJSON(context);\n        json.bindXfo = this.globalXfoOp.bindXfo.toJSON();\n        const groupGlobalXfoOperator = this.globalXfoOp;\n        json.offsetXfo = groupGlobalXfoOperator.offsetXfo.toJSON();\n        return json;\n    }\n    /**\n     * Decodes a json object for this type.\n     *\n     * @param json - The json object this item must decode.\n     * @param context - The context value.\n     */\n    fromJSON(json, context) {\n        super.fromJSON(json, context);\n        const xfo = new Xfo();\n        xfo.fromJSON(json.bindXfo);\n        const groupGlobalXfoOperator = this.globalXfoOp;\n        groupGlobalXfoOperator.setBindXfo(xfo);\n        if (json.offsetXfo) {\n            groupGlobalXfoOperator.offsetXfo.fromJSON(json.offsetXfo);\n        }\n    }\n}\nRegistry.register('KinematicGroup', KinematicGroup);\n\n/* eslint-disable no-unused-vars */\n/**\n *\n * **Parameters**\n * * **Material(`MaterialParameter`):** _todo_\n *\n * @extends BaseGroup\n */\nclass MaterialGroup extends BaseGroup {\n    // TODO: should BaseGroup have the materialParam?\n    /**\n     * @member materialParam - The Material to use when rendering this GeomItem\n     */\n    materialParam = new MaterialParameter('Material');\n    __backupMaterials = {};\n    /**\n     * Creates an instance of a group.\n     *\n     * @param name - The name of the group.\n     */\n    constructor(name) {\n        super(name);\n        this.addParameter(this.materialParam);\n        this.materialParam.on('valueChanged', () => {\n            this.updateMaterial();\n        });\n    }\n    // /////////////////////////////\n    /**\n     * The updateHighlight method.\n     * @private\n     */\n    updateHighlight() {\n        // Make this function async so that we don't pull on the\n        // graph immediately when we receive a notification.\n        // Note: propagating using an operator would be much better.\n        // setTimeout(() => {}, 0)\n        // TODO: make this async\n        this.updateHighlightHelper();\n    }\n    /**\n     * The updateHighlight method.\n     * @private\n     */\n    updateHighlightHelper() {\n        let highlighted = false;\n        let color;\n        if (this.isSelected()) {\n            color = this.getHighlight();\n            highlighted = true;\n            color.a = 0.2;\n        }\n        const key = 'kinematicGroupItemHighlight' + this.getId();\n        Array.from(this.itemsParam.value).forEach((item) => {\n            if (highlighted)\n                item.addHighlight(key, color, true);\n            else\n                item.removeHighlight(key, true);\n        });\n    }\n    /**\n     * Changes selection's state of the group with all items it owns.\n     *\n     * @param sel - Boolean indicating the new selection state.\n     */\n    setSelected(sel) {\n        super.setSelected(sel);\n        this.updateHighlight();\n    }\n    // ////////////////////////////////////////\n    // Materials\n    /**\n     * The updateOpacity method.\n     */\n    updateOpacity() {\n        super.updateOpacity();\n        Array.from(this.itemsParam.value).forEach((item) => {\n            item.opacityParam.value = this.opacity;\n        });\n    }\n    /**\n     * The updateMaterial method.\n     * @private\n     */\n    updateMaterial() {\n        // Make this function async so that we don't pull on the\n        // graph immediately when we receive a notification.\n        // Note: propagating using an operator would be much better.\n        // setTimeout(() => {}, 0)\n        // TODO: make async\n        this.updateMaterialHelper();\n    }\n    /**\n     * The updateMaterial method.\n     * @private\n     */\n    updateMaterialHelper() {\n        const material = this.materialParam.value;\n        // TODO: Bind an operator\n        Array.from(this.itemsParam.value).forEach((item) => {\n            item.traverse((treeItem) => {\n                if (treeItem instanceof BaseGeomItem) {\n                    const baseGeomItem = treeItem;\n                    const p = baseGeomItem.materialParam;\n                    if (material) {\n                        const m = p.value;\n                        // TODO: How do we filter material assignments? this is a nasty hack.\n                        // but else we end up assigning surface materials to our edges.\n                        if (m != material && (!m || m.getShaderName() != 'LinesShader')) {\n                            this.__backupMaterials[p.getId()] = m;\n                            p.value = material;\n                        }\n                    }\n                    else if (this.__backupMaterials[p.getId()]) {\n                        p.value = this.__backupMaterials[p.getId()];\n                    }\n                }\n            });\n        });\n    }\n    // ////////////////////////////////////////\n    // Items\n    /**\n     * The __bindItem method.\n     * @param item - The item value.\n     * @param index - The index value.\n     * @private\n     */\n    bindItem(item, index) {\n        super.bindItem(item, index);\n        // ///////////////////////////////\n        // Update the highlight\n        if (this.isSelected()) {\n            const color = this.getHighlight();\n            color.a = 0.2;\n            const key = 'materialGroupItemHighlight' + this.getId();\n            item.addHighlight(key, color, true);\n        }\n        // ///////////////////////////////\n        // Update the Material\n        const material = this.materialParam.value;\n        if (material) {\n            // TODO: Bind an operator instead\n            item.traverse((treeItem) => {\n                if (treeItem instanceof BaseGeomItem) {\n                    const baseGeomItem = treeItem;\n                    const p = baseGeomItem.materialParam;\n                    if (material) {\n                        const m = p.value;\n                        // TODO: How do we filter material assignments? this is a nasty hack.\n                        // but else we end up assigning surface materials to our edges.\n                        if (m != material && (!m || m.getShaderName() != 'LinesShader')) {\n                            this.__backupMaterials[p.getId()] = m;\n                            p.value = material;\n                        }\n                    }\n                }\n            }, true);\n        }\n        item.opacityParam.value = this.opacity;\n    }\n    /**\n     * The unbindItem method.\n     * @param item - The item value.\n     * @param index - The index value.\n     * @private\n     */\n    unbindItem(item, index) {\n        super.unbindItem(item, index);\n        if (this.isSelected()) {\n            const key = 'materialGroupItemHighlight' + this.getId();\n            item.removeHighlight(key, true);\n        }\n    }\n    // ////////////////////////////////////////\n    // Clone\n    /**\n     * The clone method constructs a new group,\n     * copies its values and returns it.\n     *\n     * @param context - The context value.\n     * @return - Returns a new cloned group.\n     */\n    clone(context) {\n        const cloned = new MaterialGroup(this.name + 'clone');\n        cloned.copyFrom(this, context);\n        return cloned;\n    }\n}\nRegistry.register('MaterialGroup', MaterialGroup);\n\n/**\n * An operator that calculates the delta transform of the group since items were bound to it.\n * @extends Operator\n *\n */\nclass CuttingPlaneOperator extends Operator {\n    groupGlobalXfo = new XfoOperatorInput('GroupGlobalXfo');\n    cuttingPlane = new Vec4OperatorOutput('CuttingPlane');\n    /**\n     * Create a GroupMemberXfoOperator operator.\n     * @param groupGlobalXfoParam - The GlobalXfo param found on the Group.\n     * @param cuttingPlaneParam - The parameter on the Group which defines the displacement to apply to the members.\n     */\n    constructor(groupGlobalXfoParam, cuttingPlaneParam) {\n        super();\n        this.groupGlobalXfo.setParam(groupGlobalXfoParam);\n        this.cuttingPlane.setParam(cuttingPlaneParam);\n        this.addInput(this.groupGlobalXfo);\n        this.addOutput(this.cuttingPlane);\n    }\n    /**\n     * The evaluate method.\n     */\n    evaluate() {\n        const groupGlobalXfo = this.groupGlobalXfo.getValue();\n        const vec = groupGlobalXfo.ori.getZaxis();\n        const dist = groupGlobalXfo.tr.dot(vec);\n        this.cuttingPlane.setClean(new Vec4(vec.x, vec.y, vec.z, -dist));\n    }\n}\n\n/* eslint-disable no-unused-vars */\n/**\n * Groups are a special type of `BaseGroup` that allows you to gather/classify/organize/modify\n * multiple items contained within the group. Items can be added to the group directly, or using\n * its path.\n * All parameters set to the group are also set to the children; in other words, it's a faster way\n * to apply common things to multiple items.\n *\n * **Parameters**\n * * **CutAwayEnabled(`BooleanParameter`):** _todo_\n * * **CutPlaneNormal(`Vec3Parameter`):** _todo_\n * * **CutPlaneDist(`NumberParameter`):** _todo_\n *\n * @extends BaseGroup\n */\nclass CuttingPlane extends BaseGroup {\n    cutPlaneOp;\n    cutAwayEnabledParam = new BooleanParameter('CutAwayEnabled', false);\n    cutPlaneParam = new Vec4Parameter('CutPlane', new Vec4(1, 0, 0));\n    /**\n     * Creates an instance of a group.\n     *\n     * @param name - The name of the group.\n     */\n    constructor(name = '') {\n        super(name);\n        this.addParameter(this.cutAwayEnabledParam);\n        this.addParameter(this.cutPlaneParam);\n        this.cutPlaneOp = new CuttingPlaneOperator(this.globalXfoParam, this.cutPlaneParam);\n        this.cutAwayEnabledParam.on('valueChanged', (event) => {\n            this.updateCutaway(event);\n        });\n        this.cutPlaneParam.on('valueChanged', (event) => {\n            this.updateCutaway(event);\n        });\n        // Create the geometry to display the plane.\n        const material = new Material('plane', 'FlatSurfaceShader');\n        material.getParameter('BaseColor').value = new Color(1, 1, 1, 0.2);\n        const plane = new GeomItem(`PlaneGeom`, new Plane(1, 1), material);\n        this.addChild(plane);\n        const borderMaterial = new Material('border', 'LinesShader');\n        borderMaterial.getParameter('BaseColor').value = new Color(1, 0, 0, 1);\n        const border = new GeomItem(`BorderGeom`, new Rect(1, 1), borderMaterial);\n        this.addChild(border);\n    }\n    // ////////////////////////////////////////\n    // Cutaways\n    /**\n     * The updateCutaway method.\n     * @param item - The item in the group.\n     * @private\n     */\n    updateCutaway(item) {\n        // Make this function async so that we don't pull on the\n        // graph immediately when we receive a notification.\n        // Note: making this async broke the tests.\n        // Note: propagating using an operator would be much better.\n        // setTimeout(() => {\n        const cutEnabled = this.cutAwayEnabledParam.value;\n        const cutPlane = this.cutPlaneParam.value;\n        const cutAwayVector = cutPlane.xyz;\n        const cutAwayDist = cutPlane.w;\n        if (item instanceof BaseGeomItem) {\n            item.setCutawayEnabled(cutEnabled);\n            item.setCutVector(cutAwayVector);\n            item.setCutDist(cutAwayDist);\n        }\n        else {\n            Array.from(this.itemsParam.value).forEach((item) => {\n                item.traverse((item) => {\n                    if (item instanceof BaseGeomItem) {\n                        item.setCutawayEnabled(cutEnabled);\n                        item.setCutVector(cutAwayVector);\n                        item.setCutDist(cutAwayDist);\n                    }\n                }, true);\n            });\n        }\n        // }, 0)\n    }\n    // ////////////////////////////////////////\n    // Items\n    /**\n     * The __bindItem method.\n     * @param item - The item value.\n     * @param index - The index value.\n     * @private\n     */\n    bindItem(item, index) {\n        // ///////////////////////////////\n        // Update the item cutaway\n        const cutEnabled = this.cutAwayEnabledParam.value;\n        if (cutEnabled) {\n            this.updateCutaway(item);\n        }\n    }\n    /**\n     * The unbindItem method.\n     * @param item - The item value.\n     * @param index - The index value.\n     * @private\n     */\n    unbindItem(item, index) {\n        super.unbindItem(item, index);\n        // ///////////////////////////////\n        // Update the item cutaway\n        item.traverse((treeItem) => {\n            if (treeItem instanceof BaseGeomItem) {\n                treeItem.setCutawayEnabled(false);\n            }\n        }, true);\n    }\n    // ////////////////////////////////////////\n    // Clone\n    /**\n     * The clone method constructs a new group,\n     * copies its values and returns it.\n     *\n     * @param context - The context value.\n     * @return - Returns a new cloned group.\n     */\n    clone(context) {\n        const cloned = new CuttingPlane();\n        cloned.copyFrom(this, context);\n        return cloned;\n    }\n}\nRegistry.register('CuttingPlane', CuttingPlane);\n\n/**\n * Given a units string, load returns a factor relative to meters\n * e.g. for Millimeters, returns 0.001, for Meters, returns 1.0\n * Given 2 different units, the factors are combined together to calculate the conversion between the 2 units.\n * @param units the name of the units value for the load context.\n * Supports: ['millimeters', 'centimeters', 'decimeters', 'meters', 'kilometers', 'inches', 'feet', 'miles']\n * @return Returns the factor relative to meters.\n */\nconst getUnitsFactor = (units) => {\n    switch (units.toLowerCase()) {\n        case 'millimeters':\n            return 0.001;\n        case 'centimeters':\n            return 0.01;\n        case 'decimeters':\n            return 0.1;\n        case 'meters':\n            return 1.0;\n        case 'kilometers':\n            return 1000.0;\n        case 'inches':\n            return 0.0254;\n        case 'feet':\n            return 0.3048;\n        case 'miles':\n            return 1609.34;\n    }\n    return 1.0;\n};\n\n/**\n * Represents a TreeItem with rendering and material capabilities.\n *\n * @extends TreeItem\n */\nclass AssetItem extends TreeItem {\n    geomLibrary = new GeomLibrary(this);\n    materialLibrary = new MaterialLibrary(this);\n    loaded = false;\n    engineDataVersion;\n    unitsScale = 1.0;\n    units = 'meters';\n    /**\n     * Create an asset item.\n     * @param name - The name of the asset item.\n     */\n    constructor(name = '') {\n        super(name);\n    }\n    /**\n     * Loads all the geometries and metadata from the asset file.\n     * @param url - The URL of the asset to load\n     * @return - Returns a promise that resolves once the initial load is complete\n     */\n    load(url) {\n        return Promise.reject(`This method is not implemented for this Asset Item: ${url}`);\n    }\n    /**\n     * Returns the loaded status of current item.\n     *\n     * @return - Returns true if the asset has already loaded its data.\n     */\n    isLoaded() {\n        return this.loaded;\n    }\n    /**\n     * Returns asset `GeomLibrary` that is in charge of rendering geometry data using workers.\n     *\n     * @return - The return value.\n     */\n    getGeometryLibrary() {\n        return this.geomLibrary;\n    }\n    /**\n     * Returns `MaterialLibrary` that is in charge of storing all materials of current Item.\n     *\n     * @return - The return value.\n     */\n    getMaterialLibrary() {\n        return this.materialLibrary;\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * The readBinary method.\n     * @param reader - The reader value.\n     * @param context - The context value.\n     */\n    readBinary(reader, context) {\n        context.assetItem = this;\n        if (!context.units)\n            context.units = 'meters';\n        if (!context.versions['zea-engine']) {\n            context.versions['zea-engine'] = new Version(reader.loadStr());\n        }\n        this.engineDataVersion = context.versions['zea-engine'];\n        // console.log('Loading file version:', this.engineDataVersion.toString(), ' generated using :', context.sdk)\n        const loadUnits = () => {\n            this.units = reader.loadStr();\n            // console.log('File units:', this.units)\n            // Add this param so it is displayed in the CADViewer.\n            this.addParameter(new StringParameter('FileUnits', this.units));\n            // Calculate a scale factor to convert\n            // the asset units to the units of the context we are loading in.\n            if (this.units != context.units) {\n                const unitsFactor = getUnitsFactor(this.units);\n                const contextUnitsFactor = getUnitsFactor(context.units);\n                this.unitsScale = unitsFactor / contextUnitsFactor;\n            }\n            // The context propagates the new units to children assets.\n            // This means that a child asset applies a unitsScale relative to this asset.\n            context.units = this.units;\n            // Apply units change to existing Xfo (avoid changing tr).\n            const localXfoParam = this.localXfoParam;\n            const xfo = localXfoParam.value;\n            xfo.sc.scaleInPlace(this.unitsScale);\n            localXfoParam.value = xfo;\n        };\n        if (context.versions['zea-engine'].compare([0, 0, 6]) > 0) {\n            // Loading units modifies our Xfo, which then propagates up\n            // the tree forcing a re-computation. Better just do it at\n            // the start.\n            loadUnits();\n        }\n        let layerRoot;\n        const layers = {};\n        context.addGeomToLayer = (geomItem, layer) => {\n            if (!layers[layer]) {\n                if (!layerRoot) {\n                    layerRoot = new TreeItem('Layers');\n                    this.addChild(layerRoot, false);\n                }\n                const group = new BaseGroup(layer);\n                layerRoot.addChild(group, false);\n                layers[layer] = group;\n            }\n            layers[layer].addItem(geomItem);\n        };\n        this.materialLibrary.readBinary(reader, context);\n        super.readBinary(reader, context);\n        if (context.versions['zea-engine'].compare([0, 0, 5]) >= 0 &&\n            context.versions['zea-engine'].compare([0, 0, 7]) < 0) {\n            loadUnits();\n        }\n        // Invoke all the post-load callbacks to resolve any\n        // remaining references.\n        context.resolvePLCBs();\n        this.loaded = true;\n    }\n    /** Checks if this item or its subtree have finished loading their geometries. */\n    haveGeomsLoaded() {\n        if (!this.geomLibrary.isLoaded())\n            return false;\n        let result = true;\n        this.traverse((item) => {\n            if (item instanceof AssetItem) {\n                if (!item.haveGeomsLoaded()) {\n                    result = false;\n                }\n                // Stop the depth first traversal at each AsseItem, as the\n                // 'haveGeomsLoaded' call has already recursivly checked that subtree.\n                return false;\n            }\n            // As soon as we have one false value, we can stop traversal\n            return result;\n        }, false);\n        return result;\n    }\n    /**\n     * The toJSON method encodes this type as a json object for persistence.\n     *\n     * @param context - The context value.\n     * @return - Returns the json object.\n     */\n    toJSON(context = {}) {\n        context.makeRelative = (path) => {\n            const assetPath = this.getPath();\n            const start = path.slice(0, assetPath.length);\n            for (let i = 0; i < start.length - 1; i++) {\n                if (start[i] != assetPath[i]) {\n                    console.warn('Param Path is not relative to the asset. May not be able to be resolved at load time:' + path);\n                    return path;\n                }\n            }\n            // Relative paths start with a symbol for the root element.\n            const relativePath = path.slice(assetPath.length - 1);\n            relativePath[0] = '.';\n            return relativePath;\n        };\n        context.assetItem = this;\n        const j = super.toJSON(context);\n        j.materialLibrary = this.materialLibrary.toJSON();\n        return j;\n    }\n    /**\n     * The fromJSON method decodes a json object for this type.\n     *\n     * @param j - The json object this item must decode.\n     * @param context - The context value.\n     */\n    fromJSON(j, context = new AssetLoadContext()) {\n        context.assetItem = this;\n        this.materialLibrary.fromJSON(j.materialLibrary, context);\n        super.fromJSON(j, context);\n        // Invoke all the post-load callbacks to resolve any\n        // remaining references.\n        context.resolvePLCBs();\n    }\n    // ////////////////////////////////////////\n    // Clone and Destroy\n    /**\n     * The clone method constructs a new tree item, copies its values\n     * from this item and returns it.\n     *\n     * @param context - The context value.\n     * @return - Returns a new cloned tree item.\n     */\n    clone(context) {\n        const cloned = new AssetItem();\n        cloned.copyFrom(this, context);\n        return cloned;\n    }\n    /**\n     * Copies current TreeItem with all its children.\n     *\n     * @param src - The tree item to copy from.\n     * @param context - The context value.\n     */\n    copyFrom(src, context) {\n        if (!(src instanceof AssetItem)) {\n            throw new Error('cannot copy from src');\n        }\n        this.geomLibrary = src.geomLibrary;\n        this.materialLibrary = src.materialLibrary;\n        this.units = src.units;\n        this.loaded = src.loaded;\n        super.copyFrom(src, context);\n        if (!src.loaded) {\n            src.once('loaded', () => {\n                this.units = src.units;\n                const srcLocalXfo = src.localXfoParam.value;\n                const localXfo = this.localXfoParam.value;\n                localXfo.sc = srcLocalXfo.sc.clone();\n                this.localXfoParam.value = localXfo;\n                // Note: An XRef stored in an assembly may contain a cache of its subtree.\n                // If the XRef url does resolve to a file, we must clear this cache before loading the actual data.\n                this.removeAllChildren();\n                src.getChildren().forEach((srcChildItem) => {\n                    this.addChild(srcChildItem.clone(context), false, false);\n                });\n                this.loaded = true;\n                this.emit('loaded');\n                // We cn only determine if the geoms are loaded, after the initial tree is loaded.\n                // As we clone a subtree that may contain asset items. (happens when loading XRefs)\n                // The cloned tree needs to emit events when the source tree emits its events.\n                if (!src.haveGeomsLoaded()) {\n                    src.once('geomsLoaded', () => this.emit('geomsLoaded'));\n                }\n                else {\n                    this.emit('geomsLoaded');\n                }\n            });\n        }\n        else {\n            this.emit('loaded');\n            if (!src.haveGeomsLoaded()) {\n                src.once('geomsLoaded', () => this.emit('geomsLoaded'));\n            }\n            else {\n                this.emit('geomsLoaded');\n            }\n        }\n    }\n}\nRegistry.register('AssetItem', AssetItem);\n\nconst BillboardAlignment = {\n    AlignedToWorld: 0,\n    AlignedToCamera: 1,\n    AlignedToCameraAndXAxis: 2,\n};\n/**\n * A special type of TreeItem(Item with hierarchical abilities) class that represents a banner in a 2D dimension.\n * Can own any type of `BaseImage`.\n * **Parameters**\n * * **Image(`ImageParameter`):** Is the BaseImage you want to display on the board.\n * * **PixelsPerMeter(`NumberParameter`):** Quality and Size of the board. The bigger the number, the smaller the board.\n * * **Alpha(`NumberParameter`):** Transparency of the board, from 0 to 1.\n * * **AlignedToCamera(`BooleanParameter`):** Faces or not the board to the camera at all time(Moves with camera movement).\n * * **DrawOnTop(`BooleanParameter`):** The billboards are rendered overlaid on the scene.\n * * **FixedSizeOnscreen(`BooleanParameter`):** The billboards are rendered at a fixed size on screen, regardless of the distance to the billboard.\n *\n * @extends TreeItem\n */\nclass BillboardItem extends TreeItem {\n    /**\n     * Creates a billboard item.\n     *\n     * @param name - The name of the billboard item.\n     * @param image - The image value.\n     */\n    /**\n     * @member imageParam - Is the BaseImage you want to display on the board.\n     */\n    imageParam = new ImageParameter('Image');\n    /**\n     * @member pixelsPerMeterParam - Quality and Size of the board. The bigger the number, the smaller the board.\n     */\n    pixelsPerMeterParam = new NumberParameter('PixelsPerMeter', 1000.0);\n    /**\n     * @member alphaParam - Transparency of the board, from 0 to 1.\n     */\n    alphaParam = new NumberParameter('Alpha', 1.0);\n    /**\n     * @member colorParam - The color of the billboard\n     */\n    colorParam = new ColorParameter('Color', new Color(1.0, 1.0, 1.0));\n    /**\n     * @member alignedToCameraParam - Faces or not the board to the camera at all time(Moves with camera movement).\n     */\n    alignmentParam = new MultiChoiceParameter('Alignment', 0, Object.keys(BillboardAlignment));\n    /**\n     * @member drawOnTopParam - The billboards are rendered overlaid on the scene.\n     */\n    drawOnTopParam = new BooleanParameter('DrawOnTop', false);\n    /**\n     * @member fixedSizeOnscreenParam - The billboards are rendered at a fixed size on screen, regardless of the distance to the billboard.\n     */\n    fixedSizeOnscreenParam = new BooleanParameter('FixedSizeOnscreen', false);\n    /**\n     * @member fixedSizeOnscreenParam - The billboards is always rendered facing the user\n     */\n    frontFacingParam = new BooleanParameter('FrontFacing', true);\n    /**\n     * @member pivotParam - Where the pivot of the billboard is.\n     */\n    pivotParam = new Vec2Parameter('Pivot', new Vec2(0.5, 0.0));\n    constructor(name, image) {\n        super(name);\n        const imageParamResult = this.addParameter(this.imageParam);\n        if (image)\n            imageParamResult.value = image; // Note: this dirties the param and will ensure it is saved to JSON\n        this.addParameter(this.pixelsPerMeterParam);\n        this.addParameter(this.alphaParam);\n        this.addParameter(this.colorParam);\n        this.addParameter(this.alignmentParam);\n        this.addParameter(this.drawOnTopParam);\n        this.addParameter(this.fixedSizeOnscreenParam);\n        this.addParameter(this.pivotParam);\n    }\n}\nRegistry.register('BillboardItem', BillboardItem);\n\n/**\n * Class for loading zcad files.\n * The CADAsset is a TreeItem and can be added to the scene tree.\n *\n * **Events**\n * * **loaded:** Emitted when the  asset is loaded\n * @extends AssetItem\n */\nclass CADAsset extends AssetItem {\n    sdk;\n    url;\n    metadataLoadPromise;\n    metadataLoaded = false;\n    /**\n     * Create a CAD asset.\n     * @param {string} name - The name value.\n     */\n    constructor(name) {\n        super(name);\n    }\n    /**\n     * The clone method constructs a new CADAsset, copies its values\n     * from this item and returns it.\n     *\n     * @param context - The CloneContext param.\n     * @return - The cloned instance.\n     */\n    clone(context) {\n        const cloned = new CADAsset();\n        cloned.copyFrom(this, context);\n        return cloned;\n    }\n    /**\n     * Copies current TreeItem with all its children.\n     *\n     * @param src - The tree item to copy from.\n     * @param context - The context value.\n     */\n    copyFrom(src, context) {\n        if (!(src instanceof CADAsset)) {\n            throw new Error('cannot copy from src');\n        }\n        super.copyFrom(src, context);\n        this.url = src.url;\n        if (!src.loaded) {\n            src.once('geomsLoaded', (event) => {\n                this.emit('geomsLoaded', event);\n            });\n        }\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * Initializes CADAsset's asset, material, version and layers; adding current `CADAsset` Geometry Item toall the layers in reader\n     *\n     * @param {BinReader} reader - The reader param.\n     * @param {AssetLoadContext} context - The load context object that provides additional data such as the units of the scene we are loading into.\n     */\n    readRootLevelBinary(reader, context) {\n        // Reset the versions dictionary. We don't want a shared context to provide from other asset loads.\n        context.versions['zea-cad'] = new Version(reader.loadStr());\n        context.sdk = reader.loadStr();\n        this.sdk = context.sdk;\n        // console.log('Loading CAD File version:', this.cadfileVersion, ' exported using SDK:', context.cadSDK)\n        super.readBinary(reader, context);\n    }\n    /**\n     * Enables loading zcad data records.\n     *\n     * @param {Record<string, Uint8Array>} entries - The entries that were stored in the zcad file.\n     * @param {AssetLoadContext} context - The load context object that provides additional data such as the units of the scene we are loading into.\n     */\n    async loadZCADEntries(entries, context) {\n        const treeReader = new BinReader((entries.tree2 || entries.tree).buffer, 0, SystemDesc.isMobileDevice);\n        context.versions = {};\n        // Note: An XRef stored in an assembly may contain a cache of its subtree.\n        // If the XRef url does resolve to a file, we must clear this cache before loading the actual data.\n        // keep the assembly level features and apply them after the load.\n        this.removeAllChildren();\n        const name = this.getName();\n        this.readRootLevelBinary(treeReader, context);\n        // Maintain the name provided by the user before loading.\n        if (name != '')\n            this.setName(name);\n        if (entries.geomsdata) {\n            // If metadata is available, load it straight away.\n            this.metadataLoadPromise = new Promise((resolve) => {\n                this.geomLibrary.once('loaded', () => {\n                    this.geomLibrary.loadMetadata(entries.geomsdata, context);\n                    this.metadataLoaded = true;\n                    resolve();\n                });\n            });\n        }\n        if (entries.geoms) {\n            const geomFileID = -1;\n            this.geomLibrary.readBinaryBuffer(geomFileID, entries.geoms.buffer, context);\n        }\n        else if (entries['geomLibrary.json']) {\n            const geomLibraryJSON = JSON.parse(new TextDecoder('utf-8').decode(entries['geomLibrary.json']));\n            const url = context.url;\n            const filename = url.lastIndexOf('/') > -1 ? url.substring(url.lastIndexOf('/') + 1) : '';\n            const stem = filename.substring(0, filename.lastIndexOf('.'));\n            const basePath = context.folder + stem;\n            if (geomLibraryJSON.numGeomFiles == 0) {\n                console.error(\"Corrupt zcad file. Missing 'geoms':\", url);\n            }\n            else {\n                this.geomLibrary.loadGeomFilesStream(geomLibraryJSON, basePath, context);\n            }\n        }\n        return new Promise((resolve, reject) => {\n            Promise.allSettled(context.promisses)\n                .then(() => {\n                this.loaded = true;\n                this.emit('loaded');\n                resolve();\n                // Now check if we have GeomLibraries loading that we need to wait for.\n                // We want to emit an event when the entire sub-tree has loaded.\n                const geomPromises = [];\n                if (!this.geomLibrary.isLoaded()) {\n                    geomPromises.push(new Promise((resolve) => this.geomLibrary.once('loaded', resolve)));\n                }\n                const includeThis = false;\n                this.traverse((item) => {\n                    if (item instanceof CADAsset && !item.geomLibrary.isLoaded()) {\n                        geomPromises.push(new Promise((resolve) => item.once('geomsLoaded', resolve)));\n                    }\n                }, includeThis);\n                Promise.allSettled(geomPromises).then(() => this.emit('geomsLoaded'));\n            })\n                .catch((reason) => {\n                reject(reason);\n            });\n        });\n    }\n    /**\n     * Loads all the geometries and metadata from the asset file.\n     * @param data - The URL of the asset to load, or the ArrayBuffer of the asset.\n     * @param context - The load context object that provides additional data such as paths to external references.\n     * @return - Returns a promise that resolves once the load of the tree is complete. Geometries, textures and other resources might still be loading.\n     */\n    async load(data, context = new AssetLoadContext()) {\n        // Clone the context to avoid modifying the input context\n        // which could be shared between assets and supplying desired units values.\n        context = context.clone();\n        // These values are used by XRef to generate URLS.\n        context.assetItem = this;\n        return new Promise((resolve, reject) => {\n            // We add a 'workload' to the resource loader, to represent the\n            // parsing of the loaded zcad file.\n            // Note: this addresses an issue where the load count drops to 0 as soon\n            // as loadFile('archive' resolves.\n            resourceLoader.incrementWorkload(1);\n            if (typeof data == 'string') {\n                const url = data;\n                const folder = url.lastIndexOf('/') > -1 ? url.substring(0, url.lastIndexOf('/')) + '/' : '';\n                this.url = url;\n                context.url = url;\n                context.folder = folder;\n                context.urlStack.push(url);\n                context.assetStack.push(this);\n                resourceLoader.loadFile('archive', url).then((entries) => {\n                    if (!(entries.tree2 || entries.tree)) {\n                        resourceLoader.incrementWorkDone(1);\n                        const error = \"Corrupt zcad file. Missing 'tree':\" + url;\n                        this.emit('error', error);\n                        reject(error);\n                        return;\n                    }\n                    this.loadZCADEntries(entries, context).then(() => {\n                        resourceLoader.incrementWorkDone(1);\n                        resolve();\n                    });\n                }, (error) => {\n                    resourceLoader.incrementWorkDone(1);\n                    this.emit('error', error);\n                    reject(error);\n                });\n            }\n            else if (data instanceof ArrayBuffer) {\n                // Note: Some clients have asked to be able to load zcad files\n                // directly from ArrayBuffers, potentially generated from Node.fs module.\n                const archiveUnpacker = resourceLoader.plugins['archive'];\n                archiveUnpacker.extractFile(data).then((entries) => {\n                    this.loadZCADEntries(entries, context).then(() => {\n                        resourceLoader.incrementWorkDone(1);\n                        resolve();\n                    });\n                }, (error) => {\n                    resourceLoader.incrementWorkDone(1);\n                    this.emit('error', error);\n                    reject(error);\n                });\n            }\n        });\n    }\n    /**\n     * Loads the metadata file for the previously loaded zcad file.\n     * Note: in most cases, the CADAsset can generate the url for the metadata file.\n     *\n     * @param metaDataUrl - The URL of the metadata file to load.\n     */\n    loadMetadata(metaDataUrl = '') {\n        if (this.metadataLoadPromise)\n            return this.metadataLoadPromise;\n        this.metadataLoadPromise = new Promise((resolve, reject) => {\n            if (this.metadataLoaded)\n                resolve();\n            if (metaDataUrl == '') {\n                const url = this.url;\n                const base = url.substring(0, url.lastIndexOf('.'));\n                metaDataUrl = base + '.zmetadata';\n            }\n            resourceLoader.incrementWorkload();\n            resourceLoader.loadFile('archive', metaDataUrl).then((entries) => {\n                const context = new AssetLoadContext();\n                context.versions['zea-engine'] = this.engineDataVersion;\n                this.geomLibrary.loadMetadata(entries.geomsdata, context);\n                resourceLoader.incrementWorkDone(1);\n                this.metadataLoaded = true;\n                resolve();\n            }, (error) => {\n                resourceLoader.incrementWorkDone(1);\n                this.emit('error', error);\n                reject(error);\n            });\n        });\n        return this.metadataLoadPromise;\n    }\n}\nRegistry.register('CADAsset', CADAsset);\n\n/**\n * Represents a Tree Item of an Assembly modeling. Brings together components to define a larger product.\n *\n * @extends TreeItem\n */\nclass CADAssembly extends TreeItem {\n    /**\n     * Create a CAD assembly.\n     *\n     * @param name - The name of the tree item.\n     */\n    constructor(name) {\n        super(name);\n    }\n    /**\n     * The clone method constructs a new CADAssembly item, copies its values\n     * from this item and returns it.\n     *\n     * @param context - The CloneContext param.\n     * @return - The cloned instance.\n     */\n    clone(context) {\n        const cloned = new CADAssembly();\n        cloned.copyFrom(this, context);\n        return cloned;\n    }\n}\nRegistry.register('CADAssembly', CADAssembly);\n\n/**\n * Represents a Part within a CAD assembly.\n *\n * @extends TreeItem\n */\nclass CADPart extends TreeItem {\n    /**\n     * Creates an instance of CADPart setting up the initial configuration for Material and Color parameters.\n     *\n     * @param name - The name value.\n     */\n    constructor(name) {\n        super(name);\n    }\n    clone(context) {\n        const cloned = new CADPart();\n        cloned.copyFrom(this, context);\n        return cloned;\n    }\n}\nRegistry.register('CADPart', CADPart);\n\n/**\n * Represents a Body within a CAD Part. A Body is made up of either a single mesh or a collection of meshes, one for each surface.\n * When a zcad file is produced, the tool can  optimize bodies to contain only one mesh to speed up loading of large models, and support bigger models being loaded.\n *\n * @extends GeomItem\n */\nclass CADBody extends GeomItem {\n    shattered = false;\n    /**\n     * Creates an instance of CADBody setting up the initial configuration for Material and Color parameters.\n     *\n     * @param {string} name - The name value.\n     */\n    constructor(name) {\n        super(name);\n    }\n    /**\n     * Sets the state of this CADBody whether the geometry isdisplayed as\n     * 'shattered', meaning that each face, edge and vertex can be selected\n     * individually.\n     *\n     * @param state - The state value.\n     */\n    setShatterState(state) {\n        if (this.shattered != state) {\n            this.shattered = state;\n            this.emit('shatterStateChanged', new StateChangedEvent(state));\n        }\n    }\n    /**\n     * The clone method constructs a new CADBody, copies its values\n     * from this item and returns it.\n     *\n     * @param context - The CloneContext param.\n     * @return - The cloned instance.\n     */\n    clone(context) {\n        const cloned = new CADBody();\n        cloned.copyFrom(this, context);\n        return cloned;\n    }\n    // ///////////////////////////\n    // Persistence\n    /**\n     * Initializes CADBody's asset, material, version and layers; adding current `CADBody` Geometry Item toall the layers in reader\n     *\n     * @param reader - The reader param.\n     * @param context - The context param.\n     */\n    readBinary(reader, context) {\n        if (context.versions['zea-engine'].compare([3, 9, 0]) < 0) {\n            BaseGeomItem.prototype.readBinary.call(this, reader, context);\n            // Note: the bodyDescId is now deprecated as it is part of the parametric surface evaluation code.\n            // The BinReader must read the value to continue loading others.\n            /* const bodyDescId = */ reader.loadSInt32();\n            if (context.versions['zea-cad'].compare([0, 0, 4]) < 0) {\n                const materialName = reader.loadStr();\n                const materialLibrary = context.assetItem.getMaterialLibrary();\n                let material = materialLibrary.getMaterial(materialName);\n                if (!material) {\n                    material = new Material(materialName, 'SimpleSurfaceShader');\n                    material.getParameter('BaseColor').setValue(Color.random(0.25));\n                    context.assetItem.getMaterialLibrary().addMaterial(material);\n                }\n                this.materialParam.setValue(material);\n            }\n            if (context.versions['zea-cad'].compare([0, 0, 2]) >= 0 && context.versions['zea-cad'].compare([0, 0, 4]) < 0) {\n                this.layers = reader.loadStrArray();\n                // console.log(\"Layers:\", this.layers)\n                // Note: addGeomToLayer should take a 'BaseGeomItem'\n                // @ts-ignore\n                for (const layer of this.layers)\n                    context.addGeomToLayer(this, layer);\n            }\n        }\n        else {\n            super.readBinary(reader, context);\n        }\n    }\n}\nRegistry.register('CADBody', CADBody);\n\nconst plane = new Cuboid(1, 1, 1);\nlet planeMaterial = null;\n// Disable all highlighting so it never shows on screen.\nclass PMIPickingPlane extends GeomItem {\n    addHighlight(name, color, propagateToChildren = true) { }\n    removeHighlight(name, propagateToChildren = true) { }\n}\n/**\n * Represents a view of PMI data. within a CAD assembly.\n *\n * @extends TreeItem\n */\nclass PMIItem extends TreeItem {\n    materialMapping = {};\n    /**\n     * Creates an instance of PMIItem setting up the initial configuration for Material and Color parameters.\n     *\n     * @param {string} name - The name value.\n     */\n    constructor(name) {\n        super(name);\n    }\n    clone(context) {\n        const cloned = new PMIItem();\n        cloned.copyFrom(this, context);\n        return cloned;\n    }\n    /**\n     * Changes the current state of the selection of this item.\n     * Note: the PMIItem also activates the PMI linking when selected.\n     *\n     * @emits `selectedChanged` with selected state\n     * @param sel - Boolean indicating the new selection state.\n     */\n    setSelected(sel) {\n        super.setSelected(sel);\n        if (sel)\n            this.activate();\n        else\n            this.deactivate();\n    }\n    /**\n     * Activates the PMIView, adjusting visibility of the PMI items and the camera Xfo\n     */\n    activate() { }\n    /**\n     * Deactivates the PMIItem\n     */\n    deactivate() { }\n    /**\n     * Adds a highlight to the tree item.\n     *\n     * @param {string} name - The name of the tree item.\n     * @param {Color} color - The color of the highlight.\n     * @param {boolean} propagateToChildren - A boolean indicating whether to propagate to children.\n     */\n    addHighlight(name, color, propagateToChildren = true) {\n        super.addHighlight(name, color, false);\n        // Instead of adding highlights around the PMI text, which makes it difficult to read\n        // we clone the material and modify it so the text, symbols, and line colors\n        // become the highlight color.\n        if (propagateToChildren) {\n            const baseColor = color.clone();\n            baseColor.a = 1.0; // highlight colors often have zero alpha, as it controls the highlight fill.\n            const materialCache = {};\n            this.traverse((treeItem) => {\n                if (treeItem instanceof PMIPickingPlane)\n                    return false;\n                if (treeItem instanceof GeomItem) {\n                    const material = treeItem.materialParam.value;\n                    this.materialMapping[treeItem.getId()] = material;\n                    if (!(material.getId() in materialCache)) {\n                        const highlightMaterial = material.clone();\n                        if (highlightMaterial.hasParameter('BaseColor')) {\n                            const param = highlightMaterial.getParameter('BaseColor');\n                            if (param instanceof MaterialColorParam)\n                                param.colorSpace = ColorSpace.Gamma;\n                            param.setValue(baseColor);\n                        }\n                        if (highlightMaterial.hasParameter('EdgeColor')) {\n                            const param = highlightMaterial.getParameter('EdgeColor');\n                            if (param instanceof MaterialColorParam)\n                                param.colorSpace = ColorSpace.Gamma;\n                            param.setValue(baseColor);\n                        }\n                        if (highlightMaterial.hasParameter('Overlay')) {\n                            highlightMaterial.getParameter('Overlay').setValue(0.85);\n                        }\n                        // This *hack* forces PMI text to be rendered to the transparent layer\n                        // which means it will not have an outline drawn around it.\n                        // Maybe we should add PMI to the 'OverLay' pass.\n                        // This would assume that the overlay pass does not clear the depth buffer, which\n                        // it does right now.\n                        // @ts-ignore\n                        highlightMaterial.__isOpaque = false;\n                        treeItem.materialParam.value = highlightMaterial;\n                        // We can reuse this material on other PMI items with the same\n                        // original material\n                        materialCache[material.getId()] = highlightMaterial;\n                    }\n                    treeItem.materialParam.value = materialCache[material.getId()];\n                }\n            });\n        }\n        const pmiContainer = this.getOwner().getOwner(); // TODO: check\n        const pmiOwner = pmiContainer.getOwner();\n        if (pmiOwner) {\n            const linkedBodies = {};\n            const linkedBodyElements = {};\n            const linkedEntitiesParam = this.getParameter('LinkedEntities');\n            if (linkedEntitiesParam) {\n                const linkedEntityPaths = linkedEntitiesParam.getValue();\n                linkedEntityPaths.forEach((pathStr, index) => {\n                    if (pathStr == '')\n                        return;\n                    const path = pathStr.split(', ');\n                    const elemId = path.pop();\n                    try {\n                        const cadBody = pmiOwner.resolvePath(path);\n                        if (cadBody && cadBody instanceof CADBody) {\n                            if (cadBody.getNumChildren() == 0) {\n                                cadBody.setShatterState(true);\n                                if (!linkedBodies[cadBody.getId()]) {\n                                    linkedBodies[cadBody.getId()] = cadBody;\n                                    linkedBodyElements[cadBody.getId()] = [];\n                                }\n                                linkedBodyElements[cadBody.getId()].push(elemId);\n                            }\n                            else {\n                                const linkedEntity = cadBody.getChildByName(elemId);\n                                if (linkedEntity)\n                                    linkedEntity.addHighlight(name, color, true);\n                            }\n                            // linkedEntity.addHighlight(name + ':' + elemId, color, true)\n                        }\n                        else {\n                            console.log('linkedEntity.addHighlight(name, color, true):', path);\n                        }\n                    }\n                    catch (e) {\n                        console.log(index + ':' + e.message);\n                    }\n                });\n                for (let key in linkedBodies) {\n                    const cadBody = linkedBodies[key];\n                    const elemIds = linkedBodyElements[key];\n                    cadBody.addHighlight(name + ':' + elemIds.toString(), color, true);\n                }\n            }\n        }\n    }\n    /**\n     * Removes a highlight to the tree item.\n     *\n     * @param {string} name - The name of the tree item.\n     * @param {boolean} propagateToChildren - A boolean indicating whether to propagate to children.\n     */\n    removeHighlight(name, propagateToChildren = true) {\n        // super.removeHighlight(name, propagateToChildren)\n        super.removeHighlight(name, false);\n        if (propagateToChildren) {\n            this.traverse((treeItem) => {\n                if (treeItem instanceof GeomItem) {\n                    if (treeItem.getId() in this.materialMapping) {\n                        treeItem.materialParam.value = this.materialMapping[treeItem.getId()];\n                        delete this.materialMapping[treeItem.getId()];\n                    }\n                }\n            });\n        }\n        const pmiContainer = this.getOwner().getOwner();\n        const pmiOwner = pmiContainer.getOwner();\n        if (pmiOwner) {\n            const linkedBodies = {};\n            const linkedBodyElements = {};\n            const linkedEntitiesParam = this.getParameter('LinkedEntities');\n            if (linkedEntitiesParam) {\n                const linkedEntityPaths = linkedEntitiesParam.getValue();\n                linkedEntityPaths.forEach((pathStr) => {\n                    if (pathStr == '')\n                        return;\n                    const path = pathStr.split(', ');\n                    const elemId = path.pop();\n                    try {\n                        const cadBody = pmiOwner.resolvePath(path);\n                        if (cadBody && cadBody instanceof CADBody) {\n                            if (cadBody.getNumChildren() == 0) {\n                                cadBody.setShatterState(false);\n                                if (!linkedBodies[cadBody.getId()]) {\n                                    linkedBodies[cadBody.getId()] = cadBody;\n                                    linkedBodyElements[cadBody.getId()] = [];\n                                }\n                                linkedBodyElements[cadBody.getId()].push(elemId);\n                            }\n                            else {\n                                const linkedEntity = cadBody.getChildByName(elemId);\n                                if (linkedEntity)\n                                    linkedEntity.removeHighlight(name, true);\n                            }\n                            // linkedEntity.addHighlight(name + ':' + elemId, color, true)\n                        }\n                        else {\n                            console.log('linkedEntity.addHighlight(name, color, true):failed');\n                        }\n                    }\n                    catch (e) {\n                        console.log(e.message);\n                    }\n                });\n                for (let key in linkedBodies) {\n                    const cadBody = linkedBodies[key];\n                    const elemIds = linkedBodyElements[key];\n                    cadBody.removeHighlight(name + ':' + elemIds.toString(), true);\n                }\n            }\n        }\n    }\n    // ///////////////////////////\n    // Persistence\n    /**\n     * Load the binary data for this class\n     * @param reader - The reader param.\n     * @param context - The context param.\n     */\n    readBinary(reader, context) {\n        super.readBinary(reader, context);\n        this.traverse((item) => {\n            if (item instanceof GeomItem) {\n                const material = item.materialParam.value;\n                if (material.getShaderName() == 'StandardSurfaceShader') {\n                    material.setShaderName('FlatSurfaceShader');\n                }\n                // This *hack* forces PMI text to be rendered to the transparent layer\n                // which means it will not have an outline drawn around it.\n                // Maybe we should add PMI to the 'OverLay' pass.\n                // This would assume that the overlay pass does not clear the depth buffer, which\n                // it does right now.\n                // @ts-ignore\n                item.opacity = 0.99;\n            }\n        });\n        // Here we place a transparent plane behind the PMI Text to enable\n        // easier clicking on PMI items in the 3d Viewport.\n        context.assetItem.getGeometryLibrary().once('loaded', () => {\n            this.traverse((item) => {\n                // Note: We could implement a PMIText class that is generated in the bridge\n                // when processing PMI, so we don't need to do this hacky name check.\n                // Then the Text would be able to generate the plane during load.\n                if (item.getName().startsWith('Text')) {\n                    const planeItems = [];\n                    item.traverse((item) => {\n                        if (item instanceof GeomItem) {\n                            const geom = item.geomParam.value;\n                            const bbox = geom.getBoundingBox();\n                            if (!planeMaterial) {\n                                planeMaterial = new FlatSurfaceMaterial('plane');\n                                planeMaterial.baseColorParam.value = new Color(1, 1, 0, 0.001);\n                                planeMaterial.overlayParam.value = -0.001;\n                            }\n                            const planeGeomItem = new PMIPickingPlane('plane', plane, planeMaterial);\n                            const xfo = item.localXfoParam.value.multiply(item.geomOffsetXfoParam.value);\n                            xfo.tr.addInPlace(bbox.center());\n                            xfo.sc.multiplyInPlace(bbox.diagonal());\n                            planeGeomItem.localXfoParam.value = xfo;\n                            planeItems.push(planeGeomItem);\n                        }\n                    }, false);\n                    planeItems.forEach((planeItem) => item.addChild(planeItem, false));\n                    return false;\n                }\n            }, false);\n        });\n    }\n}\nRegistry.register('PMIItem', PMIItem);\n\n/**\n * Represents a view of PMI data. within a CAD assembly.\n *\n * @extends PMIItem\n */\nclass PMIView extends PMIItem {\n    camera;\n    /**\n     * Creates an instance of PMIView setting up the initial configuration for Material and Color parameters.\n     *\n     * @param {string} name - The name value.\n     */\n    constructor(name) {\n        super(name);\n        this.camera = null;\n    }\n    /**\n     * The clone method constructs a new PMIView, copies its values\n     * from this item and returns it.\n     *\n     * @param context - The clone context.\n     * @return - The return value.\n     */\n    clone(context) {\n        const cloned = new PMIView();\n        cloned.copyFrom(this, context);\n        return cloned;\n    }\n    /**\n     * Activates the PMIView, adjusting visibility of the PMI items and the camera Xfo\n     */\n    activate() {\n        super.activate();\n        let graphicalItems = [];\n        if (this.hasParameter('GraphicalElements')) {\n            graphicalItems = this.getParameter('GraphicalElements').getValue();\n        }\n        const findAssetItem = () => {\n            let item = this;\n            while (item && !(item instanceof CADAsset))\n                item = item.getParentItem();\n            if (item instanceof CADAsset)\n                return item;\n            return null;\n        };\n        const assetItem = findAssetItem();\n        const pmiContainer = this.getParentItem().getParentItem();\n        const pmiOwner = pmiContainer.getParentItem();\n        if (pmiOwner) {\n            const pmiItems = [];\n            pmiContainer.traverse((item) => {\n                if (item instanceof PMIView)\n                    return;\n                if (item instanceof PMIItem)\n                    pmiItems.push(item);\n            });\n            pmiItems.forEach((pmiItem) => {\n                const visible = graphicalItems.includes(pmiItem.getName());\n                pmiItem.setVisible(visible);\n            });\n        }\n        if (this.camera) {\n            const cameraXfo = this.localXfoParam.value.clone();\n            const TargetPoint = this.getParameter('TargetPoint').getValue().clone();\n            const CameraType = this.getParameter('CameraType').getValue();\n            cameraXfo.tr.scaleInPlace(assetItem.unitsScale);\n            TargetPoint.scaleInPlace(assetItem.unitsScale);\n            const dist = cameraXfo.tr.distanceTo(TargetPoint);\n            cameraXfo.sc.set(1.0, 1.0, 1.0);\n            this.camera.globalXfoParam.value = cameraXfo;\n            this.camera.setFocalDistance(dist);\n            if (CameraType == 'Camera_Orthographic') {\n                this.camera.setIsOrthographic(1, 0);\n                // When switching from perspective to ortho here is how the zoom is computed:\n                // _zoom = 1.f;\n                // float coef = _targetDistance * CATTan(CATDegreeToRadian * _viewAngle);\n                // if (coef > 0.f) _zoom = 1./ coef;\n                if (this.hasParameter('CameraZoom') && assetItem) {\n                    const CameraZoom = this.getParameter('CameraZoom').getValue();\n                    const FrustHeight = (1 / CameraZoom) * assetItem.unitsScale * 2;\n                    this.camera.setFrustumHeight(FrustHeight);\n                }\n            }\n        }\n        if (this.hasParameter('ClippingPlaneOrigin')) {\n            const clippingPlaneOrigin = this.getParameter('ClippingPlaneOrigin').getValue();\n            const clippingPlaneNormal = this.getParameter('ClippingPlaneNormal').getValue();\n            const cutEnabled = true;\n            const cutAwayDist = -clippingPlaneOrigin.dot(clippingPlaneNormal) * assetItem.unitsScale;\n            pmiOwner.traverse((item) => {\n                if (item instanceof PMIItem)\n                    return false;\n                if (item instanceof GeomItem) {\n                    item.setCutawayEnabled(cutEnabled);\n                    item.setCutVector(clippingPlaneNormal);\n                    item.setCutDist(cutAwayDist);\n                }\n            });\n        }\n        else {\n            pmiOwner.traverse((item) => {\n                if (item instanceof PMIItem)\n                    return false;\n                if (item instanceof GeomItem) {\n                    item.setCutawayEnabled(false);\n                }\n            });\n        }\n    }\n    /**\n     * Deactivates the PMIItem\n     */\n    deactivate() {\n        super.deactivate();\n        // if (this.hasParameter('GraphicalElements')) {\n        //   const pmiContainer = (this.getOwner() as TreeItem).getOwner() as TreeItem\n        //   const pmiOwner = pmiContainer.getOwner()\n        //   if (pmiOwner) {\n        //     const pmiItems: TreeItem[] = []\n        //     pmiContainer.traverse((item: TreeItem) => {\n        //       if (item instanceof PMIView) return\n        //       if (item instanceof PMIItem) pmiItems.push(item)\n        //     })\n        //     pmiItems.forEach((pmiItem) => {\n        //       pmiItem.setVisible(true)\n        //     })\n        //   }\n        // }\n        // // Note: leave the camera as is\n        // if (this.camera) {\n        //   this.camera.setIsOrthographic(0)\n        // }\n    }\n    // ///////////////////////////\n    // Persistence\n    /**\n     * Load the binary data for this class\n     * @param reader - The reader param.\n     * @param context - The context param.\n     */\n    readBinary(reader, context) {\n        super.readBinary(reader, context);\n        if (context.camera) {\n            this.camera = context.camera;\n        }\n    }\n}\nRegistry.register('PMIView', PMIView);\n\n/**\n * Represents a view of PMI data. within a CAD assembly.\n *\n * @extends TreeItem\n */\nclass XRef extends CADAsset {\n    /**\n     * @member configurationParam - Stores the value of the configuration this XRef must attempt to load\n     */\n    configurationParam = new StringParameter('Configuration');\n    /**\n     * Creates an instance of XRef setting up the initial configuration for Material and Color parameters.\n     *\n     * @param {string} name - The name value.\n     */\n    constructor(name) {\n        super(name);\n        this.addParameter(this.configurationParam);\n    }\n    /**\n     * The clone method constructs a new XRef, copies its values\n     * from this item and returns it.\n     *\n     * @param context - The context value.\n     * @return - Returns a new cloned xref.\n     */\n    clone(context) {\n        const cloned = new XRef();\n        cloned.copyFrom(this, context);\n        return cloned;\n    }\n    // ///////////////////////////\n    // Persistence\n    /**\n     * Initializes XRef's asset, material, version and layers; adding current `XRef` Geometry Item toall the layers in reader\n     *\n     * @paramreader - The reader param.\n     * @param context - The load context param.\n     */\n    readBinary(reader, context) {\n        let relativePath;\n        if (context.versions['zea-engine'].compare([3, 13, 1]) >= 0) {\n            TreeItem.prototype.readBinary.call(this, reader, context);\n            relativePath = reader.loadStr();\n        }\n        else {\n            reader.loadStr(); // read type\n            const name = reader.loadStr(); // read name\n            this.setName(name);\n            relativePath = reader.loadStr();\n            const xfo = new Xfo();\n            if (context.versions['zea-cad'].compare([3, 6, 2]) > 0) {\n                xfo.tr = reader.loadFloat32Vec3();\n                xfo.ori = reader.loadFloat32Quat();\n                this.localXfoParam.value = xfo;\n            }\n            else {\n                // Note: the SpatialBridge now encodes the 'ReferenceName' into the\n                // XRef, while CADEx didn't provide one. Use the name if it is provided.\n                if (name == '')\n                    this.setName(relativePath);\n            }\n            // XRefs can now contain custom props that may contain colors, or configurations.\n            if (context.versions['zea-engine'].compare([3, 11, 1]) > 0) {\n                // Note: after the refactor of the Class hierarchy where\n                // we inverted the relationship between BaseItem and PArameterOWner\n                // we needed to fix this code path.\n                //@ts-ignore\n                this.readBinaryParams(reader, context);\n            }\n        }\n        const assemblyFeatures = this.getChildByName('Assembly Features');\n        if (assemblyFeatures) {\n            this.removeChildByHandle(assemblyFeatures);\n        }\n        // /////////////////////////////////////\n        // URL\n        // If a resources dict has been provided, look it up, else\n        // generate a url.\n        let url = undefined;\n        if (context.resources) {\n            if (context.resources[relativePath]) {\n                url = context.resources[relativePath];\n            }\n            else {\n                // CAD systems seem to have flexible path resolution strategies that we dont yet support.\n                // e.g. looking in multiple folders for a file.\n                // The relative paths often break.\n                // If the user provides a mapping table, we will use it, else\n                // we assume files will all be in the same folder.\n                if (relativePath.includes('/')) {\n                    relativePath = relativePath.slice(relativePath.lastIndexOf('/') + 1);\n                }\n                else if (relativePath.includes('\\\\')) {\n                    relativePath = relativePath.slice(relativePath.lastIndexOf('\\\\') + 1);\n                }\n                if (context.resources[relativePath]) {\n                    url = context.resources[relativePath];\n                }\n                else if (context.xrefLoadCallback) {\n                    url = context.xrefLoadCallback.call(context, relativePath, this);\n                }\n            }\n        }\n        else if (context.xrefLoadCallback) {\n            url = context.xrefLoadCallback.call(context, relativePath, this);\n        }\n        else {\n            if (relativePath.includes('/')) {\n                relativePath = relativePath.slice(relativePath.lastIndexOf('/') + 1);\n            }\n            else if (relativePath.includes('\\\\')) {\n                relativePath = relativePath.slice(relativePath.lastIndexOf('\\\\') + 1);\n            }\n            // Generate a url relative to the folder of the asset we are currently loading.\n            if (relativePath.endsWith('.zcad')) {\n                url = context.folder + relativePath;\n            }\n            else {\n                url = context.folder + relativePath + '.zcad';\n            }\n        }\n        if (url) {\n            // Note: this occurs in Vallee data: CELA00925.sldasm (imports its self.)\n            if (context.urlStack.includes(url)) {\n                const index = context.urlStack.indexOf(url);\n                const asset = context.assetStack[index];\n                console.warn('Circular load occurring at:', asset.path);\n                return;\n            }\n            // If an XRef already exists to the same zcad file, we can just clone the existing XRef.\n            // This means the geometry will only be loaded once, and it will become re-used\n            // by the cloned XRefs.\n            if (context.xrefs[url]) {\n                context.addPromise(new Promise((resolve, reject) => {\n                    const xref = context.xrefs[url];\n                    const copyFromXRef = () => {\n                        // Note: we do clone the reference and update other properties that\n                        // would have been loaded from the file..\n                        // We don't clone the src xref as that overwites the name, visiblity and xfo values.\n                        this.url = xref.url;\n                        this.sdk = xref.sdk;\n                        this.engineDataVersion = xref.engineDataVersion;\n                        this.units = xref.units;\n                        if (this.units != context.units) {\n                            // The scale factor we must apply is relative to our parent, which\n                            // could have a different units to the src(cloned) XRef. We re-calculate\n                            // units scale based on our parents unit.\n                            const unitsFactor = getUnitsFactor(this.units);\n                            const contextUnitsFactor = getUnitsFactor(context.units);\n                            this.unitsScale = unitsFactor / contextUnitsFactor;\n                            const xfo = this.localXfoParam.value;\n                            xfo.sc.scaleInPlace(this.unitsScale);\n                            xfo.tr.scaleInPlace(this.unitsScale);\n                            this.localXfoParam.value = xfo;\n                        }\n                        const reference = xref.getChild(0);\n                        if (reference) {\n                            this.removeAllChildren();\n                            const clonedContext = new CloneContext();\n                            const clonedReference = reference.clone(clonedContext);\n                            this.addChild(clonedReference, false, false);\n                        }\n                        if (assemblyFeatures) {\n                            this.applyAssemblyLevelFeatures(assemblyFeatures);\n                        }\n                        resolve();\n                    };\n                    const loadFailed = () => {\n                        this.emit('error');\n                        reject();\n                    };\n                    if (!xref.loaded) {\n                        xref.once('xrefLoaded', copyFromXRef);\n                        xref.once('error', loadFailed);\n                    }\n                    else {\n                        copyFromXRef();\n                    }\n                }));\n            }\n            else {\n                context.xrefs[url] = this;\n                context.addPromise(new Promise((resolve, reject) => {\n                    this.load(url, new AssetLoadContext(context)).then(() => {\n                        this.emit('xrefLoaded');\n                        // CADAsset applies a units scale to the sc, but not the tr.\n                        const xfo = this.localXfoParam.value;\n                        xfo.tr.scaleInPlace(this.unitsScale);\n                        this.localXfoParam.value = xfo;\n                        if (assemblyFeatures) {\n                            this.applyAssemblyLevelFeatures(assemblyFeatures);\n                        }\n                        resolve();\n                    }, () => {\n                        // console.warn(`While Loading ${this.getPath()} unable to load XRef: ${relativePath}`)\n                        reject();\n                    });\n                }));\n            }\n        }\n        else {\n            console.warn(`While Loading ${this.getPath()} unable to load XRef: ${relativePath}`);\n            // If the XRef didn't resolve, we can keep the Assembly features,\n            // which represent a cache of the data as it was last saved.\n            if (assemblyFeatures) {\n                const children = assemblyFeatures.getChildren();\n                for (const subFeatureTreeItem of children) {\n                    this.addChild(subFeatureTreeItem, false);\n                }\n            }\n        }\n    }\n    applyAssemblyLevelFeatures(assemblyFeatures) {\n        // An Xef contains only one child. Either a part or an assembly.\n        // this.applyFeatureToChildren(assemblyFeatures, this)\n        const featureTreeChild = assemblyFeatures.getChild(0);\n        const prototypeTreeItem = this.getChild(0);\n        if (featureTreeChild && prototypeTreeItem)\n            this.applyFeature(featureTreeChild, prototypeTreeItem);\n        // this.addChild(assemblyFeatures)\n    }\n    applyFeatureToChildren(featureTreeItem, prototypeTreeItem) {\n        const children = [...featureTreeItem.getChildren()];\n        for (const subFeatureTreeItem of children) {\n            const subAssemblyTreeItem = prototypeTreeItem.getChildByName(subFeatureTreeItem.name);\n            if (subAssemblyTreeItem) {\n                this.applyFeature(subFeatureTreeItem, subAssemblyTreeItem);\n            }\n            else\n                console.log(`Feature node: ${subFeatureTreeItem.path} does not match a node in the assembly tree for the following XRef:`, this.name);\n        }\n    }\n    applyFeature(featureTreeItem, prototypeTreeItem) {\n        const xfo = featureTreeItem.localXfoParam.value;\n        if (!xfo.isIdentity()) {\n            prototypeTreeItem.localXfoParam.value = featureTreeItem.localXfoParam.value;\n        }\n        if (featureTreeItem instanceof GeomItem) {\n            const material = featureTreeItem.materialParam.value;\n            prototypeTreeItem.traverse((subTreeItem) => {\n                if (subTreeItem instanceof GeomItem) {\n                    subTreeItem.materialParam.value = material;\n                    // Remove any per-face materials that would override the assembly material\n                    const geom = subTreeItem.geomParam.value;\n                    if (geom instanceof CompoundGeom)\n                        geom.clearMaterials();\n                    else {\n                        subTreeItem.geomParam.once('valueChanged', () => {\n                            const geom = subTreeItem.geomParam.value;\n                            if (geom instanceof CompoundGeom) {\n                                geom.clearMaterials();\n                            }\n                        });\n                    }\n                }\n            }, true);\n            // Note: the GeomItem can contain children with other data to apply in the tree.\n            // We allow the traversal to continue.\n        }\n        else if (featureTreeItem instanceof CADPart) {\n            if (prototypeTreeItem instanceof CADPart) {\n                const xfo = prototypeTreeItem.localXfoParam.value;\n                const parentItem = prototypeTreeItem.parent;\n                parentItem.removeChildByHandle(prototypeTreeItem);\n                parentItem.addChild(featureTreeItem, false, false);\n                featureTreeItem.localXfoParam.value = xfo;\n            }\n            else if (prototypeTreeItem instanceof XRef || prototypeTreeItem instanceof InstanceItem) {\n                featureTreeItem.localXfoParam.value = new Xfo();\n                prototypeTreeItem.removeAllChildren();\n                prototypeTreeItem.addChild(featureTreeItem, false, false);\n            }\n            return;\n        }\n        if (prototypeTreeItem instanceof XRef && prototypeTreeItem.getNumChildren() == 1) {\n            // Note: the Assembly Feature tree does not include nodes for Instance items.\n            // and instead only has the prototype. We need to step down into the\n            // prototype to access its children.\n            prototypeTreeItem = prototypeTreeItem.getChild(0);\n        }\n        if (prototypeTreeItem) {\n            this.applyFeatureToChildren(featureTreeItem, prototypeTreeItem);\n        }\n    }\n}\nRegistry.register('XRef', XRef);\n\nconst PassType = {\n    PRE: 1,\n    OPAQUE: 2,\n    TRANSPARENT: 3,\n    OVERLAY: 4,\n};\n\n/** This class abstracts the rendering of a collection of geometries to screen.\n * @extends EventEmitter\n */\nclass GLPass extends EventEmitter {\n    enabled = true;\n    passIndex = -1;\n    __gl = null;\n    renderer = null;\n    __renderer = null;\n    /**\n     * Create a GL pass.\n     */\n    constructor() {\n        super();\n        this.enabled = true;\n        this.passIndex = 0;\n    }\n    /**\n     * The init method.\n     * @param renderer - The renderer value.\n     * @param passIndex - The index of the pass in the GLRenderer\n     */\n    init(renderer, passIndex) {\n        if (passIndex == undefined)\n            throw new Error('Missing constructor argument.'); // Type checking. Seomthing that TypeScript will do for us.\n        this.__gl = renderer.gl;\n        this.renderer = renderer;\n        this.__renderer = renderer;\n        this.passIndex = passIndex;\n    }\n    /**\n     * The setPassIndex method.\n     * @param passIndex - The index of the pass in the GLRenderer\n     */\n    setPassIndex(passIndex) {\n        this.passIndex = passIndex;\n    }\n    /**\n     * Returns the pass type. OPAQUE passes are always rendered first, followed by TRANSPARENT passes, and finally OVERLAY.\n     * @return - The pass type value.\n     */\n    getPassType() {\n        return PassType.OPAQUE;\n    }\n    /**\n     * The itemAddedToScene method is called on each pass when a new item\n     * is added to the scene, and the renderer must decide how to render it.\n     * It allows Passes to select geometries to handle the drawing of.\n     * @param treeItem - The treeItem value.\n     * @param rargs - Extra return values are passed back in this object.\n     * The object contains a parameter 'continueInSubTree', which can be set to false,\n     * so the subtree of this node will not be traversed after this node is handled.\n     * @return - The return value.\n     */\n    itemAddedToScene(treeItem, rargs) {\n        throw Error(`${this.constructor.name} must implement itemAddedToScene and itemRemovedFromScene`);\n    }\n    /**\n     * The itemRemovedFromScene method is called on each pass when aa item\n     * is removed to the scene, and the pass must handle cleaning up any resources.\n     * @param treeItem - The treeItem value.\n     * @param rargs - Extra return values are passed back in this object.\n     * @return - The return value.\n     */\n    itemRemovedFromScene(treeItem, rargs) {\n        throw Error(`${this.constructor.name} must implement itemAddedToScene and itemRemovedFromScene`);\n    }\n    /**\n     * The startPresenting method.\n     */\n    startPresenting() { }\n    /**\n     * The stopPresenting method.\n     */\n    stopPresenting() { }\n    // ///////////////////////////////////\n    // Rendering\n    /**\n     * The draw method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    draw(renderstate) {\n        throw Error('draw not implemented on GLPass');\n    }\n    /**\n     * The drawHighlightedGeoms method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    drawHighlightedGeoms(renderstate) { }\n    /**\n     * The drawGeomData method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    drawGeomData(renderstate) { }\n    /**\n     * The getGeomItemAndDist method.\n     * @param geomData - The geomData value.\n     */\n    getGeomItemAndDist(geomData) {\n        throw Error('getGeomItemAndDist not implemented on GLPass');\n    }\n}\n\n/**\n * Class representing a GL CAD pass.\n *\n * **Events**\n * * **updated**\n * @extends GLPass\n */\nclass GLCADPass extends GLPass {\n    /**\n     * Create a GL CAD pass.\n     * @param {boolean} debugMode - If true, then puts the GLCADPass rendering into debug mode.\n     */\n    constructor(debugMode = false) {\n        super();\n        console.warn('GLCADPass is deprecated. No need to install this pass in the renderer.');\n    }\n    /**\n     * The itemAddedToScene method is called on each pass when a new item\n     * is added to the scene, and the renderer must decide how to render it.\n     * It allows Passes to select geometries to handle the drawing of.\n     * @param {TreeItem} treeItem - The treeItem value.\n     * @param {object} rargs - Extra return values are passed back in this object.\n     * The object contains a parameter 'continueInSubTree', which can be set to false,\n     * so the subtree of this node will not be traversed after this node is handled.\n     * @return {Boolean} - The return value.\n     */\n    itemAddedToScene(treeItem, rargs) {\n        return false;\n    }\n    /**\n     * The itemRemovedFromScene method is called on each pass when aa item\n     * is removed to the scene, and the pass must handle cleaning up any resources.\n     * @param {TreeItem} treeItem - The treeItem value.\n     * @param {object} rargs - Extra return values are passed back in this object.\n     * @return {Boolean} - The return value.\n     */\n    itemRemovedFromScene(treeItem, rargs) {\n        return false;\n    }\n}\n\nconst placeHolderItems = new Map();\nlet disableLoading = false;\nclass PlaceholderGeomItem extends GeomItem {\n    relativePath;\n    loadContext;\n    parentCache;\n    parentChildIndexCache;\n    loading = false;\n    constructor(name = '') {\n        super(name);\n    }\n    clone(context) {\n        const cloned = new PlaceholderGeomItem();\n        cloned.copyFrom(this, context);\n        return cloned;\n    }\n    copyFrom(src, context) {\n        if (!(src instanceof PlaceholderGeomItem)) {\n            throw new Error('cannot copy from src');\n        }\n        super.copyFrom(src);\n        this.relativePath = src.relativePath;\n        this.loadContext = src.loadContext;\n    }\n    readBinary(reader, context) {\n        super.readBinary(reader, context);\n        this.relativePath = reader.loadStr();\n        this.loadContext = context;\n    }\n    load() {\n        // if (this.relativePath.endsWith('Walls-6501.zcad')) {\n        //   disableLoading = true\n        //   console.log('stop')\n        // }\n        if (this.loading || disableLoading) {\n            return;\n        }\n        this.loading = true;\n        let asset;\n        // console.log(`Placeholders ${loadedPlaceholders}/${numPlaceholders}`)\n        // console.log('Loading Placeholder', this.path, this.relativePath)\n        const replaceMe = () => {\n            const asset = this.loadContext.xrefs[this.relativePath];\n            // const parentAsset = findAsset(this)\n            // const subPath = this.path.slice(parentAsset.path.length)\n            // console.log('Loading Placeholder', subPath, this.relativePath, calcTreeComplexity(asset))\n            this.parentCache = this.parent;\n            this.parentChildIndexCache = this.parentCache.getChildIndex(this);\n            this.parentCache.removeChild(this.parentChildIndexCache);\n            // Clone the array as we will remove items from the source asset changing the array.\n            let children;\n            if (placeHolderItems.has(this.relativePath)) {\n                children = placeHolderItems.get(this.relativePath);\n                // If multiple placeholders are loading this asset, we have to clone as each child can only\n                // be assigned to one parent tree item\n                children.forEach((child, index) => {\n                    this.parentCache.insertChild(child.clone(), this.parentChildIndexCache + index, false);\n                });\n            }\n            else {\n                children = [...asset.getChildren()];\n                placeHolderItems.set(this.relativePath, children);\n                children.forEach((child, index) => {\n                    this.parentCache.insertChild(child, this.parentChildIndexCache + index, false);\n                });\n            }\n        };\n        if (this.relativePath) {\n            const url = this.loadContext.folder + this.relativePath;\n            asset = this.loadContext.xrefs[this.relativePath];\n            if (!asset) {\n                asset = new XRef(this.relativePath);\n                asset.load(url);\n                this.loadContext.xrefs[this.relativePath] = asset;\n            }\n            if (asset.loaded && asset.geomLibrary.loaded) {\n                replaceMe();\n            }\n            else {\n                asset.once('geomsLoaded', replaceMe);\n            }\n        }\n    }\n    unload() {\n        this.parentCache.removeChild(this.parentChildIndexCache);\n        this.parentCache.insertChild(this, this.parentChildIndexCache);\n        this.loading = false;\n    }\n    static disableLoading() {\n        disableLoading = true;\n    }\n}\nRegistry.register('Placeholder', PlaceholderGeomItem);\n\n/* eslint-disable no-unused-vars */\n/**\n * The Camera class is used to provide a point of view of the scene. The viewport is assigned\n * a camera, which is uses during drawing. The camera controls the view and projection used to\n * render the scene.\n *\n * Cameras can provide a perspective projection, or an orthographic projection, and anything in between.\n * To configure whether th projection provided by the camera is Orthographic or Perspective, set\n * the value of the 'isOrthographic' Parameter to a value between 0 and 1. 0.0 being fully perspective\n * and 1.0 being fully Orthographic.\n * Alternatively, you can call camera.setIsOrthographic and pass the value, and a time in milliseconds to\n * take to transition between the current value and your new value.\n * ```javascript\n *   camera.setIsOrthographic(1, 400);\n * ```\n *\n * By default, the Camera automatically adjusts the near and far planes as the focal distance is modified. This\n * behavior can be disabled, by setting the adjustNearAndFarPlanesToFocalDist property to false.\n * Alternatively, you can also adjust the factors that are used to modify the near and far plane based on the\n * focal distance.\n * ```javascript\n *   camera.adjustNearAndFarPlanesToFocalDist = true\n *   camera.nearDistFactor = 0.01\n *   camera.farDistFactor = 5\n * ```\n *\n * **Parameters**\n * * **isOrthographic(`NumberParameter`):** Controls the projection matrix generated by the camera. A value of 0.0, means a perspective projection, while 1 an orthographic projection. Any value in between generates a blended perspective -> orthographic projection.\n * * **fov(`NumberParameter`):** The vertical angle of the view frustum when generating a perspective projection. In orthographic mode, this value is used to calculate the size of the view at the target distance.\n * * **near(`NumberParameter`):** The near clipping distance of the camera.\n * * **far(`NumberParameter`):** The far clipping distance of the camera.\n * * **focalDistance(`NumberParameter`):** The distance at which the camera is focussed. Note: the CameraManipulator sets the focal distance when zooming in on a target.\n *\n * **Events**\n * * **projectionParamChanged:** When on of the parameters above change, the camera emits this event. Note: the Viewport listens to this event and triggers re-rendering.\n * * **movementFinished:** Triggered at the conclusion of some action. E.g. when a zoom action is finished, or when the mouse is released after an orbit action. The viewport listens to this event and triggers a re-rendering of the selection buffers.\n *\n * @extends TreeItem\n */\nclass Camera extends TreeItem {\n    isOrthographicParam = new NumberParameter('isOrthographic', 0.0);\n    fovParam = new NumberParameter('fov', 1.0);\n    nearParam = new NumberParameter('near', 0.1);\n    farParam = new NumberParameter('far', 1000.0);\n    focalDistanceParam = new NumberParameter('focalDistance', 5.0);\n    // Controls whether the camera automatically adjusts the near and far planes\n    // as the focal distance changes. Set to false to explicitly control the near\n    // and far planes.\n    adjustNearAndFarPlanesToFocalDist = true;\n    // The factor by which the near plane is adjusted based on the focal distance.\n    nearDistFactor = 0.01;\n    // The factor by which the far plane is adjusted based on the focal distance.\n    farDistFactor = 100;\n    frameOnBoundingSphere = false;\n    viewHeight = 0;\n    intervalId = -1;\n    /**\n     * Instantiates a camera object, setting default configuration like zoom, target and positioning.\n     *\n     * @param name - The name of the camera.\n     */\n    constructor(name = 'Camera') {\n        super(name);\n        this.addParameter(this.isOrthographicParam);\n        this.addParameter(this.fovParam);\n        this.addParameter(this.nearParam);\n        this.addParameter(this.farParam);\n        this.addParameter(this.focalDistanceParam);\n        const emitProjChanged = (event) => {\n            this.emit('projectionParamChanged', event);\n        };\n        this.isOrthographicParam.on('valueChanged', emitProjChanged);\n        this.fovParam.on('valueChanged', emitProjChanged);\n        this.nearParam.on('valueChanged', emitProjChanged);\n        this.farParam.on('valueChanged', emitProjChanged);\n        // Initial viewing coords of a person standing 3 meters away from the\n        // center of the stage looking at something 1 meter off the ground.\n        this.setPositionAndTarget(new Vec3(3, 3, 1.75), new Vec3(0, 0, 1));\n        this.setLensFocalLength('35mm');\n    }\n    // ////////////////////////////////////////////\n    // Getters/setters.\n    /**\n     * Returns `near` parameter value.\n     *\n     * @return - Returns the near value.\n     */\n    getNear() {\n        return this.nearParam.value;\n    }\n    /**\n     * Sets `near` parameter value\n     *\n     * @param value - The near value.\n     */\n    setNear(value) {\n        this.nearParam.value = value;\n    }\n    /**\n     * Returns `far` parameter value.\n     *\n     * @return - Returns the far value.\n     */\n    getFar() {\n        return this.farParam.value;\n    }\n    /**\n     * Sets `far` parameter value\n     *\n     * @param value - The far value.\n     */\n    setFar(value) {\n        this.farParam.value = value;\n    }\n    /**\n     * Getter for the camera field of view (FOV).\n     * The FOV defines the vertical angle of the view frustum\n     * The horizontal angle is calculated from the FOV and the Viewport aspect ratio.\n     *\n     * @return - Returns the FOV value.\n     */\n    getFov() {\n        return this.fovParam.value;\n    }\n    /**\n     * Setter for the camera field of view (FOV).\n     * The FOV defines the vertical angle of the view frustum\n     * The horizontal angle is calculated from the FOV and the Viewport aspect ratio.\n     * > Note: The Fov can also be set by calling #setLensFocalLength\n     *\n     * @param value - The new FOV value.\n     */\n    setFov(value) {\n        this.fovParam.value = value;\n    }\n    /**\n     * Getter for the camera frustum height value.\n     * The frustum hight value is used to compute the orthographic projection of the scene.\n     *\n     * @return - Returns the Frustum Height value.\n     */\n    getFrustumHeight() {\n        return this.viewHeight;\n    }\n    /**\n     * Setter for the camera frustum height in orthographic mode.\n     * > Note: in perspective mode, the frustum height is calculated based on the FOV value and focal distance.\n     *\n     * @param value - The new Frustum Height value.\n     */\n    setFrustumHeight(value) {\n        this.viewHeight = value;\n        this.emit('projectionParamChanged');\n    }\n    /**\n     * Setter for the camera lens focal length. This method calculates a new vertical Field of View value\n     * from the provided camera lense focal length.\n     * > Note: conversion from Lense Focal length to Fov is based on the table found here: https://www.nikonians.org/reviews/fov-tables\n     *\n     * **Focal Length accepted values as string values:** 10mm, 11mm, 12mm, 14mm, 15mm, 17mm, 18mm,\n     * 19mm, 20mm, 24mm, 28mm, 30mm, 35mm, 45mm, 50mm, 55mm, 60mm, 70mm, 75mm, 80mm,\n     * 85mm, 90mm, 100mm, 105mm, 120mm, 125mm, 135mm, 150mm, 170mm, 180mm, 210mm, 300mm,\n     * 400mm, 500mm, 600mm, 800mm\n     *\n     * @param value - The lens focal length value.\n     */\n    setLensFocalLength(value) {\n        // https://www.nikonians.org/reviews/fov-tables\n        const mapping = {\n            '10mm': 100.4,\n            '11mm': 95.0,\n            '12mm': 90.0,\n            '14mm': 81.2,\n            '15mm': 77.3,\n            '17mm': 70.4,\n            '18mm': 67.4,\n            '19mm': 64.6,\n            '20mm': 61.9,\n            '24mm': 53.1,\n            '28mm': 46.4,\n            '30mm': 43.6,\n            '35mm': 37.8,\n            '45mm': 29.9,\n            '50mm': 27.0,\n            '55mm': 24.6,\n            '60mm': 22.6,\n            '70mm': 19.5,\n            '75mm': 18.2,\n            '80mm': 17.1,\n            '85mm': 16.1,\n            '90mm': 15.2,\n            '100mm': 13.7,\n            '105mm': 13.0,\n            '120mm': 11.4,\n            '125mm': 11.0,\n            '135mm': 10.2,\n            '150mm': 9.1,\n            '170mm': 8.1,\n            '180mm': 7.6,\n            '210mm': 6.5,\n            '300mm': 4.6,\n            '400mm': 3.4,\n            '500mm': 2.7,\n            '600mm': 2.3,\n            '800mm': 1.7,\n        };\n        if (!(value in mapping)) {\n            console.warn('Camera lense focal length not supported:' + value);\n            return;\n        }\n        this.fovParam.value = MathFunctions.degToRad(mapping[value]);\n    }\n    /**\n     * Returns `focalDistance` parameter value.\n     *\n     * @return - Returns the lens focal length value..\n     */\n    getFocalDistance() {\n        return this.focalDistanceParam.value;\n    }\n    /**\n     * Sets `focalDistance` parameter value.\n     *\n     * @errors on dist value lower or less than zero.\n     * @param dist - The focal distance value.\n     */\n    setFocalDistance(dist) {\n        if (dist < 0.0001)\n            console.error('Never set focal distance to zero');\n        this.focalDistanceParam.value = dist;\n        if (this.adjustNearAndFarPlanesToFocalDist) {\n            this.nearParam.value = dist * this.nearDistFactor;\n            this.farParam.value = dist * this.farDistFactor;\n        }\n    }\n    /**\n     * Returns true if the camera is providing an orthographic projection.\n     * @return - true if orthographic else false\n     */\n    isOrthographic() {\n        return this.isOrthographicParam.value == 1.0;\n    }\n    /**\n     * Sets the camera to be orthographic. The value can be between 0, and 1.\n     * A value of 0 means fully perspective. A value of 1 means fully orthographic.\n     * Any value in between produces a linear interpolation of perspective and orthographic.\n     *\n     * @param value - The value param.\n     * @param duration - The duration in milliseconds to change the projection.\n     */\n    setIsOrthographic(value, duration = 0) {\n        if (this.intervalId)\n            clearInterval(this.intervalId);\n        if (value > 0.5) {\n            const fov = this.fovParam.value;\n            const focalDistance = this.focalDistanceParam.value;\n            this.viewHeight = Math.sin(fov * 0.5) * focalDistance * 2;\n        }\n        if (duration == 0) {\n            this.isOrthographicParam.value = value;\n        }\n        else {\n            const count = Math.round(duration / 20); // each step is 20ms\n            let i = 0;\n            const prevValue = this.isOrthographicParam.value;\n            const applyMovement = () => {\n                i++;\n                const lerpValue = MathFunctions.lerp(prevValue, value, i / count);\n                this.isOrthographicParam.value = lerpValue;\n                if (i < count) {\n                    this.intervalId = window.setTimeout(applyMovement, 20);\n                }\n                else {\n                    this.intervalId = -1;\n                    this.emit('movementFinished');\n                }\n            };\n            applyMovement();\n        }\n    }\n    /**\n     * Setter for the camera position and target.\n     * As described at the start of the class, this is a `TreeItem`,\n     * which means we can move it around using translation modifiers.\n     * You can do it this way or using the changing `TreeItem` parameters,\n     * although we recommend this one because it also changes focal distance.\n     *\n     * @param position - The position of the camera.\n     * @param target - The target of the camera.\n     */\n    setPositionAndTarget(position, target) {\n        this.setFocalDistance(position.distanceTo(target));\n        const xfo = new Xfo();\n        xfo.setLookAt(position, target, new Vec3(0.0, 0.0, 1.0));\n        this.globalXfoParam.value = xfo;\n        this.emit('movementFinished');\n    }\n    /**\n     * Getter for the target position.\n     * @return - Returns the target position.\n     */\n    getTargetPosition() {\n        const focalDistance = this.focalDistanceParam.value;\n        const xfo = this.globalXfoParam.value;\n        const target = xfo.ori.getZaxis();\n        target.scaleInPlace(-focalDistance);\n        target.addInPlace(xfo.tr);\n        return target;\n    }\n    // ///////////////////////////\n    /**\n     * Calculates a new camera position that frames all the items passed in `treeItems` array, moving\n     * the camera to a point where we can see all of them.\n     *\n     * @param viewport - The viewport value.\n     * @param treeItems - The treeItems value.\n     * @param duration - The duration of time to apply the frame. A value of 0 specifies an instantaneous movement of the camera.\n     * @param frameBorder - The variable to use to provide an empty space around the border for geometries.\n     */\n    frameView(width, height, treeItems, duration = 0, frameBorder = 0.1) {\n        const focalDistance = this.focalDistanceParam.value;\n        const fovY = this.fovParam.value;\n        const isOrthographic = this.isOrthographicParam.value;\n        const newGlobalXfo = this.globalXfoParam.value.clone();\n        const aspectRatio = width / height;\n        const fovX = Math.atan(Math.tan(fovY * 0.5) * aspectRatio) * 2.0;\n        let newFocalDistance = focalDistance;\n        if (this.frameOnBoundingSphere) {\n            const box3 = new Box3();\n            for (const treeItem of treeItems) {\n                box3.addBox3(treeItem.boundingBoxParam.value);\n            }\n            if (!box3.isValid()) {\n                console.warn('Bounding box not valid.');\n                return;\n            }\n            const cameraViewVec = newGlobalXfo.ori.getZaxis();\n            const targetOffset = cameraViewVec.scale(-focalDistance);\n            const currTarget = newGlobalXfo.tr.add(targetOffset);\n            const newTarget = box3.center();\n            const pan = newTarget.subtract(currTarget);\n            newGlobalXfo.tr.addInPlace(pan);\n            // Compute the distance the camera should be to fit the entire bounding sphere\n            newFocalDistance = box3.size() / Math.tan(fovY);\n            // const dollyDist = newFocalDistance - focalDistance\n            // newGlobalXfo.tr.addInPlace(cameraViewVec.scale(dollyDist))\n        }\n        else {\n            // Based on the solution described here:\n            // https://stackoverflow.com/a/66113254/5546902\n            const boundaryPoints = [];\n            {\n                treeItems.forEach((treeItem) => {\n                    treeItem.traverse((childItem) => {\n                        // Stop traversal when we hig an item with a disabled bounding box\n                        // or non-tree item.\n                        if (!(childItem instanceof TreeItem))\n                            return false;\n                        if (childItem.disableBoundingBox)\n                            return false;\n                        if (!childItem.isVisible() || !childItem.isPickable())\n                            return false;\n                        if (childItem instanceof GeomItem) {\n                            const geom = childItem.geomParam.value;\n                            if (geom) {\n                                const box3 = geom.getBoundingBox();\n                                if (box3.isValid()) {\n                                    const mat4 = childItem.geomMatParam.value;\n                                    boundaryPoints.push(mat4.transformVec3(box3.p0));\n                                    boundaryPoints.push(mat4.transformVec3(new Vec3(box3.p0.x, box3.p0.y, box3.p1.z)));\n                                    boundaryPoints.push(mat4.transformVec3(new Vec3(box3.p0.x, box3.p1.y, box3.p0.z)));\n                                    boundaryPoints.push(mat4.transformVec3(new Vec3(box3.p1.x, box3.p0.y, box3.p0.z)));\n                                    boundaryPoints.push(mat4.transformVec3(new Vec3(box3.p0.x, box3.p1.y, box3.p1.z)));\n                                    boundaryPoints.push(mat4.transformVec3(new Vec3(box3.p1.x, box3.p0.y, box3.p1.z)));\n                                    boundaryPoints.push(mat4.transformVec3(new Vec3(box3.p1.x, box3.p1.y, box3.p0.z)));\n                                    boundaryPoints.push(mat4.transformVec3(box3.p1));\n                                    return;\n                                }\n                            }\n                        }\n                        if (childItem.getNumChildren() == 0 || childItem instanceof BaseGroup) {\n                            const box3 = childItem.boundingBoxParam.value;\n                            if (box3.isValid()) {\n                                // Note: passing box3.p0 into boundaryPoints caused corruption later on.\n                                // I could not figure out how/why, but by constructing a new vector here,\n                                // we avoid the problem.\n                                boundaryPoints.push(new Vec3(box3.p0.x, box3.p0.y, box3.p0.z));\n                                boundaryPoints.push(new Vec3(box3.p0.x, box3.p0.y, box3.p1.z));\n                                boundaryPoints.push(new Vec3(box3.p0.x, box3.p1.y, box3.p0.z));\n                                boundaryPoints.push(new Vec3(box3.p1.x, box3.p0.y, box3.p0.z));\n                                boundaryPoints.push(new Vec3(box3.p0.x, box3.p1.y, box3.p1.z));\n                                boundaryPoints.push(new Vec3(box3.p1.x, box3.p0.y, box3.p1.z));\n                                boundaryPoints.push(new Vec3(box3.p1.x, box3.p1.y, box3.p0.z));\n                                boundaryPoints.push(new Vec3(box3.p1.x, box3.p1.y, box3.p1.z));\n                                return;\n                            }\n                        }\n                    }, true /*include this*/);\n                });\n            }\n            if (boundaryPoints.length == 0)\n                return;\n            const angleX = isOrthographic ? 0 : fovX / 2;\n            const angleY = isOrthographic ? 0 : fovY / 2;\n            const frustumPlaneNormals = {};\n            frustumPlaneNormals.XPos = new Vec3(Math.cos(angleX), 0, Math.sin(angleX));\n            frustumPlaneNormals.XNeg = new Vec3(-Math.cos(angleX), 0, Math.sin(angleX));\n            frustumPlaneNormals.YPos = new Vec3(0, Math.cos(angleY), Math.sin(angleY));\n            frustumPlaneNormals.YNeg = new Vec3(0, -Math.cos(angleY), Math.sin(angleY));\n            frustumPlaneNormals.ZPos = new Vec3(0, 0, 1);\n            frustumPlaneNormals.ZNeg = new Vec3(0, 0, -1);\n            const frustumPlaneNormalsWs = {};\n            const frustumPlaneOffsets = {};\n            // eslint-disable-next-line guard-for-in\n            for (const key in frustumPlaneNormals) {\n                frustumPlaneNormalsWs[key] = newGlobalXfo.ori.rotateVec3(frustumPlaneNormals[key]);\n                frustumPlaneOffsets[key] = Number.NEGATIVE_INFINITY;\n            }\n            const centroid = new Vec3();\n            boundaryPoints.forEach((point, index) => {\n                // Previously we had corrupt values coming through there. That is fixed,\n                // but just in case, we filter them out again here.\n                if (!Number.isFinite(point.x) || !Number.isFinite(point.y) || !Number.isFinite(point.z)) {\n                    return;\n                }\n                const delta = point.subtract(newGlobalXfo.tr);\n                // eslint-disable-next-line guard-for-in\n                for (const key in frustumPlaneNormals) {\n                    const planeOffset = delta.dot(frustumPlaneNormalsWs[key]);\n                    if (planeOffset > frustumPlaneOffsets[key] && planeOffset != Number.POSITIVE_INFINITY) {\n                        frustumPlaneOffsets[key] = planeOffset;\n                    }\n                }\n                centroid.addInPlace(point);\n            });\n            // eslint-disable-next-line guard-for-in\n            // Check for invalid planes.\n            for (const key in frustumPlaneOffsets) {\n                if (frustumPlaneOffsets[key] == Number.POSITIVE_INFINITY)\n                    return;\n            }\n            centroid.scaleInPlace(1 / boundaryPoints.length);\n            let dolly = 0;\n            if (isOrthographic) {\n                const pan = new Vec3((-frustumPlaneOffsets.XNeg + frustumPlaneOffsets.XPos) * 0.5, (-frustumPlaneOffsets.YNeg + frustumPlaneOffsets.YPos) * 0.5, (-frustumPlaneOffsets.ZNeg + frustumPlaneOffsets.ZPos) * 0.5);\n                // Move the camera back by 2x the depth range of the scene.\n                const zrange = frustumPlaneOffsets.ZNeg + frustumPlaneOffsets.ZPos;\n                dolly = zrange * 2;\n                pan.z = -frustumPlaneOffsets.ZNeg + dolly;\n                newGlobalXfo.tr.addInPlace(newGlobalXfo.ori.rotateVec3(pan));\n                newFocalDistance = zrange * 2;\n                const viewWidth = frustumPlaneOffsets.XPos + frustumPlaneOffsets.XNeg;\n                const viewHeight = frustumPlaneOffsets.YPos + frustumPlaneOffsets.YNeg;\n                this.viewHeight = Math.max(viewHeight, viewWidth / aspectRatio);\n                this.viewHeight += this.viewHeight * frameBorder;\n            }\n            else {\n                const angleX = fovX / 2;\n                const angleY = fovY / 2;\n                // Now we solve the problem in 2D. For each camera plane (XZ and YZ), we calculate the lines in 2d that\n                // represent the frustum planes for the top and bottom, adjusted so they touch the boundary points. We\n                // then find the intersection of these 2 2d lines to calculate the adjustment in that axis for the camera.\n                // We need to dolly back to fix the plane which needs the most adjustment.\n                // Calculate a 2d point on the line for each plane, and a direction.\n                const xP0 = new Vec2(Math.cos(angleX) * frustumPlaneOffsets.XPos, Math.sin(angleX) * frustumPlaneOffsets.XPos);\n                const xP1 = xP0.add(new Vec2(Math.sin(angleX), -Math.cos(angleX)));\n                const xP2 = new Vec2(-Math.cos(angleX) * frustumPlaneOffsets.XNeg, Math.sin(angleX) * frustumPlaneOffsets.XNeg);\n                const xP3 = xP2.add(new Vec2(-Math.sin(angleX), -Math.cos(angleX)));\n                const xP = Vec2.intersectionOfLines(xP0, xP1, xP2, xP3);\n                const yP0 = new Vec2(Math.cos(angleY) * frustumPlaneOffsets.YPos, Math.sin(angleY) * frustumPlaneOffsets.YPos);\n                const yP1 = yP0.add(new Vec2(Math.sin(angleY), -Math.cos(angleY)));\n                const yP2 = new Vec2(-Math.cos(angleY) * frustumPlaneOffsets.YNeg, Math.sin(angleY) * frustumPlaneOffsets.YNeg);\n                const yP3 = yP2.add(new Vec2(-Math.sin(angleY), -Math.cos(angleY)));\n                const yP = Vec2.intersectionOfLines(yP0, yP1, yP2, yP3);\n                if (xP === null || yP === null) {\n                    console.warn('xP or yP === null');\n                    return;\n                }\n                dolly = Math.max(xP.y, yP.y);\n                const pan = new Vec3(xP.x, yP.x, dolly);\n                newGlobalXfo.tr.addInPlace(newGlobalXfo.ori.rotateVec3(pan));\n                newFocalDistance = centroid.distanceTo(newGlobalXfo.tr);\n                const frameBorderAdjustment = newFocalDistance * frameBorder;\n                newGlobalXfo.tr.addInPlace(newGlobalXfo.ori.rotateVec3(new Vec3(0, 0, frameBorderAdjustment)));\n                dolly += frameBorderAdjustment;\n            }\n            if (this.adjustNearAndFarPlanesToFocalDist) {\n                frustumPlaneOffsets.ZPos -= dolly;\n                frustumPlaneOffsets.ZNeg += dolly;\n                const near = frustumPlaneOffsets.ZNeg * this.nearDistFactor;\n                const far = -frustumPlaneOffsets.ZPos * this.farDistFactor;\n                this.nearParam.value = near;\n                this.farParam.value = far;\n            }\n        }\n        if (duration == 0) {\n            this.setFocalDistance(newFocalDistance);\n            this.globalXfoParam.value = newGlobalXfo;\n            this.emit('movementFinished');\n        }\n        else {\n            if (this.intervalId > 0)\n                window.clearTimeout(this.intervalId);\n            const count = Math.round(duration / 20); // each step is 20ms\n            let i = 0;\n            const prevFocalDistance = this.focalDistanceParam.value;\n            const prevXfo = this.globalXfoParam.value;\n            const applyMovement = () => {\n                i++;\n                const t = i / count;\n                const focalDistance = MathFunctions.lerp(prevFocalDistance, newFocalDistance, t);\n                const globalXfo = prevXfo.lerp(newGlobalXfo, t);\n                this.globalXfoParam.value = globalXfo;\n                this.setFocalDistance(focalDistance);\n                if (i < count) {\n                    this.intervalId = window.setTimeout(applyMovement, 20);\n                }\n                else {\n                    this.intervalId = -1;\n                    this.emit('movementFinished');\n                }\n            };\n            applyMovement();\n        }\n    }\n    /**\n     * Sets camera perspective from a Mat4 object.\n     *\n     * @param mat - The mat value.\n     * @param aspect - The aspect value.\n     */\n    updateProjectionMatrix(mat, aspect) {\n        const isOrthographic = this.isOrthographicParam.value;\n        const fov = this.fovParam.value;\n        const near = this.nearParam.value;\n        const far = this.farParam.value;\n        const orthoMat = new Mat4();\n        if (isOrthographic > 0.0) {\n            const halfHeight = this.viewHeight * 0.5;\n            const bottom = -halfHeight;\n            const top = halfHeight;\n            const left = halfHeight * -aspect;\n            const right = halfHeight * aspect;\n            orthoMat.setOrthographicMatrix(left, right, bottom, top, near, far);\n        }\n        if (isOrthographic < 1.0) {\n            mat.setPerspectiveMatrix(fov, aspect, near, far);\n        }\n        if (isOrthographic == 1.0) {\n            mat.setFromMat4(orthoMat);\n        }\n        else if (isOrthographic > 0.0) {\n            mat.set(MathFunctions.lerp(mat.m00, orthoMat.m00, isOrthographic), MathFunctions.lerp(mat.m01, orthoMat.m01, isOrthographic), MathFunctions.lerp(mat.m02, orthoMat.m02, isOrthographic), MathFunctions.lerp(mat.m03, orthoMat.m03, isOrthographic), MathFunctions.lerp(mat.m10, orthoMat.m10, isOrthographic), MathFunctions.lerp(mat.m11, orthoMat.m11, isOrthographic), MathFunctions.lerp(mat.m12, orthoMat.m12, isOrthographic), MathFunctions.lerp(mat.m13, orthoMat.m13, isOrthographic), MathFunctions.lerp(mat.m20, orthoMat.m20, isOrthographic), MathFunctions.lerp(mat.m21, orthoMat.m21, isOrthographic), MathFunctions.lerp(mat.m22, orthoMat.m22, isOrthographic), MathFunctions.lerp(mat.m23, orthoMat.m23, isOrthographic), MathFunctions.lerp(mat.m30, orthoMat.m30, isOrthographic), MathFunctions.lerp(mat.m31, orthoMat.m31, isOrthographic), MathFunctions.lerp(mat.m32, orthoMat.m32, isOrthographic), MathFunctions.lerp(mat.m33, orthoMat.m33, isOrthographic));\n        }\n    }\n}\nRegistry.register('Camera', Camera);\n\n/**\n * The GridTreeItem displays a grid of a given size and resolution. The Grid is oriented on the XY plane\n * and highlights the X and Y axes with Red and Green lines. Grids are useful in displaying scene scale and coordinate system.\n * The Grid geometry does not return a bounding box and so does not effect the bounding of the scene.\n *\n * @extends {TreeItem}\n */\nclass GridTreeItem extends TreeItem {\n    /**\n     * Creates an instance of GridTree.\n     *\n     * @param gridSize\n     * @param resolution\n     * @param gridColor\n     */\n    constructor(gridSize = 5, resolution = 50, gridColor = new Color('#DCDCDC')) {\n        super('GridTree');\n        this.disableBoundingBox = true;\n        this.pickableParam.value = false;\n        const gridMaterial = new LinesMaterial('gridMaterial');\n        gridMaterial.baseColorParam.value = gridColor;\n        gridMaterial.overlayParam.value = 0.0;\n        const grid = new Grid(gridSize, gridSize, resolution, resolution, true);\n        const gridItem = new GeomItem('GridItem', grid, gridMaterial);\n        gridItem.pickableParam.value = false;\n        this.addChild(gridItem, false);\n        const axisLine = new Lines();\n        axisLine.setNumVertices(2);\n        axisLine.setNumSegments(1);\n        axisLine.setSegmentVertexIndices(0, 0, 1);\n        const positions = axisLine.getVertexAttribute('positions');\n        positions.setValue(0, new Vec3(gridSize * -0.5, 0.0, 0.0));\n        positions.setValue(1, new Vec3(gridSize * 0.5, 0.0, 0.0));\n        const gridXAxisMaterial = new LinesMaterial('gridXAxisMaterial');\n        gridXAxisMaterial.baseColorParam.value = new Color(gridColor.luminance(), 0, 0);\n        gridXAxisMaterial.overlayParam.value = 0.0;\n        const gridXAxis = new GeomItem('xAxisLine', axisLine, gridXAxisMaterial);\n        gridXAxis.pickableParam.value = false;\n        this.addChild(gridXAxis, false);\n        const gridYAxisMaterial = new LinesMaterial('gridYAxisMaterial');\n        gridYAxisMaterial.baseColorParam.value = new Color(0, gridColor.luminance(), 0);\n        gridYAxisMaterial.overlayParam.value = 0.0;\n        const zAxisLineItem = new GeomItem('yAxisLine', axisLine, gridYAxisMaterial);\n        zAxisLineItem.pickableParam.value = false;\n        const geomOffset = new Xfo();\n        geomOffset.ori.setFromAxisAndAngle(new Vec3(0, 0, 1), Math.PI * 0.5);\n        zAxisLineItem.geomOffsetXfoParam.value = geomOffset;\n        this.addChild(zAxisLineItem, false);\n    }\n    cleanBoundingBox() {\n        return new Box3();\n    }\n}\nRegistry.register('GridTreeItem', GridTreeItem);\n\nconst defaultGridColor = new Color('#DCDCDC');\n/**\n * Class representing the environment where all the displayed assets live.\n */\nclass Scene {\n    /**\n     * @member envMapParam - The image displayed and used for the environment map.\n     */\n    envMapParam = new ImageParameter('EnvMap');\n    /**\n     * @member displayEnvMapParam - Boolean that determines whether or not the environment map should be displayed.\n     */\n    displayEnvMapParam = new BooleanParameter('Display EnvMap', false);\n    /**\n     * @member envMapLODParam - TODO\n     */\n    envMapLODParam = new NumberParameter('EnvMapLOD', 0);\n    root = new TreeItem('root');\n    /**\n     * Create a scene.\n     */\n    constructor() { }\n    /**\n     * Returns the scene's root item(`TreeItem`) that owns every item in the scene.\n     *\n     * @return - The return value.\n     */\n    getRoot() {\n        return this.root;\n    }\n    /**\n     * Returns resourceLoader object set on class initialization.\n     *\n     * @return - The return value.\n     */\n    getResourceLoader() {\n        return resourceLoader;\n    }\n    /**\n     * Sets Environment Map with the BaseImage you'd like to display in your scene background.\n     *\n     * @param envMap - The envMap value.\n     */\n    setEnvMap(envMap) {\n        this.envMapParam.value = envMap;\n    }\n    /**\n     * Sets up and displays the scene grid of a given size and resolution. The Grid is oriented on the XY plane\n     * and highlights the X and Y axes with Red and Green lines. Grids are useful in displaying scene scale and coordinate system.\n     * The Grid geometry does not return a bounding box and so does not effect the bounding of the scene.\n     * The GridTreeItem display a grid of a given size and resolution. The Grid is oriented on the XY plane\n     * and highlights the X and Y axes with Red and Green lines.\n     *\n     * @param gridSize - The size of the grid.\n     * @param resolution - The resolution of the grid.\n     * @param gridColor - The color of the grid.\n     * @return - The return value.\n     */\n    setupGrid(gridSize = 5, resolution = 50, gridColor = defaultGridColor) {\n        const gridTreeItem = new GridTreeItem(gridSize, resolution, gridColor);\n        this.root.addChild(gridTreeItem, false);\n        return gridTreeItem;\n    }\n}\n\n/**\n * Class designed to load and handle `.vla` files.\n *\n * **Events**\n * * **loaded:** Triggered once the tree is loaded. Note: the tree bounding box is valid once the tree is loaded.\n * * **geomsLoaded:** Triggered once all geometries are loaded.\n *\n * @extends AssetItem\n */\nclass VLAAsset extends AssetItem {\n    /**\n     * Create a VLA asset.\n     * @param name - The name value.\n     */\n    constructor(name) {\n        super(name);\n        // A signal that is emitted once all the geometries are loaded.\n        // Often the state machine will activate the\n        // first state when this signal emits.\n        this.geomLibrary.on('loaded', () => {\n            this.emit('geomsLoaded');\n        });\n    }\n    // ////////////////////////////////////////\n    // Persistence\n    /**\n     * Sets state of current asset using a binary reader object.\n     *\n     * @param reader - The reader value.\n     * @param context - The context value.\n     * @return - The return value.\n     */\n    readBinary(reader, context) {\n        if (context.versions['zea-engine']) ;\n        else {\n            // Now we split the mesh out from the engine version.\n            context.versions['zea-mesh'] = new Version(reader.loadStr());\n        }\n        // console.log('Loading Mesh File version:', context.versions['zea-mesh'])\n        const numGeomsFiles = reader.loadUInt32();\n        super.readBinary(reader, context);\n        if (context.versions['zea-engine'].compare([2, 1, 0]) < 0) {\n            // Some data is no longer being read at the end of the buffer\n            // so we skip to the end here.\n            // The data was the atlas size of the lightmap that we no longer support.\n            reader.loadFloat32Vec2();\n        }\n        this.geomLibrary.setNumGeoms(reader.loadUInt32());\n        return numGeomsFiles;\n    }\n    /**\n     * Loads all the geometries and metadata from the asset file.\n     * @param url - The URL of the asset to load\n     * @param context - The load context object that provides additional data such as the units of the scene we are loading into.\n     * @return - Returns a promise that resolves once the initial load is complete\n     */\n    load(url, context = new AssetLoadContext()) {\n        return new Promise((resolve, reject) => {\n            const folder = url.lastIndexOf('/') > -1 ? url.substring(0, url.lastIndexOf('/')) + '/' : '';\n            const filename = url.lastIndexOf('/') > -1 ? url.substring(url.lastIndexOf('/') + 1) : '';\n            const stem = filename.substring(0, filename.lastIndexOf('.'));\n            let numGeomsFiles = 0;\n            context.assetItem = this;\n            context.url = url;\n            context.folder = folder;\n            // preload in case we don't have embedded geoms.\n            // completed by geomLibrary.on('loaded' ..\n            resourceLoader.incrementWorkload(1);\n            // To ensure that the resource loader knows when\n            // parsing is done, we listen to the GeomLibrary streamFileLoaded\n            // signal. This is fired once the entire stream is parsed.\n            this.geomLibrary.on('loaded', () => {\n                // A chunk of geoms are now parsed, so update the resource loader.\n                resourceLoader.incrementWorkDone(1);\n            });\n            resourceLoader.loadFile('archive', url).then((entries) => {\n                // Load the tree file. This file contains\n                // the scene tree of the asset, and also\n                // tells us how many geom files will need to be loaded.\n                let treeReader;\n                if (entries.tree2) {\n                    treeReader = new BinReader(entries.tree2.buffer, 0, SystemDesc.isMobileDevice);\n                }\n                else {\n                    const entry = entries.tree ? entries.tree : entries[Object.keys(entries)[0]];\n                    treeReader = new BinReader(entry.buffer, 0, SystemDesc.isMobileDevice);\n                    context.versions['zea-engine'] = new Version();\n                }\n                numGeomsFiles = this.readBinary(treeReader, context);\n                this.loaded = true;\n                this.emit('loaded');\n                if (numGeomsFiles == 0 && entries.geoms) {\n                    this.geomLibrary.readBinaryBuffer(-1, entries.geoms.buffer, context);\n                }\n                else {\n                    const basePath = folder + stem;\n                    const geomLibraryJSON = {\n                        numGeomsPerFile: numGeomsFiles,\n                        numGeoms: this.geomLibrary.getNumGeoms(), // Note: was set during readBinary.Why do we need to provide this again?\n                    };\n                    this.geomLibrary.loadGeomFilesStream(geomLibraryJSON, basePath, context);\n                }\n                resolve();\n            }, (error) => {\n                this.emit('error', error);\n                reject(error);\n            });\n        });\n    }\n}\nRegistry.register('VLAAsset', VLAAsset);\n\n/* eslint-disable guard-for-in */\n// AssetItem.registerDataLoader('.obj', ObjDataLoader);\n/**\n * Class designed to load and handle `.obj` files.\n * Which define the geometry and other properties for objects.\n *\n * **Parameters**\n * * **splitObjects(`BooleanParameter`):** _todo_\n * * **splitGroupsIntoObjects(`BooleanParameter`):** _todo_\n * * **loadMtlFile(`BooleanParameter`):** _todo_\n * * **unitsConversion(`NumberParameter`):** _todo_\n * * **defaultShader(`StringParameter`):** _todo_\n *\n * **Events**\n * * **loaded:** Triggered once everything is loaded.\n * * **geomsLoaded:** Triggered once all geometries are loaded.\n *\n * @extends AssetItem\n */\nclass ObjAsset extends AssetItem {\n    splitObjects = new BooleanParameter('splitObjects', false);\n    splitGroupsIntoObjects = new BooleanParameter('splitGroupsIntoObjects', false);\n    loadMtlFile = new BooleanParameter('loadMtlFile', true);\n    unitsConversion = new NumberParameter('unitsConversion', 1.0);\n    defaultShader = new StringParameter('defaultShader', '');\n    /**\n     * Create an obj asset.\n     * @param name - The name of the object asset.\n     */\n    /**\n     * @member splitObjectsParam - TODO\n     */\n    splitObjectsParam = new BooleanParameter('splitObjects', false);\n    /**\n     * @member splitGroupsIntoObjectsParam - TODO\n     */\n    splitGroupsIntoObjectsParam = new BooleanParameter('splitGroupsIntoObjects', false);\n    /**\n     * @member loadMtlFileParam - TODO\n     */\n    loadMtlFileParam = new BooleanParameter('loadMtlFile', true);\n    /**\n     * @member unitsConversionParam - TODO\n     */\n    unitsConversionParam = new NumberParameter('unitsConversion', 1.0);\n    /**\n     * @member defaultShaderParam - The default shader to use.\n     */\n    defaultShaderParam = new StringParameter('defaultShader', '');\n    constructor(name) {\n        super(name);\n        this.addParameter(this.splitObjectsParam);\n        this.addParameter(this.splitGroupsIntoObjectsParam);\n        this.addParameter(this.loadMtlFileParam);\n        this.addParameter(this.unitsConversionParam);\n        this.addParameter(this.defaultShaderParam);\n    }\n    /**\n     * Loads all the geometries and metadata from the Obj file.\n     * @param url - The URL of the asset to load\n     * @return - Returns a promise that resolves once the initial load is complete\n     */\n    load(url) {\n        this.loaded = false;\n        return new Promise((resolve, reject) => {\n            const fileFolder = url.substring(0, url.lastIndexOf('/')) + '/';\n            const parseMtlData = (mtlFileData) => {\n                const lines = mtlFileData.split('\\n');\n                const WHITESPACE_RE = /\\s+/;\n                let material;\n                const parseColor = function (elements) {\n                    if (elements.length == 3)\n                        return new Color(parseFloat(elements[0]), parseFloat(elements[1]), parseFloat(elements[2]));\n                    else\n                        throw new Error('Unable to parse a color from the following parts:' + elements.join('_'));\n                };\n                const parseMap = (name, filename) => {\n                    const fileImage = new FileImage(name);\n                    fileImage.load(fileFolder + filename);\n                    return fileImage;\n                };\n                for (let i = 0; i < lines.length; i++) {\n                    let line = lines[i].trim();\n                    if (line.startsWith('#'))\n                        continue;\n                    if (line.includes('#'))\n                        line = line.substring(0, line.indexOf('#')).trim();\n                    const elements = line.split(WHITESPACE_RE);\n                    const key = elements.shift();\n                    const value = elements.join(' ');\n                    switch (key) {\n                        case 'newmtl':\n                            material = new StandardSurfaceMaterial(value);\n                            this.materialLibrary.addMaterial(material);\n                            break;\n                        case 'Kd': {\n                            material.baseColorParam.value = parseColor(elements);\n                            material.baseColorParam.colorSpace == ColorSpace.Linear;\n                            break;\n                        }\n                        case 'map_Kd': {\n                            material.baseColorParam.setImage(parseMap('map_Kd', elements[0]));\n                            break;\n                        }\n                        case 'Ks':\n                            const specular = (parseFloat(elements[0]) + parseFloat(elements[1]) + parseFloat(elements[2])) / 3.0;\n                            material.roughnessParam.value = 1.0 - specular;\n                            material.reflectanceParam.value = specular;\n                            break;\n                        case 'map_Ks':\n                            material.roughnessParam.setImage(parseMap('map_Ks', elements[0])); /* flags=TEXTURE_INVERT */\n                            material.reflectanceParam.value = 0.2;\n                            break;\n                        case 'd':\n                            material.opacityParam.value = parseFloat(value);\n                            break;\n                        case 'map_d':\n                            material.opacityParam.setImage(parseMap('map_Kd', elements[0]));\n                            break;\n                        case 'map_bump':\n                            material.normalParam.setImage(parseMap('normal', elements[0])); /* flags=BUMP_TO_NORMAL */\n                            break;\n                        // console.warn(\"Unhandled material parameter: '\" + key +\"' in:\" + filePath);\n                    }\n                }\n            };\n            const loadMtlFile = (mtlFile) => {\n                return new Promise((resolve) => {\n                    loadTextfile(mtlFile, (fileData) => {\n                        resourceLoader.incrementWorkDone(1);\n                        parseMtlData(fileData);\n                        resourceLoader.incrementWorkDone(1);\n                        resolve();\n                    });\n                });\n            };\n            const vertices = [];\n            const normals = [];\n            const texCoords = [];\n            const geomDatas = {};\n            const parseObjData = async (fileData) => {\n                // performance.mark(\"parseObjData\");\n                // array of lines separated by the newline\n                const lines = fileData.split('\\n');\n                const WHITESPACE_RE = /\\s+/;\n                let currGeom = undefined;\n                let currMtl = undefined;\n                let numGeoms = 0;\n                const newGeom = (name) => {\n                    if (name in geomDatas) {\n                        let suffix = 1;\n                        while (name + String(suffix) in geomDatas) {\n                            suffix++;\n                        }\n                        name = name + String(suffix);\n                    }\n                    currGeom = {\n                        verticesRemapping: {},\n                        texCoordsRemapping: {},\n                        normalsRemapping: {},\n                        vertexIndices: [],\n                        texCoordIndices: [],\n                        normalIndices: [],\n                        numVertices: 0,\n                        numTexCoords: 0,\n                        numNormals: 0,\n                        faceCounts: [],\n                        material: currMtl,\n                    };\n                    geomDatas[name] = currGeom;\n                    numGeoms++;\n                };\n                newGeom('geom');\n                const splitGroupsIntoObjects = this.splitGroupsIntoObjectsParam.value;\n                const stop = false;\n                // let numPolys = 0;\n                for (let i = 0; i < lines.length && !stop; i++) {\n                    let line = lines[i].trim();\n                    if (line.startsWith('#'))\n                        continue;\n                    if (line.includes('#'))\n                        line = line.substring(0, line.indexOf('#')).trim();\n                    const elements = line.split(WHITESPACE_RE);\n                    const key = elements.shift();\n                    const value = elements.join(' ');\n                    switch (key) {\n                        case '':\n                        case 's':\n                            // ignore shading groups\n                            continue;\n                        case 'mtllib':\n                            if (!this.loadMtlFileParam.value)\n                                continue;\n                            // Load and parse the mat lib.\n                            resourceLoader.incrementWorkload(2);\n                            const mtlFile = fileFolder + value;\n                            if (mtlFile) {\n                                await loadMtlFile(mtlFile);\n                            }\n                            break;\n                        case 'o':\n                            newGeom(value);\n                            break;\n                        case 'usemtl':\n                            currMtl = value;\n                            newGeom(value + Object.keys(geomDatas).length);\n                            break;\n                        case 'g':\n                            if (splitGroupsIntoObjects) {\n                                newGeom(value ? elements.join('_') : 'Group' + numGeoms);\n                            }\n                            break;\n                        case 'v':\n                            vertices.push(elements.map((i) => parseFloat(i)));\n                            break;\n                        case 'vt':\n                            texCoords.push(elements.map((i) => parseFloat(i)));\n                            break;\n                        case 'vn':\n                            normals.push(elements.map((i) => parseFloat(i)));\n                            break;\n                        case 'f': {\n                            const v_poly = [];\n                            const vt_poly = [];\n                            const vn_poly = [];\n                            for (let j = 0, eleLen = elements.length; j < eleLen; j++) {\n                                // v/vt/vn\n                                const indices = elements[j].split('/').map((i) => parseInt(i) - 1);\n                                const v = indices[0];\n                                // v_poly.push(v);\n                                let v_index = currGeom.verticesRemapping[v];\n                                if (v_index == undefined) {\n                                    v_index = currGeom.numVertices;\n                                    currGeom.verticesRemapping[v] = v_index;\n                                    currGeom.numVertices++;\n                                }\n                                v_poly.push(v_index);\n                                if (indices.length > 1 && !isNaN(indices[1])) {\n                                    const vt = indices[1];\n                                    vt_poly.push(vt);\n                                }\n                                if (indices.length > 2 && !isNaN(indices[2])) {\n                                    const vn = indices[2];\n                                    vn_poly.push(vn);\n                                }\n                            }\n                            currGeom.vertexIndices.push(v_poly);\n                            if (vn_poly.length > 0)\n                                currGeom.normalIndices.push(vn_poly);\n                            if (vt_poly.length > 0)\n                                currGeom.texCoordIndices.push(vt_poly);\n                            if (currGeom.faceCounts[v_poly.length - 3] == undefined) {\n                                currGeom.faceCounts[v_poly.length - 3] = [];\n                            }\n                            currGeom.faceCounts[v_poly.length - 3]++;\n                            // numPolys++;\n                            // if(numPolys == 16000)\n                            //     stop = true;\n                            break;\n                        }\n                        default: {\n                            console.warn('Unhandled line:' + line);\n                        }\n                    }\n                }\n            };\n            const buildChildItems = () => {\n                // performance.mark(\"parseObjDataDone\");\n                // performance.mark(\"buildObjTree\");\n                for (const geomName in geomDatas) {\n                    if (geomDatas[geomName].numVertices == 0)\n                        continue;\n                    buildChildItem(geomName, geomDatas[geomName]);\n                }\n                // Done.\n                this.emit('loaded');\n                this.getGeometryLibrary().emit('loaded');\n                this.emit('geomsLoaded');\n                resolve();\n            };\n            const buildChildItem = (geomName, geomData) => {\n                for (let i = 0; i < geomData.faceCounts.length; i++) {\n                    if (geomData.faceCounts[i] == undefined) {\n                        geomData.faceCounts[i] = 0;\n                    }\n                }\n                const numVertices = geomData.numVertices;\n                const mesh = new Mesh();\n                mesh.name = geomName;\n                mesh.setFaceCounts(geomData.faceCounts);\n                mesh.setNumVertices(numVertices);\n                const positionsAttr = mesh.getVertexAttribute('positions');\n                const unitsConversion = this.unitsConversionParam.value;\n                for (const vsrcKey in geomData.verticesRemapping) {\n                    const vsrc = Number.parseInt(vsrcKey);\n                    const vtgt = geomData.verticesRemapping[vsrc];\n                    positionsAttr.setValue(vtgt, new Vec3(vertices[vsrc][0] * unitsConversion, vertices[vsrc][1] * unitsConversion, vertices[vsrc][2] * unitsConversion));\n                }\n                let normalsAttr;\n                let texCoordsAttr;\n                if (geomData.normalIndices.length > 0) {\n                    normalsAttr = new Vec3Attribute();\n                    mesh.addVertexAttribute('normals', normalsAttr); // TODO: this method returns void\n                }\n                if (geomData.texCoordIndices.length > 0) {\n                    texCoordsAttr = new Vec2Attribute();\n                    mesh.addVertexAttribute('texCoords', texCoordsAttr);\n                }\n                const loadedFaces = Array(geomData.faceCounts.length).fill(0);\n                for (let i = 0; i < geomData.vertexIndices.length; i++) {\n                    const v_poly = geomData.vertexIndices[i];\n                    let faceId = 0;\n                    for (let j = 0; j < v_poly.length - 3; ++j) {\n                        if (geomData.faceCounts[j])\n                            faceId += geomData.faceCounts[j];\n                    }\n                    faceId += loadedFaces[v_poly.length - 3];\n                    loadedFaces[v_poly.length - 3]++;\n                    mesh.setFaceVertexIndices(faceId, v_poly);\n                    // Set the texCoords and normals...\n                    if (normalsAttr) {\n                        const vn_poly = geomData.normalIndices[i];\n                        for (let j = 0; j < vn_poly.length; j++) {\n                            const value = new Vec3(normals[vn_poly[j]][0], normals[vn_poly[j]][1], normals[vn_poly[j]][2]);\n                            normalsAttr.setFaceVertexValue(faceId, j, value);\n                        }\n                    }\n                    if (texCoordsAttr && geomData.texCoordIndices.length == geomData.vertexIndices.length) {\n                        const vt_poly = geomData.texCoordIndices[i];\n                        for (let j = 0; j < vt_poly.length; j++) {\n                            const value = new Vec2(texCoords[vt_poly[j]][0], texCoords[vt_poly[j]][1]);\n                            texCoordsAttr.setFaceVertexValue(faceId, j, value);\n                        }\n                    }\n                }\n                const geomItem = new GeomItem(geomName, mesh);\n                // Move the transform of the geom item to the center of the geom.\n                // This is so that transparent objects can render correctly, and the\n                // transform gizmo becomes centered on each geom(for testing)\n                const delta = mesh.getBoundingBox().center();\n                {\n                    const offset = delta.negate();\n                    const positions = mesh.getVertexAttribute('positions');\n                    for (let i = 0; i < positions.getCount(); i++) {\n                        positions.setValue(i, positions.getValue(i).add(offset));\n                    }\n                    mesh.setBoundingBoxDirty();\n                }\n                geomItem.localXfoParam.value = new Xfo(delta);\n                if (geomData.material != undefined && this.materialLibrary.hasMaterial(geomData.material)) {\n                    geomItem.materialParam.value = this.materialLibrary.getMaterial(geomData.material);\n                }\n                else {\n                    const defaultShader = this.defaultShaderParam.value;\n                    const material = new Material(geomName + ' mat');\n                    material.setShaderName(defaultShader != '' ? defaultShader : 'StandardSurfaceShader');\n                    this.materialLibrary.addMaterial(material);\n                    geomItem.materialParam.value = material;\n                }\n                this.addChild(geomItem, false);\n            };\n            const loadObjData = () => {\n                resourceLoader.incrementWorkload(2);\n                loadTextfile(url, (fileData) => {\n                    resourceLoader.incrementWorkDone(1);\n                    parseObjData(fileData).then(() => {\n                        buildChildItems();\n                        resourceLoader.incrementWorkDone(1);\n                    });\n                }, (error) => {\n                    this.emit('error', error);\n                    reject(error);\n                });\n            };\n            loadObjData();\n        });\n    }\n}\n\n/**\n * The BaseTool provides an interface you can implement to define your own mouse, keyboard, and touch event handlers.\n *\n * A tool is a class that is delegated the handling of all user interaction events. The built-in {CameraManipulator}\n * class provides a default tool for moving the viewport camera.\n *\n * You can define your own custom tool, and replace the default CameraManipulator like so.\n * ```javascript\n *   const customManipulator = new MyCustomCameraManipulator()\n *   renderer.getViewport().setManipulator(customManipulator)\n * ```\n *\n * Each tool should provide handlers for the main types of events it will be responsible for handling.\n * These include mouse, keyboard, touch and VR events. Once a tool is installed on the viewport, the viewport\n * will start invoking the handler methods defined in the interface.\n * If the Tool handles an event, it should call stopPropagation on the event so the engine knows to stop the\n * propagation of the event to other classes.\n *\n * > Note: VR Events are ann emulation of mouse events, generated by the engine, allowing custom tools to be used to provide various VR interactions.\n *\n * **Events**\n * * **installChanged:** Triggered when the tool is installed or uninstalled.\n * * **activatedChanged:** Triggered when a tool is activated or deactivated.\n *\n * @extends ParameterOwner\n */\nclass BaseTool extends ParameterOwner {\n    __activated = false;\n    /**\n     * Creates an instance of BaseTool.\n     */\n    constructor() {\n        super();\n    }\n    /**\n     * Enables tools usage. This method is called by either the Viewport when a tool is removed, or the ToolManage if it is installed.\n     */\n    activateTool() {\n        if (this.__activated)\n            console.warn('Tool already active');\n        this.__activated = true;\n        this.emit('activatedChanged', { activated: this.__activated });\n    }\n    /**\n     * Disables tool usage. This method is called by either the Viewport when a tool is removed, or the ToolManage if it is installed.\n     */\n    deactivateTool() {\n        this.__activated = false;\n        this.emit('activatedChanged', { activated: this.__activated });\n    }\n    // ///////////////////////////////////\n    // Pointer events\n    /**\n     * Event fired when either the mouse button is pressed, or a touch start event occurs.\n     *\n     * @param event - The event param.\n     */\n    onPointerDown(event) {\n        // console.warn('Implement me')\n    }\n    /**\n     * Event fired when either the mouse cursor is moved, or a touch point moves.\n     *\n     * @param event - The event param.\n     */\n    onPointerMove(event) {\n        // console.warn('Implement me')\n    }\n    /**\n     * Event fired when either the mouse button is released, or a touch end event occurs.\n     *\n     * @param event - The event param.\n     */\n    onPointerUp(event) {\n        // console.warn('Implement me')\n    }\n    /**\n     * Event fired when a pointing device button is clicked.\n     *\n     * @param event - The event param.\n     */\n    onPointerClick(event) {\n        // console.warn('Implement me')\n    }\n    /**\n     * Event fired when a pointing device button is double clicked.\n     *\n     * @param event - The event param.\n     */\n    onPointerDoubleClick(event) {\n        // console.warn('Implement me')\n    }\n    /**\n     * Event fired when a pointing device button is held for a long time..\n     *\n     * @param event - The event param.\n     */\n    onPointerLongPress(event) {\n        // console.warn('Implement me')\n    }\n    /**\n     * Event fired when a mouse pointer enters the viewport\n     *\n     * @param event - The event param.\n     */\n    onPointerEnter(event) {\n        // console.warn('Implement me')\n    }\n    /**\n     * Event fired when a mouse pointer leaves the viewport\n     *\n     * @param event - The event param.\n     */\n    onPointerLeave(event) {\n        // console.warn('Implement me')\n    }\n    /**\n     * Event fired when the user rotates the pointing device wheel.\n     *\n     * @param event - The event param.\n     */\n    onWheel(event) {\n        // console.warn('Implement me')\n    }\n    // ///////////////////////////////////\n    // Keyboard events\n    /**\n     * Event fired when the user presses down a key on the keyboard.\n     *\n     * @param event - The event param.\n     */\n    onKeyDown(event) {\n        // console.warn('Implement me')\n    }\n    /**\n     * Event fired when the user releases a key on the keyboard.\n     *\n     * @param event - The event param.\n     */\n    onKeyUp(event) {\n        // console.warn('Implement me')\n    }\n    // ///////////////////////////////////\n    // Touch events\n    /**\n     * Event fired when one or more touch points have been disrupted in an implementation-specific manner.\n     *\n     * @param event - The event param.\n     */\n    onTouchCancel(event) {\n        // console.warn('Implement me')\n    }\n}\n\n/* eslint-disable require-jsdoc */\nconst MANIPULATION_MODES = {\n    pan: 0,\n    dolly: 1,\n    zoom: 2,\n    look: 3,\n    turntable: 4,\n    tumbler: 5,\n    trackball: 6,\n};\n/**\n * Class for defining and interaction model of the camera.\n *\n * The CameraManipulator supports a variety of manipulation modes, and hotkeys/modifier keys\n * that allow the user to rapidly switch between modes, such as 'turntable' and 'pan'.\n * A detailed explanation of various camera manipulation modes can be found\n * here: https://www.mattkeeter.com/projects/rotation/\n *\n * **MANIPULATION_MODES**\n * * **pan:** Translates the camera sideways according the the camera's current orientation. Activated by the right mouse button, or two fingered touches on mobile.\n * * **dolly:** Translates the camera forwards and backwards according the the camera's current orientation. Activated by holding the ctrl and alt keys while using the left mouse button, or the mouse wheel, or two fingered touches on mobile.\n * * **focussing:** Focusses the camera on a specific 3d point in the scene. Activated by double clicking, or double tapping on a geometry in the 3d view.\n * * **look:** Rotates the camera around its own position. Useful for simulating looking by turning ones head inside a scene. Activated by holding the ctrl key and right mouse button.\n * * **turntable:** Rotates the camera around the current camera target, using the turntable style manipulation described above. Activated by the left mouse button.\n * * **tumbler:** Rotates the camera around the current camera target, using the tumbler style manipulation described above. Activated by the left mouse button.\n * * **trackball:** Rotates the camera around the current camera target, using the trackball style manipulation described above. Activated by the left mouse button.\n *\n * The default manipulation mode, is the mode that is active with only the left mouse button. The default manipulation mode is currently 'turntable'.\n *\n * To Assign a different default manipulation mode, retrieve the manipulator from the viewport\n * and set the default mode.\n * ```\n * const cameraManipulator = renderer.getViewport().getManipulator()\n * cameraManipulator.setDefaultManipulationMode(CameraManipulator.MANIPULATION_MODES.trackball);\n * ```\n *\n * This class is the default manipulator, and can be replaced with custom manipulators.\n *\n * ```\n * const customManipulator = new CustomCameraManipulator()\n * renderer.getViewport().setManipulator(customManipulator);\n * ```\n *\n * The Camera manipulator can focus the view on a point in the view by various gestures.\n * A single click or touch tap can cause the view to be focussed or a double click or tap.\n * This behavior can be configured using the 2 values.\n * e.g. to disable all focus gestures, set both values to zero.\n * ```\n * // Make the aim focus occur after a single touch or click.\n * const cameraManipulator = renderer.getViewport().getManipulator()\n * cameraManipulator.aimFocusOnTouchTap = 1\n * cameraManipulator.aimFocusOnMouseClick = 1\n * ```\n *\n * **Parameters**\n * * **OrbitRate(`NumberParameter`):** The rate at which mouse or touch interactions are translated camera orientation changes.\n * * **DollySpeed(`NumberParameter`):** The rate at which the mouse button or touch interactions are translated camera dolly movement.\n * * **mouseWheelDollySpeed(`NumberParameter`):** The rate at which the mouse wheel interactions are translated camera dolly movement.\n *\n *   Note: this value defaults to different values for touch based interfaces to mouse based input.\n *   For mobile devices, the orbit rate defaults to 0.5, and for mouse based interaction, the value defaults to 1.\n *   A value of 1 means that the camera will rotate 180 degrees for a mouse interaction that spans from the left border of the viewport to the right border.\n *   Some applications might require lower, or higher default values\n *\n * To set different default values for mobile or desktop set a different value based on the SystemDesc.isMobileDevice flag.\n * ```\n * const cameraManipulator = renderer.getViewport().getManipulator()\n * cameraManipulator.getParameter('OrbitRate').setValue(SystemDesc.isMobileDevice ? 0.1 : 0.4)\n * ```\n *\n * **Events**\n * * **movementFinished:** Emitted when a camera movement is finished. E.g. when the user releases the mouse after a dolly, or after the focussing action has completed.\n * * **aimingFocus:** Emitted when a camera is being focussed on a target. E.g. when the user double clicks the mouse on a geometry in the view.\n *\n * @extends BaseTool\n */\nclass CameraManipulator extends BaseTool {\n    appData;\n    orbitAroundCursor = false;\n    zoomTowardGeomUnderCursor = false;\n    aimFocusOnTouchTap = 2;\n    aimFocusOnMouseClick = 2;\n    enabledWASDWalkMode = false;\n    defaultManipulationState = MANIPULATION_MODES.turntable;\n    prevCursor;\n    manipulationState;\n    pointerDown = false;\n    dragging = 0;\n    keyboardMovement = false;\n    keysPressed = [];\n    velocity = new Vec3();\n    prevVelocityIntegrationTime = -1;\n    ongoingTouches = {};\n    orbitTarget;\n    prevMousePos;\n    focusIntervalId;\n    mouseWheelMovementDist = 0;\n    mouseWheelZoomCount = 0;\n    mouseWheelZoomId = -1;\n    /**\n     * @member orbitRateParam - The rate at which mouse or touch interactions are translated camera orientation changes.\n     */\n    orbitRateParam = new NumberParameter('OrbitRate', SystemDesc.isMobileDevice ? 0.5 : 1);\n    /**\n     * @member dollySpeedParam - The rate at which the mouse button or touch interactions are translated camera dolly movement.\n     */\n    dollySpeedParam = new NumberParameter('DollySpeed', 0.001);\n    /**\n     * @member mouseWheelDollySpeedParam - The rate at which the mouse wheel interactions are translated camera dolly movement.\n     */\n    mouseWheelDollySpeedParam = new NumberParameter('MouseWheelDollySpeed', 0.1);\n    /**\n     * @member walkSpeedParam - TODO\n     */\n    walkSpeedParam = new NumberParameter('WalkSpeed', 5); // Value is in meters/second\n    /**\n     * @member walkModeCollisionDetection - TODO\n     */\n    walkModeCollisionDetection = new BooleanParameter('WalkModeCollisionDetection', false);\n    /**\n     * Create a camera, mouse and keyboard\n     * @param appData - The object containing the scene and the renderer.\n     */\n    constructor(appData) {\n        super();\n        this.appData = appData;\n        this.defaultManipulationState = MANIPULATION_MODES.turntable;\n        this.manipulationState = this.defaultManipulationState;\n        this.addParameter(this.orbitRateParam);\n        this.addParameter(this.dollySpeedParam);\n        this.addParameter(this.mouseWheelDollySpeedParam);\n        this.addParameter(this.walkSpeedParam);\n        this.addParameter(this.walkModeCollisionDetection);\n    }\n    /**\n     * Enables tools usage.\n     */\n    activateTool() {\n        super.activateTool();\n        if (this.appData && this.appData.renderer) {\n            this.prevCursor = this.appData.renderer.getGLCanvas().style.cursor;\n            this.appData.renderer.getGLCanvas().style.cursor = 'cursor';\n        }\n    }\n    /**\n     * Disables tool usage.\n     */\n    deactivateTool() {\n        super.deactivateTool();\n        if (this.appData && this.appData.renderer) {\n            this.appData.renderer.getGLCanvas().style.cursor = this.prevCursor;\n        }\n    }\n    /**\n     * Sets default manipulation mode.\n     * The value can be on of the keys in #CameraManipulator.MANIPULATION_MODES\n     *\n     * @param manipulationMode - The manipulation mode value.\n     */\n    setDefaultManipulationMode(manipulationMode) {\n        if (typeof manipulationMode == 'string') {\n            this.defaultManipulationState = MANIPULATION_MODES[manipulationMode];\n        }\n        else\n            this.defaultManipulationState = manipulationMode;\n        if (!Object.values(MANIPULATION_MODES).includes(this.defaultManipulationState)) {\n            throw new Error('Invalid Camera Manipulation Mode. Must be one of ' + Object.keys(MANIPULATION_MODES));\n        }\n    }\n    /**\n     * The look method.\n     * @param event - The event value.\n     * @param dragVec - The drag vector value.\n     */\n    look(event, dragVec) {\n        const { viewport } = event;\n        const camera = viewport.getCamera();\n        const orbitRate = this.orbitRateParam.value;\n        const globalXfo = camera.globalXfoParam.value;\n        // Orbit\n        const orbit = new Quat();\n        orbit.rotateZ((dragVec.x / viewport.getWidth()) * Math.PI * orbitRate);\n        globalXfo.ori = orbit.multiply(globalXfo.ori);\n        // Pitch\n        const pitch = new Quat();\n        pitch.rotateX((dragVec.y / viewport.getHeight()) * Math.PI * orbitRate);\n        globalXfo.ori.multiplyInPlace(pitch);\n        camera.globalXfoParam.value = globalXfo;\n    }\n    /**\n     * Rotates viewport camera about the target.\n     *\n     * @param event - The event value.\n     * @param dragVec - The drag vector value.\n     */\n    turntable(event, dragVec) {\n        const { viewport } = event;\n        const camera = viewport.getCamera();\n        const orbitRate = this.orbitRateParam.value;\n        const globalXfo = camera.globalXfoParam.value;\n        const cameraTargetOffset = globalXfo.ori.inverse().rotateVec3(globalXfo.tr.subtract(this.orbitTarget));\n        // Orbit\n        const orbit = new Quat();\n        orbit.rotateZ((dragVec.x / viewport.getWidth()) * 2 * Math.PI * -orbitRate);\n        globalXfo.ori = orbit.multiply(globalXfo.ori);\n        // Pitch\n        const pitch = new Quat();\n        pitch.rotateX((dragVec.y / viewport.getHeight()) * Math.PI * -orbitRate);\n        globalXfo.ori.multiplyInPlace(pitch);\n        globalXfo.tr = this.orbitTarget.add(globalXfo.ori.rotateVec3(cameraTargetOffset));\n        camera.globalXfoParam.value = globalXfo;\n    }\n    /**\n     * Rotates viewport camera about the target.\n     *\n     * @param event - The event value.\n     * @param dragVec - The drag vector value.\n     */\n    tumbler(event, dragVec) {\n        const { viewport } = event;\n        const camera = viewport.getCamera();\n        const orbitRate = this.orbitRateParam.value;\n        const globalXfo = camera.globalXfoParam.value;\n        const xVec = globalXfo.ori.getXaxis();\n        const yVec = globalXfo.ori.getYaxis();\n        const zVec = globalXfo.ori.getZaxis();\n        const vec = xVec.scale(-dragVec.x).add(yVec.scale(dragVec.y));\n        const rotateAxis = vec.cross(zVec);\n        rotateAxis.normalizeInPlace();\n        const dragVecLength = dragVec.length();\n        const cameraTargetOffset = globalXfo.ori.inverse().rotateVec3(globalXfo.tr.subtract(this.orbitTarget));\n        // Orbit\n        const orbit = new Quat();\n        orbit.setFromAxisAndAngle(rotateAxis, (dragVecLength / viewport.getWidth()) * Math.PI * -orbitRate);\n        globalXfo.ori = orbit.multiply(globalXfo.ori);\n        globalXfo.tr = this.orbitTarget.add(globalXfo.ori.rotateVec3(cameraTargetOffset));\n        camera.globalXfoParam.value = globalXfo;\n    }\n    /**\n     * Rotates viewport camera about the target.\n     *\n     * @param event - The event value.\n     * @param dragVec - The drag vector value.\n     */\n    trackball(event, dragVec) {\n        const { viewport } = event;\n        const camera = viewport.getCamera();\n        const orbitRate = this.orbitRateParam.value;\n        const globalXfo = camera.globalXfoParam.value;\n        const xVec = globalXfo.ori.getXaxis();\n        const yVec = globalXfo.ori.getYaxis();\n        const zVec = globalXfo.ori.getZaxis();\n        const vec = xVec.scale(-dragVec.x).add(yVec.scale(dragVec.y));\n        const rotateAxis = vec.cross(zVec);\n        rotateAxis.normalizeInPlace();\n        const dragVecLength = dragVec.length();\n        const cameraTargetOffset = globalXfo.ori.inverse().rotateVec3(globalXfo.tr.subtract(this.orbitTarget));\n        // Orbit\n        const orbit = new Quat();\n        orbit.setFromAxisAndAngle(rotateAxis, (dragVecLength / viewport.getWidth()) * Math.PI * -orbitRate);\n        globalXfo.ori = orbit.multiply(globalXfo.ori);\n        globalXfo.tr = this.orbitTarget.add(globalXfo.ori.rotateVec3(cameraTargetOffset));\n        camera.globalXfoParam.value = globalXfo;\n    }\n    /**\n     * Rotates the camera around its own `X`,`Y` axes.\n     *\n     * @param event - The event value.\n     * @param dragVec - The drag vector value.\n     */\n    pan(event, dragVec) {\n        const { viewport } = event;\n        const camera = viewport.getCamera();\n        const delta = new Xfo();\n        const xAxis = new Vec3(1, 0, 0);\n        const yAxis = new Vec3(0, 1, 0);\n        if (camera.isOrthographic()) {\n            const frustumHeight = camera.getFrustumHeight();\n            const frustumWidth = frustumHeight * (viewport.getWidth() / viewport.getHeight());\n            delta.tr = xAxis.scale(-(dragVec.x / viewport.getWidth()) * frustumWidth);\n            delta.tr.addInPlace(yAxis.scale((dragVec.y / viewport.getHeight()) * frustumHeight));\n        }\n        else {\n            const focalDistance = camera.getFocalDistance();\n            const fovY = camera.getFov();\n            const cameraPlaneHeight = 2.0 * focalDistance * Math.tan(0.5 * fovY);\n            const cameraPlaneWidth = cameraPlaneHeight * (viewport.getWidth() / viewport.getHeight());\n            delta.tr = xAxis.scale(-(dragVec.x / viewport.getWidth()) * cameraPlaneWidth);\n            delta.tr.addInPlace(yAxis.scale((dragVec.y / viewport.getHeight()) * cameraPlaneHeight));\n        }\n        const cameraXfo = camera.globalXfoParam.value;\n        camera.globalXfoParam.value = cameraXfo.multiply(delta);\n    }\n    /**\n     * Dollying moves the camera forward at a constant speed, not changing the focal distance.\n     * @param event - The event value.\n     * @param dragVec - The drag vector value.\n     */\n    dolly(event, pointerPos, dragVec) {\n        const viewport = event.viewport;\n        const camera = viewport.getCamera();\n        const focalDistance = camera.getFocalDistance();\n        // As we click and drag away from the center of the screen, we move forward.\n        // Like pullingoutelves into the screen farther.\n        const screenCenter = new Vec2(viewport.getWidth() * 0.5, viewport.getHeight() * 0.5);\n        const vecFromCenter = pointerPos.subtract(screenCenter).normalize();\n        const dragDist = dragVec.dot(vecFromCenter);\n        const applyMovement = () => {\n            const dollyDist = dragDist * this.dollySpeedParam.value * focalDistance;\n            const delta = new Xfo();\n            delta.tr.set(0, 0, dollyDist);\n            const globalXfo = camera.globalXfoParam.value;\n            camera.globalXfoParam.value = globalXfo.multiply(delta);\n        };\n        const applyViewScale = () => {\n            const dollyDist = dragDist * this.dollySpeedParam.value;\n            const viewHeight = camera.getFrustumHeight();\n            const zoomDist = viewHeight * dollyDist;\n            camera.setFrustumHeight(viewHeight + zoomDist);\n        };\n        if (camera.isOrthographic()) {\n            applyViewScale();\n        }\n        else {\n            applyMovement();\n        }\n    }\n    /**\n     * Zooms the camera towards the target.\n     * @param event - The event value.\n     * @param dragVec - The drag vector value.\n     */\n    zoom(event, dragStartPos, dragVec) {\n        const viewport = event.viewport;\n        const camera = viewport.getCamera();\n        const focalDistance = camera.getFocalDistance();\n        // As we click and drag away from the center of the screen, we move forward.\n        // Like pullingoutelves into the screen farther.\n        const screenCenter = new Vec2((viewport.getWidth() * 0.5) / window.devicePixelRatio, (viewport.getHeight() * 0.5) / window.devicePixelRatio);\n        const vecFromCenter = dragStartPos.subtract(screenCenter).normalize();\n        const dragDist = dragVec.dot(vecFromCenter);\n        const applyMovement = () => {\n            const zoomDist = -dragDist * this.dollySpeedParam.value * focalDistance;\n            const delta = new Xfo();\n            delta.tr.set(0, 0, zoomDist);\n            const globalXfo = camera.globalXfoParam.value;\n            camera.setFocalDistance(focalDistance + zoomDist);\n            camera.globalXfoParam.value = globalXfo.multiply(delta);\n        };\n        const applyViewScale = () => {\n            const dollyDist = -dragDist * this.dollySpeedParam.value;\n            const viewHeight = camera.getFrustumHeight();\n            const zoomDist = viewHeight * dollyDist;\n            camera.setFrustumHeight(viewHeight + zoomDist);\n        };\n        if (camera.isOrthographic()) {\n            applyViewScale();\n        }\n        else {\n            applyMovement();\n        }\n    }\n    /**\n     * The initDrag method.\n     *\n     * @private\n     * @param event - The event value.\n     */\n    initDrag(event) {\n        this.pointerDown = true;\n        const viewport = event.viewport;\n        const camera = viewport.getCamera();\n        const xfo = camera.globalXfoParam.value;\n        if (this.orbitAroundCursor) {\n            if (event.intersectionData != undefined && this.orbitAroundCursor) {\n                this.orbitTarget = event.intersectionData.intersectionPos;\n                const vec = xfo.inverse().transformVec3(event.intersectionData.intersectionPos);\n                camera.setFocalDistance(-vec.z);\n            }\n            else if (!this.orbitTarget) {\n                if (event.pointerRay) {\n                    this.orbitTarget = event.pointerRay.pointAtDist(camera.getFocalDistance());\n                }\n                else {\n                    this.orbitTarget = xfo.tr.add(xfo.ori.getZaxis().scale(-camera.getFocalDistance()));\n                }\n            }\n        }\n        else {\n            this.orbitTarget = xfo.tr.add(xfo.ori.getZaxis().scale(-camera.getFocalDistance()));\n        }\n        this.dragging = 1;\n    }\n    /**\n     * The initDrag method.\n     *\n     * @private\n     * @param event - The event value.\n     */\n    endDrag(event) {\n        if (event.getCapture() == this)\n            event.releaseCapture();\n        this.dragging = 0;\n        this.pointerDown = false;\n    }\n    /**\n     * The aimFocus method.\n     *\n     * @private\n     * @param camera - The camera that we are aiming\n     * @param target - The target to focus on.\n     * @param distance - The distance from the target to get to.\n     * @param duration - The duration in milliseconds to aim the focus.\n     */\n    aimFocus(camera, target, distance = -1, duration = 400) {\n        if (this.focusIntervalId)\n            clearInterval(this.focusIntervalId);\n        const count = Math.round(duration / 20); // each step is 20ms\n        const initalMode = this.defaultManipulationState;\n        let i = 0;\n        const applyMovement = () => {\n            const prevGlobalXfo = camera.globalXfoParam.value;\n            const initialDist = camera.getFocalDistance();\n            const dir = target.subtract(prevGlobalXfo.tr);\n            const currDist = dir.normalizeInPlace();\n            const targetGlobalXfo = prevGlobalXfo.clone();\n            if (initalMode == MANIPULATION_MODES.turntable || initalMode == MANIPULATION_MODES.look) {\n                // Orbit\n                {\n                    const currDir = prevGlobalXfo.ori.getZaxis().clone();\n                    currDir.z = 0;\n                    const newDir = dir.negate();\n                    newDir.z = 0;\n                    const orbit = new Quat();\n                    orbit.setFrom2Vectors(currDir, newDir);\n                    targetGlobalXfo.ori = orbit.multiply(targetGlobalXfo.ori);\n                }\n                // Pitch\n                {\n                    const xAxis = prevGlobalXfo.ori.getXaxis().clone();\n                    const currDir = prevGlobalXfo.ori.getZaxis().clone();\n                    const newDir = dir.negate();\n                    newDir.subtractInPlace(xAxis.scale(newDir.dot(xAxis)));\n                    newDir.normalizeInPlace();\n                    const pitch = new Quat();\n                    if (currDir.cross(newDir).dot(xAxis) > 0.0)\n                        pitch.rotateX(currDir.angleTo(newDir));\n                    else\n                        pitch.rotateX(-currDir.angleTo(newDir));\n                    targetGlobalXfo.ori = targetGlobalXfo.ori.multiply(pitch);\n                }\n                // Fix Roll\n                {\n                    const currDir = targetGlobalXfo.ori.getXaxis().clone();\n                    const newDir = currDir.clone();\n                    newDir.z = 0;\n                    newDir.normalizeInPlace();\n                    const roll = new Quat();\n                    roll.setFrom2Vectors(currDir, newDir);\n                    targetGlobalXfo.ori = roll.multiply(targetGlobalXfo.ori);\n                }\n            }\n            else {\n                const currDir = prevGlobalXfo.ori.getZaxis().clone();\n                const newDir = dir.negate();\n                const orbit = new Quat();\n                orbit.setFrom2Vectors(currDir, newDir);\n                targetGlobalXfo.ori = orbit.multiply(targetGlobalXfo.ori);\n            }\n            // With each iteration we get closer to our goal\n            // and on the final iteration we should aim perfectly at\n            // the target.\n            const t = Math.pow(i / count, 2);\n            const globalXfo = prevGlobalXfo.clone();\n            globalXfo.ori = prevGlobalXfo.ori.lerp(targetGlobalXfo.ori, t);\n            if (distance > 0) {\n                const displacement = dir.scale(currDist - distance);\n                globalXfo.tr.addInPlace(displacement.scale(t));\n            }\n            camera.setFocalDistance(initialDist + (currDist - initialDist) * t);\n            camera.globalXfoParam.value = globalXfo;\n            i++;\n            if (i <= count) {\n                // @ts-ignore\n                this.focusIntervalId = setTimeout(applyMovement, 20);\n            }\n            else {\n                this.focusIntervalId = undefined;\n                this.emit('movementFinished');\n                camera.emit('movementFinished');\n            }\n        };\n        applyMovement();\n    }\n    /**\n     * The orientPointOfView method.\n     *\n     * @private\n     * @param camera - The camera that we are orienting\n     * @param position - The target to focus on.\n     * @param target - The target to focus on.\n     * @param distance - The distance to the specified we want the user to be moved to\n     * @param duration - The duration in milliseconds to aim the focus.\n     */\n    orientPointOfView(camera, position, target, distance = 0, duration = 400) {\n        if (this.focusIntervalId)\n            clearInterval(this.focusIntervalId);\n        const count = Math.round(duration / 20); // each step is 20ms\n        let i = 0;\n        const applyMovement = () => {\n            const initialGlobalXfo = camera.globalXfoParam.value;\n            const initialTarget = camera.getTargetPosition();\n            // With each iteration we get closer to our goal\n            // and on the final iteration we should aim perfectly at\n            // the target.\n            const t = Math.pow(i / count, 2);\n            // Sometimes we want to pull users to within some threshold of the specified position.\n            const dirToPosition = position.subtract(initialGlobalXfo.tr);\n            const currDistToPosition = dirToPosition.normalizeInPlace();\n            const displacement = dirToPosition.scale(currDistToPosition - distance);\n            const pos = initialGlobalXfo.tr.add(displacement.scale(t));\n            const targetPos = initialTarget.lerp(target, t);\n            camera.setPositionAndTarget(pos, targetPos);\n            i++;\n            if (i <= count) {\n                // @ts-ignore\n                this.focusIntervalId = setTimeout(applyMovement, 20);\n            }\n            else {\n                this.focusIntervalId = undefined;\n                this.emit('movementFinished');\n                camera.emit('movementFinished');\n            }\n        };\n        applyMovement();\n    }\n    /**\n     * Invoked when a user double presses a pointer over an element.\n     *\n     * @param event - The pointer event that occurs\n     * @memberof CameraManipulator\n     */\n    onPointerDoubleClick(event) {\n        const aimFocus = (pointerRay) => {\n            const viewport = event.viewport;\n            const camera = viewport.getCamera();\n            const cameraGlobalXfo = camera.globalXfoParam.value;\n            const aimTarget = cameraGlobalXfo.tr.add(pointerRay.dir.scale(event.intersectionData.dist));\n            this.aimFocus(camera, aimTarget);\n            // Note: Collab can use these mouseEvents to guide users attention.\n            // @ts-ignore\n            event.aimTarget = aimTarget;\n            // @ts-ignore\n            event.aimDistance = event.intersectionData.dist;\n            this.emit('aimingFocus', event);\n            camera.emit('aimingFocus', event);\n            event.stopPropagation();\n        };\n        if (event.intersectionData && this.aimFocusOnMouseClick) {\n            if (event instanceof ZeaMouseEvent && this.aimFocusOnMouseClick == 2) {\n                const mouseEvent = event;\n                aimFocus(mouseEvent.pointerRay);\n                mouseEvent.preventDefault();\n            }\n            if (event instanceof ZeaTouchEvent && this.aimFocusOnTouchTap == 2) {\n                const pointerEvent = event;\n                aimFocus(pointerEvent.pointerRay);\n            }\n        }\n    }\n    /**\n     * Event fired when either the mouse button is pressed, or a touch start event occurs.\n     *\n     * @param event - The mouse event that occurs.\n     */\n    onPointerDown(event) {\n        if (event instanceof ZeaMouseEvent) {\n            if (this.dragging == 1) {\n                this.endDrag(event);\n            }\n            this.initDrag(event);\n            const mouseEvent = event;\n            this.prevMousePos = mouseEvent.pointerPos;\n            if (mouseEvent.button == 2) {\n                this.manipulationState = MANIPULATION_MODES.pan;\n            }\n            else if (mouseEvent.ctrlKey && mouseEvent.altKey) {\n                this.manipulationState = MANIPULATION_MODES.dolly;\n            }\n            else if (mouseEvent.ctrlKey || mouseEvent.button == 2) {\n                this.manipulationState = MANIPULATION_MODES.look;\n            }\n            else {\n                this.manipulationState = this.defaultManipulationState;\n            }\n            mouseEvent.preventDefault();\n        }\n        else if (event instanceof ZeaTouchEvent) {\n            this._onTouchStart(event);\n        }\n    }\n    /**\n     * Event fired when either the mouse cursor is moved, or a touch point moves.\n     *\n     * @param event - The mouse event that occurs.\n     */\n    onPointerMove(event) {\n        if (this.dragging != 0) {\n            if (event instanceof ZeaMouseEvent) {\n                this._onMouseMove(event);\n                event.preventDefault();\n            }\n            if (event instanceof ZeaTouchEvent) {\n                this._onTouchMove(event);\n            }\n            this.dragging = 2;\n            // Note: the Capture is essential to performance on large scenes\n            // as it prevents the geom data buffer from being queried(and potentially cleaned)\n            // during camera movements.\n            event.setCapture(this);\n            event.stopPropagation();\n        }\n    }\n    /**\n     * The event that occurs when the user moves the pointer across a screen.\n     *\n     * @param event -The event value\n     */\n    _onMouseMove(event) {\n        if (!this.pointerDown)\n            return;\n        const pointerPos = event.pointerPos;\n        const dragVec = pointerPos.subtract(this.prevMousePos);\n        // Note: at mouse down, we selected the manipulation\n        // mode to use for this interaction.\n        switch (this.manipulationState) {\n            case MANIPULATION_MODES.turntable:\n                this.turntable(event, dragVec);\n                break;\n            case MANIPULATION_MODES.tumbler:\n                this.tumbler(event, dragVec);\n                break;\n            case MANIPULATION_MODES.trackball:\n                this.trackball(event, dragVec);\n                break;\n            case MANIPULATION_MODES.look:\n                this.look(event, dragVec);\n                break;\n            case MANIPULATION_MODES.pan:\n                this.pan(event, pointerPos.subtract(this.prevMousePos));\n                break;\n            case MANIPULATION_MODES.dolly:\n                this.dolly(event, pointerPos, dragVec);\n                break;\n            case MANIPULATION_MODES.zoom:\n                this.zoom(event, pointerPos, dragVec);\n                break;\n        }\n        this.prevMousePos = pointerPos;\n    }\n    /**\n     * The event that occurs when the user moves pointer across a touch screen.\n     *\n     * @param event - The touch event that occurs.\n     * @private\n     */\n    _onTouchMove(event) {\n        const touches = event.touches;\n        if (touches.length == 1) {\n            const touch = touches[0];\n            const touchPos = touch.touchPos;\n            const touchData = this.ongoingTouches[touch.identifier];\n            if (!touchData)\n                return;\n            const dragVec = touchPos.subtract(touchData.pos);\n            switch (this.defaultManipulationState) {\n                case MANIPULATION_MODES.look:\n                    // TODO: scale panning here.\n                    dragVec.scaleInPlace(6.0);\n                    this.look(event, dragVec);\n                    break;\n                case MANIPULATION_MODES.turntable:\n                    this.turntable(event, dragVec);\n                    break;\n                case MANIPULATION_MODES.tumbler:\n                    this.tumbler(event, dragVec);\n                    break;\n                case MANIPULATION_MODES.trackball:\n                    this.trackball(event, dragVec);\n                    break;\n                case MANIPULATION_MODES.pan:\n                    this.pan(event, dragVec);\n                    break;\n                case MANIPULATION_MODES.dolly:\n                    this.dolly(event, touchPos, dragVec);\n                    break;\n                case MANIPULATION_MODES.zoom:\n                    this.zoom(event, touchData.pos, dragVec);\n                    break;\n            }\n            touchData.pos = touchPos;\n        }\n        else if (touches.length == 2) {\n            const touch0 = touches[0];\n            const touchData0 = this.ongoingTouches[touch0.identifier];\n            const touch1 = touches[1];\n            const touchData1 = this.ongoingTouches[touch1.identifier];\n            if (!touchData0 || !touchData1)\n                return;\n            const touch0Pos = touch0.touchPos;\n            const touch1Pos = touch1.touchPos;\n            const startSeparation = touchData1.pos.subtract(touchData0.pos).length();\n            const dragSeparation = touch1Pos.subtract(touch0Pos).length();\n            const separationDist = startSeparation - dragSeparation;\n            const touch0Drag = touch0Pos.subtract(touchData0.pos);\n            const touch1Drag = touch1Pos.subtract(touchData1.pos);\n            const dragVec = touch0Drag.add(touch1Drag);\n            // TODO: scale panning here.\n            dragVec.scaleInPlace(0.5);\n            // apply the vectors to calculate a pan and zoom\n            const dragDist = separationDist * 0.002;\n            const { viewport } = event;\n            const camera = viewport.getCamera();\n            const focalDistance = camera.getFocalDistance();\n            const fovY = camera.getFov();\n            const xAxis = new Vec3(1, 0, 0);\n            const yAxis = new Vec3(0, 1, 0);\n            const cameraPlaneHeight = 2.0 * focalDistance * Math.tan(0.5 * fovY);\n            const cameraPlaneWidth = cameraPlaneHeight * (viewport.getWidth() / viewport.getHeight());\n            const delta = new Xfo();\n            delta.tr = xAxis.scale(-(dragVec.x / viewport.getWidth()) * cameraPlaneWidth);\n            delta.tr.addInPlace(yAxis.scale((dragVec.y / viewport.getHeight()) * cameraPlaneHeight));\n            const zoomDist = dragDist * focalDistance;\n            camera.setFocalDistance(focalDistance + zoomDist);\n            delta.tr.z += zoomDist;\n            // Apply the roll\n            switch (this.defaultManipulationState) {\n                case MANIPULATION_MODES.tumbler:\n                case MANIPULATION_MODES.trackball:\n                    const vecPrev = touchData1.pos.subtract(touchData0.pos);\n                    const vecNow = touch1Pos.subtract(touch0Pos);\n                    let deltaAngle = vecPrev.normalize().angleTo(vecNow.normalize());\n                    if (vecPrev.cross(vecNow) < 0.0) {\n                        deltaAngle = -deltaAngle;\n                    }\n                    const roll = new Quat();\n                    roll.rotateZ(deltaAngle);\n                    delta.ori.multiplyInPlace(roll);\n                    break;\n            }\n            const globalXfo = camera.globalXfoParam.value;\n            camera.globalXfoParam.value = globalXfo.multiply(delta);\n            touchData0.pos = touch0Pos;\n            touchData1.pos = touch1Pos;\n        }\n    }\n    /**\n     * Event fired when either the mouse button is released, or a touch end event occurs.\n     *\n     * @param event - The mouse event that occurs.\n     */\n    onPointerUp(event) {\n        if (this.dragging == 1) {\n            // No dragging occurred. Release the capture and let the event propagate like normal.\n            this.endDrag(event);\n            if (event.intersectionData) {\n                if ((event instanceof ZeaMouseEvent && this.aimFocusOnMouseClick == 1) ||\n                    (event instanceof ZeaTouchEvent && this.aimFocusOnTouchTap == 1)) {\n                    const viewport = event.viewport;\n                    const camera = viewport.getCamera();\n                    const cameraGlobalXfo = camera.globalXfoParam.value;\n                    const pointerRay = event.pointerRay;\n                    const aimTarget = cameraGlobalXfo.tr.add(pointerRay.dir.scale(event.intersectionData.dist));\n                    this.aimFocus(camera, aimTarget);\n                    // Note: Collab can use these events to guide users attention.\n                    // @ts-ignore\n                    event.aimTarget = aimTarget;\n                    // @ts-ignore\n                    event.aimDistance = event.intersectionData.dist;\n                    this.emit('aimingFocus', event);\n                    camera.emit('aimingFocus', event);\n                    // Note: for a single click (no-drag) we don't want to stop the propagation of the event.\n                    event.stopPropagation();\n                    if (event instanceof ZeaMouseEvent)\n                        event.preventDefault();\n                }\n            }\n        }\n        else if (this.dragging == 2) {\n            if (event instanceof ZeaMouseEvent) {\n                this.endDrag(event);\n                // Note: the Capture is essential to performance on large scenes\n                // as it prevents the geom data buffer from being queried(and potentially cleaned)\n                // during camera movements.\n                event.releaseCapture();\n                this.emit('movementFinished');\n                const viewport = event.viewport;\n                viewport.getCamera().emit('movementFinished');\n            }\n            else if (event instanceof ZeaTouchEvent) {\n                const touchEvent = event;\n                const { changedTouches, touches } = touchEvent;\n                for (let i = 0; i < changedTouches.length; i++) {\n                    this.__endTouch(changedTouches[i]);\n                }\n                if (Object.keys(this.ongoingTouches).length == 0) {\n                    this.endDrag(event);\n                    // Note: the Capture is essential to performance on large scenes\n                    // as it prevents the geom data buffer from being queried(and potentially cleaned)\n                    // during camera movements.\n                    event.releaseCapture();\n                    const viewport = event.viewport;\n                    viewport.getCamera().emit('movementFinished');\n                }\n                touchEvent.preventDefault();\n            }\n            // Note: the Capture is essential to performance on large scenes\n            // as it prevents the geom data buffer from being queried(and potentially cleaned)\n            // during camera movements.\n            event.releaseCapture();\n            event.stopPropagation();\n        }\n    }\n    /**\n     * Causes an event to occur when the mouse pointer is moved out of this viewport\n     * @param event - The event that occurs.\n     */\n    onPointerLeave(event) {\n        // If the pointer leaves the viewport, then we will no longer receive key up events,\n        // so we must immediately disable movement here.\n        if (this.keysPressed.length > 0) {\n            this.keysPressed = [];\n            this.velocity.set(0, 0, 0);\n            this.keyboardMovement = false;\n        }\n    }\n    /**\n     * Invoked when the mouse wheel is rolled up or down over an element.\n     *\n     * @param event - The wheel event that occurs.\n     */\n    onWheel(event) {\n        const viewport = event.viewport;\n        const camera = viewport.getCamera();\n        const mouseWheelDollySpeed = this.mouseWheelDollySpeedParam.value;\n        const modulator = event.shiftKey ? 0.1 : 0.5;\n        const xfo = camera.globalXfoParam.value;\n        let dir;\n        if (!camera.isOrthographic()) {\n            if (this.zoomTowardGeomUnderCursor) {\n                if (event.intersectionData != undefined) {\n                    dir = xfo.tr.subtract(event.intersectionData.intersectionPos);\n                    dir.normalizeInPlace();\n                    const viewVec = xfo.inverse().transformVec3(event.intersectionData.intersectionPos);\n                    camera.setFocalDistance(-viewVec.z);\n                }\n                else {\n                    const point = event.pointerRay.pointAtDist(camera.getFocalDistance());\n                    dir = xfo.tr.subtract(point);\n                    dir.normalizeInPlace();\n                }\n            }\n            else {\n                dir = camera.globalXfoParam.value.ori.getZaxis();\n            }\n        }\n        // To normalize mouse wheel speed across vendors and OSs, it is recommended to simply convert scroll value to -1 or 1\n        // See here: https://stackoverflow.com/questions/5527601/normalizing-mousewheel-speed-across-browsers\n        const steps = 6;\n        const direction = event.deltaY < 0 ? -1 : 1;\n        const applyMovement = () => {\n            const focalDistance = camera.getFocalDistance();\n            const zoomDist = focalDistance * this.mouseWheelMovementDist;\n            xfo.tr.addInPlace(dir.scale(zoomDist));\n            camera.setFocalDistance(focalDistance + zoomDist);\n            camera.globalXfoParam.value = xfo;\n            this.mouseWheelZoomCount++;\n            if (this.mouseWheelZoomCount < steps) {\n                this.mouseWheelZoomId = window.setTimeout(applyMovement, 10);\n            }\n            else {\n                this.mouseWheelZoomId = -1;\n                this.emit('movementFinished');\n                camera.emit('movementFinished');\n            }\n        };\n        const applyDolly = () => {\n            const dollyDist = 50.0 * this.mouseWheelMovementDist;\n            const delta = new Xfo();\n            delta.tr.set(0, 0, dollyDist);\n            xfo.tr.addInPlace(dir.scale(dollyDist));\n            camera.globalXfoParam.value = xfo;\n        };\n        const applyViewScale = () => {\n            const frustumHeight = camera.getFrustumHeight();\n            const zoomDist = frustumHeight * this.mouseWheelMovementDist;\n            camera.setFrustumHeight(frustumHeight + zoomDist);\n            if (event.intersectionData && this.zoomTowardGeomUnderCursor) {\n                const dir = xfo.tr.subtract(event.intersectionData.intersectionPos);\n                const zAxis = xfo.ori.getZaxis();\n                dir.subtractInPlace(zAxis.scale(dir.dot(zAxis)));\n                xfo.tr.addInPlace(dir.scale(zoomDist / (frustumHeight + zoomDist)));\n                camera.globalXfoParam.value = xfo;\n            }\n            this.mouseWheelZoomCount++;\n            if (this.mouseWheelZoomCount < steps) {\n                this.mouseWheelZoomId = window.setTimeout(applyViewScale, 10);\n            }\n            else {\n                this.mouseWheelZoomId = -1;\n                this.emit('movementFinished');\n                camera.emit('movementFinished');\n            }\n        };\n        if (this.mouseWheelZoomId > 0) {\n            // If a new wheel event arrives while the previous is still running, modify the distance\n            // and reset.\n            this.mouseWheelMovementDist += (direction * mouseWheelDollySpeed * modulator * 0.5) / steps;\n            this.mouseWheelZoomCount = 0;\n        }\n        else {\n            this.mouseWheelMovementDist = (direction * mouseWheelDollySpeed * modulator) / steps;\n            this.mouseWheelZoomCount = 0;\n            if (camera.isOrthographic()) {\n                applyViewScale();\n            }\n            else {\n                if (event.ctrlKey)\n                    applyDolly();\n                else\n                    applyMovement();\n            }\n        }\n        event.preventDefault();\n        event.stopPropagation();\n    }\n    /**\n     * The integrateVelocityChange method.\n     * @param event - The event value.\n     * @private\n     */\n    integrateVelocityChange(event) {\n        const { viewport } = event;\n        const camera = viewport.getCamera();\n        const time = performance.now();\n        if (this.prevVelocityIntegrationTime > 0) {\n            const timeDelta = (time - this.prevVelocityIntegrationTime) / 1000;\n            const speed = this.walkSpeedParam.value;\n            // movement.tr = this.velocity.normalize().scale(speed * timeDelta)\n            if (speed > 0.0) {\n                // As we move over a terrain, it can be helpful to allow users to walk\n                // over surfaces without falling through them. This allows users to look\n                // down while walking forwards for example.\n                // Calculate where we might be soon\n                const movement = new Xfo();\n                movement.tr = this.velocity.normalize().scale(speed * timeDelta);\n                const cameraXfo = camera.globalXfoParam.value;\n                const newXfo = cameraXfo.multiply(movement);\n                const collisionDetection = this.walkModeCollisionDetection.value;\n                if (collisionDetection) {\n                    // Raycast from 1.5 meter up\n                    const headHeight = 1.5;\n                    const dist = 1.5;\n                    const area = 0.5;\n                    const raycastXfo = new Xfo(newXfo.tr);\n                    const ray = new Ray(newXfo.tr, new Vec3(0, 0, -1));\n                    const results = viewport.getRenderer().raycastCluster(raycastXfo, ray, dist, area, PassType.OPAQUE);\n                    if (results.length > 0) {\n                        let avgDist = 0;\n                        // eslint-disable-next-line guard-for-in\n                        results.forEach((result) => {\n                            avgDist += result.dist;\n                        });\n                        avgDist /= results.length;\n                        // Snap the movement vector to make the user rest on the ground.\n                        newXfo.tr = ray.start.add(ray.dir.scale(avgDist - headHeight));\n                    }\n                }\n                camera.globalXfoParam.value = newXfo;\n            }\n        }\n        this.prevVelocityIntegrationTime = time;\n    }\n    /**\n     * Invoked when the user is pressing a key on the keyboard.\n     *\n     * @param event - The keyboard event that occurs.\n     */\n    onKeyDown(event) {\n        if (!this.enabledWASDWalkMode)\n            return;\n        const key = event.key.toLowerCase();\n        // Note: onKeyPressed is called initially only once, and then we\n        // get a series of calls. Here we ignore subsequent events.\n        if (this.keysPressed.includes(key))\n            return;\n        switch (key) {\n            case 'w':\n                this.velocity.z -= 1.0;\n                break;\n            case 's':\n                this.velocity.z += 1.0;\n                break;\n            case 'a':\n                this.velocity.x -= 1.0;\n                break;\n            case 'd':\n                this.velocity.x += 1.0;\n                break;\n            default:\n                return;\n        }\n        event.stopPropagation();\n        this.keysPressed.push(key);\n        if (!this.keyboardMovement) {\n            this.keyboardMovement = true;\n            this.prevVelocityIntegrationTime = performance.now();\n            const animationFrame = () => {\n                this.integrateVelocityChange(event);\n                if (this.keyboardMovement) {\n                    window.requestAnimationFrame(animationFrame);\n                }\n            };\n            window.requestAnimationFrame(animationFrame);\n        }\n    }\n    /**\n     * Invoked when the user releases a key on the keyboard.\n     *\n     * @param event - The event that occurs.\n     */\n    onKeyUp(event) {\n        const key = event.key.toLowerCase();\n        if (!this.keysPressed.includes(key))\n            return;\n        switch (key) {\n            case 'w':\n                this.velocity.z += 1.0;\n                break;\n            case 's':\n                this.velocity.z -= 1.0;\n                break;\n            case 'a':\n                this.velocity.x += 1.0;\n                break;\n            case 'd':\n                this.velocity.x -= 1.0;\n                break;\n            default:\n                return;\n        }\n        event.stopPropagation();\n        const keyIndex = this.keysPressed.indexOf(key);\n        this.keysPressed.splice(keyIndex, 1);\n        if (this.keysPressed.length == 0)\n            this.keyboardMovement = false;\n    }\n    // ///////////////////////////////////\n    // Touch controls\n    /**\n     * The __startTouch method.\n     * @param touch - The touch value.\n     * @private\n     */\n    __startTouch(touch) {\n        this.ongoingTouches[touch.identifier] = {\n            identifier: touch.identifier,\n            pos: touch.touchPos,\n        };\n    }\n    /**\n     * The __endTouch method.\n     * @param touch - The touch value.\n     * @private\n     */\n    __endTouch(touch) {\n        delete this.ongoingTouches[touch.identifier];\n    }\n    // Touch events\n    /**\n     * Invoked when the user touches an element on a touch screen.\n     * @private\n     * @param event - The touch event that occurs.\n     */\n    _onTouchStart(event) {\n        const touches = event.changedTouches;\n        for (let i = 0; i < touches.length; i++) {\n            this.__startTouch(touches[i]);\n        }\n        this.initDrag(event);\n    }\n    /**\n     * Invoked when the user removes his/her finger from the touch pad.\n     *\n     * @param event - The touch event that occurs.\n     */\n    onTouchEnd(event) {\n        event.preventDefault();\n        event.stopPropagation();\n        const touches = event.changedTouches;\n        for (let i = 0; i < touches.length; i++) {\n            this.__endTouch(touches[i]);\n        }\n        if (Object.keys(this.ongoingTouches).length == 0)\n            this.endDrag(event);\n    }\n    /**\n     * Invoked when the touch event gets interrupted.\n     *\n     * @param event - The touch event that occurs.\n     */\n    onTouchCancel(event) {\n        event.preventDefault();\n        const touches = event.touches;\n        for (let i = 0; i < touches.length; i++) {\n            this.__endTouch(touches[i]);\n        }\n        if (Object.keys(this.ongoingTouches).length == 0)\n            this.endDrag(event);\n    }\n    /**\n     * Returns a dictionary of support manipulation modes.\n     *\n     * @param event - The touch event that occurs.\n     */\n    static get MANIPULATION_MODES() {\n        return MANIPULATION_MODES;\n    }\n}\n\nvar GeomType$2;\n(function (GeomType) {\n    GeomType[GeomType[\"TRIANGLES\"] = 0] = \"TRIANGLES\";\n    GeomType[GeomType[\"LINES\"] = 1] = \"LINES\";\n    GeomType[GeomType[\"POINTS\"] = 2] = \"POINTS\";\n})(GeomType$2 || (GeomType$2 = {}));\n\nconst create3DContext = function (canvas, opt_attribs) {\n    let context = null;\n    if (opt_attribs.webglContextType != undefined) {\n        try {\n            context = canvas.getContext(opt_attribs.webglContextType, opt_attribs);\n            context.name = opt_attribs.webglContextType;\n        }\n        catch (e) { }\n    }\n    else {\n        const names = ['webgl2', 'webgl'];\n        for (let i = 0; i < names.length; i++) {\n            const name = names[i];\n            try {\n                context = canvas.getContext(name, opt_attribs);\n                context.name = name;\n            }\n            catch (e) { }\n            if (context) {\n                break;\n            }\n        }\n    }\n    if (!context) {\n        throw new Error('WebGL not supported on your system');\n    }\n    // context.setupInstancedQuad = setupInstancedQuad;\n    // context.bindInstancedQuad = bindInstancedQuad;\n    context.sizeInBytes = function (type) {\n        switch (type) {\n            case this.BYTE:\n            case this.UNSIGNED_BYTE:\n                return 1;\n            case this.SHORT:\n            case this.UNSIGNED_SHORT:\n                return 2;\n            case this.INT:\n            case this.UNSIGNED_INT:\n            case this.FLOAT:\n                return 4;\n            default:\n                throw new Error('unknown type');\n        }\n    };\n    context.floatTexturesSupported = true;\n    context.__ext_texture_float = context.getExtension('OES_texture_float');\n    context.__ext_float_linear = context.getExtension('OES_texture_float_linear');\n    context.__ext_texture_half_float = context.getExtension('OES_texture_half_float');\n    context.__ext_texture_half_float_linear = context.getExtension('OES_texture_half_float_linear');\n    // Needed for rendering to float textures in an Fbo\n    context.__ext_color_buffer_float = context.getExtension('EXT_color_buffer_float');\n    context.setupInstancedQuad = function () {\n        // ////////////////////////////\n        // Generate a buffer for drawing a full screen quad.\n        const vertexIDs = new Float32Array([0.0, 1.0, 2.0, 3.0]);\n        const indices = new Uint8Array([0, 1, 2, 2, 1, 3]);\n        this.__quadVertexIdsBuffer = this.createBuffer();\n        this.bindBuffer(this.ARRAY_BUFFER, this.__quadVertexIdsBuffer);\n        this.bufferData(this.ARRAY_BUFFER, vertexIDs, this.STATIC_DRAW);\n        this.__quadIndexBuffer = this.createBuffer();\n        this.bindBuffer(this.ELEMENT_ARRAY_BUFFER, this.__quadIndexBuffer);\n        this.bufferData(this.ELEMENT_ARRAY_BUFFER, indices, this.STATIC_DRAW);\n        this.__quadattrbuffers = {\n            vertexIDs: {\n                buffer: this.__quadVertexIdsBuffer,\n                dataType: context.FLOAT,\n                dimension: 1,\n                elementSize: 4,\n                count: vertexIDs.length,\n                shared: true /*This buffer is shared between geoms. do not destroy */,\n            },\n        };\n    };\n    context.drawQuad = function () {\n        this.drawElements(this.TRIANGLES, 6, this.UNSIGNED_BYTE, 0);\n    };\n    return context;\n};\n\nconst processTextureParams = function (gl, params) {\n    if (!params.width || !params.height) {\n        if (!params.width)\n            throw new Error(`Invalid texture params. 'width' not provided`);\n        if (!params.height)\n            throw new Error(`Invalid texture params. 'height' not provided`);\n    }\n    const maxSize = gl.getParameter(gl.MAX_TEXTURE_SIZE);\n    if (params.width <= 0 ||\n        params.width > maxSize ||\n        params.height <= 0 ||\n        params.height > maxSize) {\n        throw new Error('GLTextureParams: Invalid texture size. width:' +\n            params.width +\n            ' height:' +\n            params.height +\n            ' maxSize:' +\n            maxSize);\n    }\n    const result = {\n        width: params.width,\n        height: params.height,\n    };\n    const getGLConst = (nameOrValue) => {\n        return isNaN(nameOrValue) ? gl[nameOrValue] : nameOrValue;\n    };\n    const processParam = (name, defaultValue) => {\n        if (name in params)\n            result[name] = getGLConst(params[name]);\n        else if (defaultValue)\n            result[name] = getGLConst(defaultValue);\n    };\n    processParam('format');\n    processParam('internalFormat', result.format);\n    processParam('type', gl.UNSIGNED_BYTE);\n    processParam('minFilter', params.filter ? params.filter : gl.LINEAR);\n    processParam('magFilter', params.filter ? params.filter : gl.LINEAR);\n    processParam('wrapS', params.wrapS ? params.wrapS : gl.CLAMP_TO_EDGE);\n    processParam('wrapT', params.wrapT ? params.wrapT : gl.CLAMP_TO_EDGE);\n    processParam('mipMapped', false);\n    processParam('depthInternalFormat');\n    processParam('depthFormat');\n    processParam('depthType');\n    if (params.createDepthTexture) {\n        if (gl.name != 'webgl2' && !gl.__ext_WEBGL_depth_texture) {\n            result['depthType'] = gl.UNSIGNED_SHORT;\n        }\n        else {\n            // the proper texture format combination can be found here\n            // https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glTexImage2D.xhtml\n            // https://github.com/WebGLSamples/WebGL2Samples/blob/master/samples/fbo_rtt_depth_texture.html\n            // gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT16, this.width, this.height, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_SHORT, null);\n            result['depthFormat'] = gl.DEPTH_COMPONENT;\n            result['depthType'] = gl.UNSIGNED_INT;\n        }\n    }\n    // https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glTexImage2D.xhtml\n    if (result.format == gl.FLOAT) {\n        if (result.filter == gl.LINEAR && !gl.__ext_float_linear) {\n            console.warn('Floating point texture filtering not supported on result device');\n            result.filter = gl.NEAREST;\n        }\n    }\n    else if (result.format == gl.HALF_FLOAT) ;\n    else if (result.format == 'sRGB') {\n        if (!gl.__ext_sRGB)\n            throw new Error('EXT_sRGB is not available');\n    }\n    // ////////////////////////////////////////////////////\n    // Format ... InternalFormat combos.\n    // Setup the correct combos.\n    // the proper texture format combination can be found here\n    // https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glTexImage2D.xhtml\n    // Determine the internal format from mthe format and type.\n    if (result.format != undefined && result.internalFormat == result.format) {\n        if (result.type == gl.FLOAT) {\n            if (result.format == gl.RED) {\n                result.internalFormat = gl.R32F;\n            }\n            else if (result.format == gl.RG) {\n                result.internalFormat = gl.RG32F;\n            }\n            else if (result.format == gl.RGB) {\n                result.internalFormat = gl.RGB32F;\n            }\n            else if (result.format == gl.RGBA) {\n                result.internalFormat = gl.RGBA32F;\n            }\n        }\n        else if (result.type == gl.HALF_FLOAT) {\n            if (result.format == gl.RED) {\n                result.internalFormat = gl.R16F;\n            }\n            else if (result.format == gl.RGB) {\n                result.internalFormat = gl.RGB16F;\n            }\n            else if (result.format == gl.RGBA) {\n                result.internalFormat = gl.RGBA16F;\n            }\n        }\n        else if (result.type == gl.UNSIGNED_BYTE) {\n            if (result.format == gl.RED) {\n                result.internalFormat = gl.R8;\n            }\n            if (result.format == gl.RGB) {\n                result.internalFormat = gl.RGB8;\n            }\n            else if (result.format == gl.RGBA) {\n                result.internalFormat = gl.RGBA8;\n            }\n        }\n    }\n    if (result.depthFormat != undefined) {\n        if (result.depthType == gl.UNSIGNED_SHORT) {\n            result.depthInternalFormat = gl.DEPTH_COMPONENT16;\n        }\n        else if (result.depthType == gl.UNSIGNED_INT) {\n            result.depthInternalFormat = gl.DEPTH_COMPONENT24;\n        }\n    }\n    return result;\n};\n\n/**\n * Represents a texture that contains 2-dimensional images.\n * Images have width and height, but no depth.\n *\n * @extends RefCounted\n */\nclass GLTexture2D extends RefCounted {\n    gl;\n    width = 0;\n    height = 0;\n    textureType;\n    textureDesc;\n    loaded;\n    image = null;\n    internalFormat = 0;\n    format = 0;\n    type = 0;\n    minFilter = 0;\n    magFilter = 0;\n    wrapS = 0;\n    wrapT = 0;\n    mipMapped = false;\n    invert = false;\n    gltex = null;\n    /**\n     * Create a GL texture 2D.\n     *\n     * @param gl - The gl value.\n     * @param params - The params value.\n     */\n    constructor(gl, params) {\n        super();\n        this.gl = gl;\n        this.textureType = 1; // Default 2d 24bit texture image texture. No alpha.\n        this.textureDesc = [0, 0, 0, 0]; // To be populated by derived classes.\n        this.loaded = false;\n        if (params != undefined) {\n            if (params instanceof BaseImage) {\n                this.image = params;\n                const imageUpdated = () => {\n                    // this.bufferData(data);\n                    const params = this.image.getParams();\n                    const width = params.width;\n                    const height = params.height;\n                    const data = params.data;\n                    this.bufferData(data, width, height);\n                };\n                this.image.on('updated', imageUpdated);\n                if (this.image.isLoaded()) {\n                    this.configure(this.image.getParams());\n                }\n                else {\n                    this.image.on('loaded', () => {\n                        this.configure(this.image.getParams());\n                    });\n                }\n            }\n            else {\n                this.configure(params);\n            }\n        }\n    }\n    /**\n     * Builds the GLTexture2D using the specified parameters object.\n     * Parameters must have the `BaseImage` properties structure.\n     *\n     * @param params - The params value.\n     *\n     * @param emit - The emit value.\n     */\n    configure(params) {\n        const gl = this.gl;\n        {\n            const p = processTextureParams(gl, params); // TODO: check method\n            this.format = p.format;\n            this.internalFormat = p.internalFormat;\n            this.type = p.type;\n            this.minFilter = p.minFilter;\n            this.magFilter = p.magFilter;\n            this.wrapS = p.wrapS;\n            this.wrapT = p.wrapT;\n            this.mipMapped = 'mipMapped' in params ? params.mipMapped : false;\n        }\n        this.textureType = 1; // Default 2d 8 bit texture image texture.\n        this.textureDesc[0] = this.width;\n        this.textureDesc[1] = this.height;\n        // Detect an 8 bit image with an alpha channel.\n        if (this.textureType == 1 && this.format == gl.RGBA) {\n            this.textureType = 2; // 32bit BPP image.\n        }\n        if (this.gltex) {\n            gl.deleteTexture(this.gltex);\n            this.width = 0;\n            this.height = 0;\n        }\n        this.gltex = gl.createTexture();\n        this.updateGLTexParams();\n        const data = params.data;\n        if (data) {\n            this.bufferData(data, params.width, params.height, false, false);\n        }\n        else {\n            this.resize(params.width, params.height, false, false);\n        }\n        if (!this.loaded) {\n            this.emit('ready');\n            this.loaded = true;\n        }\n    }\n    activateLastTextureUnit() {\n        // Load the image into the GPU for rendering.\n        // We often need to populate textures during rendering.\n        // e.g. when lazily updating a texture containing geometry\n        // buffers (FatPoints)\n        // We don't want to bind over an existing texture, so we use the\n        // last texture unit. (we bind starting from 0, and go up)\n        const gl = this.gl;\n        const maxTextures = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS);\n        gl.activeTexture(gl.TEXTURE0 + maxTextures - 1);\n    }\n    /**\n     * The updateGLTexParams method.\n     * @private\n     */\n    updateGLTexParams() {\n        const gl = this.gl;\n        this.activateLastTextureUnit();\n        gl.bindTexture(gl.TEXTURE_2D, this.gltex);\n        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, this.minFilter);\n        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, this.magFilter);\n        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, this.wrapS);\n        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, this.wrapT);\n    }\n    /**\n     * Initializes and creates the buffer of the object's data store.\n     *\n     * @param data - The data value.\n     * @param width - The width value.\n     * @param height - The height value.\n     * @param bind - The bind value.\n     * @param emit - The emit value.\n     */\n    // TODO: type Image doesn't exist.\n    bufferData(data, width = -1, height = -1, bind = true, emit = true) {\n        const gl = this.gl;\n        if (data != undefined) {\n            if (data instanceof WebGLTexture) {\n                this.gltex = data;\n            }\n            else if (data instanceof HTMLImageElement ||\n                data instanceof ImageData ||\n                data instanceof HTMLCanvasElement ||\n                data instanceof HTMLImageElement ||\n                data instanceof HTMLVideoElement) {\n                if (bind) {\n                    this.activateLastTextureUnit();\n                    gl.bindTexture(gl.TEXTURE_2D, this.gltex);\n                }\n                gl.texImage2D(gl.TEXTURE_2D, 0, this.internalFormat, this.format, this.type, data);\n                this.width = data.width;\n                this.height = data.height;\n            }\n            else {\n                // if wieght and height not specified, assume they stay the same.\n                if (width == -1) {\n                    width = this.width;\n                }\n                if (height == -1) {\n                    height = this.height;\n                }\n                // Note: data images must have an even size width/height to load correctly.\n                // this doesn't mean they must be pot textures...\n                const numPixels = width * height;\n                let numChannels;\n                switch (this.format) {\n                    case gl.RED:\n                    case gl.RED_INTEGER:\n                    case gl.ALPHA:\n                    case gl.LUMINANCE:\n                    case gl.LUMINANCE_ALPHA:\n                        numChannels = 1;\n                        break;\n                    case gl.RG:\n                        numChannels = 2;\n                        // Note: when uploading UNSIGNED_BYTE  RG textures, I received the following error: ArrayBuffer not big enough for request\n                        // This answer on stack overflow lead me to this fix.\n                        // https://stackoverflow.com/questions/42789896/webgl-error-arraybuffer-not-big-enough-for-request-in-case-of-gl-luminance\n                        // The same fix maybe need to be applied to single channel textures above, although I have not seen the error.\n                        gl.pixelStorei(gl.UNPACK_ALIGNMENT, 2);\n                        break;\n                    case gl.RGB:\n                    case gl.RGB_INTEGER:\n                        numChannels = 3;\n                        break;\n                    case gl.RGBA:\n                    case gl.RGBA_INTEGER:\n                        numChannels = 4;\n                        break;\n                    default:\n                        console.warn('Reaching default case: numChannels:=1');\n                        numChannels = 1;\n                        break;\n                }\n                if (data.length != numPixels * numChannels) {\n                    console.warn('Invalid data for Image width:' +\n                        width +\n                        ' height:' +\n                        height +\n                        ' Data Length:' +\n                        data.length +\n                        ' Expected:' +\n                        numPixels * numChannels);\n                }\n                let uploadData = data;\n                if (this.type == gl.HALF_FLOAT && data instanceof Float32Array) {\n                    uploadData = MathFunctions.convertFloat32ArrayToUInt16Array(data);\n                }\n                if (bind) {\n                    this.activateLastTextureUnit();\n                    gl.bindTexture(gl.TEXTURE_2D, this.gltex);\n                }\n                gl.texImage2D(gl.TEXTURE_2D, 0, this.internalFormat, width, height, 0, this.format, this.type, uploadData, 0);\n                // These values may not have changed....\n                this.width = width;\n                this.height = height;\n            }\n            if (this.mipMapped) {\n                gl.generateMipmap(gl.TEXTURE_2D);\n            }\n        }\n        else {\n            if (bind) {\n                this.activateLastTextureUnit();\n                gl.bindTexture(gl.TEXTURE_2D, this.gltex);\n            }\n            gl.texImage2D(gl.TEXTURE_2D, 0, this.internalFormat, this.width, this.height, 0, this.format, this.type, null);\n            // simply resize the buffer.\n            this.width = width;\n            this.height = height;\n        }\n        if (emit) {\n            this.emit('updated');\n        }\n    }\n    /**\n     * Clears the buffers to preset values\n     */\n    clear() {\n        const gl = this.gl;\n        const numPixels = this.width * this.height;\n        let numChannels;\n        switch (this.format) {\n            case gl.RED:\n            case gl.RED_INTEGER:\n            case gl.ALPHA:\n            case gl.LUMINANCE:\n            case gl.LUMINANCE_ALPHA:\n                numChannels = 1;\n                break;\n            case gl.RG:\n                numChannels = 2;\n                break;\n            case gl.RGB:\n                numChannels = 3;\n                break;\n            case gl.RGBA:\n                numChannels = 4;\n                break;\n            default:\n                throw new Error('Invalid Format');\n        }\n        let data;\n        switch (this.type) {\n            case gl.UNSIGNED_BYTE:\n                data = new Uint8Array(numPixels * numChannels);\n                break;\n            case gl.HALF_FLOAT:\n                data = new Uint16Array(numPixels * numChannels);\n                break;\n            case gl.FLOAT:\n                data = new Float32Array(numPixels * numChannels);\n                break;\n            default:\n                throw new Error('Invalid Type');\n        }\n        gl.texImage2D(gl.TEXTURE_2D, 0, this.internalFormat, this.width, this.height, 0, this.format, this.type, data, 0);\n    }\n    /**\n     * The resize method.\n     * @param width - The width value.\n     * @param height - The height value.\n     * @param preserveData - The preserveData value.\n     * @param emit - The emit value.\n     */\n    resize(width, height, preserveData = false, emit = true) {\n        const gl = this.gl;\n        const sizeChanged = this.width != width || this.height != height;\n        if (sizeChanged) {\n            const maxSize = gl.getParameter(gl.MAX_TEXTURE_SIZE);\n            if (width < 0 || width > maxSize || height < 0 || height > maxSize) {\n                throw new Error('gl-texture2d: Invalid texture size. width:' + width + ' height:' + height + ' maxSize:' + maxSize);\n            }\n            if (preserveData) {\n                const gltex = gl.createTexture();\n                this.activateLastTextureUnit();\n                gl.bindTexture(gl.TEXTURE_2D, gltex);\n                gl.texImage2D(gl.TEXTURE_2D, 0, this.internalFormat, width, height, 0, this.format, this.type, null);\n                const fbo = gl.createFramebuffer();\n                gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);\n                gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.gltex, 0);\n                gl.copyTexImage2D(gl.TEXTURE_2D, 0, this.internalFormat, 0, 0, this.width, this.height, 0);\n                gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n                gl.deleteFramebuffer(fbo);\n                this.gl.deleteTexture(this.gltex);\n                this.gltex = gltex;\n                this.updateGLTexParams();\n            }\n            else {\n                if (this.width > 0 && this.height > 0) {\n                    this.gl.deleteTexture(this.gltex);\n                    this.gltex = gl.createTexture();\n                    this.updateGLTexParams();\n                }\n                gl.bindTexture(gl.TEXTURE_2D, this.gltex);\n                gl.texImage2D(gl.TEXTURE_2D, 0, this.internalFormat, width, height, 0, this.format, this.type, null);\n            }\n            this.width = width;\n            this.height = height;\n            if (emit) {\n                const event = new ResizedEvent(width, height);\n                this.emit('resized', event);\n            }\n        }\n    }\n    /**\n     * Upload data for the image to the GPU.\n     *\n     * @param dataArray - The dataArray value.\n     * @param width - The width value\n     * @param height - The height value\n     * @param offsetX - The offsetX value\n     * @param offsetY - The offsetY value\n     * @param bind - The bind value\n     */\n    populate(dataArray, width, height, offsetX = 0, offsetY = 0, bind = true) {\n        const gl = this.gl;\n        if (bind) {\n            this.activateLastTextureUnit();\n            gl.bindTexture(gl.TEXTURE_2D, this.gltex);\n        }\n        gl.texSubImage2D(gl.TEXTURE_2D, 0, offsetX, offsetY, width, height, this.format, this.type, dataArray);\n        if (bind)\n            gl.bindTexture(gl.TEXTURE_2D, null);\n    }\n    /**\n     * Returns the `width`(Index 0) and the `height`(Index 1) of the GL Texture.\n     *\n     * @return - The return value.\n     */\n    getSize() {\n        return [this.width, this.height];\n    }\n    /**\n     * Returns the value of the WebGLTexture value\n     *\n     * @return - The return value.\n     */\n    get glTex() {\n        return this.gltex;\n    }\n    /**\n     * Returns the value of the WebGLTexture value\n     *\n     * @return - The return value.\n     */\n    getTexHdl() {\n        return this.gltex;\n    }\n    /**\n     * The preBind method.\n     * @param unif - The unif value.\n     * @param unifs - The unifs value.\n     * @return - The return value.\n     */\n    preBind(unif, unifs) {\n        return {\n            textureTypeUnif: unifs[unif.name + 'Type'],\n            textureDescUnif: unifs[unif.name + 'Desc'],\n        };\n    }\n    /**\n     * Binds Texture to the ShaderUniform attribute.\n     *\n     * @param renderstate - The renderstate value.\n     * @param unif - The unif value.\n     * @param bindings - The bindings value.\n     * @return - The return value.\n     */\n    bindToUniform(renderstate, unif, bindings) {\n        if (!this.loaded) {\n            return false;\n        }\n        if (!this.gltex) {\n            throw new Error('Unable to bind non-initialized or deleted texture.');\n        }\n        renderstate.bindTexture(unif, this.gltex);\n        if (bindings) {\n            const gl = this.gl;\n            if (bindings.textureTypeUnif) {\n                gl.uniform1i(bindings.textureTypeUnif.location, this.textureType);\n            }\n            if (bindings.textureDescUnif) {\n                gl.uniform4fv(bindings.textureDescUnif.location, this.textureDesc);\n            }\n        }\n        return true;\n    }\n    /**\n     * The destroy is called by the system to cause explicit resources cleanup.\n     * Users should never need to call this method directly.\n     */\n    destroy() {\n        super.destroy();\n        this.gl.deleteTexture(this.gltex);\n        this.gltex = null;\n    }\n}\n\n/*\n  regex variables\n*/\nconst WHITESPACE_RE = /\\s+/;\n/** Class representing a shader library.\n * @private\n */\nclass ShaderLibrary {\n    __shaderModules;\n    materialTemplates;\n    /**\n     * Create a shader library.\n     */\n    constructor() {\n        this.__shaderModules = {};\n        this.materialTemplates = {};\n    }\n    /**\n     * The setShaderModule method. Shader must be set before parsing.\n     * @param shaderName - The shader name.\n     * @param shader - The unparsed shader GLSL.\n     */\n    setShaderModule(shaderName, shader) {\n        if (!(shaderName in this.__shaderModules)) {\n            this.__shaderModules[shaderName] = shader;\n            return;\n        }\n        // note: this code does not update shader snippets, whatever is first, stays.\n        // important for creating tests, since shaderLibrary is global.\n    }\n    /**\n     * The getShaderModule method. Access specific uniforms, attributes of a particular module.\n     * @param shaderName - The shader name.\n     * @return - The return value.\n     */\n    getShaderModule(shaderName) {\n        return this.__shaderModules[shaderName];\n    }\n    /**\n     * The getShaderModuleNames method.\n     * @return - The return value.\n     */\n    getShaderModuleNames() {\n        const shaderNames = [];\n        // eslint-disable-next-line guard-for-in\n        for (const shaderName in this.__shaderModules)\n            shaderNames.push(shaderName);\n        return shaderNames;\n    }\n    /**\n     * The parseAttr\n     * @param parts - parts\n     * @param instanced - instanced\n     * @param result - result object to store parsed data\n     */\n    parseAttr(parts, instanced, result, line) {\n        const name = parts[2].slice(0, parts[2].length - 1);\n        const type = parts[1];\n        const isInteger = type == 'int' || type == 'uint' || type == 'ivec2' || type == 'ivec3' || type == 'ivec4';\n        result.attributes[name] = {\n            glslType: type,\n            instanced: instanced,\n            integer: isInteger,\n        };\n        // console.log('attributes:' + name + \":\" + parts[1]);\n        if (parts[1] == 'color') {\n            parts[1] = 'vec4';\n            parts.join(' ');\n        }\n    }\n    /**\n     * The handleImport method -- takes the includeFile and if it exists, adds the parsed glsl, uniforms, and attributes to the result, recursively.\n     * @param result - result object that stores the glsl, attribute, uniform\n     * @param shaderName - shaderName\n     * @param includeFile - file name of the shader snippet/module\n     * @param includes - keep track of what was included\n     * @param lineNumber - keep track of what line we're on\n     */\n    handleImport(result, shaderName, includeFile, includes, lineNumber) {\n        if (includeFile in this.__shaderModules) {\n            const includedGLSL = this.__shaderModules[includeFile]; // get glsl snippet code to add\n            if (!includedGLSL)\n                throw Error('snippet not loaded or does not exists!');\n            // recursively includes glsl snippets\n            const reursiveResult = this.parseShaderHelper(shaderName, includedGLSL, includes, lineNumber);\n            // adding code + snippet glsl, if not already added.\n            includes.push(includeFile); // keep track of imports\n            result.glsl = result.glsl + reursiveResult.glsl;\n            result.numLines += reursiveResult.numLines;\n            result.uniforms = {\n                ...result.uniforms,\n                ...reursiveResult.uniforms,\n            };\n            result.attributes = {\n                ...result.attributes,\n                ...reursiveResult.attributes,\n            };\n            // console.log('\\n glsl snippet: ' + reursiveResult.glsl) // print out snippets\n        }\n        else {\n            // throw new Error(shaderName + ': SNIPPET NOT FOUND: ' + includeFile)\n            console.log('shaderName: ' + shaderName);\n            console.log('SNIPPET NOT FOUND: ' + includeFile);\n        }\n    }\n    /**\n     * The parseShader method.\n     * @param shaderName - The shader name.\n     * @param glsl - The glsl param.\n     * @return - returns the 'result' object\n     */\n    parseShader(shaderName, glsl) {\n        return this.parseShaderHelper(shaderName, glsl, [], 0);\n    }\n    /**\n     * The parseShader recursive helper method\n     * @param shaderName - The shader name.\n     * @param glsl - The glsl param.\n     * @param includes - keep track of what was included\n     * @param lineNumber - keep track of what line we're on\n     * @return - The return value.\n     */\n    parseShaderHelper(shaderName, glsl, includes, lineNumber) {\n        // console.log('parseShader:' + shaderName)\n        const addLine = (result, line) => {\n            result.glsl = result.glsl + line + '\\n';\n            result.numLines++;\n        };\n        includes.push(shaderName);\n        // result that is returned\n        const result = {\n            glsl: '',\n            numLines: 0,\n            uniforms: {},\n            attributes: {},\n        };\n        // go through each line of a GLSL file\n        glsl = glsl.toString(); // TODO: remove ideally, this cast is here just to make jest pass\n        const lines = glsl.split('\\n'); // break up code by newlines\n        for (let i = 0; i < lines.length; i++) {\n            let line = lines[i];\n            const trimmedLine = line.trim();\n            // Get first token of a statement and switch\n            const parts = trimmedLine.split(WHITESPACE_RE);\n            const firstToken = parts[0];\n            switch (firstToken) {\n                // TODO: deprecated - remove eventually\n                case '<%include':\n                case 'import': {\n                    // get the contents between quotes and then if there are '/' get the filename\n                    const includeFile = trimmedLine.split(/'|\"|`/)[1].split('/').pop(); // can be undefined\n                    if (!includes.includes(includeFile)) {\n                        this.handleImport(result, shaderName, includeFile, includes, lineNumber);\n                    }\n                    break;\n                }\n                case 'attribute': {\n                    this.parseAttr(parts, false, result, line);\n                    addLine(result, line);\n                    break;\n                }\n                case 'instancedattribute': {\n                    this.parseAttr(parts, true, result, line);\n                    parts[0] = 'attribute';\n                    line = parts.join(' ');\n                    addLine(result, line);\n                    break;\n                }\n                case 'uniform': {\n                    // When a precision qualifier exists in the uniform definition.\n                    // e.g. uniform highp int instancesTextureSize;\n                    let typeIndex = 1;\n                    if (parts.length == 4)\n                        typeIndex = 2;\n                    const typeName = parts[typeIndex];\n                    const name = parts[typeIndex + 1].slice(0, parts[typeIndex + 1].length - 1);\n                    if (name.includes('[')) {\n                        // Strip off the square brackets.\n                        result.uniforms[name.substring(0, name.indexOf('['))] = {\n                            glslType: typeName,\n                        };\n                    }\n                    else {\n                        result.uniforms[name] = {\n                            glslType: typeName,\n                        };\n                    }\n                    if (typeName == 'struct') {\n                        console.log(parts);\n                    }\n                    if (parts[1] == 'color') {\n                        parts[1] = 'vec4';\n                        line = parts.join(' ');\n                    }\n                    addLine(result, line);\n                    break;\n                }\n                // TODO: structs disabled in ts-migration\n                // case 'struct': {\n                //   let membersStr = ''\n                //   if (trimmedLine.includes('}')) {\n                //     membersStr = trimmedLine.substring(trimmedLine.indexOf('{') + 1, trimmedLine.indexOf('}') - 1)\n                //   } else {\n                //     i++\n                //     while (true) {\n                //       line += lines[i] + '\\n'\n                //       membersStr += line.trim()\n                //       i++\n                //       if (membersStr.includes('}')) break\n                //     }\n                //   }\n                //   const structMembers = membersStr.substring(membersStr.indexOf('{') + 1, membersStr.indexOf('}') - 1)\n                //   const members = structMembers.split(';')\n                //   const structDesc = []\n                //   for (const member of members) {\n                //     if (member.length == 0) continue\n                //     const memberparts = member.trim().split(WHITESPACE_RE)\n                //     structDesc.push({\n                //       name: memberparts[1],\n                //       type: GlslTypes[memberparts[0]],\n                //     })\n                //   }\n                //   GlslTypes[parts[1]] = structDesc\n                //   addLine(result, line)\n                //   break\n                // }\n                default: {\n                    // all other statements\n                    addLine(result, line);\n                    break;\n                }\n            } // end of switch\n        } // end of forloop\n        // console.log('length of shader: ' + result.numLines)\n        // console.log(result.glsl)\n        return result;\n    }\n}\nconst shaderLibrary = new ShaderLibrary();\n\nclass RenderState {\n    gl;\n    renderer;\n    stack = [];\n    top;\n    glShader;\n    shaderkey;\n    directives = [];\n    directivesHash;\n    attrs;\n    unifs;\n    drawItemsTexture;\n    shaderInstancedGeom;\n    glGeom;\n    boundVao;\n    xrviewport;\n    passIndex;\n    pass;\n    vrPresenting;\n    supportsInstancing;\n    viewport; // Viewport\n    viewports;\n    bindViewports;\n    bindRendererUnifs;\n    boundTextures;\n    boundRendertarget;\n    geometryMaskTextures;\n    viewXfo;\n    viewScale;\n    region;\n    depthRange;\n    cameraMatrix;\n    constructor(gl) {\n        this.gl = gl;\n    }\n    pushGLStack(name) {\n        this.top;\n        this.top = { name, enabled: new Set(), disabled: new Set(), functions: {} };\n        // Enable me to debug the rendering stack.\n        // console.log('pushGLStack:', prevTop ? prevTop.name : '', ' > ', this.top.name)\n        this.stack.push(this.top);\n    }\n    popGLStack() {\n        const prevTop = this.stack.pop();\n        this.top = this.stack[this.stack.length - 1];\n        // Enable me to debug the rendering stack.\n        // console.log('popGLStack:', prevTop.name, ' > ', this.top ? this.top.name : '')\n        // As we pop the stack we must restore the GL state to what it was.\n        if (this.stack.length > 0) {\n            prevTop.enabled.forEach((prop) => {\n                let i;\n                for (i = this.stack.length - 1; i >= 0; i--) {\n                    const stackItem = this.stack[i];\n                    if (stackItem.enabled.has(prop)) {\n                        break;\n                    }\n                    else if (stackItem.disabled.has(prop)) {\n                        this.gl.disable(prop);\n                        break;\n                    }\n                }\n                if (i < 0) {\n                    this.gl.disable(prop);\n                }\n            });\n            prevTop.disabled.forEach((prop) => {\n                let i;\n                for (i = this.stack.length - 1; i >= 0; i--) {\n                    const stackItem = this.stack[i];\n                    if (stackItem.disabled.has(prop)) {\n                        break;\n                    }\n                    else if (stackItem.enabled.has(prop)) {\n                        this.gl.enable(prop);\n                        break;\n                    }\n                }\n                if (i < 0) {\n                    this.gl.enable(prop);\n                }\n            });\n        }\n        //   for (let key in prevTop.enabled) {\n        //   }\n        //   for (let key in prevTop.disabled) {\n        //     const prop = prevTop.enabled[key]\n        //     if (stackItem.enabled[key] == prop) {\n        //       break\n        //     } else if (stackItem.disabled[key] == prop) {\n        //       this.gl.enable(prop)\n        //       break\n        //     }\n        //   }\n        // }\n        /*\n          for (let key in prevTop.functions) {\n            const args = prevTop[key]\n            for (let i = this.stack.length - 1; i >= 0; i--) {\n              const stackItem = this.stack[i]\n              const prevArgs = stackItem.functions[key]\n              if (prevArgs) {\n                if (prevArgs != args) {\n                  if (Array.isArray(prevArgs)) {\n                    this.gl[key](...prevArgs)\n                  } else {\n                    this.gl[key](prevArgs)\n                  }\n                }\n                break\n              }\n            }\n          }*/\n        // }\n    }\n    glEnable(prop) {\n        this.gl.enable(prop);\n        this.top.enabled.add(prop);\n    }\n    glDisable(prop) {\n        this.gl.disable(prop);\n        this.top.disabled.add(prop);\n    }\n    bindTexture(unif, gltex) {\n        const unit = this.boundTextures++;\n        const gl = this.gl;\n        gl.activeTexture(gl.TEXTURE0 + unit);\n        gl.bindTexture(gl.TEXTURE_2D, gltex);\n        gl.uniform1i(unif.location, unit);\n    }\n}\n\nclass HighlightRenderState extends RenderState {\n}\n\nclass ColorRenderState extends RenderState {\n    envMap;\n    renderMode;\n    outlineMethod;\n    outlineThickness;\n    outlineColor;\n    hiddenLineColor;\n    screenQuad;\n    exposure; // must initialize these\n    gamma;\n    toHighlightRenderState() {\n        const highlightRenderState = new HighlightRenderState(this.gl);\n        highlightRenderState.boundRendertarget = this.boundRendertarget;\n        highlightRenderState.viewXfo = this.viewXfo;\n        highlightRenderState.viewScale = this.viewScale;\n        highlightRenderState.region = this.region;\n        highlightRenderState.cameraMatrix = this.cameraMatrix;\n        highlightRenderState.viewport = this.viewport;\n        highlightRenderState.vrPresenting = this.vrPresenting;\n        highlightRenderState.bindViewports = this.bindViewports;\n        highlightRenderState.bindRendererUnifs = this.bindRendererUnifs;\n        return highlightRenderState;\n    }\n}\n\nclass GeomDataRenderState extends RenderState {\n    geomDataFbo; // only used in geomdata buffer rendering\n    floatGeomBuffer;\n    occlusionCulling;\n    debugGeomDataBuffer;\n    pointAndLinePickingSize;\n}\n\n/* eslint-disable valid-jsdoc */\n// Every instance of every shader should have a unique id.\n// This is so that we can uniquely identify the bound shader during\n// rendering. Materials and geometries cache bindings to shaders.\n// And need the id to be unique. (Note: we used to use the constructor.name\n// which was only unique if the same shader was constructed once, and\n// never unique in release mode after the port to Rollup)\nlet shaderInstanceId = 0;\n/** Class representing a GL shader.\n * @extends BaseItem\n * @private\n */\nclass GLShader extends BaseItem {\n    __gl;\n    shaderStagesGLSL = {};\n    shaderStages = {};\n    shaderProgramHdls = {};\n    /**\n     * Create a GL shader.\n     * @param gl - The webgl rendering context.\n     */\n    constructor(gl, name) {\n        super(name);\n        if (gl)\n            this.__gl = gl;\n        this.__id = shaderInstanceId++;\n        // hack to enable Zea-UX to work untill its upgraded.\n        //@ts-ignore\n        this.__shaderStages = this.shaderStages;\n    }\n    /**\n     * Sets the GL context to the shader.\n     * > Note: normally the context should be passed to the constructor. This method us used when using the Registry to construct shaders.\n     * @param gl - The webgl rendering context.\n     */\n    setGLContext(gl) {\n        this.__gl = gl;\n    }\n    /**\n     * Sets the GLSL code for a given shader stage.\n     * @param stageName - The name of the stage. currently only 'VERTEX_SHADER' or 'FRAGMENT_SHADER' are supported.\n     * @param glsl - The GLSL code for the shader stage.\n     */\n    setShaderStage(stageName, glsl) {\n        this.shaderStagesGLSL[stageName] = glsl;\n        this.clearProgramsCache();\n    }\n    /**\n     * Gets the GLSL code for a given shader stage.\n     * @param stageName - The name of the stage. currently only 'VERTEX_SHADER' or 'FRAGMENT_SHADER' are supported.\n     * @return - The GLSL code for the shader stage.\n     */\n    getShaderStage(stageName) {\n        return this.shaderStagesGLSL[stageName];\n    }\n    /**\n     * Clears all cached shader compilations for this shader.\n     */\n    clearProgramsCache() {\n        const gl = this.__gl;\n        for (const shaderProgramkey in this.shaderProgramHdls) {\n            const shaderCompilationResult = this.shaderProgramHdls[shaderProgramkey];\n            for (const shaderKey in shaderCompilationResult.shaderHdls) {\n                gl.deleteShader(shaderCompilationResult.shaderHdls[shaderKey]);\n            }\n            gl.deleteProgram(shaderCompilationResult.shaderProgramHdl);\n        }\n    }\n    /**\n     * The isOpaque method.\n     * @return - The return value.\n     */\n    static isOpaque() {\n        return true;\n    }\n    /**\n     * The isOverlay method.\n     * @return - The return value.\n     */\n    static isOverlay() {\n        return false;\n    }\n    // /////////////////////////////////\n    // Compilation\n    generateNumberedLines(lines, startOffset, endOffset, errorLines) {\n        const numberedLinesWithErrors = [];\n        for (const key in errorLines) {\n            const lineNumber = Number.parseInt(key) - 1;\n            for (let i = Math.max(0, lineNumber - startOffset); i < lineNumber; i++)\n                numberedLinesWithErrors.push((i + 1 + ' ').padStart(3) + '\\x1B[34;107;2m' + lines[i] + '\\x1B[m');\n            numberedLinesWithErrors.push((lineNumber + 1 + '>').padStart(3) + '\\x1B[41;93;4m' + lines[lineNumber] + '\\x1B[m');\n            for (let i = lineNumber + 1; i < Math.min(lines.length - 1, lineNumber + endOffset); i++)\n                numberedLinesWithErrors.push((i + 1 + ' ').padStart(3) + '\\x1B[34;107;2m' + lines[i] + '\\x1B[m');\n            const errors = errorLines[key];\n            for (const error of errors) {\n                numberedLinesWithErrors.push(error);\n            }\n        }\n        return numberedLinesWithErrors;\n    }\n    /**\n     * The compileShaderStage method.\n     * @param glsl - The glsl value.\n     * @param stageID - The stageID value.\n     * @param name - The name value.\n     * @param directives - The directives value.\n     * @return - The return value.\n     * @private\n     */\n    compileShaderStage(glsl, stageID, name, directives) {\n        const gl = this.__gl;\n        // console.log(\"compileShaderStage:\" + this.name+\".\"+name + \" glsl:\\n\" + glsl);\n        if (directives) {\n            const defines = directives.join('\\n') + '\\n';\n            glsl = defines + glsl;\n        }\n        glsl = StringFunctions.replaceAll(glsl, 'attribute', 'in');\n        if (name == 'vertexShader')\n            glsl = StringFunctions.replaceAll(glsl, 'varying', 'out');\n        else\n            glsl = StringFunctions.replaceAll(glsl, 'varying', 'in');\n        glsl = StringFunctions.replaceAll(glsl, 'texture2D', 'texture');\n        const prefix = '#version 300 es\\n';\n        glsl = prefix + glsl;\n        const shaderHdl = gl.createShader(stageID);\n        if (!shaderHdl)\n            throw Error('shaderHdl not defined');\n        gl.shaderSource(shaderHdl, glsl);\n        // Compile the shader program.\n        gl.compileShader(shaderHdl);\n        // See if it compiled successfully\n        if (!gl.getShaderParameter(shaderHdl, gl.COMPILE_STATUS)) {\n            console.log('Errors in :' + this.constructor.name + '.' + name);\n            const errors = gl.getShaderInfoLog(shaderHdl).split('\\n');\n            const errorLines = {};\n            for (let i = 0; i < errors.length; i++) {\n                const parts = errors[i].split(':');\n                if (parts.length >= 2) {\n                    const lineNum = parseInt(parts[2]); // TODO check against ATI and intel cards\n                    if (!isNaN(lineNum)) {\n                        if (errorLines[lineNum])\n                            errorLines[lineNum].push(errors[i]);\n                        else\n                            errorLines[lineNum] = [errors[i]];\n                    }\n                }\n            }\n            const lines = glsl.split('\\n');\n            console.groupCollapsed('ShaderError-All');\n            const allErrorLines = this.generateNumberedLines(lines, lines.length, lines.length, errorLines);\n            allErrorLines.forEach((line) => console.info(line));\n            console.groupEnd();\n            console.group('ShaderError-Summary');\n            const sumaryLinesWithErrors = this.generateNumberedLines(lines, 4, 5, errorLines);\n            sumaryLinesWithErrors.forEach((line) => console.info(line));\n            console.groupEnd();\n            throw new Error('An error occurred compiling the shader \\n=================\\n' + this.constructor.name + '.' + name);\n        }\n        return shaderHdl;\n    }\n    /**\n     * The createProgram method.\n     * @param directives - The directives value.\n     * @return - The program value.\n     * @private\n     */\n    createProgram(directives) {\n        const gl = this.__gl;\n        const shaderProgramHdl = gl.createProgram();\n        if (!shaderProgramHdl)\n            throw Error('shaderProgramHdl not defined');\n        const shaderHdls = {};\n        {\n            if (!this.shaderStages['VERTEX_SHADER']) {\n                // preprocess the GLSL, including all shader snippets\n                this.shaderStages['VERTEX_SHADER'] = shaderLibrary.parseShader('VERTEX_SHADER', this.shaderStagesGLSL['VERTEX_SHADER']);\n            }\n            const glsl = this.shaderStages['VERTEX_SHADER'].glsl;\n            if (glsl != undefined) {\n                const vertexShader = this.compileShaderStage(glsl, gl.VERTEX_SHADER, 'vertexShader', directives);\n                if (!vertexShader) {\n                    return;\n                }\n                gl.attachShader(shaderProgramHdl, vertexShader);\n                shaderHdls[gl.VERTEX_SHADER] = vertexShader;\n            }\n        }\n        {\n            if (!this.shaderStages['FRAGMENT_SHADER']) {\n                // preprocess the GLSL, including all shader snippets\n                this.shaderStages['FRAGMENT_SHADER'] = shaderLibrary.parseShader('FRAGMENT_SHADER', this.shaderStagesGLSL['FRAGMENT_SHADER']);\n            }\n            const glsl = this.shaderStages['FRAGMENT_SHADER'].glsl;\n            if (glsl != undefined) {\n                const fragmentShader = this.compileShaderStage(glsl, gl.FRAGMENT_SHADER, 'fragmentShader', directives);\n                if (!fragmentShader) {\n                    return;\n                }\n                gl.attachShader(shaderProgramHdl, fragmentShader);\n                shaderHdls[gl.FRAGMENT_SHADER] = fragmentShader;\n            }\n        }\n        gl.linkProgram(shaderProgramHdl);\n        if (!gl.getProgramParameter(shaderProgramHdl, gl.LINK_STATUS)) {\n            const info = gl.getProgramInfoLog(shaderProgramHdl);\n            if (!info)\n                throw Error('info not defined');\n            if (info.includes('D3D shader compilation failed')) {\n                // Usefull for debugging very nasty compiler errors generated only in the ANGL layer.\n                const debugExt = gl.getExtension('WEBGL_debug_shaders');\n                if (debugExt) {\n                    const hlsl = debugExt.getTranslatedShaderSource(shaderHdls[gl.VERTEX_SHADER]);\n                    console.log(hlsl);\n                }\n            }\n            console.groupCollapsed('vertexShaderGLSL');\n            console.log(this.shaderStages['VERTEX_SHADER'].glsl);\n            console.groupEnd();\n            console.groupCollapsed('fragmentShaderGLSL');\n            console.log(this.shaderStages['FRAGMENT_SHADER'].glsl);\n            console.groupEnd();\n            throw new Error('Unable to link the shader program:' + this.constructor.name + '\\n==================\\n' + info);\n        }\n        const attributeAndUniformLocation = this.extractAttributeAndUniformLocations(shaderProgramHdl);\n        return {\n            shaderHdls,\n            shaderProgramHdl,\n            unifs: attributeAndUniformLocation.unifs,\n            attrs: attributeAndUniformLocation.attrs,\n        };\n    }\n    /**\n     * The extractAttributeAndUniformLocations method.\n     * @param shaderProgramHdl - The shaderProgramHdl value.\n     * @param directives - GLSL shader directives\n     * @return - The dictionary of attributes and uniform values\n     * @private\n     */\n    extractAttributeAndUniformLocations(shaderProgramHdl) {\n        const gl = this.__gl;\n        const attrs = this.getAttributes();\n        const result = {\n            attrs: {},\n            unifs: {},\n        };\n        for (const attrName in attrs) {\n            const location = gl.getAttribLocation(shaderProgramHdl, attrName);\n            if (location == undefined) {\n                console.warn('Shader attribute not found:' + attrName);\n                continue;\n            }\n            const attrDesc = attrs[attrName];\n            result.attrs[attrName] = {\n                name: attrName,\n                location: location,\n                glslType: attrDesc.glslType,\n                instanced: attrDesc.instanced,\n                integer: attrDesc.integer,\n            };\n        }\n        const unifs = this.getUniforms(); // TODO: refactor type in fn()\n        for (let uniformName in unifs) {\n            const unifParseResult = unifs[uniformName];\n            // TODO: array uniform disabled during ts-migration\n            // if (unifType instanceof Array) {\n            //   for (const member of unifType) {\n            //     const structMemberName = uniformName + '.' + member.name\n            //     const location = gl.getUniformLocation(shaderProgramHdl, structMemberName)\n            //     if (location == undefined) {\n            //       // console.warn(this.constructor.name + \" uniform found in shader code but not in compiled program:\" + uniformName);\n            //       continue\n            //     }\n            //     result.unifs[structMemberName] = {\n            //       name: structMemberName,\n            //       location: location,\n            //       type: member.type,\n            //     }\n            //   }\n            // }\n            const location = gl.getUniformLocation(shaderProgramHdl, uniformName);\n            if (location == undefined) {\n                // console.warn(this.constructor.name + \" uniform found in shader code but not in compiled program:\" + uniformName);\n                continue;\n            }\n            result.unifs[uniformName] = {\n                name: uniformName,\n                location: location,\n                glslType: unifParseResult.glslType,\n            };\n        }\n        return result;\n    }\n    /**\n     * The getAttributes method.\n     * @return - The dictionary of attributes that this shader expects to be bound.\n     */\n    getAttributes() {\n        const attributes = {};\n        for (const stageName in this.shaderStages) {\n            const shaderStageBlock = this.shaderStages[stageName];\n            for (const attrName in shaderStageBlock['attributes'])\n                attributes[attrName] = shaderStageBlock['attributes'][attrName];\n        }\n        return attributes;\n    }\n    /**\n     * The getUniforms method.\n     * @return - The dictionary of uniforms that this shader expects to be bound.\n     */\n    getUniforms() {\n        const uniforms = {};\n        for (const stageName in this.shaderStages) {\n            const shaderStageBlock = this.shaderStages[stageName];\n            for (const unifName in shaderStageBlock['uniforms'])\n                uniforms[unifName] = shaderStageBlock['uniforms'][unifName];\n        }\n        return uniforms;\n    }\n    /**\n     * Checks to see if the engine is compiled for the target specified by the key\n     * @param key - The key value.\n     * @return - The return value.\n     */\n    isCompiledForTarget(key) {\n        // The provided key only needs to be unique within each shaders cachel\n        const shaderkey = key + this.getId() + '';\n        return this.shaderProgramHdls[shaderkey] != undefined;\n    }\n    /**\n     * The compileForTarget method.\n     * @param key - The key value.\n     * @param directives - The directives value.\n     * @return - The result of the shader compilation.\n     */\n    compileForTarget(key, directives) {\n        // Each time a shader is compiled, we cache the result.\n        // A drived shader should not share cache value with its base class,\n        // so we add the id to the cache key.\n        const shaderkey = key + this.getId() + '';\n        let shaderCompilationResult = this.shaderProgramHdls[shaderkey];\n        if (!shaderCompilationResult) {\n            shaderCompilationResult = this.createProgram(directives || []);\n            // Note: the id is always added to the key, so cache the key without the id\n            // so if we check the key again, the id is simply re-added.\n            // see: GLGeomItemSetMultiDrawCompoundGeom.drawGeomData\n            // When the geomDataShader is re-bound, it uses a cached key.\n            // > geomDataShader.bind(renderstate, geomDataShaderKey)\n            if (shaderCompilationResult)\n                shaderCompilationResult.shaderkey = key;\n            this.shaderProgramHdls[shaderkey] = shaderCompilationResult;\n            return shaderCompilationResult;\n        }\n        return shaderCompilationResult;\n    }\n    /**\n     * The bind method.\n     * @param renderstate - The object tracking the current state of the renderer\n     * @param key - The key value.\n     * @return - The return value.\n     */\n    bind(renderstate, key) {\n        const gl = this.__gl;\n        if (renderstate.glShader != this) {\n            const shaderCompilationResult = this.compileForTarget(key, renderstate.directives);\n            if (!shaderCompilationResult) {\n                // TODO: compileForTarget should return null or empty\n                console.warn(this.constructor.name + ' is not compiled for ' + key);\n                return false;\n            }\n            const shaderProgramHdl = shaderCompilationResult.shaderProgramHdl;\n            gl.useProgram(shaderProgramHdl);\n            renderstate.glShader = this;\n            renderstate.shaderkey = shaderCompilationResult.shaderkey;\n            renderstate.unifs = shaderCompilationResult.unifs;\n            renderstate.attrs = shaderCompilationResult.attrs;\n            renderstate.boundTextures = 0;\n            // Make sure we clear the binding cached.\n            renderstate.glGeom = undefined;\n            // Once the shader has been bound, we allow the renderer to bind any\n            // of its global uniform values. (e.g. env map values etc...)\n            if (renderstate.bindRendererUnifs)\n                renderstate.bindRendererUnifs(shaderCompilationResult.unifs);\n            if (renderstate.geometryMaskTextures && renderstate.unifs.frontDepthTexture) {\n                const { frontDepthTexture, backDepthTexture, viewportSize } = renderstate.unifs;\n                renderstate.bindTexture(frontDepthTexture, renderstate.geometryMaskTextures[0]);\n                renderstate.bindTexture(backDepthTexture, renderstate.geometryMaskTextures[1]);\n                gl.uniform2f(viewportSize.location, renderstate.region[2] - renderstate.region[0], renderstate.region[3] - renderstate.region[1]);\n            }\n            if (renderstate instanceof GeomDataRenderState) {\n                const { floatGeomBuffer, occlusionCulling, debugGeomDataBuffer } = renderstate.unifs;\n                if (floatGeomBuffer) {\n                    gl.uniform1i(floatGeomBuffer.location, renderstate.floatGeomBuffer ? 1 : 0);\n                }\n                if (occlusionCulling) {\n                    gl.uniform1i(occlusionCulling.location, renderstate.occlusionCulling);\n                }\n                if (debugGeomDataBuffer) {\n                    gl.uniform1i(debugGeomDataBuffer.location, renderstate.debugGeomDataBuffer ? 1 : 0);\n                }\n            }\n        }\n        // By default shaders support instancing.\n        // Derived Shaders may set this to false.\n        renderstate.supportsInstancing = true;\n        return true;\n    }\n    /**\n     * The unbind method.\n     * @param renderstate - The object tracking the current state of the renderer\n     * @return - The return value.\n     */\n    unbind(renderstate) {\n        renderstate.glShader = null;\n        renderstate.shaderkey = '';\n        renderstate.unifs = {};\n        renderstate.attrs = {};\n        return true;\n    }\n    // /////////////////////////////\n    // Parameters\n    /**\n     * The getGeomDataShaderName method.\n     * @return - an array of param declarations that the shader expects the material tp provide.\n     */\n    getGeomDataShaderName() {\n        return '';\n    }\n    /**\n     * The getSelectedShaderName method.\n     */\n    getSelectedShaderName() {\n        return '';\n    }\n    /**\n     * The supportsInstancing method.\n     * @return - return false for shaders that cannot be rendered in instanced mode.\n     */\n    static supportsInstancing() {\n        return true;\n    }\n    /**\n     * The getPackedMaterialData method.\n     * @param material - The material param.\n     * @return - The return value.\n     */\n    static getPackedMaterialData(material) {\n        const matData = new Float32Array(4);\n        return matData;\n    }\n    /**\n     * Each shader provides a template material that each material instance is\n     * based on. The shader specifies the parameters needed by the shader, and\n     * the material provides values to the shader during rendering.\n     * @return - The template material value.\n     */\n    static getMaterialTemplate() {\n        throw new Error('Shader does not provide a material template.');\n    }\n    // /////////////////////////////////\n    // Destroy\n    /**\n     * The destroy is called by the system to cause explicit resources cleanup.\n     * Users should never need to call this method directly.\n     */\n    destroy() {\n        const gl = this.__gl;\n        // eslint-disable-next-line guard-for-in\n        for (const key in this.shaderProgramHdls) {\n            const shaderCompilationResult = this.shaderProgramHdls[key];\n            gl.deleteProgram(shaderCompilationResult.shaderProgramHdl);\n        }\n        this.shaderProgramHdls = {};\n    }\n}\n\n/**\n * This class abstracts the rendering of a collection of geometries to screen.\n */\nclass GLFbo {\n    colorTextureResizeEventId = -1;\n    __gl;\n    __colorTexture;\n    __createDepthTexture;\n    __clearColor;\n    __depthTexture = null;\n    __fbo = null;\n    __prevBoundFbo = null;\n    /**\n     * Creates a GL Framebuffer Object\n     *\n     * @param gl - The Canvas 3D Context.\n     * @param colorTexture - Represents 2D Texture in GL.\n     * @param createDepthTexture - The createDepthTexture value.\n     */\n    constructor(gl, colorTexture, createDepthTexture = false) {\n        this.__gl = gl;\n        this.__colorTexture = colorTexture;\n        this.__createDepthTexture = createDepthTexture;\n        this.__clearColor = new Color(0, 0, 0, 0);\n        if (this.__colorTexture) {\n            this.colorTextureResizeEventId = this.__colorTexture.on('resized', () => {\n                console.warn('This code path will be deprecated. Instead, resize the GLFbo and it will resize the texture.');\n                this.resize(this.__colorTexture.width, this.__colorTexture.height, false);\n            });\n        }\n        this.setup();\n    }\n    /**\n     * Sets FBO clear color using RGBA array structure.\n     *\n     * @param clearColor - The clearColor value.\n     */\n    setClearColor(clearColor) {\n        this.__clearColor = clearColor;\n    }\n    /**\n     * Returns the `width` of the GL Texture\n     *\n     * @return - The return value.\n     */\n    getWidth() {\n        return this.__colorTexture.width;\n    }\n    /**\n     * Returns the `height` of the GL Texture\n     *\n     * @return - The return value.\n     */\n    getHeight() {\n        return this.__colorTexture.height;\n    }\n    /**\n     * Returns the `width`(Index 0) and the `height`(Index 1) of the GL Texture.\n     *\n     * @return - The return value.\n     */\n    getSize() {\n        return [this.__colorTexture.width, this.__colorTexture.height];\n    }\n    /**\n     * Returns the ColorTexture of the Fbo\n     *\n     * @return - The return value.\n     */\n    getColorTexture() {\n        return this.__colorTexture;\n    }\n    /**\n     * Returns the value of the deptTexture property.\n     *\n     * @return - The return value.\n     */\n    getDepthTextureGL() {\n        return this.__depthTexture;\n    }\n    /**\n     * Returns the `width` of the GL Texture\n     *\n     * @return - width of GLTexture\n     */\n    get width() {\n        return this.__colorTexture.width;\n    }\n    /**\n     * Returns the `height` of the GL Texture\n     *\n     * @return - height of GLTexture\n     */\n    get height() {\n        return this.__colorTexture.height;\n    }\n    /**\n     * Returns the [width, height] of the GL Texture.\n     *\n     * @return - returns [width, height] of the __colorTexture\n     */\n    get size() {\n        return [this.__colorTexture.width, this.__colorTexture.height];\n    }\n    /**\n     * Returns the ColorTexture of the Fbo\n     *\n     * @returns {GLTexture2D} - returns this.__colorTexture\n     */\n    get colorTexture() {\n        return this.__colorTexture;\n    }\n    /**\n     * Sets ColorTexture of the Fbo.\n     *\n     * @param colorTexture - The colorTexture value.\n     */\n    setColorTexture(colorTexture) {\n        const gl = this.__gl;\n        this.__colorTexture = colorTexture;\n        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.__colorTexture.glTex, 0);\n    }\n    /**\n     * Returns the value of the depthTexture property.\n     *\n     * @return\n     */\n    get depthTextureGL() {\n        return this.__depthTexture;\n    }\n    /**\n     * The setup method.\n     */\n    setup() {\n        const gl = this.__gl;\n        this.__fbo = gl.createFramebuffer();\n        gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, this.__fbo);\n        if (this.__colorTexture) {\n            gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.__colorTexture.glTex, 0);\n        }\n        // Create the depth texture\n        if (this.__createDepthTexture) {\n            this.createDepthTexture();\n        }\n        checkFramebuffer(gl, this.width, this.height);\n        gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);\n    }\n    createDepthTexture() {\n        const gl = this.__gl;\n        if (gl.name != 'webgl2' && !gl.__ext_WEBGL_depth_texture) {\n            // Create the depth buffer\n            const depthBuffer = gl.createRenderbuffer();\n            gl.bindRenderbuffer(gl.RENDERBUFFER, depthBuffer);\n            gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, this.width, this.height);\n            gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthBuffer);\n        }\n        else {\n            gl.activeTexture(gl.TEXTURE0);\n            this.__depthTexture = gl.createTexture();\n            gl.bindTexture(gl.TEXTURE_2D, this.__depthTexture);\n            // TODO: Copy params from the color image.\n            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);\n            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);\n            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n            // the proper texture format combination can be found here\n            // https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glTexImage2D.xhtml\n            // https://github.com/WebGLSamples/WebGL2Samples/blob/master/samples/fbo_rtt_depth_texture.html\n            // gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT16, this.width, this.height, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_SHORT, null);\n            gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT24, this.width, this.height, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_INT, null);\n            gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, this.__depthTexture, 0);\n        }\n    }\n    /**\n     * Triggered Automatically when the texture resizes.\n     *\n     * @todo: Fbos should manage the textures assigned to them.\n     * E.g. resizing and preserving data.\n     */\n    resize(width, height, resizeTexture = true) {\n        const gl = this.__gl;\n        gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n        gl.deleteFramebuffer(this.__fbo);\n        if (resizeTexture) {\n            this.__colorTexture.resize(width, height, false, false);\n        }\n        this.__fbo = gl.createFramebuffer();\n        gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, this.__fbo);\n        // The color texture is destoryed and re-created when it is resized,\n        // so we must re-bind it here.\n        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.__colorTexture.glTex, 0);\n        if (this.__depthTexture) {\n            gl.deleteTexture(this.__depthTexture);\n            this.createDepthTexture();\n        }\n        checkFramebuffer(gl, this.width, this.height);\n        gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);\n    }\n    /**\n     * Binds the Fbo to the canvas context, meaning that all WRITE operations will affect the current Fbo.\n     *\n     * @param renderstate - The renderstate value.\n     */\n    bindForWriting(renderstate) {\n        if (renderstate) {\n            this.__prevBoundFbo = renderstate.boundRendertarget;\n            renderstate.boundRendertarget = this.__fbo;\n        }\n        const gl = this.__gl;\n        gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, this.__fbo);\n        gl.viewport(0, 0, this.width, this.height); // Match the viewport to the texture size\n    }\n    /**\n     * Unbinds the Fbo to the canvas context for WRITE operations.\n     *\n     * @param renderstate - The renderstate value.\n     */\n    unbindForWriting(renderstate) {\n        if (renderstate)\n            renderstate.boundRendertarget = this.__prevBoundFbo;\n        const gl = this.__gl;\n        gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, this.__prevBoundFbo);\n    }\n    /**\n     * Binds the Fbo to the canvas context, meaning that all WRITE operations will affect the current Fbo.\n     *\n     * @param renderstate - The renderstate value.\n     */\n    bind(renderstate) {\n        this.bindForWriting(renderstate);\n    }\n    /**\n     * Unbinds the Fbo to the canvas context for WRITE operations.\n     *\n     * @param renderstate - The renderstate value.\n     */\n    unbind(renderstate) {\n        if (renderstate) {\n            // For write operations\n            this.unbindForWriting(renderstate);\n        }\n        else {\n            const gl = this.__gl;\n            gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n        }\n    }\n    /**\n     * Binds the Fbo to the canvas context, meaning that all READ operations will affect the current Fbo.\n     *\n     * @param renderstate - The renderstate value.\n     */\n    bindForReading(renderstate) {\n        const gl = this.__gl;\n        gl.bindFramebuffer(gl.READ_FRAMEBUFFER, this.__fbo);\n    }\n    /**\n     * Unbinds the Fbo to the canvas context for READ operations.\n     *\n     * @param renderstate - The renderstate value.\n     */\n    unbindForReading() {\n        const gl = this.__gl;\n        gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null);\n    }\n    /**\n     * Enables all color components of the rendering context of the Fbo,\n     * specifying the default color values when clearing color buffers and clears the buffers to preset values.\n     */\n    clear() {\n        const gl = this.__gl;\n        gl.colorMask(true, true, true, true);\n        const col = this.__clearColor.asArray();\n        gl.clearColor(col[0], col[1], col[2], col[3]);\n        if (this.__createDepthTexture) {\n            gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);\n        }\n        else {\n            gl.clear(gl.COLOR_BUFFER_BIT);\n        }\n    }\n    /**\n     * Runs [`bind`](#bind) then [`clear`](#clear) methods.\n     * @param renderstate - The renderstate value.\n     */\n    bindAndClear(renderstate) {\n        this.bind(renderstate);\n        this.clear();\n    }\n    /**\n     * The destroy is called by the system to cause explicit resources cleanup.\n     * Users should never need to call this method directly.\n     */\n    destroy() {\n        const gl = this.__gl;\n        gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n        gl.deleteFramebuffer(this.__fbo);\n        this.__fbo = null;\n        this.__colorTexture.off('resized', this.colorTextureResizeEventId);\n    }\n}\nfunction checkFramebuffer(gl, width, height) {\n    let check;\n    check = gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER);\n    if (check !== gl.FRAMEBUFFER_COMPLETE) {\n        gl.bindTexture(gl.TEXTURE_2D, null);\n        gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);\n        console.warn('Error creating Fbo width:', width, ', height:', height);\n        switch (check) {\n            case gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT:\n                throw new Error('The attachment types are mismatched or not all framebuffer attachment points are framebuffer attachment complete.');\n            case gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:\n                throw new Error('There is no attachment.');\n            case gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS:\n                throw new Error('Height and width of the attachment are not the same.');\n            case gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS:\n                throw new Error('The format of the attachment is not supported or if depth and stencil attachments are not the same renderbuffer.');\n            case 36061: // gl.GL_FRAMEBUFFER_UNSUPPORTED:\n                throw new Error('The framebuffer is unsupported');\n            default:\n                throw new Error('Incomplete Frambuffer');\n        }\n    }\n}\n\n/** The GLRenderTarget is used to generate a WebGL Framebuffer and its associated textures.\n * It can be used to create a FrameBuffer, several color textures and an optional depth texture, all bound to the Framebuffer.\n *\n *\n * ```javascript\n *  const renderTarget = new GLRenderTarget(gl, {\n *    type: gl.FLOAT,\n *    format: gl.RGBA,\n *    minFilter: gl.NEAREST,\n *    magFilter: gl.NEAREST,\n *    width: 128,\n *    height: 64,\n *    depthType: gl.FLOAT,\n *    depthFormat: gl.DEPTH_COMPONENT,\n *    depthInternalFormat: gl.DEPTH_COMPONENT32F,\n *  })\n * ```\n */\nclass GLRenderTarget extends EventEmitter {\n    gl;\n    textureTargets;\n    depthTexture;\n    frameBuffer;\n    textureDesc;\n    type;\n    format;\n    internalFormat;\n    depthFormat;\n    depthInternalFormat;\n    depthType;\n    minFilter;\n    magFilter;\n    wrapS = 0;\n    wrapT = 0;\n    width = 0;\n    height = 0;\n    clearColor;\n    colorMask;\n    textureType;\n    prevBoundFbo;\n    /**\n     * Create a GL render target.\n     * @param gl - The webgl rendering context.\n     * @param params - The params value.\n     */\n    constructor(gl, params) {\n        super();\n        this.gl = gl;\n        this.textureTargets = [];\n        this.depthTexture = null;\n        this.textureDesc = [0, 0, 0, 0];\n        this.clearColor = new Color(0, 0, 0, 0);\n        this.colorMask = [true, true, true, true];\n        if (params) {\n            this.configure(params);\n        }\n    }\n    /**\n     * The configure method.\n     * @param params - The params param.\n     */\n    configure(params) {\n        const gl = this.gl;\n        {\n            const p = processTextureParams(gl, params); // TODO: review\n            this.type = p.type;\n            this.format = p.format;\n            this.internalFormat = p.internalFormat;\n            this.depthType = p.depthType;\n            this.depthFormat = p.depthFormat;\n            this.depthInternalFormat = p.depthInternalFormat;\n            this.minFilter = p.minFilter ? p.minFilter : p.filter;\n            this.magFilter = p.magFilter ? p.magFilter : p.filter;\n            this.wrapS = p.wrapS;\n            this.wrapT = p.wrapT;\n            this.width = p.width;\n            this.height = p.height;\n        }\n        this.textureType = 1; // Default 2d 8 bit texture image texture.\n        this.textureDesc[0] = this.width;\n        this.textureDesc[1] = this.height;\n        this.textureTargets.forEach((colorTexture) => {\n            gl.deleteTexture(colorTexture);\n        });\n        this.textureTargets = [];\n        if (this.depthTexture) {\n            gl.deleteTexture(this.depthTexture);\n            this.depthTexture = null;\n        }\n        if (this.frameBuffer) {\n            gl.deleteFramebuffer(this.frameBuffer);\n        }\n        // -- Initialize texture targets\n        const numColorChannels = params.numColorChannels != undefined ? params.numColorChannels : this.format != undefined ? 1 : 0;\n        for (let i = 0; i < numColorChannels; i++) {\n            gl.activeTexture(gl.TEXTURE0 + 1);\n            const colorTexture = gl.createTexture();\n            gl.bindTexture(gl.TEXTURE_2D, colorTexture);\n            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, this.wrapS);\n            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, this.wrapT);\n            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, this.minFilter);\n            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, this.magFilter);\n            gl.texImage2D(gl.TEXTURE_2D, 0, this.internalFormat, this.width, this.height, 0, this.format, this.type, null);\n            this.textureTargets.push(colorTexture);\n        }\n        if (this.depthFormat) {\n            if (gl.name == 'webgl' && !gl.__ext_WEBGL_depth_texture)\n                throw new Error('Depth textures not support on this device');\n            // -- Initialize depth texture\n            gl.activeTexture(gl.TEXTURE0);\n            this.depthTexture = gl.createTexture();\n            gl.bindTexture(gl.TEXTURE_2D, this.depthTexture);\n            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, this.wrapS);\n            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, this.wrapT);\n            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, this.minFilter);\n            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, this.magFilter);\n            // the proper texture format combination can be found here\n            // https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glTexImage2D.xhtml\n            gl.texImage2D(gl.TEXTURE_2D, 0, this.depthInternalFormat, this.width, this.height, 0, this.depthFormat, this.depthType, null);\n        }\n        // -- Initialize frame buffer\n        this.frameBuffer = gl.createFramebuffer();\n        this.bindForWriting();\n        if (this.textureTargets.length > 0) {\n            if (this.textureTargets.length > 1) {\n                if (gl.name == 'webgl' && !gl.drawBuffers) ;\n            }\n            const bufferIds = [];\n            for (let i = 0; i < this.textureTargets.length; i++) {\n                gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + i, gl.TEXTURE_2D, this.textureTargets[i], 0);\n                bufferIds.push(gl.COLOR_ATTACHMENT0 + i);\n            }\n            if (this.textureTargets.length > 1) {\n                gl.drawBuffers(bufferIds);\n            }\n        }\n        if (this.depthTexture) {\n            gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, this.depthTexture, 0);\n        }\n        this.checkFramebuffer();\n    }\n    /**\n     * The checkFramebuffer method.\n     */\n    checkFramebuffer() {\n        this.bindForWriting(); // TODO\n        const gl = this.gl;\n        const status = gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER);\n        if (status != gl.FRAMEBUFFER_COMPLETE) {\n            switch (status) {\n                case gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT:\n                    throw new Error('The attachment types are mismatched or not all framebuffer attachment points are framebuffer attachment complete.');\n                case gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:\n                    throw new Error('There is no attachment.');\n                case gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS:\n                    throw new Error('Height and width of the attachment are not the same.');\n                case gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS:\n                    throw new Error('The format of the attachment is not supported or if depth and stencil attachments are not the same renderbuffer.');\n                case 36061: // gl.GL_FRAMEBUFFER_UNSUPPORTED:\n                    throw new Error('The framebuffer is unsupported');\n                default:\n                    throw new Error('Incomplete Frambuffer');\n            }\n        }\n        this.unbindForWriting();\n    }\n    /**\n     * The bindForWriting method.\n     * @param renderstate - The object tracking the current state of the renderer\n     * @param clear - The clear value.\n     */\n    bindForWriting(renderstate, clear = false) {\n        if (renderstate) {\n            this.prevBoundFbo = renderstate.boundRendertarget;\n            renderstate.boundRendertarget = this.frameBuffer;\n        }\n        const gl = this.gl;\n        gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, this.frameBuffer);\n        gl.viewport(0, 0, this.width, this.height); // Match the viewport to the texture size\n        if (clear)\n            this.clear();\n    }\n    /**\n     * The unbindForWriting method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    unbindForWriting(renderstate) {\n        if (renderstate)\n            renderstate.boundRendertarget = this.prevBoundFbo;\n        const gl = this.gl;\n        gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, this.prevBoundFbo);\n        this.prevBoundFbo = null;\n    }\n    /**\n     * The clear method.\n     * @param clearDepth - The clearDepth value.\n     */\n    clear(clearDepth = true) {\n        const gl = this.gl;\n        const colMask = this.colorMask;\n        gl.colorMask(colMask[0], colMask[1], colMask[2], colMask[3]);\n        const clearCol = this.clearColor.asArray();\n        gl.clearColor(clearCol[0], clearCol[1], clearCol[2], clearCol[3]);\n        let flags = 0;\n        if (this.textureTargets.length > 0)\n            flags |= gl.COLOR_BUFFER_BIT;\n        if (this.depthTexture)\n            flags |= gl.DEPTH_BUFFER_BIT;\n        gl.clear(flags);\n    }\n    /**\n     * Binds the render target in preparation for 'readPixels' calls to pull data back to main memory.\n     */\n    bindForReading() {\n        const gl = this.gl;\n        gl.bindFramebuffer(gl.READ_FRAMEBUFFER, this.frameBuffer);\n    }\n    /**\n     * The unbindForReading method.\n     */\n    unbindForReading() {\n        const gl = this.gl;\n        gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null);\n    }\n    /**\n     * The bindColorTexture method.\n     * @param renderstate - The object tracking the current state of the renderer\n     * @param channelId - The channelId value.\n     * @return - The return value.\n     */\n    bindColorTexture(renderstate, unif, channelId = 0) {\n        const gl = this.gl;\n        const unit = renderstate.boundTextures++;\n        gl.uniform1i(unif.location, unit);\n        gl.activeTexture(gl.TEXTURE0 + unit);\n        gl.bindTexture(gl.TEXTURE_2D, this.textureTargets[channelId]);\n        return true;\n    }\n    /**\n     * The bindDepthTexture method.\n     * @param renderstate - The object tracking the current state of the renderer\n     * @param unif - The WebGL uniform\n     * @return - The return value.\n     */\n    bindDepthTexture(renderstate, unif) {\n        const gl = this.gl;\n        const unit = renderstate.boundTextures++;\n        gl.uniform1i(unif.location, unit);\n        gl.activeTexture(gl.TEXTURE0 + unit);\n        gl.bindTexture(gl.TEXTURE_2D, this.depthTexture);\n        return true;\n    }\n    /**\n     * The unbind method.\n     */\n    unbind(renderstate) {\n        this.unbindForWriting(renderstate);\n    }\n    /**\n     * The resize method.\n     * @param width - The width value.\n     * @param height - The height value.\n     * @param preserveData - The preserveData value.\n     */\n    resize(width, height, preserveData = false) {\n        const gl = this.gl;\n        const sizeChanged = this.width != width || this.height != height;\n        if (sizeChanged) {\n            const maxSize = gl.getParameter(gl.MAX_TEXTURE_SIZE);\n            if (width < 0 || width > maxSize || height < 0 || height > maxSize) {\n                throw new Error(`GLRenderTarget: Invalid texture size. width: ${width} height: ${height} maxSize: ${maxSize}`);\n            }\n            if (preserveData) {\n                this.bindForReading();\n            }\n            for (let i = 0; i < this.textureTargets.length; i++) {\n                const colorTexture = gl.createTexture();\n                gl.bindTexture(gl.TEXTURE_2D, colorTexture);\n                gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, this.wrapS);\n                gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, this.wrapT);\n                gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, this.minFilter);\n                gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, this.magFilter);\n                gl.texImage2D(gl.TEXTURE_2D, 0, this.internalFormat, width, height, 0, this.format, this.type, null);\n                if (preserveData) {\n                    // see: http://jsfiddle.net/greggman/rs21sr46\n                    gl.copyTexImage2D(gl.TEXTURE_2D, 0, this.internalFormat, 0, 0, Math.min(width, this.width), Math.min(height, this.height), 0);\n                }\n                gl.deleteTexture(this.textureTargets[i]);\n                this.textureTargets[i] = colorTexture;\n            }\n            if (this.depthFormat) {\n                if (gl.name == 'webgl' && !gl.__ext_WEBGL_depth_texture)\n                    throw new Error('Depth textures not support on this device');\n                // -- Initialize depth texture\n                gl.activeTexture(gl.TEXTURE0);\n                const depthTexture = gl.createTexture();\n                gl.bindTexture(gl.TEXTURE_2D, depthTexture);\n                gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, this.wrapS);\n                gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, this.wrapT);\n                gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, this.minFilter);\n                gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, this.magFilter);\n                // the proper texture format combination can be found here\n                // https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glTexImage2D.xhtml\n                gl.texImage2D(gl.TEXTURE_2D, 0, this.depthInternalFormat, width, height, 0, this.depthFormat, this.depthType, null);\n                if (preserveData) {\n                    // see: http://jsfiddle.net/greggman/rs21sr46\n                    gl.copyTexImage2D(gl.TEXTURE_2D, 0, this.internalFormat, 0, 0, Math.min(width, this.width), Math.min(height, this.height), 0);\n                }\n                gl.deleteTexture(this.depthTexture);\n                this.depthTexture = depthTexture;\n            }\n            if (preserveData) {\n                this.unbindForReading();\n            }\n            this.width = width;\n            this.height = height;\n            // -- Initialize frame buffer\n            if (this.frameBuffer) {\n                // Note: avoid re-using the framebuffer.\n                // see here: https://gamedev.stackexchange.com/questions/91991/resizing-a-framebuffer-object-ie-its-attachments-on-screen-resize\n                gl.deleteFramebuffer(this.frameBuffer);\n            }\n            this.frameBuffer = gl.createFramebuffer();\n            this.bindForWriting();\n            if (this.textureTargets.length > 0) {\n                if (this.textureTargets.length > 1) {\n                    if (gl.name == 'webgl' && !gl.drawBuffers) ;\n                }\n                const bufferIds = [];\n                for (let i = 0; i < this.textureTargets.length; i++) {\n                    gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + i, gl.TEXTURE_2D, this.textureTargets[i], 0);\n                    bufferIds.push(gl.COLOR_ATTACHMENT0 + i);\n                }\n                if (this.textureTargets.length > 1) {\n                    gl.drawBuffers(bufferIds);\n                }\n            }\n            if (this.depthTexture) {\n                gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, this.depthTexture, 0);\n            }\n            this.checkFramebuffer();\n        }\n    }\n    /**\n     * The bindToUniform method.\n     * @param renderstate - The renderstate param.\n     * @param unif - The WebGL uniform\n     * @param bindings - The bindings param.\n     * @return - The return value.\n     */\n    bindToUniform(renderstate, unif, bindings) {\n        // if (!this.__loaded) {\n        //   return false\n        // }\n        // if (!this.gltex) {\n        //   throw new Error('Unable to bind non-initialized or deleted texture.')\n        // }\n        const unit = renderstate.boundTextures++;\n        const texId = this.gl.TEXTURE0 + unit;\n        const gl = this.gl;\n        gl.activeTexture(texId);\n        gl.bindTexture(gl.TEXTURE_2D, this.textureTargets[0]);\n        gl.uniform1i(unif.location, unit);\n        if (bindings) {\n            if (bindings.textureTypeUnif) {\n                gl.uniform1i(bindings.textureTypeUnif.location, this.textureType);\n            }\n            if (bindings.textureDescUnif) {\n                this.gl.uniform4fv(bindings.textureDescUnif.location, this.textureDesc);\n            }\n        }\n        return true;\n    }\n    /**\n     * The destroy is called by the system to cause explicit resources cleanup.\n     * Users should never need to call this method directly.\n     */\n    destroy() {\n        const gl = this.gl;\n        this.textureTargets.forEach((colorTexture) => {\n            gl.deleteTexture(colorTexture);\n        });\n        this.textureTargets = [];\n        if (this.depthTexture) {\n            gl.deleteTexture(this.depthTexture);\n            this.depthTexture = null;\n        }\n        if (this.frameBuffer) {\n            gl.deleteFramebuffer(this.frameBuffer);\n        }\n    }\n}\n\nvar computeViewNormal = \"#define GLSLIFY 1\\n  \\n#ifdef ENABLE_ES3\\nvec3 computeViewNormal(vec3 viewPos) {\\n  vec3 fdx = dFdx(viewPos);\\n  vec3 fdy = dFdy(viewPos);\\n  return normalize(cross(fdx, fdy));\\n}\\n#else \\nvec3 computeViewNormal(vec3 viewPos) {\\n  return vec3(0.0, 0.0, 0.0);\\n}\\n#endif\\n\"; // eslint-disable-line\n\nvar calcFatLinesViewPos = \"#define GLSLIFY 1\\nimport 'GLSLUtils.glsl'\\nvec3 calcFatLinesViewPos(int vertexID, mat4 modelViewMatrix, inout vec3 viewNormal, inout vec2 texCoord, inout vec3 pos) {\\n\\n  int seqentialIndex_0 = int(mod(segmentIndices.x, 2.));\\n  int seqentialIndex_1 = int(mod(segmentIndices.y, 2.));\\n  int index_0 = int(segmentIndices.x) / 2;\\n  int index_1 = int(segmentIndices.y) / 2;\\n\\n  vec3 viewPos;\\n  vec4 data_0 = fetchTexel(positionsTexture, positionsTextureSize, index_0);\\n  vec4 data_1 = fetchTexel(positionsTexture, positionsTextureSize, index_1);\\n\\n  // During XR sessions, there is a scaling applied to the view matrix\\n  // which causes a distortion to the line width. We extract that scale here\\n  // and use to correct the distortion.\\n  // See also: FatPointsShader\\n  vec3 viewZ = modelViewMatrix[2].xyz;\\n  float viewScale = length(viewZ);\\n\\n  vec4 pos_0 = modelViewMatrix * vec4(data_0.xyz, 1.0);\\n  vec4 pos_1 = modelViewMatrix * vec4(data_1.xyz, 1.0);\\n  // Note: multiply the per-vertex line thickness with the line thickness uniform value;\\n  float lineThickness_0 = LineThickness * data_0.w * viewScale;\\n  float lineThickness_1 = LineThickness * data_1.w * viewScale;\\n\\n  if (vertexID < 2) {\\n    pos = data_0.xyz;\\n    viewPos = pos_0.xyz;\\n  }\\n  else {\\n    pos = data_1.xyz;\\n    viewPos = pos_1.xyz;\\n  }\\n  if (pos_1 != pos_0) {\\n    vec3 segmentDir = normalize(pos_1.xyz - pos_0.xyz);\\n    vec3 viewVector = normalize(viewPos);\\n\\n    if (vertexID < 2) {\\n      vec3 segmentStartDir = segmentDir;\\n      if (seqentialIndex_0 != 0) {\\n        //if index_0 == 0, get the last index in the line as previous\\n        int index_prev = (index_0 > 0) ? (index_0-1) : (positionsTextureSize-1);\\n        vec4 data_prev = fetchTexel(positionsTexture, positionsTextureSize, index_prev);\\n        vec4 pos_prev = modelViewMatrix * vec4(data_prev.xyz, 1.0);\\n        segmentStartDir = normalize(segmentDir + normalize(pos_0.xyz - pos_prev.xyz));\\n        // segmentStartDir = segmentDir;\\n      }\\n      // vec3 startBiTangent = normalize(cross(segmentStartDir, viewVector));\\n      // viewNormal = normalize(cross(segmentStartDir, startBiTangent));\\n      vec3 startBiTangent = normalize(vec3(-segmentStartDir.y, segmentStartDir.x, 0.0));\\n      viewNormal = normalize(-viewVector);\\n      // Move the endpoints to overlap a bit more.\\n      //viewPos -= vec3(segmentStartDir * lineThickness_0 * 0.25);\\n      if (mod(vertexIDs, 2.0) == 0.0) {\\n        viewPos += vec3(startBiTangent * lineThickness_0);\\n        texCoord.x = 1.0;\\n      }\\n      else {\\n        viewPos -= vec3(startBiTangent * lineThickness_0);\\n        texCoord.x = 0.0;\\n      }\\n      texCoord.y = 0.0;\\n    }\\n    else {\\n      vec3 segmentEndDir = segmentDir;\\n      if (seqentialIndex_1 != 0) {\\n        //if index_1 == numPoints-1, get the first index in the line as next\\n        int index_next = (index_1 < (positionsTextureSize-1)) ? (index_1+1) : 0;\\n        vec4 data_next = fetchTexel(positionsTexture, positionsTextureSize, index_next);\\n        vec4 pos_next = modelViewMatrix * vec4(data_next.xyz, 1.0);\\n        segmentEndDir = normalize(segmentDir + normalize(pos_next.xyz - pos_1.xyz));\\n        // segmentEndDir = segmentDir;\\n      }\\n      // vec3 endBiTangent = normalize(cross(segmentEndDir, viewVector));\\n      // viewNormal = normalize(cross(segmentEndDir, endBiTangent));\\n      vec3 endBiTangent = normalize(vec3(-segmentEndDir.y, segmentEndDir.x, 0.0));\\n      viewNormal = normalize(-viewVector);\\n      // Move the endpoints to overlap a bit more.\\n      //viewPos += vec3(segmentEndDir * lineThickness_1 * 0.25);\\n      if (mod(vertexIDs, 2.0) == 0.0) {\\n        viewPos += vec3(endBiTangent * lineThickness_1);\\n        texCoord.x = 1.0;\\n      }\\n      else {\\n        viewPos -= vec3(endBiTangent * lineThickness_1);\\n        texCoord.x = 0.0;\\n      }\\n      texCoord.y = 1.0;\\n    }\\n\\n    // Move the line towards the viewer by the line thickness.\\n    // this is to avoid depth issues when lines are rendered over meshes. \\n    viewPos.z += (lineThickness_0 + lineThickness_1) * 0.5;\\n  }\\n\\n  return viewPos;\\n}\\n\\n\"; // eslint-disable-line\n\nvar constants = \"#define GLSLIFY 1\\n#define PI 3.141592653589793\\n#define TwoPI (2.0 * PI)\\n#define HalfPI (0.5 * PI)\\n\\n\"; // eslint-disable-line\n\nvar convolveHelpers = \"#define GLSLIFY 1\\n\\n#ifdef ENVMAP_CUBE\\n\\nuniform samplerCube envMap;\\n\\nvec4 sampleEnvMap(vec3 dir) {\\n  return texture(envMap, dir);\\n}\\n\\n#else \\n\\nuniform sampler2D   envMap;\\n\\nimport 'envmap-octahedral.glsl'\\n\\nvec4 sampleEnvMap(vec3 dir) {\\n  vec2 uv = dirToSphOctUv(dir);\\n  vec4 texel = texture2D(envMap, vec2(uv.x, 1.0 - uv.y));\\n  return vec4(texel.rgb/texel.a, 1.0); // TODO: Check this line. Do we need it?\\n}\\n\\n#endif \\n\\nvec3 cubeFaceUvToDir(float u, float v, int faceId) {\\n\\n  // normalize into [-1, 1] range\\n  float n_u = 2.0 * u - 1.0;\\n  float n_v = 2.0 * v - 1.0;\\n\\n  vec3 dir;\\n  switch (faceId)\\n  {\\n  case 0: //TEXTURE_CUBE_MAP_POSITIVE_X:\\n    dir.x = 1.0f;\\n    dir.y = n_v;\\n    dir.z = -n_u;\\n    break;\\n  case 1: //TEXTURE_CUBE_MAP_NEGATIVE_X:\\n    dir.x = -1.0f;\\n    dir.y = n_v;\\n    dir.z = n_u;\\n    break;\\n  case 3: //TEXTURE_CUBE_MAP_POSITIVE_Y:\\n    dir.x = n_u;\\n    dir.y = 1.0f;\\n    dir.z = -n_v;\\n    break;\\n  case 2: //TEXTURE_CUBE_MAP_NEGATIVE_Y:\\n    dir.x = n_u;\\n    dir.y = -1.0f;\\n    dir.z = n_v;\\n    break;\\n  case 4: //TEXTURE_CUBE_MAP_POSITIVE_Z:\\n    dir.x = n_u;\\n    dir.y = n_v;\\n    dir.z = 1.0f;\\n    break;\\n  case 5: //TEXTURE_CUBE_MAP_NEGATIVE_Z:\\n    dir.x = -n_u;\\n    dir.y = n_v;\\n    dir.z = -1.0f;\\n    break;\\n  }\\n  return normalize(dir);\\n}\\n\\n\"; // eslint-disable-line\n\nvar cutaways = \"#define GLSLIFY 1\\nuniform color cutColor;\\n\\n#ifdef ENABLE_FLOAT_TEXTURES\\n  vec4 getCutaway(int id) {\\n    return fetchTexel(instancesTexture, instancesTextureSize, (id * pixelsPerItem) + 5);\\n  }\\n\\n#else\\n\\n  uniform vec4 cutawayData;\\n\\n  vec4 getCutaway(int id) {\\n    return cutawayData;\\n  }\\n\\n#endif\\n\\n#define RAY_EPS 0.0000001\\nstruct Ray {\\n  vec3 start;\\n  vec3 dir;\\n};\\n\\nfloat intersectRayPlane(Ray ray, Ray plane) {\\n  vec3 w = ray.start - plane.start;\\n  float D = dot(plane.dir, ray.dir);\\n  float N = dot(-plane.dir, w);\\n\\n  if (abs(D) < RAY_EPS) {\\n    // segment is parallel to plane\\n    if (N == 0.0)\\n      return -1.0; // segment lies in plane\\n    else\\n      return -1.0; // no intersection\\n  }\\n  // they are not parallel\\n  // compute intersect param\\n  float sI = N / D;\\n  if (sI < -RAY_EPS) {\\n    return -1.0; // no intersection\\n  }\\n  return sI;\\n}\\n\\nbool cutaway(vec3 worldPos, vec3 planeNormal, float planeDist) {\\n\\n  vec3 planePos = planeNormal * planeDist;\\n  vec3 planeDir = worldPos + planePos;\\n  float planeOffset = dot(planeDir, planeNormal);\\n  if (planeOffset > 0.0) {\\n    return true;\\n  }\\n  return false;\\n}\\n\"; // eslint-disable-line\n\nvar debugColors = \"#define GLSLIFY 1\\nimport 'GLSLUtils.glsl'\\n\\nvec3 getDebugColor(float id) {\\n  int sel = int(round(mod(round(id), 16.0)));\\n  \\n  if (sel==0)\\n    return vec3(0.0, 1.0, 1.0);\\n  else if (sel==1)\\n    return vec3(0.0, 1.0, 0.0);\\n  else if (sel==2)\\n    return vec3(1.0, 0.0, 1.0);\\n  else if (sel==3)\\n    return vec3(0.75, 0.75, 0.0);\\n  else if (sel==4)\\n    return vec3(0.0, 0.75, 0.75);\\n  else if (sel==5)\\n    return vec3(0.75, 0.0, 0.75);\\n  else if (sel==6)\\n    return vec3(0.45, 0.95, 0.0);\\n  else if (sel==7)\\n    return vec3(0.0, 0.45, 0.95);\\n  else if (sel==8)\\n    return vec3(0.95, 0.0, 0.45);\\n  else if (sel==9)\\n    return vec3(0.95, 0.45, 0.0);\\n  else if (sel==10)\\n    return vec3(0.0, 0.95, 0.45);\\n  else if (sel==11)\\n    return vec3(0.45, 0.0, 0.95);\\n  else if (sel==12)\\n    return vec3(0.45, 0.45, 0.95);\\n  else if (sel==13)\\n    return vec3(0.0, 0.0, 0.45);\\n  else if (sel==14)\\n    return vec3(0.0, 0.45, 0.45);\\n  else if (sel==15)\\n    return vec3(0.45, 0.0, 0.45);\\n  else return vec3(0.2, 0.2, 0.2);\\n}\\n\\n\"; // eslint-disable-line\n\nvar geomItemId = \"#define GLSLIFY 1\\n\\n#ifdef ENABLE_MULTI_DRAW\\n\\n// On some mobile GPUs the sampler2D defaults to lowp, which implies a maximum\\n// resolution of 255. This caused rendering artifacts on larger scenes on mobile\\n// devices.\\nuniform highp sampler2D drawIdsTexture;\\n\\n#ifdef EMULATE_MULTI_DRAW\\nuniform int drawId;\\n#endif // EMULATE_MULTI_DRAW\\n\\nint getGeomItemId() {\\n#ifndef EMULATE_MULTI_DRAW\\n  int drawId = gl_DrawID;\\n#endif // EMULATE_MULTI_DRAW\\n\\n  ivec2 texSize = textureSize(drawIdsTexture, 0);\\n  ivec2 texelCoords = ivec2(drawId % texSize.x, drawId / texSize.x);\\n  return int(texelFetch(drawIdsTexture, texelCoords, 0).r + 0.5);\\n}\\n\\nvec4 getDrawItemIds() {\\n#ifndef EMULATE_MULTI_DRAW\\n  int drawId = gl_DrawID;\\n#endif // EMULATE_MULTI_DRAW\\n\\n  ivec2 texSize = textureSize(drawIdsTexture, 0);\\n  ivec2 texelCoords = ivec2(drawId % texSize.x, drawId / texSize.x);\\n  vec4 color = texelFetch(drawIdsTexture, texelCoords, 0);\\n  // Note: A 0 value in the texture means no sub-geom index is being rendered.\\n  // subtract off 1 to get the true sub-geom index.\\n  return vec4(color.r, color.g - 1.0, color.b, color.a);\\n}\\n\\n#else // ENABLE_MULTI_DRAW\\n\\nuniform int geomItemId;\\n\\nattribute float instancedIds;    // instanced attribute..\\nuniform int instancedDraw;\\n\\nint getGeomItemId() {\\n  if (instancedDraw == 0) {\\n    return geomItemId;\\n  }\\n  else {\\n    return int(instancedIds);\\n  }\\n}\\n\\nvec4 getDrawItemIds() {\\n  if (instancedDraw == 0) {\\n    return vec4(float(geomItemId), 0.0, -1.0, -1.0);\\n  }\\n  else {\\n    return vec4(float(instancedIds), 0.0, -1.0, -1.0);\\n  }\\n}\\n\\n#endif // ENABLE_MULTI_DRAW\\n\\n// For backwards compatibility with older plugins (UX.HandleShader)\\nint getDrawItemId() {\\n  return getGeomItemId();\\n}\\n\"; // eslint-disable-line\n\nvar geomItemFlags = \"#define GLSLIFY 1\\nconst int GEOMITEM_FLAG_CUTAWAY = 2; // 1<<1;\\nconst int GEOMITEM_INVISIBLE_IN_GEOMDATA = 4; // 1<<2;\\nconst int GEOMITEM_TRANSPARENT = 8; // 1<<3;\\nconst int GEOMITEM_PLACEHOLDER = 16; // 1<<4;\\nconst int GEOMITEM_MASK = 32; // 1<<5;\\n\"; // eslint-disable-line\n\nvar geomType = \"#define GLSLIFY 1\\n\\nconst int TRIANGLES = 0;\\nconst int LINES = 1;\\nconst int POINTS = 2;\"; // eslint-disable-line\n\nvar geometryMask = \"#define GLSLIFY 1\\nuniform sampler2D frontDepthTexture;\\nuniform sampler2D backDepthTexture;\\n\\nuniform vec2 depthRange;\\nuniform vec2 viewportSize;\\n\\nbool testGeometryMask(vec3 viewPos) {\\n  float depth = gl_FragCoord.z;\\n  vec2 texCoord = gl_FragCoord.xy / viewportSize;\\n  float front = texture2D(frontDepthTexture, texCoord).r;\\n  float back = texture2D(backDepthTexture, texCoord).r;\\n\\n  return depth < front || depth > back;\\n}\\n\"; // eslint-disable-line\n\nvar drawItemTexture = \"#define GLSLIFY 1\\nimport 'GLSLUtils.glsl'\\n\\n// The texture populated by the GLGeomItemLibrary\\nuniform sampler2D instancesTexture;\\nuniform highp int instancesTextureSize;\\n\\n// See also: src\\\\Renderer\\\\GLSLConstants.js\\nconst int pixelsPerItem = 8;\\n\\nvec4 getInstanceData(int id) {\\n  return fetchTexel(instancesTexture, instancesTextureSize, (id * pixelsPerItem) + 0);\\n}\\n\\n\"; // eslint-disable-line\n\nvar envmapDualfisheye = \"#define GLSLIFY 1\\n\\nvec2 dualfisheyeUVsFromDir(vec3 dir) {\\n  vec2 result;\\n  float angle = 0.465;\\n  if (dir.x < 0.0) {\\n    result = vec2(((dir.z * -angle) + 0.5) * 0.5, (dir.y * angle) + 0.5);\\n  }\\n  else {\\n    result = vec2( 0.5 + ((dir.z * angle) + 0.5) * 0.5, (dir.y * angle) + 0.5);\\n  }\\n  return result;\\n}\\n\\n\"; // eslint-disable-line\n\nvar envmapEquirect = \"#define GLSLIFY 1 \\nimport 'constants.glsl'\\n\\nvec2 latLongUVsFromDir(vec3 dir) {\\n  // Math function taken from...\\n  // http://gl.ict.usc.edu/Data/HighResProbes/\\n  // Note: Scaling from u=[0,2], v=[0,1] to u=[0,1], v=[0,1]\\n  float phi = acos(dir.z);\\n  float theta = atan(dir.x, dir.y);\\n  return vec2((1.0 + theta / PI) / 2.0, phi / PI);\\n}\\n\\n// Note: when u == 0.5 z = 1.0\\nvec3 dirFromLatLongUVs(float u, float v) {\\n  // http://gl.ict.usc.edu/Data/HighResProbes/\\n  float theta = PI*((u * 2.0) - 1.0);\\n  float phi = PI*v;\\n  return vec3(sin(phi)*sin(theta), sin(phi)*cos(theta), cos(phi));\\n}\\n\\nvec3 dirFromPolar(vec2 polar) {\\n  float u = polar.x / (PI * 2.0);\\n  float v = polar.y / PI;\\n  return dirFromLatLongUVs(u, v);\\n}\\n\\n\"; // eslint-disable-line\n\nvar envmapOctahedral = \"#define GLSLIFY 1\\nimport 'constants.glsl'\\nimport 'GLSLUtils.glsl'\\n#define sectorize(value) step(0.0, (value))*2.0-1.0\\n#define sum(value) dot(clamp((value), 1.0, 1.0), (value))\\n\\nvec2 dirToSphOctUv(vec3 normal) {\\n  normal = normalize(normal);\\n  vec3 aNorm = abs(normal);\\n  vec3 sNorm = sectorize(normal);\\n  \\n  vec2 dir = aNorm.xy;\\n  float orient = atan(dir.x, max(dir.y,0.0000000000000001))/HalfPI;\\n\\n  dir = vec2(aNorm.z, length(aNorm.xy));\\n  float pitch = atan(dir.y, dir.x)/HalfPI;\\n\\n  vec2 uv = vec2(sNorm.x*orient, sNorm.y*(1.0-orient))*pitch;\\n\\n  if (normal.z < 0.0) {\\n    uv = sNorm.xy - abs(uv.ts)*sNorm.xy;\\n  }\\n  vec2 res = uv*0.5+0.5;\\n  // Flip-v\\n  // return res;\\n  return vec2(res.x, 1.0 - res.y);\\n}\\n\\nvec3 sphOctUvToDir(vec2 uv) {\\n  uv = uv*2.0-1.0;\\n  // Flip-v\\n  uv.y = -uv.y;\\n  vec2 suv = sectorize(uv);\\n  float sabsuv = sum(abs(uv));\\n  float pitch = sabsuv*HalfPI;\\n\\n  if (pitch <= 0.0) {\\n    return vec3(0.0, 0.0, 1.0);\\n  }\\n  if (abs(pitch - PI) < 0.000001) {\\n    return vec3(0.0, 0.0, -1.0);\\n  }\\n  if (sabsuv > 1.0) {\\n    uv = (1.0-abs(uv.ts))*suv;\\n  }\\n\\n  float orient = (abs(uv.s)/sabsuv)*HalfPI;\\n  float sOrient = sin(orient);\\n  float cOrient = cos(orient);\\n  float sPitch = sin(pitch);\\n  float cPitch = cos(pitch);\\n\\n  return vec3(\\n    sOrient*suv.s*sPitch,\\n    cOrient*suv.t*sPitch,\\n    cPitch\\n  );\\n}\\n\\n\"; // eslint-disable-line\n\nvar GLSLBits = \"#define GLSLIFY 1\\n    \\n/////////////////////////////////////////////////////////////////\\n// http://concord-consortium.github.io/lab/experiments/webgl-gpgpu/script.js\\nfloat shift_right(float v, float amt) {\\n  v = floor(v) + 0.5;\\n  return floor(v / exp2(amt));\\n}\\nfloat shift_left(float v, float amt) {\\n  return floor(v * exp2(amt) + 0.5);\\n}\\n\\nfloat mask_last(float v, float bits) {\\n  return mod(v, shift_left(1.0, bits));\\n}\\nfloat extract_bits(float num, float from, float to) {\\n  from = floor(from + 0.5);\\n  to = floor(to + 0.5);\\n  return mask_last(shift_right(num, from), to - from);\\n}\\n\\n/////////////////////////////////////////////////////////////////\\n// https://stackoverflow.com/questions/18453302/how-do-you-pack-one-32bit-int-into-4-8bit-ints-in-glsl-webgl\\n\\nconst vec4 bitEnc = vec4(1.,255.,65025.,16581375.);\\nconst vec4 bitDec = 1./bitEnc;\\nvec4 EncodeFloatRGBA (float v) {\\n  vec4 enc = bitEnc * v;\\n  enc = fract(enc);\\n  enc -= enc.yzww * vec2(1./255., 0.).xxxy;\\n  return enc;\\n}\\nfloat DecodeFloatRGBA (vec4 v) {\\n  return dot(v, bitDec);\\n}\\n\\n/////////////////////////////////////////////////////////////////\\n// https://gist.github.com/Flexi23/1713774\\n// \\nvec2 encode16BitFloatInto2xUInt8(float v) {\\n  vec2 c = vec2(0.);\\n\\n  int signum = (v >= 0.) ? 128 : 0;\\n  v = abs(v);\\n  int exponent = 15;\\n  float limit = 1024.; // considering the bias from 2^-5 to 2^10 (==1024)\\n  for(int exp = 15; exp > 0; exp--) {\\n    if ( v < limit) {\\n      limit /= 2.;\\n      exponent--;\\n    }\\n  }\\n\\n  float rest;\\n  if (exponent == 0) {\\n    rest = v / limit / 2.;      // \\\"subnormalize\\\" implicite preceding 0. \\n  } \\n  else {\\n    rest = (v - limit)/limit;   // normalize accordingly to implicite preceding 1.\\n  }\\n\\n  int mantissa = int(rest * 2048.);   // 2048 = 2^11 for the (split) 11 bit mantissa\\n  int msb = mantissa / 256;           // the most significant 3 bits go into the lower part of the first byte\\n  int lsb = mantissa - msb * 256;     // there go the other 8 bit of the lower significance\\n\\n  c.x = float(signum + exponent * 8 + msb) / 255.;    // color normalization for texture2D\\n  c.y = float(lsb) / 255.;\\n\\n  if (v >= 2048.) {\\n    c.y = 1.;\\n  }\\n\\n  return c;\\n}\\n\\nfloat decode16BitFloatFrom2xUInt8(vec2 c) {\\n  float v = 0.;\\n\\n  int ix = int(c.x*255.); // 1st byte: 1 bit signum, 4 bits exponent, 3 bits mantissa (MSB)\\n  int iy = int(c.y*255.); // 2nd byte: 8 bit mantissa (LSB)\\n\\n  int s = (c.x >= 0.5) ? 1 : -1;\\n  ix = (s > 0) ? ix - 128 : ix;   // remove the signum bit from exponent\\n  int iexp = ix / 8;              // cut off the last 3 bits of the mantissa to select the 4 exponent bits\\n  int msb = ix - iexp * 8;        // subtract the exponent bits to select the 3 most significant bits of the mantissa\\n\\n  int norm = (iexp == 0) ? 0 : 2048;          // distinguish between normalized and subnormalized numbers\\n  int mantissa = norm + msb * 256 + iy;       // implicite preceding 1 or 0 added here\\n  norm = (iexp == 0) ? 1 : 0;                 // normalization toggle\\n  float exponent = pow( 2., float(iexp + norm) - 16.); // -5 for the the exponent bias from 2^-5 to 2^10 plus another -11 for the normalized 12 bit mantissa \\n  v = float( s * mantissa ) * exponent;\\n\\n  return v;\\n}\\n\\n// TODO : Encoding Float32 to 4x UInt8\\n// http://concord-consortium.github.io/lab/experiments/webgl-gpgpu/script.js\\n// http://ultraist.hatenablog.com/entry/20110608/1307539319\\n\\n\"; // eslint-disable-line\n\nvar GLSLUtils = \"#define GLSLIFY 1\\n\\nint ftoi(float val) {\\n  return int(floor(val + 0.5));\\n}\\nivec2 ftoi(vec2 v2) {\\n  return ivec2(ftoi(v2.x), ftoi(v2.y));\\n}\\nivec3 ftoi(vec3 v4) {\\n  return ivec3(ftoi(v4.x), ftoi(v4.y), ftoi(v4.z));\\n}\\nivec4 ftoi(vec4 v4) {\\n  return ivec4(ftoi(v4.x), ftoi(v4.y), ftoi(v4.z), ftoi(v4.w));\\n}\\n\\n#ifdef ENABLE_ES3\\n\\nint imod(int x, int y) {\\n  return x % y;\\n}\\n\\nvoid setFlag(inout int flags, int flag) {\\n  flags |= flag;\\n}\\n\\nvoid clearFlag(inout int flags, int flag) {\\n  flags &= ~flag;\\n}\\n\\nbool testFlag(int flags, int flag) {\\n  return (flags & flag) != 0;\\n}\\n\\n// private function: Mangle me...\\nivec2 _pixelIndexToUV(int index, int textureWidth) {\\n  return ivec2(index % textureWidth, index / textureWidth);\\n}\\n\\nvec4 fetchTexel(sampler2D texture, int textureWidth, int index) {\\n  return texelFetch(texture, _pixelIndexToUV(index, textureWidth), 0);\\n}\\n\\nvec4 fetchTexel(sampler2D texture, ivec2 textureSize, ivec2 texCoord) {\\n  return texelFetch(texture, texCoord, 0);\\n}\\n\\nvec4 fetchTexel(sampler2D texture, ivec2 textureSize, int index) {\\n    return texelFetch(texture, _pixelIndexToUV(index, textureSize.x), 0);\\n}\\n\\n#else\\n\\n// TODO: integrate: https://gist.github.com/mattatz/70b96f8c57d4ba1ad2cd\\n\\nint max(int a, int b) {\\n  return a > b ? a : b;\\n}\\nint min(int a, int b) {\\n  return a < b ? a : b;\\n}\\n\\nfloat round(float val) {\\n  return floor(val + 0.4);\\n}\\n\\nint imod(int x, int y) {\\n  return x-y*(x/y);\\n}\\n\\nvoid setFlag(inout int flags, int flag) {\\n  flags += flag;\\n}\\nvoid clearFlag(inout int flags, int flag) {\\n  flags -= flag;\\n}\\n\\nbool testFlag(int flags, int flag) {\\n  return imod(flags / flag, 2) != 0;\\n}\\n\\n// private function: Mangle me...\\nvec2 _pixelIndexToUV(int index, int textureSize) {\\n  float flTexSize = float(textureSize);\\n  float x = (float(imod(index, textureSize))+0.5)/flTexSize;\\n  float y = (floor(float(index / textureSize))+0.5)/flTexSize;\\n  return vec2(x, y);\\n}\\n\\nvec4 fetchTexel(sampler2D texture, int textureSize, int index) {\\n  vec2 texCoord = _pixelIndexToUV(index, textureSize);\\n  return texture2D(texture, texCoord);\\n}\\n\\nvec4 fetchTexel(sampler2D texture, ivec2 textureSize, ivec2 texCoord) {\\n  vec2 ftextureSize = vec2(textureSize);\\n  return texture2D(texture, (vec2(texCoord) + 0.5) / ftextureSize);\\n}\\n\\n#endif // ENABLE_ES3\\n\\nint uvToPixelIndex(vec2 uv, int textureSize) {\\n  return int(uv.x * float(textureSize)) + (int(floor(uv.y * float(textureSize))) * textureSize);\\n}\\n\\n\"; // eslint-disable-line\n\nvar Hammersley = \"#define GLSLIFY 1\\nfloat RadicalInverse_VdC(uint bits) \\n{\\n  bits = (bits << 16u) | (bits >> 16u);\\n  bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);\\n  bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);\\n  bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);\\n  bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);\\n  return float(bits) * 2.3283064365386963e-10; // / 0x100000000\\n}\\n// ----------------------------------------------------------------------------\\nvec2 Hammersley(uint i, uint N)\\n{\\n  return vec2(float(i)/float(N), RadicalInverse_VdC(i));\\n} \\n\"; // eslint-disable-line\n\nvar ImportanceSampleGGX = \"#define GLSLIFY 1\\nimport 'constants.glsl'\\n\\nvec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness)\\n{\\n  float a = roughness*roughness;\\n\\n  float phi = 2.0 * PI * Xi.x;\\n  float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y));\\n  float sinTheta = sqrt(1.0 - cosTheta*cosTheta);\\n\\n  // from spherical coordinates to cartesian coordinates\\n  vec3 H = vec3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta);\\n\\n  // from tangent-space vector to world-space sample vector\\n  vec3 up        = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);\\n  vec3 tangent   = normalize(cross(up, N));\\n  vec3 bitangent = cross(N, tangent);\\n\\n  vec3 sampleVec = tangent * H.x + bitangent * H.y + N * H.z;\\n  return normalize(sampleVec);\\n} \\n\"; // eslint-disable-line\n\nvar materialparams = \"#define GLSLIFY 1\\nimport 'GLSLUtils.glsl'\\nimport 'gamma.glsl'\\n\\nconst int FatPointsShaderId = 1;\\nconst int FlatSurfaceShaderId = 2;\\nconst int LinesShaderId = 3;\\nconst int PointsShaderId = 4;\\nconst int ScreenSpaceShaderId = 5;\\nconst int SimpleSurfaceShaderId = 6;\\nconst int StandardSurfaceShaderId = 7;\\n\\nconst int HeaderId = 0;\\nconst int BaseColorId = 1;\\n \\nuniform sampler2D materialsTexture;\\nuniform highp ivec2 materialsTextureSize;\\n\\nvec4 getMaterialValue(vec2 materialCoords, int valueIndex) {\\n  int index = ftoi(materialCoords.x) + valueIndex;\\n  ivec2 texelCoords = ivec2(imod(index, materialsTextureSize.x), index / materialsTextureSize.x);\\n  \\n  return fetchTexel(materialsTexture, materialsTextureSize, texelCoords);\\n}\\n\\n////////////////////////\\n// Material Param Helpers.\\n\\nvoid getTextureColorValue(inout vec4 value, sampler2D tex, int texType, vec2 texCoord) {\\n  if (texType == 1 || texType == 2) {\\n    // Note: we assume textures are always in gamma space, and must be converted\\n    // to linear. I cann't find evidence that 8-bit textures can be in linear space.\\n    // TODO: Use SRGB textures.\\n    value = toLinear(texture2D(tex, texCoord));\\n  }\\n  else if (texType == 3) {\\n    // Float HDR Texture. We assume these textures are in linear space.\\n    value = texture2D(tex, texCoord);\\n  }\\n}\\n\\nvec4 getColorParamValue(in vec4 value, sampler2D tex, int texType, vec2 texCoord) {\\n  // for backwards compatiblity with zea-ux shader\\n  vec4 tmp = value;\\n  getTextureColorValue(tmp, tex, texType, texCoord);\\n  return tmp;\\n}\\n\\nfloat luminanceFromRGB(vec3 rgb) {\\n  return 0.2126*rgb.r + 0.7152*rgb.g + 0.0722*rgb.b;\\n}\\n\\nvoid getTextureLuminanceValue(inout float value, sampler2D tex, int texType, vec2 texCoord) {\\n  if (texType != 0)\\n    value = luminanceFromRGB(texture2D(tex, texCoord).rgb);\\n}\\n\\nfloat getLuminanceParamValue(in float value, sampler2D tex, int texType, vec2 texCoord) {\\n  // for backwards compatiblity with zea-ux shader\\n  float tmp = value;\\n  getTextureLuminanceValue(tmp, tex, texType, texCoord);\\n  // for backwards compatiblity with zea-ux shader\\n  return tmp;\\n}\\n\\n\"; // eslint-disable-line\n\nvar modelMatrix = \"#define GLSLIFY 1\\n#ifdef ENABLE_FLOAT_TEXTURES\\nimport 'GLSLUtils.glsl'\\nimport 'transpose.glsl'\\nmat4 getMatrix(sampler2D texture, int textureSize, int index) {\\n  // Unpack 3 x 4 matrix columns into a 4 x 4 matrix.\\n  vec4 col0 = fetchTexel(texture, textureSize, (index * pixelsPerItem) + 1);\\n  vec4 col1 = fetchTexel(texture, textureSize, (index * pixelsPerItem) + 2);\\n  vec4 col2 = fetchTexel(texture, textureSize, (index * pixelsPerItem) + 3);\\n  mat4 result = transpose(mat4(col0, col1, col2, vec4(0.0, 0.0, 0.0, 1.0)));\\n  return result;\\n}\\n\\nmat4 getModelMatrix(int id) {\\n  return getMatrix(instancesTexture, instancesTextureSize, id);\\n}\\n\\n#else\\n\\nuniform mat4 modelMatrix;\\n\\nmat4 getModelMatrix(int id) {\\n  return modelMatrix;\\n}\\n\\n#endif\\n\\n\"; // eslint-disable-line\n\nvar PBRSurfaceRadiance = \"#define GLSLIFY 1\\nimport 'GLSLUtils.glsl'\\nconst int ENVMAP_FLAG_HEADLIGHT =  1; // 1<<0;\\n\\nstruct MaterialParams {\\n  vec3 baseColor;\\n  float ambientOcclusion;\\n  float metallic;\\n  float roughness;\\n  float reflectance;\\n  float opacity;\\n  float emission;\\n};\\n\\n#ifndef ENABLE_PBR\\n\\nvec4 pbrSurfaceRadiance(in MaterialParams material, vec3 normal, in vec3 viewVector) {\\n  vec3 irradiance = vec3(dot(normal, viewVector));\\n  float ao = material.ambientOcclusion; \\n  return vec4(material.baseColor * ao * irradiance + (material.emission * material.baseColor), material.opacity);\\n\\n  // return vec4(material.baseColor * ao * irradiance , material.opacity);\\n}\\n\\n#else\\n\\nuniform int envMapFlags;\\nuniform samplerCube irradianceMap;\\nuniform samplerCube prefilterMap;\\nuniform sampler2D brdfLUT;\\n\\nvec3 sampleIrradiance(vec3 dir) {\\n  return texture(irradianceMap, dir).rgb;\\n}\\n\\nvec3 fresnelSchlickRoughness(float cosTheta, vec3 F0, float roughness) {\\n  return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(max(1.0 - cosTheta, 0.0), 5.0);\\n}\\n\\nfloat luminance(vec3 color) {\\n  return 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b;\\n}\\n\\nvec4 pbrSurfaceRadiance(in MaterialParams material, vec3 normal, in vec3 viewVector) {\\n  if (envMapFlags == -1) {\\n    vec3 irradiance = vec3(dot(normal, viewVector));\\n    float ao = material.ambientOcclusion; \\n    return vec4(material.baseColor * ao * irradiance + (material.emission * material.baseColor), material.opacity);\\n  }\\n\\n  vec3 N = normal;\\n  vec3 V = viewVector;\\n  vec3 R = reflect(-V, N);\\n  float roughness = material.roughness * material.roughness;\\n  vec3 diffuseColor = (1.0 - material.metallic) * material.baseColor;\\n\\n  // Note: The specular reflectance of metallic surfaces is chromatic\\n  // https://google.github.io/filament/Filament.html#listing_fnormal\\n  vec3 F0 = 0.16 * material.reflectance * material.reflectance * (1.0 - material.metallic) + material.baseColor * material.metallic;\\n\\n  float NdotV = dot(N, V);\\n\\n  vec3 F = fresnelSchlickRoughness(max(NdotV, 0.0), F0, roughness);\\n\\n  vec3 kS = F;\\n  vec3 kD = 1.0 - kS;\\n  kD *= 1.0 - material.metallic;\\n  float ao = material.ambientOcclusion; \\n  \\n  vec3 irradiance;\\n  vec3 irradianceSampleDir = normal;\\n  \\n  bool headLightMode = testFlag(envMapFlags, ENVMAP_FLAG_HEADLIGHT);\\n  if (headLightMode) {\\n    irradianceSampleDir = viewVector;\\n  }\\n  irradiance = sampleIrradiance(irradianceSampleDir);\\n  // vec3 irradiance = shGetIrradianceAt(shCoefficients, N);\\n  vec3 diffuse    = irradiance * diffuseColor;\\n  \\n  const float MAX_REFLECTION_LOD = 4.0;\\n  vec3 prefilteredColor = textureLod(prefilterMap, R,  roughness * MAX_REFLECTION_LOD).rgb;   \\n  vec2 envBRDF  = texture(brdfLUT, vec2(max(NdotV, 0.0), roughness)).rg;\\n  vec3 specular = prefilteredColor * (F * envBRDF.x + envBRDF.y);\\n  \\n  vec3 radiance = (kD * diffuse + specular) * ao;\\n  \\n  // Now handle semi-transparent objects. We need to be able to linearly interpolate\\n  // opacity to make objects disappear, so we need a continuous change.\\n  float opacity = material.opacity;\\n  vec4 transparent = vec4((radiance * opacity) + specular, opacity + luminance(specular) + luminance(F));\\n  vec4 result = mix(transparent, vec4(radiance, 1.0), opacity);\\n\\n  // Add emission on as the final component.\\n  // Note: emission allows a material to blend off its specular component, \\n  // which can also be used to make an object completely disappear if also transparent.\\n  return mix(result, vec4(material.baseColor, opacity), material.emission);\\n}\\n\\n#endif // ENABLE_PBR\\n\"; // eslint-disable-line\n\nvar SHCoeffs = \"#define GLSLIFY 1\\nuniform vec3 shCoeffs[9];\\n\\nvec3 sampleSHCoeffs(vec3 dir) {\\n  // dir is assumed to have unit length\\n  float x = dir.x, y = dir.y, z = dir.z;\\n  // band 0\\n  vec3 result = shCoeffs[ 0 ] * 0.886227;\\n  // band 1\\n  result += shCoeffs[ 1 ] * 2.0 * 0.511664 * y;\\n  result += shCoeffs[ 2 ] * 2.0 * 0.511664 * z;\\n  result += shCoeffs[ 3 ] * 2.0 * 0.511664 * x;\\n  // band 2\\n  result += shCoeffs[ 4 ] * 2.0 * 0.429043 * x * y;\\n  result += shCoeffs[ 5 ] * 2.0 * 0.429043 * y * z;\\n  result += shCoeffs[ 6 ] * ( 0.743125 * z * z - 0.247708 );\\n  result += shCoeffs[ 7 ] * 2.0 * 0.429043 * x * z;\\n  result += shCoeffs[ 8 ] * 0.429043 * ( x * x - y * y );\\n  return result;\\n}\\n\"; // eslint-disable-line\n\nvar gamma = \"#define GLSLIFY 1\\nconst float gamma_const = 2.2;\\n\\nfloat toLinear(float v) {\\n  return pow(v, gamma_const);\\n}\\n\\nvec2 toLinear(vec2 v) {\\n  return pow(v, vec2(gamma_const));\\n}\\n\\nvec3 toLinear(vec3 v) {\\n  return pow(v, vec3(gamma_const));\\n}\\n\\nvec4 toLinear(vec4 v) {\\n  return vec4(toLinear(v.rgb), v.a);\\n}\\n\\nfloat toGamma(float v) {\\n  return pow(v, 1.0 / gamma_const);\\n}\\n\\nvec2 toGamma(vec2 v) {\\n  return pow(v, vec2(1.0 / gamma_const));\\n}\\n\\nvec3 toGamma(vec3 v) {\\n  return pow(v, vec3(1.0 / gamma_const));\\n}\\n\\nvec4 toGamma(vec4 v) {\\n  return vec4(toGamma(v.rgb), v.a);\\n}\\n\\nfloat toGamma(float v, float gamma) {\\n  return pow(v, 1.0 / gamma);\\n}\\n\\nvec2 toGamma(vec2 v, float gamma) {\\n  return pow(v, vec2(1.0 / gamma));\\n}\\n\\nvec3 toGamma(vec3 v, float gamma) {\\n  return pow(v, vec3(1.0 / gamma));\\n}\\n\\nvec4 toGamma(vec4 v, float gamma) {\\n  return vec4(toGamma(v.rgb, gamma), v.a);\\n}\\n\\n\"; // eslint-disable-line\n\nvar inverse = \"#define GLSLIFY 1\\n\\n#ifndef ENABLE_ES3\\n\\nfloat inverse(float m) {\\n  return 1.0 / m;\\n}\\n\\nmat2 inverse(mat2 m) {\\n  return mat2(m[1][1],-m[0][1],\\n             -m[1][0], m[0][0]) / (m[0][0]*m[1][1] - m[0][1]*m[1][0]);\\n}\\n\\nmat3 inverse(mat3 m) {\\n  float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2];\\n  float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2];\\n  float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2];\\n\\n  float b01 = a22 * a11 - a12 * a21;\\n  float b11 = -a22 * a10 + a12 * a20;\\n  float b21 = a21 * a10 - a11 * a20;\\n\\n  float det = a00 * b01 + a01 * b11 + a02 * b21;\\n\\n  return mat3(b01, (-a22 * a01 + a02 * a21), (a12 * a01 - a02 * a11),\\n              b11, (a22 * a00 - a02 * a20), (-a12 * a00 + a02 * a10),\\n              b21, (-a21 * a00 + a01 * a20), (a11 * a00 - a01 * a10)) / det;\\n}\\n\\nmat4 inverse(mat4 m) {\\n  float\\n      a00 = m[0][0], a01 = m[0][1], a02 = m[0][2], a03 = m[0][3],\\n      a10 = m[1][0], a11 = m[1][1], a12 = m[1][2], a13 = m[1][3],\\n      a20 = m[2][0], a21 = m[2][1], a22 = m[2][2], a23 = m[2][3],\\n      a30 = m[3][0], a31 = m[3][1], a32 = m[3][2], a33 = m[3][3],\\n\\n      b00 = a00 * a11 - a01 * a10,\\n      b01 = a00 * a12 - a02 * a10,\\n      b02 = a00 * a13 - a03 * a10,\\n      b03 = a01 * a12 - a02 * a11,\\n      b04 = a01 * a13 - a03 * a11,\\n      b05 = a02 * a13 - a03 * a12,\\n      b06 = a20 * a31 - a21 * a30,\\n      b07 = a20 * a32 - a22 * a30,\\n      b08 = a20 * a33 - a23 * a30,\\n      b09 = a21 * a32 - a22 * a31,\\n      b10 = a21 * a33 - a23 * a31,\\n      b11 = a22 * a33 - a23 * a32,\\n\\n      det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;\\n\\n  return mat4(\\n      a11 * b11 - a12 * b10 + a13 * b09,\\n      a02 * b10 - a01 * b11 - a03 * b09,\\n      a31 * b05 - a32 * b04 + a33 * b03,\\n      a22 * b04 - a21 * b05 - a23 * b03,\\n      a12 * b08 - a10 * b11 - a13 * b07,\\n      a00 * b11 - a02 * b08 + a03 * b07,\\n      a32 * b02 - a30 * b05 - a33 * b01,\\n      a20 * b05 - a22 * b02 + a23 * b01,\\n      a10 * b10 - a11 * b08 + a13 * b06,\\n      a01 * b08 - a00 * b10 - a03 * b06,\\n      a30 * b04 - a31 * b02 + a33 * b00,\\n      a21 * b02 - a20 * b04 - a23 * b00,\\n      a11 * b07 - a10 * b09 - a12 * b06,\\n      a00 * b09 - a01 * b07 + a02 * b06,\\n      a31 * b01 - a30 * b03 - a32 * b00,\\n      a20 * b03 - a21 * b01 + a22 * b00) / det;\\n}\\n\\n#endif\\n\\n\"; // eslint-disable-line\n\nvar transpose = \"#define GLSLIFY 1\\n\\n#ifndef ENABLE_ES3\\n\\nfloat transpose(float m) {\\n  return m;\\n}\\n\\nmat2 transpose(mat2 m) {\\n  return mat2(m[0][0], m[1][0],\\n              m[0][1], m[1][1]);\\n}\\n\\nmat3 transpose(mat3 m) {\\n  return mat3(m[0][0], m[1][0], m[2][0],\\n              m[0][1], m[1][1], m[2][1],\\n              m[0][2], m[1][2], m[2][2]);\\n}\\n\\nmat4 transpose(mat4 m) {\\n  return mat4(m[0][0], m[1][0], m[2][0], m[3][0],\\n              m[0][1], m[1][1], m[2][1], m[3][1],\\n              m[0][2], m[1][2], m[2][2], m[3][2],\\n              m[0][3], m[1][3], m[2][3], m[3][3]);\\n}\\n\\n#endif\\n\\n\"; // eslint-disable-line\n\nvar quadVertexFromID = \"#define GLSLIFY 1\\nattribute float vertexIDs;\\n\\nvec2 getQuadVertexPositionFromID() {\\n  int vertexID = int(vertexIDs);\\n  if (vertexID == 0)\\n    return vec2(-0.5, -0.5);\\n  else if (vertexID == 1)\\n    return vec2(0.5, -0.5);\\n  else if (vertexID == 2)\\n    return vec2(-0.5, 0.5);\\n  else if (vertexID == 3)\\n    return vec2(0.5, 0.5);\\n  return vec2(0,0);\\n}\\n\"; // eslint-disable-line\n\nvar unpackHDR = \"#define GLSLIFY 1\\n\\nvec3 decodeHDR(const in vec3 ldrPixel, const in float cdmAlpha) {\\n  float avg = (cdmAlpha * 16.0 - 8.0);\\n  float scl = 1.0;\\n  vec3 color;\\n  color.x = (tan((ldrPixel.x-0.5)*1.5)/scl)+avg;\\n  color.y = (tan((ldrPixel.y-0.5)*1.5)/scl)+avg;\\n  color.z = (tan((ldrPixel.z-0.5)*1.5)/scl)+avg;\\n\\n  // convert from logarithmic curve to linear curve.\\n  // subtract the epsilon that was added during encoding.\\n  const float eps = 0.001;\\n  color.x = pow(10.0, color.x) - eps;\\n  color.y = pow(10.0, color.y) - eps;\\n  color.z = pow(10.0, color.z) - eps;\\n  return color;\\n}\\n\\nvec3 decodeHDR(sampler2D ldrSampler, sampler2D cdmSampler, vec2 texCoord) {\\n#ifdef ENABLE_ES3\\n  float cdm = texture2D(cdmSampler, texCoord).r;\\n#else\\n  float cdm = texture2D(cdmSampler, texCoord).a;\\n#endif\\n  return decodeHDR(texture2D(ldrSampler, texCoord).rgb, cdm);\\n}\\n\\n\"; // eslint-disable-line\n\nvar surfaceGeomData = \"#define GLSLIFY 1\\n\\n  uniform int floatGeomBuffer; // Remove once we update UX. \\n  uniform int passId;\\n  uniform int occlusionCulling;\\n  uniform int debugGeomDataBuffer;\\n\\n  import 'geomItemFlags.glsl'\\n  import 'GLSLBits.glsl'\\n  import 'geomType.glsl'\\n  \\n  vec4 setFragColor_geomData(vec3 v_viewPos, float geomItemId, float elemItemId, int isOrthographic, int flags, int geomType){\\n    vec4 fragColor;\\n  \\n    if (occlusionCulling != 0) {\\n      // Transparent geoms do not render to the occlusion buffer\\n      if (testFlag(flags, GEOMITEM_TRANSPARENT)) {\\n        discard;\\n        return fragColor;\\n      }\\n\\n      // Calculate a simple stochastic transparency to reduce the cost of the reduction shader.\\n      // We only need one pixel to be visible to consider the geometry visible, so here we \\n      // keep only one in 7x7 (49) pixels. This signficatly reduces the cost of reducing the scene\\n      // to the reduction data buffer.\\n      // Note: this is not a stochastic transparency, as we are simply setting black pixels to \\n      // reduce the number of reduction points for this geometry. The black pixels (not discarded)\\n      // still occlude other geometries, but during reduction count to nothing.\\n      int x = int(gl_FragCoord.x * 1000.0);\\n      int y = int(gl_FragCoord.y * 1000.0);\\n      if (x % 7 != 0 || y % 7 != 0) {\\n        fragColor = vec4(0.0, 0.0, 0.0, 1.0);\\n      } else {\\n        // Write out just the green channel for the ReductionShader\\n        fragColor.r = float(geomItemId);\\n\\n        // Write out a value to the Green channel to indicate this is not a BBox.\\n        // We propagate this value in the ReductionShader to the output histogram\\n        // to determine if we should trigger loading of placeholders. (BBox should not)\\n        fragColor.g = 1.0;\\n\\n        \\n        // Note: the alpha value is simply so we can debug the buffer over the top of the viewport.\\n        fragColor.a = 1.0;\\n      }\\n    }\\n    else {\\n      // When not occlusion culling, we don't render non-selectable objects.\\n      //When occlusion culling, we want to draw all the geom data for all objects.\\n      if (testFlag(flags, GEOMITEM_INVISIBLE_IN_GEOMDATA)) {\\n        discard;\\n        return fragColor;\\n      }\\n\\n      float viewDist;\\n      if (isOrthographic > 0) {\\n        viewDist = abs(v_viewPos.z);\\n      } else {\\n        viewDist = length(v_viewPos);\\n      }\\n      \\n      fragColor.r = float(passId); \\n      fragColor.g = float(geomItemId);\\n      fragColor.b = elemItemId;\\n      fragColor.a = viewDist;\\n      \\n      if (debugGeomDataBuffer == 1) {\\n        if (geomType == TRIANGLES) {\\n          fragColor = vec4(1.0, 0.0, 0.0, 1.0); \\n        }\\n        else if (geomType == LINES) {\\n          fragColor = vec4(0.0, 1.0, 0.0, 1.0); \\n        } \\n        else if (geomType == POINTS) {\\n          fragColor = vec4(0.0, 0.0, 1.0, 1.0); \\n        } \\n      }\\n\\n    }\\n\\n    return fragColor;\\n  }\\n  vec4 setFragColor_geomData(vec3 v_viewPos, float geomItemId, float elemItemId, int isOrthographic, int flags){\\n    return setFragColor_geomData(v_viewPos, geomItemId, 0.0, isOrthographic, flags, TRIANGLES);\\n  }\\n\\n  vec4 setFragColor_geomData(vec3 v_viewPos, int floatGeomBuffer, int passId, float geomItemId, int isOrthographic){\\n    return setFragColor_geomData(v_viewPos, geomItemId, 0.0, isOrthographic, 0);\\n  }\\n  vec4 setFragColor_geomData(vec3 v_viewPos, int floatGeomBuffer, int passId, float geomItemId, float elemItemId, int isOrthographic){\\n    return setFragColor_geomData(v_viewPos, geomItemId, elemItemId, isOrthographic, 0);\\n  }\"; // eslint-disable-line\n\nvar surfaceHighlight = \"#define GLSLIFY 1\\nimport 'GLSLUtils.glsl'\\nimport 'drawItemTexture.glsl'\\n\\nvec4 getHighlightColor(int id) {\\n  return fetchTexel(instancesTexture, instancesTextureSize, (id * pixelsPerItem) + 4);\\n}\\n\\nvec4 setFragColor_highlight(float geomItemId){\\n  vec4 fragColor = getHighlightColor(int(round(geomItemId)));\\n  return fragColor;\\n}\\n\"; // eslint-disable-line\n\nvar imageAtlas = \"#define GLSLIFY 1\\n// Note: On mobile, I can't seem to pass around a stuct containing sampler2D.\\n// I have to unpack the struct and pass its members. :(\\n// struct ImageAtlas {\\n//     sampler2D layout;\\n//     sampler2D image;\\n//     vec4 desc;\\n// };\\n\\nimport 'GLSLUtils.glsl'\\n\\nvec4 getSubImageLayout(int index, in sampler2D atlasLayout, in vec4 atlasDesc){\\n    return fetchTexel(atlasLayout, int(floor(atlasDesc.z+0.5)), index);\\n}\\nvec2 calcSubImageTexCoords(vec2 texCoord, int index, in sampler2D atlasLayout, in vec4 atlasDesc){\\n    vec4 layoutData = fetchTexel(atlasLayout, int(floor(atlasDesc.z+0.5)), index);\\n    // The following line is a hack to fix artifacts in our PBR lighting\\n    // We were seeing loads of lighting garbage on some sufaces that were orthogonal\\n    // to the world. The UV coordinates would have been landing right on the edges\\n    // of our subimages and were often sampling outside the image. This couuld\\n    // have been because of filtering, or an error in the uv coords. \\n    texCoord = clamp(texCoord, vec2(0.01, 0.01), vec2(0.99, 0.99));\\n    vec2 subimageTexel = texCoord * layoutData.zw;\\n    // subimageTexel = clamp(subimageTexel, vec2(0.0, 0.0), vec2(1.0, 1.0));\\n    return subimageTexel + layoutData.xy;\\n}\\nvec4 sampleSubImage(vec2 texCoord, int index, in sampler2D atlasLayout, in sampler2D atlasImage, in vec4 atlasDesc){\\n    vec4 layoutData = fetchTexel(atlasLayout, int(floor(atlasDesc.z+0.5)), index);\\n    vec2 atlasCoords = calcSubImageTexCoords(texCoord, index, atlasLayout, atlasDesc);\\n    return texture2D(atlasImage, atlasCoords);\\n}\"; // eslint-disable-line\n\n// @ts-nocheck\nshaderLibrary.setShaderModule('imageAtlas.glsl', imageAtlas);\nshaderLibrary.setShaderModule('surfaceGeomData.glsl', surfaceGeomData);\nshaderLibrary.setShaderModule('surfaceHighlight.glsl', surfaceHighlight);\nshaderLibrary.setShaderModule('computeViewNormal.glsl', computeViewNormal);\nshaderLibrary.setShaderModule('calcFatLinesViewPos.glsl', calcFatLinesViewPos);\nshaderLibrary.setShaderModule('constants.glsl', constants);\nshaderLibrary.setShaderModule('convolve-helpers.glsl', convolveHelpers);\nshaderLibrary.setShaderModule('cutaways.glsl', cutaways);\nshaderLibrary.setShaderModule('debugColors.glsl', debugColors);\nshaderLibrary.setShaderModule('drawItemId.glsl', geomItemId); // Needed for backwards compatiblity with older versions of ux.\nshaderLibrary.setShaderModule('geomItemId.glsl', geomItemId);\nshaderLibrary.setShaderModule('geomItemFlags.glsl', geomItemFlags);\nshaderLibrary.setShaderModule('geomType.glsl', geomType);\nshaderLibrary.setShaderModule('geometryMask.glsl', geometryMask);\nshaderLibrary.setShaderModule('drawItemTexture.glsl', drawItemTexture);\nshaderLibrary.setShaderModule('envmap-dualfisheye.glsl', envmapDualfisheye);\nshaderLibrary.setShaderModule('envmap-equirect.glsl', envmapEquirect);\nshaderLibrary.setShaderModule('envmap-octahedral.glsl', envmapOctahedral);\nshaderLibrary.setShaderModule('GLSLBits.glsl', GLSLBits);\nshaderLibrary.setShaderModule('GLSLUtils.glsl', GLSLUtils);\nshaderLibrary.setShaderModule('Hammersley.glsl', Hammersley);\nshaderLibrary.setShaderModule('ImportanceSampleGGX.glsl', ImportanceSampleGGX);\nshaderLibrary.setShaderModule('materialparams.glsl', materialparams);\nshaderLibrary.setShaderModule('modelMatrix.glsl', modelMatrix);\nshaderLibrary.setShaderModule('PBRSurfaceRadiance.glsl', PBRSurfaceRadiance);\nshaderLibrary.setShaderModule('SHCoeffs.glsl', SHCoeffs);\nshaderLibrary.setShaderModule('gamma.glsl', gamma);\nshaderLibrary.setShaderModule('inverse.glsl', inverse);\nshaderLibrary.setShaderModule('transpose.glsl', transpose);\nshaderLibrary.setShaderModule('quadVertexFromID.glsl', quadVertexFromID);\nshaderLibrary.setShaderModule('unpackHDR.glsl', unpackHDR);\n\nvar frag$i = \" \\nprecision highp float;\\n#define GLSLIFY 1\\n\\nvarying vec2 v_texCoord;\\nuniform sampler2D ldrSampler;\\nuniform sampler2D cdmSampler;\\nuniform vec4 srcRegion; // pos, and size of the source region\\n\\nimport 'unpackHDR.glsl'\\n\\n#ifdef ENABLE_ES3\\n  out vec4 fragColor;\\n#endif\\nvoid main(void) {\\n\\n#ifndef ENABLE_ES3\\n  vec4 fragColor;\\n#endif\\n\\n  vec2 srcUv = srcRegion.xy + (v_texCoord * srcRegion.zw);\\n\\n  fragColor = vec4(decodeHDR(ldrSampler, cdmSampler, srcUv), 1.0);\\n\\n#ifndef ENABLE_ES3\\n  gl_FragColor = fragColor;\\n#endif\\n}\\n\\n\"; // eslint-disable-line\n\nvar vert$j = \"\\nprecision highp float;\\n#define GLSLIFY 1\\n\\nimport 'quadVertexFromID.glsl'\\n\\n/* VS Outputs */\\nvarying vec2 v_texCoord;\\n \\nvoid main()\\n{\\n  vec2 position = getQuadVertexPositionFromID();\\n  v_texCoord = position+0.5;\\n  gl_Position = vec4(position*2.0, 0.0, 1.0);\\n}\\n\"; // eslint-disable-line\n\n/* eslint-disable require-jsdoc */\n/** Shader for unpacking HDR images using Boost HDR algorithm.\n * @extends GLShader\n * @private\n */\nclass UnpackHDRShader extends GLShader {\n    /**\n     * Create a GL shader.\n     * @param gl - The webgl rendering context.\n     */\n    constructor(gl) {\n        super(gl, 'UnpackHDRShader');\n        this.setShaderStage('VERTEX_SHADER', vert$j);\n        this.setShaderStage('FRAGMENT_SHADER', frag$i);\n    }\n}\n\n/* eslint-disable guard-for-in */\n/**\n * Returns a descriptor for the provided geom attribute.\n * Used to generate WebGLBuffers from the data provided by the geometry.\n * @private\n * @param gl - The webgl context\n * @param attrDataType - The geometry attribute value.\n *\n * @return\n */\nconst genDataTypeDesc = (gl, name) => {\n    let dimension;\n    let elementSize;\n    let dataType;\n    switch (name) {\n        case 'UInt8':\n            dimension = 1;\n            elementSize = 4;\n            dataType = gl.UNSIGNED_BYTE;\n            break;\n        case 'SInt8':\n            dimension = 1;\n            elementSize = 1;\n            dataType = gl.BYTE;\n            break;\n        case 'UInt16':\n            dimension = 1;\n            elementSize = 2;\n            dataType = gl.UNSIGNED_SHORT;\n            break;\n        case 'SInt16':\n            dimension = 1;\n            elementSize = 2;\n            dataType = gl.SHORT;\n            break;\n        case 'UInt32':\n            dimension = 1;\n            elementSize = 4;\n            dataType = gl.UNSIGNED_INT;\n            break;\n        case 'SInt32':\n            dimension = 1;\n            elementSize = 4;\n            dataType = gl.INT;\n            break;\n        case 'Float32':\n            dimension = 1;\n            elementSize = 4;\n            dataType = gl.FLOAT;\n            break;\n        case 'Vec2f8':\n            dimension = 2;\n            elementSize = 1;\n            dataType = gl.BYTE;\n            break;\n        case 'Vec2f16':\n            dimension = 2;\n            elementSize = 2;\n            dataType = gl.HALF_FLOAT;\n            break;\n        case 'Vec2':\n            dimension = 2;\n            elementSize = 4;\n            dataType = gl.FLOAT;\n            break;\n        case 'Vec3f8':\n            dimension = 3;\n            elementSize = 1;\n            dataType = gl.BYTE;\n            break;\n        case 'Vec3f16':\n            dimension = 3;\n            elementSize = 2;\n            dataType = gl.HALF_FLOAT;\n            break;\n        case 'Vec3':\n            dimension = 3;\n            elementSize = 4;\n            dataType = gl.FLOAT;\n            break;\n        case 'Vec4':\n        case 'Color':\n            dimension = 4;\n            elementSize = 4;\n            dataType = gl.FLOAT;\n            break;\n        case 'Vec4f8':\n            dimension = 4;\n            elementSize = 1;\n            dataType = gl.BYTE;\n            break;\n        case 'Vec4f16':\n            dimension = 4;\n            elementSize = 2;\n            dataType = gl.HALF_FLOAT;\n            break;\n        case 'RGBA':\n            dimension = 4;\n            elementSize = 1;\n            dataType = gl.UNSIGNED_BYTE;\n            break;\n        default:\n            throw 'Unhandled Type:' + name;\n    }\n    return {\n        name,\n        dimension,\n        elementSize,\n        dataType,\n    };\n};\nclass IGeomShaderBinding {\n}\n/** Class representing a geom shader binding.\n * @private\n */\nclass GeomShaderBinding extends IGeomShaderBinding {\n    gl;\n    shaderAttrs;\n    glattrbuffers;\n    indexBuffer;\n    /**\n     * Create a geom shader binding.\n     * @param gl - The webgl rendering context.\n     * @param shaderAttrs - The shader attributes.\n     * @param geomAttrBuffers - The geomAttrBuffers value.\n     * @param indexBuffer - The index buffer.\n     */\n    constructor(gl, shaderAttrs, geomAttrBuffers, indexBuffer) {\n        super();\n        this.gl = gl;\n        this.shaderAttrs = shaderAttrs;\n        this.glattrbuffers = geomAttrBuffers;\n        this.indexBuffer = indexBuffer;\n    }\n    /**\n     * The bind method.\n     * @param renderstate - The render state.\n     * @return - The return value.\n     */\n    bind(renderstate) {\n        const gl = this.gl;\n        for (const attrName in this.shaderAttrs) {\n            if (attrName == 'instancedIds')\n                continue;\n            const shaderAttrDesc = this.shaderAttrs[attrName];\n            const location = shaderAttrDesc.location;\n            if (location == -1)\n                continue;\n            const geomAttrBuffer = this.glattrbuffers[attrName];\n            if (!geomAttrBuffer) {\n                gl.disableVertexAttribArray(location);\n                continue;\n            }\n            const dimension = geomAttrBuffer.dimension;\n            const dataType = geomAttrBuffer.dataType;\n            const normalized = geomAttrBuffer.normalized;\n            const isInteger = shaderAttrDesc.integer;\n            const stride = dimension * geomAttrBuffer.elementSize;\n            const offset = geomAttrBuffer.offset != undefined ? geomAttrBuffer.offset * dimension * geomAttrBuffer.elementSize : 0;\n            const instanced = shaderAttrDesc.instanced;\n            gl.enableVertexAttribArray(location);\n            gl.bindBuffer(gl.ARRAY_BUFFER, geomAttrBuffer.buffer);\n            if (isInteger) {\n                gl.vertexAttribIPointer(location, dimension, dataType, stride, offset);\n            }\n            else {\n                gl.vertexAttribPointer(location, dimension, dataType, normalized, stride, offset);\n            }\n            if (instanced == true) {\n                gl.vertexAttribDivisor(location, 1); // This makes it instanced\n            }\n            else {\n                gl.vertexAttribDivisor(location, 0); // This makes it not-instanced\n            }\n            // console.log(\"Binding :\" + attrName + \" to attr:\" + location + \" count:\" + geomAttrBuffer.count + \" dimension:\" + dimension  + \" stride:\" + stride  + \" offset:\" + offset + \" normalized:\" + normalized + \" instanced:\" + instanced);\n        }\n        if (this.indexBuffer)\n            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);\n        return true;\n    }\n    /**\n     * The unbind method.\n     */\n    unbind(renderstate) {\n        const gl = this.gl;\n        for (const attrName in this.shaderAttrs) {\n            const shaderAttrDesc = this.shaderAttrs[attrName];\n            const location = shaderAttrDesc.location;\n            if (location == -1) {\n                gl.enableVertexAttribArray(location);\n            }\n            if (shaderAttrDesc.instanced) {\n                gl.vertexAttribDivisor(location, 0); // This makes it not-instanced\n            }\n            // console.log(\"Binding :\" + attrName + \" to attr:\" + location + \" count:\" + geomAttrBuffer.count + \" dimension:\" + dimension  + \" stride:\" + stride  + \" offset:\" + offset + \" normalized:\" + normalized + \" instanced:\" + instanced);\n        }\n        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);\n    }\n    /**\n     * The destroy is called by the system to cause explicit resources cleanup.\n     * Users should never need to call this method directly.\n     */\n    destroy() { }\n}\n/** Class representing vertex array objects (VAO) geom shader binding.\n * @private\n */\nclass VAOGeomShaderBinding extends IGeomShaderBinding {\n    vao;\n    gl;\n    indexBuffer;\n    /**\n     * Create VAO geom shader binding.\n     * @param gl - The webgl rendering context.\n     * @param shaderAttrs - The shaderAttrs value.\n     * @param geomAttrBuffers - The geomAttrBuffers value.\n     * @param indexBuffer - The indexBuffer value.\n     */\n    constructor(gl, shaderAttrs, geomAttrBuffers, indexBuffer) {\n        super();\n        this.gl = gl;\n        this.vao = gl.createVertexArray();\n        gl.bindVertexArray(this.vao);\n        for (const attrName in shaderAttrs) {\n            if (attrName == 'instancedIds')\n                continue;\n            const shaderAttrDesc = shaderAttrs[attrName];\n            const location = shaderAttrDesc.location;\n            if (location == -1)\n                continue;\n            let geomAttrBuffer = geomAttrBuffers[attrName];\n            let offset = 0;\n            if (!geomAttrBuffer) {\n                if (attrName.endsWith('Next')) {\n                    geomAttrBuffer = geomAttrBuffers[attrName.substring(0, attrName.length - 4)];\n                    offset = 1 * geomAttrBuffer.dimension * geomAttrBuffer.elementSize;\n                }\n                if (!geomAttrBuffer) {\n                    // console.warn(\"geomAttrBuffer missing:\" + attrName + \" location:\" + location);\n                    gl.disableVertexAttribArray(location);\n                    continue;\n                }\n            }\n            const dimension = geomAttrBuffer.dimension;\n            const dataType = geomAttrBuffer.dataType;\n            const stride = geomAttrBuffer.dimension * geomAttrBuffer.elementSize;\n            const isInteger = shaderAttrDesc.integer;\n            const instanced = shaderAttrDesc.instanced;\n            gl.enableVertexAttribArray(location);\n            gl.bindBuffer(gl.ARRAY_BUFFER, geomAttrBuffer.buffer);\n            if (isInteger) {\n                gl.vertexAttribIPointer(location, dimension, dataType, stride, offset);\n            }\n            else {\n                const normalized = geomAttrBuffer.normalized == true;\n                gl.vertexAttribPointer(location, dimension, dataType, normalized, stride, offset);\n            }\n            if (gl.vertexAttribDivisor) {\n                if (instanced == true) {\n                    gl.vertexAttribDivisor(location, 1); // This makes it instanced\n                }\n                else {\n                    gl.vertexAttribDivisor(location, 0); // This makes it not-instanced\n                }\n            }\n            // console.log(\"Binding :\" + attrName + \" to attr:\" + location + \" count:\" + geomAttrBuffer.count + \" dimension:\" + dimension  + \" stride:\" + stride  + \" offset:\" + offset + \" normalized:\" + normalized + \" instanced:\" + instanced);\n        }\n        this.indexBuffer = indexBuffer;\n        if (this.indexBuffer)\n            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);\n    }\n    /**\n     * The bind method.\n     * @param renderstate - The render state.\n     * @return - The return value.\n     */\n    bind(renderstate) {\n        const gl = this.gl;\n        gl.bindVertexArray(this.vao);\n        if (this.indexBuffer)\n            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);\n        return true;\n    }\n    /**\n     * The unbind method.\n     */\n    unbind(renderstate) {\n        const gl = this.gl;\n        gl.bindVertexArray(null);\n        if (this.indexBuffer)\n            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);\n    }\n    /**\n     * The destroy is called by the system to cause explicit resources cleanup.\n     * Users should never need to call this method directly.\n     */\n    destroy() {\n        const gl = this.gl;\n        // Ensure we detach the index buffer before deleting the VAO.\n        if (this.indexBuffer) {\n            gl.bindVertexArray(this.vao);\n            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);\n        }\n        gl.deleteVertexArray(this.vao);\n    }\n}\nfunction generateShaderGeomBinding(gl, shaderAttrs, geomAttrBuffers, indexBuffer) {\n    if (gl.createVertexArray == null) {\n        return new GeomShaderBinding(gl, shaderAttrs, geomAttrBuffers, indexBuffer);\n    }\n    else {\n        return new VAOGeomShaderBinding(gl, shaderAttrs, geomAttrBuffers, indexBuffer);\n    }\n}\n\n/** Class representing a GL high dynamic range (HDR) image.\n * @extends GLTexture2D\n * @private\n */\nclass GLHDRImage extends GLTexture2D {\n    listenerIDs = {};\n    hdrImage;\n    fbo = null;\n    srcLDRTex = null;\n    srcCDMTex = null;\n    unpackHDRShader = null;\n    shaderBinding = null;\n    /**\n     * Create a GL HDR image.\n     * @param gl - The webgl rendering context.\n     * @param hdrImage - The HDR image.\n     */\n    constructor(gl, hdrImage) {\n        super(gl);\n        this.hdrImage = hdrImage;\n        const loadImage = () => {\n            this.__unpackHDRImage(this.hdrImage.getParams());\n        };\n        this.listenerIDs['updated'] = this.hdrImage.on('updated', loadImage);\n        if (this.hdrImage.isLoaded()) {\n            loadImage();\n        }\n        else {\n            this.listenerIDs['loaded'] = this.hdrImage.on('loaded', loadImage);\n        }\n    }\n    /**\n     * Returns the `BaseImage` of the GL Texture\n     *\n     * @return - The return value.\n     */\n    getImage() {\n        return this.hdrImage;\n    }\n    /**\n     * The __unpackHDRImage method.\n     * @param hdrImageParams - The HDR image parameters.\n     * @private\n     */\n    __unpackHDRImage(hdrImageParams) {\n        const gl = this.gl;\n        const ldr = hdrImageParams.data.ldr;\n        const cdm = hdrImageParams.data.cdm;\n        if (!this.fbo) {\n            // Note: iOS devices create FLOAT Fbox.\n            // If we want better quality, we could unpack the texture in JavaScript.\n            this.configure({\n                format: this.gl.RGBA,\n                // Note: Safari17 broke support for linear float textures.\n                // Safari does support linear half-float textures, so we now use that in the PBR lighting pipeline.\n                type: this.gl.HALF_FLOAT,\n                width: ldr.width,\n                height: ldr.height,\n                filter: this.gl.LINEAR,\n                wrap: this.gl.CLAMP_TO_EDGE,\n            });\n            this.fbo = new GLFbo(this.gl, this);\n            this.fbo.setClearColor(new Color(0, 0, 0, 0));\n            this.srcLDRTex = new GLTexture2D(this.gl, {\n                format: this.gl.RGB,\n                type: this.gl.UNSIGNED_BYTE,\n                width: ldr.width,\n                height: ldr.height,\n                filter: this.gl.NEAREST,\n                mipMapped: false,\n                wrap: this.gl.CLAMP_TO_EDGE,\n                data: ldr,\n            });\n            this.srcCDMTex = new GLTexture2D(this.gl, {\n                format: this.gl.RED,\n                type: this.gl.UNSIGNED_BYTE,\n                width: ldr.width /* 8*/,\n                height: ldr.height /* 8*/,\n                filter: this.gl.NEAREST,\n                mipMapped: false,\n                wrap: this.gl.CLAMP_TO_EDGE,\n                data: cdm,\n            });\n            this.unpackHDRShader = new UnpackHDRShader(this.gl);\n            const shaderComp = this.unpackHDRShader.compileForTarget('GLHDRImage', ['#define ENABLE_ES3']);\n            this.shaderBinding = generateShaderGeomBinding(this.gl, shaderComp.attrs, gl.__quadattrbuffers, gl.__quadIndexBuffer);\n        }\n        else {\n            this.srcLDRTex.bufferData(ldr);\n            this.srcCDMTex.bufferData(cdm);\n        }\n        const renderstate = new RenderState(this.gl);\n        this.fbo.bindForWriting(renderstate);\n        this.fbo.clear();\n        this.unpackHDRShader.bind(renderstate, 'GLHDRImage');\n        this.shaderBinding.bind(renderstate);\n        const unifs = renderstate.unifs;\n        this.srcLDRTex.bindToUniform(renderstate, unifs.ldrSampler);\n        this.srcCDMTex.bindToUniform(renderstate, unifs.cdmSampler);\n        gl.uniform4fv(unifs.srcRegion.location, [0, 0, 1, 1]);\n        gl.drawQuad();\n        this.fbo.unbindForWriting(renderstate);\n        this.emit('updated');\n    }\n    /**\n     * The bindToUniform method.\n     * @param renderstate - The object tracking the current state of the renderer\n     * @param unif - The WebGL uniform\n     * @param bindings - The bindings value.\n     * @return - The return value.\n     */\n    bindToUniform(renderstate, unif, bindings) {\n        return super.bindToUniform(renderstate, unif, bindings);\n    }\n    /**\n     * The destroy is called by the system to cause explicit resources cleanup.\n     * Users should never need to call this method directly.\n     */\n    destroy() {\n        super.destroy();\n        if (this.fbo) {\n            this.fbo.destroy();\n            this.srcLDRTex.destroy();\n            this.srcCDMTex.destroy();\n        }\n        if (this.unpackHDRShader)\n            this.unpackHDRShader.destroy();\n        if (this.shaderBinding)\n            this.shaderBinding.destroy();\n        if ('loaded' in this.listenerIDs)\n            this.hdrImage.off('loaded', this.listenerIDs['loaded']);\n        this.hdrImage.off('updated', this.listenerIDs['updated']);\n    }\n}\n\n/** Class representing a GL geom.\n * @private\n */\nclass GLGeom extends RefCounted {\n    __gl;\n    geom;\n    numVertices = -1;\n    glattrbuffers = {};\n    shaderBindings = {};\n    buffersDirty = true;\n    genBufferOpts = {};\n    indexBuffer = null;\n    /**\n     * Create a GL geom.\n     * @param gl - The webgl rendering context.\n     * @param geom - A geometry object\n     */\n    constructor(gl, geom) {\n        super();\n        this.__gl = gl;\n        this.geom = geom;\n        const geomDataChanged = (opts) => {\n            this.dirtyBuffers(opts);\n        };\n        this.geom.on('geomDataChanged', geomDataChanged);\n        const geomDataTopologyChanged = (opts) => {\n            this.clearBuffers();\n            this.dirtyBuffers(opts);\n        };\n        this.geom.on('geomDataTopologyChanged', geomDataTopologyChanged);\n    }\n    /**\n     * Returns the owned Geometry object\n     * @return - The geometry object.\n     */\n    getGeom() {\n        return this.geom;\n    }\n    // /////////////////////////////////////\n    // Buffers\n    /**\n     * The dirtyBuffers method.\n     * @param opts - options passed when geomDataChanged is emitted. (Currently ony used by the FreehandLines tool)\n     */\n    dirtyBuffers(opts) {\n        this.genBufferOpts = opts;\n        this.buffersDirty = true;\n        this.emit('updated');\n    }\n    /**\n     * The genBuffers method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    genBuffers(renderstate) {\n        const gl = this.__gl;\n        const geomBuffers = this.geom.genBuffers();\n        // eslint-disable-next-line guard-for-in\n        for (const attrName in geomBuffers.attrBuffers) {\n            if (!renderstate.attrs[attrName])\n                continue;\n            if (this.glattrbuffers[attrName] && this.glattrbuffers[attrName].buffer) {\n                gl.deleteBuffer(this.glattrbuffers[attrName].buffer);\n            }\n            const attrData = geomBuffers.attrBuffers[attrName];\n            const attrDesc = genDataTypeDesc(gl, attrData.dataType);\n            const attrBuffer = gl.createBuffer();\n            gl.bindBuffer(gl.ARRAY_BUFFER, attrBuffer);\n            gl.bufferData(gl.ARRAY_BUFFER, attrData.values, gl.STATIC_DRAW);\n            this.glattrbuffers[attrName] = {\n                dataType: attrDesc.dataType,\n                name: attrName,\n                dimension: attrData.dimension,\n                elementSize: attrDesc.elementSize,\n                normalized: false,\n                shared: false,\n                numValues: attrData.count,\n                buffer: attrBuffer,\n            };\n        }\n        this.numVertices = this.geom.getNumVertices();\n        this.buffersDirty = false;\n    }\n    /**\n     * The updateBuffers method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    updateBuffers(renderstate) {\n        if (this.numVertices != this.geom.getNumVertices()) {\n            this.genBuffers(renderstate);\n            return;\n        }\n        const gl = this.__gl;\n        const geomBuffers = this.geom.genBuffers({ includeIndices: false });\n        // eslint-disable-next-line guard-for-in\n        for (const attrName in geomBuffers.attrBuffers) {\n            const attrData = geomBuffers.attrBuffers[attrName];\n            const glattr = this.glattrbuffers[attrName];\n            gl.bindBuffer(gl.ARRAY_BUFFER, glattr.buffer);\n            gl.bufferData(gl.ARRAY_BUFFER, attrData.values, gl.STATIC_DRAW);\n        }\n        this.buffersDirty = false;\n    }\n    // /////////////////////////////////////\n    // Binding\n    /**\n     * The bind method.\n     * @param renderstate - The object tracking the current state of the renderer\n     * @return - returns false if the binding failed.\n     */\n    bind(renderstate) {\n        if (this.buffersDirty)\n            this.updateBuffers(renderstate);\n        let shaderBinding = this.shaderBindings[renderstate.shaderkey];\n        if (!shaderBinding) {\n            const gl = this.__gl;\n            shaderBinding = generateShaderGeomBinding(gl, renderstate.attrs, this.glattrbuffers, this.indexBuffer);\n            this.shaderBindings[renderstate.shaderkey] = shaderBinding;\n        }\n        shaderBinding.bind(renderstate);\n    }\n    /**\n     * The unbind method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    unbind(renderstate) {\n        // Unbinding a geom is important as it puts back some important\n        // GL state. (vertexAttribDivisor)\n        const shaderBinding = this.shaderBindings[renderstate.shaderkey];\n        if (shaderBinding) {\n            shaderBinding.unbind(renderstate);\n        }\n    }\n    // /////////////////////////////////////\n    // Drawing\n    // Draw an item to screen.\n    /**\n     * The draw method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    draw(renderstate) {\n        throw new Error('Not implemented. Implement this method in a derived class.');\n    }\n    /**\n     * The drawInstanced method.\n     * @param renderstate - The object tracking the current state of the renderer\n     * @param instanceCount - The instanceCount param.\n     */\n    drawInstanced(renderstate, instanceCount) {\n        throw new Error('Not implemented. Implement this method in a derived class.');\n    }\n    /**\n     * The bindAndDraw method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    bindAndDraw(renderstate) {\n        this.bind(renderstate);\n        this.draw(renderstate);\n    }\n    /**\n     * The clearBuffers method.\n     */\n    clearBuffers() {\n        const gl = this.__gl;\n        // eslint-disable-next-line guard-for-in\n        for (const attrName in this.glattrbuffers) {\n            const glbuffer = this.glattrbuffers[attrName];\n            if (glbuffer.shared)\n                continue; /* This buffer is shared between geoms. do not destroy */\n            gl.deleteBuffer(glbuffer.buffer);\n        }\n        this.glattrbuffers = {};\n        // eslint-disable-next-line guard-for-in\n        for (const shaderkey in this.shaderBindings) {\n            const shaderBinding = this.shaderBindings[shaderkey];\n            shaderBinding.destroy();\n        }\n        this.shaderBindings = {};\n    }\n    /**\n     * The destroy is called by the system to cause explicit resources cleanup.\n     * Users should never need to call this method directly.\n     */\n    destroy() {\n        this.clearBuffers();\n        super.destroy();\n    }\n}\n\n/** Class representing a GL mesh.\n * @extends GLGeom\n * @private\n */\nclass GLMesh extends GLGeom {\n    numTriIndices = 0;\n    indexDataType = 0;\n    numTriangles = 0;\n    /**\n     * Create a GL mesh.\n     * @param gl - The webgl rendering context.\n     * @param mesh - The mesh value.\n     */\n    constructor(gl, mesh) {\n        super(gl, mesh);\n    }\n    // /////////////////////////////////////\n    // Buffers\n    /**\n     * The genBuffers method.\n     */\n    genBuffers(renderstate) {\n        super.genBuffers(renderstate);\n        const gl = this.__gl;\n        const geomBuffers = this.geom.genBuffers();\n        const indices = geomBuffers.indices;\n        if (indices instanceof Uint8Array)\n            this.indexDataType = this.__gl.UNSIGNED_BYTE;\n        if (indices instanceof Uint16Array)\n            this.indexDataType = this.__gl.UNSIGNED_SHORT;\n        if (indices instanceof Uint32Array)\n            this.indexDataType = this.__gl.UNSIGNED_INT;\n        if (this.indexBuffer) {\n            gl.deleteBuffer(this.indexBuffer);\n        }\n        this.indexBuffer = gl.createBuffer();\n        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);\n        gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, geomBuffers.indices, gl.STATIC_DRAW);\n        this.numTriIndices = geomBuffers.indices.length;\n        this.numTriangles = indices.length / 3;\n        if (this.glattrbuffers.textureCoords) {\n            this.glattrbuffers.texCoords = this.glattrbuffers.textureCoords;\n            delete this.glattrbuffers.textureCoords;\n        }\n    }\n    /**\n     * The clearBuffers method.\n     */\n    clearBuffers() {\n        const gl = this.__gl;\n        gl.deleteBuffer(this.indexBuffer);\n        this.indexBuffer = null;\n        super.clearBuffers();\n    }\n    // /////////////////////////////////////\n    // Binding\n    /**\n     * The bind method.\n     * @param renderstate - The object tracking the current state of the renderer\n     * @return - returns false if the binding failed.\n     */\n    bind(renderstate) {\n        super.bind(renderstate);\n        const { geomType } = renderstate.unifs;\n        if (geomType)\n            this.__gl.uniform1i(geomType.location, 0 /*GeomType.TRIANGLES*/);\n    }\n    // ////////////////////////////////\n    // Regular Drawing.\n    /**\n     * Draw an item to screen.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    draw(renderstate) {\n        this.__gl.drawElements(this.__gl.TRIANGLES, this.numTriIndices, this.indexDataType, 0);\n    }\n    /**\n     * The drawInstanced method.\n     * @param renderstate - The object tracking the current state of the renderer\n     * @param instanceCount - The instanceCount value.\n     */\n    drawInstanced(renderstate, instanceCount) {\n        const gl = this.__gl;\n        gl.drawElementsInstanced(this.__gl.TRIANGLES, this.numTriIndices, this.indexDataType, 0, instanceCount);\n    }\n    /**\n     * The destroy is called by the system to cause explicit resources cleanup.\n     * Users should never need to call this method directly.\n     */\n    destroy() {\n        super.destroy();\n        const gl = this.__gl;\n        gl.deleteBuffer(this.indexBuffer);\n        this.indexBuffer = null;\n    }\n}\n\nconst FRAMEBUFFER = {\n    MSAA_RENDERBUFFER: 0,\n    COLORBUFFER: 1,\n    DEPTHBUFFER: 2,\n};\n/**\n * Class representing a GL base viewport.\n * @extends ParameterOwner\n * @private\n */\nclass GLBaseViewport extends ParameterOwner {\n    __gl;\n    renderer;\n    __renderer;\n    __fbo = null;\n    quad;\n    offscreenBuffer = null;\n    depthTexture = null;\n    highlightedGeomsBufferFbo;\n    __backgroundTexture = null;\n    __backgroundGLTexture = null;\n    offscreenBufferFbo = null;\n    width = 0;\n    height = 0;\n    __canvasWidth = 0;\n    __canvasHeight = 0;\n    fb = null;\n    colorRenderbuffer;\n    depthBuffer = null;\n    EXT_frag_depth = null;\n    manipulator;\n    depthRange = [0, 0];\n    region = [0, 0, 0, 0];\n    /**\n     * @member backgroundColorParam - Changes background color of the scene\n     */\n    backgroundColorParam = new ColorParameter('BackgroundColor', new Color('#eeeeee')); // owned by viewport\n    // The time between clicks for a double click to be registered.\n    clickTime = 200;\n    doubleClickTime = 200;\n    // The duration for the pointer to be held to emit a long press event.\n    longPressTime = 1000;\n    // The maximum movingment of the pointer to still be considered a 'click'\n    pointerClickTolerance = 5;\n    /**\n     * Create a GL base viewport.\n     * @param renderer - The renderer value.\n     */\n    constructor(renderer) {\n        super();\n        this.renderer = renderer;\n        this.__renderer = renderer;\n        const gl = this.__renderer.gl;\n        this.__gl = gl;\n        this.quad = new GLMesh(gl, new Plane(1, 1));\n        // //////////////////////////////////\n        // Setup Offscreen Render Targets\n        // Note: On low end devices, such as Oculus, blitting the multi-sampled depth buffer is throwing errors,\n        // and so we are simply disabling silhouettes on all low end devices now.\n        this.highlightedGeomsBufferFbo = new GLRenderTarget(gl, {\n            type: gl.UNSIGNED_BYTE,\n            format: gl.RGBA,\n            filter: gl.NEAREST,\n            width: 4,\n            height: 4,\n            createDepthTexture: true,\n        });\n        this.highlightedGeomsBufferFbo.clearColor = new Color(0, 0, 0, 0);\n        // //////////////////////////////////\n        // Setup Camera Manipulator\n        const processBGValue = () => {\n            const value = this.backgroundColorParam.value;\n            if (value instanceof BaseImage) {\n                if (value instanceof HDRImage) {\n                    this.__backgroundTexture = value;\n                    this.__backgroundGLTexture = new GLHDRImage(gl, value);\n                }\n                else {\n                    this.__backgroundTexture = value;\n                    this.__backgroundGLTexture = new GLTexture2D(gl, value);\n                }\n            }\n            else if (value instanceof Color) {\n                if (this.__backgroundGLTexture) {\n                    this.__backgroundGLTexture.destroy();\n                    this.__backgroundGLTexture = null;\n                    this.__backgroundTexture = null;\n                }\n                if (this.offscreenBufferFbo) {\n                    this.offscreenBufferFbo.clearColor = value;\n                }\n            }\n            else {\n                console.warn('Invalid background:' + value);\n            }\n            this.emit('updated');\n        };\n        processBGValue();\n        this.backgroundColorParam.on('valueChanged', processBGValue);\n    }\n    /**\n     * Returns the renderer this viewport is bound to.\n     */\n    getRenderer() {\n        return this.renderer;\n    }\n    /**\n     * The getWidth method.\n     * @return - The return value.\n     */\n    getWidth() {\n        return this.width;\n    }\n    /**\n     * The getHeight method.\n     * @return - The return value.\n     */\n    getHeight() {\n        return this.height;\n    }\n    /**\n     * The resize method.\n     * @param canvasWidth - The canvasWidth value.\n     * @param canvasHeight - The canvasHeight value.\n     */\n    resize(canvasWidth, canvasHeight) {\n        if (this.__canvasWidth == canvasWidth && this.__canvasHeight == canvasHeight)\n            return;\n        this.__canvasWidth = canvasWidth;\n        this.__canvasHeight = canvasHeight;\n        this.width = canvasWidth;\n        this.height = canvasHeight;\n        this.region = [0, 0, this.width, this.height];\n        this.resizeRenderTargets(canvasWidth, canvasHeight);\n        const event = new ResizedEvent(this.width, this.height);\n        this.emit('resized', event);\n    }\n    /**\n     * Resize any offscreen render targets.\n     * > Note: Values ,ay not be the entire canvas with if multiple viewports exists.\n     * @param width - The width used by this viewport.\n     * @param height - The height  used by this viewport.\n     */\n    resizeRenderTargets(width, height) {\n        if (this.highlightedGeomsBufferFbo) {\n            // Note: on mobile devices the screen width * devicePixelRatio is bigger than the max texture size.\n            // We don't need a high-dpi highlightedGeomsBufferFbo\n            this.highlightedGeomsBufferFbo.resize(width / devicePixelRatio, height / devicePixelRatio);\n        }\n        const gl = this.__renderer.gl;\n        if (this.renderer.outlineThickness > 0 && this.renderer.outlineMethod == 'image') {\n            const disableOnSafari = SystemDesc.browserName == 'Safari';\n            // Note: On low end devices, such as Oculus, blitting the multi-sampled depth buffer is throwing errors,\n            // and so we are simply disabling silhouettes on all low end devices now.\n            if (disableOnSafari || gl.name == 'webgl') {\n                console.warn('Disabling outlines on Safari due to a regression in WebKit', SystemDesc);\n                return;\n            }\n            if (this.fb) {\n                gl.deleteFramebuffer(this.fb[FRAMEBUFFER.MSAA_RENDERBUFFER]);\n                gl.deleteFramebuffer(this.fb[FRAMEBUFFER.COLORBUFFER]);\n                gl.deleteFramebuffer(this.fb[FRAMEBUFFER.DEPTHBUFFER]);\n                if (this.colorRenderbuffer)\n                    gl.deleteRenderbuffer(this.colorRenderbuffer);\n                if (this.depthBuffer)\n                    gl.deleteRenderbuffer(this.depthBuffer);\n            }\n            // //////////////////////////////////\n            // Setup Offscreen Render Targets\n            // Note: On low end devices, such as Oculus, blitting the multi-sampled depth buffer is throwing errors,\n            // and so we are simply disabling silhouettes on all low end devices now.\n            if (!this.offscreenBuffer || !this.depthTexture) {\n                this.offscreenBuffer = new GLTexture2D(gl, {\n                    type: 'UNSIGNED_BYTE',\n                    format: 'RGBA',\n                    filter: 'LINEAR',\n                    width: 4,\n                    height: 4,\n                });\n                this.depthTexture = new GLTexture2D(gl, {\n                    type: gl.UNSIGNED_INT_24_8,\n                    format: gl.DEPTH_STENCIL,\n                    internalFormat: gl.name == 'webgl' ? gl.DEPTH24_STENCIL8 : gl.DEPTH_COMPONENT,\n                    filter: gl.NEAREST,\n                    wrap: gl.CLAMP_TO_EDGE,\n                    width: 4,\n                    height: 4,\n                });\n            }\n            else {\n                this.offscreenBuffer.resize(width, height);\n                this.depthTexture.resize(width, height);\n            }\n            // Create and bind the framebuffer\n            this.fb = [];\n            this.fb[FRAMEBUFFER.MSAA_RENDERBUFFER] = gl.createFramebuffer();\n            gl.bindFramebuffer(gl.FRAMEBUFFER, this.fb[FRAMEBUFFER.MSAA_RENDERBUFFER]);\n            this.colorRenderbuffer = gl.createRenderbuffer();\n            // Create the color buffer\n            gl.bindRenderbuffer(gl.RENDERBUFFER, this.colorRenderbuffer);\n            // iOS devices have trouble with Multisample render buffers\n            if (this.renderer.multiSampledScreenBuffer)\n                gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA8, width, height);\n            else\n                gl.renderbufferStorageMultisample(gl.RENDERBUFFER, 4, gl.RGBA8, width, height);\n            gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, this.colorRenderbuffer);\n            this.depthBuffer = gl.createRenderbuffer();\n            gl.bindRenderbuffer(gl.RENDERBUFFER, this.depthBuffer);\n            if (this.renderer.multiSampledScreenBuffer)\n                gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH24_STENCIL8, width, height);\n            else\n                gl.renderbufferStorageMultisample(gl.RENDERBUFFER, 4, gl.DEPTH24_STENCIL8, width, height);\n            gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, this.depthBuffer);\n            // //////////////////////////////////\n            // COLORBUFFER\n            this.fb[FRAMEBUFFER.COLORBUFFER] = gl.createFramebuffer();\n            gl.bindFramebuffer(gl.FRAMEBUFFER, this.fb[FRAMEBUFFER.COLORBUFFER]);\n            gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.offscreenBuffer.glTex, 0);\n            gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n            // //////////////////////////////////\n            // DEPTHBUFFER\n            // Create the depth texture that will be bitted to.\n            this.fb[FRAMEBUFFER.DEPTHBUFFER] = gl.createFramebuffer();\n            gl.bindFramebuffer(gl.FRAMEBUFFER, this.fb[FRAMEBUFFER.DEPTHBUFFER]);\n            gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, this.depthTexture.glTex, 0);\n            gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n            const check = gl.checkFramebufferStatus(gl.name == 'webgl' ? gl.DRAW_FRAMEBUFFER : gl.FRAMEBUFFER);\n            if (check !== gl.FRAMEBUFFER_COMPLETE) {\n                switch (check) {\n                    case gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT:\n                        throw new Error('The attachment types are mismatched or not all framebuffer attachment points are framebuffer attachment complete.');\n                    case gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:\n                        throw new Error('There is no attachment.');\n                    case gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS:\n                        throw new Error('Height and width of the attachment are not the same.');\n                    case gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS:\n                        throw new Error('The format of the attachment is not supported or if depth and stencil attachments are not the same renderbuffer.');\n                    case 36061: // gl.GL_FRAMEBUFFER_UNSUPPORTED:\n                        throw new Error('The framebuffer is unsupported');\n                    default:\n                        throw new Error('Incomplete Frambuffer');\n                }\n            }\n        }\n    }\n    /**\n     * The draw method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    draw(renderstate) {\n        const gl = this.__renderer.gl;\n        renderstate.pushGLStack('GLBaseViewport.draw');\n        const prevRendertarget = renderstate.boundRendertarget;\n        if (this.renderer.outlineThickness > 0 && this.renderer.outlineMethod == 'image') {\n            const disableOnSafari = SystemDesc.browserName == 'Safari';\n            if (disableOnSafari || gl.name == 'webgl') {\n                console.warn('Disabling outlines on Safari due to a regression in WebKit', SystemDesc);\n            }\n            else {\n                if (!this.fb)\n                    this.resizeRenderTargets(this.width, this.height);\n                const frameBuffer = this.fb[FRAMEBUFFER.MSAA_RENDERBUFFER];\n                gl.bindFramebuffer(gl.name == 'webgl' ? gl.DRAW_FRAMEBUFFER : gl.FRAMEBUFFER, frameBuffer);\n                renderstate.boundRendertarget = frameBuffer;\n            }\n        }\n        else {\n            // Make sure the default fbo is bound\n            // Note: boundRendertarget will be set during a WebXR session\n            // Note: Sometimes an Fbo is left bound\n            // from another op(like resizing, populating etc..)\n            // We need to unbind here to ensure rendering is to the\n            // right target.\n            if (!renderstate.boundRendertarget)\n                gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n        }\n        renderstate.glEnable(gl.DEPTH_TEST);\n        this.__renderer.drawScene(renderstate);\n        const highlightRenderState = renderstate.toHighlightRenderState();\n        this.drawHighlights(highlightRenderState);\n        if (highlightRenderState.stack.length != 0) {\n            console.warn(' corrupt highlightRenderState.stack.length:', highlightRenderState.stack.length);\n        }\n        // //////////////////////////////////\n        // Post processing.\n        if (this.fb) {\n            // \"blit\" the scene into the color buffer\n            gl.bindFramebuffer(gl.READ_FRAMEBUFFER, this.fb[FRAMEBUFFER.MSAA_RENDERBUFFER]);\n            gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, this.fb[FRAMEBUFFER.COLORBUFFER]);\n            gl.clearBufferfv(gl.COLOR, 0, [0.0, 0.0, 0.0, 0.0]);\n            gl.blitFramebuffer(0, 0, this.width, this.height, 0, 0, this.width, this.height, gl.COLOR_BUFFER_BIT, gl.LINEAR);\n            gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, prevRendertarget);\n            renderstate.boundRendertarget = prevRendertarget;\n            gl.viewport(this.region[0], this.region[1], this.region[2], this.region[3]);\n            gl.disable(gl.DEPTH_TEST);\n            const screenQuad = this.__renderer.screenQuad;\n            screenQuad.bindShader(renderstate);\n            screenQuad.draw(renderstate, this.offscreenBuffer);\n            gl.enable(gl.DEPTH_TEST);\n        }\n        renderstate.popGLStack();\n        this.renderer.emit('redrawOccurred');\n    }\n    /**\n     * Draws the Silhouettes around geometries.\n     * @param renderstate - The object tracking the current state of the renderer\n     * @private\n     */\n    drawSilhouettes(renderstate) {\n        renderstate.pushGLStack('GLBaseViewport.drawSilhouettes');\n        // We cannot render silhouettes in iOS because EXT_frag_depth is not supported\n        // and without it, we cannot draw lines over the top of geometries.\n        // Note: On low end devices, such as Oculus, blitting the multi-sampled depth buffer is throwing errors,\n        // and so we are simply disabling silhouettes on all low end devices now.\n        const gl = this.__renderer.gl;\n        gl.bindFramebuffer(gl.READ_FRAMEBUFFER, this.fb[FRAMEBUFFER.MSAA_RENDERBUFFER]);\n        gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, this.fb[FRAMEBUFFER.DEPTHBUFFER]);\n        gl.clearBufferfv(gl.COLOR, 0, [1, 1, 1, 1]);\n        gl.blitFramebuffer(0, 0, this.width, this.height, 0, 0, this.width, this.height, gl.DEPTH_BUFFER_BIT, gl.NEAREST);\n        // Rebind the MSAA RenderBuffer.\n        gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, this.fb[FRAMEBUFFER.MSAA_RENDERBUFFER]);\n        renderstate.boundRendertarget = this.fb[FRAMEBUFFER.MSAA_RENDERBUFFER];\n        gl.viewport(this.region[0], this.region[1], this.region[2], this.region[3]);\n        // ////////////////////////////////////\n        //\n        renderstate.glEnable(gl.BLEND);\n        renderstate.glDisable(gl.DEPTH_TEST);\n        gl.blendEquation(gl.FUNC_ADD);\n        gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ZERO, gl.ONE);\n        gl.depthMask(false);\n        this.renderer.silhouetteShader.bind(renderstate);\n        const unifs = renderstate.unifs;\n        this.depthTexture.bindToUniform(renderstate, unifs.depthTexture);\n        gl.uniform2f(unifs.screenSize.location, this.width, this.height);\n        gl.uniform1f(unifs.outlineThickness.location, this.renderer.outlineThickness * window.devicePixelRatio);\n        const oc = this.renderer.outlineColor.asArray();\n        gl.uniform4f(unifs.outlineColor.location, oc[0], oc[1], oc[2], oc[3]);\n        gl.uniform1f(unifs.outlineSensitivity.location, this.renderer.outlineSensitivity);\n        gl.uniform1f(unifs.outlineDepthBias.location, this.renderer.outlineDepthBias);\n        gl.uniform2f(unifs.depthRange.location, this.depthRange[0], this.depthRange[1]);\n        this.quad.bindAndDraw(renderstate);\n        gl.depthMask(true);\n        renderstate.popGLStack();\n    }\n    /**\n     * Draws the highlights around geometries.\n     * @param renderstate - The object tracking the current state of the renderer\n     * @private\n     */\n    drawHighlights(renderstate) {\n        if (this.highlightedGeomsBufferFbo) {\n            const gl = this.__renderer.gl;\n            renderstate.pushGLStack('GLBaseViewport.drawHighlights');\n            this.highlightedGeomsBufferFbo.bindForWriting(renderstate, true);\n            // Highlighted geoms should always be rendered 2-sided\n            renderstate.glEnable(gl.CULL_FACE);\n            renderstate.glEnable(gl.DEPTH_TEST);\n            renderstate.glDisable(gl.BLEND);\n            gl.depthFunc(gl.LESS);\n            gl.depthMask(true);\n            renderstate.glShader = null; // clear any bound shaders.\n            this.__renderer.drawHighlightedGeoms(renderstate);\n            // Unbind and restore the bound fbo\n            this.highlightedGeomsBufferFbo.unbindForWriting(renderstate);\n            // Now render the outlines to the entire screen.\n            gl.viewport(this.region[0], this.region[1], this.region[2], this.region[3]);\n            {\n                renderstate.pushGLStack('GLBaseViewport.drawHighlights.highlightsShader');\n                this.renderer.highlightsShader.bind(renderstate);\n                renderstate.glEnable(gl.BLEND);\n                gl.blendEquation(gl.FUNC_ADD);\n                gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE);\n                const unifs = renderstate.unifs;\n                gl.uniform1f(unifs.outlineThickness.location, this.renderer.highlightOutlineThickness);\n                this.highlightedGeomsBufferFbo.bindColorTexture(renderstate, unifs.highlightDataTexture);\n                this.quad.bindAndDraw(renderstate);\n                renderstate.popGLStack();\n            }\n            renderstate.popGLStack();\n        }\n    }\n    // ///////////////////////////\n    // Events\n    /**\n     * The getManipulator method.\n     * @return - The return value.\n     */\n    getManipulator() {\n        return this.manipulator;\n    }\n    /**\n     * Sets the tool that will receive mouse, touch and keyboard events from the viewport.\n     * @param tool - The manipulator value.\n     */\n    setManipulator(tool) {\n        if (this.manipulator != tool) {\n            if (this.manipulator && this.manipulator.deactivateTool) {\n                this.manipulator.deactivateTool();\n            }\n            this.manipulator = tool;\n            if (this.manipulator.activateTool) {\n                this.manipulator.activateTool();\n            }\n        }\n    }\n    /**\n     * Handler of the `pointerdown` event fired when the pointer device is initially pressed.\n     *\n     * @param event - The DOM event produced by a pointer\n     */\n    onPointerDown(event) {\n        console.warn('@GLBaseViewport#onPointerDown - Implement me!');\n    }\n    /**\n     * Handler of the `pointerup` event fired when the pointer device is finally released.\n     *\n     * @param event - The DOM event produced by a pointer\n     */\n    onPointerUp(event) {\n        console.warn('@GLBaseViewport#onPointerUp - Implement me!');\n    }\n    /**\n     * Handler of the `pointermove` event fired when the pointer device changes coordinates, and the pointer has not been cancelled\n     *\n     * @param event - The DOM event produced by a pointer\n     */\n    onPointerMove(event) {\n        console.warn('@GLBaseViewport#onPointerMove - Implement me!');\n    }\n    /**\n     * Invoked when the mouse pointer is moved into this viewport.\n     *\n     * @param event - The DOM event produced by a pointer\n     */\n    onPointerEnter(event) {\n        console.warn('@GLBaseViewport#onPointerEnter - Implement me!');\n    }\n    /**\n     * Invoked when the mouse pointer is moved out of this viewport.\n     *\n     * @param event - The DOM event produced by a pointer\n     */\n    onPointerLeave(event) {\n        console.warn('@GLBaseViewport#onPointerLeave - Implement me!');\n    }\n    /**\n     * Invoked when the mouse pointer is moved out of an element.\n     * @param event - The event that occurs.\n     */\n    onMouseLeave(event) { }\n    /**\n     * Invoked when the user is pressing a key on the keyboard.\n     * @param event - The event that occurs.\n     */\n    onKeyDown(event) { }\n    /**\n     * Causes an event to occur  when the user releases a key on the keyboard.\n     * @param event - The event that occurs.\n     */\n    onKeyUp(event) { }\n}\n\n/* eslint-disable guard-for-in */\n/**\n * Class representing a GL viewport.\n *\n * **Events**\n * * **resized:** Emitted when the GLViewport resizes\n * * **updated:** Emitted when the GLViewport needs updating. The Renderer will trigger a redraw when this occurs.\n * * **viewChanged:** Emitted when the view changes. Usually caused by the camera moving.\n * * **pointerDoubleClick:** Emitted when the user double clicks with the mouse, or double taps in the viewport.\n * * **pointerDown:** Emitted when the user presses a pointer\n * * **pointerUp:** Emitted when the user releases a pointer\n * * **pointerEnterGeom:** Emitted when the pointer is moved over a geometry\n * * **pointerLeaveGeom:** Emitted when the pointer is moved off a geometry\n * * **pointerMove:** Emitted when the pointer is moved\n * * **pointerEnter:** Emitted when the pointer is moved into thg viewport\n * * **pointerLeave:** Emitted when the mouse leaves the viewport.\n * * **pointerClick:** Emitted when a pointer is clicked on an item.\n * * **pointerLongPress:** Emitted when a pointer is clicked and held on an item for a long time.\n * * **keyDown:** Emitted when the user presses a key on the keyboard\n * * **keyUp:** Emitted when the user releases a key on the keyboard\n * * **touchCancel:** Emitted when the user cancels a touch interaction\n *\n * @extends GLBaseViewport\n */\nclass GLViewport extends GLBaseViewport {\n    debugGeomDataBuffer = false;\n    pointAndLinePickingSize = 3;\n    debugOcclusionBuffer = false;\n    debugReductionBuffer = false;\n    debugHighlightedGeomsBuffer = false;\n    // To enable picking small items, we enable searching an area around the click point\n    // for the closest item. Reduce the size of this value if\n    mousePointerSearchArea = 5;\n    // To enable picking small items, we enable searching an area around the touch point\n    // for the closest item. This value approximates the size of the touch area.\n    // The picking system will return the closest item to the camera within this search area.\n    // To enable precise surface placement, this value should be reduced to a value such as 1.\n    touchPointerSearchArea = 45;\n    projectionMatrix;\n    viewportFrustum;\n    camera;\n    bottomLeftCoords = new Vec2(0, 0);\n    topRightCoords = new Vec2(1, 1);\n    posX = 0;\n    posY = 0;\n    pointerDownTime = [];\n    pointerDownButton = -1;\n    pointerDownPos = new Vec2(-1, -1);\n    prevClickTime;\n    prevClickPos = new Vec2(-1, -1);\n    prevClickButton = -1;\n    geomDataBufferSizeFactor = window.devicePixelRatio;\n    geomDataRenderTarget;\n    geomDataBufferInvalid = true;\n    cameraXfo = new Xfo();\n    cameraMat = new Mat4();\n    viewMatrix = new Mat4();\n    screenPos = null;\n    intersectionData;\n    pointerOverItem;\n    longPressId;\n    /**\n     * Create a GL viewport.\n     * @param renderer - The renderer value.\n     * @param name - The name value.\n     * @param width - The width of the viewport\n     * @param height - The height of the viewport\n     */\n    constructor(renderer, name, width, height) {\n        super(renderer);\n        this.name = name;\n        this.projectionMatrix = new Mat4();\n        this.viewportFrustum = new Vec4();\n        // Layout coords, x:[0..1], y:[0..1]\n        this.bottomLeftCoords = new Vec2(0, 0);\n        this.topRightCoords = new Vec2(1, 1);\n        this.prevClickTime = 0;\n        // //////////////////////////////////\n        // Setup GeomData Fbo\n        if (SystemDesc.isMobileDevice) {\n            this.geomDataBufferSizeFactor = 8;\n        }\n        const gl = this.__renderer.gl;\n        this.geomDataRenderTarget = new GLRenderTarget(gl, {\n            type: renderer.floatGeomBuffer ? gl.FLOAT : gl.UNSIGNED_BYTE,\n            format: gl.RGBA,\n            filter: gl.NEAREST,\n            width: width <= 1 ? 1 : Math.floor(width / this.geomDataBufferSizeFactor),\n            height: height <= 1 ? 1 : Math.floor(height / this.geomDataBufferSizeFactor),\n            createDepthTexture: true,\n        });\n        this.geomDataRenderTarget.clearColor = new Color(0, 0, 0, 0);\n        // //////////////////////////////////\n        // Setup Camera Manipulator\n        // Each user has a separate camera, and so the default\n        //  camera cannot be part of the scene.\n        this.camera = new Camera('DefaultCamera');\n        this.setCamera(this.camera);\n        this.setManipulator(new CameraManipulator({ renderer }));\n        this.resize(width, height);\n    }\n    /**\n     * The getBl method.\n     * @return - The return value.\n     */\n    getBl() {\n        return this.bottomLeftCoords;\n    }\n    /**\n     * The setBl method.\n     * @param bl - The bl value.\n     */\n    setBl(bl) {\n        this.bottomLeftCoords = bl;\n        this.#updateLayout();\n    }\n    /**\n     * The getTr method.\n     * @return - The return value.\n     */\n    getTr() {\n        return this.topRightCoords;\n    }\n    /**\n     * The setTr method.\n     * @param tr - The tr value.\n     */\n    setTr(tr) {\n        this.topRightCoords = tr;\n        this.#updateLayout();\n    }\n    /**\n     * The getPosX method.\n     * @return - The return value.\n     */\n    getPosX() {\n        return this.posX;\n    }\n    /**\n     * The getPosY method.\n     * @return - The return value.\n     */\n    getPosY() {\n        return this.posY;\n    }\n    /**\n     * Dynamically resizes viewport.\n     *\n     * @param canvasWidth - The canvasWidth value.\n     * @param canvasHeight - The canvasHeight value.\n     */\n    resize(canvasWidth, canvasHeight) {\n        this.__canvasWidth = canvasWidth;\n        this.__canvasHeight = canvasHeight;\n        this.#updateLayout();\n    }\n    #updateLayout() {\n        this.posX = Math.round(this.__canvasWidth * this.bottomLeftCoords.x);\n        this.posY = Math.round(this.__canvasWidth * this.bottomLeftCoords.y);\n        this.width = Math.round(this.__canvasWidth * this.topRightCoords.x - this.__canvasWidth * this.bottomLeftCoords.x);\n        this.height = Math.round(this.__canvasHeight * this.topRightCoords.y - this.__canvasHeight * this.bottomLeftCoords.y);\n        this.region = [this.posX, this.posY, this.width, this.height];\n        if (this.camera)\n            this.updateProjectionMatrix();\n        this.resizeRenderTargets(this.width, this.height);\n        const event = new ResizedEvent(this.width, this.height);\n        this.emit('resized', event);\n    }\n    /**\n     * Resize any offscreen render targets.\n     * > Note: Values ,ay not be the entire canvas with if multiple viewports exists.\n     * @param width - The width used by this viewport.\n     * @param height - The height  used by this viewport.\n     */\n    resizeRenderTargets(width, height) {\n        super.resizeRenderTargets(width, height);\n        if (this.geomDataRenderTarget) {\n            this.geomDataRenderTarget.resize(Math.floor(this.width / this.geomDataBufferSizeFactor), Math.floor(this.height / this.geomDataBufferSizeFactor));\n            this.invalidateGeomDataBuffer();\n        }\n    }\n    /**\n     * Returns current camera object\n     *\n     * @return - The return value.\n     */\n    getCamera() {\n        return this.camera;\n    }\n    /**\n     * Sets current camera object\n     *\n     * @param camera - The camera value.\n     */\n    setCamera(camera) {\n        this.camera = camera;\n        this.depthRange = [this.camera.getNear(), this.camera.getFar()];\n        const globalXfoParam = camera.globalXfoParam;\n        const getCameraParams = () => {\n            this.cameraXfo = globalXfoParam.value;\n            this.cameraMat = this.cameraXfo.toMat4();\n            this.viewMatrix = this.cameraMat.inverse();\n        };\n        getCameraParams();\n        globalXfoParam.on('valueChanged', () => {\n            getCameraParams();\n            this.emit('updated');\n            this.invalidateGeomDataBuffer();\n            const event = new ViewChangedEvent('CameraAndPointer', this.cameraXfo);\n            this.emit('viewChanged', event);\n        });\n        this.camera.on('projectionParamChanged', () => {\n            this.updateProjectionMatrix();\n            this.depthRange = [this.camera.getNear(), this.camera.getFar()];\n            this.emit('updated');\n        });\n        this.updateProjectionMatrix();\n    }\n    // eslint-disable-next-line require-jsdoc\n    updateProjectionMatrix() {\n        const aspect = this.width / this.height;\n        this.camera.updateProjectionMatrix(this.projectionMatrix, aspect);\n        const flocalDist = this.camera.getFocalDistance();\n        const fovY = this.camera.getFov();\n        const isOrthographic = this.camera.isOrthographicParam.value;\n        const frustumHPersp = Math.tan(fovY / 2.0) * flocalDist * 2.0;\n        const frustumWPersp = frustumHPersp * aspect;\n        const frustumHOrtho = this.camera.getFrustumHeight();\n        const frustumWOrtho = frustumHPersp * aspect;\n        this.viewportFrustum.set(MathFunctions.lerp(frustumWPersp, frustumWOrtho, isOrthographic), MathFunctions.lerp(frustumHPersp, frustumHOrtho, isOrthographic), flocalDist, fovY);\n    }\n    /**\n     * The getProjectionMatrix method.\n     * @return - The return projection matrix for the viewport.\n     */\n    getProjectionMatrix() {\n        return this.projectionMatrix;\n    }\n    /**\n     * The getProjectionMatrix method.\n     * @return - The return projection matrix for the viewport.\n     */\n    getViewMatrix() {\n        return this.viewMatrix;\n    }\n    /**\n     * Calculates a new camera position that frames all the items passed in `treeItems` array, moving\n     * the camera to a point where we can see all of them.\n     * > See Camera.frameView\n     * @param treeItems - The array of TreeItem.\n     * @param duration - The duration of time to apply the frame. A value of 0 specifies an instantaneous movement of the camera.\n     * @param frameBorder - The variable to use to provide an empty space around the border for geometries.\n     */\n    frameView(treeItems, duration = 0, frameBorder = 0.1) {\n        if (this.width > 0 && this.height > 0) {\n            this.camera.frameView(this.width, this.height, treeItems, duration, frameBorder);\n        }\n        else {\n            // Sometimes thew renderer is not yet setup, so here we\n            // wait till the window is resized and try again.\n            this.once('resized', () => this.frameView(treeItems, duration, frameBorder));\n        }\n    }\n    /**\n     * Compute the screen space position of an item from a world space coordinate.\n     * @param screenPos - The screen position.\n     * @return - The return value.\n     */\n    calcScreenPosFromWorldPos(worldPos) {\n        const viewProjMatrix = this.projectionMatrix.multiply(this.viewMatrix);\n        const projSpacePos = viewProjMatrix.transformVec4(new Vec4(worldPos.x, worldPos.y, worldPos.z, 1));\n        // perspective divide\n        projSpacePos.x /= projSpacePos.w;\n        projSpacePos.y /= projSpacePos.w;\n        return new Vec2((projSpacePos.x * 0.5 + 0.5) * this.width, (projSpacePos.y * -0.5 + 0.5) * this.height);\n    }\n    /**\n     * Compute a ray into the scene based on a mouse coordinate.\n     * @param screenPos - The screen position.\n     * @return - The return value.\n     */\n    calcRayFromScreenPos(screenPos) {\n        // Convert the raster coordinates to screen space ([0,{w|h}] -> [-1,1]\n        // - Note: The raster vertical is inverted wrt OGL screenspace Y\n        const x_pixelPos = screenPos.x * window.devicePixelRatio;\n        const y_pixelPos = screenPos.y * window.devicePixelRatio;\n        const top_y = this.__canvasHeight * (1.0 - this.topRightCoords.y);\n        // sx /sy range from -1 ... +1\n        const sx = ((x_pixelPos - this.posX) / this.width) * 2.0 - 1.0;\n        const sy = ((y_pixelPos - top_y) / this.height) * 2.0 - 1.0;\n        // Transform the origin from camera local to world space\n        const cameraMat = this.cameraMat;\n        const projInv = this.projectionMatrix.inverse();\n        if (projInv == null) {\n            // Sometimes this happens, not sure why...\n            console.warn(`Unable to generate Ray from screen pos:${screenPos.toString()} in region ${this.region}`);\n            return new Ray();\n        }\n        let rayStart;\n        let rayDirection;\n        if (this.camera.isOrthographic()) {\n            // Orthographic projections.\n            const cameraSpaceOffset = projInv.transformVec3(new Vec3(sx, -sy, -1.0));\n            cameraSpaceOffset.z = 0;\n            rayStart = cameraMat.transformVec3(cameraSpaceOffset);\n            rayDirection = new Vec3(0.0, 0.0, -1.0);\n        }\n        else {\n            rayStart = cameraMat.translation;\n            // Get the projected window coordinate on the near plane\n            // See http://www.songho.ca/opengl/gl_projectionmatrix.html\n            // for details.\n            rayDirection = projInv.transformVec3(new Vec3(sx, -sy, -1.0));\n        }\n        // And from projection space to camera local.\n        // - We nuke the translation part since we're transforming a vector.\n        rayDirection = cameraMat.rotateVec3(rayDirection).normalize();\n        return new Ray(rayStart, rayDirection);\n    }\n    // //////////////////////////\n    // GeomData\n    /**\n     * Renders the scene geometry to the viewport's geom data buffer\n     * in preparation for mouse picking.\n     */\n    renderGeomDataFbo() {\n        if (this.geomDataRenderTarget) {\n            const geomDataRenderstate = new GeomDataRenderState(this.renderer.__gl);\n            geomDataRenderstate.pushGLStack('GLViewport.renderGeomDataFbo');\n            this.bindGLViewport(geomDataRenderstate);\n            // Note: GLLinesPass binds a new Fbo, but shares this ones depth buffer.\n            geomDataRenderstate.geomDataFbo = this.geomDataRenderTarget;\n            geomDataRenderstate.debugGeomDataBuffer = this.debugGeomDataBuffer;\n            geomDataRenderstate.pointAndLinePickingSize = this.pointAndLinePickingSize;\n            this.geomDataRenderTarget.bindForWriting(geomDataRenderstate, true);\n            this.__renderer.drawSceneGeomData(geomDataRenderstate);\n            this.geomDataRenderTarget.unbindForWriting();\n            geomDataRenderstate.popGLStack();\n            this.geomDataBufferInvalid = false;\n        }\n    }\n    /**\n     * The invalidateGeomDataBuffer method.\n     */\n    invalidateGeomDataBuffer() {\n        this.geomDataBufferInvalid = true;\n    }\n    /**\n     * The getGeomDataAtPos method.\n     * @param screenPos - The screen position.\n     * @param pointerRay - The pointerRay value.\n     * @return - The return value.\n     */\n    getGeomDataAtPos(screenPos, pointerRay, searchArea = 5) {\n        if (this.geomDataRenderTarget) {\n            if (this.geomDataBufferInvalid) {\n                this.renderGeomDataFbo();\n                this.screenPos = null;\n            }\n            // Cache the intersection tests result so subsequent queries will return the same value.\n            // Note: every new mouse event will generate a new pointerPos value, so the cache\n            // is only valid for a given event propagation, and for that exact pointerPos value.\n            if (screenPos === this.screenPos) {\n                return this.intersectionData;\n            }\n            this.screenPos = screenPos;\n            this.intersectionData = null;\n            const gl = this.__renderer.gl;\n            gl.finish();\n            this.geomDataRenderTarget.bindForReading();\n            // const logGeomData = ()=>{\n            //     console.log(\"logGeomData :[\" + this.geomDataRenderTarget.width +\",\"+ this.geomDataRenderTarget.height + \"]\")\n            //     const pixels = new Float32Array(this.geomDataRenderTarget.width * 4);\n            //     for(let i=0; i<this.geomDataRenderTarget.height; i++){\n            //       gl.readPixels(0, i, this.geomDataRenderTarget.width, 1, gl.RGBA, gl.FLOAT, pixels);\n            //         for(let j=0; j<this.geomDataRenderTarget.width; j++){\n            //             const geomData = pixels.subarray(j*4, (j+1)*4);\n            //             if (geomData[0] != 0 || geomData[1] != 0){\n            //                 console.log(j, i)\n            //                 break; // Only log the left border pixels.\n            //             }\n            //         }\n            //       // console.log(pixels);\n            //     }\n            // }\n            // logGeomData();\n            // console.log(\"getGeomDataAtPos:\", screenPos.toString(), screenPos.x,this.width)\n            const x_pixelPos = screenPos.x * window.devicePixelRatio;\n            const y_pixelPos = screenPos.y * window.devicePixelRatio;\n            const numPixels = searchArea * searchArea;\n            const bufferWidth = this.geomDataRenderTarget.width;\n            const bufferHeight = this.geomDataRenderTarget.height;\n            const x = Math.floor(x_pixelPos * (bufferWidth / this.width)) - searchArea * 0.5;\n            const y = Math.floor(bufferHeight - y_pixelPos * (bufferHeight / this.height) - 1) - searchArea * 0.5;\n            // Allocate a 5x5 pixel block and read from the GeomData buffer.\n            const geomDatas = new Float32Array(4 * numPixels);\n            gl.readPixels(x, y, searchArea, searchArea, gl.RGBA, gl.FLOAT, geomDatas);\n            this.geomDataRenderTarget.unbindForReading();\n            let geomData;\n            let geomItemAndDist = null;\n            const componentIds = new Map();\n            // ////////////////////////////////////\n            // scan to find the closest geom\n            const checkPixel = (id) => {\n                // Mask the first 2 bits of the 'red' channel for the pass Id.\n                // This allows some passes to pack more data into the 'red' channel\n                const passId = Math.round(geomDatas[id * 4 + 0]) & 0x3f;\n                const pass = this.__renderer.getPass(passId);\n                if (!pass) {\n                    console.warn('Geom data buffer returns invalid pass id:', passId);\n                    return null;\n                }\n                geomData = geomDatas.slice(id * 4, (id + 1) * 4);\n                geomItemAndDist = pass.getGeomItemAndDist(geomData);\n                if (geomItemAndDist) {\n                    return true;\n                }\n                return false;\n            };\n            // Start at the middle pixel and scan outward looking for a valid pixel.\n            const searchRadius = searchArea / 2;\n            for (let i = 0; i < searchRadius && !geomItemAndDist; i++) {\n                for (let x = -i; x <= i && !geomItemAndDist; x++) {\n                    for (let y = -i; y <= i && !geomItemAndDist; y++) {\n                        const xTmp = searchRadius + x;\n                        const yTmp = searchRadius + x;\n                        const pixelId = xTmp + yTmp * searchArea;\n                        if (checkPixel(pixelId))\n                            break;\n                    }\n                }\n            }\n            if (!pointerRay)\n                pointerRay = this.calcRayFromScreenPos(screenPos);\n            if (geomItemAndDist) {\n                const intersectionPos = pointerRay.start.add(pointerRay.dir.scale(geomItemAndDist.dist));\n                this.intersectionData = new IntersectionData(screenPos, pointerRay, intersectionPos, geomData, geomItemAndDist);\n                if (componentIds.has(geomItemAndDist.geomItem)) {\n                    this.intersectionData.componentIds = Array.from(componentIds.get(geomItemAndDist.geomItem));\n                }\n            }\n            return this.intersectionData;\n        }\n        return null;\n    }\n    /**\n     * this method returns an object containing an array of geomitems, and an array of count values in\n     * the form of a histogram. The results are sorted by count, so the first items are the most visible,\n     * down to the least visible.\n     * @param tl - The top left value of the rectangle.\n     * @param br - The bottom right corner of the rectangle.\n     * @return - The return value.\n     */\n    getGeomVisiblity(tl, br) {\n        if (this.geomDataRenderTarget) {\n            if (this.geomDataBufferInvalid) {\n                this.renderGeomDataFbo();\n                this.screenPos = null;\n            }\n            const gl = this.__renderer.gl;\n            gl.finish();\n            // Allocate a pixel block.\n            const bufferWidth = this.geomDataRenderTarget.width;\n            const bufferHeight = this.geomDataRenderTarget.height;\n            const widthFactor = bufferWidth / this.width;\n            const heightFactor = bufferHeight / this.height;\n            const tlX = Math.round(tl.x * widthFactor);\n            const tlY = Math.round(tl.y * heightFactor);\n            const brX = Math.round(br.x * widthFactor);\n            const brY = Math.round(br.y * heightFactor);\n            const rectBottom = Math.round(bufferHeight - brY);\n            const rectLeft = Math.round(tlX);\n            const rectWidth = Math.round(brX - tlX);\n            const rectHeight = Math.round(brY - tlY);\n            const numPixels = rectWidth * rectHeight;\n            this.geomDataRenderTarget.bindForReading();\n            let geomDatas;\n            if (this.__renderer.floatGeomBuffer) {\n                geomDatas = new Float32Array(4 * numPixels);\n                gl.readPixels(rectLeft, rectBottom, rectWidth, rectHeight, gl.RGBA, gl.FLOAT, geomDatas);\n            }\n            else {\n                geomDatas = new Uint8Array(4 * numPixels);\n                gl.readPixels(rectLeft, rectBottom, rectWidth, rectHeight, gl.RGBA, gl.UNSIGNED_BYTE, geomDatas);\n            }\n            this.geomDataRenderTarget.unbindForReading();\n            const geomItems = [];\n            const histogram = [];\n            const keys = new Map();\n            for (let i = 0; i < numPixels; i++) {\n                let passId;\n                const geomData = geomDatas.subarray(i * 4, (i + 1) * 4);\n                if (this.__renderer.floatGeomBuffer) {\n                    if (geomData[3] == 0)\n                        continue;\n                    // Mask the first 2 bits of the 'red' channel for the pass Id.\n                    // This allows some passes to pack more data into the 'red' channel\n                    passId = Math.round(geomData[0]) & 0x3f;\n                }\n                else {\n                    if (geomData[0] == 0 && geomData[1] == 0)\n                        continue;\n                    passId = Math.floor(geomData[1] / 64);\n                }\n                const key = geomData[0] + '-' + geomData[1];\n                const index = keys.get(key);\n                if (index != undefined) {\n                    histogram[index]++;\n                    continue;\n                }\n                const geomItemAndDist = this.__renderer.getPass(passId)?.getGeomItemAndDist(geomData);\n                if (geomItemAndDist) {\n                    keys.set(key, histogram.length);\n                    histogram.push(1);\n                    geomItems.push(geomItemAndDist.geomItem);\n                }\n            }\n            const indexArray = [];\n            for (let i = 0; i < histogram.length; i++) {\n                indexArray[i] = i;\n            }\n            indexArray.sort((a, b) => {\n                return histogram[a] > histogram[b] ? -1 : 1;\n            });\n            return {\n                geomItems: indexArray.map((index) => geomItems[index]),\n                histogram: indexArray.map((index) => histogram[index]),\n            };\n        }\n        return null;\n    }\n    /**\n     * getGeomItemsInRect\n     * Gathers all the geoms renders in a given rectangle of the viewport.\n     * @param tl - The top left value of the rectangle.\n     * @param br - The bottom right corner of the rectangle.\n     * @return - The return value.\n     */\n    getGeomItemsInRect(tl, br) {\n        const geomsInView = this.getGeomVisiblity(tl, br);\n        const set = new Set();\n        geomsInView.geomItems.forEach((geomItem) => {\n            set.add(geomItem);\n        });\n        return set;\n    }\n    // ///////////////////////////\n    // Events\n    /**\n     * Calculates the event coordinates relative to the viewport.\n     * There could be multiple viewports connected to the current renderer.\n     *\n     * @param rendererX - The rendererX value\n     * @param rendererY - The rendererY value\n     * @return - Returns a new Vec2.\n     * @private\n     */\n    __getPointerPos(rendererX, rendererY) {\n        return new Vec2(rendererX - this.getPosX(), rendererY - this.getPosY());\n    }\n    /**\n     * Prepares pointer event by adding properties of the engine to it.\n     *\n     * @param event - The event that occurs in the canvas\n     * @private\n     */\n    prepareUIEvent(event) {\n        event.viewport = this;\n    }\n    /**\n     * Handler of the `pointerdown` event fired when the pointer device is initially pressed.\n     *\n     * @param event - The DOM event produced by a pointer\n     */\n    onPointerDown(event) {\n        this.prepareUIEvent(event);\n        if (event instanceof ZeaMouseEvent) {\n            event.pointerPos = this.__getPointerPos(event.rendererX, event.rendererY);\n            event.pointerRay = this.calcRayFromScreenPos(event.pointerPos);\n            // Cache Pointer Down for PointerClick\n            this.pointerDownButton = event.button;\n            this.pointerDownPos = event.pointerPos;\n            this.pointerDownTime[event.button] = Date.now();\n        }\n        else if (event instanceof ZeaTouchEvent) {\n            const touch = event.touches[0];\n            event.pointerPos = this.__getPointerPos(touch.rendererX, touch.rendererY);\n            event.pointerRay = this.calcRayFromScreenPos(event.pointerPos);\n            // Cache Pointer Down for PointerClick\n            this.pointerDownButton = 0;\n            this.pointerDownPos = event.pointerPos;\n            this.pointerDownTime[0] = Date.now();\n        }\n        if (event.propagating && event.getCapture()) {\n            // events are now always sent to the capture item first,\n            // but can continue propagating to other items if no call\n            // to event.stopPropagation() was made.\n            event.getCapture().onPointerDown(event);\n        }\n        if (event.propagating) {\n            event.intersectionData = this.getGeomDataAtPos(event.pointerPos, event.pointerRay, this.mousePointerSearchArea);\n            if (event.intersectionData) {\n                event.intersectionData.geomItem.onPointerDown(event);\n            }\n        }\n        if (event.propagating) {\n            this.emit('pointerDown', event);\n        }\n        if (event.propagating && this.manipulator) {\n            this.manipulator.onPointerDown(event);\n        }\n        // //////////////////////////////////\n        // Start the long press timer\n        if (this.longPressId != undefined)\n            clearTimeout(this.longPressId);\n        if (event instanceof ZeaMouseEvent || (event instanceof ZeaTouchEvent && event.changedTouches.length == 1)) {\n            this.longPressId = setTimeout(() => {\n                this.longPressId = undefined;\n                event.propagating = true;\n                if (event.intersectionData && event.intersectionData.geomItem) {\n                    event.intersectionData.geomItem.onPointerLongPress(event);\n                }\n                this.emit('pointerLongPress', event);\n                if (event.propagating && this.manipulator) {\n                    this.manipulator.onPointerLongPress(event);\n                }\n            }, this.longPressTime);\n        }\n    }\n    /**\n     * Causes an event to occur when a user releases a mouse button over a element.\n     *\n     * @param event - The event that occurs.\n     */\n    onPointerUp(event) {\n        this.prepareUIEvent(event);\n        if (event.pointerType === POINTER_TYPES.mouse) {\n            const mouseEvent = event;\n            mouseEvent.pointerPos = this.__getPointerPos(mouseEvent.rendererX, mouseEvent.rendererY);\n            mouseEvent.pointerRay = this.calcRayFromScreenPos(mouseEvent.pointerPos);\n        }\n        else if (event.pointerType === POINTER_TYPES.touch) {\n            const touchEvent = event;\n            if (touchEvent.changedTouches.length == 1) {\n                const touch = touchEvent.changedTouches[0];\n                touchEvent.pointerPos = this.__getPointerPos(touch.rendererX, touch.rendererY);\n                touchEvent.pointerRay = this.calcRayFromScreenPos(touchEvent.pointerPos);\n            }\n        }\n        // ///////////////////////////////////////\n        // Clear Long Press\n        if (this.longPressId != undefined)\n            clearTimeout(this.longPressId);\n        if (event.getCapture()) {\n            // events are now always sent to the capture item first,\n            // but can continue propagating to other items if no call\n            // to event.stopPropagation() was made.\n            event.getCapture().onPointerUp(event);\n        }\n        if (event.propagating) {\n            event.intersectionData = this.getGeomDataAtPos(event.pointerPos, event.pointerRay, this.mousePointerSearchArea);\n            if (event.intersectionData) {\n                event.intersectionData.geomItem.onPointerUp(event);\n            }\n        }\n        if (event.propagating) {\n            this.emit('pointerUp', event);\n        }\n        if (event.propagating && this.manipulator) {\n            this.manipulator.onPointerUp(event);\n        }\n        // //////////////////////////////////////\n        // Detect a Pointer Click\n        // Generate a pointer click if we detect a pointerDown and a pointerUp in the\n        // same location.\n        const button = event instanceof ZeaMouseEvent ? event.button : 0;\n        const pointerUpTime = Date.now();\n        if ((event instanceof ZeaMouseEvent || (event instanceof ZeaTouchEvent && event.changedTouches.length == 1)) &&\n            pointerUpTime - this.pointerDownTime[button] < this.clickTime &&\n            event.pointerPos.distanceTo(this.pointerDownPos) < this.pointerClickTolerance &&\n            this.pointerDownButton == button) {\n            const clickTime = pointerUpTime;\n            event.propagating = true;\n            // Emit a double click if this is a second click.\n            if (button == this.prevClickButton && clickTime - this.prevClickTime < this.doubleClickTime) {\n                if (event.intersectionData && event.intersectionData.geomItem) {\n                    event.intersectionData.geomItem.onPointerDoubleClick(event);\n                }\n                if (event.propagating && event.propagating) {\n                    this.emit('pointerDoubleClick', event);\n                }\n                if (event.propagating && this.manipulator) {\n                    this.manipulator.onPointerDoubleClick(event);\n                }\n            }\n            else {\n                this.prevClickButton = button;\n                this.prevClickPos = event.pointerPos;\n                this.prevClickTime = clickTime;\n                if (event.intersectionData && event.intersectionData.geomItem) {\n                    event.intersectionData.geomItem.onPointerClick(event);\n                }\n                if (event.propagating) {\n                    this.emit('pointerClick', event);\n                }\n                if (event.propagating && this.manipulator) {\n                    this.manipulator.onPointerClick(event);\n                }\n            }\n        }\n        // //////////////////////////////////////\n    }\n    /**\n     * Causes an event to occur when the pointer device is moving.\n     *\n     * @param event - The event that occurs.\n     */\n    onPointerMove(event) {\n        this.prepareUIEvent(event);\n        if (event.pointerType === POINTER_TYPES.mouse) {\n            const mouseEvent = event;\n            const pointerPos = this.__getPointerPos(mouseEvent.rendererX, mouseEvent.rendererY);\n            mouseEvent.pointerPos = pointerPos;\n            mouseEvent.pointerRay = this.calcRayFromScreenPos(pointerPos);\n        }\n        else if (event.pointerType === POINTER_TYPES.touch) {\n            const touchEvent = event;\n            for (let index = 0; index < touchEvent.touches.length; index++) {\n                const touch = touchEvent.touches[index];\n                touch.touchPos = this.__getPointerPos(touch.rendererX, touch.rendererY);\n                touch.touchRay = this.calcRayFromScreenPos(touch.touchPos);\n            }\n            touchEvent.pointerPos = touchEvent.touches[0].touchPos;\n            touchEvent.pointerRay = touchEvent.touches[0].touchRay;\n        }\n        // Clear the long press timer if the pointer moves too far.\n        if (this.longPressId != undefined &&\n            event.pointerPos.distanceTo(this.pointerDownPos) > this.pointerClickTolerance) {\n            clearTimeout(this.longPressId);\n            this.longPressId = undefined;\n        }\n        // Note: the Captured item might be a tool, which might not need to have\n        // the geom under the pointer. e.g. the CameraManipulator during a drag.\n        if (event.getCapture()) {\n            // events are now always sent to the capture item first,\n            // but can continue propagating to other items if no call\n            // to event.stopPropagation() was made.\n            event.getCapture().onPointerMove(event);\n        }\n        if (event.propagating) {\n            event.intersectionData = this.getGeomDataAtPos(event.pointerPos, event.pointerRay, this.mousePointerSearchArea);\n            if (event.intersectionData) {\n                if (event.intersectionData.geomItem != this.pointerOverItem) {\n                    if (this.pointerOverItem) {\n                        event.leftGeometry = this.pointerOverItem;\n                        this.pointerOverItem.onPointerLeave(event);\n                        if (event.propagating) {\n                            this.emit('pointerLeaveGeom', event);\n                        }\n                    }\n                    event.propagating = true;\n                    this.pointerOverItem = event.intersectionData.geomItem;\n                    this.pointerOverItem.onPointerEnter(event);\n                    if (event.propagating) {\n                        this.emit('pointerEnterGeom', event);\n                    }\n                }\n                event.propagating = true;\n                event.intersectionData.geomItem.onPointerMove(event);\n            }\n            else if (event.propagating && this.pointerOverItem) {\n                event.leftGeometry = this.pointerOverItem;\n                this.pointerOverItem.onPointerLeave(event);\n                this.pointerOverItem = null;\n                this.emit('pointerLeaveGeom', event);\n            }\n        }\n        if (event.propagating) {\n            this.emit('pointerMove', event);\n        }\n        if (event.propagating && this.manipulator) {\n            this.manipulator.onPointerMove(event);\n        }\n    }\n    /**\n     * Causes an event to occur when the mouse pointer is moved into this viewport\n     * @param event - The event that occurs.\n     */\n    onPointerEnter(event) {\n        this.prepareUIEvent(event);\n        this.emit('pointerEnter', event);\n        if (event.propagating && this.manipulator && this.manipulator.onPointerEnter) {\n            this.manipulator.onPointerEnter(event);\n        }\n    }\n    /**\n     * Causes an event to occur when the mouse pointer is moved out of this viewport\n     * @param event - The event that occurs.\n     */\n    onPointerLeave(event) {\n        this.prepareUIEvent(event);\n        this.emit('pointerLeave', event);\n        if (!event.propagating)\n            return;\n        if (this.manipulator && this.manipulator.onPointerLeave) {\n            this.manipulator.onPointerLeave(event);\n            if (!event.propagating)\n                return;\n        }\n    }\n    /**\n     * Causes an event to occur when the user is pressing a key on the keyboard.\n     * @param event - The event that occurs.\n     */\n    onKeyDown(event) {\n        this.prepareUIEvent(event);\n        if (this.manipulator) {\n            this.manipulator.onKeyDown(event);\n            if (!event.propagating)\n                return;\n        }\n        this.emit('keyDown', event);\n    }\n    /**\n     * Causes an event to occur  when the user releases a key on the keyboard.\n     * @param event - The event that occurs.\n     */\n    onKeyUp(event) {\n        this.prepareUIEvent(event);\n        if (this.manipulator) {\n            this.manipulator.onKeyUp(event);\n            if (!event.propagating)\n                return;\n        }\n        this.emit('keyUp', event);\n    }\n    /**\n     * Causes an event to occur when the mouse wheel is rolled up or down over an element.\n     * @param event - The event that occurs.\n     */\n    onWheel(event) {\n        this.prepareUIEvent(event);\n        event.pointerPos = this.__getPointerPos(event.rendererX, event.rendererY);\n        event.pointerRay = this.calcRayFromScreenPos(event.pointerPos);\n        event.intersectionData = this.getGeomDataAtPos(event.pointerPos, event.pointerRay, this.mousePointerSearchArea);\n        if (event.intersectionData != undefined) {\n            event.intersectionData.geomItem.onWheel(event);\n            if (!event.propagating)\n                return;\n        }\n        if (this.manipulator) {\n            this.manipulator.onWheel(event);\n            return;\n        }\n        this.emit('mouseWheel', event);\n    }\n    // Touch events\n    /**\n     * Causes an event to occur when the touch event gets interrupted.\n     * @param event - The event that occurs.\n     */\n    onTouchCancel(event) {\n        this.prepareUIEvent(event);\n        if (event.getCapture()) {\n            // events are now always sent to the capture item first,\n            // but can continue propagating to other items if no call\n            // to event.stopPropagation() was made.\n            event.getCapture().onTouchCancel(event);\n            if (!event.propagating)\n                return;\n        }\n        if (this.manipulator) {\n            this.manipulator.onTouchCancel(event);\n            if (!event.propagating)\n                return;\n        }\n        this.emit('touchCancel', event);\n    }\n    // //////////////////////////\n    // Rendering\n    /**\n     * The bindGLViewport method.\n     * @param renderstate - The object tracking the current state of the renderer\n     * @private\n     */\n    bindGLViewport(renderstate) {\n        // console.log(this.viewMatrix.toString())\n        renderstate.viewXfo = this.cameraXfo;\n        renderstate.viewScale = 1.0;\n        renderstate.region = this.region;\n        renderstate.depthRange = this.depthRange;\n        renderstate.cameraMatrix = this.cameraMat;\n        renderstate.viewport = this;\n        const gl = this.__renderer.gl;\n        renderstate.bindRendererUnifs = (unifs) => {\n            const { cameraMatrix, viewMatrix, projectionMatrix, eye, isOrthographic, viewportFrustum } = unifs;\n            if (cameraMatrix) {\n                gl.uniformMatrix4fv(cameraMatrix.location, false, renderstate.cameraMatrix.asArray());\n            }\n            if (viewMatrix) {\n                gl.uniformMatrix4fv(viewMatrix.location, false, this.viewMatrix.asArray());\n            }\n            if (projectionMatrix) {\n                gl.uniformMatrix4fv(projectionMatrix.location, false, this.projectionMatrix.asArray());\n            }\n            if (eye) {\n                // for monocular rendering, we just render viewport 0\n                gl.uniform1i(eye.location, 0);\n            }\n            if (isOrthographic) {\n                // Left or right eye, when rendering stereo VR.\n                gl.uniform1i(isOrthographic.location, this.camera.isOrthographic() ? 1 : 0);\n            }\n            if (viewportFrustum && this.viewportFrustum) {\n                // Left or right eye, when rendering stereo VR.\n                gl.uniform4f(viewportFrustum.location, this.viewportFrustum.x, this.viewportFrustum.y, this.viewportFrustum.z, this.viewportFrustum.w);\n            }\n        };\n        renderstate.bindViewports = (unifs, draw) => draw();\n    }\n    /**\n     * The draw method.\n     */\n    draw(renderstate) {\n        // Turn this on to debug the geom data buffer.\n        if (this.debugGeomDataBuffer) {\n            this.renderGeomDataFbo();\n            const gl = this.__renderer.gl;\n            gl.viewport(this.region[0], this.region[1], this.region[2], this.region[3]);\n            const bg = this.backgroundColorParam.value.asArray();\n            gl.clearColor(bg[0], bg[1], bg[2], bg[3]);\n            // Note: renderGeomDataFbo would have bound other shaders.\n            // and the renderstate used above is no longer valid. Reset.\n            const renderstate = new ColorRenderState(this.__renderer.gl);\n            const screenQuad = this.__renderer.screenQuad;\n            screenQuad.bindShader(renderstate);\n            screenQuad.draw(renderstate, this.geomDataRenderTarget.textureTargets[0]);\n            return;\n        }\n        const gl = this.__renderer.gl;\n        this.bindGLViewport(renderstate);\n        renderstate.pushGLStack('GLViewport.draw');\n        renderstate.glDisable(gl.BLEND);\n        renderstate.glEnable(gl.DEPTH_TEST);\n        renderstate.glEnable(gl.CULL_FACE);\n        gl.viewport(this.region[0], this.region[1], this.region[2], this.region[3]);\n        const bg = this.backgroundColorParam.value.asArray();\n        gl.clearColor(bg[0], bg[1], bg[2], bg[3]);\n        gl.colorMask(true, true, true, true);\n        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);\n        super.draw(renderstate);\n        renderstate.popGLStack();\n        if (this.debugHighlightedGeomsBuffer) {\n            // Note: renderGeomDataFbo would have bound other shaders.\n            // and the renderstate used above is no blonger valid. Reset.\n            const renderstate = new ColorRenderState(this.__renderer.gl);\n            const screenQuad = this.__renderer.screenQuad;\n            screenQuad.bindShader(renderstate);\n            screenQuad.draw(renderstate, this.highlightedGeomsBufferFbo.textureTargets[0]);\n        }\n        if (this.debugOcclusionBuffer) {\n            renderstate.pushGLStack('debugOcclusionBuffer');\n            gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);\n            // @ts-ignore\n            const occlusionDataBuffer = this.__renderer.glGeomItemLibrary.occlusionDataBuffer;\n            renderstate.glEnable(gl.BLEND);\n            renderstate.glDisable(gl.DEPTH_TEST);\n            gl.blendEquation(gl.FUNC_ADD);\n            gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE);\n            const screenQuad = this.__renderer.screenQuad;\n            screenQuad.bindShader(renderstate);\n            screenQuad.draw(renderstate, occlusionDataBuffer.textureTargets[0]);\n            renderstate.popGLStack();\n        }\n        if (this.debugReductionBuffer) {\n            // @ts-ignore\n            const reductionDataBuffer = this.__renderer.glGeomItemLibrary.reductionDataBuffer;\n            const screenQuad = this.__renderer.screenQuad;\n            screenQuad.bindShader(renderstate);\n            const imageInif = renderstate.unifs.image;\n            reductionDataBuffer.bindColorTexture(renderstate, imageInif);\n            const gl = this.__renderer.gl;\n            gl.uniform1i(renderstate.unifs.isTextured.location, 1);\n            gl.enable(gl.BLEND);\n            gl.blendEquation(gl.FUNC_ADD);\n            gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE);\n            screenQuad.draw(renderstate, null);\n            gl.disable(gl.BLEND);\n        }\n    }\n}\n\nvar frag$h = \"\\nprecision highp float;\\n#define GLSLIFY 1\\n\\nuniform sampler2D image;\\nuniform vec4 color;\\nuniform int isTextured;\\n\\nvarying vec2 v_texCoord;\\n\\n#ifdef ENABLE_ES3\\n  out vec4 fragColor;\\n#endif\\nvoid main(void) {\\n#ifndef ENABLE_ES3\\n  vec4 fragColor;\\n#endif\\n\\n  if (isTextured != 0)\\n    fragColor = texture2D(image, v_texCoord);\\n  else \\n    fragColor = color;\\n\\n#ifndef ENABLE_ES3\\n  gl_FragColor = fragColor;\\n#endif\\n}\\n\"; // eslint-disable-line\n\nvar vert$i = \"\\nprecision highp float;\\n#define GLSLIFY 1\\n\\nimport 'quadVertexFromID.glsl'\\n\\nuniform vec2 pos;\\nuniform vec2 size;\\n\\n/* VS Outputs */\\nvarying vec2 v_texCoord;\\n \\nvoid main()\\n{\\n  vec2 position = getQuadVertexPositionFromID();\\n  v_texCoord = position+0.5;\\n  gl_Position = vec4(vec2(-1.0, -1.0) + (pos * 2.0) + (v_texCoord * abs(size) * 2.0), 0.0, 1.0);\\n  if (size.x < 0.0)\\n    v_texCoord.x = 1.0 - v_texCoord.x;\\n  if (size.y < 0.0)\\n    v_texCoord.y = 1.0 - v_texCoord.y;\\n}\\n\"; // eslint-disable-line\n\n/* eslint-disable require-jsdoc */\nclass ScreenQuadShader extends GLShader {\n    /**\n     * Create a GL shader.\n     * @param gl - The webgl rendering context.\n     */\n    constructor(gl) {\n        super(gl, 'ScreenQuadShader');\n        this.setShaderStage('VERTEX_SHADER', vert$i);\n        this.setShaderStage('FRAGMENT_SHADER', frag$h);\n    }\n}\n\n/** Class representing a GL screen quad.\n * @private\n */\nclass GLScreenQuad {\n    __gl;\n    __pos;\n    __size;\n    __glshader;\n    __quadBinding; // GeomShaderBinding | VAOGeomShaderBinding\n    ready;\n    /**\n     * Create a GL screen quad.\n     * @param gl - The webgl rendering context.\n     * @param directives - GLSL shader directives\n     */\n    constructor(gl, directives) {\n        this.__gl = gl;\n        this.__pos = [0.0, 0.0];\n        this.__size = [1.0, 1.0];\n        this.__glshader = new ScreenQuadShader(gl);\n        if (!gl.__quadVertexIdsBuffer)\n            gl.setupInstancedQuad();\n        const shaderComp = this.__glshader.compileForTarget('GLScreenQuad', directives);\n        this.__quadBinding = generateShaderGeomBinding(this.__gl, shaderComp.attrs, gl.__quadattrbuffers, gl.__quadIndexBuffer);\n    }\n    /**\n     * The bind method.\n     * @param renderstate - The object tracking the current state of the renderer\n     * @param textureOrColor - The texture or color value.\n     * @param pos - The pos value.\n     * @param size - The size value.\n     */\n    bind(renderstate, textureOrColor, pos, size) {\n        const unifs = renderstate.unifs;\n        const gl = this.__gl;\n        if (textureOrColor instanceof GLTexture2D) {\n            gl.uniform1i(unifs.isTextured.location, 1);\n            textureOrColor.bindToUniform(renderstate, renderstate.unifs.image);\n        }\n        else if (textureOrColor instanceof WebGLTexture) {\n            gl.uniform1i(unifs.isTextured.location, 1);\n            const unit = renderstate.boundTextures++;\n            gl.activeTexture(gl.TEXTURE0 + unit);\n            gl.bindTexture(gl.TEXTURE_2D, textureOrColor);\n            gl.uniform1i(unifs.image.location, unit);\n        }\n        else if (textureOrColor && textureOrColor instanceof Color) {\n            gl.uniform1i(unifs.isTextured.location, 0);\n            gl.uniform4fv(unifs.color.location, textureOrColor.asArray());\n        }\n        {\n            const unif = unifs.pos;\n            if (unif) {\n                let list = pos ? (pos instanceof Vec2 ? pos.asArray() : pos) : this.__pos;\n                gl.uniform2fv(unif.location, list);\n            }\n        }\n        {\n            const unif = unifs.size;\n            if (unif) {\n                let list = size ? (size instanceof Vec2 ? size.asArray() : size) : this.__size;\n                gl.uniform2fv(unif.location, list);\n            }\n        }\n        this.__quadBinding.bind(renderstate);\n    }\n    /**\n     * The bindShader method.\n     * @param renderstate - The object tracking the current state of the renderer\n     * @return - The return value.\n     */\n    bindShader(renderstate) {\n        return this.__glshader.bind(renderstate, 'GLScreenQuad');\n    }\n    /**\n     * The draw method.\n     * @param renderstate - The object tracking the current state of the renderer\n     * @param textureOrColor - The texture or color value.\n     * @param pos - The pos value.\n     * @param size - The size value.\n     */\n    draw(renderstate, textureOrColor, pos, size) {\n        this.bind(renderstate, textureOrColor, pos, size);\n        const gl = this.__gl;\n        gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0);\n    }\n}\n\nconst gltextureCache = new Map();\nclass ParamUniformBinding extends BaseClass {\n    unif;\n    dirty = false;\n    constructor(unif) {\n        super();\n        this.unif = unif;\n    }\n    /**\n     * The unbind method.\n     */\n    bind(renderstate) { }\n    /**\n     * The unbind method.\n     */\n    unbind(renderstate) { }\n    /**\n     * The destroy method.\n     */\n    destroy() { }\n}\nclass Sampler2DBinding extends ParamUniformBinding {\n    boundImage;\n    textureType;\n    textureTypeUnif;\n    dirty = false;\n    param;\n    texBinding;\n    gltexture = null;\n    constructor(gl, glMaterial, param, textureUnif, unifs) {\n        super(textureUnif);\n        const name = param.getName();\n        this.param = param;\n        // this.textureUnif = textureUnif\n        this.textureTypeUnif = unifs[name + 'Type'];\n        const genGLTex = (image) => {\n            let gltexture = gltextureCache.get(image);\n            const textureType = 1;\n            if (!gltexture) {\n                if (image.type === 'HDR') {\n                    gltexture = new GLHDRImage(gl, image);\n                }\n                else {\n                    gltexture = new GLTexture2D(gl, image);\n                }\n                gltextureCache.set(image, gltexture);\n            }\n            this.texBinding = gltexture.preBind(this.unif, unifs);\n            gltexture.on('updated', () => {\n                glMaterial.emit('updated');\n            });\n            this.gltexture = gltexture;\n            this.gltexture.addRef(this);\n            this.textureType = textureType;\n            glMaterial.emit('updated');\n        };\n        let imageLoadedId;\n        const connectImage = (image) => {\n            if (!image.isLoaded()) {\n                imageLoadedId = image.on('loaded', () => {\n                    genGLTex(this.boundImage);\n                });\n            }\n            else {\n                genGLTex(image);\n            }\n            this.boundImage = image;\n        };\n        const disconnectImage = () => {\n            const gltexture = gltextureCache.get(this.boundImage);\n            gltexture.removeRef(this);\n            this.texBinding = null;\n            this.gltexture = null;\n            this.textureType = -1;\n            if (imageLoadedId) {\n                this.boundImage.off('loaded', imageLoadedId);\n            }\n            this.boundImage = null;\n            imageLoadedId = null;\n            glMaterial.emit('updated');\n        };\n        if (param.getImage())\n            connectImage(param.getImage());\n        param.on('textureConnected', () => {\n            connectImage(param.getImage());\n        });\n        param.on('textureDisconnected', () => {\n            disconnectImage();\n        });\n        this.dirty = true;\n        param.on('valueChanged', () => {\n            this.dirty = true;\n            glMaterial.emit('updated');\n        });\n    }\n    /**\n     * The unbind method.\n     */\n    bind(renderstate) {\n        if (this.gltexture)\n            this.gltexture.bindToUniform(renderstate, this.unif, this.texBinding);\n    }\n}\n/** Class representing simple uniform binding.\n * @private\n */\nclass SimpleUniformBinding extends ParamUniformBinding {\n    param;\n    textureUnif;\n    textureTypeUnif;\n    texBinding;\n    gltexture = null;\n    textureType = -1;\n    val;\n    uniform1i;\n    uniformXX;\n    update;\n    /**\n     * Create simple uniform binding.\n     * @param gl - The webgl rendering context.\n     * @param glMaterial - The glMaterial value.\n     * @param param - The param value.\n     * @param unif - The WebGL uniform\n     * @param unifs - The dictionary of WebGL uniforms.\n     */\n    constructor(gl, glMaterial, param, unif, unifs) {\n        super(unif);\n        const name = param.getName();\n        this.param = param;\n        this.unif = unif;\n        this.textureUnif = unifs[name + 'Tex'];\n        this.textureTypeUnif = unifs[name + 'TexType'];\n        this.uniform1i = gl.uniform1i.bind(gl);\n        switch (this.unif.glslType) {\n            case 'bool':\n                // gl.uniform1ui(unif.location, value);// WebGL 2\n                this.uniformXX = gl.uniform1i.bind(gl);\n                break;\n            case 'uint':\n                this.uniformXX = gl.uniform1ui.bind(gl);\n                break;\n            case 'int':\n                this.uniformXX = gl.uniform1i.bind(gl);\n                break;\n            case 'float':\n                this.uniformXX = gl.uniform1f.bind(gl);\n                break;\n        }\n        this.bind = this.bindValue;\n        const genGLTex = (image) => {\n            let gltexture = gltextureCache.get(image);\n            const textureType = 1;\n            if (!gltexture) {\n                if (image.type === 'HDR') {\n                    gltexture = new GLHDRImage(gl, image);\n                }\n                else {\n                    gltexture = new GLTexture2D(gl, image);\n                }\n                gltextureCache.set(image, gltexture);\n            }\n            this.texBinding = gltexture.preBind(this.textureUnif, unifs);\n            gltexture.on('updated', () => {\n                glMaterial.emit('updated');\n            });\n            this.gltexture = gltexture;\n            this.gltexture.addRef(this);\n            this.textureType = textureType;\n            this.bind = this.bindTexture;\n            glMaterial.emit('updated');\n        };\n        let boundImage;\n        let imageLoadedId;\n        this.update = () => {\n            try {\n                // Sometimes the value of a color param is an image.\n                if (boundImage) {\n                }\n                else {\n                    if (typeof param.value == 'boolean') {\n                        this.val = param.value ? 1 : 0;\n                    }\n                    else\n                        this.val = param.value;\n                }\n            }\n            catch (e) { }\n            glMaterial.emit('updated');\n        };\n        /**\n         * The update method.\n         */\n        if (this.textureUnif && param instanceof MaterialFloatParam) {\n            const connectImage = (image) => {\n                if (!image.isLoaded()) {\n                    imageLoadedId = image.on('loaded', () => {\n                        genGLTex(boundImage);\n                    });\n                }\n                else {\n                    genGLTex(image);\n                }\n                boundImage = image;\n            };\n            const disconnectImage = () => {\n                const gltexture = gltextureCache.get(boundImage);\n                gltexture.removeRef(this);\n                this.texBinding = null;\n                this.gltexture = null;\n                this.textureType = -1;\n                this.bind = this.bindValue;\n                if (imageLoadedId) {\n                    boundImage.off('loaded', imageLoadedId);\n                }\n                boundImage = null;\n                imageLoadedId = null;\n                glMaterial.emit('updated');\n            };\n            if (param.getImage())\n                connectImage(param.getImage());\n            param.on('textureConnected', () => {\n                connectImage(param.getImage());\n            });\n            param.on('textureDisconnected', () => {\n                disconnectImage();\n            });\n        }\n        this.dirty = true;\n        param.on('valueChanged', () => {\n            this.dirty = true;\n            glMaterial.emit('updated');\n        });\n    }\n    /**\n     * The bindValue method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    bindValue(renderstate) {\n        if (this.dirty) {\n            this.update();\n            this.dirty = false;\n        }\n        if (this.unif)\n            this.uniformXX(this.unif.location, this.val);\n        if (this.textureTypeUnif)\n            this.uniform1i(this.textureTypeUnif.location, 0);\n    }\n    /**\n     * The bindTexture method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    bindTexture(renderstate) {\n        if (this.dirty) {\n            this.update();\n            this.dirty = false;\n        }\n        this.gltexture.bindToUniform(renderstate, this.textureUnif, this.texBinding);\n    }\n}\n/** Class representing complex uniform binding.\n * @private\n */\nclass ComplexUniformBinding extends ParamUniformBinding {\n    param;\n    values;\n    uniformXX;\n    /**\n     * Create complex uniform binding.\n     * @param gl - The webgl rendering context.\n     * @param glMaterial - The glMaterial value.\n     * @param param - The param value.\n     * @param unif - The WebGL uniform\n     */\n    constructor(gl, glMaterial, param, unif) {\n        super(unif);\n        this.param = param;\n        switch (this.unif.glslType) {\n            case 'vec2':\n                this.uniformXX = gl.uniform2fv.bind(gl);\n                break;\n            case 'vec3':\n                this.uniformXX = gl.uniform3fv.bind(gl);\n                break;\n            case 'vec4':\n                this.uniformXX = gl.uniform4fv.bind(gl);\n                break;\n        }\n        this.dirty = true;\n        param.on('valueChanged', () => {\n            this.dirty = true;\n            glMaterial.emit('updated');\n        });\n    }\n    /**\n     * The bind method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    bind(renderstate) {\n        if (this.dirty) {\n            this.values = this.param.value.asArray();\n            this.dirty = false;\n        }\n        this.uniformXX(this.unif.location, this.values);\n    }\n    /**\n     * The unbind method.\n     */\n    unbind() { }\n    /**\n     * The destroy method.\n     */\n    destroy() { }\n}\n/** Class representing material uniform binding.\n * @private\n */\nclass MatrixUniformBinding extends ParamUniformBinding {\n    param;\n    uniformMatrixXXX;\n    values = [];\n    /**\n     * Create material uniform binding.\n     * @param gl - The webgl rendering context.\n     * @param glMaterial - The glMaterial value.\n     * @param param - The param value.\n     * @param unif - The WebGL uniform\n     */\n    constructor(gl, glMaterial, param, unif) {\n        super(unif);\n        this.param = param;\n        switch (this.unif.glslType) {\n            case 'mat3':\n                this.uniformMatrixXXX = gl.uniformMatrix3fv.bind(gl);\n                break;\n            case 'mat4':\n                this.uniformMatrixXXX = gl.uniformMatrix4fv.bind(gl);\n                break;\n        }\n        this.dirty = true;\n        param.on('valueChanged', () => {\n            this.dirty = true;\n            glMaterial.emit('updated');\n        });\n    }\n    /**\n     * The bind method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    bind(renderstate) {\n        if (this.dirty) {\n            this.values = this.param.value.asArray();\n            this.dirty = false;\n        }\n        this.uniformMatrixXXX(this.unif.location, false, this.values);\n    }\n    /**\n     * The unbind method.\n     */\n    unbind() { }\n    /**\n     * The destroy method.\n     */\n    destroy() { }\n}\n/** Class representing color uniform binding.\n * @private\n */\nclass ColorUniformBinding extends ParamUniformBinding {\n    param;\n    textureUnif;\n    textureTypeUnif;\n    values = [];\n    gltexture;\n    textureType;\n    texBinding;\n    uniform1i;\n    uniform4fv;\n    update;\n    /**\n     * Create color uniform binding.\n     * @param gl - The webgl rendering context.\n     * @param glMaterial - The glMaterial value.\n     * @param param - The param value.\n     * @param unif - The WebGL uniform\n     * @param unifs - The dictionary of WebGL uniforms.\n     */\n    constructor(gl, glMaterial, param, unif, unifs) {\n        super(unif);\n        const name = param.getName();\n        this.param = param;\n        this.textureUnif = unifs[name + 'Tex'];\n        this.textureTypeUnif = unifs[name + 'TexType'];\n        this.values = [0, 0, 0, 0];\n        this.bind = this.bindValue;\n        let boundImage;\n        let imageLoadedId;\n        this.update = () => {\n            try {\n                // Sometimes the value of a color param is an image.\n                if (boundImage) {\n                }\n                else if (this.unif) {\n                    if (param instanceof MaterialColorParam && param.colorSpace == ColorSpace.Gamma) {\n                        this.values = param.value.toLinear().asArray();\n                    }\n                    else {\n                        this.values = param.value.asArray();\n                    }\n                }\n            }\n            catch (e) { }\n            glMaterial.emit('updated');\n        };\n        /**\n         * The update method.\n         */\n        if (this.textureUnif && param instanceof MaterialColorParam) {\n            const genGLTex = (image) => {\n                boundImage = image;\n                let gltexture = gltextureCache.get(image);\n                const textureType = 1;\n                if (!gltexture) {\n                    if (image.type === 'FLOAT') {\n                        gltexture = new GLHDRImage(gl, image);\n                    }\n                    else {\n                        gltexture = new GLTexture2D(gl, image);\n                    }\n                    gltextureCache.set(image, gltexture);\n                }\n                this.texBinding = gltexture.preBind(this.textureUnif, unifs);\n                gltexture.on('updated', () => {\n                    glMaterial.emit('updated');\n                });\n                this.gltexture = gltexture;\n                this.gltexture.addRef(this);\n                this.textureType = textureType;\n                this.bind = this.bindTexture;\n                glMaterial.emit('updated');\n            };\n            const connectImage = (image) => {\n                if (!image.isLoaded()) {\n                    imageLoadedId = image.once('loaded', () => {\n                        genGLTex(image);\n                    });\n                }\n                else {\n                    genGLTex(image);\n                }\n            };\n            const disconnectImage = () => {\n                this.gltexture.removeRef(this);\n                this.gltexture = null;\n                this.texBinding = null;\n                this.textureType = null;\n                if (imageLoadedId) {\n                    boundImage.off('loaded', imageLoadedId);\n                }\n                this.bind = this.bindValue;\n                boundImage = null;\n                imageLoadedId = null;\n                glMaterial.emit('updated');\n            };\n            if (param.getImage())\n                connectImage(param.getImage());\n            param.on('textureConnected', () => {\n                connectImage(param.getImage());\n            });\n            param.on('textureDisconnected', () => {\n                disconnectImage();\n            });\n        }\n        this.dirty = true;\n        param.on('valueChanged', () => {\n            this.dirty = true;\n        });\n        this.uniform1i = gl.uniform1i.bind(gl);\n        this.uniform4fv = gl.uniform4fv.bind(gl);\n    }\n    /**\n     * The bindValue method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    bindValue(renderstate) {\n        if (!this.unif)\n            return; // Note: Normals parms have no unif and can only be bound to a texture.\n        if (this.dirty) {\n            this.update();\n            this.dirty = false;\n        }\n        if (this.unif)\n            this.uniform4fv(this.unif.location, this.values);\n        if (this.textureTypeUnif)\n            this.uniform1i(this.textureTypeUnif.location, 0);\n    }\n    /**\n     * The bindTexture method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    bindTexture(renderstate) {\n        if (this.dirty) {\n            this.update();\n            this.dirty = false;\n        }\n        this.gltexture.bindToUniform(renderstate, this.textureUnif, this.texBinding);\n    }\n}\n/** Class representing material shader binding.\n * @private\n */\nclass MaterialShaderBinding {\n    uniformBindings = [];\n    /**\n     * Create material shader binding.\n     * @param gl - The webgl rendering context.\n     * @param glMaterial - The glMaterial value.\n     * @param unifs - The dictionary of WebGL uniforms.\n     * @param warnMissingUnifs - The warnMissingUnifs value.\n     */\n    constructor(gl, glMaterial, unifs, warnMissingUnifs) {\n        const bindParam = (param) => {\n            const name = param.getName();\n            const unif = unifs[name];\n            if (unif) {\n                // Note:\n                switch (unif.glslType) {\n                    case 'bool':\n                    case 'uint':\n                    case 'int':\n                    case 'float':\n                        this.uniformBindings.push(new SimpleUniformBinding(gl, glMaterial, param, unif, unifs));\n                        break;\n                    case 'vec2':\n                    case 'vec3':\n                    case 'vec4':\n                        this.uniformBindings.push(new ComplexUniformBinding(gl, glMaterial, param, unif));\n                        break;\n                    case 'color':\n                        this.uniformBindings.push(new ColorUniformBinding(gl, glMaterial, param, unif, unifs));\n                        break;\n                    case 'mat4':\n                        this.uniformBindings.push(new MatrixUniformBinding(gl, glMaterial, param, unif));\n                        break;\n                    default:\n                        console.warn('Param :' + name + ' has unhandled data type:' + unif.glslType);\n                        return;\n                }\n            }\n            else {\n                const textureUnif = unifs[name + 'Tex'];\n                if (textureUnif &&\n                    textureUnif.glslType == 'sampler2D' &&\n                    (param instanceof MaterialColorParam || param instanceof MaterialFloatParam) &&\n                    param.getImage()) {\n                    if (textureUnif && textureUnif.glslType == 'sampler2D') {\n                        this.uniformBindings.push(new Sampler2DBinding(gl, glMaterial, param, textureUnif, unifs));\n                    }\n                }\n            }\n        };\n        const params = glMaterial.material.getParameters();\n        for (const param of params) {\n            bindParam(param);\n        }\n    }\n    /**\n     * The bind method.\n     * @param renderstate - The object tracking the current state of the renderer\n     * @return - The return value.\n     */\n    bind(renderstate) {\n        for (const uniformBinding of this.uniformBindings) {\n            uniformBinding.bind(renderstate);\n        }\n        return true;\n    }\n    /**\n     * The unbind method.\n     */\n    unbind(renderstate) {\n        for (const uniformBinding of this.uniformBindings) {\n            uniformBinding.unbind(renderstate);\n        }\n    }\n    /**\n     * The destroy is called by the system to cause explicit resources cleanup.\n     * Users should never need to call this method directly.\n     */\n    destroy() {\n        for (const uniformBinding of this.uniformBindings) {\n            uniformBinding.destroy();\n        }\n    }\n}\n\n/** Class representing a GL material.\n * @extends EventEmitter\n * @private\n */\nclass GLMaterial extends EventEmitter {\n    gl;\n    material;\n    glShader;\n    shaderBindings;\n    boundTexturesBeforeMaterial;\n    /**\n     * Create a GL material.\n     * @param gl - The webgl rendering context.\n     * @param material - The material value.\n     * @param glShader - The glShader value.\n     */\n    constructor(gl, material, glShader) {\n        super();\n        this.gl = gl;\n        this.material = material;\n        this.glShader = glShader;\n        this.shaderBindings = {};\n        material.on('parameterValueChanged', () => this.emit('updated'));\n    }\n    /**\n     * The bind method.\n     * @param renderstate - The object tracking the current state of the renderer\n     * @param warnMissingUnifs - The renderstate value.\n     */\n    bind(renderstate, warnMissingUnifs) {\n        this.boundTexturesBeforeMaterial = renderstate.boundTextures;\n        let shaderBinding = this.shaderBindings[renderstate.shaderkey];\n        if (!shaderBinding) {\n            const gl = this.gl;\n            shaderBinding = new MaterialShaderBinding(gl, this, renderstate.unifs, warnMissingUnifs);\n            this.shaderBindings[renderstate.shaderkey] = shaderBinding;\n        }\n        shaderBinding.bind(renderstate);\n    }\n    /**\n     * The unbind method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    unbind(renderstate) {\n        // Enable texture units to be re-used by resetting the count back\n        // to what it was.\n        // Note: we don't need to unbind each texture, as re-binding a new material\n        // will overwrite the bindings made by this material.\n        renderstate.boundTextures = this.boundTexturesBeforeMaterial;\n    }\n}\n\n/** Class representing a GL CAD material library.\n * @ignore\n */\nclass GLMaterialLibrary extends EventEmitter {\n    renderer;\n    materials = [];\n    materialBindings = new Map();\n    freeIndices = [];\n    dirtyIndices = new Set();\n    materialsAllocator = new Allocator1D();\n    materialsTexture;\n    /**\n     * Create a GL CAD material library.\n     * @param renderer - The renderer object\n     */\n    constructor(renderer) {\n        super();\n        this.renderer = renderer;\n        this.materialsAllocator.on('dataReallocated', (event) => {\n            // during allocation, a defragment might occur, which means\n            // we need to re-upload some of our data.\n            const id = event.id;\n            this.dirtyIndices.add(id);\n        });\n    }\n    /**\n     * The addMaterial method.\n     * @param material - The material object.\n     * @return - The index of GLMaterial\n     */\n    addMaterial(material) {\n        const binding = this.materialBindings.get(material);\n        if (binding != undefined) {\n            // Increment the ref count for the Material\n            binding.refCount++;\n            return binding.index;\n        }\n        const index = this.freeIndices.length > 0 ? this.freeIndices.pop() : this.materials.length;\n        this.materials[index] = material;\n        const listenerIDs = {};\n        const matData = material.getShaderClass().getPackedMaterialData(material);\n        this.materialsAllocator.allocate(index, matData.length / 4);\n        const parameterValueChanged = () => {\n            this.dirtyIndices.add(index);\n            this.emit('updated');\n        };\n        listenerIDs['parameterValueChanged'] = material.on('parameterValueChanged', parameterValueChanged);\n        this.materialBindings.set(material, { index, refCount: 1, listenerIDs });\n        this.dirtyIndices.add(index);\n        return index;\n    }\n    /**\n     * Given a material, generates a GLMaterial that manages the GPU state for the material.\n     * @param material - The material value.\n     * @return - The constructed GLMaterial.\n     */\n    getGLMaterial(material) {\n        this.addMaterial(material);\n        const binding = this.materialBindings.get(material);\n        if (binding.glMaterial)\n            return binding.glMaterial;\n        const glShader = this.renderer.getOrCreateShader(material.getShaderName());\n        const gl = this.renderer.gl;\n        const glMaterial = new GLMaterial(gl, material, glShader);\n        binding.listenerIDs['updated'] = glMaterial.on('updated', () => {\n            this.renderer.requestRedraw();\n        });\n        binding.glMaterial = glMaterial;\n        return glMaterial;\n    }\n    getMaterialAllocation(material) {\n        const binding = this.materialBindings.get(material);\n        if (binding != undefined) {\n            return this.materialsAllocator.getAllocation(binding.index);\n        }\n        return undefined;\n    }\n    /**\n     * The removeMaterial method.\n     * @param material - The material object.\n     */\n    removeMaterial(material) {\n        const binding = this.materialBindings.get(material);\n        binding.refCount--;\n        // If there are still refs to this geom. (GeomItems that use it)\n        // then we keep it in the renderer.\n        if (binding.refCount > 0) {\n            return;\n        }\n        this.freeIndices.push(binding.index);\n        this.materialsAllocator.deallocate(binding.index);\n        this.materials[binding.index] = null;\n        this.materialBindings.delete(material);\n        if (binding.listenerIDs['updated'] && binding.glMaterial) {\n            binding.glMaterial.off('updated', binding.listenerIDs['updated']);\n        }\n        if (binding.listenerIDs['parameterValueChanged']) {\n            material.off('parameterValueChanged', binding.listenerIDs['parameterValueChanged']);\n        }\n        if (this.dirtyIndices.has(binding.index)) {\n            this.dirtyIndices.delete(binding.index);\n        }\n    }\n    /**\n     * The uploadMaterials method.\n     * @param renderstate - The render state for the current draw traversal\n     */\n    uploadMaterials(renderstate) {\n        const gl = this.renderer.__gl;\n        const materialsTextureSize = MathFunctions.nextPow2(Math.ceil(Math.sqrt(this.materialsAllocator.reservedSpace)));\n        const unit = renderstate.boundTextures++;\n        gl.activeTexture(gl.TEXTURE0 + unit);\n        if (!this.materialsTexture) {\n            this.materialsTexture = new GLTexture2D(this.renderer.__gl, {\n                format: 'RGBA',\n                type: 'FLOAT',\n                width: materialsTextureSize,\n                height: materialsTextureSize,\n                filter: 'NEAREST',\n                wrap: 'CLAMP_TO_EDGE',\n                mipMapped: false,\n            });\n            this.materialsTexture.clear();\n        }\n        else if (this.materialsTexture.width < materialsTextureSize) {\n            this.materialsTexture.resize(materialsTextureSize, materialsTextureSize);\n            for (let i = 0; i < this.materials.length; i++) {\n                if (this.materialsAllocator.getAllocation(i)) {\n                    this.dirtyIndices.add(i);\n                }\n            }\n        }\n        const tex = this.materialsTexture;\n        const texWidth = this.materialsTexture.width;\n        gl.bindTexture(gl.TEXTURE_2D, tex.glTex);\n        this.dirtyIndices.forEach((index) => {\n            const allocation = this.materialsAllocator.getAllocation(index);\n            const material = this.materials[index];\n            const matData = material.getShaderClass().getPackedMaterialData(material);\n            const level = 0;\n            const xoffset = allocation.start % texWidth;\n            const height = 1;\n            const rows = Math.ceil((xoffset + allocation.size) / texWidth);\n            let consumed = 0;\n            let remaining = allocation.size;\n            let rowStart = xoffset;\n            for (let i = 0; i < rows; i++) {\n                let width;\n                if (rowStart + remaining > texWidth) {\n                    width = texWidth - rowStart;\n                    rowStart = 0;\n                }\n                else {\n                    width = remaining;\n                }\n                const x = (allocation.start + consumed) % texWidth;\n                const y = Math.floor((allocation.start + consumed) / texWidth);\n                const data = matData.subarray(consumed * 4, (consumed + width) * 4);\n                gl.texSubImage2D(gl.TEXTURE_2D, level, x, y, width, height, tex.format, tex.type, data);\n                consumed += width;\n                remaining -= width;\n            }\n        });\n        this.dirtyIndices = new Set();\n        gl.bindTexture(gl.TEXTURE_2D, null);\n        renderstate.boundTextures--;\n    }\n    /**\n     * Updates the GPU state if any update is needed.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    update(renderstate) {\n        if (this.dirtyIndices.size > 0)\n            this.uploadMaterials(renderstate);\n    }\n    /**\n     * The bind method.\n     * @param renderstate - The renderstate param.\n     * @return - The return value.\n     */\n    bind(renderstate) {\n        if (this.dirtyIndices.size > 0)\n            this.uploadMaterials(renderstate);\n        if (!this.materialsTexture)\n            return false;\n        const { materialsTexture, materialsTextureSize } = renderstate.unifs;\n        if (materialsTexture) {\n            this.materialsTexture.bindToUniform(renderstate, materialsTexture);\n            if (materialsTextureSize) {\n                const gl = this.renderer.gl;\n                gl.uniform2i(materialsTextureSize.location, this.materialsTexture.width, this.materialsTexture.height);\n            }\n        }\n        return true;\n    }\n}\n\n/** Class representing GL points.\n * @extends GLGeom\n * @private\n */\nclass GLPoints extends GLGeom {\n    /**\n     * Create a GL point.\n     * @param gl - The webgl rendering context.\n     * @param points - The points value.\n     */\n    constructor(gl, points) {\n        super(gl, points);\n    }\n    /**\n     * The draw method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    draw(renderstate) {\n        const gl = this.__gl;\n        // Support drawing custom geometry per point.\n        // e.g. the arrow shader.\n        if (renderstate.shaderInstancedGeom) {\n            gl.drawElementsInstanced(gl.TRIANGLES, renderstate.shaderInstancedGeom.numTriIndices, renderstate.shaderInstancedGeom.indexDataType, 0, this.numVertices);\n        }\n        else {\n            gl.drawArrays(gl.POINTS, 0, this.numVertices);\n        }\n    }\n    /**\n     * The drawInstanced method.\n     * @param renderstate - The object tracking the current state of the renderer\n     * @param instanceCount - The instanceCount value.\n     */\n    drawInstanced(renderstate, instanceCount) {\n        const gl = this.__gl;\n        gl.drawArraysInstanced(this.__gl.POINTS, 0, this.numVertices, instanceCount);\n    }\n}\n\nconst convertValue = (srcData, index) => {\n    if (srcData instanceof Int16Array || srcData instanceof Uint16Array) {\n        return MathFunctions.decode16BitFloat(srcData[index]);\n    }\n    else if (srcData instanceof Int16Array || srcData instanceof Uint16Array) {\n        return MathFunctions.decode16BitFloat(srcData[index]);\n    }\n    return srcData[index];\n};\nconst convertBuffer = (gl, attrData, attrDesc) => {\n    const srcData = attrData.values;\n    const tgtLength = attrData.count * attrDesc.dimension;\n    // console.log('convertBuffer:', attrDesc.name, srcData)\n    switch (attrDesc.dataType) {\n        case gl.BYTE:\n            if (srcData instanceof Int8Array)\n                return srcData;\n            const tgt = new Int8Array(tgtLength);\n            if (srcData instanceof Float32Array) {\n                srcData.forEach((value, i) => {\n                    const tgtIdx = (i % attrData.dimension) + Math.floor(i / attrData.dimension) * attrDesc.dimension;\n                    tgt[tgtIdx] = MathFunctions.remap(value, -1, 1, -127, 127);\n                });\n            }\n            return tgt;\n        case gl.UNSIGNED_BYTE: {\n            if (srcData instanceof Uint8Array)\n                return srcData;\n            const tgt = new Uint8Array(tgtLength);\n            if (srcData instanceof Float32Array) {\n                srcData.forEach((value, i) => {\n                    const tgtIdx = (i % attrData.dimension) + Math.floor(i / attrData.dimension) * attrDesc.dimension;\n                    tgt[tgtIdx] = MathFunctions.remap(value, 0, 1, 0, 255);\n                });\n            }\n            return tgt;\n        }\n        case gl.UNSIGNED_SHORT: {\n            if (srcData instanceof Uint16Array)\n                return srcData;\n            const tgt = new Uint16Array(tgtLength);\n            for (let i = 0; i < attrData.count; i++) {\n                tgt.set(srcData.subarray(i * attrData.dimension, (i + 1) * attrData.dimension), i * attrDesc.dimension);\n            }\n            return tgt;\n        }\n        case gl.SHORT: {\n            if (srcData instanceof Int16Array)\n                return srcData;\n            const tgt = new Int16Array(tgtLength);\n            for (let i = 0; i < attrData.count; i++) {\n                tgt.set(srcData.subarray(i * attrData.dimension, (i + 1) * attrData.dimension), i * attrDesc.dimension);\n            }\n            return tgt;\n        }\n        case gl.HALF_FLOAT: {\n            if (srcData instanceof Uint16Array)\n                return srcData;\n            if (srcData instanceof Float32Array) {\n                return MathFunctions.convertFloat32ArrayToUInt16Array(srcData);\n            }\n            throw 'Unable to convert from src data array';\n        }\n        case gl.FLOAT: {\n            if (srcData instanceof Float32Array)\n                return srcData;\n            const tgt = new Float32Array(tgtLength);\n            if (srcData instanceof Uint16Array) {\n                for (let i = 0; i < srcData.length; i++) {\n                    tgt[i] = MathFunctions.decode16BitFloat(srcData[i]);\n                }\n            }\n            return tgt;\n        }\n        default:\n            throw `Unhandled attribute type: ${attrDesc.dataType} for ${srcData.constructor.name}`;\n    }\n};\n\n/** Class representing GL lines.\n * @extends GLGeom\n * @private\n */\nclass GLLines extends GLGeom {\n    numSegIndices = -1;\n    fatBuffersNeedUpload = true;\n    numFatVertices = -1;\n    fatBuffers = null;\n    indexDataType = 0;\n    /**\n     * Create a GL line.\n     * @param gl - The webgl rendering context.\n     * @param lines - The geom value.\n     */\n    constructor(gl, lines) {\n        super(gl, lines);\n    }\n    /**\n     * The dirtyBuffers method.\n     * @param opts - options passed when geomDataChanged is emitted. (Currently ony used by the FreehandLines tool)\n     */\n    dirtyBuffers(opts) {\n        super.dirtyBuffers(opts);\n        this.fatBuffersNeedUpload = true;\n        this.emit('updated');\n    }\n    /**\n     * The clearBuffers method.\n     */\n    clearBuffers() {\n        const gl = this.__gl;\n        gl.deleteBuffer(this.indexBuffer);\n        this.indexBuffer = null;\n        if (this.fatBuffers && this.fatBuffers.positionsTexture) {\n            if (this.fatBuffers.positionsTexture) {\n                this.fatBuffers.positionsTexture.destroy();\n                this.fatBuffers.positionsTexture = null;\n            }\n            const segmentIndices = this.fatBuffers.glattrbuffers.segmentIndices;\n            if (segmentIndices.buffer) {\n                gl.deleteBuffer(segmentIndices.buffer);\n                this.fatBuffers.glattrbuffers.segmentIndices = null;\n            }\n        }\n        super.clearBuffers();\n    }\n    /**\n     * The genFatBuffers method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    genFatBuffers(renderstate) {\n        // if (!(this.geom instanceof Lines)\n        const gl = this.__gl;\n        const geomBuffers = this.geom.genBuffers();\n        const indices = geomBuffers.indices;\n        const numVertsChanged = geomBuffers.numVertices != this.numFatVertices;\n        if (!gl.__quadVertexIdsBuffer) {\n            gl.setupInstancedQuad();\n        }\n        if (!this.fatBuffers) {\n            this.fatBuffers = { drawCount: 0, positionsTexture: null, glattrbuffers: {} };\n            this.fatBuffers.glattrbuffers.vertexIDs = gl.__quadattrbuffers.vertexIDs;\n        }\n        const unit = renderstate.boundTextures++;\n        gl.activeTexture(this.__gl.TEXTURE0 + unit);\n        this.fatBuffers.drawCount = indices.length / 2;\n        const positions = geomBuffers.attrBuffers.positions;\n        const lineThicknessAttr = geomBuffers.attrBuffers.lineThickness;\n        const stride = 4; // The number of floats per draw item.\n        const dataArray = new Float32Array(positions.count * stride);\n        for (let i = 0; i < positions.count; i++) {\n            dataArray[i * stride + 0] = convertValue(positions.values, i * 3 + 0);\n            dataArray[i * stride + 1] = convertValue(positions.values, i * 3 + 1);\n            dataArray[i * stride + 2] = convertValue(positions.values, i * 3 + 2);\n            // The thickness of the line.\n            if (lineThicknessAttr)\n                dataArray[i * stride + 3] = convertValue(lineThicknessAttr.values, i);\n            else\n                dataArray[i * stride + 3] = 1.0;\n        }\n        if (numVertsChanged && this.fatBuffers.positionsTexture) {\n            this.fatBuffers.positionsTexture.destroy();\n            this.fatBuffers.positionsTexture = null;\n        }\n        if (!this.fatBuffers.positionsTexture) {\n            this.fatBuffers.positionsTexture = new GLTexture2D(this.__gl, {\n                format: 'RGBA',\n                type: 'FLOAT',\n                width: positions.count,\n                /* each pixel has 4 floats*/\n                height: 1,\n                filter: 'NEAREST',\n                wrap: 'CLAMP_TO_EDGE',\n                data: dataArray,\n                mipMapped: false,\n            });\n        }\n        else {\n            this.fatBuffers.positionsTexture.bufferData(dataArray, positions.count, 1);\n        }\n        const makeIndices = () => {\n            const indexArray = new Float32Array(indices.length);\n            for (let i = 0; i < indices.length; i++) {\n                let seqentialIndex;\n                if (i % 2 == 0) {\n                    seqentialIndex = i > 0 ? indices[i] == indices[i - 1] : indices[i] == indices[indices.length - 1];\n                }\n                else {\n                    seqentialIndex = i < indices.length - 1 ? indices[i] == indices[i + 1] : indices[i] == indices[0];\n                }\n                // encode the flag into the indices values.\n                // this flag is decoded in GLSL.\n                indexArray[i] = (seqentialIndex ? 1 : 0) + indices[i] * 2;\n            }\n            return indexArray;\n        };\n        if (!this.fatBuffers.glattrbuffers.segmentIndices) {\n            const indexBuffer = gl.createBuffer();\n            gl.bindBuffer(gl.ARRAY_BUFFER, indexBuffer);\n            gl.bufferData(gl.ARRAY_BUFFER, makeIndices(), gl.STATIC_DRAW);\n            this.fatBuffers.glattrbuffers.segmentIndices = {\n                dataType: gl.FLOAT,\n                name: 'segmentIndices',\n                dimension: 2,\n                elementSize: 4,\n                normalized: false,\n                shared: false,\n                numValues: indices.length,\n                buffer: indexBuffer,\n            };\n        }\n        else {\n            if (!this.genBufferOpts || (this.genBufferOpts && this.genBufferOpts.topologyChanged)) {\n                gl.bindBuffer(gl.ARRAY_BUFFER, this.fatBuffers.glattrbuffers.segmentIndices.buffer);\n                gl.bufferData(gl.ARRAY_BUFFER, makeIndices(), gl.STATIC_DRAW);\n            }\n        }\n        gl.bindTexture(gl.TEXTURE_2D, null);\n        renderstate.boundTextures--;\n        this.numSegIndices = indices.length;\n        this.numFatVertices = geomBuffers.numVertices;\n        this.fatBuffersNeedUpload = false;\n    }\n    /**\n     * The genBuffers method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    genBuffers(renderstate) {\n        super.genBuffers(renderstate);\n        const gl = this.__gl;\n        const geomBuffers = this.geom.genBuffers();\n        const indices = geomBuffers.indices;\n        // Note: the topology can change without the number of vertices changing\n        // and vice versa.\n        if (this.numSegIndices != indices.length) {\n            gl.deleteBuffer(this.indexBuffer);\n            this.indexBuffer = gl.createBuffer();\n        }\n        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);\n        gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);\n        this.numSegIndices = indices.length;\n        this.numVertices = geomBuffers.numVertices;\n        if (indices instanceof Uint8Array)\n            this.indexDataType = this.__gl.UNSIGNED_BYTE;\n        if (indices instanceof Uint16Array)\n            this.indexDataType = this.__gl.UNSIGNED_SHORT;\n        if (indices instanceof Uint32Array)\n            this.indexDataType = this.__gl.UNSIGNED_INT;\n    }\n    /**\n     * The bind method.\n     * @param renderstate - The object tracking the current state of the renderer\n     * @return - The return value.\n     */\n    bind(renderstate) {\n        const gl = this.__gl;\n        const unifs = renderstate.unifs;\n        const { LineThickness, geomType } = renderstate.unifs;\n        if (geomType)\n            this.__gl.uniform1i(geomType.location, 1 /*GeomType.LINES*/);\n        if (LineThickness && gl.floatTexturesSupported) {\n            if (this.fatBuffersNeedUpload)\n                this.genFatBuffers(renderstate); // (renderstate, true)\n            const fatBuffers = this.fatBuffers;\n            let shaderBinding = this.shaderBindings[renderstate.shaderkey];\n            if (!shaderBinding) {\n                shaderBinding = generateShaderGeomBinding(this.__gl, renderstate.attrs, fatBuffers.glattrbuffers, gl.__quadIndexBuffer);\n                this.shaderBindings[renderstate.shaderkey] = shaderBinding;\n            }\n            shaderBinding.bind(renderstate);\n            if (unifs.positionsTexture) {\n                fatBuffers.positionsTexture.bindToUniform(renderstate, unifs.positionsTexture);\n                gl.uniform1i(unifs.positionsTextureSize.location, fatBuffers.positionsTexture.width);\n            }\n            return true;\n        }\n        else {\n            super.bind(renderstate);\n            return true;\n        }\n    }\n    // ////////////////////////////////\n    // Drawing Lines Points.\n    /**\n     * The drawPoints method.\n     */\n    drawPoints() {\n        this.__gl.drawArrays(this.__gl.POINTS, 0, this.geom.getNumVertices());\n    }\n    // ////////////////////////////////\n    // Regular Drawing.\n    /**\n     * The draw method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    draw(renderstate) {\n        const gl = this.__gl;\n        if (renderstate.unifs.LineThickness && gl.floatTexturesSupported) {\n            gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, this.fatBuffers.drawCount);\n            // Note: We don't have a solution for drawing fat lines to the geom data buffer.\n        }\n        else {\n            gl.drawElements(this.__gl.LINES, this.numSegIndices, this.indexDataType, 0);\n        }\n    }\n    /**\n     * The drawInstanced method.\n     * @param renderstate - The object tracking the current state of the renderer\n     * @param instanceCount - The instanceCount value.\n     */\n    drawInstanced(renderstate, instanceCount) {\n        const gl = this.__gl;\n        const { occluded } = renderstate.unifs;\n        if (occluded) {\n            gl.uniform1i(occluded.location, 0);\n        }\n        gl.drawElementsInstanced(this.__gl.LINES, this.numSegIndices, this.indexDataType, 0, instanceCount);\n        if (occluded) {\n            gl.uniform1i(occluded.location, 1);\n            gl.depthFunc(gl.GREATER);\n            gl.drawElementsInstanced(this.__gl.LINES, this.numSegIndices, this.indexDataType, 0, instanceCount);\n            gl.depthFunc(gl.LEQUAL);\n        }\n    }\n}\n\n/** Class representing a GL mesh.\n * @extends GLGeom\n * @private\n */\nclass GLCompoundGeom extends GLGeom {\n    indexDataType = 0;\n    drawCounts = {};\n    /**\n     * Create a GL mesh.\n     * @param gl - The webgl rendering context.\n     * @param compoundGeom - The CompoundGeom value.\n     */\n    constructor(gl, compoundGeom) {\n        //@ts-ignore.\n        super(gl, compoundGeom);\n    }\n    // /////////////////////////////////////\n    // Buffers\n    /**\n     * The genBuffers method.\n     */\n    genBuffers(renderstate) {\n        super.genBuffers(renderstate);\n        const gl = this.__gl;\n        const geomBuffers = this.geom.genBuffers();\n        const indices = geomBuffers.indices;\n        let elementSize = 0;\n        if (indices instanceof Uint8Array) {\n            this.indexDataType = this.__gl.UNSIGNED_BYTE;\n            elementSize = 1;\n        }\n        else if (indices instanceof Uint16Array) {\n            this.indexDataType = this.__gl.UNSIGNED_SHORT;\n            elementSize = 2;\n        }\n        else if (indices instanceof Uint32Array) {\n            this.indexDataType = this.__gl.UNSIGNED_INT;\n            elementSize = 4;\n        }\n        this.numVertices = this.geom.getNumVertices();\n        if (this.indexBuffer) {\n            gl.deleteBuffer(this.indexBuffer);\n        }\n        this.indexBuffer = gl.createBuffer();\n        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);\n        gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, geomBuffers.indices, gl.STATIC_DRAW);\n        this.updateDrawIds(renderstate, geomBuffers, elementSize);\n        this.buffersDirty = false;\n    }\n    updateDrawIds(renderstate, geomBuffers, elementSize) {\n        const materials = geomBuffers.materials;\n        const getMaterialAddr = (materialId) => {\n            const material = materials[materialId];\n            const materialAddr = renderstate.renderer.glMaterialLibrary.getMaterialAllocation(material);\n            return materialAddr.start;\n        };\n        {\n            if (geomBuffers.materialSubGeoms && false) {\n                for (let key in geomBuffers.materialSubGeoms) {\n                    if (geomBuffers.materialSubGeoms[key].length > 0) {\n                        const subGeoms = geomBuffers.materialSubGeoms[key];\n                        const drawSubGeom = {\n                            geomType: GeomType$2[key],\n                            offsets: new Int32Array(subGeoms.length),\n                            counts: new Int32Array(subGeoms.length),\n                            materialIds: new Uint8Array(subGeoms.length),\n                        };\n                        for (let i = 0; i < subGeoms.length; i++) {\n                            drawSubGeom.offsets[i] = subGeoms[i].offset * elementSize;\n                            drawSubGeom.counts[i] = subGeoms[i].count;\n                            drawSubGeom.materialIds[i] = getMaterialAddr(subGeoms[i].materialId);\n                        }\n                        this.drawCounts[key] = drawSubGeom;\n                    }\n                }\n            }\n            else {\n                for (let key in geomBuffers.counts) {\n                    if (geomBuffers.counts[key] > 0) {\n                        const drawSubGeom = {\n                            geomType: GeomType$2[key],\n                            offsets: new Int32Array([geomBuffers.offsets[key] * elementSize]),\n                            counts: new Int32Array([geomBuffers.counts[key]]),\n                            materialIds: new Uint8Array(geomBuffers.counts.length),\n                        };\n                        this.drawCounts[key] = drawSubGeom;\n                    }\n                }\n            }\n        }\n    }\n    /**\n     * The updateBuffers method.\n     * @param opts - The options object.\n     */\n    updateBuffers(renderstate) {\n        this.__gl;\n        if (this.numVertices != this.geom.getNumVertices()) {\n            this.genBuffers(renderstate);\n            return;\n        }\n        super.updateBuffers(renderstate);\n        let elementSize = 0;\n        if (this.indexDataType == this.__gl.UNSIGNED_BYTE)\n            elementSize = 1;\n        if (this.indexDataType == this.__gl.UNSIGNED_SHORT)\n            elementSize = 2;\n        if (this.indexDataType == this.__gl.UNSIGNED_INT)\n            elementSize = 4;\n        const geomBuffers = this.geom.genBuffers({ includeIndices: false });\n        this.updateDrawIds(renderstate, geomBuffers, elementSize);\n    }\n    /**\n     * The clearBuffers method.\n     */\n    clearBuffers() {\n        const gl = this.__gl;\n        gl.deleteBuffer(this.indexBuffer);\n        this.indexBuffer = null;\n        super.clearBuffers();\n    }\n    // ////////////////////////////////\n    // Regular Drawing.\n    /**\n     * Draw an item to screen.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    draw(renderstate) {\n        this.drawInstanced(renderstate, 1);\n    }\n    /**\n     * The drawInstanced method.\n     * @param renderstate - The object tracking the current state of the renderer\n     * @param instanceCount - The instanceCount value.\n     */\n    drawInstanced(renderstate, instanceCount) {\n        renderstate.pushGLStack('GLCompoundGeom.drawInstanced');\n        const blendPointsAndLines = true;\n        const gl = this.__gl;\n        const { drawIds, geomType, outlineThickness, viewportSize, occluded } = renderstate.unifs;\n        const depthFuncValue = gl.getParameter(gl.DEPTH_FUNC);\n        let renderModeValue = null;\n        let drawingOutlines = false;\n        let drawingHiddenLines = false;\n        if (renderstate instanceof ColorRenderState) {\n            renderModeValue = renderstate.renderMode;\n            const drawEdges = renderModeValue != 'flat-noedges' && renderModeValue != 'shaded-noedges' && renderModeValue != 'pbr-noedges';\n            drawingOutlines =\n                outlineThickness &&\n                    viewportSize &&\n                    renderstate.outlineMethod == 'geometry' &&\n                    renderstate.outlineThickness > 0 &&\n                    drawEdges;\n            // Note: multiple different rendermodes could potentially draw hidden line.\n            drawingHiddenLines = renderModeValue == 'hiddenline' && occluded != null;\n        }\n        if (this.drawCounts['TRIANGLES']) {\n            if (geomType)\n                gl.uniform1i(geomType.location, GeomType$2.TRIANGLES);\n            if (renderModeValue == 'hiddenline') {\n                // don't render surfaces\n                gl.colorMask(false, false, false, false);\n            }\n            // Always zero this value before drawing the faces, else the shader could think its drawing the outline.\n            if (outlineThickness) {\n                gl.uniform1f(outlineThickness.location, 0);\n            }\n            const draw = this.drawCounts['TRIANGLES'];\n            const instCounts = draw.counts.map(() => instanceCount);\n            if (!gl.multiDrawElementsInstanced) {\n                for (let i = 0; i < draw.counts.length; i++) {\n                    if (drawIds) {\n                        gl.uniform2i(drawIds.location, i, draw.materialIds[i]);\n                    }\n                    this.__gl.drawElementsInstanced(gl.TRIANGLES, draw.counts[i], this.indexDataType, draw.offsets[i], instanceCount);\n                }\n            }\n            else {\n                gl.multiDrawElementsInstanced(gl.TRIANGLES, draw.counts, 0, this.indexDataType, draw.offsets, 0, instCounts, 0, draw.counts.length);\n            }\n            if (drawingOutlines) {\n                // Only draw font faces. BEcause all faces are drawn, it can make a mess to see the back faces through the front faces.\n                // e.g. we might see the triangles on the other side of a sphere rendered over the top of triangles on the near side.\n                renderstate.pushGLStack('GLCompoundGeom.drawingOutlines');\n                renderstate.glEnable(gl.CULL_FACE);\n                gl.cullFace(gl.FRONT);\n                // @ts-ignore\n                gl.uniform1f(outlineThickness.location, renderstate.outlineThickness * window.devicePixelRatio);\n                gl.uniform2f(viewportSize.location, renderstate.region[2] - renderstate.region[0], renderstate.region[3] - renderstate.region[1]);\n                if (renderModeValue == 'hiddenline') {\n                    // start rendering surfaces again\n                    gl.colorMask(true, true, true, true);\n                }\n                if (!gl.multiDrawElementsInstanced) {\n                    for (let i = 0; i < draw.counts.length; i++) {\n                        if (drawIds) {\n                            gl.uniform2i(drawIds.location, i, draw.materialIds[i]);\n                        }\n                        this.__gl.drawElementsInstanced(gl.TRIANGLES, draw.counts[i], this.indexDataType, draw.offsets[i], instanceCount);\n                    }\n                }\n                else {\n                    gl.multiDrawElementsInstanced(gl.TRIANGLES, draw.counts, 0, this.indexDataType, draw.offsets, 0, instCounts, 0, draw.counts.length);\n                }\n                renderstate.popGLStack();\n                gl.cullFace(gl.BACK);\n            }\n        }\n        if (renderstate instanceof ColorRenderState && blendPointsAndLines) {\n            renderstate.glEnable(gl.BLEND);\n            gl.blendEquation(gl.FUNC_ADD);\n            gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE);\n        }\n        if (this.drawCounts['LINES']) {\n            if (geomType)\n                gl.uniform1i(geomType.location, GeomType$2.LINES);\n            const draw = this.drawCounts['LINES'];\n            const instCounts = draw.counts.map(() => instanceCount);\n            if (!gl.multiDrawElementsInstanced) {\n                for (let i = 0; i < draw.counts.length; i++) {\n                    if (drawIds) {\n                        gl.uniform2i(drawIds.location, i, draw.materialIds[i]);\n                    }\n                    gl.drawElementsInstanced(gl.LINES, draw.counts[i], this.indexDataType, draw.offsets[i], instanceCount);\n                }\n            }\n            else {\n                gl.multiDrawElementsInstanced(gl.LINES, draw.counts, 0, this.indexDataType, draw.offsets, 0, instCounts, 0, draw.counts.length);\n            }\n            if (drawingHiddenLines) {\n                const { hiddenLineColor } = renderstate.unifs;\n                gl.uniform1i(occluded.location, 1);\n                // @ts-ignore\n                gl.uniform4fv(hiddenLineColor.location, renderstate.hiddenLineColor.asArray());\n                gl.depthFunc(gl.GREATER);\n                gl.depthMask(false);\n                if (!gl.multiDrawElementsInstanced) {\n                    for (let i = 0; i < draw.counts.length; i++) {\n                        if (drawIds) {\n                            gl.uniform2i(drawIds.location, i, draw.materialIds[i]);\n                        }\n                        gl.drawElementsInstanced(gl.LINES, draw.counts[i], this.indexDataType, draw.offsets[i], instanceCount);\n                    }\n                }\n                else {\n                    gl.multiDrawElementsInstanced(gl.LINES, draw.counts, 0, this.indexDataType, draw.offsets, 0, instCounts, 0, draw.counts.length);\n                }\n                // Restore defaults.\n                gl.depthFunc(depthFuncValue);\n                gl.depthMask(true);\n                gl.uniform1i(occluded.location, 0);\n            }\n        }\n        if (this.drawCounts['POINTS']) {\n            if (geomType)\n                gl.uniform1i(geomType.location, GeomType$2.POINTS);\n            const draw = this.drawCounts['POINTS'];\n            const instCounts = draw.counts.map(() => instanceCount);\n            {\n                gl.multiDrawElementsInstanced(gl.POINTS, draw.counts, 0, this.indexDataType, draw.offsets, 0, instCounts, 0, draw.counts.length);\n            }\n            if (drawingHiddenLines) {\n                const { hiddenLineColor } = renderstate.unifs;\n                gl.uniform1i(occluded.location, 1);\n                // @ts-ignore\n                gl.uniform4fv(hiddenLineColor.location, renderstate.hiddenLineColor.asArray());\n                gl.depthFunc(gl.GREATER);\n                gl.depthMask(false);\n                gl.multiDrawElementsInstanced(gl.POINTS, draw.counts, 0, this.indexDataType, draw.offsets, 0, instCounts, 0, draw.counts.length);\n                gl.depthFunc(depthFuncValue);\n                gl.depthMask(true);\n                gl.uniform1i(occluded.location, 0);\n            }\n        }\n        renderstate.popGLStack();\n    }\n    /**\n     * The destroy is called by the system to cause explicit resources cleanup.\n     * Users should never need to call this method directly.\n     */\n    destroy() {\n        super.destroy();\n        const gl = this.__gl;\n        gl.deleteBuffer(this.indexBuffer);\n        this.indexBuffer = null;\n        // if (this.__wireframesVao)\n        //     gl.deleteVertexArray(this.__wireframesVao);\n        // if (this.__hardEdgesVao)\n        //     gl.deleteVertexArray(this.__hardEdgesVao);\n    }\n}\n\n/**\n * An Image Atlas lays out multiple smaller images within a larger image atlas, and tracks their positions.\n * @private\n */\nclass GLImageAtlas extends GLTexture2D {\n    subImages = [];\n    layoutNeedsRegeneration = false;\n    asyncCount = 0;\n    layout = [];\n    freeIndices = [];\n    atlasLayoutTexture;\n    layoutVec4s = [];\n    constructor(gl, format, type) {\n        super(gl);\n        this.format = format;\n        this.type = type;\n    }\n    // eslint-disable-next-line require-jsdoc\n    incAsyncCount(count = 1) {\n        this.asyncCount += count;\n    }\n    // eslint-disable-next-line require-jsdoc\n    decAsyncCount() {\n        if (this.asyncCount > 0) {\n            this.asyncCount--;\n            if (this.asyncCount == 0) {\n                this.emit('loaded');\n            }\n        }\n    }\n    /**\n     * The isLoaded method.\n     * @return - The return value.\n     */\n    isLoaded() {\n        return this.asyncCount == 0;\n    }\n    get needsUpdate() {\n        return this.layoutNeedsRegeneration;\n    }\n    addSubImage(subImage) {\n        const index = this.freeIndices.length ? this.freeIndices.pop() : this.subImages.length;\n        if (!subImage.isLoaded()) {\n            this.incAsyncCount();\n            subImage.on('loaded', () => {\n                // This line triggers the rendering of labels.\n                subImage.getParams();\n                this.decAsyncCount();\n            });\n        }\n        subImage.on('updated', () => {\n            // TODO: Check to see if the new dimensions\n            // do not match the previous. If not, then we\n            // need to re-layout. We could also avoid a complete\n            // relayout by re-removing and re-adding this image.\n            this.layoutNeedsRegeneration = true;\n        });\n        this.subImages[index] = subImage;\n        this.layoutNeedsRegeneration = true;\n        return index;\n    }\n    removeSubImage(subImage) {\n        const index = this.subImages.indexOf(subImage);\n        this.freeIndices.push(index);\n        this.subImages[index] = null;\n        this.layoutNeedsRegeneration = true;\n    }\n    getSubImage(index) {\n        return this.subImages[index];\n    }\n    /**\n     * The numSubImages method.\n     * @return - The return value.\n     */\n    numSubImages() {\n        if (this.layout)\n            return this.layout.length;\n        return this.subImages.length - this.freeIndices.length;\n    }\n    generateAtlasLayout() {\n        if (this.subImages.length - this.freeIndices.length == 0) {\n            this.layoutNeedsRegeneration = false;\n            return;\n        }\n        const border = 2;\n        // We must lay out the sub images in order of size.\n        // else the paker might have trouble.\n        const blocks = [];\n        this.subImages.forEach((subImage, index) => {\n            if (!subImage)\n                return;\n            blocks.push({\n                w: subImage.width + border * 2,\n                h: subImage.height + border * 2,\n                area: subImage.width * subImage.height,\n                index,\n            });\n        });\n        blocks.sort((a, b) => (a.area > b.area ? -1 : a.area < b.area ? 1 : 0));\n        const packer = new GrowingPacker();\n        packer.fit(blocks);\n        this.layout = [];\n        blocks.forEach((block) => {\n            if (block.fit) {\n                this.layout[block.index] = {\n                    pos: new Vec2(block.fit.x + border, block.fit.y + border),\n                    size: new Vec2(block.w, block.h),\n                };\n            }\n            else {\n                console.warn('Unable to fit image');\n            }\n        });\n        const width = packer.root.w;\n        const height = packer.root.h;\n        const gl = this.gl;\n        if (!this.glTex) {\n            this.configure({\n                width,\n                height,\n                format: this.format,\n                type: this.type,\n                filter: gl.LINEAR,\n            });\n        }\n        else {\n            this.resize(width, height);\n        }\n        const pixelsPerItem = 1;\n        let size = Math.round(Math.sqrt(this.layout.length * pixelsPerItem) + 0.5);\n        // Only support power 2 textures. Else we get strange corruption on some GPUs\n        // in some scenes.\n        size = MathFunctions.nextPow2(size);\n        // Size should be a multiple of pixelsPerItem, so each geom item is always contiguous\n        // in memory. (makes updating a lot easier. See __updateItemInstanceData below)\n        if (size % pixelsPerItem != 0)\n            size += pixelsPerItem - (size % pixelsPerItem);\n        if (!gl.floatTexturesSupported) {\n            this.layoutVec4s = [];\n            this.layout.forEach((layoutItem, index) => {\n                if (!layoutItem)\n                    return;\n                this.layoutVec4s[index] = [\n                    layoutItem.pos.x / width,\n                    layoutItem.pos.y / height,\n                    layoutItem.size.x / width,\n                    layoutItem.size.y / height,\n                ];\n            });\n        }\n        else {\n            const dataArray = new Float32Array(size * size * 4); /* each pixel has 4 floats*/\n            this.layout.forEach((layoutItem, index) => {\n                if (!layoutItem)\n                    return;\n                const array = dataArray.subarray(index * 4, (index + 1) * 4);\n                array[0] = layoutItem.pos.x / width;\n                array[1] = layoutItem.pos.y / height;\n                array[2] = layoutItem.size.x / width;\n                array[3] = layoutItem.size.y / height;\n            });\n            if (!this.atlasLayoutTexture || this.atlasLayoutTexture.width != size || this.atlasLayoutTexture.height != size) {\n                if (this.atlasLayoutTexture)\n                    this.atlasLayoutTexture.destroy();\n                this.atlasLayoutTexture = new GLTexture2D(gl, {\n                    format: gl.RGBA,\n                    type: gl.FLOAT,\n                    filter: gl.NEAREST,\n                    wrap: gl.CLAMP_TO_EDGE,\n                    mipMapped: false,\n                    width: size,\n                    height: size,\n                    data: dataArray,\n                });\n            }\n            else {\n                this.atlasLayoutTexture.bufferData(dataArray, size, size);\n            }\n        }\n        this.textureDesc[0] = this.width;\n        this.textureDesc[1] = this.height;\n        this.textureDesc[2] = this.atlasLayoutTexture.width;\n        // this.textureDesc[3] // flags\n        this.layoutNeedsRegeneration = false;\n    }\n    /**\n     * The getLayoutData method.\n     * @param index - The index value.\n     * @return - The return value.\n     */\n    getLayoutData(index) {\n        return this.layoutVec4s[index];\n    }\n    /**\n     * The renderAtlas method.\n     * @param cleanup - The cleanup value.\n     * @param off - The off value.\n     */\n    renderAtlas(cleanup = false, off = 0) {\n        if (this.subImages.length - this.freeIndices.length == 0) {\n            return;\n        }\n        if (this.layoutNeedsRegeneration) {\n            this.generateAtlasLayout();\n        }\n        const gl = this.gl;\n        gl.bindTexture(gl.TEXTURE_2D, this.glTex);\n        // const unifs = renderstate.unifs\n        for (let j = off; j < this.subImages.length; j++) {\n            const subImage = this.subImages[j];\n            if (!subImage)\n                continue;\n            const layoutItem = this.layout[j];\n            const params = subImage.getParams();\n            const source = params.data;\n            gl.texSubImage2D(gl.TEXTURE_2D, 0, layoutItem.pos.x, layoutItem.pos.y, subImage.width, subImage.height, this.format, this.type, source);\n        }\n        if (cleanup) {\n            this.cleanup();\n        }\n        this.emit('updated');\n    }\n    /**\n     * The isReady method.\n     * @return - The return value.\n     */\n    isReady() {\n        return this.atlasLayoutTexture != undefined;\n    }\n    /**\n     * The bindToUniform method.\n     * @param renderstate - The object tracking the current state of the renderer\n     * @param unif - The WebGL uniform\n     * @return - The return value.\n     */\n    bindToUniform(renderstate, unif) {\n        super.bindToUniform(renderstate, unif);\n        const unifs = renderstate.unifs;\n        if (this.atlasLayoutTexture) {\n            const atlasLayoutUnif = unifs[unif.name + '_layout'];\n            if (atlasLayoutUnif)\n                this.atlasLayoutTexture.bindToUniform(renderstate, atlasLayoutUnif);\n            const atlasDescUnif = unifs[unif.name + '_desc'];\n            if (atlasDescUnif) {\n                this.gl.uniform4fv(atlasDescUnif.location, this.textureDesc);\n            }\n        }\n        else {\n            const atlasDescUnif = unifs[unif.name + '_desc'];\n            if (atlasDescUnif)\n                this.gl.uniform4f(atlasDescUnif.location, 0, 0, 0, 0);\n        }\n        return true;\n    }\n    /**\n     * The cleanup method.\n     */\n    cleanup() {\n        this.subImages = [];\n        this.destroy();\n    }\n    /**\n     * The destroy is called by the system to cause explicit resources cleanup.\n     * Users should never need to call this method directly.\n     */\n    destroy() {\n        this.cleanup();\n        super.destroy();\n    }\n}\n\n/** Class representing GL points.\n * @extends GLGeom\n * @private\n */\nclass GLFatPoints extends GLPoints {\n    indexArray = new Int32Array(0);\n    distances = new Float32Array(0);\n    pointsAttributesTexture = null;\n    texelsPerPoint = 1;\n    prevSortCameraPos = new Vec3();\n    threshold = 0;\n    atlas = null;\n    spriteCoords = null;\n    /**\n     * Create a GL point.\n     * @param gl - The webgl rendering context.\n     * @param points - The points value.\n     */\n    constructor(gl, points) {\n        super(gl, points);\n    }\n    /**\n     * The genBuffers method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    genBuffers(renderstate) {\n        const gl = this.__gl;\n        const points = this.geom;\n        const geomBuffers = this.geom.genBuffers();\n        this.numVertices = this.geom.getNumVertices();\n        this.texelsPerPoint = 1;\n        const positions = geomBuffers.attrBuffers.positions;\n        const colors = geomBuffers.attrBuffers.colors;\n        const sizes = geomBuffers.attrBuffers.sizes;\n        if (colors) {\n            this.texelsPerPoint = 2;\n        }\n        const spriteIndices = geomBuffers.attrBuffers.spriteIndices;\n        const sprites = points.getParameter('Sprites');\n        if (spriteIndices && sprites && sprites.value.length > 0) {\n            this.texelsPerPoint = 3;\n            this.atlas = new GLImageAtlas(gl, gl.RGBA, gl.UNSIGNED_BYTE);\n            const emitUpdated = (event) => this.emit('updated', event);\n            this.atlas.on('loaded', emitUpdated);\n            this.atlas.on('updated', emitUpdated);\n            const images = sprites.value;\n            images.forEach((image) => this.atlas.addSubImage(image));\n            if (this.atlas.isLoaded()) {\n                this.atlas.renderAtlas();\n            }\n            else {\n                // Note: Maybe the atlas is already up to date. It should\n                // maintain its own coherencey by listening to the sub images.\n                this.atlas.on('loaded', () => {\n                    this.atlas.renderAtlas();\n                });\n            }\n        }\n        const size = MathFunctions.nextPow2(Math.round(Math.sqrt(this.numVertices) + 0.5));\n        const data = new Float32Array(size * this.texelsPerPoint * size * 4);\n        const stride = this.texelsPerPoint * 4;\n        for (let i = 0; i < positions.count; i++) {\n            data[i * stride + 0] = convertValue(positions.values, i * 3 + 0);\n            data[i * stride + 1] = convertValue(positions.values, i * 3 + 1);\n            data[i * stride + 2] = convertValue(positions.values, i * 3 + 2);\n            if (sizes)\n                data[i * stride + 3] = sizes.values[i];\n            else\n                data[i * stride + 3] = 1.0;\n            if (colors) {\n                data.set(colors.values.subarray(i * 4, (i + 1) * 4), i * stride + 4);\n            }\n            if (spriteIndices) {\n                data[i * stride + 8] = spriteIndices.values[i];\n            }\n        }\n        const width = size * this.texelsPerPoint;\n        const height = size;\n        this.pointsAttributesTexture = new GLTexture2D(gl, {\n            format: gl.RGBA,\n            type: gl.FLOAT,\n            width,\n            height,\n            data,\n            filter: gl.NEAREST,\n            wrap: gl.CLAMP_TO_EDGE,\n            mipMapped: false,\n        });\n        this.numVertices = geomBuffers.numVertices;\n        this.buffersDirty = false;\n    }\n    /**\n     * The updateBuffers method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    updateBuffers(renderstate) {\n        if (this.numVertices != this.geom.getNumVertices()) {\n            this.genBuffers(renderstate);\n            return;\n        }\n        const geomBuffers = this.geom.genBuffers();\n        const positions = geomBuffers.attrBuffers.positions;\n        const sizes = geomBuffers.attrBuffers.sizes;\n        const colors = geomBuffers.attrBuffers.colors;\n        const spriteIndices = geomBuffers.attrBuffers.spriteIndices;\n        // Only support power 2 textures. Else we get strange corruption on some GPUs\n        // in some scenes.\n        const size = MathFunctions.nextPow2(Math.round(Math.sqrt(geomBuffers.numVertices) + 0.5));\n        const data = new Float32Array(size * this.texelsPerPoint * size * 4);\n        const stride = this.texelsPerPoint * 4;\n        for (let i = 0; i < positions.count; i++) {\n            data[i * stride + 0] = convertValue(positions.values, i * 3 + 0);\n            data[i * stride + 1] = convertValue(positions.values, i * 3 + 1);\n            data[i * stride + 2] = convertValue(positions.values, i * 3 + 2);\n            if (sizes)\n                data[i * stride + 3] = sizes.values[i];\n            else\n                data[i * stride + 3] = 1.0;\n            if (colors) {\n                data.set(colors.values.subarray(i * 4, (i + 1) * 4), i * stride + 4);\n            }\n            if (spriteIndices) {\n                data[i * stride + 8] = spriteIndices.values[i];\n            }\n        }\n        const width = size * this.texelsPerPoint;\n        const height = size;\n        this.pointsAttributesTexture.populate(data, width, height);\n        // Cache the size so we know later if it changed (see below)\n        this.numVertices = geomBuffers.numVertices;\n        this.buffersDirty = false;\n    }\n    /**\n     * The sort method.\n     * @param cameraPos - The cameraPos value.\n     */\n    sort(cameraPos) {\n        const positions = this.geom.positions;\n        this.distances = new Float32Array(positions.count);\n        let bufferSizeChanged = false;\n        if (this.indexArray.length != this.distances.length) {\n            this.indexArray = new Int32Array(this.distances.length);\n            bufferSizeChanged = true;\n        }\n        for (let i = 0; i < positions.count; i++) {\n            const pos = positions.getValue(i);\n            this.distances[i] = pos.distanceTo(cameraPos);\n            this.indexArray[i] = i;\n        }\n        this.indexArray.sort((a, b) => {\n            return this.distances[a] > this.distances[b] ? -1 : 1;\n        });\n        const gl = this.__gl;\n        if (!this.glattrbuffers.drawIndices) {\n            this.glattrbuffers.drawIndices = {\n                name: 'drawIndices',\n                dimension: 1,\n                elementSize: 4,\n                buffer: gl.createBuffer(),\n                dataType: gl.INT,\n                normalized: false,\n                shared: false,\n                numValues: positions.count,\n            };\n        }\n        else if (bufferSizeChanged) {\n            if (this.glattrbuffers.drawIndices.buffer)\n                gl.deleteBuffer(this.glattrbuffers.drawIndices.buffer);\n            this.glattrbuffers.drawIndices.buffer = gl.createBuffer();\n        }\n        gl.bindBuffer(gl.ARRAY_BUFFER, this.glattrbuffers.drawIndices.buffer);\n        gl.bufferData(gl.ARRAY_BUFFER, this.indexArray, gl.STATIC_DRAW);\n        this.threshold = 0.0;\n    }\n    /**\n     * The bind method.\n     * @param renderstate - The object tracking the current state of the renderer\n     * @return - The return value.\n     */\n    bind(renderstate) {\n        if (this.buffersDirty)\n            this.updateBuffers(renderstate);\n        if (renderstate.attrs.drawIndices) {\n            const cameraPos = renderstate.viewXfo.tr;\n            const dist = cameraPos.distanceTo(this.prevSortCameraPos);\n            // Avoid sorting if the camera did not move more than 3 meters.\n            if (dist > this.threshold) {\n                this.sort(cameraPos);\n                this.prevSortCameraPos = cameraPos.clone();\n                if (this.distances.length > 1) {\n                    const idx0 = this.indexArray[this.indexArray.length - 1];\n                    const dist0 = this.distances[idx0];\n                    this.threshold = dist0 * 0.25;\n                }\n                else {\n                    this.threshold = 9999;\n                }\n            }\n        }\n        let shaderBinding = this.shaderBindings[renderstate.shaderkey];\n        if (!shaderBinding) {\n            // Merge the points attrs with the quad attrs.\n            const attrbuffers = Object.assign(this.glattrbuffers, renderstate.shaderInstancedGeom.attrBuffers);\n            shaderBinding = generateShaderGeomBinding(this.__gl, renderstate.attrs, attrbuffers, renderstate.shaderInstancedGeom.indexBuffer);\n            this.shaderBindings[renderstate.shaderkey] = shaderBinding;\n        }\n        shaderBinding.bind(renderstate);\n        const { pointsAttributes, texelsPerPoint, atlasSprites } = renderstate.unifs;\n        if (pointsAttributes) {\n            this.pointsAttributesTexture.bindToUniform(renderstate, pointsAttributes);\n            this.__gl.uniform1i(texelsPerPoint.location, this.texelsPerPoint);\n        }\n        const { geomType } = renderstate.unifs;\n        if (geomType)\n            this.__gl.uniform1i(geomType.location, 2 /*GeomType.POINTS*/);\n        if (atlasSprites && this.atlas) {\n            this.atlas.bindToUniform(renderstate, atlasSprites);\n        }\n        return true;\n    }\n    /**\n     * The draw method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    draw(renderstate) {\n        const gl = this.__gl;\n        if (renderstate.shaderInstancedGeom) {\n            gl.drawElementsInstanced(gl.TRIANGLES, renderstate.shaderInstancedGeom.numTriIndices, renderstate.shaderInstancedGeom.indexDataType, 0, this.numVertices);\n        }\n        else {\n            gl.drawArrays(gl.POINTS, 0, this.numVertices);\n        }\n    }\n}\n\n/* eslint-disable guard-for-in */\nconst resizeIntArray = (intArray, newSize) => {\n    const newArray = new Int32Array(newSize);\n    newArray.set(intArray);\n    return newArray;\n};\n/** Class representing a GL geom.\n * @private\n */\nclass GLGeomLibrary extends EventEmitter {\n    renderer;\n    __gl;\n    freeGeomIndices = [];\n    geoms = [];\n    geomRefCounts = [];\n    geomsDict = new Map();\n    glGeomsDict = new Map();\n    geomBuffersTmp = []; // for each geom, these are the buffer\n    shaderAttrSpec = {};\n    glattrbuffers = {};\n    shaderBindings = {};\n    attributesBufferNeedsRealloc = false;\n    attributesBufferNeedsAlloc = [];\n    attributesAllocator = new Allocator1D();\n    dirtyGeomIndices = new Set();\n    geomVertexOffsets = new Int32Array(1);\n    geomVertexCounts = new Int32Array(1);\n    numIndices = 0;\n    indicesBufferNeedsRealloc = false;\n    indicesAllocator = new Allocator1D();\n    indicesCounts = new Int32Array(1);\n    indicesOffsets = new Int32Array(1);\n    indexBuffer = null;\n    freeDataAfterUpload = false;\n    __destroyed = false;\n    geomEventHandlerIds = [];\n    /**\n     * Create a GLGeomLibrary.\n     * @param renderer - The renderer object\n     */\n    constructor(renderer) {\n        super();\n        this.renderer = renderer;\n        this.__gl = renderer.gl;\n        // If the allocator ever resizes, then we need to re-upload everything.\n        this.attributesAllocator.on('resized', () => {\n            this.attributesBufferNeedsRealloc = true;\n        });\n        this.attributesAllocator.on('dataReallocated', (event) => {\n            // during allocation, a defragment might occur, which means\n            // we need to re-upload some of our data.\n            const id = event.id;\n            const allocation = event.allocation;\n            this.dirtyGeomIndices.add(id);\n            this.geomVertexOffsets[id] = allocation.start;\n            this.geomVertexCounts[id] = allocation.size;\n        });\n        this.freeGeomIndices.push(0);\n        // //////////////////////////////////////\n        // Indices\n        this.indicesAllocator.on('resized', () => {\n            // 540M indices == 2Gb of indices, which is the maximum allows by WebGL.\n            // This is because WebGL may accept JS arrays which can contain floating point indices.\n            // After we have allocated More than 256 Mb of indices, we then force allocations to be limited\n            // to the exact allocated space.\n            if (Math.log2(this.indicesAllocator.reservedSpace) >= 29) {\n                if (Math.log2(this.indicesAllocator.allocatedSpace) >= 29) {\n                    throw 'Indices buffer too big. WebGL cannot allocate index buffers more than 2Gb';\n                }\n                // console.log(\"this.indicesAllocator. capped to':\", this.indicesAllocator.allocatedSpace + 1)\n                this.indicesAllocator.reservedSpace = (1 << 29) - 1;\n            }\n            this.indicesBufferNeedsRealloc = true;\n        });\n        this.indicesAllocator.on('dataReallocated', (event) => {\n            // during allocation, a defragment might occur, which means\n            // we need to re-upload some of our data.\n            const id = event.id;\n            this.dirtyGeomIndices.add(id);\n        });\n        // Allocate enough space for 1M verts to begin with. This avoids lots of small\n        // copies when loading small files.\n        const size = 2 << 19;\n        this.reserveSpace(size, size * 2);\n        // this.shaderAttrSpec['positions'] = genDataTypeDesc(this.__gl, 'Vec4f16')\n        // this.shaderAttrSpec['normals'] = genDataTypeDesc(this.__gl, 'Vec4f8')\n    }\n    reserveSpace(attributeCount, vertexCount) {\n        this.attributesAllocator.reservedSpace = attributeCount;\n        this.indicesAllocator.reservedSpace = vertexCount;\n        this.attributesBufferNeedsRealloc = true;\n        this.indicesBufferNeedsRealloc = true;\n    }\n    /**\n     * Given a BaseGeom, constructs the GLGeom that manages the state of the geometry in the GPU.\n     * @param geom - The geom value.\n     * @return - The return value.\n     */\n    constructGLGeom(geom) {\n        let glgeom = this.glGeomsDict.get(geom);\n        if (glgeom != undefined) {\n            // Increment the ref count for the GLGeom\n            // glgeom.addRef(this)\n            return glgeom;\n        }\n        const gl = this.__gl;\n        if (geom instanceof Mesh || geom instanceof MeshProxy) {\n            glgeom = new GLMesh(gl, geom);\n        }\n        else if (geom instanceof Lines || geom instanceof LinesProxy) {\n            glgeom = new GLLines(gl, geom);\n        }\n        else if (geom instanceof FatPoints) {\n            glgeom = new GLFatPoints(gl, geom);\n        }\n        else if (geom instanceof Points || geom instanceof PointsProxy) {\n            glgeom = new GLPoints(gl, geom);\n        }\n        else if (geom instanceof CompoundGeom) {\n            glgeom = new GLCompoundGeom(gl, geom);\n        }\n        else {\n            throw new Error('Unsupported geom type:' + geom.constructor.name);\n        }\n        this.glGeomsDict.set(geom, glgeom);\n        glgeom.on('updated', () => {\n            this.renderer.requestRedraw();\n        });\n        glgeom.addRef(this);\n        return glgeom;\n    }\n    /**\n     * Adds a geom to the GLGeomLibrary.\n     *\n     * @param geom - The geom to be managed by this GLGeomLibrary.\n     * @return - The index of the geom in the GLGeomLibrary\n     */\n    addGeom(geom) {\n        let index = this.geomsDict.get(geom);\n        if (index != undefined) {\n            // Increment the ref count for the GLGeom\n            this.geomRefCounts[index]++;\n            return index;\n        }\n        if (this.freeGeomIndices.length == 0) {\n            const prevSize = this.geomVertexCounts.length;\n            const newSize = prevSize * 2;\n            this.geomVertexCounts = resizeIntArray(this.geomVertexCounts, newSize);\n            this.geomVertexOffsets = resizeIntArray(this.geomVertexOffsets, newSize);\n            this.indicesCounts = resizeIntArray(this.indicesCounts, newSize);\n            this.indicesOffsets = resizeIntArray(this.indicesOffsets, newSize);\n            for (let i = newSize - 1; i >= prevSize; i--) {\n                this.freeGeomIndices.push(i);\n            }\n        }\n        index = this.freeGeomIndices.pop();\n        this.geoms[index] = geom;\n        this.geomRefCounts[index] = 1;\n        this.geomsDict.set(geom, index);\n        this.dirtyGeomIndices.add(index);\n        this.geomVertexCounts[index] = 0;\n        this.geomVertexOffsets[index] = 0;\n        this.indicesCounts[index] = 0;\n        this.indicesOffsets[index] = 0;\n        const geomDataChanged = () => {\n            this.dirtyGeomIndices.add(index);\n            this.emit('updated');\n        };\n        const geomDataTopologyChanged = () => {\n            this.dirtyGeomIndices.add(index);\n            this.emit('updated');\n        };\n        const eventHandlerIds = {};\n        eventHandlerIds.geomDataChanged = geom.on('geomDataChanged', geomDataChanged);\n        eventHandlerIds.geomDataTopologyChanged = geom.on('geomDataTopologyChanged', geomDataTopologyChanged);\n        if (geom instanceof CompoundGeom) {\n            const glMaterialLibrary = this.renderer.glMaterialLibrary;\n            geom.materials.forEach((material) => {\n                // Some zcad files are having null materials here.\n                // This is a bug in the encoding of zcad files that needs to be addressed.\n                if (material) {\n                    glMaterialLibrary.addMaterial(material);\n                }\n            });\n            eventHandlerIds.materialsChanged = geom.on('materialsChanged', () => {\n                geom.materials.forEach((material) => {\n                    if (material) {\n                        glMaterialLibrary.addMaterial(material);\n                    }\n                });\n                this.emit('geomDataChanged', new IndexEvent(index));\n                this.emit('updated');\n            });\n        }\n        this.geomEventHandlerIds[index] = eventHandlerIds;\n        return index;\n    }\n    /**\n     * Removes a Geom managed by this GLGeomLibrary.\n     * @param geom - The geom to remove\n     */\n    removeGeom(geom) {\n        let index;\n        if (geom instanceof BaseGeom || geom instanceof BaseProxy) {\n            index = this.geomsDict.get(geom);\n        }\n        else {\n            index = geom;\n            geom = this.geoms[index];\n        }\n        if (index == undefined) {\n            console.warn('geom does not exist in the GLGeomLibrary');\n            return;\n        }\n        this.geomRefCounts[index]--;\n        // If there are still refs to this geom. (GeomItems that use it)\n        // then we keep it in the renderer.\n        if (this.geomRefCounts[index] > 0) {\n            return;\n        }\n        // If the geom was never drawn, and we are already removing it, there may be no allocation.\n        if (this.attributesAllocator.getAllocation(index)) {\n            this.attributesAllocator.deallocate(index);\n        }\n        if (this.indicesAllocator.getAllocation(index)) {\n            this.indicesAllocator.deallocate(index);\n        }\n        if (this.dirtyGeomIndices.has(index)) {\n            this.dirtyGeomIndices.delete(index);\n        }\n        this.geomVertexCounts[index] = 0;\n        this.geomVertexOffsets[index] = 0;\n        this.geoms[index] = null;\n        this.freeGeomIndices.push(index);\n        this.geomsDict.delete(geom);\n        delete this.geomBuffersTmp[index];\n        this.indicesCounts[index] = 0;\n        this.indicesOffsets[index] = 0;\n        const eventHandlerIds = this.geomEventHandlerIds[index];\n        geom.off('geomDataChanged', eventHandlerIds.geomDataChanged);\n        geom.off('geomDataTopologyChanged', eventHandlerIds.geomDataTopologyChanged);\n        if (geom instanceof CompoundGeom) {\n            geom.off('materialsChanged', eventHandlerIds.materialsChanged);\n        }\n    }\n    /**\n     * Returns a Geom managed by this GLGeomLibrary.\n     * @param index - The index of the geom to retrieve\n     * @return - The return value.\n     */\n    getGeom(index) {\n        return this.geoms[index];\n    }\n    /**\n     * Returns a Geom managed by this GLGeomLibrary.\n     * @param index - The index of the geom to retrieve\n     * @return - The return value.\n     */\n    getGeomOffsetAndCount(index) {\n        return [this.indicesOffsets[index], this.indicesCounts[index]];\n    }\n    /**\n     * Returns a Geom managed by this GLGeomLibrary.\n     * @param {number} index - The index of the geom to retrieve\n     * @return {array} - The return value.\n     */\n    getGeomBuffers(index) {\n        return this.geomBuffersTmp[index];\n    }\n    // /////////////////////////////////////\n    // Buffers\n    /**\n     * Allocates space for the geomBuffers for the specified geometry\n     * @param index - The index of the geom to upload\n     */\n    allocateBuffers(index) {\n        const geom = this.geoms[index];\n        if (!geom)\n            return;\n        const geomBuffers = geom.genBuffers();\n        const numVerts = geomBuffers.numRenderVerts ? geomBuffers.numRenderVerts : geomBuffers.numVertices;\n        if (this.geomVertexCounts[index] != numVerts) {\n            if (numVerts == 0) {\n                this.attributesAllocator.deallocate(index);\n                this.geomVertexOffsets[index] = 0;\n                this.geomVertexCounts[index] = 0;\n            }\n            else {\n                const allocation = this.attributesAllocator.allocate(index, numVerts);\n                this.geomVertexOffsets[index] = allocation.start;\n                this.geomVertexCounts[index] = allocation.size;\n            }\n        }\n        // eslint-disable-next-line guard-for-in\n        for (const attrName in geomBuffers.attrBuffers) {\n            // Removing these because multi-draw doesn't support textures anyway\n            // so no need to upload texture coordinates.\n            if (attrName == 'textureCoords' || attrName == 'texCoords')\n                continue;\n            if (!this.shaderAttrSpec[attrName]) {\n                const attrData = geomBuffers.attrBuffers[attrName];\n                this.shaderAttrSpec[attrName] = genDataTypeDesc(this.__gl, attrData.dataType);\n                this.shaderAttrSpec[attrName].normalized = attrData.normalized;\n                this.attributesBufferNeedsAlloc.push(attrName);\n            }\n        }\n        // //////////////////////////////////////\n        // Indices\n        if (geomBuffers.indices) {\n            const numIndices = geomBuffers.indices.length;\n            if (this.indicesCounts[index] != numIndices) {\n                if (numIndices == 0) {\n                    this.indicesAllocator.deallocate(index);\n                    this.indicesOffsets[index] = 0;\n                    this.indicesCounts[index] = 0;\n                }\n                else {\n                    const allocation = this.indicesAllocator.allocate(index, numIndices);\n                    const elementSize = 4; //  Uint32Array for UNSIGNED_INT\n                    this.indicesOffsets[index] = allocation.start * elementSize; // offset is in bytes\n                    this.indicesCounts[index] = allocation.size;\n                }\n            }\n        }\n        else {\n            // Note: for non-indexed data, like Points, we provide\n            // the vertex data as offset and count in the method\n            // getGeomOffsetAndCount.\n            this.indicesOffsets[index] = this.geomVertexOffsets[index];\n            this.indicesCounts[index] = this.geomVertexCounts[index];\n        }\n        this.geomBuffersTmp[index] = geomBuffers;\n    }\n    /**\n     * Generates the GPU buffers required to store all the geometries\n     */\n    genAttributesBuffers() {\n        // eslint-disable-next-line guard-for-in\n        for (const attrName in this.shaderAttrSpec) {\n            this.genAttributesBuffer(attrName);\n        }\n        // Clear this list if it had anything in it.\n        this.attributesBufferNeedsAlloc = [];\n    }\n    /**\n     * Generates a single GPU buffer\n     */\n    genAttributesBuffer(attrName) {\n        // Removing these because multi-draw doesn't support textures anyway\n        // so no need to upload texture coordinates.\n        if (attrName == 'textureCoords' || attrName == 'texCoords')\n            return;\n        const reservedSpace = this.attributesAllocator.reservedSpace;\n        const gl = this.__gl;\n        {\n            const attrSpec = this.shaderAttrSpec[attrName];\n            const numValues = reservedSpace * attrSpec.dimension;\n            const attrBuffer = gl.createBuffer();\n            gl.bindBuffer(gl.ARRAY_BUFFER, attrBuffer);\n            const sizeInBytes = numValues * attrSpec.elementSize;\n            gl.bufferData(gl.ARRAY_BUFFER, sizeInBytes, gl.STATIC_DRAW);\n            if (this.glattrbuffers[attrName] && this.glattrbuffers[attrName].buffer) {\n                gl.bindBuffer(gl.COPY_WRITE_BUFFER, attrBuffer);\n                gl.bindBuffer(gl.COPY_READ_BUFFER, this.glattrbuffers[attrName].buffer);\n                gl.copyBufferSubData(gl.COPY_READ_BUFFER, gl.COPY_WRITE_BUFFER, 0, 0, this.glattrbuffers[attrName].numValues * attrSpec.elementSize);\n                gl.deleteBuffer(this.glattrbuffers[attrName].buffer);\n            }\n            this.glattrbuffers[attrName] = {\n                name: attrName,\n                elementSize: attrSpec.elementSize,\n                buffer: attrBuffer,\n                dataType: attrSpec.dataType,\n                normalized: attrSpec.normalized,\n                numValues: numValues,\n                dimension: attrSpec.dimension,\n                shared: false,\n            };\n        }\n    }\n    genIndicesBuffers() {\n        // //////////////////////////////////////\n        // Indices\n        const reservedSpace = this.indicesAllocator.reservedSpace;\n        if (this.numIndices != reservedSpace) {\n            const gl = this.__gl;\n            const indexBuffer = gl.createBuffer();\n            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);\n            const elementSize = 4; //  Uint32Array for UNSIGNED_INT\n            const sizeInBytes = reservedSpace * elementSize;\n            gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, sizeInBytes, gl.STATIC_DRAW);\n            if (this.indexBuffer) {\n                gl.bindBuffer(gl.COPY_WRITE_BUFFER, indexBuffer);\n                gl.bindBuffer(gl.COPY_READ_BUFFER, this.indexBuffer);\n                gl.copyBufferSubData(gl.COPY_READ_BUFFER, gl.COPY_WRITE_BUFFER, 0, 0, this.numIndices * elementSize);\n                gl.deleteBuffer(this.indexBuffer);\n            }\n            this.indexBuffer = indexBuffer;\n            this.numIndices = reservedSpace;\n        }\n    }\n    /**\n     * The uploadBuffers method.\n     * @param index - The index of the geom to upload\n     */\n    uploadBuffers(index) {\n        const gl = this.__gl;\n        // Note: when we allocate the buffers, we may resize the buffer, which\n        // means we need to re-upload geoms that were not changed.\n        let geomBuffers = this.geomBuffersTmp[index];\n        if (!geomBuffers) {\n            const geom = this.geoms[index];\n            if (!geom)\n                return;\n            geomBuffers = geom.genBuffers();\n            this.geomBuffersTmp[index] = geomBuffers;\n        }\n        const count = this.geomVertexCounts[index];\n        const numVerts = geomBuffers.numRenderVerts ? geomBuffers.numRenderVerts : geomBuffers.numVertices;\n        if (count != numVerts) {\n            throw new Error('Invalid allocation for this geom');\n        }\n        if (numVerts == 0) {\n            const event = new IndexEvent(index);\n            this.emit('geomDataChanged', event);\n            return;\n        }\n        // eslint-disable-next-line guard-for-in\n        for (const attrName in geomBuffers.attrBuffers) {\n            const attrSpec = this.shaderAttrSpec[attrName];\n            const attrData = geomBuffers.attrBuffers[attrName];\n            const glattrbuffer = this.glattrbuffers[attrName];\n            // Some geoms might not have all the attributes.\n            // and some geoms have more attributes than others.\n            if (!attrData || !glattrbuffer)\n                continue;\n            gl.bindBuffer(gl.ARRAY_BUFFER, glattrbuffer.buffer);\n            const elementSize = attrSpec.elementSize;\n            const offsetInBytes = this.geomVertexOffsets[index] * elementSize * attrSpec.dimension;\n            const values = convertBuffer(gl, attrData, attrSpec);\n            gl.bufferSubData(gl.ARRAY_BUFFER, offsetInBytes, values);\n        }\n        gl.bindBuffer(gl.ARRAY_BUFFER, null);\n        // //////////////////////////////////////\n        // Indices\n        // Note: we sometimes see geometries with zero vertices/indices which means\n        // no allocation has yet been made. We can safely skip these.\n        if (geomBuffers.indices && geomBuffers.indices.length > 0) {\n            const indices = geomBuffers.indices;\n            const allocation = this.indicesAllocator.getAllocation(index);\n            if (allocation.size != indices.length) {\n                throw new Error('Invalid allocation for this geom');\n            }\n            const attributesAllocation = this.attributesAllocator.getAllocation(index);\n            // The indices need to be offset so they they index the new attributes array.\n            const offsettedIndices = new Uint32Array(allocation.size);\n            for (let i = 0; i < indices.length; i++) {\n                offsettedIndices[i] = geomBuffers.indices[i] + attributesAllocation.start;\n            }\n            const gl = this.__gl;\n            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);\n            const elementSize = 4; //  Uint32Array\n            const offsetInBytes = allocation.start * elementSize;\n            gl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, offsetInBytes, offsettedIndices);\n            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);\n        }\n        if (this.freeDataAfterUpload) {\n            const geom = this.geoms[index];\n            geom.freeBuffers();\n        }\n        this.emit('geomDataChanged', new IndexEvent(index));\n    }\n    /**\n     * Cleans the state of this GeomSet during rendering.\n     */\n    cleanGeomBuffers() {\n        // First we allocate all memory needed to clean the GeomSet,\n        // and then we start uploading all the data.\n        this.dirtyGeomIndices.forEach((index) => {\n            this.allocateBuffers(index);\n        });\n        if (this.attributesBufferNeedsRealloc || this.indicesBufferNeedsRealloc) {\n            // If the geom buffers are re-allocated, we need to regenerate\n            // all the shader bindings.\n            this.resetBindings();\n            if (this.attributesBufferNeedsRealloc) {\n                this.genAttributesBuffers();\n                this.attributesBufferNeedsRealloc = false;\n            }\n            if (this.indicesBufferNeedsRealloc) {\n                this.genIndicesBuffers();\n                this.indicesBufferNeedsRealloc = false;\n            }\n            // console.log('GLGeomLibrary MemoryAllocation:', this.calcMemoryAllocation())\n        }\n        else if (this.attributesBufferNeedsAlloc.length > 0) {\n            // Sometimes new attributes are added after the main attributes.\n            // e.g. Normals could be computed.\n            // We now need to generate those missing buffers.\n            this.attributesBufferNeedsAlloc.forEach((attrName) => {\n                this.genAttributesBuffer(attrName);\n            });\n            this.attributesBufferNeedsAlloc = [];\n        }\n        this.dirtyGeomIndices.forEach((index) => {\n            this.uploadBuffers(index);\n        });\n        this.dirtyGeomIndices = new Set();\n    }\n    calcMemoryAllocation() {\n        const summary = {\n            attrs: {},\n            indices: {},\n        };\n        const MB = 1 << 20;\n        for (const attrName in this.shaderAttrSpec) {\n            const attrSpec = this.shaderAttrSpec[attrName];\n            const reservedSpace = this.attributesAllocator.reservedSpace;\n            const allocatedSpace = this.attributesAllocator.allocatedSpace;\n            const numValues = reservedSpace * attrSpec.dimension;\n            const sizeInBytes = numValues * attrSpec.elementSize;\n            summary.attrs[attrName] = {\n                count: allocatedSpace,\n                MB: sizeInBytes / MB,\n            };\n        }\n        const reservedSpace = this.indicesAllocator.reservedSpace;\n        const allocatedSpace = this.indicesAllocator.allocatedSpace;\n        const elementSize = 4; //  Uint32Array for UNSIGNED_INT\n        const sizeInBytes = reservedSpace * elementSize;\n        summary.indices = {\n            count: allocatedSpace,\n            MB: sizeInBytes / MB,\n        };\n        return summary;\n    }\n    // /////////////////////////////////////\n    // Binding\n    resetBindings() {\n        for (const shaderkey in this.shaderBindings) {\n            const shaderBinding = this.shaderBindings[shaderkey];\n            shaderBinding.destroy();\n        }\n        this.shaderBindings = {};\n    }\n    /**\n     * The bind method.\n     * @param renderstate - The renderstate value.\n     * @return - Returns true if binding was successful\n     */\n    bind(renderstate) {\n        if (this.dirtyGeomIndices.size > 0) {\n            this.cleanGeomBuffers();\n        }\n        const shaderkey = renderstate.glShader.getId() + renderstate.shaderkey;\n        let shaderBinding = this.shaderBindings[shaderkey];\n        if (!shaderBinding) {\n            const gl = this.__gl;\n            shaderBinding = generateShaderGeomBinding(gl, renderstate.attrs, this.glattrbuffers, this.indexBuffer);\n            this.shaderBindings[shaderkey] = shaderBinding;\n            if (SystemDesc.browserName == 'Safari' && SystemDesc.fullVersion == '15.4') {\n                // Hack to force the primitive restart index cache to be dirty...\n                // https://bugs.webkit.org/show_bug.cgi?id=239015\n                // - First draw updates the indexType to be correct (invalid enum -> draw buffer element type)\n                const gl = this.__gl;\n                gl.drawElements(gl.POINTS, 1, gl.UNSIGNED_INT, 0);\n                gl.drawElements(gl.LINES, 2, gl.UNSIGNED_INT, 0);\n                gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0);\n                // - dummy subbuffer update marks the cache dirty\n                // bufferSubData an array of size 1 at the end of the current allocation.\n                const dummyIndices = new Uint32Array(1);\n                const elementSize = 4; //  Uint32Array\n                const offsetInBytes = this.indicesAllocator.allocatedSpace * elementSize;\n                gl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, offsetInBytes, dummyIndices);\n            }\n        }\n        else {\n            shaderBinding.bind(renderstate);\n        }\n        return true;\n    }\n    /**\n     * The unbind method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    unbind(renderstate) {\n        // Unbinding a geom is important as it puts back some important\n        // GL state. (vertexAttribDivisor)\n        const shaderkey = renderstate.glShader.getId() + renderstate.shaderkey;\n        const shaderBinding = this.shaderBindings[shaderkey];\n        if (shaderBinding) {\n            shaderBinding.unbind(renderstate);\n        }\n    }\n    // /////////////////////////////////////\n    // Drawing\n    /**\n     * The clearBuffers method.\n     */\n    clearBuffers() {\n        const gl = this.__gl;\n        // eslint-disable-next-line guard-for-in\n        for (const attrName in this.glattrbuffers) {\n            const glbuffer = this.glattrbuffers[attrName];\n            if (glbuffer.shared)\n                continue; /* This buffer is shared between geoms. do not destroy */\n            gl.deleteBuffer(glbuffer.buffer);\n        }\n        this.glattrbuffers = {};\n        if (this.indexBuffer) {\n            gl.deleteBuffer(this.indexBuffer);\n            this.indexBuffer = null;\n        }\n        // eslint-disable-next-line guard-for-in\n        this.resetBindings();\n    }\n    /**\n     * The destroy is called by the system to cause explicit resources cleanup.\n     * Users should never need to call this method directly.\n     */\n    destroy() {\n        // this.geoms.forEach((geom) => this.removeGeom(geom))\n        this.clearBuffers();\n        this.__destroyed = true;\n        //  Note: PoTree listens to this event. If moved up into RefCounted, make sure it is still emitted.\n        this.emit('destructing');\n    }\n}\n\nconst GLGeomItemChangeType = {\n    GEOMITEM_CHANGED: 0,\n    GEOM_CHANGED: 1,\n    VISIBILITY_CHANGED: 2,\n    HIGHLIGHT_CHANGED: 3,\n};\nconst GLGeomItemFlags = {\n    GEOMITEM_FLAG_CUTAWAY: 2, // 1<<1;\n    GEOMITEM_INVISIBLE_IN_GEOMDATA: 4, // 1<<2;\n    GEOMITEM_TRANSPARENT: 8, // 1<<3;\n};\n/** This class is responsible for managing a GeomItem within the renderer.\n * @private\n * @extends EventEmitter\n */\nclass GLGeomItem extends EventEmitter {\n    listenerIDs = {};\n    // //referenced by other classes\n    GLGeomItemSet;\n    GLShaderGeomSets;\n    gl;\n    geomItem;\n    geomItemId;\n    geomId;\n    materialId;\n    supportInstancing;\n    visible;\n    shattered = false;\n    culled = false;\n    geomMatrixDirty = false;\n    modelMatrixArray;\n    geomData = [];\n    highlightSubIndex = -1;\n    /**\n     * Create a GL geom item.\n     * @param gl - The gl value.\n     * @param geomItem - The geomItem value.\n     * @param geomItemId - The geomItemId value.\n     * @param geomId - The geomId value.\n     * @param materialId - The materialId value.\n     * @param supportInstancing - a boolean to disable instancing support on some mobile platforms\n     */\n    constructor(gl, geomItem, geomItemId, geomId, materialId, supportInstancing = false) {\n        super();\n        this.gl = gl;\n        this.geomItem = geomItem;\n        this.geomItemId = geomItemId;\n        this.geomId = geomId;\n        this.materialId = materialId;\n        this.supportInstancing = supportInstancing;\n        this.visible = this.geomItem.isVisible();\n        this.listenerIDs['visibilityChanged'] = this.geomItem.on('visibilityChanged', (event) => {\n            const wasVisible = !this.culled && this.visible;\n            this.visible = event.state;\n            const isVisible = !this.culled && this.visible;\n            if (wasVisible != isVisible) {\n                this.emit('visibilityChanged', new StateChangedEvent(isVisible));\n            }\n        });\n        if (geomItem instanceof CADBody)\n            this.shattered = geomItem.shattered;\n        this.listenerIDs['shatterStateChanged'] = this.geomItem.on('shatterStateChanged', (event) => {\n            this.shattered = event.state;\n            this.emit('shatterStateChanged', event);\n        });\n        if (!this.supportInstancing) {\n            const highlightChanged = (event) => {\n                if (event.name) {\n                    const highlightName = event.name;\n                    const subGeomIndexIndex = highlightName.indexOf(':');\n                    let subGeomIndices = [];\n                    if (subGeomIndexIndex != -1) {\n                        subGeomIndices = highlightName\n                            .substring(subGeomIndexIndex + 1)\n                            .split(',')\n                            .map((v) => Number.parseInt(v));\n                        this.highlightSubIndex = subGeomIndices[0];\n                    }\n                }\n                else {\n                    this.highlightSubIndex = -1;\n                }\n            };\n            this.listenerIDs['highlightChanged'] = this.geomItem.on('highlightChanged', highlightChanged);\n        }\n    }\n    /**\n     * The isVisible method.\n     * @return - The return value.\n     */\n    isVisible() {\n        return !this.culled && this.visible;\n    }\n    /**\n     * Sets the additional culled value which controls visiblity\n     * @param culled - True if culled, else false.\n     */\n    setCulled(culled) {\n        const wasVisible = !this.culled && this.visible;\n        this.culled = culled;\n        const isVisible = !this.culled && this.visible;\n        if (wasVisible != isVisible) {\n            this.emit('visibilityChanged', new StateChangedEvent(isVisible));\n        }\n    }\n    /**\n     * The bind method.\n     * @param renderstate - The object tracking the current state of the renderer\n     * @return - The return value.\n     */\n    bind(renderstate) {\n        const gl = this.gl;\n        const { highlightSubIndex, geomItemId } = renderstate.unifs;\n        if (highlightSubIndex) {\n            gl.uniform1i(highlightSubIndex.location, this.highlightSubIndex);\n        }\n        if (geomItemId) {\n            gl.uniform1i(geomItemId.location, this.geomItemId);\n        }\n        return true;\n    }\n    /**\n     * The destroy is called by the system to cause explicit resources cleanup.\n     * Users should never need to call this method directly.\n     */\n    destroy() {\n        this.geomItem.off('visibilityChanged', this.listenerIDs['visibilityChanged']);\n        if (!this.supportInstancing) {\n            this.geomItem.off('highlightChanged', this.listenerIDs['highlightChanged']);\n        }\n    }\n}\n\n// eslint-disable-next-line require-jsdoc\nclass ReductionShader extends GLShader {\n    /**\n     * Create an atlas layout shader.\n     * @param gl - The webgl rendering context.\n     */\n    constructor(gl) {\n        super(gl, 'ReductionShader');\n        this.setShaderStage('VERTEX_SHADER', `\r\n\r\nprecision highp float;\r\n\r\nuniform int reductionTextureWidth;\r\nuniform sampler2D geomDataTexture;\r\n\r\nivec2 texelCoordFromVertexId(){\r\n  ivec2 texSize = textureSize(geomDataTexture, 0);\r\n  return ivec2(\r\n    gl_VertexID % texSize.x, \r\n    gl_VertexID / texSize.x\r\n    );\r\n}\r\n\r\nvec2 pointPositionFromGeomItemId(int geomItemId){\r\n  vec2 result = vec2(\r\n    (float(geomItemId % reductionTextureWidth) + 0.5) / float(reductionTextureWidth), \r\n    (float(geomItemId / reductionTextureWidth) + 0.5) / float(reductionTextureWidth)\r\n    );\r\n  return vec2(-1.0, -1.0) + (result * 2.0);\r\n}\r\n\r\n/* VS Outputs */\r\nvarying vec4 v_geomDataPixel;\r\n\r\nvoid main()\r\n{\r\n  // Get the texel coordinate in the source geomdata buffer.\r\n  // there is one point for every pixel in the geomdata texture.\r\n  ivec2 texelCoord = texelCoordFromVertexId();\r\n  v_geomDataPixel = texelFetch(geomDataTexture, texelCoord, 0);\r\n  int geomItemId = int(v_geomDataPixel.r + 0.5);\r\n\r\n  if (geomItemId > 0) {\r\n    vec2 position = pointPositionFromGeomItemId(geomItemId);\r\n    gl_Position = vec4(position, 0.0, 1.0);\r\n    gl_PointSize = 1.0;\r\n  } else {\r\n    // Move it off screen\r\n    gl_Position = vec4(-2.0, -2.0, 0.0, 1.0);\r\n    gl_PointSize = 0.0;\r\n  }\r\n}\r\n\r\n`);\n        this.setShaderStage('FRAGMENT_SHADER', `\r\nprecision highp float;\r\n\r\n\r\n/* VS Outputs */\r\nvarying vec4 v_geomDataPixel;\r\n\r\n#ifdef ENABLE_ES3\r\n  out vec4 fragColor;\r\n#endif\r\n\r\nvoid main(void) {\r\n#ifndef ENABLE_ES3\r\n  vec4 fragColor;\r\n#endif\r\n\r\n  fragColor.r = 1.0/255.0;\r\n\r\n  // Note: the green channel in the histogram image indicates if the source\r\n  // pixel contained a real geom or a bounding box.\r\n  fragColor.g = v_geomDataPixel.g;\r\n\r\n#ifndef ENABLE_ES3\r\n  gl_FragColor = fragColor;\r\n#endif\r\n}\r\n\r\n`);\n    }\n}\n\nvar frag$g = \"\\nprecision highp float;\\n#define GLSLIFY 1\\n\\n/* VS Outputs */\\nvarying vec4 v_color;\\n\\n#ifdef ENABLE_ES3\\n  out vec4 fragColor;\\n#endif\\nvoid main(void) {\\n#ifndef ENABLE_ES3\\n  vec4 fragColor;\\n#endif\\n\\n  int drawItemId = int(v_color.g);\\n  fragColor = v_color;\\n\\n#ifndef ENABLE_ES3\\n  gl_FragColor = fragColor;\\n#endif\\n}\\n\"; // eslint-disable-line\n\nvar vert$h = \"\\nprecision highp float;\\n#define GLSLIFY 1\\n\\nattribute vec4 positions;\\n\\nuniform mat4 viewMatrix;\\nuniform mat4 projectionMatrix;\\nuniform mat4 cameraMatrix;\\n\\nuniform highp int occlusionCulling;\\nuniform sampler2D reductionDataTexture;\\n\\nimport 'transpose.glsl'\\nimport 'GLSLUtils.glsl'\\nimport 'stack-gl/transpose.glsl'\\nimport 'stack-gl/inverse.glsl'\\nimport 'geomItemId.glsl'\\nimport 'drawItemTexture.glsl'\\nimport 'modelMatrix.glsl'\\n\\nconst int GEOMITEM_INVISIBLE_IN_GEOMDATA = 2; // 1<<1;\\n\\n/* VS Outputs */\\nvarying vec4 v_color;\\n\\nvoid main(void) {\\n\\n  int drawItemId = getGeomItemId();\\n  vec4 geomItemData  = getInstanceData(drawItemId);\\n  int flags = int(geomItemData.r + 0.5);\\n\\n  if (occlusionCulling != 0) {\\n    // Check if in the reduction texture, this item is already flagged as visible.\\n    // Note: we only draw bboxes for those that have been flagged as invisible, but might\\n    // be just off screen, or onscreen, but were culled in the previous update.\\n    float isVisible = fetchTexel(reductionDataTexture, textureSize(reductionDataTexture, 0), drawItemId).r;\\n    if (isVisible > 0.0) {\\n      return;\\n    }\\n  }\\n\\n  vec4 bboxMin = fetchTexel(instancesTexture, instancesTextureSize, (drawItemId * pixelsPerItem) + 6);\\n  vec4 bboxMax = fetchTexel(instancesTexture, instancesTextureSize, (drawItemId * pixelsPerItem) + 7);\\n  mat4 viewProjectionMatrix = projectionMatrix * viewMatrix;\\n\\n  if (occlusionCulling != 0) {\\n    // Note: write the drawItemId to the red channel.\\n    // this aligns with src\\\\Renderer\\\\Shaders\\\\GLSL\\\\surfaceGeomData.glsl:39\\n    // The ReductionShader reads the drawItemId from the red channel, and if the texel\\n    // contained a bbox from the green channel. (in this case, it does not)\\n    // Note: the alpha value is simply so we can debug the buffer over the top of the viewport.\\n    v_color = vec4(float(drawItemId), 0.0, 0.0, 1.0);\\n  } else {\\n    v_color = fetchTexel(instancesTexture, instancesTextureSize, (drawItemId * pixelsPerItem) + 4);\\n  }\\n\\n  vec4 pos = positions;\\n  if (pos.x < 0.0) pos.x = bboxMin.x;\\n  else if (pos.x > 0.0) pos.x = bboxMax.x;\\n  if (pos.y < 0.0) pos.y = bboxMin.y;\\n  else if (pos.y > 0.0) pos.y = bboxMax.y;\\n  if (pos.z < 0.0) pos.z = bboxMin.z;\\n  else if (pos.z > 0.0) pos.z = bboxMax.z;\\n\\n  gl_Position = viewProjectionMatrix * pos;\\n}\\n\"; // eslint-disable-line\n\n/* eslint-disable require-jsdoc */\nclass BoundingBoxShader extends GLShader {\n    /**\n     * Create a GL shader.\n     * @param gl - The webgl rendering context.\n     */\n    constructor(gl) {\n        super(gl, 'BoundingBoxShader');\n        this.setShaderStage('VERTEX_SHADER', vert$h);\n        this.setShaderStage('FRAGMENT_SHADER', frag$g);\n    }\n}\n\nvar WorkerFactory = createBase64WorkerFactory('Lyogcm9sbHVwLXBsdWdpbi13ZWItd29ya2VyLWxvYWRlciAqLwp2YXIgd29ya2VyX2NvZGUgPSAoZnVuY3Rpb24gKGV4cG9ydHMpIHsKICAndXNlIHN0cmljdCc7CgogIC8qIGVzbGludC1kaXNhYmxlIGNhbWVsY2FzZSAqLw0KICBjb25zdCB2ZWMzX3N1YnRyYWN0ID0gKHZlYzEsIHZlYzIpID0+IHsNCiAgICByZXR1cm4gW3ZlYzFbMF0gLSB2ZWMyWzBdLCB2ZWMxWzFdIC0gdmVjMlsxXSwgdmVjMVsyXSAtIHZlYzJbMl1dDQogIH07DQogIGNvbnN0IHZlYzNfbGVuZ3RoID0gKHZlYykgPT4gew0KICAgIHJldHVybiBNYXRoLnNxcnQodmVjWzBdICogdmVjWzBdICsgdmVjWzFdICogdmVjWzFdICsgdmVjWzJdICogdmVjWzJdKQ0KICB9Ow0KICBjb25zdCB2ZWMyX3NjYWxlID0gKHZlYywgc2NsKSA9PiB7DQogICAgcmV0dXJuIFt2ZWNbMF0gKiBzY2wsIHZlY1sxXSAqIHNjbF0NCiAgfTsNCiAgY29uc3QgdmVjMl9sZW5ndGggPSAodmVjKSA9PiB7DQogICAgcmV0dXJuIE1hdGguc3FydCh2ZWNbMF0gKiB2ZWNbMF0gKyB2ZWNbMV0gKiB2ZWNbMV0pDQogIH07DQoNCiAgY29uc3QgcXVhdF9jb25qdWdhdGUgPSAocXVhdCkgPT4gew0KICAgIHJldHVybiBbLXF1YXRbMF0sIC1xdWF0WzFdLCAtcXVhdFsyXSwgcXVhdFszXV0NCiAgfTsNCiAgY29uc3QgcXVhdF9tdWx0aXBseSA9IChxdWF0MSwgcXVhdDIpID0+IHsNCiAgICBjb25zdCBheCA9IHF1YXQxWzBdOw0KICAgIGNvbnN0IGF5ID0gcXVhdDFbMV07DQogICAgY29uc3QgYXogPSBxdWF0MVsyXTsNCiAgICBjb25zdCBhdyA9IHF1YXQxWzNdOw0KICAgIGNvbnN0IGJ4ID0gcXVhdDJbMF07DQogICAgY29uc3QgYnkgPSBxdWF0MlsxXTsNCiAgICBjb25zdCBieiA9IHF1YXQyWzJdOw0KICAgIGNvbnN0IGJ3ID0gcXVhdDJbM107DQoNCiAgICByZXR1cm4gWw0KICAgICAgYXggKiBidyArIGF3ICogYnggKyBheSAqIGJ6IC0gYXogKiBieSwNCiAgICAgIGF5ICogYncgKyBhdyAqIGJ5ICsgYXogKiBieCAtIGF4ICogYnosDQogICAgICBheiAqIGJ3ICsgYXcgKiBieiArIGF4ICogYnkgLSBheSAqIGJ4LA0KICAgICAgYXcgKiBidyAtIGF4ICogYnggLSBheSAqIGJ5IC0gYXogKiBieiwNCiAgICBdDQogIH07DQogIGNvbnN0IHF1YXRfcm90YXRlVmVjMyA9IChxdWF0LCB2ZWMzKSA9PiB7DQogICAgY29uc3QgdnEgPSBbdmVjM1swXSwgdmVjM1sxXSwgdmVjM1syXSwgMC4wXTsNCiAgICBjb25zdCBwcSA9IHF1YXRfbXVsdGlwbHkocXVhdF9tdWx0aXBseShxdWF0LCB2cSksIHF1YXRfY29uanVnYXRlKHF1YXQpKTsNCiAgICByZXR1cm4gW3BxWzBdLCBwcVsxXSwgcHFbMl1dDQogIH07DQoNCiAgLy8gLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8NCiAgLy8gRnJ1c3R1bSBDdWxsaW5nIGRhdGEuDQogIGxldCBlbmFibGVPY2NsdXNpb25DdWxsaW5nID0gZmFsc2U7DQogIGNvbnN0IGdlb21JdGVtc0RhdGEgPSBbXTsNCiAgY29uc3Qgb3V0T2ZGcnVzdHVtID0gW107DQogIGxldCBmcnVzdHVtQ3VsbGVkQ291bnQgPSAwOw0KICBsZXQgbmV3bHlDdWxsZWQgPSBbXTsNCiAgbGV0IG5ld2x5VW5DdWxsZWQgPSBbXTsNCg0KICBsZXQgdmlzaWJsZUNvdW50ID0gMDsNCiAgY29uc3QgdG90YWxHZW9tU3RhdHMgPSB7DQogICAgdHJpYW5nbGVzOiAwLA0KICAgIGxpbmVzOiAwLA0KICAgIHBvaW50czogMCwNCiAgfTsNCiAgY29uc3QgdmlzaWJsZUdlb21TdGF0cyA9IHsNCiAgICB0cmlhbmdsZXM6IDAsDQogICAgbGluZXM6IDAsDQogICAgcG9pbnRzOiAwLA0KICB9Ow0KICBjb25zdCBnZW9tU3RhdHNfYWRkVG90YWwgPSAoZ2VvbVN0YXRzKSA9PiB7DQogICAgLy8gY29uc29sZS5sb2coJ2dlb21TdGF0c19hZGQ6JywgZ2VvbVN0YXRzLnRyaWFuZ2xlcywgdmlzaWJsZUdlb21TdGF0cy50cmlhbmdsZXMpDQogICAgdG90YWxHZW9tU3RhdHMudHJpYW5nbGVzICs9IGdlb21TdGF0cy50cmlhbmdsZXM7DQogICAgdG90YWxHZW9tU3RhdHMubGluZXMgKz0gZ2VvbVN0YXRzLmxpbmVzOw0KICAgIHRvdGFsR2VvbVN0YXRzLnBvaW50cyArPSBnZW9tU3RhdHMucG9pbnRzOw0KICB9Ow0KICBjb25zdCBnZW9tU3RhdHNfc3VidHJhY3RUb3RhbCA9IChnZW9tU3RhdHMpID0+IHsNCiAgICAvLyBjb25zb2xlLmxvZygnZ2VvbVN0YXRzX3N1YnRyYWN0OicsIGdlb21TdGF0cy50cmlhbmdsZXMsIHZpc2libGVHZW9tU3RhdHMudHJpYW5nbGVzKQ0KICAgIHRvdGFsR2VvbVN0YXRzLnRyaWFuZ2xlcyAtPSBnZW9tU3RhdHMudHJpYW5nbGVzOw0KICAgIHRvdGFsR2VvbVN0YXRzLmxpbmVzIC09IGdlb21TdGF0cy5saW5lczsNCiAgICB0b3RhbEdlb21TdGF0cy5wb2ludHMgLT0gZ2VvbVN0YXRzLnBvaW50czsNCiAgfTsNCiAgY29uc3QgZ2VvbVN0YXRzX2FkZCA9IChnZW9tU3RhdHMpID0+IHsNCiAgICAvLyBjb25zb2xlLmxvZygnZ2VvbVN0YXRzX2FkZDonLCBnZW9tU3RhdHMudHJpYW5nbGVzLCB2aXNpYmxlR2VvbVN0YXRzLnRyaWFuZ2xlcykNCiAgICB2aXNpYmxlQ291bnQrKzsNCiAgICB2aXNpYmxlR2VvbVN0YXRzLnRyaWFuZ2xlcyArPSBnZW9tU3RhdHMudHJpYW5nbGVzOw0KICAgIHZpc2libGVHZW9tU3RhdHMubGluZXMgKz0gZ2VvbVN0YXRzLmxpbmVzOw0KICAgIHZpc2libGVHZW9tU3RhdHMucG9pbnRzICs9IGdlb21TdGF0cy5wb2ludHM7DQogIH07DQogIGNvbnN0IGdlb21TdGF0c19zdWJ0cmFjdCA9IChnZW9tU3RhdHMpID0+IHsNCiAgICAvLyBjb25zb2xlLmxvZygnZ2VvbVN0YXRzX3N1YnRyYWN0OicsIGdlb21TdGF0cy50cmlhbmdsZXMsIHZpc2libGVHZW9tU3RhdHMudHJpYW5nbGVzKQ0KICAgIHZpc2libGVDb3VudC0tOw0KICAgIHZpc2libGVHZW9tU3RhdHMudHJpYW5nbGVzIC09IGdlb21TdGF0cy50cmlhbmdsZXM7DQogICAgdmlzaWJsZUdlb21TdGF0cy5saW5lcyAtPSBnZW9tU3RhdHMubGluZXM7DQogICAgdmlzaWJsZUdlb21TdGF0cy5wb2ludHMgLT0gZ2VvbVN0YXRzLnBvaW50czsNCiAgfTsNCg0KICBsZXQgY2FtZXJhUG9zOw0KICBsZXQgY2FtZXJhSW52T3JpOw0KICBsZXQgaXNPcnRob2dyYXBoaWMgPSBmYWxzZTsNCiAgbGV0IGZydXN0dW1IZWlnaHQgPSAwOw0KICBsZXQgZnJ1c3R1bVdpZHRoID0gMDsNCiAgbGV0IGZydXN0dW1IYWxmQW5nbGVYID0gMDsNCiAgbGV0IGZydXN0dW1IYWxmQW5nbGVZID0gMDsNCiAgbGV0IHNvbGlkQW5nbGVMaW1pdCA9IDAuMDA0Ow0KICBsZXQgcGxhY2Vob2xkZXJMb2FkVGhyZXNob2xkID0gMjAwOw0KDQogIGNvbnN0IGN1bGwgPSAoaW5kZXgpID0+IHsNCiAgICBpZiAoIW91dE9mRnJ1c3R1bVtpbmRleF0pIHsNCiAgICAgIG91dE9mRnJ1c3R1bVtpbmRleF0gPSB0cnVlOw0KICAgICAgZnJ1c3R1bUN1bGxlZENvdW50Kys7DQogICAgICBuZXdseUN1bGxlZC5wdXNoKGluZGV4KTsNCg0KICAgICAgLy8gV2UgY291bGQgYmUgY3VsbGluZyBzb21ldGhpbmcgdGhhdCB3YXMgYWxyZWFkeQ0KICAgICAgLy8gbm90IHZpc2libGUgaW4gdGhlIG9jY2x1c2lvbiBidWZmZXIuDQogICAgICBpZiAoIWVuYWJsZU9jY2x1c2lvbkN1bGxpbmcgfHwgIW9jY2x1ZGVkW2luZGV4XSkgew0KICAgICAgICBnZW9tU3RhdHNfc3VidHJhY3QoZ2VvbUl0ZW1zRGF0YVtpbmRleF0uZ2VvbVN0YXRzKTsNCiAgICAgIH0NCiAgICB9DQogIH07DQogIGNvbnN0IHVuQ3VsbCA9IChpbmRleCkgPT4gew0KICAgIGlmIChvdXRPZkZydXN0dW1baW5kZXhdKSB7DQogICAgICBvdXRPZkZydXN0dW1baW5kZXhdID0gZmFsc2U7DQogICAgICBmcnVzdHVtQ3VsbGVkQ291bnQtLTsNCiAgICAgIG5ld2x5VW5DdWxsZWQucHVzaChpbmRleCk7DQoNCiAgICAgIC8vIE9jY2x1c2lvbiBjdWxsaW5nIGNhbiBvbmx5IGRldGVybWluZSBpZiBzb21ldGhpbmcgaXMgdmlzaWJsZQ0KICAgICAgLy8gbWVhbmluZyB0aGF0IHdlIGFzc3VtZSBpdCBpcyBub3QsIHVudGlsIGl0IHNob3dzIHVwIGluIHRoZSBvY2NsdXNpb24gYnVmZmVyLg0KICAgICAgLy8gT25jZSBpdCBhcHBlYXJzIGluIHRoZSBvY2NsdXNpb24gYnVmZmVyLCB3ZSBzdGFydCByZW5kZXJpbmcgaXQgYWdhaW4uDQogICAgICAvLyBTbywgd2hlbiBhbiBpdGVtIGNvbWVzIGJhY2sgaW50byB0aGUgZnJ1c3R1bSwgd2Ugc3RhcnQgcmVuZGVyaW5nIGl0cyBiYm94Lg0KICAgICAgLy8gVGhlbiBpZiB0aGUgYmJveCBpcyBzZWVuLCB3ZSB0aGVuIHN0YXJ0IHNob3dpbmcgaXQuDQogICAgICBpZiAoZW5hYmxlT2NjbHVzaW9uQ3VsbGluZyAmJiAhZ2VvbUl0ZW1zRGF0YVtpbmRleF0udHJhbnNwYXJlbnQpIHsNCiAgICAgICAgb2NjbHVkZWRbaW5kZXhdID0gdHJ1ZTsNCiAgICAgIH0gZWxzZSB7DQogICAgICAgIGdlb21TdGF0c19hZGQoZ2VvbUl0ZW1zRGF0YVtpbmRleF0uZ2VvbVN0YXRzKTsNCiAgICAgIH0NCiAgICB9DQogIH07DQoNCiAgY29uc3QgY2hlY2tHZW9tSXRlbSA9IChnZW9tSXRlbURhdGEpID0+IHsNCiAgICBpZiAoIWdlb21JdGVtRGF0YSB8fCAhY2FtZXJhUG9zKSByZXR1cm4NCiAgICBpZiAoIWdlb21JdGVtRGF0YS52aXNpYmxlKSB7DQogICAgICByZXR1cm4NCiAgICB9DQoNCiAgICAvLyBTb21lIGl0ZW1zLCBsaWtlIEhhbmRsZXMgYW5kIHRoZSBncmlkLCBvciBvciB0aGUgVlIgY29udHJvbGxlcnMgdGhhdCBzaG91bGQgbm90IGJlIGN1bGxlZC4NCiAgICBpZiAoIWdlb21JdGVtRGF0YS5jdWxsYWJsZSkgew0KICAgICAgdW5DdWxsKGdlb21JdGVtRGF0YS5pZCk7DQogICAgICByZXR1cm4NCiAgICB9DQogICAgY29uc3QgYm91bmRpbmdSYWRpdXMgPSBnZW9tSXRlbURhdGEuYm91bmRpbmdSYWRpdXM7DQoNCiAgICBpZiAoaXNPcnRob2dyYXBoaWMpIHsNCiAgICAgIC8vIEN1bGwgdmVyeSBzbWFsbCBpdGVtcw0KICAgICAgLy8gTm90ZTogd2hlbiBpbiBWUiwgdGhlIEZvViBiZWNvbWVzIHZlcnkgd2lkZSBhbmQgdGhlIHBpeGVsDQogICAgICAvLyBoZWlnaHQgdmFyaWVzLiBJdCBzZWVtcyBtb3JlIGNvbnNpc3RlbnQgdG8ganVzdCB1c2Ugc29saWRBbmdsZQ0KICAgICAgLy8gd2hpY2ggaXMgcmVzb2x1dGlvbiBpbnZhcmlhbnQuDQogICAgICBjb25zdCB2aGVpZ2h0ID0gYm91bmRpbmdSYWRpdXMgLyBmcnVzdHVtSGVpZ2h0Ow0KICAgICAgaWYgKHNvbGlkQW5nbGVMaW1pdCA+IDAgJiYgdmhlaWdodCA8IHNvbGlkQW5nbGVMaW1pdCkgew0KICAgICAgICBjdWxsKGdlb21JdGVtRGF0YS5pZCk7DQogICAgICAgIHJldHVybg0KICAgICAgfQ0KDQogICAgICAvLyBOb3cgd2UgY2hlY2sgaWYgdGhlIGl0ZW0gaXMgd2l0aGluIHRoZSB2aWV3IGZydXN0dW0uDQogICAgICAvLyBXZSBuZWVkIHRoZSBzb2xpZCBhbmdsZSBvZiB0aGUgaXRlbSBmb3IgZWFjaCBheGlzIChYICYgWSkNCiAgICAgIC8vIFRoaXMgaXMgYmVjYXVzZSBhdCB0aGUgY29ybmVycyBvZiB0aGUgc2NyZWVuLCB0aGUgb2JqZWN0IGlzIHNsaWdodGx5DQogICAgICAvLyBmdXJ0aGVyIGF3YXksIHNvIHRoZSBzb2xpZCBhbmdsZSBjYWxjdWxhdGVkIGFib3ZlIGdldHMgc21hbGxlci4NCiAgICAgIC8vIFRoaXMgd2FzIGNhdXNpbmcgaXRlbXMgd2l0aCBiaWcgYm91bmRpbmcgc3BoZXJlcyB0byBiZSBjdWxsZWQgdG9vIGVhcmx5DQogICAgICAvLyBhdCB0aGUgY29ybmVyIG9mIHRoZSBzY3JlZW4uDQogICAgICBjb25zdCB2ZWMgPSB2ZWMzX3N1YnRyYWN0KGdlb21JdGVtRGF0YS5wb3MsIGNhbWVyYVBvcyk7DQogICAgICBjb25zdCB2aWV3UG9zID0gcXVhdF9yb3RhdGVWZWMzKGNhbWVyYUludk9yaSwgdmVjKTsNCiAgICAgIGlmICgNCiAgICAgICAgTWF0aC5hYnModmlld1Bvc1swXSkgLSBib3VuZGluZ1JhZGl1cyA+IGZydXN0dW1XaWR0aCAqIDAuNSB8fA0KICAgICAgICBNYXRoLmFicyh2aWV3UG9zWzFdKSAtIGJvdW5kaW5nUmFkaXVzID4gZnJ1c3R1bUhlaWdodCAqIDAuNQ0KICAgICAgKSB7DQogICAgICAgIGN1bGwoZ2VvbUl0ZW1EYXRhLmlkKTsNCiAgICAgICAgcmV0dXJuDQogICAgICB9DQogICAgfSBlbHNlIHsNCiAgICAgIGNvbnN0IHZlYyA9IHZlYzNfc3VidHJhY3QoZ2VvbUl0ZW1EYXRhLnBvcywgY2FtZXJhUG9zKTsNCiAgICAgIGNvbnN0IGRpc3QgPSB2ZWMzX2xlbmd0aCh2ZWMpOw0KICAgICAgLy8gdW5DdWxsIGl0ZW1zIGNsb3NlIHRvIHRoZSB2aWV3Lg0KICAgICAgaWYgKGRpc3QgPCBib3VuZGluZ1JhZGl1cykgew0KICAgICAgICB1bkN1bGwoZ2VvbUl0ZW1EYXRhLmlkKTsNCiAgICAgICAgcmV0dXJuDQogICAgICB9DQogICAgICAvLyBDdWxsIHZlcnkgc21hbGwgaXRlbXMNCiAgICAgIC8vIE5vdGU6IHdoZW4gaW4gVlIsIHRoZSBGb1YgYmVjb21lcyB2ZXJ5IHdpZGUgYW5kIHRoZSBwaXhlbA0KICAgICAgLy8gaGVpZ2h0IHZhcmllcy4gSXQgc2VlbXMgbW9yZSBjb25zaXN0ZW50IHRvIGp1c3QgdXNlIHNvbGlkQW5nbGUNCiAgICAgIC8vIHdoaWNoIGlzIHJlc29sdXRpb24gaW52YXJpYW50Lg0KICAgICAgY29uc3Qgc29saWRBbmdsZSA9IE1hdGguYXNpbihib3VuZGluZ1JhZGl1cyAvIGRpc3QpOw0KICAgICAgaWYgKHNvbGlkQW5nbGVMaW1pdCA+IDAgJiYgc29saWRBbmdsZSA8IHNvbGlkQW5nbGVMaW1pdCkgew0KICAgICAgICBjdWxsKGdlb21JdGVtRGF0YS5pZCk7DQogICAgICAgIHJldHVybg0KICAgICAgfQ0KDQogICAgICAvLyBOb3cgd2UgY2hlY2sgaWYgdGhlIGl0ZW0gaXMgd2l0aGluIHRoZSB2aWV3IGZydXN0dW0uDQogICAgICAvLyBXZSBuZWVkIHRoZSBzb2xpZCBhbmdsZSBvZiB0aGUgaXRlbSBmb3IgZWFjaCBheGlzIChYICYgWSkNCiAgICAgIC8vIFRoaXMgaXMgYmVjYXVzZSBhdCB0aGUgY29ybmVycyBvZiB0aGUgc2NyZWVuLCB0aGUgb2JqZWN0IGlzIHNsaWdodGx5DQogICAgICAvLyBmdXJ0aGVyIGF3YXksIHNvIHRoZSBzb2xpZCBhbmdsZSBjYWxjdWxhdGVkIGFib3ZlIGdldHMgc21hbGxlci4NCiAgICAgIC8vIFRoaXMgd2FzIGNhdXNpbmcgaXRlbXMgd2l0aCBiaWcgYm91bmRpbmcgc3BoZXJlcyB0byBiZSBjdWxsZWQgdG9vIGVhcmx5DQogICAgICAvLyBhdCB0aGUgY29ybmVyIG9mIHRoZSBzY3JlZW4uDQogICAgICBjb25zdCB2aWV3UG9zID0gcXVhdF9yb3RhdGVWZWMzKGNhbWVyYUludk9yaSwgdmVjKTsNCiAgICAgIGNvbnN0IHZpZXdWZWNYWiA9IFt2aWV3UG9zWzBdLCB2aWV3UG9zWzJdXTsNCiAgICAgIGNvbnN0IHZpZXdWZWNZWiA9IFt2aWV3UG9zWzFdLCB2aWV3UG9zWzJdXTsNCiAgICAgIGNvbnN0IGRpc3RYID0gdmVjMl9sZW5ndGgodmlld1ZlY1haKTsNCiAgICAgIGNvbnN0IGRpc3RZID0gdmVjMl9sZW5ndGgodmlld1ZlY1laKTsNCiAgICAgIGNvbnN0IHNvbGlkQW5nbGVYWiA9IE1hdGguYXNpbihib3VuZGluZ1JhZGl1cyAvIGRpc3RYKTsNCiAgICAgIGNvbnN0IHNvbGlkQW5nbGVZWiA9IE1hdGguYXNpbihib3VuZGluZ1JhZGl1cyAvIGRpc3RZKTsNCiAgICAgIGNvbnN0IHZpZXdWZWNOb3JtWFogPSB2ZWMyX3NjYWxlKHZpZXdWZWNYWiwgMSAvIGRpc3RYKTsNCiAgICAgIGNvbnN0IHZpZXdWZWNOb3JtWVogPSB2ZWMyX3NjYWxlKHZpZXdWZWNZWiwgMSAvIGRpc3RZKTsNCg0KICAgICAgbGV0IHZpZXdBbmdsZTsNCiAgICAgIC8vIElmIGFuIGl0ZW0gaXMgYmVoaW5kIHRoZSB2aWV3ZXINCiAgICAgIGlmICh2aWV3UG9zWzJdID4gMCkgew0KICAgICAgICB2aWV3QW5nbGUgPSBbDQogICAgICAgICAgTWF0aC5QSSAtIE1hdGguYWJzKE1hdGguYXNpbih2aWV3VmVjTm9ybVhaWzBdKSkgLSBzb2xpZEFuZ2xlWFosDQogICAgICAgICAgTWF0aC5QSSAtIE1hdGguYWJzKE1hdGguYXNpbih2aWV3VmVjTm9ybVlaWzBdKSkgLSBzb2xpZEFuZ2xlWVosDQogICAgICAgIF07DQogICAgICB9IGVsc2Ugew0KICAgICAgICB2aWV3QW5nbGUgPSBbDQogICAgICAgICAgTWF0aC5hYnMoTWF0aC5hc2luKHZpZXdWZWNOb3JtWFpbMF0pKSAtIHNvbGlkQW5nbGVYWiwNCiAgICAgICAgICBNYXRoLmFicyhNYXRoLmFzaW4odmlld1ZlY05vcm1ZWlswXSkpIC0gc29saWRBbmdsZVlaLA0KICAgICAgICBdOw0KICAgICAgfQ0KICAgICAgLy8gY29uc29sZS5sb2coZ2VvbUl0ZW1EYXRhLmlkLCAnYW5nbGUgVG8gSXRlbTonLCBmcnVzdHVtSGFsZkFuZ2xlWCwgdmlld0FuZ2xlWzBdLCBmcnVzdHVtSGFsZkFuZ2xlWSwgdmlld0FuZ2xlWzFdKQ0KICAgICAgaWYgKHZpZXdBbmdsZVswXSA+IGZydXN0dW1IYWxmQW5nbGVYIHx8IHZpZXdBbmdsZVsxXSA+IGZydXN0dW1IYWxmQW5nbGVZKSB7DQogICAgICAgIGN1bGwoZ2VvbUl0ZW1EYXRhLmlkKTsNCiAgICAgICAgcmV0dXJuDQogICAgICB9DQogICAgfQ0KDQogICAgdW5DdWxsKGdlb21JdGVtRGF0YS5pZCk7DQogIH07DQoNCiAgY29uc3Qgb25WaWV3UG9ydENoYW5nZWQgPSAoZGF0YSwgcG9zdE1lc3NhZ2UpID0+IHsNCiAgICBpZiAoZGF0YS5pc09ydGhvZ3JhcGhpYykgew0KICAgICAgaXNPcnRob2dyYXBoaWMgPSB0cnVlOw0KICAgICAgZnJ1c3R1bUhlaWdodCA9IGRhdGEuZnJ1c3R1bUhlaWdodDsNCiAgICAgIGZydXN0dW1XaWR0aCA9IGRhdGEuZnJ1c3R1bVdpZHRoOw0KICAgIH0gZWxzZSB7DQogICAgICBpc09ydGhvZ3JhcGhpYyA9IGZhbHNlOw0KICAgICAgZnJ1c3R1bUhhbGZBbmdsZVggPSBkYXRhLmZydXN0dW1IYWxmQW5nbGVYOw0KICAgICAgZnJ1c3R1bUhhbGZBbmdsZVkgPSBkYXRhLmZydXN0dW1IYWxmQW5nbGVZOw0KICAgIH0NCg0KICAgIHNvbGlkQW5nbGVMaW1pdCA9IGRhdGEuc29saWRBbmdsZUxpbWl0Ow0KICAgIGlmIChjYW1lcmFQb3MgJiYgY2FtZXJhSW52T3JpKSB7DQogICAgICBnZW9tSXRlbXNEYXRhLmZvckVhY2goY2hlY2tHZW9tSXRlbSk7DQogICAgICBvbkRvbmVGcnVzdHVtQ3VsbChwb3N0TWVzc2FnZSk7DQogICAgfQ0KICB9Ow0KDQogIGNvbnN0IG9uVmlld0NoYW5nZWQgPSAoZGF0YSwgcG9zdE1lc3NhZ2UpID0+IHsNCiAgICBjYW1lcmFQb3MgPSBkYXRhLmNhbWVyYVBvczsNCiAgICBjYW1lcmFJbnZPcmkgPSBxdWF0X2Nvbmp1Z2F0ZShkYXRhLmNhbWVyYU9yaSk7DQogICAgc29saWRBbmdsZUxpbWl0ID0gZGF0YS5zb2xpZEFuZ2xlTGltaXQ7DQogICAgaWYgKGdlb21JdGVtc0RhdGEubGVuZ3RoID4gMCkgew0KICAgICAgZ2VvbUl0ZW1zRGF0YS5mb3JFYWNoKGNoZWNrR2VvbUl0ZW0pOw0KICAgICAgb25Eb25lRnJ1c3R1bUN1bGwocG9zdE1lc3NhZ2UpOw0KICAgIH0NCiAgfTsNCg0KICBsZXQgaW5GcnVzdHVtRHJhd0lkc0J1ZmZlclBvcHVsYXRlZCA9IGZhbHNlOw0KICBjb25zdCBnZW5lcmF0ZUluRnJ1c3R1bUluZGljZXMgPSAoKSA9PiB7DQogICAgbGV0IG9mZnNldCA9IDA7DQogICAgb3V0T2ZGcnVzdHVtLmZvckVhY2goKHZhbHVlLCBpbmRleCkgPT4gew0KICAgICAgaWYgKGluZGV4ID4gMCAmJiAhdmFsdWUgJiYgZ2VvbUl0ZW1zRGF0YVtpbmRleF0udmlzaWJsZSAmJiAhZ2VvbUl0ZW1zRGF0YVtpbmRleF0udHJhbnNwYXJlbnQpIG9mZnNldCsrOw0KICAgIH0pOw0KICAgIC8vIENyZWF0ZSBhIGZsb2F0IGFycmF5IHRoYXQgY2FuIGJlIHVzZWQgYXMgYW4gaW5zdGFuY2VzDQogICAgLy8gYXR0cmlidXRlIHRvIHBhc3MgaW50byB0aGUgZHJhd2luZyBvZiB0aGUgYm91bmRpbmcgYm94ZXMuDQogICAgY29uc3QgaW5GcnVzdHVtSW5kaWNlcyA9IG5ldyBGbG9hdDMyQXJyYXkob2Zmc2V0KTsNCiAgICBvZmZzZXQgPSAwOw0KICAgIG91dE9mRnJ1c3R1bS5mb3JFYWNoKCh2YWx1ZSwgaW5kZXgpID0+IHsNCiAgICAgIGlmIChpbmRleCA+IDAgJiYgIXZhbHVlICYmIGdlb21JdGVtc0RhdGFbaW5kZXhdLnZpc2libGUgJiYgIWdlb21JdGVtc0RhdGFbaW5kZXhdLnRyYW5zcGFyZW50KSB7DQogICAgICAgIGluRnJ1c3R1bUluZGljZXNbb2Zmc2V0XSA9IGluZGV4Ow0KICAgICAgICBvZmZzZXQrKzsNCiAgICAgIH0NCiAgICB9KTsNCiAgICByZXR1cm4gaW5GcnVzdHVtSW5kaWNlcw0KICB9Ow0KDQogIGNvbnN0IG9uRG9uZUZydXN0dW1DdWxsID0gKHBvc3RNZXNzYWdlKSA9PiB7DQogICAgaWYgKCFlbmFibGVPY2NsdXNpb25DdWxsaW5nKSB7DQogICAgICBjb25zdCBjb3VudEluRnJ1c3R1bSA9IGdlb21JdGVtc0RhdGEubGVuZ3RoIC0gMSAtIGZydXN0dW1DdWxsZWRDb3VudDsNCg0KICAgICAgcG9zdE1lc3NhZ2Uoew0KICAgICAgICB0eXBlOiAnQ3VsbFJlc3VsdHMnLA0KICAgICAgICBuZXdseUN1bGxlZCwNCiAgICAgICAgbmV3bHlVbkN1bGxlZCwNCiAgICAgICAgdmlzaWJsZTogY291bnRJbkZydXN0dW0sDQogICAgICAgIHRvdGFsOiBnZW9tSXRlbXNEYXRhLmxlbmd0aCAtIDEsDQogICAgICAgIHZpc2libGVHZW9tU3RhdHMsDQogICAgICAgIHRvdGFsR2VvbVN0YXRzLA0KICAgICAgfSk7DQogICAgfSBlbHNlIHsNCiAgICAgIC8vIGNvbnNvbGUubG9nKCdGcnVzdHVtQ3VsbFJlc3VsdHM6JywgJ25ld2x5Q3VsbGVkOicsIG5ld2x5Q3VsbGVkLCAnbmV3bHlVbkN1bGxlZDonLCBuZXdseVVuQ3VsbGVkLCBvdXRPZkZydXN0dW0pDQogICAgICAvLyBjb25zdCBjb3VudEluRnJ1c3R1bSA9IGdlb21JdGVtc0RhdGEubGVuZ3RoIC0gMSAtIGZydXN0dW1DdWxsZWRDb3VudA0KDQogICAgICAvLyBpZiAoY291bnRJbkZydXN0dW0gPiAzMDApIHsNCiAgICAgIC8vICAgY29uc29sZS5sb2coJ2NvdW50SW5GcnVzdHVtOicsIGNvdW50SW5GcnVzdHVtKQ0KICAgICAgLy8gfQ0KICAgICAgaWYgKG5ld2x5Q3VsbGVkLmxlbmd0aCA+IDAgfHwgbmV3bHlVbkN1bGxlZC5sZW5ndGggPiAwIHx8ICFpbkZydXN0dW1EcmF3SWRzQnVmZmVyUG9wdWxhdGVkKSB7DQogICAgICAgIGNvbnN0IGluRnJ1c3R1bUluZGljZXMgPSBnZW5lcmF0ZUluRnJ1c3R1bUluZGljZXMoKTsNCg0KICAgICAgICAvLyBXaGVuIG9jY2x1c2lvbiBjdWxsaW5nIGlzIG9uLCB3ZSBvbmx5IHVuY3VsbCBpdGVtcyBhZnRlciB0aGV5DQogICAgICAgIC8vIGFyZSBkZXRlY3RlZCBpbiB0aGUgb2NjbHVzaW9uIGJ1ZmZlci4gVHJhbnNwYXJlbnQgaXRlbXMgYXJlIG5vdA0KICAgICAgICAvLyByZW5kZXJlZCB0byB0aGUgb2NjbHVzaW9uIGJ1ZmZlciwgc28gbXVzdCBiZSB1bmN1bGxlZCBpbW1lZGlhdGVseS4NCiAgICAgICAgY29uc3QgbmV3bHlVbkN1bGxlZF90cmFuc3BhcmVudCA9IFtdOw0KICAgICAgICBuZXdseVVuQ3VsbGVkLmZvckVhY2goKGluZGV4KSA9PiB7DQogICAgICAgICAgaWYgKGluZGV4ID4gMCAmJiBnZW9tSXRlbXNEYXRhW2luZGV4XSAmJiBnZW9tSXRlbXNEYXRhW2luZGV4XS52aXNpYmxlICYmIGdlb21JdGVtc0RhdGFbaW5kZXhdLnRyYW5zcGFyZW50KSB7DQogICAgICAgICAgICBuZXdseVVuQ3VsbGVkX3RyYW5zcGFyZW50LnB1c2goaW5kZXgpOw0KICAgICAgICAgIH0NCiAgICAgICAgfSk7DQogICAgICAgIHBvc3RNZXNzYWdlKA0KICAgICAgICAgIHsNCiAgICAgICAgICAgIHR5cGU6ICdJbkZydXN0dW1JbmRpY2VzJywNCiAgICAgICAgICAgIG5ld2x5Q3VsbGVkLA0KICAgICAgICAgICAgbmV3bHlVbkN1bGxlZDogbmV3bHlVbkN1bGxlZF90cmFuc3BhcmVudCwNCiAgICAgICAgICAgIC8qIFdoZW4gb2NjbHVzaW9uIGN1bGxpbmcgaXMgcnVubmluZyx3ZSBvbmx5IGNvbnNpZGVyDQogICAgICAgICAgICBjdWxsaW5nIGNvbXBsZXRlZCBhZnRlciB0aGUgb2NjbHVzaW9uIGN1bGxpbmcgaXMgZG9uZS4NCiAgICAgICAgICAgIHZpc2libGU6IHZpc2libGVDb3VudCwNCiAgICAgICAgICAgIHRvdGFsOiBnZW9tSXRlbXNEYXRhLmxlbmd0aCAtIDEsDQogICAgICAgICAgICB2aXNpYmxlR2VvbVN0YXRzLA0KICAgICAgICAgICAgdG90YWxHZW9tU3RhdHMsKi8NCiAgICAgICAgICAgIGluRnJ1c3R1bUluZGljZXMsDQogICAgICAgICAgfSwNCiAgICAgICAgICBbaW5GcnVzdHVtSW5kaWNlcy5idWZmZXJdDQogICAgICAgICk7DQogICAgICAgIGluRnJ1c3R1bURyYXdJZHNCdWZmZXJQb3B1bGF0ZWQgPSB0cnVlOw0KICAgICAgfSBlbHNlIHsNCiAgICAgICAgLy8gTm90ZTogdGhlIGluRnJ1c3R1bURyYXdJZHNCdWZmZXIgaXMgYWxyZWFkeSB1cCB0byBkYXRlIHdlIGNhbiBza2lwIHRoaXMuDQogICAgICAgIHBvc3RNZXNzYWdlKHsNCiAgICAgICAgICB0eXBlOiAnSW5GcnVzdHVtSW5kaWNlcycsDQogICAgICAgICAgbmV3bHlDdWxsZWQ6IFtdLA0KICAgICAgICAgIG5ld2x5VW5DdWxsZWQ6IFtdLA0KICAgICAgICAgIHZpc2libGU6IHZpc2libGVDb3VudCwNCiAgICAgICAgICB0b3RhbDogZ2VvbUl0ZW1zRGF0YS5sZW5ndGggLSAxLA0KICAgICAgICAgIHZpc2libGVHZW9tU3RhdHMsDQogICAgICAgICAgdG90YWxHZW9tU3RhdHMsDQogICAgICAgIH0pOw0KICAgICAgfQ0KICAgIH0NCg0KICAgIG5ld2x5Q3VsbGVkID0gW107DQogICAgbmV3bHlVbkN1bGxlZCA9IFtdOw0KICB9Ow0KDQogIC8vIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vDQogIC8vIE9jY2x1c2lvbiBDdWxsaW5nIGRhdGEuDQogIGNvbnN0IG9jY2x1ZGVkID0gW107DQogIGNvbnN0IHByb2Nlc3NPY2NsdXNpb25EYXRhID0gKGRhdGEpID0+IHsNCiAgICBjb25zdCByZWR1Y3Rpb25EYXRhQXJyYXkgPSBkYXRhLnJlZHVjdGlvbkRhdGFBcnJheTsgLy8gVWludDhBcnJheQ0KDQogICAgY29uc3QgbmV3bHlDdWxsZWQgPSBbXTsNCiAgICBjb25zdCBuZXdseVVuQ3VsbGVkID0gW107DQogICAgY29uc3QgdmlzaWJsZVBsYWNlaG9sZGVycyA9IFtdOw0KICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcmVkdWN0aW9uRGF0YUFycmF5Lmxlbmd0aDsgaSArPSAyKSB7DQogICAgICBjb25zdCBpbmRleCA9IGkgLyAyOw0KICAgICAgY29uc3QgdmFsdWUgPSByZWR1Y3Rpb25EYXRhQXJyYXlbaV07DQoNCiAgICAgIGlmIChpbmRleCA9PSAwKSBjb250aW51ZQ0KICAgICAgaWYgKGluZGV4ID49IGdlb21JdGVtc0RhdGEubGVuZ3RoKSB7DQogICAgICAgIGJyZWFrDQogICAgICB9DQoNCiAgICAgIGNvbnN0IGdlb21JdGVtRGF0YSA9IGdlb21JdGVtc0RhdGFbaW5kZXhdOw0KICAgICAgaWYgKCFnZW9tSXRlbURhdGEgfHwgIWdlb21JdGVtRGF0YS5jdWxsYWJsZSB8fCAhZ2VvbUl0ZW1EYXRhLnZpc2libGUgfHwgZ2VvbUl0ZW1EYXRhLnRyYW5zcGFyZW50KSB7DQogICAgICAgIGNvbnRpbnVlDQogICAgICB9DQoNCiAgICAgIGlmIChnZW9tSXRlbURhdGEuaXNQbGFjZWhvbGRlciAmJiB2YWx1ZSA+IHBsYWNlaG9sZGVyTG9hZFRocmVzaG9sZCkgew0KICAgICAgICBjb25zdCBpc05vdEJCb3ggPSByZWR1Y3Rpb25EYXRhQXJyYXlbaSArIDFdID4gMDsNCiAgICAgICAgaWYgKGlzTm90QkJveCkgew0KICAgICAgICAgIHZpc2libGVQbGFjZWhvbGRlcnMucHVzaCh7IGluZGV4LCBjb3VudDogdmFsdWUgfSk7DQogICAgICAgIH0NCiAgICAgIH0NCg0KICAgICAgaWYgKCFvdXRPZkZydXN0dW1baW5kZXhdKSB7DQogICAgICAgIGlmICh2YWx1ZSA9PSAwKSB7DQogICAgICAgICAgLy8gTm90IHRyYW5zcGFyZW50IG9iamVjdCBjYW4gbm90IGJlIG9jY2x1c2lvbiBjdWxsZWQsIGJlY2F1c2Ugd2UgZG8gbm90IHJlbmRlciB0aGVtIHRvIHRoZQ0KICAgICAgICAgIC8vIG9jY2x1c2lvbiBidWZmZXIuIFRoaXMgbWVhbnMgdGhleSBjYW5ub3Qgb2NjbHVkZSwgb3IgYmUgY29uc2lkZXJlZCBvY2NsdWRlZC4NCiAgICAgICAgICBpZiAoIW9jY2x1ZGVkW2luZGV4XSkgew0KICAgICAgICAgICAgb2NjbHVkZWRbaW5kZXhdID0gdHJ1ZTsNCiAgICAgICAgICAgIG5ld2x5Q3VsbGVkLnB1c2goaW5kZXgpOw0KICAgICAgICAgICAgZ2VvbVN0YXRzX3N1YnRyYWN0KGdlb21JdGVtRGF0YS5nZW9tU3RhdHMpOw0KICAgICAgICAgIH0NCiAgICAgICAgfSBlbHNlIHsNCiAgICAgICAgICBpZiAob2NjbHVkZWRbaW5kZXhdKSB7DQogICAgICAgICAgICBvY2NsdWRlZFtpbmRleF0gPSBmYWxzZTsNCiAgICAgICAgICAgIG5ld2x5VW5DdWxsZWQucHVzaChpbmRleCk7DQogICAgICAgICAgICBnZW9tU3RhdHNfYWRkKGdlb21JdGVtRGF0YS5nZW9tU3RhdHMpOw0KICAgICAgICAgIH0NCiAgICAgICAgfQ0KICAgICAgfQ0KICAgIH0NCiAgICAvLyBOb3RlOiBldmVuIGlmIG9jY2x1c2lvbiBjdWxsaW5nIGRpZCBudCBmaWx0ZXIgb3V0IGFueSBtb3JlIGl0ZW1zDQogICAgLy8gd2UgbXVzdCBlbWl0IHRoaXMgbWVzc2FnZSB0byB0aGUgbWFpbnMgd29ya2VyIHNvIGl0IGtub3dzIHRoYXQgY3VsbGluZyBpcyBjb21wbGV0ZWQuDQogICAgcG9zdE1lc3NhZ2Uoew0KICAgICAgdHlwZTogJ0N1bGxSZXN1bHRzJywNCiAgICAgIG5ld2x5Q3VsbGVkLA0KICAgICAgbmV3bHlVbkN1bGxlZCwNCiAgICAgIHZpc2libGU6IHZpc2libGVDb3VudCwNCiAgICAgIHRvdGFsOiBnZW9tSXRlbXNEYXRhLmxlbmd0aCAtIDEsDQogICAgICB2aXNpYmxlR2VvbVN0YXRzLA0KICAgICAgdG90YWxHZW9tU3RhdHMsDQogICAgICB2aXNpYmxlUGxhY2Vob2xkZXJzLA0KICAgIH0pOw0KICB9Ow0KDQogIC8vIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vDQogIC8vIE1lc3NhZ2luZw0KICBjb25zdCBoYW5kbGVNZXNzYWdlID0gKGRhdGEsIHBvc3RNZXNzYWdlKSA9PiB7DQogICAgaWYgKGRhdGEudHlwZSA9PSAnSW5pdCcpIHsNCiAgICAgIGNvbnNvbGUubG9nKCdJbml0aWFsaXplZCBDdWxsaW5nIFdvcmtlcicpOw0KICAgICAgZW5hYmxlT2NjbHVzaW9uQ3VsbGluZyA9IGRhdGEuZW5hYmxlT2NjbHVzaW9uQ3VsbGluZzsNCiAgICAgIHBsYWNlaG9sZGVyTG9hZFRocmVzaG9sZCA9IGRhdGEucGxhY2Vob2xkZXJMb2FkVGhyZXNob2xkOw0KICAgICAgcG9zdE1lc3NhZ2Uoew0KICAgICAgICB0eXBlOiAnV29ya2VyUmVhZHknLA0KICAgICAgfSk7DQogICAgfSBlbHNlIGlmIChkYXRhLnR5cGUgPT0gJ1ZpZXdwb3J0Q2hhbmdlZCcpIHsNCiAgICAgIG9uVmlld1BvcnRDaGFuZ2VkKGRhdGEsIHBvc3RNZXNzYWdlKTsNCiAgICB9IGVsc2UgaWYgKGRhdGEudHlwZSA9PSAnVmlld0NoYW5nZWQnKSB7DQogICAgICBvblZpZXdDaGFuZ2VkKGRhdGEsIHBvc3RNZXNzYWdlKTsNCiAgICB9IGVsc2UgaWYgKGRhdGEudHlwZSA9PSAnVXBkYXRlR2VvbUl0ZW1zJykgew0KICAgICAgZGF0YS5yZW1vdmVkSXRlbUluZGljZXMuZm9yRWFjaCgoaW5kZXgpID0+IHsNCiAgICAgICAgY29uc3QgZ2VvbUl0ZW1EYXRhID0gZ2VvbUl0ZW1zRGF0YVtpbmRleF07DQogICAgICAgIGlmIChnZW9tSXRlbURhdGEgJiYgZ2VvbUl0ZW1EYXRhLnZpc2libGUpIHsNCiAgICAgICAgICBnZW9tU3RhdHNfc3VidHJhY3RUb3RhbChnZW9tSXRlbURhdGEuZ2VvbVN0YXRzKTsNCiAgICAgICAgICBpZiAoIWVuYWJsZU9jY2x1c2lvbkN1bGxpbmcgfHwgIW9jY2x1ZGVkW2luZGV4XSkgew0KICAgICAgICAgICAgZ2VvbVN0YXRzX3N1YnRyYWN0KGdlb21JdGVtRGF0YS5nZW9tU3RhdHMpOw0KICAgICAgICAgIH0NCiAgICAgICAgfQ0KICAgICAgICBnZW9tSXRlbXNEYXRhW2luZGV4XSA9IG51bGw7DQogICAgICAgIG91dE9mRnJ1c3R1bVtpbmRleF0gPSB0cnVlOw0KICAgICAgfSk7DQogICAgICBkYXRhLmdlb21JdGVtcy5mb3JFYWNoKChnZW9tSXRlbURhdGEpID0+IHsNCiAgICAgICAgY29uc3QgaW5kZXggPSBnZW9tSXRlbURhdGEuaWQ7DQogICAgICAgIC8vIE5ldyBnZW9tcyBkZWZhdWx0IHRvIGJlaW5nIHVuLWN1bGxlZA0KICAgICAgICAvLyBFeGlzdGluZyBnZW9tcyB0aGF0IG1heSBiZSBjaGFuZ2luZyBzdGF0ZSwgbGlrZSBjaGFuZ2luZw0KICAgICAgICAvLyB2aXNpYmlsaXR5IG9yIHRyYW5zZm9ybWF0aW9ucyBzaG91bGQgc2ltcGx5IHVwZGF0ZS4NCiAgICAgICAgaWYgKCFnZW9tSXRlbXNEYXRhW2luZGV4XSkgew0KICAgICAgICAgIG91dE9mRnJ1c3R1bVtpbmRleF0gPSBmYWxzZTsNCiAgICAgICAgICBpZiAoZ2VvbUl0ZW1EYXRhLnZpc2libGUpIHsNCiAgICAgICAgICAgIGdlb21TdGF0c19hZGRUb3RhbChnZW9tSXRlbURhdGEuZ2VvbVN0YXRzKTsNCiAgICAgICAgICAgIGdlb21TdGF0c19hZGQoZ2VvbUl0ZW1EYXRhLmdlb21TdGF0cyk7DQogICAgICAgICAgfQ0KICAgICAgICB9IGVsc2Ugew0KICAgICAgICAgIC8vIGFyZSBlaXRoZXIgYWRkaW5nIGEgbmV3IGl0ZW0sIG9yIHVuaGlkaW5nIGFuIGV4aXN0aW5nIGl0ZW0uDQogICAgICAgICAgY29uc3QgYmVjb21pbmdWaXNpYmxlID0gIWdlb21JdGVtc0RhdGFbaW5kZXhdLnZpc2libGUgJiYgZ2VvbUl0ZW1EYXRhLnZpc2libGU7DQogICAgICAgICAgY29uc3QgYmVjb21pbmdJblZpc2libGUgPSBnZW9tSXRlbXNEYXRhW2luZGV4XS52aXNpYmxlICYmICFnZW9tSXRlbURhdGEudmlzaWJsZTsNCiAgICAgICAgICBpZiAoYmVjb21pbmdWaXNpYmxlKSB7DQogICAgICAgICAgICBnZW9tU3RhdHNfYWRkVG90YWwoZ2VvbUl0ZW1EYXRhLmdlb21TdGF0cyk7DQogICAgICAgICAgICBvdXRPZkZydXN0dW1baW5kZXhdID0gdHJ1ZTsNCiAgICAgICAgICAgIG9jY2x1ZGVkW2luZGV4XSA9IGZhbHNlOw0KICAgICAgICAgICAgLy8gaWYgKCFvdXRPZkZydXN0dW1baW5kZXhdICYmICFvY2NsdWRlZFtpbmRleF0pIHsNCiAgICAgICAgICAgIC8vICAgZ2VvbVN0YXRzX2FkZChnZW9tSXRlbURhdGEuZ2VvbVN0YXRzKQ0KICAgICAgICAgICAgLy8gfQ0KICAgICAgICAgIH0gZWxzZSBpZiAoYmVjb21pbmdJblZpc2libGUpIHsNCiAgICAgICAgICAgIGdlb21TdGF0c19zdWJ0cmFjdFRvdGFsKGdlb21JdGVtRGF0YS5nZW9tU3RhdHMpOw0KICAgICAgICAgICAgaWYgKCFvdXRPZkZydXN0dW1baW5kZXhdICYmICghZW5hYmxlT2NjbHVzaW9uQ3VsbGluZyB8fCAhb2NjbHVkZWRbaW5kZXhdKSkgew0KICAgICAgICAgICAgICBnZW9tU3RhdHNfc3VidHJhY3QoZ2VvbUl0ZW1EYXRhLmdlb21TdGF0cyk7DQogICAgICAgICAgICB9DQogICAgICAgICAgICBvdXRPZkZydXN0dW1baW5kZXhdID0gdHJ1ZTsNCiAgICAgICAgICAgIG9jY2x1ZGVkW2luZGV4XSA9IGZhbHNlOw0KICAgICAgICAgIH0gZWxzZSB7DQogICAgICAgICAgICBjb25zdCBiZWNvbWluZ1RyYW5zcGFyZW50ID0gIWdlb21JdGVtc0RhdGFbaW5kZXhdLnRyYW5zcGFyZW50ICYmIGdlb21JdGVtRGF0YS50cmFuc3BhcmVudDsNCiAgICAgICAgICAgIGNvbnN0IGJlY29taW5nT3BhcXVlID0gZ2VvbUl0ZW1zRGF0YVtpbmRleF0udHJhbnNwYXJlbnQgJiYgIWdlb21JdGVtRGF0YS50cmFuc3BhcmVudDsNCiAgICAgICAgICAgIGlmIChiZWNvbWluZ1RyYW5zcGFyZW50KSB7DQogICAgICAgICAgICAgIGlmIChlbmFibGVPY2NsdXNpb25DdWxsaW5nICYmICFvdXRPZkZydXN0dW1baW5kZXhdICYmIG9jY2x1ZGVkW2luZGV4XSkgew0KICAgICAgICAgICAgICAgIC8vIEl0ZW1zIGJlY29taW5nIHRyYW5zcGFyZW50IG11c3QgYmUgdW5jdWxsZWQgaW1tZWRpYXRlbHkuDQogICAgICAgICAgICAgICAgbmV3bHlVbkN1bGxlZC5wdXNoKGluZGV4KTsNCiAgICAgICAgICAgICAgICBnZW9tU3RhdHNfYWRkKGdlb21JdGVtRGF0YS5nZW9tU3RhdHMpOw0KICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9IGVsc2UgaWYgKGJlY29taW5nT3BhcXVlKSB7DQogICAgICAgICAgICAgIC8vIGNvbnNvbGUubG9nKCdCZWNvbWluZyBvcGFxdWU6JywgaW5kZXgpDQogICAgICAgICAgICAgIC8vIEl0ZW1zIGJlY29taW5nIHRyYW5zcGFyZW50IG11c3QgYmUgdW5jdWxsZWQgaW1tZWRpYXRlbHkuDQogICAgICAgICAgICAgIC8vIE9jY2x1c2lvbiBjdWxsaW5nIGNhbiBvbmx5IGRldGVybWluZSBpZiBzb21ldGhpbmcgaXMgdmlzaWJsZQ0KICAgICAgICAgICAgICAvLyBtZWFuaW5nIHRoYXQgd2UgYXNzdW1lIGl0IGlzIG5vdCwgdW50aWwgaXQgc2hvd3MgdXAgaW4gdGhlIG9jY2x1c2lvbiBidWZmZXIuDQogICAgICAgICAgICAgIC8vIE9uY2UgaXQgYXBwZWFycyBpbiB0aGUgb2NjbHVzaW9uIGJ1ZmZlciwgd2Ugc3RhcnQgcmVuZGVyaW5nIGl0IGFnYWluLg0KICAgICAgICAgICAgICAvLyBTbywgd2hlbiBhbiBpdGVtIGNvbWVzIGJhY2sgaW50byB0aGUgZnJ1c3R1bSwgd2Ugc3RhcnQgcmVuZGVyaW5nIGl0cyBiYm94Lg0KICAgICAgICAgICAgICAvLyBUaGVuIGlmIHRoZSBiYm94IGlzIHNlZW4sIHdlIHRoZW4gc3RhcnQgc2hvd2luZyBpdC4NCiAgICAgICAgICAgICAgaWYgKGVuYWJsZU9jY2x1c2lvbkN1bGxpbmcgJiYgIW91dE9mRnJ1c3R1bVtpbmRleF0pIHsNCiAgICAgICAgICAgICAgICBvY2NsdWRlZFtpbmRleF0gPSB0cnVlOw0KICAgICAgICAgICAgICAgIGdlb21TdGF0c19zdWJ0cmFjdChnZW9tSXRlbURhdGEuZ2VvbVN0YXRzKTsNCiAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfQ0KICAgICAgICAgIH0NCiAgICAgICAgfQ0KICAgICAgICBnZW9tSXRlbXNEYXRhW2luZGV4XSA9IGdlb21JdGVtRGF0YTsNCiAgICAgICAgY2hlY2tHZW9tSXRlbShnZW9tSXRlbXNEYXRhW2luZGV4XSk7DQogICAgICB9KTsNCiAgICAgIGluRnJ1c3R1bURyYXdJZHNCdWZmZXJQb3B1bGF0ZWQgPSBmYWxzZTsNCiAgICAgIG9uRG9uZUZydXN0dW1DdWxsKHBvc3RNZXNzYWdlKTsNCiAgICB9IGVsc2UgaWYgKGRhdGEudHlwZSA9PSAnT2NjbHVzaW9uRGF0YScpIHsNCiAgICAgIHByb2Nlc3NPY2NsdXNpb25EYXRhKGRhdGEpOw0KICAgIH0NCiAgfTsNCg0KICBzZWxmLm9ubWVzc2FnZSA9IGZ1bmN0aW9uIChldmVudCkgew0KICAgIGhhbmRsZU1lc3NhZ2UoZXZlbnQuZGF0YSwgc2VsZi5wb3N0TWVzc2FnZSk7DQogIH07CgogIGV4cG9ydHMuaGFuZGxlTWVzc2FnZSA9IGhhbmRsZU1lc3NhZ2U7CgogIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCAnX19lc01vZHVsZScsIHsgdmFsdWU6IHRydWUgfSk7CgogIHJldHVybiBleHBvcnRzOwoKfSkoe30pOwoK', null, false);\n/* eslint-enable */\n\n// See also: src\\Renderer\\Shaders\\GLSL\\drawItemId.glsl\n// const int pixelsPerItem = 8;\nconst pixelsPerItem$1 = 8;\n\n// https://forum.babylonjs.com/t/speeding-up-readpixels/12739\nclass AbortController {\n    __abort = false;\n    abort() {\n        this.__abort = true;\n    }\n}\nfunction clientWaitAsync(gl, sync, flags, interval_ms, abortController) {\n    return new Promise((resolve, reject) => {\n        const id = setInterval(() => {\n            if (abortController.__abort) {\n                // Note: I preferred to 'reject' here if the abortController is aborted.\n                // However, that would always generate an error message 'Uncaught (in promise)',\n                // with a callstack in the console starting at the 'setInterval' call..\n                // Even with 'try/catch' blocks around the 'await' calls, the error message would still appear.\n                // So I decided to 'resolve' instead, and check the status of the abortController\n                // as the stack unwinds. (see below)\n                clearInterval(id);\n                resolve();\n                return;\n            }\n            const res = gl.clientWaitSync(sync, flags, 0);\n            if (res == gl.WAIT_FAILED) {\n                clearInterval(id);\n                reject();\n                return;\n            }\n            if (res == gl.TIMEOUT_EXPIRED) {\n                return;\n            }\n            clearInterval(id);\n            resolve();\n        }, interval_ms);\n    });\n}\nasync function getBufferSubDataAsync(gl, target, buffer, srcByteOffset, dstBuffer, abortController, \n/* optional */ dstOffset = 0, \n/* optional */ length = 0) {\n    const sync = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0);\n    gl.flush();\n    await clientWaitAsync(gl, sync, 0, 10, abortController);\n    if (!abortController.__abort) {\n        gl.bindBuffer(target, buffer);\n        gl.getBufferSubData(target, srcByteOffset, dstBuffer, dstOffset, length);\n        gl.bindBuffer(target, null);\n    }\n    gl.deleteSync(sync);\n    return dstBuffer;\n}\nasync function readPixelsAsync(gl, x, y, w, h, format, type, dest, abortController) {\n    const buf = gl.createBuffer();\n    gl.bindBuffer(gl.PIXEL_PACK_BUFFER, buf);\n    gl.bufferData(gl.PIXEL_PACK_BUFFER, dest.byteLength, gl.STREAM_READ);\n    gl.readPixels(x, y, w, h, format, type, 0);\n    gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);\n    await getBufferSubDataAsync(gl, gl.PIXEL_PACK_BUFFER, buf, 0, dest, abortController);\n    gl.deleteBuffer(buf);\n    return dest;\n}\n\n/**\n * @private\n * @extends {ProceduralMesh}\n */\nclass BBoxOcclusionLinesCuboid extends Lines {\n    constructor() {\n        super();\n        this.setNumVertices(8);\n        const positions = this.getVertexAttribute('positions');\n        positions.setValue(0, new Vec3(0.5, -0.5, 0.5));\n        positions.setValue(1, new Vec3(0.5, 0.5, 0.5));\n        positions.setValue(2, new Vec3(-0.5, 0.5, 0.5));\n        positions.setValue(3, new Vec3(-0.5, -0.5, 0.5));\n        positions.setValue(4, new Vec3(0.5, -0.5, -0.5));\n        positions.setValue(5, new Vec3(0.5, 0.5, -0.5));\n        positions.setValue(6, new Vec3(-0.5, 0.5, -0.5));\n        positions.setValue(7, new Vec3(-0.5, -0.5, -0.5));\n        //\n        //      7*----------*6\n        //     /   \\  /   / |\n        //  4*----------*5  |\n        //   | \\     /  |   |\n        //   |   \\ /    |   |\n        //   |   / \\3   |  /2\n        //   | /     \\  |/\n        //  0*----------*1\n        //\n        this.setNumSegments(34);\n        this.setSegmentVertexIndices(0, 0, 1);\n        this.setSegmentVertexIndices(1, 0, 2);\n        this.setSegmentVertexIndices(2, 0, 3);\n        this.setSegmentVertexIndices(3, 0, 4);\n        this.setSegmentVertexIndices(4, 0, 5);\n        this.setSegmentVertexIndices(5, 0, 6);\n        this.setSegmentVertexIndices(6, 0, 7);\n        this.setSegmentVertexIndices(7, 1, 0);\n        this.setSegmentVertexIndices(8, 1, 2);\n        this.setSegmentVertexIndices(9, 1, 3);\n        this.setSegmentVertexIndices(10, 1, 4);\n        this.setSegmentVertexIndices(11, 1, 5);\n        this.setSegmentVertexIndices(12, 1, 6);\n        this.setSegmentVertexIndices(13, 1, 7);\n        this.setSegmentVertexIndices(14, 2, 0);\n        this.setSegmentVertexIndices(15, 2, 1);\n        this.setSegmentVertexIndices(16, 2, 3);\n        this.setSegmentVertexIndices(17, 2, 4);\n        this.setSegmentVertexIndices(18, 2, 5);\n        this.setSegmentVertexIndices(19, 2, 6);\n        this.setSegmentVertexIndices(20, 2, 7);\n        this.setSegmentVertexIndices(21, 3, 1);\n        this.setSegmentVertexIndices(22, 3, 2);\n        this.setSegmentVertexIndices(23, 3, 0);\n        this.setSegmentVertexIndices(24, 3, 4);\n        this.setSegmentVertexIndices(25, 3, 5);\n        this.setSegmentVertexIndices(26, 3, 6);\n        this.setSegmentVertexIndices(27, 3, 7);\n        this.setSegmentVertexIndices(28, 4, 5);\n        this.setSegmentVertexIndices(29, 4, 6);\n        this.setSegmentVertexIndices(30, 4, 7);\n        this.setSegmentVertexIndices(31, 5, 6);\n        this.setSegmentVertexIndices(32, 5, 7);\n        this.setSegmentVertexIndices(33, 6, 7);\n    }\n}\n\n/** This base class supports various XR experiences via spcialized clases such as VRViewport and XRViewport.\n * @extends GLBaseViewport\n */\nclass XRViewport extends GLBaseViewport {\n    projectionMatricesUpdated;\n    tick;\n    stageTreeItem;\n    stageScale;\n    viewXfo = new Xfo();\n    stageXfo = new Xfo();\n    invStageXfo = new Xfo();\n    invStageMatrix = new Mat4();\n    region = [];\n    session = null;\n    refSpace;\n    projectionMatrices = [];\n    viewMatrices = [];\n    cameraMatrices = [];\n    sessionMode = 'immersive-vr';\n    controllersMap = {};\n    controllers = [];\n    controllerPointerDownTime = [];\n    /**\n     * Create a VR viewport.\n     * @param renderer - The renderer value.\n     */\n    constructor(renderer, sessionMode) {\n        super(renderer);\n        this.clickTime = 300;\n        this.doubleClickTime = 300;\n        this.sessionMode = sessionMode;\n        // ////////////////////////////////////////////\n        // Tree\n        this.stageTreeItem = new TreeItem('VRStage');\n        this.stageTreeItem.setVisible(false);\n        this.__renderer.addTreeItem(this.stageTreeItem);\n        // ////////////////////////////////////////////\n        // Xfos\n        const xfo = new Xfo();\n        // Convert Y-Up to Z-Up.\n        xfo.ori.setFromAxisAndAngle(new Vec3(1, 0, 0), Math.PI * 0.5);\n        this.setXfo(xfo); // Reset the stage Xfo.\n    }\n    getRenderer() {\n        return this.renderer;\n    }\n    /**\n     * The getTreeItem method.\n     * @return - The return value.\n     */\n    getTreeItem() {\n        return this.stageTreeItem;\n    }\n    /**\n     * The getXfo method.\n     * @return - The return value.\n     */\n    getXfo() {\n        return this.stageXfo;\n    }\n    /**\n     * Sets the stage Xfo, which is the Xfo that transforms the user into the world.\n     * The local displacement of the user within their volume is applied on top of this Xfo.\n     * @param xfo - The xfo value.\n     */\n    setXfo(xfo) {\n        this.stageXfo = xfo;\n        this.stageTreeItem.globalXfoParam.value = xfo;\n        this.invStageXfo = xfo.inverse();\n        this.invStageMatrix = this.invStageXfo.toMat4();\n        this.stageScale = xfo.sc.x;\n    }\n    /**\n     * The getControllers method.\n     * @return - The return value.\n     */\n    getControllers() {\n        return this.controllers;\n    }\n    // //////////////////////////\n    // Presenting\n    /**\n     * The isPresenting method.\n     * @return - The return value.\n     */\n    isPresenting() {\n        return this.session != null;\n    }\n    /**\n     * Lanuches the session loop\n     */\n    startSession() {\n        const onAnimationFrame = (t, frame) => {\n            if (this.session) {\n                this.session.requestAnimationFrame(onAnimationFrame);\n                this.drawXRFrame(frame);\n            }\n        };\n        this.session.requestAnimationFrame(onAnimationFrame);\n    }\n    /**\n     * The stopPresenting method.\n     */\n    stopPresenting() {\n        if (!this.session)\n            return;\n        this.session.end();\n    }\n    /**\n     * The togglePresenting method.\n     */\n    togglePresenting() {\n        if (this.session)\n            this.stopPresenting();\n        else\n            this.startPresenting();\n    }\n    /**\n     * The bindCullingViewport method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    bindCullingViewport(renderstate, fovY, projectionMatrixMat4) {\n        renderstate.viewXfo = this.viewXfo;\n        renderstate.viewScale = 1.0;\n        renderstate.region = this.region;\n        renderstate.cameraMatrix = renderstate.viewXfo.toMat4();\n        const viewMatrixMat4 = renderstate.cameraMatrix.inverse();\n        renderstate.viewport = this;\n        // const frustumHPersp = Math.tan(fovY / 2.0) * flocalDist * 2.0\n        // const frustumWPersp = frustumHPersp * aspect\n        // const frustumHOrtho = this.camera.getFrustumHeight()\n        // const frustumWOrtho = frustumHPersp * aspect\n        // const viewportFrustum = Vec4(\n        //   MathFunctions.lerp(frustumWPersp, frustumWOrtho, isOrthographic),\n        //   MathFunctions.lerp(frustumHPersp, frustumHOrtho, isOrthographic),\n        //   flocalDist,\n        //   fovY\n        // )\n        const gl = this.__renderer.gl;\n        renderstate.bindRendererUnifs = (unifs) => {\n            const { cameraMatrix, viewMatrix, projectionMatrix, eye, isOrthographic } = unifs;\n            if (cameraMatrix) {\n                gl.uniformMatrix4fv(cameraMatrix.location, false, renderstate.cameraMatrix.asArray());\n            }\n            if (viewMatrix) {\n                gl.uniformMatrix4fv(viewMatrix.location, false, viewMatrixMat4.asArray());\n            }\n            if (projectionMatrix) {\n                gl.uniformMatrix4fv(projectionMatrix.location, false, projectionMatrixMat4.asArray());\n            }\n            if (eye) {\n                // for monocular rendering, we just render viewport 0\n                gl.uniform1i(eye.location, 0);\n            }\n            if (isOrthographic) {\n                // Left or right eye, when rendering stereo VR.\n                gl.uniform1i(isOrthographic.location, 0);\n            }\n            // if (viewportFrustum && this.viewportFrustum) {\n            //   // Left or right eye, when rendering stereo VR.\n            //   gl.uniform4f(\n            //     viewportFrustum.location,\n            //     this.viewportFrustum.x,\n            //     this.viewportFrustum.y,\n            //     this.viewportFrustum.z,\n            //     this.viewportFrustum.w\n            //   )\n            // }\n        };\n        renderstate.bindViewports = (unifs, draw) => draw();\n    }\n    /**\n     * The bindXRViewport method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    bindXRViewport(renderstate, viewports) {\n        renderstate.viewXfo = this.viewXfo;\n        renderstate.viewScale = 1.0;\n        renderstate.region = this.region;\n        renderstate.cameraMatrix = renderstate.viewXfo.toMat4();\n        renderstate.viewport = this;\n        const gl = this.__renderer.gl;\n        renderstate.bindRendererUnifs = (unifs) => {\n            // Note: the camera matrix should be the head position instead\n            // of the eye position. The inverse(viewMatrix) can be used\n            // when we want the eye pos.\n            const { cameraMatrix } = unifs;\n            if (cameraMatrix) {\n                gl.uniformMatrix4fv(cameraMatrix.location, false, renderstate.cameraMatrix.asArray());\n            }\n        };\n        renderstate.bindViewports = (unifs, draw) => {\n            const { isOrthographic } = unifs;\n            if (isOrthographic) {\n                gl.uniform1i(isOrthographic.location, 0);\n            }\n            viewports.forEach((vp, index) => {\n                let vp_region = vp.region;\n                gl.viewport(vp_region[0], vp_region[1], vp_region[2], vp_region[3]);\n                const { viewMatrix, projectionMatrix, eye } = unifs;\n                if (viewMatrix) {\n                    gl.uniformMatrix4fv(viewMatrix.location, false, vp.viewMatrix.asArray());\n                }\n                if (projectionMatrix) {\n                    gl.uniformMatrix4fv(projectionMatrix.location, false, vp.projectionMatrix.asArray());\n                }\n                if (eye) {\n                    // Left or right eye, when rendering stereo VR.\n                    gl.uniform1i(eye.location, index);\n                }\n                draw();\n            });\n        };\n    }\n}\n\n/** Class representing a VR head.\n * @private\n */\nclass XRHead {\n    xrvp;\n    treeItem;\n    mat4;\n    localXfo;\n    hmdGeomItem;\n    /**\n     * Create a VR head.\n     * @param xrvp - The VR viewport.\n     * @param stageTreeItem - The stageTreeItem value.\n     */\n    constructor(xrvp, stageTreeItem) {\n        this.xrvp = xrvp;\n        this.treeItem = new TreeItem('XRHead');\n        stageTreeItem.addChild(this.treeItem);\n        this.mat4 = new Mat4();\n        this.localXfo = new Xfo();\n    }\n    /**\n     * The Set wether the HMB is visible in rendering or not. Used in spectator rendering.\n     * @param state - The visibility value.\n     */\n    setVisible(state) {\n        if (state && !this.hmdGeomItem) {\n            const assetItem = this.xrvp.getAsset();\n            if (!assetItem)\n                return;\n            const hmdGeomItem = assetItem.getChildByName('HMD');\n            if (!hmdGeomItem)\n                return;\n            this.hmdGeomItem = hmdGeomItem.clone({ assetItem });\n            if (this.hmdGeomItem) {\n                const quat = new Quat();\n                quat.setFromAxisAndAngle(new Vec3(0, 1, 0), Math.PI);\n                this.hmdGeomItem.localXfoParam.value = new Xfo(new Vec3(0, -0.035, -0.03), quat, new Vec3(0.001, 0.001, 0.001) // VRAsset units are in mm.\n                );\n                this.treeItem.addChild(this.hmdGeomItem, false);\n            }\n        }\n        if (this.hmdGeomItem) {\n            this.hmdGeomItem.visibleParam.value = state;\n        }\n    }\n    /**\n     * The update method.\n     * @param pose - The pose value.\n     */\n    update(pose) {\n        // Old\n        // this.mat4.fromArray(pose.poseModelMatrix);\n        // New\n        this.mat4.fromArray(pose.transform.matrix);\n        this.localXfo.setFromMat4(this.mat4);\n        // const pos = pose.transform.position;\n        // this.localXfo.tr.set(pos.x, pos.y,pos.z);\n        // const ori = pose.transform.orientation;\n        // this.localXfo.ori.set(ori.x, ori.y, ori.z, ori.x);\n        this.treeItem.localXfoParam.value = this.localXfo;\n    }\n    /**\n     * The getTreeItem method.\n     * @return - The return value.\n     */\n    getTreeItem() {\n        return this.treeItem;\n    }\n    /**\n     * The getXfo method.\n     * @return - The return value.\n     */\n    getXfo() {\n        return this.localXfo;\n    }\n}\n\n// const line = new Lines()\n// line.setNumVertices(2)\n// line.setNumSegments(1)\n// line.setSegmentVertexIndices(0, 0, 1)\n// const positions = <Vec3Attribute>line.getVertexAttribute('positions')\n// positions.setValue(0, new Vec3(0.0, 0.0, 0.0))\n// positions.setValue(1, new Vec3(0.0, 0.0, -1.0))\n// line.setBoundingBoxDirty()\n/** Class representing a VR controller.\n *\n * The XRController class wraps the XRInputSource provided by the WebXR API.\n *\n * https://developer.mozilla.org/en-US/docs/Web/API/XRInputSource\n *\n * The XRController provides a tree item that can be used to attach geometries to represenet\n * the controllers or tools that the user may have in thier hands.\n * ```javascript\n * renderer.getXRViewport().then((xrvp) => {\n *   xrvp.on('controllerAdded', (event) => {\n *     const controller = event.controller\n *\n *     // Configure the distance of the ray cast performed by the controller into the scene.\n *     // Note: setting to 0 disables ray casting.\n *     controller.raycastDist = 20.0\n *\n *     // Remove the green ball added by the VRViewManipulator.\n *     controller.tipItem.removeAllChildren()\n *\n *     // Add a visual indication of the ray.\n *     const pointerItem = new GeomItem('PointerRay', line, pointermat)\n *     pointerItem.pickableParam.value = false\n *     const pointerXfo = new Xfo()\n *     pointerXfo.sc.set(1, 1, controller.raycastDist)\n *     pointerItem.localXfoParam.value = pointerXfo\n *     controller.tipItem.addChild(pointerItem, false)\n *\n *     // The tip items needs to be rotated down a little to make it\n *     // point in the right direction.\n *     const tipItemXfo = controller.tipItem.localXfoParam.value\n *     tipItemXfo.ori.setFromAxisAndAngle(new Vec3(1, 0, 0), -0.8)\n *     controller.tipItem.localXfoParam.value = tipItemXfo\n *\n *     controller.on('buttonPressed', (event) => {\n *       console.log('buttonPressed', event)\n *     })\n *     controller.on('buttonReleased', (event) => {\n *       console.log('buttonReleased', event)\n *     })\n *   })\n * })\n * ```\n *\n * **Events**\n * * **buttonPressed:** Emitted when the user presses any of the buttons aside from the trigger button.\n * * **buttonReleased:** Emitted when the user release any of the buttons aside from the trigger button.\n *\n *\n * @extends EventEmitter\n */\nclass XRController extends EventEmitter {\n    id;\n    buttonPressed;\n    xrvp;\n    inputSource;\n    pressedButtons = [];\n    treeItem;\n    tipItem;\n    // The frequency of raycasting into the scene for this controller\n    raycastTick = 5;\n    raycastArea = 0.005;\n    raycastDist = 0.04;\n    pointerRay = new Ray();\n    mat4 = new Mat4();\n    xfo = new Xfo();\n    raycastAreaCache = 0;\n    raycastDistCache = 0;\n    rayCastRenderTargetProjMatrix = new Mat4();\n    tick;\n    hitTested;\n    pointerOverItem;\n    intersectionData;\n    /**\n     * Create a VR controller.\n     * @param xrvp - The Vr viewport.\n     * @param inputSource - The input source.\n     * @param id - The id value.\n     */\n    constructor(xrvp, inputSource, id) {\n        super();\n        this.xrvp = xrvp;\n        this.inputSource = inputSource;\n        this.id = id;\n        this.buttonPressed = false;\n        this.inputSource.gamepad.buttons.forEach((button, index) => {\n            if (index == 0)\n                return;\n            this.pressedButtons[index] = button.pressed;\n        });\n        // /////////////////////////////////\n        this.treeItem = new TreeItem('XRController:' + inputSource.handedness + id);\n        // Controller coordinate system\n        // X = Horizontal.\n        // Y = Down through the knuckles.\n        // Z = Towards handle base.\n        if (!SystemDesc.isMobileDevice) {\n            // A Vive or Oculus Controller\n            this.tipItem = new TreeItem('Tip');\n            // Note: the tip of the controller need to be off\n            // the end of the controller. getGeomItemAtTip\n            // now searches a grid in that area and so we need to\n            // ensure that the grid does not touch the controller,\n            // else it will return the controller geom from\n            // the getGeomItemAtTip function\n            // Flip the pointer to face the +Z direction and\n            // tilt it down to be a little to be easier on the wrists.\n            this.tipItem.localXfoParam.value.tr.set(0.0, -0.05, -0.13);\n            this.tipItem.localXfoParam.value.ori.setFromAxisAndAngle(new Vec3(1, 0, 0), Math.PI * 0.8);\n            this.treeItem.addChild(this.tipItem, false);\n            xrvp.stageTreeItem.addChild(this.treeItem);\n            if (inputSource.targetRayMode == 'tracked-pointer') {\n                // Once we have an input profile, we can determine the XR Device in use.\n                switch (inputSource.profiles[0]) {\n                    case 'htc-vive':\n                        localStorage.setItem('ZeaEngine_XRDevice', 'Vive');\n                        break;\n                    case 'oculus-touch':\n                    case 'oculus-touch-v2':\n                    case 'oculus-touch-v3':\n                        localStorage.setItem('ZeaEngine_XRDevice', 'Oculus');\n                        break;\n                }\n                xrvp.loadHMDResources().then((assetItem) => {\n                    if (!assetItem)\n                        return;\n                    const localXfo = new Xfo();\n                    localXfo.ori.setFromAxisAndAngle(new Vec3(0, 1, 0), Math.PI);\n                    localXfo.sc.set(0.001, 0.001, 0.001); // VRAsset units are in mm.\n                    let srcControllerTree;\n                    if (inputSource.profiles[0] == 'htc-vive') {\n                        srcControllerTree = assetItem.getChildByName('Controller');\n                        localXfo.tr.set(0, -0.035, -0.085);\n                    }\n                    else {\n                        switch (inputSource.handedness) {\n                            case 'left':\n                                srcControllerTree = assetItem.getChildByName('LeftController');\n                                localXfo.tr.set(0, -0.035, -0.085);\n                                localXfo.sc.scaleInPlace(0.85);\n                                break;\n                            case 'right':\n                                srcControllerTree = assetItem.getChildByName('RightController');\n                                localXfo.tr.set(0, -0.035, -0.085);\n                                localXfo.sc.scaleInPlace(0.85);\n                                break;\n                            case 'none':\n                            default:\n                                srcControllerTree = assetItem.getChildByName('Controller');\n                                break;\n                        }\n                    }\n                    if (srcControllerTree) {\n                        const cloneContext = new CloneContext();\n                        cloneContext.assetItem = assetItem;\n                        const controllerTree = srcControllerTree.clone(cloneContext);\n                        controllerTree.localXfoParam.value = localXfo;\n                        this.treeItem.addChild(controllerTree, false);\n                    }\n                });\n            }\n        }\n        this.tick = 0;\n    }\n    /**\n     * The getHandedness method.\n     * @return - The return value.\n     */\n    getHandedness() {\n        return this.inputSource.handedness;\n    }\n    /**\n     * The getId method.\n     * @return - The return value.\n     */\n    getId() {\n        return this.id;\n    }\n    /**\n     * The getTreeItem method.\n     * @return - The return value.\n     */\n    getTreeItem() {\n        return this.treeItem;\n    }\n    /**\n     * The getTipItem method.\n     * @return - The return value.\n     */\n    getTipItem() {\n        return this.tipItem;\n    }\n    /**\n     * The getTipXfo method.\n     * @return - The return value.\n     */\n    getTipXfo() {\n        return this.tipItem.globalXfoParam.value;\n    }\n    /**\n     * The isButtonPressed method.\n     * @return - The return value.\n     */\n    isButtonPressed() {\n        return this.buttonPressed;\n    }\n    /**\n     * The getControllerStageLocalXfo method.\n     * @return - The return value.\n     */\n    getControllerStageLocalXfo() {\n        return this.xfo;\n    }\n    /**\n     * The getControllerTipStageLocalXfo method.\n     * @return - The return value.\n     */\n    getControllerTipStageLocalXfo() {\n        return this.xfo.multiply(this.tipItem.localXfoParam.value);\n    }\n    // ////////////////////////////////\n    /**\n     * The updatePose method.\n     * @param refSpace - The refSpace value.\n     * @param xrFrame - The xrFrame value.\n     * @param inputSource - The inputSource value.\n     */\n    updatePose(refSpace, xrFrame, inputSource) {\n        const inputPose = xrFrame.getPose(inputSource.gripSpace, refSpace);\n        // We may not get a inputPose back in cases where the input source has lost\n        // tracking or does not know where it is relative to the given frame\n        // of reference.\n        if (!inputPose || !inputPose.transform) {\n            return;\n        }\n        this.mat4.fromArray(inputPose.transform.matrix);\n        this.xfo.setFromMat4(this.mat4);\n        // const pos = inputPose.transform.position;\n        // this.xfo.tr.set(pos.x, pos.y,pos.z);\n        // const ori = inputPose.transform.orientation;\n        // this.xfo.ori.set(ori.x, ori.y, ori.z, ori.x);\n        // //////////////////////////////\n        this.treeItem.localXfoParam.value = this.xfo;\n        const tipXfo = this.tipItem.globalXfoParam.value;\n        this.pointerRay.start = tipXfo.tr;\n        this.pointerRay.dir = tipXfo.ori.getZaxis();\n        // Reset the geom at tip so it will be recomputed if necessary\n        this.hitTested = false;\n        let rebindRenderTarget = false;\n        // /////////////////////////////////\n        // Simulate Pointer Enter/Leave Events.\n        // Check for pointer over every Nth frame (at 90fps this should be fine.)\n        if (this.raycastDist > 0.0 && this.raycastTick > 0 && this.tick % this.raycastTick == 0) {\n            const intersectionData = this.getGeomItemAtTip();\n            rebindRenderTarget = true;\n            if (intersectionData != undefined) {\n                const event = new XRControllerEvent(this.xrvp, this, 0, this.buttonPressed ? 1 : 0);\n                event.intersectionData = intersectionData;\n                event.pointerRay = this.pointerRay;\n                if (intersectionData.geomItem != this.pointerOverItem) {\n                    if (this.pointerOverItem) {\n                        event.leftGeometry = this.pointerOverItem;\n                        this.pointerOverItem.onPointerLeave(event);\n                        if (event.propagating)\n                            this.xrvp.emit('pointerLeaveGeom', event);\n                    }\n                    event.propagating = true;\n                    this.pointerOverItem = intersectionData.geomItem;\n                    this.pointerOverItem.onPointerEnter(event);\n                    if (event.propagating)\n                        this.xrvp.emit('pointerOverGeom', event);\n                }\n                // emit the pointer move event directly to the item.\n                intersectionData.geomItem.onPointerMove(event);\n            }\n            else if (this.pointerOverItem) {\n                const event = new XRControllerEvent(this.xrvp, this, 0, this.buttonPressed ? 1 : 0);\n                event.pointerRay = this.pointerRay;\n                event.leftGeometry = this.pointerOverItem;\n                this.pointerOverItem.onPointerLeave(event);\n                this.pointerOverItem = null;\n            }\n        }\n        this.inputSource.gamepad.buttons.forEach((button, index) => {\n            if (index == 0)\n                return; // skip the trigger\n            if (button.pressed && !this.pressedButtons[index]) {\n                this.pressedButtons[index] = true;\n                const event = new XRControllerEvent(this.xrvp, this, index, 1);\n                event.intersectionData = this.getGeomItemAtTip();\n                event.pointerRay = this.pointerRay;\n                this.emit('buttonPressed', event);\n                rebindRenderTarget = true;\n            }\n            else if (!button.pressed && this.pressedButtons[index]) {\n                this.pressedButtons[index] = false;\n                const event = new XRControllerEvent(this.xrvp, this, index, 0);\n                this.emit('buttonReleased', event);\n            }\n        });\n        this.tick++;\n        return rebindRenderTarget;\n    }\n    // ////////////////////////////////\n    /**\n     * The getGeomItemAtTip method.\n     * @return - The return value.\n     */\n    getGeomItemAtTip() {\n        if (this.hitTested)\n            return this.intersectionData;\n        this.hitTested = true;\n        if (this.raycastDist == 0)\n            return null;\n        const dist = this.raycastDist * this.xrvp.stageScale;\n        const area = this.raycastArea * this.xrvp.stageScale;\n        if (dist != this.raycastDistCache || area != this.raycastAreaCache) {\n            this.rayCastRenderTargetProjMatrix.setOrthographicMatrix(area * -0.5, area * 0.5, area * -0.5, area * 0.5, 0.0, -dist // negate as we raycast doen the +Z asix of the tip item.\n            );\n            this.raycastDistCache = dist;\n            this.raycastAreaCache = area;\n        }\n        const renderer = this.xrvp.getRenderer();\n        const xfo = this.tipItem.globalXfoParam.value.clone();\n        xfo.sc.set(1, 1, 1);\n        this.intersectionData = renderer.raycastWithProjection(xfo, this.rayCastRenderTargetProjMatrix, this.pointerRay);\n        return this.intersectionData;\n    }\n}\nclass VRController extends XRController {\n}\n\n/**\n * Class representing a view tool\n * @extends BaseTool\n */\nclass XRViewManipulator extends BaseTool {\n    enableViewScale = true;\n    listenerIDs = {};\n    controllerTriggersHeld = [];\n    xrvp;\n    vrControllerToolTip;\n    vrControllerToolTipMat;\n    grabPos;\n    stageXfo__GrabStart;\n    grabDir;\n    grabDist;\n    /**\n     */\n    constructor(xrvp) {\n        super();\n        this.xrvp = xrvp;\n        this.vrControllerToolTip = new Cross(0.05);\n        this.vrControllerToolTipMat = new Material('VRController Cross', 'LinesShader');\n        this.vrControllerToolTipMat.getParameter('BaseColor').value = new Color('#03E3AC');\n    }\n    // /////////////////////////////////////\n    //\n    /**\n     * Adds the icon to the tip of the VR Controller\n     * @param event\n     */\n    /**\n     * The activateTool method.\n     */\n    activateTool() {\n        super.activateTool();\n        const bindController = (controller) => {\n            const geomItem = new GeomItem('XRViewManipulatorToolTip', this.vrControllerToolTip, this.vrControllerToolTipMat);\n            geomItem.pickableParam.value = false;\n            controller.getTipItem().removeAllChildren();\n            controller.getTipItem().addChild(geomItem, false);\n        };\n        for (const controller of this.xrvp.getControllers()) {\n            bindController(controller);\n        }\n        this.listenerIDs['controllerAdded'] = this.xrvp.on('controllerAdded', (event) => {\n            bindController(event.controller);\n        });\n    }\n    /**\n     * The deactivateTool method.\n     */\n    deactivateTool() {\n        super.deactivateTool();\n        const unbindController = (controller) => {\n            const geomItem = controller.getTipItem().getChildByName('XRViewManipulatorToolTip');\n            controller.getTipItem().removeChildByHandle(geomItem);\n        };\n        for (const controller of this.xrvp.getControllers()) {\n            unbindController(controller);\n        }\n        this.xrvp.off('controllerAdded', this.listenerIDs['controllerAdded']);\n    }\n    // ///////////////////////////////////\n    // XRController events\n    // eslint-disable-next-line require-jsdoc\n    initMoveStage() {\n        if (this.controllerTriggersHeld.length == 1) {\n            this.grabPos = this.controllerTriggersHeld[0].getControllerTipStageLocalXfo().tr.clone();\n            this.stageXfo__GrabStart = this.xrvp.getXfo().clone();\n        }\n        else if (this.controllerTriggersHeld.length == 2) {\n            const p0 = this.controllerTriggersHeld[0].getControllerTipStageLocalXfo().tr;\n            const p1 = this.controllerTriggersHeld[1].getControllerTipStageLocalXfo().tr;\n            this.grabDir = p1.subtract(p0);\n            this.grabPos = p0.lerp(p1, 0.5);\n            this.grabDir.y = 0.0;\n            this.grabDist = this.grabDir.length();\n            this.grabDir.scaleInPlace(1 / this.grabDist);\n            this.stageXfo__GrabStart = this.xrvp.getXfo().clone();\n        }\n    }\n    /**\n     * The onXRControllerButtonDown method.\n     * @param event - The event param.\n     * @return The return value.\n     */\n    onXRControllerButtonDown(event) {\n        if (event.button != 0)\n            return;\n        const index = this.controllerTriggersHeld.indexOf(event.controller);\n        if (index == -1) {\n            this.controllerTriggersHeld.push(event.controller);\n            this.initMoveStage();\n            event.stopPropagation();\n            event.setCapture(this);\n        }\n    }\n    /**\n     * The onXRControllerButtonUp method.\n     * @param event - The event param.\n     * @return The return value.\n     */\n    onXRControllerButtonUp(event) {\n        if (event.button != 0)\n            return;\n        const index = this.controllerTriggersHeld.indexOf(event.controller);\n        if (index != -1) {\n            this.controllerTriggersHeld.splice(index, 1);\n            this.initMoveStage();\n            event.stopPropagation();\n            if (this.controllerTriggersHeld.length == 0) {\n                event.releaseCapture();\n            }\n        }\n    }\n    /**\n     * The onVRControllerDoubleClicked method.\n     * @param event - The event param.\n     */\n    onVRControllerDoubleClicked(event) {\n        console.log('onVRControllerDoubleClicked:', this.controllerTriggersHeld.length);\n        const stageXfo = this.xrvp.getXfo().clone();\n        stageXfo.sc.set(1, 1, 1);\n        this.xrvp.setXfo(stageXfo);\n    }\n    /**\n     * The onVRPoseChanged method.\n     * @param event - The event param.\n     */\n    onVRPoseChanged(event) {\n        if (this.controllerTriggersHeld.length == 1) {\n            const grabPos = this.controllerTriggersHeld[0].getControllerTipStageLocalXfo().tr;\n            const deltaXfo = new Xfo();\n            deltaXfo.tr = this.grabPos.subtract(grabPos);\n            // //////////////\n            // Update the stage Xfo\n            const stageXfo = this.stageXfo__GrabStart.multiply(deltaXfo);\n            this.xrvp.setXfo(stageXfo);\n        }\n        else if (this.controllerTriggersHeld.length == 2) {\n            const p0 = this.controllerTriggersHeld[0].getControllerTipStageLocalXfo().tr;\n            const p1 = this.controllerTriggersHeld[1].getControllerTipStageLocalXfo().tr;\n            const grabPos = p0.lerp(p1, 0.5);\n            const grabDir = p1.subtract(p0);\n            grabDir.y = 0.0;\n            const grabDist = grabDir.length();\n            // Sometimes we would get NaN values in the stage Xfo\n            if (grabDist < 0.0001)\n                return;\n            grabDir.scaleInPlace(1 / grabDist);\n            const deltaXfo = new Xfo();\n            // //////////////\n            // Compute ori\n            let angle = this.grabDir.angleTo(grabDir);\n            if (this.grabDir.cross(grabDir).y > 0.0) {\n                angle = -angle;\n            }\n            deltaXfo.ori.rotateY(angle);\n            const deltaTr = this.grabPos.subtract(grabPos);\n            // Rotate around the point between the hands.\n            const oriTrDelta = deltaXfo.ori.rotateVec3(this.grabPos);\n            deltaXfo.tr.addInPlace(this.grabPos.subtract(oriTrDelta));\n            // //////////////\n            // Compute sc\n            // Limit to a 10x change in scale per grab.\n            if (this.enableViewScale) {\n                const sc = Math.max(Math.min(this.grabDist / grabDist, 10.0), 0.1);\n                // Avoid causing a scale that would make the user < 1.0 scale factor.\n                // if(stageSc < 1.0){\n                //     sc = 1.0 / this.stageXfo__GrabStart.sc.x;\n                // }\n                deltaXfo.sc.set(sc, sc, sc);\n                // Scale around the point between the hands.\n                const deltaSc = this.grabPos.scale(1.0 - sc);\n                deltaXfo.tr.addInPlace(deltaXfo.ori.rotateVec3(deltaSc));\n                deltaTr.scaleInPlace(sc);\n            }\n            // //////////////\n            // Compute tr\n            deltaXfo.tr.addInPlace(deltaXfo.ori.rotateVec3(deltaTr));\n            // //////////////\n            // Update the stage Xfo\n            const stageXfo = this.stageXfo__GrabStart.multiply(deltaXfo);\n            this.xrvp.setXfo(stageXfo);\n        }\n    }\n    // ///////////////////////////////////\n    // Pointer events\n    /**\n     * Event fired when a pointing device button is pressed while the pointer is over the tool.\n     *\n     * @param event - The event param.\n     */\n    onPointerDown(event) {\n        if (event instanceof XRControllerEvent) {\n            this.onXRControllerButtonDown(event);\n        }\n    }\n    /**\n     * Event fired when a pointing device is moved while the cursor's hotspot is inside it.\n     *\n     * @param event - The event param.\n     */\n    onPointerMove(event) {\n        if (event instanceof XRPoseEvent) {\n            this.onVRPoseChanged(event);\n        }\n    }\n    /**\n     * Event fired when a pointing device button is released while the pointer is over the tool.\n     *\n     * @param event - The event param.\n     */\n    onPointerUp(event) {\n        if (event instanceof XRControllerEvent) {\n            this.onXRControllerButtonUp(event);\n        }\n    }\n    /**\n     * Event fired when a pointing device button is double clicked on the tool.\n     *\n     * @param event - The event param.\n     */\n    onPointerDoubleClick(event) {\n        if (event instanceof XRControllerEvent) {\n            this.onVRControllerDoubleClicked(event);\n        }\n    }\n}\n\n/** This Viewport class is used for rendering stereoscopic views to VR controllers using the WebXR api.\n *  When the GLRenderer class detects a valid WebXF capable device is plugged in, this class is automatically\n *  instantiated ready for XR sessions\n *\n * **Events**\n * * **presentingChanged:** Emitted when presenting is started or stopped\n * * **controllerAdded:** Emitted when a new XR controller is detected.\n * * **viewChanged:** Emitted during presentation each time the frame is rendered.\n * * **pointerDoubleClick:** Emitted when the user double clicks with an XR pointer.\n * * **pointerDown:** Emitted when the user presses an XR pointer\n * * **pointerUp:** Emitted when the user releases an XR pointer\n *\n * @extends XRViewport\n */\nclass VRViewport extends XRViewport {\n    vrAsset;\n    hmd = '';\n    hmdAssetPromise;\n    xrhead;\n    /**\n     * Create a VR viewport.\n     * @param renderer - The renderer value.\n     */\n    constructor(renderer, sessionMode) {\n        super(renderer, sessionMode);\n        this.xrhead = new XRHead(this, this.stageTreeItem);\n        this.setManipulator(new XRViewManipulator(this));\n    }\n    /**\n     * The getAsset method.\n     * @return - The return value.\n     */\n    getAsset() {\n        return this.vrAsset;\n    }\n    /**\n     * The getVRHead method.\n     * @return - The return value.\n     */\n    getVRHead() {\n        return this.xrhead;\n    }\n    /**\n     * Returns the name of the HMD being used.\n     * @return - The return value.\n     */\n    getHMDName() {\n        return this.hmd;\n    }\n    /**\n     * The loadHMDResources method.\n     * @return - The return value.\n     */\n    loadHMDResources() {\n        if (SystemDesc.isMobileDevice) {\n            return Promise.resolve(null);\n        }\n        // If the HMD has changed, reset it.\n        let hmd = localStorage.getItem('ZeaEngine_XRDevice');\n        if (!hmd) {\n            hmd = 'Oculus';\n            localStorage.setItem('ZeaEngine_XRDevice', hmd);\n        }\n        if (this.hmd != hmd) {\n            this.hmdAssetPromise = undefined;\n        }\n        else if (this.hmdAssetPromise)\n            return this.hmdAssetPromise;\n        this.hmd = hmd;\n        this.hmdAssetPromise = new Promise((resolve, reject) => {\n            // ////////////////////////////////////////////\n            // Resources\n            {\n                let hmdAssetId;\n                switch (hmd) {\n                    case 'Vive':\n                        hmdAssetId = 'ZeaEngine/Vive.vla';\n                        break;\n                    case 'Oculus':\n                        hmdAssetId = 'ZeaEngine/Oculus.vla';\n                        break;\n                    default:\n                        hmdAssetId = 'ZeaEngine/Vive.vla';\n                        break;\n                }\n                if (!resourceLoader.commonResources[hmdAssetId]) {\n                    // Cache the asset so if an avatar needs to display,\n                    // it can use the same asset.\n                    const asset = new VLAAsset(hmdAssetId);\n                    asset.load(resourceLoader.systemUrls[hmdAssetId]);\n                    resourceLoader.commonResources[hmdAssetId] = asset;\n                }\n                this.vrAsset = resourceLoader.getCommonResource(hmdAssetId);\n                const bind = () => {\n                    const materialLibrary = this.vrAsset.getMaterialLibrary();\n                    const materialNames = materialLibrary.getMaterialNames();\n                    for (const name of materialNames) {\n                        const material = materialLibrary.getMaterial(name);\n                        if (material) {\n                            material.setShaderName('SimpleSurfaceShader');\n                        }\n                    }\n                    this.vrAsset.traverse((item) => {\n                        item.pickableParam.value = false;\n                    });\n                    resolve(this.vrAsset);\n                };\n                if (this.vrAsset.isLoaded())\n                    bind();\n                else\n                    this.vrAsset.once('loaded', bind);\n            }\n        });\n        return this.hmdAssetPromise;\n    }\n    /**\n     * The startPresenting method.\n     */\n    startPresenting() {\n        return new Promise((resolve, reject) => {\n            // https://github.com/immersive-web/webxr/blob/master/explainer.md\n            const startPresenting = () => {\n                navigator.xr\n                    .requestSession('immersive-vr', {\n                    // Our standing experience will require at least a local-floor\n                    // reference space (which will be available even on 3DoF device)\n                    // but can optionally make use of bounded-floor reference spaces\n                    // when available.\n                    requiredFeatures: ['local-floor'],\n                    optionalFeatures: ['bounded-floor'],\n                })\n                    .then((session) => {\n                    const viewport = this.__renderer.getViewport();\n                    if (viewport) {\n                        const camera = viewport.getCamera();\n                        const cameraXfo = camera.globalXfoParam.value;\n                        // Convert Y-Up to Z-Up.\n                        const stageXfo = new Xfo();\n                        stageXfo.tr = cameraXfo.tr.clone();\n                        stageXfo.tr.z -= 1.3; // assume sitting, and move the floor down a bit\n                        const dir = cameraXfo.ori.getZaxis();\n                        dir.z = 0;\n                        dir.normalizeInPlace();\n                        stageXfo.ori.setFromDirectionAndUpvector(dir, new Vec3(0, 0, 1));\n                        this.setXfo(stageXfo);\n                    }\n                    session.addEventListener('end', () => {\n                        this.stageTreeItem.setVisible(false);\n                        this.session = null;\n                        // Make sure the default fbo is bound.\n                        // This addrsses an error generated by rendring directly after the session ends.\n                        // INVALID_FRAMEBUFFER_OPERATION: clear: Cannot render to a XRWebGLLayer framebuffer outside of an XRSession animation frame callback.\n                        const gl = this.__renderer.gl;\n                        gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n                        this.emit('presentingChanged', new StateChangedEvent(false));\n                    });\n                    const onSelectStart = (event) => {\n                        const controller = this.controllersMap[event.inputSource.handedness];\n                        if (controller) {\n                            controller.buttonPressed = true;\n                            this.onPointerDown(new XRControllerEvent(this, controller, 0, 1));\n                        }\n                    };\n                    const onSelectEnd = (ev) => {\n                        const controller = this.controllersMap[ev.inputSource.handedness];\n                        if (controller) {\n                            controller.buttonPressed = false;\n                            this.onPointerUp(new XRControllerEvent(this, controller, 0, 0));\n                        }\n                    };\n                    const createVRController = (inputSource) => {\n                        if (this.controllersMap[inputSource.handedness]) {\n                            this.controllersMap[inputSource.handedness].inputSource = inputSource;\n                            return;\n                        }\n                        const id = this.controllers.length;\n                        console.log('creating controller:', inputSource.handedness, inputSource.profiles);\n                        const controller = new XRController(this, inputSource, id);\n                        this.controllersMap[inputSource.handedness] = controller;\n                        this.controllers[id] = controller;\n                        this.controllerPointerDownTime[id] = [];\n                        controller.on('buttonPressed', (event) => {\n                            this.onPointerDown(event);\n                        });\n                        controller.on('buttonReleased', (event) => {\n                            this.onPointerUp(event);\n                        });\n                        const event = new ControllerAddedEvent(controller);\n                        this.emit('controllerAdded', event);\n                        return controller;\n                    };\n                    const onInputSourcesChange = (event) => {\n                        // As input sources are connected if they are tracked-pointer devices\n                        // look up which meshes should be associated with their profile and\n                        // load as the controller model for that hand.\n                        for (const inputSource of event.added) {\n                            if (inputSource.profiles.length == 0)\n                                continue;\n                            if (inputSource.profiles[0] == 'generic-touchscreen') ;\n                            else {\n                                createVRController(inputSource);\n                            }\n                        }\n                    };\n                    session.addEventListener('selectstart', onSelectStart);\n                    session.addEventListener('selectend', onSelectEnd);\n                    session.addEventListener('inputsourceschange', onInputSourcesChange);\n                    this.session = session;\n                    // ////////////////////////////\n                    // @ts-ignore - Note: We could install the webxr type definitions and remove this ignore.\n                    const glLayer = new XRWebGLLayer(session, this.__gl);\n                    session.updateRenderState({\n                        baseLayer: glLayer,\n                    });\n                    this.width = glLayer.framebufferWidth;\n                    this.height = glLayer.framebufferHeight;\n                    this.region = [0, 0, this.width, this.height];\n                    this.depthRange = [session.renderState.depthNear, session.renderState.depthFar];\n                    this.resizeRenderTargets(this.width, this.height);\n                    // ////////////////////////////\n                    // eslint-disable-next-line require-jsdoc\n                    const onRefSpaceCreated = (refSpace) => {\n                        this.refSpace = refSpace;\n                        this.stageTreeItem.setVisible(true);\n                        this.emit('presentingChanged', new StateChangedEvent(true));\n                        // In VR, we need to load the HMD so we can see\n                        // our controllers.\n                        this.loadHMDResources().then(() => {\n                            this.startSession();\n                            resolve();\n                        });\n                    };\n                    // Attempt to get a 'bounded-floor' reference space, which will align\n                    // the user's physical floor with Y=0 and provide boundaries that\n                    // indicate where the user can safely walk.\n                    session\n                        .requestReferenceSpace('bounded-floor')\n                        .catch((e) => {\n                        console.warn(e.message);\n                        // If a bounded reference space isn't supported, fall back to a\n                        // local-floor reference space. This still provides a floor-relative\n                        // space and will always be supported for immersive sessions. It\n                        // will not, however, provide boundaries and generally expects the\n                        // user to stand in one place. If the device doesn't have a way of\n                        // determining the floor level (for example, with a 3DoF device)\n                        // then it will return an emulated local-floor space, where the view\n                        // is translated up by a static height so that the scene still\n                        // renders in approximately the right place.\n                        console.log('Falling back to local-floor reference space');\n                        session.requestReferenceSpace('local-floor').then(onRefSpaceCreated);\n                    })\n                        .then((value) => {\n                        if (value)\n                            onRefSpaceCreated(value);\n                    })\n                        .catch((e) => {\n                        console.warn(e.message);\n                        reject(new Error('Unable to start XR Session:' + e.message));\n                    });\n                })\n                    .catch((e) => {\n                    console.warn(e.message);\n                });\n            };\n            startPresenting();\n        });\n    }\n    // //////////////////////////\n    // Controllers\n    /**\n     * The updateControllers method.\n     * @param xrFrame - The xrFrame value.\n     * @param event - The pose changed event object that will be emitted for observers such as collab.\n     */\n    updateControllers(xrFrame) {\n        let rebindRenderTarget = false;\n        const inputSources = this.session.inputSources;\n        for (let i = 0; i < inputSources.length; i++) {\n            const inputSource = inputSources[i];\n            // Note: This is to avoid a bug/feature in WebXR where initially the\n            // controllers have no handedness specified, then suddenly\n            // get handedness. We need the handedness before we can setup the controller.\n            if (inputSource.profiles.length == 0)\n                return;\n            if (!this.controllers[i]) {\n                console.warn('Missing controller');\n                continue;\n                // this.__createController(i, inputSource)\n            }\n            const res = this.controllers[i].updatePose(this.refSpace, xrFrame, inputSource);\n            rebindRenderTarget = rebindRenderTarget || res;\n        }\n        return rebindRenderTarget;\n    }\n    /**\n     * The drawXRFrame method.\n     * @param xrFrame - The xrFrame value.\n     */\n    drawXRFrame(xrFrame) {\n        const session = xrFrame.session;\n        const layer = session.renderState.baseLayer;\n        const pose = xrFrame.getViewerPose(this.refSpace);\n        if (!pose) {\n            // No pose available during XR present\n            // Note: before the Headset is put on the pose is missing, or after it is taken off\n            return;\n        }\n        const views = pose.views;\n        if (!this.projectionMatricesUpdated) {\n            this.projectionMatrices = [];\n            this.viewMatrices = [];\n            this.cameraMatrices = [];\n            for (let i = 0; i < views.length; i++) {\n                const view = views[i];\n                const projMat = new Mat4();\n                projMat.fromArray(view.projectionMatrix);\n                this.projectionMatrices[i] = projMat;\n                this.viewMatrices[i] = new Mat4();\n                this.cameraMatrices[i] = new Mat4();\n            }\n            this.projectionMatricesUpdated = true;\n        }\n        const gl = this.__renderer.gl;\n        this.depthRange = [session.renderState.depthNear, session.renderState.depthFar]; // TODO: check if this changes during session\n        const renderstate = new ColorRenderState(this.__renderer.gl);\n        renderstate.pushGLStack('VRViewport.drawXRFrame');\n        renderstate.boundRendertarget = layer.framebuffer;\n        renderstate.region = this.region;\n        renderstate.depthRange = this.depthRange;\n        renderstate.viewport = this;\n        renderstate.xrviewport = this;\n        const viewports = [];\n        for (let i = 0; i < views.length; i++) {\n            const view = views[i];\n            this.viewMatrices[i].fromArray(view.transform.inverse.matrix);\n            this.viewMatrices[i].multiplyInPlace(this.invStageMatrix);\n            const vp = layer.getViewport(view);\n            viewports.push({\n                viewMatrix: this.viewMatrices[i],\n                projectionMatrix: this.projectionMatrices[i],\n                region: [vp.x, vp.y, vp.width, vp.height],\n                isOrthographic: 0,\n            });\n        }\n        this.xrhead.update(pose);\n        const headXfo = this.xrhead.getTreeItem().globalXfoParam.value;\n        const cameraMatrixMat4 = headXfo.toMat4();\n        this.viewXfo = headXfo;\n        renderstate.viewXfo = headXfo;\n        renderstate.cameraMatrix = cameraMatrixMat4;\n        renderstate.viewScale = this.stageScale;\n        renderstate.region = this.region;\n        renderstate.vrPresenting = true; // Some rendering is adjusted slightly in VR. e.g. Billboards\n        this.updateControllers(xrFrame);\n        // ///////////////////////\n        // Prepare the pointerMove event.\n        const event = new XRPoseEvent(this, this.viewXfo, this.controllers);\n        if (event.getCapture()) {\n            event.getCapture().onPointerMove(event);\n            // events are now always sent to the capture item first,\n            // but can continue propagating to other items if no call\n            // to event.stopPropagation() was made.\n        }\n        if (this.manipulator && event.propagating) {\n            this.manipulator.onPointerMove(event);\n        }\n        // ///////////////////////\n        // Binding\n        this.bindXRViewport(renderstate, viewports);\n        // ///////////////////////\n        // Drawing\n        // If any of the controllers did some raycasting, then we need to rebind the\n        // WebXR render target before we draw the scene.\n        gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, renderstate.boundRendertarget);\n        let col = this.backgroundColorParam.value.asArray();\n        gl.clearColor(col[0], col[1], col[2], col[3]);\n        gl.colorMask(true, true, true, true);\n        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);\n        this.draw(renderstate);\n        renderstate.popGLStack();\n        if (renderstate.stack.length != 0) {\n            console.warn(' corrupt renderstate.stack.length:', renderstate.stack.length);\n        }\n        // ///////////////////////\n        // Emit a signal for the shared session.\n        const viewChangedEvent = new XRViewChangedEvent(renderstate.viewXfo);\n        // TODO: better solution than setting members individually?\n        viewChangedEvent.hmd = this.hmd;\n        viewChangedEvent.controllers = this.controllers;\n        viewChangedEvent.viewport = this;\n        viewChangedEvent.xrviewport = this;\n        this.emit('viewChanged', viewChangedEvent);\n        this.tick++;\n    }\n    /**\n     * Handler of the `pointerdown` event fired when the pointer device is initially pressed.\n     *\n     * @param event - The DOM event produced by a pointer\n     */\n    onPointerDown(event) {\n        event.intersectionData = event.controller.getGeomItemAtTip();\n        event.pointerRay = event.controller.pointerRay;\n        // //////////////////////////////////////\n        // Double Tap\n        // First check for double tap handlers.\n        // If the manipulator or the viewport handle that\n        // then skip the 'pointerDown' event.\n        const downTime = Date.now();\n        if (downTime - this.controllerPointerDownTime[event.controller.id][event.button] < this.doubleClickTime) {\n            this.emit('pointerDoubleClick', event);\n            if (!event.propagating)\n                return;\n            if (this.manipulator) {\n                this.manipulator.onPointerDoubleClick(event);\n                if (!event.propagating)\n                    return;\n            }\n        }\n        this.controllerPointerDownTime[event.controller.id][event.button] = downTime;\n        // //////////////////////////////////////\n        if (event.getCapture()) {\n            event.getCapture().onPointerDown(event);\n            // events are now always sent to the capture item first,\n            // but can continue propagating to other items if no call\n            // to event.stopPropagation() was made.\n            if (!event.propagating)\n                return;\n        }\n        if (event.intersectionData != undefined) {\n            event.intersectionData.geomItem.onPointerDown(event);\n            if (!event.propagating)\n                return;\n        }\n        this.emit('pointerDown', event);\n        if (!event.propagating)\n            return;\n        if (this.manipulator) {\n            this.manipulator.onPointerDown(event);\n        }\n    }\n    /**\n     * Causes an event to occur when a user releases a mouse button over a element.\n     *\n     * @param event - The event that occurs.\n     */\n    onPointerUp(event) {\n        event.pointerRay = event.controller.pointerRay;\n        event.intersectionData = event.controller.getGeomItemAtTip();\n        if (event.getCapture()) {\n            event.getCapture().onPointerUp(event);\n            // events are now always sent to the capture item first,\n            // but can continue propagating to other items if no call\n            // to event.stopPropagation() was made.\n        }\n        if (event.propagating) {\n            if (event.intersectionData != undefined) {\n                event.intersectionData.geomItem.onPointerUp(event);\n            }\n        }\n        if (event.propagating) {\n            this.emit('pointerUp', event);\n        }\n        if (event.propagating) {\n            if (this.manipulator) {\n                this.manipulator.onPointerUp(event);\n            }\n        }\n        const pointerDownTime = this.controllerPointerDownTime[event.controller.id][event.button];\n        const pointerUpTime = Date.now();\n        if (pointerUpTime - pointerDownTime < this.clickTime) {\n            event.propagating = true;\n            if (event.intersectionData != undefined) {\n                event.intersectionData.geomItem.onPointerClick(event);\n            }\n            if (event.propagating) {\n                this.emit('pointerClick', event);\n            }\n            if (event.propagating && this.manipulator) {\n                this.manipulator.onPointerClick(event);\n            }\n        }\n        this.controllerPointerDownTime[event.controller.id][event.button] = 0;\n    }\n}\n\n/** This Viewport class is used for rendering stereoscopic views to VR controllers using the WebXR api.\n *  When the GLRenderer class detects a valid WebXF capable device is plugged in, this class is automatically\n *  instantiated ready for XR sessions\n *\n * **Events**\n * * **presentingChanged:** Emitted when presenting is started or stopped\n * * **controllerAdded:** Emitted when a new XR controller is detected.\n * * **viewChanged:** Emitted during presentation each time the frame is rendered.\n * * **pointerDoubleClick:** Emitted when the user double clicks with an XR pointer.\n * * **pointerDown:** Emitted when the user presses an XR pointer\n * * **pointerUp:** Emitted when the user releases an XR pointer\n *\n * @extends XRViewport\n */\nclass ARViewport extends XRViewport {\n    stageXfoSet = false;\n    xrViewerSpace;\n    xrHitTestSource;\n    reticle;\n    /**\n     * Create a VR viewport.\n     * @param renderer - The renderer value.\n     */\n    constructor(renderer, sessionMode) {\n        super(renderer, sessionMode);\n        const disc = new Disc(0.1, 24);\n        const material = new FlatSurfaceMaterial('reticle');\n        material.baseColorParam.value = new Color(0.75, 0.75, 0.75, 0.4);\n        this.reticle = new GeomItem('reticle', disc, material);\n        // Convert Y-Up to Z-Up.\n        const xfo = new Xfo();\n        // Convert Y-Up to Z-Up.\n        xfo.ori.setFromAxisAndAngle(new Vec3(1, 0, 0), Math.PI * 0.5);\n        this.reticle.geomOffsetXfoParam.value = xfo;\n        this.stageTreeItem.addChild(this.reticle);\n    }\n    /**\n     * The startPresenting method.\n     */\n    startPresenting() {\n        return new Promise((resolve, reject) => {\n            // https://github.com/immersive-web/webxr/blob/master/explainer.md\n            const startPresenting = () => {\n                // @ts-ignore\n                navigator.xr\n                    .requestSession('immersive-ar', { requiredFeatures: ['local', 'hit-test', 'anchors'] })\n                    .then((session) => {\n                    session.addEventListener('end', () => {\n                        this.stageTreeItem.setVisible(false);\n                        this.session = null;\n                        this.emit('presentingChanged', new StateChangedEvent(false));\n                    });\n                    this.reticle.setVisible(true);\n                    const onSelect = (event) => {\n                        const hitTestResults = event.frame.getHitTestResults(this.xrHitTestSource);\n                        if (hitTestResults.length > 0) {\n                            const pose = hitTestResults[0].getPose(this.refSpace);\n                            if (this.reticle.isVisible()) {\n                                if (!this.stageXfoSet) {\n                                    this.stageXfo.tr = this.reticle.globalXfoParam.value.tr.negate();\n                                    this.setXfo(this.stageXfo);\n                                    this.stageXfoSet = true;\n                                }\n                                else {\n                                    const pointerEvent = new XRPointerEvent(this, this.reticle.globalXfoParam.value, event, hitTestResults);\n                                    this.emit('pointerPressed', pointerEvent);\n                                }\n                            }\n                            else {\n                                const localXfo = new Xfo();\n                                localXfo.setFromMat4(new Mat4(...pose.transform.matrix));\n                                const pointerEvent = new XRPointerEvent(this, this.stageXfo.multiply(localXfo), event, hitTestResults);\n                                this.emit('pointerPressed', pointerEvent);\n                            }\n                        }\n                    };\n                    session.addEventListener('select', onSelect);\n                    this.session = session;\n                    // ////////////////////////////\n                    // @ts-ignore - Note: We could install the webxr type definitions and remove this ignore.\n                    const glLayer = new XRWebGLLayer(session, this.__gl);\n                    session.updateRenderState({\n                        baseLayer: glLayer,\n                    });\n                    this.width = glLayer.framebufferWidth;\n                    this.height = glLayer.framebufferHeight;\n                    this.region = [0, 0, this.width, this.height];\n                    this.depthRange = [session.renderState.depthNear, session.renderState.depthFar];\n                    this.resizeRenderTargets(this.width, this.height);\n                    // ////////////////////////////\n                    // In this sample we want to cast a ray straight out from the viewer's\n                    // position and render a reticle where it intersects with a real world\n                    // surface. To do this we first get the viewer space, then create a\n                    // hitTestSource that tracks it.\n                    session.requestReferenceSpace('viewer').then((refSpace) => {\n                        this.xrViewerSpace = refSpace;\n                        session.requestHitTestSource({ space: this.xrViewerSpace }).then((hitTestSource) => {\n                            this.xrHitTestSource = hitTestSource;\n                        });\n                    });\n                    session.requestReferenceSpace('local').then((refSpace) => {\n                        this.refSpace = refSpace;\n                        this.stageTreeItem.setVisible(true);\n                        this.emit('presentingChanged', new StateChangedEvent(true));\n                        this.startSession();\n                        resolve();\n                    });\n                })\n                    .catch((e) => {\n                    console.warn(e.message);\n                });\n            };\n            startPresenting();\n        });\n    }\n    /**\n     * The drawXRFrame method.\n     * @param xrFrame - The xrFrame value.\n     */\n    drawXRFrame(xrFrame) {\n        const session = xrFrame.session;\n        const layer = session.renderState.baseLayer;\n        const pose = xrFrame.getViewerPose(this.refSpace);\n        if (!pose) {\n            // No pose available during XR present\n            // Note: before the Headset is put on the pose is missing, or after it is taken off\n            return;\n        }\n        if (this.xrHitTestSource && this.reticle.isVisible()) {\n            const hitTestResults = xrFrame.getHitTestResults(this.xrHitTestSource);\n            if (hitTestResults.length > 0) {\n                const hitPose = hitTestResults[0].getPose(this.refSpace);\n                const localXfo = new Xfo();\n                localXfo.setFromMat4(new Mat4(hitPose.transform.matrix));\n                this.reticle.localXfoParam.value = localXfo;\n            }\n        }\n        const views = pose.views;\n        if (!this.projectionMatricesUpdated) {\n            this.projectionMatrices = [];\n            this.viewMatrices = [];\n            this.cameraMatrices = [];\n            for (let i = 0; i < views.length; i++) {\n                const view = views[i];\n                const projMat = new Mat4();\n                projMat.fromArray(view.projectionMatrix);\n                this.projectionMatrices[i] = projMat;\n                this.viewMatrices[i] = new Mat4();\n                this.cameraMatrices[i] = new Mat4();\n            }\n            this.projectionMatricesUpdated = true;\n        }\n        this.depthRange = [session.renderState.depthNear, session.renderState.depthFar]; // TODO: check if this changes during session\n        const renderstate = new ColorRenderState(this.__renderer.gl);\n        renderstate.boundRendertarget = layer.framebuffer;\n        renderstate.region = this.region;\n        renderstate.viewport = this;\n        renderstate.xrviewport = this;\n        const viewports = [];\n        // renderstate.boundRendertarget.vrfbo = true;\n        for (let i = 0; i < views.length; i++) {\n            const view = views[i];\n            this.viewMatrices[i].fromArray(view.transform.inverse.matrix);\n            // Note: the stage matrix\n            this.viewMatrices[i].multiplyInPlace(this.invStageMatrix);\n            // this.cameraMatrices[i].fromArray(view.transform.matrix);\n            const vp = layer.getViewport(view);\n            viewports.push({\n                viewMatrix: this.viewMatrices[i],\n                projectionMatrix: this.projectionMatrices[i],\n                region: [vp.x, vp.y, vp.width, vp.height],\n                isOrthographic: 0,\n            });\n        }\n        this.viewXfo.setFromMat4(new Mat4(pose.transform.matrix));\n        renderstate.viewXfo = this.stageXfo.multiply(this.viewXfo);\n        renderstate.cameraMatrix = renderstate.viewXfo.toMat4();\n        renderstate.viewScale = this.stageScale;\n        renderstate.region = this.region;\n        renderstate.vrPresenting = true; // Some rendering is adjusted slightly in VR. e.g. Billboards\n        // ///////////////////////\n        // Binding\n        this.bindXRViewport(renderstate, viewports);\n        this.draw(renderstate);\n        {\n            // ///////////////////////\n            // Prepare the pointerMove event.\n            const event = new XRPoseEvent(this, this.viewXfo);\n            if (event.getCapture()) {\n                event.getCapture().onPointerMove(event);\n                // events are now always sent to the capture item first,\n                // but can continue propagating to other items if no call\n                // to event.stopPropagation() was made.\n            }\n            if (this.manipulator && event.propagating) {\n                this.manipulator.onPointerMove(event);\n            }\n        }\n        // ///////////////////////\n        // Emit a signal for the shared session.\n        const viewChangedEvent = new XRViewChangedEvent(renderstate.viewXfo);\n        // TODO: better solution than setting members individually?\n        viewChangedEvent.viewport = this;\n        viewChangedEvent.xrviewport = this;\n        this.emit('viewChanged', viewChangedEvent);\n        this.tick++;\n    }\n}\n\n/* eslint-disable guard-for-in */\n/** Class for managing all the GeomItems discovered in the SceneTree.\n * @private\n */\nclass GLGeomItemLibrary extends EventEmitter {\n    renderer;\n    // Note: item 0 is always null.\n    // The reduction shader reads pixel values, and assumes 0 is an empty pixel.\n    glGeomItems = [null];\n    glGeomItemEventHandlers = [];\n    glGeomItemsMap = new Map();\n    glGeomItemsIndexFreeList = [];\n    dirtyItemIndices = new Set();\n    // Items that have transform or bounding box changes and need to be updated in the worker.\n    dirtyWorkerItemIndices = new Set();\n    removedItemIndices = [];\n    glGeomItemsTexture = null;\n    enableFrustumCulling;\n    xrViewport;\n    xrPresenting = false;\n    xrFovY = 0.0;\n    xrProjectionMatrix = new Mat4();\n    // Occlusion Culling\n    enableOcclusionCulling;\n    debugOcclusionBuffer = false;\n    occlusionDataBuffer;\n    occlusionImage;\n    occlusionImageItem;\n    reductionDataBuffer;\n    reductionDataArray;\n    bbox;\n    reductionShader;\n    boundingBoxShader;\n    inFrustumIndicesCount = 0;\n    inFrustumDrawIdsBuffer;\n    abortController = null;\n    cameraMovementInProgress = false;\n    occlusionDataBufferSizeFactor = window.devicePixelRatio;\n    occlusionDataBufferSizeFactorXR = 2;\n    // Note: only one in 7x7 (49) pixels are rendered, so we only need to see a\n    // few of these pixels for the object to be considered very visible.\n    placeholderLoadThreshold = 5;\n    timer_query_ext = null;\n    worker;\n    /**\n     * Create a GLGeomItemLibrary.\n     * @param renderer - The renderer instance\n     * @param options - The options object passed to the GLRenderer constructor.\n     */\n    constructor(renderer, options) {\n        super();\n        this.renderer = renderer;\n        this.enableFrustumCulling = options.enableFrustumCulling || options.enableOcclusionCulling;\n        this.enableOcclusionCulling = options.enableOcclusionCulling;\n        this.debugOcclusionBuffer = renderer.getViewport().debugOcclusionBuffer;\n        if (this.enableFrustumCulling) {\n            this.setupCullingWorker(renderer);\n        }\n    }\n    /**\n     * Sets up the Culling Worker to start calculating frustum culling.\n     * @param renderer - The renderer instance\n     */\n    setupCullingWorker(renderer) {\n        this.worker = new WorkerFactory();\n        // This is a mock web worker to use when testing.\n        // this.worker = {\n        //   postMessage: (message) => {\n        //     handleMessage(message, (message) => {\n        //       this.worker.onmessage({data: message })\n        //     })\n        //   },\n        // }\n        let workerReady = false;\n        this.worker.postMessage({\n            type: 'Init',\n            enableOcclusionCulling: this.enableOcclusionCulling,\n            placeholderLoadThreshold: this.placeholderLoadThreshold,\n        });\n        this.worker.onmessage = (message) => {\n            if (message.data.type == 'WorkerReady') {\n                viewportChanged();\n                workerReady = true;\n            }\n            else if (message.data.type == 'InFrustumIndices') {\n                if (this.enableOcclusionCulling) {\n                    // First full the items that the frustum culling removed.\n                    if (message.data.newlyCulled) {\n                        this.applyCullResults(message.data);\n                    }\n                    this.calculateOcclusionCulling(message.data.inFrustumIndices);\n                }\n                else {\n                    this.applyCullResults(message.data);\n                    this.emitCullingUpdateData(message.data);\n                    workerReady = true;\n                }\n            }\n            else if (message.data.type == 'CullResults') {\n                this.applyCullResults(message.data);\n                this.emitCullingUpdateData(message.data);\n                workerReady = true;\n            }\n            else if (message.data.type == 'Done') {\n                // Used mostly to make our unit testing robust.\n                this.renderer.emit('CullingUpdated');\n            }\n            workerReady = true;\n        };\n        const viewportChanged = () => {\n            const viewport = renderer.getViewport();\n            const camera = renderer.getViewport().getCamera();\n            const aspectRatio = viewport.getWidth() / viewport.getHeight();\n            if (camera.isOrthographic()) {\n                const frustumHeight = camera.getFrustumHeight();\n                const frustumWidth = frustumHeight * aspectRatio;\n                this.worker.postMessage({\n                    type: 'ViewportChanged',\n                    frustumHeight,\n                    frustumWidth,\n                    isOrthographic: true,\n                    solidAngleLimit: renderer.solidAngleLimit,\n                });\n            }\n            else {\n                const frustumHalfAngleY = camera.getFov() * 0.5;\n                const frustumHalfAngleX = Math.atan(Math.tan(frustumHalfAngleY) * aspectRatio);\n                this.worker.postMessage({\n                    type: 'ViewportChanged',\n                    frustumHalfAngleX,\n                    frustumHalfAngleY,\n                    isOrthographic: false,\n                    solidAngleLimit: renderer.solidAngleLimit,\n                });\n            }\n        };\n        renderer.on('resized', viewportChanged);\n        const camera = renderer.getViewport().getCamera();\n        camera.on('projectionParamChanged', (event) => {\n            if (camera.isOrthographic()) {\n                viewportChanged();\n            }\n        });\n        renderer.once('xrViewportSetup', (event) => {\n            this.xrViewport = event.xrViewport;\n            const xrvp = event.xrViewport;\n            xrvp.on('presentingChanged', (event) => {\n                this.xrPresenting = event.state;\n                if (event.state) {\n                    cullFreq = 10;\n                    let frustumHalfAngleX;\n                    let frustumHalfAngleY;\n                    if (xrvp instanceof VRViewport) {\n                        // Note: We approximate the culling viewport to be\n                        // a wider version of the 2 eye frustums merged together.\n                        // Wider, so that items are considered visible before the are in view.\n                        // Note each VR headset comes with its own FOV, and I can't seem to be\n                        // able to get it from the WebXR API, so I am putting in some guesses\n                        // based on this diagram: https://blog.mozvr.com/content/images/2016/02/human-visual-field.jpg\n                        frustumHalfAngleX = MathFunctions.degToRad(62);\n                        frustumHalfAngleY = MathFunctions.degToRad(50);\n                    }\n                    else if (xrvp instanceof ARViewport) {\n                        // TODO: determine the frustum size for a phone.\n                        const aspectRatio = xrvp.getWidth() / xrvp.getHeight();\n                        frustumHalfAngleY = 62 * MathFunctions.degToRad(0.5);\n                        frustumHalfAngleX = Math.atan(Math.tan(frustumHalfAngleY) * aspectRatio);\n                    }\n                    this.xrFovY = frustumHalfAngleY * 2.0;\n                    const aspect = frustumHalfAngleY / frustumHalfAngleX;\n                    // @ts-ignore\n                    const near = xrvp.depthRange[0];\n                    // @ts-ignore\n                    const far = xrvp.depthRange[1];\n                    this.xrProjectionMatrix.setPerspectiveMatrix(this.xrFovY, aspect, near, far);\n                    this.worker.postMessage({\n                        type: 'ViewportChanged',\n                        frustumHalfAngleX,\n                        frustumHalfAngleY,\n                        isOrthographic: false,\n                        solidAngleLimit: renderer.solidAngleLimit * 4,\n                    });\n                    this.occlusionDataBuffer.resize(Math.ceil(xrvp.getWidth() / this.occlusionDataBufferSizeFactorXR), Math.ceil(xrvp.getWidth() / this.occlusionDataBufferSizeFactorXR));\n                }\n                else {\n                    cullFreq = 5;\n                    viewportChanged();\n                    // push the camera xfo to the worker.\n                    forceViewChanged();\n                }\n            });\n        });\n        let tick = 0;\n        let cullFreq = 5;\n        renderer.on('viewChanged', (event) => {\n            this.cameraMovementInProgress = true;\n            // Calculate culling every Nth frame.\n            if (workerReady) {\n                if (tick % cullFreq == 0) {\n                    workerReady = false;\n                    const pos = event.viewXfo.tr;\n                    const ori = event.viewXfo.ori;\n                    this.worker.postMessage({\n                        type: 'ViewChanged',\n                        cameraPos: pos.asArray(),\n                        cameraOri: ori.asArray(),\n                        solidAngleLimit: renderer.solidAngleLimit,\n                    });\n                }\n                tick++;\n            }\n        });\n        const forceViewChanged = () => {\n            this.cameraMovementInProgress = false;\n            const camera = renderer.getViewport().getCamera();\n            const viewXfo = camera.globalXfoParam.value;\n            const pos = viewXfo.tr;\n            const ori = viewXfo.ori;\n            this.worker.postMessage({\n                type: 'ViewChanged',\n                cameraPos: pos.asArray(),\n                cameraOri: ori.asArray(),\n                solidAngleLimit: renderer.solidAngleLimit,\n            });\n        };\n        // If a movement finishes, we should update the culling results\n        // based on the last position. (we might have skipped it in the viewChanged handler above)\n        renderer.getViewport().getCamera().on('movementFinished', forceViewChanged);\n        // Initialize the view values on the worker.\n        forceViewChanged();\n        {\n            // ////////////////////////////////////////\n            // Occlusion Culling\n            if (this.enableOcclusionCulling) {\n                const gl = this.renderer.gl;\n                // https://www.khronos.org/registry/webgl/extensions/EXT_disjoint_timer_query_webgl2/\n                // this.timer_query_ext = gl.getExtension('EXT_disjoint_timer_query_webgl2')\n                const occlusionDataBufferWidth = Math.ceil(this.renderer.getWidth() / this.occlusionDataBufferSizeFactor);\n                const occlusionDataBufferHeight = Math.ceil(this.renderer.getHeight() / this.occlusionDataBufferSizeFactor);\n                this.occlusionDataBuffer = new GLRenderTarget(gl, {\n                    type: gl.FLOAT,\n                    format: gl.RGBA,\n                    minFilter: gl.NEAREST,\n                    magFilter: gl.NEAREST,\n                    width: occlusionDataBufferWidth,\n                    height: occlusionDataBufferHeight,\n                    depthType: gl.UNSIGNED_INT,\n                    depthFormat: gl.DEPTH_COMPONENT,\n                    depthInternalFormat: gl.DEPTH_COMPONENT24,\n                });\n                // this.occlusionDataBuffer.clearColor.set(0.1, 0, 0, 1)\n                this.renderer.on('resized', (event) => {\n                    if (!this.xrPresenting) {\n                        this.occlusionDataBuffer.resize(Math.ceil(event.width / this.occlusionDataBufferSizeFactor), Math.ceil(event.height / this.occlusionDataBufferSizeFactor));\n                    }\n                });\n                this.reductionDataBuffer = new GLRenderTarget(gl, {\n                    type: gl.UNSIGNED_BYTE,\n                    format: gl.RG,\n                    internalFormat: gl.RG8,\n                    minFilter: gl.NEAREST,\n                    magFilter: gl.NEAREST,\n                    width: 1,\n                    height: 1,\n                });\n                this.bbox = new GLLines(gl, new BBoxOcclusionLinesCuboid());\n                this.reductionShader = new ReductionShader(gl);\n                this.boundingBoxShader = new BoundingBoxShader(gl);\n                this.boundingBoxShader.compileForTarget('GLGeomItemLibrary', this.renderer.directives);\n                this.inFrustumIndicesCount = 0;\n            }\n        }\n    }\n    /**\n     * Handles applying the culling results received from the GLGeomItemLibraryCullingWorker\n     * @param {object} data - The object containing the newlyCulled and newlyUnCulled results.\n     */\n    applyCullResults(data) {\n        if (data.newlyCulled) {\n            data.newlyCulled.forEach((index) => {\n                const glGeomItem = this.glGeomItems[index];\n                if (glGeomItem)\n                    glGeomItem.setCulled(true);\n            });\n        }\n        if (data.newlyUnCulled) {\n            data.newlyUnCulled.forEach((index) => {\n                const glGeomItem = this.glGeomItems[index];\n                if (glGeomItem)\n                    glGeomItem.setCulled(false);\n            });\n        }\n        if (data.visiblePlaceholders && data.visiblePlaceholders.length > 0 && !this.cameraMovementInProgress) {\n            data.visiblePlaceholders.forEach((data) => {\n                const geomItem = this.glGeomItems[data.index]?.geomItem;\n                if (geomItem instanceof PlaceholderGeomItem && !geomItem.loading) {\n                    geomItem.load();\n                }\n            });\n        }\n        this.renderer.requestRedraw();\n    }\n    emitCullingUpdateData(data) {\n        // Used mostly to make our unit testing robust.\n        // Also to help display render stats.\n        // console.log(`visible: ${data.visible} / total: ${data.total}`)\n        this.renderer.emit('CullingUpdated', {\n            culled: data.newlyCulled?.length,\n            unCulled: data.newlyUnCulled?.length,\n            visible: data.visible,\n            total: data.total,\n            visibleGeomStats: data.visibleGeomStats,\n            totalGeomStats: data.totalGeomStats,\n        });\n    }\n    /**\n     * Given the IDs of the items we know are in the frustum, setup an instanced attribute we can use\n     * to render bounding boxes for these items if they do not show up in the initial GPU buffer.\n     * @param {Float32Array} inFrustumIndices - The array of indices of items we know are in the frustum.\n     */\n    updateCulledDrawIDsBuffer(inFrustumIndices) {\n        const gl = this.renderer.gl;\n        if (!gl.floatTexturesSupported) {\n            return;\n        }\n        if (this.inFrustumDrawIdsBuffer && this.inFrustumIndicesCount != inFrustumIndices.length) {\n            gl.deleteBuffer(this.inFrustumDrawIdsBuffer);\n            this.inFrustumDrawIdsBuffer = null;\n        }\n        if (!this.inFrustumDrawIdsBuffer) {\n            this.inFrustumDrawIdsBuffer = gl.createBuffer();\n            gl.bindBuffer(gl.ARRAY_BUFFER, this.inFrustumDrawIdsBuffer);\n        }\n        gl.bindBuffer(gl.ARRAY_BUFFER, this.inFrustumDrawIdsBuffer);\n        gl.bufferData(gl.ARRAY_BUFFER, inFrustumIndices, gl.STATIC_DRAW);\n        this.inFrustumIndicesCount = inFrustumIndices.length;\n        // Note: we get errors trying to read data back from images less than 4x4 pixels.\n        const size = Math.max(4, MathFunctions.nextPow2(Math.round(Math.sqrt(this.glGeomItems.length) + 0.5)));\n        if (this.reductionDataBuffer.width != size) {\n            this.reductionDataBuffer.resize(size, size);\n            this.reductionDataArray = new Uint8Array(size * size * 2);\n        }\n    }\n    /**\n     * Calculate a further refinement of the culling by using the GPU to see which items are actually visible.\n     * @param inFrustumIndices - The array of indices of items we know are in the frustum.\n     */\n    calculateOcclusionCulling(inFrustumIndices) {\n        if (inFrustumIndices && inFrustumIndices.length > 0) {\n            this.updateCulledDrawIDsBuffer(inFrustumIndices);\n        }\n        // Cancel any running culling as it is already out of date.\n        if (this.abortController) {\n            this.abortController.abort();\n        }\n        this.abortController = new AbortController();\n        if (this.inFrustumIndicesCount == 0) {\n            return;\n        }\n        const gl = this.renderer.gl;\n        const renderstate = new GeomDataRenderState(gl);\n        renderstate.pushGLStack('calculateOcclusionCulling');\n        this.renderer.bindGLRenderer(renderstate);\n        renderstate.directives = [...this.renderer.directives, '#define DRAW_GEOMDATA'];\n        renderstate.floatGeomBuffer = true;\n        renderstate.occlusionCulling = 1;\n        if (this.xrPresenting) {\n            this.xrViewport.bindCullingViewport(renderstate, this.xrFovY, this.xrProjectionMatrix);\n        }\n        else {\n            this.renderer.getViewport().bindGLViewport(renderstate);\n        }\n        // this.renderer.drawSceneGeomData(renderstate)\n        const drawSceneGeomData = (renderstate) => {\n            this.occlusionDataBuffer.bindForWriting(renderstate, true);\n            renderstate.glDisable(gl.BLEND);\n            renderstate.glDisable(gl.CULL_FACE);\n            renderstate.glEnable(gl.DEPTH_TEST);\n            gl.depthFunc(gl.LESS);\n            gl.depthMask(true);\n            // For now, just rendering the main opaque geoms.\n            const opaqueGeomsPass = this.renderer.getPass(0);\n            opaqueGeomsPass.drawGeomData(renderstate);\n            const linesPass = this.renderer.getPass(1);\n            linesPass.drawGeomData(renderstate);\n            // for (const key in this.__passes) {\n            //   // Skip pass categories that do not match\n            //   // the mask. E.g. we may not want to hit\n            //   // \"Overlay\" geoms such as labels,\n            //   // or we might be trying to move labels and don't\n            //   // want to grab normal geoms.\n            //   if ((Number.parseInt(key) & mask) == 0) continue\n            //   const passSet = this.__passes[key]\n            //   for (const pass of passSet) {\n            //     if (pass.enabled) pass.drawGeomData(renderstate)\n            //   }\n            // }\n            this.occlusionDataBuffer.unbindForWriting(renderstate);\n        };\n        // Draw one point for each pixel in the occlusion buffer.\n        // This point will color a single pixel in the reduction buffer.\n        const numReductionPoints = this.occlusionDataBuffer.width * this.occlusionDataBuffer.height;\n        const ext = this.timer_query_ext;\n        // Now perform a reduction to calculate the indices of visible items.\n        const reduce = (renderstate, clear, query) => {\n            this.reductionDataBuffer.bindForWriting(renderstate, clear);\n            // The second time we reduce into the reductionDataBuffer, we want to\n            // keep the values that were already there. The first reduction counted\n            // the items visible after the scene was drawn. The second one adds items\n            // visible due to the bounding boxes being visible.\n            gl.enable(gl.BLEND);\n            gl.blendEquation(gl.FUNC_ADD);\n            gl.blendFunc(gl.ONE, gl.ONE);\n            this.reductionShader.bind(renderstate);\n            const { geomDataTexture, reductionTextureWidth } = renderstate.unifs;\n            if (geomDataTexture)\n                this.occlusionDataBuffer.bindToUniform(renderstate, geomDataTexture);\n            if (reductionTextureWidth)\n                gl.uniform1i(reductionTextureWidth.location, this.reductionDataBuffer.width);\n            if (ext)\n                gl.beginQuery(ext.TIME_ELAPSED_EXT, query);\n            gl.drawArrays(gl.POINTS, 0, numReductionPoints);\n            if (ext)\n                gl.endQuery(ext.TIME_ELAPSED_EXT);\n            gl.disable(gl.BLEND);\n            this.reductionDataBuffer.unbindForWriting(renderstate);\n        };\n        const drawCulledBBoxes = () => {\n            this.occlusionDataBuffer.bindForWriting(renderstate, false);\n            // Now clear the color buffer, but not the depth buffer\n            // and draw the bounding boxes of occluded items.\n            // This means the second reduction only count fragments\n            // rasterized by the bounding boxes, and not the initial\n            // scene geometry.(which was counted in the first reduce)\n            // Note: disable this code to see the full occlusion buffer in debugging.\n            if (!this.debugOcclusionBuffer) {\n                gl.colorMask(true, true, true, true);\n                gl.clearColor(0, 0, 0, 0);\n                gl.clear(gl.COLOR_BUFFER_BIT); // do _not_ clear depth.\n            }\n            this.boundingBoxShader.bind(renderstate, 'GLGeomItemLibrary');\n            this.bbox.bind(renderstate);\n            // Read each Matrix and Bbox settings from the Texture.\n            const { instancesTexture, instancesTextureSize, instancedDraw, reductionDataTexture, occlusionCulling } = renderstate.unifs;\n            this.glGeomItemsTexture.bindToUniform(renderstate, instancesTexture);\n            gl.uniform1i(instancesTextureSize.location, this.glGeomItemsTexture.width);\n            gl.uniform1i(instancedDraw.location, 1);\n            this.reductionDataBuffer.bindColorTexture(renderstate, reductionDataTexture);\n            // The instanced transform ids are bound as an instanced attribute.\n            const location = renderstate.attrs.instancedIds.location;\n            gl.enableVertexAttribArray(location);\n            gl.bindBuffer(gl.ARRAY_BUFFER, this.inFrustumDrawIdsBuffer);\n            gl.vertexAttribPointer(location, 1, gl.FLOAT, false, 1 * 4, 0);\n            gl.vertexAttribDivisor(location, 1); // This makes it instanced\n            // Now draw all the bounding boxes to make sure we catch anything.\n            // Note: If the geometry is listed visibility buffer, we skip it.\n            // Do this draws only the bounding boxes for non-visible geometries.\n            renderstate.bindViewports(renderstate.unifs, () => {\n                this.bbox.drawInstanced(renderstate, this.inFrustumIndicesCount);\n            });\n            this.occlusionDataBuffer.unbindForWriting(renderstate);\n        };\n        let queryDrawScene;\n        let queryReduceSceneGeoms;\n        let queryDrawCulledBBoxes;\n        let queryReduceBBoxes;\n        if (ext) {\n            queryDrawScene = gl.createQuery();\n            gl.beginQuery(ext.TIME_ELAPSED_EXT, queryDrawScene);\n        }\n        drawSceneGeomData(renderstate);\n        if (ext)\n            gl.endQuery(ext.TIME_ELAPSED_EXT);\n        // We render the scene geometry, reduce, then render\n        // the boxes, reduce again. The bounding boxes displayed\n        // are based on the results of the first reduce.\n        if (ext)\n            queryReduceSceneGeoms = gl.createQuery();\n        reduce(renderstate, true, queryReduceSceneGeoms);\n        // /////////////////////////\n        //\n        if (ext) {\n            queryDrawCulledBBoxes = gl.createQuery();\n            gl.beginQuery(ext.TIME_ELAPSED_EXT, queryDrawCulledBBoxes);\n        }\n        drawCulledBBoxes();\n        if (ext)\n            gl.endQuery(ext.TIME_ELAPSED_EXT);\n        // /////////////////////////\n        if (ext)\n            queryReduceBBoxes = gl.createQuery();\n        reduce(renderstate, false, queryReduceBBoxes);\n        // All rendering is done.\n        renderstate.popGLStack();\n        const queryResults = {\n            numReductionPoints,\n        };\n        const checkQuery = (name, query) => {\n            const available = gl.getQueryParameter(query, gl.QUERY_RESULT_AVAILABLE);\n            const disjoint = gl.getParameter(ext.GPU_DISJOINT_EXT);\n            if (available && !disjoint) {\n                // See how much time the rendering of the object took in nanoseconds.\n                const timeElapsed = gl.getQueryParameter(query, gl.QUERY_RESULT);\n                queryResults[name] = timeElapsed / 1000000;\n                // Clean up the query object.\n                gl.deleteQuery(query);\n            }\n        };\n        // //////////////////////////////////////////\n        // Pull down the reduction values from the GPU for processing.\n        const w = this.reductionDataBuffer.width;\n        const h = this.reductionDataBuffer.height;\n        const format = gl.RG;\n        const type = gl.UNSIGNED_BYTE;\n        this.reductionDataBuffer.bindForReading();\n        const abortController = this.abortController;\n        readPixelsAsync(gl, 0, 0, w, h, format, type, this.reductionDataArray, abortController).then(() => {\n            this.reductionDataBuffer.unbindForReading();\n            if (abortController.__abort) {\n                // The readpixels was aborted.\n                // This can happen if the new data is loaded before the readpixels is done.\n                return;\n            }\n            if (ext) {\n                checkQuery('queryDrawScene', queryDrawScene);\n                checkQuery('queryDrawCulledBBoxes', queryDrawCulledBBoxes);\n                checkQuery('queryReduceSceneGeoms', queryReduceSceneGeoms);\n                checkQuery('queryReduceBBoxes', queryReduceBBoxes);\n                this.renderer.emit('occlusionCullingProfilingData', queryResults);\n            }\n            // console.log(this.reductionDataArray)\n            // Now send the buffer to the worker, where it will determine what culling\n            // needs to be applied on top of the frustum culling.\n            this.worker.postMessage({\n                type: 'OcclusionData',\n                reductionDataArray: this.reductionDataArray,\n            });\n            this.abortController = null;\n        });\n    }\n    /**\n     * The addGeomItem method.\n     * @param geomItem - The geomItem value.\n     * @return - The index of GLGeomItem\n     */\n    addGeomItem(geomItem) {\n        let index = this.glGeomItemsMap.get(geomItem);\n        if (index != undefined) {\n            // Increment the ref count for the GLGeom\n            return this.glGeomItems[index];\n        }\n        // Use recycled indices if there are any available...\n        if (this.glGeomItemsIndexFreeList.length > 0) {\n            index = this.glGeomItemsIndexFreeList.pop();\n        }\n        else {\n            index = this.glGeomItems.length;\n            this.glGeomItems.push(null);\n        }\n        // If an item is removed and re-added immediately, we avoid removing the item from the culling worker.\n        if (this.removedItemIndices.includes(index)) {\n            this.removedItemIndices.splice(this.removedItemIndices.indexOf(index), 1);\n        }\n        this.dirtyItemIndices.add(index);\n        // ///////////////////////////////////////////\n        // Material\n        const materialParam = geomItem.materialParam;\n        let material = materialParam.value;\n        // Add the material here so that when we populate the GeomItem texture.\n        // the material already has an Id.\n        const matIndex = this.renderer.glMaterialLibrary.addMaterial(material);\n        const materialChanged = () => {\n            // Ref count the materials in the material library.\n            this.renderer.glMaterialLibrary.removeMaterial(material);\n            material = materialParam.value;\n            if (material) {\n                glGeomItem.materialId = this.renderer.glMaterialLibrary.addMaterial(material);\n            }\n            else {\n                glGeomItem.materialId = -1;\n            }\n            workerItemDataChanged();\n            geomItemChanged();\n        };\n        materialParam.on('valueChanged', materialChanged);\n        // ///////////////////////////////////////////\n        // GeomItem\n        const gl = this.renderer.gl;\n        const supportInstancing = material.getShaderClass().supportsInstancing();\n        const geomIndex = -1;\n        const glGeomItem = new GLGeomItem(gl, geomItem, index, geomIndex, matIndex, supportInstancing);\n        const geomItemChanged = () => {\n            if (this.dirtyItemIndices.has(index))\n                return;\n            this.dirtyItemIndices.add(index);\n            const invalidateGeomDataBuffer = geomItem.isPickable();\n            this.renderer.drawItemChanged(invalidateGeomDataBuffer);\n        };\n        geomItem.geomMatParam.on('valueChanged', geomItemChanged);\n        geomItem.on('cutAwayChanged', geomItemChanged);\n        geomItem.on('highlightChanged', geomItemChanged);\n        geomItem.on('selectabilityChanged', geomItemChanged);\n        geomItem.on('opacityChanged', geomItemChanged);\n        geomItem.on('pickabilityChanged', geomItemChanged);\n        const workerItemDataChanged = () => {\n            if (this.enableFrustumCulling) {\n                if (!this.dirtyWorkerItemIndices.has(index)) {\n                    this.dirtyWorkerItemIndices.add(index);\n                    const invalidateGeomDataBuffer = geomItem.isPickable();\n                    this.renderer.drawItemChanged(invalidateGeomDataBuffer);\n                }\n            }\n        };\n        if (this.enableFrustumCulling) {\n            this.dirtyWorkerItemIndices.add(index);\n        }\n        geomItem.on('visibilityChanged', workerItemDataChanged);\n        geomItem.on('opacityChanged', workerItemDataChanged);\n        geomItem.geomMatParam.on('valueChanged', workerItemDataChanged);\n        geomItem.geomParam.on('boundingBoxChanged', workerItemDataChanged);\n        this.glGeomItems[index] = glGeomItem;\n        this.glGeomItemEventHandlers[index] = {\n            geomItemChanged,\n            materialChanged,\n            workerItemDataChanged,\n        };\n        this.glGeomItemsMap.set(geomItem, index);\n        // Note: before the renderer is disabled, this is a  no-op.\n        this.renderer.requestRedraw();\n        return glGeomItem;\n    }\n    /**\n     * The removeGeomItem method.\n     * @param geomItem - The geomItem value.\n     * @return - The return value.\n     */\n    removeGeomItem(geomItem) {\n        const index = this.glGeomItemsMap.get(geomItem);\n        // This GeomItem may not yet have been added to the Renderer.\n        // This may be because it is part of an asset that is still loading\n        // and has not yet received its geometry.\n        if (index == undefined)\n            return null;\n        const glGeomItem = this.glGeomItems[index];\n        const material = geomItem.materialParam.value;\n        this.renderer.glMaterialLibrary.removeMaterial(material);\n        const handlers = this.glGeomItemEventHandlers[index];\n        const materialParam = geomItem.materialParam;\n        materialParam.off('valueChanged', handlers.materialChanged);\n        geomItem.geomMatParam.off('valueChanged', handlers.geomItemChanged);\n        geomItem.off('cutAwayChanged', handlers.geomItemChanged);\n        geomItem.off('highlightChanged', handlers.geomItemChanged);\n        geomItem.off('selectabilityChanged', handlers.geomItemChanged);\n        // material.off('opacityChanged', handlers.geomItemChanged)\n        geomItem.off('opacityChanged', handlers.geomItemChanged);\n        geomItem.off('pickabilityChanged', handlers.geomItemChanged);\n        geomItem.off('visibilityChanged', handlers.workerItemDataChanged);\n        geomItem.geomMatParam.off('valueChanged', handlers.workerItemDataChanged);\n        geomItem.off('opacityChanged', handlers.workerItemDataChanged);\n        geomItem.geomParam.off('boundingBoxChanged', handlers.workerItemDataChanged);\n        this.glGeomItems[index] = null;\n        this.glGeomItemEventHandlers[index] = null;\n        this.glGeomItemsIndexFreeList.push(index);\n        this.glGeomItemsMap.delete(geomItem);\n        this.removedItemIndices.push(index);\n        if (this.dirtyWorkerItemIndices.has(index)) {\n            this.dirtyWorkerItemIndices.delete(index);\n        }\n        this.renderer.requestRedraw();\n        return glGeomItem;\n    }\n    /**\n     * The getGeomItem method.\n     * @param index - The index value.\n     * @return - The GLGeomItem that wraps the provided GeomItem\n     */\n    getGeomItem(index) {\n        if (index >= this.glGeomItems.length) {\n            console.warn('Invalid Draw Item id:' + index + ' NumItems:' + (this.glGeomItems.length - 1));\n            return undefined;\n        }\n        return this.glGeomItems[index]?.geomItem;\n    }\n    /**\n     * The getGeomItem method.\n     * @param geomItem - The geomItem value.\n     * @return - The GLGeomItem that wraps the provided GeomItem\n     */\n    getGLGeomItem(geomItem) {\n        const index = this.glGeomItemsMap.get(geomItem);\n        if (index != undefined) {\n            // Increment the ref count for the GLGeom\n            return this.glGeomItems[index];\n        }\n        return null;\n    }\n    // ////////////////////////////////////////////////\n    // Data Uploading\n    /**\n     * The populateDrawItemDataArray method.\n     * @param index - The index of the item in the library.\n     * @param subIndex - The index of the item within the block being uploaded.\n     * @param dataArray - The dataArray value.\n     * @private\n     */\n    populateDrawItemDataArray(index, subIndex, dataArray) {\n        const glGeomItem = this.glGeomItems[index];\n        // When an item is deleted, we allocate its index to the free list\n        // and null this item in the array. skip over null items.\n        if (!glGeomItem)\n            return;\n        const { geomItem, geomId } = glGeomItem;\n        const material = geomItem.materialParam.value;\n        const stride = pixelsPerItem$1 * 4; // The number of floats per draw item.\n        const offset = subIndex * stride;\n        // /////////////////////////\n        // Geom Item Params\n        let flags = 0;\n        if (geomItem.isCutawayEnabled()) {\n            flags |= GLGeomItemFlags.GEOMITEM_FLAG_CUTAWAY;\n        }\n        if (!geomItem.isPickable()) {\n            flags |= GLGeomItemFlags.GEOMITEM_INVISIBLE_IN_GEOMDATA;\n        }\n        if (!material.isOpaque() || !geomItem.isOpaque()) {\n            flags |= GLGeomItemFlags.GEOMITEM_TRANSPARENT;\n        }\n        const pix0 = new Float32Array(dataArray.buffer, (offset + 0) * 4, 4);\n        pix0[0] = flags;\n        pix0[1] = geomItem.opacity;\n        const allocation = this.renderer.glMaterialLibrary.getMaterialAllocation(material);\n        if (allocation) {\n            pix0[2] = allocation.start;\n        }\n        // Store the geomId for debugging purposes.\n        // see: DEBUG_GEOM_ID\n        pix0[4] = geomId;\n        // /////////////////////////\n        // Geom Matrix\n        const mat4 = geomItem.geomMatParam.value;\n        const pix1 = new Float32Array(dataArray.buffer, (offset + 1 * 4) * 4, 4);\n        const pix2 = new Float32Array(dataArray.buffer, (offset + 2 * 4) * 4, 4);\n        const pix3 = new Float32Array(dataArray.buffer, (offset + 3 * 4) * 4, 4);\n        pix1.set([mat4.xAxis.x, mat4.yAxis.x, mat4.zAxis.x, mat4.translation.x]);\n        pix2.set([mat4.xAxis.y, mat4.yAxis.y, mat4.zAxis.y, mat4.translation.y]);\n        pix3.set([mat4.xAxis.z, mat4.yAxis.z, mat4.zAxis.z, mat4.translation.z]);\n        // /////////////////////////\n        // Highlight\n        const pix4 = new Float32Array(dataArray.buffer, (offset + 4 * 4) * 4, 4);\n        if (geomItem.isHighlighted()) {\n            const highlight = geomItem.getHighlight();\n            pix4.set([highlight.r, highlight.g, highlight.b, highlight.a]);\n        }\n        // /////////////////////////\n        // Cutaway\n        const pix5 = new Float32Array(dataArray.buffer, (offset + 5 * 4) * 4, 4);\n        if (geomItem.isCutawayEnabled()) {\n            const cutAwayVector = geomItem.getCutVector();\n            const cutAwayDist = geomItem.getCutDist();\n            // console.log(geomItem.getName(), geomItem.isCutawayEnabled(), flags, pix0.toString())\n            pix5.set([cutAwayVector.x, cutAwayVector.y, cutAwayVector.z, cutAwayDist]);\n        }\n        // /////////////////////////\n        // Bounding Box\n        const bbox = geomItem.boundingBoxParam.value;\n        const pix6 = new Float32Array(dataArray.buffer, (offset + 6 * 4) * 4);\n        const pix7 = new Float32Array(dataArray.buffer, (offset + 7 * 4) * 4);\n        pix6.set([bbox.p0.x, bbox.p0.y, bbox.p0.z, 0.0]);\n        pix7.set([bbox.p1.x, bbox.p1.y, bbox.p1.z, 0.0]);\n    }\n    /**\n     * Gathers data to pass to the culling worker.\n     * @param geomItem - The GeomItem to gether the data for.\n     * @param material - The material of GeomItem.\n     * @param index - The index of the item to gether the data for.\n     * @return - the JSON data that will be passed to the worker.\n     */\n    getCullingWorkerData(geomItem, index) {\n        const bbox = geomItem.boundingBoxParam.value;\n        const boundingRadius = bbox.size() * 0.5;\n        const pos = bbox.center();\n        const material = geomItem.materialParam.value;\n        // Some items can't be culled. They should be flagged as overlay or not cullable\n        const cullable = geomItem.cullable && !geomItem.isOverlay() && !material.getShaderClass().isOverlay();\n        const transparent = !geomItem.isOpaque() || !material.isOpaque();\n        const isPlaceholder = geomItem instanceof PlaceholderGeomItem;\n        const geomStats = {\n            triangles: 0,\n            lines: 0,\n            points: 0,\n        };\n        const geom = geomItem.geomParam.value;\n        if (geom instanceof CompoundGeom) {\n            geomStats.triangles += geom.getNumTriangles();\n            geomStats.lines += geom.getNumLineSegments();\n            geomStats.points += geom.getNumPoints();\n        }\n        else if (geom instanceof Mesh || geom instanceof MeshProxy) {\n            geomStats.triangles += geom.getNumTriangles();\n        }\n        else if (geom instanceof Lines || geom instanceof LinesProxy) {\n            geomStats.lines += geom.getNumLineSegments();\n        }\n        else if (geom instanceof Points || geom instanceof PointsProxy) {\n            geomStats.points += geom.getNumVertices();\n        }\n        else {\n            throw new Error('Unsupported geom type:' + geom.constructor.name);\n        }\n        return {\n            id: index,\n            boundingRadius,\n            pos: pos.asArray(),\n            cullable,\n            visible: geomItem.isVisible(),\n            transparent,\n            isPlaceholder,\n            geomStats,\n        };\n    }\n    /**\n     * Any items that need to be updated on the worker are now pushed.\n     */\n    uploadGeomItemsToWorker() {\n        if (this.enableFrustumCulling) {\n            const geomItemsUpdateToCullingWorker = [];\n            this.dirtyWorkerItemIndices.forEach((index) => {\n                const glGeomItem = this.glGeomItems[index];\n                // When an item is deleted, we allocate its index to the free list\n                // and null this item in the array. skip over null items.\n                if (!glGeomItem)\n                    return;\n                const { geomItem } = glGeomItem;\n                const data = this.getCullingWorkerData(geomItem, index);\n                if (data)\n                    geomItemsUpdateToCullingWorker.push(data);\n            });\n            // /////////////////////////\n            // Update the culling worker\n            this.worker.postMessage({\n                type: 'UpdateGeomItems',\n                geomItems: geomItemsUpdateToCullingWorker,\n                removedItemIndices: this.removedItemIndices,\n            });\n            this.dirtyWorkerItemIndices.clear();\n            this.removedItemIndices = [];\n        }\n    }\n    /**\n     * The uploadGeomItems method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    uploadGeomItems(renderstate) {\n        const gl = this.renderer.gl;\n        if (!gl.floatTexturesSupported) {\n            return;\n        }\n        let size = Math.round(Math.sqrt(this.glGeomItems.length * pixelsPerItem$1) + 0.5);\n        // Only support power 2 textures. Else we get strange corruption on some GPUs\n        // in some scenes.\n        size = MathFunctions.nextPow2(size);\n        // Size should be a multiple of pixelsPerItem, so each geom item is always contiguous\n        // in memory. (makes updating a lot easier. See __updateItemInstanceData below)\n        if (size % pixelsPerItem$1 != 0)\n            size += pixelsPerItem$1 - (size % pixelsPerItem$1);\n        if (!this.glGeomItemsTexture) {\n            this.glGeomItemsTexture = new GLTexture2D(gl, {\n                format: 'RGBA',\n                type: 'FLOAT',\n                width: size,\n                height: size,\n                filter: 'NEAREST',\n                wrap: 'CLAMP_TO_EDGE',\n                mipMapped: false,\n            });\n            this.glGeomItemsTexture.clear();\n        }\n        else if (this.glGeomItemsTexture.width != size) {\n            this.glGeomItemsTexture.resize(size, size);\n            this.dirtyItemIndices = new Set(Array((size * size) / pixelsPerItem$1)\n                .fill(0) // TODO: check, is 0 ok as an argument here?\n                .map((v, i) => i));\n        }\n        gl.bindTexture(gl.TEXTURE_2D, this.glGeomItemsTexture.glTex);\n        const typeId = this.glGeomItemsTexture.type;\n        const dirtyItemIndices = Array.from(this.dirtyItemIndices);\n        for (let i = 0; i < dirtyItemIndices.length; i++) {\n            const indexStart = dirtyItemIndices[i];\n            const yoffset = Math.floor((indexStart * pixelsPerItem$1) / size);\n            let indexEnd = indexStart + 1;\n            for (let j = i + 1; j < dirtyItemIndices.length; j++) {\n                const index = dirtyItemIndices[j];\n                if (Math.floor((index * pixelsPerItem$1) / size) != yoffset) {\n                    break;\n                }\n                if (index != indexEnd) {\n                    break;\n                }\n                indexEnd++;\n            }\n            // TODO: for contiguous blocks, we create larger arrays and populate\n            // and upload them in one step.\n            const uploadCount = indexEnd - indexStart;\n            const xoffset = (indexStart * pixelsPerItem$1) % size;\n            const width = pixelsPerItem$1 * uploadCount;\n            const height = 1;\n            const dataArray = new Float32Array(pixelsPerItem$1 * 4 * uploadCount); // 4==RGBA pixels.\n            for (let j = indexStart; j < indexEnd; j++) {\n                this.populateDrawItemDataArray(j, j - indexStart, dataArray);\n            }\n            if (typeId == gl.FLOAT) {\n                this.glGeomItemsTexture.populate(dataArray, width, height, xoffset, yoffset, false);\n            }\n            else {\n                const unit16s = MathFunctions.convertFloat32ArrayToUInt16Array(dataArray);\n                this.glGeomItemsTexture.populate(unit16s, width, height, xoffset, yoffset, false);\n            }\n            i += uploadCount - 1;\n        }\n        this.removedItemIndices = [];\n        this.dirtyItemIndices = new Set();\n    }\n    /**\n     * Updates the GPU state if any update is needed.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    bind(renderstate) {\n        if (this.dirtyWorkerItemIndices.size > 0 || this.removedItemIndices.length > 0) {\n            this.uploadGeomItemsToWorker();\n        }\n        if (this.dirtyItemIndices.size > 0) {\n            this.uploadGeomItems(renderstate);\n        }\n        const gl = this.renderer.gl;\n        const { instancesTexture, instancesTextureSize } = renderstate.unifs;\n        if (instancesTexture) {\n            this.glGeomItemsTexture.bindToUniform(renderstate, instancesTexture);\n            gl.uniform1i(instancesTextureSize.location, this.glGeomItemsTexture.width);\n        }\n    }\n}\n\nvar frag$f = \"\\nprecision highp float;\\n#define GLSLIFY 1\\n\\nuniform float outlineThickness;\\nuniform sampler2D highlightDataTexture;\\n\\nvarying vec2 v_texCoord;\\n\\nfloat M_PI = 3.141592653589793;\\nfloat diff(vec4 pixelA, vec4 pixelB)\\n{\\n  return abs(pixelA.r - pixelB.r) + abs(pixelA.g - pixelB.g) + abs(pixelA.b - pixelB.b) + abs(pixelA.a - pixelB.a);\\n}\\n\\n// find the first pixel which is not the same as the center pixel.\\nvec4 RadialSearch(vec2 uv)\\n{\\n  vec2 texSize = vec2(textureSize(highlightDataTexture, 0));\\n  ivec2 pixelCenterCoord = ivec2(uv * texSize);\\n  vec4 pixelCenter = texelFetch(highlightDataTexture, pixelCenterCoord, 0);\\n\\n  vec3 offset = vec3((1.0 / texSize.x), (1.0 / texSize.y), 0.0);\\n\\n  vec4 result = pixelCenter;\\n  float weights = 1.0;\\n  float radius = 0.0;\\n  int differentPixels = 0;\\n  while (radius <= outlineThickness + 0.001) {\\n    radius += 1.0;\\n    \\n    int samples = int(2.0 * M_PI * radius);\\n    for (int i =0; i<samples; i++) {\\n      float theta = (float(i) / float(samples)) * 2.0 * M_PI;\\n      vec2 dir = vec2(radius * cos(theta) * offset.x, radius * sin(theta) * offset.y);\\n      \\n      ivec2 pixelCoord = ivec2((uv + dir) * texSize);\\n      vec4 pixel = texelFetch(highlightDataTexture, pixelCoord, 0);\\n      if ((pixel.r > 0.0 || pixel.g > 0.0 || pixel.b > 0.0)) {\\n        if (diff(pixel, pixelCenter) > 0.1) differentPixels++;\\n        // Blend the outer ring of pixels.\\n        // Note: disabled because I ran out of time. We can blend off the highlight towards\\n        // the edges to get a nicely anti-aliazed outline. \\n        // float dist = length(vec2(pixelCoord) - vec2(pixelCenterCoord));\\n        // float blendStart = max(1.0, outlineThickness - 0.5);\\n        pixel.a = 1.0; //smoothstep(1.0, 0.0, dist - blendStart);\\n\\n        result += pixel;\\n        weights += pixel.a;\\n      }\\n    }\\n  }\\n\\n  // Note: at the boundary between 2 highlighted objects, we get a nice blending effect. \\n  if (weights > 1.0) {\\n    result = result / weights;\\n  }\\n\\n  // If all the pixels found are the same as the center pixel, we just\\n  // return the center pixel.\\n  if (differentPixels == 0) {\\n    return pixelCenter;\\n  }\\n\\n  return result;\\n}\\n\\n#ifdef ENABLE_ES3\\nout vec4 fragColor;\\n#endif\\n\\nvoid main(void) {\\n    \\n  vec4 outlineColor = RadialSearch(v_texCoord);\\n  \\n  if (outlineColor.a > 0.0001) {\\n#ifndef ENABLE_ES3\\n    gl_FragColor = outlineColor;\\n#else\\n    fragColor = outlineColor;\\n#endif\\n  }\\n  else {\\n    discard;\\n  }\\n}\\n\\n\"; // eslint-disable-line\n\nvar vert$g = \"\\nprecision highp float;\\n#define GLSLIFY 1\\n\\nattribute vec3 positions;    //(location = 0)\\n\\n/* VS Outputs */\\nvarying vec2 v_texCoord;\\n \\nvoid main()\\n{\\n  v_texCoord = positions.xy+0.5;\\n  gl_Position = vec4(positions.xy*2.0, 0.0, 1.0);\\n}\\n\\n\"; // eslint-disable-line\n\n/* eslint-disable require-jsdoc */\nclass HighlightsShader extends GLShader {\n    /**\n     * Create a GL shader.\n     * @param gl - The webgl rendering context.\n     */\n    constructor(gl) {\n        super(gl, 'HighlightsShader');\n        this.setShaderStage('VERTEX_SHADER', vert$g);\n        this.setShaderStage('FRAGMENT_SHADER', frag$f);\n    }\n}\n\nvar frag$e = \"\\n#ifndef ENABLE_ES3\\n#extension GL_EXT_frag_depth: enable\\n#endif\\nprecision highp float;\\n#define GLSLIFY 1\\n\\nuniform sampler2D colorTexture;\\nuniform sampler2D depthTexture;\\nuniform vec2 screenSize;\\nuniform vec2 depthRange;\\n\\nuniform float outlineThickness;\\nuniform color outlineColor;\\nuniform float outlineSensitivity;\\nuniform float outlineDepthBias;\\n\\nvarying vec2 v_texCoord;\\n\\n// http://web.archive.org/web/20130416194336/http://olivers.posterous.com/linear-depth-in-glsl-for-real\\nfloat LinearEyeDepth(float z_b) {\\n  float z_n = 2.0 * z_b - 1.0;\\n  float z_e = 2.0 * depthRange.x * depthRange.y / (depthRange.y + depthRange.x - z_n * (depthRange.y - depthRange.x));\\n  return z_e;\\n}\\n\\nfloat LogEyeDepth(float z_b) {\\n  return depthRange.x + ((depthRange.y - depthRange.x) * z_b);\\n}\\n\\n// https://www.vertexfragment.com/ramblings/unity-postprocessing-sobel-outline/#depth-based-outline\\n// https://github.com/ssell/UnitySobelOutline/blob/2e1f4a5b4e703ae2c96aaf08d5518ce58abbaab9/Assets/Resources/Shaders/SobelOutlineHLSL.shader\\n\\nfloat SobelDepth(float ldc, float ldl, float ldr, float ldu, float ldd)\\n{\\n  return abs(ldl - ldc) +\\n      abs(ldr - ldc) +\\n      abs(ldu - ldc) +\\n      abs(ldd - ldc);\\n}\\n\\nfloat SobelSampleDepth(vec2 uv, vec3 offset)\\n{\\n  float pixelCenter = LinearEyeDepth(texture2D(depthTexture, uv).r);\\n  float pixelLeft   = LinearEyeDepth(texture2D(depthTexture, uv - offset.xz).r);\\n  float pixelRight  = LinearEyeDepth(texture2D(depthTexture, uv + offset.xz).r);\\n  float pixelUp     = LinearEyeDepth(texture2D(depthTexture, uv + offset.zy).r);\\n  float pixelDown   = LinearEyeDepth(texture2D(depthTexture, uv - offset.zy).r);\\n\\n  float  outlineDepthMultiplier = (1.0 / pixelCenter) * outlineSensitivity;\\n\\n  return SobelDepth(pixelCenter, pixelLeft, pixelRight, pixelUp, pixelDown) * outlineDepthMultiplier;\\n}\\n\\n#ifdef ENABLE_ES3\\n  out vec4 fragColor;\\n#endif\\nvoid main(void) {\\n#ifndef ENABLE_ES3\\n  vec4 fragColor;\\n#endif\\n\\n  vec3 offset = vec3((1.0 / screenSize.x), (1.0 / screenSize.y), 0.0) * outlineThickness;\\n  float sobelDepth = SobelSampleDepth(v_texCoord, offset);\\n  float sobelValue = pow(sobelDepth, outlineDepthBias);\\n\\n  float minEdgeValue = 0.25;\\n  float maxEdgeValue = 0.55;\\n  sobelDepth = smoothstep(minEdgeValue, maxEdgeValue, sobelValue);\\n\\n#ifdef ENABLE_ES3\\n  fragColor = vec4(outlineColor.rgb, sobelDepth);\\n#else\\n  fragColor = vec4(mix(texture2D(colorTexture, v_texCoord).rgb, outlineColor.rgb, sobelDepth), 1.0);\\n#ifdef  GL_EXT_frag_depth\\n  gl_FragDepthEXT = texture2D(depthTexture, v_texCoord).r;\\n#endif\\n#endif\\n\\n  // float z = texture2D(depthTexture, v_texCoord).r;\\n  // float near = depthRange.x * 2.0;    // the near plane\\n  // float far = depthRange.y / 2.0;     // the far plane\\n  // float c = (2.0 * near) / (far + near - z * (far - near));  // convert to linear values \\n  // fragColor = vec4(vec3(c), 1.0);\\n\\n  \\n\\n#ifndef ENABLE_ES3\\n  gl_FragColor = fragColor;\\n#endif\\n}\\n\"; // eslint-disable-line\n\nvar vert$f = \"\\nprecision highp float;\\n#define GLSLIFY 1\\nattribute vec3 positions;    //(location = 0)\\n\\n/* VS Outputs */\\nvarying vec2 v_texCoord;\\n \\nvoid main()\\n{\\n  v_texCoord = positions.xy+0.5;\\n  gl_Position = vec4(positions.xy*2.0, 0.0, 1.0);\\n}\\n\"; // eslint-disable-line\n\n/* eslint-disable require-jsdoc */\nclass SilhouetteShader extends GLShader {\n    /**\n     * Create a GL shader.\n     * @param gl - The webgl rendering context.\n     */\n    constructor(gl) {\n        super(gl, 'SilhouetteShader');\n        this.setShaderStage('VERTEX_SHADER', vert$f);\n        this.setShaderStage('FRAGMENT_SHADER', frag$e);\n    }\n}\n\n/** Detect free variable `global` from Node.js. */\nvar freeGlobal = typeof global == 'object' && global && global.Object === Object && global;\n\nvar freeGlobal$1 = freeGlobal;\n\n/** Detect free variable `self`. */\nvar freeSelf = typeof self == 'object' && self && self.Object === Object && self;\n\n/** Used as a reference to the global object. */\nvar root = freeGlobal$1 || freeSelf || Function('return this')();\n\nvar root$1 = root;\n\n/** Built-in value references. */\nvar Symbol$1 = root$1.Symbol;\n\nvar Symbol$2 = Symbol$1;\n\n/** Used for built-in method references. */\nvar objectProto$1 = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto$1.hasOwnProperty;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString$1 = objectProto$1.toString;\n\n/** Built-in value references. */\nvar symToStringTag$1 = Symbol$2 ? Symbol$2.toStringTag : undefined;\n\n/**\n * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the raw `toStringTag`.\n */\nfunction getRawTag(value) {\n  var isOwn = hasOwnProperty.call(value, symToStringTag$1),\n      tag = value[symToStringTag$1];\n\n  try {\n    value[symToStringTag$1] = undefined;\n    var unmasked = true;\n  } catch (e) {}\n\n  var result = nativeObjectToString$1.call(value);\n  if (unmasked) {\n    if (isOwn) {\n      value[symToStringTag$1] = tag;\n    } else {\n      delete value[symToStringTag$1];\n    }\n  }\n  return result;\n}\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/**\n * Converts `value` to a string using `Object.prototype.toString`.\n *\n * @private\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n */\nfunction objectToString(value) {\n  return nativeObjectToString.call(value);\n}\n\n/** `Object#toString` result references. */\nvar nullTag = '[object Null]',\n    undefinedTag = '[object Undefined]';\n\n/** Built-in value references. */\nvar symToStringTag = Symbol$2 ? Symbol$2.toStringTag : undefined;\n\n/**\n * The base implementation of `getTag` without fallbacks for buggy environments.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the `toStringTag`.\n */\nfunction baseGetTag(value) {\n  if (value == null) {\n    return value === undefined ? undefinedTag : nullTag;\n  }\n  return (symToStringTag && symToStringTag in Object(value))\n    ? getRawTag(value)\n    : objectToString(value);\n}\n\n/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n  return value != null && typeof value == 'object';\n}\n\n/** `Object#toString` result references. */\nvar symbolTag = '[object Symbol]';\n\n/**\n * Checks if `value` is classified as a `Symbol` primitive or object.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.\n * @example\n *\n * _.isSymbol(Symbol.iterator);\n * // => true\n *\n * _.isSymbol('abc');\n * // => false\n */\nfunction isSymbol(value) {\n  return typeof value == 'symbol' ||\n    (isObjectLike(value) && baseGetTag(value) == symbolTag);\n}\n\n/** Used to match a single whitespace character. */\nvar reWhitespace = /\\s/;\n\n/**\n * Used by `_.trim` and `_.trimEnd` to get the index of the last non-whitespace\n * character of `string`.\n *\n * @private\n * @param {string} string The string to inspect.\n * @returns {number} Returns the index of the last non-whitespace character.\n */\nfunction trimmedEndIndex(string) {\n  var index = string.length;\n\n  while (index-- && reWhitespace.test(string.charAt(index))) {}\n  return index;\n}\n\n/** Used to match leading whitespace. */\nvar reTrimStart = /^\\s+/;\n\n/**\n * The base implementation of `_.trim`.\n *\n * @private\n * @param {string} string The string to trim.\n * @returns {string} Returns the trimmed string.\n */\nfunction baseTrim(string) {\n  return string\n    ? string.slice(0, trimmedEndIndex(string) + 1).replace(reTrimStart, '')\n    : string;\n}\n\n/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n  var type = typeof value;\n  return value != null && (type == 'object' || type == 'function');\n}\n\n/** Used as references for various `Number` constants. */\nvar NAN = 0 / 0;\n\n/** Used to detect bad signed hexadecimal string values. */\nvar reIsBadHex = /^[-+]0x[0-9a-f]+$/i;\n\n/** Used to detect binary string values. */\nvar reIsBinary = /^0b[01]+$/i;\n\n/** Used to detect octal string values. */\nvar reIsOctal = /^0o[0-7]+$/i;\n\n/** Built-in method references without a dependency on `root`. */\nvar freeParseInt = parseInt;\n\n/**\n * Converts `value` to a number.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to process.\n * @returns {number} Returns the number.\n * @example\n *\n * _.toNumber(3.2);\n * // => 3.2\n *\n * _.toNumber(Number.MIN_VALUE);\n * // => 5e-324\n *\n * _.toNumber(Infinity);\n * // => Infinity\n *\n * _.toNumber('3.2');\n * // => 3.2\n */\nfunction toNumber(value) {\n  if (typeof value == 'number') {\n    return value;\n  }\n  if (isSymbol(value)) {\n    return NAN;\n  }\n  if (isObject(value)) {\n    var other = typeof value.valueOf == 'function' ? value.valueOf() : value;\n    value = isObject(other) ? (other + '') : other;\n  }\n  if (typeof value != 'string') {\n    return value === 0 ? value : +value;\n  }\n  value = baseTrim(value);\n  var isBinary = reIsBinary.test(value);\n  return (isBinary || reIsOctal.test(value))\n    ? freeParseInt(value.slice(2), isBinary ? 2 : 8)\n    : (reIsBadHex.test(value) ? NAN : +value);\n}\n\n/**\n * Gets the timestamp of the number of milliseconds that have elapsed since\n * the Unix epoch (1 January 1970 00:00:00 UTC).\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Date\n * @returns {number} Returns the timestamp.\n * @example\n *\n * _.defer(function(stamp) {\n *   console.log(_.now() - stamp);\n * }, _.now());\n * // => Logs the number of milliseconds it took for the deferred invocation.\n */\nvar now = function() {\n  return root$1.Date.now();\n};\n\nvar now$1 = now;\n\n/** Error message constants. */\nvar FUNC_ERROR_TEXT$1 = 'Expected a function';\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeMax = Math.max,\n    nativeMin = Math.min;\n\n/**\n * Creates a debounced function that delays invoking `func` until after `wait`\n * milliseconds have elapsed since the last time the debounced function was\n * invoked. The debounced function comes with a `cancel` method to cancel\n * delayed `func` invocations and a `flush` method to immediately invoke them.\n * Provide `options` to indicate whether `func` should be invoked on the\n * leading and/or trailing edge of the `wait` timeout. The `func` is invoked\n * with the last arguments provided to the debounced function. Subsequent\n * calls to the debounced function return the result of the last `func`\n * invocation.\n *\n * **Note:** If `leading` and `trailing` options are `true`, `func` is\n * invoked on the trailing edge of the timeout only if the debounced function\n * is invoked more than once during the `wait` timeout.\n *\n * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred\n * until to the next tick, similar to `setTimeout` with a timeout of `0`.\n *\n * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)\n * for details over the differences between `_.debounce` and `_.throttle`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Function\n * @param {Function} func The function to debounce.\n * @param {number} [wait=0] The number of milliseconds to delay.\n * @param {Object} [options={}] The options object.\n * @param {boolean} [options.leading=false]\n *  Specify invoking on the leading edge of the timeout.\n * @param {number} [options.maxWait]\n *  The maximum time `func` is allowed to be delayed before it's invoked.\n * @param {boolean} [options.trailing=true]\n *  Specify invoking on the trailing edge of the timeout.\n * @returns {Function} Returns the new debounced function.\n * @example\n *\n * // Avoid costly calculations while the window size is in flux.\n * jQuery(window).on('resize', _.debounce(calculateLayout, 150));\n *\n * // Invoke `sendMail` when clicked, debouncing subsequent calls.\n * jQuery(element).on('click', _.debounce(sendMail, 300, {\n *   'leading': true,\n *   'trailing': false\n * }));\n *\n * // Ensure `batchLog` is invoked once after 1 second of debounced calls.\n * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });\n * var source = new EventSource('/stream');\n * jQuery(source).on('message', debounced);\n *\n * // Cancel the trailing debounced invocation.\n * jQuery(window).on('popstate', debounced.cancel);\n */\nfunction debounce(func, wait, options) {\n  var lastArgs,\n      lastThis,\n      maxWait,\n      result,\n      timerId,\n      lastCallTime,\n      lastInvokeTime = 0,\n      leading = false,\n      maxing = false,\n      trailing = true;\n\n  if (typeof func != 'function') {\n    throw new TypeError(FUNC_ERROR_TEXT$1);\n  }\n  wait = toNumber(wait) || 0;\n  if (isObject(options)) {\n    leading = !!options.leading;\n    maxing = 'maxWait' in options;\n    maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;\n    trailing = 'trailing' in options ? !!options.trailing : trailing;\n  }\n\n  function invokeFunc(time) {\n    var args = lastArgs,\n        thisArg = lastThis;\n\n    lastArgs = lastThis = undefined;\n    lastInvokeTime = time;\n    result = func.apply(thisArg, args);\n    return result;\n  }\n\n  function leadingEdge(time) {\n    // Reset any `maxWait` timer.\n    lastInvokeTime = time;\n    // Start the timer for the trailing edge.\n    timerId = setTimeout(timerExpired, wait);\n    // Invoke the leading edge.\n    return leading ? invokeFunc(time) : result;\n  }\n\n  function remainingWait(time) {\n    var timeSinceLastCall = time - lastCallTime,\n        timeSinceLastInvoke = time - lastInvokeTime,\n        timeWaiting = wait - timeSinceLastCall;\n\n    return maxing\n      ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke)\n      : timeWaiting;\n  }\n\n  function shouldInvoke(time) {\n    var timeSinceLastCall = time - lastCallTime,\n        timeSinceLastInvoke = time - lastInvokeTime;\n\n    // Either this is the first call, activity has stopped and we're at the\n    // trailing edge, the system time has gone backwards and we're treating\n    // it as the trailing edge, or we've hit the `maxWait` limit.\n    return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||\n      (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));\n  }\n\n  function timerExpired() {\n    var time = now$1();\n    if (shouldInvoke(time)) {\n      return trailingEdge(time);\n    }\n    // Restart the timer.\n    timerId = setTimeout(timerExpired, remainingWait(time));\n  }\n\n  function trailingEdge(time) {\n    timerId = undefined;\n\n    // Only invoke if we have `lastArgs` which means `func` has been\n    // debounced at least once.\n    if (trailing && lastArgs) {\n      return invokeFunc(time);\n    }\n    lastArgs = lastThis = undefined;\n    return result;\n  }\n\n  function cancel() {\n    if (timerId !== undefined) {\n      clearTimeout(timerId);\n    }\n    lastInvokeTime = 0;\n    lastArgs = lastCallTime = lastThis = timerId = undefined;\n  }\n\n  function flush() {\n    return timerId === undefined ? result : trailingEdge(now$1());\n  }\n\n  function debounced() {\n    var time = now$1(),\n        isInvoking = shouldInvoke(time);\n\n    lastArgs = arguments;\n    lastThis = this;\n    lastCallTime = time;\n\n    if (isInvoking) {\n      if (timerId === undefined) {\n        return leadingEdge(lastCallTime);\n      }\n      if (maxing) {\n        // Handle invocations in a tight loop.\n        clearTimeout(timerId);\n        timerId = setTimeout(timerExpired, wait);\n        return invokeFunc(lastCallTime);\n      }\n    }\n    if (timerId === undefined) {\n      timerId = setTimeout(timerExpired, wait);\n    }\n    return result;\n  }\n  debounced.cancel = cancel;\n  debounced.flush = flush;\n  return debounced;\n}\n\n/** Error message constants. */\nvar FUNC_ERROR_TEXT = 'Expected a function';\n\n/**\n * Creates a throttled function that only invokes `func` at most once per\n * every `wait` milliseconds. The throttled function comes with a `cancel`\n * method to cancel delayed `func` invocations and a `flush` method to\n * immediately invoke them. Provide `options` to indicate whether `func`\n * should be invoked on the leading and/or trailing edge of the `wait`\n * timeout. The `func` is invoked with the last arguments provided to the\n * throttled function. Subsequent calls to the throttled function return the\n * result of the last `func` invocation.\n *\n * **Note:** If `leading` and `trailing` options are `true`, `func` is\n * invoked on the trailing edge of the timeout only if the throttled function\n * is invoked more than once during the `wait` timeout.\n *\n * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred\n * until to the next tick, similar to `setTimeout` with a timeout of `0`.\n *\n * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)\n * for details over the differences between `_.throttle` and `_.debounce`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Function\n * @param {Function} func The function to throttle.\n * @param {number} [wait=0] The number of milliseconds to throttle invocations to.\n * @param {Object} [options={}] The options object.\n * @param {boolean} [options.leading=true]\n *  Specify invoking on the leading edge of the timeout.\n * @param {boolean} [options.trailing=true]\n *  Specify invoking on the trailing edge of the timeout.\n * @returns {Function} Returns the new throttled function.\n * @example\n *\n * // Avoid excessively updating the position while scrolling.\n * jQuery(window).on('scroll', _.throttle(updatePosition, 100));\n *\n * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.\n * var throttled = _.throttle(renewToken, 300000, { 'trailing': false });\n * jQuery(element).on('click', throttled);\n *\n * // Cancel the trailing throttled invocation.\n * jQuery(window).on('popstate', throttled.cancel);\n */\nfunction throttle(func, wait, options) {\n  var leading = true,\n      trailing = true;\n\n  if (typeof func != 'function') {\n    throw new TypeError(FUNC_ERROR_TEXT);\n  }\n  if (isObject(options)) {\n    leading = 'leading' in options ? !!options.leading : leading;\n    trailing = 'trailing' in options ? !!options.trailing : trailing;\n  }\n  return debounce(func, wait, {\n    'leading': leading,\n    'maxWait': wait,\n    'trailing': trailing\n  });\n}\n\n/* eslint-disable guard-for-in */\nlet activeGLRenderer;\nlet pointerIsDown = false;\nlet pointerLeft = false;\nconst registeredPasses = [];\n// On Firefox, this provides better performance.\n// Portafill from 24FPS to 28fps....\n// https://hackmd.io/@jgilbert/HkwAQHKRr?type=view#Use-requestPostAnimationFrame-not-requestAnimationFrame\nlet requestPostAnimationFrame;\n// @ts-ignore\nif (globalThis.requestPostAnimationFrame) {\n    // @ts-ignore\n    requestPostAnimationFrame = window.requestPostAnimationFrame;\n}\nelse {\n    // @ts-ignore\n    requestPostAnimationFrame = function (callback) {\n        requestAnimationFrame(() => {\n            setTimeout(callback, 0);\n        });\n    };\n}\n/**\n * Class representing a GL base renderer.\n *\n * @extends ParameterOwner\n */\nclass GLBaseRenderer extends ParameterOwner {\n    #listenerIDs = new Map();\n    directives = [];\n    directivesHash;\n    solidAngleLimit = 0.004;\n    __gl;\n    glcanvas = null;\n    #scene = null;\n    #shaderDirectives = {};\n    #renderGeomDataFbosRequested = false;\n    #shaders = {};\n    #passes = {};\n    #passAssignments = new Map();\n    #passesRegistrationOrder = [];\n    #viewports = [];\n    #activeViewport = undefined;\n    #continuousDrawing = false;\n    #redrawRequested = false;\n    #drawSuspensionLevel = 0;\n    #prevFrameTime = 0;\n    #prevFrameDuration = 0;\n    floatGeomBuffer = true;\n    multiSampledScreenBuffer = false;\n    xrViewportPresenting = false;\n    xrViewport = undefined;\n    #xrViewportPromise;\n    glMaterialLibrary;\n    glGeomItemLibrary;\n    glGeomLibrary;\n    highlightsShader;\n    silhouetteShader;\n    screenQuad = null;\n    #resizeObserver;\n    #onResizeCallback;\n    /**\n     * Create a GL base renderer.\n     * @param $canvas - The canvas element.\n     * @param options - The options value.\n     */\n    constructor($canvas, options = {}) {\n        super();\n        if (!SystemDesc.gpuDesc) {\n            throw new Error('Unable to create renderer. WebGL not Supported');\n        }\n        // Function Bindings.\n        this.requestRedraw = this.requestRedraw.bind(this);\n        this.__gl = this.setupWebGL($canvas, options);\n        const gl = this.__gl;\n        this.highlightsShader = new HighlightsShader(gl);\n        this.silhouetteShader = new SilhouetteShader(gl);\n        this.screenQuad = new GLScreenQuad(this.__gl, this.directives);\n        this.bindEventHandlers();\n        const mainViewport = this.addViewport('main');\n        mainViewport.debugGeomDataBuffer = options.debugGeomDataBuffer;\n        mainViewport.debugOcclusionBuffer = options.debugOcclusionBuffer;\n        this.glMaterialLibrary = new GLMaterialLibrary(this);\n        this.glMaterialLibrary.on('updated', () => {\n            this.requestRedraw();\n        });\n        this.glGeomLibrary = new GLGeomLibrary(this);\n        this.glGeomLibrary.on('updated', () => {\n            this.requestRedraw();\n        });\n        this.glGeomItemLibrary = new GLGeomItemLibrary(this, options);\n        this.glGeomItemLibrary.on('updated', () => {\n            this.requestRedraw();\n        });\n        registeredPasses.forEach((reg) => {\n            // eslint-disable-next-line new-cap\n            // @ts-ignore\n            const pass = new reg.cls();\n            this.addPass(pass, reg.passType);\n        });\n        // ////////////////////////////////////////////\n        // WebXR\n        this.#xrViewportPromise = new Promise((resolve, reject) => {\n            if ((options.supportXR ?? true) && navigator.xr) {\n                const sessionMode = (options.xrMode ?? 'VR') == 'AR' ? 'immersive-ar' : 'immersive-vr';\n                const setupXRViewport = () => {\n                    this.xrViewport = this.setupXRViewport(sessionMode);\n                    let event = new XrViewportEvent(this.xrViewport);\n                    this.emit('xrViewportSetup', event);\n                    resolve(this.xrViewport);\n                };\n                navigator.xr\n                    .isSessionSupported(sessionMode)\n                    .then((isSupported) => {\n                    if (isSupported) {\n                        setupXRViewport();\n                    }\n                })\n                    .catch((reason) => {\n                    console.warn('Unable to setup XR:' + reason);\n                    reject('Unable to setup XR:' + reason);\n                });\n            }\n        });\n    }\n    /**\n     * The setShaderPreprocessorDirective method.\n     * @param name - The name value.\n     * @param value - The value param.\n     */\n    setShaderPreprocessorDirective(name, value) {\n        // const gl = this.__gl\n        this.#shaderDirectives[name] = value;\n        const directives = [];\n        let str = '';\n        // eslint-disable-next-line guard-for-in\n        for (const key in this.#shaderDirectives) {\n            const directive = this.#shaderDirectives[key];\n            directives.push(directive);\n            str += directive;\n        }\n        this.directives = directives;\n        this.directivesHash = '' + StringFunctions.hashStr(str);\n    }\n    /**\n     * Returns HTMLCanvasElement's width\n     *\n     * @return - The return value.\n     */\n    getWidth() {\n        return this.glcanvas.width;\n    }\n    /**\n     * Returns HTMLCanvasElement's Height\n     * @return - The return value.\n     */\n    getHeight() {\n        return this.glcanvas.height;\n    }\n    // //////////////////////////////////////\n    // Viewports\n    /**\n     * Adds a new viewport(viewing region) to the scene.\n     *\n     * @param name - The name of the viewport.\n     * @return - The return value.\n     */\n    addViewport(name) {\n        // TODO: We may need to merge GLBaseRenderer into GLRenderer to avoid this nasty cast.\n        const renderer = this;\n        const vp = new GLViewport(renderer, name, this.getWidth(), this.getHeight());\n        const updated = () => {\n            this.requestRedraw();\n        };\n        const viewChanged = (data) => {\n            if (!this.xrViewportPresenting) {\n                this.emit('viewChanged', data);\n            }\n        };\n        vp.on('updated', updated);\n        vp.on('viewChanged', viewChanged);\n        this.#viewports.push(vp);\n        this.#activeViewport = vp;\n        return vp;\n    }\n    /**\n     * Returns a viewport element by specifying its index in the list of viewports.\n     *\n     * @param index - The index value.\n     * @return - The return value.\n     */\n    getViewport(index = 0) {\n        return this.#viewports[index];\n    }\n    /**\n     * Returns a viewport element under the specified XY coordinates.\n     *\n     * @param offsetX - The viewport offset in the X axis.\n     * @param offsetY - The viewport offset in the Y axis.\n     * @return - The return value.\n     */\n    getViewportAtPos(offsetX, offsetY) {\n        for (const vp of this.#viewports) {\n            const x = vp.getPosX();\n            const y = vp.getPosY();\n            const width = vp.getWidth();\n            const height = vp.getHeight();\n            if (offsetX >= x && offsetY >= y && offsetX <= width + x && offsetY <= height + y)\n                return vp;\n        }\n        return undefined;\n    }\n    /**\n     * Sets as `active` the specified viewport.\n     *\n     * @param vp - The viewport.\n     */\n    activateViewport(vp) {\n        if (this.#activeViewport == vp)\n            return;\n        this.#activeViewport = vp;\n    }\n    /**\n     * Sets as àctive` the viewport under the specified XY coordinates.\n     *\n     * @param offsetX - The viewport offset in the X axis.\n     * @param offsetY - The viewport offset in the Y axis.\n     */\n    activateViewportAtPos(offsetX, offsetY) {\n        if (this.xrViewportPresenting)\n            return;\n        const vp = this.getViewportAtPos(offsetX, offsetY);\n        if (vp && vp != this.#activeViewport)\n            this.activateViewport(vp);\n    }\n    /**\n     * Returns current active viewport.\n     *\n     * @return - The return value.\n     */\n    getActiveViewport() {\n        return this.#activeViewport;\n    }\n    /**\n     * The suspendDrawing method.\n     */\n    suspendDrawing() {\n        this.#drawSuspensionLevel++;\n    }\n    /**\n     * The resumeDrawing method.\n     */\n    resumeDrawing() {\n        this.#drawSuspensionLevel--;\n        if (this.#drawSuspensionLevel == 0) {\n            this.renderGeomDataFbos();\n            this.requestRedraw();\n        }\n    }\n    /**\n     * The renderGeomDataFbos method. Frame buffer (FBO).\n     */\n    renderGeomDataFbos() {\n        if (this.#renderGeomDataFbosRequested == true)\n            return;\n        this.#renderGeomDataFbosRequested = true;\n        const onAnimationFrame = () => {\n            for (const vp of this.#viewports) {\n                vp.invalidateGeomDataBuffer();\n            }\n            this.#renderGeomDataFbosRequested = false;\n        };\n        requestPostAnimationFrame(onAnimationFrame);\n    }\n    // //////////////////////////////////////\n    // Scene\n    /**\n     * Returns current scene(Environment where all assets live) object.\n     *\n     * @return - The return value.\n     */\n    getScene() {\n        return this.#scene;\n    }\n    /**\n     * Sets scene to the renderer.\n     *\n     * @param scene - The scene value.\n     */\n    setScene(scene) {\n        this.#scene = scene;\n        this.addTreeItem(this.#scene.getRoot());\n        let event = new SceneSetEvent(this.#scene);\n        this.emit('sceneSet', event);\n    }\n    /**\n     * Adds tree items to the renderer, selecting the correct pass to delegate rendering too, and listens to future changes in the tree.\n     *\n     * @param treeItem - The tree item to add.\n     */\n    addTreeItem(treeItem) {\n        // Note: we can have BaseItems in the tree now.\n        if (!(treeItem instanceof TreeItem))\n            return;\n        const listenerIDs = {};\n        let continueInSubTree = true;\n        if (treeItem instanceof GeomItem) {\n            const geomParam = treeItem.geomParam;\n            if (geomParam.value == undefined) {\n                // we will add this geomItem once it receives its geom.\n                const geomAssigned = () => {\n                    delete listenerIDs['Geometry.valueChanged'];\n                    this.assignTreeItemToGLPass(treeItem);\n                };\n                listenerIDs['Geometry.valueChanged'] = geomParam.once('valueChanged', geomAssigned);\n            }\n            else {\n                continueInSubTree = this.assignTreeItemToGLPass(treeItem);\n            }\n        }\n        else {\n            continueInSubTree = this.assignTreeItemToGLPass(treeItem);\n        }\n        if (continueInSubTree) {\n            // Traverse the tree adding items until we hit the leaves (which are usually GeomItems.)\n            for (const childItem of treeItem.getChildren()) {\n                if (childItem)\n                    this.addTreeItem(childItem);\n            }\n            listenerIDs['childAdded'] = treeItem.on('childAdded', (event) => {\n                this.addTreeItem(event.childItem);\n            });\n            listenerIDs['childRemoved'] = treeItem.on('childRemoved', (event) => {\n                this.removeTreeItem(event.childItem);\n            });\n        }\n        listenerIDs['visibilityChanged'] = treeItem.on('visibilityChanged', () => {\n            this.renderGeomDataFbos();\n        });\n        listenerIDs['pickabilityChanged'] = treeItem.on('pickabilityChanged', () => {\n            this.renderGeomDataFbos();\n        });\n        this.#listenerIDs.set(treeItem, listenerIDs);\n        this.renderGeomDataFbos();\n    }\n    /**\n     * Searches through the passes and finds the appropriate pass to draw the given tree items.\n     *\n     * @param treeItem - The tree item to assign.\n     */\n    assignTreeItemToGLPass(treeItem) {\n        if (treeItem instanceof GeomItem) {\n            const geomItem = treeItem;\n            this.glGeomItemLibrary.addGeomItem(geomItem);\n        }\n        for (let i = this.#passesRegistrationOrder.length - 1; i >= 0; i--) {\n            const pass = this.#passesRegistrationOrder[i];\n            const rargs = {\n                continueInSubTree: true,\n            };\n            const handled = pass.itemAddedToScene(treeItem, rargs);\n            if (handled) {\n                this.#passAssignments.set(treeItem, pass);\n                return rargs.continueInSubTree;\n            }\n        }\n        return true;\n    }\n    /**\n     * Remove tree items from the scene.\n     *\n     * @param treeItem - The tree item to remove.\n     */\n    removeTreeItem(treeItem) {\n        // Note: we can have BaseItems in the tree now.\n        if (!(treeItem instanceof TreeItem))\n            return;\n        const listenerIDs = this.#listenerIDs.get(treeItem);\n        this.#listenerIDs.delete(treeItem);\n        treeItem.off('visibilityChanged', listenerIDs['visibilityChanged']);\n        treeItem.off('pickabilityChanged', listenerIDs['pickabilityChanged']);\n        const pass = this.#passAssignments.get(treeItem);\n        if (pass != undefined) {\n            const rargs = {\n                continueInSubTree: true,\n            };\n            pass.itemRemovedFromScene(treeItem, rargs);\n            this.#passAssignments.delete(treeItem);\n        }\n        // Note: if 'continueInSubTree' was false when adding the\n        //  item to the tree these listeners were never bound.\n        const continueInSubTree = listenerIDs['childAdded'] != undefined && listenerIDs['childRemoved'] != undefined;\n        if (continueInSubTree) {\n            treeItem.off('childAdded', listenerIDs['childAdded']);\n            treeItem.off('childRemoved', listenerIDs['childRemoved']);\n            // Traverse the tree adding items till we hit the leaves (which are usually GeomItems).\n            for (const childItem of treeItem.getChildren()) {\n                if (childItem)\n                    this.removeTreeItem(childItem);\n            }\n        }\n        if (treeItem instanceof GeomItem) {\n            const geomItem = treeItem;\n            if (listenerIDs['Geometry.valueChanged']) {\n                const geomParam = treeItem.geomParam;\n                geomParam.off('valueChanged', listenerIDs['Geometry.valueChanged']);\n            }\n            this.glGeomItemLibrary.removeGeomItem(geomItem);\n        }\n        this.renderGeomDataFbos();\n    }\n    // ///////////////////////\n    // Renderer Setup\n    /**\n     * Getter for gl.\n     */\n    get gl() {\n        return this.__gl;\n    }\n    /**\n     * The getGL method.\n     * @return - The return value.\n     */\n    getGL() {\n        return this.__gl;\n    }\n    /**\n     * Handle the canvas's parent resizing.\n     *\n     * @param newWidth - The new width of the canvas.\n     * @param newHeight - The new height of the canvas.\n     *\n     * @private\n     */\n    handleResize(newWidth, newHeight) {\n        if (this.xrViewportPresenting) {\n            return;\n        }\n        const width = Math.round(Math.max(4, newWidth) * window.devicePixelRatio);\n        const height = Math.round(Math.max(4, newHeight) * window.devicePixelRatio);\n        if (this.glcanvas.width != width || this.glcanvas.height != height) {\n            this.glcanvas.width = width;\n            this.glcanvas.height = height;\n            this.#viewports.forEach((viewport) => {\n                viewport.resize(width, height);\n            });\n            const event = new ResizedEvent(width, height);\n            this.emit('resized', event);\n            this.requestRedraw();\n        }\n    }\n    /**\n     * Returns host div of the canvas element.\n     *\n     * @return - The return value.\n     */\n    getDiv() {\n        return this.glcanvas.parentElement;\n    }\n    /**\n     * Setups the WebGL configuration for the renderer, specifying the canvas element where our\n     * @private\n     * @param $canvas - The $canvas element.\n     * @param webglOptions - The webglOptions value.\n     */\n    setupWebGL($canvas, options = {}) {\n        const { tagName } = $canvas;\n        if (!['DIV', 'CANVAS'].includes(tagName)) {\n            throw new Error('Only CANVAS and DIV are valid root elements.');\n        }\n        const rootIsDiv = tagName === 'DIV';\n        this.glcanvas = $canvas;\n        if (rootIsDiv) {\n            console.warn('@GLBaseRenderer#setupWebGL.', 'Using a DIV as root element is deprecated.', 'Use a CANVAS instead.', 'See: https://docs.zea.live/zea-engine/#/getting-started/get-started-with-engine?id=basic-setup');\n            this.glcanvas = document.createElement('canvas');\n            $canvas.appendChild(this.glcanvas);\n        }\n        else {\n            this.glcanvas = $canvas;\n        }\n        //@ts-ignore\n        this.glcanvas.style['touch-action'] = 'none';\n        //@ts-ignore\n        this.glcanvas.style['user-select'] = 'none';\n        //@ts-ignore\n        this.glcanvas.style['-webkit-user-select'] = 'none';\n        //@ts-ignore\n        this.glcanvas.style['-webkit-touch-callout'] = 'none';\n        this.glcanvas.parentElement.style.position = 'relative';\n        // Now scrollbars can appear causing the content size to change,\n        // causing an infinite loop of resizing.\n        this.glcanvas.parentElement.style.overflow = 'hidden';\n        this.glcanvas.style.width = '100%';\n        this.glcanvas.style.height = '100%';\n        this.glcanvas.style.position = 'absolute';\n        // Rapid resizing of the canvas would cause issues with WebGL.\n        // FrameBuffer objects would end up all black. So here we throttle\n        // the resizing of the canvas to ensure 2 resize commands are not\n        // closer than 100ms appart.\n        const throttledResize = throttle((entries) => {\n            if (!this.__gl)\n                return;\n            if (this.__gl.isContextLost()) {\n                console.warn('WebGL Context Lost');\n                return;\n            }\n            if (!Array.isArray(entries) || !entries.length)\n                return;\n            for (const entry of entries) {\n                if (!entry.contentRect)\n                    return;\n                const displayWidth = Math.round(entry.contentRect.width);\n                const displayHeight = Math.round(entry.contentRect.height);\n                this.handleResize(displayWidth, displayHeight);\n            }\n        }, 500);\n        this.#onResizeCallback = () => {\n            // The ResizeObserver below will miss zoom changes, while this\n            // resize event catches them. Both may be triggered by window\n            // resizes, but the throttle function ensures we don't resize\n            // needlessly.\n            const entries = [\n                {\n                    contentRect: {\n                        width: this.glcanvas.parentElement.clientWidth,\n                        height: this.glcanvas.parentElement.clientHeight,\n                    },\n                },\n            ];\n            throttledResize(entries);\n        };\n        window.addEventListener('resize', this.#onResizeCallback);\n        // https://webglfundamentals.org/webgl/lessons/webgl-resizing-the-canvas.html\n        this.#resizeObserver = new ResizeObserver(throttledResize);\n        try {\n            // only call us of the number of device pixels changed\n            // @ts-ignore\n            this.#resizeObserver.observe(this.glcanvas.parentNode, { box: 'device-pixel-content-box' });\n        }\n        catch (ex) {\n            // device-pixel-content-box is not supported so fallback to this\n            // @ts-ignore\n            this.#resizeObserver.observe(this.glcanvas.parentNode, { box: 'content-box' });\n        }\n        this.handleResize(this.glcanvas.parentElement.clientWidth, this.glcanvas.parentElement.clientHeight);\n        const disablingOnMacOsChrome = SystemDesc.OS === 'macOS' && SystemDesc.browserName === 'Chrome';\n        const disablingOnMobileSafari = SystemDesc.isIOSDevice;\n        const webglOptions = {};\n        webglOptions.preserveDrawingBuffer = true; // Note: The unit tests all render black if this is false\n        webglOptions.antialias = disablingOnMacOsChrome || disablingOnMobileSafari ? false : options.antialias ?? true;\n        webglOptions.depth = true;\n        webglOptions.stencil = true;\n        webglOptions.alpha = options.alpha ?? true;\n        webglOptions.premultipliedAlpha = options.premultipliedAlpha ?? false;\n        // Detect if an XR Compatible device is plugged in and automatically enable XR.\n        if (navigator.xr || options.supportXR) {\n            webglOptions.xrCompatible = true;\n        }\n        this.multiSampledScreenBuffer = webglOptions.antialias;\n        // Most applications of our engine will prefer the high-performance context by default.\n        webglOptions.powerPreference = options.powerPreference || 'high-performance';\n        const gl = create3DContext(this.glcanvas, webglOptions);\n        if (!gl)\n            alert('Unable to create WebGL context. WebGL not supported.');\n        this.setShaderPreprocessorDirective('ENABLE_ES3', '#define ENABLE_ES3');\n        if (gl.floatTexturesSupported) {\n            this.setShaderPreprocessorDirective('ENABLE_FLOAT_TEXTURES', '#define ENABLE_FLOAT_TEXTURES');\n        }\n        {\n            const ext = gl.getExtension('WEBGL_multi_draw');\n            if (ext && !options.disableMultiDraw) {\n                gl.multiDrawArrays = ext.multiDrawArraysWEBGL.bind(ext);\n                gl.multiDrawElements = ext.multiDrawElementsWEBGL.bind(ext);\n                gl.multiDrawElementsInstanced = ext.multiDrawElementsInstancedWEBGL.bind(ext);\n                gl.multiDrawArraysInstanced = ext.multiDrawArraysInstancedWEBGL.bind(ext);\n            }\n            else {\n                this.setShaderPreprocessorDirective('EMULATE_MULTI_DRAW', '#define EMULATE_MULTI_DRAW');\n            }\n        }\n        // Note: Mobile devices don't provide much support for reading data back from float textures,\n        // and checking compatibility is patchy at best.\n        // Note: We are now pushing on high-end mobile devices.\n        // Galaxy and above. We need this. We need to accurately determine\n        // if the float buffer is not supported.\n        if (SystemDesc.browserName == 'Safari' && gl.name == 'webgl') {\n            this.floatGeomBuffer = false;\n        }\n        else {\n            this.floatGeomBuffer = options.floatGeomBuffer != undefined ? options.floatGeomBuffer : gl.floatTexturesSupported;\n        }\n        gl.floatGeomBuffer = this.floatGeomBuffer;\n        return gl;\n    }\n    /**\n     * Binds IO event handlers to the canvas\n     */\n    bindEventHandlers() {\n        // ////////////////////////////////\n        // Setup event handlers\n        const isValidCanvas = () => this.getWidth() > 0 && this.getHeight();\n        /** Mouse Events Start */\n        // Mobile devices emulate mouse events after emitting touch events\n        // which causes double taps and other weirdness.\n        const isMobileDeviceMouseEvent = (event) => {\n            if (SystemDesc.isMobileDevice) {\n                // console.warn('Mobile device is triggering mouse event:', event.type)\n                return true;\n            }\n            return false;\n        };\n        this.glcanvas.addEventListener('mousedown', (event) => {\n            if (isMobileDeviceMouseEvent()) {\n                return;\n            }\n            const pointerEvent = new ZeaMouseEvent(event, this.glcanvas.getBoundingClientRect());\n            pointerIsDown = true;\n            activeGLRenderer = this;\n            this.activateViewportAtPos(pointerEvent.rendererX, pointerEvent.rendererY);\n            const viewport = this.getActiveViewport();\n            if (viewport) {\n                viewport.onPointerDown(pointerEvent);\n            }\n            pointerLeft = false;\n        });\n        document.addEventListener('mouseup', (event) => {\n            if (isMobileDeviceMouseEvent()) {\n                return;\n            }\n            if (activeGLRenderer != this || !isValidCanvas())\n                return;\n            const pointerEvent = new ZeaMouseEvent(event, this.glcanvas.getBoundingClientRect());\n            pointerIsDown = false;\n            const viewport = this.getActiveViewport();\n            if (viewport) {\n                viewport.onPointerUp(pointerEvent);\n            }\n            if (pointerLeft) {\n                if (viewport) {\n                    viewport.onPointerLeave(pointerEvent);\n                }\n                activeGLRenderer = undefined;\n            }\n        });\n        document.addEventListener('mousemove', (event) => {\n            if (isMobileDeviceMouseEvent()) {\n                return;\n            }\n            if (activeGLRenderer != this || !isValidCanvas())\n                return;\n            const pointerEvent = new ZeaMouseEvent(event, this.glcanvas.getBoundingClientRect());\n            if (!pointerIsDown)\n                this.activateViewportAtPos(pointerEvent.rendererX, pointerEvent.rendererY);\n            const viewport = this.getActiveViewport();\n            if (viewport) {\n                viewport.onPointerMove(pointerEvent);\n            }\n        });\n        this.glcanvas.addEventListener('mouseenter', (event) => {\n            if (isMobileDeviceMouseEvent()) {\n                return;\n            }\n            if (!pointerIsDown) {\n                activeGLRenderer = this;\n                const pointerEvent = new ZeaMouseEvent(event, this.glcanvas.getBoundingClientRect());\n                this.activateViewportAtPos(pointerEvent.rendererX, pointerEvent.rendererY);\n                if (!pointerIsDown) {\n                    const viewport = this.getActiveViewport();\n                    if (viewport) {\n                        viewport.onPointerEnter(pointerEvent);\n                    }\n                }\n                pointerLeft = false;\n            }\n        });\n        this.glcanvas.addEventListener('mouseleave', (event) => {\n            if (isMobileDeviceMouseEvent()) {\n                return;\n            }\n            if (activeGLRenderer != this || !isValidCanvas())\n                return;\n            const pointerEvent = new ZeaMouseEvent(event, this.glcanvas.getBoundingClientRect());\n            if (!pointerIsDown) {\n                const viewport = this.getActiveViewport();\n                if (viewport) {\n                    viewport.onPointerLeave(pointerEvent);\n                }\n                activeGLRenderer = undefined;\n            }\n            else {\n                pointerLeft = true;\n            }\n        });\n        document.addEventListener('contextmenu', (event) => {\n            if (activeGLRenderer != this || !isValidCanvas())\n                return;\n            // prevent context menu from being displayed when right clicking on the viewport.\n            // Note: we allow context menus for other items.\n            event.preventDefault();\n            event.stopPropagation();\n        });\n        /** Mouse Events End */\n        /** Touch Events Start */\n        this.glcanvas.addEventListener('touchstart', (event) => {\n            activeGLRenderer = this;\n            const viewport = this.getActiveViewport();\n            const pointerEvent = new ZeaTouchEvent(event, this.glcanvas.getBoundingClientRect());\n            viewport.onPointerDown(pointerEvent);\n        }, { passive: true });\n        this.glcanvas.addEventListener('touchend', (event) => {\n            const viewport = this.getActiveViewport();\n            const pointerEvent = new ZeaTouchEvent(event, this.glcanvas.getBoundingClientRect());\n            viewport.onPointerUp(pointerEvent);\n        }, { passive: true });\n        this.glcanvas.addEventListener('touchmove', (event) => {\n            const viewport = this.getActiveViewport();\n            const pointerEvent = new ZeaTouchEvent(event, this.glcanvas.getBoundingClientRect());\n            viewport.onPointerMove(pointerEvent);\n        }, { passive: true });\n        this.glcanvas.addEventListener('touchcancel', (event) => {\n            const viewport = this.getActiveViewport();\n            const pointerEvent = new ZeaTouchEvent(event, this.glcanvas.getBoundingClientRect());\n            viewport.onTouchCancel(pointerEvent);\n        }, { passive: true });\n        /** Touch Events End */\n        const onWheel = (event) => {\n            if (activeGLRenderer != this || !isValidCanvas())\n                return;\n            if (activeGLRenderer) {\n                const pointerEvent = new ZeaWheelEvent(event, this.glcanvas.getBoundingClientRect());\n                const vp = activeGLRenderer.getActiveViewport();\n                if (vp) {\n                    vp.onWheel(pointerEvent);\n                }\n            }\n        };\n        /** DOMMouseScroll is for mozilla. */\n        window.addEventListener('wheel', onWheel, { passive: false });\n        document.addEventListener('keydown', (event) => {\n            if (activeGLRenderer != this || !isValidCanvas())\n                return;\n            const keyboardEvent = new ZeaKeyboardEvent(event);\n            const vp = activeGLRenderer.getActiveViewport();\n            if (vp) {\n                vp.onKeyDown(keyboardEvent);\n            }\n        });\n        document.addEventListener('keyup', (event) => {\n            if (activeGLRenderer != this || !isValidCanvas())\n                return;\n            const keyboardEvent = new ZeaKeyboardEvent(event);\n            const vp = activeGLRenderer.getActiveViewport();\n            if (vp) {\n                vp.onKeyUp(keyboardEvent);\n            }\n        });\n    }\n    /**\n     * Returns canvas that was used to generate the gl context.\n     *\n     * @return - The return value.\n     */\n    getGLCanvas() {\n        return this.glcanvas;\n    }\n    /**\n     * Frames the specified viewport to the entire scene.\n     * > See also: ${Viewport#frameView}\n     * @param viewportIndex - The viewportIndex value. If multiple viewports are configured, a viewport index will need to be provided.\n     * @param duration - The duration of time to apply the frame. A value of 0 specifies an instantaneous movement of the camera.\n     * @param frameBorder - The variable to use to provide an empty space around the border for geometries.\n     */\n    frameAll(viewportIndex = 0, duration = 0, frameBorder = 0.1) {\n        this.#viewports[viewportIndex].frameView([this.#scene.getRoot()], duration, frameBorder);\n    }\n    // ///////////////////////\n    // Render Items Setup\n    /**\n     * A factory function used to construct new shader objects. If that specified shader has already been constructed, it returns the existing shader.\n     * @param shaderName - The shader name.\n     * @return - The return value.\n     */\n    getOrCreateShader(shaderName) {\n        let glShader = this.#shaders[shaderName];\n        if (!glShader) {\n            glShader = Registry.constructClass(shaderName);\n            if (!glShader)\n                console.error('@GLBaseRenderer#getOrCreateShader - Shader not registered with the Registry:', shaderName);\n            glShader.setGLContext(this.__gl);\n            this.#shaders[shaderName] = glShader;\n        }\n        return glShader;\n    }\n    /**\n     * The addPass method.\n     * @param pass - The pass value.\n     * @param passType - The passType value.\n     * @param updateIndices - The updateIndices value.\n     * @return - The return value.\n     */\n    addPass(pass, passType = -1) {\n        if (passType == -1)\n            passType = pass.getPassType();\n        if (!this.#passes[passType])\n            this.#passes[passType] = [];\n        let index = 0;\n        for (const key in this.#passes) {\n            if (key == passType.toString())\n                break;\n            index += this.#passes[key].length;\n        }\n        index += this.#passes[passType].length;\n        pass.on('updated', (event) => {\n            this.requestRedraw();\n            // If a pass is requesting an update, it is because geometry or\n            // visibility is changing and the geom data Fbo will also be out\n            // of date.\n            this.renderGeomDataFbos();\n        });\n        // @ts-ignore TODO: Merge GLRenderer and GLBaseRenderer.\n        pass.init(this, index);\n        this.#passes[passType].push(pass);\n        // Now update all the  subsequent pass indices because the\n        // indices after will have changed.\n        let offset = 0;\n        for (const key in this.#passes) {\n            const passSet = this.#passes[key];\n            passSet.forEach((pass, index) => {\n                pass.setPassIndex(offset + index);\n            });\n            offset += passSet.length;\n        }\n        this.#passesRegistrationOrder.push(pass);\n        this.requestRedraw();\n        return index;\n    }\n    /**\n     * The getPass method.\n     * @param index - The index value.\n     * @return - The return value.\n     */\n    getPass(index) {\n        let offset = 0;\n        for (const key in this.#passes) {\n            const passSet = this.#passes[key];\n            if (index - offset < passSet.length)\n                return passSet[index - offset];\n            offset += passSet.length;\n        }\n        return undefined;\n    }\n    /**\n     * Find a pass given a class type. Used by the GPViewport to find the GLOverlayPass.\n     * @param index - The index value.\n     * @return - The return value.\n     */\n    findPassIndex(cls) {\n        let offset = 0;\n        for (const key in this.#passes) {\n            const passSet = this.#passes[key];\n            for (let i = 0; i < passSet.length; i++) {\n                if (passSet[i] instanceof cls)\n                    return offset;\n                offset++;\n            }\n        }\n        return -1;\n    }\n    // ///////////////////////\n    // VR Setup\n    /**\n     * The setupXRViewport method.\n     */\n    setupXRViewport(sessionMode) {\n        // Always get the last display. Additional displays are added at the end.(e.g. [Polyfill, HMD])\n        const xrvp = sessionMode == 'immersive-ar' ? new ARViewport(this, sessionMode) : new VRViewport(this, sessionMode);\n        const emitViewChanged = (event) => {\n            this.emit('viewChanged', event);\n        };\n        xrvp.on('presentingChanged', (event) => {\n            const state = event.state;\n            // Note: the WebXREmulator does a double emit and this causes issues.\n            if (this.xrViewportPresenting == state)\n                return;\n            this.xrViewportPresenting = state;\n            if (state) {\n                // Let the passes know that VR is starting.\n                // They can do things like optimize shaders.\n                for (const key in this.#passes) {\n                    const passSet = this.#passes[key];\n                    for (const pass of passSet) {\n                        pass.startPresenting();\n                    }\n                }\n                xrvp.on('viewChanged', emitViewChanged);\n            }\n            else {\n                xrvp.off('viewChanged', emitViewChanged);\n                this.emit('updated');\n                for (const key in this.#passes) {\n                    const passSet = this.#passes[key];\n                    for (const pass of passSet) {\n                        pass.stopPresenting();\n                    }\n                }\n                const viewXfo = this.getViewport().getCamera().globalXfoParam.value;\n                const event = new ViewChangedEvent('CameraAndPointer', viewXfo);\n                this.emit('viewChanged', event);\n                this.requestRedraw();\n            }\n        });\n        return xrvp;\n    }\n    /**\n     * The getVRViewport method.\n     * @return - The return value.\n     */\n    getVRViewport() {\n        return this.xrViewport;\n    }\n    /**\n     * The getXRViewport method.\n     * @return - The return value.\n     */\n    getXRViewport() {\n        return this.#xrViewportPromise;\n    }\n    /**\n     * The isXRViewportPresenting method.\n     * @return - The return value.\n     */\n    isXRViewportPresenting() {\n        return this.xrViewportPresenting;\n    }\n    // //////////////////////////\n    // Rendering\n    /**\n     * The isContinuouslyDrawing method.\n     * @return - The return value.\n     */\n    isContinuouslyDrawing() {\n        return this.#continuousDrawing;\n    }\n    /**\n     * The startContinuousDrawing method.\n     */\n    startContinuousDrawing() {\n        if (this.isContinuouslyDrawing() || this.xrViewportPresenting)\n            return;\n        const onAnimationFrame = () => {\n            const renderstate = new ColorRenderState(this.gl);\n            if (this.#continuousDrawing && !this.xrViewportPresenting)\n                window.requestAnimationFrame(onAnimationFrame);\n            for (const vp of this.#viewports)\n                vp.draw(renderstate);\n        };\n        this.#continuousDrawing = true;\n        requestPostAnimationFrame(onAnimationFrame);\n    }\n    /**\n     * The stopContinuousDrawing method.\n     */\n    stopContinuousDrawing() {\n        this.#continuousDrawing = false;\n    }\n    /**\n     * The toggleContinuousDrawing method.\n     */\n    toggleContinuousDrawing() {\n        if (!this.#continuousDrawing) {\n            this.startContinuousDrawing();\n        }\n        else {\n            this.stopContinuousDrawing();\n        }\n    }\n    /**\n     * The drawItemChanged method.\n     */\n    drawItemChanged(invalidateGeomDataBuffer) {\n        if (invalidateGeomDataBuffer) {\n            for (const vp of this.#viewports) {\n                vp.invalidateGeomDataBuffer();\n            }\n        }\n        this.requestRedraw();\n    }\n    /**\n     * Request a single redraw, usually in response to a signal/event.\n     * @return - The return value.\n     */\n    requestRedraw() {\n        // If a redraw has already been requested, then simply return and wait.\n        if (!this.__gl ||\n            this.#redrawRequested ||\n            this.#continuousDrawing ||\n            this.xrViewportPresenting ||\n            this.#drawSuspensionLevel > 0) {\n            return false;\n        }\n        if (this.__gl.isContextLost()) {\n            console.warn('WebGL Context Lost');\n            return false;\n        }\n        const onAnimationFrame = () => {\n            this.#redrawRequested = false;\n            const start = performance.now();\n            const renderstate = new ColorRenderState(this.gl);\n            for (const vp of this.#viewports) {\n                vp.draw(renderstate);\n            }\n            if (renderstate.stack.length != 0) {\n                console.warn(' corrupt renderstate.stack.length:', renderstate.stack.length);\n            }\n            const end = performance.now();\n            this.#prevFrameTime = end;\n            this.#prevFrameDuration = end - start;\n        };\n        // requestPostAnimationFrame(onAnimationFrame)\n        requestAnimationFrame(() => {\n            const now = performance.now();\n            const timeDelta = now - this.#prevFrameTime;\n            const frameTime = 1000 / 60;\n            const delay = Math.max(0, frameTime - timeDelta - this.#prevFrameDuration);\n            setTimeout(onAnimationFrame, delay);\n        });\n        // requestAnimationFrame()\n        this.#redrawRequested = true;\n        return true;\n    }\n    /**\n     * Forces a redraw of the viewports\n     */\n    forceRender() {\n        if (!this.#redrawRequested) {\n            console.warn('@GlBaseRenderer#forceRender - Scene is not dirty');\n            return;\n        }\n        this.#redrawRequested = false;\n        const renderstate = new ColorRenderState(this.gl);\n        for (const vp of this.#viewports) {\n            vp.draw(renderstate);\n        }\n    }\n    /**\n     * The bindGLRenderer method.\n     * @param renderstate - The renderstate value.\n     */\n    bindGLRenderer(renderstate) {\n        renderstate.gl = this.__gl;\n        renderstate.renderer = this;\n        renderstate.directives = this.directives;\n        renderstate.directivesHash = this.directivesHash;\n    }\n    /**\n     * The drawScene method.\n     * @param renderstate - The renderstate value.\n     */\n    drawScene(renderstate) {\n        // Bind already called by GLRenderer.\n        renderstate.directives = [...this.directives, '#define DRAW_COLOR'];\n        for (const key in this.#passes) {\n            const passSet = this.#passes[key];\n            for (const pass of passSet) {\n                if (pass.enabled)\n                    pass.draw(renderstate);\n            }\n        }\n    }\n    /**\n     * The drawHighlightedGeoms method.\n     * @param renderstate - The renderstate value.\n     */\n    drawHighlightedGeoms(renderstate) {\n        this.bindGLRenderer(renderstate);\n        renderstate.directives = [...this.directives, '#define DRAW_HIGHLIGHT'];\n        for (const key in this.#passes) {\n            const passSet = this.#passes[key];\n            for (const pass of passSet) {\n                if (pass.enabled)\n                    pass.drawHighlightedGeoms(renderstate);\n            }\n        }\n    }\n    /**\n     * The drawSceneGeomData method.\n     * @param renderstate - The renderstate value.\n     * @param mask - The mask value\n     */\n    drawSceneGeomData(renderstate, mask = 255) {\n        renderstate.pushGLStack('GLBaseRenderer.drawSceneGeomData');\n        renderstate.glEnable(this.__gl.DEPTH_TEST);\n        renderstate.glEnable(this.__gl.CULL_FACE);\n        this.bindGLRenderer(renderstate);\n        renderstate.directives = [...this.directives, '#define DRAW_GEOMDATA'];\n        renderstate.floatGeomBuffer = this.floatGeomBuffer;\n        for (const key in this.#passes) {\n            // Skip pass categories that do not match\n            // the mask. E.g. we may not want to hit\n            // \"Overlay\" geoms such as labels,\n            // or we might be trying to move labels and don't\n            // want to grab normal geoms.\n            if ((Number.parseInt(key) & mask) == 0)\n                continue;\n            const passSet = this.#passes[key];\n            for (const pass of passSet) {\n                if (pass.enabled)\n                    pass.drawGeomData(renderstate);\n            }\n        }\n        renderstate.popGLStack();\n    }\n    // ////////////////////////////////////////\n    // Static Methods\n    /**\n     * The registerPass method.\n     * @param cls - The cls value.\n     * @param passType - The passType value.\n     */\n    static registerPass(cls, passType) {\n        registeredPasses.push({ cls, passType });\n    }\n    /**\n     * The destroy is called by the system to cause explicit resources cleanup.\n     * Users should never need to call this method directly.\n     */\n    destroy(loseContext = true) {\n        this.#resizeObserver.disconnect();\n        window.removeEventListener('resize', this.#onResizeCallback);\n        if (loseContext) {\n            const ext = this.__gl.getExtension('WEBGL_lose_context');\n            if (ext)\n                ext.loseContext();\n        }\n    }\n}\n\nvar frag$d = \"\\nprecision highp float;\\n#define GLSLIFY 1\\n\\nvarying vec2 v_texCoord;\\n\\nimport 'GLSLUtils.glsl'\\nimport 'Hammersley.glsl'\\nimport 'ImportanceSampleGGX.glsl'\\n\\nfloat GeometrySchlickGGX(float NdotV, float roughness)\\n{\\n  float a = roughness;\\n  float k = (a * a) / 2.0;\\n\\n  float nom   = NdotV;\\n  float denom = NdotV * (1.0 - k) + k;\\n\\n  return nom / denom;\\n}\\n// ----------------------------------------------------------------------------\\nfloat GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness)\\n{\\n  float NdotV = max(dot(N, V), 0.0);\\n  float NdotL = max(dot(N, L), 0.0);\\n  float ggx2 = GeometrySchlickGGX(NdotV, roughness);\\n  float ggx1 = GeometrySchlickGGX(NdotL, roughness);\\n\\n  return ggx1 * ggx2;\\n}\\n\\nvec2 IntegrateBRDF(float NdotV, float roughness)\\n{\\n  vec3 V;\\n  V.x = sqrt(1.0 - NdotV*NdotV);\\n  V.y = 0.0;\\n  V.z = NdotV;\\n\\n  float A = 0.0;\\n  float B = 0.0;\\n\\n  vec3 N = vec3(0.0, 0.0, 1.0);\\n\\n  for(uint i = 0u; i < SAMPLE_COUNT; ++i)\\n  {\\n    vec2 Xi = Hammersley(i, SAMPLE_COUNT);\\n    vec3 H  = ImportanceSampleGGX(Xi, N, roughness);\\n    vec3 L  = normalize(2.0 * dot(V, H) * H - V);\\n\\n    float NdotL = max(L.z, 0.0);\\n    float NdotH = max(H.z, 0.0);\\n    float VdotH = max(dot(V, H), 0.0);\\n\\n    if (NdotL > 0.0)\\n    {\\n      float G = GeometrySmith(N, V, L, roughness);\\n      float G_Vis = (G * VdotH) / (NdotH * NdotV);\\n      float Fc = pow(1.0 - VdotH, 5.0);\\n\\n      A += (1.0 - Fc) * G_Vis;\\n      B += Fc * G_Vis;\\n    }\\n  }\\n  A /= float(SAMPLE_COUNT);\\n  B /= float(SAMPLE_COUNT);\\n  return vec2(A, B);\\n}\\n\\nout vec2 fragColor;\\nvoid main(void) {\\n  vec2 integratedBRDF = IntegrateBRDF(v_texCoord.x, v_texCoord.y);\\n  fragColor = integratedBRDF;\\n}\\n\\n\"; // eslint-disable-line\n\nvar vert$e = \"\\nprecision highp float;\\n#define GLSLIFY 1\\n\\nimport 'quadVertexFromID.glsl'\\n\\n/* VS Outputs */\\nvarying vec2 v_texCoord;\\n \\nvoid main()\\n{\\n  vec2 position = getQuadVertexPositionFromID();\\n  v_texCoord = position+0.5;\\n  gl_Position = vec4(position*2.0, 0.0, 1.0);\\n}\\n\"; // eslint-disable-line\n\n/* eslint-disable require-jsdoc */\n/** Shader for convolving Environment maps.\n * @extends GLShader\n * @private\n */\nclass PreComputeBRDFShader extends GLShader {\n    /**\n     * Create a GL renderer.\n     * @param gl - The options value.\n     */\n    constructor(gl) {\n        super(gl, 'PreComputeBRDFShader');\n        this.setShaderStage('VERTEX_SHADER', vert$e);\n        this.setShaderStage('FRAGMENT_SHADER', frag$d);\n    }\n}\n\nvar frag$c = \"\\nprecision highp float;\\n#define GLSLIFY 1\\nimport 'constants.glsl'\\nimport 'convolve-helpers.glsl'\\n\\nuniform int faceId;\\nvarying vec2 v_texCoord;\\n\\nout vec4 fragColor;\\nvoid main(void) {\\n\\n  vec3 N = cubeFaceUvToDir(v_texCoord.x, v_texCoord.y, faceId);   \\n\\n  vec3 irradiance = vec3(0.0);\\n\\n  vec3 up        = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);\\n  vec3 tangent   = normalize(cross(up, N));\\n  vec3 bitangent = cross(N, tangent);\\n\\n  float nrSamples = 0.0; \\n  for(float phi = 0.0; phi < 2.0 * PI; phi += SAMPLE_DELTA)\\n  {\\n    for(float theta = 0.0; theta < 0.5 * PI; theta += SAMPLE_DELTA)\\n    {\\n      // spherical to cartesian (in tangent space)\\n      // from spherical coordinates to cartesian coordinates\\n      vec3 H = vec3(cos(phi) * sin(theta), sin(phi) * sin(theta), cos(theta));\\n      // tangent space to world\\n      vec3 sampleVec = tangent * H.x + bitangent * H.y + N * H.z;\\n\\n      irradiance += sampleEnvMap(normalize(sampleVec)).rgb * cos(theta) * sin(theta);\\n      nrSamples++;\\n    }\\n  }\\n  irradiance = PI * irradiance * (1.0 / float(nrSamples));\\n\\n  fragColor = vec4(irradiance, 1.0);\\n}\\n\"; // eslint-disable-line\n\nvar vert$d = \"\\nprecision highp float;\\n#define GLSLIFY 1\\n\\nimport 'quadVertexFromID.glsl'\\n\\n/* VS Outputs */\\nvarying vec2 v_texCoord;\\n \\nvoid main()\\n{\\n  vec2 position = getQuadVertexPositionFromID();\\n  v_texCoord = position+0.5;\\n  gl_Position = vec4(position*2.0, 0.0, 1.0);\\n}\\n\"; // eslint-disable-line\n\n/* eslint-disable require-jsdoc */\n/** Shader for convolving Environment maps.\n * @extends GLShader\n * @private\n */\nclass ConvolveIrradianceShader extends GLShader {\n    /**\n     * Create a GL renderer.\n     * @param gl - The options value.\n     */\n    constructor(gl) {\n        super(gl, 'ConvolveIrradianceShader');\n        this.setShaderStage('VERTEX_SHADER', vert$d);\n        this.setShaderStage('FRAGMENT_SHADER', frag$c);\n    }\n}\n\nvar vert$c = \"\\nprecision highp float;\\n#define GLSLIFY 1\\n\\nimport 'quadVertexFromID.glsl'\\n\\n/* VS Outputs */\\nvarying vec2 v_texCoord;\\n \\nvoid main()\\n{\\n  vec2 position = getQuadVertexPositionFromID();\\n  v_texCoord = position+0.5;\\n  gl_Position = vec4(position*2.0, 0.0, 1.0);\\n}\\n\"; // eslint-disable-line\n\nvar frag$b = \"precision highp float;\\nprecision highp int;\\n#define GLSLIFY 1\\n\\nimport 'GLSLUtils.glsl'\\nimport 'ImportanceSampleGGX.glsl'\\nimport 'convolve-helpers.glsl'\\nimport 'Hammersley.glsl'\\n  \\n\\nuniform int faceId;\\nuniform float roughness;\\n\\nvarying vec2 v_texCoord;\\n\\nout vec4 fragColor;\\nvoid main(void) {\\n\\n  vec3 N = cubeFaceUvToDir(v_texCoord.x, v_texCoord.y, faceId);   \\n\\n  vec3 R = N;\\n  vec3 V = R;\\n\\n  float totalWeight = 0.0;   \\n  vec3 prefilteredColor = vec3(0.0);     \\n  for(uint i = 0u; i < SAMPLE_COUNT; ++i)\\n  {\\n    vec2 Xi = Hammersley(i, SAMPLE_COUNT);\\n    vec3 H  = ImportanceSampleGGX(Xi, N, roughness);\\n    vec3 L  = normalize(2.0 * dot(V, H) * H - V);\\n\\n    float NdotL = max(dot(N, L), 0.0);\\n    if (NdotL > 0.0)\\n    {\\n      prefilteredColor += sampleEnvMap(L).rgb * NdotL;\\n      totalWeight      += NdotL;\\n    }\\n  }\\n  prefilteredColor = prefilteredColor / totalWeight;\\n\\n  fragColor = vec4(prefilteredColor, 1.0);\\n}\\n\"; // eslint-disable-line\n\n/* eslint-disable require-jsdoc */\n/** Shader for convolving Environment maps.\n * @extends GLShader\n * @private\n */\nclass ConvolveSpecularShader extends GLShader {\n    /**\n     * Create a GL renderer.\n     * @param gl - The options value.\n     */\n    constructor(gl) {\n        super(gl, 'ConvolveSpecularShader');\n        this.setShaderStage('VERTEX_SHADER', vert$c);\n        this.setShaderStage('FRAGMENT_SHADER', frag$b);\n    }\n}\n\n/** Class representing a GL probe.\n * @private\n */\nclass GLProbe extends EventEmitter {\n    gl;\n    textureDesc;\n    maxFragmentShaderTextureUnits;\n    textureType;\n    convolved = false;\n    brdfLUTTexture;\n    irradianceCubeTex;\n    specularCubetex;\n    /**\n     * Create a GL probe.\n     * @param gl - The webgl rendering context.\n     * @param name - The name value.\n     */\n    constructor(gl, name) {\n        super();\n        this.gl = gl;\n        this.maxFragmentShaderTextureUnits = gl.getParameter(this.gl.MAX_TEXTURE_IMAGE_UNITS);\n        if (!this.gl.__quadVertexIdsBuffer)\n            this.gl.setupInstancedQuad();\n        this.textureType = 1; // Default 2d 8 bit texture image texture.\n        this.textureDesc = [0, 0, 0, 0]; // To be populated by derived classes.\n        this.convolved = false;\n    }\n    /**\n     * The convolveProbe method.\n     * @param srcGLTex - The srcGLTex value.\n     */\n    convolveProbe(srcGLTex) {\n        const gl = this.gl;\n        const renderstate = new RenderState(gl);\n        renderstate.directives = ['#define ENABLE_ES3', '#define ENABLE_FLOAT_TEXTURES'];\n        // Note: in testing we are running on the Google SwiftShader emulated GPU.\n        if (SystemDesc.deviceCategory == 'Low') {\n            renderstate.directives.push('#define SAMPLE_DELTA 0.1');\n            renderstate.directives.push('#define SAMPLE_COUNT 64u');\n        }\n        else if (SystemDesc.deviceCategory == 'Medium') {\n            renderstate.directives.push('#define SAMPLE_DELTA 0.08');\n            renderstate.directives.push('#define SAMPLE_COUNT 256u');\n        }\n        else {\n            renderstate.directives.push('#define SAMPLE_DELTA 0.025');\n            renderstate.directives.push('#define SAMPLE_COUNT 1024u');\n        }\n        this.brdfLUTTexture = gl.createTexture();\n        // pre-allocate enough memory for the LUT texture.\n        gl.bindTexture(gl.TEXTURE_2D, this.brdfLUTTexture);\n        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RG16F, 512, 512, 0, gl.RG, gl.HALF_FLOAT, null);\n        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);\n        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);\n        const brdfShader = new PreComputeBRDFShader(this.gl);\n        const brdfShaderComp = brdfShader.compileForTarget('GLProbe', renderstate.directives);\n        const brdfShaderBinding = generateShaderGeomBinding(this.gl, brdfShaderComp.attrs, gl.__quadattrbuffers, gl.__quadIndexBuffer);\n        const brdfFboId = gl.createFramebuffer();\n        gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, brdfFboId);\n        gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.brdfLUTTexture, 0);\n        brdfShader.bind(renderstate);\n        brdfShaderBinding.bind(renderstate);\n        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);\n        gl.viewport(0, 0, 512, 512);\n        gl.drawQuad();\n        gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);\n        gl.deleteFramebuffer(brdfFboId);\n        brdfShader.unbind(renderstate);\n        brdfShader.destroy();\n        // ////////////////////////////////////////////\n        // ConvolveIrradianceShader Shader\n        {\n            const convolveIrradianceShader = new ConvolveIrradianceShader(this.gl);\n            const convolveIrradianceShaderComp = convolveIrradianceShader.compileForTarget('GLProbe', renderstate.directives);\n            const convolveIrradianceShaderBinding = generateShaderGeomBinding(this.gl, convolveIrradianceShaderComp.attrs, gl.__quadattrbuffers, gl.__quadIndexBuffer);\n            convolveIrradianceShader.bind(renderstate, 'GLProbe');\n            convolveIrradianceShaderBinding.bind(renderstate);\n            const unifs = renderstate.unifs;\n            srcGLTex.bindToUniform(renderstate, unifs.envMap);\n            // ////////////////////////////////////////////\n            // Irradiance Cube\n            const size = 64;\n            this.irradianceCubeTex = gl.createTexture();\n            gl.bindTexture(gl.TEXTURE_CUBE_MAP, this.irradianceCubeTex);\n            gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR);\n            gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);\n            gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n            gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n            gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE);\n            // Resize all the faces first.\n            for (let i = 0; i < 6; i++) {\n                gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, gl.RGBA16F, size, size, 0, gl.RGBA, gl.HALF_FLOAT, null);\n            }\n            // Attach one face of cube map\n            const irradianceFboId = gl.createFramebuffer();\n            gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, irradianceFboId);\n            for (let i = 0; i < 6; ++i) {\n                gl.uniform1i(unifs.faceId.location, i);\n                gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, this.irradianceCubeTex, 0);\n                gl.viewport(0, 0, size, size); // Match the viewport to the texture size\n                gl.clearColor(1, 0, 0, 1);\n                gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);\n                gl.drawQuad();\n            }\n            gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);\n            gl.deleteFramebuffer(irradianceFboId);\n            // Note: without the mipmaps, te cube sampling seems a big broken.\n            // No colors.\n            gl.generateMipmap(gl.TEXTURE_CUBE_MAP);\n        }\n        // ////////////////////////////////////////////\n        // Specular Cube Pyramid\n        {\n            const convolverShader = new ConvolveSpecularShader(this.gl);\n            const covolverShaderComp = convolverShader.compileForTarget('GLProbe', renderstate.directives);\n            const covolverShaderBinding = generateShaderGeomBinding(this.gl, covolverShaderComp.attrs, gl.__quadattrbuffers, gl.__quadIndexBuffer);\n            convolverShader.bind(renderstate, 'GLProbe');\n            covolverShaderBinding.bind(renderstate);\n            const unifs = renderstate.unifs;\n            srcGLTex.bindToUniform(renderstate, unifs.envMap);\n            this.specularCubetex = gl.createTexture();\n            gl.bindTexture(gl.TEXTURE_CUBE_MAP, this.specularCubetex);\n            gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR);\n            gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);\n            gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n            gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n            gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE);\n            // Resize all the faces first.\n            const size = 256;\n            for (let i = 0; i < 6; i++) {\n                gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, gl.RGBA16F, size, size, 0, gl.RGBA, gl.HALF_FLOAT, null);\n            }\n            gl.generateMipmap(gl.TEXTURE_CUBE_MAP);\n            // gl.enable(gl.TEXTURE_CUBE_MAP_SEAMLESS) // not supported in webgl\n            const maxMipLevels = 5;\n            for (let mip = 0; mip < maxMipLevels; ++mip) {\n                // resize framebuffer according to mip-level size.\n                const mipWidth = size * Math.pow(0.5, mip);\n                const mipHeight = size * Math.pow(0.5, mip);\n                // Attach one face of cube map\n                const fboId = gl.createFramebuffer();\n                gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fboId);\n                gl.viewport(0, 0, mipWidth, mipHeight); // Match the viewport to the texture size\n                const roughness = mip / (maxMipLevels - 1);\n                gl.uniform1f(unifs.roughness.location, roughness);\n                for (let i = 0; i < 6; ++i) {\n                    gl.uniform1i(unifs.faceId.location, i);\n                    gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, this.specularCubetex, mip);\n                    gl.drawQuad();\n                }\n                gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);\n                gl.deleteFramebuffer(fboId);\n            }\n            convolverShader.destroy();\n        }\n        this.convolved = true;\n    }\n    /**\n     * The bind method.\n     * @param renderstate - The object tracking the current state of the renderer\n     * @param unif - The WebGL uniform\n     * @return - Returns true if the Probe was successfully bound.\n     */\n    bind(renderstate) {\n        const gl = this.gl;\n        const { irradianceMap, prefilterMap, brdfLUT, envMapFlags } = renderstate.unifs;\n        if (!this.convolved) {\n            // By default, all the texture units are bound to unit:0\n            // So if a shader contains cube maps, and they are left on unit 0\n            // and also the shader contains regular textures, and they are also left on unit 0\n            // then we get errors saying:\n            // GL_INVALID_OPERATION: Two textures of different types use the same sampler location.\n            // So bind to an unused texture unit...\n            if (irradianceMap) {\n                gl.uniform1i(irradianceMap.location, this.maxFragmentShaderTextureUnits - 1);\n            }\n            if (prefilterMap) {\n                gl.uniform1i(prefilterMap.location, this.maxFragmentShaderTextureUnits - 1);\n            }\n            if (envMapFlags) {\n                gl.uniform1i(envMapFlags.location, -1);\n            }\n            return false;\n        }\n        // Note: a cube map can never be bound to texture unit 0.\n        // This is because if any other samplers are left unbound\n        // (e.g. a diffuse sampler left unbound because no diffuse texture is assigned)\n        // then the texture unit binding defaults to 0.\n        // If the cube map is then bound to unit 0, then we get the error message:\n        // GL_INVALID_OPERATION: Two textures of different types use the same sampler location.\n        // Ths simple workaround here is to bind the BRDF Lut first, which is a TEXTURE_2D, and the cube maps\n        // to other units:(1 & 2).\n        // This error started occuring when we moved PBR binding to the shader instead of in the renderer.\n        // See: StandardSurfaceShader.bind\n        if (brdfLUT) {\n            const unit = renderstate.boundTextures++;\n            gl.activeTexture(this.gl.TEXTURE0 + unit);\n            gl.bindTexture(gl.TEXTURE_2D, this.brdfLUTTexture);\n            gl.uniform1i(brdfLUT.location, unit);\n        }\n        if (irradianceMap) {\n            const unit = renderstate.boundTextures++;\n            const texId = this.gl.TEXTURE0 + unit;\n            gl.activeTexture(texId);\n            gl.bindTexture(gl.TEXTURE_CUBE_MAP, this.irradianceCubeTex);\n            gl.uniform1i(irradianceMap.location, unit);\n        }\n        if (prefilterMap) {\n            const unit = renderstate.boundTextures++;\n            const texId = this.gl.TEXTURE0 + unit;\n            gl.activeTexture(texId);\n            gl.bindTexture(gl.TEXTURE_CUBE_MAP, this.specularCubetex);\n            gl.uniform1i(prefilterMap.location, unit);\n        }\n        if (envMapFlags) {\n            gl.uniform1i(envMapFlags.location, 0);\n        }\n        return true;\n    }\n    /**\n     * The destroy is called by the system to cause explicit resources cleanup.\n     * Users should never need to call this method directly.\n     */\n    destroy() {\n        // super.destroy()\n    }\n}\n\nvar frag$a = \"\\nprecision highp float;\\n#define GLSLIFY 1\\n\\nimport 'GLSLUtils.glsl'\\nimport 'gamma.glsl'\\nimport 'constants.glsl'\\n\\nuniform float focus;\\nuniform float exposure;\\n\\n/* VS Outputs */\\nvarying vec3 v_worldDir;\\nvarying vec2 v_texCoord;\\n\\n#define ENABLE_INLINE_GAMMACORRECTION\\n\\n#define ENV_MAP_LATLONG 0\\n#define ENV_MAP_OCT 1\\n#define ENV_MAP_CUBE 2\\n#define ENV_MAP_irradianceMap 8\\n#define ENV_MAP_prefilterMap 3\\n#define ENV_MAP_STEREO_LATLONG 4\\n#define ENV_MAP_DUALFISHEYE 5\\n#define ENV_MAP_SH 6\\n#define ENV_MAP_BRDF_LUT 7\\n\\n#define ENV_MAPTYPE ENV_MAP_OCT\\n\\n#if (ENV_MAPTYPE == ENV_MAP_LATLONG)  \\n\\nimport 'envmap-equirect.glsl'\\n\\nuniform sampler2D backgroundImage;\\n\\nvec4 sampleEnvMap(vec3 dir) {\\n  vec2 uv = latLongUVsFromDir(normalize(dir));\\n  vec4 texel = texture2D(backgroundImage, uv) * exposure;\\n  return vec4(texel.rgb/texel.a, 1.0);\\n}\\n\\n#elif (ENV_MAPTYPE == ENV_MAP_OCT)  \\n\\nimport 'envmap-octahedral.glsl'\\n\\nuniform sampler2D   envMap;\\n\\nvec4 sampleEnvMap(vec3 dir) {\\n  vec2 uv = dirToSphOctUv(normalize(dir));\\n  if (false) {\\n    vec4 texel = texture2D(envMap, uv);\\n    return vec4(texel.rgb/texel.a, 1.0);\\n  }\\n  else {\\n    return texture2D(envMap, uv) * exposure;\\n  }\\n}\\n\\n#elif (ENV_MAPTYPE == ENV_MAP_CUBE)\\n\\nuniform samplerCube cubeMap;\\n\\nvec4 sampleEnvMap(vec3 dir) {\\n  return texture(cubeMap, dir, 0.0);// * exposure;\\n  // return textureLod(cubeMap, dir, exposure);\\n}\\n\\n#elif (ENV_MAPTYPE == ENV_MAP_irradianceMap)\\n\\nuniform samplerCube irradianceMap;\\n\\nvec4 sampleEnvMap(vec3 dir) {\\n  return textureLod(irradianceMap, dir, exposure);\\n}\\n\\n#elif (ENV_MAPTYPE == ENV_MAP_prefilterMap)\\n\\nuniform samplerCube prefilterMap;\\n\\nvec4 sampleEnvMap(vec3 dir) {\\n  return textureLod(prefilterMap, dir, exposure);\\n}\\n\\n#elif (ENV_MAPTYPE == ENV_MAP_STEREO_LATLONG)  \\n\\nimport 'envmap-equirect.glsl'\\nuniform int eye;// L = 0, R = 1;\\nuniform sampler2D backgroundImage;\\n\\nvec4 sampleEnvMap(vec3 dir) {\\n  vec2 uv = latLongUVsFromDir(normalize(v_worldDir));\\n  uv.y *= 0.5;\\n  if (eye == 1) {\\n    uv.y += 0.5;\\n  }\\n  vec4 texel = texture2D(backgroundImage, uv) * exposure;\\n  fragColor = vec4(texel.rgb/texel.a, 1.0);\\n}\\n\\n#elif (ENV_MAPTYPE == ENV_MAP_DUALFISHEYE)\\n\\nimport 'envmap-dualfisheye.glsl'\\n\\nvec4 sampleEnvMap(vec3 dir) {\\n  vec2 uv = dualfisheyeUVsFromDir(dir);\\n  return texture2D(backgroundImage, uv) * exposure;\\n}\\n\\n#elif (ENV_MAPTYPE == ENV_MAP_SH)\\n\\nimport 'SHCoeffs.glsl'\\n\\nvec4 sampleEnvMap(vec3 dir) {\\n\\treturn vec4(sampleSHCoeffs(dir) * exposure, 1.0);\\n}\\n\\n#elif (ENV_MAPTYPE == ENV_MAP_BRDF_LUT)\\n\\nuniform sampler2D brdfLUT;\\n\\nvec4 sampleEnvMap(vec3 dir) {\\n  return texture2D(brdfLUT, v_texCoord);\\n}\\n#endif\\n\\n#ifdef ENABLE_ES3\\n  out vec4 fragColor;\\n#endif\\n\\nvoid main(void) {\\n#ifndef ENABLE_ES3\\n  vec4 fragColor;\\n#endif\\n\\n  fragColor = sampleEnvMap(normalize(v_worldDir));\\n  fragColor.a = 1.0;\\n\\n#ifdef ENABLE_INLINE_GAMMACORRECTION\\n  fragColor.rgb = toGamma(fragColor.rgb);\\n#endif\\n\\n#ifndef ENABLE_ES3\\n  gl_FragColor = fragColor;\\n#endif\\n}\\n\"; // eslint-disable-line\n\nvar vert$b = \"\\nprecision highp float;\\n#define GLSLIFY 1\\n\\nimport 'quadVertexFromID.glsl'\\n\\nuniform mat4 projectionMatrix;\\nuniform mat4 viewMatrix;\\n\\nimport 'inverse.glsl'\\nimport 'transpose.glsl'\\n\\n/* VS Outputs */\\nvarying vec3 v_worldDir;\\nvarying vec2 v_texCoord;\\n \\nvoid main()\\n{\\n  vec2 position = getQuadVertexPositionFromID() * 2.0;\\n  v_texCoord = position * 0.5 + 0.5;\\n\\n  mat4 inverseProjection = inverse(projectionMatrix);\\n  mat3 inverseModelview = transpose(mat3(viewMatrix));\\n\\n  // transform from the normalized device coordinates back to the view space\\n  vec3 unprojected = (inverseProjection * vec4(position, 0, 1)).xyz;\\n\\n  // transfrom from the view space back to the world space\\n  // and use it as a sampling vector\\n  v_worldDir = inverseModelview * unprojected;\\n\\n  gl_Position = vec4(position, 0, 1);\\n}\\n\"; // eslint-disable-line\n\n/* eslint-disable require-jsdoc */\nclass EnvMapShader extends GLShader {\n    /**\n     * Create a GL shader.\n     * @param gl - The webgl rendering context.\n     */\n    constructor(gl) {\n        super(gl, 'EnvMapShader');\n        this.setShaderStage('VERTEX_SHADER', vert$b);\n        this.setShaderStage('FRAGMENT_SHADER', frag$a);\n    }\n}\n\n/** Class representing a GL environment map.\n * @extends GLProbe\n * @private\n */\nclass GLEnvMap extends GLProbe {\n    renderer;\n    envMap;\n    backgroundFocus;\n    srcGLTex = null;\n    envMapShader = null;\n    envMapShaderBinding = null;\n    /**\n     * Create a GL env map.\n     * @param renderer - The renderer value.\n     * @param envMap - The environment map.\n     */\n    constructor(renderer, envMap) {\n        super(renderer.gl, 'EnvMap');\n        this.renderer = renderer;\n        this.envMap = envMap;\n        this.backgroundFocus = 0.0;\n        if (this.envMap.isLoaded()) {\n            this.init();\n        }\n        else {\n            this.envMap.once('loaded', (event) => {\n                this.init();\n            });\n        }\n    }\n    get glTex() {\n        return this.srcGLTex;\n    }\n    /**\n     * @private\n     */\n    init() {\n        const gl = this.renderer.gl;\n        if (!gl.__quadVertexIdsBuffer)\n            gl.setupInstancedQuad();\n        this.srcGLTex = new GLHDRImage(gl, this.envMap);\n        this.envMapShader = new EnvMapShader(gl);\n        const envMapShaderComp = this.envMapShader.compileForTarget('GLEnvMap', ['#define ENABLE_ES3']);\n        this.envMapShaderBinding = generateShaderGeomBinding(gl, envMapShaderComp.attrs, gl.__quadattrbuffers, gl.__quadIndexBuffer);\n        const headlightParam = this.envMap.headlightModeParam;\n        const updateHeadlightModeFlag = () => {\n            const ENVMAP_FLAG_HEADLIGHT = 1; // 1<<0;\n            if (headlightParam.value) {\n                this.textureDesc[3] |= ENVMAP_FLAG_HEADLIGHT;\n            }\n            else {\n                this.textureDesc[3] &= ~ENVMAP_FLAG_HEADLIGHT;\n            }\n        };\n        updateHeadlightModeFlag();\n        headlightParam.on('valueChanged', () => {\n            updateHeadlightModeFlag();\n            this.emit('updated');\n        });\n        this.convolveProbe(this.srcGLTex);\n        this.emit('updated');\n    }\n    /**\n     * The getEnvMap method.\n     * @return - The return value.\n     */\n    getEnvMap() {\n        return this.envMap;\n    }\n    /**\n     * The getBackgroundFocus method.\n     * @return - The return value.\n     */\n    getBackgroundFocus() {\n        return this.backgroundFocus;\n    }\n    /**\n     * The setBackgroundFocus method.\n     * @param val - The val param.\n     */\n    setBackgroundFocus(val) {\n        this.backgroundFocus = val;\n        this.renderer.requestRedraw();\n    }\n    /**\n     * The draw method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    draw(renderstate) {\n        if (this.envMap.isLoaded()) {\n            const gl = this.gl;\n            {\n                // /////////////////\n                this.envMapShader.bind(renderstate, 'GLEnvMap');\n                const unifs = renderstate.unifs;\n                const { envMap, focus, exposure } = renderstate.unifs;\n                if (envMap) {\n                    this.srcGLTex.bindToUniform(renderstate, envMap);\n                }\n                if (focus)\n                    gl.uniform1f(focus.location, this.backgroundFocus);\n                if (exposure)\n                    gl.uniform1f(exposure.location, renderstate.exposure);\n                this.envMapShaderBinding.bind(renderstate);\n                gl.depthMask(false);\n                renderstate.bindViewports(unifs, () => {\n                    gl.drawQuad();\n                });\n                gl.depthMask(true);\n            }\n        }\n    }\n    /**\n     * The destroy is called by the system to cause explicit resources cleanup.\n     * Users should never need to call this method directly.\n     */\n    destroy() {\n        super.destroy();\n        if (this.srcGLTex)\n            this.srcGLTex.destroy();\n    }\n}\n\nconst ALL_PASSES = PassType.OPAQUE | PassType.TRANSPARENT | PassType.OVERLAY;\n// TODO: move this fn somewhere\n/** Class representing a GL renderer.\n * @extends GLBaseRenderer\n */\nclass GLRenderer extends GLBaseRenderer {\n    #exposure = 1.0;\n    #gamma = 2.2;\n    #glEnvMap = null;\n    #glBackgroundMap;\n    #displayEnvironment;\n    highlightOutlineThickness = 1;\n    renderMode = 'pbr';\n    outlineMethod = 'geometry';\n    outlineThickness = 0;\n    outlineColor = new Color(0.15, 0.15, 0.15, 1);\n    hiddenLineColor = new Color(0.15, 0.15, 0.15, 0.0);\n    outlineSensitivity = 2;\n    outlineDepthBias = 0.7;\n    #rayCastDist;\n    #rayCastArea;\n    #rayCastRenderTarget = null;\n    #backgroundMapShader = null;\n    #backgroundMapShaderBinding = null;\n    #rayCastRenderTargetProjMatrix = new Mat4();\n    /**\n     * Create a GL renderer.\n     * @param $canvas - The $canvas value.\n     * @param options - The dictionary of options.\n     */\n    constructor($canvas, options = {}) {\n        // use HTMLCanvasElement?\n        super($canvas, options);\n        // ///////////////////////\n        // Renderer Setup\n        this.#exposure = 1.0;\n        this.#gamma = 2.2;\n        this.#displayEnvironment = true;\n        this.#rayCastDist = 0;\n        this.#rayCastArea = 0;\n        this.setShaderPreprocessorDirective('ENABLE_GAMMACORRECTION', '#define ENABLE_INLINE_GAMMACORRECTION');\n        if (!options.disableTextures) {\n            this.setShaderPreprocessorDirective('ENABLE_TEXTURES', '#define ENABLE_TEXTURES');\n        }\n        if (options.debugGeomIds) {\n            this.setShaderPreprocessorDirective('DEBUG_GEOM_ID', '#define DEBUG_GEOM_ID');\n        }\n    }\n    /**\n     * The __bindEnvMap method.\n     * @param env - The env value.\n     * @private\n     */\n    __bindEnvMap(env) {\n        const gl = this.__gl;\n        if (env instanceof EnvMap) {\n            // Note: Safari doesn't support rendering to floating\n            // point textures, so our PBR lighting pipeline doesn't work.\n            if (gl.name !== 'webgl2') {\n                return;\n            }\n            if (env.type === 'FLOAT') {\n                this.setShaderPreprocessorDirective('ENABLE_PBR', '#define ENABLE_PBR');\n                this.#glEnvMap = new GLEnvMap(this, env);\n            }\n            // } else if (env.isStreamAtlas()) { // TODO: are these two lines still needed?\n            //   this.#glEnvMap = new GLImageStream(gl, env)\n            // else {\n            //   this.#glEnvMap = new GLTexture2D(this.__gl, env)\n            // }\n        }\n        else {\n            // Note: The difference between an EnvMap and a BackgroundMap, is that\n            // An EnvMap must be HDR, and can be convolved for reflections.\n            // A Background map can be simply an image.\n            const backgroundMap = env;\n            if (backgroundMap.type === 'HDR') {\n                this.#glBackgroundMap = new GLHDRImage(this.__gl, backgroundMap); // todo: is this cast ok?\n            }\n            else {\n                this.#glBackgroundMap = new GLTexture2D(this.__gl, backgroundMap);\n            }\n            this.#glBackgroundMap.on('loaded', () => {\n                this.requestRedraw();\n            });\n            this.#glBackgroundMap.on('updated', () => {\n                this.requestRedraw();\n            });\n            if (!this.#backgroundMapShader) {\n                if (!gl.__quadVertexIdsBuffer)\n                    gl.setupInstancedQuad();\n                this.#backgroundMapShader = new EnvMapShader(this.__gl);\n                // switch (backgroundMap.getMapping()) {\n                //   case 'octahedral':\n                //     break\n                //   case 'latlong':\n                //     break\n                //   case 'steriolatlong':\n                //     break\n                //   case 'dualfisheye':\n                //     break\n                //   case 'uv':\n                //   default:\n                //     break\n                // }\n                const shaderComp = this.#backgroundMapShader.compileForTarget('key', []);\n                this.#backgroundMapShaderBinding = generateShaderGeomBinding(this.__gl, shaderComp.attrs, gl.__quadattrbuffers, gl.__quadIndexBuffer);\n            }\n            // console.warn('Unsupported EnvMap:' + env)\n            return;\n        }\n        this.#glEnvMap.on('loaded', (event) => {\n            this.requestRedraw();\n        });\n        this.#glEnvMap.on('updated', (event) => {\n            this.requestRedraw();\n        });\n        const event = new EnvMapAssignedEvent(this.#glEnvMap);\n        this.emit('envMapAssigned', event);\n    }\n    /**\n     * The setScene method.\n     * @param scene - The scene value.\n     */\n    setScene(scene) {\n        const envMapParam = scene.envMapParam;\n        if (envMapParam.value != undefined) {\n            this.__bindEnvMap(envMapParam.value);\n        }\n        envMapParam.on('valueChanged', () => {\n            this.__bindEnvMap(envMapParam.value);\n        });\n        const displayEnvMapParam = scene.displayEnvMapParam;\n        this.#displayEnvironment = displayEnvMapParam.value;\n        displayEnvMapParam.on('valueChanged', () => {\n            this.#displayEnvironment = displayEnvMapParam.value;\n            this.requestRedraw();\n        });\n        super.setScene(scene);\n    }\n    /**\n     * The addViewport method.\n     * @param name - The name value.\n     * @return - The return value.\n     */\n    addViewport(name) {\n        const vp = super.addViewport(name);\n        return vp;\n    }\n    // //////////////////////////\n    // GUI\n    /**\n     * Getter for exposure.\n     * @return exposure\n     */\n    get exposure() {\n        return this.#exposure;\n    }\n    /**\n     * Setter for exposure.\n     * @param val - The val value.\n     */\n    set exposure(val) {\n        this.#exposure = val;\n        this.requestRedraw();\n    }\n    /**\n     * Getter for gamma.\n     */\n    get gamma() {\n        return this.#gamma;\n    }\n    /**\n     * Setter for gamma.\n     * @param val - The val value.\n     */\n    set gamma(val) {\n        this.#gamma = val;\n        this.requestRedraw();\n    }\n    /**\n     * Getter for displayEnvironment.\n     */\n    get displayEnvironment() {\n        return this.#displayEnvironment;\n    }\n    /**\n     * Setter for displayEnvironment.\n     * @param val - The val value.\n     */\n    set displayEnvironment(val) {\n        this.#displayEnvironment = val;\n        this.requestRedraw();\n    }\n    // //////////////////////////\n    // Raycasting\n    bindRaycastViewport(renderstate, viewXfo, projectionMatrixMat4) {\n        const region = [0, 0, 3, 3];\n        renderstate.viewXfo = viewXfo;\n        renderstate.cameraMatrix = viewXfo.toMat4();\n        renderstate.viewScale = 1.0;\n        renderstate.region = region;\n        const viewMatrixMat4 = renderstate.cameraMatrix.inverse();\n        const gl = this.gl;\n        renderstate.bindRendererUnifs = (unifs) => {\n            const { cameraMatrix, viewMatrix, projectionMatrix, eye, isOrthographic, viewportFrustum } = unifs;\n            if (cameraMatrix) {\n                gl.uniformMatrix4fv(cameraMatrix.location, false, renderstate.cameraMatrix.asArray());\n            }\n            if (viewMatrix) {\n                gl.uniformMatrix4fv(viewMatrix.location, false, viewMatrixMat4.asArray());\n            }\n            if (projectionMatrix) {\n                gl.uniformMatrix4fv(projectionMatrix.location, false, projectionMatrixMat4.asArray());\n            }\n            if (eye) {\n                gl.uniform1i(eye.location, 0);\n            }\n            if (isOrthographic) {\n                gl.uniform1i(isOrthographic.location, 1);\n            }\n        };\n        renderstate.bindViewports = (unifs, draw) => draw();\n    }\n    /**\n     * Ray casting is implemented by rendering a small image from the position of the ray, and capturing geometries detected in the resulting image.\n     * This method takes a Ray value, and uses that base the ray cast operation.\n     *\n     * @param ray - The ray to use in the raycast.\n     * @param dist - The maximum distance to cast the ray\n     * @param area - The area to use for the ray\n     * @param mask - The mask to filter our certain pass types. Can be PassType.OPAQUE | PassType.TRANSPARENT | PassType.OVERLAY\n     * @return - The object containing the ray cast results.\n     */\n    raycastWithRay(ray, dist, area = 0.01, mask = ALL_PASSES) {\n        const xfo = new Xfo();\n        xfo.setLookAt(ray.start, ray.start.add(ray.dir), new Vec3(0, 0, 1));\n        return this.raycast(xfo, ray, dist, area, mask);\n    }\n    /**\n     * Ray casting is implemented by rendering a small image from the position of the ray, and capturing geometries detected in the resulting image.\n     * This method takes an Xfo value, and uses that base the ray cast operation.\n     *\n     * @param xfo - The xfo to use in the raycast.\n     * @param dist - The maximum distance to cast the ray\n     * @param area - The area to use for the ray\n     * @param mask - The mask to filter our certain pass types. Can be PassType.OPAQUE | PassType.TRANSPARENT | PassType.OVERLAY\n     * @return - The object containing the ray cast results.\n     */\n    raycastWithXfo(xfo, dist, area = 0.01, mask = ALL_PASSES) {\n        const ray = new Ray(xfo.tr, xfo.ori.getZaxis().negate());\n        return this.raycast(xfo, ray, dist, area, mask);\n    }\n    /**\n     * Ray casting is implemented by rendering a small image from the position of the ray, and capturing geometries detected in the resulting image.\n     *\n     * @private\n     *\n     * @param xfo - The xfo to use in the raycast.\n     * @param ray - The ray to use in the raycast.\n     * @param dist - The maximum distance to cast the ray\n     * @param area - The area to use for the ray\n     * @param mask - The mask to filter our certain pass types. Can be PassType.OPAQUE | PassType.TRANSPARENT | PassType.OVERLAY\n     * @return - The object containing the ray cast results.\n     */\n    raycast(xfo, ray, dist, area = 0.01, mask = ALL_PASSES) {\n        if (this.#rayCastDist != dist || this.#rayCastArea != area) {\n            this.#rayCastRenderTargetProjMatrix.setOrthographicMatrix(area * -0.5, area * 0.5, area * -0.5, area * 0.5, 0.0, dist);\n            this.#rayCastDist = dist;\n            this.#rayCastArea = area;\n        }\n        return this.raycastWithProjection(xfo, this.#rayCastRenderTargetProjMatrix, ray, mask);\n    }\n    /**\n     * Ray casting is implemented by rendering a small image from the position of the ray, and capturing geometries detected in the resulting image.\n     *\n     * @private\n     *\n     * @param viewXfo - The xfo to use in the raycast.\n     * @param projectionMatrix - The projectionMatrix to use in the raycast.\n     * @param ray - The ray to use in the raycast.\n     * @param mask - The mask to filter our certain pass types. Can be PassType.OPAQUE | PassType.TRANSPARENT | PassType.OVERLAY\n     * @return - The object containing the ray cast results.\n     */\n    raycastWithProjection(viewXfo, projectionMatrix, ray, mask = ALL_PASSES) {\n        const renderstate = new GeomDataRenderState(this.__gl);\n        this.bindRaycastViewport(renderstate, viewXfo, projectionMatrix);\n        const gl = this.__gl;\n        if (!this.#rayCastRenderTarget) {\n            this.#rayCastRenderTarget = new GLRenderTarget(gl, {\n                type: gl.FLOAT,\n                format: gl.RGBA,\n                filter: gl.NEAREST,\n                createDepthTexture: true,\n                width: 3,\n                height: 3,\n                numColorChannels: 1,\n            });\n        }\n        this.#rayCastRenderTarget.bindForWriting(renderstate, true);\n        gl.enable(gl.CULL_FACE);\n        gl.enable(gl.DEPTH_TEST);\n        gl.depthFunc(gl.LEQUAL);\n        gl.depthMask(true);\n        this.drawSceneGeomData(renderstate, mask);\n        gl.finish();\n        this.#rayCastRenderTarget.unbindForWriting();\n        this.#rayCastRenderTarget.bindForReading();\n        const geomDatas = new Float32Array(4 * 9);\n        gl.readPixels(0, 0, 3, 3, gl.RGBA, gl.FLOAT, geomDatas);\n        this.#rayCastRenderTarget.unbindForReading();\n        // ////////////////////////////////////\n        // We have a 3x3 grid of pixels, and we\n        // scan them to find if any geom was in the\n        // frustum.\n        // Starting with the center pixel (4),\n        // then left and right (3, 5)\n        // Then top bottom (1, 7)\n        const checkPixel = (id) => geomDatas[id * 4 + 3] != 0;\n        const dataPixels = [4, 3, 5, 1, 7];\n        let geomData;\n        for (const pixelID of dataPixels) {\n            if (checkPixel(pixelID)) {\n                geomData = geomDatas.subarray(pixelID * 4, pixelID * 4 + 4);\n                break;\n            }\n        }\n        if (!geomData)\n            return null;\n        // Mask the pass id to be only the first 6 bits of the integer.\n        const passId = Math.round(geomData[0]) & (64 - 1);\n        const geomItemAndDist = this.getPass(passId)?.getGeomItemAndDist(geomData);\n        if (geomItemAndDist) {\n            const intersectionPos = ray.start.add(ray.dir.scale(geomItemAndDist.dist));\n            return {\n                pointerRay: ray,\n                intersectionPos,\n                geomItem: geomItemAndDist.geomItem,\n                componentId: -1,\n                dist: geomItemAndDist.dist,\n                geomData,\n            };\n        }\n        else {\n            return null;\n        }\n    }\n    /**\n     *\n     * @private\n     *\n     * @param xfo - The ray to use in the raycast.\n     * @param ray - The ray to use in the raycast.\n     * @param dist - The maximum distance to cast the ray\n     * @param area - The area to use for the ray\n     * @param mask - The mask to filter our certain pass types. Can be PassType.OPAQUE | PassType.TRANSPARENT | PassType.OVERLAY\n     * @return - The object containing the ray cast results.\n     */\n    raycastCluster(xfo, ray, dist, area = 0.01, mask = ALL_PASSES) {\n        const gl = this.__gl;\n        const renderstate = new GeomDataRenderState(this.__gl);\n        this.bindRaycastViewport(renderstate, xfo, this.#rayCastRenderTargetProjMatrix);\n        if (!this.#rayCastRenderTarget) {\n            this.#rayCastRenderTarget = new GLRenderTarget(gl, {\n                type: 'FLOAT',\n                format: 'RGBA',\n                filter: 'NEAREST',\n                createDepthTexture: true,\n                width: 3,\n                height: 3,\n                numColorChannels: 1,\n            });\n            this.#rayCastRenderTargetProjMatrix = new Mat4();\n        }\n        if (this.#rayCastDist != dist || this.#rayCastArea != area) {\n            this.#rayCastRenderTargetProjMatrix.setOrthographicMatrix(area * -0.5, area * 0.5, area * -0.5, area * 0.5, 0.0, dist);\n            this.#rayCastDist = dist;\n            this.#rayCastArea = area;\n        }\n        this.#rayCastRenderTarget.bindForWriting(renderstate, true);\n        gl.enable(gl.CULL_FACE);\n        gl.enable(gl.DEPTH_TEST);\n        gl.depthFunc(gl.LEQUAL);\n        gl.depthMask(true);\n        this.drawSceneGeomData(renderstate, mask);\n        gl.finish();\n        this.#rayCastRenderTarget.unbindForWriting();\n        this.#rayCastRenderTarget.bindForReading();\n        const geomDatas = new Float32Array(4 * 9);\n        gl.readPixels(0, 0, 3, 3, gl.RGBA, gl.FLOAT, geomDatas);\n        this.#rayCastRenderTarget.unbindForReading();\n        // ////////////////////////////////////\n        // We have a 3x3 grid of pixels, and we\n        // scan them to find if any geom was in the\n        // frustum.\n        // Note: we return every intersection, because even multiple intersections\n        // on the same geometry will be at different distances.\n        // This method is often used to get an average distance.\n        const checkPixel = (id) => geomDatas[id * 4 + 3] != 0;\n        const result = [];\n        for (let i = 0; i < 9; i++) {\n            if (checkPixel(i)) {\n                const geomData = geomDatas.subarray(i * 4, i * 4 + 4);\n                // Mask the pass id to be only the first 6 bits of the integer.\n                const passId = Math.round(geomData[0]) & (64 - 1);\n                const pass = this.getPass(passId);\n                if (pass) {\n                    const geomItemAndDist = pass.getGeomItemAndDist(geomData);\n                    if (geomItemAndDist) {\n                        const intersectionPos = ray.start.add(ray.dir.scale(geomItemAndDist.dist));\n                        result.push({\n                            pointerRay: ray,\n                            intersectionPos,\n                            geomItem: geomItemAndDist.geomItem,\n                            componentId: -1,\n                            dist: geomItemAndDist.dist,\n                            geomData,\n                        });\n                    }\n                }\n            }\n        }\n        return result;\n    }\n    // //////////////////////////\n    // Rendering\n    /**\n     * The drawBackground method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    drawBackground(renderstate) {\n        if (this.#glBackgroundMap && this.#backgroundMapShader && this.#backgroundMapShaderBinding) {\n            if (!this.#glBackgroundMap.isLoaded())\n                return;\n            const gl = this.__gl;\n            gl.depthMask(false);\n            this.#backgroundMapShader.bind(renderstate);\n            const unifs = renderstate.unifs;\n            this.#glBackgroundMap.bindToUniform(renderstate, unifs.backgroundImage);\n            this.#backgroundMapShaderBinding.bind(renderstate);\n            gl.drawQuad();\n        }\n        else if (this.#glEnvMap && this.#glEnvMap.draw /* Note: video env maps cannot be drawn directly.*/) {\n            this.#glEnvMap.draw(renderstate);\n        }\n    }\n    /**\n     * The bindGLRenderer method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    bindGLRenderer(renderstate) {\n        super.bindGLRenderer(renderstate);\n        if (renderstate instanceof ColorRenderState) {\n            renderstate.envMap = this.#glEnvMap;\n            renderstate.exposure = this.#exposure;\n            renderstate.renderMode = this.renderMode;\n            renderstate.outlineThickness = this.outlineThickness;\n            renderstate.outlineColor = this.outlineColor;\n            renderstate.hiddenLineColor = this.hiddenLineColor;\n            renderstate.outlineMethod = this.outlineMethod;\n            renderstate.screenQuad = this.screenQuad;\n        }\n    }\n    /**\n     * The drawScene method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    drawScene(renderstate) {\n        this.bindGLRenderer(renderstate);\n        if (this.#displayEnvironment)\n            this.drawBackground(renderstate);\n        super.drawScene(renderstate);\n        // console.log(\"Draw Calls:\" + renderstate['drawCalls']);\n    }\n}\n\n/** This class abstracts the rendering of a collection of geometries to screen.\n * @extends EventEmitter\n * @private\n */\nclass GLGeomItemSetMultiDraw extends EventEmitter {\n    renderer;\n    gl;\n    glGeomItems = [];\n    glGeomIdsMapping = {};\n    glgeomItemEventHandlers = [];\n    freeIndices = [];\n    // The last camera position from which the data was sorted\n    viewPos = new Vec3();\n    // Mapping from the array of glGeomItems, to the actual rendering\n    // order. When rendering transparent geoms, we sort this array.\n    // Mapping from the array of glGeomItems, to the actual rendering\n    // order. When rendering transparent geoms, we sort this array.\n    drawElementCounts = new Int32Array(0);\n    drawElementOffsets = new Int32Array(0);\n    highlightElementCounts = new Int32Array(0);\n    highlightElementOffsets = new Int32Array(0);\n    drawOrderToIndex = [];\n    indexToDrawIndex = [];\n    drawIdsArray = new Float32Array(0);\n    drawIdsBufferDirty = true;\n    drawIdsTexture = null;\n    highlightedItems = [];\n    highlightedIdsArray = null;\n    highlightedIdsTexture = null;\n    highlightedIdsBufferDirty = false;\n    // When a geometry changes, we update offset and count the values.\n    dirtyGeomIndices = new Set();\n    /**\n     * Create a GL geom item set.\n     * @param renderer - The renderer object.\n     */\n    constructor(renderer) {\n        super();\n        this.renderer = renderer;\n        this.gl = renderer.gl;\n        this.renderer.glGeomLibrary.on('geomDataChanged', (event) => {\n            const geomItemIndices = this.glGeomIdsMapping[event.index];\n            if (geomItemIndices != undefined) {\n                this.dirtyGeomIndices.add(event.index);\n            }\n        });\n    }\n    /**\n     * The addGLGeomItem method.\n     * @param glGeomItem - The glGeomItem value.\n     */\n    addGLGeomItem(glGeomItem) {\n        const index = this.freeIndices.length > 0 ? this.freeIndices.pop() : this.glGeomItems.length;\n        // Note: we now allocate the draw index right away.\n        // Visibility only controls the element count value\n        this.indexToDrawIndex[index] = this.drawOrderToIndex.length;\n        this.drawOrderToIndex.push(index);\n        const eventHandlers = {};\n        // //////////////////////////////\n        // Visibility\n        eventHandlers.visibilityChanged = (event) => {\n            const drawIndex = this.indexToDrawIndex[index];\n            if (event.state) {\n                const offsetAndCount = this.renderer.glGeomLibrary.getGeomOffsetAndCount(glGeomItem.geomId);\n                this.drawElementCounts[drawIndex] = offsetAndCount[1];\n            }\n            else {\n                this.drawElementCounts[drawIndex] = 0;\n            }\n            this.emit('updated');\n        };\n        glGeomItem.on('visibilityChanged', eventHandlers.visibilityChanged);\n        // //////////////////////////////\n        // Highlighted\n        if (glGeomItem.geomItem.isHighlighted()) {\n            this.highlightedItems.push(glGeomItem);\n            this.highlightedIdsBufferDirty = true;\n        }\n        eventHandlers.highlightChanged = (event) => {\n            if (event && event.name) {\n                // Note: highlightChanged is fired when the color changes\n                // or another highlight is added over the top. We avoid\n                // adding the same index again here. (TODO: use Set?)\n                if (this.highlightedItems.includes(glGeomItem))\n                    return;\n                this.highlightedItems.push(glGeomItem);\n            }\n            else {\n                this.highlightedItems.splice(this.highlightedItems.indexOf(glGeomItem), 1);\n            }\n            // console.log(\"highlightChanged:\", glGeomItem.geomItem.getName(), glGeomItem.geomItem.isHighlighted(), this.highlightedItems)\n            this.highlightedIdsBufferDirty = true;\n            this.emit('updated');\n        };\n        glGeomItem.geomItem.on('highlightChanged', eventHandlers.highlightChanged);\n        // //////////////////////////////\n        // Geometry\n        const geomParam = glGeomItem.geomItem.geomParam;\n        let geom = geomParam.value;\n        glGeomItem.geomId = this.renderer.glGeomLibrary.addGeom(geom);\n        // Keep track of which geomitems use which geoms, so we can update the offset and count array if they change.\n        if (!this.glGeomIdsMapping[glGeomItem.geomId]) {\n            this.glGeomIdsMapping[glGeomItem.geomId] = [index];\n        }\n        else {\n            this.glGeomIdsMapping[glGeomItem.geomId].push(index);\n        }\n        this.glGeomItems[index] = glGeomItem;\n        this.glgeomItemEventHandlers[index] = eventHandlers;\n        this.drawIdsBufferDirty = true;\n        this.emit('updated');\n    }\n    /**\n     * The removeGLGeomItem method.\n     * @param glGeomItem - The glGeomItem value.\n     */\n    removeGLGeomItem(glGeomItem) {\n        const index = this.glGeomItems.indexOf(glGeomItem);\n        const geom = this.renderer.glGeomLibrary.getGeom(glGeomItem.geomId);\n        this.renderer.glGeomLibrary.removeGeom(geom);\n        const geomItemIndices = this.glGeomIdsMapping[glGeomItem.geomId];\n        geomItemIndices.splice(geomItemIndices.indexOf(index), 1);\n        if (geomItemIndices.length == 0) {\n            delete this.glGeomIdsMapping[glGeomItem.geomId];\n            if (this.dirtyGeomIndices.has(glGeomItem.geomId))\n                this.dirtyGeomIndices.delete(glGeomItem.geomId);\n        }\n        const eventHandlers = this.glgeomItemEventHandlers[index];\n        glGeomItem.geomItem.off('highlightChanged', eventHandlers.highlightChanged);\n        glGeomItem.off('visibilityChanged', eventHandlers.visibilityChanged);\n        this.glGeomItems[index] = null;\n        this.glgeomItemEventHandlers[index] = null;\n        this.drawIdsArray[index] = 0;\n        this.freeIndices.push(index);\n        const drawIndex = this.drawOrderToIndex.indexOf(index);\n        this.drawOrderToIndex.splice(drawIndex, 1);\n        this.indexToDrawIndex[index] = -1;\n        this.drawElementOffsets[drawIndex] = 0;\n        this.drawElementCounts[drawIndex] = 0;\n        this.drawIdsBufferDirty = true;\n        if (glGeomItem.geomItem.isHighlighted()) {\n            const highlightIndex = this.highlightedItems.indexOf(glGeomItem);\n            this.highlightedItems.splice(highlightIndex, 1);\n            this.highlightedIdsBufferDirty = true;\n        }\n        this.emit('updated');\n    }\n    // ////////////////////////////////////\n    // Draw Ids\n    cleanGeomIds() {\n        // When a geometry changes, we update offset and count the values.\n        // Note: this method is quite expensive.\n        // (taking up 80% of the time to load the GPU in the Memory test before it was refactored)\n        // The cost is probably in the \"drawOrderToIndex.indexOf(index)\" call below.\n        // Most of the time, we are adding/removing GeomItems. The geoms rarely change\n        // independently.\n        // We run this method in the rare occurrence that a geom changes, and not its GeomItem.\n        this.dirtyGeomIndices.forEach((geomId) => {\n            const geomItemIndices = this.glGeomIdsMapping[geomId];\n            if (geomItemIndices != undefined) {\n                const offsetAndCount = this.renderer.glGeomLibrary.getGeomOffsetAndCount(geomId);\n                geomItemIndices.forEach((index) => {\n                    const glGeomItem = this.glGeomItems[index];\n                    if (glGeomItem.isVisible()) {\n                        const drawIndex = this.indexToDrawIndex[index];\n                        this.drawElementOffsets[drawIndex] = offsetAndCount[0];\n                        this.drawElementCounts[drawIndex] = offsetAndCount[1];\n                        this.drawIdsArray[drawIndex] = glGeomItem.geomItemId;\n                        const highlightIndex = this.highlightedItems.indexOf(glGeomItem);\n                        if (highlightIndex != -1) {\n                            this.highlightElementOffsets[highlightIndex] = offsetAndCount[0];\n                            this.highlightElementCounts[highlightIndex] = offsetAndCount[1];\n                        }\n                    }\n                });\n            }\n        });\n        this.dirtyGeomIndices = new Set();\n    }\n    /**\n     * The updateDrawIDsBuffer method.\n     * @param renderstate - The object used to track state changes during rendering.\n     */\n    updateDrawIDsBuffer(renderstate) {\n        {\n            if (!this.drawIdsArray || this.drawOrderToIndex.length > this.drawIdsArray.length) {\n                this.drawIdsArray = new Float32Array(this.drawOrderToIndex.length);\n                // Note: the +1 here is to avoid an exception thrown on Safari if the offsets and counts are\n                // exactly the size of the number of drawn items. (a bug in the validation).\n                this.drawElementOffsets = new Int32Array(this.drawOrderToIndex.length + 1);\n                this.drawElementCounts = new Int32Array(this.drawOrderToIndex.length + 1);\n            }\n            this.drawOrderToIndex.forEach((itemIndex, drawIndex) => {\n                const glGeomItem = this.glGeomItems[itemIndex];\n                if (!glGeomItem)\n                    return;\n                const offsetAndCount = this.renderer.glGeomLibrary.getGeomOffsetAndCount(glGeomItem.geomId);\n                this.drawElementOffsets[drawIndex] = offsetAndCount[0];\n                this.drawElementCounts[drawIndex] = glGeomItem.isVisible() ? offsetAndCount[1] : 0;\n                this.drawIdsArray[drawIndex] = glGeomItem.geomItemId;\n                // Note: as items are removed, these indices must be updated.\n                this.indexToDrawIndex[itemIndex] = drawIndex;\n            });\n            this.dirtyGeomIndices = new Set();\n        }\n        const gl = this.renderer.gl;\n        const unit = renderstate.boundTextures++;\n        gl.activeTexture(gl.TEXTURE0 + unit);\n        const drawIdsTextureSize = MathFunctions.nextPow2(Math.ceil(Math.sqrt(this.drawOrderToIndex.length))) * 2;\n        if (!this.drawIdsTexture) {\n            this.drawIdsTexture = new GLTexture2D(this.gl, {\n                format: this.gl.RED,\n                type: this.gl.FLOAT,\n                width: drawIdsTextureSize,\n                height: drawIdsTextureSize,\n                filter: this.gl.NEAREST,\n                wrap: this.gl.CLAMP_TO_EDGE,\n                mipMapped: false,\n            });\n        }\n        else if (this.drawIdsTexture.width < drawIdsTextureSize || this.drawIdsTexture.height < drawIdsTextureSize) {\n            this.drawIdsTexture.resize(drawIdsTextureSize, drawIdsTextureSize);\n        }\n        {\n            const tex = this.drawIdsTexture;\n            const texWidth = this.drawIdsTexture.width;\n            gl.bindTexture(gl.TEXTURE_2D, tex.glTex);\n            const level = 0;\n            const xoffset = 0;\n            const height = 1;\n            const format = tex.format;\n            const type = tex.type;\n            const rows = Math.ceil((xoffset + this.drawOrderToIndex.length) / texWidth);\n            let consumed = 0;\n            let remaining = this.drawOrderToIndex.length;\n            let rowStart = xoffset;\n            for (let i = 0; i < rows; i++) {\n                let width;\n                if (rowStart + remaining > texWidth) {\n                    width = texWidth - rowStart;\n                    rowStart = 0;\n                }\n                else {\n                    width = remaining;\n                }\n                const x = consumed % texWidth;\n                const y = Math.floor(consumed / texWidth);\n                const data = this.drawIdsArray.subarray(consumed, consumed + width);\n                gl.texSubImage2D(gl.TEXTURE_2D, level, x, y, width, height, format, type, data);\n                consumed += width;\n                remaining -= width;\n            }\n        }\n        gl.bindTexture(gl.TEXTURE_2D, null);\n        renderstate.boundTextures--;\n        this.drawIdsBufferDirty = false;\n    }\n    // ////////////////////////////////////\n    // Selected Items\n    /**\n     * The updateHighlightedIDsBuffer method.\n     * @param renderstate - The object used to track state changes during rendering.\n     */\n    updateHighlightedIDsBuffer(renderstate) {\n        if (this.highlightedIdsBufferDirty) {\n            if (!this.highlightedIdsArray || this.highlightedItems.length > this.highlightedIdsArray.length) {\n                this.highlightedIdsArray = new Float32Array(this.highlightedItems.length);\n                // Note: the +1 here is to avoid an exception thrown on Safari if the offsets and counts are\n                // exactly the size of the number of drawn items. (a bug in the validation).\n                this.highlightElementOffsets = new Int32Array(this.highlightedItems.length + 1);\n                this.highlightElementCounts = new Int32Array(this.highlightedItems.length + 1);\n            }\n            // Collect all visible geom ids into the instanceIds array.\n            // Note: the draw count can be less than the number of instances\n            // we re-use the same buffer and simply invoke fewer draw calls.\n            this.highlightedItems.forEach((glGeomItem, index) => {\n                this.highlightedIdsArray[index] = glGeomItem.geomItemId;\n                const offsetAndCount = this.renderer.glGeomLibrary.getGeomOffsetAndCount(glGeomItem.geomId);\n                this.highlightElementOffsets[index] = offsetAndCount[0];\n                this.highlightElementCounts[index] = offsetAndCount[1];\n            });\n            for (let i = this.highlightedItems.length; i < this.highlightElementCounts.length; i++) {\n                this.highlightElementOffsets[i] = 0;\n                this.highlightElementCounts[i] = 0;\n            }\n            this.highlightedIdsBufferDirty = false;\n        }\n        const gl = this.renderer.gl;\n        const unit = renderstate.boundTextures++;\n        gl.activeTexture(gl.TEXTURE0 + unit);\n        const highlightIdsTextureSize = MathFunctions.nextPow2(Math.ceil(Math.sqrt(this.highlightedItems.length)));\n        if (!this.highlightedIdsTexture) {\n            this.highlightedIdsTexture = new GLTexture2D(this.gl, {\n                format: this.gl.RED,\n                type: this.gl.FLOAT,\n                width: highlightIdsTextureSize,\n                height: highlightIdsTextureSize,\n                filter: this.gl.NEAREST,\n                wrap: this.gl.CLAMP_TO_EDGE,\n                mipMapped: false,\n            });\n        }\n        else if (this.highlightedIdsTexture.width < highlightIdsTextureSize ||\n            this.highlightedIdsTexture.height < highlightIdsTextureSize) {\n            this.highlightedIdsTexture.resize(highlightIdsTextureSize, highlightIdsTextureSize);\n        }\n        {\n            const tex = this.highlightedIdsTexture;\n            const texWidth = this.highlightedIdsTexture.width;\n            gl.bindTexture(gl.TEXTURE_2D, tex.glTex);\n            const level = 0;\n            const xoffset = 0;\n            const height = 1;\n            const format = tex.format;\n            const type = tex.type;\n            const rows = Math.ceil((xoffset + this.highlightedIdsArray.length) / texWidth);\n            let consumed = 0;\n            let remaining = this.highlightedIdsArray.length;\n            let rowStart = xoffset;\n            for (let i = 0; i < rows; i++) {\n                let width;\n                if (rowStart + remaining > texWidth) {\n                    width = texWidth - rowStart;\n                    rowStart = 0;\n                }\n                else {\n                    width = remaining;\n                }\n                const x = consumed % texWidth;\n                const y = Math.floor(consumed / texWidth);\n                const data = this.highlightedIdsArray.subarray(consumed, consumed + width);\n                gl.texSubImage2D(gl.TEXTURE_2D, level, x, y, width, height, format, type, data);\n                consumed += width;\n                remaining -= width;\n            }\n        }\n        gl.bindTexture(gl.TEXTURE_2D, null);\n        renderstate.boundTextures--;\n    }\n    // ////////////////////////////////////\n    // Drawing\n    /**\n     * The draw method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    draw(renderstate) {\n        if (this.drawIdsBufferDirty) {\n            this.updateDrawIDsBuffer(renderstate);\n        }\n        else if (this.dirtyGeomIndices.size > 0) {\n            this.cleanGeomIds();\n        }\n        // Note: updateDrawIDsBuffer first, as this avoids a case where the buffers stay dirty\n        // because the last item was removed.\n        if (this.drawIdsArray.length == 0) {\n            return;\n        }\n        if (this.drawIdsTexture) {\n            const { drawIdsTexture } = renderstate.unifs;\n            this.drawIdsTexture.bindToUniform(renderstate, drawIdsTexture);\n        }\n        this.bindAndRender(renderstate, this.drawElementCounts, this.drawElementOffsets, this.drawOrderToIndex.length);\n    }\n    /**\n     * The drawHighlighted method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    drawHighlighted(renderstate) {\n        if (this.highlightedItems.length == 0) {\n            return;\n        }\n        if (this.highlightedIdsBufferDirty) {\n            this.updateHighlightedIDsBuffer(renderstate);\n        }\n        if (this.highlightedIdsTexture) {\n            const { drawIdsTexture } = renderstate.unifs;\n            this.highlightedIdsTexture.bindToUniform(renderstate, drawIdsTexture);\n        }\n        this.bindAndRender(renderstate, this.highlightElementCounts, this.highlightElementOffsets, this.highlightedItems.length);\n    }\n    /**\n     * The drawGeomData method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    drawGeomData(renderstate) {\n        if (this.drawIdsBufferDirty) {\n            this.updateDrawIDsBuffer(renderstate);\n        }\n        // Note: updateDrawIDsBuffer first, as this avoids a case where the buffers stay dirty\n        // because the last item was removed.\n        if (this.drawOrderToIndex.length == 0) {\n            return;\n        }\n        if (this.drawIdsTexture) {\n            const { drawIdsTexture } = renderstate.unifs;\n            this.drawIdsTexture.bindToUniform(renderstate, drawIdsTexture);\n        }\n        this.bindAndRender(renderstate, this.drawElementCounts, this.drawElementOffsets, this.drawOrderToIndex.length);\n    }\n    /**\n     * The bindAndRender method.\n     * @param renderstate - The object tracking the current state of the renderer\n     * @param counts - the counts for each element drawn in by this draw call.\n     * @param offsets - the offsets for each element drawn in by this draw call.\n     * @private\n     */\n    bindAndRender(renderstate, counts, offsets, drawCount) {\n        const gl = this.gl;\n        const unifs = renderstate.unifs;\n        // Specify an instanced draw to the shader so it knows how\n        // to retrieve the modelmatrix.\n        if (unifs.instancedDraw) {\n            gl.uniform1i(renderstate.unifs.instancedDraw.location, 1);\n        }\n        renderstate.bindViewports(unifs, () => {\n            this.multiDraw(renderstate, counts, offsets, drawCount);\n        });\n    }\n    /**\n     * Sorts the drawn items in order furthest to nearest when rendering transparent objects.\n     * @param viewPos - The position of the camera that we are sorting relative to.\n     */\n    sortItems(viewPos) {\n        const distances = new Float32Array(this.drawOrderToIndex.length);\n        this.drawOrderToIndex.forEach((itemIndex) => {\n            const glGeomItem = this.glGeomItems[itemIndex];\n            if (glGeomItem) {\n                const bbox = glGeomItem.geomItem.boundingBoxParam.value;\n                // Calculate the disance to the surface of the bounding sphere.\n                // TODO: calculate the distance the nearest point on the bounding box.\n                const center = bbox.center();\n                const size = bbox.size();\n                const dist = center.distanceTo(viewPos) - size;\n                distances[itemIndex] = dist;\n            }\n        });\n        this.drawOrderToIndex.sort((a, b) => distances[b] - distances[a]);\n        this.drawOrderToIndex.forEach((itemIndex, drawIndex) => {\n            const glGeomItem = this.glGeomItems[itemIndex];\n            if (glGeomItem) {\n                this.drawIdsArray[drawIndex] = glGeomItem.geomItemId;\n                this.indexToDrawIndex[itemIndex] = drawIndex;\n            }\n        });\n        // Force the re-generation of the draw ids texture using the new ordering.\n        this.drawIdsBufferDirty = true;\n        this.viewPos = viewPos;\n    }\n    /**\n     * The destroy is called by the system to cause explicit resources cleanup.\n     * Users should never need to call this method directly.\n     */\n    destroy() {\n        if (this.drawIdsTexture) {\n            this.drawIdsTexture.destroy();\n        }\n        if (this.highlightedIdsTexture) {\n            this.highlightedIdsTexture.destroy();\n        }\n        this.emit('destructing');\n    }\n}\n\n/** Class representing a GL mesh.\n * @extends GLGeom\n * @private\n */\nclass GLPointsItemSet extends GLGeomItemSetMultiDraw {\n    /**\n     * Draw an item to screen.\n     * @param renderstate - The object tracking the current state of the renderer\n     * @param drawIds - the draw id for each element drawn in by this draw call.\n     * @param counts - the geom element count for each element drawn in by this draw call.\n     * @param offsets - the geom element offset for each element drawn in by this draw call.\n     * @param drawCount - the number of active draw calls for this invocation\n     */\n    multiDraw(renderstate, counts, offsets, drawCount) {\n        const gl = this.gl;\n        if (gl.multiDrawArrays) {\n            gl.multiDrawArrays(gl.POINTS, offsets, 0, counts, 0, drawCount);\n        }\n        else {\n            const { drawId } = renderstate.unifs;\n            for (let i = 0; i < drawCount; i++) {\n                gl.uniform1i(drawId.location, i);\n                gl.drawArrays(gl.POINTS, offsets[i], counts[i]);\n            }\n        }\n    }\n}\n\n/** Class representing a GL mesh.\n * @extends GLGeom\n * @private\n */\nclass GLLinesItemSet extends GLGeomItemSetMultiDraw {\n    /**\n     * Draw an item to screen.\n     * @param renderstate - The object tracking the current state of the renderer\n     * @param drawIds - the draw id for each element drawn in by this draw call.\n     * @param counts - the geom element count for each element drawn in by this draw call.\n     * @param offsets - the geom element offset for each element drawn in by this draw call.\n     * @param drawCount - the number of active draw calls for this invocation\n     */\n    multiDraw(renderstate, counts, offsets, drawCount) {\n        const { occluded, hiddenLineColor } = renderstate.unifs;\n        // @ts-ignore\n        const drawingHiddenLines = \n        // @ts-ignore\n        renderstate.hiddenLineColor &&\n            // @ts-ignore\n            renderstate.hiddenLineColor.a > 0 &&\n            occluded &&\n            hiddenLineColor;\n        const gl = this.gl;\n        if (gl.multiDrawArrays) {\n            gl.multiDrawElements(gl.LINES, counts, 0, gl.UNSIGNED_INT, offsets, 0, drawCount);\n            if (drawingHiddenLines) {\n                gl.uniform1i(occluded.location, 1);\n                // @ts-ignore\n                gl.uniform4fv(hiddenLineColor.location, renderstate.hiddenLineColor.asArray());\n                gl.depthFunc(gl.GREATER);\n                gl.depthMask(false);\n                gl.multiDrawElements(gl.LINES, counts, 0, gl.UNSIGNED_INT, offsets, 0, drawCount);\n                gl.depthFunc(gl.LEQUAL);\n                gl.depthMask(true);\n                gl.uniform1i(occluded.location, 0);\n            }\n        }\n        else {\n            const { drawId } = renderstate.unifs;\n            for (let i = 0; i < drawCount; i++) {\n                gl.uniform1i(drawId.location, i);\n                gl.drawElements(gl.LINES, counts[i], gl.UNSIGNED_INT, offsets[i]);\n            }\n            if (drawingHiddenLines) {\n                gl.uniform1i(occluded.location, 1);\n                // @ts-ignore\n                gl.uniform4fv(hiddenLineColor.location, renderstate.hiddenLineColor.asArray());\n                gl.depthFunc(gl.GREATER);\n                gl.depthMask(false);\n                for (let i = 0; i < drawCount; i++) {\n                    gl.uniform1i(drawId.location, i);\n                    gl.drawElements(gl.LINES, counts[i], gl.UNSIGNED_INT, offsets[i]);\n                }\n                gl.depthFunc(gl.LEQUAL);\n                gl.depthMask(true);\n                gl.uniform1i(occluded.location, 0);\n            }\n        }\n    }\n}\n\nvar GeomType$1;\n(function (GeomType) {\n    GeomType[GeomType[\"TRIANGLES\"] = 0] = \"TRIANGLES\";\n    GeomType[GeomType[\"LINES\"] = 1] = \"LINES\";\n    GeomType[GeomType[\"POINTS\"] = 2] = \"POINTS\";\n})(GeomType$1 || (GeomType$1 = {}));\n/** Class representing a GL mesh.\n * @extends GLGeom\n * @private\n */\nclass GLMeshItemSet extends GLGeomItemSetMultiDraw {\n    /**\n     * Draw an item to screen.\n     * @param renderstate - The object tracking the current state of the renderer\n     * @param drawIds - the draw id for each element drawn in by this draw call.\n     * @param counts - the geom element count for each element drawn in by this draw call.\n     * @param offsets - the geom element offset for each element drawn in by this draw call.\n     * @param drawCount - the number of active draw calls for this invocation\n     */\n    multiDraw(renderstate, counts, offsets, drawCount) {\n        const gl = this.gl;\n        const multiDrawMeshes = () => {\n            if (gl.multiDrawElements) {\n                gl.multiDrawElements(gl.TRIANGLES, counts, 0, gl.UNSIGNED_INT, offsets, 0, drawCount);\n            }\n            else {\n                const { drawId } = renderstate.unifs;\n                for (let i = 0; i < drawCount; i++) {\n                    gl.uniform1i(drawId.location, i);\n                    gl.drawElements(gl.TRIANGLES, counts[i], gl.UNSIGNED_INT, offsets[i]);\n                }\n            }\n        };\n        const { geomType, outlineThickness, viewportSize, renderMode } = renderstate.unifs;\n        const renderModeValue = renderstate instanceof ColorRenderState && renderMode ? renderstate.renderMode : null;\n        const drawingOutlines = renderstate instanceof ColorRenderState &&\n            outlineThickness &&\n            viewportSize &&\n            renderstate.outlineMethod == 'geometry' &&\n            renderstate.outlineThickness > 0 &&\n            renderModeValue != 'flat-noedges' &&\n            renderModeValue != 'pbr-noedges';\n        const drawingWireframeOutlines = drawingOutlines && renderModeValue == 'wireframe';\n        if (drawingWireframeOutlines) {\n            gl.enable(gl.STENCIL_TEST);\n            gl.clearStencil(0);\n            gl.clear(gl.STENCIL_BUFFER_BIT);\n            gl.stencilOpSeparate(gl.FRONT, gl.DECR_WRAP, gl.DECR_WRAP, gl.DECR_WRAP);\n            gl.stencilOpSeparate(gl.BACK, gl.INCR_WRAP, gl.INCR_WRAP, gl.INCR_WRAP);\n            gl.stencilFunc(gl.ALWAYS, 0, 0xff);\n            gl.enable(gl.CULL_FACE);\n            gl.cullFace(gl.BACK);\n            gl.disable(gl.DEPTH_TEST);\n            gl.depthMask(false);\n            gl.colorMask(false, false, false, false);\n            // @ts-ignore\n        }\n        else if (renderModeValue == 'hiddenline') {\n            // Note: only the standard surface shader exposes the 'renderMode' uniform,\n            // so this prevents other shaders from being skippped.\n            // e.g. PMI data shoudl show up normally in wireframe mode and it is rendered using the FlatSurfaceShader.\n            // don't render surfaces\n            // Note: Make sure to render alpha channel\n            gl.colorMask(false, false, false, true);\n        }\n        if (geomType)\n            gl.uniform1i(geomType.location, GeomType$1.TRIANGLES);\n        // Always zero this value before drawing the faces, else the shader could think its drawing the outline.\n        if (outlineThickness) {\n            gl.uniform1f(outlineThickness.location, 0);\n        }\n        multiDrawMeshes();\n        if (drawingOutlines) {\n            const colorRenderState = renderstate;\n            // Only draw font faces. BEcause all faces are drawn, it can make a mess to see the back faces through the front faces.\n            // e.g. we might see the triangles on the other side of a sphere rendered over the top of triangles on the near side.\n            gl.enable(gl.CULL_FACE);\n            gl.cullFace(gl.FRONT);\n            // @ts-ignore\n            gl.uniform1f(outlineThickness.location, colorRenderState.outlineThickness * window.devicePixelRatio);\n            gl.uniform2f(viewportSize.location, renderstate.region[2] - renderstate.region[0], renderstate.region[3] - renderstate.region[1]);\n            // @ts-ignore\n            if (renderModeValue == 'hiddenline') {\n                // start rendering surfaces again\n                gl.colorMask(true, true, true, true);\n            }\n            if (!drawingWireframeOutlines) {\n                gl.enable(gl.BLEND);\n                gl.blendEquation(gl.FUNC_ADD);\n                gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE);\n            }\n            multiDrawMeshes();\n            gl.disable(gl.CULL_FACE);\n            gl.cullFace(gl.BACK);\n            if (drawingWireframeOutlines) {\n                gl.enable(gl.DEPTH_TEST);\n                gl.depthMask(true);\n                gl.colorMask(true, true, true, true);\n                gl.stencilFunc(gl.NOTEQUAL, 0x0, 0xff);\n                gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);\n                // Blend the outline over the existing geometry.\n                {\n                    gl.enable(gl.BLEND);\n                    gl.blendEquation(gl.FUNC_ADD);\n                    gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE);\n                }\n                // cache the previously bound shader.\n                const shader = colorRenderState.glShader;\n                const shaderKey = colorRenderState.shaderkey;\n                const screenQuad = colorRenderState.screenQuad;\n                screenQuad.bindShader(colorRenderState);\n                screenQuad.draw(colorRenderState, colorRenderState.outlineColor);\n                // Re-bind the previously bound geomdata shader.\n                shader.bind(colorRenderState, shaderKey);\n                this.renderer.glGeomItemLibrary.bind(colorRenderState);\n                this.renderer.glGeomLibrary.bind(colorRenderState);\n                this.renderer.glMaterialLibrary.bind(colorRenderState);\n                gl.disable(gl.STENCIL_TEST);\n            }\n        }\n    }\n}\n\n/** This class abstracts the rendering of a collection of geometries to screen.\n * @extends EventEmitter\n * @private\n */\nclass GLGeomItemSet extends EventEmitter {\n    gl;\n    glGeom;\n    id;\n    glGeomItems;\n    glgeomItems_freeIndices;\n    glgeomItemEventHandlers;\n    drawIdsArray = null;\n    drawIdsBuffer = null;\n    drawIdsBufferDirty;\n    highlightedIdsArray = null;\n    highlightedIdsBuffer = null;\n    highlightedIdsBufferDirty;\n    visibleItems;\n    highlightedItems;\n    /**\n     * Create a GL geom item set.\n     * @param gl - The webgl rendering context.\n     * @param glGeom - The glGeom value.\n     */\n    constructor(gl, glGeom) {\n        super();\n        this.gl = gl;\n        this.glGeom = glGeom;\n        this.id = glGeom ? glGeom.getGeom().getId() : this.getId();\n        this.glGeomItems = [];\n        this.glgeomItems_freeIndices = [];\n        this.glgeomItemEventHandlers = [];\n        this.drawIdsArray = null;\n        this.drawIdsBuffer = null;\n        this.drawIdsBufferDirty = true;\n        this.highlightedIdsArray = null;\n        this.highlightedIdsBuffer = null;\n        this.highlightedIdsBufferDirty = true;\n        this.visibleItems = [];\n        this.highlightedItems = [];\n    }\n    /**\n     * The getGLGeom method.\n     * @return - The return value.\n     */\n    getGLGeom() {\n        return this.glGeom;\n    }\n    /**\n     * The getDrawCount method.\n     * @return - The return value.\n     */\n    getDrawCount() {\n        return this.visibleItems.length;\n    }\n    /**\n     * The addGLGeomItem method.\n     * @param glGeomItem - The glGeomItem value.\n     */\n    addGLGeomItem(glGeomItem) {\n        let index;\n        if (this.glgeomItems_freeIndices.length > 0) {\n            index = this.glgeomItems_freeIndices.pop();\n        }\n        else {\n            index = this.glGeomItems.length;\n            this.glGeomItems.push(null);\n        }\n        if (glGeomItem.geomItem.isVisible()) {\n            this.visibleItems.push(index);\n            const event = new CountChangedEvent(1, this.visibleItems.length);\n            this.emit('drawCountChanged', event);\n        }\n        if (glGeomItem.geomItem.isHighlighted()) {\n            this.highlightedItems.push(index);\n            this.highlightedIdsBufferDirty = true;\n        }\n        const eventHandlers = {};\n        eventHandlers.highlightChanged = (event) => {\n            if (glGeomItem.geomItem.isHighlighted()) {\n                // Note: highlightChanged is fired when the color changes\n                // or another highlight is added over the top. We avoid\n                // adding the same index again here. (TODO: use Set?)\n                if (this.highlightedItems.includes(index))\n                    return;\n                this.highlightedItems.push(index);\n                const event = new CountChangedEvent(1, this.highlightedItems.length);\n                this.emit('highlightedCountChanged', event);\n            }\n            else {\n                this.highlightedItems.splice(this.highlightedItems.indexOf(index), 1);\n                const event = new CountChangedEvent(-1, this.highlightedItems.length);\n                this.emit('highlightedCountChanged', event);\n            }\n            // console.log(\"highlightChanged:\", glGeomItem.geomItem.getName(), glGeomItem.geomItem.isHighlighted(), this.highlightedItems)\n            this.highlightedIdsBufferDirty = true;\n        };\n        glGeomItem.geomItem.on('highlightChanged', eventHandlers.highlightChanged);\n        eventHandlers.visibilityChanged = (event) => {\n            const visible = event.state;\n            if (visible) {\n                this.visibleItems.push(index);\n                const event = new CountChangedEvent(1, this.visibleItems.length);\n                this.emit('drawCountChanged', event);\n            }\n            else {\n                this.visibleItems.splice(this.visibleItems.indexOf(index), 1);\n                const event = new CountChangedEvent(-1, this.visibleItems.length);\n                this.emit('drawCountChanged', event);\n            }\n            this.drawIdsBufferDirty = true;\n        };\n        glGeomItem.geomItem.on('visibilityChanged', eventHandlers.visibilityChanged);\n        this.glGeomItems[index] = glGeomItem;\n        this.glgeomItemEventHandlers[index] = eventHandlers;\n        this.drawIdsBufferDirty = true;\n        glGeomItem.GLGeomItemSet = this;\n    }\n    /**\n     * The removeGLGeomItem method.\n     * @param glGeomItem - The glGeomItem value.\n     */\n    removeGLGeomItem(glGeomItem) {\n        const index = this.glGeomItems.indexOf(glGeomItem);\n        const eventHandlers = this.glgeomItemEventHandlers[index];\n        glGeomItem.geomItem.off('highlightChanged', eventHandlers.highlightChanged);\n        glGeomItem.geomItem.off('visibilityChanged', eventHandlers.visibilityChanged);\n        this.glGeomItems[index] = null;\n        this.glgeomItemEventHandlers[index] = null;\n        glGeomItem.GLGeomItemSet = null;\n        this.glgeomItems_freeIndices.push(index);\n        if (glGeomItem.geomItem.isVisible()) {\n            this.visibleItems.splice(this.visibleItems.indexOf(index), 1);\n            const event = new CountChangedEvent(-1, this.visibleItems.length);\n            this.emit('drawCountChanged', event);\n        }\n        if (glGeomItem.geomItem.isHighlighted()) {\n            this.highlightedItems.splice(this.highlightedItems.indexOf(index), 1);\n            const event = new CountChangedEvent(-1, this.highlightedItems.length);\n            this.emit('highlightedCountChanged', event);\n        }\n        this.drawIdsBufferDirty = true;\n        // console.log(\"removeGLGeomItem:\", glGeomItem.geomItem.getName(), this.glGeomItems.length)\n        if (this.glGeomItems.length == this.glgeomItems_freeIndices.length) {\n            this.destroy();\n        }\n    }\n    // ////////////////////////////////////\n    // Instance Ids\n    /**\n     * The updateDrawIDsBuffer method.\n     * The culling system will specify a subset of the total number of items for\n     * drawing.\n     */\n    updateDrawIDsBuffer() {\n        const gl = this.gl;\n        if (!gl.floatTexturesSupported) {\n            this.drawIdsBufferDirty = false;\n            return;\n        }\n        if (this.drawIdsBuffer && this.glGeomItems.length != this.drawIdsArray.length) {\n            this.gl.deleteBuffer(this.drawIdsBuffer);\n            this.drawIdsBuffer = null;\n        }\n        if (!this.drawIdsBuffer) {\n            this.drawIdsBuffer = gl.createBuffer();\n            gl.bindBuffer(gl.ARRAY_BUFFER, this.drawIdsBuffer);\n        }\n        gl.bindBuffer(gl.ARRAY_BUFFER, this.drawIdsBuffer);\n        gl.bufferData(gl.ARRAY_BUFFER, this.getDrawIdsArray(), gl.STATIC_DRAW);\n        this.drawIdsBufferDirty = false;\n    }\n    /**\n     * The getDrawIdsArray method.\n     * @return - The drawIds for each GeomItem packed into a Float32Array\n     */\n    getDrawIdsArray() {\n        if (this.drawIdsBufferDirty) {\n            if (!this.drawIdsArray || this.glGeomItems.length != this.drawIdsArray.length) {\n                this.drawIdsArray = new Float32Array(this.glGeomItems.length);\n            }\n            // Collect all visible geom ids into the instanceIds array.\n            // Note: the draw count can be less than the number of instances\n            // we re-use the same buffer and simply invoke fewer draw calls.\n            this.visibleItems.forEach((index, tgtIndex) => {\n                this.drawIdsArray[tgtIndex] = this.glGeomItems[index].geomItemId;\n            });\n            this.drawIdsBufferDirty = false;\n        }\n        return this.drawIdsArray;\n    }\n    // ////////////////////////////////////\n    // Selected Items\n    /**\n     * The updateHighlightedIDsBuffer method.\n     */\n    updateHighlightedIDsBuffer() {\n        const gl = this.gl;\n        if (!gl.floatTexturesSupported) {\n            this.highlightedIdsBufferDirty = false;\n            return;\n        }\n        if (this.highlightedIdsBuffer && this.glGeomItems.length > this.highlightedIdsArray.length) {\n            this.gl.deleteBuffer(this.highlightedIdsBuffer);\n            this.highlightedIdsBuffer = null;\n        }\n        if (!this.highlightedIdsBuffer) {\n            this.highlightedIdsBuffer = gl.createBuffer();\n        }\n        gl.bindBuffer(gl.ARRAY_BUFFER, this.highlightedIdsBuffer);\n        gl.bufferData(gl.ARRAY_BUFFER, this.getHighlightedIdsArray(), gl.STATIC_DRAW);\n        this.highlightedIdsBufferDirty = false;\n    }\n    /**\n     * The getHighlightedIdsArray method.\n     * @return - The drawIds for each GeomItem packed into a Float32Array\n     */\n    getHighlightedIdsArray() {\n        if (this.highlightedIdsBufferDirty) {\n            if (!this.highlightedIdsArray || this.highlightedItems.length > this.highlightedIdsArray.length) {\n                this.highlightedIdsArray = new Float32Array(this.glGeomItems.length);\n            }\n            // Collect all visible geom ids into the instanceIds array.\n            // Note: the draw count can be less than the number of instances\n            // we re-use the same buffer and simply invoke fewer draw calls.\n            this.highlightedItems.forEach((index, tgtIndex) => {\n                this.highlightedIdsArray[tgtIndex] = this.glGeomItems[index].geomItemId;\n            });\n            this.highlightedIdsBufferDirty = false;\n        }\n        return this.highlightedIdsArray;\n    }\n    // ////////////////////////////////////\n    // Drawing\n    /**\n     * The draw method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    draw(renderstate) {\n        if (this.visibleItems.length == 0) {\n            return;\n        }\n        if (this.drawIdsBufferDirty) {\n            this.updateDrawIDsBuffer();\n        }\n        this.bindAndRender(renderstate, this.visibleItems, this.drawIdsBuffer);\n    }\n    /**\n     * The drawHighlighted method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    drawHighlighted(renderstate) {\n        if (this.highlightedItems.length == 0) {\n            return;\n        }\n        if (this.highlightedIdsBufferDirty) {\n            this.updateHighlightedIDsBuffer();\n        }\n        this.bindAndRender(renderstate, this.highlightedItems, this.highlightedIdsBuffer);\n    }\n    /**\n     * The drawGeomData method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    drawGeomData(renderstate) {\n        if (this.visibleItems.length == 0) {\n            return;\n        }\n        if (this.drawIdsBufferDirty) {\n            this.updateDrawIDsBuffer();\n        }\n        this.bindAndRender(renderstate, this.visibleItems, this.drawIdsBuffer);\n    }\n    bindAndRender(renderstate, itemIndices, drawIdsBuffer) {\n        const gl = this.gl;\n        const unifs = renderstate.unifs;\n        // Lazy unbinding. We can have situations where we have many materials\n        // all bound to the same geom. e.g. lots of billboards\n        // We can avoid the expensive re-binding of geoms with a simple check.\n        if (renderstate.glGeom != this.glGeom) {\n            this.glGeom.bind(renderstate);\n            renderstate.glGeom = this.glGeom;\n        }\n        if (!gl.floatTexturesSupported || !gl.drawElementsInstanced || !renderstate.supportsInstancing) {\n            if (renderstate.unifs.instancedDraw) {\n                gl.uniform1i(renderstate.unifs.instancedDraw.location, 0);\n            }\n            itemIndices.forEach((index) => {\n                this.glGeomItems[index].bind(renderstate);\n                renderstate.bindViewports(unifs, () => {\n                    this.glGeom.draw(renderstate);\n                });\n            });\n        }\n        else {\n            // console.log(\"draw:\"+ this.drawIdsArray);\n            // Specify an instanced draw to the shader so it knows how\n            // to retrieve the modelmatrix.\n            if (renderstate.unifs.instancedDraw) {\n                gl.uniform1i(renderstate.unifs.instancedDraw.location, 1);\n            }\n            // The instanced transform ids are bound as an instanced attribute.\n            const location = renderstate.attrs.instancedIds.location;\n            gl.enableVertexAttribArray(location);\n            gl.bindBuffer(gl.ARRAY_BUFFER, drawIdsBuffer);\n            gl.vertexAttribPointer(location, 1, gl.FLOAT, false, 1 * 4, 0);\n            gl.vertexAttribDivisor(location, 1); // This makes it instanced\n            renderstate.bindViewports(unifs, () => {\n                this.glGeom.drawInstanced(renderstate, itemIndices.length);\n            });\n        }\n    }\n    /**\n     * The destroy is called by the system to cause explicit resources cleanup.\n     * Users should never need to call this method directly.\n     */\n    destroy() {\n        if (this.drawIdsBuffer) {\n            this.gl.deleteBuffer(this.drawIdsBuffer);\n            this.drawIdsBuffer = null;\n        }\n        if (this.highlightedIdsBuffer) {\n            this.gl.deleteBuffer(this.highlightedIdsBuffer);\n            this.highlightedIdsBuffer = null;\n        }\n        this.emit('destructing');\n    }\n}\n\nvar vert$a = \"\\nprecision highp float;\\n#define GLSLIFY 1\\nattribute vec3 positions;  //(location = 0)\\n\\n/* VS Outputs */\\nvarying vec2 v_texCoord;\\n \\nvoid main()\\n{\\n  v_texCoord = positions.xy+0.5;\\n  gl_Position = vec4(positions.xy*2.0, -1.0, 1.0);\\n}\\n\"; // eslint-disable-line\n\nvar frag$9 = \"\\nprecision highp float;\\n#define GLSLIFY 1\\n\\nuniform sampler2D colorTexture;\\nuniform sampler2D depthTexture;\\nuniform vec2 screenSize;\\n\\nuniform int pointAndLinePickingSize;\\n\\nvarying vec2 v_texCoord;\\n\\nbool sampleNeiPixel(vec2 fragCoord, inout vec4 res) {\\n  res = texture2D(colorTexture, fragCoord/screenSize);\\n  if (res.a > 0.0) {\\n    return true;\\n  }\\n  return false;\\n}\\n\\nvec4 samplePixels(vec2 fragCoord, int dist) {\\n  vec4 res = vec4(0.0);\\n  \\n  \\n  // Search surrounding pixels for geoms\\n  if (sampleNeiPixel(fragCoord+vec2( dist, 0), res)) return res; // E\\n  if (sampleNeiPixel(fragCoord+vec2(-dist, 0), res)) return res; // W\\n  if (sampleNeiPixel(fragCoord+vec2( 0, dist), res)) return res; // N\\n  if (sampleNeiPixel(fragCoord+vec2( 0,-dist), res)) return res; // S\\n  if (sampleNeiPixel(fragCoord+vec2( dist, dist), res)) return res; // NW\\n  if (sampleNeiPixel(fragCoord+vec2(-dist, dist), res)) return res; // NE\\n  if (sampleNeiPixel(fragCoord+vec2( dist,-dist), res)) return res; // SW\\n  if (sampleNeiPixel(fragCoord+vec2(-dist,-dist), res)) return res; // SE\\n  \\n  return res;\\n}\\n\\n#ifdef ENABLE_ES3\\n  out vec4 fragColor;\\n#endif\\nvoid main(void) {\\n#ifndef ENABLE_ES3\\n  vec4 fragColor;\\n#endif\\n\\n  sampleNeiPixel(gl_FragCoord.xy, fragColor);\\n  if (fragColor.a < 0.0001 && pointAndLinePickingSize > 1) {\\n    for (int i=1; i<pointAndLinePickingSize; i++) {\\n      fragColor = samplePixels(gl_FragCoord.xy, i);\\n      if (fragColor.a > 0.0001) {\\n        break;\\n      } \\n    }\\n  }\\n\\n  if (fragColor.a < 0.0001) {\\n    discard; \\n  }\\n\\n#ifndef ENABLE_ES3\\n  gl_FragColor = fragColor;\\n#endif\\n}\\n\"; // eslint-disable-line\n\n/* eslint-disable require-jsdoc */\nclass FattenLinesShader extends GLShader {\n    /**\n     * Create a GL shader.\n     * @param gl - The webgl rendering context.\n     */\n    constructor(gl) {\n        super(gl, 'FattenLinesShader');\n        this.setShaderStage('VERTEX_SHADER', vert$a);\n        this.setShaderStage('FRAGMENT_SHADER', frag$9);\n    }\n}\n\nconst deepEquals = (arr0, arr1) => {\n    return arr0.length == arr1.length && !arr0.some((v, index) => v != arr1[index]);\n};\nvar GeomType;\n(function (GeomType) {\n    GeomType[GeomType[\"TRIANGLES\"] = 0] = \"TRIANGLES\";\n    GeomType[GeomType[\"LINES\"] = 1] = \"LINES\";\n    GeomType[GeomType[\"POINTS\"] = 2] = \"POINTS\";\n})(GeomType || (GeomType = {}));\n/** This class abstracts the rendering of a collection of geometries to screen.\n * @extends EventEmitter\n * @private\n */\nclass GLGeomItemSetMultiDrawCompoundGeom extends EventEmitter {\n    renderer;\n    gl;\n    glGeomItems = [];\n    glGeomIdsMapping = {};\n    glgeomItemEventHandlers = [];\n    freeIndices = [];\n    // protected visibleItems: GLGeomItem[] = []\n    dirtyGeomItems = new Set();\n    drawIdsBufferDirty = true;\n    // protected drawCounts: Record<string, number> = {}\n    drawIdsArraysAllocators = {};\n    drawIdsArrays = {};\n    drawIdsTextures = {};\n    drawElementCounts = {};\n    drawElementOffsets = {};\n    drawOrderToIndex = [];\n    indexToDrawIndex = [];\n    // As transparent geometries are re-sorted, the allocations are moved around\n    // This array stores the new start position of each geometries allocation.\n    // Note: sorting is disabled untill we fix all remaining issues.\n    // protected indexToOffsets: Record<string, number[]> = {}\n    highlightedItems = {};\n    highlightedIdsArraysAllocators = {};\n    // protected highlightedDrawCounts: Record<string, number> = {}\n    highlightElementCounts = {};\n    highlightElementOffsets = {};\n    highlightedIdsArray = {};\n    highlightedIdsTextures = {};\n    dirtyHighlightedGeomItems = new Set();\n    highlightedIdsBufferDirty = true;\n    linesGeomDataBuffer = null;\n    fattenLinesShader = null;\n    quad = null;\n    fbo = null;\n    /**\n     * Create a GL geom item set.\n     * @param {GLBaseRenderer} renderer - The renderer object.\n     */\n    constructor(renderer) {\n        super();\n        this.renderer = renderer;\n        this.gl = renderer.gl;\n        this.renderer.glGeomLibrary.on('geomDataChanged', (event) => {\n            const geomItemIndices = this.glGeomIdsMapping[event.index];\n            if (geomItemIndices != undefined) {\n                geomItemIndices.forEach((index) => {\n                    this.dirtyGeomItems.add(index);\n                    if (!this.drawIdsBufferDirty) {\n                        this.drawIdsBufferDirty = true;\n                        this.emit('updated');\n                    }\n                });\n            }\n        });\n    }\n    addItemToHighlight(index, highlightName) {\n        // Check to see if the highlight key contains\n        // a subGeomIndex at the end separated by a ':'\n        const subGeomIndexIndex = highlightName.indexOf(':');\n        let subGeomIndices = [];\n        if (subGeomIndexIndex != -1) {\n            subGeomIndices = highlightName\n                .substring(subGeomIndexIndex + 1)\n                .split(',')\n                .map((v) => Number.parseInt(v));\n        }\n        // Note: highlightChanged is fired when the color changes\n        // or another highlight is added over the top. We avoid\n        // adding the same index again here. (TODO: use Set?)\n        if (this.highlightedItems[index] && deepEquals(this.highlightedItems[index], subGeomIndices))\n            return;\n        this.highlightedItems[index] = subGeomIndices;\n        this.highlightedIdsBufferDirty = true;\n        this.emit('updated');\n    }\n    /**\n     * The addGLGeomItem method.\n     * @param {GLGeomItem} glGeomItem - The glGeomItem value.\n     */\n    addGLGeomItem(glGeomItem) {\n        const index = this.freeIndices.length > 0 ? this.freeIndices.pop() : this.glGeomItems.length;\n        this.indexToDrawIndex[index] = this.drawOrderToIndex.length;\n        this.drawOrderToIndex.push(index);\n        this.dirtyGeomItems.add(index);\n        const eventHandlers = {};\n        // //////////////////////////////\n        // Visibility\n        eventHandlers.visibilityChanged = (event) => {\n            this.dirtyGeomItems.add(index);\n            this.drawIdsBufferDirty = true;\n            this.emit('updated');\n        };\n        glGeomItem.on('visibilityChanged', eventHandlers.visibilityChanged);\n        // //////////////////////////////\n        // Highlighted\n        if (glGeomItem.geomItem.isHighlighted()) {\n            this.addItemToHighlight(index, glGeomItem.geomItem.getHighlightName());\n        }\n        eventHandlers.highlightChanged = (event) => {\n            if (event && event.name) {\n                this.addItemToHighlight(index, event.name);\n            }\n            else {\n                delete this.highlightedItems[index];\n                // console.log(\"highlightChanged:\", glGeomItem.geomItem.getName(), glGeomItem.geomItem.isHighlighted(), this.highlightedItems)\n                this.highlightedIdsBufferDirty = true;\n                this.emit('updated');\n            }\n        };\n        glGeomItem.geomItem.on('highlightChanged', eventHandlers.highlightChanged);\n        // //////////////////////////////\n        // ShatterState\n        eventHandlers.shatterStateChanged = (event) => {\n            // const geomBuffers = this.renderer.glGeomLibrary.getGeomBuffers(glGeomItem.geomId)\n            // if (geomBuffers.materials.length == 0)\n            {\n                this.dirtyGeomItems.add(index);\n                this.drawIdsBufferDirty = true;\n                // We need the new GeomData Fbos written so we can\n                // detect these subgeoms.\n                this.renderer.renderGeomDataFbos();\n            }\n        };\n        glGeomItem.on('shatterStateChanged', eventHandlers.shatterStateChanged);\n        // //////////////////////////////\n        // Geometry\n        const geomParam = glGeomItem.geomItem.geomParam;\n        let geom = geomParam.value;\n        glGeomItem.geomId = this.renderer.glGeomLibrary.addGeom(geom);\n        // Keep track of which geomitems use which geoms, so we can update the offset and count array if they change.\n        if (!this.glGeomIdsMapping[glGeomItem.geomId]) {\n            this.glGeomIdsMapping[glGeomItem.geomId] = [index];\n        }\n        else {\n            this.glGeomIdsMapping[glGeomItem.geomId].push(index);\n        }\n        this.glGeomItems[index] = glGeomItem;\n        this.glgeomItemEventHandlers[index] = eventHandlers;\n        this.drawIdsBufferDirty = true;\n        this.emit('updated');\n    }\n    /**\n     * The removeGLGeomItem method.\n     * @param {GLGeomItem} glGeomItem - The glGeomItem value.\n     */\n    removeGLGeomItem(glGeomItem) {\n        const index = this.glGeomItems.indexOf(glGeomItem);\n        const geomItemIndices = this.glGeomIdsMapping[glGeomItem.geomId];\n        geomItemIndices.splice(geomItemIndices.indexOf(index), 1);\n        if (geomItemIndices.length == 0) {\n            delete this.glGeomIdsMapping[glGeomItem.geomId];\n        }\n        this.renderer.glGeomLibrary.removeGeom(glGeomItem.geomId);\n        const eventHandlers = this.glgeomItemEventHandlers[index];\n        glGeomItem.geomItem.off('highlightChanged', eventHandlers.highlightChanged);\n        glGeomItem.off('visibilityChanged', eventHandlers.visibilityChanged);\n        this.glGeomItems[index] = null;\n        this.glgeomItemEventHandlers[index] = null;\n        this.freeIndices.push(index);\n        if (this.dirtyGeomItems.has(index)) {\n            this.dirtyGeomItems.delete(index);\n        }\n        // Clear any drawing allocations.\n        for (let key in this.drawIdsArraysAllocators) {\n            const prevAllocation = this.drawIdsArraysAllocators[key].getAllocation(index);\n            if (prevAllocation) {\n                for (let i = 0; i < prevAllocation.size; i++) {\n                    this.drawElementOffsets[key][prevAllocation.start + i] = 0;\n                    this.drawElementCounts[key][prevAllocation.start + i] = 0;\n                }\n                this.drawIdsArraysAllocators[key].deallocate(index);\n            }\n        }\n        const drawIndex = this.drawOrderToIndex.indexOf(index);\n        this.drawOrderToIndex.splice(drawIndex, 1);\n        this.indexToDrawIndex[index] = -1;\n        this.drawIdsBufferDirty = true;\n        if (glGeomItem.geomItem.isHighlighted()) {\n            delete this.highlightedItems[index];\n            this.highlightedIdsBufferDirty = true;\n        }\n        this.emit('updated');\n    }\n    // ////////////////////////////////////\n    // Draw Ids\n    // ////////////////////////////////////\n    // Instance Ids\n    /**\n     * The updateDrawIDsBuffer method.\n     * @param {RenderState} renderstate - The object used to track state changes during rendering.\n     */\n    updateDrawIDsBuffer(renderstate) {\n        this.dirtyGeomItems.forEach((index) => {\n            const glGeomItem = this.glGeomItems[index];\n            if (!glGeomItem)\n                return;\n            // Note: culled geoms should still be allocated.\n            // unculling/changing visiblity only changes the count value from zero to the actual value.\n            {\n                const geom = this.renderer.glGeomLibrary.getGeom(glGeomItem.geomId);\n                const geomBuffers = geom.genBuffers();\n                // Here we calculate how many draws for each type of geometry, each\n                // compound goem needs. We then allocate the space we have specified.\n                let drawCounts = {};\n                if (glGeomItem.shattered) {\n                    // for shattered geoms, we draw once for each subgeom for each element type\n                    for (let key in geomBuffers.subGeomCounts) {\n                        drawCounts[key] = geomBuffers.subGeomCounts[key].length;\n                    }\n                }\n                else {\n                    // for non-shattered geoms, we just draw once for each element type per GeomItem.\n                    for (let key in geomBuffers.materialSubGeoms) {\n                        drawCounts[key] = geomBuffers.materialSubGeoms[key].length;\n                    }\n                }\n                for (let key in drawCounts) {\n                    const drawCount = drawCounts[key];\n                    let allocator = this.drawIdsArraysAllocators[key];\n                    if (!allocator) {\n                        allocator = new Allocator1D();\n                        this.drawIdsArraysAllocators[key] = allocator;\n                    }\n                    else {\n                        // This happens when an item drawing changes. e.g. it becomes shattered.\n                        const prevAllocation = allocator.getAllocation(index);\n                        if (prevAllocation) {\n                            if (prevAllocation.size == drawCount)\n                                continue;\n                            // Zero the previous allocation to remove any rendering.\n                            for (let i = 0; i < prevAllocation.size; i++) {\n                                this.drawElementCounts[key][prevAllocation.start + i] = 0;\n                            }\n                        }\n                    }\n                    allocator.allocate(index, drawCount);\n                }\n            }\n        });\n        for (let key in this.drawIdsArraysAllocators) {\n            const allocator = this.drawIdsArraysAllocators[key];\n            // Note: the - 1 here is to avoid an exception thrown on Safari if the offsets and counts are\n            // exactly the size of the number of drawn items. (a bug in the validation).\n            if (!this.drawElementCounts[key] || allocator.reservedSpace > this.drawElementCounts[key].length - 1) {\n                const drawIdsArray = new Float32Array(allocator.reservedSpace * 4); // one RGBA pixel per drawn geometry.\n                // Note: the +1 here is to avoid an exception thrown on Safari if the offsets and counts are\n                // exactly the size of the number of drawn items. (a bug in the validation).\n                const drawElementOffsets = new Int32Array(allocator.reservedSpace + 1);\n                const drawElementCounts = new Int32Array(allocator.reservedSpace + 1);\n                if (this.drawElementCounts[key]) {\n                    drawIdsArray.set(this.drawIdsArrays[key], 0);\n                    drawElementOffsets.set(this.drawElementOffsets[key], 0);\n                    drawElementCounts.set(this.drawElementCounts[key], 0);\n                }\n                this.drawIdsArrays[key] = drawIdsArray;\n                this.drawElementOffsets[key] = drawElementOffsets;\n                this.drawElementCounts[key] = drawElementCounts;\n            }\n        }\n        const elementSize = 4; //  Uint32Array for UNSIGNED_INT\n        this.dirtyGeomItems.forEach((itemIndex) => {\n            const glGeomItem = this.glGeomItems[itemIndex];\n            if (!glGeomItem)\n                return;\n            const offsetAndCount = this.renderer.glGeomLibrary.getGeomOffsetAndCount(glGeomItem.geomId);\n            const geomBuffers = this.renderer.glGeomLibrary.getGeomBuffers(glGeomItem.geomId);\n            // If an item is invisible, we allocate values, but set all count values to zero\n            const visible = glGeomItem.isVisible();\n            if (glGeomItem.shattered) {\n                let subIndex = 0;\n                const addSubGeoms = (offsets, counts, type) => {\n                    const allocator = this.drawIdsArraysAllocators[type];\n                    const drawIdsArray = this.drawIdsArrays[type];\n                    const drawElementOffsets = this.drawElementOffsets[type];\n                    const drawElementCounts = this.drawElementCounts[type];\n                    const allocation = allocator.getAllocation(itemIndex);\n                    if (!allocation)\n                        return;\n                    const materials = geomBuffers.materials;\n                    // if (!this.indexToOffsets[type]) this.indexToOffsets[type] = []\n                    // this.indexToOffsets[type][itemIndex] = allocation.start\n                    for (let i = 0; i < offsets.length; i++) {\n                        // The draw id within this element type. (e.g. TRIANGLES, LINES, POINTS)\n                        const drawId = allocation.start + i;\n                        drawElementOffsets[drawId] = offsetAndCount[0] + offsets[i] * elementSize;\n                        drawElementCounts[drawId] = visible ? counts[i] : 0;\n                        drawIdsArray[drawId * 4 + 0] = glGeomItem.geomItemId;\n                        // Note: a zero value means no sub-geom was being drawn.\n                        drawIdsArray[drawId * 4 + 1] = subIndex + 1;\n                        // Note: subGeomMaterialIndices is Uint8Array, and 0 means no custom\n                        // material is assigned to the subGeom.\n                        // Subtract 1 to get the actual material id.\n                        const materialId = geomBuffers.subGeomMaterialIndices[subIndex];\n                        if (materials.length > 0 && materialId > 0 && materialId <= geomBuffers.materials.length) {\n                            const material = geomBuffers.materials[materialId - 1];\n                            const materialAddr = this.renderer.glMaterialLibrary.getMaterialAllocation(material);\n                            drawIdsArray[drawId * 4 + 2] = materialAddr.start;\n                        }\n                        else {\n                            drawIdsArray[drawId * 4 + 2] = 0.0;\n                        }\n                        drawIdsArray[drawId * 4 + 3] = 0; // spare\n                        subIndex++;\n                    }\n                };\n                addSubGeoms(geomBuffers.subGeomOffsets['TRIANGLES'], geomBuffers.subGeomCounts['TRIANGLES'], 'TRIANGLES');\n                addSubGeoms(geomBuffers.subGeomOffsets['LINES'], geomBuffers.subGeomCounts['LINES'], 'LINES');\n                addSubGeoms(geomBuffers.subGeomOffsets['POINTS'], geomBuffers.subGeomCounts['POINTS'], 'POINTS');\n            }\n            else {\n                const addSubGeoms = (subGeoms, type) => {\n                    const allocator = this.drawIdsArraysAllocators[type];\n                    const drawIdsArray = this.drawIdsArrays[type];\n                    const drawElementOffsets = this.drawElementOffsets[type];\n                    const drawElementCounts = this.drawElementCounts[type];\n                    const allocation = allocator.getAllocation(itemIndex);\n                    if (!allocation)\n                        return;\n                    const materials = geomBuffers.materials;\n                    // if (!this.indexToOffsets[type]) this.indexToOffsets[type] = []\n                    // this.indexToOffsets[type][itemIndex] = allocation.start\n                    for (let i = 0; i < subGeoms.length; i++) {\n                        const subGeom = subGeoms[i];\n                        // The draw id within this element type. (e.g. TRIANGLES, LINES, POINTS)\n                        const drawId = allocation.start + i;\n                        drawElementOffsets[drawId] = offsetAndCount[0] + subGeom.offset * elementSize;\n                        drawElementCounts[drawId] = visible ? subGeom.count : 0;\n                        drawIdsArray[drawId * 4 + 0] = glGeomItem.geomItemId;\n                        // Note: a zero value means no sub-geom was being drawn.\n                        drawIdsArray[drawId * 4 + 1] = 0;\n                        if (materials.length > 0 && subGeom.materialId >= 0 && geomBuffers.materials[subGeom.materialId]) {\n                            const material = geomBuffers.materials[subGeom.materialId];\n                            const materialAddr = this.renderer.glMaterialLibrary.getMaterialAllocation(material);\n                            drawIdsArray[drawId * 4 + 2] = materialAddr.start;\n                        }\n                        else {\n                            drawIdsArray[drawId * 4 + 2] = 0.0;\n                        }\n                        drawIdsArray[drawId * 4 + 3] = 0; // spare\n                    }\n                };\n                for (let key in geomBuffers.materialSubGeoms) {\n                    const allocator = this.drawIdsArraysAllocators[key];\n                    const allocation = allocator.getAllocation(itemIndex);\n                    if (!allocation)\n                        continue;\n                    const subGeoms = geomBuffers.materialSubGeoms[key];\n                    addSubGeoms(subGeoms, key);\n                }\n            }\n        });\n        const gl = this.renderer.gl;\n        let regen = false;\n        const updateDrawIdsTexture = (key) => {\n            const drawIdsArray = this.drawIdsArrays[key];\n            let drawIdsTexture = this.drawIdsTextures[key];\n            const reservedSpaceDrawCount = this.drawIdsArraysAllocators[key].reservedSpace;\n            const unit = renderstate.boundTextures++;\n            gl.activeTexture(gl.TEXTURE0 + unit);\n            const drawIdsTextureSize = MathFunctions.nextPow2(Math.ceil(Math.sqrt(reservedSpaceDrawCount)));\n            if (!drawIdsTexture) {\n                drawIdsTexture = new GLTexture2D(this.gl, {\n                    format: 'RGBA',\n                    type: 'FLOAT',\n                    width: drawIdsTextureSize,\n                    height: drawIdsTextureSize,\n                    filter: 'NEAREST',\n                    wrap: 'CLAMP_TO_EDGE',\n                    mipMapped: false,\n                });\n                this.drawIdsTextures[key] = drawIdsTexture;\n                regen = true;\n            }\n            else if (drawIdsTexture.width < drawIdsTextureSize || drawIdsTexture.height < drawIdsTextureSize) {\n                drawIdsTexture.resize(drawIdsTextureSize, drawIdsTextureSize);\n                for (let i = 0; i < this.drawOrderToIndex.length; i++)\n                    this.dirtyGeomItems.add(i);\n                regen = true;\n            }\n            {\n                const tex = drawIdsTexture;\n                const texWidth = drawIdsTexture.width;\n                gl.bindTexture(gl.TEXTURE_2D, tex.glTex);\n                const level = 0;\n                const xoffset = 0;\n                const height = 1;\n                const format = tex.format;\n                const type = tex.type;\n                if (regen) {\n                    const drawCount = this.drawIdsArraysAllocators[key].allocatedSpace;\n                    const rows = Math.ceil((xoffset + drawCount) / texWidth);\n                    let consumed = 0;\n                    let remaining = drawCount;\n                    let rowStart = xoffset;\n                    for (let i = 0; i < rows; i++) {\n                        let width;\n                        if (rowStart + remaining > texWidth) {\n                            width = texWidth - rowStart;\n                            rowStart = 0;\n                        }\n                        else {\n                            width = remaining;\n                        }\n                        const x = consumed % texWidth;\n                        const y = Math.floor(consumed / texWidth);\n                        const data = drawIdsArray.subarray(consumed * 4, (consumed + width) * 4);\n                        if (data.length != width * 4) {\n                            throw new Error('Invalid drawIds subarray :' + data.length + ' width:' + width);\n                        }\n                        gl.texSubImage2D(gl.TEXTURE_2D, level, x, y, width, height, format, type, data);\n                        consumed += width;\n                        remaining -= width;\n                    }\n                }\n                else {\n                    const allocator = this.drawIdsArraysAllocators[key];\n                    this.dirtyGeomItems.forEach((itemIndex) => {\n                        // const glGeomItem = this.glGeomItems[itemIndex]!\n                        // if (!glGeomItem /* || !glGeomItem.isVisible()*/) return\n                        const allocation = allocator.getAllocation(itemIndex);\n                        if (!allocation)\n                            return;\n                        const start = allocation.start;\n                        const drawCount = allocation.size;\n                        const xoffset = start % texWidth;\n                        const rows = Math.ceil((xoffset + drawCount) / texWidth);\n                        let consumed = 0;\n                        let remaining = drawCount;\n                        let rowStart = xoffset;\n                        for (let i = 0; i < rows; i++) {\n                            let width;\n                            if (rowStart + remaining > texWidth) {\n                                width = texWidth - rowStart;\n                                rowStart = 0;\n                            }\n                            else {\n                                width = remaining;\n                            }\n                            const x = (start + consumed) % texWidth;\n                            const y = Math.floor((start + consumed) / texWidth);\n                            const data = drawIdsArray.subarray((start + consumed) * 4, (start + consumed + width) * 4);\n                            if (data.length != width * 4) {\n                                throw new Error('Invalid drawIds subarray :' + data.length + ' width:' + width);\n                            }\n                            gl.texSubImage2D(gl.TEXTURE_2D, level, x, y, width, height, format, type, data);\n                            consumed += width;\n                            remaining -= width;\n                        }\n                    });\n                }\n            }\n            gl.bindTexture(gl.TEXTURE_2D, null);\n            renderstate.boundTextures--;\n        };\n        for (let key in this.drawIdsArrays) {\n            // TODO: Only re-upload the dirty items.\n            updateDrawIdsTexture(key);\n        }\n        this.dirtyGeomItems = new Set();\n        this.drawIdsBufferDirty = false;\n    }\n    // ////////////////////////////////////\n    // Selected Items\n    /**\n     * The updateHighlightedIDsBuffer method.\n     * @param {RenderState} renderstate - The object used to track state changes during rendering.\n     */\n    updateHighlightedIDsBuffer(renderstate) {\n        if (this.highlightedIdsBufferDirty) {\n            // Clear all previous highlight buffers.\n            // Note: we could considerably simplify the following code if we don't plan on\n            // incrementally updating the highlight code.\n            this.highlightedIdsArraysAllocators = {};\n            this.highlightedIdsArray = {};\n            this.highlightElementOffsets = {};\n            this.highlightElementCounts = {};\n            for (let key in this.highlightedItems) {\n                const index = Number.parseInt(key);\n                const subGeomIndices = this.highlightedItems[key];\n                const glGeomItem = this.glGeomItems[index];\n                const geomBuffers = this.renderer.glGeomLibrary.getGeomBuffers(glGeomItem.geomId);\n                let drawCounts = {\n                    TRIANGLES: 0,\n                    LINES: 0,\n                    POINTS: 0,\n                };\n                if (subGeomIndices.length > 0) {\n                    // for shattered geoms, we draw once for each subgeom for each element type\n                    subGeomIndices.forEach((subGeomIndex) => {\n                        if (subGeomIndex < geomBuffers.subGeomCounts['TRIANGLES'].length)\n                            drawCounts['TRIANGLES']++;\n                        else {\n                            const linesSubGeomIndex = subGeomIndex - geomBuffers.subGeomCounts['TRIANGLES'].length;\n                            if (linesSubGeomIndex < geomBuffers.subGeomCounts['LINES'].length)\n                                drawCounts['LINES']++;\n                            else {\n                                const pointsSubGeomIndex = linesSubGeomIndex - geomBuffers.subGeomCounts['LINES'].length;\n                                if (pointsSubGeomIndex < geomBuffers.subGeomCounts['POINTS'].length)\n                                    drawCounts['POINTS']++;\n                            }\n                        }\n                    });\n                }\n                else {\n                    // for non-shattered geoms, we just draw once for each element type per GeomItem.\n                    for (let key in geomBuffers.counts) {\n                        if (geomBuffers.counts[key] > 0)\n                            drawCounts[key] = 1;\n                    }\n                }\n                for (let key in drawCounts) {\n                    const drawCount = drawCounts[key];\n                    if (drawCount == 0)\n                        continue;\n                    if (!this.highlightedIdsArraysAllocators[key]) {\n                        this.highlightedIdsArraysAllocators[key] = new Allocator1D();\n                    }\n                    this.highlightedIdsArraysAllocators[key].allocate(index, drawCount);\n                }\n            }\n            // let regen = false\n            for (let key in this.highlightedIdsArraysAllocators) {\n                const allocator = this.highlightedIdsArraysAllocators[key];\n                // Note: the - 1 here is to avoid an exception thrown on Safari if the offsets and counts are\n                // exactly the size of the number of drawn items. (a bug in the validation).\n                if (!this.highlightElementCounts[key] ||\n                    allocator.reservedSpace > this.highlightElementCounts[key].length - 1) {\n                    // if (this.highlightElementCounts[key] && allocator.reservedSpace > this.highlightElementCounts[key].length - 1) regen = true\n                    this.highlightedIdsArray[key] = new Float32Array(allocator.reservedSpace * 4); // one RGBA pixel per drawn geometry.\n                    // Note: the +1 here is to avoid an exception thrown on Safari if the offsets and counts are\n                    // exactly the size of the number of drawn items. (a bug in the validation).\n                    this.highlightElementOffsets[key] = new Int32Array(allocator.reservedSpace + 1);\n                    this.highlightElementCounts[key] = new Int32Array(allocator.reservedSpace + 1);\n                }\n            }\n            const elementSize = 4; //  Uint32Array for UNSIGNED_INT\n            for (let key in this.highlightedItems) {\n                const itemIndex = Number.parseInt(key);\n                const subGeomIndices = this.highlightedItems[key];\n                const glGeomItem = this.glGeomItems[itemIndex];\n                const offsetAndCount = this.renderer.glGeomLibrary.getGeomOffsetAndCount(glGeomItem.geomId);\n                const geomBuffers = this.renderer.glGeomLibrary.getGeomBuffers(glGeomItem.geomId);\n                if (subGeomIndices.length != 0) {\n                    const subGeomOffsetsByType = { TRIANGLES: 0, LINES: 0, POINTS: 0 };\n                    subGeomIndices.forEach((subGeomIndex) => {\n                        const addSubGeom = (subGeomOffset, offsets, counts, type, subIndex) => {\n                            const allocator = this.highlightedIdsArraysAllocators[type];\n                            const drawIdsArray = this.highlightedIdsArray[type];\n                            const drawElementOffsets = this.highlightElementOffsets[type];\n                            const drawElementCounts = this.highlightElementCounts[type];\n                            const allocation = allocator.getAllocation(itemIndex);\n                            const drawId = allocation.start + subGeomOffset;\n                            drawElementOffsets[drawId] = offsetAndCount[0] + offsets[subIndex] * elementSize;\n                            drawElementCounts[drawId] = counts[subIndex];\n                            drawIdsArray[drawId * 4 + 0] = glGeomItem.geomItemId;\n                            drawIdsArray[drawId * 4 + 1] = subGeomIndex + 1;\n                            drawIdsArray[drawId * 4 + 2] = 0.0; // materialId\n                            drawIdsArray[drawId * 4 + 3] = 0.0; // spare\n                        };\n                        if (subGeomIndex < geomBuffers.subGeomCounts['TRIANGLES'].length) {\n                            addSubGeom(subGeomOffsetsByType['TRIANGLES'], geomBuffers.subGeomOffsets['TRIANGLES'], geomBuffers.subGeomCounts['TRIANGLES'], 'TRIANGLES', subGeomIndex);\n                            subGeomOffsetsByType['TRIANGLES']++;\n                        }\n                        else {\n                            const linesSubGeomIndex = subGeomIndex - geomBuffers.subGeomCounts['TRIANGLES'].length;\n                            if (linesSubGeomIndex < geomBuffers.subGeomCounts['LINES'].length) {\n                                addSubGeom(subGeomOffsetsByType['LINES'], geomBuffers.subGeomOffsets['LINES'], geomBuffers.subGeomCounts['LINES'], 'LINES', linesSubGeomIndex);\n                                subGeomOffsetsByType['LINES']++;\n                            }\n                            else {\n                                const pointsSubGeomIndex = linesSubGeomIndex - geomBuffers.subGeomCounts['LINES'].length;\n                                if (pointsSubGeomIndex < geomBuffers.subGeomCounts['POINTS'].length) {\n                                    addSubGeom(subGeomOffsetsByType['POINTS'], geomBuffers.subGeomOffsets['POINTS'], geomBuffers.subGeomCounts['POINTS'], 'POINTS', pointsSubGeomIndex);\n                                    subGeomOffsetsByType['POINTS']++;\n                                }\n                            }\n                        }\n                    });\n                }\n                else {\n                    for (let key in geomBuffers.offsets) {\n                        const count = geomBuffers.counts[key];\n                        if (count == 0)\n                            continue;\n                        const offset = geomBuffers.offsets[key];\n                        const allocator = this.highlightedIdsArraysAllocators[key];\n                        const allocation = allocator.getAllocation(itemIndex);\n                        const drawId = allocation.start;\n                        this.highlightElementOffsets[key][drawId] = offsetAndCount[0] + offset * elementSize;\n                        this.highlightElementCounts[key][drawId] = count;\n                        this.highlightedIdsArray[key][drawId * 4 + 0] = glGeomItem.geomItemId;\n                    }\n                }\n            }\n            this.highlightedIdsBufferDirty = false;\n        }\n        const gl = this.renderer.gl;\n        const updateDrawIdsTexture = (key) => {\n            const drawIdsArray = this.highlightedIdsArray[key];\n            if (!drawIdsArray || drawIdsArray.length == 0)\n                return;\n            let drawIdsTexture = this.highlightedIdsTextures[key];\n            const reservedSpaceDrawCount = this.highlightedIdsArraysAllocators[key].reservedSpace;\n            const unit = renderstate.boundTextures++;\n            gl.activeTexture(gl.TEXTURE0 + unit);\n            const drawIdsTextureSize = MathFunctions.nextPow2(Math.ceil(Math.sqrt(reservedSpaceDrawCount)));\n            if (!drawIdsTexture) {\n                drawIdsTexture = new GLTexture2D(this.gl, {\n                    format: 'RGBA',\n                    type: 'FLOAT',\n                    width: drawIdsTextureSize,\n                    height: drawIdsTextureSize,\n                    filter: 'NEAREST',\n                    wrap: 'CLAMP_TO_EDGE',\n                    mipMapped: false,\n                });\n                this.highlightedIdsTextures[key] = drawIdsTexture;\n            }\n            else if (drawIdsTexture.width < drawIdsTextureSize || drawIdsTexture.height < drawIdsTextureSize) {\n                drawIdsTexture.resize(drawIdsTextureSize, drawIdsTextureSize);\n            }\n            {\n                const tex = drawIdsTexture;\n                const texWidth = drawIdsTexture.width;\n                gl.bindTexture(gl.TEXTURE_2D, tex.glTex);\n                const level = 0;\n                const xoffset = 0;\n                const height = 1;\n                const format = tex.format;\n                const type = tex.type;\n                const drawCount = this.highlightedIdsArraysAllocators[key].allocatedSpace;\n                const rows = Math.ceil((xoffset + drawCount) / texWidth);\n                let consumed = 0;\n                let remaining = drawCount;\n                let rowStart = xoffset;\n                for (let i = 0; i < rows; i++) {\n                    let width;\n                    if (rowStart + remaining > texWidth) {\n                        width = texWidth - rowStart;\n                        rowStart = 0;\n                    }\n                    else {\n                        width = remaining;\n                    }\n                    const x = consumed % texWidth;\n                    const y = Math.floor(consumed / texWidth);\n                    const data = drawIdsArray.subarray(consumed * 4, (consumed + width) * 4);\n                    if (data.length != width * 4) {\n                        throw new Error('Invalid drawIds subarray :' + data.length + ' width:' + width);\n                    }\n                    gl.texSubImage2D(gl.TEXTURE_2D, level, x, y, width, height, format, type, data);\n                    consumed += width;\n                    remaining -= width;\n                }\n            }\n            gl.bindTexture(gl.TEXTURE_2D, null);\n            renderstate.boundTextures--;\n        };\n        for (let key in this.highlightedIdsArray) {\n            // TODO: Only re-upload the dirty items.\n            updateDrawIdsTexture(key);\n        }\n    }\n    // ////////////////////////////////////\n    // Drawing\n    /**\n     * The draw method.\n     * @param {RenderState} renderstate - The object tracking the current state of the renderer\n     */\n    draw(renderstate) {\n        if (this.drawOrderToIndex.length == 0) {\n            return;\n        }\n        if (this.drawIdsBufferDirty) {\n            this.updateDrawIDsBuffer(renderstate);\n        }\n        renderstate.pushGLStack('GLGeomItemSetMultiDrawCompoundGeom.draw');\n        const drawIdsArray = this.drawIdsArrays;\n        const counts = this.drawElementCounts;\n        const offsets = this.drawElementOffsets;\n        const drawIdsTextures = this.drawIdsTextures;\n        const allocators = this.drawIdsArraysAllocators;\n        const gl = this.gl;\n        const unifs = renderstate.unifs;\n        const depthFuncValue = gl.getParameter(gl.DEPTH_FUNC);\n        const { drawIdsTexture, geomType, outlineThickness, viewportSize, occluded, renderMode } = renderstate.unifs;\n        const renderModeValue = renderstate instanceof ColorRenderState && renderMode ? renderstate.renderMode : null;\n        const drawEdges = renderModeValue != 'flat-noedges' && renderModeValue != 'shaded-noedges' && renderModeValue != 'pbr-noedges';\n        const drawingOutlines = renderstate instanceof ColorRenderState &&\n            outlineThickness &&\n            viewportSize &&\n            renderstate.outlineMethod == 'geometry' &&\n            renderstate.outlineThickness > 0 &&\n            drawEdges;\n        const drawingWireframeOutlines = drawingOutlines && renderModeValue == 'wireframe';\n        // @ts-ignore\n        const drawingHiddenLines = \n        // @ts-ignore\n        renderstate.hiddenLineColor &&\n            // @ts-ignore\n            renderstate.hiddenLineColor.a > 0 &&\n            occluded;\n        if (drawingWireframeOutlines) {\n            gl.enable(gl.STENCIL_TEST);\n            gl.clearStencil(0);\n            gl.clear(gl.STENCIL_BUFFER_BIT);\n            gl.stencilOpSeparate(gl.FRONT, gl.DECR_WRAP, gl.DECR_WRAP, gl.DECR_WRAP);\n            gl.stencilOpSeparate(gl.BACK, gl.INCR_WRAP, gl.INCR_WRAP, gl.INCR_WRAP);\n            gl.stencilFunc(gl.ALWAYS, 0, 0xff);\n            gl.enable(gl.CULL_FACE);\n            gl.cullFace(gl.BACK);\n            gl.disable(gl.DEPTH_TEST);\n            gl.depthMask(false);\n            gl.colorMask(false, false, false, false);\n        }\n        else if (renderModeValue == 'hiddenline') {\n            // don't render surfaces. But render alpha channel\n            gl.colorMask(false, false, false, true);\n        }\n        else {\n            // Compound Geoms should always be rendered double sided\n            // so we can correctly render cutting planes.\n            // Note: We needed this because the FlatSurfaceShader turns on culling\n            // when it unbinds which then affects the rendering of other items like this.\n            // An issue is logged to clean this up.\n            // https://github.com/ZeaInc/zea-engine/issues/699\n            gl.disable(gl.CULL_FACE);\n        }\n        if (drawIdsArray['TRIANGLES'] && allocators['TRIANGLES'].allocatedSpace > 0) {\n            drawIdsTextures['TRIANGLES'].bindToUniform(renderstate, drawIdsTexture);\n            if (geomType)\n                gl.uniform1i(geomType.location, GeomType.TRIANGLES);\n            gl.enable(gl.POLYGON_OFFSET_FILL);\n            gl.polygonOffset(1, 1);\n            // Always zero this value before drawing the faces, else the shader could think its drawing the outline.\n            if (outlineThickness) {\n                gl.uniform1f(outlineThickness.location, 0);\n            }\n            renderstate.bindViewports(unifs, () => {\n                this.multiDrawMeshes(renderstate, counts['TRIANGLES'], offsets['TRIANGLES'], allocators['TRIANGLES'].allocatedSpace);\n            });\n            if (drawingOutlines) {\n                // Only draw font faces. BEcause all faces are drawn, it can make a mess to see the back faces through the front faces.\n                // e.g. we might see the triangles on the other side of a sphere rendered over the top of triangles on the near side.\n                gl.enable(gl.CULL_FACE);\n                gl.cullFace(gl.FRONT);\n                gl.uniform1f(outlineThickness.location, this.renderer.outlineThickness * window.devicePixelRatio);\n                gl.uniform2f(viewportSize.location, renderstate.region[2] - renderstate.region[0], renderstate.region[3] - renderstate.region[1]);\n                if (renderModeValue == 'hiddenline') {\n                    // start rendering surfaces again\n                    gl.colorMask(true, true, true, true);\n                }\n                if (!drawingWireframeOutlines) {\n                    renderstate.glEnable(gl.BLEND);\n                    gl.blendEquation(gl.FUNC_ADD);\n                    gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE);\n                }\n                renderstate.bindViewports(unifs, () => {\n                    this.multiDrawMeshes(renderstate, counts['TRIANGLES'], offsets['TRIANGLES'], allocators['TRIANGLES'].allocatedSpace);\n                });\n                gl.disable(gl.CULL_FACE);\n                gl.cullFace(gl.BACK);\n                if (drawingWireframeOutlines) {\n                    gl.enable(gl.DEPTH_TEST);\n                    gl.depthMask(true);\n                    gl.colorMask(true, true, true, true);\n                    gl.stencilFunc(gl.NOTEQUAL, 0x0, 0xff);\n                    gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);\n                    {\n                        renderstate.glEnable(gl.BLEND);\n                        gl.blendEquation(gl.FUNC_ADD);\n                        gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE);\n                    }\n                    // cache the previously bound shader.\n                    const shader = renderstate.glShader;\n                    const shaderKey = renderstate.shaderkey;\n                    const screenQuad = this.renderer.screenQuad;\n                    screenQuad.bindShader(renderstate);\n                    screenQuad.draw(renderstate, this.renderer.outlineColor);\n                    // Re-bind the previously bound geomdata shader.\n                    shader.bind(renderstate, shaderKey);\n                    this.renderer.glGeomItemLibrary.bind(renderstate);\n                    this.renderer.glGeomLibrary.bind(renderstate);\n                    this.renderer.glMaterialLibrary.bind(renderstate);\n                    gl.disable(gl.STENCIL_TEST);\n                }\n            }\n            else {\n                renderstate.glEnable(gl.BLEND);\n                gl.blendEquation(gl.FUNC_ADD);\n                gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE);\n            }\n            gl.disable(gl.POLYGON_OFFSET_FILL);\n        }\n        if (drawEdges && drawIdsArray['LINES'] && allocators['LINES'].allocatedSpace > 0) {\n            drawIdsTextures['LINES'].bindToUniform(renderstate, drawIdsTexture);\n            if (geomType)\n                gl.uniform1i(geomType.location, GeomType.LINES);\n            renderstate.bindViewports(unifs, () => {\n                this.multiDrawLines(renderstate, counts['LINES'], offsets['LINES'], allocators['LINES'].allocatedSpace);\n            });\n            if (drawingHiddenLines) {\n                const { hiddenLineColor } = renderstate.unifs;\n                gl.uniform1i(occluded.location, 1);\n                // @ts-ignore\n                gl.uniform4fv(hiddenLineColor.location, renderstate.hiddenLineColor.asArray());\n                gl.depthFunc(gl.GREATER);\n                gl.depthMask(false);\n                renderstate.bindViewports(unifs, () => {\n                    this.multiDrawLines(renderstate, counts['LINES'], offsets['LINES'], allocators['LINES'].allocatedSpace);\n                });\n                // Restore defaults.\n                gl.depthFunc(depthFuncValue);\n                gl.depthMask(true);\n                gl.uniform1i(occluded.location, 0);\n            }\n        }\n        if (drawIdsArray['POINTS'] && allocators['POINTS'].allocatedSpace > 0) {\n            drawIdsTextures['POINTS'].bindToUniform(renderstate, drawIdsTexture);\n            if (geomType)\n                gl.uniform1i(geomType.location, GeomType.POINTS);\n            renderstate.bindViewports(unifs, () => {\n                this.multiDrawPoints(renderstate, counts['POINTS'], offsets['POINTS'], allocators['POINTS'].allocatedSpace);\n            });\n            if (drawingHiddenLines) {\n                const { hiddenLineColor } = renderstate.unifs;\n                gl.uniform1i(occluded.location, 1);\n                // @ts-ignore\n                gl.uniform4fv(hiddenLineColor.location, renderstate.hiddenLineColor.asArray());\n                gl.depthFunc(gl.GREATER);\n                gl.depthMask(false);\n                renderstate.bindViewports(unifs, () => {\n                    this.multiDrawPoints(renderstate, counts['POINTS'], offsets['POINTS'], allocators['POINTS'].allocatedSpace);\n                });\n                gl.depthFunc(depthFuncValue);\n                gl.depthMask(true);\n                gl.uniform1i(occluded.location, 0);\n            }\n        }\n        // Reset to drawing triangles in case the shader is used\n        // to draw a regular mesh next.\n        if (geomType)\n            gl.uniform1i(geomType.location, 0);\n        renderstate.popGLStack();\n    }\n    /**\n     * The drawGeomData method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    drawGeomData(renderstate) {\n        if (this.drawIdsBufferDirty) {\n            this.updateDrawIDsBuffer(renderstate);\n        }\n        renderstate.pushGLStack('GLGeomItemSetMultiDrawCompoundGeom.drawGeomData');\n        const gl = this.renderer.gl;\n        const unifs = renderstate.unifs;\n        const { drawIdsTexture, geomType } = unifs;\n        const counts = this.drawElementCounts;\n        const offsets = this.drawElementOffsets;\n        const drawIdsTextures = this.drawIdsTextures;\n        const allocators = this.drawIdsArraysAllocators;\n        const drawIdsArray = this.drawIdsArrays;\n        if (this.renderer.renderMode != 'wireframe') {\n            renderstate.bindViewports(unifs, () => {\n                if (drawIdsArray['TRIANGLES'] && allocators['TRIANGLES'].allocatedSpace > 0) {\n                    drawIdsTextures['TRIANGLES'].bindToUniform(renderstate, drawIdsTexture);\n                    if (geomType)\n                        gl.uniform1i(geomType.location, GeomType.TRIANGLES);\n                    gl.enable(gl.POLYGON_OFFSET_FILL);\n                    gl.polygonOffset(1, 1);\n                    this.multiDrawMeshes(renderstate, counts['TRIANGLES'], offsets['TRIANGLES'], allocators['TRIANGLES'].allocatedSpace);\n                    gl.disable(gl.POLYGON_OFFSET_FILL);\n                }\n            });\n        }\n        //  Note: lines in VR are not fattened...\n        const enableLineFattening = true;\n        if (renderstate.geomDataFbo && enableLineFattening) {\n            if (!this.linesGeomDataBuffer) {\n                this.linesGeomDataBuffer = new GLTexture2D(gl, {\n                    type: this.renderer.floatGeomBuffer ? 'FLOAT' : 'UNSIGNED_BYTE',\n                    format: 'RGBA',\n                    filter: 'NEAREST',\n                    width: 1,\n                    height: 2,\n                });\n                this.fattenLinesShader = new FattenLinesShader(gl);\n                this.quad = new GLMesh(gl, new Plane(1, 1));\n            }\n            const geomDataFbo = renderstate.geomDataFbo;\n            const width = geomDataFbo.width;\n            const height = geomDataFbo.height;\n            if (this.linesGeomDataBuffer.width != width || this.linesGeomDataBuffer.height != height) {\n                if (this.fbo) {\n                    gl.deleteFramebuffer(this.fbo);\n                    this.fbo = null;\n                }\n                this.linesGeomDataBuffer.resize(width, height);\n                this.fbo = gl.createFramebuffer();\n                const colorTex = this.linesGeomDataBuffer.glTex;\n                const depthBuffer = geomDataFbo.depthTexture; // Share the existing depth buffer.\n                gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, this.fbo);\n                gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, colorTex, 0);\n                gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, depthBuffer, 0);\n                checkFramebuffer(gl, width, height);\n            }\n            else {\n                gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, this.fbo);\n            }\n            gl.colorMask(true, true, true, true);\n            gl.clearColor(0, 0, 0, 0);\n            gl.clear(gl.COLOR_BUFFER_BIT); // do not clear depth\n        }\n        renderstate.bindViewports(unifs, () => {\n            if (drawIdsArray['LINES'] && allocators['LINES'].allocatedSpace > 0) {\n                drawIdsTextures['LINES'].bindToUniform(renderstate, drawIdsTexture);\n                if (geomType)\n                    gl.uniform1i(geomType.location, GeomType.LINES);\n                this.multiDrawLines(renderstate, counts['LINES'], offsets['LINES'], allocators['LINES'].allocatedSpace);\n            }\n            if (drawIdsArray['POINTS'] && allocators['POINTS'].allocatedSpace > 0) {\n                drawIdsTextures['POINTS'].bindToUniform(renderstate, drawIdsTexture);\n                if (geomType)\n                    gl.uniform1i(geomType.location, GeomType.POINTS);\n                this.multiDrawPoints(renderstate, counts['POINTS'], offsets['POINTS'], allocators['POINTS'].allocatedSpace);\n            }\n        });\n        if (this.linesGeomDataBuffer && renderstate.geomDataFbo && enableLineFattening) {\n            renderstate.boundRendertarget = null;\n            renderstate.geomDataFbo.bindForWriting(renderstate);\n            // cache the previously bound shader.\n            const geomDataShader = renderstate.glShader;\n            const geomDataShaderKey = renderstate.shaderkey;\n            this.fattenLinesShader.bind(renderstate);\n            gl.disable(gl.DEPTH_TEST);\n            const { colorTexture, screenSize, pointAndLinePickingSize } = renderstate.unifs;\n            this.linesGeomDataBuffer.bindToUniform(renderstate, colorTexture);\n            const geomDataFbo = renderstate.geomDataFbo;\n            gl.uniform2f(screenSize.location, geomDataFbo.width, geomDataFbo.height);\n            gl.uniform1i(pointAndLinePickingSize.location, renderstate.pointAndLinePickingSize);\n            this.quad.bindAndDraw(renderstate);\n            gl.enable(gl.DEPTH_TEST);\n            // Re-bind the previously bound geomdata shader.\n            geomDataShader.bind(renderstate, geomDataShaderKey);\n            this.renderer.glGeomItemLibrary.bind(renderstate);\n            this.renderer.glGeomLibrary.bind(renderstate);\n            this.renderer.glMaterialLibrary.bind(renderstate);\n        }\n        renderstate.popGLStack();\n    }\n    /**\n     * The drawHighlighted method.\n     * @param {HighlightRenderState} renderstate - The object tracking the current state of the renderer\n     */\n    drawHighlighted(renderstate) {\n        if (Object.keys(this.highlightedItems).length == 0) {\n            return;\n        }\n        if (this.highlightedIdsBufferDirty) {\n            this.updateHighlightedIDsBuffer(renderstate);\n        }\n        renderstate.pushGLStack('GLGeomItemSetMultiDrawCompoundGeom.drawHighlighted');\n        const drawIdsArray = this.highlightedIdsArray;\n        const counts = this.highlightElementCounts;\n        const offsets = this.highlightElementOffsets;\n        const drawIdsTextures = this.highlightedIdsTextures;\n        const allocators = this.highlightedIdsArraysAllocators;\n        const unifs = renderstate.unifs;\n        const gl = this.renderer.gl;\n        // Compound Geoms should always be rendered double sided\n        // so we can correctly render cutting planes.\n        // Note: We needed this because the FlatSurfaceShader turns on culling\n        // when it unbinds which then affects the rendering of other items like this.\n        // An issue is logged to clean this up.\n        // https://github.com/ZeaInc/zea-engine/issues/699\n        renderstate.glDisable(gl.CULL_FACE);\n        const { drawIdsTexture, geomType } = renderstate.unifs;\n        renderstate.bindViewports(unifs, () => {\n            if (drawIdsArray['TRIANGLES'] && allocators['TRIANGLES'].allocatedSpace > 0) {\n                drawIdsTextures['TRIANGLES'].bindToUniform(renderstate, drawIdsTexture);\n                gl.enable(gl.POLYGON_OFFSET_FILL);\n                gl.polygonOffset(1, 1);\n                if (geomType)\n                    gl.uniform1i(geomType.location, GeomType.TRIANGLES);\n                this.multiDrawMeshes(renderstate, counts['TRIANGLES'], offsets['TRIANGLES'], allocators['TRIANGLES'].allocatedSpace);\n                gl.disable(gl.POLYGON_OFFSET_FILL);\n            }\n            if (drawIdsArray['LINES'] && allocators['LINES'].allocatedSpace > 0) {\n                drawIdsTextures['LINES'].bindToUniform(renderstate, drawIdsTexture);\n                if (geomType)\n                    gl.uniform1i(geomType.location, GeomType.LINES);\n                this.multiDrawLines(renderstate, counts['LINES'], offsets['LINES'], allocators['LINES'].allocatedSpace);\n            }\n            if (drawIdsArray['POINTS'] && allocators['POINTS'].allocatedSpace > 0) {\n                drawIdsTextures['POINTS'].bindToUniform(renderstate, drawIdsTexture);\n                if (geomType)\n                    gl.uniform1i(geomType.location, GeomType.POINTS);\n                this.multiDrawPoints(renderstate, counts['POINTS'], offsets['POINTS'], allocators['POINTS'].allocatedSpace);\n            }\n        });\n        // Reset to drawing triangles in case the shader is used\n        // to draw a regular mesh next.\n        if (geomType)\n            gl.uniform1i(geomType.location, 0);\n        renderstate.popGLStack();\n    }\n    multiDrawMeshes(renderstate, counts, offsets, drawCount) {\n        const gl = this.gl;\n        if (gl.multiDrawElements) {\n            gl.multiDrawElements(gl.TRIANGLES, counts, 0, gl.UNSIGNED_INT, offsets, 0, drawCount);\n        }\n        else {\n            const { drawId } = renderstate.unifs;\n            for (let i = 0; i < drawCount; i++) {\n                gl.uniform1i(drawId.location, i);\n                gl.drawElements(gl.TRIANGLES, counts[i], gl.UNSIGNED_INT, offsets[i]);\n            }\n        }\n    }\n    multiDrawLines(renderstate, counts, offsets, drawCount) {\n        const gl = this.gl;\n        if (gl.multiDrawElements) {\n            gl.multiDrawElements(gl.LINES, counts, 0, gl.UNSIGNED_INT, offsets, 0, drawCount);\n        }\n        else {\n            const { drawId } = renderstate.unifs;\n            for (let i = 0; i < drawCount; i++) {\n                gl.uniform1i(drawId.location, i);\n                gl.drawElements(gl.LINES, counts[i], gl.UNSIGNED_INT, offsets[i]);\n            }\n        }\n    }\n    multiDrawPoints(renderstate, counts, offsets, drawCount) {\n        const gl = this.gl;\n        if (gl.multiDrawElements) {\n            gl.multiDrawElements(gl.POINTS, counts, 0, gl.UNSIGNED_INT, offsets, 0, drawCount);\n        }\n        else {\n            const { drawId } = renderstate.unifs;\n            for (let i = 0; i < drawCount; i++) {\n                gl.uniform1i(drawId.location, i);\n                gl.drawElements(gl.POINTS, counts[i], gl.UNSIGNED_INT, offsets[i]);\n            }\n        }\n    }\n    // /**\n    //  * Draw an item to screen.\n    //  * @param {RenderState} renderstate - The object tracking the current state of the renderer\n    //  * @param {Float32Array} drawIds - the draw id for each element drawn in by this draw call.\n    //  * @param {Int32Array} counts - the geom element count for each element drawn in by this draw call.\n    //  * @param {Int32Array} offsets - the geom element offset for each element drawn in by this draw call.\n    //  * @param {number} drawCount - the number of active draw calls for this invocation\n    //  */\n    // abstract multiDraw(\n    //   renderstate: RenderState,\n    //   drawIds: Float32Array,\n    //   counts: Int32Array,\n    //   offsets: Int32Array,\n    //   drawCount: number\n    // ): void\n    /**\n     * Sorts the drawn items in order furthest to nearest when rendering transparent objects.\n     * @param {Vec3} viewPos - The position of the camera that we are sorting relative to.\n     */\n    sortItems(viewPos) {\n        if (this.drawIdsBufferDirty) {\n            return;\n        }\n        // The sorting breaks the tellescope dataset is strange ways.\n        // disabling for now.\n        return;\n        /*\n        const distances: Float32Array = new Float32Array(this.drawOrderToIndex.length)\n        this.drawOrderToIndex.forEach((itemIndex) => {\n          const glGeomItem = this.glGeomItems[itemIndex]\n          if (glGeomItem) {\n            const bbox = glGeomItem.geomItem.boundingBoxParam.value\n            // Calculate the disance to the surface of the bounding sphere.\n            // TODO: calculate the distance the nearest point on the bounding box.\n            const center = bbox.center()\n            const size = bbox.size()\n            const dist = center.distanceTo(viewPos) - size\n    \n            distances[itemIndex] = dist\n          }\n        })\n        this.drawOrderToIndex.sort((a, b) => distances[b] - distances[a])\n    \n        // Now we re-create the drawElementCounts arrays according to the order of the drawn GLGeomItems.\n        // Note: We draw the TRIANGLES, then LINES, then POINTS. We can't draw lines behind transparent geoms.\n        // We could simply not bother sorting the lines and points.\n        const gl = this.gl\n        const drawElementCounts: Record<string, Int32Array> = {}\n        const drawElementOffsets: Record<string, Int32Array> = {}\n        if (this.drawElementCounts.TRIANGLES) {\n          drawElementCounts.TRIANGLES = new Int32Array(this.drawElementCounts.TRIANGLES.length + 1)\n          drawElementOffsets.TRIANGLES = new Int32Array(this.drawElementOffsets.TRIANGLES.length + 1)\n        }\n        if (this.drawElementCounts.TRIANGLES) {\n          drawElementCounts.LINES = new Int32Array(this.drawElementCounts.LINES.length + 1)\n          drawElementOffsets.LINES = new Int32Array(this.drawElementOffsets.LINES.length + 1)\n        }\n        if (this.drawElementCounts.POINTS) {\n          drawElementCounts.POINTS = new Int32Array(this.drawElementCounts.POINTS.length + 1)\n          drawElementOffsets.POINTS = new Int32Array(this.drawElementOffsets.POINTS.length + 1)\n        }\n    \n        const drawOffsets: Record<string, number> = {\n          TRIANGLES: 0,\n          LINES: 0,\n          POINTS: 0,\n        }\n        const elementSize = 4 //  Uint32Array for UNSIGNED_INT\n        this.drawOrderToIndex.forEach((itemIndex, drawIndex) => {\n          const glGeomItem = this.glGeomItems[itemIndex]\n          if (glGeomItem) {\n            for (let key in this.drawIdsArraysAllocators) {\n              const drawOffset = drawOffsets[key]\n              const allocation = this.drawIdsArraysAllocators[key].getAllocation(itemIndex)\n              if (!allocation) continue\n    \n              const geomBuffers = this.renderer.glGeomLibrary.getGeomBuffers(glGeomItem.geomId)\n              const offsetAndCount = this.renderer.glGeomLibrary.getGeomOffsetAndCount(glGeomItem.geomId)\n              if (allocation.size > 1) {\n                for (let i = 0; i < allocation.size; i++) {\n                  const drawId = drawOffset + i\n                  drawElementCounts[key][drawId] = glGeomItem.culled ? 0 : geomBuffers.subGeomCounts[key][i]\n                  drawElementOffsets[key][drawId] = offsetAndCount[0] + geomBuffers.offsets[key] * elementSize\n                }\n              } else {\n                drawElementCounts[key][drawOffset] = glGeomItem.culled ? 0 : geomBuffers.counts[key]\n                drawElementOffsets[key][drawOffset] = offsetAndCount[0] + geomBuffers.offsets[key] * elementSize\n              }\n              if (!this.indexToOffsets[key]) this.indexToOffsets[key] = []\n              this.indexToOffsets[key][itemIndex] = drawOffset\n    \n              ////////////////////////////////////////\n              //\n              const drawIdsArray = this.drawIdsArrays[key]\n              let drawIdsTexture = this.drawIdsTextures[key]\n              const tex = drawIdsTexture\n              const texWidth = drawIdsTexture.width\n              gl.bindTexture(gl.TEXTURE_2D, tex.glTex)\n              const level = 0\n              const height = 1\n              const format = tex.format\n              const type = tex.type\n    \n              const startSrc = allocation.start\n              const startTgt = drawOffset\n              const drawCount = allocation.size\n    \n              const xoffset = startTgt % texWidth\n              const rows = Math.ceil((xoffset + drawCount) / texWidth)\n              let consumed = 0\n              let remaining = drawCount\n              let rowStart = xoffset\n              for (let i = 0; i < rows; i++) {\n                let width\n                if (rowStart + remaining > texWidth) {\n                  width = texWidth - rowStart\n                  rowStart = 0\n                } else {\n                  width = remaining\n                }\n                const x = (startTgt + consumed) % texWidth\n                const y = Math.floor((startTgt + consumed) / texWidth)\n                const data = drawIdsArray.subarray((startSrc + consumed) * 4, (startSrc + consumed + width) * 4)\n                if (data.length != width * 4) {\n                  throw new Error('Invalid drawIds subarray :' + data.length + ' width:' + width)\n                }\n                gl.texSubImage2D(gl.TEXTURE_2D, level, x, y, width, height, format, type, data)\n    \n                consumed += width\n                remaining -= width\n              }\n              drawOffsets[key] += allocation.size\n            }\n            this.indexToDrawIndex[itemIndex] = drawIndex\n          }\n        })\n        this.drawElementCounts = drawElementCounts\n        this.drawElementOffsets = drawElementOffsets\n    \n        gl.bindTexture(gl.TEXTURE_2D, null)\n        */\n    }\n    /**\n     * The destroy is called by the system to cause explicit resources cleanup.\n     * Users should never need to call this method directly.\n     */\n    destroy() {\n        for (let key in this.drawIdsTextures) {\n            this.drawIdsTextures[key].destroy();\n        }\n        for (let key in this.highlightedIdsTextures) {\n            this.highlightedIdsTextures[key].destroy();\n        }\n        this.emit('destructing');\n    }\n}\n\n/* eslint-disable guard-for-in */\n/** Class representing GL shader materials.\n * @private\n */\nclass GLShaderGeomSets extends EventEmitter {\n    renderer;\n    gl;\n    glShader;\n    glGeomItemSets = {};\n    /**\n     * Create a GL shader material.\n     * @param pass - The pass that owns this object.\n     * @param gl - The glShader value.\n     * @param shaders - The shader value.\n     */\n    constructor(renderer, gl, glShader) {\n        super();\n        this.renderer = renderer;\n        this.gl = gl;\n        this.glShader = glShader;\n    }\n    /**\n     * Given a GeomItem, constructs the GLGeomItemSet that handles drawing that type of geometry.\n     * @param geom - The geomitem value.\n     * @return - The return value.\n     * */\n    getOrCreateGLGeomItemSet(geom) {\n        let glGeomItemSet;\n        if (geom instanceof CompoundGeom) {\n            if (this.glGeomItemSets['CompoundGeom'])\n                return this.glGeomItemSets['CompoundGeom'];\n            glGeomItemSet = new GLGeomItemSetMultiDrawCompoundGeom(this.renderer);\n            this.glGeomItemSets['CompoundGeom'] = glGeomItemSet;\n        }\n        else if (geom instanceof Mesh || geom instanceof MeshProxy) {\n            if (this.glGeomItemSets['GLMesh'])\n                return this.glGeomItemSets['GLMesh'];\n            glGeomItemSet = new GLMeshItemSet(this.renderer);\n            this.glGeomItemSets['GLMesh'] = glGeomItemSet;\n        }\n        else if (geom instanceof Lines || geom instanceof LinesProxy) {\n            if (this.glGeomItemSets['GLLines'])\n                return this.glGeomItemSets['GLLines'];\n            glGeomItemSet = new GLLinesItemSet(this.renderer);\n            this.glGeomItemSets['GLLines'] = glGeomItemSet;\n        }\n        else if (geom instanceof Points || geom instanceof PointsProxy) {\n            if (this.glGeomItemSets['GLPoints'])\n                return this.glGeomItemSets['GLPoints'];\n            glGeomItemSet = new GLPointsItemSet(this.renderer);\n            this.glGeomItemSets['GLPoints'] = glGeomItemSet;\n        }\n        else {\n            throw new Error('Unsupported geom type:' + geom.constructor.name);\n        }\n        glGeomItemSet.on('updated', () => {\n            this.emit('updated');\n        });\n        return glGeomItemSet;\n    }\n    /**\n     * The addGLGeomItem method.\n     * @param glGeomItem - The glGeomItem value.\n     */\n    addGLGeomItem(glGeomItem) {\n        const geom = glGeomItem.geomItem.geomParam.value;\n        const glGeomItemSet = this.getOrCreateGLGeomItemSet(geom);\n        glGeomItem.GLGeomItemSet = glGeomItemSet;\n        glGeomItemSet.addGLGeomItem(glGeomItem);\n    }\n    /**\n     *  Called by the GLPass to remove an item from this GLShaderGeomSets object.\n     * @param glGeomItem - The glGeomItem value.\n     */\n    removeGLGeomItem(glGeomItem) {\n        const glGeomItemSet = glGeomItem.GLGeomItemSet;\n        glGeomItemSet.removeGLGeomItem(glGeomItem);\n        glGeomItem.GLGeomItemSet = null;\n    }\n    /**\n     * Binds one of its shaders for rendering, and also the other textures and values needed.\n     * @param glShader - The shader to bind\n     * @param renderstate - The render state for the current draw traversal\n     * @param key - The key to use to cache the shader binding.\n     * @private\n     */\n    bindShader(glShader, renderstate, key) {\n        const gl = this.gl;\n        // to force the re-compliation of a shader with different\n        // directives, we supply a different key.\n        if (!glShader.isCompiledForTarget(key)) {\n            if (gl.multiDrawElements) {\n                renderstate.directives.push('#define ENABLE_MULTI_DRAW\\n#extension GL_ANGLE_multi_draw : enable');\n            }\n            else {\n                renderstate.directives.push('#define ENABLE_MULTI_DRAW');\n            }\n            glShader.compileForTarget(key, renderstate.directives);\n            renderstate.directives.pop();\n        }\n        if (!glShader.bind(renderstate, key)) {\n            throw new Error('Unable to bind shader:' + glShader);\n        }\n        this.renderer.glGeomItemLibrary.bind(renderstate);\n        this.renderer.glGeomLibrary.bind(renderstate);\n        this.renderer.glMaterialLibrary.bind(renderstate);\n    }\n    /**\n     * Draws all elements, binding the shader and continuing into the GLGLGeomSetGeomItemSets\n     * @param renderstate - The render state for the current draw traversal\n     */\n    draw(renderstate) {\n        this.bindShader(this.glShader, renderstate, 'multidraw-draw');\n        for (const elementType in this.glGeomItemSets) {\n            this.glGeomItemSets[elementType].draw(renderstate);\n        }\n        this.glShader.unbind(renderstate);\n    }\n    /**\n     * The drawHighlightedGeoms method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    drawHighlightedGeoms(renderstate) {\n        this.bindShader(this.glShader, renderstate, 'multidraw-highlight');\n        for (const elementType in this.glGeomItemSets) {\n            this.glGeomItemSets[elementType].drawHighlighted(renderstate);\n        }\n        this.glShader.unbind(renderstate);\n    }\n    /**\n     * The drawGeomData method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    drawGeomData(renderstate) {\n        this.bindShader(this.glShader, renderstate, 'multidraw-geomdata');\n        const gl = renderstate.gl;\n        const { passId } = renderstate.unifs;\n        if (passId) {\n            gl.uniform1i(passId.location, renderstate.passIndex);\n        }\n        for (const elementType in this.glGeomItemSets) {\n            this.glGeomItemSets[elementType].drawGeomData(renderstate);\n        }\n        this.glShader.unbind(renderstate);\n    }\n    /**\n     * Sorts the drawn items in order furthest to nearest when rendering transparent objects.\n     * @param viewPos - The position of the camera that we are sorting relative to.\n     */\n    sortItems(viewPos) {\n        // Note: sorting here will not sort geometries of different types.\n        // this is a flawed solution that only sorts geomemtries of the same\n        // time and same shader against each other. Given that this is the data 99% o\n        // of the time, this is an acceptable tradeoff\n        for (const elementType in this.glGeomItemSets) {\n            this.glGeomItemSets[elementType].sortItems(viewPos);\n        }\n    }\n}\n\n/* eslint-disable guard-for-in */\n/** Class representing GL material geom item sets.\n * @private\n */\nclass GLMaterialGeomItemSets extends EventEmitter {\n    pass;\n    gl;\n    glMaterial;\n    glGeomItemSets = new Map();\n    listenerIds = {};\n    drawCount = 0;\n    /**\n     * Create a GL material geom item set.\n     * @param pass - The pass that owns the GLMaterialGeomItemSets.\n     * @param glMaterial - The glMaterial value.\n     */\n    constructor(pass, glMaterial) {\n        super();\n        this.pass = pass;\n        this.gl = pass.renderer.gl;\n        if (glMaterial) {\n            this.glMaterial = glMaterial;\n            const material = glMaterial.material;\n            const opacityChanged = () => {\n                material.off('opacityChanged', opacityChanged);\n                this.glGeomItemSets.forEach((glGeomItemSet) => {\n                    for (const glGeomItem of glGeomItemSet.glGeomItems) {\n                        const geomItem = glGeomItem.geomItem;\n                        this.pass.removeGeomItem(geomItem);\n                        this.pass.renderer.assignTreeItemToGLPass(geomItem);\n                    }\n                });\n            };\n            this.listenerIds['material.opacityChanged'] = material.on('opacityChanged', opacityChanged);\n        }\n    }\n    /**\n     * The addGLGeomItem method.\n     * @param glGeomItem - The glGeomItem value.\n     * @param glGeom - The glGeomItem value.\n     * @private\n     */\n    addGLGeomItem(glGeomItem, glGeom) {\n        let geomItemSet = this.glGeomItemSets.get(glGeom);\n        if (!geomItemSet) {\n            geomItemSet = new GLGeomItemSet(this.gl, glGeom);\n            this.addGeomItemSet(geomItemSet);\n        }\n        geomItemSet.addGLGeomItem(glGeomItem);\n    }\n    /**\n     * The drawCountChanged method.\n     * @param event - The change value.\n     * @private\n     */\n    drawCountChanged(event) {\n        this.drawCount += event.change;\n        this.emit('updated');\n    }\n    /**\n     * The addGeomItemSet method.\n     * @param glGeomItemSet - The glGeomItemSet value.\n     */\n    addGeomItemSet(glGeomItemSet) {\n        this.glGeomItemSets.set(glGeomItemSet.getGLGeom(), glGeomItemSet);\n        const listenerID = glGeomItemSet.on('drawCountChanged', (event) => {\n            this.drawCountChanged(event);\n        });\n        glGeomItemSet.once('destructing', () => {\n            glGeomItemSet.off('drawCountChanged', listenerID);\n            this.glGeomItemSets.delete(glGeomItemSet.getGLGeom());\n            if (this.glGeomItemSets.size == 0 && this.glMaterial) {\n                // Remove the listeners.\n                const material = this.glMaterial.material;\n                material.off('opacityChanged', this.listenerIds['material.opacityChanged']);\n                this.emit('destructing');\n            }\n        });\n    }\n    /**\n     * Draws all elements, binding the shader and continuing into the GLGeomItemSet\n     * @param renderstate - The render state for the current draw traversal\n     */\n    draw(renderstate) {\n        if (this.drawCount == 0)\n            return;\n        const warnMissingUnifs = true;\n        if (this.glMaterial)\n            this.glMaterial.bind(renderstate, warnMissingUnifs);\n        this.glGeomItemSets.forEach((glGeomItemSet) => {\n            glGeomItemSet.draw(renderstate);\n        });\n        if (this.glMaterial)\n            this.glMaterial.unbind(renderstate);\n    }\n    /**\n     * The drawHighlighted method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    drawHighlighted(renderstate) {\n        if (this.glMaterial)\n            this.glMaterial.bind(renderstate, false);\n        this.glGeomItemSets.forEach((glGeomItemSet) => {\n            glGeomItemSet.drawHighlighted(renderstate);\n        });\n        if (this.glMaterial)\n            this.glMaterial.unbind(renderstate);\n    }\n    /**\n     * The drawHighlightedGeoms method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    drawGeomData(renderstate) {\n        if (this.glMaterial)\n            this.glMaterial.bind(renderstate, false);\n        this.glGeomItemSets.forEach((glGeomItemSet) => {\n            glGeomItemSet.drawGeomData(renderstate);\n        });\n        if (this.glMaterial)\n            this.glMaterial.unbind(renderstate);\n    }\n}\n\n/** Class representing GL shader materials.\n * @private\n */\nclass GLShaderMaterials extends EventEmitter {\n    gl;\n    pass;\n    glShader;\n    // to force the re-compliation of a shader with different\n    // directives, we supply a different key.\n    glShaderKey = '';\n    glShaderGeomDataKey = '';\n    glShaderHighlightKey = '';\n    glMaterialGeomItemSets = new Map();\n    /**\n     * Create a GL shader material.\n     * @param gl - The WebGL Context value.\n     * @param pass - The pass that owns this GLShaderMaterials object.\n     * @param shaders - The shaders value.\n     */\n    constructor(gl, pass, glShader) {\n        super();\n        this.gl = gl;\n        this.pass = pass;\n        this.glShader = glShader;\n        this.glShaderKey = 'draw';\n        this.glShaderGeomDataKey = 'geomdata';\n        this.glShaderHighlightKey = 'highlight';\n    }\n    getOrCreateGLMaterialGeomItemSets(key) {\n        let glMaterialGeomItemSets = this.glMaterialGeomItemSets.get(key);\n        if (!glMaterialGeomItemSets) {\n            glMaterialGeomItemSets = new GLMaterialGeomItemSets(this.pass, key);\n            this.addMaterialGeomItemSets(key, glMaterialGeomItemSets);\n        }\n        return glMaterialGeomItemSets;\n    }\n    addGLGeomItem(glGeomItem, glGeom, glMaterial) {\n        // Non textured materails do not need to be bound separately as all the\n        // uniform values come from the material texture.\n        if (!glMaterial.material.isTextured()) {\n            const glMaterialGeomItemSets = this.getOrCreateGLMaterialGeomItemSets(null);\n            glMaterialGeomItemSets.addGLGeomItem(glGeomItem, glGeom);\n        }\n        else {\n            const glMaterialGeomItemSets = this.getOrCreateGLMaterialGeomItemSets(glMaterial);\n            glMaterialGeomItemSets.addGLGeomItem(glGeomItem, glGeom);\n        }\n    }\n    addMaterialGeomItemSets(glMaterial, glMaterialGeomItemSets) {\n        this.glMaterialGeomItemSets.set(glMaterial, glMaterialGeomItemSets);\n        const updated = () => {\n            this.emit('updated');\n        };\n        const destructing = () => {\n            glMaterialGeomItemSets.off('updated', updated);\n            glMaterialGeomItemSets.off('destructing', destructing);\n            this.glMaterialGeomItemSets.delete(glMaterial);\n            if (this.glMaterialGeomItemSets.size == 0) {\n                // TODO: clean up the shader...\n                this.emit('destructing');\n            }\n        };\n        glMaterialGeomItemSets.on('updated', updated);\n        glMaterialGeomItemSets.on('destructing', destructing);\n    }\n    /**\n     * The removeMaterialGeomItemSets method.\n     * @param glMaterialGeomItemSets - The glMaterialGeomItemSets value.\n     */\n    removeMaterialGeomItemSets(glMaterial) {\n        this.glMaterialGeomItemSets.delete(glMaterial);\n    }\n    /**\n     * Draws all elements, binding the shader and continuing into the GLMaterialGeomItemSets\n     * @param renderstate - The render state for the current draw traversal\n     */\n    draw(renderstate) {\n        const glShader = this.glShader;\n        if (!this.glShader.bind(renderstate, this.glShaderKey))\n            return;\n        this.pass.renderer.glGeomItemLibrary.bind(renderstate);\n        this.pass.renderer.glMaterialLibrary.bind(renderstate);\n        this.glMaterialGeomItemSets.forEach((glMaterialGeomItemSet) => {\n            glMaterialGeomItemSet.draw(renderstate);\n        });\n        glShader.unbind(renderstate);\n    }\n    /**\n     * The drawHighlightedGeoms method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    drawHighlightedGeoms(renderstate) {\n        if (!this.glShader.bind(renderstate, this.glShaderHighlightKey))\n            return;\n        this.pass.renderer.glGeomItemLibrary.bind(renderstate);\n        this.pass.renderer.glMaterialLibrary.bind(renderstate);\n        this.glMaterialGeomItemSets.forEach((glMaterialGeomItemSet) => {\n            glMaterialGeomItemSet.drawHighlighted(renderstate);\n        });\n        this.glShader.unbind(renderstate);\n    }\n    /**\n     * The drawGeomData method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    drawGeomData(renderstate) {\n        if (!this.glShader.bind(renderstate, this.glShaderGeomDataKey))\n            return;\n        this.pass.renderer.glGeomItemLibrary.bind(renderstate);\n        this.pass.renderer.glMaterialLibrary.bind(renderstate);\n        const gl = this.gl;\n        const { passId } = renderstate.unifs;\n        if (passId) {\n            gl.uniform1i(passId.location, renderstate.passIndex);\n        }\n        this.glMaterialGeomItemSets.forEach((glMaterialGeomItemSet) => {\n            glMaterialGeomItemSet.drawGeomData(renderstate);\n        });\n        this.glShader.unbind(renderstate);\n    }\n}\n\nvar frag$8 = \"\\nprecision highp float;\\nprecision highp int;\\n#define GLSLIFY 1\\n\\nimport 'imageAtlas.glsl'\\n\\nuniform sampler2D atlasBillboards;\\n\\n/* VS Outputs */\\nvarying float v_instanceID;\\nvarying vec2 v_texCoord;\\nvarying vec4 v_layoutData;\\nvarying float v_alpha;\\nvarying vec4 v_tint;\\nvarying vec3 v_viewPos;\\nvarying float v_frontFacing;\\n\\nuniform sampler2D instancesTexture;\\nuniform int instancesTextureSize;\\n\\n#if defined(DRAW_GEOMDATA)\\n  uniform int isOrthographic;\\n  import 'surfaceGeomData.glsl'\\n#endif // DRAW_GEOMDATA\\n\\nconst int cols_per_instance = 7;\\n\\nvec4 getHilightColor(int id) {\\n  return fetchTexel(instancesTexture, instancesTextureSize, (id * cols_per_instance) + 6);\\n}\\n\\n#ifdef ENABLE_ES3\\n  out vec4 fragColor;\\n#endif\\nvoid main(void) {\\n#ifndef ENABLE_ES3\\n  vec4 fragColor;\\n#endif\\n\\n  int instanceID = int(v_instanceID);\\n\\n  vec2 texCoord = v_texCoord;\\n\\n  bool frontFacing = bool(v_frontFacing);\\n  if (frontFacing && !gl_FrontFacing) {\\n    texCoord.x = 1.0 - texCoord.x;\\n  }\\n  texCoord *= v_layoutData.zw;\\n  texCoord += v_layoutData.xy;\\n\\n  vec4 imageColor = texture2D(atlasBillboards, texCoord) * v_tint;\\n  imageColor.a *= v_alpha;\\n  if(imageColor.a < 0.1)\\n    discard;\\n\\n#if defined(DRAW_COLOR)\\n  fragColor = imageColor;\\n  // fragColor.r = 1.0;\\n  // fragColor.a = 1.0;\\n#elif defined(DRAW_GEOMDATA)\\n  fragColor = setFragColor_geomData(v_viewPos, v_instanceID, 0.0, isOrthographic, 0, TRIANGLES);\\n#elif defined(DRAW_HIGHLIGHT)\\n  fragColor = getHilightColor(instanceID);\\n  // Skip unhilighting labels.\\n  if(fragColor.r < 0.001 && fragColor.g < 0.001 && fragColor.b < 0.001)\\n    discard;\\n#endif // DRAW_HIGHLIGHT\\n  \\n#ifndef ENABLE_ES3\\n  gl_FragColor = fragColor;\\n#endif\\n}\\n\"; // eslint-disable-line\n\nvar vert$9 = \"\\nprecision highp float;\\nprecision highp int;\\n#define GLSLIFY 1\\n\\nimport 'quadVertexFromID.glsl'\\n\\nuniform mat4 viewMatrix;\\nuniform mat4 projectionMatrix;\\nuniform mat4 cameraMatrix;\\nuniform int isOrthographic;\\nuniform vec4 viewportFrustum;\\n\\nimport 'GLSLUtils.glsl'\\n\\n#ifdef ENABLE_FLOAT_TEXTURES\\n\\n// A sorted attribute of instance Ids so we draw from back to front.\\ninstancedattribute float instanceIds;\\n\\nimport 'transpose.glsl'\\nimport 'imageAtlas.glsl'\\n\\nuniform sampler2D atlasBillboards_layout;\\nuniform vec4 atlasBillboards_desc;\\n\\nuniform sampler2D instancesTexture;\\nuniform int instancesTextureSize;\\n\\nconst int cols_per_instance = 7;\\n\\nconst int ALIGN_TO_CAMERA_FLAG = 1 << 2;\\nconst int ALIGN_TO_CAMERA_AND_AXIS_FLAG = 1 << 3;\\nconst int DRAW_ON_TOP_FLAG = 1 << 4;\\nconst int FIXED_SIZE_ON_SCREEN_FLAG = 1 << 5;\\nconst int FRONT_FACING_FLAG = 1 << 6;\\n\\nmat4 getMatrix(sampler2D texture, int textureSize, int index) {\\n  // Unpack 3 x 4 matix columns into a 4 x 4 matrix.\\n  vec4 col0 = fetchTexel(texture, textureSize, (index * cols_per_instance) + 0);\\n  vec4 col1 = fetchTexel(texture, textureSize, (index * cols_per_instance) + 1);\\n  vec4 col2 = fetchTexel(texture, textureSize, (index * cols_per_instance) + 2);\\n  mat4 result = mat4(col0, col1, col2, vec4(0.0, 0.0, 0.0, 1.0));\\n  return transpose(result);\\n  // return mat4(1.0);\\n}\\n\\nmat4 getModelMatrix(int id) {\\n  return getMatrix(instancesTexture, instancesTextureSize, id);\\n}\\nvec4 getInstanceData(int id) {\\n  return fetchTexel(instancesTexture, instancesTextureSize, (id * cols_per_instance) + 3);\\n}\\nvec4 getPivot(int id) {\\n  return fetchTexel(instancesTexture, instancesTextureSize, (id * cols_per_instance) + 4);\\n}\\nvec4 getTintColor(int id) {\\n  return fetchTexel(instancesTexture, instancesTextureSize, (id * cols_per_instance) + 5);\\n}\\n\\n#else\\n\\nuniform vec4 atlasBillboards_desc;\\n\\nuniform mat4 modelMatrix;\\nuniform vec2 pivot;\\nuniform vec4 billboardData;\\nuniform vec4 tintColor;\\nuniform vec4 layoutData;\\n\\n#endif\\n\\nuniform int inVR;\\n\\nmat4 calcAlignToCameraMatrix(mat4 modelMatrix, mat4 cameraMatrix) {\\n  vec3 cameraY = vec3(cameraMatrix[1][0], cameraMatrix[1][1], cameraMatrix[1][2]);\\n  vec3 cameraZ = vec3(cameraMatrix[2][0], cameraMatrix[2][1], cameraMatrix[2][2]);\\n\\n  vec3 modelOrigin = vec3(modelMatrix[3][0], modelMatrix[3][1], modelMatrix[3][2]);\\n\\n  vec3 zAxis = normalize(cameraZ);\\n  vec3 xAxis = normalize(cross(cameraY, zAxis));\\n  vec3 yAxis = normalize(cross(zAxis, xAxis));\\n\\n  return mat4(vec4(xAxis, 0.0), vec4(yAxis, 0.0), vec4(zAxis, 0.0), vec4(modelOrigin, 1.0));\\n}\\n  \\n\\nmat4 calcAlignToCameraAndXAxisMatrix(mat4 modelMatrix, mat4 cameraMatrix) {\\n  vec3 cameraPos = vec3(cameraMatrix[3][0], cameraMatrix[3][1], cameraMatrix[3][2]);\\n  vec3 cameraY = vec3(cameraMatrix[1][0], cameraMatrix[1][1], cameraMatrix[1][2]);\\n  vec3 cameraZ = vec3(cameraMatrix[2][0], cameraMatrix[2][1], cameraMatrix[2][2]);\\n\\n  vec3 modelOrigin = vec3(modelMatrix[3][0], modelMatrix[3][1], modelMatrix[3][2]);\\n  vec3 modelXAxis = normalize(vec3(modelMatrix[0][0], modelMatrix[0][1], modelMatrix[0][2]));\\n  vec3 modelToCamera = normalize(cameraPos - modelOrigin);\\n\\n  vec3 zAxis;\\n  if (isOrthographic > 0) {\\n    zAxis = normalize(cameraZ);\\n  } else {\\n    zAxis = normalize(modelToCamera);\\n  }\\n  vec3 yAxis = normalize(cross(zAxis, modelXAxis));\\n  vec3 xAxis = normalize(cross(zAxis, yAxis));\\n\\n  if (dot(cameraY, yAxis) < 0.0) {\\n    yAxis = -yAxis;\\n  }\\n\\n  return mat4(vec4(xAxis, 0.0), vec4(yAxis, 0.0), vec4(zAxis, 0.0), vec4(modelOrigin, 1.0));\\n}\\n\\nfloat map(float value, float inMin, float inMax, float outMin, float outMax) {\\n  return outMin + (outMax - outMin) * (value - inMin) / (inMax - inMin);\\n}\\n\\n/* VS Outputs */\\nvarying float v_instanceID;\\nvarying vec2 v_texCoord;\\nvarying vec4 v_layoutData;\\nvarying float v_alpha;\\nvarying vec4 v_tint;\\nvarying vec3 v_viewPos;\\nvarying float v_frontFacing;\\n\\nvoid main(void) {\\n\\n#ifdef ENABLE_FLOAT_TEXTURES\\n\\n  int instanceID = int(instanceIds);\\n  v_instanceID = float(instanceID) + 0.25;\\n\\n  mat4 modelMatrix = getModelMatrix(instanceID);\\n  vec2 pivot = getPivot(instanceID).xy;\\n  vec4 billboardData = getInstanceData(instanceID);\\n  vec4 layoutData = fetchTexel(atlasBillboards_layout, int(atlasBillboards_desc.z), int(billboardData.z));\\n  v_tint = getTintColor(instanceID);\\n\\n#else\\n\\n  v_tint = tintColor;\\n\\n#endif\\n\\n  vec2 quadVertex = getQuadVertexPositionFromID();\\n  \\n  vec2 pos = quadVertex + vec2(0.5, 0.0) - pivot;\\n\\n  v_layoutData = layoutData;\\n  v_texCoord = vec2(quadVertex.x, -quadVertex.y) + 0.5;\\n  v_alpha = billboardData.w;\\n\\n  float scl = billboardData.x;\\n  float width = layoutData.z * atlasBillboards_desc.x * scl;\\n  float height = layoutData.w * atlasBillboards_desc.y * scl;\\n  int flags = int(billboardData.y);\\n\\n  // Use cross platform bit flags methods\\n  bool alignedToCamera = testFlag(flags, ALIGN_TO_CAMERA_FLAG);\\n  bool alignedToCameraAndXAxis = testFlag(flags, ALIGN_TO_CAMERA_AND_AXIS_FLAG);\\n  bool drawOnTop = testFlag(flags, DRAW_ON_TOP_FLAG);\\n  bool fixedSizeOnscreen = testFlag(flags, FIXED_SIZE_ON_SCREEN_FLAG);\\n  bool frontFacing = testFlag(flags, FRONT_FACING_FLAG);\\n\\n  v_frontFacing = float(frontFacing);\\n\\n  mat4 modelViewMatrix = viewMatrix * modelMatrix;\\n\\n  // Note: items in front of the camera will have a negative value here.\\n  float sc = 1.0;\\n  if (fixedSizeOnscreen) {\\n    if (isOrthographic > 0){\\n      // At a distance of 1, we should match the orthographic and perspective sizes.\\n      // Calculate the size of the handle in perpective projection at 1 meter.\\n      // With a 24mm camera, the Fov is 46.4 degrees, or 0.8098327729253689 radians.\\n      // (0.81 / 2.0) * focalDist * 2.0\\n      // The frustum height at 1m is 0.81.\\n      sc = viewportFrustum.y / 0.8098327;\\n    } else {\\n      sc = -modelViewMatrix[3][2];\\n      \\n      if (inVR == 1) {\\n        // During XR sessions, there is a scaling applied to the view matrix\\n        // which causes a distortion to the line width. We extract that scale here\\n        // and use to correct the distortion.\\n        // See also: FatPointsShader\\n        vec3 viewZ = modelViewMatrix[2].xyz;\\n        float viewScale = length(viewZ);\\n        sc /= viewScale;\\n      }\\n    }\\n  }\\n  \\n  float aspect = viewportFrustum.x / viewportFrustum.y;\\n  if (alignedToCamera || alignedToCameraAndXAxis) {\\n    if (alignedToCamera) {\\n      mat4 lookAt = calcAlignToCameraMatrix(modelMatrix, cameraMatrix);\\n      modelViewMatrix = viewMatrix * lookAt;\\n    }\\n    else if (alignedToCameraAndXAxis) {\\n      // Align the billboard to the camera, while preserving the X axis in the modelMatrix;\\n      mat4 lookAt = calcAlignToCameraAndXAxisMatrix(modelMatrix, cameraMatrix);\\n      modelViewMatrix = viewMatrix * lookAt;\\n    }\\n  }\\n  v_viewPos =  (modelViewMatrix * vec4(pos.x * width * sc, (pos.y + 0.5) * height * sc, 0.0, 1.0)).xyz;\\n  gl_Position = projectionMatrix * vec4(v_viewPos, 1.0);\\n  \\n\\n  // Use cross platform bit flags methods\\n  if (drawOnTop) {\\n    if (isOrthographic > 0){\\n      gl_Position.z = mix(gl_Position.z, -1.0, 0.5);\\n    } else {\\n      gl_Position.z = mix(gl_Position.z, -gl_Position.z, 0.5);\\n    }\\n  }\\n}\\n\"; // eslint-disable-line\n\n/* eslint-disable require-jsdoc */\nclass BillboardShader extends GLShader {\n    /**\n     * Create a GL shader.\n     * @param gl - The webgl rendering context.\n     */\n    constructor(gl) {\n        super(gl, 'BillboardShader');\n        this.setShaderStage('VERTEX_SHADER', vert$9);\n        this.setShaderStage('FRAGMENT_SHADER', frag$8);\n    }\n}\n\nvar vert$8 = \"\\nprecision highp float;\\n#define GLSLIFY 1\\n\\nattribute vec3 positions;    //(location = 0)\\n\\nuniform mat4 viewMatrix;\\nuniform mat4 projectionMatrix;\\nuniform vec3 projectionCenter;\\n\\nimport 'transpose.glsl'\\nimport 'GLSLUtils.glsl'\\nimport 'stack-gl/transpose.glsl'\\nimport 'stack-gl/inverse.glsl'\\nimport 'geomItemId.glsl'\\nimport 'drawItemTexture.glsl'\\nimport 'modelMatrix.glsl'\\n\\n/* VS Outputs */\\nvarying vec3 v_worldDir;\\n \\nvoid main()\\n{\\n  int geomItemId = getGeomItemId();\\n  vec4 pos = vec4(positions, 1.);\\n  mat4 modelMatrix = getModelMatrix(geomItemId);\\n  mat4 modelViewProjectionMatrix = projectionMatrix * viewMatrix * modelMatrix;\\n\\n  gl_Position = modelViewProjectionMatrix * pos;\\n\\n  vec4 worldPos = modelMatrix * pos;\\n  v_worldDir = worldPos.xyz - projectionCenter;\\n}\\n\\n\"; // eslint-disable-line\n\nvar OctahedralEnvProjectionFrag = \"\\nprecision highp float;\\n#define GLSLIFY 1\\n\\nimport 'GLSLUtils.glsl'\\nimport 'envmap-octahedral.glsl'\\nimport 'gamma.glsl'\\nimport 'materialparams.glsl'\\n\\nuniform sampler2D envMap;\\nuniform int envMapLoaded;\\n\\n#ifdef ENABLE_INLINE_GAMMACORRECTION\\nuniform float exposure;\\n#endif\\n\\nvec4 sampleEnvMap(vec3 dir) {\\n  vec2 uv = dirToSphOctUv(dir);\\n  vec4 texel = texture2D(envMap, vec2(uv.x, 1.0 - uv.y));\\n  return vec4(texel.rgb/texel.a, 1.0); // TODO: Check this line. Do we need it?\\n}\\n\\n/* VS Outputs */\\nvarying vec3 v_worldDir;\\n\\n#ifdef ENABLE_ES3\\n  out vec4 fragColor;\\n#endif\\nvoid main(void) {\\n#ifndef ENABLE_ES3\\n  vec4 fragColor;\\n#endif\\n\\n  if (envMapLoaded == 0)  {\\n    discard;\\n    return;\\n  }\\n\\n  fragColor = sampleEnvMap(normalize(v_worldDir));\\n\\n#ifdef ENABLE_INLINE_GAMMACORRECTION\\n  fragColor.rgb = toGamma(fragColor.rgb * exposure);\\n#endif\\n\\n#ifndef ENABLE_ES3\\n  gl_FragColor = fragColor;\\n#endif\\n}\\n\"; // eslint-disable-line\n\nclass EnvProjectionShader extends GLShader {\n    /**\n     * Create a GL shader.\n     * @param gl - The webgl rendering context.\n     */\n    constructor(gl) {\n        super(gl, 'EnvProjectionShader');\n        this.setShaderStage('VERTEX_SHADER', vert$8);\n        this.setShaderStage('FRAGMENT_SHADER', OctahedralEnvProjectionFrag);\n    }\n    /**\n     * The bind method.\n     * @param renderstate - The object tracking the current state of the renderer\n     * @param key - The key value.\n     * @return - The return value.\n     */\n    bind(renderstate, key) {\n        super.bind(renderstate, key);\n        if (renderstate instanceof ColorRenderState) {\n            const colorRenderState = renderstate;\n            const gl = this.__gl;\n            const { envMap, envMapLoaded, exposure } = renderstate.unifs;\n            if (colorRenderState.envMap && colorRenderState.envMap.glTex) {\n                // colorRenderState.envMap.bind(colorRenderState)\n                colorRenderState.envMap.glTex.bindToUniform(renderstate, envMap);\n                gl.uniform1i(envMapLoaded.location, 1);\n            }\n            else {\n                gl.uniform1i(envMapLoaded.location, 0);\n            }\n            if (exposure) {\n                gl.uniform1f(exposure.location, colorRenderState.exposure);\n            }\n        }\n        return true;\n    }\n    /**\n     * The supportsInstancing method.\n     * @return - return false for shaders that cannot be rendered in instanced mode.\n     */\n    static supportsInstancing() {\n        return false;\n    }\n    /**\n     * Each shader provides a template material that each material instance is\n     * based on. The shader specifies the parameters needed by the shader, and\n     * the material provides values to the shader during rendering.\n     * @return - The template material value.\n     */\n    static getMaterialTemplate() {\n        return material$9;\n    }\n}\nconst material$9 = new EnvProjectionMaterial();\nRegistry.register('EnvProjectionShader', EnvProjectionShader);\n\nvar frag$7 = \"\\nprecision highp float;\\n#define GLSLIFY 1\\n\\nuniform color BaseColor;\\nuniform float Opacity;\\nuniform mat4 cameraMatrix;\\n\\n#ifdef ENABLE_ES3\\n  out vec4 fragColor;\\n#endif\\n\\n/* VS Outputs */\\nvarying vec3 v_viewPos;\\nvarying vec3 v_viewNormal;\\nvarying vec2 v_texCoord;\\nvarying float v_geomItemId;\\nvarying vec4 v_geomItemData;\\nvarying float v_drawItemID;\\nvarying vec3 v_worldPos;\\n\\nimport 'GLSLUtils.glsl'\\nimport 'drawItemTexture.glsl'\\nimport 'cutaways.glsl'\\nimport 'geometryMask.glsl'\\nimport 'GLSLBits.glsl'\\nimport 'geomItemFlags.glsl'\\n\\nuniform int passId;\\n\\n#if defined(DRAW_HIGHLIGHT)\\n  import 'surfaceHighlight.glsl'\\n#endif\\n\\nvoid main(void) {\\n#ifndef ENABLE_ES3\\n  vec4 fragColor;\\n#endif\\n  int geomItemId = int(round(v_geomItemId));\\n  int flags = int(round(v_geomItemData.x));\\n  float treeItemOpacity = v_geomItemData.y;\\n\\n  // Cutaways\\n  if (testFlag(flags, GEOMITEM_FLAG_CUTAWAY)) {\\n    vec4 cutAwayData  = getCutaway(geomItemId);\\n    vec3 planeNormal = cutAwayData.xyz;\\n    float planeDist = cutAwayData.w;\\n    if (length(planeNormal) > 0.5) {\\n      if (cutaway(v_worldPos, planeNormal, planeDist)) {\\n          discard;\\n          return;\\n      }\\n    } else {\\n      if (testGeometryMask(v_viewPos)) {\\n        discard;\\n        return;\\n      }\\n    }\\n  }\\n\\n#if defined(DRAW_COLOR)\\n  int debugLevel = 0;\\n  if (debugLevel == 0) {\\n\\n    vec3 viewVector = mat3(cameraMatrix) * normalize(-v_viewPos);\\n    vec3 normal = mat3(cameraMatrix) * v_viewNormal;\\n    float NdotV = dot(normalize(normal), normalize(viewVector));\\n\\n    // Modulate the lighting using the texture coord so the line looks round.\\n    NdotV *= cos((v_texCoord.x - 0.5) * 2.0);\\n\\n    vec4 color = BaseColor * NdotV;\\n    fragColor = vec4(color.rgb, BaseColor.a * Opacity * treeItemOpacity);\\n  }\\n  else {\\n    fragColor = vec4(v_texCoord.x, 0.0, 0.0, 1.0);\\n  }\\n#elif defined(DRAW_GEOMDATA)\\n\\n  if (testFlag(flags, GEOMITEM_INVISIBLE_IN_GEOMDATA)) {\\n    discard;\\n    return;\\n  }\\n\\n  float dist = length(v_viewPos);\\n  fragColor.r = float(passId); \\n  fragColor.g = float(v_drawItemID);\\n  fragColor.b = 0.0;// TODO: store poly-id or something.\\n  fragColor.a = dist;\\n    \\n#elif defined(DRAW_HIGHLIGHT)\\n  fragColor = setFragColor_highlight(v_geomItemId);\\n#endif\\n\\n#ifndef ENABLE_ES3\\n  gl_FragColor = fragColor;\\n#endif\\n}\\n\"; // eslint-disable-line\n\nvar vert$7 = \"\\nprecision highp float;\\n#define GLSLIFY 1\\n\\ninstancedattribute vec2 segmentIndices;\\nattribute float vertexIDs;\\n\\nuniform mat4 viewMatrix;\\nuniform mat4 projectionMatrix;\\nuniform int isOrthographic;\\n\\nimport 'drawItemTexture.glsl'\\nimport 'modelMatrix.glsl'\\n\\nuniform int geomItemId;\\nint getGeomItemId() {\\n  return geomItemId;\\n}\\n\\nuniform sampler2D positionsTexture;\\nuniform int positionsTextureSize;\\n\\nuniform float LineThickness;\\nuniform float Overlay;\\n\\nimport 'calcFatLinesViewPos.glsl'\\n\\nvarying vec3 v_viewPos;\\nvarying vec3 v_viewNormal;\\nvarying vec2 v_texCoord;\\n\\nvarying float v_geomItemId;\\nvarying vec4 v_geomItemData;\\nvarying float v_drawItemID;\\nvarying vec3 v_worldPos;\\n\\nvoid main(void) {\\n\\n  int geomItemId = getGeomItemId();\\n  v_geomItemId = float(geomItemId);\\n  v_geomItemData = getInstanceData(geomItemId);\\n\\n  int vertexID = int(vertexIDs);\\n\\n  mat4 modelMatrix = getModelMatrix(geomItemId);\\n  mat4 modelViewMatrix = viewMatrix * modelMatrix;\\n\\n  vec3 pos;\\n  v_viewPos       = calcFatLinesViewPos(vertexID, modelViewMatrix, v_viewNormal, v_texCoord, pos);\\n  v_worldPos      = (modelMatrix * vec4(pos, 1.0)).xyz;\\n  v_drawItemID    = float(getGeomItemId());\\n\\n  gl_Position     = projectionMatrix * vec4(v_viewPos, 1.0);\\n\\n  if (isOrthographic > 0){\\n    gl_Position.z -= mix(gl_Position.z, -1.0, Overlay);\\n  } else {\\n    gl_Position.z = mix(gl_Position.z, -gl_Position.z, Overlay);\\n  }\\n\\n}\\n\"; // eslint-disable-line\n\n/* eslint-disable require-jsdoc */\n/** Shader for drawing Fat lines\n * @extends GLShader\n * @private\n */\nclass FatLinesShader extends GLShader {\n    /**\n     * Create a GL shader.\n     * @param gl - The webgl rendering context.\n     */\n    constructor(gl) {\n        super(gl, 'FatLinesShader');\n        this.setShaderStage('VERTEX_SHADER', vert$7);\n        this.setShaderStage('FRAGMENT_SHADER', frag$7);\n    }\n    bind(renderstate, key) {\n        if (super.bind(renderstate, key)) {\n            renderstate.supportsInstancing = false;\n            return true;\n        }\n        return false;\n    }\n    /**\n     * The supportsInstancing method.\n     * @return - return false for shaders that cannot be rendered in instanced mode.\n     */\n    static supportsInstancing() {\n        return false;\n    }\n    /**\n     * Each shader provides a template material that each material instance is\n     * based on. The shader specifies the parameters needed by the shader, and\n     * the material provides values to the shader during rendering.\n     * @return - The template material value.\n     */\n    static getMaterialTemplate() {\n        return material$8;\n    }\n}\nconst material$8 = new FatLinesMaterial('FatLinesShader_template');\nRegistry.register('FatLinesShader', FatLinesShader);\n\nvar vert$6 = \"\\nprecision highp float;\\nprecision highp int;\\n#define GLSLIFY 1\\n\\nattribute vec3 positions;\\n#ifdef ENABLE_TEXTURES\\nattribute vec2 texCoords;\\n#endif\\n\\nuniform mat4 viewMatrix;\\nuniform mat4 projectionMatrix;\\nuniform int isOrthographic;\\n\\nimport 'GLSLUtils.glsl'\\nimport 'geomItemId.glsl'\\nimport 'drawItemTexture.glsl'\\nimport 'modelMatrix.glsl'\\nimport 'geomItemFlags.glsl'\\nimport 'materialparams.glsl'\\n\\n/* VS Outputs */\\nvarying vec4 v_drawItemIds;\\nvarying vec4 v_geomItemData;\\nvarying vec3 v_viewPos;\\n#ifdef ENABLE_TEXTURES\\nvarying vec2 v_textureCoord;\\n#endif\\nvarying vec3 v_worldPos;\\n\\nvoid main(void) {\\n  v_drawItemIds = getDrawItemIds();\\n  int geomItemId = int(round(v_drawItemIds.x));\\n  v_geomItemData  = getInstanceData(geomItemId);\\n\\n  mat4 modelMatrix = getModelMatrix(geomItemId);\\n  mat4 modelViewMatrix = viewMatrix * modelMatrix;\\n\\n  vec4 pos = vec4(positions, 1.);\\n  vec4 viewPos = (modelViewMatrix * pos);\\n  gl_Position = projectionMatrix * viewPos;\\n\\n  v_viewPos = viewPos.xyz;\\n#ifdef ENABLE_TEXTURES\\n  v_textureCoord = texCoords;\\n  v_textureCoord.y = 1.0 - v_textureCoord.y;// Flip y\\n#endif\\n\\n  //////////////////////////////////////////////\\n  // Overlay\\n  vec2 materialCoords = v_geomItemData.zw;\\n  vec4 materialValue1 = getMaterialValue(materialCoords, 2);\\n  float overlay = materialValue1.x;\\n\\n  if (isOrthographic > 0){\\n    gl_Position.z -= overlay;\\n  } else {\\n    gl_Position.z = mix(gl_Position.z, -gl_Position.z, overlay);\\n  }\\n\\n  //////////////////////////////////////////////\\n  \\n  v_worldPos      = (modelMatrix * pos).xyz;\\n}\\n\"; // eslint-disable-line\n\nvar frag$6 = \"\\nprecision highp float;\\nprecision highp int;\\n#define GLSLIFY 1\\n\\nimport 'GLSLUtils.glsl'\\nimport 'drawItemTexture.glsl'\\nimport 'cutaways.glsl'\\nimport 'geometryMask.glsl'\\nimport 'gamma.glsl'\\nimport 'materialparams.glsl'\\nimport 'geomItemFlags.glsl'\\n\\n#ifdef DEBUG_GEOM_ID\\nimport 'debugColors.glsl'\\n#endif\\n\\n#ifdef ENABLE_TEXTURES\\nuniform sampler2D BaseColorTex;\\nuniform int BaseColorTexType;\\n#endif\\n\\n/* VS Outputs */\\nvarying vec4 v_drawItemIds;\\nvarying vec4 v_geomItemData;\\nvarying vec3 v_viewPos;\\n#ifdef ENABLE_TEXTURES\\nvarying vec2 v_textureCoord;\\n#endif\\nvarying vec3 v_worldPos;\\n\\n#ifdef ENABLE_ES3\\nout vec4 fragColor;\\n#endif\\n\\n#if defined(DRAW_GEOMDATA)\\n  uniform int isOrthographic;\\n  import 'surfaceGeomData.glsl'\\n#elif defined(DRAW_HIGHLIGHT)\\n  import 'surfaceHighlight.glsl'\\n#endif // DRAW_HIGHLIGHT\\n\\nvoid main(void) {\\n#ifndef ENABLE_ES3\\n  vec4 fragColor;\\n#endif\\n\\n  int geomItemId = int(round(v_drawItemIds.x));\\n  int flags = int(round(v_geomItemData.x));\\n  float treeItemOpacity = v_geomItemData.y;\\n\\n  // We can make geoms invisible to hide them. \\n  // Avoid drawing GeomData for geoms that are completely transparent.\\n  if (treeItemOpacity < 0.001) {\\n    discard;\\n    return;\\n  }\\n  \\n  // Cutaways\\n  if (testFlag(flags, GEOMITEM_FLAG_CUTAWAY)) \\n  {\\n    vec4 cutAwayData   = getCutaway(geomItemId);\\n    vec3 planeNormal = cutAwayData.xyz;\\n    float planeDist = cutAwayData.w;\\n    if (length(planeNormal) > 0.5) {\\n      if (cutaway(v_worldPos, planeNormal, planeDist)) {\\n          discard;\\n          return;\\n      }\\n    } else {\\n      if (testGeometryMask(v_viewPos)) {\\n        discard;\\n        return;\\n      }\\n    }\\n  }\\n\\n  //////////////////////////////////////////////\\n  // Material\\n\\n  vec2 materialCoords = v_geomItemData.zw;\\n  if (v_drawItemIds.z > 0.5) {\\n    materialCoords.x = v_drawItemIds.z;\\n  }\\n  vec4 baseColor = getMaterialValue(materialCoords, 1);\\n\\n#ifdef ENABLE_TEXTURES\\n  getTextureColorValue(baseColor, BaseColorTex, BaseColorTexType, v_textureCoord);\\n#endif // ENABLE_TEXTURES\\n\\n  baseColor.a *= treeItemOpacity;\\n\\n#if defined(DRAW_COLOR)\\n\\n  //////////////////////////////////////////////\\n  fragColor = baseColor;\\n\\n#ifdef DEBUG_GEOM_ID\\n  // ///////////////////////\\n  // Debug Draw ID (this correlates to GeomID within a GLGeomSet)\\n  float geomId = v_geomItemData.w;\\n  fragColor.rgb = getDebugColor(geomId);\\n  // ///////////////////////\\n#endif\\n\\n#ifdef ENABLE_INLINE_GAMMACORRECTION\\n  fragColor.rgb = toGamma(fragColor.rgb);\\n#endif\\n\\n#elif defined(DRAW_GEOMDATA)\\n\\n  fragColor = setFragColor_geomData(v_viewPos, v_drawItemIds.x, v_drawItemIds.y, isOrthographic, flags, TRIANGLES);\\n#elif defined(DRAW_HIGHLIGHT)\\n  fragColor = setFragColor_highlight(v_drawItemIds.x);\\n#endif // DRAW_HIGHLIGHT\\n\\n#ifndef ENABLE_ES3\\n  gl_FragColor = fragColor;\\n#endif\\n}\\n\"; // eslint-disable-line\n\nclass FlatSurfaceShader extends GLShader {\n    /**\n     * Create a GL shader.\n     * @param gl - The webgl rendering context.\n     */\n    constructor(gl) {\n        super(gl, 'FlatSurfaceShader');\n        this.setShaderStage('VERTEX_SHADER', vert$6);\n        this.setShaderStage('FRAGMENT_SHADER', frag$6);\n    }\n    /**\n     * The bind method.\n     * @param renderstate - The object tracking the current state of the renderer\n     * @param key - The key value.\n     * @return - The return value.\n     */\n    bind(renderstate, key) {\n        super.bind(renderstate, key);\n        renderstate.pushGLStack('FlatSurfaceShader.bind');\n        // Note: The GLTransparentGeoms pass only  renders the font faces of objects because for complex geoms, this makes sense\n        // but flat surfaces should be double sided, as they are almost always labels, or UI elements.\n        const gl = this.__gl;\n        renderstate.glDisable(gl.CULL_FACE);\n        return true;\n    }\n    /**\n     * The unbind method.\n     * @param renderstate - The object tracking the current state of the renderer\n     * @return - The return value.\n     */\n    unbind(renderstate) {\n        super.unbind(renderstate);\n        renderstate.popGLStack();\n        return true;\n    }\n    /**\n     * The getPackedMaterialData method.\n     * @param material - The material param.\n     * @return - The return value.\n     */\n    static getPackedMaterialData(material) {\n        const matData = new Float32Array(12);\n        let pixId = 0;\n        matData[pixId * 4 + 0] = 2;\n        const baseColorParam = material.getParameter('BaseColor');\n        let baseColor;\n        if (baseColorParam instanceof MaterialColorParam && baseColorParam.colorSpace == ColorSpace.Gamma) {\n            baseColor = baseColorParam.value.toLinear();\n        }\n        else {\n            baseColor = baseColorParam.value;\n        }\n        pixId++;\n        matData[pixId * 4 + 0] = baseColor.r;\n        matData[pixId * 4 + 1] = baseColor.g;\n        matData[pixId * 4 + 2] = baseColor.b;\n        matData[pixId * 4 + 3] = baseColor.a;\n        pixId++;\n        const overlayParam = material.getParameter('Overlay');\n        if (overlayParam)\n            matData[pixId * 4 + 0] = overlayParam.getValue();\n        return matData;\n    }\n    /**\n     * Each shader provides a template material that each material instance is\n     * based on. The shader specifies the parameters needed by the shader, and\n     * the material provides values to the shader during rendering.\n     * @return - The template material value.\n     */\n    static getMaterialTemplate() {\n        return material$7;\n    }\n}\nconst material$7 = new FlatSurfaceMaterial('FlatSurfaceShader_template');\nRegistry.register('FlatSurfaceShader', FlatSurfaceShader);\n\nvar vert$5 = \"\\nprecision highp float;\\nprecision highp int;\\n#define GLSLIFY 1\\n\\nattribute vec3 positions;\\n\\nimport 'GLSLUtils.glsl'\\nimport 'geomItemId.glsl'\\nimport 'drawItemTexture.glsl'\\nimport 'modelMatrix.glsl'\\nimport 'materialparams.glsl'\\n\\nuniform mat4 viewMatrix;\\nuniform mat4 projectionMatrix;\\nuniform int isOrthographic;\\n\\n/* VS Outputs */\\nvarying float v_geomItemId;\\nvarying vec4 v_geomItemData;\\nvarying vec3 v_viewPos;\\nvarying vec3 v_worldPos;\\n\\nvoid main(void) {\\n  int geomItemId = getGeomItemId();\\n  v_geomItemId = float(geomItemId);\\n  v_geomItemData  = getInstanceData(geomItemId);\\n\\n  mat4 modelMatrix = getModelMatrix(geomItemId);\\n  mat4 modelViewMatrix = viewMatrix * modelMatrix;\\n  vec4 viewPos = modelViewMatrix * vec4(positions, 1.0);\\n\\n  v_viewPos = viewPos.xyz;\\n  gl_Position = projectionMatrix * viewPos;\\n\\n  //////////////////////////////////////////////\\n  // Overlay\\n  vec2 materialCoords = v_geomItemData.zw;\\n  vec4 materialValue1 = getMaterialValue(materialCoords, 2);\\n  float overlay = materialValue1.y;\\n   \\n#if defined(DRAW_GEOMDATA)\\n  float _overlay = mix(overlay, 1.0, 0.0001);\\n#else\\n  float _overlay = overlay;\\n#endif\\n\\n  if (isOrthographic > 0){\\n    gl_Position.z -= _overlay;\\n  } else {\\n    gl_Position.z = mix(gl_Position.z, -gl_Position.z, _overlay);\\n  }\\n  \\n  vec4 pos = vec4(positions, 1.);\\n  v_worldPos      = (modelMatrix * pos).xyz;\\n}\\n\"; // eslint-disable-line\n\nvar frag$5 = \"\\nprecision highp float;\\nprecision highp int;\\n#define GLSLIFY 1\\n\\nimport 'GLSLUtils.glsl'\\nimport 'drawItemTexture.glsl'\\nimport 'cutaways.glsl'\\nimport 'geometryMask.glsl'\\nimport 'materialparams.glsl'\\nimport 'geomItemFlags.glsl'\\n\\n#if defined(DRAW_COLOR)\\n\\nuniform int occluded;\\nuniform vec4 hiddenLineColor;\\n\\n#elif defined(DRAW_GEOMDATA)\\n\\nuniform int isOrthographic;\\nimport 'surfaceGeomData.glsl'\\n\\n#elif defined(DRAW_HIGHLIGHT)\\n\\n#ifdef ENABLE_FLOAT_TEXTURES\\nvec4 getHighlightColor(int id) {\\n  return fetchTexel(instancesTexture, instancesTextureSize, (id * pixelsPerItem) + 4);\\n}\\n#else // ENABLE_FLOAT_TEXTURES\\n\\nuniform vec4 highlightColor;\\n\\nvec4 getHighlightColor() {\\n  return highlightColor;\\n}\\n\\n#endif // ENABLE_FLOAT_TEXTURES\\n\\n#endif // DRAW_HIGHLIGHT\\n\\n/* VS Outputs */\\nvarying float v_geomItemId;\\nvarying vec4 v_geomItemData;\\nvarying vec3 v_viewPos;\\nvarying vec3 v_worldPos;\\n\\n#ifdef ENABLE_ES3\\n  out vec4 fragColor;\\n#endif\\n\\nvoid main(void) {\\n#ifndef ENABLE_ES3\\n  vec4 fragColor;\\n#endif\\n\\n  int geomItemId = int(round(v_geomItemId));\\n  int flags = int(round(v_geomItemData.x));\\n  float treeItemOpacity = v_geomItemData.y;\\n\\n  // Cutaways\\n  if (testFlag(flags, GEOMITEM_FLAG_CUTAWAY)) \\n  {\\n    vec4 cutAwayData   = getCutaway(geomItemId);\\n    vec3 planeNormal = cutAwayData.xyz;\\n    float planeDist = cutAwayData.w;\\n    if (length(planeNormal) > 0.5) {\\n      if (cutaway(v_worldPos, planeNormal, planeDist)) {\\n          discard;\\n          return;\\n      }\\n    } else {\\n      if (testGeometryMask(v_viewPos)) {\\n        discard;\\n        return;\\n      }\\n    }\\n  }\\n\\n  //////////////////////////////////////////////\\n  // Material\\n  vec2 materialCoords = v_geomItemData.zw;\\n  vec4 BaseColor = getMaterialValue(materialCoords, 1);\\n  vec4 matValue1 = getMaterialValue(materialCoords, 2);\\n  vec4 matValue2 = getMaterialValue(materialCoords, 3);\\n  float Opacity  = matValue1.r;\\n\\n  //////////////////////////////////////////////\\n  // Color\\n#if defined(DRAW_COLOR)\\n\\n  fragColor = BaseColor;\\n  \\n  if (occluded == 1) {\\n    fragColor = hiddenLineColor;\\n  }\\n\\n  fragColor.a *= Opacity * treeItemOpacity;\\n\\n  //////////////////////////////////////////////\\n  // GeomData\\n#elif defined(DRAW_GEOMDATA)\\n\\n  fragColor = setFragColor_geomData(v_viewPos, v_geomItemId, 0.0, isOrthographic, flags, LINES);\\n  \\n  //////////////////////////////////////////////\\n  // Highlight\\n#elif defined(DRAW_HIGHLIGHT)\\n  \\n  fragColor = getHighlightColor(geomItemId);\\n\\n#endif // DRAW_HIGHLIGHT\\n\\n#ifndef ENABLE_ES3\\n  gl_FragColor = fragColor;\\n#endif\\n}\\n\"; // eslint-disable-line\n\n/* eslint-disable require-jsdoc */\nclass LinesShader extends GLShader {\n    /**\n     * Create a GL shader.\n     * @param gl - The webgl rendering context.\n     */\n    constructor(gl) {\n        super(gl, 'LinesShader');\n        this.setShaderStage('VERTEX_SHADER', vert$5);\n        this.setShaderStage('FRAGMENT_SHADER', frag$5);\n    }\n    /**\n     * The getPackedMaterialData method.\n     * @param material - The material param.\n     * @return - The return value.\n     */\n    static getPackedMaterialData(material) {\n        const matData = new Float32Array(12);\n        let pixId = 0;\n        matData[pixId * 4 + 0] = 3;\n        const baseColorParam = material.getParameter('BaseColor');\n        let baseColor;\n        if (baseColorParam instanceof MaterialColorParam && baseColorParam.colorSpace == ColorSpace.Gamma) {\n            baseColor = baseColorParam.value.toLinear();\n        }\n        else {\n            baseColor = baseColorParam.value;\n        }\n        pixId++;\n        matData[pixId * 4 + 0] = baseColor.r;\n        matData[pixId * 4 + 1] = baseColor.g;\n        matData[pixId * 4 + 2] = baseColor.b;\n        matData[pixId * 4 + 3] = baseColor.a;\n        pixId++;\n        // Note: By avoiding calling this value 'Opacity', the lines will not be considered 'Transparent'\n        // Lines do not need to be depth sorted....\n        matData[pixId * 4 + 0] = material.getParameter('Opacity').value;\n        matData[pixId * 4 + 1] = material.getParameter('Overlay').value;\n        return matData;\n    }\n    /**\n     * Each shader provides a template material that each material instance is\n     * based on. The shader specifies the parameters needed by the shader, and\n     * the material provides values to the shader during rendering.\n     * @return - The template material value.\n     */\n    static getMaterialTemplate() {\n        return material$6;\n    }\n}\nconst material$6 = new LinesMaterial('LinesShader_template');\nRegistry.register('LinesShader', LinesShader);\n\nvar frag$4 = \"\\nprecision highp float;\\n#define GLSLIFY 1\\n\\nimport 'GLSLUtils.glsl'\\nimport 'drawItemTexture.glsl'\\nimport 'cutaways.glsl'\\nimport 'geometryMask.glsl'\\nimport 'materialparams.glsl'\\nimport 'geomItemFlags.glsl'\\nimport 'surfaceGeomData.glsl'\\n\\n#if defined(DRAW_GEOMDATA)\\n\\nimport 'GLSLBits.glsl'\\nuniform highp int isOrthographic;\\n\\n#elif defined(DRAW_HIGHLIGHT)\\n\\n#ifdef ENABLE_FLOAT_TEXTURES\\nvec4 getHighlightColor(int id) {\\n  return fetchTexel(instancesTexture, instancesTextureSize, (id * pixelsPerItem) + 4);\\n}\\n#else // ENABLE_FLOAT_TEXTURES\\n\\nuniform vec4 highlightColor;\\n\\nvec4 getHighlightColor() {\\n  return highlightColor;\\n}\\n\\n#endif // ENABLE_FLOAT_TEXTURES\\n\\n#endif // DRAW_HIGHLIGHT\\n\\n/* VS Outputs */\\nvarying vec2 v_drawItemIds;\\nvarying vec4 v_geomItemData;\\nvarying vec3 v_viewPos;\\n/* VS Outputs */\\n\\n#ifdef ENABLE_ES3\\nout vec4 fragColor;\\n#endif\\n\\nvoid main(void) {\\n\\n#ifndef ENABLE_ES3\\n  vec4 fragColor;\\n#endif\\n\\n  //////////////////////////////////////////////\\n  // Color\\n#if defined(DRAW_COLOR)\\n\\n  vec2 materialCoords = v_geomItemData.zw;\\n  vec4 baseColor = getMaterialValue(materialCoords, 1);\\n  vec4 matValue1 = getMaterialValue(materialCoords, 2);\\n  float pointSize     = baseColor.a * matValue1.r;\\n  float overlay       = matValue1.g;\\n\\n  fragColor = baseColor;\\n\\n  //////////////////////////////////////////////\\n  // GeomData\\n#elif defined(DRAW_GEOMDATA)\\n\\n  fragColor = setFragColor_geomData(v_viewPos, v_drawItemIds.x, v_drawItemIds.y, isOrthographic, 0, POINTS);\\n\\n  //////////////////////////////////////////////\\n  // Highlight\\n#elif defined(DRAW_HIGHLIGHT)\\n  \\n  int geomItemId = int(round(v_drawItemIds.x));\\n  fragColor = getHighlightColor(geomItemId);\\n\\n#endif // DRAW_HIGHLIGHT\\n\\n#ifndef ENABLE_ES3\\n  gl_FragColor = fragColor;\\n#endif\\n}\\n\"; // eslint-disable-line\n\nvar vert$4 = \"\\nprecision highp float;\\n#define GLSLIFY 1\\n\\nattribute vec3 positions;\\n\\nimport 'GLSLUtils.glsl'\\nimport 'geomItemId.glsl'\\nimport 'drawItemTexture.glsl'\\nimport 'modelMatrix.glsl'\\nimport 'materialparams.glsl'\\n\\nuniform mat4 viewMatrix;\\nuniform mat4 projectionMatrix;\\nuniform int isOrthographic;\\n\\n/* VS Outputs */\\nvarying vec2 v_drawItemIds;\\nvarying vec4 v_geomItemData;\\nvarying vec3 v_viewPos;\\n\\nvoid main(void) {\\n  int geomItemId = getGeomItemId();\\n  v_drawItemIds.x = float(geomItemId);\\n  v_drawItemIds.y = float(gl_VertexID);\\n  v_geomItemData  = getInstanceData(geomItemId);\\n\\n  mat4 modelMatrix = getModelMatrix(geomItemId);\\n  mat4 modelViewMatrix = viewMatrix * modelMatrix;\\n  \\n  vec4 viewPos = modelViewMatrix * vec4(positions, 1.);\\n  gl_Position = projectionMatrix * viewPos;\\n  \\n\\n  //////////////////////////////////////////////\\n  // Material\\n  vec2 materialCoords = v_geomItemData.zw;\\n  vec4 materialValue1 = getMaterialValue(materialCoords, 2);\\n  float pointSize = materialValue1.x;\\n  float overlay = materialValue1.y;\\n\\n  //////////////////////////////////////////////\\n\\n  // Note: as of 22/01/2021 gl_PointSize has stopped working again...\\n  // It is working again now in Chrome\\n  gl_PointSize = pointSize * 1.0 / length(viewPos.xyz);\\n\\n  if (isOrthographic > 0){\\n    gl_Position.z -= overlay;\\n  } else {\\n    gl_Position.z = mix(gl_Position.z, -gl_Position.z, overlay);\\n  }\\n  \\n  v_viewPos = -viewPos.xyz;\\n}\\n\"; // eslint-disable-line\n\nclass PointsShader extends GLShader {\n    /**\n     * Create a GL shader.\n     * @param gl - The webgl rendering context.\n     */\n    constructor(gl) {\n        super(gl, 'PointsShader');\n        this.setShaderStage('VERTEX_SHADER', vert$4);\n        this.setShaderStage('FRAGMENT_SHADER', frag$4);\n    }\n    /**\n     * The getPackedMaterialData method.\n     * @param material - The material param.\n     * @return - The return value.\n     */\n    static getPackedMaterialData(material) {\n        const matData = new Float32Array(12);\n        let pixId = 0;\n        matData[pixId * 4 + 0] = 4;\n        const baseColorParam = material.getParameter('BaseColor');\n        let baseColor;\n        if (baseColorParam instanceof MaterialColorParam && baseColorParam.colorSpace == ColorSpace.Gamma) {\n            baseColor = baseColorParam.value.toLinear();\n        }\n        else {\n            baseColor = baseColorParam.value;\n        }\n        pixId++;\n        matData[pixId * 4 + 0] = baseColor.r;\n        matData[pixId * 4 + 1] = baseColor.g;\n        matData[pixId * 4 + 2] = baseColor.b;\n        matData[pixId * 4 + 3] = baseColor.a;\n        pixId++;\n        matData[pixId * 4 + 0] = material.getParameter('PointSize').value;\n        matData[pixId * 4 + 1] = material.getParameter('Overlay').value;\n        return matData;\n    }\n    /**\n     * Each shader provides a template material that each material instance is\n     * based on. The shader specifies the parameters needed by the shader, and\n     * the material provides values to the shader during rendering.\n     * @return - The template material value.\n     */\n    static getMaterialTemplate() {\n        return material$5;\n    }\n}\nconst material$5 = new PointsMaterial('PointsShader_template');\nRegistry.register('PointsShader', PointsShader);\n\nvar vert$3 = \"\\nprecision highp float;\\nprecision highp int;\\n#define GLSLIFY 1\\n\\ninstancedattribute int drawIndices;\\nuniform sampler2D pointsAttributes;\\nuniform int texelsPerPoint;\\n\\nuniform mat4 viewMatrix;\\nuniform mat4 projectionMatrix;\\nuniform int isOrthographic;\\n\\nimport 'GLSLUtils.glsl' \\nimport 'inverse.glsl'\\nimport 'drawItemTexture.glsl'\\nimport 'geomItemId.glsl'\\nimport 'modelMatrix.glsl'\\nimport 'quadVertexFromID.glsl'\\nimport 'materialparams.glsl'\\n\\n/* VS Outputs */\\nvarying vec4 v_drawItemIds;\\nvarying vec4 v_geomItemData;\\nvarying vec3 v_texCoord;\\nvarying vec3 v_viewPos;\\nvarying vec4 v_color;\\n\\nvoid main(void) {\\n  int geomItemId = getGeomItemId();\\n  v_geomItemData  = getInstanceData(geomItemId);\\n\\n  vec2 quadPointPos = getQuadVertexPositionFromID();\\n  v_texCoord.xy = vec2(quadPointPos.x, -quadPointPos.y) + 0.5;\\n\\n  mat4 modelMatrix = getModelMatrix(geomItemId);\\n  mat4 modelViewMatrix = viewMatrix * modelMatrix;\\n\\n  ivec2 texSize = textureSize(pointsAttributes, 0);\\n  int texelIndex = drawIndices * texelsPerPoint;\\n  ivec2 texelCoord = ivec2(\\n    texelIndex % texSize.x, \\n    texelIndex / texSize.x\\n  );\\n  vec4 texel0 = texelFetch(pointsAttributes, texelCoord, 0);\\n\\n  vec3 pos = texel0.xyz;\\n  float size = texel0.w;\\n\\n  if (texelsPerPoint >= 2) {\\n    vec4 texel1 = texelFetch(pointsAttributes, ivec2(texelCoord.x + 1, texelCoord.y), 0);\\n    v_color = texel1;\\n  } else {\\n    v_color = vec4(1., 1., 1., 1.);\\n  }\\n\\n  if (texelsPerPoint >= 3) {\\n    vec4 texel2 = texelFetch(pointsAttributes, ivec2(texelCoord.x + 2, texelCoord.y), 0);\\n    v_texCoord.z = texel2.x;\\n  } else {\\n    v_texCoord.z = -1.0;\\n  }\\n  \\n  //////////////////////////////////////////////\\n  // Material\\n  vec2 materialCoords = v_geomItemData.zw;\\n  vec4 materialValue1 = getMaterialValue(materialCoords, 1);\\n  float pointSize = materialValue1.r * size;\\n  float overlay = materialValue1.b;\\n\\n  vec4 viewPos = modelViewMatrix * vec4(pos, 1.0);\\n\\n  // During XR sessions, there is a scaling applied to the view matrix\\n  // which causes a distortion to the line width. We extract that scale here\\n  // and use to correct the distortion.\\n  // See also: FatLinesShader\\n  vec3 viewZ = modelViewMatrix[2].xyz;\\n  float viewScale = length(viewZ);\\n  viewPos += vec4(vec3(quadPointPos, 0.0) * pointSize * viewScale, 0.);\\n\\n  // Generate a quad which is 0.5 * PointSize closer towards\\n  // us. This allows points to be visualized even if snug on \\n  // a surface. (else they get fully clipped)\\n  viewPos.z += 0.5 * pointSize;\\n\\n  v_drawItemIds.x = float(geomItemId);\\n  v_drawItemIds.y = float(drawIndices);\\n  v_viewPos = -viewPos.xyz;\\n  \\n  gl_Position = projectionMatrix * viewPos;\\n\\n  if (isOrthographic > 0){\\n    gl_Position.z -= overlay;\\n  } else {\\n    gl_Position.z = mix(gl_Position.z, -gl_Position.z, overlay);\\n  }\\n}\\n\"; // eslint-disable-line\n\nvar frag$3 = \"\\nprecision highp float;\\nprecision highp int;\\n#define GLSLIFY 1\\n\\nimport 'constants.glsl'\\nimport 'GLSLUtils.glsl'\\nimport 'materialparams.glsl'\\n\\nuniform sampler2D BaseColorTex;\\nuniform int BaseColorTexType;\\nuniform int highlightSubIndex;\\n\\nuniform sampler2D atlasSprites;\\nuniform sampler2D atlasSprites_layout;\\nuniform vec4 atlasSprites_desc;\\n\\n/* VS Outputs */\\nvarying vec4 v_drawItemIds;\\nvarying vec4 v_geomItemData;\\nvarying vec3 v_texCoord;\\nvarying vec3 v_viewPos;\\nvarying vec4 v_color;\\n\\nvec4 sampleSpriteAtlas(int spriteCoord) {\\n  ivec2 atlasSpritesSize = textureSize(atlasSprites_layout, 0);\\n  // round to an integer, and avoid floating point issues by adding a small value\\n  ivec2 texelCoord = ivec2(\\n    spriteCoord % atlasSpritesSize.x, \\n    spriteCoord / atlasSpritesSize.x\\n  );\\n  vec4 layoutData = fetchTexel(atlasSprites_layout, atlasSpritesSize, spriteCoord);\\n  vec2 spriteTexCoord = v_texCoord.xy;\\n  spriteTexCoord *= layoutData.zw;\\n  spriteTexCoord += layoutData.xy;\\n  return texture2D(atlasSprites, spriteTexCoord);\\n}\\n\\n#ifdef ENABLE_ES3\\nout vec4 fragColor;\\n#endif\\n\\n#if defined(DRAW_GEOMDATA)\\n  uniform int isOrthographic;\\n  import 'surfaceGeomData.glsl'\\n#elif defined(DRAW_HIGHLIGHT)\\n  import 'surfaceHighlight.glsl'\\n#endif // DRAW_HIGHLIGHT\\n\\nvoid main(void) {\\n\\n#ifndef ENABLE_ES3\\n  vec4 fragColor;\\n#endif\\n\\n#if defined(DRAW_COLOR)\\n\\n  vec2 materialCoords = v_geomItemData.zw;\\n  vec4 baseColor = getMaterialValue(materialCoords, 0);\\n  vec4 matValue1 = getMaterialValue(materialCoords, 1);\\n  float pointSize     = matValue1.r;\\n  float borderWidth   = matValue1.g;\\n\\n  if (v_texCoord.z > -0.5) {\\n    int spriteCoord = int(v_texCoord.z + 0.1);\\n    baseColor = sampleSpriteAtlas(spriteCoord) * v_color;\\n    if (baseColor.a < 0.0001) discard;\\n  } else {\\n    \\n    float dist = length(v_texCoord.xy - 0.5);\\n    if (dist > 0.5) discard;\\n\\n    if (dist > 0.5 - (borderWidth * 0.5))\\n      baseColor = vec4(0.,0.,0.,1.);\\n    else {\\n      baseColor = baseColor * v_color;\\n      ivec2 texSize = textureSize(BaseColorTex, 0);\\n      if (texSize.x == 1 && texSize.y > 1) {\\n        vec4 gradient = texture2D(BaseColorTex, vec2(0.5, dist * 2.0));\\n        baseColor *= gradient;\\n      }\\n    }\\n  }\\n\\n  fragColor = baseColor;\\n#elif defined(DRAW_GEOMDATA)\\n  fragColor = setFragColor_geomData(v_viewPos, v_drawItemIds.x, v_drawItemIds.y, isOrthographic, 0, POINTS);\\n#elif defined(DRAW_HIGHLIGHT)\\n  if (highlightSubIndex != -1 && int(round(v_drawItemIds.y)) != highlightSubIndex) discard;\\n  fragColor = setFragColor_highlight(v_drawItemIds.x);\\n#endif // DRAW_HIGHLIGHT\\n\\n#ifndef ENABLE_ES3\\n  gl_FragColor = fragColor;\\n#endif\\n}\\n\"; // eslint-disable-line\n\n/* eslint-disable require-jsdoc */\nclass FatPointsShader extends GLShader {\n    /**\n     * Create a GL shader.\n     * @param gl - The webgl rendering context.\n     */\n    constructor(gl) {\n        super(gl, 'FatPointsShader');\n        this.setShaderStage('VERTEX_SHADER', vert$3);\n        this.setShaderStage('FRAGMENT_SHADER', frag$3);\n    }\n    bind(renderstate, key) {\n        if (super.bind(renderstate, key)) {\n            renderstate.supportsInstancing = false;\n            const gl = this.__gl;\n            if (!gl.__quadVertexIdsBuffer)\n                gl.setupInstancedQuad();\n            renderstate.shaderInstancedGeom = {\n                attrBuffers: gl.__quadattrbuffers,\n                indexBuffer: gl.__quadIndexBuffer,\n                indexDataType: gl.UNSIGNED_BYTE,\n                numVertices: 4,\n                numTriIndices: 6,\n            };\n            renderstate.supportsInstancing = false;\n            return true;\n        }\n        return false;\n    }\n    /**\n     * The getPackedMaterialData method.\n     * @param material - The material param.\n     * @return - The return value.\n     */\n    static getPackedMaterialData(material) {\n        const matData = new Float32Array(8);\n        const baseColorParam = material.getParameter('BaseColor');\n        let baseColor;\n        if (baseColorParam instanceof MaterialColorParam && baseColorParam.colorSpace == ColorSpace.Gamma) {\n            baseColor = baseColorParam.value.toLinear();\n        }\n        else {\n            baseColor = baseColorParam.value;\n        }\n        let pixId = 0;\n        matData[pixId * 4 + 0] = baseColor.r;\n        matData[pixId * 4 + 1] = baseColor.g;\n        matData[pixId * 4 + 2] = baseColor.b;\n        matData[pixId * 4 + 3] = baseColor.a;\n        pixId++;\n        matData[pixId * 4 + 0] = material.getParameter('PointSize').value;\n        matData[pixId * 4 + 1] = material.getParameter('BorderWidth').value;\n        matData[pixId * 4 + 2] = material.getParameter('Overlay').value;\n        return matData;\n    }\n    /**\n     * The supportsInstancing method.\n     * @return - return false for shaders that cannot be rendered in instanced mode.\n     */\n    static supportsInstancing() {\n        return false;\n    }\n    /**\n     * Each shader provides a template material that each material instance is\n     * based on. The shader specifies the parameters needed by the shader, and\n     * the material provides values to the shader during rendering.\n     * @return - The template material value.\n     */\n    static getMaterialTemplate() {\n        return material$4;\n    }\n}\nconst material$4 = new FatPointsMaterial('FatPointsShader_template');\nRegistry.register('FatPointsShader', FatPointsShader);\n\nvar frag$2 = \"precision highp float;\\n#define GLSLIFY 1\\n\\nimport 'GLSLUtils.glsl'\\nimport 'drawItemTexture.glsl'\\nimport 'cutaways.glsl'\\nimport 'geometryMask.glsl'\\nimport 'gamma.glsl'\\nimport 'materialparams.glsl'\\nimport 'geomItemFlags.glsl'\\n\\n#ifdef DEBUG_GEOM_ID\\nimport 'debugColors.glsl'\\n#endif\\n\\n/* VS Outputs */\\nvarying vec4 v_drawItemIds;\\nvarying vec4 v_geomItemData;\\nvarying vec3 v_viewPos;\\nvarying vec3 v_viewNormal;\\n#ifdef ENABLE_TEXTURES\\nvarying vec2 v_textureCoord;\\n#endif\\nvarying vec3 v_worldPos;\\n/* VS Outputs */\\n\\nuniform mat4 cameraMatrix;\\nuniform int isOrthographic;\\n\\n#ifdef ENABLE_ES3\\n    out vec4 fragColor;\\n#endif\\n\\n#if defined(DRAW_COLOR)\\n\\n#ifdef ENABLE_TEXTURES\\nuniform sampler2D BaseColorTex;\\nuniform int BaseColorTexType;\\nuniform sampler2D OpacityTex;\\nuniform int OpacityTexType;\\nuniform sampler2D EmissiveStrengthTex;\\nuniform int EmissiveStrengthTexType;\\n#endif // ENABLE_TEXTURES\\n\\nimport 'computeViewNormal.glsl'\\n  \\n// end DRAW_COLOR\\n#elif defined(DRAW_GEOMDATA)\\n  import 'surfaceGeomData.glsl'\\n#elif defined(DRAW_HIGHLIGHT)\\n  import 'surfaceHighlight.glsl'\\n#endif // DRAW_HIGHLIGHT\\n\\nvoid main(void) {\\n#ifndef ENABLE_ES3\\n  vec4 fragColor;\\n#endif\\n  int geomItemId = int(round(v_drawItemIds.x));\\n  int elemId = int(round(v_drawItemIds.y));\\n  int perFaceMaterialId = int(round(v_drawItemIds.z));\\n  int flags = int(round(v_geomItemData.x));\\n  float treeItemOpacity = v_geomItemData.y;\\n\\n  // We can make geoms invisible to hide them. \\n  // Avoid drawing GeomData for geoms that are completely transparent.\\n  if (treeItemOpacity < 0.001 && !testFlag(flags, GEOMITEM_MASK)) {\\n    discard;\\n    return;\\n  }\\n  \\n  // Cutaways\\n  if (testFlag(flags, GEOMITEM_FLAG_CUTAWAY)) \\n  {\\n    vec4 cutAwayData   = getCutaway(geomItemId);\\n    vec3 planeNormal = cutAwayData.xyz;\\n    float planeDist = cutAwayData.w;\\n    if (length(planeNormal) > 0.5) {\\n      if (cutaway(v_worldPos, planeNormal, planeDist)) {\\n          discard;\\n          return;\\n      }\\n    } else {\\n      if (testGeometryMask(v_viewPos)) {\\n        discard;\\n        return;\\n      }\\n    }\\n  }\\n\\n#if defined(DRAW_COLOR)\\n\\n  //////////////////////////////////////////////\\n  // Normals\\n  \\n  vec3 viewNormal;\\n  if (length(v_viewNormal) < 0.1) {\\n    viewNormal = computeViewNormal(v_viewPos);\\n  } else {\\n    viewNormal = normalize(v_viewNormal);\\n  }\\n  vec3 normal = normalize(mat3(cameraMatrix) * viewNormal);\\n  \\n  vec3 viewVector;\\n  if (isOrthographic == 0)\\n    viewVector = normalize(mat3(cameraMatrix) * normalize(v_viewPos));\\n  else \\n    viewVector = vec3(-cameraMatrix[2][0], -cameraMatrix[2][1], -cameraMatrix[2][2]);\\n  \\n  //////////////////////////////////////////////\\n  // Material\\n\\n  vec2 materialCoords = v_geomItemData.zw;\\n  if (perFaceMaterialId > 0) {\\n    materialCoords.x = float(perFaceMaterialId);\\n  }\\n  vec4 baseColor      = getMaterialValue(materialCoords, 1);\\n  vec4 matValue1      = getMaterialValue(materialCoords, 2);\\n  float opacity       = baseColor.a * matValue1.r;\\n  float emission      = matValue1.g;\\n\\n#ifdef ENABLE_TEXTURES\\n  getTextureColorValue(baseColor, BaseColorTex, BaseColorTexType, v_textureCoord);\\n  getTextureLuminanceValue(opacity, OpacityTex, OpacityTexType, v_textureCoord);\\n  getTextureLuminanceValue(emission, EmissiveStrengthTex, EmissiveStrengthTexType, v_textureCoord);\\n#endif\\n\\n  // Cutaways\\n  if (testFlag(flags, GEOMITEM_FLAG_CUTAWAY) && !gl_FrontFacing) {\\n    fragColor = baseColor;\\n  } else {\\n    // Hacky simple irradiance. \\n    float ndotv = dot(normal, viewVector);\\n    if (ndotv < 0.0) {\\n      normal = -normal;\\n      ndotv = dot(normal, viewVector);\\n\\n      // Note: these 2 lines can be used to debug inverted meshes.\\n      //baseColor = vec4(1.0, 0.0, 0.0, 1.0);\\n      //ndotv = 1.0;\\n    }\\n\\n    fragColor = vec4((ndotv * baseColor.rgb) + (emission * baseColor.rgb), opacity);\\n  }\\n\\n  // Note: the 'treeItemOpacity' is not an input to the lighting, \\n  // as we want to also blend off the specular reflections to make an object\\n  // fade away to nothing. (not become a transparent glass object).\\n  fragColor.a *= treeItemOpacity;\\n\\n#ifdef DEBUG_GEOM_ID\\n  // ///////////////////////\\n  // Debug Draw ID (this correlates to GeomID within a GLGeomSet)\\n  float geomId = v_geomItemData.w;\\n  fragColor.rgb = getDebugColor(geomId);\\n  // ///////////////////////\\n#endif\\n\\n#ifdef ENABLE_INLINE_GAMMACORRECTION\\n  fragColor.rgb = toGamma(fragColor.rgb);\\n#endif\\n\\n#elif defined(DRAW_GEOMDATA)\\n  fragColor = setFragColor_geomData(v_viewPos, v_drawItemIds.x, v_drawItemIds.y, isOrthographic, flags, TRIANGLES);\\n#elif defined(DRAW_HIGHLIGHT)\\n  fragColor = setFragColor_highlight(v_drawItemIds.x);\\n#endif // DRAW_HIGHLIGHT\\n\\n#ifndef ENABLE_ES3\\n  gl_FragColor = fragColor;\\n#endif\\n}\"; // eslint-disable-line\n\nvar vert$2 = \"precision highp float;\\n#define GLSLIFY 1\\n\\nattribute vec3 positions;\\nattribute vec3 normals;\\n#ifdef ENABLE_TEXTURES\\nattribute vec2 texCoords;\\n#endif\\n\\nuniform mat4 viewMatrix;\\nuniform mat4 projectionMatrix;\\n\\nimport 'GLSLUtils.glsl'\\nimport 'transpose.glsl'\\nimport 'inverse.glsl'\\nimport 'geomItemId.glsl'\\nimport 'drawItemTexture.glsl'\\nimport 'modelMatrix.glsl'\\n\\n/* VS Outputs */\\nvarying vec4 v_drawItemIds;\\nvarying vec4 v_geomItemData;\\nvarying vec3 v_viewPos;\\nvarying vec3 v_viewNormal;\\n#ifdef ENABLE_TEXTURES\\nvarying vec2 v_textureCoord;\\n#endif\\nvarying vec3 v_worldPos;\\n\\nvoid main(void) {\\n  v_drawItemIds = getDrawItemIds();\\n  int geomItemId = int(round(v_drawItemIds.x));\\n  v_geomItemData  = getInstanceData(geomItemId);\\n\\n  mat4 modelMatrix = getModelMatrix(geomItemId);\\n  mat4 modelViewMatrix = viewMatrix * modelMatrix;\\n\\n  vec4 pos = vec4(positions, 1.);\\n  vec4 viewPos    = modelViewMatrix * pos;\\n  gl_Position     = projectionMatrix * viewPos;\\n\\n  mat3 normalMatrix = mat3(transpose(inverse(modelViewMatrix)));\\n  v_viewPos       = -viewPos.xyz;\\n  v_viewNormal    = normalMatrix * normals; // Note: we normalize in the fragment shader.\\n\\n#ifdef ENABLE_TEXTURES\\n  v_textureCoord = texCoords;\\n  v_textureCoord.y = 1.0 - v_textureCoord.y;// Flip y\\n#endif\\n\\n  v_worldPos      = (modelMatrix * pos).xyz;\\n}\\n\"; // eslint-disable-line\n\n/* eslint-disable require-jsdoc */\n/** A simple shader with no support for PBR or textures\n * @ignore\n */\nclass SimpleSurfaceShader extends GLShader {\n    /**\n     * Create a SimpleSurfaceShader\n     * @param gl - gl context\n     */\n    constructor(gl) {\n        super(gl, 'SimpleSurfaceShader');\n        this.setShaderStage('VERTEX_SHADER', vert$2);\n        this.setShaderStage('FRAGMENT_SHADER', frag$2);\n    }\n    /**\n     * The getPackedMaterialData method.\n     * @param material - The material param.\n     * @return - The return value.\n     */\n    static getPackedMaterialData(material) {\n        const matData = new Float32Array(12);\n        let pixId = 0;\n        matData[pixId * 4 + 0] = 6;\n        const baseColorParam = material.getParameter('BaseColor');\n        let baseColor;\n        if (baseColorParam instanceof MaterialColorParam && baseColorParam.colorSpace == ColorSpace.Gamma) {\n            baseColor = baseColorParam.value.toLinear();\n        }\n        else {\n            baseColor = baseColorParam.value;\n        }\n        pixId++;\n        matData[pixId * 4 + 0] = baseColor.r;\n        matData[pixId * 4 + 1] = baseColor.g;\n        matData[pixId * 4 + 2] = baseColor.b;\n        matData[pixId * 4 + 3] = baseColor.a;\n        pixId++;\n        matData[pixId * 4 + 0] = material.getParameter('Opacity').value;\n        matData[pixId * 4 + 1] = material.getParameter('EmissiveStrength').value;\n        return matData;\n    }\n    /**\n     * Each shader provides a template material that each material instance is\n     * based on. The shader specifies the parameters needed by the shader, and\n     * the material provides values to the shader during rendering.\n     * @return - The template material value.\n     */\n    static getMaterialTemplate() {\n        return material$3;\n    }\n}\nconst material$3 = new SimpleSurfaceMaterial('SimpleSurfaceShader_template');\nRegistry.register('SimpleSurfaceShader', SimpleSurfaceShader);\n\nvar vert$1 = \"\\nprecision highp float;\\nprecision highp int;\\n#define GLSLIFY 1\\n\\nattribute vec3 positions;\\nattribute vec3 normals;\\n#ifdef ENABLE_TEXTURES\\nattribute vec2 texCoords;\\n#endif\\n\\nuniform mat4 viewMatrix;\\nuniform mat4 projectionMatrix;\\nuniform int isOrthographic;\\n\\n// Now that we render multiple types of geometry from a single shader\\n// we need to know what kind of geometry it is...\\nuniform int geomType;\\n\\nuniform float outlineThickness;\\nuniform vec2 viewportSize;\\n\\n// should be imported by bottom 3\\nimport 'GLSLUtils.glsl'\\nimport 'transpose.glsl'\\nimport 'inverse.glsl'\\n\\nimport 'geomItemId.glsl'\\nimport 'geomType.glsl'\\nimport 'drawItemTexture.glsl'\\nimport 'modelMatrix.glsl'\\nimport 'geomItemFlags.glsl'\\nimport 'materialparams.glsl'\\n\\n/* VS Outputs */\\nvarying vec4 v_drawItemIds;\\nvarying vec4 v_geomItemData;\\nvarying vec3 v_viewPos;\\nvarying vec3 v_viewNormal;\\n#ifdef ENABLE_TEXTURES\\nvarying vec2 v_textureCoord;\\n#endif\\nvarying vec3 v_worldPos;\\n/* VS Outputs */\\n\\n#if defined(DRAW_COLOR)\\n#elif defined(DRAW_GEOMDATA)\\n#elif defined(DRAW_HIGHLIGHT)\\n#endif // DRAW_HIGHLIGHT\\n\\nvoid main(void) {\\n\\n  v_drawItemIds = getDrawItemIds();\\n  int geomItemId = int(round(v_drawItemIds.x));\\n  v_geomItemData = getInstanceData(geomItemId);\\n  mat4 modelMatrix = getModelMatrix(geomItemId);\\n\\n  vec4 pos = vec4(positions, 1.);\\n  mat4 modelViewMatrix = viewMatrix * modelMatrix;\\n  vec4 viewPos    = modelViewMatrix * pos;\\n  gl_Position     = projectionMatrix * viewPos;\\n  v_viewPos       = -viewPos.xyz;\\n  v_worldPos      = (modelMatrix * pos).xyz;\\n\\n  mat3 normalMatrix = mat3(transpose(inverse(modelViewMatrix)));\\n  v_viewNormal    = normalMatrix * normals; // Note: we normalize in the fragment shader.\\n  \\n  // offset slightly the lines and points to make them clearly defined.\\n  // This ensures that lines drawn over surfaces are solid and not clipped\\n  // at all by the surface.\\n  if (geomType == TRIANGLES) {\\n    if (outlineThickness > 0.00001) {\\n      vec2 screenNormal = v_viewNormal.xy;\\n      gl_Position.xy += normalize(screenNormal) * ((2.0 / viewportSize) * outlineThickness) * gl_Position.w;\\n    }\\n  }\\n  \\n  //////////////////////////////////////////////\\n  // Overlay\\n  float viewDepth = v_viewPos.z;\\n    \\n  vec2 materialCoords = v_geomItemData.zw;\\n  vec4 materialValue2 = getMaterialValue(materialCoords, 3);\\n  vec4 materialValue5 = getMaterialValue(materialCoords, 6);\\n  float overlay = materialValue2.b;\\n  float pointSize = materialValue5.r;\\n\\n  if (geomType == POINTS) { // start 'POINTS'\\n    // Fixed size on screen points.\\n    gl_PointSize = pointSize;\\n    overlay += 0.000005 / viewDepth;\\n  }  // end 'POINTS'\\n\\n  if (isOrthographic > 0){\\n    gl_Position.z -= overlay;\\n  } else {\\n    gl_Position.z = mix(gl_Position.z, -gl_Position.z, overlay);\\n  }\\n\\n#ifdef ENABLE_TEXTURES\\n  v_textureCoord = texCoords;\\n  v_textureCoord.y = 1.0 - v_textureCoord.y;// Flip y\\n#endif\\n\\n}\\n\"; // eslint-disable-line\n\nvar frag$1 = \"precision highp float;\\nprecision highp int;\\n#define GLSLIFY 1\\nimport 'GLSLUtils.glsl'\\nimport 'drawItemTexture.glsl' \\nimport 'cutaways.glsl'\\nimport 'geometryMask.glsl'\\nimport 'gamma.glsl'\\nimport 'materialparams.glsl'\\nimport 'GLSLBits.glsl'\\nimport 'geomItemFlags.glsl'\\n\\n/* VS Outputs */\\nvarying vec4 v_drawItemIds;\\nvarying vec4 v_geomItemData;\\nvarying vec3 v_viewPos;\\nvarying vec3 v_viewNormal;\\n#ifdef ENABLE_TEXTURES\\nvarying vec2 v_textureCoord;\\n#endif\\nvarying vec3 v_worldPos;\\n/* VS Outputs */\\n\\n#ifdef ENABLE_ES3\\n  out vec4 fragColor;\\n#endif\\n\\n// Now that we render multiple types of geometry from a single shader\\n// we need to know what kind of geometry it is...\\nuniform int geomType;\\nimport 'geomType.glsl'\\n\\nuniform int isOrthographic;\\n\\n#if defined(DRAW_COLOR)\\n\\nuniform int renderMode;\\nuniform int occluded;\\nuniform float outlineThickness;\\nuniform vec4 hiddenLineColor;\\n\\n#ifdef ENABLE_INLINE_GAMMACORRECTION\\nuniform float exposure;\\n#endif\\n\\nuniform mat4 cameraMatrix;\\n\\n#ifdef ENABLE_TEXTURES\\nuniform sampler2D BaseColorTex;\\nuniform int BaseColorTexType;\\n\\nuniform sampler2D AmbientOcclusionTex;\\nuniform int AmbientOcclusionTexType;\\n\\n#ifdef ENABLE_PBR\\nuniform sampler2D RoughnessTex;\\nuniform int RoughnessTexType;\\n\\nuniform sampler2D MetallicTex;\\nuniform int MetallicTexType;\\n\\nuniform sampler2D ReflectanceTex;\\nuniform int ReflectanceTexType;\\n\\nuniform sampler2D NormalTex;\\nuniform int NormalTexType;\\n#endif // ENABLE_PBR\\n\\nuniform sampler2D EmissiveStrengthTex;\\nuniform int EmissiveStrengthTexType;\\n\\n#endif // ENABLE_TEXTURES\\n\\nimport 'PBRSurfaceRadiance.glsl'\\n\\n#ifdef ENABLE_PBR\\nmat3 cotangentFrame( in vec3 normal, in vec3 pos, in vec2 texCoord ) {\\n  // https://stackoverflow.com/questions/5255806/how-to-calculate-tangent-and-binormal\\n  vec3 n = normal;\\n  // derivations of the fragment position\\n  vec3 pos_dx = dFdx( pos );\\n  vec3 pos_dy = dFdy( pos );\\n  // derivations of the texture coordinate\\n  vec2 texC_dx = dFdx( texCoord );\\n  vec2 texC_dy = dFdy( texCoord );\\n  // tangent vector and binormal vector\\n  vec3 t = -(texC_dy.y * pos_dx - texC_dx.y * pos_dy);\\n  vec3 b = -(texC_dx.x * pos_dy - texC_dy.x * pos_dx);\\n\\n  t = t - n * dot( t, n ); // orthonormalization ot the tangent vectors\\n  b = b - n * dot( b, n ); // orthonormalization of the binormal vectors to the normal vector\\n  b = b - t * dot( b, t ); // orthonormalization of the binormal vectors to the tangent vector\\n  mat3 tbn = mat3( normalize(t), normalize(b), n );\\n\\n  return tbn;\\n}\\n#endif\\n\\nimport 'computeViewNormal.glsl'\\n\\n#ifdef DEBUG_GEOM_ID\\nimport 'debugColors.glsl'\\n#endif\\n\\n// end DRAW_COLOR\\n#elif defined(DRAW_GEOMDATA)\\n\\nimport 'surfaceGeomData.glsl'\\n\\n#elif defined(DRAW_HIGHLIGHT)\\nimport 'surfaceHighlight.glsl'\\n#endif // DRAW_HIGHLIGHT\\n\\nvoid main(void) {\\n  #ifndef ENABLE_ES3\\n    vec4 fragColor;\\n  #endif\\n  \\n  int geomItemId = int(round(v_drawItemIds.x));\\n  int elemId = int(round(v_drawItemIds.y));\\n  int perElementMaterialId = int(round(v_drawItemIds.z));\\n  int flags = int(round(v_geomItemData.x));\\n  float treeItemOpacity = v_geomItemData.y;\\n\\n  // We can make geoms invisible to hide them. \\n  // Avoid drawing GeomData for geoms that are completely transparent.\\n  if (treeItemOpacity < 0.001) {\\n    discard;\\n    return;\\n  }\\n  \\n  if (testFlag(flags, GEOMITEM_FLAG_CUTAWAY)) {\\n    vec4 cutAwayData   = getCutaway(geomItemId);\\n    vec3 planeNormal = cutAwayData.xyz;\\n    float planeDist = cutAwayData.w;\\n    if (length(planeNormal) > 0.5) {\\n      if (cutaway(v_worldPos, planeNormal, planeDist)) {\\n          discard;\\n          return;\\n      }\\n    } else {\\n      if (testGeometryMask(v_viewPos)) {\\n        discard;\\n        return;\\n      }\\n    }\\n  }\\n  vec2 materialCoords = v_geomItemData.zw;\\n  if (perElementMaterialId > 0) {\\n    materialCoords.x = float(perElementMaterialId);\\n  }\\n\\n  \\n  vec4 materialHeader      = getMaterialValue(materialCoords, 0);\\n  int materialId = int(materialHeader.x + 0.5);\\n  \\n#if defined(DRAW_COLOR)\\n\\n  if (geomType == TRIANGLES) { // start 'TRIANGLES'\\n\\n    //////////////////////////////////////////////\\n    // Normals\\n    vec3 viewNormal;\\n    if (length(v_viewNormal) < 0.1) {\\n      viewNormal = computeViewNormal(v_viewPos);\\n    } else {\\n      viewNormal = normalize(v_viewNormal);\\n    }\\n    vec3 normal = normalize(mat3(cameraMatrix) * viewNormal);\\n    \\n    vec3 viewVector;\\n    if (isOrthographic == 0)\\n      viewVector = normalize(mat3(cameraMatrix) * normalize(v_viewPos));\\n    else \\n      viewVector = vec3(cameraMatrix[2][0], cameraMatrix[2][1], cameraMatrix[2][2]);\\n      \\n    if (dot(normal, viewVector) < 0.0) {\\n      normal = -normal;\\n      // Note: this line can be used to debug inverted meshes.\\n      //material.baseColor = vec3(1.0, 0.0, 0.0);\\n    }\\n\\n    //////////////////////////////////////////////\\n    // Material\\n\\n    MaterialParams material;\\n\\n    vec4 matValue0      = getMaterialValue(materialCoords, 1);\\n    vec4 matValue1      = getMaterialValue(materialCoords, 2);\\n    vec4 matValue2      = getMaterialValue(materialCoords, 3);\\n\\n    vec4 baseColor = matValue0;\\n    float opacity = matValue2.g;\\n    material.baseColor     = baseColor.rgb;\\n    material.ambientOcclusion = matValue1.r;\\n    material.metallic      = matValue1.g;\\n    material.roughness     = matValue1.b;\\n    material.reflectance   = matValue1.a;\\n\\n    material.emission      = matValue2.r;\\n    material.opacity       = opacity * baseColor.a;\\n\\n#ifdef ENABLE_TEXTURES\\n\\n    // Planar YZ projection for texturing, repeating every meter.\\n    // vec2 texCoord       = v_worldPos.xz * 0.2;\\n    vec2 texCoord          = v_textureCoord;\\n\\n    getTextureColorValue(baseColor, BaseColorTex, BaseColorTexType, texCoord);\\n    getTextureLuminanceValue(material.ambientOcclusion, AmbientOcclusionTex, AmbientOcclusionTexType, texCoord);\\n    \\n    material.baseColor     = baseColor.rgb;\\n    material.opacity       = opacity * baseColor.a;\\n\\n#ifdef ENABLE_PBR\\n\\n    getTextureLuminanceValue(material.metallic, MetallicTex, MetallicTexType, texCoord);\\n    getTextureLuminanceValue(material.roughness, RoughnessTex, RoughnessTexType, texCoord);\\n\\n    // TODO: Communicate that this tex contains the roughness as well.\\n    if (MetallicTexType != 0) {\\n      vec4 metallicRoughness = texture2D(MetallicTex, texCoord);\\n      material.roughness = metallicRoughness.g;\\n      material.metallic = metallicRoughness.b;\\n    }\\n\\n    getTextureLuminanceValue(material.reflectance, ReflectanceTex, ReflectanceTexType, texCoord);\\n#endif // ENABLE_PBR\\n\\n    getTextureLuminanceValue(material.emission, EmissiveStrengthTex, EmissiveStrengthTexType, texCoord);\\n#endif // ENABLE_TEXTURES\\n\\n#ifdef ENABLE_TEXTURES\\n#ifdef ENABLE_PBR\\n    if (NormalTexType != 0) {\\n      mat3 tbn = cotangentFrame(normal, viewVector, texCoord);\\n      normal = normalize(tbn * (texture2D(NormalTex, texCoord).rgb * 2.0 - 1.0));\\n    }\\n#endif // ENABLE_PBR\\n#endif // ENABLE_TEXTURES\\n\\n    if (outlineThickness > 0.00001) {\\n      vec4 edgeColor      = getMaterialValue(materialCoords, 4);\\n      vec4 matValue2      = getMaterialValue(materialCoords, 3);\\n      float opacity       = matValue2.g;\\n\\n      edgeColor.a = edgeColor.a * opacity * treeItemOpacity;\\n      \\n      fragColor = edgeColor;\\n    } else {\\n      \\n      if (testFlag(flags, GEOMITEM_FLAG_CUTAWAY) && !gl_FrontFacing) {\\n        fragColor = vec4(material.baseColor, material.opacity);\\n      }\\n      else if (renderMode == 1) { // Flat\\n        fragColor = vec4(material.baseColor, material.opacity);\\n      } else if (renderMode == 2) { // Shaded\\n        // simple irradiance. \\n        float ndotv = dot(normal, viewVector);\\n        fragColor = vec4((ndotv * material.baseColor) + (material.emission * material.baseColor), material.opacity);\\n      } else if (renderMode == 3) { // PBR\\n        fragColor = pbrSurfaceRadiance(material, normal, viewVector);\\n      }\\n      \\n      // Note: the 'treeItemOpacity' is not an input to the PBR lighting, \\n      // as we want to also blend off the specular reflections to make an object\\n      // fade away to nothing. (not become a transparent glass object).\\n      fragColor.a *= treeItemOpacity;\\n\\n      // Debugging code to help understand what might be happening in the shader.\\n      // fragColor = vec4(texture2D(NormalTex, texCoord).rgb, 1.0);\\n      // fragColor = metallicRoughness;\\n      // fragColor = vec4(material.baseColor, 1.0);;\\n      // fragColor = vec4(vec3(material.metallic), 1.0);;\\n      // fragColor = vec4(vec3(material.roughness), 1.0);;\\n      // fragColor = vec4(vec3(material.ambientOcclusion), 1.0);\\n    }\\n\\n  } // end 'TRIANGLES'\\n  else if (geomType == LINES) { // start 'LINES'\\n    if (occluded == 1) {\\n      vec4 matValue2      = getMaterialValue(materialCoords, 3);\\n      float opacity       = matValue2.g;\\n      fragColor = hiddenLineColor;\\n      fragColor.a = hiddenLineColor.a * opacity * treeItemOpacity;\\n    } else {\\n      vec4 edgeColor;\\n      // Note: if a custom material has been assigned to an edge, we use the base color, not the edge color.\\n      // The ZeaSpatialBridge actually assigns 'LineColor' to the edges, so they only have a 'baseColor'.\\n      \\n      if (materialId == StandardSurfaceShaderId) {\\n        vec4 matValue2      = getMaterialValue(materialCoords, 3);\\n        edgeColor           = getMaterialValue(materialCoords, 4);\\n        float opacity       = matValue2.g;\\n        float edgeWeight    = matValue2.a;\\n        edgeColor.a = edgeColor.a * edgeWeight * opacity * treeItemOpacity;\\n      } else {\\n        vec4 baseColor      = getMaterialValue(materialCoords, 1);\\n        baseColor.a = baseColor.a * treeItemOpacity;\\n        edgeColor = baseColor;\\n      }\\n      fragColor = edgeColor;\\n    }\\n  } // end 'LINES'\\n  else if (geomType == POINTS) { // start 'POINTS'\\n    if (materialId == StandardSurfaceShaderId) {\\n      vec4 matValue2      = getMaterialValue(materialCoords, 3);\\n      vec4 pointColor     = getMaterialValue(materialCoords, 5);\\n      float opacity       = matValue2.g;\\n      pointColor.a = pointColor.a * opacity * treeItemOpacity;\\n      fragColor = pointColor;\\n    } else {\\n      vec4 baseColor      = getMaterialValue(materialCoords, 1);\\n      baseColor.a = baseColor.a * treeItemOpacity;\\n      fragColor = baseColor;\\n    }\\n  }  // end 'POINTS'\\n  \\n#ifdef DEBUG_GEOM_ID\\n  // ///////////////////////\\n  // Debug Draw ID (this correlates to GeomID within a GLGeomSet)\\n  float geomId = v_geomItemData.w;\\n  fragColor.rgb = getDebugColor(geomId);\\n  // ///////////////////////\\n#endif\\n\\n#ifdef ENABLE_INLINE_GAMMACORRECTION\\n  fragColor.rgb = toGamma(fragColor.rgb * exposure);\\n#endif\\n\\n// end DRAW_COLOR\\n#elif defined(DRAW_GEOMDATA)\\n\\n  fragColor = setFragColor_geomData(v_viewPos, v_drawItemIds.x, v_drawItemIds.y, isOrthographic, flags, geomType);\\n   \\n#elif defined(DRAW_HIGHLIGHT)\\n\\n  // we don't render highlighs for non-selectable objects.\\n  if (testFlag(flags, GEOMITEM_INVISIBLE_IN_GEOMDATA)) {\\n    discard;\\n  }\\n\\n  fragColor = getHighlightColor(geomItemId);\\n#endif // DRAW_HIGHLIGHT\\n\\n#ifndef ENABLE_ES3\\n  gl_FragColor = fragColor;\\n#endif\\n\\n}\"; // eslint-disable-line\n\n/* eslint-disable require-jsdoc */\n/** A standard shader handling Opaque and transparent items and PBR rendering.\n * @extends GLShader\n * @private\n */\nclass StandardSurfaceShader extends GLShader {\n    /**\n     * Create a GL shader.\n     * @param gl - The webgl rendering context.\n     */\n    constructor(gl) {\n        super(gl, 'StandardSuraceShader');\n        this.setShaderStage('VERTEX_SHADER', vert$1);\n        this.setShaderStage('FRAGMENT_SHADER', frag$1);\n    }\n    /**\n     * The bind method.\n     * @param renderstate - The object tracking the current state of the renderer\n     * @param key - The key value.\n     * @return - The return value.\n     */\n    bind(renderstate, key) {\n        super.bind(renderstate, key);\n        if (renderstate instanceof ColorRenderState) {\n            const colorRenderState = renderstate;\n            const gl = this.__gl;\n            if (colorRenderState.envMap) {\n                colorRenderState.envMap.bind(colorRenderState);\n            }\n            const { exposure, renderMode } = colorRenderState.unifs;\n            if (exposure) {\n                gl.uniform1f(exposure.location, colorRenderState.exposure);\n            }\n            if (colorRenderState.renderMode && renderMode) {\n                if (colorRenderState.renderMode == 'flat' || colorRenderState.renderMode == 'flat-noedges') {\n                    gl.uniform1i(renderMode.location, 1);\n                }\n                else if (colorRenderState.renderMode == 'shaded' || colorRenderState.renderMode == 'shaded-noedges') {\n                    gl.uniform1i(renderMode.location, 2);\n                }\n                else if (colorRenderState.renderMode == 'pbr' || colorRenderState.renderMode == 'pbr-noedges') {\n                    gl.uniform1i(renderMode.location, 3);\n                }\n            }\n        }\n        return true;\n    }\n    /**\n     * The getPackedMaterialData method.\n     * @param material - The material param.\n     * @return - The return value.\n     */\n    static getPackedMaterialData(material) {\n        const matData = new Float32Array(28);\n        let pixId = 0;\n        matData[pixId * 4 + 0] = 7;\n        const baseColorParam = material.getParameter('BaseColor');\n        let baseColor;\n        if (baseColorParam instanceof MaterialColorParam && baseColorParam.colorSpace == ColorSpace.Gamma) {\n            baseColor = baseColorParam.value.toLinear();\n        }\n        else {\n            baseColor = baseColorParam.value;\n        }\n        pixId++;\n        matData[pixId * 4 + 0] = baseColor.r;\n        matData[pixId * 4 + 1] = baseColor.g;\n        matData[pixId * 4 + 2] = baseColor.b;\n        matData[pixId * 4 + 3] = baseColor.a;\n        pixId++;\n        matData[pixId * 4 + 0] = material.getParameter('AmbientOcclusion').value;\n        matData[pixId * 4 + 1] = material.getParameter('Metallic').value;\n        matData[pixId * 4 + 2] = material.getParameter('Roughness').value;\n        matData[pixId * 4 + 3] = material.getParameter('Reflectance').value;\n        pixId++;\n        matData[pixId * 4 + 0] = material.getParameter('EmissiveStrength').value;\n        matData[pixId * 4 + 1] = material.getParameter('Opacity').value;\n        matData[pixId * 4 + 2] = material.getParameter('Overlay').value;\n        matData[pixId * 4 + 3] = material.getParameter('EdgeWeight').value;\n        pixId++;\n        const edgeColor = material.getParameter('EdgeColor').value;\n        matData[pixId * 4 + 0] = edgeColor.r;\n        matData[pixId * 4 + 1] = edgeColor.g;\n        matData[pixId * 4 + 2] = edgeColor.b;\n        matData[pixId * 4 + 3] = edgeColor.a;\n        pixId++;\n        const pointColor = material.getParameter('PointColor').value;\n        matData[pixId * 4 + 0] = pointColor.r;\n        matData[pixId * 4 + 1] = pointColor.g;\n        matData[pixId * 4 + 2] = pointColor.b;\n        matData[pixId * 4 + 3] = pointColor.a;\n        pixId++;\n        matData[pixId * 4 + 0] = material.getParameter('PointSize').value;\n        return matData;\n    }\n    /**\n     * Each shader provides a template material that each material instance is\n     * based on. The shader specifies the parameters needed by the shader, and\n     * the material provides values to the shader during rendering.\n     * @return - The template material value.\n     */\n    static getMaterialTemplate() {\n        return material$2;\n    }\n}\nconst material$2 = new StandardSurfaceMaterial('StandardSurfaceShader_template');\nRegistry.register('StandardSurfaceShader', StandardSurfaceShader);\nRegistry.register('TransparentSurfaceShader', StandardSurfaceShader);\n\n/* eslint-disable require-jsdoc */\n/** A simple shader with no support for PBR or textures\n * @ignore\n */\nclass VertexColorShader extends GLShader {\n    /**\n     * Create a VertexColorShader\n     * @param gl - gl context\n     */\n    constructor(gl) {\n        super(gl, 'VertexColorShader');\n        this.setShaderStage('VERTEX_SHADER', `precision highp float;\r\n\r\n\r\n    attribute vec3 positions;\r\n    attribute vec3 normals;\r\n    #ifdef ENABLE_TEXTURES\r\n    attribute vec2 texCoords;\r\n    #endif\r\n    attribute vec4 colors;\r\n    \r\n    uniform mat4 viewMatrix;\r\n    uniform mat4 projectionMatrix;\r\n    \r\n    import 'GLSLUtils.glsl'\r\n    import 'transpose.glsl'\r\n    import 'inverse.glsl'\r\n    import 'geomItemId.glsl'\r\n    import 'drawItemTexture.glsl'\r\n    import 'modelMatrix.glsl'\r\n    \r\n    /* VS Outputs */\r\n    varying vec4 v_drawItemIds;\r\n    varying vec4 v_geomItemData;\r\n    varying vec3 v_viewPos;\r\n    varying vec3 v_viewNormal;\r\n    varying vec4 v_vertexColors;\r\n    #ifdef ENABLE_TEXTURES\r\n    varying vec2 v_textureCoord;\r\n    #endif\r\n    varying vec3 v_worldPos;\r\n    \r\n    void main(void) {\r\n      v_drawItemIds = getDrawItemIds();\r\n      int geomItemId = int(round(v_drawItemIds.x));\r\n      v_geomItemData  = getInstanceData(geomItemId);\r\n      v_vertexColors = colors;\r\n      \r\n      mat4 modelMatrix = getModelMatrix(geomItemId);\r\n      mat4 modelViewMatrix = viewMatrix * modelMatrix;\r\n    \r\n      vec4 pos = vec4(positions, 1.);\r\n      vec4 viewPos    = modelViewMatrix * pos;\r\n      gl_Position     = projectionMatrix * viewPos;\r\n    \r\n      mat3 normalMatrix = mat3(transpose(inverse(modelViewMatrix)));\r\n      v_viewPos       = -viewPos.xyz;\r\n      v_viewNormal    = normalMatrix * normals; // Note: we normalize in the fragment shader.\r\n    \r\n    #ifdef ENABLE_TEXTURES\r\n      v_textureCoord  = texCoords;\r\n      // v_textureCoord.y = 1.0 - v_textureCoord.y;// Flip y\r\n    #endif\r\n    \r\n      v_worldPos      = (modelMatrix * pos).xyz;\r\n    }\r\n    `);\n        this.setShaderStage('FRAGMENT_SHADER', `precision highp float;\r\n\r\n    import 'GLSLUtils.glsl'\r\n    import 'drawItemTexture.glsl'\r\n    import 'cutaways.glsl'\r\n    import 'geometryMask.glsl'\r\n    import 'gamma.glsl'\r\n    import 'materialparams.glsl'\r\n    import 'geomItemFlags.glsl'\r\n    \r\n    #ifdef DEBUG_GEOM_ID\r\n    import 'debugColors.glsl'\r\n    #endif\r\n    \r\n    /* VS Outputs */\r\n    varying vec4 v_drawItemIds;\r\n    varying vec4 v_geomItemData;\r\n    varying vec3 v_viewPos;\r\n    varying vec3 v_viewNormal;\r\n    varying vec4 v_vertexColors;\r\n    #ifdef ENABLE_TEXTURES\r\n    varying vec2 v_textureCoord;\r\n    #endif\r\n    varying vec3 v_worldPos;\r\n    /* VS Outputs */\r\n    \r\n    uniform mat4 cameraMatrix;\r\n    uniform int isOrthographic;\r\n    \r\n    #ifdef ENABLE_ES3\r\n        out vec4 fragColor;\r\n    #endif\r\n    \r\n    \r\n    #if defined(DRAW_COLOR)\r\n    \r\n    import 'computeViewNormal.glsl'\r\n      \r\n    // end DRAW_COLOR\r\n    #elif defined(DRAW_GEOMDATA)\r\n      import 'surfaceGeomData.glsl'\r\n    #elif defined(DRAW_HIGHLIGHT)\r\n      import 'surfaceHighlight.glsl'\r\n    #endif // DRAW_HIGHLIGHT\r\n    \r\n    \r\n    void main(void) {\r\n    #ifndef ENABLE_ES3\r\n      vec4 fragColor;\r\n    #endif\r\n      int geomItemId = int(round(v_drawItemIds.x));\r\n      int elemId = int(round(v_drawItemIds.y));\r\n      int perFaceMaterialId = int(round(v_drawItemIds.z));\r\n      int flags = int(round(v_geomItemData.x));\r\n      float treeItemOpacity = v_geomItemData.y;\r\n    \r\n      // We can make geoms invisible to hide them. \r\n      // Avoid drawing GeomData for geoms that are completely transparent.\r\n      if (treeItemOpacity < 0.001) {\r\n        discard;\r\n        return;\r\n      }\r\n      \r\n      // Cutaways\r\n      if (testFlag(flags, GEOMITEM_FLAG_CUTAWAY)) \r\n      {\r\n        vec4 cutAwayData   = getCutaway(geomItemId);\r\n        vec3 planeNormal = cutAwayData.xyz;\r\n        float planeDist = cutAwayData.w;\r\n        if (length(planeNormal) > 0.5) {\r\n          if (cutaway(v_worldPos, planeNormal, planeDist)) {\r\n              discard;\r\n              return;\r\n          }\r\n        } else {\r\n          if (testGeometryMask(v_viewPos)) {\r\n            discard;\r\n            return;\r\n          }\r\n        }\r\n      }\r\n    \r\n    #if defined(DRAW_COLOR)\r\n    \r\n      if (testFlag(flags, GEOMITEM_FLAG_CUTAWAY) && !gl_FrontFacing) {\r\n        fragColor = cutColor;\r\n        return;\r\n      } else {\r\n\r\n        //////////////////////////////////////////////\r\n        // Normals\r\n        \r\n        vec3 viewNormal;\r\n        if (length(v_viewNormal) < 0.1) {\r\n          viewNormal = computeViewNormal(v_viewPos);\r\n        } else {\r\n          viewNormal = normalize(v_viewNormal);\r\n        }\r\n        vec3 normal = normalize(mat3(cameraMatrix) * viewNormal);\r\n        \r\n        vec3 viewVector;\r\n        if (isOrthographic == 0)\r\n          viewVector = normalize(mat3(cameraMatrix) * normalize(v_viewPos));\r\n        else \r\n          viewVector = vec3(-cameraMatrix[2][0], -cameraMatrix[2][1], -cameraMatrix[2][2]);\r\n        \r\n        //////////////////////////////////////////////\r\n        // Material\r\n      \r\n        vec4 baseColor = v_vertexColors;\r\n      \r\n        // Hacky simple irradiance. \r\n        float ndotv = dot(normal, viewVector);\r\n        if (ndotv < 0.0) {\r\n          normal = -normal;\r\n          ndotv = dot(normal, viewVector);\r\n      \r\n          // Note: these 2 lines can be used to debug inverted meshes.\r\n          //baseColor = vec4(1.0, 0.0, 0.0, 1.0);\r\n          //ndotv = 1.0;\r\n        }\r\n\r\n        fragColor = vec4((ndotv * baseColor.rgb), 1.0);\r\n      }\r\n    \r\n      // Note: the 'treeItemOpacity' is not an input to the lighting, \r\n      // as we want to also blend off the specular reflections to make an object\r\n      // fade away to nothing. (not become a transparent glass object).\r\n      fragColor.a *= treeItemOpacity;\r\n    \r\n    \r\n    #ifdef DEBUG_GEOM_ID\r\n      // ///////////////////////\r\n      // Debug Draw ID (this correlates to GeomID within a GLGeomSet)\r\n      float geomId = v_geomItemData.w;\r\n      fragColor.rgb = getDebugColor(geomId);\r\n      // ///////////////////////\r\n    #endif\r\n    \r\n    #ifdef ENABLE_INLINE_GAMMACORRECTION\r\n      fragColor.rgb = toGamma(fragColor.rgb);\r\n    #endif\r\n    \r\n    #elif defined(DRAW_GEOMDATA)\r\n      fragColor = setFragColor_geomData(v_viewPos, v_drawItemIds.x, v_drawItemIds.y, isOrthographic, 0, TRIANGLES);\r\n    #elif defined(DRAW_HIGHLIGHT)\r\n      fragColor = setFragColor_highlight(v_drawItemIds.x);\r\n    #endif // DRAW_HIGHLIGHT\r\n    \r\n    #ifndef ENABLE_ES3\r\n      gl_FragColor = fragColor;\r\n    #endif\r\n    }`);\n    }\n    /**\n     * The bind method.\n     * @param renderstate - The object tracking the current state of the renderer\n     * @param key - The key value.\n     * @return - The return value.\n     */\n    bind(renderstate, key) {\n        super.bind(renderstate, key);\n        if (renderstate instanceof ColorRenderState) {\n            const gl = this.__gl;\n            const { cutColor } = renderstate.unifs;\n            if (cutColor) {\n                gl.uniform4f(cutColor.location, 0.3, 0, 0, 1);\n            }\n        }\n        return true;\n    }\n    /**\n     * Each shader provides a template material that each material instance is\n     * based on. The shader specifies the parameters needed by the shader, and\n     * the material provides values to the shader during rendering.\n     * @return - The template material value.\n     */\n    static getMaterialTemplate() {\n        return material$1;\n    }\n    /**\n     * The supportsInstancing method.\n     * @return - return false for shaders that cannot be rendered in instanced mode.\n     */\n    static supportsInstancing() {\n        return false;\n    }\n}\nconst material$1 = new VertexColorMaterial('VertexColorShader_template');\nRegistry.register('VertexColorShader', VertexColorShader);\n\nvar frag = \"\\nprecision highp float;\\n#define GLSLIFY 1\\n\\nimport 'GLSLUtils.glsl'\\nimport 'drawItemTexture.glsl'\\n\\nimport 'gamma.glsl'\\nimport 'materialparams.glsl'\\nimport 'geomItemFlags.glsl'\\n\\n#if defined(DRAW_COLOR)\\n\\n#ifdef ENABLE_TEXTURES\\nuniform sampler2D BaseColorTex;\\nuniform int BaseColorTexType;\\n#endif\\n\\n#endif // DRAW_COLOR\\n\\n/* VS Outputs */\\nvarying float v_geomItemId;\\nvarying vec4 v_geomItemData;\\n#ifdef ENABLE_TEXTURES\\nvarying vec2 v_textureCoord;\\n#endif\\n\\n#if defined(DRAW_GEOMDATA)\\n  uniform int isOrthographic;\\n  import 'surfaceGeomData.glsl'\\n#elif defined(DRAW_HIGHLIGHT)\\n  import 'surfaceHighlight.glsl'\\n#endif // DRAW_HIGHLIGHT\\n\\n#ifdef ENABLE_ES3\\n  out vec4 fragColor;\\n#endif\\n\\nvoid main(void) {\\n  \\n#ifndef ENABLE_ES3\\n  vec4 fragColor;\\n#endif\\n\\n  //////////////////////////////////////////////\\n  // Color\\n#if defined(DRAW_COLOR)\\n\\n    vec2 materialCoords = v_geomItemData.zw;\\n    vec4 baseColor = getMaterialValue(materialCoords, 0);\\n\\n  #ifdef ENABLE_TEXTURES\\n    getTextureColorValue(baseColor, BaseColorTex, BaseColorTexType, v_textureCoord);\\n  #endif\\n\\n    fragColor = baseColor;\\n\\n  #ifdef ENABLE_INLINE_GAMMACORRECTION\\n    fragColor.rgb = toGamma(fragColor.rgb);\\n  #endif\\n\\n  //////////////////////////////////////////////\\n  // GeomData\\n#elif defined(DRAW_GEOMDATA)\\n  fragColor = setFragColor_geomData(vec3(0,0,0), v_geomItemId, 0.0, isOrthographic, 0, TRIANGLES);\\n#elif defined(DRAW_HIGHLIGHT)\\n  fragColor = setFragColor_highlight(v_geomItemId);\\n#endif // DRAW_HIGHLIGHT\\n\\n#ifndef ENABLE_ES3\\n  gl_FragColor = fragColor;\\n#endif\\n}\\n\"; // eslint-disable-line\n\nvar vert = \"\\nprecision highp float;\\n#define GLSLIFY 1\\n\\nattribute vec3 positions;\\n#ifdef ENABLE_TEXTURES\\nattribute vec2 texCoords;\\n#endif\\n\\nimport 'GLSLUtils.glsl'\\nimport 'geomItemId.glsl'\\nimport 'drawItemTexture.glsl'\\nimport 'modelMatrix.glsl'\\n\\n/* VS Outputs */\\nvarying float v_geomItemId;\\nvarying vec4 v_geomItemData;\\n#ifdef ENABLE_TEXTURES\\nvarying vec2 v_textureCoord;\\n#endif\\n\\nvoid main(void) {\\n  int geomItemId = getGeomItemId();\\n  v_geomItemId = float(geomItemId);\\n  v_geomItemData  = getInstanceData(geomItemId);\\n\\n  mat4 modelMatrix = getModelMatrix(geomItemId);\\n\\n  gl_Position = (modelMatrix * vec4(positions, 1.0));\\n\\n  v_textureCoord = texCoords;\\n  v_textureCoord.y = 1.0 - v_textureCoord.y;// Flip y\\n}\\n\"; // eslint-disable-line\n\nclass ScreenSpaceShader extends GLShader {\n    /**\n     * Create a GL shader.\n     * @param gl - The webgl rendering context.\n     */\n    constructor(gl) {\n        super(gl, 'ScreenSpaceShader');\n        this.setShaderStage('VERTEX_SHADER', vert);\n        this.setShaderStage('FRAGMENT_SHADER', frag);\n    }\n    static isOverlay() {\n        return true;\n    }\n    /**\n     * The getPackedMaterialData method.\n     * @param material - The material param.\n     * @return - The return value.\n     */\n    static getPackedMaterialData(material) {\n        const matData = new Float32Array(8);\n        let pixId = 0;\n        const baseColorParam = material.getParameter('BaseColor');\n        let baseColor;\n        if (baseColorParam instanceof MaterialColorParam && baseColorParam.colorSpace == ColorSpace.Gamma) {\n            baseColor = baseColorParam.value.toLinear();\n        }\n        else {\n            baseColor = baseColorParam.value;\n        }\n        matData[pixId + 0] = baseColor.r;\n        matData[pixId + 1] = baseColor.g;\n        matData[pixId + 2] = baseColor.b;\n        matData[pixId + 3] = baseColor.a;\n        return matData;\n    }\n    /**\n     * Each shader provides a template material that each material instance is\n     * based on. The shader specifies the parameters needed by the shader, and\n     * the material provides values to the shader during rendering.\n     * @return - The template material value.\n     */\n    static getMaterialTemplate() {\n        return material;\n    }\n}\nconst material = new ScreenSpaceMaterial('ScreenSpaceShader_template');\nRegistry.register('ScreenSpaceShader', ScreenSpaceShader);\n\n/** This class abstracts the rendering of a collection of geometries to screen.\n * @extends GLPass\n */\nclass GLStandardGeomsPass extends GLPass {\n    materials = new Map();\n    listenerIDs = new Map();\n    /**\n     * Create a GL pass.\n     */\n    constructor() {\n        super();\n    }\n    /**\n     * The init method.\n     * @param renderer - The renderer value.\n     * @param passIndex - The index of the pass in the GLRenderer\n     */\n    init(renderer, passIndex) {\n        super.init(renderer, passIndex);\n    }\n    /**\n     * The itemAddedToScene method is called on each pass when a new item\n     * is added to the scene, and the renderer must decide how to render it.\n     * It allows Passes to select geometries to handle the drawing of.\n     * @param treeItem - The treeItem value.\n     * @param rargs - Extra return values are passed back in this object.\n     * The object contains a parameter 'continueInSubTree', which can be set to false,\n     * so the subtree of this node will not be traversed after this node is handled.\n     * @return - Returns true if the item is now added to the pass.\n     */\n    itemAddedToScene(treeItem, rargs) {\n        if (treeItem instanceof GeomItem) {\n            const geomItem = treeItem;\n            {\n                {\n                    if (this.filterGeomItem(geomItem)) {\n                        this.addGeomItem(geomItem);\n                        return true;\n                    }\n                    else {\n                        return false;\n                    }\n                }\n            }\n        }\n        else {\n            return false;\n        }\n    }\n    /**\n     * The itemRemovedFromScene method is called on each pass when aa item\n     * is removed to the scene, and the pass must handle cleaning up any resources.\n     * @param treeItem - The treeItem value.\n     * @param rargs - Extra return values are passed back in this object.\n     * @return - The return value.\n     */\n    itemRemovedFromScene(treeItem, rargs) {\n        if (treeItem instanceof GeomItem) {\n            this.removeGeomItem(treeItem);\n            return true;\n        }\n        return false;\n    }\n    /**\n     * The filterGeomItem method.\n     * @param geomItem - The geomItem value.\n     * @return - The return value.\n     */\n    filterGeomItem(geomItem) {\n        return true;\n    }\n    /**\n     * Checks the material to see if it is opaque.\n     * @param material - The geomItem value.\n     * @return - The return value.\n     */\n    checkMaterial(material) {\n        return true;\n    }\n    /**\n     * The addGeomItem method.\n     * @param geomItem - The geomItem value.\n     */\n    addGeomItem(geomItem) {\n        const listenerIDs = {};\n        this.listenerIDs.set(geomItem, listenerIDs);\n        // ////////////////////////////////////\n        // Tracking Material Transparency changes...\n        // In the case that a geometry material changes, we may need to\n        // select a different pass. e.g. if the new material is transparent.\n        const reassignPass = () => {\n            this.removeGeomItem(geomItem);\n            this.renderer.assignTreeItemToGLPass(geomItem);\n        };\n        listenerIDs['materialParam.valueChanged'] = geomItem.materialParam.on('valueChanged', reassignPass);\n        listenerIDs['geomParam.valueChanged'] = geomItem.geomParam.on('valueChanged', reassignPass);\n        const opacityChanged = (event) => {\n            if (event.isOpaqueStateChanged) {\n                reassignPass();\n            }\n        };\n        const material = geomItem.materialParam.value;\n        this.materials.set(geomItem, material);\n        listenerIDs['geomItem.opacityChanged'] = geomItem.on('opacityChanged', opacityChanged);\n        listenerIDs['material.opacityChanged'] = material.on('opacityChanged', opacityChanged);\n    }\n    /**\n     * The removeGeomItem method.\n     * @param geomItem - The geomItem value.\n     */\n    removeGeomItem(geomItem) {\n        const listenerIDs = this.listenerIDs.get(geomItem);\n        this.listenerIDs.delete(geomItem);\n        geomItem.materialParam.off('valueChanged', listenerIDs['materialParam.valueChanged']);\n        geomItem.geomParam.off('valueChanged', listenerIDs['geomParam.valueChanged']);\n        const material = this.materials.get(geomItem);\n        this.materials.delete(geomItem);\n        geomItem.off('opacityChanged', listenerIDs['geomItem.opacityChanged']);\n        material.off('opacityChanged', listenerIDs['material.opacityChanged']);\n    }\n    /**\n     * The constructShader method.\n     * Given a material, generate the various shaders required to render objects\n     * using this material. There should always be at least a single glShader\n     * and optionally a glgeomdatashader for rendering the goem data buffer\n     * and a glselectedshader for rendering selection hilghlights\n     * @param shaderName - The name of the base shader.\n     * @return - The object containing the shader instances.\n     */\n    constructShader(shaderName) {\n        const glShader = this.__renderer.getOrCreateShader(shaderName);\n        return glShader;\n    }\n    /**\n     * The getGeomItemAndDist method.\n     * @param geomData - The geomData value.\n     * @return - The return value.\n     */\n    getGeomItemAndDist(geomData) {\n        let itemId;\n        let componentId = -1;\n        let dist;\n        if (geomData instanceof Float32Array) {\n            itemId = Math.round(geomData[1]);\n            componentId = Math.round(geomData[2]);\n            dist = geomData[3];\n        }\n        else {\n            itemId = geomData[0] + ((geomData[1] & 63) << 8);\n            dist = MathFunctions.decode16BitFloatFrom2xUInt8(geomData.slice(2, 3));\n        }\n        const geomItem = this.renderer.glGeomItemLibrary.getGeomItem(itemId);\n        if (geomItem) {\n            return {\n                geomItem,\n                componentId,\n                dist,\n            };\n        }\n        return undefined;\n    }\n}\n\n/** Class representing a GL opaque geoms pass.\n * @extends GLStandardGeomsPass\n * @private\n */\nclass GLOpaqueGeomsPass extends GLStandardGeomsPass {\n    glShaderMaterials = new Map();\n    glShaderGeomSets = new Map();\n    /**\n     * Create a GL opaque geoms pass.\n     */\n    constructor() {\n        super();\n        // Optimized Render Tree\n        // Structured like so for efficient render traversial.\n        // {GLShaders}[GLMaterials][GLGeoms][GLGeomItems]\n    }\n    /**\n     * Returns the pass type. OPAQUE passes are always rendered first, followed by TRANSPARENT passes, and finally OVERLAY.\n     * @return - The pass type value.\n     */\n    getPassType() {\n        return PassType.OPAQUE;\n    }\n    // ///////////////////////////////////\n    // Bind to Render Tree\n    /**\n     * The filterGeomItem method.\n     * @param geomItem - The geomItem value.\n     * @return - The return value.\n     */\n    filterGeomItem(geomItem) {\n        const material = geomItem.materialParam.value;\n        return geomItem.isOpaque() && material.isOpaque();\n    }\n    /**\n     * Checks the material to see if it is opaque.\n     * @param material - The geomItem value.\n     * @return - The return value.\n     */\n    checkMaterial(material) {\n        return material.isOpaque();\n    }\n    /**\n     * Removes the GeomITem from this pass, and then asks the renderer to re-add it.\n     * @param geomItem - The geomItem value.\n     */\n    removeAndReAddGeomItem(geomItem) {\n        this.removeGeomItem(geomItem);\n        this.__renderer.assignTreeItemToGLPass(geomItem);\n    }\n    /**\n     * The addGeomItem method.\n     * @param geomItem - The geomItem value.\n     * @return - The return value.\n     */\n    addGeomItem(geomItem) {\n        super.addGeomItem(geomItem);\n        const materialParam = geomItem.materialParam;\n        const material = materialParam.value;\n        const glGeomItem = this.renderer.glGeomItemLibrary.getGLGeomItem(geomItem);\n        const gl = this.__gl;\n        if (gl.multiDrawElementsInstanced && glGeomItem.supportInstancing && !material.isTextured()) {\n            this.addGeomItemToMultiDraw(geomItem, glGeomItem);\n        }\n        else {\n            this.addGeomItemToConventionalDraw(geomItem, glGeomItem);\n        }\n    }\n    addGeomItemToMultiDraw(geomItem, glGeomItem) {\n        const materialParam = geomItem.materialParam;\n        const material = materialParam.value;\n        const shaderName = material.getShaderName();\n        const shader = this.__renderer.getOrCreateShader(shaderName);\n        let glShaderGeomSets = this.glShaderGeomSets.get(shader);\n        if (!glShaderGeomSets) {\n            glShaderGeomSets = new GLShaderGeomSets(this.__renderer, this.__gl, shader);\n            glShaderGeomSets.on('updated', () => {\n                this.__renderer.requestRedraw();\n            });\n            this.glShaderGeomSets.set(shader, glShaderGeomSets);\n        }\n        glShaderGeomSets.addGLGeomItem(glGeomItem);\n        glGeomItem.GLShaderGeomSets = glShaderGeomSets;\n        this.emit('updated');\n    }\n    addGeomItemToConventionalDraw(geomItem, glGeomItem) {\n        const materialParam = geomItem.materialParam;\n        const material = materialParam.value;\n        const glGeomLibrary = this.renderer.glGeomLibrary;\n        const glGeom = glGeomLibrary.constructGLGeom(geomItem.geomParam.value);\n        // ////////////////////////////////////\n        // Shaders\n        const shaderName = material.getShaderName();\n        const glMaterial = this.renderer.glMaterialLibrary.getGLMaterial(material);\n        const glShader = glMaterial.glShader;\n        let glShaderMaterials = this.glShaderMaterials.get(glShader);\n        if (!glShaderMaterials) {\n            const shader = this.constructShader(shaderName);\n            glShaderMaterials = new GLShaderMaterials(this.__gl, this, shader);\n            this.glShaderMaterials.set(glShader, glShaderMaterials);\n            glShaderMaterials.on('updated', () => {\n                this.__renderer.requestRedraw();\n            });\n        }\n        glShaderMaterials.addGLGeomItem(glGeomItem, glGeom, glMaterial);\n        return;\n    }\n    /**\n     * The removeGeomItem method.\n     * @param geomItem - The geomItem value.\n     * @return - The return value.\n     */\n    removeGeomItem(geomItem) {\n        super.removeGeomItem(geomItem);\n        const glGeomItem = this.renderer.glGeomItemLibrary.getGLGeomItem(geomItem);\n        if (glGeomItem.GLShaderGeomSets) {\n            const glShaderGeomSets = glGeomItem.GLShaderGeomSets;\n            glShaderGeomSets.removeGLGeomItem(glGeomItem);\n            glGeomItem.GLShaderGeomSets = null;\n            return;\n        }\n        if (glGeomItem.GLGeomItemSet) {\n            const glGeomItemSet = glGeomItem.GLGeomItemSet;\n            glGeomItemSet.removeGLGeomItem(glGeomItem);\n            glGeomItem.GLGeomItemSet = null;\n            return;\n        }\n        return;\n    }\n    /**\n     * The removeMaterial method.\n     * @param material - The material value.\n     */\n    removeMaterial(material) {\n        const glMaterial = this.renderer.glMaterialLibrary.getGLMaterial(material);\n        const glShader = glMaterial.glShader;\n        const glShaderMaterials = this.glShaderMaterials.get(glShader);\n        glShaderMaterials.removeMaterialGeomItemSets(glMaterial);\n    }\n    /**\n     * The traverseTreeAndDraw method.\n     * @param renderstate - The renderstate value.\n     * @private\n     */\n    traverseTreeAndDraw(renderstate) {\n        // eslint-disable-next-line guard-for-in\n        this.glShaderGeomSets.forEach((glShaderGeomSet) => {\n            glShaderGeomSet.draw(renderstate);\n        });\n        this.glShaderMaterials.forEach((glShaderMaterials) => {\n            glShaderMaterials.draw(renderstate);\n        });\n        if (renderstate.glGeom) {\n            renderstate.glGeom.unbind(renderstate);\n        }\n    }\n    /**\n     * The draw method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    draw(renderstate) {\n        const gl = this.__gl;\n        renderstate.pushGLStack('GLOpaqueGeomsPass.drawGeomData');\n        renderstate.glDisable(gl.BLEND);\n        renderstate.glEnable(gl.DEPTH_TEST);\n        // gl.disable(gl.BLEND)\n        // Note: our zcad files can contain surfaces with flipped normals.\n        // This is due to re-using geoms on various sides of a mesh, while applying\n        // a -1 scale on one of the axes to flip. We need 2-sided rendering enabled\n        // by default.\n        {\n            // 2-sided rendering.\n            // gl.disable(gl.CULL_FACE)\n            renderstate.glDisable(gl.CULL_FACE);\n        }\n        // gl.enable(gl.DEPTH_TEST)\n        gl.depthFunc(gl.LEQUAL);\n        gl.depthMask(true);\n        this.traverseTreeAndDraw(renderstate);\n        const renderer = this.renderer;\n        if (renderer.outlineThickness > 0 && renderer.outlineMethod == 'image') {\n            renderstate.viewport.drawSilhouettes(renderstate);\n        }\n        renderstate.popGLStack();\n    }\n    /**\n     * The drawHighlightedGeoms method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    drawHighlightedGeoms(renderstate) {\n        const gl = this.__gl;\n        gl.disable(gl.CULL_FACE); // 2-sided rendering.\n        this.glShaderGeomSets.forEach((glShaderGeomSet) => {\n            glShaderGeomSet.drawHighlightedGeoms(renderstate);\n        });\n        this.glShaderMaterials.forEach((glShaderMaterials) => {\n            glShaderMaterials.drawHighlightedGeoms(renderstate);\n        });\n        if (renderstate.glGeom) {\n            renderstate.glGeom.unbind(renderstate);\n        }\n    }\n    /**\n     * The drawGeomData method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    drawGeomData(renderstate) {\n        renderstate.passIndex = this.passIndex;\n        const gl = this.__gl;\n        gl.disable(gl.BLEND);\n        gl.disable(gl.CULL_FACE);\n        gl.enable(gl.DEPTH_TEST);\n        gl.depthFunc(gl.LEQUAL);\n        gl.depthMask(true);\n        this.glShaderGeomSets.forEach((glShaderGeomSet) => {\n            glShaderGeomSet.drawGeomData(renderstate);\n        });\n        this.glShaderMaterials.forEach((glShaderMaterials) => {\n            glShaderMaterials.drawGeomData(renderstate);\n        });\n        if (renderstate.glGeom) {\n            renderstate.glGeom.unbind(renderstate);\n        }\n    }\n}\nGLRenderer.registerPass(GLOpaqueGeomsPass, PassType.OPAQUE);\n\n/** Class representing a GL opaque geoms pass.\n * @extends GLOpaqueGeomsPass\n * @private\n */\nclass GLLinesPass extends GLOpaqueGeomsPass {\n    linesGeomDataBuffer = null;\n    fattenLinesShader = null;\n    quad = null;\n    fbo = null;\n    /**\n     * Create a GL opaque geoms pass.\n     */\n    constructor() {\n        super();\n    }\n    /**\n     * The init method.\n     * @param renderer - The renderer value.\n     * @param passIndex - The index of the pass in the GLBAseRenderer\n     */\n    init(renderer, passIndex) {\n        super.init(renderer, passIndex);\n    }\n    /**\n     * The filterGeomItem method.\n     * @param geomItem - The geomItem value.\n     * @return - The return value.\n     */\n    filterGeomItem(geomItem) {\n        const geom = geomItem.geomParam.value;\n        if (geom instanceof Lines || geom instanceof LinesProxy || geom instanceof Points || geom instanceof PointsProxy) {\n            return true;\n        }\n        return false;\n    }\n    /**\n     * The draw method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    draw(renderstate) {\n        const gl = this.__gl;\n        renderstate.pushGLStack('GLLinesPass.draw');\n        renderstate.glEnable(gl.BLEND);\n        renderstate.glEnable(gl.DEPTH_TEST);\n        // gl.enable(gl.BLEND)\n        // gl.enable(gl.DEPTH_TEST)\n        gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE);\n        gl.depthFunc(gl.LEQUAL);\n        gl.depthMask(true);\n        this.traverseTreeAndDraw(renderstate);\n        // gl.disable(gl.BLEND)\n        renderstate.popGLStack();\n    }\n    /**\n     * The drawGeomData method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    drawGeomData(renderstate) {\n        const gl = this.__gl;\n        //  Note: lines in VR are not fattened...\n        if (renderstate.geomDataFbo && !renderstate.occlusionCulling) {\n            renderstate.pushGLStack('GLLinesPass.drawGeomData');\n            if (!this.linesGeomDataBuffer) {\n                this.linesGeomDataBuffer = new GLTexture2D(gl, {\n                    type: this.__renderer.floatGeomBuffer ? 'FLOAT' : 'UNSIGNED_BYTE',\n                    format: 'RGBA',\n                    filter: 'NEAREST',\n                    width: 1,\n                    height: 2,\n                });\n                this.fattenLinesShader = new FattenLinesShader(gl);\n                this.quad = new GLMesh(gl, new Plane(1, 1));\n            }\n            const geomDataFbo = renderstate.geomDataFbo;\n            const width = geomDataFbo.width;\n            const height = geomDataFbo.height;\n            if (this.linesGeomDataBuffer.width != width || this.linesGeomDataBuffer.height != height) {\n                if (this.fbo) {\n                    gl.deleteFramebuffer(this.fbo);\n                    this.fbo = null;\n                }\n                this.linesGeomDataBuffer.resize(width, height);\n                this.fbo = gl.createFramebuffer();\n                const colorTex = this.linesGeomDataBuffer.glTex;\n                const depthBuffer = geomDataFbo.depthTexture; // Share the existing depth buffer.\n                gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, this.fbo);\n                gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, colorTex, 0);\n                gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, depthBuffer, 0);\n                checkFramebuffer(gl, width, height);\n            }\n            else {\n                gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, this.fbo);\n            }\n            gl.colorMask(true, true, true, true);\n            gl.clearColor(0, 0, 0, 0);\n            gl.clear(gl.COLOR_BUFFER_BIT);\n        }\n        super.drawGeomData(renderstate);\n        if (renderstate.geomDataFbo && !renderstate.occlusionCulling) {\n            renderstate.popGLStack();\n            // Re-bind the FBo.\n            // Note: bindForWriting tries to cache the previously bound Fbo, which is actually\n            // the geomDataFbo. So we need to null here to avoid that.\n            // I did work on making the renderstate track the bound Fbo, so it would do it more\n            // elegantly than this, but it was a big change.\n            renderstate.boundRendertarget = null;\n            renderstate.geomDataFbo.bindForWriting(renderstate);\n            this.fattenLinesShader.bind(renderstate);\n            const { colorTexture, screenSize, pointAndLinePickingSize } = renderstate.unifs;\n            this.linesGeomDataBuffer.bindToUniform(renderstate, colorTexture);\n            gl.uniform1i(pointAndLinePickingSize.location, renderstate.pointAndLinePickingSize);\n            const geomDataFbo = renderstate.geomDataFbo;\n            gl.uniform2f(screenSize.location, geomDataFbo.width, geomDataFbo.height);\n            this.quad.bindAndDraw(renderstate);\n        }\n    }\n}\nGLRenderer.registerPass(GLLinesPass, PassType.OPAQUE);\n\n/** Class representing a GL transparent geoms pass.\n * @extends GLStandardGeomsPass\n * @private\n */\nclass GLTransparentGeomsPass extends GLStandardGeomsPass {\n    itemCount = 0;\n    glShaderGeomSets = {}; // GLShaderGeomSets\n    transparentItems = [];\n    transparentItemIndices = new Map();\n    freeList = [];\n    visibleItems = [];\n    prevSortCameraPos = new Vec3(999, 999, 999);\n    sortCameraMovementDistance = 0.25; // meters\n    reSort = false;\n    /**\n     * Create GL transparent geoms pass.\n     */\n    constructor() {\n        super();\n    }\n    /**\n     * The init method.\n     * @param renderer - The renderer value.\n     * @param passIndex - The index of the pass in the GLBAseRenderer\n     */\n    init(renderer, passIndex) {\n        super.init(renderer, passIndex);\n    }\n    /**\n     * Returns the pass type. OPAQUE passes are always rendered first, followed by TRANSPARENT passes, and finally OVERLAY.\n     * @return - The pass type value.\n     */\n    getPassType() {\n        return PassType.TRANSPARENT;\n    }\n    /**\n     * The init method.\n     * @param geomItem - The geomItem value.\n     * @return - The return value.\n     */\n    filterGeomItem(geomItem) {\n        const geom = geomItem.geomParam.value;\n        if (geom instanceof Lines || geom instanceof Points || geom instanceof PointsProxy || geom instanceof LinesProxy)\n            return false;\n        const material = geomItem.materialParam.value;\n        return !geomItem.isOpaque() || !material.isOpaque();\n    }\n    /**\n     * When an item visibility changes, we trigger this method, as new items become visible\n     */\n    resortNeeded() {\n        this.reSort = true;\n    }\n    /**\n     * The addGeomItem method.\n     * @param geomItem - The geomItem value.\n     */\n    addGeomItem(geomItem) {\n        super.addGeomItem(geomItem);\n        this.itemCount++;\n        const listenerIDs = this.listenerIDs.get(geomItem);\n        const material = geomItem.materialParam.value;\n        const shaderName = material.getShaderName();\n        const glShader = this.constructShader(shaderName);\n        if (!material.isTextured()) {\n            if (material.getShaderClass().supportsInstancing()) {\n                let glShaderGeomSets = this.glShaderGeomSets[shaderName];\n                if (!glShaderGeomSets) {\n                    glShaderGeomSets = new GLShaderGeomSets(this.__renderer, this.__gl, glShader);\n                    glShaderGeomSets.on('updated', () => {\n                        this.renderer.requestRedraw();\n                    });\n                    this.glShaderGeomSets[shaderName] = glShaderGeomSets;\n                }\n                const glGeomItem = this.renderer.glGeomItemLibrary.getGLGeomItem(geomItem);\n                glShaderGeomSets.addGLGeomItem(glGeomItem);\n                listenerIDs['glGeomItem.visibilityChanged'] = glGeomItem.on('visibilityChanged', () => {\n                    this.resortNeeded();\n                });\n                this.emit('updated');\n                glGeomItem.GLShaderGeomSets = glShaderGeomSets;\n                // force a reSort.\n                this.reSort = true;\n                return;\n            }\n        }\n        const glGeom = this.renderer.glGeomLibrary.constructGLGeom(geomItem.geomParam.value);\n        // const glGeomItem = this.constructGLGeomItem(geomItem)\n        const glGeomItem = this.renderer.glGeomItemLibrary.getGLGeomItem(geomItem);\n        if (!glGeomItem)\n            throw new Error('glGeomItem not found for geomItem:' + geomItem.getName());\n        // @todo - make sure we remove materials and GeomItems from the base pass.\n        // This code will leak memory for these classes as we are not cleaning them up.\n        const glMaterial = this.renderer.glMaterialLibrary.getGLMaterial(material);\n        // ////////////////////////////////////\n        // Tracking visibility changes.\n        const visibilityChanged = (event) => {\n            if (event.state) {\n                this.visibleItems.push(item);\n            }\n            else {\n                const index = this.visibleItems.indexOf(item);\n                this.visibleItems.splice(index, 1);\n            }\n            this.reSort = true;\n        };\n        listenerIDs['glGeomItem.visibilityChanged'] = glGeomItem.on('visibilityChanged', visibilityChanged);\n        // ////////////////////////////////////\n        // Tracking GeomMat changes.\n        listenerIDs['GeomMat.valueChanged'] = geomItem.geomMatParam.on('valueChanged', () => {\n            this.reSort = true;\n        });\n        const item = {\n            geomItem,\n            glShader,\n            glGeom,\n            glMaterial,\n            glGeomItem,\n            material,\n            dist: 0,\n        };\n        let itemindex;\n        if (this.freeList.length > 0)\n            itemindex = this.freeList.pop();\n        else\n            itemindex = this.transparentItems.length;\n        this.transparentItems[itemindex] = item;\n        this.transparentItemIndices.set(geomItem, itemindex);\n        if (geomItem.isVisible()) {\n            this.visibleItems.push(item);\n        }\n        // force a reSort.\n        this.reSort = true;\n    }\n    /**\n     * The removeGeomItem method.\n     * @param geomItem - The geomItem value.\n     */\n    removeGeomItem(geomItem) {\n        this.itemCount--;\n        const listenerIDs = this.listenerIDs.get(geomItem);\n        super.removeGeomItem(geomItem);\n        const glGeomItem = this.renderer.glGeomItemLibrary.getGLGeomItem(geomItem);\n        if (!glGeomItem)\n            throw new Error('glGeomItem not found for geomItem:' + geomItem.getName());\n        glGeomItem.off('visibilityChanged', listenerIDs['glGeomItem.visibilityChanged']);\n        if (glGeomItem.GLShaderGeomSets) {\n            const glShaderGeomSets = glGeomItem.GLShaderGeomSets;\n            glShaderGeomSets.removeGLGeomItem(glGeomItem);\n            glGeomItem.GLShaderGeomSets = null;\n        }\n        else {\n            const itemindex = this.transparentItemIndices.get(geomItem);\n            const item = this.transparentItems[itemindex];\n            this.transparentItemIndices.delete(geomItem);\n            this.transparentItems[itemindex] = null;\n            this.freeList.push(itemindex);\n            const visibleindex = this.visibleItems.indexOf(item);\n            if (visibleindex != -1)\n                this.visibleItems.splice(visibleindex, 1);\n        }\n        this.emit('updated');\n        return true;\n    }\n    /**\n     * Sorts the drawn items in order furthest to nearest when rendering transparent objects.\n     * @param viewPos - The position of the camera that we are sorting relative to.\n     */\n    sortItems(viewPos) {\n        // eslint-disable-next-line guard-for-in\n        for (const shaderName in this.glShaderGeomSets) {\n            this.glShaderGeomSets[shaderName].sortItems(viewPos);\n        }\n        for (const transparentItem of this.visibleItems) {\n            const mat4 = transparentItem.glGeomItem.geomItem.geomMatParam.value;\n            transparentItem.dist = mat4.translation.distanceTo(viewPos);\n        }\n        this.visibleItems.sort((a, b) => (a.dist > b.dist ? -1 : a.dist < b.dist ? 1 : 0));\n        this.reSort = false;\n    }\n    /**\n     * Draw n individual item, binding the shader and material if necessary.\n     * @param renderstate - current renderstad\n     * @param transparentItem - current item to render\n     * @param cache - cache tracking which material/shader is currently bound.\n     */\n    drawItem(renderstate, transparentItem, cache) {\n        if (cache.currentGLMaterial != transparentItem.glMaterial) {\n            cache.currentGLMaterial = transparentItem.glMaterial;\n            cache.currentGLMaterial.bind(renderstate, false);\n        }\n        if (cache.currentGLGeom != transparentItem.glGeom) {\n            cache.currentGLGeom = transparentItem.glGeom;\n            cache.currentGLGeom.bind(renderstate);\n        }\n        const glGeomItem = transparentItem.glGeomItem;\n        glGeomItem.bind(renderstate);\n        renderstate.bindViewports(renderstate.unifs, () => {\n            cache.currentGLGeom.draw(renderstate);\n        });\n    }\n    /**\n     * The _drawItems method.\n     * @param renderstate - The object tracking the current state of the renderer\n     * @private\n     */\n    _drawItems(renderstate) {\n        // Note: sorting here will not sort geometries of different types.\n        // this is a flawed solution that only sorts geomemtries of the same\n        // time and same shader against each other. Given that this is the data 99% o\n        // of the time, this is an acceptable tradeoff\n        // eslint-disable-next-line guard-for-in\n        for (const shaderName in this.glShaderGeomSets) {\n            this.glShaderGeomSets[shaderName].draw(renderstate);\n        }\n        const cache = {\n            currentglShader: null,\n            currentGLMaterial: null,\n            currentGLGeom: null,\n        };\n        for (const transparentItem of this.visibleItems) {\n            const glShader = transparentItem.glShader;\n            if (cache.currentglShader != glShader) {\n                // Some passes, like the depth pass, bind custom uniforms.\n                // Note: No 'unbind' here before binding the next shader.\n                // That is to support a simple hack. LinesShader enables blend\n                // each time it is bound, and then disables on unbind.\n                if (!glShader.bind(renderstate, 'color')) {\n                    continue;\n                }\n                // Specify an non-instanced draw to the shader\n                const gl = this.__gl;\n                const unifs = renderstate.unifs;\n                if (unifs.instancedDraw) {\n                    gl.uniform1i(unifs.instancedDraw.location, 0);\n                }\n                // Note: this disables the attribute location, which must be enabled again for\n                // the next geom, which might use a different attribute location.\n                // e.g.\n                // one shader might specify attributes ['positions', 'instancedIds]\n                // another  might specify attributes ['positions', 'texCoords' 'instancedIds]\n                // In this case, we should re-enabled location 2 and then disable 3.\n                // if (renderstate.attrs.instancedIds && renderstate.attrs.instancedIds.location != -1) {\n                //   gl.disableVertexAttribArray(renderstate.attrs.instancedIds.location)\n                // }\n                this.renderer.glGeomItemLibrary.bind(renderstate);\n                this.renderer.glGeomLibrary.bind(renderstate);\n                this.renderer.glMaterialLibrary.bind(renderstate);\n                cache.currentglShader = glShader;\n            }\n            this.drawItem(renderstate, transparentItem, cache);\n        }\n        if (cache.currentglShader)\n            cache.currentglShader.unbind(renderstate);\n        // if (cache.currentGLGeom) cache.currentGLGeom.unbind(renderstate)\n    }\n    /**\n     * The draw method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    draw(renderstate) {\n        if (this.itemCount == 0)\n            return;\n        const gl = this.__gl;\n        const viewPos = renderstate.viewXfo.tr;\n        // Avoid sorting if the camera did not move more than the specified tolerance.\n        if (this.reSort || viewPos.distanceTo(this.prevSortCameraPos) > this.sortCameraMovementDistance) {\n            this.sortItems(viewPos);\n            this.prevSortCameraPos = viewPos;\n            if (renderstate.xrviewport) {\n                // Adapt the sort tolerance to the focal distance.\n                // In a tiny scene, we want to sort more frequently.\n                this.sortCameraMovementDistance = renderstate.viewScale * 0.2;\n            }\n            else if (renderstate.viewport) {\n                // Adapt the sort tolerance to the focal distance.\n                // In a tiny scene, we want to sort more frequently.\n                const camera = renderstate.viewport.getCamera(); // TODO: check if this cast is correct.\n                this.sortCameraMovementDistance = camera.getFocalDistance() * 0.3;\n            }\n        }\n        renderstate.pushGLStack('GLTransparentGeomsPass.draw');\n        renderstate.glEnable(gl.BLEND);\n        renderstate.glEnable(gl.DEPTH_TEST);\n        renderstate.glEnable(gl.CULL_FACE);\n        // gl.enable(gl.DEPTH_TEST)\n        // gl.enable(gl.BLEND)\n        gl.depthFunc(gl.LESS);\n        gl.blendEquation(gl.FUNC_ADD);\n        // Complex transparent surfaces require multiple passes.\n        // First the multiply pass tints the background color, simulating\n        // light passing through the surface, and then the add layer\n        // adds new color to the backbuffer to simulate light bouncing off\n        // the surface.\n        // TODO: Optimise this system.\n        // After depth sorting, we should split the items into 2 groups.\n        // Multiply items, and Add  items. (Many items will be in both)\n        // Then we can simply check if we have any multiply items here\n        // before rendering all items.\n        // for Multiply pass, we can use front and back surfaces to calculate depth and how much\n        // of the background layer to let through.\n        // gl.disable(gl.CULL_FACE)\n        // gl.blendFunc(gl.DST_COLOR, gl.ZERO) // For multiply, select this.\n        // this._drawItems(renderstate)\n        // for the Add\n        renderstate.pass = 'ADD';\n        // https://google.github.io/filament/Filament.html#lighting/transparencyandtranslucencylighting/transparency\n        gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE);\n        // Only draw font faces. BEcause all faces are drawn, it can make a mess to see the back faces through the front faces.\n        // e.g. we might see the triangles on the other side of a sphere rendered over the top of triangles on the near side.\n        // gl.enable(gl.CULL_FACE)\n        gl.cullFace(gl.BACK);\n        this._drawItems(renderstate);\n        // gl.disable(gl.BLEND)\n        // gl.depthMask(true)\n        renderstate.popGLStack();\n    }\n    /**\n     * The drawHighlightedGeoms method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    drawHighlightedGeoms(renderstate) {\n        const gl = this.__gl;\n        gl.disable(gl.CULL_FACE); // 2-sided rendering.\n        // eslint-disable-next-line guard-for-in\n        for (const shaderName in this.glShaderGeomSets) {\n            this.glShaderGeomSets[shaderName].drawHighlightedGeoms(renderstate);\n        }\n        const cache = {\n            currentglShader: null,\n            currentGLMaterial: null,\n            currentGLGeom: null,\n        };\n        for (const transparentItem of this.visibleItems) {\n            if (!transparentItem.geomItem.isHighlighted())\n                continue;\n            const glShader = transparentItem.glShader;\n            if (cache.currentglShader != glShader) {\n                // Some passes, like the depth pass, bind custom uniforms.\n                if (!glShader.bind(renderstate, 'highlight')) {\n                    continue;\n                }\n                cache.currentglShader = glShader;\n                const { floatGeomBuffer, passId, instancedDraw } = renderstate.unifs;\n                if (floatGeomBuffer) {\n                    gl.uniform1i(floatGeomBuffer.location, gl.floatGeomBuffer ? 1 : 0);\n                }\n                if (passId) {\n                    gl.uniform1i(passId.location, this.passIndex);\n                }\n                if (instancedDraw) {\n                    gl.uniform1i(instancedDraw.location, 0);\n                }\n                this.renderer.glGeomItemLibrary.bind(renderstate);\n            }\n            this.drawItem(renderstate, transparentItem, cache);\n        }\n        if (cache.currentglShader)\n            cache.currentglShader.unbind(renderstate);\n        if (cache.currentGLGeom)\n            cache.currentGLGeom.unbind(renderstate);\n    }\n    /**\n     * The drawGeomData method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    drawGeomData(renderstate) {\n        const gl = this.__gl;\n        renderstate.pushGLStack('GLTransparentGeomsPass.drawGeomData');\n        renderstate.glEnable(gl.DEPTH_TEST);\n        renderstate.glEnable(gl.CULL_FACE);\n        // eslint-disable-next-line guard-for-in\n        for (const shaderName in this.glShaderGeomSets) {\n            this.glShaderGeomSets[shaderName].drawGeomData(renderstate);\n        }\n        const cache = {\n            currentglShader: null,\n            currentGLMaterial: null,\n            currentGLGeom: null,\n        };\n        for (const transparentItem of this.visibleItems) {\n            if (!transparentItem.glGeomItem.geomItem.isPickable())\n                continue;\n            const glShader = transparentItem.glShader;\n            if (!glShader) {\n                continue;\n            }\n            if (cache.currentglShader != glShader) {\n                // Some passes, like the depth pass, bind custom uniforms.\n                if (!glShader.bind(renderstate, 'geomdata')) {\n                    continue;\n                }\n                cache.currentglShader = glShader;\n                const { floatGeomBuffer, passId, instancedDraw } = renderstate.unifs;\n                if (floatGeomBuffer) {\n                    gl.uniform1i(floatGeomBuffer.location, gl.floatGeomBuffer ? 1 : 0);\n                }\n                if (passId) {\n                    gl.uniform1i(passId.location, this.passIndex);\n                }\n                if (instancedDraw) {\n                    gl.uniform1i(instancedDraw.location, 0);\n                }\n                this.renderer.glGeomItemLibrary.bind(renderstate);\n            }\n            this.drawItem(renderstate, transparentItem, cache);\n        }\n        if (cache.currentGLGeom)\n            cache.currentGLGeom.unbind(renderstate);\n        if (cache.currentglShader)\n            cache.currentglShader.unbind(renderstate);\n        renderstate.popGLStack();\n    }\n}\nGLRenderer.registerPass(GLTransparentGeomsPass, PassType.TRANSPARENT);\n\nconst pixelsPerItem = 7; // The number of pixels per draw item.\nconst ALIGN_TO_CAMERA_FLAG = 1 << 2;\nconst ALIGN_TO_CAMERA_AND_AXIS_FLAG = 1 << 3;\nconst DRAW_ON_TOP_FLAG = 1 << 4;\nconst FIXED_SIZE_ON_SCREEN_FLAG = 1 << 5;\nconst FRONT_FACING_FLAG = 1 << 6;\n/** Class representing a GL billboards pass.\n * @extends GLPass\n * @private\n */\nclass GLBillboardsPass extends GLPass {\n    billboards = [];\n    billboardIndices = new Map();\n    dirtyBillboards = new Set();\n    freeIndices = [];\n    drawCount = 0;\n    threshold = 0;\n    prevSortCameraPos = new Vec3();\n    atlas = null;\n    indexArrayUpdateNeeded = false;\n    instanceIdsBuffer = null;\n    indexArray = new Float32Array(0);\n    glshader = null;\n    shaderBinding = null;\n    modelMatrixArray = [];\n    billboardDataArray = [];\n    tintColorArray = [];\n    drawItemsTexture = null;\n    /**\n     * Create a GL billboards pass.\n     */\n    constructor() {\n        super();\n    }\n    /**\n     * The init method.\n     * @param renderer - The renderer value.\n     * @param passIndex - The index of the pass in the GLBAseRenderer\n     */\n    init(renderer, passIndex) {\n        super.init(renderer, passIndex);\n        const gl = this.renderer.gl;\n        this.atlas = new GLImageAtlas(gl, gl.RGBA, gl.UNSIGNED_BYTE);\n        const emitUpdated = () => this.emit('updated');\n        this.atlas.on('loaded', emitUpdated);\n        this.atlas.on('updated', emitUpdated);\n    }\n    /**\n     * Returns the pass type. OPAQUE passes are always rendered first, followed by TRANSPARENT passes, and finally OVERLAY.\n     * @return - The pass type value.\n     */\n    getPassType() {\n        return PassType.TRANSPARENT;\n    }\n    /**\n     * The itemAddedToScene method is called on each pass when a new item\n     * is added to the scene, and the renderer must decide how to render it.\n     * It allows Passes to select geometries to handle the drawing of.\n     * @param treeItem - The treeItem value.\n     * @param rargs - Extra return values are passed back in this object.\n     * The object contains a parameter 'continueInSubTree', which can be set to false,\n     * so the subtree of this node will not be traversed after this node is handled.\n     * @return - The return value.\n     */\n    itemAddedToScene(treeItem, rargs) {\n        if (treeItem instanceof BillboardItem) {\n            this.addBillboard(treeItem);\n            return true;\n        }\n        return false;\n    }\n    /**\n     * The itemRemovedFromScene method is called on each pass when aa item\n     * is removed to the scene, and the pass must handle cleaning up any resources.\n     * @param treeItem - The treeItem value.\n     * @param rargs - Extra return values are passed back in this object.\n     * @return - The return value.\n     */\n    itemRemovedFromScene(treeItem, rargs) {\n        if (treeItem instanceof BillboardItem) {\n            this.removeBillboard(treeItem);\n            return true;\n        }\n        return false;\n    }\n    // ///////////////////////////////////\n    // Bind to Render Tree\n    /**\n     * The addBillboard method.\n     * @param billboard - The billboard value.\n     */\n    addBillboard(billboard) {\n        const imageParam = billboard.imageParam;\n        const image = imageParam.value;\n        if (!image) {\n            imageParam.on('valueChanged', () => this.addBillboard(billboard));\n            return;\n        }\n        let index;\n        if (this.freeIndices.length > 0)\n            index = this.freeIndices.pop();\n        else\n            index = this.billboards.length;\n        const imageIndex = this.atlas.addSubImage(image);\n        this.billboardIndices.set(billboard, index);\n        const visibilityChanged = () => {\n            if (billboard.isVisible()) {\n                this.drawCount++;\n                // The billboard Xfo might have changed while it was\n                // not visible. We need to update here.\n                this.dirtyBillboards.add(index);\n            }\n            else\n                this.drawCount--;\n            this.reqUpdateIndexArray();\n        };\n        billboard.on('visibilityChanged', visibilityChanged);\n        const updateBillboard = () => {\n            if (billboard.isVisible()) {\n                this.dirtyBillboards.add(index);\n                this.emit('updated');\n            }\n        };\n        billboard.on('parameterValueChanged', updateBillboard);\n        billboard.on('highlightChanged', updateBillboard);\n        if (billboard.isVisible())\n            this.drawCount++;\n        this.billboards[index] = {\n            billboard,\n            imageIndex,\n            dist: 0,\n            visibilityChanged,\n            updateBillboard,\n        };\n        this.dirtyBillboards.add(index);\n        this.indexArrayUpdateNeeded = true;\n        this.emit('updated');\n    }\n    /**\n     * The removeBillboard method.\n     * @param billboard - The billboard value.\n     */\n    removeBillboard(billboard) {\n        const index = this.billboardIndices.get(billboard);\n        if (index == -1) {\n            console.warn('Billboard already removed.');\n            return;\n        }\n        const billboardData = this.billboards[index];\n        const image = billboardData.billboard.imageParam.value;\n        this.atlas.removeSubImage(image);\n        billboard.off('visibilityChanged', billboardData.visibilityChanged);\n        billboard.off('highlightChanged', billboardData.updateBillboard);\n        billboard.off('parameterValueChanged', billboardData.updateBillboard);\n        if (billboard.isVisible())\n            this.drawCount--;\n        this.billboards[index] = null;\n        this.billboardIndices.delete(billboard);\n        this.freeIndices.push(index);\n        if (this.dirtyBillboards.has(index)) {\n            this.dirtyBillboards.delete(index);\n        }\n        this.indexArrayUpdateNeeded = true;\n        this.emit('updated');\n    }\n    /**\n     * The populateBillboardDataArray method.\n     * @param billboardData - The billboardData value.\n     * @param index - The index value.\n     * @param dataArray - The dataArray value.\n     */\n    populateBillboardDataArray(billboardData, index, dataArray) {\n        const billboard = billboardData.billboard;\n        const mat4 = billboard.globalXfoParam.value.toMat4();\n        const ppm = billboard.pixelsPerMeterParam.value;\n        const pivot = billboard.pivotParam.value;\n        const scale = 1 / ppm;\n        // Until webgl2 is standard, we will avoid using bit flags.\n        // instead, we will use decimals.\n        let flags = 0;\n        switch (billboard.alignmentParam.value) {\n            case 0: //'AlignedToWorld':\n                break;\n            case 1: //'AlignedToCamera':\n                flags |= ALIGN_TO_CAMERA_FLAG;\n                break;\n            case 2: //'AlignedToCameraAndXAxis':\n                flags |= ALIGN_TO_CAMERA_AND_AXIS_FLAG;\n                break;\n        }\n        if (billboard.drawOnTopParam.value)\n            flags |= DRAW_ON_TOP_FLAG;\n        if (billboard.fixedSizeOnscreenParam.value)\n            flags |= FIXED_SIZE_ON_SCREEN_FLAG;\n        if (billboard.frontFacingParam.value)\n            flags |= FRONT_FACING_FLAG;\n        const alpha = billboard.alphaParam.value;\n        const color = billboard.colorParam.value;\n        const offset = index * pixelsPerItem * 4;\n        const col0 = new Float32Array(dataArray.buffer, offset * 4, 4);\n        const col1 = new Float32Array(dataArray.buffer, (offset + 4) * 4, 4);\n        const col2 = new Float32Array(dataArray.buffer, (offset + 8) * 4, 4);\n        const col3 = new Float32Array(dataArray.buffer, (offset + 12) * 4, 4);\n        col0.set([mat4.xAxis.x, mat4.yAxis.x, mat4.zAxis.x, mat4.translation.x]);\n        col1.set([mat4.xAxis.y, mat4.yAxis.y, mat4.zAxis.y, mat4.translation.y]);\n        col2.set([mat4.xAxis.z, mat4.yAxis.z, mat4.zAxis.z, mat4.translation.z]);\n        col3.set([scale, flags, billboardData.imageIndex, alpha]);\n        const col4 = new Float32Array(dataArray.buffer, (offset + 16) * 4, 4);\n        col4.set([pivot.x, pivot.y, 0, 0]);\n        const col5 = new Float32Array(dataArray.buffer, (offset + 20) * 4, 4);\n        col5.set([color.r, color.g, color.b, color.a]);\n        // /////////////////////////\n        // Highlight\n        if (billboard.isHighlighted()) {\n            const highlight = billboard.getHighlight();\n            const col6 = new Float32Array(dataArray.buffer, (offset + 24) * 4, 4);\n            col6.set([highlight.r, highlight.g, highlight.b, highlight.a]);\n        }\n    }\n    reqUpdateIndexArray() {\n        if (this.indexArrayUpdateNeeded)\n            return;\n        this.indexArrayUpdateNeeded = true;\n        this.emit('updated');\n    }\n    updateIndexArray() {\n        const gl = this.__gl;\n        // Note: When the camera moves, this array is sorted and re-upload.\n        if (this.indexArray && this.indexArray.length != this.drawCount) {\n            gl.deleteBuffer(this.instanceIdsBuffer);\n            this.instanceIdsBuffer = null;\n        }\n        this.indexArray = new Float32Array(this.drawCount);\n        let offset = 0;\n        for (let i = 0; i < this.billboards.length; i++) {\n            if (this.billboards[i] && this.billboards[i].billboard.isVisible()) {\n                this.indexArray[offset] = i;\n                offset++;\n            }\n        }\n        if (!this.instanceIdsBuffer)\n            this.instanceIdsBuffer = gl.createBuffer();\n        gl.bindBuffer(gl.ARRAY_BUFFER, this.instanceIdsBuffer);\n        gl.bufferData(gl.ARRAY_BUFFER, this.indexArray, gl.STATIC_DRAW);\n        this.indexArrayUpdateNeeded = false;\n    }\n    /**\n     * The updateBillboards method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    updateBillboards(renderstate) {\n        const dirtyBillboards = new Set(this.dirtyBillboards);\n        this.dirtyBillboards.clear();\n        const doIt = () => {\n            if (this.indexArrayUpdateNeeded)\n                this.updateIndexArray();\n            const gl = this.__gl;\n            if (!this.glshader) {\n                if (!gl.__quadVertexIdsBuffer) {\n                    gl.setupInstancedQuad();\n                }\n                this.glshader = new BillboardShader(gl);\n                const shaderComp = this.glshader.compileForTarget('GLBillboardsPass', renderstate.directives);\n                this.shaderBinding = generateShaderGeomBinding(gl, shaderComp.attrs, gl.__quadattrbuffers, gl.__quadIndexBuffer);\n            }\n            if (this.atlas.needsUpdate) {\n                this.atlas.renderAtlas();\n            }\n            if (!gl.floatTexturesSupported || !gl.drawElementsInstanced) {\n                this.modelMatrixArray = [];\n                this.billboardDataArray = [];\n                this.tintColorArray = [];\n                dirtyBillboards.forEach((index) => {\n                    // if (index == -1) return;\n                    const billboardData = this.billboards[index];\n                    const billboard = billboardData.billboard;\n                    const mat4 = billboard.globalXfoParam.value.toMat4();\n                    const ppm = billboard.pixelsPerMeterParam.value;\n                    const scale = 1 / ppm;\n                    let flags = 0;\n                    switch (billboard.alignmentParam.value) {\n                        case 0: //'AlignedToWorld':\n                            break;\n                        case 1: //'AlignedToCamera':\n                            flags |= ALIGN_TO_CAMERA_FLAG;\n                            break;\n                        case 2: //'AlignedToCameraAndXAxis':\n                            flags |= ALIGN_TO_CAMERA_AND_AXIS_FLAG;\n                            break;\n                    }\n                    if (billboard.drawOnTopParam.value)\n                        flags |= 1 << 3;\n                    if (billboard.fixedSizeOnscreenParam.value)\n                        flags |= 1 << 4;\n                    const alpha = billboard.alphaParam.value;\n                    const color = billboard.colorParam.value;\n                    this.modelMatrixArray[index] = mat4.asArray();\n                    this.billboardDataArray[index] = [scale, flags, billboardData.imageIndex, alpha];\n                    this.tintColorArray[index] = [color.r, color.g, color.b, color.a];\n                });\n                return;\n            }\n            let size = Math.ceil(Math.sqrt(this.billboards.length * pixelsPerItem));\n            // Note: the following few lines need a cleanup.\n            // We should be using power of 2 textures. The problem is that pot texture sizes don't\n            // align with the 6 pixels per draw item. So we need to upload a slightly bigger texture\n            // but upload the 'usable' size.\n            // Only support power 2 textures. Else we get strange corruption on some GPUs\n            // in some scenes.\n            // Size should be a multiple of pixelsPerItem, so each geom item is always contiguous\n            // in memory. (makes updating a lot easier. See updateBillboard below)\n            // size = Math.nextPow2(size);\n            if (size % pixelsPerItem != 0)\n                size += pixelsPerItem - (size % pixelsPerItem);\n            if (!this.drawItemsTexture) {\n                const params = {\n                    format: gl.RGBA,\n                    type: gl.FLOAT,\n                    width: size,\n                    height: size,\n                    filter: gl.NEAREST,\n                    wrap: gl.CLAMP_TO_EDGE,\n                    mipMapped: false,\n                };\n                this.drawItemsTexture = new GLTexture2D(gl, params);\n                this.drawItemsTexture.clear();\n            }\n            else if (this.drawItemsTexture.width != size) {\n                this.drawItemsTexture.resize(size, size);\n                this.billboards.forEach((billboardData, index) => {\n                    this.dirtyBillboards.add(index);\n                });\n            }\n            dirtyBillboards.forEach((index) => {\n                this.updateBillboard(index);\n            });\n        };\n        if (this.atlas.isLoaded()) {\n            doIt();\n        }\n        else {\n            this.atlas.on('loaded', doIt);\n        }\n    }\n    /**\n     * The updateBillboard method.\n     * @param index - The index of the Billboard to update .\n     */\n    updateBillboard(index) {\n        if (!this.billboards[index]) {\n            // console.warn('Billboard is being updated after it was removed from the scene.')\n            return;\n        }\n        const billboardData = this.billboards[index];\n        if (!billboardData.billboard.isVisible())\n            return;\n        const gl = this.__gl;\n        const dataArray = new Float32Array(pixelsPerItem * 4);\n        this.populateBillboardDataArray(billboardData, 0, dataArray);\n        gl.bindTexture(gl.TEXTURE_2D, this.drawItemsTexture.glTex);\n        const xoffset = (index * pixelsPerItem) % this.drawItemsTexture.width;\n        const yoffset = Math.floor((index * pixelsPerItem) / this.drawItemsTexture.width);\n        const width = pixelsPerItem;\n        const height = 1;\n        const type = this.drawItemsTexture.type;\n        const format = this.drawItemsTexture.format;\n        if (type == gl.FLOAT) {\n            gl.texSubImage2D(gl.TEXTURE_2D, 0, xoffset, yoffset, width, height, format, type, dataArray);\n        }\n        else {\n            const unit16s = MathFunctions.convertFloat32ArrayToUInt16Array(dataArray);\n            gl.texSubImage2D(gl.TEXTURE_2D, 0, xoffset, yoffset, width, height, format, type, unit16s);\n        }\n    }\n    /**\n     * The sort method.\n     * @param cameraPos - The cameraPos value.\n     */\n    sort(cameraPos) {\n        for (const billboardData of this.billboards) {\n            if (!billboardData)\n                continue;\n            const { billboard } = billboardData;\n            if (billboard && billboard.isVisible()) {\n                const xfo = billboard.globalXfoParam.value;\n                billboardData.dist = xfo.tr.distanceTo(cameraPos);\n            }\n        }\n        this.indexArray.sort((a, b) => {\n            if (a == -1)\n                return 1;\n            if (b == -1)\n                return -1;\n            return this.billboards[a].dist > this.billboards[b].dist\n                ? -1\n                : this.billboards[a].dist < this.billboards[b].dist\n                    ? 1\n                    : 0;\n        });\n        const gl = this.__gl;\n        if (gl.floatTexturesSupported && this.instanceIdsBuffer) {\n            gl.bindBuffer(gl.ARRAY_BUFFER, this.instanceIdsBuffer);\n            gl.bufferData(gl.ARRAY_BUFFER, this.indexArray, gl.STATIC_DRAW);\n        }\n    }\n    /**\n     * Invoke the drawing of each item, compiling the shader using the provided key.\n     * @param renderstate - The object tracking the current state of the renderer\n     * @param key - The key to cache the compiler results against.\n     */\n    __draw(renderstate, key) {\n        const gl = this.__gl;\n        if (!this.glshader)\n            return;\n        this.glshader.bind(renderstate, key);\n        this.shaderBinding.bind(renderstate);\n        const unifs = renderstate.unifs;\n        const { atlasBillboards, passId, floatGeomBuffer, inVR } = renderstate.unifs;\n        if (atlasBillboards) {\n            this.atlas.bindToUniform(renderstate, atlasBillboards);\n        }\n        if (floatGeomBuffer && renderstate instanceof GeomDataRenderState) {\n            gl.uniform1i(floatGeomBuffer.location, renderstate.floatGeomBuffer ? 1 : 0);\n        }\n        if (passId) {\n            gl.uniform1i(passId.location, this.passIndex);\n        }\n        if (inVR) {\n            gl.uniform1i(inVR.location, renderstate.vrPresenting ? 1 : 0);\n        }\n        if (!gl.floatTexturesSupported || !gl.drawElementsInstanced) {\n            const { modelMatrix, billboardData, tintColor, layoutData } = renderstate.unifs;\n            const len = this.indexArray.length;\n            for (let i = 0; i < len; i++) {\n                gl.uniformMatrix4fv(modelMatrix.location, false, this.modelMatrixArray[i]);\n                gl.uniform4fv(billboardData.location, this.billboardDataArray[i]);\n                gl.uniform4fv(tintColor.location, this.tintColorArray[i]);\n                gl.uniform4fv(layoutData.location, this.atlas.getLayoutData(this.billboards[i].imageIndex));\n                renderstate.bindViewports(unifs, () => {\n                    gl.drawQuad();\n                });\n            }\n        }\n        else {\n            const { instancesTexture, instancesTextureSize } = renderstate.unifs;\n            this.drawItemsTexture.bindToUniform(renderstate, instancesTexture);\n            gl.uniform1i(instancesTextureSize.location, this.drawItemsTexture.width);\n            {\n                // The instance billboard ids are bound as an instanced attribute.\n                const location = renderstate.attrs.instanceIds.location;\n                gl.enableVertexAttribArray(location);\n                gl.bindBuffer(gl.ARRAY_BUFFER, this.instanceIdsBuffer);\n                gl.vertexAttribPointer(location, 1, gl.FLOAT, false, 4, 0);\n                gl.vertexAttribDivisor(location, 1); // This makes it instanced\n            }\n            renderstate.bindViewports(unifs, () => {\n                gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, this.drawCount);\n            });\n        }\n    }\n    /**\n     * The sort method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    draw(renderstate) {\n        if (this.drawCount == 0)\n            return;\n        if (this.dirtyBillboards.size > 0) {\n            this.updateBillboards(renderstate);\n        }\n        // Note: renderGeomDataFbo would have bound other shaders.\n        // and the renderstate used above is no longer valid. Reset.\n        // const screenQuad = this.__renderer.screenQuad!\n        // screenQuad.bindShader(renderstate)\n        // screenQuad.draw(renderstate, this.atlas.textureTargets[0])\n        // return\n        if (this.indexArrayUpdateNeeded)\n            this.updateIndexArray();\n        if (!this.glshader)\n            return;\n        const cameraPos = renderstate.viewXfo.tr;\n        const dist = cameraPos.distanceTo(this.prevSortCameraPos);\n        // Avoid sorting if the camera did not move more than 3 meters.\n        if (dist > this.threshold) {\n            this.sort(cameraPos);\n            this.prevSortCameraPos = cameraPos.clone();\n            if (this.drawCount > 1) {\n                const idx0 = this.indexArray[this.indexArray.length - 1];\n                const idx1 = this.indexArray[this.indexArray.length - 2];\n                const billboard0 = this.billboards[idx0].billboard;\n                const billboard1 = this.billboards[idx1].billboard;\n                const tr0 = billboard0.globalXfoParam.value.tr;\n                const tr1 = billboard1.globalXfoParam.value.tr;\n                this.threshold = tr0.distanceTo(tr1);\n            }\n            else {\n                this.threshold = 9999;\n            }\n        }\n        const gl = this.__gl;\n        gl.depthMask(false);\n        gl.disable(gl.CULL_FACE);\n        gl.enable(gl.BLEND);\n        gl.blendEquation(gl.FUNC_ADD);\n        gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE);\n        this.__draw(renderstate, 'DRAW_COLOR');\n        gl.disable(gl.BLEND);\n        gl.depthMask(true);\n    }\n    /**\n     * The drawHighlightedGeoms method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    drawHighlightedGeoms(renderstate) {\n        if (this.drawCount == 0)\n            return;\n        this.__draw(renderstate, 'DRAW_HIGHLIGHT');\n    }\n    /**\n     * The drawGeomData method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    drawGeomData(renderstate) {\n        if (this.drawCount == 0)\n            return;\n        this.__draw(renderstate, 'DRAW_GEOMDATA');\n    }\n    /**\n     * The getGeomItemAndDist method.\n     * @param geomData - The geomData value.\n     * @return - The return value.\n     */\n    getGeomItemAndDist(geomData) {\n        let itemId;\n        let dist;\n        if (geomData instanceof Float32Array) {\n            itemId = Math.round(geomData[1]);\n            dist = geomData[3];\n        }\n        else {\n            itemId = geomData[0] + ((geomData[1] & 63) << 8);\n            dist = MathFunctions.decode16BitFloatFrom2xUInt8(geomData.slice(2, 3));\n        }\n        if (itemId >= this.billboards.length) {\n            console.warn('Invalid Draw Item id:' + itemId + ' NumBillboards:' + (this.billboards.length - 1));\n            return undefined;\n        }\n        return {\n            geomItem: this.billboards[itemId].billboard,\n            componentId: 0,\n            dist,\n        };\n    }\n}\nGLRenderer.registerPass(GLBillboardsPass, PassType.TRANSPARENT);\n\n/** Class representing a GL overlay pass.\n * @extends GLOpaqueGeomsPass\n */\nclass GLOverlayPass extends GLOpaqueGeomsPass {\n    /**\n     * Create a GL overlay pass.\n     * @param name - The name value.\n     */\n    constructor() {\n        super();\n    }\n    /**\n     * Returns the pass type. OPAQUE passes are always rendered first, followed by TRANSPARENT passes, and finally OVERLAY.\n     * @return - The pass type value.\n     */\n    getPassType() {\n        return PassType.OVERLAY;\n    }\n    // ///////////////////////////////////\n    // Bind to Render Tree\n    /**\n     * The filterGeomItem method.\n     * @param geomItem - The geomItem value.\n     * @return - The return value.\n     */\n    filterGeomItem(geomItem) {\n        if (geomItem.isOverlay())\n            return true;\n        const shaderClass = geomItem.materialParam.value.getShaderClass();\n        if (shaderClass) {\n            if (shaderClass.isOverlay())\n                return true;\n        }\n        return false;\n    }\n    /**\n     * The draw method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    draw(renderstate) {\n        const gl = this.__gl;\n        // Clear the depth buffer so handls are always drawn over the top.\n        gl.clear(gl.DEPTH_BUFFER_BIT);\n        {\n            gl.enable(gl.CULL_FACE);\n            gl.cullFace(gl.BACK);\n        }\n        gl.enable(gl.BLEND);\n        gl.blendEquation(gl.FUNC_ADD);\n        renderstate.pass = 'ADD';\n        gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE); // For add\n        this.traverseTreeAndDraw(renderstate);\n        gl.disable(gl.BLEND);\n        // gl.enable(gl.DEPTH_TEST);\n    }\n    /**\n     * The drawGeomData method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    drawGeomData(renderstate) {\n        const gl = this.__gl;\n        // Clear the depth buffer so handls are always drawn over the top.\n        gl.clear(gl.DEPTH_BUFFER_BIT);\n        gl.enable(gl.CULL_FACE);\n        gl.cullFace(gl.BACK);\n        gl.enable(gl.BLEND);\n        gl.blendEquation(gl.FUNC_ADD);\n        renderstate.pass = 'ADD';\n        gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE); // For add\n        super.drawGeomData(renderstate);\n        gl.disable(gl.BLEND);\n        gl.enable(gl.DEPTH_TEST);\n    }\n}\nGLRenderer.registerPass(GLOverlayPass, PassType.OVERLAY);\n// We register the overlay pass here so that the GLViewport can\n// find it in the GLRebderer,\n// Note: We can't simply import the class into the GLViewpoirt as that\n// is a circular import.\nRegistry.register('GLOverlayPass', GLOverlayPass);\n\n/** Class representing a GL treeItems pass.\n * @extends GLPass\n * @private\n */\nclass GLBoundingBoxPass extends GLPass {\n    boxes = [];\n    dirtyBoxes = new Set();\n    freeIndices = [];\n    idToIndex = new Map();\n    drawCount = 0;\n    indexArrayUpdateNeeded = false;\n    __updateRequested = false;\n    glgeom;\n    glshader;\n    __modelMatrixArray = [];\n    __treeItemDataArray = [];\n    __tintColorArray = [];\n    __instanceIdsBuffer;\n    __indexArray = new Float32Array(0);\n    __drawItemsTexture;\n    width = 0;\n    /**\n     * Create a GL treeItems pass.\n     */\n    constructor() {\n        super();\n    }\n    /**\n     * The getPassType method.\n     * @return - The pass type value.\n     */\n    getPassType() {\n        return PassType.OPAQUE;\n    }\n    /**\n     * The init method.\n     * @param renderer - The renderer value.\n     * @param passIndex - The index of the pass in the GLBAseRenderer\n     */\n    init(renderer, passIndex) {\n        super.init(renderer, passIndex);\n        const gl = this.__renderer.gl;\n        this.glgeom = new GLLines(gl, new LinesCuboid(1, 1, 1));\n        this.glshader = new BoundingBoxShader(gl);\n    }\n    /**\n     * The itemAddedToScene method is called on each pass when a new item\n     * is added to the scene, and the renderer must decide how to render it.\n     * It allows Passes to select geometries to handle the drawing of.\n     * @param treeItem - The treeItem value.\n     * @param rargs - Extra return values are passed back in this object.\n     * The object contains a parameter 'continueInSubTree', which can be set to false,\n     * so the subtree of this node will not be traversed after this node is handled.\n     * @return - The return value.\n     */\n    itemAddedToScene(treeItem, rargs) {\n        // if (treeItem instanceof TreeItem) {\n        //   this.bindTreeItem(treeItem)\n        //   return false\n        // }\n        return false;\n    }\n    /**\n     * The itemRemovedFromScene method is called on each pass when aa item\n     * is removed to the scene, and the pass must handle cleaning up any resources.\n     * @param treeItem - The treeItem value.\n     * @param rargs - Extra return values are passed back in this object.\n     * @return - The return value.\n     */\n    itemRemovedFromScene(treeItem, rargs) {\n        // if (treeItem instanceof TreeItem) {\n        //   this.unbindTreeItem(treeItem)\n        //   return true\n        // }\n        return false;\n    }\n    // ///////////////////////////////////\n    // Bind to Render Tree\n    /**\n     * Adds tree items to the renderer, selecting the correct pass to delegate rendering too, and listens to future changes in the tree.\n     *\n     * @param treeItem - The tree item to add.\n     */\n    addTreeItem(treeItem, continueIntoSubTree = true) {\n        // Note: we can have BaseItems in the tree now.\n        if (!(treeItem instanceof TreeItem))\n            return;\n        this.bindTreeItem(treeItem);\n        if (continueIntoSubTree) {\n            // Traverse the tree adding items until we hit the leaves (which are usually GeomItems.)\n            for (const childItem of treeItem.getChildren()) {\n                if (childItem)\n                    this.addTreeItem(childItem);\n            }\n            treeItem.on('childAdded', (event) => {\n                this.addTreeItem(event.childItem);\n            });\n            treeItem.on('childRemoved', (event) => {\n                this.unbindTreeItem(event.childItem);\n            });\n        }\n    }\n    /**\n     * The bindTreeItem method.\n     * @param treeItem - The treeItem value.\n     */\n    bindTreeItem(treeItem) {\n        let index;\n        let index_check = this.freeIndices.pop();\n        if (index_check)\n            index = index_check;\n        else\n            index = this.boxes.length;\n        this.idToIndex.set(treeItem, index);\n        const visibilityChanged = () => {\n            if (treeItem.isVisible()) {\n                this.drawCount++;\n                // The treeItem Xfo might have changed while it was\n                // not visible. We need to update here.\n                this.dirtyBoxes.add(index);\n            }\n            else\n                this.drawCount--;\n            this.indexArrayUpdateNeeded = true;\n        };\n        treeItem.on('visibilityChanged', visibilityChanged);\n        const xfoChanged = () => {\n            if (treeItem.isVisible()) {\n                this.dirtyBoxes.add(index);\n                this.emit('updated');\n            }\n        };\n        treeItem.globalXfoParam.on('valueChanged', xfoChanged);\n        treeItem.boundingBoxParam.on('valueChanged', xfoChanged);\n        if (treeItem.isVisible())\n            this.drawCount++;\n        // TODO: make this a type\n        this.boxes[index] = {\n            treeItem,\n            visibilityChanged,\n            xfoChanged,\n        };\n        this.indexArrayUpdateNeeded = true;\n        this.__updateRequested = true;\n        this.emit('updated');\n    }\n    /**\n     * The unbindTreeItem method.\n     * @param treeItem - The treeItem value.\n     */\n    unbindTreeItem(treeItem) {\n        if (!this.idToIndex.has(treeItem)) {\n            console.warn('Billboard already removed.');\n            return;\n        }\n        const index = this.idToIndex.get(treeItem);\n        const treeItemData = this.boxes[index];\n        treeItem.off('visibilityChanged', treeItemData.visibilityChanged);\n        treeItem.globalXfoParam.off('valueChanged', treeItemData.xfoChanged);\n        treeItem.boundingBoxParam.off('valueChanged', treeItemData.xfoChanged);\n        this.boxes[index] = null;\n        this.freeIndices.push(index);\n        if (treeItem.isVisible())\n            this.drawCount--;\n        this.indexArrayUpdateNeeded = true;\n        this.__updateRequested = true;\n        this.__updateBoxes();\n        this.emit('updated');\n    }\n    /**\n     * The __populateBoxesDataArray method.\n     * @param treeItemData - The treeItemData value.\n     * @param index - The index value.\n     * @param dataArray - The dataArray value.\n     * @private\n     */\n    __populateBoxesDataArray(treeItemData, index, dataArray) {\n        const treeItem = treeItemData.treeItem;\n        let color;\n        let mat4;\n        if (treeItem instanceof GeomItem) {\n            color = new Color(1, 0, 0, 1);\n            mat4 = treeItem.geomMatParam.value;\n        }\n        else {\n            color = new Color(0, 0, 1, 1);\n            mat4 = treeItem.globalXfoParam.value.toMat4();\n        }\n        const bbox = treeItem.boundingBoxParam.value;\n        const offset = index * pixelsPerItem$1 * 4;\n        const pixel0 = new Float32Array(dataArray.buffer, offset * 4, 4);\n        const pixel1 = new Float32Array(dataArray.buffer, (offset + 4) * 4, 4);\n        const pixel2 = new Float32Array(dataArray.buffer, (offset + 8) * 4, 4);\n        const pixel3 = new Float32Array(dataArray.buffer, (offset + 12) * 4, 4);\n        const pixel4 = new Float32Array(dataArray.buffer, (offset + 16) * 4, 4);\n        // const pixel5 = new Float32Array(dataArray.buffer, (offset + 20) * 4, 4)\n        const pixel6 = new Float32Array(dataArray.buffer, (offset + 24) * 4, 4);\n        const pixel7 = new Float32Array(dataArray.buffer, (offset + 28) * 4, 4);\n        let flags = 0;\n        pixel0.set([flags, 0, 0, 0]);\n        pixel1.set([mat4.xAxis.x, mat4.yAxis.x, mat4.zAxis.x, mat4.translation.x]);\n        pixel2.set([mat4.xAxis.y, mat4.yAxis.y, mat4.zAxis.y, mat4.translation.y]);\n        pixel3.set([mat4.xAxis.z, mat4.yAxis.z, mat4.zAxis.z, mat4.translation.z]);\n        pixel4.set([color.r, color.g, color.b, color.a]);\n        pixel6.set([bbox.p0.x, bbox.p0.y, bbox.p0.z, 0.0]);\n        pixel7.set([bbox.p1.x, bbox.p1.y, bbox.p1.z, 0.0]);\n    }\n    // eslint-disable-next-line require-jsdoc\n    __updateIndexArray() {\n        const gl = this.__gl;\n        // Note: When the camera moves, this array is sorted and re-upload.\n        if (this.__indexArray && this.__indexArray.length != this.drawCount) {\n            gl.deleteBuffer(this.__instanceIdsBuffer);\n            this.__instanceIdsBuffer = undefined;\n        }\n        this.__indexArray = new Float32Array(this.drawCount);\n        let offset = 0;\n        for (let i = 0; i < this.boxes.length; i++) {\n            if (this.boxes[i] && this.boxes[i].treeItem.isVisible()) {\n                this.__indexArray[offset] = i;\n                offset++;\n            }\n        }\n        if (!this.__instanceIdsBuffer)\n            this.__instanceIdsBuffer = gl.createBuffer();\n        gl.bindBuffer(gl.ARRAY_BUFFER, this.__instanceIdsBuffer);\n        gl.bufferData(gl.ARRAY_BUFFER, this.__indexArray, gl.STATIC_DRAW);\n        this.indexArrayUpdateNeeded = false;\n    }\n    /**\n     * The __updateBoxes method.\n     * @private\n     */\n    __updateBoxes() {\n        if (this.indexArrayUpdateNeeded)\n            this.__updateIndexArray();\n        const gl = this.__renderer.gl;\n        let size = Math.round(Math.sqrt((this.boxes.length - this.freeIndices.length) * pixelsPerItem$1) + 0.5);\n        // Note: the following few lines need a cleanup.\n        // We should be using power of 2 textures. The problem is that pot texture sizes don't\n        // align with the 6 pixels per draw item. So we need to upload a slightly bigger texture\n        // but upload the 'usable' size.\n        // Only support power 2 textures. Else we get strange corruption on some GPUs\n        // in some scenes.\n        // Size should be a multiple of pixelsPerItem, so each geom item is always contiguous\n        // in memory. (makes updating a lot easier. See __updateItemInstanceData below)\n        // size = Math.nextPow2(size);\n        if (size % pixelsPerItem$1 != 0)\n            size += pixelsPerItem$1 - (size % pixelsPerItem$1);\n        this.width = size;\n        // if((this.width % pixelsPerItem) != 0)\n        //     this.width -= (this.width % pixelsPerItem);\n        if (!this.__drawItemsTexture) {\n            this.__drawItemsTexture = new GLTexture2D(gl, {\n                format: 'RGBA',\n                type: 'FLOAT',\n                width: size,\n                height: size,\n                filter: 'NEAREST',\n                wrap: 'CLAMP_TO_EDGE',\n                mipMapped: false,\n            });\n            this.__drawItemsTexture.clear();\n        }\n        else {\n            this.__drawItemsTexture.resize(size, size);\n        }\n        this.__indexArray.forEach((index) => {\n            if (index != -1)\n                this.__updateBox(index);\n        });\n        this.__updateRequested = false;\n    }\n    /**\n     * The __updateBoxes method.\n     * @param index - The index value.\n     * @private\n     */\n    __updateBox(index) {\n        if (this.drawCount == 0 || !this.__drawItemsTexture) {\n            return;\n        }\n        const treeItemData = this.boxes[index];\n        if (!treeItemData.treeItem.isVisible())\n            return;\n        const gl = this.__gl;\n        const dataArray = new Float32Array(pixelsPerItem$1 * 4);\n        this.__populateBoxesDataArray(treeItemData, 0, dataArray);\n        gl.bindTexture(gl.TEXTURE_2D, this.__drawItemsTexture.glTex);\n        const xoffset = (index * pixelsPerItem$1) % this.width;\n        const yoffset = Math.floor((index * pixelsPerItem$1) / this.width);\n        const width = pixelsPerItem$1;\n        const height = 1;\n        const type = this.__drawItemsTexture.type;\n        const format = this.__drawItemsTexture.format;\n        if (type == gl.FLOAT) {\n            gl.texSubImage2D(gl.TEXTURE_2D, 0, xoffset, yoffset, width, height, format, type, dataArray);\n        }\n        else {\n            const unit16s = MathFunctions.convertFloat32ArrayToUInt16Array(dataArray);\n            gl.texSubImage2D(gl.TEXTURE_2D, 0, xoffset, yoffset, width, height, format, type, unit16s);\n        }\n    }\n    /**\n     * The sort method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    draw(renderstate) {\n        if (this.drawCount == 0) {\n            return;\n        }\n        if (this.__updateRequested) {\n            this.__updateBoxes();\n        }\n        if (this.dirtyBoxes.size > 0) {\n            this.dirtyBoxes.forEach((index) => {\n                this.__updateBox(index);\n            });\n            this.dirtyBoxes.clear();\n        }\n        if (this.indexArrayUpdateNeeded)\n            this.__updateIndexArray();\n        const gl = this.__gl;\n        // gl.disable(gl.CULL_FACE)\n        // gl.enable(gl.BLEND)\n        // gl.blendEquation(gl.FUNC_ADD)\n        // gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE)\n        this.glshader.bind(renderstate);\n        this.glgeom.bind(renderstate);\n        const unifs = renderstate.unifs;\n        if (!gl.floatTexturesSupported || !gl.drawElementsInstanced) {\n            const len = this.__indexArray.length;\n            for (let i = 0; i < len; i++) {\n                renderstate.bindViewports(unifs, () => {\n                    gl.drawQuad();\n                });\n            }\n        }\n        else {\n            this.__drawItemsTexture.bindToUniform(renderstate, unifs.instancesTexture);\n            gl.uniform1i(unifs.instancesTextureSize.location, this.width);\n            {\n                // The instance transform ids are bound as an instanced attribute.\n                const location = renderstate.attrs.instancedIds.location;\n                gl.enableVertexAttribArray(location);\n                gl.bindBuffer(gl.ARRAY_BUFFER, this.__instanceIdsBuffer);\n                gl.vertexAttribPointer(location, 1, gl.FLOAT, false, 4, 0);\n                gl.vertexAttribDivisor(location, 1); // This makes it instanced\n            }\n            gl.uniform1i(unifs.instancedDraw.location, 1);\n            renderstate.bindViewports(unifs, () => {\n                this.glgeom.drawInstanced(renderstate, this.drawCount);\n            });\n        }\n        // gl.disable(gl.BLEND)\n    }\n}\n\nclass GLMaskGeomsPass extends GLOpaqueGeomsPass {\n    frontRenderTarget;\n    backRenderTarget;\n    itemCount = 0;\n    drawMaskGeoms = false;\n    init(renderer, passIndex) {\n        super.init(renderer, passIndex);\n        const gl = renderer.gl;\n        this.frontRenderTarget = new GLRenderTarget(gl, {\n            numColorChannels: 0,\n            minFilter: gl.NEAREST,\n            magFilter: gl.NEAREST,\n            width: 4,\n            height: 4,\n            depthType: gl.UNSIGNED_SHORT,\n            depthFormat: gl.DEPTH_COMPONENT,\n            depthInternalFormat: gl.DEPTH_COMPONENT16,\n        });\n        this.frontRenderTarget.clearColor = new Color(0, 0, 0, 0);\n        this.backRenderTarget = new GLRenderTarget(gl, {\n            numColorChannels: 0,\n            minFilter: gl.NEAREST,\n            magFilter: gl.NEAREST,\n            width: 4,\n            height: 4,\n            depthType: gl.UNSIGNED_SHORT,\n            depthFormat: gl.DEPTH_COMPONENT,\n            depthInternalFormat: gl.DEPTH_COMPONENT16,\n        });\n        this.backRenderTarget.clearColor = new Color(0, 0, 0, 0);\n    }\n    filterGeomItem(geomItem) {\n        const material = geomItem.materialParam.value;\n        if (material instanceof MaskMaterial) {\n            return true;\n        }\n        return false;\n    }\n    /**\n     * The addGeomItem method.\n     * @param geomItem - The geomItem value.\n     */\n    addGeomItem(geomItem) {\n        super.addGeomItem(geomItem);\n        this.itemCount++;\n    }\n    /**\n     * The removeGeomItem method.\n     * @param geomItem - The geomItem value.\n     */\n    removeGeomItem(geomItem) {\n        super.removeGeomItem(geomItem);\n        this.itemCount--;\n    }\n    /**\n     * The draw method.\n     * @param renderstate - The object tracking the current state of the renderer\n     */\n    draw(renderstate) {\n        if (this.itemCount == 0)\n            return;\n        renderstate.pushGLStack('GLMaskGeomsPass.draw');\n        const gl = this.__gl;\n        if (this.drawMaskGeoms) {\n            renderstate.glEnable(gl.BLEND);\n            gl.blendEquation(gl.FUNC_ADD);\n            gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE);\n            this.traverseTreeAndDraw(renderstate);\n            renderstate.glDisable(gl.BLEND);\n            gl.clear(gl.DEPTH_BUFFER_BIT);\n        }\n        const width = renderstate.region[2];\n        const height = renderstate.region[3];\n        if (width != this.frontRenderTarget.width || height != this.frontRenderTarget.height) {\n            this.frontRenderTarget.resize(width, height);\n            this.backRenderTarget.resize(width, height);\n        }\n        gl.depthFunc(gl.LESS);\n        gl.depthMask(true);\n        renderstate.glEnable(gl.DEPTH_TEST);\n        this.frontRenderTarget.bindForWriting(renderstate, true);\n        this.traverseTreeAndDraw(renderstate);\n        this.frontRenderTarget.unbindForWriting(renderstate);\n        this.backRenderTarget.bindForWriting(renderstate, true);\n        // Here we invert the depth range to make the front buffer\n        gl.depthFunc(gl.GREATER);\n        gl.clearDepth(0);\n        gl.clear(gl.DEPTH_BUFFER_BIT);\n        gl.cullFace(gl.FRONT);\n        this.traverseTreeAndDraw(renderstate);\n        this.backRenderTarget.unbindForWriting(renderstate);\n        gl.clearDepth(1);\n        gl.depthFunc(gl.LESS);\n        gl.cullFace(gl.BACK);\n        renderstate.geometryMaskTextures = [this.frontRenderTarget.depthTexture, this.backRenderTarget.depthTexture];\n        renderstate.popGLStack();\n    }\n    drawGeomData(renderstate) {\n        // We do not want to draw the masks to the GeomData buffer\n        // else it will interfere with picking objects in the scene.\n    }\n}\nGLRenderer.registerPass(GLMaskGeomsPass, PassType.PRE);\n\n//@ts-ignore\nconsole.log(`Zea Engine v${version}`);\nconst libsRegistry = new LibsRegistry(version);\n\nexport { Allocation1D, Allocator1D, AngleParameter, AssetItem, AssetLoadContext, Attribute, BaseClass, BaseEvent, BaseGeom, BaseGeomItem, BaseGroup, BaseImage, BaseItem, BaseProxy, BaseTool, BillboardAlignment, BillboardItem, BillboardShader, BinReader, BinWriter, BooleanOperatorInput, BooleanOperatorOutput, BooleanParameter, Box2, Box2Parameter, Box3, Box3Parameter, CADAssembly, CADAsset, CADBody, CADPart, Camera, CameraManipulator, ChildAddedEvent, Circle, CloneContext, Color, ColorAttribute, ColorOperatorInput, ColorOperatorOutput, ColorParameter, ColorRenderState, ColorSpace, CompoundGeom, Cone, ControllerAddedEvent, CountChangedEvent, Cross, Cuboid, CuttingPlane, Cylinder, DataImage, Disc, EnvMap, EnvMapAssignedEvent, EnvMapShader, EnvProjectionMaterial, EnvProjectionShader, EulerAngles, EulerAnglesAxisOrder, EventEmitter, FRAMEBUFFER, FatLinesMaterial, FatLinesShader, FatPoints, FatPointsMaterial, FatPointsShader, FileImage, FileImage2D, FlatSurfaceMaterial, FlatSurfaceShader, Float32, Float32ArrayParameter, Frustum, GIFImage, GLBaseRenderer, GLBaseViewport, GLBillboardsPass, GLBoundingBoxPass, GLCADPass, GLFbo, GLGeom, GLGeomItem, GLGeomItemChangeType, GLGeomItemFlags, GLGeomItemSet, GLGeomItemSetMultiDraw, GLGeomItemSetMultiDrawCompoundGeom, GLLines, GLLinesItemSet, GLLinesPass, GLMaskGeomsPass, GLMaterial, GLMaterialGeomItemSets, GLMesh, GLMeshItemSet, GLOpaqueGeomsPass, GLOverlayPass, GLPass, GLPoints, GLPointsItemSet, GLRenderTarget, GLRenderer, GLShader, GLShaderGeomSets, GLShaderMaterials, GLStandardGeomsPass, GLTexture2D, GLTransparentGeomsPass, GLViewport, GROUP_XFO_MODES, GeomDataRenderState, GeomItem, GeomLibrary, GeomType$2 as GeomType, GeometryParameter, Grid, GridTreeItem, GrowingPacker, HDRImage, HighlightRenderState, IGeomShaderBinding, ImageParameter, IndexDBCache, IndexEvent, InstanceItem, IntersectionData, ItemEvent, ItemSetParameter, KeyboardEvent, KinematicGroup, LDRImage, LDRVideo, Label, LabelManager, Lines, LinesCuboid, LinesCylinder, LinesMaterial, LinesProxy, LinesShader, LinesSphere, ListParameter, MaskMaterial, Mat3, Mat3OperatorInput, Mat3OperatorOutput, Mat3Parameter, Mat4, Mat4OperatorInput, Mat4OperatorOutput, Mat4Parameter, Material, MaterialColorParam, MaterialFloatParam, MaterialGroup, MaterialLibrary, MaterialParameter, MathFunctions, Mesh, MeshProxy, MultiChoiceParameter, NameChangedEvent, NumberOperatorInput, NumberOperatorOutput, NumberParameter, ObjAsset, OpacityStateChangedEvent, Operator, OperatorInput, OperatorOutput, OperatorOutputMode, PMIItem, PMIView, POINTER_TYPES, Parameter, ParameterAddedEvent, ParameterOwner, ParameterRemovedEvent, PassType, PlaceholderGeomItem, Plane, PlaneType, PointGrid, Points, PointsMaterial, PointsProxy, PointsShader, ProceduralLines, ProceduralMesh, ProceduralPoints, ProgressEvent, Quat, QuatOperatorInput, QuatOperatorOutput, QuatParameter, RGBA, RangeLoadedEvent, Ray, Rect, RefCounted, Registry, RenderState, ResizedEvent, ResourceLoader, SInt16, SInt32, SInt8, Scene, SceneSetEvent, ScreenQuadShader, ScreenSpaceMaterial, ScreenSpaceShader, SelectabilityChangedEvent, SelectedEvent, SelectionSet, ShaderLibrary, ShaderNameChangedEvent, SimpleSurfaceMaterial, SimpleSurfaceShader, Sphere, SphereType, StandardSurfaceMaterial, StandardSurfaceShader, StateChangedEvent, StreamFileParsedEvent, StringFunctions, StringListParameter, StringParameter, StructParameter, SystemDesc, TexturedChangedEvent, Torus, Touch, TreeItem, TreeItemParameter, UInt16, UInt32, UInt8, UnpackHDRShader, VLAAsset, VRController, VRViewport, Vec2, Vec2Attribute, Vec2OperatorInput, Vec2OperatorOutput, Vec2Parameter, Vec3, Vec3Attribute, Vec3OperatorInput, Vec3OperatorOutput, Vec3Parameter, Vec4, Vec4Attribute, Vec4OperatorInput, Vec4OperatorOutput, Vec4Parameter, Version, VertexColorMaterial, VertexColorShader, VideoStreamImage2D, ViewChangedEvent, XRController, XRControllerEvent, XRHead, XRPointerEvent, XRPoseEvent, XRViewChangedEvent, XRViewManipulator, XRViewport, XRef, Xfo, XfoOperatorInput, XfoOperatorOutput, XfoParameter, XrViewportEvent, ZeaKeyboardEvent, ZeaMouseEvent, ZeaPointerEvent, ZeaTouchEvent, ZeaUIEvent, ZeaWheelEvent, archiveUnpackerWorkerPool, checkFramebuffer, create3DContext, genDataTypeDesc, generateShaderGeomBinding, geomParserWorkerPool, getFileFolder, labelManager, libsRegistry, loadBinfile, loadJSONfile, loadTextfile, loadXMLfile, resourceLoader, shaderLibrary };\n"]}