@meframe/core 0.1.0 → 0.1.1

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.
Files changed (44) hide show
  1. package/dist/cache/CacheManager.d.ts +1 -1
  2. package/dist/cache/CacheManager.d.ts.map +1 -1
  3. package/dist/cache/CacheManager.js +2 -2
  4. package/dist/cache/CacheManager.js.map +1 -1
  5. package/dist/cache/l1/AudioL1Cache.d.ts +1 -1
  6. package/dist/cache/l1/AudioL1Cache.d.ts.map +1 -1
  7. package/dist/cache/l1/AudioL1Cache.js +2 -2
  8. package/dist/cache/l1/AudioL1Cache.js.map +1 -1
  9. package/dist/controllers/PlaybackController.d.ts.map +1 -1
  10. package/dist/controllers/PlaybackController.js +1 -1
  11. package/dist/controllers/PlaybackController.js.map +1 -1
  12. package/dist/model/CompositionModel.d.ts.map +1 -1
  13. package/dist/model/CompositionModel.js +4 -5
  14. package/dist/model/CompositionModel.js.map +1 -1
  15. package/dist/model/types.d.ts +6 -0
  16. package/dist/model/types.d.ts.map +1 -1
  17. package/dist/model/types.js.map +1 -1
  18. package/dist/orchestrator/CompositionPlanner.d.ts +0 -1
  19. package/dist/orchestrator/CompositionPlanner.d.ts.map +1 -1
  20. package/dist/orchestrator/CompositionPlanner.js +4 -12
  21. package/dist/orchestrator/CompositionPlanner.js.map +1 -1
  22. package/dist/orchestrator/ExportScheduler.d.ts.map +1 -1
  23. package/dist/orchestrator/ExportScheduler.js +1 -0
  24. package/dist/orchestrator/ExportScheduler.js.map +1 -1
  25. package/dist/orchestrator/GlobalAudioSession.d.ts +1 -1
  26. package/dist/orchestrator/GlobalAudioSession.d.ts.map +1 -1
  27. package/dist/orchestrator/GlobalAudioSession.js +2 -1
  28. package/dist/orchestrator/GlobalAudioSession.js.map +1 -1
  29. package/dist/orchestrator/Orchestrator.d.ts.map +1 -1
  30. package/dist/orchestrator/Orchestrator.js +2 -7
  31. package/dist/orchestrator/Orchestrator.js.map +1 -1
  32. package/dist/stages/compose/LayerRenderer.d.ts +5 -0
  33. package/dist/stages/compose/LayerRenderer.d.ts.map +1 -1
  34. package/dist/stages/compose/LayerRenderer.js +91 -89
  35. package/dist/stages/compose/LayerRenderer.js.map +1 -1
  36. package/dist/stages/compose/instructions.d.ts +6 -6
  37. package/dist/stages/compose/instructions.d.ts.map +1 -1
  38. package/dist/stages/compose/types.d.ts +6 -0
  39. package/dist/stages/compose/types.d.ts.map +1 -1
  40. package/dist/workers/stages/compose/{video-compose.worker.B-_C-_y6.js → video-compose.worker.C8728Oi3.js} +97 -98
  41. package/dist/workers/stages/compose/video-compose.worker.C8728Oi3.js.map +1 -0
  42. package/dist/workers/worker-manifest.json +1 -1
  43. package/package.json +1 -1
  44. package/dist/workers/stages/compose/video-compose.worker.B-_C-_y6.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"video-compose.worker.B-_C-_y6.js","sources":["../../../../src/stages/compose/text-utils/text-metrics.ts","../../../../src/stages/compose/text-utils/text-wrapper.ts","../../../../src/stages/compose/text-renderers/animation-utils.ts","../../../../src/stages/compose/text-utils/locale-detector.ts","../../../../src/stages/compose/text-renderers/basic-text-renderer.ts","../../../../src/stages/compose/text-renderers/word-by-word-renderer.ts","../../../../src/stages/compose/text-renderers/character-ktv-renderer.ts","../../../../src/stages/compose/text-renderers/word-fancy-renderer.ts","../../../../src/stages/compose/LayerRenderer.ts","../../../../src/stages/compose/TransitionProcessor.ts","../../../../src/stages/compose/FilterProcessor.ts","../../../../src/stages/compose/VideoComposer.ts","../../../../src/utils/time-utils.ts","../../../../src/utils/animation-utils.ts","../../../../src/stages/compose/FrameRateConverter.ts","../../../../src/stages/compose/video-compose.worker.ts"],"sourcesContent":["export function measureTextWidth(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n text: string,\n fontSize: number,\n fontFamily: string,\n fontWeight: string | number = 400\n): number {\n ctx.save();\n ctx.font = `${fontWeight} ${fontSize}px ${fontFamily}`;\n const metrics = ctx.measureText(text);\n ctx.restore();\n return metrics.width;\n}\n\nexport function getLetterCaseText(text: string, letterCase?: 'upper' | 'lower' | 'none'): string {\n if (letterCase === 'upper') {\n return text.toUpperCase();\n }\n if (letterCase === 'lower') {\n return text.toLowerCase();\n }\n return text;\n}\n","import { measureTextWidth } from './text-metrics';\n\nfunction findAllBreakPoints(text: string): number[] {\n const breakPoints = [0];\n const chars = Array.from(text);\n\n for (let i = 1; i < chars.length - 1; i++) {\n if (/[、。!?,,!?;:]/.test(chars[i]!)) {\n breakPoints.push(i + 1);\n } else if (\n /[\\u3040-\\u309F\\u30A0-\\u30FF\\u4E00-\\u9FAF]/.test(chars[i]!) &&\n /[\\u3040-\\u309F\\u30A0-\\u30FF\\u4E00-\\u9FAF]/.test(chars[i + 1]!)\n ) {\n breakPoints.push(i + 1);\n } else if (/[\\s\\-–—,.!?;:]/.test(chars[i]!)) {\n breakPoints.push(i + 1);\n } else if (/\\s/.test(chars[i]!) && /[a-zA-Z]/.test(chars[i + 1]!)) {\n breakPoints.push(i + 1);\n }\n }\n\n breakPoints.push(chars.length);\n return breakPoints;\n}\n\nfunction evaluateBalance(\n lines: string[],\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n fontSize: number,\n fontFamily: string,\n fontWeight: string | number\n): number {\n if (lines.length <= 1) return 0;\n const lengths = lines.map((line) =>\n measureTextWidth(ctx, line, fontSize, fontFamily, fontWeight)\n );\n const avgLength = lengths.reduce((a, b) => a + b, 0) / lengths.length;\n return lengths.reduce((sum, len) => sum + Math.abs(len - avgLength), 0);\n}\n\nfunction tryBreakPointsForMultipleLines(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n text: string,\n start: number,\n remainingLines: number,\n currentLines: string[],\n maxWidth: number,\n fontSize: number,\n fontFamily: string,\n fontWeight: string | number,\n breakPoints: number[]\n): {\n bestLines: string[];\n bestBalance: number;\n} {\n let bestLines: string[] = [];\n let bestBalance = Infinity;\n\n if (remainingLines === 1) {\n const lastLine = text.slice(start).trim();\n const lastLineWidth = measureTextWidth(ctx, lastLine, fontSize, fontFamily, fontWeight);\n\n if (lastLineWidth <= maxWidth) {\n const allLines = [...currentLines, lastLine];\n const balance = evaluateBalance(allLines, ctx, fontSize, fontFamily, fontWeight);\n\n if (balance < bestBalance) {\n bestBalance = balance;\n bestLines = allLines;\n }\n } else {\n const words = lastLine.split(/\\s+/);\n let currentLine = '';\n let tempLines = [...currentLines];\n\n for (const word of words) {\n const testLine = currentLine ? `${currentLine} ${word}` : word;\n const lineWidth = measureTextWidth(ctx, testLine, fontSize, fontFamily, fontWeight);\n\n if (lineWidth <= maxWidth) {\n currentLine = testLine;\n } else {\n if (currentLine) {\n tempLines.push(currentLine);\n currentLine = word;\n } else {\n tempLines.push(word);\n currentLine = '';\n }\n }\n }\n\n if (currentLine) {\n tempLines.push(currentLine);\n }\n\n const balance = evaluateBalance(tempLines, ctx, fontSize, fontFamily, fontWeight);\n if (balance < bestBalance) {\n bestBalance = balance;\n bestLines = tempLines;\n }\n }\n return { bestLines, bestBalance };\n }\n\n let foundValidBreak = false;\n\n for (let i = 0; i < breakPoints.length; i++) {\n const bp = breakPoints[i]!;\n if (bp <= start || bp >= text.length) continue;\n\n const line = text.slice(start, bp).trim();\n const lineWidth = measureTextWidth(ctx, line, fontSize, fontFamily, fontWeight);\n\n if (lineWidth <= maxWidth) {\n foundValidBreak = true;\n const result = tryBreakPointsForMultipleLines(\n ctx,\n text,\n bp,\n remainingLines - 1,\n [...currentLines, line],\n maxWidth,\n fontSize,\n fontFamily,\n fontWeight,\n breakPoints\n );\n if (result.bestBalance < bestBalance) {\n bestBalance = result.bestBalance;\n bestLines = result.bestLines;\n }\n }\n }\n\n if (!foundValidBreak) {\n const textPortion = text.slice(start);\n const words = textPortion.split(/\\s+/);\n let currentLine = '';\n let tempLines = [...currentLines];\n\n for (const word of words) {\n const testLine = currentLine ? `${currentLine} ${word}` : word;\n const lineWidth = measureTextWidth(ctx, testLine, fontSize, fontFamily, fontWeight);\n\n if (lineWidth <= maxWidth) {\n currentLine = testLine;\n } else {\n if (currentLine) {\n tempLines.push(currentLine);\n currentLine = word;\n } else {\n tempLines.push(word);\n }\n }\n }\n\n if (currentLine) {\n tempLines.push(currentLine);\n }\n\n bestLines = tempLines;\n }\n\n return { bestLines, bestBalance };\n}\n\nexport function wrapText(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n text: string,\n maxWidth: number,\n fontSize: number,\n fontFamily: string,\n fontWeight: string | number = 400\n): string[] {\n const textWidth = measureTextWidth(ctx, text, fontSize, fontFamily, fontWeight);\n if (textWidth <= maxWidth) {\n return [text];\n }\n\n const estimatedLines = Math.ceil(textWidth / maxWidth);\n const breakPoints = findAllBreakPoints(text);\n\n const { bestLines } = tryBreakPointsForMultipleLines(\n ctx,\n text,\n 0,\n estimatedLines,\n [],\n maxWidth,\n fontSize,\n fontFamily,\n fontWeight,\n breakPoints\n );\n\n return bestLines.length > 0 ? bestLines : [text];\n}\n\nexport function formLinesWithWords(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n words: string[],\n maxWidth: number,\n fontSize: number,\n needsSpace: boolean,\n fontFamily: string,\n fontWeight: string | number = 400\n): string[] {\n const result: string[] = [];\n let accumulatedWidth = 0;\n const spaceWidth = measureTextWidth(ctx, ' ', fontSize, fontFamily, fontWeight);\n let currentLine = '';\n\n for (const word of words) {\n let wordWidth = measureTextWidth(ctx, word, fontSize, fontFamily, fontWeight);\n if (needsSpace) {\n wordWidth += spaceWidth;\n }\n if (wordWidth + accumulatedWidth <= maxWidth) {\n currentLine += word + (needsSpace ? ' ' : '');\n accumulatedWidth += wordWidth;\n } else {\n if (currentLine) {\n result.push(currentLine);\n }\n currentLine = word + (needsSpace ? ' ' : '');\n accumulatedWidth = wordWidth;\n }\n }\n if (currentLine !== '') {\n result.push(currentLine);\n }\n return result;\n}\n\nexport function formEvenLinesWithWords(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n words: string[],\n maxWidth: number,\n fontSize: number,\n needsSpace: boolean,\n fontFamily: string,\n fontWeight: string | number = 400\n): string[] {\n let minWidth = maxWidth / 2;\n for (const word of words) {\n const wordWidth = measureTextWidth(ctx, word, fontSize, fontFamily, fontWeight);\n if (wordWidth > minWidth) {\n minWidth = wordWidth;\n }\n }\n\n const leastLineNum = formLinesWithWords(\n ctx,\n words,\n maxWidth,\n fontSize,\n needsSpace,\n fontFamily,\n fontWeight\n ).length;\n\n let bestDelta = maxWidth;\n let bestWidth = minWidth;\n for (let width = maxWidth; width >= minWidth; width -= 1) {\n const lines = formLinesWithWords(\n ctx,\n words,\n width,\n fontSize,\n needsSpace,\n fontFamily,\n fontWeight\n );\n if (lines.length > leastLineNum) {\n break;\n }\n let minLineWidth = Infinity;\n let maxLineWidth = 0;\n for (const line of lines) {\n const lineWidth = measureTextWidth(ctx, line, fontSize, fontFamily, fontWeight);\n if (lineWidth < minLineWidth) {\n minLineWidth = lineWidth;\n }\n if (lineWidth > maxLineWidth) {\n maxLineWidth = lineWidth;\n }\n }\n const delta = maxLineWidth - minLineWidth;\n if (delta < bestDelta) {\n bestDelta = delta;\n bestWidth = width;\n }\n }\n\n return formLinesWithWords(ctx, words, bestWidth, fontSize, needsSpace, fontFamily, fontWeight);\n}\n","export interface SpringConfig {\n damping: number;\n mass: number;\n stiffness: number;\n overshootClamping?: boolean;\n}\n\nexport function springEasing(frame: number, config: SpringConfig): number {\n const { damping, mass, stiffness, overshootClamping = false } = config;\n\n if (frame <= 0) return 0;\n\n const zeta = damping / (2 * Math.sqrt(mass * stiffness));\n const omega = Math.sqrt(stiffness / mass);\n const t = frame / 60;\n\n let value: number;\n\n if (zeta < 1) {\n const omegaD = omega * Math.sqrt(1 - zeta * zeta);\n const A = 1;\n const B = (zeta * omega) / omegaD;\n value = 1 - Math.exp(-zeta * omega * t) * (A * Math.cos(omegaD * t) + B * Math.sin(omegaD * t));\n } else if (zeta === 1) {\n value = 1 - Math.exp(-omega * t) * (1 + omega * t);\n } else {\n const r1 = -omega * (zeta - Math.sqrt(zeta * zeta - 1));\n const r2 = -omega * (zeta + Math.sqrt(zeta * zeta - 1));\n const A = r2 / (r2 - r1);\n const B = 1 - A;\n value = 1 - A * Math.exp(r1 * t) - B * Math.exp(r2 * t);\n }\n\n if (overshootClamping && value > 1) {\n return 1;\n }\n\n return Math.max(0, value);\n}\n\nexport function interpolate(\n value: number,\n inputRange: [number, number],\n outputRange: [number, number],\n options?: {\n extrapolateLeft?: 'clamp' | 'extend';\n extrapolateRight?: 'clamp' | 'extend';\n }\n): number {\n const { extrapolateLeft = 'extend', extrapolateRight = 'extend' } = options || {};\n\n const [inputMin, inputMax] = inputRange;\n const [outputMin, outputMax] = outputRange;\n\n if (value < inputMin) {\n if (extrapolateLeft === 'clamp') {\n return outputMin;\n }\n }\n\n if (value > inputMax) {\n if (extrapolateRight === 'clamp') {\n return outputMax;\n }\n }\n\n const inputDelta = inputMax - inputMin;\n if (inputDelta === 0) {\n return outputMin;\n }\n\n const progress = (value - inputMin) / inputDelta;\n const outputDelta = outputMax - outputMin;\n\n return outputMin + progress * outputDelta;\n}\n\nfunction parseRgb(color: string): { r: number; g: number; b: number } | null {\n const match = color.match(/rgb\\((\\d+),\\s*(\\d+),\\s*(\\d+)\\)/);\n if (match) {\n return {\n r: parseInt(match[1]!, 10),\n g: parseInt(match[2]!, 10),\n b: parseInt(match[3]!, 10),\n };\n }\n return null;\n}\n\nexport function interpolateColor(color1: string, color2: string, progress: number): string {\n const rgb1 = parseRgb(color1);\n const rgb2 = parseRgb(color2);\n\n if (!rgb1 || !rgb2) {\n return color1;\n }\n\n const r = Math.round(interpolate(progress, [0, 1], [rgb1.r, rgb2.r]));\n const g = Math.round(interpolate(progress, [0, 1], [rgb1.g, rgb2.g]));\n const b = Math.round(interpolate(progress, [0, 1], [rgb1.b, rgb2.b]));\n\n return `rgb(${r}, ${g}, ${b})`;\n}\n\nexport type EasingFunction = (t: number) => number;\n\nexport const easingFunctions: Record<string, EasingFunction> = {\n linear: (t) => t,\n 'ease-in': (t) => t * t,\n 'ease-out': (t) => t * (2 - t),\n 'ease-in-out': (t) => (t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t),\n};\n\nexport function calculateProgress(\n frame: number,\n startFrame: number,\n duration: number,\n easing: string = 'linear'\n): number {\n if (frame < startFrame) return 0;\n if (frame >= startFrame + duration) return 1;\n\n const rawProgress = (frame - startFrame) / duration;\n const easingFn = easingFunctions[easing] || easingFunctions.linear;\n return easingFn!(rawProgress);\n}\n","import type { LocaleCode } from '../font-system/types';\n\nconst CJK_REGEX = /[\\u4e00-\\u9fff\\u3040-\\u309f\\u30a0-\\u30ff\\u3400-\\u4dbf\\uac00-\\ud7af]/g;\n\nexport function needsSpaceBetweenWords(locale: LocaleCode | string, text?: string): boolean {\n if (text) {\n const cjkMatches = text.match(CJK_REGEX);\n const cjkCount = cjkMatches ? cjkMatches.length : 0;\n\n if (cjkCount > 0 && cjkCount / text.length >= 0.6) {\n return false;\n }\n return true;\n }\n\n return !['zh-CN', 'ja-JP', 'ko-KR'].includes(locale);\n}\n\nexport function detectLocaleFromText(text: string): LocaleCode {\n const cjkMatches = text.match(CJK_REGEX);\n const cjkCount = cjkMatches ? cjkMatches.length : 0;\n\n if (cjkCount > 0 && cjkCount / text.length >= 0.6) {\n const chineseCount = (text.match(/[\\u4e00-\\u9fff]/g) || []).length;\n const japaneseCount = (text.match(/[\\u3040-\\u309f\\u30a0-\\u30ff]/g) || []).length;\n const koreanCount = (text.match(/[\\uac00-\\ud7af]/g) || []).length;\n\n if (chineseCount >= japaneseCount && chineseCount >= koreanCount) {\n return 'zh-CN';\n }\n if (japaneseCount >= koreanCount) {\n return 'ja-JP';\n }\n return 'ko-KR';\n }\n\n const arabicCount = (text.match(/[\\u0600-\\u06FF]/g) || []).length;\n if (arabicCount > 0 && arabicCount / text.length >= 0.5) {\n return 'ar-SA';\n }\n\n return 'en-US';\n}\n","import type { TextLayer } from '../types';\nimport { wrapText, formEvenLinesWithWords } from '../text-utils/text-wrapper';\nimport { getLetterCaseText } from '../text-utils/text-metrics';\nimport { springEasing, interpolate } from './animation-utils';\nimport { needsSpaceBetweenWords } from '../text-utils/locale-detector';\n\nfunction calculateYPosition(\n canvasHeight: number,\n totalHeight: number,\n globalPosition?: {\n position?: 'absolute';\n top?: string;\n bottom?: string;\n left?: string;\n right?: string;\n display?: string;\n alignItems?: string;\n justifyContent?: string;\n }\n): number {\n if (!globalPosition) {\n return canvasHeight / 2 - totalHeight / 2;\n }\n\n // Handle percentage-based positioning\n if (globalPosition.top) {\n const topPercent = parseFloat(globalPosition.top) / 100;\n return canvasHeight * topPercent;\n }\n\n if (globalPosition.bottom) {\n const bottomPercent = parseFloat(globalPosition.bottom) / 100;\n return canvasHeight * (1 - bottomPercent) - totalHeight;\n }\n\n // Handle center alignment\n if (globalPosition.justifyContent === 'center' || globalPosition.alignItems === 'center') {\n return canvasHeight / 2 - totalHeight / 2;\n }\n\n // Default to center\n return canvasHeight / 2 - totalHeight / 2;\n}\n\nexport function renderBasicText(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n layer: TextLayer,\n canvasWidth: number,\n canvasHeight: number,\n _relativeFrame: number\n): void {\n const fontConfig = layer.fontConfig?.textStyle;\n if (!fontConfig) return;\n\n const fontSize = fontConfig.fontSize;\n const fontFamily = fontConfig.fontFamily;\n const fontWeight = fontConfig.fontWeight;\n const fill = fontConfig.fill;\n const stroke = fontConfig.stroke;\n const strokeWidth = fontConfig.strokeWidth || 0;\n const lineHeight = fontConfig.lineHeight || 1.2;\n\n const maxWidth = canvasWidth * 0.64;\n const text = getLetterCaseText(layer.text, layer.letterCase);\n\n let lines: string[];\n if (layer.wordTimings && layer.wordTimings.length > 0) {\n const needsSpace = needsSpaceBetweenWords(layer.localeCode || 'en-US', text);\n const words = text.split(needsSpace ? /\\s+/ : '');\n lines = formEvenLinesWithWords(\n ctx,\n words,\n maxWidth,\n fontSize,\n needsSpace,\n fontFamily,\n fontWeight\n );\n } else {\n lines = wrapText(ctx, text, maxWidth, fontSize, fontFamily, fontWeight);\n }\n\n ctx.save();\n ctx.font = `${fontWeight} ${fontSize}px ${fontFamily}`;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.lineJoin = 'round';\n ctx.lineCap = 'round';\n\n const totalHeight = lines.length * fontSize * lineHeight;\n const startY = calculateYPosition(canvasHeight, totalHeight, layer.fontConfig?.globalPosition);\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!;\n const y = startY + i * fontSize * lineHeight + fontSize / 2;\n\n if (stroke && strokeWidth > 0) {\n ctx.strokeStyle = stroke;\n ctx.lineWidth = strokeWidth;\n ctx.strokeText(line, canvasWidth / 2, y);\n }\n ctx.fillStyle = fill;\n ctx.fillText(line, canvasWidth / 2, y);\n }\n\n ctx.restore();\n}\n\nexport function renderTextWithEntrance(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n layer: TextLayer,\n canvasWidth: number,\n canvasHeight: number,\n relativeFrame: number\n): void {\n const fontConfig = layer.fontConfig?.textStyle;\n if (!fontConfig) return;\n\n const entrance = springEasing(relativeFrame, {\n damping: 200,\n mass: 1,\n stiffness: 300,\n });\n\n const opacity = interpolate(entrance, [0, 1], [0, 1]);\n const scale = interpolate(entrance, [0, 1], [0.9, 1]);\n\n ctx.save();\n ctx.globalAlpha = opacity;\n ctx.translate(canvasWidth / 2, canvasHeight / 2);\n ctx.scale(scale, scale);\n ctx.translate(-canvasWidth / 2, -canvasHeight / 2);\n\n renderBasicText(ctx, layer, canvasWidth, canvasHeight, relativeFrame);\n\n ctx.restore();\n}\n","import type { TextLayer } from '../types';\nimport { formEvenLinesWithWords } from '../text-utils/text-wrapper';\nimport { getLetterCaseText, measureTextWidth } from '../text-utils/text-metrics';\nimport { interpolate, interpolateColor } from './animation-utils';\nimport { needsSpaceBetweenWords } from '../text-utils/locale-detector';\n\ninterface WordPosition {\n text: string;\n x: number;\n y: number;\n lineIndex: number;\n wordIndex: number;\n timing?: { startFrame: number; endFrame: number };\n}\n\nfunction usToFrame(us: number, fps: number): number {\n return Math.floor(us / (1000000 / fps));\n}\n\nfunction calculateYPosition(\n canvasHeight: number,\n totalHeight: number,\n globalPosition?: {\n position?: 'absolute';\n top?: string;\n bottom?: string;\n left?: string;\n right?: string;\n display?: string;\n alignItems?: string;\n justifyContent?: string;\n }\n): number {\n if (!globalPosition) {\n return canvasHeight / 2 - totalHeight / 2;\n }\n\n if (globalPosition.top) {\n const topPercent = parseFloat(globalPosition.top) / 100;\n return canvasHeight * topPercent;\n }\n\n if (globalPosition.bottom) {\n const bottomPercent = parseFloat(globalPosition.bottom) / 100;\n return canvasHeight * (1 - bottomPercent) - totalHeight;\n }\n\n if (globalPosition.justifyContent === 'center' || globalPosition.alignItems === 'center') {\n return canvasHeight / 2 - totalHeight / 2;\n }\n\n return canvasHeight / 2 - totalHeight / 2;\n}\n\nexport function renderWordByWord(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n layer: TextLayer,\n canvasWidth: number,\n canvasHeight: number,\n relativeFrame: number,\n fps: number = 30\n): void {\n const fontConfig = layer.fontConfig?.textStyle;\n if (!fontConfig) return;\n\n const fontSize = fontConfig.fontSize;\n const fontFamily = fontConfig.fontFamily;\n const fontWeight = fontConfig.fontWeight;\n const fill = fontConfig.fill;\n const stroke = fontConfig.stroke;\n const strokeWidth = fontConfig.strokeWidth || 0;\n const lineHeight = fontConfig.lineHeight || 1.2;\n\n const highlightFill = layer.animation?.highlightTextStyle?.fill || 'rgb(255, 215, 0)';\n const highlightStroke = layer.animation?.highlightTextStyle?.stroke || stroke;\n\n const maxWidth = canvasWidth * 0.64;\n const text = getLetterCaseText(layer.text, layer.letterCase);\n const needsSpace = needsSpaceBetweenWords(layer.localeCode || 'en-US', text);\n const words = text.split(needsSpace ? /\\s+/ : '');\n const lines = formEvenLinesWithWords(\n ctx,\n words,\n maxWidth,\n fontSize,\n needsSpace,\n fontFamily,\n fontWeight\n );\n\n const wordPositions: WordPosition[] = [];\n let wordIndex = 0;\n\n const totalHeight = lines.length * fontSize * lineHeight;\n const startY = calculateYPosition(canvasHeight, totalHeight, layer.fontConfig?.globalPosition);\n\n for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {\n const line = lines[lineIndex]!;\n const lineWords = line.split(needsSpace ? /\\s+/ : '');\n const y = startY + lineIndex * fontSize * lineHeight + fontSize / 2;\n\n const lineWidth = measureTextWidth(ctx, line, fontSize, fontFamily, fontWeight);\n let currentX = canvasWidth / 2 - lineWidth / 2;\n\n for (const word of lineWords) {\n const wordWidth = measureTextWidth(ctx, word, fontSize, fontFamily, fontWeight);\n const wordTimingUs = layer.wordTimings?.[wordIndex];\n\n const wordTiming = wordTimingUs\n ? {\n startFrame: usToFrame(wordTimingUs.startUs, fps),\n endFrame: usToFrame(wordTimingUs.endUs, fps),\n }\n : undefined;\n\n wordPositions.push({\n text: word,\n x: currentX + wordWidth / 2,\n y,\n lineIndex,\n wordIndex,\n timing: wordTiming,\n });\n\n currentX +=\n wordWidth + (needsSpace ? measureTextWidth(ctx, ' ', fontSize, fontFamily, fontWeight) : 0);\n wordIndex++;\n }\n }\n\n ctx.save();\n ctx.font = `${fontWeight} ${fontSize}px ${fontFamily}`;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.lineJoin = 'round';\n ctx.lineCap = 'round';\n\n for (const wordPos of wordPositions) {\n let currentFill = fill;\n let currentStroke = stroke;\n\n if (wordPos.timing) {\n const { startFrame, endFrame } = wordPos.timing;\n\n if (relativeFrame >= startFrame && relativeFrame <= endFrame) {\n const transitionProgressIn = interpolate(\n relativeFrame,\n [startFrame, startFrame + 3],\n [0, 1],\n {\n extrapolateLeft: 'clamp',\n extrapolateRight: 'clamp',\n }\n );\n\n currentFill = interpolateColor(fill, highlightFill, transitionProgressIn);\n if (stroke && highlightStroke) {\n currentStroke = interpolateColor(stroke, highlightStroke, transitionProgressIn);\n }\n } else if (relativeFrame > endFrame) {\n const transitionProgressOut = interpolate(relativeFrame, [endFrame, endFrame + 3], [1, 0], {\n extrapolateLeft: 'clamp',\n extrapolateRight: 'clamp',\n });\n\n currentFill = interpolateColor(fill, highlightFill, transitionProgressOut);\n if (stroke && highlightStroke) {\n currentStroke = interpolateColor(stroke, highlightStroke, transitionProgressOut);\n }\n }\n }\n\n if (currentStroke && strokeWidth > 0) {\n ctx.strokeStyle = currentStroke;\n ctx.lineWidth = strokeWidth;\n ctx.strokeText(wordPos.text, wordPos.x, wordPos.y);\n }\n ctx.fillStyle = currentFill;\n ctx.fillText(wordPos.text, wordPos.x, wordPos.y);\n }\n\n ctx.restore();\n}\n","import type { TextLayer } from '../types';\nimport { wrapText } from '../text-utils/text-wrapper';\nimport { getLetterCaseText, measureTextWidth } from '../text-utils/text-metrics';\nimport { needsSpaceBetweenWords } from '../text-utils/locale-detector';\n\ninterface CharacterTiming {\n char: string;\n index: number;\n startFrame: number;\n}\n\nfunction usToFrame(us: number, fps: number): number {\n return Math.floor(us / (1000000 / fps));\n}\n\nfunction calculateYPosition(\n canvasHeight: number,\n totalHeight: number,\n globalPosition?: {\n position?: 'absolute';\n top?: string;\n bottom?: string;\n left?: string;\n right?: string;\n display?: string;\n alignItems?: string;\n justifyContent?: string;\n }\n): number {\n if (!globalPosition) {\n return canvasHeight / 2 - totalHeight / 2;\n }\n\n if (globalPosition.top) {\n const topPercent = parseFloat(globalPosition.top) / 100;\n return canvasHeight * topPercent;\n }\n\n if (globalPosition.bottom) {\n const bottomPercent = parseFloat(globalPosition.bottom) / 100;\n return canvasHeight * (1 - bottomPercent) - totalHeight;\n }\n\n if (globalPosition.justifyContent === 'center' || globalPosition.alignItems === 'center') {\n return canvasHeight / 2 - totalHeight / 2;\n }\n\n return canvasHeight / 2 - totalHeight / 2;\n}\n\nexport function renderCharacterKTV(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n layer: TextLayer,\n canvasWidth: number,\n canvasHeight: number,\n relativeFrame: number,\n fps: number = 30\n): void {\n const fontConfig = layer.fontConfig?.textStyle;\n if (!fontConfig) return;\n\n const fontSize = fontConfig.fontSize;\n const fontFamily = fontConfig.fontFamily;\n const fontWeight = fontConfig.fontWeight;\n const baseFill = fontConfig.fill;\n const stroke = fontConfig.stroke;\n const strokeWidth = fontConfig.strokeWidth || 0;\n const lineHeight = fontConfig.lineHeight || 1.2;\n\n const highlightFill = layer.animation?.highlightTextStyle?.fill || 'rgb(255, 215, 0)';\n const glowColor = layer.animation?.glowColor || '#ffffff';\n const glowIntensity = layer.animation?.glowIntensity || 3;\n const transitionFrames = layer.animation?.transitionFrames || 10;\n\n const maxWidth = canvasWidth * 0.9;\n const text = getLetterCaseText(layer.text, layer.letterCase);\n const needsSpace = needsSpaceBetweenWords(layer.localeCode || 'en-US', text);\n const characterTimings: CharacterTiming[] = [];\n\n if (layer.wordTimings && layer.wordTimings.length > 0) {\n let charIndex = 0;\n\n for (let wordIndex = 0; wordIndex < layer.wordTimings.length; wordIndex++) {\n const word = layer.wordTimings[wordIndex]!;\n const wordChars = word.text.split('');\n const wordStartFrame = usToFrame(word.startUs, fps);\n const wordEndFrame = usToFrame(word.endUs, fps);\n const framesPerChar =\n wordChars.length > 0 ? (wordEndFrame - wordStartFrame) / wordChars.length : 0;\n\n for (let i = 0; i < wordChars.length; i++) {\n const charStartFrame = Math.floor(wordStartFrame + i * framesPerChar);\n characterTimings.push({\n char: wordChars[i]!,\n index: charIndex,\n startFrame: charStartFrame,\n });\n charIndex++;\n }\n\n if (needsSpace && wordIndex < layer.wordTimings.length - 1) {\n const nextWord = layer.wordTimings[wordIndex + 1];\n const nextWordFirstChar = nextWord?.text?.[0] || '';\n const isPunctuation = /[.,!?;:)]/.test(nextWordFirstChar);\n\n if (!isPunctuation) {\n const spaceStartFrame = characterTimings[characterTimings.length - 1]?.startFrame || 0;\n characterTimings.push({\n char: ' ',\n index: charIndex,\n startFrame: spaceStartFrame,\n });\n charIndex++;\n }\n }\n }\n } else {\n const totalFrames = 100;\n const chars = text.split('');\n const framesPerChar = chars.length > 0 ? totalFrames / chars.length : 0;\n\n for (let i = 0; i < chars.length; i++) {\n characterTimings.push({\n char: chars[i]!,\n index: i,\n startFrame: Math.floor(i * framesPerChar),\n });\n }\n }\n\n const fullText = characterTimings.map((ct) => ct.char).join('');\n const fullTextLines = wrapText(ctx, fullText, maxWidth, fontSize, fontFamily, fontWeight);\n\n ctx.save();\n ctx.font = `${fontWeight} ${fontSize}px ${fontFamily}`;\n ctx.textAlign = 'left';\n ctx.textBaseline = 'middle';\n ctx.lineJoin = 'round';\n ctx.lineCap = 'round';\n\n const totalHeight = fullTextLines.length * fontSize * lineHeight;\n const startY = calculateYPosition(canvasHeight, totalHeight, layer.fontConfig?.globalPosition);\n\n let charIndexInText = 0;\n\n for (let lineIndex = 0; lineIndex < fullTextLines.length; lineIndex++) {\n const line = fullTextLines[lineIndex]!;\n const y = startY + lineIndex * fontSize * lineHeight + fontSize / 2;\n const lineWidth = measureTextWidth(ctx, line, fontSize, fontFamily, fontWeight);\n let currentX = canvasWidth / 2 - lineWidth / 2;\n\n for (let i = 0; i < line.length; i++) {\n const char = line[i]!;\n const timing = characterTimings[charIndexInText];\n\n if (timing) {\n const hasScanned = relativeFrame >= timing.startFrame;\n const isCurrentlySinging =\n hasScanned && relativeFrame < timing.startFrame + transitionFrames;\n\n ctx.fillStyle = hasScanned ? highlightFill : baseFill;\n\n if (isCurrentlySinging) {\n ctx.shadowColor = glowColor;\n ctx.shadowBlur = glowIntensity * 10;\n } else {\n ctx.shadowBlur = 0;\n }\n\n if (stroke && strokeWidth > 0) {\n ctx.strokeStyle = stroke;\n ctx.lineWidth = strokeWidth;\n ctx.strokeText(char, currentX, y);\n }\n ctx.fillText(char, currentX, y);\n ctx.shadowBlur = 0;\n }\n\n currentX += measureTextWidth(ctx, char, fontSize, fontFamily, fontWeight);\n charIndexInText++;\n }\n }\n\n ctx.restore();\n}\n","import type { TextLayer } from '../types';\nimport { formEvenLinesWithWords } from '../text-utils/text-wrapper';\nimport { getLetterCaseText, measureTextWidth } from '../text-utils/text-metrics';\nimport { springEasing, interpolate } from './animation-utils';\nimport { needsSpaceBetweenWords } from '../text-utils/locale-detector';\n\ninterface WordPosition {\n text: string;\n x: number;\n y: number;\n width: number;\n lineIndex: number;\n wordIndex: number;\n timing?: { startFrame: number; endFrame: number };\n}\n\nfunction usToFrame(us: number, fps: number): number {\n return Math.floor(us / (1000000 / fps));\n}\n\nfunction calculateYPosition(\n canvasHeight: number,\n totalHeight: number,\n globalPosition?: {\n position?: 'absolute';\n top?: string;\n bottom?: string;\n left?: string;\n right?: string;\n display?: string;\n alignItems?: string;\n justifyContent?: string;\n }\n): number {\n if (!globalPosition) {\n return canvasHeight / 2 - totalHeight / 2;\n }\n\n if (globalPosition.top) {\n const topPercent = parseFloat(globalPosition.top) / 100;\n return canvasHeight * topPercent;\n }\n\n if (globalPosition.bottom) {\n const bottomPercent = parseFloat(globalPosition.bottom) / 100;\n return canvasHeight * (1 - bottomPercent) - totalHeight;\n }\n\n if (globalPosition.justifyContent === 'center' || globalPosition.alignItems === 'center') {\n return canvasHeight / 2 - totalHeight / 2;\n }\n\n return canvasHeight / 2 - totalHeight / 2;\n}\n\nexport function renderWordByWordFancy(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n layer: TextLayer,\n canvasWidth: number,\n canvasHeight: number,\n relativeFrame: number,\n fps: number = 30\n): void {\n const fontConfig = layer.fontConfig?.textStyle;\n if (!fontConfig) return;\n\n const fontSize = fontConfig.fontSize;\n const fontFamily = fontConfig.fontFamily;\n const fontWeight = fontConfig.fontWeight;\n const fill = fontConfig.fill;\n const stroke = fontConfig.stroke;\n const strokeWidth = fontConfig.strokeWidth || 0;\n const lineHeight = fontConfig.lineHeight || 1.2;\n\n const highlightBackgroundColor = layer.animation?.highlightColor || 'rgb(255, 215, 0)';\n\n const maxWidth = canvasWidth * 0.64;\n const text = getLetterCaseText(layer.text, layer.letterCase);\n const needsSpace = needsSpaceBetweenWords(layer.localeCode || 'en-US', text);\n const words = text.split(needsSpace ? /\\s+/ : '');\n const lines = formEvenLinesWithWords(\n ctx,\n words,\n maxWidth,\n fontSize,\n needsSpace,\n fontFamily,\n fontWeight\n );\n\n const wordPositions: WordPosition[] = [];\n let wordIndex = 0;\n\n const totalHeight = lines.length * fontSize * lineHeight;\n const startY = calculateYPosition(canvasHeight, totalHeight, layer.fontConfig?.globalPosition);\n\n for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {\n const line = lines[lineIndex]!;\n const lineWords = line.split(needsSpace ? /\\s+/ : '');\n const y = startY + lineIndex * fontSize * lineHeight + fontSize / 2;\n\n const lineWidth = measureTextWidth(ctx, line, fontSize, fontFamily, fontWeight);\n let currentX = canvasWidth / 2 - lineWidth / 2;\n\n for (const word of lineWords) {\n const wordWidth = measureTextWidth(ctx, word, fontSize, fontFamily, fontWeight);\n const wordTimingUs = layer.wordTimings?.[wordIndex];\n\n const wordTiming = wordTimingUs\n ? {\n startFrame: usToFrame(wordTimingUs.startUs, fps),\n endFrame: usToFrame(wordTimingUs.endUs, fps),\n }\n : undefined;\n\n wordPositions.push({\n text: word,\n x: currentX + wordWidth / 2,\n y,\n width: wordWidth,\n lineIndex,\n wordIndex,\n timing: wordTiming,\n });\n\n currentX +=\n wordWidth + (needsSpace ? measureTextWidth(ctx, ' ', fontSize, fontFamily, fontWeight) : 0);\n wordIndex++;\n }\n }\n\n ctx.save();\n ctx.font = `${fontWeight} ${fontSize}px ${fontFamily}`;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.lineJoin = 'round';\n ctx.lineCap = 'round';\n\n for (const wordPos of wordPositions) {\n let backgroundOpacity = 0;\n let backgroundScale = 0.8;\n\n if (wordPos.timing) {\n const { startFrame, endFrame } = wordPos.timing;\n const preStartFrames = 3;\n const isActive = relativeFrame >= startFrame && relativeFrame <= endFrame;\n\n if (isActive) {\n const scaleSpringIn = springEasing(relativeFrame - (startFrame - preStartFrames), {\n damping: 6,\n mass: 0.35,\n stiffness: 200,\n overshootClamping: false,\n });\n\n const inProgress = interpolate(relativeFrame, [startFrame, startFrame + 1], [0, 1], {\n extrapolateLeft: 'clamp',\n extrapolateRight: 'clamp',\n });\n\n backgroundOpacity = 0.9 * inProgress;\n backgroundScale = 0.8 + scaleSpringIn * 0.45;\n } else if (relativeFrame > endFrame) {\n backgroundOpacity = 0;\n backgroundScale = 0.8;\n }\n\n if (backgroundOpacity > 0) {\n const padding = 8;\n const bgWidth = (wordPos.width + padding * 2) * backgroundScale;\n const bgHeight = (fontSize + padding) * backgroundScale;\n\n ctx.save();\n ctx.globalAlpha = backgroundOpacity;\n ctx.fillStyle = highlightBackgroundColor;\n ctx.beginPath();\n ctx.roundRect(wordPos.x - bgWidth / 2, wordPos.y - bgHeight / 2, bgWidth, bgHeight, 8);\n ctx.fill();\n ctx.restore();\n }\n }\n\n if (stroke && strokeWidth > 0) {\n ctx.strokeStyle = stroke;\n ctx.lineWidth = strokeWidth;\n ctx.strokeText(wordPos.text, wordPos.x, wordPos.y);\n }\n ctx.fillStyle = fill;\n ctx.fillText(wordPos.text, wordPos.x, wordPos.y);\n }\n\n ctx.restore();\n}\n","import type { Layer, VideoLayer, ImageLayer, TextLayer, Transform2D, MaskConfig } from './types';\nimport { renderBasicText, renderTextWithEntrance } from './text-renderers/basic-text-renderer';\nimport { renderWordByWord } from './text-renderers/word-by-word-renderer';\nimport { renderCharacterKTV } from './text-renderers/character-ktv-renderer';\nimport { renderWordByWordFancy } from './text-renderers/word-fancy-renderer';\n\n/**\n * LayerRenderer - Handles rendering of individual layers\n * Single responsibility: Draw a single layer to the canvas context\n */\nexport class LayerRenderer {\n private ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D;\n private width: number;\n private height: number;\n private currentFrame: number = 0;\n private fps: number = 30;\n private readonly FILL_THRESHOLD = 0.9;\n\n constructor(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n width: number,\n height: number,\n fps: number = 30\n ) {\n this.ctx = ctx;\n this.width = width;\n this.height = height;\n this.fps = fps;\n this.ensureHighQualityRendering();\n }\n\n setCurrentFrame(frame: number): void {\n this.currentFrame = frame;\n }\n\n private ensureHighQualityRendering(): void {\n this.ctx.imageSmoothingEnabled = true;\n this.ctx.imageSmoothingQuality = 'high';\n }\n\n /**\n * Render a single layer with all its properties\n */\n renderLayer(layer: Layer): void {\n if (!layer.visible || layer.opacity <= 0) return;\n\n // Only save/restore context if layer has properties that need it\n const needsStateManagement =\n layer.opacity !== 1 || layer.blendMode || layer.transform || layer.mask;\n\n if (needsStateManagement) {\n this.ctx.save();\n }\n\n try {\n // Apply layer properties only when needed\n if (layer.opacity !== 1) {\n this.ctx.globalAlpha = layer.opacity;\n }\n\n if (layer.blendMode) {\n this.ctx.globalCompositeOperation = layer.blendMode;\n }\n\n if (layer.transform) {\n // Get layer dimensions for transform anchor calculation\n const layerDimensions = this.getLayerDimensions(layer);\n this.applyTransform(layer.transform, layerDimensions);\n }\n // Render based on layer type\n switch (layer.type) {\n case 'video':\n this.renderVideoLayer(layer as VideoLayer);\n break;\n case 'image':\n this.renderImageLayer(layer as ImageLayer);\n break;\n case 'text':\n this.renderTextLayer(layer as TextLayer);\n break;\n }\n\n // Apply mask if present\n if (layer.mask) {\n this.applyMask(layer.mask);\n }\n } finally {\n if (needsStateManagement) {\n this.ctx.restore();\n }\n }\n }\n\n private parseDimension(\n value: number | string | undefined,\n canvasSize: number\n ): number | undefined {\n if (value === undefined) return undefined;\n if (typeof value === 'number') return value;\n\n // value is string at this point\n const strValue = value as string;\n\n // Parse percentage string like \"5%\"\n if (strValue.includes('%')) {\n const numValue = parseFloat(strValue);\n return isNaN(numValue) ? undefined : (numValue / 100) * canvasSize;\n }\n\n // Parse as pixel value\n const parsed = parseFloat(strValue);\n return isNaN(parsed) ? undefined : parsed;\n }\n\n private getLayerDimensions(layer: Layer): { width: number; height: number } {\n if (layer.type === 'image') {\n const imageLayer = layer as ImageLayer;\n if (imageLayer.source) {\n const imgWidth = imageLayer.source.width;\n const imgHeight = imageLayer.source.height;\n\n // For attachment layers with target dimensions, calculate rendered size\n const isAttachment = !!imageLayer.attachmentId;\n if (isAttachment) {\n const targetWidthRaw = (imageLayer as any).targetWidth;\n const targetHeightRaw = (imageLayer as any).targetHeight;\n\n // Parse dimensions (supports both pixels and percentages)\n const targetWidth = this.parseDimension(targetWidthRaw, this.width);\n const targetHeight = this.parseDimension(targetHeightRaw, this.height);\n\n if (targetWidth && targetHeight) {\n return { width: targetWidth, height: targetHeight };\n } else if (targetWidth) {\n return {\n width: targetWidth,\n height: (imgHeight / imgWidth) * targetWidth,\n };\n } else if (targetHeight) {\n return {\n width: (imgWidth / imgHeight) * targetHeight,\n height: targetHeight,\n };\n }\n }\n\n // No scaling, return original dimensions\n return { width: imgWidth, height: imgHeight };\n }\n } else if (layer.type === 'video') {\n const videoLayer = layer as VideoLayer;\n const videoFrame = videoLayer.videoFrame;\n return {\n width: videoFrame.displayWidth || videoFrame.codedWidth,\n height: videoFrame.displayHeight || videoFrame.codedHeight,\n };\n }\n // Default to canvas dimensions\n return { width: this.width, height: this.height };\n }\n\n /**\n * Calculate render dimensions with smart fill logic\n * @param sourceWidth Source width\n * @param sourceHeight Source height\n * @param naturalScale Natural scale factor (scaleY for video, scaleX for image)\n * @returns Render dimensions and position\n */\n private calculateRenderDimensions(\n sourceWidth: number,\n sourceHeight: number,\n naturalScale: number\n ): { width: number; height: number; x: number; y: number } {\n const scaledWidth = sourceWidth * naturalScale;\n const scaledHeight = sourceHeight * naturalScale;\n\n // Smart fill: when scaled size is close to container (>90%), use cover mode\n const shouldFill =\n scaledWidth / this.width > this.FILL_THRESHOLD &&\n scaledHeight / this.height > this.FILL_THRESHOLD;\n\n let renderWidth: number;\n let renderHeight: number;\n\n if (shouldFill) {\n // Cover mode: use Math.max to ensure entire canvas is covered while maintaining aspect ratio\n const coverScale = Math.max(this.width / sourceWidth, this.height / sourceHeight);\n renderWidth = Math.round(sourceWidth * coverScale);\n renderHeight = Math.round(sourceHeight * coverScale);\n } else {\n // Natural scale mode: use scaled dimensions\n renderWidth = Math.round(scaledWidth);\n renderHeight = Math.round(scaledHeight);\n }\n\n // Center the content\n const renderX = Math.round((this.width - renderWidth) / 2);\n const renderY = Math.round((this.height - renderHeight) / 2);\n\n return { width: renderWidth, height: renderHeight, x: renderX, y: renderY };\n }\n\n private applyTransform(\n transform: Transform2D,\n layerDimensions: { width: number; height: number }\n ): void {\n // Use layer dimensions (not canvas dimensions) for anchor calculation\n const anchorX = transform.anchorX ?? 0.5;\n const anchorY = transform.anchorY ?? 0.5;\n const centerX = layerDimensions.width * anchorX;\n const centerY = layerDimensions.height * anchorY;\n\n // Move to the layer position + anchor offset\n this.ctx.translate(transform.x + centerX, transform.y + centerY);\n\n if (transform.rotation) {\n this.ctx.rotate(transform.rotation);\n }\n\n this.ctx.scale(transform.scaleX, transform.scaleY);\n\n if (transform.skewX || transform.skewY) {\n this.ctx.transform(1, transform.skewY ?? 0, transform.skewX ?? 0, 1, 0, 0);\n }\n\n // Move back by anchor offset\n this.ctx.translate(-centerX, -centerY);\n }\n\n private renderVideoLayer(layer: VideoLayer): void {\n const { videoFrame, crop } = layer;\n\n // Get video dimensions\n const videoWidth = videoFrame.displayWidth || videoFrame.codedWidth;\n const videoHeight = videoFrame.displayHeight || videoFrame.codedHeight;\n\n // Video uses scaleY (height-based scaling) to match legacy behavior\n const naturalScale = this.height / videoHeight;\n const dimensions = this.calculateRenderDimensions(videoWidth, videoHeight, naturalScale);\n\n if (crop) {\n this.ctx.drawImage(\n videoFrame,\n crop.x,\n crop.y,\n crop.width,\n crop.height,\n dimensions.x,\n dimensions.y,\n dimensions.width,\n dimensions.height\n );\n } else {\n this.ctx.drawImage(\n videoFrame,\n dimensions.x,\n dimensions.y,\n dimensions.width,\n dimensions.height\n );\n }\n // NOTE: Do not close videoFrame - it's managed by RcFrame wrapper\n }\n\n private renderImageLayer(layer: ImageLayer): void {\n const { source, crop } = layer;\n\n // Handle ImageData by putting it on canvas first\n if (source instanceof ImageData) {\n if (crop) {\n // For ImageData with crop, we need to extract the cropped region\n const tempCanvas = new OffscreenCanvas(crop.width, crop.height);\n const tempCtx = tempCanvas.getContext('2d')!;\n tempCtx.putImageData(source, -crop.x, -crop.y);\n this.ctx.drawImage(tempCanvas, 0, 0, this.width, this.height);\n } else {\n // Put ImageData directly\n this.ctx.putImageData(source, 0, 0);\n }\n } else {\n // ImageBitmap can be drawn directly\n if (!source) {\n return;\n }\n\n // Determine if this is an attachment layer (has attachmentId)\n const isAttachment = !!layer.attachmentId;\n const imgWidth = source.width;\n const imgHeight = source.height;\n\n let renderWidth: number;\n let renderHeight: number;\n\n if (isAttachment) {\n // Attachment images use original size (or targetWidth/targetHeight if specified)\n const targetWidthRaw = (layer as any).targetWidth;\n const targetHeightRaw = (layer as any).targetHeight;\n\n // Parse dimensions (supports both pixels and percentages)\n const targetWidth = this.parseDimension(targetWidthRaw, this.width);\n const targetHeight = this.parseDimension(targetHeightRaw, this.height);\n\n if (targetWidth && targetHeight) {\n // Both specified, use as-is\n renderWidth = targetWidth;\n renderHeight = targetHeight;\n } else if (targetWidth) {\n // Only width specified, maintain aspect ratio\n renderWidth = targetWidth;\n renderHeight = (imgHeight / imgWidth) * targetWidth;\n } else if (targetHeight) {\n // Only height specified, maintain aspect ratio\n renderHeight = targetHeight;\n renderWidth = (imgWidth / imgHeight) * targetHeight;\n } else {\n // No target size, use original\n renderWidth = imgWidth;\n renderHeight = imgHeight;\n }\n } else {\n // Main track images use scaleX (width-based scaling) to match legacy behavior\n const naturalScale = this.width / imgWidth;\n const dimensions = this.calculateRenderDimensions(imgWidth, imgHeight, naturalScale);\n renderWidth = dimensions.width;\n renderHeight = dimensions.height;\n }\n\n // Calculate render position (center for main track images, origin for attachments)\n const renderX = isAttachment ? 0 : Math.round((this.width - renderWidth) / 2);\n const renderY = isAttachment ? 0 : Math.round((this.height - renderHeight) / 2);\n\n if (crop) {\n this.ctx.drawImage(\n source,\n crop.x,\n crop.y,\n crop.width,\n crop.height,\n renderX,\n renderY,\n renderWidth,\n renderHeight\n );\n } else {\n this.ctx.drawImage(source, renderX, renderY, renderWidth, renderHeight);\n }\n }\n }\n\n private renderTextLayer(layer: TextLayer): void {\n const animationType = layer.animation?.type;\n const hasWordTimings = layer.wordTimings && layer.wordTimings.length > 0;\n\n const needsWordTimings = ['wordByWord', 'characterKTV', 'wordByWordFancy'].includes(\n animationType || ''\n );\n\n if (needsWordTimings && !hasWordTimings) {\n renderBasicText(this.ctx, layer, this.width, this.height, this.currentFrame);\n return;\n }\n\n switch (animationType) {\n case 'wordByWord':\n renderWordByWord(this.ctx, layer, this.width, this.height, this.currentFrame, this.fps);\n break;\n case 'characterKTV':\n renderCharacterKTV(this.ctx, layer, this.width, this.height, this.currentFrame, this.fps);\n break;\n case 'wordByWordFancy':\n renderWordByWordFancy(\n this.ctx,\n layer,\n this.width,\n this.height,\n this.currentFrame,\n this.fps\n );\n break;\n case 'fade':\n renderTextWithEntrance(this.ctx, layer, this.width, this.height, this.currentFrame);\n break;\n default:\n renderBasicText(this.ctx, layer, this.width, this.height, this.currentFrame);\n break;\n }\n }\n\n private applyMask(mask: MaskConfig): void {\n this.ctx.globalCompositeOperation = mask.invert ? 'source-out' : 'destination-in';\n\n if (mask.source) {\n this.ctx.drawImage(mask.source, 0, 0, this.width, this.height);\n } else if (mask.shape === 'circle') {\n this.ctx.beginPath();\n this.ctx.arc(\n this.width / 2,\n this.height / 2,\n Math.min(this.width, this.height) / 2,\n 0,\n Math.PI * 2\n );\n this.ctx.fill();\n }\n }\n\n updateDimensions(width: number, height: number): void {\n this.width = width;\n this.height = height;\n this.ensureHighQualityRendering();\n }\n}\n","import type { TransitionEffect } from './types';\n\n/**\n * TransitionProcessor - Handles transition effects between frames/scenes\n * Single responsibility: Apply transition transformations to canvas context\n */\nexport class TransitionProcessor {\n private width: number;\n private height: number;\n\n constructor(width: number, height: number) {\n this.width = width;\n this.height = height;\n }\n\n /**\n * Apply transition effect to the canvas context\n * Returns true if transition was applied, false if not needed\n */\n applyTransition(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n transition: TransitionEffect\n ): boolean {\n if (!transition || transition.progress <= 0) return false;\n\n const progress = this.calculateEasedProgress(transition.progress, transition.easing);\n\n switch (transition.type) {\n case 'fade':\n return this.applyFade(ctx, progress);\n case 'slide':\n return this.applySlide(ctx, progress, transition.direction);\n case 'wipe':\n return this.applyWipe(ctx, progress, transition.direction);\n case 'zoom':\n return this.applyZoom(ctx, progress, transition.direction);\n case 'rotate':\n return this.applyRotate(ctx, progress);\n case 'dissolve':\n return this.applyDissolve(ctx, progress);\n default:\n return false;\n }\n }\n\n private calculateEasedProgress(\n progress: number,\n easing?: 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out'\n ): number {\n switch (easing) {\n case 'ease-in':\n return progress * progress;\n case 'ease-out':\n return 1 - (1 - progress) * (1 - progress);\n case 'ease-in-out':\n return progress < 0.5 ? 2 * progress * progress : 1 - Math.pow(-2 * progress + 2, 2) / 2;\n default:\n return progress;\n }\n }\n\n private applyFade(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n progress: number\n ): boolean {\n ctx.globalAlpha = progress;\n return true;\n }\n\n private applySlide(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n progress: number,\n direction?: 'left' | 'right' | 'up' | 'down' | 'in' | 'out'\n ): boolean {\n const distance = 1 - progress;\n\n switch (direction) {\n case 'left':\n ctx.translate(-this.width * distance, 0);\n break;\n case 'right':\n ctx.translate(this.width * distance, 0);\n break;\n case 'up':\n ctx.translate(0, -this.height * distance);\n break;\n case 'down':\n ctx.translate(0, this.height * distance);\n break;\n default:\n ctx.translate(-this.width * distance, 0);\n }\n\n return true;\n }\n\n private applyWipe(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n progress: number,\n direction?: 'left' | 'right' | 'up' | 'down' | 'in' | 'out'\n ): boolean {\n ctx.save();\n ctx.beginPath();\n\n switch (direction) {\n case 'left':\n ctx.rect(0, 0, this.width * progress, this.height);\n break;\n case 'right':\n ctx.rect(this.width * (1 - progress), 0, this.width * progress, this.height);\n break;\n case 'up':\n ctx.rect(0, 0, this.width, this.height * progress);\n break;\n case 'down':\n ctx.rect(0, this.height * (1 - progress), this.width, this.height * progress);\n break;\n default:\n ctx.rect(0, 0, this.width * progress, this.height);\n }\n\n ctx.clip();\n return true;\n }\n\n private applyZoom(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n progress: number,\n direction?: 'left' | 'right' | 'up' | 'down' | 'in' | 'out'\n ): boolean {\n const scale = direction === 'out' ? 1 + (1 - progress) : progress;\n const centerX = this.width / 2;\n const centerY = this.height / 2;\n\n ctx.translate(centerX, centerY);\n ctx.scale(scale, scale);\n ctx.translate(-centerX, -centerY);\n\n if (direction === 'out') {\n ctx.globalAlpha = progress;\n }\n\n return true;\n }\n\n private applyRotate(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n progress: number\n ): boolean {\n const rotation = (1 - progress) * Math.PI * 2;\n const centerX = this.width / 2;\n const centerY = this.height / 2;\n\n ctx.translate(centerX, centerY);\n ctx.rotate(rotation);\n ctx.translate(-centerX, -centerY);\n\n return true;\n }\n\n private applyDissolve(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n progress: number\n ): boolean {\n // Simple dissolve using alpha\n ctx.globalAlpha = progress;\n ctx.globalCompositeOperation = 'multiply';\n return true;\n }\n\n /**\n * Create a transition mask for advanced effects\n */\n createTransitionMask(transition: TransitionEffect, canvas: OffscreenCanvas): ImageData | null {\n const ctx = canvas.getContext('2d');\n if (!ctx) return null;\n\n const imageData = ctx.createImageData(this.width, this.height);\n const data = imageData.data;\n const progress = this.calculateEasedProgress(transition.progress, transition.easing);\n\n // Generate gradient mask based on transition type\n for (let y = 0; y < this.height; y++) {\n for (let x = 0; x < this.width; x++) {\n const index = (y * this.width + x) * 4;\n let alpha = 255;\n\n switch (transition.type) {\n case 'wipe':\n alpha = this.calculateWipeAlpha(x, y, progress, transition.direction);\n break;\n case 'dissolve':\n // Random noise dissolve\n alpha = Math.random() < progress ? 255 : 0;\n break;\n default:\n alpha = Math.floor(255 * progress);\n }\n\n data[index] = 255; // R\n data[index + 1] = 255; // G\n data[index + 2] = 255; // B\n data[index + 3] = alpha; // A\n }\n }\n\n return imageData;\n }\n\n private calculateWipeAlpha(\n x: number,\n y: number,\n progress: number,\n direction?: 'left' | 'right' | 'up' | 'down' | 'in' | 'out'\n ): number {\n let position = 0;\n\n switch (direction) {\n case 'left':\n position = x / this.width;\n break;\n case 'right':\n position = 1 - x / this.width;\n break;\n case 'up':\n position = y / this.height;\n break;\n case 'down':\n position = 1 - y / this.height;\n break;\n case 'in': {\n // Radial wipe from center\n const cx = x - this.width / 2;\n const cy = y - this.height / 2;\n const maxDist = Math.sqrt(this.width * this.width + this.height * this.height) / 2;\n position = Math.sqrt(cx * cx + cy * cy) / maxDist;\n break;\n }\n case 'out': {\n // Radial wipe to center\n const cx2 = x - this.width / 2;\n const cy2 = y - this.height / 2;\n const maxDist2 = Math.sqrt(this.width * this.width + this.height * this.height) / 2;\n position = 1 - Math.sqrt(cx2 * cx2 + cy2 * cy2) / maxDist2;\n break;\n }\n default:\n position = x / this.width;\n }\n\n return position < progress ? 255 : 0;\n }\n\n updateDimensions(width: number, height: number): void {\n this.width = width;\n this.height = height;\n }\n}\n","import type { VisualFilter } from './types';\n\n/**\n * FilterProcessor - Handles visual filters and effects\n * Single responsibility: Apply CSS filters and custom shader effects\n */\nexport class FilterProcessor {\n private filterCache = new Map<string, string>();\n\n /**\n * Apply filters to canvas context\n * Combines multiple filters into a single CSS filter string for performance\n */\n applyFilters(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n filters: VisualFilter[]\n ): void {\n if (!filters || filters.length === 0) {\n ctx.filter = 'none';\n return;\n }\n\n // Generate cache key\n const cacheKey = this.generateCacheKey(filters);\n\n // Check cache\n let filterString = this.filterCache.get(cacheKey);\n\n if (!filterString) {\n filterString = this.buildFilterString(filters);\n this.filterCache.set(cacheKey, filterString);\n }\n\n ctx.filter = filterString;\n }\n\n /**\n * Build CSS filter string from filter array\n */\n private buildFilterString(filters: VisualFilter[]): string {\n const filterStrings: string[] = [];\n\n for (const filter of filters) {\n const filterStr = this.buildSingleFilter(filter);\n if (filterStr) {\n filterStrings.push(filterStr);\n }\n }\n\n return filterStrings.length > 0 ? filterStrings.join(' ') : 'none';\n }\n\n private buildSingleFilter(filter: VisualFilter): string | null {\n switch (filter.type) {\n case 'blur':\n return `blur(${filter.value ?? 0}px)`;\n\n case 'brightness':\n return `brightness(${filter.value ?? 1})`;\n\n case 'contrast':\n return `contrast(${filter.value ?? 1})`;\n\n case 'grayscale':\n return `grayscale(${filter.value ?? 0})`;\n\n case 'hue-rotate':\n return `hue-rotate(${filter.value ?? 0}deg)`;\n\n case 'saturate':\n return `saturate(${filter.value ?? 1})`;\n\n case 'sepia':\n return `sepia(${filter.value ?? 0})`;\n\n case 'custom':\n return this.buildCustomFilter(filter);\n\n default:\n console.warn(`Unknown filter type: ${filter.type}`);\n return null;\n }\n }\n\n /**\n * Build custom filter from params\n */\n private buildCustomFilter(filter: VisualFilter): string | null {\n if (!filter.params) return null;\n\n const { type, ...params } = filter.params;\n\n switch (type) {\n case 'drop-shadow':\n return `drop-shadow(${params.offsetX}px ${params.offsetY}px ${params.blur}px ${params.color})`;\n\n case 'opacity':\n return `opacity(${params.value})`;\n\n case 'invert':\n return `invert(${params.value})`;\n\n default:\n return null;\n }\n }\n\n /**\n * Apply color matrix transformation for advanced effects\n * This allows for more complex color manipulations than CSS filters\n */\n applyColorMatrix(imageData: ImageData, matrix: number[]): ImageData {\n if (matrix.length !== 20) {\n throw new Error('Color matrix must have 20 values (4x5 matrix)');\n }\n\n const data = imageData.data;\n const length = data.length;\n\n for (let i = 0; i < length; i += 4) {\n const r = data[i]!;\n const g = data[i + 1]!;\n const b = data[i + 2]!;\n const a = data[i + 3]!;\n const m = matrix;\n\n // Apply matrix transformation\n data[i] = this.clamp(r * m[0]! + g * m[1]! + b * m[2]! + a * m[3]! + m[4]! * 255);\n data[i + 1] = this.clamp(r * m[5]! + g * m[6]! + b * m[7]! + a * m[8]! + m[9]! * 255);\n data[i + 2] = this.clamp(r * m[10]! + g * m[11]! + b * m[12]! + a * m[13]! + m[14]! * 255);\n data[i + 3] = this.clamp(r * m[15]! + g * m[16]! + b * m[17]! + a * m[18]! + m[19]! * 255);\n }\n\n return imageData;\n }\n\n /**\n * Predefined color matrices for common effects\n */\n getPresetMatrix(preset: string): number[] | null {\n switch (preset) {\n case 'vintage':\n return [\n 0.393, 0.769, 0.189, 0, 0, 0.349, 0.686, 0.168, 0, 0, 0.272, 0.534, 0.131, 0, 0, 0, 0, 0,\n 1, 0,\n ];\n\n case 'noir':\n return [\n 0.25, 0.25, 0.25, 0, 0, 0.25, 0.25, 0.25, 0, 0, 0.25, 0.25, 0.25, 0, 0, 0, 0, 0, 1, 0,\n ];\n\n case 'cool':\n return [0.8, 0, 0, 0, 0, 0, 0.9, 0, 0, 0, 0, 0, 1.2, 0, 0, 0, 0, 0, 1, 0];\n\n case 'warm':\n return [1.2, 0, 0, 0, 0, 0, 1.1, 0, 0, 0, 0, 0, 0.8, 0, 0, 0, 0, 0, 1, 0];\n\n default:\n return null;\n }\n }\n\n /**\n * Apply Gaussian blur manually (for cases where CSS filter is not enough)\n */\n applyGaussianBlur(imageData: ImageData, radius: number): ImageData {\n // Simplified box blur approximation of Gaussian blur\n const output = new ImageData(\n new Uint8ClampedArray(imageData.data),\n imageData.width,\n imageData.height\n );\n\n const width = imageData.width;\n const height = imageData.height;\n const data = imageData.data;\n const outData = output.data;\n\n // Horizontal pass\n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) {\n let r = 0,\n g = 0,\n b = 0,\n a = 0;\n let count = 0;\n\n for (let dx = -radius; dx <= radius; dx++) {\n const nx = Math.min(Math.max(x + dx, 0), width - 1);\n const idx = (y * width + nx) * 4;\n r += data[idx]!;\n g += data[idx + 1]!;\n b += data[idx + 2]!;\n a += data[idx + 3]!;\n count++;\n }\n\n const idx = (y * width + x) * 4;\n outData[idx] = r / count;\n outData[idx + 1] = g / count;\n outData[idx + 2] = b / count;\n outData[idx + 3] = a / count;\n }\n }\n\n // Vertical pass\n for (let x = 0; x < width; x++) {\n for (let y = 0; y < height; y++) {\n let r = 0,\n g = 0,\n b = 0,\n a = 0;\n let count = 0;\n\n for (let dy = -radius; dy <= radius; dy++) {\n const ny = Math.min(Math.max(y + dy, 0), height - 1);\n const idx = (ny * width + x) * 4;\n r += outData[idx]!;\n g += outData[idx + 1]!;\n b += outData[idx + 2]!;\n a += outData[idx + 3]!;\n count++;\n }\n\n const idx = (y * width + x) * 4;\n data[idx] = r / count;\n data[idx + 1] = g / count;\n data[idx + 2] = b / count;\n data[idx + 3] = a / count;\n }\n }\n\n return imageData;\n }\n\n private clamp(value: number): number {\n return Math.min(255, Math.max(0, Math.round(value)));\n }\n\n private generateCacheKey(filters: VisualFilter[]): string {\n return filters.map((f) => `${f.type}:${f.value ?? 'default'}`).join('|');\n }\n\n clearCache(): void {\n this.filterCache.clear();\n }\n\n getCacheSize(): number {\n return this.filterCache.size;\n }\n}\n","import type {\n VideoComposeConfig,\n ComposeRequest,\n ComposeResult,\n TransitionEffect,\n VideoLayer,\n Layer,\n} from './types';\nimport { LayerRenderer } from './LayerRenderer';\nimport { TransitionProcessor } from './TransitionProcessor';\nimport { FilterProcessor } from './FilterProcessor';\nimport { ClipInstructionSet } from './instructions';\n\nconst closeLayerFrame = (layer: Layer) => {\n if (layer.type === 'video') {\n const videoLayer = layer as VideoLayer;\n // Only close videoFrame if layer doesn't use RcFrame wrapper\n // RcFrame-wrapped frames are managed by CacheManager lifecycle\n if (!videoLayer.rcFrame) {\n const vf = videoLayer.videoFrame;\n if (vf?.close) {\n vf.close();\n }\n }\n }\n};\n\n/**\n * VideoComposer - Main visual composition orchestrator\n */\nexport class VideoComposer {\n readonly config: Omit<Required<VideoComposeConfig>, 'externalCanvas'> & {\n externalCanvas?: HTMLCanvasElement | OffscreenCanvas;\n };\n readonly canvas: OffscreenCanvas | HTMLCanvasElement;\n\n private ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D;\n private layerRenderer: LayerRenderer;\n private transitionProcessor: TransitionProcessor;\n private filterProcessor: FilterProcessor;\n private frameDurationUs: number; // Cached frame duration\n private fontsLoadingPromise: Promise<void> | null = null;\n private loadedFonts = new Set<string>();\n\n constructor(config: VideoComposeConfig) {\n this.config = this.applyDefaults(config);\n this.frameDurationUs = Math.round(1_000_000 / this.config.fps); // Pre-calculate\n\n if (config.externalCanvas) {\n this.canvas = config.externalCanvas;\n\n // FIX: Ensure external canvas dimensions match the config\n if (this.canvas.width !== this.config.width || this.canvas.height !== this.config.height) {\n this.canvas.width = this.config.width;\n this.canvas.height = this.config.height;\n }\n\n this.ctx = this.canvas.getContext('2d', {\n alpha: true,\n desynchronized: true,\n willReadFrequently: false,\n colorSpace: 'srgb',\n }) as CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D;\n } else {\n this.canvas = new OffscreenCanvas(this.config.width, this.config.height);\n this.ctx = this.canvas.getContext('2d', {\n alpha: true,\n desynchronized: true,\n willReadFrequently: false,\n colorSpace: 'srgb',\n }) as OffscreenCanvasRenderingContext2D;\n }\n\n if (!this.ctx) {\n throw new Error('Failed to create 2D rendering context');\n }\n\n this.ctx.imageSmoothingEnabled = this.config.enableSmoothing;\n\n // Start loading fonts but don't block constructor\n this.fontsLoadingPromise = this.loadFonts();\n this.ctx.imageSmoothingQuality = 'high';\n\n this.layerRenderer = new LayerRenderer(\n this.ctx,\n this.config.width,\n this.config.height,\n this.config.fps\n );\n this.transitionProcessor = new TransitionProcessor(this.config.width, this.config.height);\n this.filterProcessor = new FilterProcessor();\n }\n\n private applyDefaults(config: VideoComposeConfig): Omit<\n Required<VideoComposeConfig>,\n 'externalCanvas'\n > & {\n externalCanvas?: HTMLCanvasElement | OffscreenCanvas;\n } {\n return {\n width: config.width || 720,\n height: config.height || 1280,\n fps: config.fps || 30,\n backgroundColor: config.backgroundColor ?? '#000',\n renderer: config.renderer ?? 'canvas2d',\n enableSmoothing: config.enableSmoothing ?? true,\n enableHardwareAcceleration: config.enableHardwareAcceleration ?? true,\n revision: config.revision ?? 0,\n inputHighWaterMark: config.inputHighWaterMark ?? 3,\n outputHighWaterMark: config.outputHighWaterMark ?? 1,\n maxLayers: config.maxLayers ?? 100,\n timeline: config.timeline ?? {\n clipId: 'default',\n trackId: 'main',\n clipStartUs: 0,\n clipDurationUs: Infinity,\n compositionFps: 30,\n },\n fonts: config.fonts ?? [],\n externalCanvas: config.externalCanvas,\n };\n }\n\n createStreams(_instruction?: ClipInstructionSet): TransformStream<ComposeRequest, VideoFrame> {\n // Always create new streams for each clip\n // ReadableStreams can only be consumed once\n const stream = new TransformStream<ComposeRequest, VideoFrame>(\n {\n transform: async (request, controller) => {\n // console.log('[VideoComposer] transform', request, controller.desiredSize);\n const result = await this.composeFrame(request);\n if (result.frame) {\n controller.enqueue(result.frame);\n }\n // setTimeout(() => {\n // result.frame.close();\n // }, 1000);\n },\n\n flush: async () => {\n this.filterProcessor.clearCache();\n },\n },\n {\n highWaterMark: this.config.inputHighWaterMark,\n },\n {\n highWaterMark: this.config.outputHighWaterMark,\n }\n );\n return stream;\n }\n async composeFrame(request: ComposeRequest): Promise<ComposeResult> {\n // Ensure fonts are loaded before rendering\n if (this.fontsLoadingPromise) {\n await this.fontsLoadingPromise;\n this.fontsLoadingPromise = null; // Only wait once\n }\n\n if (request.layers.length > this.config.maxLayers) {\n throw new Error(`Too many layers: ${request.layers.length} > ${this.config.maxLayers}`);\n }\n\n this.clearCanvas();\n\n // Calculate current frame number for animations (relative to clip start)\n const frameDurationUs = 1_000_000 / this.config.fps;\n const relativeFrame = Math.floor(request.timeUs / frameDurationUs);\n this.layerRenderer.setCurrentFrame(relativeFrame);\n\n if (request.transition) {\n this.ctx.save();\n this.transitionProcessor.applyTransition(this.ctx, request.transition);\n }\n\n for (const layer of request.layers) {\n if (!layer.visible || layer.opacity <= 0) {\n // Close video frame for invisible layers\n closeLayerFrame(layer);\n continue;\n }\n\n try {\n // If layer has RcFrame, use it within the rendering scope\n const videoLayer = layer as VideoLayer;\n if (videoLayer.rcFrame) {\n videoLayer.rcFrame.use((frame: VideoFrame) => {\n // Set the frame reference (direct access, no clone for performance)\n videoLayer.videoFrame = frame;\n\n if (layer.filters && layer.filters.length > 0) {\n this.ctx.save();\n this.filterProcessor.applyFilters(this.ctx, layer.filters);\n }\n this.layerRenderer.renderLayer(layer);\n\n if (layer.filters && layer.filters.length > 0) {\n this.ctx.restore();\n }\n });\n } else {\n // Regular layer without RcFrame\n if (layer.filters && layer.filters.length > 0) {\n this.ctx.save();\n this.filterProcessor.applyFilters(this.ctx, layer.filters);\n }\n this.layerRenderer.renderLayer(layer);\n\n if (layer.filters && layer.filters.length > 0) {\n this.ctx.restore();\n }\n }\n } catch (error) {\n console.error('[VideoComposer] composeFrame error: ', error);\n } finally {\n closeLayerFrame(layer);\n }\n }\n\n if (request.transition) {\n this.ctx.restore();\n }\n\n let frame: VideoFrame | null = null;\n if (!this.config.externalCanvas) {\n frame = await this.createOutputFrame(request.timeUs);\n }\n\n return {\n frame,\n timeUs: request.timeUs,\n };\n }\n\n async composeTransition(\n fromRequest: ComposeRequest,\n toRequest: ComposeRequest,\n transition: TransitionEffect\n ): Promise<ComposeResult> {\n await this.composeFrame(fromRequest);\n\n const toFrameRequest = {\n ...toRequest,\n transition,\n };\n\n return this.composeFrame(toFrameRequest);\n }\n\n private clearCanvas(): void {\n if (this.config.backgroundColor) {\n this.ctx.fillStyle = this.config.backgroundColor;\n this.ctx.fillRect(0, 0, this.config.width, this.config.height);\n } else {\n this.ctx.clearRect(0, 0, this.config.width, this.config.height);\n }\n }\n\n // private sortLayers(layers: Layer[]): Layer[] {\n // return [...layers].sort((a, b) => a.zIndex - b.zIndex);\n // }\n\n private async createOutputFrame(timeUs: number): Promise<VideoFrame> {\n const frame = new VideoFrame(this.canvas, {\n timestamp: timeUs,\n duration: this.frameDurationUs, // Use cached duration\n alpha: 'discard',\n visibleRect: { x: 0, y: 0, width: this.canvas.width, height: this.canvas.height },\n });\n return frame;\n }\n\n private async loadFonts(): Promise<void> {\n if (!this.config.fonts || this.config.fonts.length === 0) {\n return;\n }\n\n for (const font of this.config.fonts) {\n if (this.loadedFonts.has(font.family)) {\n continue;\n }\n\n try {\n const fontFace = new FontFace(font.family, `url(${font.url})`);\n const loadedFont = await fontFace.load();\n\n if ('fonts' in self) {\n self.fonts.add(loadedFont);\n }\n\n this.loadedFonts.add(font.family);\n } catch {\n // Font loading failed, will fallback to system fonts\n }\n }\n }\n\n updateConfig(config: Partial<VideoComposeConfig>): void {\n Object.assign(this.config, this.applyDefaults({ ...this.config, ...config }));\n\n if (config.fps !== undefined) {\n this.frameDurationUs = Math.round(1_000_000 / this.config.fps); // Update cached duration\n }\n\n if (config.width || config.height) {\n this.canvas.width = this.config.width;\n this.canvas.height = this.config.height;\n this.layerRenderer.updateDimensions(this.config.width, this.config.height);\n this.transitionProcessor.updateDimensions(this.config.width, this.config.height);\n }\n\n if (config.enableSmoothing !== undefined) {\n this.ctx.imageSmoothingEnabled = this.config.enableSmoothing;\n }\n\n if (config.fonts) {\n this.fontsLoadingPromise = this.loadFonts();\n }\n }\n\n dispose(): void {\n this.filterProcessor.clearCache();\n }\n}\n","export type QuantizeStrategy = 'nearest' | 'floor' | 'ceil';\ntype TimeUs = number;\nexport const MICROSECONDS_PER_SECOND = 1_000_000;\n\nconst DEFAULT_FPS = 30;\n\nexport const DEFAULT_FRAME_TOLERANCE_US: TimeUs = 33_333;\n\nexport function normalizeFps(value?: number): number {\n if (!Number.isFinite(value) || (value as number) <= 0) {\n return DEFAULT_FPS;\n }\n return value as number;\n}\n\nexport function frameDurationFromFps(fps?: number): TimeUs {\n const normalized = normalizeFps(fps);\n const duration = MICROSECONDS_PER_SECOND / normalized;\n return Math.max(Math.round(duration), 1);\n}\n\nexport function frameIndexFromTimestamp(\n baseTimestampUs: TimeUs,\n timestampUs: TimeUs,\n fps?: number,\n strategy: QuantizeStrategy = 'nearest'\n): number {\n const frameDurationUs = frameDurationFromFps(fps);\n if (frameDurationUs <= 0) {\n return 0;\n }\n\n const delta = timestampUs - baseTimestampUs;\n const rawIndex = delta / frameDurationUs;\n\n if (!Number.isFinite(rawIndex)) {\n return 0;\n }\n\n switch (strategy) {\n case 'floor':\n return Math.floor(rawIndex);\n case 'ceil':\n return Math.ceil(rawIndex);\n default:\n return Math.round(rawIndex);\n }\n}\n\nexport function quantizeTimestampToFrame(\n timestampUs: TimeUs,\n baseTimestampUs: TimeUs,\n fps?: number,\n strategy: QuantizeStrategy = 'nearest'\n): TimeUs {\n const frameDurationUs = frameDurationFromFps(fps);\n const index = frameIndexFromTimestamp(baseTimestampUs, timestampUs, fps, strategy);\n return baseTimestampUs + index * frameDurationUs;\n}\n\nexport function isTimestampWithinFrame(\n targetTimeUs: TimeUs,\n frameTimestampUs: TimeUs,\n frameDurationUs: TimeUs,\n toleranceUs: TimeUs = DEFAULT_FRAME_TOLERANCE_US\n): boolean {\n if (!Number.isFinite(frameTimestampUs)) {\n return false;\n }\n\n const delta = Math.abs(targetTimeUs - frameTimestampUs);\n if (delta <= toleranceUs) {\n return true;\n }\n\n if (frameDurationUs > 0 && frameTimestampUs <= targetTimeUs) {\n return targetTimeUs < frameTimestampUs + frameDurationUs;\n }\n\n return false;\n}\n","import type { Transform2D } from '../model/types';\n\nexport interface AnimationKeyframeInput {\n time: number;\n transform?: Transform2D;\n opacity?: number;\n easing?: string;\n}\n\nexport function interpolateKeyframes(\n keyframes: AnimationKeyframeInput[],\n timeUs: number\n): { transform: Transform2D; opacity?: number } {\n const defaultTransform: Transform2D = {\n x: 0,\n y: 0,\n scaleX: 1,\n scaleY: 1,\n rotation: 0,\n anchorX: 0.5,\n anchorY: 0.5,\n };\n\n if (keyframes.length === 0) {\n return { transform: defaultTransform };\n }\n\n const firstFrame = keyframes[0]!;\n const lastFrame = keyframes[keyframes.length - 1]!;\n\n if (timeUs <= firstFrame.time) {\n return {\n transform: { ...defaultTransform, ...firstFrame.transform },\n opacity: firstFrame.opacity,\n };\n }\n\n if (timeUs >= lastFrame.time) {\n return {\n transform: { ...defaultTransform, ...lastFrame.transform },\n opacity: lastFrame.opacity,\n };\n }\n\n // Find current keyframe interval\n let prevFrame = firstFrame;\n let nextFrame = lastFrame;\n\n for (let i = 0; i < keyframes.length - 1; i++) {\n const currentFrame = keyframes[i]!;\n const followingFrame = keyframes[i + 1]!;\n if (timeUs >= currentFrame.time && timeUs < followingFrame.time) {\n prevFrame = currentFrame;\n nextFrame = followingFrame;\n break;\n }\n }\n\n const duration = nextFrame.time - prevFrame.time;\n const elapsed = timeUs - prevFrame.time;\n const progress = elapsed / duration;\n const easedProgress = applyEasing(progress, prevFrame.easing ?? 'linear');\n\n const prevTransform = prevFrame.transform ?? { x: 0, y: 0 };\n const nextTransform = nextFrame.transform ?? { x: 0, y: 0 };\n\n const transform = interpolateTransform(prevTransform, nextTransform, easedProgress);\n\n const opacity =\n prevFrame.opacity !== undefined && nextFrame.opacity !== undefined\n ? lerp(prevFrame.opacity, nextFrame.opacity, easedProgress)\n : undefined;\n\n return { transform, opacity };\n}\n\nexport function interpolateTransform(from: Transform2D, to: Transform2D, t: number): Transform2D {\n return {\n x: lerp(from.x ?? 0, to.x ?? 0, t),\n y: lerp(from.y ?? 0, to.y ?? 0, t),\n scaleX: lerp(from.scaleX ?? 1, to.scaleX ?? 1, t),\n scaleY: lerp(from.scaleY ?? 1, to.scaleY ?? 1, t),\n rotation: lerp(from.rotation ?? 0, to.rotation ?? 0, t),\n anchorX: lerp(from.anchorX ?? 0.5, to.anchorX ?? 0.5, t),\n anchorY: lerp(from.anchorY ?? 0.5, to.anchorY ?? 0.5, t),\n };\n}\n\nexport function lerp(a: number, b: number, t: number): number {\n return a + (b - a) * t;\n}\n\nexport function applyEasing(t: number, easing: string): number {\n switch (easing) {\n case 'linear':\n return t;\n case 'ease-in':\n // Cubic ease-in: t^3\n return t * t * t;\n case 'ease-out': {\n // Cubic ease-out: 1 - (1-t)^3\n const oneMinusT = 1 - t;\n return 1 - oneMinusT * oneMinusT * oneMinusT;\n }\n case 'ease-in-out':\n // Cubic ease-in-out: smoother transition\n return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;\n default:\n return t;\n }\n}\n","import type { TimeUs } from '../../model/types';\n\n/**\n * FrameRateConverter - Converts VFR (Variable Frame Rate) to CFR (Constant Frame Rate)\n *\n * Receives VideoFrames with irregular timestamps from decoder (VFR)\n * and outputs VideoFrames with regular timestamps based on target fps (CFR).\n *\n * Algorithm:\n * - Generate target frame sequence: t = 0, 33333, 66666, ... µs (for 30fps)\n * - For each target time t, find the closest source frame\n * - Output new frame with standardized timestamp t\n * - Close source frames after use to prevent memory leaks\n *\n * Trim Support:\n * - Frames with timestamp < trimStartUs are filtered out (closed and skipped)\n * - Remaining frame timestamps are adjusted: adjustedTimestamp = timestamp - trimStartUs\n *\n * Duration Handling:\n * - Output stops when source frames are exhausted (no frame padding)\n * - If source is shorter than clipDurationUs, output ends early\n *\n * Scenarios:\n * - Downsampling (60fps→30fps): Skip every other frame\n * - Upsampling (24fps→30fps): Duplicate some frames\n * - Same rate (30fps→30fps): Normalize timestamps\n */\nexport class FrameRateConverter {\n private readonly clipDurationUs: TimeUs;\n private readonly frameDurationUs: number;\n private readonly trimStartUs: TimeUs;\n\n // State for frame processing\n private targetFrameIndex = 0;\n private targetFrameTimeUs: TimeUs = 0;\n private sourceFrameBuffer: VideoFrame[] = [];\n\n constructor(targetFps: number, clipDurationUs: TimeUs, trimStartUs: TimeUs = 0) {\n if (targetFps <= 0) {\n throw new Error(`Invalid target fps: ${targetFps}`);\n }\n if (clipDurationUs <= 0) {\n throw new Error(`Invalid clip duration: ${clipDurationUs}`);\n }\n\n this.clipDurationUs = clipDurationUs;\n this.frameDurationUs = Math.round(1_000_000 / targetFps);\n this.trimStartUs = trimStartUs;\n }\n\n /**\n * Create a TransformStream that converts VFR frames to CFR frames\n */\n createStream(): TransformStream<VideoFrame, VideoFrame> {\n return new TransformStream<VideoFrame, VideoFrame>({\n start: () => {\n // Reset state for new stream\n this.targetFrameIndex = 0;\n this.targetFrameTimeUs = 0;\n this.sourceFrameBuffer = [];\n this.sourceFrameCount = 0;\n this.outputFrameCount = 0;\n },\n\n transform: (sourceFrame, controller) => {\n this.processSourceFrame(sourceFrame, controller);\n },\n\n flush: (controller) => {\n this.flushRemainingFrames(controller);\n },\n });\n }\n\n private sourceFrameCount = 0;\n private outputFrameCount = 0;\n\n /**\n * Process incoming source frame and output target frames\n */\n private processSourceFrame(\n sourceFrame: VideoFrame,\n controller: TransformStreamDefaultController<VideoFrame>\n ): void {\n const sourceTimestamp = sourceFrame.timestamp ?? 0;\n\n // Filter frames before trim start point\n if (sourceTimestamp < this.trimStartUs) {\n sourceFrame.close();\n return;\n }\n\n // Only create adjusted frame if trimStartUs > 0 (needs timestamp shift)\n let frameToBuffer: VideoFrame;\n if (this.trimStartUs > 0) {\n // Convert resource time to clip-relative time\n const adjustedTimestamp = sourceTimestamp - this.trimStartUs;\n frameToBuffer = new VideoFrame(sourceFrame, {\n timestamp: adjustedTimestamp,\n duration: sourceFrame.duration ?? undefined,\n });\n sourceFrame.close();\n } else {\n // No trim, use source frame directly\n frameToBuffer = sourceFrame;\n }\n\n // Add frame to buffer\n this.sourceFrameBuffer.push(frameToBuffer);\n this.sourceFrameCount++;\n\n // Try to output target frames that can be satisfied with current buffer\n while (this.targetFrameTimeUs < this.clipDurationUs) {\n const closestFrame = this.findClosestFrame(this.targetFrameTimeUs);\n\n if (!closestFrame) {\n // Need more source frames\n break;\n }\n\n // Check if we need to wait for next source frame\n // (if closest frame is before target and we might get a better match)\n if (this.shouldWaitForNextFrame(closestFrame)) {\n break;\n }\n\n // Output target frame with standardized timestamp\n try {\n const targetFrame = new VideoFrame(closestFrame, {\n timestamp: this.targetFrameTimeUs,\n duration: this.frameDurationUs,\n });\n\n controller.enqueue(targetFrame);\n this.outputFrameCount++;\n\n // Clean up old frames that are no longer needed\n this.cleanupOldFrames(this.targetFrameTimeUs);\n\n // Move to next target frame\n this.targetFrameIndex++;\n this.targetFrameTimeUs = this.targetFrameIndex * this.frameDurationUs;\n } catch (_error) {\n console.error('[FrameRateConverter] Failed to create target frame:', _error);\n // Continue processing even if one frame fails\n this.targetFrameIndex++;\n this.targetFrameTimeUs = this.targetFrameIndex * this.frameDurationUs;\n }\n }\n }\n\n /**\n * Flush remaining target frames at end of stream\n */\n private flushRemainingFrames(controller: TransformStreamDefaultController<VideoFrame>): void {\n // Process remaining buffered source frames\n while (this.sourceFrameBuffer.length > 0 && this.targetFrameTimeUs < this.clipDurationUs) {\n const closestFrame = this.findClosestFrame(this.targetFrameTimeUs);\n if (!closestFrame) break;\n\n if (!this.outputTargetFrame(closestFrame, controller)) break;\n }\n\n // Clean up all remaining frames\n this.cleanupAllFrames(null);\n }\n\n /**\n * Output a single target frame\n */\n private outputTargetFrame(\n sourceFrame: VideoFrame,\n controller: TransformStreamDefaultController<VideoFrame>\n ): boolean {\n try {\n const targetFrame = new VideoFrame(sourceFrame, {\n timestamp: this.targetFrameTimeUs,\n duration: this.frameDurationUs,\n });\n\n controller.enqueue(targetFrame);\n this.targetFrameIndex++;\n this.targetFrameTimeUs = this.targetFrameIndex * this.frameDurationUs;\n return true;\n } catch (error) {\n console.error('[FrameRateConverter] Failed to create target frame:', error);\n return false;\n }\n }\n\n /**\n * Clean up all buffered frames (except the specified frame to keep)\n */\n private cleanupAllFrames(keepFrame: VideoFrame | null): void {\n for (const frame of this.sourceFrameBuffer) {\n if (frame === keepFrame) continue;\n\n try {\n frame.close();\n } catch {\n // Ignore close errors\n }\n }\n this.sourceFrameBuffer = [];\n }\n\n /**\n * Find the source frame closest to target time\n */\n private findClosestFrame(targetTimeUs: TimeUs): VideoFrame | null {\n if (this.sourceFrameBuffer.length === 0) {\n return null;\n }\n\n let closestFrame = this.sourceFrameBuffer[0];\n let minError = Math.abs((closestFrame?.timestamp ?? 0) - targetTimeUs);\n\n for (const frame of this.sourceFrameBuffer) {\n const error = Math.abs((frame.timestamp ?? 0) - targetTimeUs);\n if (error < minError) {\n minError = error;\n closestFrame = frame;\n }\n }\n\n return closestFrame ?? null;\n }\n\n /**\n * Check if we should wait for next source frame before outputting\n * Returns true if:\n * - We only have 1 frame in buffer\n * - The closest frame is before target time\n * - We might get a better match from next frame\n */\n private shouldWaitForNextFrame(closestFrame: VideoFrame): boolean {\n if (this.sourceFrameBuffer.length <= 1) {\n const frameTimestamp = closestFrame.timestamp ?? 0;\n // If we only have one frame and it's before target, wait for more frames\n // unless it's far ahead (meaning we're falling behind)\n if (frameTimestamp < this.targetFrameTimeUs) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * Clean up source frames that are no longer needed\n * Keep frames that might be needed for future target frames\n */\n private cleanupOldFrames(currentTargetTimeUs: TimeUs): void {\n const nextTargetTimeUs = currentTargetTimeUs + this.frameDurationUs;\n\n // Remove frames that are definitely too old (before previous target time)\n const previousTargetTimeUs = currentTargetTimeUs - this.frameDurationUs;\n\n let removeCount = 0;\n for (let i = 0; i < this.sourceFrameBuffer.length; i++) {\n const frame = this.sourceFrameBuffer[i];\n if (!frame) continue;\n\n const frameTimestamp = frame.timestamp ?? 0;\n\n // Keep frame if:\n // 1. It's close to current or next target time\n // 2. We haven't used it yet\n // 3. It might be needed for next target\n const isNeededForNext =\n Math.abs(frameTimestamp - nextTargetTimeUs) <\n Math.abs(frameTimestamp - previousTargetTimeUs);\n\n if (frameTimestamp < previousTargetTimeUs && !isNeededForNext) {\n // This frame is too old and won't be needed\n try {\n frame.close();\n } catch {\n // Ignore close errors\n }\n removeCount++;\n } else {\n // Keep this frame and all subsequent frames\n break;\n }\n }\n\n // Remove closed frames from buffer\n if (removeCount > 0) {\n this.sourceFrameBuffer.splice(0, removeCount);\n }\n }\n\n /**\n * Get current conversion state (for debugging)\n */\n getState(): {\n targetFrameIndex: number;\n targetFrameTimeUs: TimeUs;\n bufferSize: number;\n frameDurationUs: number;\n } {\n return {\n targetFrameIndex: this.targetFrameIndex,\n targetFrameTimeUs: this.targetFrameTimeUs,\n bufferSize: this.sourceFrameBuffer.length,\n frameDurationUs: this.frameDurationUs,\n };\n }\n}\n","import { WorkerChannel } from '../../worker/WorkerChannel';\nimport { WorkerMessageType, WorkerState } from '../../worker/types';\nimport { VideoComposer } from './VideoComposer';\nimport type { VideoComposeConfig, ComposeRequest, Layer, ImageLayer, Transform2D } from './types';\nimport type {\n ClipInstructionSet,\n SerializedLayerPlan,\n SerializedTransitionPlan,\n SerializedImageLayerPayload,\n SerializedTextLayerPayload,\n} from './instructions';\nimport { frameDurationFromFps } from '../../utils/time-utils';\nimport { interpolateKeyframes } from '../../utils/animation-utils';\nimport { FrameRateConverter } from './FrameRateConverter';\n\ntype TimeUs = number;\n\nfunction resolveActiveLayers(\n layers: SerializedLayerPlan[],\n timestamp: number\n): SerializedLayerPlan[] {\n return layers.filter((layer) => {\n // Check if layer is active at current timestamp\n return layer.activeRanges.some(\n (range) => timestamp >= range.startUs && timestamp < range.endUs\n );\n });\n}\n\nfunction materializeLayer(\n layer: SerializedLayerPlan,\n frame: VideoFrame,\n imageMap: Map<string, ImageBitmap>,\n globalTimeUs?: number\n): Layer | null {\n const baseLayer: Layer = {\n id: layer.layerId,\n type: layer.type as any,\n zIndex: layer.zIndex ?? 0,\n visible: true,\n opacity: layer.opacity ?? 1,\n };\n\n if (layer.type === 'video') {\n return {\n ...baseLayer,\n type: 'video',\n videoFrame: frame,\n } as Layer;\n }\n\n if (layer.type === 'text') {\n const payload = layer.payload as SerializedTextLayerPayload;\n return {\n ...baseLayer,\n type: 'text',\n text: payload.text,\n localeCode: payload.localeCode,\n fontConfig: payload.fontConfig,\n animation: payload.animation,\n wordTimings: payload.wordTimings,\n letterCase: payload.letterCase,\n } as Layer;\n }\n\n if (layer.type === 'image') {\n const payload = layer.payload as SerializedImageLayerPayload;\n const resourceId = payload.resourceId;\n const source = imageMap.get(resourceId) ?? null;\n\n const imageLayer: ImageLayer = {\n ...baseLayer,\n type: 'image',\n source,\n attachmentId: payload.attachmentId,\n };\n\n // Add target dimensions if specified\n if (payload.targetWidth !== undefined) {\n (imageLayer as any).targetWidth = payload.targetWidth;\n }\n if (payload.targetHeight !== undefined) {\n (imageLayer as any).targetHeight = payload.targetHeight;\n }\n\n // If has animation config, compute current animation state\n if (payload.animation && globalTimeUs !== undefined) {\n const animState = computeAnimationState(payload.animation, globalTimeUs);\n\n // If not visible, return null to filter out\n if (!animState.visible) {\n return null;\n }\n\n // Ensure all transform fields have values for stages/compose Transform2D type\n imageLayer.transform = {\n x: animState.transform.x ?? 0,\n y: animState.transform.y ?? 0,\n scaleX: animState.transform.scaleX ?? 1,\n scaleY: animState.transform.scaleY ?? 1,\n rotation: animState.transform.rotation ?? 0,\n anchorX: animState.transform.anchorX ?? 0.5,\n anchorY: animState.transform.anchorY ?? 0.5,\n };\n if (animState.opacity !== undefined) {\n imageLayer.opacity = animState.opacity;\n }\n }\n\n return imageLayer;\n }\n\n return baseLayer;\n}\n\nfunction computeAnimationState(\n animation: NonNullable<SerializedImageLayerPayload['animation']>,\n globalTimeUs: number\n): { transform: Transform2D; opacity?: number; visible: boolean } {\n const { position, keyframes, overlayClipStartUs } = animation;\n\n // Calculate time relative to overlay clip start\n const relativeTimeUs = globalTimeUs - overlayClipStartUs;\n\n // If outside keyframe range, hide\n if (relativeTimeUs < 0 || relativeTimeUs > keyframes[keyframes.length - 1].time) {\n return {\n transform: { x: 0, y: 0, scaleX: 1, scaleY: 1, rotation: 0, anchorX: 0.5, anchorY: 0.5 },\n opacity: 0,\n visible: false,\n };\n }\n\n // Interpolate keyframes\n const animState = interpolateKeyframes(keyframes, relativeTimeUs);\n\n // Merge base position and relative transform\n // Convert rotation from degrees (model) to radians (render layer)\n const rotationDeg = animState.transform?.rotation ?? 0;\n const rotationRad = (rotationDeg * Math.PI) / 180;\n\n const finalTransform: Transform2D = {\n x: position.x + (animState.transform?.x ?? 0),\n y: position.y + (animState.transform?.y ?? 0),\n scaleX: animState.transform?.scaleX ?? 1,\n scaleY: animState.transform?.scaleY ?? 1,\n rotation: rotationRad,\n anchorX: animState.transform?.anchorX ?? 0.5,\n anchorY: animState.transform?.anchorY ?? 0.5,\n };\n\n return {\n transform: finalTransform,\n opacity: animState.opacity,\n visible: true,\n };\n}\n\n/**\n * VideoComposeWorker - Visual composition in the pipeline\n * Receives decoded video frames and outputs composed frames\n *\n * Pipeline: DecodeWorker → VideoComposeWorker → EncodeWorker\n *\n * Features:\n * - Multi-layer composition with Canvas2D/WebGL\n * - Transition effects and filters\n * - Text and image overlay support\n * - Stream-based processing with configurable backpressure\n */\nexport class VideoComposeWorker {\n private channel: WorkerChannel;\n private composer: VideoComposer | null = null;\n private composeStream: TransformStream<ComposeRequest, VideoFrame> | null = null;\n\n private sessionId: string | null = null;\n private downstreamPort: MessagePort | null = null;\n private upstreamPort: MessagePort | null = null;\n private instructions: ClipInstructionSet | null = null;\n private imageMap = new Map<string, ImageBitmap>();\n\n constructor() {\n // Initialize WorkerChannel\n this.channel = new WorkerChannel(self, {\n name: 'VideoComposeWorker',\n timeout: 30000,\n });\n\n this.setupHandlers();\n }\n\n private setupHandlers(): void {\n // Register message handlers\n this.channel.registerHandler('configure', this.handleConfigure.bind(this));\n this.channel.registerHandler('connect', this.handleConnect.bind(this));\n this.channel.registerHandler('flush', this.handleFlush.bind(this));\n // this.channel.registerHandler('get_stream', this.handleGetStream.bind(this));\n this.channel.registerHandler('get_stats', this.handleGetStats.bind(this));\n this.channel.registerHandler('install_instructions', this.handleInstallInstructions.bind(this));\n this.channel.registerHandler('receive_image', this.handleReceiveImage.bind(this));\n this.channel.registerHandler('dispose_clip', this.handleDisposeClip.bind(this));\n this.channel.registerHandler(WorkerMessageType.Dispose, this.handleDispose.bind(this));\n\n // Support receiving VideoFrame stream directly from main thread (export mode)\n this.channel.receiveStream(this.handleReceiveStream.bind(this));\n }\n\n /**\n * Unified connect handler used by stream pipeline\n */\n private async handleConnect(payload: {\n direction: 'upstream' | 'downstream';\n port: MessagePort;\n streamType: 'video' | 'audio' | 'frame' | 'chunk';\n sessionId?: string;\n }): Promise<{ success: boolean }> {\n const { port, direction, sessionId } = payload;\n\n if (sessionId && !this.sessionId) {\n this.sessionId = sessionId;\n }\n\n if (direction === 'upstream') {\n this.upstreamPort = port;\n const channel = new WorkerChannel(port, {\n name: 'VideoCompose-Decode',\n timeout: 30000,\n });\n channel.receiveStream(this.handleReceiveStream.bind(this));\n }\n if (direction === 'downstream') {\n this.downstreamPort = port;\n }\n return { success: true };\n }\n\n /**\n * Configure composer\n * According to docs/impl/14-config, only reinitialize when initial=true\n */\n private async handleConfigure(payload: {\n config: VideoComposeConfig;\n initial?: boolean;\n }): Promise<{\n success: boolean;\n config: VideoComposeConfig;\n }> {\n const { config, initial } = payload;\n const hasValidDimensions = config.width > 0 && config.height > 0;\n const hasValidFps = config.fps > 0;\n\n if (!hasValidDimensions || !hasValidFps) {\n throw new Error(\n `VideoComposeWorker: invalid canvas config width=${config.width}, height=${config.height}, fps=${config.fps}`\n );\n }\n\n // Set worker state to ready on initial configuration\n if (initial) {\n this.channel.state = WorkerState.Ready;\n }\n\n if (initial || !this.composer) {\n // Initial configuration or composer doesn't exist\n if (this.composer) {\n this.composer.dispose();\n this.composeStream = null;\n }\n\n // Create new composer\n this.composer = new VideoComposer(config);\n } else {\n // Just update configuration\n this.composer.updateConfig(config);\n }\n\n // Notify configuration complete\n this.channel.notify('configured', {\n config: this.composer.config,\n initialized: initial || false,\n });\n\n return {\n success: true,\n config: this.composer.config,\n };\n }\n\n private async handleReceiveStream(\n stream: ReadableStream,\n metadata?: Record<string, any>\n ): Promise<void> {\n if (!this.composer) {\n console.error('[VideoComposeWorker] Composer not configured');\n return;\n }\n\n // Support inline instructions from metadata (export mode)\n // This ensures instructions arrive with the stream to avoid race conditions\n if (metadata?.instructions) {\n await this.handleInstallInstructions(metadata.instructions);\n }\n\n if (!this.instructions) {\n console.error('[VideoComposeWorker] No instructions available after metadata check');\n return;\n }\n\n // Get trimStartUs from main video layer (layer without attachmentId)\n const mainLayer = this.instructions.layers.find(\n (l) => l.type === 'video' && !l.payload.attachmentId\n );\n const trimStartUs = mainLayer?.type === 'video' ? (mainLayer.payload.trimStartUs ?? 0) : 0;\n\n // Insert FrameRateConverter to convert VFR to CFR with trim support\n const timeline = this.instructions.baseConfig.timeline;\n const fpsConverter = new FrameRateConverter(\n timeline?.compositionFps ?? 30,\n timeline?.clipDurationUs ?? Infinity,\n trimStartUs\n );\n\n // Pipeline: decode stream → fps converter (VFR→CFR + trim) → filter → compose\n const cfrStream = stream.pipeThrough(fpsConverter.createStream());\n\n const filteredStream = cfrStream.pipeThrough(\n new TransformStream<VideoFrame, ComposeRequest>({\n transform: (frame, controller) => {\n try {\n const request = this.buildComposeRequest(this.instructions!, frame);\n if (!request) {\n frame.close();\n return;\n }\n controller.enqueue(request);\n } catch (error) {\n console.error('[VideoComposeWorker] buildComposeRequest error:', error);\n frame?.close?.();\n throw error;\n }\n },\n })\n );\n\n const composeStream = this.composer.createStreams();\n\n filteredStream.pipeTo(composeStream.writable).catch((error) => {\n console.error('[VideoComposeWorker] compose stream error', this.sessionId, error);\n });\n\n const meta = {\n ...metadata,\n streamType: 'video',\n sessionId: this.sessionId,\n };\n\n if (this.downstreamPort) {\n const encodeChannel = new WorkerChannel(this.downstreamPort, {\n name: 'VideoCompose-Encode',\n timeout: 30000,\n });\n encodeChannel.sendStream(composeStream.readable, meta);\n } else {\n this.channel.sendStream(composeStream.readable, meta);\n }\n }\n\n // private handleGetStream(): ReadableStream<VideoFrame> | undefined {\n // return this.composer?.createStreams()?.cacheStream;\n // }\n\n /**\n * Flush the composition pipeline\n */\n private async handleFlush(): Promise<{ success: boolean }> {\n try {\n // Flush any pending frames in the stream\n // The stream will handle this automatically\n\n this.channel.notify('flush_complete', {});\n return { success: true };\n } catch (error: any) {\n throw {\n code: 'FLUSH_ERROR',\n message: error.message,\n };\n }\n }\n\n /**\n * Get composer statistics\n */\n private async handleGetStats(): Promise<{\n configured: boolean;\n config?: VideoComposeConfig;\n streaming: boolean;\n }> {\n return {\n configured: this.composer !== null,\n config: this.composer?.config,\n streaming: this.composeStream !== null,\n };\n }\n\n /**\n * Dispose worker and cleanup resources\n */\n private async handleDispose(): Promise<{ success: boolean }> {\n if (this.composer) {\n this.composer.dispose();\n this.composer = null;\n }\n\n this.composeStream = null;\n\n this.downstreamPort?.close();\n this.upstreamPort?.close();\n this.downstreamPort = null;\n this.upstreamPort = null;\n\n this.imageMap.forEach((bitmap) => bitmap.close());\n this.imageMap.clear();\n this.instructions = null;\n\n this.channel.state = WorkerState.Disposed;\n\n return { success: true };\n }\n\n private async handleInstallInstructions(\n payload: ClipInstructionSet\n ): Promise<{ success: boolean }> {\n const { clipId, revision } = payload;\n\n if (!this.sessionId) {\n this.sessionId = clipId;\n }\n\n if (this.instructions && this.instructions.revision > revision) {\n return { success: false };\n }\n\n this.instructions = payload;\n\n return { success: true };\n }\n\n /**\n * Receive image data with instructions (aligned with video pipeline)\n * Note: ImageBitmap is required because VideoFrame constructor in Worker context\n * only accepts ImageBitmap/OffscreenCanvas, not HTMLImageElement or Blob\n */\n private async handleReceiveImage(payload: {\n resourceId: string;\n sessionId: string;\n imageBitmap: ImageBitmap;\n instructions?: ClipInstructionSet;\n }): Promise<{ success: boolean }> {\n const { resourceId, sessionId, imageBitmap, instructions } = payload;\n\n if (!this.sessionId) {\n this.sessionId = sessionId;\n }\n\n // Install instructions if provided (aligned with video pipeline metadata)\n if (instructions) {\n await this.handleInstallInstructions(instructions);\n }\n\n // Store in Map (release old value if exists)\n const existing = this.imageMap.get(resourceId);\n if (existing) {\n existing.close();\n }\n\n this.imageMap.set(resourceId, imageBitmap);\n\n // Start frame stream if this is main track image\n if (this.instructions) {\n const mainLayer = this.instructions.layers.find((l) => !l.payload.attachmentId);\n const mainResourceId = mainLayer?.payload.resourceId;\n if (resourceId === mainResourceId) {\n await this.startImageFrameStream();\n }\n }\n\n return { success: true };\n }\n\n private async handleDisposeClip(): Promise<{ success: boolean }> {\n this.instructions = null;\n\n this.downstreamPort?.close();\n this.upstreamPort?.close();\n this.downstreamPort = null;\n this.upstreamPort = null;\n\n this.imageMap.forEach((bitmap) => bitmap.close());\n this.imageMap.clear();\n\n return { success: true };\n }\n\n private async startImageFrameStream(): Promise<void> {\n if (!this.instructions || !this.composer) {\n return;\n }\n\n const timeline = this.instructions.baseConfig.timeline;\n if (!timeline) {\n return;\n }\n\n // Find main track resource ImageBitmap from Map\n const mainLayer = this.instructions.layers.find((l) => !l.payload.attachmentId);\n if (!mainLayer) return;\n\n const mainResourceId = (mainLayer.payload as any).resourceId as string;\n const imageBitmap = this.imageMap.get(mainResourceId);\n if (!imageBitmap) {\n console.warn('[VideoComposeWorker] Main track ImageBitmap not found:', mainResourceId);\n return;\n }\n\n const composeStream = this.composer.createStreams();\n\n const { clipDurationUs, compositionFps } = timeline;\n\n let currentTimeUs = 0;\n const readableStream = new ReadableStream<ComposeRequest>({\n pull: (controller) => {\n if (currentTimeUs >= clipDurationUs) {\n controller.close();\n return;\n }\n\n const videoFrame = new VideoFrame(imageBitmap, {\n timestamp: currentTimeUs,\n duration: frameDurationFromFps(compositionFps),\n });\n try {\n const request = this.buildComposeRequest(this.instructions!, videoFrame);\n if (request) {\n controller.enqueue(request);\n } else {\n videoFrame.close();\n }\n currentTimeUs += frameDurationFromFps(compositionFps);\n } catch (error) {\n videoFrame.close();\n throw error;\n }\n },\n });\n\n readableStream.pipeTo(composeStream.writable).catch((error) => {\n console.error('[VideoComposeWorker] image frame stream error', this.sessionId, error);\n });\n\n const meta = {\n streamType: 'video',\n sessionId: this.sessionId,\n };\n\n if (this.downstreamPort) {\n const encodeChannel = new WorkerChannel(this.downstreamPort, {\n name: 'VideoCompose-Encode',\n timeout: 30000,\n });\n encodeChannel.sendStream(composeStream.readable, meta);\n } else {\n this.channel.sendStream(composeStream.readable, meta);\n }\n }\n\n private buildComposeRequest(\n instruction: ClipInstructionSet,\n frame: VideoFrame\n ): ComposeRequest | null {\n const clipRelativeTime = frame.timestamp ?? 0;\n const clipDurationUs = instruction.baseConfig.timeline?.clipDurationUs ?? Infinity;\n\n // Check if frame is within clip boundary (relative time)\n if (clipRelativeTime < 0 || clipRelativeTime >= clipDurationUs) {\n return null;\n }\n\n const activeLayers = resolveActiveLayers(instruction.layers, clipRelativeTime);\n\n if (!activeLayers.length) {\n return null;\n }\n\n // Calculate global time\n const clipStartUs = instruction.baseConfig.timeline?.clipStartUs ?? 0;\n const globalTimeUs = clipStartUs + clipRelativeTime;\n\n // Materialize layers with global time\n const layers = activeLayers\n .map((layer) => materializeLayer(layer, frame, this.imageMap, globalTimeUs))\n .filter((layer): layer is Layer => layer !== null);\n\n if (!layers.length) {\n return null;\n }\n\n return {\n timeUs: clipRelativeTime,\n globalTimeUs,\n layers,\n transition: VideoComposeWorker.buildTransition(\n instruction.transitions,\n clipRelativeTime,\n instruction.baseConfig.timeline\n ),\n };\n }\n\n private static buildTransition(\n transitions: SerializedTransitionPlan[],\n timeUs: TimeUs,\n _timeline?: VideoComposeConfig['timeline']\n ) {\n const entry = transitions.find((transition) => {\n const { startUs, endUs } = transition.range;\n return timeUs >= startUs && timeUs < endUs;\n });\n if (!entry) {\n return undefined;\n }\n const durationUs = entry.range.endUs - entry.range.startUs;\n const progress = durationUs > 0 ? (timeUs - entry.range.startUs) / durationUs : 0;\n return {\n type: entry.params.type,\n progress: Math.min(Math.max(progress, 0), 1),\n easing: entry.params.easing,\n params: entry.params.payload,\n direction: entry.params.payload?.direction,\n } as any;\n }\n}\n\n// Initialize worker\nconst worker = new VideoComposeWorker();\n\n// Handle worker termination\nself.addEventListener('beforeunload', () => {\n worker['handleDispose']();\n});\n\nexport default null; // Required for TypeScript worker compilation\n"],"names":["calculateYPosition","usToFrame","idx","frame"],"mappings":";AAAO,SAAS,iBACd,KACA,MACA,UACA,YACA,aAA8B,KACtB;AACR,MAAI,KAAA;AACJ,MAAI,OAAO,GAAG,UAAU,IAAI,QAAQ,MAAM,UAAU;AACpD,QAAM,UAAU,IAAI,YAAY,IAAI;AACpC,MAAI,QAAA;AACJ,SAAO,QAAQ;AACjB;AAEO,SAAS,kBAAkB,MAAc,YAAiD;AAC/F,MAAI,eAAe,SAAS;AAC1B,WAAO,KAAK,YAAA;AAAA,EACd;AACA,MAAI,eAAe,SAAS;AAC1B,WAAO,KAAK,YAAA;AAAA,EACd;AACA,SAAO;AACT;ACpBA,SAAS,mBAAmB,MAAwB;AAClD,QAAM,cAAc,CAAC,CAAC;AACtB,QAAM,QAAQ,MAAM,KAAK,IAAI;AAE7B,WAAS,IAAI,GAAG,IAAI,MAAM,SAAS,GAAG,KAAK;AACzC,QAAI,eAAe,KAAK,MAAM,CAAC,CAAE,GAAG;AAClC,kBAAY,KAAK,IAAI,CAAC;AAAA,IACxB,WACE,4CAA4C,KAAK,MAAM,CAAC,CAAE,KAC1D,4CAA4C,KAAK,MAAM,IAAI,CAAC,CAAE,GAC9D;AACA,kBAAY,KAAK,IAAI,CAAC;AAAA,IACxB,WAAW,iBAAiB,KAAK,MAAM,CAAC,CAAE,GAAG;AAC3C,kBAAY,KAAK,IAAI,CAAC;AAAA,IACxB,WAAW,KAAK,KAAK,MAAM,CAAC,CAAE,KAAK,WAAW,KAAK,MAAM,IAAI,CAAC,CAAE,GAAG;AACjE,kBAAY,KAAK,IAAI,CAAC;AAAA,IACxB;AAAA,EACF;AAEA,cAAY,KAAK,MAAM,MAAM;AAC7B,SAAO;AACT;AAEA,SAAS,gBACP,OACA,KACA,UACA,YACA,YACQ;AACR,MAAI,MAAM,UAAU,EAAG,QAAO;AAC9B,QAAM,UAAU,MAAM;AAAA,IAAI,CAAC,SACzB,iBAAiB,KAAK,MAAM,UAAU,YAAY,UAAU;AAAA,EAAA;AAE9D,QAAM,YAAY,QAAQ,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC,IAAI,QAAQ;AAC/D,SAAO,QAAQ,OAAO,CAAC,KAAK,QAAQ,MAAM,KAAK,IAAI,MAAM,SAAS,GAAG,CAAC;AACxE;AAEA,SAAS,+BACP,KACA,MACA,OACA,gBACA,cACA,UACA,UACA,YACA,YACA,aAIA;AACA,MAAI,YAAsB,CAAA;AAC1B,MAAI,cAAc;AAElB,MAAI,mBAAmB,GAAG;AACxB,UAAM,WAAW,KAAK,MAAM,KAAK,EAAE,KAAA;AACnC,UAAM,gBAAgB,iBAAiB,KAAK,UAAU,UAAU,YAAY,UAAU;AAEtF,QAAI,iBAAiB,UAAU;AAC7B,YAAM,WAAW,CAAC,GAAG,cAAc,QAAQ;AAC3C,YAAM,UAAU,gBAAgB,UAAU,KAAK,UAAU,YAAY,UAAU;AAE/E,UAAI,UAAU,aAAa;AACzB,sBAAc;AACd,oBAAY;AAAA,MACd;AAAA,IACF,OAAO;AACL,YAAM,QAAQ,SAAS,MAAM,KAAK;AAClC,UAAI,cAAc;AAClB,UAAI,YAAY,CAAC,GAAG,YAAY;AAEhC,iBAAW,QAAQ,OAAO;AACxB,cAAM,WAAW,cAAc,GAAG,WAAW,IAAI,IAAI,KAAK;AAC1D,cAAM,YAAY,iBAAiB,KAAK,UAAU,UAAU,YAAY,UAAU;AAElF,YAAI,aAAa,UAAU;AACzB,wBAAc;AAAA,QAChB,OAAO;AACL,cAAI,aAAa;AACf,sBAAU,KAAK,WAAW;AAC1B,0BAAc;AAAA,UAChB,OAAO;AACL,sBAAU,KAAK,IAAI;AACnB,0BAAc;AAAA,UAChB;AAAA,QACF;AAAA,MACF;AAEA,UAAI,aAAa;AACf,kBAAU,KAAK,WAAW;AAAA,MAC5B;AAEA,YAAM,UAAU,gBAAgB,WAAW,KAAK,UAAU,YAAY,UAAU;AAChF,UAAI,UAAU,aAAa;AACzB,sBAAc;AACd,oBAAY;AAAA,MACd;AAAA,IACF;AACA,WAAO,EAAE,WAAW,YAAA;AAAA,EACtB;AAEA,MAAI,kBAAkB;AAEtB,WAAS,IAAI,GAAG,IAAI,YAAY,QAAQ,KAAK;AAC3C,UAAM,KAAK,YAAY,CAAC;AACxB,QAAI,MAAM,SAAS,MAAM,KAAK,OAAQ;AAEtC,UAAM,OAAO,KAAK,MAAM,OAAO,EAAE,EAAE,KAAA;AACnC,UAAM,YAAY,iBAAiB,KAAK,MAAM,UAAU,YAAY,UAAU;AAE9E,QAAI,aAAa,UAAU;AACzB,wBAAkB;AAClB,YAAM,SAAS;AAAA,QACb;AAAA,QACA;AAAA,QACA;AAAA,QACA,iBAAiB;AAAA,QACjB,CAAC,GAAG,cAAc,IAAI;AAAA,QACtB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MAAA;AAEF,UAAI,OAAO,cAAc,aAAa;AACpC,sBAAc,OAAO;AACrB,oBAAY,OAAO;AAAA,MACrB;AAAA,IACF;AAAA,EACF;AAEA,MAAI,CAAC,iBAAiB;AACpB,UAAM,cAAc,KAAK,MAAM,KAAK;AACpC,UAAM,QAAQ,YAAY,MAAM,KAAK;AACrC,QAAI,cAAc;AAClB,QAAI,YAAY,CAAC,GAAG,YAAY;AAEhC,eAAW,QAAQ,OAAO;AACxB,YAAM,WAAW,cAAc,GAAG,WAAW,IAAI,IAAI,KAAK;AAC1D,YAAM,YAAY,iBAAiB,KAAK,UAAU,UAAU,YAAY,UAAU;AAElF,UAAI,aAAa,UAAU;AACzB,sBAAc;AAAA,MAChB,OAAO;AACL,YAAI,aAAa;AACf,oBAAU,KAAK,WAAW;AAC1B,wBAAc;AAAA,QAChB,OAAO;AACL,oBAAU,KAAK,IAAI;AAAA,QACrB;AAAA,MACF;AAAA,IACF;AAEA,QAAI,aAAa;AACf,gBAAU,KAAK,WAAW;AAAA,IAC5B;AAEA,gBAAY;AAAA,EACd;AAEA,SAAO,EAAE,WAAW,YAAA;AACtB;AAEO,SAAS,SACd,KACA,MACA,UACA,UACA,YACA,aAA8B,KACpB;AACV,QAAM,YAAY,iBAAiB,KAAK,MAAM,UAAU,YAAY,UAAU;AAC9E,MAAI,aAAa,UAAU;AACzB,WAAO,CAAC,IAAI;AAAA,EACd;AAEA,QAAM,iBAAiB,KAAK,KAAK,YAAY,QAAQ;AACrD,QAAM,cAAc,mBAAmB,IAAI;AAE3C,QAAM,EAAE,cAAc;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,CAAA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAGF,SAAO,UAAU,SAAS,IAAI,YAAY,CAAC,IAAI;AACjD;AAEO,SAAS,mBACd,KACA,OACA,UACA,UACA,YACA,YACA,aAA8B,KACpB;AACV,QAAM,SAAmB,CAAA;AACzB,MAAI,mBAAmB;AACvB,QAAM,aAAa,iBAAiB,KAAK,KAAK,UAAU,YAAY,UAAU;AAC9E,MAAI,cAAc;AAElB,aAAW,QAAQ,OAAO;AACxB,QAAI,YAAY,iBAAiB,KAAK,MAAM,UAAU,YAAY,UAAU;AAC5E,QAAI,YAAY;AACd,mBAAa;AAAA,IACf;AACA,QAAI,YAAY,oBAAoB,UAAU;AAC5C,qBAAe,QAAQ,aAAa,MAAM;AAC1C,0BAAoB;AAAA,IACtB,OAAO;AACL,UAAI,aAAa;AACf,eAAO,KAAK,WAAW;AAAA,MACzB;AACA,oBAAc,QAAQ,aAAa,MAAM;AACzC,yBAAmB;AAAA,IACrB;AAAA,EACF;AACA,MAAI,gBAAgB,IAAI;AACtB,WAAO,KAAK,WAAW;AAAA,EACzB;AACA,SAAO;AACT;AAEO,SAAS,uBACd,KACA,OACA,UACA,UACA,YACA,YACA,aAA8B,KACpB;AACV,MAAI,WAAW,WAAW;AAC1B,aAAW,QAAQ,OAAO;AACxB,UAAM,YAAY,iBAAiB,KAAK,MAAM,UAAU,YAAY,UAAU;AAC9E,QAAI,YAAY,UAAU;AACxB,iBAAW;AAAA,IACb;AAAA,EACF;AAEA,QAAM,eAAe;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,EACA;AAEF,MAAI,YAAY;AAChB,MAAI,YAAY;AAChB,WAAS,QAAQ,UAAU,SAAS,UAAU,SAAS,GAAG;AACxD,UAAM,QAAQ;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAEF,QAAI,MAAM,SAAS,cAAc;AAC/B;AAAA,IACF;AACA,QAAI,eAAe;AACnB,QAAI,eAAe;AACnB,eAAW,QAAQ,OAAO;AACxB,YAAM,YAAY,iBAAiB,KAAK,MAAM,UAAU,YAAY,UAAU;AAC9E,UAAI,YAAY,cAAc;AAC5B,uBAAe;AAAA,MACjB;AACA,UAAI,YAAY,cAAc;AAC5B,uBAAe;AAAA,MACjB;AAAA,IACF;AACA,UAAM,QAAQ,eAAe;AAC7B,QAAI,QAAQ,WAAW;AACrB,kBAAY;AACZ,kBAAY;AAAA,IACd;AAAA,EACF;AAEA,SAAO,mBAAmB,KAAK,OAAO,WAAW,UAAU,YAAY,YAAY,UAAU;AAC/F;ACjSO,SAAS,aAAa,OAAe,QAA8B;AACxE,QAAM,EAAE,SAAS,MAAM,WAAW,oBAAoB,UAAU;AAEhE,MAAI,SAAS,EAAG,QAAO;AAEvB,QAAM,OAAO,WAAW,IAAI,KAAK,KAAK,OAAO,SAAS;AACtD,QAAM,QAAQ,KAAK,KAAK,YAAY,IAAI;AACxC,QAAM,IAAI,QAAQ;AAElB,MAAI;AAEJ,MAAI,OAAO,GAAG;AACZ,UAAM,SAAS,QAAQ,KAAK,KAAK,IAAI,OAAO,IAAI;AAChD,UAAM,IAAI;AACV,UAAM,IAAK,OAAO,QAAS;AAC3B,YAAQ,IAAI,KAAK,IAAI,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI,KAAK,IAAI,SAAS,CAAC,IAAI,IAAI,KAAK,IAAI,SAAS,CAAC;AAAA,EAC/F,WAAW,SAAS,GAAG;AACrB,YAAQ,IAAI,KAAK,IAAI,CAAC,QAAQ,CAAC,KAAK,IAAI,QAAQ;AAAA,EAClD,OAAO;AACL,UAAM,KAAK,CAAC,SAAS,OAAO,KAAK,KAAK,OAAO,OAAO,CAAC;AACrD,UAAM,KAAK,CAAC,SAAS,OAAO,KAAK,KAAK,OAAO,OAAO,CAAC;AACrD,UAAM,IAAI,MAAM,KAAK;AACrB,UAAM,IAAI,IAAI;AACd,YAAQ,IAAI,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,IAAI,KAAK,CAAC;AAAA,EACxD;AAEA,MAAI,qBAAqB,QAAQ,GAAG;AAClC,WAAO;AAAA,EACT;AAEA,SAAO,KAAK,IAAI,GAAG,KAAK;AAC1B;AAEO,SAAS,YACd,OACA,YACA,aACA,SAIQ;AACR,QAAM,EAAE,kBAAkB,UAAU,mBAAmB,SAAA,IAAa,WAAW,CAAA;AAE/E,QAAM,CAAC,UAAU,QAAQ,IAAI;AAC7B,QAAM,CAAC,WAAW,SAAS,IAAI;AAE/B,MAAI,QAAQ,UAAU;AACpB,QAAI,oBAAoB,SAAS;AAC/B,aAAO;AAAA,IACT;AAAA,EACF;AAEA,MAAI,QAAQ,UAAU;AACpB,QAAI,qBAAqB,SAAS;AAChC,aAAO;AAAA,IACT;AAAA,EACF;AAEA,QAAM,aAAa,WAAW;AAC9B,MAAI,eAAe,GAAG;AACpB,WAAO;AAAA,EACT;AAEA,QAAM,YAAY,QAAQ,YAAY;AACtC,QAAM,cAAc,YAAY;AAEhC,SAAO,YAAY,WAAW;AAChC;AAEA,SAAS,SAAS,OAA2D;AAC3E,QAAM,QAAQ,MAAM,MAAM,gCAAgC;AAC1D,MAAI,OAAO;AACT,WAAO;AAAA,MACL,GAAG,SAAS,MAAM,CAAC,GAAI,EAAE;AAAA,MACzB,GAAG,SAAS,MAAM,CAAC,GAAI,EAAE;AAAA,MACzB,GAAG,SAAS,MAAM,CAAC,GAAI,EAAE;AAAA,IAAA;AAAA,EAE7B;AACA,SAAO;AACT;AAEO,SAAS,iBAAiB,QAAgB,QAAgB,UAA0B;AACzF,QAAM,OAAO,SAAS,MAAM;AAC5B,QAAM,OAAO,SAAS,MAAM;AAE5B,MAAI,CAAC,QAAQ,CAAC,MAAM;AAClB,WAAO;AAAA,EACT;AAEA,QAAM,IAAI,KAAK,MAAM,YAAY,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC;AACpE,QAAM,IAAI,KAAK,MAAM,YAAY,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC;AACpE,QAAM,IAAI,KAAK,MAAM,YAAY,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC;AAEpE,SAAO,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;AAC7B;ACpGA,MAAM,YAAY;AAEX,SAAS,uBAAuB,QAA6B,MAAwB;AAC1F,MAAI,MAAM;AACR,UAAM,aAAa,KAAK,MAAM,SAAS;AACvC,UAAM,WAAW,aAAa,WAAW,SAAS;AAElD,QAAI,WAAW,KAAK,WAAW,KAAK,UAAU,KAAK;AACjD,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAEA,SAAO,CAAC,CAAC,SAAS,SAAS,OAAO,EAAE,SAAS,MAAM;AACrD;ACVA,SAASA,qBACP,cACA,aACA,gBAUQ;AACR,MAAI,CAAC,gBAAgB;AACnB,WAAO,eAAe,IAAI,cAAc;AAAA,EAC1C;AAGA,MAAI,eAAe,KAAK;AACtB,UAAM,aAAa,WAAW,eAAe,GAAG,IAAI;AACpD,WAAO,eAAe;AAAA,EACxB;AAEA,MAAI,eAAe,QAAQ;AACzB,UAAM,gBAAgB,WAAW,eAAe,MAAM,IAAI;AAC1D,WAAO,gBAAgB,IAAI,iBAAiB;AAAA,EAC9C;AAGA,MAAI,eAAe,mBAAmB,YAAY,eAAe,eAAe,UAAU;AACxF,WAAO,eAAe,IAAI,cAAc;AAAA,EAC1C;AAGA,SAAO,eAAe,IAAI,cAAc;AAC1C;AAEO,SAAS,gBACd,KACA,OACA,aACA,cACA,gBACM;AACN,QAAM,aAAa,MAAM,YAAY;AACrC,MAAI,CAAC,WAAY;AAEjB,QAAM,WAAW,WAAW;AAC5B,QAAM,aAAa,WAAW;AAC9B,QAAM,aAAa,WAAW;AAC9B,QAAM,OAAO,WAAW;AACxB,QAAM,SAAS,WAAW;AAC1B,QAAM,cAAc,WAAW,eAAe;AAC9C,QAAM,aAAa,WAAW,cAAc;AAE5C,QAAM,WAAW,cAAc;AAC/B,QAAM,OAAO,kBAAkB,MAAM,MAAM,MAAM,UAAU;AAE3D,MAAI;AACJ,MAAI,MAAM,eAAe,MAAM,YAAY,SAAS,GAAG;AACrD,UAAM,aAAa,uBAAuB,MAAM,cAAc,SAAS,IAAI;AAC3E,UAAM,QAAQ,KAAK,MAAM,aAAa,QAAQ,EAAE;AAChD,YAAQ;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,EAEJ,OAAO;AACL,YAAQ,SAAS,KAAK,MAAM,UAAU,UAAU,YAAY,UAAU;AAAA,EACxE;AAEA,MAAI,KAAA;AACJ,MAAI,OAAO,GAAG,UAAU,IAAI,QAAQ,MAAM,UAAU;AACpD,MAAI,YAAY;AAChB,MAAI,eAAe;AACnB,MAAI,WAAW;AACf,MAAI,UAAU;AAEd,QAAM,cAAc,MAAM,SAAS,WAAW;AAC9C,QAAM,SAASA,qBAAmB,cAAc,aAAa,MAAM,YAAY,cAAc;AAE7F,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,UAAM,OAAO,MAAM,CAAC;AACpB,UAAM,IAAI,SAAS,IAAI,WAAW,aAAa,WAAW;AAE1D,QAAI,UAAU,cAAc,GAAG;AAC7B,UAAI,cAAc;AAClB,UAAI,YAAY;AAChB,UAAI,WAAW,MAAM,cAAc,GAAG,CAAC;AAAA,IACzC;AACA,QAAI,YAAY;AAChB,QAAI,SAAS,MAAM,cAAc,GAAG,CAAC;AAAA,EACvC;AAEA,MAAI,QAAA;AACN;AAEO,SAAS,uBACd,KACA,OACA,aACA,cACA,eACM;AACN,QAAM,aAAa,MAAM,YAAY;AACrC,MAAI,CAAC,WAAY;AAEjB,QAAM,WAAW,aAAa,eAAe;AAAA,IAC3C,SAAS;AAAA,IACT,MAAM;AAAA,IACN,WAAW;AAAA,EAAA,CACZ;AAED,QAAM,UAAU,YAAY,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACpD,QAAM,QAAQ,YAAY,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AAEpD,MAAI,KAAA;AACJ,MAAI,cAAc;AAClB,MAAI,UAAU,cAAc,GAAG,eAAe,CAAC;AAC/C,MAAI,MAAM,OAAO,KAAK;AACtB,MAAI,UAAU,CAAC,cAAc,GAAG,CAAC,eAAe,CAAC;AAEjD,kBAAgB,KAAK,OAAO,aAAa,YAA2B;AAEpE,MAAI,QAAA;AACN;ACzHA,SAASC,YAAU,IAAY,KAAqB;AAClD,SAAO,KAAK,MAAM,MAAM,MAAU,IAAI;AACxC;AAEA,SAASD,qBACP,cACA,aACA,gBAUQ;AACR,MAAI,CAAC,gBAAgB;AACnB,WAAO,eAAe,IAAI,cAAc;AAAA,EAC1C;AAEA,MAAI,eAAe,KAAK;AACtB,UAAM,aAAa,WAAW,eAAe,GAAG,IAAI;AACpD,WAAO,eAAe;AAAA,EACxB;AAEA,MAAI,eAAe,QAAQ;AACzB,UAAM,gBAAgB,WAAW,eAAe,MAAM,IAAI;AAC1D,WAAO,gBAAgB,IAAI,iBAAiB;AAAA,EAC9C;AAEA,MAAI,eAAe,mBAAmB,YAAY,eAAe,eAAe,UAAU;AACxF,WAAO,eAAe,IAAI,cAAc;AAAA,EAC1C;AAEA,SAAO,eAAe,IAAI,cAAc;AAC1C;AAEO,SAAS,iBACd,KACA,OACA,aACA,cACA,eACA,MAAc,IACR;AACN,QAAM,aAAa,MAAM,YAAY;AACrC,MAAI,CAAC,WAAY;AAEjB,QAAM,WAAW,WAAW;AAC5B,QAAM,aAAa,WAAW;AAC9B,QAAM,aAAa,WAAW;AAC9B,QAAM,OAAO,WAAW;AACxB,QAAM,SAAS,WAAW;AAC1B,QAAM,cAAc,WAAW,eAAe;AAC9C,QAAM,aAAa,WAAW,cAAc;AAE5C,QAAM,gBAAgB,MAAM,WAAW,oBAAoB,QAAQ;AACnE,QAAM,kBAAkB,MAAM,WAAW,oBAAoB,UAAU;AAEvE,QAAM,WAAW,cAAc;AAC/B,QAAM,OAAO,kBAAkB,MAAM,MAAM,MAAM,UAAU;AAC3D,QAAM,aAAa,uBAAuB,MAAM,cAAc,SAAS,IAAI;AAC3E,QAAM,QAAQ,KAAK,MAAM,aAAa,QAAQ,EAAE;AAChD,QAAM,QAAQ;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAGF,QAAM,gBAAgC,CAAA;AACtC,MAAI,YAAY;AAEhB,QAAM,cAAc,MAAM,SAAS,WAAW;AAC9C,QAAM,SAASA,qBAAmB,cAAc,aAAa,MAAM,YAAY,cAAc;AAE7F,WAAS,YAAY,GAAG,YAAY,MAAM,QAAQ,aAAa;AAC7D,UAAM,OAAO,MAAM,SAAS;AAC5B,UAAM,YAAY,KAAK,MAAM,aAAa,QAAQ,EAAE;AACpD,UAAM,IAAI,SAAS,YAAY,WAAW,aAAa,WAAW;AAElE,UAAM,YAAY,iBAAiB,KAAK,MAAM,UAAU,YAAY,UAAU;AAC9E,QAAI,WAAW,cAAc,IAAI,YAAY;AAE7C,eAAW,QAAQ,WAAW;AAC5B,YAAM,YAAY,iBAAiB,KAAK,MAAM,UAAU,YAAY,UAAU;AAC9E,YAAM,eAAe,MAAM,cAAc,SAAS;AAElD,YAAM,aAAa,eACf;AAAA,QACE,YAAYC,YAAU,aAAa,SAAS,GAAG;AAAA,QAC/C,UAAUA,YAAU,aAAa,OAAO,GAAG;AAAA,MAAA,IAE7C;AAEJ,oBAAc,KAAK;AAAA,QACjB,MAAM;AAAA,QACN,GAAG,WAAW,YAAY;AAAA,QAC1B;AAAA,QACA;AAAA,QACA;AAAA,QACA,QAAQ;AAAA,MAAA,CACT;AAED,kBACE,aAAa,aAAa,iBAAiB,KAAK,KAAK,UAAU,YAAY,UAAU,IAAI;AAC3F;AAAA,IACF;AAAA,EACF;AAEA,MAAI,KAAA;AACJ,MAAI,OAAO,GAAG,UAAU,IAAI,QAAQ,MAAM,UAAU;AACpD,MAAI,YAAY;AAChB,MAAI,eAAe;AACnB,MAAI,WAAW;AACf,MAAI,UAAU;AAEd,aAAW,WAAW,eAAe;AACnC,QAAI,cAAc;AAClB,QAAI,gBAAgB;AAEpB,QAAI,QAAQ,QAAQ;AAClB,YAAM,EAAE,YAAY,SAAA,IAAa,QAAQ;AAEzC,UAAI,iBAAiB,cAAc,iBAAiB,UAAU;AAC5D,cAAM,uBAAuB;AAAA,UAC3B;AAAA,UACA,CAAC,YAAY,aAAa,CAAC;AAAA,UAC3B,CAAC,GAAG,CAAC;AAAA,UACL;AAAA,YACE,iBAAiB;AAAA,YACjB,kBAAkB;AAAA,UAAA;AAAA,QACpB;AAGF,sBAAc,iBAAiB,MAAM,eAAe,oBAAoB;AACxE,YAAI,UAAU,iBAAiB;AAC7B,0BAAgB,iBAAiB,QAAQ,iBAAiB,oBAAoB;AAAA,QAChF;AAAA,MACF,WAAW,gBAAgB,UAAU;AACnC,cAAM,wBAAwB,YAAY,eAAe,CAAC,UAAU,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG;AAAA,UACzF,iBAAiB;AAAA,UACjB,kBAAkB;AAAA,QAAA,CACnB;AAED,sBAAc,iBAAiB,MAAM,eAAe,qBAAqB;AACzE,YAAI,UAAU,iBAAiB;AAC7B,0BAAgB,iBAAiB,QAAQ,iBAAiB,qBAAqB;AAAA,QACjF;AAAA,MACF;AAAA,IACF;AAEA,QAAI,iBAAiB,cAAc,GAAG;AACpC,UAAI,cAAc;AAClB,UAAI,YAAY;AAChB,UAAI,WAAW,QAAQ,MAAM,QAAQ,GAAG,QAAQ,CAAC;AAAA,IACnD;AACA,QAAI,YAAY;AAChB,QAAI,SAAS,QAAQ,MAAM,QAAQ,GAAG,QAAQ,CAAC;AAAA,EACjD;AAEA,MAAI,QAAA;AACN;AC3KA,SAASA,YAAU,IAAY,KAAqB;AAClD,SAAO,KAAK,MAAM,MAAM,MAAU,IAAI;AACxC;AAEA,SAASD,qBACP,cACA,aACA,gBAUQ;AACR,MAAI,CAAC,gBAAgB;AACnB,WAAO,eAAe,IAAI,cAAc;AAAA,EAC1C;AAEA,MAAI,eAAe,KAAK;AACtB,UAAM,aAAa,WAAW,eAAe,GAAG,IAAI;AACpD,WAAO,eAAe;AAAA,EACxB;AAEA,MAAI,eAAe,QAAQ;AACzB,UAAM,gBAAgB,WAAW,eAAe,MAAM,IAAI;AAC1D,WAAO,gBAAgB,IAAI,iBAAiB;AAAA,EAC9C;AAEA,MAAI,eAAe,mBAAmB,YAAY,eAAe,eAAe,UAAU;AACxF,WAAO,eAAe,IAAI,cAAc;AAAA,EAC1C;AAEA,SAAO,eAAe,IAAI,cAAc;AAC1C;AAEO,SAAS,mBACd,KACA,OACA,aACA,cACA,eACA,MAAc,IACR;AACN,QAAM,aAAa,MAAM,YAAY;AACrC,MAAI,CAAC,WAAY;AAEjB,QAAM,WAAW,WAAW;AAC5B,QAAM,aAAa,WAAW;AAC9B,QAAM,aAAa,WAAW;AAC9B,QAAM,WAAW,WAAW;AAC5B,QAAM,SAAS,WAAW;AAC1B,QAAM,cAAc,WAAW,eAAe;AAC9C,QAAM,aAAa,WAAW,cAAc;AAE5C,QAAM,gBAAgB,MAAM,WAAW,oBAAoB,QAAQ;AACnE,QAAM,YAAY,MAAM,WAAW,aAAa;AAChD,QAAM,gBAAgB,MAAM,WAAW,iBAAiB;AACxD,QAAM,mBAAmB,MAAM,WAAW,oBAAoB;AAE9D,QAAM,WAAW,cAAc;AAC/B,QAAM,OAAO,kBAAkB,MAAM,MAAM,MAAM,UAAU;AAC3D,QAAM,aAAa,uBAAuB,MAAM,cAAc,SAAS,IAAI;AAC3E,QAAM,mBAAsC,CAAA;AAE5C,MAAI,MAAM,eAAe,MAAM,YAAY,SAAS,GAAG;AACrD,QAAI,YAAY;AAEhB,aAAS,YAAY,GAAG,YAAY,MAAM,YAAY,QAAQ,aAAa;AACzE,YAAM,OAAO,MAAM,YAAY,SAAS;AACxC,YAAM,YAAY,KAAK,KAAK,MAAM,EAAE;AACpC,YAAM,iBAAiBC,YAAU,KAAK,SAAS,GAAG;AAClD,YAAM,eAAeA,YAAU,KAAK,OAAO,GAAG;AAC9C,YAAM,gBACJ,UAAU,SAAS,KAAK,eAAe,kBAAkB,UAAU,SAAS;AAE9E,eAAS,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK;AACzC,cAAM,iBAAiB,KAAK,MAAM,iBAAiB,IAAI,aAAa;AACpE,yBAAiB,KAAK;AAAA,UACpB,MAAM,UAAU,CAAC;AAAA,UACjB,OAAO;AAAA,UACP,YAAY;AAAA,QAAA,CACb;AACD;AAAA,MACF;AAEA,UAAI,cAAc,YAAY,MAAM,YAAY,SAAS,GAAG;AAC1D,cAAM,WAAW,MAAM,YAAY,YAAY,CAAC;AAChD,cAAM,oBAAoB,UAAU,OAAO,CAAC,KAAK;AACjD,cAAM,gBAAgB,YAAY,KAAK,iBAAiB;AAExD,YAAI,CAAC,eAAe;AAClB,gBAAM,kBAAkB,iBAAiB,iBAAiB,SAAS,CAAC,GAAG,cAAc;AACrF,2BAAiB,KAAK;AAAA,YACpB,MAAM;AAAA,YACN,OAAO;AAAA,YACP,YAAY;AAAA,UAAA,CACb;AACD;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF,OAAO;AACL,UAAM,cAAc;AACpB,UAAM,QAAQ,KAAK,MAAM,EAAE;AAC3B,UAAM,gBAAgB,MAAM,SAAS,IAAI,cAAc,MAAM,SAAS;AAEtE,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,uBAAiB,KAAK;AAAA,QACpB,MAAM,MAAM,CAAC;AAAA,QACb,OAAO;AAAA,QACP,YAAY,KAAK,MAAM,IAAI,aAAa;AAAA,MAAA,CACzC;AAAA,IACH;AAAA,EACF;AAEA,QAAM,WAAW,iBAAiB,IAAI,CAAC,OAAO,GAAG,IAAI,EAAE,KAAK,EAAE;AAC9D,QAAM,gBAAgB,SAAS,KAAK,UAAU,UAAU,UAAU,YAAY,UAAU;AAExF,MAAI,KAAA;AACJ,MAAI,OAAO,GAAG,UAAU,IAAI,QAAQ,MAAM,UAAU;AACpD,MAAI,YAAY;AAChB,MAAI,eAAe;AACnB,MAAI,WAAW;AACf,MAAI,UAAU;AAEd,QAAM,cAAc,cAAc,SAAS,WAAW;AACtD,QAAM,SAASD,qBAAmB,cAAc,aAAa,MAAM,YAAY,cAAc;AAE7F,MAAI,kBAAkB;AAEtB,WAAS,YAAY,GAAG,YAAY,cAAc,QAAQ,aAAa;AACrE,UAAM,OAAO,cAAc,SAAS;AACpC,UAAM,IAAI,SAAS,YAAY,WAAW,aAAa,WAAW;AAClE,UAAM,YAAY,iBAAiB,KAAK,MAAM,UAAU,YAAY,UAAU;AAC9E,QAAI,WAAW,cAAc,IAAI,YAAY;AAE7C,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,YAAM,OAAO,KAAK,CAAC;AACnB,YAAM,SAAS,iBAAiB,eAAe;AAE/C,UAAI,QAAQ;AACV,cAAM,aAAa,iBAAiB,OAAO;AAC3C,cAAM,qBACJ,cAAc,gBAAgB,OAAO,aAAa;AAEpD,YAAI,YAAY,aAAa,gBAAgB;AAE7C,YAAI,oBAAoB;AACtB,cAAI,cAAc;AAClB,cAAI,aAAa,gBAAgB;AAAA,QACnC,OAAO;AACL,cAAI,aAAa;AAAA,QACnB;AAEA,YAAI,UAAU,cAAc,GAAG;AAC7B,cAAI,cAAc;AAClB,cAAI,YAAY;AAChB,cAAI,WAAW,MAAM,UAAU,CAAC;AAAA,QAClC;AACA,YAAI,SAAS,MAAM,UAAU,CAAC;AAC9B,YAAI,aAAa;AAAA,MACnB;AAEA,kBAAY,iBAAiB,KAAK,MAAM,UAAU,YAAY,UAAU;AACxE;AAAA,IACF;AAAA,EACF;AAEA,MAAI,QAAA;AACN;ACxKA,SAAS,UAAU,IAAY,KAAqB;AAClD,SAAO,KAAK,MAAM,MAAM,MAAU,IAAI;AACxC;AAEA,SAAS,mBACP,cACA,aACA,gBAUQ;AACR,MAAI,CAAC,gBAAgB;AACnB,WAAO,eAAe,IAAI,cAAc;AAAA,EAC1C;AAEA,MAAI,eAAe,KAAK;AACtB,UAAM,aAAa,WAAW,eAAe,GAAG,IAAI;AACpD,WAAO,eAAe;AAAA,EACxB;AAEA,MAAI,eAAe,QAAQ;AACzB,UAAM,gBAAgB,WAAW,eAAe,MAAM,IAAI;AAC1D,WAAO,gBAAgB,IAAI,iBAAiB;AAAA,EAC9C;AAEA,MAAI,eAAe,mBAAmB,YAAY,eAAe,eAAe,UAAU;AACxF,WAAO,eAAe,IAAI,cAAc;AAAA,EAC1C;AAEA,SAAO,eAAe,IAAI,cAAc;AAC1C;AAEO,SAAS,sBACd,KACA,OACA,aACA,cACA,eACA,MAAc,IACR;AACN,QAAM,aAAa,MAAM,YAAY;AACrC,MAAI,CAAC,WAAY;AAEjB,QAAM,WAAW,WAAW;AAC5B,QAAM,aAAa,WAAW;AAC9B,QAAM,aAAa,WAAW;AAC9B,QAAM,OAAO,WAAW;AACxB,QAAM,SAAS,WAAW;AAC1B,QAAM,cAAc,WAAW,eAAe;AAC9C,QAAM,aAAa,WAAW,cAAc;AAE5C,QAAM,2BAA2B,MAAM,WAAW,kBAAkB;AAEpE,QAAM,WAAW,cAAc;AAC/B,QAAM,OAAO,kBAAkB,MAAM,MAAM,MAAM,UAAU;AAC3D,QAAM,aAAa,uBAAuB,MAAM,cAAc,SAAS,IAAI;AAC3E,QAAM,QAAQ,KAAK,MAAM,aAAa,QAAQ,EAAE;AAChD,QAAM,QAAQ;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAGF,QAAM,gBAAgC,CAAA;AACtC,MAAI,YAAY;AAEhB,QAAM,cAAc,MAAM,SAAS,WAAW;AAC9C,QAAM,SAAS,mBAAmB,cAAc,aAAa,MAAM,YAAY,cAAc;AAE7F,WAAS,YAAY,GAAG,YAAY,MAAM,QAAQ,aAAa;AAC7D,UAAM,OAAO,MAAM,SAAS;AAC5B,UAAM,YAAY,KAAK,MAAM,aAAa,QAAQ,EAAE;AACpD,UAAM,IAAI,SAAS,YAAY,WAAW,aAAa,WAAW;AAElE,UAAM,YAAY,iBAAiB,KAAK,MAAM,UAAU,YAAY,UAAU;AAC9E,QAAI,WAAW,cAAc,IAAI,YAAY;AAE7C,eAAW,QAAQ,WAAW;AAC5B,YAAM,YAAY,iBAAiB,KAAK,MAAM,UAAU,YAAY,UAAU;AAC9E,YAAM,eAAe,MAAM,cAAc,SAAS;AAElD,YAAM,aAAa,eACf;AAAA,QACE,YAAY,UAAU,aAAa,SAAS,GAAG;AAAA,QAC/C,UAAU,UAAU,aAAa,OAAO,GAAG;AAAA,MAAA,IAE7C;AAEJ,oBAAc,KAAK;AAAA,QACjB,MAAM;AAAA,QACN,GAAG,WAAW,YAAY;AAAA,QAC1B;AAAA,QACA,OAAO;AAAA,QACP;AAAA,QACA;AAAA,QACA,QAAQ;AAAA,MAAA,CACT;AAED,kBACE,aAAa,aAAa,iBAAiB,KAAK,KAAK,UAAU,YAAY,UAAU,IAAI;AAC3F;AAAA,IACF;AAAA,EACF;AAEA,MAAI,KAAA;AACJ,MAAI,OAAO,GAAG,UAAU,IAAI,QAAQ,MAAM,UAAU;AACpD,MAAI,YAAY;AAChB,MAAI,eAAe;AACnB,MAAI,WAAW;AACf,MAAI,UAAU;AAEd,aAAW,WAAW,eAAe;AACnC,QAAI,oBAAoB;AACxB,QAAI,kBAAkB;AAEtB,QAAI,QAAQ,QAAQ;AAClB,YAAM,EAAE,YAAY,SAAA,IAAa,QAAQ;AACzC,YAAM,iBAAiB;AACvB,YAAM,WAAW,iBAAiB,cAAc,iBAAiB;AAEjE,UAAI,UAAU;AACZ,cAAM,gBAAgB,aAAa,iBAAiB,aAAa,iBAAiB;AAAA,UAChF,SAAS;AAAA,UACT,MAAM;AAAA,UACN,WAAW;AAAA,UACX,mBAAmB;AAAA,QAAA,CACpB;AAED,cAAM,aAAa,YAAY,eAAe,CAAC,YAAY,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG;AAAA,UAClF,iBAAiB;AAAA,UACjB,kBAAkB;AAAA,QAAA,CACnB;AAED,4BAAoB,MAAM;AAC1B,0BAAkB,MAAM,gBAAgB;AAAA,MAC1C,WAAW,gBAAgB,UAAU;AACnC,4BAAoB;AACpB,0BAAkB;AAAA,MACpB;AAEA,UAAI,oBAAoB,GAAG;AACzB,cAAM,UAAU;AAChB,cAAM,WAAW,QAAQ,QAAQ,UAAU,KAAK;AAChD,cAAM,YAAY,WAAW,WAAW;AAExC,YAAI,KAAA;AACJ,YAAI,cAAc;AAClB,YAAI,YAAY;AAChB,YAAI,UAAA;AACJ,YAAI,UAAU,QAAQ,IAAI,UAAU,GAAG,QAAQ,IAAI,WAAW,GAAG,SAAS,UAAU,CAAC;AACrF,YAAI,KAAA;AACJ,YAAI,QAAA;AAAA,MACN;AAAA,IACF;AAEA,QAAI,UAAU,cAAc,GAAG;AAC7B,UAAI,cAAc;AAClB,UAAI,YAAY;AAChB,UAAI,WAAW,QAAQ,MAAM,QAAQ,GAAG,QAAQ,CAAC;AAAA,IACnD;AACA,QAAI,YAAY;AAChB,QAAI,SAAS,QAAQ,MAAM,QAAQ,GAAG,QAAQ,CAAC;AAAA,EACjD;AAEA,MAAI,QAAA;AACN;ACtLO,MAAM,cAAc;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAuB;AAAA,EACvB,MAAc;AAAA,EACL,iBAAiB;AAAA,EAElC,YACE,KACA,OACA,QACA,MAAc,IACd;AACA,SAAK,MAAM;AACX,SAAK,QAAQ;AACb,SAAK,SAAS;AACd,SAAK,MAAM;AACX,SAAK,2BAAA;AAAA,EACP;AAAA,EAEA,gBAAgB,OAAqB;AACnC,SAAK,eAAe;AAAA,EACtB;AAAA,EAEQ,6BAAmC;AACzC,SAAK,IAAI,wBAAwB;AACjC,SAAK,IAAI,wBAAwB;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,OAAoB;AAC9B,QAAI,CAAC,MAAM,WAAW,MAAM,WAAW,EAAG;AAG1C,UAAM,uBACJ,MAAM,YAAY,KAAK,MAAM,aAAa,MAAM,aAAa,MAAM;AAErE,QAAI,sBAAsB;AACxB,WAAK,IAAI,KAAA;AAAA,IACX;AAEA,QAAI;AAEF,UAAI,MAAM,YAAY,GAAG;AACvB,aAAK,IAAI,cAAc,MAAM;AAAA,MAC/B;AAEA,UAAI,MAAM,WAAW;AACnB,aAAK,IAAI,2BAA2B,MAAM;AAAA,MAC5C;AAEA,UAAI,MAAM,WAAW;AAEnB,cAAM,kBAAkB,KAAK,mBAAmB,KAAK;AACrD,aAAK,eAAe,MAAM,WAAW,eAAe;AAAA,MACtD;AAEA,cAAQ,MAAM,MAAA;AAAA,QACZ,KAAK;AACH,eAAK,iBAAiB,KAAmB;AACzC;AAAA,QACF,KAAK;AACH,eAAK,iBAAiB,KAAmB;AACzC;AAAA,QACF,KAAK;AACH,eAAK,gBAAgB,KAAkB;AACvC;AAAA,MAAA;AAIJ,UAAI,MAAM,MAAM;AACd,aAAK,UAAU,MAAM,IAAI;AAAA,MAC3B;AAAA,IACF,UAAA;AACE,UAAI,sBAAsB;AACxB,aAAK,IAAI,QAAA;AAAA,MACX;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,eACN,OACA,YACoB;AACpB,QAAI,UAAU,OAAW,QAAO;AAChC,QAAI,OAAO,UAAU,SAAU,QAAO;AAGtC,UAAM,WAAW;AAGjB,QAAI,SAAS,SAAS,GAAG,GAAG;AAC1B,YAAM,WAAW,WAAW,QAAQ;AACpC,aAAO,MAAM,QAAQ,IAAI,SAAa,WAAW,MAAO;AAAA,IAC1D;AAGA,UAAM,SAAS,WAAW,QAAQ;AAClC,WAAO,MAAM,MAAM,IAAI,SAAY;AAAA,EACrC;AAAA,EAEQ,mBAAmB,OAAiD;AAC1E,QAAI,MAAM,SAAS,SAAS;AAC1B,YAAM,aAAa;AACnB,UAAI,WAAW,QAAQ;AACrB,cAAM,WAAW,WAAW,OAAO;AACnC,cAAM,YAAY,WAAW,OAAO;AAGpC,cAAM,eAAe,CAAC,CAAC,WAAW;AAClC,YAAI,cAAc;AAChB,gBAAM,iBAAkB,WAAmB;AAC3C,gBAAM,kBAAmB,WAAmB;AAG5C,gBAAM,cAAc,KAAK,eAAe,gBAAgB,KAAK,KAAK;AAClE,gBAAM,eAAe,KAAK,eAAe,iBAAiB,KAAK,MAAM;AAErE,cAAI,eAAe,cAAc;AAC/B,mBAAO,EAAE,OAAO,aAAa,QAAQ,aAAA;AAAA,UACvC,WAAW,aAAa;AACtB,mBAAO;AAAA,cACL,OAAO;AAAA,cACP,QAAS,YAAY,WAAY;AAAA,YAAA;AAAA,UAErC,WAAW,cAAc;AACvB,mBAAO;AAAA,cACL,OAAQ,WAAW,YAAa;AAAA,cAChC,QAAQ;AAAA,YAAA;AAAA,UAEZ;AAAA,QACF;AAGA,eAAO,EAAE,OAAO,UAAU,QAAQ,UAAA;AAAA,MACpC;AAAA,IACF,WAAW,MAAM,SAAS,SAAS;AACjC,YAAM,aAAa;AACnB,YAAM,aAAa,WAAW;AAC9B,aAAO;AAAA,QACL,OAAO,WAAW,gBAAgB,WAAW;AAAA,QAC7C,QAAQ,WAAW,iBAAiB,WAAW;AAAA,MAAA;AAAA,IAEnD;AAEA,WAAO,EAAE,OAAO,KAAK,OAAO,QAAQ,KAAK,OAAA;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASQ,0BACN,aACA,cACA,cACyD;AACzD,UAAM,cAAc,cAAc;AAClC,UAAM,eAAe,eAAe;AAGpC,UAAM,aACJ,cAAc,KAAK,QAAQ,KAAK,kBAChC,eAAe,KAAK,SAAS,KAAK;AAEpC,QAAI;AACJ,QAAI;AAEJ,QAAI,YAAY;AAEd,YAAM,aAAa,KAAK,IAAI,KAAK,QAAQ,aAAa,KAAK,SAAS,YAAY;AAChF,oBAAc,KAAK,MAAM,cAAc,UAAU;AACjD,qBAAe,KAAK,MAAM,eAAe,UAAU;AAAA,IACrD,OAAO;AAEL,oBAAc,KAAK,MAAM,WAAW;AACpC,qBAAe,KAAK,MAAM,YAAY;AAAA,IACxC;AAGA,UAAM,UAAU,KAAK,OAAO,KAAK,QAAQ,eAAe,CAAC;AACzD,UAAM,UAAU,KAAK,OAAO,KAAK,SAAS,gBAAgB,CAAC;AAE3D,WAAO,EAAE,OAAO,aAAa,QAAQ,cAAc,GAAG,SAAS,GAAG,QAAA;AAAA,EACpE;AAAA,EAEQ,eACN,WACA,iBACM;AAEN,UAAM,UAAU,UAAU,WAAW;AACrC,UAAM,UAAU,UAAU,WAAW;AACrC,UAAM,UAAU,gBAAgB,QAAQ;AACxC,UAAM,UAAU,gBAAgB,SAAS;AAGzC,SAAK,IAAI,UAAU,UAAU,IAAI,SAAS,UAAU,IAAI,OAAO;AAE/D,QAAI,UAAU,UAAU;AACtB,WAAK,IAAI,OAAO,UAAU,QAAQ;AAAA,IACpC;AAEA,SAAK,IAAI,MAAM,UAAU,QAAQ,UAAU,MAAM;AAEjD,QAAI,UAAU,SAAS,UAAU,OAAO;AACtC,WAAK,IAAI,UAAU,GAAG,UAAU,SAAS,GAAG,UAAU,SAAS,GAAG,GAAG,GAAG,CAAC;AAAA,IAC3E;AAGA,SAAK,IAAI,UAAU,CAAC,SAAS,CAAC,OAAO;AAAA,EACvC;AAAA,EAEQ,iBAAiB,OAAyB;AAChD,UAAM,EAAE,YAAY,KAAA,IAAS;AAG7B,UAAM,aAAa,WAAW,gBAAgB,WAAW;AACzD,UAAM,cAAc,WAAW,iBAAiB,WAAW;AAG3D,UAAM,eAAe,KAAK,SAAS;AACnC,UAAM,aAAa,KAAK,0BAA0B,YAAY,aAAa,YAAY;AAEvF,QAAI,MAAM;AACR,WAAK,IAAI;AAAA,QACP;AAAA,QACA,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,WAAW;AAAA,QACX,WAAW;AAAA,QACX,WAAW;AAAA,QACX,WAAW;AAAA,MAAA;AAAA,IAEf,OAAO;AACL,WAAK,IAAI;AAAA,QACP;AAAA,QACA,WAAW;AAAA,QACX,WAAW;AAAA,QACX,WAAW;AAAA,QACX,WAAW;AAAA,MAAA;AAAA,IAEf;AAAA,EAEF;AAAA,EAEQ,iBAAiB,OAAyB;AAChD,UAAM,EAAE,QAAQ,KAAA,IAAS;AAGzB,QAAI,kBAAkB,WAAW;AAC/B,UAAI,MAAM;AAER,cAAM,aAAa,IAAI,gBAAgB,KAAK,OAAO,KAAK,MAAM;AAC9D,cAAM,UAAU,WAAW,WAAW,IAAI;AAC1C,gBAAQ,aAAa,QAAQ,CAAC,KAAK,GAAG,CAAC,KAAK,CAAC;AAC7C,aAAK,IAAI,UAAU,YAAY,GAAG,GAAG,KAAK,OAAO,KAAK,MAAM;AAAA,MAC9D,OAAO;AAEL,aAAK,IAAI,aAAa,QAAQ,GAAG,CAAC;AAAA,MACpC;AAAA,IACF,OAAO;AAEL,UAAI,CAAC,QAAQ;AACX;AAAA,MACF;AAGA,YAAM,eAAe,CAAC,CAAC,MAAM;AAC7B,YAAM,WAAW,OAAO;AACxB,YAAM,YAAY,OAAO;AAEzB,UAAI;AACJ,UAAI;AAEJ,UAAI,cAAc;AAEhB,cAAM,iBAAkB,MAAc;AACtC,cAAM,kBAAmB,MAAc;AAGvC,cAAM,cAAc,KAAK,eAAe,gBAAgB,KAAK,KAAK;AAClE,cAAM,eAAe,KAAK,eAAe,iBAAiB,KAAK,MAAM;AAErE,YAAI,eAAe,cAAc;AAE/B,wBAAc;AACd,yBAAe;AAAA,QACjB,WAAW,aAAa;AAEtB,wBAAc;AACd,yBAAgB,YAAY,WAAY;AAAA,QAC1C,WAAW,cAAc;AAEvB,yBAAe;AACf,wBAAe,WAAW,YAAa;AAAA,QACzC,OAAO;AAEL,wBAAc;AACd,yBAAe;AAAA,QACjB;AAAA,MACF,OAAO;AAEL,cAAM,eAAe,KAAK,QAAQ;AAClC,cAAM,aAAa,KAAK,0BAA0B,UAAU,WAAW,YAAY;AACnF,sBAAc,WAAW;AACzB,uBAAe,WAAW;AAAA,MAC5B;AAGA,YAAM,UAAU,eAAe,IAAI,KAAK,OAAO,KAAK,QAAQ,eAAe,CAAC;AAC5E,YAAM,UAAU,eAAe,IAAI,KAAK,OAAO,KAAK,SAAS,gBAAgB,CAAC;AAE9E,UAAI,MAAM;AACR,aAAK,IAAI;AAAA,UACP;AAAA,UACA,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK;AAAA,UACL;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QAAA;AAAA,MAEJ,OAAO;AACL,aAAK,IAAI,UAAU,QAAQ,SAAS,SAAS,aAAa,YAAY;AAAA,MACxE;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,gBAAgB,OAAwB;AAC9C,UAAM,gBAAgB,MAAM,WAAW;AACvC,UAAM,iBAAiB,MAAM,eAAe,MAAM,YAAY,SAAS;AAEvE,UAAM,mBAAmB,CAAC,cAAc,gBAAgB,iBAAiB,EAAE;AAAA,MACzE,iBAAiB;AAAA,IAAA;AAGnB,QAAI,oBAAoB,CAAC,gBAAgB;AACvC,sBAAgB,KAAK,KAAK,OAAO,KAAK,OAAO,KAAK,QAAQ,KAAK,YAAY;AAC3E;AAAA,IACF;AAEA,YAAQ,eAAA;AAAA,MACN,KAAK;AACH,yBAAiB,KAAK,KAAK,OAAO,KAAK,OAAO,KAAK,QAAQ,KAAK,cAAc,KAAK,GAAG;AACtF;AAAA,MACF,KAAK;AACH,2BAAmB,KAAK,KAAK,OAAO,KAAK,OAAO,KAAK,QAAQ,KAAK,cAAc,KAAK,GAAG;AACxF;AAAA,MACF,KAAK;AACH;AAAA,UACE,KAAK;AAAA,UACL;AAAA,UACA,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK;AAAA,QAAA;AAEP;AAAA,MACF,KAAK;AACH,+BAAuB,KAAK,KAAK,OAAO,KAAK,OAAO,KAAK,QAAQ,KAAK,YAAY;AAClF;AAAA,MACF;AACE,wBAAgB,KAAK,KAAK,OAAO,KAAK,OAAO,KAAK,QAAQ,KAAK,YAAY;AAC3E;AAAA,IAAA;AAAA,EAEN;AAAA,EAEQ,UAAU,MAAwB;AACxC,SAAK,IAAI,2BAA2B,KAAK,SAAS,eAAe;AAEjE,QAAI,KAAK,QAAQ;AACf,WAAK,IAAI,UAAU,KAAK,QAAQ,GAAG,GAAG,KAAK,OAAO,KAAK,MAAM;AAAA,IAC/D,WAAW,KAAK,UAAU,UAAU;AAClC,WAAK,IAAI,UAAA;AACT,WAAK,IAAI;AAAA,QACP,KAAK,QAAQ;AAAA,QACb,KAAK,SAAS;AAAA,QACd,KAAK,IAAI,KAAK,OAAO,KAAK,MAAM,IAAI;AAAA,QACpC;AAAA,QACA,KAAK,KAAK;AAAA,MAAA;AAEZ,WAAK,IAAI,KAAA;AAAA,IACX;AAAA,EACF;AAAA,EAEA,iBAAiB,OAAe,QAAsB;AACpD,SAAK,QAAQ;AACb,SAAK,SAAS;AACd,SAAK,2BAAA;AAAA,EACP;AACF;ACrZO,MAAM,oBAAoB;AAAA,EACvB;AAAA,EACA;AAAA,EAER,YAAY,OAAe,QAAgB;AACzC,SAAK,QAAQ;AACb,SAAK,SAAS;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,gBACE,KACA,YACS;AACT,QAAI,CAAC,cAAc,WAAW,YAAY,EAAG,QAAO;AAEpD,UAAM,WAAW,KAAK,uBAAuB,WAAW,UAAU,WAAW,MAAM;AAEnF,YAAQ,WAAW,MAAA;AAAA,MACjB,KAAK;AACH,eAAO,KAAK,UAAU,KAAK,QAAQ;AAAA,MACrC,KAAK;AACH,eAAO,KAAK,WAAW,KAAK,UAAU,WAAW,SAAS;AAAA,MAC5D,KAAK;AACH,eAAO,KAAK,UAAU,KAAK,UAAU,WAAW,SAAS;AAAA,MAC3D,KAAK;AACH,eAAO,KAAK,UAAU,KAAK,UAAU,WAAW,SAAS;AAAA,MAC3D,KAAK;AACH,eAAO,KAAK,YAAY,KAAK,QAAQ;AAAA,MACvC,KAAK;AACH,eAAO,KAAK,cAAc,KAAK,QAAQ;AAAA,MACzC;AACE,eAAO;AAAA,IAAA;AAAA,EAEb;AAAA,EAEQ,uBACN,UACA,QACQ;AACR,YAAQ,QAAA;AAAA,MACN,KAAK;AACH,eAAO,WAAW;AAAA,MACpB,KAAK;AACH,eAAO,KAAK,IAAI,aAAa,IAAI;AAAA,MACnC,KAAK;AACH,eAAO,WAAW,MAAM,IAAI,WAAW,WAAW,IAAI,KAAK,IAAI,KAAK,WAAW,GAAG,CAAC,IAAI;AAAA,MACzF;AACE,eAAO;AAAA,IAAA;AAAA,EAEb;AAAA,EAEQ,UACN,KACA,UACS;AACT,QAAI,cAAc;AAClB,WAAO;AAAA,EACT;AAAA,EAEQ,WACN,KACA,UACA,WACS;AACT,UAAM,WAAW,IAAI;AAErB,YAAQ,WAAA;AAAA,MACN,KAAK;AACH,YAAI,UAAU,CAAC,KAAK,QAAQ,UAAU,CAAC;AACvC;AAAA,MACF,KAAK;AACH,YAAI,UAAU,KAAK,QAAQ,UAAU,CAAC;AACtC;AAAA,MACF,KAAK;AACH,YAAI,UAAU,GAAG,CAAC,KAAK,SAAS,QAAQ;AACxC;AAAA,MACF,KAAK;AACH,YAAI,UAAU,GAAG,KAAK,SAAS,QAAQ;AACvC;AAAA,MACF;AACE,YAAI,UAAU,CAAC,KAAK,QAAQ,UAAU,CAAC;AAAA,IAAA;AAG3C,WAAO;AAAA,EACT;AAAA,EAEQ,UACN,KACA,UACA,WACS;AACT,QAAI,KAAA;AACJ,QAAI,UAAA;AAEJ,YAAQ,WAAA;AAAA,MACN,KAAK;AACH,YAAI,KAAK,GAAG,GAAG,KAAK,QAAQ,UAAU,KAAK,MAAM;AACjD;AAAA,MACF,KAAK;AACH,YAAI,KAAK,KAAK,SAAS,IAAI,WAAW,GAAG,KAAK,QAAQ,UAAU,KAAK,MAAM;AAC3E;AAAA,MACF,KAAK;AACH,YAAI,KAAK,GAAG,GAAG,KAAK,OAAO,KAAK,SAAS,QAAQ;AACjD;AAAA,MACF,KAAK;AACH,YAAI,KAAK,GAAG,KAAK,UAAU,IAAI,WAAW,KAAK,OAAO,KAAK,SAAS,QAAQ;AAC5E;AAAA,MACF;AACE,YAAI,KAAK,GAAG,GAAG,KAAK,QAAQ,UAAU,KAAK,MAAM;AAAA,IAAA;AAGrD,QAAI,KAAA;AACJ,WAAO;AAAA,EACT;AAAA,EAEQ,UACN,KACA,UACA,WACS;AACT,UAAM,QAAQ,cAAc,QAAQ,KAAK,IAAI,YAAY;AACzD,UAAM,UAAU,KAAK,QAAQ;AAC7B,UAAM,UAAU,KAAK,SAAS;AAE9B,QAAI,UAAU,SAAS,OAAO;AAC9B,QAAI,MAAM,OAAO,KAAK;AACtB,QAAI,UAAU,CAAC,SAAS,CAAC,OAAO;AAEhC,QAAI,cAAc,OAAO;AACvB,UAAI,cAAc;AAAA,IACpB;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,YACN,KACA,UACS;AACT,UAAM,YAAY,IAAI,YAAY,KAAK,KAAK;AAC5C,UAAM,UAAU,KAAK,QAAQ;AAC7B,UAAM,UAAU,KAAK,SAAS;AAE9B,QAAI,UAAU,SAAS,OAAO;AAC9B,QAAI,OAAO,QAAQ;AACnB,QAAI,UAAU,CAAC,SAAS,CAAC,OAAO;AAEhC,WAAO;AAAA,EACT;AAAA,EAEQ,cACN,KACA,UACS;AAET,QAAI,cAAc;AAClB,QAAI,2BAA2B;AAC/B,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,qBAAqB,YAA8B,QAA2C;AAC5F,UAAM,MAAM,OAAO,WAAW,IAAI;AAClC,QAAI,CAAC,IAAK,QAAO;AAEjB,UAAM,YAAY,IAAI,gBAAgB,KAAK,OAAO,KAAK,MAAM;AAC7D,UAAM,OAAO,UAAU;AACvB,UAAM,WAAW,KAAK,uBAAuB,WAAW,UAAU,WAAW,MAAM;AAGnF,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,eAAS,IAAI,GAAG,IAAI,KAAK,OAAO,KAAK;AACnC,cAAM,SAAS,IAAI,KAAK,QAAQ,KAAK;AACrC,YAAI,QAAQ;AAEZ,gBAAQ,WAAW,MAAA;AAAA,UACjB,KAAK;AACH,oBAAQ,KAAK,mBAAmB,GAAG,GAAG,UAAU,WAAW,SAAS;AACpE;AAAA,UACF,KAAK;AAEH,oBAAQ,KAAK,OAAA,IAAW,WAAW,MAAM;AACzC;AAAA,UACF;AACE,oBAAQ,KAAK,MAAM,MAAM,QAAQ;AAAA,QAAA;AAGrC,aAAK,KAAK,IAAI;AACd,aAAK,QAAQ,CAAC,IAAI;AAClB,aAAK,QAAQ,CAAC,IAAI;AAClB,aAAK,QAAQ,CAAC,IAAI;AAAA,MACpB;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,mBACN,GACA,GACA,UACA,WACQ;AACR,QAAI,WAAW;AAEf,YAAQ,WAAA;AAAA,MACN,KAAK;AACH,mBAAW,IAAI,KAAK;AACpB;AAAA,MACF,KAAK;AACH,mBAAW,IAAI,IAAI,KAAK;AACxB;AAAA,MACF,KAAK;AACH,mBAAW,IAAI,KAAK;AACpB;AAAA,MACF,KAAK;AACH,mBAAW,IAAI,IAAI,KAAK;AACxB;AAAA,MACF,KAAK,MAAM;AAET,cAAM,KAAK,IAAI,KAAK,QAAQ;AAC5B,cAAM,KAAK,IAAI,KAAK,SAAS;AAC7B,cAAM,UAAU,KAAK,KAAK,KAAK,QAAQ,KAAK,QAAQ,KAAK,SAAS,KAAK,MAAM,IAAI;AACjF,mBAAW,KAAK,KAAK,KAAK,KAAK,KAAK,EAAE,IAAI;AAC1C;AAAA,MACF;AAAA,MACA,KAAK,OAAO;AAEV,cAAM,MAAM,IAAI,KAAK,QAAQ;AAC7B,cAAM,MAAM,IAAI,KAAK,SAAS;AAC9B,cAAM,WAAW,KAAK,KAAK,KAAK,QAAQ,KAAK,QAAQ,KAAK,SAAS,KAAK,MAAM,IAAI;AAClF,mBAAW,IAAI,KAAK,KAAK,MAAM,MAAM,MAAM,GAAG,IAAI;AAClD;AAAA,MACF;AAAA,MACA;AACE,mBAAW,IAAI,KAAK;AAAA,IAAA;AAGxB,WAAO,WAAW,WAAW,MAAM;AAAA,EACrC;AAAA,EAEA,iBAAiB,OAAe,QAAsB;AACpD,SAAK,QAAQ;AACb,SAAK,SAAS;AAAA,EAChB;AACF;AC3PO,MAAM,gBAAgB;AAAA,EACnB,kCAAkB,IAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAM1B,aACE,KACA,SACM;AACN,QAAI,CAAC,WAAW,QAAQ,WAAW,GAAG;AACpC,UAAI,SAAS;AACb;AAAA,IACF;AAGA,UAAM,WAAW,KAAK,iBAAiB,OAAO;AAG9C,QAAI,eAAe,KAAK,YAAY,IAAI,QAAQ;AAEhD,QAAI,CAAC,cAAc;AACjB,qBAAe,KAAK,kBAAkB,OAAO;AAC7C,WAAK,YAAY,IAAI,UAAU,YAAY;AAAA,IAC7C;AAEA,QAAI,SAAS;AAAA,EACf;AAAA;AAAA;AAAA;AAAA,EAKQ,kBAAkB,SAAiC;AACzD,UAAM,gBAA0B,CAAA;AAEhC,eAAW,UAAU,SAAS;AAC5B,YAAM,YAAY,KAAK,kBAAkB,MAAM;AAC/C,UAAI,WAAW;AACb,sBAAc,KAAK,SAAS;AAAA,MAC9B;AAAA,IACF;AAEA,WAAO,cAAc,SAAS,IAAI,cAAc,KAAK,GAAG,IAAI;AAAA,EAC9D;AAAA,EAEQ,kBAAkB,QAAqC;AAC7D,YAAQ,OAAO,MAAA;AAAA,MACb,KAAK;AACH,eAAO,QAAQ,OAAO,SAAS,CAAC;AAAA,MAElC,KAAK;AACH,eAAO,cAAc,OAAO,SAAS,CAAC;AAAA,MAExC,KAAK;AACH,eAAO,YAAY,OAAO,SAAS,CAAC;AAAA,MAEtC,KAAK;AACH,eAAO,aAAa,OAAO,SAAS,CAAC;AAAA,MAEvC,KAAK;AACH,eAAO,cAAc,OAAO,SAAS,CAAC;AAAA,MAExC,KAAK;AACH,eAAO,YAAY,OAAO,SAAS,CAAC;AAAA,MAEtC,KAAK;AACH,eAAO,SAAS,OAAO,SAAS,CAAC;AAAA,MAEnC,KAAK;AACH,eAAO,KAAK,kBAAkB,MAAM;AAAA,MAEtC;AACE,gBAAQ,KAAK,wBAAwB,OAAO,IAAI,EAAE;AAClD,eAAO;AAAA,IAAA;AAAA,EAEb;AAAA;AAAA;AAAA;AAAA,EAKQ,kBAAkB,QAAqC;AAC7D,QAAI,CAAC,OAAO,OAAQ,QAAO;AAE3B,UAAM,EAAE,MAAM,GAAG,OAAA,IAAW,OAAO;AAEnC,YAAQ,MAAA;AAAA,MACN,KAAK;AACH,eAAO,eAAe,OAAO,OAAO,MAAM,OAAO,OAAO,MAAM,OAAO,IAAI,MAAM,OAAO,KAAK;AAAA,MAE7F,KAAK;AACH,eAAO,WAAW,OAAO,KAAK;AAAA,MAEhC,KAAK;AACH,eAAO,UAAU,OAAO,KAAK;AAAA,MAE/B;AACE,eAAO;AAAA,IAAA;AAAA,EAEb;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,iBAAiB,WAAsB,QAA6B;AAClE,QAAI,OAAO,WAAW,IAAI;AACxB,YAAM,IAAI,MAAM,+CAA+C;AAAA,IACjE;AAEA,UAAM,OAAO,UAAU;AACvB,UAAM,SAAS,KAAK;AAEpB,aAAS,IAAI,GAAG,IAAI,QAAQ,KAAK,GAAG;AAClC,YAAM,IAAI,KAAK,CAAC;AAChB,YAAM,IAAI,KAAK,IAAI,CAAC;AACpB,YAAM,IAAI,KAAK,IAAI,CAAC;AACpB,YAAM,IAAI,KAAK,IAAI,CAAC;AACpB,YAAM,IAAI;AAGV,WAAK,CAAC,IAAI,KAAK,MAAM,IAAI,EAAE,CAAC,IAAK,IAAI,EAAE,CAAC,IAAK,IAAI,EAAE,CAAC,IAAK,IAAI,EAAE,CAAC,IAAK,EAAE,CAAC,IAAK,GAAG;AAChF,WAAK,IAAI,CAAC,IAAI,KAAK,MAAM,IAAI,EAAE,CAAC,IAAK,IAAI,EAAE,CAAC,IAAK,IAAI,EAAE,CAAC,IAAK,IAAI,EAAE,CAAC,IAAK,EAAE,CAAC,IAAK,GAAG;AACpF,WAAK,IAAI,CAAC,IAAI,KAAK,MAAM,IAAI,EAAE,EAAE,IAAK,IAAI,EAAE,EAAE,IAAK,IAAI,EAAE,EAAE,IAAK,IAAI,EAAE,EAAE,IAAK,EAAE,EAAE,IAAK,GAAG;AACzF,WAAK,IAAI,CAAC,IAAI,KAAK,MAAM,IAAI,EAAE,EAAE,IAAK,IAAI,EAAE,EAAE,IAAK,IAAI,EAAE,EAAE,IAAK,IAAI,EAAE,EAAE,IAAK,EAAE,EAAE,IAAK,GAAG;AAAA,IAC3F;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAgB,QAAiC;AAC/C,YAAQ,QAAA;AAAA,MACN,KAAK;AACH,eAAO;AAAA,UACL;AAAA,UAAO;AAAA,UAAO;AAAA,UAAO;AAAA,UAAG;AAAA,UAAG;AAAA,UAAO;AAAA,UAAO;AAAA,UAAO;AAAA,UAAG;AAAA,UAAG;AAAA,UAAO;AAAA,UAAO;AAAA,UAAO;AAAA,UAAG;AAAA,UAAG;AAAA,UAAG;AAAA,UAAG;AAAA,UACvF;AAAA,UAAG;AAAA,QAAA;AAAA,MAGP,KAAK;AACH,eAAO;AAAA,UACL;AAAA,UAAM;AAAA,UAAM;AAAA,UAAM;AAAA,UAAG;AAAA,UAAG;AAAA,UAAM;AAAA,UAAM;AAAA,UAAM;AAAA,UAAG;AAAA,UAAG;AAAA,UAAM;AAAA,UAAM;AAAA,UAAM;AAAA,UAAG;AAAA,UAAG;AAAA,UAAG;AAAA,UAAG;AAAA,UAAG;AAAA,UAAG;AAAA,QAAA;AAAA,MAGxF,KAAK;AACH,eAAO,CAAC,KAAK,GAAG,GAAG,GAAG,GAAG,GAAG,KAAK,GAAG,GAAG,GAAG,GAAG,GAAG,KAAK,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAAA,MAE1E,KAAK;AACH,eAAO,CAAC,KAAK,GAAG,GAAG,GAAG,GAAG,GAAG,KAAK,GAAG,GAAG,GAAG,GAAG,GAAG,KAAK,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAAA,MAE1E;AACE,eAAO;AAAA,IAAA;AAAA,EAEb;AAAA;AAAA;AAAA;AAAA,EAKA,kBAAkB,WAAsB,QAA2B;AAEjE,UAAM,SAAS,IAAI;AAAA,MACjB,IAAI,kBAAkB,UAAU,IAAI;AAAA,MACpC,UAAU;AAAA,MACV,UAAU;AAAA,IAAA;AAGZ,UAAM,QAAQ,UAAU;AACxB,UAAM,SAAS,UAAU;AACzB,UAAM,OAAO,UAAU;AACvB,UAAM,UAAU,OAAO;AAGvB,aAAS,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC/B,eAAS,IAAI,GAAG,IAAI,OAAO,KAAK;AAC9B,YAAI,IAAI,GACN,IAAI,GACJ,IAAI,GACJ,IAAI;AACN,YAAI,QAAQ;AAEZ,iBAAS,KAAK,CAAC,QAAQ,MAAM,QAAQ,MAAM;AACzC,gBAAM,KAAK,KAAK,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,GAAG,QAAQ,CAAC;AAClD,gBAAME,QAAO,IAAI,QAAQ,MAAM;AAC/B,eAAK,KAAKA,IAAG;AACb,eAAK,KAAKA,OAAM,CAAC;AACjB,eAAK,KAAKA,OAAM,CAAC;AACjB,eAAK,KAAKA,OAAM,CAAC;AACjB;AAAA,QACF;AAEA,cAAM,OAAO,IAAI,QAAQ,KAAK;AAC9B,gBAAQ,GAAG,IAAI,IAAI;AACnB,gBAAQ,MAAM,CAAC,IAAI,IAAI;AACvB,gBAAQ,MAAM,CAAC,IAAI,IAAI;AACvB,gBAAQ,MAAM,CAAC,IAAI,IAAI;AAAA,MACzB;AAAA,IACF;AAGA,aAAS,IAAI,GAAG,IAAI,OAAO,KAAK;AAC9B,eAAS,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC/B,YAAI,IAAI,GACN,IAAI,GACJ,IAAI,GACJ,IAAI;AACN,YAAI,QAAQ;AAEZ,iBAAS,KAAK,CAAC,QAAQ,MAAM,QAAQ,MAAM;AACzC,gBAAM,KAAK,KAAK,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,GAAG,SAAS,CAAC;AACnD,gBAAMA,QAAO,KAAK,QAAQ,KAAK;AAC/B,eAAK,QAAQA,IAAG;AAChB,eAAK,QAAQA,OAAM,CAAC;AACpB,eAAK,QAAQA,OAAM,CAAC;AACpB,eAAK,QAAQA,OAAM,CAAC;AACpB;AAAA,QACF;AAEA,cAAM,OAAO,IAAI,QAAQ,KAAK;AAC9B,aAAK,GAAG,IAAI,IAAI;AAChB,aAAK,MAAM,CAAC,IAAI,IAAI;AACpB,aAAK,MAAM,CAAC,IAAI,IAAI;AACpB,aAAK,MAAM,CAAC,IAAI,IAAI;AAAA,MACtB;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,MAAM,OAAuB;AACnC,WAAO,KAAK,IAAI,KAAK,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,CAAC,CAAC;AAAA,EACrD;AAAA,EAEQ,iBAAiB,SAAiC;AACxD,WAAO,QAAQ,IAAI,CAAC,MAAM,GAAG,EAAE,IAAI,IAAI,EAAE,SAAS,SAAS,EAAE,EAAE,KAAK,GAAG;AAAA,EACzE;AAAA,EAEA,aAAmB;AACjB,SAAK,YAAY,MAAA;AAAA,EACnB;AAAA,EAEA,eAAuB;AACrB,WAAO,KAAK,YAAY;AAAA,EAC1B;AACF;AC9OA,MAAM,kBAAkB,CAAC,UAAiB;AACxC,MAAI,MAAM,SAAS,SAAS;AAC1B,UAAM,aAAa;AAGnB,QAAI,CAAC,WAAW,SAAS;AACvB,YAAM,KAAK,WAAW;AACtB,UAAI,IAAI,OAAO;AACb,WAAG,MAAA;AAAA,MACL;AAAA,IACF;AAAA,EACF;AACF;AAKO,MAAM,cAAc;AAAA,EAChB;AAAA,EAGA;AAAA,EAED;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EACA,sBAA4C;AAAA,EAC5C,kCAAkB,IAAA;AAAA,EAE1B,YAAY,QAA4B;AACtC,SAAK,SAAS,KAAK,cAAc,MAAM;AACvC,SAAK,kBAAkB,KAAK,MAAM,MAAY,KAAK,OAAO,GAAG;AAE7D,QAAI,OAAO,gBAAgB;AACzB,WAAK,SAAS,OAAO;AAGrB,UAAI,KAAK,OAAO,UAAU,KAAK,OAAO,SAAS,KAAK,OAAO,WAAW,KAAK,OAAO,QAAQ;AACxF,aAAK,OAAO,QAAQ,KAAK,OAAO;AAChC,aAAK,OAAO,SAAS,KAAK,OAAO;AAAA,MACnC;AAEA,WAAK,MAAM,KAAK,OAAO,WAAW,MAAM;AAAA,QACtC,OAAO;AAAA,QACP,gBAAgB;AAAA,QAChB,oBAAoB;AAAA,QACpB,YAAY;AAAA,MAAA,CACb;AAAA,IACH,OAAO;AACL,WAAK,SAAS,IAAI,gBAAgB,KAAK,OAAO,OAAO,KAAK,OAAO,MAAM;AACvE,WAAK,MAAM,KAAK,OAAO,WAAW,MAAM;AAAA,QACtC,OAAO;AAAA,QACP,gBAAgB;AAAA,QAChB,oBAAoB;AAAA,QACpB,YAAY;AAAA,MAAA,CACb;AAAA,IACH;AAEA,QAAI,CAAC,KAAK,KAAK;AACb,YAAM,IAAI,MAAM,uCAAuC;AAAA,IACzD;AAEA,SAAK,IAAI,wBAAwB,KAAK,OAAO;AAG7C,SAAK,sBAAsB,KAAK,UAAA;AAChC,SAAK,IAAI,wBAAwB;AAEjC,SAAK,gBAAgB,IAAI;AAAA,MACvB,KAAK;AAAA,MACL,KAAK,OAAO;AAAA,MACZ,KAAK,OAAO;AAAA,MACZ,KAAK,OAAO;AAAA,IAAA;AAEd,SAAK,sBAAsB,IAAI,oBAAoB,KAAK,OAAO,OAAO,KAAK,OAAO,MAAM;AACxF,SAAK,kBAAkB,IAAI,gBAAA;AAAA,EAC7B;AAAA,EAEQ,cAAc,QAKpB;AACA,WAAO;AAAA,MACL,OAAO,OAAO,SAAS;AAAA,MACvB,QAAQ,OAAO,UAAU;AAAA,MACzB,KAAK,OAAO,OAAO;AAAA,MACnB,iBAAiB,OAAO,mBAAmB;AAAA,MAC3C,UAAU,OAAO,YAAY;AAAA,MAC7B,iBAAiB,OAAO,mBAAmB;AAAA,MAC3C,4BAA4B,OAAO,8BAA8B;AAAA,MACjE,UAAU,OAAO,YAAY;AAAA,MAC7B,oBAAoB,OAAO,sBAAsB;AAAA,MACjD,qBAAqB,OAAO,uBAAuB;AAAA,MACnD,WAAW,OAAO,aAAa;AAAA,MAC/B,UAAU,OAAO,YAAY;AAAA,QAC3B,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,aAAa;AAAA,QACb,gBAAgB;AAAA,QAChB,gBAAgB;AAAA,MAAA;AAAA,MAElB,OAAO,OAAO,SAAS,CAAA;AAAA,MACvB,gBAAgB,OAAO;AAAA,IAAA;AAAA,EAE3B;AAAA,EAEA,cAAc,cAAgF;AAG5F,UAAM,SAAS,IAAI;AAAA,MACjB;AAAA,QACE,WAAW,OAAO,SAAS,eAAe;AAExC,gBAAM,SAAS,MAAM,KAAK,aAAa,OAAO;AAC9C,cAAI,OAAO,OAAO;AAChB,uBAAW,QAAQ,OAAO,KAAK;AAAA,UACjC;AAAA,QAIF;AAAA,QAEA,OAAO,YAAY;AACjB,eAAK,gBAAgB,WAAA;AAAA,QACvB;AAAA,MAAA;AAAA,MAEF;AAAA,QACE,eAAe,KAAK,OAAO;AAAA,MAAA;AAAA,MAE7B;AAAA,QACE,eAAe,KAAK,OAAO;AAAA,MAAA;AAAA,IAC7B;AAEF,WAAO;AAAA,EACT;AAAA,EACA,MAAM,aAAa,SAAiD;AAElE,QAAI,KAAK,qBAAqB;AAC5B,YAAM,KAAK;AACX,WAAK,sBAAsB;AAAA,IAC7B;AAEA,QAAI,QAAQ,OAAO,SAAS,KAAK,OAAO,WAAW;AACjD,YAAM,IAAI,MAAM,oBAAoB,QAAQ,OAAO,MAAM,MAAM,KAAK,OAAO,SAAS,EAAE;AAAA,IACxF;AAEA,SAAK,YAAA;AAGL,UAAM,kBAAkB,MAAY,KAAK,OAAO;AAChD,UAAM,gBAAgB,KAAK,MAAM,QAAQ,SAAS,eAAe;AACjE,SAAK,cAAc,gBAAgB,aAAa;AAEhD,QAAI,QAAQ,YAAY;AACtB,WAAK,IAAI,KAAA;AACT,WAAK,oBAAoB,gBAAgB,KAAK,KAAK,QAAQ,UAAU;AAAA,IACvE;AAEA,eAAW,SAAS,QAAQ,QAAQ;AAClC,UAAI,CAAC,MAAM,WAAW,MAAM,WAAW,GAAG;AAExC,wBAAgB,KAAK;AACrB;AAAA,MACF;AAEA,UAAI;AAEF,cAAM,aAAa;AACnB,YAAI,WAAW,SAAS;AACtB,qBAAW,QAAQ,IAAI,CAACC,WAAsB;AAE5C,uBAAW,aAAaA;AAExB,gBAAI,MAAM,WAAW,MAAM,QAAQ,SAAS,GAAG;AAC7C,mBAAK,IAAI,KAAA;AACT,mBAAK,gBAAgB,aAAa,KAAK,KAAK,MAAM,OAAO;AAAA,YAC3D;AACA,iBAAK,cAAc,YAAY,KAAK;AAEpC,gBAAI,MAAM,WAAW,MAAM,QAAQ,SAAS,GAAG;AAC7C,mBAAK,IAAI,QAAA;AAAA,YACX;AAAA,UACF,CAAC;AAAA,QACH,OAAO;AAEL,cAAI,MAAM,WAAW,MAAM,QAAQ,SAAS,GAAG;AAC7C,iBAAK,IAAI,KAAA;AACT,iBAAK,gBAAgB,aAAa,KAAK,KAAK,MAAM,OAAO;AAAA,UAC3D;AACA,eAAK,cAAc,YAAY,KAAK;AAEpC,cAAI,MAAM,WAAW,MAAM,QAAQ,SAAS,GAAG;AAC7C,iBAAK,IAAI,QAAA;AAAA,UACX;AAAA,QACF;AAAA,MACF,SAAS,OAAO;AACd,gBAAQ,MAAM,wCAAwC,KAAK;AAAA,MAC7D,UAAA;AACE,wBAAgB,KAAK;AAAA,MACvB;AAAA,IACF;AAEA,QAAI,QAAQ,YAAY;AACtB,WAAK,IAAI,QAAA;AAAA,IACX;AAEA,QAAI,QAA2B;AAC/B,QAAI,CAAC,KAAK,OAAO,gBAAgB;AAC/B,cAAQ,MAAM,KAAK,kBAAkB,QAAQ,MAAM;AAAA,IACrD;AAEA,WAAO;AAAA,MACL;AAAA,MACA,QAAQ,QAAQ;AAAA,IAAA;AAAA,EAEpB;AAAA,EAEA,MAAM,kBACJ,aACA,WACA,YACwB;AACxB,UAAM,KAAK,aAAa,WAAW;AAEnC,UAAM,iBAAiB;AAAA,MACrB,GAAG;AAAA,MACH;AAAA,IAAA;AAGF,WAAO,KAAK,aAAa,cAAc;AAAA,EACzC;AAAA,EAEQ,cAAoB;AAC1B,QAAI,KAAK,OAAO,iBAAiB;AAC/B,WAAK,IAAI,YAAY,KAAK,OAAO;AACjC,WAAK,IAAI,SAAS,GAAG,GAAG,KAAK,OAAO,OAAO,KAAK,OAAO,MAAM;AAAA,IAC/D,OAAO;AACL,WAAK,IAAI,UAAU,GAAG,GAAG,KAAK,OAAO,OAAO,KAAK,OAAO,MAAM;AAAA,IAChE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,kBAAkB,QAAqC;AACnE,UAAM,QAAQ,IAAI,WAAW,KAAK,QAAQ;AAAA,MACxC,WAAW;AAAA,MACX,UAAU,KAAK;AAAA;AAAA,MACf,OAAO;AAAA,MACP,aAAa,EAAE,GAAG,GAAG,GAAG,GAAG,OAAO,KAAK,OAAO,OAAO,QAAQ,KAAK,OAAO,OAAA;AAAA,IAAO,CACjF;AACD,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,YAA2B;AACvC,QAAI,CAAC,KAAK,OAAO,SAAS,KAAK,OAAO,MAAM,WAAW,GAAG;AACxD;AAAA,IACF;AAEA,eAAW,QAAQ,KAAK,OAAO,OAAO;AACpC,UAAI,KAAK,YAAY,IAAI,KAAK,MAAM,GAAG;AACrC;AAAA,MACF;AAEA,UAAI;AACF,cAAM,WAAW,IAAI,SAAS,KAAK,QAAQ,OAAO,KAAK,GAAG,GAAG;AAC7D,cAAM,aAAa,MAAM,SAAS,KAAA;AAElC,YAAI,WAAW,MAAM;AACnB,eAAK,MAAM,IAAI,UAAU;AAAA,QAC3B;AAEA,aAAK,YAAY,IAAI,KAAK,MAAM;AAAA,MAClC,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AAAA,EAEA,aAAa,QAA2C;AACtD,WAAO,OAAO,KAAK,QAAQ,KAAK,cAAc,EAAE,GAAG,KAAK,QAAQ,GAAG,OAAA,CAAQ,CAAC;AAE5E,QAAI,OAAO,QAAQ,QAAW;AAC5B,WAAK,kBAAkB,KAAK,MAAM,MAAY,KAAK,OAAO,GAAG;AAAA,IAC/D;AAEA,QAAI,OAAO,SAAS,OAAO,QAAQ;AACjC,WAAK,OAAO,QAAQ,KAAK,OAAO;AAChC,WAAK,OAAO,SAAS,KAAK,OAAO;AACjC,WAAK,cAAc,iBAAiB,KAAK,OAAO,OAAO,KAAK,OAAO,MAAM;AACzE,WAAK,oBAAoB,iBAAiB,KAAK,OAAO,OAAO,KAAK,OAAO,MAAM;AAAA,IACjF;AAEA,QAAI,OAAO,oBAAoB,QAAW;AACxC,WAAK,IAAI,wBAAwB,KAAK,OAAO;AAAA,IAC/C;AAEA,QAAI,OAAO,OAAO;AAChB,WAAK,sBAAsB,KAAK,UAAA;AAAA,IAClC;AAAA,EACF;AAAA,EAEA,UAAgB;AACd,SAAK,gBAAgB,WAAA;AAAA,EACvB;AACF;ACjUO,MAAM,0BAA0B;AAEvC,MAAM,cAAc;AAIb,SAAS,aAAa,OAAwB;AACnD,MAAI,CAAC,OAAO,SAAS,KAAK,KAAM,SAAoB,GAAG;AACrD,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEO,SAAS,qBAAqB,KAAsB;AACzD,QAAM,aAAa,aAAa,GAAG;AACnC,QAAM,WAAW,0BAA0B;AAC3C,SAAO,KAAK,IAAI,KAAK,MAAM,QAAQ,GAAG,CAAC;AACzC;ACVO,SAAS,qBACd,WACA,QAC8C;AAC9C,QAAM,mBAAgC;AAAA,IACpC,GAAG;AAAA,IACH,GAAG;AAAA,IACH,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,SAAS;AAAA,IACT,SAAS;AAAA,EAAA;AAGX,MAAI,UAAU,WAAW,GAAG;AAC1B,WAAO,EAAE,WAAW,iBAAA;AAAA,EACtB;AAEA,QAAM,aAAa,UAAU,CAAC;AAC9B,QAAM,YAAY,UAAU,UAAU,SAAS,CAAC;AAEhD,MAAI,UAAU,WAAW,MAAM;AAC7B,WAAO;AAAA,MACL,WAAW,EAAE,GAAG,kBAAkB,GAAG,WAAW,UAAA;AAAA,MAChD,SAAS,WAAW;AAAA,IAAA;AAAA,EAExB;AAEA,MAAI,UAAU,UAAU,MAAM;AAC5B,WAAO;AAAA,MACL,WAAW,EAAE,GAAG,kBAAkB,GAAG,UAAU,UAAA;AAAA,MAC/C,SAAS,UAAU;AAAA,IAAA;AAAA,EAEvB;AAGA,MAAI,YAAY;AAChB,MAAI,YAAY;AAEhB,WAAS,IAAI,GAAG,IAAI,UAAU,SAAS,GAAG,KAAK;AAC7C,UAAM,eAAe,UAAU,CAAC;AAChC,UAAM,iBAAiB,UAAU,IAAI,CAAC;AACtC,QAAI,UAAU,aAAa,QAAQ,SAAS,eAAe,MAAM;AAC/D,kBAAY;AACZ,kBAAY;AACZ;AAAA,IACF;AAAA,EACF;AAEA,QAAM,WAAW,UAAU,OAAO,UAAU;AAC5C,QAAM,UAAU,SAAS,UAAU;AACnC,QAAM,WAAW,UAAU;AAC3B,QAAM,gBAAgB,YAAY,UAAU,UAAU,UAAU,QAAQ;AAExE,QAAM,gBAAgB,UAAU,aAAa,EAAE,GAAG,GAAG,GAAG,EAAA;AACxD,QAAM,gBAAgB,UAAU,aAAa,EAAE,GAAG,GAAG,GAAG,EAAA;AAExD,QAAM,YAAY,qBAAqB,eAAe,eAAe,aAAa;AAElF,QAAM,UACJ,UAAU,YAAY,UAAa,UAAU,YAAY,SACrD,KAAK,UAAU,SAAS,UAAU,SAAS,aAAa,IACxD;AAEN,SAAO,EAAE,WAAW,QAAA;AACtB;AAEO,SAAS,qBAAqB,MAAmB,IAAiB,GAAwB;AAC/F,SAAO;AAAA,IACL,GAAG,KAAK,KAAK,KAAK,GAAG,GAAG,KAAK,GAAG,CAAC;AAAA,IACjC,GAAG,KAAK,KAAK,KAAK,GAAG,GAAG,KAAK,GAAG,CAAC;AAAA,IACjC,QAAQ,KAAK,KAAK,UAAU,GAAG,GAAG,UAAU,GAAG,CAAC;AAAA,IAChD,QAAQ,KAAK,KAAK,UAAU,GAAG,GAAG,UAAU,GAAG,CAAC;AAAA,IAChD,UAAU,KAAK,KAAK,YAAY,GAAG,GAAG,YAAY,GAAG,CAAC;AAAA,IACtD,SAAS,KAAK,KAAK,WAAW,KAAK,GAAG,WAAW,KAAK,CAAC;AAAA,IACvD,SAAS,KAAK,KAAK,WAAW,KAAK,GAAG,WAAW,KAAK,CAAC;AAAA,EAAA;AAE3D;AAEO,SAAS,KAAK,GAAW,GAAW,GAAmB;AAC5D,SAAO,KAAK,IAAI,KAAK;AACvB;AAEO,SAAS,YAAY,GAAW,QAAwB;AAC7D,UAAQ,QAAA;AAAA,IACN,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAEH,aAAO,IAAI,IAAI;AAAA,IACjB,KAAK,YAAY;AAEf,YAAM,YAAY,IAAI;AACtB,aAAO,IAAI,YAAY,YAAY;AAAA,IACrC;AAAA,IACA,KAAK;AAEH,aAAO,IAAI,MAAM,IAAI,IAAI,IAAI,IAAI,IAAI,KAAK,IAAI,KAAK,IAAI,GAAG,CAAC,IAAI;AAAA,IACjE;AACE,aAAO;AAAA,EAAA;AAEb;ACnFO,MAAM,mBAAmB;AAAA,EACb;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAGT,mBAAmB;AAAA,EACnB,oBAA4B;AAAA,EAC5B,oBAAkC,CAAA;AAAA,EAE1C,YAAY,WAAmB,gBAAwB,cAAsB,GAAG;AAC9E,QAAI,aAAa,GAAG;AAClB,YAAM,IAAI,MAAM,uBAAuB,SAAS,EAAE;AAAA,IACpD;AACA,QAAI,kBAAkB,GAAG;AACvB,YAAM,IAAI,MAAM,0BAA0B,cAAc,EAAE;AAAA,IAC5D;AAEA,SAAK,iBAAiB;AACtB,SAAK,kBAAkB,KAAK,MAAM,MAAY,SAAS;AACvD,SAAK,cAAc;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKA,eAAwD;AACtD,WAAO,IAAI,gBAAwC;AAAA,MACjD,OAAO,MAAM;AAEX,aAAK,mBAAmB;AACxB,aAAK,oBAAoB;AACzB,aAAK,oBAAoB,CAAA;AACzB,aAAK,mBAAmB;AACxB,aAAK,mBAAmB;AAAA,MAC1B;AAAA,MAEA,WAAW,CAAC,aAAa,eAAe;AACtC,aAAK,mBAAmB,aAAa,UAAU;AAAA,MACjD;AAAA,MAEA,OAAO,CAAC,eAAe;AACrB,aAAK,qBAAqB,UAAU;AAAA,MACtC;AAAA,IAAA,CACD;AAAA,EACH;AAAA,EAEQ,mBAAmB;AAAA,EACnB,mBAAmB;AAAA;AAAA;AAAA;AAAA,EAKnB,mBACN,aACA,YACM;AACN,UAAM,kBAAkB,YAAY,aAAa;AAGjD,QAAI,kBAAkB,KAAK,aAAa;AACtC,kBAAY,MAAA;AACZ;AAAA,IACF;AAGA,QAAI;AACJ,QAAI,KAAK,cAAc,GAAG;AAExB,YAAM,oBAAoB,kBAAkB,KAAK;AACjD,sBAAgB,IAAI,WAAW,aAAa;AAAA,QAC1C,WAAW;AAAA,QACX,UAAU,YAAY,YAAY;AAAA,MAAA,CACnC;AACD,kBAAY,MAAA;AAAA,IACd,OAAO;AAEL,sBAAgB;AAAA,IAClB;AAGA,SAAK,kBAAkB,KAAK,aAAa;AACzC,SAAK;AAGL,WAAO,KAAK,oBAAoB,KAAK,gBAAgB;AACnD,YAAM,eAAe,KAAK,iBAAiB,KAAK,iBAAiB;AAEjE,UAAI,CAAC,cAAc;AAEjB;AAAA,MACF;AAIA,UAAI,KAAK,uBAAuB,YAAY,GAAG;AAC7C;AAAA,MACF;AAGA,UAAI;AACF,cAAM,cAAc,IAAI,WAAW,cAAc;AAAA,UAC/C,WAAW,KAAK;AAAA,UAChB,UAAU,KAAK;AAAA,QAAA,CAChB;AAED,mBAAW,QAAQ,WAAW;AAC9B,aAAK;AAGL,aAAK,iBAAiB,KAAK,iBAAiB;AAG5C,aAAK;AACL,aAAK,oBAAoB,KAAK,mBAAmB,KAAK;AAAA,MACxD,SAAS,QAAQ;AACf,gBAAQ,MAAM,uDAAuD,MAAM;AAE3E,aAAK;AACL,aAAK,oBAAoB,KAAK,mBAAmB,KAAK;AAAA,MACxD;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,qBAAqB,YAAgE;AAE3F,WAAO,KAAK,kBAAkB,SAAS,KAAK,KAAK,oBAAoB,KAAK,gBAAgB;AACxF,YAAM,eAAe,KAAK,iBAAiB,KAAK,iBAAiB;AACjE,UAAI,CAAC,aAAc;AAEnB,UAAI,CAAC,KAAK,kBAAkB,cAAc,UAAU,EAAG;AAAA,IACzD;AAGA,SAAK,iBAAiB,IAAI;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAKQ,kBACN,aACA,YACS;AACT,QAAI;AACF,YAAM,cAAc,IAAI,WAAW,aAAa;AAAA,QAC9C,WAAW,KAAK;AAAA,QAChB,UAAU,KAAK;AAAA,MAAA,CAChB;AAED,iBAAW,QAAQ,WAAW;AAC9B,WAAK;AACL,WAAK,oBAAoB,KAAK,mBAAmB,KAAK;AACtD,aAAO;AAAA,IACT,SAAS,OAAO;AACd,cAAQ,MAAM,uDAAuD,KAAK;AAC1E,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,iBAAiB,WAAoC;AAC3D,eAAW,SAAS,KAAK,mBAAmB;AAC1C,UAAI,UAAU,UAAW;AAEzB,UAAI;AACF,cAAM,MAAA;AAAA,MACR,QAAQ;AAAA,MAER;AAAA,IACF;AACA,SAAK,oBAAoB,CAAA;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA,EAKQ,iBAAiB,cAAyC;AAChE,QAAI,KAAK,kBAAkB,WAAW,GAAG;AACvC,aAAO;AAAA,IACT;AAEA,QAAI,eAAe,KAAK,kBAAkB,CAAC;AAC3C,QAAI,WAAW,KAAK,KAAK,cAAc,aAAa,KAAK,YAAY;AAErE,eAAW,SAAS,KAAK,mBAAmB;AAC1C,YAAM,QAAQ,KAAK,KAAK,MAAM,aAAa,KAAK,YAAY;AAC5D,UAAI,QAAQ,UAAU;AACpB,mBAAW;AACX,uBAAe;AAAA,MACjB;AAAA,IACF;AAEA,WAAO,gBAAgB;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASQ,uBAAuB,cAAmC;AAChE,QAAI,KAAK,kBAAkB,UAAU,GAAG;AACtC,YAAM,iBAAiB,aAAa,aAAa;AAGjD,UAAI,iBAAiB,KAAK,mBAAmB;AAC3C,eAAO;AAAA,MACT;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,iBAAiB,qBAAmC;AAC1D,UAAM,mBAAmB,sBAAsB,KAAK;AAGpD,UAAM,uBAAuB,sBAAsB,KAAK;AAExD,QAAI,cAAc;AAClB,aAAS,IAAI,GAAG,IAAI,KAAK,kBAAkB,QAAQ,KAAK;AACtD,YAAM,QAAQ,KAAK,kBAAkB,CAAC;AACtC,UAAI,CAAC,MAAO;AAEZ,YAAM,iBAAiB,MAAM,aAAa;AAM1C,YAAM,kBACJ,KAAK,IAAI,iBAAiB,gBAAgB,IAC1C,KAAK,IAAI,iBAAiB,oBAAoB;AAEhD,UAAI,iBAAiB,wBAAwB,CAAC,iBAAiB;AAE7D,YAAI;AACF,gBAAM,MAAA;AAAA,QACR,QAAQ;AAAA,QAER;AACA;AAAA,MACF,OAAO;AAEL;AAAA,MACF;AAAA,IACF;AAGA,QAAI,cAAc,GAAG;AACnB,WAAK,kBAAkB,OAAO,GAAG,WAAW;AAAA,IAC9C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,WAKE;AACA,WAAO;AAAA,MACL,kBAAkB,KAAK;AAAA,MACvB,mBAAmB,KAAK;AAAA,MACxB,YAAY,KAAK,kBAAkB;AAAA,MACnC,iBAAiB,KAAK;AAAA,IAAA;AAAA,EAE1B;AACF;ACpSA,SAAS,oBACP,QACA,WACuB;AACvB,SAAO,OAAO,OAAO,CAAC,UAAU;AAE9B,WAAO,MAAM,aAAa;AAAA,MACxB,CAAC,UAAU,aAAa,MAAM,WAAW,YAAY,MAAM;AAAA,IAAA;AAAA,EAE/D,CAAC;AACH;AAEA,SAAS,iBACP,OACA,OACA,UACA,cACc;AACd,QAAM,YAAmB;AAAA,IACvB,IAAI,MAAM;AAAA,IACV,MAAM,MAAM;AAAA,IACZ,QAAQ,MAAM,UAAU;AAAA,IACxB,SAAS;AAAA,IACT,SAAS,MAAM,WAAW;AAAA,EAAA;AAG5B,MAAI,MAAM,SAAS,SAAS;AAC1B,WAAO;AAAA,MACL,GAAG;AAAA,MACH,MAAM;AAAA,MACN,YAAY;AAAA,IAAA;AAAA,EAEhB;AAEA,MAAI,MAAM,SAAS,QAAQ;AACzB,UAAM,UAAU,MAAM;AACtB,WAAO;AAAA,MACL,GAAG;AAAA,MACH,MAAM;AAAA,MACN,MAAM,QAAQ;AAAA,MACd,YAAY,QAAQ;AAAA,MACpB,YAAY,QAAQ;AAAA,MACpB,WAAW,QAAQ;AAAA,MACnB,aAAa,QAAQ;AAAA,MACrB,YAAY,QAAQ;AAAA,IAAA;AAAA,EAExB;AAEA,MAAI,MAAM,SAAS,SAAS;AAC1B,UAAM,UAAU,MAAM;AACtB,UAAM,aAAa,QAAQ;AAC3B,UAAM,SAAS,SAAS,IAAI,UAAU,KAAK;AAE3C,UAAM,aAAyB;AAAA,MAC7B,GAAG;AAAA,MACH,MAAM;AAAA,MACN;AAAA,MACA,cAAc,QAAQ;AAAA,IAAA;AAIxB,QAAI,QAAQ,gBAAgB,QAAW;AACpC,iBAAmB,cAAc,QAAQ;AAAA,IAC5C;AACA,QAAI,QAAQ,iBAAiB,QAAW;AACrC,iBAAmB,eAAe,QAAQ;AAAA,IAC7C;AAGA,QAAI,QAAQ,aAAa,iBAAiB,QAAW;AACnD,YAAM,YAAY,sBAAsB,QAAQ,WAAW,YAAY;AAGvE,UAAI,CAAC,UAAU,SAAS;AACtB,eAAO;AAAA,MACT;AAGA,iBAAW,YAAY;AAAA,QACrB,GAAG,UAAU,UAAU,KAAK;AAAA,QAC5B,GAAG,UAAU,UAAU,KAAK;AAAA,QAC5B,QAAQ,UAAU,UAAU,UAAU;AAAA,QACtC,QAAQ,UAAU,UAAU,UAAU;AAAA,QACtC,UAAU,UAAU,UAAU,YAAY;AAAA,QAC1C,SAAS,UAAU,UAAU,WAAW;AAAA,QACxC,SAAS,UAAU,UAAU,WAAW;AAAA,MAAA;AAE1C,UAAI,UAAU,YAAY,QAAW;AACnC,mBAAW,UAAU,UAAU;AAAA,MACjC;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,SAAS,sBACP,WACA,cACgE;AAChE,QAAM,EAAE,UAAU,WAAW,mBAAA,IAAuB;AAGpD,QAAM,iBAAiB,eAAe;AAGtC,MAAI,iBAAiB,KAAK,iBAAiB,UAAU,UAAU,SAAS,CAAC,EAAE,MAAM;AAC/E,WAAO;AAAA,MACL,WAAW,EAAE,GAAG,GAAG,GAAG,GAAG,QAAQ,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,KAAK,SAAS,IAAA;AAAA,MACnF,SAAS;AAAA,MACT,SAAS;AAAA,IAAA;AAAA,EAEb;AAGA,QAAM,YAAY,qBAAqB,WAAW,cAAc;AAIhE,QAAM,cAAc,UAAU,WAAW,YAAY;AACrD,QAAM,cAAe,cAAc,KAAK,KAAM;AAE9C,QAAM,iBAA8B;AAAA,IAClC,GAAG,SAAS,KAAK,UAAU,WAAW,KAAK;AAAA,IAC3C,GAAG,SAAS,KAAK,UAAU,WAAW,KAAK;AAAA,IAC3C,QAAQ,UAAU,WAAW,UAAU;AAAA,IACvC,QAAQ,UAAU,WAAW,UAAU;AAAA,IACvC,UAAU;AAAA,IACV,SAAS,UAAU,WAAW,WAAW;AAAA,IACzC,SAAS,UAAU,WAAW,WAAW;AAAA,EAAA;AAG3C,SAAO;AAAA,IACL,WAAW;AAAA,IACX,SAAS,UAAU;AAAA,IACnB,SAAS;AAAA,EAAA;AAEb;AAcO,MAAM,mBAAmB;AAAA,EACtB;AAAA,EACA,WAAiC;AAAA,EACjC,gBAAoE;AAAA,EAEpE,YAA2B;AAAA,EAC3B,iBAAqC;AAAA,EACrC,eAAmC;AAAA,EACnC,eAA0C;AAAA,EAC1C,+BAAe,IAAA;AAAA,EAEvB,cAAc;AAEZ,SAAK,UAAU,IAAI,cAAc,MAAM;AAAA,MACrC,MAAM;AAAA,MACN,SAAS;AAAA,IAAA,CACV;AAED,SAAK,cAAA;AAAA,EACP;AAAA,EAEQ,gBAAsB;AAE5B,SAAK,QAAQ,gBAAgB,aAAa,KAAK,gBAAgB,KAAK,IAAI,CAAC;AACzE,SAAK,QAAQ,gBAAgB,WAAW,KAAK,cAAc,KAAK,IAAI,CAAC;AACrE,SAAK,QAAQ,gBAAgB,SAAS,KAAK,YAAY,KAAK,IAAI,CAAC;AAEjE,SAAK,QAAQ,gBAAgB,aAAa,KAAK,eAAe,KAAK,IAAI,CAAC;AACxE,SAAK,QAAQ,gBAAgB,wBAAwB,KAAK,0BAA0B,KAAK,IAAI,CAAC;AAC9F,SAAK,QAAQ,gBAAgB,iBAAiB,KAAK,mBAAmB,KAAK,IAAI,CAAC;AAChF,SAAK,QAAQ,gBAAgB,gBAAgB,KAAK,kBAAkB,KAAK,IAAI,CAAC;AAC9E,SAAK,QAAQ,gBAAgB,kBAAkB,SAAS,KAAK,cAAc,KAAK,IAAI,CAAC;AAGrF,SAAK,QAAQ,cAAc,KAAK,oBAAoB,KAAK,IAAI,CAAC;AAAA,EAChE;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,cAAc,SAKM;AAChC,UAAM,EAAE,MAAM,WAAW,UAAA,IAAc;AAEvC,QAAI,aAAa,CAAC,KAAK,WAAW;AAChC,WAAK,YAAY;AAAA,IACnB;AAEA,QAAI,cAAc,YAAY;AAC5B,WAAK,eAAe;AACpB,YAAM,UAAU,IAAI,cAAc,MAAM;AAAA,QACtC,MAAM;AAAA,QACN,SAAS;AAAA,MAAA,CACV;AACD,cAAQ,cAAc,KAAK,oBAAoB,KAAK,IAAI,CAAC;AAAA,IAC3D;AACA,QAAI,cAAc,cAAc;AAC9B,WAAK,iBAAiB;AAAA,IACxB;AACA,WAAO,EAAE,SAAS,KAAA;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,gBAAgB,SAM3B;AACD,UAAM,EAAE,QAAQ,QAAA,IAAY;AAC5B,UAAM,qBAAqB,OAAO,QAAQ,KAAK,OAAO,SAAS;AAC/D,UAAM,cAAc,OAAO,MAAM;AAEjC,QAAI,CAAC,sBAAsB,CAAC,aAAa;AACvC,YAAM,IAAI;AAAA,QACR,mDAAmD,OAAO,KAAK,YAAY,OAAO,MAAM,SAAS,OAAO,GAAG;AAAA,MAAA;AAAA,IAE/G;AAGA,QAAI,SAAS;AACX,WAAK,QAAQ,QAAQ,YAAY;AAAA,IACnC;AAEA,QAAI,WAAW,CAAC,KAAK,UAAU;AAE7B,UAAI,KAAK,UAAU;AACjB,aAAK,SAAS,QAAA;AACd,aAAK,gBAAgB;AAAA,MACvB;AAGA,WAAK,WAAW,IAAI,cAAc,MAAM;AAAA,IAC1C,OAAO;AAEL,WAAK,SAAS,aAAa,MAAM;AAAA,IACnC;AAGA,SAAK,QAAQ,OAAO,cAAc;AAAA,MAChC,QAAQ,KAAK,SAAS;AAAA,MACtB,aAAa,WAAW;AAAA,IAAA,CACzB;AAED,WAAO;AAAA,MACL,SAAS;AAAA,MACT,QAAQ,KAAK,SAAS;AAAA,IAAA;AAAA,EAE1B;AAAA,EAEA,MAAc,oBACZ,QACA,UACe;AACf,QAAI,CAAC,KAAK,UAAU;AAClB,cAAQ,MAAM,8CAA8C;AAC5D;AAAA,IACF;AAIA,QAAI,UAAU,cAAc;AAC1B,YAAM,KAAK,0BAA0B,SAAS,YAAY;AAAA,IAC5D;AAEA,QAAI,CAAC,KAAK,cAAc;AACtB,cAAQ,MAAM,qEAAqE;AACnF;AAAA,IACF;AAGA,UAAM,YAAY,KAAK,aAAa,OAAO;AAAA,MACzC,CAAC,MAAM,EAAE,SAAS,WAAW,CAAC,EAAE,QAAQ;AAAA,IAAA;AAE1C,UAAM,cAAc,WAAW,SAAS,UAAW,UAAU,QAAQ,eAAe,IAAK;AAGzF,UAAM,WAAW,KAAK,aAAa,WAAW;AAC9C,UAAM,eAAe,IAAI;AAAA,MACvB,UAAU,kBAAkB;AAAA,MAC5B,UAAU,kBAAkB;AAAA,MAC5B;AAAA,IAAA;AAIF,UAAM,YAAY,OAAO,YAAY,aAAa,cAAc;AAEhE,UAAM,iBAAiB,UAAU;AAAA,MAC/B,IAAI,gBAA4C;AAAA,QAC9C,WAAW,CAAC,OAAO,eAAe;AAChC,cAAI;AACF,kBAAM,UAAU,KAAK,oBAAoB,KAAK,cAAe,KAAK;AAClE,gBAAI,CAAC,SAAS;AACZ,oBAAM,MAAA;AACN;AAAA,YACF;AACA,uBAAW,QAAQ,OAAO;AAAA,UAC5B,SAAS,OAAO;AACd,oBAAQ,MAAM,mDAAmD,KAAK;AACtE,mBAAO,QAAA;AACP,kBAAM;AAAA,UACR;AAAA,QACF;AAAA,MAAA,CACD;AAAA,IAAA;AAGH,UAAM,gBAAgB,KAAK,SAAS,cAAA;AAEpC,mBAAe,OAAO,cAAc,QAAQ,EAAE,MAAM,CAAC,UAAU;AAC7D,cAAQ,MAAM,6CAA6C,KAAK,WAAW,KAAK;AAAA,IAClF,CAAC;AAED,UAAM,OAAO;AAAA,MACX,GAAG;AAAA,MACH,YAAY;AAAA,MACZ,WAAW,KAAK;AAAA,IAAA;AAGlB,QAAI,KAAK,gBAAgB;AACvB,YAAM,gBAAgB,IAAI,cAAc,KAAK,gBAAgB;AAAA,QAC3D,MAAM;AAAA,QACN,SAAS;AAAA,MAAA,CACV;AACD,oBAAc,WAAW,cAAc,UAAU,IAAI;AAAA,IACvD,OAAO;AACL,WAAK,QAAQ,WAAW,cAAc,UAAU,IAAI;AAAA,IACtD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAc,cAA6C;AACzD,QAAI;AAIF,WAAK,QAAQ,OAAO,kBAAkB,CAAA,CAAE;AACxC,aAAO,EAAE,SAAS,KAAA;AAAA,IACpB,SAAS,OAAY;AACnB,YAAM;AAAA,QACJ,MAAM;AAAA,QACN,SAAS,MAAM;AAAA,MAAA;AAAA,IAEnB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,iBAIX;AACD,WAAO;AAAA,MACL,YAAY,KAAK,aAAa;AAAA,MAC9B,QAAQ,KAAK,UAAU;AAAA,MACvB,WAAW,KAAK,kBAAkB;AAAA,IAAA;AAAA,EAEtC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,gBAA+C;AAC3D,QAAI,KAAK,UAAU;AACjB,WAAK,SAAS,QAAA;AACd,WAAK,WAAW;AAAA,IAClB;AAEA,SAAK,gBAAgB;AAErB,SAAK,gBAAgB,MAAA;AACrB,SAAK,cAAc,MAAA;AACnB,SAAK,iBAAiB;AACtB,SAAK,eAAe;AAEpB,SAAK,SAAS,QAAQ,CAAC,WAAW,OAAO,OAAO;AAChD,SAAK,SAAS,MAAA;AACd,SAAK,eAAe;AAEpB,SAAK,QAAQ,QAAQ,YAAY;AAEjC,WAAO,EAAE,SAAS,KAAA;AAAA,EACpB;AAAA,EAEA,MAAc,0BACZ,SAC+B;AAC/B,UAAM,EAAE,QAAQ,SAAA,IAAa;AAE7B,QAAI,CAAC,KAAK,WAAW;AACnB,WAAK,YAAY;AAAA,IACnB;AAEA,QAAI,KAAK,gBAAgB,KAAK,aAAa,WAAW,UAAU;AAC9D,aAAO,EAAE,SAAS,MAAA;AAAA,IACpB;AAEA,SAAK,eAAe;AAEpB,WAAO,EAAE,SAAS,KAAA;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,mBAAmB,SAKC;AAChC,UAAM,EAAE,YAAY,WAAW,aAAa,iBAAiB;AAE7D,QAAI,CAAC,KAAK,WAAW;AACnB,WAAK,YAAY;AAAA,IACnB;AAGA,QAAI,cAAc;AAChB,YAAM,KAAK,0BAA0B,YAAY;AAAA,IACnD;AAGA,UAAM,WAAW,KAAK,SAAS,IAAI,UAAU;AAC7C,QAAI,UAAU;AACZ,eAAS,MAAA;AAAA,IACX;AAEA,SAAK,SAAS,IAAI,YAAY,WAAW;AAGzC,QAAI,KAAK,cAAc;AACrB,YAAM,YAAY,KAAK,aAAa,OAAO,KAAK,CAAC,MAAM,CAAC,EAAE,QAAQ,YAAY;AAC9E,YAAM,iBAAiB,WAAW,QAAQ;AAC1C,UAAI,eAAe,gBAAgB;AACjC,cAAM,KAAK,sBAAA;AAAA,MACb;AAAA,IACF;AAEA,WAAO,EAAE,SAAS,KAAA;AAAA,EACpB;AAAA,EAEA,MAAc,oBAAmD;AAC/D,SAAK,eAAe;AAEpB,SAAK,gBAAgB,MAAA;AACrB,SAAK,cAAc,MAAA;AACnB,SAAK,iBAAiB;AACtB,SAAK,eAAe;AAEpB,SAAK,SAAS,QAAQ,CAAC,WAAW,OAAO,OAAO;AAChD,SAAK,SAAS,MAAA;AAEd,WAAO,EAAE,SAAS,KAAA;AAAA,EACpB;AAAA,EAEA,MAAc,wBAAuC;AACnD,QAAI,CAAC,KAAK,gBAAgB,CAAC,KAAK,UAAU;AACxC;AAAA,IACF;AAEA,UAAM,WAAW,KAAK,aAAa,WAAW;AAC9C,QAAI,CAAC,UAAU;AACb;AAAA,IACF;AAGA,UAAM,YAAY,KAAK,aAAa,OAAO,KAAK,CAAC,MAAM,CAAC,EAAE,QAAQ,YAAY;AAC9E,QAAI,CAAC,UAAW;AAEhB,UAAM,iBAAkB,UAAU,QAAgB;AAClD,UAAM,cAAc,KAAK,SAAS,IAAI,cAAc;AACpD,QAAI,CAAC,aAAa;AAChB,cAAQ,KAAK,0DAA0D,cAAc;AACrF;AAAA,IACF;AAEA,UAAM,gBAAgB,KAAK,SAAS,cAAA;AAEpC,UAAM,EAAE,gBAAgB,eAAA,IAAmB;AAE3C,QAAI,gBAAgB;AACpB,UAAM,iBAAiB,IAAI,eAA+B;AAAA,MACxD,MAAM,CAAC,eAAe;AACpB,YAAI,iBAAiB,gBAAgB;AACnC,qBAAW,MAAA;AACX;AAAA,QACF;AAEA,cAAM,aAAa,IAAI,WAAW,aAAa;AAAA,UAC7C,WAAW;AAAA,UACX,UAAU,qBAAqB,cAAc;AAAA,QAAA,CAC9C;AACD,YAAI;AACF,gBAAM,UAAU,KAAK,oBAAoB,KAAK,cAAe,UAAU;AACvE,cAAI,SAAS;AACX,uBAAW,QAAQ,OAAO;AAAA,UAC5B,OAAO;AACL,uBAAW,MAAA;AAAA,UACb;AACA,2BAAiB,qBAAqB,cAAc;AAAA,QACtD,SAAS,OAAO;AACd,qBAAW,MAAA;AACX,gBAAM;AAAA,QACR;AAAA,MACF;AAAA,IAAA,CACD;AAED,mBAAe,OAAO,cAAc,QAAQ,EAAE,MAAM,CAAC,UAAU;AAC7D,cAAQ,MAAM,iDAAiD,KAAK,WAAW,KAAK;AAAA,IACtF,CAAC;AAED,UAAM,OAAO;AAAA,MACX,YAAY;AAAA,MACZ,WAAW,KAAK;AAAA,IAAA;AAGlB,QAAI,KAAK,gBAAgB;AACvB,YAAM,gBAAgB,IAAI,cAAc,KAAK,gBAAgB;AAAA,QAC3D,MAAM;AAAA,QACN,SAAS;AAAA,MAAA,CACV;AACD,oBAAc,WAAW,cAAc,UAAU,IAAI;AAAA,IACvD,OAAO;AACL,WAAK,QAAQ,WAAW,cAAc,UAAU,IAAI;AAAA,IACtD;AAAA,EACF;AAAA,EAEQ,oBACN,aACA,OACuB;AACvB,UAAM,mBAAmB,MAAM,aAAa;AAC5C,UAAM,iBAAiB,YAAY,WAAW,UAAU,kBAAkB;AAG1E,QAAI,mBAAmB,KAAK,oBAAoB,gBAAgB;AAC9D,aAAO;AAAA,IACT;AAEA,UAAM,eAAe,oBAAoB,YAAY,QAAQ,gBAAgB;AAE7E,QAAI,CAAC,aAAa,QAAQ;AACxB,aAAO;AAAA,IACT;AAGA,UAAM,cAAc,YAAY,WAAW,UAAU,eAAe;AACpE,UAAM,eAAe,cAAc;AAGnC,UAAM,SAAS,aACZ,IAAI,CAAC,UAAU,iBAAiB,OAAO,OAAO,KAAK,UAAU,YAAY,CAAC,EAC1E,OAAO,CAAC,UAA0B,UAAU,IAAI;AAEnD,QAAI,CAAC,OAAO,QAAQ;AAClB,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,MACL,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,MACA,YAAY,mBAAmB;AAAA,QAC7B,YAAY;AAAA,QACZ;AAAA,QACA,YAAY,WAAW;AAAA,MAAA;AAAA,IACzB;AAAA,EAEJ;AAAA,EAEA,OAAe,gBACb,aACA,QACA,WACA;AACA,UAAM,QAAQ,YAAY,KAAK,CAAC,eAAe;AAC7C,YAAM,EAAE,SAAS,MAAA,IAAU,WAAW;AACtC,aAAO,UAAU,WAAW,SAAS;AAAA,IACvC,CAAC;AACD,QAAI,CAAC,OAAO;AACV,aAAO;AAAA,IACT;AACA,UAAM,aAAa,MAAM,MAAM,QAAQ,MAAM,MAAM;AACnD,UAAM,WAAW,aAAa,KAAK,SAAS,MAAM,MAAM,WAAW,aAAa;AAChF,WAAO;AAAA,MACL,MAAM,MAAM,OAAO;AAAA,MACnB,UAAU,KAAK,IAAI,KAAK,IAAI,UAAU,CAAC,GAAG,CAAC;AAAA,MAC3C,QAAQ,MAAM,OAAO;AAAA,MACrB,QAAQ,MAAM,OAAO;AAAA,MACrB,WAAW,MAAM,OAAO,SAAS;AAAA,IAAA;AAAA,EAErC;AACF;AAGA,MAAM,SAAS,IAAI,mBAAA;AAGnB,KAAK,iBAAiB,gBAAgB,MAAM;AAC1C,SAAO,eAAe,EAAA;AACxB,CAAC;AAED,MAAA,sBAAe;"}