{"version":3,"file":"VideoSource.mjs","sources":["../../../../../../src/rendering/renderers/shared/texture/sources/VideoSource.ts"],"sourcesContent":["// VideoSource.ts\n\nimport { ExtensionType } from '../../../../../extensions/Extensions';\nimport { Ticker } from '../../../../../ticker/Ticker';\nimport { detectVideoAlphaMode } from '../../../../../utils/browser/detectVideoAlphaMode';\nimport { TextureSource } from './TextureSource';\n\nimport type { ExtensionMetadata } from '../../../../../extensions/Extensions';\nimport type { Dict } from '../../../../../utils/types';\nimport type { ALPHA_MODES } from '../const';\nimport type { TextureSourceOptions } from './TextureSource';\n\ntype VideoResource = HTMLVideoElement;\n\n/**\n * Options for video sources.\n * @memberof rendering\n */\nexport interface VideoSourceOptions extends TextureSourceOptions<VideoResource>\n{\n    /** If true, the video will start loading immediately. */\n    autoLoad?: boolean;\n    /** If true, the video will start playing as soon as it is loaded. */\n    autoPlay?: boolean;\n    /** The number of times a second to update the texture from the video. Leave at 0 to update at every render. */\n    updateFPS?: number;\n    /** If true, the video will be loaded with the `crossorigin` attribute. */\n    crossorigin?: boolean | string;\n    /** If true, the video will loop when it ends. */\n    loop?: boolean;\n    /** If true, the video will be muted. */\n    muted?: boolean;\n    /** If true, the video will play inline. */\n    playsinline?: boolean;\n    /** If true, the video will be preloaded. */\n    preload?: boolean;\n    /** The time in milliseconds to wait for the video to preload before timing out. */\n    preloadTimeoutMs?: number;\n    /** The alpha mode of the video. */\n    alphaMode?: ALPHA_MODES;\n}\n\nexport interface VideoResourceOptionsElement\n{\n    src: string;\n    mime: string;\n}\n\n/**\n * A source for video-based textures.\n * @memberof rendering\n */\nexport class VideoSource extends TextureSource<VideoResource>\n{\n    public static extension: ExtensionMetadata = ExtensionType.TextureSource;\n\n    /** The default options for video sources. */\n    public static defaultOptions: VideoSourceOptions = {\n        ...TextureSource.defaultOptions,\n        /** If true, the video will start loading immediately. */\n        autoLoad: true,\n        /** If true, the video will start playing as soon as it is loaded. */\n        autoPlay: true,\n        /** The number of times a second to update the texture from the video. Leave at 0 to update at every render. */\n        updateFPS: 0,\n        /** If true, the video will be loaded with the `crossorigin` attribute. */\n        crossorigin: true,\n        /** If true, the video will loop when it ends. */\n        loop: false,\n        /** If true, the video will be muted. */\n        muted: true,\n        /** If true, the video will play inline. */\n        playsinline: true,\n        /** If true, the video will be preloaded. */\n        preload: false,\n    };\n\n    // Public\n    /** Whether or not the video is ready to play. */\n    public isReady = false;\n    /** The upload method for this texture. */\n    public uploadMethodId = 'video';\n\n    // Protected\n    /**\n     * When set to true will automatically play videos used by this texture once\n     * they are loaded. If false, it will not modify the playing state.\n     * @default true\n     */\n    protected autoPlay: boolean;\n\n    // Private\n    /**\n     * `true` to use Ticker.shared to auto update the base texture.\n     * @default true\n     */\n    private _autoUpdate: boolean;\n\n    /**\n     * `true` if the instance is currently connected to Ticker.shared to auto update the base texture.\n     * @default false\n     */\n    private _isConnectedToTicker: boolean;\n\n    /**\n     * Promise when loading.\n     * @default null\n     */\n    private _load: Promise<this>;\n\n    private _msToNextUpdate: number;\n    private _preloadTimeout: number;\n\n    /** Callback when completed with load. */\n    private _resolve: (value?: this | PromiseLike<this>) => void;\n    private _reject: (error: ErrorEvent) => void;\n\n    private _updateFPS: number;\n    private _videoFrameRequestCallbackHandle: number | null;\n\n    constructor(\n        options: VideoSourceOptions\n    )\n    {\n        super(options);\n\n        // Merge provided options with default ones\n        options = {\n            ...VideoSource.defaultOptions,\n            ...options\n        };\n\n        this._autoUpdate = true;\n        this._isConnectedToTicker = false;\n        this._updateFPS = options.updateFPS || 0;\n        this._msToNextUpdate = 0;\n        this.autoPlay = options.autoPlay !== false;\n        this.alphaMode = options.alphaMode ?? 'premultiply-alpha-on-upload';\n\n        // Binding for frame updates\n        this._videoFrameRequestCallback = this._videoFrameRequestCallback.bind(this);\n        this._videoFrameRequestCallbackHandle = null;\n\n        this._load = null;\n        this._resolve = null;\n        this._reject = null;\n\n        // Bind for listeners\n        this._onCanPlay = this._onCanPlay.bind(this);\n        this._onCanPlayThrough = this._onCanPlayThrough.bind(this);\n        this._onError = this._onError.bind(this);\n        this._onPlayStart = this._onPlayStart.bind(this);\n        this._onPlayStop = this._onPlayStop.bind(this);\n        this._onSeeked = this._onSeeked.bind(this);\n\n        if (options.autoLoad !== false)\n        {\n            void this.load();\n        }\n    }\n\n    /** Update the video frame if the source is not destroyed and meets certain conditions. */\n    protected updateFrame(): void\n    {\n        if (this.destroyed)\n        {\n            return;\n        }\n\n        if (this._updateFPS)\n        {\n            // Account for if video has had its playbackRate changed\n            const elapsedMS = Ticker.shared.elapsedMS * this.resource.playbackRate;\n\n            this._msToNextUpdate = Math.floor(this._msToNextUpdate - elapsedMS);\n        }\n\n        if (!this._updateFPS || this._msToNextUpdate <= 0)\n        {\n            this._msToNextUpdate = this._updateFPS ? Math.floor(1000 / this._updateFPS) : 0;\n        }\n\n        if (this.isValid)\n        {\n            this.update();\n        }\n    }\n\n    /** Callback to update the video frame and potentially request the next frame update. */\n    private _videoFrameRequestCallback(): void\n    {\n        this.updateFrame();\n\n        if (this.destroyed)\n        {\n            this._videoFrameRequestCallbackHandle = null;\n        }\n        else\n        {\n            this._videoFrameRequestCallbackHandle = this.resource.requestVideoFrameCallback(\n                this._videoFrameRequestCallback\n            );\n        }\n    }\n\n    /**\n     * Checks if the resource has valid dimensions.\n     * @returns {boolean} True if width and height are set, otherwise false.\n     */\n    public get isValid(): boolean\n    {\n        return !!this.resource.videoWidth && !!this.resource.videoHeight;\n    }\n\n    /**\n     * Start preloading the video resource.\n     * @returns {Promise<this>} Handle the validate event\n     */\n    public async load(): Promise<this>\n    {\n        if (this._load)\n        {\n            return this._load;\n        }\n\n        const source = this.resource;\n        const options = this.options as VideoSourceOptions;\n\n        // Check if source data is enough and set it to complete if needed\n        if ((source.readyState === source.HAVE_ENOUGH_DATA || source.readyState === source.HAVE_FUTURE_DATA)\n            && source.width && source.height)\n        {\n            (source as any).complete = true;\n        }\n\n        // Add event listeners related to playback and seeking\n        source.addEventListener('play', this._onPlayStart);\n        source.addEventListener('pause', this._onPlayStop);\n        source.addEventListener('seeked', this._onSeeked);\n\n        // Add or handle source readiness event listeners\n        if (!this._isSourceReady())\n        {\n            if (!options.preload)\n            {\n                // since this event fires early, only bind if not waiting for a preload event\n                source.addEventListener('canplay', this._onCanPlay);\n            }\n            source.addEventListener('canplaythrough', this._onCanPlayThrough);\n            source.addEventListener('error', this._onError, true);\n        }\n        else\n        {\n            // Source is already ready, so handle it immediately\n            this._mediaReady();\n        }\n\n        this.alphaMode = await detectVideoAlphaMode();\n\n        // Create and return the loading promise\n        this._load = new Promise((resolve, reject): void =>\n        {\n            if (this.isValid)\n            {\n                resolve(this);\n            }\n            else\n            {\n                this._resolve = resolve;\n                this._reject = reject;\n\n                if (options.preloadTimeoutMs !== undefined)\n                {\n                    this._preloadTimeout = setTimeout(() =>\n                    {\n                        this._onError(new ErrorEvent(`Preload exceeded timeout of ${options.preloadTimeoutMs}ms`));\n                    }) as unknown as number;\n                }\n                source.load();\n            }\n        });\n\n        return this._load;\n    }\n\n    /**\n     * Handle video error events.\n     * @param event - The error event\n     */\n    private _onError(event: ErrorEvent): void\n    {\n        this.resource.removeEventListener('error', this._onError, true);\n        this.emit('error', event);\n\n        if (this._reject)\n        {\n            this._reject(event);\n            this._reject = null;\n            this._resolve = null;\n        }\n    }\n\n    /**\n     * Checks if the underlying source is playing.\n     * @returns True if playing.\n     */\n    private _isSourcePlaying(): boolean\n    {\n        const source = this.resource;\n\n        return (!source.paused && !source.ended);\n    }\n\n    /**\n     * Checks if the underlying source is ready for playing.\n     * @returns True if ready.\n     */\n    private _isSourceReady(): boolean\n    {\n        const source = this.resource;\n\n        return source.readyState > 2;\n    }\n\n    /** Runs the update loop when the video is ready to play. */\n    private _onPlayStart(): void\n    {\n        // Handle edge case where video might not have received its \"can play\" event yet\n        if (!this.isValid)\n        {\n            this._mediaReady();\n        }\n\n        this._configureAutoUpdate();\n    }\n\n    /** Stops the update loop when a pause event is triggered. */\n    private _onPlayStop(): void\n    {\n        this._configureAutoUpdate();\n    }\n\n    /** Handles behavior when the video completes seeking to the current playback position. */\n    private _onSeeked(): void\n    {\n        if (this._autoUpdate && !this._isSourcePlaying())\n        {\n            this._msToNextUpdate = 0;\n            this.updateFrame();\n            this._msToNextUpdate = 0;\n        }\n    }\n\n    private _onCanPlay(): void\n    {\n        const source = this.resource;\n\n        // Remove event listeners\n        source.removeEventListener('canplay', this._onCanPlay);\n\n        this._mediaReady();\n    }\n\n    private _onCanPlayThrough(): void\n    {\n        const source = this.resource;\n\n        // Remove event listeners\n        source.removeEventListener('canplaythrough', this._onCanPlay);\n\n        if (this._preloadTimeout)\n        {\n            clearTimeout(this._preloadTimeout);\n            this._preloadTimeout = undefined;\n        }\n\n        this._mediaReady();\n    }\n\n    /** Fired when the video is loaded and ready to play. */\n    private _mediaReady(): void\n    {\n        const source = this.resource;\n\n        if (this.isValid)\n        {\n            this.isReady = true;\n            this.resize(source.videoWidth, source.videoHeight);\n        }\n\n        // Reset update timers and perform a frame update\n        this._msToNextUpdate = 0;\n        this.updateFrame();\n        this._msToNextUpdate = 0;\n\n        // Resolve the loading promise if it exists\n        if (this._resolve)\n        {\n            this._resolve(this);\n            this._resolve = null;\n            this._reject = null;\n        }\n\n        // Handle play behavior based on current source status\n        if (this._isSourcePlaying())\n        {\n            this._onPlayStart();\n        }\n        else if (this.autoPlay)\n        {\n            void this.resource.play();\n        }\n    }\n\n    /** Cleans up resources and event listeners associated with this texture. */\n    public destroy()\n    {\n        this._configureAutoUpdate();\n\n        const source = this.resource;\n\n        if (source)\n        {\n            // Remove event listeners\n            source.removeEventListener('play', this._onPlayStart);\n            source.removeEventListener('pause', this._onPlayStop);\n            source.removeEventListener('seeked', this._onSeeked);\n            source.removeEventListener('canplay', this._onCanPlay);\n            source.removeEventListener('canplaythrough', this._onCanPlayThrough);\n            source.removeEventListener('error', this._onError, true);\n\n            // Clear the video source and pause\n            source.pause();\n            source.src = '';\n            source.load();\n        }\n\n        super.destroy();\n    }\n\n    /** Should the base texture automatically update itself, set to true by default. */\n    get autoUpdate(): boolean\n    {\n        return this._autoUpdate;\n    }\n\n    set autoUpdate(value: boolean)\n    {\n        if (value !== this._autoUpdate)\n        {\n            this._autoUpdate = value;\n            this._configureAutoUpdate();\n        }\n    }\n\n    /**\n     * How many times a second to update the texture from the video.\n     * Leave at 0 to update at every render.\n     * A lower fps can help performance, as updating the texture at 60fps on a 30ps video may not be efficient.\n     */\n    get updateFPS(): number\n    {\n        return this._updateFPS;\n    }\n\n    set updateFPS(value: number)\n    {\n        if (value !== this._updateFPS)\n        {\n            this._updateFPS = value;\n            this._configureAutoUpdate();\n        }\n    }\n\n    /**\n     * Configures the updating mechanism based on the current state and settings.\n     *\n     * This method decides between using the browser's native video frame callback or a custom ticker\n     * for updating the video frame. It ensures optimal performance and responsiveness\n     * based on the video's state, playback status, and the desired frames-per-second setting.\n     *\n     * - If `_autoUpdate` is enabled and the video source is playing:\n     *   - It will prefer the native video frame callback if available and no specific FPS is set.\n     *   - Otherwise, it will use a custom ticker for manual updates.\n     * - If `_autoUpdate` is disabled or the video isn't playing, any active update mechanisms are halted.\n     */\n    private _configureAutoUpdate(): void\n    {\n        // Check if automatic updating is enabled and if the source is currently playing\n        if (this._autoUpdate && this._isSourcePlaying())\n        {\n            // Determine if we should use the browser's native video frame callback (generally for better performance)\n            if (!this._updateFPS && this.resource.requestVideoFrameCallback)\n            {\n                // If connected to a custom ticker, remove the update frame function from it\n                if (this._isConnectedToTicker)\n                {\n                    Ticker.shared.remove(this.updateFrame, this);\n                    this._isConnectedToTicker = false;\n                    // Reset the time until the next update\n                    this._msToNextUpdate = 0;\n                }\n\n                // Check if we haven't already requested a video frame callback, and if not, request one\n                if (this._videoFrameRequestCallbackHandle === null)\n                {\n                    this._videoFrameRequestCallbackHandle = this.resource.requestVideoFrameCallback(\n                        this._videoFrameRequestCallback\n                    );\n                }\n            }\n            else\n            {\n                // If a video frame request callback exists, cancel it, as we are switching to manual ticker-based updates\n                if (this._videoFrameRequestCallbackHandle !== null)\n                {\n                    this.resource.cancelVideoFrameCallback(this._videoFrameRequestCallbackHandle);\n                    this._videoFrameRequestCallbackHandle = null;\n                }\n\n                // If not connected to the custom ticker, add the update frame function to it\n                if (!this._isConnectedToTicker)\n                {\n                    Ticker.shared.add(this.updateFrame, this);\n                    this._isConnectedToTicker = true;\n                    // Reset the time until the next update\n                    this._msToNextUpdate = 0;\n                }\n            }\n        }\n        else\n        {\n            // If automatic updating is disabled or the source isn't playing, perform cleanup\n\n            // Cancel any existing video frame callback request\n            if (this._videoFrameRequestCallbackHandle !== null)\n            {\n                this.resource.cancelVideoFrameCallback(this._videoFrameRequestCallbackHandle);\n                this._videoFrameRequestCallbackHandle = null;\n            }\n\n            // Remove the update frame function from the custom ticker\n            if (this._isConnectedToTicker)\n            {\n                Ticker.shared.remove(this.updateFrame, this);\n                this._isConnectedToTicker = false;\n                // Reset the time until the next update\n                this._msToNextUpdate = 0;\n            }\n        }\n    }\n\n    /**\n     * Map of video MIME types that can't be directly derived from file extensions.\n     * @readonly\n     */\n    public static MIME_TYPES: Dict<string>\n        = {\n            ogv: 'video/ogg',\n            mov: 'video/quicktime',\n            m4v: 'video/mp4',\n        };\n\n    public static test(resource: any): resource is VideoResource\n    {\n        return (globalThis.HTMLVideoElement && resource instanceof HTMLVideoElement);\n    }\n}\n"],"names":[],"mappings":";;;;;;AAoDO,MAAM,YAAA,GAAN,MAAM,YAAA,SAAoB,aACjC,CAAA;AAAA,EAmEI,YACI,OAEJ,EAAA;AACI,IAAA,KAAA,CAAM,OAAO,CAAA,CAAA;AA7CjB;AAAA;AAAA,IAAA,IAAA,CAAO,OAAU,GAAA,KAAA,CAAA;AAEjB;AAAA,IAAA,IAAA,CAAO,cAAiB,GAAA,OAAA,CAAA;AA8CpB,IAAU,OAAA,GAAA;AAAA,MACN,GAAG,YAAY,CAAA,cAAA;AAAA,MACf,GAAG,OAAA;AAAA,KACP,CAAA;AAEA,IAAA,IAAA,CAAK,WAAc,GAAA,IAAA,CAAA;AACnB,IAAA,IAAA,CAAK,oBAAuB,GAAA,KAAA,CAAA;AAC5B,IAAK,IAAA,CAAA,UAAA,GAAa,QAAQ,SAAa,IAAA,CAAA,CAAA;AACvC,IAAA,IAAA,CAAK,eAAkB,GAAA,CAAA,CAAA;AACvB,IAAK,IAAA,CAAA,QAAA,GAAW,QAAQ,QAAa,KAAA,KAAA,CAAA;AACrC,IAAK,IAAA,CAAA,SAAA,GAAY,QAAQ,SAAa,IAAA,6BAAA,CAAA;AAGtC,IAAA,IAAA,CAAK,0BAA6B,GAAA,IAAA,CAAK,0BAA2B,CAAA,IAAA,CAAK,IAAI,CAAA,CAAA;AAC3E,IAAA,IAAA,CAAK,gCAAmC,GAAA,IAAA,CAAA;AAExC,IAAA,IAAA,CAAK,KAAQ,GAAA,IAAA,CAAA;AACb,IAAA,IAAA,CAAK,QAAW,GAAA,IAAA,CAAA;AAChB,IAAA,IAAA,CAAK,OAAU,GAAA,IAAA,CAAA;AAGf,IAAA,IAAA,CAAK,UAAa,GAAA,IAAA,CAAK,UAAW,CAAA,IAAA,CAAK,IAAI,CAAA,CAAA;AAC3C,IAAA,IAAA,CAAK,iBAAoB,GAAA,IAAA,CAAK,iBAAkB,CAAA,IAAA,CAAK,IAAI,CAAA,CAAA;AACzD,IAAA,IAAA,CAAK,QAAW,GAAA,IAAA,CAAK,QAAS,CAAA,IAAA,CAAK,IAAI,CAAA,CAAA;AACvC,IAAA,IAAA,CAAK,YAAe,GAAA,IAAA,CAAK,YAAa,CAAA,IAAA,CAAK,IAAI,CAAA,CAAA;AAC/C,IAAA,IAAA,CAAK,WAAc,GAAA,IAAA,CAAK,WAAY,CAAA,IAAA,CAAK,IAAI,CAAA,CAAA;AAC7C,IAAA,IAAA,CAAK,SAAY,GAAA,IAAA,CAAK,SAAU,CAAA,IAAA,CAAK,IAAI,CAAA,CAAA;AAEzC,IAAI,IAAA,OAAA,CAAQ,aAAa,KACzB,EAAA;AACI,MAAA,KAAK,KAAK,IAAK,EAAA,CAAA;AAAA,KACnB;AAAA,GACJ;AAAA;AAAA,EAGU,WACV,GAAA;AACI,IAAA,IAAI,KAAK,SACT,EAAA;AACI,MAAA,OAAA;AAAA,KACJ;AAEA,IAAA,IAAI,KAAK,UACT,EAAA;AAEI,MAAA,MAAM,SAAY,GAAA,MAAA,CAAO,MAAO,CAAA,SAAA,GAAY,KAAK,QAAS,CAAA,YAAA,CAAA;AAE1D,MAAA,IAAA,CAAK,eAAkB,GAAA,IAAA,CAAK,KAAM,CAAA,IAAA,CAAK,kBAAkB,SAAS,CAAA,CAAA;AAAA,KACtE;AAEA,IAAA,IAAI,CAAC,IAAA,CAAK,UAAc,IAAA,IAAA,CAAK,mBAAmB,CAChD,EAAA;AACI,MAAK,IAAA,CAAA,eAAA,GAAkB,KAAK,UAAa,GAAA,IAAA,CAAK,MAAM,GAAO,GAAA,IAAA,CAAK,UAAU,CAAI,GAAA,CAAA,CAAA;AAAA,KAClF;AAEA,IAAA,IAAI,KAAK,OACT,EAAA;AACI,MAAA,IAAA,CAAK,MAAO,EAAA,CAAA;AAAA,KAChB;AAAA,GACJ;AAAA;AAAA,EAGQ,0BACR,GAAA;AACI,IAAA,IAAA,CAAK,WAAY,EAAA,CAAA;AAEjB,IAAA,IAAI,KAAK,SACT,EAAA;AACI,MAAA,IAAA,CAAK,gCAAmC,GAAA,IAAA,CAAA;AAAA,KAG5C,MAAA;AACI,MAAK,IAAA,CAAA,gCAAA,GAAmC,KAAK,QAAS,CAAA,yBAAA;AAAA,QAClD,IAAK,CAAA,0BAAA;AAAA,OACT,CAAA;AAAA,KACJ;AAAA,GACJ;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAW,OACX,GAAA;AACI,IAAO,OAAA,CAAC,CAAC,IAAK,CAAA,QAAA,CAAS,cAAc,CAAC,CAAC,KAAK,QAAS,CAAA,WAAA,CAAA;AAAA,GACzD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAa,IACb,GAAA;AACI,IAAA,IAAI,KAAK,KACT,EAAA;AACI,MAAA,OAAO,IAAK,CAAA,KAAA,CAAA;AAAA,KAChB;AAEA,IAAA,MAAM,SAAS,IAAK,CAAA,QAAA,CAAA;AACpB,IAAA,MAAM,UAAU,IAAK,CAAA,OAAA,CAAA;AAGrB,IAAK,IAAA,CAAA,MAAA,CAAO,UAAe,KAAA,MAAA,CAAO,gBAAoB,IAAA,MAAA,CAAO,UAAe,KAAA,MAAA,CAAO,gBAC5E,KAAA,MAAA,CAAO,KAAS,IAAA,MAAA,CAAO,MAC9B,EAAA;AACI,MAAC,OAAe,QAAW,GAAA,IAAA,CAAA;AAAA,KAC/B;AAGA,IAAO,MAAA,CAAA,gBAAA,CAAiB,MAAQ,EAAA,IAAA,CAAK,YAAY,CAAA,CAAA;AACjD,IAAO,MAAA,CAAA,gBAAA,CAAiB,OAAS,EAAA,IAAA,CAAK,WAAW,CAAA,CAAA;AACjD,IAAO,MAAA,CAAA,gBAAA,CAAiB,QAAU,EAAA,IAAA,CAAK,SAAS,CAAA,CAAA;AAGhD,IAAI,IAAA,CAAC,IAAK,CAAA,cAAA,EACV,EAAA;AACI,MAAI,IAAA,CAAC,QAAQ,OACb,EAAA;AAEI,QAAO,MAAA,CAAA,gBAAA,CAAiB,SAAW,EAAA,IAAA,CAAK,UAAU,CAAA,CAAA;AAAA,OACtD;AACA,MAAO,MAAA,CAAA,gBAAA,CAAiB,gBAAkB,EAAA,IAAA,CAAK,iBAAiB,CAAA,CAAA;AAChE,MAAA,MAAA,CAAO,gBAAiB,CAAA,OAAA,EAAS,IAAK,CAAA,QAAA,EAAU,IAAI,CAAA,CAAA;AAAA,KAGxD,MAAA;AAEI,MAAA,IAAA,CAAK,WAAY,EAAA,CAAA;AAAA,KACrB;AAEA,IAAK,IAAA,CAAA,SAAA,GAAY,MAAM,oBAAqB,EAAA,CAAA;AAG5C,IAAA,IAAA,CAAK,KAAQ,GAAA,IAAI,OAAQ,CAAA,CAAC,SAAS,MACnC,KAAA;AACI,MAAA,IAAI,KAAK,OACT,EAAA;AACI,QAAA,OAAA,CAAQ,IAAI,CAAA,CAAA;AAAA,OAGhB,MAAA;AACI,QAAA,IAAA,CAAK,QAAW,GAAA,OAAA,CAAA;AAChB,QAAA,IAAA,CAAK,OAAU,GAAA,MAAA,CAAA;AAEf,QAAI,IAAA,OAAA,CAAQ,qBAAqB,KACjC,CAAA,EAAA;AACI,UAAK,IAAA,CAAA,eAAA,GAAkB,WAAW,MAClC;AACI,YAAA,IAAA,CAAK,SAAS,IAAI,UAAA,CAAW,+BAA+B,OAAQ,CAAA,gBAAgB,IAAI,CAAC,CAAA,CAAA;AAAA,WAC5F,CAAA,CAAA;AAAA,SACL;AACA,QAAA,MAAA,CAAO,IAAK,EAAA,CAAA;AAAA,OAChB;AAAA,KACH,CAAA,CAAA;AAED,IAAA,OAAO,IAAK,CAAA,KAAA,CAAA;AAAA,GAChB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,SAAS,KACjB,EAAA;AACI,IAAA,IAAA,CAAK,QAAS,CAAA,mBAAA,CAAoB,OAAS,EAAA,IAAA,CAAK,UAAU,IAAI,CAAA,CAAA;AAC9D,IAAK,IAAA,CAAA,IAAA,CAAK,SAAS,KAAK,CAAA,CAAA;AAExB,IAAA,IAAI,KAAK,OACT,EAAA;AACI,MAAA,IAAA,CAAK,QAAQ,KAAK,CAAA,CAAA;AAClB,MAAA,IAAA,CAAK,OAAU,GAAA,IAAA,CAAA;AACf,MAAA,IAAA,CAAK,QAAW,GAAA,IAAA,CAAA;AAAA,KACpB;AAAA,GACJ;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,gBACR,GAAA;AACI,IAAA,MAAM,SAAS,IAAK,CAAA,QAAA,CAAA;AAEpB,IAAA,OAAQ,CAAC,MAAA,CAAO,MAAU,IAAA,CAAC,MAAO,CAAA,KAAA,CAAA;AAAA,GACtC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,cACR,GAAA;AACI,IAAA,MAAM,SAAS,IAAK,CAAA,QAAA,CAAA;AAEpB,IAAA,OAAO,OAAO,UAAa,GAAA,CAAA,CAAA;AAAA,GAC/B;AAAA;AAAA,EAGQ,YACR,GAAA;AAEI,IAAI,IAAA,CAAC,KAAK,OACV,EAAA;AACI,MAAA,IAAA,CAAK,WAAY,EAAA,CAAA;AAAA,KACrB;AAEA,IAAA,IAAA,CAAK,oBAAqB,EAAA,CAAA;AAAA,GAC9B;AAAA;AAAA,EAGQ,WACR,GAAA;AACI,IAAA,IAAA,CAAK,oBAAqB,EAAA,CAAA;AAAA,GAC9B;AAAA;AAAA,EAGQ,SACR,GAAA;AACI,IAAA,IAAI,IAAK,CAAA,WAAA,IAAe,CAAC,IAAA,CAAK,kBAC9B,EAAA;AACI,MAAA,IAAA,CAAK,eAAkB,GAAA,CAAA,CAAA;AACvB,MAAA,IAAA,CAAK,WAAY,EAAA,CAAA;AACjB,MAAA,IAAA,CAAK,eAAkB,GAAA,CAAA,CAAA;AAAA,KAC3B;AAAA,GACJ;AAAA,EAEQ,UACR,GAAA;AACI,IAAA,MAAM,SAAS,IAAK,CAAA,QAAA,CAAA;AAGpB,IAAO,MAAA,CAAA,mBAAA,CAAoB,SAAW,EAAA,IAAA,CAAK,UAAU,CAAA,CAAA;AAErD,IAAA,IAAA,CAAK,WAAY,EAAA,CAAA;AAAA,GACrB;AAAA,EAEQ,iBACR,GAAA;AACI,IAAA,MAAM,SAAS,IAAK,CAAA,QAAA,CAAA;AAGpB,IAAO,MAAA,CAAA,mBAAA,CAAoB,gBAAkB,EAAA,IAAA,CAAK,UAAU,CAAA,CAAA;AAE5D,IAAA,IAAI,KAAK,eACT,EAAA;AACI,MAAA,YAAA,CAAa,KAAK,eAAe,CAAA,CAAA;AACjC,MAAA,IAAA,CAAK,eAAkB,GAAA,KAAA,CAAA,CAAA;AAAA,KAC3B;AAEA,IAAA,IAAA,CAAK,WAAY,EAAA,CAAA;AAAA,GACrB;AAAA;AAAA,EAGQ,WACR,GAAA;AACI,IAAA,MAAM,SAAS,IAAK,CAAA,QAAA,CAAA;AAEpB,IAAA,IAAI,KAAK,OACT,EAAA;AACI,MAAA,IAAA,CAAK,OAAU,GAAA,IAAA,CAAA;AACf,MAAA,IAAA,CAAK,MAAO,CAAA,MAAA,CAAO,UAAY,EAAA,MAAA,CAAO,WAAW,CAAA,CAAA;AAAA,KACrD;AAGA,IAAA,IAAA,CAAK,eAAkB,GAAA,CAAA,CAAA;AACvB,IAAA,IAAA,CAAK,WAAY,EAAA,CAAA;AACjB,IAAA,IAAA,CAAK,eAAkB,GAAA,CAAA,CAAA;AAGvB,IAAA,IAAI,KAAK,QACT,EAAA;AACI,MAAA,IAAA,CAAK,SAAS,IAAI,CAAA,CAAA;AAClB,MAAA,IAAA,CAAK,QAAW,GAAA,IAAA,CAAA;AAChB,MAAA,IAAA,CAAK,OAAU,GAAA,IAAA,CAAA;AAAA,KACnB;AAGA,IAAI,IAAA,IAAA,CAAK,kBACT,EAAA;AACI,MAAA,IAAA,CAAK,YAAa,EAAA,CAAA;AAAA,KACtB,MAAA,IACS,KAAK,QACd,EAAA;AACI,MAAK,KAAA,IAAA,CAAK,SAAS,IAAK,EAAA,CAAA;AAAA,KAC5B;AAAA,GACJ;AAAA;AAAA,EAGO,OACP,GAAA;AACI,IAAA,IAAA,CAAK,oBAAqB,EAAA,CAAA;AAE1B,IAAA,MAAM,SAAS,IAAK,CAAA,QAAA,CAAA;AAEpB,IAAA,IAAI,MACJ,EAAA;AAEI,MAAO,MAAA,CAAA,mBAAA,CAAoB,MAAQ,EAAA,IAAA,CAAK,YAAY,CAAA,CAAA;AACpD,MAAO,MAAA,CAAA,mBAAA,CAAoB,OAAS,EAAA,IAAA,CAAK,WAAW,CAAA,CAAA;AACpD,MAAO,MAAA,CAAA,mBAAA,CAAoB,QAAU,EAAA,IAAA,CAAK,SAAS,CAAA,CAAA;AACnD,MAAO,MAAA,CAAA,mBAAA,CAAoB,SAAW,EAAA,IAAA,CAAK,UAAU,CAAA,CAAA;AACrD,MAAO,MAAA,CAAA,mBAAA,CAAoB,gBAAkB,EAAA,IAAA,CAAK,iBAAiB,CAAA,CAAA;AACnE,MAAA,MAAA,CAAO,mBAAoB,CAAA,OAAA,EAAS,IAAK,CAAA,QAAA,EAAU,IAAI,CAAA,CAAA;AAGvD,MAAA,MAAA,CAAO,KAAM,EAAA,CAAA;AACb,MAAA,MAAA,CAAO,GAAM,GAAA,EAAA,CAAA;AACb,MAAA,MAAA,CAAO,IAAK,EAAA,CAAA;AAAA,KAChB;AAEA,IAAA,KAAA,CAAM,OAAQ,EAAA,CAAA;AAAA,GAClB;AAAA;AAAA,EAGA,IAAI,UACJ,GAAA;AACI,IAAA,OAAO,IAAK,CAAA,WAAA,CAAA;AAAA,GAChB;AAAA,EAEA,IAAI,WAAW,KACf,EAAA;AACI,IAAI,IAAA,KAAA,KAAU,KAAK,WACnB,EAAA;AACI,MAAA,IAAA,CAAK,WAAc,GAAA,KAAA,CAAA;AACnB,MAAA,IAAA,CAAK,oBAAqB,EAAA,CAAA;AAAA,KAC9B;AAAA,GACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAI,SACJ,GAAA;AACI,IAAA,OAAO,IAAK,CAAA,UAAA,CAAA;AAAA,GAChB;AAAA,EAEA,IAAI,UAAU,KACd,EAAA;AACI,IAAI,IAAA,KAAA,KAAU,KAAK,UACnB,EAAA;AACI,MAAA,IAAA,CAAK,UAAa,GAAA,KAAA,CAAA;AAClB,MAAA,IAAA,CAAK,oBAAqB,EAAA,CAAA;AAAA,KAC9B;AAAA,GACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcQ,oBACR,GAAA;AAEI,IAAA,IAAI,IAAK,CAAA,WAAA,IAAe,IAAK,CAAA,gBAAA,EAC7B,EAAA;AAEI,MAAA,IAAI,CAAC,IAAA,CAAK,UAAc,IAAA,IAAA,CAAK,SAAS,yBACtC,EAAA;AAEI,QAAA,IAAI,KAAK,oBACT,EAAA;AACI,UAAA,MAAA,CAAO,MAAO,CAAA,MAAA,CAAO,IAAK,CAAA,WAAA,EAAa,IAAI,CAAA,CAAA;AAC3C,UAAA,IAAA,CAAK,oBAAuB,GAAA,KAAA,CAAA;AAE5B,UAAA,IAAA,CAAK,eAAkB,GAAA,CAAA,CAAA;AAAA,SAC3B;AAGA,QAAI,IAAA,IAAA,CAAK,qCAAqC,IAC9C,EAAA;AACI,UAAK,IAAA,CAAA,gCAAA,GAAmC,KAAK,QAAS,CAAA,yBAAA;AAAA,YAClD,IAAK,CAAA,0BAAA;AAAA,WACT,CAAA;AAAA,SACJ;AAAA,OAGJ,MAAA;AAEI,QAAI,IAAA,IAAA,CAAK,qCAAqC,IAC9C,EAAA;AACI,UAAK,IAAA,CAAA,QAAA,CAAS,wBAAyB,CAAA,IAAA,CAAK,gCAAgC,CAAA,CAAA;AAC5E,UAAA,IAAA,CAAK,gCAAmC,GAAA,IAAA,CAAA;AAAA,SAC5C;AAGA,QAAI,IAAA,CAAC,KAAK,oBACV,EAAA;AACI,UAAA,MAAA,CAAO,MAAO,CAAA,GAAA,CAAI,IAAK,CAAA,WAAA,EAAa,IAAI,CAAA,CAAA;AACxC,UAAA,IAAA,CAAK,oBAAuB,GAAA,IAAA,CAAA;AAE5B,UAAA,IAAA,CAAK,eAAkB,GAAA,CAAA,CAAA;AAAA,SAC3B;AAAA,OACJ;AAAA,KAGJ,MAAA;AAII,MAAI,IAAA,IAAA,CAAK,qCAAqC,IAC9C,EAAA;AACI,QAAK,IAAA,CAAA,QAAA,CAAS,wBAAyB,CAAA,IAAA,CAAK,gCAAgC,CAAA,CAAA;AAC5E,QAAA,IAAA,CAAK,gCAAmC,GAAA,IAAA,CAAA;AAAA,OAC5C;AAGA,MAAA,IAAI,KAAK,oBACT,EAAA;AACI,QAAA,MAAA,CAAO,MAAO,CAAA,MAAA,CAAO,IAAK,CAAA,WAAA,EAAa,IAAI,CAAA,CAAA;AAC3C,QAAA,IAAA,CAAK,oBAAuB,GAAA,KAAA,CAAA;AAE5B,QAAA,IAAA,CAAK,eAAkB,GAAA,CAAA,CAAA;AAAA,OAC3B;AAAA,KACJ;AAAA,GACJ;AAAA,EAaA,OAAc,KAAK,QACnB,EAAA;AACI,IAAQ,OAAA,UAAA,CAAW,oBAAoB,QAAoB,YAAA,gBAAA,CAAA;AAAA,GAC/D;AACJ,CAAA,CAAA;AAngBa,YAAA,CAEK,YAA+B,aAAc,CAAA,aAAA,CAAA;AAAA;AAFlD,YAAA,CAKK,cAAqC,GAAA;AAAA,EAC/C,GAAG,aAAc,CAAA,cAAA;AAAA;AAAA,EAEjB,QAAU,EAAA,IAAA;AAAA;AAAA,EAEV,QAAU,EAAA,IAAA;AAAA;AAAA,EAEV,SAAW,EAAA,CAAA;AAAA;AAAA,EAEX,WAAa,EAAA,IAAA;AAAA;AAAA,EAEb,IAAM,EAAA,KAAA;AAAA;AAAA,EAEN,KAAO,EAAA,IAAA;AAAA;AAAA,EAEP,WAAa,EAAA,IAAA;AAAA;AAAA,EAEb,OAAS,EAAA,KAAA;AACb,CAAA,CAAA;AAAA;AAAA;AAAA;AAAA;AAvBS,YAAA,CAwfK,UACR,GAAA;AAAA,EACE,GAAK,EAAA,WAAA;AAAA,EACL,GAAK,EAAA,iBAAA;AAAA,EACL,GAAK,EAAA,WAAA;AACT,CAAA,CAAA;AA7fD,IAAM,WAAN,GAAA;;;;"}