1 line
23 KiB
Plaintext
1 line
23 KiB
Plaintext
{"version":3,"file":"Ticker.mjs","sources":["../src/Ticker.ts"],"sourcesContent":["import { UPDATE_PRIORITY } from './const';\nimport { TickerListener } from './TickerListener';\n\nexport type TickerCallback<T> = (this: T, dt: number) => any;\n\n/**\n * A Ticker class that runs an update loop that other objects listen to.\n *\n * This class is composed around listeners meant for execution on the next requested animation frame.\n * Animation frames are requested only when necessary, e.g. When the ticker is started and the emitter has listeners.\n * @class\n * @memberof PIXI\n */\nexport class Ticker\n{\n /**\n * Target frames per millisecond.\n * @static\n */\n public static targetFPMS = 0.06;\n\n /** The private shared ticker instance */\n private static _shared: Ticker;\n /** The private system ticker instance */\n private static _system: Ticker;\n\n /**\n * Whether or not this ticker should invoke the method\n * {@link PIXI.Ticker#start} automatically\n * when a listener is added.\n */\n public autoStart = false;\n /**\n * Scalar time value from last frame to this frame.\n * This value is capped by setting {@link PIXI.Ticker#minFPS}\n * and is scaled with {@link PIXI.Ticker#speed}.\n * **Note:** The cap may be exceeded by scaling.\n */\n public deltaTime = 1;\n /**\n * Scaler time elapsed in milliseconds from last frame to this frame.\n * This value is capped by setting {@link PIXI.Ticker#minFPS}\n * and is scaled with {@link PIXI.Ticker#speed}.\n * **Note:** The cap may be exceeded by scaling.\n * If the platform supports DOMHighResTimeStamp,\n * this value will have a precision of 1 µs.\n * Defaults to target frame time\n * @default 16.66\n */\n public deltaMS: number;\n /**\n * Time elapsed in milliseconds from last frame to this frame.\n * Opposed to what the scalar {@link PIXI.Ticker#deltaTime}\n * is based, this value is neither capped nor scaled.\n * If the platform supports DOMHighResTimeStamp,\n * this value will have a precision of 1 µs.\n * Defaults to target frame time\n * @default 16.66\n */\n public elapsedMS: number;\n /**\n * The last time {@link PIXI.Ticker#update} was invoked.\n * This value is also reset internally outside of invoking\n * update, but only when a new animation frame is requested.\n * If the platform supports DOMHighResTimeStamp,\n * this value will have a precision of 1 µs.\n */\n public lastTime = -1;\n /**\n * Factor of current {@link PIXI.Ticker#deltaTime}.\n * @example\n * // Scales ticker.deltaTime to what would be\n * // the equivalent of approximately 120 FPS\n * ticker.speed = 2;\n */\n public speed = 1;\n /**\n * Whether or not this ticker has been started.\n * `true` if {@link PIXI.Ticker#start} has been called.\n * `false` if {@link PIXI.Ticker#stop} has been called.\n * While `false`, this value may change to `true` in the\n * event of {@link PIXI.Ticker#autoStart} being `true`\n * and a listener is added.\n */\n public started = false;\n\n /** The first listener. All new listeners added are chained on this. */\n private _head: TickerListener;\n /** Internal current frame request ID */\n private _requestId: number = null;\n /**\n * Internal value managed by minFPS property setter and getter.\n * This is the maximum allowed milliseconds between updates.\n */\n private _maxElapsedMS = 100;\n /**\n * Internal value managed by minFPS property setter and getter.\n * This is the minimum allowed milliseconds between updates.\n */\n private _minElapsedMS = 0;\n /** If enabled, deleting is disabled.*/\n private _protected = false;\n /** The last time keyframe was executed. Maintains a relatively fixed interval with the previous value. */\n private _lastFrame = -1;\n /**\n * Internal tick method bound to ticker instance.\n * This is because in early 2015, Function.bind\n * is still 60% slower in high performance scenarios.\n * Also separating frame requests from update method\n * so listeners may be called at any time and with\n * any animation API, just invoke ticker.update(time).\n * @param time - Time since last tick.\n */\n private _tick: (time: number) => any;\n\n constructor()\n {\n this._head = new TickerListener(null, null, Infinity);\n this.deltaMS = 1 / Ticker.targetFPMS;\n this.elapsedMS = 1 / Ticker.targetFPMS;\n\n this._tick = (time: number): void =>\n {\n this._requestId = null;\n\n if (this.started)\n {\n // Invoke listeners now\n this.update(time);\n // Listener side effects may have modified ticker state.\n if (this.started && this._requestId === null && this._head.next)\n {\n this._requestId = requestAnimationFrame(this._tick);\n }\n }\n };\n }\n\n /**\n * Conditionally requests a new animation frame.\n * If a frame has not already been requested, and if the internal\n * emitter has listeners, a new frame is requested.\n * @private\n */\n private _requestIfNeeded(): void\n {\n if (this._requestId === null && this._head.next)\n {\n // ensure callbacks get correct delta\n this.lastTime = performance.now();\n this._lastFrame = this.lastTime;\n this._requestId = requestAnimationFrame(this._tick);\n }\n }\n\n /**\n * Conditionally cancels a pending animation frame.\n * @private\n */\n private _cancelIfNeeded(): void\n {\n if (this._requestId !== null)\n {\n cancelAnimationFrame(this._requestId);\n this._requestId = null;\n }\n }\n\n /**\n * Conditionally requests a new animation frame.\n * If the ticker has been started it checks if a frame has not already\n * been requested, and if the internal emitter has listeners. If these\n * conditions are met, a new frame is requested. If the ticker has not\n * been started, but autoStart is `true`, then the ticker starts now,\n * and continues with the previous conditions to request a new frame.\n * @private\n */\n private _startIfPossible(): void\n {\n if (this.started)\n {\n this._requestIfNeeded();\n }\n else if (this.autoStart)\n {\n this.start();\n }\n }\n\n /**\n * Register a handler for tick events. Calls continuously unless\n * it is removed or the ticker is stopped.\n * @param fn - The listener function to be added for updates\n * @param context - The listener context\n * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting\n * @returns This instance of a ticker\n */\n add<T = any>(fn: TickerCallback<T>, context?: T, priority = UPDATE_PRIORITY.NORMAL): this\n {\n return this._addListener(new TickerListener(fn, context, priority));\n }\n\n /**\n * Add a handler for the tick event which is only execute once.\n * @param fn - The listener function to be added for one update\n * @param context - The listener context\n * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting\n * @returns This instance of a ticker\n */\n addOnce<T = any>(fn: TickerCallback<T>, context?: T, priority = UPDATE_PRIORITY.NORMAL): this\n {\n return this._addListener(new TickerListener(fn, context, priority, true));\n }\n\n /**\n * Internally adds the event handler so that it can be sorted by priority.\n * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run\n * before the rendering.\n * @private\n * @param listener - Current listener being added.\n * @returns This instance of a ticker\n */\n private _addListener(listener: TickerListener): this\n {\n // For attaching to head\n let current = this._head.next;\n let previous = this._head;\n\n // Add the first item\n if (!current)\n {\n listener.connect(previous);\n }\n else\n {\n // Go from highest to lowest priority\n while (current)\n {\n if (listener.priority > current.priority)\n {\n listener.connect(previous);\n break;\n }\n previous = current;\n current = current.next;\n }\n\n // Not yet connected\n if (!listener.previous)\n {\n listener.connect(previous);\n }\n }\n\n this._startIfPossible();\n\n return this;\n }\n\n /**\n * Removes any handlers matching the function and context parameters.\n * If no handlers are left after removing, then it cancels the animation frame.\n * @param fn - The listener function to be removed\n * @param context - The listener context to be removed\n * @returns This instance of a ticker\n */\n remove<T = any>(fn: TickerCallback<T>, context?: T): this\n {\n let listener = this._head.next;\n\n while (listener)\n {\n // We found a match, lets remove it\n // no break to delete all possible matches\n // incase a listener was added 2+ times\n if (listener.match(fn, context))\n {\n listener = listener.destroy();\n }\n else\n {\n listener = listener.next;\n }\n }\n\n if (!this._head.next)\n {\n this._cancelIfNeeded();\n }\n\n return this;\n }\n\n /**\n * The number of listeners on this ticker, calculated by walking through linked list\n * @readonly\n * @member {number}\n */\n get count(): number\n {\n if (!this._head)\n {\n return 0;\n }\n\n let count = 0;\n let current = this._head;\n\n while ((current = current.next))\n {\n count++;\n }\n\n return count;\n }\n\n /** Starts the ticker. If the ticker has listeners a new animation frame is requested at this point. */\n start(): void\n {\n if (!this.started)\n {\n this.started = true;\n this._requestIfNeeded();\n }\n }\n\n /** Stops the ticker. If the ticker has requested an animation frame it is canceled at this point. */\n stop(): void\n {\n if (this.started)\n {\n this.started = false;\n this._cancelIfNeeded();\n }\n }\n\n /** Destroy the ticker and don't use after this. Calling this method removes all references to internal events. */\n destroy(): void\n {\n if (!this._protected)\n {\n this.stop();\n\n let listener = this._head.next;\n\n while (listener)\n {\n listener = listener.destroy(true);\n }\n\n this._head.destroy();\n this._head = null;\n }\n }\n\n /**\n * Triggers an update. An update entails setting the\n * current {@link PIXI.Ticker#elapsedMS},\n * the current {@link PIXI.Ticker#deltaTime},\n * invoking all listeners with current deltaTime,\n * and then finally setting {@link PIXI.Ticker#lastTime}\n * with the value of currentTime that was provided.\n * This method will be called automatically by animation\n * frame callbacks if the ticker instance has been started\n * and listeners are added.\n * @param {number} [currentTime=performance.now()] - the current time of execution\n */\n update(currentTime = performance.now()): void\n {\n let elapsedMS;\n\n // If the difference in time is zero or negative, we ignore most of the work done here.\n // If there is no valid difference, then should be no reason to let anyone know about it.\n // A zero delta, is exactly that, nothing should update.\n //\n // The difference in time can be negative, and no this does not mean time traveling.\n // This can be the result of a race condition between when an animation frame is requested\n // on the current JavaScript engine event loop, and when the ticker's start method is invoked\n // (which invokes the internal _requestIfNeeded method). If a frame is requested before\n // _requestIfNeeded is invoked, then the callback for the animation frame the ticker requests,\n // can receive a time argument that can be less than the lastTime value that was set within\n // _requestIfNeeded. This difference is in microseconds, but this is enough to cause problems.\n //\n // This check covers this browser engine timing issue, as well as if consumers pass an invalid\n // currentTime value. This may happen if consumers opt-out of the autoStart, and update themselves.\n\n if (currentTime > this.lastTime)\n {\n // Save uncapped elapsedMS for measurement\n elapsedMS = this.elapsedMS = currentTime - this.lastTime;\n\n // cap the milliseconds elapsed used for deltaTime\n if (elapsedMS > this._maxElapsedMS)\n {\n elapsedMS = this._maxElapsedMS;\n }\n\n elapsedMS *= this.speed;\n\n // If not enough time has passed, exit the function.\n // Get ready for next frame by setting _lastFrame, but based on _minElapsedMS\n // adjustment to ensure a relatively stable interval.\n if (this._minElapsedMS)\n {\n const delta = currentTime - this._lastFrame | 0;\n\n if (delta < this._minElapsedMS)\n {\n return;\n }\n\n this._lastFrame = currentTime - (delta % this._minElapsedMS);\n }\n\n this.deltaMS = elapsedMS;\n this.deltaTime = this.deltaMS * Ticker.targetFPMS;\n\n // Cache a local reference, in-case ticker is destroyed\n // during the emit, we can still check for head.next\n const head = this._head;\n\n // Invoke listeners added to internal emitter\n let listener = head.next;\n\n while (listener)\n {\n listener = listener.emit(this.deltaTime);\n }\n\n if (!head.next)\n {\n this._cancelIfNeeded();\n }\n }\n else\n {\n this.deltaTime = this.deltaMS = this.elapsedMS = 0;\n }\n\n this.lastTime = currentTime;\n }\n\n /**\n * The frames per second at which this ticker is running.\n * The default is approximately 60 in most modern browsers.\n * **Note:** This does not factor in the value of\n * {@link PIXI.Ticker#speed}, which is specific\n * to scaling {@link PIXI.Ticker#deltaTime}.\n * @member {number}\n * @readonly\n */\n get FPS(): number\n {\n return 1000 / this.elapsedMS;\n }\n\n /**\n * Manages the maximum amount of milliseconds allowed to\n * elapse between invoking {@link PIXI.Ticker#update}.\n * This value is used to cap {@link PIXI.Ticker#deltaTime},\n * but does not effect the measured value of {@link PIXI.Ticker#FPS}.\n * When setting this property it is clamped to a value between\n * `0` and `Ticker.targetFPMS * 1000`.\n * @member {number}\n * @default 10\n */\n get minFPS(): number\n {\n return 1000 / this._maxElapsedMS;\n }\n\n set minFPS(fps: number)\n {\n // Minimum must be below the maxFPS\n const minFPS = Math.min(this.maxFPS, fps);\n\n // Must be at least 0, but below 1 / Ticker.targetFPMS\n const minFPMS = Math.min(Math.max(0, minFPS) / 1000, Ticker.targetFPMS);\n\n this._maxElapsedMS = 1 / minFPMS;\n }\n\n /**\n * Manages the minimum amount of milliseconds required to\n * elapse between invoking {@link PIXI.Ticker#update}.\n * This will effect the measured value of {@link PIXI.Ticker#FPS}.\n * If it is set to `0`, then there is no limit; PixiJS will render as many frames as it can.\n * Otherwise it will be at least `minFPS`\n * @member {number}\n * @default 0\n */\n get maxFPS(): number\n {\n if (this._minElapsedMS)\n {\n return Math.round(1000 / this._minElapsedMS);\n }\n\n return 0;\n }\n\n set maxFPS(fps: number)\n {\n if (fps === 0)\n {\n this._minElapsedMS = 0;\n }\n else\n {\n // Max must be at least the minFPS\n const maxFPS = Math.max(this.minFPS, fps);\n\n this._minElapsedMS = 1 / (maxFPS / 1000);\n }\n }\n\n /**\n * The shared ticker instance used by {@link PIXI.AnimatedSprite} and by\n * {@link PIXI.VideoResource} to update animation frames / video textures.\n *\n * It may also be used by {@link PIXI.Application} if created with the `sharedTicker` option property set to true.\n *\n * The property {@link PIXI.Ticker#autoStart} is set to `true` for this instance.\n * Please follow the examples for usage, including how to opt-out of auto-starting the shared ticker.\n * @example\n * import { Ticker } from 'pixi.js';\n *\n * const ticker = Ticker.shared;\n * // Set this to prevent starting this ticker when listeners are added.\n * // By default this is true only for the PIXI.Ticker.shared instance.\n * ticker.autoStart = false;\n *\n * // FYI, call this to ensure the ticker is stopped. It should be stopped\n * // if you have not attempted to render anything yet.\n * ticker.stop();\n *\n * // Call this when you are ready for a running shared ticker.\n * ticker.start();\n * @example\n * import { autoDetectRenderer, Container } from 'pixi.js';\n *\n * // You may use the shared ticker to render...\n * const renderer = autoDetectRenderer();\n * const stage = new Container();\n * document.body.appendChild(renderer.view);\n * ticker.add((time) => renderer.render(stage));\n *\n * // Or you can just update it manually.\n * ticker.autoStart = false;\n * ticker.stop();\n * const animate = (time) => {\n * ticker.update(time);\n * renderer.render(stage);\n * requestAnimationFrame(animate);\n * };\n * animate(performance.now());\n * @member {PIXI.Ticker}\n * @static\n */\n static get shared(): Ticker\n {\n if (!Ticker._shared)\n {\n const shared = Ticker._shared = new Ticker();\n\n shared.autoStart = true;\n shared._protected = true;\n }\n\n return Ticker._shared;\n }\n\n /**\n * The system ticker instance used by {@link PIXI.BasePrepare} for core timing\n * functionality that shouldn't usually need to be paused, unlike the `shared`\n * ticker which drives visual animations and rendering which may want to be paused.\n *\n * The property {@link PIXI.Ticker#autoStart} is set to `true` for this instance.\n * @member {PIXI.Ticker}\n * @static\n */\n static get system(): Ticker\n {\n if (!Ticker._system)\n {\n const system = Ticker._system = new Ticker();\n\n system.autoStart = true;\n system._protected = true;\n }\n\n return Ticker._system;\n }\n}\n"],"names":["_Ticker"],"mappings":";;AAaO,MAAM,UAAN,MAAMA,SACb;AAAA,EAqGI,cACA;AArFA,SAAO,YAAY,IAOnB,KAAO,YAAY,GA6BnB,KAAO,WAAW,IAQlB,KAAO,QAAQ,GASf,KAAO,UAAU,IAKjB,KAAQ,aAAqB,MAK7B,KAAQ,gBAAgB,KAKxB,KAAQ,gBAAgB,GAExB,KAAQ,aAAa,IAErB,KAAQ,aAAa,IAcZ,KAAA,QAAQ,IAAI,eAAe,MAAM,MAAM,IAAQ,CAAA,GACpD,KAAK,UAAU,IAAIA,SAAO,YAC1B,KAAK,YAAY,IAAIA,SAAO,YAE5B,KAAK,QAAQ,CAAC,SACd;AACS,WAAA,aAAa,MAEd,KAAK,YAGL,KAAK,OAAO,IAAI,GAEZ,KAAK,WAAW,KAAK,eAAe,QAAQ,KAAK,MAAM,SAEvD,KAAK,aAAa,sBAAsB,KAAK,KAAK;AAAA,IAAA;AAAA,EAIlE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,mBACR;AACQ,SAAK,eAAe,QAAQ,KAAK,MAAM,SAGvC,KAAK,WAAW,YAAY,OAC5B,KAAK,aAAa,KAAK,UACvB,KAAK,aAAa,sBAAsB,KAAK,KAAK;AAAA,EAE1D;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,kBACR;AACQ,SAAK,eAAe,SAEpB,qBAAqB,KAAK,UAAU,GACpC,KAAK,aAAa;AAAA,EAE1B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWQ,mBACR;AACQ,SAAK,UAEL,KAAK,iBAAA,IAEA,KAAK,aAEV,KAAK;EAEb;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,IAAa,IAAuB,SAAa,WAAW,gBAAgB,QAC5E;AACI,WAAO,KAAK,aAAa,IAAI,eAAe,IAAI,SAAS,QAAQ,CAAC;AAAA,EACtE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,QAAiB,IAAuB,SAAa,WAAW,gBAAgB,QAChF;AACW,WAAA,KAAK,aAAa,IAAI,eAAe,IAAI,SAAS,UAAU,EAAI,CAAC;AAAA,EAC5E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUQ,aAAa,UACrB;AAEI,QAAI,UAAU,KAAK,MAAM,MACrB,WAAW,KAAK;AAGpB,QAAI,CAAC;AAED,eAAS,QAAQ,QAAQ;AAAA,SAG7B;AAEI,aAAO,WACP;AACQ,YAAA,SAAS,WAAW,QAAQ,UAChC;AACI,mBAAS,QAAQ,QAAQ;AACzB;AAAA,QACJ;AACW,mBAAA,SACX,UAAU,QAAQ;AAAA,MACtB;AAGK,eAAS,YAEV,SAAS,QAAQ,QAAQ;AAAA,IAEjC;AAEA,WAAA,KAAK,iBAEE,GAAA;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAgB,IAAuB,SACvC;AACQ,QAAA,WAAW,KAAK,MAAM;AAEnB,WAAA;AAKC,eAAS,MAAM,IAAI,OAAO,IAE1B,WAAW,SAAS,QAIpB,IAAA,WAAW,SAAS;AAI5B,WAAK,KAAK,MAAM,QAEZ,KAAK,gBAGF,GAAA;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAI,QACJ;AACI,QAAI,CAAC,KAAK;AAEC,aAAA;AAGP,QAAA,QAAQ,GACR,UAAU,KAAK;AAEnB,WAAQ,UAAU,QAAQ;AAEtB;AAGG,WAAA;AAAA,EACX;AAAA;AAAA,EAGA,QACA;AACS,SAAK,YAEN,KAAK,UAAU,IACf,KAAK,iBAAiB;AAAA,EAE9B;AAAA;AAAA,EAGA,OACA;AACQ,SAAK,YAEL,KAAK,UAAU,IACf,KAAK,gBAAgB;AAAA,EAE7B;AAAA;AAAA,EAGA,UACA;AACQ,QAAA,CAAC,KAAK,YACV;AACI,WAAK,KAAK;AAEN,UAAA,WAAW,KAAK,MAAM;AAEnB,aAAA;AAEQ,mBAAA,SAAS,QAAQ,EAAI;AAGpC,WAAK,MAAM,QAAA,GACX,KAAK,QAAQ;AAAA,IACjB;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,OAAO,cAAc,YAAY,OACjC;AACQ,QAAA;AAiBA,QAAA,cAAc,KAAK,UACvB;AAeI,UAbA,YAAY,KAAK,YAAY,cAAc,KAAK,UAG5C,YAAY,KAAK,kBAEjB,YAAY,KAAK,gBAGrB,aAAa,KAAK,OAKd,KAAK,eACT;AACU,cAAA,QAAQ,cAAc,KAAK,aAAa;AAE9C,YAAI,QAAQ,KAAK;AAEb;AAGC,aAAA,aAAa,cAAe,QAAQ,KAAK;AAAA,MAClD;AAEA,WAAK,UAAU,WACf,KAAK,YAAY,KAAK,UAAUA,SAAO;AAIvC,YAAM,OAAO,KAAK;AAGlB,UAAI,WAAW,KAAK;AAEb,aAAA;AAEQ,mBAAA,SAAS,KAAK,KAAK,SAAS;AAGtC,WAAK,QAEN,KAAK;IAEb;AAGI,WAAK,YAAY,KAAK,UAAU,KAAK,YAAY;AAGrD,SAAK,WAAW;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,IAAI,MACJ;AACI,WAAO,MAAO,KAAK;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,IAAI,SACJ;AACI,WAAO,MAAO,KAAK;AAAA,EACvB;AAAA,EAEA,IAAI,OAAO,KACX;AAEI,UAAM,SAAS,KAAK,IAAI,KAAK,QAAQ,GAAG,GAGlC,UAAU,KAAK,IAAI,KAAK,IAAI,GAAG,MAAM,IAAI,KAAMA,SAAO,UAAU;AAEtE,SAAK,gBAAgB,IAAI;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,IAAI,SACJ;AACI,WAAI,KAAK,gBAEE,KAAK,MAAM,MAAO,KAAK,aAAa,IAGxC;AAAA,EACX;AAAA,EAEA,IAAI,OAAO,KACX;AACI,QAAI,QAAQ;AAER,WAAK,gBAAgB;AAAA,SAGzB;AAEI,YAAM,SAAS,KAAK,IAAI,KAAK,QAAQ,GAAG;AAEnC,WAAA,gBAAgB,KAAK,SAAS;AAAA,IACvC;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA6CA,WAAW,SACX;AACQ,QAAA,CAACA,SAAO,SACZ;AACI,YAAM,SAASA,SAAO,UAAU,IAAIA,SAAO;AAEpC,aAAA,YAAY,IACnB,OAAO,aAAa;AAAA,IACxB;AAEA,WAAOA,SAAO;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,WAAW,SACX;AACQ,QAAA,CAACA,SAAO,SACZ;AACI,YAAM,SAASA,SAAO,UAAU,IAAIA,SAAO;AAEpC,aAAA,YAAY,IACnB,OAAO,aAAa;AAAA,IACxB;AAEA,WAAOA,SAAO;AAAA,EAClB;AACJ;AApkBa,QAMK,aAAa;AANxB,IAAM,SAAN;"} |