@prose-reader/core 1.273.0 → 1.274.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.umd.cjs","sources":["../src/report.ts","../src/utils/dom.ts","../src/utils/frames.ts","../src/enhancers/accessibility.ts","../src/enhancers/chrome.ts","../src/enhancers/events/translateFramePositionIntoPage.ts","../src/enhancers/events/normalizeEventForViewport.ts","../src/enhancers/events/events.ts","../src/utils/objects.ts","../src/utils/rxjs.ts","../src/settings/SettingsManagerOverload.ts","../src/enhancers/fonts/SettingsManager.ts","../src/enhancers/fonts/fonts.ts","../src/enhancers/hotkeys.ts","../src/enhancers/html/links.ts","../src/utils/ReactiveEntity.ts","../src/spineItem/renderer/DocumentRenderer.ts","../src/spineItem/resources/ResourceHandler.ts","../src/enhancers/html/renderer/assets.ts","../src/constants.ts","../src/enhancers/html/renderer/createHtmlPageFromResource.ts","../src/enhancers/html/renderer/attachFrameSrc.ts","../src/enhancers/html/renderer/createFrameElement.ts","../src/enhancers/html/renderer/prePaginated/renderPrePaginated.ts","../src/enhancers/html/renderer/reflowable/styles.ts","../src/enhancers/html/renderer/reflowable/renderReflowable.ts","../src/enhancers/html/renderer/HtmlRenderer.ts","../src/enhancers/html/enhancer.ts","../src/utils/isDefined.ts","../src/spineItem/types.ts","../src/spine/types.ts","../src/utils/coordinates.ts","../src/enhancers/layout/coordinates.ts","../src/enhancers/layout/createMovingSafePan$.ts","../src/enhancers/layout/createPlaceholderPages.ts","../src/enhancers/layout/fixIframeScrollbar.ts","../src/enhancers/layout/fixReflowable.ts","../src/enhancers/layout/flagSpineItems.ts","../src/enhancers/layout/SettingsManager.ts","../src/enhancers/layout/updateSpreadMode.ts","../src/enhancers/layout/layoutEnhancer.ts","../src/enhancers/media/ImageRenderer.ts","../src/enhancers/media/media.ts","../src/enhancers/navigation/links.ts","../src/enhancers/navigation/report.ts","../src/enhancers/navigation/resolvers/getSpineItemPositionForLeftPage.ts","../src/enhancers/navigation/resolvers/getNavigationForLeftSinglePage.ts","../src/enhancers/navigation/resolvers/getNavigationForLeftOrTopPage.ts","../src/enhancers/navigation/resolvers/getSpineItemPositionForRightPage.ts","../src/enhancers/navigation/resolvers/getNavigationForRightOrBottomSinglePage.ts","../src/enhancers/navigation/resolvers/getNavigationForRightOrBottomPage.ts","../src/enhancers/navigation/navigators/manualNavigator.ts","../src/enhancers/navigation/navigators/panNavigator.ts","../src/utils/DestroyableClass.ts","../src/enhancers/navigation/navigators/UserScrollNavigation.ts","../src/enhancers/navigation/state.ts","../src/enhancers/navigation/throttleLock.ts","../src/enhancers/navigation/index.ts","../src/enhancers/pagination/chapters.ts","../src/enhancers/pagination/progression.ts","../src/enhancers/pagination/spine.ts","../src/enhancers/pagination/pagination.ts","../src/cfi/generate.ts","../src/cfi/parse.ts","../src/cfi/resolve.ts","../src/enhancers/pagination/ResourcesLocator.ts","../src/enhancers/pagination/enhancer.ts","../src/enhancers/resources/indexedDB.ts","../src/enhancers/resources/resourcesManager.ts","../src/enhancers/resources/index.ts","../src/enhancers/selection/selection.ts","../src/enhancers/selection/FrameSelectionTracker.ts","../src/enhancers/selection/trackSpineItemSelection.ts","../src/enhancers/selection/selectionEnhancer.ts","../src/enhancers/theme.ts","../src/enhancers/utils.ts","../src/enhancers/webkit.ts","../src/enhancers/zoom/constraints.ts","../src/enhancers/zoom/controlled.ts","../src/types/index.ts","../src/navigation/controllers/ScrollNavigationController.ts","../src/enhancers/zoom/scrollable.ts","../src/enhancers/zoom/ZoomController.ts","../src/enhancers/zoom/index.ts","../src/manifest/isFullyPrePaginated.ts","../src/context/BridgeEvent.ts","../src/context/Context.ts","../src/features/Features.ts","../src/hooks/HookManager.ts","../src/navigation/controllers/positions.ts","../src/navigation/controllers/ControlledNavigationController.ts","../src/navigation/consolidation/withPaginationInfo.ts","../src/navigation/consolidation/consolidateWithPagination.ts","../src/navigation/consolidation/mapUserNavigationToInternal.ts","../src/navigation/consolidation/withCfiPosition.ts","../src/navigation/consolidation/withDirection.ts","../src/navigation/consolidation/withFallbackPosition.ts","../src/navigation/consolidation/withSpineItem.ts","../src/navigation/consolidation/withSpineItemLayoutInfo.ts","../src/navigation/consolidation/withSpineItemPosition.ts","../src/navigation/consolidation/withUrlInfo.ts","../src/navigation/Locker.ts","../src/navigation/restoration/restoreNavigationForControlledPageTurnMode.ts","../src/navigation/restoration/restorePosition.ts","../src/navigation/restoration/withRestoredPosition.ts","../src/navigation/InternalNavigator.ts","../src/spineItem/helpers.ts","../src/spineItem/layout/getPageFromOffset.ts","../src/spineItem/layout/getSafePosition.ts","../src/spineItem/layout/getSpineItemNumberOfPages.ts","../src/spineItem/layout/getSpineItemPageIndexFromSpineItemPosition.ts","../src/spineItem/layout/getSpineItemPositionFromPageIndex.ts","../src/spineItem/locationResolver.ts","../src/spineItem/navigationResolver.ts","../src/navigation/resolvers/fromOutOfBoundsSpinePosition.ts","../src/navigation/resolvers/fromUnboundSpinePosition.ts","../src/navigation/resolvers/getAdjustedPositionForSpread.ts","../src/navigation/resolvers/getNavigationForPosition.ts","../src/navigation/resolvers/getNavigationForSpineItemPage.ts","../src/navigation/resolvers/getNavigationForUrl.ts","../src/navigation/resolvers/getNavigationFromSpineItemPosition.ts","../src/navigation/resolvers/NavigationResolver.ts","../src/navigation/Navigator.ts","../src/pagination/Pagination.ts","../src/pagination/PaginationController.ts","../src/settings/computeSpreadMode.ts","../src/settings/SettingsManager.ts","../src/settings/ReaderSettingsManager.ts","../src/spineItem/renderer/DefaultRenderer.ts","../src/spineItem/SpineItemLayout.ts","../src/spineItem/SpineItem.ts","../src/spine/loader/SpineItemsLoader.ts","../src/viewport/translateSpinePositionToRelativeViewport.ts","../src/viewport/types.ts","../src/spine/locator/getAbsolutePageIndexFromPageIndex.ts","../src/spine/locator/getItemVisibilityForPosition.ts","../src/spine/locator/getSpineItemFromPosition.ts","../src/spine/locator/getSpinePositionFromSpineItemPosition.ts","../src/spine/locator/getVisibleSpineItemsFromPosition.ts","../src/spine/locator/SpineLocator.ts","../src/spine/report.ts","../src/spine/Pages.ts","../src/spine/SpineItemsObserver.ts","../src/spine/SpineLayout.ts","../src/spine/Spine.ts","../src/spine/SpineItemsManager.ts","../src/viewport/Viewport.ts","../src/reader.ts","../src/createReaderWithEnhancer.ts","../src/enhancers/types/enhancer.ts"],"sourcesContent":["const ROOT_NAMESPACE = `@prose-reader/core`\n\nimport { Report as SharedReport } from \"@prose-reader/shared\"\n\nexport const Report = SharedReport.namespace(ROOT_NAMESPACE, undefined, {\n color: `#98cde7`,\n})\n","import { Report } from \"../report\"\n\nconst pointerEvents: string[] = [\n `pointercancel` as const,\n `pointerdown` as const,\n `pointerenter` as const,\n `pointerleave` as const,\n `pointermove` as const,\n `pointerout` as const,\n `pointerover` as const,\n `pointerup` as const,\n // `touchstart` as const,\n // `touchend` as const,\n]\n\nfunction createRangeOrCaretFromPoint(\n doc: Document,\n startX: number,\n startY: number,\n) {\n // @see https://developer.mozilla.org/en-US/docs/Web/API/Document/caretPositionFromPoint\n if (`caretPositionFromPoint` in doc) {\n // @see https://developer.mozilla.org/en-US/docs/Web/API/CaretPosition\n return doc.caretPositionFromPoint(startX, startY) as {\n offsetNode: Node\n offset: number\n }\n }\n if (\n \"caretRangeFromPoint\" in doc &&\n // @ts-expect-error limited availability\n typeof doc.caretRangeFromPoint !== \"undefined\"\n ) {\n // @ts-expect-error limited availability\n return doc.caretRangeFromPoint(startX, startY)\n }\n}\n\ntype ViewPort = { left: number; right: number; top: number; bottom: number }\n\n/**\n * @todo optimize\n */\nexport const getFirstVisibleNodeForPositionRelativeTo = (\n documentOrElement: Document | Element,\n viewport: ViewPort,\n) => {\n const ownerDocument =\n `createRange` in documentOrElement\n ? documentOrElement\n : documentOrElement.ownerDocument\n\n if (!ownerDocument) return undefined\n\n const element =\n `body` in documentOrElement\n ? getFirstVisibleElementForViewport(documentOrElement.body, viewport)\n : getFirstVisibleElementForViewport(documentOrElement, viewport)\n\n if (element) {\n let lastValidRange: Range | undefined\n let lastValidOffset = 0\n const range = ownerDocument.createRange()\n\n /**\n * We iterate through children to ensure we match the writing mode (direction)\n * of the document (This is easier than having to do some heuristics to match the direction)\n * Although probably not perfect ?\n */\n Array.from(element.childNodes).some((childNode) => {\n range.selectNodeContents(childNode)\n\n const rects = range.getClientRects() // this forces layout ? needs to find better approach\n\n const visibleRect = getFirstVisibleDOMRect(rects, viewport)\n\n // At this point we know the range is valid and contains visible rect.\n // This means we have a valid Node. We still need to know the visible offset to be 100% accurate\n if (visibleRect) {\n lastValidRange = range.cloneRange()\n\n /**\n * Now we will try to refine the search to get the offset\n * this is an incredibly expensive operation so we will try to\n * use native functions to get something\n * @important\n * when using float value it looks like sometime when at the begin of the book the returned range will be the last offset of the page\n * it can be tested with moby-dick.txt by using different font size. Whenever using something different than default font size we might\n * have floating point for font and we start having issue. Using ceil \"make sure\" to be inside the point. Hopefully.\n */\n const rangeOrCaret = createRangeOrCaretFromPoint(\n ownerDocument,\n Math.ceil(visibleRect.left),\n Math.ceil(visibleRect.top),\n )\n\n // good news we found something with same node so we can assume the offset is already better than nothing\n if (\n rangeOrCaret &&\n `startContainer` in rangeOrCaret &&\n rangeOrCaret.startContainer === lastValidRange.startContainer\n ) {\n lastValidOffset = rangeOrCaret.startOffset\n }\n if (\n rangeOrCaret &&\n `offsetNode` in rangeOrCaret &&\n rangeOrCaret.offsetNode === lastValidRange.startContainer\n ) {\n lastValidOffset = rangeOrCaret.offset\n }\n return true\n }\n return false\n })\n\n if (lastValidRange) {\n return {\n node: lastValidRange.startContainer,\n offset: lastValidOffset,\n }\n }\n\n return { node: element, offset: 0 }\n }\n\n return undefined\n}\n\nconst getFirstVisibleElementForViewport = (\n element: Element,\n viewport: ViewPort,\n): Element | undefined => {\n const rect = element.getBoundingClientRect()\n const positionFromViewport = getElementOrNodePositionFromViewPort(\n rect,\n viewport,\n )\n\n let lastValidElement: Element | undefined\n\n /**\n * @important\n * We cannot safely early return if the element is completely outside bounds. This is\n * because a children of that element could very much be positioned outside of its parent.\n *\n * We could do some heuristic assumptions or checking depth but nothing is quite safe at 100%\n */\n\n if (positionFromViewport !== `before` && positionFromViewport !== `after`) {\n lastValidElement = element\n }\n\n for (const child of element.children) {\n const childInViewPort = getFirstVisibleElementForViewport(child, viewport)\n\n if (childInViewPort) {\n return childInViewPort\n }\n }\n\n return lastValidElement\n}\n\nfunction getElementOrNodePositionFromViewPort(\n domRect: DOMRect,\n { left, right }: ViewPort,\n) {\n // horizontal + ltr\n if (domRect.left <= left && domRect.right <= left) return `before`\n if (domRect.left <= left && domRect.right > left && domRect.right <= right)\n return `partially-before`\n if (domRect.left <= right && domRect.right > right) return `partially-after`\n if (domRect.left > right) return `after`\n return `within`\n\n // @todo rtl\n // @todo vertical-lrt\n // @todo vertical-rtl\n}\n\nfunction getFirstVisibleDOMRect(domRect: DOMRectList, viewport: ViewPort) {\n return Array.from(domRect).find((domRect) => {\n const position = getElementOrNodePositionFromViewPort(domRect, viewport)\n\n if (position !== `before` && position !== `after`) {\n return true\n }\n return false\n })\n}\n\nexport const getRangeFromNode = (node: Node, offset: number) => {\n if (\n node.nodeType !== Node.CDATA_SECTION_NODE &&\n node.nodeType !== Node.DOCUMENT_TYPE_NODE\n ) {\n const range = node.ownerDocument?.createRange()\n range?.selectNodeContents(node)\n\n try {\n if (offset <= (range?.endOffset || 0)) {\n range?.setStart(node, offset || 0)\n }\n } catch (e) {\n Report.error(e)\n }\n\n return range\n }\n\n return undefined\n}\n\nexport const isPointerEvent = (event: Event): event is PointerEvent => {\n if (\n (event as PointerEvent)?.target &&\n (event?.target as Element)?.ownerDocument?.defaultView\n ) {\n const eventView = (event?.target as Element)?.ownerDocument\n ?.defaultView as Window & typeof globalThis\n\n if (eventView.PointerEvent && event instanceof eventView.PointerEvent) {\n return true\n }\n }\n\n if ((event as PointerEvent)?.view?.window) {\n const eventView = (event as PointerEvent)?.view as Window &\n typeof globalThis\n\n if (eventView.PointerEvent && event instanceof eventView.PointerEvent) {\n return true\n }\n }\n\n if (pointerEvents.includes(event.type)) {\n return true\n }\n\n return false\n}\n\nexport const isMouseEvent = (event: Event): event is MouseEvent => {\n if (isPointerEvent(event)) return false\n\n if (\n (event as MouseEvent)?.target &&\n (event?.target as Element)?.ownerDocument?.defaultView\n ) {\n const eventView = (event?.target as Element)?.ownerDocument\n ?.defaultView as Window & typeof globalThis\n\n if (eventView.MouseEvent) {\n return event instanceof eventView.MouseEvent\n }\n }\n\n if ((event as MouseEvent)?.view?.window) {\n const eventView = (event as MouseEvent)?.view as Window & typeof globalThis\n\n if (eventView.MouseEvent) {\n return event instanceof eventView.MouseEvent\n }\n }\n\n return false\n}\n\nexport const isTouchEvent = (event: Event): event is TouchEvent => {\n if (\n (event as TouchEvent)?.target &&\n (event?.target as Element)?.ownerDocument?.defaultView\n ) {\n const eventView = (event?.target as Element)?.ownerDocument\n ?.defaultView as Window & typeof globalThis\n\n if (eventView.TouchEvent) {\n return event instanceof eventView.TouchEvent\n }\n }\n\n if ((event as TouchEvent)?.view?.window) {\n const eventView = (event as TouchEvent)?.view as Window & typeof globalThis\n\n if (eventView.TouchEvent) {\n return event instanceof eventView.TouchEvent\n }\n }\n\n return false\n}\n\nexport const noopElement = () => document.createElement(\"div\")\n\nexport const getElementsWithAssets = (\n _document: Document | null | undefined,\n) => {\n const RESOURCE_ELEMENTS = [\n \"img\", // Images\n \"video\", // Video files\n \"audio\", // Audio files\n \"source\", // Source elements within video/audio\n \"link\", // Stylesheets and other linked resources\n \"script\", // JavaScript files\n ].join(\",\")\n\n return Array.from(_document?.querySelectorAll(RESOURCE_ELEMENTS) || [])\n}\n\n/**\n * Revoke all found blob urls in the document\n * - elements with src or href attribute\n * - stylesheet font-face rules\n */\nexport const revokeDocumentBlobs = (_document: Document | null | undefined) => {\n const elementsWithAsset = getElementsWithAssets(_document)\n\n elementsWithAsset.forEach((element) => {\n const url = element.getAttribute(\"src\") || element.getAttribute(\"href\")\n\n if (url?.startsWith(\"blob:\")) {\n _document?.defaultView?.URL.revokeObjectURL(url)\n }\n })\n\n if (_document) {\n const styleSheets = Array.from(_document.styleSheets || [])\n\n for (const sheet of styleSheets) {\n const rules = Array.from(sheet.cssRules || [])\n\n for (const rule of rules) {\n if (\n _document.defaultView &&\n rule instanceof _document.defaultView.CSSFontFaceRule\n ) {\n // eg:\n // 'url(\"font.woff2\") format(\"woff2\"), url(\"font.woff\") format(\"woff\"), url(blob:http://example.com/1234) format(\"opentype\")'\n // 'url(blob:http://example.com/1234)'\n const src = rule.style.getPropertyValue(\"src\")\n // handle multiple comma-separated sources\n const blobUrls = src.match(/blob:[^,\\s'\")]+/g)\n\n if (blobUrls) {\n blobUrls.forEach((url) => {\n _document?.defaultView?.URL.revokeObjectURL(url)\n })\n }\n }\n }\n }\n }\n}\n\n/**\n * Generic structural type checker - checks if an object has the expected properties\n * @param obj The object to check\n * @param requiredProps Array of property names that must exist\n * @param optionalMethods Array of method names that should be functions (optional)\n */\nexport function hasShape<T>(\n obj: unknown,\n requiredProps: (keyof T)[],\n optionalMethods: (keyof T)[] = [],\n): obj is T {\n if (typeof obj !== \"object\" || obj === null) return false\n\n // Check required properties exist\n for (const prop of requiredProps) {\n if (!(prop in obj)) return false\n }\n\n // Check optional methods are functions\n for (const method of optionalMethods) {\n // biome-ignore lint/suspicious/noExplicitAny: TODO\n if (method in obj && typeof (obj as any)[method] !== \"function\") {\n return false\n }\n }\n\n return true\n}\n\n/**\n * Global env agnostic method to detect if an element is HtmlElement.\n *\n * @example\n * checking instance of element from iframe will not work because\n * `window.HtmlElement` is not the same as iframe.window.HtmlElement\n * element instanceof HtmlElement -> false\n *\n * isHtmlElement(element) -> true\n */\nexport function isHtmlElement(element: unknown): element is HTMLElement {\n return (\n hasShape<HTMLElement>(\n element,\n [\"nodeType\"],\n [],\n // biome-ignore lint/suspicious/noExplicitAny: TODO\n ) && (element as any).nodeType === Node.ELEMENT_NODE\n )\n}\n\n/**\n * Type guard function to check if an element is a specific HTML tag element\n * @param element The element to check\n * @param tagName The HTML tag name (e.g., 'div', 'span', 'a')\n * @returns True if the element is an HTMLElement of the specified tag\n */\nexport function isHtmlTagElement<K extends keyof HTMLElementTagNameMap>(\n element: unknown,\n tagName: K,\n): element is HTMLElementTagNameMap[K] {\n return (\n isHtmlElement(element) &&\n element.tagName.toLowerCase() === tagName.toLowerCase()\n )\n}\n\nexport function isHtmlRange(element: unknown): element is Range {\n return hasShape<Range>(\n element,\n [\n \"startContainer\",\n \"endContainer\",\n \"startOffset\",\n \"endOffset\",\n \"collapsed\",\n \"commonAncestorContainer\",\n ],\n [\"setStart\", \"setEnd\", \"selectNodeContents\"],\n )\n}\n\nexport const injectCSS = (\n doc: Document,\n id: string,\n style: string,\n prepend?: boolean,\n) => {\n const userStyle = doc.createElement(`style`)\n userStyle.id = id\n userStyle.innerHTML = style\n\n if (prepend) {\n doc.head.prepend(userStyle)\n } else {\n doc.head.appendChild(userStyle)\n }\n\n return () => {\n removeCSS(doc, id)\n }\n}\n\nexport const removeCSS = (doc: Document, id: string) => {\n if (doc?.head) {\n const styleElement = doc.getElementById(id)\n\n if (styleElement) {\n styleElement.remove()\n }\n }\n}\n","import {\n from,\n fromEvent,\n map,\n type Observable,\n of,\n switchMap,\n take,\n} from \"rxjs\"\nimport {\n injectCSS as injectCSSToDocument,\n removeCSS as removeCSSToDocument,\n} from \"./dom\"\n\nexport const getAttributeValueFromString = (string: string, key: string) => {\n const regExp = new RegExp(`${key}\\\\s*=\\\\s*([0-9.]+)`, `i`)\n const match = string.match(regExp) || []\n const firstMatch = match[1] || `0`\n\n return (match && Number.parseFloat(firstMatch)) || 0\n}\n\nexport const injectCSSToFrame = (\n frameElement: HTMLIFrameElement,\n id: string,\n style: string,\n prepend?: boolean,\n) => {\n if (!frameElement?.contentDocument?.head) return\n\n injectCSSToDocument(frameElement.contentDocument, id, style, prepend)\n}\n\nexport const removeCSS = (frameElement: HTMLIFrameElement, id: string) => {\n if (!frameElement?.contentDocument) return\n\n removeCSSToDocument(frameElement.contentDocument, id)\n}\n\nexport const upsertCSSToFrame = (\n frameElement: HTMLIFrameElement | undefined,\n id: string,\n style: string,\n prepend?: boolean,\n) => {\n if (!frameElement) return\n\n const existingElement = frameElement?.contentDocument?.getElementById(\n id,\n ) as HTMLStyleElement\n\n if (existingElement) {\n existingElement.innerHTML = style\n return\n }\n\n injectCSSToFrame(frameElement, id, style, prepend)\n}\n\nexport const getFrameViewportInfo = (frame: HTMLIFrameElement | undefined) => {\n if (frame?.contentDocument) {\n const doc = frame.contentDocument\n const viewportMetaElement = doc.querySelector(`meta[name='viewport']`)\n\n if (viewportMetaElement) {\n const viewportContent = viewportMetaElement.getAttribute(`content`)\n\n if (viewportContent) {\n const width = getAttributeValueFromString(viewportContent, `width`)\n const height = getAttributeValueFromString(viewportContent, `height`)\n\n if (width > 0 && height > 0) {\n return {\n hasViewport: true,\n width: width,\n height: height,\n }\n }\n return { hasViewport: true }\n }\n }\n }\n\n return { hasViewport: false }\n}\n\nexport const waitForFrameLoad = (stream: Observable<HTMLIFrameElement>) =>\n stream.pipe(\n switchMap((frame) => {\n if (\n frame.src === \"about:blank\" &&\n frame.contentDocument?.readyState === \"complete\" &&\n frame.contentDocument.body\n ) {\n return of(frame)\n }\n\n return fromEvent(frame, `load`).pipe(\n take(1),\n map(() => frame),\n )\n }),\n )\n\nexport const waitForFrameReady = (stream: Observable<HTMLIFrameElement>) =>\n stream.pipe(\n switchMap((frame) => {\n const readyPromise = frame?.contentDocument?.fonts.ready\n\n if (readyPromise) {\n return from(readyPromise).pipe(map(() => frame))\n }\n\n return of(undefined)\n }),\n )\n","import { upsertCSSToFrame } from \"../utils/frames\"\nimport type { EnhancerOutput, RootEnhancer } from \"./types/enhancer\"\n\n/**\n *\n */\nexport const accessibilityEnhancer =\n <InheritOptions, InheritOutput extends EnhancerOutput<RootEnhancer>>(\n next: (options: InheritOptions) => InheritOutput,\n ) =>\n (options: InheritOptions): InheritOutput => {\n const reader = next(options)\n\n const observer = new IntersectionObserver((entries) => {\n entries.forEach((entry) => {\n if (entry.isIntersecting) {\n entry.target.removeAttribute(`tab-index`)\n } else {\n entry.target.setAttribute(`tab-index`, `-1`)\n }\n })\n }, {})\n\n reader.hookManager.register(\n `item.onDocumentLoad`,\n ({ itemId, destroy }) => {\n const item = reader.spineItemsManager.get(itemId)\n\n if (!item) return\n\n const frame = item.renderer.getDocumentFrame()\n\n if (!frame) return\n\n upsertCSSToFrame(\n frame,\n `prose-reader-accessibility`,\n `\n :focus-visible {\n ${\n /*\n Some epubs remove the outline, this is not good practice since it reduce accessibility.\n We will try to restore it by force.\n */ ``\n }\n outline: -webkit-focus-ring-color auto 1px;\n }\n `,\n )\n\n const links = frame.contentDocument?.body.querySelectorAll(`a`)\n\n links?.forEach((link) => {\n observer.observe(link)\n })\n\n destroy(() => {\n links?.forEach((link) => {\n observer.unobserve(link)\n })\n })\n },\n )\n\n return {\n ...reader,\n }\n }\n","import { takeUntil } from \"rxjs\"\nimport type { EnhancerOutput, RootEnhancer } from \"./types/enhancer\"\n\n/**\n * All fixes relative to chromes\n */\nexport const chromeEnhancer =\n <InheritOptions, InheritOutput extends EnhancerOutput<RootEnhancer>>(\n next: (options: InheritOptions) => InheritOutput,\n ) =>\n (options: InheritOptions): InheritOutput => {\n const reader = next(options)\n\n /**\n * This element is used to force a refresh of a screen in order to fix the\n * frozen screen that happens with chrome.\n * The bug is weird and I have yet to explain it correctly, what happens\n * is that sometime when moving the x-axis on navigation, the screen will still display\n * the old screen, as if it was frozen. Generally any interaction with the page will unfreeze\n * the screen and the new iframe will be displayed. It also happens within the same iframe.\n * So far it seems to be due to scaling and x-axis moving.\n * To ensure the screen does not freeze we are moving a 1:1 square in & out of the screen.\n * That way chrome is \"forced\" to refresh the screen.\n *\n * @todo\n * check https://developer.mozilla.org/en-US/docs/Web/CSS/will-change with will-change: transform\n * to see if it does refresh all the time itself.\n *\n * @todo\n * use transform and translate rather than changing top so it only affect composite layer rather than paint\n * @see https://www.algolia.com/blog/engineering/performant-web-animations/\n *\n * @important\n * This is disabled for now as removing will-change on container seems to fix the issue\n */\n // let screenForceRefreshElt: HTMLDivElement | undefined = undefined\n\n reader.context\n .watch(\"rootElement\")\n .pipe(takeUntil(reader.context.destroy$))\n .subscribe((rootElement) => {\n if (!rootElement) return\n\n const onScroll = () => {\n if (reader.settings.values.computedPageTurnMode === `controlled`) {\n rootElement.scrollTo(0, 0)\n }\n }\n\n /**\n * For some reason I have yet to find, chrome will force scroll x-axis on the container\n * whenever the user select text and drag it to the edges. This is not a scroll inside the iframe\n * but a scroll on the container itself..\n */\n rootElement.addEventListener(`scroll`, onScroll)\n })\n\n reader.hookManager.register(`item.onDocumentLoad`, ({ itemId }) => {\n const item = reader.spineItemsManager.get(itemId)\n const frame = item?.renderer.getDocumentFrame()\n\n if (!frame) return\n\n /**\n * Disable touch to search on first text touch / click. This does not prevent\n * it when selecting text. It needs to be turned off by the user.\n * @see https://developers.google.com/web/updates/2015/10/tap-to-search\n */\n frame.contentDocument?.body.setAttribute(`tabindex`, `-1`)\n })\n\n // const forceScreenRefresh$ = reader.$.$\n // .pipe(\n // // filter(event => event.type === `onNavigationChange`),\n // tap(() => {\n // // screenForceRefreshElt?.style.setProperty(`top`, `0px`)\n // // requestAnimationFrame(() => {\n // // screenForceRefreshElt?.style.setProperty(`top`, `-1px`)\n // // })\n // })\n // )\n\n // merge(forceScreenRefresh$)\n // .pipe(takeUntil(reader.$.destroy$))\n // .subscribe()\n\n return reader\n }\n","/**\n * Take the relative position of the event in the iframe and translate\n * it to the page coordinates.\n *\n * For example the page 2 of an iframe could be at x=600 but\n * the cursor on the page would be at x=100. That is for a\n * webpage of 500px of width and not using spread.\n */\nexport const translateFramePositionIntoPage = ({\n position,\n frameElement,\n}: {\n position: {\n clientX: number\n clientY: number\n }\n frameElement: HTMLIFrameElement\n pageWidth: number\n pageHeight: number\n}) => {\n // Get the frame's current transform scale\n const frameRect = frameElement.getBoundingClientRect()\n const scaleX = frameRect.width / frameElement.offsetWidth\n const scaleY = frameRect.height / frameElement.offsetHeight\n\n // Get the frame's position relative to the viewport\n const { left = 0, top = 0 } = frameRect\n\n // Transform the coordinates:\n // 1. Scale the position from iframe coordinates\n // 2. Add the frame's offset relative to viewport\n const adjustedX = position.clientX * scaleX + left\n const adjustedY = position.clientY * scaleY + top\n\n return {\n clientX: adjustedX,\n clientY: adjustedY,\n }\n}\n","import type { SpineLocator } from \"../../spine/locator/SpineLocator\"\nimport { isMouseEvent, isPointerEvent, isTouchEvent } from \"../../utils/dom\"\nimport type { Viewport } from \"../../viewport/Viewport\"\nimport { translateFramePositionIntoPage } from \"./translateFramePositionIntoPage\"\n\nexport const normalizeEventForViewport = <\n E extends MouseEvent | TouchEvent | PointerEvent,\n>(\n event: E,\n iframeOriginalEvent: E,\n locator: SpineLocator,\n viewport: Viewport,\n) => {\n const originalFrame = iframeOriginalEvent?.view?.frameElement\n\n if (!iframeOriginalEvent || !originalFrame) return event\n\n const spineItem = locator.getSpineItemFromIframe(originalFrame)\n const frameElement = originalFrame\n const { height: pageHeight, width: pageWidth } = viewport.pageSize\n\n if (!spineItem || !(frameElement instanceof HTMLIFrameElement)) return event\n\n if (isPointerEvent(event)) {\n const { clientX, clientY } = translateFramePositionIntoPage({\n position: event,\n frameElement,\n pageHeight,\n pageWidth,\n })\n\n const newEvent = new PointerEvent(event.type, {\n ...event,\n pointerId: event.pointerId,\n clientX,\n clientY,\n }) as E\n\n Object.defineProperty(newEvent, `target`, {\n value: iframeOriginalEvent.target,\n enumerable: true,\n })\n\n return newEvent\n }\n\n if (isMouseEvent(event)) {\n const { clientX, clientY } = translateFramePositionIntoPage({\n position: event,\n frameElement,\n pageHeight,\n pageWidth,\n })\n\n const newEvent = new MouseEvent(event.type, {\n ...event,\n clientX,\n clientY,\n }) as E\n\n Object.defineProperty(newEvent, `target`, {\n value: iframeOriginalEvent.target,\n enumerable: true,\n })\n\n return newEvent\n }\n\n if (isTouchEvent(event)) {\n const touches = Array.from(event.touches).map((touch) => {\n const { clientX, clientY } = translateFramePositionIntoPage({\n position: touch,\n frameElement,\n pageHeight,\n pageWidth,\n })\n\n return new Touch({\n identifier: touch.identifier,\n target: touch.target,\n clientX,\n clientY,\n })\n })\n\n const newEvent = new TouchEvent(event.type, {\n touches,\n changedTouches: touches,\n targetTouches: touches,\n }) as E\n\n Object.defineProperty(newEvent, `target`, {\n value: iframeOriginalEvent.target,\n enumerable: true,\n })\n\n return newEvent\n }\n\n return event\n}\n","import { isPointerEvent } from \"../../utils/dom\"\nimport type { EnhancerOutput, RootEnhancer } from \"../types/enhancer\"\nimport { normalizeEventForViewport } from \"./normalizeEventForViewport\"\n\nconst pointerEvents = [\n `pointercancel` as const,\n `pointerdown` as const,\n `pointerenter` as const,\n `pointerleave` as const,\n `pointermove` as const,\n `pointerout` as const,\n `pointerover` as const,\n `pointerup` as const,\n]\n\nconst passthroughEvents = [...pointerEvents /*, ...mouseEvents*/]\n\nexport const eventsEnhancer =\n <InheritOptions, InheritOutput extends EnhancerOutput<RootEnhancer>>(\n next: (options: InheritOptions) => InheritOutput,\n ) =>\n (options: InheritOptions): InheritOutput => {\n const reader = next(options)\n\n reader.hookManager.register(\n `item.onDocumentLoad`,\n ({ destroy, itemId }) => {\n const item = reader.spineItemsManager.get(itemId)\n\n const frame = item?.renderer.getDocumentFrame()\n\n if (!frame || !item) return\n\n /**\n * Register event listener for all mouse/pointer event in order to\n * passthrough events to main document\n */\n const unregister = passthroughEvents.map((event) => {\n const listener = (e: MouseEvent | PointerEvent | TouchEvent) => {\n let convertedEvent = e\n /**\n * We have to create a new fake event since the original one is already dispatched\n * on original frame.\n *\n * @see Failed to execute 'dispatchEvent' on 'EventTarget': The event is already being dispatched.\n */\n if (isPointerEvent(e)) {\n convertedEvent = new PointerEvent(e.type, e)\n }\n\n if (convertedEvent !== e) {\n const normalizedEvent = normalizeEventForViewport(\n convertedEvent,\n e,\n reader.spine.locator,\n reader.viewport,\n )\n\n reader.context.value.rootElement?.dispatchEvent(normalizedEvent)\n }\n }\n\n frame.contentDocument?.addEventListener(event, listener)\n\n return () => {\n frame.contentDocument?.removeEventListener(event, listener)\n }\n })\n\n destroy(() => {\n unregister.forEach((cb) => {\n cb()\n })\n })\n },\n )\n\n return reader\n }\n","export { isShallowEqual } from \"@prose-reader/shared\"\n\nexport const getBase64FromBlob = (data: Blob) => {\n const reader = new FileReader()\n\n return new Promise<string>((resolve) => {\n reader.addEventListener(\n `load`,\n () => {\n resolve(reader.result as string)\n },\n false,\n )\n\n reader.readAsDataURL(data)\n })\n}\n\nexport const pick = <R extends Record<string, unknown>, K extends keyof R>(\n obj: R,\n keys: K[],\n): Pick<R, K> => {\n return Object.entries(obj).reduce(\n (acc, [key, entry]) => {\n // biome-ignore lint/suspicious/noExplicitAny: TODO\n if (keys.includes(key as any)) {\n return {\n ...acc,\n [key]: entry,\n }\n }\n\n return acc\n },\n {} as Pick<typeof obj, K>,\n )\n}\n","import { isShallowEqual } from \"@prose-reader/shared\"\nimport { defer, Observable, type OperatorFunction, of } from \"rxjs\"\nimport { distinctUntilChanged, first, map, switchMap } from \"rxjs/operators\"\nimport { pick } from \"./objects\"\n\nexport const mapKeysTo = <R extends Record<string, unknown>, K extends keyof R>(\n keys: K[],\n): OperatorFunction<R, Pick<R, K>> => {\n return map((obj) => pick(obj, keys))\n}\n\nexport const watchKeys =\n <R extends Record<string, unknown>, K extends keyof R>(keys: K[]) =>\n (stream: Observable<R>) => {\n return stream.pipe(mapKeysTo(keys), distinctUntilChanged(isShallowEqual))\n }\n\nexport function observeResize(\n element: HTMLElement,\n): Observable<ResizeObserverEntry[]> {\n return new Observable<ResizeObserverEntry[]>((observer) => {\n const resizeObserver = new ResizeObserver((entries) => {\n observer.next(entries)\n })\n\n resizeObserver.observe(element)\n\n return () => {\n resizeObserver.disconnect()\n }\n })\n}\n\nexport const waitForSwitch =\n <O>(waitForStream: Observable<O>) =>\n <N>(stream: Observable<N>) =>\n stream.pipe(\n switchMap((value) =>\n waitForStream.pipe(\n first(),\n map(() => value),\n ),\n ),\n )\n\nexport const deferNextResult = <T>(stream: Observable<T>) => {\n let value: { result: T } | undefined\n\n const sub = stream.subscribe((result) => {\n value = { result: result }\n })\n\n return () => {\n sub.unsubscribe()\n\n if (value) {\n return of(value.result)\n }\n\n return stream\n }\n}\n\nexport function idle(): Observable<void> {\n return new Observable<void>((observer) => {\n // webkit does not support requestIdleCallback yet\n if (window.requestIdleCallback) {\n const handle = window.requestIdleCallback(() => {\n observer.next()\n observer.complete()\n })\n\n return () => cancelIdleCallback(handle)\n }\n\n const timeout = setTimeout(() => {\n observer.next()\n observer.complete()\n }, 1)\n\n return () => clearTimeout(timeout)\n })\n}\n\nexport function deferIdle<T>(callback: () => Observable<T>) {\n return defer(() => idle().pipe(switchMap(callback)))\n}\n\nexport const observeMutation = (\n target: Node,\n options?: MutationObserverInit,\n) => {\n return new Observable<MutationRecord[]>((subscriber) => {\n const observer = new MutationObserver((mutations) => {\n subscriber.next(mutations)\n })\n\n observer.observe(target, options)\n\n return () => observer.disconnect()\n })\n}\n\nexport function observeIntersection(\n element: HTMLElement,\n options?: IntersectionObserverInit,\n): Observable<IntersectionObserverEntry[]> {\n return new Observable<IntersectionObserverEntry[]>((observer) => {\n const intersectionObserver = new IntersectionObserver((entries) => {\n observer.next(entries)\n }, options)\n\n intersectionObserver.observe(element)\n\n return () => {\n intersectionObserver.disconnect()\n }\n })\n}\n","import { isShallowEqual, shallowMergeIfDefined } from \"@prose-reader/shared\"\nimport {\n combineLatest,\n type Observable,\n type ObservedValueOf,\n Subject,\n} from \"rxjs\"\nimport {\n distinctUntilChanged,\n map,\n shareReplay,\n startWith,\n} from \"rxjs/operators\"\nimport { watchKeys } from \"../utils/rxjs\"\nimport type { SettingsInterface } from \"./SettingsInterface\"\nimport type { CoreInputSettings, CoreOutputSettings } from \"./types\"\n\nexport abstract class SettingsManagerOverload<\n InputSettings extends object,\n OutputSettings extends object,\n ParentInputSettings extends CoreInputSettings,\n ParentOutputSettings extends CoreOutputSettings,\n> implements\n SettingsInterface<\n InputSettings & ParentInputSettings,\n OutputSettings & ParentOutputSettings\n >\n{\n protected inputSettings: InputSettings\n protected outputSettings: OutputSettings\n protected outputSettingsUpdateSubject: Subject<OutputSettings>\n protected settingsManager: SettingsInterface<\n ParentInputSettings,\n ParentOutputSettings\n >\n\n public values$: Observable<ParentOutputSettings & OutputSettings>\n\n constructor(\n initialSettings: Partial<InputSettings>,\n settingsManager: SettingsInterface<\n ParentInputSettings,\n ParentOutputSettings\n >,\n ) {\n this.settingsManager = settingsManager\n\n const inputSettings = shallowMergeIfDefined(\n this.getDefaultSettings(),\n initialSettings,\n )\n\n this.outputSettings = this.computeOutputSettings(inputSettings)\n this.inputSettings = shallowMergeIfDefined(\n this.getDefaultSettings(),\n initialSettings,\n )\n this.outputSettingsUpdateSubject = new Subject()\n\n this.values$ = combineLatest([\n this.settingsManager.values$,\n this.outputSettingsUpdateSubject.pipe(startWith(this.outputSettings)),\n ]).pipe(\n map(([parentSettings, settings]) => ({ ...parentSettings, ...settings })),\n shareReplay(1),\n )\n\n this.values$.subscribe()\n }\n\n abstract getDefaultSettings(): InputSettings\n\n abstract computeOutputSettings(inputSettings: InputSettings): OutputSettings\n\n /**\n * Returns true if both are equal\n */\n abstract hasSettingsChanged(newOutputSettings: OutputSettings): boolean\n\n abstract getCleanedParentInputSettings(\n settings: Partial<InputSettings & ParentInputSettings>,\n ): ParentInputSettings\n\n _prepareUpdate(settings: Partial<InputSettings & ParentInputSettings>): {\n hasChanged: boolean\n commit: () => OutputSettings & ParentOutputSettings\n } {\n const parentInputSettings = this.getCleanedParentInputSettings(settings)\n\n const parentManagerPreparedUpdate =\n this.settingsManager._prepareUpdate(parentInputSettings)\n\n const inputSettings = shallowMergeIfDefined(this.inputSettings, settings)\n\n const outputSettings = this.computeOutputSettings(inputSettings)\n const hasChanged = this.hasSettingsChanged(outputSettings)\n\n return {\n hasChanged: hasChanged || parentManagerPreparedUpdate.hasChanged,\n commit: () => {\n this.inputSettings = inputSettings\n this.outputSettings = outputSettings\n\n if (!parentManagerPreparedUpdate.hasChanged && hasChanged) {\n this.outputSettingsUpdateSubject.next(outputSettings)\n }\n\n const parentOutputSettings = parentManagerPreparedUpdate.commit()\n\n return {\n ...parentOutputSettings,\n ...outputSettings,\n }\n },\n }\n }\n\n public update(settings: Partial<InputSettings & ParentInputSettings>) {\n const { commit } = this._prepareUpdate(settings)\n\n commit()\n }\n\n get values(): ParentOutputSettings & OutputSettings {\n return {\n ...this.settingsManager.values,\n ...this.outputSettings,\n }\n }\n public watch<K extends keyof ObservedValueOf<typeof this.values$>>(\n key: K,\n ): Observable<(ParentOutputSettings & OutputSettings)[K]>\n public watch<K extends keyof ObservedValueOf<typeof this.values$>>(\n keys: K[],\n ): Observable<Pick<ParentOutputSettings & OutputSettings, K>>\n public watch<K extends keyof ObservedValueOf<typeof this.values$>>(\n keyOrKeys: K | K[],\n ) {\n if (Array.isArray(keyOrKeys)) {\n return this.values$.pipe(watchKeys(keyOrKeys))\n }\n\n return this.values$.pipe(\n map((result) => result[keyOrKeys]),\n distinctUntilChanged(isShallowEqual),\n )\n }\n\n public destroy() {\n this.outputSettingsUpdateSubject.complete()\n }\n}\n","import { SettingsManagerOverload } from \"../../settings/SettingsManagerOverload\"\nimport type {\n CoreInputSettings,\n CoreOutputSettings,\n} from \"../../settings/types\"\nimport { isShallowEqual } from \"../../utils/objects\"\nimport type { EnhancerFontsInputSettings } from \"./types\"\n\nexport class SettingsManager<\n ParentInputSettings extends CoreInputSettings,\n ParentOutputSettings extends CoreOutputSettings,\n> extends SettingsManagerOverload<\n EnhancerFontsInputSettings,\n EnhancerFontsInputSettings,\n ParentInputSettings,\n ParentOutputSettings\n> {\n computeOutputSettings(\n settings: EnhancerFontsInputSettings,\n ): EnhancerFontsInputSettings {\n return settings\n }\n\n hasSettingsChanged(newOutputSettings: EnhancerFontsInputSettings): boolean {\n return !isShallowEqual(this.outputSettings, newOutputSettings)\n }\n\n getCleanedParentInputSettings(\n settings: Partial<EnhancerFontsInputSettings & ParentInputSettings>,\n ): ParentInputSettings {\n const {\n fontJustification: _unused1,\n fontScale: _unused2,\n fontWeight: _unused3,\n lineHeight: _unused4,\n ...rest\n } = settings\n\n return rest as unknown as ParentInputSettings\n }\n\n getDefaultSettings(): EnhancerFontsInputSettings {\n return {\n fontScale: 1,\n fontWeight: \"publisher\",\n lineHeight: \"publisher\",\n fontJustification: \"publisher\",\n }\n }\n}\n","import {\n type Observable,\n type ObservedValueOf,\n Subject,\n map,\n takeUntil,\n} from \"rxjs\"\nimport { pairwise, tap } from \"rxjs/operators\"\nimport type { SettingsInterface } from \"../../settings/SettingsInterface\"\nimport { upsertCSSToFrame } from \"../../utils/frames\"\nimport type {\n EnhancerOptions,\n EnhancerOutput,\n RootEnhancer,\n} from \"../types/enhancer\"\nimport { SettingsManager } from \"./SettingsManager\"\nimport type { EnhancerFontsInputSettings } from \"./types\"\n\ntype OutputOptions = Required<EnhancerFontsInputSettings>\n\n/**\n * @important\n * We don't apply font scaling on pre-paginated because it could potentially\n * break publisher scaling. Since it's specifically made for the given fixed layout\n * we should trust the publisher and not break its rendering.\n * @see 9781250213662\n *\n * Setting the font scale on body still has a chance to break publisher potential\n * font size on body if they already use something.\n * @see 9782714493743\n */\nexport const fontsEnhancer =\n <\n InheritOptions extends EnhancerOptions<RootEnhancer>,\n InheritOutput extends EnhancerOutput<RootEnhancer>,\n InheritSettings extends NonNullable<\n InheritOutput[\"settings\"][\"_inputSettings\"]\n >,\n InheritComputedSettings extends NonNullable<\n InheritOutput[\"settings\"][\"_outputSettings\"]\n >,\n Output extends Omit<InheritOutput, \"settings\"> & {\n settings: SettingsInterface<\n InheritSettings & EnhancerFontsInputSettings,\n EnhancerFontsInputSettings & InheritComputedSettings\n >\n },\n >(\n next: (options: InheritOptions) => InheritOutput,\n ) =>\n (options: InheritOptions & Partial<EnhancerFontsInputSettings>): Output => {\n const { fontScale, lineHeight, fontWeight, fontJustification } = options\n const changes$ = new Subject<Partial<OutputOptions>>()\n const reader = next(options)\n\n const settingsManager = new SettingsManager<\n InheritSettings,\n InheritComputedSettings\n >(\n {\n fontScale,\n lineHeight,\n fontWeight,\n fontJustification,\n },\n reader.settings as SettingsInterface<\n InheritSettings,\n InheritComputedSettings\n >,\n )\n\n const getStyle = () => `\n ${\n /*\n Ideally, we would like to use !important but it could break publisher specific\n cases.\n Also right now we do not apply it to * since it would also break publisher\n more specific scaling down the tree.\n\n body *:not([class^=\"mjx-\"]) {\n */ ``\n }\n body {\n ${settingsManager.values.fontScale !== 1 ? `font-size: ${settingsManager.values.fontScale}em !important;` : ``}\n ${settingsManager.values.lineHeight !== `publisher` ? `line-height: ${settingsManager.values.lineHeight} !important;` : ``}\n ${settingsManager.values.fontWeight !== `publisher` ? `font-weight: ${settingsManager.values.fontWeight} !important;` : ``}\n ${settingsManager.values.fontJustification !== `publisher` ? `text-align: ${settingsManager.values.fontJustification} !important;` : ``}\n }\n `\n\n /**\n * Programmatically update every loaded items\n */\n const applyChangeToSpineItems = (requireLayout: boolean) => {\n reader.spineItemsManager.items.forEach((item) => {\n if (item.renditionLayout !== `pre-paginated`) {\n const frame = item.renderer.getDocumentFrame()\n\n if (frame) {\n upsertCSSToFrame(frame, `prose-reader-fonts`, getStyle())\n }\n }\n })\n\n if (requireLayout) {\n reader.layout()\n }\n }\n\n /**\n * Make sure we apply the style to any new item loaded.\n */\n reader.hookManager.register(`item.onDocumentLoad`, ({ itemId }) => {\n const item = reader.spineItemsManager.get(itemId)\n\n if (item?.renditionLayout !== `pre-paginated`) {\n const frame = item?.renderer.getDocumentFrame()\n\n if (frame) {\n upsertCSSToFrame(frame, `prose-reader-fonts`, getStyle())\n }\n }\n })\n\n const shouldRequireLayout = <T extends ObservedValueOf<typeof changes$>>(\n source: Observable<T>,\n ) =>\n source.pipe(\n pairwise(),\n map(([old, latest]) => {\n if (latest.fontScale !== old.fontScale) return true\n if (latest.lineHeight !== old.lineHeight) return true\n\n return false\n }),\n )\n\n settingsManager.values$\n .pipe(\n shouldRequireLayout,\n tap(applyChangeToSpineItems),\n takeUntil(reader.$.destroy$),\n )\n .subscribe()\n\n return {\n ...reader,\n destroy: () => {\n changes$.complete()\n settingsManager.destroy()\n reader.destroy()\n },\n settings: settingsManager,\n } as unknown as Output\n }\n","import type { KeyboardEvent } from \"react\"\nimport { EMPTY, fromEvent, map, merge, switchMap, takeUntil } from \"rxjs\"\nimport type { NavigationEnhancerOutput } from \"./navigation/types\"\nimport type {\n EnhancerOptions,\n EnhancerOutput,\n RootEnhancer,\n} from \"./types/enhancer\"\n\nexport const hotkeysEnhancer =\n <\n InheritOptions extends EnhancerOptions<RootEnhancer>,\n InheritOutput extends EnhancerOutput<RootEnhancer> &\n NavigationEnhancerOutput,\n >(\n next: (options: InheritOptions) => InheritOutput,\n ) =>\n (options: InheritOptions): InheritOutput => {\n const reader = next(options)\n\n const navigateOnKey = (document: Document) =>\n fromEvent<KeyboardEvent>(document, \"keyup\").pipe(\n map((e) => {\n const { pageTurnDirection, computedPageTurnMode } =\n reader.settings.values\n\n if (computedPageTurnMode === \"scrollable\") {\n return e\n }\n\n if (pageTurnDirection === \"horizontal\") {\n if (e.key === `ArrowRight`) {\n return reader.navigation.turnRight()\n }\n\n if (e.key === `ArrowLeft`) {\n return reader.navigation.turnLeft()\n }\n }\n\n if (pageTurnDirection === \"vertical\") {\n if (e.key === `ArrowDown`) {\n return reader.navigation.turnRight()\n }\n\n if (e.key === `ArrowUp`) {\n return reader.navigation.turnLeft()\n }\n }\n\n return e\n }),\n )\n\n navigateOnKey(document).pipe(takeUntil(reader.$.destroy$)).subscribe()\n\n reader.spineItemsManager.items$\n .pipe(\n switchMap((spineItems) =>\n merge(\n ...spineItems.map((item) =>\n item.watch(\"isLoaded\").pipe(\n switchMap(() => {\n const element = item.renderer.getDocumentFrame()\n\n return element instanceof HTMLIFrameElement &&\n element?.contentDocument\n ? navigateOnKey(element.contentDocument)\n : EMPTY\n }),\n ),\n ),\n ),\n ),\n takeUntil(reader.$.destroy$),\n )\n .subscribe()\n\n return reader\n }\n","import { fromEvent, merge, NEVER, share, switchMap, tap } from \"rxjs\"\nimport type { Reader } from \"../../reader\"\n\nexport const handleLinks = (reader: Reader) => {\n return reader.spine.spineItemsManager.items$.pipe(\n switchMap((items) =>\n merge(\n ...items.map((item) => {\n return item.watch(\"isLoaded\").pipe(\n switchMap(() => {\n const frame = item.renderer.getDocumentFrame()\n\n if (!frame || !frame?.contentDocument) return NEVER\n\n const anchorElements = Array.from(\n frame.contentDocument.querySelectorAll(`a`),\n )\n\n const events$ = anchorElements.map((element) =>\n fromEvent<MouseEvent>(element, `click`),\n )\n\n return merge(...events$)\n }),\n )\n }),\n ),\n ),\n tap((event) => {\n event.preventDefault()\n }),\n share(),\n )\n}\n","import { isShallowEqual } from \"@prose-reader/shared\"\nimport {\n BehaviorSubject,\n distinctUntilChanged,\n map,\n Observable,\n Subject,\n takeUntil,\n} from \"rxjs\"\nimport { watchKeys } from \"./rxjs\"\n\n/**\n * Convenience class to manage reactive entities.\n * Used across the codebase.\n *\n * Embed within commonly used methods.\n */\nexport class ReactiveEntity<\n T extends Record<string, unknown>,\n> extends Observable<T> {\n protected stateSubject: BehaviorSubject<T>\n protected _destroy$ = new Subject<void>()\n\n constructor(initialState: T) {\n super((subscriber) => {\n const sub = this.stateSubject\n .pipe(takeUntil(this._destroy$))\n .subscribe(subscriber)\n\n return sub\n })\n this.stateSubject = new BehaviorSubject<T>(initialState)\n }\n\n protected next(value: T) {\n this.stateSubject.next(value)\n }\n\n /**\n * Default shallow compare.\n */\n protected mergeCompare(pagination: Partial<T>) {\n const newValue = { ...this.value, ...pagination }\n\n if (isShallowEqual(this.value, newValue)) return\n\n this.stateSubject.next(newValue)\n }\n\n public watch<K extends keyof T>(key: K): Observable<T[K]>\n public watch<K extends keyof T>(keys: K[]): Observable<Pick<T, K>>\n public watch<K extends keyof T>(keyOrKeys: K | K[]) {\n if (Array.isArray(keyOrKeys)) {\n return this.stateSubject.pipe(watchKeys(keyOrKeys))\n }\n return this.stateSubject.pipe(\n map((result) => result[keyOrKeys]),\n distinctUntilChanged(isShallowEqual),\n )\n }\n\n public get value() {\n return this.stateSubject.value\n }\n\n public destroy$ = this._destroy$.asObservable()\n\n public destroy() {\n this.stateSubject.complete()\n this._destroy$.complete()\n }\n}\n","import type { Manifest } from \"@prose-reader/shared\"\nimport {\n catchError,\n combineLatest,\n defer,\n EMPTY,\n endWith,\n filter,\n finalize,\n first,\n map,\n merge,\n mergeMap,\n Observable,\n of,\n Subject,\n share,\n switchMap,\n takeUntil,\n} from \"rxjs\"\nimport type { Context } from \"../../context/Context\"\nimport type { HookManager } from \"../../hooks/HookManager\"\nimport { Report } from \"../../report\"\nimport type { ReaderSettingsManager } from \"../../settings/ReaderSettingsManager\"\nimport { getFrameViewportInfo } from \"../../utils/frames\"\nimport { ReactiveEntity } from \"../../utils/ReactiveEntity\"\nimport { waitForSwitch } from \"../../utils/rxjs\"\nimport type { Viewport } from \"../../viewport/Viewport\"\nimport type { ResourceHandler } from \"../resources/ResourceHandler\"\n\nexport type DocumentRendererParams = {\n context: Context\n settings: ReaderSettingsManager\n hookManager: HookManager\n item: Manifest[`spineItems`][number]\n containerElement: HTMLElement\n resourcesHandler: ResourceHandler\n viewport: Viewport\n}\n\ntype LayoutParams = {\n minPageSpread: number\n blankPagePosition: `before` | `after` | `none`\n spreadPosition: `none` | `left` | `right`\n minimumWidth: number\n}\n\ntype DocumentRendererState =\n | {\n state: `error`\n error: unknown\n }\n | {\n state: `idle` | `loading` | `loaded` | `unloading`\n error: undefined\n }\n\nexport abstract class DocumentRenderer extends ReactiveEntity<DocumentRendererState> {\n static readonly DOCUMENT_CONTAINER_CLASS_NAME =\n `prose-reader-document-container`\n private triggerSubject = new Subject<{ type: `load` } | { type: `unload` }>()\n\n protected viewport: Viewport\n protected context: Context\n protected settings: ReaderSettingsManager\n protected hookManager: HookManager\n protected item: Manifest[`spineItems`][number]\n protected containerElement: HTMLElement\n protected resourcesHandler: ResourceHandler\n\n // protected unload$ = this.triggerSubject.pipe(\n // withLatestFrom(this.stateSubject),\n // filter(\n // ([trigger, state]) =>\n // trigger.type === `unload` && state.state !== \"idle\" && state.state !== \"unloading\",\n // ),\n // map(() => undefined),\n // share(),\n // )\n\n // protected load$ = this.triggerSubject.pipe(\n // withLatestFrom(this.stateSubject),\n // filter(\n // ([trigger, state]) =>\n // trigger.type === `load` && state.state !== \"loaded\" && state.state !== \"loading\",\n // ),\n // map(() => undefined),\n // share(),\n // )\n\n public loaded$: Observable<void>\n public unloaded$: Observable<void>\n\n private _documentContainer: HTMLElement | undefined\n\n constructor(params: {\n context: Context\n settings: ReaderSettingsManager\n hookManager: HookManager\n item: Manifest[`spineItems`][number]\n containerElement: HTMLElement\n resourcesHandler: ResourceHandler\n viewport: Viewport\n }) {\n super({\n state: `idle`,\n error: undefined,\n })\n\n this.context = params.context\n this.settings = params.settings\n this.hookManager = params.hookManager\n this.item = params.item\n this.containerElement = params.containerElement\n this.resourcesHandler = params.resourcesHandler\n this.viewport = params.viewport\n\n const unloadTrigger$ = this.triggerSubject.pipe(\n filter((trigger) => trigger.type === `unload`),\n )\n\n const loadTrigger$ = this.triggerSubject.pipe(\n filter((trigger) => trigger.type === `load`),\n )\n\n this.loaded$ = loadTrigger$.pipe(\n mergeMap(() => {\n const canBeIgnored =\n this.value.state === `loaded` || this.value.state === `loading`\n\n if (canBeIgnored) return EMPTY\n\n this.next({ state: `loading`, error: undefined })\n\n const createDocument$ = this.onCreateDocument().pipe(first())\n\n return createDocument$.pipe(\n mergeMap((documentContainer) => {\n this.hookManager.execute(`item.onDocumentCreated`, this.item.id, {\n itemId: this.item.id,\n documentContainer,\n })\n\n const loadDocument$ = this.onLoadDocument().pipe(\n endWith(null),\n first(),\n )\n\n return loadDocument$.pipe(\n waitForSwitch(this.context.bridgeEvent.viewportFree$),\n switchMap(() => {\n const hookResults = this.hookManager\n .execute(`item.onDocumentLoad`, this.item.id, {\n itemId: this.item.id,\n documentContainer,\n })\n .filter(\n (result): result is Observable<void> =>\n result instanceof Observable,\n )\n\n return combineLatest([of(null), ...hookResults]).pipe(first())\n }),\n )\n }),\n map(() => {\n this.next({ state: `loaded`, error: undefined })\n\n return undefined\n }),\n takeUntil(unloadTrigger$),\n )\n }),\n share(),\n )\n\n this.unloaded$ = unloadTrigger$.pipe(\n mergeMap(() => {\n const canBeIgnored =\n this.value.state === `unloading` || this.value.state === `idle`\n\n if (canBeIgnored) return EMPTY\n\n this.next({ state: `unloading`, error: undefined })\n\n return this.context.bridgeEvent.viewportFree$.pipe(\n first(),\n switchMap(() => {\n this.hookManager.destroy(`item.onDocumentLoad`, this.item.id)\n\n const onUnload$ = this.onUnload().pipe(endWith(null), first())\n\n return onUnload$\n }),\n map(() => {\n this.next({ state: `idle`, error: undefined })\n\n return undefined\n }),\n takeUntil(loadTrigger$),\n )\n }),\n share(),\n )\n\n merge(this.loaded$, this.unloaded$)\n .pipe(\n catchError((error) => {\n this.next({ state: `error`, error })\n\n return EMPTY\n }),\n takeUntil(this.destroy$),\n )\n .subscribe()\n }\n\n protected setDocumentContainer(element: HTMLElement) {\n this._documentContainer = element\n this._documentContainer.classList.add(\n DocumentRenderer.DOCUMENT_CONTAINER_CLASS_NAME,\n )\n }\n\n protected attach() {\n if (this.documentContainer) {\n this.containerElement.appendChild(this.documentContainer)\n }\n }\n\n protected detach() {\n this._documentContainer?.remove()\n this._documentContainer = undefined\n }\n\n public get state$() {\n return this.stateSubject\n }\n\n public get isLoaded$() {\n return this.state$.pipe(map((state) => state.state === `loaded`))\n }\n\n public load() {\n this.triggerSubject.next({ type: `load` })\n }\n\n public unload() {\n this.triggerSubject.next({ type: `unload` })\n }\n\n /**\n * Automatically release on complete or error.\n */\n public renderHeadless(): Observable<\n { doc: Document; release: () => void } | undefined\n > {\n const releaseSubject = new Subject<void>()\n\n return defer(() => this.onRenderHeadless({ release: releaseSubject })).pipe(\n endWith(undefined),\n first(),\n map((doc) => {\n if (!doc) return undefined\n\n return {\n doc,\n release: () => {\n releaseSubject.next(undefined)\n },\n }\n }),\n finalize(() => {\n releaseSubject.complete()\n }),\n catchError((e) => {\n Report.error(e)\n\n return of(undefined)\n }),\n )\n }\n\n public layout(params: LayoutParams) {\n return this.onLayout(params)\n }\n\n public destroy() {\n this.unload()\n this.stateSubject.complete()\n\n super.destroy()\n }\n\n abstract onRenderHeadless(params: {\n release: Observable<void>\n }): Observable<Document | undefined>\n\n abstract onUnload(): Observable<unknown>\n\n /**\n * This lifecycle lets you fetch your resource and create the document.\n * You can fill the layers with your document(s). You can also preload or\n * load any resources that you need as well.\n *\n * @important Do not attach anything to the dom yet.\n */\n abstract onCreateDocument(): Observable<HTMLElement>\n\n /**\n * This lifecycle lets you load whatever you need once the document is attached to\n * the dom. Some operations can only be done at this stage (eg: loading iframe).\n *\n * @important By the end of your stream, the layers should be attached to the dom.\n */\n abstract onLoadDocument(): Observable<unknown>\n\n abstract onLayout(\n params: LayoutParams,\n ): Observable<{ width: number; height: number } | undefined>\n\n /**\n * Return the main document iframe.\n */\n abstract getDocumentFrame(): HTMLIFrameElement | undefined\n\n get documentContainer() {\n return this._documentContainer\n }\n\n get writingMode(): `vertical-rl` | `horizontal-tb` | undefined {\n return undefined\n }\n\n get readingDirection(): `rtl` | `ltr` | undefined {\n return undefined\n }\n\n get renditionLayout() {\n const itemRenditionLayout = this.item.renditionLayout\n\n if (itemRenditionLayout) return itemRenditionLayout\n\n const iframe = this.getDocumentFrame()\n\n if (iframe) {\n const { hasViewport } = getFrameViewportInfo(iframe)\n\n if (hasViewport) return \"pre-paginated\"\n }\n\n return this.context.manifest?.renditionLayout ?? \"reflowable\"\n }\n}\n","import type { Manifest } from \"@prose-reader/shared\"\nimport type { ReaderSettingsManager } from \"../../settings/ReaderSettingsManager\"\nimport { lastValueFrom, of } from \"rxjs\"\n\nconst defaultGetResource = (item: Manifest[\"items\"][0]) => new URL(item.href)\n\nexport class ResourceHandler {\n constructor(\n protected item: Manifest[\"items\"][number],\n protected settings: ReaderSettingsManager,\n ) {}\n\n public async getResource() {\n const resource = await lastValueFrom(\n this.settings.values.getResource?.(this.item) ?? of(undefined),\n )\n\n return resource ?? defaultGetResource(this.item)\n }\n\n public async fetchResource() {\n const resource = await this.getResource()\n\n if (resource instanceof Response) return resource\n\n if (resource instanceof URL) return fetch(resource)\n\n return resource\n }\n}\n","import { type Manifest, getParentPath } from \"@prose-reader/shared\"\nimport {\n Observable,\n combineLatest,\n from,\n map,\n mergeMap,\n of,\n switchMap,\n} from \"rxjs\"\nimport type { Context } from \"../../../context/Context\"\nimport type { ReaderSettingsManager } from \"../../../settings/ReaderSettingsManager\"\nimport { ResourceHandler } from \"../../../spineItem/resources/ResourceHandler\"\nimport { getElementsWithAssets, revokeDocumentBlobs } from \"../../../utils/dom\"\n\n/**\n * @important Firefox handles file protocol weirdly and will not\n * go up one directory when using \"../\". We temporarily replace to http://\n * to keep our behavior.\n */\nconst joinPath = (base: string, path: string) => {\n // Temporarily replace file:// with http:// for consistent URL handling\n const isFileProtocol = base.startsWith(\"file://\")\n const tempBase = isFileProtocol ? base.replace(\"file://\", \"http://\") : base\n const result = new URL(path, tempBase).toString()\n\n // Convert back to file:// if needed\n return isFileProtocol ? result.replace(\"http://\", \"file://\") : result\n}\n\nconst loadFontFaces = async (\n document: Document | null | undefined,\n element: HTMLLinkElement,\n spineItemUriParentPath: string,\n context: Context,\n settings: ReaderSettingsManager,\n): Promise<void> => {\n if (!document || !document.defaultView) return\n\n const sheet = element.sheet\n\n if (!sheet) return\n\n try {\n const rules = Array.from(sheet.cssRules || [])\n\n for (let i = 0; i < rules.length; i++) {\n const rule = rules[i]\n if (\n document.defaultView &&\n rule instanceof document.defaultView.CSSFontFaceRule\n ) {\n const src = rule.style.getPropertyValue(\"src\")\n const matches = src.match(/url\\(['\"]?([^'\"]+)['\"]?\\)/g)\n\n if (matches) {\n // Split the src value into individual sources\n const srcParts = src.split(\",\").map((part) => part.trim())\n\n const newSrcParts = await Promise.all(\n srcParts.map(async (part) => {\n // If it's a local() source, preserve it as-is\n if (part.startsWith(\"local(\")) {\n return part\n }\n\n // Extract URL and format parts\n const urlMatch = part.match(/url\\(['\"]?([^'\"]+)['\"]?\\)/)\n if (!urlMatch) return part\n\n const originalSrc = urlMatch[1] ?? ``\n\n // Find the font resource in the manifest\n const foundItem = context.manifest?.items.find(({ href }) => {\n return `${joinPath(spineItemUriParentPath, originalSrc).toLowerCase()}`.endsWith(\n `${href.toLowerCase()}`,\n )\n })\n\n if (foundItem) {\n const resourceHandler = new ResourceHandler(foundItem, settings)\n\n try {\n const resource = await resourceHandler.getResource()\n\n if (resource instanceof Response) {\n const blob = await resource.blob()\n const blobUrl =\n document.defaultView?.URL.createObjectURL(blob)\n\n // Reconstruct the source with the new blob URL and preserve format/tech\n const newPart = part.replace(\n urlMatch[0],\n `url(\"${blobUrl}\")`,\n )\n\n return newPart\n }\n } catch (e) {\n console.error(\"Error loading font:\", e)\n }\n }\n return part\n }),\n )\n\n // Instead of modifying the existing rule, create a new one\n // firefox will not allow to modify the existing rule\n // Get the complete rule text and replace the entire src declaration\n const newRule = rule.cssText.replace(\n /src:\\s*[^;]+;/,\n `src: ${newSrcParts.join(\", \")};`,\n )\n\n // Delete the old rule and insert the new one\n sheet.deleteRule(i)\n sheet.insertRule(newRule, i)\n }\n }\n }\n } catch (e) {\n console.error(\"Could not access stylesheet rules:\", e)\n }\n}\n\nconst loadElementSrc = (\n _document: Document | null | undefined,\n element: Element,\n spineItemUriParentPath: string,\n context: Context,\n settings: ReaderSettingsManager,\n) => {\n const originalSrc =\n element.getAttribute(\"src\") || element.getAttribute(\"href\")\n\n if (!originalSrc) return of(null)\n\n // EPUB/image.png needs to match frame relative src /image.png\n const foundItem = context.manifest?.items.find(({ href }) => {\n // this will remove things like \"../..\" and have a normal relative path\n return `${joinPath(spineItemUriParentPath, originalSrc).toLowerCase()}`.endsWith(\n `${href.toLowerCase()}`,\n )\n })\n\n if (!foundItem) return of(null)\n\n const resourceHandler = new ResourceHandler(foundItem, settings)\n\n /**\n * For each resources, if it's a response and not a URL, we should convert it to a blob\n * because it will not be accessible otherwise.\n */\n return from(resourceHandler.getResource()).pipe(\n mergeMap((resource) =>\n resource instanceof Response ? from(resource.blob()) : of(undefined),\n ),\n mergeMap((blob) => {\n if (!blob) {\n return of(null)\n }\n\n const blobUrl = _document?.defaultView?.URL.createObjectURL(blob) ?? ``\n\n if (element.hasAttribute(\"src\")) {\n element.setAttribute(\"src\", blobUrl)\n } else if (element.hasAttribute(\"href\")) {\n element.setAttribute(\"href\", blobUrl)\n\n if (\n _document?.defaultView &&\n element instanceof _document.defaultView.HTMLLinkElement\n ) {\n return new Observable<void>((observer) => {\n element.onload = async () => {\n try {\n // Now that the stylesheet is loaded, replace font URLs\n // we cannot do that before because the stylesheet is not loaded\n // and we would not have access to it.\n if (element.sheet) {\n await loadFontFaces(\n _document,\n element,\n spineItemUriParentPath,\n context,\n settings,\n )\n }\n observer.next()\n observer.complete()\n } catch (error) {\n observer.error(error)\n }\n }\n element.onerror = observer.error\n })\n }\n }\n\n return of(null)\n }),\n )\n}\n\nexport const loadAssets =\n ({\n settings,\n item,\n context,\n }: {\n settings: ReaderSettingsManager\n item: Manifest[\"items\"][number]\n context: Context\n }) =>\n (stream: Observable<HTMLIFrameElement>) =>\n stream.pipe(\n switchMap((frameElement) => {\n const elementsWithAsset = getElementsWithAssets(\n frameElement.contentDocument,\n )\n\n const spineItemUriParentPath = getParentPath(item.href)\n\n const assetsLoad$ = elementsWithAsset.map((element) =>\n loadElementSrc(\n frameElement.contentDocument,\n element,\n spineItemUriParentPath,\n context,\n settings,\n ),\n )\n\n return combineLatest(assetsLoad$).pipe(map(() => frameElement))\n }),\n )\n\nexport const unloadAssets = (frameElement?: HTMLIFrameElement) => {\n revokeDocumentBlobs(frameElement?.contentDocument)\n}\n","export const PROSE_READER_NAMESPACE = `@prose-reader/core`\nexport const VIEWPORT_ADJUSTMENT_THROTTLE = 0\nexport const PAGINATION_UPDATE_AFTER_VIEWPORT_ADJUSTMENT_DEBOUNCE = 200\nexport const ITEM_EXTENSION_VALID_FOR_FRAME_SRC = [`.xhtml`, `.html`, `.htm`]\nexport const HTML_PREFIX = `prose-reader`\nexport const HTML_STYLE_PREFIX = `${HTML_PREFIX}-style`\nexport const HTML_ATTRIBUTE_DATA_READER_ID = `data-${HTML_PREFIX}-id`\nexport const HTML_PREFIX_VIEWPORT = `${HTML_PREFIX}-viewport`\nexport const HTML_PREFIX_SCROLL_NAVIGATOR = `${HTML_PREFIX}-scroll-navigator`\n","import { detectMimeTypeFromName, parseContentType } from \"@prose-reader/shared\"\nimport type { Manifest } from \"../../..\"\n\n/**\n * Document is application/xhtml+xml\n * @todo move this into a enhancer\n * @todo only keep a very basic default one which just put the resource as <media> inside html page\n * @todo use the core default one as last resort if the pipe does not return an html document\n */\nexport const createHtmlPageFromResource = async (\n resourceResponse: Response | string,\n item: Manifest[`spineItems`][number],\n) => {\n if (typeof resourceResponse === \"string\") return resourceResponse\n\n const contentType =\n parseContentType(resourceResponse.headers.get(`Content-Type`) || ``) ||\n detectMimeTypeFromName(item.href)\n\n if (\n [`image/jpg`, `image/jpeg`, `image/png`, `image/webp`].some(\n (mime) => mime === contentType,\n )\n ) {\n const blob = await resourceResponse.blob()\n const objectUrl = URL.createObjectURL(blob)\n const bitmap = await createImageBitmap(blob)\n const { width, height } = { width: bitmap.width, height: bitmap.height }\n bitmap.close()\n\n return `\n <html>\n <head>\n ${item.renditionLayout === `pre-paginated` ? `<meta name=\"viewport\" content=\"width=${width}, height=${height}\">` : ``}\n </head>\n <body style=\"margin: 0px;\" tab-index=\"-1;\">\n <img\n src=\"${objectUrl}\"\n style=\"max-width: 100%;height:100%;object-fit:contain;\"\n >\n </body>\n </html>\n `\n }\n\n if ([`text/plain`].some((mime) => mime === contentType)) {\n const data = await resourceResponse.text()\n\n return `\n <!DOCTYPE html>\n <html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:epub=\"http://www.idpf.org/2007/ops\" xml:lang=\"en\" lang=\"en\">\n <head>\n <style>\n pre {\n white-space: pre;\n white-space: pre-wrap;\n word-wrap: break-word;\n }\n </style>\n </head>\n <body>\n <pre>${data}</pre>\n </body>\n </html>\n `\n }\n\n const content = await resourceResponse.text()\n\n return content\n}\n","import type { Manifest } from \"@prose-reader/shared\"\nimport {\n type Observable,\n catchError,\n from,\n map,\n of,\n switchMap,\n tap,\n} from \"rxjs\"\nimport { ITEM_EXTENSION_VALID_FOR_FRAME_SRC } from \"../../../constants\"\nimport { Report } from \"../../../report\"\nimport type { ReaderSettingsManager } from \"../../../settings/ReaderSettingsManager\"\nimport type { ResourceHandler } from \"../../../spineItem/resources/ResourceHandler\"\nimport { createHtmlPageFromResource } from \"./createHtmlPageFromResource\"\n\nexport const attachFrameSrc = ({\n item,\n resourcesHandler,\n}: {\n settings: ReaderSettingsManager\n item: Manifest[`spineItems`][number]\n resourcesHandler: ResourceHandler\n}) => {\n const getHtmlFromResource = (response: Response) =>\n createHtmlPageFromResource(response, item)\n\n return (stream: Observable<HTMLIFrameElement>) =>\n stream.pipe(\n switchMap((frameElement) => {\n return from(resourcesHandler.getResource()).pipe(\n switchMap((resource) => {\n /**\n * Because of the bug with iframe and sw, we should not use srcdoc and sw together for\n * html document. This is because resources will not pass through SW. IF `fetchResource` is being\n * used the user should be aware of the limitation. We use srcdoc for everything except if we detect\n * an html document and same origin. Hopefully that bug gets fixed one day.\n * @see https://bugs.chromium.org/p/chromium/issues/detail?id=880768\n */\n if (\n resource instanceof URL &&\n item.href.startsWith(window.location.origin) &&\n // we have an encoding and it's a valid html\n ((item.mediaType &&\n [\n `application/xhtml+xml`,\n `application/xml`,\n `text/html`,\n `text/xml`,\n ].includes(item.mediaType)) ||\n // no encoding ? then try to detect html\n (!item.mediaType &&\n ITEM_EXTENSION_VALID_FOR_FRAME_SRC.some((extension) =>\n item.href.endsWith(extension),\n )))\n ) {\n frameElement?.setAttribute(`src`, item.href)\n\n return of(frameElement)\n }\n\n const resourceResponse$ =\n resource instanceof URL\n ? from(resourcesHandler.fetchResource())\n : of(resource)\n\n return resourceResponse$.pipe(\n switchMap((response) => {\n if (!(response instanceof Response)) {\n throw new Error(`Invalid resource`)\n }\n\n return from(getHtmlFromResource(response))\n }),\n tap((htmlDoc) => {\n if (htmlDoc) {\n const blob = new Blob([htmlDoc], { type: \"text/html\" })\n /**\n * The blob will be released once the document is destroyed.\n * No need to deal with it ourselves.\n */\n const blobURL = URL.createObjectURL(blob)\n\n frameElement?.setAttribute(`src`, blobURL)\n }\n }),\n map(() => frameElement),\n catchError((e) => {\n Report.error(\n `Error while trying to fetch or load resource for item ${item.id}`,\n resource,\n )\n Report.error(e)\n\n return of(frameElement)\n }),\n )\n }),\n )\n }),\n )\n}\n","export const createFrameElement = () => {\n // we force undefined because otherwise the load method will believe it's defined after this call but the code is async and\n // the iframe could be undefined later\n const frame = document.createElement(`iframe`)\n frame.frameBorder = `no`\n frame.tabIndex = 0\n frame.setAttribute(\n `sandbox`,\n `\n allow-same-origin \n allow-scripts \n allow-top-navigation-to-custom-protocols\n`,\n )\n frame.style.cssText = `\n overflow: hidden;\n background-color: transparent;\n border: 0px none transparent;\n padding: 0px;\n`\n\n frame.setAttribute(`role`, `main`)\n\n return frame\n}\n","import { getFrameViewportInfo } from \"../../../../utils/frames\"\n\nexport const getViewPortInformation = ({\n pageHeight,\n pageWidth,\n frameElement,\n}: {\n pageWidth: number\n pageHeight: number\n frameElement: HTMLIFrameElement\n}) => {\n const viewportDimensions = getFrameViewportInfo(frameElement)\n\n if (\n frameElement?.contentDocument &&\n frameElement.contentWindow &&\n viewportDimensions\n ) {\n const computedWidthScale = pageWidth / (viewportDimensions.width ?? 1)\n const computedScale = Math.min(\n computedWidthScale,\n pageHeight / (viewportDimensions.height ?? 1),\n )\n\n return { computedScale, computedWidthScale, viewportDimensions }\n }\n}\n\n/**\n * Upward layout is used when the parent wants to manipulate the iframe without triggering\n * `layout` event. This is a particular case needed for iframe because the parent can layout following\n * an iframe `layout` event. Because the parent `layout` may change some of iframe properties we do not\n * want the iframe to trigger a new `layout` even and have infinite loop.\n */\nconst staticLayout = (\n frameElement: HTMLIFrameElement,\n size: { width: number; height: number },\n) => {\n frameElement.style.width = `${size.width}px`\n frameElement.style.height = `${size.height}px`\n}\n\nexport const renderPrePaginated = ({\n minPageSpread,\n blankPagePosition,\n spreadPosition,\n pageHeight,\n pageWidth,\n frameElement,\n isRTL,\n}: {\n minPageSpread: number\n blankPagePosition: `before` | `after` | `none`\n spreadPosition: `none` | `left` | `right`\n pageWidth: number\n pageHeight: number\n frameElement?: HTMLIFrameElement\n isRTL: boolean\n}) => {\n const minimumWidth = minPageSpread * pageWidth\n\n if (frameElement?.contentDocument && frameElement?.contentWindow) {\n const { viewportDimensions, computedScale = 1 } =\n getViewPortInformation({ frameElement, pageHeight, pageWidth }) ?? {}\n const hasViewportDimensions = !!viewportDimensions\n const contentWidth = pageWidth\n const contentHeight = pageHeight\n\n if (frameElement.contentDocument?.documentElement) {\n frameElement.contentDocument?.documentElement.setAttribute(\n `data-prose-reader-html-renderer-has-viewport-dimensions`,\n hasViewportDimensions.toString(),\n )\n }\n // frameElement?.style.setProperty(`visibility`, `visible`)\n // frameElement?.style.setProperty(`opacity`, `1`)\n\n if (viewportDimensions) {\n staticLayout(frameElement, {\n width: viewportDimensions.width ?? 1,\n height: viewportDimensions.height ?? 1,\n })\n } else {\n staticLayout(frameElement, {\n width: contentWidth,\n height: contentHeight,\n })\n }\n\n if (viewportDimensions) {\n frameElement?.style.setProperty(`position`, `absolute`)\n frameElement?.style.setProperty(`top`, `50%`)\n\n if (spreadPosition === `left`) {\n frameElement?.style.setProperty(`right`, `0`)\n frameElement?.style.removeProperty(`left`)\n } else if (blankPagePosition === `before` && isRTL) {\n frameElement?.style.setProperty(`right`, `50%`)\n frameElement?.style.removeProperty(`left`)\n } else if (spreadPosition === `right`) {\n frameElement?.style.setProperty(`left`, `0`)\n frameElement?.style.removeProperty(`right`)\n } else {\n frameElement?.style.setProperty(\n `left`,\n blankPagePosition === `before`\n ? isRTL\n ? `25%`\n : `75%`\n : blankPagePosition === `after`\n ? isRTL\n ? `75%`\n : `25%`\n : `50%`,\n )\n frameElement?.style.removeProperty(`right`)\n }\n const transformTranslateX = spreadPosition !== `none` ? `0` : `-50%`\n const transformOriginX =\n spreadPosition === `right` && blankPagePosition !== `before`\n ? `left`\n : spreadPosition === `left` ||\n (blankPagePosition === `before` && isRTL)\n ? `right`\n : `center`\n frameElement?.style.setProperty(\n `transform`,\n `translate(${transformTranslateX}, -50%) scale(${computedScale})`,\n )\n frameElement?.style.setProperty(\n `transform-origin`,\n `${transformOriginX} center`,\n )\n } else {\n if (blankPagePosition === `before`) {\n if (isRTL) {\n frameElement?.style.setProperty(`margin-right`, `${pageWidth}px`)\n } else {\n frameElement?.style.setProperty(`margin-left`, `${pageWidth}px`)\n }\n } else {\n frameElement?.style.removeProperty(`margin-left`)\n frameElement?.style.removeProperty(`margin-right`)\n }\n }\n\n return { width: minimumWidth, height: contentHeight }\n }\n\n return { width: minimumWidth, height: pageHeight }\n}\n","/**\n * Item is:\n * - anything that contains a defined width/height viewport\n *\n * In this case we respect the viewport, scale it and act as pre-paginated.\n *\n * Using a viewport means the page should fit and be displayed as it is. This\n * is one of the reason of using viewport.\n *\n * Ideally we should not touch too much of how things are presented, especially\n * images since this mode would be most often used for it.\n *\n * Changing text display needs to be done carefully as well since it may overflow\n * Again this is because the page is designed to fit perfectly due to viewport\n */\nexport const buildStyleForViewportFrame = () => {\n return `\n body {\n margin: 0;\n }\n html {\n width: 100%;\n height: 100%;\n }\n body {\n width: 100%;\n height: 100%;\n margin: 0;\n }\n ${\n /*\n * @see https://hammerjs.github.io/touch-action/\n */\n ``\n }\n html, body {\n touch-action: none;\n }\n `\n}\n\n/**\n * Item is:\n * - not pre-paginated (we would not be in this item otherwise)\n * - jpg, png, etc\n *\n * It does not means it has to be pre-paginated (scrollable for example)\n */\nexport const buildStyleForReflowableImageOnly = ({\n isScrollable,\n enableTouch,\n}: {\n enableTouch: boolean\n isScrollable: boolean\n}) => {\n return `\n ${\n /*\n * @see https://hammerjs.github.io/touch-action/\n */\n ``\n }\n html, body {\n width: 100%;\n margin: 0;\n padding: 0;\n ${\n !enableTouch\n ? `\n touch-action: none\n `\n : ``\n }\n }\n ${\n isScrollable\n ? `\n img {\n height: auto !important;\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n ${\n // we make sure img spread on entire screen\n ``\n }\n width: 100%;\n ${\n /**\n * line break issue\n * @see https://stackoverflow.com/questions/37869020/image-not-taking-up-the-full-height-of-container\n */\n ``\n }\n display: block;\n }\n `\n : ``\n }\n `\n}\n\n/**\n * Item is:\n * - regular html document\n * - does not contain defined width/height viewport\n *\n * We use css multi column to paginate it\n *\n * @important\n * The style here does not takes margin into account, we assume everything is 0.\n * It is being handled by enhancer.\n */\nexport const buildStyleWithMultiColumn = ({\n width,\n columnHeight,\n columnWidth,\n}: {\n width: number\n columnWidth: number\n columnHeight: number\n}) => {\n return `\n parsererror {\n display: none !important;\n }\n ${\n /*\n might be html * but it does mess up things like figure if so.\n check accessible_epub_3\n */ ``\n }\n html, body {\n margin: 0;\n padding: 0 !important;\n -max-width: ${columnWidth}px !important;\n }\n ${\n /*\n body {\n height: ${columnHeight}px !important;\n width: ${columnWidth}px !important;\n -margin-left: ${horizontalMargin}px !important;\n -margin-right: ${horizontalMargin}px !important;\n -margin: ${verticalMargin}px ${horizontalMargin}px !important;\n -padding-top: ${horizontalMargin}px !important;\n -padding-bottom: ${horizontalMargin}px !important;\n }\n */ ``\n }\n body {\n padding: 0 !important;\n width: ${width}px !important;\n height: ${columnHeight}px !important;\n overflow-y: hidden;\n column-gap: 0px !important;\n column-width: ${columnWidth}px !important;\n column-fill: auto !important;\n word-wrap: break-word;\n box-sizing: border-box;\n }\n body {\n margin: 0;\n }\n body:focus-visible {\n ${\n /*\n we make sure that there are no outline when we focus something inside the iframe\n */ ``\n }\n outline: none;\n }\n ${\n /*\n * @see https://hammerjs.github.io/touch-action/\n */\n ``\n }\n html, body {\n touch-action: none;\n }\n ${\n /*\n this messes up hard, be careful with this\n */ ``\n }\n * {\n -max-width: ${columnWidth}px !important;\n }\n ${\n /*\n this is necessary to have a proper calculation when determining size\n of iframe content. If an img is using something like width:100% it would expand to\n the size of the original image and potentially gives back a wrong size (much larger)\n @see https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Columns/Handling_Overflow_in_Multicol\n */ ``\n }\n img, video, audio, object, svg {\n max-width: 100%;\n -max-width: ${columnWidth}px !important;\n -max-height: ${columnHeight}px !important;\n -pointer-events: none;\n -webkit-column-break-inside: avoid;\n page-break-inside: avoid;\n break-inside: avoid;\n }\n figure {\n d-max-width: ${columnWidth}px !important;\n }\n img {\n object-fit: contain;\n break-inside: avoid;\n box-sizing: border-box;\n d-max-width: ${columnWidth}px !important;\n }\n ${\n /*\n img, video, audio, object, svg {\n max-height: ${columnHeight}px !important;\n box-sizing: border-box;\n object-fit: contain;\n -webkit-column-break-inside: avoid;\n page-break-inside: avoid;\n break-inside: avoid;\n }\n */ ``\n }\n table {\n max-width: ${columnWidth}px !important;\n table-layout: fixed;\n }\n td {\n max-width: ${columnWidth}px;\n }\n `\n}\n","import type { Manifest } from \"@prose-reader/shared\"\nimport { upsertCSSToFrame } from \"../../../../utils/frames\"\nimport { getViewPortInformation } from \"../prePaginated/renderPrePaginated\"\nimport {\n buildStyleForReflowableImageOnly,\n buildStyleForViewportFrame,\n buildStyleWithMultiColumn,\n} from \"./styles\"\n\nconst getDimensionsForReflowableContent = ({\n isUsingVerticalWriting,\n minimumWidth,\n pageHeight,\n pageWidth,\n}: {\n isUsingVerticalWriting: boolean\n minimumWidth: number\n pageWidth: number\n pageHeight: number\n}) => {\n const horizontalMargin = 0\n const verticalMargin = 0\n let columnWidth = pageWidth - horizontalMargin * 2\n const columnHeight = pageHeight - verticalMargin * 2\n let width = pageWidth - horizontalMargin * 2\n\n if (isUsingVerticalWriting) {\n width = minimumWidth - horizontalMargin * 2\n columnWidth = columnHeight\n }\n\n return {\n columnHeight,\n columnWidth,\n width,\n }\n}\n\n/**\n * Upward layout is used when the parent wants to manipulate the iframe without triggering\n * `layout` event. This is a particular case needed for iframe because the parent can layout following\n * an iframe `layout` event. Because the parent `layout` may change some of iframe properties we do not\n * want the iframe to trigger a new `layout` even and have infinite loop.\n */\nconst staticLayout = (\n frameElement: HTMLIFrameElement,\n size: { width: number; height: number },\n) => {\n frameElement.style.width = `${size.width}px`\n frameElement.style.height = `${size.height}px`\n}\n\nexport const renderReflowable = ({\n pageHeight: pageSizeHeight,\n pageWidth,\n frameElement,\n manifest,\n minPageSpread,\n isRTL,\n blankPagePosition,\n isImageType,\n enableTouch,\n isUsingVerticalWriting,\n}: {\n blankPagePosition: `before` | `after` | `none`\n pageWidth: number\n pageHeight: number\n frameElement: HTMLIFrameElement\n manifest?: Manifest\n minPageSpread: number\n isRTL: boolean\n isImageType: boolean\n enableTouch: boolean\n isUsingVerticalWriting: boolean\n}) => {\n const minimumWidth = minPageSpread * pageWidth\n const continuousScrollableReflowableItem =\n manifest?.renditionLayout === \"reflowable\" &&\n manifest?.renditionFlow === \"scrolled-continuous\"\n\n /**\n * In case of reflowable with continuous scrolling, we don't know if the content is\n * bigger or smaller than the page size, therefore we find a middle ground to have\n * a pre-load page that is not too big nor too small to prevent weird jumping\n * once the frame load.\n *\n * We also use a minimum height still because we don't want all of the items to\n * preload since they would be in the current viewport.\n *\n * @todo make it a setting\n */\n const pageHeight = continuousScrollableReflowableItem\n ? Math.min(400, pageSizeHeight)\n : pageSizeHeight\n\n // reset width of iframe to be able to retrieve real size later\n frameElement?.style.setProperty(`width`, `${pageWidth}px`)\n\n /**\n * In case of reflowable with continuous scrolling, we let the frame takes whatever height\n * it needs since it could be less or more than page size and we want a continuous reading\n */\n if (!continuousScrollableReflowableItem) {\n frameElement?.style.setProperty(`height`, `${pageHeight}px`)\n } else {\n frameElement?.style.removeProperty(`height`)\n }\n\n const { viewportDimensions, computedScale = 1 } =\n getViewPortInformation({\n frameElement,\n pageHeight,\n pageWidth,\n }) ?? {}\n const isGloballyPrePaginated = manifest?.renditionLayout === `pre-paginated`\n\n // @todo simplify ? should be from common spine item\n if (\n frameElement?.contentDocument &&\n frameElement?.contentWindow &&\n frameElement.contentDocument.body\n ) {\n let contentWidth = pageWidth\n let contentHeight = pageHeight\n\n if (viewportDimensions?.hasViewport) {\n upsertCSSToFrame(\n frameElement,\n `prose-reader-html-renderer-framce-css`,\n buildStyleForViewportFrame(),\n )\n\n staticLayout(frameElement, {\n width: viewportDimensions.width ?? 1,\n height: viewportDimensions.height ?? 1,\n })\n\n frameElement?.style.setProperty(`position`, `absolute`)\n frameElement?.style.setProperty(`top`, `50%`)\n frameElement?.style.setProperty(\n `left`,\n blankPagePosition === `before`\n ? isRTL\n ? `25%`\n : `75%`\n : blankPagePosition === `after`\n ? isRTL\n ? `75%`\n : `25%`\n : `50%`,\n )\n\n frameElement?.style.setProperty(\n `transform`,\n `translate(-50%, -50%) scale(${computedScale})`,\n )\n frameElement?.style.setProperty(`transform-origin`, `center center`)\n } else {\n const frameStyle = isImageType\n ? buildStyleForReflowableImageOnly({\n isScrollable: manifest?.renditionFlow === `scrolled-continuous`,\n enableTouch,\n })\n : buildStyleWithMultiColumn(\n getDimensionsForReflowableContent({\n isUsingVerticalWriting: isUsingVerticalWriting,\n minimumWidth,\n pageHeight,\n pageWidth,\n }),\n )\n\n upsertCSSToFrame(frameElement, `prose-reader-css`, frameStyle, true)\n\n if (isUsingVerticalWriting) {\n const pages = Math.ceil(\n frameElement.contentDocument.documentElement.scrollHeight /\n pageHeight,\n )\n contentHeight = pages * pageHeight\n\n staticLayout(frameElement, {\n width: minimumWidth,\n height: contentHeight,\n })\n } else if (manifest?.renditionFlow === `scrolled-continuous`) {\n /**\n * We take body content here because the frame body might be smaller after\n * layout due to possible image content and image ratio. We need to be able\n * to retrieve the actual real body height. The window height is probably the same\n * as the current frame set height which may be wrong after resize.\n */\n contentHeight = frameElement.contentDocument.body.scrollHeight\n\n staticLayout(frameElement, {\n width: minimumWidth,\n height: contentHeight,\n })\n } else {\n const pages = Math.ceil(\n frameElement.contentDocument.documentElement.scrollWidth / pageWidth,\n )\n /**\n * It is possible that a pre-paginated epub has reflowable item inside it. This is weird because\n * the spec says that we should use pre-paginated for each spine item. Could be a publisher mistake, in\n * any case we follow the spec and enforce the iframe to be contained within page width.\n * If we don't respect the spec we end up with dynamic pagination for a fixed document, which can update\n * the correct number of pages when item is loaded/unload. Bringing weird user experience.\n * The publisher should use global reflowable with pre-paginated content instead.\n */\n if (isGloballyPrePaginated) {\n contentWidth = pageWidth\n } else {\n contentWidth = pages * pageWidth\n }\n\n staticLayout(frameElement, {\n width: contentWidth,\n height: contentHeight,\n })\n }\n }\n\n const isFillingAllScreen = contentWidth % minimumWidth === 0\n\n // when a reflow iframe does not fill the entire screen (when spread) we will\n // enlarge the container to make sure no other reflow item starts on the same screen\n if (!isFillingAllScreen) {\n contentWidth = contentWidth + pageWidth\n if (isRTL && !isUsingVerticalWriting) {\n frameElement?.style.setProperty(`margin-left`, `${pageWidth}px`)\n }\n } else {\n frameElement?.style.setProperty(`margin-left`, `0px`)\n }\n\n return { width: contentWidth, height: contentHeight }\n }\n\n return undefined\n}\n","import { detectMimeTypeFromName } from \"@prose-reader/shared\"\nimport { EMPTY, from, map, of, switchMap, tap } from \"rxjs\"\nimport { DocumentRenderer } from \"../../../spineItem/renderer/DocumentRenderer\"\nimport {\n upsertCSSToFrame,\n waitForFrameLoad,\n waitForFrameReady,\n} from \"../../../utils/frames\"\nimport { waitForSwitch } from \"../../../utils/rxjs\"\nimport { loadAssets, unloadAssets } from \"./assets\"\nimport { attachFrameSrc } from \"./attachFrameSrc\"\nimport { createFrameElement } from \"./createFrameElement\"\nimport prePaginatedStyle from \"./prePaginated/pre-paginated.css?inline\"\nimport { renderPrePaginated } from \"./prePaginated/renderPrePaginated\"\n// import reflowableImageStyle from \"./reflowable/reflowable-image.css?inline\"\nimport { renderReflowable } from \"./reflowable/renderReflowable\"\nexport class HtmlRenderer extends DocumentRenderer {\n onCreateDocument() {\n const frameElement = createFrameElement()\n\n this.setDocumentContainer(frameElement)\n\n return of(frameElement)\n }\n\n onLoadDocument() {\n const frameElement = this.getFrameElement()\n\n if (!frameElement) throw new Error(`invalid frame`)\n\n return of(frameElement).pipe(\n attachFrameSrc({\n item: this.item,\n resourcesHandler: this.resourcesHandler,\n settings: this.settings,\n }),\n waitForSwitch(this.context.bridgeEvent.viewportFree$),\n tap(() => {\n this.attach()\n }),\n waitForFrameLoad,\n tap((frameElement) => {\n if (this.isPrePaginated()) {\n upsertCSSToFrame(frameElement, `prose-reader-css`, prePaginatedStyle)\n } else {\n if (this.isImageType()) {\n // upsertCSSToFrame(\n // frameElement,\n // `prose-reader-css`,\n // reflowableImageStyle,\n // )\n } else {\n // upsertCSSToFrame(frameElement, `prose-reader-css`, reflowableStyle)\n }\n }\n }),\n loadAssets({\n context: this.context,\n item: this.item,\n settings: this.settings,\n }),\n waitForFrameReady,\n )\n }\n\n onUnload() {\n unloadAssets(this.getFrameElement())\n\n this.detach()\n\n return EMPTY\n }\n\n onLayout({\n minPageSpread,\n blankPagePosition,\n spreadPosition,\n }: {\n minPageSpread: number\n blankPagePosition: `before` | `after` | `none`\n spreadPosition: `none` | `left` | `right`\n }) {\n const { width: pageWidth, height: pageHeight } = this.viewport.pageSize\n const frameElement = this.getFrameElement()\n\n if (!frameElement) return of(undefined)\n\n const isUsingVerticalWriting = !!this.writingMode?.startsWith(`vertical`)\n\n /**\n * When we have scrollable content, we use \"native\" touch event from the frame instead of\n * our own gestures.\n * @todo move this into scroll navigator\n */\n const isTouchEnabled =\n this.settings.values.computedPageTurnMode === `scrollable`\n\n if (frameElement.contentDocument?.documentElement) {\n frameElement.contentDocument?.documentElement.setAttribute(\n `data-prose-reader-html-renderer-spread-position`,\n spreadPosition,\n )\n if (isTouchEnabled) {\n frameElement.contentDocument?.documentElement.classList.add(\n `prose-reader-html-renderer-touch-enabled`,\n )\n } else {\n frameElement.contentDocument?.documentElement.classList.remove(\n `prose-reader-html-renderer-touch-enabled`,\n )\n }\n }\n\n if (this.isPrePaginated()) {\n const dims = renderPrePaginated({\n blankPagePosition,\n frameElement,\n isRTL: this.context.isRTL(),\n minPageSpread,\n pageHeight,\n pageWidth,\n spreadPosition,\n })\n\n return of(dims)\n }\n\n const dims = renderReflowable({\n pageHeight,\n pageWidth,\n frameElement,\n manifest: this.context.manifest,\n blankPagePosition,\n isUsingVerticalWriting,\n isRTL: this.context.isRTL(),\n minPageSpread,\n isImageType: this.isImageType(),\n /**\n * When we have scrollable content, we use \"native\" touch event from the frame instead of\n * our own gestures.\n * @todo move this into scroll navigator\n */\n enableTouch: this.settings.values.computedPageTurnMode === `scrollable`,\n })\n\n return of(dims)\n }\n\n onRenderHeadless() {\n return from(this.resourcesHandler.fetchResource()).pipe(\n switchMap((resource) => {\n if (resource instanceof Response) {\n const contentType = resource.headers.get(\"content-type\") ?? \"\"\n const parsableContentTypes: DOMParserSupportedType[] = [\n `application/xhtml+xml`,\n `application/xml`,\n `text/html`,\n `text/xml`,\n ]\n\n if (\n parsableContentTypes.includes(contentType as DOMParserSupportedType)\n ) {\n return from(resource.text()).pipe(\n map((text) => {\n const domParser = new DOMParser()\n const doc = domParser.parseFromString(\n text,\n contentType as DOMParserSupportedType,\n )\n\n return doc\n }),\n )\n }\n }\n\n return of(undefined)\n }),\n )\n }\n\n private isPrePaginated = () => {\n return (\n this.item.renditionLayout === `pre-paginated` ||\n (!this.item.renditionLayout &&\n this.context.manifest?.renditionLayout === `pre-paginated`)\n )\n }\n\n private isImageType = () => {\n const mimeType =\n this.item.mediaType ?? detectMimeTypeFromName(this.item.href)\n\n return !!mimeType?.startsWith(`image/`)\n }\n\n private getFrameElement() {\n const frame = this.documentContainer\n\n if (!(frame instanceof HTMLIFrameElement)) return\n\n return frame\n }\n\n // @todo optimize\n public getComputedStyleAfterLoad() {\n const frame = this.getFrameElement()\n\n const body = frame?.contentDocument?.body\n\n if (body) {\n return frame?.contentWindow?.getComputedStyle(body)\n }\n }\n\n get writingMode() {\n return this.getComputedStyleAfterLoad()?.writingMode as\n | `vertical-rl`\n | `horizontal-tb`\n | undefined\n }\n\n get readingDirection() {\n const writingMode = this.writingMode\n\n if (writingMode === `vertical-rl`) {\n return `rtl`\n }\n\n const direction = this.getComputedStyleAfterLoad()?.direction\n\n switch (direction) {\n case `ltr`:\n case `inherit`:\n case `initial`: {\n return `ltr`\n }\n\n case `rtl`:\n return `rtl`\n\n default:\n return undefined\n }\n }\n\n getDocumentFrame() {\n return this.getFrameElement()\n }\n}\n","import { takeUntil } from \"rxjs\"\nimport type {\n EnhancerOptions,\n EnhancerOutput,\n RootEnhancer,\n} from \"../types/enhancer\"\nimport { handleLinks } from \"./links\"\nimport { HtmlRenderer } from \"./renderer/HtmlRenderer\"\n\ntype HandleLinksReturnType = ReturnType<typeof handleLinks>\n\nexport type HtmlEnhancerOutput = {\n links$: HandleLinksReturnType\n}\n\nexport const htmlEnhancer =\n <\n InheritOptions extends EnhancerOptions<RootEnhancer>,\n InheritOutput extends EnhancerOutput<RootEnhancer>,\n >(\n next: (options: InheritOptions) => InheritOutput,\n ) =>\n (\n options: InheritOptions,\n ): InheritOutput & {\n links$: HandleLinksReturnType\n } => {\n const reader = next({\n ...options,\n getRenderer(item) {\n const maybeFactory = options.getRenderer?.(item)\n\n return maybeFactory ?? ((props) => new HtmlRenderer(props))\n },\n })\n\n const links$ = handleLinks(reader)\n\n links$.pipe(takeUntil(reader.$.destroy$)).subscribe()\n\n return {\n ...reader,\n links$,\n }\n }\n","export function isDefined<T>(\n arg: T | null | undefined,\n): arg is T extends null | undefined ? never : T {\n return arg !== null && arg !== undefined\n}\n","export class LayoutEntry {\n public readonly left: number\n public readonly right: number\n public readonly top: number\n public readonly bottom: number\n public readonly width: number\n public readonly height: number\n public readonly x: number\n public readonly y: number\n\n constructor(layout: {\n left: number\n right: number\n top: number\n bottom: number\n width: number\n height: number\n x: number\n y: number\n }) {\n this.left = layout.left\n this.right = layout.right\n this.top = layout.top\n this.bottom = layout.bottom\n this.width = layout.width\n this.height = layout.height\n this.x = layout.x\n this.y = layout.y\n }\n}\n\nexport class SpineItemPosition {\n public readonly x: number\n public readonly y: number\n public readonly __symbol = Symbol(`SpineItemPosition`)\n\n constructor(position: { x: number; y: number }) {\n this.x = position.x\n this.y = position.y\n }\n}\n\n/**\n * Allow out of bounds positions\n */\nexport class UnboundSpineItemPagePosition {\n public readonly x: number\n public readonly y: number\n public readonly __symbol = Symbol(`SpineItemPagePosition`)\n\n constructor(position: { x: number; y: number }) {\n this.x = position.x\n this.y = position.y\n }\n}\n\nexport class SpineItemPageLayout extends LayoutEntry {\n public readonly __symbol = `SpineItemPageLayout`\n}\n","import { LayoutEntry } from \"../spineItem/types\"\n\n/**\n * Position of an item relative to spine element.\n *\n * LTR (Spine spread positively from left=0)\n * [item1 ] [item2]\n * [0, 100] [100, 200]\n * [x: 0, y: 0] [x: 100, y: 0]\n *\n * RTL (Spine spread negatively from right=0)\n * [item1 ] [item2]\n * [-100, 0] [0, 100]\n * [left: -100, right: 0] [left: 0, right: 100]\n *\n * This allow the viewport to move in a natural position following the reading direction.\n *\n * This is similar to `getBoundingClientRect` but is stable since it is absolute and will not\n * changed if any transformation is applied to the spine. A different term could be absolute position\n * of an element relative to the book view.\n *\n * You can leverage this layout info for positioning overlay elements (eg: bookmarks).\n */\nexport class SpineItemSpineLayout extends LayoutEntry {\n public readonly __symbol = `SpineItemSpineLayout`\n}\n\nexport class SpineItemPageSpineLayout extends LayoutEntry {\n public readonly __symbol = `SpineItemPageSpineLayout`\n}\n\nexport class AbstractSpinePosition {\n public readonly x: number\n public readonly y: number\n\n constructor(position: { x: number; y: number }) {\n this.x = position.x\n this.y = position.y\n }\n}\n\n/**\n * Guaranteed to be a valid spine position at a given layout.\n *\n * Meaning:\n * - within safe edges x/y\n * - at a valid page edge offset\n */\nexport class SpinePosition extends AbstractSpinePosition {\n public readonly __symbol = `SpinePosition`\n\n static from(position: UnboundSpinePosition | SpinePosition) {\n return new SpinePosition(position)\n }\n}\n\n/**\n * Represents a spine position that may not be:\n * - within safe edges x/y (eg: out of bounds)\n * - at a page edge offset (eg: 20% on a page)\n *\n * Such spine position is usually used for scroll navigation or calculations\n * of relative things.\n *\n * This is just a class to flag potential misuses, getting a UnboundSpinePosition does not\n * means the position is offset.\n */\nexport class UnboundSpinePosition extends AbstractSpinePosition {\n public readonly __symbol = `UnboundSpinePosition`\n\n static from(position: SpinePosition) {\n return new UnboundSpinePosition(position)\n }\n}\n","export const getPositionRelativeToNonTransformedElement = (\n position: { x: number; y: number },\n element: HTMLElement,\n) => {\n const elementRect = element.getBoundingClientRect()\n const { x, y } = position\n const { left, top } = elementRect\n\n // Get the scale factors\n const scaleX = elementRect.width / element.offsetWidth\n const scaleY = elementRect.height / element.offsetHeight\n\n // Calculate position relative to the transformed element\n const relativeX = x - left\n const relativeY = y - top\n\n // Convert back to non-transformed coordinates\n return {\n x: relativeX / scaleX,\n y: relativeY / scaleY,\n }\n}\n","import type { Reader } from \"../../reader\"\nimport { UnboundSpinePosition } from \"../../spine/types\"\nimport { getPositionRelativeToNonTransformedElement } from \"../../utils/coordinates\"\n\nexport const getSpinePositionFromClientPosition = (\n position: { x: number; y: number },\n spineElement: HTMLElement,\n) => {\n // Convert back to non-transformed coordinates\n return new UnboundSpinePosition(\n getPositionRelativeToNonTransformedElement(position, spineElement),\n )\n}\n\nexport const createCoordinatesApi = (reader: Reader) => {\n return {\n getSpinePositionFromClientPosition: (position: { x: number; y: number }) =>\n reader.spine.element\n ? getSpinePositionFromClientPosition(position, reader.spine.element)\n : undefined,\n }\n}\n","import {\n animationFrameScheduler,\n merge,\n NEVER,\n Observable,\n of,\n scheduled,\n} from \"rxjs\"\nimport {\n distinctUntilChanged,\n map,\n switchMap,\n take,\n takeUntil,\n tap,\n} from \"rxjs/operators\"\nimport type { Reader } from \"../../reader\"\n\n/**\n * For some reason (bug / expected / engine layout optimization) when the viewport is being animated clicking inside iframe\n * sometimes returns invalid clientX value. This means that when rapidly (or not) clicking during animation on iframe will often\n * time returns invalid value. In order to reduce potential unwanted behavior on consumer side, we temporarily hide the iframe behind\n * an overlay. That way the overlay take over for the pointer event and we all good.\n *\n * @important\n * This obviously block any interaction with iframe but there should not be such interaction with iframe in theory.\n * Theoretically if user decide to interact during the animation that's either to stop it or swipe the pages.\n */\nexport const createMovingSafePan$ = (reader: Reader) => {\n let iframeOverlayForAnimationsElement: HTMLDivElement | undefined\n\n const updateOverlayElement$ = reader.context.watch(\"rootElement\").pipe(\n switchMap((rootElement) => {\n if (!rootElement) return NEVER\n\n return new Observable(() => {\n iframeOverlayForAnimationsElement =\n rootElement.ownerDocument.createElement(`div`)\n iframeOverlayForAnimationsElement.style.cssText = `\n position: absolute;\n left: 0;\n top: 0;\n width: 100%;\n height: 100%;\n visibility: hidden;\n `\n rootElement.appendChild(iframeOverlayForAnimationsElement)\n\n return () => {\n iframeOverlayForAnimationsElement?.remove()\n iframeOverlayForAnimationsElement = undefined\n }\n })\n }),\n )\n\n const createResetLock$ = <T>(source: Observable<T>) =>\n scheduled(source, animationFrameScheduler).pipe(\n tap(() => {\n iframeOverlayForAnimationsElement?.style.setProperty(\n `visibility`,\n `hidden`,\n )\n }),\n )\n\n const lockAfterViewportBusy$ = reader.context.bridgeEvent.viewportBusy$.pipe(\n tap(() => {\n iframeOverlayForAnimationsElement?.style.setProperty(\n `visibility`,\n `visible`,\n )\n }),\n )\n\n const resetLockViewportFree$ = createResetLock$(reader.viewportFree$).pipe(\n take(1),\n )\n\n const pageTurnMode$ = reader.settings.values$.pipe(\n map(() => reader.settings.values.computedPageTurnMode),\n distinctUntilChanged(),\n )\n\n const handleViewportLock$ = pageTurnMode$.pipe(\n switchMap((mode) =>\n mode === `controlled`\n ? lockAfterViewportBusy$.pipe(switchMap(() => resetLockViewportFree$))\n : createResetLock$(of(undefined)),\n ),\n takeUntil(reader.$.destroy$),\n )\n\n return merge(updateOverlayElement$, handleViewportLock$)\n}\n","import type { Manifest } from \"@prose-reader/shared\"\nimport { combineLatest, merge, type Observable } from \"rxjs\"\nimport { switchMap, tap } from \"rxjs/operators\"\nimport { HTML_PREFIX as HTML_PREFIX_CORE } from \"../../constants\"\nimport type { Reader } from \"../../reader\"\nimport type { Viewport } from \"../../viewport/Viewport\"\nimport type { Theme } from \"../theme\"\n\nexport const HTML_PREFIX = `${HTML_PREFIX_CORE}-enhancer-loading`\nexport const CONTAINER_HTML_PREFIX = `${HTML_PREFIX}-container`\n\n/**\n * We use iframe for loading element mainly to be able to use share hooks / manipulation\n * with iframe. That way the loading element always match whatever style is applied to iframe.\n */\nconst defaultLoadingElementCreate = ({\n container,\n item,\n viewport,\n}: {\n container: HTMLElement\n item: Manifest[`spineItems`][number]\n viewport: Viewport\n}) => {\n const loadingElementContainer = container.ownerDocument.createElement(`div`)\n loadingElementContainer.classList.add(CONTAINER_HTML_PREFIX)\n loadingElementContainer.style.cssText = `\n height: 100%;\n width: 100%;\n max-width: ${viewport.absoluteViewport.width}px;\n text-align: center;\n display: flex;\n justify-content: center;\n align-items: center;\n flex-direction: column;\n position: absolute;\n left: 0;\n top: 0;\n color: rgb(202, 202, 202);\n background-color: white;\n z-index: 1;\n `\n\n const logoElement = loadingElementContainer.ownerDocument.createElement(`div`)\n logoElement.innerText = `prose`\n logoElement.style.cssText = `\n font-size: 4em;\n `\n const detailsElement =\n loadingElementContainer.ownerDocument.createElement(`div`)\n detailsElement.setAttribute(`data-details-element`, `true`)\n detailsElement.innerText = `loading ${item.id}`\n detailsElement.style.cssText = `\n font-size: 1.2em;\n text-overflow: ellipsis;\n white-space: nowrap;\n overflow: hidden;\n max-width: 300px;\n width: 80%;\n `\n loadingElementContainer.appendChild(logoElement)\n loadingElementContainer.appendChild(detailsElement)\n\n return loadingElementContainer\n}\n\nexport const createPlaceholderPages = (\n reader: Reader & { theme: { $: { theme$: Observable<Theme> } } },\n) => {\n return reader.spineItemsManager.items$.pipe(\n switchMap((items) =>\n merge(\n ...items.map((item) => {\n // since we will use z-index for the loading element, we need to set the parent\n // to 0 to have it work as relative reference.\n item.containerElement.style.zIndex = `0`\n\n const alreadyExistingElement = item.containerElement.querySelector(\n `.${CONTAINER_HTML_PREFIX}`,\n )\n\n const loadingElementContainer =\n alreadyExistingElement instanceof HTMLElement\n ? alreadyExistingElement\n : defaultLoadingElementCreate({\n container: item.containerElement,\n item: item.item,\n viewport: reader.viewport,\n })\n\n item.containerElement.appendChild(loadingElementContainer)\n\n return merge(\n item.pipe(\n tap((state) => {\n loadingElementContainer.style.setProperty(\n `visibility`,\n state.isReady ? `hidden` : `visible`,\n )\n loadingElementContainer.style.setProperty(\n `z-index`,\n state.isReady ? `0` : `1`,\n )\n\n if (state.isError) {\n const detailsElement = loadingElementContainer.querySelector(\n `[data-details-element]`,\n )\n if (detailsElement instanceof HTMLElement) {\n detailsElement.innerText =\n state.error?.toString() ?? `Unknown error`\n }\n }\n }),\n ),\n combineLatest([reader.spine.layout$, reader.theme.$.theme$]).pipe(\n tap(([, theme]) => {\n const viewportWidth = reader.viewport.absoluteViewport.width\n\n loadingElementContainer.style.setProperty(\n `max-width`,\n `${viewportWidth}px`,\n )\n loadingElementContainer.style.setProperty(\n `color`,\n theme === `sepia` ? `#939393` : `rgb(202, 202, 202)`,\n )\n }),\n ),\n )\n }),\n ),\n ),\n )\n}\n","import type { Reader } from \"../../reader\"\n\nexport const fixIframeScrollbar = (reader: Reader) => {\n /**\n * Sometimes when iframe is being loaded and resized during layout, a scrollbar\n * may appear on the iframe#document level. It will be \"empty\" but stay there and\n * catch scrolling events instead.\n *\n * It is possible to prevent it by setting overflow: hidden in the iframe#html\n * element but I feel like this could have side effects and therefore it's better\n * to just disable it the old way even if this is deprecated.\n */\n reader.hookManager.register(`item.onDocumentLoad`, ({ itemId }) => {\n const spineItem = reader.spineItemsManager.get(itemId)\n const element = spineItem?.renderer.getDocumentFrame()\n\n element?.setAttribute(\"scrolling\", \"no\")\n })\n}\n","import type { Reader } from \"../../reader\"\nimport { getFrameViewportInfo } from \"../../utils/frames\"\n\nexport const fixReflowable = (reader: Reader) => {\n /**\n * Handle page spread for reflowable item that act as pre-paginated\n *\n * - we have a reflowable item\n * - we want page spread\n * - the item has viewport dimension\n * - normal reflowable should not have viewport and should spread correctly\n * - because it has viewport we will scale the item to one page size (pre-paginated)\n *\n * @problem\n * If no blank page are demanded by the spine manager, the frame will be displayed\n * in the middle because of the item taking the entire width (spread). The spine manager\n * might not know that it is a pre-paginated because of missing meta and will not give\n * any blank page instruction.\n *\n * To fix the issue we manually add a blank page at the end if none were demanded\n *\n * @important\n * This fix might not be needed anymore if:\n *\n * - the core handle this kind of fake reflowable and insert blank page\n */\n reader.hookManager.register(\n `item.onAfterLayout`,\n ({ item, blankPagePosition, minimumWidth }) => {\n const spineItem = reader.spineItemsManager.get(item.id)\n const element = spineItem?.renderer.getDocumentFrame()\n\n if (\n !(spineItem?.renditionLayout === `reflowable`) ||\n !(element instanceof HTMLIFrameElement)\n )\n return\n\n const { hasViewport } = getFrameViewportInfo(element)\n const { width: pageWidth } = reader.viewport.pageSize\n const frameElement = spineItem?.renderer.getDocumentFrame()\n\n if (hasViewport) {\n const spineManagerWantAFullWidthItem = pageWidth < minimumWidth\n const noBlankPageAsked = blankPagePosition === `none`\n\n if (\n noBlankPageAsked &&\n spineManagerWantAFullWidthItem &&\n frameElement instanceof HTMLIFrameElement\n ) {\n frameElement?.style.setProperty(\n `left`,\n reader.context.isRTL() ? `75%` : `25%`,\n )\n }\n }\n },\n )\n}\n","import { tap } from \"rxjs\"\nimport type { Reader } from \"../../reader\"\n\nexport const flagSpineItems = (reader: Reader) => {\n return reader.spineItemsObserver.states$.pipe(\n tap(({ item, isReady, isDirty }) => {\n // biome-ignore lint/complexity/useLiteralKeys: TS needs it\n item.containerElement.dataset[\"isDirty\"] = isDirty.toString()\n // biome-ignore lint/complexity/useLiteralKeys: TS needs it\n item.containerElement.dataset[\"isReady\"] = isReady.toString()\n }),\n )\n}\n","import { SettingsManagerOverload } from \"../../settings/SettingsManagerOverload\"\nimport type {\n CoreInputSettings,\n CoreOutputSettings,\n} from \"../../settings/types\"\nimport { isShallowEqual } from \"../../utils/objects\"\nimport type { EnhancerLayoutInputSettings, OutputSettings } from \"./types\"\n\nexport class SettingsManager<\n ParentInputSettings extends CoreInputSettings,\n ParentOutputSettings extends CoreOutputSettings,\n> extends SettingsManagerOverload<\n EnhancerLayoutInputSettings,\n OutputSettings,\n ParentInputSettings,\n ParentOutputSettings\n> {\n computeOutputSettings(\n inputSettings: EnhancerLayoutInputSettings,\n ): EnhancerLayoutInputSettings {\n return inputSettings\n }\n\n hasSettingsChanged(newOutputSettings: EnhancerLayoutInputSettings): boolean {\n return !isShallowEqual(this.outputSettings, newOutputSettings)\n }\n\n getCleanedParentInputSettings(\n settings: Partial<EnhancerLayoutInputSettings & ParentInputSettings>,\n ): ParentInputSettings {\n const {\n layoutAutoResize: _unused1,\n pageHorizontalMargin: _unused2,\n pageVerticalMargin: _unused3,\n layoutLayerTransition: _unused4,\n ...rest\n } = settings\n\n return rest as unknown as ParentInputSettings\n }\n\n getDefaultSettings(): EnhancerLayoutInputSettings {\n return {\n layoutAutoResize: \"container\",\n pageHorizontalMargin: 24,\n pageVerticalMargin: 24,\n layoutLayerTransition: true,\n }\n }\n}\n","import { combineLatest, tap } from \"rxjs\"\nimport type { Reader } from \"../../reader\"\n\nexport const updateSpreadMode = (reader: Reader) => {\n return combineLatest([\n reader.viewport.watch([\"width\", \"height\"]),\n reader.context.watch(\"manifest\"),\n ]).pipe(\n tap(([{ width, height }, manifest]) => {\n const isLandscape = width > height\n\n if (!isLandscape && manifest?.renditionSpread === `portrait`) {\n return reader.settings.update({ spreadMode: true })\n }\n\n if (\n isLandscape &&\n (manifest?.renditionSpread === undefined ||\n manifest?.renditionSpread === `auto` ||\n manifest?.renditionSpread === `landscape` ||\n manifest?.renditionSpread === `both`)\n ) {\n return reader.settings.update({ spreadMode: true })\n }\n\n return reader.settings.update({ spreadMode: false })\n }),\n )\n}\n","import { detectMimeTypeFromName } from \"@prose-reader/shared\"\nimport { merge, type Observable, type ObservedValueOf } from \"rxjs\"\nimport {\n debounceTime,\n filter,\n shareReplay,\n skip,\n switchMap,\n takeUntil,\n tap,\n} from \"rxjs/operators\"\nimport type { SettingsInterface } from \"../../settings/SettingsInterface\"\nimport type { Pages } from \"../../spine/Pages\"\nimport { upsertCSSToFrame } from \"../../utils/frames\"\nimport { isDefined } from \"../../utils/isDefined\"\nimport { observeResize } from \"../../utils/rxjs\"\nimport type { themeEnhancer } from \"../theme\"\nimport type {\n EnhancerOptions,\n EnhancerOutput,\n RootEnhancer,\n} from \"../types/enhancer\"\nimport { createCoordinatesApi } from \"./coordinates\"\nimport { createMovingSafePan$ } from \"./createMovingSafePan$\"\nimport { createPlaceholderPages } from \"./createPlaceholderPages\"\nimport { fixIframeScrollbar } from \"./fixIframeScrollbar\"\nimport { fixReflowable } from \"./fixReflowable\"\nimport { flagSpineItems } from \"./flagSpineItems\"\nimport { SettingsManager } from \"./SettingsManager\"\nimport type { EnhancerLayoutInputSettings, OutputSettings } from \"./types\"\nimport { updateSpreadMode } from \"./updateSpreadMode\"\n\nexport type LayoutEnhancerOutput = {\n layout$: Observable<ObservedValueOf<Pages>>\n layoutInfo$: Observable<ObservedValueOf<Pages>>\n coordinates: ReturnType<typeof createCoordinatesApi>\n}\n\nexport const layoutEnhancer =\n <\n InheritOptions extends EnhancerOptions<RootEnhancer>,\n InheritOutput extends EnhancerOutput<typeof themeEnhancer>,\n InheritSettings extends NonNullable<\n InheritOutput[\"settings\"][\"_inputSettings\"]\n >,\n InheritComputedSettings extends NonNullable<\n InheritOutput[\"settings\"][\"_outputSettings\"]\n >,\n Output extends Omit<InheritOutput, \"settings\"> &\n LayoutEnhancerOutput & {\n settings: SettingsInterface<\n InheritSettings & EnhancerLayoutInputSettings,\n OutputSettings & InheritComputedSettings\n >\n },\n >(\n next: (options: InheritOptions) => InheritOutput,\n ) =>\n (options: InheritOptions & Partial<EnhancerLayoutInputSettings>): Output => {\n const {\n pageHorizontalMargin,\n pageVerticalMargin,\n layoutAutoResize,\n layoutLayerTransition,\n } = options\n const reader = next(options)\n\n const settingsManager = new SettingsManager<\n InheritSettings,\n InheritComputedSettings\n >(\n {\n pageHorizontalMargin,\n pageVerticalMargin,\n layoutAutoResize,\n layoutLayerTransition,\n },\n reader.settings as SettingsInterface<\n InheritSettings,\n InheritComputedSettings\n >,\n )\n\n reader.hookManager.register(`onViewportOffsetAdjust`, () => {\n let hasRedrawn = false\n\n /**\n * When adjusting the offset, there is a chance that pointer event being dispatched right after\n * have a wrong `clientX` / `pageX` etc. This is because even if the iframe\n * left value (once requested) is correct,\n * it does not seem to have been correctly taken by the browser when creating the event.\n * What we do here is that after a viewport adjustment we immediately force a reflow on the engine.\n *\n * @example\n * [pointer event] -> clientX = 50, left = 0, translated clientX = 50 (CORRECT)\n * [translate viewport] -> left = +100px\n * [pointer event] -> clientX = ~50, left = -100, translated clientX = ~-50 (INCORRECT)\n * [pointer event] -> clientX = 150, left = -100, translated clientX = 50 (CORRECT)\n *\n * For some reason the engine must be doing some optimization and unfortunately the first pointer event gets the clientX wrong.\n *\n * The bug can be observed by commenting this code, using CPU slowdown and increasing the throttle on the adjustment stream.\n * The bug seems to affect only chrome / firefox. Nor safari.\n *\n * Also we only need to use `getBoundingClientRect` once.\n *\n * @todo\n * Consider creating a bug ticket on both chromium and gecko projects.\n */\n reader.spineItemsManager.items.forEach((item) => {\n const frame = item.renderer.getDocumentFrame()\n\n if (!hasRedrawn && frame) {\n void frame.getBoundingClientRect().left\n hasRedrawn = true\n }\n })\n })\n\n /**\n * @todo move to theming\n */\n reader.hookManager.register(`item.onBeforeLayout`, ({ item }) => {\n const spineItem = reader.spineItemsManager.get(item.id)\n const mimeType = item.mediaType ?? detectMimeTypeFromName(item.href)\n const isImageType = !!mimeType?.startsWith(`image/`)\n\n const { pageHorizontalMargin = 0, pageVerticalMargin = 0 } =\n settingsManager.values\n const pageSize = reader.viewport.pageSize\n\n if (spineItem?.renditionLayout === `reflowable` && !isImageType) {\n let columnWidth = pageSize.width - pageHorizontalMargin * 2\n const columnHeight = pageSize.height - pageVerticalMargin * 2\n let width = pageSize.width - pageHorizontalMargin * 2\n let columnGap = pageHorizontalMargin * 2\n\n if (spineItem.isUsingVerticalWriting()) {\n width = pageSize.width - pageHorizontalMargin * 2\n columnWidth = columnHeight\n columnGap = pageVerticalMargin * 2\n }\n\n const frame = spineItem?.renderer.getDocumentFrame()\n\n if (frame) {\n upsertCSSToFrame(\n frame,\n `prose-layout-enhancer-css`,\n `\n body {\n width: ${width}px !important;\n margin: ${pageVerticalMargin}px ${pageHorizontalMargin}px !important;\n column-gap: ${columnGap}px !important;\n column-width: ${columnWidth}px !important;\n height: ${columnHeight}px !important;\n }\n img, video, audio, object, svg {\n -max-width: ${columnWidth}px !important;\n -max-height: ${columnHeight}px !important;\n }\n table {\n max-width: ${columnWidth}px !important;\n }\n td {\n max-width: ${columnWidth}px;\n }\n `,\n )\n }\n }\n })\n\n fixReflowable(reader)\n fixIframeScrollbar(reader)\n\n reader.hookManager.register(\n `item.onDocumentCreated`,\n ({ documentContainer }) => {\n /**\n * Hide document until it's ready\n */\n documentContainer.style.opacity = `0`\n if (settingsManager.values.layoutLayerTransition) {\n documentContainer.style.transition = `opacity 300ms`\n }\n },\n )\n\n reader.hookManager.register(`item.onBeforeLayout`, ({ item }) => {\n const spineItem = reader.spineItemsManager.get(item.id)\n\n const element = spineItem?.renderer.documentContainer\n\n // @todo dont remember why i did this but there should be a reason. If i get time to explain\n if (reader.settings.values.computedPageTurnMode !== `scrollable`) {\n // @todo see what's the impact\n element?.setAttribute(`tab-index`, `0`)\n }\n })\n\n const revealItemOnReady$ = reader.spineItemsObserver.states$.pipe(\n filter(({ isReady }) => isReady),\n tap(({ item }) => {\n const element = item.renderer.documentContainer\n\n if (element) {\n element.style.opacity = `1`\n }\n }),\n )\n\n // @todo fix the pan-start issue\n // @todo maybe increasing the hammer distance before triggering pan as well\n // reader.registerHook(`item.onDocumentLoad`, ({frame}) => {\n // frame.contentDocument?.body.addEventListener(`contextmenu`, e => {\n // e.preventDefault()\n // })\n // })\n\n const layoutOnContainerResize$ = settingsManager.values$.pipe(\n filter(({ layoutAutoResize }) => layoutAutoResize === \"container\"),\n switchMap(() => reader.context.watch(`rootElement`)),\n filter(isDefined),\n switchMap((element) => observeResize(element)),\n debounceTime(100),\n filter(isDefined),\n tap(() => {\n reader?.layout()\n }),\n )\n\n const movingSafePan$ = createMovingSafePan$(reader)\n\n settingsManager\n .watch([`pageHorizontalMargin`, `pageVerticalMargin`])\n .pipe(\n skip(1),\n tap(() => {\n reader.layout()\n }),\n takeUntil(reader.$.destroy$),\n )\n .subscribe()\n\n const layoutInfo$ = reader.spine.pages.pipe(\n shareReplay({ refCount: true, bufferSize: 1 }),\n )\n\n const flagSpineItems$ = flagSpineItems(reader)\n\n const updateSpreadMode$ = updateSpreadMode(reader)\n\n const placeholderPages$ = createPlaceholderPages(reader)\n\n merge(\n revealItemOnReady$,\n movingSafePan$,\n layoutOnContainerResize$,\n layoutInfo$,\n flagSpineItems$,\n updateSpreadMode$,\n placeholderPages$,\n )\n .pipe(takeUntil(reader.$.destroy$))\n .subscribe()\n\n return {\n ...reader,\n destroy: () => {\n settingsManager.destroy()\n reader.destroy()\n },\n settings: settingsManager,\n layout$: reader.spine.layout$,\n layoutInfo$,\n coordinates: createCoordinatesApi(reader),\n } as unknown as Output\n }\n","import { EMPTY, from, fromEvent, map, of, switchMap } from \"rxjs\"\nimport { DocumentRenderer } from \"../../spineItem/renderer/DocumentRenderer\"\n\nexport class ImageRenderer extends DocumentRenderer {\n private getImageElement() {\n const element = this.documentContainer\n\n if (!(element instanceof HTMLImageElement)) return undefined\n\n return element\n }\n\n onCreateDocument() {\n const imgElement = this.containerElement.ownerDocument.createElement(`img`)\n\n return from(this.resourcesHandler.getResource()).pipe(\n switchMap((responseOrUrl) => {\n this.setDocumentContainer(imgElement)\n\n imgElement.style.objectFit = `contain`\n imgElement.style.userSelect = `none`\n\n if (responseOrUrl instanceof URL) {\n return of(responseOrUrl.href)\n }\n if (responseOrUrl instanceof Response) {\n return from(responseOrUrl.blob()).pipe(\n map((blob) => {\n return URL.createObjectURL(blob)\n }),\n )\n }\n\n throw new Error(`Invalid resource`)\n }),\n map((src) => {\n const element = this.getImageElement()\n\n if (element) {\n element.src = src\n }\n\n return imgElement\n }),\n )\n }\n\n onLoadDocument() {\n const imageElement = this.getImageElement()\n\n if (!imageElement) throw new Error(`invalid element`)\n\n this.attach()\n\n return fromEvent(imageElement, `load`)\n }\n\n onUnload() {\n const imageElement = this.getImageElement()\n\n if (imageElement) {\n URL.revokeObjectURL(imageElement.src)\n }\n\n this.detach()\n\n return EMPTY\n }\n\n onLayout({\n spreadPosition,\n }: {\n minPageSpread: number\n blankPagePosition: `before` | `after` | `none`\n spreadPosition: `none` | `left` | `right`\n }) {\n const element = this.getImageElement()\n const { height: pageHeight, width: pageWidth } =\n this.viewport.value.pageSize\n\n let height = pageHeight\n\n const width = pageWidth\n\n if (!element) return of(undefined)\n\n const naturalWidth = element.naturalWidth || 1\n const naturalHeight = element.naturalHeight || 1\n const ratio = naturalWidth / naturalHeight\n\n /**\n * In case of continuous scroll, we scale up/down the height\n * to match the page width.\n */\n if (\n this.settings.values.computedPageTurnDirection === \"vertical\" &&\n this.settings.values.computedPageTurnMode === \"scrollable\" &&\n !this.settings.values.computedSpreadMode\n ) {\n height = Math.ceil(pageWidth / ratio)\n }\n\n element.style.height = `${height}px`\n element.style.width = `${width}px`\n element.style.objectPosition =\n spreadPosition === \"left\"\n ? `right`\n : spreadPosition === `right`\n ? `left`\n : `center`\n\n return of({\n width,\n height,\n })\n }\n\n onRenderHeadless() {\n return EMPTY\n }\n\n getDocumentFrame() {\n return undefined\n }\n}\n","import { detectMimeTypeFromName } from \"@prose-reader/shared\"\nimport type {\n EnhancerOptions,\n EnhancerOutput,\n RootEnhancer,\n} from \"../types/enhancer\"\nimport { ImageRenderer } from \"./ImageRenderer\"\n\nexport const mediaEnhancer =\n <\n InheritOptions extends EnhancerOptions<RootEnhancer>,\n InheritOutput extends EnhancerOutput<RootEnhancer>,\n >(\n next: (options: InheritOptions) => InheritOutput,\n ) =>\n (options: InheritOptions): InheritOutput => {\n const reader = next({\n ...options,\n getRenderer(item) {\n const maybeFactory = options.getRenderer?.(item)\n const mimeType = item.mediaType ?? detectMimeTypeFromName(item.href)\n const isImageType = !!mimeType?.startsWith(`image/`)\n\n if (!maybeFactory && isImageType) {\n return (props) => new ImageRenderer(props)\n }\n\n return maybeFactory\n },\n })\n\n const frameObserver = new IntersectionObserver(\n (entries) => {\n entries.forEach((entry) => {\n const frame = entry.target as HTMLIFrameElement\n const audios = Array.from(\n frame.contentDocument?.body.getElementsByTagName(`audio`) || [],\n )\n\n if (!entry.isIntersecting) {\n audios.forEach((audioElement) => {\n audioElement.pause()\n audioElement.currentTime = 0\n })\n } else {\n audios.forEach((audioElement) => {\n if (\n audioElement.hasAttribute(`autoplay`) &&\n audioElement.paused &&\n audioElement.readyState >= 2\n ) {\n audioElement.play().catch(console.error)\n }\n })\n }\n })\n },\n {\n threshold: 0.01,\n },\n )\n\n const elementObserver = new IntersectionObserver(\n (entries) => {\n entries.forEach((entry) => {\n if (entry.target.tagName === `video`) {\n const video = entry.target as HTMLVideoElement\n if (!entry.isIntersecting) {\n video.pause()\n video.currentTime = 0\n } else {\n if (video.hasAttribute(`autoplay`)) {\n // this can fail when we play the first time due to user not having interacted with\n // document yet. Browsers policy. autoplay will play it the first time anyway.\n if (video.paused && video.readyState >= 2) {\n video.play().catch(console.error)\n }\n }\n }\n }\n })\n },\n {\n threshold: 0.5,\n },\n )\n\n reader.hookManager.register(\n `item.onDocumentLoad`,\n ({ destroy, itemId }) => {\n const frame = reader.spineItemsManager\n .get(itemId)\n ?.renderer.getDocumentFrame()\n\n if (!frame) return\n\n frameObserver.observe(frame)\n\n const videos = frame.contentDocument?.body.getElementsByTagName(`video`)\n\n const unobserveElements = Array.from(videos || []).map((element) => {\n elementObserver.observe(element)\n\n return () => elementObserver.unobserve(element)\n })\n\n destroy(() => {\n frameObserver.unobserve(frame)\n unobserveElements.forEach((unobserve) => {\n unobserve()\n })\n })\n },\n )\n\n const destroy = () => {\n frameObserver.disconnect()\n elementObserver.disconnect()\n reader.destroy()\n }\n\n return {\n ...reader,\n destroy,\n }\n }\n","import { tap } from \"rxjs\"\nimport type { Reader } from \"../../reader\"\nimport { isHtmlTagElement } from \"../../utils/dom\"\nimport type { HtmlEnhancerOutput } from \"../html/enhancer\"\nimport type { ManualNavigator } from \"./navigators/manualNavigator\"\n\nexport const handleLinksNavigation = (\n reader: Reader & HtmlEnhancerOutput,\n manualNavigator: ManualNavigator,\n) => {\n return reader.links$.pipe(\n tap((event) => {\n if (!isHtmlTagElement(event.target, \"a\") || event.type !== \"click\") return\n\n const hrefUrl = new URL(event.target.href)\n const hrefWithoutAnchor = `${hrefUrl.origin}${hrefUrl.pathname}`\n\n // internal link, we can handle\n const hasExistingSpineItem = reader.context.manifest?.spineItems.some(\n (item) => item.href === hrefWithoutAnchor,\n )\n\n if (hasExistingSpineItem) {\n manualNavigator.goToUrl(hrefUrl)\n }\n }),\n )\n}\n","import { Report } from \"../../report\"\n\nexport const navigationReport = Report.namespace(`navigation`)\n","import type { SpineItem } from \"../../../spineItem/SpineItem\"\nimport type { SpineItemLocator } from \"../../../spineItem/locationResolver\"\nimport { SpineItemPosition } from \"../../../spineItem/types\"\n\nexport const getSpineItemPositionForLeftPage = ({\n position,\n spineItem,\n pageHeight,\n pageWidth,\n spineItemLocator,\n}: {\n position: SpineItemPosition\n spineItem: SpineItem\n pageWidth: number\n pageHeight: number\n spineItemLocator: SpineItemLocator\n}): SpineItemPosition => {\n let nextPotentialPosition = new SpineItemPosition({\n x: position.x - pageWidth,\n y: position.y,\n })\n\n if (spineItem.isUsingVerticalWriting()) {\n nextPotentialPosition = new SpineItemPosition({\n x: position.x,\n y: position.y + pageHeight,\n })\n }\n\n const navigationPosition =\n spineItemLocator.getSpineItemClosestPositionFromUnsafePosition(\n nextPotentialPosition,\n spineItem,\n )\n\n return navigationPosition\n}\n","import type { NavigationResolver } from \"../../../navigation/resolvers/NavigationResolver\"\nimport type { SpineLocator } from \"../../../spine/locator/SpineLocator\"\nimport type { SpineItemsManager } from \"../../../spine/SpineItemsManager\"\nimport { SpinePosition, type UnboundSpinePosition } from \"../../../spine/types\"\nimport type { Viewport } from \"../../../viewport/Viewport\"\nimport { getSpineItemPositionForLeftPage } from \"./getSpineItemPositionForLeftPage\"\n\nexport const getNavigationForLeftSinglePage = ({\n position,\n navigationResolver,\n computedPageTurnDirection,\n spineItemsManager,\n spineLocator,\n viewport,\n}: {\n position: SpinePosition | UnboundSpinePosition\n navigationResolver: NavigationResolver\n computedPageTurnDirection: \"horizontal\" | \"vertical\"\n spineItemsManager: SpineItemsManager\n spineLocator: SpineLocator\n viewport: Viewport\n}): SpinePosition | UnboundSpinePosition => {\n const pageTurnDirection = computedPageTurnDirection\n const spineItem =\n spineLocator.getSpineItemFromPosition(position) || spineItemsManager.get(0)\n const defaultNavigation = position\n\n if (!spineItem) {\n return defaultNavigation\n }\n\n const spineItemPosition = spineLocator.getSpineItemPositionFromSpinePosition(\n position,\n spineItem,\n )\n\n const spineItemNavigation = getSpineItemPositionForLeftPage({\n position: spineItemPosition,\n spineItem,\n pageHeight: viewport.pageSize.height,\n pageWidth: viewport.pageSize.width,\n spineItemLocator: spineLocator.spineItemLocator,\n })\n\n const isNewNavigationInCurrentItem = navigationResolver.arePositionsDifferent(\n spineItemNavigation,\n spineItemPosition,\n )\n\n if (!isNewNavigationInCurrentItem) {\n return navigationResolver.fromUnboundSpinePosition(\n pageTurnDirection === `horizontal`\n ? new SpinePosition({\n x: position.x - viewport.pageSize.width,\n y: 0,\n })\n : new SpinePosition({\n y: position.y - viewport.pageSize.height,\n x: 0,\n }),\n )\n }\n const readingOrderPosition =\n spineLocator.getSpinePositionFromSpineItemPosition({\n spineItemPosition: spineItemNavigation,\n spineItem,\n })\n\n return readingOrderPosition\n}\n","import type { Context } from \"../../../context/Context\"\nimport type { NavigationResolver } from \"../../../navigation/resolvers/NavigationResolver\"\nimport type { SettingsInterface } from \"../../../settings/SettingsInterface\"\nimport type {\n ComputedCoreSettings,\n CoreInputSettings,\n} from \"../../../settings/types\"\nimport type { SpineLocator } from \"../../../spine/locator/SpineLocator\"\nimport type { SpineItemsManager } from \"../../../spine/SpineItemsManager\"\nimport type { SpinePosition, UnboundSpinePosition } from \"../../../spine/types\"\nimport type { SpineItem } from \"../../../spineItem/SpineItem\"\nimport type { Viewport } from \"../../../viewport/Viewport\"\nimport { getNavigationForLeftSinglePage } from \"./getNavigationForLeftSinglePage\"\n\n/**\n * Very naive approach for spread. It could be optimized but by using this approach\n * we do not add complexity to the code and use the current logic to handle it correctly.\n *\n * @important\n * Special case for vertical content, read content\n */\nexport const getNavigationForLeftOrTopPage = ({\n position,\n spineItem,\n context,\n navigationResolver,\n spineItemsManager,\n spineLocator,\n computedPageTurnDirection,\n viewport,\n settings,\n}: {\n position: SpinePosition | UnboundSpinePosition\n spineItem: SpineItem\n context: Context\n spineItemsManager: SpineItemsManager\n navigationResolver: NavigationResolver\n spineLocator: SpineLocator\n computedPageTurnDirection: \"horizontal\" | \"vertical\"\n viewport: Viewport\n settings: SettingsInterface<\n CoreInputSettings,\n CoreInputSettings & ComputedCoreSettings\n >\n}): SpinePosition | UnboundSpinePosition => {\n const navigation = getNavigationForLeftSinglePage({\n position,\n viewport,\n navigationResolver,\n computedPageTurnDirection,\n spineItemsManager,\n spineLocator,\n })\n\n // when we move withing vertical content, because only y moves, we don't need two navigation\n if (spineItem?.isUsingVerticalWriting() && position.x === navigation.x) {\n return navigationResolver.getAdjustedPositionForSpread(navigation)\n }\n\n if (settings.values.computedSpreadMode) {\n // in case of spread the entire screen is taken as one real page for vertical content\n // in order to move out from it we add an extra page width.\n // using `getNavigationForLeftSinglePage` again would keep x as it is and wrongly move y\n // for the next item in case it's also a vertical content\n if (spineItem?.isUsingVerticalWriting() && position.x !== navigation.x) {\n return navigationResolver.getAdjustedPositionForSpread(\n navigationResolver.fromUnboundSpinePosition(\n context.isRTL()\n ? { ...navigation, x: navigation.x + viewport.pageSize.width }\n : {\n ...navigation,\n x: navigation.x - viewport.pageSize.width,\n },\n ),\n )\n }\n\n /**\n * In vase we move vertically and the y is already different, we don't need a second navigation\n * since we already jumped to a new screen\n */\n if (\n computedPageTurnDirection === `vertical` &&\n position.y !== navigation.y\n ) {\n return navigationResolver.getAdjustedPositionForSpread(navigation)\n }\n\n const doubleNavigation = getNavigationForLeftSinglePage({\n position: navigation,\n viewport,\n navigationResolver,\n computedPageTurnDirection,\n spineItemsManager,\n spineLocator,\n })\n\n return navigationResolver.getAdjustedPositionForSpread(doubleNavigation)\n }\n\n return navigationResolver.getAdjustedPositionForSpread(navigation)\n}\n","import type { SpineItemLocator } from \"../../../spineItem/locationResolver\"\nimport type { SpineItem } from \"../../../spineItem/SpineItem\"\nimport { SpineItemPosition } from \"../../../spineItem/types\"\n\nexport const getSpineItemPositionForRightPage = ({\n position,\n spineItem,\n pageHeight,\n pageWidth,\n spineItemLocator,\n}: {\n position: SpineItemPosition\n spineItem: SpineItem\n pageWidth: number\n pageHeight: number\n spineItemLocator: SpineItemLocator\n}): SpineItemPosition => {\n let nextPotentialPosition = new SpineItemPosition({\n x: position.x + pageWidth,\n y: position.y,\n })\n\n if (spineItem.isUsingVerticalWriting()) {\n nextPotentialPosition = new SpineItemPosition({\n x: position.x,\n y: position.y - pageHeight,\n })\n }\n\n const navigationPosition =\n spineItemLocator.getSpineItemClosestPositionFromUnsafePosition(\n nextPotentialPosition,\n spineItem,\n )\n\n return navigationPosition\n}\n","import type { NavigationResolver } from \"../../../navigation/resolvers/NavigationResolver\"\nimport type { SpineLocator } from \"../../../spine/locator/SpineLocator\"\nimport type { SpineItemsManager } from \"../../../spine/SpineItemsManager\"\nimport { type SpinePosition, UnboundSpinePosition } from \"../../../spine/types\"\nimport type { Viewport } from \"../../../viewport/Viewport\"\nimport { getSpineItemPositionForRightPage } from \"./getSpineItemPositionForRightPage\"\n\n/**\n * @important\n * Although we check for right page, it has the side effect to work for vertical\n * controlled books because when checking right page, we will get nothing and therefore\n * move the cursor to the next valid position, in turn getting the next bottom page.\n */\nexport const getNavigationForRightOrBottomSinglePage = ({\n position,\n navigationResolver,\n computedPageTurnDirection,\n spineItemsManager,\n spineLocator,\n viewport,\n}: {\n position: SpinePosition | UnboundSpinePosition\n navigationResolver: NavigationResolver\n computedPageTurnDirection: \"horizontal\" | \"vertical\"\n spineItemsManager: SpineItemsManager\n spineLocator: SpineLocator\n viewport: Viewport\n}): SpinePosition | UnboundSpinePosition => {\n const pageTurnDirection = computedPageTurnDirection\n const spineItem =\n spineLocator.getSpineItemFromPosition(position) || spineItemsManager.get(0)\n const defaultNavigation = position\n\n if (!spineItem) {\n return defaultNavigation\n }\n\n // translate viewport position into reading item local position\n const spineItemPosition = spineLocator.getSpineItemPositionFromSpinePosition(\n position,\n spineItem,\n )\n\n // get reading item local position for right page\n const spineItemNavigationForRightPage = getSpineItemPositionForRightPage({\n position: spineItemPosition,\n spineItem,\n pageHeight: viewport.pageSize.height,\n pageWidth: viewport.pageSize.width,\n spineItemLocator: spineLocator.spineItemLocator,\n })\n\n // check both position to see if we moved out of it\n const positionsAreDifferent = navigationResolver.arePositionsDifferent(\n spineItemNavigationForRightPage,\n spineItemPosition,\n )\n\n if (!positionsAreDifferent) {\n return navigationResolver.fromUnboundSpinePosition(\n pageTurnDirection === `horizontal`\n ? new UnboundSpinePosition({\n x: position.x + viewport.pageSize.width,\n y: 0,\n })\n : new UnboundSpinePosition({\n y: position.y + viewport.pageSize.height,\n x: 0,\n }),\n )\n }\n\n const readingOrderPosition =\n spineLocator.getSpinePositionFromSpineItemPosition({\n spineItemPosition: spineItemNavigationForRightPage,\n spineItem,\n })\n\n return readingOrderPosition\n}\n","import type { Context } from \"../../../context/Context\"\nimport type { NavigationResolver } from \"../../../navigation/resolvers/NavigationResolver\"\nimport type { SettingsInterface } from \"../../../settings/SettingsInterface\"\nimport type {\n ComputedCoreSettings,\n CoreInputSettings,\n} from \"../../../settings/types\"\nimport type { SpineLocator } from \"../../../spine/locator/SpineLocator\"\nimport type { SpineItemsManager } from \"../../../spine/SpineItemsManager\"\nimport type { SpinePosition, UnboundSpinePosition } from \"../../../spine/types\"\nimport type { SpineItem } from \"../../../spineItem/SpineItem\"\nimport type { Viewport } from \"../../../viewport/Viewport\"\nimport { getNavigationForRightOrBottomSinglePage } from \"./getNavigationForRightOrBottomSinglePage\"\n\n/**\n * Very naive approach for spread. It could be optimized but by using this approach\n * we do not add complexity to the code and use the current logic to handle it correctly.\n *\n * @important\n * Special case for vertical content, read content\n */\nexport const getNavigationForRightOrBottomPage = ({\n position,\n spineItem,\n context,\n navigationResolver,\n spineItemsManager,\n spineLocator,\n computedPageTurnDirection,\n viewport,\n settings,\n}: {\n position: SpinePosition | UnboundSpinePosition\n spineItem: SpineItem\n context: Context\n spineItemsManager: SpineItemsManager\n navigationResolver: NavigationResolver\n spineLocator: SpineLocator\n computedPageTurnDirection: \"horizontal\" | \"vertical\"\n viewport: Viewport\n settings: SettingsInterface<\n CoreInputSettings,\n CoreInputSettings & ComputedCoreSettings\n >\n}): SpinePosition => {\n const navigation = getNavigationForRightOrBottomSinglePage({\n position,\n viewport,\n navigationResolver,\n computedPageTurnDirection,\n spineItemsManager,\n spineLocator,\n })\n\n // when we move withing vertical content, because only y moves, we don't need two navigation\n if (spineItem?.isUsingVerticalWriting() && position.x === navigation.x) {\n return navigationResolver.getAdjustedPositionForSpread(navigation)\n }\n\n if (settings.values.computedSpreadMode) {\n // in case of spread the entire screen is taken as one real page for vertical content\n // in order to move out from it we add an extra page width.\n // using `getNavigationForLeftSinglePage` again would keep x as it is and wrongly move y\n // for the next item in case it's also a vertical content\n if (spineItem?.isUsingVerticalWriting() && position.x !== navigation.x) {\n return navigationResolver.getAdjustedPositionForSpread(\n navigationResolver.fromUnboundSpinePosition(\n context.isRTL()\n ? {\n ...navigation,\n x: navigation.x - viewport.pageSize.width,\n }\n : {\n ...navigation,\n x: navigation.x + viewport.pageSize.width,\n },\n ),\n )\n }\n\n /**\n * In vase we move vertically and the y is already different, we don't need a second navigation\n * since we already jumped to a new screen\n */\n if (\n computedPageTurnDirection === `vertical` &&\n position.y !== navigation.y\n ) {\n return navigationResolver.getAdjustedPositionForSpread(navigation)\n }\n\n const doubleNavigation = getNavigationForRightOrBottomSinglePage({\n position: navigation,\n viewport,\n navigationResolver,\n computedPageTurnDirection,\n spineItemsManager,\n spineLocator,\n })\n\n return navigationResolver.getAdjustedPositionForSpread(doubleNavigation)\n }\n\n return navigationResolver.getAdjustedPositionForSpread(navigation)\n}\n","import type { UserNavigationEntry } from \"../../../navigation/types\"\nimport type { Reader } from \"../../../reader\"\nimport { SpinePosition } from \"../../../spine/types\"\nimport type { SpineItemReference } from \"../../../spineItem/SpineItem\"\nimport { navigationReport } from \"../report\"\nimport { getNavigationForLeftOrTopPage } from \"../resolvers/getNavigationForLeftOrTopPage\"\nimport { getNavigationForRightOrBottomPage } from \"../resolvers/getNavigationForRightOrBottomPage\"\n\nexport class ManualNavigator {\n movingLastDelta = { x: 0, y: 0 }\n movingLastPosition = new SpinePosition({ x: 0, y: 0 })\n unlock: ReturnType<Reader[\"navigation\"][\"lock\"]> | undefined = undefined\n\n constructor(protected reader: Reader) {}\n\n turnRight() {\n return this.turnRightOrBottom()\n }\n\n turnLeft() {\n return this.turnLeftOrTop()\n }\n\n turnTop() {\n return this.turnLeftOrTop()\n }\n\n turnBottom() {\n return this.turnRightOrBottom()\n }\n\n turnRightOrBottom() {\n const navigation = this.reader.navigation.getNavigation()\n const spineItem = this.reader.spineItemsManager.get(navigation.spineItem)\n\n if (!spineItem) return\n\n const position = getNavigationForRightOrBottomPage({\n context: this.reader.context,\n navigationResolver: this.reader.navigation.navigationResolver,\n position: navigation.position,\n computedPageTurnDirection:\n this.reader.settings.values.computedPageTurnDirection,\n spineItem,\n spineItemsManager: this.reader.spineItemsManager,\n spineLocator: this.reader.spine.locator,\n viewport: this.reader.viewport,\n settings: this.reader.settings,\n })\n\n return this.reader.navigation.navigate({\n position,\n })\n }\n\n turnLeftOrTop() {\n const navigation = this.reader.navigation.getNavigation()\n const spineItem = this.reader.spineItemsManager.get(navigation.spineItem)\n\n if (!spineItem) return\n\n const position = getNavigationForLeftOrTopPage({\n context: this.reader.context,\n navigationResolver: this.reader.navigation.navigationResolver,\n position: navigation.position,\n computedPageTurnDirection:\n this.reader.settings.values.computedPageTurnDirection,\n spineItem,\n spineItemsManager: this.reader.spineItemsManager,\n spineLocator: this.reader.spine.locator,\n viewport: this.reader.viewport,\n settings: this.reader.settings,\n })\n\n return this.reader.navigation.navigate({\n position,\n })\n }\n\n goToCfi(cfi: string, options: { animate: boolean } = { animate: true }) {\n return this.reader.navigation.navigate({\n animation: options.animate ? \"turn\" : false,\n cfi,\n })\n }\n\n goToSpineItem({\n indexOrId,\n ...rest\n }: { indexOrId: SpineItemReference } & Pick<\n UserNavigationEntry,\n \"animation\"\n >) {\n const spineItem = this.reader.spineItemsManager.get(indexOrId)\n\n if (spineItem === undefined) {\n navigationReport.warn(\n `goToSpineItem`,\n `Ignore navigation to ${indexOrId} since the item does not exist`,\n )\n\n return\n }\n\n this.reader.navigation.navigate({\n spineItem: spineItem.index,\n ...rest,\n })\n }\n\n goToNextSpineItem() {\n const { endIndex = 0 } =\n this.reader.spine.locator.getVisibleSpineItemsFromPosition({\n position: this.reader.navigation.getNavigation().position,\n threshold: { type: \"percentage\", value: 0.5 },\n }) || {}\n\n this.goToSpineItem({ indexOrId: endIndex + 1 })\n }\n\n goToPreviousSpineItem() {\n const { beginIndex = 0 } =\n this.reader.spine.locator.getVisibleSpineItemsFromPosition({\n position: this.reader.navigation.getNavigation().position,\n threshold: { type: \"percentage\", value: 0.5 },\n }) ?? {}\n\n this.goToSpineItem({ indexOrId: beginIndex - 1 })\n }\n\n goToUrl(url: string | URL) {\n this.reader.navigation.navigate({\n url,\n animation: false,\n })\n }\n\n goToRightSpineItem() {\n if (this.reader.settings.values.computedPageTurnDirection === \"vertical\") {\n navigationReport.warn(\n `You cannot call this navigation method on vertical direction`,\n )\n\n return\n }\n\n if (this.reader.context.isRTL()) {\n return this.goToPreviousSpineItem()\n }\n\n return this.goToNextSpineItem()\n }\n\n goToRightOrBottomSpineItem() {\n if (this.reader.settings.values.computedPageTurnDirection === \"vertical\") {\n return this.goToBottomSpineItem()\n }\n\n return this.goToRightSpineItem()\n }\n\n goToLeftOrTopSpineItem() {\n if (this.reader.settings.values.computedPageTurnDirection === \"vertical\") {\n return this.goToTopSpineItem()\n }\n\n return this.goToLeftSpineItem()\n }\n\n goToLeftSpineItem() {\n if (this.reader.settings.values.computedPageTurnDirection === \"vertical\") {\n navigationReport.warn(\n `You cannot call this navigation method on vertical direction`,\n )\n\n return\n }\n\n if (this.reader.context.isRTL()) {\n return this.goToNextSpineItem()\n }\n\n return this.goToPreviousSpineItem()\n }\n\n goToTopSpineItem() {\n if (\n this.reader.settings.values.computedPageTurnDirection === \"horizontal\"\n ) {\n navigationReport.warn(\n `You cannot call this navigation method on horizontal direction`,\n )\n\n return\n }\n\n return this.goToPreviousSpineItem()\n }\n\n goToBottomSpineItem() {\n if (\n this.reader.settings.values.computedPageTurnDirection === \"horizontal\"\n ) {\n navigationReport.warn(\n `You cannot call this navigation method on horizontal direction`,\n )\n\n return\n }\n\n return this.goToNextSpineItem()\n }\n\n goToPageOfSpineItem({\n pageIndex,\n spineItemId,\n ...rest\n }: {\n pageIndex: number\n spineItemId: string | number\n } & Pick<UserNavigationEntry, \"animation\">) {\n const position =\n this.reader.navigation.navigationResolver.getNavigationForSpineItemPage({\n pageIndex,\n spineItemId,\n })\n\n navigationReport.debug(`.goToPageOfSpineItem()`, {\n pageIndex,\n spineItemId,\n ...rest,\n position,\n })\n\n this.reader.navigation.navigate({\n position,\n ...rest,\n })\n }\n\n goToAbsolutePageIndex({\n absolutePageIndex,\n ...rest\n }: { absolutePageIndex: number } & Pick<UserNavigationEntry, \"animation\">) {\n const foundInfo =\n this.reader.spine.pages.fromAbsolutePageIndex(absolutePageIndex)\n\n navigationReport.debug(`.goToAbsolutePageIndex()`, {\n absolutePageIndex,\n ...rest,\n foundInfo,\n })\n\n if (foundInfo) {\n const position =\n this.reader.navigation.navigationResolver.getNavigationForSpineItemPage(\n {\n pageIndex: foundInfo.pageIndex,\n spineItemId: foundInfo.itemIndex,\n },\n )\n\n return this.reader.navigation.navigate({\n position,\n ...rest,\n })\n }\n }\n}\n","import type { Reader } from \"../../../reader\"\nimport { SpinePosition, type UnboundSpinePosition } from \"../../../spine/types\"\nimport { ReactiveEntity } from \"../../../utils/ReactiveEntity\"\nimport { navigationReport } from \"../report\"\nexport class PanNavigator extends ReactiveEntity<{\n lastDelta: { x: number; y: number }\n lastPosition: SpinePosition | UnboundSpinePosition\n lastStartPosition: SpinePosition\n isStarted: boolean\n}> {\n unlock: ReturnType<Reader[\"navigation\"][\"lock\"]> | undefined = undefined\n\n constructor(protected reader: Reader) {\n super({\n lastDelta: { x: 0, y: 0 },\n lastPosition: new SpinePosition({ x: 0, y: 0 }),\n lastStartPosition: new SpinePosition({ x: 0, y: 0 }),\n isStarted: false,\n })\n }\n\n start(delta: { x: number; y: number }) {\n this.unlock?.()\n this.unlock = this.reader.navigation.lock()\n\n this.mergeCompare({\n isStarted: true,\n lastDelta: delta,\n lastStartPosition:\n this.reader.navigation.controlledNavigationController.viewportPosition,\n lastPosition:\n this.reader.navigation.controlledNavigationController.viewportPosition,\n })\n }\n\n stop(delta: { x: number; y: number }) {\n this.panMoveTo(delta)\n\n this.mergeCompare({\n isStarted: false,\n })\n\n this.unlock?.()\n }\n\n panMoveTo(delta: { x: number; y: number } | undefined) {\n if (this.reader.settings.values.computedPageTurnMode === `scrollable`) {\n navigationReport.warn(\n `pan control is not available on free page turn mode`,\n )\n\n return\n }\n\n if (!this.value.isStarted) {\n navigationReport.error(`Pan navigator is not started`)\n\n return\n }\n\n const pageTurnDirection =\n this.reader.settings.values.computedPageTurnDirection\n\n let navigation: SpinePosition | UnboundSpinePosition =\n this.reader.navigation.getNavigation().position\n\n if (delta) {\n const viewportScale =\n this.reader.viewport.absoluteViewport.width /\n this.reader.viewport.relativeViewport.width\n /**\n * We floor the delta to avoid having wrong direction derived because of\n * some sub pixel difference due to gesture precision\n */\n const correctedX = Math.floor(delta.x) - (this.value.lastDelta?.x || 0)\n const correctedY = Math.floor(delta.y) - (this.value.lastDelta?.y || 0)\n const x = Math.floor(\n pageTurnDirection === `horizontal`\n ? this.value.lastPosition.x - correctedX / viewportScale\n : 0,\n )\n const y = Math.floor(\n pageTurnDirection === `horizontal`\n ? 0\n : this.value.lastPosition.y - correctedY / viewportScale,\n )\n\n navigation = new SpinePosition({\n x,\n y,\n })\n\n this.mergeCompare({\n lastDelta: delta,\n })\n } else {\n navigation = this.value.lastPosition\n }\n\n this.mergeCompare({\n lastPosition: navigation,\n })\n\n this.reader.navigation.navigate({\n position: navigation,\n animation: false,\n })\n }\n}\n","import { Subject } from \"rxjs\"\n\nexport class DestroyableClass {\n protected isDestroyed = false\n private destroySubject = new Subject<void>()\n\n protected destroy$ = this.destroySubject.asObservable()\n\n public destroy() {\n if (this.isDestroyed) return\n\n this.isDestroyed = true\n\n this.destroySubject.next()\n this.destroySubject.complete()\n }\n}\n","import {\n animationFrameScheduler,\n debounceTime,\n exhaustMap,\n finalize,\n first,\n merge,\n of,\n Subject,\n takeUntil,\n tap,\n} from \"rxjs\"\nimport type { ScrollNavigationController } from \"../../../navigation/controllers/ScrollNavigationController\"\nimport type { Locker } from \"../../../navigation/Locker\"\nimport type { UserNavigationEntry } from \"../../../navigation/types\"\nimport { DestroyableClass } from \"../../../utils/DestroyableClass\"\n\nconst SCROLL_FINISHED_DEBOUNCE_TIMEOUT = 500\n\nexport class UserScrollNavigation extends DestroyableClass {\n /**\n * Navigation from external API.\n *\n * This is the navigation used by navigators and is not necessarily valid.\n * We need to verify and adjust the correct navigation afterward\n */\n protected navigationSubject = new Subject<UserNavigationEntry>()\n\n public navigation$ = this.navigationSubject.asObservable()\n\n constructor(\n protected scrollNavigationController: ScrollNavigationController,\n protected locker: Locker,\n ) {\n super()\n\n /**\n * Update the navigation as the user scroll.\n *\n * Keep it synchronized with scrolling. This should\n * not trigger viewport navigation, only update internal navigation.\n */\n const navigateOnScroll$ = this.scrollNavigationController.userScroll$.pipe(\n exhaustMap((event) => {\n const unlock = this.locker.lock()\n\n return merge(\n this.scrollNavigationController.userScroll$,\n of(event),\n ).pipe(\n debounceTime(\n SCROLL_FINISHED_DEBOUNCE_TIMEOUT,\n animationFrameScheduler,\n ),\n first(),\n tap(() => {\n const spinePosition =\n this.scrollNavigationController.fromScrollPosition(\n this.scrollNavigationController.scrollPosition,\n )\n\n this.navigationSubject.next({\n animation: false,\n type: \"scroll\",\n position: spinePosition,\n })\n }),\n finalize(() => {\n unlock()\n }),\n )\n }),\n )\n\n merge(navigateOnScroll$).pipe(takeUntil(this.destroy$)).subscribe()\n }\n}\n","import { distinctUntilChanged, map, withLatestFrom } from \"rxjs\"\nimport type { Reader } from \"../../reader\"\nimport { isShallowEqual } from \"../../utils/objects\"\n\nexport type State = ReturnType<typeof observeState>\n\nexport const observeState = (reader: Reader) => {\n return reader.pagination.state$.pipe(\n withLatestFrom(reader.context.manifest$, reader.settings.values$),\n map(\n ([\n paginationInfo,\n { spineItems, readingDirection },\n { computedPageTurnDirection },\n ]) => {\n const numberOfSpineItems = spineItems.length ?? 0\n const isAtAbsoluteBeginning = paginationInfo.beginSpineItemIndex === 0\n const isAtAbsoluteEnd =\n paginationInfo.endSpineItemIndex ===\n Math.max(numberOfSpineItems - 1, 0)\n\n const isAtEndSpineItem =\n paginationInfo.endSpineItemIndex ===\n Math.max(numberOfSpineItems - 1, 0)\n\n const isAtBeginSpineItem = paginationInfo.beginSpineItemIndex === 0\n\n const isAtBeginFirstPage =\n paginationInfo.beginPageIndexInSpineItem === 0\n\n const isAtEndLastPage =\n paginationInfo.endPageIndexInSpineItem ===\n paginationInfo.endNumberOfPagesInSpineItem - 1\n\n return {\n canTurnLeft:\n computedPageTurnDirection === \"vertical\"\n ? false\n : !isAtBeginFirstPage,\n canTurnRight:\n computedPageTurnDirection === \"vertical\" ? false : !isAtEndLastPage,\n canGoTopSpineItem:\n computedPageTurnDirection === \"vertical\" && !isAtAbsoluteBeginning,\n canGoBottomSpineItem:\n computedPageTurnDirection === \"vertical\" && !isAtAbsoluteEnd,\n canGoLeftSpineItem:\n computedPageTurnDirection !== \"vertical\" &&\n ((readingDirection === \"ltr\" && !isAtAbsoluteBeginning) ||\n (readingDirection === \"rtl\" && !isAtEndSpineItem)),\n canGoRightSpineItem:\n computedPageTurnDirection !== \"vertical\" &&\n ((readingDirection === \"ltr\" && !isAtAbsoluteEnd) ||\n (readingDirection === \"rtl\" && !isAtBeginSpineItem)),\n }\n },\n ),\n distinctUntilChanged(isShallowEqual),\n )\n}\n","import {\n animationFrameScheduler,\n finalize,\n type Observable,\n tap,\n throttleTime,\n} from \"rxjs\"\nimport type { Reader } from \"../../reader\"\n\nexport const throttleLock =\n ({ reader, duration }: { reader: Reader; duration: number }) =>\n <T>(stream: Observable<T>) => {\n let unlockFn: (() => void) | undefined\n const unlock = () => {\n unlockFn?.()\n unlockFn = undefined\n }\n\n return stream.pipe(\n tap(() => {\n if (!unlockFn) {\n unlockFn = reader?.navigation.lock()\n }\n }),\n throttleTime(duration, animationFrameScheduler, {\n trailing: true,\n leading: true,\n }),\n tap(unlock),\n finalize(unlock),\n )\n }\n","import { merge, takeUntil, tap } from \"rxjs\"\nimport type { HtmlEnhancerOutput } from \"../html/enhancer\"\nimport type {\n EnhancerOptions,\n EnhancerOutput,\n RootEnhancer,\n} from \"../types/enhancer\"\nimport { handleLinksNavigation } from \"./links\"\nimport { ManualNavigator } from \"./navigators/manualNavigator\"\nimport { PanNavigator } from \"./navigators/panNavigator\"\nimport { UserScrollNavigation } from \"./navigators/UserScrollNavigation\"\nimport { observeState } from \"./state\"\nimport { throttleLock } from \"./throttleLock\"\nimport type { NavigationEnhancerOutput } from \"./types\"\n\nexport const navigationEnhancer =\n <\n InheritOptions extends EnhancerOptions<RootEnhancer>,\n InheritOutput extends EnhancerOutput<RootEnhancer> & HtmlEnhancerOutput,\n >(\n next: (options: InheritOptions) => InheritOutput,\n ) =>\n (\n options: InheritOptions,\n ): Omit<InheritOutput, \"load\"> & NavigationEnhancerOutput => {\n const reader = next(options)\n const state$ = observeState(reader)\n const manualNavigator = new ManualNavigator(reader)\n const panNavigator = new PanNavigator(reader)\n const userScrollNavigation = new UserScrollNavigation(\n reader.navigation.scrollNavigationController,\n reader.navigation.locker,\n )\n\n const linksNavigation$ = handleLinksNavigation(reader, manualNavigator)\n const navigateOnUserScroll$ = userScrollNavigation.navigation$.pipe(\n tap((navigation) => {\n reader.navigation.navigate(navigation)\n }),\n )\n\n merge(linksNavigation$, navigateOnUserScroll$)\n .pipe(takeUntil(reader.$.destroy$))\n .subscribe()\n\n const load: NavigationEnhancerOutput[\"load\"] = (options) => {\n const { cfi, ...rest } = options\n\n reader.load(rest)\n\n if (cfi) {\n manualNavigator.goToCfi(cfi, { animate: false })\n }\n }\n\n const destroy = () => {\n userScrollNavigation.destroy()\n reader.destroy()\n }\n\n return {\n ...reader,\n load,\n destroy,\n navigation: {\n ...reader.navigation,\n state$,\n throttleLock: ({ duration, trigger }) =>\n trigger.pipe(throttleLock({ duration, reader })),\n panNavigator,\n turnBottom: manualNavigator.turnBottom.bind(manualNavigator),\n turnTop: manualNavigator.turnTop.bind(manualNavigator),\n turnLeftOrTop: manualNavigator.turnLeftOrTop.bind(manualNavigator),\n turnRightOrBottom:\n manualNavigator.turnRightOrBottom.bind(manualNavigator),\n turnLeft: manualNavigator.turnLeft.bind(manualNavigator),\n turnRight: manualNavigator.turnRight.bind(manualNavigator),\n goToCfi: manualNavigator.goToCfi.bind(manualNavigator),\n goToUrl: manualNavigator.goToUrl.bind(manualNavigator),\n goToSpineItem: manualNavigator.goToSpineItem.bind(manualNavigator),\n goToNextSpineItem:\n manualNavigator.goToNextSpineItem.bind(manualNavigator),\n goToPreviousSpineItem:\n manualNavigator.goToPreviousSpineItem.bind(manualNavigator),\n goToLeftOrTopSpineItem:\n manualNavigator.goToLeftOrTopSpineItem.bind(manualNavigator),\n goToRightOrBottomSpineItem:\n manualNavigator.goToRightOrBottomSpineItem.bind(manualNavigator),\n goToTopSpineItem:\n manualNavigator.goToTopSpineItem.bind(manualNavigator),\n goToBottomSpineItem:\n manualNavigator.goToBottomSpineItem.bind(manualNavigator),\n goToLeftSpineItem:\n manualNavigator.goToLeftSpineItem.bind(manualNavigator),\n goToRightSpineItem:\n manualNavigator.goToRightSpineItem.bind(manualNavigator),\n goToPageOfSpineItem:\n manualNavigator.goToPageOfSpineItem.bind(manualNavigator),\n goToAbsolutePageIndex:\n manualNavigator.goToAbsolutePageIndex.bind(manualNavigator),\n },\n }\n }\n","import { map, startWith } from \"rxjs\"\nimport type { Reader } from \"../../reader\"\nimport type { Manifest } from \"@prose-reader/shared\"\n\n/**\n * @todo\n * Using recursive here provoke this error\n * https://www.google.com/search?q=recursive+Exported+variable+has+or+is+using+namefrom+external+module+but+cannot+be+named.&rlz=1C5CHFA_en&sxsrf=AOaemvK4craypli45-fXfFRdfO82ibGRog%3A1631106978791&ei=orc4YZPUL-6tmAWJgKT4Dw&oq=recursive+Exported+variable+has+or+is+using+namefrom+external+module+but+cannot+be+named.&gs_lcp=Cgdnd3Mtd2l6EAM6BwgAEEcQsANKBAhBGABQjgdYjgdgtQtoAnACeACAAWGIAWGSAQExmAEAoAEByAEIwAEB&sclient=gws-wiz&ved=0ahUKEwiTrb6Au-_yAhXuFqYKHQkACf8Q4dUDCA4&uact=5\n * My guess is that something is wrong and I have too many recursive / inferred types everywhere and especially on the enhancer thingy.\n */\nexport type ChapterInfo = {\n title: string\n subChapter?: {\n title: string\n subChapter?: {\n title: string\n subChapter?: {\n title: string\n path: string\n }\n path: string\n }\n path: string\n }\n path: string\n}\n\n/**\n * @important it's important to compare only path vs path and or href vs href since\n * they have not comparable due to possible encoded values\n */\nconst buildChaptersInfo = (\n href: string,\n tocItem: NonNullable<Manifest[\"nav\"]>[\"toc\"],\n manifest: Manifest,\n): ChapterInfo | undefined => {\n const spineItemIndex = manifest.spineItems.findIndex(\n (item) => item.href === href,\n )\n\n return tocItem.reduce((acc: ChapterInfo | undefined, tocItem) => {\n const indexOfHash = tocItem.href.indexOf(`#`)\n const tocItemPathWithoutAnchor =\n indexOfHash > 0 ? tocItem.href.substr(0, indexOfHash) : tocItem.href\n const tocItemHrefWithoutFilename = tocItemPathWithoutAnchor.substring(\n 0,\n tocItemPathWithoutAnchor.lastIndexOf(\"/\"),\n )\n const hrefWithoutFilename = href.substring(0, href.lastIndexOf(\"/\"))\n\n const hrefIsChapterHref = href.endsWith(tocItemPathWithoutAnchor)\n const hrefIsWithinChapter =\n hrefWithoutFilename !== \"\" &&\n hrefWithoutFilename.endsWith(tocItemHrefWithoutFilename)\n\n /**\n * @important\n * A possible toc item candidate means that the chapter is at least not after the item.\n * It does not mean it's the correct chapter. The algorithm proceed by reducing every item\n * until we find the one that is not. We then return the last found one.\n *\n * This is the most important piece as it's the reason why we can detect all the pages\n * within a chapter.\n *\n * We rely on the order of items to be true. See https://www.w3.org/publishing/epub3/epub-packages.html#sec-nav-toc\n */\n const isPossibleTocItemCandidate = hrefIsChapterHref || hrefIsWithinChapter\n\n if (isPossibleTocItemCandidate) {\n const spineItemIndexOfPossibleCandidate = manifest.spineItems.findIndex(\n (item) => item.href === tocItem.href,\n )\n const spineItemIsBeforeThisTocItem =\n spineItemIndex < spineItemIndexOfPossibleCandidate\n\n if (spineItemIsBeforeThisTocItem) return acc\n\n const info = {\n title: tocItem.title,\n path: tocItem.path,\n }\n\n const subInfo = buildChaptersInfo(href, tocItem.contents, manifest)\n\n if (subInfo) {\n return {\n ...info,\n subChapter: subInfo,\n }\n }\n\n return info\n }\n\n return acc\n }, undefined)\n}\n\nconst buildChapterInfoFromSpineItem = (\n manifest: Manifest,\n item: Manifest[`spineItems`][number],\n) => {\n const { href } = item\n\n return buildChaptersInfo(href, manifest.nav?.toc ?? [], manifest)\n}\n\nexport const getChaptersInfo = (\n reader: Reader,\n): { [key: string]: ChapterInfo | undefined } => {\n const manifest = reader.context.manifest\n const items = reader.spineItemsManager.items\n\n if (!manifest) return {}\n\n return items.reduce(\n (acc, { item }) => {\n acc[item.id] = buildChapterInfoFromSpineItem(manifest, item)\n\n return acc\n },\n {} as { [key: string]: ChapterInfo | undefined },\n )\n}\n\nexport const trackChapterInfo = (reader: Reader) => {\n return reader.spineItemsManager.items$.pipe(\n startWith([]),\n map(() => getChaptersInfo(reader)),\n )\n}\n","import { first, map, withLatestFrom } from \"rxjs\"\nimport type { Reader } from \"../../reader\"\nimport type { SpineItem } from \"../../spineItem/SpineItem\"\nimport type { LayoutEnhancerOutput } from \"../layout/layoutEnhancer\"\n\nconst getTotalProgressFromPercentages = (\n estimateBeforeThisItem: number,\n currentItemWeight: number,\n progressWithinThisItem: number,\n) => {\n return estimateBeforeThisItem + currentItemWeight * progressWithinThisItem\n}\n\nconst getScrollPercentageWithinItem = (\n reader: Reader,\n currentPosition: { x: number; y: number },\n currentItem: SpineItem,\n) => {\n const { height, width } = currentItem.layoutInfo\n\n const { top, left } = reader.spine.getSpineItemSpineLayoutInfo(currentItem)\n\n if (reader.settings.values.computedPageTurnDirection === `vertical`) {\n return Math.max(\n 0,\n Math.min(\n 1,\n (currentPosition.y - top + reader.viewport.absoluteViewport.height) /\n height,\n ),\n )\n }\n return Math.max(\n 0,\n Math.min(\n 1,\n (currentPosition.x - left + reader.viewport.absoluteViewport.width) /\n width,\n ),\n )\n}\n\nexport const getPercentageEstimate = (\n reader: Reader & LayoutEnhancerOutput,\n currentSpineIndex: number,\n pageIndex: number,\n currentPosition: { x: number; y: number },\n currentItem: SpineItem,\n) => {\n return currentItem.isReady$.pipe(\n first(),\n withLatestFrom(reader.layoutInfo$),\n map(([itemIsReady, layout]) => {\n const context = reader.context\n\n const isGloballyPrePaginated =\n context.manifest?.renditionLayout === `pre-paginated`\n const readingOrderLength = context.manifest?.spineItems.length || 0\n const estimateBeforeThisItem =\n context.manifest?.spineItems\n .slice(0, currentSpineIndex)\n .reduce((acc, item) => acc + (item.progressionWeight ?? 0), 0) || 0\n const itemIndexNumber =\n reader.spineItemsManager.getSpineItemIndex(currentItem) ?? 0\n\n const numberOfSpineItems = reader.context.manifest?.spineItems.length ?? 0\n\n const spineItemNumberOfPages =\n layout.pages.filter((page) => page.itemIndex === itemIndexNumber)\n .length ?? 0\n\n const currentItemWeight =\n context.manifest?.spineItems[currentSpineIndex]?.progressionWeight ??\n // if no progressionWeight is defined we \"assume\" the document weight to be\n // relative to the total number of documents\n (itemIndexNumber + 1) / numberOfSpineItems\n\n let progressWithinThisItem =\n (pageIndex + 1) * (currentItemWeight / spineItemNumberOfPages)\n\n if (\n !isGloballyPrePaginated &&\n currentItem.renditionLayout === `reflowable` &&\n !itemIsReady\n ) {\n progressWithinThisItem = 0\n }\n\n let totalProgress = estimateBeforeThisItem + progressWithinThisItem\n\n if (context.manifest?.renditionFlow === `scrolled-continuous`) {\n if (itemIsReady) {\n progressWithinThisItem = getScrollPercentageWithinItem(\n reader,\n currentPosition,\n currentItem,\n )\n } else {\n // that way we avoid having a progress of 1 just because the item is not loaded and cover all screen due to smaller size.\n // Therefore it effectively prevent jump from 30% to 25% for example.\n progressWithinThisItem = 0\n }\n totalProgress = getTotalProgressFromPercentages(\n estimateBeforeThisItem,\n currentItemWeight,\n progressWithinThisItem,\n )\n }\n\n // because the rounding of weight use a lot of decimals we will end up with\n // something like 0.999878 for the last page\n if (\n currentSpineIndex === readingOrderLength - 1 &&\n pageIndex === spineItemNumberOfPages - 1 &&\n totalProgress > 0.99\n ) {\n return 1\n }\n\n return totalProgress\n }),\n )\n}\n","import {\n animationFrameScheduler,\n debounceTime,\n distinctUntilChanged,\n map,\n type Observable,\n startWith,\n withLatestFrom,\n} from \"rxjs\"\nimport type { Reader } from \"../../reader\"\nimport { isShallowEqual } from \"../../utils/objects\"\n\nexport const trackTotalPages = (reader: Reader) => {\n const totalPages$: Observable<{\n numberOfPagesPerItems: number[]\n numberOfTotalPages: number\n }> = reader.spine.layout$.pipe(\n debounceTime(10, animationFrameScheduler),\n withLatestFrom(reader.pagination.state$),\n map(() => {\n return {\n numberOfPagesPerItems: reader.spineItemsManager.items.reduce(\n (acc, item) => {\n return [...acc, item.numberOfPages]\n },\n [] as number[],\n ),\n /**\n * This may be not accurate for reflowable due to dynamic load / unload.\n */\n numberOfTotalPages: reader.spine.pages.value.pages.length,\n }\n }),\n distinctUntilChanged(isShallowEqual),\n startWith({\n numberOfPagesPerItems: [],\n numberOfTotalPages: 0,\n }),\n )\n\n return totalPages$\n}\n","import {\n BehaviorSubject,\n combineLatest,\n distinctUntilChanged,\n map,\n type Observable,\n type ObservedValueOf,\n of,\n shareReplay,\n switchMap,\n tap,\n} from \"rxjs\"\nimport type { PaginationInfo } from \"../../pagination/types\"\nimport type { Reader } from \"../../reader\"\nimport { isShallowEqual } from \"../../utils/objects\"\nimport type { LayoutEnhancerOutput } from \"../layout/layoutEnhancer\"\nimport { trackChapterInfo } from \"./chapters\"\nimport { getPercentageEstimate } from \"./progression\"\nimport { trackTotalPages } from \"./spine\"\nimport type { EnhancerPaginationInto, ExtraPaginationInfo } from \"./types\"\n\nexport const mapPaginationInfoToExtendedInfo = (\n reader: Reader,\n paginationInfo: PaginationInfo,\n chaptersInfo: ObservedValueOf<ReturnType<typeof trackChapterInfo>>,\n percentageEstimateOfBook: number,\n): Observable<\n Omit<\n ExtraPaginationInfo,\n | \"beginAbsolutePageIndex\"\n | \"endAbsolutePageIndex\"\n | \"beginAbsolutePageIndex\"\n | \"numberOfTotalPages\"\n >\n> => {\n const beginItem =\n paginationInfo.beginSpineItemIndex !== undefined\n ? reader.spineItemsManager.get(paginationInfo.beginSpineItemIndex)\n : undefined\n const endItem =\n paginationInfo.endSpineItemIndex !== undefined\n ? reader.spineItemsManager.get(paginationInfo.endSpineItemIndex)\n : undefined\n\n return of({\n ...paginationInfo,\n beginChapterInfo: beginItem ? chaptersInfo[beginItem.item.id] : undefined,\n // chapterIndex: number;\n // pages: number;\n // pageIndexInBook: number;\n // pageIndexInChapter: number;\n // pagesOfChapter: number;\n // pagePercentageInChapter: number;\n // offsetPercentageInChapter: number;\n // domIndex: number;\n // charOffset: number;\n // serializeString?: string;\n beginSpineItemReadingDirection: beginItem?.readingDirection,\n endChapterInfo: endItem ? chaptersInfo[endItem.item.id] : undefined,\n endSpineItemReadingDirection: endItem?.readingDirection,\n // spineItemReadingDirection: focusedSpineItem?.getReadingDirection(),\n /**\n * This percentage is based of the weight (kb) of every items and the number of pages.\n * It is not accurate but gives a general good idea of the overall progress.\n * It is recommended to use this progress only for reflow books. For pre-paginated books\n * the number of pages and current index can be used instead since 1 page = 1 chapter.\n */\n percentageEstimateOfBook,\n isUsingSpread: reader.settings.values.computedSpreadMode ?? false,\n // hasNextChapter: (reader.spine.spineItemIndex || 0) < (manifest.readingOrder.length - 1),\n // hasPreviousChapter: (reader.spine.spineItemIndex || 0) < (manifest.readingOrder.length - 1),\n // numberOfSpineItems: context.manifest?.readingOrder.length,\n })\n}\n\nconst observeProgression = (reader: Reader & LayoutEnhancerOutput) => {\n return combineLatest([\n reader.pagination.state$,\n // Usually pagination change if layout changes (number of pages) however it is especially\n // useful for like webtoon where you still have one page but only the layout will give you the final size\n // although the pagination will stay stable from the begining\n reader.layout$,\n ]).pipe(\n switchMap(([paginationInfo]) => {\n const endItem =\n paginationInfo.endSpineItemIndex !== undefined\n ? reader.spineItemsManager.get(paginationInfo.endSpineItemIndex)\n : undefined\n\n return endItem\n ? getPercentageEstimate(\n reader,\n paginationInfo.endSpineItemIndex ?? 0,\n paginationInfo.endPageIndexInSpineItem || 0,\n reader.navigation.getNavigation().position,\n endItem,\n )\n : of(0)\n }),\n )\n}\n\nexport const trackPaginationInfo = (reader: Reader & LayoutEnhancerOutput) => {\n const chaptersInfo$ = trackChapterInfo(reader)\n const totalPages$ = trackTotalPages(reader)\n const currentValue = new BehaviorSubject<EnhancerPaginationInto>({\n ...reader.pagination.state,\n beginChapterInfo: undefined,\n beginCfi: undefined,\n beginPageIndexInSpineItem: undefined,\n isUsingSpread: false,\n beginAbsolutePageIndex: 0,\n endAbsolutePageIndex: 0,\n numberOfTotalPages: 0,\n beginSpineItemReadingDirection: undefined,\n beginSpineItemIndex: undefined,\n endCfi: undefined,\n endChapterInfo: undefined,\n endSpineItemReadingDirection: undefined,\n percentageEstimateOfBook: 0,\n })\n\n const extandedBasePagination$ = combineLatest([\n reader.pagination.state$,\n chaptersInfo$,\n observeProgression(reader),\n ]).pipe(\n switchMap(([info, chaptersInfo, percentageEstimateOfBook]) =>\n mapPaginationInfoToExtendedInfo(\n reader,\n info,\n chaptersInfo,\n percentageEstimateOfBook,\n ).pipe(\n map((extendedInfo) => ({\n ...info,\n ...extendedInfo,\n })),\n ),\n ),\n distinctUntilChanged(isShallowEqual),\n )\n\n const paginationInfo$: Observable<EnhancerPaginationInto> = combineLatest([\n extandedBasePagination$,\n totalPages$,\n ]).pipe(\n map(([pageInfo, totalPageInfo]) => ({\n ...pageInfo,\n ...totalPageInfo,\n beginAbsolutePageIndex: totalPageInfo.numberOfPagesPerItems\n .slice(0, pageInfo.beginSpineItemIndex)\n .reduce(\n (acc, numberOfPagesForItem) => acc + numberOfPagesForItem,\n pageInfo.beginPageIndexInSpineItem ?? 0,\n ),\n endAbsolutePageIndex: totalPageInfo.numberOfPagesPerItems\n .slice(0, pageInfo.endSpineItemIndex)\n .reduce(\n (acc, numberOfPagesForItem) => acc + numberOfPagesForItem,\n pageInfo.endPageIndexInSpineItem ?? 0,\n ),\n })),\n tap((value) => {\n currentValue.next(value)\n }),\n shareReplay(1),\n )\n\n return { paginationInfo$, getPaginationInfo: () => currentValue.value }\n}\n","import { generate } from \"@prose-reader/cfi\"\nimport type { Manifest } from \"@prose-reader/shared\"\nimport type { PageEntry } from \"../spine/Pages\"\nimport { isHtmlRange } from \"../utils/dom\"\n\nexport const generateRootCfi = (item: Manifest[\"spineItems\"][number]) => {\n return generate({\n spineIndex: item.index,\n spineId: item.id,\n })\n}\n\nconst generateCfi = ({\n nodeOrRange,\n offset,\n item,\n}: {\n nodeOrRange: Node | Range\n offset?: number\n item: Manifest[\"spineItems\"][number]\n}) => {\n const nodeOrRangeOwnerDocument =\n \"ownerDocument\" in nodeOrRange\n ? nodeOrRange.ownerDocument\n : nodeOrRange.startContainer.ownerDocument\n\n if (\n !nodeOrRangeOwnerDocument ||\n !nodeOrRangeOwnerDocument?.documentElement ||\n nodeOrRange === nodeOrRangeOwnerDocument\n )\n return generateRootCfi(item)\n\n if (isHtmlRange(nodeOrRange)) {\n return generate({\n start: {\n node: nodeOrRange.startContainer,\n offset: nodeOrRange.startOffset,\n spineIndex: item.index,\n spineId: item.id,\n },\n end: {\n node: nodeOrRange.endContainer,\n offset: nodeOrRange.endOffset,\n spineIndex: item.index,\n spineId: item.id,\n },\n })\n }\n\n return generate({\n node: nodeOrRange,\n offset,\n spineIndex: item.index,\n spineId: item.id,\n })\n}\n\n/**\n * Heavy cfi hookup. Use it to have a refined, precise cfi anchor. It requires the content to be loaded otherwise\n * it will return a root cfi.\n *\n * @todo optimize\n */\nexport const generateCfiForSpineItemPage = ({\n spineItem,\n pageNode,\n}: {\n spineItem: Manifest[\"spineItems\"][number]\n pageNode: NonNullable<PageEntry[\"firstVisibleNode\"]>\n}) => {\n const cfiString = generateCfi({\n nodeOrRange: pageNode.node,\n offset: pageNode.offset,\n item: spineItem,\n })\n\n return cfiString.trim()\n}\n\nexport const generateCfiFromRange = (\n range: Range,\n item: Manifest[`spineItems`][number],\n) => {\n return generateCfi({\n nodeOrRange: range,\n item,\n })\n}\n\nexport const getItemAnchor = (item: Manifest[\"spineItems\"][number]) =>\n item.index.toString()\n","import {\n type CfiPart,\n isIndirectionOnly,\n isParsedCfiRange,\n type ParsedCfi,\n parse,\n} from \"@prose-reader/cfi\"\n\nexport type ProseParsedCfi = {\n isCfiRange: boolean\n itemIndex: number\n}\n\nconst hasIndirectionMarker = (part: CfiPart[]) => {\n return part[0]?.index === 6 && part.length > 1\n}\n\n/**\n * Root CFI are prose specific CFI that start with /0.\n * They are used when the item is not loaded and we have no other information\n * for the CFI available but still want to generate a CFI. This is the equivalent\n * of a fake CFI.\n */\nexport const isRootCfi = (cfi: string) => {\n const parsed = parse(cfi)\n\n return isIndirectionOnly(parsed)\n}\n\nconst extractIndirectionPart = (parsedCfi: ParsedCfi) => {\n return Array.isArray(parsedCfi)\n ? parsedCfi[0] && hasIndirectionMarker(parsedCfi[0])\n ? parsedCfi[0]\n : undefined\n : parsedCfi.parent[0] && hasIndirectionMarker(parsedCfi.parent[0])\n ? parsedCfi.parent[0]\n : undefined\n}\n\nexport const parseCfi = (cfi: string): ProseParsedCfi & { offset: number } => {\n const parsedCfi = parse(cfi)\n const indirectionPart = extractIndirectionPart(parsedCfi)\n const itemIndexPart = (indirectionPart ?? [])[1]\n const parsedSpineItemIndex = itemIndexPart?.index ?? 2\n const spineItemIndex = parsedSpineItemIndex / 2 - 1\n const isCfiRange = isParsedCfiRange(parsedCfi)\n const offset = isCfiRange\n ? parsedCfi.end.at(-1)?.at(-1)?.offset\n : parsedCfi.at(-1)?.at(-1)?.offset\n\n return {\n isCfiRange,\n itemIndex: spineItemIndex,\n offset: offset ?? 0,\n }\n}\n","import { resolve } from \"@prose-reader/cfi\"\nimport { Report } from \"../report\"\nimport type { SpineItemsManager } from \"../spine/SpineItemsManager\"\nimport type { SpineItem } from \"../spineItem/SpineItem\"\nimport { parseCfi } from \"./parse\"\n\n/**\n * Returns the node and offset for the given cfi.\n *\n * A CFI can only resolve if the item is loaded.\n *\n * @important\n * This is up to you to resolve CFI at the right time. Trying to resolve a CFI to an invalid\n * document will raise a warning but not crash.\n */\nexport const resolveCfi = ({\n cfi,\n spineItemsManager,\n}: {\n cfi: string\n spineItemsManager: SpineItemsManager\n}): Omit<ReturnType<typeof parseCfi>, \"offset\"> & {\n offset?: number | undefined\n node: Node | null\n range?: Range | null\n spineItem?: SpineItem\n} => {\n const { itemIndex, ...restParsed } = parseCfi(cfi)\n\n const spineItem = spineItemsManager.get(itemIndex)\n\n if (!spineItem)\n return {\n ...restParsed,\n itemIndex,\n node: null,\n }\n\n const rendererElement = spineItem.renderer.getDocumentFrame()\n\n if (rendererElement instanceof HTMLIFrameElement) {\n const doc = rendererElement.contentWindow?.document\n\n if (doc) {\n try {\n const resolved = resolve(cfi, doc, {\n throwOnError: true,\n })\n\n return {\n ...restParsed,\n itemIndex,\n node: resolved.isRange\n ? (resolved.node?.startContainer ?? null)\n : (resolved.node ?? null),\n isCfiRange: resolved.isRange,\n range: resolved.isRange ? resolved.node : undefined,\n offset: Array.isArray(resolved.offset)\n ? resolved.offset.at(-1)\n : resolved.offset,\n spineItem,\n }\n } catch (e) {\n Report.warn(`Error resolving cfi: ${cfi}.`)\n Report.warn(e)\n\n return {\n ...restParsed,\n spineItem,\n itemIndex,\n node: null,\n }\n }\n }\n }\n\n return {\n ...restParsed,\n itemIndex,\n spineItem,\n node: null,\n }\n}\n","import {\n combineLatest,\n debounceTime,\n defaultIfEmpty,\n finalize,\n map,\n type Observable,\n of,\n shareReplay,\n startWith,\n switchScan,\n withLatestFrom,\n} from \"rxjs\"\nimport {\n generateRootCfi,\n type ProseParsedCfi,\n type resolveCfi,\n} from \"../../cfi\"\nimport type { Reader } from \"../../reader\"\nimport type { SpineItem } from \"../../spineItem/SpineItem\"\nimport { deferIdle, idle } from \"../../utils/rxjs\"\n\ntype CfiLocatableResource = {\n cfi: string\n}\n\nexport type LocatableResource = SpineItem | CfiLocatableResource\n\nexport type ConsolidatedResource = ReturnType<typeof resolveCfi> &\n ProseParsedCfi &\n CfiLocatableResource & {\n itemPageIndex?: number\n absolutePageIndex?: number\n startOffset?: number\n range?: Range | null\n }\n\nconst toCfiLocatableResource = (\n reader: Reader,\n resource: LocatableResource | CfiLocatableResource,\n): ConsolidatedResource => {\n if (\"cfi\" in resource) {\n const { itemIndex, ...restParsedCfi } = reader.cfi.parseCfi(resource.cfi)\n\n return {\n ...resource,\n ...restParsedCfi,\n itemIndex,\n node: null,\n }\n }\n\n const item = reader.spineItemsManager.get(resource)\n\n if (!item) {\n throw new Error(`Spine item not found`)\n }\n\n const cfi = generateRootCfi(item.item)\n\n const parsedCfi = reader.cfi.parseCfi(cfi)\n\n return {\n ...parsedCfi,\n cfi: generateRootCfi(item.item),\n itemIndex: item.index,\n node: null,\n }\n}\n\nexport const consolidate = (\n resource: ConsolidatedResource,\n reader: Reader,\n): Observable<ConsolidatedResource> => {\n let itemPageIndex = resource?.itemPageIndex\n const { itemIndex, ...restParsedCfi } = reader.cfi.parseCfi(resource.cfi)\n const spineItem = reader.spineItemsManager.get(itemIndex)\n\n if (!spineItem) return of({ ...resource, itemIndex, ...restParsedCfi })\n\n return idle().pipe(\n withLatestFrom(spineItem.isReady$),\n map(([, isSpineItemReady]) => {\n const {\n node = null,\n offset: startOffset,\n range,\n } = isSpineItemReady ? reader.cfi.resolveCfi({ cfi: resource.cfi }) : {}\n\n const reflowableItemWithFoundNode =\n spineItem.renditionLayout !== `pre-paginated` && node\n\n if (reflowableItemWithFoundNode) {\n itemPageIndex =\n reader.spine.locator.spineItemLocator.getSpineItemPageIndexFromNode(\n node,\n startOffset ?? 0,\n spineItem,\n ) ?? itemPageIndex\n }\n\n let absolutePageIndex = resource?.absolutePageIndex\n\n /**\n * No itemPageIndex resolved from cfi.\n * We fallback to 0.\n */\n if (itemPageIndex === undefined) {\n itemPageIndex = 0\n }\n\n absolutePageIndex =\n reader.spine.locator._getAbsolutePageIndexFromPageIndex({\n pageIndex: itemPageIndex,\n spineItemOrId: spineItem,\n }) ?? resource?.absolutePageIndex\n\n return {\n ...resource,\n ...restParsedCfi,\n range,\n itemIndex,\n node,\n startOffset,\n absolutePageIndex,\n itemPageIndex,\n }\n }),\n )\n}\n\ntype Options = {\n /**\n * does not load document if shallow\n */\n mode?: \"shallow\" | \"load\"\n}\n\n/**\n * @todo optimize and share as much as possible when several same items are retrieved\n */\nexport class ResourcesLocator {\n constructor(private reader: Reader) {}\n\n private locatorsByKey = new Map<\n string,\n {\n observerCount: number\n consolidate$: Observable<{\n resource: LocatableResource\n meta: ConsolidatedResource\n }>\n }\n >()\n\n private deregisterMemoizedStream = (key: string) => {\n const value = this.locatorsByKey.get(key)\n\n if (!value) return\n\n value.observerCount--\n\n if (value.observerCount === 0) {\n this.locatorsByKey.delete(key)\n }\n }\n\n locate = <T extends LocatableResource>(\n resource: T,\n options: Options,\n ): Observable<{ resource: T; meta: ConsolidatedResource }> => {\n const initialConsolidatedValue = {\n resource,\n meta: toCfiLocatableResource(this.reader, resource),\n }\n\n return deferIdle(() => {\n /**\n * We only force open reflowable spine items.\n * This is because page index and absolute pages can be retrieved on\n * a pre-paginated content without having to load it.\n */\n\n const item = this.reader.spineItemsManager.get(\n initialConsolidatedValue.meta.itemIndex ?? 0,\n )\n const isReflowable = item?.renditionLayout === `reflowable`\n\n const release =\n options.mode === \"shallow\" || !isReflowable || !item\n ? () => {}\n : this.reader.spine.spineItemsLoader.forceOpen([item.index])\n\n const key = \"cfi\" in resource ? resource.cfi : undefined\n const memoizedConsolidate$ = key ? this.locatorsByKey.get(key) : undefined\n\n const withRelease = (\n stream: Observable<{ resource: T; meta: ConsolidatedResource }>,\n ) => {\n return stream.pipe(\n finalize(() => {\n if (key) {\n this.deregisterMemoizedStream(key)\n }\n\n /**\n * Make sure we wait a bit so if the user re-locate right after\n * we don't have a flicker of unload/load. It helps stabilize\n * resubscribing.\n */\n setTimeout(() => {\n release()\n }, 1000)\n }),\n )\n }\n\n if (key && memoizedConsolidate$) {\n memoizedConsolidate$.observerCount++\n\n return withRelease(\n memoizedConsolidate$.consolidate$.pipe(\n map(({ resource, meta }) => ({\n resource: resource as T,\n meta: meta as ConsolidatedResource,\n })),\n ),\n )\n }\n\n const consolidate$ = this.reader.spine.layout$.pipe(\n debounceTime(10),\n startWith(initialConsolidatedValue),\n switchScan((acc) => {\n return consolidate(acc.meta, this.reader).pipe(\n map((consolidatedResource) => ({\n ...acc,\n meta: consolidatedResource,\n })),\n )\n }, initialConsolidatedValue),\n shareReplay({ refCount: true, bufferSize: 1 }),\n )\n\n if (key) {\n this.locatorsByKey.set(key, {\n observerCount: 1,\n consolidate$,\n })\n }\n\n return withRelease(consolidate$)\n })\n }\n\n locateResource<T extends LocatableResource>(\n resource: T,\n options?: Options,\n ): Observable<{ resource: T; meta: ConsolidatedResource }>\n locateResource<T extends LocatableResource>(\n resource: T[],\n options?: Options,\n ): Observable<{ resource: T; meta: ConsolidatedResource }[]>\n locateResource<T extends LocatableResource>(\n resource: T | T[],\n options?: Options,\n ):\n | Observable<{ resource: T; meta: ConsolidatedResource }>\n | Observable<{ resource: T; meta: ConsolidatedResource }[]> {\n if (Array.isArray(resource)) {\n return deferIdle(() =>\n combineLatest(\n resource.map((item) => this.locate(item, options ?? {})),\n ).pipe(defaultIfEmpty([])),\n )\n }\n\n return this.locate(resource, options ?? {})\n }\n}\n","import { takeUntil } from \"rxjs\"\nimport type { LayoutEnhancerOutput } from \"../layout/layoutEnhancer\"\nimport type { EnhancerOutput, RootEnhancer } from \"../types/enhancer\"\nimport { trackPaginationInfo } from \"./pagination\"\nimport { ResourcesLocator } from \"./ResourcesLocator\"\nimport type { PaginationEnhancerAPI } from \"./types\"\n\nexport type { EnhancerPaginationInto, PaginationEnhancerAPI } from \"./types\"\n\nexport const paginationEnhancer =\n <\n InheritOptions,\n InheritOutput extends EnhancerOutput<RootEnhancer> & LayoutEnhancerOutput,\n PaginationOutput extends PaginationEnhancerAPI<InheritOutput>,\n >(\n next: (options: InheritOptions) => InheritOutput,\n ) =>\n (options: InheritOptions): PaginationOutput => {\n const reader = next(options)\n\n const { paginationInfo$, getPaginationInfo } = trackPaginationInfo(reader)\n\n paginationInfo$.pipe(takeUntil(reader.$.destroy$)).subscribe()\n\n const resourcesLocator = new ResourcesLocator(reader)\n\n return {\n ...reader,\n locateResource: resourcesLocator.locateResource.bind(resourcesLocator),\n pagination: {\n ...reader.pagination,\n get state() {\n return getPaginationInfo()\n },\n get state$() {\n return paginationInfo$\n },\n },\n } as unknown as PaginationOutput\n }\n","const createDatabase = (db: globalThis.IDBDatabase) => {\n const put = (key: string, data: Blob) => {\n return new Promise<void>((resolve, reject) => {\n const transaction = db.transaction([`store`], `readwrite`)\n\n transaction.onerror = (event) => {\n reject(event)\n }\n\n transaction.oncomplete = () => {\n resolve()\n }\n\n const objectStore = transaction.objectStore(`store`)\n const listener = objectStore.put(data, key)\n\n listener.onsuccess = () => {\n resolve()\n }\n\n listener.onerror = (event) => {\n reject(event)\n }\n })\n }\n\n const get = (key: string) => {\n return new Promise<Blob | null>((resolve, reject) => {\n const transaction = db.transaction([`store`], `readwrite`)\n const objectStore = transaction.objectStore(`store`)\n const request = objectStore.get(key)\n\n request.onsuccess = () => {\n let value = request.result\n if (value === undefined) {\n value = null\n }\n resolve(value)\n }\n\n transaction.onerror = () => {\n reject(request.error)\n }\n })\n }\n\n const remove = (key: globalThis.IDBValidKey) => {\n return new Promise<void>((resolve, reject) => {\n const transaction = db.transaction([`store`], `readwrite`)\n\n const objectStore = transaction.objectStore(`store`)\n const request = objectStore.delete(key)\n\n transaction.onerror = () => {\n reject(request.error)\n }\n\n transaction.oncomplete = () => {\n resolve()\n }\n\n // The request will be also be aborted if we've exceeded our storage\n // space.\n transaction.onabort = () => {\n const err = request.error ? request.error : request.transaction?.error\n reject(err)\n }\n })\n }\n\n const keys = () => {\n return new Promise<globalThis.IDBValidKey[]>((resolve, reject) => {\n const transaction = db.transaction([`store`], `readonly`)\n\n transaction.onerror = (event) => {\n reject(event)\n }\n\n // transaction.oncomplete = function () {\n // resolve()\n // };\n\n const objectStore = transaction.objectStore(`store`)\n const request = objectStore.openKeyCursor()\n const keys: globalThis.IDBValidKey[] = []\n\n request.onsuccess = () => {\n const cursor = request.result\n\n if (!cursor) {\n resolve(keys)\n return\n }\n\n keys.push(cursor.key)\n cursor.continue()\n }\n\n request.onerror = () => {\n reject(request.error)\n }\n })\n }\n\n return {\n put,\n keys,\n get,\n remove,\n }\n}\n\nexport const openDatabase = async (name: string) => {\n return new Promise<ReturnType<typeof createDatabase>>((resolve, reject) => {\n const request = window.indexedDB.open(name)\n\n request.onerror = (event) => {\n reject(event)\n }\n\n request.onsuccess = () => {\n resolve(createDatabase(request.result))\n }\n\n request.onupgradeneeded = () => {\n request.result.createObjectStore(`store`)\n }\n })\n}\n","/**\n * @todo web worker\n */\nimport { EMPTY, forkJoin, from, merge, Subject } from \"rxjs\"\nimport {\n catchError,\n map,\n mergeMap,\n switchMap,\n takeUntil,\n tap,\n} from \"rxjs/operators\"\nimport type { Manifest } from \"../..\"\nimport type { Context } from \"../../context/Context\"\nimport { Report } from \"../../report\"\nimport { openDatabase } from \"./indexedDB\"\n\nexport const createResourcesManager = (context: Context) => {\n let uniqueID = Date.now().toString()\n const cache$ = new Subject<{\n id: number | Pick<Manifest[`spineItems`][number], `id`>\n data: Response\n }>()\n\n const retrieveItem = (\n itemIndexOrId: number | string | Pick<Manifest[`spineItems`][number], `id`>,\n ) => {\n if (\n typeof itemIndexOrId === \"string\" ||\n typeof itemIndexOrId === \"object\"\n ) {\n const id =\n typeof itemIndexOrId === \"object\" ? itemIndexOrId.id : itemIndexOrId\n return context.manifest?.spineItems.find((entry) => entry.id === id)\n }\n\n return context.manifest?.spineItems[itemIndexOrId]\n }\n\n const get = async (\n itemIndexOrId: number | Pick<Manifest[`spineItems`][number], `id`>,\n fetchResource?: (item: Manifest[`spineItems`][number]) => Promise<Response>,\n ) => {\n const item = retrieveItem(itemIndexOrId)\n\n if (!item) return new Response(`Item not found`, { status: 404 })\n\n const db = await openDatabase(`prose-reader`)\n\n const cacheData = await db.get(`${uniqueID}_${item.id}`)\n\n if (cacheData) {\n return new Response(cacheData, { status: 200 })\n }\n\n const data =\n (fetchResource && (await fetchResource(item))) || (await fetch(item.href))\n\n cache(item, data.clone())\n\n return data\n }\n\n const cache = (\n itemIndexOrId: number | Pick<Manifest[`spineItems`][number], `id`>,\n data: Response,\n ) => {\n cache$.next({ id: itemIndexOrId, data })\n }\n\n cache$\n .asObservable()\n .pipe(\n mergeMap(({ id, data }) => {\n const item = retrieveItem(id)\n\n if (!item) return EMPTY\n\n return from(\n forkJoin([openDatabase(`prose-reader`), from(data.blob())]),\n ).pipe(\n switchMap(([db, blob]) => {\n return from(db.put(`${uniqueID}_${item.id}`, blob))\n }),\n catchError((error) => {\n Report.error(error)\n\n return EMPTY\n }),\n )\n }),\n takeUntil(context.destroy$),\n )\n .subscribe()\n\n const onLoad$ = context.manifest$.pipe(\n tap(() => {\n uniqueID = Date.now().toString()\n }),\n )\n\n /**\n * Cleanup old cache on startup if needed\n * @todo\n * do on first time and only then on subsequent load\n */\n merge(onLoad$)\n .pipe(\n switchMap(() => {\n Report.debug(`Cleanup up old cache...`)\n\n return from(openDatabase(`prose-reader`)).pipe(\n switchMap((db) =>\n from(db.keys()).pipe(\n map((keys) =>\n keys.filter((key) => !key.toString().startsWith(uniqueID)),\n ),\n switchMap((keysToRemove) => {\n const promises = keysToRemove.map((key) => db.remove(key))\n\n return from(Promise.all(promises))\n }),\n ),\n ),\n catchError((error) => {\n Report.error(error)\n\n return EMPTY\n }),\n )\n }),\n takeUntil(context.destroy$),\n )\n .subscribe()\n\n const destroy = () => {\n cache$.complete()\n }\n\n return {\n get,\n destroy,\n }\n}\n","import type { EnhancerOutput, RootEnhancer } from \"../types/enhancer\"\nimport { createResourcesManager } from \"./resourcesManager\"\n\nexport const resourcesEnhancer =\n <InheritOptions, InheritOutput extends EnhancerOutput<RootEnhancer>>(\n next: (options: InheritOptions) => InheritOutput,\n ) =>\n (options: InheritOptions): InheritOutput => {\n const reader = next(options)\n const resourceManager = createResourcesManager(reader.context)\n\n /**\n * We will serve resources from cache if they exist otherwise fetch it normally.\n * The resource manager use the provided user option to fetch resource if it exists\n */\n // const load: typeof reader.load = (manifest, loadOptions) => {\n // reader.load(manifest, {\n // ...loadOptions,\n // })\n // }\n\n // reader.registerHook(`item.onGetResource`, (fetcher) => async (item) => {\n // return resourceManager.get(item, fetcher)\n // })\n\n const destroy = () => {\n resourceManager.destroy()\n reader.destroy()\n }\n\n return {\n ...reader,\n // $: {\n // ...reader.$,\n // errors$: merge(reader.$.errors$, errorsSubject$.asObservable())\n // },\n destroy,\n // load,\n }\n }\n","import { Report } from \"../../report\"\nimport type { SpineItem } from \"../../spineItem/SpineItem\"\n\nexport const getRangeFromSelection = (\n anchor: { node: Node; offset?: number },\n focus: { node: Node; offset?: number },\n) => {\n const range = anchor.node.ownerDocument?.createRange()\n const comparison = anchor.node.compareDocumentPosition(focus.node)\n\n if (!range) return undefined\n\n try {\n // If focus comes before anchor in the document\n if (comparison & Node.DOCUMENT_POSITION_PRECEDING) {\n range.setStart(focus.node, focus.offset || 0)\n range.setEnd(anchor.node, anchor.offset || 0)\n // If focus comes after anchor in the document\n } else if (comparison & Node.DOCUMENT_POSITION_FOLLOWING) {\n range.setStart(anchor.node, anchor.offset || 0)\n range.setEnd(focus.node, focus.offset || 0)\n }\n // If they're the same node\n else {\n const startOffset = Math.min(anchor.offset || 0, focus.offset || 0)\n const endOffset = Math.max(anchor.offset || 0, focus.offset || 0)\n range.setStart(anchor.node, startOffset)\n range.setEnd(anchor.node, endOffset)\n }\n } catch (e) {\n Report.warn(\"Failed to create range from selection\", e, {\n anchor,\n focus,\n })\n }\n\n return range\n}\n\nexport const createOrderedRangeFromSelection = ({\n selection,\n spineItem,\n}: {\n selection: {\n anchorNode?: Node | null\n anchorOffset?: number\n focusNode?: Node | null\n focusOffset?: number\n }\n spineItem: SpineItem\n}) => {\n const { anchorNode, anchorOffset, focusNode, focusOffset } = selection\n\n if (!anchorNode || !focusNode) {\n return undefined\n }\n\n try {\n return getRangeFromSelection(\n { node: anchorNode, offset: anchorOffset },\n { node: focusNode, offset: focusOffset },\n )\n } catch (e) {\n Report.warn(\"Failed to create range from selection\", e, {\n selection,\n spineItem,\n })\n\n return undefined\n }\n}\n","import {\n delay,\n endWith,\n filter,\n first,\n merge,\n NEVER,\n type Observable,\n of,\n switchMap,\n takeUntil,\n} from \"rxjs\"\nimport { fromEvent, map } from \"rxjs\"\nimport { DestroyableClass } from \"../../utils/DestroyableClass\"\nimport { isDefined } from \"../../utils/isDefined\"\nimport { observeMutation } from \"../../utils/rxjs\"\n\nexport class FrameSelectionTracker extends DestroyableClass {\n selectionChange$: Observable<Selection | null>\n selectionOver$: Observable<readonly [Event, Selection]>\n\n constructor(frame: HTMLIFrameElement) {\n super()\n\n const frameDoc = frame.contentDocument || frame.contentWindow?.document\n\n if (!frameDoc) {\n this.selectionChange$ = NEVER\n this.selectionOver$ = NEVER\n } else {\n /**\n * We observe mutation on the doc to intercept potential\n * change in selection that would not be triggered by API.\n * Such as iframe nodes being recreated on layout.\n */\n const frameDocMutation$ = observeMutation(frameDoc.body, {\n childList: true,\n subtree: true,\n }).pipe(\n filter(\n (mutations) =>\n !!mutations.find((mutation) => {\n return (\n mutation.type === \"childList\" && mutation.removedNodes.length\n )\n }),\n ),\n )\n\n /**\n * We observe direct destruction of the iframe as well to remove current\n * selection if needed.\n */\n const iframeDestroyed$ = !frame.parentElement\n ? of(null)\n : observeMutation(frame.parentElement, {\n childList: true,\n }).pipe(\n filter(\n (mutation) =>\n !!mutation.find((mutation) =>\n Array.from(mutation.removedNodes).includes(frame),\n ),\n ),\n )\n\n this.selectionChange$ = merge(\n fromEvent(frameDoc, \"selectionchange\"),\n frameDocMutation$,\n ).pipe(\n map(() => frameDoc.getSelection()),\n takeUntil(merge(iframeDestroyed$, this.destroy$)),\n endWith(null),\n )\n\n this.selectionOver$ = fromEvent(frameDoc, \"pointerdown\").pipe(\n switchMap(() =>\n merge(\n fromEvent(frameDoc, \"pointerup\"),\n fromEvent(frameDoc, \"pointercancel\"),\n fromEvent(frameDoc, \"contextmenu\"),\n ).pipe(\n first(),\n /**\n * The selection is still valid during the event even if it will\n * be discarded. The timeout make sure to detect this edge case.\n */\n delay(0),\n map((event) => {\n const selection = frameDoc.getSelection()\n\n return selection && !selection.isCollapsed\n ? ([event, selection] as const)\n : undefined\n }),\n filter(isDefined),\n ),\n ),\n takeUntil(merge(iframeDestroyed$, this.destroy$)),\n )\n }\n }\n}\n","import {\n distinctUntilChanged,\n endWith,\n finalize,\n map,\n merge,\n NEVER,\n switchMap,\n takeUntil,\n} from \"rxjs\"\nimport type { SpineItem } from \"../../spineItem/SpineItem\"\nimport { FrameSelectionTracker } from \"./FrameSelectionTracker\"\n\nexport const trackSpineItemSelection = (spineItem: SpineItem) =>\n spineItem.watch(\"isLoaded\").pipe(\n switchMap(() => {\n const frame = spineItem.renderer.getDocumentFrame()\n const frameDoc = frame?.contentDocument || frame?.contentWindow?.document\n\n if (!frame || !frameDoc) return NEVER\n\n const selectionTracker = new FrameSelectionTracker(frame)\n\n return merge(\n selectionTracker.selectionChange$.pipe(\n map((selection) => {\n if (selection?.toString()) {\n return {\n type: \"change\" as const,\n selection,\n }\n }\n return undefined\n }),\n ),\n selectionTracker.selectionOver$.pipe(\n map(([event, selection]) => {\n return {\n type: \"over\" as const,\n event,\n selection,\n }\n }),\n ),\n ).pipe(\n takeUntil(spineItem.unloaded$),\n endWith(undefined),\n finalize(() => {\n selectionTracker.destroy()\n }),\n )\n }),\n distinctUntilChanged(),\n )\n","import {\n distinctUntilChanged,\n filter,\n fromEvent,\n map,\n merge,\n type Observable,\n share,\n shareReplay,\n startWith,\n switchMap,\n takeUntil,\n tap,\n withLatestFrom,\n} from \"rxjs\"\nimport type { SpineItem } from \"../..\"\nimport { isDefined } from \"../../utils/isDefined\"\nimport type { EnhancerOutput, RootEnhancer } from \"../types/enhancer\"\nimport { createOrderedRangeFromSelection } from \"./selection\"\nimport { trackSpineItemSelection } from \"./trackSpineItemSelection\"\n\ntype SelectionChange = {\n itemIndex: number\n type: \"change\"\n selection: Selection\n}\n\ntype SelectionOver = {\n itemIndex: number\n type: \"over\"\n event: Event\n selection: Selection\n}\n\ntype SelectionValue = SelectionChange | SelectionOver | undefined\n\nexport const selectionEnhancer =\n <InheritOptions, InheritOutput extends EnhancerOutput<RootEnhancer>>(\n next: (options: InheritOptions) => InheritOutput,\n ) =>\n (\n options: InheritOptions,\n ): InheritOutput & {\n selection: {\n selection$: Observable<SelectionValue>\n selectionStart$: Observable<boolean>\n selectionEnd$: Observable<void>\n selectionOver$: Observable<SelectionOver>\n lastSelectionOnPointerdown$: Observable<SelectionValue>\n getSelection: () => SelectionValue\n createOrderedRangeFromSelection: (params: {\n selection: {\n anchorNode?: Node | null\n anchorOffset?: number\n focusNode?: Node | null\n focusOffset?: number\n }\n spineItem: SpineItem\n }) => Range | undefined\n }\n } => {\n const reader = next(options)\n let lasSelection: SelectionValue\n\n const trackedSelection$ = reader.spineItemsManager.items$.pipe(\n switchMap((spineItems) => {\n const instances = spineItems.map((spineItem) => {\n const itemIndex =\n reader.spineItemsManager.getSpineItemIndex(spineItem) ?? 0\n\n return trackSpineItemSelection(spineItem).pipe(\n map((entry) => {\n if (!entry) return undefined\n\n return {\n ...entry,\n itemIndex,\n }\n }),\n )\n })\n\n return merge(...instances)\n }),\n startWith(undefined),\n distinctUntilChanged(),\n tap((value) => {\n lasSelection = value\n }),\n shareReplay({ refCount: true, bufferSize: 1 }),\n )\n\n const selection$ = trackedSelection$\n\n const selectionStart$ = trackedSelection$.pipe(\n map((selection) => !!selection),\n distinctUntilChanged(),\n filter((isSelecting) => isSelecting),\n share(),\n )\n\n const selectionEnd$ = selectionStart$.pipe(\n switchMap(() => selection$),\n distinctUntilChanged(),\n filter((selection) => !selection),\n share(),\n )\n\n const selectionOver$ = trackedSelection$.pipe(\n filter((selection) => selection?.type === \"over\"),\n share(),\n )\n\n const lastSelectionOnPointerdown$ = reader.context\n .watch(`rootElement`)\n .pipe(\n filter(isDefined),\n switchMap((container) => fromEvent(container, \"pointerdown\")),\n withLatestFrom(selection$),\n map(([, selection]) => selection),\n startWith(undefined),\n shareReplay({ refCount: true, bufferSize: 1 }),\n )\n\n merge(selection$, lastSelectionOnPointerdown$)\n .pipe(takeUntil(reader.$.destroy$))\n .subscribe()\n\n return {\n ...reader,\n selection: {\n selection$,\n selectionStart$,\n selectionEnd$,\n selectionOver$,\n lastSelectionOnPointerdown$,\n getSelection: () => lasSelection,\n createOrderedRangeFromSelection,\n },\n }\n }\n","import { BehaviorSubject, type Observable } from \"rxjs\"\nimport { takeUntil, tap } from \"rxjs/operators\"\nimport { upsertCSSToFrame } from \"../utils/frames\"\nimport type { EnhancerOutput, RootEnhancer } from \"./types/enhancer\"\n\nconst defaultThemes = [\n {\n name: `bright` as const,\n backgroundColor: `white`,\n },\n {\n name: `sepia` as const,\n backgroundColor: `#eaddc7`,\n foregroundColor: `black`,\n },\n {\n name: `night` as const,\n backgroundColor: `#191717`,\n foregroundColor: `#f1ebeb`,\n },\n]\n\nexport type Theme = (typeof defaultThemes)[number][`name`] | `publisher`\n\nexport type ThemeEnhancer = <\n InheritOptions,\n InheritOutput extends EnhancerOutput<RootEnhancer>,\n>(\n next: (options: InheritOptions) => InheritOutput,\n) => (\n options: InheritOptions & {\n theme?: Theme\n },\n) => InheritOutput & {\n theme: {\n set: (theme: Theme) => void\n get: () => Theme\n $: {\n theme$: Observable<Theme>\n }\n }\n}\n\nexport const themeEnhancer: ThemeEnhancer = (next) => (options) => {\n const reader = next(options)\n const currentThemeSubject$ = new BehaviorSubject<Theme>(\n options.theme ?? `bright`,\n )\n\n const getStyle = () => {\n const foundTheme = defaultThemes.find(\n (entry) => entry.name === currentThemeSubject$.value,\n )\n\n return `\n body {\n ${foundTheme !== undefined ? `background-color: ${foundTheme.backgroundColor} !important;` : ``}\n }\n ${\n foundTheme?.foregroundColor\n ? `\n body * {\n ${\n /*\n Ideally, we would like to use !important but it could break publisher specific\n cases\n */ ``\n }\n color: ${foundTheme.foregroundColor};\n }\n `\n : ``\n }\n `\n }\n\n const applyChangeToSpineItemElement = ({\n container,\n }: {\n container: HTMLElement\n }) => {\n const foundTheme = defaultThemes.find(\n (entry) => entry.name === currentThemeSubject$.value,\n )\n if (foundTheme) {\n container.style.setProperty(\n `background-color`,\n foundTheme.backgroundColor,\n )\n }\n\n return () => {\n // __\n }\n }\n\n const applyChangeToSpineItem = () => {\n reader.spineItemsManager.items.forEach((item) => {\n const frame = item.renderer.getDocumentFrame()\n\n if (frame) {\n upsertCSSToFrame(frame, `prose-reader-theme`, getStyle())\n }\n\n applyChangeToSpineItemElement({ container: item.element })\n })\n }\n\n /**\n * Make sure to apply theme on item load\n */\n reader.hookManager.register(`item.onDocumentLoad`, ({ itemId }) => {\n const item = reader.spineItemsManager.get(itemId)\n\n /**\n * We don't apply the theme on pre-paginated items\n * because the theme is applied on the page level.\n *\n * A good example is the iframe generated by pdf for annotations.\n * It would mess up with the rendering.\n */\n if (item?.renditionLayout !== \"pre-paginated\") {\n const frame = item?.renderer.getDocumentFrame()\n\n if (frame) {\n upsertCSSToFrame(frame, `prose-reader-theme`, getStyle())\n }\n }\n })\n\n /**\n * Make sure to apply theme on item container (fixed layout)\n * & loading element\n */\n reader.spineItemsManager.items$\n .pipe(\n tap((items) =>\n items.map(({ element }) =>\n applyChangeToSpineItemElement({ container: element }),\n ),\n ),\n takeUntil(reader.$.destroy$),\n )\n .subscribe()\n\n currentThemeSubject$\n .pipe(\n tap(() => {\n applyChangeToSpineItem()\n }),\n takeUntil(reader.$.destroy$),\n )\n .subscribe()\n\n return {\n ...reader,\n theme: {\n set: (theme) => {\n if (theme !== currentThemeSubject$.value) {\n currentThemeSubject$.next(theme)\n }\n },\n get: () => currentThemeSubject$.value,\n $: {\n theme$: currentThemeSubject$.asObservable(),\n },\n },\n }\n}\n","import { injectCSS, isHtmlElement } from \"../utils/dom\"\nimport type { EnhancerOutput, RootEnhancer } from \"./types/enhancer\"\n\nexport const utilsEnhancer =\n <InheritOptions, InheritOutput extends EnhancerOutput<RootEnhancer>>(\n next: (options: InheritOptions) => InheritOutput,\n ) =>\n (\n options: InheritOptions,\n ): InheritOutput & {\n utils: {\n isOrIsWithinValidLink: (target: Event[`target`]) => boolean\n injectScopedCSS: (\n doc: Document,\n scope: string,\n styleTemplate: string,\n ) => () => void\n }\n } => {\n const reader = next(options)\n\n const isOrIsWithinValidLink = (target: Event[`target`]) => {\n if (isHtmlElement(target)) {\n const link = target.nodeName === `a` ? target : target.closest(`a`)\n if (link?.getAttribute(`href`)) {\n return true\n }\n }\n\n return false\n }\n\n const injectScopedCSS = (\n doc: Document,\n scope: string,\n styleTemplate: string,\n ) => {\n // biome-ignore lint/suspicious/noTemplateCurlyInString: Expected\n const styleWithIdReplaced = styleTemplate.replace(\"${id}\", reader.id)\n\n return injectCSS(doc, `${scope}-${reader.id}`, styleWithIdReplaced)\n }\n\n return {\n ...reader,\n utils: {\n isOrIsWithinValidLink,\n injectScopedCSS,\n },\n }\n }\n","import type {\n EnhancerOptions,\n EnhancerOutput,\n RootEnhancer,\n} from \"./types/enhancer\"\n\n/**\n * Ideally we want to target all webkit browser but afaik there are no reliable way to do it.\n * We will fix at least safari\n */\nconst IS_SAFARI =\n navigator.userAgent.indexOf(``) > -1 &&\n navigator.userAgent.indexOf(`Chrome`) <= -1\n\n/**\n * All fixes relative to webkit\n */\nexport const webkitEnhancer =\n <\n InheritOptions extends EnhancerOptions<RootEnhancer>,\n InheritOutput extends EnhancerOutput<RootEnhancer>,\n >(\n createReader: (options: InheritOptions) => InheritOutput,\n ) =>\n (options: InheritOptions): InheritOutput => {\n const reader = createReader(options)\n\n /**\n * These hooks are used to fix the flickering on safari that occurs when using transform\n * and more generally GPU transformation. I am not sure what is the impact on performance so\n * we only use them on needed engine (webkit).\n */\n if (IS_SAFARI) {\n // reader.hookManager.register(\n // \"navigator.onBeforeContainerCreated\",\n // ({ element }) => {\n // element.style.cssText = `\n // ${element.style.cssText}\n // -webkit-transform-style: preserve-3d;\n // `\n // },\n // )\n // reader.hookManager.register(\n // \"item.onBeforeContainerCreated\",\n // ({ element }) => {\n // element.style.cssText = `\n // ${element.style.cssText}\n // -webkit-transform-style: preserve-3d;\n // -webkit-backface-visibility: hidden;\n // `\n // },\n // )\n }\n\n return reader\n }\n","import type { Viewport } from \"../../viewport/Viewport\"\nimport type { ZoomPosition } from \"./types\"\n\n/**\n * Make sure to constraint position within viewport boundaries when zoomed.\n * This only works when zoomed in.\n */\nexport const constrainPositionWithinViewport = (\n position: ZoomPosition,\n scale: number,\n viewport: Viewport,\n) => {\n const { clientWidth, clientHeight } = viewport.value.element\n\n // Calculate the maximum allowed translation (always 0, top-left)\n // and minimum allowed translation (negative value representing the overflow)\n const bounds = {\n maxX: 0,\n minX: clientWidth * (1 - scale),\n maxY: 0,\n minY: clientHeight * (1 - scale),\n }\n\n return {\n x: Math.min(Math.max(position.x, bounds.minX), bounds.maxX),\n y: Math.min(Math.max(position.y, bounds.minY), bounds.maxY),\n }\n}\n","export const applyViewportTransformForControlledMode = (\n scale: number,\n position: { x: number; y: number },\n viewportElement: HTMLElement,\n) => {\n viewportElement.style.transformOrigin = `0 0`\n\n const translateTransform = `translate3d(${position.x}px, ${position.y}px, 0px)`\n const scaleTransform = `scale(${scale})`\n\n viewportElement.style.transform = `${translateTransform} ${scaleTransform}`\n}\n\nexport const derivePositionFromScaleForControlledMode = (\n currentScale: number,\n userScale: number,\n viewportElement: HTMLElement,\n currentPosition: { x: number; y: number },\n) => {\n const scaleFactor = userScale / currentScale\n\n // Use clientWidth/clientHeight to get original dimensions before transforms\n const originalWidth = viewportElement.clientWidth\n const originalHeight = viewportElement.clientHeight\n\n // Calculate the center of what the user is currently seeing\n // Use original dimensions, not transformed ones\n const visualCenterX = originalWidth / 2 - currentPosition.x\n const visualCenterY = originalHeight / 2 - currentPosition.y\n\n // Calculate new position to keep the visual center fixed during scaling\n const newPosition = {\n x: currentPosition.x + visualCenterX * (1 - scaleFactor),\n y: currentPosition.y + visualCenterY * (1 - scaleFactor),\n }\n\n return newPosition\n}\n","/// <reference types=\"vite/client\" />\nimport type { Manifest } from \"@prose-reader/shared\"\n\nexport type { Manifest }\n\nexport abstract class AbstractPosition {\n public readonly x: number\n public readonly y: number\n\n constructor(position: { x: number; y: number }) {\n this.x = position.x\n this.y = position.y\n }\n}\n","import {\n BehaviorSubject,\n combineLatest,\n distinctUntilChanged,\n filter,\n fromEvent,\n map,\n merge,\n NEVER,\n type Observable,\n of,\n Subject,\n share,\n shareReplay,\n skip,\n startWith,\n switchMap,\n takeUntil,\n tap,\n timer,\n withLatestFrom,\n} from \"rxjs\"\nimport { HTML_PREFIX_SCROLL_NAVIGATOR } from \"../../constants\"\nimport type { Context } from \"../../context/Context\"\nimport type { HookManager } from \"../../hooks/HookManager\"\nimport type { ReaderSettingsManager } from \"../../settings/ReaderSettingsManager\"\nimport type { Spine } from \"../../spine/Spine\"\nimport { type SpinePosition, UnboundSpinePosition } from \"../../spine/types\"\nimport { AbstractPosition } from \"../../types\"\nimport { isDefined } from \"../../utils/isDefined\"\nimport { ReactiveEntity } from \"../../utils/ReactiveEntity\"\nimport { observeResize, watchKeys } from \"../../utils/rxjs\"\nimport type { Viewport } from \"../../viewport/Viewport\"\n\nexport class ScrollPosition extends AbstractPosition {}\nexport class UnboundScrollPosition extends AbstractPosition {\n public readonly __symbol = Symbol(`UnboundScrollPosition`)\n}\n\nexport type ScrollNavigationViewportNavigationEntry = {\n position: UnboundSpinePosition | SpinePosition\n}\n\nexport class ScrollNavigationController extends ReactiveEntity<{\n element: HTMLElement | undefined\n}> {\n protected navigateSubject =\n new Subject<ScrollNavigationViewportNavigationEntry>()\n protected scrollingSubject = new BehaviorSubject(false)\n\n public isScrolling$ = this.scrollingSubject.asObservable()\n public isNavigating$: Observable<boolean>\n public userScroll$: Observable<Event>\n\n constructor(\n protected viewport: Viewport,\n protected settings: ReaderSettingsManager,\n protected hookManager: HookManager,\n protected spine: Spine,\n protected context: Context,\n ) {\n super({\n element: undefined,\n })\n\n const elementCreation$ = this.context.pipe(\n watchKeys([\"rootElement\"]),\n tap(({ rootElement }) => {\n if (!rootElement) return\n\n const element = document.createElement(`div`)\n element.setAttribute(`data-${HTML_PREFIX_SCROLL_NAVIGATOR}`, \"\")\n element.appendChild(this.viewport.value.element)\n rootElement.appendChild(element)\n\n this.update({ element })\n }),\n )\n\n const toggleElementDisplay$ = combineLatest([\n settings.watch([`computedPageTurnMode`]),\n this.watch(\"element\"),\n ]).pipe(\n tap(([{ computedPageTurnMode }, element]) => {\n if (!element) return\n\n if (computedPageTurnMode === `scrollable`) {\n element.style.display = \"block\"\n } else {\n element.style.display = \"contents\"\n }\n }),\n )\n\n const navigate$ = this.navigateSubject.pipe(tap(this.setViewportPosition))\n\n this.isNavigating$ = this.navigateSubject.pipe(\n startWith(false),\n switchMap(() => merge(of(true), of(false))),\n shareReplay(1),\n )\n\n // might be a bit overkill but we want to be sure of sure\n const isSpineScrolling$ = merge(\n spine.element$.pipe(\n filter(isDefined),\n switchMap((element) => observeResize(element)),\n ),\n spine.element$.pipe(\n filter(isDefined),\n switchMap((element) => fromEvent(element, \"scroll\")),\n ),\n spine.spineItemsObserver.itemResize$,\n ).pipe(\n switchMap(() =>\n timer(10).pipe(\n map(() => false),\n startWith(true),\n ),\n ),\n distinctUntilChanged(),\n startWith(false),\n )\n\n const scrollHappeningFromBrowser$ = combineLatest([\n isSpineScrolling$,\n this.isScrolling$,\n ]).pipe(\n map(\n ([spineScrolling, viewportScrolling]) =>\n spineScrolling || viewportScrolling,\n ),\n shareReplay(1),\n )\n\n this.userScroll$ = this.watch(\"element\").pipe(\n filter(isDefined),\n switchMap((element) =>\n settings.watch([\"computedPageTurnMode\"]).pipe(\n switchMap(({ computedPageTurnMode }) =>\n computedPageTurnMode === \"controlled\"\n ? NEVER\n : fromEvent(element, `scroll`).pipe(\n withLatestFrom(scrollHappeningFromBrowser$),\n filter(\n ([, shouldAvoidScrollEvent]) => !shouldAvoidScrollEvent,\n ),\n map(([event]) => event),\n ),\n ),\n ),\n ),\n share(),\n )\n\n merge(elementCreation$, toggleElementDisplay$, navigate$)\n .pipe(takeUntil(this.destroy$))\n .subscribe()\n }\n\n /**\n * Usually occurs due to navigation.\n *\n * @see https://stackoverflow.com/questions/22111256/translate3d-vs-translate-performance\n * for remark about flicker / fonts smoothing\n */\n protected setViewportPosition = ({\n position,\n }: ScrollNavigationViewportNavigationEntry) => {\n const element = this.value.element\n\n this.scrollingSubject.next(true)\n\n const scaledPosition = this.fromSpinePosition(position)\n\n element?.scrollTo({\n left: scaledPosition.x,\n top: scaledPosition.y,\n behavior: \"instant\",\n })\n\n timer(1)\n .pipe(\n tap(() => {\n this.scrollingSubject.next(false)\n }),\n takeUntil(merge(this.scrollingSubject.pipe(skip(1)), this.destroy$)),\n )\n .subscribe()\n\n this.hookManager.execute(\"onViewportOffsetAdjust\", undefined, {})\n }\n\n public update(\n value: Partial<{\n element: HTMLElement | undefined\n }>,\n ) {\n this.mergeCompare(value)\n }\n\n navigate(navigation: ScrollNavigationViewportNavigationEntry) {\n this.navigateSubject.next(navigation)\n }\n\n public fromScrollPosition(position: UnboundScrollPosition | ScrollPosition) {\n const scaleFactor = this.viewport.scaleFactor\n\n return new UnboundSpinePosition({\n x: position.x / scaleFactor,\n y: position.y / scaleFactor,\n })\n }\n\n public fromSpinePosition(position: UnboundSpinePosition | SpinePosition) {\n const scaleFactor = this.viewport.scaleFactor\n\n return new ScrollPosition({\n x: position.x * scaleFactor,\n y: position.y * scaleFactor,\n })\n }\n\n public get scrollPosition() {\n const element = this.value.element\n\n return new ScrollPosition({\n x: element?.scrollLeft ?? 0,\n y: element?.scrollTop ?? 0,\n })\n }\n}\n","import { HTML_PREFIX } from \"../../constants\"\nimport { UnboundScrollPosition } from \"../../navigation/controllers/ScrollNavigationController\"\nimport type { Reader } from \"../../reader\"\nimport { noopElement } from \"../../utils/dom\"\n\nexport const adjustScrollToKeepContentCentered = (\n scrollContainer: HTMLElement,\n fromScale: number,\n toScale: number,\n marginX: number,\n marginY: number,\n) => {\n const containerWidth = scrollContainer.clientWidth\n const containerHeight = scrollContainer.clientHeight\n\n // Current scroll position\n const currentScrollLeft = scrollContainer.scrollLeft\n const currentScrollTop = scrollContainer.scrollTop\n\n // Calculate what's currently in the center of the visible area, accounting for margins\n const visibleCenterX = currentScrollLeft + containerWidth / 2 - marginX\n const visibleCenterY = currentScrollTop + containerHeight / 2 - marginY\n\n // After scaling, calculate where we need to scroll to keep the same content centered\n const scaleFactor = toScale / fromScale\n const newVisibleCenterX = visibleCenterX * scaleFactor\n const newVisibleCenterY = visibleCenterY * scaleFactor\n\n // Calculate new scroll position to keep the center content visible, accounting for margins\n const scrollLeft = newVisibleCenterX - containerWidth / 2 + marginX\n const scrollTop = newVisibleCenterY - containerHeight / 2 + marginY\n\n return new UnboundScrollPosition({\n x: scrollLeft,\n y: scrollTop,\n })\n}\n\nexport const applyScaleToViewportForScroll = (\n scale: number,\n reader: Reader,\n) => {\n const viewport = reader.viewport\n const scrollNavigationController =\n reader.navigation.scrollNavigationController\n const viewportElement = viewport.value.element\n const scrollContainer = scrollNavigationController.value.element\n const scrollNavigationElement = scrollNavigationController.value.element\n\n const currentScale = Math.round(viewport.scaleFactor * 100) / 100\n\n // We assume the viewport is directly under the scroll container\n // therefore we can use offsetLeft/offsetTop to get the margin\n const marginX = viewportElement.offsetLeft\n const marginY = viewportElement.offsetTop\n\n const newCenterPositionAfterNewScaleProjection =\n adjustScrollToKeepContentCentered(\n scrollContainer ?? noopElement(),\n currentScale,\n scale,\n marginX,\n marginY,\n )\n\n const direction = scale < 1 ? \"down\" : \"up\"\n scrollNavigationElement?.setAttribute(\n `data-${HTML_PREFIX}-zooming-direction`,\n direction,\n )\n\n /**\n * When zooming out, we want to keep the content centered. Since we don't have a scrollbar we will cheat\n * with origin and force it centered.\n * When zooming in, we want to keep the content centered as well but we now have a scrollbar so we adjust it.\n * Keeping the origin centered would make it impossible to scroll the left content\n */\n if (scale < 1) {\n viewportElement.style.transformOrigin = `top`\n } else if (scale > 1) {\n /**\n * @important\n * Transform origin `center` would cut left part of the content because it would expand\n * beyond the container on both side (albeit right side would be scrollable).\n * transform origin `left` would cut right part of the content if the viewport has margin\n * (eg: 50% viewport fit)\n * Therefore we need to use an origin that start at the actual content eliminating margin.\n */\n viewportElement.style.transformOrigin = `${marginX}px ${marginY}px`\n }\n\n viewportElement.style.transform = `scale(${scale})`\n\n const spinePosition = scrollNavigationController.fromScrollPosition(\n newCenterPositionAfterNewScaleProjection,\n )\n\n reader.navigation.navigate({\n position: spinePosition,\n })\n}\n","import {\n EMPTY,\n merge,\n type ObservedValueOf,\n Subject,\n switchMap,\n takeUntil,\n tap,\n timer,\n} from \"rxjs\"\nimport { HTML_PREFIX } from \"../../constants\"\nimport type { Reader } from \"../../reader\"\nimport { ReactiveEntity } from \"../../utils/ReactiveEntity\"\nimport { constrainPositionWithinViewport } from \"./constraints\"\nimport {\n applyViewportTransformForControlledMode,\n derivePositionFromScaleForControlledMode,\n} from \"./controlled\"\nimport { applyScaleToViewportForScroll } from \"./scrollable\"\nimport type { ZoomPosition } from \"./types\"\n\nexport type ZoomControllerState = {\n isZooming: boolean\n currentScale: number\n /**\n * Represents the origin translate position before zoom is applied\n * and is based of an origin of 0,0.\n */\n currentPosition: ZoomPosition\n}\n\n/**\n * @important\n * Animation is not possible for scrolling mode because the animation\n * is based on transform origin and its impossible to have a correct\n * centered transform origin with the viewport in a scrollable container.\n * What we do is compute the \"wanted\" scroll position to make it look like\n * scale down/up appears centered.\n */\nconst ANIMATION_DURATION = 200\n\nexport class ZoomController extends ReactiveEntity<ZoomControllerState> {\n private enterSubject = new Subject<\n | undefined\n | {\n element?: HTMLImageElement\n scale?: number\n animate?: boolean\n }\n >()\n private exitSubject = new Subject<{ animate?: boolean } | undefined>()\n\n constructor(protected reader: Reader) {\n super({\n isZooming: false,\n currentScale: 1,\n currentPosition: { x: 0, y: 0 },\n })\n\n const enter$ = this.enterSubject.pipe(\n switchMap((options) => {\n const { scale = 1, animate = false } = options ?? {}\n const viewportElement = this.reader.viewport.value.element\n\n this.viewport.element.setAttribute(\n `data-${HTML_PREFIX}-zooming`,\n \"true\",\n )\n\n this.scrollNavigationController.value.element?.setAttribute(\n `data-${HTML_PREFIX}-zooming`,\n this.isControlled ? \"false\" : \"true\",\n )\n\n if (animate && this.isControlled) {\n viewportElement.style.transition = `transform ${ANIMATION_DURATION}ms`\n }\n\n this.mergeCompare({\n isZooming: true,\n currentScale: 1,\n currentPosition: { x: 0, y: 0 },\n })\n\n this.updateZoom(scale)\n\n if (scale !== 1 && this.isControlled) {\n return timer(options?.animate ? ANIMATION_DURATION : 0).pipe(\n tap(() => {\n this.reader.layout()\n }),\n )\n }\n\n return EMPTY\n }),\n )\n\n const exit$ = this.exitSubject.pipe(\n switchMap((options) => {\n const viewportElement = this.reader.viewport.value.element\n\n this.viewport.element.setAttribute(\n `data-${HTML_PREFIX}-zooming`,\n \"false\",\n )\n\n this.scrollNavigationController.value.element?.removeAttribute(\n `data-${HTML_PREFIX}-zooming-direction`,\n )\n this.scrollNavigationController.value.element?.setAttribute(\n `data-${HTML_PREFIX}-zooming`,\n \"false\",\n )\n\n if (options?.animate && this.isControlled) {\n viewportElement.style.transition = `transform ${ANIMATION_DURATION}ms`\n }\n\n this.updateZoom(1, { x: 0, y: 0 })\n\n viewportElement.style.transform = ``\n\n this.mergeCompare({\n isZooming: false,\n })\n\n return timer(options?.animate ? ANIMATION_DURATION : 0).pipe(\n tap(() => {\n const viewportElement = this.reader.viewport.value.element\n viewportElement.style.transformOrigin = ``\n viewportElement.style.transition = ``\n\n if (this.isControlled) {\n this.reader.layout()\n }\n }),\n takeUntil(this.enterSubject),\n )\n }),\n )\n\n merge(enter$, exit$).pipe(takeUntil(this.destroy$)).subscribe()\n }\n\n public enter(options?: ObservedValueOf<typeof this.enterSubject>) {\n this.enterSubject.next(options)\n }\n\n public exit(options?: ObservedValueOf<typeof this.exitSubject>) {\n this.exitSubject.next(options)\n }\n\n public move(\n position: { x: number; y: number },\n options?: { constrain?: \"within-viewport\" },\n ) {\n // no moving needed for scrollable mode\n if (!this.isControlled) return\n\n // make sure to prevent animation before applying the new position\n this.viewport.element.style.transition = ``\n\n this.updateZoom(this.value.currentScale, position, {\n constraints:\n options?.constrain === \"within-viewport\"\n ? (...rest) =>\n constrainPositionWithinViewport(...rest, this.reader.viewport)\n : undefined,\n })\n }\n\n public scaleAt(\n userScale: number,\n options?: { constrain?: \"within-viewport\" },\n ): void {\n // make sure to prevent animation before applying the new position\n this.viewport.element.style.transition = ``\n\n const roundedScale = Math.ceil(userScale * 100) / 100\n const newScale = roundedScale\n\n this.updateZoom(newScale, undefined, {\n constraints:\n options?.constrain === \"within-viewport\"\n ? (...rest) =>\n constrainPositionWithinViewport(...rest, this.reader.viewport)\n : undefined,\n })\n }\n\n protected updateZoom(\n scale: number,\n position?: ZoomPosition,\n options?: {\n constraints?: (position: ZoomPosition, scale: number) => ZoomPosition\n },\n ) {\n if (this.isControlled) {\n const newPosition = position\n ? position\n : derivePositionFromScaleForControlledMode(\n this.value.currentScale,\n scale,\n this.viewport.element,\n this.value.currentPosition,\n )\n\n const constrainedPosition =\n options?.constraints?.(newPosition, scale) ?? newPosition\n\n this.applyZoom(scale, constrainedPosition)\n\n return this.mergeCompare({\n currentScale: scale,\n currentPosition: constrainedPosition,\n })\n }\n\n this.applyZoom(scale, position ?? this.value.currentPosition)\n\n this.mergeCompare({\n currentScale: scale,\n })\n }\n\n protected applyZoom(scale: number, position: { x: number; y: number }) {\n if (!this.isControlled) {\n /**\n * @important\n * This does trigger a navigation to always re-center the scroll position with the new scale\n */\n applyScaleToViewportForScroll(scale, this.reader)\n } else {\n applyViewportTransformForControlledMode(\n scale,\n position,\n this.viewport.element,\n )\n }\n }\n\n protected get isControlled() {\n return this.reader.settings.values.computedPageTurnMode === \"controlled\"\n }\n\n protected get scrollNavigationController() {\n return this.reader.navigation.scrollNavigationController\n }\n\n protected get viewport() {\n return this.reader.viewport.value\n }\n}\n","import { HTML_STYLE_PREFIX } from \"../../constants\"\nimport type { Reader } from \"../../reader\"\nimport { injectCSS, removeCSS } from \"../../utils/dom\"\nimport styles from \"./index.scss?inline\"\nimport type { ZoomEnhancerOutput } from \"./types\"\nimport { ZoomController } from \"./ZoomController\"\n\nconst STYLES_ID = `${HTML_STYLE_PREFIX}-enhancer-zoom`\n\nexport const zoomEnhancer =\n <InheritOptions, InheritOutput extends Reader>(\n next: (options: InheritOptions) => InheritOutput,\n ) =>\n (options: InheritOptions): InheritOutput & ZoomEnhancerOutput => {\n const reader = next(options)\n const zoomController = new ZoomController(reader)\n\n injectCSS(document, STYLES_ID, styles)\n\n const destroy = () => {\n removeCSS(document, STYLES_ID)\n\n zoomController.destroy()\n reader.destroy()\n }\n\n const state$ = zoomController\n\n return {\n ...reader,\n destroy,\n zoom: {\n enter: zoomController.enter.bind(zoomController),\n scaleAt: zoomController.scaleAt.bind(zoomController),\n move: zoomController.move.bind(zoomController),\n exit: zoomController.exit.bind(zoomController),\n state$,\n get state() {\n return zoomController.value\n },\n },\n }\n }\n","import type { Manifest } from \"@prose-reader/shared\"\n\nexport const isFullyPrePaginated = (manifest?: Manifest) =>\n manifest?.renditionLayout === \"pre-paginated\" ||\n manifest?.spineItems.every((item) => item.renditionLayout === \"pre-paginated\")\n","import {\n BehaviorSubject,\n distinctUntilChanged,\n filter,\n ReplaySubject,\n} from \"rxjs\"\nimport type { Navigation } from \"../navigation/types\"\nimport type { PaginationInfo } from \"../pagination/types\"\n\n/**\n * Bridge events that are transverse to the project and needed across several\n * layout and level of components.\n *\n * These events have important and rather general meaning for the engine.\n *\n * This is also mostly because some components would have circular dep if\n * the events weren't extracted. (navigation and pagination both need to listen\n * to one another for example).\n */\nexport class BridgeEvent {\n public navigationSubject = new ReplaySubject<Navigation>(1)\n public viewportStateSubject = new BehaviorSubject<`free` | `busy`>(`free`)\n public paginationSubject = new ReplaySubject<PaginationInfo>()\n public navigationIsLockedSubject = new BehaviorSubject(false)\n\n /**\n * Replay last pagination and emit next changes\n */\n public pagination$ = this.paginationSubject.asObservable()\n\n /**\n * Emit whenever the navigation is unlocked.\n */\n public navigationUnlocked$ = this.navigationIsLockedSubject.pipe(\n distinctUntilChanged(),\n filter((isLocked) => !isLocked),\n )\n\n /**\n * Replay and emit viewport state\n */\n public viewportState$ = this.viewportStateSubject.asObservable()\n\n /**\n * Replay and emit whenever viewport is free\n */\n public viewportFree$ = this.viewportState$.pipe(\n filter((state) => state === \"free\"),\n )\n\n /**\n * Replay and emit whenever viewport is busy\n */\n public viewportBusy$ = this.viewportState$.pipe(\n filter((state) => state === \"busy\"),\n )\n\n /**\n * Replay and emit navigation\n */\n public navigation$ = this.navigationSubject.asObservable()\n}\n","import type { Manifest } from \"@prose-reader/shared\"\nimport { distinctUntilChanged, filter, map } from \"rxjs/operators\"\nimport { isFullyPrePaginated } from \"../manifest/isFullyPrePaginated\"\nimport { isDefined } from \"../utils/isDefined\"\nimport { ReactiveEntity } from \"../utils/ReactiveEntity\"\nimport { BridgeEvent } from \"./BridgeEvent\"\n\nexport type ContextState = {\n rootElement?: HTMLElement\n manifest?: Manifest\n hasVerticalWriting?: boolean\n assumedRenditionLayout: \"reflowable\" | \"pre-paginated\"\n isFullyPrePaginated?: boolean\n}\n\nexport class Context extends ReactiveEntity<ContextState> {\n public bridgeEvent = new BridgeEvent()\n public manifest$ = this.pipe(\n map((state) => state.manifest),\n filter(isDefined),\n distinctUntilChanged(),\n )\n\n constructor() {\n super({\n assumedRenditionLayout: \"reflowable\",\n })\n }\n\n public update(newState: Partial<ContextState>) {\n const previousState = this.value\n const manifest = newState.manifest ?? previousState.manifest\n\n const newCompleteState = {\n ...previousState,\n ...newState,\n ...(newState.manifest && {\n isFullyPrePaginated: isFullyPrePaginated(manifest),\n assumedRenditionLayout: manifest?.renditionLayout ?? \"reflowable\",\n }),\n }\n\n this.mergeCompare(newCompleteState)\n }\n\n /**\n * RTL only makes sense for horizontal scrolling\n */\n public isRTL = () => {\n return this.value.manifest?.readingDirection === `rtl`\n }\n\n get manifest() {\n return this.value.manifest\n }\n\n get readingDirection() {\n return this.manifest?.readingDirection\n }\n}\n","import { isShallowEqual } from \"@prose-reader/shared\"\nimport { combineLatest, distinctUntilChanged, map, takeUntil } from \"rxjs\"\nimport type { Context } from \"../context/Context\"\nimport type { ReaderSettingsManager } from \"../settings/ReaderSettingsManager\"\nimport type { CoreInputSettings } from \"../settings/types\"\nimport { ReactiveEntity } from \"../utils/ReactiveEntity\"\n\nexport type ContextSettings = Partial<CoreInputSettings>\n\ntype State = {\n supportedPageTurnAnimation: NonNullable<\n ContextSettings[`pageTurnAnimation`]\n >[]\n supportedPageTurnMode: NonNullable<ContextSettings[`pageTurnMode`]>[]\n supportedPageTurnDirection: NonNullable<\n ContextSettings[`pageTurnDirection`]\n >[]\n supportedComputedPageTurnDirection: NonNullable<\n ContextSettings[`pageTurnDirection`]\n >[]\n}\n\nexport class Features extends ReactiveEntity<State> {\n constructor(context: Context, settingsManager: ReaderSettingsManager) {\n super({\n supportedPageTurnAnimation: [`fade`, `none`, `slide`],\n supportedPageTurnMode: [`controlled`, `scrollable`],\n supportedPageTurnDirection: [`horizontal`, `vertical`],\n supportedComputedPageTurnDirection: [`horizontal`, `vertical`],\n })\n\n combineLatest([\n context.watch([\"manifest\", \"hasVerticalWriting\"]),\n settingsManager.watch([`computedPageTurnMode`]),\n ])\n .pipe(\n map(([{ manifest, hasVerticalWriting }, { computedPageTurnMode }]) => ({\n hasVerticalWriting,\n renditionFlow: manifest?.renditionFlow,\n renditionLayout: manifest?.renditionLayout,\n computedPageTurnMode,\n })),\n distinctUntilChanged(isShallowEqual),\n map(\n ({\n hasVerticalWriting,\n renditionFlow,\n renditionLayout,\n computedPageTurnMode,\n }) => {\n return {\n ...this.value,\n supportedPageTurnMode:\n renditionFlow === `scrolled-continuous`\n ? [`scrollable`]\n : [`controlled`, `scrollable`],\n supportedPageTurnAnimation:\n renditionFlow === `scrolled-continuous` ||\n computedPageTurnMode === `scrollable`\n ? [`none`]\n : hasVerticalWriting\n ? [`fade`, `none`]\n : [`fade`, `none`, `slide`],\n supportedPageTurnDirection:\n computedPageTurnMode === `scrollable`\n ? [`vertical`]\n : renditionLayout === `reflowable`\n ? [`horizontal`]\n : [`horizontal`, `vertical`],\n } satisfies State\n },\n ),\n takeUntil(this.destroy$),\n )\n .subscribe(this.next.bind(this))\n }\n}\n","import { combineLatest, of, Subject } from \"rxjs\"\nimport type {\n CoreHook,\n Hook,\n HookExecution,\n HookFrom,\n UserDestroyFn,\n} from \"./types\"\n\n// biome-ignore lint/suspicious/noExplicitAny: TODO\nexport class HookManager<H extends Hook<any, any, any> = CoreHook> {\n _hooks: Array<H> = []\n _hookExecutions: Array<HookExecution<H>> = []\n\n /**\n * Will:\n * - call destroy function for every execution of this specific hook\n * - remove the hook for further calls\n */\n protected deregister(hookToDeregister: H) {\n this._hooks = this._hooks.filter((hook) => hook !== hookToDeregister)\n\n return this.destroy(hookToDeregister.name, undefined, hookToDeregister)\n }\n\n /**\n * Ideal when your logic only needs to apply something to the item when it's loaded.\n * You can manipulate your item later if you need to update it and trigger a layout.\n * This logic will not run every time there is a layout.\n */\n public register<Name extends H[\"name\"]>(\n name: Name,\n fn: HookFrom<H, Name>[\"runFn\"],\n ) {\n const hook = {\n name,\n runFn: fn,\n }\n\n this._hooks.push(hook as H)\n\n return () => {\n this.deregister(hook as H)\n }\n }\n\n public execute<Name extends H[\"name\"]>(\n name: Name,\n id: string | undefined,\n params: Omit<\n Parameters<HookFrom<H, Name>[\"runFn\"]>[0],\n \"destroy\" | \"destroy$\"\n >,\n ): ReturnType<HookFrom<H, Name>[\"runFn\"]>[] {\n const hooks = this._hooks.filter(\n (hook): hook is HookFrom<H, Name> => name === hook.name,\n )\n\n const fnResults = hooks.map((hook) => {\n let userDestroyFn: UserDestroyFn = () => of(undefined)\n\n const destroySubject = new Subject<void>()\n const destroy = (fn: UserDestroyFn) => {\n userDestroyFn = fn\n }\n\n const destroyFn = () => {\n destroySubject.next()\n destroySubject.complete()\n\n const result = userDestroyFn()\n\n return result ?? of(undefined)\n }\n\n const fnResult = hook.runFn({\n // biome-ignore lint/suspicious/noExplicitAny: TODO\n ...(params as any),\n destroy$: destroySubject.asObservable(),\n destroy,\n })\n\n this._hookExecutions.push({\n name,\n id,\n destroyFn,\n ref: hook,\n })\n\n return fnResult\n })\n\n return fnResults\n }\n\n public destroy<Name extends H[\"name\"]>(name: Name, id?: string, ref?: H) {\n const instances = this._hookExecutions.filter(\n (hookInstance) =>\n // by ref is higher priority\n (ref && hookInstance.ref === ref) ||\n // otherwise we refine by name and eventually by id\n (name === hookInstance.name && (!id || (id && id === hookInstance.id))),\n )\n\n // remove destroyed instances from internal list\n this._hookExecutions = this._hookExecutions.filter(\n (instance) => !instances.includes(instance),\n )\n\n const destroyFns = instances.map(({ destroyFn }) => destroyFn())\n\n return combineLatest(destroyFns)\n }\n}\n","import { SpinePosition } from \"../../spine/types\"\n\n/**\n * LTR uses positive spine position and translate to negative translation.\n * Works both way for RTL.\n * @returns\n */\nexport const spinePositionToTranslation = (position: SpinePosition) => {\n return {\n x: -position.x,\n y: -position.y,\n }\n}\n\nexport const translationToSpinePosition = (\n translation: { x: number; y: number } | DOMMatrix,\n): SpinePosition => {\n if (translation instanceof DOMMatrix) {\n return new SpinePosition({\n x: -translation.e,\n y: -translation.f,\n })\n }\n\n return new SpinePosition({\n x: -translation.x,\n y: -translation.y,\n })\n}\n","import {\n animationFrameScheduler,\n BehaviorSubject,\n combineLatest,\n delay,\n filter,\n identity,\n map,\n merge,\n mergeMap,\n type Observable,\n of,\n Subject,\n share,\n shareReplay,\n startWith,\n switchMap,\n takeUntil,\n tap,\n withLatestFrom,\n} from \"rxjs\"\nimport { HTML_PREFIX } from \"../../constants\"\nimport type { Context } from \"../../context/Context\"\nimport type { HookManager } from \"../../hooks/HookManager\"\nimport { Report } from \"../../report\"\nimport type { ReaderSettingsManager } from \"../../settings/ReaderSettingsManager\"\nimport type { Spine } from \"../../spine/Spine\"\nimport { SpinePosition } from \"../../spine/types\"\nimport { DestroyableClass } from \"../../utils/DestroyableClass\"\nimport { isDefined } from \"../../utils/isDefined\"\nimport type { Viewport } from \"../../viewport/Viewport\"\nimport {\n spinePositionToTranslation,\n translationToSpinePosition,\n} from \"./positions\"\n\nconst NAMESPACE = `navigation/ViewportNavigator`\n\nconst report = Report.namespace(NAMESPACE)\n\nexport type ViewportNavigationEntry = {\n position: SpinePosition\n animation?: boolean | \"turn\" | \"snap\"\n}\n\nexport class ControlledNavigationController extends DestroyableClass {\n protected navigateSubject = new Subject<ViewportNavigationEntry>()\n\n public readonly element$ = new BehaviorSubject<HTMLElement>(\n document.createElement(`div`),\n )\n public isNavigating$: Observable<boolean>\n public layout$: Observable<unknown>\n\n constructor(\n protected settings: ReaderSettingsManager,\n protected hookManager: HookManager,\n protected context: Context,\n protected spine: Spine,\n protected viewport: Viewport,\n ) {\n super()\n\n const elementInit$ = this.spine.element$.pipe(\n filter(isDefined),\n withLatestFrom(this.element$),\n tap(([spineElement, element]) => {\n element.style.cssText = `\n height: 100%;\n width: 100%;\n position: relative;\n `\n element.className = `${HTML_PREFIX}-controlled-navigator`\n element.innerHTML = ``\n element.appendChild(spineElement)\n this.viewport.value.element.appendChild(element)\n this.element$.next(element)\n }),\n )\n\n const settingsThatRequireLayout$ = settings.watch([\n `computedPageTurnDirection`,\n `computedPageTurnMode`,\n `numberOfAdjacentSpineItemToPreLoad`,\n ])\n\n /**\n * Watch for settings update that require changes\n * on this layer.\n *\n * @important\n * Try not to have duplicate with other lower components that also listen to settings change and re-layout\n * on the same settings.\n */\n const updateElementOnSettingsChange$ = combineLatest([\n settingsThatRequireLayout$,\n this.element$,\n ]).pipe(\n tap(([, element]) => {\n if (settings.values.computedPageTurnMode === `scrollable`) {\n element.style.display = `contents`\n } else {\n element.style.display = `block`\n }\n }),\n )\n\n this.layout$ = updateElementOnSettingsChange$.pipe(\n tap(() => {\n report.info(`layout`, settings.values)\n }),\n share(),\n )\n\n const navigate$ = this.navigateSubject.pipe(\n tap((navigation) => {\n report.info(`Navigation requested`, navigation)\n }),\n )\n\n this.isNavigating$ = navigate$.pipe(\n map(({ animation, position }) => {\n const shouldAnimate = !(\n !animation ||\n (animation === `turn` &&\n settings.values.computedPageTurnAnimation === `none`)\n )\n\n return {\n type: `manualAdjust` as const,\n shouldAnimate,\n animation,\n position,\n }\n }),\n switchMap((currentEvent) => {\n const element = this.element$.getValue()\n\n // cleanup potential previous manual adjust\n element.style.setProperty(`transition`, `none`)\n element.style.setProperty(`opacity`, `1`)\n\n return merge(\n of(true),\n of(null).pipe(\n mergeMap(() => {\n if (currentEvent?.type !== `manualAdjust`) return of(false)\n\n const animationDuration =\n currentEvent.animation === `snap`\n ? settings.values.snapAnimationDuration\n : settings.values.computedPageTurnAnimationDuration\n const pageTurnAnimation =\n currentEvent.animation === `snap`\n ? (`slide` as const)\n : settings.values.computedPageTurnAnimation\n\n return of(currentEvent).pipe(\n /**\n * @important\n * Optimization:\n * When the adjustment does not need animation it means we want to be there as fast as possible\n * One example is when we adjust position after layout. In this case we don't want to have flicker or see\n * anything for x ms while we effectively adjust. We want it to be immediate.\n * However when user is repeatedly turning page, we can improve smoothness by delaying a bit the adjustment\n */\n currentEvent.shouldAnimate\n ? delay(1, animationFrameScheduler)\n : identity,\n tap((data) => {\n const element = this.element$.getValue()\n const noAdjustmentNeeded = false\n\n if (data.shouldAnimate && !noAdjustmentNeeded) {\n if (pageTurnAnimation === `fade`) {\n element.style.setProperty(\n `transition`,\n `opacity ${animationDuration / 2}ms`,\n )\n element.style.setProperty(`opacity`, `0`)\n } else if (\n currentEvent.animation === `snap` ||\n pageTurnAnimation === `slide`\n ) {\n element.style.setProperty(\n `transition`,\n `transform ${animationDuration}ms`,\n )\n element.style.setProperty(`opacity`, `1`)\n }\n } else {\n element.style.setProperty(`transition`, `none`)\n element.style.setProperty(`opacity`, `1`)\n }\n }),\n /**\n * @important\n * We always need to adjust the reading offset. Even if the current viewport value\n * is the same as the payload position. This is because an already running animation could\n * be active, meaning the viewport is still adjusting itself (after animation duration). So we\n * need to adjust to anchor to the payload position. This is because we use viewport computed position,\n * not the value set by `setProperty`\n */\n tap((data) => {\n if (pageTurnAnimation !== `fade`) {\n this.setViewportPosition(data.position)\n }\n }),\n currentEvent.shouldAnimate\n ? delay(animationDuration / 2, animationFrameScheduler)\n : identity,\n tap((data) => {\n const element = this.element$.getValue()\n\n if (pageTurnAnimation === `fade`) {\n this.setViewportPosition(data.position)\n element.style.setProperty(`opacity`, `1`)\n }\n }),\n currentEvent.shouldAnimate\n ? delay(animationDuration / 2, animationFrameScheduler)\n : identity,\n tap((data) => {\n if (pageTurnAnimation === `fade`) {\n this.setViewportPosition(data.position)\n }\n }),\n )\n }),\n map(() => false),\n ),\n )\n }),\n startWith(false),\n shareReplay(1),\n )\n\n merge(elementInit$, this.isNavigating$, this.layout$)\n .pipe(takeUntil(this.destroy$))\n .subscribe()\n }\n\n /**\n * Programmatically set the viewport position.\n *\n * Usually occurs due to navigation.\n *\n * @see https://stackoverflow.com/questions/22111256/translate3d-vs-translate-performance\n * for remark about flicker / fonts smoothing\n */\n protected setViewportPosition(position: SpinePosition) {\n const element = this.element$.getValue()\n\n const translation = spinePositionToTranslation(position)\n element.style.transform = `translate(${translation.x}px, ${translation.y}px)`\n\n this.hookManager.execute(\"onViewportOffsetAdjust\", undefined, {})\n }\n\n navigate(navigation: ViewportNavigationEntry) {\n this.navigateSubject.next(navigation)\n }\n\n /**\n * @important The reason we use computed transform and not bounding client is to avoid\n * transformation inconsistency between the viewport and the spine.\n */\n public get viewportPosition(): SpinePosition {\n const element = this.element$.getValue()\n\n const computedStyle = window.getComputedStyle(element)\n const transform = computedStyle.transform || computedStyle.webkitTransform\n\n if (!transform || transform === \"none\") {\n return new SpinePosition({ x: 0, y: 0 })\n }\n\n // Parse the transform matrix\n // The matrix is in the format: matrix(a, b, c, d, tx, ty) or matrix3d(...)\n const matrix = new DOMMatrix(transform)\n\n return translationToSpinePosition(matrix)\n }\n}\n","import { type Observable, map } from \"rxjs\"\nimport type { PaginationInfo } from \"../../pagination\"\nimport type { InternalNavigationEntry } from \"../types\"\n\ntype Navigation = {\n navigation: InternalNavigationEntry\n pagination: PaginationInfo\n}\n\nexport const withPaginationInfo =\n () =>\n <N extends Navigation>(stream: Observable<N>): Observable<N> => {\n return stream.pipe(\n map(({ navigation, pagination, ...rest }) => {\n return {\n navigation: {\n ...navigation,\n paginationBeginCfi: pagination.beginCfi,\n },\n ...rest,\n } as N\n }),\n )\n }\n","import {\n distinctUntilChanged,\n filter,\n first,\n map,\n type Observable,\n of,\n switchMap,\n withLatestFrom,\n} from \"rxjs\"\nimport type { Context } from \"../../context/Context\"\nimport type { Spine } from \"../../spine/Spine\"\nimport type { InternalNavigationEntry } from \"../types\"\nimport { withPaginationInfo } from \"./withPaginationInfo\"\n\nexport const consolidateWithPagination = (\n context: Context,\n navigation$: Observable<InternalNavigationEntry>,\n spine: Spine,\n) =>\n context.bridgeEvent.pagination$.pipe(\n withLatestFrom(navigation$),\n filter(\n ([pagination, navigation]) => pagination.navigationId === navigation.id,\n ),\n /**\n * We only register the pagination cfi IF the spine item is ready.\n * Otherwise we might save something incomplete and thus restore\n * the user to an invalid location.\n */\n switchMap(([pagination, navigation]) => {\n const spineItem = spine.spineItemsManager.get(navigation.spineItem)\n\n return (spineItem?.isReady$.pipe(first()) ?? of(false)).pipe(\n filter((isReady) => isReady),\n map(() => ({\n pagination,\n navigation,\n })),\n )\n }),\n withPaginationInfo(),\n distinctUntilChanged(\n (prev, curr) =>\n prev.navigation.paginationBeginCfi ===\n curr.navigation.paginationBeginCfi,\n ),\n map(\n ({ navigation }) =>\n ({\n ...navigation,\n meta: {\n triggeredBy: \"pagination\",\n },\n }) satisfies InternalNavigationEntry,\n ),\n )\n","import { map, type Observable } from \"rxjs\"\nimport type { NavigationResolver } from \"../resolvers/NavigationResolver\"\nimport type {\n InternalNavigationEntry,\n InternalNavigationInput,\n UserNavigationEntry,\n} from \"../types\"\n\nexport const mapUserNavigationToInternal =\n ({ navigationResolver }: { navigationResolver: NavigationResolver }) =>\n (\n stream: Observable<[UserNavigationEntry, InternalNavigationEntry]>,\n ): Observable<{\n navigation: InternalNavigationInput\n previousNavigation: InternalNavigationEntry\n }> => {\n return stream.pipe(\n map(([userNavigation, previousNavigation]) => {\n const navigation: InternalNavigationInput = {\n type: \"api\",\n meta: {\n triggeredBy: \"user\",\n },\n id: Symbol(),\n animation: \"turn\",\n ...userNavigation,\n /**\n * @important\n * For now we do not allow out of bounds positions. (this happens when scroll mode with a zoom out).\n * Although it's technically possible to be out of bounds, in terms of navigation and the rest of the app\n * it's hard to predict what will happens with negative x/y. spine item will not be retrieved, the spine position might\n * not be within anything (although the viewport slice is).\n *\n * Spine position should ideally be within the spine (even when viewport is scaled down/up). That's why we have viewport\n * on top of the spine.\n *\n * For now having things centered (negative x) on zoom out in scroll mode can be achieved with transform origin for example.\n * This \"limitation\" is here at the moment to avoid unexpected behaviors.\n *\n * @note\n * Has a bug where scaling from < 1 to 1 was creating positive x offset. This is \"expected\" since on scroll mode the viewport\n * is at the offset 0 at scale 0.2 for eg: then when calculating new scroll delta, we get positive x offset. Anyway, to prevent\n * out of bounds position this should make sure we always stay within an item.\n */\n position: userNavigation.position\n ? navigationResolver.fromOutOfBoundsSpinePosition(\n userNavigation.position,\n )\n : undefined,\n }\n\n return {\n previousNavigation,\n navigation,\n }\n }),\n )\n }\n","import { map, type Observable } from \"rxjs\"\nimport type { NavigationResolver } from \"../resolvers/NavigationResolver\"\nimport type { InternalNavigationInput } from \"../types\"\n\ntype Navigation = {\n navigation: InternalNavigationInput\n}\n\nexport const withCfiPosition =\n ({ navigationResolver }: { navigationResolver: NavigationResolver }) =>\n <N extends Navigation>(stream: Observable<N>): Observable<N> => {\n return stream.pipe(\n map((params) => {\n if (params.navigation.cfi) {\n const position = navigationResolver.getNavigationForCfi(\n params.navigation.cfi,\n )\n\n if (position) {\n return {\n ...params,\n navigation: {\n ...params.navigation,\n position,\n },\n } as N\n }\n }\n\n return params\n }),\n )\n }\n","import { map, type Observable } from \"rxjs\"\nimport type { Context } from \"../../context/Context\"\nimport type { ReaderSettingsManager } from \"../../settings/ReaderSettingsManager\"\nimport type { InternalNavigationEntry, InternalNavigationInput } from \"../types\"\n\ntype Navigation = {\n navigation: InternalNavigationInput\n previousNavigation: InternalNavigationEntry\n}\n\n/**\n * Since a consolidation happens synchronously after each navigation\n * we know we have at leat spine item everytime (independently from TS).\n *\n * For same spine item, we can only speculate\n */\nexport const getOrGuessDirection = ({\n navigation,\n previousNavigation,\n settings,\n}: {\n previousNavigation: InternalNavigationEntry\n navigation: InternalNavigationInput\n context: Context\n settings: ReaderSettingsManager\n}): InternalNavigationEntry[\"directionFromLastNavigation\"] => {\n /**\n * When we come from a restoration we might already have the\n * value setup, we should keep it.\n */\n if (navigation.directionFromLastNavigation)\n return navigation.directionFromLastNavigation\n\n // if (navigation.direction) {\n // switch (navigation.direction) {\n // case \"bottom\":\n // return \"forward\"\n // case \"top\":\n // return \"backward\"\n // case \"left\":\n // return context.isRTL() ? \"forward\" : \"backward\"\n // case \"right\":\n // return context.isRTL() ? \"backward\" : \"forward\"\n // }\n // }\n\n if (navigation.url !== undefined || navigation.cfi !== undefined) {\n return \"anchor\"\n }\n\n if (previousNavigation.spineItem === undefined) {\n return \"forward\"\n }\n\n /**\n * User navigate to specific spine item, we should\n * treat it as forward.\n *\n * Use case:\n * User navigate to back spine item & spine item is unloaded.\n * When spine item load and if we use backward, we will give the\n * idea the user want to be restored from the end of spine item whereas\n * he should be redirected to the begining of spine item.\n */\n if (navigation.spineItem) {\n return \"forward\"\n }\n\n if (!navigation.position) {\n return \"forward\"\n }\n\n /**\n * From this point forward, we can only make assumptions\n */\n if (settings.values.computedPageTurnDirection === \"vertical\") {\n if (navigation.position.y > previousNavigation.position.y) {\n return \"forward\"\n }\n\n if (\n navigation.position.y === previousNavigation.position.y &&\n previousNavigation.directionFromLastNavigation !== \"backward\"\n ) {\n return \"forward\"\n }\n return \"backward\"\n }\n\n if (\n Math.abs(navigation.position.x) > Math.abs(previousNavigation.position.x)\n ) {\n return \"forward\"\n }\n\n if (\n navigation.position.x === previousNavigation.position.x &&\n previousNavigation.directionFromLastNavigation !== \"backward\"\n ) {\n return \"forward\"\n }\n\n return \"backward\"\n}\n\nexport const withDirection =\n ({\n context,\n settings,\n }: {\n context: Context\n settings: ReaderSettingsManager\n }) =>\n (\n stream: Observable<Navigation>,\n ): Observable<\n Navigation & {\n direction: InternalNavigationEntry[\"directionFromLastNavigation\"]\n }\n > => {\n return stream.pipe(\n map(({ navigation, previousNavigation }) => {\n const direction = getOrGuessDirection({\n context,\n navigation,\n previousNavigation,\n settings,\n })\n\n const conslidatedNavigation: InternalNavigationInput = {\n ...navigation,\n directionFromLastNavigation: direction,\n }\n\n return {\n previousNavigation,\n navigation: conslidatedNavigation,\n direction,\n }\n }),\n )\n }\n","import { map, type Observable } from \"rxjs\"\nimport type { ReaderSettingsManager } from \"../../settings/ReaderSettingsManager\"\nimport type { SpineItemsManager } from \"../../spine/SpineItemsManager\"\nimport { UnboundSpinePosition } from \"../../spine/types\"\nimport type { NavigationResolver } from \"../resolvers/NavigationResolver\"\nimport type { InternalNavigationEntry, InternalNavigationInput } from \"../types\"\n\nexport const withFallbackPosition =\n ({\n spineItemsManager,\n navigationResolver,\n settings,\n }: {\n spineItemsManager: SpineItemsManager\n navigationResolver: NavigationResolver\n settings: ReaderSettingsManager\n }) =>\n <\n Navigation extends {\n navigation: InternalNavigationInput\n previousNavigation: InternalNavigationEntry\n },\n >(\n stream: Observable<Navigation>,\n ): Observable<\n Omit<Navigation, \"navigation\"> & {\n navigation: InternalNavigationEntry\n }\n > => {\n return stream.pipe(\n map(({ navigation, ...rest }) => {\n const spineItem = spineItemsManager.get(navigation.spineItem)\n\n if (navigation.position) {\n /**\n * Scrollable mode does allow unbound position by design.\n */\n if (settings.values.computedPageTurnMode === \"scrollable\") {\n return {\n navigation: {\n ...navigation,\n position: navigation.position,\n },\n ...rest,\n }\n }\n\n /**\n * We have been given position, we just make sure to prevent navigation\n * in outer edges.\n */\n return {\n navigation: {\n ...navigation,\n position: navigationResolver.fromUnboundSpinePosition(\n navigation.position,\n ),\n },\n ...rest,\n }\n }\n\n if (!spineItem)\n return {\n navigation: {\n ...navigation,\n position: rest.previousNavigation.position,\n },\n ...rest,\n }\n\n /**\n * Fallback.\n *\n * We get the most appropriate navigation for spine item.\n */\n const position =\n navigationResolver.getNavigationForSpineIndexOrId(spineItem)\n\n /**\n * We try to maintain x axis for scrollable mode.\n */\n const adjustedPosition =\n settings.values.computedPageTurnMode === \"scrollable\"\n ? new UnboundSpinePosition({\n x: position.x + rest.previousNavigation.position.x,\n y: position.y,\n })\n : navigationResolver.fromUnboundSpinePosition(position)\n\n return {\n navigation: {\n ...navigation,\n position: adjustedPosition,\n },\n ...rest,\n }\n }),\n )\n }\n","import { map, type Observable } from \"rxjs\"\nimport type { Context } from \"../../context/Context\"\nimport type { ReaderSettingsManager } from \"../../settings/ReaderSettingsManager\"\nimport type { SpineLocator } from \"../../spine/locator/SpineLocator\"\nimport type { SpineItemsManager } from \"../../spine/SpineItemsManager\"\nimport type { NavigationResolver } from \"../resolvers/NavigationResolver\"\nimport type { InternalNavigationInput } from \"../types\"\n\ntype Navigation = {\n navigation: InternalNavigationInput\n}\n\nexport const withSpineItem =\n ({\n settings,\n spineItemsManager,\n navigationResolver,\n spineLocator,\n }: {\n context: Context\n settings: ReaderSettingsManager\n spineItemsManager: SpineItemsManager\n navigationResolver: NavigationResolver\n spineLocator: SpineLocator\n }) =>\n <N extends Navigation>(stream: Observable<N>): Observable<N> => {\n const getSpineItem = (navigation: InternalNavigationInput) => {\n const {\n position,\n spineItem,\n cfi,\n directionFromLastNavigation: direction,\n } = navigation\n const { navigationSnapThreshold, computedPageTurnMode } = settings.values\n\n /**\n * - valid given spine item\n */\n if (spineItem !== undefined) {\n const existingSpineItem = spineItemsManager.get(spineItem)\n\n if (existingSpineItem) return existingSpineItem\n }\n\n /**\n * - invalid spine item given\n * - number too high\n * - number too low\n */\n if (typeof spineItem === \"number\") {\n if (spineItem > spineItemsManager.items.length - 1) {\n return spineItemsManager.get(spineItemsManager.items.length - 1)\n }\n\n return spineItemsManager.get(0)\n }\n\n /**\n * - cfi given\n * - we can grab safely the item\n */\n if (cfi) {\n const existingSpineItem = spineItemsManager.getSpineItemFromCfi(cfi)\n\n if (existingSpineItem) return existingSpineItem\n }\n\n /**\n * - controlled mode\n * - we have a position\n * - we retrieve the item that correspond the closest to the position\n */\n if (position && computedPageTurnMode === \"controlled\") {\n /**\n * @important\n *\n * Due to spread layout and/or LTR this part is a bit tricky.\n * It works in principe for a spread of N and any reading direction\n * since it uses begin/end concept.\n *\n * 1. We check the farthest visible spine item for the given navigation\n * 2. We check the farthest visible page for the item\n * 3. We retrieve the farthest navigable position.\n *\n * From that point we have the farthest navigable valid position for a given\n * navigation. (remember given navigation is not trustable). We will use this\n * navigation to lookup correctly the item\n *\n * 4. We lookup from the navigation the begin item (forward) or the end item (backward).\n */\n const { beginIndex, endIndex } =\n spineLocator.getVisibleSpineItemsFromPosition({\n position,\n threshold: navigationSnapThreshold,\n restrictToScreen: false,\n }) ?? {}\n\n const farthestSpineItemIndex =\n (direction === \"forward\" || direction === \"anchor\"\n ? endIndex\n : beginIndex) ?? beginIndex\n\n const farthestSpineItem = spineItemsManager.get(farthestSpineItemIndex)\n\n if (!farthestSpineItem) return undefined\n\n const { endPageIndex, beginPageIndex } =\n spineLocator.getVisiblePagesFromViewportPosition({\n position,\n spineItem: farthestSpineItem,\n threshold: navigationSnapThreshold,\n restrictToScreen: false,\n }) ?? {}\n\n const farthestVisiblePageIndex =\n (direction === \"forward\" || direction === \"anchor\"\n ? endPageIndex\n : beginPageIndex) ?? 0\n\n const navigationForPosition =\n navigationResolver.getNavigationForSpineItemPage({\n pageIndex: farthestVisiblePageIndex,\n spineItemId: farthestSpineItem,\n })\n\n const visibleSpineItemsFromNavigablePosition =\n spineLocator.getVisibleSpineItemsFromPosition({\n position: navigationForPosition,\n threshold: navigationSnapThreshold,\n restrictToScreen: false,\n })\n\n const finalSpineItemIndex =\n direction === \"forward\" || direction === \"anchor\"\n ? visibleSpineItemsFromNavigablePosition?.beginIndex\n : visibleSpineItemsFromNavigablePosition?.endIndex\n\n return spineItemsManager.get(finalSpineItemIndex)\n }\n\n /**\n * - scrollable content\n * - we have position\n * - we just pick the right item\n */\n if (position && computedPageTurnMode === \"scrollable\") {\n return spineLocator.getSpineItemFromPosition(position)\n }\n\n return spineItemsManager.get(0)\n }\n\n return stream.pipe(\n map(({ navigation, ...rest }) => {\n const spineItem = getSpineItem(navigation)\n\n return {\n navigation: {\n ...navigation,\n spineItem: spineItemsManager.getSpineItemIndex(spineItem),\n },\n ...rest,\n } as N\n }),\n )\n }\n","import { first, map, type Observable, of, switchMap } from \"rxjs\"\nimport type { Spine } from \"../../spine/Spine\"\nimport type { InternalNavigationEntry, InternalNavigationInput } from \"../types\"\n\ntype Navigation = {\n navigation: InternalNavigationInput | InternalNavigationEntry\n}\n\nexport const withSpineItemLayoutInfo =\n ({ spine }: { spine: Spine }) =>\n <N extends Navigation>(stream: Observable<N>): Observable<N> => {\n return stream.pipe(\n switchMap(({ navigation, ...rest }) => {\n const spineItemDimensions = spine.getSpineItemSpineLayoutInfo(\n navigation.spineItem,\n )\n const spineItem = spine.spineItemsManager.get(navigation.spineItem)\n\n return (spineItem?.isReady$ ?? of(false)).pipe(\n first(),\n map(\n (isReady) =>\n ({\n navigation: {\n ...navigation,\n spineItemHeight: spineItemDimensions?.height,\n spineItemWidth: spineItemDimensions?.width,\n spineItemLeft: spineItemDimensions.left,\n spineItemTop: spineItemDimensions.top,\n spineItemIsUsingVerticalWriting:\n spineItem?.isUsingVerticalWriting(),\n spineItemIsReady: isReady,\n },\n ...rest,\n }) as N,\n ),\n )\n }),\n )\n }\n","import { map, type Observable } from \"rxjs\"\nimport type { ReaderSettingsManager } from \"../../settings/ReaderSettingsManager\"\nimport type { SpineLocator } from \"../../spine/locator/SpineLocator\"\nimport type { SpineItemsManager } from \"../../spine/SpineItemsManager\"\nimport type { NavigationResolver } from \"../resolvers/NavigationResolver\"\nimport type { InternalNavigationEntry, InternalNavigationInput } from \"../types\"\n\ntype Navigation = {\n navigation: InternalNavigationEntry | InternalNavigationInput\n}\n\nexport const withSpineItemPosition =\n ({\n settings,\n spineItemsManager,\n spineLocator,\n navigationResolver,\n }: {\n settings: ReaderSettingsManager\n spineItemsManager: SpineItemsManager\n navigationResolver: NavigationResolver\n spineLocator: SpineLocator\n }) =>\n <N extends Navigation>(stream: Observable<N>): Observable<N> => {\n const getPosition = (navigation: N[\"navigation\"]) => {\n const { navigationSnapThreshold, computedPageTurnMode } = settings.values\n const spineItem = spineItemsManager.get(navigation.spineItem)\n\n if (!spineItem || !navigation.position) return undefined\n\n /**\n * - controlled mode\n * - we have navigation\n * - we update spine position from navigation\n */\n if (computedPageTurnMode === \"controlled\") {\n /**\n * @important\n *\n * Due to spread layout and/or LTR this part is a bit tricky.\n * It works in principe for a spread of N and any reading direction\n * since it uses begin/end concept.\n *\n * 1. We can trust the given spine item\n * 2. We get the farthest page from current position on item\n * - forward: we take end\n * - backward: we take begin\n * 3. We get navigable position for this page\n * 4. We get visible pages strictly for this position (no snapping)\n * - forward: we take begin\n * - backward: we take end\n * 5. We keep position in spine item for that page\n */\n const { endPageIndex, beginPageIndex } =\n spineLocator.getVisiblePagesFromViewportPosition({\n position: navigation.position,\n spineItem,\n threshold: navigationSnapThreshold,\n restrictToScreen: false,\n }) ?? {}\n\n const farthestPageIndex =\n (navigation.directionFromLastNavigation === \"forward\" ||\n navigation.directionFromLastNavigation === \"anchor\"\n ? endPageIndex\n : beginPageIndex) ?? 0\n\n const navigableSpinePositionForFarthestPageIndex =\n navigationResolver.getNavigationForSpineItemPage({\n pageIndex: farthestPageIndex,\n spineItemId: spineItem,\n })\n\n const visiblePagesAtNavigablePosition =\n spineLocator.getVisiblePagesFromViewportPosition({\n position: navigableSpinePositionForFarthestPageIndex,\n spineItem,\n threshold: { type: \"percentage\", value: 0 },\n restrictToScreen: true,\n })\n\n const beginPageIndexForDirection =\n (navigation.directionFromLastNavigation === \"forward\" ||\n navigation.directionFromLastNavigation === \"anchor\"\n ? visiblePagesAtNavigablePosition?.beginPageIndex\n : visiblePagesAtNavigablePosition?.endPageIndex) ?? 0\n\n const positionInSpineItem =\n spineLocator.spineItemLocator.getSpineItemPositionFromPageIndex({\n pageIndex: beginPageIndexForDirection,\n spineItem,\n })\n\n return positionInSpineItem\n }\n\n /**\n * - fallback\n * - we just get position in item from item\n */\n return spineLocator.getSpineItemPositionFromSpinePosition(\n navigation.position,\n spineItem,\n )\n }\n\n return stream.pipe(\n map(({ navigation, ...rest }) => {\n return {\n navigation: {\n ...navigation,\n positionInSpineItem: getPosition(navigation),\n },\n ...rest,\n } as N\n }),\n )\n }\n","import { map, type Observable } from \"rxjs\"\nimport type { NavigationResolver } from \"../resolvers/NavigationResolver\"\nimport type { InternalNavigationInput } from \"../types\"\n\ntype Navigation = {\n navigation: InternalNavigationInput\n}\n\nexport const withUrlInfo =\n ({ navigationResolver }: { navigationResolver: NavigationResolver }) =>\n <N extends Navigation>(stream: Observable<N>): Observable<N> => {\n return stream.pipe(\n map((params) => {\n if (params.navigation.url) {\n const result = navigationResolver.getNavigationForUrl(\n params.navigation.url,\n )\n\n if (result) {\n return {\n ...params,\n navigation: {\n ...params.navigation,\n position: result.position,\n spineItem: result.spineItemId,\n },\n } as N\n }\n }\n\n return params\n }),\n )\n }\n","import { BehaviorSubject, distinctUntilChanged, map } from \"rxjs\"\n\nexport class Locker {\n protected isLockedSubject = new BehaviorSubject(0)\n\n public isLocked$ = this.isLockedSubject.pipe(\n map((locked) => !!locked),\n distinctUntilChanged(),\n )\n\n public lock() {\n let isCalled = false\n this.isLockedSubject.next(this.isLockedSubject.getValue() + 1)\n\n return () => {\n if (isCalled) return\n\n isCalled = true\n\n this.isLockedSubject.next(this.isLockedSubject.getValue() - 1)\n }\n }\n}\n","import { type Observable, first, map, of } from \"rxjs\"\nimport { isRootCfi } from \"../../cfi\"\nimport type { Spine } from \"../../spine/Spine\"\nimport type { SpineItemsManager } from \"../../spine/SpineItemsManager\"\nimport type { SpineLocator } from \"../../spine/locator/SpineLocator\"\nimport { SpinePosition } from \"../../spine/types\"\nimport { SpineItemPosition } from \"../../spineItem/types\"\nimport type { NavigationResolver } from \"../resolvers/NavigationResolver\"\nimport type { InternalNavigationEntry } from \"../types\"\n\nexport const restoreNavigationForControlledPageTurnMode = ({\n spineLocator,\n navigation,\n navigationResolver,\n spineItemsManager,\n spine,\n}: {\n navigation: InternalNavigationEntry\n spineLocator: SpineLocator\n navigationResolver: NavigationResolver\n spineItemsManager: SpineItemsManager\n spine: Spine\n}): Observable<SpinePosition> => {\n const spineItem = spineItemsManager.get(navigation.spineItem)\n\n if (!spineItem) {\n return of(new SpinePosition({ x: 0, y: 0 }))\n }\n\n return spineItem.isReady$.pipe(\n first(),\n map((isReady) => {\n const spineItemAbsolutePosition =\n spine.getSpineItemSpineLayoutInfo(spineItem)\n\n const isPositionWithinSpineItem = spineLocator.isPositionWithinSpineItem(\n navigation.position,\n spineItem,\n )\n\n const spineItemWidthDifference =\n spineItemAbsolutePosition.width - (navigation.spineItemWidth ?? 0)\n const spineItemHeighDifference =\n spineItemAbsolutePosition.height - (navigation.spineItemHeight ?? 0)\n\n const hasSpineItemGrewOrShrink =\n spineItemWidthDifference !== 0 || spineItemHeighDifference !== 0\n\n /**\n * Url navigation has higher priority together with CFI, we should\n * restore from it first.\n *\n * If the layout did not change, we should not restore from cfi since\n * we will have better accuracy from all other consolidation.\n *\n * Basically as long as the item itself did not change, we can recover from\n * consolidation. In case the item changed, we should be careful and try to\n * anchor back to cfi.\n */\n if (navigation.url !== undefined) {\n if (\n spineItemWidthDifference ||\n spineItemHeighDifference ||\n // when spine item is ready dimensions may have not changed but the position\n // of dom elements may have!\n (isReady && !navigation.spineItemIsReady)\n ) {\n const urlResult = navigationResolver.getNavigationForUrl(\n navigation.url,\n )\n\n if (urlResult) {\n return urlResult.position\n }\n }\n }\n\n const cfi = navigation.cfi ?? navigation.paginationBeginCfi\n\n /**\n * Restoration from cfi.\n * If the layout did not change, we should not restore from cfi since\n * we will have better accuracy from all other consolidation.\n *\n * Basically as long as the item itself did not change, we can recover from\n * consolidation. In case the item changed, we should be careful and try to\n * anchor back to cfi.\n */\n if (cfi !== undefined && !isRootCfi(cfi)) {\n if (\n spineItemWidthDifference ||\n spineItemHeighDifference ||\n // when spine item is ready dimensions may have not changed but the position\n // of dom elements may have!\n (isReady && !navigation.spineItemIsReady)\n ) {\n const cfiResultPosition = navigationResolver.getNavigationForCfi(cfi)\n\n if (cfiResultPosition) {\n return cfiResultPosition\n }\n }\n }\n\n if (\n isPositionWithinSpineItem &&\n hasSpineItemGrewOrShrink &&\n navigation.directionFromLastNavigation === \"backward\"\n ) {\n const positionInSpineItemWithDifference = new SpineItemPosition({\n x:\n (navigation.positionInSpineItem?.x ?? 0) + spineItemWidthDifference,\n y:\n (navigation.positionInSpineItem?.y ?? 0) + spineItemHeighDifference,\n })\n\n return navigationResolver.getNavigationFromSpineItemPosition({\n spineItem,\n spineItemPosition: positionInSpineItemWithDifference,\n })\n }\n\n /**\n * - position in spine item known\n * - dimensions of item known\n * - we can retrieve the desired page index\n * - we get navigation for same page on current item\n */\n if (\n navigation.positionInSpineItem &&\n navigation.spineItemHeight &&\n navigation.spineItemWidth\n ) {\n const pageIndex =\n spineLocator.spineItemLocator.getSpineItemPageIndexFromPosition({\n itemWidth: navigation.spineItemWidth,\n itemHeight: navigation.spineItemHeight,\n isUsingVerticalWriting:\n !!navigation.spineItemIsUsingVerticalWriting,\n position: navigation.positionInSpineItem,\n })\n\n return navigationResolver.getNavigationForSpineItemPage({\n pageIndex,\n spineItemId: spineItem,\n })\n }\n\n /**\n * - position is within spine item\n * - position is somewhat trustable\n * - we will retrieve the closest valid navigation\n */\n if (isPositionWithinSpineItem) {\n return navigationResolver.getNavigationForPosition(navigation.position)\n }\n\n /**\n * - position is not within spine item\n * - position is not trustable\n * - fallback to default navigation for spine item\n */\n return navigationResolver.getNavigationForSpineIndexOrId(spineItem)\n }),\n )\n}\n","import { type Observable, of } from \"rxjs\"\nimport type { Context } from \"../../context/Context\"\nimport type { ReaderSettingsManager } from \"../../settings/ReaderSettingsManager\"\nimport type { SpineLocator } from \"../../spine/locator/SpineLocator\"\nimport type { Spine } from \"../../spine/Spine\"\nimport type { SpineItemsManager } from \"../../spine/SpineItemsManager\"\nimport { SpinePosition, type UnboundSpinePosition } from \"../../spine/types\"\nimport type { SpineItemLocator } from \"../../spineItem/locationResolver\"\nimport { SpineItemPosition } from \"../../spineItem/types\"\nimport type { NavigationResolver } from \"../resolvers/NavigationResolver\"\nimport type { InternalNavigationEntry } from \"../types\"\nimport { restoreNavigationForControlledPageTurnMode } from \"./restoreNavigationForControlledPageTurnMode\"\n\nconst restoreNavigationForScrollingPageTurnMode = ({\n navigation,\n spineLocator,\n spineItemsManager,\n settings,\n navigationResolver,\n spine,\n}: {\n spineItemsManager: SpineItemsManager\n spineLocator: SpineLocator\n settings: ReaderSettingsManager\n navigationResolver: NavigationResolver\n navigation: InternalNavigationEntry\n spine: Spine\n}): InternalNavigationEntry[\"position\"] => {\n const { spineItem } = navigation\n const foundSpineItem = spineItemsManager.get(spineItem)\n\n if (!foundSpineItem) return new SpinePosition({ x: 0, y: 0 })\n\n const { height, top } = spine.getSpineItemSpineLayoutInfo(foundSpineItem)\n\n const isPositionWithinSpineItem = spineLocator.isPositionWithinSpineItem(\n navigation.position,\n foundSpineItem,\n )\n\n const positionInSpineItem =\n navigation.positionInSpineItem ??\n new SpineItemPosition({\n y: 0,\n x: 0,\n })\n\n /**\n * - vertical scroll\n */\n if (settings.values.computedPageTurnDirection === \"vertical\") {\n /**\n * - item did not shift\n * - item same height\n * - we are still within the item\n */\n if (\n top === navigation.spineItemTop &&\n height === navigation.spineItemHeight &&\n isPositionWithinSpineItem\n ) {\n /**\n * -> nothing\n */\n return navigation.position\n }\n\n /**\n * vertical scroll\n * - item did not shift\n * - item same height\n * - not within item\n */\n if (\n top === navigation.spineItemTop &&\n height === navigation.spineItemHeight &&\n !isPositionWithinSpineItem\n ) {\n /**\n * -> fallback to beginning of item\n */\n return navigationResolver.getNavigationForSpineIndexOrId(foundSpineItem)\n }\n\n /**\n * - item shifted\n */\n if (top !== navigation.spineItemTop) {\n /**\n * -> fallback to position we were in spine item\n */\n const positionInSpineItem =\n spineLocator.getSafeSpineItemPositionFromUnsafeSpineItemPosition(\n navigation.positionInSpineItem ??\n new SpineItemPosition({\n x: 0,\n y: 0,\n }),\n foundSpineItem,\n )\n\n return spineLocator.getSpinePositionFromSpineItemPosition({\n spineItemPosition: positionInSpineItem,\n spineItem: foundSpineItem,\n })\n }\n\n /**\n * - item did not shift\n * - height changed\n */\n if (\n top === navigation.spineItemTop &&\n height !== navigation.spineItemHeight\n ) {\n const positionYfromBottomPreviousNavigation =\n (navigation.spineItemHeight ?? positionInSpineItem.y) -\n positionInSpineItem.y\n\n const positionInspineItem = new SpineItemPosition({\n y:\n navigation.directionFromLastNavigation === \"backward\"\n ? height - positionYfromBottomPreviousNavigation\n : positionInSpineItem.y,\n x: navigation.position.x,\n })\n\n /**\n * - position within item\n *\n * @problems\n * - position may be wrong since the item changed its content\n *\n * @restoration\n * We try to get as much as info as possible from previous navigation\n * so we can find the best accurate spot the user was\n */\n if (isPositionWithinSpineItem) {\n /**\n * - we navigate to the closest valid position\n */\n const positionInSpineItem =\n spineLocator.getSafeSpineItemPositionFromUnsafeSpineItemPosition(\n positionInspineItem,\n foundSpineItem,\n )\n\n return spineLocator.getSpinePositionFromSpineItemPosition({\n spineItemPosition: positionInSpineItem,\n spineItem: foundSpineItem,\n })\n }\n\n /**\n * - position not within item anymore\n */\n if (!isPositionWithinSpineItem) {\n const positionIsBeforeItem = navigation.position.y < top\n\n /**\n * In case the navigation is too far down, we try to anchor back to\n * the spine item but we also try to keep the same previous offset\n * we had, the point is not to just anchor back to the begining or the\n * exact end of the spine item.\n * example:\n * - we are at 100px from bottom of a 300px height item\n * - layout happens and item becomes 200px height\n * - we are now at the end of item, we need to go back by 100px\n */\n if (!positionIsBeforeItem) {\n const positionInItem = new SpineItemPosition({\n y: height - positionYfromBottomPreviousNavigation,\n x: navigation.position.x,\n })\n\n return spineLocator.getSpinePositionFromSpineItemPosition({\n spineItemPosition:\n spineLocator.getSafeSpineItemPositionFromUnsafeSpineItemPosition(\n positionInItem,\n foundSpineItem,\n ),\n spineItem: foundSpineItem,\n })\n }\n\n /**\n * - we anchor back to begining of item\n */\n return navigationResolver.getNavigationForSpineIndexOrId(foundSpineItem)\n }\n }\n }\n\n return navigation.position\n}\n\nexport const restorePosition = ({\n navigation,\n spineItemsManager,\n settings,\n spineLocator,\n navigationResolver,\n spine,\n}: {\n spineLocator: SpineLocator\n settings: ReaderSettingsManager\n navigationResolver: NavigationResolver\n navigation: InternalNavigationEntry\n spineItemsManager: SpineItemsManager\n spineItemLocator: SpineItemLocator\n context: Context\n spine: Spine\n}): Observable<SpinePosition | UnboundSpinePosition> => {\n if (settings.values.computedPageTurnMode === \"scrollable\") {\n return of(\n restoreNavigationForScrollingPageTurnMode({\n navigation,\n spineLocator,\n navigationResolver,\n settings,\n spineItemsManager,\n spine,\n }),\n )\n }\n\n return restoreNavigationForControlledPageTurnMode({\n navigation,\n spineLocator,\n navigationResolver,\n spineItemsManager,\n spine,\n })\n}\n","import { map, type Observable, switchMap } from \"rxjs\"\nimport type { Context } from \"../../context/Context\"\nimport type { ReaderSettingsManager } from \"../../settings/ReaderSettingsManager\"\nimport type { Spine } from \"../../spine/Spine\"\nimport type { NavigationResolver } from \"../resolvers/NavigationResolver\"\nimport type { InternalNavigationEntry } from \"../types\"\nimport { restorePosition } from \"./restorePosition\"\n\ntype Navigation = {\n navigation: InternalNavigationEntry\n}\n\nexport const withRestoredPosition =\n ({\n settings,\n navigationResolver,\n context,\n spine,\n }: {\n navigationResolver: NavigationResolver\n settings: ReaderSettingsManager\n context: Context\n spine: Spine\n }) =>\n <N extends Navigation>(stream: Observable<N>): Observable<N> =>\n stream.pipe(\n switchMap((params) => {\n return restorePosition({\n spineLocator: spine.locator,\n navigation: params.navigation,\n navigationResolver,\n settings,\n spineItemsManager: spine.spineItemsManager,\n spineItemLocator: spine.locator.spineItemLocator,\n context,\n spine,\n }).pipe(\n map((restoredPosition) => ({\n ...params,\n navigation: {\n ...params.navigation,\n position: restoredPosition,\n },\n })),\n )\n }),\n )\n","import {\n BehaviorSubject,\n distinctUntilChanged,\n filter,\n finalize,\n first,\n identity,\n map,\n merge,\n type Observable,\n of,\n share,\n shareReplay,\n skip,\n switchMap,\n takeUntil,\n tap,\n withLatestFrom,\n} from \"rxjs\"\nimport type { Context } from \"../context/Context\"\nimport { Report } from \"../report\"\nimport type { ReaderSettingsManager } from \"../settings/ReaderSettingsManager\"\nimport type { Spine } from \"../spine/Spine\"\nimport { SpinePosition } from \"../spine/types\"\nimport { DestroyableClass } from \"../utils/DestroyableClass\"\nimport { isShallowEqual } from \"../utils/objects\"\nimport { consolidateWithPagination } from \"./consolidation/consolidateWithPagination\"\nimport { mapUserNavigationToInternal } from \"./consolidation/mapUserNavigationToInternal\"\nimport { withCfiPosition } from \"./consolidation/withCfiPosition\"\nimport { withDirection } from \"./consolidation/withDirection\"\nimport { withFallbackPosition } from \"./consolidation/withFallbackPosition\"\nimport { withSpineItem } from \"./consolidation/withSpineItem\"\nimport { withSpineItemLayoutInfo } from \"./consolidation/withSpineItemLayoutInfo\"\nimport { withSpineItemPosition } from \"./consolidation/withSpineItemPosition\"\nimport { withUrlInfo } from \"./consolidation/withUrlInfo\"\nimport type { ControlledNavigationController } from \"./controllers/ControlledNavigationController\"\nimport type { ScrollNavigationController } from \"./controllers/ScrollNavigationController\"\nimport { Locker } from \"./Locker\"\nimport type { createNavigationResolver } from \"./resolvers/NavigationResolver\"\nimport { withRestoredPosition } from \"./restoration/withRestoredPosition\"\nimport type { InternalNavigationEntry, UserNavigationEntry } from \"./types\"\n\nconst NAMESPACE = `navigation/InternalNavigator`\n\nconst report = Report.namespace(NAMESPACE)\n\nexport class InternalNavigator extends DestroyableClass {\n /**\n * This position correspond to the current navigation position.\n * This is always sync with navigation and adjustment but IS NOT necessarily\n * synced with current viewport. This is because viewport can be animated.\n * This value may be used to adjust / get current valid info about what should be visible.\n * This DOES NOT reflect necessarily what is visible for the user at instant T.\n */\n public navigationSubject = new BehaviorSubject<InternalNavigationEntry>({\n animation: false,\n position: new SpinePosition({ x: 0, y: 0 }),\n meta: {\n triggeredBy: \"user\",\n },\n spineItemIsReady: false,\n type: \"api\",\n id: Symbol(),\n })\n\n public navigated$ = this.navigationSubject.pipe(skip(1))\n\n public navigation$ = this.navigationSubject.pipe(\n map(({ position, id }) => ({\n position,\n id,\n })),\n distinctUntilChanged(\n (\n { position: previousPosition, ...previousRest },\n { position: currentPosition, ...currentRest },\n ) =>\n isShallowEqual(previousRest, currentRest) &&\n isShallowEqual(previousPosition, currentPosition),\n ),\n shareReplay(1),\n )\n\n public locker = new Locker()\n\n constructor(\n protected settings: ReaderSettingsManager,\n protected context: Context,\n protected userNavigation$: Observable<UserNavigationEntry>,\n protected controlledNavigationController: ControlledNavigationController,\n protected scrollNavigationController: ScrollNavigationController,\n protected navigationResolver: ReturnType<typeof createNavigationResolver>,\n protected spine: Spine,\n /**\n * Allow automatic restoration to happens.\n * - correction of position\n * - restoration of position\n */\n protected isRestorationLocked$: Observable<boolean>,\n ) {\n super()\n\n const navigationFromUser$ = userNavigation$\n .pipe(\n withLatestFrom(this.navigationSubject),\n mapUserNavigationToInternal({\n navigationResolver,\n }),\n /**\n * Url lookup is heavier so we start with it to fill\n * as much information as needed to reduce later lookup\n */\n withUrlInfo({\n navigationResolver,\n }),\n /**\n * Cfi lookup is heavier so we start with it to fill\n * as much information as needed to reduce later lookup\n */\n withCfiPosition({\n navigationResolver,\n }),\n withDirection({ context, settings }),\n withSpineItem({\n context,\n navigationResolver,\n settings,\n spineItemsManager: spine.spineItemsManager,\n spineLocator: spine.locator,\n }),\n withSpineItemPosition({\n navigationResolver,\n settings,\n spineItemsManager: spine.spineItemsManager,\n spineLocator: spine.locator,\n }),\n withSpineItemLayoutInfo({\n spine,\n }),\n )\n .pipe(\n withFallbackPosition({\n navigationResolver,\n spineItemsManager: spine.spineItemsManager,\n settings,\n }),\n withLatestFrom(isRestorationLocked$),\n switchMap(([params, isUserLocked]) => {\n const shouldNotAlterPosition =\n params.navigation.cfi ||\n params.navigation.url ||\n settings.values.computedPageTurnMode === \"scrollable\" ||\n isUserLocked\n\n return of(params).pipe(\n shouldNotAlterPosition\n ? identity\n : withRestoredPosition({\n navigationResolver,\n settings,\n spine,\n context,\n }),\n )\n }),\n withSpineItemPosition({\n spineItemsManager: spine.spineItemsManager,\n spineLocator: spine.locator,\n settings,\n navigationResolver,\n }),\n map((params) => params.navigation),\n share(),\n )\n\n const navigationUpdateFollowingUserUnlock$ = navigationFromUser$.pipe(\n withLatestFrom(isRestorationLocked$),\n filter(([, isUserLocked]) => isUserLocked),\n switchMap(([navigation]) => {\n // @todo emit true/false to keep stream pure\n const unlock = this.locker.lock()\n\n return isRestorationLocked$.pipe(\n filter((isUserLocked) => !isUserLocked),\n first(),\n map(\n (): InternalNavigationEntry => ({\n ...navigation,\n animation: \"snap\" as const,\n }),\n ),\n finalize(() => {\n unlock()\n }),\n takeUntil(navigationFromUser$),\n )\n }),\n share(),\n )\n\n /**\n * Once a layout change happens we want\n * to validate the navigation. Basically we make sure the current navigation\n * is correct for the current layout.\n *\n * @important\n * We want the restoration to happens as fast as possible so it is invisible for the user.\n * Consider the scenario where an item load / unload and create a shift, we want\n * the user to be restored instantly.\n *\n * This means that if a layout happens during navigation, we will cut it and navigate\n * directly to new position. NO layout should happens during viewport busy.\n * This is responsibility of other components.\n */\n const navigationUpdateFromLayout$ = merge(\n controlledNavigationController.layout$,\n spine.layout$,\n ).pipe(\n switchMap(() => {\n return of(null).pipe(\n switchMap(() =>\n isRestorationLocked$.pipe(\n filter((isLocked) => !isLocked),\n first(),\n ),\n ),\n map(\n (): InternalNavigationEntry => ({\n ...this.navigationSubject.getValue(),\n animation: false,\n }),\n ),\n /**\n * We need to cancel the restoration as soon as there is\n * another navigation. Whether it's user or internal, it means\n * it has been controlled outside.\n */\n takeUntil(\n merge(navigationUpdateFollowingUserUnlock$, navigationFromUser$),\n ),\n )\n }),\n )\n\n const navigationRestored$ = merge(\n navigationUpdateFromLayout$,\n navigationUpdateFollowingUserUnlock$,\n ).pipe(\n map((navigation) => ({ navigation })),\n withRestoredPosition({\n navigationResolver,\n settings,\n context,\n spine,\n }),\n map((params) => {\n const navigation: InternalNavigationEntry = {\n ...params.navigation,\n meta: {\n triggeredBy: `restoration`,\n },\n }\n\n return {\n ...params,\n navigation,\n }\n }),\n /**\n * The spine item may be undefined after a restoration.\n * eg: after the reader load and the user has never navigated\n * yet.\n */\n withSpineItem({\n context,\n navigationResolver,\n settings,\n spineItemsManager: spine.spineItemsManager,\n spineLocator: spine.locator,\n }),\n withSpineItemLayoutInfo({\n spine,\n }),\n withSpineItemPosition({\n spineItemsManager: spine.spineItemsManager,\n spineLocator: spine.locator,\n settings,\n navigationResolver,\n }),\n map(({ navigation }) => navigation),\n share(),\n )\n\n // @todo export\n // @todo we should only update the cfi if the content of the\n // item change, because otherwise every time the viewport get bigger\n // the pagination cfi will change and thus this one too, indefinitely\n // pulling the user back since we always use the first visible node\n const navigationUpdateOnPaginationUpdate$ = consolidateWithPagination(\n context,\n this.navigationSubject,\n spine,\n )\n\n const navigationUpdate$ = merge(\n navigationRestored$,\n navigationFromUser$,\n navigationUpdateOnPaginationUpdate$,\n )\n\n const notifyNavigationUpdate = (\n stream: Observable<[InternalNavigationEntry, InternalNavigationEntry]>,\n ) =>\n stream.pipe(\n tap(([currentNavigation, previousNavigation]) => {\n report.info(\n `navigation updated from ${currentNavigation.meta.triggeredBy} of type ${currentNavigation.type}`,\n {\n previousNavigation,\n currentNavigation,\n },\n )\n\n this.navigationSubject.next(currentNavigation)\n }),\n )\n\n const navigateViewport = (\n stream: Observable<[InternalNavigationEntry, InternalNavigationEntry]>,\n ) =>\n stream.pipe(\n tap(([currentNavigation, previousNavigation]) => {\n const isScrollFromUser = currentNavigation.type === `scroll`\n const isPaginationUpdate =\n currentNavigation.meta.triggeredBy === \"pagination\"\n const isRestoration =\n currentNavigation.meta.triggeredBy === \"restoration\"\n const positionIsSame = isShallowEqual(\n previousNavigation.position,\n currentNavigation.position,\n )\n\n if (\n (isScrollFromUser && !isRestoration) ||\n isPaginationUpdate ||\n positionIsSame\n )\n return\n\n const navigation = {\n position: currentNavigation.position,\n animation: currentNavigation.animation,\n }\n\n if (settings.values.computedPageTurnMode === `scrollable`) {\n this.scrollNavigationController.navigate(navigation)\n } else {\n this.controlledNavigationController.navigate({\n ...navigation,\n /**\n * @important\n * Explicitly trust the unbound position to be valid at this point.\n * Thanks to consolidation and restoration.\n */\n position: SpinePosition.from(navigation.position),\n })\n }\n }),\n )\n\n navigationUpdate$\n .pipe(\n withLatestFrom(this.navigationSubject),\n /**\n * @important\n *\n * We need to start navigating viewport before notifying navigation\n * change, this is to keep viewportState sync and avoid a \"free\" ping\n * in between.\n */\n navigateViewport,\n notifyNavigationUpdate,\n takeUntil(this.destroy$),\n )\n .subscribe()\n }\n\n get navigation() {\n return this.navigationSubject.getValue()\n }\n}\n","export const getItemOffsetFromPageIndex = (\n pageWidth: number,\n pageIndex: number,\n itemWidth: number,\n) => {\n const lastPageOffset = itemWidth - pageWidth\n const logicalOffset = (itemWidth * (pageIndex * pageWidth)) / (itemWidth || 1)\n\n return Math.max(0, Math.min(lastPageOffset, logicalOffset))\n}\n\nexport const calculateNumberOfPagesForItem = (\n itemWidth: number,\n pageWidth: number,\n) => {\n if ((pageWidth || 0) === 0 || (itemWidth || 0) === 0) return 1\n return Math.floor(Math.max(1, itemWidth / pageWidth))\n}\n\nexport const getClosestValidOffsetFromApproximateOffsetInPages = (\n offset: number,\n pageWidth: number,\n itemWidth: number,\n) => {\n const numberOfPages = calculateNumberOfPagesForItem(itemWidth, pageWidth)\n const offsetValues = [...Array(numberOfPages)].map((_, i) => i * pageWidth)\n\n if (offset >= numberOfPages * pageWidth)\n return offsetValues[offsetValues.length - 1] || 0\n\n return (\n offsetValues.find((offsetRange) => offset < offsetRange + pageWidth) || 0\n )\n}\n","export const getPageFromOffset = (\n offset: number,\n pageWidth: number,\n numberOfPages: number,\n) => {\n const offsetValues = [...Array(numberOfPages)].map((_, i) => i * pageWidth)\n\n if (offset <= 0 || numberOfPages === 0) return 0\n\n if (offset >= numberOfPages * pageWidth) return numberOfPages - 1\n\n return (\n offsetValues.findIndex((offsetRange) => offset < offsetRange + pageWidth) ??\n 0\n )\n}\n","import { SpineItemPosition } from \"../types\"\n\nexport const getSafePosition = ({\n itemWidth,\n itemHeight,\n spineItemPosition,\n}: {\n spineItemPosition: SpineItemPosition\n itemWidth: number\n itemHeight: number\n}): SpineItemPosition =>\n new SpineItemPosition({\n x: Math.min(itemWidth, Math.max(0, spineItemPosition.x)),\n y: Math.min(itemHeight, Math.max(0, spineItemPosition.y)),\n })\n","import { calculateNumberOfPagesForItem } from \"../helpers\"\n\nexport const getSpineItemNumberOfPages = ({\n itemHeight,\n itemWidth,\n isUsingVerticalWriting,\n pageWidth,\n pageHeight,\n pageTurnDirection,\n pageTurnMode,\n}: {\n itemWidth: number\n itemHeight: number\n isUsingVerticalWriting: boolean\n pageWidth: number\n pageHeight: number\n pageTurnDirection: \"vertical\" | \"horizontal\"\n pageTurnMode: \"scrollable\" | \"controlled\"\n}) => {\n if (pageTurnDirection === `vertical` && pageTurnMode === `scrollable`) {\n return 1\n }\n\n if (isUsingVerticalWriting || pageTurnDirection === `vertical`) {\n return calculateNumberOfPagesForItem(itemHeight, pageHeight)\n }\n\n return calculateNumberOfPagesForItem(itemWidth, pageWidth)\n}\n","import type { SpineItemPosition } from \"../types\"\nimport { getPageFromOffset } from \"./getPageFromOffset\"\nimport { getSafePosition } from \"./getSafePosition\"\nimport { getSpineItemNumberOfPages } from \"./getSpineItemNumberOfPages\"\n\n/**\n * @important\n * This calculation takes blank page into account, the iframe could be only one page but with a blank page\n * positioned before. Resulting on two page index possible values (0 & 1).\n */\nexport const getSpineItemPageIndexFromSpineItemPosition = ({\n itemWidth,\n itemHeight,\n position,\n isUsingVerticalWriting,\n pageWidth,\n pageHeight,\n pageTurnDirection,\n pageTurnMode,\n isRTL,\n}: {\n itemWidth: number\n itemHeight: number\n position: SpineItemPosition\n isUsingVerticalWriting: boolean\n pageWidth: number\n pageHeight: number\n pageTurnDirection: \"vertical\" | \"horizontal\"\n pageTurnMode: \"scrollable\" | \"controlled\"\n isRTL: boolean\n}) => {\n const safePosition = getSafePosition({\n spineItemPosition: position,\n itemHeight,\n itemWidth,\n })\n\n const offset = safePosition.x\n\n const numberOfPages = getSpineItemNumberOfPages({\n isUsingVerticalWriting,\n itemHeight,\n itemWidth,\n pageWidth,\n pageHeight,\n pageTurnDirection,\n pageTurnMode,\n })\n\n if (isUsingVerticalWriting) {\n return getPageFromOffset(position.y, pageHeight, numberOfPages)\n }\n\n const pageIndex = getPageFromOffset(offset, pageWidth, numberOfPages)\n\n if (isRTL) {\n // Reverse the page index for RTL\n return numberOfPages - 1 - pageIndex\n }\n\n return pageIndex\n}\n","import type { Context } from \"../../context/Context\"\nimport type { Viewport } from \"../../viewport/Viewport\"\nimport { getItemOffsetFromPageIndex } from \"../helpers\"\nimport { SpineItemPosition } from \"../types\"\n\nexport const getSpineItemPositionFromPageIndex = ({\n pageIndex,\n itemLayout,\n context,\n isUsingVerticalWriting,\n viewport,\n}: {\n pageIndex: number\n itemLayout: { width: number; height: number }\n context: Context\n isUsingVerticalWriting: boolean\n viewport: Viewport\n}): SpineItemPosition => {\n if (isUsingVerticalWriting) {\n const ltrRelativeOffset = getItemOffsetFromPageIndex(\n viewport.pageSize.height,\n pageIndex,\n itemLayout.height,\n )\n\n return new SpineItemPosition({\n x: 0,\n y: ltrRelativeOffset,\n })\n }\n\n const ltrRelativeOffset = getItemOffsetFromPageIndex(\n viewport.pageSize.width,\n pageIndex,\n itemLayout.width,\n )\n\n if (context.isRTL()) {\n return new SpineItemPosition({\n x: itemLayout.width - ltrRelativeOffset - viewport.pageSize.width,\n y: 0,\n })\n }\n\n return new SpineItemPosition({\n x: ltrRelativeOffset,\n y: 0,\n })\n}\n","import type { Context } from \"../context/Context\"\nimport type { ReaderSettingsManager } from \"../settings/ReaderSettingsManager\"\nimport { getRangeFromNode } from \"../utils/dom\"\nimport type { Viewport } from \"../viewport/Viewport\"\nimport {\n getClosestValidOffsetFromApproximateOffsetInPages,\n getItemOffsetFromPageIndex,\n} from \"./helpers\"\nimport { getSpineItemPageIndexFromSpineItemPosition } from \"./layout/getSpineItemPageIndexFromSpineItemPosition\"\nimport { getSpineItemPositionFromPageIndex } from \"./layout/getSpineItemPositionFromPageIndex\"\nimport type { SpineItem } from \"./SpineItem\"\nimport { SpineItemPosition, UnboundSpineItemPagePosition } from \"./types\"\n\nexport type SpineItemLocator = ReturnType<typeof createSpineItemLocator>\n\nexport const createSpineItemLocator = ({\n context,\n settings,\n viewport,\n}: {\n context: Context\n settings: ReaderSettingsManager\n viewport: Viewport\n}) => {\n const getSpineItemPositionFromNode = (\n node: Node,\n offset: number,\n spineItem: SpineItem,\n ) => {\n let offsetOfNodeInSpineItem: number | undefined\n\n // for some reason `img` does not work with range (x always = 0)\n if (\n node?.nodeName === `img` ||\n (node?.textContent === `` && node.nodeType === Node.ELEMENT_NODE)\n ) {\n offsetOfNodeInSpineItem = (node as HTMLElement).getBoundingClientRect().x\n } else if (node) {\n const range = node ? getRangeFromNode(node, offset) : undefined\n offsetOfNodeInSpineItem =\n range?.getBoundingClientRect().x || offsetOfNodeInSpineItem\n }\n\n const spineItemWidth = spineItem.layoutInfo?.width || 0\n const pageWidth = viewport.pageSize.width\n\n if (offsetOfNodeInSpineItem !== undefined) {\n const val = getClosestValidOffsetFromApproximateOffsetInPages(\n offsetOfNodeInSpineItem,\n pageWidth,\n spineItemWidth,\n )\n\n // @todo vertical\n return new SpineItemPosition({ x: val, y: 0 })\n }\n\n return undefined\n }\n\n const getSpineItemClosestPositionFromUnsafePosition = (\n unsafePosition: SpineItemPosition,\n spineItem: SpineItem,\n ) => {\n const { width, height } = spineItem.layoutInfo\n\n const adjustedPosition = new SpineItemPosition({\n x: getClosestValidOffsetFromApproximateOffsetInPages(\n unsafePosition.x,\n viewport.pageSize.width,\n width,\n ),\n y: getClosestValidOffsetFromApproximateOffsetInPages(\n unsafePosition.y,\n viewport.pageSize.height,\n height,\n ),\n })\n\n return adjustedPosition\n }\n\n const getSpineItemPageIndexFromNode = (\n node: Node,\n offset: number,\n spineItem: SpineItem,\n ) => {\n const position = getSpineItemPositionFromNode(node, offset, spineItem)\n const { height, width } = spineItem.layoutInfo\n\n return position\n ? getSpineItemPageIndexFromSpineItemPosition({\n isUsingVerticalWriting: !!spineItem.isUsingVerticalWriting(),\n position,\n itemHeight: height,\n itemWidth: width,\n isRTL: context.isRTL(),\n pageWidth: viewport.pageSize.width,\n pageHeight: viewport.pageSize.height,\n pageTurnDirection: settings.values.computedPageTurnDirection,\n pageTurnMode: settings.values.pageTurnMode,\n })\n : undefined\n }\n\n const getSpineItemPagePositionFromSpineItemPosition = (\n position: SpineItemPosition,\n pageIndex: number,\n spineItem: SpineItem,\n ) => {\n const { width, height } = spineItem.layoutInfo\n const pageWidth = viewport.pageSize.width\n const pageHeight = viewport.pageSize.height\n const isUsingVerticalWriting = !!spineItem.isUsingVerticalWriting()\n\n if (isUsingVerticalWriting) {\n // For vertical writing, pages stack vertically\n const pageStartY = getItemOffsetFromPageIndex(\n pageHeight,\n pageIndex,\n height,\n )\n return new UnboundSpineItemPagePosition({\n x: position.x,\n y: position.y - pageStartY,\n })\n }\n\n // For horizontal writing\n const pageStartX = getItemOffsetFromPageIndex(pageWidth, pageIndex, width)\n\n if (context.isRTL()) {\n // For RTL, pages are positioned from right to left\n const rtlPageStartX = width - (pageIndex + 1) * pageWidth\n return new UnboundSpineItemPagePosition({\n x: position.x - Math.max(0, rtlPageStartX),\n y: position.y,\n })\n }\n\n // For LTR, simply subtract the page start position from the absolute position\n return new UnboundSpineItemPagePosition({\n x: position.x - pageStartX,\n y: position.y,\n })\n }\n\n return {\n getSpineItemPositionFromNode,\n getSpineItemPositionFromPageIndex: ({\n pageIndex,\n spineItem,\n }: {\n pageIndex: number\n spineItem: SpineItem\n }) =>\n getSpineItemPositionFromPageIndex({\n context,\n isUsingVerticalWriting: !!spineItem.isUsingVerticalWriting(),\n itemLayout: spineItem.layoutInfo,\n pageIndex,\n viewport,\n }),\n getSpineItemPageIndexFromPosition: (params: {\n position: SpineItemPosition\n isUsingVerticalWriting: boolean\n itemWidth: number\n itemHeight: number\n }) =>\n getSpineItemPageIndexFromSpineItemPosition({\n ...params,\n isRTL: context.isRTL(),\n pageWidth: viewport.pageSize.width,\n pageHeight: viewport.pageSize.height,\n pageTurnDirection: settings.values.computedPageTurnDirection,\n pageTurnMode: settings.values.pageTurnMode,\n }),\n getSpineItemPageIndexFromNode,\n getSpineItemClosestPositionFromUnsafePosition,\n getSpineItemPagePositionFromSpineItemPosition,\n }\n}\n","import type { Context } from \"../context/Context\"\nimport type { ReaderSettingsManager } from \"../settings/ReaderSettingsManager\"\nimport type { Viewport } from \"../viewport/Viewport\"\nimport { createSpineItemLocator } from \"./locationResolver\"\nimport type { SpineItem } from \"./SpineItem\"\nimport { SpineItemPosition } from \"./types\"\n\nexport type SpineItemNavigationResolver = ReturnType<\n typeof createNavigationResolver\n>\n\nexport const createNavigationResolver = ({\n context,\n settings,\n viewport,\n}: {\n context: Context\n settings: ReaderSettingsManager\n viewport: Viewport\n}) => {\n const spineItemLocator = createSpineItemLocator({\n context,\n settings,\n viewport,\n })\n\n const getNavigationForLastPage = (spineItem: SpineItem) => {\n const numberOfPages = spineItem.numberOfPages\n\n return spineItemLocator.getSpineItemPositionFromPageIndex({\n pageIndex: numberOfPages - 1,\n spineItem,\n })\n }\n\n const getNavigationFromNode = (\n spineItem: SpineItem,\n node: Node,\n offset: number,\n ): SpineItemPosition => {\n const position = spineItemLocator.getSpineItemPositionFromNode(\n node,\n offset,\n spineItem,\n )\n\n return position || new SpineItemPosition({ x: 0, y: 0 })\n }\n\n const getNavigationForPosition = (\n spineItem: SpineItem,\n position: SpineItemPosition,\n ): SpineItemPosition => {\n const potentiallyCorrectedPosition =\n spineItemLocator.getSpineItemClosestPositionFromUnsafePosition(\n position,\n spineItem,\n )\n\n return potentiallyCorrectedPosition\n }\n\n return {\n getNavigationForLastPage,\n getNavigationForPosition,\n getNavigationFromNode,\n }\n}\n","import type { Spine } from \"../../spine/Spine\"\nimport type { SpineItemsManager } from \"../../spine/SpineItemsManager\"\nimport { SpinePosition, type UnboundSpinePosition } from \"../../spine/types\"\n\nexport const NAMESPACE = `spineNavigator`\n\ntype SharedParams = {\n isRTL: boolean\n spineItemsManager: SpineItemsManager\n spine: Spine\n viewportWidth: number\n}\n\nexport function fromOutOfBoundsSpinePosition(\n params: SharedParams & {\n position: SpinePosition\n },\n): SpinePosition\n\nexport function fromOutOfBoundsSpinePosition(\n params: SharedParams & {\n position: UnboundSpinePosition\n },\n): UnboundSpinePosition\n\nexport function fromOutOfBoundsSpinePosition(\n params: SharedParams & {\n position: UnboundSpinePosition | SpinePosition\n },\n): UnboundSpinePosition | SpinePosition\n\n/**\n * Only make sure x/y are not out of the bounds of the spine.\n */\nexport function fromOutOfBoundsSpinePosition({\n position,\n isRTL,\n spineItemsManager,\n spine,\n viewportWidth,\n}: SharedParams & {\n position: SpinePosition | UnboundSpinePosition\n}): SpinePosition | UnboundSpinePosition {\n // @todo use container width instead to increase performances\n const lastSpineItem = spineItemsManager.get(\n spineItemsManager.items.length - 1,\n )\n const distanceOfLastSpineItem = spine.getSpineItemSpineLayoutInfo(\n lastSpineItem || 0,\n )\n\n // fallback on last element (before last pixel)\n const maximumYOffset = distanceOfLastSpineItem.bottom - 1\n const positiveY = Math.max(0, position.y)\n const y = Math.min(positiveY, maximumYOffset)\n\n /**\n * For RTL books we move from right to left so negative x.\n * [-x, 0]\n */\n if (isRTL) {\n const maximumX = Math.min(viewportWidth, position.x)\n const minimumX = Math.max(maximumX, distanceOfLastSpineItem.left)\n\n return new SpinePosition({\n x: minimumX,\n y,\n })\n }\n\n // fallback on last element (before last pixel)\n const maximumXOffset = distanceOfLastSpineItem.right - 1\n const positiveX = Math.max(0, position.x)\n const boundedX = Math.min(positiveX, maximumXOffset)\n\n return new SpinePosition({\n x: boundedX,\n y,\n })\n}\n","import type { Spine } from \"../../spine/Spine\"\nimport type { SpineItemsManager } from \"../../spine/SpineItemsManager\"\nimport { SpinePosition, type UnboundSpinePosition } from \"../../spine/types\"\nimport { fromOutOfBoundsSpinePosition } from \"./fromOutOfBoundsSpinePosition\"\n\nexport const NAMESPACE = `spineNavigator`\n\nexport const fromUnboundSpinePosition = ({\n position,\n isRTL,\n pageSizeHeight,\n spineItemsManager,\n visibleAreaRectWidth,\n spine,\n}: {\n position: SpinePosition | UnboundSpinePosition\n isRTL: boolean\n pageSizeHeight: number\n spineItemsManager: SpineItemsManager\n visibleAreaRectWidth: number\n spine: Spine\n}) => {\n const unboundPosition = fromOutOfBoundsSpinePosition({\n position,\n isRTL,\n spineItemsManager,\n spine,\n viewportWidth: visibleAreaRectWidth,\n })\n\n // @todo use container width instead to increase performances\n const lastSpineItem = spineItemsManager.get(\n spineItemsManager.items.length - 1,\n )\n const distanceOfLastSpineItem =\n spine.getSpineItemSpineLayoutInfo(lastSpineItem)\n\n const maximumYOffset = distanceOfLastSpineItem.bottom - pageSizeHeight\n const y = Math.min(unboundPosition.y, maximumYOffset)\n\n /**\n * For RTL books we move from right to left so negative x.\n * [-x, 0]\n */\n if (isRTL) {\n const maximumX = Math.min(0, unboundPosition.x)\n\n return new SpinePosition({\n x: maximumX,\n y,\n })\n }\n\n const maximumXOffset = distanceOfLastSpineItem.right - visibleAreaRectWidth\n\n return new SpinePosition({\n x: Math.min(unboundPosition.x, maximumXOffset),\n y,\n })\n}\n","import { SpinePosition, type UnboundSpinePosition } from \"../../spine/types\"\n\nexport const getAdjustedPositionForSpread = ({\n position: { x, y },\n pageSizeWidth,\n visibleAreaRectWidth,\n}: {\n position: SpinePosition | UnboundSpinePosition\n pageSizeWidth: number\n visibleAreaRectWidth: number\n}): SpinePosition => {\n const isOffsetNotAtEdge = x % visibleAreaRectWidth !== 0\n const correctedX = isOffsetNotAtEdge ? x - pageSizeWidth : x\n\n return new SpinePosition({ x: correctedX, y })\n}\n","import type { SpineLocator } from \"../../spine/locator/SpineLocator\"\nimport { SpinePosition, type UnboundSpinePosition } from \"../../spine/types\"\nimport type { SpineItemNavigationResolver } from \"../../spineItem/navigationResolver\"\nimport type { Viewport } from \"../../viewport/Viewport\"\nimport { getAdjustedPositionForSpread } from \"./getAdjustedPositionForSpread\"\n\nexport const getNavigationForPosition = ({\n viewportPosition,\n spineLocator,\n spineItemNavigationResolver,\n viewport,\n}: {\n viewportPosition: SpinePosition | UnboundSpinePosition\n spineLocator: SpineLocator\n spineItemNavigationResolver: SpineItemNavigationResolver\n viewport: Viewport\n}) => {\n const spineItem = spineLocator.getSpineItemFromPosition(viewportPosition)\n\n if (spineItem) {\n const spineItemPosition =\n spineLocator.getSpineItemPositionFromSpinePosition(\n viewportPosition,\n spineItem,\n )\n\n const spineItemValidPosition =\n spineItemNavigationResolver.getNavigationForPosition(\n spineItem,\n spineItemPosition,\n )\n\n const viewportNavigation =\n spineLocator.getSpinePositionFromSpineItemPosition({\n spineItemPosition: spineItemValidPosition,\n spineItem,\n })\n\n return getAdjustedPositionForSpread({\n position: viewportNavigation,\n pageSizeWidth: viewport.pageSize.width,\n visibleAreaRectWidth: viewport.absoluteViewport.width,\n })\n }\n\n return new SpinePosition({ x: 0, y: 0 })\n}\n","import type { SpineLocator } from \"../../spine/locator/SpineLocator\"\nimport type { SpineItemsManager } from \"../../spine/SpineItemsManager\"\nimport { SpinePosition } from \"../../spine/types\"\nimport type { SpineItemNavigationResolver } from \"../../spineItem/navigationResolver\"\nimport type { SpineItem } from \"../../spineItem/SpineItem\"\nimport type { Viewport } from \"../../viewport/Viewport\"\nimport { getAdjustedPositionForSpread } from \"./getAdjustedPositionForSpread\"\nimport { getNavigationForPosition } from \"./getNavigationForPosition\"\n\nexport const getNavigationForSpineItemPage = ({\n pageIndex,\n spineItemsManager,\n spineItemId,\n spineLocator,\n spineItemNavigationResolver,\n viewport,\n}: {\n pageIndex: number\n spineItemId: SpineItem | number | string\n spineItemsManager: SpineItemsManager\n spineItemNavigationResolver: SpineItemNavigationResolver\n spineLocator: SpineLocator\n viewport: Viewport\n}): SpinePosition => {\n const spineItem = spineItemsManager.get(spineItemId)\n\n // lookup for entire book\n // This is reliable for pre-paginated, do not use it for reflowable book\n if (!spineItem) {\n const xPositionForPageIndex = pageIndex * viewport.pageSize.width\n return getNavigationForPosition({\n viewportPosition: new SpinePosition({ x: xPositionForPageIndex, y: 0 }),\n spineItemNavigationResolver,\n spineLocator,\n viewport,\n })\n }\n\n const spineItemNavigation =\n spineLocator.spineItemLocator.getSpineItemPositionFromPageIndex({\n pageIndex,\n spineItem,\n })\n\n const readingOffset = spineLocator.getSpinePositionFromSpineItemPosition({\n spineItemPosition: spineItemNavigation,\n spineItem,\n })\n\n return getAdjustedPositionForSpread({\n position: readingOffset,\n pageSizeWidth: viewport.pageSize.width,\n visibleAreaRectWidth: viewport.absoluteViewport.width,\n })\n}\n","import type { Context } from \"../../context/Context\"\nimport type { SpineLocator } from \"../../spine/locator/SpineLocator\"\nimport type { Spine } from \"../../spine/Spine\"\nimport type { SpineItemsManager } from \"../../spine/SpineItemsManager\"\nimport type { SpinePosition } from \"../../spine/types\"\nimport type { SpineItem } from \"../../spineItem/SpineItem\"\nimport { SpineItemPosition } from \"../../spineItem/types\"\nimport { getAdjustedPositionForSpread } from \"./getAdjustedPositionForSpread\"\n\nconst getNodeFromSelector = (\n selector: string,\n frameElement?: HTMLIFrameElement,\n) => {\n if (frameElement && frameElement instanceof HTMLIFrameElement) {\n if (selector.startsWith(`#`)) {\n return frameElement.contentDocument?.getElementById(\n selector.replace(`#`, ``),\n )\n }\n\n return frameElement.contentDocument?.querySelector(selector)\n }\n}\n\n/**\n * @todo vertical, should returns spine position or something anyway\n */\nconst getSpineItemOffsetFromAnchor = ({\n anchor,\n spineItem,\n spine,\n}: {\n anchor: string\n spineItem: SpineItem\n spine: Spine\n}) => {\n const node = getNodeFromSelector(\n anchor,\n spineItem.renderer.getDocumentFrame(),\n )\n\n if (!node) {\n return 0\n }\n\n return (\n spine.spineItemLocator.getSpineItemPositionFromNode(node, 0, spineItem)\n ?.x ?? 0\n )\n}\n\nconst getSpinePositionFromSpineItemAnchor = ({\n anchor,\n spineItem,\n spineLocator,\n spine,\n}: {\n anchor: string\n spineItem: SpineItem\n spineLocator: SpineLocator\n spine: Spine\n}) => {\n const spineItemOffset = getSpineItemOffsetFromAnchor({\n anchor,\n spineItem,\n spine,\n })\n\n const position = spineLocator.getSpinePositionFromSpineItemPosition({\n spineItemPosition: new SpineItemPosition({ x: spineItemOffset, y: 0 }),\n spineItem,\n })\n\n return position\n}\n\nconst getNavigationForAnchor = ({\n anchor,\n spineItem,\n spineLocator,\n spine,\n pageSizeWidth,\n visibleAreaRectWidth,\n}: {\n anchor: string\n spineItem: SpineItem\n spineLocator: SpineLocator\n spine: Spine\n pageSizeWidth: number\n visibleAreaRectWidth: number\n}) => {\n const position = getSpinePositionFromSpineItemAnchor({\n anchor,\n spineItem,\n spineLocator,\n spine,\n })\n\n return getAdjustedPositionForSpread({\n position,\n pageSizeWidth,\n visibleAreaRectWidth,\n })\n}\n\n/**\n * @todo should be part of enhancer, all the core needs to know to restore navigation\n * is a spine item id AND a node ID.\n */\nexport const getNavigationForUrl = ({\n spine,\n spineItemsManager,\n spineLocator,\n url,\n context,\n pageSizeWidth,\n visibleAreaRectWidth,\n}: {\n url: string | URL\n spineItemsManager: SpineItemsManager\n spineLocator: SpineLocator\n context: Context\n spine: Spine\n pageSizeWidth: number\n visibleAreaRectWidth: number\n}): { position: SpinePosition; spineItemId: string } | undefined => {\n try {\n const validUrl = url instanceof URL ? url : new URL(url)\n const urlWithoutAnchor = `${validUrl.origin}${validUrl.pathname}`\n const existingSpineItem = context.manifest?.spineItems.find(\n (item) => item.href === urlWithoutAnchor,\n )\n\n if (existingSpineItem) {\n const spineItem = spineItemsManager.get(existingSpineItem.id)\n\n if (spineItem) {\n const position = getNavigationForAnchor({\n anchor: validUrl.hash,\n spineItem,\n spine,\n spineLocator,\n pageSizeWidth,\n visibleAreaRectWidth,\n })\n\n return {\n position: getAdjustedPositionForSpread({\n position,\n pageSizeWidth,\n visibleAreaRectWidth,\n }),\n spineItemId: existingSpineItem.id,\n }\n }\n }\n\n return undefined\n } catch (e) {\n console.error(e)\n\n return undefined\n }\n}\n","import type { SpineLocator } from \"../../spine/locator/SpineLocator\"\nimport type { SpineItemLocator } from \"../../spineItem/locationResolver\"\nimport type { SpineItem } from \"../../spineItem/SpineItem\"\nimport type { SpineItemPosition } from \"../../spineItem/types\"\nimport type { Viewport } from \"../../viewport/Viewport\"\nimport { getAdjustedPositionForSpread } from \"./getAdjustedPositionForSpread\"\n\nexport const getNavigationFromSpineItemPosition = ({\n spineItem,\n spineItemPosition,\n spineLocator,\n spineItemLocator,\n viewport,\n}: {\n spineItemPosition: SpineItemPosition\n spineItem: SpineItem\n spineLocator: SpineLocator\n spineItemLocator: SpineItemLocator\n viewport: Viewport\n}) => {\n const navigationInSpineItem =\n spineItemLocator.getSpineItemClosestPositionFromUnsafePosition(\n spineItemPosition,\n spineItem,\n )\n\n const spinePosition = spineLocator.getSpinePositionFromSpineItemPosition({\n spineItemPosition: navigationInSpineItem,\n spineItem,\n })\n\n return getAdjustedPositionForSpread({\n position: spinePosition,\n pageSizeWidth: viewport.pageSize.width,\n visibleAreaRectWidth: viewport.absoluteViewport.width,\n })\n}\n","import { resolveCfi } from \"../../cfi\"\nimport type { Context } from \"../../context/Context\"\nimport { Report } from \"../../report\"\nimport type { ReaderSettingsManager } from \"../../settings/ReaderSettingsManager\"\nimport type { SpineLocator } from \"../../spine/locator/SpineLocator\"\nimport type { Spine } from \"../../spine/Spine\"\nimport type { SpineItemsManager } from \"../../spine/SpineItemsManager\"\nimport { SpinePosition, type UnboundSpinePosition } from \"../../spine/types\"\nimport { createNavigationResolver as createSpineItemNavigator } from \"../../spineItem/navigationResolver\"\nimport type { SpineItem } from \"../../spineItem/SpineItem\"\nimport { SpineItemPosition } from \"../../spineItem/types\"\nimport type { Viewport } from \"../../viewport/Viewport\"\nimport { fromOutOfBoundsSpinePosition } from \"./fromOutOfBoundsSpinePosition\"\nimport { fromUnboundSpinePosition } from \"./fromUnboundSpinePosition\"\nimport { getAdjustedPositionForSpread } from \"./getAdjustedPositionForSpread\"\nimport { getNavigationForPosition } from \"./getNavigationForPosition\"\nimport { getNavigationForSpineItemPage } from \"./getNavigationForSpineItemPage\"\nimport { getNavigationForUrl } from \"./getNavigationForUrl\"\nimport { getNavigationFromSpineItemPosition } from \"./getNavigationFromSpineItemPosition\"\n\nexport const NAMESPACE = `spineNavigator`\n\nexport type NavigationResolver = ReturnType<typeof createNavigationResolver>\n\nexport const createNavigationResolver = ({\n context,\n spineItemsManager,\n locator,\n settings,\n spine,\n viewport,\n}: {\n context: Context\n spineItemsManager: SpineItemsManager\n locator: SpineLocator\n settings: ReaderSettingsManager\n spine: Spine\n viewport: Viewport\n}) => {\n const spineItemNavigator = createSpineItemNavigator({\n context,\n settings,\n viewport,\n })\n\n const arePositionsDifferent = (\n a: { x: number; y: number },\n b: { x: number; y: number },\n ) => a.x !== b.x || a.y !== b.y\n\n const getNavigationForCfi = (cfi: string): SpinePosition | undefined => {\n const spineItem = spineItemsManager.getSpineItemFromCfi(cfi)\n const { node, offset = 0 } = resolveCfi({\n cfi,\n spineItemsManager,\n })\n\n if (!spineItem) {\n Report.warn(NAMESPACE, `unable to detect item id from cfi ${cfi}`)\n\n return undefined\n }\n\n const spineItemNavigation = node\n ? spineItemNavigator.getNavigationFromNode(spineItem, node, offset)\n : new SpineItemPosition({ x: 0, y: 0 })\n const readingPosition = locator.getSpinePositionFromSpineItemPosition({\n spineItemPosition: spineItemNavigation,\n spineItem,\n })\n\n return getAdjustedPositionForSpread({\n position: readingPosition,\n pageSizeWidth: viewport.pageSize.width,\n visibleAreaRectWidth: viewport.absoluteViewport.width,\n })\n }\n\n const getNavigationForLastPage = (spineItem: SpineItem): SpinePosition => {\n const spineItemNavigation =\n spineItemNavigator.getNavigationForLastPage(spineItem)\n const position = locator.getSpinePositionFromSpineItemPosition({\n spineItemPosition: spineItemNavigation,\n spineItem,\n })\n\n return getAdjustedPositionForSpread({\n position,\n pageSizeWidth: viewport.pageSize.width,\n visibleAreaRectWidth: viewport.absoluteViewport.width,\n })\n }\n\n const getNavigationForSpineIndexOrId = (\n indexOrId: number | string | SpineItem,\n ): SpinePosition => {\n const spineItem = spineItemsManager.get(indexOrId)\n\n if (spineItem) {\n const position = locator.getSpinePositionFromSpineItem(spineItem)\n\n return getAdjustedPositionForSpread({\n position,\n pageSizeWidth: viewport.pageSize.width,\n visibleAreaRectWidth: viewport.absoluteViewport.width,\n })\n }\n\n return new SpinePosition({ x: 0, y: 0 })\n }\n\n /**\n * Useful when you want to get a navigation from a scroll position. It uses trigger points so it will\n * try to get the most visible / relevant element as navigation reference\n */\n const getMostPredominantNavigationForPosition = (\n viewportPosition: SpinePosition,\n ): SpinePosition => {\n const pageTurnDirection = settings.values.computedPageTurnDirection\n // @todo movingForward does not work same with free-scroll, try to find a reliable way to detect\n // const movingForward = navigator.isNavigationGoingForwardFrom(navigation, currentNavigationPosition)\n // const triggerPercentage = movingForward ? 0.7 : 0.3\n const triggerPercentage = 0.5\n const triggerXPosition =\n pageTurnDirection === `horizontal`\n ? viewportPosition.x +\n viewport.absoluteViewport.width * triggerPercentage\n : 0\n const triggerYPosition =\n pageTurnDirection === `horizontal`\n ? 0\n : viewportPosition.y +\n viewport.absoluteViewport.height * triggerPercentage\n const midScreenPositionSafePosition = fromUnboundSpinePosition({\n position: new SpinePosition({\n x: triggerXPosition,\n y: triggerYPosition,\n }),\n isRTL: context.isRTL(),\n pageSizeHeight: viewport.pageSize.height,\n visibleAreaRectWidth: viewport.absoluteViewport.width,\n spineItemsManager,\n spine,\n })\n\n return getNavigationForPosition({\n spineItemNavigationResolver: spineItemNavigator,\n spineLocator: locator,\n viewportPosition: midScreenPositionSafePosition,\n viewport,\n })\n }\n\n const isNavigationGoingForwardFrom = (\n to: SpinePosition,\n from: SpinePosition,\n ) => {\n const pageTurnDirection = settings.values.computedPageTurnDirection\n\n if (pageTurnDirection === `vertical`) {\n return to.y > from.y\n }\n\n return to.x > from.x\n }\n\n return {\n getNavigationForUrl: (url: string | URL) =>\n getNavigationForUrl({\n context,\n spineItemsManager,\n spineLocator: locator,\n url,\n pageSizeWidth: viewport.pageSize.width,\n visibleAreaRectWidth: viewport.absoluteViewport.width,\n spine,\n }),\n getNavigationForSpineItemPage: (\n params: Omit<\n Parameters<typeof getNavigationForSpineItemPage>[0],\n | \"spineItemsManager\"\n | \"spineItemNavigationResolver\"\n | \"spineLocator\"\n | \"viewport\"\n >,\n ) =>\n getNavigationForSpineItemPage({\n ...params,\n spineItemsManager,\n spineItemNavigationResolver: spineItemNavigator,\n spineLocator: locator,\n viewport,\n }),\n getNavigationFromSpineItemPosition: (params: {\n spineItemPosition: SpineItemPosition\n spineItem: SpineItem\n }) =>\n getNavigationFromSpineItemPosition({\n ...params,\n spineItemLocator: locator.spineItemLocator,\n spineLocator: locator,\n viewport,\n }),\n getNavigationForCfi,\n getNavigationForLastPage,\n getNavigationForSpineIndexOrId,\n getNavigationForPosition: (\n viewportPosition: SpinePosition | UnboundSpinePosition,\n ) =>\n getNavigationForPosition({\n viewportPosition,\n spineItemNavigationResolver: spineItemNavigator,\n spineLocator: locator,\n viewport,\n }),\n getMostPredominantNavigationForPosition,\n fromUnboundSpinePosition: (\n position: SpinePosition | UnboundSpinePosition,\n ) =>\n fromUnboundSpinePosition({\n position,\n isRTL: context.isRTL(),\n pageSizeHeight: viewport.pageSize.height,\n visibleAreaRectWidth: viewport.absoluteViewport.width,\n spineItemsManager,\n spine,\n }),\n fromOutOfBoundsSpinePosition: (\n position: SpinePosition | UnboundSpinePosition,\n ) =>\n fromOutOfBoundsSpinePosition({\n position,\n isRTL: context.isRTL(),\n spineItemsManager,\n spine,\n viewportWidth: viewport.absoluteViewport.width,\n }),\n isNavigationGoingForwardFrom,\n arePositionsDifferent,\n getAdjustedPositionForSpread: (\n position: SpinePosition | UnboundSpinePosition,\n ) =>\n getAdjustedPositionForSpread({\n position,\n pageSizeWidth: viewport.pageSize.width,\n visibleAreaRectWidth: viewport.absoluteViewport.width,\n }),\n spineItemNavigator,\n }\n}\n","import { combineLatest, Subject } from \"rxjs\"\nimport { distinctUntilChanged, map, shareReplay } from \"rxjs/operators\"\nimport type { Context } from \"../context/Context\"\nimport type { HookManager } from \"../hooks/HookManager\"\nimport type { ReaderSettingsManager } from \"../settings/ReaderSettingsManager\"\nimport type { Spine } from \"../spine/Spine\"\nimport type { SpineItemsManager } from \"../spine/SpineItemsManager\"\nimport type { Viewport } from \"../viewport/Viewport\"\nimport { ControlledNavigationController } from \"./controllers/ControlledNavigationController\"\nimport { ScrollNavigationController } from \"./controllers/ScrollNavigationController\"\nimport { InternalNavigator } from \"./InternalNavigator\"\nimport { Locker } from \"./Locker\"\nimport { createNavigationResolver } from \"./resolvers/NavigationResolver\"\nimport type { UserNavigationEntry } from \"./types\"\n\nexport const createNavigator = ({\n spineItemsManager,\n context,\n hookManager,\n spine,\n settings,\n viewport,\n}: {\n spineItemsManager: SpineItemsManager\n context: Context\n hookManager: HookManager\n spine: Spine\n settings: ReaderSettingsManager\n viewport: Viewport\n}) => {\n const userExplicitNavigationSubject = new Subject<UserNavigationEntry>()\n const userNavigation$ = userExplicitNavigationSubject.asObservable()\n /**\n * Allow automatic restoration to happens.\n * - correction of position\n * - restoration of position\n */\n const restorationLocker = new Locker()\n const navigationResolver = createNavigationResolver({\n context,\n settings,\n spineItemsManager,\n locator: spine.locator,\n spine,\n viewport,\n })\n\n const controlledNavigationController = new ControlledNavigationController(\n settings,\n hookManager,\n context,\n spine,\n viewport,\n )\n\n const scrollNavigationController = new ScrollNavigationController(\n viewport,\n settings,\n hookManager,\n spine,\n context,\n )\n\n const internalNavigator = new InternalNavigator(\n settings,\n context,\n userNavigation$,\n controlledNavigationController,\n scrollNavigationController,\n navigationResolver,\n spine,\n restorationLocker.isLocked$,\n )\n\n const navigationState$ = combineLatest([\n controlledNavigationController.isNavigating$,\n scrollNavigationController.isNavigating$,\n restorationLocker.isLocked$,\n internalNavigator.locker.isLocked$,\n ]).pipe(\n map((states) => (states.some((isLocked) => isLocked) ? `busy` : `free`)),\n distinctUntilChanged(),\n shareReplay(1),\n )\n\n const navigate = (to: UserNavigationEntry) => {\n userExplicitNavigationSubject.next(to)\n }\n\n const destroy = () => {\n controlledNavigationController.destroy()\n internalNavigator.destroy()\n }\n\n return {\n destroy,\n getNavigation: () => internalNavigator.navigation,\n internalNavigator,\n scrollNavigationController,\n controlledNavigationController,\n locker: restorationLocker,\n navigationState$,\n navigate,\n /**\n * Prevent further navigation until the lock is released.\n * Useful if you want to start navigation by panning for example.\n */\n lock() {\n return restorationLocker.lock()\n },\n navigationResolver: navigationResolver,\n navigation$: internalNavigator.navigation$,\n }\n}\n\nexport type Navigator = ReturnType<typeof createNavigator>\n","import type { Context } from \"../context/Context\"\nimport type { SpineItemsManager } from \"../spine/SpineItemsManager\"\nimport { ReactiveEntity } from \"../utils/ReactiveEntity\"\nimport type { PaginationInfo } from \"./types\"\n\nexport class Pagination extends ReactiveEntity<PaginationInfo> {\n constructor(\n protected context: Context,\n protected spineItemsManager: SpineItemsManager,\n ) {\n super({\n beginPageIndexInSpineItem: undefined,\n beginNumberOfPagesInSpineItem: 0,\n beginCfi: undefined,\n beginSpineItemIndex: undefined,\n endPageIndexInSpineItem: undefined,\n endNumberOfPagesInSpineItem: 0,\n endCfi: undefined,\n endSpineItemIndex: undefined,\n navigationId: undefined,\n })\n }\n\n public update(pagination: Partial<PaginationInfo>) {\n this.mergeCompare(pagination)\n }\n}\n","import { merge, switchMap, take, takeUntil, tap, withLatestFrom } from \"rxjs\"\nimport { generateCfiForSpineItemPage, generateRootCfi, isRootCfi } from \"../cfi\"\nimport type { Context } from \"../context/Context\"\nimport type { Spine } from \"../spine/Spine\"\nimport type { SpineItemsManager } from \"../spine/SpineItemsManager\"\nimport type { SpinePosition, UnboundSpinePosition } from \"../spine/types\"\nimport type { createSpineItemLocator } from \"../spineItem/locationResolver\"\nimport type { SpineItem } from \"../spineItem/SpineItem\"\nimport { DestroyableClass } from \"../utils/DestroyableClass\"\nimport { waitForSwitch } from \"../utils/rxjs\"\nimport type { Pagination } from \"./Pagination\"\n\nexport class PaginationController extends DestroyableClass {\n constructor(\n protected context: Context,\n protected pagination: Pagination,\n protected spineItemsManager: SpineItemsManager,\n protected spine: Spine,\n protected spineItemLocator: ReturnType<typeof createSpineItemLocator>,\n ) {\n super()\n\n /**\n * Adjust heavier pagination once the navigation and items are updated.\n * This is also cancelled if the layout changes, because the layout will\n * trigger a new navigation adjustment and pagination again.\n *\n * This adjustment is used to update the pagination with the most up to date values we can.\n * It needs to be ran only when viewport is free because some operation such as looking up cfi can\n * be really heavy.\n *\n * The cfi will only be updated if it needs to be:\n * - cfi is a root target\n * - cfi is undefined\n * - items are different\n */\n const updatePagination$ = merge(\n this.context.bridgeEvent.navigation$,\n spine.layout$,\n ).pipe(\n switchMap(() => {\n const getVisiblePagesFromViewportPosition = ({\n spineItem,\n position,\n }: {\n spineItem: SpineItem\n position: SpinePosition | UnboundSpinePosition\n }) =>\n this.spine.locator.getVisiblePagesFromViewportPosition({\n spineItem: spineItem,\n position,\n threshold: { type: \"percentage\", value: 0.5 },\n })\n\n /**\n * @important\n *\n * It's important to soft update pagination immediatly.\n * This will avoid delay in potential user feedbacks (navigation buttons).\n *\n * However we wait for the navigator to be unlocked, this avoid updating the pagination\n * while the user is panning for exemple. We consider a locked navigator as unfinished\n * navigation.\n *\n * Nothing here should be heavier than layout lookup.\n */\n return this.context.bridgeEvent.navigationUnlocked$.pipe(\n take(1),\n withLatestFrom(this.context.bridgeEvent.navigation$),\n tap(([, navigation]) => {\n const { position } = navigation\n const previousPagination = this.pagination.value\n\n const {\n beginIndex: beginSpineItemIndex,\n endIndex: endSpineItemIndex,\n } =\n this.spine.locator.getVisibleSpineItemsFromPosition({\n position,\n threshold: { type: \"percentage\", value: 0.5 },\n }) ?? {}\n\n const beginSpineItem =\n this.spineItemsManager.get(beginSpineItemIndex)\n const endSpineItem = this.spineItemsManager.get(endSpineItemIndex)\n\n if (!beginSpineItem || !endSpineItem) return\n\n const beginLastCfi = previousPagination.beginCfi\n const endLastCfi = previousPagination.endCfi\n\n const { beginPageIndex = 0 } =\n getVisiblePagesFromViewportPosition({\n spineItem: beginSpineItem,\n position,\n }) ?? {}\n\n const { endPageIndex = 0 } =\n getVisiblePagesFromViewportPosition({\n spineItem: endSpineItem,\n position,\n }) ?? {}\n\n const shouldUpdateBeginCfi =\n beginLastCfi === undefined ||\n isRootCfi(beginLastCfi) ||\n previousPagination.beginSpineItemIndex !== beginSpineItemIndex\n\n const shouldUpdateEndCfi =\n previousPagination.endSpineItemIndex !== endSpineItemIndex ||\n endLastCfi === undefined ||\n isRootCfi(endLastCfi)\n\n const beginCfi = shouldUpdateBeginCfi\n ? generateRootCfi(beginSpineItem.item)\n : beginLastCfi\n\n const endCfi = shouldUpdateEndCfi\n ? generateRootCfi(endSpineItem.item)\n : endLastCfi\n\n const beginNumberOfPagesInSpineItem = beginSpineItem.numberOfPages\n\n const endNumberOfPagesInSpineItem = endSpineItem.numberOfPages\n\n this.pagination.update({\n beginCfi,\n beginNumberOfPagesInSpineItem,\n beginPageIndexInSpineItem: beginPageIndex,\n beginSpineItemIndex,\n endCfi,\n endNumberOfPagesInSpineItem,\n endPageIndexInSpineItem: endPageIndex,\n endSpineItemIndex,\n navigationId: navigation.id,\n })\n }),\n )\n }),\n )\n\n /**\n * Heavy operation, needs to be optimized as much as possible.\n *\n * @todo add more optimization, comparing item before, after with position, etc\n */\n const updateCfi$ = updatePagination$.pipe(\n waitForSwitch(this.context.bridgeEvent.viewportFree$),\n tap(() => {\n const {\n beginSpineItemIndex,\n endSpineItemIndex,\n beginPageIndexInSpineItem,\n endPageIndexInSpineItem,\n } = this.pagination.value\n\n if (\n beginPageIndexInSpineItem === undefined ||\n endPageIndexInSpineItem === undefined ||\n beginSpineItemIndex === undefined ||\n endSpineItemIndex === undefined\n )\n return\n\n const beginSpineItem = this.spineItemsManager.get(beginSpineItemIndex)\n const endSpineItem = this.spineItemsManager.get(endSpineItemIndex)\n\n if (beginSpineItem === undefined || endSpineItem === undefined) return\n\n const beginPageEntry = this.spine.pages.fromSpineItemPageIndex(\n beginSpineItem,\n beginPageIndexInSpineItem,\n )\n const endPageEntry = this.spine.pages.fromSpineItemPageIndex(\n endSpineItem,\n endPageIndexInSpineItem,\n )\n\n // @todo only update long cfi if the item layout change but specifically its content\n this.pagination.update({\n beginCfi: beginPageEntry?.firstVisibleNode\n ? generateCfiForSpineItemPage({\n spineItem: beginSpineItem.item,\n pageNode: beginPageEntry?.firstVisibleNode,\n })\n : generateRootCfi(beginSpineItem.item),\n endCfi: endPageEntry?.firstVisibleNode\n ? generateCfiForSpineItemPage({\n spineItem: endSpineItem.item,\n pageNode: endPageEntry?.firstVisibleNode,\n })\n : generateRootCfi(endSpineItem.item),\n })\n }),\n )\n\n merge(updatePagination$, updateCfi$)\n .pipe(takeUntil(this.destroy$))\n .subscribe()\n }\n}\n","import type { Manifest } from \"@prose-reader/shared\"\n\n/**\n * Global spread behavior\n * @see http://idpf.org/epub/fxl/#property-spread\n * @todo user setting\n */\nexport const computeSpreadMode = ({\n manifest,\n spreadMode,\n}: {\n spreadMode: boolean\n manifest?: Manifest\n}) => {\n /**\n * For now we don't support spread for reflowable & scrollable content since\n * two items could have different height, resulting in weird stuff.\n */\n if (manifest?.renditionFlow === `scrolled-continuous`) return false\n\n return spreadMode\n}\n","import { isShallowEqual, shallowMergeIfDefined } from \"@prose-reader/shared\"\nimport {\n distinctUntilChanged,\n type Observable,\n Subject,\n shareReplay,\n} from \"rxjs\"\nimport { DestroyableClass } from \"../utils/DestroyableClass\"\nimport { mapKeysTo } from \"../utils/rxjs\"\nimport type { SettingsInterface } from \"./SettingsInterface\"\n\nexport abstract class SettingsManager<\n InputSettings extends object,\n OutputSettings extends Record<string, unknown>,\n >\n extends DestroyableClass\n implements SettingsInterface<InputSettings, OutputSettings>\n{\n protected inputSettings: InputSettings\n protected outputSettings?: OutputSettings\n protected outputSettingsUpdateSubject: Subject<OutputSettings>\n\n public _settings$: Observable<OutputSettings>\n\n constructor(initialSettings: Partial<InputSettings>) {\n super()\n\n const settingsWithDefaults: InputSettings = {\n ...this.getDefaultSettings(),\n ...initialSettings,\n }\n\n this.inputSettings = settingsWithDefaults\n this.outputSettingsUpdateSubject = new Subject()\n\n this._settings$ = this.outputSettingsUpdateSubject\n .asObservable()\n .pipe(shareReplay(1))\n\n this._settings$.subscribe()\n }\n\n _prepareUpdate(settings: Partial<InputSettings>): {\n hasChanged: boolean\n state: OutputSettings\n commit: () => OutputSettings\n } {\n const newInputSettings = shallowMergeIfDefined(this.inputSettings, settings)\n\n const state = this.getOutputSettings(newInputSettings)\n\n const hasChanged = !isShallowEqual(this.outputSettings, state)\n\n return {\n hasChanged: hasChanged,\n state,\n commit: () => {\n this.inputSettings = newInputSettings\n this.outputSettings = state\n\n if (hasChanged) {\n this.outputSettingsUpdateSubject.next(state)\n }\n\n return state\n },\n }\n }\n\n abstract getOutputSettings(inputSettings: InputSettings): OutputSettings\n\n abstract getDefaultSettings(): InputSettings\n\n public update(settings: Partial<InputSettings>) {\n const { commit } = this._prepareUpdate(settings)\n\n commit()\n }\n\n get values() {\n if (!this.outputSettings) {\n const { commit } = this._prepareUpdate(this.inputSettings)\n\n return commit()\n }\n\n return this.outputSettings\n }\n\n get values$() {\n if (!this.outputSettings) {\n const { commit } = this._prepareUpdate(this.inputSettings)\n\n commit()\n }\n\n return this._settings$\n }\n\n public watch<K extends keyof OutputSettings>(keys: K[]) {\n return this.values$.pipe(\n mapKeysTo(keys),\n distinctUntilChanged(isShallowEqual),\n )\n }\n\n public destroy() {\n super.destroy()\n this.outputSettingsUpdateSubject.complete()\n }\n}\n","import { takeUntil, tap } from \"rxjs\"\nimport type { Context } from \"../context/Context\"\nimport { Report } from \"../report\"\nimport { computeSpreadMode } from \"./computeSpreadMode\"\nimport type { SettingsInterface } from \"./SettingsInterface\"\nimport { SettingsManager } from \"./SettingsManager\"\nimport type {\n ComputedCoreSettings,\n CoreInputSettings,\n CoreOutputSettings,\n} from \"./types\"\n\n/**\n * @important If a settings needs to be derived from a sub component, it needs to live next to the said\n * component or pushed back into the context.\n */\nexport class ReaderSettingsManager\n extends SettingsManager<CoreInputSettings, CoreOutputSettings>\n implements SettingsInterface<CoreInputSettings, CoreOutputSettings>\n{\n constructor(\n initialSettings: Partial<CoreInputSettings>,\n protected context: Context,\n ) {\n super(initialSettings)\n\n context\n .watch([\"manifest\", \"hasVerticalWriting\"])\n .pipe(\n tap(() => this.update(this.values)),\n takeUntil(this.destroy$),\n )\n .subscribe()\n }\n\n private getComputedSettings(\n settings: CoreInputSettings,\n ): ComputedCoreSettings {\n const manifest = this.context.manifest\n const hasVerticalWriting = this.context.value.hasVerticalWriting ?? false\n const computedSettings: ComputedCoreSettings = {\n computedPageTurnDirection: settings.pageTurnDirection,\n computedPageTurnAnimation: settings.pageTurnAnimation,\n computedPageTurnMode: settings.pageTurnMode,\n computedPageTurnAnimationDuration: 0,\n computedSpreadMode: computeSpreadMode({\n spreadMode: settings.spreadMode,\n manifest,\n }),\n }\n\n // We force scroll mode for some books\n if (manifest?.renditionFlow === `scrolled-continuous`) {\n computedSettings.computedPageTurnMode = `scrollable`\n }\n\n if (computedSettings.computedPageTurnMode === \"scrollable\") {\n computedSettings.computedPageTurnDirection = `vertical`\n }\n\n // some settings are not available for vertical writing\n if (\n hasVerticalWriting &&\n computedSettings.computedPageTurnAnimation === `slide`\n ) {\n Report.warn(\n `pageTurnAnimation ${computedSettings.computedPageTurnAnimation} incompatible with current book, switching back to default`,\n )\n computedSettings.computedPageTurnAnimation = `none`\n }\n\n // for now we only support animation none for scrollable\n if (computedSettings.computedPageTurnMode === `scrollable`) {\n computedSettings.computedPageTurnAnimationDuration = 0\n computedSettings.computedPageTurnAnimation = `none`\n } else {\n computedSettings.computedPageTurnAnimationDuration =\n settings.pageTurnAnimationDuration !== undefined\n ? settings.pageTurnAnimationDuration\n : 300\n }\n\n return computedSettings\n }\n\n getOutputSettings(\n inputSettings: CoreInputSettings,\n ): CoreInputSettings & ComputedCoreSettings {\n const computedSettings = this.getComputedSettings(inputSettings)\n\n return { ...this.outputSettings, ...inputSettings, ...computedSettings }\n }\n\n getDefaultSettings() {\n return {\n spreadMode: false,\n pageTurnAnimation: `slide`,\n pageTurnDirection: `horizontal` as const,\n pageTurnAnimationDuration: undefined,\n pageTurnMode: `controlled` as const,\n snapAnimationDuration: 300,\n navigationSnapThreshold: { type: \"pixels\", value: 40 },\n numberOfAdjacentSpineItemToPreLoad: 3,\n } satisfies CoreInputSettings\n }\n}\n","import { EMPTY, of } from \"rxjs\"\nimport { DocumentRenderer } from \"./DocumentRenderer\"\n\nexport class DefaultRenderer extends DocumentRenderer {\n onUnload() {\n return EMPTY\n }\n\n onCreateDocument() {\n return of(document.createElement(\"div\"))\n }\n\n onLoadDocument() {\n return EMPTY\n }\n\n onLayout() {\n return of(undefined)\n }\n\n onRenderHeadless() {\n return EMPTY\n }\n\n getDocumentFrame() {\n return undefined\n }\n}\n","import { isShallowEqual, type Manifest } from \"@prose-reader/shared\"\nimport {\n filter,\n first,\n map,\n merge,\n type Observable,\n type ObservedValueOf,\n of,\n Subject,\n share,\n switchMap,\n} from \"rxjs\"\nimport type { Context } from \"../context/Context\"\nimport type { HookManager } from \"../hooks/HookManager\"\nimport { isFullyPrePaginated } from \"../manifest/isFullyPrePaginated\"\nimport type { ReaderSettingsManager } from \"../settings/ReaderSettingsManager\"\nimport { DestroyableClass } from \"../utils/DestroyableClass\"\nimport { deferNextResult } from \"../utils/rxjs\"\nimport type { Viewport } from \"../viewport/Viewport\"\nimport type { DocumentRenderer } from \"./renderer/DocumentRenderer\"\n\nexport class SpineItemLayout extends DestroyableClass {\n private layoutTriggerSubject = new Subject<{\n spreadPosition: \"left\" | \"right\" | \"none\"\n horizontalOffset: number\n isLastItem: boolean\n edgeX: number\n edgeY: number\n }>()\n\n private lastLayout: {\n width: number\n height: number\n pageSize: { width: number; height: number }\n } | null = null\n\n public readonly didLayout$: Observable<{ width: number; height: number }>\n\n constructor(\n public item: Manifest[`spineItems`][number],\n public containerElement: HTMLElement,\n public context: Context,\n public hookManager: HookManager,\n public renderer: DocumentRenderer,\n public settings: ReaderSettingsManager,\n public viewport: Viewport,\n ) {\n super()\n\n const layoutProcess$ = this.layoutTriggerSubject.pipe(\n switchMap(\n ({ spreadPosition, horizontalOffset, isLastItem, edgeX, edgeY }) => {\n const { blankPagePosition, minimumWidth } =\n this.computeLayoutInformation({ horizontalOffset, isLastItem })\n\n this.hookManager.execute(`item.onBeforeLayout`, undefined, {\n blankPagePosition,\n item: this.item,\n minimumWidth,\n })\n\n const rendererLayout$ = this.renderer.layout({\n blankPagePosition,\n minPageSpread: minimumWidth / this.viewport.pageSize.width,\n minimumWidth,\n spreadPosition,\n })\n\n return merge(\n of({ type: \"start\" } as const),\n rendererLayout$.pipe(\n /**\n * Now that inner layout is done from the renderer, we adjust the dimensions\n * of the outer container element\n */\n this.updateContainerLayout({\n minimumWidth,\n edgeX,\n edgeY,\n }),\n map((data) => {\n this.hookManager.execute(`item.onAfterLayout`, undefined, {\n blankPagePosition,\n item: this.item,\n minimumWidth,\n })\n\n return {\n type: \"end\",\n data,\n } as const\n }),\n ),\n )\n },\n ),\n share(),\n )\n\n this.didLayout$ = layoutProcess$.pipe(\n filter((event) => event.type === `end`),\n map((event) => event.data),\n share(),\n )\n }\n\n private validateDimension(\n value: number,\n pageSize: number,\n minimum: number,\n ): number {\n if (value <= 0) return minimum\n\n const maxValue = Math.max(value, minimum)\n\n // Check if value is a multiple of page size\n const multiplier = Math.ceil(maxValue / pageSize)\n const adjustedValue = multiplier * pageSize\n\n // Ensure the value meets minimum requirement\n return Math.max(adjustedValue, pageSize)\n }\n\n private computeLayoutInformation = ({\n isLastItem,\n horizontalOffset,\n }: {\n isLastItem: boolean\n horizontalOffset: number\n }) => {\n let minimumWidth = this.viewport.value.pageSize.width\n let blankPagePosition: `none` | `before` | `after` = `none`\n const isScreenStartItem =\n horizontalOffset % this.viewport.absoluteViewport.width === 0\n const manifest = this.context.manifest\n const isGloballyPrePaginated = isFullyPrePaginated(manifest) ?? false\n\n if (this.settings.values.computedSpreadMode) {\n /**\n * for now every reflowable content that has reflow siblings takes the entire screen by default\n * this simplify many things and I am not sure the specs allow one reflow\n * to end and an other one to start on the same screen anyway\n *\n * @important\n * For now this is impossible to have reflow not taking all screen. This is because\n * when an element is unloaded, the next element will move back its x axis, then an adjustment\n * will occurs and the previous element will become visible again, meaning it will be loaded,\n * therefore pushing the focused element, meaning adjustment again, then unload of previous one,\n * ... infinite loop. Due to the nature of reflow it's pretty much impossible to not load the entire\n * book with spread on to make it work.\n *\n * @important\n * When the book is globally pre-paginated we will not apply any of this even if each item is\n * reflowable. This is mostly a publisher mistake but does not comply with spec. Therefore\n * we ignore it\n */\n if (\n !isGloballyPrePaginated &&\n this.renderer.renditionLayout === `reflowable` &&\n !isLastItem\n ) {\n minimumWidth = this.viewport.value.pageSize.width * 2\n }\n\n // mainly to make loading screen looks good\n if (\n !isGloballyPrePaginated &&\n this.renderer.renditionLayout === `reflowable` &&\n isLastItem &&\n isScreenStartItem\n ) {\n minimumWidth = this.viewport.value.pageSize.width * 2\n }\n\n const lastItemStartOnNewScreenInAPrepaginatedBook =\n isScreenStartItem && isLastItem && isGloballyPrePaginated\n\n if (\n this.item.pageSpreadRight &&\n isScreenStartItem &&\n !this.context.isRTL()\n ) {\n blankPagePosition = `before`\n minimumWidth = this.viewport.value.pageSize.width * 2\n } else if (\n this.item.pageSpreadLeft &&\n isScreenStartItem &&\n this.context.isRTL()\n ) {\n blankPagePosition = `before`\n minimumWidth = this.viewport.value.pageSize.width * 2\n } else if (lastItemStartOnNewScreenInAPrepaginatedBook) {\n if (this.context.isRTL()) {\n blankPagePosition = `before`\n } else {\n blankPagePosition = `after`\n }\n\n minimumWidth = this.viewport.value.pageSize.width * 2\n }\n }\n\n return {\n minimumWidth,\n blankPagePosition,\n }\n }\n\n private adjustPositionOfElement = ({\n right,\n left,\n top,\n }: {\n right?: number\n left?: number\n top?: number\n }) => {\n if (right !== undefined) {\n this.containerElement.style.right = `${right}px`\n } else {\n this.containerElement.style.removeProperty(`right`)\n }\n if (left !== undefined) {\n this.containerElement.style.left = `${left}px`\n } else {\n this.containerElement.style.removeProperty(`left`)\n }\n if (top !== undefined) {\n this.containerElement.style.top = `${top}px`\n } else {\n this.containerElement.style.removeProperty(`top`)\n }\n }\n\n private updateContainerLayout =\n ({\n minimumWidth,\n edgeX,\n edgeY,\n }: {\n minimumWidth: number\n edgeX: number\n edgeY: number\n }) =>\n (stream: Observable<{ width: number; height: number } | undefined>) =>\n stream.pipe(\n map((dims) => {\n const trustableLastLayout = isShallowEqual(\n this.lastLayout?.pageSize,\n this.viewport.pageSize,\n )\n ? this.lastLayout\n : undefined\n\n const { width: previousWidth, height: previousHeight } =\n trustableLastLayout ?? {}\n const { width = previousWidth, height = previousHeight } = dims ?? {}\n const { width: pageSizeWidth, height: pageSizeHeight } =\n this.viewport.pageSize\n\n const safeWidth = this.validateDimension(\n width ?? pageSizeWidth,\n pageSizeWidth,\n minimumWidth,\n )\n const safeHeight =\n this.settings.values.computedPageTurnMode === \"scrollable\"\n ? (height ?? pageSizeHeight)\n : this.validateDimension(\n height ?? pageSizeHeight,\n pageSizeHeight,\n pageSizeHeight,\n )\n\n this.lastLayout = {\n width: safeWidth,\n height: safeHeight,\n pageSize: this.viewport.pageSize,\n }\n\n this.containerElement.style.width = `${safeWidth}px`\n this.containerElement.style.height = `${safeHeight}px`\n\n if (this.settings.values.computedPageTurnDirection === `vertical`) {\n this.adjustPositionOfElement({\n top: edgeY,\n left: edgeX,\n })\n\n return { width: safeWidth, height: safeHeight }\n }\n\n // We can now adjust the position of the item if needed based on its new layout.\n // For simplification we use an edge offset, which means for LTR it will be x from left and for RTL\n // it will be x from right\n this.adjustPositionOfElement(\n this.context.isRTL()\n ? { right: edgeX, top: 0 }\n : { left: edgeX, top: 0 },\n )\n\n return { width: safeWidth, height: safeHeight }\n }),\n )\n\n public layout = (\n params: ObservedValueOf<typeof this.layoutTriggerSubject>,\n ) => {\n const nextResult = deferNextResult(this.didLayout$.pipe(first()))\n\n this.layoutTriggerSubject.next(params)\n\n return nextResult()\n }\n\n get layoutInfo() {\n const style = this.containerElement.style\n const width = style.width ? parseFloat(style.width) : 0\n const height = style.height ? parseFloat(style.height) : 0\n\n return {\n width,\n height,\n }\n }\n}\n","import { merge } from \"rxjs\"\nimport { share, takeUntil, tap } from \"rxjs/operators\"\nimport type { Manifest } from \"..\"\nimport type { Context } from \"../context/Context\"\nimport type { HookManager } from \"../hooks/HookManager\"\nimport type { ReaderSettingsManager } from \"../settings/ReaderSettingsManager\"\nimport { ReactiveEntity } from \"../utils/ReactiveEntity\"\nimport type { Viewport } from \"../viewport/Viewport\"\nimport { getSpineItemNumberOfPages } from \"./layout/getSpineItemNumberOfPages\"\nimport { DefaultRenderer } from \"./renderer/DefaultRenderer\"\nimport type { DocumentRenderer } from \"./renderer/DocumentRenderer\"\nimport { ResourceHandler } from \"./resources/ResourceHandler\"\nimport { SpineItemLayout } from \"./SpineItemLayout\"\n\nexport type SpineItemReference = string | SpineItem | number\n\nexport type SpineItemState = {\n isLoaded: boolean\n /**\n * - Content has been loaded\n * - A first layout has been done\n */\n isReady: boolean\n isError: boolean\n error: unknown | undefined\n /**\n * - Layout has been requested\n * - Item layout not done yet\n */\n isDirty: boolean\n}\n\nexport class SpineItem extends ReactiveEntity<SpineItemState> {\n public readonly containerElement: HTMLElement\n public readonly renderer: DocumentRenderer\n public readonly resourcesHandler: ResourceHandler\n\n /**\n * Dispatched once the item has fully did layout. State is also updated before the dispatch.\n * - not dirty\n * - ready (if loaded)\n * - element adjusted\n */\n public readonly didLayout$: SpineItemLayout[\"didLayout$\"]\n\n private readonly _layout: SpineItemLayout\n\n constructor(\n public item: Manifest[`spineItems`][number],\n public parentElement: HTMLElement,\n public context: Context,\n public settings: ReaderSettingsManager,\n public hookManager: HookManager,\n public index: number,\n public viewport: Viewport,\n ) {\n super({\n isLoaded: false,\n isReady: false,\n isDirty: false,\n isError: false,\n error: undefined,\n })\n\n this.containerElement = createContainerElement(\n parentElement,\n item,\n hookManager,\n )\n\n parentElement.appendChild(this.containerElement)\n\n const rendererFactory = this.settings.values.getRenderer?.(item)\n\n this.resourcesHandler = new ResourceHandler(item, this.settings)\n\n const rendererParams = {\n context,\n settings,\n hookManager,\n item,\n containerElement: this.containerElement,\n resourcesHandler: this.resourcesHandler,\n viewport: this.viewport,\n }\n\n this.renderer = rendererFactory\n ? rendererFactory(rendererParams)\n : new DefaultRenderer(rendererParams)\n\n this._layout = new SpineItemLayout(\n item,\n this.containerElement,\n context,\n hookManager,\n this.renderer,\n this.settings,\n this.viewport,\n )\n\n const updateStateOnLoaded$ = this.renderer.state$.pipe(\n tap(({ state, error }) => {\n this.mergeCompare({\n isLoaded: state === \"loaded\",\n isError: state === \"error\",\n error: state === \"error\" ? error : undefined,\n })\n }),\n )\n\n this.didLayout$ = this._layout.didLayout$.pipe(\n tap(() => {\n this.mergeCompare({\n isDirty: false,\n isReady: this.renderer.state$.value.state === \"loaded\",\n })\n }),\n share(),\n )\n\n merge(\n /**\n * @important\n * The order is important here. We want to ensure the state value\n * is set before dispatching the layout event. Elements reacting\n * to layout changes may rely on the state value to be updated.\n */\n updateStateOnLoaded$,\n this.didLayout$,\n )\n .pipe(takeUntil(this.destroy$))\n .subscribe()\n }\n\n load = () => {\n this.renderer.load()\n }\n\n unload = () => {\n this.renderer.unload()\n }\n\n public markDirty = () => {\n this.mergeCompare({\n isDirty: true,\n })\n }\n\n /**\n * Renderer loaded + spine item layout done\n * Will switch back and forth every new layout.\n */\n public get isReady$() {\n return this.watch(`isReady`)\n }\n\n public destroy = () => {\n super.destroy()\n\n this.containerElement.remove()\n this.renderer.destroy()\n }\n\n get element() {\n return this.containerElement\n }\n\n /**\n * @important\n * Do not use this value for layout and navigation. It will be in possible conflict\n * with the global reading direction. A book should not mix them anyway. A page can have\n * a different reading direction for style reason but it should be in theory pre-paginated.\n * For example an english page in a japanese manga. That's expected and will\n * be confined to a single page.\n */\n get readingDirection() {\n return this.renderer.readingDirection\n }\n\n isUsingVerticalWriting = () =>\n !!this.renderer.writingMode?.startsWith(`vertical`)\n\n /**\n * Note that this is dispatched AFTER the state has been updated.\n */\n get loaded$() {\n return this.renderer.loaded$\n }\n\n /**\n * Note that this is dispatched AFTER the state has been updated.\n */\n get unloaded$() {\n return this.renderer.unloaded$\n }\n\n get renditionLayout() {\n return this.renderer.renditionLayout\n }\n\n get layoutInfo() {\n return this._layout.layoutInfo\n }\n\n get numberOfPages() {\n return getSpineItemNumberOfPages({\n isUsingVerticalWriting: !!this.isUsingVerticalWriting(),\n itemHeight: this._layout.layoutInfo.height,\n itemWidth: this._layout.layoutInfo.width,\n pageWidth: this.viewport.pageSize.width,\n pageHeight: this.viewport.pageSize.height,\n pageTurnDirection: this.settings.values.computedPageTurnDirection,\n pageTurnMode: this.settings.values.pageTurnMode,\n })\n }\n\n public layout: SpineItemLayout[\"layout\"] = (params) => {\n return this._layout.layout(params)\n }\n}\n\nconst createContainerElement = (\n containerElement: HTMLElement,\n item: Manifest[`spineItems`][number],\n hookManager: HookManager,\n) => {\n const element: HTMLElement =\n containerElement.ownerDocument.createElement(`div`)\n element.classList.add(`spineItem`)\n element.classList.add(`spineItem-${item.renditionLayout ?? \"reflowable\"}`)\n element.style.cssText = `\n position: absolute;\n overflow: hidden;\n `\n // biome-ignore lint/complexity/useLiteralKeys: TODO\n element.dataset[\"isReady\"] = `false`\n\n hookManager.execute(\"item.onBeforeContainerCreated\", undefined, { element })\n\n return element\n}\n","import { arrayEqual } from \"@prose-reader/shared\"\nimport {\n animationFrameScheduler,\n BehaviorSubject,\n debounceTime,\n distinctUntilChanged,\n map,\n merge,\n shareReplay,\n takeUntil,\n withLatestFrom,\n} from \"rxjs\"\nimport type { Context } from \"../../context/Context\"\nimport type { ReaderSettingsManager } from \"../../settings/ReaderSettingsManager\"\nimport type { SpineItem } from \"../../spineItem/SpineItem\"\nimport { DestroyableClass } from \"../../utils/DestroyableClass\"\nimport { waitForSwitch } from \"../../utils/rxjs\"\nimport type { SpineLocator } from \"../locator/SpineLocator\"\nimport type { SpineItemsManager } from \"../SpineItemsManager\"\nimport type { SpineLayout } from \"../SpineLayout\"\n\nexport class SpineItemsLoader extends DestroyableClass {\n private forcedOpenSubject = new BehaviorSubject<Map<number, number>>(\n new Map(),\n )\n\n constructor(\n protected context: Context,\n protected spineItemsManager: SpineItemsManager,\n protected spineLocator: SpineLocator,\n protected settings: ReaderSettingsManager,\n protected spineLayout: SpineLayout,\n ) {\n super()\n\n const forcedOpen$ = this.forcedOpenSubject.pipe(\n map((v) => Array.from(v.keys()).sort((a, b) => a - b)),\n distinctUntilChanged(arrayEqual),\n shareReplay({ bufferSize: 1, refCount: true }),\n )\n\n const shouldReloadSpineItems$ = merge(\n this.context.bridgeEvent.navigation$,\n this.spineLayout.layout$,\n forcedOpen$,\n settings.watch([\"numberOfAdjacentSpineItemToPreLoad\"]),\n )\n\n /**\n * Loading and unloading content has two important issues that need to be considered\n * - For reflow book it will un-sync the viewport\n * - Loading / unload is CPU intensive.\n *\n * Because of theses two reason we only load/unload when the adjustment is done. This ensure a smooth transition for the second point.\n * For the first point it avoid having content being un-sync while the transition is happening. That way we avoid a new chapter\n * to suddenly being displayed under the transition. The first issue is only a problem for reflow book as paginated will not\n * un-sync the viewport.\n * The flow for the first point is as follow:\n * [navigate] -> [transition] -> [new position] -> [iframe unload/load] -> (eventual adjustment).\n *\n * It would ne nice to be able to load/unload without having to worry about viewport mis-adjustment but due to the current iframe and viewport\n * layout method we have to take it into consideration.\n */\n const loadSpineItems$ = shouldReloadSpineItems$.pipe(\n // this can be changed by whatever we want and SHOULD not break navigation.\n // Ideally loading faster is better but loading too close to user navigating can\n // be dangerous.\n debounceTime(100, animationFrameScheduler),\n waitForSwitch(this.context.bridgeEvent.viewportFree$),\n withLatestFrom(this.context.bridgeEvent.navigation$, forcedOpen$),\n map(([, navigation, forcedOpenIndexes]) => {\n const { numberOfAdjacentSpineItemToPreLoad } = settings.values\n // these are real visible items to load\n const { beginIndex = 0, endIndex = 0 } =\n spineLocator.getVisibleSpineItemsFromPosition({\n position: navigation.position,\n threshold: { type: \"percentage\", value: 0 },\n useAbsoluteViewport: false,\n }) || {}\n\n // we increase the range based on settings\n const beginMaximumIndex =\n numberOfAdjacentSpineItemToPreLoad === Infinity\n ? 0\n : beginIndex - numberOfAdjacentSpineItemToPreLoad\n const endMaximumIndex =\n numberOfAdjacentSpineItemToPreLoad === Infinity\n ? spineItemsManager.items.length - 1\n : endIndex + numberOfAdjacentSpineItemToPreLoad\n\n const visibleIndexes = Array.from(\n { length: endMaximumIndex - beginMaximumIndex + 1 },\n (_, i) => beginMaximumIndex + i,\n )\n\n // we combine with forced open to ensure we load the forced open items\n const indexesToLoad = [...forcedOpenIndexes, ...visibleIndexes]\n\n spineItemsManager.items.forEach((orderedSpineItem, index) => {\n if (indexesToLoad.includes(index)) {\n orderedSpineItem.load()\n } else {\n orderedSpineItem.unload()\n }\n })\n }),\n )\n\n loadSpineItems$.pipe(takeUntil(this.destroy$)).subscribe()\n }\n\n forceOpen(spineItems: (number | SpineItem)[]) {\n const indexes = spineItems.map((item) =>\n typeof item === \"number\" ? item : item.index,\n )\n\n const updateMap = (add: boolean) => {\n const map = this.forcedOpenSubject.value\n indexes.forEach((index) => {\n const count = map.get(index) || 0\n const newCount = add ? count + 1 : count - 1\n if (newCount <= 0) map.delete(index)\n else map.set(index, newCount)\n })\n this.forcedOpenSubject.next(map)\n }\n\n updateMap(true)\n\n return () => {\n if (this.isDestroyed) return\n updateMap(false)\n }\n }\n\n public destroy(): void {\n super.destroy()\n\n this.forcedOpenSubject.complete()\n }\n}\n","import { type SpinePosition, UnboundSpinePosition } from \"../spine/types\"\nimport type { AbsoluteViewport, RelativeViewport } from \"./types\"\n\nexport const translateSpinePositionToRelativeViewport = (\n absolutePosition: SpinePosition | UnboundSpinePosition,\n absoluteViewport: AbsoluteViewport,\n relativeViewport: RelativeViewport | AbsoluteViewport,\n): UnboundSpinePosition => {\n // Calculate the offset needed to center the relative viewport within the absolute viewport\n const offsetX = (relativeViewport.width - absoluteViewport.width) / 2\n const offsetY = (relativeViewport.height - absoluteViewport.height) / 2\n\n return new UnboundSpinePosition({\n x: absolutePosition.x - offsetX,\n y: absolutePosition.y - offsetY,\n })\n}\n","import type { SpinePosition, UnboundSpinePosition } from \"../spine/types\"\n\n/**\n * This correspond to a visible slice of the viewport\n * with its coordinate and size. This is not a navigable position\n * nor a spine position. It could be navigable and could be a valid\n * spine position but its intent is different and usually to deduce\n * visible elements on screen for example.\n *\n * This is mostly useful when the viewport is scaled up / down. If there was\n * no scale this would be the equivalent of spine position + viewport\n *\n * You can also see it as a superposition of a spine position and a viewport creating\n * a new position + its spanning size\n */\nexport class ViewportSlicePosition extends DOMRect {\n public readonly __symbol = Symbol(`ViewportPosition`)\n\n static from(rect: {\n x: number\n y: number\n width: number\n height: number\n }): ViewportSlicePosition\n\n static from(\n position: SpinePosition | UnboundSpinePosition,\n viewport: AbsoluteViewport | RelativeViewport,\n ): ViewportSlicePosition\n\n static from(\n positionOrRect:\n | SpinePosition\n | UnboundSpinePosition\n | { x: number; y: number; width: number; height: number },\n viewport?: AbsoluteViewport | RelativeViewport,\n ): ViewportSlicePosition {\n if (viewport) {\n // Second overload: position and viewport\n const position = positionOrRect as SpinePosition\n return new ViewportSlicePosition(\n position.x,\n position.y,\n viewport.width,\n viewport.height,\n )\n }\n // First overload: rect with x, y, width, height\n const rect = positionOrRect as {\n x: number\n y: number\n width: number\n height: number\n }\n return new ViewportSlicePosition(rect.x, rect.y, rect.width, rect.height)\n }\n}\n\nexport class AbsoluteViewport {\n width: number\n height: number\n\n public readonly __symbol = Symbol(`AbsoluteViewport`)\n\n constructor({ width, height }: { width: number; height: number }) {\n this.width = width\n this.height = height\n }\n}\n\nexport class RelativeViewport {\n width: number\n height: number\n\n public readonly __symbol = Symbol(`RelativeViewport`)\n\n constructor({ width, height }: { width: number; height: number }) {\n this.width = width\n this.height = height\n }\n}\n","import type { Context } from \"../../context/Context\"\nimport type { ReaderSettingsManager } from \"../../settings/ReaderSettingsManager\"\nimport type { SpineItem } from \"../../spineItem/SpineItem\"\nimport type { SpineItemsManager } from \"../SpineItemsManager\"\nimport type { SpineLayout } from \"../SpineLayout\"\n\n/**\n * @deprecated use Pages\n */\nexport const getAbsolutePageIndexFromPageIndex = ({\n pageIndex,\n spineItemOrId,\n spineItemsManager,\n}: {\n pageIndex: number\n spineItemOrId: number | SpineItem | string\n spineLayout: SpineLayout\n spineItemsManager: SpineItemsManager\n context: Context\n settings: ReaderSettingsManager\n}) => {\n const items = spineItemsManager.items\n const spineItem = spineItemsManager.get(spineItemOrId)\n\n if (!spineItem) return undefined\n\n const { currentAbsolutePage } = items.reduce(\n (acc, item) => {\n if (acc.found) return acc\n\n const numberOfPages = item.numberOfPages\n\n if (spineItem === item) {\n if (pageIndex <= numberOfPages - 1) {\n return {\n currentAbsolutePage: acc.currentAbsolutePage + pageIndex,\n found: true,\n }\n }\n }\n\n return {\n ...acc,\n currentAbsolutePage: acc.currentAbsolutePage + numberOfPages,\n }\n },\n { currentAbsolutePage: 0, found: false },\n )\n\n return currentAbsolutePage\n}\n","import type { ViewportSlicePosition } from \"../../viewport/types\"\n\nconst isItemVisibleByThresholdForPosition = ({\n itemHeight,\n itemWidth,\n visibleWidthOfItem,\n visibleHeightOfItem,\n threshold,\n}: {\n itemWidth: number\n visibleWidthOfItem: number\n visibleHeightOfItem: number\n itemHeight: number\n threshold:\n | { type: \"percentage\"; value: number }\n | { type: \"pixels\"; value: number }\n}) => {\n const visibleWidthRatioOfSpineItem = visibleWidthOfItem / itemWidth\n const visibleHeightRatioOfSpineItem = visibleHeightOfItem / itemHeight\n\n const isItemVisibleEnough =\n threshold.type === \"percentage\"\n ? visibleWidthRatioOfSpineItem >= threshold.value &&\n visibleHeightRatioOfSpineItem >= threshold.value\n : visibleWidthOfItem >= threshold.value &&\n visibleHeightOfItem >= threshold.value\n\n return isItemVisibleEnough\n}\n\nconst isItemVisibleOnScreenByThresholdForPosition = ({\n visibleWidthOfItem,\n visibleHeightOfItem,\n threshold,\n viewportPosition,\n}: {\n visibleWidthOfItem: number\n visibleHeightOfItem: number\n threshold:\n | { type: \"percentage\"; value: number }\n | { type: \"pixels\"; value: number }\n viewportPosition: ViewportSlicePosition\n}) => {\n const widthRatioOfSpaceTakenInScreen =\n visibleWidthOfItem / viewportPosition.width\n\n const heightRatioOfSpaceTakenInScreen =\n visibleHeightOfItem / viewportPosition.height\n\n const isItemVisibleEnoughOnScreen =\n threshold.type === \"percentage\"\n ? heightRatioOfSpaceTakenInScreen >= threshold.value &&\n widthRatioOfSpaceTakenInScreen >= threshold.value\n : visibleHeightOfItem >= threshold.value &&\n visibleWidthOfItem >= threshold.value\n\n return isItemVisibleEnoughOnScreen\n}\n\n/**\n * Will check whether a spine item is visible on screen\n * by either:\n *\n * - reach the threshold of visibility on screen\n * - reach the threshold of visibility relative to itself\n *\n * This cover the items that are completely visible on screen\n * but too small to reach the threshold of visibility on screen.\n * (we see them entirely but they are maybe too small on screen).\n *\n * Then will cover items that are cut on screen but we see them enough\n * on the screen to consider them.\n */\nexport const getItemVisibilityForPosition = ({\n itemPosition: {\n bottom,\n left,\n right,\n top,\n width: itemWidth,\n height: itemHeight,\n },\n threshold,\n viewportPosition,\n restrictToScreen,\n}: {\n itemPosition: {\n right: number\n left: number\n bottom: number\n top: number\n height: number\n width: number\n }\n viewportPosition: ViewportSlicePosition\n threshold:\n | { type: \"percentage\"; value: number }\n | { type: \"pixels\"; value: number }\n restrictToScreen?: boolean\n}) => {\n const viewportLeft = viewportPosition.x\n const viewportRight = viewportPosition.x + (viewportPosition.width - 1)\n\n const viewportTop = viewportPosition.y\n const viewportBottom = Math.max(\n viewportPosition.y + (viewportPosition.height - 1),\n 0,\n )\n\n const visibleWidthOfItem = Math.max(\n 0,\n Math.min(right, viewportRight) - Math.max(left, viewportLeft),\n )\n\n const visibleHeightOfItem = Math.max(\n 0,\n Math.min(bottom, viewportBottom) - Math.max(top, viewportTop),\n )\n\n const itemIsOnTheOuterEdge =\n visibleWidthOfItem <= 0 || visibleHeightOfItem <= 0\n\n // const thresholdValidRightEdge = viewportRight - viewportWidth * threshold\n // const thresholdValidLeftEdge = viewportLeft + viewportWidth * threshold\n\n if (itemIsOnTheOuterEdge) return { visible: false }\n\n const isItemVisibleEnoughOnScreen =\n isItemVisibleOnScreenByThresholdForPosition({\n threshold,\n visibleHeightOfItem,\n visibleWidthOfItem,\n viewportPosition,\n })\n\n if (restrictToScreen) {\n return { visible: isItemVisibleEnoughOnScreen }\n }\n\n const isItemVisibleEnough = isItemVisibleByThresholdForPosition({\n itemHeight,\n itemWidth,\n threshold,\n visibleHeightOfItem,\n visibleWidthOfItem,\n })\n\n return {\n visible: isItemVisibleEnough || isItemVisibleEnoughOnScreen,\n }\n}\n","import type { SpineItemsManager } from \"../SpineItemsManager\"\nimport type { SpineLayout } from \"../SpineLayout\"\nimport type { SpinePosition, UnboundSpinePosition } from \"../types\"\n\n/**\n * Returns the first element that is within the given position.\n *\n * This method is safe and take into account boundaries.\n */\nexport const getSpineItemFromPosition = ({\n position,\n spineItemsManager,\n spineLayout,\n}: {\n position: SpinePosition | SpinePosition | UnboundSpinePosition\n spineItemsManager: SpineItemsManager\n spineLayout: SpineLayout\n}) => {\n const spineItem = spineItemsManager.items.find((item) => {\n const { left, right, bottom, top } =\n spineLayout.getSpineItemSpineLayoutInfo(item)\n\n const isWithinXAxis = position.x >= left && position.x < right\n\n const isWithinYAxis = position.y >= top && position.y < bottom\n\n return isWithinXAxis && isWithinYAxis\n })\n\n if (position.x === 0 && !spineItem) {\n return spineItemsManager.items[0]\n }\n\n return spineItem\n}\n","import type { SpineItemPosition } from \"../../spineItem/types\"\nimport { SpinePosition } from \"../types\"\n\n/**\n * Be careful when using with spread with RTL, this will return the position for one page size. This is in order to prevent wrong position when\n * an item is not taking the entire spread. That way we always have a valid position for the given item. However you need to adjust it\n * when on spread mode to be sure to position the viewport on the edge.\n *\n * @example\n * [ item-a | item-a ]\n * 400 200 0\n * will return 200, which probably needs to be adjusted as 0\n */\nexport const getSpinePositionFromSpineItemPosition = ({\n spineItemPosition,\n itemLayout: { left, top },\n}: {\n spineItemPosition: SpineItemPosition\n itemLayout: { left: number; top: number }\n}) => {\n /**\n * For this case the global offset move from right to left but this specific item\n * reads from left to right. This means that when the offset is at the start of the item\n * it is in fact at his end. This behavior can be observed in `haruko` about chapter.\n * @example\n * <---------------------------------------------------- global offset\n * item offset ------------------>\n * [item2 (page0 - page1 - page2)] [item1 (page1 - page0)] [item0 (page0)]\n */\n // if (context.isRTL() && itemReadingDirection === 'ltr') {\n // return (end - spineItemOffset) - context.getPageSize().width\n // }\n\n return new SpinePosition({\n x: left + spineItemPosition.x,\n y: top + spineItemPosition.y,\n })\n}\n","import type { ReaderSettingsManager } from \"../../settings/ReaderSettingsManager\"\nimport type { SpineItem } from \"../../spineItem/SpineItem\"\nimport { translateSpinePositionToRelativeViewport } from \"../../viewport/translateSpinePositionToRelativeViewport\"\nimport { ViewportSlicePosition } from \"../../viewport/types\"\nimport type { Viewport } from \"../../viewport/Viewport\"\nimport type { SpineItemsManager } from \"../SpineItemsManager\"\nimport type { SpineLayout } from \"../SpineLayout\"\nimport type { SpinePosition, UnboundSpinePosition } from \"../types\"\nimport { getItemVisibilityForPosition } from \"./getItemVisibilityForPosition\"\nimport { getSpineItemFromPosition } from \"./getSpineItemFromPosition\"\n\nexport const getVisibleSpineItemsFromPosition = ({\n position,\n threshold,\n restrictToScreen,\n spineItemsManager,\n spineLayout,\n useAbsoluteViewport = true,\n viewport,\n}: {\n position: SpinePosition | UnboundSpinePosition\n threshold:\n | { type: \"percentage\"; value: number }\n | { type: \"pixels\"; value: number }\n restrictToScreen?: boolean\n spineItemsManager: SpineItemsManager\n settings: ReaderSettingsManager\n spineLayout: SpineLayout\n useAbsoluteViewport?: boolean\n viewport: Viewport\n}):\n | {\n beginIndex: number\n endIndex: number\n }\n | undefined => {\n const fallbackSpineItem =\n getSpineItemFromPosition({\n position,\n spineItemsManager,\n spineLayout,\n }) || spineItemsManager.get(0)\n\n const spineItemsVisible = spineItemsManager.items.reduce<SpineItem[]>(\n (acc, spineItem) => {\n const itemPosition = spineLayout.getSpineItemSpineLayoutInfo(spineItem)\n const viewportInfo = useAbsoluteViewport\n ? viewport.absoluteViewport\n : viewport.relativeViewport\n const relativeSpinePosition = translateSpinePositionToRelativeViewport(\n position,\n viewport.absoluteViewport,\n viewportInfo,\n )\n\n const viewportPosition = ViewportSlicePosition.from(\n relativeSpinePosition,\n viewportInfo,\n )\n const { visible } = getItemVisibilityForPosition({\n itemPosition,\n threshold,\n viewportPosition,\n restrictToScreen,\n })\n\n if (visible) {\n return [...acc, spineItem]\n }\n\n return acc\n },\n [],\n )\n\n const beginItem = spineItemsVisible[0] ?? fallbackSpineItem\n const endItem = spineItemsVisible[spineItemsVisible.length - 1] ?? beginItem\n\n if (!beginItem || !endItem) return undefined\n\n const beginItemIndex = spineItemsManager.getSpineItemIndex(beginItem)\n const endItemIndex = spineItemsManager.getSpineItemIndex(endItem)\n\n return {\n beginIndex: beginItemIndex ?? 0,\n endIndex: endItemIndex ?? 0,\n }\n}\n","import type { Context } from \"../../context/Context\"\nimport type { ReaderSettingsManager } from \"../../settings/ReaderSettingsManager\"\nimport type { createSpineItemLocator } from \"../../spineItem/locationResolver\"\nimport type { SpineItem } from \"../../spineItem/SpineItem\"\nimport { SpineItemPosition } from \"../../spineItem/types\"\nimport { translateSpinePositionToRelativeViewport } from \"../../viewport/translateSpinePositionToRelativeViewport\"\nimport { ViewportSlicePosition } from \"../../viewport/types\"\nimport type { Viewport } from \"../../viewport/Viewport\"\nimport type { SpineItemsManager } from \"../SpineItemsManager\"\nimport type { SpineLayout } from \"../SpineLayout\"\nimport type { SpinePosition, UnboundSpinePosition } from \"../types\"\nimport { getAbsolutePageIndexFromPageIndex } from \"./getAbsolutePageIndexFromPageIndex\"\nimport { getItemVisibilityForPosition } from \"./getItemVisibilityForPosition\"\nimport { getSpineItemFromPosition } from \"./getSpineItemFromPosition\"\nimport { getSpinePositionFromSpineItemPosition } from \"./getSpinePositionFromSpineItemPosition\"\nimport { getVisibleSpineItemsFromPosition } from \"./getVisibleSpineItemsFromPosition\"\n\nexport type SpineLocator = ReturnType<typeof createSpineLocator>\n\nexport const createSpineLocator = ({\n spineItemsManager,\n context,\n spineItemLocator,\n settings,\n spineLayout,\n viewport,\n}: {\n spineItemsManager: SpineItemsManager\n context: Context\n spineItemLocator: ReturnType<typeof createSpineItemLocator>\n settings: ReaderSettingsManager\n spineLayout: SpineLayout\n viewport: Viewport\n}) => {\n const getSpineItemPositionFromSpinePosition = (\n position: SpinePosition | UnboundSpinePosition,\n spineItem: SpineItem,\n ): SpineItemPosition => {\n const { left, top } = spineLayout.getSpineItemSpineLayoutInfo(spineItem)\n\n /**\n * For this case the global offset move from right to left but this specific item\n * reads from left to right. This means that when the offset is at the start of the item\n * it is in fact at his end. This behavior can be observed in `haruko` about chapter.\n * @example\n * <---------------------------------------------------- global offset\n * item offset ------------------>\n * [item2 (page0 - page1 - page2)] [item1 (page1 - page0)] [item0 (page0)]\n */\n // if (context.isRTL() && itemReadingDirection === 'ltr') {\n // return (end - readingOrderViewOffset) - context.getPageSize().width\n // }\n\n return new SpineItemPosition({\n /**\n * when using spread the item could be on the right and therefore will be negative\n * @example\n * 400 (position = viewport), page of 200\n * 400 - 600 = -200.\n * However we can assume we are at 0, because we in fact can see the beginning of the item\n */\n x: Math.max(position.x - left, 0),\n y: Math.max(position.y - top, 0),\n })\n }\n\n const getSpinePositionFromSpineItem = (spineItem: SpineItem) => {\n return getSpinePositionFromSpineItemPosition({\n spineItemPosition: new SpineItemPosition({ x: 0, y: 0 }),\n itemLayout: spineLayout.getSpineItemSpineLayoutInfo(spineItem),\n })\n }\n\n const getSpineItemFromIframe = (iframe: Element) => {\n return spineItemsManager.items.find((item) => {\n const element = item.renderer.getDocumentFrame()\n\n return element === iframe\n })\n }\n\n const getSpineItemPageIndexFromNode = (\n node: Node,\n offset: number | undefined,\n spineItemOrIndex: SpineItem | number,\n ) => {\n if (typeof spineItemOrIndex === \"number\") {\n const spineItem = spineItemsManager.get(spineItemOrIndex)\n return spineItem\n ? spineItemLocator.getSpineItemPageIndexFromNode(\n node,\n offset || 0,\n spineItem,\n )\n : undefined\n }\n\n return spineItemLocator.getSpineItemPageIndexFromNode(\n node,\n offset || 0,\n spineItemOrIndex,\n )\n }\n\n const getVisiblePagesFromViewportPosition = ({\n position,\n threshold,\n spineItem,\n restrictToScreen,\n useAbsoluteViewport = true,\n viewport,\n }: {\n position: SpinePosition | UnboundSpinePosition\n threshold:\n | { type: \"percentage\"; value: number }\n | { type: \"pixels\"; value: number }\n spineItem: SpineItem\n restrictToScreen?: boolean\n useAbsoluteViewport?: boolean\n viewport: Viewport\n }):\n | {\n beginPageIndex: number\n endPageIndex: number\n }\n | undefined => {\n const numberOfPages = spineItem.numberOfPages\n\n const pages = Array.from(Array(numberOfPages)).map((_, index) => {\n const spineItemPosition =\n spineItemLocator.getSpineItemPositionFromPageIndex({\n pageIndex: index,\n spineItem,\n })\n\n const spinePosition = getSpinePositionFromSpineItemPosition({\n spineItemPosition,\n itemLayout: spineLayout.getSpineItemSpineLayoutInfo(spineItem),\n })\n\n return {\n index,\n absolutePosition: {\n width: viewport.pageSize.width,\n height: viewport.pageSize.height,\n left: spinePosition.x,\n top: spinePosition.y,\n bottom: spinePosition.y + viewport.pageSize.height,\n right: spinePosition.x + viewport.pageSize.width,\n },\n }\n })\n\n const pagesVisible = pages.reduce<number[]>(\n (acc, { absolutePosition, index }) => {\n const viewportInfo = useAbsoluteViewport\n ? viewport.absoluteViewport\n : viewport.relativeViewport\n\n const relativeSpinePosition = translateSpinePositionToRelativeViewport(\n position,\n viewport.absoluteViewport,\n viewportInfo,\n )\n\n const viewportPosition = ViewportSlicePosition.from(\n relativeSpinePosition,\n viewportInfo,\n )\n\n const { visible } = getItemVisibilityForPosition({\n viewportPosition,\n restrictToScreen,\n threshold,\n itemPosition: absolutePosition,\n })\n\n if (visible) {\n return [...acc, index]\n }\n\n return acc\n },\n [],\n )\n\n const beginPageIndex = pagesVisible[0]\n const endPageIndex = pagesVisible[pagesVisible.length - 1] ?? beginPageIndex\n\n if (beginPageIndex === undefined || endPageIndex === undefined)\n return undefined\n\n return {\n beginPageIndex,\n endPageIndex,\n }\n }\n\n const isPositionWithinSpineItem = (\n position: ViewportSlicePosition | SpinePosition | UnboundSpinePosition,\n spineItem: SpineItem,\n ) => {\n const { bottom, left, right, top } =\n spineLayout.getSpineItemSpineLayoutInfo(spineItem)\n\n return (\n position.x >= left &&\n position.x <= right &&\n position.y <= bottom &&\n position.y >= top\n )\n }\n\n // @todo move into spine item locator\n const getSafeSpineItemPositionFromUnsafeSpineItemPosition = (\n unsafePosition: SpineItemPosition,\n spineItem: SpineItem,\n ): SpineItemPosition => {\n const { height, width } = spineLayout.getSpineItemSpineLayoutInfo(spineItem)\n\n return new SpineItemPosition({\n x: Math.min(Math.max(0, unsafePosition.x), width),\n y: Math.min(Math.max(0, unsafePosition.y), height),\n })\n }\n\n const getSpineItemPagePositionFromSpinePosition = (\n spinePosition: UnboundSpinePosition | SpinePosition,\n ) => {\n const spineItem = getSpineItemFromPosition({\n position: spinePosition,\n spineItemsManager,\n spineLayout,\n })\n\n if (!spineItem) {\n return undefined\n }\n\n const spineItemPosition = getSpineItemPositionFromSpinePosition(\n spinePosition,\n spineItem,\n )\n\n const spineItemPageIndex =\n spineItemLocator.getSpineItemPageIndexFromPosition({\n itemWidth: spineItem.layoutInfo.width,\n itemHeight: spineItem.layoutInfo.height,\n position: spineItemPosition,\n isUsingVerticalWriting: !!spineItem.isUsingVerticalWriting(),\n })\n\n const spineItemPagePosition =\n spineItemLocator.getSpineItemPagePositionFromSpineItemPosition(\n spineItemPosition,\n spineItemPageIndex,\n spineItem,\n )\n\n return {\n spineItem,\n spineItemPageIndex,\n spineItemPagePosition,\n pageSize: viewport.value.pageSize,\n }\n }\n\n return {\n getSpinePositionFromSpineItemPosition: ({\n spineItem,\n spineItemPosition,\n }: {\n spineItemPosition: SpineItemPosition\n spineItem: SpineItem\n }) => {\n const itemLayout = spineLayout.getSpineItemSpineLayoutInfo(spineItem)\n\n return getSpinePositionFromSpineItemPosition({\n itemLayout,\n spineItemPosition,\n })\n },\n /**\n * @deprecated use Pages\n */\n _getAbsolutePageIndexFromPageIndex: (\n params: Omit<\n Parameters<typeof getAbsolutePageIndexFromPageIndex>[0],\n \"context\" | \"settings\" | \"spineLayout\" | \"spineItemsManager\"\n >,\n ) =>\n getAbsolutePageIndexFromPageIndex({\n ...params,\n context,\n settings,\n spineItemsManager,\n spineLayout,\n }),\n getSpineItemPagePositionFromSpinePosition,\n getSpinePositionFromSpineItem,\n getSpineItemPositionFromSpinePosition,\n getSpineItemFromPosition: (\n position: SpinePosition | UnboundSpinePosition,\n ) =>\n getSpineItemFromPosition({\n position,\n spineItemsManager,\n spineLayout,\n }),\n getSpineItemFromIframe,\n getSpineItemPageIndexFromNode,\n getVisibleSpineItemsFromPosition: (\n params: Omit<\n Parameters<typeof getVisibleSpineItemsFromPosition>[0],\n \"spineItemsManager\" | \"settings\" | \"spineLayout\" | \"viewport\"\n >,\n ) =>\n getVisibleSpineItemsFromPosition({\n settings,\n spineItemsManager,\n spineLayout,\n viewport,\n ...params,\n }),\n getVisiblePagesFromViewportPosition: (\n params: Omit<\n Parameters<typeof getVisiblePagesFromViewportPosition>[0],\n \"viewport\"\n >,\n ) =>\n getVisiblePagesFromViewportPosition({\n ...params,\n viewport,\n }),\n isPositionWithinSpineItem,\n spineItemLocator,\n getSafeSpineItemPositionFromUnsafeSpineItemPosition,\n }\n}\n","import { Report as SharedReport } from \"../report\"\n\nexport const Report = SharedReport.namespace(`spine`)\n","import {\n combineLatest,\n map,\n type Observable,\n of,\n share,\n switchMap,\n takeUntil,\n withLatestFrom,\n} from \"rxjs\"\nimport type { Context } from \"../context/Context\"\nimport type { SpineItemLocator } from \"../spineItem/locationResolver\"\nimport type { SpineItem } from \"../spineItem/SpineItem\"\nimport { SpineItemPageLayout } from \"../spineItem/types\"\nimport { getFirstVisibleNodeForPositionRelativeTo } from \"../utils/dom\"\nimport { ReactiveEntity } from \"../utils/ReactiveEntity\"\nimport { idle } from \"../utils/rxjs\"\nimport type { Viewport } from \"../viewport/Viewport\"\nimport type { SpineLocator } from \"./locator/SpineLocator\"\nimport { Report } from \"./report\"\nimport type { SpineItemsManager } from \"./SpineItemsManager\"\nimport type { SpineLayout } from \"./SpineLayout\"\nimport { SpineItemPageSpineLayout, type SpinePosition } from \"./types\"\n\nexport const spinePositionToSpineItemSpineLayout = ({\n position,\n pageSize,\n}: {\n position: SpinePosition\n pageSize: { height: number; width: number }\n}) => {\n return new SpineItemPageSpineLayout({\n ...position,\n left: position.x,\n top: position.y,\n width: pageSize.width,\n height: pageSize.height,\n bottom: position.y + pageSize.height,\n right: position.x + pageSize.width,\n })\n}\n\nexport type PageEntry = {\n absoluteLayout: SpineItemPageSpineLayout\n layout: SpineItemPageLayout\n itemIndex: number\n absolutePageIndex: number\n pageIndex: number\n firstVisibleNode: { node: Node; offset: number } | undefined\n}\n\ntype State = {\n pages: PageEntry[]\n}\n\n/**\n * Hold relevant information about spine pages.\n */\nexport class Pages extends ReactiveEntity<State> {\n public readonly layout$: Observable<State>\n\n constructor(\n public readonly spineLayout: SpineLayout,\n public readonly spineItemsManager: SpineItemsManager,\n public readonly spineItemLocator: SpineItemLocator,\n public readonly context: Context,\n public readonly locator: SpineLocator,\n public readonly viewport: Viewport,\n ) {\n super({ pages: [] })\n\n this.layout$ = spineLayout.layout$.pipe(\n withLatestFrom(viewport),\n switchMap(([, { pageSize }]) => {\n const pages = spineItemsManager.items.reduce(\n (\n acc: (Omit<PageEntry, \"firstVisibleNode\"> & {\n spineItem: SpineItem\n })[],\n spineItem,\n itemIndex,\n ) => {\n const pages = new Array(spineItem.numberOfPages).fill(undefined)\n\n const pagesAbsolutePositions = pages.map((_, pageIndex) => {\n // @todo handle vertical jp\n // top seems ok but left is not, it should probably not be 0 or something\n const pageSpineItemPosition =\n spineItemLocator.getSpineItemPositionFromPageIndex({\n spineItem,\n pageIndex,\n })\n\n const pageSpinePosition =\n locator.getSpinePositionFromSpineItemPosition({\n spineItem,\n spineItemPosition: pageSpineItemPosition,\n })\n\n return {\n absoluteLayout: spinePositionToSpineItemSpineLayout({\n pageSize,\n position: pageSpinePosition,\n }),\n layout: new SpineItemPageLayout({\n left: pageSpineItemPosition.x,\n right: pageSpineItemPosition.x + pageSize.width,\n top: pageSpineItemPosition.y,\n bottom: pageSpineItemPosition.y + pageSize.height,\n width: pageSize.width,\n height: pageSize.height,\n x: pageSpineItemPosition.x,\n y: pageSpineItemPosition.y,\n }),\n itemIndex,\n absolutePageIndex: acc.length + pageIndex,\n spineItem,\n pageIndex,\n }\n })\n\n return [...acc, ...pagesAbsolutePositions]\n },\n [],\n )\n\n const pages$ = combineLatest(\n pages.map((page) => {\n const { spineItem: _unused, ...rest } = page\n\n /**\n * Note that this part adds a significant overhead\n * - lot of rxjs subscribers\n * - overhead of the idle browser task chain\n * - overhead with node finding\n * This is directly tied to the number of items the user loads in parallel\n * and the size of the book.\n * However there are realistically no reason a user would want to load\n * a massive book entirely in parallel.\n */\n if (page.spineItem.value.isLoaded) {\n const frame = page.spineItem.renderer?.getDocumentFrame()\n\n if (\n frame &&\n frame?.contentWindow?.document &&\n frame.contentWindow.document.body !== null\n ) {\n const _document = frame.contentWindow.document\n\n // might need to buffer them to run them all within a single idle task.\n // not sure stacking lot of them like this is a good idea. additionally, maybe we can\n // use something more efficient if its just to ensure 60fps.\n return idle().pipe(\n map(() => {\n const firstVisibleNode =\n getFirstVisibleNodeForPositionRelativeTo(\n _document,\n page.layout,\n )\n\n return {\n ...rest,\n firstVisibleNode,\n }\n }),\n )\n }\n }\n\n // Fast path: No overhead for majority of pages\n return of({ ...rest, firstVisibleNode: undefined })\n }),\n )\n\n return pages$\n }),\n map((pages) => {\n Report.info(`Pages layout`, pages)\n return { pages }\n }),\n share(),\n )\n\n this.layout$.pipe(takeUntil(this.destroy$)).subscribe(this.next.bind(this))\n }\n\n fromSpineItemPageIndex = (spineItem: SpineItem, pageIndex: number) => {\n return this.value.pages.find(\n (page) =>\n page.itemIndex === spineItem.index && page.pageIndex === pageIndex,\n )\n }\n\n fromAbsolutePageIndex = (absolutePageIndex: number) => {\n return this.value.pages.find(\n (page) => page.absolutePageIndex === absolutePageIndex,\n )\n }\n\n observeFromAbsolutePageIndex = (absolutePageIndex: number) =>\n this.pipe(map(() => this.fromAbsolutePageIndex(absolutePageIndex)))\n}\n","import { isShallowEqual } from \"@prose-reader/shared\"\nimport {\n distinctUntilChanged,\n map,\n merge,\n type Observable,\n share,\n switchMap,\n} from \"rxjs\"\nimport type { SpineItem, SpineItemState } from \"../spineItem/SpineItem\"\nimport { DestroyableClass } from \"../utils/DestroyableClass\"\nimport { observeResize } from \"../utils/rxjs\"\nimport type { SpineItemsManager } from \"./SpineItemsManager\"\n\nexport class SpineItemsObserver extends DestroyableClass {\n /**\n * Shared observable which emits every time a spine item state change.\n * As there can be lot of spine items and subscriptions can become costly it is\n * encouraged to use this shared observable.\n */\n public states$: Observable<{ item: SpineItem } & SpineItemState>\n\n /**\n * Observable directly plugged to ResizeObserver for each item.\n */\n public itemResize$: Observable<{\n item: SpineItem\n entries: ResizeObserverEntry[]\n }>\n\n public itemLoad$: Observable<SpineItem>\n public itemUnload$: Observable<SpineItem>\n\n constructor(protected spineItemsManager: SpineItemsManager) {\n super()\n\n this.states$ = this.spineItemsManager.items$.pipe(\n switchMap((items) => {\n return merge(\n ...items.map((item) =>\n item.pipe(\n map((state) => ({ item, ...state })),\n distinctUntilChanged(isShallowEqual),\n ),\n ),\n )\n }),\n share(),\n )\n\n this.itemResize$ = this.spineItemsManager.items$.pipe(\n switchMap((items) => {\n const resize$ = items.map((item) =>\n observeResize(item.element).pipe(\n map((entries) => ({ entries, item })),\n ),\n )\n\n return merge(...resize$)\n }),\n share(),\n )\n\n this.itemLoad$ = this.spineItemsManager.items$.pipe(\n switchMap((items) => {\n return merge(...items.map((item) => item.loaded$.pipe(map(() => item))))\n }),\n share(),\n )\n\n this.itemUnload$ = this.spineItemsManager.items$.pipe(\n switchMap((items) => {\n return merge(\n ...items.map((item) => item.unloaded$.pipe(map(() => item))),\n )\n }),\n share(),\n )\n }\n}\n","import {\n concatMap,\n debounceTime,\n map,\n merge,\n type Observable,\n of,\n Subject,\n share,\n switchMap,\n takeUntil,\n tap,\n} from \"rxjs\"\nimport type { Context } from \"../context/Context\"\nimport type { ReaderSettingsManager } from \"../settings/ReaderSettingsManager\"\nimport type { SpineItem } from \"../spineItem/SpineItem\"\nimport { DestroyableClass } from \"../utils/DestroyableClass\"\nimport type { Viewport } from \"../viewport/Viewport\"\nimport type { SpineItemsManager } from \"./SpineItemsManager\"\nimport type { SpineItemsObserver } from \"./SpineItemsObserver\"\nimport { SpineItemSpineLayout } from \"./types\"\n\nexport type PageLayoutInformation = {\n absolutePageIndex: number\n itemIndex: number\n absolutePosition: SpineItemSpineLayout\n}\n\nexport type LayoutInfo = {\n pages: PageLayoutInformation[]\n}\n\nexport class SpineLayout extends DestroyableClass {\n protected externalLayoutTrigger = new Subject()\n\n /**\n * @todo use absolute position for all direction.\n * translation of position should be done elsewhere\n */\n protected spineItemsRelativeLayouts: SpineItemSpineLayout[] = []\n\n /**\n * Emit layout info after each layout is done.\n */\n public readonly layout$: Observable<unknown>\n\n constructor(\n protected spineItemsManager: SpineItemsManager,\n protected spineItemsObserver: SpineItemsObserver,\n protected context: Context,\n protected settings: ReaderSettingsManager,\n protected viewport: Viewport,\n ) {\n super()\n\n // upstream change, meaning we need to layout again to both resize correctly each item but also to\n // adjust positions, etc\n // This is dispatched AFTER the spine item state has been updated.\n const spineItemNeedsLayout$ = merge(\n spineItemsObserver.itemLoad$,\n spineItemsObserver.itemUnload$,\n )\n\n const layoutTrigger$ = merge(\n this.externalLayoutTrigger,\n spineItemNeedsLayout$,\n )\n\n this.layout$ = layoutTrigger$.pipe(\n tap(() => {\n this.spineItemsManager.items.forEach((item) => {\n item.markDirty()\n })\n }),\n debounceTime(50),\n switchMap(() =>\n this.spineItemsManager.items.reduce(\n (acc$, item, itemIndex) =>\n acc$.pipe(\n concatMap(({ horizontalOffset, verticalOffset }) => {\n const isScreenStartItem =\n horizontalOffset % viewport.absoluteViewport.width === 0\n const isLastItem =\n itemIndex === spineItemsManager.items.length - 1\n const isVertical =\n settings.values.computedPageTurnDirection === `vertical`\n const isRTL = context.isRTL()\n\n const spreadPosition = this.getSpreadPosition(\n isScreenStartItem,\n isRTL,\n )\n const { edgeX, edgeY } = this.getStartEdges(\n isVertical,\n isScreenStartItem,\n horizontalOffset,\n verticalOffset,\n viewport.absoluteViewport.height,\n )\n\n // we trigger an item layout which will update the visual and return\n // us with the item new eventual layout information.\n // This step is not yet about moving item or adjusting position.\n return item\n .layout({\n spreadPosition,\n horizontalOffset,\n isLastItem,\n edgeX,\n edgeY,\n })\n .pipe(\n map(({ width, height }) => {\n const layoutPosition = this.createSpineItemLayout(\n isVertical,\n isRTL,\n edgeX,\n edgeY,\n width,\n height,\n viewport.absoluteViewport.width,\n )\n\n this.spineItemsRelativeLayouts[itemIndex] = layoutPosition\n\n return {\n horizontalOffset: edgeX + width,\n verticalOffset: isVertical ? edgeY + height : 0,\n }\n }),\n )\n }),\n ),\n of({ horizontalOffset: 0, verticalOffset: 0 }),\n ),\n ),\n takeUntil(this.destroy$),\n share(),\n )\n\n this.layout$.subscribe()\n\n this.watchForVerticalWritingUpdate()\n }\n\n private watchForVerticalWritingUpdate() {\n this.spineItemsObserver.itemLoad$\n .pipe(\n tap((spineItem) => {\n this.context.update({\n hasVerticalWriting: spineItem.isUsingVerticalWriting(),\n })\n }),\n takeUntil(this.destroy$),\n )\n .subscribe()\n }\n\n layout() {\n this.externalLayoutTrigger.next(undefined)\n }\n\n public getSpineItemSpineLayoutInfo(\n spineItemOrIndex: SpineItem | number | string | undefined,\n ) {\n const itemIndex =\n this.spineItemsManager.getSpineItemIndex(spineItemOrIndex) ?? 0\n\n return (\n this.spineItemsRelativeLayouts[itemIndex] ||\n new SpineItemSpineLayout({\n left: 0,\n right: 0,\n top: 0,\n bottom: 0,\n width: 0,\n height: 0,\n x: 0,\n y: 0,\n })\n )\n }\n\n get numberOfPages() {\n return this.spineItemsManager.items.reduce((acc, item) => {\n return acc + item.numberOfPages\n }, 0)\n }\n\n public destroy() {\n super.destroy()\n\n this.externalLayoutTrigger.complete()\n }\n\n private getSpreadPosition(\n isScreenStartItem: boolean,\n isRTL: boolean,\n ): \"left\" | \"right\" | \"none\" {\n if (!this.settings.values.computedSpreadMode) return \"none\"\n\n if (isScreenStartItem) {\n return isRTL ? \"right\" : \"left\"\n }\n\n return isRTL ? \"left\" : \"right\"\n }\n\n private getStartEdges(\n isVertical: boolean,\n isScreenStartItem: boolean,\n horizontalOffset: number,\n verticalOffset: number,\n viewportHeight: number,\n ) {\n if (isVertical) {\n return {\n edgeX: isScreenStartItem ? 0 : horizontalOffset,\n edgeY: isScreenStartItem\n ? verticalOffset\n : verticalOffset - viewportHeight,\n }\n }\n\n return {\n edgeX: horizontalOffset,\n edgeY: 0,\n }\n }\n\n private createSpineItemLayout(\n isVertical: boolean,\n isRTL: boolean,\n edgeX: number,\n edgeY: number,\n width: number,\n height: number,\n viewportWidth: number,\n ) {\n if (isVertical) {\n const newEdgeX = width + edgeX\n const newEdgeY = height + edgeY\n\n return new SpineItemSpineLayout({\n left: edgeX,\n right: newEdgeX,\n top: edgeY,\n bottom: newEdgeY,\n height,\n width,\n x: edgeX,\n y: edgeY,\n })\n }\n\n const left = isRTL ? viewportWidth - edgeX - width : edgeX\n\n return new SpineItemSpineLayout({\n right: isRTL ? viewportWidth - edgeX : edgeX + width,\n left,\n x: left,\n top: edgeY,\n bottom: height,\n height,\n width,\n y: edgeY,\n })\n }\n}\n","import { BehaviorSubject, combineLatest, merge } from \"rxjs\"\nimport { filter, takeUntil, tap } from \"rxjs/operators\"\nimport { HTML_PREFIX } from \"../constants\"\nimport type { Context } from \"../context/Context\"\nimport type { HookManager } from \"../hooks/HookManager\"\nimport type { Pagination } from \"../pagination/Pagination\"\nimport type { ReaderSettingsManager } from \"../settings/ReaderSettingsManager\"\nimport type { createSpineItemLocator as createSpineItemLocationResolver } from \"../spineItem/locationResolver\"\nimport { SpineItem } from \"../spineItem/SpineItem\"\nimport { DestroyableClass } from \"../utils/DestroyableClass\"\nimport { isDefined } from \"../utils/isDefined\"\nimport type { Viewport } from \"../viewport/Viewport\"\nimport { SpineItemsLoader } from \"./loader/SpineItemsLoader\"\nimport { createSpineLocator, type SpineLocator } from \"./locator/SpineLocator\"\nimport { Pages } from \"./Pages\"\nimport type { SpineItemsManager } from \"./SpineItemsManager\"\nimport { SpineItemsObserver } from \"./SpineItemsObserver\"\nimport { SpineLayout } from \"./SpineLayout\"\n\nexport class Spine extends DestroyableClass {\n protected elementSubject = new BehaviorSubject<HTMLElement | undefined>(\n undefined,\n )\n protected spineLayout: SpineLayout\n\n public readonly spineItemsLoader: SpineItemsLoader\n public locator: SpineLocator\n public spineItemsObserver: SpineItemsObserver\n public pages: Pages\n public element$ = this.elementSubject.asObservable()\n\n constructor(\n protected context: Context,\n protected pagination: Pagination,\n public spineItemsManager: SpineItemsManager,\n public spineItemLocator: ReturnType<typeof createSpineItemLocationResolver>,\n protected settings: ReaderSettingsManager,\n protected hookManager: HookManager,\n protected viewport: Viewport,\n ) {\n super()\n\n this.spineItemsObserver = new SpineItemsObserver(spineItemsManager)\n\n this.spineLayout = new SpineLayout(\n spineItemsManager,\n this.spineItemsObserver,\n context,\n settings,\n viewport,\n )\n\n this.locator = createSpineLocator({\n context,\n spineItemsManager,\n spineItemLocator,\n settings,\n spineLayout: this.spineLayout,\n viewport,\n })\n\n this.spineItemsLoader = new SpineItemsLoader(\n this.context,\n spineItemsManager,\n this.locator,\n settings,\n this.spineLayout,\n )\n\n this.pages = new Pages(\n this.spineLayout,\n this.spineItemsManager,\n this.spineItemLocator,\n this.context,\n this.locator,\n this.viewport,\n )\n\n const spineElementUpdate$ = context.watch(`rootElement`).pipe(\n filter(isDefined),\n tap((rootElement) => {\n const element: HTMLElement =\n rootElement.ownerDocument.createElement(`div`)\n element.style.cssText = `\n height: 100%;\n position: relative;\n `\n element.className = `${HTML_PREFIX}-spine`\n\n this.elementSubject.next(element)\n }),\n )\n\n const loadSpineItems$ = combineLatest([\n this.context.manifest$,\n this.element$,\n ]).pipe(\n tap(([manifest, element]) => {\n if (!element) return\n\n this.spineItemsManager.destroyItems()\n\n const spineItems = manifest.spineItems.map(\n (resource, index) =>\n new SpineItem(\n resource,\n element,\n this.context,\n this.settings,\n this.hookManager,\n index,\n this.viewport,\n ),\n )\n\n this.spineItemsManager.addMany(spineItems)\n }),\n )\n\n merge(loadSpineItems$, spineElementUpdate$)\n .pipe(takeUntil(this.destroy$))\n .subscribe()\n }\n\n public get element() {\n return this.elementSubject.getValue()\n }\n\n public layout() {\n this.spineLayout.layout()\n }\n\n public getSpineItemSpineLayoutInfo(\n spineItemOrIndex: SpineItem | number | string | undefined,\n ) {\n return this.spineLayout.getSpineItemSpineLayoutInfo(spineItemOrIndex)\n }\n\n public get layout$() {\n // first spineLayout then pages\n return this.pages.layout$\n }\n\n public destroy() {\n super.destroy()\n\n this.pages.destroy()\n this.spineItemsLoader.destroy()\n this.elementSubject.getValue()?.remove()\n this.elementSubject.complete()\n }\n}\n","import { BehaviorSubject } from \"rxjs\"\nimport { parseCfi } from \"../cfi\"\nimport type { Context } from \"../context/Context\"\nimport type { ReaderSettingsManager } from \"../settings/ReaderSettingsManager\"\nimport { SpineItem, type SpineItemReference } from \"../spineItem/SpineItem\"\nimport { DestroyableClass } from \"../utils/DestroyableClass\"\n\nexport class SpineItemsManager extends DestroyableClass {\n constructor(\n protected context: Context,\n protected settings: ReaderSettingsManager,\n ) {\n super()\n }\n\n protected orderedSpineItemsSubject = new BehaviorSubject<SpineItem[]>([])\n public items$ = this.orderedSpineItemsSubject.asObservable()\n\n get(indexOrId: SpineItemReference | undefined) {\n if (typeof indexOrId === \"number\") {\n return this.orderedSpineItemsSubject.value[indexOrId]\n }\n\n if (typeof indexOrId === \"string\") {\n return this.orderedSpineItemsSubject.value.find(\n ({ item }) => item.id === indexOrId,\n )\n }\n\n return indexOrId\n }\n\n comparePositionOf(toCompare: SpineItem, withItem: SpineItem) {\n const toCompareIndex = this.getSpineItemIndex(toCompare) ?? 0\n const withIndex = this.getSpineItemIndex(withItem) ?? 0\n\n return toCompareIndex > withIndex\n ? `after`\n : toCompareIndex === withIndex\n ? `same`\n : `before`\n }\n\n getSpineItemIndex(spineItemOrId: SpineItem | string | number | undefined) {\n const spineItem =\n spineItemOrId instanceof SpineItem\n ? spineItemOrId\n : this.get(spineItemOrId)\n\n if (!spineItem) return undefined\n\n const index = this.orderedSpineItemsSubject.value.indexOf(spineItem)\n\n return index < 0 ? undefined : index\n }\n\n addMany(spineItems: SpineItem[]) {\n this.orderedSpineItemsSubject.next([\n ...this.orderedSpineItemsSubject.getValue(),\n ...spineItems,\n ])\n }\n\n // @todo move\n getSpineItemFromCfi(cfi: string) {\n const { itemIndex } = parseCfi(cfi)\n\n if (itemIndex !== undefined) {\n return this.get(itemIndex)\n }\n\n return undefined\n }\n\n get items() {\n return this.orderedSpineItemsSubject.value\n }\n\n /**\n * @todo handle reload, remove subscription to each items etc. See add()\n */\n destroyItems() {\n this.orderedSpineItemsSubject.value.forEach((item) => {\n item.destroy()\n })\n }\n}\n","import { merge, takeUntil, tap } from \"rxjs\"\nimport { HTML_PREFIX_VIEWPORT } from \"../constants\"\nimport type { Context } from \"../context/Context\"\nimport type { ReaderSettingsManager } from \"../settings/ReaderSettingsManager\"\nimport { ReactiveEntity } from \"../utils/ReactiveEntity\"\nimport { AbsoluteViewport, RelativeViewport } from \"./types\"\n\ntype State = {\n element: HTMLElement\n /**\n * Anything that can change the page size should trigger a layout and thus\n * force a recalculation of the page size.\n */\n pageSize: {\n width: number\n height: number\n }\n /**\n * To get the absolute viewport we consider clientWidth/clientHeight which gives more\n * flexibility for the reader container. For example when using scrollbar with scroll\n * navigator. The viewport dimensions will be affected by the scrollbar.\n *\n * The viewport dimensions are updated only before a layout.\n */\n width: number\n height: number\n}\n\nexport class Viewport extends ReactiveEntity<State> {\n constructor(\n protected context: Context,\n protected settingsManager: ReaderSettingsManager,\n ) {\n const element = document.createElement(\"div\")\n\n element.setAttribute(`data-${HTML_PREFIX_VIEWPORT}`, \"\")\n\n super({\n element,\n pageSize: {\n width: 1,\n height: 1,\n },\n width: 1,\n height: 1,\n })\n\n const updatePageSize$ = this.settingsManager\n .watch([\"computedSpreadMode\"])\n .pipe(\n tap(() => {\n this.mergeCompare({\n pageSize: this.calculatePageSize(this.value),\n })\n }),\n )\n\n const updateLayout$ = this.context.watch(\"rootElement\").pipe(\n tap(() => {\n this.layout()\n }),\n )\n\n merge(updatePageSize$, updateLayout$)\n .pipe(takeUntil(this.destroy$))\n .subscribe()\n }\n\n protected calculatePageSize(layout: { width: number; height: number }) {\n const { computedSpreadMode } = this.settingsManager.values\n\n const pageSize = {\n width: computedSpreadMode ? layout.width / 2 : layout.width,\n height: layout.height,\n }\n\n return pageSize\n }\n\n public layout() {\n const layout = {\n width: this.value.element.clientWidth,\n height: this.value.element.clientHeight,\n }\n\n this.mergeCompare({\n pageSize: this.calculatePageSize(layout),\n ...layout,\n })\n }\n\n public get absoluteViewport() {\n return new AbsoluteViewport({\n width: this.value.width,\n height: this.value.height,\n })\n }\n\n public get pageSize() {\n return this.value.pageSize\n }\n\n public get scaleFactor() {\n const absoluteViewport = this.absoluteViewport\n const viewportRect = this.value.element.getBoundingClientRect()\n const relativeScale =\n (viewportRect?.width ?? absoluteViewport.width) / absoluteViewport.width\n\n return relativeScale\n }\n\n /**\n * Returns the relative viewport after eventual transforms.\n * For example if the viewport was zoomed out, we start seeing more left and right\n * items. Therefore we can virtually expand the viewport.\n * Inversely if the viewport is zoomed in, we see less left and right items.\n *\n * This is mostly useful for detecting what should be visible, navigable, etc.\n *\n * @important\n * Contains long floating values.\n *\n * @todo take position of translate into consideration in something\n * like relativeViewportPosition or even better a ViewportSlicePosition\n */\n public get relativeViewport() {\n const absoluteViewport = this.absoluteViewport\n const relativeScale = this.scaleFactor\n\n return new RelativeViewport({\n width: absoluteViewport.width / relativeScale,\n height: absoluteViewport.height / relativeScale,\n })\n }\n}\n","import { merge, type Observable, type ObservedValueOf, of, Subject } from \"rxjs\"\nimport { map, skip, takeUntil, tap } from \"rxjs/operators\"\nimport {\n generateCfiForSpineItemPage,\n generateCfiFromRange,\n parseCfi,\n} from \"./cfi\"\nimport { resolveCfi } from \"./cfi/resolve\"\nimport {\n HTML_ATTRIBUTE_DATA_READER_ID,\n HTML_PREFIX,\n HTML_STYLE_PREFIX,\n} from \"./constants\"\nimport { Context, type ContextState } from \"./context/Context\"\nimport { Features } from \"./features/Features\"\nimport { HookManager } from \"./hooks/HookManager\"\nimport styles from \"./index.scss?inline\"\nimport { createNavigator } from \"./navigation/Navigator\"\nimport { Pagination } from \"./pagination/Pagination\"\nimport { PaginationController } from \"./pagination/PaginationController\"\nimport { Report } from \"./report\"\nimport { ReaderSettingsManager } from \"./settings/ReaderSettingsManager\"\nimport type { SettingsInterface } from \"./settings/SettingsInterface\"\nimport type { CoreInputSettings } from \"./settings/types\"\nimport { Spine } from \"./spine/Spine\"\nimport { SpineItemsManager } from \"./spine/SpineItemsManager\"\nimport { createSpineItemLocator } from \"./spineItem/locationResolver\"\nimport type { SpineItemReference } from \"./spineItem/SpineItem\"\nimport { injectCSS, removeCSS } from \"./utils/dom\"\nimport { Viewport } from \"./viewport/Viewport\"\n\nexport type CreateReaderOptions = Partial<CoreInputSettings>\n\nexport type CreateReaderParameters = CreateReaderOptions\n\nexport type ContextSettings = Partial<CoreInputSettings>\n\nexport type ReaderInternal = ReturnType<typeof createReader>\n\nconst STYLES_ID = `${HTML_STYLE_PREFIX}-core`\n\nexport const createReader = (inputSettings: CreateReaderOptions) => {\n const id = crypto.randomUUID()\n const layoutSubject = new Subject<void>()\n const destroy$ = new Subject<void>()\n const hookManager = new HookManager()\n const context = new Context()\n const settingsManager = new ReaderSettingsManager(inputSettings, context)\n const features = new Features(context, settingsManager)\n const spineItemsManager = new SpineItemsManager(context, settingsManager)\n const viewport = new Viewport(context, settingsManager)\n const spineItemLocator = createSpineItemLocator({\n context,\n settings: settingsManager,\n viewport,\n })\n const pagination = new Pagination(context, spineItemsManager)\n const spine = new Spine(\n context,\n pagination,\n spineItemsManager,\n spineItemLocator,\n settingsManager,\n hookManager,\n viewport,\n )\n const navigator = createNavigator({\n context,\n spineItemsManager,\n hookManager,\n spine,\n settings: settingsManager,\n viewport,\n })\n const paginationController = new PaginationController(\n context,\n pagination,\n spineItemsManager,\n spine,\n spineItemLocator,\n )\n\n // bridge all navigation stream with reader so they can be shared across app\n navigator.navigationState$.subscribe(context.bridgeEvent.viewportStateSubject)\n navigator.navigation$.subscribe(context.bridgeEvent.navigationSubject)\n navigator.locker.isLocked$.subscribe(\n context.bridgeEvent.navigationIsLockedSubject,\n )\n pagination.subscribe(context.bridgeEvent.paginationSubject)\n\n const layout = () => {\n layoutSubject.next()\n }\n\n const load = (\n options: Required<\n Pick<ContextState, \"manifest\"> & { containerElement: HTMLElement }\n >,\n ) => {\n const { containerElement, manifest } = options\n\n if (context.manifest) {\n Report.warn(`loading a new book is not supported yet`)\n\n return\n }\n\n Report.log(`load`, { options })\n\n const element = wrapContainer(containerElement, id)\n\n context.update({\n manifest,\n rootElement: element,\n })\n\n layout()\n }\n\n const layoutOnSpreadModeChange$ = settingsManager\n .watch([`computedSpreadMode`])\n .pipe(skip(1), tap(layout))\n\n const layout$ = layoutSubject.pipe(\n tap(() => {\n const containerElement = context.value.rootElement\n\n if (!containerElement) return\n\n containerElement.style.setProperty(`overflow`, `hidden`)\n\n viewport.layout()\n spine.layout()\n }),\n takeUntil(destroy$),\n )\n\n const subs = merge(layout$, layoutOnSpreadModeChange$).subscribe()\n\n injectCSS(document, STYLES_ID, styles)\n\n /**\n * Free up resources, and dispose the whole reader.\n * You should call this method if you leave the reader.\n *\n * This is not possible to use any of the reader features once it\n * has been destroyed. If you need to open a new book you need to\n * either create a new reader or call `load` with a different manifest\n * instead of destroying it.\n */\n const destroy = () => {\n removeCSS(document, STYLES_ID)\n\n subs.unsubscribe()\n spineItemsManager.destroy()\n paginationController.destroy()\n settingsManager.destroy()\n pagination.destroy()\n context.destroy()\n navigator.destroy()\n spine.destroy()\n features.destroy()\n destroy$.next()\n destroy$.complete()\n viewport.destroy()\n }\n\n return {\n id,\n context,\n spine,\n hookManager,\n cfi: {\n generateCfiFromRange,\n parseCfi,\n generateCfiForSpineItemPage,\n resolveCfi: (\n params: Omit<Parameters<typeof resolveCfi>[0], \"spineItemsManager\">,\n ) => resolveCfi({ ...params, spineItemsManager }),\n },\n navigation: navigator,\n spineItemsObserver: spine.spineItemsObserver,\n spineItemsManager,\n layout,\n load,\n destroy,\n pagination: {\n get state() {\n return pagination.value\n },\n get state$(): Observable<ObservedValueOf<typeof pagination>> {\n return pagination\n },\n },\n settings: settingsManager as SettingsInterface<\n NonNullable<(typeof settingsManager)[\"inputSettings\"]>,\n NonNullable<(typeof settingsManager)[\"outputSettings\"]>\n >,\n renderHeadless: (spineItem: SpineItemReference) => {\n return (\n spineItemsManager.get(spineItem)?.renderer.renderHeadless() ??\n of(undefined)\n )\n },\n viewport,\n viewportState$: context.bridgeEvent.viewportState$,\n viewportFree$: context.bridgeEvent.viewportFree$,\n /**\n * Dispatched when the reader has loaded a book and is rendering a book.\n * Using navigation API and getting information about current content will\n * have an effect.\n * It can typically be used to hide a loading indicator.\n */\n state$: context.manifest$.pipe(\n map((manifest) => (manifest ? \"ready\" : \"idle\")),\n ),\n features,\n $: {\n destroy$,\n },\n }\n}\n\nconst wrapContainer = (containerElement: HTMLElement, id: string) => {\n containerElement.style.cssText = `\n ${containerElement.style.cssText}\n background-color: white;\n position: relative;\n `\n containerElement.classList.add(`${HTML_PREFIX}-reader`)\n containerElement.setAttribute(HTML_ATTRIBUTE_DATA_READER_ID, id)\n containerElement.setAttribute(\"data-prose-reader-container\", id)\n\n return containerElement\n}\n\ntype Reader = ReturnType<typeof createReader>\n\nexport type { Reader }\n","import { accessibilityEnhancer } from \"./enhancers/accessibility\"\nimport { chromeEnhancer } from \"./enhancers/chrome\"\nimport { eventsEnhancer } from \"./enhancers/events/events\"\nimport { fontsEnhancer } from \"./enhancers/fonts\"\nimport { hotkeysEnhancer } from \"./enhancers/hotkeys\"\nimport { htmlEnhancer } from \"./enhancers/html/enhancer\"\nimport { layoutEnhancer } from \"./enhancers/layout/layoutEnhancer\"\nimport { mediaEnhancer } from \"./enhancers/media/media\"\nimport { navigationEnhancer } from \"./enhancers/navigation\"\nimport { paginationEnhancer } from \"./enhancers/pagination/enhancer\"\nimport { resourcesEnhancer } from \"./enhancers/resources\"\nimport { selectionEnhancer } from \"./enhancers/selection/selectionEnhancer\"\nimport { themeEnhancer } from \"./enhancers/theme\"\nimport { utilsEnhancer } from \"./enhancers/utils\"\nimport { webkitEnhancer } from \"./enhancers/webkit\"\nimport { zoomEnhancer } from \"./enhancers/zoom\"\nimport { createReader as createInternalReader } from \"./reader\"\n\nexport const createReaderWithEnhancers = //__\n selectionEnhancer(\n hotkeysEnhancer(\n webkitEnhancer(\n fontsEnhancer(\n accessibilityEnhancer(\n resourcesEnhancer(\n utilsEnhancer(\n zoomEnhancer(\n navigationEnhancer(\n htmlEnhancer(\n mediaEnhancer(\n chromeEnhancer(\n eventsEnhancer(\n paginationEnhancer(\n layoutEnhancer(\n themeEnhancer(\n // __\n createInternalReader,\n ),\n ),\n ),\n ),\n ),\n ),\n ),\n ),\n ),\n ),\n ),\n ),\n ),\n ),\n ),\n )\n","import type { CreateReaderParameters, ReaderInternal } from \"../../reader\"\n\n// biome-ignore lint/suspicious/noExplicitAny: TODO\nexport type EnhancerOutput<Enhancer extends (options: any) => any> = ReturnType<\n ReturnType<Enhancer>\n>\n// biome-ignore lint/suspicious/noExplicitAny: TODO\nexport type EnhancerOptions<Enhancer extends (options: any) => any> =\n Parameters<ReturnType<Enhancer>>[0]\n\nexport type RootEnhancer<\n Options extends CreateReaderParameters = CreateReaderParameters,\n Reader extends ReaderInternal = ReaderInternal,\n> = (next: (options: Options) => Reader) => (options: Options) => Reader\n\nexport const rootEnhancer =\n <Options extends CreateReaderParameters, Reader extends ReaderInternal>(\n next: (options: Options) => Reader,\n ) =>\n (options: Options): Reader => {\n const reader = next(options)\n\n return reader\n }\n"],"names":["Report","SharedReport","pointerEvents","createRangeOrCaretFromPoint","doc","startX","startY","getFirstVisibleNodeForPositionRelativeTo","documentOrElement","viewport","ownerDocument","element","getFirstVisibleElementForViewport","lastValidRange","lastValidOffset","range","childNode","rects","visibleRect","getFirstVisibleDOMRect","rangeOrCaret","rect","positionFromViewport","getElementOrNodePositionFromViewPort","lastValidElement","child","childInViewPort","domRect","left","right","position","getRangeFromNode","node","offset","e","isPointerEvent","event","eventView","isMouseEvent","isTouchEvent","noopElement","getElementsWithAssets","_document","RESOURCE_ELEMENTS","revokeDocumentBlobs","url","styleSheets","sheet","rules","rule","blobUrls","hasShape","obj","requiredProps","optionalMethods","prop","method","isHtmlElement","isHtmlTagElement","tagName","isHtmlRange","injectCSS","id","style","prepend","userStyle","removeCSS","styleElement","getAttributeValueFromString","string","key","regExp","match","firstMatch","injectCSSToFrame","frameElement","injectCSSToDocument","removeCSSToDocument","upsertCSSToFrame","existingElement","getFrameViewportInfo","frame","viewportMetaElement","viewportContent","width","height","waitForFrameLoad","stream","switchMap","of","fromEvent","take","map","waitForFrameReady","readyPromise","from","accessibilityEnhancer","next","options","reader","observer","entries","entry","itemId","destroy","item","links","link","chromeEnhancer","takeUntil","rootElement","onScroll","translateFramePositionIntoPage","frameRect","scaleX","scaleY","top","adjustedX","adjustedY","normalizeEventForViewport","iframeOriginalEvent","locator","originalFrame","spineItem","pageHeight","pageWidth","clientX","clientY","newEvent","touches","touch","passthroughEvents","eventsEnhancer","unregister","listener","convertedEvent","normalizedEvent","cb","getBase64FromBlob","data","resolve","pick","keys","acc","mapKeysTo","watchKeys","distinctUntilChanged","isShallowEqual","observeResize","Observable","resizeObserver","waitForSwitch","waitForStream","value","first","deferNextResult","sub","result","idle","handle","timeout","deferIdle","callback","defer","observeMutation","target","subscriber","mutations","observeIntersection","intersectionObserver","SettingsManagerOverload","initialSettings","settingsManager","inputSettings","shallowMergeIfDefined","Subject","combineLatest","startWith","parentSettings","settings","shareReplay","parentInputSettings","parentManagerPreparedUpdate","outputSettings","hasChanged","commit","keyOrKeys","newOutputSettings","_unused1","_unused2","_unused3","_unused4","rest","fontsEnhancer","fontScale","lineHeight","fontWeight","fontJustification","changes$","SettingsManager","getStyle","applyChangeToSpineItems","requireLayout","shouldRequireLayout","source","pairwise","old","latest","tap","hotkeysEnhancer","navigateOnKey","document","pageTurnDirection","computedPageTurnMode","spineItems","merge","EMPTY","handleLinks","items","NEVER","events$","share","ReactiveEntity","initialState","BehaviorSubject","pagination","newValue","_DocumentRenderer","params","unloadTrigger$","filter","trigger","loadTrigger$","mergeMap","documentContainer","endWith","hookResults","catchError","error","state","releaseSubject","finalize","itemRenditionLayout","iframe","hasViewport","DocumentRenderer","defaultGetResource","ResourceHandler","lastValueFrom","resource","joinPath","base","path","isFileProtocol","tempBase","loadFontFaces","spineItemUriParentPath","context","i","src","srcParts","part","newSrcParts","urlMatch","originalSrc","foundItem","href","resourceHandler","blob","blobUrl","newRule","loadElementSrc","loadAssets","elementsWithAsset","getParentPath","assetsLoad$","unloadAssets","PROSE_READER_NAMESPACE","VIEWPORT_ADJUSTMENT_THROTTLE","PAGINATION_UPDATE_AFTER_VIEWPORT_ADJUSTMENT_DEBOUNCE","ITEM_EXTENSION_VALID_FOR_FRAME_SRC","HTML_PREFIX","HTML_STYLE_PREFIX","HTML_ATTRIBUTE_DATA_READER_ID","HTML_PREFIX_VIEWPORT","HTML_PREFIX_SCROLL_NAVIGATOR","createHtmlPageFromResource","resourceResponse","contentType","parseContentType","detectMimeTypeFromName","mime","objectUrl","bitmap","attachFrameSrc","resourcesHandler","getHtmlFromResource","response","extension","htmlDoc","blobURL","createFrameElement","getViewPortInformation","viewportDimensions","computedWidthScale","staticLayout","size","renderPrePaginated","minPageSpread","blankPagePosition","spreadPosition","isRTL","minimumWidth","computedScale","hasViewportDimensions","contentWidth","contentHeight","transformTranslateX","transformOriginX","buildStyleForViewportFrame","buildStyleForReflowableImageOnly","isScrollable","enableTouch","buildStyleWithMultiColumn","columnHeight","columnWidth","getDimensionsForReflowableContent","isUsingVerticalWriting","renderReflowable","pageSizeHeight","manifest","isImageType","continuousScrollableReflowableItem","isGloballyPrePaginated","frameStyle","pages","HtmlRenderer","prePaginatedStyle","isTouchEnabled","dims","text","body","htmlEnhancer","props","links$","isDefined","arg","LayoutEntry","layout","SpineItemPosition","UnboundSpineItemPagePosition","SpineItemPageLayout","SpineItemSpineLayout","SpineItemPageSpineLayout","AbstractSpinePosition","SpinePosition","UnboundSpinePosition","getPositionRelativeToNonTransformedElement","elementRect","x","y","relativeX","relativeY","getSpinePositionFromClientPosition","spineElement","createCoordinatesApi","createMovingSafePan$","iframeOverlayForAnimationsElement","updateOverlayElement$","createResetLock$","scheduled","animationFrameScheduler","lockAfterViewportBusy$","resetLockViewportFree$","handleViewportLock$","mode","CONTAINER_HTML_PREFIX","HTML_PREFIX_CORE","defaultLoadingElementCreate","container","loadingElementContainer","logoElement","detailsElement","createPlaceholderPages","alreadyExistingElement","theme","viewportWidth","fixIframeScrollbar","fixReflowable","spineManagerWantAFullWidthItem","flagSpineItems","isReady","isDirty","updateSpreadMode","isLandscape","layoutEnhancer","pageHorizontalMargin","pageVerticalMargin","layoutAutoResize","layoutLayerTransition","hasRedrawn","pageSize","columnGap","revealItemOnReady$","layoutOnContainerResize$","debounceTime","movingSafePan$","skip","layoutInfo$","flagSpineItems$","updateSpreadMode$","placeholderPages$","ImageRenderer","imgElement","responseOrUrl","imageElement","naturalWidth","naturalHeight","ratio","mediaEnhancer","maybeFactory","frameObserver","audios","audioElement","elementObserver","video","videos","unobserveElements","unobserve","handleLinksNavigation","manualNavigator","hrefUrl","hrefWithoutAnchor","navigationReport","getSpineItemPositionForLeftPage","spineItemLocator","nextPotentialPosition","getNavigationForLeftSinglePage","navigationResolver","computedPageTurnDirection","spineItemsManager","spineLocator","defaultNavigation","spineItemPosition","spineItemNavigation","getNavigationForLeftOrTopPage","navigation","doubleNavigation","getSpineItemPositionForRightPage","getNavigationForRightOrBottomSinglePage","spineItemNavigationForRightPage","getNavigationForRightOrBottomPage","ManualNavigator","cfi","indexOrId","endIndex","beginIndex","pageIndex","spineItemId","absolutePageIndex","foundInfo","PanNavigator","delta","viewportScale","correctedX","correctedY","DestroyableClass","SCROLL_FINISHED_DEBOUNCE_TIMEOUT","UserScrollNavigation","scrollNavigationController","locker","navigateOnScroll$","exhaustMap","unlock","spinePosition","observeState","withLatestFrom","paginationInfo","readingDirection","numberOfSpineItems","isAtAbsoluteBeginning","isAtAbsoluteEnd","isAtEndSpineItem","isAtBeginSpineItem","isAtBeginFirstPage","isAtEndLastPage","throttleLock","duration","unlockFn","throttleTime","navigationEnhancer","state$","panNavigator","userScrollNavigation","linksNavigation$","navigateOnUserScroll$","buildChaptersInfo","tocItem","spineItemIndex","indexOfHash","tocItemPathWithoutAnchor","tocItemHrefWithoutFilename","hrefWithoutFilename","hrefIsChapterHref","hrefIsWithinChapter","spineItemIndexOfPossibleCandidate","info","subInfo","buildChapterInfoFromSpineItem","getChaptersInfo","trackChapterInfo","getTotalProgressFromPercentages","estimateBeforeThisItem","currentItemWeight","progressWithinThisItem","getScrollPercentageWithinItem","currentPosition","currentItem","getPercentageEstimate","currentSpineIndex","itemIsReady","readingOrderLength","itemIndexNumber","spineItemNumberOfPages","page","totalProgress","trackTotalPages","mapPaginationInfoToExtendedInfo","chaptersInfo","percentageEstimateOfBook","beginItem","endItem","observeProgression","trackPaginationInfo","chaptersInfo$","totalPages$","currentValue","extandedBasePagination$","extendedInfo","pageInfo","totalPageInfo","numberOfPagesForItem","generateRootCfi","generate","generateCfi","nodeOrRange","nodeOrRangeOwnerDocument","generateCfiForSpineItemPage","pageNode","generateCfiFromRange","getItemAnchor","hasIndirectionMarker","isRootCfi","parsed","parse","isIndirectionOnly","extractIndirectionPart","parsedCfi","parseCfi","isCfiRange","isParsedCfiRange","resolveCfi","itemIndex","restParsed","rendererElement","resolved","toCfiLocatableResource","restParsedCfi","consolidate","itemPageIndex","isSpineItemReady","startOffset","ResourcesLocator","initialConsolidatedValue","isReflowable","release","memoizedConsolidate$","withRelease","meta","consolidate$","switchScan","consolidatedResource","defaultIfEmpty","paginationEnhancer","paginationInfo$","getPaginationInfo","resourcesLocator","createDatabase","db","reject","transaction","request","cursor","err","openDatabase","name","createResourcesManager","uniqueID","cache$","retrieveItem","itemIndexOrId","get","fetchResource","cacheData","cache","forkJoin","onLoad$","keysToRemove","promises","resourcesEnhancer","resourceManager","getRangeFromSelection","anchor","focus","comparison","endOffset","createOrderedRangeFromSelection","selection","anchorNode","anchorOffset","focusNode","focusOffset","FrameSelectionTracker","frameDoc","frameDocMutation$","mutation","iframeDestroyed$","delay","trackSpineItemSelection","selectionTracker","selectionEnhancer","lasSelection","trackedSelection$","instances","selection$","selectionStart$","isSelecting","selectionEnd$","selectionOver$","lastSelectionOnPointerdown$","defaultThemes","themeEnhancer","currentThemeSubject$","foundTheme","applyChangeToSpineItemElement","applyChangeToSpineItem","utilsEnhancer","scope","styleTemplate","styleWithIdReplaced","webkitEnhancer","createReader","constrainPositionWithinViewport","scale","clientWidth","clientHeight","bounds","applyViewportTransformForControlledMode","viewportElement","translateTransform","scaleTransform","derivePositionFromScaleForControlledMode","currentScale","userScale","scaleFactor","originalWidth","originalHeight","visualCenterX","visualCenterY","AbstractPosition","ScrollPosition","UnboundScrollPosition","ScrollNavigationController","hookManager","spine","scaledPosition","timer","elementCreation$","toggleElementDisplay$","navigate$","isSpineScrolling$","scrollHappeningFromBrowser$","spineScrolling","viewportScrolling","shouldAvoidScrollEvent","adjustScrollToKeepContentCentered","scrollContainer","fromScale","toScale","marginX","marginY","containerWidth","containerHeight","currentScrollLeft","currentScrollTop","visibleCenterX","visibleCenterY","newVisibleCenterX","newVisibleCenterY","scrollLeft","scrollTop","applyScaleToViewportForScroll","scrollNavigationElement","newCenterPositionAfterNewScaleProjection","direction","ANIMATION_DURATION","ZoomController","enter$","animate","exit$","newScale","newPosition","constrainedPosition","STYLES_ID","zoomEnhancer","zoomController","styles","isFullyPrePaginated","BridgeEvent","ReplaySubject","isLocked","Context","newState","previousState","newCompleteState","Features","hasVerticalWriting","renditionFlow","renditionLayout","HookManager","hookToDeregister","hook","fn","userDestroyFn","destroySubject","destroyFn","fnResult","ref","hookInstance","instance","destroyFns","spinePositionToTranslation","translationToSpinePosition","translation","report","ControlledNavigationController","elementInit$","settingsThatRequireLayout$","updateElementOnSettingsChange$","animation","currentEvent","animationDuration","pageTurnAnimation","identity","computedStyle","transform","matrix","withPaginationInfo","consolidateWithPagination","navigation$","prev","curr","mapUserNavigationToInternal","userNavigation","previousNavigation","withCfiPosition","getOrGuessDirection","withDirection","conslidatedNavigation","withFallbackPosition","adjustedPosition","withSpineItem","getSpineItem","navigationSnapThreshold","existingSpineItem","farthestSpineItemIndex","farthestSpineItem","endPageIndex","beginPageIndex","farthestVisiblePageIndex","navigationForPosition","visibleSpineItemsFromNavigablePosition","finalSpineItemIndex","withSpineItemLayoutInfo","spineItemDimensions","withSpineItemPosition","getPosition","farthestPageIndex","navigableSpinePositionForFarthestPageIndex","visiblePagesAtNavigablePosition","beginPageIndexForDirection","withUrlInfo","Locker","locked","isCalled","restoreNavigationForControlledPageTurnMode","spineItemAbsolutePosition","isPositionWithinSpineItem","spineItemWidthDifference","spineItemHeighDifference","hasSpineItemGrewOrShrink","urlResult","cfiResultPosition","positionInSpineItemWithDifference","restoreNavigationForScrollingPageTurnMode","foundSpineItem","positionInSpineItem","positionYfromBottomPreviousNavigation","positionInspineItem","positionInItem","restorePosition","withRestoredPosition","restoredPosition","InternalNavigator","userNavigation$","controlledNavigationController","isRestorationLocked$","previousPosition","previousRest","currentRest","navigationFromUser$","isUserLocked","shouldNotAlterPosition","navigationUpdateFollowingUserUnlock$","navigationUpdateFromLayout$","navigationRestored$","navigationUpdateOnPaginationUpdate$","navigationUpdate$","notifyNavigationUpdate","currentNavigation","navigateViewport","isScrollFromUser","isPaginationUpdate","isRestoration","positionIsSame","getItemOffsetFromPageIndex","itemWidth","lastPageOffset","logicalOffset","calculateNumberOfPagesForItem","getClosestValidOffsetFromApproximateOffsetInPages","numberOfPages","offsetValues","_","offsetRange","getPageFromOffset","getSafePosition","itemHeight","getSpineItemNumberOfPages","pageTurnMode","getSpineItemPageIndexFromSpineItemPosition","getSpineItemPositionFromPageIndex","itemLayout","ltrRelativeOffset","createSpineItemLocator","getSpineItemPositionFromNode","offsetOfNodeInSpineItem","spineItemWidth","val","unsafePosition","pageStartY","pageStartX","rtlPageStartX","createNavigationResolver","fromOutOfBoundsSpinePosition","lastSpineItem","distanceOfLastSpineItem","maximumYOffset","positiveY","maximumX","minimumX","maximumXOffset","positiveX","boundedX","fromUnboundSpinePosition","visibleAreaRectWidth","unboundPosition","getAdjustedPositionForSpread","pageSizeWidth","getNavigationForPosition","viewportPosition","spineItemNavigationResolver","spineItemValidPosition","viewportNavigation","getNavigationForSpineItemPage","xPositionForPageIndex","readingOffset","getNodeFromSelector","selector","getSpineItemOffsetFromAnchor","getSpinePositionFromSpineItemAnchor","spineItemOffset","getNavigationForAnchor","getNavigationForUrl","validUrl","urlWithoutAnchor","getNavigationFromSpineItemPosition","navigationInSpineItem","NAMESPACE","spineItemNavigator","createSpineItemNavigator","readingPosition","triggerPercentage","triggerXPosition","triggerYPosition","midScreenPositionSafePosition","to","a","b","createNavigator","userExplicitNavigationSubject","restorationLocker","internalNavigator","navigationState$","states","Pagination","PaginationController","updatePagination$","getVisiblePagesFromViewportPosition","previousPagination","beginSpineItemIndex","endSpineItemIndex","beginSpineItem","endSpineItem","beginLastCfi","endLastCfi","shouldUpdateBeginCfi","shouldUpdateEndCfi","beginCfi","endCfi","beginNumberOfPagesInSpineItem","endNumberOfPagesInSpineItem","updateCfi$","beginPageIndexInSpineItem","endPageIndexInSpineItem","beginPageEntry","endPageEntry","computeSpreadMode","spreadMode","settingsWithDefaults","newInputSettings","ReaderSettingsManager","computedSettings","DefaultRenderer","SpineItemLayout","containerElement","renderer","isLastItem","horizontalOffset","isScreenStartItem","lastItemStartOnNewScreenInAPrepaginatedBook","edgeX","edgeY","trustableLastLayout","previousWidth","previousHeight","safeWidth","safeHeight","nextResult","layoutProcess$","rendererLayout$","minimum","maxValue","adjustedValue","SpineItem","parentElement","index","createContainerElement","rendererFactory","rendererParams","updateStateOnLoaded$","SpineItemsLoader","spineLayout","forcedOpen$","v","arrayEqual","forcedOpenIndexes","numberOfAdjacentSpineItemToPreLoad","beginMaximumIndex","endMaximumIndex","visibleIndexes","indexesToLoad","orderedSpineItem","indexes","updateMap","add","count","newCount","translateSpinePositionToRelativeViewport","absolutePosition","absoluteViewport","relativeViewport","offsetX","offsetY","ViewportSlicePosition","positionOrRect","AbsoluteViewport","RelativeViewport","getAbsolutePageIndexFromPageIndex","spineItemOrId","currentAbsolutePage","isItemVisibleByThresholdForPosition","visibleWidthOfItem","visibleHeightOfItem","threshold","visibleWidthRatioOfSpineItem","visibleHeightRatioOfSpineItem","isItemVisibleOnScreenByThresholdForPosition","widthRatioOfSpaceTakenInScreen","heightRatioOfSpaceTakenInScreen","getItemVisibilityForPosition","bottom","restrictToScreen","viewportLeft","viewportRight","viewportTop","viewportBottom","isItemVisibleEnoughOnScreen","getSpineItemFromPosition","isWithinXAxis","isWithinYAxis","getSpinePositionFromSpineItemPosition","getVisibleSpineItemsFromPosition","useAbsoluteViewport","fallbackSpineItem","spineItemsVisible","itemPosition","viewportInfo","relativeSpinePosition","visible","beginItemIndex","endItemIndex","createSpineLocator","getSpineItemPositionFromSpinePosition","getSpinePositionFromSpineItem","getSpineItemFromIframe","getSpineItemPageIndexFromNode","spineItemOrIndex","pagesVisible","spineItemPageIndex","spineItemPagePosition","spinePositionToSpineItemSpineLayout","Pages","pagesAbsolutePositions","pageSpineItemPosition","pageSpinePosition","_unused","firstVisibleNode","SpineItemsObserver","resize$","SpineLayout","spineItemsObserver","spineItemNeedsLayout$","layoutTrigger$","acc$","concatMap","verticalOffset","isVertical","layoutPosition","viewportHeight","newEdgeX","newEdgeY","Spine","spineElementUpdate$","loadSpineItems$","SpineItemsManager","toCompare","withItem","toCompareIndex","withIndex","Viewport","updatePageSize$","updateLayout$","computedSpreadMode","relativeScale","layoutSubject","destroy$","features","navigator","paginationController","load","wrapContainer","layoutOnSpreadModeChange$","layout$","subs","createReaderWithEnhancers","createInternalReader","rootEnhancer"],"mappings":"kbAIO,MAAMA,EAASC,EAAAA,OAAa,UAJZ,qBAIsC,OAAW,CACtE,MAAO,SACT,CAAC,ECJKC,GAA0B,CAC9B,gBACA,cACA,eACA,eACA,cACA,aACA,cACA,WAGF,EAEA,SAASC,GACPC,EACAC,EACAC,EACA,CAEA,GAAI,2BAA4BF,EAE9B,OAAOA,EAAI,uBAAuBC,EAAQC,CAAM,EAKlD,GACE,wBAAyBF,GAEzB,OAAOA,EAAI,oBAAwB,IAGnC,OAAOA,EAAI,oBAAoBC,EAAQC,CAAM,CAEjD,CAOO,MAAMC,GAA2C,CACtDC,EACAC,IACG,CACH,MAAMC,EACJ,gBAAiBF,EACbA,EACAA,EAAkB,cAExB,GAAI,CAACE,EAAe,OAEpB,MAAMC,EACJ,SAAUH,EACNI,GAAkCJ,EAAkB,KAAMC,CAAQ,EAClEG,GAAkCJ,EAAmBC,CAAQ,EAEnE,GAAIE,EAAS,CACX,IAAIE,EACAC,EAAkB,EACtB,MAAMC,EAAQL,EAAc,YAAA,EAsD5B,OA/CA,MAAM,KAAKC,EAAQ,UAAU,EAAE,KAAMK,GAAc,CACjDD,EAAM,mBAAmBC,CAAS,EAElC,MAAMC,EAAQF,EAAM,eAAA,EAEdG,EAAcC,GAAuBF,EAAOR,CAAQ,EAI1D,GAAIS,EAAa,CACfL,EAAiBE,EAAM,WAAA,EAWvB,MAAMK,EAAejB,GACnBO,EACA,KAAK,KAAKQ,EAAY,IAAI,EAC1B,KAAK,KAAKA,EAAY,GAAG,CAAA,EAI3B,OACEE,GACA,mBAAoBA,GACpBA,EAAa,iBAAmBP,EAAe,iBAE/CC,EAAkBM,EAAa,aAG/BA,GACA,eAAgBA,GAChBA,EAAa,aAAeP,EAAe,iBAE3CC,EAAkBM,EAAa,QAE1B,EACT,CACA,MAAO,EACT,CAAC,EAEGP,EACK,CACL,KAAMA,EAAe,eACrB,OAAQC,CAAA,EAIL,CAAE,KAAMH,EAAS,OAAQ,CAAA,CAClC,CAGF,EAEMC,GAAoC,CACxCD,EACAF,IACwB,CACxB,MAAMY,EAAOV,EAAQ,sBAAA,EACfW,EAAuBC,GAC3BF,EACAZ,CAAA,EAGF,IAAIe,EAUAF,IAAyB,UAAYA,IAAyB,UAChEE,EAAmBb,GAGrB,UAAWc,KAASd,EAAQ,SAAU,CACpC,MAAMe,EAAkBd,GAAkCa,EAAOhB,CAAQ,EAEzE,GAAIiB,EACF,OAAOA,CAEX,CAEA,OAAOF,CACT,EAEA,SAASD,GACPI,EACA,CAAE,KAAAC,EAAM,MAAAC,GACR,CAEA,OAAIF,EAAQ,MAAQC,GAAQD,EAAQ,OAASC,EAAa,SACtDD,EAAQ,MAAQC,GAAQD,EAAQ,MAAQC,GAAQD,EAAQ,OAASE,EAC5D,mBACLF,EAAQ,MAAQE,GAASF,EAAQ,MAAQE,EAAc,kBACvDF,EAAQ,KAAOE,EAAc,QAC1B,QAKT,CAEA,SAASV,GAAuBQ,EAAsBlB,EAAoB,CACxE,OAAO,MAAM,KAAKkB,CAAO,EAAE,KAAMA,GAAY,CAC3C,MAAMG,EAAWP,GAAqCI,EAASlB,CAAQ,EAEvE,OAAIqB,IAAa,UAAYA,IAAa,OAI5C,CAAC,CACH,CAEO,MAAMC,GAAmB,CAACC,EAAYC,IAAmB,CAC9D,GACED,EAAK,WAAa,KAAK,oBACvBA,EAAK,WAAa,KAAK,mBACvB,CACA,MAAMjB,EAAQiB,EAAK,eAAe,YAAA,EAClCjB,GAAO,mBAAmBiB,CAAI,EAE9B,GAAI,CACEC,IAAWlB,GAAO,WAAa,IACjCA,GAAO,SAASiB,EAAMC,GAAU,CAAC,CAErC,OAASC,EAAG,CACVlC,EAAO,MAAMkC,CAAC,CAChB,CAEA,OAAOnB,CACT,CAGF,EAEaoB,GAAkBC,GAAwC,CACrE,GACGA,GAAwB,QACxBA,GAAO,QAAoB,eAAe,YAC3C,CACA,MAAMC,EAAaD,GAAO,QAAoB,eAC1C,YAEJ,GAAIC,EAAU,cAAgBD,aAAiBC,EAAU,aACvD,MAAO,EAEX,CAEA,GAAKD,GAAwB,MAAM,OAAQ,CACzC,MAAMC,EAAaD,GAAwB,KAG3C,GAAIC,EAAU,cAAgBD,aAAiBC,EAAU,aACvD,MAAO,EAEX,CAEA,MAAInC,EAAAA,GAAc,SAASkC,EAAM,IAAI,CAKvC,EAEaE,GAAgBF,GAAsC,CACjE,GAAID,GAAeC,CAAK,EAAG,MAAO,GAElC,GACGA,GAAsB,QACtBA,GAAO,QAAoB,eAAe,YAC3C,CACA,MAAMC,EAAaD,GAAO,QAAoB,eAC1C,YAEJ,GAAIC,EAAU,WACZ,OAAOD,aAAiBC,EAAU,UAEtC,CAEA,GAAKD,GAAsB,MAAM,OAAQ,CACvC,MAAMC,EAAaD,GAAsB,KAEzC,GAAIC,EAAU,WACZ,OAAOD,aAAiBC,EAAU,UAEtC,CAEA,MAAO,EACT,EAEaE,GAAgBH,GAAsC,CACjE,GACGA,GAAsB,QACtBA,GAAO,QAAoB,eAAe,YAC3C,CACA,MAAMC,EAAaD,GAAO,QAAoB,eAC1C,YAEJ,GAAIC,EAAU,WACZ,OAAOD,aAAiBC,EAAU,UAEtC,CAEA,GAAKD,GAAsB,MAAM,OAAQ,CACvC,MAAMC,EAAaD,GAAsB,KAEzC,GAAIC,EAAU,WACZ,OAAOD,aAAiBC,EAAU,UAEtC,CAEA,MAAO,EACT,EAEaG,GAAc,IAAM,SAAS,cAAc,KAAK,EAEhDC,GACXC,GACG,CACH,MAAMC,EAAoB,CACxB,MACA,QACA,QACA,SACA,OACA,QAAA,EACA,KAAK,GAAG,EAEV,OAAO,MAAM,KAAKD,GAAW,iBAAiBC,CAAiB,GAAK,EAAE,CACxE,EAOaC,GAAuBF,GAA2C,CAW7E,GAV0BD,GAAsBC,CAAS,EAEvC,QAAS/B,GAAY,CACrC,MAAMkC,EAAMlC,EAAQ,aAAa,KAAK,GAAKA,EAAQ,aAAa,MAAM,EAElEkC,GAAK,WAAW,OAAO,GACzBH,GAAW,aAAa,IAAI,gBAAgBG,CAAG,CAEnD,CAAC,EAEGH,EAAW,CACb,MAAMI,EAAc,MAAM,KAAKJ,EAAU,aAAe,CAAA,CAAE,EAE1D,UAAWK,KAASD,EAAa,CAC/B,MAAME,EAAQ,MAAM,KAAKD,EAAM,UAAY,CAAA,CAAE,EAE7C,UAAWE,KAAQD,EACjB,GACEN,EAAU,aACVO,aAAgBP,EAAU,YAAY,gBACtC,CAMA,MAAMQ,EAFMD,EAAK,MAAM,iBAAiB,KAAK,EAExB,MAAM,kBAAkB,EAEzCC,GACFA,EAAS,QAASL,GAAQ,CACxBH,GAAW,aAAa,IAAI,gBAAgBG,CAAG,CACjD,CAAC,CAEL,CAEJ,CACF,CACF,EAQO,SAASM,GACdC,EACAC,EACAC,EAA+B,CAAA,EACrB,CACV,GAAI,OAAOF,GAAQ,UAAYA,IAAQ,KAAM,MAAO,GAGpD,UAAWG,KAAQF,EACjB,GAAI,EAAEE,KAAQH,GAAM,MAAO,GAI7B,UAAWI,KAAUF,EAEnB,GAAIE,KAAUJ,GAAO,OAAQA,EAAYI,CAAM,GAAM,WACnD,MAAO,GAIX,MAAO,EACT,CAYO,SAASC,GAAc9C,EAA0C,CACtE,OACEwC,GACExC,EACA,CAAC,UAAU,EACX,CAAA,CAAC,GAEGA,EAAgB,WAAa,KAAK,YAE5C,CAQO,SAAS+C,GACd/C,EACAgD,EACqC,CACrC,OACEF,GAAc9C,CAAO,GACrBA,EAAQ,QAAQ,YAAA,IAAkBgD,EAAQ,YAAA,CAE9C,CAEO,SAASC,GAAYjD,EAAoC,CAC9D,OAAOwC,GACLxC,EACA,CACE,iBACA,eACA,cACA,YACA,YACA,yBAAA,EAEF,CAAC,WAAY,SAAU,oBAAoB,CAAA,CAE/C,CAEO,MAAMkD,EAAY,CACvBzD,EACA0D,EACAC,EACAC,IACG,CACH,MAAMC,EAAY7D,EAAI,cAAc,OAAO,EAC3C,OAAA6D,EAAU,GAAKH,EACfG,EAAU,UAAYF,EAElBC,EACF5D,EAAI,KAAK,QAAQ6D,CAAS,EAE1B7D,EAAI,KAAK,YAAY6D,CAAS,EAGzB,IAAM,CACXC,EAAU9D,EAAK0D,CAAE,CACnB,CACF,EAEaI,EAAY,CAAC9D,EAAe0D,IAAe,CACtD,GAAI1D,GAAK,KAAM,CACb,MAAM+D,EAAe/D,EAAI,eAAe0D,CAAE,EAEtCK,GACFA,EAAa,OAAA,CAEjB,CACF,ECncaC,GAA8B,CAACC,EAAgBC,IAAgB,CAC1E,MAAMC,EAAS,IAAI,OAAO,GAAGD,CAAG,qBAAsB,GAAG,EACnDE,EAAQH,EAAO,MAAME,CAAM,GAAK,CAAA,EAChCE,EAAaD,EAAM,CAAC,GAAK,IAE/B,OAAQA,GAAS,OAAO,WAAWC,CAAU,GAAM,CACrD,EAEaC,GAAmB,CAC9BC,EACAb,EACAC,EACAC,IACG,CACEW,GAAc,iBAAiB,MAEpCC,EAAoBD,EAAa,gBAAiBb,EAAIC,EAAOC,CAAO,CACtE,EAEaE,GAAY,CAACS,EAAiCb,IAAe,CACnEa,GAAc,iBAEnBE,EAAoBF,EAAa,gBAAiBb,CAAE,CACtD,EAEagB,EAAmB,CAC9BH,EACAb,EACAC,EACAC,IACG,CACH,GAAI,CAACW,EAAc,OAEnB,MAAMI,EAAkBJ,GAAc,iBAAiB,eACrDb,CAAA,EAGF,GAAIiB,EAAiB,CACnBA,EAAgB,UAAYhB,EAC5B,MACF,CAEAW,GAAiBC,EAAcb,EAAIC,EAAOC,CAAO,CACnD,EAEagB,EAAwBC,GAAyC,CAC5E,GAAIA,GAAO,gBAAiB,CAE1B,MAAMC,EADMD,EAAM,gBACc,cAAc,uBAAuB,EAErE,GAAIC,EAAqB,CACvB,MAAMC,EAAkBD,EAAoB,aAAa,SAAS,EAElE,GAAIC,EAAiB,CACnB,MAAMC,EAAQhB,GAA4Be,EAAiB,OAAO,EAC5DE,EAASjB,GAA4Be,EAAiB,QAAQ,EAEpE,OAAIC,EAAQ,GAAKC,EAAS,EACjB,CACL,YAAa,GACb,MAAAD,EACA,OAAAC,CAAA,EAGG,CAAE,YAAa,EAAA,CACxB,CACF,CACF,CAEA,MAAO,CAAE,YAAa,EAAA,CACxB,EAEaC,GAAoBC,GAC/BA,EAAO,KACLC,EAAAA,UAAWP,GAEPA,EAAM,MAAQ,eACdA,EAAM,iBAAiB,aAAe,YACtCA,EAAM,gBAAgB,KAEfQ,EAAAA,GAAGR,CAAK,EAGVS,EAAAA,UAAUT,EAAO,MAAM,EAAE,KAC9BU,EAAAA,KAAK,CAAC,EACNC,EAAAA,IAAI,IAAMX,CAAK,CAAA,CAElB,CACH,EAEWY,GAAqBN,GAChCA,EAAO,KACLC,EAAAA,UAAWP,GAAU,CACnB,MAAMa,EAAeb,GAAO,iBAAiB,MAAM,MAEnD,OAAIa,EACKC,EAAAA,KAAKD,CAAY,EAAE,KAAKF,EAAAA,IAAI,IAAMX,CAAK,CAAC,EAG1CQ,EAAAA,GAAG,MAAS,CACrB,CAAC,CACH,EC7GWO,GAETC,GAEDC,GAA2C,CAC1C,MAAMC,EAASF,EAAKC,CAAO,EAErBE,EAAW,IAAI,qBAAsBC,GAAY,CACrDA,EAAQ,QAASC,GAAU,CACrBA,EAAM,eACRA,EAAM,OAAO,gBAAgB,WAAW,EAExCA,EAAM,OAAO,aAAa,YAAa,IAAI,CAE/C,CAAC,CACH,EAAG,CAAA,CAAE,EAEL,OAAAH,EAAO,YAAY,SACjB,sBACA,CAAC,CAAE,OAAAI,EAAQ,QAAAC,KAAc,CACvB,MAAMC,EAAON,EAAO,kBAAkB,IAAII,CAAM,EAEhD,GAAI,CAACE,EAAM,OAEX,MAAMxB,EAAQwB,EAAK,SAAS,iBAAA,EAE5B,GAAI,CAACxB,EAAO,OAEZH,EACEG,EACA,6BACA;AAAA;AAAA;AAAA;AAAA;AAAA,aAOM,EAMR,MAAMyB,EAAQzB,EAAM,iBAAiB,KAAK,iBAAiB,GAAG,EAE9DyB,GAAO,QAASC,GAAS,CACvBP,EAAS,QAAQO,CAAI,CACvB,CAAC,EAEDH,EAAQ,IAAM,CACZE,GAAO,QAASC,GAAS,CACvBP,EAAS,UAAUO,CAAI,CACzB,CAAC,CACH,CAAC,CACH,CAAA,EAGK,CACL,GAAGR,CAAA,CAEP,EC7DWS,GAETX,GAEDC,GAA2C,CAC1C,MAAMC,EAASF,EAAKC,CAAO,EA0B3B,OAAAC,EAAO,QACJ,MAAM,aAAa,EACnB,KAAKU,EAAAA,UAAUV,EAAO,QAAQ,QAAQ,CAAC,EACvC,UAAWW,GAAgB,CAC1B,GAAI,CAACA,EAAa,OAElB,MAAMC,EAAW,IAAM,CACjBZ,EAAO,SAAS,OAAO,uBAAyB,cAClDW,EAAY,SAAS,EAAG,CAAC,CAE7B,EAOAA,EAAY,iBAAiB,SAAUC,CAAQ,CACjD,CAAC,EAEHZ,EAAO,YAAY,SAAS,sBAAuB,CAAC,CAAE,OAAAI,KAAa,CAEjE,MAAMtB,EADOkB,EAAO,kBAAkB,IAAII,CAAM,GAC5B,SAAS,iBAAA,EAExBtB,GAOLA,EAAM,iBAAiB,KAAK,aAAa,WAAY,IAAI,CAC3D,CAAC,EAiBMkB,CACT,EC/EWa,GAAiC,CAAC,CAC7C,SAAAlF,EACA,aAAA6C,CACF,IAQM,CAEJ,MAAMsC,EAAYtC,EAAa,sBAAA,EACzBuC,EAASD,EAAU,MAAQtC,EAAa,YACxCwC,EAASF,EAAU,OAAStC,EAAa,aAGzC,CAAE,KAAA/C,EAAO,EAAG,IAAAwF,EAAM,GAAMH,EAKxBI,EAAYvF,EAAS,QAAUoF,EAAStF,EACxC0F,EAAYxF,EAAS,QAAUqF,EAASC,EAE9C,MAAO,CACL,QAASC,EACT,QAASC,CAAA,CAEb,ECjCaC,GAA4B,CAGvCnF,EACAoF,EACAC,EACAhH,IACG,CACH,MAAMiH,EAAgBF,GAAqB,MAAM,aAEjD,GAAI,CAACA,GAAuB,CAACE,EAAe,OAAOtF,EAEnD,MAAMuF,EAAYF,EAAQ,uBAAuBC,CAAa,EACxD/C,EAAe+C,EACf,CAAE,OAAQE,EAAY,MAAOC,CAAA,EAAcpH,EAAS,SAE1D,GAAI,CAACkH,GAAa,EAAEhD,aAAwB,mBAAoB,OAAOvC,EAEvE,GAAID,GAAeC,CAAK,EAAG,CACzB,KAAM,CAAE,QAAA0F,EAAS,QAAAC,CAAA,EAAYf,GAA+B,CAC1D,SAAU5E,EACV,aAAAuC,CAGF,CAAC,EAEKqD,EAAW,IAAI,aAAa5F,EAAM,KAAM,CAC5C,GAAGA,EACH,UAAWA,EAAM,UACjB,QAAA0F,EACA,QAAAC,CAAA,CACD,EAED,cAAO,eAAeC,EAAU,SAAU,CACxC,MAAOR,EAAoB,OAC3B,WAAY,EAAA,CACb,EAEMQ,CACT,CAEA,GAAI1F,GAAaF,CAAK,EAAG,CACvB,KAAM,CAAE,QAAA0F,EAAS,QAAAC,CAAA,EAAYf,GAA+B,CAC1D,SAAU5E,EACV,aAAAuC,CAGF,CAAC,EAEKqD,EAAW,IAAI,WAAW5F,EAAM,KAAM,CAC1C,GAAGA,EACH,QAAA0F,EACA,QAAAC,CAAA,CACD,EAED,cAAO,eAAeC,EAAU,SAAU,CACxC,MAAOR,EAAoB,OAC3B,WAAY,EAAA,CACb,EAEMQ,CACT,CAEA,GAAIzF,GAAaH,CAAK,EAAG,CACvB,MAAM6F,EAAU,MAAM,KAAK7F,EAAM,OAAO,EAAE,IAAK8F,GAAU,CACvD,KAAM,CAAE,QAAAJ,EAAS,QAAAC,CAAA,EAAYf,GAA+B,CAC1D,SAAUkB,EACV,aAAAvD,CAGF,CAAC,EAED,OAAO,IAAI,MAAM,CACf,WAAYuD,EAAM,WAClB,OAAQA,EAAM,OACd,QAAAJ,EACA,QAAAC,CAAA,CACD,CACH,CAAC,EAEKC,EAAW,IAAI,WAAW5F,EAAM,KAAM,CAC1C,QAAA6F,EACA,eAAgBA,EAChB,cAAeA,CAAA,CAChB,EAED,cAAO,eAAeD,EAAU,SAAU,CACxC,MAAOR,EAAoB,OAC3B,WAAY,EAAA,CACb,EAEMQ,CACT,CAEA,OAAO5F,CACT,ECrFM+F,GAAoB,CAAC,GAXL,CACpB,gBACA,cACA,eACA,eACA,cACA,aACA,cACA,WACF,CAEgE,EAEnDC,GAETnC,GAEDC,GAA2C,CAC1C,MAAMC,EAASF,EAAKC,CAAO,EAE3B,OAAAC,EAAO,YAAY,SACjB,sBACA,CAAC,CAAE,QAAAK,EAAS,OAAAD,KAAa,CACvB,MAAME,EAAON,EAAO,kBAAkB,IAAII,CAAM,EAE1CtB,EAAQwB,GAAM,SAAS,iBAAA,EAE7B,GAAI,CAACxB,GAAS,CAACwB,EAAM,OAMrB,MAAM4B,EAAaF,GAAkB,IAAK/F,GAAU,CAClD,MAAMkG,EAAYpG,GAA8C,CAC9D,IAAIqG,EAAiBrG,EAWrB,GAJIC,GAAeD,CAAC,IAClBqG,EAAiB,IAAI,aAAarG,EAAE,KAAMA,CAAC,GAGzCqG,IAAmBrG,EAAG,CACxB,MAAMsG,EAAkBjB,GACtBgB,EACArG,EACAiE,EAAO,MAAM,QACbA,EAAO,QAAA,EAGTA,EAAO,QAAQ,MAAM,aAAa,cAAcqC,CAAe,CACjE,CACF,EAEA,OAAAvD,EAAM,iBAAiB,iBAAiB7C,EAAOkG,CAAQ,EAEhD,IAAM,CACXrD,EAAM,iBAAiB,oBAAoB7C,EAAOkG,CAAQ,CAC5D,CACF,CAAC,EAED9B,EAAQ,IAAM,CACZ6B,EAAW,QAASI,GAAO,CACzBA,EAAA,CACF,CAAC,CACH,CAAC,CACH,CAAA,EAGKtC,CACT,EC5EWuC,GAAqBC,GAAe,CAC/C,MAAMxC,EAAS,IAAI,WAEnB,OAAO,IAAI,QAAiByC,GAAY,CACtCzC,EAAO,iBACL,OACA,IAAM,CACJyC,EAAQzC,EAAO,MAAgB,CACjC,EACA,EAAA,EAGFA,EAAO,cAAcwC,CAAI,CAC3B,CAAC,CACH,EAEaE,GAAO,CAClBzF,EACA0F,IAEO,OAAO,QAAQ1F,CAAG,EAAE,OACzB,CAAC2F,EAAK,CAACzE,EAAKgC,CAAK,IAEXwC,EAAK,SAASxE,CAAU,EACnB,CACL,GAAGyE,EACH,CAACzE,CAAG,EAAGgC,CAAA,EAIJyC,EAET,CAAA,CAAC,EC7BQC,GACXF,GAEOlD,EAAAA,IAAKxC,GAAQyF,GAAKzF,EAAK0F,CAAI,CAAC,EAGxBG,EAC4CH,GACtDvD,GACQA,EAAO,KAAKyD,GAAUF,CAAI,EAAGI,EAAAA,qBAAqBC,EAAAA,cAAc,CAAC,EAGrE,SAASC,EACdzI,EACmC,CACnC,OAAO,IAAI0I,EAAAA,WAAmCjD,GAAa,CACzD,MAAMkD,EAAiB,IAAI,eAAgBjD,GAAY,CACrDD,EAAS,KAAKC,CAAO,CACvB,CAAC,EAED,OAAAiD,EAAe,QAAQ3I,CAAO,EAEvB,IAAM,CACX2I,EAAe,WAAA,CACjB,CACF,CAAC,CACH,CAEO,MAAMC,EACPC,GACAjE,GACFA,EAAO,KACLC,EAAAA,UAAWiE,GACTD,EAAc,KACZE,QAAA,EACA9D,EAAAA,IAAI,IAAM6D,CAAK,CAAA,CACjB,CAEJ,EAESE,GAAsBpE,GAA0B,CAC3D,IAAIkE,EAEJ,MAAMG,EAAMrE,EAAO,UAAWsE,GAAW,CACvCJ,EAAQ,CAAE,OAAAI,CAAA,CACZ,CAAC,EAED,MAAO,KACLD,EAAI,YAAA,EAEAH,EACKhE,EAAAA,GAAGgE,EAAM,MAAM,EAGjBlE,EAEX,EAEO,SAASuE,GAAyB,CACvC,OAAO,IAAIT,EAAAA,WAAkBjD,GAAa,CAExC,GAAI,OAAO,oBAAqB,CAC9B,MAAM2D,EAAS,OAAO,oBAAoB,IAAM,CAC9C3D,EAAS,KAAA,EACTA,EAAS,SAAA,CACX,CAAC,EAED,MAAO,IAAM,mBAAmB2D,CAAM,CACxC,CAEA,MAAMC,EAAU,WAAW,IAAM,CAC/B5D,EAAS,KAAA,EACTA,EAAS,SAAA,CACX,EAAG,CAAC,EAEJ,MAAO,IAAM,aAAa4D,CAAO,CACnC,CAAC,CACH,CAEO,SAASC,GAAaC,EAA+B,CAC1D,OAAOC,EAAAA,MAAM,IAAML,EAAA,EAAO,KAAKtE,EAAAA,UAAU0E,CAAQ,CAAC,CAAC,CACrD,CAEO,MAAME,GAAkB,CAC7BC,EACAnE,IAEO,IAAImD,EAAAA,WAA8BiB,GAAe,CACtD,MAAMlE,EAAW,IAAI,iBAAkBmE,GAAc,CACnDD,EAAW,KAAKC,CAAS,CAC3B,CAAC,EAED,OAAAnE,EAAS,QAAQiE,EAAQnE,CAAO,EAEzB,IAAME,EAAS,WAAA,CACxB,CAAC,EAGI,SAASoE,GACd7J,EACAuF,EACyC,CACzC,OAAO,IAAImD,EAAAA,WAAyCjD,GAAa,CAC/D,MAAMqE,EAAuB,IAAI,qBAAsBpE,GAAY,CACjED,EAAS,KAAKC,CAAO,CACvB,EAAGH,CAAO,EAEV,OAAAuE,EAAqB,QAAQ9J,CAAO,EAE7B,IAAM,CACX8J,EAAqB,WAAA,CACvB,CACF,CAAC,CACH,CCrGO,MAAeC,EAUtB,CAWE,YACEC,EACAC,EAIA,CACA,KAAK,gBAAkBA,EAEvB,MAAMC,EAAgBC,EAAAA,sBACpB,KAAK,mBAAA,EACLH,CAAA,EAGF,KAAK,eAAiB,KAAK,sBAAsBE,CAAa,EAC9D,KAAK,cAAgBC,EAAAA,sBACnB,KAAK,mBAAA,EACLH,CAAA,EAEF,KAAK,4BAA8B,IAAII,UAEvC,KAAK,QAAUC,gBAAc,CAC3B,KAAK,gBAAgB,QACrB,KAAK,4BAA4B,KAAKC,EAAAA,UAAU,KAAK,cAAc,CAAC,CAAA,CACrE,EAAE,KACDrF,MAAI,CAAC,CAACsF,EAAgBC,CAAQ,KAAO,CAAE,GAAGD,EAAgB,GAAGC,CAAA,EAAW,EACxEC,EAAAA,YAAY,CAAC,CAAA,EAGf,KAAK,QAAQ,UAAA,CACf,CAeA,eAAeD,EAGb,CACA,MAAME,EAAsB,KAAK,8BAA8BF,CAAQ,EAEjEG,EACJ,KAAK,gBAAgB,eAAeD,CAAmB,EAEnDR,EAAgBC,EAAAA,sBAAsB,KAAK,cAAeK,CAAQ,EAElEI,EAAiB,KAAK,sBAAsBV,CAAa,EACzDW,EAAa,KAAK,mBAAmBD,CAAc,EAEzD,MAAO,CACL,WAAYC,GAAcF,EAA4B,WACtD,OAAQ,KACN,KAAK,cAAgBT,EACrB,KAAK,eAAiBU,EAElB,CAACD,EAA4B,YAAcE,GAC7C,KAAK,4BAA4B,KAAKD,CAAc,EAK/C,CACL,GAH2BD,EAA4B,OAAA,EAIvD,GAAGC,CAAA,EAEP,CAEJ,CAEO,OAAOJ,EAAwD,CACpE,KAAM,CAAE,OAAAM,CAAA,EAAW,KAAK,eAAeN,CAAQ,EAE/CM,EAAA,CACF,CAEA,IAAI,QAAgD,CAClD,MAAO,CACL,GAAG,KAAK,gBAAgB,OACxB,GAAG,KAAK,cAAA,CAEZ,CAOO,MACLC,EACA,CACA,OAAI,MAAM,QAAQA,CAAS,EAClB,KAAK,QAAQ,KAAKzC,EAAUyC,CAAS,CAAC,EAGxC,KAAK,QAAQ,KAClB9F,EAAAA,IAAKiE,GAAWA,EAAO6B,CAAS,CAAC,EACjCxC,EAAAA,qBAAqBC,EAAAA,cAAc,CAAA,CAEvC,CAEO,SAAU,CACf,KAAK,4BAA4B,SAAA,CACnC,CACF,QC/IO,cAGGuB,EAKR,CACA,sBACES,EAC4B,CAC5B,OAAOA,CACT,CAEA,mBAAmBQ,EAAwD,CACzE,MAAO,CAACxC,EAAAA,eAAe,KAAK,eAAgBwC,CAAiB,CAC/D,CAEA,8BACER,EACqB,CACrB,KAAM,CACJ,kBAAmBS,EACnB,UAAWC,EACX,WAAYC,EACZ,WAAYC,EACZ,GAAGC,CAAA,EACDb,EAEJ,OAAOa,CACT,CAEA,oBAAiD,CAC/C,MAAO,CACL,UAAW,EACX,WAAY,YACZ,WAAY,YACZ,kBAAmB,WAAA,CAEvB,CACF,EClBO,MAAMC,GAiBThG,GAEDC,GAA0E,CACzE,KAAM,CAAE,UAAAgG,EAAW,WAAAC,EAAY,WAAAC,EAAY,kBAAAC,GAAsBnG,EAC3DoG,EAAW,IAAIvB,UACf5E,EAASF,EAAKC,CAAO,EAErB0E,EAAkB,IAAI2B,GAI1B,CACE,UAAAL,EACA,WAAAC,EACA,WAAAC,EACA,kBAAAC,CAAA,EAEFlG,EAAO,QAAA,EAMHqG,EAAW,IAAM;AAAA;AAAA;AAAA,QAYnB5B,EAAgB,OAAO,YAAc,EAAI,cAAcA,EAAgB,OAAO,SAAS,iBAAmB,EAAE;AAAA,QAC5GA,EAAgB,OAAO,aAAe,YAAc,gBAAgBA,EAAgB,OAAO,UAAU,eAAiB,EAAE;AAAA,QACxHA,EAAgB,OAAO,aAAe,YAAc,gBAAgBA,EAAgB,OAAO,UAAU,eAAiB,EAAE;AAAA,QACxHA,EAAgB,OAAO,oBAAsB,YAAc,eAAeA,EAAgB,OAAO,iBAAiB,eAAiB,EAAE;AAAA;AAAA,IAOnI6B,EAA2BC,GAA2B,CAC1DvG,EAAO,kBAAkB,MAAM,QAASM,GAAS,CAC/C,GAAIA,EAAK,kBAAoB,gBAAiB,CAC5C,MAAMxB,EAAQwB,EAAK,SAAS,iBAAA,EAExBxB,GACFH,EAAiBG,EAAO,qBAAsBuH,EAAA,CAAU,CAE5D,CACF,CAAC,EAEGE,GACFvG,EAAO,OAAA,CAEX,EAKAA,EAAO,YAAY,SAAS,sBAAuB,CAAC,CAAE,OAAAI,KAAa,CACjE,MAAME,EAAON,EAAO,kBAAkB,IAAII,CAAM,EAEhD,GAAIE,GAAM,kBAAoB,gBAAiB,CAC7C,MAAMxB,EAAQwB,GAAM,SAAS,iBAAA,EAEzBxB,GACFH,EAAiBG,EAAO,qBAAsBuH,EAAA,CAAU,CAE5D,CACF,CAAC,EAED,MAAMG,EACJC,GAEAA,EAAO,KACLC,WAAA,EACAjH,EAAAA,IAAI,CAAC,CAACkH,EAAKC,CAAM,IACXA,EAAO,YAAcD,EAAI,WACzBC,EAAO,aAAeD,EAAI,UAG/B,CAAA,EAGL,OAAAlC,EAAgB,QACb,KACC+B,EACAK,EAAAA,IAAIP,CAAuB,EAC3B5F,YAAUV,EAAO,EAAE,QAAQ,CAAA,EAE5B,UAAA,EAEI,CACL,GAAGA,EACH,QAAS,IAAM,CACbmG,EAAS,SAAA,EACT1B,EAAgB,QAAA,EAChBzE,EAAO,QAAA,CACT,EACA,SAAUyE,CAAA,CAEd,ECjJWqC,GAMThH,GAEDC,GAA2C,CAC1C,MAAMC,EAASF,EAAKC,CAAO,EAErBgH,EAAiBC,GACrBzH,EAAAA,UAAyByH,EAAU,OAAO,EAAE,KAC1CvH,EAAAA,IAAK1D,GAAM,CACT,KAAM,CAAE,kBAAAkL,EAAmB,qBAAAC,CAAA,EACzBlH,EAAO,SAAS,OAElB,GAAIkH,IAAyB,aAC3B,OAAOnL,EAGT,GAAIkL,IAAsB,aAAc,CACtC,GAAIlL,EAAE,MAAQ,aACZ,OAAOiE,EAAO,WAAW,UAAA,EAG3B,GAAIjE,EAAE,MAAQ,YACZ,OAAOiE,EAAO,WAAW,SAAA,CAE7B,CAEA,GAAIiH,IAAsB,WAAY,CACpC,GAAIlL,EAAE,MAAQ,YACZ,OAAOiE,EAAO,WAAW,UAAA,EAG3B,GAAIjE,EAAE,MAAQ,UACZ,OAAOiE,EAAO,WAAW,SAAA,CAE7B,CAEA,OAAOjE,CACT,CAAC,CAAA,EAGL,OAAAgL,EAAc,QAAQ,EAAE,KAAKrG,EAAAA,UAAUV,EAAO,EAAE,QAAQ,CAAC,EAAE,UAAA,EAE3DA,EAAO,kBAAkB,OACtB,KACCX,EAAAA,UAAW8H,GACTC,EAAAA,MACE,GAAGD,EAAW,IAAK7G,GACjBA,EAAK,MAAM,UAAU,EAAE,KACrBjB,EAAAA,UAAU,IAAM,CACd,MAAM7E,EAAU8F,EAAK,SAAS,iBAAA,EAE9B,OAAO9F,aAAmB,mBACxBA,GAAS,gBACPuM,EAAcvM,EAAQ,eAAe,EACrC6M,EAAAA,KACN,CAAC,CAAA,CACH,CACF,CACF,EAEF3G,YAAUV,EAAO,EAAE,QAAQ,CAAA,EAE5B,UAAA,EAEIA,CACT,EC5EWsH,GAAetH,GACnBA,EAAO,MAAM,kBAAkB,OAAO,KAC3CX,EAAAA,UAAWkI,GACTH,EAAAA,MACE,GAAGG,EAAM,IAAKjH,GACLA,EAAK,MAAM,UAAU,EAAE,KAC5BjB,EAAAA,UAAU,IAAM,CACd,MAAMP,EAAQwB,EAAK,SAAS,iBAAA,EAE5B,GAAI,CAACxB,GAAS,CAACA,GAAO,gBAAiB,OAAO0I,EAAAA,MAM9C,MAAMC,EAJiB,MAAM,KAC3B3I,EAAM,gBAAgB,iBAAiB,GAAG,CAAA,EAGb,IAAKtE,GAClC+E,EAAAA,UAAsB/E,EAAS,OAAO,CAAA,EAGxC,OAAO4M,EAAAA,MAAM,GAAGK,CAAO,CACzB,CAAC,CAAA,CAEJ,CAAA,CACH,EAEFZ,EAAAA,IAAK5K,GAAU,CACbA,EAAM,eAAA,CACR,CAAC,EACDyL,EAAAA,MAAA,CAAM,ECdH,MAAMC,UAEHzE,EAAAA,UAAc,CAItB,YAAY0E,EAAiB,CAC3B,MAAOzD,GACO,KAAK,aACd,KAAKzD,EAAAA,UAAU,KAAK,SAAS,CAAC,EAC9B,UAAUyD,CAAU,CAGxB,EATH,KAAU,UAAY,IAAIS,UA4C1B,KAAO,SAAW,KAAK,UAAU,aAAA,EAlC/B,KAAK,aAAe,IAAIiD,EAAAA,gBAAmBD,CAAY,CACzD,CAEU,KAAKtE,EAAU,CACvB,KAAK,aAAa,KAAKA,CAAK,CAC9B,CAKU,aAAawE,EAAwB,CAC7C,MAAMC,EAAW,CAAE,GAAG,KAAK,MAAO,GAAGD,CAAA,EAEjC9E,iBAAe,KAAK,MAAO+E,CAAQ,GAEvC,KAAK,aAAa,KAAKA,CAAQ,CACjC,CAIO,MAAyBxC,EAAoB,CAClD,OAAI,MAAM,QAAQA,CAAS,EAClB,KAAK,aAAa,KAAKzC,EAAUyC,CAAS,CAAC,EAE7C,KAAK,aAAa,KACvB9F,EAAAA,IAAKiE,GAAWA,EAAO6B,CAAS,CAAC,EACjCxC,EAAAA,qBAAqBC,EAAAA,cAAc,CAAA,CAEvC,CAEA,IAAW,OAAQ,CACjB,OAAO,KAAK,aAAa,KAC3B,CAIO,SAAU,CACf,KAAK,aAAa,SAAA,EAClB,KAAK,UAAU,SAAA,CACjB,CACF,CCdO,MAAegF,GAAf,MAAeA,WAAyBL,CAAsC,CAsCnF,YAAYM,EAQT,CACD,MAAM,CACJ,MAAO,OACP,MAAO,MAAA,CACR,EA/CH,KAAQ,eAAiB,IAAIrD,UAiD3B,KAAK,QAAUqD,EAAO,QACtB,KAAK,SAAWA,EAAO,SACvB,KAAK,YAAcA,EAAO,YAC1B,KAAK,KAAOA,EAAO,KACnB,KAAK,iBAAmBA,EAAO,iBAC/B,KAAK,iBAAmBA,EAAO,iBAC/B,KAAK,SAAWA,EAAO,SAEvB,MAAMC,EAAiB,KAAK,eAAe,KACzCC,EAAAA,OAAQC,GAAYA,EAAQ,OAAS,QAAQ,CAAA,EAGzCC,EAAe,KAAK,eAAe,KACvCF,EAAAA,OAAQC,GAAYA,EAAQ,OAAS,MAAM,CAAA,EAG7C,KAAK,QAAUC,EAAa,KAC1BC,EAAAA,SAAS,IAEL,KAAK,MAAM,QAAU,UAAY,KAAK,MAAM,QAAU,UAE/BjB,EAAAA,OAEzB,KAAK,KAAK,CAAE,MAAO,UAAW,MAAO,OAAW,EAExB,KAAK,iBAAA,EAAmB,KAAK9D,EAAAA,OAAO,EAErC,KACrB+E,EAAAA,SAAUC,IACR,KAAK,YAAY,QAAQ,yBAA0B,KAAK,KAAK,GAAI,CAC/D,OAAQ,KAAK,KAAK,GAClB,kBAAAA,CAAA,CACD,EAEqB,KAAK,eAAA,EAAiB,KAC1CC,EAAAA,QAAQ,IAAI,EACZjF,EAAAA,MAAA,CAAM,EAGa,KACnBH,EAAc,KAAK,QAAQ,YAAY,aAAa,EACpD/D,EAAAA,UAAU,IAAM,CACd,MAAMoJ,EAAc,KAAK,YACtB,QAAQ,sBAAuB,KAAK,KAAK,GAAI,CAC5C,OAAQ,KAAK,KAAK,GAClB,kBAAAF,CAAA,CACD,EACA,OACE7E,GACCA,aAAkBR,EAAAA,UAAA,EAGxB,OAAO2B,EAAAA,cAAc,CAACvF,EAAAA,GAAG,IAAI,EAAG,GAAGmJ,CAAW,CAAC,EAAE,KAAKlF,EAAAA,OAAO,CAC/D,CAAC,CAAA,EAEJ,EACD9D,EAAAA,IAAI,IAAM,CACR,KAAK,KAAK,CAAE,MAAO,SAAU,MAAO,OAAW,CAGjD,CAAC,EACDiB,EAAAA,UAAUwH,CAAc,CAAA,EAE3B,EACDR,EAAAA,MAAA,CAAM,EAGR,KAAK,UAAYQ,EAAe,KAC9BI,EAAAA,SAAS,IAEL,KAAK,MAAM,QAAU,aAAe,KAAK,MAAM,QAAU,OAElCjB,EAAAA,OAEzB,KAAK,KAAK,CAAE,MAAO,YAAa,MAAO,OAAW,EAE3C,KAAK,QAAQ,YAAY,cAAc,KAC5C9D,QAAA,EACAlE,EAAAA,UAAU,KACR,KAAK,YAAY,QAAQ,sBAAuB,KAAK,KAAK,EAAE,EAE1C,KAAK,SAAA,EAAW,KAAKmJ,UAAQ,IAAI,EAAGjF,EAAAA,OAAO,EAG9D,EACD9D,EAAAA,IAAI,IAAM,CACR,KAAK,KAAK,CAAE,MAAO,OAAQ,MAAO,OAAW,CAG/C,CAAC,EACDiB,EAAAA,UAAU2H,CAAY,CAAA,EAEzB,EACDX,EAAAA,MAAA,CAAM,EAGRN,EAAAA,MAAM,KAAK,QAAS,KAAK,SAAS,EAC/B,KACCsB,EAAAA,WAAYC,IACV,KAAK,KAAK,CAAE,MAAO,QAAS,MAAAA,EAAO,EAE5BtB,EAAAA,MACR,EACD3G,EAAAA,UAAU,KAAK,QAAQ,CAAA,EAExB,UAAA,CACL,CAEU,qBAAqBlG,EAAsB,CACnD,KAAK,mBAAqBA,EAC1B,KAAK,mBAAmB,UAAU,IAChCwN,GAAiB,6BAAA,CAErB,CAEU,QAAS,CACb,KAAK,mBACP,KAAK,iBAAiB,YAAY,KAAK,iBAAiB,CAE5D,CAEU,QAAS,CACjB,KAAK,oBAAoB,OAAA,EACzB,KAAK,mBAAqB,MAC5B,CAEA,IAAW,QAAS,CAClB,OAAO,KAAK,YACd,CAEA,IAAW,WAAY,CACrB,OAAO,KAAK,OAAO,KAAKvI,MAAKmJ,GAAUA,EAAM,QAAU,QAAQ,CAAC,CAClE,CAEO,MAAO,CACZ,KAAK,eAAe,KAAK,CAAE,KAAM,OAAQ,CAC3C,CAEO,QAAS,CACd,KAAK,eAAe,KAAK,CAAE,KAAM,SAAU,CAC7C,CAKO,gBAEL,CACA,MAAMC,EAAiB,IAAIjE,UAE3B,OAAOZ,EAAAA,MAAM,IAAM,KAAK,iBAAiB,CAAE,QAAS6E,CAAA,CAAgB,CAAC,EAAE,KACrEL,EAAAA,QAAQ,MAAS,EACjBjF,QAAA,EACA9D,EAAAA,IAAKxF,GAAQ,CACX,GAAKA,EAEL,MAAO,CACL,IAAAA,EACA,QAAS,IAAM,CACb4O,EAAe,KAAK,MAAS,CAC/B,CAAA,CAEJ,CAAC,EACDC,EAAAA,SAAS,IAAM,CACbD,EAAe,SAAA,CACjB,CAAC,EACDH,EAAAA,WAAY3M,IACVlC,EAAO,MAAMkC,CAAC,EAEPuD,EAAAA,GAAG,MAAS,EACpB,CAAA,CAEL,CAEO,OAAO2I,EAAsB,CAClC,OAAO,KAAK,SAASA,CAAM,CAC7B,CAEO,SAAU,CACf,KAAK,OAAA,EACL,KAAK,aAAa,SAAA,EAElB,MAAM,QAAA,CACR,CAkCA,IAAI,mBAAoB,CACtB,OAAO,KAAK,kBACd,CAEA,IAAI,aAA2D,CAE/D,CAEA,IAAI,kBAA8C,CAElD,CAEA,IAAI,iBAAkB,CACpB,MAAMc,EAAsB,KAAK,KAAK,gBAEtC,GAAIA,EAAqB,OAAOA,EAEhC,MAAMC,EAAS,KAAK,iBAAA,EAEpB,GAAIA,EAAQ,CACV,KAAM,CAAE,YAAAC,CAAA,EAAgBpK,EAAqBmK,CAAM,EAEnD,GAAIC,EAAa,MAAO,eAC1B,CAEA,OAAO,KAAK,QAAQ,UAAU,iBAAmB,YACnD,CACF,EAvSEjB,GAAgB,8BACd,kCAFG,IAAekB,EAAflB,GCrDP,MAAMmB,GAAsB7I,GAA+B,IAAI,IAAIA,EAAK,IAAI,EAErE,MAAM8I,EAAgB,CAC3B,YACY9I,EACA0E,EACV,CAFU,KAAA,KAAA1E,EACA,KAAA,SAAA0E,CACT,CAEH,MAAa,aAAc,CAKzB,OAJiB,MAAMqE,EAAAA,cACrB,KAAK,SAAS,OAAO,cAAc,KAAK,IAAI,GAAK/J,EAAAA,GAAG,MAAS,CAAA,GAG5C6J,GAAmB,KAAK,IAAI,CACjD,CAEA,MAAa,eAAgB,CAC3B,MAAMG,EAAW,MAAM,KAAK,YAAA,EAE5B,OAAIA,aAAoB,SAAiBA,EAErCA,aAAoB,IAAY,MAAMA,CAAQ,EAE3CA,CACT,CACF,CCTA,MAAMC,GAAW,CAACC,EAAcC,IAAiB,CAE/C,MAAMC,EAAiBF,EAAK,WAAW,SAAS,EAC1CG,EAAWD,EAAiBF,EAAK,QAAQ,UAAW,SAAS,EAAIA,EACjE9F,EAAS,IAAI,IAAI+F,EAAME,CAAQ,EAAE,SAAA,EAGvC,OAAOD,EAAiBhG,EAAO,QAAQ,UAAW,SAAS,EAAIA,CACjE,EAEMkG,GAAgB,MACpB5C,EACAxM,EACAqP,EACAC,EACA9E,IACkB,CAClB,GAAI,CAACgC,GAAY,CAACA,EAAS,YAAa,OAExC,MAAMpK,EAAQpC,EAAQ,MAEtB,GAAKoC,EAEL,GAAI,CACF,MAAMC,EAAQ,MAAM,KAAKD,EAAM,UAAY,CAAA,CAAE,EAE7C,QAASmN,EAAI,EAAGA,EAAIlN,EAAM,OAAQkN,IAAK,CACrC,MAAMjN,EAAOD,EAAMkN,CAAC,EACpB,GACE/C,EAAS,aACTlK,aAAgBkK,EAAS,YAAY,gBACrC,CACA,MAAMgD,EAAMlN,EAAK,MAAM,iBAAiB,KAAK,EAG7C,GAFgBkN,EAAI,MAAM,4BAA4B,EAEzC,CAEX,MAAMC,EAAWD,EAAI,MAAM,GAAG,EAAE,IAAKE,GAASA,EAAK,MAAM,EAEnDC,EAAc,MAAM,QAAQ,IAChCF,EAAS,IAAI,MAAOC,GAAS,CAE3B,GAAIA,EAAK,WAAW,QAAQ,EAC1B,OAAOA,EAIT,MAAME,EAAWF,EAAK,MAAM,2BAA2B,EACvD,GAAI,CAACE,EAAU,OAAOF,EAEtB,MAAMG,EAAcD,EAAS,CAAC,GAAK,GAG7BE,EAAYR,EAAQ,UAAU,MAAM,KAAK,CAAC,CAAE,KAAAS,KACzC,GAAGhB,GAASM,EAAwBQ,CAAW,EAAE,YAAA,CAAa,GAAG,SACtE,GAAGE,EAAK,aAAa,EAAA,CAExB,EAED,GAAID,EAAW,CACb,MAAME,EAAkB,IAAIpB,GAAgBkB,EAAWtF,CAAQ,EAE/D,GAAI,CACF,MAAMsE,EAAW,MAAMkB,EAAgB,YAAA,EAEvC,GAAIlB,aAAoB,SAAU,CAChC,MAAMmB,EAAO,MAAMnB,EAAS,KAAA,EACtBoB,EACJ1D,EAAS,aAAa,IAAI,gBAAgByD,CAAI,EAQhD,OALgBP,EAAK,QACnBE,EAAS,CAAC,EACV,QAAQM,CAAO,IAAA,CAInB,CACF,OAAS3O,EAAG,CACV,QAAQ,MAAM,sBAAuBA,CAAC,CACxC,CACF,CACA,OAAOmO,CACT,CAAC,CAAA,EAMGS,EAAU7N,EAAK,QAAQ,QAC3B,gBACA,QAAQqN,EAAY,KAAK,IAAI,CAAC,GAAA,EAIhCvN,EAAM,WAAWmN,CAAC,EAClBnN,EAAM,WAAW+N,EAASZ,CAAC,CAC7B,CACF,CACF,CACF,OAAShO,EAAG,CACV,QAAQ,MAAM,qCAAsCA,CAAC,CACvD,CACF,EAEM6O,GAAiB,CACrBrO,EACA/B,EACAqP,EACAC,EACA9E,IACG,CACH,MAAMqF,EACJ7P,EAAQ,aAAa,KAAK,GAAKA,EAAQ,aAAa,MAAM,EAE5D,GAAI,CAAC6P,EAAa,OAAO/K,EAAAA,GAAG,IAAI,EAGhC,MAAMgL,EAAYR,EAAQ,UAAU,MAAM,KAAK,CAAC,CAAE,KAAAS,KAEzC,GAAGhB,GAASM,EAAwBQ,CAAW,EAAE,YAAA,CAAa,GAAG,SACtE,GAAGE,EAAK,aAAa,EAAA,CAExB,EAED,GAAI,CAACD,EAAW,OAAOhL,EAAAA,GAAG,IAAI,EAE9B,MAAMkL,EAAkB,IAAIpB,GAAgBkB,EAAWtF,CAAQ,EAM/D,OAAOpF,OAAK4K,EAAgB,YAAA,CAAa,EAAE,KACzClC,EAAAA,SAAUgB,GACRA,aAAoB,SAAW1J,EAAAA,KAAK0J,EAAS,KAAA,CAAM,EAAIhK,EAAAA,GAAG,MAAS,CAAA,EAErEgJ,EAAAA,SAAUmC,GAAS,CACjB,GAAI,CAACA,EACH,OAAOnL,EAAAA,GAAG,IAAI,EAGhB,MAAMoL,EAAUnO,GAAW,aAAa,IAAI,gBAAgBkO,CAAI,GAAK,GAErE,GAAIjQ,EAAQ,aAAa,KAAK,EAC5BA,EAAQ,aAAa,MAAOkQ,CAAO,UAC1BlQ,EAAQ,aAAa,MAAM,IACpCA,EAAQ,aAAa,OAAQkQ,CAAO,EAGlCnO,GAAW,aACX/B,aAAmB+B,EAAU,YAAY,iBAEzC,OAAO,IAAI2G,EAAAA,WAAkBjD,GAAa,CACxCzF,EAAQ,OAAS,SAAY,CAC3B,GAAI,CAIEA,EAAQ,OACV,MAAMoP,GACJrN,EACA/B,EACAqP,EACAC,EACA9E,CAAA,EAGJ/E,EAAS,KAAA,EACTA,EAAS,SAAA,CACX,OAAS0I,EAAO,CACd1I,EAAS,MAAM0I,CAAK,CACtB,CACF,EACAnO,EAAQ,QAAUyF,EAAS,KAC7B,CAAC,EAIL,OAAOX,EAAAA,GAAG,IAAI,CAChB,CAAC,CAAA,CAEL,EAEauL,GACX,CAAC,CACC,SAAA7F,EACA,KAAA1E,EACA,QAAAwJ,CACF,IAKC1K,GACCA,EAAO,KACLC,EAAAA,UAAWb,GAAiB,CAC1B,MAAMsM,EAAoBxO,GACxBkC,EAAa,eAAA,EAGTqL,EAAyBkB,EAAAA,cAAczK,EAAK,IAAI,EAEhD0K,EAAcF,EAAkB,IAAKtQ,GACzCoQ,GACEpM,EAAa,gBACbhE,EACAqP,EACAC,EACA9E,CAAA,CACF,EAGF,OAAOH,EAAAA,cAAcmG,CAAW,EAAE,KAAKvL,EAAAA,IAAI,IAAMjB,CAAY,CAAC,CAChE,CAAC,CACH,EAESyM,GAAgBzM,GAAqC,CAChE/B,GAAoB+B,GAAc,eAAe,CACnD,EC/Oa0M,GAAyB,qBACzBC,GAA+B,EAC/BC,GAAuD,IACvDC,GAAqC,CAAC,SAAU,QAAS,MAAM,EAC/DC,EAAc,eACdC,GAAoB,GAAGD,CAAW,SAClCE,GAAgC,QAAQF,CAAW,MACnDG,GAAuB,GAAGH,CAAW,YACrCI,GAA+B,GAAGJ,CAAW,oBCC7CK,GAA6B,MACxCC,EACAtL,IACG,CACH,GAAI,OAAOsL,GAAqB,SAAU,OAAOA,EAEjD,MAAMC,EACJC,EAAAA,iBAAiBF,EAAiB,QAAQ,IAAI,cAAc,GAAK,EAAE,GACnEG,EAAAA,uBAAuBzL,EAAK,IAAI,EAElC,GACE,CAAC,YAAa,aAAc,YAAa,YAAY,EAAE,KACpD0L,GAASA,IAASH,CAAA,EAErB,CACA,MAAMpB,EAAO,MAAMmB,EAAiB,KAAA,EAC9BK,EAAY,IAAI,gBAAgBxB,CAAI,EACpCyB,EAAS,MAAM,kBAAkBzB,CAAI,EACrC,CAAE,MAAAxL,EAAO,OAAAC,CAAA,EAAW,CAAE,MAAOgN,EAAO,MAAO,OAAQA,EAAO,MAAA,EAChE,OAAAA,EAAO,MAAA,EAEA;AAAA;AAAA;AAAA,YAGC5L,EAAK,kBAAoB,gBAAkB,wCAAwCrB,CAAK,YAAYC,CAAM,KAAO,EAAE;AAAA;AAAA;AAAA;AAAA,mBAI5G+M,CAAS;AAAA;AAAA;AAAA;AAAA;AAAA,SAM1B,CAEA,MAAI,CAAC,YAAY,EAAE,KAAMD,GAASA,IAASH,CAAW,EAG7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAFM,MAAMD,EAAiB,KAAA,CAenB;AAAA;AAAA;AAAA,MAMH,MAAMA,EAAiB,KAAA,CAGzC,ECtDaO,GAAiB,CAAC,CAC7B,KAAA7L,EACA,iBAAA8L,CACF,IAIM,CACJ,MAAMC,EAAuBC,GAC3BX,GAA2BW,EAAUhM,CAAI,EAE3C,OAAQlB,GACNA,EAAO,KACLC,EAAAA,UAAWb,GACFoB,OAAKwM,EAAiB,YAAA,CAAa,EAAE,KAC1C/M,EAAAA,UAAWiK,GASPA,aAAoB,KACpBhJ,EAAK,KAAK,WAAW,OAAO,SAAS,MAAM,IAEzCA,EAAK,WACL,CACE,wBACA,kBACA,YACA,UAAA,EACA,SAASA,EAAK,SAAS,GAExB,CAACA,EAAK,WACL+K,GAAmC,KAAMkB,GACvCjM,EAAK,KAAK,SAASiM,CAAS,CAAA,IAGlC/N,GAAc,aAAa,MAAO8B,EAAK,IAAI,EAEpChB,EAAAA,GAAGd,CAAY,IAItB8K,aAAoB,IAChB1J,EAAAA,KAAKwM,EAAiB,cAAA,CAAe,EACrC9M,EAAAA,GAAGgK,CAAQ,GAEQ,KACvBjK,EAAAA,UAAWiN,GAAa,CACtB,GAAI,EAAEA,aAAoB,UACxB,MAAM,IAAI,MAAM,kBAAkB,EAGpC,OAAO1M,EAAAA,KAAKyM,EAAoBC,CAAQ,CAAC,CAC3C,CAAC,EACDzF,EAAAA,IAAK2F,GAAY,CACf,GAAIA,EAAS,CACX,MAAM/B,EAAO,IAAI,KAAK,CAAC+B,CAAO,EAAG,CAAE,KAAM,YAAa,EAKhDC,EAAU,IAAI,gBAAgBhC,CAAI,EAExCjM,GAAc,aAAa,MAAOiO,CAAO,CAC3C,CACF,CAAC,EACDhN,EAAAA,IAAI,IAAMjB,CAAY,EACtBkK,EAAAA,WAAY3M,IACVlC,EAAO,MACL,yDAAyDyG,EAAK,EAAE,GAChEgJ,CAAA,EAEFzP,EAAO,MAAMkC,CAAC,EAEPuD,EAAAA,GAAGd,CAAY,EACvB,CAAA,CAEJ,CAAA,CAEJ,CAAA,CAEP,ECrGakO,GAAqB,IAAM,CAGtC,MAAM5N,EAAQ,SAAS,cAAc,QAAQ,EAC7C,OAAAA,EAAM,YAAc,KACpBA,EAAM,SAAW,EACjBA,EAAM,aACJ,UACA;AAAA;AAAA;AAAA;AAAA,CAAA,EAMFA,EAAM,MAAM,QAAU;AAAA;AAAA;AAAA;AAAA;AAAA,EAOtBA,EAAM,aAAa,OAAQ,MAAM,EAE1BA,CACT,y9BCtBa6N,GAAyB,CAAC,CACrC,WAAAlL,EACA,UAAAC,EACA,aAAAlD,CACF,IAIM,CACJ,MAAMoO,EAAqB/N,EAAqBL,CAAY,EAE5D,GACEA,GAAc,iBACdA,EAAa,eACboO,EACA,CACA,MAAMC,EAAqBnL,GAAakL,EAAmB,OAAS,GAMpE,MAAO,CAAE,cALa,KAAK,IACzBC,EACApL,GAAcmL,EAAmB,QAAU,EAAA,EAGrB,mBAAAC,EAAoB,mBAAAD,CAAA,CAC9C,CACF,EAQME,GAAe,CACnBtO,EACAuO,IACG,CACHvO,EAAa,MAAM,MAAQ,GAAGuO,EAAK,KAAK,KACxCvO,EAAa,MAAM,OAAS,GAAGuO,EAAK,MAAM,IAC5C,EAEaC,GAAqB,CAAC,CACjC,cAAAC,EACA,kBAAAC,EACA,eAAAC,EACA,WAAA1L,EACA,UAAAC,EACA,aAAAlD,EACA,MAAA4O,CACF,IAQM,CACJ,MAAMC,EAAeJ,EAAgBvL,EAErC,GAAIlD,GAAc,iBAAmBA,GAAc,cAAe,CAChE,KAAM,CAAE,mBAAAoO,EAAoB,cAAAU,EAAgB,GAC1CX,GAAuB,CAAE,aAAAnO,EAAc,WAAAiD,EAAY,UAAAC,CAAA,CAAW,GAAK,CAAA,EAC/D6L,EAAwB,CAAC,CAACX,EAC1BY,EAAe9L,EACf+L,EAAgBhM,EAuBtB,GArBIjD,EAAa,iBAAiB,iBAChCA,EAAa,iBAAiB,gBAAgB,aAC5C,0DACA+O,EAAsB,SAAA,CAAS,EAM/BX,EACFE,GAAatO,EAAc,CACzB,MAAOoO,EAAmB,OAAS,EACnC,OAAQA,EAAmB,QAAU,CAAA,CACtC,EAEDE,GAAatO,EAAc,CACzB,MAAOgP,EACP,OAAQC,CAAA,CACT,EAGCb,EAAoB,CACtBpO,GAAc,MAAM,YAAY,WAAY,UAAU,EACtDA,GAAc,MAAM,YAAY,MAAO,KAAK,EAExC2O,IAAmB,QACrB3O,GAAc,MAAM,YAAY,QAAS,GAAG,EAC5CA,GAAc,MAAM,eAAe,MAAM,GAChC0O,IAAsB,UAAYE,GAC3C5O,GAAc,MAAM,YAAY,QAAS,KAAK,EAC9CA,GAAc,MAAM,eAAe,MAAM,GAChC2O,IAAmB,SAC5B3O,GAAc,MAAM,YAAY,OAAQ,GAAG,EAC3CA,GAAc,MAAM,eAAe,OAAO,IAE1CA,GAAc,MAAM,YAClB,OACA0O,IAAsB,SAClBE,EACE,MACA,MACFF,IAAsB,QACpBE,EACE,MACA,MACF,KAAA,EAER5O,GAAc,MAAM,eAAe,OAAO,GAE5C,MAAMkP,EAAsBP,IAAmB,OAAS,IAAM,OACxDQ,EACJR,IAAmB,SAAWD,IAAsB,SAChD,OACAC,IAAmB,QAChBD,IAAsB,UAAYE,EACnC,QACA,SACR5O,GAAc,MAAM,YAClB,YACA,aAAakP,CAAmB,iBAAiBJ,CAAa,GAAA,EAEhE9O,GAAc,MAAM,YAClB,mBACA,GAAGmP,CAAgB,SAAA,CAEvB,MACMT,IAAsB,SACpBE,EACF5O,GAAc,MAAM,YAAY,eAAgB,GAAGkD,CAAS,IAAI,EAEhElD,GAAc,MAAM,YAAY,cAAe,GAAGkD,CAAS,IAAI,GAGjElD,GAAc,MAAM,eAAe,aAAa,EAChDA,GAAc,MAAM,eAAe,cAAc,GAIrD,MAAO,CAAE,MAAO6O,EAAc,OAAQI,CAAA,CACxC,CAEA,MAAO,CAAE,MAAOJ,EAAc,OAAQ5L,CAAA,CACxC,ECvIamM,GAA6B,IACjC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAgCIC,GAAmC,CAAC,CAC/C,aAAAC,EACA,YAAAC,CACF,IAIS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UAYEA,EAIG,GAHA;AAAA;AAAA,SAIN;AAAA;AAAA,QAGAD,EACI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAqBA,EACN;AAAA,MAeOE,GAA4B,CAAC,CACxC,MAAA/O,EACA,aAAAgP,EACA,YAAAC,CACF,IAKS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAaaA,CAAW;AAAA;AAAA;AAAA;AAAA;AAAA,iBAiBhBjP,CAAK;AAAA,kBACJgP,CAAY;AAAA;AAAA;AAAA,wBAGNC,CAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBA+BbA,CAAW;AAAA;AAAA;AAAA;AAAA;AAAA,sBAYXA,CAAW;AAAA,uBACVD,CAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uBAOZC,CAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uBAMXA,CAAW;AAAA;AAAA;AAAA;AAAA,qBAebA,CAAW;AAAA;AAAA;AAAA;AAAA,qBAIXA,CAAW;AAAA;AAAA,MC/N1BC,GAAoC,CAAC,CACzC,uBAAAC,EACA,aAAAf,EACA,WAAA5L,EACA,UAAAC,CACF,IAKM,CAGJ,IAAIwM,EAAcxM,EAAY,EAC9B,MAAMuM,EAAexM,EAAa,EAClC,IAAIxC,EAAQyC,EAAY,EAExB,OAAI0M,IACFnP,EAAQoO,EAAe,EACvBa,EAAcD,GAGT,CACL,aAAAA,EACA,YAAAC,EACA,MAAAjP,CAAA,CAEJ,EAQM6N,GAAe,CACnBtO,EACAuO,IACG,CACHvO,EAAa,MAAM,MAAQ,GAAGuO,EAAK,KAAK,KACxCvO,EAAa,MAAM,OAAS,GAAGuO,EAAK,MAAM,IAC5C,EAEasB,GAAmB,CAAC,CAC/B,WAAYC,EACZ,UAAA5M,EACA,aAAAlD,EACA,SAAA+P,EACA,cAAAtB,EACA,MAAAG,EACA,kBAAAF,EACA,YAAAsB,EACA,YAAAT,EACA,uBAAAK,CACF,IAWM,CACJ,MAAMf,EAAeJ,EAAgBvL,EAC/B+M,EACJF,GAAU,kBAAoB,cAC9BA,GAAU,gBAAkB,sBAaxB9M,EAAagN,EACf,KAAK,IAAI,IAAKH,CAAc,EAC5BA,EAGJ9P,GAAc,MAAM,YAAY,QAAS,GAAGkD,CAAS,IAAI,EAMpD+M,EAGHjQ,GAAc,MAAM,eAAe,QAAQ,EAF3CA,GAAc,MAAM,YAAY,SAAU,GAAGiD,CAAU,IAAI,EAK7D,KAAM,CAAE,mBAAAmL,EAAoB,cAAAU,EAAgB,CAAA,EAC1CX,GAAuB,CACrB,aAAAnO,EACA,WAAAiD,EACA,UAAAC,CAAA,CACD,GAAK,CAAA,EACFgN,EAAyBH,GAAU,kBAAoB,gBAG7D,GACE/P,GAAc,iBACdA,GAAc,eACdA,EAAa,gBAAgB,KAC7B,CACA,IAAIgP,EAAe9L,EACf+L,EAAgBhM,EAEpB,GAAImL,GAAoB,YACtBjO,EACEH,EACA,wCACAoP,GAAA,CAA2B,EAG7Bd,GAAatO,EAAc,CACzB,MAAOoO,EAAmB,OAAS,EACnC,OAAQA,EAAmB,QAAU,CAAA,CACtC,EAEDpO,GAAc,MAAM,YAAY,WAAY,UAAU,EACtDA,GAAc,MAAM,YAAY,MAAO,KAAK,EAC5CA,GAAc,MAAM,YAClB,OACA0O,IAAsB,SAClBE,EACE,MACA,MACFF,IAAsB,QACpBE,EACE,MACA,MACF,KAAA,EAGR5O,GAAc,MAAM,YAClB,YACA,+BAA+B8O,CAAa,GAAA,EAE9C9O,GAAc,MAAM,YAAY,mBAAoB,eAAe,MAC9D,CACL,MAAMmQ,EAAaH,EACfX,GAAiC,CAC/B,aAAcU,GAAU,gBAAkB,sBAC1C,YAAAR,CAAA,CACD,EACDC,GACEG,GAAkC,CAChC,uBAAAC,EACA,aAAAf,EACA,WAAA5L,EACA,UAAAC,CAAA,CACD,CAAA,EAKP,GAFA/C,EAAiBH,EAAc,mBAAoBmQ,EAAY,EAAI,EAE/DP,EAKFX,EAJc,KAAK,KACjBjP,EAAa,gBAAgB,gBAAgB,aAC3CiD,CAAA,EAEoBA,EAExBqL,GAAatO,EAAc,CACzB,MAAO6O,EACP,OAAQI,CAAA,CACT,UACQc,GAAU,gBAAkB,sBAOrCd,EAAgBjP,EAAa,gBAAgB,KAAK,aAElDsO,GAAatO,EAAc,CACzB,MAAO6O,EACP,OAAQI,CAAA,CACT,MACI,CACL,MAAMmB,EAAQ,KAAK,KACjBpQ,EAAa,gBAAgB,gBAAgB,YAAckD,CAAA,EAUzDgN,EACFlB,EAAe9L,EAEf8L,EAAeoB,EAAQlN,EAGzBoL,GAAatO,EAAc,CACzB,MAAOgP,EACP,OAAQC,CAAA,CACT,CACH,CACF,CAMA,OAJ2BD,EAAeH,IAAiB,EAUzD7O,GAAc,MAAM,YAAY,cAAe,KAAK,GALpDgP,EAAeA,EAAe9L,EAC1B0L,GAAS,CAACgB,GACZ5P,GAAc,MAAM,YAAY,cAAe,GAAGkD,CAAS,IAAI,GAM5D,CAAE,MAAO8L,EAAc,OAAQC,CAAA,CACxC,CAGF,EChOO,MAAMoB,WAAqB3F,CAAiB,CAA5C,aAAA,CAAA,MAAA,GAAA,SAAA,EAsKL,KAAQ,eAAiB,IAErB,KAAK,KAAK,kBAAoB,iBAC7B,CAAC,KAAK,KAAK,iBACV,KAAK,QAAQ,UAAU,kBAAoB,gBAIjD,KAAQ,YAAc,IAIb,CAAC,EAFN,KAAK,KAAK,WAAa6C,EAAAA,uBAAuB,KAAK,KAAK,IAAI,IAE3C,WAAW,QAAQ,CACxC,CAlLA,kBAAmB,CACjB,MAAMvN,EAAekO,GAAA,EAErB,YAAK,qBAAqBlO,CAAY,EAE/Bc,EAAAA,GAAGd,CAAY,CACxB,CAEA,gBAAiB,CACf,MAAMA,EAAe,KAAK,gBAAA,EAE1B,GAAI,CAACA,EAAc,MAAM,IAAI,MAAM,eAAe,EAElD,OAAOc,EAAAA,GAAGd,CAAY,EAAE,KACtB2N,GAAe,CACb,KAAM,KAAK,KACX,iBAAkB,KAAK,iBACvB,SAAU,KAAK,QAAA,CAChB,EACD/I,EAAc,KAAK,QAAQ,YAAY,aAAa,EACpDyD,EAAAA,IAAI,IAAM,CACR,KAAK,OAAA,CACP,CAAC,EACD1H,GACA0H,EAAAA,IAAKrI,GAAiB,CAChB,KAAK,iBACPG,EAAiBH,EAAc,mBAAoBsQ,EAAiB,EAEhE,KAAK,aAUb,CAAC,EACDjE,GAAW,CACT,QAAS,KAAK,QACd,KAAM,KAAK,KACX,SAAU,KAAK,QAAA,CAChB,EACDnL,EAAA,CAEJ,CAEA,UAAW,CACT,OAAAuL,GAAa,KAAK,iBAAiB,EAEnC,KAAK,OAAA,EAEE5D,EAAAA,KACT,CAEA,SAAS,CACP,cAAA4F,EACA,kBAAAC,EACA,eAAAC,CAAA,EAKC,CACD,KAAM,CAAE,MAAOzL,EAAW,OAAQD,GAAe,KAAK,SAAS,SACzDjD,EAAe,KAAK,gBAAA,EAE1B,GAAI,CAACA,EAAc,OAAOc,EAAAA,GAAG,MAAS,EAEtC,MAAM8O,EAAyB,CAAC,CAAC,KAAK,aAAa,WAAW,UAAU,EAOlEW,EACJ,KAAK,SAAS,OAAO,uBAAyB,aAkBhD,GAhBIvQ,EAAa,iBAAiB,kBAChCA,EAAa,iBAAiB,gBAAgB,aAC5C,kDACA2O,CAAA,EAEE4B,EACFvQ,EAAa,iBAAiB,gBAAgB,UAAU,IACtD,0CAAA,EAGFA,EAAa,iBAAiB,gBAAgB,UAAU,OACtD,0CAAA,GAKF,KAAK,iBAAkB,CACzB,MAAMwQ,EAAOhC,GAAmB,CAC9B,kBAAAE,EACA,aAAA1O,EACA,MAAO,KAAK,QAAQ,MAAA,EACpB,cAAAyO,EACA,WAAAxL,EACA,UAAAC,EACA,eAAAyL,CAAA,CACD,EAED,OAAO7N,EAAAA,GAAG0P,CAAI,CAChB,CAEA,MAAMA,EAAOX,GAAiB,CAC5B,WAAA5M,EACA,UAAAC,EACA,aAAAlD,EACA,SAAU,KAAK,QAAQ,SACvB,kBAAA0O,EACA,uBAAAkB,EACA,MAAO,KAAK,QAAQ,MAAA,EACpB,cAAAnB,EACA,YAAa,KAAK,YAAA,EAMlB,YAAa,KAAK,SAAS,OAAO,uBAAyB,YAAA,CAC5D,EAED,OAAO3N,EAAAA,GAAG0P,CAAI,CAChB,CAEA,kBAAmB,CACjB,OAAOpP,EAAAA,KAAK,KAAK,iBAAiB,cAAA,CAAe,EAAE,KACjDP,EAAAA,UAAWiK,GAAa,CACtB,GAAIA,aAAoB,SAAU,CAChC,MAAMuC,EAAcvC,EAAS,QAAQ,IAAI,cAAc,GAAK,GAQ5D,GAPuD,CACrD,wBACA,kBACA,YACA,UAAA,EAIqB,SAASuC,CAAqC,EAEnE,OAAOjM,OAAK0J,EAAS,KAAA,CAAM,EAAE,KAC3B7J,EAAAA,IAAKwP,GACe,IAAI,UAAA,EACA,gBACpBA,EACApD,CAAA,CAIH,CAAA,CAGP,CAEA,OAAOvM,EAAAA,GAAG,MAAS,CACrB,CAAC,CAAA,CAEL,CAiBQ,iBAAkB,CACxB,MAAMR,EAAQ,KAAK,kBAEnB,GAAMA,aAAiB,kBAEvB,OAAOA,CACT,CAGO,2BAA4B,CACjC,MAAMA,EAAQ,KAAK,gBAAA,EAEboQ,EAAOpQ,GAAO,iBAAiB,KAErC,GAAIoQ,EACF,OAAOpQ,GAAO,eAAe,iBAAiBoQ,CAAI,CAEtD,CAEA,IAAI,aAAc,CAChB,OAAO,KAAK,6BAA6B,WAI3C,CAEA,IAAI,kBAAmB,CAGrB,GAFoB,KAAK,cAEL,cAClB,MAAO,MAKT,OAFkB,KAAK,0BAAA,GAA6B,UAE5C,CACN,IAAK,MACL,IAAK,UACL,IAAK,UACH,MAAO,MAGT,IAAK,MACH,MAAO,MAET,QACE,MAAO,CAEb,CAEA,kBAAmB,CACjB,OAAO,KAAK,gBAAA,CACd,CACF,CC3OO,MAAMC,GAKTrP,GAGAC,GAGG,CACH,MAAMC,EAASF,EAAK,CAClB,GAAGC,EACH,YAAYO,EAAM,CAGhB,OAFqBP,EAAQ,cAAcO,CAAI,IAEtB8O,GAAU,IAAIP,GAAaO,CAAK,EAC3D,CAAA,CACD,EAEKC,EAAS/H,GAAYtH,CAAM,EAEjC,OAAAqP,EAAO,KAAK3O,YAAUV,EAAO,EAAE,QAAQ,CAAC,EAAE,UAAA,EAEnC,CACL,GAAGA,EACH,OAAAqP,CAAA,CAEJ,EC5CK,SAASC,EACdC,EAC+C,CAC/C,OAAOA,GAAQ,IACjB,CCJO,MAAMC,EAAY,CAUvB,YAAYC,EAST,CACD,KAAK,KAAOA,EAAO,KACnB,KAAK,MAAQA,EAAO,MACpB,KAAK,IAAMA,EAAO,IAClB,KAAK,OAASA,EAAO,OACrB,KAAK,MAAQA,EAAO,MACpB,KAAK,OAASA,EAAO,OACrB,KAAK,EAAIA,EAAO,EAChB,KAAK,EAAIA,EAAO,CAClB,CACF,CAEO,MAAMC,CAAkB,CAK7B,YAAY/T,EAAoC,CAFhD,KAAgB,gBAAkB,mBAAmB,EAGnD,KAAK,EAAIA,EAAS,EAClB,KAAK,EAAIA,EAAS,CACpB,CACF,CAKO,MAAMgU,EAA6B,CAKxC,YAAYhU,EAAoC,CAFhD,KAAgB,gBAAkB,uBAAuB,EAGvD,KAAK,EAAIA,EAAS,EAClB,KAAK,EAAIA,EAAS,CACpB,CACF,CAEO,MAAMiU,WAA4BJ,EAAY,CAA9C,aAAA,CAAA,MAAA,GAAA,SAAA,EACL,KAAgB,SAAW,qBAAA,CAC7B,CCnCO,MAAMK,WAA6BL,EAAY,CAA/C,aAAA,CAAA,MAAA,GAAA,SAAA,EACL,KAAgB,SAAW,sBAAA,CAC7B,CAEO,MAAMM,WAAiCN,EAAY,CAAnD,aAAA,CAAA,MAAA,GAAA,SAAA,EACL,KAAgB,SAAW,0BAAA,CAC7B,CAEO,MAAMO,EAAsB,CAIjC,YAAYpU,EAAoC,CAC9C,KAAK,EAAIA,EAAS,EAClB,KAAK,EAAIA,EAAS,CACpB,CACF,CASO,MAAMqU,UAAsBD,EAAsB,CAAlD,aAAA,CAAA,MAAA,GAAA,SAAA,EACL,KAAgB,SAAW,eAAA,CAE3B,OAAO,KAAKpU,EAAgD,CAC1D,OAAO,IAAIqU,EAAcrU,CAAQ,CACnC,CACF,CAaO,MAAMsU,UAA6BF,EAAsB,CAAzD,aAAA,CAAA,MAAA,GAAA,SAAA,EACL,KAAgB,SAAW,sBAAA,CAE3B,OAAO,KAAKpU,EAAyB,CACnC,OAAO,IAAIsU,EAAqBtU,CAAQ,CAC1C,CACF,CCzEO,MAAMuU,GAA6C,CACxDvU,EACAnB,IACG,CACH,MAAM2V,EAAc3V,EAAQ,sBAAA,EACtB,CAAE,EAAA4V,EAAG,EAAAC,CAAA,EAAM1U,EACX,CAAE,KAAAF,EAAM,IAAAwF,CAAA,EAAQkP,EAGhBpP,EAASoP,EAAY,MAAQ3V,EAAQ,YACrCwG,EAASmP,EAAY,OAAS3V,EAAQ,aAGtC8V,EAAYF,EAAI3U,EAChB8U,EAAYF,EAAIpP,EAGtB,MAAO,CACL,EAAGqP,EAAYvP,EACf,EAAGwP,EAAYvP,CAAA,CAEnB,ECjBawP,GAAqC,CAChD7U,EACA8U,IAGO,IAAIR,EACTC,GAA2CvU,EAAU8U,CAAY,CAAA,EAIxDC,GAAwB1Q,IAC5B,CACL,mCAAqCrE,GACnCqE,EAAO,MAAM,QACTwQ,GAAmC7U,EAAUqE,EAAO,MAAM,OAAO,EACjE,MAAA,GCSG2Q,GAAwB3Q,GAAmB,CACtD,IAAI4Q,EAEJ,MAAMC,EAAwB7Q,EAAO,QAAQ,MAAM,aAAa,EAAE,KAChEX,EAAAA,UAAWsB,GACJA,EAEE,IAAIuC,EAAAA,WAAW,KACpB0N,EACEjQ,EAAY,cAAc,cAAc,KAAK,EAC/CiQ,EAAkC,MAAM,QAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAQlDjQ,EAAY,YAAYiQ,CAAiC,EAElD,IAAM,CACXA,GAAmC,OAAA,EACnCA,EAAoC,MACtC,EACD,EAnBwBpJ,EAAAA,KAoB1B,CAAA,EAGGsJ,EAAuBrK,GAC3BsK,EAAAA,UAAUtK,EAAQuK,EAAAA,uBAAuB,EAAE,KACzCnK,EAAAA,IAAI,IAAM,CACR+J,GAAmC,MAAM,YACvC,aACA,QAAA,CAEJ,CAAC,CAAA,EAGCK,EAAyBjR,EAAO,QAAQ,YAAY,cAAc,KACtE6G,EAAAA,IAAI,IAAM,CACR+J,GAAmC,MAAM,YACvC,aACA,SAAA,CAEJ,CAAC,CAAA,EAGGM,EAAyBJ,EAAiB9Q,EAAO,aAAa,EAAE,KACpER,EAAAA,KAAK,CAAC,CAAA,EAQF2R,EALgBnR,EAAO,SAAS,QAAQ,KAC5CP,EAAAA,IAAI,IAAMO,EAAO,SAAS,OAAO,oBAAoB,EACrD+C,EAAAA,qBAAA,CAAqB,EAGmB,KACxC1D,EAAAA,UAAW+R,GACTA,IAAS,aACLH,EAAuB,KAAK5R,EAAAA,UAAU,IAAM6R,CAAsB,CAAC,EACnEJ,EAAiBxR,EAAAA,GAAG,MAAS,CAAC,CAAA,EAEpCoB,YAAUV,EAAO,EAAE,QAAQ,CAAA,EAG7B,OAAOoH,EAAAA,MAAMyJ,EAAuBM,CAAmB,CACzD,ECrFaE,GAAwB,GADV,GAAGC,CAAgB,mBACK,aAM7CC,GAA8B,CAAC,CACnC,UAAAC,EACA,KAAAlR,EACA,SAAAhG,CACF,IAIM,CACJ,MAAMmX,EAA0BD,EAAU,cAAc,cAAc,KAAK,EAC3EC,EAAwB,UAAU,IAAIJ,EAAqB,EAC3DI,EAAwB,MAAM,QAAU;AAAA;AAAA;AAAA,mBAGvBnX,EAAS,iBAAiB,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAchD,MAAMoX,EAAcD,EAAwB,cAAc,cAAc,KAAK,EAC7EC,EAAY,UAAY,QACxBA,EAAY,MAAM,QAAU;AAAA;AAAA,MAG5B,MAAMC,EACJF,EAAwB,cAAc,cAAc,KAAK,EAC3D,OAAAE,EAAe,aAAa,uBAAwB,MAAM,EAC1DA,EAAe,UAAY,WAAWrR,EAAK,EAAE,GAC7CqR,EAAe,MAAM,QAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQ/BF,EAAwB,YAAYC,CAAW,EAC/CD,EAAwB,YAAYE,CAAc,EAE3CF,CACT,EAEaG,GACX5R,GAEOA,EAAO,kBAAkB,OAAO,KACrCX,EAAAA,UAAWkI,GACTH,EAAAA,MACE,GAAGG,EAAM,IAAKjH,GAAS,CAGrBA,EAAK,iBAAiB,MAAM,OAAS,IAErC,MAAMuR,EAAyBvR,EAAK,iBAAiB,cACnD,IAAI+Q,EAAqB,EAAA,EAGrBI,EACJI,aAAkC,YAC9BA,EACAN,GAA4B,CAC1B,UAAWjR,EAAK,iBAChB,KAAMA,EAAK,KACX,SAAUN,EAAO,QAAA,CAClB,EAEP,OAAAM,EAAK,iBAAiB,YAAYmR,CAAuB,EAElDrK,EAAAA,MACL9G,EAAK,KACHuG,EAAAA,IAAK+B,GAAU,CAUb,GATA6I,EAAwB,MAAM,YAC5B,aACA7I,EAAM,QAAU,SAAW,SAAA,EAE7B6I,EAAwB,MAAM,YAC5B,UACA7I,EAAM,QAAU,IAAM,GAAA,EAGpBA,EAAM,QAAS,CACjB,MAAM+I,EAAiBF,EAAwB,cAC7C,wBAAA,EAEEE,aAA0B,cAC5BA,EAAe,UACb/I,EAAM,OAAO,SAAA,GAAc,gBAEjC,CACF,CAAC,CAAA,EAEH/D,gBAAc,CAAC7E,EAAO,MAAM,QAASA,EAAO,MAAM,EAAE,MAAM,CAAC,EAAE,KAC3D6G,MAAI,CAAC,CAAA,CAAGiL,CAAK,IAAM,CACjB,MAAMC,EAAgB/R,EAAO,SAAS,iBAAiB,MAEvDyR,EAAwB,MAAM,YAC5B,YACA,GAAGM,CAAa,IAAA,EAElBN,EAAwB,MAAM,YAC5B,QACAK,IAAU,QAAU,UAAY,oBAAA,CAEpC,CAAC,CAAA,CACH,CAEJ,CAAC,CAAA,CACH,CACF,EClISE,GAAsBhS,GAAmB,CAUpDA,EAAO,YAAY,SAAS,sBAAuB,CAAC,CAAE,OAAAI,KAAa,CAC/CJ,EAAO,kBAAkB,IAAII,CAAM,GAC1B,SAAS,iBAAA,GAE3B,aAAa,YAAa,IAAI,CACzC,CAAC,CACH,ECfa6R,GAAiBjS,GAAmB,CAuB/CA,EAAO,YAAY,SACjB,qBACA,CAAC,CAAE,KAAAM,EAAM,kBAAA4M,EAAmB,aAAAG,KAAmB,CAC7C,MAAM7L,EAAYxB,EAAO,kBAAkB,IAAIM,EAAK,EAAE,EAChD9F,EAAUgH,GAAW,SAAS,iBAAA,EAEpC,GACIA,GAAW,kBAAoB,cACjC,EAAEhH,aAAmB,mBAErB,OAEF,KAAM,CAAE,YAAAyO,CAAA,EAAgBpK,EAAqBrE,CAAO,EAC9C,CAAE,MAAOkH,CAAA,EAAc1B,EAAO,SAAS,SACvCxB,EAAegD,GAAW,SAAS,iBAAA,EAEzC,GAAIyH,EAAa,CACf,MAAMiJ,EAAiCxQ,EAAY2L,EAC1BH,IAAsB,QAI7CgF,GACA1T,aAAwB,mBAExBA,GAAc,MAAM,YAClB,OACAwB,EAAO,QAAQ,MAAA,EAAU,MAAQ,KAAA,CAGvC,CACF,CAAA,CAEJ,ECxDamS,GAAkBnS,GACtBA,EAAO,mBAAmB,QAAQ,KACvC6G,EAAAA,IAAI,CAAC,CAAE,KAAAvG,EAAM,QAAA8R,EAAS,QAAAC,KAAc,CAElC/R,EAAK,iBAAiB,QAAQ,QAAa+R,EAAQ,SAAA,EAEnD/R,EAAK,iBAAiB,QAAQ,QAAa8R,EAAQ,SAAA,CACrD,CAAC,CAAA,SCFE,cAGG7N,EAKR,CACA,sBACEG,EAC6B,CAC7B,OAAOA,CACT,CAEA,mBAAmBc,EAAyD,CAC1E,MAAO,CAACxC,EAAAA,eAAe,KAAK,eAAgBwC,CAAiB,CAC/D,CAEA,8BACER,EACqB,CACrB,KAAM,CACJ,iBAAkBS,EAClB,qBAAsBC,EACtB,mBAAoBC,EACpB,sBAAuBC,EACvB,GAAGC,CAAA,EACDb,EAEJ,OAAOa,CACT,CAEA,oBAAkD,CAChD,MAAO,CACL,iBAAkB,YAClB,qBAAsB,GACtB,mBAAoB,GACpB,sBAAuB,EAAA,CAE3B,CACF,EC9CO,MAAMyM,GAAoBtS,GACxB6E,gBAAc,CACnB7E,EAAO,SAAS,MAAM,CAAC,QAAS,QAAQ,CAAC,EACzCA,EAAO,QAAQ,MAAM,UAAU,CAAA,CAChC,EAAE,KACD6G,EAAAA,IAAI,CAAC,CAAC,CAAE,MAAA5H,EAAO,OAAAC,CAAA,EAAUqP,CAAQ,IAAM,CACrC,MAAMgE,EAActT,EAAQC,EAE5B,MAAI,CAACqT,GAAehE,GAAU,kBAAoB,WACzCvO,EAAO,SAAS,OAAO,CAAE,WAAY,GAAM,EAIlDuS,IACChE,GAAU,kBAAoB,QAC7BA,GAAU,kBAAoB,QAC9BA,GAAU,kBAAoB,aAC9BA,GAAU,kBAAoB,QAEzBvO,EAAO,SAAS,OAAO,CAAE,WAAY,GAAM,EAG7CA,EAAO,SAAS,OAAO,CAAE,WAAY,GAAO,CACrD,CAAC,CAAA,ECYQwS,GAkBT1S,GAEDC,GAA2E,CAC1E,KAAM,CACJ,qBAAA0S,EACA,mBAAAC,EACA,iBAAAC,EACA,sBAAAC,CAAA,EACE7S,EACEC,EAASF,EAAKC,CAAO,EAErB0E,EAAkB,IAAI2B,GAI1B,CACE,qBAAAqM,EACA,mBAAAC,EACA,iBAAAC,EACA,sBAAAC,CAAA,EAEF5S,EAAO,QAAA,EAMTA,EAAO,YAAY,SAAS,yBAA0B,IAAM,CAC1D,IAAI6S,EAAa,GAyBjB7S,EAAO,kBAAkB,MAAM,QAASM,GAAS,CAC/C,MAAMxB,EAAQwB,EAAK,SAAS,iBAAA,EAExB,CAACuS,GAAc/T,IACZA,EAAM,wBAAwB,KACnC+T,EAAa,GAEjB,CAAC,CACH,CAAC,EAKD7S,EAAO,YAAY,SAAS,sBAAuB,CAAC,CAAE,KAAAM,KAAW,CAC/D,MAAMkB,EAAYxB,EAAO,kBAAkB,IAAIM,EAAK,EAAE,EAEhDkO,EAAc,CAAC,EADJlO,EAAK,WAAayL,EAAAA,uBAAuBzL,EAAK,IAAI,IACnC,WAAW,QAAQ,EAE7C,CAAE,qBAAAmS,EAAuB,EAAG,mBAAAC,EAAqB,GACrDjO,EAAgB,OACZqO,EAAW9S,EAAO,SAAS,SAEjC,GAAIwB,GAAW,kBAAoB,cAAgB,CAACgN,EAAa,CAC/D,IAAIN,EAAc4E,EAAS,MAAQL,EAAuB,EAC1D,MAAMxE,EAAe6E,EAAS,OAASJ,EAAqB,EAC5D,IAAIzT,EAAQ6T,EAAS,MAAQL,EAAuB,EAChDM,EAAYN,EAAuB,EAEnCjR,EAAU,2BACZvC,EAAQ6T,EAAS,MAAQL,EAAuB,EAChDvE,EAAcD,EACd8E,EAAYL,EAAqB,GAGnC,MAAM5T,EAAQ0C,GAAW,SAAS,iBAAA,EAE9B1C,GACFH,EACEG,EACA,4BACA;AAAA;AAAA,yBAEaG,CAAK;AAAA,0BACJyT,CAAkB,MAAMD,CAAoB;AAAA,8BACxCM,CAAS;AAAA,gCACP7E,CAAW;AAAA,0BACjBD,CAAY;AAAA;AAAA;AAAA,8BAGRC,CAAW;AAAA,+BACVD,CAAY;AAAA;AAAA;AAAA,6BAGdC,CAAW;AAAA;AAAA;AAAA,6BAGXA,CAAW;AAAA;AAAA,aAAA,CAKlC,CACF,CAAC,EAED+D,GAAcjS,CAAM,EACpBgS,GAAmBhS,CAAM,EAEzBA,EAAO,YAAY,SACjB,yBACA,CAAC,CAAE,kBAAAuI,CAAA,IAAwB,CAIzBA,EAAkB,MAAM,QAAU,IAC9B9D,EAAgB,OAAO,wBACzB8D,EAAkB,MAAM,WAAa,gBAEzC,CAAA,EAGFvI,EAAO,YAAY,SAAS,sBAAuB,CAAC,CAAE,KAAAM,KAAW,CAG/D,MAAM9F,EAFYwF,EAAO,kBAAkB,IAAIM,EAAK,EAAE,GAE3B,SAAS,kBAGhCN,EAAO,SAAS,OAAO,uBAAyB,cAElDxF,GAAS,aAAa,YAAa,GAAG,CAE1C,CAAC,EAED,MAAMwY,EAAqBhT,EAAO,mBAAmB,QAAQ,KAC3DmI,EAAAA,OAAO,CAAC,CAAE,QAAAiK,CAAA,IAAcA,CAAO,EAC/BvL,MAAI,CAAC,CAAE,KAAAvG,KAAW,CAChB,MAAM9F,EAAU8F,EAAK,SAAS,kBAE1B9F,IACFA,EAAQ,MAAM,QAAU,IAE5B,CAAC,CAAA,EAWGyY,EAA2BxO,EAAgB,QAAQ,KACvD0D,EAAAA,OAAO,CAAC,CAAE,iBAAAwK,CAAAA,IAAuBA,IAAqB,WAAW,EACjEtT,EAAAA,UAAU,IAAMW,EAAO,QAAQ,MAAM,aAAa,CAAC,EACnDmI,EAAAA,OAAOmH,CAAS,EAChBjQ,EAAAA,UAAW7E,GAAYyI,EAAczI,CAAO,CAAC,EAC7C0Y,EAAAA,aAAa,GAAG,EAChB/K,EAAAA,OAAOmH,CAAS,EAChBzI,EAAAA,IAAI,IAAM,CACR7G,GAAQ,OAAA,CACV,CAAC,CAAA,EAGGmT,EAAiBxC,GAAqB3Q,CAAM,EAElDyE,EACG,MAAM,CAAC,uBAAwB,oBAAoB,CAAC,EACpD,KACC2O,EAAAA,KAAK,CAAC,EACNvM,EAAAA,IAAI,IAAM,CACR7G,EAAO,OAAA,CACT,CAAC,EACDU,YAAUV,EAAO,EAAE,QAAQ,CAAA,EAE5B,UAAA,EAEH,MAAMqT,EAAcrT,EAAO,MAAM,MAAM,KACrCiF,EAAAA,YAAY,CAAE,SAAU,GAAM,WAAY,EAAG,CAAA,EAGzCqO,EAAkBnB,GAAenS,CAAM,EAEvCuT,EAAoBjB,GAAiBtS,CAAM,EAE3CwT,EAAoB5B,GAAuB5R,CAAM,EAEvDoH,OAAAA,EAAAA,MACE4L,EACAG,EACAF,EACAI,EACAC,EACAC,EACAC,CAAA,EAEC,KAAK9S,EAAAA,UAAUV,EAAO,EAAE,QAAQ,CAAC,EACjC,UAAA,EAEI,CACL,GAAGA,EACH,QAAS,IAAM,CACbyE,EAAgB,QAAA,EAChBzE,EAAO,QAAA,CACT,EACA,SAAUyE,EACV,QAASzE,EAAO,MAAM,QACtB,YAAAqT,EACA,YAAa3C,GAAqB1Q,CAAM,CAAA,CAE5C,ECnRK,MAAMyT,WAAsBvK,CAAiB,CAC1C,iBAAkB,CACxB,MAAM1O,EAAU,KAAK,kBAErB,GAAMA,aAAmB,iBAEzB,OAAOA,CACT,CAEA,kBAAmB,CACjB,MAAMkZ,EAAa,KAAK,iBAAiB,cAAc,cAAc,KAAK,EAE1E,OAAO9T,EAAAA,KAAK,KAAK,iBAAiB,YAAA,CAAa,EAAE,KAC/CP,EAAAA,UAAWsU,GAAkB,CAM3B,GALA,KAAK,qBAAqBD,CAAU,EAEpCA,EAAW,MAAM,UAAY,UAC7BA,EAAW,MAAM,WAAa,OAE1BC,aAAyB,IAC3B,OAAOrU,EAAAA,GAAGqU,EAAc,IAAI,EAE9B,GAAIA,aAAyB,SAC3B,OAAO/T,OAAK+T,EAAc,KAAA,CAAM,EAAE,KAChClU,EAAAA,IAAKgL,GACI,IAAI,gBAAgBA,CAAI,CAChC,CAAA,EAIL,MAAM,IAAI,MAAM,kBAAkB,CACpC,CAAC,EACDhL,EAAAA,IAAKuK,GAAQ,CACX,MAAMxP,EAAU,KAAK,gBAAA,EAErB,OAAIA,IACFA,EAAQ,IAAMwP,GAGT0J,CACT,CAAC,CAAA,CAEL,CAEA,gBAAiB,CACf,MAAME,EAAe,KAAK,gBAAA,EAE1B,GAAI,CAACA,EAAc,MAAM,IAAI,MAAM,iBAAiB,EAEpD,YAAK,OAAA,EAEErU,YAAUqU,EAAc,MAAM,CACvC,CAEA,UAAW,CACT,MAAMA,EAAe,KAAK,gBAAA,EAE1B,OAAIA,GACF,IAAI,gBAAgBA,EAAa,GAAG,EAGtC,KAAK,OAAA,EAEEvM,EAAAA,KACT,CAEA,SAAS,CACP,eAAA8F,CAAA,EAKC,CACD,MAAM3S,EAAU,KAAK,gBAAA,EACf,CAAE,OAAQiH,EAAY,MAAOC,GACjC,KAAK,SAAS,MAAM,SAEtB,IAAIxC,EAASuC,EAEb,MAAMxC,EAAQyC,EAEd,GAAI,CAAClH,EAAS,OAAO8E,EAAAA,GAAG,MAAS,EAEjC,MAAMuU,EAAerZ,EAAQ,cAAgB,EACvCsZ,EAAgBtZ,EAAQ,eAAiB,EACzCuZ,EAAQF,EAAeC,EAM7B,OACE,KAAK,SAAS,OAAO,4BAA8B,YACnD,KAAK,SAAS,OAAO,uBAAyB,cAC9C,CAAC,KAAK,SAAS,OAAO,qBAEtB5U,EAAS,KAAK,KAAKwC,EAAYqS,CAAK,GAGtCvZ,EAAQ,MAAM,OAAS,GAAG0E,CAAM,KAChC1E,EAAQ,MAAM,MAAQ,GAAGyE,CAAK,KAC9BzE,EAAQ,MAAM,eACZ2S,IAAmB,OACf,QACAA,IAAmB,QACjB,OACA,SAED7N,KAAG,CACR,MAAAL,EACA,OAAAC,CAAA,CACD,CACH,CAEA,kBAAmB,CACjB,OAAOmI,EAAAA,KACT,CAEA,kBAAmB,CAEnB,CACF,CCpHO,MAAM2M,GAKTlU,GAEDC,GAA2C,CAC1C,MAAMC,EAASF,EAAK,CAClB,GAAGC,EACH,YAAYO,EAAM,CAChB,MAAM2T,EAAelU,EAAQ,cAAcO,CAAI,EAEzCkO,EAAc,CAAC,EADJlO,EAAK,WAAayL,EAAAA,uBAAuBzL,EAAK,IAAI,IACnC,WAAW,QAAQ,EAEnD,MAAI,CAAC2T,GAAgBzF,EACXY,GAAU,IAAIqE,GAAcrE,CAAK,EAGpC6E,CACT,CAAA,CACD,EAEKC,EAAgB,IAAI,qBACvBhU,GAAY,CACXA,EAAQ,QAASC,GAAU,CACzB,MAAMrB,EAAQqB,EAAM,OACdgU,EAAS,MAAM,KACnBrV,EAAM,iBAAiB,KAAK,qBAAqB,OAAO,GAAK,CAAA,CAAC,EAG3DqB,EAAM,eAMTgU,EAAO,QAASC,GAAiB,CAE7BA,EAAa,aAAa,UAAU,GACpCA,EAAa,QACbA,EAAa,YAAc,GAE3BA,EAAa,KAAA,EAAO,MAAM,QAAQ,KAAK,CAE3C,CAAC,EAbDD,EAAO,QAASC,GAAiB,CAC/BA,EAAa,MAAA,EACbA,EAAa,YAAc,CAC7B,CAAC,CAYL,CAAC,CACH,EACA,CACE,UAAW,GAAA,CACb,EAGIC,EAAkB,IAAI,qBACzBnU,GAAY,CACXA,EAAQ,QAASC,GAAU,CACzB,GAAIA,EAAM,OAAO,UAAY,QAAS,CACpC,MAAMmU,EAAQnU,EAAM,OACfA,EAAM,eAILmU,EAAM,aAAa,UAAU,GAG3BA,EAAM,QAAUA,EAAM,YAAc,GACtCA,EAAM,KAAA,EAAO,MAAM,QAAQ,KAAK,GAPpCA,EAAM,MAAA,EACNA,EAAM,YAAc,EAUxB,CACF,CAAC,CACH,EACA,CACE,UAAW,EAAA,CACb,EAGF,OAAAtU,EAAO,YAAY,SACjB,sBACA,CAAC,CAAE,QAAAK,EAAS,OAAAD,KAAa,CACvB,MAAMtB,EAAQkB,EAAO,kBAClB,IAAII,CAAM,GACT,SAAS,iBAAA,EAEb,GAAI,CAACtB,EAAO,OAEZoV,EAAc,QAAQpV,CAAK,EAE3B,MAAMyV,EAASzV,EAAM,iBAAiB,KAAK,qBAAqB,OAAO,EAEjE0V,EAAoB,MAAM,KAAKD,GAAU,CAAA,CAAE,EAAE,IAAK/Z,IACtD6Z,EAAgB,QAAQ7Z,CAAO,EAExB,IAAM6Z,EAAgB,UAAU7Z,CAAO,EAC/C,EAED6F,EAAQ,IAAM,CACZ6T,EAAc,UAAUpV,CAAK,EAC7B0V,EAAkB,QAASC,GAAc,CACvCA,EAAA,CACF,CAAC,CACH,CAAC,CACH,CAAA,EASK,CACL,GAAGzU,EACH,QARc,IAAM,CACpBkU,EAAc,WAAA,EACdG,EAAgB,WAAA,EAChBrU,EAAO,QAAA,CACT,CAIE,CAEJ,ECvHW0U,GAAwB,CACnC1U,EACA2U,IAEO3U,EAAO,OAAO,KACnB6G,EAAAA,IAAK5K,GAAU,CACb,GAAI,CAACsB,GAAiBtB,EAAM,OAAQ,GAAG,GAAKA,EAAM,OAAS,QAAS,OAEpE,MAAM2Y,EAAU,IAAI,IAAI3Y,EAAM,OAAO,IAAI,EACnC4Y,EAAoB,GAAGD,EAAQ,MAAM,GAAGA,EAAQ,QAAQ,GAGjC5U,EAAO,QAAQ,UAAU,WAAW,KAC9DM,GAASA,EAAK,OAASuU,CAAA,GAIxBF,EAAgB,QAAQC,CAAO,CAEnC,CAAC,CAAA,ECvBQE,EAAmBjb,EAAO,UAAU,YAAY,ECEhDkb,GAAkC,CAAC,CAC9C,SAAApZ,EACA,UAAA6F,EACA,WAAAC,EACA,UAAAC,EACA,iBAAAsT,CACF,IAMyB,CACvB,IAAIC,EAAwB,IAAIvF,EAAkB,CAChD,EAAG/T,EAAS,EAAI+F,EAChB,EAAG/F,EAAS,CAAA,CACb,EAED,OAAI6F,EAAU,2BACZyT,EAAwB,IAAIvF,EAAkB,CAC5C,EAAG/T,EAAS,EACZ,EAAGA,EAAS,EAAI8F,CAAA,CACjB,GAIDuT,EAAiB,8CACfC,EACAzT,CAAA,CAIN,EC7Ba0T,GAAiC,CAAC,CAC7C,SAAAvZ,EACA,mBAAAwZ,EACA,0BAAAC,EACA,kBAAAC,EACA,aAAAC,EACA,SAAAhb,CACF,IAO4C,CAC1C,MAAM2M,EAAoBmO,EACpB5T,EACJ8T,EAAa,yBAAyB3Z,CAAQ,GAAK0Z,EAAkB,IAAI,CAAC,EACtEE,EAAoB5Z,EAE1B,GAAI,CAAC6F,EACH,OAAO+T,EAGT,MAAMC,EAAoBF,EAAa,sCACrC3Z,EACA6F,CAAA,EAGIiU,EAAsBV,GAAgC,CAC1D,SAAUS,EACV,UAAAhU,EACA,WAAYlH,EAAS,SAAS,OAC9B,UAAWA,EAAS,SAAS,MAC7B,iBAAkBgb,EAAa,gBAAA,CAChC,EAOD,OALqCH,EAAmB,sBACtDM,EACAD,CAAA,EAiBAF,EAAa,sCAAsC,CACjD,kBAAmBG,EACnB,UAAAjU,CAAA,CACD,EAhBM2T,EAAmB,yBACxBlO,IAAsB,aAClB,IAAI+I,EAAc,CAChB,EAAGrU,EAAS,EAAIrB,EAAS,SAAS,MAClC,EAAG,CAAA,CACJ,EACD,IAAI0V,EAAc,CAChB,EAAGrU,EAAS,EAAIrB,EAAS,SAAS,OAClC,EAAG,CAAA,CACJ,CAAA,CAUX,EChDaob,GAAgC,CAAC,CAC5C,SAAA/Z,EACA,UAAA6F,EACA,QAAAsI,EACA,mBAAAqL,EACA,kBAAAE,EACA,aAAAC,EACA,0BAAAF,EACA,SAAA9a,EACA,SAAA0K,CACF,IAa4C,CAC1C,MAAM2Q,EAAaT,GAA+B,CAChD,SAAAvZ,EACA,SAAArB,EACA,mBAAA6a,EACA,0BAAAC,EACA,kBAAAC,EACA,aAAAC,CAAA,CACD,EAGD,GAAI9T,GAAW,uBAAA,GAA4B7F,EAAS,IAAMga,EAAW,EACnE,OAAOR,EAAmB,6BAA6BQ,CAAU,EAGnE,GAAI3Q,EAAS,OAAO,mBAAoB,CAKtC,GAAIxD,GAAW,uBAAA,GAA4B7F,EAAS,IAAMga,EAAW,EACnE,OAAOR,EAAmB,6BACxBA,EAAmB,yBACjBrL,EAAQ,MAAA,EACJ,CAAE,GAAG6L,EAAY,EAAGA,EAAW,EAAIrb,EAAS,SAAS,KAAA,EACrD,CACE,GAAGqb,EACH,EAAGA,EAAW,EAAIrb,EAAS,SAAS,KAAA,CACtC,CACN,EAQJ,GACE8a,IAA8B,YAC9BzZ,EAAS,IAAMga,EAAW,EAE1B,OAAOR,EAAmB,6BAA6BQ,CAAU,EAGnE,MAAMC,EAAmBV,GAA+B,CACtD,SAAUS,EACV,SAAArb,EACA,mBAAA6a,EACA,0BAAAC,EACA,kBAAAC,EACA,aAAAC,CAAA,CACD,EAED,OAAOH,EAAmB,6BAA6BS,CAAgB,CACzE,CAEA,OAAOT,EAAmB,6BAA6BQ,CAAU,CACnE,ECjGaE,GAAmC,CAAC,CAC/C,SAAAla,EACA,UAAA6F,EACA,WAAAC,EACA,UAAAC,EACA,iBAAAsT,CACF,IAMyB,CACvB,IAAIC,EAAwB,IAAIvF,EAAkB,CAChD,EAAG/T,EAAS,EAAI+F,EAChB,EAAG/F,EAAS,CAAA,CACb,EAED,OAAI6F,EAAU,2BACZyT,EAAwB,IAAIvF,EAAkB,CAC5C,EAAG/T,EAAS,EACZ,EAAGA,EAAS,EAAI8F,CAAA,CACjB,GAIDuT,EAAiB,8CACfC,EACAzT,CAAA,CAIN,ECvBasU,GAA0C,CAAC,CACtD,SAAAna,EACA,mBAAAwZ,EACA,0BAAAC,EACA,kBAAAC,EACA,aAAAC,EACA,SAAAhb,CACF,IAO4C,CAC1C,MAAM2M,EAAoBmO,EACpB5T,EACJ8T,EAAa,yBAAyB3Z,CAAQ,GAAK0Z,EAAkB,IAAI,CAAC,EACtEE,EAAoB5Z,EAE1B,GAAI,CAAC6F,EACH,OAAO+T,EAIT,MAAMC,EAAoBF,EAAa,sCACrC3Z,EACA6F,CAAA,EAIIuU,EAAkCF,GAAiC,CACvE,SAAUL,EACV,UAAAhU,EACA,WAAYlH,EAAS,SAAS,OAC9B,UAAWA,EAAS,SAAS,MAC7B,iBAAkBgb,EAAa,gBAAA,CAChC,EAQD,OAL8BH,EAAmB,sBAC/CY,EACAP,CAAA,EAkBAF,EAAa,sCAAsC,CACjD,kBAAmBS,EACnB,UAAAvU,CAAA,CACD,EAjBM2T,EAAmB,yBACxBlO,IAAsB,aAClB,IAAIgJ,EAAqB,CACvB,EAAGtU,EAAS,EAAIrB,EAAS,SAAS,MAClC,EAAG,CAAA,CACJ,EACD,IAAI2V,EAAqB,CACvB,EAAGtU,EAAS,EAAIrB,EAAS,SAAS,OAClC,EAAG,CAAA,CACJ,CAAA,CAWX,EC1Da0b,GAAoC,CAAC,CAChD,SAAAra,EACA,UAAA6F,EACA,QAAAsI,EACA,mBAAAqL,EACA,kBAAAE,EACA,aAAAC,EACA,0BAAAF,EACA,SAAA9a,EACA,SAAA0K,CACF,IAaqB,CACnB,MAAM2Q,EAAaG,GAAwC,CACzD,SAAAna,EACA,SAAArB,EACA,mBAAA6a,EACA,0BAAAC,EACA,kBAAAC,EACA,aAAAC,CAAA,CACD,EAGD,GAAI9T,GAAW,uBAAA,GAA4B7F,EAAS,IAAMga,EAAW,EACnE,OAAOR,EAAmB,6BAA6BQ,CAAU,EAGnE,GAAI3Q,EAAS,OAAO,mBAAoB,CAKtC,GAAIxD,GAAW,uBAAA,GAA4B7F,EAAS,IAAMga,EAAW,EACnE,OAAOR,EAAmB,6BACxBA,EAAmB,yBACjBrL,EAAQ,QACJ,CACE,GAAG6L,EACH,EAAGA,EAAW,EAAIrb,EAAS,SAAS,KAAA,EAEtC,CACE,GAAGqb,EACH,EAAGA,EAAW,EAAIrb,EAAS,SAAS,KAAA,CACtC,CACN,EAQJ,GACE8a,IAA8B,YAC9BzZ,EAAS,IAAMga,EAAW,EAE1B,OAAOR,EAAmB,6BAA6BQ,CAAU,EAGnE,MAAMC,EAAmBE,GAAwC,CAC/D,SAAUH,EACV,SAAArb,EACA,mBAAA6a,EACA,0BAAAC,EACA,kBAAAC,EACA,aAAAC,CAAA,CACD,EAED,OAAOH,EAAmB,6BAA6BS,CAAgB,CACzE,CAEA,OAAOT,EAAmB,6BAA6BQ,CAAU,CACnE,EChGO,MAAMM,EAAgB,CAK3B,YAAsBjW,EAAgB,CAAhB,KAAA,OAAAA,EAJtB,KAAA,gBAAkB,CAAE,EAAG,EAAG,EAAG,CAAA,EAC7B,KAAA,mBAAqB,IAAIgQ,EAAc,CAAE,EAAG,EAAG,EAAG,EAAG,EACrD,KAAA,OAA+D,MAExB,CAEvC,WAAY,CACV,OAAO,KAAK,kBAAA,CACd,CAEA,UAAW,CACT,OAAO,KAAK,cAAA,CACd,CAEA,SAAU,CACR,OAAO,KAAK,cAAA,CACd,CAEA,YAAa,CACX,OAAO,KAAK,kBAAA,CACd,CAEA,mBAAoB,CAClB,MAAM2F,EAAa,KAAK,OAAO,WAAW,cAAA,EACpCnU,EAAY,KAAK,OAAO,kBAAkB,IAAImU,EAAW,SAAS,EAExE,GAAI,CAACnU,EAAW,OAEhB,MAAM7F,EAAWqa,GAAkC,CACjD,QAAS,KAAK,OAAO,QACrB,mBAAoB,KAAK,OAAO,WAAW,mBAC3C,SAAUL,EAAW,SACrB,0BACE,KAAK,OAAO,SAAS,OAAO,0BAC9B,UAAAnU,EACA,kBAAmB,KAAK,OAAO,kBAC/B,aAAc,KAAK,OAAO,MAAM,QAChC,SAAU,KAAK,OAAO,SACtB,SAAU,KAAK,OAAO,QAAA,CACvB,EAED,OAAO,KAAK,OAAO,WAAW,SAAS,CACrC,SAAA7F,CAAA,CACD,CACH,CAEA,eAAgB,CACd,MAAMga,EAAa,KAAK,OAAO,WAAW,cAAA,EACpCnU,EAAY,KAAK,OAAO,kBAAkB,IAAImU,EAAW,SAAS,EAExE,GAAI,CAACnU,EAAW,OAEhB,MAAM7F,EAAW+Z,GAA8B,CAC7C,QAAS,KAAK,OAAO,QACrB,mBAAoB,KAAK,OAAO,WAAW,mBAC3C,SAAUC,EAAW,SACrB,0BACE,KAAK,OAAO,SAAS,OAAO,0BAC9B,UAAAnU,EACA,kBAAmB,KAAK,OAAO,kBAC/B,aAAc,KAAK,OAAO,MAAM,QAChC,SAAU,KAAK,OAAO,SACtB,SAAU,KAAK,OAAO,QAAA,CACvB,EAED,OAAO,KAAK,OAAO,WAAW,SAAS,CACrC,SAAA7F,CAAA,CACD,CACH,CAEA,QAAQua,EAAanW,EAAgC,CAAE,QAAS,IAAQ,CACtE,OAAO,KAAK,OAAO,WAAW,SAAS,CACrC,UAAWA,EAAQ,QAAU,OAAS,GACtC,IAAAmW,CAAA,CACD,CACH,CAEA,cAAc,CACZ,UAAAC,EACA,GAAGtQ,CAAA,EAIF,CACD,MAAMrE,EAAY,KAAK,OAAO,kBAAkB,IAAI2U,CAAS,EAE7D,GAAI3U,IAAc,OAAW,CAC3BsT,EAAiB,KACf,gBACA,wBAAwBqB,CAAS,gCAAA,EAGnC,MACF,CAEA,KAAK,OAAO,WAAW,SAAS,CAC9B,UAAW3U,EAAU,MACrB,GAAGqE,CAAA,CACJ,CACH,CAEA,mBAAoB,CAClB,KAAM,CAAE,SAAAuQ,EAAW,GACjB,KAAK,OAAO,MAAM,QAAQ,iCAAiC,CACzD,SAAU,KAAK,OAAO,WAAW,gBAAgB,SACjD,UAAW,CAAE,KAAM,aAAc,MAAO,EAAA,CAAI,CAC7C,GAAK,CAAA,EAER,KAAK,cAAc,CAAE,UAAWA,EAAW,EAAG,CAChD,CAEA,uBAAwB,CACtB,KAAM,CAAE,WAAAC,EAAa,GACnB,KAAK,OAAO,MAAM,QAAQ,iCAAiC,CACzD,SAAU,KAAK,OAAO,WAAW,gBAAgB,SACjD,UAAW,CAAE,KAAM,aAAc,MAAO,EAAA,CAAI,CAC7C,GAAK,CAAA,EAER,KAAK,cAAc,CAAE,UAAWA,EAAa,EAAG,CAClD,CAEA,QAAQ3Z,EAAmB,CACzB,KAAK,OAAO,WAAW,SAAS,CAC9B,IAAAA,EACA,UAAW,EAAA,CACZ,CACH,CAEA,oBAAqB,CACnB,GAAI,KAAK,OAAO,SAAS,OAAO,4BAA8B,WAAY,CACxEoY,EAAiB,KACf,8DAAA,EAGF,MACF,CAEA,OAAI,KAAK,OAAO,QAAQ,MAAA,EACf,KAAK,sBAAA,EAGP,KAAK,kBAAA,CACd,CAEA,4BAA6B,CAC3B,OAAI,KAAK,OAAO,SAAS,OAAO,4BAA8B,WACrD,KAAK,oBAAA,EAGP,KAAK,mBAAA,CACd,CAEA,wBAAyB,CACvB,OAAI,KAAK,OAAO,SAAS,OAAO,4BAA8B,WACrD,KAAK,iBAAA,EAGP,KAAK,kBAAA,CACd,CAEA,mBAAoB,CAClB,GAAI,KAAK,OAAO,SAAS,OAAO,4BAA8B,WAAY,CACxEA,EAAiB,KACf,8DAAA,EAGF,MACF,CAEA,OAAI,KAAK,OAAO,QAAQ,MAAA,EACf,KAAK,kBAAA,EAGP,KAAK,sBAAA,CACd,CAEA,kBAAmB,CACjB,GACE,KAAK,OAAO,SAAS,OAAO,4BAA8B,aAC1D,CACAA,EAAiB,KACf,gEAAA,EAGF,MACF,CAEA,OAAO,KAAK,sBAAA,CACd,CAEA,qBAAsB,CACpB,GACE,KAAK,OAAO,SAAS,OAAO,4BAA8B,aAC1D,CACAA,EAAiB,KACf,gEAAA,EAGF,MACF,CAEA,OAAO,KAAK,kBAAA,CACd,CAEA,oBAAoB,CAClB,UAAAwB,EACA,YAAAC,EACA,GAAG1Q,CAAA,EAIuC,CAC1C,MAAMlK,EACJ,KAAK,OAAO,WAAW,mBAAmB,8BAA8B,CACtE,UAAA2a,EACA,YAAAC,CAAA,CACD,EAEHzB,EAAiB,MAAM,yBAA0B,CAC/C,UAAAwB,EACA,YAAAC,EACA,GAAG1Q,EACH,SAAAlK,CAAA,CACD,EAED,KAAK,OAAO,WAAW,SAAS,CAC9B,SAAAA,EACA,GAAGkK,CAAA,CACJ,CACH,CAEA,sBAAsB,CACpB,kBAAA2Q,EACA,GAAG3Q,CAAA,EACsE,CACzE,MAAM4Q,EACJ,KAAK,OAAO,MAAM,MAAM,sBAAsBD,CAAiB,EAQjE,GANA1B,EAAiB,MAAM,2BAA4B,CACjD,kBAAA0B,EACA,GAAG3Q,EACH,UAAA4Q,CAAA,CACD,EAEGA,EAAW,CACb,MAAM9a,EACJ,KAAK,OAAO,WAAW,mBAAmB,8BACxC,CACE,UAAW8a,EAAU,UACrB,YAAaA,EAAU,SAAA,CACzB,EAGJ,OAAO,KAAK,OAAO,WAAW,SAAS,CACrC,SAAA9a,EACA,GAAGkK,CAAA,CACJ,CACH,CACF,CACF,CCxQO,MAAM6Q,WAAqB/O,CAK/B,CAGD,YAAsB3H,EAAgB,CACpC,MAAM,CACJ,UAAW,CAAE,EAAG,EAAG,EAAG,CAAA,EACtB,aAAc,IAAIgQ,EAAc,CAAE,EAAG,EAAG,EAAG,EAAG,EAC9C,kBAAmB,IAAIA,EAAc,CAAE,EAAG,EAAG,EAAG,EAAG,EACnD,UAAW,EAAA,CACZ,EANmB,KAAA,OAAAhQ,EAFtB,KAAA,OAA+D,MAS/D,CAEA,MAAM2W,EAAiC,CACrC,KAAK,SAAA,EACL,KAAK,OAAS,KAAK,OAAO,WAAW,KAAA,EAErC,KAAK,aAAa,CAChB,UAAW,GACX,UAAWA,EACX,kBACE,KAAK,OAAO,WAAW,+BAA+B,iBACxD,aACE,KAAK,OAAO,WAAW,+BAA+B,gBAAA,CACzD,CACH,CAEA,KAAKA,EAAiC,CACpC,KAAK,UAAUA,CAAK,EAEpB,KAAK,aAAa,CAChB,UAAW,EAAA,CACZ,EAED,KAAK,SAAA,CACP,CAEA,UAAUA,EAA6C,CACrD,GAAI,KAAK,OAAO,SAAS,OAAO,uBAAyB,aAAc,CACrE7B,EAAiB,KACf,qDAAA,EAGF,MACF,CAEA,GAAI,CAAC,KAAK,MAAM,UAAW,CACzBA,EAAiB,MAAM,8BAA8B,EAErD,MACF,CAEA,MAAM7N,EACJ,KAAK,OAAO,SAAS,OAAO,0BAE9B,IAAI0O,EACF,KAAK,OAAO,WAAW,gBAAgB,SAEzC,GAAIgB,EAAO,CACT,MAAMC,EACJ,KAAK,OAAO,SAAS,iBAAiB,MACtC,KAAK,OAAO,SAAS,iBAAiB,MAKlCC,EAAa,KAAK,MAAMF,EAAM,CAAC,GAAK,KAAK,MAAM,WAAW,GAAK,GAC/DG,EAAa,KAAK,MAAMH,EAAM,CAAC,GAAK,KAAK,MAAM,WAAW,GAAK,GAC/DvG,EAAI,KAAK,MACbnJ,IAAsB,aAClB,KAAK,MAAM,aAAa,EAAI4P,EAAaD,EACzC,CAAA,EAEAvG,EAAI,KAAK,MACbpJ,IAAsB,aAClB,EACA,KAAK,MAAM,aAAa,EAAI6P,EAAaF,CAAA,EAG/CjB,EAAa,IAAI3F,EAAc,CAC7B,EAAAI,EACA,EAAAC,CAAA,CACD,EAED,KAAK,aAAa,CAChB,UAAWsG,CAAA,CACZ,CACH,MACEhB,EAAa,KAAK,MAAM,aAG1B,KAAK,aAAa,CAChB,aAAcA,CAAA,CACf,EAED,KAAK,OAAO,WAAW,SAAS,CAC9B,SAAUA,EACV,UAAW,EAAA,CACZ,CACH,CACF,CC1GO,MAAMoB,CAAiB,CAAvB,aAAA,CACL,KAAU,YAAc,GACxB,KAAQ,eAAiB,IAAInS,UAE7B,KAAU,SAAW,KAAK,eAAe,aAAA,CAAa,CAE/C,SAAU,CACX,KAAK,cAET,KAAK,YAAc,GAEnB,KAAK,eAAe,KAAA,EACpB,KAAK,eAAe,SAAA,EACtB,CACF,CCCA,MAAMoS,GAAmC,IAElC,MAAMC,WAA6BF,CAAiB,CAWzD,YACYG,EACAC,EACV,CACA,MAAA,EAHU,KAAA,2BAAAD,EACA,KAAA,OAAAC,EANZ,KAAU,kBAAoB,IAAIvS,UAElC,KAAO,YAAc,KAAK,kBAAkB,aAAA,EAc1C,MAAMwS,EAAoB,KAAK,2BAA2B,YAAY,KACpEC,EAAAA,WAAYpb,GAAU,CACpB,MAAMqb,EAAS,KAAK,OAAO,KAAA,EAE3B,OAAOlQ,EAAAA,MACL,KAAK,2BAA2B,YAChC9H,EAAAA,GAAGrD,CAAK,CAAA,EACR,KACAiX,EAAAA,aACE8D,GACAhG,EAAAA,uBAAA,EAEFzN,QAAA,EACAsD,EAAAA,IAAI,IAAM,CACR,MAAM0Q,EACJ,KAAK,2BAA2B,mBAC9B,KAAK,2BAA2B,cAAA,EAGpC,KAAK,kBAAkB,KAAK,CAC1B,UAAW,GACX,KAAM,SACN,SAAUA,CAAA,CACX,CACH,CAAC,EACDzO,EAAAA,SAAS,IAAM,CACbwO,EAAA,CACF,CAAC,CAAA,CAEL,CAAC,CAAA,EAGHlQ,QAAMgQ,CAAiB,EAAE,KAAK1W,EAAAA,UAAU,KAAK,QAAQ,CAAC,EAAE,UAAA,CAC1D,CACF,CCtEO,MAAM8W,GAAgBxX,GACpBA,EAAO,WAAW,OAAO,KAC9ByX,EAAAA,eAAezX,EAAO,QAAQ,UAAWA,EAAO,SAAS,OAAO,EAChEP,EAAAA,IACE,CAAC,CACCiY,EACA,CAAE,WAAAvQ,EAAY,iBAAAwQ,CAAA,EACd,CAAE,0BAAAvC,CAAA,CAA0B,IACxB,CACJ,MAAMwC,EAAqBzQ,EAAW,QAAU,EAC1C0Q,EAAwBH,EAAe,sBAAwB,EAC/DI,EACJJ,EAAe,oBACf,KAAK,IAAIE,EAAqB,EAAG,CAAC,EAE9BG,EACJL,EAAe,oBACf,KAAK,IAAIE,EAAqB,EAAG,CAAC,EAE9BI,EAAqBN,EAAe,sBAAwB,EAE5DO,EACJP,EAAe,4BAA8B,EAEzCQ,EACJR,EAAe,0BACfA,EAAe,4BAA8B,EAE/C,MAAO,CACL,YACEtC,IAA8B,WAC1B,GACA,CAAC6C,EACP,aACE7C,IAA8B,WAAa,GAAQ,CAAC8C,EACtD,kBACE9C,IAA8B,YAAc,CAACyC,EAC/C,qBACEzC,IAA8B,YAAc,CAAC0C,EAC/C,mBACE1C,IAA8B,aAC5BuC,IAAqB,OAAS,CAACE,GAC9BF,IAAqB,OAAS,CAACI,GACpC,oBACE3C,IAA8B,aAC5BuC,IAAqB,OAAS,CAACG,GAC9BH,IAAqB,OAAS,CAACK,EAAA,CAExC,CAAA,EAEFjV,EAAAA,qBAAqBC,EAAAA,cAAc,CAAA,EC/C1BmV,GACX,CAAC,CAAE,OAAAnY,EAAQ,SAAAoY,CAAA,IACPhZ,GAA0B,CAC5B,IAAIiZ,EACJ,MAAMf,EAAS,IAAM,CACnBe,IAAA,EACAA,EAAW,MACb,EAEA,OAAOjZ,EAAO,KACZyH,EAAAA,IAAI,IAAM,CACHwR,IACHA,EAAWrY,GAAQ,WAAW,KAAA,EAElC,CAAC,EACDsY,EAAAA,aAAaF,EAAUpH,0BAAyB,CAC9C,SAAU,GACV,QAAS,EAAA,CACV,EACDnK,EAAAA,IAAIyQ,CAAM,EACVxO,EAAAA,SAASwO,CAAM,CAAA,CAEnB,EChBWiB,GAKTzY,GAGAC,GAC2D,CAC3D,MAAMC,EAASF,EAAKC,CAAO,EACrByY,EAAShB,GAAaxX,CAAM,EAC5B2U,EAAkB,IAAIsB,GAAgBjW,CAAM,EAC5CyY,EAAe,IAAI/B,GAAa1W,CAAM,EACtC0Y,EAAuB,IAAIzB,GAC/BjX,EAAO,WAAW,2BAClBA,EAAO,WAAW,MAAA,EAGd2Y,EAAmBjE,GAAsB1U,EAAQ2U,CAAe,EAChEiE,EAAwBF,EAAqB,YAAY,KAC7D7R,EAAAA,IAAK8O,GAAe,CAClB3V,EAAO,WAAW,SAAS2V,CAAU,CACvC,CAAC,CAAA,EAGHvO,OAAAA,EAAAA,MAAMuR,EAAkBC,CAAqB,EAC1C,KAAKlY,EAAAA,UAAUV,EAAO,EAAE,QAAQ,CAAC,EACjC,UAAA,EAiBI,CACL,GAAGA,EACH,KAjB8CD,GAAY,CAC1D,KAAM,CAAE,IAAAmW,EAAK,GAAGrQ,CAAA,EAAS9F,EAEzBC,EAAO,KAAK6F,CAAI,EAEZqQ,GACFvB,EAAgB,QAAQuB,EAAK,CAAE,QAAS,GAAO,CAEnD,EAUE,QARc,IAAM,CACpBwC,EAAqB,QAAA,EACrB1Y,EAAO,QAAA,CACT,EAME,WAAY,CACV,GAAGA,EAAO,WACV,OAAAwY,EACA,aAAc,CAAC,CAAE,SAAAJ,EAAU,QAAAhQ,KACzBA,EAAQ,KAAK+P,GAAa,CAAE,SAAAC,EAAU,OAAApY,CAAA,CAAQ,CAAC,EACjD,aAAAyY,EACA,WAAY9D,EAAgB,WAAW,KAAKA,CAAe,EAC3D,QAASA,EAAgB,QAAQ,KAAKA,CAAe,EACrD,cAAeA,EAAgB,cAAc,KAAKA,CAAe,EACjE,kBACEA,EAAgB,kBAAkB,KAAKA,CAAe,EACxD,SAAUA,EAAgB,SAAS,KAAKA,CAAe,EACvD,UAAWA,EAAgB,UAAU,KAAKA,CAAe,EACzD,QAASA,EAAgB,QAAQ,KAAKA,CAAe,EACrD,QAASA,EAAgB,QAAQ,KAAKA,CAAe,EACrD,cAAeA,EAAgB,cAAc,KAAKA,CAAe,EACjE,kBACEA,EAAgB,kBAAkB,KAAKA,CAAe,EACxD,sBACEA,EAAgB,sBAAsB,KAAKA,CAAe,EAC5D,uBACEA,EAAgB,uBAAuB,KAAKA,CAAe,EAC7D,2BACEA,EAAgB,2BAA2B,KAAKA,CAAe,EACjE,iBACEA,EAAgB,iBAAiB,KAAKA,CAAe,EACvD,oBACEA,EAAgB,oBAAoB,KAAKA,CAAe,EAC1D,kBACEA,EAAgB,kBAAkB,KAAKA,CAAe,EACxD,mBACEA,EAAgB,mBAAmB,KAAKA,CAAe,EACzD,oBACEA,EAAgB,oBAAoB,KAAKA,CAAe,EAC1D,sBACEA,EAAgB,sBAAsB,KAAKA,CAAe,CAAA,CAC9D,CAEJ,ECvEIkE,GAAoB,CACxBtO,EACAuO,EACAvK,IAC4B,CAC5B,MAAMwK,EAAiBxK,EAAS,WAAW,UACxCjO,GAASA,EAAK,OAASiK,CAAA,EAG1B,OAAOuO,EAAQ,OAAO,CAAClW,EAA8BkW,IAAY,CAC/D,MAAME,EAAcF,EAAQ,KAAK,QAAQ,GAAG,EACtCG,EACJD,EAAc,EAAIF,EAAQ,KAAK,OAAO,EAAGE,CAAW,EAAIF,EAAQ,KAC5DI,EAA6BD,EAAyB,UAC1D,EACAA,EAAyB,YAAY,GAAG,CAAA,EAEpCE,EAAsB5O,EAAK,UAAU,EAAGA,EAAK,YAAY,GAAG,CAAC,EAE7D6O,EAAoB7O,EAAK,SAAS0O,CAAwB,EAC1DI,EACJF,IAAwB,IACxBA,EAAoB,SAASD,CAA0B,EAezD,GAFmCE,GAAqBC,EAExB,CAC9B,MAAMC,EAAoC/K,EAAS,WAAW,UAC3DjO,GAASA,EAAK,OAASwY,EAAQ,IAAA,EAKlC,GAFEC,EAAiBO,EAEe,OAAO1W,EAEzC,MAAM2W,EAAO,CACX,MAAOT,EAAQ,MACf,KAAMA,EAAQ,IAAA,EAGVU,EAAUX,GAAkBtO,EAAMuO,EAAQ,SAAUvK,CAAQ,EAElE,OAAIiL,EACK,CACL,GAAGD,EACH,WAAYC,CAAA,EAITD,CACT,CAEA,OAAO3W,CACT,EAAG,MAAS,CACd,EAEM6W,GAAgC,CACpClL,EACAjO,IACG,CACH,KAAM,CAAE,KAAAiK,GAASjK,EAEjB,OAAOuY,GAAkBtO,EAAMgE,EAAS,KAAK,KAAO,CAAA,EAAIA,CAAQ,CAClE,EAEamL,GACX1Z,GAC+C,CAC/C,MAAMuO,EAAWvO,EAAO,QAAQ,SAC1BuH,EAAQvH,EAAO,kBAAkB,MAEvC,OAAKuO,EAEEhH,EAAM,OACX,CAAC3E,EAAK,CAAE,KAAAtC,MACNsC,EAAItC,EAAK,EAAE,EAAImZ,GAA8BlL,EAAUjO,CAAI,EAEpDsC,GAET,CAAA,CAAC,EARmB,CAAA,CAUxB,EAEa+W,GAAoB3Z,GACxBA,EAAO,kBAAkB,OAAO,KACrC8E,EAAAA,UAAU,CAAA,CAAE,EACZrF,MAAI,IAAMia,GAAgB1Z,CAAM,CAAC,CAAA,EC3H/B4Z,GAAkC,CACtCC,EACAC,EACAC,IAEOF,EAAyBC,EAAoBC,EAGhDC,GAAgC,CACpCha,EACAia,EACAC,IACG,CACH,KAAM,CAAE,OAAAhb,EAAQ,MAAAD,CAAA,EAAUib,EAAY,WAEhC,CAAE,IAAAjZ,EAAK,KAAAxF,CAAA,EAASuE,EAAO,MAAM,4BAA4Bka,CAAW,EAE1E,OAAIla,EAAO,SAAS,OAAO,4BAA8B,WAChD,KAAK,IACV,EACA,KAAK,IACH,GACCia,EAAgB,EAAIhZ,EAAMjB,EAAO,SAAS,iBAAiB,QAC1Dd,CAAA,CACJ,EAGG,KAAK,IACV,EACA,KAAK,IACH,GACC+a,EAAgB,EAAIxe,EAAOuE,EAAO,SAAS,iBAAiB,OAC3Df,CAAA,CACJ,CAEJ,EAEakb,GAAwB,CACnCna,EACAoa,EACA9D,EACA2D,EACAC,IAEOA,EAAY,SAAS,KAC1B3W,QAAA,EACAkU,EAAAA,eAAezX,EAAO,WAAW,EACjCP,EAAAA,IAAI,CAAC,CAAC4a,EAAa5K,CAAM,IAAM,CAC7B,MAAM3F,EAAU9J,EAAO,QAEjB0O,EACJ5E,EAAQ,UAAU,kBAAoB,gBAClCwQ,EAAqBxQ,EAAQ,UAAU,WAAW,QAAU,EAC5D+P,EACJ/P,EAAQ,UAAU,WACf,MAAM,EAAGsQ,CAAiB,EAC1B,OAAO,CAACxX,EAAKtC,IAASsC,GAAOtC,EAAK,mBAAqB,GAAI,CAAC,GAAK,EAChEia,EACJva,EAAO,kBAAkB,kBAAkBka,CAAW,GAAK,EAEvDtC,EAAqB5X,EAAO,QAAQ,UAAU,WAAW,QAAU,EAEnEwa,EACJ/K,EAAO,MAAM,OAAQgL,GAASA,EAAK,YAAcF,CAAe,EAC7D,QAAU,EAETT,EACJhQ,EAAQ,UAAU,WAAWsQ,CAAiB,GAAG,oBAGhDG,EAAkB,GAAK3C,EAE1B,IAAImC,GACDzD,EAAY,IAAMwD,EAAoBU,GAGvC,CAAC9L,GACDwL,EAAY,kBAAoB,cAChC,CAACG,IAEDN,EAAyB,GAG3B,IAAIW,EAAgBb,EAAyBE,EAuB7C,OArBIjQ,EAAQ,UAAU,gBAAkB,wBAClCuQ,EACFN,EAAyBC,GACvBha,EACAia,EACAC,CAAA,EAKFH,EAAyB,EAE3BW,EAAgBd,GACdC,EACAC,EACAC,CAAA,GAOFK,IAAsBE,EAAqB,GAC3ChE,IAAckE,EAAyB,GACvCE,EAAgB,IAET,EAGFA,CACT,CAAC,CAAA,EC5GQC,GAAmB3a,GAIzBA,EAAO,MAAM,QAAQ,KACxBkT,EAAAA,aAAa,GAAIlC,yBAAuB,EACxCyG,iBAAezX,EAAO,WAAW,MAAM,EACvCP,EAAAA,IAAI,KACK,CACL,sBAAuBO,EAAO,kBAAkB,MAAM,OACpD,CAAC4C,EAAKtC,IACG,CAAC,GAAGsC,EAAKtC,EAAK,aAAa,EAEpC,CAAA,CAAC,EAKH,mBAAoBN,EAAO,MAAM,MAAM,MAAM,MAAM,MAAA,EAEtD,EACD+C,EAAAA,qBAAqBC,EAAAA,cAAc,EACnC8B,YAAU,CACR,sBAAuB,CAAA,EACvB,mBAAoB,CAAA,CACrB,CAAA,EChBQ8V,GAAkC,CAC7C5a,EACA0X,EACAmD,EACAC,IASG,CACH,MAAMC,EACJrD,EAAe,sBAAwB,OACnC1X,EAAO,kBAAkB,IAAI0X,EAAe,mBAAmB,EAC/D,OACAsD,EACJtD,EAAe,oBAAsB,OACjC1X,EAAO,kBAAkB,IAAI0X,EAAe,iBAAiB,EAC7D,OAEN,OAAOpY,KAAG,CACR,GAAGoY,EACH,iBAAkBqD,EAAYF,EAAaE,EAAU,KAAK,EAAE,EAAI,OAWhE,+BAAgCA,GAAW,iBAC3C,eAAgBC,EAAUH,EAAaG,EAAQ,KAAK,EAAE,EAAI,OAC1D,6BAA8BA,GAAS,iBAQvC,yBAAAF,EACA,cAAe9a,EAAO,SAAS,OAAO,oBAAsB,EAAA,CAI7D,CACH,EAEMib,GAAsBjb,GACnB6E,gBAAc,CACnB7E,EAAO,WAAW,OAIlBA,EAAO,OAAA,CACR,EAAE,KACDX,YAAU,CAAC,CAACqY,CAAc,IAAM,CAC9B,MAAMsD,EACJtD,EAAe,oBAAsB,OACjC1X,EAAO,kBAAkB,IAAI0X,EAAe,iBAAiB,EAC7D,OAEN,OAAOsD,EACHb,GACEna,EACA0X,EAAe,mBAAqB,EACpCA,EAAe,yBAA2B,EAC1C1X,EAAO,WAAW,cAAA,EAAgB,SAClCgb,CAAA,EAEF1b,EAAAA,GAAG,CAAC,CACV,CAAC,CAAA,EAIQ4b,GAAuBlb,GAA0C,CAC5E,MAAMmb,EAAgBxB,GAAiB3Z,CAAM,EACvCob,EAAcT,GAAgB3a,CAAM,EACpCqb,EAAe,IAAIxT,kBAAwC,CAC/D,GAAG7H,EAAO,WAAW,MACrB,iBAAkB,OAClB,SAAU,OACV,0BAA2B,OAC3B,cAAe,GACf,uBAAwB,EACxB,qBAAsB,EACtB,mBAAoB,EACpB,+BAAgC,OAChC,oBAAqB,OACrB,OAAQ,OACR,eAAgB,OAChB,6BAA8B,OAC9B,yBAA0B,CAAA,CAC3B,EAEKsb,EAA0BzW,EAAAA,cAAc,CAC5C7E,EAAO,WAAW,OAClBmb,EACAF,GAAmBjb,CAAM,CAAA,CAC1B,EAAE,KACDX,EAAAA,UAAU,CAAC,CAACka,EAAMsB,EAAcC,CAAwB,IACtDF,GACE5a,EACAuZ,EACAsB,EACAC,CAAA,EACA,KACArb,EAAAA,IAAK8b,IAAkB,CACrB,GAAGhC,EACH,GAAGgC,CAAA,EACH,CAAA,CACJ,EAEFxY,EAAAA,qBAAqBC,EAAAA,cAAc,CAAA,EA6BrC,MAAO,CAAE,gBA1BmD6B,EAAAA,cAAc,CACxEyW,EACAF,CAAA,CACD,EAAE,KACD3b,EAAAA,IAAI,CAAC,CAAC+b,EAAUC,CAAa,KAAO,CAClC,GAAGD,EACH,GAAGC,EACH,uBAAwBA,EAAc,sBACnC,MAAM,EAAGD,EAAS,mBAAmB,EACrC,OACC,CAAC5Y,EAAK8Y,IAAyB9Y,EAAM8Y,EACrCF,EAAS,2BAA6B,CAAA,EAE1C,qBAAsBC,EAAc,sBACjC,MAAM,EAAGD,EAAS,iBAAiB,EACnC,OACC,CAAC5Y,EAAK8Y,IAAyB9Y,EAAM8Y,EACrCF,EAAS,yBAA2B,CAAA,CACtC,EACF,EACF3U,EAAAA,IAAKvD,GAAU,CACb+X,EAAa,KAAK/X,CAAK,CACzB,CAAC,EACD2B,EAAAA,YAAY,CAAC,CAAA,EAGW,kBAAmB,IAAMoW,EAAa,KAAA,CAClE,ECrKaM,EAAmBrb,GACvBsb,WAAS,CACd,WAAYtb,EAAK,MACjB,QAASA,EAAK,EAAA,CACf,EAGGub,GAAc,CAAC,CACnB,YAAAC,EACA,OAAAhgB,EACA,KAAAwE,CACF,IAIM,CACJ,MAAMyb,EACJ,kBAAmBD,EACfA,EAAY,cACZA,EAAY,eAAe,cAEjC,MACE,CAACC,GACD,CAACA,GAA0B,iBAC3BD,IAAgBC,EAETJ,EAAgBrb,CAAI,EAEzB7C,GAAYqe,CAAW,EAClBF,WAAS,CACd,MAAO,CACL,KAAME,EAAY,eAClB,OAAQA,EAAY,YACpB,WAAYxb,EAAK,MACjB,QAASA,EAAK,EAAA,EAEhB,IAAK,CACH,KAAMwb,EAAY,aAClB,OAAQA,EAAY,UACpB,WAAYxb,EAAK,MACjB,QAASA,EAAK,EAAA,CAChB,CACD,EAGIsb,WAAS,CACd,KAAME,EACN,OAAAhgB,EACA,WAAYwE,EAAK,MACjB,QAASA,EAAK,EAAA,CACf,CACH,EAQa0b,GAA8B,CAAC,CAC1C,UAAAxa,EACA,SAAAya,CACF,IAIoBJ,GAAY,CAC5B,YAAaI,EAAS,KACtB,OAAQA,EAAS,OACjB,KAAMza,CAAA,CACP,EAEgB,KAAA,EAGN0a,GAAuB,CAClCthB,EACA0F,IAEOub,GAAY,CACjB,YAAajhB,EACb,KAAA0F,CAAA,CACD,EAGU6b,GAAiB7b,GAC5BA,EAAK,MAAM,SAAA,EC9EP8b,GAAwBlS,GACrBA,EAAK,CAAC,GAAG,QAAU,GAAKA,EAAK,OAAS,EASlCmS,GAAanG,GAAgB,CACxC,MAAMoG,EAASC,EAAAA,MAAMrG,CAAG,EAExB,OAAOsG,EAAAA,kBAAkBF,CAAM,CACjC,EAEMG,GAA0BC,GACvB,MAAM,QAAQA,CAAS,EAC1BA,EAAU,CAAC,GAAKN,GAAqBM,EAAU,CAAC,CAAC,EAC/CA,EAAU,CAAC,EACX,OACFA,EAAU,OAAO,CAAC,GAAKN,GAAqBM,EAAU,OAAO,CAAC,CAAC,EAC7DA,EAAU,OAAO,CAAC,EAClB,OAGKC,GAAYzG,GAAqD,CAC5E,MAAMwG,EAAYH,EAAAA,MAAMrG,CAAG,EAIrB6C,IAHkB0D,GAAuBC,CAAS,GACd,CAAA,GAAI,CAAC,GACH,OAAS,GACP,EAAI,EAC5CE,EAAaC,EAAAA,iBAAiBH,CAAS,EACvC5gB,EAAS8gB,EACXF,EAAU,IAAI,GAAG,EAAE,GAAG,GAAG,EAAE,GAAG,OAC9BA,EAAU,GAAG,EAAE,GAAG,GAAG,EAAE,GAAG,OAE9B,MAAO,CACL,WAAAE,EACA,UAAW7D,EACX,OAAQjd,GAAU,CAAA,CAEtB,ECxCaghB,GAAa,CAAC,CAAA,IACzB5G,EACA,kBAAAb,CACF,IAQK,CACH,KAAM,CAAE,UAAA0H,EAAW,GAAGC,CAAA,EAAeL,GAASzG,CAAG,EAE3C1U,EAAY6T,EAAkB,IAAI0H,CAAS,EAEjD,GAAI,CAACvb,EACH,MAAO,CACL,GAAGwb,EACH,UAAAD,EACA,KAAM,IAAA,EAGV,MAAME,EAAkBzb,EAAU,SAAS,iBAAA,EAE3C,GAAIyb,aAA2B,kBAAmB,CAChD,MAAMhjB,EAAMgjB,EAAgB,eAAe,SAE3C,GAAIhjB,EACF,GAAI,CACF,MAAMijB,EAAWza,EAAAA,QAAQyT,EAAKjc,EAAK,CACjC,aAAc,EAAA,CACf,EAED,MAAO,CACL,GAAG+iB,EACH,UAAAD,EACA,KAAMG,EAAS,QACVA,EAAS,MAAM,gBAAkB,KACjCA,EAAS,MAAQ,KACtB,WAAYA,EAAS,QACrB,MAAOA,EAAS,QAAUA,EAAS,KAAO,OAC1C,OAAQ,MAAM,QAAQA,EAAS,MAAM,EACjCA,EAAS,OAAO,GAAG,EAAE,EACrBA,EAAS,OACb,UAAA1b,CAAA,CAEJ,OAASzF,EAAG,CACVlC,OAAAA,EAAO,KAAK,wBAAwBqc,CAAG,GAAG,EAC1Crc,EAAO,KAAKkC,CAAC,EAEN,CACL,GAAGihB,EACH,UAAAxb,EACA,UAAAub,EACA,KAAM,IAAA,CAEV,CAEJ,CAEA,MAAO,CACL,GAAGC,EACH,UAAAD,EACA,UAAAvb,EACA,KAAM,IAAA,CAEV,EC7CM2b,GAAyB,CAC7Bnd,EACAsJ,IACyB,CACzB,GAAI,QAASA,EAAU,CACrB,KAAM,CAAE,UAAAyT,EAAW,GAAGK,CAAA,EAAkBpd,EAAO,IAAI,SAASsJ,EAAS,GAAG,EAExE,MAAO,CACL,GAAGA,EACH,GAAG8T,EACH,UAAAL,EACA,KAAM,IAAA,CAEV,CAEA,MAAMzc,EAAON,EAAO,kBAAkB,IAAIsJ,CAAQ,EAElD,GAAI,CAAChJ,EACH,MAAM,IAAI,MAAM,sBAAsB,EAGxC,MAAM4V,EAAMyF,EAAgBrb,EAAK,IAAI,EAIrC,MAAO,CACL,GAHgBN,EAAO,IAAI,SAASkW,CAAG,EAIvC,IAAKyF,EAAgBrb,EAAK,IAAI,EAC9B,UAAWA,EAAK,MAChB,KAAM,IAAA,CAEV,EAEa+c,GAAc,CACzB/T,EACAtJ,IACqC,CACrC,IAAIsd,EAAgBhU,GAAU,cAC9B,KAAM,CAAE,UAAAyT,EAAW,GAAGK,CAAA,EAAkBpd,EAAO,IAAI,SAASsJ,EAAS,GAAG,EAClE9H,EAAYxB,EAAO,kBAAkB,IAAI+c,CAAS,EAExD,OAAKvb,EAEEmC,IAAO,KACZ8T,EAAAA,eAAejW,EAAU,QAAQ,EACjC/B,MAAI,CAAC,CAAA,CAAG8d,CAAgB,IAAM,CAC5B,KAAM,CACJ,KAAA1hB,EAAO,KACP,OAAQ2hB,EACR,MAAA5iB,CAAA,EACE2iB,EAAmBvd,EAAO,IAAI,WAAW,CAAE,IAAKsJ,EAAS,GAAA,CAAK,EAAI,CAAA,EAGpE9H,EAAU,kBAAoB,iBAAmB3F,IAGjDyhB,EACEtd,EAAO,MAAM,QAAQ,iBAAiB,8BACpCnE,EACA2hB,GAAe,EACfhc,CAAA,GACG8b,GAGT,IAAI9G,EAAoBlN,GAAU,kBAMlC,OAAIgU,IAAkB,SACpBA,EAAgB,GAGlB9G,EACExW,EAAO,MAAM,QAAQ,mCAAmC,CACtD,UAAWsd,EACX,cAAe9b,CAAA,CAChB,GAAK8H,GAAU,kBAEX,CACL,GAAGA,EACH,GAAG8T,EACH,MAAAxiB,EACA,UAAAmiB,EACA,KAAAlhB,EACA,YAAA2hB,EACA,kBAAAhH,EACA,cAAA8G,CAAA,CAEJ,CAAC,CAAA,EAjDoBhe,KAAG,CAAE,GAAGgK,EAAU,UAAAyT,EAAW,GAAGK,EAAe,CAmDxE,EAYO,MAAMK,EAAiB,CAC5B,YAAoBzd,EAAgB,CAAhB,KAAA,OAAAA,EAEpB,KAAQ,kBAAoB,IAW5B,KAAQ,yBAA4B7B,GAAgB,CAClD,MAAMmF,EAAQ,KAAK,cAAc,IAAInF,CAAG,EAEnCmF,IAELA,EAAM,gBAEFA,EAAM,gBAAkB,GAC1B,KAAK,cAAc,OAAOnF,CAAG,EAEjC,EAEA,KAAA,OAAS,CACPmL,EACAvJ,IAC4D,CAC5D,MAAM2d,EAA2B,CAC/B,SAAApU,EACA,KAAM6T,GAAuB,KAAK,OAAQ7T,CAAQ,CAAA,EAGpD,OAAOxF,GAAU,IAAM,CAOrB,MAAMxD,EAAO,KAAK,OAAO,kBAAkB,IACzCod,EAAyB,KAAK,WAAa,CAAA,EAEvCC,EAAerd,GAAM,kBAAoB,aAEzCsd,EACJ7d,EAAQ,OAAS,WAAa,CAAC4d,GAAgB,CAACrd,EAC5C,IAAM,CAAC,EACP,KAAK,OAAO,MAAM,iBAAiB,UAAU,CAACA,EAAK,KAAK,CAAC,EAEzDnC,EAAM,QAASmL,EAAWA,EAAS,IAAM,OACzCuU,EAAuB1f,EAAM,KAAK,cAAc,IAAIA,CAAG,EAAI,OAE3D2f,EACJ1e,GAEOA,EAAO,KACZ0J,EAAAA,SAAS,IAAM,CACT3K,GACF,KAAK,yBAAyBA,CAAG,EAQnC,WAAW,IAAM,CACfyf,EAAA,CACF,EAAG,GAAI,CACT,CAAC,CAAA,EAIL,GAAIzf,GAAO0f,EACT,OAAAA,EAAqB,gBAEdC,EACLD,EAAqB,aAAa,KAChCpe,EAAAA,IAAI,CAAC,CAAE,SAAA6J,EAAU,KAAAyU,MAAY,CAC3B,SAAUzU,EACV,KAAAyU,CAAA,EACA,CAAA,CACJ,EAIJ,MAAMC,EAAe,KAAK,OAAO,MAAM,QAAQ,KAC7C9K,EAAAA,aAAa,EAAE,EACfpO,EAAAA,UAAU4Y,CAAwB,EAClCO,EAAAA,WAAYrb,GACHya,GAAYza,EAAI,KAAM,KAAK,MAAM,EAAE,KACxCnD,EAAAA,IAAKye,IAA0B,CAC7B,GAAGtb,EACH,KAAMsb,CAAA,EACN,CAAA,EAEHR,CAAwB,EAC3BzY,EAAAA,YAAY,CAAE,SAAU,GAAM,WAAY,EAAG,CAAA,EAG/C,OAAI9G,GACF,KAAK,cAAc,IAAIA,EAAK,CAC1B,cAAe,EACf,aAAA6f,CAAA,CACD,EAGIF,EAAYE,CAAY,CACjC,CAAC,CACH,CA/GqC,CAyHrC,eACE1U,EACAvJ,EAG4D,CAC5D,OAAI,MAAM,QAAQuJ,CAAQ,EACjBxF,GAAU,IACfe,EAAAA,cACEyE,EAAS,IAAKhJ,GAAS,KAAK,OAAOA,EAAMP,GAAW,EAAE,CAAC,CAAA,EACvD,KAAKoe,EAAAA,eAAe,EAAE,CAAC,CAAA,EAItB,KAAK,OAAO7U,EAAUvJ,GAAW,CAAA,CAAE,CAC5C,CACF,CC9QO,MAAMqe,GAMTte,GAEDC,GAA8C,CAC7C,MAAMC,EAASF,EAAKC,CAAO,EAErB,CAAE,gBAAAse,EAAiB,kBAAAC,GAAsBpD,GAAoBlb,CAAM,EAEzEqe,EAAgB,KAAK3d,YAAUV,EAAO,EAAE,QAAQ,CAAC,EAAE,UAAA,EAEnD,MAAMue,EAAmB,IAAId,GAAiBzd,CAAM,EAEpD,MAAO,CACL,GAAGA,EACH,eAAgBue,EAAiB,eAAe,KAAKA,CAAgB,EACrE,WAAY,CACV,GAAGve,EAAO,WACV,IAAI,OAAQ,CACV,OAAOse,EAAA,CACT,EACA,IAAI,QAAS,CACX,OAAOD,CACT,CAAA,CACF,CAEJ,ECvCIG,GAAkBC,IAwGf,CACL,IAxGU,CAACtgB,EAAaqE,IACjB,IAAI,QAAc,CAACC,EAASic,IAAW,CAC5C,MAAMC,EAAcF,EAAG,YAAY,CAAC,OAAO,EAAG,WAAW,EAEzDE,EAAY,QAAW1iB,GAAU,CAC/ByiB,EAAOziB,CAAK,CACd,EAEA0iB,EAAY,WAAa,IAAM,CAC7Blc,EAAA,CACF,EAGA,MAAMN,EADcwc,EAAY,YAAY,OAAO,EACtB,IAAInc,EAAMrE,CAAG,EAE1CgE,EAAS,UAAY,IAAM,CACzBM,EAAA,CACF,EAEAN,EAAS,QAAWlG,GAAU,CAC5ByiB,EAAOziB,CAAK,CACd,CACF,CAAC,EAmFD,KApCW,IACJ,IAAI,QAAkC,CAACwG,EAASic,IAAW,CAChE,MAAMC,EAAcF,EAAG,YAAY,CAAC,OAAO,EAAG,UAAU,EAExDE,EAAY,QAAW1iB,GAAU,CAC/ByiB,EAAOziB,CAAK,CACd,EAOA,MAAM2iB,EADcD,EAAY,YAAY,OAAO,EACvB,cAAA,EACtBhc,EAAiC,CAAA,EAEvCic,EAAQ,UAAY,IAAM,CACxB,MAAMC,EAASD,EAAQ,OAEvB,GAAI,CAACC,EAAQ,CACXpc,EAAQE,CAAI,EACZ,MACF,CAEAA,EAAK,KAAKkc,EAAO,GAAG,EACpBA,EAAO,SAAA,CACT,EAEAD,EAAQ,QAAU,IAAM,CACtBF,EAAOE,EAAQ,KAAK,CACtB,CACF,CAAC,EAMD,IAjFWzgB,GACJ,IAAI,QAAqB,CAACsE,EAASic,IAAW,CACnD,MAAMC,EAAcF,EAAG,YAAY,CAAC,OAAO,EAAG,WAAW,EAEnDG,EADcD,EAAY,YAAY,OAAO,EACvB,IAAIxgB,CAAG,EAEnCygB,EAAQ,UAAY,IAAM,CACxB,IAAItb,EAAQsb,EAAQ,OAChBtb,IAAU,SACZA,EAAQ,MAEVb,EAAQa,CAAK,CACf,EAEAqb,EAAY,QAAU,IAAM,CAC1BD,EAAOE,EAAQ,KAAK,CACtB,CACF,CAAC,EAiED,OA9DczgB,GACP,IAAI,QAAc,CAACsE,EAASic,IAAW,CAC5C,MAAMC,EAAcF,EAAG,YAAY,CAAC,OAAO,EAAG,WAAW,EAGnDG,EADcD,EAAY,YAAY,OAAO,EACvB,OAAOxgB,CAAG,EAEtCwgB,EAAY,QAAU,IAAM,CAC1BD,EAAOE,EAAQ,KAAK,CACtB,EAEAD,EAAY,WAAa,IAAM,CAC7Blc,EAAA,CACF,EAIAkc,EAAY,QAAU,IAAM,CAC1B,MAAMG,EAAMF,EAAQ,MAAQA,EAAQ,MAAQA,EAAQ,aAAa,MACjEF,EAAOI,CAAG,CACZ,CACF,CAAC,CAyCD,GAISC,GAAe,MAAOC,GAC1B,IAAI,QAA2C,CAACvc,EAASic,IAAW,CACzE,MAAME,EAAU,OAAO,UAAU,KAAKI,CAAI,EAE1CJ,EAAQ,QAAW3iB,GAAU,CAC3ByiB,EAAOziB,CAAK,CACd,EAEA2iB,EAAQ,UAAY,IAAM,CACxBnc,EAAQ+b,GAAeI,EAAQ,MAAM,CAAC,CACxC,EAEAA,EAAQ,gBAAkB,IAAM,CAC9BA,EAAQ,OAAO,kBAAkB,OAAO,CAC1C,CACF,CAAC,EC9GUK,GAA0BnV,GAAqB,CAC1D,IAAIoV,EAAW,KAAK,IAAA,EAAM,SAAA,EAC1B,MAAMC,EAAS,IAAIva,UAKbwa,EACJC,GACG,CACH,GACE,OAAOA,GAAkB,UACzB,OAAOA,GAAkB,SACzB,CACA,MAAM1hB,EACJ,OAAO0hB,GAAkB,SAAWA,EAAc,GAAKA,EACzD,OAAOvV,EAAQ,UAAU,WAAW,KAAM3J,GAAUA,EAAM,KAAOxC,CAAE,CACrE,CAEA,OAAOmM,EAAQ,UAAU,WAAWuV,CAAa,CACnD,EAEMC,EAAM,MACVD,EACAE,IACG,CACH,MAAMjf,EAAO8e,EAAaC,CAAa,EAEvC,GAAI,CAAC/e,EAAM,OAAO,IAAI,SAAS,iBAAkB,CAAE,OAAQ,IAAK,EAIhE,MAAMkf,EAAY,MAFP,MAAMT,GAAa,cAAc,GAEjB,IAAI,GAAGG,CAAQ,IAAI5e,EAAK,EAAE,EAAE,EAEvD,GAAIkf,EACF,OAAO,IAAI,SAASA,EAAW,CAAE,OAAQ,IAAK,EAGhD,MAAMhd,EACH+c,GAAkB,MAAMA,EAAcjf,CAAI,GAAQ,MAAM,MAAMA,EAAK,IAAI,EAE1E,OAAAmf,EAAMnf,EAAMkC,EAAK,OAAO,EAEjBA,CACT,EAEMid,EAAQ,CACZJ,EACA7c,IACG,CACH2c,EAAO,KAAK,CAAE,GAAIE,EAAe,KAAA7c,EAAM,CACzC,EAEA2c,EACG,eACA,KACC7W,EAAAA,SAAS,CAAC,CAAE,GAAA3K,EAAI,KAAA6E,KAAW,CACzB,MAAMlC,EAAO8e,EAAazhB,CAAE,EAE5B,OAAK2C,EAEEV,EAAAA,KACL8f,WAAS,CAACX,GAAa,cAAc,EAAGnf,OAAK4C,EAAK,KAAA,CAAM,CAAC,CAAC,CAAA,EAC1D,KACAnD,EAAAA,UAAU,CAAC,CAACof,EAAIhU,CAAI,IACX7K,OAAK6e,EAAG,IAAI,GAAGS,CAAQ,IAAI5e,EAAK,EAAE,GAAImK,CAAI,CAAC,CACnD,EACD/B,EAAAA,WAAYC,IACV9O,EAAO,MAAM8O,CAAK,EAEXtB,EAAAA,MACR,CAAA,EAZeA,EAAAA,KAcpB,CAAC,EACD3G,EAAAA,UAAUoJ,EAAQ,QAAQ,CAAA,EAE3B,UAAA,EAEH,MAAM6V,EAAU7V,EAAQ,UAAU,KAChCjD,EAAAA,IAAI,IAAM,CACRqY,EAAW,KAAK,IAAA,EAAM,SAAA,CACxB,CAAC,CAAA,EAQH9X,OAAAA,EAAAA,MAAMuY,CAAO,EACV,KACCtgB,EAAAA,UAAU,KACRxF,EAAO,MAAM,yBAAyB,EAE/B+F,EAAAA,KAAKmf,GAAa,cAAc,CAAC,EAAE,KACxC1f,EAAAA,UAAWof,GACT7e,EAAAA,KAAK6e,EAAG,KAAA,CAAM,EAAE,KACdhf,EAAAA,IAAKkD,GACHA,EAAK,OAAQxE,GAAQ,CAACA,EAAI,SAAA,EAAW,WAAW+gB,CAAQ,CAAC,CAAA,EAE3D7f,EAAAA,UAAWugB,GAAiB,CAC1B,MAAMC,EAAWD,EAAa,IAAKzhB,GAAQsgB,EAAG,OAAOtgB,CAAG,CAAC,EAEzD,OAAOyB,OAAK,QAAQ,IAAIigB,CAAQ,CAAC,CACnC,CAAC,CAAA,CACH,EAEFnX,EAAAA,WAAYC,IACV9O,EAAO,MAAM8O,CAAK,EAEXtB,EAAAA,MACR,CAAA,EAEJ,EACD3G,EAAAA,UAAUoJ,EAAQ,QAAQ,CAAA,EAE3B,UAAA,EAMI,CACL,IAAAwV,EACA,QANc,IAAM,CACpBH,EAAO,SAAA,CACT,CAIE,CAEJ,EC5IaW,GAEThgB,GAEDC,GAA2C,CAC1C,MAAMC,EAASF,EAAKC,CAAO,EACrBggB,EAAkBd,GAAuBjf,EAAO,OAAO,EAqB7D,MAAO,CACL,GAAGA,EAKH,QAXc,IAAM,CACpB+f,EAAgB,QAAA,EAChB/f,EAAO,QAAA,CACT,CAQE,CAGJ,ECpCWggB,GAAwB,CACnCC,EACAC,IACG,CACH,MAAMtlB,EAAQqlB,EAAO,KAAK,eAAe,YAAA,EACnCE,EAAaF,EAAO,KAAK,wBAAwBC,EAAM,IAAI,EAEjE,GAAKtlB,EAEL,IAAI,CAEF,GAAIulB,EAAa,KAAK,4BACpBvlB,EAAM,SAASslB,EAAM,KAAMA,EAAM,QAAU,CAAC,EAC5CtlB,EAAM,OAAOqlB,EAAO,KAAMA,EAAO,QAAU,CAAC,UAEnCE,EAAa,KAAK,4BAC3BvlB,EAAM,SAASqlB,EAAO,KAAMA,EAAO,QAAU,CAAC,EAC9CrlB,EAAM,OAAOslB,EAAM,KAAMA,EAAM,QAAU,CAAC,MAGvC,CACH,MAAM1C,EAAc,KAAK,IAAIyC,EAAO,QAAU,EAAGC,EAAM,QAAU,CAAC,EAC5DE,EAAY,KAAK,IAAIH,EAAO,QAAU,EAAGC,EAAM,QAAU,CAAC,EAChEtlB,EAAM,SAASqlB,EAAO,KAAMzC,CAAW,EACvC5iB,EAAM,OAAOqlB,EAAO,KAAMG,CAAS,CACrC,CACF,OAASrkB,EAAG,CACVlC,EAAO,KAAK,wCAAyCkC,EAAG,CACtD,OAAAkkB,EACA,MAAAC,CAAA,CACD,CACH,CAEA,OAAOtlB,EACT,EAEaylB,GAAkC,CAAC,CAC9C,UAAAC,EACA,UAAA9e,CACF,IAQM,CACJ,KAAM,CAAE,WAAA+e,EAAY,aAAAC,EAAc,UAAAC,EAAW,YAAAC,GAAgBJ,EAE7D,GAAI,GAACC,GAAc,CAACE,GAIpB,GAAI,CACF,OAAOT,GACL,CAAE,KAAMO,EAAY,OAAQC,CAAA,EAC5B,CAAE,KAAMC,EAAW,OAAQC,CAAA,CAAY,CAE3C,OAAS3kB,EAAG,CACVlC,EAAO,KAAK,wCAAyCkC,EAAG,CACtD,UAAAukB,EACA,UAAA9e,CAAA,CACD,EAED,MACF,CACF,ECrDO,MAAMmf,WAA8B5J,CAAiB,CAI1D,YAAYjY,EAA0B,CACpC,MAAA,EAEA,MAAM8hB,EAAW9hB,EAAM,iBAAmBA,EAAM,eAAe,SAE/D,GAAI,CAAC8hB,EACH,KAAK,iBAAmBpZ,EAAAA,MACxB,KAAK,eAAiBA,EAAAA,UACjB,CAML,MAAMqZ,EAAoB5c,GAAgB2c,EAAS,KAAM,CACvD,UAAW,GACX,QAAS,EAAA,CACV,EAAE,KACDzY,EAAAA,OACG/D,GACC,CAAC,CAACA,EAAU,KAAM0c,GAEdA,EAAS,OAAS,aAAeA,EAAS,aAAa,MAE1D,CAAA,CACL,EAOIC,EAAoBjiB,EAAM,cAE5BmF,GAAgBnF,EAAM,cAAe,CACnC,UAAW,EAAA,CACZ,EAAE,KACDqJ,EAAAA,OACG2Y,GACC,CAAC,CAACA,EAAS,KAAMA,GACf,MAAM,KAAKA,EAAS,YAAY,EAAE,SAAShiB,CAAK,CAAA,CAClD,CACJ,EATFQ,EAAAA,GAAG,IAAI,EAYX,KAAK,iBAAmB8H,EAAAA,MACtB7H,EAAAA,UAAUqhB,EAAU,iBAAiB,EACrCC,CAAA,EACA,KACAphB,MAAI,IAAMmhB,EAAS,cAAc,EACjClgB,EAAAA,UAAU0G,EAAAA,MAAM2Z,EAAkB,KAAK,QAAQ,CAAC,EAChDvY,EAAAA,QAAQ,IAAI,CAAA,EAGd,KAAK,eAAiBjJ,EAAAA,UAAUqhB,EAAU,aAAa,EAAE,KACvDvhB,EAAAA,UAAU,IACR+H,EAAAA,MACE7H,EAAAA,UAAUqhB,EAAU,WAAW,EAC/BrhB,EAAAA,UAAUqhB,EAAU,eAAe,EACnCrhB,EAAAA,UAAUqhB,EAAU,aAAa,CAAA,EACjC,KACArd,QAAA,EAKAyd,EAAAA,MAAM,CAAC,EACPvhB,EAAAA,IAAKxD,GAAU,CACb,MAAMqkB,EAAYM,EAAS,aAAA,EAE3B,OAAON,GAAa,CAACA,EAAU,YAC1B,CAACrkB,EAAOqkB,CAAS,EAClB,MACN,CAAC,EACDnY,EAAAA,OAAOmH,CAAS,CAAA,CAClB,EAEF5O,EAAAA,UAAU0G,EAAAA,MAAM2Z,EAAkB,KAAK,QAAQ,CAAC,CAAA,CAEpD,CACF,CACF,CCzFO,MAAME,GAA2Bzf,GACtCA,EAAU,MAAM,UAAU,EAAE,KAC1BnC,EAAAA,UAAU,IAAM,CACd,MAAMP,EAAQ0C,EAAU,SAAS,iBAAA,EAC3Bof,EAAW9hB,GAAO,iBAAmBA,GAAO,eAAe,SAEjE,GAAI,CAACA,GAAS,CAAC8hB,EAAU,OAAOpZ,EAAAA,MAEhC,MAAM0Z,EAAmB,IAAIP,GAAsB7hB,CAAK,EAExD,OAAOsI,EAAAA,MACL8Z,EAAiB,iBAAiB,KAChCzhB,EAAAA,IAAK6gB,GAAc,CACjB,GAAIA,GAAW,WACb,MAAO,CACL,KAAM,SACN,UAAAA,CAAA,CAIN,CAAC,CAAA,EAEHY,EAAiB,eAAe,KAC9BzhB,EAAAA,IAAI,CAAC,CAACxD,EAAOqkB,CAAS,KACb,CACL,KAAM,OACN,MAAArkB,EACA,UAAAqkB,CAAA,EAEH,CAAA,CACH,EACA,KACA5f,EAAAA,UAAUc,EAAU,SAAS,EAC7BgH,EAAAA,QAAQ,MAAS,EACjBM,EAAAA,SAAS,IAAM,CACboY,EAAiB,QAAA,CACnB,CAAC,CAAA,CAEL,CAAC,EACDne,EAAAA,qBAAA,CACF,ECjBWoe,GAETrhB,GAGAC,GAmBG,CACH,MAAMC,EAASF,EAAKC,CAAO,EAC3B,IAAIqhB,EAEJ,MAAMC,EAAoBrhB,EAAO,kBAAkB,OAAO,KACxDX,EAAAA,UAAW8H,GAAe,CACxB,MAAMma,EAAYna,EAAW,IAAK3F,GAAc,CAC9C,MAAMub,EACJ/c,EAAO,kBAAkB,kBAAkBwB,CAAS,GAAK,EAE3D,OAAOyf,GAAwBzf,CAAS,EAAE,KACxC/B,EAAAA,IAAKU,GAAU,CACb,GAAKA,EAEL,MAAO,CACL,GAAGA,EACH,UAAA4c,CAAA,CAEJ,CAAC,CAAA,CAEL,CAAC,EAED,OAAO3V,EAAAA,MAAM,GAAGka,CAAS,CAC3B,CAAC,EACDxc,EAAAA,UAAU,MAAS,EACnB/B,uBAAA,EACA8D,EAAAA,IAAKvD,GAAU,CACb8d,EAAe9d,CACjB,CAAC,EACD2B,EAAAA,YAAY,CAAE,SAAU,GAAM,WAAY,EAAG,CAAA,EAGzCsc,EAAaF,EAEbG,EAAkBH,EAAkB,KACxC5hB,EAAAA,IAAK6gB,GAAc,CAAC,CAACA,CAAS,EAC9Bvd,uBAAA,EACAoF,SAAQsZ,GAAgBA,CAAW,EACnC/Z,EAAAA,MAAA,CAAM,EAGFga,EAAgBF,EAAgB,KACpCniB,EAAAA,UAAU,IAAMkiB,CAAU,EAC1Bxe,uBAAA,EACAoF,SAAQmY,GAAc,CAACA,CAAS,EAChC5Y,EAAAA,MAAA,CAAM,EAGFia,EAAiBN,EAAkB,KACvClZ,EAAAA,OAAQmY,GAAcA,GAAW,OAAS,MAAM,EAChD5Y,EAAAA,MAAA,CAAM,EAGFka,EAA8B5hB,EAAO,QACxC,MAAM,aAAa,EACnB,KACCmI,EAAAA,OAAOmH,CAAS,EAChBjQ,EAAAA,UAAWmS,GAAcjS,EAAAA,UAAUiS,EAAW,aAAa,CAAC,EAC5DiG,EAAAA,eAAe8J,CAAU,EACzB9hB,EAAAA,IAAI,CAAC,CAAA,CAAG6gB,CAAS,IAAMA,CAAS,EAChCxb,EAAAA,UAAU,MAAS,EACnBG,EAAAA,YAAY,CAAE,SAAU,GAAM,WAAY,EAAG,CAAA,EAGjDmC,OAAAA,EAAAA,MAAMma,EAAYK,CAA2B,EAC1C,KAAKlhB,EAAAA,UAAUV,EAAO,EAAE,QAAQ,CAAC,EACjC,UAAA,EAEI,CACL,GAAGA,EACH,UAAW,CACT,WAAAuhB,EACA,gBAAAC,EACA,cAAAE,EACA,eAAAC,EACA,4BAAAC,EACA,aAAc,IAAMR,EACpB,gCAAAf,EAAA,CACF,CAEJ,ECvIIwB,GAAgB,CACpB,CACE,KAAM,SACN,gBAAiB,OAAA,EAEnB,CACE,KAAM,QACN,gBAAiB,UACjB,gBAAiB,OAAA,EAEnB,CACE,KAAM,QACN,gBAAiB,UACjB,gBAAiB,SAAA,CAErB,EAuBaC,GAAgChiB,GAAUC,GAAY,CACjE,MAAMC,EAASF,EAAKC,CAAO,EACrBgiB,EAAuB,IAAIla,EAAAA,gBAC/B9H,EAAQ,OAAS,QAAA,EAGbsG,EAAW,IAAM,CACrB,MAAM2b,EAAaH,GAAc,KAC9B1hB,GAAUA,EAAM,OAAS4hB,EAAqB,KAAA,EAGjD,MAAO;AAAA;AAAA,UAEDC,IAAe,OAAY,qBAAqBA,EAAW,eAAe,eAAiB,EAAE;AAAA;AAAA,QAG/FA,GAAY,gBACR;AAAA;AAAA;AAAA,qBAQSA,EAAW,eAAe;AAAA;AAAA,UAGnC,EACN;AAAA,KAEJ,EAEMC,EAAgC,CAAC,CACrC,UAAAzQ,CAAA,IAGI,CACJ,MAAMwQ,EAAaH,GAAc,KAC9B1hB,GAAUA,EAAM,OAAS4hB,EAAqB,KAAA,EAEjD,OAAIC,GACFxQ,EAAU,MAAM,YACd,mBACAwQ,EAAW,eAAA,EAIR,IAAM,CAEb,CACF,EAEME,EAAyB,IAAM,CACnCliB,EAAO,kBAAkB,MAAM,QAASM,GAAS,CAC/C,MAAMxB,EAAQwB,EAAK,SAAS,iBAAA,EAExBxB,GACFH,EAAiBG,EAAO,qBAAsBuH,EAAA,CAAU,EAG1D4b,EAA8B,CAAE,UAAW3hB,EAAK,OAAA,CAAS,CAC3D,CAAC,CACH,EAKA,OAAAN,EAAO,YAAY,SAAS,sBAAuB,CAAC,CAAE,OAAAI,KAAa,CACjE,MAAME,EAAON,EAAO,kBAAkB,IAAII,CAAM,EAShD,GAAIE,GAAM,kBAAoB,gBAAiB,CAC7C,MAAMxB,EAAQwB,GAAM,SAAS,iBAAA,EAEzBxB,GACFH,EAAiBG,EAAO,qBAAsBuH,EAAA,CAAU,CAE5D,CACF,CAAC,EAMDrG,EAAO,kBAAkB,OACtB,KACC6G,EAAAA,IAAKU,GACHA,EAAM,IAAI,CAAC,CAAE,QAAA/M,CAAA,IACXynB,EAA8B,CAAE,UAAWznB,EAAS,CAAA,CACtD,EAEFkG,YAAUV,EAAO,EAAE,QAAQ,CAAA,EAE5B,UAAA,EAEH+hB,EACG,KACClb,EAAAA,IAAI,IAAM,CACRqb,EAAA,CACF,CAAC,EACDxhB,YAAUV,EAAO,EAAE,QAAQ,CAAA,EAE5B,UAAA,EAEI,CACL,GAAGA,EACH,MAAO,CACL,IAAM8R,GAAU,CACVA,IAAUiQ,EAAqB,OACjCA,EAAqB,KAAKjQ,CAAK,CAEnC,EACA,IAAK,IAAMiQ,EAAqB,MAChC,EAAG,CACD,OAAQA,EAAqB,aAAA,CAAa,CAC5C,CACF,CAEJ,ECrKaI,GAETriB,GAGAC,GAUG,CACH,MAAMC,EAASF,EAAKC,CAAO,EAwB3B,MAAO,CACL,GAAGC,EACH,MAAO,CACL,sBAzB2BkE,GACzB,GAAA5G,GAAc4G,CAAM,IACTA,EAAO,WAAa,IAAMA,EAASA,EAAO,QAAQ,GAAG,IACxD,aAAa,MAAM,GAuB7B,gBAfoB,CACtBjK,EACAmoB,EACAC,IACG,CAEH,MAAMC,EAAsBD,EAAc,QAAQ,QAASriB,EAAO,EAAE,EAEpE,OAAOtC,EAAUzD,EAAK,GAAGmoB,CAAK,IAAIpiB,EAAO,EAAE,GAAIsiB,CAAmB,CACpE,CAMI,CACF,CAEJ,ECvCA,UAAU,UAAU,QAAQ,EAAE,EAAI,IAClC,UAAU,UAAU,QAAQ,QAAQ,GAAK,GAKpC,MAAMC,GAKTC,GAEDziB,GACgByiB,EAAaziB,CAAO,4NClB1B0iB,GAAkC,CAC7C9mB,EACA+mB,EACApoB,IACG,CACH,KAAM,CAAE,YAAAqoB,EAAa,aAAAC,CAAA,EAAiBtoB,EAAS,MAAM,QAI/CuoB,EAAS,CACb,KAAM,EACN,KAAMF,GAAe,EAAID,GACzB,KAAM,EACN,KAAME,GAAgB,EAAIF,EAAA,EAG5B,MAAO,CACL,EAAG,KAAK,IAAI,KAAK,IAAI/mB,EAAS,EAAGknB,EAAO,IAAI,EAAGA,EAAO,IAAI,EAC1D,EAAG,KAAK,IAAI,KAAK,IAAIlnB,EAAS,EAAGknB,EAAO,IAAI,EAAGA,EAAO,IAAI,CAAA,CAE9D,EC3BaC,GAA0C,CACrDJ,EACA/mB,EACAonB,IACG,CACHA,EAAgB,MAAM,gBAAkB,MAExC,MAAMC,EAAqB,eAAernB,EAAS,CAAC,OAAOA,EAAS,CAAC,WAC/DsnB,EAAiB,SAASP,CAAK,IAErCK,EAAgB,MAAM,UAAY,GAAGC,CAAkB,IAAIC,CAAc,EAC3E,EAEaC,GAA2C,CACtDC,EACAC,EACAL,EACA9I,IACG,CACH,MAAMoJ,EAAcD,EAAYD,EAG1BG,EAAgBP,EAAgB,YAChCQ,EAAiBR,EAAgB,aAIjCS,EAAgBF,EAAgB,EAAIrJ,EAAgB,EACpDwJ,EAAgBF,EAAiB,EAAItJ,EAAgB,EAQ3D,MALoB,CAClB,EAAGA,EAAgB,EAAIuJ,GAAiB,EAAIH,GAC5C,EAAGpJ,EAAgB,EAAIwJ,GAAiB,EAAIJ,EAAA,CAIhD,EChCO,MAAeK,EAAiB,CAIrC,YAAY/nB,EAAoC,CAC9C,KAAK,EAAIA,EAAS,EAClB,KAAK,EAAIA,EAAS,CACpB,CACF,CCqBO,MAAMgoB,WAAuBD,EAAiB,CAAC,CAC/C,MAAME,WAA8BF,EAAiB,CAArD,aAAA,CAAA,MAAA,GAAA,SAAA,EACL,KAAgB,gBAAkB,uBAAuB,CAAA,CAC3D,CAMO,MAAMG,WAAmClc,CAE7C,CASD,YACYrN,EACA0K,EACA8e,EACAC,EACAja,EACV,CACA,MAAM,CACJ,QAAS,MAAA,CACV,EARS,KAAA,SAAAxP,EACA,KAAA,SAAA0K,EACA,KAAA,YAAA8e,EACA,KAAA,MAAAC,EACA,KAAA,QAAAja,EAbZ,KAAU,gBACR,IAAIlF,UACN,KAAU,iBAAmB,IAAIiD,EAAAA,gBAAgB,EAAK,EAEtD,KAAO,aAAe,KAAK,iBAAiB,aAAA,EAoH5C,KAAU,oBAAsB,CAAC,CAC/B,SAAAlM,CAAA,IAC6C,CAC7C,MAAMnB,EAAU,KAAK,MAAM,QAE3B,KAAK,iBAAiB,KAAK,EAAI,EAE/B,MAAMwpB,EAAiB,KAAK,kBAAkBroB,CAAQ,EAEtDnB,GAAS,SAAS,CAChB,KAAMwpB,EAAe,EACrB,IAAKA,EAAe,EACpB,SAAU,SAAA,CACX,EAEDC,EAAAA,MAAM,CAAC,EACJ,KACCpd,EAAAA,IAAI,IAAM,CACR,KAAK,iBAAiB,KAAK,EAAK,CAClC,CAAC,EACDnG,YAAU0G,EAAAA,MAAM,KAAK,iBAAiB,KAAKgM,EAAAA,KAAK,CAAC,CAAC,EAAG,KAAK,QAAQ,CAAC,CAAA,EAEpE,UAAA,EAEH,KAAK,YAAY,QAAQ,yBAA0B,OAAW,CAAA,CAAE,CAClE,EA9HE,MAAM8Q,EAAmB,KAAK,QAAQ,KACpCphB,EAAU,CAAC,aAAa,CAAC,EACzB+D,MAAI,CAAC,CAAE,YAAAlG,KAAkB,CACvB,GAAI,CAACA,EAAa,OAElB,MAAMnG,EAAU,SAAS,cAAc,KAAK,EAC5CA,EAAQ,aAAa,QAAQkR,EAA4B,GAAI,EAAE,EAC/DlR,EAAQ,YAAY,KAAK,SAAS,MAAM,OAAO,EAC/CmG,EAAY,YAAYnG,CAAO,EAE/B,KAAK,OAAO,CAAE,QAAAA,EAAS,CACzB,CAAC,CAAA,EAGG2pB,EAAwBtf,EAAAA,cAAc,CAC1CG,EAAS,MAAM,CAAC,sBAAsB,CAAC,EACvC,KAAK,MAAM,SAAS,CAAA,CACrB,EAAE,KACD6B,EAAAA,IAAI,CAAC,CAAC,CAAE,qBAAAK,CAAA,EAAwB1M,CAAO,IAAM,CACtCA,IAED0M,IAAyB,aAC3B1M,EAAQ,MAAM,QAAU,QAExBA,EAAQ,MAAM,QAAU,WAE5B,CAAC,CAAA,EAGG4pB,EAAY,KAAK,gBAAgB,KAAKvd,MAAI,KAAK,mBAAmB,CAAC,EAEzE,KAAK,cAAgB,KAAK,gBAAgB,KACxC/B,EAAAA,UAAU,EAAK,EACfzF,EAAAA,UAAU,IAAM+H,EAAAA,MAAM9H,EAAAA,GAAG,EAAI,EAAGA,EAAAA,GAAG,EAAK,CAAC,CAAC,EAC1C2F,EAAAA,YAAY,CAAC,CAAA,EAIf,MAAMof,EAAoBjd,EAAAA,MACxB2c,EAAM,SAAS,KACb5b,EAAAA,OAAOmH,CAAS,EAChBjQ,EAAAA,UAAW7E,GAAYyI,EAAczI,CAAO,CAAC,CAAA,EAE/CupB,EAAM,SAAS,KACb5b,EAAAA,OAAOmH,CAAS,EAChBjQ,EAAAA,UAAW7E,GAAY+E,YAAU/E,EAAS,QAAQ,CAAC,CAAA,EAErDupB,EAAM,mBAAmB,WAAA,EACzB,KACA1kB,EAAAA,UAAU,IACR4kB,EAAAA,MAAM,EAAE,EAAE,KACRxkB,EAAAA,IAAI,IAAM,EAAK,EACfqF,EAAAA,UAAU,EAAI,CAAA,CAChB,EAEF/B,uBAAA,EACA+B,EAAAA,UAAU,EAAK,CAAA,EAGXwf,EAA8Bzf,EAAAA,cAAc,CAChDwf,EACA,KAAK,YAAA,CACN,EAAE,KACD5kB,EAAAA,IACE,CAAC,CAAC8kB,EAAgBC,CAAiB,IACjCD,GAAkBC,CAAA,EAEtBvf,EAAAA,YAAY,CAAC,CAAA,EAGf,KAAK,YAAc,KAAK,MAAM,SAAS,EAAE,KACvCkD,EAAAA,OAAOmH,CAAS,EAChBjQ,EAAAA,UAAW7E,GACTwK,EAAS,MAAM,CAAC,sBAAsB,CAAC,EAAE,KACvC3F,EAAAA,UAAU,CAAC,CAAE,qBAAA6H,CAAA,IACXA,IAAyB,aACrBM,EAAAA,MACAjI,EAAAA,UAAU/E,EAAS,QAAQ,EAAE,KAC3Bid,EAAAA,eAAe6M,CAA2B,EAC1Cnc,EAAAA,OACE,CAAC,CAAA,CAAGsc,CAAsB,IAAM,CAACA,CAAA,EAEnChlB,MAAI,CAAC,CAACxD,CAAK,IAAMA,CAAK,CAAA,CACxB,CACN,CACF,EAEFyL,EAAAA,MAAA,CAAM,EAGRN,EAAAA,MAAM8c,EAAkBC,EAAuBC,CAAS,EACrD,KAAK1jB,EAAAA,UAAU,KAAK,QAAQ,CAAC,EAC7B,UAAA,CACL,CAmCO,OACL4C,EAGA,CACA,KAAK,aAAaA,CAAK,CACzB,CAEA,SAASqS,EAAqD,CAC5D,KAAK,gBAAgB,KAAKA,CAAU,CACtC,CAEO,mBAAmBha,EAAkD,CAC1E,MAAM0nB,EAAc,KAAK,SAAS,YAElC,OAAO,IAAIpT,EAAqB,CAC9B,EAAGtU,EAAS,EAAI0nB,EAChB,EAAG1nB,EAAS,EAAI0nB,CAAA,CACjB,CACH,CAEO,kBAAkB1nB,EAAgD,CACvE,MAAM0nB,EAAc,KAAK,SAAS,YAElC,OAAO,IAAIM,GAAe,CACxB,EAAGhoB,EAAS,EAAI0nB,EAChB,EAAG1nB,EAAS,EAAI0nB,CAAA,CACjB,CACH,CAEA,IAAW,gBAAiB,CAC1B,MAAM7oB,EAAU,KAAK,MAAM,QAE3B,OAAO,IAAImpB,GAAe,CACxB,EAAGnpB,GAAS,YAAc,EAC1B,EAAGA,GAAS,WAAa,CAAA,CAC1B,CACH,CACF,CClOO,MAAMkqB,GAAoC,CAC/CC,EACAC,EACAC,EACAC,EACAC,IACG,CACH,MAAMC,EAAiBL,EAAgB,YACjCM,EAAkBN,EAAgB,aAGlCO,EAAoBP,EAAgB,WACpCQ,EAAmBR,EAAgB,UAGnCS,EAAiBF,EAAoBF,EAAiB,EAAIF,EAC1DO,EAAiBF,EAAmBF,EAAkB,EAAIF,EAG1D1B,EAAcwB,EAAUD,EACxBU,EAAoBF,EAAiB/B,EACrCkC,EAAoBF,EAAiBhC,EAGrCmC,EAAaF,EAAoBN,EAAiB,EAAIF,EACtDW,EAAYF,EAAoBN,EAAkB,EAAIF,EAE5D,OAAO,IAAInB,GAAsB,CAC/B,EAAG4B,EACH,EAAGC,CAAA,CACJ,CACH,EAEaC,GAAgC,CAC3ChD,EACA1iB,IACG,CACH,MAAM1F,EAAW0F,EAAO,SAClBkX,EACJlX,EAAO,WAAW,2BACd+iB,EAAkBzoB,EAAS,MAAM,QACjCqqB,EAAkBzN,EAA2B,MAAM,QACnDyO,EAA0BzO,EAA2B,MAAM,QAE3DiM,EAAe,KAAK,MAAM7oB,EAAS,YAAc,GAAG,EAAI,IAIxDwqB,EAAU/B,EAAgB,WAC1BgC,EAAUhC,EAAgB,UAE1B6C,EACJlB,GACEC,GAAmBtoB,GAAA,EACnB8mB,EACAT,EACAoC,EACAC,CAAA,EAGEc,EAAYnD,EAAQ,EAAI,OAAS,KACvCiD,GAAyB,aACvB,QAAQra,CAAW,qBACnBua,CAAA,EASEnD,EAAQ,EACVK,EAAgB,MAAM,gBAAkB,MAC/BL,EAAQ,IASjBK,EAAgB,MAAM,gBAAkB,GAAG+B,CAAO,MAAMC,CAAO,MAGjEhC,EAAgB,MAAM,UAAY,SAASL,CAAK,IAEhD,MAAMnL,EAAgBL,EAA2B,mBAC/C0O,CAAA,EAGF5lB,EAAO,WAAW,SAAS,CACzB,SAAUuX,CAAA,CACX,CACH,EC7DMuO,GAAqB,IAEpB,MAAMC,WAAuBpe,CAAoC,CAWtE,YAAsB3H,EAAgB,CACpC,MAAM,CACJ,UAAW,GACX,aAAc,EACd,gBAAiB,CAAE,EAAG,EAAG,EAAG,CAAA,CAAE,CAC/B,EALmB,KAAA,OAAAA,EAVtB,KAAQ,aAAe,IAAI4E,UAQ3B,KAAQ,YAAc,IAAIA,UASxB,MAAMohB,EAAS,KAAK,aAAa,KAC/B3mB,EAAAA,UAAWU,GAAY,CACrB,KAAM,CAAE,MAAA2iB,EAAQ,EAAG,QAAAuD,EAAU,EAAA,EAAUlmB,GAAW,CAAA,EAC5CgjB,EAAkB,KAAK,OAAO,SAAS,MAAM,QAwBnD,OAtBA,KAAK,SAAS,QAAQ,aACpB,QAAQzX,CAAW,WACnB,MAAA,EAGF,KAAK,2BAA2B,MAAM,SAAS,aAC7C,QAAQA,CAAW,WACnB,KAAK,aAAe,QAAU,MAAA,EAG5B2a,GAAW,KAAK,eAClBlD,EAAgB,MAAM,WAAa,aAAa+C,EAAkB,MAGpE,KAAK,aAAa,CAChB,UAAW,GACX,aAAc,EACd,gBAAiB,CAAE,EAAG,EAAG,EAAG,CAAA,CAAE,CAC/B,EAED,KAAK,WAAWpD,CAAK,EAEjBA,IAAU,GAAK,KAAK,aACfuB,EAAAA,MAAMlkB,GAAS,QAAU+lB,GAAqB,CAAC,EAAE,KACtDjf,EAAAA,IAAI,IAAM,CACR,KAAK,OAAO,OAAA,CACd,CAAC,CAAA,EAIEQ,EAAAA,KACT,CAAC,CAAA,EAGG6e,EAAQ,KAAK,YAAY,KAC7B7mB,EAAAA,UAAWU,GAAY,CACrB,MAAMgjB,EAAkB,KAAK,OAAO,SAAS,MAAM,QAEnD,YAAK,SAAS,QAAQ,aACpB,QAAQzX,CAAW,WACnB,OAAA,EAGF,KAAK,2BAA2B,MAAM,SAAS,gBAC7C,QAAQA,CAAW,oBAAA,EAErB,KAAK,2BAA2B,MAAM,SAAS,aAC7C,QAAQA,CAAW,WACnB,OAAA,EAGEvL,GAAS,SAAW,KAAK,eAC3BgjB,EAAgB,MAAM,WAAa,aAAa+C,EAAkB,MAGpE,KAAK,WAAW,EAAG,CAAE,EAAG,EAAG,EAAG,EAAG,EAEjC/C,EAAgB,MAAM,UAAY,GAElC,KAAK,aAAa,CAChB,UAAW,EAAA,CACZ,EAEMkB,EAAAA,MAAMlkB,GAAS,QAAU+lB,GAAqB,CAAC,EAAE,KACtDjf,EAAAA,IAAI,IAAM,CACR,MAAMkc,EAAkB,KAAK,OAAO,SAAS,MAAM,QACnDA,EAAgB,MAAM,gBAAkB,GACxCA,EAAgB,MAAM,WAAa,GAE/B,KAAK,cACP,KAAK,OAAO,OAAA,CAEhB,CAAC,EACDriB,EAAAA,UAAU,KAAK,YAAY,CAAA,CAE/B,CAAC,CAAA,EAGH0G,QAAM4e,EAAQE,CAAK,EAAE,KAAKxlB,EAAAA,UAAU,KAAK,QAAQ,CAAC,EAAE,UAAA,CACtD,CAEO,MAAMX,EAAqD,CAChE,KAAK,aAAa,KAAKA,CAAO,CAChC,CAEO,KAAKA,EAAoD,CAC9D,KAAK,YAAY,KAAKA,CAAO,CAC/B,CAEO,KACLpE,EACAoE,EACA,CAEK,KAAK,eAGV,KAAK,SAAS,QAAQ,MAAM,WAAa,GAEzC,KAAK,WAAW,KAAK,MAAM,aAAcpE,EAAU,CACjD,YACEoE,GAAS,YAAc,kBACnB,IAAI8F,IACF4c,GAAgC,GAAG5c,EAAM,KAAK,OAAO,QAAQ,EAC/D,MAAA,CACP,EACH,CAEO,QACLud,EACArjB,EACM,CAEN,KAAK,SAAS,QAAQ,MAAM,WAAa,GAGzC,MAAMomB,EADe,KAAK,KAAK/C,EAAY,GAAG,EAAI,IAGlD,KAAK,WAAW+C,EAAU,OAAW,CACnC,YACEpmB,GAAS,YAAc,kBACnB,IAAI8F,IACF4c,GAAgC,GAAG5c,EAAM,KAAK,OAAO,QAAQ,EAC/D,MAAA,CACP,CACH,CAEU,WACR6c,EACA/mB,EACAoE,EAGA,CACA,GAAI,KAAK,aAAc,CACrB,MAAMqmB,EAAczqB,GAEhBunB,GACE,KAAK,MAAM,aACXR,EACA,KAAK,SAAS,QACd,KAAK,MAAM,eAAA,EAGX2D,EACJtmB,GAAS,cAAcqmB,EAAa1D,CAAK,GAAK0D,EAEhD,YAAK,UAAU1D,EAAO2D,CAAmB,EAElC,KAAK,aAAa,CACvB,aAAc3D,EACd,gBAAiB2D,CAAA,CAClB,CACH,CAEA,KAAK,UAAU3D,EAAO/mB,GAAY,KAAK,MAAM,eAAe,EAE5D,KAAK,aAAa,CAChB,aAAc+mB,CAAA,CACf,CACH,CAEU,UAAUA,EAAe/mB,EAAoC,CAChE,KAAK,aAORmnB,GACEJ,EACA/mB,EACA,KAAK,SAAS,OAAA,EALhB+pB,GAA8BhD,EAAO,KAAK,MAAM,CAQpD,CAEA,IAAc,cAAe,CAC3B,OAAO,KAAK,OAAO,SAAS,OAAO,uBAAyB,YAC9D,CAEA,IAAc,4BAA6B,CACzC,OAAO,KAAK,OAAO,WAAW,0BAChC,CAEA,IAAc,UAAW,CACvB,OAAO,KAAK,OAAO,SAAS,KAC9B,CACF,CCtPA,MAAM4D,GAAY,GAAG/a,EAAiB,iBAEzBgb,GAETzmB,GAEDC,GAAgE,CAC/D,MAAMC,EAASF,EAAKC,CAAO,EACrBymB,EAAiB,IAAIT,GAAe/lB,CAAM,EAEhDtC,EAAU,SAAU4oB,GAAWG,EAAM,EAErC,MAAMpmB,EAAU,IAAM,CACpBtC,EAAU,SAAUuoB,EAAS,EAE7BE,EAAe,QAAA,EACfxmB,EAAO,QAAA,CACT,EAEMwY,EAASgO,EAEf,MAAO,CACL,GAAGxmB,EACH,QAAAK,EACA,KAAM,CACJ,MAAOmmB,EAAe,MAAM,KAAKA,CAAc,EAC/C,QAASA,EAAe,QAAQ,KAAKA,CAAc,EACnD,KAAMA,EAAe,KAAK,KAAKA,CAAc,EAC7C,KAAMA,EAAe,KAAK,KAAKA,CAAc,EAC7C,OAAAhO,EACA,IAAI,OAAQ,CACV,OAAOgO,EAAe,KACxB,CAAA,CACF,CAEJ,ECxCWE,GAAuBnY,GAClCA,GAAU,kBAAoB,iBAC9BA,GAAU,WAAW,MAAOjO,GAASA,EAAK,kBAAoB,eAAe,ECexE,MAAMqmB,EAAY,CAAlB,aAAA,CACL,KAAO,kBAAoB,IAAIC,EAAAA,cAA0B,CAAC,EAC1D,KAAO,qBAAuB,IAAI/e,kBAAiC,MAAM,EACzE,KAAO,kBAAoB,IAAI+e,gBAC/B,KAAO,0BAA4B,IAAI/e,EAAAA,gBAAgB,EAAK,EAK5D,KAAO,YAAc,KAAK,kBAAkB,aAAA,EAK5C,KAAO,oBAAsB,KAAK,0BAA0B,KAC1D9E,uBAAA,EACAoF,SAAQ0e,GAAa,CAACA,CAAQ,CAAA,EAMhC,KAAO,eAAiB,KAAK,qBAAqB,aAAA,EAKlD,KAAO,cAAgB,KAAK,eAAe,KACzC1e,SAAQS,GAAUA,IAAU,MAAM,CAAA,EAMpC,KAAO,cAAgB,KAAK,eAAe,KACzCT,SAAQS,GAAUA,IAAU,MAAM,CAAA,EAMpC,KAAO,YAAc,KAAK,kBAAkB,aAAA,CAAa,CAC3D,CC9CO,MAAMke,WAAgBnf,CAA6B,CAQxD,aAAc,CACZ,MAAM,CACJ,uBAAwB,YAAA,CACzB,EAVH,KAAO,YAAc,IAAIgf,GACzB,KAAO,UAAY,KAAK,KACtBlnB,EAAAA,IAAKmJ,GAAUA,EAAM,QAAQ,EAC7BT,EAAAA,OAAOmH,CAAS,EAChBvM,EAAAA,qBAAA,CAAqB,EA4BvB,KAAO,MAAQ,IACN,KAAK,MAAM,UAAU,mBAAqB,KAtBnD,CAEO,OAAOgkB,EAAiC,CAC7C,MAAMC,EAAgB,KAAK,MACrBzY,EAAWwY,EAAS,UAAYC,EAAc,SAE9CC,EAAmB,CACvB,GAAGD,EACH,GAAGD,EACH,GAAIA,EAAS,UAAY,CACvB,oBAAqBL,GAAoBnY,CAAQ,EACjD,uBAAwBA,GAAU,iBAAmB,YAAA,CACvD,EAGF,KAAK,aAAa0Y,CAAgB,CACpC,CASA,IAAI,UAAW,CACb,OAAO,KAAK,MAAM,QACpB,CAEA,IAAI,kBAAmB,CACrB,OAAO,KAAK,UAAU,gBACxB,CACF,CCrCO,MAAMC,WAAiBvf,CAAsB,CAClD,YAAYmC,EAAkBrF,EAAwC,CACpE,MAAM,CACJ,2BAA4B,CAAC,OAAQ,OAAQ,OAAO,EACpD,sBAAuB,CAAC,aAAc,YAAY,EAClD,2BAA4B,CAAC,aAAc,UAAU,EACrD,mCAAoC,CAAC,aAAc,UAAU,CAAA,CAC9D,EAEDI,gBAAc,CACZiF,EAAQ,MAAM,CAAC,WAAY,oBAAoB,CAAC,EAChDrF,EAAgB,MAAM,CAAC,sBAAsB,CAAC,CAAA,CAC/C,EACE,KACChF,EAAAA,IAAI,CAAC,CAAC,CAAE,SAAA8O,EAAU,mBAAA4Y,GAAsB,CAAE,qBAAAjgB,CAAA,CAAsB,KAAO,CACrE,mBAAAigB,EACA,cAAe5Y,GAAU,cACzB,gBAAiBA,GAAU,gBAC3B,qBAAArH,CAAA,EACA,EACFnE,EAAAA,qBAAqBC,EAAAA,cAAc,EACnCvD,EAAAA,IACE,CAAC,CACC,mBAAA0nB,EACA,cAAAC,EACA,gBAAAC,EACA,qBAAAngB,CAAA,KAEO,CACL,GAAG,KAAK,MACR,sBACEkgB,IAAkB,sBACd,CAAC,YAAY,EACb,CAAC,aAAc,YAAY,EACjC,2BACEA,IAAkB,uBAClBlgB,IAAyB,aACrB,CAAC,MAAM,EACPigB,EACE,CAAC,OAAQ,MAAM,EACf,CAAC,OAAQ,OAAQ,OAAO,EAChC,2BACEjgB,IAAyB,aACrB,CAAC,UAAU,EACXmgB,IAAoB,aAClB,CAAC,YAAY,EACb,CAAC,aAAc,UAAU,CAAA,EAErC,EAEF3mB,EAAAA,UAAU,KAAK,QAAQ,CAAA,EAExB,UAAU,KAAK,KAAK,KAAK,IAAI,CAAC,CACnC,CACF,CClEO,MAAM4mB,EAAsD,CAA5D,aAAA,CACL,KAAA,OAAmB,CAAA,EACnB,KAAA,gBAA2C,CAAA,CAAC,CAOlC,WAAWC,EAAqB,CACxC,YAAK,OAAS,KAAK,OAAO,OAAQC,GAASA,IAASD,CAAgB,EAE7D,KAAK,QAAQA,EAAiB,KAAM,OAAWA,CAAgB,CACxE,CAOO,SACLvI,EACAyI,EACA,CACA,MAAMD,EAAO,CACX,KAAAxI,EACA,MAAOyI,CAAA,EAGT,YAAK,OAAO,KAAKD,CAAS,EAEnB,IAAM,CACX,KAAK,WAAWA,CAAS,CAC3B,CACF,CAEO,QACLxI,EACArhB,EACAsK,EAI0C,CAuC1C,OAtCc,KAAK,OAAO,OACvBuf,GAAoCxI,IAASwI,EAAK,IAAA,EAG7B,IAAKA,GAAS,CACpC,IAAIE,EAA+B,IAAMpoB,EAAAA,GAAG,MAAS,EAErD,MAAMqoB,EAAiB,IAAI/iB,UACrBvE,EAAWonB,GAAsB,CACrCC,EAAgBD,CAClB,EAEMG,EAAY,KAChBD,EAAe,KAAA,EACfA,EAAe,SAAA,EAEAD,EAAA,GAEEpoB,EAAAA,GAAG,MAAS,GAGzBuoB,EAAWL,EAAK,MAAM,CAE1B,GAAIvf,EACJ,SAAU0f,EAAe,aAAA,EACzB,QAAAtnB,CAAA,CACD,EAED,YAAK,gBAAgB,KAAK,CACxB,KAAA2e,EACA,GAAArhB,EACA,UAAAiqB,EACA,IAAKJ,CAAA,CACN,EAEMK,CACT,CAAC,CAGH,CAEO,QAAgC7I,EAAYrhB,EAAamqB,EAAS,CACvE,MAAMxG,EAAY,KAAK,gBAAgB,OACpCyG,GAEED,GAAOC,EAAa,MAAQD,GAE5B9I,IAAS+I,EAAa,OAAS,CAACpqB,GAAOA,GAAMA,IAAOoqB,EAAa,GAAA,EAItE,KAAK,gBAAkB,KAAK,gBAAgB,OACzCC,GAAa,CAAC1G,EAAU,SAAS0G,CAAQ,CAAA,EAG5C,MAAMC,EAAa3G,EAAU,IAAI,CAAC,CAAE,UAAAsG,CAAA,IAAgBA,GAAW,EAE/D,OAAO/iB,EAAAA,cAAcojB,CAAU,CACjC,CACF,2NC1GaC,GAA8BvsB,IAClC,CACL,EAAG,CAACA,EAAS,EACb,EAAG,CAACA,EAAS,CAAA,GAIJwsB,GACXC,GAEIA,aAAuB,UAClB,IAAIpY,EAAc,CACvB,EAAG,CAACoY,EAAY,EAChB,EAAG,CAACA,EAAY,CAAA,CACjB,EAGI,IAAIpY,EAAc,CACvB,EAAG,CAACoY,EAAY,EAChB,EAAG,CAACA,EAAY,CAAA,CACjB,ECWGC,GAASxuB,EAAO,UAFJ,8BAEuB,EAOlC,MAAMyuB,WAAuCvR,CAAiB,CASnE,YACY/R,EACA8e,EACAha,EACAia,EACAzpB,EACV,CACA,MAAA,EANU,KAAA,SAAA0K,EACA,KAAA,YAAA8e,EACA,KAAA,QAAAha,EACA,KAAA,MAAAia,EACA,KAAA,SAAAzpB,EAbZ,KAAU,gBAAkB,IAAIsK,UAEhC,KAAgB,SAAW,IAAIiD,EAAAA,gBAC7B,SAAS,cAAc,KAAK,CAAA,EAc5B,MAAM0gB,EAAe,KAAK,MAAM,SAAS,KACvCpgB,EAAAA,OAAOmH,CAAS,EAChBmI,EAAAA,eAAe,KAAK,QAAQ,EAC5B5Q,EAAAA,IAAI,CAAC,CAAC4J,EAAcjW,CAAO,IAAM,CAC/BA,EAAQ,MAAM,QAAU;AAAA;AAAA;AAAA;AAAA,UAKxBA,EAAQ,UAAY,GAAG8Q,CAAW,wBAClC9Q,EAAQ,UAAY,GACpBA,EAAQ,YAAYiW,CAAY,EAChC,KAAK,SAAS,MAAM,QAAQ,YAAYjW,CAAO,EAC/C,KAAK,SAAS,KAAKA,CAAO,CAC5B,CAAC,CAAA,EAGGguB,EAA6BxjB,EAAS,MAAM,CAChD,4BACA,uBACA,oCAAA,CACD,EAUKyjB,EAAiC5jB,EAAAA,cAAc,CACnD2jB,EACA,KAAK,QAAA,CACN,EAAE,KACD3hB,MAAI,CAAC,CAAA,CAAGrM,CAAO,IAAM,CACfwK,EAAS,OAAO,uBAAyB,aAC3CxK,EAAQ,MAAM,QAAU,WAExBA,EAAQ,MAAM,QAAU,OAE5B,CAAC,CAAA,EAGH,KAAK,QAAUiuB,EAA+B,KAC5C5hB,EAAAA,IAAI,IAAM,CACRwhB,GAAO,KAAK,SAAUrjB,EAAS,MAAM,CACvC,CAAC,EACD0C,EAAAA,MAAA,CAAM,EAGR,MAAM0c,EAAY,KAAK,gBAAgB,KACrCvd,EAAAA,IAAK8O,GAAe,CAClB0S,GAAO,KAAK,uBAAwB1S,CAAU,CAChD,CAAC,CAAA,EAGH,KAAK,cAAgByO,EAAU,KAC7B3kB,EAAAA,IAAI,CAAC,CAAE,UAAAipB,EAAW,SAAA/sB,MAOT,CACL,KAAM,eACN,cARoB,EACpB,CAAC+sB,GACAA,IAAc,QACb1jB,EAAS,OAAO,4BAA8B,QAMhD,UAAA0jB,EACA,SAAA/sB,CAAA,EAEH,EACD0D,EAAAA,UAAWspB,GAAiB,CAC1B,MAAMnuB,EAAU,KAAK,SAAS,SAAA,EAG9B,OAAAA,EAAQ,MAAM,YAAY,aAAc,MAAM,EAC9CA,EAAQ,MAAM,YAAY,UAAW,GAAG,EAEjC4M,EAAAA,MACL9H,EAAAA,GAAG,EAAI,EACPA,EAAAA,GAAG,IAAI,EAAE,KACPgJ,EAAAA,SAAS,IAAM,CACb,GAAIqgB,GAAc,OAAS,eAAgB,OAAOrpB,EAAAA,GAAG,EAAK,EAE1D,MAAMspB,EACJD,EAAa,YAAc,OACvB3jB,EAAS,OAAO,sBAChBA,EAAS,OAAO,kCAChB6jB,EACJF,EAAa,YAAc,OACtB,QACD3jB,EAAS,OAAO,0BAEtB,OAAO1F,EAAAA,GAAGqpB,CAAY,EAAE,KAStBA,EAAa,cACT3H,EAAAA,MAAM,EAAGhQ,EAAAA,uBAAuB,EAChC8X,EAAAA,SACJjiB,EAAAA,IAAKrE,GAAS,CACZ,MAAMhI,EAAU,KAAK,SAAS,SAAA,EAG1BgI,EAAK,cACHqmB,IAAsB,QACxBruB,EAAQ,MAAM,YACZ,aACA,WAAWouB,EAAoB,CAAC,IAAA,EAElCpuB,EAAQ,MAAM,YAAY,UAAW,GAAG,IAExCmuB,EAAa,YAAc,QAC3BE,IAAsB,WAEtBruB,EAAQ,MAAM,YACZ,aACA,aAAaouB,CAAiB,IAAA,EAEhCpuB,EAAQ,MAAM,YAAY,UAAW,GAAG,IAG1CA,EAAQ,MAAM,YAAY,aAAc,MAAM,EAC9CA,EAAQ,MAAM,YAAY,UAAW,GAAG,EAE5C,CAAC,EASDqM,EAAAA,IAAKrE,GAAS,CACRqmB,IAAsB,QACxB,KAAK,oBAAoBrmB,EAAK,QAAQ,CAE1C,CAAC,EACDmmB,EAAa,cACT3H,EAAAA,MAAM4H,EAAoB,EAAG5X,EAAAA,uBAAuB,EACpD8X,EAAAA,SACJjiB,EAAAA,IAAKrE,GAAS,CACZ,MAAMhI,EAAU,KAAK,SAAS,SAAA,EAE1BquB,IAAsB,SACxB,KAAK,oBAAoBrmB,EAAK,QAAQ,EACtChI,EAAQ,MAAM,YAAY,UAAW,GAAG,EAE5C,CAAC,EACDmuB,EAAa,cACT3H,EAAAA,MAAM4H,EAAoB,EAAG5X,EAAAA,uBAAuB,EACpD8X,EAAAA,SACJjiB,EAAAA,IAAKrE,GAAS,CACRqmB,IAAsB,QACxB,KAAK,oBAAoBrmB,EAAK,QAAQ,CAE1C,CAAC,CAAA,CAEL,CAAC,EACD/C,EAAAA,IAAI,IAAM,EAAK,CAAA,CACjB,CAEJ,CAAC,EACDqF,EAAAA,UAAU,EAAK,EACfG,EAAAA,YAAY,CAAC,CAAA,EAGfmC,EAAAA,MAAMmhB,EAAc,KAAK,cAAe,KAAK,OAAO,EACjD,KAAK7nB,EAAAA,UAAU,KAAK,QAAQ,CAAC,EAC7B,UAAA,CACL,CAUU,oBAAoB/E,EAAyB,CACrD,MAAMnB,EAAU,KAAK,SAAS,SAAA,EAExB4tB,EAAcF,GAA2BvsB,CAAQ,EACvDnB,EAAQ,MAAM,UAAY,aAAa4tB,EAAY,CAAC,OAAOA,EAAY,CAAC,MAExE,KAAK,YAAY,QAAQ,yBAA0B,OAAW,CAAA,CAAE,CAClE,CAEA,SAASzS,EAAqC,CAC5C,KAAK,gBAAgB,KAAKA,CAAU,CACtC,CAMA,IAAW,kBAAkC,CAC3C,MAAMnb,EAAU,KAAK,SAAS,SAAA,EAExBuuB,EAAgB,OAAO,iBAAiBvuB,CAAO,EAC/CwuB,EAAYD,EAAc,WAAaA,EAAc,gBAE3D,GAAI,CAACC,GAAaA,IAAc,OAC9B,OAAO,IAAIhZ,EAAc,CAAE,EAAG,EAAG,EAAG,EAAG,EAKzC,MAAMiZ,EAAS,IAAI,UAAUD,CAAS,EAEtC,OAAOb,GAA2Bc,CAAM,CAC1C,CACF,CClRO,MAAMC,GACX,IACuB9pB,GACdA,EAAO,KACZK,EAAAA,IAAI,CAAC,CAAE,WAAAkW,EAAY,WAAA7N,EAAY,GAAGjC,MACzB,CACL,WAAY,CACV,GAAG8P,EACH,mBAAoB7N,EAAW,QAAA,EAEjC,GAAGjC,CAAA,EAEN,CAAA,ECNMsjB,GAA4B,CACvCrf,EACAsf,EACArF,IAEAja,EAAQ,YAAY,YAAY,KAC9B2N,EAAAA,eAAe2R,CAAW,EAC1BjhB,EAAAA,OACE,CAAC,CAACL,EAAY6N,CAAU,IAAM7N,EAAW,eAAiB6N,EAAW,EAAA,EAOvEtW,EAAAA,UAAU,CAAC,CAACyI,EAAY6N,CAAU,KACdoO,EAAM,kBAAkB,IAAIpO,EAAW,SAAS,GAE/C,SAAS,KAAKpS,EAAAA,MAAA,CAAO,GAAKjE,EAAAA,GAAG,EAAK,GAAG,KACtD6I,SAAQiK,GAAYA,CAAO,EAC3B3S,EAAAA,IAAI,KAAO,CACT,WAAAqI,EACA,WAAA6N,CAAA,EACA,CAAA,CAEL,EACDuT,GAAA,EACAnmB,EAAAA,qBACE,CAACsmB,EAAMC,IACLD,EAAK,WAAW,qBAChBC,EAAK,WAAW,kBAAA,EAEpB7pB,EAAAA,IACE,CAAC,CAAE,WAAAkW,CAAA,KACA,CACC,GAAGA,EACH,KAAM,CACJ,YAAa,YAAA,CACf,EACF,CAEN,EChDW4T,GACX,CAAC,CAAE,mBAAApU,CAAA,IAED/V,GAKOA,EAAO,KACZK,EAAAA,IAAI,CAAC,CAAC+pB,EAAgBC,CAAkB,IAAM,CAC5C,MAAM9T,EAAsC,CAC1C,KAAM,MACN,KAAM,CACJ,YAAa,MAAA,EAEf,GAAI,OAAA,EACJ,UAAW,OACX,GAAG6T,EAmBH,SAAUA,EAAe,SACrBrU,EAAmB,6BACjBqU,EAAe,QAAA,EAEjB,MAAA,EAGN,MAAO,CACL,mBAAAC,EACA,WAAA9T,CAAA,CAEJ,CAAC,CAAA,EC/CM+T,GACX,CAAC,CAAE,mBAAAvU,CAAA,IACoB/V,GACdA,EAAO,KACZK,EAAAA,IAAKwI,GAAW,CACd,GAAIA,EAAO,WAAW,IAAK,CACzB,MAAMtM,EAAWwZ,EAAmB,oBAClClN,EAAO,WAAW,GAAA,EAGpB,GAAItM,EACF,MAAO,CACL,GAAGsM,EACH,WAAY,CACV,GAAGA,EAAO,WACV,SAAAtM,CAAA,CACF,CAGN,CAEA,OAAOsM,CACT,CAAC,CAAA,ECdM0hB,GAAsB,CAAC,CAClC,WAAAhU,EACA,mBAAA8T,EACA,SAAAzkB,CACF,IAUM2Q,EAAW,4BACNA,EAAW,4BAehBA,EAAW,MAAQ,QAAaA,EAAW,MAAQ,OAC9C,SAGL8T,EAAmB,YAAc,QAcjC9T,EAAW,WAIX,CAACA,EAAW,SACP,UAML3Q,EAAS,OAAO,4BAA8B,WAC5C2Q,EAAW,SAAS,EAAI8T,EAAmB,SAAS,GAKtD9T,EAAW,SAAS,IAAM8T,EAAmB,SAAS,GACtDA,EAAmB,8BAAgC,WAE5C,UAEF,WAIP,KAAK,IAAI9T,EAAW,SAAS,CAAC,EAAI,KAAK,IAAI8T,EAAmB,SAAS,CAAC,GAMxE9T,EAAW,SAAS,IAAM8T,EAAmB,SAAS,GACtDA,EAAmB,8BAAgC,WAE5C,UAGF,WAGIG,GACX,CAAC,CACC,QAAA9f,EACA,SAAA9E,CACF,IAKE5F,GAMOA,EAAO,KACZK,EAAAA,IAAI,CAAC,CAAE,WAAAkW,EAAY,mBAAA8T,KAAyB,CAC1C,MAAM5D,EAAY8D,GAAoB,CAEpC,WAAAhU,EACA,mBAAA8T,EACA,SAAAzkB,CAAA,CACD,EAEK6kB,EAAiD,CACrD,GAAGlU,EACH,4BAA6BkQ,CAAA,EAG/B,MAAO,CACL,mBAAA4D,EACA,WAAYI,EACZ,UAAAhE,CAAA,CAEJ,CAAC,CAAA,ECpIMiE,GACX,CAAC,CACC,kBAAAzU,EACA,mBAAAF,EACA,SAAAnQ,CACF,IAWE5F,GAMOA,EAAO,KACZK,EAAAA,IAAI,CAAC,CAAE,WAAAkW,EAAY,GAAG9P,KAAW,CAC/B,MAAMrE,EAAY6T,EAAkB,IAAIM,EAAW,SAAS,EAE5D,GAAIA,EAAW,SAIb,OAAI3Q,EAAS,OAAO,uBAAyB,aACpC,CACL,WAAY,CACV,GAAG2Q,EACH,SAAUA,EAAW,QAAA,EAEvB,GAAG9P,CAAA,EAQA,CACL,WAAY,CACV,GAAG8P,EACH,SAAUR,EAAmB,yBAC3BQ,EAAW,QAAA,CACb,EAEF,GAAG9P,CAAA,EAIP,GAAI,CAACrE,EACH,MAAO,CACL,WAAY,CACV,GAAGmU,EACH,SAAU9P,EAAK,mBAAmB,QAAA,EAEpC,GAAGA,CAAA,EAQP,MAAMlK,EACJwZ,EAAmB,+BAA+B3T,CAAS,EAKvDuoB,EACJ/kB,EAAS,OAAO,uBAAyB,aACrC,IAAIiL,EAAqB,CACvB,EAAGtU,EAAS,EAAIkK,EAAK,mBAAmB,SAAS,EACjD,EAAGlK,EAAS,CAAA,CACb,EACDwZ,EAAmB,yBAAyBxZ,CAAQ,EAE1D,MAAO,CACL,WAAY,CACV,GAAGga,EACH,SAAUoU,CAAA,EAEZ,GAAGlkB,CAAA,CAEP,CAAC,CAAA,ECrFMmkB,GACX,CAAC,CACC,SAAAhlB,EACA,kBAAAqQ,EACA,mBAAAF,EACA,aAAAG,CACF,IAOuBlW,GAAyC,CAC9D,MAAM6qB,EAAgBtU,GAAwC,CAC5D,KAAM,CACJ,SAAAha,EACA,UAAA6F,EACA,IAAA0U,EACA,4BAA6B2P,CAAA,EAC3BlQ,EACE,CAAE,wBAAAuU,EAAyB,qBAAAhjB,CAAA,EAAyBlC,EAAS,OAKnE,GAAIxD,IAAc,OAAW,CAC3B,MAAM2oB,EAAoB9U,EAAkB,IAAI7T,CAAS,EAEzD,GAAI2oB,EAAmB,OAAOA,CAChC,CAOA,GAAI,OAAO3oB,GAAc,SACvB,OAAIA,EAAY6T,EAAkB,MAAM,OAAS,EACxCA,EAAkB,IAAIA,EAAkB,MAAM,OAAS,CAAC,EAG1DA,EAAkB,IAAI,CAAC,EAOhC,GAAIa,EAAK,CACP,MAAMiU,EAAoB9U,EAAkB,oBAAoBa,CAAG,EAEnE,GAAIiU,EAAmB,OAAOA,CAChC,CAOA,GAAIxuB,GAAYuL,IAAyB,aAAc,CAkBrD,KAAM,CAAE,WAAAmP,EAAY,SAAAD,GAClBd,EAAa,iCAAiC,CAC5C,SAAA3Z,EACA,UAAWuuB,EACX,iBAAkB,EAAA,CACnB,GAAK,CAAA,EAEFE,GACHvE,IAAc,WAAaA,IAAc,SACtCzP,EACAC,IAAeA,EAEfgU,EAAoBhV,EAAkB,IAAI+U,CAAsB,EAEtE,GAAI,CAACC,EAAmB,OAExB,KAAM,CAAE,aAAAC,EAAc,eAAAC,GACpBjV,EAAa,oCAAoC,CAC/C,SAAA3Z,EACA,UAAW0uB,EACX,UAAWH,EACX,iBAAkB,EAAA,CACnB,GAAK,CAAA,EAEFM,GACH3E,IAAc,WAAaA,IAAc,SACtCyE,EACAC,IAAmB,EAEnBE,EACJtV,EAAmB,8BAA8B,CAC/C,UAAWqV,EACX,YAAaH,CAAA,CACd,EAEGK,EACJpV,EAAa,iCAAiC,CAC5C,SAAUmV,EACV,UAAWP,EACX,iBAAkB,EAAA,CACnB,EAEGS,EACJ9E,IAAc,WAAaA,IAAc,SACrC6E,GAAwC,WACxCA,GAAwC,SAE9C,OAAOrV,EAAkB,IAAIsV,CAAmB,CAClD,CAOA,OAAIhvB,GAAYuL,IAAyB,aAChCoO,EAAa,yBAAyB3Z,CAAQ,EAGhD0Z,EAAkB,IAAI,CAAC,CAChC,EAEA,OAAOjW,EAAO,KACZK,EAAAA,IAAI,CAAC,CAAE,WAAAkW,EAAY,GAAG9P,KAAW,CAC/B,MAAMrE,EAAYyoB,EAAatU,CAAU,EAEzC,MAAO,CACL,WAAY,CACV,GAAGA,EACH,UAAWN,EAAkB,kBAAkB7T,CAAS,CAAA,EAE1D,GAAGqE,CAAA,CAEP,CAAC,CAAA,CAEL,EC7JW+kB,GACX,CAAC,CAAE,MAAA7G,CAAA,IACoB3kB,GACdA,EAAO,KACZC,EAAAA,UAAU,CAAC,CAAE,WAAAsW,EAAY,GAAG9P,KAAW,CACrC,MAAMglB,EAAsB9G,EAAM,4BAChCpO,EAAW,SAAA,EAEPnU,EAAYuiB,EAAM,kBAAkB,IAAIpO,EAAW,SAAS,EAElE,OAAQnU,GAAW,UAAYlC,EAAAA,GAAG,EAAK,GAAG,KACxCiE,QAAA,EACA9D,EAAAA,IACG2S,IACE,CACC,WAAY,CACV,GAAGuD,EACH,gBAAiBkV,GAAqB,OACtC,eAAgBA,GAAqB,MACrC,cAAeA,EAAoB,KACnC,aAAcA,EAAoB,IAClC,gCACErpB,GAAW,uBAAA,EACb,iBAAkB4Q,CAAA,EAEpB,GAAGvM,CAAA,EACL,CACJ,CAEJ,CAAC,CAAA,EC1BMilB,GACX,CAAC,CACC,SAAA9lB,EACA,kBAAAqQ,EACA,aAAAC,EACA,mBAAAH,CACF,IAMuB/V,GAAyC,CAC9D,MAAM2rB,EAAepV,GAAgC,CACnD,KAAM,CAAE,wBAAAuU,EAAyB,qBAAAhjB,CAAA,EAAyBlC,EAAS,OAC7DxD,EAAY6T,EAAkB,IAAIM,EAAW,SAAS,EAE5D,GAAI,GAACnU,GAAa,CAACmU,EAAW,UAO9B,IAAIzO,IAAyB,aAAc,CAkBzC,KAAM,CAAE,aAAAojB,EAAc,eAAAC,GACpBjV,EAAa,oCAAoC,CAC/C,SAAUK,EAAW,SACrB,UAAAnU,EACA,UAAW0oB,EACX,iBAAkB,EAAA,CACnB,GAAK,CAAA,EAEFc,GACHrV,EAAW,8BAAgC,WAC5CA,EAAW,8BAAgC,SACvC2U,EACAC,IAAmB,EAEnBU,EACJ9V,EAAmB,8BAA8B,CAC/C,UAAW6V,EACX,YAAaxpB,CAAA,CACd,EAEG0pB,EACJ5V,EAAa,oCAAoC,CAC/C,SAAU2V,EACV,UAAAzpB,EACA,UAAW,CAAE,KAAM,aAAc,MAAO,CAAA,EACxC,iBAAkB,EAAA,CACnB,EAEG2pB,GACHxV,EAAW,8BAAgC,WAC5CA,EAAW,8BAAgC,SACvCuV,GAAiC,eACjCA,GAAiC,eAAiB,EAQxD,OALE5V,EAAa,iBAAiB,kCAAkC,CAC9D,UAAW6V,EACX,UAAA3pB,CAAA,CACD,CAGL,CAMA,OAAO8T,EAAa,sCAClBK,EAAW,SACXnU,CAAA,EAEJ,EAEA,OAAOpC,EAAO,KACZK,EAAAA,IAAI,CAAC,CAAE,WAAAkW,EAAY,GAAG9P,MACb,CACL,WAAY,CACV,GAAG8P,EACH,oBAAqBoV,EAAYpV,CAAU,CAAA,EAE7C,GAAG9P,CAAA,EAEN,CAAA,CAEL,EC7GWulB,GACX,CAAC,CAAE,mBAAAjW,CAAA,IACoB/V,GACdA,EAAO,KACZK,EAAAA,IAAKwI,GAAW,CACd,GAAIA,EAAO,WAAW,IAAK,CACzB,MAAMvE,EAASyR,EAAmB,oBAChClN,EAAO,WAAW,GAAA,EAGpB,GAAIvE,EACF,MAAO,CACL,GAAGuE,EACH,WAAY,CACV,GAAGA,EAAO,WACV,SAAUvE,EAAO,SACjB,UAAWA,EAAO,WAAA,CACpB,CAGN,CAEA,OAAOuE,CACT,CAAC,CAAA,EC7BA,MAAMojB,EAAO,CAAb,aAAA,CACL,KAAU,gBAAkB,IAAIxjB,EAAAA,gBAAgB,CAAC,EAEjD,KAAO,UAAY,KAAK,gBAAgB,KACtCpI,EAAAA,IAAK6rB,GAAW,CAAC,CAACA,CAAM,EACxBvoB,EAAAA,qBAAA,CAAqB,CACvB,CAEO,MAAO,CACZ,IAAIwoB,EAAW,GACf,YAAK,gBAAgB,KAAK,KAAK,gBAAgB,SAAA,EAAa,CAAC,EAEtD,IAAM,CACPA,IAEJA,EAAW,GAEX,KAAK,gBAAgB,KAAK,KAAK,gBAAgB,SAAA,EAAa,CAAC,EAC/D,CACF,CACF,CCZO,MAAMC,GAA6C,CAAC,CACzD,aAAAlW,EACA,WAAAK,EACA,mBAAAR,EACA,kBAAAE,EACA,MAAA0O,CACF,IAMiC,CAC/B,MAAMviB,EAAY6T,EAAkB,IAAIM,EAAW,SAAS,EAE5D,OAAKnU,EAIEA,EAAU,SAAS,KACxB+B,QAAA,EACA9D,EAAAA,IAAK2S,GAAY,CACf,MAAMqZ,EACJ1H,EAAM,4BAA4BviB,CAAS,EAEvCkqB,EAA4BpW,EAAa,0BAC7CK,EAAW,SACXnU,CAAA,EAGImqB,EACJF,EAA0B,OAAS9V,EAAW,gBAAkB,GAC5DiW,EACJH,EAA0B,QAAU9V,EAAW,iBAAmB,GAE9DkW,EACJF,IAA6B,GAAKC,IAA6B,EAajE,GAAIjW,EAAW,MAAQ,SAEnBgW,GACAC,GAGCxZ,GAAW,CAACuD,EAAW,kBACxB,CACA,MAAMmW,EAAY3W,EAAmB,oBACnCQ,EAAW,GAAA,EAGb,GAAImW,EACF,OAAOA,EAAU,QAErB,CAGF,MAAM5V,EAAMP,EAAW,KAAOA,EAAW,mBAWzC,GAAIO,IAAQ,QAAa,CAACmG,GAAUnG,CAAG,IAEnCyV,GACAC,GAGCxZ,GAAW,CAACuD,EAAW,kBACxB,CACA,MAAMoW,EAAoB5W,EAAmB,oBAAoBe,CAAG,EAEpE,GAAI6V,EACF,OAAOA,CAEX,CAGF,GACEL,GACAG,GACAlW,EAAW,8BAAgC,WAC3C,CACA,MAAMqW,EAAoC,IAAItc,EAAkB,CAC9D,GACGiG,EAAW,qBAAqB,GAAK,GAAKgW,EAC7C,GACGhW,EAAW,qBAAqB,GAAK,GAAKiW,CAAA,CAC9C,EAED,OAAOzW,EAAmB,mCAAmC,CAC3D,UAAA3T,EACA,kBAAmBwqB,CAAA,CACpB,CACH,CAQA,GACErW,EAAW,qBACXA,EAAW,iBACXA,EAAW,eACX,CACA,MAAMW,EACJhB,EAAa,iBAAiB,kCAAkC,CAC9D,UAAWK,EAAW,eACtB,WAAYA,EAAW,gBACvB,uBACE,CAAC,CAACA,EAAW,gCACf,SAAUA,EAAW,mBAAA,CACtB,EAEH,OAAOR,EAAmB,8BAA8B,CACtD,UAAAmB,EACA,YAAa9U,CAAA,CACd,CACH,CAOA,OAAIkqB,EACKvW,EAAmB,yBAAyBQ,EAAW,QAAQ,EAQjER,EAAmB,+BAA+B3T,CAAS,CACpE,CAAC,CAAA,EAzIMlC,EAAAA,GAAG,IAAI0Q,EAAc,CAAE,EAAG,EAAG,EAAG,CAAA,CAAG,CAAC,CA2I/C,ECxJMic,GAA4C,CAAC,CACjD,WAAAtW,EACA,aAAAL,EACA,kBAAAD,EACA,SAAArQ,EACA,mBAAAmQ,EACA,MAAA4O,CACF,IAO2C,CACzC,KAAM,CAAE,UAAAviB,GAAcmU,EAChBuW,EAAiB7W,EAAkB,IAAI7T,CAAS,EAEtD,GAAI,CAAC0qB,EAAgB,OAAO,IAAIlc,EAAc,CAAE,EAAG,EAAG,EAAG,EAAG,EAE5D,KAAM,CAAE,OAAA9Q,EAAQ,IAAA+B,CAAA,EAAQ8iB,EAAM,4BAA4BmI,CAAc,EAElER,EAA4BpW,EAAa,0BAC7CK,EAAW,SACXuW,CAAA,EAGIC,EACJxW,EAAW,qBACX,IAAIjG,EAAkB,CACpB,EAAG,EACH,EAAG,CAAA,CACJ,EAKH,GAAI1K,EAAS,OAAO,4BAA8B,WAAY,CAM5D,GACE/D,IAAQ0U,EAAW,cACnBzW,IAAWyW,EAAW,iBACtB+V,EAKA,OAAO/V,EAAW,SASpB,GACE1U,IAAQ0U,EAAW,cACnBzW,IAAWyW,EAAW,iBACtB,CAAC+V,EAKD,OAAOvW,EAAmB,+BAA+B+W,CAAc,EAMzE,GAAIjrB,IAAQ0U,EAAW,aAAc,CAInC,MAAMwW,EACJ7W,EAAa,oDACXK,EAAW,qBACT,IAAIjG,EAAkB,CACpB,EAAG,EACH,EAAG,CAAA,CACJ,EACHwc,CAAA,EAGJ,OAAO5W,EAAa,sCAAsC,CACxD,kBAAmB6W,EACnB,UAAWD,CAAA,CACZ,CACH,CAMA,GACEjrB,IAAQ0U,EAAW,cACnBzW,IAAWyW,EAAW,gBACtB,CACA,MAAMyW,GACHzW,EAAW,iBAAmBwW,EAAoB,GACnDA,EAAoB,EAEhBE,EAAsB,IAAI3c,EAAkB,CAChD,EACEiG,EAAW,8BAAgC,WACvCzW,EAASktB,EACTD,EAAoB,EAC1B,EAAGxW,EAAW,SAAS,CAAA,CACxB,EAYD,GAAI+V,EAA2B,CAI7B,MAAMS,EACJ7W,EAAa,oDACX+W,EACAH,CAAA,EAGJ,OAAO5W,EAAa,sCAAsC,CACxD,kBAAmB6W,EACnB,UAAWD,CAAA,CACZ,CACH,CAKA,GAAI,CAACR,EAA2B,CAa9B,GAAI,EAZyB/V,EAAW,SAAS,EAAI1U,GAY1B,CACzB,MAAMqrB,EAAiB,IAAI5c,EAAkB,CAC3C,EAAGxQ,EAASktB,EACZ,EAAGzW,EAAW,SAAS,CAAA,CACxB,EAED,OAAOL,EAAa,sCAAsC,CACxD,kBACEA,EAAa,oDACXgX,EACAJ,CAAA,EAEJ,UAAWA,CAAA,CACZ,CACH,CAKA,OAAO/W,EAAmB,+BAA+B+W,CAAc,CACzE,CACF,CACF,CAEA,OAAOvW,EAAW,QACpB,EAEa4W,GAAkB,CAAC,CAC9B,WAAA5W,EACA,kBAAAN,EACA,SAAArQ,EACA,aAAAsQ,EACA,mBAAAH,EACA,MAAA4O,CACF,IAUM/e,EAAS,OAAO,uBAAyB,aACpC1F,EAAAA,GACL2sB,GAA0C,CACxC,WAAAtW,EACA,aAAAL,EACA,mBAAAH,EACA,SAAAnQ,EACA,kBAAAqQ,EACA,MAAA0O,CAAA,CACD,CAAA,EAIEyH,GAA2C,CAChD,WAAA7V,EACA,aAAAL,EACA,mBAAAH,EACA,kBAAAE,EACA,MAAA0O,CAAA,CACD,EC5NUyI,GACX,CAAC,CACC,SAAAxnB,EACA,mBAAAmQ,EACA,QAAArL,EACA,MAAAia,CACF,IAMuB3kB,GACrBA,EAAO,KACLC,EAAAA,UAAW4I,GACFskB,GAAgB,CACrB,aAAcxI,EAAM,QACpB,WAAY9b,EAAO,WACnB,mBAAAkN,EACA,SAAAnQ,EACA,kBAAmB+e,EAAM,kBACzB,iBAAkBA,EAAM,QAAQ,iBAEhC,MAAAA,CAAA,CACD,EAAE,KACDtkB,EAAAA,IAAKgtB,IAAsB,CACzB,GAAGxkB,EACH,WAAY,CACV,GAAGA,EAAO,WACV,SAAUwkB,CAAA,CACZ,EACA,CAAA,CAEL,CACH,ECFEpE,GAASxuB,EAAO,UAFJ,8BAEuB,EAElC,MAAM6yB,WAA0B3V,CAAiB,CAuCtD,YACY/R,EACA8E,EACA6iB,EACAC,EACA1V,EACA/B,EACA4O,EAMA8I,EACV,CACA,MAAA,EAdU,KAAA,SAAA7nB,EACA,KAAA,QAAA8E,EACA,KAAA,gBAAA6iB,EACA,KAAA,+BAAAC,EACA,KAAA,2BAAA1V,EACA,KAAA,mBAAA/B,EACA,KAAA,MAAA4O,EAMA,KAAA,qBAAA8I,EA5CZ,KAAO,kBAAoB,IAAIhlB,kBAAyC,CACtE,UAAW,GACX,SAAU,IAAImI,EAAc,CAAE,EAAG,EAAG,EAAG,EAAG,EAC1C,KAAM,CACJ,YAAa,MAAA,EAEf,iBAAkB,GAClB,KAAM,MACN,GAAI,OAAA,CAAO,CACZ,EAED,KAAO,WAAa,KAAK,kBAAkB,KAAKoD,EAAAA,KAAK,CAAC,CAAC,EAEvD,KAAO,YAAc,KAAK,kBAAkB,KAC1C3T,EAAAA,IAAI,CAAC,CAAE,SAAA9D,EAAU,GAAAgC,MAAU,CACzB,SAAAhC,EACA,GAAAgC,CAAA,EACA,EACFoF,EAAAA,qBACE,CACE,CAAE,SAAU+pB,EAAkB,GAAGC,CAAA,EACjC,CAAE,SAAU9S,EAAiB,GAAG+S,CAAA,IAEhChqB,EAAAA,eAAe+pB,EAAcC,CAAW,GACxChqB,EAAAA,eAAe8pB,EAAkB7S,CAAe,CAAA,EAEpDhV,EAAAA,YAAY,CAAC,CAAA,EAGf,KAAO,OAAS,IAAIomB,GAmBlB,MAAM4B,EAAsBN,EACzB,KACClV,EAAAA,eAAe,KAAK,iBAAiB,EACrC8R,GAA4B,CAC1B,mBAAApU,CAAA,CACD,EAKDiW,GAAY,CACV,mBAAAjW,CAAA,CACD,EAKDuU,GAAgB,CACd,mBAAAvU,CAAA,CACD,EACDyU,GAAc,CAAE,QAAA9f,EAAS,SAAA9E,EAAU,EACnCglB,GAAc,CAEZ,mBAAA7U,EACA,SAAAnQ,EACA,kBAAmB+e,EAAM,kBACzB,aAAcA,EAAM,OAAA,CACrB,EACD+G,GAAsB,CACpB,mBAAA3V,EACA,SAAAnQ,EACA,kBAAmB+e,EAAM,kBACzB,aAAcA,EAAM,OAAA,CACrB,EACD6G,GAAwB,CACtB,MAAA7G,CAAA,CACD,CAAA,EAEF,KACC+F,GAAqB,CACnB,mBAAA3U,EACA,kBAAmB4O,EAAM,kBACzB,SAAA/e,CAAA,CACD,EACDyS,EAAAA,eAAeoV,CAAoB,EACnCxtB,EAAAA,UAAU,CAAC,CAAC4I,EAAQilB,CAAY,IAAM,CACpC,MAAMC,EACJllB,EAAO,WAAW,KAClBA,EAAO,WAAW,KAClBjD,EAAS,OAAO,uBAAyB,cACzCkoB,EAEF,OAAO5tB,EAAAA,GAAG2I,CAAM,EAAE,KAChBklB,EACIrE,EAAAA,SACA0D,GAAqB,CACnB,mBAAArX,EACA,SAAAnQ,EACA,MAAA+e,EACA,QAAAja,CAAA,CACD,CAAA,CAET,CAAC,EACDghB,GAAsB,CACpB,kBAAmB/G,EAAM,kBACzB,aAAcA,EAAM,QACpB,SAAA/e,EACA,mBAAAmQ,CAAA,CACD,EACD1V,EAAAA,IAAKwI,GAAWA,EAAO,UAAU,EACjCP,EAAAA,MAAA,CAAM,EAGJ0lB,EAAuCH,EAAoB,KAC/DxV,EAAAA,eAAeoV,CAAoB,EACnC1kB,EAAAA,OAAO,CAAC,CAAA,CAAG+kB,CAAY,IAAMA,CAAY,EACzC7tB,YAAU,CAAC,CAACsW,CAAU,IAAM,CAE1B,MAAM2B,EAAS,KAAK,OAAO,KAAA,EAE3B,OAAOuV,EAAqB,KAC1B1kB,SAAQ+kB,GAAiB,CAACA,CAAY,EACtC3pB,QAAA,EACA9D,EAAAA,IACE,KAAgC,CAC9B,GAAGkW,EACH,UAAW,MAAA,EACb,EAEF7M,EAAAA,SAAS,IAAM,CACbwO,EAAA,CACF,CAAC,EACD5W,EAAAA,UAAUusB,CAAmB,CAAA,CAEjC,CAAC,EACDvlB,EAAAA,MAAA,CAAM,EAiBF2lB,EAA8BjmB,EAAAA,MAClCwlB,EAA+B,QAC/B7I,EAAM,OAAA,EACN,KACA1kB,EAAAA,UAAU,IACDC,EAAAA,GAAG,IAAI,EAAE,KACdD,EAAAA,UAAU,IACRwtB,EAAqB,KACnB1kB,SAAQ0e,GAAa,CAACA,CAAQ,EAC9BtjB,EAAAA,MAAA,CAAM,CACR,EAEF9D,EAAAA,IACE,KAAgC,CAC9B,GAAG,KAAK,kBAAkB,SAAA,EAC1B,UAAW,EAAA,EACb,EAOFiB,EAAAA,UACE0G,EAAAA,MAAMgmB,EAAsCH,CAAmB,CAAA,CACjE,CAEH,CAAA,EAGGK,EAAsBlmB,EAAAA,MAC1BimB,EACAD,CAAA,EACA,KACA3tB,EAAAA,IAAKkW,IAAgB,CAAE,WAAAA,GAAa,EACpC6W,GAAqB,CACnB,mBAAArX,EACA,SAAAnQ,EACA,QAAA8E,EACA,MAAAia,CAAA,CACD,EACDtkB,EAAAA,IAAKwI,GAAW,CACd,MAAM0N,EAAsC,CAC1C,GAAG1N,EAAO,WACV,KAAM,CACJ,YAAa,aAAA,CACf,EAGF,MAAO,CACL,GAAGA,EACH,WAAA0N,CAAA,CAEJ,CAAC,EAMDqU,GAAc,CAEZ,mBAAA7U,EACA,SAAAnQ,EACA,kBAAmB+e,EAAM,kBACzB,aAAcA,EAAM,OAAA,CACrB,EACD6G,GAAwB,CACtB,MAAA7G,CAAA,CACD,EACD+G,GAAsB,CACpB,kBAAmB/G,EAAM,kBACzB,aAAcA,EAAM,QACpB,SAAA/e,EACA,mBAAAmQ,CAAA,CACD,EACD1V,EAAAA,IAAI,CAAC,CAAE,WAAAkW,CAAA,IAAiBA,CAAU,EAClCjO,EAAAA,MAAA,CAAM,EAQF6lB,EAAsCpE,GAC1Crf,EACA,KAAK,kBACLia,CAAA,EAGIyJ,EAAoBpmB,EAAAA,MACxBkmB,EACAL,EACAM,CAAA,EAGIE,EACJruB,GAEAA,EAAO,KACLyH,EAAAA,IAAI,CAAC,CAAC6mB,EAAmBjE,CAAkB,IAAM,CAC/CpB,GAAO,KACL,2BAA2BqF,EAAkB,KAAK,WAAW,YAAYA,EAAkB,IAAI,GAC/F,CACE,mBAAAjE,EACA,kBAAAiE,CAAA,CACF,EAGF,KAAK,kBAAkB,KAAKA,CAAiB,CAC/C,CAAC,CAAA,EAGCC,EACJvuB,GAEAA,EAAO,KACLyH,EAAAA,IAAI,CAAC,CAAC6mB,EAAmBjE,CAAkB,IAAM,CAC/C,MAAMmE,EAAmBF,EAAkB,OAAS,SAC9CG,EACJH,EAAkB,KAAK,cAAgB,aACnCI,EACJJ,EAAkB,KAAK,cAAgB,cACnCK,EAAiB/qB,EAAAA,eACrBymB,EAAmB,SACnBiE,EAAkB,QAAA,EAGpB,GACGE,GAAoB,CAACE,GACtBD,GACAE,EAEA,OAEF,MAAMpY,EAAa,CACjB,SAAU+X,EAAkB,SAC5B,UAAWA,EAAkB,SAAA,EAG3B1oB,EAAS,OAAO,uBAAyB,aAC3C,KAAK,2BAA2B,SAAS2Q,CAAU,EAEnD,KAAK,+BAA+B,SAAS,CAC3C,GAAGA,EAMH,SAAU3F,EAAc,KAAK2F,EAAW,QAAQ,CAAA,CACjD,CAEL,CAAC,CAAA,EAGL6X,EACG,KACC/V,EAAAA,eAAe,KAAK,iBAAiB,EAQrCkW,EACAF,EACA/sB,EAAAA,UAAU,KAAK,QAAQ,CAAA,EAExB,UAAA,CACL,CAEA,IAAI,YAAa,CACf,OAAO,KAAK,kBAAkB,SAAA,CAChC,CACF,CCtYO,MAAMstB,GAA6B,CACxCtsB,EACA4U,EACA2X,IACG,CACH,MAAMC,EAAiBD,EAAYvsB,EAC7BysB,EAAiBF,GAAa3X,EAAY5U,IAAeusB,GAAa,GAE5E,OAAO,KAAK,IAAI,EAAG,KAAK,IAAIC,EAAgBC,CAAa,CAAC,CAC5D,EAEaC,GAAgC,CAC3CH,EACAvsB,KAEKA,GAAa,KAAO,IAAMusB,GAAa,KAAO,EAAU,EACtD,KAAK,MAAM,KAAK,IAAI,EAAGA,EAAYvsB,CAAS,CAAC,EAGzC2sB,GAAoD,CAC/DvyB,EACA4F,EACAusB,IACG,CACH,MAAMK,EAAgBF,GAA8BH,EAAWvsB,CAAS,EAClE6sB,EAAe,CAAC,GAAG,MAAMD,CAAa,CAAC,EAAE,IAAI,CAACE,EAAGzkB,IAAMA,EAAIrI,CAAS,EAE1E,OAAI5F,GAAUwyB,EAAgB5sB,EACrB6sB,EAAaA,EAAa,OAAS,CAAC,GAAK,EAGhDA,EAAa,KAAME,GAAgB3yB,EAAS2yB,EAAc/sB,CAAS,GAAK,CAE5E,ECjCagtB,GAAoB,CAC/B5yB,EACA4F,EACA4sB,IACG,CACH,MAAMC,EAAe,CAAC,GAAG,MAAMD,CAAa,CAAC,EAAE,IAAI,CAACE,EAAGzkB,IAAMA,EAAIrI,CAAS,EAE1E,OAAI5F,GAAU,GAAKwyB,IAAkB,EAAU,EAE3CxyB,GAAUwyB,EAAgB5sB,EAAkB4sB,EAAgB,EAG9DC,EAAa,UAAWE,GAAgB3yB,EAAS2yB,EAAc/sB,CAAS,GACxE,CAEJ,ECbaitB,GAAkB,CAAC,CAC9B,UAAAV,EACA,WAAAW,EACA,kBAAApZ,CACF,IAKE,IAAI9F,EAAkB,CACpB,EAAG,KAAK,IAAIue,EAAW,KAAK,IAAI,EAAGzY,EAAkB,CAAC,CAAC,EACvD,EAAG,KAAK,IAAIoZ,EAAY,KAAK,IAAI,EAAGpZ,EAAkB,CAAC,CAAC,CAC1D,CAAC,ECZUqZ,GAA4B,CAAC,CACxC,WAAAD,EACA,UAAAX,EACA,uBAAA7f,EACA,UAAA1M,EACA,WAAAD,EACA,kBAAAwF,EACA,aAAA6nB,CACF,IASM7nB,IAAsB,YAAc6nB,IAAiB,aAChD,EAGL1gB,GAA0BnH,IAAsB,WAC3CmnB,GAA8BQ,EAAYntB,CAAU,EAGtD2sB,GAA8BH,EAAWvsB,CAAS,ECjB9CqtB,GAA6C,CAAC,CACzD,UAAAd,EACA,WAAAW,EACA,SAAAjzB,EACA,uBAAAyS,EACA,UAAA1M,EACA,WAAAD,EACA,kBAAAwF,EACA,aAAA6nB,EACA,MAAA1hB,CACF,IAUM,CAOJ,MAAMtR,EANe6yB,GAAgB,CACnC,kBAAmBhzB,EACnB,WAAAizB,EACA,UAAAX,CAAA,CACD,EAE2B,EAEtBK,EAAgBO,GAA0B,CAC9C,uBAAAzgB,EACA,WAAAwgB,EACA,UAAAX,EACA,UAAAvsB,EACA,WAAAD,EACA,kBAAAwF,EACA,aAAA6nB,CAAA,CACD,EAED,GAAI1gB,EACF,OAAOsgB,GAAkB/yB,EAAS,EAAG8F,EAAY6sB,CAAa,EAGhE,MAAMhY,EAAYoY,GAAkB5yB,EAAQ4F,EAAW4sB,CAAa,EAEpE,OAAIlhB,EAEKkhB,EAAgB,EAAIhY,EAGtBA,CACT,ECxDa0Y,GAAoC,CAAC,CAChD,UAAA1Y,EACA,WAAA2Y,EACA,QAAAnlB,EACA,uBAAAsE,EACA,SAAA9T,CACF,IAMyB,CACvB,GAAI8T,EAAwB,CAC1B,MAAM8gB,EAAoBlB,GACxB1zB,EAAS,SAAS,OAClBgc,EACA2Y,EAAW,MAAA,EAGb,OAAO,IAAIvf,EAAkB,CAC3B,EAAG,EACH,EAAGwf,CAAA,CACJ,CACH,CAEA,MAAMA,EAAoBlB,GACxB1zB,EAAS,SAAS,MAClBgc,EACA2Y,EAAW,KAAA,EAGb,OAAInlB,EAAQ,QACH,IAAI4F,EAAkB,CAC3B,EAAGuf,EAAW,MAAQC,EAAoB50B,EAAS,SAAS,MAC5D,EAAG,CAAA,CACJ,EAGI,IAAIoV,EAAkB,CAC3B,EAAGwf,EACH,EAAG,CAAA,CACJ,CACH,ECjCaC,GAAyB,CAAC,CACrC,QAAArlB,EACA,SAAA9E,EACA,SAAA1K,CACF,IAIM,CACJ,MAAM80B,EAA+B,CACnCvzB,EACAC,EACA0F,IACG,CACH,IAAI6tB,EAIFxzB,GAAM,WAAa,OAClBA,GAAM,cAAgB,IAAMA,EAAK,WAAa,KAAK,aAEpDwzB,EAA2BxzB,EAAqB,wBAAwB,EAC/DA,IAETwzB,GADcxzB,EAAOD,GAAiBC,EAAMC,CAAM,EAAI,SAE7C,sBAAA,EAAwB,GAAKuzB,GAGxC,MAAMC,EAAiB9tB,EAAU,YAAY,OAAS,EAChDE,EAAYpH,EAAS,SAAS,MAEpC,GAAI+0B,IAA4B,OAAW,CACzC,MAAME,EAAMlB,GACVgB,EACA3tB,EACA4tB,CAAA,EAIF,OAAO,IAAI5f,EAAkB,CAAE,EAAG6f,EAAK,EAAG,EAAG,CAC/C,CAGF,EAyFA,MAAO,CACL,6BAAAH,EACA,kCAAmC,CAAC,CAClC,UAAA9Y,EACA,UAAA9U,CAAA,IAKAwtB,GAAkC,CAChC,QAAAllB,EACA,uBAAwB,CAAC,CAACtI,EAAU,uBAAA,EACpC,WAAYA,EAAU,WACtB,UAAA8U,EACA,SAAAhc,CAAA,CACD,EACH,kCAAoC2N,GAMlC8mB,GAA2C,CACzC,GAAG9mB,EACH,MAAO6B,EAAQ,MAAA,EACf,UAAWxP,EAAS,SAAS,MAC7B,WAAYA,EAAS,SAAS,OAC9B,kBAAmB0K,EAAS,OAAO,0BACnC,aAAcA,EAAS,OAAO,YAAA,CAC/B,EACH,8BA/FoC,CACpCnJ,EACAC,EACA0F,IACG,CACH,MAAM7F,EAAWyzB,EAA6BvzB,EAAMC,EAAQ0F,CAAS,EAC/D,CAAE,OAAAtC,EAAQ,MAAAD,CAAA,EAAUuC,EAAU,WAEpC,OAAO7F,EACHozB,GAA2C,CACzC,uBAAwB,CAAC,CAACvtB,EAAU,uBAAA,EACpC,SAAA7F,EACA,WAAYuD,EACZ,UAAWD,EACX,MAAO6K,EAAQ,MAAA,EACf,UAAWxP,EAAS,SAAS,MAC7B,WAAYA,EAAS,SAAS,OAC9B,kBAAmB0K,EAAS,OAAO,0BACnC,aAAcA,EAAS,OAAO,YAAA,CAC/B,EACD,MACN,EA2EE,8CAtHoD,CACpDwqB,EACAhuB,IACG,CACH,KAAM,CAAE,MAAAvC,EAAO,OAAAC,CAAA,EAAWsC,EAAU,WAepC,OAbyB,IAAIkO,EAAkB,CAC7C,EAAG2e,GACDmB,EAAe,EACfl1B,EAAS,SAAS,MAClB2E,CAAA,EAEF,EAAGovB,GACDmB,EAAe,EACfl1B,EAAS,SAAS,OAClB4E,CAAA,CACF,CACD,CAGH,EAmGE,8CA1EoD,CACpDvD,EACA2a,EACA9U,IACG,CACH,KAAM,CAAE,MAAAvC,EAAO,OAAAC,CAAA,EAAWsC,EAAU,WAC9BE,EAAYpH,EAAS,SAAS,MAC9BmH,EAAanH,EAAS,SAAS,OAGrC,GAF+B,CAAC,CAACkH,EAAU,uBAAA,EAEf,CAE1B,MAAMiuB,EAAazB,GACjBvsB,EACA6U,EACApX,CAAA,EAEF,OAAO,IAAIyQ,GAA6B,CACtC,EAAGhU,EAAS,EACZ,EAAGA,EAAS,EAAI8zB,CAAA,CACjB,CACH,CAGA,MAAMC,EAAa1B,GAA2BtsB,EAAW4U,EAAWrX,CAAK,EAEzE,GAAI6K,EAAQ,QAAS,CAEnB,MAAM6lB,EAAgB1wB,GAASqX,EAAY,GAAK5U,EAChD,OAAO,IAAIiO,GAA6B,CACtC,EAAGhU,EAAS,EAAI,KAAK,IAAI,EAAGg0B,CAAa,EACzC,EAAGh0B,EAAS,CAAA,CACb,CACH,CAGA,OAAO,IAAIgU,GAA6B,CACtC,EAAGhU,EAAS,EAAI+zB,EAChB,EAAG/zB,EAAS,CAAA,CACb,CACH,CAkCE,CAEJ,EC1Kai0B,GAA2B,CAAC,CACvC,QAAA9lB,EACA,SAAA9E,EACA,SAAA1K,CACF,IAIM,CACJ,MAAM0a,EAAmBma,GAAuB,CAC9C,QAAArlB,EACA,SAAA9E,EACA,SAAA1K,CAAA,CACD,EAsCD,MAAO,CACL,yBArCgCkH,GAAyB,CACzD,MAAM8sB,EAAgB9sB,EAAU,cAEhC,OAAOwT,EAAiB,kCAAkC,CACxD,UAAWsZ,EAAgB,EAC3B,UAAA9sB,CAAA,CACD,CACH,EA+BE,yBAf+B,CAC/BA,EACA7F,IAGEqZ,EAAiB,8CACfrZ,EACA6F,CAAA,EASJ,sBA9B4B,CAC5BA,EACA3F,EACAC,IAEiBkZ,EAAiB,6BAChCnZ,EACAC,EACA0F,CAAA,GAGiB,IAAIkO,EAAkB,CAAE,EAAG,EAAG,EAAG,EAAG,CAmBvD,CAEJ,ECjCO,SAASmgB,GAA6B,CAC3C,SAAAl0B,EACA,MAAAyR,EACA,kBAAAiI,EACA,MAAA0O,EACA,cAAAhS,CACF,EAEyC,CAEvC,MAAM+d,EAAgBza,EAAkB,IACtCA,EAAkB,MAAM,OAAS,CAAA,EAE7B0a,EAA0BhM,EAAM,4BACpC+L,GAAiB,CAAA,EAIbE,EAAiBD,EAAwB,OAAS,EAClDE,EAAY,KAAK,IAAI,EAAGt0B,EAAS,CAAC,EAClC0U,EAAI,KAAK,IAAI4f,EAAWD,CAAc,EAM5C,GAAI5iB,EAAO,CACT,MAAM8iB,EAAW,KAAK,IAAIne,EAAepW,EAAS,CAAC,EAC7Cw0B,EAAW,KAAK,IAAID,EAAUH,EAAwB,IAAI,EAEhE,OAAO,IAAI/f,EAAc,CACvB,EAAGmgB,EACH,EAAA9f,CAAA,CACD,CACH,CAGA,MAAM+f,EAAiBL,EAAwB,MAAQ,EACjDM,EAAY,KAAK,IAAI,EAAG10B,EAAS,CAAC,EAClC20B,EAAW,KAAK,IAAID,EAAWD,CAAc,EAEnD,OAAO,IAAIpgB,EAAc,CACvB,EAAGsgB,EACH,EAAAjgB,CAAA,CACD,CACH,CCxEO,MAAMkgB,GAA2B,CAAC,CACvC,SAAA50B,EACA,MAAAyR,EACA,eAAAkB,EACA,kBAAA+G,EACA,qBAAAmb,EACA,MAAAzM,CACF,IAOM,CACJ,MAAM0M,EAAkBZ,GAA6B,CACnD,SAAAl0B,EACA,MAAAyR,EACA,kBAAAiI,EACA,MAAA0O,EACA,cAAeyM,CAAA,CAChB,EAGKV,EAAgBza,EAAkB,IACtCA,EAAkB,MAAM,OAAS,CAAA,EAE7B0a,EACJhM,EAAM,4BAA4B+L,CAAa,EAE3CE,EAAiBD,EAAwB,OAASzhB,EAClD+B,EAAI,KAAK,IAAIogB,EAAgB,EAAGT,CAAc,EAMpD,GAAI5iB,EAAO,CACT,MAAM8iB,EAAW,KAAK,IAAI,EAAGO,EAAgB,CAAC,EAE9C,OAAO,IAAIzgB,EAAc,CACvB,EAAGkgB,EACH,EAAA7f,CAAA,CACD,CACH,CAEA,MAAM+f,EAAiBL,EAAwB,MAAQS,EAEvD,OAAO,IAAIxgB,EAAc,CACvB,EAAG,KAAK,IAAIygB,EAAgB,EAAGL,CAAc,EAC7C,EAAA/f,CAAA,CACD,CACH,ECzDaqgB,EAA+B,CAAC,CAC3C,SAAU,CAAE,EAAAtgB,EAAG,EAAAC,CAAA,EACf,cAAAsgB,EACA,qBAAAH,CACF,IAIqB,CAEnB,MAAM3Z,EADoBzG,EAAIogB,IAAyB,EAChBpgB,EAAIugB,EAAgBvgB,EAE3D,OAAO,IAAIJ,EAAc,CAAE,EAAG6G,EAAY,EAAAxG,EAAG,CAC/C,ECTaugB,GAA2B,CAAC,CACvC,iBAAAC,EACA,aAAAvb,EACA,4BAAAwb,EACA,SAAAx2B,CACF,IAKM,CACJ,MAAMkH,EAAY8T,EAAa,yBAAyBub,CAAgB,EAExE,GAAIrvB,EAAW,CACb,MAAMgU,EACJF,EAAa,sCACXub,EACArvB,CAAA,EAGEuvB,EACJD,EAA4B,yBAC1BtvB,EACAgU,CAAA,EAGEwb,EACJ1b,EAAa,sCAAsC,CACjD,kBAAmByb,EACnB,UAAAvvB,CAAA,CACD,EAEH,OAAOkvB,EAA6B,CAClC,SAAUM,EACV,cAAe12B,EAAS,SAAS,MACjC,qBAAsBA,EAAS,iBAAiB,KAAA,CACjD,CACH,CAEA,OAAO,IAAI0V,EAAc,CAAE,EAAG,EAAG,EAAG,EAAG,CACzC,ECrCaihB,GAAgC,CAAC,CAC5C,UAAA3a,EACA,kBAAAjB,EACA,YAAAkB,EACA,aAAAjB,EACA,4BAAAwb,EACA,SAAAx2B,CACF,IAOqB,CACnB,MAAMkH,EAAY6T,EAAkB,IAAIkB,CAAW,EAInD,GAAI,CAAC/U,EAAW,CACd,MAAM0vB,EAAwB5a,EAAYhc,EAAS,SAAS,MAC5D,OAAOs2B,GAAyB,CAC9B,iBAAkB,IAAI5gB,EAAc,CAAE,EAAGkhB,EAAuB,EAAG,EAAG,EACtE,4BAAAJ,EACA,aAAAxb,EACA,SAAAhb,CAAA,CACD,CACH,CAEA,MAAMmb,EACJH,EAAa,iBAAiB,kCAAkC,CAC9D,UAAAgB,EACA,UAAA9U,CAAA,CACD,EAEG2vB,EAAgB7b,EAAa,sCAAsC,CACvE,kBAAmBG,EACnB,UAAAjU,CAAA,CACD,EAED,OAAOkvB,EAA6B,CAClC,SAAUS,EACV,cAAe72B,EAAS,SAAS,MACjC,qBAAsBA,EAAS,iBAAiB,KAAA,CACjD,CACH,EC7CM82B,GAAsB,CAC1BC,EACA7yB,IACG,CACH,GAAIA,GAAgBA,aAAwB,kBAC1C,OAAI6yB,EAAS,WAAW,GAAG,EAClB7yB,EAAa,iBAAiB,eACnC6yB,EAAS,QAAQ,IAAK,EAAE,CAAA,EAIrB7yB,EAAa,iBAAiB,cAAc6yB,CAAQ,CAE/D,EAKMC,GAA+B,CAAC,CACpC,OAAArR,EACA,UAAAze,EACA,MAAAuiB,CACF,IAIM,CACJ,MAAMloB,EAAOu1B,GACXnR,EACAze,EAAU,SAAS,iBAAA,CAAiB,EAGtC,OAAK3F,EAKHkoB,EAAM,iBAAiB,6BAA6BloB,EAAM,EAAG2F,CAAS,GAClE,GAAK,EALF,CAOX,EAEM+vB,GAAsC,CAAC,CAC3C,OAAAtR,EACA,UAAAze,EACA,aAAA8T,EACA,MAAAyO,CACF,IAKM,CACJ,MAAMyN,EAAkBF,GAA6B,CACnD,OAAArR,EACA,UAAAze,EACA,MAAAuiB,CAAA,CACD,EAOD,OALiBzO,EAAa,sCAAsC,CAClE,kBAAmB,IAAI5F,EAAkB,CAAE,EAAG8hB,EAAiB,EAAG,EAAG,EACrE,UAAAhwB,CAAA,CACD,CAGH,EAEMiwB,GAAyB,CAAC,CAC9B,OAAAxR,EACA,UAAAze,EACA,aAAA8T,EACA,MAAAyO,EACA,cAAA4M,EACA,qBAAAH,CACF,IAOM,CACJ,MAAM70B,EAAW41B,GAAoC,CACnD,OAAAtR,EACA,UAAAze,EACA,aAAA8T,EACA,MAAAyO,CAAA,CACD,EAED,OAAO2M,EAA6B,CAClC,SAAA/0B,EACA,cAAAg1B,EACA,qBAAAH,CAAA,CACD,CACH,EAMakB,GAAsB,CAAC,CAClC,MAAA3N,EACA,kBAAA1O,EACA,aAAAC,EACA,IAAA5Y,EACA,QAAAoN,EACA,cAAA6mB,EACA,qBAAAH,CACF,IAQoE,CAClE,GAAI,CACF,MAAMmB,EAAWj1B,aAAe,IAAMA,EAAM,IAAI,IAAIA,CAAG,EACjDk1B,EAAmB,GAAGD,EAAS,MAAM,GAAGA,EAAS,QAAQ,GACzDxH,EAAoBrgB,EAAQ,UAAU,WAAW,KACpDxJ,GAASA,EAAK,OAASsxB,CAAA,EAG1B,GAAIzH,EAAmB,CACrB,MAAM3oB,EAAY6T,EAAkB,IAAI8U,EAAkB,EAAE,EAE5D,GAAI3oB,EAAW,CACb,MAAM7F,EAAW81B,GAAuB,CACtC,OAAQE,EAAS,KACjB,UAAAnwB,EACA,MAAAuiB,EACA,aAAAzO,EACA,cAAAqb,EACA,qBAAAH,CAAA,CACD,EAED,MAAO,CACL,SAAUE,EAA6B,CACrC,SAAA/0B,EACA,cAAAg1B,EACA,qBAAAH,CAAA,CACD,EACD,YAAarG,EAAkB,EAAA,CAEnC,CACF,CAEA,MACF,OAASpuB,EAAG,CACV,QAAQ,MAAMA,CAAC,EAEf,MACF,CACF,EC5Ja81B,GAAqC,CAAC,CACjD,UAAArwB,EACA,kBAAAgU,EACA,aAAAF,EACA,iBAAAN,EACA,SAAA1a,CACF,IAMM,CACJ,MAAMw3B,EACJ9c,EAAiB,8CACfQ,EACAhU,CAAA,EAGE+V,EAAgBjC,EAAa,sCAAsC,CACvE,kBAAmBwc,EACnB,UAAAtwB,CAAA,CACD,EAED,OAAOkvB,EAA6B,CAClC,SAAUnZ,EACV,cAAejd,EAAS,SAAS,MACjC,qBAAsBA,EAAS,iBAAiB,KAAA,CACjD,CACH,EChBay3B,GAAY,iBAIZnC,GAA2B,CAAC,CACvC,QAAA9lB,EACA,kBAAAuL,EACA,QAAA/T,EACA,SAAA0D,EACA,MAAA+e,EACA,SAAAzpB,CACF,IAOM,CACJ,MAAM03B,EAAqBC,GAAyB,CAClD,QAAAnoB,EACA,SAAA9E,EACA,SAAA1K,CAAA,CACD,EA2HD,MAAO,CACL,oBAAsBoC,GACpBg1B,GAAoB,CAClB,QAAA5nB,EACA,kBAAAuL,EACA,aAAc/T,EACd,IAAA5E,EACA,cAAepC,EAAS,SAAS,MACjC,qBAAsBA,EAAS,iBAAiB,MAChD,MAAAypB,CAAA,CACD,EACH,8BACE9b,GAQAgpB,GAA8B,CAC5B,GAAGhpB,EACH,kBAAAoN,EACA,4BAA6B2c,EAC7B,aAAc1wB,EACd,SAAAhH,CAAA,CACD,EACH,mCAAqC2N,GAInC4pB,GAAmC,CACjC,GAAG5pB,EACH,iBAAkB3G,EAAQ,iBAC1B,aAAcA,EACd,SAAAhH,CAAA,CACD,EACH,oBAzJ2B4b,GAA2C,CACtE,MAAM1U,EAAY6T,EAAkB,oBAAoBa,CAAG,EACrD,CAAE,KAAAra,EAAM,OAAAC,EAAS,CAAA,EAAMghB,GAAW,CACtC,IAAA5G,EACA,kBAAAb,CAAA,CACD,EAED,GAAI,CAAC7T,EAAW,CACd3H,EAAO,KAAKk4B,GAAW,qCAAqC7b,CAAG,EAAE,EAEjE,MACF,CAEA,MAAMT,EAAsB5Z,EACxBm2B,EAAmB,sBAAsBxwB,EAAW3F,EAAMC,CAAM,EAChE,IAAI4T,EAAkB,CAAE,EAAG,EAAG,EAAG,EAAG,EAClCwiB,EAAkB5wB,EAAQ,sCAAsC,CACpE,kBAAmBmU,EACnB,UAAAjU,CAAA,CACD,EAED,OAAOkvB,EAA6B,CAClC,SAAUwB,EACV,cAAe53B,EAAS,SAAS,MACjC,qBAAsBA,EAAS,iBAAiB,KAAA,CACjD,CACH,EAgIE,yBA9HgCkH,GAAwC,CACxE,MAAMiU,EACJuc,EAAmB,yBAAyBxwB,CAAS,EACjD7F,EAAW2F,EAAQ,sCAAsC,CAC7D,kBAAmBmU,EACnB,UAAAjU,CAAA,CACD,EAED,OAAOkvB,EAA6B,CAClC,SAAA/0B,EACA,cAAerB,EAAS,SAAS,MACjC,qBAAsBA,EAAS,iBAAiB,KAAA,CACjD,CACH,EAkHE,+BA/GA6b,GACkB,CAClB,MAAM3U,EAAY6T,EAAkB,IAAIc,CAAS,EAEjD,GAAI3U,EAAW,CACb,MAAM7F,EAAW2F,EAAQ,8BAA8BE,CAAS,EAEhE,OAAOkvB,EAA6B,CAClC,SAAA/0B,EACA,cAAerB,EAAS,SAAS,MACjC,qBAAsBA,EAAS,iBAAiB,KAAA,CACjD,CACH,CAEA,OAAO,IAAI0V,EAAc,CAAE,EAAG,EAAG,EAAG,EAAG,CACzC,EAiGE,yBACE6gB,GAEAD,GAAyB,CACvB,iBAAAC,EACA,4BAA6BmB,EAC7B,aAAc1wB,EACd,SAAAhH,CAAA,CACD,EACH,wCAnGAu2B,GACkB,CAClB,MAAM5pB,EAAoBjC,EAAS,OAAO,0BAIpCmtB,EAAoB,GACpBC,EACJnrB,IAAsB,aAClB4pB,EAAiB,EACjBv2B,EAAS,iBAAiB,MAAQ63B,EAClC,EACAE,EACJprB,IAAsB,aAClB,EACA4pB,EAAiB,EACjBv2B,EAAS,iBAAiB,OAAS63B,EACnCG,EAAgC/B,GAAyB,CAC7D,SAAU,IAAIvgB,EAAc,CAC1B,EAAGoiB,EACH,EAAGC,CAAA,CACJ,EACD,MAAOvoB,EAAQ,MAAA,EACf,eAAgBxP,EAAS,SAAS,OAClC,qBAAsBA,EAAS,iBAAiB,MAChD,kBAAA+a,EACA,MAAA0O,CAAA,CACD,EAED,OAAO6M,GAAyB,CAC9B,4BAA6BoB,EAC7B,aAAc1wB,EACd,iBAAkBgxB,EAClB,SAAAh4B,CAAA,CACD,CACH,EAiEE,yBACEqB,GAEA40B,GAAyB,CACvB,SAAA50B,EACA,MAAOmO,EAAQ,MAAA,EACf,eAAgBxP,EAAS,SAAS,OAClC,qBAAsBA,EAAS,iBAAiB,MAChD,kBAAA+a,EACA,MAAA0O,CAAA,CACD,EACH,6BACEpoB,GAEAk0B,GAA6B,CAC3B,SAAAl0B,EACA,MAAOmO,EAAQ,MAAA,EACf,kBAAAuL,EACA,MAAA0O,EACA,cAAezpB,EAAS,iBAAiB,KAAA,CAC1C,EACH,6BApFmC,CACnCi4B,EACA3yB,IAE0BoF,EAAS,OAAO,4BAEhB,WACjButB,EAAG,EAAI3yB,EAAK,EAGd2yB,EAAG,EAAI3yB,EAAK,EA2EnB,sBAjM4B,CAC5B4yB,EACAC,IACGD,EAAE,IAAMC,EAAE,GAAKD,EAAE,IAAMC,EAAE,EA+L5B,6BACE92B,GAEA+0B,EAA6B,CAC3B,SAAA/0B,EACA,cAAerB,EAAS,SAAS,MACjC,qBAAsBA,EAAS,iBAAiB,KAAA,CACjD,EACH,mBAAA03B,CAAA,CAEJ,EC1OaU,GAAkB,CAAC,CAC9B,kBAAArd,EACA,QAAAvL,EACA,YAAAga,EACA,MAAAC,EACA,SAAA/e,EACA,SAAA1K,CACF,IAOM,CACJ,MAAMq4B,EAAgC,IAAI/tB,UACpC+nB,EAAkBgG,EAA8B,aAAA,EAMhDC,EAAoB,IAAIvH,GACxBlW,EAAqBya,GAAyB,CAClD,QAAA9lB,EACA,SAAA9E,EACA,kBAAAqQ,EACA,QAAS0O,EAAM,QACf,MAAAA,EACA,SAAAzpB,CAAA,CACD,EAEKsyB,EAAiC,IAAItE,GACzCtjB,EACA8e,EACAha,EACAia,EACAzpB,CAAA,EAGI4c,EAA6B,IAAI2M,GACrCvpB,EACA0K,EACA8e,EACAC,EACAja,CAAA,EAGI+oB,EAAoB,IAAInG,GAC5B1nB,EACA8E,EACA6iB,EACAC,EACA1V,EACA/B,EACA4O,EACA6O,EAAkB,SAAA,EAGdE,EAAmBjuB,EAAAA,cAAc,CACrC+nB,EAA+B,cAC/B1V,EAA2B,cAC3B0b,EAAkB,UAClBC,EAAkB,OAAO,SAAA,CAC1B,EAAE,KACDpzB,EAAAA,IAAKszB,GAAYA,EAAO,KAAMlM,GAAaA,CAAQ,EAAI,OAAS,MAAO,EACvE9jB,uBAAA,EACAkC,EAAAA,YAAY,CAAC,CAAA,EAYf,MAAO,CACL,QANc,IAAM,CACpB2nB,EAA+B,QAAA,EAC/BiG,EAAkB,QAAA,CACpB,EAIE,cAAe,IAAMA,EAAkB,WACvC,kBAAAA,EACA,2BAAA3b,EACA,+BAAA0V,EACA,OAAQgG,EACR,iBAAAE,EACA,SAjBgBP,GAA4B,CAC5CI,EAA8B,KAAKJ,CAAE,CACvC,EAoBE,MAAO,CACL,OAAOK,EAAkB,KAAA,CAC3B,EACA,mBAAAzd,EACA,YAAa0d,EAAkB,WAAA,CAEnC,EC5GO,MAAMG,WAAmBrrB,CAA+B,CAC7D,YACYmC,EACAuL,EACV,CACA,MAAM,CACJ,0BAA2B,OAC3B,8BAA+B,EAC/B,SAAU,OACV,oBAAqB,OACrB,wBAAyB,OACzB,4BAA6B,EAC7B,OAAQ,OACR,kBAAmB,OACnB,aAAc,MAAA,CACf,EAbS,KAAA,QAAAvL,EACA,KAAA,kBAAAuL,CAaZ,CAEO,OAAOvN,EAAqC,CACjD,KAAK,aAAaA,CAAU,CAC9B,CACF,CCdO,MAAMmrB,WAA6Blc,CAAiB,CACzD,YACYjN,EACAhC,EACAuN,EACA0O,EACA/O,EACV,CACA,MAAA,EANU,KAAA,QAAAlL,EACA,KAAA,WAAAhC,EACA,KAAA,kBAAAuN,EACA,KAAA,MAAA0O,EACA,KAAA,iBAAA/O,EAkBV,MAAMke,EAAoB9rB,EAAAA,MACxB,KAAK,QAAQ,YAAY,YACzB2c,EAAM,OAAA,EACN,KACA1kB,EAAAA,UAAU,IAAM,CACd,MAAM8zB,EAAsC,CAAC,CAC3C,UAAA3xB,EACA,SAAA7F,CAAA,IAKA,KAAK,MAAM,QAAQ,oCAAoC,CACrD,UAAA6F,EACA,SAAA7F,EACA,UAAW,CAAE,KAAM,aAAc,MAAO,EAAA,CAAI,CAC7C,EAcH,OAAO,KAAK,QAAQ,YAAY,oBAAoB,KAClD6D,EAAAA,KAAK,CAAC,EACNiY,EAAAA,eAAe,KAAK,QAAQ,YAAY,WAAW,EACnD5Q,MAAI,CAAC,CAAA,CAAG8O,CAAU,IAAM,CACtB,KAAM,CAAE,SAAAha,GAAaga,EACfyd,EAAqB,KAAK,WAAW,MAErC,CACJ,WAAYC,EACZ,SAAUC,CAAA,EAEV,KAAK,MAAM,QAAQ,iCAAiC,CAClD,SAAA33B,EACA,UAAW,CAAE,KAAM,aAAc,MAAO,EAAA,CAAI,CAC7C,GAAK,CAAA,EAEF43B,EACJ,KAAK,kBAAkB,IAAIF,CAAmB,EAC1CG,EAAe,KAAK,kBAAkB,IAAIF,CAAiB,EAEjE,GAAI,CAACC,GAAkB,CAACC,EAAc,OAEtC,MAAMC,EAAeL,EAAmB,SAClCM,EAAaN,EAAmB,OAEhC,CAAE,eAAA7I,EAAiB,CAAA,EACvB4I,EAAoC,CAClC,UAAWI,EACX,SAAA53B,CAAA,CACD,GAAK,CAAA,EAEF,CAAE,aAAA2uB,EAAe,CAAA,EACrB6I,EAAoC,CAClC,UAAWK,EACX,SAAA73B,CAAA,CACD,GAAK,CAAA,EAEFg4B,EACJF,IAAiB,QACjBpX,GAAUoX,CAAY,GACtBL,EAAmB,sBAAwBC,EAEvCO,EACJR,EAAmB,oBAAsBE,GACzCI,IAAe,QACfrX,GAAUqX,CAAU,EAEhBG,EAAWF,EACbhY,EAAgB4X,EAAe,IAAI,EACnCE,EAEEK,EAASF,EACXjY,EAAgB6X,EAAa,IAAI,EACjCE,EAEEK,EAAgCR,EAAe,cAE/CS,EAA8BR,EAAa,cAEjD,KAAK,WAAW,OAAO,CACrB,SAAAK,EACA,8BAAAE,EACA,0BAA2BxJ,EAC3B,oBAAA8I,EACA,OAAAS,EACA,4BAAAE,EACA,wBAAyB1J,EACzB,kBAAAgJ,EACA,aAAc3d,EAAW,EAAA,CAC1B,CACH,CAAC,CAAA,CAEL,CAAC,CAAA,EAQGse,EAAaf,EAAkB,KACnC9vB,EAAc,KAAK,QAAQ,YAAY,aAAa,EACpDyD,EAAAA,IAAI,IAAM,CACR,KAAM,CACJ,oBAAAwsB,EACA,kBAAAC,EACA,0BAAAY,EACA,wBAAAC,CAAA,EACE,KAAK,WAAW,MAEpB,GACED,IAA8B,QAC9BC,IAA4B,QAC5Bd,IAAwB,QACxBC,IAAsB,OAEtB,OAEF,MAAMC,EAAiB,KAAK,kBAAkB,IAAIF,CAAmB,EAC/DG,EAAe,KAAK,kBAAkB,IAAIF,CAAiB,EAEjE,GAAIC,IAAmB,QAAaC,IAAiB,OAAW,OAEhE,MAAMY,EAAiB,KAAK,MAAM,MAAM,uBACtCb,EACAW,CAAA,EAEIG,EAAe,KAAK,MAAM,MAAM,uBACpCb,EACAW,CAAA,EAIF,KAAK,WAAW,OAAO,CACrB,SAAUC,GAAgB,iBACtBpY,GAA4B,CAC1B,UAAWuX,EAAe,KAC1B,SAAUa,GAAgB,gBAAA,CAC3B,EACDzY,EAAgB4X,EAAe,IAAI,EACvC,OAAQc,GAAc,iBAClBrY,GAA4B,CAC1B,UAAWwX,EAAa,KACxB,SAAUa,GAAc,gBAAA,CACzB,EACD1Y,EAAgB6X,EAAa,IAAI,CAAA,CACtC,CACH,CAAC,CAAA,EAGHpsB,QAAM8rB,EAAmBe,CAAU,EAChC,KAAKvzB,EAAAA,UAAU,KAAK,QAAQ,CAAC,EAC7B,UAAA,CACL,CACF,CCjMO,MAAM4zB,GAAoB,CAAC,CAChC,SAAA/lB,EACA,WAAAgmB,CACF,IAQMhmB,GAAU,gBAAkB,sBAA8B,GAEvDgmB,ECTF,MAAenuB,WAIZ2Q,CAEV,CAOE,YAAYvS,EAAyC,CACnD,MAAA,EAEA,MAAMgwB,EAAsC,CAC1C,GAAG,KAAK,mBAAA,EACR,GAAGhwB,CAAA,EAGL,KAAK,cAAgBgwB,EACrB,KAAK,4BAA8B,IAAI5vB,UAEvC,KAAK,WAAa,KAAK,4BACpB,aAAA,EACA,KAAKK,cAAY,CAAC,CAAC,EAEtB,KAAK,WAAW,UAAA,CAClB,CAEA,eAAeD,EAIb,CACA,MAAMyvB,EAAmB9vB,EAAAA,sBAAsB,KAAK,cAAeK,CAAQ,EAErE4D,EAAQ,KAAK,kBAAkB6rB,CAAgB,EAE/CpvB,EAAa,CAACrC,EAAAA,eAAe,KAAK,eAAgB4F,CAAK,EAE7D,MAAO,CACL,WAAAvD,EACA,MAAAuD,EACA,OAAQ,KACN,KAAK,cAAgB6rB,EACrB,KAAK,eAAiB7rB,EAElBvD,GACF,KAAK,4BAA4B,KAAKuD,CAAK,EAGtCA,EACT,CAEJ,CAMO,OAAO5D,EAAkC,CAC9C,KAAM,CAAE,OAAAM,CAAA,EAAW,KAAK,eAAeN,CAAQ,EAE/CM,EAAA,CACF,CAEA,IAAI,QAAS,CACX,GAAI,CAAC,KAAK,eAAgB,CACxB,KAAM,CAAE,OAAAA,CAAA,EAAW,KAAK,eAAe,KAAK,aAAa,EAEzD,OAAOA,EAAA,CACT,CAEA,OAAO,KAAK,cACd,CAEA,IAAI,SAAU,CACZ,GAAI,CAAC,KAAK,eAAgB,CACxB,KAAM,CAAE,OAAAA,CAAA,EAAW,KAAK,eAAe,KAAK,aAAa,EAEzDA,EAAA,CACF,CAEA,OAAO,KAAK,UACd,CAEO,MAAsC3C,EAAW,CACtD,OAAO,KAAK,QAAQ,KAClBE,GAAUF,CAAI,EACdI,EAAAA,qBAAqBC,EAAAA,cAAc,CAAA,CAEvC,CAEO,SAAU,CACf,MAAM,QAAA,EACN,KAAK,4BAA4B,SAAA,CACnC,CACF,CC9FO,MAAM0xB,WACHtuB,EAEV,CACE,YACE5B,EACUsF,EACV,CACA,MAAMtF,CAAe,EAFX,KAAA,QAAAsF,EAIVA,EACG,MAAM,CAAC,WAAY,oBAAoB,CAAC,EACxC,KACCjD,EAAAA,IAAI,IAAM,KAAK,OAAO,KAAK,MAAM,CAAC,EAClCnG,EAAAA,UAAU,KAAK,QAAQ,CAAA,EAExB,UAAA,CACL,CAEQ,oBACNsE,EACsB,CACtB,MAAMuJ,EAAW,KAAK,QAAQ,SACxB4Y,EAAqB,KAAK,QAAQ,MAAM,oBAAsB,GAC9DwN,EAAyC,CAC7C,0BAA2B3vB,EAAS,kBACpC,0BAA2BA,EAAS,kBACpC,qBAAsBA,EAAS,aAC/B,kCAAmC,EACnC,mBAAoBsvB,GAAkB,CACpC,WAAYtvB,EAAS,WACrB,SAAAuJ,CAAA,CACD,CAAA,EAIH,OAAIA,GAAU,gBAAkB,wBAC9BomB,EAAiB,qBAAuB,cAGtCA,EAAiB,uBAAyB,eAC5CA,EAAiB,0BAA4B,YAK7CxN,GACAwN,EAAiB,4BAA8B,UAE/C96B,EAAO,KACL,qBAAqB86B,EAAiB,yBAAyB,4DAAA,EAEjEA,EAAiB,0BAA4B,QAI3CA,EAAiB,uBAAyB,cAC5CA,EAAiB,kCAAoC,EACrDA,EAAiB,0BAA4B,QAE7CA,EAAiB,kCACf3vB,EAAS,4BAA8B,OACnCA,EAAS,0BACT,IAGD2vB,CACT,CAEA,kBACEjwB,EAC0C,CAC1C,MAAMiwB,EAAmB,KAAK,oBAAoBjwB,CAAa,EAE/D,MAAO,CAAE,GAAG,KAAK,eAAgB,GAAGA,EAAe,GAAGiwB,CAAA,CACxD,CAEA,oBAAqB,CACnB,MAAO,CACL,WAAY,GACZ,kBAAmB,QACnB,kBAAmB,aACnB,0BAA2B,OAC3B,aAAc,aACd,sBAAuB,IACvB,wBAAyB,CAAE,KAAM,SAAU,MAAO,EAAA,EAClD,mCAAoC,CAAA,CAExC,CACF,CCtGO,MAAMC,WAAwB1rB,CAAiB,CACpD,UAAW,CACT,OAAO7B,EAAAA,KACT,CAEA,kBAAmB,CACjB,OAAO/H,KAAG,SAAS,cAAc,KAAK,CAAC,CACzC,CAEA,gBAAiB,CACf,OAAO+H,EAAAA,KACT,CAEA,UAAW,CACT,OAAO/H,EAAAA,GAAG,MAAS,CACrB,CAEA,kBAAmB,CACjB,OAAO+H,EAAAA,KACT,CAEA,kBAAmB,CAEnB,CACF,CCLO,MAAMwtB,WAAwB9d,CAAiB,CAiBpD,YACSzW,EACAw0B,EACAhrB,EACAga,EACAiR,EACA/vB,EACA1K,EACP,CACA,MAAA,EARO,KAAA,KAAAgG,EACA,KAAA,iBAAAw0B,EACA,KAAA,QAAAhrB,EACA,KAAA,YAAAga,EACA,KAAA,SAAAiR,EACA,KAAA,SAAA/vB,EACA,KAAA,SAAA1K,EAvBT,KAAQ,qBAAuB,IAAIsK,UAQnC,KAAQ,WAIG,KAyFX,KAAQ,yBAA2B,CAAC,CAClC,WAAAowB,EACA,iBAAAC,CAAA,IAII,CACJ,IAAI5nB,EAAe,KAAK,SAAS,MAAM,SAAS,MAC5CH,EAAiD,OACrD,MAAMgoB,EACJD,EAAmB,KAAK,SAAS,iBAAiB,QAAU,EACxD1mB,EAAW,KAAK,QAAQ,SACxBG,EAAyBgY,GAAoBnY,CAAQ,GAAK,GAEhE,GAAI,KAAK,SAAS,OAAO,mBAAoB,CAoBzC,CAACG,GACD,KAAK,SAAS,kBAAoB,cAClC,CAACsmB,IAED3nB,EAAe,KAAK,SAAS,MAAM,SAAS,MAAQ,GAKpD,CAACqB,GACD,KAAK,SAAS,kBAAoB,cAClCsmB,GACAE,IAEA7nB,EAAe,KAAK,SAAS,MAAM,SAAS,MAAQ,GAGtD,MAAM8nB,EACJD,GAAqBF,GAActmB,EAGnC,KAAK,KAAK,iBACVwmB,GACA,CAAC,KAAK,QAAQ,SAEdhoB,EAAoB,SACpBG,EAAe,KAAK,SAAS,MAAM,SAAS,MAAQ,GAEpD,KAAK,KAAK,gBACV6nB,GACA,KAAK,QAAQ,SAEbhoB,EAAoB,SACpBG,EAAe,KAAK,SAAS,MAAM,SAAS,MAAQ,GAC3C8nB,IACL,KAAK,QAAQ,QACfjoB,EAAoB,SAEpBA,EAAoB,QAGtBG,EAAe,KAAK,SAAS,MAAM,SAAS,MAAQ,EAExD,CAEA,MAAO,CACL,aAAAA,EACA,kBAAAH,CAAA,CAEJ,EAEA,KAAQ,wBAA0B,CAAC,CACjC,MAAAxR,EACA,KAAAD,EACA,IAAAwF,CAAA,IAKI,CACAvF,IAAU,OACZ,KAAK,iBAAiB,MAAM,MAAQ,GAAGA,CAAK,KAE5C,KAAK,iBAAiB,MAAM,eAAe,OAAO,EAEhDD,IAAS,OACX,KAAK,iBAAiB,MAAM,KAAO,GAAGA,CAAI,KAE1C,KAAK,iBAAiB,MAAM,eAAe,MAAM,EAE/CwF,IAAQ,OACV,KAAK,iBAAiB,MAAM,IAAM,GAAGA,CAAG,KAExC,KAAK,iBAAiB,MAAM,eAAe,KAAK,CAEpD,EAEA,KAAQ,sBACN,CAAC,CACC,aAAAoM,EACA,MAAA+nB,EACA,MAAAC,CAAA,IAMDj2B,GACCA,EAAO,KACLK,EAAAA,IAAKuP,GAAS,CACZ,MAAMsmB,EAAsBtyB,EAAAA,eAC1B,KAAK,YAAY,SACjB,KAAK,SAAS,QAAA,EAEZ,KAAK,WACL,OAEE,CAAE,MAAOuyB,EAAe,OAAQC,CAAA,EACpCF,GAAuB,CAAA,EACnB,CAAE,MAAAr2B,EAAQs2B,EAAe,OAAAr2B,EAASs2B,CAAA,EAAmBxmB,GAAQ,CAAA,EAC7D,CAAE,MAAO2hB,EAAe,OAAQriB,GACpC,KAAK,SAAS,SAEVmnB,EAAY,KAAK,kBACrBx2B,GAAS0xB,EACTA,EACAtjB,CAAA,EAEIqoB,EACJ,KAAK,SAAS,OAAO,uBAAyB,aACzCx2B,GAAUoP,EACX,KAAK,kBACHpP,GAAUoP,EACVA,EACAA,CAAA,EAYR,OATA,KAAK,WAAa,CAChB,MAAOmnB,EACP,OAAQC,EACR,SAAU,KAAK,SAAS,QAAA,EAG1B,KAAK,iBAAiB,MAAM,MAAQ,GAAGD,CAAS,KAChD,KAAK,iBAAiB,MAAM,OAAS,GAAGC,CAAU,KAE9C,KAAK,SAAS,OAAO,4BAA8B,YACrD,KAAK,wBAAwB,CAC3B,IAAKL,EACL,KAAMD,CAAA,CACP,EAEM,CAAE,MAAOK,EAAW,OAAQC,CAAA,IAMrC,KAAK,wBACH,KAAK,QAAQ,QACT,CAAE,MAAON,EAAO,IAAK,CAAA,EACrB,CAAE,KAAMA,EAAO,IAAK,CAAA,CAAE,EAGrB,CAAE,MAAOK,EAAW,OAAQC,CAAA,EACrC,CAAC,CAAA,EAGP,KAAO,OACLztB,GACG,CACH,MAAM0tB,EAAanyB,GAAgB,KAAK,WAAW,KAAKD,EAAAA,MAAA,CAAO,CAAC,EAEhE,YAAK,qBAAqB,KAAK0E,CAAM,EAE9B0tB,EAAA,CACT,EAxQE,MAAMC,EAAiB,KAAK,qBAAqB,KAC/Cv2B,EAAAA,UACE,CAAC,CAAE,eAAA8N,EAAgB,iBAAA8nB,EAAkB,WAAAD,EAAY,MAAAI,EAAO,MAAAC,KAAY,CAClE,KAAM,CAAE,kBAAAnoB,EAAmB,aAAAG,GACzB,KAAK,yBAAyB,CAAE,iBAAA4nB,EAAkB,WAAAD,EAAY,EAEhE,KAAK,YAAY,QAAQ,sBAAuB,OAAW,CACzD,kBAAA9nB,EACA,KAAM,KAAK,KACX,aAAAG,CAAA,CACD,EAED,MAAMwoB,EAAkB,KAAK,SAAS,OAAO,CAC3C,kBAAA3oB,EACA,cAAeG,EAAe,KAAK,SAAS,SAAS,MACrD,aAAAA,EACA,eAAAF,CAAA,CACD,EAED,OAAO/F,EAAAA,MACL9H,KAAG,CAAE,KAAM,QAAkB,EAC7Bu2B,EAAgB,KAKd,KAAK,sBAAsB,CACzB,aAAAxoB,EACA,MAAA+nB,EACA,MAAAC,CAAA,CACD,EACD51B,EAAAA,IAAK+C,IACH,KAAK,YAAY,QAAQ,qBAAsB,OAAW,CACxD,kBAAA0K,EACA,KAAM,KAAK,KACX,aAAAG,CAAA,CACD,EAEM,CACL,KAAM,MACN,KAAA7K,CAAA,EAEH,CAAA,CACH,CAEJ,CAAA,EAEFkF,EAAAA,MAAA,CAAM,EAGR,KAAK,WAAakuB,EAAe,KAC/BztB,EAAAA,OAAQlM,GAAUA,EAAM,OAAS,KAAK,EACtCwD,EAAAA,IAAKxD,GAAUA,EAAM,IAAI,EACzByL,EAAAA,MAAA,CAAM,CAEV,CAEQ,kBACNpE,EACAwP,EACAgjB,EACQ,CACR,GAAIxyB,GAAS,EAAG,OAAOwyB,EAEvB,MAAMC,EAAW,KAAK,IAAIzyB,EAAOwyB,CAAO,EAIlCE,EADa,KAAK,KAAKD,EAAWjjB,CAAQ,EACbA,EAGnC,OAAO,KAAK,IAAIkjB,EAAeljB,CAAQ,CACzC,CAkMA,IAAI,YAAa,CACf,MAAMlV,EAAQ,KAAK,iBAAiB,MAC9BqB,EAAQrB,EAAM,MAAQ,WAAWA,EAAM,KAAK,EAAI,EAChDsB,EAAStB,EAAM,OAAS,WAAWA,EAAM,MAAM,EAAI,EAEzD,MAAO,CACL,MAAAqB,EACA,OAAAC,CAAA,CAEJ,CACF,CCtSO,MAAM+2B,WAAkBtuB,CAA+B,CAe5D,YACSrH,EACA41B,EACApsB,EACA9E,EACA8e,EACAqS,EACA77B,EACP,CACA,MAAM,CACJ,SAAU,GACV,QAAS,GACT,QAAS,GACT,QAAS,GACT,MAAO,MAAA,CACR,EAdM,KAAA,KAAAgG,EACA,KAAA,cAAA41B,EACA,KAAA,QAAApsB,EACA,KAAA,SAAA9E,EACA,KAAA,YAAA8e,EACA,KAAA,MAAAqS,EACA,KAAA,SAAA77B,EAgFT,KAAA,KAAO,IAAM,CACX,KAAK,SAAS,KAAA,CAChB,EAEA,KAAA,OAAS,IAAM,CACb,KAAK,SAAS,OAAA,CAChB,EAEA,KAAO,UAAY,IAAM,CACvB,KAAK,aAAa,CAChB,QAAS,EAAA,CACV,CACH,EAUA,KAAO,QAAU,IAAM,CACrB,MAAM,QAAA,EAEN,KAAK,iBAAiB,OAAA,EACtB,KAAK,SAAS,QAAA,CAChB,EAkBA,KAAA,uBAAyB,IACvB,CAAC,CAAC,KAAK,SAAS,aAAa,WAAW,UAAU,EAoCpD,KAAO,OAAqC2N,GACnC,KAAK,QAAQ,OAAOA,CAAM,EAzJjC,KAAK,iBAAmBmuB,GACtBF,EACA51B,EACAwjB,CAAA,EAGFoS,EAAc,YAAY,KAAK,gBAAgB,EAE/C,MAAMG,EAAkB,KAAK,SAAS,OAAO,cAAc/1B,CAAI,EAE/D,KAAK,iBAAmB,IAAI8I,GAAgB9I,EAAM,KAAK,QAAQ,EAE/D,MAAMg2B,EAAiB,CACrB,QAAAxsB,EACA,SAAA9E,EACA,YAAA8e,EACA,KAAAxjB,EACA,iBAAkB,KAAK,iBACvB,iBAAkB,KAAK,iBACvB,SAAU,KAAK,QAAA,EAGjB,KAAK,SAAW+1B,EACZA,EAAgBC,CAAc,EAC9B,IAAI1B,GAAgB0B,CAAc,EAEtC,KAAK,QAAU,IAAIzB,GACjBv0B,EACA,KAAK,iBACLwJ,EACAga,EACA,KAAK,SACL,KAAK,SACL,KAAK,QAAA,EAGP,MAAMyS,EAAuB,KAAK,SAAS,OAAO,KAChD1vB,EAAAA,IAAI,CAAC,CAAE,MAAA+B,EAAO,MAAAD,KAAY,CACxB,KAAK,aAAa,CAChB,SAAUC,IAAU,SACpB,QAASA,IAAU,QACnB,MAAOA,IAAU,QAAUD,EAAQ,MAAA,CACpC,CACH,CAAC,CAAA,EAGH,KAAK,WAAa,KAAK,QAAQ,WAAW,KACxC9B,EAAAA,IAAI,IAAM,CACR,KAAK,aAAa,CAChB,QAAS,GACT,QAAS,KAAK,SAAS,OAAO,MAAM,QAAU,QAAA,CAC/C,CACH,CAAC,EACDa,EAAAA,MAAA,CAAM,EAGRN,EAAAA,MAOEmvB,EACA,KAAK,UAAA,EAEJ,KAAK71B,EAAAA,UAAU,KAAK,QAAQ,CAAC,EAC7B,UAAA,CACL,CAoBA,IAAW,UAAW,CACpB,OAAO,KAAK,MAAM,SAAS,CAC7B,CASA,IAAI,SAAU,CACZ,OAAO,KAAK,gBACd,CAUA,IAAI,kBAAmB,CACrB,OAAO,KAAK,SAAS,gBACvB,CAQA,IAAI,SAAU,CACZ,OAAO,KAAK,SAAS,OACvB,CAKA,IAAI,WAAY,CACd,OAAO,KAAK,SAAS,SACvB,CAEA,IAAI,iBAAkB,CACpB,OAAO,KAAK,SAAS,eACvB,CAEA,IAAI,YAAa,CACf,OAAO,KAAK,QAAQ,UACtB,CAEA,IAAI,eAAgB,CAClB,OAAOmuB,GAA0B,CAC/B,uBAAwB,CAAC,CAAC,KAAK,uBAAA,EAC/B,WAAY,KAAK,QAAQ,WAAW,OACpC,UAAW,KAAK,QAAQ,WAAW,MACnC,UAAW,KAAK,SAAS,SAAS,MAClC,WAAY,KAAK,SAAS,SAAS,OACnC,kBAAmB,KAAK,SAAS,OAAO,0BACxC,aAAc,KAAK,SAAS,OAAO,YAAA,CACpC,CACH,CAKF,CAEA,MAAMuH,GAAyB,CAC7BtB,EACAx0B,EACAwjB,IACG,CACH,MAAMtpB,EACJs6B,EAAiB,cAAc,cAAc,KAAK,EACpD,OAAAt6B,EAAQ,UAAU,IAAI,WAAW,EACjCA,EAAQ,UAAU,IAAI,aAAa8F,EAAK,iBAAmB,YAAY,EAAE,EACzE9F,EAAQ,MAAM,QAAU;AAAA;AAAA;AAAA,IAKxBA,EAAQ,QAAQ,QAAa,QAE7BspB,EAAY,QAAQ,gCAAiC,OAAW,CAAE,QAAAtpB,EAAS,EAEpEA,CACT,EC3NO,MAAMg8B,WAAyBzf,CAAiB,CAKrD,YACYjN,EACAuL,EACAC,EACAtQ,EACAyxB,EACV,CACA,MAAA,EANU,KAAA,QAAA3sB,EACA,KAAA,kBAAAuL,EACA,KAAA,aAAAC,EACA,KAAA,SAAAtQ,EACA,KAAA,YAAAyxB,EATZ,KAAQ,kBAAoB,IAAI5uB,EAAAA,oBAC1B,GAAI,EAYR,MAAM6uB,EAAc,KAAK,kBAAkB,KACzCj3B,EAAAA,IAAKk3B,GAAM,MAAM,KAAKA,EAAE,KAAA,CAAM,EAAE,KAAK,CAACnE,EAAGC,IAAMD,EAAIC,CAAC,CAAC,EACrD1vB,EAAAA,qBAAqB6zB,EAAAA,UAAU,EAC/B3xB,EAAAA,YAAY,CAAE,WAAY,EAAG,SAAU,GAAM,CAAA,EAGfmC,EAAAA,MAC9B,KAAK,QAAQ,YAAY,YACzB,KAAK,YAAY,QACjBsvB,EACA1xB,EAAS,MAAM,CAAC,oCAAoC,CAAC,CAAA,EAkBP,KAI9CkO,EAAAA,aAAa,IAAKlC,yBAAuB,EACzC5N,EAAc,KAAK,QAAQ,YAAY,aAAa,EACpDqU,EAAAA,eAAe,KAAK,QAAQ,YAAY,YAAaif,CAAW,EAChEj3B,EAAAA,IAAI,CAAC,CAAA,CAAGkW,EAAYkhB,CAAiB,IAAM,CACzC,KAAM,CAAE,mCAAAC,GAAuC9xB,EAAS,OAElD,CAAE,WAAAqR,EAAa,EAAG,SAAAD,EAAW,CAAA,EACjCd,EAAa,iCAAiC,CAC5C,SAAUK,EAAW,SACrB,UAAW,CAAE,KAAM,aAAc,MAAO,CAAA,EACxC,oBAAqB,EAAA,CACtB,GAAK,CAAA,EAGFohB,EACJD,IAAuC,IACnC,EACAzgB,EAAaygB,EACbE,EACJF,IAAuC,IACnCzhB,EAAkB,MAAM,OAAS,EACjCe,EAAW0gB,EAEXG,EAAiB,MAAM,KAC3B,CAAE,OAAQD,EAAkBD,EAAoB,CAAA,EAChD,CAACvI,EAAGzkB,IAAMgtB,EAAoBhtB,CAAA,EAI1BmtB,EAAgB,CAAC,GAAGL,EAAmB,GAAGI,CAAc,EAE9D5hB,EAAkB,MAAM,QAAQ,CAAC8hB,EAAkBhB,IAAU,CACvDe,EAAc,SAASf,CAAK,EAC9BgB,EAAiB,KAAA,EAEjBA,EAAiB,OAAA,CAErB,CAAC,CACH,CAAC,CAAA,EAGa,KAAKz2B,EAAAA,UAAU,KAAK,QAAQ,CAAC,EAAE,UAAA,CACjD,CAEA,UAAUyG,EAAoC,CAC5C,MAAMiwB,EAAUjwB,EAAW,IAAK7G,GAC9B,OAAOA,GAAS,SAAWA,EAAOA,EAAK,KAAA,EAGnC+2B,EAAaC,GAAiB,CAClC,MAAM73B,EAAM,KAAK,kBAAkB,MACnC23B,EAAQ,QAASjB,GAAU,CACzB,MAAMoB,EAAQ93B,EAAI,IAAI02B,CAAK,GAAK,EAC1BqB,EAAWF,EAAMC,EAAQ,EAAIA,EAAQ,EACvCC,GAAY,EAAG/3B,EAAI,OAAO02B,CAAK,EAC9B12B,EAAI,IAAI02B,EAAOqB,CAAQ,CAC9B,CAAC,EACD,KAAK,kBAAkB,KAAK/3B,CAAG,CACjC,EAEA,OAAA43B,EAAU,EAAI,EAEP,IAAM,CACP,KAAK,aACTA,EAAU,EAAK,CACjB,CACF,CAEO,SAAgB,CACrB,MAAM,QAAA,EAEN,KAAK,kBAAkB,SAAA,CACzB,CACF,CCzIO,MAAMI,GAA2C,CACtDC,EACAC,EACAC,IACyB,CAEzB,MAAMC,GAAWD,EAAiB,MAAQD,EAAiB,OAAS,EAC9DG,GAAWF,EAAiB,OAASD,EAAiB,QAAU,EAEtE,OAAO,IAAI1nB,EAAqB,CAC9B,EAAGynB,EAAiB,EAAIG,EACxB,EAAGH,EAAiB,EAAII,CAAA,CACzB,CACH,ECDO,MAAMC,UAA8B,OAAQ,CAA5C,aAAA,CAAA,MAAA,GAAA,SAAA,EACL,KAAgB,gBAAkB,kBAAkB,CAAA,CAcpD,OAAO,KACLC,EAIA19B,EACuB,CACvB,GAAIA,EAAU,CAEZ,MAAMqB,EAAWq8B,EACjB,OAAO,IAAID,EACTp8B,EAAS,EACTA,EAAS,EACTrB,EAAS,MACTA,EAAS,MAAA,CAEb,CAEA,MAAMY,EAAO88B,EAMb,OAAO,IAAID,EAAsB78B,EAAK,EAAGA,EAAK,EAAGA,EAAK,MAAOA,EAAK,MAAM,CAC1E,CACF,CAEO,MAAM+8B,EAAiB,CAM5B,YAAY,CAAE,MAAAh5B,EAAO,OAAAC,GAA6C,CAFlE,KAAgB,gBAAkB,kBAAkB,EAGlD,KAAK,MAAQD,EACb,KAAK,OAASC,CAChB,CACF,CAEO,MAAMg5B,EAAiB,CAM5B,YAAY,CAAE,MAAAj5B,EAAO,OAAAC,GAA6C,CAFlE,KAAgB,gBAAkB,kBAAkB,EAGlD,KAAK,MAAQD,EACb,KAAK,OAASC,CAChB,CACF,CCvEO,MAAMi5B,GAAoC,CAAC,CAChD,UAAA7hB,EACA,cAAA8hB,EACA,kBAAA/iB,CACF,IAOM,CACJ,MAAM9N,EAAQ8N,EAAkB,MAC1B7T,EAAY6T,EAAkB,IAAI+iB,CAAa,EAErD,GAAI,CAAC52B,EAAW,OAEhB,KAAM,CAAE,oBAAA62B,GAAwB9wB,EAAM,OACpC,CAAC3E,EAAKtC,IAAS,CACb,GAAIsC,EAAI,MAAO,OAAOA,EAEtB,MAAM0rB,EAAgBhuB,EAAK,cAE3B,OAAIkB,IAAclB,GACZgW,GAAagY,EAAgB,EACxB,CACL,oBAAqB1rB,EAAI,oBAAsB0T,EAC/C,MAAO,EAAA,EAKN,CACL,GAAG1T,EACH,oBAAqBA,EAAI,oBAAsB0rB,CAAA,CAEnD,EACA,CAAE,oBAAqB,EAAG,MAAO,EAAA,CAAM,EAGzC,OAAO+J,CACT,EChDMC,GAAsC,CAAC,CAC3C,WAAA1J,EACA,UAAAX,EACA,mBAAAsK,EACA,oBAAAC,EACA,UAAAC,CACF,IAQM,CACJ,MAAMC,EAA+BH,EAAqBtK,EACpD0K,EAAgCH,EAAsB5J,EAS5D,OANE6J,EAAU,OAAS,aACfC,GAAgCD,EAAU,OAC1CE,GAAiCF,EAAU,MAC3CF,GAAsBE,EAAU,OAChCD,GAAuBC,EAAU,KAGzC,EAEMG,GAA8C,CAAC,CACnD,mBAAAL,EACA,oBAAAC,EACA,UAAAC,EACA,iBAAA5H,CACF,IAOM,CACJ,MAAMgI,EACJN,EAAqB1H,EAAiB,MAElCiI,EACJN,EAAsB3H,EAAiB,OASzC,OANE4H,EAAU,OAAS,aACfK,GAAmCL,EAAU,OAC7CI,GAAkCJ,EAAU,MAC5CD,GAAuBC,EAAU,OACjCF,GAAsBE,EAAU,KAGxC,EAgBaM,GAA+B,CAAC,CAC3C,aAAc,CACZ,OAAAC,EACA,KAAAv9B,EACA,MAAAC,EACA,IAAAuF,EACA,MAAOgtB,EACP,OAAQW,CAAA,EAEV,UAAA6J,EACA,iBAAA5H,EACA,iBAAAoI,CACF,IAcM,CACJ,MAAMC,EAAerI,EAAiB,EAChCsI,EAAgBtI,EAAiB,GAAKA,EAAiB,MAAQ,GAE/DuI,EAAcvI,EAAiB,EAC/BwI,EAAiB,KAAK,IAC1BxI,EAAiB,GAAKA,EAAiB,OAAS,GAChD,CAAA,EAGI0H,EAAqB,KAAK,IAC9B,EACA,KAAK,IAAI78B,EAAOy9B,CAAa,EAAI,KAAK,IAAI19B,EAAMy9B,CAAY,CAAA,EAGxDV,EAAsB,KAAK,IAC/B,EACA,KAAK,IAAIQ,EAAQK,CAAc,EAAI,KAAK,IAAIp4B,EAAKm4B,CAAW,CAAA,EAS9D,GALEb,GAAsB,GAAKC,GAAuB,EAK1B,MAAO,CAAE,QAAS,EAAA,EAE5C,MAAMc,EACJV,GAA4C,CAC1C,UAAAH,EACA,oBAAAD,EACA,mBAAAD,EACA,iBAAA1H,CAAA,CACD,EAEH,OAAIoI,EACK,CAAE,QAASK,CAAA,EAWb,CACL,QAT0BhB,GAAoC,CAC9D,WAAA1J,EACA,UAAAX,EACA,UAAAwK,EACA,oBAAAD,EACA,mBAAAD,CAAA,CACD,GAGiCe,CAAA,CAEpC,EC7IaC,GAA2B,CAAC,CACvC,SAAA59B,EACA,kBAAA0Z,EACA,YAAAohB,CACF,IAIM,CACJ,MAAMj1B,EAAY6T,EAAkB,MAAM,KAAM/U,GAAS,CACvD,KAAM,CAAE,KAAA7E,EAAM,MAAAC,EAAO,OAAAs9B,EAAQ,IAAA/3B,GAC3Bw1B,EAAY,4BAA4Bn2B,CAAI,EAExCk5B,EAAgB79B,EAAS,GAAKF,GAAQE,EAAS,EAAID,EAEnD+9B,EAAgB99B,EAAS,GAAKsF,GAAOtF,EAAS,EAAIq9B,EAExD,OAAOQ,GAAiBC,CAC1B,CAAC,EAED,OAAI99B,EAAS,IAAM,GAAK,CAAC6F,EAChB6T,EAAkB,MAAM,CAAC,EAG3B7T,CACT,ECrBak4B,GAAwC,CAAC,CACpD,kBAAAlkB,EACA,WAAY,CAAE,KAAA/Z,EAAM,IAAAwF,CAAA,CACtB,IAiBS,IAAI+O,EAAc,CACvB,EAAGvU,EAAO+Z,EAAkB,EAC5B,EAAGvU,EAAMuU,EAAkB,CAAA,CAC5B,ECzBUmkB,GAAmC,CAAC,CAC/C,SAAAh+B,EACA,UAAA88B,EACA,iBAAAQ,EACA,kBAAA5jB,EACA,YAAAohB,EACA,oBAAAmD,EAAsB,GACtB,SAAAt/B,CACF,IAgBiB,CACf,MAAMu/B,EACJN,GAAyB,CACvB,SAAA59B,EACA,kBAAA0Z,EACA,YAAAohB,CAAA,CACD,GAAKphB,EAAkB,IAAI,CAAC,EAEzBykB,EAAoBzkB,EAAkB,MAAM,OAChD,CAACzS,EAAKpB,IAAc,CAClB,MAAMu4B,EAAetD,EAAY,4BAA4Bj1B,CAAS,EAChEw4B,EAAeJ,EACjBt/B,EAAS,iBACTA,EAAS,iBACP2/B,EAAwBxC,GAC5B97B,EACArB,EAAS,iBACT0/B,CAAA,EAGInJ,EAAmBkH,EAAsB,KAC7CkC,EACAD,CAAA,EAEI,CAAE,QAAAE,CAAA,EAAYnB,GAA6B,CAC/C,aAAAgB,EACA,UAAAtB,EACA,iBAAA5H,EACA,iBAAAoI,CAAA,CACD,EAED,OAAIiB,EACK,CAAC,GAAGt3B,EAAKpB,CAAS,EAGpBoB,CACT,EACA,CAAA,CAAC,EAGGmY,EAAY+e,EAAkB,CAAC,GAAKD,EACpC7e,EAAU8e,EAAkBA,EAAkB,OAAS,CAAC,GAAK/e,EAEnE,GAAI,CAACA,GAAa,CAACC,EAAS,OAE5B,MAAMmf,EAAiB9kB,EAAkB,kBAAkB0F,CAAS,EAC9Dqf,EAAe/kB,EAAkB,kBAAkB2F,CAAO,EAEhE,MAAO,CACL,WAAYmf,GAAkB,EAC9B,SAAUC,GAAgB,CAAA,CAE9B,ECpEaC,GAAqB,CAAC,CACjC,kBAAAhlB,EACA,QAAAvL,EACA,iBAAAkL,EACA,SAAAhQ,EACA,YAAAyxB,EACA,SAAAn8B,CACF,IAOM,CACJ,MAAMggC,EAAwC,CAC5C3+B,EACA6F,IACsB,CACtB,KAAM,CAAE,KAAA/F,EAAM,IAAAwF,CAAA,EAAQw1B,EAAY,4BAA4Bj1B,CAAS,EAevE,OAAO,IAAIkO,EAAkB,CAQ3B,EAAG,KAAK,IAAI/T,EAAS,EAAIF,EAAM,CAAC,EAChC,EAAG,KAAK,IAAIE,EAAS,EAAIsF,EAAK,CAAC,CAAA,CAChC,CACH,EAEMs5B,EAAiC/4B,GAC9Bk4B,GAAsC,CAC3C,kBAAmB,IAAIhqB,EAAkB,CAAE,EAAG,EAAG,EAAG,EAAG,EACvD,WAAY+mB,EAAY,4BAA4Bj1B,CAAS,CAAA,CAC9D,EAGGg5B,EAA0BxxB,GACvBqM,EAAkB,MAAM,KAAM/U,GACnBA,EAAK,SAAS,iBAAA,IAEX0I,CACpB,EAGGyxB,EAAgC,CACpC5+B,EACAC,EACA4+B,IACG,CACH,GAAI,OAAOA,GAAqB,SAAU,CACxC,MAAMl5B,EAAY6T,EAAkB,IAAIqlB,CAAgB,EACxD,OAAOl5B,EACHwT,EAAiB,8BACfnZ,EACAC,GAAU,EACV0F,CAAA,EAEF,MACN,CAEA,OAAOwT,EAAiB,8BACtBnZ,EACAC,GAAU,EACV4+B,CAAA,CAEJ,EAEMvH,EAAsC,CAAC,CAC3C,SAAAx3B,EACA,UAAA88B,EACA,UAAAj3B,EACA,iBAAAy3B,EACA,oBAAAW,EAAsB,GACtB,SAAAt/B,CAAA,IAee,CACf,MAAMg0B,EAAgB9sB,EAAU,cA2B1Bm5B,EAzBQ,MAAM,KAAK,MAAMrM,CAAa,CAAC,EAAE,IAAI,CAACE,EAAG2H,IAAU,CAC/D,MAAM3gB,GACJR,EAAiB,kCAAkC,CACjD,UAAWmhB,EACX,UAAA30B,CAAA,CACD,EAEG+V,EAAgBmiB,GAAsC,CAC1D,kBAAAlkB,GACA,WAAYihB,EAAY,4BAA4Bj1B,CAAS,CAAA,CAC9D,EAED,MAAO,CACL,MAAA20B,EACA,iBAAkB,CAChB,MAAO77B,EAAS,SAAS,MACzB,OAAQA,EAAS,SAAS,OAC1B,KAAMid,EAAc,EACpB,IAAKA,EAAc,EACnB,OAAQA,EAAc,EAAIjd,EAAS,SAAS,OAC5C,MAAOid,EAAc,EAAIjd,EAAS,SAAS,KAAA,CAC7C,CAEJ,CAAC,EAE0B,OACzB,CAACsI,EAAK,CAAE,iBAAA80B,EAAkB,MAAAvB,MAAY,CACpC,MAAM6D,EAAeJ,EACjBt/B,EAAS,iBACTA,EAAS,iBAEP2/B,GAAwBxC,GAC5B97B,EACArB,EAAS,iBACT0/B,CAAA,EAGInJ,GAAmBkH,EAAsB,KAC7CkC,GACAD,CAAA,EAGI,CAAE,QAAAE,EAAA,EAAYnB,GAA6B,CAC/C,iBAAAlI,GACA,iBAAAoI,EACA,UAAAR,EACA,aAAcf,CAAA,CACf,EAED,OAAIwC,GACK,CAAC,GAAGt3B,EAAKuzB,EAAK,EAGhBvzB,CACT,EACA,CAAA,CAAC,EAGG2nB,EAAiBoQ,EAAa,CAAC,EAC/BrQ,EAAeqQ,EAAaA,EAAa,OAAS,CAAC,GAAKpQ,EAE9D,GAAI,EAAAA,IAAmB,QAAaD,IAAiB,QAGrD,MAAO,CACL,eAAAC,EACA,aAAAD,CAAA,CAEJ,EAuEA,MAAO,CACL,sCAAuC,CAAC,CACtC,UAAA9oB,EACA,kBAAAgU,CAAA,IAII,CACJ,MAAMyZ,EAAawH,EAAY,4BAA4Bj1B,CAAS,EAEpE,OAAOk4B,GAAsC,CAC3C,WAAAzK,EACA,kBAAAzZ,CAAA,CACD,CACH,EAIA,mCACEvN,GAKAkwB,GAAkC,CAChC,GAAGlwB,EAGH,kBAAAoN,CAEF,CAAC,EACH,0CAvEAkC,GACG,CACH,MAAM/V,EAAY+3B,GAAyB,CACzC,SAAUhiB,EACV,kBAAAlC,EACA,YAAAohB,CAAA,CACD,EAED,GAAI,CAACj1B,EACH,OAGF,MAAMgU,EAAoB8kB,EACxB/iB,EACA/V,CAAA,EAGIo5B,EACJ5lB,EAAiB,kCAAkC,CACjD,UAAWxT,EAAU,WAAW,MAChC,WAAYA,EAAU,WAAW,OACjC,SAAUgU,EACV,uBAAwB,CAAC,CAAChU,EAAU,uBAAA,CAAuB,CAC5D,EAEGq5B,EACJ7lB,EAAiB,8CACfQ,EACAolB,EACAp5B,CAAA,EAGJ,MAAO,CACL,UAAAA,EACA,mBAAAo5B,EACA,sBAAAC,EACA,SAAUvgC,EAAS,MAAM,QAAA,CAE7B,EAkCE,8BAAAigC,EACA,sCAAAD,EACA,yBACE3+B,GAEA49B,GAAyB,CACvB,SAAA59B,EACA,kBAAA0Z,EACA,YAAAohB,CAAA,CACD,EACH,uBAAA+D,EACA,8BAAAC,EACA,iCACExyB,GAKA0xB,GAAiC,CAE/B,kBAAAtkB,EACA,YAAAohB,EACA,SAAAn8B,EACA,GAAG2N,CAAA,CACJ,EACH,oCACEA,GAKAkrB,EAAoC,CAClC,GAAGlrB,EACH,SAAA3N,CAAA,CACD,EACH,0BAxIgC,CAChCqB,EACA6F,IACG,CACH,KAAM,CAAE,OAAAw3B,EAAQ,KAAAv9B,EAAM,MAAAC,EAAO,IAAAuF,GAC3Bw1B,EAAY,4BAA4Bj1B,CAAS,EAEnD,OACE7F,EAAS,GAAKF,GACdE,EAAS,GAAKD,GACdC,EAAS,GAAKq9B,GACdr9B,EAAS,GAAKsF,CAElB,EA4HE,iBAAA+T,EACA,oDA1H0D,CAC1Dwa,EACAhuB,IACsB,CACtB,KAAM,CAAE,OAAAtC,EAAQ,MAAAD,CAAA,EAAUw3B,EAAY,4BAA4Bj1B,CAAS,EAE3E,OAAO,IAAIkO,EAAkB,CAC3B,EAAG,KAAK,IAAI,KAAK,IAAI,EAAG8f,EAAe,CAAC,EAAGvwB,CAAK,EAChD,EAAG,KAAK,IAAI,KAAK,IAAI,EAAGuwB,EAAe,CAAC,EAAGtwB,CAAM,CAAA,CAClD,CACH,CAgHE,CAEJ,EChVarF,GAASC,EAAa,UAAU,OAAO,ECsBvCghC,GAAsC,CAAC,CAClD,SAAAn/B,EACA,SAAAmX,CACF,IAIS,IAAIhD,GAAyB,CAClC,GAAGnU,EACH,KAAMA,EAAS,EACf,IAAKA,EAAS,EACd,MAAOmX,EAAS,MAChB,OAAQA,EAAS,OACjB,OAAQnX,EAAS,EAAImX,EAAS,OAC9B,MAAOnX,EAAS,EAAImX,EAAS,KAAA,CAC9B,EAmBI,MAAMioB,WAAcpzB,CAAsB,CAG/C,YACkB8uB,EACAphB,EACAL,EACAlL,EACAxI,EACAhH,EAChB,CACA,MAAM,CAAE,MAAO,CAAA,EAAI,EAPH,KAAA,YAAAm8B,EACA,KAAA,kBAAAphB,EACA,KAAA,iBAAAL,EACA,KAAA,QAAAlL,EACA,KAAA,QAAAxI,EACA,KAAA,SAAAhH,EAwHlB,KAAA,uBAAyB,CAACkH,EAAsB8U,IACvC,KAAK,MAAM,MAAM,KACrBmE,GACCA,EAAK,YAAcjZ,EAAU,OAASiZ,EAAK,YAAcnE,CAAA,EAI/D,KAAA,sBAAyBE,GAChB,KAAK,MAAM,MAAM,KACrBiE,GAASA,EAAK,oBAAsBjE,CAAA,EAIzC,KAAA,6BAAgCA,GAC9B,KAAK,KAAK/W,EAAAA,IAAI,IAAM,KAAK,sBAAsB+W,CAAiB,CAAC,CAAC,EAlIlE,KAAK,QAAUigB,EAAY,QAAQ,KACjChf,EAAAA,eAAend,CAAQ,EACvB+E,EAAAA,UAAU,CAAC,CAAA,CAAG,CAAE,SAAAyT,CAAA,CAAU,IAAM,CAC9B,MAAMlE,EAAQyG,EAAkB,MAAM,OACpC,CACEzS,EAGApB,EACAub,IACG,CAGH,MAAMie,EAFQ,IAAI,MAAMx5B,EAAU,aAAa,EAAE,KAAK,MAAS,EAE1B,IAAI,CAACgtB,EAAGlY,IAAc,CAGzD,MAAM2kB,EACJjmB,EAAiB,kCAAkC,CACjD,UAAAxT,EACA,UAAA8U,CAAA,CACD,EAEG4kB,EACJ55B,EAAQ,sCAAsC,CAC5C,UAAAE,EACA,kBAAmBy5B,CAAA,CACpB,EAEH,MAAO,CACL,eAAgBH,GAAoC,CAClD,SAAAhoB,EACA,SAAUooB,CAAA,CACX,EACD,OAAQ,IAAItrB,GAAoB,CAC9B,KAAMqrB,EAAsB,EAC5B,MAAOA,EAAsB,EAAInoB,EAAS,MAC1C,IAAKmoB,EAAsB,EAC3B,OAAQA,EAAsB,EAAInoB,EAAS,OAC3C,MAAOA,EAAS,MAChB,OAAQA,EAAS,OACjB,EAAGmoB,EAAsB,EACzB,EAAGA,EAAsB,CAAA,CAC1B,EACD,UAAAle,EACA,kBAAmBna,EAAI,OAAS0T,EAChC,UAAA9U,EACA,UAAA8U,CAAA,CAEJ,CAAC,EAED,MAAO,CAAC,GAAG1T,EAAK,GAAGo4B,CAAsB,CAC3C,EACA,CAAA,CAAC,EAoDH,OAjDen2B,EAAAA,cACb+J,EAAM,IAAK6L,GAAS,CAClB,KAAM,CAAE,UAAW0gB,EAAS,GAAGt1B,GAAS4U,EAYxC,GAAIA,EAAK,UAAU,MAAM,SAAU,CACjC,MAAM3b,EAAQ2b,EAAK,UAAU,UAAU,iBAAA,EAEvC,GACE3b,GACAA,GAAO,eAAe,UACtBA,EAAM,cAAc,SAAS,OAAS,KACtC,CACA,MAAMvC,EAAYuC,EAAM,cAAc,SAKtC,OAAO6E,IAAO,KACZlE,EAAAA,IAAI,IAAM,CACR,MAAM27B,EACJhhC,GACEmC,EACAke,EAAK,MAAA,EAGT,MAAO,CACL,GAAG5U,EACH,iBAAAu1B,CAAA,CAEJ,CAAC,CAAA,CAEL,CACF,CAGA,OAAO97B,EAAAA,GAAG,CAAE,GAAGuG,EAAM,iBAAkB,OAAW,CACpD,CAAC,CAAA,CAIL,CAAC,EACDpG,EAAAA,IAAKmP,IACH/U,GAAO,KAAK,eAAgB+U,CAAK,EAC1B,CAAE,MAAAA,CAAA,EACV,EACDlH,EAAAA,MAAA,CAAM,EAGR,KAAK,QAAQ,KAAKhH,EAAAA,UAAU,KAAK,QAAQ,CAAC,EAAE,UAAU,KAAK,KAAK,KAAK,IAAI,CAAC,CAC5E,CAiBF,CC5LO,MAAM26B,WAA2BtkB,CAAiB,CAmBvD,YAAsB1B,EAAsC,CAC1D,MAAA,EADoB,KAAA,kBAAAA,EAGpB,KAAK,QAAU,KAAK,kBAAkB,OAAO,KAC3ChW,EAAAA,UAAWkI,GACFH,EAAAA,MACL,GAAGG,EAAM,IAAKjH,GACZA,EAAK,KACHb,EAAAA,IAAKmJ,IAAW,CAAE,KAAAtI,EAAM,GAAGsI,GAAQ,EACnC7F,EAAAA,qBAAqBC,EAAAA,cAAc,CAAA,CACrC,CACF,CAEH,EACD0E,EAAAA,MAAA,CAAM,EAGR,KAAK,YAAc,KAAK,kBAAkB,OAAO,KAC/CrI,EAAAA,UAAWkI,GAAU,CACnB,MAAM+zB,EAAU/zB,EAAM,IAAKjH,GACzB2C,EAAc3C,EAAK,OAAO,EAAE,KAC1Bb,EAAAA,IAAKS,IAAa,CAAE,QAAAA,EAAS,KAAAI,GAAO,CAAA,CACtC,EAGF,OAAO8G,EAAAA,MAAM,GAAGk0B,CAAO,CACzB,CAAC,EACD5zB,EAAAA,MAAA,CAAM,EAGR,KAAK,UAAY,KAAK,kBAAkB,OAAO,KAC7CrI,EAAAA,UAAWkI,GACFH,EAAAA,MAAM,GAAGG,EAAM,IAAKjH,GAASA,EAAK,QAAQ,KAAKb,EAAAA,IAAI,IAAMa,CAAI,CAAC,CAAC,CAAC,CACxE,EACDoH,EAAAA,MAAA,CAAM,EAGR,KAAK,YAAc,KAAK,kBAAkB,OAAO,KAC/CrI,EAAAA,UAAWkI,GACFH,EAAAA,MACL,GAAGG,EAAM,IAAKjH,GAASA,EAAK,UAAU,KAAKb,EAAAA,IAAI,IAAMa,CAAI,CAAC,CAAC,CAAA,CAE9D,EACDoH,EAAAA,MAAA,CAAM,CAEV,CACF,CC/CO,MAAM6zB,WAAoBxkB,CAAiB,CAchD,YACY1B,EACAmmB,EACA1xB,EACA9E,EACA1K,EACV,CACA,MAAA,EANU,KAAA,kBAAA+a,EACA,KAAA,mBAAAmmB,EACA,KAAA,QAAA1xB,EACA,KAAA,SAAA9E,EACA,KAAA,SAAA1K,EAlBZ,KAAU,sBAAwB,IAAIsK,UAMtC,KAAU,0BAAoD,CAAA,EAmB5D,MAAM62B,EAAwBr0B,EAAAA,MAC5Bo0B,EAAmB,UACnBA,EAAmB,WAAA,EAGfE,EAAiBt0B,EAAAA,MACrB,KAAK,sBACLq0B,CAAA,EAGF,KAAK,QAAUC,EAAe,KAC5B70B,EAAAA,IAAI,IAAM,CACR,KAAK,kBAAkB,MAAM,QAASvG,GAAS,CAC7CA,EAAK,UAAA,CACP,CAAC,CACH,CAAC,EACD4S,EAAAA,aAAa,EAAE,EACf7T,EAAAA,UAAU,IACR,KAAK,kBAAkB,MAAM,OAC3B,CAACs8B,EAAMr7B,EAAMyc,IACX4e,EAAK,KACHC,EAAAA,UAAU,CAAC,CAAE,iBAAA3G,EAAkB,eAAA4G,KAAqB,CAClD,MAAM3G,EACJD,EAAmB36B,EAAS,iBAAiB,QAAU,EACnD06B,EACJjY,IAAc1H,EAAkB,MAAM,OAAS,EAC3CymB,EACJ92B,EAAS,OAAO,4BAA8B,WAC1CoI,EAAQtD,EAAQ,MAAA,EAEhBqD,EAAiB,KAAK,kBAC1B+nB,EACA9nB,CAAA,EAEI,CAAE,MAAAgoB,EAAO,MAAAC,CAAA,EAAU,KAAK,cAC5ByG,EACA5G,EACAD,EACA4G,EACAvhC,EAAS,iBAAiB,MAAA,EAM5B,OAAOgG,EACJ,OAAO,CACN,eAAA6M,EACA,iBAAA8nB,EACA,WAAAD,EACA,MAAAI,EACA,MAAAC,CAAA,CACD,EACA,KACC51B,EAAAA,IAAI,CAAC,CAAE,MAAAR,EAAO,OAAAC,KAAa,CACzB,MAAM68B,EAAiB,KAAK,sBAC1BD,EACA1uB,EACAgoB,EACAC,EACAp2B,EACAC,EACA5E,EAAS,iBAAiB,KAAA,EAG5B,YAAK,0BAA0ByiB,CAAS,EAAIgf,EAErC,CACL,iBAAkB3G,EAAQn2B,EAC1B,eAAgB68B,EAAazG,EAAQn2B,EAAS,CAAA,CAElD,CAAC,CAAA,CAEP,CAAC,CAAA,EAELI,EAAAA,GAAG,CAAE,iBAAkB,EAAG,eAAgB,EAAG,CAAA,CAC/C,EAEFoB,EAAAA,UAAU,KAAK,QAAQ,EACvBgH,EAAAA,MAAA,CAAM,EAGR,KAAK,QAAQ,UAAA,EAEb,KAAK,8BAAA,CACP,CAEQ,+BAAgC,CACtC,KAAK,mBAAmB,UACrB,KACCb,EAAAA,IAAKrF,GAAc,CACjB,KAAK,QAAQ,OAAO,CAClB,mBAAoBA,EAAU,uBAAA,CAAuB,CACtD,CACH,CAAC,EACDd,EAAAA,UAAU,KAAK,QAAQ,CAAA,EAExB,UAAA,CACL,CAEA,QAAS,CACP,KAAK,sBAAsB,KAAK,MAAS,CAC3C,CAEO,4BACLg6B,EACA,CACA,MAAM3d,EACJ,KAAK,kBAAkB,kBAAkB2d,CAAgB,GAAK,EAEhE,OACE,KAAK,0BAA0B3d,CAAS,GACxC,IAAIlN,GAAqB,CACvB,KAAM,EACN,MAAO,EACP,IAAK,EACL,OAAQ,EACR,MAAO,EACP,OAAQ,EACR,EAAG,EACH,EAAG,CAAA,CACJ,CAEL,CAEA,IAAI,eAAgB,CAClB,OAAO,KAAK,kBAAkB,MAAM,OAAO,CAACjN,EAAKtC,IACxCsC,EAAMtC,EAAK,cACjB,CAAC,CACN,CAEO,SAAU,CACf,MAAM,QAAA,EAEN,KAAK,sBAAsB,SAAA,CAC7B,CAEQ,kBACN40B,EACA9nB,EAC2B,CAC3B,OAAK,KAAK,SAAS,OAAO,mBAEtB8nB,EACK9nB,EAAQ,QAAU,OAGpBA,EAAQ,OAAS,QAN6B,MAOvD,CAEQ,cACN0uB,EACA5G,EACAD,EACA4G,EACAG,EACA,CACA,OAAIF,EACK,CACL,MAAO5G,EAAoB,EAAID,EAC/B,MAAOC,EACH2G,EACAA,EAAiBG,CAAA,EAIlB,CACL,MAAO/G,EACP,MAAO,CAAA,CAEX,CAEQ,sBACN6G,EACA1uB,EACAgoB,EACAC,EACAp2B,EACAC,EACA6S,EACA,CACA,GAAI+pB,EAAY,CACd,MAAMG,EAAWh9B,EAAQm2B,EACnB8G,EAAWh9B,EAASm2B,EAE1B,OAAO,IAAIxlB,GAAqB,CAC9B,KAAMulB,EACN,MAAO6G,EACP,IAAK5G,EACL,OAAQ6G,EACR,OAAAh9B,EACA,MAAAD,EACA,EAAGm2B,EACH,EAAGC,CAAA,CACJ,CACH,CAEA,MAAM55B,EAAO2R,EAAQ2E,EAAgBqjB,EAAQn2B,EAAQm2B,EAErD,OAAO,IAAIvlB,GAAqB,CAC9B,MAAOzC,EAAQ2E,EAAgBqjB,EAAQA,EAAQn2B,EAC/C,KAAAxD,EACA,EAAGA,EACH,IAAK45B,EACL,OAAQn2B,EACR,OAAAA,EACA,MAAAD,EACA,EAAGo2B,CAAA,CACJ,CACH,CACF,CCzPO,MAAM8G,WAAcplB,CAAiB,CAY1C,YACYjN,EACAhC,EACHuN,EACAL,EACGhQ,EACA8e,EACAxpB,EACV,CACA,MAAA,EARU,KAAA,QAAAwP,EACA,KAAA,WAAAhC,EACH,KAAA,kBAAAuN,EACA,KAAA,iBAAAL,EACG,KAAA,SAAAhQ,EACA,KAAA,YAAA8e,EACA,KAAA,SAAAxpB,EAlBZ,KAAU,eAAiB,IAAIuN,EAAAA,gBAC7B,MAAA,EAQF,KAAO,SAAW,KAAK,eAAe,aAAA,EAapC,KAAK,mBAAqB,IAAIwzB,GAAmBhmB,CAAiB,EAElE,KAAK,YAAc,IAAIkmB,GACrBlmB,EACA,KAAK,mBACLvL,EACA9E,EACA1K,CAAA,EAGF,KAAK,QAAU+/B,GAAmB,CAChC,QAAAvwB,EACA,kBAAAuL,EACA,iBAAAL,EACA,SAAAhQ,EACA,YAAa,KAAK,YAClB,SAAA1K,CAAA,CACD,EAED,KAAK,iBAAmB,IAAIk8B,GAC1B,KAAK,QACLnhB,EACA,KAAK,QACLrQ,EACA,KAAK,WAAA,EAGP,KAAK,MAAQ,IAAI+1B,GACf,KAAK,YACL,KAAK,kBACL,KAAK,iBACL,KAAK,QACL,KAAK,QACL,KAAK,QAAA,EAGP,MAAMqB,EAAsBtyB,EAAQ,MAAM,aAAa,EAAE,KACvD3B,EAAAA,OAAOmH,CAAS,EAChBzI,EAAAA,IAAKlG,GAAgB,CACnB,MAAMnG,EACJmG,EAAY,cAAc,cAAc,KAAK,EAC/CnG,EAAQ,MAAM,QAAU;AAAA;AAAA;AAAA,UAIxBA,EAAQ,UAAY,GAAG8Q,CAAW,SAElC,KAAK,eAAe,KAAK9Q,CAAO,CAClC,CAAC,CAAA,EAGG6hC,EAAkBx3B,EAAAA,cAAc,CACpC,KAAK,QAAQ,UACb,KAAK,QAAA,CACN,EAAE,KACDgC,EAAAA,IAAI,CAAC,CAAC0H,EAAU/T,CAAO,IAAM,CAC3B,GAAI,CAACA,EAAS,OAEd,KAAK,kBAAkB,aAAA,EAEvB,MAAM2M,EAAaoH,EAAS,WAAW,IACrC,CAACjF,EAAU6sB,IACT,IAAIF,GACF3sB,EACA9O,EACA,KAAK,QACL,KAAK,SACL,KAAK,YACL27B,EACA,KAAK,QAAA,CACP,EAGJ,KAAK,kBAAkB,QAAQhvB,CAAU,CAC3C,CAAC,CAAA,EAGHC,QAAMi1B,EAAiBD,CAAmB,EACvC,KAAK17B,EAAAA,UAAU,KAAK,QAAQ,CAAC,EAC7B,UAAA,CACL,CAEA,IAAW,SAAU,CACnB,OAAO,KAAK,eAAe,SAAA,CAC7B,CAEO,QAAS,CACd,KAAK,YAAY,OAAA,CACnB,CAEO,4BACLg6B,EACA,CACA,OAAO,KAAK,YAAY,4BAA4BA,CAAgB,CACtE,CAEA,IAAW,SAAU,CAEnB,OAAO,KAAK,MAAM,OACpB,CAEO,SAAU,CACf,MAAM,QAAA,EAEN,KAAK,MAAM,QAAA,EACX,KAAK,iBAAiB,QAAA,EACtB,KAAK,eAAe,SAAA,GAAY,OAAA,EAChC,KAAK,eAAe,SAAA,CACtB,CACF,CChJO,MAAM4B,WAA0BvlB,CAAiB,CACtD,YACYjN,EACA9E,EACV,CACA,MAAA,EAHU,KAAA,QAAA8E,EACA,KAAA,SAAA9E,EAKZ,KAAU,yBAA2B,IAAI6C,EAAAA,gBAA6B,EAAE,EACxE,KAAO,OAAS,KAAK,yBAAyB,aAAA,CAH9C,CAKA,IAAIsO,EAA2C,CAC7C,OAAI,OAAOA,GAAc,SAChB,KAAK,yBAAyB,MAAMA,CAAS,EAGlD,OAAOA,GAAc,SAChB,KAAK,yBAAyB,MAAM,KACzC,CAAC,CAAE,KAAA7V,CAAA,IAAWA,EAAK,KAAO6V,CAAA,EAIvBA,CACT,CAEA,kBAAkBomB,EAAsBC,EAAqB,CAC3D,MAAMC,EAAiB,KAAK,kBAAkBF,CAAS,GAAK,EACtDG,EAAY,KAAK,kBAAkBF,CAAQ,GAAK,EAEtD,OAAOC,EAAiBC,EACpB,QACAD,IAAmBC,EACjB,OACA,QACR,CAEA,kBAAkBtE,EAAwD,CACxE,MAAM52B,EACJ42B,aAAyBnC,GACrBmC,EACA,KAAK,IAAIA,CAAa,EAE5B,GAAI,CAAC52B,EAAW,OAEhB,MAAM20B,EAAQ,KAAK,yBAAyB,MAAM,QAAQ30B,CAAS,EAEnE,OAAO20B,EAAQ,EAAI,OAAYA,CACjC,CAEA,QAAQhvB,EAAyB,CAC/B,KAAK,yBAAyB,KAAK,CACjC,GAAG,KAAK,yBAAyB,SAAA,EACjC,GAAGA,CAAA,CACJ,CACH,CAGA,oBAAoB+O,EAAa,CAC/B,KAAM,CAAE,UAAA6G,CAAA,EAAcJ,GAASzG,CAAG,EAElC,GAAI6G,IAAc,OAChB,OAAO,KAAK,IAAIA,CAAS,CAI7B,CAEA,IAAI,OAAQ,CACV,OAAO,KAAK,yBAAyB,KACvC,CAKA,cAAe,CACb,KAAK,yBAAyB,MAAM,QAASzc,GAAS,CACpDA,EAAK,QAAA,CACP,CAAC,CACH,CACF,CC1DO,MAAMq8B,WAAiBh1B,CAAsB,CAClD,YACYmC,EACArF,EACV,CACA,MAAMjK,EAAU,SAAS,cAAc,KAAK,EAE5CA,EAAQ,aAAa,QAAQiR,EAAoB,GAAI,EAAE,EAEvD,MAAM,CACJ,QAAAjR,EACA,SAAU,CACR,MAAO,EACP,OAAQ,CAAA,EAEV,MAAO,EACP,OAAQ,CAAA,CACT,EAfS,KAAA,QAAAsP,EACA,KAAA,gBAAArF,EAgBV,MAAMm4B,EAAkB,KAAK,gBAC1B,MAAM,CAAC,oBAAoB,CAAC,EAC5B,KACC/1B,EAAAA,IAAI,IAAM,CACR,KAAK,aAAa,CAChB,SAAU,KAAK,kBAAkB,KAAK,KAAK,CAAA,CAC5C,CACH,CAAC,CAAA,EAGCg2B,EAAgB,KAAK,QAAQ,MAAM,aAAa,EAAE,KACtDh2B,EAAAA,IAAI,IAAM,CACR,KAAK,OAAA,CACP,CAAC,CAAA,EAGHO,QAAMw1B,EAAiBC,CAAa,EACjC,KAAKn8B,EAAAA,UAAU,KAAK,QAAQ,CAAC,EAC7B,UAAA,CACL,CAEU,kBAAkB+O,EAA2C,CACrE,KAAM,CAAE,mBAAAqtB,CAAA,EAAuB,KAAK,gBAAgB,OAOpD,MALiB,CACf,MAAOA,EAAqBrtB,EAAO,MAAQ,EAAIA,EAAO,MACtD,OAAQA,EAAO,MAAA,CAInB,CAEO,QAAS,CACd,MAAMA,EAAS,CACb,MAAO,KAAK,MAAM,QAAQ,YAC1B,OAAQ,KAAK,MAAM,QAAQ,YAAA,EAG7B,KAAK,aAAa,CAChB,SAAU,KAAK,kBAAkBA,CAAM,EACvC,GAAGA,CAAA,CACJ,CACH,CAEA,IAAW,kBAAmB,CAC5B,OAAO,IAAIwoB,GAAiB,CAC1B,MAAO,KAAK,MAAM,MAClB,OAAQ,KAAK,MAAM,MAAA,CACpB,CACH,CAEA,IAAW,UAAW,CACpB,OAAO,KAAK,MAAM,QACpB,CAEA,IAAW,aAAc,CACvB,MAAMN,EAAmB,KAAK,iBAK9B,OAJqB,KAAK,MAAM,QAAQ,sBAAA,GAEvB,OAASA,EAAiB,OAASA,EAAiB,KAGvE,CAgBA,IAAW,kBAAmB,CAC5B,MAAMA,EAAmB,KAAK,iBACxBoF,EAAgB,KAAK,YAE3B,OAAO,IAAI7E,GAAiB,CAC1B,MAAOP,EAAiB,MAAQoF,EAChC,OAAQpF,EAAiB,OAASoF,CAAA,CACnC,CACH,CACF,CC/FA,MAAMzW,GAAY,GAAG/a,EAAiB,QAEzBiX,GAAgB9d,GAAuC,CAClE,MAAM/G,EAAK,OAAO,WAAA,EACZq/B,EAAgB,IAAIp4B,UACpBq4B,EAAW,IAAIr4B,UACfkf,EAAc,IAAIwD,GAClBxd,EAAU,IAAIgd,GACdriB,EAAkB,IAAIiwB,GAAsBhwB,EAAeoF,CAAO,EAClEozB,EAAW,IAAIhW,GAASpd,EAASrF,CAAe,EAChD4Q,EAAoB,IAAIinB,GAAkBxyB,EAASrF,CAAe,EAClEnK,EAAW,IAAIqiC,GAAS7yB,EAASrF,CAAe,EAChDuQ,EAAmBma,GAAuB,CAC9C,QAAArlB,EACA,SAAUrF,EACV,SAAAnK,CAAA,CACD,EACKwN,EAAa,IAAIkrB,GAAWlpB,EAASuL,CAAiB,EACtD0O,EAAQ,IAAIoY,GAChBryB,EACAhC,EACAuN,EACAL,EACAvQ,EACAqf,EACAxpB,CAAA,EAEI6iC,EAAYzK,GAAgB,CAChC,QAAA5oB,EACA,kBAAAuL,EACA,YAAAyO,EACA,MAAAC,EACA,SAAUtf,EACV,SAAAnK,CAAA,CACD,EACK8iC,EAAuB,IAAInK,GAC/BnpB,EACAhC,EACAuN,EACA0O,EACA/O,CAAA,EAIFmoB,EAAU,iBAAiB,UAAUrzB,EAAQ,YAAY,oBAAoB,EAC7EqzB,EAAU,YAAY,UAAUrzB,EAAQ,YAAY,iBAAiB,EACrEqzB,EAAU,OAAO,UAAU,UACzBrzB,EAAQ,YAAY,yBAAA,EAEtBhC,EAAW,UAAUgC,EAAQ,YAAY,iBAAiB,EAE1D,MAAM2F,EAAS,IAAM,CACnButB,EAAc,KAAA,CAChB,EAEMK,EACJt9B,GAGG,CACH,KAAM,CAAE,iBAAA+0B,EAAkB,SAAAvmB,CAAA,EAAaxO,EAEvC,GAAI+J,EAAQ,SAAU,CACpBjQ,EAAO,KAAK,yCAAyC,EAErD,MACF,CAEAA,EAAO,IAAI,OAAQ,CAAE,QAAAkG,CAAA,CAAS,EAE9B,MAAMvF,EAAU8iC,GAAcxI,EAAkBn3B,CAAE,EAElDmM,EAAQ,OAAO,CACb,SAAAyE,EACA,YAAa/T,CAAA,CACd,EAEDiV,EAAA,CACF,EAEM8tB,EAA4B94B,EAC/B,MAAM,CAAC,oBAAoB,CAAC,EAC5B,KAAK2O,EAAAA,KAAK,CAAC,EAAGvM,EAAAA,IAAI4I,CAAM,CAAC,EAEtB+tB,EAAUR,EAAc,KAC5Bn2B,EAAAA,IAAI,IAAM,CACR,MAAMiuB,EAAmBhrB,EAAQ,MAAM,YAElCgrB,IAELA,EAAiB,MAAM,YAAY,WAAY,QAAQ,EAEvDx6B,EAAS,OAAA,EACTypB,EAAM,OAAA,EACR,CAAC,EACDrjB,EAAAA,UAAUu8B,CAAQ,CAAA,EAGdQ,EAAOr2B,EAAAA,MAAMo2B,EAASD,CAAyB,EAAE,UAAA,EAEvD7/B,EAAU,SAAU4oB,GAAWG,EAAM,EAWrC,MAAMpmB,EAAU,IAAM,CACpBtC,EAAU,SAAUuoB,EAAS,EAE7BmX,EAAK,YAAA,EACLpoB,EAAkB,QAAA,EAClB+nB,EAAqB,QAAA,EACrB34B,EAAgB,QAAA,EAChBqD,EAAW,QAAA,EACXgC,EAAQ,QAAA,EACRqzB,EAAU,QAAA,EACVpZ,EAAM,QAAA,EACNmZ,EAAS,QAAA,EACTD,EAAS,KAAA,EACTA,EAAS,SAAA,EACT3iC,EAAS,QAAA,CACX,EAEA,MAAO,CACL,GAAAqD,EACA,QAAAmM,EACA,MAAAia,EACA,YAAAD,EACA,IAAK,CACH,qBAAA5H,GACA,SAAAS,GACA,4BAAAX,GACA,WACE/T,GACG6U,GAAW,CAAE,GAAG7U,EAAQ,kBAAAoN,EAAmB,CAAA,EAElD,WAAY8nB,EACZ,mBAAoBpZ,EAAM,mBAC1B,kBAAA1O,EACA,OAAA5F,EACA,KAAA4tB,EACA,QAAAh9B,EACA,WAAY,CACV,IAAI,OAAQ,CACV,OAAOyH,EAAW,KACpB,EACA,IAAI,QAAyD,CAC3D,OAAOA,CACT,CAAA,EAEF,SAAUrD,EAIV,eAAiBjD,GAEb6T,EAAkB,IAAI7T,CAAS,GAAG,SAAS,eAAA,GAC3ClC,EAAAA,GAAG,MAAS,EAGhB,SAAAhF,EACA,eAAgBwP,EAAQ,YAAY,eACpC,cAAeA,EAAQ,YAAY,cAOnC,OAAQA,EAAQ,UAAU,KACxBrK,EAAAA,IAAK8O,GAAcA,EAAW,QAAU,MAAO,CAAA,EAEjD,SAAA2uB,EACA,EAAG,CACD,SAAAD,CAAA,CACF,CAEJ,EAEMK,GAAgB,CAACxI,EAA+Bn3B,KACpDm3B,EAAiB,MAAM,QAAU;AAAA,MAC7BA,EAAiB,MAAM,OAAO;AAAA;AAAA;AAAA,IAIlCA,EAAiB,UAAU,IAAI,GAAGxpB,CAAW,SAAS,EACtDwpB,EAAiB,aAAatpB,GAA+B7N,CAAE,EAC/Dm3B,EAAiB,aAAa,8BAA+Bn3B,CAAE,EAExDm3B,GCvNI4I,GACXvc,GACEra,GACEyb,GACEzc,GACEjG,GACEigB,GACEqC,GACEoE,GACEhO,GACEpJ,GACE6E,GACEvT,GACEwB,GACEmc,GACE5L,GACEsP,GAEE6b,EAAA,CACF,CACF,CACF,CACF,CACF,CACF,CACF,CACF,CACF,CACF,CACF,CACF,CACF,CACF,CACF,ECpCSC,GAET99B,GAEDC,GACgBD,EAAKC,CAAO"}
1
+ {"version":3,"file":"index.umd.cjs","sources":["../src/report.ts","../src/utils/dom.ts","../src/utils/frames.ts","../src/enhancers/accessibility.ts","../src/enhancers/chrome.ts","../src/enhancers/events/translateFramePositionIntoPage.ts","../src/enhancers/events/normalizeEventForViewport.ts","../src/enhancers/events/events.ts","../src/utils/objects.ts","../src/utils/rxjs.ts","../src/settings/SettingsManagerOverload.ts","../src/enhancers/fonts/SettingsManager.ts","../src/enhancers/fonts/fonts.ts","../src/enhancers/hotkeys.ts","../src/enhancers/html/links.ts","../src/utils/ReactiveEntity.ts","../src/spineItem/renderer/DocumentRenderer.ts","../src/spineItem/resources/ResourceHandler.ts","../src/enhancers/html/renderer/assets.ts","../src/constants.ts","../src/enhancers/html/renderer/createHtmlPageFromResource.ts","../src/enhancers/html/renderer/attachFrameSrc.ts","../src/enhancers/html/renderer/createFrameElement.ts","../src/enhancers/html/renderer/prePaginated/renderPrePaginated.ts","../src/enhancers/html/renderer/reflowable/styles.ts","../src/enhancers/html/renderer/reflowable/renderReflowable.ts","../src/enhancers/html/renderer/HtmlRenderer.ts","../src/enhancers/html/enhancer.ts","../src/utils/isDefined.ts","../src/spineItem/types.ts","../src/spine/types.ts","../src/utils/coordinates.ts","../src/enhancers/layout/coordinates.ts","../src/enhancers/layout/createMovingSafePan$.ts","../src/enhancers/layout/createPlaceholderPages.ts","../src/enhancers/layout/fixIframeScrollbar.ts","../src/enhancers/layout/fixReflowable.ts","../src/enhancers/layout/flagSpineItems.ts","../src/enhancers/layout/SettingsManager.ts","../src/enhancers/layout/updateSpreadMode.ts","../src/enhancers/layout/layoutEnhancer.ts","../src/enhancers/media/ImageRenderer.ts","../src/enhancers/media/media.ts","../src/enhancers/navigation/links.ts","../src/enhancers/navigation/report.ts","../src/enhancers/navigation/resolvers/getSpineItemPositionForLeftPage.ts","../src/enhancers/navigation/resolvers/getNavigationForLeftSinglePage.ts","../src/enhancers/navigation/resolvers/getNavigationForLeftOrTopPage.ts","../src/enhancers/navigation/resolvers/getSpineItemPositionForRightPage.ts","../src/enhancers/navigation/resolvers/getNavigationForRightOrBottomSinglePage.ts","../src/enhancers/navigation/resolvers/getNavigationForRightOrBottomPage.ts","../src/enhancers/navigation/navigators/manualNavigator.ts","../src/enhancers/navigation/navigators/panNavigator.ts","../src/utils/DestroyableClass.ts","../src/enhancers/navigation/navigators/UserScrollNavigation.ts","../src/enhancers/navigation/state.ts","../src/enhancers/navigation/throttleLock.ts","../src/enhancers/navigation/index.ts","../src/enhancers/pagination/chapters.ts","../src/enhancers/pagination/progression.ts","../src/enhancers/pagination/spine.ts","../src/enhancers/pagination/pagination.ts","../src/cfi/generate.ts","../src/cfi/parse.ts","../src/cfi/resolve.ts","../src/enhancers/pagination/ResourcesLocator.ts","../src/enhancers/pagination/enhancer.ts","../src/enhancers/resources/indexedDB.ts","../src/enhancers/resources/resourcesManager.ts","../src/enhancers/resources/index.ts","../src/enhancers/selection/selection.ts","../src/enhancers/selection/FrameSelectionTracker.ts","../src/enhancers/selection/trackSpineItemSelection.ts","../src/enhancers/selection/selectionEnhancer.ts","../src/enhancers/theme.ts","../src/enhancers/utils.ts","../src/enhancers/webkit.ts","../src/enhancers/zoom/constraints.ts","../src/enhancers/zoom/controlled.ts","../src/types/index.ts","../src/navigation/controllers/ScrollNavigationController.ts","../src/enhancers/zoom/scrollable.ts","../src/enhancers/zoom/ZoomController.ts","../src/enhancers/zoom/index.ts","../src/manifest/isFullyPrePaginated.ts","../src/context/BridgeEvent.ts","../src/context/Context.ts","../src/features/Features.ts","../src/hooks/HookManager.ts","../src/navigation/controllers/positions.ts","../src/navigation/controllers/ControlledNavigationController.ts","../src/navigation/consolidation/withPaginationInfo.ts","../src/navigation/consolidation/consolidateWithPagination.ts","../src/navigation/consolidation/mapUserNavigationToInternal.ts","../src/navigation/consolidation/withCfiPosition.ts","../src/navigation/consolidation/withDirection.ts","../src/navigation/consolidation/withFallbackPosition.ts","../src/navigation/consolidation/withSpineItem.ts","../src/navigation/consolidation/withSpineItemLayoutInfo.ts","../src/navigation/consolidation/withSpineItemPosition.ts","../src/navigation/consolidation/withUrlInfo.ts","../src/navigation/Locker.ts","../src/navigation/restoration/restoreNavigationForControlledPageTurnMode.ts","../src/navigation/restoration/restorePosition.ts","../src/navigation/restoration/withRestoredPosition.ts","../src/navigation/InternalNavigator.ts","../src/spineItem/helpers.ts","../src/spineItem/layout/getPageFromOffset.ts","../src/spineItem/layout/getSafePosition.ts","../src/spineItem/layout/getSpineItemNumberOfPages.ts","../src/spineItem/layout/getSpineItemPageIndexFromSpineItemPosition.ts","../src/spineItem/layout/getSpineItemPositionFromPageIndex.ts","../src/spineItem/locationResolver.ts","../src/spineItem/navigationResolver.ts","../src/navigation/resolvers/fromOutOfBoundsSpinePosition.ts","../src/navigation/resolvers/fromUnboundSpinePosition.ts","../src/navigation/resolvers/getAdjustedPositionForSpread.ts","../src/navigation/resolvers/getNavigationForPosition.ts","../src/navigation/resolvers/getNavigationForSpineItemPage.ts","../src/navigation/resolvers/getNavigationForUrl.ts","../src/navigation/resolvers/getNavigationFromSpineItemPosition.ts","../src/navigation/resolvers/NavigationResolver.ts","../src/navigation/Navigator.ts","../src/pagination/Pagination.ts","../src/pagination/PaginationController.ts","../src/settings/computeSpreadMode.ts","../src/settings/SettingsManager.ts","../src/settings/ReaderSettingsManager.ts","../src/spineItem/renderer/DefaultRenderer.ts","../src/spineItem/SpineItemLayout.ts","../src/spineItem/SpineItem.ts","../src/spine/loader/SpineItemsLoader.ts","../src/viewport/translateSpinePositionToRelativeViewport.ts","../src/viewport/types.ts","../src/spine/locator/getAbsolutePageIndexFromPageIndex.ts","../src/spine/locator/getItemVisibilityForPosition.ts","../src/spine/locator/getSpineItemFromPosition.ts","../src/spine/locator/getSpinePositionFromSpineItemPosition.ts","../src/spine/locator/getVisibleSpineItemsFromPosition.ts","../src/spine/locator/SpineLocator.ts","../src/spine/report.ts","../src/spine/Pages.ts","../src/spine/SpineItemsObserver.ts","../src/spine/SpineLayout.ts","../src/spine/Spine.ts","../src/spine/SpineItemsManager.ts","../src/viewport/Viewport.ts","../src/reader.ts","../src/createReaderWithEnhancer.ts","../src/enhancers/types/enhancer.ts"],"sourcesContent":["const ROOT_NAMESPACE = `@prose-reader/core`\n\nimport { Report as SharedReport } from \"@prose-reader/shared\"\n\nexport const Report = SharedReport.namespace(ROOT_NAMESPACE, undefined, {\n color: `#98cde7`,\n})\n","import { Report } from \"../report\"\n\nconst pointerEvents: string[] = [\n `pointercancel` as const,\n `pointerdown` as const,\n `pointerenter` as const,\n `pointerleave` as const,\n `pointermove` as const,\n `pointerout` as const,\n `pointerover` as const,\n `pointerup` as const,\n // `touchstart` as const,\n // `touchend` as const,\n]\n\nfunction createRangeOrCaretFromPoint(\n doc: Document,\n startX: number,\n startY: number,\n) {\n // @see https://developer.mozilla.org/en-US/docs/Web/API/Document/caretPositionFromPoint\n if (`caretPositionFromPoint` in doc) {\n // @see https://developer.mozilla.org/en-US/docs/Web/API/CaretPosition\n return doc.caretPositionFromPoint(startX, startY) as {\n offsetNode: Node\n offset: number\n }\n }\n if (\n \"caretRangeFromPoint\" in doc &&\n // @ts-expect-error limited availability\n typeof doc.caretRangeFromPoint !== \"undefined\"\n ) {\n // @ts-expect-error limited availability\n return doc.caretRangeFromPoint(startX, startY)\n }\n}\n\ntype ViewPort = { left: number; right: number; top: number; bottom: number }\n\n/**\n * @todo optimize\n */\nexport const getFirstVisibleNodeForPositionRelativeTo = (\n documentOrElement: Document | Element,\n viewport: ViewPort,\n) => {\n const ownerDocument =\n `createRange` in documentOrElement\n ? documentOrElement\n : documentOrElement.ownerDocument\n\n if (!ownerDocument) return undefined\n\n const element =\n `body` in documentOrElement\n ? getFirstVisibleElementForViewport(documentOrElement.body, viewport)\n : getFirstVisibleElementForViewport(documentOrElement, viewport)\n\n if (element) {\n let lastValidRange: Range | undefined\n let lastValidOffset = 0\n const range = ownerDocument.createRange()\n\n /**\n * We iterate through children to ensure we match the writing mode (direction)\n * of the document (This is easier than having to do some heuristics to match the direction)\n * Although probably not perfect ?\n */\n Array.from(element.childNodes).some((childNode) => {\n range.selectNodeContents(childNode)\n\n const rects = range.getClientRects() // this forces layout ? needs to find better approach\n\n const visibleRect = getFirstVisibleDOMRect(rects, viewport)\n\n // At this point we know the range is valid and contains visible rect.\n // This means we have a valid Node. We still need to know the visible offset to be 100% accurate\n if (visibleRect) {\n lastValidRange = range.cloneRange()\n\n /**\n * Now we will try to refine the search to get the offset\n * this is an incredibly expensive operation so we will try to\n * use native functions to get something\n * @important\n * when using float value it looks like sometime when at the begin of the book the returned range will be the last offset of the page\n * it can be tested with moby-dick.txt by using different font size. Whenever using something different than default font size we might\n * have floating point for font and we start having issue. Using ceil \"make sure\" to be inside the point. Hopefully.\n */\n const rangeOrCaret = createRangeOrCaretFromPoint(\n ownerDocument,\n Math.ceil(visibleRect.left),\n Math.ceil(visibleRect.top),\n )\n\n // good news we found something with same node so we can assume the offset is already better than nothing\n if (\n rangeOrCaret &&\n `startContainer` in rangeOrCaret &&\n rangeOrCaret.startContainer === lastValidRange.startContainer\n ) {\n lastValidOffset = rangeOrCaret.startOffset\n }\n if (\n rangeOrCaret &&\n `offsetNode` in rangeOrCaret &&\n rangeOrCaret.offsetNode === lastValidRange.startContainer\n ) {\n lastValidOffset = rangeOrCaret.offset\n }\n return true\n }\n return false\n })\n\n if (lastValidRange) {\n return {\n node: lastValidRange.startContainer,\n offset: lastValidOffset,\n }\n }\n\n return { node: element, offset: 0 }\n }\n\n return undefined\n}\n\nconst getFirstVisibleElementForViewport = (\n element: Element,\n viewport: ViewPort,\n): Element | undefined => {\n const rect = element.getBoundingClientRect()\n const positionFromViewport = getElementOrNodePositionFromViewPort(\n rect,\n viewport,\n )\n\n let lastValidElement: Element | undefined\n\n /**\n * @important\n * We cannot safely early return if the element is completely outside bounds. This is\n * because a children of that element could very much be positioned outside of its parent.\n *\n * We could do some heuristic assumptions or checking depth but nothing is quite safe at 100%\n */\n\n if (positionFromViewport !== `before` && positionFromViewport !== `after`) {\n lastValidElement = element\n }\n\n for (const child of element.children) {\n const childInViewPort = getFirstVisibleElementForViewport(child, viewport)\n\n if (childInViewPort) {\n return childInViewPort\n }\n }\n\n return lastValidElement\n}\n\nfunction getElementOrNodePositionFromViewPort(\n domRect: DOMRect,\n { left, right }: ViewPort,\n) {\n // horizontal + ltr\n if (domRect.left <= left && domRect.right <= left) return `before`\n if (domRect.left <= left && domRect.right > left && domRect.right <= right)\n return `partially-before`\n if (domRect.left <= right && domRect.right > right) return `partially-after`\n if (domRect.left > right) return `after`\n return `within`\n\n // @todo rtl\n // @todo vertical-lrt\n // @todo vertical-rtl\n}\n\nfunction getFirstVisibleDOMRect(domRect: DOMRectList, viewport: ViewPort) {\n return Array.from(domRect).find((domRect) => {\n const position = getElementOrNodePositionFromViewPort(domRect, viewport)\n\n if (position !== `before` && position !== `after`) {\n return true\n }\n return false\n })\n}\n\nexport const getRangeFromNode = (node: Node, offset: number) => {\n if (\n node.nodeType !== Node.CDATA_SECTION_NODE &&\n node.nodeType !== Node.DOCUMENT_TYPE_NODE\n ) {\n const range = node.ownerDocument?.createRange()\n range?.selectNodeContents(node)\n\n try {\n if (offset <= (range?.endOffset || 0)) {\n range?.setStart(node, offset || 0)\n }\n } catch (e) {\n Report.error(e)\n }\n\n return range\n }\n\n return undefined\n}\n\nexport const isPointerEvent = (event: Event): event is PointerEvent => {\n if (\n (event as PointerEvent)?.target &&\n (event?.target as Element)?.ownerDocument?.defaultView\n ) {\n const eventView = (event?.target as Element)?.ownerDocument\n ?.defaultView as Window & typeof globalThis\n\n if (eventView.PointerEvent && event instanceof eventView.PointerEvent) {\n return true\n }\n }\n\n if ((event as PointerEvent)?.view?.window) {\n const eventView = (event as PointerEvent)?.view as Window &\n typeof globalThis\n\n if (eventView.PointerEvent && event instanceof eventView.PointerEvent) {\n return true\n }\n }\n\n if (pointerEvents.includes(event.type)) {\n return true\n }\n\n return false\n}\n\nexport const isMouseEvent = (event: Event): event is MouseEvent => {\n if (isPointerEvent(event)) return false\n\n if (\n (event as MouseEvent)?.target &&\n (event?.target as Element)?.ownerDocument?.defaultView\n ) {\n const eventView = (event?.target as Element)?.ownerDocument\n ?.defaultView as Window & typeof globalThis\n\n if (eventView.MouseEvent) {\n return event instanceof eventView.MouseEvent\n }\n }\n\n if ((event as MouseEvent)?.view?.window) {\n const eventView = (event as MouseEvent)?.view as Window & typeof globalThis\n\n if (eventView.MouseEvent) {\n return event instanceof eventView.MouseEvent\n }\n }\n\n return false\n}\n\nexport const isTouchEvent = (event: Event): event is TouchEvent => {\n if (\n (event as TouchEvent)?.target &&\n (event?.target as Element)?.ownerDocument?.defaultView\n ) {\n const eventView = (event?.target as Element)?.ownerDocument\n ?.defaultView as Window & typeof globalThis\n\n if (eventView.TouchEvent) {\n return event instanceof eventView.TouchEvent\n }\n }\n\n if ((event as TouchEvent)?.view?.window) {\n const eventView = (event as TouchEvent)?.view as Window & typeof globalThis\n\n if (eventView.TouchEvent) {\n return event instanceof eventView.TouchEvent\n }\n }\n\n return false\n}\n\nexport const noopElement = () => document.createElement(\"div\")\n\nexport const getElementsWithAssets = (\n _document: Document | null | undefined,\n) => {\n const RESOURCE_ELEMENTS = [\n \"img\", // Images\n \"video\", // Video files\n \"audio\", // Audio files\n \"source\", // Source elements within video/audio\n \"link\", // Stylesheets and other linked resources\n \"script\", // JavaScript files\n ].join(\",\")\n\n return Array.from(_document?.querySelectorAll(RESOURCE_ELEMENTS) || [])\n}\n\n/**\n * Revoke all found blob urls in the document\n * - elements with src or href attribute\n * - stylesheet font-face rules\n */\nexport const revokeDocumentBlobs = (_document: Document | null | undefined) => {\n const elementsWithAsset = getElementsWithAssets(_document)\n\n elementsWithAsset.forEach((element) => {\n const url = element.getAttribute(\"src\") || element.getAttribute(\"href\")\n\n if (url?.startsWith(\"blob:\")) {\n _document?.defaultView?.URL.revokeObjectURL(url)\n }\n })\n\n if (_document) {\n const styleSheets = Array.from(_document.styleSheets || [])\n\n for (const sheet of styleSheets) {\n const getRules = () => {\n /**\n * Some stylesheets are not accessible in some cases and this may be a legit error.\n * - cross-origin\n * - resource not found (eg: epub internal structure error)\n */\n try {\n return Array.from(sheet.cssRules || [])\n } catch (e) {\n Report.warn(`Error getting rules for sheet: ${sheet.href}`, e)\n return []\n }\n }\n\n const rules = getRules()\n\n for (const rule of rules) {\n if (\n _document.defaultView &&\n rule instanceof _document.defaultView.CSSFontFaceRule\n ) {\n // eg:\n // 'url(\"font.woff2\") format(\"woff2\"), url(\"font.woff\") format(\"woff\"), url(blob:http://example.com/1234) format(\"opentype\")'\n // 'url(blob:http://example.com/1234)'\n const src = rule.style.getPropertyValue(\"src\")\n // handle multiple comma-separated sources\n const blobUrls = src.match(/blob:[^,\\s'\")]+/g)\n\n if (blobUrls) {\n blobUrls.forEach((url) => {\n _document?.defaultView?.URL.revokeObjectURL(url)\n })\n }\n }\n }\n }\n }\n}\n\n/**\n * Generic structural type checker - checks if an object has the expected properties\n * @param obj The object to check\n * @param requiredProps Array of property names that must exist\n * @param optionalMethods Array of method names that should be functions (optional)\n */\nexport function hasShape<T>(\n obj: unknown,\n requiredProps: (keyof T)[],\n optionalMethods: (keyof T)[] = [],\n): obj is T {\n if (typeof obj !== \"object\" || obj === null) return false\n\n // Check required properties exist\n for (const prop of requiredProps) {\n if (!(prop in obj)) return false\n }\n\n // Check optional methods are functions\n for (const method of optionalMethods) {\n // biome-ignore lint/suspicious/noExplicitAny: TODO\n if (method in obj && typeof (obj as any)[method] !== \"function\") {\n return false\n }\n }\n\n return true\n}\n\n/**\n * Global env agnostic method to detect if an element is HtmlElement.\n *\n * @example\n * checking instance of element from iframe will not work because\n * `window.HtmlElement` is not the same as iframe.window.HtmlElement\n * element instanceof HtmlElement -> false\n *\n * isHtmlElement(element) -> true\n */\nexport function isHtmlElement(element: unknown): element is HTMLElement {\n return (\n hasShape<HTMLElement>(\n element,\n [\"nodeType\"],\n [],\n // biome-ignore lint/suspicious/noExplicitAny: TODO\n ) && (element as any).nodeType === Node.ELEMENT_NODE\n )\n}\n\n/**\n * Type guard function to check if an element is a specific HTML tag element\n * @param element The element to check\n * @param tagName The HTML tag name (e.g., 'div', 'span', 'a')\n * @returns True if the element is an HTMLElement of the specified tag\n */\nexport function isHtmlTagElement<K extends keyof HTMLElementTagNameMap>(\n element: unknown,\n tagName: K,\n): element is HTMLElementTagNameMap[K] {\n return (\n isHtmlElement(element) &&\n element.tagName.toLowerCase() === tagName.toLowerCase()\n )\n}\n\nexport function isHtmlRange(element: unknown): element is Range {\n return hasShape<Range>(\n element,\n [\n \"startContainer\",\n \"endContainer\",\n \"startOffset\",\n \"endOffset\",\n \"collapsed\",\n \"commonAncestorContainer\",\n ],\n [\"setStart\", \"setEnd\", \"selectNodeContents\"],\n )\n}\n\nexport const injectCSS = (\n doc: Document,\n id: string,\n style: string,\n prepend?: boolean,\n) => {\n const userStyle = doc.createElement(`style`)\n userStyle.id = id\n userStyle.innerHTML = style\n\n if (prepend) {\n doc.head.prepend(userStyle)\n } else {\n doc.head.appendChild(userStyle)\n }\n\n return () => {\n removeCSS(doc, id)\n }\n}\n\nexport const removeCSS = (doc: Document, id: string) => {\n if (doc?.head) {\n const styleElement = doc.getElementById(id)\n\n if (styleElement) {\n styleElement.remove()\n }\n }\n}\n","import {\n from,\n fromEvent,\n map,\n type Observable,\n of,\n switchMap,\n take,\n} from \"rxjs\"\nimport {\n injectCSS as injectCSSToDocument,\n removeCSS as removeCSSToDocument,\n} from \"./dom\"\n\nexport const getAttributeValueFromString = (string: string, key: string) => {\n const regExp = new RegExp(`${key}\\\\s*=\\\\s*([0-9.]+)`, `i`)\n const match = string.match(regExp) || []\n const firstMatch = match[1] || `0`\n\n return (match && Number.parseFloat(firstMatch)) || 0\n}\n\nexport const injectCSSToFrame = (\n frameElement: HTMLIFrameElement,\n id: string,\n style: string,\n prepend?: boolean,\n) => {\n if (!frameElement?.contentDocument?.head) return\n\n injectCSSToDocument(frameElement.contentDocument, id, style, prepend)\n}\n\nexport const removeCSS = (frameElement: HTMLIFrameElement, id: string) => {\n if (!frameElement?.contentDocument) return\n\n removeCSSToDocument(frameElement.contentDocument, id)\n}\n\nexport const upsertCSSToFrame = (\n frameElement: HTMLIFrameElement | undefined,\n id: string,\n style: string,\n prepend?: boolean,\n) => {\n if (!frameElement) return\n\n const existingElement = frameElement?.contentDocument?.getElementById(\n id,\n ) as HTMLStyleElement\n\n if (existingElement) {\n existingElement.innerHTML = style\n return\n }\n\n injectCSSToFrame(frameElement, id, style, prepend)\n}\n\nexport const getFrameViewportInfo = (frame: HTMLIFrameElement | undefined) => {\n if (frame?.contentDocument) {\n const doc = frame.contentDocument\n const viewportMetaElement = doc.querySelector(`meta[name='viewport']`)\n\n if (viewportMetaElement) {\n const viewportContent = viewportMetaElement.getAttribute(`content`)\n\n if (viewportContent) {\n const width = getAttributeValueFromString(viewportContent, `width`)\n const height = getAttributeValueFromString(viewportContent, `height`)\n\n if (width > 0 && height > 0) {\n return {\n hasViewport: true,\n width: width,\n height: height,\n }\n }\n return { hasViewport: true }\n }\n }\n }\n\n return { hasViewport: false }\n}\n\nexport const waitForFrameLoad = (stream: Observable<HTMLIFrameElement>) =>\n stream.pipe(\n switchMap((frame) => {\n if (\n frame.src === \"about:blank\" &&\n frame.contentDocument?.readyState === \"complete\" &&\n frame.contentDocument.body\n ) {\n return of(frame)\n }\n\n return fromEvent(frame, `load`).pipe(\n take(1),\n map(() => frame),\n )\n }),\n )\n\nexport const waitForFrameReady = (stream: Observable<HTMLIFrameElement>) =>\n stream.pipe(\n switchMap((frame) => {\n const readyPromise = frame?.contentDocument?.fonts.ready\n\n if (readyPromise) {\n return from(readyPromise).pipe(map(() => frame))\n }\n\n return of(undefined)\n }),\n )\n","import { upsertCSSToFrame } from \"../utils/frames\"\nimport type { EnhancerOutput, RootEnhancer } from \"./types/enhancer\"\n\n/**\n *\n */\nexport const accessibilityEnhancer =\n <InheritOptions, InheritOutput extends EnhancerOutput<RootEnhancer>>(\n next: (options: InheritOptions) => InheritOutput,\n ) =>\n (options: InheritOptions): InheritOutput => {\n const reader = next(options)\n\n const observer = new IntersectionObserver((entries) => {\n entries.forEach((entry) => {\n if (entry.isIntersecting) {\n entry.target.removeAttribute(`tab-index`)\n } else {\n entry.target.setAttribute(`tab-index`, `-1`)\n }\n })\n }, {})\n\n reader.hookManager.register(\n `item.onDocumentLoad`,\n ({ itemId, destroy }) => {\n const item = reader.spineItemsManager.get(itemId)\n\n if (!item) return\n\n const frame = item.renderer.getDocumentFrame()\n\n if (!frame) return\n\n upsertCSSToFrame(\n frame,\n `prose-reader-accessibility`,\n `\n :focus-visible {\n ${\n /*\n Some epubs remove the outline, this is not good practice since it reduce accessibility.\n We will try to restore it by force.\n */ ``\n }\n outline: -webkit-focus-ring-color auto 1px;\n }\n `,\n )\n\n const links = frame.contentDocument?.body.querySelectorAll(`a`)\n\n links?.forEach((link) => {\n observer.observe(link)\n })\n\n destroy(() => {\n links?.forEach((link) => {\n observer.unobserve(link)\n })\n })\n },\n )\n\n return {\n ...reader,\n }\n }\n","import { takeUntil } from \"rxjs\"\nimport type { EnhancerOutput, RootEnhancer } from \"./types/enhancer\"\n\n/**\n * All fixes relative to chromes\n */\nexport const chromeEnhancer =\n <InheritOptions, InheritOutput extends EnhancerOutput<RootEnhancer>>(\n next: (options: InheritOptions) => InheritOutput,\n ) =>\n (options: InheritOptions): InheritOutput => {\n const reader = next(options)\n\n /**\n * This element is used to force a refresh of a screen in order to fix the\n * frozen screen that happens with chrome.\n * The bug is weird and I have yet to explain it correctly, what happens\n * is that sometime when moving the x-axis on navigation, the screen will still display\n * the old screen, as if it was frozen. Generally any interaction with the page will unfreeze\n * the screen and the new iframe will be displayed. It also happens within the same iframe.\n * So far it seems to be due to scaling and x-axis moving.\n * To ensure the screen does not freeze we are moving a 1:1 square in & out of the screen.\n * That way chrome is \"forced\" to refresh the screen.\n *\n * @todo\n * check https://developer.mozilla.org/en-US/docs/Web/CSS/will-change with will-change: transform\n * to see if it does refresh all the time itself.\n *\n * @todo\n * use transform and translate rather than changing top so it only affect composite layer rather than paint\n * @see https://www.algolia.com/blog/engineering/performant-web-animations/\n *\n * @important\n * This is disabled for now as removing will-change on container seems to fix the issue\n */\n // let screenForceRefreshElt: HTMLDivElement | undefined = undefined\n\n reader.context\n .watch(\"rootElement\")\n .pipe(takeUntil(reader.context.destroy$))\n .subscribe((rootElement) => {\n if (!rootElement) return\n\n const onScroll = () => {\n if (reader.settings.values.computedPageTurnMode === `controlled`) {\n rootElement.scrollTo(0, 0)\n }\n }\n\n /**\n * For some reason I have yet to find, chrome will force scroll x-axis on the container\n * whenever the user select text and drag it to the edges. This is not a scroll inside the iframe\n * but a scroll on the container itself..\n */\n rootElement.addEventListener(`scroll`, onScroll)\n })\n\n reader.hookManager.register(`item.onDocumentLoad`, ({ itemId }) => {\n const item = reader.spineItemsManager.get(itemId)\n const frame = item?.renderer.getDocumentFrame()\n\n if (!frame) return\n\n /**\n * Disable touch to search on first text touch / click. This does not prevent\n * it when selecting text. It needs to be turned off by the user.\n * @see https://developers.google.com/web/updates/2015/10/tap-to-search\n */\n frame.contentDocument?.body.setAttribute(`tabindex`, `-1`)\n })\n\n // const forceScreenRefresh$ = reader.$.$\n // .pipe(\n // // filter(event => event.type === `onNavigationChange`),\n // tap(() => {\n // // screenForceRefreshElt?.style.setProperty(`top`, `0px`)\n // // requestAnimationFrame(() => {\n // // screenForceRefreshElt?.style.setProperty(`top`, `-1px`)\n // // })\n // })\n // )\n\n // merge(forceScreenRefresh$)\n // .pipe(takeUntil(reader.$.destroy$))\n // .subscribe()\n\n return reader\n }\n","/**\n * Take the relative position of the event in the iframe and translate\n * it to the page coordinates.\n *\n * For example the page 2 of an iframe could be at x=600 but\n * the cursor on the page would be at x=100. That is for a\n * webpage of 500px of width and not using spread.\n */\nexport const translateFramePositionIntoPage = ({\n position,\n frameElement,\n}: {\n position: {\n clientX: number\n clientY: number\n }\n frameElement: HTMLIFrameElement\n pageWidth: number\n pageHeight: number\n}) => {\n // Get the frame's current transform scale\n const frameRect = frameElement.getBoundingClientRect()\n const scaleX = frameRect.width / frameElement.offsetWidth\n const scaleY = frameRect.height / frameElement.offsetHeight\n\n // Get the frame's position relative to the viewport\n const { left = 0, top = 0 } = frameRect\n\n // Transform the coordinates:\n // 1. Scale the position from iframe coordinates\n // 2. Add the frame's offset relative to viewport\n const adjustedX = position.clientX * scaleX + left\n const adjustedY = position.clientY * scaleY + top\n\n return {\n clientX: adjustedX,\n clientY: adjustedY,\n }\n}\n","import type { SpineLocator } from \"../../spine/locator/SpineLocator\"\nimport { isMouseEvent, isPointerEvent, isTouchEvent } from \"../../utils/dom\"\nimport type { Viewport } from \"../../viewport/Viewport\"\nimport { translateFramePositionIntoPage } from \"./translateFramePositionIntoPage\"\n\nexport const normalizeEventForViewport = <\n E extends MouseEvent | TouchEvent | PointerEvent,\n>(\n event: E,\n iframeOriginalEvent: E,\n locator: SpineLocator,\n viewport: Viewport,\n) => {\n const originalFrame = iframeOriginalEvent?.view?.frameElement\n\n if (!iframeOriginalEvent || !originalFrame) return event\n\n const spineItem = locator.getSpineItemFromIframe(originalFrame)\n const frameElement = originalFrame\n const { height: pageHeight, width: pageWidth } = viewport.pageSize\n\n if (!spineItem || !(frameElement instanceof HTMLIFrameElement)) return event\n\n if (isPointerEvent(event)) {\n const { clientX, clientY } = translateFramePositionIntoPage({\n position: event,\n frameElement,\n pageHeight,\n pageWidth,\n })\n\n const newEvent = new PointerEvent(event.type, {\n ...event,\n pointerId: event.pointerId,\n clientX,\n clientY,\n }) as E\n\n Object.defineProperty(newEvent, `target`, {\n value: iframeOriginalEvent.target,\n enumerable: true,\n })\n\n return newEvent\n }\n\n if (isMouseEvent(event)) {\n const { clientX, clientY } = translateFramePositionIntoPage({\n position: event,\n frameElement,\n pageHeight,\n pageWidth,\n })\n\n const newEvent = new MouseEvent(event.type, {\n ...event,\n clientX,\n clientY,\n }) as E\n\n Object.defineProperty(newEvent, `target`, {\n value: iframeOriginalEvent.target,\n enumerable: true,\n })\n\n return newEvent\n }\n\n if (isTouchEvent(event)) {\n const touches = Array.from(event.touches).map((touch) => {\n const { clientX, clientY } = translateFramePositionIntoPage({\n position: touch,\n frameElement,\n pageHeight,\n pageWidth,\n })\n\n return new Touch({\n identifier: touch.identifier,\n target: touch.target,\n clientX,\n clientY,\n })\n })\n\n const newEvent = new TouchEvent(event.type, {\n touches,\n changedTouches: touches,\n targetTouches: touches,\n }) as E\n\n Object.defineProperty(newEvent, `target`, {\n value: iframeOriginalEvent.target,\n enumerable: true,\n })\n\n return newEvent\n }\n\n return event\n}\n","import { isPointerEvent } from \"../../utils/dom\"\nimport type { EnhancerOutput, RootEnhancer } from \"../types/enhancer\"\nimport { normalizeEventForViewport } from \"./normalizeEventForViewport\"\n\nconst pointerEvents = [\n `pointercancel` as const,\n `pointerdown` as const,\n `pointerenter` as const,\n `pointerleave` as const,\n `pointermove` as const,\n `pointerout` as const,\n `pointerover` as const,\n `pointerup` as const,\n]\n\nconst passthroughEvents = [...pointerEvents /*, ...mouseEvents*/]\n\nexport const eventsEnhancer =\n <InheritOptions, InheritOutput extends EnhancerOutput<RootEnhancer>>(\n next: (options: InheritOptions) => InheritOutput,\n ) =>\n (options: InheritOptions): InheritOutput => {\n const reader = next(options)\n\n reader.hookManager.register(\n `item.onDocumentLoad`,\n ({ destroy, itemId }) => {\n const item = reader.spineItemsManager.get(itemId)\n\n const frame = item?.renderer.getDocumentFrame()\n\n if (!frame || !item) return\n\n /**\n * Register event listener for all mouse/pointer event in order to\n * passthrough events to main document\n */\n const unregister = passthroughEvents.map((event) => {\n const listener = (e: MouseEvent | PointerEvent | TouchEvent) => {\n let convertedEvent = e\n /**\n * We have to create a new fake event since the original one is already dispatched\n * on original frame.\n *\n * @see Failed to execute 'dispatchEvent' on 'EventTarget': The event is already being dispatched.\n */\n if (isPointerEvent(e)) {\n convertedEvent = new PointerEvent(e.type, e)\n }\n\n if (convertedEvent !== e) {\n const normalizedEvent = normalizeEventForViewport(\n convertedEvent,\n e,\n reader.spine.locator,\n reader.viewport,\n )\n\n reader.context.value.rootElement?.dispatchEvent(normalizedEvent)\n }\n }\n\n frame.contentDocument?.addEventListener(event, listener)\n\n return () => {\n frame.contentDocument?.removeEventListener(event, listener)\n }\n })\n\n destroy(() => {\n unregister.forEach((cb) => {\n cb()\n })\n })\n },\n )\n\n return reader\n }\n","export { isShallowEqual } from \"@prose-reader/shared\"\n\nexport const getBase64FromBlob = (data: Blob) => {\n const reader = new FileReader()\n\n return new Promise<string>((resolve) => {\n reader.addEventListener(\n `load`,\n () => {\n resolve(reader.result as string)\n },\n false,\n )\n\n reader.readAsDataURL(data)\n })\n}\n\nexport const pick = <R extends Record<string, unknown>, K extends keyof R>(\n obj: R,\n keys: K[],\n): Pick<R, K> => {\n return Object.entries(obj).reduce(\n (acc, [key, entry]) => {\n // biome-ignore lint/suspicious/noExplicitAny: TODO\n if (keys.includes(key as any)) {\n return {\n ...acc,\n [key]: entry,\n }\n }\n\n return acc\n },\n {} as Pick<typeof obj, K>,\n )\n}\n","import { isShallowEqual } from \"@prose-reader/shared\"\nimport { defer, Observable, type OperatorFunction, of } from \"rxjs\"\nimport { distinctUntilChanged, first, map, switchMap } from \"rxjs/operators\"\nimport { pick } from \"./objects\"\n\nexport const mapKeysTo = <R extends Record<string, unknown>, K extends keyof R>(\n keys: K[],\n): OperatorFunction<R, Pick<R, K>> => {\n return map((obj) => pick(obj, keys))\n}\n\nexport const watchKeys =\n <R extends Record<string, unknown>, K extends keyof R>(keys: K[]) =>\n (stream: Observable<R>) => {\n return stream.pipe(mapKeysTo(keys), distinctUntilChanged(isShallowEqual))\n }\n\nexport function observeResize(\n element: HTMLElement,\n): Observable<ResizeObserverEntry[]> {\n return new Observable<ResizeObserverEntry[]>((observer) => {\n const resizeObserver = new ResizeObserver((entries) => {\n observer.next(entries)\n })\n\n resizeObserver.observe(element)\n\n return () => {\n resizeObserver.disconnect()\n }\n })\n}\n\nexport const waitForSwitch =\n <O>(waitForStream: Observable<O>) =>\n <N>(stream: Observable<N>) =>\n stream.pipe(\n switchMap((value) =>\n waitForStream.pipe(\n first(),\n map(() => value),\n ),\n ),\n )\n\nexport const deferNextResult = <T>(stream: Observable<T>) => {\n let value: { result: T } | undefined\n\n const sub = stream.subscribe((result) => {\n value = { result: result }\n })\n\n return () => {\n sub.unsubscribe()\n\n if (value) {\n return of(value.result)\n }\n\n return stream\n }\n}\n\nexport function idle(): Observable<void> {\n return new Observable<void>((observer) => {\n // webkit does not support requestIdleCallback yet\n if (window.requestIdleCallback) {\n const handle = window.requestIdleCallback(() => {\n observer.next()\n observer.complete()\n })\n\n return () => cancelIdleCallback(handle)\n }\n\n const timeout = setTimeout(() => {\n observer.next()\n observer.complete()\n }, 1)\n\n return () => clearTimeout(timeout)\n })\n}\n\nexport function deferIdle<T>(callback: () => Observable<T>) {\n return defer(() => idle().pipe(switchMap(callback)))\n}\n\nexport const observeMutation = (\n target: Node,\n options?: MutationObserverInit,\n) => {\n return new Observable<MutationRecord[]>((subscriber) => {\n const observer = new MutationObserver((mutations) => {\n subscriber.next(mutations)\n })\n\n observer.observe(target, options)\n\n return () => observer.disconnect()\n })\n}\n\nexport function observeIntersection(\n element: HTMLElement,\n options?: IntersectionObserverInit,\n): Observable<IntersectionObserverEntry[]> {\n return new Observable<IntersectionObserverEntry[]>((observer) => {\n const intersectionObserver = new IntersectionObserver((entries) => {\n observer.next(entries)\n }, options)\n\n intersectionObserver.observe(element)\n\n return () => {\n intersectionObserver.disconnect()\n }\n })\n}\n","import { isShallowEqual, shallowMergeIfDefined } from \"@prose-reader/shared\"\nimport {\n combineLatest,\n type Observable,\n type ObservedValueOf,\n Subject,\n} from \"rxjs\"\nimport {\n distinctUntilChanged,\n map,\n shareReplay,\n startWith,\n} from \"rxjs/operators\"\nimport { watchKeys } from \"../utils/rxjs\"\nimport type { SettingsInterface } from \"./SettingsInterface\"\nimport type { CoreInputSettings, CoreOutputSettings } from \"./types\"\n\nexport abstract class SettingsManagerOverload<\n InputSettings extends object,\n OutputSettings extends object,\n ParentInputSettings extends CoreInputSettings,\n ParentOutputSettings extends CoreOutputSettings,\n> implements\n SettingsInterface<\n InputSettings & ParentInputSettings,\n OutputSettings & ParentOutputSettings\n >\n{\n protected inputSettings: InputSettings\n protected outputSettings: OutputSettings\n protected outputSettingsUpdateSubject: Subject<OutputSettings>\n protected settingsManager: SettingsInterface<\n ParentInputSettings,\n ParentOutputSettings\n >\n\n public values$: Observable<ParentOutputSettings & OutputSettings>\n\n constructor(\n initialSettings: Partial<InputSettings>,\n settingsManager: SettingsInterface<\n ParentInputSettings,\n ParentOutputSettings\n >,\n ) {\n this.settingsManager = settingsManager\n\n const inputSettings = shallowMergeIfDefined(\n this.getDefaultSettings(),\n initialSettings,\n )\n\n this.outputSettings = this.computeOutputSettings(inputSettings)\n this.inputSettings = shallowMergeIfDefined(\n this.getDefaultSettings(),\n initialSettings,\n )\n this.outputSettingsUpdateSubject = new Subject()\n\n this.values$ = combineLatest([\n this.settingsManager.values$,\n this.outputSettingsUpdateSubject.pipe(startWith(this.outputSettings)),\n ]).pipe(\n map(([parentSettings, settings]) => ({ ...parentSettings, ...settings })),\n shareReplay(1),\n )\n\n this.values$.subscribe()\n }\n\n abstract getDefaultSettings(): InputSettings\n\n abstract computeOutputSettings(inputSettings: InputSettings): OutputSettings\n\n /**\n * Returns true if both are equal\n */\n abstract hasSettingsChanged(newOutputSettings: OutputSettings): boolean\n\n abstract getCleanedParentInputSettings(\n settings: Partial<InputSettings & ParentInputSettings>,\n ): ParentInputSettings\n\n _prepareUpdate(settings: Partial<InputSettings & ParentInputSettings>): {\n hasChanged: boolean\n commit: () => OutputSettings & ParentOutputSettings\n } {\n const parentInputSettings = this.getCleanedParentInputSettings(settings)\n\n const parentManagerPreparedUpdate =\n this.settingsManager._prepareUpdate(parentInputSettings)\n\n const inputSettings = shallowMergeIfDefined(this.inputSettings, settings)\n\n const outputSettings = this.computeOutputSettings(inputSettings)\n const hasChanged = this.hasSettingsChanged(outputSettings)\n\n return {\n hasChanged: hasChanged || parentManagerPreparedUpdate.hasChanged,\n commit: () => {\n this.inputSettings = inputSettings\n this.outputSettings = outputSettings\n\n if (!parentManagerPreparedUpdate.hasChanged && hasChanged) {\n this.outputSettingsUpdateSubject.next(outputSettings)\n }\n\n const parentOutputSettings = parentManagerPreparedUpdate.commit()\n\n return {\n ...parentOutputSettings,\n ...outputSettings,\n }\n },\n }\n }\n\n public update(settings: Partial<InputSettings & ParentInputSettings>) {\n const { commit } = this._prepareUpdate(settings)\n\n commit()\n }\n\n get values(): ParentOutputSettings & OutputSettings {\n return {\n ...this.settingsManager.values,\n ...this.outputSettings,\n }\n }\n public watch<K extends keyof ObservedValueOf<typeof this.values$>>(\n key: K,\n ): Observable<(ParentOutputSettings & OutputSettings)[K]>\n public watch<K extends keyof ObservedValueOf<typeof this.values$>>(\n keys: K[],\n ): Observable<Pick<ParentOutputSettings & OutputSettings, K>>\n public watch<K extends keyof ObservedValueOf<typeof this.values$>>(\n keyOrKeys: K | K[],\n ) {\n if (Array.isArray(keyOrKeys)) {\n return this.values$.pipe(watchKeys(keyOrKeys))\n }\n\n return this.values$.pipe(\n map((result) => result[keyOrKeys]),\n distinctUntilChanged(isShallowEqual),\n )\n }\n\n public destroy() {\n this.outputSettingsUpdateSubject.complete()\n }\n}\n","import { SettingsManagerOverload } from \"../../settings/SettingsManagerOverload\"\nimport type {\n CoreInputSettings,\n CoreOutputSettings,\n} from \"../../settings/types\"\nimport { isShallowEqual } from \"../../utils/objects\"\nimport type { EnhancerFontsInputSettings } from \"./types\"\n\nexport class SettingsManager<\n ParentInputSettings extends CoreInputSettings,\n ParentOutputSettings extends CoreOutputSettings,\n> extends SettingsManagerOverload<\n EnhancerFontsInputSettings,\n EnhancerFontsInputSettings,\n ParentInputSettings,\n ParentOutputSettings\n> {\n computeOutputSettings(\n settings: EnhancerFontsInputSettings,\n ): EnhancerFontsInputSettings {\n return settings\n }\n\n hasSettingsChanged(newOutputSettings: EnhancerFontsInputSettings): boolean {\n return !isShallowEqual(this.outputSettings, newOutputSettings)\n }\n\n getCleanedParentInputSettings(\n settings: Partial<EnhancerFontsInputSettings & ParentInputSettings>,\n ): ParentInputSettings {\n const {\n fontJustification: _unused1,\n fontScale: _unused2,\n fontWeight: _unused3,\n lineHeight: _unused4,\n ...rest\n } = settings\n\n return rest as unknown as ParentInputSettings\n }\n\n getDefaultSettings(): EnhancerFontsInputSettings {\n return {\n fontScale: 1,\n fontWeight: \"publisher\",\n lineHeight: \"publisher\",\n fontJustification: \"publisher\",\n }\n }\n}\n","import {\n type Observable,\n type ObservedValueOf,\n Subject,\n map,\n takeUntil,\n} from \"rxjs\"\nimport { pairwise, tap } from \"rxjs/operators\"\nimport type { SettingsInterface } from \"../../settings/SettingsInterface\"\nimport { upsertCSSToFrame } from \"../../utils/frames\"\nimport type {\n EnhancerOptions,\n EnhancerOutput,\n RootEnhancer,\n} from \"../types/enhancer\"\nimport { SettingsManager } from \"./SettingsManager\"\nimport type { EnhancerFontsInputSettings } from \"./types\"\n\ntype OutputOptions = Required<EnhancerFontsInputSettings>\n\n/**\n * @important\n * We don't apply font scaling on pre-paginated because it could potentially\n * break publisher scaling. Since it's specifically made for the given fixed layout\n * we should trust the publisher and not break its rendering.\n * @see 9781250213662\n *\n * Setting the font scale on body still has a chance to break publisher potential\n * font size on body if they already use something.\n * @see 9782714493743\n */\nexport const fontsEnhancer =\n <\n InheritOptions extends EnhancerOptions<RootEnhancer>,\n InheritOutput extends EnhancerOutput<RootEnhancer>,\n InheritSettings extends NonNullable<\n InheritOutput[\"settings\"][\"_inputSettings\"]\n >,\n InheritComputedSettings extends NonNullable<\n InheritOutput[\"settings\"][\"_outputSettings\"]\n >,\n Output extends Omit<InheritOutput, \"settings\"> & {\n settings: SettingsInterface<\n InheritSettings & EnhancerFontsInputSettings,\n EnhancerFontsInputSettings & InheritComputedSettings\n >\n },\n >(\n next: (options: InheritOptions) => InheritOutput,\n ) =>\n (options: InheritOptions & Partial<EnhancerFontsInputSettings>): Output => {\n const { fontScale, lineHeight, fontWeight, fontJustification } = options\n const changes$ = new Subject<Partial<OutputOptions>>()\n const reader = next(options)\n\n const settingsManager = new SettingsManager<\n InheritSettings,\n InheritComputedSettings\n >(\n {\n fontScale,\n lineHeight,\n fontWeight,\n fontJustification,\n },\n reader.settings as SettingsInterface<\n InheritSettings,\n InheritComputedSettings\n >,\n )\n\n const getStyle = () => `\n ${\n /*\n Ideally, we would like to use !important but it could break publisher specific\n cases.\n Also right now we do not apply it to * since it would also break publisher\n more specific scaling down the tree.\n\n body *:not([class^=\"mjx-\"]) {\n */ ``\n }\n body {\n ${settingsManager.values.fontScale !== 1 ? `font-size: ${settingsManager.values.fontScale}em !important;` : ``}\n ${settingsManager.values.lineHeight !== `publisher` ? `line-height: ${settingsManager.values.lineHeight} !important;` : ``}\n ${settingsManager.values.fontWeight !== `publisher` ? `font-weight: ${settingsManager.values.fontWeight} !important;` : ``}\n ${settingsManager.values.fontJustification !== `publisher` ? `text-align: ${settingsManager.values.fontJustification} !important;` : ``}\n }\n `\n\n /**\n * Programmatically update every loaded items\n */\n const applyChangeToSpineItems = (requireLayout: boolean) => {\n reader.spineItemsManager.items.forEach((item) => {\n if (item.renditionLayout !== `pre-paginated`) {\n const frame = item.renderer.getDocumentFrame()\n\n if (frame) {\n upsertCSSToFrame(frame, `prose-reader-fonts`, getStyle())\n }\n }\n })\n\n if (requireLayout) {\n reader.layout()\n }\n }\n\n /**\n * Make sure we apply the style to any new item loaded.\n */\n reader.hookManager.register(`item.onDocumentLoad`, ({ itemId }) => {\n const item = reader.spineItemsManager.get(itemId)\n\n if (item?.renditionLayout !== `pre-paginated`) {\n const frame = item?.renderer.getDocumentFrame()\n\n if (frame) {\n upsertCSSToFrame(frame, `prose-reader-fonts`, getStyle())\n }\n }\n })\n\n const shouldRequireLayout = <T extends ObservedValueOf<typeof changes$>>(\n source: Observable<T>,\n ) =>\n source.pipe(\n pairwise(),\n map(([old, latest]) => {\n if (latest.fontScale !== old.fontScale) return true\n if (latest.lineHeight !== old.lineHeight) return true\n\n return false\n }),\n )\n\n settingsManager.values$\n .pipe(\n shouldRequireLayout,\n tap(applyChangeToSpineItems),\n takeUntil(reader.$.destroy$),\n )\n .subscribe()\n\n return {\n ...reader,\n destroy: () => {\n changes$.complete()\n settingsManager.destroy()\n reader.destroy()\n },\n settings: settingsManager,\n } as unknown as Output\n }\n","import type { KeyboardEvent } from \"react\"\nimport { EMPTY, fromEvent, map, merge, switchMap, takeUntil } from \"rxjs\"\nimport type { NavigationEnhancerOutput } from \"./navigation/types\"\nimport type {\n EnhancerOptions,\n EnhancerOutput,\n RootEnhancer,\n} from \"./types/enhancer\"\n\nexport const hotkeysEnhancer =\n <\n InheritOptions extends EnhancerOptions<RootEnhancer>,\n InheritOutput extends EnhancerOutput<RootEnhancer> &\n NavigationEnhancerOutput,\n >(\n next: (options: InheritOptions) => InheritOutput,\n ) =>\n (options: InheritOptions): InheritOutput => {\n const reader = next(options)\n\n const navigateOnKey = (document: Document) =>\n fromEvent<KeyboardEvent>(document, \"keyup\").pipe(\n map((e) => {\n const { pageTurnDirection, computedPageTurnMode } =\n reader.settings.values\n\n if (computedPageTurnMode === \"scrollable\") {\n return e\n }\n\n if (pageTurnDirection === \"horizontal\") {\n if (e.key === `ArrowRight`) {\n return reader.navigation.turnRight()\n }\n\n if (e.key === `ArrowLeft`) {\n return reader.navigation.turnLeft()\n }\n }\n\n if (pageTurnDirection === \"vertical\") {\n if (e.key === `ArrowDown`) {\n return reader.navigation.turnRight()\n }\n\n if (e.key === `ArrowUp`) {\n return reader.navigation.turnLeft()\n }\n }\n\n return e\n }),\n )\n\n navigateOnKey(document).pipe(takeUntil(reader.$.destroy$)).subscribe()\n\n reader.spineItemsManager.items$\n .pipe(\n switchMap((spineItems) =>\n merge(\n ...spineItems.map((item) =>\n item.watch(\"isLoaded\").pipe(\n switchMap(() => {\n const element = item.renderer.getDocumentFrame()\n\n return element instanceof HTMLIFrameElement &&\n element?.contentDocument\n ? navigateOnKey(element.contentDocument)\n : EMPTY\n }),\n ),\n ),\n ),\n ),\n takeUntil(reader.$.destroy$),\n )\n .subscribe()\n\n return reader\n }\n","import { fromEvent, merge, NEVER, share, switchMap, tap } from \"rxjs\"\nimport type { Reader } from \"../../reader\"\n\nexport const handleLinks = (reader: Reader) => {\n return reader.spine.spineItemsManager.items$.pipe(\n switchMap((items) =>\n merge(\n ...items.map((item) => {\n return item.watch(\"isLoaded\").pipe(\n switchMap(() => {\n const frame = item.renderer.getDocumentFrame()\n\n if (!frame || !frame?.contentDocument) return NEVER\n\n const anchorElements = Array.from(\n frame.contentDocument.querySelectorAll(`a`),\n )\n\n const events$ = anchorElements.map((element) =>\n fromEvent<MouseEvent>(element, `click`),\n )\n\n return merge(...events$)\n }),\n )\n }),\n ),\n ),\n tap((event) => {\n event.preventDefault()\n }),\n share(),\n )\n}\n","import { isShallowEqual } from \"@prose-reader/shared\"\nimport {\n BehaviorSubject,\n distinctUntilChanged,\n map,\n Observable,\n Subject,\n takeUntil,\n} from \"rxjs\"\nimport { watchKeys } from \"./rxjs\"\n\n/**\n * Convenience class to manage reactive entities.\n * Used across the codebase.\n *\n * Embed within commonly used methods.\n */\nexport class ReactiveEntity<\n T extends Record<string, unknown>,\n> extends Observable<T> {\n protected stateSubject: BehaviorSubject<T>\n protected _destroy$ = new Subject<void>()\n\n constructor(initialState: T) {\n super((subscriber) => {\n const sub = this.stateSubject\n .pipe(takeUntil(this._destroy$))\n .subscribe(subscriber)\n\n return sub\n })\n this.stateSubject = new BehaviorSubject<T>(initialState)\n }\n\n protected next(value: T) {\n this.stateSubject.next(value)\n }\n\n /**\n * Default shallow compare.\n */\n protected mergeCompare(pagination: Partial<T>) {\n const newValue = { ...this.value, ...pagination }\n\n if (isShallowEqual(this.value, newValue)) return\n\n this.stateSubject.next(newValue)\n }\n\n public watch<K extends keyof T>(key: K): Observable<T[K]>\n public watch<K extends keyof T>(keys: K[]): Observable<Pick<T, K>>\n public watch<K extends keyof T>(keyOrKeys: K | K[]) {\n if (Array.isArray(keyOrKeys)) {\n return this.stateSubject.pipe(watchKeys(keyOrKeys))\n }\n return this.stateSubject.pipe(\n map((result) => result[keyOrKeys]),\n distinctUntilChanged(isShallowEqual),\n )\n }\n\n public get value() {\n return this.stateSubject.value\n }\n\n public destroy$ = this._destroy$.asObservable()\n\n public destroy() {\n this.stateSubject.complete()\n this._destroy$.complete()\n }\n}\n","import type { Manifest } from \"@prose-reader/shared\"\nimport {\n catchError,\n combineLatest,\n defer,\n EMPTY,\n endWith,\n filter,\n finalize,\n first,\n map,\n merge,\n mergeMap,\n Observable,\n of,\n Subject,\n share,\n switchMap,\n takeUntil,\n} from \"rxjs\"\nimport type { Context } from \"../../context/Context\"\nimport type { HookManager } from \"../../hooks/HookManager\"\nimport { Report } from \"../../report\"\nimport type { ReaderSettingsManager } from \"../../settings/ReaderSettingsManager\"\nimport { getFrameViewportInfo } from \"../../utils/frames\"\nimport { ReactiveEntity } from \"../../utils/ReactiveEntity\"\nimport { waitForSwitch } from \"../../utils/rxjs\"\nimport type { Viewport } from \"../../viewport/Viewport\"\nimport type { ResourceHandler } from \"../resources/ResourceHandler\"\n\nexport type DocumentRendererParams = {\n context: Context\n settings: ReaderSettingsManager\n hookManager: HookManager\n item: Manifest[`spineItems`][number]\n containerElement: HTMLElement\n resourcesHandler: ResourceHandler\n viewport: Viewport\n}\n\ntype LayoutParams = {\n minPageSpread: number\n blankPagePosition: `before` | `after` | `none`\n spreadPosition: `none` | `left` | `right`\n minimumWidth: number\n}\n\ntype DocumentRendererState =\n | {\n state: `error`\n error: unknown\n }\n | {\n state: `idle` | `loading` | `loaded` | `unloading`\n error: undefined\n }\n\nexport abstract class DocumentRenderer extends ReactiveEntity<DocumentRendererState> {\n static readonly DOCUMENT_CONTAINER_CLASS_NAME =\n `prose-reader-document-container`\n private triggerSubject = new Subject<{ type: `load` } | { type: `unload` }>()\n\n protected viewport: Viewport\n protected context: Context\n protected settings: ReaderSettingsManager\n protected hookManager: HookManager\n protected item: Manifest[`spineItems`][number]\n protected containerElement: HTMLElement\n protected resourcesHandler: ResourceHandler\n\n // protected unload$ = this.triggerSubject.pipe(\n // withLatestFrom(this.stateSubject),\n // filter(\n // ([trigger, state]) =>\n // trigger.type === `unload` && state.state !== \"idle\" && state.state !== \"unloading\",\n // ),\n // map(() => undefined),\n // share(),\n // )\n\n // protected load$ = this.triggerSubject.pipe(\n // withLatestFrom(this.stateSubject),\n // filter(\n // ([trigger, state]) =>\n // trigger.type === `load` && state.state !== \"loaded\" && state.state !== \"loading\",\n // ),\n // map(() => undefined),\n // share(),\n // )\n\n public loaded$: Observable<void>\n public unloaded$: Observable<void>\n\n private _documentContainer: HTMLElement | undefined\n\n constructor(params: {\n context: Context\n settings: ReaderSettingsManager\n hookManager: HookManager\n item: Manifest[`spineItems`][number]\n containerElement: HTMLElement\n resourcesHandler: ResourceHandler\n viewport: Viewport\n }) {\n super({\n state: `idle`,\n error: undefined,\n })\n\n this.context = params.context\n this.settings = params.settings\n this.hookManager = params.hookManager\n this.item = params.item\n this.containerElement = params.containerElement\n this.resourcesHandler = params.resourcesHandler\n this.viewport = params.viewport\n\n const unloadTrigger$ = this.triggerSubject.pipe(\n filter((trigger) => trigger.type === `unload`),\n )\n\n const loadTrigger$ = this.triggerSubject.pipe(\n filter((trigger) => trigger.type === `load`),\n )\n\n this.loaded$ = loadTrigger$.pipe(\n mergeMap(() => {\n const canBeIgnored =\n this.value.state === `loaded` || this.value.state === `loading`\n\n if (canBeIgnored) return EMPTY\n\n this.next({ state: `loading`, error: undefined })\n\n const createDocument$ = this.onCreateDocument().pipe(first())\n\n return createDocument$.pipe(\n mergeMap((documentContainer) => {\n this.hookManager.execute(`item.onDocumentCreated`, this.item.id, {\n itemId: this.item.id,\n documentContainer,\n })\n\n const loadDocument$ = this.onLoadDocument().pipe(\n endWith(null),\n first(),\n )\n\n return loadDocument$.pipe(\n waitForSwitch(this.context.bridgeEvent.viewportFree$),\n switchMap(() => {\n const hookResults = this.hookManager\n .execute(`item.onDocumentLoad`, this.item.id, {\n itemId: this.item.id,\n documentContainer,\n })\n .filter(\n (result): result is Observable<void> =>\n result instanceof Observable,\n )\n\n return combineLatest([of(null), ...hookResults]).pipe(first())\n }),\n )\n }),\n map(() => {\n this.next({ state: `loaded`, error: undefined })\n\n return undefined\n }),\n takeUntil(unloadTrigger$),\n )\n }),\n share(),\n )\n\n this.unloaded$ = unloadTrigger$.pipe(\n mergeMap(() => {\n const canBeIgnored =\n this.value.state === `unloading` || this.value.state === `idle`\n\n if (canBeIgnored) return EMPTY\n\n this.next({ state: `unloading`, error: undefined })\n\n return this.context.bridgeEvent.viewportFree$.pipe(\n first(),\n switchMap(() => {\n this.hookManager.destroy(`item.onDocumentLoad`, this.item.id)\n\n const onUnload$ = defer(() => this.onUnload()).pipe(\n endWith(null),\n first(),\n catchError((error) => {\n Report.error(`Error unloading document`, error)\n\n return of(null)\n }),\n )\n\n return onUnload$\n }),\n map(() => {\n this.next({ state: `idle`, error: undefined })\n\n return undefined\n }),\n takeUntil(loadTrigger$),\n )\n }),\n share(),\n )\n\n merge(this.loaded$, this.unloaded$)\n .pipe(\n catchError((error) => {\n this.next({ state: `error`, error })\n\n return EMPTY\n }),\n takeUntil(this.destroy$),\n )\n .subscribe()\n }\n\n protected setDocumentContainer(element: HTMLElement) {\n this._documentContainer = element\n this._documentContainer.classList.add(\n DocumentRenderer.DOCUMENT_CONTAINER_CLASS_NAME,\n )\n }\n\n protected attach() {\n if (this.documentContainer) {\n this.containerElement.appendChild(this.documentContainer)\n }\n }\n\n protected detach() {\n this._documentContainer?.remove()\n this._documentContainer = undefined\n }\n\n public get state$() {\n return this.stateSubject\n }\n\n public get isLoaded$() {\n return this.state$.pipe(map((state) => state.state === `loaded`))\n }\n\n public load() {\n this.triggerSubject.next({ type: `load` })\n }\n\n public unload() {\n this.triggerSubject.next({ type: `unload` })\n }\n\n /**\n * Automatically release on complete or error.\n */\n public renderHeadless(): Observable<\n { doc: Document; release: () => void } | undefined\n > {\n const releaseSubject = new Subject<void>()\n\n return defer(() => this.onRenderHeadless({ release: releaseSubject })).pipe(\n endWith(undefined),\n first(),\n map((doc) => {\n if (!doc) return undefined\n\n return {\n doc,\n release: () => {\n releaseSubject.next(undefined)\n },\n }\n }),\n finalize(() => {\n releaseSubject.complete()\n }),\n catchError((e) => {\n Report.error(e)\n\n return of(undefined)\n }),\n )\n }\n\n public layout(params: LayoutParams) {\n return this.onLayout(params)\n }\n\n public destroy() {\n this.unload()\n this.stateSubject.complete()\n\n super.destroy()\n }\n\n abstract onRenderHeadless(params: {\n release: Observable<void>\n }): Observable<Document | undefined>\n\n abstract onUnload(): Observable<unknown>\n\n /**\n * This lifecycle lets you fetch your resource and create the document.\n * You can fill the layers with your document(s). You can also preload or\n * load any resources that you need as well.\n *\n * @important Do not attach anything to the dom yet.\n */\n abstract onCreateDocument(): Observable<HTMLElement>\n\n /**\n * This lifecycle lets you load whatever you need once the document is attached to\n * the dom. Some operations can only be done at this stage (eg: loading iframe).\n *\n * @important By the end of your stream, the layers should be attached to the dom.\n */\n abstract onLoadDocument(): Observable<unknown>\n\n abstract onLayout(\n params: LayoutParams,\n ): Observable<{ width: number; height: number } | undefined>\n\n /**\n * Return the main document iframe.\n */\n abstract getDocumentFrame(): HTMLIFrameElement | undefined\n\n get documentContainer() {\n return this._documentContainer\n }\n\n get writingMode(): `vertical-rl` | `horizontal-tb` | undefined {\n return undefined\n }\n\n get readingDirection(): `rtl` | `ltr` | undefined {\n return undefined\n }\n\n get renditionLayout() {\n const itemRenditionLayout = this.item.renditionLayout\n\n if (itemRenditionLayout) return itemRenditionLayout\n\n const iframe = this.getDocumentFrame()\n\n if (iframe) {\n const { hasViewport } = getFrameViewportInfo(iframe)\n\n if (hasViewport) return \"pre-paginated\"\n }\n\n return this.context.manifest?.renditionLayout ?? \"reflowable\"\n }\n}\n","import type { Manifest } from \"@prose-reader/shared\"\nimport type { ReaderSettingsManager } from \"../../settings/ReaderSettingsManager\"\nimport { lastValueFrom, of } from \"rxjs\"\n\nconst defaultGetResource = (item: Manifest[\"items\"][0]) => new URL(item.href)\n\nexport class ResourceHandler {\n constructor(\n protected item: Manifest[\"items\"][number],\n protected settings: ReaderSettingsManager,\n ) {}\n\n public async getResource() {\n const resource = await lastValueFrom(\n this.settings.values.getResource?.(this.item) ?? of(undefined),\n )\n\n return resource ?? defaultGetResource(this.item)\n }\n\n public async fetchResource() {\n const resource = await this.getResource()\n\n if (resource instanceof Response) return resource\n\n if (resource instanceof URL) return fetch(resource)\n\n return resource\n }\n}\n","import { type Manifest, getParentPath } from \"@prose-reader/shared\"\nimport {\n Observable,\n combineLatest,\n from,\n map,\n mergeMap,\n of,\n switchMap,\n} from \"rxjs\"\nimport type { Context } from \"../../../context/Context\"\nimport type { ReaderSettingsManager } from \"../../../settings/ReaderSettingsManager\"\nimport { ResourceHandler } from \"../../../spineItem/resources/ResourceHandler\"\nimport { getElementsWithAssets, revokeDocumentBlobs } from \"../../../utils/dom\"\n\n/**\n * @important Firefox handles file protocol weirdly and will not\n * go up one directory when using \"../\". We temporarily replace to http://\n * to keep our behavior.\n */\nconst joinPath = (base: string, path: string) => {\n // Temporarily replace file:// with http:// for consistent URL handling\n const isFileProtocol = base.startsWith(\"file://\")\n const tempBase = isFileProtocol ? base.replace(\"file://\", \"http://\") : base\n const result = new URL(path, tempBase).toString()\n\n // Convert back to file:// if needed\n return isFileProtocol ? result.replace(\"http://\", \"file://\") : result\n}\n\nconst loadFontFaces = async (\n document: Document | null | undefined,\n element: HTMLLinkElement,\n spineItemUriParentPath: string,\n context: Context,\n settings: ReaderSettingsManager,\n): Promise<void> => {\n if (!document || !document.defaultView) return\n\n const sheet = element.sheet\n\n if (!sheet) return\n\n try {\n const rules = Array.from(sheet.cssRules || [])\n\n for (let i = 0; i < rules.length; i++) {\n const rule = rules[i]\n if (\n document.defaultView &&\n rule instanceof document.defaultView.CSSFontFaceRule\n ) {\n const src = rule.style.getPropertyValue(\"src\")\n const matches = src.match(/url\\(['\"]?([^'\"]+)['\"]?\\)/g)\n\n if (matches) {\n // Split the src value into individual sources\n const srcParts = src.split(\",\").map((part) => part.trim())\n\n const newSrcParts = await Promise.all(\n srcParts.map(async (part) => {\n // If it's a local() source, preserve it as-is\n if (part.startsWith(\"local(\")) {\n return part\n }\n\n // Extract URL and format parts\n const urlMatch = part.match(/url\\(['\"]?([^'\"]+)['\"]?\\)/)\n if (!urlMatch) return part\n\n const originalSrc = urlMatch[1] ?? ``\n\n // Find the font resource in the manifest\n const foundItem = context.manifest?.items.find(({ href }) => {\n return `${joinPath(spineItemUriParentPath, originalSrc).toLowerCase()}`.endsWith(\n `${href.toLowerCase()}`,\n )\n })\n\n if (foundItem) {\n const resourceHandler = new ResourceHandler(foundItem, settings)\n\n try {\n const resource = await resourceHandler.getResource()\n\n if (resource instanceof Response) {\n const blob = await resource.blob()\n const blobUrl =\n document.defaultView?.URL.createObjectURL(blob)\n\n // Reconstruct the source with the new blob URL and preserve format/tech\n const newPart = part.replace(\n urlMatch[0],\n `url(\"${blobUrl}\")`,\n )\n\n return newPart\n }\n } catch (e) {\n console.error(\"Error loading font:\", e)\n }\n }\n return part\n }),\n )\n\n // Instead of modifying the existing rule, create a new one\n // firefox will not allow to modify the existing rule\n // Get the complete rule text and replace the entire src declaration\n const newRule = rule.cssText.replace(\n /src:\\s*[^;]+;/,\n `src: ${newSrcParts.join(\", \")};`,\n )\n\n // Delete the old rule and insert the new one\n sheet.deleteRule(i)\n sheet.insertRule(newRule, i)\n }\n }\n }\n } catch (e) {\n console.error(\"Could not access stylesheet rules:\", e)\n }\n}\n\nconst loadElementSrc = (\n _document: Document | null | undefined,\n element: Element,\n spineItemUriParentPath: string,\n context: Context,\n settings: ReaderSettingsManager,\n) => {\n const originalSrc =\n element.getAttribute(\"src\") || element.getAttribute(\"href\")\n\n if (!originalSrc) return of(null)\n\n // EPUB/image.png needs to match frame relative src /image.png\n const foundItem = context.manifest?.items.find(({ href }) => {\n // this will remove things like \"../..\" and have a normal relative path\n return `${joinPath(spineItemUriParentPath, originalSrc).toLowerCase()}`.endsWith(\n `${href.toLowerCase()}`,\n )\n })\n\n if (!foundItem) return of(null)\n\n const resourceHandler = new ResourceHandler(foundItem, settings)\n\n /**\n * For each resources, if it's a response and not a URL, we should convert it to a blob\n * because it will not be accessible otherwise.\n */\n return from(resourceHandler.getResource()).pipe(\n mergeMap((resource) =>\n resource instanceof Response ? from(resource.blob()) : of(undefined),\n ),\n mergeMap((blob) => {\n if (!blob) {\n return of(null)\n }\n\n const blobUrl = _document?.defaultView?.URL.createObjectURL(blob) ?? ``\n\n if (element.hasAttribute(\"src\")) {\n element.setAttribute(\"src\", blobUrl)\n } else if (element.hasAttribute(\"href\")) {\n element.setAttribute(\"href\", blobUrl)\n\n if (\n _document?.defaultView &&\n element instanceof _document.defaultView.HTMLLinkElement\n ) {\n return new Observable<void>((observer) => {\n element.onload = async () => {\n try {\n // Now that the stylesheet is loaded, replace font URLs\n // we cannot do that before because the stylesheet is not loaded\n // and we would not have access to it.\n if (element.sheet) {\n await loadFontFaces(\n _document,\n element,\n spineItemUriParentPath,\n context,\n settings,\n )\n }\n observer.next()\n observer.complete()\n } catch (error) {\n observer.error(error)\n }\n }\n element.onerror = observer.error\n })\n }\n }\n\n return of(null)\n }),\n )\n}\n\nexport const loadAssets =\n ({\n settings,\n item,\n context,\n }: {\n settings: ReaderSettingsManager\n item: Manifest[\"items\"][number]\n context: Context\n }) =>\n (stream: Observable<HTMLIFrameElement>) =>\n stream.pipe(\n switchMap((frameElement) => {\n const elementsWithAsset = getElementsWithAssets(\n frameElement.contentDocument,\n )\n\n const spineItemUriParentPath = getParentPath(item.href)\n\n const assetsLoad$ = elementsWithAsset.map((element) =>\n loadElementSrc(\n frameElement.contentDocument,\n element,\n spineItemUriParentPath,\n context,\n settings,\n ),\n )\n\n return combineLatest(assetsLoad$).pipe(map(() => frameElement))\n }),\n )\n\nexport const unloadAssets = (frameElement?: HTMLIFrameElement) => {\n revokeDocumentBlobs(frameElement?.contentDocument)\n}\n","export const PROSE_READER_NAMESPACE = `@prose-reader/core`\nexport const VIEWPORT_ADJUSTMENT_THROTTLE = 0\nexport const PAGINATION_UPDATE_AFTER_VIEWPORT_ADJUSTMENT_DEBOUNCE = 200\nexport const ITEM_EXTENSION_VALID_FOR_FRAME_SRC = [`.xhtml`, `.html`, `.htm`]\nexport const HTML_PREFIX = `prose-reader`\nexport const HTML_STYLE_PREFIX = `${HTML_PREFIX}-style`\nexport const HTML_ATTRIBUTE_DATA_READER_ID = `data-${HTML_PREFIX}-id`\nexport const HTML_PREFIX_VIEWPORT = `${HTML_PREFIX}-viewport`\nexport const HTML_PREFIX_SCROLL_NAVIGATOR = `${HTML_PREFIX}-scroll-navigator`\n","import { detectMimeTypeFromName, parseContentType } from \"@prose-reader/shared\"\nimport type { Manifest } from \"../../..\"\n\n/**\n * Document is application/xhtml+xml\n * @todo move this into a enhancer\n * @todo only keep a very basic default one which just put the resource as <media> inside html page\n * @todo use the core default one as last resort if the pipe does not return an html document\n */\nexport const createHtmlPageFromResource = async (\n resourceResponse: Response | string,\n item: Manifest[`spineItems`][number],\n) => {\n if (typeof resourceResponse === \"string\") return resourceResponse\n\n const contentType =\n parseContentType(resourceResponse.headers.get(`Content-Type`) || ``) ||\n detectMimeTypeFromName(item.href)\n\n if (\n [`image/jpg`, `image/jpeg`, `image/png`, `image/webp`].some(\n (mime) => mime === contentType,\n )\n ) {\n const blob = await resourceResponse.blob()\n const objectUrl = URL.createObjectURL(blob)\n const bitmap = await createImageBitmap(blob)\n const { width, height } = { width: bitmap.width, height: bitmap.height }\n bitmap.close()\n\n return `\n <html>\n <head>\n ${item.renditionLayout === `pre-paginated` ? `<meta name=\"viewport\" content=\"width=${width}, height=${height}\">` : ``}\n </head>\n <body style=\"margin: 0px;\" tab-index=\"-1;\">\n <img\n src=\"${objectUrl}\"\n style=\"max-width: 100%;height:100%;object-fit:contain;\"\n >\n </body>\n </html>\n `\n }\n\n if ([`text/plain`].some((mime) => mime === contentType)) {\n const data = await resourceResponse.text()\n\n return `\n <!DOCTYPE html>\n <html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:epub=\"http://www.idpf.org/2007/ops\" xml:lang=\"en\" lang=\"en\">\n <head>\n <style>\n pre {\n white-space: pre;\n white-space: pre-wrap;\n word-wrap: break-word;\n }\n </style>\n </head>\n <body>\n <pre>${data}</pre>\n </body>\n </html>\n `\n }\n\n const content = await resourceResponse.text()\n\n return content\n}\n","import type { Manifest } from \"@prose-reader/shared\"\nimport {\n type Observable,\n catchError,\n from,\n map,\n of,\n switchMap,\n tap,\n} from \"rxjs\"\nimport { ITEM_EXTENSION_VALID_FOR_FRAME_SRC } from \"../../../constants\"\nimport { Report } from \"../../../report\"\nimport type { ReaderSettingsManager } from \"../../../settings/ReaderSettingsManager\"\nimport type { ResourceHandler } from \"../../../spineItem/resources/ResourceHandler\"\nimport { createHtmlPageFromResource } from \"./createHtmlPageFromResource\"\n\nexport const attachFrameSrc = ({\n item,\n resourcesHandler,\n}: {\n settings: ReaderSettingsManager\n item: Manifest[`spineItems`][number]\n resourcesHandler: ResourceHandler\n}) => {\n const getHtmlFromResource = (response: Response) =>\n createHtmlPageFromResource(response, item)\n\n return (stream: Observable<HTMLIFrameElement>) =>\n stream.pipe(\n switchMap((frameElement) => {\n return from(resourcesHandler.getResource()).pipe(\n switchMap((resource) => {\n /**\n * Because of the bug with iframe and sw, we should not use srcdoc and sw together for\n * html document. This is because resources will not pass through SW. IF `fetchResource` is being\n * used the user should be aware of the limitation. We use srcdoc for everything except if we detect\n * an html document and same origin. Hopefully that bug gets fixed one day.\n * @see https://bugs.chromium.org/p/chromium/issues/detail?id=880768\n */\n if (\n resource instanceof URL &&\n item.href.startsWith(window.location.origin) &&\n // we have an encoding and it's a valid html\n ((item.mediaType &&\n [\n `application/xhtml+xml`,\n `application/xml`,\n `text/html`,\n `text/xml`,\n ].includes(item.mediaType)) ||\n // no encoding ? then try to detect html\n (!item.mediaType &&\n ITEM_EXTENSION_VALID_FOR_FRAME_SRC.some((extension) =>\n item.href.endsWith(extension),\n )))\n ) {\n frameElement?.setAttribute(`src`, item.href)\n\n return of(frameElement)\n }\n\n const resourceResponse$ =\n resource instanceof URL\n ? from(resourcesHandler.fetchResource())\n : of(resource)\n\n return resourceResponse$.pipe(\n switchMap((response) => {\n if (!(response instanceof Response)) {\n throw new Error(`Invalid resource`)\n }\n\n return from(getHtmlFromResource(response))\n }),\n tap((htmlDoc) => {\n if (htmlDoc) {\n const blob = new Blob([htmlDoc], { type: \"text/html\" })\n /**\n * The blob will be released once the document is destroyed.\n * No need to deal with it ourselves.\n */\n const blobURL = URL.createObjectURL(blob)\n\n frameElement?.setAttribute(`src`, blobURL)\n }\n }),\n map(() => frameElement),\n catchError((e) => {\n Report.error(\n `Error while trying to fetch or load resource for item ${item.id}`,\n resource,\n )\n Report.error(e)\n\n return of(frameElement)\n }),\n )\n }),\n )\n }),\n )\n}\n","export const createFrameElement = () => {\n // we force undefined because otherwise the load method will believe it's defined after this call but the code is async and\n // the iframe could be undefined later\n const frame = document.createElement(`iframe`)\n frame.frameBorder = `no`\n frame.tabIndex = 0\n frame.setAttribute(\n `sandbox`,\n `\n allow-same-origin \n allow-scripts \n allow-top-navigation-to-custom-protocols\n`,\n )\n frame.style.cssText = `\n overflow: hidden;\n background-color: transparent;\n border: 0px none transparent;\n padding: 0px;\n`\n\n frame.setAttribute(`role`, `main`)\n\n return frame\n}\n","import { getFrameViewportInfo } from \"../../../../utils/frames\"\n\nexport const getViewPortInformation = ({\n pageHeight,\n pageWidth,\n frameElement,\n}: {\n pageWidth: number\n pageHeight: number\n frameElement: HTMLIFrameElement\n}) => {\n const viewportDimensions = getFrameViewportInfo(frameElement)\n\n if (\n frameElement?.contentDocument &&\n frameElement.contentWindow &&\n viewportDimensions\n ) {\n const computedWidthScale = pageWidth / (viewportDimensions.width ?? 1)\n const computedScale = Math.min(\n computedWidthScale,\n pageHeight / (viewportDimensions.height ?? 1),\n )\n\n return { computedScale, computedWidthScale, viewportDimensions }\n }\n}\n\n/**\n * Upward layout is used when the parent wants to manipulate the iframe without triggering\n * `layout` event. This is a particular case needed for iframe because the parent can layout following\n * an iframe `layout` event. Because the parent `layout` may change some of iframe properties we do not\n * want the iframe to trigger a new `layout` even and have infinite loop.\n */\nconst staticLayout = (\n frameElement: HTMLIFrameElement,\n size: { width: number; height: number },\n) => {\n frameElement.style.width = `${size.width}px`\n frameElement.style.height = `${size.height}px`\n}\n\nexport const renderPrePaginated = ({\n minPageSpread,\n blankPagePosition,\n spreadPosition,\n pageHeight,\n pageWidth,\n frameElement,\n isRTL,\n}: {\n minPageSpread: number\n blankPagePosition: `before` | `after` | `none`\n spreadPosition: `none` | `left` | `right`\n pageWidth: number\n pageHeight: number\n frameElement?: HTMLIFrameElement\n isRTL: boolean\n}) => {\n const minimumWidth = minPageSpread * pageWidth\n\n if (frameElement?.contentDocument && frameElement?.contentWindow) {\n const { viewportDimensions, computedScale = 1 } =\n getViewPortInformation({ frameElement, pageHeight, pageWidth }) ?? {}\n const hasViewportDimensions = !!viewportDimensions\n const contentWidth = pageWidth\n const contentHeight = pageHeight\n\n if (frameElement.contentDocument?.documentElement) {\n frameElement.contentDocument?.documentElement.setAttribute(\n `data-prose-reader-html-renderer-has-viewport-dimensions`,\n hasViewportDimensions.toString(),\n )\n }\n // frameElement?.style.setProperty(`visibility`, `visible`)\n // frameElement?.style.setProperty(`opacity`, `1`)\n\n if (viewportDimensions) {\n staticLayout(frameElement, {\n width: viewportDimensions.width ?? 1,\n height: viewportDimensions.height ?? 1,\n })\n } else {\n staticLayout(frameElement, {\n width: contentWidth,\n height: contentHeight,\n })\n }\n\n if (viewportDimensions) {\n frameElement?.style.setProperty(`position`, `absolute`)\n frameElement?.style.setProperty(`top`, `50%`)\n\n if (spreadPosition === `left`) {\n frameElement?.style.setProperty(`right`, `0`)\n frameElement?.style.removeProperty(`left`)\n } else if (blankPagePosition === `before` && isRTL) {\n frameElement?.style.setProperty(`right`, `50%`)\n frameElement?.style.removeProperty(`left`)\n } else if (spreadPosition === `right`) {\n frameElement?.style.setProperty(`left`, `0`)\n frameElement?.style.removeProperty(`right`)\n } else {\n frameElement?.style.setProperty(\n `left`,\n blankPagePosition === `before`\n ? isRTL\n ? `25%`\n : `75%`\n : blankPagePosition === `after`\n ? isRTL\n ? `75%`\n : `25%`\n : `50%`,\n )\n frameElement?.style.removeProperty(`right`)\n }\n const transformTranslateX = spreadPosition !== `none` ? `0` : `-50%`\n const transformOriginX =\n spreadPosition === `right` && blankPagePosition !== `before`\n ? `left`\n : spreadPosition === `left` ||\n (blankPagePosition === `before` && isRTL)\n ? `right`\n : `center`\n frameElement?.style.setProperty(\n `transform`,\n `translate(${transformTranslateX}, -50%) scale(${computedScale})`,\n )\n frameElement?.style.setProperty(\n `transform-origin`,\n `${transformOriginX} center`,\n )\n } else {\n if (blankPagePosition === `before`) {\n if (isRTL) {\n frameElement?.style.setProperty(`margin-right`, `${pageWidth}px`)\n } else {\n frameElement?.style.setProperty(`margin-left`, `${pageWidth}px`)\n }\n } else {\n frameElement?.style.removeProperty(`margin-left`)\n frameElement?.style.removeProperty(`margin-right`)\n }\n }\n\n return { width: minimumWidth, height: contentHeight }\n }\n\n return { width: minimumWidth, height: pageHeight }\n}\n","/**\n * Item is:\n * - anything that contains a defined width/height viewport\n *\n * In this case we respect the viewport, scale it and act as pre-paginated.\n *\n * Using a viewport means the page should fit and be displayed as it is. This\n * is one of the reason of using viewport.\n *\n * Ideally we should not touch too much of how things are presented, especially\n * images since this mode would be most often used for it.\n *\n * Changing text display needs to be done carefully as well since it may overflow\n * Again this is because the page is designed to fit perfectly due to viewport\n */\nexport const buildStyleForViewportFrame = () => {\n return `\n body {\n margin: 0;\n }\n html {\n width: 100%;\n height: 100%;\n }\n body {\n width: 100%;\n height: 100%;\n margin: 0;\n }\n ${\n /*\n * @see https://hammerjs.github.io/touch-action/\n */\n ``\n }\n html, body {\n touch-action: none;\n }\n `\n}\n\n/**\n * Item is:\n * - not pre-paginated (we would not be in this item otherwise)\n * - jpg, png, etc\n *\n * It does not means it has to be pre-paginated (scrollable for example)\n */\nexport const buildStyleForReflowableImageOnly = ({\n isScrollable,\n enableTouch,\n}: {\n enableTouch: boolean\n isScrollable: boolean\n}) => {\n return `\n ${\n /*\n * @see https://hammerjs.github.io/touch-action/\n */\n ``\n }\n html, body {\n width: 100%;\n margin: 0;\n padding: 0;\n ${\n !enableTouch\n ? `\n touch-action: none\n `\n : ``\n }\n }\n ${\n isScrollable\n ? `\n img {\n height: auto !important;\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n ${\n // we make sure img spread on entire screen\n ``\n }\n width: 100%;\n ${\n /**\n * line break issue\n * @see https://stackoverflow.com/questions/37869020/image-not-taking-up-the-full-height-of-container\n */\n ``\n }\n display: block;\n }\n `\n : ``\n }\n `\n}\n\n/**\n * Item is:\n * - regular html document\n * - does not contain defined width/height viewport\n *\n * We use css multi column to paginate it\n *\n * @important\n * The style here does not takes margin into account, we assume everything is 0.\n * It is being handled by enhancer.\n */\nexport const buildStyleWithMultiColumn = ({\n width,\n columnHeight,\n columnWidth,\n}: {\n width: number\n columnWidth: number\n columnHeight: number\n}) => {\n return `\n parsererror {\n display: none !important;\n }\n ${\n /*\n might be html * but it does mess up things like figure if so.\n check accessible_epub_3\n */ ``\n }\n html, body {\n margin: 0;\n padding: 0 !important;\n -max-width: ${columnWidth}px !important;\n }\n ${\n /*\n body {\n height: ${columnHeight}px !important;\n width: ${columnWidth}px !important;\n -margin-left: ${horizontalMargin}px !important;\n -margin-right: ${horizontalMargin}px !important;\n -margin: ${verticalMargin}px ${horizontalMargin}px !important;\n -padding-top: ${horizontalMargin}px !important;\n -padding-bottom: ${horizontalMargin}px !important;\n }\n */ ``\n }\n body {\n padding: 0 !important;\n width: ${width}px !important;\n height: ${columnHeight}px !important;\n overflow-y: hidden;\n column-gap: 0px !important;\n column-width: ${columnWidth}px !important;\n column-fill: auto !important;\n word-wrap: break-word;\n box-sizing: border-box;\n }\n body {\n margin: 0;\n }\n body:focus-visible {\n ${\n /*\n we make sure that there are no outline when we focus something inside the iframe\n */ ``\n }\n outline: none;\n }\n ${\n /*\n * @see https://hammerjs.github.io/touch-action/\n */\n ``\n }\n html, body {\n touch-action: none;\n }\n ${\n /*\n this messes up hard, be careful with this\n */ ``\n }\n * {\n -max-width: ${columnWidth}px !important;\n }\n ${\n /*\n this is necessary to have a proper calculation when determining size\n of iframe content. If an img is using something like width:100% it would expand to\n the size of the original image and potentially gives back a wrong size (much larger)\n @see https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Columns/Handling_Overflow_in_Multicol\n */ ``\n }\n img, video, audio, object, svg {\n max-width: 100%;\n -max-width: ${columnWidth}px !important;\n -max-height: ${columnHeight}px !important;\n -pointer-events: none;\n -webkit-column-break-inside: avoid;\n page-break-inside: avoid;\n break-inside: avoid;\n }\n figure {\n d-max-width: ${columnWidth}px !important;\n }\n img {\n object-fit: contain;\n break-inside: avoid;\n box-sizing: border-box;\n d-max-width: ${columnWidth}px !important;\n }\n ${\n /*\n img, video, audio, object, svg {\n max-height: ${columnHeight}px !important;\n box-sizing: border-box;\n object-fit: contain;\n -webkit-column-break-inside: avoid;\n page-break-inside: avoid;\n break-inside: avoid;\n }\n */ ``\n }\n table {\n max-width: ${columnWidth}px !important;\n table-layout: fixed;\n }\n td {\n max-width: ${columnWidth}px;\n }\n `\n}\n","import type { Manifest } from \"@prose-reader/shared\"\nimport { upsertCSSToFrame } from \"../../../../utils/frames\"\nimport { getViewPortInformation } from \"../prePaginated/renderPrePaginated\"\nimport {\n buildStyleForReflowableImageOnly,\n buildStyleForViewportFrame,\n buildStyleWithMultiColumn,\n} from \"./styles\"\n\nconst getDimensionsForReflowableContent = ({\n isUsingVerticalWriting,\n minimumWidth,\n pageHeight,\n pageWidth,\n}: {\n isUsingVerticalWriting: boolean\n minimumWidth: number\n pageWidth: number\n pageHeight: number\n}) => {\n const horizontalMargin = 0\n const verticalMargin = 0\n let columnWidth = pageWidth - horizontalMargin * 2\n const columnHeight = pageHeight - verticalMargin * 2\n let width = pageWidth - horizontalMargin * 2\n\n if (isUsingVerticalWriting) {\n width = minimumWidth - horizontalMargin * 2\n columnWidth = columnHeight\n }\n\n return {\n columnHeight,\n columnWidth,\n width,\n }\n}\n\n/**\n * Upward layout is used when the parent wants to manipulate the iframe without triggering\n * `layout` event. This is a particular case needed for iframe because the parent can layout following\n * an iframe `layout` event. Because the parent `layout` may change some of iframe properties we do not\n * want the iframe to trigger a new `layout` even and have infinite loop.\n */\nconst staticLayout = (\n frameElement: HTMLIFrameElement,\n size: { width: number; height: number },\n) => {\n frameElement.style.width = `${size.width}px`\n frameElement.style.height = `${size.height}px`\n}\n\nexport const renderReflowable = ({\n pageHeight: pageSizeHeight,\n pageWidth,\n frameElement,\n manifest,\n minPageSpread,\n isRTL,\n blankPagePosition,\n isImageType,\n enableTouch,\n isUsingVerticalWriting,\n}: {\n blankPagePosition: `before` | `after` | `none`\n pageWidth: number\n pageHeight: number\n frameElement: HTMLIFrameElement\n manifest?: Manifest\n minPageSpread: number\n isRTL: boolean\n isImageType: boolean\n enableTouch: boolean\n isUsingVerticalWriting: boolean\n}) => {\n const minimumWidth = minPageSpread * pageWidth\n const continuousScrollableReflowableItem =\n manifest?.renditionLayout === \"reflowable\" &&\n manifest?.renditionFlow === \"scrolled-continuous\"\n\n /**\n * In case of reflowable with continuous scrolling, we don't know if the content is\n * bigger or smaller than the page size, therefore we find a middle ground to have\n * a pre-load page that is not too big nor too small to prevent weird jumping\n * once the frame load.\n *\n * We also use a minimum height still because we don't want all of the items to\n * preload since they would be in the current viewport.\n *\n * @todo make it a setting\n */\n const pageHeight = continuousScrollableReflowableItem\n ? Math.min(400, pageSizeHeight)\n : pageSizeHeight\n\n // reset width of iframe to be able to retrieve real size later\n frameElement?.style.setProperty(`width`, `${pageWidth}px`)\n\n /**\n * In case of reflowable with continuous scrolling, we let the frame takes whatever height\n * it needs since it could be less or more than page size and we want a continuous reading\n */\n if (!continuousScrollableReflowableItem) {\n frameElement?.style.setProperty(`height`, `${pageHeight}px`)\n } else {\n frameElement?.style.removeProperty(`height`)\n }\n\n const { viewportDimensions, computedScale = 1 } =\n getViewPortInformation({\n frameElement,\n pageHeight,\n pageWidth,\n }) ?? {}\n const isGloballyPrePaginated = manifest?.renditionLayout === `pre-paginated`\n\n // @todo simplify ? should be from common spine item\n if (\n frameElement?.contentDocument &&\n frameElement?.contentWindow &&\n frameElement.contentDocument.body\n ) {\n let contentWidth = pageWidth\n let contentHeight = pageHeight\n\n if (viewportDimensions?.hasViewport) {\n upsertCSSToFrame(\n frameElement,\n `prose-reader-html-renderer-framce-css`,\n buildStyleForViewportFrame(),\n )\n\n staticLayout(frameElement, {\n width: viewportDimensions.width ?? 1,\n height: viewportDimensions.height ?? 1,\n })\n\n frameElement?.style.setProperty(`position`, `absolute`)\n frameElement?.style.setProperty(`top`, `50%`)\n frameElement?.style.setProperty(\n `left`,\n blankPagePosition === `before`\n ? isRTL\n ? `25%`\n : `75%`\n : blankPagePosition === `after`\n ? isRTL\n ? `75%`\n : `25%`\n : `50%`,\n )\n\n frameElement?.style.setProperty(\n `transform`,\n `translate(-50%, -50%) scale(${computedScale})`,\n )\n frameElement?.style.setProperty(`transform-origin`, `center center`)\n } else {\n const frameStyle = isImageType\n ? buildStyleForReflowableImageOnly({\n isScrollable: manifest?.renditionFlow === `scrolled-continuous`,\n enableTouch,\n })\n : buildStyleWithMultiColumn(\n getDimensionsForReflowableContent({\n isUsingVerticalWriting: isUsingVerticalWriting,\n minimumWidth,\n pageHeight,\n pageWidth,\n }),\n )\n\n upsertCSSToFrame(frameElement, `prose-reader-css`, frameStyle, true)\n\n if (isUsingVerticalWriting) {\n const pages = Math.ceil(\n frameElement.contentDocument.documentElement.scrollHeight /\n pageHeight,\n )\n contentHeight = pages * pageHeight\n\n staticLayout(frameElement, {\n width: minimumWidth,\n height: contentHeight,\n })\n } else if (manifest?.renditionFlow === `scrolled-continuous`) {\n /**\n * We take body content here because the frame body might be smaller after\n * layout due to possible image content and image ratio. We need to be able\n * to retrieve the actual real body height. The window height is probably the same\n * as the current frame set height which may be wrong after resize.\n */\n contentHeight = frameElement.contentDocument.body.scrollHeight\n\n staticLayout(frameElement, {\n width: minimumWidth,\n height: contentHeight,\n })\n } else {\n const pages = Math.ceil(\n frameElement.contentDocument.documentElement.scrollWidth / pageWidth,\n )\n /**\n * It is possible that a pre-paginated epub has reflowable item inside it. This is weird because\n * the spec says that we should use pre-paginated for each spine item. Could be a publisher mistake, in\n * any case we follow the spec and enforce the iframe to be contained within page width.\n * If we don't respect the spec we end up with dynamic pagination for a fixed document, which can update\n * the correct number of pages when item is loaded/unload. Bringing weird user experience.\n * The publisher should use global reflowable with pre-paginated content instead.\n */\n if (isGloballyPrePaginated) {\n contentWidth = pageWidth\n } else {\n contentWidth = pages * pageWidth\n }\n\n staticLayout(frameElement, {\n width: contentWidth,\n height: contentHeight,\n })\n }\n }\n\n const isFillingAllScreen = contentWidth % minimumWidth === 0\n\n // when a reflow iframe does not fill the entire screen (when spread) we will\n // enlarge the container to make sure no other reflow item starts on the same screen\n if (!isFillingAllScreen) {\n contentWidth = contentWidth + pageWidth\n if (isRTL && !isUsingVerticalWriting) {\n frameElement?.style.setProperty(`margin-left`, `${pageWidth}px`)\n }\n } else {\n frameElement?.style.setProperty(`margin-left`, `0px`)\n }\n\n return { width: contentWidth, height: contentHeight }\n }\n\n return undefined\n}\n","import { detectMimeTypeFromName } from \"@prose-reader/shared\"\nimport { EMPTY, from, map, of, switchMap, tap } from \"rxjs\"\nimport { DocumentRenderer } from \"../../../spineItem/renderer/DocumentRenderer\"\nimport {\n upsertCSSToFrame,\n waitForFrameLoad,\n waitForFrameReady,\n} from \"../../../utils/frames\"\nimport { waitForSwitch } from \"../../../utils/rxjs\"\nimport { loadAssets, unloadAssets } from \"./assets\"\nimport { attachFrameSrc } from \"./attachFrameSrc\"\nimport { createFrameElement } from \"./createFrameElement\"\nimport prePaginatedStyle from \"./prePaginated/pre-paginated.css?inline\"\nimport { renderPrePaginated } from \"./prePaginated/renderPrePaginated\"\n// import reflowableImageStyle from \"./reflowable/reflowable-image.css?inline\"\nimport { renderReflowable } from \"./reflowable/renderReflowable\"\nexport class HtmlRenderer extends DocumentRenderer {\n onCreateDocument() {\n const frameElement = createFrameElement()\n\n this.setDocumentContainer(frameElement)\n\n return of(frameElement)\n }\n\n onLoadDocument() {\n const frameElement = this.getFrameElement()\n\n if (!frameElement) throw new Error(`invalid frame`)\n\n return of(frameElement).pipe(\n attachFrameSrc({\n item: this.item,\n resourcesHandler: this.resourcesHandler,\n settings: this.settings,\n }),\n waitForSwitch(this.context.bridgeEvent.viewportFree$),\n tap(() => {\n this.attach()\n }),\n waitForFrameLoad,\n tap((frameElement) => {\n if (this.isPrePaginated()) {\n upsertCSSToFrame(frameElement, `prose-reader-css`, prePaginatedStyle)\n } else {\n if (this.isImageType()) {\n // upsertCSSToFrame(\n // frameElement,\n // `prose-reader-css`,\n // reflowableImageStyle,\n // )\n } else {\n // upsertCSSToFrame(frameElement, `prose-reader-css`, reflowableStyle)\n }\n }\n }),\n loadAssets({\n context: this.context,\n item: this.item,\n settings: this.settings,\n }),\n waitForFrameReady,\n )\n }\n\n onUnload() {\n unloadAssets(this.getFrameElement())\n\n this.detach()\n\n return EMPTY\n }\n\n onLayout({\n minPageSpread,\n blankPagePosition,\n spreadPosition,\n }: {\n minPageSpread: number\n blankPagePosition: `before` | `after` | `none`\n spreadPosition: `none` | `left` | `right`\n }) {\n const { width: pageWidth, height: pageHeight } = this.viewport.pageSize\n const frameElement = this.getFrameElement()\n\n if (!frameElement) return of(undefined)\n\n const isUsingVerticalWriting = !!this.writingMode?.startsWith(`vertical`)\n\n /**\n * When we have scrollable content, we use \"native\" touch event from the frame instead of\n * our own gestures.\n * @todo move this into scroll navigator\n */\n const isTouchEnabled =\n this.settings.values.computedPageTurnMode === `scrollable`\n\n if (frameElement.contentDocument?.documentElement) {\n frameElement.contentDocument?.documentElement.setAttribute(\n `data-prose-reader-html-renderer-spread-position`,\n spreadPosition,\n )\n if (isTouchEnabled) {\n frameElement.contentDocument?.documentElement.classList.add(\n `prose-reader-html-renderer-touch-enabled`,\n )\n } else {\n frameElement.contentDocument?.documentElement.classList.remove(\n `prose-reader-html-renderer-touch-enabled`,\n )\n }\n }\n\n if (this.isPrePaginated()) {\n const dims = renderPrePaginated({\n blankPagePosition,\n frameElement,\n isRTL: this.context.isRTL(),\n minPageSpread,\n pageHeight,\n pageWidth,\n spreadPosition,\n })\n\n return of(dims)\n }\n\n const dims = renderReflowable({\n pageHeight,\n pageWidth,\n frameElement,\n manifest: this.context.manifest,\n blankPagePosition,\n isUsingVerticalWriting,\n isRTL: this.context.isRTL(),\n minPageSpread,\n isImageType: this.isImageType(),\n /**\n * When we have scrollable content, we use \"native\" touch event from the frame instead of\n * our own gestures.\n * @todo move this into scroll navigator\n */\n enableTouch: this.settings.values.computedPageTurnMode === `scrollable`,\n })\n\n return of(dims)\n }\n\n onRenderHeadless() {\n return from(this.resourcesHandler.fetchResource()).pipe(\n switchMap((resource) => {\n if (resource instanceof Response) {\n const contentType = resource.headers.get(\"content-type\") ?? \"\"\n const parsableContentTypes: DOMParserSupportedType[] = [\n `application/xhtml+xml`,\n `application/xml`,\n `text/html`,\n `text/xml`,\n ]\n\n if (\n parsableContentTypes.includes(contentType as DOMParserSupportedType)\n ) {\n return from(resource.text()).pipe(\n map((text) => {\n const domParser = new DOMParser()\n const doc = domParser.parseFromString(\n text,\n contentType as DOMParserSupportedType,\n )\n\n return doc\n }),\n )\n }\n }\n\n return of(undefined)\n }),\n )\n }\n\n private isPrePaginated = () => {\n return (\n this.item.renditionLayout === `pre-paginated` ||\n (!this.item.renditionLayout &&\n this.context.manifest?.renditionLayout === `pre-paginated`)\n )\n }\n\n private isImageType = () => {\n const mimeType =\n this.item.mediaType ?? detectMimeTypeFromName(this.item.href)\n\n return !!mimeType?.startsWith(`image/`)\n }\n\n private getFrameElement() {\n const frame = this.documentContainer\n\n if (!(frame instanceof HTMLIFrameElement)) return\n\n return frame\n }\n\n // @todo optimize\n public getComputedStyleAfterLoad() {\n const frame = this.getFrameElement()\n\n const body = frame?.contentDocument?.body\n\n if (body) {\n return frame?.contentWindow?.getComputedStyle(body)\n }\n }\n\n get writingMode() {\n return this.getComputedStyleAfterLoad()?.writingMode as\n | `vertical-rl`\n | `horizontal-tb`\n | undefined\n }\n\n get readingDirection() {\n const writingMode = this.writingMode\n\n if (writingMode === `vertical-rl`) {\n return `rtl`\n }\n\n const direction = this.getComputedStyleAfterLoad()?.direction\n\n switch (direction) {\n case `ltr`:\n case `inherit`:\n case `initial`: {\n return `ltr`\n }\n\n case `rtl`:\n return `rtl`\n\n default:\n return undefined\n }\n }\n\n getDocumentFrame() {\n return this.getFrameElement()\n }\n}\n","import { takeUntil } from \"rxjs\"\nimport type {\n EnhancerOptions,\n EnhancerOutput,\n RootEnhancer,\n} from \"../types/enhancer\"\nimport { handleLinks } from \"./links\"\nimport { HtmlRenderer } from \"./renderer/HtmlRenderer\"\n\ntype HandleLinksReturnType = ReturnType<typeof handleLinks>\n\nexport type HtmlEnhancerOutput = {\n links$: HandleLinksReturnType\n}\n\nexport const htmlEnhancer =\n <\n InheritOptions extends EnhancerOptions<RootEnhancer>,\n InheritOutput extends EnhancerOutput<RootEnhancer>,\n >(\n next: (options: InheritOptions) => InheritOutput,\n ) =>\n (\n options: InheritOptions,\n ): InheritOutput & {\n links$: HandleLinksReturnType\n } => {\n const reader = next({\n ...options,\n getRenderer(item) {\n const maybeFactory = options.getRenderer?.(item)\n\n return maybeFactory ?? ((props) => new HtmlRenderer(props))\n },\n })\n\n const links$ = handleLinks(reader)\n\n links$.pipe(takeUntil(reader.$.destroy$)).subscribe()\n\n return {\n ...reader,\n links$,\n }\n }\n","export function isDefined<T>(\n arg: T | null | undefined,\n): arg is T extends null | undefined ? never : T {\n return arg !== null && arg !== undefined\n}\n","export class LayoutEntry {\n public readonly left: number\n public readonly right: number\n public readonly top: number\n public readonly bottom: number\n public readonly width: number\n public readonly height: number\n public readonly x: number\n public readonly y: number\n\n constructor(layout: {\n left: number\n right: number\n top: number\n bottom: number\n width: number\n height: number\n x: number\n y: number\n }) {\n this.left = layout.left\n this.right = layout.right\n this.top = layout.top\n this.bottom = layout.bottom\n this.width = layout.width\n this.height = layout.height\n this.x = layout.x\n this.y = layout.y\n }\n}\n\nexport class SpineItemPosition {\n public readonly x: number\n public readonly y: number\n public readonly __symbol = Symbol(`SpineItemPosition`)\n\n constructor(position: { x: number; y: number }) {\n this.x = position.x\n this.y = position.y\n }\n}\n\n/**\n * Allow out of bounds positions\n */\nexport class UnboundSpineItemPagePosition {\n public readonly x: number\n public readonly y: number\n public readonly __symbol = Symbol(`SpineItemPagePosition`)\n\n constructor(position: { x: number; y: number }) {\n this.x = position.x\n this.y = position.y\n }\n}\n\nexport class SpineItemPageLayout extends LayoutEntry {\n public readonly __symbol = `SpineItemPageLayout`\n}\n","import { LayoutEntry } from \"../spineItem/types\"\n\n/**\n * Position of an item relative to spine element.\n *\n * LTR (Spine spread positively from left=0)\n * [item1 ] [item2]\n * [0, 100] [100, 200]\n * [x: 0, y: 0] [x: 100, y: 0]\n *\n * RTL (Spine spread negatively from right=0)\n * [item1 ] [item2]\n * [-100, 0] [0, 100]\n * [left: -100, right: 0] [left: 0, right: 100]\n *\n * This allow the viewport to move in a natural position following the reading direction.\n *\n * This is similar to `getBoundingClientRect` but is stable since it is absolute and will not\n * changed if any transformation is applied to the spine. A different term could be absolute position\n * of an element relative to the book view.\n *\n * You can leverage this layout info for positioning overlay elements (eg: bookmarks).\n */\nexport class SpineItemSpineLayout extends LayoutEntry {\n public readonly __symbol = `SpineItemSpineLayout`\n}\n\nexport class SpineItemPageSpineLayout extends LayoutEntry {\n public readonly __symbol = `SpineItemPageSpineLayout`\n}\n\nexport class AbstractSpinePosition {\n public readonly x: number\n public readonly y: number\n\n constructor(position: { x: number; y: number }) {\n this.x = position.x\n this.y = position.y\n }\n}\n\n/**\n * Guaranteed to be a valid spine position at a given layout.\n *\n * Meaning:\n * - within safe edges x/y\n * - at a valid page edge offset\n */\nexport class SpinePosition extends AbstractSpinePosition {\n public readonly __symbol = `SpinePosition`\n\n static from(position: UnboundSpinePosition | SpinePosition) {\n return new SpinePosition(position)\n }\n}\n\n/**\n * Represents a spine position that may not be:\n * - within safe edges x/y (eg: out of bounds)\n * - at a page edge offset (eg: 20% on a page)\n *\n * Such spine position is usually used for scroll navigation or calculations\n * of relative things.\n *\n * This is just a class to flag potential misuses, getting a UnboundSpinePosition does not\n * means the position is offset.\n */\nexport class UnboundSpinePosition extends AbstractSpinePosition {\n public readonly __symbol = `UnboundSpinePosition`\n\n static from(position: SpinePosition) {\n return new UnboundSpinePosition(position)\n }\n}\n","export const getPositionRelativeToNonTransformedElement = (\n position: { x: number; y: number },\n element: HTMLElement,\n) => {\n const elementRect = element.getBoundingClientRect()\n const { x, y } = position\n const { left, top } = elementRect\n\n // Get the scale factors\n const scaleX = elementRect.width / element.offsetWidth\n const scaleY = elementRect.height / element.offsetHeight\n\n // Calculate position relative to the transformed element\n const relativeX = x - left\n const relativeY = y - top\n\n // Convert back to non-transformed coordinates\n return {\n x: relativeX / scaleX,\n y: relativeY / scaleY,\n }\n}\n","import type { Reader } from \"../../reader\"\nimport { UnboundSpinePosition } from \"../../spine/types\"\nimport { getPositionRelativeToNonTransformedElement } from \"../../utils/coordinates\"\n\nexport const getSpinePositionFromClientPosition = (\n position: { x: number; y: number },\n spineElement: HTMLElement,\n) => {\n // Convert back to non-transformed coordinates\n return new UnboundSpinePosition(\n getPositionRelativeToNonTransformedElement(position, spineElement),\n )\n}\n\nexport const createCoordinatesApi = (reader: Reader) => {\n return {\n getSpinePositionFromClientPosition: (position: { x: number; y: number }) =>\n reader.spine.element\n ? getSpinePositionFromClientPosition(position, reader.spine.element)\n : undefined,\n }\n}\n","import {\n animationFrameScheduler,\n merge,\n NEVER,\n Observable,\n of,\n scheduled,\n} from \"rxjs\"\nimport {\n distinctUntilChanged,\n map,\n switchMap,\n take,\n takeUntil,\n tap,\n} from \"rxjs/operators\"\nimport type { Reader } from \"../../reader\"\n\n/**\n * For some reason (bug / expected / engine layout optimization) when the viewport is being animated clicking inside iframe\n * sometimes returns invalid clientX value. This means that when rapidly (or not) clicking during animation on iframe will often\n * time returns invalid value. In order to reduce potential unwanted behavior on consumer side, we temporarily hide the iframe behind\n * an overlay. That way the overlay take over for the pointer event and we all good.\n *\n * @important\n * This obviously block any interaction with iframe but there should not be such interaction with iframe in theory.\n * Theoretically if user decide to interact during the animation that's either to stop it or swipe the pages.\n */\nexport const createMovingSafePan$ = (reader: Reader) => {\n let iframeOverlayForAnimationsElement: HTMLDivElement | undefined\n\n const updateOverlayElement$ = reader.context.watch(\"rootElement\").pipe(\n switchMap((rootElement) => {\n if (!rootElement) return NEVER\n\n return new Observable(() => {\n iframeOverlayForAnimationsElement =\n rootElement.ownerDocument.createElement(`div`)\n iframeOverlayForAnimationsElement.style.cssText = `\n position: absolute;\n left: 0;\n top: 0;\n width: 100%;\n height: 100%;\n visibility: hidden;\n `\n rootElement.appendChild(iframeOverlayForAnimationsElement)\n\n return () => {\n iframeOverlayForAnimationsElement?.remove()\n iframeOverlayForAnimationsElement = undefined\n }\n })\n }),\n )\n\n const createResetLock$ = <T>(source: Observable<T>) =>\n scheduled(source, animationFrameScheduler).pipe(\n tap(() => {\n iframeOverlayForAnimationsElement?.style.setProperty(\n `visibility`,\n `hidden`,\n )\n }),\n )\n\n const lockAfterViewportBusy$ = reader.context.bridgeEvent.viewportBusy$.pipe(\n tap(() => {\n iframeOverlayForAnimationsElement?.style.setProperty(\n `visibility`,\n `visible`,\n )\n }),\n )\n\n const resetLockViewportFree$ = createResetLock$(reader.viewportFree$).pipe(\n take(1),\n )\n\n const pageTurnMode$ = reader.settings.values$.pipe(\n map(() => reader.settings.values.computedPageTurnMode),\n distinctUntilChanged(),\n )\n\n const handleViewportLock$ = pageTurnMode$.pipe(\n switchMap((mode) =>\n mode === `controlled`\n ? lockAfterViewportBusy$.pipe(switchMap(() => resetLockViewportFree$))\n : createResetLock$(of(undefined)),\n ),\n takeUntil(reader.$.destroy$),\n )\n\n return merge(updateOverlayElement$, handleViewportLock$)\n}\n","import type { Manifest } from \"@prose-reader/shared\"\nimport { combineLatest, merge, type Observable } from \"rxjs\"\nimport { switchMap, tap } from \"rxjs/operators\"\nimport { HTML_PREFIX as HTML_PREFIX_CORE } from \"../../constants\"\nimport type { Reader } from \"../../reader\"\nimport type { Viewport } from \"../../viewport/Viewport\"\nimport type { Theme } from \"../theme\"\n\nexport const HTML_PREFIX = `${HTML_PREFIX_CORE}-enhancer-loading`\nexport const CONTAINER_HTML_PREFIX = `${HTML_PREFIX}-container`\n\n/**\n * We use iframe for loading element mainly to be able to use share hooks / manipulation\n * with iframe. That way the loading element always match whatever style is applied to iframe.\n */\nconst defaultLoadingElementCreate = ({\n container,\n item,\n viewport,\n}: {\n container: HTMLElement\n item: Manifest[`spineItems`][number]\n viewport: Viewport\n}) => {\n const loadingElementContainer = container.ownerDocument.createElement(`div`)\n loadingElementContainer.classList.add(CONTAINER_HTML_PREFIX)\n loadingElementContainer.style.cssText = `\n height: 100%;\n width: 100%;\n max-width: ${viewport.absoluteViewport.width}px;\n text-align: center;\n display: flex;\n justify-content: center;\n align-items: center;\n flex-direction: column;\n position: absolute;\n left: 0;\n top: 0;\n color: rgb(202, 202, 202);\n background-color: white;\n z-index: 1;\n `\n\n const logoElement = loadingElementContainer.ownerDocument.createElement(`div`)\n logoElement.innerText = `prose`\n logoElement.style.cssText = `\n font-size: 4em;\n `\n const detailsElement =\n loadingElementContainer.ownerDocument.createElement(`div`)\n detailsElement.setAttribute(`data-details-element`, `true`)\n detailsElement.innerText = `loading ${item.id}`\n detailsElement.style.cssText = `\n font-size: 1.2em;\n text-overflow: ellipsis;\n white-space: nowrap;\n overflow: hidden;\n max-width: 300px;\n width: 80%;\n `\n loadingElementContainer.appendChild(logoElement)\n loadingElementContainer.appendChild(detailsElement)\n\n return loadingElementContainer\n}\n\nexport const createPlaceholderPages = (\n reader: Reader & { theme: { $: { theme$: Observable<Theme> } } },\n) => {\n return reader.spineItemsManager.items$.pipe(\n switchMap((items) =>\n merge(\n ...items.map((item) => {\n // since we will use z-index for the loading element, we need to set the parent\n // to 0 to have it work as relative reference.\n item.containerElement.style.zIndex = `0`\n\n const alreadyExistingElement = item.containerElement.querySelector(\n `.${CONTAINER_HTML_PREFIX}`,\n )\n\n const loadingElementContainer =\n alreadyExistingElement instanceof HTMLElement\n ? alreadyExistingElement\n : defaultLoadingElementCreate({\n container: item.containerElement,\n item: item.item,\n viewport: reader.viewport,\n })\n\n item.containerElement.appendChild(loadingElementContainer)\n\n return merge(\n item.pipe(\n tap((state) => {\n loadingElementContainer.style.setProperty(\n `visibility`,\n state.isReady ? `hidden` : `visible`,\n )\n loadingElementContainer.style.setProperty(\n `z-index`,\n state.isReady ? `0` : `1`,\n )\n\n if (state.isError) {\n const detailsElement = loadingElementContainer.querySelector(\n `[data-details-element]`,\n )\n if (detailsElement instanceof HTMLElement) {\n detailsElement.innerText =\n state.error?.toString() ?? `Unknown error`\n }\n }\n }),\n ),\n combineLatest([reader.spine.layout$, reader.theme.$.theme$]).pipe(\n tap(([, theme]) => {\n const viewportWidth = reader.viewport.absoluteViewport.width\n\n loadingElementContainer.style.setProperty(\n `max-width`,\n `${viewportWidth}px`,\n )\n loadingElementContainer.style.setProperty(\n `color`,\n theme === `sepia` ? `#939393` : `rgb(202, 202, 202)`,\n )\n }),\n ),\n )\n }),\n ),\n ),\n )\n}\n","import type { Reader } from \"../../reader\"\n\nexport const fixIframeScrollbar = (reader: Reader) => {\n /**\n * Sometimes when iframe is being loaded and resized during layout, a scrollbar\n * may appear on the iframe#document level. It will be \"empty\" but stay there and\n * catch scrolling events instead.\n *\n * It is possible to prevent it by setting overflow: hidden in the iframe#html\n * element but I feel like this could have side effects and therefore it's better\n * to just disable it the old way even if this is deprecated.\n */\n reader.hookManager.register(`item.onDocumentLoad`, ({ itemId }) => {\n const spineItem = reader.spineItemsManager.get(itemId)\n const element = spineItem?.renderer.getDocumentFrame()\n\n element?.setAttribute(\"scrolling\", \"no\")\n })\n}\n","import type { Reader } from \"../../reader\"\nimport { getFrameViewportInfo } from \"../../utils/frames\"\n\nexport const fixReflowable = (reader: Reader) => {\n /**\n * Handle page spread for reflowable item that act as pre-paginated\n *\n * - we have a reflowable item\n * - we want page spread\n * - the item has viewport dimension\n * - normal reflowable should not have viewport and should spread correctly\n * - because it has viewport we will scale the item to one page size (pre-paginated)\n *\n * @problem\n * If no blank page are demanded by the spine manager, the frame will be displayed\n * in the middle because of the item taking the entire width (spread). The spine manager\n * might not know that it is a pre-paginated because of missing meta and will not give\n * any blank page instruction.\n *\n * To fix the issue we manually add a blank page at the end if none were demanded\n *\n * @important\n * This fix might not be needed anymore if:\n *\n * - the core handle this kind of fake reflowable and insert blank page\n */\n reader.hookManager.register(\n `item.onAfterLayout`,\n ({ item, blankPagePosition, minimumWidth }) => {\n const spineItem = reader.spineItemsManager.get(item.id)\n const element = spineItem?.renderer.getDocumentFrame()\n\n if (\n !(spineItem?.renditionLayout === `reflowable`) ||\n !(element instanceof HTMLIFrameElement)\n )\n return\n\n const { hasViewport } = getFrameViewportInfo(element)\n const { width: pageWidth } = reader.viewport.pageSize\n const frameElement = spineItem?.renderer.getDocumentFrame()\n\n if (hasViewport) {\n const spineManagerWantAFullWidthItem = pageWidth < minimumWidth\n const noBlankPageAsked = blankPagePosition === `none`\n\n if (\n noBlankPageAsked &&\n spineManagerWantAFullWidthItem &&\n frameElement instanceof HTMLIFrameElement\n ) {\n frameElement?.style.setProperty(\n `left`,\n reader.context.isRTL() ? `75%` : `25%`,\n )\n }\n }\n },\n )\n}\n","import { tap } from \"rxjs\"\nimport type { Reader } from \"../../reader\"\n\nexport const flagSpineItems = (reader: Reader) => {\n return reader.spineItemsObserver.states$.pipe(\n tap(({ item, isReady, isDirty }) => {\n // biome-ignore lint/complexity/useLiteralKeys: TS needs it\n item.containerElement.dataset[\"isDirty\"] = isDirty.toString()\n // biome-ignore lint/complexity/useLiteralKeys: TS needs it\n item.containerElement.dataset[\"isReady\"] = isReady.toString()\n }),\n )\n}\n","import { SettingsManagerOverload } from \"../../settings/SettingsManagerOverload\"\nimport type {\n CoreInputSettings,\n CoreOutputSettings,\n} from \"../../settings/types\"\nimport { isShallowEqual } from \"../../utils/objects\"\nimport type { EnhancerLayoutInputSettings, OutputSettings } from \"./types\"\n\nexport class SettingsManager<\n ParentInputSettings extends CoreInputSettings,\n ParentOutputSettings extends CoreOutputSettings,\n> extends SettingsManagerOverload<\n EnhancerLayoutInputSettings,\n OutputSettings,\n ParentInputSettings,\n ParentOutputSettings\n> {\n computeOutputSettings(\n inputSettings: EnhancerLayoutInputSettings,\n ): EnhancerLayoutInputSettings {\n return inputSettings\n }\n\n hasSettingsChanged(newOutputSettings: EnhancerLayoutInputSettings): boolean {\n return !isShallowEqual(this.outputSettings, newOutputSettings)\n }\n\n getCleanedParentInputSettings(\n settings: Partial<EnhancerLayoutInputSettings & ParentInputSettings>,\n ): ParentInputSettings {\n const {\n layoutAutoResize: _unused1,\n pageHorizontalMargin: _unused2,\n pageVerticalMargin: _unused3,\n layoutLayerTransition: _unused4,\n ...rest\n } = settings\n\n return rest as unknown as ParentInputSettings\n }\n\n getDefaultSettings(): EnhancerLayoutInputSettings {\n return {\n layoutAutoResize: \"container\",\n pageHorizontalMargin: 24,\n pageVerticalMargin: 24,\n layoutLayerTransition: true,\n }\n }\n}\n","import { combineLatest, tap } from \"rxjs\"\nimport type { Reader } from \"../../reader\"\n\nexport const updateSpreadMode = (reader: Reader) => {\n return combineLatest([\n reader.viewport.watch([\"width\", \"height\"]),\n reader.context.watch(\"manifest\"),\n ]).pipe(\n tap(([{ width, height }, manifest]) => {\n const isLandscape = width > height\n\n if (!isLandscape && manifest?.renditionSpread === `portrait`) {\n return reader.settings.update({ spreadMode: true })\n }\n\n if (\n isLandscape &&\n (manifest?.renditionSpread === undefined ||\n manifest?.renditionSpread === `auto` ||\n manifest?.renditionSpread === `landscape` ||\n manifest?.renditionSpread === `both`)\n ) {\n return reader.settings.update({ spreadMode: true })\n }\n\n return reader.settings.update({ spreadMode: false })\n }),\n )\n}\n","import { detectMimeTypeFromName } from \"@prose-reader/shared\"\nimport { merge, type Observable, type ObservedValueOf } from \"rxjs\"\nimport {\n debounceTime,\n filter,\n shareReplay,\n skip,\n switchMap,\n takeUntil,\n tap,\n} from \"rxjs/operators\"\nimport type { SettingsInterface } from \"../../settings/SettingsInterface\"\nimport type { Pages } from \"../../spine/Pages\"\nimport { upsertCSSToFrame } from \"../../utils/frames\"\nimport { isDefined } from \"../../utils/isDefined\"\nimport { observeResize } from \"../../utils/rxjs\"\nimport type { themeEnhancer } from \"../theme\"\nimport type {\n EnhancerOptions,\n EnhancerOutput,\n RootEnhancer,\n} from \"../types/enhancer\"\nimport { createCoordinatesApi } from \"./coordinates\"\nimport { createMovingSafePan$ } from \"./createMovingSafePan$\"\nimport { createPlaceholderPages } from \"./createPlaceholderPages\"\nimport { fixIframeScrollbar } from \"./fixIframeScrollbar\"\nimport { fixReflowable } from \"./fixReflowable\"\nimport { flagSpineItems } from \"./flagSpineItems\"\nimport { SettingsManager } from \"./SettingsManager\"\nimport type { EnhancerLayoutInputSettings, OutputSettings } from \"./types\"\nimport { updateSpreadMode } from \"./updateSpreadMode\"\n\nexport type LayoutEnhancerOutput = {\n layout$: Observable<ObservedValueOf<Pages>>\n layoutInfo$: Observable<ObservedValueOf<Pages>>\n coordinates: ReturnType<typeof createCoordinatesApi>\n}\n\nexport const layoutEnhancer =\n <\n InheritOptions extends EnhancerOptions<RootEnhancer>,\n InheritOutput extends EnhancerOutput<typeof themeEnhancer>,\n InheritSettings extends NonNullable<\n InheritOutput[\"settings\"][\"_inputSettings\"]\n >,\n InheritComputedSettings extends NonNullable<\n InheritOutput[\"settings\"][\"_outputSettings\"]\n >,\n Output extends Omit<InheritOutput, \"settings\"> &\n LayoutEnhancerOutput & {\n settings: SettingsInterface<\n InheritSettings & EnhancerLayoutInputSettings,\n OutputSettings & InheritComputedSettings\n >\n },\n >(\n next: (options: InheritOptions) => InheritOutput,\n ) =>\n (options: InheritOptions & Partial<EnhancerLayoutInputSettings>): Output => {\n const {\n pageHorizontalMargin,\n pageVerticalMargin,\n layoutAutoResize,\n layoutLayerTransition,\n } = options\n const reader = next(options)\n\n const settingsManager = new SettingsManager<\n InheritSettings,\n InheritComputedSettings\n >(\n {\n pageHorizontalMargin,\n pageVerticalMargin,\n layoutAutoResize,\n layoutLayerTransition,\n },\n reader.settings as SettingsInterface<\n InheritSettings,\n InheritComputedSettings\n >,\n )\n\n reader.hookManager.register(`onViewportOffsetAdjust`, () => {\n let hasRedrawn = false\n\n /**\n * When adjusting the offset, there is a chance that pointer event being dispatched right after\n * have a wrong `clientX` / `pageX` etc. This is because even if the iframe\n * left value (once requested) is correct,\n * it does not seem to have been correctly taken by the browser when creating the event.\n * What we do here is that after a viewport adjustment we immediately force a reflow on the engine.\n *\n * @example\n * [pointer event] -> clientX = 50, left = 0, translated clientX = 50 (CORRECT)\n * [translate viewport] -> left = +100px\n * [pointer event] -> clientX = ~50, left = -100, translated clientX = ~-50 (INCORRECT)\n * [pointer event] -> clientX = 150, left = -100, translated clientX = 50 (CORRECT)\n *\n * For some reason the engine must be doing some optimization and unfortunately the first pointer event gets the clientX wrong.\n *\n * The bug can be observed by commenting this code, using CPU slowdown and increasing the throttle on the adjustment stream.\n * The bug seems to affect only chrome / firefox. Nor safari.\n *\n * Also we only need to use `getBoundingClientRect` once.\n *\n * @todo\n * Consider creating a bug ticket on both chromium and gecko projects.\n */\n reader.spineItemsManager.items.forEach((item) => {\n const frame = item.renderer.getDocumentFrame()\n\n if (!hasRedrawn && frame) {\n void frame.getBoundingClientRect().left\n hasRedrawn = true\n }\n })\n })\n\n /**\n * @todo move to theming\n */\n reader.hookManager.register(`item.onBeforeLayout`, ({ item }) => {\n const spineItem = reader.spineItemsManager.get(item.id)\n const mimeType = item.mediaType ?? detectMimeTypeFromName(item.href)\n const isImageType = !!mimeType?.startsWith(`image/`)\n\n const { pageHorizontalMargin = 0, pageVerticalMargin = 0 } =\n settingsManager.values\n const pageSize = reader.viewport.pageSize\n\n if (spineItem?.renditionLayout === `reflowable` && !isImageType) {\n let columnWidth = pageSize.width - pageHorizontalMargin * 2\n const columnHeight = pageSize.height - pageVerticalMargin * 2\n let width = pageSize.width - pageHorizontalMargin * 2\n let columnGap = pageHorizontalMargin * 2\n\n if (spineItem.isUsingVerticalWriting()) {\n width = pageSize.width - pageHorizontalMargin * 2\n columnWidth = columnHeight\n columnGap = pageVerticalMargin * 2\n }\n\n const frame = spineItem?.renderer.getDocumentFrame()\n\n if (frame) {\n upsertCSSToFrame(\n frame,\n `prose-layout-enhancer-css`,\n `\n body {\n width: ${width}px !important;\n margin: ${pageVerticalMargin}px ${pageHorizontalMargin}px !important;\n column-gap: ${columnGap}px !important;\n column-width: ${columnWidth}px !important;\n height: ${columnHeight}px !important;\n }\n img, video, audio, object, svg {\n -max-width: ${columnWidth}px !important;\n -max-height: ${columnHeight}px !important;\n }\n table {\n max-width: ${columnWidth}px !important;\n }\n td {\n max-width: ${columnWidth}px;\n }\n `,\n )\n }\n }\n })\n\n fixReflowable(reader)\n fixIframeScrollbar(reader)\n\n reader.hookManager.register(\n `item.onDocumentCreated`,\n ({ documentContainer }) => {\n /**\n * Hide document until it's ready\n */\n documentContainer.style.opacity = `0`\n if (settingsManager.values.layoutLayerTransition) {\n documentContainer.style.transition = `opacity 300ms`\n }\n },\n )\n\n reader.hookManager.register(`item.onBeforeLayout`, ({ item }) => {\n const spineItem = reader.spineItemsManager.get(item.id)\n\n const element = spineItem?.renderer.documentContainer\n\n // @todo dont remember why i did this but there should be a reason. If i get time to explain\n if (reader.settings.values.computedPageTurnMode !== `scrollable`) {\n // @todo see what's the impact\n element?.setAttribute(`tab-index`, `0`)\n }\n })\n\n const revealItemOnReady$ = reader.spineItemsObserver.states$.pipe(\n filter(({ isReady }) => isReady),\n tap(({ item }) => {\n const element = item.renderer.documentContainer\n\n if (element) {\n element.style.opacity = `1`\n }\n }),\n )\n\n // @todo fix the pan-start issue\n // @todo maybe increasing the hammer distance before triggering pan as well\n // reader.registerHook(`item.onDocumentLoad`, ({frame}) => {\n // frame.contentDocument?.body.addEventListener(`contextmenu`, e => {\n // e.preventDefault()\n // })\n // })\n\n const layoutOnContainerResize$ = settingsManager.values$.pipe(\n filter(({ layoutAutoResize }) => layoutAutoResize === \"container\"),\n switchMap(() => reader.context.watch(`rootElement`)),\n filter(isDefined),\n switchMap((element) => observeResize(element)),\n debounceTime(100),\n filter(isDefined),\n tap(() => {\n reader?.layout()\n }),\n )\n\n const movingSafePan$ = createMovingSafePan$(reader)\n\n settingsManager\n .watch([`pageHorizontalMargin`, `pageVerticalMargin`])\n .pipe(\n skip(1),\n tap(() => {\n reader.layout()\n }),\n takeUntil(reader.$.destroy$),\n )\n .subscribe()\n\n const layoutInfo$ = reader.spine.pages.pipe(\n shareReplay({ refCount: true, bufferSize: 1 }),\n )\n\n const flagSpineItems$ = flagSpineItems(reader)\n\n const updateSpreadMode$ = updateSpreadMode(reader)\n\n const placeholderPages$ = createPlaceholderPages(reader)\n\n merge(\n revealItemOnReady$,\n movingSafePan$,\n layoutOnContainerResize$,\n layoutInfo$,\n flagSpineItems$,\n updateSpreadMode$,\n placeholderPages$,\n )\n .pipe(takeUntil(reader.$.destroy$))\n .subscribe()\n\n return {\n ...reader,\n destroy: () => {\n settingsManager.destroy()\n reader.destroy()\n },\n settings: settingsManager,\n layout$: reader.spine.layout$,\n layoutInfo$,\n coordinates: createCoordinatesApi(reader),\n } as unknown as Output\n }\n","import { EMPTY, from, fromEvent, map, of, switchMap } from \"rxjs\"\nimport { DocumentRenderer } from \"../../spineItem/renderer/DocumentRenderer\"\n\nexport class ImageRenderer extends DocumentRenderer {\n private getImageElement() {\n const element = this.documentContainer\n\n if (!(element instanceof HTMLImageElement)) return undefined\n\n return element\n }\n\n onCreateDocument() {\n const imgElement = this.containerElement.ownerDocument.createElement(`img`)\n\n return from(this.resourcesHandler.getResource()).pipe(\n switchMap((responseOrUrl) => {\n this.setDocumentContainer(imgElement)\n\n imgElement.style.objectFit = `contain`\n imgElement.style.userSelect = `none`\n\n if (responseOrUrl instanceof URL) {\n return of(responseOrUrl.href)\n }\n if (responseOrUrl instanceof Response) {\n return from(responseOrUrl.blob()).pipe(\n map((blob) => {\n return URL.createObjectURL(blob)\n }),\n )\n }\n\n throw new Error(`Invalid resource`)\n }),\n map((src) => {\n const element = this.getImageElement()\n\n if (element) {\n element.src = src\n }\n\n return imgElement\n }),\n )\n }\n\n onLoadDocument() {\n const imageElement = this.getImageElement()\n\n if (!imageElement) throw new Error(`invalid element`)\n\n this.attach()\n\n return fromEvent(imageElement, `load`)\n }\n\n onUnload() {\n const imageElement = this.getImageElement()\n\n if (imageElement) {\n URL.revokeObjectURL(imageElement.src)\n }\n\n this.detach()\n\n return EMPTY\n }\n\n onLayout({\n spreadPosition,\n }: {\n minPageSpread: number\n blankPagePosition: `before` | `after` | `none`\n spreadPosition: `none` | `left` | `right`\n }) {\n const element = this.getImageElement()\n const { height: pageHeight, width: pageWidth } =\n this.viewport.value.pageSize\n\n let height = pageHeight\n\n const width = pageWidth\n\n if (!element) return of(undefined)\n\n const naturalWidth = element.naturalWidth || 1\n const naturalHeight = element.naturalHeight || 1\n const ratio = naturalWidth / naturalHeight\n\n /**\n * In case of continuous scroll, we scale up/down the height\n * to match the page width.\n */\n if (\n this.settings.values.computedPageTurnDirection === \"vertical\" &&\n this.settings.values.computedPageTurnMode === \"scrollable\" &&\n !this.settings.values.computedSpreadMode\n ) {\n height = Math.ceil(pageWidth / ratio)\n }\n\n element.style.height = `${height}px`\n element.style.width = `${width}px`\n element.style.objectPosition =\n spreadPosition === \"left\"\n ? `right`\n : spreadPosition === `right`\n ? `left`\n : `center`\n\n return of({\n width,\n height,\n })\n }\n\n onRenderHeadless() {\n return EMPTY\n }\n\n getDocumentFrame() {\n return undefined\n }\n}\n","import { detectMimeTypeFromName } from \"@prose-reader/shared\"\nimport type {\n EnhancerOptions,\n EnhancerOutput,\n RootEnhancer,\n} from \"../types/enhancer\"\nimport { ImageRenderer } from \"./ImageRenderer\"\n\nexport const mediaEnhancer =\n <\n InheritOptions extends EnhancerOptions<RootEnhancer>,\n InheritOutput extends EnhancerOutput<RootEnhancer>,\n >(\n next: (options: InheritOptions) => InheritOutput,\n ) =>\n (options: InheritOptions): InheritOutput => {\n const reader = next({\n ...options,\n getRenderer(item) {\n const maybeFactory = options.getRenderer?.(item)\n const mimeType = item.mediaType ?? detectMimeTypeFromName(item.href)\n const isImageType = !!mimeType?.startsWith(`image/`)\n\n if (!maybeFactory && isImageType) {\n return (props) => new ImageRenderer(props)\n }\n\n return maybeFactory\n },\n })\n\n const frameObserver = new IntersectionObserver(\n (entries) => {\n entries.forEach((entry) => {\n const frame = entry.target as HTMLIFrameElement\n const audios = Array.from(\n frame.contentDocument?.body.getElementsByTagName(`audio`) || [],\n )\n\n if (!entry.isIntersecting) {\n audios.forEach((audioElement) => {\n audioElement.pause()\n audioElement.currentTime = 0\n })\n } else {\n audios.forEach((audioElement) => {\n if (\n audioElement.hasAttribute(`autoplay`) &&\n audioElement.paused &&\n audioElement.readyState >= 2\n ) {\n audioElement.play().catch(console.error)\n }\n })\n }\n })\n },\n {\n threshold: 0.01,\n },\n )\n\n const elementObserver = new IntersectionObserver(\n (entries) => {\n entries.forEach((entry) => {\n if (entry.target.tagName === `video`) {\n const video = entry.target as HTMLVideoElement\n if (!entry.isIntersecting) {\n video.pause()\n video.currentTime = 0\n } else {\n if (video.hasAttribute(`autoplay`)) {\n // this can fail when we play the first time due to user not having interacted with\n // document yet. Browsers policy. autoplay will play it the first time anyway.\n if (video.paused && video.readyState >= 2) {\n video.play().catch(console.error)\n }\n }\n }\n }\n })\n },\n {\n threshold: 0.5,\n },\n )\n\n reader.hookManager.register(\n `item.onDocumentLoad`,\n ({ destroy, itemId }) => {\n const frame = reader.spineItemsManager\n .get(itemId)\n ?.renderer.getDocumentFrame()\n\n if (!frame) return\n\n frameObserver.observe(frame)\n\n const videos = frame.contentDocument?.body.getElementsByTagName(`video`)\n\n const unobserveElements = Array.from(videos || []).map((element) => {\n elementObserver.observe(element)\n\n return () => elementObserver.unobserve(element)\n })\n\n destroy(() => {\n frameObserver.unobserve(frame)\n unobserveElements.forEach((unobserve) => {\n unobserve()\n })\n })\n },\n )\n\n const destroy = () => {\n frameObserver.disconnect()\n elementObserver.disconnect()\n reader.destroy()\n }\n\n return {\n ...reader,\n destroy,\n }\n }\n","import { tap } from \"rxjs\"\nimport type { Reader } from \"../../reader\"\nimport { isHtmlTagElement } from \"../../utils/dom\"\nimport type { HtmlEnhancerOutput } from \"../html/enhancer\"\nimport type { ManualNavigator } from \"./navigators/manualNavigator\"\n\nexport const handleLinksNavigation = (\n reader: Reader & HtmlEnhancerOutput,\n manualNavigator: ManualNavigator,\n) => {\n return reader.links$.pipe(\n tap((event) => {\n if (!isHtmlTagElement(event.target, \"a\") || event.type !== \"click\") return\n\n const hrefUrl = new URL(event.target.href)\n const hrefWithoutAnchor = `${hrefUrl.origin}${hrefUrl.pathname}`\n\n // internal link, we can handle\n const hasExistingSpineItem = reader.context.manifest?.spineItems.some(\n (item) => item.href === hrefWithoutAnchor,\n )\n\n if (hasExistingSpineItem) {\n manualNavigator.goToUrl(hrefUrl)\n }\n }),\n )\n}\n","import { Report } from \"../../report\"\n\nexport const navigationReport = Report.namespace(`navigation`)\n","import type { SpineItem } from \"../../../spineItem/SpineItem\"\nimport type { SpineItemLocator } from \"../../../spineItem/locationResolver\"\nimport { SpineItemPosition } from \"../../../spineItem/types\"\n\nexport const getSpineItemPositionForLeftPage = ({\n position,\n spineItem,\n pageHeight,\n pageWidth,\n spineItemLocator,\n}: {\n position: SpineItemPosition\n spineItem: SpineItem\n pageWidth: number\n pageHeight: number\n spineItemLocator: SpineItemLocator\n}): SpineItemPosition => {\n let nextPotentialPosition = new SpineItemPosition({\n x: position.x - pageWidth,\n y: position.y,\n })\n\n if (spineItem.isUsingVerticalWriting()) {\n nextPotentialPosition = new SpineItemPosition({\n x: position.x,\n y: position.y + pageHeight,\n })\n }\n\n const navigationPosition =\n spineItemLocator.getSpineItemClosestPositionFromUnsafePosition(\n nextPotentialPosition,\n spineItem,\n )\n\n return navigationPosition\n}\n","import type { NavigationResolver } from \"../../../navigation/resolvers/NavigationResolver\"\nimport type { SpineLocator } from \"../../../spine/locator/SpineLocator\"\nimport type { SpineItemsManager } from \"../../../spine/SpineItemsManager\"\nimport { SpinePosition, type UnboundSpinePosition } from \"../../../spine/types\"\nimport type { Viewport } from \"../../../viewport/Viewport\"\nimport { getSpineItemPositionForLeftPage } from \"./getSpineItemPositionForLeftPage\"\n\nexport const getNavigationForLeftSinglePage = ({\n position,\n navigationResolver,\n computedPageTurnDirection,\n spineItemsManager,\n spineLocator,\n viewport,\n}: {\n position: SpinePosition | UnboundSpinePosition\n navigationResolver: NavigationResolver\n computedPageTurnDirection: \"horizontal\" | \"vertical\"\n spineItemsManager: SpineItemsManager\n spineLocator: SpineLocator\n viewport: Viewport\n}): SpinePosition | UnboundSpinePosition => {\n const pageTurnDirection = computedPageTurnDirection\n const spineItem =\n spineLocator.getSpineItemFromPosition(position) || spineItemsManager.get(0)\n const defaultNavigation = position\n\n if (!spineItem) {\n return defaultNavigation\n }\n\n const spineItemPosition = spineLocator.getSpineItemPositionFromSpinePosition(\n position,\n spineItem,\n )\n\n const spineItemNavigation = getSpineItemPositionForLeftPage({\n position: spineItemPosition,\n spineItem,\n pageHeight: viewport.pageSize.height,\n pageWidth: viewport.pageSize.width,\n spineItemLocator: spineLocator.spineItemLocator,\n })\n\n const isNewNavigationInCurrentItem = navigationResolver.arePositionsDifferent(\n spineItemNavigation,\n spineItemPosition,\n )\n\n if (!isNewNavigationInCurrentItem) {\n return navigationResolver.fromUnboundSpinePosition(\n pageTurnDirection === `horizontal`\n ? new SpinePosition({\n x: position.x - viewport.pageSize.width,\n y: 0,\n })\n : new SpinePosition({\n y: position.y - viewport.pageSize.height,\n x: 0,\n }),\n )\n }\n const readingOrderPosition =\n spineLocator.getSpinePositionFromSpineItemPosition({\n spineItemPosition: spineItemNavigation,\n spineItem,\n })\n\n return readingOrderPosition\n}\n","import type { Context } from \"../../../context/Context\"\nimport type { NavigationResolver } from \"../../../navigation/resolvers/NavigationResolver\"\nimport type { SettingsInterface } from \"../../../settings/SettingsInterface\"\nimport type {\n ComputedCoreSettings,\n CoreInputSettings,\n} from \"../../../settings/types\"\nimport type { SpineLocator } from \"../../../spine/locator/SpineLocator\"\nimport type { SpineItemsManager } from \"../../../spine/SpineItemsManager\"\nimport type { SpinePosition, UnboundSpinePosition } from \"../../../spine/types\"\nimport type { SpineItem } from \"../../../spineItem/SpineItem\"\nimport type { Viewport } from \"../../../viewport/Viewport\"\nimport { getNavigationForLeftSinglePage } from \"./getNavigationForLeftSinglePage\"\n\n/**\n * Very naive approach for spread. It could be optimized but by using this approach\n * we do not add complexity to the code and use the current logic to handle it correctly.\n *\n * @important\n * Special case for vertical content, read content\n */\nexport const getNavigationForLeftOrTopPage = ({\n position,\n spineItem,\n context,\n navigationResolver,\n spineItemsManager,\n spineLocator,\n computedPageTurnDirection,\n viewport,\n settings,\n}: {\n position: SpinePosition | UnboundSpinePosition\n spineItem: SpineItem\n context: Context\n spineItemsManager: SpineItemsManager\n navigationResolver: NavigationResolver\n spineLocator: SpineLocator\n computedPageTurnDirection: \"horizontal\" | \"vertical\"\n viewport: Viewport\n settings: SettingsInterface<\n CoreInputSettings,\n CoreInputSettings & ComputedCoreSettings\n >\n}): SpinePosition | UnboundSpinePosition => {\n const navigation = getNavigationForLeftSinglePage({\n position,\n viewport,\n navigationResolver,\n computedPageTurnDirection,\n spineItemsManager,\n spineLocator,\n })\n\n // when we move withing vertical content, because only y moves, we don't need two navigation\n if (spineItem?.isUsingVerticalWriting() && position.x === navigation.x) {\n return navigationResolver.getAdjustedPositionForSpread(navigation)\n }\n\n if (settings.values.computedSpreadMode) {\n // in case of spread the entire screen is taken as one real page for vertical content\n // in order to move out from it we add an extra page width.\n // using `getNavigationForLeftSinglePage` again would keep x as it is and wrongly move y\n // for the next item in case it's also a vertical content\n if (spineItem?.isUsingVerticalWriting() && position.x !== navigation.x) {\n return navigationResolver.getAdjustedPositionForSpread(\n navigationResolver.fromUnboundSpinePosition(\n context.isRTL()\n ? { ...navigation, x: navigation.x + viewport.pageSize.width }\n : {\n ...navigation,\n x: navigation.x - viewport.pageSize.width,\n },\n ),\n )\n }\n\n /**\n * In vase we move vertically and the y is already different, we don't need a second navigation\n * since we already jumped to a new screen\n */\n if (\n computedPageTurnDirection === `vertical` &&\n position.y !== navigation.y\n ) {\n return navigationResolver.getAdjustedPositionForSpread(navigation)\n }\n\n const doubleNavigation = getNavigationForLeftSinglePage({\n position: navigation,\n viewport,\n navigationResolver,\n computedPageTurnDirection,\n spineItemsManager,\n spineLocator,\n })\n\n return navigationResolver.getAdjustedPositionForSpread(doubleNavigation)\n }\n\n return navigationResolver.getAdjustedPositionForSpread(navigation)\n}\n","import type { SpineItemLocator } from \"../../../spineItem/locationResolver\"\nimport type { SpineItem } from \"../../../spineItem/SpineItem\"\nimport { SpineItemPosition } from \"../../../spineItem/types\"\n\nexport const getSpineItemPositionForRightPage = ({\n position,\n spineItem,\n pageHeight,\n pageWidth,\n spineItemLocator,\n}: {\n position: SpineItemPosition\n spineItem: SpineItem\n pageWidth: number\n pageHeight: number\n spineItemLocator: SpineItemLocator\n}): SpineItemPosition => {\n let nextPotentialPosition = new SpineItemPosition({\n x: position.x + pageWidth,\n y: position.y,\n })\n\n if (spineItem.isUsingVerticalWriting()) {\n nextPotentialPosition = new SpineItemPosition({\n x: position.x,\n y: position.y - pageHeight,\n })\n }\n\n const navigationPosition =\n spineItemLocator.getSpineItemClosestPositionFromUnsafePosition(\n nextPotentialPosition,\n spineItem,\n )\n\n return navigationPosition\n}\n","import type { NavigationResolver } from \"../../../navigation/resolvers/NavigationResolver\"\nimport type { SpineLocator } from \"../../../spine/locator/SpineLocator\"\nimport type { SpineItemsManager } from \"../../../spine/SpineItemsManager\"\nimport { type SpinePosition, UnboundSpinePosition } from \"../../../spine/types\"\nimport type { Viewport } from \"../../../viewport/Viewport\"\nimport { getSpineItemPositionForRightPage } from \"./getSpineItemPositionForRightPage\"\n\n/**\n * @important\n * Although we check for right page, it has the side effect to work for vertical\n * controlled books because when checking right page, we will get nothing and therefore\n * move the cursor to the next valid position, in turn getting the next bottom page.\n */\nexport const getNavigationForRightOrBottomSinglePage = ({\n position,\n navigationResolver,\n computedPageTurnDirection,\n spineItemsManager,\n spineLocator,\n viewport,\n}: {\n position: SpinePosition | UnboundSpinePosition\n navigationResolver: NavigationResolver\n computedPageTurnDirection: \"horizontal\" | \"vertical\"\n spineItemsManager: SpineItemsManager\n spineLocator: SpineLocator\n viewport: Viewport\n}): SpinePosition | UnboundSpinePosition => {\n const pageTurnDirection = computedPageTurnDirection\n const spineItem =\n spineLocator.getSpineItemFromPosition(position) || spineItemsManager.get(0)\n const defaultNavigation = position\n\n if (!spineItem) {\n return defaultNavigation\n }\n\n // translate viewport position into reading item local position\n const spineItemPosition = spineLocator.getSpineItemPositionFromSpinePosition(\n position,\n spineItem,\n )\n\n // get reading item local position for right page\n const spineItemNavigationForRightPage = getSpineItemPositionForRightPage({\n position: spineItemPosition,\n spineItem,\n pageHeight: viewport.pageSize.height,\n pageWidth: viewport.pageSize.width,\n spineItemLocator: spineLocator.spineItemLocator,\n })\n\n // check both position to see if we moved out of it\n const positionsAreDifferent = navigationResolver.arePositionsDifferent(\n spineItemNavigationForRightPage,\n spineItemPosition,\n )\n\n if (!positionsAreDifferent) {\n return navigationResolver.fromUnboundSpinePosition(\n pageTurnDirection === `horizontal`\n ? new UnboundSpinePosition({\n x: position.x + viewport.pageSize.width,\n y: 0,\n })\n : new UnboundSpinePosition({\n y: position.y + viewport.pageSize.height,\n x: 0,\n }),\n )\n }\n\n const readingOrderPosition =\n spineLocator.getSpinePositionFromSpineItemPosition({\n spineItemPosition: spineItemNavigationForRightPage,\n spineItem,\n })\n\n return readingOrderPosition\n}\n","import type { Context } from \"../../../context/Context\"\nimport type { NavigationResolver } from \"../../../navigation/resolvers/NavigationResolver\"\nimport type { SettingsInterface } from \"../../../settings/SettingsInterface\"\nimport type {\n ComputedCoreSettings,\n CoreInputSettings,\n} from \"../../../settings/types\"\nimport type { SpineLocator } from \"../../../spine/locator/SpineLocator\"\nimport type { SpineItemsManager } from \"../../../spine/SpineItemsManager\"\nimport type { SpinePosition, UnboundSpinePosition } from \"../../../spine/types\"\nimport type { SpineItem } from \"../../../spineItem/SpineItem\"\nimport type { Viewport } from \"../../../viewport/Viewport\"\nimport { getNavigationForRightOrBottomSinglePage } from \"./getNavigationForRightOrBottomSinglePage\"\n\n/**\n * Very naive approach for spread. It could be optimized but by using this approach\n * we do not add complexity to the code and use the current logic to handle it correctly.\n *\n * @important\n * Special case for vertical content, read content\n */\nexport const getNavigationForRightOrBottomPage = ({\n position,\n spineItem,\n context,\n navigationResolver,\n spineItemsManager,\n spineLocator,\n computedPageTurnDirection,\n viewport,\n settings,\n}: {\n position: SpinePosition | UnboundSpinePosition\n spineItem: SpineItem\n context: Context\n spineItemsManager: SpineItemsManager\n navigationResolver: NavigationResolver\n spineLocator: SpineLocator\n computedPageTurnDirection: \"horizontal\" | \"vertical\"\n viewport: Viewport\n settings: SettingsInterface<\n CoreInputSettings,\n CoreInputSettings & ComputedCoreSettings\n >\n}): SpinePosition => {\n const navigation = getNavigationForRightOrBottomSinglePage({\n position,\n viewport,\n navigationResolver,\n computedPageTurnDirection,\n spineItemsManager,\n spineLocator,\n })\n\n // when we move withing vertical content, because only y moves, we don't need two navigation\n if (spineItem?.isUsingVerticalWriting() && position.x === navigation.x) {\n return navigationResolver.getAdjustedPositionForSpread(navigation)\n }\n\n if (settings.values.computedSpreadMode) {\n // in case of spread the entire screen is taken as one real page for vertical content\n // in order to move out from it we add an extra page width.\n // using `getNavigationForLeftSinglePage` again would keep x as it is and wrongly move y\n // for the next item in case it's also a vertical content\n if (spineItem?.isUsingVerticalWriting() && position.x !== navigation.x) {\n return navigationResolver.getAdjustedPositionForSpread(\n navigationResolver.fromUnboundSpinePosition(\n context.isRTL()\n ? {\n ...navigation,\n x: navigation.x - viewport.pageSize.width,\n }\n : {\n ...navigation,\n x: navigation.x + viewport.pageSize.width,\n },\n ),\n )\n }\n\n /**\n * In vase we move vertically and the y is already different, we don't need a second navigation\n * since we already jumped to a new screen\n */\n if (\n computedPageTurnDirection === `vertical` &&\n position.y !== navigation.y\n ) {\n return navigationResolver.getAdjustedPositionForSpread(navigation)\n }\n\n const doubleNavigation = getNavigationForRightOrBottomSinglePage({\n position: navigation,\n viewport,\n navigationResolver,\n computedPageTurnDirection,\n spineItemsManager,\n spineLocator,\n })\n\n return navigationResolver.getAdjustedPositionForSpread(doubleNavigation)\n }\n\n return navigationResolver.getAdjustedPositionForSpread(navigation)\n}\n","import type { UserNavigationEntry } from \"../../../navigation/types\"\nimport type { Reader } from \"../../../reader\"\nimport { SpinePosition } from \"../../../spine/types\"\nimport type { SpineItemReference } from \"../../../spineItem/SpineItem\"\nimport { navigationReport } from \"../report\"\nimport { getNavigationForLeftOrTopPage } from \"../resolvers/getNavigationForLeftOrTopPage\"\nimport { getNavigationForRightOrBottomPage } from \"../resolvers/getNavigationForRightOrBottomPage\"\n\nexport class ManualNavigator {\n movingLastDelta = { x: 0, y: 0 }\n movingLastPosition = new SpinePosition({ x: 0, y: 0 })\n unlock: ReturnType<Reader[\"navigation\"][\"lock\"]> | undefined = undefined\n\n constructor(protected reader: Reader) {}\n\n turnRight() {\n return this.turnRightOrBottom()\n }\n\n turnLeft() {\n return this.turnLeftOrTop()\n }\n\n turnTop() {\n return this.turnLeftOrTop()\n }\n\n turnBottom() {\n return this.turnRightOrBottom()\n }\n\n turnRightOrBottom() {\n const navigation = this.reader.navigation.getNavigation()\n const spineItem = this.reader.spineItemsManager.get(navigation.spineItem)\n\n if (!spineItem) return\n\n const position = getNavigationForRightOrBottomPage({\n context: this.reader.context,\n navigationResolver: this.reader.navigation.navigationResolver,\n position: navigation.position,\n computedPageTurnDirection:\n this.reader.settings.values.computedPageTurnDirection,\n spineItem,\n spineItemsManager: this.reader.spineItemsManager,\n spineLocator: this.reader.spine.locator,\n viewport: this.reader.viewport,\n settings: this.reader.settings,\n })\n\n return this.reader.navigation.navigate({\n position,\n })\n }\n\n turnLeftOrTop() {\n const navigation = this.reader.navigation.getNavigation()\n const spineItem = this.reader.spineItemsManager.get(navigation.spineItem)\n\n if (!spineItem) return\n\n const position = getNavigationForLeftOrTopPage({\n context: this.reader.context,\n navigationResolver: this.reader.navigation.navigationResolver,\n position: navigation.position,\n computedPageTurnDirection:\n this.reader.settings.values.computedPageTurnDirection,\n spineItem,\n spineItemsManager: this.reader.spineItemsManager,\n spineLocator: this.reader.spine.locator,\n viewport: this.reader.viewport,\n settings: this.reader.settings,\n })\n\n return this.reader.navigation.navigate({\n position,\n })\n }\n\n goToCfi(cfi: string, options: { animate: boolean } = { animate: true }) {\n return this.reader.navigation.navigate({\n animation: options.animate ? \"turn\" : false,\n cfi,\n })\n }\n\n goToSpineItem({\n indexOrId,\n ...rest\n }: { indexOrId: SpineItemReference } & Pick<\n UserNavigationEntry,\n \"animation\"\n >) {\n const spineItem = this.reader.spineItemsManager.get(indexOrId)\n\n if (spineItem === undefined) {\n navigationReport.warn(\n `goToSpineItem`,\n `Ignore navigation to ${indexOrId} since the item does not exist`,\n )\n\n return\n }\n\n this.reader.navigation.navigate({\n spineItem: spineItem.index,\n ...rest,\n })\n }\n\n goToNextSpineItem() {\n const { endIndex = 0 } =\n this.reader.spine.locator.getVisibleSpineItemsFromPosition({\n position: this.reader.navigation.getNavigation().position,\n threshold: { type: \"percentage\", value: 0.5 },\n }) || {}\n\n this.goToSpineItem({ indexOrId: endIndex + 1 })\n }\n\n goToPreviousSpineItem() {\n const { beginIndex = 0 } =\n this.reader.spine.locator.getVisibleSpineItemsFromPosition({\n position: this.reader.navigation.getNavigation().position,\n threshold: { type: \"percentage\", value: 0.5 },\n }) ?? {}\n\n this.goToSpineItem({ indexOrId: beginIndex - 1 })\n }\n\n goToUrl(url: string | URL) {\n this.reader.navigation.navigate({\n url,\n animation: false,\n })\n }\n\n goToRightSpineItem() {\n if (this.reader.settings.values.computedPageTurnDirection === \"vertical\") {\n navigationReport.warn(\n `You cannot call this navigation method on vertical direction`,\n )\n\n return\n }\n\n if (this.reader.context.isRTL()) {\n return this.goToPreviousSpineItem()\n }\n\n return this.goToNextSpineItem()\n }\n\n goToRightOrBottomSpineItem() {\n if (this.reader.settings.values.computedPageTurnDirection === \"vertical\") {\n return this.goToBottomSpineItem()\n }\n\n return this.goToRightSpineItem()\n }\n\n goToLeftOrTopSpineItem() {\n if (this.reader.settings.values.computedPageTurnDirection === \"vertical\") {\n return this.goToTopSpineItem()\n }\n\n return this.goToLeftSpineItem()\n }\n\n goToLeftSpineItem() {\n if (this.reader.settings.values.computedPageTurnDirection === \"vertical\") {\n navigationReport.warn(\n `You cannot call this navigation method on vertical direction`,\n )\n\n return\n }\n\n if (this.reader.context.isRTL()) {\n return this.goToNextSpineItem()\n }\n\n return this.goToPreviousSpineItem()\n }\n\n goToTopSpineItem() {\n if (\n this.reader.settings.values.computedPageTurnDirection === \"horizontal\"\n ) {\n navigationReport.warn(\n `You cannot call this navigation method on horizontal direction`,\n )\n\n return\n }\n\n return this.goToPreviousSpineItem()\n }\n\n goToBottomSpineItem() {\n if (\n this.reader.settings.values.computedPageTurnDirection === \"horizontal\"\n ) {\n navigationReport.warn(\n `You cannot call this navigation method on horizontal direction`,\n )\n\n return\n }\n\n return this.goToNextSpineItem()\n }\n\n goToPageOfSpineItem({\n pageIndex,\n spineItemId,\n ...rest\n }: {\n pageIndex: number\n spineItemId: string | number\n } & Pick<UserNavigationEntry, \"animation\">) {\n const position =\n this.reader.navigation.navigationResolver.getNavigationForSpineItemPage({\n pageIndex,\n spineItemId,\n })\n\n navigationReport.debug(`.goToPageOfSpineItem()`, {\n pageIndex,\n spineItemId,\n ...rest,\n position,\n })\n\n this.reader.navigation.navigate({\n position,\n ...rest,\n })\n }\n\n goToAbsolutePageIndex({\n absolutePageIndex,\n ...rest\n }: { absolutePageIndex: number } & Pick<UserNavigationEntry, \"animation\">) {\n const foundInfo =\n this.reader.spine.pages.fromAbsolutePageIndex(absolutePageIndex)\n\n navigationReport.debug(`.goToAbsolutePageIndex()`, {\n absolutePageIndex,\n ...rest,\n foundInfo,\n })\n\n if (foundInfo) {\n const position =\n this.reader.navigation.navigationResolver.getNavigationForSpineItemPage(\n {\n pageIndex: foundInfo.pageIndex,\n spineItemId: foundInfo.itemIndex,\n },\n )\n\n return this.reader.navigation.navigate({\n position,\n ...rest,\n })\n }\n }\n}\n","import type { Reader } from \"../../../reader\"\nimport { SpinePosition, type UnboundSpinePosition } from \"../../../spine/types\"\nimport { ReactiveEntity } from \"../../../utils/ReactiveEntity\"\nimport { navigationReport } from \"../report\"\nexport class PanNavigator extends ReactiveEntity<{\n lastDelta: { x: number; y: number }\n lastPosition: SpinePosition | UnboundSpinePosition\n lastStartPosition: SpinePosition\n isStarted: boolean\n}> {\n unlock: ReturnType<Reader[\"navigation\"][\"lock\"]> | undefined = undefined\n\n constructor(protected reader: Reader) {\n super({\n lastDelta: { x: 0, y: 0 },\n lastPosition: new SpinePosition({ x: 0, y: 0 }),\n lastStartPosition: new SpinePosition({ x: 0, y: 0 }),\n isStarted: false,\n })\n }\n\n start(delta: { x: number; y: number }) {\n this.unlock?.()\n this.unlock = this.reader.navigation.lock()\n\n this.mergeCompare({\n isStarted: true,\n lastDelta: delta,\n lastStartPosition:\n this.reader.navigation.controlledNavigationController.viewportPosition,\n lastPosition:\n this.reader.navigation.controlledNavigationController.viewportPosition,\n })\n }\n\n stop(delta: { x: number; y: number }) {\n this.panMoveTo(delta)\n\n this.mergeCompare({\n isStarted: false,\n })\n\n this.unlock?.()\n }\n\n panMoveTo(delta: { x: number; y: number } | undefined) {\n if (this.reader.settings.values.computedPageTurnMode === `scrollable`) {\n navigationReport.warn(\n `pan control is not available on free page turn mode`,\n )\n\n return\n }\n\n if (!this.value.isStarted) {\n navigationReport.error(`Pan navigator is not started`)\n\n return\n }\n\n const pageTurnDirection =\n this.reader.settings.values.computedPageTurnDirection\n\n let navigation: SpinePosition | UnboundSpinePosition =\n this.reader.navigation.getNavigation().position\n\n if (delta) {\n const viewportScale =\n this.reader.viewport.absoluteViewport.width /\n this.reader.viewport.relativeViewport.width\n /**\n * We floor the delta to avoid having wrong direction derived because of\n * some sub pixel difference due to gesture precision\n */\n const correctedX = Math.floor(delta.x) - (this.value.lastDelta?.x || 0)\n const correctedY = Math.floor(delta.y) - (this.value.lastDelta?.y || 0)\n const x = Math.floor(\n pageTurnDirection === `horizontal`\n ? this.value.lastPosition.x - correctedX / viewportScale\n : 0,\n )\n const y = Math.floor(\n pageTurnDirection === `horizontal`\n ? 0\n : this.value.lastPosition.y - correctedY / viewportScale,\n )\n\n navigation = new SpinePosition({\n x,\n y,\n })\n\n this.mergeCompare({\n lastDelta: delta,\n })\n } else {\n navigation = this.value.lastPosition\n }\n\n this.mergeCompare({\n lastPosition: navigation,\n })\n\n this.reader.navigation.navigate({\n position: navigation,\n animation: false,\n })\n }\n}\n","import { Subject } from \"rxjs\"\n\nexport class DestroyableClass {\n protected isDestroyed = false\n private destroySubject = new Subject<void>()\n\n protected destroy$ = this.destroySubject.asObservable()\n\n public destroy() {\n if (this.isDestroyed) return\n\n this.isDestroyed = true\n\n this.destroySubject.next()\n this.destroySubject.complete()\n }\n}\n","import {\n animationFrameScheduler,\n debounceTime,\n exhaustMap,\n finalize,\n first,\n merge,\n of,\n Subject,\n takeUntil,\n tap,\n} from \"rxjs\"\nimport type { ScrollNavigationController } from \"../../../navigation/controllers/ScrollNavigationController\"\nimport type { Locker } from \"../../../navigation/Locker\"\nimport type { UserNavigationEntry } from \"../../../navigation/types\"\nimport { DestroyableClass } from \"../../../utils/DestroyableClass\"\n\nconst SCROLL_FINISHED_DEBOUNCE_TIMEOUT = 500\n\nexport class UserScrollNavigation extends DestroyableClass {\n /**\n * Navigation from external API.\n *\n * This is the navigation used by navigators and is not necessarily valid.\n * We need to verify and adjust the correct navigation afterward\n */\n protected navigationSubject = new Subject<UserNavigationEntry>()\n\n public navigation$ = this.navigationSubject.asObservable()\n\n constructor(\n protected scrollNavigationController: ScrollNavigationController,\n protected locker: Locker,\n ) {\n super()\n\n /**\n * Update the navigation as the user scroll.\n *\n * Keep it synchronized with scrolling. This should\n * not trigger viewport navigation, only update internal navigation.\n */\n const navigateOnScroll$ = this.scrollNavigationController.userScroll$.pipe(\n exhaustMap((event) => {\n const unlock = this.locker.lock()\n\n return merge(\n this.scrollNavigationController.userScroll$,\n of(event),\n ).pipe(\n debounceTime(\n SCROLL_FINISHED_DEBOUNCE_TIMEOUT,\n animationFrameScheduler,\n ),\n first(),\n tap(() => {\n const spinePosition =\n this.scrollNavigationController.fromScrollPosition(\n this.scrollNavigationController.scrollPosition,\n )\n\n this.navigationSubject.next({\n animation: false,\n type: \"scroll\",\n position: spinePosition,\n })\n }),\n finalize(() => {\n unlock()\n }),\n )\n }),\n )\n\n merge(navigateOnScroll$).pipe(takeUntil(this.destroy$)).subscribe()\n }\n}\n","import { distinctUntilChanged, map, withLatestFrom } from \"rxjs\"\nimport type { Reader } from \"../../reader\"\nimport { isShallowEqual } from \"../../utils/objects\"\n\nexport type State = ReturnType<typeof observeState>\n\nexport const observeState = (reader: Reader) => {\n return reader.pagination.state$.pipe(\n withLatestFrom(reader.context.manifest$, reader.settings.values$),\n map(\n ([\n paginationInfo,\n { spineItems, readingDirection },\n { computedPageTurnDirection },\n ]) => {\n const numberOfSpineItems = spineItems.length ?? 0\n const isAtAbsoluteBeginning = paginationInfo.beginSpineItemIndex === 0\n const isAtAbsoluteEnd =\n paginationInfo.endSpineItemIndex ===\n Math.max(numberOfSpineItems - 1, 0)\n\n const isAtEndSpineItem =\n paginationInfo.endSpineItemIndex ===\n Math.max(numberOfSpineItems - 1, 0)\n\n const isAtBeginSpineItem = paginationInfo.beginSpineItemIndex === 0\n\n const isAtBeginFirstPage =\n paginationInfo.beginPageIndexInSpineItem === 0\n\n const isAtEndLastPage =\n paginationInfo.endPageIndexInSpineItem ===\n paginationInfo.endNumberOfPagesInSpineItem - 1\n\n return {\n canTurnLeft:\n computedPageTurnDirection === \"vertical\"\n ? false\n : !isAtBeginFirstPage,\n canTurnRight:\n computedPageTurnDirection === \"vertical\" ? false : !isAtEndLastPage,\n canGoTopSpineItem:\n computedPageTurnDirection === \"vertical\" && !isAtAbsoluteBeginning,\n canGoBottomSpineItem:\n computedPageTurnDirection === \"vertical\" && !isAtAbsoluteEnd,\n canGoLeftSpineItem:\n computedPageTurnDirection !== \"vertical\" &&\n ((readingDirection === \"ltr\" && !isAtAbsoluteBeginning) ||\n (readingDirection === \"rtl\" && !isAtEndSpineItem)),\n canGoRightSpineItem:\n computedPageTurnDirection !== \"vertical\" &&\n ((readingDirection === \"ltr\" && !isAtAbsoluteEnd) ||\n (readingDirection === \"rtl\" && !isAtBeginSpineItem)),\n }\n },\n ),\n distinctUntilChanged(isShallowEqual),\n )\n}\n","import {\n animationFrameScheduler,\n finalize,\n type Observable,\n tap,\n throttleTime,\n} from \"rxjs\"\nimport type { Reader } from \"../../reader\"\n\nexport const throttleLock =\n ({ reader, duration }: { reader: Reader; duration: number }) =>\n <T>(stream: Observable<T>) => {\n let unlockFn: (() => void) | undefined\n const unlock = () => {\n unlockFn?.()\n unlockFn = undefined\n }\n\n return stream.pipe(\n tap(() => {\n if (!unlockFn) {\n unlockFn = reader?.navigation.lock()\n }\n }),\n throttleTime(duration, animationFrameScheduler, {\n trailing: true,\n leading: true,\n }),\n tap(unlock),\n finalize(unlock),\n )\n }\n","import { merge, takeUntil, tap } from \"rxjs\"\nimport type { HtmlEnhancerOutput } from \"../html/enhancer\"\nimport type {\n EnhancerOptions,\n EnhancerOutput,\n RootEnhancer,\n} from \"../types/enhancer\"\nimport { handleLinksNavigation } from \"./links\"\nimport { ManualNavigator } from \"./navigators/manualNavigator\"\nimport { PanNavigator } from \"./navigators/panNavigator\"\nimport { UserScrollNavigation } from \"./navigators/UserScrollNavigation\"\nimport { observeState } from \"./state\"\nimport { throttleLock } from \"./throttleLock\"\nimport type { NavigationEnhancerOutput } from \"./types\"\n\nexport const navigationEnhancer =\n <\n InheritOptions extends EnhancerOptions<RootEnhancer>,\n InheritOutput extends EnhancerOutput<RootEnhancer> & HtmlEnhancerOutput,\n >(\n next: (options: InheritOptions) => InheritOutput,\n ) =>\n (\n options: InheritOptions,\n ): Omit<InheritOutput, \"load\"> & NavigationEnhancerOutput => {\n const reader = next(options)\n const state$ = observeState(reader)\n const manualNavigator = new ManualNavigator(reader)\n const panNavigator = new PanNavigator(reader)\n const userScrollNavigation = new UserScrollNavigation(\n reader.navigation.scrollNavigationController,\n reader.navigation.locker,\n )\n\n const linksNavigation$ = handleLinksNavigation(reader, manualNavigator)\n const navigateOnUserScroll$ = userScrollNavigation.navigation$.pipe(\n tap((navigation) => {\n reader.navigation.navigate(navigation)\n }),\n )\n\n merge(linksNavigation$, navigateOnUserScroll$)\n .pipe(takeUntil(reader.$.destroy$))\n .subscribe()\n\n const load: NavigationEnhancerOutput[\"load\"] = (options) => {\n const { cfi, ...rest } = options\n\n reader.load(rest)\n\n if (cfi) {\n manualNavigator.goToCfi(cfi, { animate: false })\n }\n }\n\n const destroy = () => {\n userScrollNavigation.destroy()\n reader.destroy()\n }\n\n return {\n ...reader,\n load,\n destroy,\n navigation: {\n ...reader.navigation,\n state$,\n throttleLock: ({ duration, trigger }) =>\n trigger.pipe(throttleLock({ duration, reader })),\n panNavigator,\n turnBottom: manualNavigator.turnBottom.bind(manualNavigator),\n turnTop: manualNavigator.turnTop.bind(manualNavigator),\n turnLeftOrTop: manualNavigator.turnLeftOrTop.bind(manualNavigator),\n turnRightOrBottom:\n manualNavigator.turnRightOrBottom.bind(manualNavigator),\n turnLeft: manualNavigator.turnLeft.bind(manualNavigator),\n turnRight: manualNavigator.turnRight.bind(manualNavigator),\n goToCfi: manualNavigator.goToCfi.bind(manualNavigator),\n goToUrl: manualNavigator.goToUrl.bind(manualNavigator),\n goToSpineItem: manualNavigator.goToSpineItem.bind(manualNavigator),\n goToNextSpineItem:\n manualNavigator.goToNextSpineItem.bind(manualNavigator),\n goToPreviousSpineItem:\n manualNavigator.goToPreviousSpineItem.bind(manualNavigator),\n goToLeftOrTopSpineItem:\n manualNavigator.goToLeftOrTopSpineItem.bind(manualNavigator),\n goToRightOrBottomSpineItem:\n manualNavigator.goToRightOrBottomSpineItem.bind(manualNavigator),\n goToTopSpineItem:\n manualNavigator.goToTopSpineItem.bind(manualNavigator),\n goToBottomSpineItem:\n manualNavigator.goToBottomSpineItem.bind(manualNavigator),\n goToLeftSpineItem:\n manualNavigator.goToLeftSpineItem.bind(manualNavigator),\n goToRightSpineItem:\n manualNavigator.goToRightSpineItem.bind(manualNavigator),\n goToPageOfSpineItem:\n manualNavigator.goToPageOfSpineItem.bind(manualNavigator),\n goToAbsolutePageIndex:\n manualNavigator.goToAbsolutePageIndex.bind(manualNavigator),\n },\n }\n }\n","import { map, startWith } from \"rxjs\"\nimport type { Reader } from \"../../reader\"\nimport type { Manifest } from \"@prose-reader/shared\"\n\n/**\n * @todo\n * Using recursive here provoke this error\n * https://www.google.com/search?q=recursive+Exported+variable+has+or+is+using+namefrom+external+module+but+cannot+be+named.&rlz=1C5CHFA_en&sxsrf=AOaemvK4craypli45-fXfFRdfO82ibGRog%3A1631106978791&ei=orc4YZPUL-6tmAWJgKT4Dw&oq=recursive+Exported+variable+has+or+is+using+namefrom+external+module+but+cannot+be+named.&gs_lcp=Cgdnd3Mtd2l6EAM6BwgAEEcQsANKBAhBGABQjgdYjgdgtQtoAnACeACAAWGIAWGSAQExmAEAoAEByAEIwAEB&sclient=gws-wiz&ved=0ahUKEwiTrb6Au-_yAhXuFqYKHQkACf8Q4dUDCA4&uact=5\n * My guess is that something is wrong and I have too many recursive / inferred types everywhere and especially on the enhancer thingy.\n */\nexport type ChapterInfo = {\n title: string\n subChapter?: {\n title: string\n subChapter?: {\n title: string\n subChapter?: {\n title: string\n path: string\n }\n path: string\n }\n path: string\n }\n path: string\n}\n\n/**\n * @important it's important to compare only path vs path and or href vs href since\n * they have not comparable due to possible encoded values\n */\nconst buildChaptersInfo = (\n href: string,\n tocItem: NonNullable<Manifest[\"nav\"]>[\"toc\"],\n manifest: Manifest,\n): ChapterInfo | undefined => {\n const spineItemIndex = manifest.spineItems.findIndex(\n (item) => item.href === href,\n )\n\n return tocItem.reduce((acc: ChapterInfo | undefined, tocItem) => {\n const indexOfHash = tocItem.href.indexOf(`#`)\n const tocItemPathWithoutAnchor =\n indexOfHash > 0 ? tocItem.href.substr(0, indexOfHash) : tocItem.href\n const tocItemHrefWithoutFilename = tocItemPathWithoutAnchor.substring(\n 0,\n tocItemPathWithoutAnchor.lastIndexOf(\"/\"),\n )\n const hrefWithoutFilename = href.substring(0, href.lastIndexOf(\"/\"))\n\n const hrefIsChapterHref = href.endsWith(tocItemPathWithoutAnchor)\n const hrefIsWithinChapter =\n hrefWithoutFilename !== \"\" &&\n hrefWithoutFilename.endsWith(tocItemHrefWithoutFilename)\n\n /**\n * @important\n * A possible toc item candidate means that the chapter is at least not after the item.\n * It does not mean it's the correct chapter. The algorithm proceed by reducing every item\n * until we find the one that is not. We then return the last found one.\n *\n * This is the most important piece as it's the reason why we can detect all the pages\n * within a chapter.\n *\n * We rely on the order of items to be true. See https://www.w3.org/publishing/epub3/epub-packages.html#sec-nav-toc\n */\n const isPossibleTocItemCandidate = hrefIsChapterHref || hrefIsWithinChapter\n\n if (isPossibleTocItemCandidate) {\n const spineItemIndexOfPossibleCandidate = manifest.spineItems.findIndex(\n (item) => item.href === tocItem.href,\n )\n const spineItemIsBeforeThisTocItem =\n spineItemIndex < spineItemIndexOfPossibleCandidate\n\n if (spineItemIsBeforeThisTocItem) return acc\n\n const info = {\n title: tocItem.title,\n path: tocItem.path,\n }\n\n const subInfo = buildChaptersInfo(href, tocItem.contents, manifest)\n\n if (subInfo) {\n return {\n ...info,\n subChapter: subInfo,\n }\n }\n\n return info\n }\n\n return acc\n }, undefined)\n}\n\nconst buildChapterInfoFromSpineItem = (\n manifest: Manifest,\n item: Manifest[`spineItems`][number],\n) => {\n const { href } = item\n\n return buildChaptersInfo(href, manifest.nav?.toc ?? [], manifest)\n}\n\nexport const getChaptersInfo = (\n reader: Reader,\n): { [key: string]: ChapterInfo | undefined } => {\n const manifest = reader.context.manifest\n const items = reader.spineItemsManager.items\n\n if (!manifest) return {}\n\n return items.reduce(\n (acc, { item }) => {\n acc[item.id] = buildChapterInfoFromSpineItem(manifest, item)\n\n return acc\n },\n {} as { [key: string]: ChapterInfo | undefined },\n )\n}\n\nexport const trackChapterInfo = (reader: Reader) => {\n return reader.spineItemsManager.items$.pipe(\n startWith([]),\n map(() => getChaptersInfo(reader)),\n )\n}\n","import { first, map, withLatestFrom } from \"rxjs\"\nimport type { Reader } from \"../../reader\"\nimport type { SpineItem } from \"../../spineItem/SpineItem\"\nimport type { LayoutEnhancerOutput } from \"../layout/layoutEnhancer\"\n\nconst getTotalProgressFromPercentages = (\n estimateBeforeThisItem: number,\n currentItemWeight: number,\n progressWithinThisItem: number,\n) => {\n return estimateBeforeThisItem + currentItemWeight * progressWithinThisItem\n}\n\nconst getScrollPercentageWithinItem = (\n reader: Reader,\n currentPosition: { x: number; y: number },\n currentItem: SpineItem,\n) => {\n const { height, width } = currentItem.layoutInfo\n\n const { top, left } = reader.spine.getSpineItemSpineLayoutInfo(currentItem)\n\n if (reader.settings.values.computedPageTurnDirection === `vertical`) {\n return Math.max(\n 0,\n Math.min(\n 1,\n (currentPosition.y - top + reader.viewport.absoluteViewport.height) /\n height,\n ),\n )\n }\n return Math.max(\n 0,\n Math.min(\n 1,\n (currentPosition.x - left + reader.viewport.absoluteViewport.width) /\n width,\n ),\n )\n}\n\nexport const getPercentageEstimate = (\n reader: Reader & LayoutEnhancerOutput,\n currentSpineIndex: number,\n pageIndex: number,\n currentPosition: { x: number; y: number },\n currentItem: SpineItem,\n) => {\n return currentItem.isReady$.pipe(\n first(),\n withLatestFrom(reader.layoutInfo$),\n map(([itemIsReady, layout]) => {\n const context = reader.context\n\n const isGloballyPrePaginated =\n context.manifest?.renditionLayout === `pre-paginated`\n const readingOrderLength = context.manifest?.spineItems.length || 0\n const estimateBeforeThisItem =\n context.manifest?.spineItems\n .slice(0, currentSpineIndex)\n .reduce((acc, item) => acc + (item.progressionWeight ?? 0), 0) || 0\n const itemIndexNumber =\n reader.spineItemsManager.getSpineItemIndex(currentItem) ?? 0\n\n const numberOfSpineItems = reader.context.manifest?.spineItems.length ?? 0\n\n const spineItemNumberOfPages =\n layout.pages.filter((page) => page.itemIndex === itemIndexNumber)\n .length ?? 0\n\n const currentItemWeight =\n context.manifest?.spineItems[currentSpineIndex]?.progressionWeight ??\n // if no progressionWeight is defined we \"assume\" the document weight to be\n // relative to the total number of documents\n (itemIndexNumber + 1) / numberOfSpineItems\n\n let progressWithinThisItem =\n (pageIndex + 1) * (currentItemWeight / spineItemNumberOfPages)\n\n if (\n !isGloballyPrePaginated &&\n currentItem.renditionLayout === `reflowable` &&\n !itemIsReady\n ) {\n progressWithinThisItem = 0\n }\n\n let totalProgress = estimateBeforeThisItem + progressWithinThisItem\n\n if (context.manifest?.renditionFlow === `scrolled-continuous`) {\n if (itemIsReady) {\n progressWithinThisItem = getScrollPercentageWithinItem(\n reader,\n currentPosition,\n currentItem,\n )\n } else {\n // that way we avoid having a progress of 1 just because the item is not loaded and cover all screen due to smaller size.\n // Therefore it effectively prevent jump from 30% to 25% for example.\n progressWithinThisItem = 0\n }\n totalProgress = getTotalProgressFromPercentages(\n estimateBeforeThisItem,\n currentItemWeight,\n progressWithinThisItem,\n )\n }\n\n // because the rounding of weight use a lot of decimals we will end up with\n // something like 0.999878 for the last page\n if (\n currentSpineIndex === readingOrderLength - 1 &&\n pageIndex === spineItemNumberOfPages - 1 &&\n totalProgress > 0.99\n ) {\n return 1\n }\n\n return totalProgress\n }),\n )\n}\n","import {\n animationFrameScheduler,\n debounceTime,\n distinctUntilChanged,\n map,\n type Observable,\n startWith,\n withLatestFrom,\n} from \"rxjs\"\nimport type { Reader } from \"../../reader\"\nimport { isShallowEqual } from \"../../utils/objects\"\n\nexport const trackTotalPages = (reader: Reader) => {\n const totalPages$: Observable<{\n numberOfPagesPerItems: number[]\n numberOfTotalPages: number\n }> = reader.spine.layout$.pipe(\n debounceTime(10, animationFrameScheduler),\n withLatestFrom(reader.pagination.state$),\n map(() => {\n return {\n numberOfPagesPerItems: reader.spineItemsManager.items.reduce(\n (acc, item) => {\n return [...acc, item.numberOfPages]\n },\n [] as number[],\n ),\n /**\n * This may be not accurate for reflowable due to dynamic load / unload.\n */\n numberOfTotalPages: reader.spine.pages.value.pages.length,\n }\n }),\n distinctUntilChanged(isShallowEqual),\n startWith({\n numberOfPagesPerItems: [],\n numberOfTotalPages: 0,\n }),\n )\n\n return totalPages$\n}\n","import {\n BehaviorSubject,\n combineLatest,\n distinctUntilChanged,\n map,\n type Observable,\n type ObservedValueOf,\n of,\n shareReplay,\n switchMap,\n tap,\n} from \"rxjs\"\nimport type { PaginationInfo } from \"../../pagination/types\"\nimport type { Reader } from \"../../reader\"\nimport { isShallowEqual } from \"../../utils/objects\"\nimport type { LayoutEnhancerOutput } from \"../layout/layoutEnhancer\"\nimport { trackChapterInfo } from \"./chapters\"\nimport { getPercentageEstimate } from \"./progression\"\nimport { trackTotalPages } from \"./spine\"\nimport type { EnhancerPaginationInto, ExtraPaginationInfo } from \"./types\"\n\nexport const mapPaginationInfoToExtendedInfo = (\n reader: Reader,\n paginationInfo: PaginationInfo,\n chaptersInfo: ObservedValueOf<ReturnType<typeof trackChapterInfo>>,\n percentageEstimateOfBook: number,\n): Observable<\n Omit<\n ExtraPaginationInfo,\n | \"beginAbsolutePageIndex\"\n | \"endAbsolutePageIndex\"\n | \"beginAbsolutePageIndex\"\n | \"numberOfTotalPages\"\n >\n> => {\n const beginItem =\n paginationInfo.beginSpineItemIndex !== undefined\n ? reader.spineItemsManager.get(paginationInfo.beginSpineItemIndex)\n : undefined\n const endItem =\n paginationInfo.endSpineItemIndex !== undefined\n ? reader.spineItemsManager.get(paginationInfo.endSpineItemIndex)\n : undefined\n\n return of({\n ...paginationInfo,\n beginChapterInfo: beginItem ? chaptersInfo[beginItem.item.id] : undefined,\n // chapterIndex: number;\n // pages: number;\n // pageIndexInBook: number;\n // pageIndexInChapter: number;\n // pagesOfChapter: number;\n // pagePercentageInChapter: number;\n // offsetPercentageInChapter: number;\n // domIndex: number;\n // charOffset: number;\n // serializeString?: string;\n beginSpineItemReadingDirection: beginItem?.readingDirection,\n endChapterInfo: endItem ? chaptersInfo[endItem.item.id] : undefined,\n endSpineItemReadingDirection: endItem?.readingDirection,\n // spineItemReadingDirection: focusedSpineItem?.getReadingDirection(),\n /**\n * This percentage is based of the weight (kb) of every items and the number of pages.\n * It is not accurate but gives a general good idea of the overall progress.\n * It is recommended to use this progress only for reflow books. For pre-paginated books\n * the number of pages and current index can be used instead since 1 page = 1 chapter.\n */\n percentageEstimateOfBook,\n isUsingSpread: reader.settings.values.computedSpreadMode ?? false,\n // hasNextChapter: (reader.spine.spineItemIndex || 0) < (manifest.readingOrder.length - 1),\n // hasPreviousChapter: (reader.spine.spineItemIndex || 0) < (manifest.readingOrder.length - 1),\n // numberOfSpineItems: context.manifest?.readingOrder.length,\n })\n}\n\nconst observeProgression = (reader: Reader & LayoutEnhancerOutput) => {\n return combineLatest([\n reader.pagination.state$,\n // Usually pagination change if layout changes (number of pages) however it is especially\n // useful for like webtoon where you still have one page but only the layout will give you the final size\n // although the pagination will stay stable from the begining\n reader.layout$,\n ]).pipe(\n switchMap(([paginationInfo]) => {\n const endItem =\n paginationInfo.endSpineItemIndex !== undefined\n ? reader.spineItemsManager.get(paginationInfo.endSpineItemIndex)\n : undefined\n\n return endItem\n ? getPercentageEstimate(\n reader,\n paginationInfo.endSpineItemIndex ?? 0,\n paginationInfo.endPageIndexInSpineItem || 0,\n reader.navigation.getNavigation().position,\n endItem,\n )\n : of(0)\n }),\n )\n}\n\nexport const trackPaginationInfo = (reader: Reader & LayoutEnhancerOutput) => {\n const chaptersInfo$ = trackChapterInfo(reader)\n const totalPages$ = trackTotalPages(reader)\n const currentValue = new BehaviorSubject<EnhancerPaginationInto>({\n ...reader.pagination.state,\n beginChapterInfo: undefined,\n beginCfi: undefined,\n beginPageIndexInSpineItem: undefined,\n isUsingSpread: false,\n beginAbsolutePageIndex: 0,\n endAbsolutePageIndex: 0,\n numberOfTotalPages: 0,\n beginSpineItemReadingDirection: undefined,\n beginSpineItemIndex: undefined,\n endCfi: undefined,\n endChapterInfo: undefined,\n endSpineItemReadingDirection: undefined,\n percentageEstimateOfBook: 0,\n })\n\n const extandedBasePagination$ = combineLatest([\n reader.pagination.state$,\n chaptersInfo$,\n observeProgression(reader),\n ]).pipe(\n switchMap(([info, chaptersInfo, percentageEstimateOfBook]) =>\n mapPaginationInfoToExtendedInfo(\n reader,\n info,\n chaptersInfo,\n percentageEstimateOfBook,\n ).pipe(\n map((extendedInfo) => ({\n ...info,\n ...extendedInfo,\n })),\n ),\n ),\n distinctUntilChanged(isShallowEqual),\n )\n\n const paginationInfo$: Observable<EnhancerPaginationInto> = combineLatest([\n extandedBasePagination$,\n totalPages$,\n ]).pipe(\n map(([pageInfo, totalPageInfo]) => ({\n ...pageInfo,\n ...totalPageInfo,\n beginAbsolutePageIndex: totalPageInfo.numberOfPagesPerItems\n .slice(0, pageInfo.beginSpineItemIndex)\n .reduce(\n (acc, numberOfPagesForItem) => acc + numberOfPagesForItem,\n pageInfo.beginPageIndexInSpineItem ?? 0,\n ),\n endAbsolutePageIndex: totalPageInfo.numberOfPagesPerItems\n .slice(0, pageInfo.endSpineItemIndex)\n .reduce(\n (acc, numberOfPagesForItem) => acc + numberOfPagesForItem,\n pageInfo.endPageIndexInSpineItem ?? 0,\n ),\n })),\n tap((value) => {\n currentValue.next(value)\n }),\n shareReplay(1),\n )\n\n return { paginationInfo$, getPaginationInfo: () => currentValue.value }\n}\n","import { generate } from \"@prose-reader/cfi\"\nimport type { Manifest } from \"@prose-reader/shared\"\nimport type { PageEntry } from \"../spine/Pages\"\nimport { isHtmlRange } from \"../utils/dom\"\n\nexport const generateRootCfi = (item: Manifest[\"spineItems\"][number]) => {\n return generate({\n spineIndex: item.index,\n spineId: item.id,\n })\n}\n\nconst generateCfi = ({\n nodeOrRange,\n offset,\n item,\n}: {\n nodeOrRange: Node | Range\n offset?: number\n item: Manifest[\"spineItems\"][number]\n}) => {\n const nodeOrRangeOwnerDocument =\n \"ownerDocument\" in nodeOrRange\n ? nodeOrRange.ownerDocument\n : nodeOrRange.startContainer.ownerDocument\n\n if (\n !nodeOrRangeOwnerDocument ||\n !nodeOrRangeOwnerDocument?.documentElement ||\n nodeOrRange === nodeOrRangeOwnerDocument\n )\n return generateRootCfi(item)\n\n if (isHtmlRange(nodeOrRange)) {\n return generate({\n start: {\n node: nodeOrRange.startContainer,\n offset: nodeOrRange.startOffset,\n spineIndex: item.index,\n spineId: item.id,\n },\n end: {\n node: nodeOrRange.endContainer,\n offset: nodeOrRange.endOffset,\n spineIndex: item.index,\n spineId: item.id,\n },\n })\n }\n\n return generate({\n node: nodeOrRange,\n offset,\n spineIndex: item.index,\n spineId: item.id,\n })\n}\n\n/**\n * Heavy cfi hookup. Use it to have a refined, precise cfi anchor. It requires the content to be loaded otherwise\n * it will return a root cfi.\n *\n * @todo optimize\n */\nexport const generateCfiForSpineItemPage = ({\n spineItem,\n pageNode,\n}: {\n spineItem: Manifest[\"spineItems\"][number]\n pageNode: NonNullable<PageEntry[\"firstVisibleNode\"]>\n}) => {\n const cfiString = generateCfi({\n nodeOrRange: pageNode.node,\n offset: pageNode.offset,\n item: spineItem,\n })\n\n return cfiString.trim()\n}\n\nexport const generateCfiFromRange = (\n range: Range,\n item: Manifest[`spineItems`][number],\n) => {\n return generateCfi({\n nodeOrRange: range,\n item,\n })\n}\n\nexport const getItemAnchor = (item: Manifest[\"spineItems\"][number]) =>\n item.index.toString()\n","import {\n type CfiPart,\n isIndirectionOnly,\n isParsedCfiRange,\n type ParsedCfi,\n parse,\n} from \"@prose-reader/cfi\"\n\nexport type ProseParsedCfi = {\n isCfiRange: boolean\n itemIndex: number\n}\n\nconst hasIndirectionMarker = (part: CfiPart[]) => {\n return part[0]?.index === 6 && part.length > 1\n}\n\n/**\n * Root CFI are prose specific CFI that start with /0.\n * They are used when the item is not loaded and we have no other information\n * for the CFI available but still want to generate a CFI. This is the equivalent\n * of a fake CFI.\n */\nexport const isRootCfi = (cfi: string) => {\n const parsed = parse(cfi)\n\n return isIndirectionOnly(parsed)\n}\n\nconst extractIndirectionPart = (parsedCfi: ParsedCfi) => {\n return Array.isArray(parsedCfi)\n ? parsedCfi[0] && hasIndirectionMarker(parsedCfi[0])\n ? parsedCfi[0]\n : undefined\n : parsedCfi.parent[0] && hasIndirectionMarker(parsedCfi.parent[0])\n ? parsedCfi.parent[0]\n : undefined\n}\n\nexport const parseCfi = (cfi: string): ProseParsedCfi & { offset: number } => {\n const parsedCfi = parse(cfi)\n const indirectionPart = extractIndirectionPart(parsedCfi)\n const itemIndexPart = (indirectionPart ?? [])[1]\n const parsedSpineItemIndex = itemIndexPart?.index ?? 2\n const spineItemIndex = parsedSpineItemIndex / 2 - 1\n const isCfiRange = isParsedCfiRange(parsedCfi)\n const offset = isCfiRange\n ? parsedCfi.end.at(-1)?.at(-1)?.offset\n : parsedCfi.at(-1)?.at(-1)?.offset\n\n return {\n isCfiRange,\n itemIndex: spineItemIndex,\n offset: offset ?? 0,\n }\n}\n","import { resolve } from \"@prose-reader/cfi\"\nimport { Report } from \"../report\"\nimport type { SpineItemsManager } from \"../spine/SpineItemsManager\"\nimport type { SpineItem } from \"../spineItem/SpineItem\"\nimport { parseCfi } from \"./parse\"\n\n/**\n * Returns the node and offset for the given cfi.\n *\n * A CFI can only resolve if the item is loaded.\n *\n * @important\n * This is up to you to resolve CFI at the right time. Trying to resolve a CFI to an invalid\n * document will raise a warning but not crash.\n */\nexport const resolveCfi = ({\n cfi,\n spineItemsManager,\n}: {\n cfi: string\n spineItemsManager: SpineItemsManager\n}): Omit<ReturnType<typeof parseCfi>, \"offset\"> & {\n offset?: number | undefined\n node: Node | null\n range?: Range | null\n spineItem?: SpineItem\n} => {\n const { itemIndex, ...restParsed } = parseCfi(cfi)\n\n const spineItem = spineItemsManager.get(itemIndex)\n\n if (!spineItem)\n return {\n ...restParsed,\n itemIndex,\n node: null,\n }\n\n const rendererElement = spineItem.renderer.getDocumentFrame()\n\n if (rendererElement instanceof HTMLIFrameElement) {\n const doc = rendererElement.contentWindow?.document\n\n if (doc) {\n try {\n const resolved = resolve(cfi, doc, {\n throwOnError: true,\n })\n\n return {\n ...restParsed,\n itemIndex,\n node: resolved.isRange\n ? (resolved.node?.startContainer ?? null)\n : (resolved.node ?? null),\n isCfiRange: resolved.isRange,\n range: resolved.isRange ? resolved.node : undefined,\n offset: Array.isArray(resolved.offset)\n ? resolved.offset.at(-1)\n : resolved.offset,\n spineItem,\n }\n } catch (e) {\n Report.warn(`Error resolving cfi: ${cfi}.`)\n Report.warn(e)\n\n return {\n ...restParsed,\n spineItem,\n itemIndex,\n node: null,\n }\n }\n }\n }\n\n return {\n ...restParsed,\n itemIndex,\n spineItem,\n node: null,\n }\n}\n","import {\n combineLatest,\n debounceTime,\n defaultIfEmpty,\n finalize,\n map,\n type Observable,\n of,\n shareReplay,\n startWith,\n switchScan,\n withLatestFrom,\n} from \"rxjs\"\nimport {\n generateRootCfi,\n type ProseParsedCfi,\n type resolveCfi,\n} from \"../../cfi\"\nimport type { Reader } from \"../../reader\"\nimport type { SpineItem } from \"../../spineItem/SpineItem\"\nimport { deferIdle, idle } from \"../../utils/rxjs\"\n\ntype CfiLocatableResource = {\n cfi: string\n}\n\nexport type LocatableResource = SpineItem | CfiLocatableResource\n\nexport type ConsolidatedResource = ReturnType<typeof resolveCfi> &\n ProseParsedCfi &\n CfiLocatableResource & {\n itemPageIndex?: number\n absolutePageIndex?: number\n startOffset?: number\n range?: Range | null\n }\n\nconst toCfiLocatableResource = (\n reader: Reader,\n resource: LocatableResource | CfiLocatableResource,\n): ConsolidatedResource => {\n if (\"cfi\" in resource) {\n const { itemIndex, ...restParsedCfi } = reader.cfi.parseCfi(resource.cfi)\n\n return {\n ...resource,\n ...restParsedCfi,\n itemIndex,\n node: null,\n }\n }\n\n const item = reader.spineItemsManager.get(resource)\n\n if (!item) {\n throw new Error(`Spine item not found`)\n }\n\n const cfi = generateRootCfi(item.item)\n\n const parsedCfi = reader.cfi.parseCfi(cfi)\n\n return {\n ...parsedCfi,\n cfi: generateRootCfi(item.item),\n itemIndex: item.index,\n node: null,\n }\n}\n\nexport const consolidate = (\n resource: ConsolidatedResource,\n reader: Reader,\n): Observable<ConsolidatedResource> => {\n let itemPageIndex = resource?.itemPageIndex\n const { itemIndex, ...restParsedCfi } = reader.cfi.parseCfi(resource.cfi)\n const spineItem = reader.spineItemsManager.get(itemIndex)\n\n if (!spineItem) return of({ ...resource, itemIndex, ...restParsedCfi })\n\n return idle().pipe(\n withLatestFrom(spineItem.isReady$),\n map(([, isSpineItemReady]) => {\n const {\n node = null,\n offset: startOffset,\n range,\n } = isSpineItemReady ? reader.cfi.resolveCfi({ cfi: resource.cfi }) : {}\n\n const reflowableItemWithFoundNode =\n spineItem.renditionLayout !== `pre-paginated` && node\n\n if (reflowableItemWithFoundNode) {\n itemPageIndex =\n reader.spine.locator.spineItemLocator.getSpineItemPageIndexFromNode(\n node,\n startOffset ?? 0,\n spineItem,\n ) ?? itemPageIndex\n }\n\n let absolutePageIndex = resource?.absolutePageIndex\n\n /**\n * No itemPageIndex resolved from cfi.\n * We fallback to 0.\n */\n if (itemPageIndex === undefined) {\n itemPageIndex = 0\n }\n\n absolutePageIndex =\n reader.spine.locator._getAbsolutePageIndexFromPageIndex({\n pageIndex: itemPageIndex,\n spineItemOrId: spineItem,\n }) ?? resource?.absolutePageIndex\n\n return {\n ...resource,\n ...restParsedCfi,\n range,\n itemIndex,\n node,\n startOffset,\n absolutePageIndex,\n itemPageIndex,\n }\n }),\n )\n}\n\ntype Options = {\n /**\n * does not load document if shallow\n */\n mode?: \"shallow\" | \"load\"\n}\n\n/**\n * @todo optimize and share as much as possible when several same items are retrieved\n */\nexport class ResourcesLocator {\n constructor(private reader: Reader) {}\n\n private locatorsByKey = new Map<\n string,\n {\n observerCount: number\n consolidate$: Observable<{\n resource: LocatableResource\n meta: ConsolidatedResource\n }>\n }\n >()\n\n private deregisterMemoizedStream = (key: string) => {\n const value = this.locatorsByKey.get(key)\n\n if (!value) return\n\n value.observerCount--\n\n if (value.observerCount === 0) {\n this.locatorsByKey.delete(key)\n }\n }\n\n locate = <T extends LocatableResource>(\n resource: T,\n options: Options,\n ): Observable<{ resource: T; meta: ConsolidatedResource }> => {\n const initialConsolidatedValue = {\n resource,\n meta: toCfiLocatableResource(this.reader, resource),\n }\n\n return deferIdle(() => {\n /**\n * We only force open reflowable spine items.\n * This is because page index and absolute pages can be retrieved on\n * a pre-paginated content without having to load it.\n */\n\n const item = this.reader.spineItemsManager.get(\n initialConsolidatedValue.meta.itemIndex ?? 0,\n )\n const isReflowable = item?.renditionLayout === `reflowable`\n\n const release =\n options.mode === \"shallow\" || !isReflowable || !item\n ? () => {}\n : this.reader.spine.spineItemsLoader.forceOpen([item.index])\n\n const key = \"cfi\" in resource ? resource.cfi : undefined\n const memoizedConsolidate$ = key ? this.locatorsByKey.get(key) : undefined\n\n const withRelease = (\n stream: Observable<{ resource: T; meta: ConsolidatedResource }>,\n ) => {\n return stream.pipe(\n finalize(() => {\n if (key) {\n this.deregisterMemoizedStream(key)\n }\n\n /**\n * Make sure we wait a bit so if the user re-locate right after\n * we don't have a flicker of unload/load. It helps stabilize\n * resubscribing.\n */\n setTimeout(() => {\n release()\n }, 1000)\n }),\n )\n }\n\n if (key && memoizedConsolidate$) {\n memoizedConsolidate$.observerCount++\n\n return withRelease(\n memoizedConsolidate$.consolidate$.pipe(\n map(({ resource, meta }) => ({\n resource: resource as T,\n meta: meta as ConsolidatedResource,\n })),\n ),\n )\n }\n\n const consolidate$ = this.reader.spine.layout$.pipe(\n debounceTime(10),\n startWith(initialConsolidatedValue),\n switchScan((acc) => {\n return consolidate(acc.meta, this.reader).pipe(\n map((consolidatedResource) => ({\n ...acc,\n meta: consolidatedResource,\n })),\n )\n }, initialConsolidatedValue),\n shareReplay({ refCount: true, bufferSize: 1 }),\n )\n\n if (key) {\n this.locatorsByKey.set(key, {\n observerCount: 1,\n consolidate$,\n })\n }\n\n return withRelease(consolidate$)\n })\n }\n\n locateResource<T extends LocatableResource>(\n resource: T,\n options?: Options,\n ): Observable<{ resource: T; meta: ConsolidatedResource }>\n locateResource<T extends LocatableResource>(\n resource: T[],\n options?: Options,\n ): Observable<{ resource: T; meta: ConsolidatedResource }[]>\n locateResource<T extends LocatableResource>(\n resource: T | T[],\n options?: Options,\n ):\n | Observable<{ resource: T; meta: ConsolidatedResource }>\n | Observable<{ resource: T; meta: ConsolidatedResource }[]> {\n if (Array.isArray(resource)) {\n return deferIdle(() =>\n combineLatest(\n resource.map((item) => this.locate(item, options ?? {})),\n ).pipe(defaultIfEmpty([])),\n )\n }\n\n return this.locate(resource, options ?? {})\n }\n}\n","import { takeUntil } from \"rxjs\"\nimport type { LayoutEnhancerOutput } from \"../layout/layoutEnhancer\"\nimport type { EnhancerOutput, RootEnhancer } from \"../types/enhancer\"\nimport { trackPaginationInfo } from \"./pagination\"\nimport { ResourcesLocator } from \"./ResourcesLocator\"\nimport type { PaginationEnhancerAPI } from \"./types\"\n\nexport type { EnhancerPaginationInto, PaginationEnhancerAPI } from \"./types\"\n\nexport const paginationEnhancer =\n <\n InheritOptions,\n InheritOutput extends EnhancerOutput<RootEnhancer> & LayoutEnhancerOutput,\n PaginationOutput extends PaginationEnhancerAPI<InheritOutput>,\n >(\n next: (options: InheritOptions) => InheritOutput,\n ) =>\n (options: InheritOptions): PaginationOutput => {\n const reader = next(options)\n\n const { paginationInfo$, getPaginationInfo } = trackPaginationInfo(reader)\n\n paginationInfo$.pipe(takeUntil(reader.$.destroy$)).subscribe()\n\n const resourcesLocator = new ResourcesLocator(reader)\n\n return {\n ...reader,\n locateResource: resourcesLocator.locateResource.bind(resourcesLocator),\n pagination: {\n ...reader.pagination,\n get state() {\n return getPaginationInfo()\n },\n get state$() {\n return paginationInfo$\n },\n },\n } as unknown as PaginationOutput\n }\n","const createDatabase = (db: globalThis.IDBDatabase) => {\n const put = (key: string, data: Blob) => {\n return new Promise<void>((resolve, reject) => {\n const transaction = db.transaction([`store`], `readwrite`)\n\n transaction.onerror = (event) => {\n reject(event)\n }\n\n transaction.oncomplete = () => {\n resolve()\n }\n\n const objectStore = transaction.objectStore(`store`)\n const listener = objectStore.put(data, key)\n\n listener.onsuccess = () => {\n resolve()\n }\n\n listener.onerror = (event) => {\n reject(event)\n }\n })\n }\n\n const get = (key: string) => {\n return new Promise<Blob | null>((resolve, reject) => {\n const transaction = db.transaction([`store`], `readwrite`)\n const objectStore = transaction.objectStore(`store`)\n const request = objectStore.get(key)\n\n request.onsuccess = () => {\n let value = request.result\n if (value === undefined) {\n value = null\n }\n resolve(value)\n }\n\n transaction.onerror = () => {\n reject(request.error)\n }\n })\n }\n\n const remove = (key: globalThis.IDBValidKey) => {\n return new Promise<void>((resolve, reject) => {\n const transaction = db.transaction([`store`], `readwrite`)\n\n const objectStore = transaction.objectStore(`store`)\n const request = objectStore.delete(key)\n\n transaction.onerror = () => {\n reject(request.error)\n }\n\n transaction.oncomplete = () => {\n resolve()\n }\n\n // The request will be also be aborted if we've exceeded our storage\n // space.\n transaction.onabort = () => {\n const err = request.error ? request.error : request.transaction?.error\n reject(err)\n }\n })\n }\n\n const keys = () => {\n return new Promise<globalThis.IDBValidKey[]>((resolve, reject) => {\n const transaction = db.transaction([`store`], `readonly`)\n\n transaction.onerror = (event) => {\n reject(event)\n }\n\n // transaction.oncomplete = function () {\n // resolve()\n // };\n\n const objectStore = transaction.objectStore(`store`)\n const request = objectStore.openKeyCursor()\n const keys: globalThis.IDBValidKey[] = []\n\n request.onsuccess = () => {\n const cursor = request.result\n\n if (!cursor) {\n resolve(keys)\n return\n }\n\n keys.push(cursor.key)\n cursor.continue()\n }\n\n request.onerror = () => {\n reject(request.error)\n }\n })\n }\n\n return {\n put,\n keys,\n get,\n remove,\n }\n}\n\nexport const openDatabase = async (name: string) => {\n return new Promise<ReturnType<typeof createDatabase>>((resolve, reject) => {\n const request = window.indexedDB.open(name)\n\n request.onerror = (event) => {\n reject(event)\n }\n\n request.onsuccess = () => {\n resolve(createDatabase(request.result))\n }\n\n request.onupgradeneeded = () => {\n request.result.createObjectStore(`store`)\n }\n })\n}\n","/**\n * @todo web worker\n */\nimport { EMPTY, forkJoin, from, merge, Subject } from \"rxjs\"\nimport {\n catchError,\n map,\n mergeMap,\n switchMap,\n takeUntil,\n tap,\n} from \"rxjs/operators\"\nimport type { Manifest } from \"../..\"\nimport type { Context } from \"../../context/Context\"\nimport { Report } from \"../../report\"\nimport { openDatabase } from \"./indexedDB\"\n\nexport const createResourcesManager = (context: Context) => {\n let uniqueID = Date.now().toString()\n const cache$ = new Subject<{\n id: number | Pick<Manifest[`spineItems`][number], `id`>\n data: Response\n }>()\n\n const retrieveItem = (\n itemIndexOrId: number | string | Pick<Manifest[`spineItems`][number], `id`>,\n ) => {\n if (\n typeof itemIndexOrId === \"string\" ||\n typeof itemIndexOrId === \"object\"\n ) {\n const id =\n typeof itemIndexOrId === \"object\" ? itemIndexOrId.id : itemIndexOrId\n return context.manifest?.spineItems.find((entry) => entry.id === id)\n }\n\n return context.manifest?.spineItems[itemIndexOrId]\n }\n\n const get = async (\n itemIndexOrId: number | Pick<Manifest[`spineItems`][number], `id`>,\n fetchResource?: (item: Manifest[`spineItems`][number]) => Promise<Response>,\n ) => {\n const item = retrieveItem(itemIndexOrId)\n\n if (!item) return new Response(`Item not found`, { status: 404 })\n\n const db = await openDatabase(`prose-reader`)\n\n const cacheData = await db.get(`${uniqueID}_${item.id}`)\n\n if (cacheData) {\n return new Response(cacheData, { status: 200 })\n }\n\n const data =\n (fetchResource && (await fetchResource(item))) || (await fetch(item.href))\n\n cache(item, data.clone())\n\n return data\n }\n\n const cache = (\n itemIndexOrId: number | Pick<Manifest[`spineItems`][number], `id`>,\n data: Response,\n ) => {\n cache$.next({ id: itemIndexOrId, data })\n }\n\n cache$\n .asObservable()\n .pipe(\n mergeMap(({ id, data }) => {\n const item = retrieveItem(id)\n\n if (!item) return EMPTY\n\n return from(\n forkJoin([openDatabase(`prose-reader`), from(data.blob())]),\n ).pipe(\n switchMap(([db, blob]) => {\n return from(db.put(`${uniqueID}_${item.id}`, blob))\n }),\n catchError((error) => {\n Report.error(error)\n\n return EMPTY\n }),\n )\n }),\n takeUntil(context.destroy$),\n )\n .subscribe()\n\n const onLoad$ = context.manifest$.pipe(\n tap(() => {\n uniqueID = Date.now().toString()\n }),\n )\n\n /**\n * Cleanup old cache on startup if needed\n * @todo\n * do on first time and only then on subsequent load\n */\n merge(onLoad$)\n .pipe(\n switchMap(() => {\n Report.debug(`Cleanup up old cache...`)\n\n return from(openDatabase(`prose-reader`)).pipe(\n switchMap((db) =>\n from(db.keys()).pipe(\n map((keys) =>\n keys.filter((key) => !key.toString().startsWith(uniqueID)),\n ),\n switchMap((keysToRemove) => {\n const promises = keysToRemove.map((key) => db.remove(key))\n\n return from(Promise.all(promises))\n }),\n ),\n ),\n catchError((error) => {\n Report.error(error)\n\n return EMPTY\n }),\n )\n }),\n takeUntil(context.destroy$),\n )\n .subscribe()\n\n const destroy = () => {\n cache$.complete()\n }\n\n return {\n get,\n destroy,\n }\n}\n","import type { EnhancerOutput, RootEnhancer } from \"../types/enhancer\"\nimport { createResourcesManager } from \"./resourcesManager\"\n\nexport const resourcesEnhancer =\n <InheritOptions, InheritOutput extends EnhancerOutput<RootEnhancer>>(\n next: (options: InheritOptions) => InheritOutput,\n ) =>\n (options: InheritOptions): InheritOutput => {\n const reader = next(options)\n const resourceManager = createResourcesManager(reader.context)\n\n /**\n * We will serve resources from cache if they exist otherwise fetch it normally.\n * The resource manager use the provided user option to fetch resource if it exists\n */\n // const load: typeof reader.load = (manifest, loadOptions) => {\n // reader.load(manifest, {\n // ...loadOptions,\n // })\n // }\n\n // reader.registerHook(`item.onGetResource`, (fetcher) => async (item) => {\n // return resourceManager.get(item, fetcher)\n // })\n\n const destroy = () => {\n resourceManager.destroy()\n reader.destroy()\n }\n\n return {\n ...reader,\n // $: {\n // ...reader.$,\n // errors$: merge(reader.$.errors$, errorsSubject$.asObservable())\n // },\n destroy,\n // load,\n }\n }\n","import { Report } from \"../../report\"\nimport type { SpineItem } from \"../../spineItem/SpineItem\"\n\nexport const getRangeFromSelection = (\n anchor: { node: Node; offset?: number },\n focus: { node: Node; offset?: number },\n) => {\n const range = anchor.node.ownerDocument?.createRange()\n const comparison = anchor.node.compareDocumentPosition(focus.node)\n\n if (!range) return undefined\n\n try {\n // If focus comes before anchor in the document\n if (comparison & Node.DOCUMENT_POSITION_PRECEDING) {\n range.setStart(focus.node, focus.offset || 0)\n range.setEnd(anchor.node, anchor.offset || 0)\n // If focus comes after anchor in the document\n } else if (comparison & Node.DOCUMENT_POSITION_FOLLOWING) {\n range.setStart(anchor.node, anchor.offset || 0)\n range.setEnd(focus.node, focus.offset || 0)\n }\n // If they're the same node\n else {\n const startOffset = Math.min(anchor.offset || 0, focus.offset || 0)\n const endOffset = Math.max(anchor.offset || 0, focus.offset || 0)\n range.setStart(anchor.node, startOffset)\n range.setEnd(anchor.node, endOffset)\n }\n } catch (e) {\n Report.warn(\"Failed to create range from selection\", e, {\n anchor,\n focus,\n })\n }\n\n return range\n}\n\nexport const createOrderedRangeFromSelection = ({\n selection,\n spineItem,\n}: {\n selection: {\n anchorNode?: Node | null\n anchorOffset?: number\n focusNode?: Node | null\n focusOffset?: number\n }\n spineItem: SpineItem\n}) => {\n const { anchorNode, anchorOffset, focusNode, focusOffset } = selection\n\n if (!anchorNode || !focusNode) {\n return undefined\n }\n\n try {\n return getRangeFromSelection(\n { node: anchorNode, offset: anchorOffset },\n { node: focusNode, offset: focusOffset },\n )\n } catch (e) {\n Report.warn(\"Failed to create range from selection\", e, {\n selection,\n spineItem,\n })\n\n return undefined\n }\n}\n","import {\n delay,\n endWith,\n filter,\n first,\n merge,\n NEVER,\n type Observable,\n of,\n switchMap,\n takeUntil,\n} from \"rxjs\"\nimport { fromEvent, map } from \"rxjs\"\nimport { DestroyableClass } from \"../../utils/DestroyableClass\"\nimport { isDefined } from \"../../utils/isDefined\"\nimport { observeMutation } from \"../../utils/rxjs\"\n\nexport class FrameSelectionTracker extends DestroyableClass {\n selectionChange$: Observable<Selection | null>\n selectionOver$: Observable<readonly [Event, Selection]>\n\n constructor(frame: HTMLIFrameElement) {\n super()\n\n const frameDoc = frame.contentDocument || frame.contentWindow?.document\n\n if (!frameDoc) {\n this.selectionChange$ = NEVER\n this.selectionOver$ = NEVER\n } else {\n /**\n * We observe mutation on the doc to intercept potential\n * change in selection that would not be triggered by API.\n * Such as iframe nodes being recreated on layout.\n */\n const frameDocMutation$ = observeMutation(frameDoc.body, {\n childList: true,\n subtree: true,\n }).pipe(\n filter(\n (mutations) =>\n !!mutations.find((mutation) => {\n return (\n mutation.type === \"childList\" && mutation.removedNodes.length\n )\n }),\n ),\n )\n\n /**\n * We observe direct destruction of the iframe as well to remove current\n * selection if needed.\n */\n const iframeDestroyed$ = !frame.parentElement\n ? of(null)\n : observeMutation(frame.parentElement, {\n childList: true,\n }).pipe(\n filter(\n (mutation) =>\n !!mutation.find((mutation) =>\n Array.from(mutation.removedNodes).includes(frame),\n ),\n ),\n )\n\n this.selectionChange$ = merge(\n fromEvent(frameDoc, \"selectionchange\"),\n frameDocMutation$,\n ).pipe(\n map(() => frameDoc.getSelection()),\n takeUntil(merge(iframeDestroyed$, this.destroy$)),\n endWith(null),\n )\n\n this.selectionOver$ = fromEvent(frameDoc, \"pointerdown\").pipe(\n switchMap(() =>\n merge(\n fromEvent(frameDoc, \"pointerup\"),\n fromEvent(frameDoc, \"pointercancel\"),\n fromEvent(frameDoc, \"contextmenu\"),\n ).pipe(\n first(),\n /**\n * The selection is still valid during the event even if it will\n * be discarded. The timeout make sure to detect this edge case.\n */\n delay(0),\n map((event) => {\n const selection = frameDoc.getSelection()\n\n return selection && !selection.isCollapsed\n ? ([event, selection] as const)\n : undefined\n }),\n filter(isDefined),\n ),\n ),\n takeUntil(merge(iframeDestroyed$, this.destroy$)),\n )\n }\n }\n}\n","import {\n distinctUntilChanged,\n endWith,\n finalize,\n map,\n merge,\n NEVER,\n switchMap,\n takeUntil,\n} from \"rxjs\"\nimport type { SpineItem } from \"../../spineItem/SpineItem\"\nimport { FrameSelectionTracker } from \"./FrameSelectionTracker\"\n\nexport const trackSpineItemSelection = (spineItem: SpineItem) =>\n spineItem.watch(\"isLoaded\").pipe(\n switchMap(() => {\n const frame = spineItem.renderer.getDocumentFrame()\n const frameDoc = frame?.contentDocument || frame?.contentWindow?.document\n\n if (!frame || !frameDoc) return NEVER\n\n const selectionTracker = new FrameSelectionTracker(frame)\n\n return merge(\n selectionTracker.selectionChange$.pipe(\n map((selection) => {\n if (selection?.toString()) {\n return {\n type: \"change\" as const,\n selection,\n }\n }\n return undefined\n }),\n ),\n selectionTracker.selectionOver$.pipe(\n map(([event, selection]) => {\n return {\n type: \"over\" as const,\n event,\n selection,\n }\n }),\n ),\n ).pipe(\n takeUntil(spineItem.unloaded$),\n endWith(undefined),\n finalize(() => {\n selectionTracker.destroy()\n }),\n )\n }),\n distinctUntilChanged(),\n )\n","import {\n distinctUntilChanged,\n filter,\n fromEvent,\n map,\n merge,\n type Observable,\n share,\n shareReplay,\n startWith,\n switchMap,\n takeUntil,\n tap,\n withLatestFrom,\n} from \"rxjs\"\nimport type { SpineItem } from \"../..\"\nimport { isDefined } from \"../../utils/isDefined\"\nimport type { EnhancerOutput, RootEnhancer } from \"../types/enhancer\"\nimport { createOrderedRangeFromSelection } from \"./selection\"\nimport { trackSpineItemSelection } from \"./trackSpineItemSelection\"\n\ntype SelectionChange = {\n itemIndex: number\n type: \"change\"\n selection: Selection\n}\n\ntype SelectionOver = {\n itemIndex: number\n type: \"over\"\n event: Event\n selection: Selection\n}\n\ntype SelectionValue = SelectionChange | SelectionOver | undefined\n\nexport const selectionEnhancer =\n <InheritOptions, InheritOutput extends EnhancerOutput<RootEnhancer>>(\n next: (options: InheritOptions) => InheritOutput,\n ) =>\n (\n options: InheritOptions,\n ): InheritOutput & {\n selection: {\n selection$: Observable<SelectionValue>\n selectionStart$: Observable<boolean>\n selectionEnd$: Observable<void>\n selectionOver$: Observable<SelectionOver>\n lastSelectionOnPointerdown$: Observable<SelectionValue>\n getSelection: () => SelectionValue\n createOrderedRangeFromSelection: (params: {\n selection: {\n anchorNode?: Node | null\n anchorOffset?: number\n focusNode?: Node | null\n focusOffset?: number\n }\n spineItem: SpineItem\n }) => Range | undefined\n }\n } => {\n const reader = next(options)\n let lasSelection: SelectionValue\n\n const trackedSelection$ = reader.spineItemsManager.items$.pipe(\n switchMap((spineItems) => {\n const instances = spineItems.map((spineItem) => {\n const itemIndex =\n reader.spineItemsManager.getSpineItemIndex(spineItem) ?? 0\n\n return trackSpineItemSelection(spineItem).pipe(\n map((entry) => {\n if (!entry) return undefined\n\n return {\n ...entry,\n itemIndex,\n }\n }),\n )\n })\n\n return merge(...instances)\n }),\n startWith(undefined),\n distinctUntilChanged(),\n tap((value) => {\n lasSelection = value\n }),\n shareReplay({ refCount: true, bufferSize: 1 }),\n )\n\n const selection$ = trackedSelection$\n\n const selectionStart$ = trackedSelection$.pipe(\n map((selection) => !!selection),\n distinctUntilChanged(),\n filter((isSelecting) => isSelecting),\n share(),\n )\n\n const selectionEnd$ = selectionStart$.pipe(\n switchMap(() => selection$),\n distinctUntilChanged(),\n filter((selection) => !selection),\n share(),\n )\n\n const selectionOver$ = trackedSelection$.pipe(\n filter((selection) => selection?.type === \"over\"),\n share(),\n )\n\n const lastSelectionOnPointerdown$ = reader.context\n .watch(`rootElement`)\n .pipe(\n filter(isDefined),\n switchMap((container) => fromEvent(container, \"pointerdown\")),\n withLatestFrom(selection$),\n map(([, selection]) => selection),\n startWith(undefined),\n shareReplay({ refCount: true, bufferSize: 1 }),\n )\n\n merge(selection$, lastSelectionOnPointerdown$)\n .pipe(takeUntil(reader.$.destroy$))\n .subscribe()\n\n return {\n ...reader,\n selection: {\n selection$,\n selectionStart$,\n selectionEnd$,\n selectionOver$,\n lastSelectionOnPointerdown$,\n getSelection: () => lasSelection,\n createOrderedRangeFromSelection,\n },\n }\n }\n","import { BehaviorSubject, type Observable } from \"rxjs\"\nimport { takeUntil, tap } from \"rxjs/operators\"\nimport { upsertCSSToFrame } from \"../utils/frames\"\nimport type { EnhancerOutput, RootEnhancer } from \"./types/enhancer\"\n\nconst defaultThemes = [\n {\n name: `bright` as const,\n backgroundColor: `white`,\n },\n {\n name: `sepia` as const,\n backgroundColor: `#eaddc7`,\n foregroundColor: `black`,\n },\n {\n name: `night` as const,\n backgroundColor: `#191717`,\n foregroundColor: `#f1ebeb`,\n },\n]\n\nexport type Theme = (typeof defaultThemes)[number][`name`] | `publisher`\n\nexport type ThemeEnhancer = <\n InheritOptions,\n InheritOutput extends EnhancerOutput<RootEnhancer>,\n>(\n next: (options: InheritOptions) => InheritOutput,\n) => (\n options: InheritOptions & {\n theme?: Theme\n },\n) => InheritOutput & {\n theme: {\n set: (theme: Theme) => void\n get: () => Theme\n $: {\n theme$: Observable<Theme>\n }\n }\n}\n\nexport const themeEnhancer: ThemeEnhancer = (next) => (options) => {\n const reader = next(options)\n const currentThemeSubject$ = new BehaviorSubject<Theme>(\n options.theme ?? `bright`,\n )\n\n const getStyle = () => {\n const foundTheme = defaultThemes.find(\n (entry) => entry.name === currentThemeSubject$.value,\n )\n\n return `\n body {\n ${foundTheme !== undefined ? `background-color: ${foundTheme.backgroundColor} !important;` : ``}\n }\n ${\n foundTheme?.foregroundColor\n ? `\n body * {\n ${\n /*\n Ideally, we would like to use !important but it could break publisher specific\n cases\n */ ``\n }\n color: ${foundTheme.foregroundColor};\n }\n `\n : ``\n }\n `\n }\n\n const applyChangeToSpineItemElement = ({\n container,\n }: {\n container: HTMLElement\n }) => {\n const foundTheme = defaultThemes.find(\n (entry) => entry.name === currentThemeSubject$.value,\n )\n if (foundTheme) {\n container.style.setProperty(\n `background-color`,\n foundTheme.backgroundColor,\n )\n }\n\n return () => {\n // __\n }\n }\n\n const applyChangeToSpineItem = () => {\n reader.spineItemsManager.items.forEach((item) => {\n const frame = item.renderer.getDocumentFrame()\n\n if (frame) {\n upsertCSSToFrame(frame, `prose-reader-theme`, getStyle())\n }\n\n applyChangeToSpineItemElement({ container: item.element })\n })\n }\n\n /**\n * Make sure to apply theme on item load\n */\n reader.hookManager.register(`item.onDocumentLoad`, ({ itemId }) => {\n const item = reader.spineItemsManager.get(itemId)\n\n /**\n * We don't apply the theme on pre-paginated items\n * because the theme is applied on the page level.\n *\n * A good example is the iframe generated by pdf for annotations.\n * It would mess up with the rendering.\n */\n if (item?.renditionLayout !== \"pre-paginated\") {\n const frame = item?.renderer.getDocumentFrame()\n\n if (frame) {\n upsertCSSToFrame(frame, `prose-reader-theme`, getStyle())\n }\n }\n })\n\n /**\n * Make sure to apply theme on item container (fixed layout)\n * & loading element\n */\n reader.spineItemsManager.items$\n .pipe(\n tap((items) =>\n items.map(({ element }) =>\n applyChangeToSpineItemElement({ container: element }),\n ),\n ),\n takeUntil(reader.$.destroy$),\n )\n .subscribe()\n\n currentThemeSubject$\n .pipe(\n tap(() => {\n applyChangeToSpineItem()\n }),\n takeUntil(reader.$.destroy$),\n )\n .subscribe()\n\n return {\n ...reader,\n theme: {\n set: (theme) => {\n if (theme !== currentThemeSubject$.value) {\n currentThemeSubject$.next(theme)\n }\n },\n get: () => currentThemeSubject$.value,\n $: {\n theme$: currentThemeSubject$.asObservable(),\n },\n },\n }\n}\n","import { injectCSS, isHtmlElement } from \"../utils/dom\"\nimport type { EnhancerOutput, RootEnhancer } from \"./types/enhancer\"\n\nexport const utilsEnhancer =\n <InheritOptions, InheritOutput extends EnhancerOutput<RootEnhancer>>(\n next: (options: InheritOptions) => InheritOutput,\n ) =>\n (\n options: InheritOptions,\n ): InheritOutput & {\n utils: {\n isOrIsWithinValidLink: (target: Event[`target`]) => boolean\n injectScopedCSS: (\n doc: Document,\n scope: string,\n styleTemplate: string,\n ) => () => void\n }\n } => {\n const reader = next(options)\n\n const isOrIsWithinValidLink = (target: Event[`target`]) => {\n if (isHtmlElement(target)) {\n const link = target.nodeName === `a` ? target : target.closest(`a`)\n if (link?.getAttribute(`href`)) {\n return true\n }\n }\n\n return false\n }\n\n const injectScopedCSS = (\n doc: Document,\n scope: string,\n styleTemplate: string,\n ) => {\n // biome-ignore lint/suspicious/noTemplateCurlyInString: Expected\n const styleWithIdReplaced = styleTemplate.replace(\"${id}\", reader.id)\n\n return injectCSS(doc, `${scope}-${reader.id}`, styleWithIdReplaced)\n }\n\n return {\n ...reader,\n utils: {\n isOrIsWithinValidLink,\n injectScopedCSS,\n },\n }\n }\n","import type {\n EnhancerOptions,\n EnhancerOutput,\n RootEnhancer,\n} from \"./types/enhancer\"\n\n/**\n * Ideally we want to target all webkit browser but afaik there are no reliable way to do it.\n * We will fix at least safari\n */\nconst IS_SAFARI =\n navigator.userAgent.indexOf(``) > -1 &&\n navigator.userAgent.indexOf(`Chrome`) <= -1\n\n/**\n * All fixes relative to webkit\n */\nexport const webkitEnhancer =\n <\n InheritOptions extends EnhancerOptions<RootEnhancer>,\n InheritOutput extends EnhancerOutput<RootEnhancer>,\n >(\n createReader: (options: InheritOptions) => InheritOutput,\n ) =>\n (options: InheritOptions): InheritOutput => {\n const reader = createReader(options)\n\n /**\n * These hooks are used to fix the flickering on safari that occurs when using transform\n * and more generally GPU transformation. I am not sure what is the impact on performance so\n * we only use them on needed engine (webkit).\n */\n if (IS_SAFARI) {\n // reader.hookManager.register(\n // \"navigator.onBeforeContainerCreated\",\n // ({ element }) => {\n // element.style.cssText = `\n // ${element.style.cssText}\n // -webkit-transform-style: preserve-3d;\n // `\n // },\n // )\n // reader.hookManager.register(\n // \"item.onBeforeContainerCreated\",\n // ({ element }) => {\n // element.style.cssText = `\n // ${element.style.cssText}\n // -webkit-transform-style: preserve-3d;\n // -webkit-backface-visibility: hidden;\n // `\n // },\n // )\n }\n\n return reader\n }\n","import type { Viewport } from \"../../viewport/Viewport\"\nimport type { ZoomPosition } from \"./types\"\n\n/**\n * Make sure to constraint position within viewport boundaries when zoomed.\n * This only works when zoomed in.\n */\nexport const constrainPositionWithinViewport = (\n position: ZoomPosition,\n scale: number,\n viewport: Viewport,\n) => {\n const { clientWidth, clientHeight } = viewport.value.element\n\n // Calculate the maximum allowed translation (always 0, top-left)\n // and minimum allowed translation (negative value representing the overflow)\n const bounds = {\n maxX: 0,\n minX: clientWidth * (1 - scale),\n maxY: 0,\n minY: clientHeight * (1 - scale),\n }\n\n return {\n x: Math.min(Math.max(position.x, bounds.minX), bounds.maxX),\n y: Math.min(Math.max(position.y, bounds.minY), bounds.maxY),\n }\n}\n","export const applyViewportTransformForControlledMode = (\n scale: number,\n position: { x: number; y: number },\n viewportElement: HTMLElement,\n) => {\n viewportElement.style.transformOrigin = `0 0`\n\n const translateTransform = `translate3d(${position.x}px, ${position.y}px, 0px)`\n const scaleTransform = `scale(${scale})`\n\n viewportElement.style.transform = `${translateTransform} ${scaleTransform}`\n}\n\nexport const derivePositionFromScaleForControlledMode = (\n currentScale: number,\n userScale: number,\n viewportElement: HTMLElement,\n currentPosition: { x: number; y: number },\n) => {\n const scaleFactor = userScale / currentScale\n\n // Use clientWidth/clientHeight to get original dimensions before transforms\n const originalWidth = viewportElement.clientWidth\n const originalHeight = viewportElement.clientHeight\n\n // Calculate the center of what the user is currently seeing\n // Use original dimensions, not transformed ones\n const visualCenterX = originalWidth / 2 - currentPosition.x\n const visualCenterY = originalHeight / 2 - currentPosition.y\n\n // Calculate new position to keep the visual center fixed during scaling\n const newPosition = {\n x: currentPosition.x + visualCenterX * (1 - scaleFactor),\n y: currentPosition.y + visualCenterY * (1 - scaleFactor),\n }\n\n return newPosition\n}\n","/// <reference types=\"vite/client\" />\nimport type { Manifest } from \"@prose-reader/shared\"\n\nexport type { Manifest }\n\nexport abstract class AbstractPosition {\n public readonly x: number\n public readonly y: number\n\n constructor(position: { x: number; y: number }) {\n this.x = position.x\n this.y = position.y\n }\n}\n","import {\n BehaviorSubject,\n combineLatest,\n distinctUntilChanged,\n filter,\n fromEvent,\n map,\n merge,\n NEVER,\n type Observable,\n of,\n Subject,\n share,\n shareReplay,\n skip,\n startWith,\n switchMap,\n takeUntil,\n tap,\n timer,\n withLatestFrom,\n} from \"rxjs\"\nimport { HTML_PREFIX_SCROLL_NAVIGATOR } from \"../../constants\"\nimport type { Context } from \"../../context/Context\"\nimport type { HookManager } from \"../../hooks/HookManager\"\nimport type { ReaderSettingsManager } from \"../../settings/ReaderSettingsManager\"\nimport type { Spine } from \"../../spine/Spine\"\nimport { type SpinePosition, UnboundSpinePosition } from \"../../spine/types\"\nimport { AbstractPosition } from \"../../types\"\nimport { isDefined } from \"../../utils/isDefined\"\nimport { ReactiveEntity } from \"../../utils/ReactiveEntity\"\nimport { observeResize, watchKeys } from \"../../utils/rxjs\"\nimport type { Viewport } from \"../../viewport/Viewport\"\n\nexport class ScrollPosition extends AbstractPosition {}\nexport class UnboundScrollPosition extends AbstractPosition {\n public readonly __symbol = Symbol(`UnboundScrollPosition`)\n}\n\nexport type ScrollNavigationViewportNavigationEntry = {\n position: UnboundSpinePosition | SpinePosition\n}\n\nexport class ScrollNavigationController extends ReactiveEntity<{\n element: HTMLElement | undefined\n}> {\n protected navigateSubject =\n new Subject<ScrollNavigationViewportNavigationEntry>()\n protected scrollingSubject = new BehaviorSubject(false)\n\n public isScrolling$ = this.scrollingSubject.asObservable()\n public isNavigating$: Observable<boolean>\n public userScroll$: Observable<Event>\n\n constructor(\n protected viewport: Viewport,\n protected settings: ReaderSettingsManager,\n protected hookManager: HookManager,\n protected spine: Spine,\n protected context: Context,\n ) {\n super({\n element: undefined,\n })\n\n const elementCreation$ = this.context.pipe(\n watchKeys([\"rootElement\"]),\n tap(({ rootElement }) => {\n if (!rootElement) return\n\n const element = document.createElement(`div`)\n element.setAttribute(`data-${HTML_PREFIX_SCROLL_NAVIGATOR}`, \"\")\n element.appendChild(this.viewport.value.element)\n rootElement.appendChild(element)\n\n this.update({ element })\n }),\n )\n\n const toggleElementDisplay$ = combineLatest([\n settings.watch([`computedPageTurnMode`]),\n this.watch(\"element\"),\n ]).pipe(\n tap(([{ computedPageTurnMode }, element]) => {\n if (!element) return\n\n if (computedPageTurnMode === `scrollable`) {\n element.style.display = \"block\"\n } else {\n element.style.display = \"contents\"\n }\n }),\n )\n\n const navigate$ = this.navigateSubject.pipe(tap(this.setViewportPosition))\n\n this.isNavigating$ = this.navigateSubject.pipe(\n startWith(false),\n switchMap(() => merge(of(true), of(false))),\n shareReplay(1),\n )\n\n // might be a bit overkill but we want to be sure of sure\n const isSpineScrolling$ = merge(\n spine.element$.pipe(\n filter(isDefined),\n switchMap((element) => observeResize(element)),\n ),\n spine.element$.pipe(\n filter(isDefined),\n switchMap((element) => fromEvent(element, \"scroll\")),\n ),\n spine.spineItemsObserver.itemResize$,\n ).pipe(\n switchMap(() =>\n timer(10).pipe(\n map(() => false),\n startWith(true),\n ),\n ),\n distinctUntilChanged(),\n startWith(false),\n )\n\n const scrollHappeningFromBrowser$ = combineLatest([\n isSpineScrolling$,\n this.isScrolling$,\n ]).pipe(\n map(\n ([spineScrolling, viewportScrolling]) =>\n spineScrolling || viewportScrolling,\n ),\n shareReplay(1),\n )\n\n this.userScroll$ = this.watch(\"element\").pipe(\n filter(isDefined),\n switchMap((element) =>\n settings.watch([\"computedPageTurnMode\"]).pipe(\n switchMap(({ computedPageTurnMode }) =>\n computedPageTurnMode === \"controlled\"\n ? NEVER\n : fromEvent(element, `scroll`).pipe(\n withLatestFrom(scrollHappeningFromBrowser$),\n filter(\n ([, shouldAvoidScrollEvent]) => !shouldAvoidScrollEvent,\n ),\n map(([event]) => event),\n ),\n ),\n ),\n ),\n share(),\n )\n\n merge(elementCreation$, toggleElementDisplay$, navigate$)\n .pipe(takeUntil(this.destroy$))\n .subscribe()\n }\n\n /**\n * Usually occurs due to navigation.\n *\n * @see https://stackoverflow.com/questions/22111256/translate3d-vs-translate-performance\n * for remark about flicker / fonts smoothing\n */\n protected setViewportPosition = ({\n position,\n }: ScrollNavigationViewportNavigationEntry) => {\n const element = this.value.element\n\n this.scrollingSubject.next(true)\n\n const scaledPosition = this.fromSpinePosition(position)\n\n element?.scrollTo({\n left: scaledPosition.x,\n top: scaledPosition.y,\n behavior: \"instant\",\n })\n\n timer(1)\n .pipe(\n tap(() => {\n this.scrollingSubject.next(false)\n }),\n takeUntil(merge(this.scrollingSubject.pipe(skip(1)), this.destroy$)),\n )\n .subscribe()\n\n this.hookManager.execute(\"onViewportOffsetAdjust\", undefined, {})\n }\n\n public update(\n value: Partial<{\n element: HTMLElement | undefined\n }>,\n ) {\n this.mergeCompare(value)\n }\n\n navigate(navigation: ScrollNavigationViewportNavigationEntry) {\n this.navigateSubject.next(navigation)\n }\n\n public fromScrollPosition(position: UnboundScrollPosition | ScrollPosition) {\n const scaleFactor = this.viewport.scaleFactor\n\n return new UnboundSpinePosition({\n x: position.x / scaleFactor,\n y: position.y / scaleFactor,\n })\n }\n\n public fromSpinePosition(position: UnboundSpinePosition | SpinePosition) {\n const scaleFactor = this.viewport.scaleFactor\n\n return new ScrollPosition({\n x: position.x * scaleFactor,\n y: position.y * scaleFactor,\n })\n }\n\n public get scrollPosition() {\n const element = this.value.element\n\n return new ScrollPosition({\n x: element?.scrollLeft ?? 0,\n y: element?.scrollTop ?? 0,\n })\n }\n}\n","import { HTML_PREFIX } from \"../../constants\"\nimport { UnboundScrollPosition } from \"../../navigation/controllers/ScrollNavigationController\"\nimport type { Reader } from \"../../reader\"\nimport { noopElement } from \"../../utils/dom\"\n\nexport const adjustScrollToKeepContentCentered = (\n scrollContainer: HTMLElement,\n fromScale: number,\n toScale: number,\n marginX: number,\n marginY: number,\n) => {\n const containerWidth = scrollContainer.clientWidth\n const containerHeight = scrollContainer.clientHeight\n\n // Current scroll position\n const currentScrollLeft = scrollContainer.scrollLeft\n const currentScrollTop = scrollContainer.scrollTop\n\n // Calculate what's currently in the center of the visible area, accounting for margins\n const visibleCenterX = currentScrollLeft + containerWidth / 2 - marginX\n const visibleCenterY = currentScrollTop + containerHeight / 2 - marginY\n\n // After scaling, calculate where we need to scroll to keep the same content centered\n const scaleFactor = toScale / fromScale\n const newVisibleCenterX = visibleCenterX * scaleFactor\n const newVisibleCenterY = visibleCenterY * scaleFactor\n\n // Calculate new scroll position to keep the center content visible, accounting for margins\n const scrollLeft = newVisibleCenterX - containerWidth / 2 + marginX\n const scrollTop = newVisibleCenterY - containerHeight / 2 + marginY\n\n return new UnboundScrollPosition({\n x: scrollLeft,\n y: scrollTop,\n })\n}\n\nexport const applyScaleToViewportForScroll = (\n scale: number,\n reader: Reader,\n) => {\n const viewport = reader.viewport\n const scrollNavigationController =\n reader.navigation.scrollNavigationController\n const viewportElement = viewport.value.element\n const scrollContainer = scrollNavigationController.value.element\n const scrollNavigationElement = scrollNavigationController.value.element\n\n const currentScale = Math.round(viewport.scaleFactor * 100) / 100\n\n // We assume the viewport is directly under the scroll container\n // therefore we can use offsetLeft/offsetTop to get the margin\n const marginX = viewportElement.offsetLeft\n const marginY = viewportElement.offsetTop\n\n const newCenterPositionAfterNewScaleProjection =\n adjustScrollToKeepContentCentered(\n scrollContainer ?? noopElement(),\n currentScale,\n scale,\n marginX,\n marginY,\n )\n\n const direction = scale < 1 ? \"down\" : \"up\"\n scrollNavigationElement?.setAttribute(\n `data-${HTML_PREFIX}-zooming-direction`,\n direction,\n )\n\n /**\n * When zooming out, we want to keep the content centered. Since we don't have a scrollbar we will cheat\n * with origin and force it centered.\n * When zooming in, we want to keep the content centered as well but we now have a scrollbar so we adjust it.\n * Keeping the origin centered would make it impossible to scroll the left content\n */\n if (scale < 1) {\n viewportElement.style.transformOrigin = `top`\n } else if (scale > 1) {\n /**\n * @important\n * Transform origin `center` would cut left part of the content because it would expand\n * beyond the container on both side (albeit right side would be scrollable).\n * transform origin `left` would cut right part of the content if the viewport has margin\n * (eg: 50% viewport fit)\n * Therefore we need to use an origin that start at the actual content eliminating margin.\n */\n viewportElement.style.transformOrigin = `${marginX}px ${marginY}px`\n }\n\n viewportElement.style.transform = `scale(${scale})`\n\n const spinePosition = scrollNavigationController.fromScrollPosition(\n newCenterPositionAfterNewScaleProjection,\n )\n\n reader.navigation.navigate({\n position: spinePosition,\n })\n}\n","import {\n EMPTY,\n merge,\n type ObservedValueOf,\n Subject,\n switchMap,\n takeUntil,\n tap,\n timer,\n} from \"rxjs\"\nimport { HTML_PREFIX } from \"../../constants\"\nimport type { Reader } from \"../../reader\"\nimport { ReactiveEntity } from \"../../utils/ReactiveEntity\"\nimport { constrainPositionWithinViewport } from \"./constraints\"\nimport {\n applyViewportTransformForControlledMode,\n derivePositionFromScaleForControlledMode,\n} from \"./controlled\"\nimport { applyScaleToViewportForScroll } from \"./scrollable\"\nimport type { ZoomPosition } from \"./types\"\n\nexport type ZoomControllerState = {\n isZooming: boolean\n currentScale: number\n /**\n * Represents the origin translate position before zoom is applied\n * and is based of an origin of 0,0.\n */\n currentPosition: ZoomPosition\n}\n\n/**\n * @important\n * Animation is not possible for scrolling mode because the animation\n * is based on transform origin and its impossible to have a correct\n * centered transform origin with the viewport in a scrollable container.\n * What we do is compute the \"wanted\" scroll position to make it look like\n * scale down/up appears centered.\n */\nconst ANIMATION_DURATION = 200\n\nexport class ZoomController extends ReactiveEntity<ZoomControllerState> {\n private enterSubject = new Subject<\n | undefined\n | {\n element?: HTMLImageElement\n scale?: number\n animate?: boolean\n }\n >()\n private exitSubject = new Subject<{ animate?: boolean } | undefined>()\n\n constructor(protected reader: Reader) {\n super({\n isZooming: false,\n currentScale: 1,\n currentPosition: { x: 0, y: 0 },\n })\n\n const enter$ = this.enterSubject.pipe(\n switchMap((options) => {\n const { scale = 1, animate = false } = options ?? {}\n const viewportElement = this.reader.viewport.value.element\n\n this.viewport.element.setAttribute(\n `data-${HTML_PREFIX}-zooming`,\n \"true\",\n )\n\n this.scrollNavigationController.value.element?.setAttribute(\n `data-${HTML_PREFIX}-zooming`,\n this.isControlled ? \"false\" : \"true\",\n )\n\n if (animate && this.isControlled) {\n viewportElement.style.transition = `transform ${ANIMATION_DURATION}ms`\n }\n\n this.mergeCompare({\n isZooming: true,\n currentScale: 1,\n currentPosition: { x: 0, y: 0 },\n })\n\n this.updateZoom(scale)\n\n if (scale !== 1 && this.isControlled) {\n return timer(options?.animate ? ANIMATION_DURATION : 0).pipe(\n tap(() => {\n this.reader.layout()\n }),\n )\n }\n\n return EMPTY\n }),\n )\n\n const exit$ = this.exitSubject.pipe(\n switchMap((options) => {\n const viewportElement = this.reader.viewport.value.element\n\n this.viewport.element.setAttribute(\n `data-${HTML_PREFIX}-zooming`,\n \"false\",\n )\n\n this.scrollNavigationController.value.element?.removeAttribute(\n `data-${HTML_PREFIX}-zooming-direction`,\n )\n this.scrollNavigationController.value.element?.setAttribute(\n `data-${HTML_PREFIX}-zooming`,\n \"false\",\n )\n\n if (options?.animate && this.isControlled) {\n viewportElement.style.transition = `transform ${ANIMATION_DURATION}ms`\n }\n\n this.updateZoom(1, { x: 0, y: 0 })\n\n viewportElement.style.transform = ``\n\n this.mergeCompare({\n isZooming: false,\n })\n\n return timer(options?.animate ? ANIMATION_DURATION : 0).pipe(\n tap(() => {\n const viewportElement = this.reader.viewport.value.element\n viewportElement.style.transformOrigin = ``\n viewportElement.style.transition = ``\n\n if (this.isControlled) {\n this.reader.layout()\n }\n }),\n takeUntil(this.enterSubject),\n )\n }),\n )\n\n merge(enter$, exit$).pipe(takeUntil(this.destroy$)).subscribe()\n }\n\n public enter(options?: ObservedValueOf<typeof this.enterSubject>) {\n this.enterSubject.next(options)\n }\n\n public exit(options?: ObservedValueOf<typeof this.exitSubject>) {\n this.exitSubject.next(options)\n }\n\n public move(\n position: { x: number; y: number },\n options?: { constrain?: \"within-viewport\" },\n ) {\n // no moving needed for scrollable mode\n if (!this.isControlled) return\n\n // make sure to prevent animation before applying the new position\n this.viewport.element.style.transition = ``\n\n this.updateZoom(this.value.currentScale, position, {\n constraints:\n options?.constrain === \"within-viewport\"\n ? (...rest) =>\n constrainPositionWithinViewport(...rest, this.reader.viewport)\n : undefined,\n })\n }\n\n public scaleAt(\n userScale: number,\n options?: { constrain?: \"within-viewport\" },\n ): void {\n // make sure to prevent animation before applying the new position\n this.viewport.element.style.transition = ``\n\n const roundedScale = Math.ceil(userScale * 100) / 100\n const newScale = roundedScale\n\n this.updateZoom(newScale, undefined, {\n constraints:\n options?.constrain === \"within-viewport\"\n ? (...rest) =>\n constrainPositionWithinViewport(...rest, this.reader.viewport)\n : undefined,\n })\n }\n\n protected updateZoom(\n scale: number,\n position?: ZoomPosition,\n options?: {\n constraints?: (position: ZoomPosition, scale: number) => ZoomPosition\n },\n ) {\n if (this.isControlled) {\n const newPosition = position\n ? position\n : derivePositionFromScaleForControlledMode(\n this.value.currentScale,\n scale,\n this.viewport.element,\n this.value.currentPosition,\n )\n\n const constrainedPosition =\n options?.constraints?.(newPosition, scale) ?? newPosition\n\n this.applyZoom(scale, constrainedPosition)\n\n return this.mergeCompare({\n currentScale: scale,\n currentPosition: constrainedPosition,\n })\n }\n\n this.applyZoom(scale, position ?? this.value.currentPosition)\n\n this.mergeCompare({\n currentScale: scale,\n })\n }\n\n protected applyZoom(scale: number, position: { x: number; y: number }) {\n if (!this.isControlled) {\n /**\n * @important\n * This does trigger a navigation to always re-center the scroll position with the new scale\n */\n applyScaleToViewportForScroll(scale, this.reader)\n } else {\n applyViewportTransformForControlledMode(\n scale,\n position,\n this.viewport.element,\n )\n }\n }\n\n protected get isControlled() {\n return this.reader.settings.values.computedPageTurnMode === \"controlled\"\n }\n\n protected get scrollNavigationController() {\n return this.reader.navigation.scrollNavigationController\n }\n\n protected get viewport() {\n return this.reader.viewport.value\n }\n}\n","import { HTML_STYLE_PREFIX } from \"../../constants\"\nimport type { Reader } from \"../../reader\"\nimport { injectCSS, removeCSS } from \"../../utils/dom\"\nimport styles from \"./index.scss?inline\"\nimport type { ZoomEnhancerOutput } from \"./types\"\nimport { ZoomController } from \"./ZoomController\"\n\nconst STYLES_ID = `${HTML_STYLE_PREFIX}-enhancer-zoom`\n\nexport const zoomEnhancer =\n <InheritOptions, InheritOutput extends Reader>(\n next: (options: InheritOptions) => InheritOutput,\n ) =>\n (options: InheritOptions): InheritOutput & ZoomEnhancerOutput => {\n const reader = next(options)\n const zoomController = new ZoomController(reader)\n\n injectCSS(document, STYLES_ID, styles)\n\n const destroy = () => {\n removeCSS(document, STYLES_ID)\n\n zoomController.destroy()\n reader.destroy()\n }\n\n const state$ = zoomController\n\n return {\n ...reader,\n destroy,\n zoom: {\n enter: zoomController.enter.bind(zoomController),\n scaleAt: zoomController.scaleAt.bind(zoomController),\n move: zoomController.move.bind(zoomController),\n exit: zoomController.exit.bind(zoomController),\n state$,\n get state() {\n return zoomController.value\n },\n },\n }\n }\n","import type { Manifest } from \"@prose-reader/shared\"\n\nexport const isFullyPrePaginated = (manifest?: Manifest) =>\n manifest?.renditionLayout === \"pre-paginated\" ||\n manifest?.spineItems.every((item) => item.renditionLayout === \"pre-paginated\")\n","import {\n BehaviorSubject,\n distinctUntilChanged,\n filter,\n ReplaySubject,\n} from \"rxjs\"\nimport type { Navigation } from \"../navigation/types\"\nimport type { PaginationInfo } from \"../pagination/types\"\n\n/**\n * Bridge events that are transverse to the project and needed across several\n * layout and level of components.\n *\n * These events have important and rather general meaning for the engine.\n *\n * This is also mostly because some components would have circular dep if\n * the events weren't extracted. (navigation and pagination both need to listen\n * to one another for example).\n */\nexport class BridgeEvent {\n public navigationSubject = new ReplaySubject<Navigation>(1)\n public viewportStateSubject = new BehaviorSubject<`free` | `busy`>(`free`)\n public paginationSubject = new ReplaySubject<PaginationInfo>()\n public navigationIsLockedSubject = new BehaviorSubject(false)\n\n /**\n * Replay last pagination and emit next changes\n */\n public pagination$ = this.paginationSubject.asObservable()\n\n /**\n * Emit whenever the navigation is unlocked.\n */\n public navigationUnlocked$ = this.navigationIsLockedSubject.pipe(\n distinctUntilChanged(),\n filter((isLocked) => !isLocked),\n )\n\n /**\n * Replay and emit viewport state\n */\n public viewportState$ = this.viewportStateSubject.asObservable()\n\n /**\n * Replay and emit whenever viewport is free\n */\n public viewportFree$ = this.viewportState$.pipe(\n filter((state) => state === \"free\"),\n )\n\n /**\n * Replay and emit whenever viewport is busy\n */\n public viewportBusy$ = this.viewportState$.pipe(\n filter((state) => state === \"busy\"),\n )\n\n /**\n * Replay and emit navigation\n */\n public navigation$ = this.navigationSubject.asObservable()\n}\n","import type { Manifest } from \"@prose-reader/shared\"\nimport { distinctUntilChanged, filter, map } from \"rxjs/operators\"\nimport { isFullyPrePaginated } from \"../manifest/isFullyPrePaginated\"\nimport { isDefined } from \"../utils/isDefined\"\nimport { ReactiveEntity } from \"../utils/ReactiveEntity\"\nimport { BridgeEvent } from \"./BridgeEvent\"\n\nexport type ContextState = {\n rootElement?: HTMLElement\n manifest?: Manifest\n hasVerticalWriting?: boolean\n assumedRenditionLayout: \"reflowable\" | \"pre-paginated\"\n isFullyPrePaginated?: boolean\n}\n\nexport class Context extends ReactiveEntity<ContextState> {\n public bridgeEvent = new BridgeEvent()\n public manifest$ = this.pipe(\n map((state) => state.manifest),\n filter(isDefined),\n distinctUntilChanged(),\n )\n\n constructor() {\n super({\n assumedRenditionLayout: \"reflowable\",\n })\n }\n\n public update(newState: Partial<ContextState>) {\n const previousState = this.value\n const manifest = newState.manifest ?? previousState.manifest\n\n const newCompleteState = {\n ...previousState,\n ...newState,\n ...(newState.manifest && {\n isFullyPrePaginated: isFullyPrePaginated(manifest),\n assumedRenditionLayout: manifest?.renditionLayout ?? \"reflowable\",\n }),\n }\n\n this.mergeCompare(newCompleteState)\n }\n\n /**\n * RTL only makes sense for horizontal scrolling\n */\n public isRTL = () => {\n return this.value.manifest?.readingDirection === `rtl`\n }\n\n get manifest() {\n return this.value.manifest\n }\n\n get readingDirection() {\n return this.manifest?.readingDirection\n }\n}\n","import { isShallowEqual } from \"@prose-reader/shared\"\nimport { combineLatest, distinctUntilChanged, map, takeUntil } from \"rxjs\"\nimport type { Context } from \"../context/Context\"\nimport type { ReaderSettingsManager } from \"../settings/ReaderSettingsManager\"\nimport type { CoreInputSettings } from \"../settings/types\"\nimport { ReactiveEntity } from \"../utils/ReactiveEntity\"\n\nexport type ContextSettings = Partial<CoreInputSettings>\n\ntype State = {\n supportedPageTurnAnimation: NonNullable<\n ContextSettings[`pageTurnAnimation`]\n >[]\n supportedPageTurnMode: NonNullable<ContextSettings[`pageTurnMode`]>[]\n supportedPageTurnDirection: NonNullable<\n ContextSettings[`pageTurnDirection`]\n >[]\n supportedComputedPageTurnDirection: NonNullable<\n ContextSettings[`pageTurnDirection`]\n >[]\n}\n\nexport class Features extends ReactiveEntity<State> {\n constructor(context: Context, settingsManager: ReaderSettingsManager) {\n super({\n supportedPageTurnAnimation: [`fade`, `none`, `slide`],\n supportedPageTurnMode: [`controlled`, `scrollable`],\n supportedPageTurnDirection: [`horizontal`, `vertical`],\n supportedComputedPageTurnDirection: [`horizontal`, `vertical`],\n })\n\n combineLatest([\n context.watch([\"manifest\", \"hasVerticalWriting\"]),\n settingsManager.watch([`computedPageTurnMode`]),\n ])\n .pipe(\n map(([{ manifest, hasVerticalWriting }, { computedPageTurnMode }]) => ({\n hasVerticalWriting,\n renditionFlow: manifest?.renditionFlow,\n renditionLayout: manifest?.renditionLayout,\n computedPageTurnMode,\n })),\n distinctUntilChanged(isShallowEqual),\n map(\n ({\n hasVerticalWriting,\n renditionFlow,\n renditionLayout,\n computedPageTurnMode,\n }) => {\n return {\n ...this.value,\n supportedPageTurnMode:\n renditionFlow === `scrolled-continuous`\n ? [`scrollable`]\n : [`controlled`, `scrollable`],\n supportedPageTurnAnimation:\n renditionFlow === `scrolled-continuous` ||\n computedPageTurnMode === `scrollable`\n ? [`none`]\n : hasVerticalWriting\n ? [`fade`, `none`]\n : [`fade`, `none`, `slide`],\n supportedPageTurnDirection:\n computedPageTurnMode === `scrollable`\n ? [`vertical`]\n : renditionLayout === `reflowable`\n ? [`horizontal`]\n : [`horizontal`, `vertical`],\n } satisfies State\n },\n ),\n takeUntil(this.destroy$),\n )\n .subscribe(this.next.bind(this))\n }\n}\n","import { combineLatest, of, Subject } from \"rxjs\"\nimport type {\n CoreHook,\n Hook,\n HookExecution,\n HookFrom,\n UserDestroyFn,\n} from \"./types\"\n\n// biome-ignore lint/suspicious/noExplicitAny: TODO\nexport class HookManager<H extends Hook<any, any, any> = CoreHook> {\n _hooks: Array<H> = []\n _hookExecutions: Array<HookExecution<H>> = []\n\n /**\n * Will:\n * - call destroy function for every execution of this specific hook\n * - remove the hook for further calls\n */\n protected deregister(hookToDeregister: H) {\n this._hooks = this._hooks.filter((hook) => hook !== hookToDeregister)\n\n return this.destroy(hookToDeregister.name, undefined, hookToDeregister)\n }\n\n /**\n * Ideal when your logic only needs to apply something to the item when it's loaded.\n * You can manipulate your item later if you need to update it and trigger a layout.\n * This logic will not run every time there is a layout.\n */\n public register<Name extends H[\"name\"]>(\n name: Name,\n fn: HookFrom<H, Name>[\"runFn\"],\n ) {\n const hook = {\n name,\n runFn: fn,\n }\n\n this._hooks.push(hook as H)\n\n return () => {\n this.deregister(hook as H)\n }\n }\n\n public execute<Name extends H[\"name\"]>(\n name: Name,\n id: string | undefined,\n params: Omit<\n Parameters<HookFrom<H, Name>[\"runFn\"]>[0],\n \"destroy\" | \"destroy$\"\n >,\n ): ReturnType<HookFrom<H, Name>[\"runFn\"]>[] {\n const hooks = this._hooks.filter(\n (hook): hook is HookFrom<H, Name> => name === hook.name,\n )\n\n const fnResults = hooks.map((hook) => {\n let userDestroyFn: UserDestroyFn = () => of(undefined)\n\n const destroySubject = new Subject<void>()\n const destroy = (fn: UserDestroyFn) => {\n userDestroyFn = fn\n }\n\n const destroyFn = () => {\n destroySubject.next()\n destroySubject.complete()\n\n const result = userDestroyFn()\n\n return result ?? of(undefined)\n }\n\n const fnResult = hook.runFn({\n // biome-ignore lint/suspicious/noExplicitAny: TODO\n ...(params as any),\n destroy$: destroySubject.asObservable(),\n destroy,\n })\n\n this._hookExecutions.push({\n name,\n id,\n destroyFn,\n ref: hook,\n })\n\n return fnResult\n })\n\n return fnResults\n }\n\n public destroy<Name extends H[\"name\"]>(name: Name, id?: string, ref?: H) {\n const instances = this._hookExecutions.filter(\n (hookInstance) =>\n // by ref is higher priority\n (ref && hookInstance.ref === ref) ||\n // otherwise we refine by name and eventually by id\n (name === hookInstance.name && (!id || (id && id === hookInstance.id))),\n )\n\n // remove destroyed instances from internal list\n this._hookExecutions = this._hookExecutions.filter(\n (instance) => !instances.includes(instance),\n )\n\n const destroyFns = instances.map(({ destroyFn }) => destroyFn())\n\n return combineLatest(destroyFns)\n }\n}\n","import { SpinePosition } from \"../../spine/types\"\n\n/**\n * LTR uses positive spine position and translate to negative translation.\n * Works both way for RTL.\n * @returns\n */\nexport const spinePositionToTranslation = (position: SpinePosition) => {\n return {\n x: -position.x,\n y: -position.y,\n }\n}\n\nexport const translationToSpinePosition = (\n translation: { x: number; y: number } | DOMMatrix,\n): SpinePosition => {\n if (translation instanceof DOMMatrix) {\n return new SpinePosition({\n x: -translation.e,\n y: -translation.f,\n })\n }\n\n return new SpinePosition({\n x: -translation.x,\n y: -translation.y,\n })\n}\n","import {\n animationFrameScheduler,\n BehaviorSubject,\n combineLatest,\n delay,\n filter,\n identity,\n map,\n merge,\n mergeMap,\n type Observable,\n of,\n Subject,\n share,\n shareReplay,\n startWith,\n switchMap,\n takeUntil,\n tap,\n withLatestFrom,\n} from \"rxjs\"\nimport { HTML_PREFIX } from \"../../constants\"\nimport type { Context } from \"../../context/Context\"\nimport type { HookManager } from \"../../hooks/HookManager\"\nimport { Report } from \"../../report\"\nimport type { ReaderSettingsManager } from \"../../settings/ReaderSettingsManager\"\nimport type { Spine } from \"../../spine/Spine\"\nimport { SpinePosition } from \"../../spine/types\"\nimport { DestroyableClass } from \"../../utils/DestroyableClass\"\nimport { isDefined } from \"../../utils/isDefined\"\nimport type { Viewport } from \"../../viewport/Viewport\"\nimport {\n spinePositionToTranslation,\n translationToSpinePosition,\n} from \"./positions\"\n\nconst NAMESPACE = `navigation/ViewportNavigator`\n\nconst report = Report.namespace(NAMESPACE)\n\nexport type ViewportNavigationEntry = {\n position: SpinePosition\n animation?: boolean | \"turn\" | \"snap\"\n}\n\nexport class ControlledNavigationController extends DestroyableClass {\n protected navigateSubject = new Subject<ViewportNavigationEntry>()\n\n public readonly element$ = new BehaviorSubject<HTMLElement>(\n document.createElement(`div`),\n )\n public isNavigating$: Observable<boolean>\n public layout$: Observable<unknown>\n\n constructor(\n protected settings: ReaderSettingsManager,\n protected hookManager: HookManager,\n protected context: Context,\n protected spine: Spine,\n protected viewport: Viewport,\n ) {\n super()\n\n const elementInit$ = this.spine.element$.pipe(\n filter(isDefined),\n withLatestFrom(this.element$),\n tap(([spineElement, element]) => {\n element.style.cssText = `\n height: 100%;\n width: 100%;\n position: relative;\n `\n element.className = `${HTML_PREFIX}-controlled-navigator`\n element.innerHTML = ``\n element.appendChild(spineElement)\n this.viewport.value.element.appendChild(element)\n this.element$.next(element)\n }),\n )\n\n const settingsThatRequireLayout$ = settings.watch([\n `computedPageTurnDirection`,\n `computedPageTurnMode`,\n `numberOfAdjacentSpineItemToPreLoad`,\n ])\n\n /**\n * Watch for settings update that require changes\n * on this layer.\n *\n * @important\n * Try not to have duplicate with other lower components that also listen to settings change and re-layout\n * on the same settings.\n */\n const updateElementOnSettingsChange$ = combineLatest([\n settingsThatRequireLayout$,\n this.element$,\n ]).pipe(\n tap(([, element]) => {\n if (settings.values.computedPageTurnMode === `scrollable`) {\n element.style.display = `contents`\n } else {\n element.style.display = `block`\n }\n }),\n )\n\n this.layout$ = updateElementOnSettingsChange$.pipe(\n tap(() => {\n report.info(`layout`, settings.values)\n }),\n share(),\n )\n\n const navigate$ = this.navigateSubject.pipe(\n tap((navigation) => {\n report.info(`Navigation requested`, navigation)\n }),\n )\n\n this.isNavigating$ = navigate$.pipe(\n map(({ animation, position }) => {\n const shouldAnimate = !(\n !animation ||\n (animation === `turn` &&\n settings.values.computedPageTurnAnimation === `none`)\n )\n\n return {\n type: `manualAdjust` as const,\n shouldAnimate,\n animation,\n position,\n }\n }),\n switchMap((currentEvent) => {\n const element = this.element$.getValue()\n\n // cleanup potential previous manual adjust\n element.style.setProperty(`transition`, `none`)\n element.style.setProperty(`opacity`, `1`)\n\n return merge(\n of(true),\n of(null).pipe(\n mergeMap(() => {\n if (currentEvent?.type !== `manualAdjust`) return of(false)\n\n const animationDuration =\n currentEvent.animation === `snap`\n ? settings.values.snapAnimationDuration\n : settings.values.computedPageTurnAnimationDuration\n const pageTurnAnimation =\n currentEvent.animation === `snap`\n ? (`slide` as const)\n : settings.values.computedPageTurnAnimation\n\n return of(currentEvent).pipe(\n /**\n * @important\n * Optimization:\n * When the adjustment does not need animation it means we want to be there as fast as possible\n * One example is when we adjust position after layout. In this case we don't want to have flicker or see\n * anything for x ms while we effectively adjust. We want it to be immediate.\n * However when user is repeatedly turning page, we can improve smoothness by delaying a bit the adjustment\n */\n currentEvent.shouldAnimate\n ? delay(1, animationFrameScheduler)\n : identity,\n tap((data) => {\n const element = this.element$.getValue()\n const noAdjustmentNeeded = false\n\n if (data.shouldAnimate && !noAdjustmentNeeded) {\n if (pageTurnAnimation === `fade`) {\n element.style.setProperty(\n `transition`,\n `opacity ${animationDuration / 2}ms`,\n )\n element.style.setProperty(`opacity`, `0`)\n } else if (\n currentEvent.animation === `snap` ||\n pageTurnAnimation === `slide`\n ) {\n element.style.setProperty(\n `transition`,\n `transform ${animationDuration}ms`,\n )\n element.style.setProperty(`opacity`, `1`)\n }\n } else {\n element.style.setProperty(`transition`, `none`)\n element.style.setProperty(`opacity`, `1`)\n }\n }),\n /**\n * @important\n * We always need to adjust the reading offset. Even if the current viewport value\n * is the same as the payload position. This is because an already running animation could\n * be active, meaning the viewport is still adjusting itself (after animation duration). So we\n * need to adjust to anchor to the payload position. This is because we use viewport computed position,\n * not the value set by `setProperty`\n */\n tap((data) => {\n if (pageTurnAnimation !== `fade`) {\n this.setViewportPosition(data.position)\n }\n }),\n currentEvent.shouldAnimate\n ? delay(animationDuration / 2, animationFrameScheduler)\n : identity,\n tap((data) => {\n const element = this.element$.getValue()\n\n if (pageTurnAnimation === `fade`) {\n this.setViewportPosition(data.position)\n element.style.setProperty(`opacity`, `1`)\n }\n }),\n currentEvent.shouldAnimate\n ? delay(animationDuration / 2, animationFrameScheduler)\n : identity,\n tap((data) => {\n if (pageTurnAnimation === `fade`) {\n this.setViewportPosition(data.position)\n }\n }),\n )\n }),\n map(() => false),\n ),\n )\n }),\n startWith(false),\n shareReplay(1),\n )\n\n merge(elementInit$, this.isNavigating$, this.layout$)\n .pipe(takeUntil(this.destroy$))\n .subscribe()\n }\n\n /**\n * Programmatically set the viewport position.\n *\n * Usually occurs due to navigation.\n *\n * @see https://stackoverflow.com/questions/22111256/translate3d-vs-translate-performance\n * for remark about flicker / fonts smoothing\n */\n protected setViewportPosition(position: SpinePosition) {\n const element = this.element$.getValue()\n\n const translation = spinePositionToTranslation(position)\n element.style.transform = `translate(${translation.x}px, ${translation.y}px)`\n\n this.hookManager.execute(\"onViewportOffsetAdjust\", undefined, {})\n }\n\n navigate(navigation: ViewportNavigationEntry) {\n this.navigateSubject.next(navigation)\n }\n\n /**\n * @important The reason we use computed transform and not bounding client is to avoid\n * transformation inconsistency between the viewport and the spine.\n */\n public get viewportPosition(): SpinePosition {\n const element = this.element$.getValue()\n\n const computedStyle = window.getComputedStyle(element)\n const transform = computedStyle.transform || computedStyle.webkitTransform\n\n if (!transform || transform === \"none\") {\n return new SpinePosition({ x: 0, y: 0 })\n }\n\n // Parse the transform matrix\n // The matrix is in the format: matrix(a, b, c, d, tx, ty) or matrix3d(...)\n const matrix = new DOMMatrix(transform)\n\n return translationToSpinePosition(matrix)\n }\n}\n","import { type Observable, map } from \"rxjs\"\nimport type { PaginationInfo } from \"../../pagination\"\nimport type { InternalNavigationEntry } from \"../types\"\n\ntype Navigation = {\n navigation: InternalNavigationEntry\n pagination: PaginationInfo\n}\n\nexport const withPaginationInfo =\n () =>\n <N extends Navigation>(stream: Observable<N>): Observable<N> => {\n return stream.pipe(\n map(({ navigation, pagination, ...rest }) => {\n return {\n navigation: {\n ...navigation,\n paginationBeginCfi: pagination.beginCfi,\n },\n ...rest,\n } as N\n }),\n )\n }\n","import {\n distinctUntilChanged,\n filter,\n first,\n map,\n type Observable,\n of,\n switchMap,\n withLatestFrom,\n} from \"rxjs\"\nimport type { Context } from \"../../context/Context\"\nimport type { Spine } from \"../../spine/Spine\"\nimport type { InternalNavigationEntry } from \"../types\"\nimport { withPaginationInfo } from \"./withPaginationInfo\"\n\nexport const consolidateWithPagination = (\n context: Context,\n navigation$: Observable<InternalNavigationEntry>,\n spine: Spine,\n) =>\n context.bridgeEvent.pagination$.pipe(\n withLatestFrom(navigation$),\n filter(\n ([pagination, navigation]) => pagination.navigationId === navigation.id,\n ),\n /**\n * We only register the pagination cfi IF the spine item is ready.\n * Otherwise we might save something incomplete and thus restore\n * the user to an invalid location.\n */\n switchMap(([pagination, navigation]) => {\n const spineItem = spine.spineItemsManager.get(navigation.spineItem)\n\n return (spineItem?.isReady$.pipe(first()) ?? of(false)).pipe(\n filter((isReady) => isReady),\n map(() => ({\n pagination,\n navigation,\n })),\n )\n }),\n withPaginationInfo(),\n distinctUntilChanged(\n (prev, curr) =>\n prev.navigation.paginationBeginCfi ===\n curr.navigation.paginationBeginCfi,\n ),\n map(\n ({ navigation }) =>\n ({\n ...navigation,\n meta: {\n triggeredBy: \"pagination\",\n },\n }) satisfies InternalNavigationEntry,\n ),\n )\n","import { map, type Observable } from \"rxjs\"\nimport type { NavigationResolver } from \"../resolvers/NavigationResolver\"\nimport type {\n InternalNavigationEntry,\n InternalNavigationInput,\n UserNavigationEntry,\n} from \"../types\"\n\nexport const mapUserNavigationToInternal =\n ({ navigationResolver }: { navigationResolver: NavigationResolver }) =>\n (\n stream: Observable<[UserNavigationEntry, InternalNavigationEntry]>,\n ): Observable<{\n navigation: InternalNavigationInput\n previousNavigation: InternalNavigationEntry\n }> => {\n return stream.pipe(\n map(([userNavigation, previousNavigation]) => {\n const navigation: InternalNavigationInput = {\n type: \"api\",\n meta: {\n triggeredBy: \"user\",\n },\n id: Symbol(),\n animation: \"turn\",\n ...userNavigation,\n /**\n * @important\n * For now we do not allow out of bounds positions. (this happens when scroll mode with a zoom out).\n * Although it's technically possible to be out of bounds, in terms of navigation and the rest of the app\n * it's hard to predict what will happens with negative x/y. spine item will not be retrieved, the spine position might\n * not be within anything (although the viewport slice is).\n *\n * Spine position should ideally be within the spine (even when viewport is scaled down/up). That's why we have viewport\n * on top of the spine.\n *\n * For now having things centered (negative x) on zoom out in scroll mode can be achieved with transform origin for example.\n * This \"limitation\" is here at the moment to avoid unexpected behaviors.\n *\n * @note\n * Has a bug where scaling from < 1 to 1 was creating positive x offset. This is \"expected\" since on scroll mode the viewport\n * is at the offset 0 at scale 0.2 for eg: then when calculating new scroll delta, we get positive x offset. Anyway, to prevent\n * out of bounds position this should make sure we always stay within an item.\n */\n position: userNavigation.position\n ? navigationResolver.fromOutOfBoundsSpinePosition(\n userNavigation.position,\n )\n : undefined,\n }\n\n return {\n previousNavigation,\n navigation,\n }\n }),\n )\n }\n","import { map, type Observable } from \"rxjs\"\nimport type { NavigationResolver } from \"../resolvers/NavigationResolver\"\nimport type { InternalNavigationInput } from \"../types\"\n\ntype Navigation = {\n navigation: InternalNavigationInput\n}\n\nexport const withCfiPosition =\n ({ navigationResolver }: { navigationResolver: NavigationResolver }) =>\n <N extends Navigation>(stream: Observable<N>): Observable<N> => {\n return stream.pipe(\n map((params) => {\n if (params.navigation.cfi) {\n const position = navigationResolver.getNavigationForCfi(\n params.navigation.cfi,\n )\n\n if (position) {\n return {\n ...params,\n navigation: {\n ...params.navigation,\n position,\n },\n } as N\n }\n }\n\n return params\n }),\n )\n }\n","import { map, type Observable } from \"rxjs\"\nimport type { Context } from \"../../context/Context\"\nimport type { ReaderSettingsManager } from \"../../settings/ReaderSettingsManager\"\nimport type { InternalNavigationEntry, InternalNavigationInput } from \"../types\"\n\ntype Navigation = {\n navigation: InternalNavigationInput\n previousNavigation: InternalNavigationEntry\n}\n\n/**\n * Since a consolidation happens synchronously after each navigation\n * we know we have at leat spine item everytime (independently from TS).\n *\n * For same spine item, we can only speculate\n */\nexport const getOrGuessDirection = ({\n navigation,\n previousNavigation,\n settings,\n}: {\n previousNavigation: InternalNavigationEntry\n navigation: InternalNavigationInput\n context: Context\n settings: ReaderSettingsManager\n}): InternalNavigationEntry[\"directionFromLastNavigation\"] => {\n /**\n * When we come from a restoration we might already have the\n * value setup, we should keep it.\n */\n if (navigation.directionFromLastNavigation)\n return navigation.directionFromLastNavigation\n\n // if (navigation.direction) {\n // switch (navigation.direction) {\n // case \"bottom\":\n // return \"forward\"\n // case \"top\":\n // return \"backward\"\n // case \"left\":\n // return context.isRTL() ? \"forward\" : \"backward\"\n // case \"right\":\n // return context.isRTL() ? \"backward\" : \"forward\"\n // }\n // }\n\n if (navigation.url !== undefined || navigation.cfi !== undefined) {\n return \"anchor\"\n }\n\n if (previousNavigation.spineItem === undefined) {\n return \"forward\"\n }\n\n /**\n * User navigate to specific spine item, we should\n * treat it as forward.\n *\n * Use case:\n * User navigate to back spine item & spine item is unloaded.\n * When spine item load and if we use backward, we will give the\n * idea the user want to be restored from the end of spine item whereas\n * he should be redirected to the begining of spine item.\n */\n if (navigation.spineItem) {\n return \"forward\"\n }\n\n if (!navigation.position) {\n return \"forward\"\n }\n\n /**\n * From this point forward, we can only make assumptions\n */\n if (settings.values.computedPageTurnDirection === \"vertical\") {\n if (navigation.position.y > previousNavigation.position.y) {\n return \"forward\"\n }\n\n if (\n navigation.position.y === previousNavigation.position.y &&\n previousNavigation.directionFromLastNavigation !== \"backward\"\n ) {\n return \"forward\"\n }\n return \"backward\"\n }\n\n if (\n Math.abs(navigation.position.x) > Math.abs(previousNavigation.position.x)\n ) {\n return \"forward\"\n }\n\n if (\n navigation.position.x === previousNavigation.position.x &&\n previousNavigation.directionFromLastNavigation !== \"backward\"\n ) {\n return \"forward\"\n }\n\n return \"backward\"\n}\n\nexport const withDirection =\n ({\n context,\n settings,\n }: {\n context: Context\n settings: ReaderSettingsManager\n }) =>\n (\n stream: Observable<Navigation>,\n ): Observable<\n Navigation & {\n direction: InternalNavigationEntry[\"directionFromLastNavigation\"]\n }\n > => {\n return stream.pipe(\n map(({ navigation, previousNavigation }) => {\n const direction = getOrGuessDirection({\n context,\n navigation,\n previousNavigation,\n settings,\n })\n\n const conslidatedNavigation: InternalNavigationInput = {\n ...navigation,\n directionFromLastNavigation: direction,\n }\n\n return {\n previousNavigation,\n navigation: conslidatedNavigation,\n direction,\n }\n }),\n )\n }\n","import { map, type Observable } from \"rxjs\"\nimport type { ReaderSettingsManager } from \"../../settings/ReaderSettingsManager\"\nimport type { SpineItemsManager } from \"../../spine/SpineItemsManager\"\nimport { UnboundSpinePosition } from \"../../spine/types\"\nimport type { NavigationResolver } from \"../resolvers/NavigationResolver\"\nimport type { InternalNavigationEntry, InternalNavigationInput } from \"../types\"\n\nexport const withFallbackPosition =\n ({\n spineItemsManager,\n navigationResolver,\n settings,\n }: {\n spineItemsManager: SpineItemsManager\n navigationResolver: NavigationResolver\n settings: ReaderSettingsManager\n }) =>\n <\n Navigation extends {\n navigation: InternalNavigationInput\n previousNavigation: InternalNavigationEntry\n },\n >(\n stream: Observable<Navigation>,\n ): Observable<\n Omit<Navigation, \"navigation\"> & {\n navigation: InternalNavigationEntry\n }\n > => {\n return stream.pipe(\n map(({ navigation, ...rest }) => {\n const spineItem = spineItemsManager.get(navigation.spineItem)\n\n if (navigation.position) {\n /**\n * Scrollable mode does allow unbound position by design.\n */\n if (settings.values.computedPageTurnMode === \"scrollable\") {\n return {\n navigation: {\n ...navigation,\n position: navigation.position,\n },\n ...rest,\n }\n }\n\n /**\n * We have been given position, we just make sure to prevent navigation\n * in outer edges.\n */\n return {\n navigation: {\n ...navigation,\n position: navigationResolver.fromUnboundSpinePosition(\n navigation.position,\n ),\n },\n ...rest,\n }\n }\n\n if (!spineItem)\n return {\n navigation: {\n ...navigation,\n position: rest.previousNavigation.position,\n },\n ...rest,\n }\n\n /**\n * Fallback.\n *\n * We get the most appropriate navigation for spine item.\n */\n const position =\n navigationResolver.getNavigationForSpineIndexOrId(spineItem)\n\n /**\n * We try to maintain x axis for scrollable mode.\n */\n const adjustedPosition =\n settings.values.computedPageTurnMode === \"scrollable\"\n ? new UnboundSpinePosition({\n x: position.x + rest.previousNavigation.position.x,\n y: position.y,\n })\n : navigationResolver.fromUnboundSpinePosition(position)\n\n return {\n navigation: {\n ...navigation,\n position: adjustedPosition,\n },\n ...rest,\n }\n }),\n )\n }\n","import { map, type Observable } from \"rxjs\"\nimport type { Context } from \"../../context/Context\"\nimport type { ReaderSettingsManager } from \"../../settings/ReaderSettingsManager\"\nimport type { SpineLocator } from \"../../spine/locator/SpineLocator\"\nimport type { SpineItemsManager } from \"../../spine/SpineItemsManager\"\nimport type { NavigationResolver } from \"../resolvers/NavigationResolver\"\nimport type { InternalNavigationInput } from \"../types\"\n\ntype Navigation = {\n navigation: InternalNavigationInput\n}\n\nexport const withSpineItem =\n ({\n settings,\n spineItemsManager,\n navigationResolver,\n spineLocator,\n }: {\n context: Context\n settings: ReaderSettingsManager\n spineItemsManager: SpineItemsManager\n navigationResolver: NavigationResolver\n spineLocator: SpineLocator\n }) =>\n <N extends Navigation>(stream: Observable<N>): Observable<N> => {\n const getSpineItem = (navigation: InternalNavigationInput) => {\n const {\n position,\n spineItem,\n cfi,\n directionFromLastNavigation: direction,\n } = navigation\n const { navigationSnapThreshold, computedPageTurnMode } = settings.values\n\n /**\n * - valid given spine item\n */\n if (spineItem !== undefined) {\n const existingSpineItem = spineItemsManager.get(spineItem)\n\n if (existingSpineItem) return existingSpineItem\n }\n\n /**\n * - invalid spine item given\n * - number too high\n * - number too low\n */\n if (typeof spineItem === \"number\") {\n if (spineItem > spineItemsManager.items.length - 1) {\n return spineItemsManager.get(spineItemsManager.items.length - 1)\n }\n\n return spineItemsManager.get(0)\n }\n\n /**\n * - cfi given\n * - we can grab safely the item\n */\n if (cfi) {\n const existingSpineItem = spineItemsManager.getSpineItemFromCfi(cfi)\n\n if (existingSpineItem) return existingSpineItem\n }\n\n /**\n * - controlled mode\n * - we have a position\n * - we retrieve the item that correspond the closest to the position\n */\n if (position && computedPageTurnMode === \"controlled\") {\n /**\n * @important\n *\n * Due to spread layout and/or LTR this part is a bit tricky.\n * It works in principe for a spread of N and any reading direction\n * since it uses begin/end concept.\n *\n * 1. We check the farthest visible spine item for the given navigation\n * 2. We check the farthest visible page for the item\n * 3. We retrieve the farthest navigable position.\n *\n * From that point we have the farthest navigable valid position for a given\n * navigation. (remember given navigation is not trustable). We will use this\n * navigation to lookup correctly the item\n *\n * 4. We lookup from the navigation the begin item (forward) or the end item (backward).\n */\n const { beginIndex, endIndex } =\n spineLocator.getVisibleSpineItemsFromPosition({\n position,\n threshold: navigationSnapThreshold,\n restrictToScreen: false,\n }) ?? {}\n\n const farthestSpineItemIndex =\n (direction === \"forward\" || direction === \"anchor\"\n ? endIndex\n : beginIndex) ?? beginIndex\n\n const farthestSpineItem = spineItemsManager.get(farthestSpineItemIndex)\n\n if (!farthestSpineItem) return undefined\n\n const { endPageIndex, beginPageIndex } =\n spineLocator.getVisiblePagesFromViewportPosition({\n position,\n spineItem: farthestSpineItem,\n threshold: navigationSnapThreshold,\n restrictToScreen: false,\n }) ?? {}\n\n const farthestVisiblePageIndex =\n (direction === \"forward\" || direction === \"anchor\"\n ? endPageIndex\n : beginPageIndex) ?? 0\n\n const navigationForPosition =\n navigationResolver.getNavigationForSpineItemPage({\n pageIndex: farthestVisiblePageIndex,\n spineItemId: farthestSpineItem,\n })\n\n const visibleSpineItemsFromNavigablePosition =\n spineLocator.getVisibleSpineItemsFromPosition({\n position: navigationForPosition,\n threshold: navigationSnapThreshold,\n restrictToScreen: false,\n })\n\n const finalSpineItemIndex =\n direction === \"forward\" || direction === \"anchor\"\n ? visibleSpineItemsFromNavigablePosition?.beginIndex\n : visibleSpineItemsFromNavigablePosition?.endIndex\n\n return spineItemsManager.get(finalSpineItemIndex)\n }\n\n /**\n * - scrollable content\n * - we have position\n * - we just pick the right item\n */\n if (position && computedPageTurnMode === \"scrollable\") {\n return spineLocator.getSpineItemFromPosition(position)\n }\n\n return spineItemsManager.get(0)\n }\n\n return stream.pipe(\n map(({ navigation, ...rest }) => {\n const spineItem = getSpineItem(navigation)\n\n return {\n navigation: {\n ...navigation,\n spineItem: spineItemsManager.getSpineItemIndex(spineItem),\n },\n ...rest,\n } as N\n }),\n )\n }\n","import { first, map, type Observable, of, switchMap } from \"rxjs\"\nimport type { Spine } from \"../../spine/Spine\"\nimport type { InternalNavigationEntry, InternalNavigationInput } from \"../types\"\n\ntype Navigation = {\n navigation: InternalNavigationInput | InternalNavigationEntry\n}\n\nexport const withSpineItemLayoutInfo =\n ({ spine }: { spine: Spine }) =>\n <N extends Navigation>(stream: Observable<N>): Observable<N> => {\n return stream.pipe(\n switchMap(({ navigation, ...rest }) => {\n const spineItemDimensions = spine.getSpineItemSpineLayoutInfo(\n navigation.spineItem,\n )\n const spineItem = spine.spineItemsManager.get(navigation.spineItem)\n\n return (spineItem?.isReady$ ?? of(false)).pipe(\n first(),\n map(\n (isReady) =>\n ({\n navigation: {\n ...navigation,\n spineItemHeight: spineItemDimensions?.height,\n spineItemWidth: spineItemDimensions?.width,\n spineItemLeft: spineItemDimensions.left,\n spineItemTop: spineItemDimensions.top,\n spineItemIsUsingVerticalWriting:\n spineItem?.isUsingVerticalWriting(),\n spineItemIsReady: isReady,\n },\n ...rest,\n }) as N,\n ),\n )\n }),\n )\n }\n","import { map, type Observable } from \"rxjs\"\nimport type { ReaderSettingsManager } from \"../../settings/ReaderSettingsManager\"\nimport type { SpineLocator } from \"../../spine/locator/SpineLocator\"\nimport type { SpineItemsManager } from \"../../spine/SpineItemsManager\"\nimport type { NavigationResolver } from \"../resolvers/NavigationResolver\"\nimport type { InternalNavigationEntry, InternalNavigationInput } from \"../types\"\n\ntype Navigation = {\n navigation: InternalNavigationEntry | InternalNavigationInput\n}\n\nexport const withSpineItemPosition =\n ({\n settings,\n spineItemsManager,\n spineLocator,\n navigationResolver,\n }: {\n settings: ReaderSettingsManager\n spineItemsManager: SpineItemsManager\n navigationResolver: NavigationResolver\n spineLocator: SpineLocator\n }) =>\n <N extends Navigation>(stream: Observable<N>): Observable<N> => {\n const getPosition = (navigation: N[\"navigation\"]) => {\n const { navigationSnapThreshold, computedPageTurnMode } = settings.values\n const spineItem = spineItemsManager.get(navigation.spineItem)\n\n if (!spineItem || !navigation.position) return undefined\n\n /**\n * - controlled mode\n * - we have navigation\n * - we update spine position from navigation\n */\n if (computedPageTurnMode === \"controlled\") {\n /**\n * @important\n *\n * Due to spread layout and/or LTR this part is a bit tricky.\n * It works in principe for a spread of N and any reading direction\n * since it uses begin/end concept.\n *\n * 1. We can trust the given spine item\n * 2. We get the farthest page from current position on item\n * - forward: we take end\n * - backward: we take begin\n * 3. We get navigable position for this page\n * 4. We get visible pages strictly for this position (no snapping)\n * - forward: we take begin\n * - backward: we take end\n * 5. We keep position in spine item for that page\n */\n const { endPageIndex, beginPageIndex } =\n spineLocator.getVisiblePagesFromViewportPosition({\n position: navigation.position,\n spineItem,\n threshold: navigationSnapThreshold,\n restrictToScreen: false,\n }) ?? {}\n\n const farthestPageIndex =\n (navigation.directionFromLastNavigation === \"forward\" ||\n navigation.directionFromLastNavigation === \"anchor\"\n ? endPageIndex\n : beginPageIndex) ?? 0\n\n const navigableSpinePositionForFarthestPageIndex =\n navigationResolver.getNavigationForSpineItemPage({\n pageIndex: farthestPageIndex,\n spineItemId: spineItem,\n })\n\n const visiblePagesAtNavigablePosition =\n spineLocator.getVisiblePagesFromViewportPosition({\n position: navigableSpinePositionForFarthestPageIndex,\n spineItem,\n threshold: { type: \"percentage\", value: 0 },\n restrictToScreen: true,\n })\n\n const beginPageIndexForDirection =\n (navigation.directionFromLastNavigation === \"forward\" ||\n navigation.directionFromLastNavigation === \"anchor\"\n ? visiblePagesAtNavigablePosition?.beginPageIndex\n : visiblePagesAtNavigablePosition?.endPageIndex) ?? 0\n\n const positionInSpineItem =\n spineLocator.spineItemLocator.getSpineItemPositionFromPageIndex({\n pageIndex: beginPageIndexForDirection,\n spineItem,\n })\n\n return positionInSpineItem\n }\n\n /**\n * - fallback\n * - we just get position in item from item\n */\n return spineLocator.getSpineItemPositionFromSpinePosition(\n navigation.position,\n spineItem,\n )\n }\n\n return stream.pipe(\n map(({ navigation, ...rest }) => {\n return {\n navigation: {\n ...navigation,\n positionInSpineItem: getPosition(navigation),\n },\n ...rest,\n } as N\n }),\n )\n }\n","import { map, type Observable } from \"rxjs\"\nimport type { NavigationResolver } from \"../resolvers/NavigationResolver\"\nimport type { InternalNavigationInput } from \"../types\"\n\ntype Navigation = {\n navigation: InternalNavigationInput\n}\n\nexport const withUrlInfo =\n ({ navigationResolver }: { navigationResolver: NavigationResolver }) =>\n <N extends Navigation>(stream: Observable<N>): Observable<N> => {\n return stream.pipe(\n map((params) => {\n if (params.navigation.url) {\n const result = navigationResolver.getNavigationForUrl(\n params.navigation.url,\n )\n\n if (result) {\n return {\n ...params,\n navigation: {\n ...params.navigation,\n position: result.position,\n spineItem: result.spineItemId,\n },\n } as N\n }\n }\n\n return params\n }),\n )\n }\n","import { BehaviorSubject, distinctUntilChanged, map } from \"rxjs\"\n\nexport class Locker {\n protected isLockedSubject = new BehaviorSubject(0)\n\n public isLocked$ = this.isLockedSubject.pipe(\n map((locked) => !!locked),\n distinctUntilChanged(),\n )\n\n public lock() {\n let isCalled = false\n this.isLockedSubject.next(this.isLockedSubject.getValue() + 1)\n\n return () => {\n if (isCalled) return\n\n isCalled = true\n\n this.isLockedSubject.next(this.isLockedSubject.getValue() - 1)\n }\n }\n}\n","import { type Observable, first, map, of } from \"rxjs\"\nimport { isRootCfi } from \"../../cfi\"\nimport type { Spine } from \"../../spine/Spine\"\nimport type { SpineItemsManager } from \"../../spine/SpineItemsManager\"\nimport type { SpineLocator } from \"../../spine/locator/SpineLocator\"\nimport { SpinePosition } from \"../../spine/types\"\nimport { SpineItemPosition } from \"../../spineItem/types\"\nimport type { NavigationResolver } from \"../resolvers/NavigationResolver\"\nimport type { InternalNavigationEntry } from \"../types\"\n\nexport const restoreNavigationForControlledPageTurnMode = ({\n spineLocator,\n navigation,\n navigationResolver,\n spineItemsManager,\n spine,\n}: {\n navigation: InternalNavigationEntry\n spineLocator: SpineLocator\n navigationResolver: NavigationResolver\n spineItemsManager: SpineItemsManager\n spine: Spine\n}): Observable<SpinePosition> => {\n const spineItem = spineItemsManager.get(navigation.spineItem)\n\n if (!spineItem) {\n return of(new SpinePosition({ x: 0, y: 0 }))\n }\n\n return spineItem.isReady$.pipe(\n first(),\n map((isReady) => {\n const spineItemAbsolutePosition =\n spine.getSpineItemSpineLayoutInfo(spineItem)\n\n const isPositionWithinSpineItem = spineLocator.isPositionWithinSpineItem(\n navigation.position,\n spineItem,\n )\n\n const spineItemWidthDifference =\n spineItemAbsolutePosition.width - (navigation.spineItemWidth ?? 0)\n const spineItemHeighDifference =\n spineItemAbsolutePosition.height - (navigation.spineItemHeight ?? 0)\n\n const hasSpineItemGrewOrShrink =\n spineItemWidthDifference !== 0 || spineItemHeighDifference !== 0\n\n /**\n * Url navigation has higher priority together with CFI, we should\n * restore from it first.\n *\n * If the layout did not change, we should not restore from cfi since\n * we will have better accuracy from all other consolidation.\n *\n * Basically as long as the item itself did not change, we can recover from\n * consolidation. In case the item changed, we should be careful and try to\n * anchor back to cfi.\n */\n if (navigation.url !== undefined) {\n if (\n spineItemWidthDifference ||\n spineItemHeighDifference ||\n // when spine item is ready dimensions may have not changed but the position\n // of dom elements may have!\n (isReady && !navigation.spineItemIsReady)\n ) {\n const urlResult = navigationResolver.getNavigationForUrl(\n navigation.url,\n )\n\n if (urlResult) {\n return urlResult.position\n }\n }\n }\n\n const cfi = navigation.cfi ?? navigation.paginationBeginCfi\n\n /**\n * Restoration from cfi.\n * If the layout did not change, we should not restore from cfi since\n * we will have better accuracy from all other consolidation.\n *\n * Basically as long as the item itself did not change, we can recover from\n * consolidation. In case the item changed, we should be careful and try to\n * anchor back to cfi.\n */\n if (cfi !== undefined && !isRootCfi(cfi)) {\n if (\n spineItemWidthDifference ||\n spineItemHeighDifference ||\n // when spine item is ready dimensions may have not changed but the position\n // of dom elements may have!\n (isReady && !navigation.spineItemIsReady)\n ) {\n const cfiResultPosition = navigationResolver.getNavigationForCfi(cfi)\n\n if (cfiResultPosition) {\n return cfiResultPosition\n }\n }\n }\n\n if (\n isPositionWithinSpineItem &&\n hasSpineItemGrewOrShrink &&\n navigation.directionFromLastNavigation === \"backward\"\n ) {\n const positionInSpineItemWithDifference = new SpineItemPosition({\n x:\n (navigation.positionInSpineItem?.x ?? 0) + spineItemWidthDifference,\n y:\n (navigation.positionInSpineItem?.y ?? 0) + spineItemHeighDifference,\n })\n\n return navigationResolver.getNavigationFromSpineItemPosition({\n spineItem,\n spineItemPosition: positionInSpineItemWithDifference,\n })\n }\n\n /**\n * - position in spine item known\n * - dimensions of item known\n * - we can retrieve the desired page index\n * - we get navigation for same page on current item\n */\n if (\n navigation.positionInSpineItem &&\n navigation.spineItemHeight &&\n navigation.spineItemWidth\n ) {\n const pageIndex =\n spineLocator.spineItemLocator.getSpineItemPageIndexFromPosition({\n itemWidth: navigation.spineItemWidth,\n itemHeight: navigation.spineItemHeight,\n isUsingVerticalWriting:\n !!navigation.spineItemIsUsingVerticalWriting,\n position: navigation.positionInSpineItem,\n })\n\n return navigationResolver.getNavigationForSpineItemPage({\n pageIndex,\n spineItemId: spineItem,\n })\n }\n\n /**\n * - position is within spine item\n * - position is somewhat trustable\n * - we will retrieve the closest valid navigation\n */\n if (isPositionWithinSpineItem) {\n return navigationResolver.getNavigationForPosition(navigation.position)\n }\n\n /**\n * - position is not within spine item\n * - position is not trustable\n * - fallback to default navigation for spine item\n */\n return navigationResolver.getNavigationForSpineIndexOrId(spineItem)\n }),\n )\n}\n","import { type Observable, of } from \"rxjs\"\nimport type { Context } from \"../../context/Context\"\nimport type { ReaderSettingsManager } from \"../../settings/ReaderSettingsManager\"\nimport type { SpineLocator } from \"../../spine/locator/SpineLocator\"\nimport type { Spine } from \"../../spine/Spine\"\nimport type { SpineItemsManager } from \"../../spine/SpineItemsManager\"\nimport { SpinePosition, type UnboundSpinePosition } from \"../../spine/types\"\nimport type { SpineItemLocator } from \"../../spineItem/locationResolver\"\nimport { SpineItemPosition } from \"../../spineItem/types\"\nimport type { NavigationResolver } from \"../resolvers/NavigationResolver\"\nimport type { InternalNavigationEntry } from \"../types\"\nimport { restoreNavigationForControlledPageTurnMode } from \"./restoreNavigationForControlledPageTurnMode\"\n\nconst restoreNavigationForScrollingPageTurnMode = ({\n navigation,\n spineLocator,\n spineItemsManager,\n settings,\n navigationResolver,\n spine,\n}: {\n spineItemsManager: SpineItemsManager\n spineLocator: SpineLocator\n settings: ReaderSettingsManager\n navigationResolver: NavigationResolver\n navigation: InternalNavigationEntry\n spine: Spine\n}): InternalNavigationEntry[\"position\"] => {\n const { spineItem } = navigation\n const foundSpineItem = spineItemsManager.get(spineItem)\n\n if (!foundSpineItem) return new SpinePosition({ x: 0, y: 0 })\n\n const { height, top } = spine.getSpineItemSpineLayoutInfo(foundSpineItem)\n\n const isPositionWithinSpineItem = spineLocator.isPositionWithinSpineItem(\n navigation.position,\n foundSpineItem,\n )\n\n const positionInSpineItem =\n navigation.positionInSpineItem ??\n new SpineItemPosition({\n y: 0,\n x: 0,\n })\n\n /**\n * - vertical scroll\n */\n if (settings.values.computedPageTurnDirection === \"vertical\") {\n /**\n * - item did not shift\n * - item same height\n * - we are still within the item\n */\n if (\n top === navigation.spineItemTop &&\n height === navigation.spineItemHeight &&\n isPositionWithinSpineItem\n ) {\n /**\n * -> nothing\n */\n return navigation.position\n }\n\n /**\n * vertical scroll\n * - item did not shift\n * - item same height\n * - not within item\n */\n if (\n top === navigation.spineItemTop &&\n height === navigation.spineItemHeight &&\n !isPositionWithinSpineItem\n ) {\n /**\n * -> fallback to beginning of item\n */\n return navigationResolver.getNavigationForSpineIndexOrId(foundSpineItem)\n }\n\n /**\n * - item shifted\n */\n if (top !== navigation.spineItemTop) {\n /**\n * -> fallback to position we were in spine item\n */\n const positionInSpineItem =\n spineLocator.getSafeSpineItemPositionFromUnsafeSpineItemPosition(\n navigation.positionInSpineItem ??\n new SpineItemPosition({\n x: 0,\n y: 0,\n }),\n foundSpineItem,\n )\n\n return spineLocator.getSpinePositionFromSpineItemPosition({\n spineItemPosition: positionInSpineItem,\n spineItem: foundSpineItem,\n })\n }\n\n /**\n * - item did not shift\n * - height changed\n */\n if (\n top === navigation.spineItemTop &&\n height !== navigation.spineItemHeight\n ) {\n const positionYfromBottomPreviousNavigation =\n (navigation.spineItemHeight ?? positionInSpineItem.y) -\n positionInSpineItem.y\n\n const positionInspineItem = new SpineItemPosition({\n y:\n navigation.directionFromLastNavigation === \"backward\"\n ? height - positionYfromBottomPreviousNavigation\n : positionInSpineItem.y,\n x: navigation.position.x,\n })\n\n /**\n * - position within item\n *\n * @problems\n * - position may be wrong since the item changed its content\n *\n * @restoration\n * We try to get as much as info as possible from previous navigation\n * so we can find the best accurate spot the user was\n */\n if (isPositionWithinSpineItem) {\n /**\n * - we navigate to the closest valid position\n */\n const positionInSpineItem =\n spineLocator.getSafeSpineItemPositionFromUnsafeSpineItemPosition(\n positionInspineItem,\n foundSpineItem,\n )\n\n return spineLocator.getSpinePositionFromSpineItemPosition({\n spineItemPosition: positionInSpineItem,\n spineItem: foundSpineItem,\n })\n }\n\n /**\n * - position not within item anymore\n */\n if (!isPositionWithinSpineItem) {\n const positionIsBeforeItem = navigation.position.y < top\n\n /**\n * In case the navigation is too far down, we try to anchor back to\n * the spine item but we also try to keep the same previous offset\n * we had, the point is not to just anchor back to the begining or the\n * exact end of the spine item.\n * example:\n * - we are at 100px from bottom of a 300px height item\n * - layout happens and item becomes 200px height\n * - we are now at the end of item, we need to go back by 100px\n */\n if (!positionIsBeforeItem) {\n const positionInItem = new SpineItemPosition({\n y: height - positionYfromBottomPreviousNavigation,\n x: navigation.position.x,\n })\n\n return spineLocator.getSpinePositionFromSpineItemPosition({\n spineItemPosition:\n spineLocator.getSafeSpineItemPositionFromUnsafeSpineItemPosition(\n positionInItem,\n foundSpineItem,\n ),\n spineItem: foundSpineItem,\n })\n }\n\n /**\n * - we anchor back to begining of item\n */\n return navigationResolver.getNavigationForSpineIndexOrId(foundSpineItem)\n }\n }\n }\n\n return navigation.position\n}\n\nexport const restorePosition = ({\n navigation,\n spineItemsManager,\n settings,\n spineLocator,\n navigationResolver,\n spine,\n}: {\n spineLocator: SpineLocator\n settings: ReaderSettingsManager\n navigationResolver: NavigationResolver\n navigation: InternalNavigationEntry\n spineItemsManager: SpineItemsManager\n spineItemLocator: SpineItemLocator\n context: Context\n spine: Spine\n}): Observable<SpinePosition | UnboundSpinePosition> => {\n if (settings.values.computedPageTurnMode === \"scrollable\") {\n return of(\n restoreNavigationForScrollingPageTurnMode({\n navigation,\n spineLocator,\n navigationResolver,\n settings,\n spineItemsManager,\n spine,\n }),\n )\n }\n\n return restoreNavigationForControlledPageTurnMode({\n navigation,\n spineLocator,\n navigationResolver,\n spineItemsManager,\n spine,\n })\n}\n","import { map, type Observable, switchMap } from \"rxjs\"\nimport type { Context } from \"../../context/Context\"\nimport type { ReaderSettingsManager } from \"../../settings/ReaderSettingsManager\"\nimport type { Spine } from \"../../spine/Spine\"\nimport type { NavigationResolver } from \"../resolvers/NavigationResolver\"\nimport type { InternalNavigationEntry } from \"../types\"\nimport { restorePosition } from \"./restorePosition\"\n\ntype Navigation = {\n navigation: InternalNavigationEntry\n}\n\nexport const withRestoredPosition =\n ({\n settings,\n navigationResolver,\n context,\n spine,\n }: {\n navigationResolver: NavigationResolver\n settings: ReaderSettingsManager\n context: Context\n spine: Spine\n }) =>\n <N extends Navigation>(stream: Observable<N>): Observable<N> =>\n stream.pipe(\n switchMap((params) => {\n return restorePosition({\n spineLocator: spine.locator,\n navigation: params.navigation,\n navigationResolver,\n settings,\n spineItemsManager: spine.spineItemsManager,\n spineItemLocator: spine.locator.spineItemLocator,\n context,\n spine,\n }).pipe(\n map((restoredPosition) => ({\n ...params,\n navigation: {\n ...params.navigation,\n position: restoredPosition,\n },\n })),\n )\n }),\n )\n","import {\n BehaviorSubject,\n distinctUntilChanged,\n filter,\n finalize,\n first,\n identity,\n map,\n merge,\n type Observable,\n of,\n share,\n shareReplay,\n skip,\n switchMap,\n takeUntil,\n tap,\n withLatestFrom,\n} from \"rxjs\"\nimport type { Context } from \"../context/Context\"\nimport { Report } from \"../report\"\nimport type { ReaderSettingsManager } from \"../settings/ReaderSettingsManager\"\nimport type { Spine } from \"../spine/Spine\"\nimport { SpinePosition } from \"../spine/types\"\nimport { DestroyableClass } from \"../utils/DestroyableClass\"\nimport { isShallowEqual } from \"../utils/objects\"\nimport { consolidateWithPagination } from \"./consolidation/consolidateWithPagination\"\nimport { mapUserNavigationToInternal } from \"./consolidation/mapUserNavigationToInternal\"\nimport { withCfiPosition } from \"./consolidation/withCfiPosition\"\nimport { withDirection } from \"./consolidation/withDirection\"\nimport { withFallbackPosition } from \"./consolidation/withFallbackPosition\"\nimport { withSpineItem } from \"./consolidation/withSpineItem\"\nimport { withSpineItemLayoutInfo } from \"./consolidation/withSpineItemLayoutInfo\"\nimport { withSpineItemPosition } from \"./consolidation/withSpineItemPosition\"\nimport { withUrlInfo } from \"./consolidation/withUrlInfo\"\nimport type { ControlledNavigationController } from \"./controllers/ControlledNavigationController\"\nimport type { ScrollNavigationController } from \"./controllers/ScrollNavigationController\"\nimport { Locker } from \"./Locker\"\nimport type { createNavigationResolver } from \"./resolvers/NavigationResolver\"\nimport { withRestoredPosition } from \"./restoration/withRestoredPosition\"\nimport type { InternalNavigationEntry, UserNavigationEntry } from \"./types\"\n\nconst NAMESPACE = `navigation/InternalNavigator`\n\nconst report = Report.namespace(NAMESPACE)\n\nexport class InternalNavigator extends DestroyableClass {\n /**\n * This position correspond to the current navigation position.\n * This is always sync with navigation and adjustment but IS NOT necessarily\n * synced with current viewport. This is because viewport can be animated.\n * This value may be used to adjust / get current valid info about what should be visible.\n * This DOES NOT reflect necessarily what is visible for the user at instant T.\n */\n public navigationSubject = new BehaviorSubject<InternalNavigationEntry>({\n animation: false,\n position: new SpinePosition({ x: 0, y: 0 }),\n meta: {\n triggeredBy: \"user\",\n },\n spineItemIsReady: false,\n type: \"api\",\n id: Symbol(),\n })\n\n public navigated$ = this.navigationSubject.pipe(skip(1))\n\n public navigation$ = this.navigationSubject.pipe(\n map(({ position, id }) => ({\n position,\n id,\n })),\n distinctUntilChanged(\n (\n { position: previousPosition, ...previousRest },\n { position: currentPosition, ...currentRest },\n ) =>\n isShallowEqual(previousRest, currentRest) &&\n isShallowEqual(previousPosition, currentPosition),\n ),\n shareReplay(1),\n )\n\n public locker = new Locker()\n\n constructor(\n protected settings: ReaderSettingsManager,\n protected context: Context,\n protected userNavigation$: Observable<UserNavigationEntry>,\n protected controlledNavigationController: ControlledNavigationController,\n protected scrollNavigationController: ScrollNavigationController,\n protected navigationResolver: ReturnType<typeof createNavigationResolver>,\n protected spine: Spine,\n /**\n * Allow automatic restoration to happens.\n * - correction of position\n * - restoration of position\n */\n protected isRestorationLocked$: Observable<boolean>,\n ) {\n super()\n\n const navigationFromUser$ = userNavigation$\n .pipe(\n withLatestFrom(this.navigationSubject),\n mapUserNavigationToInternal({\n navigationResolver,\n }),\n /**\n * Url lookup is heavier so we start with it to fill\n * as much information as needed to reduce later lookup\n */\n withUrlInfo({\n navigationResolver,\n }),\n /**\n * Cfi lookup is heavier so we start with it to fill\n * as much information as needed to reduce later lookup\n */\n withCfiPosition({\n navigationResolver,\n }),\n withDirection({ context, settings }),\n withSpineItem({\n context,\n navigationResolver,\n settings,\n spineItemsManager: spine.spineItemsManager,\n spineLocator: spine.locator,\n }),\n withSpineItemPosition({\n navigationResolver,\n settings,\n spineItemsManager: spine.spineItemsManager,\n spineLocator: spine.locator,\n }),\n withSpineItemLayoutInfo({\n spine,\n }),\n )\n .pipe(\n withFallbackPosition({\n navigationResolver,\n spineItemsManager: spine.spineItemsManager,\n settings,\n }),\n withLatestFrom(isRestorationLocked$),\n switchMap(([params, isUserLocked]) => {\n const shouldNotAlterPosition =\n params.navigation.cfi ||\n params.navigation.url ||\n settings.values.computedPageTurnMode === \"scrollable\" ||\n isUserLocked\n\n return of(params).pipe(\n shouldNotAlterPosition\n ? identity\n : withRestoredPosition({\n navigationResolver,\n settings,\n spine,\n context,\n }),\n )\n }),\n withSpineItemPosition({\n spineItemsManager: spine.spineItemsManager,\n spineLocator: spine.locator,\n settings,\n navigationResolver,\n }),\n map((params) => params.navigation),\n share(),\n )\n\n const navigationUpdateFollowingUserUnlock$ = navigationFromUser$.pipe(\n withLatestFrom(isRestorationLocked$),\n filter(([, isUserLocked]) => isUserLocked),\n switchMap(([navigation]) => {\n // @todo emit true/false to keep stream pure\n const unlock = this.locker.lock()\n\n return isRestorationLocked$.pipe(\n filter((isUserLocked) => !isUserLocked),\n first(),\n map(\n (): InternalNavigationEntry => ({\n ...navigation,\n animation: \"snap\" as const,\n }),\n ),\n finalize(() => {\n unlock()\n }),\n takeUntil(navigationFromUser$),\n )\n }),\n share(),\n )\n\n /**\n * Once a layout change happens we want\n * to validate the navigation. Basically we make sure the current navigation\n * is correct for the current layout.\n *\n * @important\n * We want the restoration to happens as fast as possible so it is invisible for the user.\n * Consider the scenario where an item load / unload and create a shift, we want\n * the user to be restored instantly.\n *\n * This means that if a layout happens during navigation, we will cut it and navigate\n * directly to new position. NO layout should happens during viewport busy.\n * This is responsibility of other components.\n */\n const navigationUpdateFromLayout$ = merge(\n controlledNavigationController.layout$,\n spine.layout$,\n ).pipe(\n switchMap(() => {\n return of(null).pipe(\n switchMap(() =>\n isRestorationLocked$.pipe(\n filter((isLocked) => !isLocked),\n first(),\n ),\n ),\n map(\n (): InternalNavigationEntry => ({\n ...this.navigationSubject.getValue(),\n animation: false,\n }),\n ),\n /**\n * We need to cancel the restoration as soon as there is\n * another navigation. Whether it's user or internal, it means\n * it has been controlled outside.\n */\n takeUntil(\n merge(navigationUpdateFollowingUserUnlock$, navigationFromUser$),\n ),\n )\n }),\n )\n\n const navigationRestored$ = merge(\n navigationUpdateFromLayout$,\n navigationUpdateFollowingUserUnlock$,\n ).pipe(\n map((navigation) => ({ navigation })),\n withRestoredPosition({\n navigationResolver,\n settings,\n context,\n spine,\n }),\n map((params) => {\n const navigation: InternalNavigationEntry = {\n ...params.navigation,\n meta: {\n triggeredBy: `restoration`,\n },\n }\n\n return {\n ...params,\n navigation,\n }\n }),\n /**\n * The spine item may be undefined after a restoration.\n * eg: after the reader load and the user has never navigated\n * yet.\n */\n withSpineItem({\n context,\n navigationResolver,\n settings,\n spineItemsManager: spine.spineItemsManager,\n spineLocator: spine.locator,\n }),\n withSpineItemLayoutInfo({\n spine,\n }),\n withSpineItemPosition({\n spineItemsManager: spine.spineItemsManager,\n spineLocator: spine.locator,\n settings,\n navigationResolver,\n }),\n map(({ navigation }) => navigation),\n share(),\n )\n\n // @todo export\n // @todo we should only update the cfi if the content of the\n // item change, because otherwise every time the viewport get bigger\n // the pagination cfi will change and thus this one too, indefinitely\n // pulling the user back since we always use the first visible node\n const navigationUpdateOnPaginationUpdate$ = consolidateWithPagination(\n context,\n this.navigationSubject,\n spine,\n )\n\n const navigationUpdate$ = merge(\n navigationRestored$,\n navigationFromUser$,\n navigationUpdateOnPaginationUpdate$,\n )\n\n const notifyNavigationUpdate = (\n stream: Observable<[InternalNavigationEntry, InternalNavigationEntry]>,\n ) =>\n stream.pipe(\n tap(([currentNavigation, previousNavigation]) => {\n report.info(\n `navigation updated from ${currentNavigation.meta.triggeredBy} of type ${currentNavigation.type}`,\n {\n previousNavigation,\n currentNavigation,\n },\n )\n\n this.navigationSubject.next(currentNavigation)\n }),\n )\n\n const navigateViewport = (\n stream: Observable<[InternalNavigationEntry, InternalNavigationEntry]>,\n ) =>\n stream.pipe(\n tap(([currentNavigation, previousNavigation]) => {\n const isScrollFromUser = currentNavigation.type === `scroll`\n const isPaginationUpdate =\n currentNavigation.meta.triggeredBy === \"pagination\"\n const isRestoration =\n currentNavigation.meta.triggeredBy === \"restoration\"\n const positionIsSame = isShallowEqual(\n previousNavigation.position,\n currentNavigation.position,\n )\n\n if (\n (isScrollFromUser && !isRestoration) ||\n isPaginationUpdate ||\n positionIsSame\n )\n return\n\n const navigation = {\n position: currentNavigation.position,\n animation: currentNavigation.animation,\n }\n\n if (settings.values.computedPageTurnMode === `scrollable`) {\n this.scrollNavigationController.navigate(navigation)\n } else {\n this.controlledNavigationController.navigate({\n ...navigation,\n /**\n * @important\n * Explicitly trust the unbound position to be valid at this point.\n * Thanks to consolidation and restoration.\n */\n position: SpinePosition.from(navigation.position),\n })\n }\n }),\n )\n\n navigationUpdate$\n .pipe(\n withLatestFrom(this.navigationSubject),\n /**\n * @important\n *\n * We need to start navigating viewport before notifying navigation\n * change, this is to keep viewportState sync and avoid a \"free\" ping\n * in between.\n */\n navigateViewport,\n notifyNavigationUpdate,\n takeUntil(this.destroy$),\n )\n .subscribe()\n }\n\n get navigation() {\n return this.navigationSubject.getValue()\n }\n}\n","export const getItemOffsetFromPageIndex = (\n pageWidth: number,\n pageIndex: number,\n itemWidth: number,\n) => {\n const lastPageOffset = itemWidth - pageWidth\n const logicalOffset = (itemWidth * (pageIndex * pageWidth)) / (itemWidth || 1)\n\n return Math.max(0, Math.min(lastPageOffset, logicalOffset))\n}\n\nexport const calculateNumberOfPagesForItem = (\n itemWidth: number,\n pageWidth: number,\n) => {\n if ((pageWidth || 0) === 0 || (itemWidth || 0) === 0) return 1\n return Math.floor(Math.max(1, itemWidth / pageWidth))\n}\n\nexport const getClosestValidOffsetFromApproximateOffsetInPages = (\n offset: number,\n pageWidth: number,\n itemWidth: number,\n) => {\n const numberOfPages = calculateNumberOfPagesForItem(itemWidth, pageWidth)\n const offsetValues = [...Array(numberOfPages)].map((_, i) => i * pageWidth)\n\n if (offset >= numberOfPages * pageWidth)\n return offsetValues[offsetValues.length - 1] || 0\n\n return (\n offsetValues.find((offsetRange) => offset < offsetRange + pageWidth) || 0\n )\n}\n","export const getPageFromOffset = (\n offset: number,\n pageWidth: number,\n numberOfPages: number,\n) => {\n const offsetValues = [...Array(numberOfPages)].map((_, i) => i * pageWidth)\n\n if (offset <= 0 || numberOfPages === 0) return 0\n\n if (offset >= numberOfPages * pageWidth) return numberOfPages - 1\n\n return (\n offsetValues.findIndex((offsetRange) => offset < offsetRange + pageWidth) ??\n 0\n )\n}\n","import { SpineItemPosition } from \"../types\"\n\nexport const getSafePosition = ({\n itemWidth,\n itemHeight,\n spineItemPosition,\n}: {\n spineItemPosition: SpineItemPosition\n itemWidth: number\n itemHeight: number\n}): SpineItemPosition =>\n new SpineItemPosition({\n x: Math.min(itemWidth, Math.max(0, spineItemPosition.x)),\n y: Math.min(itemHeight, Math.max(0, spineItemPosition.y)),\n })\n","import { calculateNumberOfPagesForItem } from \"../helpers\"\n\nexport const getSpineItemNumberOfPages = ({\n itemHeight,\n itemWidth,\n isUsingVerticalWriting,\n pageWidth,\n pageHeight,\n pageTurnDirection,\n pageTurnMode,\n}: {\n itemWidth: number\n itemHeight: number\n isUsingVerticalWriting: boolean\n pageWidth: number\n pageHeight: number\n pageTurnDirection: \"vertical\" | \"horizontal\"\n pageTurnMode: \"scrollable\" | \"controlled\"\n}) => {\n if (pageTurnDirection === `vertical` && pageTurnMode === `scrollable`) {\n return 1\n }\n\n if (isUsingVerticalWriting || pageTurnDirection === `vertical`) {\n return calculateNumberOfPagesForItem(itemHeight, pageHeight)\n }\n\n return calculateNumberOfPagesForItem(itemWidth, pageWidth)\n}\n","import type { SpineItemPosition } from \"../types\"\nimport { getPageFromOffset } from \"./getPageFromOffset\"\nimport { getSafePosition } from \"./getSafePosition\"\nimport { getSpineItemNumberOfPages } from \"./getSpineItemNumberOfPages\"\n\n/**\n * @important\n * This calculation takes blank page into account, the iframe could be only one page but with a blank page\n * positioned before. Resulting on two page index possible values (0 & 1).\n */\nexport const getSpineItemPageIndexFromSpineItemPosition = ({\n itemWidth,\n itemHeight,\n position,\n isUsingVerticalWriting,\n pageWidth,\n pageHeight,\n pageTurnDirection,\n pageTurnMode,\n isRTL,\n}: {\n itemWidth: number\n itemHeight: number\n position: SpineItemPosition\n isUsingVerticalWriting: boolean\n pageWidth: number\n pageHeight: number\n pageTurnDirection: \"vertical\" | \"horizontal\"\n pageTurnMode: \"scrollable\" | \"controlled\"\n isRTL: boolean\n}) => {\n const safePosition = getSafePosition({\n spineItemPosition: position,\n itemHeight,\n itemWidth,\n })\n\n const offset = safePosition.x\n\n const numberOfPages = getSpineItemNumberOfPages({\n isUsingVerticalWriting,\n itemHeight,\n itemWidth,\n pageWidth,\n pageHeight,\n pageTurnDirection,\n pageTurnMode,\n })\n\n if (isUsingVerticalWriting) {\n return getPageFromOffset(position.y, pageHeight, numberOfPages)\n }\n\n const pageIndex = getPageFromOffset(offset, pageWidth, numberOfPages)\n\n if (isRTL) {\n // Reverse the page index for RTL\n return numberOfPages - 1 - pageIndex\n }\n\n return pageIndex\n}\n","import type { Context } from \"../../context/Context\"\nimport type { Viewport } from \"../../viewport/Viewport\"\nimport { getItemOffsetFromPageIndex } from \"../helpers\"\nimport { SpineItemPosition } from \"../types\"\n\nexport const getSpineItemPositionFromPageIndex = ({\n pageIndex,\n itemLayout,\n context,\n isUsingVerticalWriting,\n viewport,\n}: {\n pageIndex: number\n itemLayout: { width: number; height: number }\n context: Context\n isUsingVerticalWriting: boolean\n viewport: Viewport\n}): SpineItemPosition => {\n if (isUsingVerticalWriting) {\n const ltrRelativeOffset = getItemOffsetFromPageIndex(\n viewport.pageSize.height,\n pageIndex,\n itemLayout.height,\n )\n\n return new SpineItemPosition({\n x: 0,\n y: ltrRelativeOffset,\n })\n }\n\n const ltrRelativeOffset = getItemOffsetFromPageIndex(\n viewport.pageSize.width,\n pageIndex,\n itemLayout.width,\n )\n\n if (context.isRTL()) {\n return new SpineItemPosition({\n x: itemLayout.width - ltrRelativeOffset - viewport.pageSize.width,\n y: 0,\n })\n }\n\n return new SpineItemPosition({\n x: ltrRelativeOffset,\n y: 0,\n })\n}\n","import type { Context } from \"../context/Context\"\nimport type { ReaderSettingsManager } from \"../settings/ReaderSettingsManager\"\nimport { getRangeFromNode } from \"../utils/dom\"\nimport type { Viewport } from \"../viewport/Viewport\"\nimport {\n getClosestValidOffsetFromApproximateOffsetInPages,\n getItemOffsetFromPageIndex,\n} from \"./helpers\"\nimport { getSpineItemPageIndexFromSpineItemPosition } from \"./layout/getSpineItemPageIndexFromSpineItemPosition\"\nimport { getSpineItemPositionFromPageIndex } from \"./layout/getSpineItemPositionFromPageIndex\"\nimport type { SpineItem } from \"./SpineItem\"\nimport { SpineItemPosition, UnboundSpineItemPagePosition } from \"./types\"\n\nexport type SpineItemLocator = ReturnType<typeof createSpineItemLocator>\n\nexport const createSpineItemLocator = ({\n context,\n settings,\n viewport,\n}: {\n context: Context\n settings: ReaderSettingsManager\n viewport: Viewport\n}) => {\n const getSpineItemPositionFromNode = (\n node: Node,\n offset: number,\n spineItem: SpineItem,\n ) => {\n let offsetOfNodeInSpineItem: number | undefined\n\n // for some reason `img` does not work with range (x always = 0)\n if (\n node?.nodeName === `img` ||\n (node?.textContent === `` && node.nodeType === Node.ELEMENT_NODE)\n ) {\n offsetOfNodeInSpineItem = (node as HTMLElement).getBoundingClientRect().x\n } else if (node) {\n const range = node ? getRangeFromNode(node, offset) : undefined\n offsetOfNodeInSpineItem =\n range?.getBoundingClientRect().x || offsetOfNodeInSpineItem\n }\n\n const spineItemWidth = spineItem.layoutInfo?.width || 0\n const pageWidth = viewport.pageSize.width\n\n if (offsetOfNodeInSpineItem !== undefined) {\n const val = getClosestValidOffsetFromApproximateOffsetInPages(\n offsetOfNodeInSpineItem,\n pageWidth,\n spineItemWidth,\n )\n\n // @todo vertical\n return new SpineItemPosition({ x: val, y: 0 })\n }\n\n return undefined\n }\n\n const getSpineItemClosestPositionFromUnsafePosition = (\n unsafePosition: SpineItemPosition,\n spineItem: SpineItem,\n ) => {\n const { width, height } = spineItem.layoutInfo\n\n const adjustedPosition = new SpineItemPosition({\n x: getClosestValidOffsetFromApproximateOffsetInPages(\n unsafePosition.x,\n viewport.pageSize.width,\n width,\n ),\n y: getClosestValidOffsetFromApproximateOffsetInPages(\n unsafePosition.y,\n viewport.pageSize.height,\n height,\n ),\n })\n\n return adjustedPosition\n }\n\n const getSpineItemPageIndexFromNode = (\n node: Node,\n offset: number,\n spineItem: SpineItem,\n ) => {\n const position = getSpineItemPositionFromNode(node, offset, spineItem)\n const { height, width } = spineItem.layoutInfo\n\n return position\n ? getSpineItemPageIndexFromSpineItemPosition({\n isUsingVerticalWriting: !!spineItem.isUsingVerticalWriting(),\n position,\n itemHeight: height,\n itemWidth: width,\n isRTL: context.isRTL(),\n pageWidth: viewport.pageSize.width,\n pageHeight: viewport.pageSize.height,\n pageTurnDirection: settings.values.computedPageTurnDirection,\n pageTurnMode: settings.values.pageTurnMode,\n })\n : undefined\n }\n\n const getSpineItemPagePositionFromSpineItemPosition = (\n position: SpineItemPosition,\n pageIndex: number,\n spineItem: SpineItem,\n ) => {\n const { width, height } = spineItem.layoutInfo\n const pageWidth = viewport.pageSize.width\n const pageHeight = viewport.pageSize.height\n const isUsingVerticalWriting = !!spineItem.isUsingVerticalWriting()\n\n if (isUsingVerticalWriting) {\n // For vertical writing, pages stack vertically\n const pageStartY = getItemOffsetFromPageIndex(\n pageHeight,\n pageIndex,\n height,\n )\n return new UnboundSpineItemPagePosition({\n x: position.x,\n y: position.y - pageStartY,\n })\n }\n\n // For horizontal writing\n const pageStartX = getItemOffsetFromPageIndex(pageWidth, pageIndex, width)\n\n if (context.isRTL()) {\n // For RTL, pages are positioned from right to left\n const rtlPageStartX = width - (pageIndex + 1) * pageWidth\n return new UnboundSpineItemPagePosition({\n x: position.x - Math.max(0, rtlPageStartX),\n y: position.y,\n })\n }\n\n // For LTR, simply subtract the page start position from the absolute position\n return new UnboundSpineItemPagePosition({\n x: position.x - pageStartX,\n y: position.y,\n })\n }\n\n return {\n getSpineItemPositionFromNode,\n getSpineItemPositionFromPageIndex: ({\n pageIndex,\n spineItem,\n }: {\n pageIndex: number\n spineItem: SpineItem\n }) =>\n getSpineItemPositionFromPageIndex({\n context,\n isUsingVerticalWriting: !!spineItem.isUsingVerticalWriting(),\n itemLayout: spineItem.layoutInfo,\n pageIndex,\n viewport,\n }),\n getSpineItemPageIndexFromPosition: (params: {\n position: SpineItemPosition\n isUsingVerticalWriting: boolean\n itemWidth: number\n itemHeight: number\n }) =>\n getSpineItemPageIndexFromSpineItemPosition({\n ...params,\n isRTL: context.isRTL(),\n pageWidth: viewport.pageSize.width,\n pageHeight: viewport.pageSize.height,\n pageTurnDirection: settings.values.computedPageTurnDirection,\n pageTurnMode: settings.values.pageTurnMode,\n }),\n getSpineItemPageIndexFromNode,\n getSpineItemClosestPositionFromUnsafePosition,\n getSpineItemPagePositionFromSpineItemPosition,\n }\n}\n","import type { Context } from \"../context/Context\"\nimport type { ReaderSettingsManager } from \"../settings/ReaderSettingsManager\"\nimport type { Viewport } from \"../viewport/Viewport\"\nimport { createSpineItemLocator } from \"./locationResolver\"\nimport type { SpineItem } from \"./SpineItem\"\nimport { SpineItemPosition } from \"./types\"\n\nexport type SpineItemNavigationResolver = ReturnType<\n typeof createNavigationResolver\n>\n\nexport const createNavigationResolver = ({\n context,\n settings,\n viewport,\n}: {\n context: Context\n settings: ReaderSettingsManager\n viewport: Viewport\n}) => {\n const spineItemLocator = createSpineItemLocator({\n context,\n settings,\n viewport,\n })\n\n const getNavigationForLastPage = (spineItem: SpineItem) => {\n const numberOfPages = spineItem.numberOfPages\n\n return spineItemLocator.getSpineItemPositionFromPageIndex({\n pageIndex: numberOfPages - 1,\n spineItem,\n })\n }\n\n const getNavigationFromNode = (\n spineItem: SpineItem,\n node: Node,\n offset: number,\n ): SpineItemPosition => {\n const position = spineItemLocator.getSpineItemPositionFromNode(\n node,\n offset,\n spineItem,\n )\n\n return position || new SpineItemPosition({ x: 0, y: 0 })\n }\n\n const getNavigationForPosition = (\n spineItem: SpineItem,\n position: SpineItemPosition,\n ): SpineItemPosition => {\n const potentiallyCorrectedPosition =\n spineItemLocator.getSpineItemClosestPositionFromUnsafePosition(\n position,\n spineItem,\n )\n\n return potentiallyCorrectedPosition\n }\n\n return {\n getNavigationForLastPage,\n getNavigationForPosition,\n getNavigationFromNode,\n }\n}\n","import type { Spine } from \"../../spine/Spine\"\nimport type { SpineItemsManager } from \"../../spine/SpineItemsManager\"\nimport { SpinePosition, type UnboundSpinePosition } from \"../../spine/types\"\n\nexport const NAMESPACE = `spineNavigator`\n\ntype SharedParams = {\n isRTL: boolean\n spineItemsManager: SpineItemsManager\n spine: Spine\n viewportWidth: number\n}\n\nexport function fromOutOfBoundsSpinePosition(\n params: SharedParams & {\n position: SpinePosition\n },\n): SpinePosition\n\nexport function fromOutOfBoundsSpinePosition(\n params: SharedParams & {\n position: UnboundSpinePosition\n },\n): UnboundSpinePosition\n\nexport function fromOutOfBoundsSpinePosition(\n params: SharedParams & {\n position: UnboundSpinePosition | SpinePosition\n },\n): UnboundSpinePosition | SpinePosition\n\n/**\n * Only make sure x/y are not out of the bounds of the spine.\n */\nexport function fromOutOfBoundsSpinePosition({\n position,\n isRTL,\n spineItemsManager,\n spine,\n viewportWidth,\n}: SharedParams & {\n position: SpinePosition | UnboundSpinePosition\n}): SpinePosition | UnboundSpinePosition {\n // @todo use container width instead to increase performances\n const lastSpineItem = spineItemsManager.get(\n spineItemsManager.items.length - 1,\n )\n const distanceOfLastSpineItem = spine.getSpineItemSpineLayoutInfo(\n lastSpineItem || 0,\n )\n\n // fallback on last element (before last pixel)\n const maximumYOffset = distanceOfLastSpineItem.bottom - 1\n const positiveY = Math.max(0, position.y)\n const y = Math.min(positiveY, maximumYOffset)\n\n /**\n * For RTL books we move from right to left so negative x.\n * [-x, 0]\n */\n if (isRTL) {\n const maximumX = Math.min(viewportWidth, position.x)\n const minimumX = Math.max(maximumX, distanceOfLastSpineItem.left)\n\n return new SpinePosition({\n x: minimumX,\n y,\n })\n }\n\n // fallback on last element (before last pixel)\n const maximumXOffset = distanceOfLastSpineItem.right - 1\n const positiveX = Math.max(0, position.x)\n const boundedX = Math.min(positiveX, maximumXOffset)\n\n return new SpinePosition({\n x: boundedX,\n y,\n })\n}\n","import type { Spine } from \"../../spine/Spine\"\nimport type { SpineItemsManager } from \"../../spine/SpineItemsManager\"\nimport { SpinePosition, type UnboundSpinePosition } from \"../../spine/types\"\nimport { fromOutOfBoundsSpinePosition } from \"./fromOutOfBoundsSpinePosition\"\n\nexport const NAMESPACE = `spineNavigator`\n\nexport const fromUnboundSpinePosition = ({\n position,\n isRTL,\n pageSizeHeight,\n spineItemsManager,\n visibleAreaRectWidth,\n spine,\n}: {\n position: SpinePosition | UnboundSpinePosition\n isRTL: boolean\n pageSizeHeight: number\n spineItemsManager: SpineItemsManager\n visibleAreaRectWidth: number\n spine: Spine\n}) => {\n const unboundPosition = fromOutOfBoundsSpinePosition({\n position,\n isRTL,\n spineItemsManager,\n spine,\n viewportWidth: visibleAreaRectWidth,\n })\n\n // @todo use container width instead to increase performances\n const lastSpineItem = spineItemsManager.get(\n spineItemsManager.items.length - 1,\n )\n const distanceOfLastSpineItem =\n spine.getSpineItemSpineLayoutInfo(lastSpineItem)\n\n const maximumYOffset = distanceOfLastSpineItem.bottom - pageSizeHeight\n const y = Math.min(unboundPosition.y, maximumYOffset)\n\n /**\n * For RTL books we move from right to left so negative x.\n * [-x, 0]\n */\n if (isRTL) {\n const maximumX = Math.min(0, unboundPosition.x)\n\n return new SpinePosition({\n x: maximumX,\n y,\n })\n }\n\n const maximumXOffset = distanceOfLastSpineItem.right - visibleAreaRectWidth\n\n return new SpinePosition({\n x: Math.min(unboundPosition.x, maximumXOffset),\n y,\n })\n}\n","import { SpinePosition, type UnboundSpinePosition } from \"../../spine/types\"\n\nexport const getAdjustedPositionForSpread = ({\n position: { x, y },\n pageSizeWidth,\n visibleAreaRectWidth,\n}: {\n position: SpinePosition | UnboundSpinePosition\n pageSizeWidth: number\n visibleAreaRectWidth: number\n}): SpinePosition => {\n const isOffsetNotAtEdge = x % visibleAreaRectWidth !== 0\n const correctedX = isOffsetNotAtEdge ? x - pageSizeWidth : x\n\n return new SpinePosition({ x: correctedX, y })\n}\n","import type { SpineLocator } from \"../../spine/locator/SpineLocator\"\nimport { SpinePosition, type UnboundSpinePosition } from \"../../spine/types\"\nimport type { SpineItemNavigationResolver } from \"../../spineItem/navigationResolver\"\nimport type { Viewport } from \"../../viewport/Viewport\"\nimport { getAdjustedPositionForSpread } from \"./getAdjustedPositionForSpread\"\n\nexport const getNavigationForPosition = ({\n viewportPosition,\n spineLocator,\n spineItemNavigationResolver,\n viewport,\n}: {\n viewportPosition: SpinePosition | UnboundSpinePosition\n spineLocator: SpineLocator\n spineItemNavigationResolver: SpineItemNavigationResolver\n viewport: Viewport\n}) => {\n const spineItem = spineLocator.getSpineItemFromPosition(viewportPosition)\n\n if (spineItem) {\n const spineItemPosition =\n spineLocator.getSpineItemPositionFromSpinePosition(\n viewportPosition,\n spineItem,\n )\n\n const spineItemValidPosition =\n spineItemNavigationResolver.getNavigationForPosition(\n spineItem,\n spineItemPosition,\n )\n\n const viewportNavigation =\n spineLocator.getSpinePositionFromSpineItemPosition({\n spineItemPosition: spineItemValidPosition,\n spineItem,\n })\n\n return getAdjustedPositionForSpread({\n position: viewportNavigation,\n pageSizeWidth: viewport.pageSize.width,\n visibleAreaRectWidth: viewport.absoluteViewport.width,\n })\n }\n\n return new SpinePosition({ x: 0, y: 0 })\n}\n","import type { SpineLocator } from \"../../spine/locator/SpineLocator\"\nimport type { SpineItemsManager } from \"../../spine/SpineItemsManager\"\nimport { SpinePosition } from \"../../spine/types\"\nimport type { SpineItemNavigationResolver } from \"../../spineItem/navigationResolver\"\nimport type { SpineItem } from \"../../spineItem/SpineItem\"\nimport type { Viewport } from \"../../viewport/Viewport\"\nimport { getAdjustedPositionForSpread } from \"./getAdjustedPositionForSpread\"\nimport { getNavigationForPosition } from \"./getNavigationForPosition\"\n\nexport const getNavigationForSpineItemPage = ({\n pageIndex,\n spineItemsManager,\n spineItemId,\n spineLocator,\n spineItemNavigationResolver,\n viewport,\n}: {\n pageIndex: number\n spineItemId: SpineItem | number | string\n spineItemsManager: SpineItemsManager\n spineItemNavigationResolver: SpineItemNavigationResolver\n spineLocator: SpineLocator\n viewport: Viewport\n}): SpinePosition => {\n const spineItem = spineItemsManager.get(spineItemId)\n\n // lookup for entire book\n // This is reliable for pre-paginated, do not use it for reflowable book\n if (!spineItem) {\n const xPositionForPageIndex = pageIndex * viewport.pageSize.width\n return getNavigationForPosition({\n viewportPosition: new SpinePosition({ x: xPositionForPageIndex, y: 0 }),\n spineItemNavigationResolver,\n spineLocator,\n viewport,\n })\n }\n\n const spineItemNavigation =\n spineLocator.spineItemLocator.getSpineItemPositionFromPageIndex({\n pageIndex,\n spineItem,\n })\n\n const readingOffset = spineLocator.getSpinePositionFromSpineItemPosition({\n spineItemPosition: spineItemNavigation,\n spineItem,\n })\n\n return getAdjustedPositionForSpread({\n position: readingOffset,\n pageSizeWidth: viewport.pageSize.width,\n visibleAreaRectWidth: viewport.absoluteViewport.width,\n })\n}\n","import type { Context } from \"../../context/Context\"\nimport type { SpineLocator } from \"../../spine/locator/SpineLocator\"\nimport type { Spine } from \"../../spine/Spine\"\nimport type { SpineItemsManager } from \"../../spine/SpineItemsManager\"\nimport type { SpinePosition } from \"../../spine/types\"\nimport type { SpineItem } from \"../../spineItem/SpineItem\"\nimport { SpineItemPosition } from \"../../spineItem/types\"\nimport { getAdjustedPositionForSpread } from \"./getAdjustedPositionForSpread\"\n\nconst getNodeFromSelector = (\n selector: string,\n frameElement?: HTMLIFrameElement,\n) => {\n if (frameElement && frameElement instanceof HTMLIFrameElement) {\n if (selector.startsWith(`#`)) {\n return frameElement.contentDocument?.getElementById(\n selector.replace(`#`, ``),\n )\n }\n\n return frameElement.contentDocument?.querySelector(selector)\n }\n}\n\n/**\n * @todo vertical, should returns spine position or something anyway\n */\nconst getSpineItemOffsetFromAnchor = ({\n anchor,\n spineItem,\n spine,\n}: {\n anchor: string\n spineItem: SpineItem\n spine: Spine\n}) => {\n const node = getNodeFromSelector(\n anchor,\n spineItem.renderer.getDocumentFrame(),\n )\n\n if (!node) {\n return 0\n }\n\n return (\n spine.spineItemLocator.getSpineItemPositionFromNode(node, 0, spineItem)\n ?.x ?? 0\n )\n}\n\nconst getSpinePositionFromSpineItemAnchor = ({\n anchor,\n spineItem,\n spineLocator,\n spine,\n}: {\n anchor: string\n spineItem: SpineItem\n spineLocator: SpineLocator\n spine: Spine\n}) => {\n const spineItemOffset = getSpineItemOffsetFromAnchor({\n anchor,\n spineItem,\n spine,\n })\n\n const position = spineLocator.getSpinePositionFromSpineItemPosition({\n spineItemPosition: new SpineItemPosition({ x: spineItemOffset, y: 0 }),\n spineItem,\n })\n\n return position\n}\n\nconst getNavigationForAnchor = ({\n anchor,\n spineItem,\n spineLocator,\n spine,\n pageSizeWidth,\n visibleAreaRectWidth,\n}: {\n anchor: string\n spineItem: SpineItem\n spineLocator: SpineLocator\n spine: Spine\n pageSizeWidth: number\n visibleAreaRectWidth: number\n}) => {\n const position = getSpinePositionFromSpineItemAnchor({\n anchor,\n spineItem,\n spineLocator,\n spine,\n })\n\n return getAdjustedPositionForSpread({\n position,\n pageSizeWidth,\n visibleAreaRectWidth,\n })\n}\n\n/**\n * @todo should be part of enhancer, all the core needs to know to restore navigation\n * is a spine item id AND a node ID.\n */\nexport const getNavigationForUrl = ({\n spine,\n spineItemsManager,\n spineLocator,\n url,\n context,\n pageSizeWidth,\n visibleAreaRectWidth,\n}: {\n url: string | URL\n spineItemsManager: SpineItemsManager\n spineLocator: SpineLocator\n context: Context\n spine: Spine\n pageSizeWidth: number\n visibleAreaRectWidth: number\n}): { position: SpinePosition; spineItemId: string } | undefined => {\n try {\n const validUrl = url instanceof URL ? url : new URL(url)\n const urlWithoutAnchor = `${validUrl.origin}${validUrl.pathname}`\n const existingSpineItem = context.manifest?.spineItems.find(\n (item) => item.href === urlWithoutAnchor,\n )\n\n if (existingSpineItem) {\n const spineItem = spineItemsManager.get(existingSpineItem.id)\n\n if (spineItem) {\n const position = getNavigationForAnchor({\n anchor: validUrl.hash,\n spineItem,\n spine,\n spineLocator,\n pageSizeWidth,\n visibleAreaRectWidth,\n })\n\n return {\n position: getAdjustedPositionForSpread({\n position,\n pageSizeWidth,\n visibleAreaRectWidth,\n }),\n spineItemId: existingSpineItem.id,\n }\n }\n }\n\n return undefined\n } catch (e) {\n console.error(e)\n\n return undefined\n }\n}\n","import type { SpineLocator } from \"../../spine/locator/SpineLocator\"\nimport type { SpineItemLocator } from \"../../spineItem/locationResolver\"\nimport type { SpineItem } from \"../../spineItem/SpineItem\"\nimport type { SpineItemPosition } from \"../../spineItem/types\"\nimport type { Viewport } from \"../../viewport/Viewport\"\nimport { getAdjustedPositionForSpread } from \"./getAdjustedPositionForSpread\"\n\nexport const getNavigationFromSpineItemPosition = ({\n spineItem,\n spineItemPosition,\n spineLocator,\n spineItemLocator,\n viewport,\n}: {\n spineItemPosition: SpineItemPosition\n spineItem: SpineItem\n spineLocator: SpineLocator\n spineItemLocator: SpineItemLocator\n viewport: Viewport\n}) => {\n const navigationInSpineItem =\n spineItemLocator.getSpineItemClosestPositionFromUnsafePosition(\n spineItemPosition,\n spineItem,\n )\n\n const spinePosition = spineLocator.getSpinePositionFromSpineItemPosition({\n spineItemPosition: navigationInSpineItem,\n spineItem,\n })\n\n return getAdjustedPositionForSpread({\n position: spinePosition,\n pageSizeWidth: viewport.pageSize.width,\n visibleAreaRectWidth: viewport.absoluteViewport.width,\n })\n}\n","import { resolveCfi } from \"../../cfi\"\nimport type { Context } from \"../../context/Context\"\nimport { Report } from \"../../report\"\nimport type { ReaderSettingsManager } from \"../../settings/ReaderSettingsManager\"\nimport type { SpineLocator } from \"../../spine/locator/SpineLocator\"\nimport type { Spine } from \"../../spine/Spine\"\nimport type { SpineItemsManager } from \"../../spine/SpineItemsManager\"\nimport { SpinePosition, type UnboundSpinePosition } from \"../../spine/types\"\nimport { createNavigationResolver as createSpineItemNavigator } from \"../../spineItem/navigationResolver\"\nimport type { SpineItem } from \"../../spineItem/SpineItem\"\nimport { SpineItemPosition } from \"../../spineItem/types\"\nimport type { Viewport } from \"../../viewport/Viewport\"\nimport { fromOutOfBoundsSpinePosition } from \"./fromOutOfBoundsSpinePosition\"\nimport { fromUnboundSpinePosition } from \"./fromUnboundSpinePosition\"\nimport { getAdjustedPositionForSpread } from \"./getAdjustedPositionForSpread\"\nimport { getNavigationForPosition } from \"./getNavigationForPosition\"\nimport { getNavigationForSpineItemPage } from \"./getNavigationForSpineItemPage\"\nimport { getNavigationForUrl } from \"./getNavigationForUrl\"\nimport { getNavigationFromSpineItemPosition } from \"./getNavigationFromSpineItemPosition\"\n\nexport const NAMESPACE = `spineNavigator`\n\nexport type NavigationResolver = ReturnType<typeof createNavigationResolver>\n\nexport const createNavigationResolver = ({\n context,\n spineItemsManager,\n locator,\n settings,\n spine,\n viewport,\n}: {\n context: Context\n spineItemsManager: SpineItemsManager\n locator: SpineLocator\n settings: ReaderSettingsManager\n spine: Spine\n viewport: Viewport\n}) => {\n const spineItemNavigator = createSpineItemNavigator({\n context,\n settings,\n viewport,\n })\n\n const arePositionsDifferent = (\n a: { x: number; y: number },\n b: { x: number; y: number },\n ) => a.x !== b.x || a.y !== b.y\n\n const getNavigationForCfi = (cfi: string): SpinePosition | undefined => {\n const spineItem = spineItemsManager.getSpineItemFromCfi(cfi)\n const { node, offset = 0 } = resolveCfi({\n cfi,\n spineItemsManager,\n })\n\n if (!spineItem) {\n Report.warn(NAMESPACE, `unable to detect item id from cfi ${cfi}`)\n\n return undefined\n }\n\n const spineItemNavigation = node\n ? spineItemNavigator.getNavigationFromNode(spineItem, node, offset)\n : new SpineItemPosition({ x: 0, y: 0 })\n const readingPosition = locator.getSpinePositionFromSpineItemPosition({\n spineItemPosition: spineItemNavigation,\n spineItem,\n })\n\n return getAdjustedPositionForSpread({\n position: readingPosition,\n pageSizeWidth: viewport.pageSize.width,\n visibleAreaRectWidth: viewport.absoluteViewport.width,\n })\n }\n\n const getNavigationForLastPage = (spineItem: SpineItem): SpinePosition => {\n const spineItemNavigation =\n spineItemNavigator.getNavigationForLastPage(spineItem)\n const position = locator.getSpinePositionFromSpineItemPosition({\n spineItemPosition: spineItemNavigation,\n spineItem,\n })\n\n return getAdjustedPositionForSpread({\n position,\n pageSizeWidth: viewport.pageSize.width,\n visibleAreaRectWidth: viewport.absoluteViewport.width,\n })\n }\n\n const getNavigationForSpineIndexOrId = (\n indexOrId: number | string | SpineItem,\n ): SpinePosition => {\n const spineItem = spineItemsManager.get(indexOrId)\n\n if (spineItem) {\n const position = locator.getSpinePositionFromSpineItem(spineItem)\n\n return getAdjustedPositionForSpread({\n position,\n pageSizeWidth: viewport.pageSize.width,\n visibleAreaRectWidth: viewport.absoluteViewport.width,\n })\n }\n\n return new SpinePosition({ x: 0, y: 0 })\n }\n\n /**\n * Useful when you want to get a navigation from a scroll position. It uses trigger points so it will\n * try to get the most visible / relevant element as navigation reference\n */\n const getMostPredominantNavigationForPosition = (\n viewportPosition: SpinePosition,\n ): SpinePosition => {\n const pageTurnDirection = settings.values.computedPageTurnDirection\n // @todo movingForward does not work same with free-scroll, try to find a reliable way to detect\n // const movingForward = navigator.isNavigationGoingForwardFrom(navigation, currentNavigationPosition)\n // const triggerPercentage = movingForward ? 0.7 : 0.3\n const triggerPercentage = 0.5\n const triggerXPosition =\n pageTurnDirection === `horizontal`\n ? viewportPosition.x +\n viewport.absoluteViewport.width * triggerPercentage\n : 0\n const triggerYPosition =\n pageTurnDirection === `horizontal`\n ? 0\n : viewportPosition.y +\n viewport.absoluteViewport.height * triggerPercentage\n const midScreenPositionSafePosition = fromUnboundSpinePosition({\n position: new SpinePosition({\n x: triggerXPosition,\n y: triggerYPosition,\n }),\n isRTL: context.isRTL(),\n pageSizeHeight: viewport.pageSize.height,\n visibleAreaRectWidth: viewport.absoluteViewport.width,\n spineItemsManager,\n spine,\n })\n\n return getNavigationForPosition({\n spineItemNavigationResolver: spineItemNavigator,\n spineLocator: locator,\n viewportPosition: midScreenPositionSafePosition,\n viewport,\n })\n }\n\n const isNavigationGoingForwardFrom = (\n to: SpinePosition,\n from: SpinePosition,\n ) => {\n const pageTurnDirection = settings.values.computedPageTurnDirection\n\n if (pageTurnDirection === `vertical`) {\n return to.y > from.y\n }\n\n return to.x > from.x\n }\n\n return {\n getNavigationForUrl: (url: string | URL) =>\n getNavigationForUrl({\n context,\n spineItemsManager,\n spineLocator: locator,\n url,\n pageSizeWidth: viewport.pageSize.width,\n visibleAreaRectWidth: viewport.absoluteViewport.width,\n spine,\n }),\n getNavigationForSpineItemPage: (\n params: Omit<\n Parameters<typeof getNavigationForSpineItemPage>[0],\n | \"spineItemsManager\"\n | \"spineItemNavigationResolver\"\n | \"spineLocator\"\n | \"viewport\"\n >,\n ) =>\n getNavigationForSpineItemPage({\n ...params,\n spineItemsManager,\n spineItemNavigationResolver: spineItemNavigator,\n spineLocator: locator,\n viewport,\n }),\n getNavigationFromSpineItemPosition: (params: {\n spineItemPosition: SpineItemPosition\n spineItem: SpineItem\n }) =>\n getNavigationFromSpineItemPosition({\n ...params,\n spineItemLocator: locator.spineItemLocator,\n spineLocator: locator,\n viewport,\n }),\n getNavigationForCfi,\n getNavigationForLastPage,\n getNavigationForSpineIndexOrId,\n getNavigationForPosition: (\n viewportPosition: SpinePosition | UnboundSpinePosition,\n ) =>\n getNavigationForPosition({\n viewportPosition,\n spineItemNavigationResolver: spineItemNavigator,\n spineLocator: locator,\n viewport,\n }),\n getMostPredominantNavigationForPosition,\n fromUnboundSpinePosition: (\n position: SpinePosition | UnboundSpinePosition,\n ) =>\n fromUnboundSpinePosition({\n position,\n isRTL: context.isRTL(),\n pageSizeHeight: viewport.pageSize.height,\n visibleAreaRectWidth: viewport.absoluteViewport.width,\n spineItemsManager,\n spine,\n }),\n fromOutOfBoundsSpinePosition: (\n position: SpinePosition | UnboundSpinePosition,\n ) =>\n fromOutOfBoundsSpinePosition({\n position,\n isRTL: context.isRTL(),\n spineItemsManager,\n spine,\n viewportWidth: viewport.absoluteViewport.width,\n }),\n isNavigationGoingForwardFrom,\n arePositionsDifferent,\n getAdjustedPositionForSpread: (\n position: SpinePosition | UnboundSpinePosition,\n ) =>\n getAdjustedPositionForSpread({\n position,\n pageSizeWidth: viewport.pageSize.width,\n visibleAreaRectWidth: viewport.absoluteViewport.width,\n }),\n spineItemNavigator,\n }\n}\n","import { combineLatest, Subject } from \"rxjs\"\nimport { distinctUntilChanged, map, shareReplay } from \"rxjs/operators\"\nimport type { Context } from \"../context/Context\"\nimport type { HookManager } from \"../hooks/HookManager\"\nimport type { ReaderSettingsManager } from \"../settings/ReaderSettingsManager\"\nimport type { Spine } from \"../spine/Spine\"\nimport type { SpineItemsManager } from \"../spine/SpineItemsManager\"\nimport type { Viewport } from \"../viewport/Viewport\"\nimport { ControlledNavigationController } from \"./controllers/ControlledNavigationController\"\nimport { ScrollNavigationController } from \"./controllers/ScrollNavigationController\"\nimport { InternalNavigator } from \"./InternalNavigator\"\nimport { Locker } from \"./Locker\"\nimport { createNavigationResolver } from \"./resolvers/NavigationResolver\"\nimport type { UserNavigationEntry } from \"./types\"\n\nexport const createNavigator = ({\n spineItemsManager,\n context,\n hookManager,\n spine,\n settings,\n viewport,\n}: {\n spineItemsManager: SpineItemsManager\n context: Context\n hookManager: HookManager\n spine: Spine\n settings: ReaderSettingsManager\n viewport: Viewport\n}) => {\n const userExplicitNavigationSubject = new Subject<UserNavigationEntry>()\n const userNavigation$ = userExplicitNavigationSubject.asObservable()\n /**\n * Allow automatic restoration to happens.\n * - correction of position\n * - restoration of position\n */\n const restorationLocker = new Locker()\n const navigationResolver = createNavigationResolver({\n context,\n settings,\n spineItemsManager,\n locator: spine.locator,\n spine,\n viewport,\n })\n\n const controlledNavigationController = new ControlledNavigationController(\n settings,\n hookManager,\n context,\n spine,\n viewport,\n )\n\n const scrollNavigationController = new ScrollNavigationController(\n viewport,\n settings,\n hookManager,\n spine,\n context,\n )\n\n const internalNavigator = new InternalNavigator(\n settings,\n context,\n userNavigation$,\n controlledNavigationController,\n scrollNavigationController,\n navigationResolver,\n spine,\n restorationLocker.isLocked$,\n )\n\n const navigationState$ = combineLatest([\n controlledNavigationController.isNavigating$,\n scrollNavigationController.isNavigating$,\n restorationLocker.isLocked$,\n internalNavigator.locker.isLocked$,\n ]).pipe(\n map((states) => (states.some((isLocked) => isLocked) ? `busy` : `free`)),\n distinctUntilChanged(),\n shareReplay(1),\n )\n\n const navigate = (to: UserNavigationEntry) => {\n userExplicitNavigationSubject.next(to)\n }\n\n const destroy = () => {\n controlledNavigationController.destroy()\n internalNavigator.destroy()\n }\n\n return {\n destroy,\n getNavigation: () => internalNavigator.navigation,\n internalNavigator,\n scrollNavigationController,\n controlledNavigationController,\n locker: restorationLocker,\n navigationState$,\n navigate,\n /**\n * Prevent further navigation until the lock is released.\n * Useful if you want to start navigation by panning for example.\n */\n lock() {\n return restorationLocker.lock()\n },\n navigationResolver: navigationResolver,\n navigation$: internalNavigator.navigation$,\n }\n}\n\nexport type Navigator = ReturnType<typeof createNavigator>\n","import type { Context } from \"../context/Context\"\nimport type { SpineItemsManager } from \"../spine/SpineItemsManager\"\nimport { ReactiveEntity } from \"../utils/ReactiveEntity\"\nimport type { PaginationInfo } from \"./types\"\n\nexport class Pagination extends ReactiveEntity<PaginationInfo> {\n constructor(\n protected context: Context,\n protected spineItemsManager: SpineItemsManager,\n ) {\n super({\n beginPageIndexInSpineItem: undefined,\n beginNumberOfPagesInSpineItem: 0,\n beginCfi: undefined,\n beginSpineItemIndex: undefined,\n endPageIndexInSpineItem: undefined,\n endNumberOfPagesInSpineItem: 0,\n endCfi: undefined,\n endSpineItemIndex: undefined,\n navigationId: undefined,\n })\n }\n\n public update(pagination: Partial<PaginationInfo>) {\n this.mergeCompare(pagination)\n }\n}\n","import { merge, switchMap, take, takeUntil, tap, withLatestFrom } from \"rxjs\"\nimport { generateCfiForSpineItemPage, generateRootCfi, isRootCfi } from \"../cfi\"\nimport type { Context } from \"../context/Context\"\nimport type { Spine } from \"../spine/Spine\"\nimport type { SpineItemsManager } from \"../spine/SpineItemsManager\"\nimport type { SpinePosition, UnboundSpinePosition } from \"../spine/types\"\nimport type { createSpineItemLocator } from \"../spineItem/locationResolver\"\nimport type { SpineItem } from \"../spineItem/SpineItem\"\nimport { DestroyableClass } from \"../utils/DestroyableClass\"\nimport { waitForSwitch } from \"../utils/rxjs\"\nimport type { Pagination } from \"./Pagination\"\n\nexport class PaginationController extends DestroyableClass {\n constructor(\n protected context: Context,\n protected pagination: Pagination,\n protected spineItemsManager: SpineItemsManager,\n protected spine: Spine,\n protected spineItemLocator: ReturnType<typeof createSpineItemLocator>,\n ) {\n super()\n\n /**\n * Adjust heavier pagination once the navigation and items are updated.\n * This is also cancelled if the layout changes, because the layout will\n * trigger a new navigation adjustment and pagination again.\n *\n * This adjustment is used to update the pagination with the most up to date values we can.\n * It needs to be ran only when viewport is free because some operation such as looking up cfi can\n * be really heavy.\n *\n * The cfi will only be updated if it needs to be:\n * - cfi is a root target\n * - cfi is undefined\n * - items are different\n */\n const updatePagination$ = merge(\n this.context.bridgeEvent.navigation$,\n spine.layout$,\n ).pipe(\n switchMap(() => {\n const getVisiblePagesFromViewportPosition = ({\n spineItem,\n position,\n }: {\n spineItem: SpineItem\n position: SpinePosition | UnboundSpinePosition\n }) =>\n this.spine.locator.getVisiblePagesFromViewportPosition({\n spineItem: spineItem,\n position,\n threshold: { type: \"percentage\", value: 0.5 },\n })\n\n /**\n * @important\n *\n * It's important to soft update pagination immediatly.\n * This will avoid delay in potential user feedbacks (navigation buttons).\n *\n * However we wait for the navigator to be unlocked, this avoid updating the pagination\n * while the user is panning for exemple. We consider a locked navigator as unfinished\n * navigation.\n *\n * Nothing here should be heavier than layout lookup.\n */\n return this.context.bridgeEvent.navigationUnlocked$.pipe(\n take(1),\n withLatestFrom(this.context.bridgeEvent.navigation$),\n tap(([, navigation]) => {\n const { position } = navigation\n const previousPagination = this.pagination.value\n\n const {\n beginIndex: beginSpineItemIndex,\n endIndex: endSpineItemIndex,\n } =\n this.spine.locator.getVisibleSpineItemsFromPosition({\n position,\n threshold: { type: \"percentage\", value: 0.5 },\n }) ?? {}\n\n const beginSpineItem =\n this.spineItemsManager.get(beginSpineItemIndex)\n const endSpineItem = this.spineItemsManager.get(endSpineItemIndex)\n\n if (!beginSpineItem || !endSpineItem) return\n\n const beginLastCfi = previousPagination.beginCfi\n const endLastCfi = previousPagination.endCfi\n\n const { beginPageIndex = 0 } =\n getVisiblePagesFromViewportPosition({\n spineItem: beginSpineItem,\n position,\n }) ?? {}\n\n const { endPageIndex = 0 } =\n getVisiblePagesFromViewportPosition({\n spineItem: endSpineItem,\n position,\n }) ?? {}\n\n const shouldUpdateBeginCfi =\n beginLastCfi === undefined ||\n isRootCfi(beginLastCfi) ||\n previousPagination.beginSpineItemIndex !== beginSpineItemIndex\n\n const shouldUpdateEndCfi =\n previousPagination.endSpineItemIndex !== endSpineItemIndex ||\n endLastCfi === undefined ||\n isRootCfi(endLastCfi)\n\n const beginCfi = shouldUpdateBeginCfi\n ? generateRootCfi(beginSpineItem.item)\n : beginLastCfi\n\n const endCfi = shouldUpdateEndCfi\n ? generateRootCfi(endSpineItem.item)\n : endLastCfi\n\n const beginNumberOfPagesInSpineItem = beginSpineItem.numberOfPages\n\n const endNumberOfPagesInSpineItem = endSpineItem.numberOfPages\n\n this.pagination.update({\n beginCfi,\n beginNumberOfPagesInSpineItem,\n beginPageIndexInSpineItem: beginPageIndex,\n beginSpineItemIndex,\n endCfi,\n endNumberOfPagesInSpineItem,\n endPageIndexInSpineItem: endPageIndex,\n endSpineItemIndex,\n navigationId: navigation.id,\n })\n }),\n )\n }),\n )\n\n /**\n * Heavy operation, needs to be optimized as much as possible.\n *\n * @todo add more optimization, comparing item before, after with position, etc\n */\n const updateCfi$ = updatePagination$.pipe(\n waitForSwitch(this.context.bridgeEvent.viewportFree$),\n tap(() => {\n const {\n beginSpineItemIndex,\n endSpineItemIndex,\n beginPageIndexInSpineItem,\n endPageIndexInSpineItem,\n } = this.pagination.value\n\n if (\n beginPageIndexInSpineItem === undefined ||\n endPageIndexInSpineItem === undefined ||\n beginSpineItemIndex === undefined ||\n endSpineItemIndex === undefined\n )\n return\n\n const beginSpineItem = this.spineItemsManager.get(beginSpineItemIndex)\n const endSpineItem = this.spineItemsManager.get(endSpineItemIndex)\n\n if (beginSpineItem === undefined || endSpineItem === undefined) return\n\n const beginPageEntry = this.spine.pages.fromSpineItemPageIndex(\n beginSpineItem,\n beginPageIndexInSpineItem,\n )\n const endPageEntry = this.spine.pages.fromSpineItemPageIndex(\n endSpineItem,\n endPageIndexInSpineItem,\n )\n\n // @todo only update long cfi if the item layout change but specifically its content\n this.pagination.update({\n beginCfi: beginPageEntry?.firstVisibleNode\n ? generateCfiForSpineItemPage({\n spineItem: beginSpineItem.item,\n pageNode: beginPageEntry?.firstVisibleNode,\n })\n : generateRootCfi(beginSpineItem.item),\n endCfi: endPageEntry?.firstVisibleNode\n ? generateCfiForSpineItemPage({\n spineItem: endSpineItem.item,\n pageNode: endPageEntry?.firstVisibleNode,\n })\n : generateRootCfi(endSpineItem.item),\n })\n }),\n )\n\n merge(updatePagination$, updateCfi$)\n .pipe(takeUntil(this.destroy$))\n .subscribe()\n }\n}\n","import type { Manifest } from \"@prose-reader/shared\"\n\n/**\n * Global spread behavior\n * @see http://idpf.org/epub/fxl/#property-spread\n * @todo user setting\n */\nexport const computeSpreadMode = ({\n manifest,\n spreadMode,\n}: {\n spreadMode: boolean\n manifest?: Manifest\n}) => {\n /**\n * For now we don't support spread for reflowable & scrollable content since\n * two items could have different height, resulting in weird stuff.\n */\n if (manifest?.renditionFlow === `scrolled-continuous`) return false\n\n return spreadMode\n}\n","import { isShallowEqual, shallowMergeIfDefined } from \"@prose-reader/shared\"\nimport {\n distinctUntilChanged,\n type Observable,\n Subject,\n shareReplay,\n} from \"rxjs\"\nimport { DestroyableClass } from \"../utils/DestroyableClass\"\nimport { mapKeysTo } from \"../utils/rxjs\"\nimport type { SettingsInterface } from \"./SettingsInterface\"\n\nexport abstract class SettingsManager<\n InputSettings extends object,\n OutputSettings extends Record<string, unknown>,\n >\n extends DestroyableClass\n implements SettingsInterface<InputSettings, OutputSettings>\n{\n protected inputSettings: InputSettings\n protected outputSettings?: OutputSettings\n protected outputSettingsUpdateSubject: Subject<OutputSettings>\n\n public _settings$: Observable<OutputSettings>\n\n constructor(initialSettings: Partial<InputSettings>) {\n super()\n\n const settingsWithDefaults: InputSettings = {\n ...this.getDefaultSettings(),\n ...initialSettings,\n }\n\n this.inputSettings = settingsWithDefaults\n this.outputSettingsUpdateSubject = new Subject()\n\n this._settings$ = this.outputSettingsUpdateSubject\n .asObservable()\n .pipe(shareReplay(1))\n\n this._settings$.subscribe()\n }\n\n _prepareUpdate(settings: Partial<InputSettings>): {\n hasChanged: boolean\n state: OutputSettings\n commit: () => OutputSettings\n } {\n const newInputSettings = shallowMergeIfDefined(this.inputSettings, settings)\n\n const state = this.getOutputSettings(newInputSettings)\n\n const hasChanged = !isShallowEqual(this.outputSettings, state)\n\n return {\n hasChanged: hasChanged,\n state,\n commit: () => {\n this.inputSettings = newInputSettings\n this.outputSettings = state\n\n if (hasChanged) {\n this.outputSettingsUpdateSubject.next(state)\n }\n\n return state\n },\n }\n }\n\n abstract getOutputSettings(inputSettings: InputSettings): OutputSettings\n\n abstract getDefaultSettings(): InputSettings\n\n public update(settings: Partial<InputSettings>) {\n const { commit } = this._prepareUpdate(settings)\n\n commit()\n }\n\n get values() {\n if (!this.outputSettings) {\n const { commit } = this._prepareUpdate(this.inputSettings)\n\n return commit()\n }\n\n return this.outputSettings\n }\n\n get values$() {\n if (!this.outputSettings) {\n const { commit } = this._prepareUpdate(this.inputSettings)\n\n commit()\n }\n\n return this._settings$\n }\n\n public watch<K extends keyof OutputSettings>(keys: K[]) {\n return this.values$.pipe(\n mapKeysTo(keys),\n distinctUntilChanged(isShallowEqual),\n )\n }\n\n public destroy() {\n super.destroy()\n this.outputSettingsUpdateSubject.complete()\n }\n}\n","import { takeUntil, tap } from \"rxjs\"\nimport type { Context } from \"../context/Context\"\nimport { Report } from \"../report\"\nimport { computeSpreadMode } from \"./computeSpreadMode\"\nimport type { SettingsInterface } from \"./SettingsInterface\"\nimport { SettingsManager } from \"./SettingsManager\"\nimport type {\n ComputedCoreSettings,\n CoreInputSettings,\n CoreOutputSettings,\n} from \"./types\"\n\n/**\n * @important If a settings needs to be derived from a sub component, it needs to live next to the said\n * component or pushed back into the context.\n */\nexport class ReaderSettingsManager\n extends SettingsManager<CoreInputSettings, CoreOutputSettings>\n implements SettingsInterface<CoreInputSettings, CoreOutputSettings>\n{\n constructor(\n initialSettings: Partial<CoreInputSettings>,\n protected context: Context,\n ) {\n super(initialSettings)\n\n context\n .watch([\"manifest\", \"hasVerticalWriting\"])\n .pipe(\n tap(() => this.update(this.values)),\n takeUntil(this.destroy$),\n )\n .subscribe()\n }\n\n private getComputedSettings(\n settings: CoreInputSettings,\n ): ComputedCoreSettings {\n const manifest = this.context.manifest\n const hasVerticalWriting = this.context.value.hasVerticalWriting ?? false\n const computedSettings: ComputedCoreSettings = {\n computedPageTurnDirection: settings.pageTurnDirection,\n computedPageTurnAnimation: settings.pageTurnAnimation,\n computedPageTurnMode: settings.pageTurnMode,\n computedPageTurnAnimationDuration: 0,\n computedSpreadMode: computeSpreadMode({\n spreadMode: settings.spreadMode,\n manifest,\n }),\n }\n\n // We force scroll mode for some books\n if (manifest?.renditionFlow === `scrolled-continuous`) {\n computedSettings.computedPageTurnMode = `scrollable`\n }\n\n if (computedSettings.computedPageTurnMode === \"scrollable\") {\n computedSettings.computedPageTurnDirection = `vertical`\n }\n\n // some settings are not available for vertical writing\n if (\n hasVerticalWriting &&\n computedSettings.computedPageTurnAnimation === `slide`\n ) {\n Report.warn(\n `pageTurnAnimation ${computedSettings.computedPageTurnAnimation} incompatible with current book, switching back to default`,\n )\n computedSettings.computedPageTurnAnimation = `none`\n }\n\n // for now we only support animation none for scrollable\n if (computedSettings.computedPageTurnMode === `scrollable`) {\n computedSettings.computedPageTurnAnimationDuration = 0\n computedSettings.computedPageTurnAnimation = `none`\n } else {\n computedSettings.computedPageTurnAnimationDuration =\n settings.pageTurnAnimationDuration !== undefined\n ? settings.pageTurnAnimationDuration\n : 300\n }\n\n return computedSettings\n }\n\n getOutputSettings(\n inputSettings: CoreInputSettings,\n ): CoreInputSettings & ComputedCoreSettings {\n const computedSettings = this.getComputedSettings(inputSettings)\n\n return { ...this.outputSettings, ...inputSettings, ...computedSettings }\n }\n\n getDefaultSettings() {\n return {\n spreadMode: false,\n pageTurnAnimation: `slide`,\n pageTurnDirection: `horizontal` as const,\n pageTurnAnimationDuration: undefined,\n pageTurnMode: `controlled` as const,\n snapAnimationDuration: 300,\n navigationSnapThreshold: { type: \"pixels\", value: 40 },\n numberOfAdjacentSpineItemToPreLoad: 3,\n } satisfies CoreInputSettings\n }\n}\n","import { EMPTY, of } from \"rxjs\"\nimport { DocumentRenderer } from \"./DocumentRenderer\"\n\nexport class DefaultRenderer extends DocumentRenderer {\n onUnload() {\n return EMPTY\n }\n\n onCreateDocument() {\n return of(document.createElement(\"div\"))\n }\n\n onLoadDocument() {\n return EMPTY\n }\n\n onLayout() {\n return of(undefined)\n }\n\n onRenderHeadless() {\n return EMPTY\n }\n\n getDocumentFrame() {\n return undefined\n }\n}\n","import { isShallowEqual, type Manifest } from \"@prose-reader/shared\"\nimport {\n filter,\n first,\n map,\n merge,\n type Observable,\n type ObservedValueOf,\n of,\n Subject,\n share,\n switchMap,\n} from \"rxjs\"\nimport type { Context } from \"../context/Context\"\nimport type { HookManager } from \"../hooks/HookManager\"\nimport { isFullyPrePaginated } from \"../manifest/isFullyPrePaginated\"\nimport type { ReaderSettingsManager } from \"../settings/ReaderSettingsManager\"\nimport { DestroyableClass } from \"../utils/DestroyableClass\"\nimport { deferNextResult } from \"../utils/rxjs\"\nimport type { Viewport } from \"../viewport/Viewport\"\nimport type { DocumentRenderer } from \"./renderer/DocumentRenderer\"\n\nexport class SpineItemLayout extends DestroyableClass {\n private layoutTriggerSubject = new Subject<{\n spreadPosition: \"left\" | \"right\" | \"none\"\n horizontalOffset: number\n isLastItem: boolean\n edgeX: number\n edgeY: number\n }>()\n\n private lastLayout: {\n width: number\n height: number\n pageSize: { width: number; height: number }\n } | null = null\n\n public readonly didLayout$: Observable<{ width: number; height: number }>\n\n constructor(\n public item: Manifest[`spineItems`][number],\n public containerElement: HTMLElement,\n public context: Context,\n public hookManager: HookManager,\n public renderer: DocumentRenderer,\n public settings: ReaderSettingsManager,\n public viewport: Viewport,\n ) {\n super()\n\n const layoutProcess$ = this.layoutTriggerSubject.pipe(\n switchMap(\n ({ spreadPosition, horizontalOffset, isLastItem, edgeX, edgeY }) => {\n const { blankPagePosition, minimumWidth } =\n this.computeLayoutInformation({ horizontalOffset, isLastItem })\n\n this.hookManager.execute(`item.onBeforeLayout`, undefined, {\n blankPagePosition,\n item: this.item,\n minimumWidth,\n })\n\n const rendererLayout$ = this.renderer.layout({\n blankPagePosition,\n minPageSpread: minimumWidth / this.viewport.pageSize.width,\n minimumWidth,\n spreadPosition,\n })\n\n return merge(\n of({ type: \"start\" } as const),\n rendererLayout$.pipe(\n /**\n * Now that inner layout is done from the renderer, we adjust the dimensions\n * of the outer container element\n */\n this.updateContainerLayout({\n minimumWidth,\n edgeX,\n edgeY,\n }),\n map((data) => {\n this.hookManager.execute(`item.onAfterLayout`, undefined, {\n blankPagePosition,\n item: this.item,\n minimumWidth,\n })\n\n return {\n type: \"end\",\n data,\n } as const\n }),\n ),\n )\n },\n ),\n share(),\n )\n\n this.didLayout$ = layoutProcess$.pipe(\n filter((event) => event.type === `end`),\n map((event) => event.data),\n share(),\n )\n }\n\n private validateDimension(\n value: number,\n pageSize: number,\n minimum: number,\n ): number {\n if (value <= 0) return minimum\n\n const maxValue = Math.max(value, minimum)\n\n // Check if value is a multiple of page size\n const multiplier = Math.ceil(maxValue / pageSize)\n const adjustedValue = multiplier * pageSize\n\n // Ensure the value meets minimum requirement\n return Math.max(adjustedValue, pageSize)\n }\n\n private computeLayoutInformation = ({\n isLastItem,\n horizontalOffset,\n }: {\n isLastItem: boolean\n horizontalOffset: number\n }) => {\n let minimumWidth = this.viewport.value.pageSize.width\n let blankPagePosition: `none` | `before` | `after` = `none`\n const isScreenStartItem =\n horizontalOffset % this.viewport.absoluteViewport.width === 0\n const manifest = this.context.manifest\n const isGloballyPrePaginated = isFullyPrePaginated(manifest) ?? false\n\n if (this.settings.values.computedSpreadMode) {\n /**\n * for now every reflowable content that has reflow siblings takes the entire screen by default\n * this simplify many things and I am not sure the specs allow one reflow\n * to end and an other one to start on the same screen anyway\n *\n * @important\n * For now this is impossible to have reflow not taking all screen. This is because\n * when an element is unloaded, the next element will move back its x axis, then an adjustment\n * will occurs and the previous element will become visible again, meaning it will be loaded,\n * therefore pushing the focused element, meaning adjustment again, then unload of previous one,\n * ... infinite loop. Due to the nature of reflow it's pretty much impossible to not load the entire\n * book with spread on to make it work.\n *\n * @important\n * When the book is globally pre-paginated we will not apply any of this even if each item is\n * reflowable. This is mostly a publisher mistake but does not comply with spec. Therefore\n * we ignore it\n */\n if (\n !isGloballyPrePaginated &&\n this.renderer.renditionLayout === `reflowable` &&\n !isLastItem\n ) {\n minimumWidth = this.viewport.value.pageSize.width * 2\n }\n\n // mainly to make loading screen looks good\n if (\n !isGloballyPrePaginated &&\n this.renderer.renditionLayout === `reflowable` &&\n isLastItem &&\n isScreenStartItem\n ) {\n minimumWidth = this.viewport.value.pageSize.width * 2\n }\n\n const lastItemStartOnNewScreenInAPrepaginatedBook =\n isScreenStartItem && isLastItem && isGloballyPrePaginated\n\n if (\n this.item.pageSpreadRight &&\n isScreenStartItem &&\n !this.context.isRTL()\n ) {\n blankPagePosition = `before`\n minimumWidth = this.viewport.value.pageSize.width * 2\n } else if (\n this.item.pageSpreadLeft &&\n isScreenStartItem &&\n this.context.isRTL()\n ) {\n blankPagePosition = `before`\n minimumWidth = this.viewport.value.pageSize.width * 2\n } else if (lastItemStartOnNewScreenInAPrepaginatedBook) {\n if (this.context.isRTL()) {\n blankPagePosition = `before`\n } else {\n blankPagePosition = `after`\n }\n\n minimumWidth = this.viewport.value.pageSize.width * 2\n }\n }\n\n return {\n minimumWidth,\n blankPagePosition,\n }\n }\n\n private adjustPositionOfElement = ({\n right,\n left,\n top,\n }: {\n right?: number\n left?: number\n top?: number\n }) => {\n if (right !== undefined) {\n this.containerElement.style.right = `${right}px`\n } else {\n this.containerElement.style.removeProperty(`right`)\n }\n if (left !== undefined) {\n this.containerElement.style.left = `${left}px`\n } else {\n this.containerElement.style.removeProperty(`left`)\n }\n if (top !== undefined) {\n this.containerElement.style.top = `${top}px`\n } else {\n this.containerElement.style.removeProperty(`top`)\n }\n }\n\n private updateContainerLayout =\n ({\n minimumWidth,\n edgeX,\n edgeY,\n }: {\n minimumWidth: number\n edgeX: number\n edgeY: number\n }) =>\n (stream: Observable<{ width: number; height: number } | undefined>) =>\n stream.pipe(\n map((dims) => {\n const trustableLastLayout = isShallowEqual(\n this.lastLayout?.pageSize,\n this.viewport.pageSize,\n )\n ? this.lastLayout\n : undefined\n\n const { width: previousWidth, height: previousHeight } =\n trustableLastLayout ?? {}\n const { width = previousWidth, height = previousHeight } = dims ?? {}\n const { width: pageSizeWidth, height: pageSizeHeight } =\n this.viewport.pageSize\n\n const safeWidth = this.validateDimension(\n width ?? pageSizeWidth,\n pageSizeWidth,\n minimumWidth,\n )\n const safeHeight =\n this.settings.values.computedPageTurnMode === \"scrollable\"\n ? (height ?? pageSizeHeight)\n : this.validateDimension(\n height ?? pageSizeHeight,\n pageSizeHeight,\n pageSizeHeight,\n )\n\n this.lastLayout = {\n width: safeWidth,\n height: safeHeight,\n pageSize: this.viewport.pageSize,\n }\n\n this.containerElement.style.width = `${safeWidth}px`\n this.containerElement.style.height = `${safeHeight}px`\n\n if (this.settings.values.computedPageTurnDirection === `vertical`) {\n this.adjustPositionOfElement({\n top: edgeY,\n left: edgeX,\n })\n\n return { width: safeWidth, height: safeHeight }\n }\n\n // We can now adjust the position of the item if needed based on its new layout.\n // For simplification we use an edge offset, which means for LTR it will be x from left and for RTL\n // it will be x from right\n this.adjustPositionOfElement(\n this.context.isRTL()\n ? { right: edgeX, top: 0 }\n : { left: edgeX, top: 0 },\n )\n\n return { width: safeWidth, height: safeHeight }\n }),\n )\n\n public layout = (\n params: ObservedValueOf<typeof this.layoutTriggerSubject>,\n ) => {\n const nextResult = deferNextResult(this.didLayout$.pipe(first()))\n\n this.layoutTriggerSubject.next(params)\n\n return nextResult()\n }\n\n get layoutInfo() {\n const style = this.containerElement.style\n const width = style.width ? parseFloat(style.width) : 0\n const height = style.height ? parseFloat(style.height) : 0\n\n return {\n width,\n height,\n }\n }\n}\n","import { merge } from \"rxjs\"\nimport { share, takeUntil, tap } from \"rxjs/operators\"\nimport type { Manifest } from \"..\"\nimport type { Context } from \"../context/Context\"\nimport type { HookManager } from \"../hooks/HookManager\"\nimport type { ReaderSettingsManager } from \"../settings/ReaderSettingsManager\"\nimport { ReactiveEntity } from \"../utils/ReactiveEntity\"\nimport type { Viewport } from \"../viewport/Viewport\"\nimport { getSpineItemNumberOfPages } from \"./layout/getSpineItemNumberOfPages\"\nimport { DefaultRenderer } from \"./renderer/DefaultRenderer\"\nimport type { DocumentRenderer } from \"./renderer/DocumentRenderer\"\nimport { ResourceHandler } from \"./resources/ResourceHandler\"\nimport { SpineItemLayout } from \"./SpineItemLayout\"\n\nexport type SpineItemReference = string | SpineItem | number\n\nexport type SpineItemState = {\n isLoaded: boolean\n /**\n * - Content has been loaded\n * - A first layout has been done\n */\n isReady: boolean\n isError: boolean\n error: unknown | undefined\n /**\n * - Layout has been requested\n * - Item layout not done yet\n */\n isDirty: boolean\n}\n\nexport class SpineItem extends ReactiveEntity<SpineItemState> {\n public readonly containerElement: HTMLElement\n public readonly renderer: DocumentRenderer\n public readonly resourcesHandler: ResourceHandler\n\n /**\n * Dispatched once the item has fully did layout. State is also updated before the dispatch.\n * - not dirty\n * - ready (if loaded)\n * - element adjusted\n */\n public readonly didLayout$: SpineItemLayout[\"didLayout$\"]\n\n private readonly _layout: SpineItemLayout\n\n constructor(\n public item: Manifest[`spineItems`][number],\n public parentElement: HTMLElement,\n public context: Context,\n public settings: ReaderSettingsManager,\n public hookManager: HookManager,\n public index: number,\n public viewport: Viewport,\n ) {\n super({\n isLoaded: false,\n isReady: false,\n isDirty: false,\n isError: false,\n error: undefined,\n })\n\n this.containerElement = createContainerElement(\n parentElement,\n item,\n hookManager,\n )\n\n parentElement.appendChild(this.containerElement)\n\n const rendererFactory = this.settings.values.getRenderer?.(item)\n\n this.resourcesHandler = new ResourceHandler(item, this.settings)\n\n const rendererParams = {\n context,\n settings,\n hookManager,\n item,\n containerElement: this.containerElement,\n resourcesHandler: this.resourcesHandler,\n viewport: this.viewport,\n }\n\n this.renderer = rendererFactory\n ? rendererFactory(rendererParams)\n : new DefaultRenderer(rendererParams)\n\n this._layout = new SpineItemLayout(\n item,\n this.containerElement,\n context,\n hookManager,\n this.renderer,\n this.settings,\n this.viewport,\n )\n\n const updateStateOnLoaded$ = this.renderer.state$.pipe(\n tap(({ state, error }) => {\n this.mergeCompare({\n isLoaded: state === \"loaded\",\n isError: state === \"error\",\n error: state === \"error\" ? error : undefined,\n })\n }),\n )\n\n this.didLayout$ = this._layout.didLayout$.pipe(\n tap(() => {\n this.mergeCompare({\n isDirty: false,\n isReady: this.renderer.state$.value.state === \"loaded\",\n })\n }),\n share(),\n )\n\n merge(\n /**\n * @important\n * The order is important here. We want to ensure the state value\n * is set before dispatching the layout event. Elements reacting\n * to layout changes may rely on the state value to be updated.\n */\n updateStateOnLoaded$,\n this.didLayout$,\n )\n .pipe(takeUntil(this.destroy$))\n .subscribe()\n }\n\n load = () => {\n this.renderer.load()\n }\n\n unload = () => {\n this.renderer.unload()\n }\n\n public markDirty = () => {\n this.mergeCompare({\n isDirty: true,\n })\n }\n\n /**\n * Renderer loaded + spine item layout done\n * Will switch back and forth every new layout.\n */\n public get isReady$() {\n return this.watch(`isReady`)\n }\n\n public destroy = () => {\n super.destroy()\n\n this.containerElement.remove()\n this.renderer.destroy()\n }\n\n get element() {\n return this.containerElement\n }\n\n /**\n * @important\n * Do not use this value for layout and navigation. It will be in possible conflict\n * with the global reading direction. A book should not mix them anyway. A page can have\n * a different reading direction for style reason but it should be in theory pre-paginated.\n * For example an english page in a japanese manga. That's expected and will\n * be confined to a single page.\n */\n get readingDirection() {\n return this.renderer.readingDirection\n }\n\n isUsingVerticalWriting = () =>\n !!this.renderer.writingMode?.startsWith(`vertical`)\n\n /**\n * Note that this is dispatched AFTER the state has been updated.\n */\n get loaded$() {\n return this.renderer.loaded$\n }\n\n /**\n * Note that this is dispatched AFTER the state has been updated.\n */\n get unloaded$() {\n return this.renderer.unloaded$\n }\n\n get renditionLayout() {\n return this.renderer.renditionLayout\n }\n\n get layoutInfo() {\n return this._layout.layoutInfo\n }\n\n get numberOfPages() {\n return getSpineItemNumberOfPages({\n isUsingVerticalWriting: !!this.isUsingVerticalWriting(),\n itemHeight: this._layout.layoutInfo.height,\n itemWidth: this._layout.layoutInfo.width,\n pageWidth: this.viewport.pageSize.width,\n pageHeight: this.viewport.pageSize.height,\n pageTurnDirection: this.settings.values.computedPageTurnDirection,\n pageTurnMode: this.settings.values.pageTurnMode,\n })\n }\n\n public layout: SpineItemLayout[\"layout\"] = (params) => {\n return this._layout.layout(params)\n }\n}\n\nconst createContainerElement = (\n containerElement: HTMLElement,\n item: Manifest[`spineItems`][number],\n hookManager: HookManager,\n) => {\n const element: HTMLElement =\n containerElement.ownerDocument.createElement(`div`)\n element.classList.add(`spineItem`)\n element.classList.add(`spineItem-${item.renditionLayout ?? \"reflowable\"}`)\n element.style.cssText = `\n position: absolute;\n overflow: hidden;\n `\n // biome-ignore lint/complexity/useLiteralKeys: TODO\n element.dataset[\"isReady\"] = `false`\n\n hookManager.execute(\"item.onBeforeContainerCreated\", undefined, { element })\n\n return element\n}\n","import { arrayEqual } from \"@prose-reader/shared\"\nimport {\n animationFrameScheduler,\n BehaviorSubject,\n debounceTime,\n distinctUntilChanged,\n map,\n merge,\n shareReplay,\n takeUntil,\n withLatestFrom,\n} from \"rxjs\"\nimport type { Context } from \"../../context/Context\"\nimport type { ReaderSettingsManager } from \"../../settings/ReaderSettingsManager\"\nimport type { SpineItem } from \"../../spineItem/SpineItem\"\nimport { DestroyableClass } from \"../../utils/DestroyableClass\"\nimport { waitForSwitch } from \"../../utils/rxjs\"\nimport type { SpineLocator } from \"../locator/SpineLocator\"\nimport type { SpineItemsManager } from \"../SpineItemsManager\"\nimport type { SpineLayout } from \"../SpineLayout\"\n\nexport class SpineItemsLoader extends DestroyableClass {\n private forcedOpenSubject = new BehaviorSubject<Map<number, number>>(\n new Map(),\n )\n\n constructor(\n protected context: Context,\n protected spineItemsManager: SpineItemsManager,\n protected spineLocator: SpineLocator,\n protected settings: ReaderSettingsManager,\n protected spineLayout: SpineLayout,\n ) {\n super()\n\n const forcedOpen$ = this.forcedOpenSubject.pipe(\n map((v) => Array.from(v.keys()).sort((a, b) => a - b)),\n distinctUntilChanged(arrayEqual),\n shareReplay({ bufferSize: 1, refCount: true }),\n )\n\n const shouldReloadSpineItems$ = merge(\n this.context.bridgeEvent.navigation$,\n this.spineLayout.layout$,\n forcedOpen$,\n settings.watch([\"numberOfAdjacentSpineItemToPreLoad\"]),\n )\n\n /**\n * Loading and unloading content has two important issues that need to be considered\n * - For reflow book it will un-sync the viewport\n * - Loading / unload is CPU intensive.\n *\n * Because of theses two reason we only load/unload when the adjustment is done. This ensure a smooth transition for the second point.\n * For the first point it avoid having content being un-sync while the transition is happening. That way we avoid a new chapter\n * to suddenly being displayed under the transition. The first issue is only a problem for reflow book as paginated will not\n * un-sync the viewport.\n * The flow for the first point is as follow:\n * [navigate] -> [transition] -> [new position] -> [iframe unload/load] -> (eventual adjustment).\n *\n * It would ne nice to be able to load/unload without having to worry about viewport mis-adjustment but due to the current iframe and viewport\n * layout method we have to take it into consideration.\n */\n const loadSpineItems$ = shouldReloadSpineItems$.pipe(\n // this can be changed by whatever we want and SHOULD not break navigation.\n // Ideally loading faster is better but loading too close to user navigating can\n // be dangerous.\n debounceTime(100, animationFrameScheduler),\n waitForSwitch(this.context.bridgeEvent.viewportFree$),\n withLatestFrom(this.context.bridgeEvent.navigation$, forcedOpen$),\n map(([, navigation, forcedOpenIndexes]) => {\n const { numberOfAdjacentSpineItemToPreLoad } = settings.values\n // these are real visible items to load\n const { beginIndex = 0, endIndex = 0 } =\n spineLocator.getVisibleSpineItemsFromPosition({\n position: navigation.position,\n threshold: { type: \"percentage\", value: 0 },\n useAbsoluteViewport: false,\n }) || {}\n\n // we increase the range based on settings\n const beginMaximumIndex =\n numberOfAdjacentSpineItemToPreLoad === Infinity\n ? 0\n : beginIndex - numberOfAdjacentSpineItemToPreLoad\n const endMaximumIndex =\n numberOfAdjacentSpineItemToPreLoad === Infinity\n ? spineItemsManager.items.length - 1\n : endIndex + numberOfAdjacentSpineItemToPreLoad\n\n const visibleIndexes = Array.from(\n { length: endMaximumIndex - beginMaximumIndex + 1 },\n (_, i) => beginMaximumIndex + i,\n )\n\n // we combine with forced open to ensure we load the forced open items\n const indexesToLoad = [...forcedOpenIndexes, ...visibleIndexes]\n\n spineItemsManager.items.forEach((orderedSpineItem, index) => {\n if (indexesToLoad.includes(index)) {\n orderedSpineItem.load()\n } else {\n orderedSpineItem.unload()\n }\n })\n }),\n )\n\n loadSpineItems$.pipe(takeUntil(this.destroy$)).subscribe()\n }\n\n forceOpen(spineItems: (number | SpineItem)[]) {\n const indexes = spineItems.map((item) =>\n typeof item === \"number\" ? item : item.index,\n )\n\n const updateMap = (add: boolean) => {\n const map = this.forcedOpenSubject.value\n indexes.forEach((index) => {\n const count = map.get(index) || 0\n const newCount = add ? count + 1 : count - 1\n if (newCount <= 0) map.delete(index)\n else map.set(index, newCount)\n })\n this.forcedOpenSubject.next(map)\n }\n\n updateMap(true)\n\n return () => {\n if (this.isDestroyed) return\n updateMap(false)\n }\n }\n\n public destroy(): void {\n super.destroy()\n\n this.forcedOpenSubject.complete()\n }\n}\n","import { type SpinePosition, UnboundSpinePosition } from \"../spine/types\"\nimport type { AbsoluteViewport, RelativeViewport } from \"./types\"\n\nexport const translateSpinePositionToRelativeViewport = (\n absolutePosition: SpinePosition | UnboundSpinePosition,\n absoluteViewport: AbsoluteViewport,\n relativeViewport: RelativeViewport | AbsoluteViewport,\n): UnboundSpinePosition => {\n // Calculate the offset needed to center the relative viewport within the absolute viewport\n const offsetX = (relativeViewport.width - absoluteViewport.width) / 2\n const offsetY = (relativeViewport.height - absoluteViewport.height) / 2\n\n return new UnboundSpinePosition({\n x: absolutePosition.x - offsetX,\n y: absolutePosition.y - offsetY,\n })\n}\n","import type { SpinePosition, UnboundSpinePosition } from \"../spine/types\"\n\n/**\n * This correspond to a visible slice of the viewport\n * with its coordinate and size. This is not a navigable position\n * nor a spine position. It could be navigable and could be a valid\n * spine position but its intent is different and usually to deduce\n * visible elements on screen for example.\n *\n * This is mostly useful when the viewport is scaled up / down. If there was\n * no scale this would be the equivalent of spine position + viewport\n *\n * You can also see it as a superposition of a spine position and a viewport creating\n * a new position + its spanning size\n */\nexport class ViewportSlicePosition extends DOMRect {\n public readonly __symbol = Symbol(`ViewportPosition`)\n\n static from(rect: {\n x: number\n y: number\n width: number\n height: number\n }): ViewportSlicePosition\n\n static from(\n position: SpinePosition | UnboundSpinePosition,\n viewport: AbsoluteViewport | RelativeViewport,\n ): ViewportSlicePosition\n\n static from(\n positionOrRect:\n | SpinePosition\n | UnboundSpinePosition\n | { x: number; y: number; width: number; height: number },\n viewport?: AbsoluteViewport | RelativeViewport,\n ): ViewportSlicePosition {\n if (viewport) {\n // Second overload: position and viewport\n const position = positionOrRect as SpinePosition\n return new ViewportSlicePosition(\n position.x,\n position.y,\n viewport.width,\n viewport.height,\n )\n }\n // First overload: rect with x, y, width, height\n const rect = positionOrRect as {\n x: number\n y: number\n width: number\n height: number\n }\n return new ViewportSlicePosition(rect.x, rect.y, rect.width, rect.height)\n }\n}\n\nexport class AbsoluteViewport {\n width: number\n height: number\n\n public readonly __symbol = Symbol(`AbsoluteViewport`)\n\n constructor({ width, height }: { width: number; height: number }) {\n this.width = width\n this.height = height\n }\n}\n\nexport class RelativeViewport {\n width: number\n height: number\n\n public readonly __symbol = Symbol(`RelativeViewport`)\n\n constructor({ width, height }: { width: number; height: number }) {\n this.width = width\n this.height = height\n }\n}\n","import type { Context } from \"../../context/Context\"\nimport type { ReaderSettingsManager } from \"../../settings/ReaderSettingsManager\"\nimport type { SpineItem } from \"../../spineItem/SpineItem\"\nimport type { SpineItemsManager } from \"../SpineItemsManager\"\nimport type { SpineLayout } from \"../SpineLayout\"\n\n/**\n * @deprecated use Pages\n */\nexport const getAbsolutePageIndexFromPageIndex = ({\n pageIndex,\n spineItemOrId,\n spineItemsManager,\n}: {\n pageIndex: number\n spineItemOrId: number | SpineItem | string\n spineLayout: SpineLayout\n spineItemsManager: SpineItemsManager\n context: Context\n settings: ReaderSettingsManager\n}) => {\n const items = spineItemsManager.items\n const spineItem = spineItemsManager.get(spineItemOrId)\n\n if (!spineItem) return undefined\n\n const { currentAbsolutePage } = items.reduce(\n (acc, item) => {\n if (acc.found) return acc\n\n const numberOfPages = item.numberOfPages\n\n if (spineItem === item) {\n if (pageIndex <= numberOfPages - 1) {\n return {\n currentAbsolutePage: acc.currentAbsolutePage + pageIndex,\n found: true,\n }\n }\n }\n\n return {\n ...acc,\n currentAbsolutePage: acc.currentAbsolutePage + numberOfPages,\n }\n },\n { currentAbsolutePage: 0, found: false },\n )\n\n return currentAbsolutePage\n}\n","import type { ViewportSlicePosition } from \"../../viewport/types\"\n\nconst isItemVisibleByThresholdForPosition = ({\n itemHeight,\n itemWidth,\n visibleWidthOfItem,\n visibleHeightOfItem,\n threshold,\n}: {\n itemWidth: number\n visibleWidthOfItem: number\n visibleHeightOfItem: number\n itemHeight: number\n threshold:\n | { type: \"percentage\"; value: number }\n | { type: \"pixels\"; value: number }\n}) => {\n const visibleWidthRatioOfSpineItem = visibleWidthOfItem / itemWidth\n const visibleHeightRatioOfSpineItem = visibleHeightOfItem / itemHeight\n\n const isItemVisibleEnough =\n threshold.type === \"percentage\"\n ? visibleWidthRatioOfSpineItem >= threshold.value &&\n visibleHeightRatioOfSpineItem >= threshold.value\n : visibleWidthOfItem >= threshold.value &&\n visibleHeightOfItem >= threshold.value\n\n return isItemVisibleEnough\n}\n\nconst isItemVisibleOnScreenByThresholdForPosition = ({\n visibleWidthOfItem,\n visibleHeightOfItem,\n threshold,\n viewportPosition,\n}: {\n visibleWidthOfItem: number\n visibleHeightOfItem: number\n threshold:\n | { type: \"percentage\"; value: number }\n | { type: \"pixels\"; value: number }\n viewportPosition: ViewportSlicePosition\n}) => {\n const widthRatioOfSpaceTakenInScreen =\n visibleWidthOfItem / viewportPosition.width\n\n const heightRatioOfSpaceTakenInScreen =\n visibleHeightOfItem / viewportPosition.height\n\n const isItemVisibleEnoughOnScreen =\n threshold.type === \"percentage\"\n ? heightRatioOfSpaceTakenInScreen >= threshold.value &&\n widthRatioOfSpaceTakenInScreen >= threshold.value\n : visibleHeightOfItem >= threshold.value &&\n visibleWidthOfItem >= threshold.value\n\n return isItemVisibleEnoughOnScreen\n}\n\n/**\n * Will check whether a spine item is visible on screen\n * by either:\n *\n * - reach the threshold of visibility on screen\n * - reach the threshold of visibility relative to itself\n *\n * This cover the items that are completely visible on screen\n * but too small to reach the threshold of visibility on screen.\n * (we see them entirely but they are maybe too small on screen).\n *\n * Then will cover items that are cut on screen but we see them enough\n * on the screen to consider them.\n */\nexport const getItemVisibilityForPosition = ({\n itemPosition: {\n bottom,\n left,\n right,\n top,\n width: itemWidth,\n height: itemHeight,\n },\n threshold,\n viewportPosition,\n restrictToScreen,\n}: {\n itemPosition: {\n right: number\n left: number\n bottom: number\n top: number\n height: number\n width: number\n }\n viewportPosition: ViewportSlicePosition\n threshold:\n | { type: \"percentage\"; value: number }\n | { type: \"pixels\"; value: number }\n restrictToScreen?: boolean\n}) => {\n const viewportLeft = viewportPosition.x\n const viewportRight = viewportPosition.x + (viewportPosition.width - 1)\n\n const viewportTop = viewportPosition.y\n const viewportBottom = Math.max(\n viewportPosition.y + (viewportPosition.height - 1),\n 0,\n )\n\n const visibleWidthOfItem = Math.max(\n 0,\n Math.min(right, viewportRight) - Math.max(left, viewportLeft),\n )\n\n const visibleHeightOfItem = Math.max(\n 0,\n Math.min(bottom, viewportBottom) - Math.max(top, viewportTop),\n )\n\n const itemIsOnTheOuterEdge =\n visibleWidthOfItem <= 0 || visibleHeightOfItem <= 0\n\n // const thresholdValidRightEdge = viewportRight - viewportWidth * threshold\n // const thresholdValidLeftEdge = viewportLeft + viewportWidth * threshold\n\n if (itemIsOnTheOuterEdge) return { visible: false }\n\n const isItemVisibleEnoughOnScreen =\n isItemVisibleOnScreenByThresholdForPosition({\n threshold,\n visibleHeightOfItem,\n visibleWidthOfItem,\n viewportPosition,\n })\n\n if (restrictToScreen) {\n return { visible: isItemVisibleEnoughOnScreen }\n }\n\n const isItemVisibleEnough = isItemVisibleByThresholdForPosition({\n itemHeight,\n itemWidth,\n threshold,\n visibleHeightOfItem,\n visibleWidthOfItem,\n })\n\n return {\n visible: isItemVisibleEnough || isItemVisibleEnoughOnScreen,\n }\n}\n","import type { SpineItemsManager } from \"../SpineItemsManager\"\nimport type { SpineLayout } from \"../SpineLayout\"\nimport type { SpinePosition, UnboundSpinePosition } from \"../types\"\n\n/**\n * Returns the first element that is within the given position.\n *\n * This method is safe and take into account boundaries.\n */\nexport const getSpineItemFromPosition = ({\n position,\n spineItemsManager,\n spineLayout,\n}: {\n position: SpinePosition | SpinePosition | UnboundSpinePosition\n spineItemsManager: SpineItemsManager\n spineLayout: SpineLayout\n}) => {\n const spineItem = spineItemsManager.items.find((item) => {\n const { left, right, bottom, top } =\n spineLayout.getSpineItemSpineLayoutInfo(item)\n\n const isWithinXAxis = position.x >= left && position.x < right\n\n const isWithinYAxis = position.y >= top && position.y < bottom\n\n return isWithinXAxis && isWithinYAxis\n })\n\n if (position.x === 0 && !spineItem) {\n return spineItemsManager.items[0]\n }\n\n return spineItem\n}\n","import type { SpineItemPosition } from \"../../spineItem/types\"\nimport { SpinePosition } from \"../types\"\n\n/**\n * Be careful when using with spread with RTL, this will return the position for one page size. This is in order to prevent wrong position when\n * an item is not taking the entire spread. That way we always have a valid position for the given item. However you need to adjust it\n * when on spread mode to be sure to position the viewport on the edge.\n *\n * @example\n * [ item-a | item-a ]\n * 400 200 0\n * will return 200, which probably needs to be adjusted as 0\n */\nexport const getSpinePositionFromSpineItemPosition = ({\n spineItemPosition,\n itemLayout: { left, top },\n}: {\n spineItemPosition: SpineItemPosition\n itemLayout: { left: number; top: number }\n}) => {\n /**\n * For this case the global offset move from right to left but this specific item\n * reads from left to right. This means that when the offset is at the start of the item\n * it is in fact at his end. This behavior can be observed in `haruko` about chapter.\n * @example\n * <---------------------------------------------------- global offset\n * item offset ------------------>\n * [item2 (page0 - page1 - page2)] [item1 (page1 - page0)] [item0 (page0)]\n */\n // if (context.isRTL() && itemReadingDirection === 'ltr') {\n // return (end - spineItemOffset) - context.getPageSize().width\n // }\n\n return new SpinePosition({\n x: left + spineItemPosition.x,\n y: top + spineItemPosition.y,\n })\n}\n","import type { ReaderSettingsManager } from \"../../settings/ReaderSettingsManager\"\nimport type { SpineItem } from \"../../spineItem/SpineItem\"\nimport { translateSpinePositionToRelativeViewport } from \"../../viewport/translateSpinePositionToRelativeViewport\"\nimport { ViewportSlicePosition } from \"../../viewport/types\"\nimport type { Viewport } from \"../../viewport/Viewport\"\nimport type { SpineItemsManager } from \"../SpineItemsManager\"\nimport type { SpineLayout } from \"../SpineLayout\"\nimport type { SpinePosition, UnboundSpinePosition } from \"../types\"\nimport { getItemVisibilityForPosition } from \"./getItemVisibilityForPosition\"\nimport { getSpineItemFromPosition } from \"./getSpineItemFromPosition\"\n\nexport const getVisibleSpineItemsFromPosition = ({\n position,\n threshold,\n restrictToScreen,\n spineItemsManager,\n spineLayout,\n useAbsoluteViewport = true,\n viewport,\n}: {\n position: SpinePosition | UnboundSpinePosition\n threshold:\n | { type: \"percentage\"; value: number }\n | { type: \"pixels\"; value: number }\n restrictToScreen?: boolean\n spineItemsManager: SpineItemsManager\n settings: ReaderSettingsManager\n spineLayout: SpineLayout\n useAbsoluteViewport?: boolean\n viewport: Viewport\n}):\n | {\n beginIndex: number\n endIndex: number\n }\n | undefined => {\n const fallbackSpineItem =\n getSpineItemFromPosition({\n position,\n spineItemsManager,\n spineLayout,\n }) || spineItemsManager.get(0)\n\n const spineItemsVisible = spineItemsManager.items.reduce<SpineItem[]>(\n (acc, spineItem) => {\n const itemPosition = spineLayout.getSpineItemSpineLayoutInfo(spineItem)\n const viewportInfo = useAbsoluteViewport\n ? viewport.absoluteViewport\n : viewport.relativeViewport\n const relativeSpinePosition = translateSpinePositionToRelativeViewport(\n position,\n viewport.absoluteViewport,\n viewportInfo,\n )\n\n const viewportPosition = ViewportSlicePosition.from(\n relativeSpinePosition,\n viewportInfo,\n )\n const { visible } = getItemVisibilityForPosition({\n itemPosition,\n threshold,\n viewportPosition,\n restrictToScreen,\n })\n\n if (visible) {\n return [...acc, spineItem]\n }\n\n return acc\n },\n [],\n )\n\n const beginItem = spineItemsVisible[0] ?? fallbackSpineItem\n const endItem = spineItemsVisible[spineItemsVisible.length - 1] ?? beginItem\n\n if (!beginItem || !endItem) return undefined\n\n const beginItemIndex = spineItemsManager.getSpineItemIndex(beginItem)\n const endItemIndex = spineItemsManager.getSpineItemIndex(endItem)\n\n return {\n beginIndex: beginItemIndex ?? 0,\n endIndex: endItemIndex ?? 0,\n }\n}\n","import type { Context } from \"../../context/Context\"\nimport type { ReaderSettingsManager } from \"../../settings/ReaderSettingsManager\"\nimport type { createSpineItemLocator } from \"../../spineItem/locationResolver\"\nimport type { SpineItem } from \"../../spineItem/SpineItem\"\nimport { SpineItemPosition } from \"../../spineItem/types\"\nimport { translateSpinePositionToRelativeViewport } from \"../../viewport/translateSpinePositionToRelativeViewport\"\nimport { ViewportSlicePosition } from \"../../viewport/types\"\nimport type { Viewport } from \"../../viewport/Viewport\"\nimport type { SpineItemsManager } from \"../SpineItemsManager\"\nimport type { SpineLayout } from \"../SpineLayout\"\nimport type { SpinePosition, UnboundSpinePosition } from \"../types\"\nimport { getAbsolutePageIndexFromPageIndex } from \"./getAbsolutePageIndexFromPageIndex\"\nimport { getItemVisibilityForPosition } from \"./getItemVisibilityForPosition\"\nimport { getSpineItemFromPosition } from \"./getSpineItemFromPosition\"\nimport { getSpinePositionFromSpineItemPosition } from \"./getSpinePositionFromSpineItemPosition\"\nimport { getVisibleSpineItemsFromPosition } from \"./getVisibleSpineItemsFromPosition\"\n\nexport type SpineLocator = ReturnType<typeof createSpineLocator>\n\nexport const createSpineLocator = ({\n spineItemsManager,\n context,\n spineItemLocator,\n settings,\n spineLayout,\n viewport,\n}: {\n spineItemsManager: SpineItemsManager\n context: Context\n spineItemLocator: ReturnType<typeof createSpineItemLocator>\n settings: ReaderSettingsManager\n spineLayout: SpineLayout\n viewport: Viewport\n}) => {\n const getSpineItemPositionFromSpinePosition = (\n position: SpinePosition | UnboundSpinePosition,\n spineItem: SpineItem,\n ): SpineItemPosition => {\n const { left, top } = spineLayout.getSpineItemSpineLayoutInfo(spineItem)\n\n /**\n * For this case the global offset move from right to left but this specific item\n * reads from left to right. This means that when the offset is at the start of the item\n * it is in fact at his end. This behavior can be observed in `haruko` about chapter.\n * @example\n * <---------------------------------------------------- global offset\n * item offset ------------------>\n * [item2 (page0 - page1 - page2)] [item1 (page1 - page0)] [item0 (page0)]\n */\n // if (context.isRTL() && itemReadingDirection === 'ltr') {\n // return (end - readingOrderViewOffset) - context.getPageSize().width\n // }\n\n return new SpineItemPosition({\n /**\n * when using spread the item could be on the right and therefore will be negative\n * @example\n * 400 (position = viewport), page of 200\n * 400 - 600 = -200.\n * However we can assume we are at 0, because we in fact can see the beginning of the item\n */\n x: Math.max(position.x - left, 0),\n y: Math.max(position.y - top, 0),\n })\n }\n\n const getSpinePositionFromSpineItem = (spineItem: SpineItem) => {\n return getSpinePositionFromSpineItemPosition({\n spineItemPosition: new SpineItemPosition({ x: 0, y: 0 }),\n itemLayout: spineLayout.getSpineItemSpineLayoutInfo(spineItem),\n })\n }\n\n const getSpineItemFromIframe = (iframe: Element) => {\n return spineItemsManager.items.find((item) => {\n const element = item.renderer.getDocumentFrame()\n\n return element === iframe\n })\n }\n\n const getSpineItemPageIndexFromNode = (\n node: Node,\n offset: number | undefined,\n spineItemOrIndex: SpineItem | number,\n ) => {\n if (typeof spineItemOrIndex === \"number\") {\n const spineItem = spineItemsManager.get(spineItemOrIndex)\n return spineItem\n ? spineItemLocator.getSpineItemPageIndexFromNode(\n node,\n offset || 0,\n spineItem,\n )\n : undefined\n }\n\n return spineItemLocator.getSpineItemPageIndexFromNode(\n node,\n offset || 0,\n spineItemOrIndex,\n )\n }\n\n const getVisiblePagesFromViewportPosition = ({\n position,\n threshold,\n spineItem,\n restrictToScreen,\n useAbsoluteViewport = true,\n viewport,\n }: {\n position: SpinePosition | UnboundSpinePosition\n threshold:\n | { type: \"percentage\"; value: number }\n | { type: \"pixels\"; value: number }\n spineItem: SpineItem\n restrictToScreen?: boolean\n useAbsoluteViewport?: boolean\n viewport: Viewport\n }):\n | {\n beginPageIndex: number\n endPageIndex: number\n }\n | undefined => {\n const numberOfPages = spineItem.numberOfPages\n\n const pages = Array.from(Array(numberOfPages)).map((_, index) => {\n const spineItemPosition =\n spineItemLocator.getSpineItemPositionFromPageIndex({\n pageIndex: index,\n spineItem,\n })\n\n const spinePosition = getSpinePositionFromSpineItemPosition({\n spineItemPosition,\n itemLayout: spineLayout.getSpineItemSpineLayoutInfo(spineItem),\n })\n\n return {\n index,\n absolutePosition: {\n width: viewport.pageSize.width,\n height: viewport.pageSize.height,\n left: spinePosition.x,\n top: spinePosition.y,\n bottom: spinePosition.y + viewport.pageSize.height,\n right: spinePosition.x + viewport.pageSize.width,\n },\n }\n })\n\n const pagesVisible = pages.reduce<number[]>(\n (acc, { absolutePosition, index }) => {\n const viewportInfo = useAbsoluteViewport\n ? viewport.absoluteViewport\n : viewport.relativeViewport\n\n const relativeSpinePosition = translateSpinePositionToRelativeViewport(\n position,\n viewport.absoluteViewport,\n viewportInfo,\n )\n\n const viewportPosition = ViewportSlicePosition.from(\n relativeSpinePosition,\n viewportInfo,\n )\n\n const { visible } = getItemVisibilityForPosition({\n viewportPosition,\n restrictToScreen,\n threshold,\n itemPosition: absolutePosition,\n })\n\n if (visible) {\n return [...acc, index]\n }\n\n return acc\n },\n [],\n )\n\n const beginPageIndex = pagesVisible[0]\n const endPageIndex = pagesVisible[pagesVisible.length - 1] ?? beginPageIndex\n\n if (beginPageIndex === undefined || endPageIndex === undefined)\n return undefined\n\n return {\n beginPageIndex,\n endPageIndex,\n }\n }\n\n const isPositionWithinSpineItem = (\n position: ViewportSlicePosition | SpinePosition | UnboundSpinePosition,\n spineItem: SpineItem,\n ) => {\n const { bottom, left, right, top } =\n spineLayout.getSpineItemSpineLayoutInfo(spineItem)\n\n return (\n position.x >= left &&\n position.x <= right &&\n position.y <= bottom &&\n position.y >= top\n )\n }\n\n // @todo move into spine item locator\n const getSafeSpineItemPositionFromUnsafeSpineItemPosition = (\n unsafePosition: SpineItemPosition,\n spineItem: SpineItem,\n ): SpineItemPosition => {\n const { height, width } = spineLayout.getSpineItemSpineLayoutInfo(spineItem)\n\n return new SpineItemPosition({\n x: Math.min(Math.max(0, unsafePosition.x), width),\n y: Math.min(Math.max(0, unsafePosition.y), height),\n })\n }\n\n const getSpineItemPagePositionFromSpinePosition = (\n spinePosition: UnboundSpinePosition | SpinePosition,\n ) => {\n const spineItem = getSpineItemFromPosition({\n position: spinePosition,\n spineItemsManager,\n spineLayout,\n })\n\n if (!spineItem) {\n return undefined\n }\n\n const spineItemPosition = getSpineItemPositionFromSpinePosition(\n spinePosition,\n spineItem,\n )\n\n const spineItemPageIndex =\n spineItemLocator.getSpineItemPageIndexFromPosition({\n itemWidth: spineItem.layoutInfo.width,\n itemHeight: spineItem.layoutInfo.height,\n position: spineItemPosition,\n isUsingVerticalWriting: !!spineItem.isUsingVerticalWriting(),\n })\n\n const spineItemPagePosition =\n spineItemLocator.getSpineItemPagePositionFromSpineItemPosition(\n spineItemPosition,\n spineItemPageIndex,\n spineItem,\n )\n\n return {\n spineItem,\n spineItemPageIndex,\n spineItemPagePosition,\n pageSize: viewport.value.pageSize,\n }\n }\n\n return {\n getSpinePositionFromSpineItemPosition: ({\n spineItem,\n spineItemPosition,\n }: {\n spineItemPosition: SpineItemPosition\n spineItem: SpineItem\n }) => {\n const itemLayout = spineLayout.getSpineItemSpineLayoutInfo(spineItem)\n\n return getSpinePositionFromSpineItemPosition({\n itemLayout,\n spineItemPosition,\n })\n },\n /**\n * @deprecated use Pages\n */\n _getAbsolutePageIndexFromPageIndex: (\n params: Omit<\n Parameters<typeof getAbsolutePageIndexFromPageIndex>[0],\n \"context\" | \"settings\" | \"spineLayout\" | \"spineItemsManager\"\n >,\n ) =>\n getAbsolutePageIndexFromPageIndex({\n ...params,\n context,\n settings,\n spineItemsManager,\n spineLayout,\n }),\n getSpineItemPagePositionFromSpinePosition,\n getSpinePositionFromSpineItem,\n getSpineItemPositionFromSpinePosition,\n getSpineItemFromPosition: (\n position: SpinePosition | UnboundSpinePosition,\n ) =>\n getSpineItemFromPosition({\n position,\n spineItemsManager,\n spineLayout,\n }),\n getSpineItemFromIframe,\n getSpineItemPageIndexFromNode,\n getVisibleSpineItemsFromPosition: (\n params: Omit<\n Parameters<typeof getVisibleSpineItemsFromPosition>[0],\n \"spineItemsManager\" | \"settings\" | \"spineLayout\" | \"viewport\"\n >,\n ) =>\n getVisibleSpineItemsFromPosition({\n settings,\n spineItemsManager,\n spineLayout,\n viewport,\n ...params,\n }),\n getVisiblePagesFromViewportPosition: (\n params: Omit<\n Parameters<typeof getVisiblePagesFromViewportPosition>[0],\n \"viewport\"\n >,\n ) =>\n getVisiblePagesFromViewportPosition({\n ...params,\n viewport,\n }),\n isPositionWithinSpineItem,\n spineItemLocator,\n getSafeSpineItemPositionFromUnsafeSpineItemPosition,\n }\n}\n","import { Report as SharedReport } from \"../report\"\n\nexport const Report = SharedReport.namespace(`spine`)\n","import {\n combineLatest,\n map,\n type Observable,\n of,\n share,\n switchMap,\n takeUntil,\n withLatestFrom,\n} from \"rxjs\"\nimport type { Context } from \"../context/Context\"\nimport type { SpineItemLocator } from \"../spineItem/locationResolver\"\nimport type { SpineItem } from \"../spineItem/SpineItem\"\nimport { SpineItemPageLayout } from \"../spineItem/types\"\nimport { getFirstVisibleNodeForPositionRelativeTo } from \"../utils/dom\"\nimport { ReactiveEntity } from \"../utils/ReactiveEntity\"\nimport { idle } from \"../utils/rxjs\"\nimport type { Viewport } from \"../viewport/Viewport\"\nimport type { SpineLocator } from \"./locator/SpineLocator\"\nimport { Report } from \"./report\"\nimport type { SpineItemsManager } from \"./SpineItemsManager\"\nimport type { SpineLayout } from \"./SpineLayout\"\nimport { SpineItemPageSpineLayout, type SpinePosition } from \"./types\"\n\nexport const spinePositionToSpineItemSpineLayout = ({\n position,\n pageSize,\n}: {\n position: SpinePosition\n pageSize: { height: number; width: number }\n}) => {\n return new SpineItemPageSpineLayout({\n ...position,\n left: position.x,\n top: position.y,\n width: pageSize.width,\n height: pageSize.height,\n bottom: position.y + pageSize.height,\n right: position.x + pageSize.width,\n })\n}\n\nexport type PageEntry = {\n absoluteLayout: SpineItemPageSpineLayout\n layout: SpineItemPageLayout\n itemIndex: number\n absolutePageIndex: number\n pageIndex: number\n firstVisibleNode: { node: Node; offset: number } | undefined\n}\n\ntype State = {\n pages: PageEntry[]\n}\n\n/**\n * Hold relevant information about spine pages.\n */\nexport class Pages extends ReactiveEntity<State> {\n public readonly layout$: Observable<State>\n\n constructor(\n public readonly spineLayout: SpineLayout,\n public readonly spineItemsManager: SpineItemsManager,\n public readonly spineItemLocator: SpineItemLocator,\n public readonly context: Context,\n public readonly locator: SpineLocator,\n public readonly viewport: Viewport,\n ) {\n super({ pages: [] })\n\n this.layout$ = spineLayout.layout$.pipe(\n withLatestFrom(viewport),\n switchMap(([, { pageSize }]) => {\n const pages = spineItemsManager.items.reduce(\n (\n acc: (Omit<PageEntry, \"firstVisibleNode\"> & {\n spineItem: SpineItem\n })[],\n spineItem,\n itemIndex,\n ) => {\n const pages = new Array(spineItem.numberOfPages).fill(undefined)\n\n const pagesAbsolutePositions = pages.map((_, pageIndex) => {\n // @todo handle vertical jp\n // top seems ok but left is not, it should probably not be 0 or something\n const pageSpineItemPosition =\n spineItemLocator.getSpineItemPositionFromPageIndex({\n spineItem,\n pageIndex,\n })\n\n const pageSpinePosition =\n locator.getSpinePositionFromSpineItemPosition({\n spineItem,\n spineItemPosition: pageSpineItemPosition,\n })\n\n return {\n absoluteLayout: spinePositionToSpineItemSpineLayout({\n pageSize,\n position: pageSpinePosition,\n }),\n layout: new SpineItemPageLayout({\n left: pageSpineItemPosition.x,\n right: pageSpineItemPosition.x + pageSize.width,\n top: pageSpineItemPosition.y,\n bottom: pageSpineItemPosition.y + pageSize.height,\n width: pageSize.width,\n height: pageSize.height,\n x: pageSpineItemPosition.x,\n y: pageSpineItemPosition.y,\n }),\n itemIndex,\n absolutePageIndex: acc.length + pageIndex,\n spineItem,\n pageIndex,\n }\n })\n\n return [...acc, ...pagesAbsolutePositions]\n },\n [],\n )\n\n const pages$ = combineLatest(\n pages.map((page) => {\n const { spineItem: _unused, ...rest } = page\n\n /**\n * Note that this part adds a significant overhead\n * - lot of rxjs subscribers\n * - overhead of the idle browser task chain\n * - overhead with node finding\n * This is directly tied to the number of items the user loads in parallel\n * and the size of the book.\n * However there are realistically no reason a user would want to load\n * a massive book entirely in parallel.\n */\n if (page.spineItem.value.isLoaded) {\n const frame = page.spineItem.renderer?.getDocumentFrame()\n\n if (\n frame &&\n frame?.contentWindow?.document &&\n frame.contentWindow.document.body !== null\n ) {\n const _document = frame.contentWindow.document\n\n // might need to buffer them to run them all within a single idle task.\n // not sure stacking lot of them like this is a good idea. additionally, maybe we can\n // use something more efficient if its just to ensure 60fps.\n return idle().pipe(\n map(() => {\n const firstVisibleNode =\n getFirstVisibleNodeForPositionRelativeTo(\n _document,\n page.layout,\n )\n\n return {\n ...rest,\n firstVisibleNode,\n }\n }),\n )\n }\n }\n\n // Fast path: No overhead for majority of pages\n return of({ ...rest, firstVisibleNode: undefined })\n }),\n )\n\n return pages$\n }),\n map((pages) => {\n Report.info(`Pages layout`, pages)\n return { pages }\n }),\n share(),\n )\n\n this.layout$.pipe(takeUntil(this.destroy$)).subscribe(this.next.bind(this))\n }\n\n fromSpineItemPageIndex = (spineItem: SpineItem, pageIndex: number) => {\n return this.value.pages.find(\n (page) =>\n page.itemIndex === spineItem.index && page.pageIndex === pageIndex,\n )\n }\n\n fromAbsolutePageIndex = (absolutePageIndex: number) => {\n return this.value.pages.find(\n (page) => page.absolutePageIndex === absolutePageIndex,\n )\n }\n\n observeFromAbsolutePageIndex = (absolutePageIndex: number) =>\n this.pipe(map(() => this.fromAbsolutePageIndex(absolutePageIndex)))\n}\n","import { isShallowEqual } from \"@prose-reader/shared\"\nimport {\n distinctUntilChanged,\n map,\n merge,\n type Observable,\n share,\n switchMap,\n} from \"rxjs\"\nimport type { SpineItem, SpineItemState } from \"../spineItem/SpineItem\"\nimport { DestroyableClass } from \"../utils/DestroyableClass\"\nimport { observeResize } from \"../utils/rxjs\"\nimport type { SpineItemsManager } from \"./SpineItemsManager\"\n\nexport class SpineItemsObserver extends DestroyableClass {\n /**\n * Shared observable which emits every time a spine item state change.\n * As there can be lot of spine items and subscriptions can become costly it is\n * encouraged to use this shared observable.\n */\n public states$: Observable<{ item: SpineItem } & SpineItemState>\n\n /**\n * Observable directly plugged to ResizeObserver for each item.\n */\n public itemResize$: Observable<{\n item: SpineItem\n entries: ResizeObserverEntry[]\n }>\n\n public itemLoad$: Observable<SpineItem>\n public itemUnload$: Observable<SpineItem>\n\n constructor(protected spineItemsManager: SpineItemsManager) {\n super()\n\n this.states$ = this.spineItemsManager.items$.pipe(\n switchMap((items) => {\n return merge(\n ...items.map((item) =>\n item.pipe(\n map((state) => ({ item, ...state })),\n distinctUntilChanged(isShallowEqual),\n ),\n ),\n )\n }),\n share(),\n )\n\n this.itemResize$ = this.spineItemsManager.items$.pipe(\n switchMap((items) => {\n const resize$ = items.map((item) =>\n observeResize(item.element).pipe(\n map((entries) => ({ entries, item })),\n ),\n )\n\n return merge(...resize$)\n }),\n share(),\n )\n\n this.itemLoad$ = this.spineItemsManager.items$.pipe(\n switchMap((items) => {\n return merge(...items.map((item) => item.loaded$.pipe(map(() => item))))\n }),\n share(),\n )\n\n this.itemUnload$ = this.spineItemsManager.items$.pipe(\n switchMap((items) => {\n return merge(\n ...items.map((item) => item.unloaded$.pipe(map(() => item))),\n )\n }),\n share(),\n )\n }\n}\n","import {\n concatMap,\n debounceTime,\n map,\n merge,\n type Observable,\n of,\n Subject,\n share,\n switchMap,\n takeUntil,\n tap,\n} from \"rxjs\"\nimport type { Context } from \"../context/Context\"\nimport type { ReaderSettingsManager } from \"../settings/ReaderSettingsManager\"\nimport type { SpineItem } from \"../spineItem/SpineItem\"\nimport { DestroyableClass } from \"../utils/DestroyableClass\"\nimport type { Viewport } from \"../viewport/Viewport\"\nimport type { SpineItemsManager } from \"./SpineItemsManager\"\nimport type { SpineItemsObserver } from \"./SpineItemsObserver\"\nimport { SpineItemSpineLayout } from \"./types\"\n\nexport type PageLayoutInformation = {\n absolutePageIndex: number\n itemIndex: number\n absolutePosition: SpineItemSpineLayout\n}\n\nexport type LayoutInfo = {\n pages: PageLayoutInformation[]\n}\n\nexport class SpineLayout extends DestroyableClass {\n protected externalLayoutTrigger = new Subject()\n\n /**\n * @todo use absolute position for all direction.\n * translation of position should be done elsewhere\n */\n protected spineItemsRelativeLayouts: SpineItemSpineLayout[] = []\n\n /**\n * Emit layout info after each layout is done.\n */\n public readonly layout$: Observable<unknown>\n\n constructor(\n protected spineItemsManager: SpineItemsManager,\n protected spineItemsObserver: SpineItemsObserver,\n protected context: Context,\n protected settings: ReaderSettingsManager,\n protected viewport: Viewport,\n ) {\n super()\n\n // upstream change, meaning we need to layout again to both resize correctly each item but also to\n // adjust positions, etc\n // This is dispatched AFTER the spine item state has been updated.\n const spineItemNeedsLayout$ = merge(\n spineItemsObserver.itemLoad$,\n spineItemsObserver.itemUnload$,\n )\n\n const layoutTrigger$ = merge(\n this.externalLayoutTrigger,\n spineItemNeedsLayout$,\n )\n\n this.layout$ = layoutTrigger$.pipe(\n tap(() => {\n this.spineItemsManager.items.forEach((item) => {\n item.markDirty()\n })\n }),\n debounceTime(50),\n switchMap(() =>\n this.spineItemsManager.items.reduce(\n (acc$, item, itemIndex) =>\n acc$.pipe(\n concatMap(({ horizontalOffset, verticalOffset }) => {\n const isScreenStartItem =\n horizontalOffset % viewport.absoluteViewport.width === 0\n const isLastItem =\n itemIndex === spineItemsManager.items.length - 1\n const isVertical =\n settings.values.computedPageTurnDirection === `vertical`\n const isRTL = context.isRTL()\n\n const spreadPosition = this.getSpreadPosition(\n isScreenStartItem,\n isRTL,\n )\n const { edgeX, edgeY } = this.getStartEdges(\n isVertical,\n isScreenStartItem,\n horizontalOffset,\n verticalOffset,\n viewport.absoluteViewport.height,\n )\n\n // we trigger an item layout which will update the visual and return\n // us with the item new eventual layout information.\n // This step is not yet about moving item or adjusting position.\n return item\n .layout({\n spreadPosition,\n horizontalOffset,\n isLastItem,\n edgeX,\n edgeY,\n })\n .pipe(\n map(({ width, height }) => {\n const layoutPosition = this.createSpineItemLayout(\n isVertical,\n isRTL,\n edgeX,\n edgeY,\n width,\n height,\n viewport.absoluteViewport.width,\n )\n\n this.spineItemsRelativeLayouts[itemIndex] = layoutPosition\n\n return {\n horizontalOffset: edgeX + width,\n verticalOffset: isVertical ? edgeY + height : 0,\n }\n }),\n )\n }),\n ),\n of({ horizontalOffset: 0, verticalOffset: 0 }),\n ),\n ),\n takeUntil(this.destroy$),\n share(),\n )\n\n this.layout$.subscribe()\n\n this.watchForVerticalWritingUpdate()\n }\n\n private watchForVerticalWritingUpdate() {\n this.spineItemsObserver.itemLoad$\n .pipe(\n tap((spineItem) => {\n this.context.update({\n hasVerticalWriting: spineItem.isUsingVerticalWriting(),\n })\n }),\n takeUntil(this.destroy$),\n )\n .subscribe()\n }\n\n layout() {\n this.externalLayoutTrigger.next(undefined)\n }\n\n public getSpineItemSpineLayoutInfo(\n spineItemOrIndex: SpineItem | number | string | undefined,\n ) {\n const itemIndex =\n this.spineItemsManager.getSpineItemIndex(spineItemOrIndex) ?? 0\n\n return (\n this.spineItemsRelativeLayouts[itemIndex] ||\n new SpineItemSpineLayout({\n left: 0,\n right: 0,\n top: 0,\n bottom: 0,\n width: 0,\n height: 0,\n x: 0,\n y: 0,\n })\n )\n }\n\n get numberOfPages() {\n return this.spineItemsManager.items.reduce((acc, item) => {\n return acc + item.numberOfPages\n }, 0)\n }\n\n public destroy() {\n super.destroy()\n\n this.externalLayoutTrigger.complete()\n }\n\n private getSpreadPosition(\n isScreenStartItem: boolean,\n isRTL: boolean,\n ): \"left\" | \"right\" | \"none\" {\n if (!this.settings.values.computedSpreadMode) return \"none\"\n\n if (isScreenStartItem) {\n return isRTL ? \"right\" : \"left\"\n }\n\n return isRTL ? \"left\" : \"right\"\n }\n\n private getStartEdges(\n isVertical: boolean,\n isScreenStartItem: boolean,\n horizontalOffset: number,\n verticalOffset: number,\n viewportHeight: number,\n ) {\n if (isVertical) {\n return {\n edgeX: isScreenStartItem ? 0 : horizontalOffset,\n edgeY: isScreenStartItem\n ? verticalOffset\n : verticalOffset - viewportHeight,\n }\n }\n\n return {\n edgeX: horizontalOffset,\n edgeY: 0,\n }\n }\n\n private createSpineItemLayout(\n isVertical: boolean,\n isRTL: boolean,\n edgeX: number,\n edgeY: number,\n width: number,\n height: number,\n viewportWidth: number,\n ) {\n if (isVertical) {\n const newEdgeX = width + edgeX\n const newEdgeY = height + edgeY\n\n return new SpineItemSpineLayout({\n left: edgeX,\n right: newEdgeX,\n top: edgeY,\n bottom: newEdgeY,\n height,\n width,\n x: edgeX,\n y: edgeY,\n })\n }\n\n const left = isRTL ? viewportWidth - edgeX - width : edgeX\n\n return new SpineItemSpineLayout({\n right: isRTL ? viewportWidth - edgeX : edgeX + width,\n left,\n x: left,\n top: edgeY,\n bottom: height,\n height,\n width,\n y: edgeY,\n })\n }\n}\n","import { BehaviorSubject, combineLatest, merge } from \"rxjs\"\nimport { filter, takeUntil, tap } from \"rxjs/operators\"\nimport { HTML_PREFIX } from \"../constants\"\nimport type { Context } from \"../context/Context\"\nimport type { HookManager } from \"../hooks/HookManager\"\nimport type { Pagination } from \"../pagination/Pagination\"\nimport type { ReaderSettingsManager } from \"../settings/ReaderSettingsManager\"\nimport type { createSpineItemLocator as createSpineItemLocationResolver } from \"../spineItem/locationResolver\"\nimport { SpineItem } from \"../spineItem/SpineItem\"\nimport { DestroyableClass } from \"../utils/DestroyableClass\"\nimport { isDefined } from \"../utils/isDefined\"\nimport type { Viewport } from \"../viewport/Viewport\"\nimport { SpineItemsLoader } from \"./loader/SpineItemsLoader\"\nimport { createSpineLocator, type SpineLocator } from \"./locator/SpineLocator\"\nimport { Pages } from \"./Pages\"\nimport type { SpineItemsManager } from \"./SpineItemsManager\"\nimport { SpineItemsObserver } from \"./SpineItemsObserver\"\nimport { SpineLayout } from \"./SpineLayout\"\n\nexport class Spine extends DestroyableClass {\n protected elementSubject = new BehaviorSubject<HTMLElement | undefined>(\n undefined,\n )\n protected spineLayout: SpineLayout\n\n public readonly spineItemsLoader: SpineItemsLoader\n public locator: SpineLocator\n public spineItemsObserver: SpineItemsObserver\n public pages: Pages\n public element$ = this.elementSubject.asObservable()\n\n constructor(\n protected context: Context,\n protected pagination: Pagination,\n public spineItemsManager: SpineItemsManager,\n public spineItemLocator: ReturnType<typeof createSpineItemLocationResolver>,\n protected settings: ReaderSettingsManager,\n protected hookManager: HookManager,\n protected viewport: Viewport,\n ) {\n super()\n\n this.spineItemsObserver = new SpineItemsObserver(spineItemsManager)\n\n this.spineLayout = new SpineLayout(\n spineItemsManager,\n this.spineItemsObserver,\n context,\n settings,\n viewport,\n )\n\n this.locator = createSpineLocator({\n context,\n spineItemsManager,\n spineItemLocator,\n settings,\n spineLayout: this.spineLayout,\n viewport,\n })\n\n this.spineItemsLoader = new SpineItemsLoader(\n this.context,\n spineItemsManager,\n this.locator,\n settings,\n this.spineLayout,\n )\n\n this.pages = new Pages(\n this.spineLayout,\n this.spineItemsManager,\n this.spineItemLocator,\n this.context,\n this.locator,\n this.viewport,\n )\n\n const spineElementUpdate$ = context.watch(`rootElement`).pipe(\n filter(isDefined),\n tap((rootElement) => {\n const element: HTMLElement =\n rootElement.ownerDocument.createElement(`div`)\n element.style.cssText = `\n height: 100%;\n position: relative;\n `\n element.className = `${HTML_PREFIX}-spine`\n\n this.elementSubject.next(element)\n }),\n )\n\n const loadSpineItems$ = combineLatest([\n this.context.manifest$,\n this.element$,\n ]).pipe(\n tap(([manifest, element]) => {\n if (!element) return\n\n this.spineItemsManager.destroyItems()\n\n const spineItems = manifest.spineItems.map(\n (resource, index) =>\n new SpineItem(\n resource,\n element,\n this.context,\n this.settings,\n this.hookManager,\n index,\n this.viewport,\n ),\n )\n\n this.spineItemsManager.addMany(spineItems)\n }),\n )\n\n merge(loadSpineItems$, spineElementUpdate$)\n .pipe(takeUntil(this.destroy$))\n .subscribe()\n }\n\n public get element() {\n return this.elementSubject.getValue()\n }\n\n public layout() {\n this.spineLayout.layout()\n }\n\n public getSpineItemSpineLayoutInfo(\n spineItemOrIndex: SpineItem | number | string | undefined,\n ) {\n return this.spineLayout.getSpineItemSpineLayoutInfo(spineItemOrIndex)\n }\n\n public get layout$() {\n // first spineLayout then pages\n return this.pages.layout$\n }\n\n public destroy() {\n super.destroy()\n\n this.pages.destroy()\n this.spineItemsLoader.destroy()\n this.elementSubject.getValue()?.remove()\n this.elementSubject.complete()\n }\n}\n","import { BehaviorSubject } from \"rxjs\"\nimport { parseCfi } from \"../cfi\"\nimport type { Context } from \"../context/Context\"\nimport type { ReaderSettingsManager } from \"../settings/ReaderSettingsManager\"\nimport { SpineItem, type SpineItemReference } from \"../spineItem/SpineItem\"\nimport { DestroyableClass } from \"../utils/DestroyableClass\"\n\nexport class SpineItemsManager extends DestroyableClass {\n constructor(\n protected context: Context,\n protected settings: ReaderSettingsManager,\n ) {\n super()\n }\n\n protected orderedSpineItemsSubject = new BehaviorSubject<SpineItem[]>([])\n public items$ = this.orderedSpineItemsSubject.asObservable()\n\n get(indexOrId: SpineItemReference | undefined) {\n if (typeof indexOrId === \"number\") {\n return this.orderedSpineItemsSubject.value[indexOrId]\n }\n\n if (typeof indexOrId === \"string\") {\n return this.orderedSpineItemsSubject.value.find(\n ({ item }) => item.id === indexOrId,\n )\n }\n\n return indexOrId\n }\n\n comparePositionOf(toCompare: SpineItem, withItem: SpineItem) {\n const toCompareIndex = this.getSpineItemIndex(toCompare) ?? 0\n const withIndex = this.getSpineItemIndex(withItem) ?? 0\n\n return toCompareIndex > withIndex\n ? `after`\n : toCompareIndex === withIndex\n ? `same`\n : `before`\n }\n\n getSpineItemIndex(spineItemOrId: SpineItem | string | number | undefined) {\n const spineItem =\n spineItemOrId instanceof SpineItem\n ? spineItemOrId\n : this.get(spineItemOrId)\n\n if (!spineItem) return undefined\n\n const index = this.orderedSpineItemsSubject.value.indexOf(spineItem)\n\n return index < 0 ? undefined : index\n }\n\n addMany(spineItems: SpineItem[]) {\n this.orderedSpineItemsSubject.next([\n ...this.orderedSpineItemsSubject.getValue(),\n ...spineItems,\n ])\n }\n\n // @todo move\n getSpineItemFromCfi(cfi: string) {\n const { itemIndex } = parseCfi(cfi)\n\n if (itemIndex !== undefined) {\n return this.get(itemIndex)\n }\n\n return undefined\n }\n\n get items() {\n return this.orderedSpineItemsSubject.value\n }\n\n /**\n * @todo handle reload, remove subscription to each items etc. See add()\n */\n destroyItems() {\n this.orderedSpineItemsSubject.value.forEach((item) => {\n item.destroy()\n })\n }\n}\n","import { merge, takeUntil, tap } from \"rxjs\"\nimport { HTML_PREFIX_VIEWPORT } from \"../constants\"\nimport type { Context } from \"../context/Context\"\nimport type { ReaderSettingsManager } from \"../settings/ReaderSettingsManager\"\nimport { ReactiveEntity } from \"../utils/ReactiveEntity\"\nimport { AbsoluteViewport, RelativeViewport } from \"./types\"\n\ntype State = {\n element: HTMLElement\n /**\n * Anything that can change the page size should trigger a layout and thus\n * force a recalculation of the page size.\n */\n pageSize: {\n width: number\n height: number\n }\n /**\n * To get the absolute viewport we consider clientWidth/clientHeight which gives more\n * flexibility for the reader container. For example when using scrollbar with scroll\n * navigator. The viewport dimensions will be affected by the scrollbar.\n *\n * The viewport dimensions are updated only before a layout.\n */\n width: number\n height: number\n}\n\nexport class Viewport extends ReactiveEntity<State> {\n constructor(\n protected context: Context,\n protected settingsManager: ReaderSettingsManager,\n ) {\n const element = document.createElement(\"div\")\n\n element.setAttribute(`data-${HTML_PREFIX_VIEWPORT}`, \"\")\n\n super({\n element,\n pageSize: {\n width: 1,\n height: 1,\n },\n width: 1,\n height: 1,\n })\n\n const updatePageSize$ = this.settingsManager\n .watch([\"computedSpreadMode\"])\n .pipe(\n tap(() => {\n this.mergeCompare({\n pageSize: this.calculatePageSize(this.value),\n })\n }),\n )\n\n const updateLayout$ = this.context.watch(\"rootElement\").pipe(\n tap(() => {\n this.layout()\n }),\n )\n\n merge(updatePageSize$, updateLayout$)\n .pipe(takeUntil(this.destroy$))\n .subscribe()\n }\n\n protected calculatePageSize(layout: { width: number; height: number }) {\n const { computedSpreadMode } = this.settingsManager.values\n\n const pageSize = {\n width: computedSpreadMode ? layout.width / 2 : layout.width,\n height: layout.height,\n }\n\n return pageSize\n }\n\n public layout() {\n const layout = {\n width: this.value.element.clientWidth,\n height: this.value.element.clientHeight,\n }\n\n this.mergeCompare({\n pageSize: this.calculatePageSize(layout),\n ...layout,\n })\n }\n\n public get absoluteViewport() {\n return new AbsoluteViewport({\n width: this.value.width,\n height: this.value.height,\n })\n }\n\n public get pageSize() {\n return this.value.pageSize\n }\n\n public get scaleFactor() {\n const absoluteViewport = this.absoluteViewport\n const viewportRect = this.value.element.getBoundingClientRect()\n const relativeScale =\n (viewportRect?.width ?? absoluteViewport.width) / absoluteViewport.width\n\n return relativeScale\n }\n\n /**\n * Returns the relative viewport after eventual transforms.\n * For example if the viewport was zoomed out, we start seeing more left and right\n * items. Therefore we can virtually expand the viewport.\n * Inversely if the viewport is zoomed in, we see less left and right items.\n *\n * This is mostly useful for detecting what should be visible, navigable, etc.\n *\n * @important\n * Contains long floating values.\n *\n * @todo take position of translate into consideration in something\n * like relativeViewportPosition or even better a ViewportSlicePosition\n */\n public get relativeViewport() {\n const absoluteViewport = this.absoluteViewport\n const relativeScale = this.scaleFactor\n\n return new RelativeViewport({\n width: absoluteViewport.width / relativeScale,\n height: absoluteViewport.height / relativeScale,\n })\n }\n}\n","import { merge, type Observable, type ObservedValueOf, of, Subject } from \"rxjs\"\nimport { map, skip, takeUntil, tap } from \"rxjs/operators\"\nimport {\n generateCfiForSpineItemPage,\n generateCfiFromRange,\n parseCfi,\n} from \"./cfi\"\nimport { resolveCfi } from \"./cfi/resolve\"\nimport {\n HTML_ATTRIBUTE_DATA_READER_ID,\n HTML_PREFIX,\n HTML_STYLE_PREFIX,\n} from \"./constants\"\nimport { Context, type ContextState } from \"./context/Context\"\nimport { Features } from \"./features/Features\"\nimport { HookManager } from \"./hooks/HookManager\"\nimport styles from \"./index.scss?inline\"\nimport { createNavigator } from \"./navigation/Navigator\"\nimport { Pagination } from \"./pagination/Pagination\"\nimport { PaginationController } from \"./pagination/PaginationController\"\nimport { Report } from \"./report\"\nimport { ReaderSettingsManager } from \"./settings/ReaderSettingsManager\"\nimport type { SettingsInterface } from \"./settings/SettingsInterface\"\nimport type { CoreInputSettings } from \"./settings/types\"\nimport { Spine } from \"./spine/Spine\"\nimport { SpineItemsManager } from \"./spine/SpineItemsManager\"\nimport { createSpineItemLocator } from \"./spineItem/locationResolver\"\nimport type { SpineItemReference } from \"./spineItem/SpineItem\"\nimport { injectCSS, removeCSS } from \"./utils/dom\"\nimport { Viewport } from \"./viewport/Viewport\"\n\nexport type CreateReaderOptions = Partial<CoreInputSettings>\n\nexport type CreateReaderParameters = CreateReaderOptions\n\nexport type ContextSettings = Partial<CoreInputSettings>\n\nexport type ReaderInternal = ReturnType<typeof createReader>\n\nconst STYLES_ID = `${HTML_STYLE_PREFIX}-core`\n\nexport const createReader = (inputSettings: CreateReaderOptions) => {\n const id = crypto.randomUUID()\n const layoutSubject = new Subject<void>()\n const destroy$ = new Subject<void>()\n const hookManager = new HookManager()\n const context = new Context()\n const settingsManager = new ReaderSettingsManager(inputSettings, context)\n const features = new Features(context, settingsManager)\n const spineItemsManager = new SpineItemsManager(context, settingsManager)\n const viewport = new Viewport(context, settingsManager)\n const spineItemLocator = createSpineItemLocator({\n context,\n settings: settingsManager,\n viewport,\n })\n const pagination = new Pagination(context, spineItemsManager)\n const spine = new Spine(\n context,\n pagination,\n spineItemsManager,\n spineItemLocator,\n settingsManager,\n hookManager,\n viewport,\n )\n const navigator = createNavigator({\n context,\n spineItemsManager,\n hookManager,\n spine,\n settings: settingsManager,\n viewport,\n })\n const paginationController = new PaginationController(\n context,\n pagination,\n spineItemsManager,\n spine,\n spineItemLocator,\n )\n\n // bridge all navigation stream with reader so they can be shared across app\n navigator.navigationState$.subscribe(context.bridgeEvent.viewportStateSubject)\n navigator.navigation$.subscribe(context.bridgeEvent.navigationSubject)\n navigator.locker.isLocked$.subscribe(\n context.bridgeEvent.navigationIsLockedSubject,\n )\n pagination.subscribe(context.bridgeEvent.paginationSubject)\n\n const layout = () => {\n layoutSubject.next()\n }\n\n const load = (\n options: Required<\n Pick<ContextState, \"manifest\"> & { containerElement: HTMLElement }\n >,\n ) => {\n const { containerElement, manifest } = options\n\n if (context.manifest) {\n Report.warn(`loading a new book is not supported yet`)\n\n return\n }\n\n Report.log(`load`, { options })\n\n const element = wrapContainer(containerElement, id)\n\n context.update({\n manifest,\n rootElement: element,\n })\n\n layout()\n }\n\n const layoutOnSpreadModeChange$ = settingsManager\n .watch([`computedSpreadMode`])\n .pipe(skip(1), tap(layout))\n\n const layout$ = layoutSubject.pipe(\n tap(() => {\n const containerElement = context.value.rootElement\n\n if (!containerElement) return\n\n containerElement.style.setProperty(`overflow`, `hidden`)\n\n viewport.layout()\n spine.layout()\n }),\n takeUntil(destroy$),\n )\n\n const subs = merge(layout$, layoutOnSpreadModeChange$).subscribe()\n\n injectCSS(document, STYLES_ID, styles)\n\n /**\n * Free up resources, and dispose the whole reader.\n * You should call this method if you leave the reader.\n *\n * This is not possible to use any of the reader features once it\n * has been destroyed. If you need to open a new book you need to\n * either create a new reader or call `load` with a different manifest\n * instead of destroying it.\n */\n const destroy = () => {\n removeCSS(document, STYLES_ID)\n\n subs.unsubscribe()\n spineItemsManager.destroy()\n paginationController.destroy()\n settingsManager.destroy()\n pagination.destroy()\n context.destroy()\n navigator.destroy()\n spine.destroy()\n features.destroy()\n destroy$.next()\n destroy$.complete()\n viewport.destroy()\n }\n\n return {\n id,\n context,\n spine,\n hookManager,\n cfi: {\n generateCfiFromRange,\n parseCfi,\n generateCfiForSpineItemPage,\n resolveCfi: (\n params: Omit<Parameters<typeof resolveCfi>[0], \"spineItemsManager\">,\n ) => resolveCfi({ ...params, spineItemsManager }),\n },\n navigation: navigator,\n spineItemsObserver: spine.spineItemsObserver,\n spineItemsManager,\n layout,\n load,\n destroy,\n pagination: {\n get state() {\n return pagination.value\n },\n get state$(): Observable<ObservedValueOf<typeof pagination>> {\n return pagination\n },\n },\n settings: settingsManager as SettingsInterface<\n NonNullable<(typeof settingsManager)[\"inputSettings\"]>,\n NonNullable<(typeof settingsManager)[\"outputSettings\"]>\n >,\n renderHeadless: (spineItem: SpineItemReference) => {\n return (\n spineItemsManager.get(spineItem)?.renderer.renderHeadless() ??\n of(undefined)\n )\n },\n viewport,\n viewportState$: context.bridgeEvent.viewportState$,\n viewportFree$: context.bridgeEvent.viewportFree$,\n /**\n * Dispatched when the reader has loaded a book and is rendering a book.\n * Using navigation API and getting information about current content will\n * have an effect.\n * It can typically be used to hide a loading indicator.\n */\n state$: context.manifest$.pipe(\n map((manifest) => (manifest ? \"ready\" : \"idle\")),\n ),\n features,\n $: {\n destroy$,\n },\n }\n}\n\nconst wrapContainer = (containerElement: HTMLElement, id: string) => {\n containerElement.style.cssText = `\n ${containerElement.style.cssText}\n background-color: white;\n position: relative;\n `\n containerElement.classList.add(`${HTML_PREFIX}-reader`)\n containerElement.setAttribute(HTML_ATTRIBUTE_DATA_READER_ID, id)\n containerElement.setAttribute(\"data-prose-reader-container\", id)\n\n return containerElement\n}\n\ntype Reader = ReturnType<typeof createReader>\n\nexport type { Reader }\n","import { accessibilityEnhancer } from \"./enhancers/accessibility\"\nimport { chromeEnhancer } from \"./enhancers/chrome\"\nimport { eventsEnhancer } from \"./enhancers/events/events\"\nimport { fontsEnhancer } from \"./enhancers/fonts\"\nimport { hotkeysEnhancer } from \"./enhancers/hotkeys\"\nimport { htmlEnhancer } from \"./enhancers/html/enhancer\"\nimport { layoutEnhancer } from \"./enhancers/layout/layoutEnhancer\"\nimport { mediaEnhancer } from \"./enhancers/media/media\"\nimport { navigationEnhancer } from \"./enhancers/navigation\"\nimport { paginationEnhancer } from \"./enhancers/pagination/enhancer\"\nimport { resourcesEnhancer } from \"./enhancers/resources\"\nimport { selectionEnhancer } from \"./enhancers/selection/selectionEnhancer\"\nimport { themeEnhancer } from \"./enhancers/theme\"\nimport { utilsEnhancer } from \"./enhancers/utils\"\nimport { webkitEnhancer } from \"./enhancers/webkit\"\nimport { zoomEnhancer } from \"./enhancers/zoom\"\nimport { createReader as createInternalReader } from \"./reader\"\n\nexport const createReaderWithEnhancers = //__\n selectionEnhancer(\n hotkeysEnhancer(\n webkitEnhancer(\n fontsEnhancer(\n accessibilityEnhancer(\n resourcesEnhancer(\n utilsEnhancer(\n zoomEnhancer(\n navigationEnhancer(\n htmlEnhancer(\n mediaEnhancer(\n chromeEnhancer(\n eventsEnhancer(\n paginationEnhancer(\n layoutEnhancer(\n themeEnhancer(\n // __\n createInternalReader,\n ),\n ),\n ),\n ),\n ),\n ),\n ),\n ),\n ),\n ),\n ),\n ),\n ),\n ),\n ),\n )\n","import type { CreateReaderParameters, ReaderInternal } from \"../../reader\"\n\n// biome-ignore lint/suspicious/noExplicitAny: TODO\nexport type EnhancerOutput<Enhancer extends (options: any) => any> = ReturnType<\n ReturnType<Enhancer>\n>\n// biome-ignore lint/suspicious/noExplicitAny: TODO\nexport type EnhancerOptions<Enhancer extends (options: any) => any> =\n Parameters<ReturnType<Enhancer>>[0]\n\nexport type RootEnhancer<\n Options extends CreateReaderParameters = CreateReaderParameters,\n Reader extends ReaderInternal = ReaderInternal,\n> = (next: (options: Options) => Reader) => (options: Options) => Reader\n\nexport const rootEnhancer =\n <Options extends CreateReaderParameters, Reader extends ReaderInternal>(\n next: (options: Options) => Reader,\n ) =>\n (options: Options): Reader => {\n const reader = next(options)\n\n return reader\n }\n"],"names":["Report","SharedReport","pointerEvents","createRangeOrCaretFromPoint","doc","startX","startY","getFirstVisibleNodeForPositionRelativeTo","documentOrElement","viewport","ownerDocument","element","getFirstVisibleElementForViewport","lastValidRange","lastValidOffset","range","childNode","rects","visibleRect","getFirstVisibleDOMRect","rangeOrCaret","rect","positionFromViewport","getElementOrNodePositionFromViewPort","lastValidElement","child","childInViewPort","domRect","left","right","position","getRangeFromNode","node","offset","e","isPointerEvent","event","eventView","isMouseEvent","isTouchEvent","noopElement","getElementsWithAssets","_document","RESOURCE_ELEMENTS","revokeDocumentBlobs","url","styleSheets","sheet","rules","rule","blobUrls","hasShape","obj","requiredProps","optionalMethods","prop","method","isHtmlElement","isHtmlTagElement","tagName","isHtmlRange","injectCSS","id","style","prepend","userStyle","removeCSS","styleElement","getAttributeValueFromString","string","key","regExp","match","firstMatch","injectCSSToFrame","frameElement","injectCSSToDocument","removeCSSToDocument","upsertCSSToFrame","existingElement","getFrameViewportInfo","frame","viewportMetaElement","viewportContent","width","height","waitForFrameLoad","stream","switchMap","of","fromEvent","take","map","waitForFrameReady","readyPromise","from","accessibilityEnhancer","next","options","reader","observer","entries","entry","itemId","destroy","item","links","link","chromeEnhancer","takeUntil","rootElement","onScroll","translateFramePositionIntoPage","frameRect","scaleX","scaleY","top","adjustedX","adjustedY","normalizeEventForViewport","iframeOriginalEvent","locator","originalFrame","spineItem","pageHeight","pageWidth","clientX","clientY","newEvent","touches","touch","passthroughEvents","eventsEnhancer","unregister","listener","convertedEvent","normalizedEvent","cb","getBase64FromBlob","data","resolve","pick","keys","acc","mapKeysTo","watchKeys","distinctUntilChanged","isShallowEqual","observeResize","Observable","resizeObserver","waitForSwitch","waitForStream","value","first","deferNextResult","sub","result","idle","handle","timeout","deferIdle","callback","defer","observeMutation","target","subscriber","mutations","observeIntersection","intersectionObserver","SettingsManagerOverload","initialSettings","settingsManager","inputSettings","shallowMergeIfDefined","Subject","combineLatest","startWith","parentSettings","settings","shareReplay","parentInputSettings","parentManagerPreparedUpdate","outputSettings","hasChanged","commit","keyOrKeys","newOutputSettings","_unused1","_unused2","_unused3","_unused4","rest","fontsEnhancer","fontScale","lineHeight","fontWeight","fontJustification","changes$","SettingsManager","getStyle","applyChangeToSpineItems","requireLayout","shouldRequireLayout","source","pairwise","old","latest","tap","hotkeysEnhancer","navigateOnKey","document","pageTurnDirection","computedPageTurnMode","spineItems","merge","EMPTY","handleLinks","items","NEVER","events$","share","ReactiveEntity","initialState","BehaviorSubject","pagination","newValue","_DocumentRenderer","params","unloadTrigger$","filter","trigger","loadTrigger$","mergeMap","documentContainer","endWith","hookResults","catchError","error","state","releaseSubject","finalize","itemRenditionLayout","iframe","hasViewport","DocumentRenderer","defaultGetResource","ResourceHandler","lastValueFrom","resource","joinPath","base","path","isFileProtocol","tempBase","loadFontFaces","spineItemUriParentPath","context","i","src","srcParts","part","newSrcParts","urlMatch","originalSrc","foundItem","href","resourceHandler","blob","blobUrl","newRule","loadElementSrc","loadAssets","elementsWithAsset","getParentPath","assetsLoad$","unloadAssets","PROSE_READER_NAMESPACE","VIEWPORT_ADJUSTMENT_THROTTLE","PAGINATION_UPDATE_AFTER_VIEWPORT_ADJUSTMENT_DEBOUNCE","ITEM_EXTENSION_VALID_FOR_FRAME_SRC","HTML_PREFIX","HTML_STYLE_PREFIX","HTML_ATTRIBUTE_DATA_READER_ID","HTML_PREFIX_VIEWPORT","HTML_PREFIX_SCROLL_NAVIGATOR","createHtmlPageFromResource","resourceResponse","contentType","parseContentType","detectMimeTypeFromName","mime","objectUrl","bitmap","attachFrameSrc","resourcesHandler","getHtmlFromResource","response","extension","htmlDoc","blobURL","createFrameElement","getViewPortInformation","viewportDimensions","computedWidthScale","staticLayout","size","renderPrePaginated","minPageSpread","blankPagePosition","spreadPosition","isRTL","minimumWidth","computedScale","hasViewportDimensions","contentWidth","contentHeight","transformTranslateX","transformOriginX","buildStyleForViewportFrame","buildStyleForReflowableImageOnly","isScrollable","enableTouch","buildStyleWithMultiColumn","columnHeight","columnWidth","getDimensionsForReflowableContent","isUsingVerticalWriting","renderReflowable","pageSizeHeight","manifest","isImageType","continuousScrollableReflowableItem","isGloballyPrePaginated","frameStyle","pages","HtmlRenderer","prePaginatedStyle","isTouchEnabled","dims","text","body","htmlEnhancer","props","links$","isDefined","arg","LayoutEntry","layout","SpineItemPosition","UnboundSpineItemPagePosition","SpineItemPageLayout","SpineItemSpineLayout","SpineItemPageSpineLayout","AbstractSpinePosition","SpinePosition","UnboundSpinePosition","getPositionRelativeToNonTransformedElement","elementRect","x","y","relativeX","relativeY","getSpinePositionFromClientPosition","spineElement","createCoordinatesApi","createMovingSafePan$","iframeOverlayForAnimationsElement","updateOverlayElement$","createResetLock$","scheduled","animationFrameScheduler","lockAfterViewportBusy$","resetLockViewportFree$","handleViewportLock$","mode","CONTAINER_HTML_PREFIX","HTML_PREFIX_CORE","defaultLoadingElementCreate","container","loadingElementContainer","logoElement","detailsElement","createPlaceholderPages","alreadyExistingElement","theme","viewportWidth","fixIframeScrollbar","fixReflowable","spineManagerWantAFullWidthItem","flagSpineItems","isReady","isDirty","updateSpreadMode","isLandscape","layoutEnhancer","pageHorizontalMargin","pageVerticalMargin","layoutAutoResize","layoutLayerTransition","hasRedrawn","pageSize","columnGap","revealItemOnReady$","layoutOnContainerResize$","debounceTime","movingSafePan$","skip","layoutInfo$","flagSpineItems$","updateSpreadMode$","placeholderPages$","ImageRenderer","imgElement","responseOrUrl","imageElement","naturalWidth","naturalHeight","ratio","mediaEnhancer","maybeFactory","frameObserver","audios","audioElement","elementObserver","video","videos","unobserveElements","unobserve","handleLinksNavigation","manualNavigator","hrefUrl","hrefWithoutAnchor","navigationReport","getSpineItemPositionForLeftPage","spineItemLocator","nextPotentialPosition","getNavigationForLeftSinglePage","navigationResolver","computedPageTurnDirection","spineItemsManager","spineLocator","defaultNavigation","spineItemPosition","spineItemNavigation","getNavigationForLeftOrTopPage","navigation","doubleNavigation","getSpineItemPositionForRightPage","getNavigationForRightOrBottomSinglePage","spineItemNavigationForRightPage","getNavigationForRightOrBottomPage","ManualNavigator","cfi","indexOrId","endIndex","beginIndex","pageIndex","spineItemId","absolutePageIndex","foundInfo","PanNavigator","delta","viewportScale","correctedX","correctedY","DestroyableClass","SCROLL_FINISHED_DEBOUNCE_TIMEOUT","UserScrollNavigation","scrollNavigationController","locker","navigateOnScroll$","exhaustMap","unlock","spinePosition","observeState","withLatestFrom","paginationInfo","readingDirection","numberOfSpineItems","isAtAbsoluteBeginning","isAtAbsoluteEnd","isAtEndSpineItem","isAtBeginSpineItem","isAtBeginFirstPage","isAtEndLastPage","throttleLock","duration","unlockFn","throttleTime","navigationEnhancer","state$","panNavigator","userScrollNavigation","linksNavigation$","navigateOnUserScroll$","buildChaptersInfo","tocItem","spineItemIndex","indexOfHash","tocItemPathWithoutAnchor","tocItemHrefWithoutFilename","hrefWithoutFilename","hrefIsChapterHref","hrefIsWithinChapter","spineItemIndexOfPossibleCandidate","info","subInfo","buildChapterInfoFromSpineItem","getChaptersInfo","trackChapterInfo","getTotalProgressFromPercentages","estimateBeforeThisItem","currentItemWeight","progressWithinThisItem","getScrollPercentageWithinItem","currentPosition","currentItem","getPercentageEstimate","currentSpineIndex","itemIsReady","readingOrderLength","itemIndexNumber","spineItemNumberOfPages","page","totalProgress","trackTotalPages","mapPaginationInfoToExtendedInfo","chaptersInfo","percentageEstimateOfBook","beginItem","endItem","observeProgression","trackPaginationInfo","chaptersInfo$","totalPages$","currentValue","extandedBasePagination$","extendedInfo","pageInfo","totalPageInfo","numberOfPagesForItem","generateRootCfi","generate","generateCfi","nodeOrRange","nodeOrRangeOwnerDocument","generateCfiForSpineItemPage","pageNode","generateCfiFromRange","getItemAnchor","hasIndirectionMarker","isRootCfi","parsed","parse","isIndirectionOnly","extractIndirectionPart","parsedCfi","parseCfi","isCfiRange","isParsedCfiRange","resolveCfi","itemIndex","restParsed","rendererElement","resolved","toCfiLocatableResource","restParsedCfi","consolidate","itemPageIndex","isSpineItemReady","startOffset","ResourcesLocator","initialConsolidatedValue","isReflowable","release","memoizedConsolidate$","withRelease","meta","consolidate$","switchScan","consolidatedResource","defaultIfEmpty","paginationEnhancer","paginationInfo$","getPaginationInfo","resourcesLocator","createDatabase","db","reject","transaction","request","cursor","err","openDatabase","name","createResourcesManager","uniqueID","cache$","retrieveItem","itemIndexOrId","get","fetchResource","cacheData","cache","forkJoin","onLoad$","keysToRemove","promises","resourcesEnhancer","resourceManager","getRangeFromSelection","anchor","focus","comparison","endOffset","createOrderedRangeFromSelection","selection","anchorNode","anchorOffset","focusNode","focusOffset","FrameSelectionTracker","frameDoc","frameDocMutation$","mutation","iframeDestroyed$","delay","trackSpineItemSelection","selectionTracker","selectionEnhancer","lasSelection","trackedSelection$","instances","selection$","selectionStart$","isSelecting","selectionEnd$","selectionOver$","lastSelectionOnPointerdown$","defaultThemes","themeEnhancer","currentThemeSubject$","foundTheme","applyChangeToSpineItemElement","applyChangeToSpineItem","utilsEnhancer","scope","styleTemplate","styleWithIdReplaced","webkitEnhancer","createReader","constrainPositionWithinViewport","scale","clientWidth","clientHeight","bounds","applyViewportTransformForControlledMode","viewportElement","translateTransform","scaleTransform","derivePositionFromScaleForControlledMode","currentScale","userScale","scaleFactor","originalWidth","originalHeight","visualCenterX","visualCenterY","AbstractPosition","ScrollPosition","UnboundScrollPosition","ScrollNavigationController","hookManager","spine","scaledPosition","timer","elementCreation$","toggleElementDisplay$","navigate$","isSpineScrolling$","scrollHappeningFromBrowser$","spineScrolling","viewportScrolling","shouldAvoidScrollEvent","adjustScrollToKeepContentCentered","scrollContainer","fromScale","toScale","marginX","marginY","containerWidth","containerHeight","currentScrollLeft","currentScrollTop","visibleCenterX","visibleCenterY","newVisibleCenterX","newVisibleCenterY","scrollLeft","scrollTop","applyScaleToViewportForScroll","scrollNavigationElement","newCenterPositionAfterNewScaleProjection","direction","ANIMATION_DURATION","ZoomController","enter$","animate","exit$","newScale","newPosition","constrainedPosition","STYLES_ID","zoomEnhancer","zoomController","styles","isFullyPrePaginated","BridgeEvent","ReplaySubject","isLocked","Context","newState","previousState","newCompleteState","Features","hasVerticalWriting","renditionFlow","renditionLayout","HookManager","hookToDeregister","hook","fn","userDestroyFn","destroySubject","destroyFn","fnResult","ref","hookInstance","instance","destroyFns","spinePositionToTranslation","translationToSpinePosition","translation","report","ControlledNavigationController","elementInit$","settingsThatRequireLayout$","updateElementOnSettingsChange$","animation","currentEvent","animationDuration","pageTurnAnimation","identity","computedStyle","transform","matrix","withPaginationInfo","consolidateWithPagination","navigation$","prev","curr","mapUserNavigationToInternal","userNavigation","previousNavigation","withCfiPosition","getOrGuessDirection","withDirection","conslidatedNavigation","withFallbackPosition","adjustedPosition","withSpineItem","getSpineItem","navigationSnapThreshold","existingSpineItem","farthestSpineItemIndex","farthestSpineItem","endPageIndex","beginPageIndex","farthestVisiblePageIndex","navigationForPosition","visibleSpineItemsFromNavigablePosition","finalSpineItemIndex","withSpineItemLayoutInfo","spineItemDimensions","withSpineItemPosition","getPosition","farthestPageIndex","navigableSpinePositionForFarthestPageIndex","visiblePagesAtNavigablePosition","beginPageIndexForDirection","withUrlInfo","Locker","locked","isCalled","restoreNavigationForControlledPageTurnMode","spineItemAbsolutePosition","isPositionWithinSpineItem","spineItemWidthDifference","spineItemHeighDifference","hasSpineItemGrewOrShrink","urlResult","cfiResultPosition","positionInSpineItemWithDifference","restoreNavigationForScrollingPageTurnMode","foundSpineItem","positionInSpineItem","positionYfromBottomPreviousNavigation","positionInspineItem","positionInItem","restorePosition","withRestoredPosition","restoredPosition","InternalNavigator","userNavigation$","controlledNavigationController","isRestorationLocked$","previousPosition","previousRest","currentRest","navigationFromUser$","isUserLocked","shouldNotAlterPosition","navigationUpdateFollowingUserUnlock$","navigationUpdateFromLayout$","navigationRestored$","navigationUpdateOnPaginationUpdate$","navigationUpdate$","notifyNavigationUpdate","currentNavigation","navigateViewport","isScrollFromUser","isPaginationUpdate","isRestoration","positionIsSame","getItemOffsetFromPageIndex","itemWidth","lastPageOffset","logicalOffset","calculateNumberOfPagesForItem","getClosestValidOffsetFromApproximateOffsetInPages","numberOfPages","offsetValues","_","offsetRange","getPageFromOffset","getSafePosition","itemHeight","getSpineItemNumberOfPages","pageTurnMode","getSpineItemPageIndexFromSpineItemPosition","getSpineItemPositionFromPageIndex","itemLayout","ltrRelativeOffset","createSpineItemLocator","getSpineItemPositionFromNode","offsetOfNodeInSpineItem","spineItemWidth","val","unsafePosition","pageStartY","pageStartX","rtlPageStartX","createNavigationResolver","fromOutOfBoundsSpinePosition","lastSpineItem","distanceOfLastSpineItem","maximumYOffset","positiveY","maximumX","minimumX","maximumXOffset","positiveX","boundedX","fromUnboundSpinePosition","visibleAreaRectWidth","unboundPosition","getAdjustedPositionForSpread","pageSizeWidth","getNavigationForPosition","viewportPosition","spineItemNavigationResolver","spineItemValidPosition","viewportNavigation","getNavigationForSpineItemPage","xPositionForPageIndex","readingOffset","getNodeFromSelector","selector","getSpineItemOffsetFromAnchor","getSpinePositionFromSpineItemAnchor","spineItemOffset","getNavigationForAnchor","getNavigationForUrl","validUrl","urlWithoutAnchor","getNavigationFromSpineItemPosition","navigationInSpineItem","NAMESPACE","spineItemNavigator","createSpineItemNavigator","readingPosition","triggerPercentage","triggerXPosition","triggerYPosition","midScreenPositionSafePosition","to","a","b","createNavigator","userExplicitNavigationSubject","restorationLocker","internalNavigator","navigationState$","states","Pagination","PaginationController","updatePagination$","getVisiblePagesFromViewportPosition","previousPagination","beginSpineItemIndex","endSpineItemIndex","beginSpineItem","endSpineItem","beginLastCfi","endLastCfi","shouldUpdateBeginCfi","shouldUpdateEndCfi","beginCfi","endCfi","beginNumberOfPagesInSpineItem","endNumberOfPagesInSpineItem","updateCfi$","beginPageIndexInSpineItem","endPageIndexInSpineItem","beginPageEntry","endPageEntry","computeSpreadMode","spreadMode","settingsWithDefaults","newInputSettings","ReaderSettingsManager","computedSettings","DefaultRenderer","SpineItemLayout","containerElement","renderer","isLastItem","horizontalOffset","isScreenStartItem","lastItemStartOnNewScreenInAPrepaginatedBook","edgeX","edgeY","trustableLastLayout","previousWidth","previousHeight","safeWidth","safeHeight","nextResult","layoutProcess$","rendererLayout$","minimum","maxValue","adjustedValue","SpineItem","parentElement","index","createContainerElement","rendererFactory","rendererParams","updateStateOnLoaded$","SpineItemsLoader","spineLayout","forcedOpen$","v","arrayEqual","forcedOpenIndexes","numberOfAdjacentSpineItemToPreLoad","beginMaximumIndex","endMaximumIndex","visibleIndexes","indexesToLoad","orderedSpineItem","indexes","updateMap","add","count","newCount","translateSpinePositionToRelativeViewport","absolutePosition","absoluteViewport","relativeViewport","offsetX","offsetY","ViewportSlicePosition","positionOrRect","AbsoluteViewport","RelativeViewport","getAbsolutePageIndexFromPageIndex","spineItemOrId","currentAbsolutePage","isItemVisibleByThresholdForPosition","visibleWidthOfItem","visibleHeightOfItem","threshold","visibleWidthRatioOfSpineItem","visibleHeightRatioOfSpineItem","isItemVisibleOnScreenByThresholdForPosition","widthRatioOfSpaceTakenInScreen","heightRatioOfSpaceTakenInScreen","getItemVisibilityForPosition","bottom","restrictToScreen","viewportLeft","viewportRight","viewportTop","viewportBottom","isItemVisibleEnoughOnScreen","getSpineItemFromPosition","isWithinXAxis","isWithinYAxis","getSpinePositionFromSpineItemPosition","getVisibleSpineItemsFromPosition","useAbsoluteViewport","fallbackSpineItem","spineItemsVisible","itemPosition","viewportInfo","relativeSpinePosition","visible","beginItemIndex","endItemIndex","createSpineLocator","getSpineItemPositionFromSpinePosition","getSpinePositionFromSpineItem","getSpineItemFromIframe","getSpineItemPageIndexFromNode","spineItemOrIndex","pagesVisible","spineItemPageIndex","spineItemPagePosition","spinePositionToSpineItemSpineLayout","Pages","pagesAbsolutePositions","pageSpineItemPosition","pageSpinePosition","_unused","firstVisibleNode","SpineItemsObserver","resize$","SpineLayout","spineItemsObserver","spineItemNeedsLayout$","layoutTrigger$","acc$","concatMap","verticalOffset","isVertical","layoutPosition","viewportHeight","newEdgeX","newEdgeY","Spine","spineElementUpdate$","loadSpineItems$","SpineItemsManager","toCompare","withItem","toCompareIndex","withIndex","Viewport","updatePageSize$","updateLayout$","computedSpreadMode","relativeScale","layoutSubject","destroy$","features","navigator","paginationController","load","wrapContainer","layoutOnSpreadModeChange$","layout$","subs","createReaderWithEnhancers","createInternalReader","rootEnhancer"],"mappings":"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"}