UNPKG

listine

Version:

Angular virtual scroll component supporting variable item heights.

1 lines 19.1 kB
{"version":3,"file":"listine.mjs","sources":["../../../projects/listine/src/lib/listtine-virtual/variable-virtual-scroll/listine-virtual-scroll.component.ts","../../../projects/listine/src/lib/listtine-virtual/variable-virtual-scroll/listine-virtual-scroll.component.html","../../../projects/listine/src/public-api.ts","../../../projects/listine/src/listine.ts"],"sourcesContent":["import { NgTemplateOutlet } from '@angular/common';\nimport {\n afterNextRender,\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n Component,\n DestroyRef,\n effect,\n ElementRef,\n inject,\n input,\n NgZone,\n output,\n signal,\n TemplateRef,\n untracked,\n viewChild,\n viewChildren,\n} from '@angular/core';\n\n/**\n * `s73-variable-virtual-scroll`\n *\n * A lightweight, customizable virtual scroll component that supports variable item heights.\n * Efficiently renders only visible items to improve performance for large lists.\n *\n * ## Inputs:\n * - `items`: List of data items to display\n * - `viewportHeight`: Height of the scrollable container (default: 400px)\n * - `buffer`: Number of extra items rendered above and below the viewport for smooth scrolling (default: 5)\n * - `itemTemplate`: Angular template for rendering each item\n * - `initialItemHeight`: Default item height before measurement (default: 50px)\n * - `scrollResetTrigger`: Increment (or any new value) to run `scrollToTop()` when the list should jump back to the top (e.g. after filter/search).\n *\n * ## Outputs:\n * - `scrollEmitter`: Emits scroll position on every scroll event\n */\n@Component({\n selector: 'listine-variable-virtual-scroll',\n imports: [NgTemplateOutlet],\n standalone: true,\n templateUrl: './listine-virtual-scroll.component.html',\n styleUrls: ['./listine-virtual-scroll.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class VariableVirtualScrollComponent {\n private ngZone = inject(NgZone);\n private destroyRef = inject(DestroyRef);\n private changeDetectorRef = inject(ChangeDetectorRef);\n\n /**\n * Running maximum of measured row heights. Used when `items` is replaced so new estimates\n * are not stuck at `initialItemHeight` while real rows are taller (prevents overlap during fast filter).\n */\n private peakMeasuredItemHeight = 0;\n\n /** List of all items to render */\n readonly items = input<any[]>([]);\n\n /** Height of the scrollable viewport in pixels */\n readonly viewportHeight = input(400);\n\n /** Number of extra items to render above and below the viewport */\n readonly buffer = input(5);\n\n /** Template reference for rendering each item */\n readonly itemTemplate = input.required<TemplateRef<any>>();\n\n /** Flag to track if panel is open */\n readonly panelOpen = input(false);\n\n /** Initial estimated height of each item before actual measurement */\n readonly initialItemHeight = input(50);\n\n /**\n * Bump this value whenever the list should reset to the top (calls `scrollToTop()`).\n * Does not scroll on the initial value; only when the bound value changes.\n */\n readonly scrollToTopTrigger = input(0);\n\n /** Emits scroll position whenever user scrolls */\n readonly scrollEmitter = output<any>();\n\n /** Emits when user scrolls to the end of the list */\n readonly scrollToEnd = output<void>();\n\n /** Reference to the scrolling container */\n readonly scrollerRef = viewChild<ElementRef<HTMLDivElement>>('scroller');\n\n /** Rendered item elements (used for height measurement) */\n readonly itemElements = viewChildren<ElementRef<HTMLDivElement>>('itemElement');\n\n /** Stores measured heights of items */\n readonly itemHeights = signal<number[]>([]);\n\n /** Stores calculated top offset for each item */\n readonly itemTops = signal<number[]>([]);\n\n /** Total height of all items (used to simulate full scrollable area) */\n readonly totalContentHeight = signal(0);\n\n /** Index of the first visible item (including buffer) */\n readonly visibleStart = signal(0);\n\n /** Index of the last visible item (including buffer) */\n readonly visibleEnd = signal(0);\n\n /** Items currently visible in the viewport */\n readonly visibleItems = signal<any[]>([]);\n\n /** ResizeObserver to watch for item height changes (deferred measure, matching legacy pattern). */\n protected resizeObserver = new ResizeObserver(() => {\n this.ngZone.run(() => {\n requestAnimationFrame(() => {\n this.ngZone.run(() => {\n this.measureItemHeights();\n });\n });\n });\n });\n\n /** Previous scroll position to detect actual scrolling */\n private previousScrollTop = 0;\n\n /** Last seen `scrollResetTrigger` to detect changes without firing on first run */\n private previousScrollResetTrigger: number | undefined;\n\n constructor() {\n this.destroyRef.onDestroy(() => this.resizeObserver.disconnect());\n\n afterNextRender(() => {\n this.calculateHeights();\n this.onScroll();\n });\n\n effect(() => {\n this.items();\n untracked(() => {\n this.initializeHeights();\n this.calculateHeights();\n this.onScroll();\n });\n });\n\n effect(() => {\n if (this.panelOpen()) {\n untracked(() => {\n queueMicrotask(() => this.onScroll());\n });\n }\n });\n\n effect(() => {\n const trigger = this.scrollToTopTrigger();\n untracked(() => {\n if (this.previousScrollResetTrigger !== undefined && trigger !== this.previousScrollResetTrigger) {\n // Run after `items` and the host view have settled so `#scroller` exists and scrollTop applies.\n queueMicrotask(() => this.scrollToTop());\n }\n this.previousScrollResetTrigger = trigger;\n });\n });\n }\n\n /** Initializes item height and position tracking arrays from `items` (`itemHeights.length` matches `items.length`). */\n protected initializeHeights(): void {\n const list = this.items() ?? [];\n const estimate = Math.max(this.initialItemHeight(), this.peakMeasuredItemHeight);\n this.itemHeights.set(list.map(() => estimate));\n this.updateItemTops();\n }\n\n /** Resets scroll to top and rebuilds height estimates (e.g. after filter/search). */\n scrollToTop(): void {\n const el = this.scrollerRef()?.nativeElement;\n if (el) {\n el.scrollTop = 0;\n }\n this.previousScrollTop = 0;\n this.onScroll();\n }\n\n /** Recalculates item top positions and content height */\n protected calculateHeights() {\n this.updateItemTops();\n }\n\n /** Updates top positions of all items based on their current heights */\n protected updateItemTops() {\n const tops: number[] = [];\n let top = 0;\n for (const height of this.itemHeights()) {\n tops.push(top);\n top += height;\n }\n this.itemTops.set(tops);\n this.totalContentHeight.set(top);\n }\n\n /**\n * Returns the top position of an item by index\n * @param index - index of the item\n */\n protected getItemTop(index: number): number {\n return this.itemTops()[index] ?? 0;\n }\n\n /** Scroll event handler: calculates which items should be visible */\n protected onScroll() {\n const el = this.scrollerRef()?.nativeElement;\n if (!el) {\n return;\n }\n\n const scrollTop = el.scrollTop;\n const viewportBottom = scrollTop + this.viewportHeight();\n const list = this.items() ?? [];\n const buf = this.buffer();\n\n let start = 0;\n while (start < list.length && this.getItemTop(start + 1) < scrollTop) {\n start++;\n }\n\n let end = start;\n while (end < list.length && this.getItemTop(end) < viewportBottom) {\n end++;\n }\n this.visibleStart.set(Math.max(0, start - buf));\n this.visibleEnd.set(Math.min(list.length, end + buf));\n this.updateVisibleItems();\n this.scrollEmitter.emit(scrollTop);\n\n const scrollHeight = el.scrollHeight;\n const clientHeight = el.clientHeight;\n const isAtEnd = scrollTop + clientHeight >= scrollHeight - 1;\n\n if (isAtEnd && scrollTop > this.previousScrollTop && scrollTop > 0) {\n this.scrollToEnd.emit();\n }\n\n this.previousScrollTop = scrollTop;\n }\n\n /** Updates the list of items to be rendered based on scroll position */\n protected updateVisibleItems() {\n const list = this.items() ?? [];\n this.visibleItems.set(list.slice(this.visibleStart(), this.visibleEnd()));\n\n // Run a sync CD pass so `#itemElement` nodes exist, measure, then remeasure on the next frame after layout/fonts settle.\n queueMicrotask(() => {\n this.ngZone.run(() => {\n this.changeDetectorRef.detectChanges();\n this.measureItemHeights();\n requestAnimationFrame(() => {\n this.ngZone.run(() => this.measureItemHeights());\n });\n });\n });\n }\n\n /** Measures actual heights of rendered DOM elements and updates tracking */\n measureItemHeights() {\n const start = this.visibleStart();\n const next = [...this.itemHeights()];\n let changed = false;\n\n this.itemElements().forEach((el, idx) => {\n const index = start + idx;\n const height = el.nativeElement.offsetHeight;\n if (height > 0) {\n this.peakMeasuredItemHeight = Math.max(this.peakMeasuredItemHeight, height);\n }\n if (next[index] !== height) {\n next[index] = height;\n changed = true;\n this.resizeObserver.observe(el.nativeElement);\n }\n });\n\n if (changed) {\n this.itemHeights.set(next);\n }\n this.updateItemTops();\n }\n}\n","<div #scroller class=\"scroll-container\" (scroll)=\"onScroll()\" [style.height.px]=\"viewportHeight()\">\n <!-- totalContentHeight -->\n <div class=\"total-height\" [style.height.px]=\"viewportHeight()\">\n @for (item of visibleItems(); track item; let i = $index) {\n <div #itemElement class=\"item\" [style.transform]=\"'translateY(' + getItemTop(visibleStart() + i) + 'px)'\">\n <ng-container\n *ngTemplateOutlet=\"itemTemplate(); context: { $implicit: item, index: visibleStart() + i }\"\n ></ng-container>\n </div>\n }\n </div>\n</div>\n","/*\n * Public API Surface of Listine\n */\n\nexport * from \"./lib/listtine-virtual/variable-virtual-scroll/listine-virtual-scroll.component\";\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;AAoBA;;;;;;;;;;;;;;;;AAgBG;MASU,8BAA8B,CAAA;AACjC,IAAA,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;AACvB,IAAA,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;AAC/B,IAAA,iBAAiB,GAAG,MAAM,CAAC,iBAAiB,CAAC;AAErD;;;AAGG;IACK,sBAAsB,GAAG,CAAC;;AAGzB,IAAA,KAAK,GAAG,KAAK,CAAQ,EAAE,4EAAC;;AAGxB,IAAA,cAAc,GAAG,KAAK,CAAC,GAAG,qFAAC;;AAG3B,IAAA,MAAM,GAAG,KAAK,CAAC,CAAC,6EAAC;;AAGjB,IAAA,YAAY,GAAG,KAAK,CAAC,QAAQ,kFAAoB;;AAGjD,IAAA,SAAS,GAAG,KAAK,CAAC,KAAK,gFAAC;;AAGxB,IAAA,iBAAiB,GAAG,KAAK,CAAC,EAAE,wFAAC;AAEtC;;;AAGG;AACM,IAAA,kBAAkB,GAAG,KAAK,CAAC,CAAC,yFAAC;;IAG7B,aAAa,GAAG,MAAM,EAAO;;IAG7B,WAAW,GAAG,MAAM,EAAQ;;AAG5B,IAAA,WAAW,GAAG,SAAS,CAA6B,UAAU,kFAAC;;AAG/D,IAAA,YAAY,GAAG,YAAY,CAA6B,aAAa,mFAAC;;AAGtE,IAAA,WAAW,GAAG,MAAM,CAAW,EAAE,kFAAC;;AAGlC,IAAA,QAAQ,GAAG,MAAM,CAAW,EAAE,+EAAC;;AAG/B,IAAA,kBAAkB,GAAG,MAAM,CAAC,CAAC,yFAAC;;AAG9B,IAAA,YAAY,GAAG,MAAM,CAAC,CAAC,mFAAC;;AAGxB,IAAA,UAAU,GAAG,MAAM,CAAC,CAAC,iFAAC;;AAGtB,IAAA,YAAY,GAAG,MAAM,CAAQ,EAAE,mFAAC;;AAG/B,IAAA,cAAc,GAAG,IAAI,cAAc,CAAC,MAAK;AACjD,QAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAK;YACnB,qBAAqB,CAAC,MAAK;AACzB,gBAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAK;oBACnB,IAAI,CAAC,kBAAkB,EAAE;AAC3B,gBAAA,CAAC,CAAC;AACJ,YAAA,CAAC,CAAC;AACJ,QAAA,CAAC,CAAC;AACJ,IAAA,CAAC,CAAC;;IAGM,iBAAiB,GAAG,CAAC;;AAGrB,IAAA,0BAA0B;AAElC,IAAA,WAAA,GAAA;AACE,QAAA,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,MAAM,IAAI,CAAC,cAAc,CAAC,UAAU,EAAE,CAAC;QAEjE,eAAe,CAAC,MAAK;YACnB,IAAI,CAAC,gBAAgB,EAAE;YACvB,IAAI,CAAC,QAAQ,EAAE;AACjB,QAAA,CAAC,CAAC;QAEF,MAAM,CAAC,MAAK;YACV,IAAI,CAAC,KAAK,EAAE;YACZ,SAAS,CAAC,MAAK;gBACb,IAAI,CAAC,iBAAiB,EAAE;gBACxB,IAAI,CAAC,gBAAgB,EAAE;gBACvB,IAAI,CAAC,QAAQ,EAAE;AACjB,YAAA,CAAC,CAAC;AACJ,QAAA,CAAC,CAAC;QAEF,MAAM,CAAC,MAAK;AACV,YAAA,IAAI,IAAI,CAAC,SAAS,EAAE,EAAE;gBACpB,SAAS,CAAC,MAAK;oBACb,cAAc,CAAC,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;AACvC,gBAAA,CAAC,CAAC;YACJ;AACF,QAAA,CAAC,CAAC;QAEF,MAAM,CAAC,MAAK;AACV,YAAA,MAAM,OAAO,GAAG,IAAI,CAAC,kBAAkB,EAAE;YACzC,SAAS,CAAC,MAAK;AACb,gBAAA,IAAI,IAAI,CAAC,0BAA0B,KAAK,SAAS,IAAI,OAAO,KAAK,IAAI,CAAC,0BAA0B,EAAE;;oBAEhG,cAAc,CAAC,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;gBAC1C;AACA,gBAAA,IAAI,CAAC,0BAA0B,GAAG,OAAO;AAC3C,YAAA,CAAC,CAAC;AACJ,QAAA,CAAC,CAAC;IACJ;;IAGU,iBAAiB,GAAA;QACzB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE;AAC/B,QAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,iBAAiB,EAAE,EAAE,IAAI,CAAC,sBAAsB,CAAC;AAChF,QAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,QAAQ,CAAC,CAAC;QAC9C,IAAI,CAAC,cAAc,EAAE;IACvB;;IAGA,WAAW,GAAA;QACT,MAAM,EAAE,GAAG,IAAI,CAAC,WAAW,EAAE,EAAE,aAAa;QAC5C,IAAI,EAAE,EAAE;AACN,YAAA,EAAE,CAAC,SAAS,GAAG,CAAC;QAClB;AACA,QAAA,IAAI,CAAC,iBAAiB,GAAG,CAAC;QAC1B,IAAI,CAAC,QAAQ,EAAE;IACjB;;IAGU,gBAAgB,GAAA;QACxB,IAAI,CAAC,cAAc,EAAE;IACvB;;IAGU,cAAc,GAAA;QACtB,MAAM,IAAI,GAAa,EAAE;QACzB,IAAI,GAAG,GAAG,CAAC;QACX,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE;AACvC,YAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;YACd,GAAG,IAAI,MAAM;QACf;AACA,QAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;AACvB,QAAA,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,GAAG,CAAC;IAClC;AAEA;;;AAGG;AACO,IAAA,UAAU,CAAC,KAAa,EAAA;QAChC,OAAO,IAAI,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC;IACpC;;IAGU,QAAQ,GAAA;QAChB,MAAM,EAAE,GAAG,IAAI,CAAC,WAAW,EAAE,EAAE,aAAa;QAC5C,IAAI,CAAC,EAAE,EAAE;YACP;QACF;AAEA,QAAA,MAAM,SAAS,GAAG,EAAE,CAAC,SAAS;QAC9B,MAAM,cAAc,GAAG,SAAS,GAAG,IAAI,CAAC,cAAc,EAAE;QACxD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE;AAC/B,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE;QAEzB,IAAI,KAAK,GAAG,CAAC;AACb,QAAA,OAAO,KAAK,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,SAAS,EAAE;AACpE,YAAA,KAAK,EAAE;QACT;QAEA,IAAI,GAAG,GAAG,KAAK;AACf,QAAA,OAAO,GAAG,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,cAAc,EAAE;AACjE,YAAA,GAAG,EAAE;QACP;AACA,QAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,GAAG,CAAC,CAAC;AAC/C,QAAA,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,GAAG,CAAC,CAAC;QACrD,IAAI,CAAC,kBAAkB,EAAE;AACzB,QAAA,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC;AAElC,QAAA,MAAM,YAAY,GAAG,EAAE,CAAC,YAAY;AACpC,QAAA,MAAM,YAAY,GAAG,EAAE,CAAC,YAAY;QACpC,MAAM,OAAO,GAAG,SAAS,GAAG,YAAY,IAAI,YAAY,GAAG,CAAC;AAE5D,QAAA,IAAI,OAAO,IAAI,SAAS,GAAG,IAAI,CAAC,iBAAiB,IAAI,SAAS,GAAG,CAAC,EAAE;AAClE,YAAA,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE;QACzB;AAEA,QAAA,IAAI,CAAC,iBAAiB,GAAG,SAAS;IACpC;;IAGU,kBAAkB,GAAA;QAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE;QAC/B,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC;;QAGzE,cAAc,CAAC,MAAK;AAClB,YAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAK;AACnB,gBAAA,IAAI,CAAC,iBAAiB,CAAC,aAAa,EAAE;gBACtC,IAAI,CAAC,kBAAkB,EAAE;gBACzB,qBAAqB,CAAC,MAAK;AACzB,oBAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAC;AAClD,gBAAA,CAAC,CAAC;AACJ,YAAA,CAAC,CAAC;AACJ,QAAA,CAAC,CAAC;IACJ;;IAGA,kBAAkB,GAAA;AAChB,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,EAAE;QACjC,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QACpC,IAAI,OAAO,GAAG,KAAK;QAEnB,IAAI,CAAC,YAAY,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,GAAG,KAAI;AACtC,YAAA,MAAM,KAAK,GAAG,KAAK,GAAG,GAAG;AACzB,YAAA,MAAM,MAAM,GAAG,EAAE,CAAC,aAAa,CAAC,YAAY;AAC5C,YAAA,IAAI,MAAM,GAAG,CAAC,EAAE;AACd,gBAAA,IAAI,CAAC,sBAAsB,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,sBAAsB,EAAE,MAAM,CAAC;YAC7E;AACA,YAAA,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,MAAM,EAAE;AAC1B,gBAAA,IAAI,CAAC,KAAK,CAAC,GAAG,MAAM;gBACpB,OAAO,GAAG,IAAI;gBACd,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC,aAAa,CAAC;YAC/C;AACF,QAAA,CAAC,CAAC;QAEF,IAAI,OAAO,EAAE;AACX,YAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;QAC5B;QACA,IAAI,CAAC,cAAc,EAAE;IACvB;wGA/OW,8BAA8B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;4FAA9B,8BAA8B,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,iCAAA,EAAA,MAAA,EAAA,EAAA,KAAA,EAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,UAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,EAAA,iBAAA,EAAA,gBAAA,EAAA,UAAA,EAAA,gBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,YAAA,EAAA,EAAA,iBAAA,EAAA,cAAA,EAAA,UAAA,EAAA,cAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,iBAAA,EAAA,EAAA,iBAAA,EAAA,mBAAA,EAAA,UAAA,EAAA,mBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,kBAAA,EAAA,EAAA,iBAAA,EAAA,oBAAA,EAAA,UAAA,EAAA,oBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,aAAA,EAAA,eAAA,EAAA,WAAA,EAAA,aAAA,EAAA,EAAA,WAAA,EAAA,CAAA,EAAA,YAAA,EAAA,aAAA,EAAA,KAAA,EAAA,IAAA,EAAA,SAAA,EAAA,CAAA,UAAA,CAAA,EAAA,WAAA,EAAA,IAAA,EAAA,QAAA,EAAA,IAAA,EAAA,EAAA,EAAA,YAAA,EAAA,cAAA,EAAA,SAAA,EAAA,CAAA,aAAA,CAAA,EAAA,WAAA,EAAA,IAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EC7C3C,2kBAYA,EAAA,MAAA,EAAA,CAAA,6MAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,ED2BY,gBAAgB,EAAA,QAAA,EAAA,oBAAA,EAAA,MAAA,EAAA,CAAA,yBAAA,EAAA,kBAAA,EAAA,0BAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;4FAMf,8BAA8B,EAAA,UAAA,EAAA,CAAA;kBAR1C,SAAS;+BACE,iCAAiC,EAAA,OAAA,EAClC,CAAC,gBAAgB,CAAC,cACf,IAAI,EAAA,eAAA,EAGC,uBAAuB,CAAC,MAAM,EAAA,QAAA,EAAA,2kBAAA,EAAA,MAAA,EAAA,CAAA,6MAAA,CAAA,EAAA;AA4Cc,SAAA,CAAA,EAAA,cAAA,EAAA,MAAA,EAAA,EAAA,cAAA,EAAA,EAAA,KAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,OAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,cAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,gBAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,MAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,QAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,cAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,EAAA,SAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,WAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,iBAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,mBAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,kBAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,oBAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,aAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,MAAA,EAAA,IAAA,EAAA,CAAA,eAAA,CAAA,EAAA,CAAA,EAAA,WAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,MAAA,EAAA,IAAA,EAAA,CAAA,aAAA,CAAA,EAAA,CAAA,EAAA,WAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,SAAA,EAAA,IAAA,EAAA,CAAA,UAAU,yEAGN,aAAa,EAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,EAAA,EAAA,CAAA;;AE1FhF;;AAEG;;ACFH;;AAEG;;;;"}