mcp-scraper 0.1.0 → 0.1.2
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.
- package/README.md +5 -0
- package/dist/bin/api-server.cjs +15553 -7587
- package/dist/bin/api-server.cjs.map +1 -1
- package/dist/bin/api-server.js +3 -3
- package/dist/bin/mcp-stdio-server.cjs +312 -119
- package/dist/bin/mcp-stdio-server.cjs.map +1 -1
- package/dist/bin/mcp-stdio-server.js +1 -1
- package/dist/bin/paa-harvest.cjs +1537 -165
- package/dist/bin/paa-harvest.cjs.map +1 -1
- package/dist/bin/paa-harvest.js +1 -1
- package/dist/{chunk-LXZDJJXR.js → chunk-D4CJBZBY.js} +426 -29
- package/dist/chunk-D4CJBZBY.js.map +1 -0
- package/dist/chunk-HERFK7W6.js +2781 -0
- package/dist/chunk-HERFK7W6.js.map +1 -0
- package/dist/chunk-JQKZWEON.js +1000 -0
- package/dist/chunk-JQKZWEON.js.map +1 -0
- package/dist/chunk-Y74EXABN.js +295 -0
- package/dist/chunk-Y74EXABN.js.map +1 -0
- package/dist/{db-IOYMX64U.js → db-YWCNHBLH.js} +36 -4
- package/dist/index.cjs +1660 -237
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +169 -2
- package/dist/index.d.ts +169 -2
- package/dist/index.js +120 -69
- package/dist/index.js.map +1 -1
- package/dist/server-W5NWH5KF.js +11625 -0
- package/dist/server-W5NWH5KF.js.map +1 -0
- package/dist/{worker-3ECJHPRE.js → worker-D4D2YQTA.js} +44 -9
- package/dist/worker-D4D2YQTA.js.map +1 -0
- package/package.json +17 -5
- package/dist/chunk-4API3ZCT.js +0 -1387
- package/dist/chunk-4API3ZCT.js.map +0 -1
- package/dist/chunk-LXZDJJXR.js.map +0 -1
- package/dist/chunk-ZBP4RHNW.js +0 -805
- package/dist/chunk-ZBP4RHNW.js.map +0 -1
- package/dist/server-63DR2HE5.js +0 -6062
- package/dist/server-63DR2HE5.js.map +0 -1
- package/dist/worker-3ECJHPRE.js.map +0 -1
- /package/dist/{db-IOYMX64U.js.map → db-YWCNHBLH.js.map} +0 -0
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/schemas.ts","../src/driver/BrowserDriver.ts","../src/selectors.ts","../src/errors.ts","../src/locations.ts","../src/uule.ts","../src/lib/paa-answer-cleanup.ts","../src/extractor/PAAExtractor.ts","../src/output/OutputSerializer.ts","../src/output/ProgressReporter.ts","../src/harvest.ts","../src/video/VideoGenerator.ts","../src/video/promptBuilder.ts","../src/video/AudioGenerator.ts","../src/video/VideoMixer.ts"],"sourcesContent":["export { harvest } from './harvest.js'\nexport type { HarvestOptions, HarvestResult, PAANode, FlatRow, HarvestStats, AIOverviewResult, AIModeResult, AICitation, GoogleSurface, WhatPeopleSayingCard } from './types.js'\nexport { VideoGenerator } from './video/VideoGenerator.js'\nexport type { ClipPairOptions, ClipPairResult } from './video/VideoGenerator.js'\nexport { buildClipPrompts } from './video/promptBuilder.js'\n","import { z } from 'zod'\n\nexport const HarvestOptionsSchema = z.object({\n query: z.string().min(1),\n location: z.string().optional(),\n gl: z.string().length(2).default('us'),\n hl: z.string().length(2).default('en'),\n depth: z.number().int().min(1).max(30).default(3),\n maxQuestions: z.number().int().min(1).max(1000).default(100),\n headless: z.boolean().default(false),\n profileDir: z.string().optional(),\n proxy: z.string().url().optional(),\n kernelApiKey: z.string().optional(),\n kernelProxyId: z.string().optional(),\n outputDir: z.string().default('./paa-output'),\n format: z.enum(['json', 'csv', 'both']).default('both'),\n serpOnly: z.boolean().default(false),\n pages: z.number().int().min(1).max(2).default(1),\n})\n\nexport const MapsPlaceOptionsSchema = z.object({\n businessName: z.string().min(1),\n location: z.string().min(1),\n gl: z.string().length(2).default('us'),\n hl: z.string().length(2).default('en'),\n includeReviews: z.boolean().default(false),\n maxReviews: z.number().int().min(1).max(500).default(50),\n kernelApiKey: z.string().optional(),\n kernelProxyId: z.string().optional(),\n headless: z.boolean().default(true),\n})\n\nexport const RawPAAItemSchema = z.object({\n question: z.string().min(1),\n answer: z.string().optional(),\n sourceTitle: z.string().optional(),\n sourceSite: z.string().optional(),\n sourceCite: z.string().optional(),\n})\n","import { chromium } from 'playwright-extra'\nimport StealthPlugin from 'puppeteer-extra-plugin-stealth'\nimport { chromium as playwrightChromium } from 'playwright'\nimport type { Browser, BrowserContext, Page } from 'playwright'\nimport Kernel from '@onkernel/sdk'\nimport { PAASelectors } from '../selectors.js'\nimport { CaptchaError, ExtractionError, RECAPTCHA_INSTRUCTIONS } from '../errors.js'\nimport type { DriverConfig, UuleString } from '../types.js'\nimport type { IBrowserDriver } from './IBrowserDriver.js'\n\nchromium.use(StealthPlugin())\n\nconst DESKTOP_USER_AGENT =\n 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36'\n\nexport function buildYouTubeChannelVideosUrl(channelInput: string): string {\n const raw = channelInput.trim()\n if (!raw) throw new Error('channelHandle is required')\n\n const urlLike = /^https?:\\/\\//i.test(raw) || /^(www\\.|m\\.)?youtube\\.com\\//i.test(raw)\n if (urlLike) {\n const parsed = new URL(/^https?:\\/\\//i.test(raw) ? raw : `https://${raw}`)\n const host = parsed.hostname.replace(/^www\\./, '').replace(/^m\\./, '').toLowerCase()\n if (host !== 'youtube.com') throw new Error('channel URL must be on youtube.com')\n\n const segments = parsed.pathname.split('/').filter(Boolean)\n const first = segments[0] ?? ''\n const second = segments[1] ?? ''\n\n if (first.startsWith('@')) return `https://www.youtube.com/${first}/videos`\n if (first === 'channel' && second) return `https://www.youtube.com/channel/${second}/videos`\n if ((first === 'c' || first === 'user') && second) return `https://www.youtube.com/${first}/${second}/videos`\n\n throw new Error('channel URL must be a YouTube handle, /channel/UC..., /c/..., or /user/... URL')\n }\n\n const stripped = raw.replace(/^\\/+/, '').replace(/\\/+$/, '')\n const withoutVideos = stripped.replace(/\\/videos$/i, '')\n if (/^UC[\\w-]{20,}$/.test(withoutVideos)) {\n return `https://www.youtube.com/channel/${withoutVideos}/videos`\n }\n\n const handle = withoutVideos.startsWith('@') ? withoutVideos : `@${withoutVideos}`\n if (!/^@[\\w.-]+$/.test(handle)) {\n throw new Error('channelHandle must be an @handle, UC channel ID, or YouTube channel URL')\n }\n return `https://www.youtube.com/${handle}/videos`\n}\n\nexport class BrowserDriver implements IBrowserDriver {\n private browser: Browser | null = null\n private context: BrowserContext | null = null\n private page: Page | null = null\n private kernelClient: Kernel | null = null\n private kernelSessionId: string | null = null\n\n async launch(config: DriverConfig): Promise<void> {\n if (config.kernelApiKey) {\n this.kernelClient = new Kernel({ apiKey: config.kernelApiKey })\n const kernelBrowser = await this.kernelClient.browsers.create({\n stealth: true,\n timeout_seconds: 600,\n ...(config.kernelProxyId ? { proxy_id: config.kernelProxyId } : {}),\n })\n this.kernelSessionId = kernelBrowser.session_id\n this.browser = await playwrightChromium.connectOverCDP(kernelBrowser.cdp_ws_url)\n this.context = this.browser.contexts()[0] ?? await this.browser.newContext()\n await this.installEsbuildHelperShims(this.context)\n this.page = this.context.pages()[0] ?? await this.context.newPage()\n return\n }\n\n const launchOpts = {\n headless: config.headless,\n proxy: config.proxy ? { server: config.proxy } : undefined,\n }\n const ctxOpts = {\n viewport: config.viewport,\n locale: config.locale,\n userAgent: DESKTOP_USER_AGENT,\n }\n if (config.profileDir) {\n this.context = await chromium.launchPersistentContext(config.profileDir, {\n ...launchOpts,\n ...ctxOpts,\n })\n await this.installEsbuildHelperShims(this.context)\n this.page = await this.context.newPage()\n } else {\n this.browser = await chromium.launch(launchOpts)\n this.context = await this.browser.newContext(ctxOpts)\n await this.installEsbuildHelperShims(this.context)\n this.page = await this.context.newPage()\n }\n }\n\n private async installEsbuildHelperShims(context: BrowserContext): Promise<void> {\n await context.addInitScript(() => {\n const g = globalThis as Record<string, unknown>\n if (typeof g.__name !== 'function') g.__name = (fn: unknown) => fn\n if (typeof g.__publicField !== 'function') g.__publicField = (obj: Record<string, unknown>, key: string, value: unknown) => { obj[key] = value; return value }\n })\n }\n\n async navigateToSERP(\n query: string,\n uule: UuleString | null,\n gl: string,\n hl: string,\n ): Promise<{ hasPaa: boolean }> {\n const params = new URLSearchParams({ q: query, gl, hl })\n if (uule) params.set('uule', uule)\n const url = 'https://www.google.com/search?' + params.toString()\n\n try {\n await this.page!.goto(url, { waitUntil: 'domcontentloaded', timeout: 45_000 })\n } catch (err) {\n const diag = await this.captureDiagnostics(url)\n throw new ExtractionError(`page.goto failed: ${(err as Error).message} | ${diag}`)\n }\n\n const captchaCount = await this.page!.locator(PAASelectors.captchaMarker).count()\n if (captchaCount > 0) {\n if (this.kernelClient) {\n try {\n await this.page!.waitForSelector(PAASelectors.container, { timeout: 45_000 })\n return { hasPaa: true }\n } catch {\n throw new CaptchaError(this.captchaMessage())\n }\n }\n throw new CaptchaError(this.captchaMessage())\n }\n\n const fastFound = await this.page!.waitForSelector(PAASelectors.item, { timeout: 4_000 }).catch(() => null)\n if (fastFound) return { hasPaa: true }\n\n const captchaAfter = await this.page!.locator(PAASelectors.captchaMarker).count()\n if (captchaAfter > 0) throw new CaptchaError(this.captchaMessage())\n\n for (let i = 1; i <= 6; i++) {\n await this.page!.evaluate((f: number) => { window.scrollTo(0, document.body.scrollHeight * f) }, i / 6)\n await this.page!.waitForTimeout(600)\n const count = await this.page!.locator(PAASelectors.item).count()\n if (count > 0) return { hasPaa: true }\n }\n\n return { hasPaa: false }\n }\n\n private async captureDiagnostics(intendedUrl: string): Promise<string> {\n try {\n const finalUrl = this.page!.url()\n const title = await this.page!.title().catch(() => '')\n const bodySnippet = await this.page!.evaluate(() => {\n const t = (document.body?.innerText ?? '').replace(/\\s+/g, ' ').trim()\n return t.slice(0, 400)\n }).catch(() => '')\n const consent = /consent\\.google\\./.test(finalUrl) || /before you continue/i.test(bodySnippet)\n const recaptcha = /recaptcha|unusual traffic|are you a robot/i.test(bodySnippet)\n const flags = [\n consent ? 'CONSENT_WALL' : '',\n recaptcha ? 'BOT_CHALLENGE' : '',\n finalUrl !== intendedUrl ? 'REDIRECTED' : '',\n ].filter(Boolean).join(',')\n return `intended=${intendedUrl} | final=${finalUrl} | title=\"${title}\" | flags=[${flags}] | body=\"${bodySnippet}\"`\n } catch (e) {\n return `diagnostics-failed: ${(e as Error).message}`\n }\n }\n\n private captchaMessage(): string {\n return this.kernelClient\n ? 'Google returned a CAPTCHA on this Kernel.sh session — retrying with a fresh session.'\n : RECAPTCHA_INSTRUCTIONS\n }\n\n async navigateTo(url: string): Promise<void> {\n try {\n await this.page!.goto(url, { waitUntil: 'domcontentloaded', timeout: 45_000 })\n } catch (err) {\n const diag = await this.captureDiagnostics(url)\n throw new ExtractionError(`page.goto failed: ${(err as Error).message} | ${diag}`)\n }\n }\n\n async navigateToChannel(channelHandle: string): Promise<void> {\n const url = buildYouTubeChannelVideosUrl(channelHandle)\n try {\n await this.page!.goto(url, { waitUntil: 'networkidle', timeout: 30_000 })\n } catch (err) {\n const diag = await this.captureDiagnostics(url)\n throw new ExtractionError(`navigateToChannel failed: ${(err as Error).message} | ${diag}`)\n }\n }\n\n async evaluate<T>(fn: (...args: unknown[]) => T | Promise<T>, arg?: unknown): Promise<T> {\n return (this.page! as { evaluate(fn: unknown, arg?: unknown): Promise<T> }).evaluate(fn, arg)\n }\n\n getPage(): Page {\n return this.page!\n }\n\n async close(): Promise<void> {\n if (this.browser) {\n const b = this.browser\n const sessionId = this.kernelSessionId\n const client = this.kernelClient\n this.browser = null\n this.context = null\n this.page = null\n this.kernelSessionId = null\n this.kernelClient = null\n try {\n await b.close()\n } finally {\n if (client && sessionId) {\n await client.browsers.deleteByID(sessionId).catch((err: unknown) =>\n console.warn('Kernel session cleanup failed:', err)\n )\n }\n }\n } else if (this.context) {\n const ctx = this.context\n this.context = null\n this.page = null\n await ctx.close()\n }\n }\n}\n","export const PAASelectors = {\n container: '.eJH8qe.adDDi',\n dataInitq: '[data-initq]',\n item: '.related-question-pair',\n itemDataQ: 'data-q',\n itemDataInitQ: 'data-initq',\n itemQuestionEl: '.JlqpRe',\n answerContainer: '.bCOlv',\n sourceTitle: 'h3',\n sourceSite: '.VuuXrf',\n sourceCite: 'cite',\n clickTarget: '.JlqpRe',\n expandedClass: 'aoRk1c',\n captchaMarker: '#captcha-form, #recaptcha, form[action*=\"/sorry/\"], .g-recaptcha, [data-sitekey]',\n} as const\n\nexport const VideoSelectors = {\n container: 'div[jscontroller=\"HWk0Gf\"]',\n sectionHeading: '.mgAbYb[role=\"heading\"]',\n item: 'a.rIRoqf',\n} as const\n\nexport const ShortVideoSelectors = {\n udm: '39',\n item: 'a.rIRoqf',\n durationPattern: /^\\d+:\\d+$/,\n platforms: ['YouTube', 'TikTok', 'Instagram', 'Facebook', 'X'],\n} as const\n\nexport const ForumSelectors = {\n section: '.ULSxyf',\n item: 'a.KYg7td.INpicf',\n title: '.hyYc0c',\n source: '.K4ETW',\n} as const\n\nexport const WhatPeopleSayingSelectors = {\n sectionTag: 'g-section-with-header',\n sectionHeadingText: 'What people are saying',\n card: '.dRzkFf[role=\"listitem\"]',\n cardLink: 'a.WlydOe[jsname=\"YKoRaf\"]',\n titleH1: 'h1.WQWxe',\n titleDiv: '.eAaXgc',\n popularCommentLabel: '.qgdis',\n source: '.sTl1Td',\n platformBadge: '.appd0, .KrMNbf',\n ytChannel: '.sjVJQd',\n ytDate: '.PLq9Je',\n authorNote: '.nDgy9d',\n} as const\n\nexport const AIOverviewSelectors = {\n root: '[data-hveid=\"CBMQAA\"]',\n wrapper: '.Fgyi2e',\n citations: '.Fgyi2e [data-hveid] a[jsname=\"pxBnId\"]',\n} as const\n\nexport const AIModeSelectors = {\n root: '[data-hveid=\"CAUQAA\"]',\n wrapper: '.Fgyi2e',\n citations: '.Fgyi2e [data-hveid] a[jsname=\"pxBnId\"]',\n} as const\n\nexport const OrganicSelectors = {\n result: '.wHYlTd.tF2Cxc',\n title: 'h3.LC20lb',\n siteName: '.VuuXrf',\n cite: 'cite.tjvcx',\n snippet: '.VwiC3b',\n redditCite: 'cite.qLRx3b',\n ratingWrap: '.Y0A0hc',\n ratingValue: '.yi40Hd',\n reviewCount: '.RDApEe',\n} as const\n\nexport const LocalPackSelectors = {\n headingText: 'Businesses',\n card: '.w7Dbne',\n name: '.OSrXXb',\n ratingValue: '.yi40Hd',\n reviewCount: '.RDApEe',\n} as const\n\nexport const SELECTORS_VERSION = '2026-05-07'\n","export const RECAPTCHA_INSTRUCTIONS = 'Google returned a CAPTCHA. Run with --headless=false to re-warm the browser profile, then retry.'\n\nexport class CaptchaError extends Error {\n readonly name = 'CaptchaError'\n constructor(public readonly instructions: string) {\n super(`CAPTCHA detected. ${instructions}`)\n }\n}\n\nexport class ExtractionError extends Error {\n readonly name = 'ExtractionError'\n constructor(message: string, public readonly cause?: unknown) {\n super(message)\n }\n}\n","import type { CanonicalLocationName } from './types.js'\n\nexport const LOCATIONS: Record<string, CanonicalLocationName> = {\n 'austin': 'Austin,Texas,United States',\n 'new york': 'New York,New York,United States',\n 'new york city': 'New York,New York,United States',\n 'nyc': 'New York,New York,United States',\n 'los angeles': 'Los Angeles,California,United States',\n 'la': 'Los Angeles,California,United States',\n 'chicago': 'Chicago,Illinois,United States',\n 'houston': 'Houston,Texas,United States',\n 'phoenix': 'Phoenix,Arizona,United States',\n 'philadelphia': 'Philadelphia,Pennsylvania,United States',\n 'philly': 'Philadelphia,Pennsylvania,United States',\n 'san antonio': 'San Antonio,Texas,United States',\n 'dallas': 'Dallas,Texas,United States',\n 'miami': 'Miami,Florida,United States',\n 'seattle': 'Seattle,Washington,United States',\n 'denver': 'Denver,Colorado,United States',\n 'loveland': 'Loveland,Colorado,United States',\n 'loveland co': 'Loveland,Colorado,United States',\n 'fort collins': 'Fort Collins,Colorado,United States',\n 'boulder': 'Boulder,Colorado,United States',\n 'colorado springs': 'Colorado Springs,Colorado,United States',\n 'boston': 'Boston,Massachusetts,United States',\n 'atlanta': 'Atlanta,Georgia,United States',\n 'san francisco': 'San Francisco,California,United States',\n 'sf': 'San Francisco,California,United States',\n 'portland': 'Portland,Oregon,United States',\n 'las vegas': 'Las Vegas,Nevada,United States',\n 'minneapolis': 'Minneapolis,Minnesota,United States',\n 'detroit': 'Detroit,Michigan,United States',\n 'nashville': 'Nashville,Tennessee,United States',\n 'charlotte': 'Charlotte,North Carolina,United States',\n 'orlando': 'Orlando,Florida,United States',\n 'san diego': 'San Diego,California,United States',\n 'baltimore': 'Baltimore,Maryland,United States',\n 'sacramento': 'Sacramento,California,United States',\n 'columbus': 'Columbus,Ohio,United States',\n 'indianapolis': 'Indianapolis,Indiana,United States',\n 'san jose': 'San Jose,California,United States',\n 'fort worth': 'Fort Worth,Texas,United States',\n 'jacksonville': 'Jacksonville,Florida,United States',\n 'memphis': 'Memphis,Tennessee,United States',\n 'louisville': 'Louisville,Kentucky,United States',\n 'raleigh': 'Raleigh,North Carolina,United States',\n 'richmond': 'Richmond,Virginia,United States',\n 'salt lake city': 'Salt Lake City,Utah,United States',\n 'toronto': 'Toronto,Ontario,Canada',\n 'vancouver': 'Vancouver,British Columbia,Canada',\n 'montreal': 'Montreal,Quebec,Canada',\n 'calgary': 'Calgary,Alberta,Canada',\n 'ottawa': 'Ottawa,Ontario,Canada',\n 'london': 'London,England,United Kingdom',\n 'manchester': 'Manchester,England,United Kingdom',\n 'birmingham': 'Birmingham,England,United Kingdom',\n 'edinburgh': 'Edinburgh,Scotland,United Kingdom',\n 'glasgow': 'Glasgow,Scotland,United Kingdom',\n 'leeds': 'Leeds,England,United Kingdom',\n 'sydney': 'Sydney,New South Wales,Australia',\n 'melbourne': 'Melbourne,Victoria,Australia',\n 'brisbane': 'Brisbane,Queensland,Australia',\n 'perth': 'Perth,Western Australia,Australia',\n 'adelaide': 'Adelaide,South Australia,Australia',\n 'dublin': 'Dublin,Leinster,Ireland',\n}\n","import type { CanonicalLocationName, UuleString } from './types.js'\nimport { LOCATIONS } from './locations.js'\n\nexport function encodeUule(name: CanonicalLocationName): UuleString {\n const encoded = Buffer.from(String.fromCharCode(name.length) + name).toString('base64')\n return `w+CAIQICI${encoded}`\n}\n\nexport function normalizeLocation(input: string): CanonicalLocationName {\n const key = input.toLowerCase().trim()\n return (LOCATIONS[key] ?? input) as CanonicalLocationName\n}\n","const MAX_ANSWER_LENGTH = 1200\n\nconst BOILERPLATE_PATTERNS: RegExp[] = [\n /An AI Overview is not available for this search/gi,\n /Can't generate an AI overview right now\\.?\\s*Try again later\\.?/gi,\n /\\bAI Overview\\b/gi,\n /\\bView all\\b/gi,\n]\n\nconst CUT_MARKERS: RegExp[] = [\n /\\bRelated Links\\b/i,\n /\\bAsk anything in\\s*AI Mode\\b/i,\n /\\bAI can make mistakes\\b/i,\n /\\bThis is for informational purposes only\\b/i,\n /\\bShow more\\b/i,\n /\\b\\d+\\s+sites\\b/i,\n /\\b\\d{1,2}\\s*[msh]\\s*[A-Z][A-Za-z]/,\n /\\b(?:YouTube|Reddit|Facebook|Instagram|TikTok)·/,\n]\n\nfunction normalizeWhitespace(text: string): string {\n return text\n .replace(/\\u00a0/g, ' ')\n .replace(/([.!?])([A-Z])/g, '$1 $2')\n .replace(/([:;])([A-Z])/g, '$1 $2')\n .replace(/([a-z])([A-Z][a-z])/g, '$1 $2')\n .replace(/(\\d)([A-Z][a-z])/g, '$1 $2')\n .replace(/([a-z])(\\d)/g, '$1 $2')\n .replace(/\\s+/g, ' ')\n .trim()\n}\n\nfunction cutAtFirstMarker(text: string): string {\n let cutAt = -1\n for (const marker of CUT_MARKERS) {\n const match = marker.exec(text)\n marker.lastIndex = 0\n if (match && (cutAt === -1 || match.index < cutAt)) cutAt = match.index\n }\n return cutAt === -1 ? text : text.slice(0, cutAt)\n}\n\nfunction cutAtSourceTitle(text: string, sourceTitle?: string): string {\n const title = sourceTitle?.trim()\n if (!title || title.length < 8) return text\n const idx = text.toLowerCase().indexOf(title.toLowerCase())\n return idx > 40 ? text.slice(0, idx) : text\n}\n\nfunction findAttributionCut(beforeUrl: string): number {\n const dateMatch = beforeUrl.match(/[•·]\\s*(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[a-z]*\\.?\\s+\\d{1,2},\\s+\\d{4}/i)\n if (dateMatch?.index && dateMatch.index > 40) return dateMatch.index\n\n const start = Math.max(0, beforeUrl.length - 260)\n const tail = beforeUrl.slice(start)\n const sentenceBreaks = [...tail.matchAll(/[.!?]\\s*(?=[A-Z][A-Za-z0-9\"'$])/g)]\n for (const match of sentenceBreaks) {\n const remainder = tail.slice(match.index + 1).trim()\n const lead = remainder.slice(0, 160)\n const looksLikeTitle = /^(?:Best|Top|What|How|Why|When|Where|Which|Can|Should|Is|Are|Do|Does)\\b/i.test(remainder)\n if (\n remainder.length > 20 &&\n looksLikeTitle &&\n /(?:\\s[-|]\\s|Heating|Cooling|Company|Services|Blog|Guide|Review)/i.test(lead)\n ) {\n return start + match.index + 1\n }\n }\n const last = sentenceBreaks.at(-1)\n if (last?.index !== undefined) return start + last.index + 1\n\n return beforeUrl.length\n}\n\nfunction cutAtUrlAttribution(text: string): string {\n const urlMatch = text.match(/https?:\\/\\/\\S+/i)\n if (!urlMatch?.index) return text\n\n const beforeUrl = text.slice(0, urlMatch.index)\n return beforeUrl.slice(0, findAttributionCut(beforeUrl))\n}\n\nfunction trimToSentenceLimit(text: string): string {\n if (text.length <= MAX_ANSWER_LENGTH) return text\n const slice = text.slice(0, MAX_ANSWER_LENGTH)\n const lastSentence = Math.max(slice.lastIndexOf('.'), slice.lastIndexOf('!'), slice.lastIndexOf('?'))\n return (lastSentence > 240 ? slice.slice(0, lastSentence + 1) : slice).trim()\n}\n\nexport function cleanPAAAnswerText(\n answer: string | null | undefined,\n question?: string,\n sourceTitle?: string,\n): string | undefined {\n if (!answer) return undefined\n\n let text = normalizeWhitespace(answer)\n const normalizedQuestion = question ? normalizeWhitespace(question) : ''\n if (normalizedQuestion && text.toLowerCase().startsWith(normalizedQuestion.toLowerCase())) {\n text = text.slice(normalizedQuestion.length).trim()\n }\n\n if (/^An error has occurred\\.?\\s*Please try again later\\.?/i.test(text)) {\n return undefined\n }\n\n for (const pattern of BOILERPLATE_PATTERNS) {\n text = text.replace(pattern, ' ')\n }\n text = text\n .replace(/\\b[A-Z][A-Za-z&'\\u2019 -]{2,60}\\+\\d+\\b/g, ' ')\n .replace(/\\b(?:[a-z0-9-]+\\.)+[a-z]{2,}\\+\\d+\\b/gi, ' ')\n\n text = normalizeWhitespace(text)\n text = cutAtFirstMarker(text)\n text = cutAtSourceTitle(text, sourceTitle)\n text = cutAtUrlAttribution(text)\n text = normalizeWhitespace(text)\n text = text.replace(/\\s+(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[a-z]*\\.?\\s+\\d{1,2},\\s+\\d{4}$/i, '').trim()\n text = trimToSentenceLimit(text)\n\n if (!text) return undefined\n if (/^An error has occurred\\.?\\s*Please try again later\\.?$/i.test(text)) return undefined\n\n return text\n}\n","import type { Page } from 'playwright'\nimport type { IBrowserDriver } from '../driver/IBrowserDriver.js'\nimport type { IProgressReporter } from '../output/IProgressReporter.js'\nimport { PAASelectors, VideoSelectors, ForumSelectors, ShortVideoSelectors, AIOverviewSelectors, AIModeSelectors, WhatPeopleSayingSelectors, OrganicSelectors, LocalPackSelectors } from '../selectors.js'\nimport { encodeUule, normalizeLocation } from '../uule.js'\nimport { RawPAAItemSchema } from '../schemas.js'\nimport { cleanPAAAnswerText } from '../lib/paa-answer-cleanup.js'\nimport type {\n HarvestOptions, HarvestResult, HarvestStats,\n RawPAAItem, PAANode, FlatRow, NormalizedQuestionKey, DriverConfig,\n VideoResult, ForumResult, AIOverviewResult, AIModeResult, GoogleSurface,\n WhatPeopleSayingCard, EntityIds, EntityRecord,\n OrganicResult, LocalPackBusiness,\n} from '../types.js'\nimport type { IPAAExtractor } from './IPAAExtractor.js'\n\nexport class PAAExtractor implements IPAAExtractor {\n constructor(\n private readonly driver: IBrowserDriver,\n private readonly reporter: IProgressReporter,\n ) {}\n\n private normalizeQuestion(q: string): NormalizedQuestionKey {\n return q.toLowerCase().replace(/[^\\w\\s]/g, '').replace(/\\s+/g, ' ').trim() as NormalizedQuestionKey\n }\n\n private async extractVisibleItems(page: Page): Promise<RawPAAItem[]> {\n const sels = PAASelectors\n const raw = await page.evaluate((selectors) => {\n function cleanText(el: Element | null): string {\n if (!el) return ''\n const parts: string[] = []\n for (const n of el.childNodes) {\n if (n.nodeType === Node.TEXT_NODE) {\n const text = n.textContent?.trim()\n if (text) parts.push(text)\n } else if (\n (n as Element).tagName === 'STYLE' ||\n (n as Element).tagName === 'SCRIPT'\n ) {\n continue\n } else {\n const text = cleanText(n as Element)\n if (text) parts.push(text)\n }\n }\n return parts.join(' ').replace(/\\s+/g, ' ').trim()\n }\n return Array.from(document.querySelectorAll(selectors.item)).map((pair) => ({\n question: pair.getAttribute(selectors.itemDataQ) || pair.getAttribute(selectors.itemDataInitQ) || '',\n answer: cleanText(pair.querySelector(selectors.answerContainer)) || undefined,\n sourceTitle: (pair.querySelector(selectors.sourceTitle) as HTMLElement | null)?.innerText?.trim() || undefined,\n sourceSite: (pair.querySelector(selectors.sourceSite) as HTMLElement | null)?.innerText?.trim() || undefined,\n sourceCite: (pair.querySelector(selectors.sourceCite) as HTMLElement | null)?.innerText?.trim() || undefined,\n }))\n }, sels)\n\n return raw.flatMap((item) => {\n const cleaned = {\n ...item,\n answer: cleanPAAAnswerText(item.answer, item.question, item.sourceTitle),\n }\n const result = RawPAAItemSchema.safeParse(cleaned)\n if (!result.success) {\n console.warn('[PAAExtractor] item parse failed:', item.question, result.error.issues[0]?.message)\n return []\n }\n return [result.data]\n })\n }\n\n private async clickItem(page: Page, questionText: string): Promise<void> {\n try {\n const pairLocator = page.locator(\n `${PAASelectors.item}[data-q=\"${questionText}\"], ${PAASelectors.item}[data-initq=\"${questionText}\"]`\n ).first()\n await pairLocator.click()\n } catch { }\n }\n\n private toFlatRow(item: RawPAAItem, depth: number, parentQuestion: string | null, seed: string): FlatRow {\n return {\n seed_query: seed,\n question: item.question,\n answer: item.answer ?? '',\n source_title: item.sourceTitle ?? '',\n source_site: item.sourceSite ?? '',\n source_cite: item.sourceCite ?? '',\n depth,\n parent_question: parentQuestion ?? '',\n extracted_at: new Date().toISOString(),\n }\n }\n\n private async runBFS(page: Page, options: HarvestOptions): Promise<FlatRow[]> {\n const seenKeys = new Set<NormalizedQuestionKey>()\n const seenQs = new Set<string>()\n const depthMap = new Map<string, number>()\n const results: FlatRow[] = []\n\n const readAllQs = (): Promise<string[]> =>\n page.evaluate(\n ({ sel, dataQ, dataInitQ, questionEl }: { sel: string; dataQ: string; dataInitQ: string; questionEl: string }) =>\n Array.from(document.querySelectorAll(sel))\n .map(el =>\n el.getAttribute(dataQ) ||\n el.getAttribute(dataInitQ) ||\n (el.querySelector(questionEl) as HTMLElement | null)?.innerText?.trim() ||\n ''\n )\n .filter(Boolean),\n { sel: PAASelectors.item, dataQ: PAASelectors.itemDataQ, dataInitQ: PAASelectors.itemDataInitQ, questionEl: PAASelectors.itemQuestionEl },\n )\n\n const dupRates: number[] = []\n const orderedQs: string[] = []\n\n for (let round = 0; round < options.depth; round++) {\n this.reporter.onDepth(round + 1)\n\n if (seenQs.size >= options.maxQuestions) break\n\n const beforeQs = await readAllQs()\n if (beforeQs.length >= options.maxQuestions) break\n\n const unexpandedItems = await page.$$(\n `${PAASelectors.item}:not(.${PAASelectors.expandedClass})`\n )\n if (unexpandedItems.length === 0) break\n\n for (const item of unexpandedItems) {\n try {\n await item.scrollIntoViewIfNeeded()\n await item.click({ force: true })\n await page.waitForTimeout(500)\n } catch { }\n }\n await page.waitForTimeout(1500)\n\n const afterQs = await readAllQs()\n const newQs = afterQs.slice(beforeQs.length)\n\n const newDups = newQs.filter(q => seenQs.has(q)).length\n const dupRate = newQs.length > 0 ? newDups / newQs.length : 0\n dupRates.push(dupRate)\n if (dupRates.length > 2) dupRates.shift()\n const rollingDupRate = dupRates.reduce((a, b) => a + b, 0) / dupRates.length\n\n for (const q of afterQs) {\n if (!seenQs.has(q)) { seenQs.add(q); orderedQs.push(q) }\n if (!depthMap.has(q)) depthMap.set(q, round + 1)\n }\n\n if (afterQs.length === beforeQs.length) break\n if (rollingDupRate >= 0.6) break\n }\n\n const itemMap = new Map((await this.extractVisibleItems(page)).map(i => [i.question, i]))\n\n for (const q of orderedQs) {\n if (results.length >= options.maxQuestions) break\n const key = this.normalizeQuestion(q)\n if (seenKeys.has(key)) continue\n seenKeys.add(key)\n const d = depthMap.get(q) ?? 1\n const item = itemMap.get(q)\n if (item) {\n results.push(this.toFlatRow(item, d, null, options.query))\n this.reporter.onQuestion({ question: item.question, answer: item.answer ?? null, sourceTitle: item.sourceTitle ?? null, sourceSite: item.sourceSite ?? null, sourceCite: item.sourceCite ?? null, depth: d, parentQuestion: null, children: [] })\n } else {\n results.push(this.toFlatRow({ question: q, answer: undefined, sourceTitle: undefined, sourceSite: undefined, sourceCite: undefined }, d, null, options.query))\n }\n }\n\n return results\n }\n\n private async extractVideos(page: Page): Promise<VideoResult[]> {\n const vsels = VideoSelectors\n return page.evaluate((sels) => {\n const results: Array<{ type: 'video' | 'short_video'; title: string; channel: string; platform: string; duration: string; url: string }> = []\n const containers = Array.from(document.querySelectorAll(sels.container))\n for (const container of containers) {\n const headingEl = container.querySelector(sels.sectionHeading)\n const headingText = headingEl?.textContent?.trim() ?? ''\n const type: 'video' | 'short_video' = headingText.toLowerCase().includes('short') ? 'short_video' : 'video'\n const items = Array.from(container.querySelectorAll(sels.item))\n for (const a of items) {\n const href = (a as HTMLAnchorElement).href\n if (!href || (!href.includes('youtube') && !href.includes('youtu.be'))) continue\n const raw = a.textContent?.trim() ?? ''\n const ytIdx = raw.indexOf('YouTube')\n if (ytIdx === -1) continue\n const title = raw.slice(0, ytIdx).trim()\n const remainder = raw.slice(ytIdx + 7).replace(/^[·\\s·]+/, '')\n const channelMatch = remainder.match(/^([^·\\n]+)/)\n const channel = channelMatch ? channelMatch[1].trim() : ''\n if (title) results.push({ type, title, channel, platform: 'YouTube', duration: '', url: href })\n }\n }\n return results\n }, vsels)\n }\n\n private async extractForums(page: Page): Promise<ForumResult[]> {\n const fsels = ForumSelectors\n return page.evaluate((sels) => {\n const results: Array<{ title: string; source: string; url: string }> = []\n const sections = Array.from(document.querySelectorAll(sels.section))\n const forumSection = sections.find((s) => s.textContent?.includes('Discussions'))\n if (!forumSection) return results\n const items = Array.from(forumSection.querySelectorAll(sels.item))\n for (const a of items) {\n const href = (a as HTMLAnchorElement).href\n if (!href) continue\n const titleEl = a.querySelector(sels.title)\n const sourceEl = a.querySelector(sels.source)\n const title = titleEl?.textContent?.trim() ?? ''\n const source = sourceEl?.textContent?.trim() ?? ''\n if (title) results.push({ title, source, url: href })\n }\n return results\n }, fsels)\n }\n\n private async extractShortVideos(page: Page, shortUrl: string): Promise<VideoResult[]> {\n try {\n await page.goto(shortUrl, { waitUntil: 'domcontentloaded' })\n await page.waitForTimeout(1500)\n } catch {\n return []\n }\n\n const svSels = {\n item: ShortVideoSelectors.item,\n platforms: [...ShortVideoSelectors.platforms] as string[],\n }\n\n const raw = await page.evaluate((sels) => {\n const seen = new Set<string>()\n const results: Array<{ title: string; channel: string; platform: string; duration: string; url: string }> = []\n const items = Array.from(document.querySelectorAll(sels.item))\n\n const videoHosts = ['youtube.com', 'youtu.be', 'tiktok.com', 'instagram.com', 'facebook.com', 'fb.watch']\n\n const byHref = new Map<string, string[]>()\n for (const a of items) {\n const href = (a as HTMLAnchorElement).href\n if (!href) continue\n if (!videoHosts.some((h) => href.includes(h))) continue\n const text = a.textContent?.trim() ?? ''\n if (!byHref.has(href)) byHref.set(href, [])\n byHref.get(href)!.push(text)\n }\n\n for (const [href, texts] of byHref.entries()) {\n if (seen.has(href)) continue\n seen.add(href)\n\n const duration = texts.find((t) => /^\\d+:\\d+$/.test(t)) ?? ''\n const titleText = texts.find((t) => !/^\\d+:\\d+$/.test(t) && t.length > 5) ?? ''\n if (!titleText) continue\n\n let title = titleText\n let platform = ''\n let channel = ''\n\n for (const p of sels.platforms) {\n let lastIdx = -1\n let search = 0\n while (true) {\n const found = titleText.indexOf(p, search)\n if (found === -1) break\n lastIdx = found\n search = found + 1\n }\n if (lastIdx === -1) continue\n const after = titleText.slice(lastIdx + p.length)\n const isSourceTag = /^[\\s·]/.test(after) || after.trim() === ''\n if (!isSourceTag) continue\n title = titleText.slice(0, lastIdx).trim()\n platform = p\n const stripped = after.replace(/^[\\s·]+/, '')\n const dotIdx = stripped.indexOf('·')\n channel = (dotIdx === -1 ? stripped : stripped.slice(0, dotIdx)).trim()\n break\n }\n\n if (title) results.push({ title, channel, platform, duration, url: href })\n }\n\n return results\n }, svSels)\n\n return raw.map((r) => ({ type: 'short_video' as const, ...r }))\n }\n\n private async extractWhatPeopleSaying(page: Page): Promise<WhatPeopleSayingCard[]> {\n const sels = WhatPeopleSayingSelectors\n return page.evaluate((s) => {\n const section = Array.from(document.querySelectorAll(s.sectionTag))\n .find((el) => el.textContent?.includes(s.sectionHeadingText))\n ?? document.querySelector('.yG4QQe.TBC9ub.NbhJ1c')\n\n if (!section) return []\n\n return Array.from(section.querySelectorAll(s.card)).map((card) => {\n const link = card.querySelector(s.cardLink) as HTMLAnchorElement | null\n const url = link?.href ?? ''\n\n const titleH1 = card.querySelector(s.titleH1)?.textContent?.trim()\n const titleDiv = card.querySelector(s.titleDiv)?.textContent?.trim()\n const title = titleH1 ?? titleDiv ?? ''\n\n const sourceText = card.querySelector(s.source)?.textContent?.trim() ?? ''\n const platformEl = card.querySelector(s.platformBadge)\n const platformText = platformEl?.textContent?.trim() ?? ''\n\n const ytChannel = card.querySelector(s.ytChannel)?.textContent?.trim() ?? ''\n const ytDate = card.querySelector(s.ytDate)?.textContent?.trim() ?? ''\n const authorNote = card.querySelector(s.authorNote)?.textContent?.trim() ?? null\n\n const commentLabelEl = card.querySelector(s.popularCommentLabel)\n let popularComment: string | null = null\n if (commentLabelEl) {\n let next = commentLabelEl.nextSibling\n while (next) {\n const t = next.textContent?.trim()\n if (t) { popularComment = t; break }\n next = next.nextSibling\n }\n }\n\n const allSpans = Array.from(card.querySelectorAll('span'))\n const duration = allSpans.find((s) => /^\\d+:\\d+$/.test(s.textContent?.trim() ?? ''))?.textContent?.trim() ?? null\n const engagementParts = allSpans\n .map((s) => s.textContent?.trim() ?? '')\n .filter((t) =>\n /\\d/.test(t) && (\n t.includes('comment') || t.includes('reaction') ||\n t.includes('view') || t.includes('like') || t.includes('share')\n )\n )\n const engagement = engagementParts[0] ?? ''\n\n const dateCandidates = allSpans\n .map((s) => s.textContent?.trim() ?? '')\n .filter((t) => /\\d+ (day|week|month|year|hour)s? ago|Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec/.test(t))\n const date = ytDate || (dateCandidates[0] ?? '')\n\n const platform = platformText || (ytChannel ? 'YouTube' : '')\n const source = ytChannel || sourceText\n\n let type: 'reddit' | 'facebook' | 'youtube' | 'instagram' | 'tiktok' | 'news' | 'unknown' = 'unknown'\n const pl = platform.toLowerCase()\n const src = source.toLowerCase()\n const srcRaw = sourceText.toLowerCase()\n if (pl.includes('reddit') || src.startsWith('r/')) type = 'reddit'\n else if (pl.includes('facebook') || srcRaw.includes('facebook')) type = 'facebook'\n else if (pl.includes('instagram') || srcRaw.includes('instagram')) type = 'instagram'\n else if (pl.includes('tiktok') || srcRaw.includes('tiktok')) type = 'tiktok'\n else if (pl.includes('youtube') || !!ytChannel) type = 'youtube'\n else type = 'news'\n\n return { type, title, url, source, platform, popularComment, engagement, date, duration, authorNote }\n })\n }, sels)\n }\n\n private async extractOrganicResults(page: Page): Promise<OrganicResult[]> {\n const sels = OrganicSelectors\n return page.evaluate((s) => {\n const out: Array<{ position: number; title: string; url: string; domain: string; cite: string | null; snippet: string | null; isRedditStyle: boolean; inlineRating: { value: string; count: string } | null }> = []\n let pos = 0\n document.querySelectorAll(s.result).forEach(card => {\n const titleEl = card.querySelector(s.title)\n if (!titleEl) return\n const title = titleEl.textContent?.trim() ?? ''\n const linkEl = titleEl.closest('a') as HTMLAnchorElement | null\n const url = linkEl?.href ?? ''\n if (!title || !url) return\n pos++\n const cite = card.querySelector(s.cite)?.textContent?.trim() ?? null\n const snippet = card.querySelector(s.snippet)?.textContent?.trim() ?? null\n const isRedditStyle = !!card.querySelector(s.redditCite)\n const ratingEl = card.querySelector(s.ratingWrap)\n const inlineRating = ratingEl\n ? { value: ratingEl.querySelector(s.ratingValue)?.textContent?.trim() ?? '', count: ratingEl.querySelector(s.reviewCount)?.textContent?.trim() ?? '' }\n : null\n let domain = ''\n try { domain = new URL(url).hostname.replace(/^www\\./, '') } catch { domain = card.querySelector(s.siteName)?.textContent?.trim() ?? '' }\n out.push({ position: pos, title, url, domain, cite, snippet, isRedditStyle, inlineRating })\n })\n return out\n }, sels)\n }\n\n private async extractLocalPack(page: Page): Promise<LocalPackBusiness[]> {\n const sels = LocalPackSelectors\n return page.evaluate((s) => {\n const out: Array<{ position: number; name: string; cid: string | null; rating: string | null; reviewCount: string | null; metadata: string[]; websiteUrl: string | null; directionsUrl: string | null }> = []\n let container: Element | null = null\n document.querySelectorAll('[role=\"heading\"]').forEach(h => {\n if (!container && h.textContent?.includes(s.headingText)) container = h.closest('[data-hveid]')\n })\n if (!container) return out\n ;(container as Element).querySelectorAll(s.card).forEach((card, i) => {\n const name = card.querySelector(s.name)?.textContent?.trim() ?? ''\n if (!name) return\n const rating = card.querySelector(s.ratingValue)?.textContent?.trim() ?? null\n const reviewRaw = card.querySelector(s.reviewCount)?.textContent?.trim() ?? null\n const reviewCount = reviewRaw ? reviewRaw.replace(/[()]/g, '').trim() : null\n let cid = (card.querySelector('a[data-cid]') as HTMLAnchorElement | null)?.getAttribute('data-cid') ?? null\n if (!cid) {\n for (const link of Array.from(card.querySelectorAll('a[href]')) as HTMLAnchorElement[]) {\n const m1 = link.href.match(/[?&]cid=(\\d+)/)\n if (m1) { cid = m1[1]; break }\n const m2 = link.href.match(/!1s0x[0-9a-f]+:0x([0-9a-f]+)/i)\n if (m2) { try { cid = BigInt('0x' + m2[1]).toString() } catch { } if (cid) break }\n }\n }\n const metadata: string[] = []\n card.querySelectorAll('div, span').forEach(el => {\n const text = Array.from(el.childNodes)\n .filter(n => n.nodeType === 3)\n .map(n => n.textContent?.trim() ?? '')\n .filter(t => t.length > 1 && t.length < 120)\n .join(' ')\n if (text && !metadata.includes(text)) metadata.push(text)\n })\n const links = Array.from(card.querySelectorAll('a[href]')) as HTMLAnchorElement[]\n const directionsUrl = links.find(a => a.href.includes('google.com/maps'))?.href ?? null\n const websiteUrl = links.find(a => !a.href.includes('google.com') && a.href.startsWith('http'))?.href ?? null\n out.push({ position: i + 1, name, cid, rating, reviewCount, metadata, websiteUrl, directionsUrl })\n })\n return out\n }, sels)\n }\n\n private async extractEntityIds(page: Page): Promise<EntityIds> {\n return page.evaluate(() => {\n const kgIds = new Set<string>()\n const cids = new Set<string>()\n const gcids = new Set<string>()\n const recordMap = new Map<string, { name: string; kgId: string | null; cid: string | null; gcid: string | null }>()\n\n function nameFromWrapper(el: Element): string {\n const sel = ['.OSrXXb', '.dbg0pd', '.tzt0oe', '[role=\"heading\"]', 'h3']\n for (const s of sel) {\n const found = el.querySelector(s)\n if (found?.textContent?.trim()) return found.textContent.trim()\n }\n return ''\n }\n\n document.querySelectorAll('[id^=\"pv-/g/\"]').forEach(wrapper => {\n const raw = wrapper.getAttribute('id')\n if (!raw) return\n const kgId = raw.replace('pv-', '')\n kgIds.add(kgId)\n const name = nameFromWrapper(wrapper)\n const cidEl = wrapper.querySelector('a[data-cid]')\n const cid = cidEl?.getAttribute('data-cid') ?? null\n if (cid) cids.add(cid)\n if (name) recordMap.set(kgId, { name, kgId, cid, gcid: null })\n })\n\n document.querySelectorAll('[data-mid]').forEach(el => {\n const mid = el.getAttribute('data-mid')\n if (!mid?.startsWith('/g/')) return\n kgIds.add(mid)\n if (!recordMap.has(mid)) {\n const name = nameFromWrapper(el)\n if (name) recordMap.set(mid, { name, kgId: mid, cid: null, gcid: null })\n }\n })\n\n document.querySelectorAll('.w7Dbne').forEach(card => {\n const cidEl = card.querySelector('a[data-cid]')\n const cid = cidEl?.getAttribute('data-cid') ?? null\n if (!cid) return\n cids.add(cid)\n const name = card.querySelector('.OSrXXb')?.textContent?.trim() ?? ''\n if (!name) return\n const kgIdEl = card.querySelector('[id^=\"pv-/g/\"]')\n const kgId = kgIdEl ? kgIdEl.getAttribute('id')!.replace('pv-', '') : null\n const key = kgId ?? `cid:${cid}`\n if (recordMap.has(key)) {\n const existing = recordMap.get(key)!\n if (!existing.cid) recordMap.set(key, { ...existing, cid })\n } else {\n recordMap.set(key, { name, kgId, cid, gcid: null })\n }\n })\n\n document.querySelectorAll('a[data-cid]').forEach(el => {\n const cid = el.getAttribute('data-cid')\n if (!cid) return\n cids.add(cid)\n const alreadyNamed = [...recordMap.values()].some(r => r.cid === cid)\n if (!alreadyNamed) {\n let node: Element | null = el.parentElement\n let name = ''\n for (let i = 0; i < 8 && node; i++) {\n const h = node.querySelector('.OSrXXb, .dbg0pd, [role=\"heading\"], h3')\n if (h?.textContent?.trim()) { name = h.textContent.trim(); break }\n node = node.parentElement\n }\n if (name) recordMap.set(`cid:${cid}`, { name, kgId: null, cid, gcid: null })\n }\n })\n\n const scriptContent = Array.from(document.querySelectorAll('script:not([src])'))\n .map(s => s.textContent ?? '')\n .filter(t => t.length > 10_000)\n .join('\\n')\n\n for (const m of scriptContent.matchAll(/\\/g\\/[a-zA-Z0-9_-]{5,20}/g)) kgIds.add(m[0])\n for (const m of scriptContent.matchAll(/gcid:[a-zA-Z0-9_]+/g)) gcids.add(m[0])\n for (const m of scriptContent.matchAll(/0x[0-9a-f]+:0x([0-9a-f]+)/gi)) {\n try { cids.add(BigInt('0x' + m[1]).toString()) } catch { }\n }\n\n return { entities: [...recordMap.values()], kgIds: [...kgIds], cids: [...cids], gcids: [...gcids] }\n })\n }\n\n private mergeLocalPackIntoEntities(entityIds: EntityIds, localPack: LocalPackBusiness[]): EntityIds {\n const cidSet = new Set<string>(entityIds.cids)\n const records = entityIds.entities.map(r => ({ ...r }))\n\n for (const biz of localPack) {\n if (!biz.cid) continue\n cidSet.add(biz.cid)\n const nameNorm = biz.name.toLowerCase().trim()\n const byName = records.find(r => r.name.toLowerCase().trim() === nameNorm)\n if (byName) {\n if (!byName.cid) byName.cid = biz.cid\n } else if (!records.find(r => r.cid === biz.cid)) {\n records.push({ name: biz.name, kgId: null, cid: biz.cid, gcid: null })\n }\n }\n\n return { ...entityIds, entities: records, cids: [...cidSet] }\n }\n\n private async extractAISurfaces(page: Page): Promise<{\n surface: GoogleSurface\n aiOverview: AIOverviewResult\n aiMode: AIModeResult\n }> {\n const aioSels = AIOverviewSelectors\n const aimSels = AIModeSelectors\n\n return page.evaluate(({ aio, aim }) => {\n const sn: string = (window as unknown as { google?: { sn?: string } }).google?.sn ?? 'unknown'\n const surface: 'web' | 'aim' | 'unknown' =\n sn === 'aim' ? 'aim' : sn === 'web' ? 'web' : 'unknown'\n\n function findAIORoot(): Element | null {\n const primary = document.querySelector(aio.root)\n if (primary) return primary\n const headings = document.querySelectorAll('h1, h2, h3, [role=\"heading\"]')\n for (const h of headings) {\n if (h.textContent?.trim() === 'AI Overview') {\n let el: Element | null = h.parentElement\n for (let i = 0; i < 6 && el; i++) {\n if (el.querySelectorAll('a').length > 1) return el\n el = el.parentElement\n }\n return h.parentElement\n }\n }\n return null\n }\n\n const aioRoot = findAIORoot()\n const aioContainer = aioRoot ? (aioRoot.closest(aio.wrapper) ?? aioRoot) : null\n\n let aioText: string | null = null\n if (aioContainer) {\n const clone = aioContainer.cloneNode(true) as Element\n clone.querySelectorAll('script,style,noscript').forEach((el) => el.remove())\n clone.querySelectorAll('h1,h2,h3,h4,[role=\"heading\"]').forEach((el) => el.remove())\n clone.querySelectorAll('button,[role=\"button\"]').forEach((el) => el.remove())\n clone.querySelectorAll('a').forEach((el) => el.remove())\n const candidate = clone.textContent?.replace(/\\s+/g, ' ').trim() || null\n const isErrorState = !candidate ||\n /not available|try again|can't generate/i.test(candidate)\n aioText = isErrorState ? null : candidate\n }\n\n const aioDetected = !!aioRoot && aioText !== null\n\n const aioCitations = Array.from(aioContainer?.querySelectorAll('a[href]') ?? [])\n .filter((a) => (a as HTMLAnchorElement).href && !(a as HTMLAnchorElement).href.startsWith('javascript'))\n .map((a) => ({\n text: (a as HTMLAnchorElement).textContent?.trim() ?? '',\n href: (a as HTMLAnchorElement).href,\n }))\n .filter((c) => c.text && c.href)\n\n const aimRoot = document.querySelector(aim.root)\n const aimDetected = surface === 'aim' && !!aimRoot\n const aimContainer = aimRoot?.closest(aim.wrapper) ?? null\n\n let aimText: string | null = null\n if (aimContainer) {\n const clone = aimContainer.cloneNode(true) as Element\n clone.querySelectorAll('script,style,noscript').forEach((el) => el.remove())\n clone.querySelectorAll('h1,h2,h3,h4,[role=\"heading\"]').forEach((el) => el.remove())\n clone.querySelectorAll('button,[role=\"button\"]').forEach((el) => el.remove())\n clone.querySelectorAll('a').forEach((el) => el.remove())\n const candidate = clone.textContent?.replace(/\\s+/g, ' ').trim() || null\n const isErrorState = !candidate ||\n /not available|try again|can't generate/i.test(candidate)\n aimText = isErrorState ? null : candidate\n }\n\n const aimCitations = aimDetected\n ? Array.from(aimContainer?.querySelectorAll('a[href]') ?? [])\n .filter((a) => (a as HTMLAnchorElement).href && !(a as HTMLAnchorElement).href.startsWith('javascript'))\n .map((a) => ({\n text: (a as HTMLAnchorElement).textContent?.trim() ?? '',\n href: (a as HTMLAnchorElement).href,\n }))\n .filter((c) => c.text && c.href)\n : []\n\n return {\n surface,\n aiOverview: { detected: aioDetected, text: aioText, citations: aioCitations },\n aiMode: { detected: aimDetected, text: aimText, citations: aimCitations },\n }\n }, { aio: aioSels, aim: aimSels })\n }\n\n private buildTree(flat: FlatRow[], _seed: string): PAANode[] {\n const roots: PAANode[] = []\n const nodeMap = new Map<string, PAANode>()\n\n for (const row of flat) {\n const node: PAANode = {\n question: row.question,\n answer: row.answer || null,\n sourceTitle: row.source_title || null,\n sourceSite: row.source_site || null,\n sourceCite: row.source_cite || null,\n depth: row.depth,\n parentQuestion: row.parent_question || null,\n children: [],\n }\n nodeMap.set(row.question, node)\n }\n\n for (const node of nodeMap.values()) {\n if (node.parentQuestion && nodeMap.has(node.parentQuestion)) {\n nodeMap.get(node.parentQuestion)!.children.push(node)\n } else {\n roots.push(node)\n }\n }\n\n return roots\n }\n\n async extract(options: HarvestOptions): Promise<HarvestResult> {\n const startMs = Date.now()\n const config: DriverConfig = {\n headless: options.headless,\n profileDir: options.profileDir,\n proxy: options.proxy,\n kernelApiKey: options.kernelApiKey,\n kernelProxyId: options.kernelProxyId,\n viewport: { width: 1280, height: 800 },\n locale: `${options.hl}-${options.gl.toUpperCase()}`,\n }\n\n let errorCount = 0\n\n try {\n await this.driver.launch(config)\n const uule = options.location ? encodeUule(normalizeLocation(options.location)) : null\n const { hasPaa } = await this.driver.navigateToSERP(options.query, uule, options.gl, options.hl)\n\n const page = this.driver.getPage() as Page\n\n if (options.serpOnly) {\n const [organicResults, localPack, rawEntityIds] = await Promise.all([\n this.extractOrganicResults(page),\n this.extractLocalPack(page),\n this.extractEntityIds(page),\n ])\n const entityIds = this.mergeLocalPackIntoEntities(rawEntityIds, localPack)\n let allOrganic = organicResults\n if ((options.pages ?? 1) >= 2) {\n const p2params = new URLSearchParams({ q: options.query, gl: options.gl, hl: options.hl, start: '10' })\n if (uule) p2params.set('uule', uule)\n await this.driver.navigateTo('https://www.google.com/search?' + p2params.toString())\n const p2organic = await this.extractOrganicResults(page)\n allOrganic = [...organicResults, ...p2organic.map(r => ({ ...r, position: r.position + 10 }))]\n }\n const stats: HarvestStats = {\n seed: options.query, totalQuestions: 0, maxDepthReached: 0,\n durationMs: Date.now() - startMs, errorCount,\n }\n this.reporter.onComplete(stats)\n return {\n seed: options.query, location: options.location ?? null,\n extractedAt: new Date().toISOString(), totalQuestions: 0,\n surface: 'web' as const,\n aiOverview: { detected: false, text: null, citations: [] },\n aiMode: { detected: false, text: null, citations: [] },\n whatPeopleSaying: [], tree: [], flat: [], videos: [], forums: [],\n organicResults: allOrganic, localPack, entityIds, stats,\n }\n }\n\n const [videos, forums, whatPeopleSaying, rawEntityIds, organicResults, localPack] = await Promise.all([\n this.extractVideos(page),\n this.extractForums(page),\n this.extractWhatPeopleSaying(page),\n this.extractEntityIds(page),\n this.extractOrganicResults(page),\n this.extractLocalPack(page),\n ])\n const entityIds = this.mergeLocalPackIntoEntities(rawEntityIds, localPack)\n this.reporter.onVideos(videos)\n this.reporter.onForums(forums)\n\n if (!hasPaa) {\n let noPaaOrganic = organicResults\n if ((options.pages ?? 1) >= 2) {\n const p2params = new URLSearchParams({ q: options.query, gl: options.gl, hl: options.hl, start: '10' })\n if (uule) p2params.set('uule', uule)\n await this.driver.navigateTo('https://www.google.com/search?' + p2params.toString())\n const p2organic = await this.extractOrganicResults(page)\n noPaaOrganic = [...organicResults, ...p2organic.map(r => ({ ...r, position: r.position + 10 }))]\n }\n const aiSurfaces = await this.extractAISurfaces(page)\n const stats: HarvestStats = {\n seed: options.query, totalQuestions: 0, maxDepthReached: 0,\n durationMs: Date.now() - startMs, errorCount,\n }\n this.reporter.onComplete(stats)\n return {\n seed: options.query, location: options.location ?? null,\n extractedAt: new Date().toISOString(), totalQuestions: 0,\n surface: aiSurfaces.surface,\n aiOverview: aiSurfaces.aiOverview,\n aiMode: aiSurfaces.aiMode,\n whatPeopleSaying, tree: [], flat: [], videos, forums,\n organicResults: noPaaOrganic, localPack, entityIds, stats,\n }\n }\n\n const flat = await this.runBFS(page, options)\n const aiSurfaces = await this.extractAISurfaces(page)\n\n const shortVidsParams = new URLSearchParams({ q: options.query, gl: options.gl, hl: options.hl, udm: ShortVideoSelectors.udm })\n if (uule) shortVidsParams.set('uule', uule)\n const shortVideos = await this.extractShortVideos(page, 'https://www.google.com/search?' + shortVidsParams.toString())\n this.reporter.onVideos(shortVideos)\n\n let allOrganic = organicResults\n if ((options.pages ?? 1) >= 2) {\n const p2params = new URLSearchParams({ q: options.query, gl: options.gl, hl: options.hl, start: '10' })\n if (uule) p2params.set('uule', uule)\n await this.driver.navigateTo('https://www.google.com/search?' + p2params.toString())\n const p2organic = await this.extractOrganicResults(page)\n allOrganic = [...organicResults, ...p2organic.map(r => ({ ...r, position: r.position + 10 }))]\n }\n\n const allVideos = [...videos, ...shortVideos]\n const tree = this.buildTree(flat, options.query)\n\n const stats: HarvestStats = {\n seed: options.query,\n totalQuestions: flat.length,\n maxDepthReached: flat.reduce((m, r) => Math.max(m, r.depth), 0),\n durationMs: Date.now() - startMs,\n errorCount,\n }\n\n this.reporter.onComplete(stats)\n\n return {\n seed: options.query,\n location: options.location ?? null,\n extractedAt: new Date().toISOString(),\n totalQuestions: flat.length,\n surface: aiSurfaces.surface,\n aiOverview: aiSurfaces.aiOverview,\n aiMode: aiSurfaces.aiMode,\n whatPeopleSaying,\n tree,\n flat,\n videos: allVideos,\n forums,\n organicResults: allOrganic,\n localPack,\n entityIds,\n stats,\n }\n } catch (err) {\n errorCount++\n this.reporter.onError(err instanceof Error ? err : new Error(String(err)))\n throw err\n } finally {\n await this.driver.close()\n }\n }\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport Papa from 'papaparse'\nimport type { HarvestResult, FlatRow, VideoResult, ForumResult, AICitation, WhatPeopleSayingCard } from '../types.js'\nimport type { IOutputSerializer } from './IOutputSerializer.js'\n\nexport class OutputSerializer implements IOutputSerializer {\n async writeJSON(result: HarvestResult, outputDir: string): Promise<string> {\n await fs.mkdir(outputDir, { recursive: true })\n const slug = result.seed.toLowerCase().replace(/\\W+/g, '-').slice(0, 40)\n const filename = `${slug}-${Date.now()}.json`\n const fullPath = path.join(outputDir, filename)\n await fs.writeFile(fullPath, JSON.stringify(result, null, 2), 'utf8')\n return fullPath\n }\n\n async writeCSV(rows: FlatRow[], outputDir: string): Promise<string> {\n await fs.mkdir(outputDir, { recursive: true })\n const seedRaw = rows[0]?.seed_query ?? 'paa'\n const slug = seedRaw.toLowerCase().replace(/\\W+/g, '-').slice(0, 40)\n const csv = Papa.unparse(rows, { header: true })\n const filename = `${slug}-${Date.now()}.csv`\n const fullPath = path.join(outputDir, filename)\n await fs.writeFile(fullPath, csv, 'utf8')\n return fullPath\n }\n\n async writeVideoCSV(videos: VideoResult[], seed: string, outputDir: string): Promise<string> {\n await fs.mkdir(outputDir, { recursive: true })\n const slug = seed.toLowerCase().replace(/\\W+/g, '-').slice(0, 40)\n const csv = Papa.unparse(videos, { header: true })\n const filename = `${slug}-videos-${Date.now()}.csv`\n const fullPath = path.join(outputDir, filename)\n await fs.writeFile(fullPath, csv, 'utf8')\n return fullPath\n }\n\n async writeForumCSV(forums: ForumResult[], seed: string, outputDir: string): Promise<string> {\n await fs.mkdir(outputDir, { recursive: true })\n const slug = seed.toLowerCase().replace(/\\W+/g, '-').slice(0, 40)\n const csv = Papa.unparse(forums, { header: true })\n const filename = `${slug}-forums-${Date.now()}.csv`\n const fullPath = path.join(outputDir, filename)\n await fs.writeFile(fullPath, csv, 'utf8')\n return fullPath\n }\n\n async writeAIOverviewCSV(citations: AICitation[], text: string | null, seed: string, outputDir: string): Promise<string> {\n await fs.mkdir(outputDir, { recursive: true })\n const slug = seed.toLowerCase().replace(/\\W+/g, '-').slice(0, 40)\n const rows = citations.map((c, i) => ({\n seed_query: seed,\n response_text: i === 0 ? (text ?? '') : '',\n citation_text: c.text,\n citation_href: c.href,\n }))\n const csv = Papa.unparse(rows, { header: true })\n const filename = `${slug}-ai-overview-${Date.now()}.csv`\n const fullPath = path.join(outputDir, filename)\n await fs.writeFile(fullPath, csv, 'utf8')\n return fullPath\n }\n\n async writeAIModeCSV(citations: AICitation[], text: string | null, seed: string, outputDir: string): Promise<string> {\n await fs.mkdir(outputDir, { recursive: true })\n const slug = seed.toLowerCase().replace(/\\W+/g, '-').slice(0, 40)\n const rows = citations.map((c, i) => ({\n seed_query: seed,\n response_text: i === 0 ? (text ?? '') : '',\n citation_text: c.text,\n citation_href: c.href,\n }))\n const csv = Papa.unparse(rows, { header: true })\n const filename = `${slug}-ai-mode-${Date.now()}.csv`\n const fullPath = path.join(outputDir, filename)\n await fs.writeFile(fullPath, csv, 'utf8')\n return fullPath\n }\n\n async writeWhatPeopleSayingCSV(cards: WhatPeopleSayingCard[], seed: string, outputDir: string): Promise<string> {\n await fs.mkdir(outputDir, { recursive: true })\n const slug = seed.toLowerCase().replace(/\\W+/g, '-').slice(0, 40)\n const rows = cards.map((c) => ({ seed_query: seed, ...c }))\n const csv = Papa.unparse(rows, { header: true })\n const filename = `${slug}-what-people-saying-${Date.now()}.csv`\n const fullPath = path.join(outputDir, filename)\n await fs.writeFile(fullPath, csv, 'utf8')\n return fullPath\n }\n}\n","import type { PAANode, HarvestStats, VideoResult, ForumResult } from '../types.js'\nimport type { IProgressReporter } from './IProgressReporter.js'\n\nexport class ProgressReporter implements IProgressReporter {\n onQuestion(node: PAANode): void {\n process.stdout.write(JSON.stringify({ event: 'question', depth: node.depth, question: node.question }) + '\\n')\n }\n\n onDepth(depth: number): void {\n process.stdout.write(JSON.stringify({ event: 'depth', depth }) + '\\n')\n }\n\n onVideos(videos: VideoResult[]): void {\n for (const v of videos) {\n process.stdout.write(JSON.stringify({ event: 'video', type: v.type, platform: v.platform, duration: v.duration, title: v.title, channel: v.channel, url: v.url }) + '\\n')\n }\n }\n\n onForums(forums: ForumResult[]): void {\n for (const f of forums) {\n process.stdout.write(JSON.stringify({ event: 'forum', title: f.title, source: f.source, url: f.url }) + '\\n')\n }\n }\n\n onComplete(stats: HarvestStats): void {\n process.stdout.write(JSON.stringify({ event: 'complete', ...stats }) + '\\n')\n }\n\n onError(err: Error): void {\n process.stderr.write(JSON.stringify({ event: 'error', type: err.constructor.name, message: err.message }) + '\\n')\n }\n}\n","import { HarvestOptionsSchema } from './schemas.js'\nimport type { HarvestOptions, HarvestResult } from './types.js'\nimport { BrowserDriver } from './driver/BrowserDriver.js'\nimport { PAAExtractor } from './extractor/PAAExtractor.js'\nimport { OutputSerializer } from './output/OutputSerializer.js'\nimport { ProgressReporter } from './output/ProgressReporter.js'\nimport { CaptchaError } from './errors.js'\n\nconst MAX_ATTEMPTS = 3\n\nasync function extractOnce(options: HarvestOptions): Promise<HarvestResult> {\n const driver = new BrowserDriver()\n const reporter = new ProgressReporter()\n const extractor = new PAAExtractor(driver, reporter)\n try {\n return await extractor.extract(options)\n } finally {\n await driver.close()\n }\n}\n\nexport async function harvest(rawOptions: unknown): Promise<HarvestResult> {\n const raw = typeof rawOptions === 'object' && rawOptions !== null ? rawOptions : {}\n const merged = {\n kernelApiKey: process.env.KERNEL_API_KEY?.trim(),\n kernelProxyId: process.env.KERNEL_PROXY_ID?.trim(),\n ...raw,\n }\n const options = HarvestOptionsSchema.parse(merged)\n const serializer = new OutputSerializer()\n\n for (let i = 0; i < MAX_ATTEMPTS; i++) {\n try {\n const result = await extractOnce(options)\n if (options.format === 'json' || options.format === 'both') {\n await serializer.writeJSON(result, options.outputDir)\n }\n if (options.format === 'csv' || options.format === 'both') {\n await Promise.all([\n serializer.writeCSV(result.flat, options.outputDir),\n result.videos.length > 0 ? serializer.writeVideoCSV(result.videos, result.seed, options.outputDir) : Promise.resolve(''),\n result.forums.length > 0 ? serializer.writeForumCSV(result.forums, result.seed, options.outputDir) : Promise.resolve(''),\n result.aiOverview.detected ? serializer.writeAIOverviewCSV(result.aiOverview.citations, result.aiOverview.text, result.seed, options.outputDir) : Promise.resolve(''),\n result.aiMode.detected ? serializer.writeAIModeCSV(result.aiMode.citations, result.aiMode.text, result.seed, options.outputDir) : Promise.resolve(''),\n result.whatPeopleSaying.length > 0 ? serializer.writeWhatPeopleSayingCSV(result.whatPeopleSaying, result.seed, options.outputDir) : Promise.resolve(''),\n ])\n }\n return result\n } catch (err) {\n if (err instanceof CaptchaError && i < MAX_ATTEMPTS - 1) {\n continue\n }\n throw err\n }\n }\n const sessionDesc = options.kernelApiKey ? `${MAX_ATTEMPTS} fresh Kernel.sh sessions` : `${MAX_ATTEMPTS} attempts`\n throw new CaptchaError(`CAPTCHA on all ${sessionDesc}. Try again in a few minutes.`)\n}\n","import { execSync } from 'node:child_process'\nimport { readFileSync, writeFileSync, unlinkSync, mkdirSync } from 'node:fs'\nimport { tmpdir } from 'node:os'\nimport { join } from 'node:path'\nimport { fal } from '@fal-ai/client'\nimport { buildClipPrompts } from './promptBuilder.js'\nimport { generateVoiceover, addBackgroundAudio } from './AudioGenerator.js'\nimport { concatenateClips, uploadToFal, overlayVoiceover } from './VideoMixer.js'\n\nexport interface ClipPairOptions {\n resolution?: '480p' | '720p' | '1080p'\n aspectRatio?: '16:9' | '9:16' | '1:1'\n clipDurationSeconds?: number\n generateAudio?: boolean\n seed?: number\n outputDir?: string\n ttsVoice?: string\n}\n\nexport interface ClipPairResult {\n clip1Url: string\n clip2Url: string\n finalVideoPath: string\n seed: number\n promptClip1: string\n promptClip2: string\n voiceover: string\n audioMood: string\n}\n\ninterface VideoOutput { video: { url: string }; seed: number }\n\nconst T2V = 'bytedance/seedance-2.0/text-to-video'\nconst I2V = 'bytedance/seedance-2.0/image-to-video'\n\nfunction buildInput(prompt: string, opts: ClipPairOptions, seed?: number, imageUrl?: string) {\n return {\n prompt,\n resolution: opts.resolution ?? '720p',\n duration: opts.clipDurationSeconds ?? 8,\n aspect_ratio: opts.aspectRatio ?? '16:9',\n generate_audio: false,\n ...(seed !== undefined ? { seed } : {}),\n ...(imageUrl !== undefined ? { image_url: imageUrl } : {}),\n }\n}\n\nasync function generate(model: string, input: Record<string, unknown>): Promise<VideoOutput> {\n const { request_id } = await fal.queue.submit(model, { input })\n console.log(`[fal] submitted ${model} → ${request_id}`)\n while (true) {\n await new Promise(r => setTimeout(r, 5000))\n const s = await fal.queue.status(model, { requestId: request_id, logs: false })\n console.log(`[fal] ${request_id} → ${s.status}`)\n if ((s.status as string) === 'FAILED') throw new Error(`Request ${request_id} failed`)\n if ((s.status as string) !== 'COMPLETED') continue\n const result = await fal.queue.result(model, { requestId: request_id })\n return result.data as VideoOutput\n }\n}\n\nasync function extractLastFrame(videoUrl: string, outDir: string): Promise<string> {\n const ts = Date.now()\n const mp4Path = join(outDir, `clip1-raw-${ts}.mp4`)\n const jpgPath = join(outDir, `last-frame-${ts}.jpg`)\n\n const res = await fetch(videoUrl)\n if (!res.ok) throw new Error(`Failed to download clip 1 (${res.status})`)\n writeFileSync(mp4Path, Buffer.from(await res.arrayBuffer()))\n\n try {\n execSync(`ffmpeg -sseof -0.1 -i \"${mp4Path}\" -vframes 1 -y \"${jpgPath}\" -loglevel error`)\n } finally {\n try { unlinkSync(mp4Path) } catch {}\n }\n return jpgPath\n}\n\nexport class VideoGenerator {\n constructor(apiKey?: string) {\n const key = apiKey ?? process.env['FAL_KEY']\n if (!key) throw new Error('FAL_KEY is required')\n fal.config({ credentials: key })\n }\n\n async generateClipPair(\n question: string,\n answer: string,\n opts: ClipPairOptions = {},\n ): Promise<ClipPairResult> {\n const outDir = opts.outputDir ?? join(tmpdir(), `paa-video-${Date.now()}`)\n mkdirSync(outDir, { recursive: true })\n\n console.log('\\n[1/7] Generating prompts via QWEN 3.6...')\n const prompts = await buildClipPrompts(question, answer)\n console.log(' Voiceover:', prompts.voiceover)\n console.log(' Audio mood:', prompts.audioMood)\n\n console.log('\\n[2/7] Generating clip 1 (text-to-video)...')\n const result1 = await generate(T2V, buildInput(prompts.clip1, opts, opts.seed))\n\n console.log('\\n[3/7] Extracting last frame → clip 2 start...')\n const jpgPath = await extractLastFrame(result1.video.url, outDir)\n const imageBlob = new Blob([readFileSync(jpgPath)], { type: 'image/jpeg' })\n const frameUrl = await fal.storage.upload(imageBlob)\n try { unlinkSync(jpgPath) } catch {}\n\n console.log('\\n[4/7] Generating clip 2 (image-to-video from last frame)...')\n const seed2 = opts.seed !== undefined ? opts.seed + 1 : undefined\n const result2 = await generate(I2V, buildInput(prompts.clip2, opts, seed2, frameUrl))\n\n console.log('\\n[5/7] Concatenating clips + generating voiceover (parallel)...')\n const [combinedPath, voiceoverUrl] = await Promise.all([\n concatenateClips(result1.video.url, result2.video.url, outDir),\n generateVoiceover(prompts.voiceover, opts.ttsVoice),\n ])\n\n console.log('\\n[6/7] Adding background audio via MMAudio V2...')\n const falVideoUrl = await uploadToFal(combinedPath)\n const totalDuration = (opts.clipDurationSeconds ?? 8) * 2\n const videoWithAudioUrl = await addBackgroundAudio(falVideoUrl, prompts.audioMood, totalDuration)\n\n console.log('\\n[7/7] Overlaying voiceover on final video...')\n const videoWithAudioPath = join(outDir, `with-bg-audio-${Date.now()}.mp4`)\n const bgRes = await fetch(videoWithAudioUrl)\n writeFileSync(videoWithAudioPath, Buffer.from(await bgRes.arrayBuffer()))\n const finalVideoPath = await overlayVoiceover(videoWithAudioPath, voiceoverUrl, outDir)\n\n return {\n clip1Url: result1.video.url,\n clip2Url: result2.video.url,\n finalVideoPath,\n seed: result1.seed,\n promptClip1: prompts.clip1,\n promptClip2: prompts.clip2,\n voiceover: prompts.voiceover,\n audioMood: prompts.audioMood,\n }\n }\n}\n","export interface ClipPromptPair {\n clip1: string\n clip2: string\n voiceover: string\n audioMood: string\n}\n\nconst DEEPINFRA_URL = 'https://api.deepinfra.com/v1/openai/chat/completions'\nconst OPENROUTER_URL = 'https://openrouter.ai/api/v1/chat/completions'\nconst QWEN_MODEL = 'Qwen/Qwen3.6-35B-A3B'\n\nconst SYSTEM_PROMPT = `You are a video prompt engineer for Seedance 2.0 text-to-video AI.\n\nIMPORTANT TECHNICAL CONTEXT: Clip 2 will be generated using image-to-video, meaning it will start from the exact last frame of Clip 1. The two clips will be visually seamless — same location, same characters, continuous motion. You must write prompts that make this feel like one uninterrupted 16-second video.\n\nYour job: turn a PAA question and its answer into a complete short-form video with visuals, narration, and a background audio mood.\n\nProduce four things:\n\n1. clip1 (~8s): Show a real person experiencing the situation the question describes. End on a specific frozen moment — a held expression, a paused action — that clip 2 continues from.\n\n2. clip2 (~8s): Continue from that exact frozen frame. Deliver the informational payoff from the answer. Show specific facts playing out visually. Describe motion continuing from clip 1's ending frame, not a new scene.\n\n3. voiceover: A spoken narration that fits in 10 seconds of TTS audio. HARD LIMIT: 22 words maximum. Count every word before finalizing — if it exceeds 22 words, cut it. Starts with the problem, ends with the answer. No filler, no \"in conclusion\". Informational and direct.\n\n4. audioMood: 6-10 words describing INSTRUMENTAL background music only — no vocals, no voice, no lyrics. Describe instruments and mood (e.g. \"warm acoustic guitar, uplifting, professional home service, no vocals\"). Will be passed to an AI audio model.\n\nRules for visuals:\n- No text, captions, graphics, or overlays\n- Photorealistic, natural lighting, specific details\n- Describe exactly what the camera sees\n\nRespond with JSON only:\n{\"clip1\": \"...\", \"clip2\": \"...\", \"voiceover\": \"...\", \"audioMood\": \"...\"}`\n\ninterface ChatResponse {\n choices: Array<{ message: { content: string } }>\n}\n\nasync function callLLM(apiKey: string, baseUrl: string, question: string, answer: string): Promise<ClipPromptPair> {\n const res = await fetch(baseUrl, {\n method: 'POST',\n headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json' },\n body: JSON.stringify({\n model: QWEN_MODEL,\n temperature: 0.7,\n messages: [\n { role: 'system', content: SYSTEM_PROMPT },\n { role: 'user', content: `Question: ${question}\\n\\nAnswer: ${answer.slice(0, 500)}` },\n ],\n }),\n })\n if (!res.ok) throw new Error(`LLM call failed (${res.status}): ${await res.text()}`)\n\n const data = (await res.json()) as ChatResponse\n const raw = data.choices[0]?.message?.content?.trim() ?? ''\n const match = raw.match(/\\{[\\s\\S]*\\}/)\n if (!match) throw new Error(`No JSON in QWEN response: ${raw.slice(0, 200)}`)\n\n const parsed = JSON.parse(match[0]) as Partial<ClipPromptPair>\n if (!parsed.clip1 || !parsed.clip2 || !parsed.voiceover || !parsed.audioMood) {\n throw new Error(`QWEN response missing fields: ${raw.slice(0, 200)}`)\n }\n return parsed as ClipPromptPair\n}\n\nexport async function buildClipPrompts(question: string, answer: string): Promise<ClipPromptPair> {\n const deepinfraKey = process.env['DEEPINFRA_API_KEY']\n const openrouterKey = process.env['OPENROUTER_API_KEY']\n\n if (deepinfraKey) {\n try {\n return await callLLM(deepinfraKey, DEEPINFRA_URL, question, answer)\n } catch (err) {\n console.warn('[promptBuilder] DeepInfra failed, trying OpenRouter:', (err as Error).message)\n }\n }\n if (openrouterKey) {\n return await callLLM(openrouterKey, OPENROUTER_URL, question, answer)\n }\n throw new Error('No LLM key — set DEEPINFRA_API_KEY or OPENROUTER_API_KEY')\n}\n","const TTS_MODEL = 'fal-ai/inworld-tts'\nconst MMAUDIO_MODEL = 'fal-ai/mmaudio-v2'\nconst QUEUE_BASE = 'https://queue.fal.run'\n\ninterface TtsOutput { audio: { url: string } }\ninterface VideoOutput { video: { url: string } }\n\nasync function rawQueueRun(model: string, input: Record<string, unknown>, apiKey: string): Promise<Record<string, unknown>> {\n const headers = { 'Authorization': `Key ${apiKey}`, 'Content-Type': 'application/json' }\n\n const submitRes = await fetch(`${QUEUE_BASE}/${model}`, {\n method: 'POST', headers, body: JSON.stringify(input),\n })\n if (!submitRes.ok) throw new Error(`${model} submit failed (${submitRes.status}): ${await submitRes.text()}`)\n const { request_id } = await submitRes.json() as { request_id: string }\n console.log(`[fal] submitted ${model} → ${request_id}`)\n\n while (true) {\n await new Promise(r => setTimeout(r, 5000))\n const statusRes = await fetch(`${QUEUE_BASE}/${model}/requests/${request_id}/status`, { headers })\n if (!statusRes.ok) continue\n const { status } = await statusRes.json() as { status: string }\n console.log(`[fal] ${request_id} → ${status}`)\n if (status === 'FAILED') throw new Error(`${model} request ${request_id} failed`)\n if (status !== 'COMPLETED') continue\n const resultRes = await fetch(`${QUEUE_BASE}/${model}/requests/${request_id}`, { headers })\n if (!resultRes.ok) throw new Error(`Result fetch failed (${resultRes.status})`)\n return await resultRes.json() as Record<string, unknown>\n }\n}\n\nfunction getKey(): string {\n const key = process.env['FAL_KEY']\n if (!key) throw new Error('FAL_KEY required')\n return key\n}\n\nexport async function generateVoiceover(text: string, voice = 'Serena (en)'): Promise<string> {\n console.log('[AudioGenerator] Generating voiceover...')\n const out = await rawQueueRun(TTS_MODEL, { text, voice, sample_rate_hertz: 48000 }, getKey()) as unknown as TtsOutput\n return out.audio.url\n}\n\nexport async function addBackgroundAudio(videoUrl: string, mood: string, durationSeconds: number): Promise<string> {\n console.log('[AudioGenerator] Adding background audio via MMAudio V2...')\n const out = await rawQueueRun(MMAUDIO_MODEL, {\n video_url: videoUrl,\n prompt: mood,\n negative_prompt: 'speech, voice, talking, dialogue, narration, vocals, singing, human voice, conversation, words, lyrics, announcer, commentary',\n duration: durationSeconds,\n cfg_strength: 4.5,\n }, getKey()) as unknown as VideoOutput\n return out.video.url\n}\n","import { execSync } from 'node:child_process'\nimport { writeFileSync, mkdirSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { fal } from '@fal-ai/client'\n\nasync function download(url: string, destPath: string): Promise<void> {\n const res = await fetch(url)\n if (!res.ok) throw new Error(`Download failed (${res.status}): ${url}`)\n writeFileSync(destPath, Buffer.from(await res.arrayBuffer()))\n}\n\nexport async function concatenateClips(clip1Url: string, clip2Url: string, outDir: string): Promise<string> {\n mkdirSync(outDir, { recursive: true })\n const ts = Date.now()\n const p1 = join(outDir, `clip1-${ts}.mp4`)\n const p2 = join(outDir, `clip2-${ts}.mp4`)\n const out = join(outDir, `combined-${ts}.mp4`)\n\n console.log('[VideoMixer] Downloading clips...')\n await Promise.all([download(clip1Url, p1), download(clip2Url, p2)])\n\n console.log('[VideoMixer] Concatenating...')\n execSync(\n `ffmpeg -i \"${p1}\" -i \"${p2}\" -filter_complex \"[0:v][1:v]concat=n=2:v=1:a=0[v]\" -map \"[v]\" -y \"${out}\" -loglevel error`\n )\n return out\n}\n\nexport async function uploadToFal(localPath: string): Promise<string> {\n const { readFileSync } = await import('node:fs')\n const blob = new Blob([readFileSync(localPath)], { type: 'video/mp4' })\n const url = await fal.storage.upload(blob)\n console.log('[VideoMixer] Uploaded to fal:', url)\n return url\n}\n\nexport async function overlayVoiceover(\n videoPath: string,\n voiceoverUrl: string,\n outDir: string,\n): Promise<string> {\n const ts = Date.now()\n const wav = join(outDir, `voiceover-${ts}.wav`)\n const out = join(outDir, `final-${ts}.mp4`)\n\n console.log('[VideoMixer] Downloading voiceover...')\n await download(voiceoverUrl, wav)\n\n console.log('[VideoMixer] Mixing voiceover over background audio...')\n execSync(\n `ffmpeg -i \"${videoPath}\" -i \"${wav}\" ` +\n `-filter_complex \"[0:a]volume=0.2[bg];[1:a]volume=1.0[vo];[bg][vo]amix=inputs=2:duration=first[a]\" ` +\n `-map 0:v -map \"[a]\" -c:v copy -y \"${out}\" -loglevel error`\n )\n return out\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,iBAAkB;AAEX,IAAM,uBAAuB,aAAE,OAAO;AAAA,EAC3C,OAAc,aAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC9B,UAAc,aAAE,OAAO,EAAE,SAAS;AAAA,EAClC,IAAc,aAAE,OAAO,EAAE,OAAO,CAAC,EAAE,QAAQ,IAAI;AAAA,EAC/C,IAAc,aAAE,OAAO,EAAE,OAAO,CAAC,EAAE,QAAQ,IAAI;AAAA,EAC/C,OAAc,aAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,QAAQ,CAAC;AAAA,EACvD,cAAc,aAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,GAAI,EAAE,QAAQ,GAAG;AAAA,EAC3D,UAAc,aAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA,EACvC,YAAc,aAAE,OAAO,EAAE,SAAS;AAAA,EAClC,OAAc,aAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAAA,EACxC,cAAc,aAAE,OAAO,EAAE,SAAS;AAAA,EAClC,eAAe,aAAE,OAAO,EAAE,SAAS;AAAA,EACnC,WAAc,aAAE,OAAO,EAAE,QAAQ,cAAc;AAAA,EAC/C,QAAc,aAAE,KAAK,CAAC,QAAQ,OAAO,MAAM,CAAC,EAAE,QAAQ,MAAM;AAAA,EAC5D,UAAc,aAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA,EACvC,OAAc,aAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,QAAQ,CAAC;AACxD,CAAC;AAEM,IAAM,yBAAyB,aAAE,OAAO;AAAA,EAC7C,cAAe,aAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC/B,UAAe,aAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC/B,IAAe,aAAE,OAAO,EAAE,OAAO,CAAC,EAAE,QAAQ,IAAI;AAAA,EAChD,IAAe,aAAE,OAAO,EAAE,OAAO,CAAC,EAAE,QAAQ,IAAI;AAAA,EAChD,gBAAgB,aAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA,EACzC,YAAe,aAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,QAAQ,EAAE;AAAA,EAC1D,cAAe,aAAE,OAAO,EAAE,SAAS;AAAA,EACnC,eAAe,aAAE,OAAO,EAAE,SAAS;AAAA,EACnC,UAAe,aAAE,QAAQ,EAAE,QAAQ,IAAI;AACzC,CAAC;AAEM,IAAM,mBAAmB,aAAE,OAAO;AAAA,EACvC,UAAa,aAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC7B,QAAa,aAAE,OAAO,EAAE,SAAS;AAAA,EACjC,aAAa,aAAE,OAAO,EAAE,SAAS;AAAA,EACjC,YAAa,aAAE,OAAO,EAAE,SAAS;AAAA,EACjC,YAAa,aAAE,OAAO,EAAE,SAAS;AACnC,CAAC;;;ACtCD,8BAAyB;AACzB,4CAA0B;AAC1B,wBAA+C;AAE/C,iBAAmB;;;ACJZ,IAAM,eAAe;AAAA,EAC1B,WAAiB;AAAA,EACjB,WAAiB;AAAA,EACjB,MAAiB;AAAA,EACjB,WAAiB;AAAA,EACjB,eAAiB;AAAA,EACjB,gBAAiB;AAAA,EACjB,iBAAiB;AAAA,EACjB,aAAiB;AAAA,EACjB,YAAiB;AAAA,EACjB,YAAiB;AAAA,EACjB,aAAiB;AAAA,EACjB,eAAiB;AAAA,EACjB,eAAiB;AACnB;AAEO,IAAM,iBAAiB;AAAA,EAC5B,WAAkB;AAAA,EAClB,gBAAkB;AAAA,EAClB,MAAkB;AACpB;AAEO,IAAM,sBAAsB;AAAA,EACjC,KAAkB;AAAA,EAClB,MAAkB;AAAA,EAClB,iBAAkB;AAAA,EAClB,WAAkB,CAAC,WAAW,UAAU,aAAa,YAAY,GAAG;AACtE;AAEO,IAAM,iBAAiB;AAAA,EAC5B,SAAU;AAAA,EACV,MAAU;AAAA,EACV,OAAU;AAAA,EACV,QAAU;AACZ;AAEO,IAAM,4BAA4B;AAAA,EACvC,YAAqB;AAAA,EACrB,oBAAqB;AAAA,EACrB,MAAqB;AAAA,EACrB,UAAqB;AAAA,EACrB,SAAqB;AAAA,EACrB,UAAqB;AAAA,EACrB,qBAAqB;AAAA,EACrB,QAAqB;AAAA,EACrB,eAAqB;AAAA,EACrB,WAAqB;AAAA,EACrB,QAAqB;AAAA,EACrB,YAAqB;AACvB;AAEO,IAAM,sBAAsB;AAAA,EACjC,MAAW;AAAA,EACX,SAAW;AAAA,EACX,WAAW;AACb;AAEO,IAAM,kBAAkB;AAAA,EAC7B,MAAW;AAAA,EACX,SAAW;AAAA,EACX,WAAW;AACb;AAEO,IAAM,mBAAmB;AAAA,EAC9B,QAAc;AAAA,EACd,OAAc;AAAA,EACd,UAAc;AAAA,EACd,MAAc;AAAA,EACd,SAAc;AAAA,EACd,YAAc;AAAA,EACd,YAAc;AAAA,EACd,aAAc;AAAA,EACd,aAAc;AAChB;AAEO,IAAM,qBAAqB;AAAA,EAChC,aAAc;AAAA,EACd,MAAc;AAAA,EACd,MAAc;AAAA,EACd,aAAc;AAAA,EACd,aAAc;AAChB;;;ACjFO,IAAM,yBAAyB;AAE/B,IAAM,eAAN,cAA2B,MAAM;AAAA,EAEtC,YAA4B,cAAsB;AAChD,UAAM,qBAAqB,YAAY,EAAE;AADf;AAAA,EAE5B;AAAA,EAF4B;AAAA,EADnB,OAAO;AAIlB;AAEO,IAAM,kBAAN,cAA8B,MAAM;AAAA,EAEzC,YAAY,SAAiC,OAAiB;AAC5D,UAAM,OAAO;AAD8B;AAAA,EAE7C;AAAA,EAF6C;AAAA,EADpC,OAAO;AAIlB;;;AFJA,iCAAS,QAAI,sCAAAA,SAAc,CAAC;AAE5B,IAAM,qBACJ;AAEK,SAAS,6BAA6B,cAA8B;AACzE,QAAM,MAAM,aAAa,KAAK;AAC9B,MAAI,CAAC,IAAK,OAAM,IAAI,MAAM,2BAA2B;AAErD,QAAM,UAAU,gBAAgB,KAAK,GAAG,KAAK,+BAA+B,KAAK,GAAG;AACpF,MAAI,SAAS;AACX,UAAM,SAAS,IAAI,IAAI,gBAAgB,KAAK,GAAG,IAAI,MAAM,WAAW,GAAG,EAAE;AACzE,UAAM,OAAO,OAAO,SAAS,QAAQ,UAAU,EAAE,EAAE,QAAQ,QAAQ,EAAE,EAAE,YAAY;AACnF,QAAI,SAAS,cAAe,OAAM,IAAI,MAAM,oCAAoC;AAEhF,UAAM,WAAW,OAAO,SAAS,MAAM,GAAG,EAAE,OAAO,OAAO;AAC1D,UAAM,QAAQ,SAAS,CAAC,KAAK;AAC7B,UAAM,SAAS,SAAS,CAAC,KAAK;AAE9B,QAAI,MAAM,WAAW,GAAG,EAAG,QAAO,2BAA2B,KAAK;AAClE,QAAI,UAAU,aAAa,OAAQ,QAAO,mCAAmC,MAAM;AACnF,SAAK,UAAU,OAAO,UAAU,WAAW,OAAQ,QAAO,2BAA2B,KAAK,IAAI,MAAM;AAEpG,UAAM,IAAI,MAAM,gFAAgF;AAAA,EAClG;AAEA,QAAM,WAAW,IAAI,QAAQ,QAAQ,EAAE,EAAE,QAAQ,QAAQ,EAAE;AAC3D,QAAM,gBAAgB,SAAS,QAAQ,cAAc,EAAE;AACvD,MAAI,iBAAiB,KAAK,aAAa,GAAG;AACxC,WAAO,mCAAmC,aAAa;AAAA,EACzD;AAEA,QAAM,SAAS,cAAc,WAAW,GAAG,IAAI,gBAAgB,IAAI,aAAa;AAChF,MAAI,CAAC,aAAa,KAAK,MAAM,GAAG;AAC9B,UAAM,IAAI,MAAM,yEAAyE;AAAA,EAC3F;AACA,SAAO,2BAA2B,MAAM;AAC1C;AAEO,IAAM,gBAAN,MAA8C;AAAA,EAC3C,UAA0B;AAAA,EAC1B,UAAiC;AAAA,EACjC,OAAoB;AAAA,EACpB,eAA8B;AAAA,EAC9B,kBAAiC;AAAA,EAEzC,MAAM,OAAO,QAAqC;AAChD,QAAI,OAAO,cAAc;AACvB,WAAK,eAAe,IAAI,WAAAC,QAAO,EAAE,QAAQ,OAAO,aAAa,CAAC;AAC9D,YAAM,gBAAgB,MAAM,KAAK,aAAa,SAAS,OAAO;AAAA,QAC5D,SAAS;AAAA,QACT,iBAAiB;AAAA,QACjB,GAAI,OAAO,gBAAgB,EAAE,UAAU,OAAO,cAAc,IAAI,CAAC;AAAA,MACnE,CAAC;AACD,WAAK,kBAAkB,cAAc;AACrC,WAAK,UAAU,MAAM,kBAAAC,SAAmB,eAAe,cAAc,UAAU;AAC/E,WAAK,UAAU,KAAK,QAAQ,SAAS,EAAE,CAAC,KAAK,MAAM,KAAK,QAAQ,WAAW;AAC3E,YAAM,KAAK,0BAA0B,KAAK,OAAO;AACjD,WAAK,OAAO,KAAK,QAAQ,MAAM,EAAE,CAAC,KAAK,MAAM,KAAK,QAAQ,QAAQ;AAClE;AAAA,IACF;AAEA,UAAM,aAAa;AAAA,MACjB,UAAU,OAAO;AAAA,MACjB,OAAO,OAAO,QAAQ,EAAE,QAAQ,OAAO,MAAM,IAAI;AAAA,IACnD;AACA,UAAM,UAAU;AAAA,MACd,UAAU,OAAO;AAAA,MACjB,QAAQ,OAAO;AAAA,MACf,WAAW;AAAA,IACb;AACA,QAAI,OAAO,YAAY;AACrB,WAAK,UAAU,MAAM,iCAAS,wBAAwB,OAAO,YAAY;AAAA,QACvE,GAAG;AAAA,QACH,GAAG;AAAA,MACL,CAAC;AACD,YAAM,KAAK,0BAA0B,KAAK,OAAO;AACjD,WAAK,OAAO,MAAM,KAAK,QAAQ,QAAQ;AAAA,IACzC,OAAO;AACL,WAAK,UAAU,MAAM,iCAAS,OAAO,UAAU;AAC/C,WAAK,UAAU,MAAM,KAAK,QAAQ,WAAW,OAAO;AACpD,YAAM,KAAK,0BAA0B,KAAK,OAAO;AACjD,WAAK,OAAO,MAAM,KAAK,QAAQ,QAAQ;AAAA,IACzC;AAAA,EACF;AAAA,EAEA,MAAc,0BAA0B,SAAwC;AAC9E,UAAM,QAAQ,cAAc,MAAM;AAChC,YAAM,IAAI;AACV,UAAI,OAAO,EAAE,WAAW,WAAmB,GAAE,SAAgB,CAAC,OAAgB;AAC9E,UAAI,OAAO,EAAE,kBAAkB,WAAY,GAAE,gBAAgB,CAAC,KAA8B,KAAa,UAAmB;AAAE,YAAI,GAAG,IAAI;AAAO,eAAO;AAAA,MAAM;AAAA,IAC/J,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,eACJ,OACA,MACA,IACA,IAC8B;AAC9B,UAAM,SAAS,IAAI,gBAAgB,EAAE,GAAG,OAAO,IAAI,GAAG,CAAC;AACvD,QAAI,KAAM,QAAO,IAAI,QAAQ,IAAI;AACjC,UAAM,MAAM,mCAAmC,OAAO,SAAS;AAE/D,QAAI;AACF,YAAM,KAAK,KAAM,KAAK,KAAK,EAAE,WAAW,oBAAoB,SAAS,KAAO,CAAC;AAAA,IAC/E,SAAS,KAAK;AACZ,YAAM,OAAO,MAAM,KAAK,mBAAmB,GAAG;AAC9C,YAAM,IAAI,gBAAgB,qBAAsB,IAAc,OAAO,MAAM,IAAI,EAAE;AAAA,IACnF;AAEA,UAAM,eAAe,MAAM,KAAK,KAAM,QAAQ,aAAa,aAAa,EAAE,MAAM;AAChF,QAAI,eAAe,GAAG;AACpB,UAAI,KAAK,cAAc;AACrB,YAAI;AACF,gBAAM,KAAK,KAAM,gBAAgB,aAAa,WAAW,EAAE,SAAS,KAAO,CAAC;AAC5E,iBAAO,EAAE,QAAQ,KAAK;AAAA,QACxB,QAAQ;AACN,gBAAM,IAAI,aAAa,KAAK,eAAe,CAAC;AAAA,QAC9C;AAAA,MACF;AACA,YAAM,IAAI,aAAa,KAAK,eAAe,CAAC;AAAA,IAC9C;AAEA,UAAM,YAAY,MAAM,KAAK,KAAM,gBAAgB,aAAa,MAAM,EAAE,SAAS,IAAM,CAAC,EAAE,MAAM,MAAM,IAAI;AAC1G,QAAI,UAAW,QAAO,EAAE,QAAQ,KAAK;AAErC,UAAM,eAAe,MAAM,KAAK,KAAM,QAAQ,aAAa,aAAa,EAAE,MAAM;AAChF,QAAI,eAAe,EAAG,OAAM,IAAI,aAAa,KAAK,eAAe,CAAC;AAElE,aAAS,IAAI,GAAG,KAAK,GAAG,KAAK;AAC3B,YAAM,KAAK,KAAM,SAAS,CAAC,MAAc;AAAE,eAAO,SAAS,GAAG,SAAS,KAAK,eAAe,CAAC;AAAA,MAAE,GAAG,IAAI,CAAC;AACtG,YAAM,KAAK,KAAM,eAAe,GAAG;AACnC,YAAM,QAAQ,MAAM,KAAK,KAAM,QAAQ,aAAa,IAAI,EAAE,MAAM;AAChE,UAAI,QAAQ,EAAG,QAAO,EAAE,QAAQ,KAAK;AAAA,IACvC;AAEA,WAAO,EAAE,QAAQ,MAAM;AAAA,EACzB;AAAA,EAEA,MAAc,mBAAmB,aAAsC;AACrE,QAAI;AACF,YAAM,WAAW,KAAK,KAAM,IAAI;AAChC,YAAM,QAAQ,MAAM,KAAK,KAAM,MAAM,EAAE,MAAM,MAAM,EAAE;AACrD,YAAM,cAAc,MAAM,KAAK,KAAM,SAAS,MAAM;AAClD,cAAM,KAAK,SAAS,MAAM,aAAa,IAAI,QAAQ,QAAQ,GAAG,EAAE,KAAK;AACrE,eAAO,EAAE,MAAM,GAAG,GAAG;AAAA,MACvB,CAAC,EAAE,MAAM,MAAM,EAAE;AACjB,YAAM,UAAU,oBAAoB,KAAK,QAAQ,KAAK,uBAAuB,KAAK,WAAW;AAC7F,YAAM,YAAY,6CAA6C,KAAK,WAAW;AAC/E,YAAM,QAAQ;AAAA,QACZ,UAAU,iBAAiB;AAAA,QAC3B,YAAY,kBAAkB;AAAA,QAC9B,aAAa,cAAc,eAAe;AAAA,MAC5C,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAC1B,aAAO,YAAY,WAAW,YAAY,QAAQ,aAAa,KAAK,cAAc,KAAK,aAAa,WAAW;AAAA,IACjH,SAAS,GAAG;AACV,aAAO,uBAAwB,EAAY,OAAO;AAAA,IACpD;AAAA,EACF;AAAA,EAEQ,iBAAyB;AAC/B,WAAO,KAAK,eACR,8FACA;AAAA,EACN;AAAA,EAEA,MAAM,WAAW,KAA4B;AAC3C,QAAI;AACF,YAAM,KAAK,KAAM,KAAK,KAAK,EAAE,WAAW,oBAAoB,SAAS,KAAO,CAAC;AAAA,IAC/E,SAAS,KAAK;AACZ,YAAM,OAAO,MAAM,KAAK,mBAAmB,GAAG;AAC9C,YAAM,IAAI,gBAAgB,qBAAsB,IAAc,OAAO,MAAM,IAAI,EAAE;AAAA,IACnF;AAAA,EACF;AAAA,EAEA,MAAM,kBAAkB,eAAsC;AAC5D,UAAM,MAAM,6BAA6B,aAAa;AACtD,QAAI;AACF,YAAM,KAAK,KAAM,KAAK,KAAK,EAAE,WAAW,eAAe,SAAS,IAAO,CAAC;AAAA,IAC1E,SAAS,KAAK;AACZ,YAAM,OAAO,MAAM,KAAK,mBAAmB,GAAG;AAC9C,YAAM,IAAI,gBAAgB,6BAA8B,IAAc,OAAO,MAAM,IAAI,EAAE;AAAA,IAC3F;AAAA,EACF;AAAA,EAEA,MAAM,SAAY,IAA4C,KAA2B;AACvF,WAAQ,KAAK,KAA+D,SAAS,IAAI,GAAG;AAAA,EAC9F;AAAA,EAEA,UAAgB;AACd,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,QAAuB;AAC3B,QAAI,KAAK,SAAS;AAChB,YAAM,IAAI,KAAK;AACf,YAAM,YAAY,KAAK;AACvB,YAAM,SAAS,KAAK;AACpB,WAAK,UAAU;AACf,WAAK,UAAU;AACf,WAAK,OAAO;AACZ,WAAK,kBAAkB;AACvB,WAAK,eAAe;AACpB,UAAI;AACF,cAAM,EAAE,MAAM;AAAA,MAChB,UAAE;AACA,YAAI,UAAU,WAAW;AACvB,gBAAM,OAAO,SAAS,WAAW,SAAS,EAAE;AAAA,YAAM,CAAC,QACjD,QAAQ,KAAK,kCAAkC,GAAG;AAAA,UACpD;AAAA,QACF;AAAA,MACF;AAAA,IACF,WAAW,KAAK,SAAS;AACvB,YAAM,MAAM,KAAK;AACjB,WAAK,UAAU;AACf,WAAK,OAAO;AACZ,YAAM,IAAI,MAAM;AAAA,IAClB;AAAA,EACF;AACF;;;AGpOO,IAAM,YAAmD;AAAA,EAC9D,UAAoB;AAAA,EACpB,YAAoB;AAAA,EACpB,iBAAoB;AAAA,EACpB,OAAoB;AAAA,EACpB,eAAoB;AAAA,EACpB,MAAoB;AAAA,EACpB,WAAoB;AAAA,EACpB,WAAoB;AAAA,EACpB,WAAoB;AAAA,EACpB,gBAAoB;AAAA,EACpB,UAAoB;AAAA,EACpB,eAAoB;AAAA,EACpB,UAAoB;AAAA,EACpB,SAAoB;AAAA,EACpB,WAAoB;AAAA,EACpB,UAAoB;AAAA,EACpB,YAAoB;AAAA,EACpB,eAAoB;AAAA,EACpB,gBAAoB;AAAA,EACpB,WAAoB;AAAA,EACpB,oBAAoB;AAAA,EACpB,UAAoB;AAAA,EACpB,WAAoB;AAAA,EACpB,iBAAoB;AAAA,EACpB,MAAoB;AAAA,EACpB,YAAoB;AAAA,EACpB,aAAoB;AAAA,EACpB,eAAoB;AAAA,EACpB,WAAoB;AAAA,EACpB,aAAoB;AAAA,EACpB,aAAoB;AAAA,EACpB,WAAoB;AAAA,EACpB,aAAoB;AAAA,EACpB,aAAoB;AAAA,EACpB,cAAoB;AAAA,EACpB,YAAoB;AAAA,EACpB,gBAAoB;AAAA,EACpB,YAAoB;AAAA,EACpB,cAAoB;AAAA,EACpB,gBAAoB;AAAA,EACpB,WAAoB;AAAA,EACpB,cAAoB;AAAA,EACpB,WAAoB;AAAA,EACpB,YAAoB;AAAA,EACpB,kBAAoB;AAAA,EACpB,WAAoB;AAAA,EACpB,aAAoB;AAAA,EACpB,YAAoB;AAAA,EACpB,WAAoB;AAAA,EACpB,UAAoB;AAAA,EACpB,UAAoB;AAAA,EACpB,cAAoB;AAAA,EACpB,cAAoB;AAAA,EACpB,aAAoB;AAAA,EACpB,WAAoB;AAAA,EACpB,SAAoB;AAAA,EACpB,UAAoB;AAAA,EACpB,aAAoB;AAAA,EACpB,YAAoB;AAAA,EACpB,SAAoB;AAAA,EACpB,YAAoB;AAAA,EACpB,UAAoB;AACtB;;;AC9DO,SAAS,WAAW,MAAyC;AAClE,QAAM,UAAU,OAAO,KAAK,OAAO,aAAa,KAAK,MAAM,IAAI,IAAI,EAAE,SAAS,QAAQ;AACtF,SAAO,YAAY,OAAO;AAC5B;AAEO,SAAS,kBAAkB,OAAsC;AACtE,QAAM,MAAM,MAAM,YAAY,EAAE,KAAK;AACrC,SAAQ,UAAU,GAAG,KAAK;AAC5B;;;ACXA,IAAM,oBAAoB;AAE1B,IAAM,uBAAiC;AAAA,EACrC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,cAAwB;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,SAAS,oBAAoB,MAAsB;AACjD,SAAO,KACJ,QAAQ,WAAW,GAAG,EACtB,QAAQ,mBAAmB,OAAO,EAClC,QAAQ,kBAAkB,OAAO,EACjC,QAAQ,wBAAwB,OAAO,EACvC,QAAQ,qBAAqB,OAAO,EACpC,QAAQ,gBAAgB,OAAO,EAC/B,QAAQ,QAAQ,GAAG,EACnB,KAAK;AACV;AAEA,SAAS,iBAAiB,MAAsB;AAC9C,MAAI,QAAQ;AACZ,aAAW,UAAU,aAAa;AAChC,UAAM,QAAQ,OAAO,KAAK,IAAI;AAC9B,WAAO,YAAY;AACnB,QAAI,UAAU,UAAU,MAAM,MAAM,QAAQ,OAAQ,SAAQ,MAAM;AAAA,EACpE;AACA,SAAO,UAAU,KAAK,OAAO,KAAK,MAAM,GAAG,KAAK;AAClD;AAEA,SAAS,iBAAiB,MAAc,aAA8B;AACpE,QAAM,QAAQ,aAAa,KAAK;AAChC,MAAI,CAAC,SAAS,MAAM,SAAS,EAAG,QAAO;AACvC,QAAM,MAAM,KAAK,YAAY,EAAE,QAAQ,MAAM,YAAY,CAAC;AAC1D,SAAO,MAAM,KAAK,KAAK,MAAM,GAAG,GAAG,IAAI;AACzC;AAEA,SAAS,mBAAmB,WAA2B;AACrD,QAAM,YAAY,UAAU,MAAM,yFAAyF;AAC3H,MAAI,WAAW,SAAS,UAAU,QAAQ,GAAI,QAAO,UAAU;AAE/D,QAAM,QAAQ,KAAK,IAAI,GAAG,UAAU,SAAS,GAAG;AAChD,QAAM,OAAO,UAAU,MAAM,KAAK;AAClC,QAAM,iBAAiB,CAAC,GAAG,KAAK,SAAS,kCAAkC,CAAC;AAC5E,aAAW,SAAS,gBAAgB;AAClC,UAAM,YAAY,KAAK,MAAM,MAAM,QAAQ,CAAC,EAAE,KAAK;AACnD,UAAM,OAAO,UAAU,MAAM,GAAG,GAAG;AACnC,UAAM,iBAAiB,2EAA2E,KAAK,SAAS;AAChH,QACE,UAAU,SAAS,MACnB,kBACA,mEAAmE,KAAK,IAAI,GAC5E;AACA,aAAO,QAAQ,MAAM,QAAQ;AAAA,IAC/B;AAAA,EACF;AACA,QAAM,OAAO,eAAe,GAAG,EAAE;AACjC,MAAI,MAAM,UAAU,OAAW,QAAO,QAAQ,KAAK,QAAQ;AAE3D,SAAO,UAAU;AACnB;AAEA,SAAS,oBAAoB,MAAsB;AACjD,QAAM,WAAW,KAAK,MAAM,iBAAiB;AAC7C,MAAI,CAAC,UAAU,MAAO,QAAO;AAE7B,QAAM,YAAY,KAAK,MAAM,GAAG,SAAS,KAAK;AAC9C,SAAO,UAAU,MAAM,GAAG,mBAAmB,SAAS,CAAC;AACzD;AAEA,SAAS,oBAAoB,MAAsB;AACjD,MAAI,KAAK,UAAU,kBAAmB,QAAO;AAC7C,QAAM,QAAQ,KAAK,MAAM,GAAG,iBAAiB;AAC7C,QAAM,eAAe,KAAK,IAAI,MAAM,YAAY,GAAG,GAAG,MAAM,YAAY,GAAG,GAAG,MAAM,YAAY,GAAG,CAAC;AACpG,UAAQ,eAAe,MAAM,MAAM,MAAM,GAAG,eAAe,CAAC,IAAI,OAAO,KAAK;AAC9E;AAEO,SAAS,mBACd,QACA,UACA,aACoB;AACpB,MAAI,CAAC,OAAQ,QAAO;AAEpB,MAAI,OAAO,oBAAoB,MAAM;AACrC,QAAM,qBAAqB,WAAW,oBAAoB,QAAQ,IAAI;AACtE,MAAI,sBAAsB,KAAK,YAAY,EAAE,WAAW,mBAAmB,YAAY,CAAC,GAAG;AACzF,WAAO,KAAK,MAAM,mBAAmB,MAAM,EAAE,KAAK;AAAA,EACpD;AAEA,MAAI,yDAAyD,KAAK,IAAI,GAAG;AACvE,WAAO;AAAA,EACT;AAEA,aAAW,WAAW,sBAAsB;AAC1C,WAAO,KAAK,QAAQ,SAAS,GAAG;AAAA,EAClC;AACA,SAAO,KACJ,QAAQ,2CAA2C,GAAG,EACtD,QAAQ,yCAAyC,GAAG;AAEvD,SAAO,oBAAoB,IAAI;AAC/B,SAAO,iBAAiB,IAAI;AAC5B,SAAO,iBAAiB,MAAM,WAAW;AACzC,SAAO,oBAAoB,IAAI;AAC/B,SAAO,oBAAoB,IAAI;AAC/B,SAAO,KAAK,QAAQ,wFAAwF,EAAE,EAAE,KAAK;AACrH,SAAO,oBAAoB,IAAI;AAE/B,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI,0DAA0D,KAAK,IAAI,EAAG,QAAO;AAEjF,SAAO;AACT;;;AC7GO,IAAM,eAAN,MAA4C;AAAA,EACjD,YACmB,QACA,UACjB;AAFiB;AACA;AAAA,EAChB;AAAA,EAFgB;AAAA,EACA;AAAA,EAGX,kBAAkB,GAAkC;AAC1D,WAAO,EAAE,YAAY,EAAE,QAAQ,YAAY,EAAE,EAAE,QAAQ,QAAQ,GAAG,EAAE,KAAK;AAAA,EAC3E;AAAA,EAEA,MAAc,oBAAoB,MAAmC;AACnE,UAAM,OAAO;AACb,UAAM,MAAM,MAAM,KAAK,SAAS,CAAC,cAAc;AAC7C,eAAS,UAAU,IAA4B;AAC7C,YAAI,CAAC,GAAI,QAAO;AAChB,cAAM,QAAkB,CAAC;AACzB,mBAAW,KAAK,GAAG,YAAY;AAC7B,cAAI,EAAE,aAAa,KAAK,WAAW;AACjC,kBAAM,OAAO,EAAE,aAAa,KAAK;AACjC,gBAAI,KAAM,OAAM,KAAK,IAAI;AAAA,UAC3B,WACG,EAAc,YAAY,WAC1B,EAAc,YAAY,UAC3B;AACA;AAAA,UACF,OAAO;AACL,kBAAM,OAAO,UAAU,CAAY;AACnC,gBAAI,KAAM,OAAM,KAAK,IAAI;AAAA,UAC3B;AAAA,QACF;AACA,eAAO,MAAM,KAAK,GAAG,EAAE,QAAQ,QAAQ,GAAG,EAAE,KAAK;AAAA,MACnD;AACA,aAAO,MAAM,KAAK,SAAS,iBAAiB,UAAU,IAAI,CAAC,EAAE,IAAI,CAAC,UAAU;AAAA,QAC1E,UAAa,KAAK,aAAa,UAAU,SAAS,KAAK,KAAK,aAAa,UAAU,aAAa,KAAK;AAAA,QACrG,QAAa,UAAU,KAAK,cAAc,UAAU,eAAe,CAAC,KAAK;AAAA,QACzE,aAAc,KAAK,cAAc,UAAU,WAAW,GAA0B,WAAW,KAAK,KAAK;AAAA,QACrG,YAAc,KAAK,cAAc,UAAU,UAAU,GAA0B,WAAW,KAAK,KAAK;AAAA,QACpG,YAAc,KAAK,cAAc,UAAU,UAAU,GAA0B,WAAW,KAAK,KAAK;AAAA,MACtG,EAAE;AAAA,IACJ,GAAG,IAAI;AAEP,WAAO,IAAI,QAAQ,CAAC,SAAS;AAC3B,YAAM,UAAU;AAAA,QACd,GAAG;AAAA,QACH,QAAQ,mBAAmB,KAAK,QAAQ,KAAK,UAAU,KAAK,WAAW;AAAA,MACzE;AACA,YAAM,SAAS,iBAAiB,UAAU,OAAO;AACjD,UAAI,CAAC,OAAO,SAAS;AACnB,gBAAQ,KAAK,qCAAqC,KAAK,UAAU,OAAO,MAAM,OAAO,CAAC,GAAG,OAAO;AAChG,eAAO,CAAC;AAAA,MACV;AACA,aAAO,CAAC,OAAO,IAAI;AAAA,IACrB,CAAC;AAAA,EACH;AAAA,EAEA,MAAc,UAAU,MAAY,cAAqC;AACvE,QAAI;AACF,YAAM,cAAc,KAAK;AAAA,QACvB,GAAG,aAAa,IAAI,YAAY,YAAY,OAAO,aAAa,IAAI,gBAAgB,YAAY;AAAA,MAClG,EAAE,MAAM;AACR,YAAM,YAAY,MAAM;AAAA,IAC1B,QAAQ;AAAA,IAAE;AAAA,EACZ;AAAA,EAEQ,UAAU,MAAkB,OAAe,gBAA+B,MAAuB;AACvG,WAAO;AAAA,MACL,YAAiB;AAAA,MACjB,UAAiB,KAAK;AAAA,MACtB,QAAiB,KAAK,UAAU;AAAA,MAChC,cAAiB,KAAK,eAAe;AAAA,MACrC,aAAiB,KAAK,cAAc;AAAA,MACpC,aAAiB,KAAK,cAAc;AAAA,MACpC;AAAA,MACA,iBAAiB,kBAAkB;AAAA,MACnC,eAAiB,oBAAI,KAAK,GAAE,YAAY;AAAA,IAC1C;AAAA,EACF;AAAA,EAEA,MAAc,OAAO,MAAY,SAA6C;AAC5E,UAAM,WAAY,oBAAI,IAA2B;AACjD,UAAM,SAAY,oBAAI,IAAY;AAClC,UAAM,WAAY,oBAAI,IAAoB;AAC1C,UAAM,UAAqB,CAAC;AAE5B,UAAM,YAAY,MAChB,KAAK;AAAA,MACH,CAAC,EAAE,KAAK,OAAO,WAAW,WAAW,MACnC,MAAM,KAAK,SAAS,iBAAiB,GAAG,CAAC,EACtC;AAAA,QAAI,QACH,GAAG,aAAa,KAAK,KACrB,GAAG,aAAa,SAAS,KACxB,GAAG,cAAc,UAAU,GAA0B,WAAW,KAAK,KACtE;AAAA,MACF,EACC,OAAO,OAAO;AAAA,MACnB,EAAE,KAAK,aAAa,MAAM,OAAO,aAAa,WAAW,WAAW,aAAa,eAAe,YAAY,aAAa,eAAe;AAAA,IAC1I;AAEF,UAAM,WAAqB,CAAC;AAC5B,UAAM,YAAsB,CAAC;AAE7B,aAAS,QAAQ,GAAG,QAAQ,QAAQ,OAAO,SAAS;AAClD,WAAK,SAAS,QAAQ,QAAQ,CAAC;AAE/B,UAAI,OAAO,QAAQ,QAAQ,aAAc;AAEzC,YAAM,WAAW,MAAM,UAAU;AACjC,UAAI,SAAS,UAAU,QAAQ,aAAc;AAE7C,YAAM,kBAAkB,MAAM,KAAK;AAAA,QACjC,GAAG,aAAa,IAAI,SAAS,aAAa,aAAa;AAAA,MACzD;AACA,UAAI,gBAAgB,WAAW,EAAG;AAElC,iBAAW,QAAQ,iBAAiB;AAClC,YAAI;AACF,gBAAM,KAAK,uBAAuB;AAClC,gBAAM,KAAK,MAAM,EAAE,OAAO,KAAK,CAAC;AAChC,gBAAM,KAAK,eAAe,GAAG;AAAA,QAC/B,QAAQ;AAAA,QAAE;AAAA,MACZ;AACA,YAAM,KAAK,eAAe,IAAI;AAE9B,YAAM,UAAU,MAAM,UAAU;AAChC,YAAM,QAAU,QAAQ,MAAM,SAAS,MAAM;AAE7C,YAAM,UAAU,MAAM,OAAO,OAAK,OAAO,IAAI,CAAC,CAAC,EAAE;AACjD,YAAM,UAAU,MAAM,SAAS,IAAI,UAAU,MAAM,SAAS;AAC5D,eAAS,KAAK,OAAO;AACrB,UAAI,SAAS,SAAS,EAAG,UAAS,MAAM;AACxC,YAAM,iBAAiB,SAAS,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC,IAAI,SAAS;AAEtE,iBAAW,KAAK,SAAS;AACvB,YAAI,CAAC,OAAO,IAAI,CAAC,GAAG;AAAE,iBAAO,IAAI,CAAC;AAAG,oBAAU,KAAK,CAAC;AAAA,QAAE;AACvD,YAAI,CAAC,SAAS,IAAI,CAAC,EAAG,UAAS,IAAI,GAAG,QAAQ,CAAC;AAAA,MACjD;AAEA,UAAI,QAAQ,WAAW,SAAS,OAAQ;AACxC,UAAI,kBAAkB,IAAK;AAAA,IAC7B;AAEA,UAAM,UAAU,IAAI,KAAK,MAAM,KAAK,oBAAoB,IAAI,GAAG,IAAI,OAAK,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC;AAExF,eAAW,KAAK,WAAW;AACzB,UAAI,QAAQ,UAAU,QAAQ,aAAc;AAC5C,YAAM,MAAM,KAAK,kBAAkB,CAAC;AACpC,UAAI,SAAS,IAAI,GAAG,EAAG;AACvB,eAAS,IAAI,GAAG;AAChB,YAAM,IAAI,SAAS,IAAI,CAAC,KAAK;AAC7B,YAAM,OAAO,QAAQ,IAAI,CAAC;AAC1B,UAAI,MAAM;AACR,gBAAQ,KAAK,KAAK,UAAU,MAAM,GAAG,MAAM,QAAQ,KAAK,CAAC;AACzD,aAAK,SAAS,WAAW,EAAE,UAAU,KAAK,UAAU,QAAQ,KAAK,UAAU,MAAM,aAAa,KAAK,eAAe,MAAM,YAAY,KAAK,cAAc,MAAM,YAAY,KAAK,cAAc,MAAM,OAAO,GAAG,gBAAgB,MAAM,UAAU,CAAC,EAAE,CAAC;AAAA,MAClP,OAAO;AACL,gBAAQ,KAAK,KAAK,UAAU,EAAE,UAAU,GAAG,QAAQ,QAAW,aAAa,QAAW,YAAY,QAAW,YAAY,OAAU,GAAG,GAAG,MAAM,QAAQ,KAAK,CAAC;AAAA,MAC/J;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,cAAc,MAAoC;AAC9D,UAAM,QAAQ;AACd,WAAO,KAAK,SAAS,CAAC,SAAS;AAC7B,YAAM,UAAqI,CAAC;AAC5I,YAAM,aAAa,MAAM,KAAK,SAAS,iBAAiB,KAAK,SAAS,CAAC;AACvE,iBAAW,aAAa,YAAY;AAClC,cAAM,YAAY,UAAU,cAAc,KAAK,cAAc;AAC7D,cAAM,cAAc,WAAW,aAAa,KAAK,KAAK;AACtD,cAAM,OAAgC,YAAY,YAAY,EAAE,SAAS,OAAO,IAAI,gBAAgB;AACpG,cAAM,QAAQ,MAAM,KAAK,UAAU,iBAAiB,KAAK,IAAI,CAAC;AAC9D,mBAAW,KAAK,OAAO;AACrB,gBAAM,OAAQ,EAAwB;AACtC,cAAI,CAAC,QAAS,CAAC,KAAK,SAAS,SAAS,KAAK,CAAC,KAAK,SAAS,UAAU,EAAI;AACxE,gBAAM,MAAM,EAAE,aAAa,KAAK,KAAK;AACrC,gBAAM,QAAQ,IAAI,QAAQ,SAAS;AACnC,cAAI,UAAU,GAAI;AAClB,gBAAM,QAAQ,IAAI,MAAM,GAAG,KAAK,EAAE,KAAK;AACvC,gBAAM,YAAY,IAAI,MAAM,QAAQ,CAAC,EAAE,QAAQ,YAAY,EAAE;AAC7D,gBAAM,eAAe,UAAU,MAAM,YAAY;AACjD,gBAAM,UAAU,eAAe,aAAa,CAAC,EAAE,KAAK,IAAI;AACxD,cAAI,MAAO,SAAQ,KAAK,EAAE,MAAM,OAAO,SAAS,UAAU,WAAW,UAAU,IAAI,KAAK,KAAK,CAAC;AAAA,QAChG;AAAA,MACF;AACA,aAAO;AAAA,IACT,GAAG,KAAK;AAAA,EACV;AAAA,EAEA,MAAc,cAAc,MAAoC;AAC9D,UAAM,QAAQ;AACd,WAAO,KAAK,SAAS,CAAC,SAAS;AAC7B,YAAM,UAAiE,CAAC;AACxE,YAAM,WAAW,MAAM,KAAK,SAAS,iBAAiB,KAAK,OAAO,CAAC;AACnE,YAAM,eAAe,SAAS,KAAK,CAAC,MAAM,EAAE,aAAa,SAAS,aAAa,CAAC;AAChF,UAAI,CAAC,aAAc,QAAO;AAC1B,YAAM,QAAQ,MAAM,KAAK,aAAa,iBAAiB,KAAK,IAAI,CAAC;AACjE,iBAAW,KAAK,OAAO;AACrB,cAAM,OAAQ,EAAwB;AACtC,YAAI,CAAC,KAAM;AACX,cAAM,UAAU,EAAE,cAAc,KAAK,KAAK;AAC1C,cAAM,WAAW,EAAE,cAAc,KAAK,MAAM;AAC5C,cAAM,QAAQ,SAAS,aAAa,KAAK,KAAK;AAC9C,cAAM,SAAS,UAAU,aAAa,KAAK,KAAK;AAChD,YAAI,MAAO,SAAQ,KAAK,EAAE,OAAO,QAAQ,KAAK,KAAK,CAAC;AAAA,MACtD;AACA,aAAO;AAAA,IACT,GAAG,KAAK;AAAA,EACV;AAAA,EAEA,MAAc,mBAAmB,MAAY,UAA0C;AACrF,QAAI;AACF,YAAM,KAAK,KAAK,UAAU,EAAE,WAAW,mBAAmB,CAAC;AAC3D,YAAM,KAAK,eAAe,IAAI;AAAA,IAChC,QAAQ;AACN,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,SAAS;AAAA,MACb,MAAW,oBAAoB;AAAA,MAC/B,WAAW,CAAC,GAAG,oBAAoB,SAAS;AAAA,IAC9C;AAEA,UAAM,MAAM,MAAM,KAAK,SAAS,CAAC,SAAS;AACxC,YAAM,OAAO,oBAAI,IAAY;AAC7B,YAAM,UAAsG,CAAC;AAC7G,YAAM,QAAQ,MAAM,KAAK,SAAS,iBAAiB,KAAK,IAAI,CAAC;AAE7D,YAAM,aAAa,CAAC,eAAe,YAAY,cAAc,iBAAiB,gBAAgB,UAAU;AAExG,YAAM,SAAS,oBAAI,IAAsB;AACzC,iBAAW,KAAK,OAAO;AACrB,cAAM,OAAQ,EAAwB;AACtC,YAAI,CAAC,KAAM;AACX,YAAI,CAAC,WAAW,KAAK,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,EAAG;AAC/C,cAAM,OAAO,EAAE,aAAa,KAAK,KAAK;AACtC,YAAI,CAAC,OAAO,IAAI,IAAI,EAAG,QAAO,IAAI,MAAM,CAAC,CAAC;AAC1C,eAAO,IAAI,IAAI,EAAG,KAAK,IAAI;AAAA,MAC7B;AAEA,iBAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,GAAG;AAC5C,YAAI,KAAK,IAAI,IAAI,EAAG;AACpB,aAAK,IAAI,IAAI;AAEb,cAAM,WAAW,MAAM,KAAK,CAAC,MAAM,YAAY,KAAK,CAAC,CAAC,KAAK;AAC3D,cAAM,YAAY,MAAM,KAAK,CAAC,MAAM,CAAC,YAAY,KAAK,CAAC,KAAK,EAAE,SAAS,CAAC,KAAK;AAC7E,YAAI,CAAC,UAAW;AAEhB,YAAI,QAAQ;AACZ,YAAI,WAAW;AACf,YAAI,UAAU;AAEd,mBAAW,KAAK,KAAK,WAAW;AAC9B,cAAI,UAAU;AACd,cAAI,SAAS;AACb,iBAAO,MAAM;AACX,kBAAM,QAAQ,UAAU,QAAQ,GAAG,MAAM;AACzC,gBAAI,UAAU,GAAI;AAClB,sBAAU;AACV,qBAAS,QAAQ;AAAA,UACnB;AACA,cAAI,YAAY,GAAI;AACpB,gBAAM,QAAQ,UAAU,MAAM,UAAU,EAAE,MAAM;AAChD,gBAAM,cAAc,SAAS,KAAK,KAAK,KAAK,MAAM,KAAK,MAAM;AAC7D,cAAI,CAAC,YAAa;AAClB,kBAAQ,UAAU,MAAM,GAAG,OAAO,EAAE,KAAK;AACzC,qBAAW;AACX,gBAAM,WAAW,MAAM,QAAQ,WAAW,EAAE;AAC5C,gBAAM,SAAS,SAAS,QAAQ,MAAG;AACnC,qBAAW,WAAW,KAAK,WAAW,SAAS,MAAM,GAAG,MAAM,GAAG,KAAK;AACtE;AAAA,QACF;AAEA,YAAI,MAAO,SAAQ,KAAK,EAAE,OAAO,SAAS,UAAU,UAAU,KAAK,KAAK,CAAC;AAAA,MAC3E;AAEA,aAAO;AAAA,IACT,GAAG,MAAM;AAET,WAAO,IAAI,IAAI,CAAC,OAAO,EAAE,MAAM,eAAwB,GAAG,EAAE,EAAE;AAAA,EAChE;AAAA,EAEA,MAAc,wBAAwB,MAA6C;AACjF,UAAM,OAAO;AACb,WAAO,KAAK,SAAS,CAAC,MAAM;AAC1B,YAAM,UAAU,MAAM,KAAK,SAAS,iBAAiB,EAAE,UAAU,CAAC,EAC/D,KAAK,CAAC,OAAO,GAAG,aAAa,SAAS,EAAE,kBAAkB,CAAC,KACzD,SAAS,cAAc,uBAAuB;AAEnD,UAAI,CAAC,QAAS,QAAO,CAAC;AAEtB,aAAO,MAAM,KAAK,QAAQ,iBAAiB,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,SAAS;AAChE,cAAM,OAAO,KAAK,cAAc,EAAE,QAAQ;AAC1C,cAAM,MAAM,MAAM,QAAQ;AAE1B,cAAM,UAAU,KAAK,cAAc,EAAE,OAAO,GAAG,aAAa,KAAK;AACjE,cAAM,WAAW,KAAK,cAAc,EAAE,QAAQ,GAAG,aAAa,KAAK;AACnE,cAAM,QAAQ,WAAW,YAAY;AAErC,cAAM,aAAa,KAAK,cAAc,EAAE,MAAM,GAAG,aAAa,KAAK,KAAK;AACxE,cAAM,aAAa,KAAK,cAAc,EAAE,aAAa;AACrD,cAAM,eAAe,YAAY,aAAa,KAAK,KAAK;AAExD,cAAM,YAAY,KAAK,cAAc,EAAE,SAAS,GAAG,aAAa,KAAK,KAAK;AAC1E,cAAM,SAAY,KAAK,cAAc,EAAE,MAAM,GAAG,aAAa,KAAK,KAAK;AACvE,cAAM,aAAa,KAAK,cAAc,EAAE,UAAU,GAAG,aAAa,KAAK,KAAK;AAE5E,cAAM,iBAAiB,KAAK,cAAc,EAAE,mBAAmB;AAC/D,YAAI,iBAAgC;AACpC,YAAI,gBAAgB;AAClB,cAAI,OAAO,eAAe;AAC1B,iBAAO,MAAM;AACX,kBAAM,IAAI,KAAK,aAAa,KAAK;AACjC,gBAAI,GAAG;AAAE,+BAAiB;AAAG;AAAA,YAAM;AACnC,mBAAO,KAAK;AAAA,UACd;AAAA,QACF;AAEA,cAAM,WAAW,MAAM,KAAK,KAAK,iBAAiB,MAAM,CAAC;AACzD,cAAM,WAAW,SAAS,KAAK,CAACC,OAAM,YAAY,KAAKA,GAAE,aAAa,KAAK,KAAK,EAAE,CAAC,GAAG,aAAa,KAAK,KAAK;AAC7G,cAAM,kBAAkB,SACrB,IAAI,CAACA,OAAMA,GAAE,aAAa,KAAK,KAAK,EAAE,EACtC;AAAA,UAAO,CAAC,MACP,KAAK,KAAK,CAAC,MACT,EAAE,SAAS,SAAS,KAAK,EAAE,SAAS,UAAU,KAC9C,EAAE,SAAS,MAAM,KAAK,EAAE,SAAS,MAAM,KAAK,EAAE,SAAS,OAAO;AAAA,QAElE;AACF,cAAM,aAAa,gBAAgB,CAAC,KAAK;AAEzC,cAAM,iBAAiB,SACpB,IAAI,CAACA,OAAMA,GAAE,aAAa,KAAK,KAAK,EAAE,EACtC,OAAO,CAAC,MAAM,uFAAuF,KAAK,CAAC,CAAC;AAC/G,cAAM,OAAO,WAAW,eAAe,CAAC,KAAK;AAE7C,cAAM,WAAW,iBAAiB,YAAY,YAAY;AAC1D,cAAM,SAAS,aAAa;AAE5B,YAAI,OAAwF;AAC5F,cAAM,KAAK,SAAS,YAAY;AAChC,cAAM,MAAM,OAAO,YAAY;AAC/B,cAAM,SAAS,WAAW,YAAY;AACtC,YAAI,GAAG,SAAS,QAAQ,KAAK,IAAI,WAAW,IAAI,EAAG,QAAO;AAAA,iBACjD,GAAG,SAAS,UAAU,KAAK,OAAO,SAAS,UAAU,EAAG,QAAO;AAAA,iBAC/D,GAAG,SAAS,WAAW,KAAK,OAAO,SAAS,WAAW,EAAG,QAAO;AAAA,iBACjE,GAAG,SAAS,QAAQ,KAAK,OAAO,SAAS,QAAQ,EAAG,QAAO;AAAA,iBAC3D,GAAG,SAAS,SAAS,KAAK,CAAC,CAAC,UAAW,QAAO;AAAA,YAClD,QAAO;AAEZ,eAAO,EAAE,MAAM,OAAO,KAAK,QAAQ,UAAU,gBAAgB,YAAY,MAAM,UAAU,WAAW;AAAA,MACtG,CAAC;AAAA,IACH,GAAG,IAAI;AAAA,EACT;AAAA,EAEA,MAAc,sBAAsB,MAAsC;AACxE,UAAM,OAAO;AACb,WAAO,KAAK,SAAS,CAAC,MAAM;AAC1B,YAAM,MAA2M,CAAC;AAClN,UAAI,MAAM;AACV,eAAS,iBAAiB,EAAE,MAAM,EAAE,QAAQ,UAAQ;AAClD,cAAM,UAAU,KAAK,cAAc,EAAE,KAAK;AAC1C,YAAI,CAAC,QAAS;AACd,cAAM,QAAQ,QAAQ,aAAa,KAAK,KAAK;AAC7C,cAAM,SAAS,QAAQ,QAAQ,GAAG;AAClC,cAAM,MAAM,QAAQ,QAAQ;AAC5B,YAAI,CAAC,SAAS,CAAC,IAAK;AACpB;AACA,cAAM,OAAW,KAAK,cAAc,EAAE,IAAI,GAAG,aAAa,KAAK,KAAK;AACpE,cAAM,UAAW,KAAK,cAAc,EAAE,OAAO,GAAG,aAAa,KAAK,KAAK;AACvE,cAAM,gBAAgB,CAAC,CAAC,KAAK,cAAc,EAAE,UAAU;AACvD,cAAM,WAAW,KAAK,cAAc,EAAE,UAAU;AAChD,cAAM,eAAe,WACjB,EAAE,OAAO,SAAS,cAAc,EAAE,WAAW,GAAG,aAAa,KAAK,KAAK,IAAI,OAAO,SAAS,cAAc,EAAE,WAAW,GAAG,aAAa,KAAK,KAAK,GAAG,IACnJ;AACJ,YAAI,SAAS;AACb,YAAI;AAAE,mBAAS,IAAI,IAAI,GAAG,EAAE,SAAS,QAAQ,UAAU,EAAE;AAAA,QAAE,QAAQ;AAAE,mBAAS,KAAK,cAAc,EAAE,QAAQ,GAAG,aAAa,KAAK,KAAK;AAAA,QAAG;AACxI,YAAI,KAAK,EAAE,UAAU,KAAK,OAAO,KAAK,QAAQ,MAAM,SAAS,eAAe,aAAa,CAAC;AAAA,MAC5F,CAAC;AACD,aAAO;AAAA,IACT,GAAG,IAAI;AAAA,EACT;AAAA,EAEA,MAAc,iBAAiB,MAA0C;AACvE,UAAM,OAAO;AACb,WAAO,KAAK,SAAS,CAAC,MAAM;AAC1B,YAAM,MAAqM,CAAC;AAC5M,UAAI,YAA4B;AAChC,eAAS,iBAAiB,kBAAkB,EAAE,QAAQ,OAAK;AACzD,YAAI,CAAC,aAAa,EAAE,aAAa,SAAS,EAAE,WAAW,EAAG,aAAY,EAAE,QAAQ,cAAc;AAAA,MAChG,CAAC;AACD,UAAI,CAAC,UAAW,QAAO;AACtB,MAAC,UAAsB,iBAAiB,EAAE,IAAI,EAAE,QAAQ,CAAC,MAAM,MAAM;AACpE,cAAM,OAAO,KAAK,cAAc,EAAE,IAAI,GAAG,aAAa,KAAK,KAAK;AAChE,YAAI,CAAC,KAAM;AACX,cAAM,SAAa,KAAK,cAAc,EAAE,WAAW,GAAG,aAAa,KAAK,KAAK;AAC7E,cAAM,YAAa,KAAK,cAAc,EAAE,WAAW,GAAG,aAAa,KAAK,KAAK;AAC7E,cAAM,cAAc,YAAY,UAAU,QAAQ,SAAS,EAAE,EAAE,KAAK,IAAI;AACxE,YAAI,MAAO,KAAK,cAAc,aAAa,GAAgC,aAAa,UAAU,KAAK;AACvG,YAAI,CAAC,KAAK;AACR,qBAAW,QAAQ,MAAM,KAAK,KAAK,iBAAiB,SAAS,CAAC,GAA0B;AACtF,kBAAM,KAAK,KAAK,KAAK,MAAM,eAAe;AAC1C,gBAAI,IAAI;AAAE,oBAAM,GAAG,CAAC;AAAG;AAAA,YAAM;AAC7B,kBAAM,KAAK,KAAK,KAAK,MAAM,+BAA+B;AAC1D,gBAAI,IAAI;AAAE,kBAAI;AAAE,sBAAM,OAAO,OAAO,GAAG,CAAC,CAAC,EAAE,SAAS;AAAA,cAAE,QAAQ;AAAA,cAAE;AAAE,kBAAI,IAAK;AAAA,YAAM;AAAA,UACnF;AAAA,QACF;AACA,cAAM,WAAqB,CAAC;AAC5B,aAAK,iBAAiB,WAAW,EAAE,QAAQ,QAAM;AAC/C,gBAAM,OAAO,MAAM,KAAK,GAAG,UAAU,EAClC,OAAO,OAAK,EAAE,aAAa,CAAC,EAC5B,IAAI,OAAK,EAAE,aAAa,KAAK,KAAK,EAAE,EACpC,OAAO,OAAK,EAAE,SAAS,KAAK,EAAE,SAAS,GAAG,EAC1C,KAAK,GAAG;AACX,cAAI,QAAQ,CAAC,SAAS,SAAS,IAAI,EAAG,UAAS,KAAK,IAAI;AAAA,QAC1D,CAAC;AACD,cAAM,QAAQ,MAAM,KAAK,KAAK,iBAAiB,SAAS,CAAC;AACzD,cAAM,gBAAgB,MAAM,KAAK,OAAK,EAAE,KAAK,SAAS,iBAAiB,CAAC,GAAG,QAAQ;AACnF,cAAM,aAAgB,MAAM,KAAK,OAAK,CAAC,EAAE,KAAK,SAAS,YAAY,KAAK,EAAE,KAAK,WAAW,MAAM,CAAC,GAAG,QAAQ;AAC5G,YAAI,KAAK,EAAE,UAAU,IAAI,GAAG,MAAM,KAAK,QAAQ,aAAa,UAAU,YAAY,cAAc,CAAC;AAAA,MACnG,CAAC;AACD,aAAO;AAAA,IACT,GAAG,IAAI;AAAA,EACT;AAAA,EAEA,MAAc,iBAAiB,MAAgC;AAC7D,WAAO,KAAK,SAAS,MAAM;AACzB,YAAM,QAAQ,oBAAI,IAAY;AAC9B,YAAM,OAAQ,oBAAI,IAAY;AAC9B,YAAM,QAAQ,oBAAI,IAAY;AAC9B,YAAM,YAAY,oBAAI,IAA4F;AAElH,eAAS,gBAAgB,IAAqB;AAC5C,cAAM,MAAM,CAAC,WAAW,WAAW,WAAW,oBAAoB,IAAI;AACtE,mBAAW,KAAK,KAAK;AACnB,gBAAM,QAAQ,GAAG,cAAc,CAAC;AAChC,cAAI,OAAO,aAAa,KAAK,EAAG,QAAO,MAAM,YAAY,KAAK;AAAA,QAChE;AACA,eAAO;AAAA,MACT;AAEA,eAAS,iBAAiB,gBAAgB,EAAE,QAAQ,aAAW;AAC7D,cAAM,MAAM,QAAQ,aAAa,IAAI;AACrC,YAAI,CAAC,IAAK;AACV,cAAM,OAAO,IAAI,QAAQ,OAAO,EAAE;AAClC,cAAM,IAAI,IAAI;AACd,cAAM,OAAO,gBAAgB,OAAO;AACpC,cAAM,QAAQ,QAAQ,cAAc,aAAa;AACjD,cAAM,MAAM,OAAO,aAAa,UAAU,KAAK;AAC/C,YAAI,IAAK,MAAK,IAAI,GAAG;AACrB,YAAI,KAAM,WAAU,IAAI,MAAM,EAAE,MAAM,MAAM,KAAK,MAAM,KAAK,CAAC;AAAA,MAC/D,CAAC;AAED,eAAS,iBAAiB,YAAY,EAAE,QAAQ,QAAM;AACpD,cAAM,MAAM,GAAG,aAAa,UAAU;AACtC,YAAI,CAAC,KAAK,WAAW,KAAK,EAAG;AAC7B,cAAM,IAAI,GAAG;AACb,YAAI,CAAC,UAAU,IAAI,GAAG,GAAG;AACvB,gBAAM,OAAO,gBAAgB,EAAE;AAC/B,cAAI,KAAM,WAAU,IAAI,KAAK,EAAE,MAAM,MAAM,KAAK,KAAK,MAAM,MAAM,KAAK,CAAC;AAAA,QACzE;AAAA,MACF,CAAC;AAED,eAAS,iBAAiB,SAAS,EAAE,QAAQ,UAAQ;AACnD,cAAM,QAAQ,KAAK,cAAc,aAAa;AAC9C,cAAM,MAAM,OAAO,aAAa,UAAU,KAAK;AAC/C,YAAI,CAAC,IAAK;AACV,aAAK,IAAI,GAAG;AACZ,cAAM,OAAO,KAAK,cAAc,SAAS,GAAG,aAAa,KAAK,KAAK;AACnE,YAAI,CAAC,KAAM;AACX,cAAM,SAAS,KAAK,cAAc,gBAAgB;AAClD,cAAM,OAAO,SAAS,OAAO,aAAa,IAAI,EAAG,QAAQ,OAAO,EAAE,IAAI;AACtE,cAAM,MAAM,QAAQ,OAAO,GAAG;AAC9B,YAAI,UAAU,IAAI,GAAG,GAAG;AACtB,gBAAM,WAAW,UAAU,IAAI,GAAG;AAClC,cAAI,CAAC,SAAS,IAAK,WAAU,IAAI,KAAK,EAAE,GAAG,UAAU,IAAI,CAAC;AAAA,QAC5D,OAAO;AACL,oBAAU,IAAI,KAAK,EAAE,MAAM,MAAM,KAAK,MAAM,KAAK,CAAC;AAAA,QACpD;AAAA,MACF,CAAC;AAED,eAAS,iBAAiB,aAAa,EAAE,QAAQ,QAAM;AACrD,cAAM,MAAM,GAAG,aAAa,UAAU;AACtC,YAAI,CAAC,IAAK;AACV,aAAK,IAAI,GAAG;AACZ,cAAM,eAAe,CAAC,GAAG,UAAU,OAAO,CAAC,EAAE,KAAK,OAAK,EAAE,QAAQ,GAAG;AACpE,YAAI,CAAC,cAAc;AACjB,cAAI,OAAuB,GAAG;AAC9B,cAAI,OAAO;AACX,mBAAS,IAAI,GAAG,IAAI,KAAK,MAAM,KAAK;AAClC,kBAAM,IAAI,KAAK,cAAc,wCAAwC;AACrE,gBAAI,GAAG,aAAa,KAAK,GAAG;AAAE,qBAAO,EAAE,YAAY,KAAK;AAAG;AAAA,YAAM;AACjE,mBAAO,KAAK;AAAA,UACd;AACA,cAAI,KAAM,WAAU,IAAI,OAAO,GAAG,IAAI,EAAE,MAAM,MAAM,MAAM,KAAK,MAAM,KAAK,CAAC;AAAA,QAC7E;AAAA,MACF,CAAC;AAED,YAAM,gBAAgB,MAAM,KAAK,SAAS,iBAAiB,mBAAmB,CAAC,EAC5E,IAAI,OAAK,EAAE,eAAe,EAAE,EAC5B,OAAO,OAAK,EAAE,SAAS,GAAM,EAC7B,KAAK,IAAI;AAEZ,iBAAW,KAAK,cAAc,SAAS,2BAA2B,EAAG,OAAM,IAAI,EAAE,CAAC,CAAC;AACnF,iBAAW,KAAK,cAAc,SAAS,qBAAqB,EAAU,OAAM,IAAI,EAAE,CAAC,CAAC;AACpF,iBAAW,KAAK,cAAc,SAAS,6BAA6B,GAAG;AACrE,YAAI;AAAE,eAAK,IAAI,OAAO,OAAO,EAAE,CAAC,CAAC,EAAE,SAAS,CAAC;AAAA,QAAE,QAAQ;AAAA,QAAE;AAAA,MAC3D;AAEA,aAAO,EAAE,UAAU,CAAC,GAAG,UAAU,OAAO,CAAC,GAAG,OAAO,CAAC,GAAG,KAAK,GAAG,MAAM,CAAC,GAAG,IAAI,GAAG,OAAO,CAAC,GAAG,KAAK,EAAE;AAAA,IACpG,CAAC;AAAA,EACH;AAAA,EAEQ,2BAA2B,WAAsB,WAA2C;AAClG,UAAM,SAAS,IAAI,IAAY,UAAU,IAAI;AAC7C,UAAM,UAAU,UAAU,SAAS,IAAI,QAAM,EAAE,GAAG,EAAE,EAAE;AAEtD,eAAW,OAAO,WAAW;AAC3B,UAAI,CAAC,IAAI,IAAK;AACd,aAAO,IAAI,IAAI,GAAG;AAClB,YAAM,WAAW,IAAI,KAAK,YAAY,EAAE,KAAK;AAC7C,YAAM,SAAS,QAAQ,KAAK,OAAK,EAAE,KAAK,YAAY,EAAE,KAAK,MAAM,QAAQ;AACzE,UAAI,QAAQ;AACV,YAAI,CAAC,OAAO,IAAK,QAAO,MAAM,IAAI;AAAA,MACpC,WAAW,CAAC,QAAQ,KAAK,OAAK,EAAE,QAAQ,IAAI,GAAG,GAAG;AAChD,gBAAQ,KAAK,EAAE,MAAM,IAAI,MAAM,MAAM,MAAM,KAAK,IAAI,KAAK,MAAM,KAAK,CAAC;AAAA,MACvE;AAAA,IACF;AAEA,WAAO,EAAE,GAAG,WAAW,UAAU,SAAS,MAAM,CAAC,GAAG,MAAM,EAAE;AAAA,EAC9D;AAAA,EAEA,MAAc,kBAAkB,MAI7B;AACD,UAAM,UAAU;AAChB,UAAM,UAAU;AAEhB,WAAO,KAAK,SAAS,CAAC,EAAE,KAAK,IAAI,MAAM;AACrC,YAAM,KAAc,OAAmD,QAAQ,MAAM;AACrF,YAAM,UACJ,OAAO,QAAQ,QAAQ,OAAO,QAAQ,QAAQ;AAEhD,eAAS,cAA8B;AACrC,cAAM,UAAU,SAAS,cAAc,IAAI,IAAI;AAC/C,YAAI,QAAS,QAAO;AACpB,cAAM,WAAW,SAAS,iBAAiB,8BAA8B;AACzE,mBAAW,KAAK,UAAU;AACxB,cAAI,EAAE,aAAa,KAAK,MAAM,eAAe;AAC3C,gBAAI,KAAqB,EAAE;AAC3B,qBAAS,IAAI,GAAG,IAAI,KAAK,IAAI,KAAK;AAChC,kBAAI,GAAG,iBAAiB,GAAG,EAAE,SAAS,EAAG,QAAO;AAChD,mBAAK,GAAG;AAAA,YACV;AACA,mBAAO,EAAE;AAAA,UACX;AAAA,QACF;AACA,eAAO;AAAA,MACT;AAEA,YAAM,UAAU,YAAY;AAC5B,YAAM,eAAe,UAAW,QAAQ,QAAQ,IAAI,OAAO,KAAK,UAAW;AAE3E,UAAI,UAAyB;AAC7B,UAAI,cAAc;AAChB,cAAM,QAAQ,aAAa,UAAU,IAAI;AACzC,cAAM,iBAAiB,uBAAuB,EAAE,QAAQ,CAAC,OAAO,GAAG,OAAO,CAAC;AAC3E,cAAM,iBAAiB,8BAA8B,EAAE,QAAQ,CAAC,OAAO,GAAG,OAAO,CAAC;AAClF,cAAM,iBAAiB,wBAAwB,EAAE,QAAQ,CAAC,OAAO,GAAG,OAAO,CAAC;AAC5E,cAAM,iBAAiB,GAAG,EAAE,QAAQ,CAAC,OAAO,GAAG,OAAO,CAAC;AACvD,cAAM,YAAY,MAAM,aAAa,QAAQ,QAAQ,GAAG,EAAE,KAAK,KAAK;AACpE,cAAM,eAAe,CAAC,aACpB,0CAA0C,KAAK,SAAS;AAC1D,kBAAU,eAAe,OAAO;AAAA,MAClC;AAEA,YAAM,cAAc,CAAC,CAAC,WAAW,YAAY;AAE7C,YAAM,eAAe,MAAM,KAAK,cAAc,iBAAiB,SAAS,KAAK,CAAC,CAAC,EAC5E,OAAO,CAAC,MAAO,EAAwB,QAAQ,CAAE,EAAwB,KAAK,WAAW,YAAY,CAAC,EACtG,IAAI,CAAC,OAAO;AAAA,QACX,MAAO,EAAwB,aAAa,KAAK,KAAK;AAAA,QACtD,MAAO,EAAwB;AAAA,MACjC,EAAE,EACD,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI;AAEjC,YAAM,UAAU,SAAS,cAAc,IAAI,IAAI;AAC/C,YAAM,cAAc,YAAY,SAAS,CAAC,CAAC;AAC3C,YAAM,eAAe,SAAS,QAAQ,IAAI,OAAO,KAAK;AAEtD,UAAI,UAAyB;AAC7B,UAAI,cAAc;AAChB,cAAM,QAAQ,aAAa,UAAU,IAAI;AACzC,cAAM,iBAAiB,uBAAuB,EAAE,QAAQ,CAAC,OAAO,GAAG,OAAO,CAAC;AAC3E,cAAM,iBAAiB,8BAA8B,EAAE,QAAQ,CAAC,OAAO,GAAG,OAAO,CAAC;AAClF,cAAM,iBAAiB,wBAAwB,EAAE,QAAQ,CAAC,OAAO,GAAG,OAAO,CAAC;AAC5E,cAAM,iBAAiB,GAAG,EAAE,QAAQ,CAAC,OAAO,GAAG,OAAO,CAAC;AACvD,cAAM,YAAY,MAAM,aAAa,QAAQ,QAAQ,GAAG,EAAE,KAAK,KAAK;AACpE,cAAM,eAAe,CAAC,aACpB,0CAA0C,KAAK,SAAS;AAC1D,kBAAU,eAAe,OAAO;AAAA,MAClC;AAEA,YAAM,eAAe,cACjB,MAAM,KAAK,cAAc,iBAAiB,SAAS,KAAK,CAAC,CAAC,EACvD,OAAO,CAAC,MAAO,EAAwB,QAAQ,CAAE,EAAwB,KAAK,WAAW,YAAY,CAAC,EACtG,IAAI,CAAC,OAAO;AAAA,QACX,MAAO,EAAwB,aAAa,KAAK,KAAK;AAAA,QACtD,MAAO,EAAwB;AAAA,MACjC,EAAE,EACD,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,IACjC,CAAC;AAEL,aAAO;AAAA,QACL;AAAA,QACA,YAAY,EAAE,UAAU,aAAa,MAAM,SAAS,WAAW,aAAa;AAAA,QAC5E,QAAY,EAAE,UAAU,aAAa,MAAM,SAAU,WAAW,aAAa;AAAA,MAC/E;AAAA,IACF,GAAG,EAAE,KAAK,SAAS,KAAK,QAAQ,CAAC;AAAA,EACnC;AAAA,EAEQ,UAAU,MAAiB,OAA0B;AAC3D,UAAM,QAAmB,CAAC;AAC1B,UAAM,UAAU,oBAAI,IAAqB;AAEzC,eAAW,OAAO,MAAM;AACtB,YAAM,OAAgB;AAAA,QACpB,UAAgB,IAAI;AAAA,QACpB,QAAgB,IAAI,UAAU;AAAA,QAC9B,aAAgB,IAAI,gBAAgB;AAAA,QACpC,YAAgB,IAAI,eAAe;AAAA,QACnC,YAAgB,IAAI,eAAe;AAAA,QACnC,OAAgB,IAAI;AAAA,QACpB,gBAAgB,IAAI,mBAAmB;AAAA,QACvC,UAAgB,CAAC;AAAA,MACnB;AACA,cAAQ,IAAI,IAAI,UAAU,IAAI;AAAA,IAChC;AAEA,eAAW,QAAQ,QAAQ,OAAO,GAAG;AACnC,UAAI,KAAK,kBAAkB,QAAQ,IAAI,KAAK,cAAc,GAAG;AAC3D,gBAAQ,IAAI,KAAK,cAAc,EAAG,SAAS,KAAK,IAAI;AAAA,MACtD,OAAO;AACL,cAAM,KAAK,IAAI;AAAA,MACjB;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,QAAQ,SAAiD;AAC7D,UAAM,UAAU,KAAK,IAAI;AACzB,UAAM,SAAuB;AAAA,MAC3B,UAAe,QAAQ;AAAA,MACvB,YAAe,QAAQ;AAAA,MACvB,OAAe,QAAQ;AAAA,MACvB,cAAe,QAAQ;AAAA,MACvB,eAAe,QAAQ;AAAA,MACvB,UAAe,EAAE,OAAO,MAAM,QAAQ,IAAI;AAAA,MAC1C,QAAe,GAAG,QAAQ,EAAE,IAAI,QAAQ,GAAG,YAAY,CAAC;AAAA,IAC1D;AAEA,QAAI,aAAa;AAEjB,QAAI;AACF,YAAM,KAAK,OAAO,OAAO,MAAM;AAC/B,YAAM,OAAO,QAAQ,WAAW,WAAW,kBAAkB,QAAQ,QAAQ,CAAC,IAAI;AAClF,YAAM,EAAE,OAAO,IAAI,MAAM,KAAK,OAAO,eAAe,QAAQ,OAAO,MAAM,QAAQ,IAAI,QAAQ,EAAE;AAE/F,YAAM,OAAO,KAAK,OAAO,QAAQ;AAEjC,UAAI,QAAQ,UAAU;AACpB,cAAM,CAACC,iBAAgBC,YAAWC,aAAY,IAAI,MAAM,QAAQ,IAAI;AAAA,UAClE,KAAK,sBAAsB,IAAI;AAAA,UAC/B,KAAK,iBAAiB,IAAI;AAAA,UAC1B,KAAK,iBAAiB,IAAI;AAAA,QAC5B,CAAC;AACD,cAAMC,aAAY,KAAK,2BAA2BD,eAAcD,UAAS;AACzE,YAAIG,cAAaJ;AACjB,aAAK,QAAQ,SAAS,MAAM,GAAG;AAC7B,gBAAM,WAAW,IAAI,gBAAgB,EAAE,GAAG,QAAQ,OAAO,IAAI,QAAQ,IAAI,IAAI,QAAQ,IAAI,OAAO,KAAK,CAAC;AACtG,cAAI,KAAM,UAAS,IAAI,QAAQ,IAAI;AACnC,gBAAM,KAAK,OAAO,WAAW,mCAAmC,SAAS,SAAS,CAAC;AACnF,gBAAM,YAAY,MAAM,KAAK,sBAAsB,IAAI;AACvD,UAAAI,cAAa,CAAC,GAAGJ,iBAAgB,GAAG,UAAU,IAAI,QAAM,EAAE,GAAG,GAAG,UAAU,EAAE,WAAW,GAAG,EAAE,CAAC;AAAA,QAC/F;AACA,cAAMK,SAAsB;AAAA,UAC1B,MAAM,QAAQ;AAAA,UAAO,gBAAgB;AAAA,UAAG,iBAAiB;AAAA,UACzD,YAAY,KAAK,IAAI,IAAI;AAAA,UAAS;AAAA,QACpC;AACA,aAAK,SAAS,WAAWA,MAAK;AAC9B,eAAO;AAAA,UACL,MAAM,QAAQ;AAAA,UAAO,UAAU,QAAQ,YAAY;AAAA,UACnD,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,UAAG,gBAAgB;AAAA,UACvD,SAAS;AAAA,UACT,YAAY,EAAE,UAAU,OAAO,MAAM,MAAM,WAAW,CAAC,EAAE;AAAA,UACzD,QAAY,EAAE,UAAU,OAAO,MAAM,MAAM,WAAW,CAAC,EAAE;AAAA,UACzD,kBAAkB,CAAC;AAAA,UAAG,MAAM,CAAC;AAAA,UAAG,MAAM,CAAC;AAAA,UAAG,QAAQ,CAAC;AAAA,UAAG,QAAQ,CAAC;AAAA,UAC/D,gBAAgBD;AAAA,UAAY,WAAAH;AAAA,UAAW,WAAAE;AAAA,UAAW,OAAAE;AAAA,QACpD;AAAA,MACF;AAEA,YAAM,CAAC,QAAQ,QAAQ,kBAAkB,cAAc,gBAAgB,SAAS,IAAI,MAAM,QAAQ,IAAI;AAAA,QACpG,KAAK,cAAc,IAAI;AAAA,QACvB,KAAK,cAAc,IAAI;AAAA,QACvB,KAAK,wBAAwB,IAAI;AAAA,QACjC,KAAK,iBAAiB,IAAI;AAAA,QAC1B,KAAK,sBAAsB,IAAI;AAAA,QAC/B,KAAK,iBAAiB,IAAI;AAAA,MAC5B,CAAC;AACD,YAAM,YAAY,KAAK,2BAA2B,cAAc,SAAS;AACzE,WAAK,SAAS,SAAS,MAAM;AAC7B,WAAK,SAAS,SAAS,MAAM;AAE7B,UAAI,CAAC,QAAQ;AACX,YAAI,eAAe;AACnB,aAAK,QAAQ,SAAS,MAAM,GAAG;AAC7B,gBAAM,WAAW,IAAI,gBAAgB,EAAE,GAAG,QAAQ,OAAO,IAAI,QAAQ,IAAI,IAAI,QAAQ,IAAI,OAAO,KAAK,CAAC;AACtG,cAAI,KAAM,UAAS,IAAI,QAAQ,IAAI;AACnC,gBAAM,KAAK,OAAO,WAAW,mCAAmC,SAAS,SAAS,CAAC;AACnF,gBAAM,YAAY,MAAM,KAAK,sBAAsB,IAAI;AACvD,yBAAe,CAAC,GAAG,gBAAgB,GAAG,UAAU,IAAI,QAAM,EAAE,GAAG,GAAG,UAAU,EAAE,WAAW,GAAG,EAAE,CAAC;AAAA,QACjG;AACA,cAAMC,cAAa,MAAM,KAAK,kBAAkB,IAAI;AACpD,cAAMD,SAAsB;AAAA,UAC1B,MAAM,QAAQ;AAAA,UAAO,gBAAgB;AAAA,UAAG,iBAAiB;AAAA,UACzD,YAAY,KAAK,IAAI,IAAI;AAAA,UAAS;AAAA,QACpC;AACA,aAAK,SAAS,WAAWA,MAAK;AAC9B,eAAO;AAAA,UACL,MAAM,QAAQ;AAAA,UAAO,UAAU,QAAQ,YAAY;AAAA,UACnD,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,UAAG,gBAAgB;AAAA,UACvD,SAASC,YAAW;AAAA,UACpB,YAAYA,YAAW;AAAA,UACvB,QAAQA,YAAW;AAAA,UACnB;AAAA,UAAkB,MAAM,CAAC;AAAA,UAAG,MAAM,CAAC;AAAA,UAAG;AAAA,UAAQ;AAAA,UAC9C,gBAAgB;AAAA,UAAc;AAAA,UAAW;AAAA,UAAW,OAAAD;AAAA,QACtD;AAAA,MACF;AAEA,YAAM,OAAO,MAAM,KAAK,OAAO,MAAM,OAAO;AAC5C,YAAM,aAAa,MAAM,KAAK,kBAAkB,IAAI;AAEpD,YAAM,kBAAkB,IAAI,gBAAgB,EAAE,GAAG,QAAQ,OAAO,IAAI,QAAQ,IAAI,IAAI,QAAQ,IAAI,KAAK,oBAAoB,IAAI,CAAC;AAC9H,UAAI,KAAM,iBAAgB,IAAI,QAAQ,IAAI;AAC1C,YAAM,cAAc,MAAM,KAAK,mBAAmB,MAAM,mCAAmC,gBAAgB,SAAS,CAAC;AACrH,WAAK,SAAS,SAAS,WAAW;AAElC,UAAI,aAAa;AACjB,WAAK,QAAQ,SAAS,MAAM,GAAG;AAC7B,cAAM,WAAW,IAAI,gBAAgB,EAAE,GAAG,QAAQ,OAAO,IAAI,QAAQ,IAAI,IAAI,QAAQ,IAAI,OAAO,KAAK,CAAC;AACtG,YAAI,KAAM,UAAS,IAAI,QAAQ,IAAI;AACnC,cAAM,KAAK,OAAO,WAAW,mCAAmC,SAAS,SAAS,CAAC;AACnF,cAAM,YAAY,MAAM,KAAK,sBAAsB,IAAI;AACvD,qBAAa,CAAC,GAAG,gBAAgB,GAAG,UAAU,IAAI,QAAM,EAAE,GAAG,GAAG,UAAU,EAAE,WAAW,GAAG,EAAE,CAAC;AAAA,MAC/F;AAEA,YAAM,YAAY,CAAC,GAAG,QAAQ,GAAG,WAAW;AAC5C,YAAM,OAAO,KAAK,UAAU,MAAM,QAAQ,KAAK;AAE/C,YAAM,QAAsB;AAAA,QAC1B,MAAiB,QAAQ;AAAA,QACzB,gBAAiB,KAAK;AAAA,QACtB,iBAAiB,KAAK,OAAO,CAAC,GAAG,MAAM,KAAK,IAAI,GAAG,EAAE,KAAK,GAAG,CAAC;AAAA,QAC9D,YAAiB,KAAK,IAAI,IAAI;AAAA,QAC9B;AAAA,MACF;AAEA,WAAK,SAAS,WAAW,KAAK;AAE9B,aAAO;AAAA,QACL,MAAgB,QAAQ;AAAA,QACxB,UAAgB,QAAQ,YAAY;AAAA,QACpC,cAAgB,oBAAI,KAAK,GAAE,YAAY;AAAA,QACvC,gBAAgB,KAAK;AAAA,QACrB,SAAmB,WAAW;AAAA,QAC9B,YAAmB,WAAW;AAAA,QAC9B,QAAmB,WAAW;AAAA,QAC9B;AAAA,QACA;AAAA,QACA;AAAA,QACA,QAAS;AAAA,QACT;AAAA,QACA,gBAAgB;AAAA,QAChB;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF,SAAS,KAAK;AACZ;AACA,WAAK,SAAS,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,CAAC;AACzE,YAAM;AAAA,IACR,UAAE;AACA,YAAM,KAAK,OAAO,MAAM;AAAA,IAC1B;AAAA,EACF;AACF;;;AC5yBA,qBAA+B;AAC/B,uBAAiB;AACjB,uBAAiB;AAIV,IAAM,mBAAN,MAAoD;AAAA,EACzD,MAAM,UAAU,QAAuB,WAAoC;AACzE,UAAM,eAAAE,SAAG,MAAM,WAAW,EAAE,WAAW,KAAK,CAAC;AAC7C,UAAM,OAAO,OAAO,KAAK,YAAY,EAAE,QAAQ,QAAQ,GAAG,EAAE,MAAM,GAAG,EAAE;AACvE,UAAM,WAAW,GAAG,IAAI,IAAI,KAAK,IAAI,CAAC;AACtC,UAAM,WAAW,iBAAAC,QAAK,KAAK,WAAW,QAAQ;AAC9C,UAAM,eAAAD,SAAG,UAAU,UAAU,KAAK,UAAU,QAAQ,MAAM,CAAC,GAAG,MAAM;AACpE,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,SAAS,MAAiB,WAAoC;AAClE,UAAM,eAAAA,SAAG,MAAM,WAAW,EAAE,WAAW,KAAK,CAAC;AAC7C,UAAM,UAAU,KAAK,CAAC,GAAG,cAAc;AACvC,UAAM,OAAO,QAAQ,YAAY,EAAE,QAAQ,QAAQ,GAAG,EAAE,MAAM,GAAG,EAAE;AACnE,UAAM,MAAM,iBAAAE,QAAK,QAAQ,MAAM,EAAE,QAAQ,KAAK,CAAC;AAC/C,UAAM,WAAW,GAAG,IAAI,IAAI,KAAK,IAAI,CAAC;AACtC,UAAM,WAAW,iBAAAD,QAAK,KAAK,WAAW,QAAQ;AAC9C,UAAM,eAAAD,SAAG,UAAU,UAAU,KAAK,MAAM;AACxC,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,cAAc,QAAuB,MAAc,WAAoC;AAC3F,UAAM,eAAAA,SAAG,MAAM,WAAW,EAAE,WAAW,KAAK,CAAC;AAC7C,UAAM,OAAO,KAAK,YAAY,EAAE,QAAQ,QAAQ,GAAG,EAAE,MAAM,GAAG,EAAE;AAChE,UAAM,MAAM,iBAAAE,QAAK,QAAQ,QAAQ,EAAE,QAAQ,KAAK,CAAC;AACjD,UAAM,WAAW,GAAG,IAAI,WAAW,KAAK,IAAI,CAAC;AAC7C,UAAM,WAAW,iBAAAD,QAAK,KAAK,WAAW,QAAQ;AAC9C,UAAM,eAAAD,SAAG,UAAU,UAAU,KAAK,MAAM;AACxC,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,cAAc,QAAuB,MAAc,WAAoC;AAC3F,UAAM,eAAAA,SAAG,MAAM,WAAW,EAAE,WAAW,KAAK,CAAC;AAC7C,UAAM,OAAO,KAAK,YAAY,EAAE,QAAQ,QAAQ,GAAG,EAAE,MAAM,GAAG,EAAE;AAChE,UAAM,MAAM,iBAAAE,QAAK,QAAQ,QAAQ,EAAE,QAAQ,KAAK,CAAC;AACjD,UAAM,WAAW,GAAG,IAAI,WAAW,KAAK,IAAI,CAAC;AAC7C,UAAM,WAAW,iBAAAD,QAAK,KAAK,WAAW,QAAQ;AAC9C,UAAM,eAAAD,SAAG,UAAU,UAAU,KAAK,MAAM;AACxC,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,mBAAmB,WAAyB,MAAqB,MAAc,WAAoC;AACvH,UAAM,eAAAA,SAAG,MAAM,WAAW,EAAE,WAAW,KAAK,CAAC;AAC7C,UAAM,OAAO,KAAK,YAAY,EAAE,QAAQ,QAAQ,GAAG,EAAE,MAAM,GAAG,EAAE;AAChE,UAAM,OAAO,UAAU,IAAI,CAAC,GAAG,OAAO;AAAA,MACpC,YAAe;AAAA,MACf,eAAe,MAAM,IAAK,QAAQ,KAAM;AAAA,MACxC,eAAe,EAAE;AAAA,MACjB,eAAe,EAAE;AAAA,IACnB,EAAE;AACF,UAAM,MAAM,iBAAAE,QAAK,QAAQ,MAAM,EAAE,QAAQ,KAAK,CAAC;AAC/C,UAAM,WAAW,GAAG,IAAI,gBAAgB,KAAK,IAAI,CAAC;AAClD,UAAM,WAAW,iBAAAD,QAAK,KAAK,WAAW,QAAQ;AAC9C,UAAM,eAAAD,SAAG,UAAU,UAAU,KAAK,MAAM;AACxC,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,eAAe,WAAyB,MAAqB,MAAc,WAAoC;AACnH,UAAM,eAAAA,SAAG,MAAM,WAAW,EAAE,WAAW,KAAK,CAAC;AAC7C,UAAM,OAAO,KAAK,YAAY,EAAE,QAAQ,QAAQ,GAAG,EAAE,MAAM,GAAG,EAAE;AAChE,UAAM,OAAO,UAAU,IAAI,CAAC,GAAG,OAAO;AAAA,MACpC,YAAe;AAAA,MACf,eAAe,MAAM,IAAK,QAAQ,KAAM;AAAA,MACxC,eAAe,EAAE;AAAA,MACjB,eAAe,EAAE;AAAA,IACnB,EAAE;AACF,UAAM,MAAM,iBAAAE,QAAK,QAAQ,MAAM,EAAE,QAAQ,KAAK,CAAC;AAC/C,UAAM,WAAW,GAAG,IAAI,YAAY,KAAK,IAAI,CAAC;AAC9C,UAAM,WAAW,iBAAAD,QAAK,KAAK,WAAW,QAAQ;AAC9C,UAAM,eAAAD,SAAG,UAAU,UAAU,KAAK,MAAM;AACxC,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,yBAAyB,OAA+B,MAAc,WAAoC;AAC9G,UAAM,eAAAA,SAAG,MAAM,WAAW,EAAE,WAAW,KAAK,CAAC;AAC7C,UAAM,OAAO,KAAK,YAAY,EAAE,QAAQ,QAAQ,GAAG,EAAE,MAAM,GAAG,EAAE;AAChE,UAAM,OAAO,MAAM,IAAI,CAAC,OAAO,EAAE,YAAY,MAAM,GAAG,EAAE,EAAE;AAC1D,UAAM,MAAM,iBAAAE,QAAK,QAAQ,MAAM,EAAE,QAAQ,KAAK,CAAC;AAC/C,UAAM,WAAW,GAAG,IAAI,uBAAuB,KAAK,IAAI,CAAC;AACzD,UAAM,WAAW,iBAAAD,QAAK,KAAK,WAAW,QAAQ;AAC9C,UAAM,eAAAD,SAAG,UAAU,UAAU,KAAK,MAAM;AACxC,WAAO;AAAA,EACT;AACF;;;ACtFO,IAAM,mBAAN,MAAoD;AAAA,EACzD,WAAW,MAAqB;AAC9B,YAAQ,OAAO,MAAM,KAAK,UAAU,EAAE,OAAO,YAAY,OAAO,KAAK,OAAO,UAAU,KAAK,SAAS,CAAC,IAAI,IAAI;AAAA,EAC/G;AAAA,EAEA,QAAQ,OAAqB;AAC3B,YAAQ,OAAO,MAAM,KAAK,UAAU,EAAE,OAAO,SAAS,MAAM,CAAC,IAAI,IAAI;AAAA,EACvE;AAAA,EAEA,SAAS,QAA6B;AACpC,eAAW,KAAK,QAAQ;AACtB,cAAQ,OAAO,MAAM,KAAK,UAAU,EAAE,OAAO,SAAS,MAAM,EAAE,MAAM,UAAU,EAAE,UAAU,UAAU,EAAE,UAAU,OAAO,EAAE,OAAO,SAAS,EAAE,SAAS,KAAK,EAAE,IAAI,CAAC,IAAI,IAAI;AAAA,IAC1K;AAAA,EACF;AAAA,EAEA,SAAS,QAA6B;AACpC,eAAW,KAAK,QAAQ;AACtB,cAAQ,OAAO,MAAM,KAAK,UAAU,EAAE,OAAO,SAAS,OAAO,EAAE,OAAO,QAAQ,EAAE,QAAQ,KAAK,EAAE,IAAI,CAAC,IAAI,IAAI;AAAA,IAC9G;AAAA,EACF;AAAA,EAEA,WAAW,OAA2B;AACpC,YAAQ,OAAO,MAAM,KAAK,UAAU,EAAE,OAAO,YAAY,GAAG,MAAM,CAAC,IAAI,IAAI;AAAA,EAC7E;AAAA,EAEA,QAAQ,KAAkB;AACxB,YAAQ,OAAO,MAAM,KAAK,UAAU,EAAE,OAAO,SAAS,MAAM,IAAI,YAAY,MAAM,SAAS,IAAI,QAAQ,CAAC,IAAI,IAAI;AAAA,EAClH;AACF;;;ACvBA,IAAM,eAAe;AAErB,eAAe,YAAY,SAAiD;AAC1E,QAAM,SAAS,IAAI,cAAc;AACjC,QAAM,WAAW,IAAI,iBAAiB;AACtC,QAAM,YAAY,IAAI,aAAa,QAAQ,QAAQ;AACnD,MAAI;AACF,WAAO,MAAM,UAAU,QAAQ,OAAO;AAAA,EACxC,UAAE;AACA,UAAM,OAAO,MAAM;AAAA,EACrB;AACF;AAEA,eAAsB,QAAQ,YAA6C;AACzE,QAAM,MAAM,OAAO,eAAe,YAAY,eAAe,OAAO,aAAa,CAAC;AAClF,QAAM,SAAS;AAAA,IACb,cAAc,QAAQ,IAAI,gBAAgB,KAAK;AAAA,IAC/C,eAAe,QAAQ,IAAI,iBAAiB,KAAK;AAAA,IACjD,GAAG;AAAA,EACL;AACA,QAAM,UAAU,qBAAqB,MAAM,MAAM;AACjD,QAAM,aAAa,IAAI,iBAAiB;AAExC,WAAS,IAAI,GAAG,IAAI,cAAc,KAAK;AACrC,QAAI;AACF,YAAM,SAAS,MAAM,YAAY,OAAO;AACxC,UAAI,QAAQ,WAAW,UAAU,QAAQ,WAAW,QAAQ;AAC1D,cAAM,WAAW,UAAU,QAAQ,QAAQ,SAAS;AAAA,MACtD;AACA,UAAI,QAAQ,WAAW,SAAS,QAAQ,WAAW,QAAQ;AACzD,cAAM,QAAQ,IAAI;AAAA,UAChB,WAAW,SAAS,OAAO,MAAM,QAAQ,SAAS;AAAA,UAClD,OAAO,OAAO,SAAS,IAAI,WAAW,cAAc,OAAO,QAAQ,OAAO,MAAM,QAAQ,SAAS,IAAI,QAAQ,QAAQ,EAAE;AAAA,UACvH,OAAO,OAAO,SAAS,IAAI,WAAW,cAAc,OAAO,QAAQ,OAAO,MAAM,QAAQ,SAAS,IAAI,QAAQ,QAAQ,EAAE;AAAA,UACvH,OAAO,WAAW,WAAkB,WAAW,mBAAmB,OAAO,WAAW,WAAW,OAAO,WAAW,MAAM,OAAO,MAAM,QAAQ,SAAS,IAAI,QAAQ,QAAQ,EAAE;AAAA,UAC3K,OAAO,OAAO,WAAsB,WAAW,eAAe,OAAO,OAAO,WAAW,OAAO,OAAO,MAAM,OAAO,MAAM,QAAQ,SAAS,IAAO,QAAQ,QAAQ,EAAE;AAAA,UAClK,OAAO,iBAAiB,SAAS,IAAI,WAAW,yBAAyB,OAAO,kBAAkB,OAAO,MAAM,QAAQ,SAAS,IAAe,QAAQ,QAAQ,EAAE;AAAA,QACnK,CAAC;AAAA,MACH;AACA,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,UAAI,eAAe,gBAAgB,IAAI,eAAe,GAAG;AACvD;AAAA,MACF;AACA,YAAM;AAAA,IACR;AAAA,EACF;AACA,QAAM,cAAc,QAAQ,eAAe,GAAG,YAAY,8BAA8B,GAAG,YAAY;AACvG,QAAM,IAAI,aAAa,kBAAkB,WAAW,+BAA+B;AACrF;;;ACzDA,IAAAG,6BAAyB;AACzB,IAAAC,kBAAmE;AACnE,qBAAuB;AACvB,IAAAC,oBAAqB;AACrB,IAAAC,iBAAoB;;;ACGpB,IAAM,gBAAiB;AACvB,IAAM,iBAAiB;AACvB,IAAM,aAAiB;AAEvB,IAAM,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4BtB,eAAe,QAAQ,QAAgB,SAAiB,UAAkB,QAAyC;AACjH,QAAM,MAAM,MAAM,MAAM,SAAS;AAAA,IAC/B,QAAS;AAAA,IACT,SAAS,EAAE,iBAAiB,UAAU,MAAM,IAAI,gBAAgB,mBAAmB;AAAA,IACnF,MAAM,KAAK,UAAU;AAAA,MACnB,OAAa;AAAA,MACb,aAAa;AAAA,MACb,UAAU;AAAA,QACR,EAAE,MAAM,UAAU,SAAS,cAAc;AAAA,QACzC,EAAE,MAAM,QAAU,SAAS,aAAa,QAAQ;AAAA;AAAA,UAAe,OAAO,MAAM,GAAG,GAAG,CAAC,GAAG;AAAA,MACxF;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AACD,MAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,oBAAoB,IAAI,MAAM,MAAM,MAAM,IAAI,KAAK,CAAC,EAAE;AAEnF,QAAM,OAAS,MAAM,IAAI,KAAK;AAC9B,QAAM,MAAQ,KAAK,QAAQ,CAAC,GAAG,SAAS,SAAS,KAAK,KAAK;AAC3D,QAAM,QAAQ,IAAI,MAAM,aAAa;AACrC,MAAI,CAAC,MAAO,OAAM,IAAI,MAAM,6BAA6B,IAAI,MAAM,GAAG,GAAG,CAAC,EAAE;AAE5E,QAAM,SAAS,KAAK,MAAM,MAAM,CAAC,CAAC;AAClC,MAAI,CAAC,OAAO,SAAS,CAAC,OAAO,SAAS,CAAC,OAAO,aAAa,CAAC,OAAO,WAAW;AAC5E,UAAM,IAAI,MAAM,iCAAiC,IAAI,MAAM,GAAG,GAAG,CAAC,EAAE;AAAA,EACtE;AACA,SAAO;AACT;AAEA,eAAsB,iBAAiB,UAAkB,QAAyC;AAChG,QAAM,eAAgB,QAAQ,IAAI,mBAAmB;AACrD,QAAM,gBAAgB,QAAQ,IAAI,oBAAoB;AAEtD,MAAI,cAAc;AAChB,QAAI;AACF,aAAO,MAAM,QAAQ,cAAc,eAAe,UAAU,MAAM;AAAA,IACpE,SAAS,KAAK;AACZ,cAAQ,KAAK,wDAAyD,IAAc,OAAO;AAAA,IAC7F;AAAA,EACF;AACA,MAAI,eAAe;AACjB,WAAO,MAAM,QAAQ,eAAe,gBAAgB,UAAU,MAAM;AAAA,EACtE;AACA,QAAM,IAAI,MAAM,+DAA0D;AAC5E;;;ACjFA,IAAM,YAAgB;AACtB,IAAM,gBAAgB;AACtB,IAAM,aAAgB;AAKtB,eAAe,YAAY,OAAe,OAAgC,QAAkD;AAC1H,QAAM,UAAU,EAAE,iBAAiB,OAAO,MAAM,IAAI,gBAAgB,mBAAmB;AAEvF,QAAM,YAAY,MAAM,MAAM,GAAG,UAAU,IAAI,KAAK,IAAI;AAAA,IACtD,QAAQ;AAAA,IAAQ;AAAA,IAAS,MAAM,KAAK,UAAU,KAAK;AAAA,EACrD,CAAC;AACD,MAAI,CAAC,UAAU,GAAI,OAAM,IAAI,MAAM,GAAG,KAAK,mBAAmB,UAAU,MAAM,MAAM,MAAM,UAAU,KAAK,CAAC,EAAE;AAC5G,QAAM,EAAE,WAAW,IAAI,MAAM,UAAU,KAAK;AAC5C,UAAQ,IAAI,mBAAmB,KAAK,WAAM,UAAU,EAAE;AAEtD,SAAO,MAAM;AACX,UAAM,IAAI,QAAQ,OAAK,WAAW,GAAG,GAAI,CAAC;AAC1C,UAAM,YAAY,MAAM,MAAM,GAAG,UAAU,IAAI,KAAK,aAAa,UAAU,WAAW,EAAE,QAAQ,CAAC;AACjG,QAAI,CAAC,UAAU,GAAI;AACnB,UAAM,EAAE,OAAO,IAAI,MAAM,UAAU,KAAK;AACxC,YAAQ,IAAI,SAAS,UAAU,WAAM,MAAM,EAAE;AAC7C,QAAI,WAAW,SAAU,OAAM,IAAI,MAAM,GAAG,KAAK,YAAY,UAAU,SAAS;AAChF,QAAI,WAAW,YAAa;AAC5B,UAAM,YAAY,MAAM,MAAM,GAAG,UAAU,IAAI,KAAK,aAAa,UAAU,IAAI,EAAE,QAAQ,CAAC;AAC1F,QAAI,CAAC,UAAU,GAAI,OAAM,IAAI,MAAM,wBAAwB,UAAU,MAAM,GAAG;AAC9E,WAAO,MAAM,UAAU,KAAK;AAAA,EAC9B;AACF;AAEA,SAAS,SAAiB;AACxB,QAAM,MAAM,QAAQ,IAAI,SAAS;AACjC,MAAI,CAAC,IAAK,OAAM,IAAI,MAAM,kBAAkB;AAC5C,SAAO;AACT;AAEA,eAAsB,kBAAkB,MAAc,QAAQ,eAAgC;AAC5F,UAAQ,IAAI,0CAA0C;AACtD,QAAM,MAAM,MAAM,YAAY,WAAW,EAAE,MAAM,OAAO,mBAAmB,KAAM,GAAG,OAAO,CAAC;AAC5F,SAAO,IAAI,MAAM;AACnB;AAEA,eAAsB,mBAAmB,UAAkB,MAAc,iBAA0C;AACjH,UAAQ,IAAI,4DAA4D;AACxE,QAAM,MAAM,MAAM,YAAY,eAAe;AAAA,IAC3C,WAAiB;AAAA,IACjB,QAAiB;AAAA,IACjB,iBAAiB;AAAA,IACjB,UAAiB;AAAA,IACjB,cAAiB;AAAA,EACnB,GAAG,OAAO,CAAC;AACX,SAAO,IAAI,MAAM;AACnB;;;ACrDA,gCAAyB;AACzB,IAAAC,kBAAyC;AACzC,IAAAC,oBAAqB;AACrB,oBAAoB;AAEpB,eAAe,SAAS,KAAa,UAAiC;AACpE,QAAM,MAAM,MAAM,MAAM,GAAG;AAC3B,MAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,oBAAoB,IAAI,MAAM,MAAM,GAAG,EAAE;AACtE,qCAAc,UAAU,OAAO,KAAK,MAAM,IAAI,YAAY,CAAC,CAAC;AAC9D;AAEA,eAAsB,iBAAiB,UAAkB,UAAkB,QAAiC;AAC1G,iCAAU,QAAQ,EAAE,WAAW,KAAK,CAAC;AACrC,QAAM,KAAO,KAAK,IAAI;AACtB,QAAM,SAAO,wBAAK,QAAQ,SAAS,EAAE,MAAM;AAC3C,QAAM,SAAO,wBAAK,QAAQ,SAAS,EAAE,MAAM;AAC3C,QAAM,UAAO,wBAAK,QAAQ,YAAY,EAAE,MAAM;AAE9C,UAAQ,IAAI,mCAAmC;AAC/C,QAAM,QAAQ,IAAI,CAAC,SAAS,UAAU,EAAE,GAAG,SAAS,UAAU,EAAE,CAAC,CAAC;AAElE,UAAQ,IAAI,+BAA+B;AAC3C;AAAA,IACE,cAAc,EAAE,SAAS,EAAE,sEAAsE,GAAG;AAAA,EACtG;AACA,SAAO;AACT;AAEA,eAAsB,YAAY,WAAoC;AACpE,QAAM,EAAE,cAAAC,cAAa,IAAI,MAAM,OAAO,IAAS;AAC/C,QAAM,OAAO,IAAI,KAAK,CAACA,cAAa,SAAS,CAAC,GAAG,EAAE,MAAM,YAAY,CAAC;AACtE,QAAM,MAAO,MAAM,kBAAI,QAAQ,OAAO,IAAI;AAC1C,UAAQ,IAAI,iCAAiC,GAAG;AAChD,SAAO;AACT;AAEA,eAAsB,iBACpB,WACA,cACA,QACiB;AACjB,QAAM,KAAM,KAAK,IAAI;AACrB,QAAM,UAAM,wBAAK,QAAQ,aAAa,EAAE,MAAM;AAC9C,QAAM,UAAM,wBAAK,QAAQ,SAAS,EAAE,MAAM;AAE1C,UAAQ,IAAI,uCAAuC;AACnD,QAAM,SAAS,cAAc,GAAG;AAEhC,UAAQ,IAAI,wDAAwD;AACpE;AAAA,IACE,cAAc,SAAS,SAAS,GAAG,yIAEE,GAAG;AAAA,EAC1C;AACA,SAAO;AACT;;;AHvBA,IAAM,MAAM;AACZ,IAAM,MAAM;AAEZ,SAAS,WAAW,QAAgB,MAAuB,MAAe,UAAmB;AAC3F,SAAO;AAAA,IACL;AAAA,IACA,YAAgB,KAAK,cAAc;AAAA,IACnC,UAAgB,KAAK,uBAAuB;AAAA,IAC5C,cAAgB,KAAK,eAAe;AAAA,IACpC,gBAAgB;AAAA,IAChB,GAAI,SAAa,SAAY,EAAE,KAAK,IAAkB,CAAC;AAAA,IACvD,GAAI,aAAa,SAAY,EAAE,WAAW,SAAS,IAAI,CAAC;AAAA,EAC1D;AACF;AAEA,eAAe,SAAS,OAAe,OAAsD;AAC3F,QAAM,EAAE,WAAW,IAAI,MAAM,mBAAI,MAAM,OAAO,OAAO,EAAE,MAAM,CAAC;AAC9D,UAAQ,IAAI,mBAAmB,KAAK,WAAM,UAAU,EAAE;AACtD,SAAO,MAAM;AACX,UAAM,IAAI,QAAQ,OAAK,WAAW,GAAG,GAAI,CAAC;AAC1C,UAAM,IAAI,MAAM,mBAAI,MAAM,OAAO,OAAO,EAAE,WAAW,YAAY,MAAM,MAAM,CAAC;AAC9E,YAAQ,IAAI,SAAS,UAAU,WAAM,EAAE,MAAM,EAAE;AAC/C,QAAK,EAAE,WAAsB,SAAU,OAAM,IAAI,MAAM,WAAW,UAAU,SAAS;AACrF,QAAK,EAAE,WAAsB,YAAa;AAC1C,UAAM,SAAS,MAAM,mBAAI,MAAM,OAAO,OAAO,EAAE,WAAW,WAAW,CAAC;AACtE,WAAO,OAAO;AAAA,EAChB;AACF;AAEA,eAAe,iBAAiB,UAAkB,QAAiC;AACjF,QAAM,KAAU,KAAK,IAAI;AACzB,QAAM,cAAU,wBAAK,QAAQ,aAAa,EAAE,MAAM;AAClD,QAAM,cAAU,wBAAK,QAAQ,cAAc,EAAE,MAAM;AAEnD,QAAM,MAAM,MAAM,MAAM,QAAQ;AAChC,MAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,8BAA8B,IAAI,MAAM,GAAG;AACxE,qCAAc,SAAS,OAAO,KAAK,MAAM,IAAI,YAAY,CAAC,CAAC;AAE3D,MAAI;AACF,6CAAS,0BAA0B,OAAO,oBAAoB,OAAO,mBAAmB;AAAA,EAC1F,UAAE;AACA,QAAI;AAAE,sCAAW,OAAO;AAAA,IAAE,QAAQ;AAAA,IAAC;AAAA,EACrC;AACA,SAAO;AACT;AAEO,IAAM,iBAAN,MAAqB;AAAA,EAC1B,YAAY,QAAiB;AAC3B,UAAM,MAAM,UAAU,QAAQ,IAAI,SAAS;AAC3C,QAAI,CAAC,IAAK,OAAM,IAAI,MAAM,qBAAqB;AAC/C,uBAAI,OAAO,EAAE,aAAa,IAAI,CAAC;AAAA,EACjC;AAAA,EAEA,MAAM,iBACJ,UACA,QACA,OAA4B,CAAC,GACJ;AACzB,UAAM,SAAS,KAAK,iBAAa,4BAAK,uBAAO,GAAG,aAAa,KAAK,IAAI,CAAC,EAAE;AACzE,mCAAU,QAAQ,EAAE,WAAW,KAAK,CAAC;AAErC,YAAQ,IAAI,4CAA4C;AACxD,UAAM,UAAU,MAAM,iBAAiB,UAAU,MAAM;AACvD,YAAQ,IAAI,gBAAgB,QAAQ,SAAS;AAC7C,YAAQ,IAAI,iBAAiB,QAAQ,SAAS;AAE9C,YAAQ,IAAI,8CAA8C;AAC1D,UAAM,UAAU,MAAM,SAAS,KAAK,WAAW,QAAQ,OAAO,MAAM,KAAK,IAAI,CAAC;AAE9E,YAAQ,IAAI,sDAAiD;AAC7D,UAAM,UAAW,MAAM,iBAAiB,QAAQ,MAAM,KAAK,MAAM;AACjE,UAAM,YAAY,IAAI,KAAK,KAAC,8BAAa,OAAO,CAAC,GAAG,EAAE,MAAM,aAAa,CAAC;AAC1E,UAAM,WAAY,MAAM,mBAAI,QAAQ,OAAO,SAAS;AACpD,QAAI;AAAE,sCAAW,OAAO;AAAA,IAAE,QAAQ;AAAA,IAAC;AAEnC,YAAQ,IAAI,+DAA+D;AAC3E,UAAM,QAAU,KAAK,SAAS,SAAY,KAAK,OAAO,IAAI;AAC1D,UAAM,UAAU,MAAM,SAAS,KAAK,WAAW,QAAQ,OAAO,MAAM,OAAO,QAAQ,CAAC;AAEpF,YAAQ,IAAI,kEAAkE;AAC9E,UAAM,CAAC,cAAc,YAAY,IAAI,MAAM,QAAQ,IAAI;AAAA,MACrD,iBAAiB,QAAQ,MAAM,KAAK,QAAQ,MAAM,KAAK,MAAM;AAAA,MAC7D,kBAAkB,QAAQ,WAAW,KAAK,QAAQ;AAAA,IACpD,CAAC;AAED,YAAQ,IAAI,mDAAmD;AAC/D,UAAM,cAAqB,MAAM,YAAY,YAAY;AACzD,UAAM,iBAAsB,KAAK,uBAAuB,KAAK;AAC7D,UAAM,oBAAqB,MAAM,mBAAmB,aAAa,QAAQ,WAAW,aAAa;AAEjG,YAAQ,IAAI,gDAAgD;AAC5D,UAAM,yBAAqB,wBAAK,QAAQ,iBAAiB,KAAK,IAAI,CAAC,MAAM;AACzE,UAAM,QAAQ,MAAM,MAAM,iBAAiB;AAC3C,uCAAc,oBAAoB,OAAO,KAAK,MAAM,MAAM,YAAY,CAAC,CAAC;AACxE,UAAM,iBAAiB,MAAM,iBAAiB,oBAAoB,cAAc,MAAM;AAEtF,WAAO;AAAA,MACL,UAAgB,QAAQ,MAAM;AAAA,MAC9B,UAAgB,QAAQ,MAAM;AAAA,MAC9B;AAAA,MACA,MAAgB,QAAQ;AAAA,MACxB,aAAgB,QAAQ;AAAA,MACxB,aAAgB,QAAQ;AAAA,MACxB,WAAgB,QAAQ;AAAA,MACxB,WAAgB,QAAQ;AAAA,IAC1B;AAAA,EACF;AACF;","names":["StealthPlugin","Kernel","playwrightChromium","s","organicResults","localPack","rawEntityIds","entityIds","allOrganic","stats","aiSurfaces","fs","path","Papa","import_node_child_process","import_node_fs","import_node_path","import_client","import_node_fs","import_node_path","readFileSync"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/schemas.ts","../src/driver/BrowserDriver.ts","../src/selectors.ts","../src/errors.ts","../src/locations.ts","../src/uule.ts","../src/serp-location-debug.ts","../src/lib/paa-answer-cleanup.ts","../src/extractor/ai-surfaces.ts","../src/extractor/PAAExtractor.ts","../src/output/OutputSerializer.ts","../src/output/ProgressReporter.ts","../src/kernel-proxy-resolver.ts","../src/harvest.ts","../src/video/VideoGenerator.ts","../src/video/promptBuilder.ts","../src/video/AudioGenerator.ts","../src/video/VideoMixer.ts"],"sourcesContent":["export { harvest } from './harvest.js'\nexport type { HarvestOptions, HarvestResult, HarvestDiagnostics, HarvestCompletionStatus, PAANode, FlatRow, HarvestStats, AIOverviewResult, AIModeResult, AICitation, GoogleSurface, WhatPeopleSayingCard } from './types.js'\nexport { VideoGenerator } from './video/VideoGenerator.js'\nexport type { ClipPairOptions, ClipPairResult } from './video/VideoGenerator.js'\nexport { buildClipPrompts } from './video/promptBuilder.js'\n","import { z } from 'zod'\n\nexport const HarvestOptionsSchema = z.object({\n query: z.string().min(1),\n location: z.string().optional(),\n gl: z.string().length(2).default('us'),\n hl: z.string().length(2).default('en'),\n device: z.enum(['desktop', 'mobile']).default('desktop'),\n proxyMode: z.enum(['location', 'configured', 'none']).default('location'),\n proxyZip: z.string().regex(/^\\d{5}$/).optional(),\n debug: z.boolean().default(false),\n depth: z.number().int().min(1).max(30).default(3),\n maxQuestions: z.number().int().min(1).max(1000).default(100),\n headless: z.boolean().default(false),\n profileDir: z.string().optional(),\n proxy: z.string().url().optional(),\n kernelApiKey: z.string().optional(),\n kernelProxyId: z.string().optional(),\n kernelProxyResolution: z.unknown().optional(),\n outputDir: z.string().default('./paa-output'),\n format: z.enum(['json', 'csv', 'both']).default('both'),\n serpOnly: z.boolean().default(false),\n pages: z.number().int().min(1).max(2).default(1),\n})\n\nexport const MapsPlaceOptionsSchema = z.object({\n businessName: z.string().min(1),\n location: z.string().min(1),\n gl: z.string().length(2).default('us'),\n hl: z.string().length(2).default('en'),\n includeReviews: z.boolean().default(false),\n maxReviews: z.number().int().min(1).max(500).default(50),\n kernelApiKey: z.string().optional(),\n kernelProxyId: z.string().optional(),\n headless: z.boolean().default(true),\n})\n\nexport const RawPAAItemSchema = z.object({\n question: z.string().min(1),\n answer: z.string().optional(),\n sourceTitle: z.string().optional(),\n sourceSite: z.string().optional(),\n sourceCite: z.string().optional(),\n})\n\nexport const RawMapsOverviewSchema = z.object({\n name: z.string().nullable(),\n rating: z.string().nullable(),\n reviewCount: z.string().nullable(),\n category: z.string().nullable(),\n address: z.string().nullable(),\n hoursSummary: z.string().nullable(),\n phone: z.string().nullable(),\n phoneDisplay: z.string().nullable(),\n website: z.string().nullable(),\n plusCode: z.string().nullable(),\n bookingUrl: z.string().nullable(),\n})\n\nexport const RawMapsHoursRowSchema = z.object({\n day: z.string(),\n hours: z.string(),\n})\n\nexport const RawMapsReviewStatsSchema = z.object({\n reviewHistogram: z.array(z.object({\n stars: z.number(),\n count: z.string(),\n })),\n reviewTopics: z.array(z.object({\n label: z.string(),\n count: z.string(),\n })),\n})\n\nexport const RawMapsReviewCardSchema = z.object({\n reviewId: z.string(),\n author: z.string().nullable(),\n stars: z.string().nullable(),\n date: z.string().nullable(),\n text: z.string().nullable(),\n ownerResponse: z.string().nullable(),\n})\n\nexport const RawMapsAboutAttributeSchema = z.object({\n section: z.string(),\n attribute: z.string(),\n})\n","import { chromium } from 'playwright-extra'\nimport StealthPlugin from 'puppeteer-extra-plugin-stealth'\nimport { chromium as playwrightChromium } from 'playwright'\nimport type { Browser, BrowserContext, Page } from 'playwright'\nimport Kernel from '@onkernel/sdk'\nimport { PAASelectors } from '../selectors.js'\nimport { CaptchaError, ExtractionError, RECAPTCHA_INSTRUCTIONS } from '../errors.js'\nimport type { BrowserDebugSnapshot, BrowserNetworkLocationDebug, DriverConfig, KernelSessionDebug, ProxyMode, SerpDevice, SerpNavigationDebug, UuleString } from '../types.js'\nimport type { BrowserCloseResult, IBrowserDriver } from './IBrowserDriver.js'\n\nchromium.use(StealthPlugin())\n\nconst DESKTOP_USER_AGENT =\n 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36'\n\nconst MOBILE_USER_AGENT =\n 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1'\n\nconst DEFAULT_KERNEL_BROWSER_TIMEOUT_SECONDS = 180\nconst KERNEL_BROWSER_CLOSE_TIMEOUT_MS = 3_000\nconst KERNEL_SESSION_DELETE_TIMEOUT_MS = 5_000\n\nfunction positiveIntFromEnv(name: string, fallback: number): number {\n const raw = process.env[name]\n if (!raw) return fallback\n const parsed = Number(raw)\n return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback\n}\n\nfunction proxyIdSuffix(proxyId: string | null | undefined): string | null {\n return proxyId ? proxyId.slice(-6) : null\n}\n\nfunction errorText(err: unknown): string {\n return err instanceof Error ? err.message : String(err)\n}\n\nexport function rankCheckContextOptions(config: DriverConfig) {\n return {\n viewport: config.viewport,\n locale: config.locale,\n userAgent: config.userAgent ?? (config.isMobile ? MOBILE_USER_AGENT : DESKTOP_USER_AGENT),\n ...(config.deviceScaleFactor ? { deviceScaleFactor: config.deviceScaleFactor } : {}),\n ...(config.isMobile !== undefined ? { isMobile: config.isMobile } : {}),\n ...(config.hasTouch !== undefined ? { hasTouch: config.hasTouch } : {}),\n }\n}\n\nasync function withTimeout<T>(promise: Promise<T>, timeoutMs: number, label: string): Promise<T> {\n let timeout: ReturnType<typeof setTimeout> | undefined\n try {\n return await Promise.race([\n promise,\n new Promise<never>((_, reject) => {\n timeout = setTimeout(() => reject(new Error(`${label} timed out after ${timeoutMs}ms`)), timeoutMs)\n }),\n ])\n } finally {\n if (timeout) clearTimeout(timeout)\n }\n}\n\nexport function buildYouTubeChannelVideosUrl(channelInput: string): string {\n const raw = channelInput.trim()\n if (!raw) throw new Error('channelHandle is required')\n\n const urlLike = /^https?:\\/\\//i.test(raw) || /^(www\\.|m\\.)?youtube\\.com\\//i.test(raw)\n if (urlLike) {\n const parsed = new URL(/^https?:\\/\\//i.test(raw) ? raw : `https://${raw}`)\n const host = parsed.hostname.replace(/^www\\./, '').replace(/^m\\./, '').toLowerCase()\n if (host !== 'youtube.com') throw new Error('channel URL must be on youtube.com')\n\n const segments = parsed.pathname.split('/').filter(Boolean)\n const first = segments[0] ?? ''\n const second = segments[1] ?? ''\n\n if (first.startsWith('@')) return `https://www.youtube.com/${first}/videos`\n if (first === 'channel' && second) return `https://www.youtube.com/channel/${second}/videos`\n if ((first === 'c' || first === 'user') && second) return `https://www.youtube.com/${first}/${second}/videos`\n\n throw new Error('channel URL must be a YouTube handle, /channel/UC..., /c/..., or /user/... URL')\n }\n\n const stripped = raw.replace(/^\\/+/, '').replace(/\\/+$/, '')\n const withoutVideos = stripped.replace(/\\/videos$/i, '')\n if (/^UC[\\w-]{20,}$/.test(withoutVideos)) {\n return `https://www.youtube.com/channel/${withoutVideos}/videos`\n }\n\n const handle = withoutVideos.startsWith('@') ? withoutVideos : `@${withoutVideos}`\n if (!/^@[\\w.-]+$/.test(handle)) {\n throw new Error('channelHandle must be an @handle, UC channel ID, or YouTube channel URL')\n }\n return `https://www.youtube.com/${handle}/videos`\n}\n\nexport class BrowserDriver implements IBrowserDriver {\n private browser: Browser | null = null\n private context: BrowserContext | null = null\n private page: Page | null = null\n private kernelClient: Kernel | null = null\n private kernelSessionId: string | null = null\n private debugEnabled = false\n private debugSnapshot: BrowserDebugSnapshot = {\n kernel: null,\n context: null,\n networkLocation: null,\n serpNavigation: null,\n }\n\n async launch(config: DriverConfig): Promise<void> {\n this.debugEnabled = config.debug === true\n const proxyMode: ProxyMode = config.proxyMode ?? (config.kernelProxyId ? 'configured' : 'none')\n const device: SerpDevice = config.isMobile ? 'mobile' : 'desktop'\n this.debugSnapshot = {\n kernel: null,\n context: {\n viewport: config.viewport,\n locale: config.locale,\n device,\n userAgent: config.userAgent ?? (config.isMobile ? MOBILE_USER_AGENT : DESKTOP_USER_AGENT),\n deviceScaleFactor: config.deviceScaleFactor ?? null,\n isMobile: config.isMobile === true,\n hasTouch: config.hasTouch === true,\n },\n networkLocation: null,\n serpNavigation: null,\n }\n\n if (config.kernelApiKey) {\n this.kernelClient = new Kernel({ apiKey: config.kernelApiKey })\n const timeoutSeconds = positiveIntFromEnv('KERNEL_BROWSER_TIMEOUT_SECONDS', DEFAULT_KERNEL_BROWSER_TIMEOUT_SECONDS)\n const kernelBrowser = await this.kernelClient.browsers.create({\n stealth: true,\n timeout_seconds: timeoutSeconds,\n ...(config.kernelProxyId ? { proxy_id: config.kernelProxyId } : {}),\n })\n this.kernelSessionId = kernelBrowser.session_id\n let defaultProxyDisabled: boolean | null = null\n let defaultProxyDisableError: string | null = null\n if (proxyMode === 'none') {\n try {\n await withTimeout(\n this.kernelClient.browsers.update(this.kernelSessionId, { disable_default_proxy: true }),\n 5_000,\n `Kernel session ${this.kernelSessionId} disable default proxy`,\n )\n defaultProxyDisabled = true\n } catch (err) {\n defaultProxyDisabled = false\n defaultProxyDisableError = errorText(err)\n }\n }\n const kernelDebug: KernelSessionDebug = {\n sessionId: this.kernelSessionId,\n proxyMode,\n requestedProxyIdPresent: Boolean(config.kernelProxyId),\n requestedProxyIdSuffix: proxyIdSuffix(config.kernelProxyId),\n createdProxyIdPresent: typeof kernelBrowser.proxy_id === 'string' ? Boolean(kernelBrowser.proxy_id) : null,\n createdProxyIdSuffix: proxyIdSuffix(kernelBrowser.proxy_id),\n retrievedProxyIdPresent: null,\n retrievedProxyIdSuffix: null,\n retrievedProxyIdMatchesRequested: null,\n defaultProxyDisabled,\n defaultProxyDisableError,\n proxyResolution: config.kernelProxyResolution ?? null,\n timeoutSeconds,\n stealth: typeof kernelBrowser.stealth === 'boolean' ? kernelBrowser.stealth : null,\n profilePresent: null,\n poolPresent: null,\n retrieveError: null,\n }\n this.debugSnapshot.kernel = kernelDebug\n console.info(JSON.stringify({\n event: 'kernel_browser_created',\n kernel_session_id: this.kernelSessionId,\n timeout_seconds: timeoutSeconds,\n proxy_mode: proxyMode,\n proxy_id_present: Boolean(config.kernelProxyId),\n proxy_resolution_source: config.kernelProxyResolution?.source,\n }))\n if (this.debugEnabled) {\n await this.populateKernelRetrieveDebug(kernelDebug, config.kernelProxyId)\n }\n this.browser = await playwrightChromium.connectOverCDP(kernelBrowser.cdp_ws_url)\n this.context = await this.browser.newContext(rankCheckContextOptions(config))\n await this.installEsbuildHelperShims(this.context)\n this.page = await this.context.newPage()\n await this.page.setViewportSize(config.viewport)\n if (this.debugEnabled) {\n this.debugSnapshot.networkLocation = await this.captureBrowserNetworkLocation()\n }\n return\n }\n\n const launchOpts = {\n headless: config.headless,\n proxy: config.proxy ? { server: config.proxy } : undefined,\n }\n const ctxOpts = rankCheckContextOptions(config)\n if (config.profileDir) {\n this.context = await chromium.launchPersistentContext(config.profileDir, {\n ...launchOpts,\n ...ctxOpts,\n })\n await this.installEsbuildHelperShims(this.context)\n this.page = await this.context.newPage()\n } else {\n this.browser = await chromium.launch(launchOpts)\n this.context = await this.browser.newContext(ctxOpts)\n await this.installEsbuildHelperShims(this.context)\n this.page = await this.context.newPage()\n }\n if (this.debugEnabled) {\n this.debugSnapshot.networkLocation = await this.captureBrowserNetworkLocation()\n }\n }\n\n private async populateKernelRetrieveDebug(kernelDebug: KernelSessionDebug, requestedProxyId: string | undefined): Promise<void> {\n if (!this.kernelClient || !this.kernelSessionId) return\n try {\n const retrieved = await withTimeout(\n this.kernelClient.browsers.retrieve(this.kernelSessionId),\n 5_000,\n `Kernel session ${this.kernelSessionId} retrieve`,\n ) as { proxy_id?: string; timeout_seconds?: number; stealth?: boolean; profile?: unknown; pool?: unknown }\n kernelDebug.retrievedProxyIdPresent = typeof retrieved.proxy_id === 'string' ? Boolean(retrieved.proxy_id) : false\n kernelDebug.retrievedProxyIdSuffix = proxyIdSuffix(retrieved.proxy_id)\n kernelDebug.retrievedProxyIdMatchesRequested = requestedProxyId\n ? retrieved.proxy_id === requestedProxyId\n : !retrieved.proxy_id\n kernelDebug.timeoutSeconds = typeof retrieved.timeout_seconds === 'number' ? retrieved.timeout_seconds : kernelDebug.timeoutSeconds\n kernelDebug.stealth = typeof retrieved.stealth === 'boolean' ? retrieved.stealth : kernelDebug.stealth\n kernelDebug.profilePresent = Boolean(retrieved.profile)\n kernelDebug.poolPresent = Boolean(retrieved.pool)\n } catch (err) {\n kernelDebug.retrieveError = errorText(err)\n }\n }\n\n private async captureBrowserNetworkLocation(): Promise<BrowserNetworkLocationDebug> {\n const fallback = (message: string, source: BrowserNetworkLocationDebug['source'] = 'ipapi.co'): BrowserNetworkLocationDebug => ({\n source,\n ip: null,\n city: null,\n region: null,\n country: null,\n org: null,\n timezone: null,\n error: message,\n })\n if (!this.context) return fallback('browser context is not available')\n let debugPage: Page | null = null\n try {\n debugPage = await this.context.newPage()\n const ipwho = await this.loadJsonInDebugPage(debugPage, 'https://ipwho.is/')\n if (ipwho) {\n const connection = typeof ipwho.connection === 'object' && ipwho.connection !== null\n ? ipwho.connection as Record<string, unknown>\n : {}\n return {\n source: 'ipwho.is',\n ip: typeof ipwho.ip === 'string' ? ipwho.ip : null,\n city: typeof ipwho.city === 'string' ? ipwho.city : null,\n region: typeof ipwho.region === 'string' ? ipwho.region : null,\n country: typeof ipwho.country === 'string' ? ipwho.country : null,\n org: typeof connection.org === 'string' ? connection.org : null,\n timezone: typeof ipwho.timezone === 'object' && ipwho.timezone !== null && typeof (ipwho.timezone as Record<string, unknown>).id === 'string'\n ? (ipwho.timezone as Record<string, unknown>).id as string\n : null,\n error: null,\n }\n }\n\n const ipify = await this.loadJsonInDebugPage(debugPage, 'https://api64.ipify.org?format=json')\n if (ipify) {\n return {\n source: 'api64.ipify.org',\n ip: typeof ipify.ip === 'string' ? ipify.ip : null,\n city: null,\n region: null,\n country: null,\n org: null,\n timezone: null,\n error: null,\n }\n }\n\n await withTimeout(\n debugPage.goto('https://ipapi.co/json/', { waitUntil: 'domcontentloaded', timeout: 7_000 }),\n 8_000,\n 'browser network location navigation',\n )\n const body = await debugPage.locator('body').innerText({ timeout: 2_000 })\n const data = JSON.parse(body) as Record<string, unknown>\n return {\n source: 'ipapi.co',\n ip: typeof data.ip === 'string' ? data.ip : null,\n city: typeof data.city === 'string' ? data.city : null,\n region: typeof data.region === 'string' ? data.region : null,\n country: typeof data.country_name === 'string' ? data.country_name : typeof data.country === 'string' ? data.country : null,\n org: typeof data.org === 'string' ? data.org : null,\n timezone: typeof data.timezone === 'string' ? data.timezone : null,\n error: null,\n }\n } catch (err) {\n return fallback(errorText(err))\n } finally {\n await debugPage?.close().catch(() => {})\n }\n }\n\n private async loadJsonInDebugPage(debugPage: Page, url: string): Promise<Record<string, unknown> | null> {\n try {\n await withTimeout(\n debugPage.goto(url, { waitUntil: 'domcontentloaded', timeout: 7_000 }),\n 8_000,\n `browser network location navigation ${url}`,\n )\n const body = await debugPage.locator('body').innerText({ timeout: 2_000 })\n return JSON.parse(body) as Record<string, unknown>\n } catch {\n return null\n }\n }\n\n private async installEsbuildHelperShims(context: BrowserContext): Promise<void> {\n await context.addInitScript(() => {\n const g = globalThis as Record<string, unknown>\n if (typeof g.__name !== 'function') g.__name = (fn: unknown) => fn\n if (typeof g.__publicField !== 'function') g.__publicField = (obj: Record<string, unknown>, key: string, value: unknown) => { obj[key] = value; return value }\n })\n }\n\n async navigateToSERP(\n query: string,\n uule: UuleString | null,\n gl: string,\n hl: string,\n options?: { num?: number; debug?: boolean },\n ): Promise<{ hasPaa: boolean }> {\n const params = new URLSearchParams({ q: query, gl, hl, pws: '0' })\n if (options?.num) params.set('num', String(options.num))\n if (uule) params.set('uule', uule)\n const url = 'https://www.google.com/search?' + params.toString()\n const navDebug: SerpNavigationDebug | null = options?.debug\n ? {\n requestedUrl: url,\n finalUrl: null,\n title: null,\n bodySnippet: null,\n hasPaa: null,\n captchaDetected: null,\n googleSorryUrl: null,\n redirected: null,\n }\n : null\n if (navDebug) this.debugSnapshot.serpNavigation = navDebug\n\n try {\n await this.page!.goto(url, { waitUntil: 'domcontentloaded', timeout: 45_000 })\n } catch (err) {\n await this.updateSerpNavigationDebug(navDebug, url, { hasPaa: null, captchaDetected: null })\n const diag = await this.captureDiagnostics(url)\n throw new ExtractionError(`page.goto failed: ${(err as Error).message} | ${diag}`)\n }\n\n const captchaCount = await this.page!.locator(PAASelectors.captchaMarker).count()\n if (captchaCount > 0) {\n await this.updateSerpNavigationDebug(navDebug, url, { hasPaa: false, captchaDetected: true })\n throw new CaptchaError(this.captchaMessage())\n }\n\n const fastFound = await this.page!.waitForSelector(PAASelectors.item, { timeout: 4_000 }).catch(() => null)\n if (fastFound) {\n await this.updateSerpNavigationDebug(navDebug, url, { hasPaa: true, captchaDetected: false })\n return { hasPaa: true }\n }\n\n const captchaAfter = await this.page!.locator(PAASelectors.captchaMarker).count()\n if (captchaAfter > 0) {\n await this.updateSerpNavigationDebug(navDebug, url, { hasPaa: false, captchaDetected: true })\n throw new CaptchaError(this.captchaMessage())\n }\n\n for (let i = 1; i <= 6; i++) {\n await this.page!.evaluate((f: number) => { window.scrollTo(0, document.body.scrollHeight * f) }, i / 6)\n await this.page!.waitForTimeout(600)\n const count = await this.page!.locator(PAASelectors.item).count()\n if (count > 0) {\n await this.updateSerpNavigationDebug(navDebug, url, { hasPaa: true, captchaDetected: false })\n return { hasPaa: true }\n }\n }\n\n await this.updateSerpNavigationDebug(navDebug, url, { hasPaa: false, captchaDetected: false })\n return { hasPaa: false }\n }\n\n private async updateSerpNavigationDebug(\n navDebug: SerpNavigationDebug | null,\n requestedUrl: string,\n state: { hasPaa: boolean | null; captchaDetected: boolean | null },\n ): Promise<void> {\n if (!navDebug || !this.page) return\n try {\n const finalUrl = this.page.url()\n const title = await this.page.title().catch(() => '')\n const bodySnippet = await this.page.evaluate(() => {\n const text = (document.body?.innerText ?? '').replace(/\\s+/g, ' ').trim()\n return text.slice(0, 500)\n }).catch(() => '')\n const textCaptcha = /recaptcha|unusual traffic|are you a robot/i.test(bodySnippet)\n navDebug.finalUrl = finalUrl\n navDebug.title = title\n navDebug.bodySnippet = bodySnippet\n navDebug.hasPaa = state.hasPaa\n navDebug.captchaDetected = state.captchaDetected ?? textCaptcha\n navDebug.googleSorryUrl = /google\\.[^/]+\\/sorry\\//i.test(finalUrl)\n navDebug.redirected = finalUrl !== requestedUrl\n } catch (err) {\n navDebug.bodySnippet = `debug capture failed: ${errorText(err)}`\n }\n }\n\n private async captureDiagnostics(intendedUrl: string): Promise<string> {\n try {\n const finalUrl = this.page!.url()\n const title = await this.page!.title().catch(() => '')\n const bodySnippet = await this.page!.evaluate(() => {\n const t = (document.body?.innerText ?? '').replace(/\\s+/g, ' ').trim()\n return t.slice(0, 400)\n }).catch(() => '')\n const consent = /consent\\.google\\./.test(finalUrl) || /before you continue/i.test(bodySnippet)\n const recaptcha = /recaptcha|unusual traffic|are you a robot/i.test(bodySnippet)\n const flags = [\n consent ? 'CONSENT_WALL' : '',\n recaptcha ? 'BOT_CHALLENGE' : '',\n finalUrl !== intendedUrl ? 'REDIRECTED' : '',\n ].filter(Boolean).join(',')\n return `intended=${intendedUrl} | final=${finalUrl} | title=\"${title}\" | flags=[${flags}] | body=\"${bodySnippet}\"`\n } catch (e) {\n return `diagnostics-failed: ${(e as Error).message}`\n }\n }\n\n private captchaMessage(): string {\n return this.kernelClient\n ? 'Google returned a CAPTCHA on this session — retrying with a fresh session.'\n : RECAPTCHA_INSTRUCTIONS\n }\n\n async navigateTo(url: string): Promise<void> {\n try {\n await this.page!.goto(url, { waitUntil: 'domcontentloaded', timeout: 45_000 })\n } catch (err) {\n const diag = await this.captureDiagnostics(url)\n throw new ExtractionError(`page.goto failed: ${(err as Error).message} | ${diag}`)\n }\n }\n\n async navigateToChannel(channelHandle: string): Promise<void> {\n const url = buildYouTubeChannelVideosUrl(channelHandle)\n try {\n await this.page!.goto(url, { waitUntil: 'networkidle', timeout: 30_000 })\n } catch (err) {\n const diag = await this.captureDiagnostics(url)\n throw new ExtractionError(`navigateToChannel failed: ${(err as Error).message} | ${diag}`)\n }\n }\n\n async evaluate<T>(fn: (...args: unknown[]) => T | Promise<T>, arg?: unknown): Promise<T> {\n return (this.page! as { evaluate(fn: unknown, arg?: unknown): Promise<T> }).evaluate(fn, arg)\n }\n\n getPage(): Page {\n return this.page!\n }\n\n getKernelSessionId(): string | null {\n return this.kernelSessionId\n }\n\n getDebugSnapshot(): BrowserDebugSnapshot {\n return this.debugSnapshot\n }\n\n async close(): Promise<BrowserCloseResult> {\n if (this.browser) {\n const b = this.browser\n const sessionId = this.kernelSessionId\n const client = this.kernelClient\n this.browser = null\n this.context = null\n this.page = null\n this.kernelSessionId = null\n this.kernelClient = null\n if (client && sessionId) {\n console.info(JSON.stringify({\n event: 'kernel_browser_delete_started',\n kernel_session_id: sessionId,\n }))\n const deleteSession = withTimeout(\n client.browsers.deleteByID(sessionId),\n KERNEL_SESSION_DELETE_TIMEOUT_MS,\n `Kernel session ${sessionId} delete`,\n )\n const closeBrowser = withTimeout(\n b.close(),\n KERNEL_BROWSER_CLOSE_TIMEOUT_MS,\n `Kernel browser ${sessionId} close`,\n )\n const [deleteResult, closeResult] = await Promise.allSettled([deleteSession, closeBrowser])\n const result: BrowserCloseResult = {\n kernelSessionId: sessionId,\n kernelDeleteStarted: true,\n kernelDeleteSucceeded: deleteResult.status === 'fulfilled',\n kernelDeleteError: deleteResult.status === 'rejected'\n ? (deleteResult.reason instanceof Error ? deleteResult.reason.message : String(deleteResult.reason))\n : null,\n browserCloseSucceeded: closeResult.status === 'fulfilled',\n browserCloseError: closeResult.status === 'rejected'\n ? (closeResult.reason instanceof Error ? closeResult.reason.message : String(closeResult.reason))\n : null,\n }\n if (deleteResult.status === 'rejected') {\n console.warn(JSON.stringify({\n event: 'kernel_browser_delete_failed',\n kernel_session_id: sessionId,\n message: result.kernelDeleteError,\n }))\n console.warn(`Kernel session cleanup failed for ${sessionId}:`, deleteResult.reason)\n } else {\n console.info(JSON.stringify({\n event: 'kernel_browser_delete_succeeded',\n kernel_session_id: sessionId,\n }))\n }\n if (closeResult.status === 'rejected') {\n console.warn(JSON.stringify({\n event: 'kernel_browser_close_failed',\n kernel_session_id: sessionId,\n message: result.browserCloseError,\n }))\n console.warn(`Kernel browser close failed for ${sessionId}:`, closeResult.reason)\n }\n return result\n }\n await b.close()\n return {\n kernelSessionId: null,\n kernelDeleteStarted: false,\n kernelDeleteSucceeded: null,\n kernelDeleteError: null,\n browserCloseSucceeded: true,\n browserCloseError: null,\n }\n } else if (this.context) {\n const ctx = this.context\n this.context = null\n this.page = null\n await ctx.close()\n return {\n kernelSessionId: null,\n kernelDeleteStarted: false,\n kernelDeleteSucceeded: null,\n kernelDeleteError: null,\n browserCloseSucceeded: true,\n browserCloseError: null,\n }\n }\n return {\n kernelSessionId: null,\n kernelDeleteStarted: false,\n kernelDeleteSucceeded: null,\n kernelDeleteError: null,\n browserCloseSucceeded: null,\n browserCloseError: null,\n }\n }\n}\n","export const PAASelectors = {\n container: '.eJH8qe.adDDi',\n dataInitq: '[data-initq]',\n item: '.related-question-pair',\n itemDataQ: 'data-q',\n itemDataInitQ: 'data-initq',\n itemQuestionEl: '.JlqpRe',\n answerContainer: '.bCOlv, .hgKElc, .wDYxhc, .LGOjhe, .fo7IQd, .fmW3u',\n sourceTitle: 'h3',\n sourceSite: '.VuuXrf',\n sourceCite: 'cite',\n clickTarget: '.JlqpRe',\n expandedClass: 'aoRk1c',\n captchaMarker: '#captcha-form, #recaptcha, form[action*=\"/sorry/\"], .g-recaptcha, [data-sitekey]',\n} as const\n\nexport const VideoSelectors = {\n container: 'div[jscontroller=\"HWk0Gf\"]',\n sectionHeading: '.mgAbYb[role=\"heading\"]',\n item: 'a.rIRoqf',\n} as const\n\nexport const ShortVideoSelectors = {\n udm: '39',\n item: 'a.rIRoqf',\n durationPattern: /^\\d+:\\d+$/,\n platforms: ['YouTube', 'TikTok', 'Instagram', 'Facebook', 'X'],\n} as const\n\nexport const ForumSelectors = {\n section: '.ULSxyf',\n item: 'a.KYg7td.INpicf',\n title: '.hyYc0c',\n source: '.K4ETW',\n} as const\n\nexport const WhatPeopleSayingSelectors = {\n sectionTag: 'g-section-with-header',\n sectionHeadingText: 'What people are saying',\n card: '.dRzkFf[role=\"listitem\"]',\n cardLink: 'a.WlydOe[jsname=\"YKoRaf\"]',\n titleH1: 'h1.WQWxe',\n titleDiv: '.eAaXgc',\n popularCommentLabel: '.qgdis',\n source: '.sTl1Td',\n platformBadge: '.appd0, .KrMNbf',\n ytChannel: '.sjVJQd',\n ytDate: '.PLq9Je',\n authorNote: '.nDgy9d',\n} as const\n\nexport const AIOverviewSelectors = {\n root: '[data-lhcontainer][data-streaming-container][eid]',\n legacyRoot: '[data-hveid=\"CBMQAA\"]',\n wrapper: '.Fgyi2e',\n controller: '[jscontroller=\"AkrxPe\"]',\n contentSubtree: '[data-subtree=\"mfc\"]',\n header: '.heWuVc',\n heading: '.Fzsovc.cwYVJe.RJPOee',\n showMoreButton: '[aria-label=\"Show more AI Overview\"]',\n sourcesPanel: '.OZ9ddf.WAUd4',\n disclaimer: '.DuQANe.MSJHRb',\n} as const\n\nexport const AIModeSelectors = {\n root: '[data-hveid=\"CAUQAA\"]',\n wrapper: '.Fgyi2e',\n citations: '.Fgyi2e [data-hveid] a[jsname=\"pxBnId\"]',\n} as const\n\nexport const OrganicSelectors = {\n result: '.wHYlTd.tF2Cxc',\n title: 'h3.LC20lb',\n siteName: '.VuuXrf',\n cite: 'cite.tjvcx',\n snippet: '.VwiC3b',\n redditCite: 'cite.qLRx3b',\n ratingWrap: '.Y0A0hc',\n ratingValue: '.yi40Hd',\n reviewCount: '.RDApEe',\n} as const\n\nexport const LocalPackSelectors = {\n headingText: 'Businesses',\n card: '.w7Dbne',\n name: '.OSrXXb',\n ratingValue: '.yi40Hd',\n reviewCount: '.RDApEe',\n} as const\n\nexport const SELECTORS_VERSION = '2026-05-07'\n\nexport const MapsSelectors = {\n ratingAndCount: 'div.F7nice',\n hoursTable: 'table.eK4R0e',\n reviewScrollPane: 'div.m6QErb[tabindex=\"-1\"]',\n reviewScrollPaneFallback: '[role=\"main\"] div[tabindex=\"-1\"]',\n reviewCardAuthor: 'div.d4r55, span.d4r55, span.RPZfBb',\n reviewCardDate: 'span.rsqaWe',\n reviewCardText: 'span.wiI7pd',\n reviewCardOwnerBlock: 'div.CDe7pd',\n hoursTableAlt: 'table[aria-label*=\"Hour\"]',\n reviewCard: '[data-review-id]',\n reviewStars: '[role=\"img\"][aria-label*=\"star\"]',\n reviewTab: 'button[role=\"tab\"][aria-label*=\"Review\"]',\n aboutTab: 'button[role=\"tab\"][aria-label*=\"About\"]',\n expandReview: '[data-review-id] button[aria-label*=\"See more\"], [data-review-id] button.w8nwRe',\n} as const\n\nexport const MAPS_SELECTORS_VERSION = '2026-05-23'\n","export const RECAPTCHA_INSTRUCTIONS = 'Google returned a CAPTCHA. Run with --headless=false to re-warm the browser profile, then retry.'\n\nexport function sanitizeVendorName(message: string): string {\n return message\n .replace(/kernel\\.sh\\s+sessions?/gi, 'sessions')\n .replace(/kernel\\.sh\\s+session/gi, 'this session')\n .replace(/kernel\\.sh/gi, 'the service')\n .replace(/kernel\\s+sessions?/gi, 'sessions')\n .replace(/kernel\\s+session/gi, 'this session')\n .replace(/\\bkernel\\b/gi, 'the service')\n .replace(/ +/g, ' ')\n .trim()\n}\n\nexport class CaptchaError extends Error {\n readonly name = 'CaptchaError'\n constructor(public readonly instructions: string) {\n super(`CAPTCHA detected. ${instructions}`)\n }\n}\n\nexport class ExtractionError extends Error {\n readonly name = 'ExtractionError'\n constructor(message: string, public readonly cause?: unknown) {\n super(message)\n }\n}\n\nexport class RequestAbortedError extends Error {\n readonly name = 'RequestAbortedError'\n constructor(message = 'Request aborted before harvest completed') {\n super(message)\n }\n}\n","import type { CanonicalLocationName } from './types.js'\n\nexport const LOCATIONS: Record<string, CanonicalLocationName> = {\n 'austin': 'Austin,Texas,United States',\n 'new york': 'New York,New York,United States',\n 'new york city': 'New York,New York,United States',\n 'nyc': 'New York,New York,United States',\n 'los angeles': 'Los Angeles,California,United States',\n 'la': 'Los Angeles,California,United States',\n 'chicago': 'Chicago,Illinois,United States',\n 'houston': 'Houston,Texas,United States',\n 'phoenix': 'Phoenix,Arizona,United States',\n 'philadelphia': 'Philadelphia,Pennsylvania,United States',\n 'philly': 'Philadelphia,Pennsylvania,United States',\n 'san antonio': 'San Antonio,Texas,United States',\n 'dallas': 'Dallas,Texas,United States',\n 'miami': 'Miami,Florida,United States',\n 'seattle': 'Seattle,Washington,United States',\n 'denver': 'Denver,Colorado,United States',\n 'loveland': 'Loveland,Colorado,United States',\n 'loveland co': 'Loveland,Colorado,United States',\n 'fort collins': 'Fort Collins,Colorado,United States',\n 'boulder': 'Boulder,Colorado,United States',\n 'colorado springs': 'Colorado Springs,Colorado,United States',\n 'boston': 'Boston,Massachusetts,United States',\n 'atlanta': 'Atlanta,Georgia,United States',\n 'san francisco': 'San Francisco,California,United States',\n 'sf': 'San Francisco,California,United States',\n 'portland': 'Portland,Oregon,United States',\n 'las vegas': 'Las Vegas,Nevada,United States',\n 'minneapolis': 'Minneapolis,Minnesota,United States',\n 'detroit': 'Detroit,Michigan,United States',\n 'nashville': 'Nashville,Tennessee,United States',\n 'charlotte': 'Charlotte,North Carolina,United States',\n 'orlando': 'Orlando,Florida,United States',\n 'san diego': 'San Diego,California,United States',\n 'baltimore': 'Baltimore,Maryland,United States',\n 'sacramento': 'Sacramento,California,United States',\n 'columbus': 'Columbus,Ohio,United States',\n 'indianapolis': 'Indianapolis,Indiana,United States',\n 'san jose': 'San Jose,California,United States',\n 'fort worth': 'Fort Worth,Texas,United States',\n 'jacksonville': 'Jacksonville,Florida,United States',\n 'memphis': 'Memphis,Tennessee,United States',\n 'louisville': 'Louisville,Kentucky,United States',\n 'raleigh': 'Raleigh,North Carolina,United States',\n 'richmond': 'Richmond,Virginia,United States',\n 'salt lake city': 'Salt Lake City,Utah,United States',\n 'toronto': 'Toronto,Ontario,Canada',\n 'vancouver': 'Vancouver,British Columbia,Canada',\n 'montreal': 'Montreal,Quebec,Canada',\n 'calgary': 'Calgary,Alberta,Canada',\n 'ottawa': 'Ottawa,Ontario,Canada',\n 'london': 'London,England,United Kingdom',\n 'manchester': 'Manchester,England,United Kingdom',\n 'birmingham': 'Birmingham,England,United Kingdom',\n 'edinburgh': 'Edinburgh,Scotland,United Kingdom',\n 'glasgow': 'Glasgow,Scotland,United Kingdom',\n 'leeds': 'Leeds,England,United Kingdom',\n 'sydney': 'Sydney,New South Wales,Australia',\n 'melbourne': 'Melbourne,Victoria,Australia',\n 'brisbane': 'Brisbane,Queensland,Australia',\n 'perth': 'Perth,Western Australia,Australia',\n 'adelaide': 'Adelaide,South Australia,Australia',\n 'dublin': 'Dublin,Leinster,Ireland',\n}\n","import type { CanonicalLocationName, UuleString } from './types.js'\nimport { LOCATIONS } from './locations.js'\n\nfunction encodeVarint(value: number): number[] {\n const bytes: number[] = []\n let remaining = value\n do {\n let byte = remaining & 0x7f\n remaining >>>= 7\n if (remaining > 0) byte |= 0x80\n bytes.push(byte)\n } while (remaining > 0)\n return bytes\n}\n\nexport function encodeUule(name: CanonicalLocationName): UuleString {\n const locationBytes = Buffer.from(name, 'utf8')\n const payload = Buffer.concat([\n Buffer.from([0x08, 0x02, 0x10, 0x20, 0x22]),\n Buffer.from(encodeVarint(locationBytes.length)),\n locationBytes,\n ])\n return `w+${payload.toString('base64')}`\n}\n\nexport function normalizeLocation(input: string): CanonicalLocationName {\n const raw = input.toLowerCase().trim()\n if (LOCATIONS[raw]) return LOCATIONS[raw] as CanonicalLocationName\n const beforeComma = raw.split(',')[0].trim()\n if (beforeComma !== raw && LOCATIONS[beforeComma]) return LOCATIONS[beforeComma] as CanonicalLocationName\n const withoutState = raw.replace(/\\s+[a-z]{2}$/, '').trim()\n if (withoutState !== raw && LOCATIONS[withoutState]) return LOCATIONS[withoutState] as CanonicalLocationName\n return input as CanonicalLocationName\n}\n","import type { CanonicalLocationName, LocalPackBusiness, OrganicResult, SerpLocationCandidate, SerpLocationEvidence } from './types.js'\n\nconst STATE_TO_CODE: Record<string, string> = {\n alabama: 'AL', alaska: 'AK', arizona: 'AZ', arkansas: 'AR', california: 'CA',\n colorado: 'CO', connecticut: 'CT', delaware: 'DE', florida: 'FL', georgia: 'GA',\n hawaii: 'HI', idaho: 'ID', illinois: 'IL', indiana: 'IN', iowa: 'IA',\n kansas: 'KS', kentucky: 'KY', louisiana: 'LA', maine: 'ME', maryland: 'MD',\n massachusetts: 'MA', michigan: 'MI', minnesota: 'MN', mississippi: 'MS', missouri: 'MO',\n montana: 'MT', nebraska: 'NE', nevada: 'NV', 'new hampshire': 'NH', 'new jersey': 'NJ',\n 'new mexico': 'NM', 'new york': 'NY', 'north carolina': 'NC', 'north dakota': 'ND', ohio: 'OH',\n oklahoma: 'OK', oregon: 'OR', pennsylvania: 'PA', 'rhode island': 'RI', 'south carolina': 'SC',\n 'south dakota': 'SD', tennessee: 'TN', texas: 'TX', utah: 'UT', vermont: 'VT',\n virginia: 'VA', washington: 'WA', 'west virginia': 'WV', wisconsin: 'WI', wyoming: 'WY',\n 'district of columbia': 'DC',\n}\n\nconst STATE_PATTERN = [\n ...Object.keys(STATE_TO_CODE).map(s => s.replace(/\\s+/g, '\\\\s+')),\n ...Object.values(STATE_TO_CODE),\n].join('|')\n\nconst CITY_STATE_RE = new RegExp(`\\\\b([A-Z][A-Za-z]+(?:[\\\\s.-][A-Z][A-Za-z]+){0,4}),?\\\\s+(${STATE_PATTERN})\\\\b`, 'gi')\n\nfunction normalizeRegionCode(input: string | null | undefined): string | null {\n if (!input) return null\n const trimmed = input.trim()\n if (/^[A-Z]{2}$/i.test(trimmed)) return trimmed.toUpperCase()\n return STATE_TO_CODE[trimmed.toLowerCase()] ?? null\n}\n\nfunction normalizeCity(input: string): string {\n const cleaned = input\n .replace(/\\s+/g, ' ')\n .trim()\n .replace(/^.*\\b(?:in|near|around|serving)\\s+/i, '')\n return cleaned.toLowerCase().replace(/\\b[a-z]/g, char => char.toUpperCase())\n}\n\nfunction parseExpected(canonicalLocation: CanonicalLocationName | null): SerpLocationEvidence['expected'] {\n if (!canonicalLocation) return null\n const [city = '', region = ''] = canonicalLocation.split(',').map(part => part.trim())\n return {\n city: normalizeCity(city),\n regionCode: normalizeRegionCode(region),\n canonicalLocation,\n }\n}\n\nfunction addCandidate(\n candidates: Map<string, SerpLocationCandidate>,\n city: string,\n region: string,\n example: string,\n): void {\n const normalizedCity = normalizeCity(city)\n const regionCode = normalizeRegionCode(region)\n if (!normalizedCity || !regionCode) return\n const key = `${normalizedCity.toLowerCase()}|${regionCode}`\n const existing = candidates.get(key)\n if (existing) {\n existing.count++\n if (existing.examples.length < 3 && !existing.examples.includes(example)) existing.examples.push(example)\n return\n }\n candidates.set(key, { city: normalizedCity, regionCode, count: 1, examples: [example] })\n}\n\nfunction scanText(candidates: Map<string, SerpLocationCandidate>, text: string): void {\n const normalized = decodeURIComponent(text).replace(/[+/|_-]+/g, ' ')\n for (const match of normalized.matchAll(CITY_STATE_RE)) {\n addCandidate(candidates, match[1] ?? '', match[2] ?? '', normalized.slice(0, 180))\n }\n}\n\nexport function inferSerpLocationEvidence(\n canonicalLocation: CanonicalLocationName | null,\n organicResults: OrganicResult[],\n localPack: LocalPackBusiness[],\n): SerpLocationEvidence {\n const expected = parseExpected(canonicalLocation)\n const candidates = new Map<string, SerpLocationCandidate>()\n\n for (const result of organicResults) {\n scanText(candidates, [result.title, result.snippet ?? '', result.cite ?? '', result.url].join(' '))\n }\n for (const business of localPack) {\n scanText(candidates, [business.name, ...business.metadata, business.websiteUrl ?? '', business.directionsUrl ?? ''].join(' '))\n }\n\n const rankedCandidates = Array.from(candidates.values())\n .sort((a, b) => b.count - a.count || a.city.localeCompare(b.city))\n .slice(0, 8)\n\n if (!expected) {\n return { status: 'not_requested', expected: null, candidates: rankedCandidates }\n }\n if (rankedCandidates.length === 0) {\n return { status: 'unknown', expected, candidates: [] }\n }\n\n const matched = rankedCandidates.some(candidate =>\n candidate.city.toLowerCase() === expected.city.toLowerCase()\n && (expected.regionCode == null || candidate.regionCode === expected.regionCode)\n )\n\n return {\n status: matched ? 'matched' : 'mismatch',\n expected,\n candidates: rankedCandidates,\n }\n}\n","const MAX_ANSWER_LENGTH = 1200\n\nconst BOILERPLATE_PATTERNS: RegExp[] = [\n /An AI Overview is not available for this search/gi,\n /Can't generate an AI overview right now\\.?\\s*Try again later\\.?/gi,\n /\\bAI Overview\\b/gi,\n /\\bView all\\b/gi,\n]\n\nconst CUT_MARKERS: RegExp[] = [\n /\\bRelated Links\\b/i,\n /\\bAsk anything in\\s*AI Mode\\b/i,\n /\\bAI can make mistakes\\b/i,\n /\\bThis is for informational purposes only\\b/i,\n /\\bShow more\\b/i,\n /\\b\\d+\\s+sites\\b/i,\n /\\b\\d{1,2}\\s*[msh]\\s*[A-Z][A-Za-z]/,\n /\\b(?:YouTube|Reddit|Facebook|Instagram|TikTok)·/,\n]\n\nfunction normalizeWhitespace(text: string): string {\n return text\n .replace(/\\u00a0/g, ' ')\n .replace(/([.!?])([A-Z])/g, '$1 $2')\n .replace(/([:;])([A-Z])/g, '$1 $2')\n .replace(/([a-z])([A-Z][a-z])/g, '$1 $2')\n .replace(/(\\d)([A-Z][a-z])/g, '$1 $2')\n .replace(/([a-z])(\\d)/g, '$1 $2')\n .replace(/\\s+/g, ' ')\n .trim()\n}\n\nfunction cutAtFirstMarker(text: string): string {\n let cutAt = -1\n for (const marker of CUT_MARKERS) {\n const match = marker.exec(text)\n marker.lastIndex = 0\n if (match && (cutAt === -1 || match.index < cutAt)) cutAt = match.index\n }\n return cutAt === -1 ? text : text.slice(0, cutAt)\n}\n\nfunction cutAtSourceTitle(text: string, sourceTitle?: string): string {\n const title = sourceTitle?.trim()\n if (!title || title.length < 8) return text\n const idx = text.toLowerCase().indexOf(title.toLowerCase())\n return idx > 40 ? text.slice(0, idx) : text\n}\n\nfunction findAttributionCut(beforeUrl: string): number {\n const dateMatch = beforeUrl.match(/[•·]\\s*(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[a-z]*\\.?\\s+\\d{1,2},\\s+\\d{4}/i)\n if (dateMatch?.index && dateMatch.index > 40) return dateMatch.index\n\n const start = Math.max(0, beforeUrl.length - 260)\n const tail = beforeUrl.slice(start)\n const sentenceBreaks = [...tail.matchAll(/[.!?]\\s*(?=[A-Z][A-Za-z0-9\"'$])/g)]\n for (const match of sentenceBreaks) {\n const remainder = tail.slice(match.index + 1).trim()\n const lead = remainder.slice(0, 160)\n const looksLikeTitle = /^(?:Best|Top|What|How|Why|When|Where|Which|Can|Should|Is|Are|Do|Does)\\b/i.test(remainder)\n if (\n remainder.length > 20 &&\n looksLikeTitle &&\n /(?:\\s[-|]\\s|Heating|Cooling|Company|Services|Blog|Guide|Review)/i.test(lead)\n ) {\n return start + match.index + 1\n }\n }\n const last = sentenceBreaks.at(-1)\n if (last?.index !== undefined) return start + last.index + 1\n\n return beforeUrl.length\n}\n\nfunction cutAtUrlAttribution(text: string): string {\n const urlMatch = text.match(/https?:\\/\\/\\S+/i)\n if (!urlMatch?.index) return text\n\n const beforeUrl = text.slice(0, urlMatch.index)\n return beforeUrl.slice(0, findAttributionCut(beforeUrl))\n}\n\nfunction trimToSentenceLimit(text: string): string {\n if (text.length <= MAX_ANSWER_LENGTH) return text\n const slice = text.slice(0, MAX_ANSWER_LENGTH)\n const lastSentence = Math.max(slice.lastIndexOf('.'), slice.lastIndexOf('!'), slice.lastIndexOf('?'))\n return (lastSentence > 240 ? slice.slice(0, lastSentence + 1) : slice).trim()\n}\n\nexport function cleanPAAAnswerText(\n answer: string | null | undefined,\n question?: string,\n sourceTitle?: string,\n): string | undefined {\n if (!answer) return undefined\n\n let text = normalizeWhitespace(answer)\n const normalizedQuestion = question ? normalizeWhitespace(question) : ''\n if (normalizedQuestion && text.toLowerCase().startsWith(normalizedQuestion.toLowerCase())) {\n text = text.slice(normalizedQuestion.length).trim()\n }\n\n if (/^An error has occurred\\.?\\s*Please try again later\\.?/i.test(text)) {\n return undefined\n }\n\n for (const pattern of BOILERPLATE_PATTERNS) {\n text = text.replace(pattern, ' ')\n }\n text = text\n .replace(/\\b[A-Z][A-Za-z&'\\u2019 -]{2,60}\\+\\d+\\b/g, ' ')\n .replace(/\\b(?:[a-z0-9-]+\\.)+[a-z]{2,}\\+\\d+\\b/gi, ' ')\n\n text = normalizeWhitespace(text)\n text = cutAtFirstMarker(text)\n text = cutAtSourceTitle(text, sourceTitle)\n text = cutAtUrlAttribution(text)\n text = normalizeWhitespace(text)\n text = text.replace(/\\s+(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[a-z]*\\.?\\s+\\d{1,2},\\s+\\d{4}$/i, '').trim()\n text = trimToSentenceLimit(text)\n\n if (!text) return undefined\n if (/^An error has occurred\\.?\\s*Please try again later\\.?$/i.test(text)) return undefined\n\n return text\n}\n","export interface AISurfaceSelectorConfig {\n aio: {\n root: string\n legacyRoot?: string\n wrapper?: string\n controller: string\n contentSubtree: string\n heading: string\n header: string\n showMoreButton: string\n sourcesPanel: string\n disclaimer: string\n }\n aim: {\n root: string\n wrapper: string\n }\n expandWaitMs?: number\n}\n\nexport async function extractAISurfacesFromDocument(config?: AISurfaceSelectorConfig): Promise<{\n surface: 'web' | 'aim' | 'unknown'\n aiOverview: {\n detected: boolean\n text: string | null\n citations: Array<{ text: string; href: string }>\n expanded: boolean\n fullyExpanded: boolean\n sections: string[]\n }\n aiMode: {\n detected: boolean\n text: string | null\n citations: Array<{ text: string; href: string }>\n }\n}> {\n const selectors = config ?? {\n aio: {\n root: '[data-lhcontainer][data-streaming-container][eid]',\n legacyRoot: '[data-hveid=\"CBMQAA\"]',\n wrapper: '.Fgyi2e',\n controller: '[jscontroller=\"AkrxPe\"]',\n contentSubtree: '[data-subtree=\"mfc\"]',\n heading: '.Fzsovc.cwYVJe.RJPOee',\n header: '.heWuVc',\n showMoreButton: '[aria-label=\"Show more AI Overview\"]',\n sourcesPanel: '.OZ9ddf.WAUd4',\n disclaimer: '.DuQANe.MSJHRb',\n },\n aim: {\n root: '[data-hveid=\"CAUQAA\"]',\n wrapper: '.Fgyi2e',\n },\n expandWaitMs: 1500,\n }\n\n const sn: string = (window as unknown as { google?: { sn?: string } }).google?.sn ?? 'unknown'\n const surface: 'web' | 'aim' | 'unknown' =\n sn === 'aim' ? 'aim' : sn === 'web' ? 'web' : 'unknown'\n\n function textOf(el: Element | null): string {\n if (!el) return ''\n return ((el as HTMLElement).innerText ?? el.textContent ?? '').trim()\n }\n\n function hasAIOverviewLabel(el: Element): boolean {\n const heading = el.querySelector(selectors.aio.heading)\n if (textOf(heading) === 'AI Overview') return true\n const header = el.querySelector(selectors.aio.header)\n if (textOf(header).split(/\\n|\\s{2,}/).some(part => part.trim() === 'AI Overview')) return true\n return textOf(el).includes('AI Overview')\n }\n\n function findAIORoot(): Element | null {\n const primaryRoots = Array.from(document.querySelectorAll(selectors.aio.root))\n const labeledPrimary = primaryRoots.find(hasAIOverviewLabel)\n if (labeledPrimary) return labeledPrimary\n if (primaryRoots.length > 0) return primaryRoots[0]\n\n if (selectors.aio.legacyRoot) {\n const legacy = document.querySelector(selectors.aio.legacyRoot)\n if (legacy) return legacy\n }\n\n const headings = document.querySelectorAll(`${selectors.aio.heading}, h1, h2, h3, [role=\"heading\"]`)\n for (const h of headings) {\n if (textOf(h) !== 'AI Overview') continue\n let el: Element | null = h.parentElement\n for (let i = 0; i < 8 && el; i++) {\n if (\n el.matches(selectors.aio.root) ||\n el.querySelector(selectors.aio.controller) ||\n el.querySelector(selectors.aio.contentSubtree)\n ) {\n return el\n }\n el = el.parentElement\n }\n return h.parentElement\n }\n return null\n }\n\n function cleanText(target: Element | null): string | null {\n if (!target) return null\n const clone = target.cloneNode(true) as Element\n clone.querySelectorAll([\n 'script',\n 'style',\n 'noscript',\n 'img',\n 'picture',\n 'video',\n selectors.aio.header,\n selectors.aio.showMoreButton,\n selectors.aio.sourcesPanel,\n selectors.aio.disclaimer,\n '[data-subtree=\"dfa\"]',\n '[data-src-id]',\n '[role=\"dialog\"]',\n '.HWMcu',\n '.bTFeG',\n '.CyMdWb',\n '.MFrAxb',\n '.F0OfWd.hfWAgb',\n '.x2qcTc.fZavHb',\n '.SvjEff',\n '.sR2MY',\n '.lKuDef',\n '.GSPQcc',\n 'a[href]',\n 'button',\n '[role=\"button\"]',\n ].join(',')).forEach(el => el.remove())\n\n const holder = document.createElement('div')\n holder.style.position = 'fixed'\n holder.style.left = '-10000px'\n holder.style.top = '0'\n holder.style.width = `${Math.max(320, Math.round((target as HTMLElement).getBoundingClientRect?.().width || 960))}px`\n holder.style.opacity = '0'\n holder.style.pointerEvents = 'none'\n holder.append(clone)\n document.body.append(holder)\n\n const rendered = ((clone as HTMLElement).innerText || clone.textContent || '')\n holder.remove()\n\n const lines = rendered\n .replace(/\\r/g, '')\n .replace(/[ \\t]+\\n/g, '\\n')\n .replace(/\\n[ \\t]+/g, '\\n')\n .replace(/\\n{3,}/g, '\\n\\n')\n .replace(/[ \\t]{2,}/g, ' ')\n .trim()\n .split('\\n')\n .map(line => line.replace(/\\u00a0/g, ' ').trim())\n .filter(Boolean)\n\n const filteredLines: string[] = []\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]\n const next = lines[i + 1] ?? ''\n if (line === 'AI Overview') continue\n if (line === 'Show more') continue\n if (/^AI can make mistakes/i.test(line)) continue\n if (/^Thank you\\b/i.test(line)) continue\n if (/^Your feedback helps Google improve/i.test(line)) continue\n if (/^\\+?\\d+$/.test(line)) continue\n if (/^\\+\\d+$/.test(next) && line.length <= 80) {\n i++\n continue\n }\n filteredLines.push(line)\n }\n\n const raw = filteredLines\n .join('\\n')\n .replace(/\\n{3,}/g, '\\n\\n')\n .trim()\n\n if (!raw || /not available|try again|can't generate/i.test(raw)) return null\n return raw\n }\n\n function normalizeHref(rawHref: string): string | null {\n if (!rawHref || rawHref.startsWith('javascript:')) return null\n let href = rawHref\n try {\n const absolute = new URL(rawHref, window.location.href)\n const q = absolute.searchParams.get('q') ?? absolute.searchParams.get('url')\n if (/(\\.|^)google\\./i.test(absolute.hostname) && q?.startsWith('http')) {\n href = q\n } else {\n href = absolute.href\n }\n } catch {\n return null\n }\n\n if (!/^https?:\\/\\//i.test(href)) return null\n try {\n const url = new URL(href)\n const isGoogleInternal = /(\\.|^)google\\./i.test(url.hostname)\n if (isGoogleInternal) return null\n return url.href\n } catch {\n return null\n }\n }\n\n function extractCitations(root: Element | null): Array<{ text: string; href: string }> {\n if (!root) return []\n const seen = new Set<string>()\n const citations: Array<{ text: string; href: string }> = []\n\n for (const a of Array.from(root.querySelectorAll('a[href]'))) {\n const href = normalizeHref(a.getAttribute('href') ?? '')\n if (!href || seen.has(href)) continue\n seen.add(href)\n\n let fallbackHost = ''\n try {\n fallbackHost = new URL(href).hostname.replace(/^www\\./, '')\n } catch {}\n\n citations.push({\n text: textOf(a) || fallbackHost || href,\n href,\n })\n }\n\n return citations\n }\n\n async function maybeExpand(root: Element): Promise<boolean> {\n const button = root.querySelector(selectors.aio.showMoreButton)\n if (!button || button.getAttribute('aria-expanded') !== 'false') return false\n ;(button as HTMLElement).click()\n const waitMs = selectors.expandWaitMs ?? 1500\n if (waitMs > 0) await new Promise(resolve => setTimeout(resolve, waitMs))\n return true\n }\n\n const aioRoot = findAIORoot()\n let aioText: string | null = null\n let aioCitations: Array<{ text: string; href: string }> = []\n let aioExpanded = false\n let aioFullyExpanded = false\n let aioSections: string[] = []\n\n if (aioRoot) {\n aioExpanded = await maybeExpand(aioRoot)\n const controller = aioRoot.querySelector(selectors.aio.controller)\n const contentSubtree = aioRoot.querySelector(selectors.aio.contentSubtree)\n const showMore = aioRoot.querySelector(selectors.aio.showMoreButton)\n aioFullyExpanded =\n controller?.getAttribute('data-trnct') === 'false' ||\n showMore?.getAttribute('aria-expanded') === 'true' ||\n !showMore\n\n aioText = cleanText(contentSubtree ?? controller ?? aioRoot)\n aioSections = (aioText ?? '')\n .split('\\n')\n .map(line => line.trim())\n .filter(line => /^\\d+\\.\\s+.+/.test(line))\n aioCitations = extractCitations(aioRoot)\n }\n\n const aimRoot = document.querySelector(selectors.aim.root)\n const aimDetected = surface === 'aim' && !!aimRoot\n const aimContainer = aimRoot?.closest(selectors.aim.wrapper) ?? aimRoot\n const aimText = cleanText(aimContainer)\n const aimCitations = aimDetected ? extractCitations(aimContainer) : []\n\n return {\n surface,\n aiOverview: {\n detected: !!aioRoot && aioText !== null,\n text: aioText,\n citations: aioCitations,\n expanded: aioExpanded,\n fullyExpanded: aioFullyExpanded,\n sections: aioSections,\n },\n aiMode: {\n detected: aimDetected && aimText !== null,\n text: aimText,\n citations: aimCitations,\n },\n }\n}\n","import type { Page } from 'playwright'\nimport type { IBrowserDriver } from '../driver/IBrowserDriver.js'\nimport type { IProgressReporter } from '../output/IProgressReporter.js'\nimport { PAASelectors, VideoSelectors, ForumSelectors, ShortVideoSelectors, AIOverviewSelectors, AIModeSelectors, WhatPeopleSayingSelectors, OrganicSelectors, LocalPackSelectors } from '../selectors.js'\nimport { encodeUule, normalizeLocation } from '../uule.js'\nimport { inferSerpLocationEvidence } from '../serp-location-debug.js'\nimport { RawPAAItemSchema } from '../schemas.js'\nimport { cleanPAAAnswerText } from '../lib/paa-answer-cleanup.js'\nimport { CaptchaError, RequestAbortedError } from '../errors.js'\nimport { extractAISurfacesFromDocument } from './ai-surfaces.js'\nimport type {\n HarvestOptions, HarvestResult, HarvestStats,\n RawPAAItem, PAANode, FlatRow, NormalizedQuestionKey, DriverConfig,\n VideoResult, ForumResult, AIOverviewResult, AIModeResult, GoogleSurface,\n WhatPeopleSayingCard, EntityIds, EntityRecord, HarvestDiagnosticWarning,\n OrganicResult, LocalPackBusiness, BrowserDebugSnapshot, HarvestDebugSnapshot, SerpLocationEvidence,\n} from '../types.js'\nimport type { IPAAExtractor } from './IPAAExtractor.js'\n\nconst DESKTOP_USER_AGENT =\n 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36'\n\nconst MOBILE_USER_AGENT =\n 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1'\n\nexport class PAAExtractor implements IPAAExtractor {\n constructor(\n private readonly driver: IBrowserDriver,\n private readonly reporter: IProgressReporter,\n ) {}\n\n private normalizeQuestion(q: string): NormalizedQuestionKey {\n return q.toLowerCase().replace(/[^\\w\\s]/g, '').replace(/\\s+/g, ' ').trim() as NormalizedQuestionKey\n }\n\n private throwIfAborted(signal?: AbortSignal): void {\n if (!signal?.aborted) return\n if (signal.reason instanceof DOMException && signal.reason.name === 'TimeoutError') throw signal.reason\n throw new RequestAbortedError()\n }\n\n private async throwIfCaptcha(page: Page, context: string): Promise<void> {\n const captchaCount = await page.locator(PAASelectors.captchaMarker).count().catch(() => 0)\n if (captchaCount > 0) {\n throw new CaptchaError(`${context} returned a CAPTCHA — retrying with a fresh session.`)\n }\n }\n\n private async extractVisibleItems(page: Page): Promise<RawPAAItem[]> {\n const sels = PAASelectors\n const raw = await page.evaluate((selectors) => {\n function cleanText(el: Element | null): string {\n if (!el) return ''\n const parts: string[] = []\n for (const n of el.childNodes) {\n if (n.nodeType === Node.TEXT_NODE) {\n const text = n.textContent?.trim()\n if (text) parts.push(text)\n } else if (\n (n as Element).tagName === 'STYLE' ||\n (n as Element).tagName === 'SCRIPT'\n ) {\n continue\n } else {\n const text = cleanText(n as Element)\n if (text) parts.push(text)\n }\n }\n return parts.join(' ').replace(/\\s+/g, ' ').trim()\n }\n return Array.from(document.querySelectorAll(selectors.item)).map((pair) => ({\n question: pair.getAttribute(selectors.itemDataQ) || pair.getAttribute(selectors.itemDataInitQ) || '',\n answer: cleanText(pair.querySelector(selectors.answerContainer)) || undefined,\n sourceTitle: (pair.querySelector(selectors.sourceTitle) as HTMLElement | null)?.innerText?.trim() || undefined,\n sourceSite: (pair.querySelector(selectors.sourceSite) as HTMLElement | null)?.innerText?.trim() || undefined,\n sourceCite: (pair.querySelector(selectors.sourceCite) as HTMLElement | null)?.innerText?.trim() || undefined,\n }))\n }, sels)\n\n return raw.flatMap((item) => {\n const cleaned = {\n ...item,\n answer: cleanPAAAnswerText(item.answer, item.question, item.sourceTitle),\n }\n const result = RawPAAItemSchema.safeParse(cleaned)\n if (!result.success) {\n console.warn('[PAAExtractor] item parse failed:', item.question, result.error.issues[0]?.message)\n return []\n }\n return [result.data]\n })\n }\n\n private async clickItem(page: Page, questionText: string): Promise<void> {\n try {\n const pairLocator = page.locator(\n `${PAASelectors.item}[data-q=\"${questionText}\"], ${PAASelectors.item}[data-initq=\"${questionText}\"]`\n ).first()\n await pairLocator.click()\n } catch { }\n }\n\n private toFlatRow(item: RawPAAItem, depth: number, parentQuestion: string | null, seed: string): FlatRow {\n return {\n seed_query: seed,\n question: item.question,\n answer: item.answer ?? '',\n source_title: item.sourceTitle ?? '',\n source_site: item.sourceSite ?? '',\n source_cite: item.sourceCite ?? '',\n depth,\n parent_question: parentQuestion ?? '',\n extracted_at: new Date().toISOString(),\n }\n }\n\n private async runBFS(page: Page, options: HarvestOptions, signal?: AbortSignal): Promise<FlatRow[]> {\n const seenKeys = new Set<NormalizedQuestionKey>()\n const seenQs = new Set<string>()\n const orderedQs: string[] = []\n const results: FlatRow[] = []\n\n const readAllQs = (): Promise<string[]> =>\n page.evaluate(\n ({ sel, dataQ, dataInitQ, questionEl }: { sel: string; dataQ: string; dataInitQ: string; questionEl: string }) =>\n Array.from(document.querySelectorAll(sel))\n .map(el =>\n el.getAttribute(dataQ) ||\n el.getAttribute(dataInitQ) ||\n (el.querySelector(questionEl) as HTMLElement | null)?.innerText?.trim() ||\n ''\n )\n .filter(Boolean),\n { sel: PAASelectors.item, dataQ: PAASelectors.itemDataQ, dataInitQ: PAASelectors.itemDataInitQ, questionEl: PAASelectors.itemQuestionEl },\n )\n\n let round = 0\n while (seenQs.size < options.maxQuestions) {\n this.throwIfAborted(signal)\n await this.throwIfCaptcha(page, 'Google PAA expansion')\n const beforeQs = await readAllQs()\n if (beforeQs.length >= options.maxQuestions) break\n\n const unexpandedSel = `${PAASelectors.item}:not(.${PAASelectors.expandedClass}) ${PAASelectors.clickTarget}`\n const unexpandedCount = await page.locator(unexpandedSel).count()\n if (unexpandedCount === 0) break\n\n this.reporter.onDepth(++round)\n\n for (let ci = 0; ci < unexpandedCount; ci++) {\n this.throwIfAborted(signal)\n try {\n const btn = page.locator(unexpandedSel).first()\n await btn.scrollIntoViewIfNeeded()\n await btn.hover({ force: true })\n await page.waitForTimeout(100)\n await btn.click({ force: true })\n await page.waitForTimeout(500)\n } catch { }\n }\n await page.waitForFunction(\n ({ sel, min }: { sel: string; min: number }) => document.querySelectorAll(sel).length > min,\n { sel: PAASelectors.item, min: beforeQs.length },\n { timeout: 5000 },\n ).catch(() => {})\n await this.throwIfCaptcha(page, 'Google PAA expansion')\n\n const afterQs = await readAllQs()\n if (afterQs.length === beforeQs.length) break\n\n for (const q of afterQs) {\n if (!seenQs.has(q)) { seenQs.add(q); orderedQs.push(q) }\n }\n }\n\n const itemMap = new Map((await this.extractVisibleItems(page)).map(i => [i.question, i]))\n\n for (const q of orderedQs) {\n if (results.length >= options.maxQuestions) break\n const key = this.normalizeQuestion(q)\n if (seenKeys.has(key)) continue\n seenKeys.add(key)\n const item = itemMap.get(q)\n if (item) {\n results.push(this.toFlatRow(item, 1, null, options.query))\n this.reporter.onQuestion({ question: item.question, answer: item.answer ?? null, sourceTitle: item.sourceTitle ?? null, sourceSite: item.sourceSite ?? null, sourceCite: item.sourceCite ?? null, depth: 1, parentQuestion: null, children: [] })\n } else {\n results.push(this.toFlatRow({ question: q, answer: undefined, sourceTitle: undefined, sourceSite: undefined, sourceCite: undefined }, 1, null, options.query))\n }\n }\n\n return results\n }\n\n private async extractVideos(page: Page): Promise<VideoResult[]> {\n const vsels = VideoSelectors\n return page.evaluate((sels) => {\n const results: Array<{ type: 'video' | 'short_video'; title: string; channel: string; platform: string; duration: string; url: string }> = []\n const containers = Array.from(document.querySelectorAll(sels.container))\n for (const container of containers) {\n const headingEl = container.querySelector(sels.sectionHeading)\n const headingText = headingEl?.textContent?.trim() ?? ''\n const type: 'video' | 'short_video' = headingText.toLowerCase().includes('short') ? 'short_video' : 'video'\n const items = Array.from(container.querySelectorAll(sels.item))\n for (const a of items) {\n const href = (a as HTMLAnchorElement).href\n if (!href || (!href.includes('youtube') && !href.includes('youtu.be'))) continue\n const raw = a.textContent?.trim() ?? ''\n const ytIdx = raw.indexOf('YouTube')\n if (ytIdx === -1) continue\n const title = raw.slice(0, ytIdx).trim()\n const remainder = raw.slice(ytIdx + 7).replace(/^[·\\s·]+/, '')\n const channelMatch = remainder.match(/^([^·\\n]+)/)\n const channel = channelMatch ? channelMatch[1].trim() : ''\n if (title) results.push({ type, title, channel, platform: 'YouTube', duration: '', url: href })\n }\n }\n return results\n }, vsels)\n }\n\n private async extractForums(page: Page): Promise<ForumResult[]> {\n const fsels = ForumSelectors\n return page.evaluate((sels) => {\n const results: Array<{ title: string; source: string; url: string }> = []\n const sections = Array.from(document.querySelectorAll(sels.section))\n const forumSection = sections.find((s) => s.textContent?.includes('Discussions'))\n if (!forumSection) return results\n const items = Array.from(forumSection.querySelectorAll(sels.item))\n for (const a of items) {\n const href = (a as HTMLAnchorElement).href\n if (!href) continue\n const titleEl = a.querySelector(sels.title)\n const sourceEl = a.querySelector(sels.source)\n const title = titleEl?.textContent?.trim() ?? ''\n const source = sourceEl?.textContent?.trim() ?? ''\n if (title) results.push({ title, source, url: href })\n }\n return results\n }, fsels)\n }\n\n private async extractShortVideos(page: Page, shortUrl: string): Promise<VideoResult[]> {\n try {\n await page.goto(shortUrl, { waitUntil: 'domcontentloaded' })\n await page.waitForTimeout(1500)\n } catch {\n return []\n }\n await this.throwIfCaptcha(page, 'Google short video search')\n\n const svSels = {\n item: ShortVideoSelectors.item,\n platforms: [...ShortVideoSelectors.platforms] as string[],\n }\n\n const raw = await page.evaluate((sels) => {\n const seen = new Set<string>()\n const results: Array<{ title: string; channel: string; platform: string; duration: string; url: string }> = []\n const items = Array.from(document.querySelectorAll(sels.item))\n\n const videoHosts = ['youtube.com', 'youtu.be', 'tiktok.com', 'instagram.com', 'facebook.com', 'fb.watch']\n\n const byHref = new Map<string, string[]>()\n for (const a of items) {\n const href = (a as HTMLAnchorElement).href\n if (!href) continue\n if (!videoHosts.some((h) => href.includes(h))) continue\n const text = a.textContent?.trim() ?? ''\n if (!byHref.has(href)) byHref.set(href, [])\n byHref.get(href)!.push(text)\n }\n\n for (const [href, texts] of byHref.entries()) {\n if (seen.has(href)) continue\n seen.add(href)\n\n const duration = texts.find((t) => /^\\d+:\\d+$/.test(t)) ?? ''\n const titleText = texts.find((t) => !/^\\d+:\\d+$/.test(t) && t.length > 5) ?? ''\n if (!titleText) continue\n\n let title = titleText\n let platform = ''\n let channel = ''\n\n for (const p of sels.platforms) {\n let lastIdx = -1\n let search = 0\n while (true) {\n const found = titleText.indexOf(p, search)\n if (found === -1) break\n lastIdx = found\n search = found + 1\n }\n if (lastIdx === -1) continue\n const after = titleText.slice(lastIdx + p.length)\n const isSourceTag = /^[\\s·]/.test(after) || after.trim() === ''\n if (!isSourceTag) continue\n title = titleText.slice(0, lastIdx).trim()\n platform = p\n const stripped = after.replace(/^[\\s·]+/, '')\n const dotIdx = stripped.indexOf('·')\n channel = (dotIdx === -1 ? stripped : stripped.slice(0, dotIdx)).trim()\n break\n }\n\n if (title) results.push({ title, channel, platform, duration, url: href })\n }\n\n return results\n }, svSels)\n\n return raw.map((r) => ({ type: 'short_video' as const, ...r }))\n }\n\n private async extractWhatPeopleSaying(page: Page): Promise<WhatPeopleSayingCard[]> {\n const sels = WhatPeopleSayingSelectors\n return page.evaluate((s) => {\n const section = Array.from(document.querySelectorAll(s.sectionTag))\n .find((el) => el.textContent?.includes(s.sectionHeadingText))\n ?? document.querySelector('.yG4QQe.TBC9ub.NbhJ1c')\n\n if (!section) return []\n\n return Array.from(section.querySelectorAll(s.card)).map((card) => {\n const link = card.querySelector(s.cardLink) as HTMLAnchorElement | null\n const url = link?.href ?? ''\n\n const titleH1 = card.querySelector(s.titleH1)?.textContent?.trim()\n const titleDiv = card.querySelector(s.titleDiv)?.textContent?.trim()\n const title = titleH1 ?? titleDiv ?? ''\n\n const sourceText = card.querySelector(s.source)?.textContent?.trim() ?? ''\n const platformEl = card.querySelector(s.platformBadge)\n const platformText = platformEl?.textContent?.trim() ?? ''\n\n const ytChannel = card.querySelector(s.ytChannel)?.textContent?.trim() ?? ''\n const ytDate = card.querySelector(s.ytDate)?.textContent?.trim() ?? ''\n const authorNote = card.querySelector(s.authorNote)?.textContent?.trim() ?? null\n\n const commentLabelEl = card.querySelector(s.popularCommentLabel)\n let popularComment: string | null = null\n if (commentLabelEl) {\n let next = commentLabelEl.nextSibling\n while (next) {\n const t = next.textContent?.trim()\n if (t) { popularComment = t; break }\n next = next.nextSibling\n }\n }\n\n const allSpans = Array.from(card.querySelectorAll('span'))\n const duration = allSpans.find((s) => /^\\d+:\\d+$/.test(s.textContent?.trim() ?? ''))?.textContent?.trim() ?? null\n const engagementParts = allSpans\n .map((s) => s.textContent?.trim() ?? '')\n .filter((t) =>\n /\\d/.test(t) && (\n t.includes('comment') || t.includes('reaction') ||\n t.includes('view') || t.includes('like') || t.includes('share')\n )\n )\n const engagement = engagementParts[0] ?? ''\n\n const dateCandidates = allSpans\n .map((s) => s.textContent?.trim() ?? '')\n .filter((t) => /\\d+ (day|week|month|year|hour)s? ago|Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec/.test(t))\n const date = ytDate || (dateCandidates[0] ?? '')\n\n const platform = platformText || (ytChannel ? 'YouTube' : '')\n const source = ytChannel || sourceText\n\n let type: 'reddit' | 'facebook' | 'youtube' | 'instagram' | 'tiktok' | 'news' | 'unknown' = 'unknown'\n const pl = platform.toLowerCase()\n const src = source.toLowerCase()\n const srcRaw = sourceText.toLowerCase()\n if (pl.includes('reddit') || src.startsWith('r/')) type = 'reddit'\n else if (pl.includes('facebook') || srcRaw.includes('facebook')) type = 'facebook'\n else if (pl.includes('instagram') || srcRaw.includes('instagram')) type = 'instagram'\n else if (pl.includes('tiktok') || srcRaw.includes('tiktok')) type = 'tiktok'\n else if (pl.includes('youtube') || !!ytChannel) type = 'youtube'\n else type = 'news'\n\n return { type, title, url, source, platform, popularComment, engagement, date, duration, authorNote }\n })\n }, sels)\n }\n\n private async extractOrganicResults(page: Page): Promise<OrganicResult[]> {\n const sels = OrganicSelectors\n return page.evaluate((s) => {\n const out: Array<{ position: number; title: string; url: string; domain: string; cite: string | null; snippet: string | null; isRedditStyle: boolean; inlineRating: { value: string; count: string } | null }> = []\n let pos = 0\n document.querySelectorAll(s.result).forEach(card => {\n const titleEl = card.querySelector(s.title)\n if (!titleEl) return\n const title = titleEl.textContent?.trim() ?? ''\n const linkEl = titleEl.closest('a') as HTMLAnchorElement | null\n const url = linkEl?.href ?? ''\n if (!title || !url) return\n pos++\n const cite = card.querySelector(s.cite)?.textContent?.trim() ?? null\n const snippet = card.querySelector(s.snippet)?.textContent?.trim() ?? null\n const isRedditStyle = !!card.querySelector(s.redditCite)\n const ratingEl = card.querySelector(s.ratingWrap)\n const inlineRating = ratingEl\n ? { value: ratingEl.querySelector(s.ratingValue)?.textContent?.trim() ?? '', count: ratingEl.querySelector(s.reviewCount)?.textContent?.trim() ?? '' }\n : null\n let domain = ''\n try { domain = new URL(url).hostname.replace(/^www\\./, '') } catch { domain = card.querySelector(s.siteName)?.textContent?.trim() ?? '' }\n out.push({ position: pos, title, url, domain, cite, snippet, isRedditStyle, inlineRating })\n })\n return out\n }, sels)\n }\n\n private async extractLocalPack(page: Page): Promise<LocalPackBusiness[]> {\n const sels = LocalPackSelectors\n return page.evaluate((s) => {\n const out: Array<{ position: number; name: string; cid: string | null; rating: string | null; reviewCount: string | null; metadata: string[]; websiteUrl: string | null; directionsUrl: string | null }> = []\n let container: Element | null = null\n document.querySelectorAll('[role=\"heading\"]').forEach(h => {\n if (!container && h.textContent?.includes(s.headingText)) container = h.closest('[data-hveid]')\n })\n if (!container) return out\n ;(container as Element).querySelectorAll(s.card).forEach((card, i) => {\n const name = card.querySelector(s.name)?.textContent?.trim() ?? ''\n if (!name) return\n const rating = card.querySelector(s.ratingValue)?.textContent?.trim() ?? null\n const reviewRaw = card.querySelector(s.reviewCount)?.textContent?.trim() ?? null\n const reviewCount = reviewRaw ? reviewRaw.replace(/[()]/g, '').trim() : null\n let cid = (card.querySelector('a[data-cid]') as HTMLAnchorElement | null)?.getAttribute('data-cid') ?? null\n if (!cid) {\n for (const link of Array.from(card.querySelectorAll('a[href]')) as HTMLAnchorElement[]) {\n const m1 = link.href.match(/[?&]cid=(\\d+)/)\n if (m1) { cid = m1[1]; break }\n const m2 = link.href.match(/!1s0x[0-9a-f]+:0x([0-9a-f]+)/i)\n if (m2) { try { cid = BigInt('0x' + m2[1]).toString() } catch { } if (cid) break }\n }\n }\n const metadata: string[] = []\n card.querySelectorAll('div, span').forEach(el => {\n const text = Array.from(el.childNodes)\n .filter(n => n.nodeType === 3)\n .map(n => n.textContent?.trim() ?? '')\n .filter(t => t.length > 1 && t.length < 120)\n .join(' ')\n if (text && !metadata.includes(text)) metadata.push(text)\n })\n const links = Array.from(card.querySelectorAll('a[href]')) as HTMLAnchorElement[]\n const directionsUrl = links.find(a => a.href.includes('google.com/maps'))?.href ?? null\n const websiteUrl = links.find(a => !a.href.includes('google.com') && a.href.startsWith('http'))?.href ?? null\n out.push({ position: i + 1, name, cid, rating, reviewCount, metadata, websiteUrl, directionsUrl })\n })\n return out\n }, sels)\n }\n\n private async extractEntityIds(page: Page): Promise<EntityIds> {\n return page.evaluate(() => {\n const kgIds = new Set<string>()\n const cids = new Set<string>()\n const gcids = new Set<string>()\n const recordMap = new Map<string, { name: string; kgId: string | null; cid: string | null; gcid: string | null }>()\n\n function nameFromWrapper(el: Element): string {\n const sel = ['.OSrXXb', '.dbg0pd', '.tzt0oe', '[role=\"heading\"]', 'h3']\n for (const s of sel) {\n const found = el.querySelector(s)\n if (found?.textContent?.trim()) return found.textContent.trim()\n }\n return ''\n }\n\n document.querySelectorAll('[id^=\"pv-/g/\"]').forEach(wrapper => {\n const raw = wrapper.getAttribute('id')\n if (!raw) return\n const kgId = raw.replace('pv-', '')\n kgIds.add(kgId)\n const name = nameFromWrapper(wrapper)\n const cidEl = wrapper.querySelector('a[data-cid]')\n const cid = cidEl?.getAttribute('data-cid') ?? null\n if (cid) cids.add(cid)\n if (name) recordMap.set(kgId, { name, kgId, cid, gcid: null })\n })\n\n document.querySelectorAll('[data-mid]').forEach(el => {\n const mid = el.getAttribute('data-mid')\n if (!mid?.startsWith('/g/')) return\n kgIds.add(mid)\n if (!recordMap.has(mid)) {\n const name = nameFromWrapper(el)\n if (name) recordMap.set(mid, { name, kgId: mid, cid: null, gcid: null })\n }\n })\n\n document.querySelectorAll('.w7Dbne').forEach(card => {\n const cidEl = card.querySelector('a[data-cid]')\n const cid = cidEl?.getAttribute('data-cid') ?? null\n if (!cid) return\n cids.add(cid)\n const name = card.querySelector('.OSrXXb')?.textContent?.trim() ?? ''\n if (!name) return\n const kgIdEl = card.querySelector('[id^=\"pv-/g/\"]')\n const kgId = kgIdEl ? kgIdEl.getAttribute('id')!.replace('pv-', '') : null\n const key = kgId ?? `cid:${cid}`\n if (recordMap.has(key)) {\n const existing = recordMap.get(key)!\n if (!existing.cid) recordMap.set(key, { ...existing, cid })\n } else {\n recordMap.set(key, { name, kgId, cid, gcid: null })\n }\n })\n\n document.querySelectorAll('a[data-cid]').forEach(el => {\n const cid = el.getAttribute('data-cid')\n if (!cid) return\n cids.add(cid)\n const alreadyNamed = [...recordMap.values()].some(r => r.cid === cid)\n if (!alreadyNamed) {\n let node: Element | null = el.parentElement\n let name = ''\n for (let i = 0; i < 8 && node; i++) {\n const h = node.querySelector('.OSrXXb, .dbg0pd, [role=\"heading\"], h3')\n if (h?.textContent?.trim()) { name = h.textContent.trim(); break }\n node = node.parentElement\n }\n if (name) recordMap.set(`cid:${cid}`, { name, kgId: null, cid, gcid: null })\n }\n })\n\n const scriptContent = Array.from(document.querySelectorAll('script:not([src])'))\n .map(s => s.textContent ?? '')\n .filter(t => t.length > 10_000)\n .join('\\n')\n\n for (const m of scriptContent.matchAll(/\\/g\\/[a-zA-Z0-9_-]{5,20}/g)) kgIds.add(m[0])\n for (const m of scriptContent.matchAll(/gcid:[a-zA-Z0-9_]+/g)) gcids.add(m[0])\n for (const m of scriptContent.matchAll(/0x[0-9a-f]+:0x([0-9a-f]+)/gi)) {\n try { cids.add(BigInt('0x' + m[1]).toString()) } catch { }\n }\n\n return { entities: [...recordMap.values()], kgIds: [...kgIds], cids: [...cids], gcids: [...gcids] }\n })\n }\n\n private mergeLocalPackIntoEntities(entityIds: EntityIds, localPack: LocalPackBusiness[]): EntityIds {\n const cidSet = new Set<string>(entityIds.cids)\n const records = entityIds.entities.map(r => ({ ...r }))\n\n for (const biz of localPack) {\n if (!biz.cid) continue\n cidSet.add(biz.cid)\n const nameNorm = biz.name.toLowerCase().trim()\n const byName = records.find(r => r.name.toLowerCase().trim() === nameNorm)\n if (byName) {\n if (!byName.cid) byName.cid = biz.cid\n } else if (!records.find(r => r.cid === biz.cid)) {\n records.push({ name: biz.name, kgId: null, cid: biz.cid, gcid: null })\n }\n }\n\n return { ...entityIds, entities: records, cids: [...cidSet] }\n }\n\n private async extractAISurfaces(page: Page): Promise<{\n surface: GoogleSurface\n aiOverview: AIOverviewResult\n aiMode: AIModeResult\n }> {\n return page.evaluate(extractAISurfacesFromDocument, {\n aio: AIOverviewSelectors,\n aim: AIModeSelectors,\n expandWaitMs: 1500,\n })\n }\n\n private buildTree(flat: FlatRow[], _seed: string): PAANode[] {\n const roots: PAANode[] = []\n const nodeMap = new Map<string, PAANode>()\n\n for (const row of flat) {\n const node: PAANode = {\n question: row.question,\n answer: row.answer || null,\n sourceTitle: row.source_title || null,\n sourceSite: row.source_site || null,\n sourceCite: row.source_cite || null,\n depth: row.depth,\n parentQuestion: row.parent_question || null,\n children: [],\n }\n nodeMap.set(row.question, node)\n }\n\n for (const node of nodeMap.values()) {\n if (node.parentQuestion && nodeMap.has(node.parentQuestion)) {\n nodeMap.get(node.parentQuestion)!.children.push(node)\n } else {\n roots.push(node)\n }\n }\n\n return roots\n }\n\n private getBrowserDebugSnapshot(): BrowserDebugSnapshot {\n return this.driver.getDebugSnapshot()\n }\n\n private buildHarvestDebugSnapshot(\n options: HarvestOptions,\n canonicalLocation: string | null,\n uule: string | null,\n locationEvidence?: SerpLocationEvidence,\n ): HarvestDebugSnapshot | undefined {\n if (!options.debug) return undefined\n return {\n enabled: true,\n request: {\n query: options.query,\n locationInput: options.location ?? null,\n canonicalLocation,\n uule,\n gl: options.gl,\n hl: options.hl,\n device: options.device,\n proxyMode: options.proxyMode,\n proxyZip: options.proxyZip ?? null,\n serpOnly: options.serpOnly,\n pages: options.pages ?? 1,\n },\n browser: this.getBrowserDebugSnapshot(),\n ...(locationEvidence ? { locationEvidence } : {}),\n }\n }\n\n async extract(options: HarvestOptions, signal?: AbortSignal): Promise<HarvestResult> {\n const startMs = Date.now()\n const isMobile = options.device === 'mobile'\n const config: DriverConfig = {\n headless: options.headless,\n profileDir: options.profileDir,\n proxy: options.proxy,\n kernelApiKey: options.kernelApiKey,\n kernelProxyId: options.kernelProxyId,\n kernelProxyResolution: options.kernelProxyResolution as DriverConfig['kernelProxyResolution'],\n proxyMode: options.proxyMode,\n viewport: isMobile ? { width: 390, height: 844 } : { width: 1280, height: 800 },\n locale: `${options.hl}-${options.gl.toUpperCase()}`,\n userAgent: isMobile ? MOBILE_USER_AGENT : DESKTOP_USER_AGENT,\n deviceScaleFactor: isMobile ? 3 : 1,\n isMobile,\n hasTouch: isMobile,\n debug: options.debug,\n }\n\n let errorCount = 0\n const diagnosticWarnings: HarvestDiagnosticWarning[] = []\n\n try {\n this.throwIfAborted(signal)\n await this.driver.launch(config)\n this.throwIfAborted(signal)\n const canonicalLocation = options.location ? normalizeLocation(options.location) : null\n const uule = canonicalLocation ? encodeUule(canonicalLocation) : null\n const { hasPaa } = await this.driver.navigateToSERP(\n options.query,\n uule,\n options.gl,\n options.hl,\n {\n ...(options.serpOnly ? { num: 100 } : {}),\n debug: options.debug,\n },\n )\n this.throwIfAborted(signal)\n\n const page = this.driver.getPage() as Page\n await this.throwIfCaptcha(page, 'Google SERP')\n\n if (options.serpOnly) {\n const [organicResults, localPack, rawEntityIds] = await Promise.all([\n this.extractOrganicResults(page),\n this.extractLocalPack(page),\n this.extractEntityIds(page),\n ])\n const entityIds = this.mergeLocalPackIntoEntities(rawEntityIds, localPack)\n const aiSurfaces = await this.extractAISurfaces(page)\n let locationEvidence = options.debug\n ? inferSerpLocationEvidence(canonicalLocation, organicResults, localPack)\n : undefined\n let allOrganic = organicResults\n if ((options.pages ?? 1) >= 2) {\n const p2params = new URLSearchParams({ q: options.query, gl: options.gl, hl: options.hl, pws: '0', start: '10' })\n if (uule) p2params.set('uule', uule)\n await this.driver.navigateTo('https://www.google.com/search?' + p2params.toString())\n await this.throwIfCaptcha(page, 'Google SERP page 2')\n const p2organic = await this.extractOrganicResults(page)\n allOrganic = [...organicResults, ...p2organic.map(r => ({ ...r, position: r.position + 10 }))]\n if (options.debug) {\n locationEvidence = inferSerpLocationEvidence(canonicalLocation, allOrganic, localPack)\n }\n }\n const stats: HarvestStats = {\n seed: options.query, totalQuestions: 0, maxDepthReached: 0,\n durationMs: Date.now() - startMs, errorCount,\n }\n this.reporter.onComplete(stats)\n return {\n seed: options.query, location: options.location ?? null,\n extractedAt: new Date().toISOString(),\n diagnostics: {\n completionStatus: 'serp_only',\n problem: null,\n ...(options.debug ? { debug: this.buildHarvestDebugSnapshot(options, canonicalLocation, uule, locationEvidence) } : {}),\n },\n totalQuestions: 0,\n surface: aiSurfaces.surface,\n aiOverview: aiSurfaces.aiOverview,\n aiMode: aiSurfaces.aiMode,\n whatPeopleSaying: [], tree: [], flat: [], videos: [], forums: [],\n organicResults: allOrganic, localPack, entityIds, stats,\n }\n }\n\n const [videos, forums, whatPeopleSaying, rawEntityIds, organicResults, localPack] = await Promise.all([\n this.extractVideos(page),\n this.extractForums(page),\n this.extractWhatPeopleSaying(page),\n this.extractEntityIds(page),\n this.extractOrganicResults(page),\n this.extractLocalPack(page),\n ])\n const entityIds = this.mergeLocalPackIntoEntities(rawEntityIds, localPack)\n const initialLocationEvidence = options.debug\n ? inferSerpLocationEvidence(canonicalLocation, organicResults, localPack)\n : undefined\n this.reporter.onVideos(videos)\n this.reporter.onForums(forums)\n\n if (!hasPaa) {\n let noPaaOrganic = organicResults\n let locationEvidence = initialLocationEvidence\n if ((options.pages ?? 1) >= 2) {\n const p2params = new URLSearchParams({ q: options.query, gl: options.gl, hl: options.hl, pws: '0', start: '10' })\n if (uule) p2params.set('uule', uule)\n await this.driver.navigateTo('https://www.google.com/search?' + p2params.toString())\n await this.throwIfCaptcha(page, 'Google SERP page 2')\n const p2organic = await this.extractOrganicResults(page)\n noPaaOrganic = [...organicResults, ...p2organic.map(r => ({ ...r, position: r.position + 10 }))]\n if (options.debug) {\n locationEvidence = inferSerpLocationEvidence(canonicalLocation, noPaaOrganic, localPack)\n }\n }\n const aiSurfaces = await this.extractAISurfaces(page)\n const stats: HarvestStats = {\n seed: options.query, totalQuestions: 0, maxDepthReached: 0,\n durationMs: Date.now() - startMs, errorCount,\n }\n this.reporter.onComplete(stats)\n return {\n seed: options.query, location: options.location ?? null,\n extractedAt: new Date().toISOString(),\n diagnostics: {\n completionStatus: 'no_paa',\n problem: null,\n ...(options.debug ? { debug: this.buildHarvestDebugSnapshot(options, canonicalLocation, uule, locationEvidence) } : {}),\n },\n totalQuestions: 0,\n surface: aiSurfaces.surface,\n aiOverview: aiSurfaces.aiOverview,\n aiMode: aiSurfaces.aiMode,\n whatPeopleSaying, tree: [], flat: [], videos, forums,\n organicResults: noPaaOrganic, localPack, entityIds, stats,\n }\n }\n\n const flat = await this.runBFS(page, options, signal)\n this.throwIfAborted(signal)\n const aiSurfaces = await this.extractAISurfaces(page)\n\n const shortVidsParams = new URLSearchParams({ q: options.query, gl: options.gl, hl: options.hl, pws: '0', udm: ShortVideoSelectors.udm })\n if (uule) shortVidsParams.set('uule', uule)\n let shortVideos: VideoResult[] = []\n try {\n shortVideos = await this.extractShortVideos(page, 'https://www.google.com/search?' + shortVidsParams.toString())\n } catch (err) {\n if (!(err instanceof CaptchaError)) throw err\n errorCount++\n diagnosticWarnings.push({\n code: 'short_videos_captcha_skipped',\n surface: 'short_videos',\n message: err.message,\n retryable: true,\n })\n }\n this.reporter.onVideos(shortVideos)\n\n let allOrganic = organicResults\n let locationEvidence = initialLocationEvidence\n if ((options.pages ?? 1) >= 2) {\n const p2params = new URLSearchParams({ q: options.query, gl: options.gl, hl: options.hl, pws: '0', start: '10' })\n if (uule) p2params.set('uule', uule)\n await this.driver.navigateTo('https://www.google.com/search?' + p2params.toString())\n await this.throwIfCaptcha(page, 'Google SERP page 2')\n const p2organic = await this.extractOrganicResults(page)\n allOrganic = [...organicResults, ...p2organic.map(r => ({ ...r, position: r.position + 10 }))]\n if (options.debug) {\n locationEvidence = inferSerpLocationEvidence(canonicalLocation, allOrganic, localPack)\n }\n }\n\n const allVideos = [...videos, ...shortVideos]\n const tree = this.buildTree(flat, options.query)\n\n const stats: HarvestStats = {\n seed: options.query,\n totalQuestions: flat.length,\n maxDepthReached: flat.reduce((m, r) => Math.max(m, r.depth), 0),\n durationMs: Date.now() - startMs,\n errorCount,\n }\n\n this.reporter.onComplete(stats)\n\n return {\n seed: options.query,\n location: options.location ?? null,\n extractedAt: new Date().toISOString(),\n diagnostics: {\n completionStatus: 'paa_found',\n problem: null,\n ...(diagnosticWarnings.length > 0 ? { warnings: diagnosticWarnings } : {}),\n ...(options.debug ? { debug: this.buildHarvestDebugSnapshot(options, canonicalLocation, uule, locationEvidence) } : {}),\n },\n totalQuestions: flat.length,\n surface: aiSurfaces.surface,\n aiOverview: aiSurfaces.aiOverview,\n aiMode: aiSurfaces.aiMode,\n whatPeopleSaying,\n tree,\n flat,\n videos: allVideos,\n forums,\n organicResults: allOrganic,\n localPack,\n entityIds,\n stats,\n }\n } catch (err) {\n errorCount++\n this.reporter.onError(err instanceof Error ? err : new Error(String(err)))\n throw err\n }\n }\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport Papa from 'papaparse'\nimport type { HarvestResult, FlatRow, VideoResult, ForumResult, AICitation, WhatPeopleSayingCard } from '../types.js'\nimport type { IOutputSerializer } from './IOutputSerializer.js'\n\nexport class OutputSerializer implements IOutputSerializer {\n async writeJSON(result: HarvestResult, outputDir: string): Promise<string> {\n await fs.mkdir(outputDir, { recursive: true })\n const slug = result.seed.toLowerCase().replace(/\\W+/g, '-').slice(0, 40)\n const filename = `${slug}-${Date.now()}.json`\n const fullPath = path.join(outputDir, filename)\n await fs.writeFile(fullPath, JSON.stringify(result, null, 2), 'utf8')\n return fullPath\n }\n\n async writeCSV(rows: FlatRow[], outputDir: string): Promise<string> {\n await fs.mkdir(outputDir, { recursive: true })\n const seedRaw = rows[0]?.seed_query ?? 'paa'\n const slug = seedRaw.toLowerCase().replace(/\\W+/g, '-').slice(0, 40)\n const csv = Papa.unparse(rows, { header: true })\n const filename = `${slug}-${Date.now()}.csv`\n const fullPath = path.join(outputDir, filename)\n await fs.writeFile(fullPath, csv, 'utf8')\n return fullPath\n }\n\n async writeVideoCSV(videos: VideoResult[], seed: string, outputDir: string): Promise<string> {\n await fs.mkdir(outputDir, { recursive: true })\n const slug = seed.toLowerCase().replace(/\\W+/g, '-').slice(0, 40)\n const csv = Papa.unparse(videos, { header: true })\n const filename = `${slug}-videos-${Date.now()}.csv`\n const fullPath = path.join(outputDir, filename)\n await fs.writeFile(fullPath, csv, 'utf8')\n return fullPath\n }\n\n async writeForumCSV(forums: ForumResult[], seed: string, outputDir: string): Promise<string> {\n await fs.mkdir(outputDir, { recursive: true })\n const slug = seed.toLowerCase().replace(/\\W+/g, '-').slice(0, 40)\n const csv = Papa.unparse(forums, { header: true })\n const filename = `${slug}-forums-${Date.now()}.csv`\n const fullPath = path.join(outputDir, filename)\n await fs.writeFile(fullPath, csv, 'utf8')\n return fullPath\n }\n\n async writeAIOverviewCSV(citations: AICitation[], text: string | null, seed: string, outputDir: string): Promise<string> {\n await fs.mkdir(outputDir, { recursive: true })\n const slug = seed.toLowerCase().replace(/\\W+/g, '-').slice(0, 40)\n const rows = citations.map((c, i) => ({\n seed_query: seed,\n response_text: i === 0 ? (text ?? '') : '',\n citation_text: c.text,\n citation_href: c.href,\n }))\n const csv = Papa.unparse(rows, { header: true })\n const filename = `${slug}-ai-overview-${Date.now()}.csv`\n const fullPath = path.join(outputDir, filename)\n await fs.writeFile(fullPath, csv, 'utf8')\n return fullPath\n }\n\n async writeAIModeCSV(citations: AICitation[], text: string | null, seed: string, outputDir: string): Promise<string> {\n await fs.mkdir(outputDir, { recursive: true })\n const slug = seed.toLowerCase().replace(/\\W+/g, '-').slice(0, 40)\n const rows = citations.map((c, i) => ({\n seed_query: seed,\n response_text: i === 0 ? (text ?? '') : '',\n citation_text: c.text,\n citation_href: c.href,\n }))\n const csv = Papa.unparse(rows, { header: true })\n const filename = `${slug}-ai-mode-${Date.now()}.csv`\n const fullPath = path.join(outputDir, filename)\n await fs.writeFile(fullPath, csv, 'utf8')\n return fullPath\n }\n\n async writeWhatPeopleSayingCSV(cards: WhatPeopleSayingCard[], seed: string, outputDir: string): Promise<string> {\n await fs.mkdir(outputDir, { recursive: true })\n const slug = seed.toLowerCase().replace(/\\W+/g, '-').slice(0, 40)\n const rows = cards.map((c) => ({ seed_query: seed, ...c }))\n const csv = Papa.unparse(rows, { header: true })\n const filename = `${slug}-what-people-saying-${Date.now()}.csv`\n const fullPath = path.join(outputDir, filename)\n await fs.writeFile(fullPath, csv, 'utf8')\n return fullPath\n }\n}\n","import type { PAANode, HarvestStats, VideoResult, ForumResult } from '../types.js'\nimport type { IProgressReporter } from './IProgressReporter.js'\n\nexport class ProgressReporter implements IProgressReporter {\n onQuestion(node: PAANode): void {\n process.stdout.write(JSON.stringify({ event: 'question', depth: node.depth, question: node.question }) + '\\n')\n }\n\n onDepth(depth: number): void {\n process.stdout.write(JSON.stringify({ event: 'depth', depth }) + '\\n')\n }\n\n onVideos(videos: VideoResult[]): void {\n for (const v of videos) {\n process.stdout.write(JSON.stringify({ event: 'video', type: v.type, platform: v.platform, duration: v.duration, title: v.title, channel: v.channel, url: v.url }) + '\\n')\n }\n }\n\n onForums(forums: ForumResult[]): void {\n for (const f of forums) {\n process.stdout.write(JSON.stringify({ event: 'forum', title: f.title, source: f.source, url: f.url }) + '\\n')\n }\n }\n\n onComplete(stats: HarvestStats): void {\n process.stdout.write(JSON.stringify({ event: 'complete', ...stats }) + '\\n')\n }\n\n onError(err: Error): void {\n process.stderr.write(JSON.stringify({ event: 'error', type: err.constructor.name, message: err.message }) + '\\n')\n }\n}\n","import Kernel from '@onkernel/sdk'\nimport { normalizeLocation } from './uule.js'\nimport type { CanonicalLocationName, KernelLocationProxyTarget, KernelProxyResolutionDebug, ProxyMode } from './types.js'\n\ntype KernelProxyConfig = {\n country?: string\n state?: string\n city?: string\n zip?: string\n}\n\ntype KernelProxyListItem = {\n id?: string\n name?: string\n type?: string\n status?: string\n config?: KernelProxyConfig\n}\n\ntype KernelProxyCreateResponse = {\n id?: string\n name?: string\n type?: string\n status?: string\n config?: KernelProxyConfig\n}\n\nexport interface ResolveKernelProxyOptions {\n kernelApiKey?: string\n proxyMode: ProxyMode\n configuredKernelProxyId?: string\n location?: string\n proxyZip?: string\n gl: string\n attemptIndex?: number\n}\n\nexport interface ResolveKernelProxyResult {\n kernelProxyId?: string\n resolution: KernelProxyResolutionDebug\n}\n\nconst US_STATE_CODES: Record<string, string> = {\n alabama: 'AL',\n alaska: 'AK',\n arizona: 'AZ',\n arkansas: 'AR',\n california: 'CA',\n colorado: 'CO',\n connecticut: 'CT',\n delaware: 'DE',\n florida: 'FL',\n georgia: 'GA',\n hawaii: 'HI',\n idaho: 'ID',\n illinois: 'IL',\n indiana: 'IN',\n iowa: 'IA',\n kansas: 'KS',\n kentucky: 'KY',\n louisiana: 'LA',\n maine: 'ME',\n maryland: 'MD',\n massachusetts: 'MA',\n michigan: 'MI',\n minnesota: 'MN',\n mississippi: 'MS',\n missouri: 'MO',\n montana: 'MT',\n nebraska: 'NE',\n nevada: 'NV',\n 'new hampshire': 'NH',\n 'new jersey': 'NJ',\n 'new mexico': 'NM',\n 'new york': 'NY',\n 'north carolina': 'NC',\n 'north dakota': 'ND',\n ohio: 'OH',\n oklahoma: 'OK',\n oregon: 'OR',\n pennsylvania: 'PA',\n 'rhode island': 'RI',\n 'south carolina': 'SC',\n 'south dakota': 'SD',\n tennessee: 'TN',\n texas: 'TX',\n utah: 'UT',\n vermont: 'VT',\n virginia: 'VA',\n washington: 'WA',\n 'west virginia': 'WV',\n wisconsin: 'WI',\n wyoming: 'WY',\n}\n\nconst US_CITY_CENTER_ZIPS: Record<string, string> = {\n 'atlanta|GA': '30303',\n 'austin|TX': '78701',\n 'baltimore|MD': '21201',\n 'boston|MA': '02108',\n 'boulder|CO': '80302',\n 'charlotte|NC': '28202',\n 'chicago|IL': '60601',\n 'colorado_springs|CO': '80903',\n 'columbus|OH': '43215',\n 'dallas|TX': '75201',\n 'denver|CO': '80202',\n 'detroit|MI': '48226',\n 'fort_collins|CO': '80524',\n 'fort_worth|TX': '76102',\n 'houston|TX': '77002',\n 'indianapolis|IN': '46204',\n 'jacksonville|FL': '32202',\n 'las_vegas|NV': '89101',\n 'los_angeles|CA': '90012',\n 'louisville|KY': '40202',\n 'loveland|CO': '80537',\n 'memphis|TN': '38103',\n 'miami|FL': '33131',\n 'minneapolis|MN': '55401',\n 'nashville|TN': '37203',\n 'new_york|NY': '10001',\n 'orlando|FL': '32801',\n 'philadelphia|PA': '19103',\n 'phoenix|AZ': '85004',\n 'portland|OR': '97205',\n 'raleigh|NC': '27601',\n 'richmond|VA': '23219',\n 'sacramento|CA': '95814',\n 'salt_lake_city|UT': '84101',\n 'san_antonio|TX': '78205',\n 'san_diego|CA': '92101',\n 'san_francisco|CA': '94103',\n 'san_jose|CA': '95113',\n 'seattle|WA': '98101',\n}\n\nfunction proxyIdSuffix(proxyId: string | null | undefined): string | null {\n return proxyId ? proxyId.slice(-6) : null\n}\n\nfunction resolution(\n source: KernelProxyResolutionDebug['source'],\n proxyMode: ProxyMode,\n proxyId: string | undefined,\n target: KernelLocationProxyTarget | null,\n error: string | null,\n): ResolveKernelProxyResult {\n return {\n kernelProxyId: proxyId,\n resolution: {\n source,\n proxyMode,\n proxyIdPresent: Boolean(proxyId),\n proxyIdSuffix: proxyIdSuffix(proxyId),\n target,\n error,\n },\n }\n}\n\nfunction normalizeStateName(value: string): string {\n return value.trim().toLowerCase().replace(/\\s+/g, ' ')\n}\n\nfunction normalizeCountryName(value: string): string {\n return value.trim().toLowerCase().replace(/\\./g, '').replace(/\\s+/g, ' ')\n}\n\nfunction isUnitedStates(country: string | undefined): boolean {\n if (!country) return true\n const normalized = normalizeCountryName(country)\n return normalized === 'united states' || normalized === 'united states of america' || normalized === 'usa' || normalized === 'us'\n}\n\nfunction stateCodeFor(region: string): string | null {\n const trimmed = region.trim()\n if (/^[A-Za-z]{2}$/.test(trimmed)) return trimmed.toUpperCase()\n return US_STATE_CODES[normalizeStateName(trimmed)] ?? null\n}\n\nexport function kernelCityIdentifierCandidates(city: string): string[] {\n const ascii = city\n .normalize('NFKD')\n .replace(/[^\\x00-\\x7F]/g, '')\n .toLowerCase()\n const words = ascii.split(/[^a-z0-9]+/).filter(Boolean)\n const underscored = words.join('_')\n const compact = words.join('')\n return Array.from(new Set([underscored, compact].filter(Boolean)))\n}\n\nfunction proxyName(country: string, state: string, city?: string): string {\n return city\n ? `mcp-serp-residential-${country.toLowerCase()}-${state.toLowerCase()}-${city}`\n : `mcp-serp-residential-${country.toLowerCase()}-${state.toLowerCase()}`\n}\n\nfunction zipProxyName(zip: string): string {\n return `mcp-serp-residential-us-zip-${zip}`\n}\n\nexport function parseKernelLocationProxyTarget(location: string | undefined, gl: string): KernelLocationProxyTarget | null {\n if (!location || gl.toLowerCase() !== 'us') return null\n const canonicalLocation = normalizeLocation(location)\n let parts = canonicalLocation.split(',').map(part => part.trim()).filter(Boolean)\n if (parts.length > 1 && isUnitedStates(parts[parts.length - 1])) {\n parts = parts.slice(0, -1)\n }\n\n if (parts.length === 1) {\n const stateOnly = stateCodeFor(parts[0])\n if (!stateOnly) return null\n return {\n canonicalLocation: canonicalLocation as CanonicalLocationName,\n level: 'state',\n country: 'US',\n state: stateOnly,\n city: '',\n cityCandidates: [],\n proxyName: proxyName('US', stateOnly),\n config: {\n country: 'US',\n state: stateOnly,\n },\n }\n }\n\n const [city = '', region = ''] = parts\n if (!city || !region) return null\n const state = stateCodeFor(region)\n if (!state) return null\n const cityCandidates = kernelCityIdentifierCandidates(city)\n const primaryCity = cityCandidates[0]\n if (!primaryCity) return null\n return {\n canonicalLocation: canonicalLocation as CanonicalLocationName,\n level: 'city',\n country: 'US',\n state,\n city: primaryCity,\n cityCandidates,\n proxyName: proxyName('US', state, primaryCity),\n config: {\n country: 'US',\n state,\n city: primaryCity,\n },\n }\n}\n\nfunction cityZipKey(target: KernelLocationProxyTarget): string {\n return `${target.city}|${target.state}`\n}\n\nfunction knownZipFor(target: KernelLocationProxyTarget, explicitZip: string | undefined): string | null {\n if (explicitZip && /^\\d{5}$/.test(explicitZip)) return explicitZip\n return US_CITY_CENTER_ZIPS[cityZipKey(target)] ?? null\n}\n\nfunction zipTarget(target: KernelLocationProxyTarget, zip: string): KernelLocationProxyTarget {\n return {\n ...target,\n level: 'zip',\n zip,\n proxyName: zipProxyName(zip),\n config: {\n country: target.country,\n state: target.state,\n zip,\n },\n }\n}\n\nfunction configMatches(config: KernelProxyConfig | undefined, target: KernelLocationProxyTarget, city?: string): boolean {\n if (target.level === 'zip') {\n return config?.country?.toUpperCase() === target.country && config?.zip === target.zip\n }\n return config?.country?.toUpperCase() === target.country &&\n config?.state?.toUpperCase() === target.state &&\n (city ? config?.city === city : !config?.city)\n}\n\nfunction findExistingTargetProxy(proxies: KernelProxyListItem[], target: KernelLocationProxyTarget): KernelProxyListItem | null {\n return proxies.find(proxy => (\n proxy.type === 'residential' &&\n proxy.status !== 'unavailable' &&\n Boolean(proxy.id) &&\n (proxy.name === target.proxyName || configMatches(proxy.config, target, target.level === 'city' ? target.city : undefined))\n )) ?? null\n}\n\nfunction findExistingProxy(proxies: KernelProxyListItem[], target: KernelLocationProxyTarget): KernelProxyListItem | null {\n for (const city of target.cityCandidates) {\n const name = proxyName(target.country, target.state, city)\n const found = proxies.find(proxy => (\n proxy.type === 'residential' &&\n proxy.status !== 'unavailable' &&\n Boolean(proxy.id) &&\n (proxy.name === name || configMatches(proxy.config, target, city))\n ))\n if (found) return found\n }\n return null\n}\n\nfunction stateTarget(target: KernelLocationProxyTarget): KernelLocationProxyTarget {\n return {\n ...target,\n level: 'state',\n proxyName: proxyName(target.country, target.state),\n config: {\n country: target.country,\n state: target.state,\n },\n }\n}\n\nfunction findExistingStateProxy(proxies: KernelProxyListItem[], target: KernelLocationProxyTarget): KernelProxyListItem | null {\n const name = proxyName(target.country, target.state)\n return proxies.find(proxy => (\n proxy.type === 'residential' &&\n proxy.status !== 'unavailable' &&\n Boolean(proxy.id) &&\n (proxy.name === name || configMatches(proxy.config, target))\n )) ?? null\n}\n\nfunction escalatedTargetLevel(target: KernelLocationProxyTarget, attemptIndex: number): KernelLocationProxyTarget {\n return stateTarget(target)\n}\n\nfunction errorText(err: unknown): string {\n return err instanceof Error ? err.message : String(err)\n}\n\nexport async function resolveKernelProxyId(options: ResolveKernelProxyOptions): Promise<ResolveKernelProxyResult> {\n if (options.proxyMode === 'none') {\n return resolution('disabled', options.proxyMode, undefined, null, null)\n }\n\n if (options.proxyMode === 'configured') {\n return resolution('configured_fallback', options.proxyMode, options.configuredKernelProxyId, null, null)\n }\n\n const target = parseKernelLocationProxyTarget(options.location, options.gl)\n if (!target || !options.kernelApiKey) {\n return resolution('configured_fallback', options.proxyMode, options.configuredKernelProxyId, target, target ? null : 'location could not be normalized to a US city/state proxy target')\n }\n\n const kernel = new Kernel({ apiKey: options.kernelApiKey })\n try {\n const attemptIndex = options.attemptIndex ?? 0\n\n if (attemptIndex >= 1) {\n const escalatedTarget = escalatedTargetLevel(target, attemptIndex)\n const createErrors: string[] = []\n try {\n const created = await kernel.proxies.create({\n type: 'residential',\n name: escalatedTarget.proxyName,\n config: escalatedTarget.config,\n }) as KernelProxyCreateResponse\n if (created.id) {\n return resolution('location_created', options.proxyMode, created.id, escalatedTarget, null)\n }\n createErrors.push(`${escalatedTarget.state}: Kernel did not return a proxy id`)\n } catch (err) {\n createErrors.push(`${escalatedTarget.state}: ${errorText(err)}`)\n }\n return resolution('configured_fallback', options.proxyMode, options.configuredKernelProxyId, escalatedTarget, createErrors.join(' | '))\n }\n\n const proxies = await kernel.proxies.list() as KernelProxyListItem[]\n const zip = knownZipFor(target, options.proxyZip)\n const createErrors: string[] = []\n if (zip) {\n const targetZip = zipTarget(target, zip)\n const existingZip = findExistingTargetProxy(proxies, targetZip)\n if (existingZip?.id) {\n return resolution('location_reused', options.proxyMode, existingZip.id, targetZip, null)\n }\n try {\n const created = await kernel.proxies.create({\n type: 'residential',\n name: targetZip.proxyName,\n config: {\n country: targetZip.country,\n zip,\n },\n }) as KernelProxyCreateResponse\n if (created.id) {\n return resolution('location_created', options.proxyMode, created.id, targetZip, null)\n }\n createErrors.push(`${zip}: Kernel did not return a proxy id`)\n } catch (err) {\n createErrors.push(`${zip}: ${errorText(err)}`)\n }\n }\n\n const existing = findExistingProxy(proxies, target)\n if (existing?.id) {\n return resolution('location_reused', options.proxyMode, existing.id, target, createErrors.join(' | ') || null)\n }\n\n for (const city of target.cityCandidates) {\n try {\n const created = await kernel.proxies.create({\n type: 'residential',\n name: proxyName(target.country, target.state, city),\n config: {\n country: target.country,\n state: target.state,\n city,\n },\n }) as KernelProxyCreateResponse\n if (created.id) {\n return resolution('location_created', options.proxyMode, created.id, {\n ...target,\n level: 'city',\n city,\n proxyName: proxyName(target.country, target.state, city),\n config: {\n country: target.country,\n state: target.state,\n city,\n },\n }, null)\n }\n createErrors.push(`${city}: Kernel did not return a proxy id`)\n } catch (err) {\n createErrors.push(`${city}: ${errorText(err)}`)\n }\n }\n const fallbackTarget = stateTarget(target)\n const existingState = findExistingStateProxy(proxies, fallbackTarget)\n if (existingState?.id) {\n return resolution('location_reused', options.proxyMode, existingState.id, fallbackTarget, createErrors.join(' | '))\n }\n try {\n const created = await kernel.proxies.create({\n type: 'residential',\n name: fallbackTarget.proxyName,\n config: fallbackTarget.config,\n }) as KernelProxyCreateResponse\n if (created.id) {\n return resolution('location_created', options.proxyMode, created.id, fallbackTarget, createErrors.join(' | '))\n }\n createErrors.push(`${fallbackTarget.state}: Kernel did not return a proxy id`)\n } catch (err) {\n createErrors.push(`${fallbackTarget.state}: ${errorText(err)}`)\n }\n return resolution('configured_fallback', options.proxyMode, options.configuredKernelProxyId, target, createErrors.join(' | '))\n } catch (err) {\n return resolution('configured_fallback', options.proxyMode, options.configuredKernelProxyId, target, errorText(err))\n }\n}\n","import { HarvestOptionsSchema } from './schemas.js'\nimport type { HarvestDebugSnapshot, HarvestOptions, HarvestResult, ProxyMode } from './types.js'\nimport { BrowserDriver } from './driver/BrowserDriver.js'\nimport { PAAExtractor } from './extractor/PAAExtractor.js'\nimport { OutputSerializer } from './output/OutputSerializer.js'\nimport { ProgressReporter } from './output/ProgressReporter.js'\nimport { CaptchaError, RequestAbortedError, sanitizeVendorName } from './errors.js'\nimport type { BrowserCloseResult } from './driver/IBrowserDriver.js'\nimport { resolveKernelProxyId } from './kernel-proxy-resolver.js'\n\nconst MAX_ATTEMPTS = 3\n\nexport type HarvestAttemptOutcome =\n | 'paa_found'\n | 'paa_partial'\n | 'no_paa'\n | 'serp_only'\n | 'captcha'\n | 'request_aborted'\n | 'timeout'\n | 'error'\n\nexport type HarvestAttemptLogEvent =\n | {\n type: 'started'\n attemptNumber: number\n maxAttempts: number\n query: string\n location: string | null\n maxQuestions: number\n startedAt: string\n }\n | {\n type: 'finished'\n attemptNumber: number\n maxAttempts: number\n outcome: HarvestAttemptOutcome\n kernelSessionId: string | null\n questionCount: number\n durationMs: number\n error: string | null\n willRetry: boolean\n cleanup: BrowserCloseResult\n debug: HarvestDebugSnapshot | null\n completedAt: string\n }\n\ntype HarvestAttemptLogSink = (event: HarvestAttemptLogEvent) => void | Promise<void>\n\ntype ExtractOnceOutcome =\n | { result: HarvestResult; error: null; cleanup: BrowserCloseResult; debug: HarvestDebugSnapshot | null }\n | { result: null; error: unknown; cleanup: BrowserCloseResult; debug: HarvestDebugSnapshot | null }\n\nfunction abortReason(signal: AbortSignal): unknown {\n if (signal.reason instanceof DOMException && signal.reason.name === 'TimeoutError') return signal.reason\n return new RequestAbortedError()\n}\n\nfunction getAbortSignal(rawOptions: unknown): AbortSignal | undefined {\n if (!rawOptions || typeof rawOptions !== 'object') return undefined\n const signal = (rawOptions as { signal?: unknown }).signal\n if (signal instanceof AbortSignal) return signal\n return undefined\n}\n\nfunction getAttemptLogSink(rawOptions: unknown): HarvestAttemptLogSink | undefined {\n if (!rawOptions || typeof rawOptions !== 'object') return undefined\n const sink = (rawOptions as { onAttemptEvent?: unknown }).onAttemptEvent\n return typeof sink === 'function' ? sink as HarvestAttemptLogSink : undefined\n}\n\nasync function emitAttemptEvent(sink: HarvestAttemptLogSink | undefined, event: HarvestAttemptLogEvent): Promise<void> {\n if (!sink) return\n try {\n await sink(event)\n } catch (err) {\n console.warn(JSON.stringify({\n event: 'harvest_attempt_log_failed',\n attempt_number: event.attemptNumber,\n message: err instanceof Error ? err.message : String(err),\n }))\n }\n}\n\nfunction classifyAttemptError(err: unknown): HarvestAttemptOutcome {\n if (err instanceof CaptchaError) return 'captcha'\n if (err instanceof RequestAbortedError) return 'request_aborted'\n if (err instanceof DOMException && (err.name === 'TimeoutError' || err.name === 'AbortError')) return 'timeout'\n const message = err instanceof Error ? err.message : String(err)\n return /timeout|timed out|Timeout \\d+ms exceeded|deadline/i.test(message) ? 'timeout' : 'error'\n}\n\nfunction classifyAttemptResult(result: HarvestResult): HarvestAttemptOutcome {\n return result.diagnostics?.completionStatus ?? (result.totalQuestions > 0 ? 'paa_found' : 'no_paa')\n}\n\nfunction errorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err)\n}\n\nasync function extractOnce(options: HarvestOptions, signal?: AbortSignal): Promise<ExtractOnceOutcome> {\n const driver = new BrowserDriver()\n const reporter = new ProgressReporter()\n const extractor = new PAAExtractor(driver, reporter)\n if (signal?.aborted) {\n return {\n result: null,\n error: abortReason(signal),\n cleanup: await driver.close(),\n debug: null,\n }\n }\n\n let onAbort: (() => void) | undefined\n const abortPromise = signal\n ? new Promise<never>((_, reject) => {\n onAbort = () => reject(abortReason(signal))\n signal.addEventListener('abort', onAbort, { once: true })\n })\n : null\n\n let result: HarvestResult | null = null\n let error: unknown = null\n let cleanup: BrowserCloseResult\n let debug: HarvestDebugSnapshot | null = null\n try {\n const extraction = extractor.extract(options, signal)\n if (abortPromise) extraction.catch(() => {})\n result = await (abortPromise ? Promise.race([extraction, abortPromise]) : extraction)\n } catch (err) {\n error = err\n } finally {\n if (signal && onAbort) signal.removeEventListener('abort', onAbort)\n debug = result?.diagnostics.debug ?? (options.debug ? {\n enabled: true,\n request: {\n query: options.query,\n locationInput: options.location ?? null,\n canonicalLocation: null,\n uule: null,\n gl: options.gl,\n hl: options.hl,\n device: options.device,\n proxyMode: options.proxyMode,\n proxyZip: options.proxyZip ?? null,\n serpOnly: options.serpOnly,\n pages: options.pages ?? 1,\n },\n browser: driver.getDebugSnapshot(),\n } : null)\n cleanup = await driver.close()\n }\n return error\n ? { result: null, error, cleanup: cleanup!, debug }\n : { result: result!, error: null, cleanup: cleanup!, debug }\n}\n\nexport async function harvest(rawOptions: unknown): Promise<HarvestResult> {\n const raw = typeof rawOptions === 'object' && rawOptions !== null ? rawOptions : {}\n const signal = getAbortSignal(rawOptions)\n const onAttemptEvent = getAttemptLogSink(rawOptions)\n const requestedProxyMode = (raw as { proxyMode?: unknown }).proxyMode\n const proxyMode = requestedProxyMode === 'none'\n ? 'none'\n : requestedProxyMode === 'configured'\n ? 'configured'\n : 'location'\n const kernelApiKey = typeof (raw as { kernelApiKey?: unknown }).kernelApiKey === 'string'\n ? ((raw as { kernelApiKey: string }).kernelApiKey).trim()\n : process.env.KERNEL_API_KEY?.trim()\n const configuredKernelProxyId = typeof (raw as { kernelProxyId?: unknown }).kernelProxyId === 'string'\n ? ((raw as { kernelProxyId: string }).kernelProxyId).trim()\n : process.env.KERNEL_PROXY_ID?.trim()\n const proxyOpts = {\n kernelApiKey,\n proxyMode: proxyMode as ProxyMode,\n configuredKernelProxyId,\n location: typeof (raw as { location?: unknown }).location === 'string' ? (raw as { location: string }).location : undefined,\n proxyZip: typeof (raw as { proxyZip?: unknown }).proxyZip === 'string' ? (raw as { proxyZip: string }).proxyZip : undefined,\n gl: typeof (raw as { gl?: unknown }).gl === 'string' ? (raw as { gl: string }).gl : 'us',\n }\n const serializer = new OutputSerializer()\n\n for (let i = 0; i < MAX_ATTEMPTS; i++) {\n const attemptNumber = i + 1\n const startedAtMs = Date.now()\n try {\n if (signal?.aborted) throw abortReason(signal)\n const resolution = await resolveKernelProxyId({ ...proxyOpts, attemptIndex: i })\n const mergedAttempt = {\n ...raw,\n kernelApiKey,\n kernelProxyId: resolution.kernelProxyId,\n kernelProxyResolution: resolution.resolution,\n proxyMode,\n }\n if (proxyMode === 'none') (mergedAttempt as Record<string, unknown>).kernelProxyId = undefined\n const attemptOptions = HarvestOptionsSchema.parse(mergedAttempt)\n await emitAttemptEvent(onAttemptEvent, {\n type: 'started',\n attemptNumber,\n maxAttempts: MAX_ATTEMPTS,\n query: attemptOptions.query,\n location: attemptOptions.location ?? null,\n maxQuestions: attemptOptions.maxQuestions,\n startedAt: new Date(startedAtMs).toISOString(),\n })\n console.info(JSON.stringify({\n event: 'harvest_attempt_started',\n attempt_number: attemptNumber,\n max_attempts: MAX_ATTEMPTS,\n query: attemptOptions.query,\n location: attemptOptions.location ?? null,\n max_questions: attemptOptions.maxQuestions,\n }))\n const attempt = await extractOnce(attemptOptions, signal)\n if (attempt.error) {\n const err = attempt.error\n if (err instanceof CaptchaError) {\n const willRetry = i < MAX_ATTEMPTS - 1\n console.warn(JSON.stringify({\n event: 'harvest_attempt_captcha',\n attempt_number: attemptNumber,\n max_attempts: MAX_ATTEMPTS,\n message: err.message,\n will_retry: willRetry,\n }))\n await emitAttemptEvent(onAttemptEvent, {\n type: 'finished',\n attemptNumber,\n maxAttempts: MAX_ATTEMPTS,\n outcome: 'captcha',\n kernelSessionId: attempt.cleanup.kernelSessionId,\n questionCount: 0,\n durationMs: Date.now() - startedAtMs,\n error: err.message,\n willRetry,\n cleanup: attempt.cleanup,\n debug: attempt.debug,\n completedAt: new Date().toISOString(),\n })\n if (willRetry) continue\n break\n }\n await emitAttemptEvent(onAttemptEvent, {\n type: 'finished',\n attemptNumber,\n maxAttempts: MAX_ATTEMPTS,\n outcome: classifyAttemptError(err),\n kernelSessionId: attempt.cleanup.kernelSessionId,\n questionCount: 0,\n durationMs: Date.now() - startedAtMs,\n error: errorMessage(err),\n willRetry: false,\n cleanup: attempt.cleanup,\n debug: attempt.debug,\n completedAt: new Date().toISOString(),\n })\n throw err\n }\n const result = attempt.result\n if (!result) throw new Error('Harvest attempt completed without a result')\n await emitAttemptEvent(onAttemptEvent, {\n type: 'finished',\n attemptNumber,\n maxAttempts: MAX_ATTEMPTS,\n outcome: classifyAttemptResult(result),\n kernelSessionId: attempt.cleanup.kernelSessionId,\n questionCount: result.totalQuestions,\n durationMs: Date.now() - startedAtMs,\n error: null,\n willRetry: false,\n cleanup: attempt.cleanup,\n debug: attempt.debug,\n completedAt: new Date().toISOString(),\n })\n if (attemptOptions.format === 'json' || attemptOptions.format === 'both') {\n await serializer.writeJSON(result, attemptOptions.outputDir)\n }\n if (attemptOptions.format === 'csv' || attemptOptions.format === 'both') {\n await Promise.all([\n serializer.writeCSV(result.flat, attemptOptions.outputDir),\n result.videos.length > 0 ? serializer.writeVideoCSV(result.videos, result.seed, attemptOptions.outputDir) : Promise.resolve(''),\n result.forums.length > 0 ? serializer.writeForumCSV(result.forums, result.seed, attemptOptions.outputDir) : Promise.resolve(''),\n result.aiOverview.detected ? serializer.writeAIOverviewCSV(result.aiOverview.citations, result.aiOverview.text, result.seed, attemptOptions.outputDir) : Promise.resolve(''),\n result.aiMode.detected ? serializer.writeAIModeCSV(result.aiMode.citations, result.aiMode.text, result.seed, attemptOptions.outputDir) : Promise.resolve(''),\n result.whatPeopleSaying.length > 0 ? serializer.writeWhatPeopleSayingCSV(result.whatPeopleSaying, result.seed, attemptOptions.outputDir) : Promise.resolve(''),\n ])\n }\n return result\n } catch (err) {\n if (err instanceof CaptchaError) {\n const willRetry = i < MAX_ATTEMPTS - 1\n console.warn(JSON.stringify({\n event: 'harvest_attempt_captcha',\n attempt_number: attemptNumber,\n max_attempts: MAX_ATTEMPTS,\n message: err.message,\n will_retry: willRetry,\n }))\n await emitAttemptEvent(onAttemptEvent, {\n type: 'finished',\n attemptNumber,\n maxAttempts: MAX_ATTEMPTS,\n outcome: 'captcha',\n kernelSessionId: null,\n questionCount: 0,\n durationMs: Date.now() - startedAtMs,\n error: err.message,\n willRetry,\n cleanup: {\n kernelSessionId: null,\n kernelDeleteStarted: false,\n kernelDeleteSucceeded: null,\n kernelDeleteError: null,\n browserCloseSucceeded: null,\n browserCloseError: null,\n },\n debug: null,\n completedAt: new Date().toISOString(),\n })\n if (willRetry) continue\n break\n }\n await emitAttemptEvent(onAttemptEvent, {\n type: 'finished',\n attemptNumber,\n maxAttempts: MAX_ATTEMPTS,\n outcome: classifyAttemptError(err),\n kernelSessionId: null,\n questionCount: 0,\n durationMs: Date.now() - startedAtMs,\n error: errorMessage(err),\n willRetry: false,\n cleanup: {\n kernelSessionId: null,\n kernelDeleteStarted: false,\n kernelDeleteSucceeded: null,\n kernelDeleteError: null,\n browserCloseSucceeded: null,\n browserCloseError: null,\n },\n debug: null,\n completedAt: new Date().toISOString(),\n })\n throw err\n }\n }\n console.warn(JSON.stringify({\n event: 'harvest_captcha_exhausted',\n max_attempts: MAX_ATTEMPTS,\n session_kind: kernelApiKey ? 'kernel' : 'local',\n }))\n throw new CaptchaError(sanitizeVendorName(`CAPTCHA on all ${MAX_ATTEMPTS} fresh sessions. Try again in a few minutes.`))\n}\n","import { execSync } from 'node:child_process'\nimport { readFileSync, writeFileSync, unlinkSync, mkdirSync } from 'node:fs'\nimport { tmpdir } from 'node:os'\nimport { join } from 'node:path'\nimport { fal } from '@fal-ai/client'\nimport { buildClipPrompts, extractEpisodePrompts } from './promptBuilder.js'\nimport type { EpisodeBrief } from './episodeBrief.js'\nimport { generateVoiceover, addBackgroundAudio } from './AudioGenerator.js'\nimport { concatenateClips, uploadToFal, overlayVoiceover } from './VideoMixer.js'\n\nexport interface ClipPairOptions {\n resolution?: '480p' | '720p' | '1080p'\n aspectRatio?: '16:9' | '9:16' | '1:1'\n clipDurationSeconds?: number\n generateAudio?: boolean\n seed?: number\n outputDir?: string\n}\n\nexport interface ClipPairResult {\n clip1Url: string\n clip2Url: string\n finalVideoPath: string\n seed: number\n promptClip1: string\n promptClip2: string\n voiceover: string\n audioMood: string\n}\n\ninterface VideoOutput { video: { url: string }; seed: number }\n\nconst T2V = 'bytedance/seedance-2.0/text-to-video'\nconst I2V = 'bytedance/seedance-2.0/image-to-video'\n\nfunction buildInput(prompt: string, opts: ClipPairOptions, seed?: number, imageUrl?: string) {\n return {\n prompt,\n resolution: opts.resolution ?? '720p',\n duration: opts.clipDurationSeconds ?? 8,\n aspect_ratio: opts.aspectRatio ?? '16:9',\n generate_audio: false,\n ...(seed !== undefined ? { seed } : {}),\n ...(imageUrl !== undefined ? { image_url: imageUrl } : {}),\n }\n}\n\nasync function generate(model: string, input: Record<string, unknown>): Promise<VideoOutput> {\n const { request_id } = await fal.queue.submit(model, { input })\n console.log(`[fal] submitted ${model} → ${request_id}`)\n while (true) {\n await new Promise(r => setTimeout(r, 5000))\n const s = await fal.queue.status(model, { requestId: request_id, logs: false })\n console.log(`[fal] ${request_id} → ${s.status}`)\n if ((s.status as string) === 'FAILED') throw new Error(`Request ${request_id} failed`)\n if ((s.status as string) !== 'COMPLETED') continue\n const result = await fal.queue.result(model, { requestId: request_id })\n return result.data as VideoOutput\n }\n}\n\nasync function extractLastFrame(videoUrl: string, outDir: string): Promise<string> {\n const ts = Date.now()\n const mp4Path = join(outDir, `clip1-raw-${ts}.mp4`)\n const jpgPath = join(outDir, `last-frame-${ts}.jpg`)\n\n const res = await fetch(videoUrl)\n if (!res.ok) throw new Error(`Failed to download clip 1 (${res.status})`)\n writeFileSync(mp4Path, Buffer.from(await res.arrayBuffer()))\n\n try {\n execSync(`ffmpeg -sseof -0.1 -i \"${mp4Path}\" -vframes 1 -y \"${jpgPath}\" -loglevel error`)\n } finally {\n try { unlinkSync(mp4Path) } catch {}\n }\n return jpgPath\n}\n\nexport class VideoGenerator {\n constructor(apiKey?: string) {\n const key = apiKey ?? process.env['FAL_KEY']\n if (!key) throw new Error('FAL_KEY is required')\n fal.config({ credentials: key })\n }\n\n async generateClipPair(\n question: string,\n answer: string,\n opts: ClipPairOptions = {},\n ): Promise<ClipPairResult> {\n const outDir = opts.outputDir ?? join(tmpdir(), `paa-video-${Date.now()}`)\n mkdirSync(outDir, { recursive: true })\n\n console.log('\\n[1/7] Generating prompts via QWEN 3.6...')\n const prompts = await buildClipPrompts(question, answer)\n console.log(' Voiceover:', prompts.voiceover)\n console.log(' Audio mood:', prompts.audioMood)\n\n console.log('\\n[2/7] Generating clip 1 (text-to-video)...')\n const result1 = await generate(T2V, buildInput(prompts.clip1, opts, opts.seed))\n\n console.log('\\n[3/7] Extracting last frame → clip 2 start...')\n const jpgPath = await extractLastFrame(result1.video.url, outDir)\n const imageBlob = new Blob([readFileSync(jpgPath)], { type: 'image/jpeg' })\n const frameUrl = await fal.storage.upload(imageBlob)\n try { unlinkSync(jpgPath) } catch {}\n\n console.log('\\n[4/7] Generating clip 2 (image-to-video from last frame)...')\n const seed2 = opts.seed !== undefined ? opts.seed + 1 : undefined\n const result2 = await generate(I2V, buildInput(prompts.clip2, opts, seed2, frameUrl))\n\n console.log('\\n[5/7] Concatenating clips + generating voiceover (parallel)...')\n const [combinedPath, voiceoverUrl] = await Promise.all([\n concatenateClips(result1.video.url, result2.video.url, outDir),\n generateVoiceover(prompts.voiceover),\n ])\n\n console.log('\\n[6/7] Adding background audio via MMAudio V2...')\n const falVideoUrl = await uploadToFal(combinedPath)\n const totalDuration = (opts.clipDurationSeconds ?? 8) * 2\n const videoWithAudioUrl = await addBackgroundAudio(falVideoUrl, prompts.audioMood, totalDuration)\n\n console.log('\\n[7/7] Overlaying voiceover on final video...')\n const videoWithAudioPath = join(outDir, `with-bg-audio-${Date.now()}.mp4`)\n const bgRes = await fetch(videoWithAudioUrl)\n writeFileSync(videoWithAudioPath, Buffer.from(await bgRes.arrayBuffer()))\n const finalVideoPath = await overlayVoiceover(videoWithAudioPath, voiceoverUrl, outDir)\n\n return {\n clip1Url: result1.video.url,\n clip2Url: result2.video.url,\n finalVideoPath,\n seed: result1.seed,\n promptClip1: prompts.clip1,\n promptClip2: prompts.clip2,\n voiceover: prompts.voiceover,\n audioMood: prompts.audioMood,\n }\n }\n\n async generateEpisode(\n brief: EpisodeBrief,\n opts: ClipPairOptions = {},\n ): Promise<ClipPairResult> {\n const outDir = opts.outputDir ?? join(tmpdir(), `episode-${brief.episodeNumber}-${Date.now()}`)\n mkdirSync(outDir, { recursive: true })\n\n const prompts = extractEpisodePrompts(brief)\n console.log(`\\n[Episode ${brief.episodeNumber}/${brief.episodeCount}] ${brief.sectionTitle}`)\n console.log(' Voiceover:', prompts.voiceover)\n\n console.log('\\n[2/7] Generating clip 1 (text-to-video)...')\n const result1 = await generate(T2V, buildInput(prompts.clip1, opts, opts.seed))\n\n console.log('\\n[3/7] Extracting last frame → clip 2 start...')\n const jpgPath = await extractLastFrame(result1.video.url, outDir)\n const imageBlob = new Blob([readFileSync(jpgPath)], { type: 'image/jpeg' })\n const frameUrl = await fal.storage.upload(imageBlob)\n try { unlinkSync(jpgPath) } catch {}\n\n console.log('\\n[4/7] Generating clip 2 (image-to-video from last frame)...')\n const seed2 = opts.seed !== undefined ? opts.seed + 1 : undefined\n const result2 = await generate(I2V, buildInput(prompts.clip2, opts, seed2, frameUrl))\n\n console.log('\\n[5/7] Concatenating clips + generating voiceover (parallel)...')\n const [combinedPath, voiceoverUrl] = await Promise.all([\n concatenateClips(result1.video.url, result2.video.url, outDir),\n generateVoiceover(prompts.voiceover),\n ])\n\n console.log('\\n[6/7] Adding background audio via MMAudio V2...')\n const falVideoUrl = await uploadToFal(combinedPath)\n const totalDuration = (opts.clipDurationSeconds ?? 8) * 2\n const videoWithAudioUrl = await addBackgroundAudio(falVideoUrl, prompts.audioMood, totalDuration)\n\n console.log('\\n[7/7] Overlaying voiceover on final video...')\n const videoWithAudioPath = join(outDir, `with-bg-audio-${Date.now()}.mp4`)\n const bgRes = await fetch(videoWithAudioUrl)\n writeFileSync(videoWithAudioPath, Buffer.from(await bgRes.arrayBuffer()))\n const finalVideoPath = await overlayVoiceover(videoWithAudioPath, voiceoverUrl, outDir)\n\n return {\n clip1Url: result1.video.url,\n clip2Url: result2.video.url,\n finalVideoPath,\n seed: result1.seed,\n promptClip1: prompts.clip1,\n promptClip2: prompts.clip2,\n voiceover: prompts.voiceover,\n audioMood: prompts.audioMood,\n }\n }\n}\n","export interface ClipPromptPair {\n clip1: string\n clip2: string\n voiceover: string\n audioMood: string\n}\n\nexport interface EpisodeBriefInput {\n storyMoment: string\n characterName: string\n sectionTitle: string\n clip1: string\n clip2: string\n voiceover: string\n audioMood: string\n}\n\nconst DEEPINFRA_URL = 'https://api.deepinfra.com/v1/openai/chat/completions'\nconst OPENROUTER_URL = 'https://openrouter.ai/api/v1/chat/completions'\nconst QWEN_MODEL = 'Qwen/Qwen3.6-35B-A3B'\n\nconst SYSTEM_PROMPT = `You are a video prompt engineer for Seedance 2.0 text-to-video AI.\n\nIMPORTANT TECHNICAL CONTEXT: Clip 2 will be generated using image-to-video, meaning it will start from the exact last frame of Clip 1. The two clips will be visually seamless — same location, same characters, continuous motion. You must write prompts that make this feel like one uninterrupted 16-second video.\n\nYour job: turn a PAA question and its answer into a complete short-form video with visuals, narration, and a background audio mood.\n\nProduce four things:\n\n1. clip1 (~8s): Show a real person experiencing the situation the question describes. End on a specific frozen moment — a held expression, a paused action — that clip 2 continues from.\n\n2. clip2 (~8s): Continue from that exact frozen frame. Deliver the informational payoff from the answer. Show specific facts playing out visually. Describe motion continuing from clip 1's ending frame, not a new scene.\n\n3. voiceover: A spoken narration that fits in 10 seconds of TTS audio. HARD LIMIT: 22 words maximum. Count every word before finalizing — if it exceeds 22 words, cut it. Starts with the problem, ends with the answer. No filler, no \"in conclusion\". Informational and direct.\n\n4. audioMood: 6-10 words describing INSTRUMENTAL background music only — no vocals, no voice, no lyrics. Describe instruments and mood (e.g. \"warm acoustic guitar, uplifting, professional home service, no vocals\"). Will be passed to an AI audio model.\n\nRules for visuals:\n- No text, captions, graphics, or overlays\n- Photorealistic, natural lighting, specific details\n- Describe exactly what the camera sees\n\nRespond with JSON only:\n{\"clip1\": \"...\", \"clip2\": \"...\", \"voiceover\": \"...\", \"audioMood\": \"...\"}`\n\ninterface ChatResponse {\n choices: Array<{ message: { content: string } }>\n}\n\nasync function callLLM(apiKey: string, baseUrl: string, question: string, answer: string): Promise<ClipPromptPair> {\n const res = await fetch(baseUrl, {\n method: 'POST',\n headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json' },\n body: JSON.stringify({\n model: QWEN_MODEL,\n temperature: 0.7,\n messages: [\n { role: 'system', content: SYSTEM_PROMPT },\n { role: 'user', content: `Question: ${question}\\n\\nAnswer: ${answer.slice(0, 500)}` },\n ],\n }),\n })\n if (!res.ok) throw new Error(`LLM call failed (${res.status}): ${await res.text()}`)\n\n const data = (await res.json()) as ChatResponse\n const raw = data.choices[0]?.message?.content?.trim() ?? ''\n const match = raw.match(/\\{[\\s\\S]*\\}/)\n if (!match) throw new Error(`No JSON in QWEN response: ${raw.slice(0, 200)}`)\n\n const parsed = JSON.parse(match[0]) as Partial<ClipPromptPair>\n if (!parsed.clip1 || !parsed.clip2 || !parsed.voiceover || !parsed.audioMood) {\n throw new Error(`QWEN response missing fields: ${raw.slice(0, 200)}`)\n }\n return parsed as ClipPromptPair\n}\n\nexport async function buildClipPrompts(question: string, answer: string): Promise<ClipPromptPair> {\n const deepinfraKey = process.env['DEEPINFRA_API_KEY']\n const openrouterKey = process.env['OPENROUTER_API_KEY']\n\n if (deepinfraKey) {\n try {\n return await callLLM(deepinfraKey, DEEPINFRA_URL, question, answer)\n } catch (err) {\n console.warn('[promptBuilder] DeepInfra failed, trying OpenRouter:', (err as Error).message)\n }\n }\n if (openrouterKey) {\n return await callLLM(openrouterKey, OPENROUTER_URL, question, answer)\n }\n throw new Error('No LLM key — set DEEPINFRA_API_KEY or OPENROUTER_API_KEY')\n}\n\nexport function extractEpisodePrompts(brief: EpisodeBriefInput): ClipPromptPair {\n if (!brief.clip1 || !brief.clip2 || !brief.voiceover || !brief.audioMood) {\n throw new Error('Episode brief is missing prompt fields — run blog-to-video skill to regenerate')\n }\n return { clip1: brief.clip1, clip2: brief.clip2, voiceover: brief.voiceover, audioMood: brief.audioMood }\n}\n\nconst EPISODE_SYSTEM_PROMPT = `You are a video prompt engineer for Seedance 2.0 text-to-video AI.\n\nYou are working with a character-driven narrative brief. The clips must feel like a continuous 16-second moment in one person's story — not an explainer video.\n\nIMPORTANT TECHNICAL CONTEXT: Clip 2 will start from the exact last frame of Clip 1. Both clips must show the same person, same location, same lighting. Clip 2 continues motion from Clip 1's frozen ending frame.\n\nUse the Kling prompt format for every clip:\n[Shot type] of [character name] [action]. The scene starts at [keyframe 1]. Camera Motion: [motion] ending in [keyframe 2]. Lighting: [style]. Style: [style].\n\nShot types: Close-up, Medium shot, Over-the-shoulder, Wide shot, Tracking shot.\nCamera motions: Slow push in, Slow pull back, Rack focus, Static hold, Subtle drift right/left, Pan left/right.\n\nRules for visuals:\n- No text, no captions, no UI overlays, no readable code on screen\n- Photorealistic, specific objects, natural-feeling details\n- Keyframe 2 (clip 1's end) must be a specific held moment clip 2 continues from\n\nvoiceover: The character's internal tension, in 22 words maximum. Not a summary. Count every word.\naudioMood: Specific instruments + tempo + emotional register + \"no vocals, no lyrics\".\n\nRespond with JSON only: {\"clip1\": \"...\", \"clip2\": \"...\", \"voiceover\": \"...\", \"audioMood\": \"...\"}`\n\nasync function callEpisodeLLM(apiKey: string, baseUrl: string, brief: EpisodeBriefInput): Promise<ClipPromptPair> {\n const userContent = `Character: ${brief.characterName}\nSection: ${brief.sectionTitle}\nStory moment: ${brief.storyMoment}\n\nExisting clip1 (refine if needed): ${brief.clip1}\nExisting clip2 (refine if needed): ${brief.clip2}\nExisting voiceover: ${brief.voiceover}\nExisting audioMood: ${brief.audioMood}\n\nProduce refined Kling-format prompts that follow all rules. Keep what's good, fix what violates the format.`\n\n const res = await fetch(baseUrl, {\n method: 'POST',\n headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json' },\n body: JSON.stringify({\n model: QWEN_MODEL,\n temperature: 0.5,\n messages: [\n { role: 'system', content: EPISODE_SYSTEM_PROMPT },\n { role: 'user', content: userContent },\n ],\n }),\n })\n if (!res.ok) throw new Error(`LLM episode call failed (${res.status}): ${await res.text()}`)\n\n const data = (await res.json()) as ChatResponse\n const raw = data.choices[0]?.message?.content?.trim() ?? ''\n const match = raw.match(/\\{[\\s\\S]*\\}/)\n if (!match) throw new Error(`No JSON in episode response: ${raw.slice(0, 200)}`)\n\n const parsed = JSON.parse(match[0]) as Partial<ClipPromptPair>\n if (!parsed.clip1 || !parsed.clip2 || !parsed.voiceover || !parsed.audioMood) {\n throw new Error(`Episode response missing fields: ${raw.slice(0, 200)}`)\n }\n return parsed as ClipPromptPair\n}\n\nexport async function regenerateEpisodePrompts(brief: EpisodeBriefInput): Promise<ClipPromptPair> {\n const deepinfraKey = process.env['DEEPINFRA_API_KEY']\n const openrouterKey = process.env['OPENROUTER_API_KEY']\n\n if (deepinfraKey) {\n try {\n return await callEpisodeLLM(deepinfraKey, DEEPINFRA_URL, brief)\n } catch (err) {\n console.warn('[promptBuilder] DeepInfra failed, trying OpenRouter:', (err as Error).message)\n }\n }\n if (openrouterKey) {\n return await callEpisodeLLM(openrouterKey, OPENROUTER_URL, brief)\n }\n throw new Error('No LLM key — set DEEPINFRA_API_KEY or OPENROUTER_API_KEY')\n}\n","import { writeFileSync, mkdirSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { tmpdir } from 'node:os'\nimport { fal } from '@fal-ai/client'\n\nconst MMAUDIO_MODEL = 'fal-ai/mmaudio-v2'\nconst ELEVENLABS_MODEL = 'fal-ai/elevenlabs/tts'\nconst GEMINI_TTS_MODEL = 'fal-ai/google/gemini-2.5-flash-preview-tts'\n\ninterface VideoOutput { video: { url: string } }\ninterface TTSOutput { audio: { url: string } }\n\nasync function downloadAudio(url: string): Promise<Buffer> {\n const res = await fetch(url)\n if (!res.ok) throw new Error(`Failed to download TTS audio (${res.status})`)\n return Buffer.from(await res.arrayBuffer())\n}\n\nexport async function generateVoiceover(text: string): Promise<string> {\n console.log('[AudioGenerator] Generating voiceover...')\n\n const outDir = join(tmpdir(), `tts-${Date.now()}`)\n mkdirSync(outDir, { recursive: true })\n const outPath = join(outDir, 'voiceover.mp3')\n\n try {\n const voiceId = process.env['ELEVENLABS_VOICE_ID'] ?? 'pNInz6obpgDQGcFmaJgB'\n const result = await fal.run(ELEVENLABS_MODEL, {\n input: { text, voice_id: voiceId, model_id: 'eleven_v3' },\n }) as unknown as TTSOutput\n writeFileSync(outPath, await downloadAudio(result.audio.url))\n console.log('[AudioGenerator] TTS: ElevenLabs via fal')\n return outPath\n } catch (err) {\n console.warn('[AudioGenerator] ElevenLabs via fal failed, trying Gemini:', (err as Error).message)\n }\n\n const voice = process.env['GEMINI_TTS_VOICE'] ?? 'Kore'\n const result = await fal.run(GEMINI_TTS_MODEL, { input: { text, voice } }) as unknown as TTSOutput\n writeFileSync(outPath, await downloadAudio(result.audio.url))\n console.log('[AudioGenerator] TTS: Gemini via fal')\n return outPath\n}\n\nexport async function addBackgroundAudio(videoUrl: string, mood: string, durationSeconds: number): Promise<string> {\n console.log('[AudioGenerator] Adding background audio via MMAudio V2...')\n const result = await fal.run(MMAUDIO_MODEL, {\n input: {\n video_url: videoUrl,\n prompt: mood,\n negative_prompt: 'speech, voice, talking, dialogue, narration, vocals, singing, human voice, conversation, words, lyrics, announcer, commentary',\n duration: durationSeconds,\n cfg_strength: 4.5,\n },\n }) as unknown as VideoOutput\n return result.video.url\n}\n","import { execSync } from 'node:child_process'\nimport { writeFileSync, mkdirSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { fal } from '@fal-ai/client'\n\nasync function download(url: string, destPath: string): Promise<void> {\n const res = await fetch(url)\n if (!res.ok) throw new Error(`Download failed (${res.status}): ${url}`)\n writeFileSync(destPath, Buffer.from(await res.arrayBuffer()))\n}\n\nexport async function concatenateClips(clip1Url: string, clip2Url: string, outDir: string): Promise<string> {\n mkdirSync(outDir, { recursive: true })\n const ts = Date.now()\n const p1 = join(outDir, `clip1-${ts}.mp4`)\n const p2 = join(outDir, `clip2-${ts}.mp4`)\n const out = join(outDir, `combined-${ts}.mp4`)\n\n console.log('[VideoMixer] Downloading clips...')\n await Promise.all([download(clip1Url, p1), download(clip2Url, p2)])\n\n console.log('[VideoMixer] Concatenating...')\n execSync(\n `ffmpeg -i \"${p1}\" -i \"${p2}\" -filter_complex \"[0:v][1:v]concat=n=2:v=1:a=0[v]\" -map \"[v]\" -y \"${out}\" -loglevel error`\n )\n return out\n}\n\nexport async function uploadToFal(localPath: string): Promise<string> {\n const { readFileSync } = await import('node:fs')\n const blob = new Blob([readFileSync(localPath)], { type: 'video/mp4' })\n const url = await fal.storage.upload(blob)\n console.log('[VideoMixer] Uploaded to fal:', url)\n return url\n}\n\nexport async function overlayVoiceover(\n videoPath: string,\n voiceoverUrl: string,\n outDir: string,\n): Promise<string> {\n const ts = Date.now()\n const wav = join(outDir, `voiceover-${ts}.wav`)\n const out = join(outDir, `final-${ts}.mp4`)\n\n console.log('[VideoMixer] Downloading voiceover...')\n await download(voiceoverUrl, wav)\n\n console.log('[VideoMixer] Mixing voiceover over background audio...')\n execSync(\n `ffmpeg -i \"${videoPath}\" -i \"${wav}\" ` +\n `-filter_complex \"[0:a]volume=0.2[bg];[1:a]volume=1.0[vo];[bg][vo]amix=inputs=2:duration=first[a]\" ` +\n `-map 0:v -map \"[a]\" -c:v copy -y \"${out}\" -loglevel error`\n )\n return out\n}\n"],"mappings":"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","names":["StealthPlugin","Kernel","playwrightChromium","DESKTOP_USER_AGENT","MOBILE_USER_AGENT","s","organicResults","localPack","rawEntityIds","entityIds","aiSurfaces","locationEvidence","allOrganic","stats","fs","path","Papa","import_sdk","proxyIdSuffix","errorText","Kernel","createErrors","resolution","import_node_child_process","import_node_fs","import_node_os","import_node_path","import_client","import_node_fs","import_node_path","result","import_node_fs","import_node_path","import_client","readFileSync"]}
|