aeorank 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +172 -0
- package/dist/cli.js +2626 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.cjs +2584 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +334 -0
- package/dist/index.d.ts +334 -0
- package/dist/index.js +2536 -0
- package/dist/index.js.map +1 -0
- package/package.json +78 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/parked-domain.ts","../src/site-crawler.ts","../src/scoring.ts","../src/headless-fetch.ts","../src/scorecard-builder.ts","../src/narrative-generator.ts","../src/multi-page-fetcher.ts","../src/page-analyzer.ts","../src/audit.ts"],"sourcesContent":["/**\n * AEORank - AI Engine Optimization audit engine.\n *\n * Three tiers of access:\n * 1. Simple: import { audit } from 'aeorank'\n * 2. Typed: import type { AuditData, ScoreCardItem } from 'aeorank'\n * 3. Advanced: import { prefetchSiteData, calculateOverallScore } from 'aeorank'\n */\n\n// ─── Primary API ────────────────────────────────────────────────────────────\n\nexport { audit } from './audit.js';\nexport type { AuditOptions, AuditResult } from './audit.js';\n\n// ─── Types ──────────────────────────────────────────────────────────────────\n\nexport type {\n Status,\n Severity,\n FindingType,\n ImpactLevel,\n ScoreCardItem,\n DetailedFinding,\n CriterionDetail,\n Deliverable,\n PitchMetric,\n PageCategory,\n PageIssue,\n PageReview,\n AuditData,\n AuditStatus,\n Priority,\n FindingSeverity,\n AuditFinding,\n} from './types.js';\n\n// ─── Advanced: individual pipeline stages ───────────────────────────────────\n\nexport {\n prefetchSiteData,\n auditSiteFromData,\n extractRawDataSummary,\n} from './site-crawler.js';\n\nexport type {\n CriterionResult,\n SiteData,\n FetchResult,\n RawDataSummary,\n} from './site-crawler.js';\n\nexport { calculateOverallScore } from './scoring.js';\n\nexport {\n buildScorecard,\n buildDetailedFindings,\n scoreToStatus,\n CRITERION_LABELS,\n} from './scorecard-builder.js';\n\nexport {\n generateVerdict,\n generateOpportunities,\n generatePitchNumbers,\n generateBottomLine,\n} from './narrative-generator.js';\n\nexport {\n analyzePage,\n analyzeAllPages,\n} from './page-analyzer.js';\n\nexport {\n fetchMultiPageData,\n extractNavLinks,\n extractContentPagesFromSitemap,\n} from './multi-page-fetcher.js';\n\nexport {\n isSpaShell,\n classifyRendering,\n fetchWithHeadless,\n} from './headless-fetch.js';\n\nexport type {\n RenderingMethod,\n HeadlessOptions,\n} from './headless-fetch.js';\n\nexport { detectParkedDomain } from './parked-domain.js';\nexport type { ParkedDomainResult } from './parked-domain.js';\n","/**\n * Parked domain detection.\n * Vendored from @aeo/queue/redirect-check (pure functions, no network).\n */\n\nexport interface ParkedDomainResult {\n isParked: boolean;\n reason?: string;\n}\n\n/** Known parking paths used by domain parking services */\nconst PARKING_PATHS = ['/lander', '/parking', '/park', '/sedoparking'];\n\n/** Known parking service domains found in page HTML (scripts, iframes, links) */\nconst PARKING_SERVICE_DOMAINS = [\n 'sedoparking.com',\n 'parkingcrew.net',\n 'bodis.com',\n 'dsparking.com',\n 'hugedomains.com',\n 'afternic.com',\n 'dan.com',\n 'undeveloped.com',\n 'domainmarket.com',\n 'sav.com',\n 'domaincontrol.com',\n 'above.com',\n 'domainlore.com',\n 'domainnamesales.com',\n 'brandbucket.com',\n 'squadhelp.com',\n 'godaddy.com/domainsearch',\n];\n\n/** Parking-specific text patterns (case-insensitive) */\nconst PARKING_TEXT_PATTERNS = [\n /\\bbuy this domain\\b/i,\n /\\bdomain is for sale\\b/i,\n /\\bthis domain may be for sale\\b/i,\n /\\bdomain for sale\\b/i,\n /\\bthis domain name is available\\b/i,\n /\\bparked by/i,\n /\\bthis page is parked/i,\n /\\bdomain has expired/i,\n /\\bthis domain has been registered/i,\n /\\bmake an offer on this domain\\b/i,\n /\\bget this domain\\b/i,\n /\\bacquire this domain\\b/i,\n];\n\nfunction detectParkingRedirect(bodySnippet: string): string | null {\n const relativeRedirect = bodySnippet.match(\n /window\\.location\\.(replace|assign|href)\\s*[=(]\\s*['\"](\\/[^'\"]*)['\"]/i,\n );\n if (!relativeRedirect) return null;\n const path = relativeRedirect[2].toLowerCase().replace(/[?#].*/, '');\n if (PARKING_PATHS.includes(path)) {\n return `js-redirect to ${relativeRedirect[2]}`;\n }\n return null;\n}\n\nfunction detectParkingService(bodySnippet: string): string | null {\n const lower = bodySnippet.toLowerCase();\n for (const service of PARKING_SERVICE_DOMAINS) {\n if (lower.includes(service)) {\n return `parking service: ${service}`;\n }\n }\n return null;\n}\n\nfunction detectParkingText(bodySnippet: string): string | null {\n for (const pattern of PARKING_TEXT_PATTERNS) {\n if (pattern.test(bodySnippet)) {\n return `parking text: ${bodySnippet.match(pattern)?.[0]}`;\n }\n }\n return null;\n}\n\n/**\n * Detect if a page is a parked/lost/for-sale domain.\n * Pure function - no network calls.\n */\nexport function detectParkedDomain(bodySnippet: string): ParkedDomainResult {\n const parkingRedirect = detectParkingRedirect(bodySnippet);\n if (parkingRedirect) return { isParked: true, reason: parkingRedirect };\n\n const parkingService = detectParkingService(bodySnippet);\n if (parkingService) return { isParked: true, reason: parkingService };\n\n const parkingText = detectParkingText(bodySnippet);\n if (parkingText) return { isParked: true, reason: parkingText };\n\n return { isParked: false };\n}\n","import type { AuditFinding, AuditStatus, Priority } from './types.js';\nimport { detectParkedDomain } from './parked-domain.js';\n\nexport interface CriterionResult {\n criterion: string;\n criterion_label: string;\n score: number;\n status: AuditStatus;\n findings: AuditFinding[];\n fix_priority: Priority;\n}\n\n// ─── Pre-fetched site data (one fetch per URL, reused across all criteria) ───\n\nexport type PageCategory = 'homepage' | 'blog' | 'about' | 'pricing' | 'services'\n | 'contact' | 'team' | 'resources' | 'docs' | 'cases' | 'content';\n\nexport interface FetchResult {\n text: string;\n status: number;\n finalUrl?: string;\n category?: PageCategory;\n}\n\nexport interface SiteData {\n domain: string;\n protocol: 'https' | 'http' | null;\n homepage: FetchResult | null;\n llmsTxt: FetchResult | null;\n robotsTxt: FetchResult | null;\n faqPage: FetchResult | null;\n sitemapXml: FetchResult | null;\n rssFeed: FetchResult | null;\n aiTxt: FetchResult | null;\n /** Set when homepage redirects to a different (non-brand) domain */\n redirectedTo: string | null;\n /** Set when homepage is a parked/for-sale/lost domain */\n parkedReason: string | null;\n /** Sampled blog/content pages from sitemap (up to 5) */\n blogSample?: FetchResult[];\n}\n\n// Raw data summary for AI narrative generation\nexport interface RawDataSummary {\n domain: string;\n protocol: 'https' | 'http' | null;\n homepage_length: number;\n homepage_text_length: number;\n has_https: boolean;\n llms_txt_status: number | null;\n llms_txt_length: number;\n robots_txt_status: number | null;\n robots_txt_snippet: string;\n robots_txt_ai_crawlers: string[];\n robots_txt_blocked_crawlers: string[];\n schema_types_found: string[];\n schema_block_count: number;\n faq_page_status: number | null;\n faq_page_length: number;\n sitemap_status: number | null;\n internal_link_count: number;\n external_link_count: number;\n question_headings_count: number;\n h1_count: number;\n has_meta_description: boolean;\n has_title: boolean;\n has_phone: boolean;\n has_address: boolean;\n has_org_schema: boolean;\n has_social_links: boolean;\n semantic_elements_found: string[];\n img_count: number;\n img_with_alt_count: number;\n has_lang_attr: boolean;\n has_aria: boolean;\n has_breadcrumbs: boolean;\n has_nav: boolean;\n has_footer: boolean;\n has_case_studies: boolean;\n has_statistics: boolean;\n has_expert_attribution: boolean;\n has_blog_section: boolean;\n // New criteria fields\n has_date_modified_schema: boolean;\n time_element_count: number;\n sitemap_url_count: number;\n has_rss_feed: boolean;\n table_count: number;\n ordered_list_count: number;\n unordered_list_count: number;\n definition_pattern_count: number;\n has_ai_txt: boolean;\n has_person_schema: boolean;\n fact_data_point_count: number;\n has_canonical: boolean;\n has_license_schema: boolean;\n sitemap_recent_lastmod_count: number;\n rendered_with_headless?: boolean;\n // Speakable schema fields\n has_speakable_schema: boolean;\n speakable_selector_count: number;\n // Blog sample fields\n blog_sample_count: number;\n blog_sample_urls: string[];\n blog_sample_schema_types: string[];\n blog_sample_question_headings: number;\n blog_sample_faq_schema_found: boolean;\n}\n\nasync function fetchText(url: string): Promise<FetchResult | null> {\n try {\n const res = await fetch(url, {\n signal: AbortSignal.timeout(15000),\n headers: { 'User-Agent': 'AEO-Visibility-Bot/1.0' },\n redirect: 'follow',\n });\n const text = await res.text();\n return { text: text.slice(0, 500000), status: res.status, finalUrl: res.url };\n } catch {\n return null;\n }\n}\n\n/** Extract bare domain from URL (no protocol, www, port, path) */\nfunction extractDomain(url: string): string {\n return url.replace(/^https?:\\/\\//, '').replace(/\\/.*/, '').replace(/:[0-9]+$/, '').replace(/^www\\./, '').toLowerCase();\n}\n\n/** Extract brand name from domain (everything before TLD) */\nfunction extractBrandName(domain: string): string {\n const parts = domain.split('.');\n const twoPartTlds = ['co.uk', 'com.au', 'co.jp', 'com.br', 'co.nz', 'co.in'];\n const lastTwo = parts.slice(-2).join('.');\n if (twoPartTlds.includes(lastTwo) && parts.length > 2) {\n return parts.slice(0, -2).join('.');\n }\n return parts.length > 1 ? parts.slice(0, -1).join('.') : domain;\n}\n\n/** Check if redirect target is a different brand (hijacked domain) */\nfunction detectCrossDomainRedirect(originalDomain: string, homepage: FetchResult): string | null {\n if (!homepage.finalUrl) return null;\n const finalDomain = extractDomain(homepage.finalUrl);\n const cleanOriginal = originalDomain.replace(/^www\\./, '').toLowerCase();\n if (\n finalDomain === cleanOriginal ||\n finalDomain === `www.${cleanOriginal}` ||\n extractBrandName(finalDomain) === extractBrandName(cleanOriginal)\n ) {\n return null;\n }\n return finalDomain;\n}\n\n/** Detect JS-based cross-domain redirect in HTML body */\nfunction detectJsRedirect(bodySnippet: string, originalDomain: string): string | null {\n const jsMatch = bodySnippet.match(\n /window\\.location\\.(replace|assign|href)\\s*[=(]\\s*['\"]https?:\\/\\/([^'\"]+)['\"]/i,\n );\n if (!jsMatch) return null;\n const jsDomain = extractDomain('https://' + jsMatch[2]);\n const cleanOriginal = originalDomain.replace(/^www\\./, '').toLowerCase();\n if (\n jsDomain === cleanOriginal ||\n jsDomain === `www.${cleanOriginal}` ||\n extractBrandName(jsDomain) === extractBrandName(cleanOriginal)\n ) {\n return null;\n }\n return jsDomain;\n}\n\n/** Detect HTML served for plain-text URLs (e.g. catch-all routes returning 200 for /ai.txt) */\nfunction isHtmlResponse(result: FetchResult | null): boolean {\n if (!result || result.status !== 200) return false;\n const trimmed = result.text.trimStart().slice(0, 200).toLowerCase();\n return trimmed.startsWith('<!doctype html') || trimmed.startsWith('<html') || /<head[\\s>]/i.test(trimmed);\n}\n\n/**\n * Fetches all site data in parallel with HTTPS/HTTP fallback.\n * Single entry point for all HTTP requests - no redundant fetches.\n */\nexport async function prefetchSiteData(domain: string): Promise<SiteData> {\n // Step 1: Detect protocol (HTTPS first, fallback to HTTP)\n let protocol: 'https' | 'http' | null = null;\n let homepage: FetchResult | null = null;\n\n homepage = await fetchText(`https://${domain}`);\n if (homepage && homepage.status >= 200 && homepage.status < 400) {\n protocol = 'https';\n } else {\n homepage = await fetchText(`http://${domain}`);\n if (homepage && homepage.status >= 200 && homepage.status < 400) {\n protocol = 'http';\n }\n }\n\n if (!protocol) {\n return { domain, protocol: null, homepage: null, llmsTxt: null, robotsTxt: null, faqPage: null, sitemapXml: null, rssFeed: null, aiTxt: null, redirectedTo: null, parkedReason: null, blogSample: [] };\n }\n\n // Check for cross-domain redirect (hijacked/expired domains)\n const httpRedirect = homepage ? detectCrossDomainRedirect(domain, homepage) : null;\n const jsRedirect = homepage ? detectJsRedirect(homepage.text.slice(0, 8192), domain) : null;\n const redirectedTo = httpRedirect || jsRedirect;\n\n if (redirectedTo) {\n return { domain, protocol, homepage, llmsTxt: null, robotsTxt: null, faqPage: null, sitemapXml: null, rssFeed: null, aiTxt: null, redirectedTo, parkedReason: null, blogSample: [] };\n }\n\n // Check for parked/lost/for-sale domains\n const parkedResult = homepage ? detectParkedDomain(homepage.text.slice(0, 8192)) : { isParked: false };\n if (parkedResult.isParked) {\n return { domain, protocol, homepage, llmsTxt: null, robotsTxt: null, faqPage: null, sitemapXml: null, rssFeed: null, aiTxt: null, redirectedTo: null, parkedReason: parkedResult.reason || 'parked', blogSample: [] };\n }\n\n const baseUrl = `${protocol}://${domain}`;\n\n // Step 2: Fetch all other resources in parallel\n const [llmsTxt, robotsTxt, faqPage, sitemapXml, aiTxt] = await Promise.all([\n fetchText(`${baseUrl}/llms.txt`),\n fetchText(`${baseUrl}/robots.txt`),\n fetchText(`${baseUrl}/faq`).then(async (result) => {\n if (result && result.status === 200) return result;\n // Fallback chain for FAQ page variants\n for (const path of ['/frequently-asked-questions', '/help', '/support', '/help-center']) {\n const fallback = await fetchText(`${baseUrl}${path}`);\n if (fallback && fallback.status === 200) return fallback;\n }\n return result;\n }),\n fetchText(`${baseUrl}/sitemap.xml`),\n fetchText(`${baseUrl}/ai.txt`),\n ]);\n\n // Step 3: Discover RSS feed URL from homepage, then fetch it\n let rssFeed: FetchResult | null = null;\n if (homepage) {\n const rssLinkMatch = homepage.text.match(/<link[^>]*type=\"application\\/(?:rss|atom)\\+xml\"[^>]*href=\"([^\"]*)\"[^>]*>/i);\n if (rssLinkMatch) {\n const rssUrl = rssLinkMatch[1].startsWith('http') ? rssLinkMatch[1] : `${baseUrl}${rssLinkMatch[1]}`;\n rssFeed = await fetchText(rssUrl);\n }\n if (!rssFeed || rssFeed.status !== 200) {\n // Fallback: try common RSS paths\n for (const path of ['/feed', '/rss.xml', '/feed.xml']) {\n rssFeed = await fetchText(`${baseUrl}${path}`);\n if (rssFeed && rssFeed.status === 200 && (rssFeed.text.includes('<rss') || rssFeed.text.includes('<feed') || rssFeed.text.includes('<channel'))) break;\n rssFeed = null;\n }\n }\n }\n\n // Step 4: Sample blog pages from sitemap (up to 5)\n let blogSample: FetchResult[] = [];\n if (sitemapXml && sitemapXml.status === 200) {\n let sitemapForBlog = sitemapXml.text;\n\n // If sitemapindex, fetch the best sub-sitemap first\n const subSitemapUrl = extractSubSitemapUrl(sitemapForBlog);\n if (subSitemapUrl) {\n const subSitemap = await fetchText(subSitemapUrl);\n if (subSitemap && subSitemap.status === 200) {\n sitemapForBlog = subSitemap.text;\n }\n }\n\n const blogUrls = extractBlogUrlsFromSitemap(sitemapForBlog, domain, 10);\n if (blogUrls.length > 0) {\n const fetched = await Promise.all(blogUrls.map(url => fetchText(url)));\n blogSample = fetched.filter((r): r is FetchResult =>\n r !== null && r.status === 200 && r.text.length > 500\n );\n // Tag blog sample pages\n for (const page of blogSample) {\n page.category = 'blog';\n }\n }\n }\n\n // Tag homepage\n if (homepage) homepage.category = 'homepage';\n\n return { domain, protocol, homepage, llmsTxt, robotsTxt, faqPage, sitemapXml, rssFeed, aiTxt, redirectedTo: null, parkedReason: null, blogSample };\n}\n\n// ─── Blog sample helpers ─────────────────────────────────────────────────────\n\n/** Concatenate homepage + blog sample HTML for combined analysis */\nfunction getCombinedHtml(data: SiteData): string {\n const parts = [data.homepage?.text || ''];\n if (data.blogSample) {\n for (const page of data.blogSample) {\n parts.push(page.text);\n }\n }\n return parts.join('\\n');\n}\n\n/** Get blog-only HTML concatenated */\nfunction getBlogHtml(data: SiteData): string {\n if (!data.blogSample || data.blogSample.length === 0) return '';\n return data.blogSample.map(p => p.text).join('\\n');\n}\n\n// ─── Criterion checks (all use pre-fetched SiteData) ────────────────────────\n\n// Criterion 1: llms.txt\nfunction checkLlmsTxt(data: SiteData): CriterionResult {\n const findings: AuditFinding[] = [];\n const result = data.llmsTxt;\n\n if (!result || result.status !== 200 || isHtmlResponse(result)) {\n const statusNote = result ? (isHtmlResponse(result) ? 'HTML page served (not a valid text file)' : `HTTP ${result.status}`) : 'connection failed';\n findings.push({ severity: 'critical', detail: `No llms.txt file found at ${data.protocol}://${data.domain}/llms.txt (${statusNote})`, fix: 'Create a /llms.txt file that describes your site, services, and key pages in markdown format' });\n return { criterion: 'llms_txt', criterion_label: 'llms.txt File', score: 0, status: 'fail', findings, fix_priority: 'P0' };\n }\n\n const text = result.text;\n let score = 4; // exists\n\n if (text.length < 100) {\n findings.push({ severity: 'medium', detail: `llms.txt exists but is very short (${text.length} characters)`, fix: 'Add comprehensive description of your services, team, and key content' });\n } else {\n score += 2;\n findings.push({ severity: 'info', detail: `llms.txt file found (${text.length} characters)` });\n }\n\n if (text.includes('#') || text.includes('##')) {\n score += 2;\n findings.push({ severity: 'info', detail: 'llms.txt uses markdown headings for structure' });\n } else {\n findings.push({ severity: 'low', detail: 'llms.txt lacks markdown structure', fix: 'Add headings (# About, ## Services, etc.) for better LLM parsing' });\n }\n\n if (/https?:\\/\\//.test(text)) {\n score += 2;\n findings.push({ severity: 'info', detail: 'llms.txt includes URLs to key pages' });\n } else {\n findings.push({ severity: 'medium', detail: 'llms.txt does not link to key pages', fix: 'Add URLs to your most important pages (services, about, FAQ)' });\n }\n\n return { criterion: 'llms_txt', criterion_label: 'llms.txt File', score: Math.min(10, score), status: score >= 7 ? 'pass' : 'partial', findings, fix_priority: score >= 7 ? 'P3' : 'P0' };\n}\n\n// Criterion 2: Schema Markup\nfunction checkSchemaMarkup(data: SiteData): CriterionResult {\n const findings: AuditFinding[] = [];\n\n if (!data.homepage) {\n findings.push({ severity: 'critical', detail: 'Could not fetch homepage to check schema markup' });\n return { criterion: 'schema_markup', criterion_label: 'Schema.org Structured Data', score: 0, status: 'not_found', findings, fix_priority: 'P1' };\n }\n\n const html = data.homepage.text;\n const ldJsonMatches = html.match(/<script[^>]*type=\"application\\/ld\\+json\"[^>]*>([\\s\\S]*?)<\\/script>/gi) || [];\n let score = 0;\n\n if (ldJsonMatches.length === 0) {\n findings.push({ severity: 'critical', detail: 'No JSON-LD structured data found on homepage', fix: 'Add Organization, LocalBusiness, or WebSite schema in a <script type=\"application/ld+json\"> tag' });\n return { criterion: 'schema_markup', criterion_label: 'Schema.org Structured Data', score: 0, status: 'fail', findings, fix_priority: 'P1' };\n }\n\n score += 3;\n findings.push({ severity: 'info', detail: `Found ${ldJsonMatches.length} JSON-LD block(s) on homepage` });\n\n const allSchemaText = ldJsonMatches.join(' ').toLowerCase();\n const schemaTypes = ['organization', 'localbusiness', 'faqpage', 'service', 'article', 'webpage', 'website', 'breadcrumblist', 'howto', 'product'];\n const foundTypes: string[] = [];\n\n for (const type of schemaTypes) {\n if (allSchemaText.includes(`\"${type}\"`) || allSchemaText.includes(`\"@type\":\"${type}\"`)) {\n foundTypes.push(type);\n }\n }\n\n if (foundTypes.length > 0) {\n score += Math.min(4, foundTypes.length * 2);\n findings.push({ severity: 'info', detail: `Schema types found: ${foundTypes.join(', ')}` });\n }\n\n if (!foundTypes.includes('organization') && !foundTypes.includes('localbusiness')) {\n findings.push({ severity: 'high', detail: 'Missing Organization or LocalBusiness schema', fix: 'Add Organization schema with name, url, logo, contactPoint, and sameAs properties' });\n } else {\n score += 2;\n findings.push({ severity: 'info', detail: 'Organization or LocalBusiness schema found' });\n }\n\n if (!foundTypes.includes('faqpage')) {\n findings.push({ severity: 'medium', detail: 'No FAQPage schema found', fix: 'Add FAQPage schema on pages with FAQ content' });\n } else {\n score += 1;\n findings.push({ severity: 'info', detail: 'FAQPage schema markup present' });\n }\n\n // Blog sample enhancement: additional schema types from blog posts\n if (data.blogSample && data.blogSample.length > 0) {\n const blogHtml = getBlogHtml(data);\n const blogLdJson = blogHtml.match(/<script[^>]*type=\"application\\/ld\\+json\"[^>]*>([\\s\\S]*?)<\\/script>/gi) || [];\n if (blogLdJson.length > 0) {\n const blogSchemaText = blogLdJson.join(' ').toLowerCase();\n const blogTypes = schemaTypes.filter(t =>\n (blogSchemaText.includes(`\"${t}\"`) || blogSchemaText.includes(`\"@type\":\"${t}\"`)) && !foundTypes.includes(t)\n );\n if (blogTypes.length > 0) {\n score += Math.min(2, blogTypes.length);\n findings.push({ severity: 'info', detail: `Additional schema types found on blog pages: ${blogTypes.join(', ')}` });\n }\n // FAQPage on blog is especially valuable\n if (!foundTypes.includes('faqpage') && /faqpage/i.test(blogSchemaText)) {\n score += 1;\n findings.push({ severity: 'info', detail: 'FAQPage schema found on blog posts' });\n }\n }\n }\n\n return { criterion: 'schema_markup', criterion_label: 'Schema.org Structured Data', score: Math.min(10, score), status: score >= 7 ? 'pass' : score >= 4 ? 'partial' : 'fail', findings, fix_priority: score >= 7 ? 'P2' : 'P1' };\n}\n\n// Criterion 3: Q&A Content Format\nfunction checkQAFormat(data: SiteData): CriterionResult {\n const findings: AuditFinding[] = [];\n\n if (!data.homepage) {\n findings.push({ severity: 'critical', detail: 'Could not fetch homepage' });\n return { criterion: 'qa_content_format', criterion_label: 'Q&A Content Format', score: 0, status: 'not_found', findings, fix_priority: 'P1' };\n }\n\n const html = data.homepage.text;\n let score = 0;\n\n // Count question headings from homepage + blog sample combined\n const combinedHtml = getCombinedHtml(data);\n const hTagContent = (combinedHtml.match(/<h[1-6][^>]*>([\\s\\S]*?)<\\/h[1-6]>/gi) || []).map(h => h.replace(/<[^>]*>/g, ''));\n const questionHeadings = hTagContent.filter(h => h.includes('?') || /^(what|how|why|when|who|where|can|do|does|is|are|should)\\s/i.test(h));\n\n if (questionHeadings.length >= 10) {\n score += 5;\n findings.push({ severity: 'info', detail: `Found ${questionHeadings.length} question-format headings` });\n } else if (questionHeadings.length >= 3) {\n score += 3;\n findings.push({ severity: 'info', detail: `Found ${questionHeadings.length} question-format headings` });\n } else if (questionHeadings.length >= 1) {\n score += 1;\n findings.push({ severity: 'low', detail: `Only ${questionHeadings.length} question-format heading(s) found`, fix: 'Structure more content as Q&A with question headings (H2/H3) followed by direct answers' });\n } else {\n findings.push({ severity: 'high', detail: 'No question-format headings found', fix: 'Add Q&A sections with headings like \"What is...?\", \"How does...?\" followed by concise answers' });\n }\n\n // Check for question heading followed by a paragraph (20-500 chars, allowing nested inline tags)\n const hasDirectAnswers = /<h[2-3][^>]*>[^<]*\\?<\\/h[2-3]>\\s*<p[^>]*>[\\s\\S]{20,500}<\\/p>/i.test(combinedHtml);\n if (hasDirectAnswers) {\n score += 3;\n findings.push({ severity: 'info', detail: 'Content uses direct-answer format after question headings' });\n } else {\n findings.push({ severity: 'medium', detail: 'Content does not follow direct-answer format', fix: 'Start each answer paragraph with a concise 1-2 sentence definition before elaborating' });\n }\n\n const h1Count = (html.match(/<h1[\\s>]/gi) || []).length;\n if (h1Count === 1) {\n score += 2;\n findings.push({ severity: 'info', detail: 'Proper single H1 tag hierarchy' });\n } else if (h1Count === 0) {\n findings.push({ severity: 'high', detail: 'No H1 tag found', fix: 'Add exactly one H1 tag as the main page heading' });\n } else {\n score += 1;\n findings.push({ severity: 'medium', detail: `Multiple H1 tags found (${h1Count})`, fix: 'Use only one H1 per page; use H2/H3 for subsections' });\n }\n\n return { criterion: 'qa_content_format', criterion_label: 'Q&A Content Format', score: Math.min(10, score), status: score >= 7 ? 'pass' : score >= 4 ? 'partial' : 'fail', findings, fix_priority: score >= 7 ? 'P2' : 'P1' };\n}\n\n// Criterion 4: Clean HTML (includes HTTPS check - v4 requirement)\nfunction checkCleanHTML(data: SiteData): CriterionResult {\n const findings: AuditFinding[] = [];\n\n if (!data.homepage) {\n findings.push({ severity: 'critical', detail: 'Could not fetch homepage' });\n return { criterion: 'clean_html', criterion_label: 'Clean, Crawlable HTML', score: 0, status: 'not_found', findings, fix_priority: 'P1' };\n }\n\n const html = data.homepage.text;\n let score = 0;\n const httpsAvailable = data.protocol === 'https';\n\n // HTTPS check (v4 requirement: no HTTPS = cap at 3)\n if (httpsAvailable) {\n findings.push({ severity: 'info', detail: 'Site serves over HTTPS' });\n } else {\n findings.push({ severity: 'critical', detail: 'Site does not support HTTPS', fix: 'Enable HTTPS with a valid SSL certificate. Sites without HTTPS are penalized by AI crawlers.' });\n }\n\n // Check for semantic elements\n const hasMain = /<main[\\s>]/i.test(html);\n const hasArticle = /<article[\\s>]/i.test(html);\n const hasSection = /<section[\\s>]/i.test(html);\n\n const semanticCount = [hasMain, hasArticle, hasSection].filter(Boolean).length;\n score += Math.min(3, semanticCount * 1);\n if (semanticCount >= 2) {\n findings.push({ severity: 'info', detail: `Uses semantic HTML5 elements: ${[hasMain && 'main', hasArticle && 'article', hasSection && 'section'].filter(Boolean).join(', ')}` });\n } else {\n findings.push({ severity: 'medium', detail: 'Limited semantic HTML5 usage', fix: 'Wrap main content in <main>, use <article> for standalone content, <section> for grouped content' });\n }\n\n // Check H1 count\n const h1Count = (html.match(/<h1[\\s>]/gi) || []).length;\n if (h1Count === 1) {\n score += 2;\n findings.push({ severity: 'info', detail: 'Single H1 tag found - correct heading hierarchy' });\n } else {\n findings.push({ severity: h1Count === 0 ? 'high' : 'medium', detail: `${h1Count === 0 ? 'No' : 'Multiple'} H1 tag(s) found (${h1Count})`, fix: 'Use exactly one H1 per page' });\n }\n\n // Check for text content (not JS-only)\n const textContent = html.replace(/<[^>]*>/g, '').replace(/\\s+/g, ' ').trim();\n if (textContent.length > 500) {\n score += 3;\n findings.push({ severity: 'info', detail: 'Page has substantial text content accessible without JavaScript' });\n } else {\n findings.push({ severity: 'high', detail: 'Very little text content visible in HTML source', fix: 'Ensure key content is server-rendered, not loaded via JavaScript only' });\n }\n\n // Check for meta tags\n const hasMetaDesc = /<meta[^>]*name=\"description\"[^>]*>/i.test(html);\n const hasTitle = /<title[^>]*>[^<]+<\\/title>/i.test(html);\n if (hasMetaDesc && hasTitle) {\n score += 2;\n findings.push({ severity: 'info', detail: 'Page has title and meta description' });\n } else {\n findings.push({ severity: 'medium', detail: `Missing ${!hasTitle ? 'title tag' : ''}${!hasTitle && !hasMetaDesc ? ' and ' : ''}${!hasMetaDesc ? 'meta description' : ''}`, fix: 'Add <title> and <meta name=\"description\"> tags' });\n }\n\n // HTTPS cap: no HTTPS = max 3 for this criterion\n if (!httpsAvailable) {\n score = Math.min(score, 3);\n }\n\n return { criterion: 'clean_html', criterion_label: 'Clean, Crawlable HTML', score: Math.min(10, score), status: score >= 7 ? 'pass' : score >= 4 ? 'partial' : 'fail', findings, fix_priority: score >= 7 ? 'P3' : 'P1' };\n}\n\n// Criterion 5: Entity Consistency\nfunction checkEntityConsistency(data: SiteData): CriterionResult {\n const findings: AuditFinding[] = [];\n\n if (!data.homepage) {\n findings.push({ severity: 'critical', detail: 'Could not fetch homepage' });\n return { criterion: 'entity_consistency', criterion_label: 'Entity Authority & E-E-A-T', score: 0, status: 'not_found', findings, fix_priority: 'P1' };\n }\n\n const html = data.homepage.text;\n const text = html.replace(/<[^>]*>/g, ' ').replace(/\\s+/g, ' ');\n let score = 0;\n\n // Check for phone numbers with context validation\n // A regex match only counts if it has supporting context (tel: link, schema, or nearby keywords)\n const hasTelLink = /href=\"tel:/i.test(html);\n const hasSchemaTelephone = /\"telephone\"/i.test(html);\n const phoneContextWords = /\\b(phone|call|tel:|contact\\s*us|fax|dial)\\b/i;\n\n const phoneRegex = /(?:\\+?1[-.\\s]?)?\\(?\\d{3}\\)?[-.\\s]?\\d{3}[-.\\s]?\\d{4}/g;\n const phones = text.match(phoneRegex) || [];\n const contextValidatedPhones: string[] = [];\n\n if (hasTelLink || hasSchemaTelephone) {\n // Global context validates all matches\n contextValidatedPhones.push(...phones);\n } else {\n // Check each match for nearby context words (~100 chars around match)\n let match: RegExpExecArray | null;\n const phoneRegex2 = /(?:\\+?1[-.\\s]?)?\\(?\\d{3}\\)?[-.\\s]?\\d{3}[-.\\s]?\\d{4}/g;\n while ((match = phoneRegex2.exec(text)) !== null) {\n const start = Math.max(0, match.index - 100);\n const end = Math.min(text.length, match.index + match[0].length + 100);\n const surrounding = text.slice(start, end);\n if (phoneContextWords.test(surrounding)) {\n contextValidatedPhones.push(match[0]);\n }\n }\n }\n\n const uniquePhones = [...new Set(contextValidatedPhones.map(p => p.replace(/\\D/g, '')))];\n if (uniquePhones.length === 1) {\n score += 3;\n findings.push({ severity: 'info', detail: 'Single consistent phone number found' });\n } else if (uniquePhones.length > 1) {\n score += 1;\n findings.push({ severity: 'medium', detail: `Multiple phone numbers found (${uniquePhones.length})`, fix: 'Use one primary phone number consistently across all pages' });\n } else {\n findings.push({ severity: 'low', detail: 'No phone number found on homepage' });\n score += 1;\n }\n\n // Check for address\n const hasAddress = /\\d+\\s+\\w+\\s+(street|st|avenue|ave|road|rd|drive|dr|blvd|boulevard|lane|ln|way|court|ct)/i.test(text);\n if (hasAddress) {\n score += 2;\n findings.push({ severity: 'info', detail: 'Physical address found on page' });\n }\n\n // Check for Organization schema\n const hasOrgSchema = /organization|localbusiness/i.test(html);\n if (hasOrgSchema) {\n score += 3;\n findings.push({ severity: 'info', detail: 'Organization/LocalBusiness schema reinforces entity identity' });\n } else {\n findings.push({ severity: 'high', detail: 'No Organization schema to reinforce entity identity', fix: 'Add Organization JSON-LD with consistent name, address, phone, and social links' });\n }\n\n // Check for social proof\n const hasSameAs = /sameas|linkedin\\.com|facebook\\.com|twitter\\.com|x\\.com/i.test(html);\n if (hasSameAs) {\n score += 2;\n findings.push({ severity: 'info', detail: 'Social media / sameAs references found' });\n } else {\n findings.push({ severity: 'low', detail: 'No social media links or sameAs found', fix: 'Add sameAs links in Organization schema to social profiles' });\n }\n\n return { criterion: 'entity_consistency', criterion_label: 'Entity Authority & E-E-A-T', score: Math.min(10, score), status: score >= 7 ? 'pass' : score >= 4 ? 'partial' : 'fail', findings, fix_priority: score >= 7 ? 'P3' : 'P1' };\n}\n\n// Criterion 6: robots.txt\nfunction checkRobotsTxt(data: SiteData): CriterionResult {\n const findings: AuditFinding[] = [];\n const result = data.robotsTxt;\n\n if (!result || result.status !== 200 || isHtmlResponse(result)) {\n findings.push({ severity: 'high', detail: 'No robots.txt file found', fix: 'Create a robots.txt that explicitly allows AI crawlers' });\n return { criterion: 'robots_txt', criterion_label: 'robots.txt for AI Crawlers', score: 2, status: 'fail', findings, fix_priority: 'P0' };\n }\n\n const text = result.text.toLowerCase();\n let score = 3; // exists\n\n const aiCrawlers = ['gptbot', 'claudebot', 'perplexitybot', 'anthropic', 'chatgpt'];\n const mentionedCrawlers = aiCrawlers.filter(c => text.includes(c));\n\n if (mentionedCrawlers.length > 0) {\n score += 3;\n findings.push({ severity: 'info', detail: `AI crawlers mentioned: ${mentionedCrawlers.join(', ')}` });\n\n const blocked = mentionedCrawlers.filter(c => {\n // Extract only this crawler's section (up to next User-agent: or EOF)\n // NOTE: do NOT use 'm' flag here - it makes $ match end-of-line, causing\n // non-greedy [\\s\\S]*? to stop at the first line instead of capturing the full section\n const sectionRegex = new RegExp(`user-agent:\\\\s*${c}[^\\\\S\\\\n]*\\\\n([\\\\s\\\\S]*?)(?=user-agent:|$)`, 'i');\n const match = sectionRegex.exec(result.text);\n if (!match) return false;\n const section = match[1];\n // If section has \"Allow: /\", the crawler is explicitly allowed (not blocked)\n if (/^allow:\\s*\\/\\s*$/im.test(section)) return false;\n // Check for \"Disallow: /\" (root-only, not /path) within this section\n return /^disallow:\\s*\\/\\s*$/im.test(section);\n });\n if (blocked.length > 0) {\n score -= 2;\n findings.push({ severity: 'critical', detail: `AI crawlers BLOCKED: ${blocked.join(', ')}`, fix: 'Change Disallow: / to Allow: / for AI crawler user-agents' });\n } else {\n score += 2;\n findings.push({ severity: 'info', detail: 'AI crawlers are allowed to index the site' });\n }\n } else {\n findings.push({ severity: 'medium', detail: 'No explicit AI crawler rules in robots.txt', fix: 'Add User-agent rules for GPTBot, ClaudeBot, PerplexityBot with Allow: /' });\n }\n\n if (text.includes('sitemap:')) {\n score += 2;\n findings.push({ severity: 'info', detail: 'Sitemap URL referenced in robots.txt' });\n } else {\n findings.push({ severity: 'low', detail: 'No sitemap reference in robots.txt', fix: 'Add Sitemap: https://yoursite.com/sitemap.xml to robots.txt' });\n }\n\n return { criterion: 'robots_txt', criterion_label: 'robots.txt for AI Crawlers', score: Math.min(10, score), status: score >= 7 ? 'pass' : score >= 4 ? 'partial' : 'fail', findings, fix_priority: score >= 4 ? 'P2' : 'P0' };\n}\n\n// Criterion 7: FAQ Section\nfunction checkFAQSection(data: SiteData): CriterionResult {\n const findings: AuditFinding[] = [];\n let score = 0;\n\n const homepage = data.homepage;\n const hasHomepageFAQ = homepage && /faq|frequently\\s+asked/i.test(homepage.text);\n\n if (hasHomepageFAQ) {\n score += 2;\n findings.push({ severity: 'info', detail: 'FAQ content found on homepage' });\n } else {\n findings.push({ severity: 'low', detail: 'No FAQ content found on homepage', fix: 'Add an FAQ section to your homepage addressing common visitor questions' });\n }\n\n const faqPage = data.faqPage;\n const hasFaqPage = faqPage && faqPage.status === 200 && faqPage.text.length > 500;\n\n if (hasFaqPage) {\n score += 3;\n findings.push({ severity: 'info', detail: 'Dedicated FAQ page exists' });\n\n if (/accordion|toggle|collaps|expand/i.test(faqPage.text)) {\n score += 1;\n findings.push({ severity: 'info', detail: 'FAQ uses accordion/toggle UI pattern' });\n }\n } else {\n findings.push({ severity: 'high', detail: 'No dedicated FAQ page found at /faq', fix: 'Create a comprehensive FAQ page at /faq covering common questions about your service' });\n }\n\n // Check for FAQPage schema (homepage + FAQ page + blog sample)\n const blogHtml = getBlogHtml(data);\n const allHtml = (homepage?.text || '') + (faqPage?.text || '') + blogHtml;\n if (/faqpage/i.test(allHtml) && /application\\/ld\\+json/i.test(allHtml)) {\n score += 3;\n const faqOnBlog = blogHtml && /faqpage/i.test(blogHtml) && /application\\/ld\\+json/i.test(blogHtml);\n findings.push({ severity: 'info', detail: faqOnBlog ? 'FAQPage schema markup found on blog posts' : 'FAQPage schema markup found' });\n } else {\n findings.push({ severity: 'medium', detail: 'No FAQPage schema markup', fix: 'Add FAQPage JSON-LD schema to pages with FAQ content' });\n }\n\n const questionCount = (allHtml.match(/<h[2-4][^>]*>[^<]*\\?<\\/h[2-4]>/gi) || []).length;\n if (questionCount >= 10) {\n score += 1;\n findings.push({ severity: 'info', detail: `${questionCount} question headings found across checked pages` });\n } else if (questionCount >= 5) {\n findings.push({ severity: 'low', detail: `Only ${questionCount} question headings found`, fix: 'Expand FAQ to cover at least 10-15 common questions' });\n }\n\n return { criterion: 'faq_section', criterion_label: 'Comprehensive FAQ Sections', score: Math.min(10, score), status: score >= 7 ? 'pass' : score >= 4 ? 'partial' : 'fail', findings, fix_priority: score >= 4 ? 'P2' : 'P1' };\n}\n\n// Criterion 8: Original Data\nfunction checkOriginalData(data: SiteData): CriterionResult {\n const findings: AuditFinding[] = [];\n\n if (!data.homepage) {\n findings.push({ severity: 'critical', detail: 'Could not fetch homepage' });\n return { criterion: 'original_data', criterion_label: 'Original Data & Expert Content', score: 0, status: 'not_found', findings, fix_priority: 'P2' };\n }\n\n const html = data.homepage.text;\n const text = html.replace(/<[^>]*>/g, ' ').replace(/\\s+/g, ' ');\n let score = 0;\n\n // Stats check: strong (+3) if research context nearby, weak (+1) for generic marketing stats\n const statPatterns = /\\d+%|\\d+\\s*(patients|clients|customers|cases|years|professionals|specialists|companies|users|businesses|domains|audits)/i;\n if (statPatterns.test(text)) {\n const researchContext = /\\b(our\\s+(?:study|analysis|research|data|survey|findings|report)|we\\s+(?:surveyed|analyzed|studied|measured|tracked)|proprietary|methodology|original\\s+research)\\b/i;\n if (researchContext.test(text)) {\n score += 3;\n findings.push({ severity: 'info', detail: 'Proprietary statistics with research context found on homepage' });\n } else {\n score += 1;\n findings.push({ severity: 'low', detail: 'Statistics found but without research context (e.g., \"500+ clients\")', fix: 'Add context about your methodology: \"Our analysis of X found...\" or \"We surveyed Y...\"' });\n }\n } else {\n findings.push({ severity: 'medium', detail: 'No proprietary data or statistics found', fix: 'Add unique statistics, case study results, or industry data that LLMs would cite as authoritative' });\n }\n\n // Case studies: with nearby metric (+3), without metric (+1)\n const caseStudyPattern = /case\\s+stud|testimonial|success\\s+stor|client\\s+stor/i;\n if (caseStudyPattern.test(text)) {\n // Check for a numeric metric within ~200 chars of the case study mention\n const caseStudyRegex = /case\\s+stud|testimonial|success\\s+stor|client\\s+stor/gi;\n let hasMetricNearby = false;\n let csMatch: RegExpExecArray | null;\n while ((csMatch = caseStudyRegex.exec(text)) !== null) {\n const start = Math.max(0, csMatch.index - 200);\n const end = Math.min(text.length, csMatch.index + csMatch[0].length + 200);\n const surrounding = text.slice(start, end);\n if (/\\d+%|\\$[\\d,]+|\\d+x\\b/i.test(surrounding)) {\n hasMetricNearby = true;\n break;\n }\n }\n if (hasMetricNearby) {\n score += 3;\n findings.push({ severity: 'info', detail: 'Case studies or testimonials with specific metrics found' });\n } else {\n score += 1;\n findings.push({ severity: 'low', detail: 'Case studies or testimonials mentioned but without specific metrics', fix: 'Add measurable outcomes to case studies (e.g., \"increased traffic by 45%\")' });\n }\n } else {\n findings.push({ severity: 'medium', detail: 'No case studies or testimonials found', fix: 'Add case studies with specific outcomes and metrics' });\n }\n\n // Expert attribution (+2) - check homepage + blog\n const combinedText = data.blogSample && data.blogSample.length > 0\n ? text + ' ' + data.blogSample.map(p => p.text.replace(/<[^>]*>/g, ' ').replace(/\\s+/g, ' ')).join(' ')\n : text;\n if (/written\\s+by|authored\\s+by|expert|specialist|board.certified|licensed/i.test(combinedText)) {\n score += 2;\n findings.push({ severity: 'info', detail: 'Expert attribution or credentials found' });\n } else {\n findings.push({ severity: 'low', detail: 'No expert attribution or credentials visible', fix: 'Add author bios with credentials to establish E-E-A-T signals' });\n }\n\n // Blog check: require actual href links to content paths, not just the word \"blog\"\n const contentLinkPattern = /href=\"[^\"]*\\/(?:blog|articles|insights|guides|resources)\\b[^\"]*\"/i;\n if (contentLinkPattern.test(html)) {\n score += 2;\n findings.push({ severity: 'info', detail: 'Links to blog/articles section found on site' });\n } else {\n findings.push({ severity: 'medium', detail: 'No links to blog or articles section found', fix: 'Create a content section with expert articles and link to it from your homepage' });\n }\n\n // Blog sample enhancement: case studies from blog posts\n if (data.blogSample && data.blogSample.length > 0 && !caseStudyPattern.test(text)) {\n const blogText = data.blogSample.map(p => p.text.replace(/<[^>]*>/g, ' ').replace(/\\s+/g, ' ')).join(' ');\n if (caseStudyPattern.test(blogText)) {\n score += 1;\n findings.push({ severity: 'info', detail: 'Case studies or testimonials found on blog posts' });\n }\n }\n\n return { criterion: 'original_data', criterion_label: 'Original Data & Expert Content', score: Math.min(10, score), status: score >= 7 ? 'pass' : score >= 4 ? 'partial' : 'fail', findings, fix_priority: score >= 4 ? 'P2' : 'P2' };\n}\n\n// Criterion 9: Internal Linking\nfunction checkInternalLinking(data: SiteData): CriterionResult {\n const findings: AuditFinding[] = [];\n\n if (!data.homepage) {\n findings.push({ severity: 'critical', detail: 'Could not fetch homepage' });\n return { criterion: 'internal_linking', criterion_label: 'Internal Linking Architecture', score: 0, status: 'not_found', findings, fix_priority: 'P2' };\n }\n\n const html = data.homepage.text;\n let score = 0;\n\n const linkMatches = html.match(/<a[^>]*href=\"([^\"]*)\"[^>]*>/gi) || [];\n const internalLinks = linkMatches.filter(l => {\n const href = l.match(/href=\"([^\"]*)\"/)?.[1] || '';\n return href.startsWith('/') || href.includes(data.domain);\n });\n\n if (internalLinks.length >= 20) {\n score += 3;\n findings.push({ severity: 'info', detail: `${internalLinks.length} internal links found on homepage` });\n } else if (internalLinks.length >= 10) {\n score += 2;\n findings.push({ severity: 'low', detail: `${internalLinks.length} internal links on homepage`, fix: 'Add more internal links to key service/content pages' });\n } else {\n findings.push({ severity: 'high', detail: `Only ${internalLinks.length} internal links on homepage`, fix: 'Add prominent internal links to service pages, FAQ, blog, and about pages' });\n }\n\n if (/breadcrumb|aria-label=\"breadcrumb\"/i.test(html)) {\n score += 2;\n findings.push({ severity: 'info', detail: 'Breadcrumb navigation detected' });\n } else {\n findings.push({ severity: 'medium', detail: 'No breadcrumb navigation found', fix: 'Add breadcrumb navigation with BreadcrumbList schema markup' });\n }\n\n if (/<nav[\\s>]/i.test(html)) {\n score += 2;\n findings.push({ severity: 'info', detail: 'Semantic <nav> element used for navigation' });\n } else {\n findings.push({ severity: 'low', detail: 'No semantic <nav> element found', fix: 'Wrap navigation menus in <nav> for better AI and accessibility parsing' });\n }\n\n if (/related|see\\s+also|learn\\s+more|explore|you\\s+may\\s+also/i.test(html)) {\n score += 2;\n findings.push({ severity: 'info', detail: 'Related content or cross-linking sections found' });\n } else {\n findings.push({ severity: 'low', detail: 'No related content or cross-linking found', fix: 'Add \"Related Services\" or \"Learn More\" sections to build topic clusters' });\n }\n\n if (/<footer[\\s>]/i.test(html)) {\n score += 1;\n findings.push({ severity: 'info', detail: 'Footer element with likely navigation links' });\n } else {\n findings.push({ severity: 'low', detail: 'No <footer> element found', fix: 'Add a <footer> with navigation links, contact info, and site structure' });\n }\n\n return { criterion: 'internal_linking', criterion_label: 'Internal Linking Architecture', score: Math.min(10, score), status: score >= 7 ? 'pass' : score >= 4 ? 'partial' : 'fail', findings, fix_priority: score >= 4 ? 'P2' : 'P1' };\n}\n\n// Criterion 10: Semantic HTML\nfunction checkSemanticHTML(data: SiteData): CriterionResult {\n const findings: AuditFinding[] = [];\n\n if (!data.homepage) {\n findings.push({ severity: 'critical', detail: 'Could not fetch homepage' });\n return { criterion: 'semantic_html', criterion_label: 'Semantic HTML5 & Accessibility', score: 0, status: 'not_found', findings, fix_priority: 'P2' };\n }\n\n // Use combined HTML for semantic element detection\n const combinedHtml = getCombinedHtml(data);\n const html = data.homepage.text;\n let score = 0;\n\n const checks: [string, RegExp, string][] = [\n ['<main>', /<main[\\s>]/i, 'Wrap primary page content in <main>'],\n ['<article>', /<article[\\s>]/i, 'Use <article> for standalone content blocks'],\n ['<time>', /<time[\\s>]/i, 'Use <time> elements for dates'],\n ['<nav>', /<nav[\\s>]/i, 'Use <nav> for navigation sections'],\n ['<header>', /<header[\\s>]/i, 'Use <header> for page/section headers'],\n ['<footer>', /<footer[\\s>]/i, 'Use <footer> for page/section footers'],\n ];\n\n let found = 0;\n for (const [name, regex, fix] of checks) {\n if (regex.test(combinedHtml)) {\n found++;\n } else {\n findings.push({ severity: 'low', detail: `Missing ${name} element`, fix });\n }\n }\n score += Math.min(4, Math.floor(found * 0.7));\n if (found >= 4) findings.push({ severity: 'info', detail: `${found}/6 key semantic HTML5 elements found` });\n\n // Check img alt text\n const images = html.match(/<img[^>]*>/gi) || [];\n const imagesWithAlt = images.filter(img => /alt=\"[^\"]+\"/i.test(img));\n if (images.length > 0) {\n const ratio = imagesWithAlt.length / images.length;\n if (ratio >= 0.8) {\n score += 2;\n findings.push({ severity: 'info', detail: `${Math.round(ratio * 100)}% of images have alt text` });\n } else {\n findings.push({ severity: 'medium', detail: `Only ${Math.round(ratio * 100)}% of images have alt text`, fix: 'Add descriptive alt text to all images' });\n }\n }\n\n // Check lang attribute\n if (/lang=\"[a-z]{2}\"/i.test(html)) {\n score += 2;\n findings.push({ severity: 'info', detail: 'HTML lang attribute set' });\n } else {\n findings.push({ severity: 'medium', detail: 'Missing lang attribute on <html> tag', fix: 'Add lang=\"en\" (or appropriate language) to the <html> tag' });\n }\n\n // Check for ARIA roles\n if (/role=\"|aria-/i.test(html)) {\n score += 2;\n findings.push({ severity: 'info', detail: 'ARIA attributes found for accessibility' });\n } else {\n findings.push({ severity: 'low', detail: 'No ARIA roles or attributes found', fix: 'Add ARIA roles and labels to improve accessibility and semantic parsing' });\n }\n\n return { criterion: 'semantic_html', criterion_label: 'Semantic HTML5 & Accessibility', score: Math.min(10, score), status: score >= 7 ? 'pass' : score >= 4 ? 'partial' : 'fail', findings, fix_priority: score >= 4 ? 'P3' : 'P2' };\n}\n\n// Criterion 11: Content Freshness\nfunction checkContentFreshness(data: SiteData): CriterionResult {\n const findings: AuditFinding[] = [];\n\n if (!data.homepage) {\n findings.push({ severity: 'critical', detail: 'Could not fetch homepage' });\n return { criterion: 'content_freshness', criterion_label: 'Content Freshness Signals', score: 0, status: 'not_found', findings, fix_priority: 'P2' };\n }\n\n const html = data.homepage.text;\n let score = 0;\n\n // JSON-LD date signals (datePublished, dateModified)\n const hasDatePublished = /datePublished|dateCreated/i.test(html);\n const hasDateModified = /dateModified/i.test(html);\n if (hasDatePublished || hasDateModified) {\n score += 3;\n findings.push({ severity: 'info', detail: `JSON-LD date properties found: ${[hasDatePublished && 'datePublished', hasDateModified && 'dateModified'].filter(Boolean).join(', ')}` });\n } else {\n findings.push({ severity: 'high', detail: 'No JSON-LD date properties (datePublished/dateModified) found', fix: 'Add datePublished and dateModified to Article or WebPage schema' });\n }\n\n // <time> elements\n const timeElements = html.match(/<time[\\s>]/gi) || [];\n if (timeElements.length >= 2) {\n score += 3;\n findings.push({ severity: 'info', detail: `${timeElements.length} <time> elements found` });\n } else if (timeElements.length === 1) {\n score += 1;\n findings.push({ severity: 'low', detail: 'Only 1 <time> element found', fix: 'Use <time datetime=\"...\"> for all dates to help AI parsers' });\n } else {\n findings.push({ severity: 'medium', detail: 'No <time> elements found', fix: 'Wrap publication and modification dates in <time datetime=\"...\"> elements' });\n }\n\n // Article meta (article:published_time, article:modified_time)\n const hasArticleMeta = /article:published_time|article:modified_time/i.test(html);\n if (hasArticleMeta) {\n score += 2;\n findings.push({ severity: 'info', detail: 'Open Graph article date meta tags found' });\n } else {\n findings.push({ severity: 'low', detail: 'No article:published_time or article:modified_time meta tags', fix: 'Add Open Graph article date meta tags' });\n }\n\n // Recency check - look for recent year references\n const currentYear = new Date().getFullYear();\n const hasRecentYear = html.includes(String(currentYear)) || html.includes(String(currentYear - 1));\n if (hasRecentYear) {\n score += 2;\n findings.push({ severity: 'info', detail: `References to ${currentYear} or ${currentYear - 1} found, suggesting recent content` });\n } else {\n findings.push({ severity: 'low', detail: 'No references to recent years found on homepage' });\n }\n\n return { criterion: 'content_freshness', criterion_label: 'Content Freshness Signals', score: Math.min(10, score), status: score >= 7 ? 'pass' : score >= 4 ? 'partial' : 'fail', findings, fix_priority: score >= 7 ? 'P3' : 'P2' };\n}\n\n// Criterion 12: Sitemap Completeness\nfunction checkSitemapCompleteness(data: SiteData): CriterionResult {\n const findings: AuditFinding[] = [];\n const sitemap = data.sitemapXml;\n\n if (!sitemap || sitemap.status !== 200) {\n findings.push({ severity: 'critical', detail: 'No sitemap.xml found', fix: 'Create a sitemap.xml with all indexable pages and submit to search engines' });\n return { criterion: 'sitemap_completeness', criterion_label: 'Sitemap Completeness', score: 0, status: 'fail', findings, fix_priority: 'P1' };\n }\n\n const text = sitemap.text;\n let score = 2; // exists\n\n // Valid XML structure\n if (text.includes('<urlset') || text.includes('<sitemapindex')) {\n score += 2;\n findings.push({ severity: 'info', detail: 'Valid sitemap XML structure detected' });\n } else {\n findings.push({ severity: 'high', detail: 'sitemap.xml does not contain valid XML structure', fix: 'Ensure sitemap uses proper <urlset> or <sitemapindex> XML format' });\n }\n\n // Count URLs\n const urlCount = (text.match(/<loc>/gi) || []).length;\n if (urlCount >= 50) {\n score += 3;\n findings.push({ severity: 'info', detail: `${urlCount} URLs in sitemap` });\n } else if (urlCount >= 10) {\n score += 2;\n findings.push({ severity: 'info', detail: `${urlCount} URLs in sitemap` });\n } else if (urlCount > 0) {\n score += 1;\n findings.push({ severity: 'low', detail: `Only ${urlCount} URL(s) in sitemap`, fix: 'Add all important pages to your sitemap' });\n }\n\n // Recent lastmod dates\n const lastmodMatches = text.match(/<lastmod>([^<]+)<\\/lastmod>/gi) || [];\n if (lastmodMatches.length > 0) {\n score += 2;\n findings.push({ severity: 'info', detail: `${lastmodMatches.length} URLs have lastmod dates` });\n } else {\n findings.push({ severity: 'medium', detail: 'No lastmod dates in sitemap', fix: 'Add <lastmod> dates to sitemap entries for freshness signals' });\n }\n\n // Sitemap index\n if (text.includes('<sitemapindex')) {\n score += 1;\n findings.push({ severity: 'info', detail: 'Sitemap index found, indicating organized sitemap structure' });\n } else {\n findings.push({ severity: 'low', detail: 'No sitemap index structure', fix: 'Use a <sitemapindex> with multiple child sitemaps for larger sites to improve crawl efficiency' });\n }\n\n return { criterion: 'sitemap_completeness', criterion_label: 'Sitemap Completeness', score: Math.min(10, score), status: score >= 7 ? 'pass' : score >= 4 ? 'partial' : 'fail', findings, fix_priority: score >= 7 ? 'P3' : 'P1' };\n}\n\n// Criterion 13: RSS Feed\nfunction checkRssFeed(data: SiteData): CriterionResult {\n const findings: AuditFinding[] = [];\n let score = 0;\n\n // Check for RSS link tag in homepage\n const hasRssLink = data.homepage && /<link[^>]*type=\"application\\/(?:rss|atom)\\+xml\"/i.test(data.homepage.text);\n if (hasRssLink) {\n score += 3;\n findings.push({ severity: 'info', detail: 'RSS/Atom feed link tag found in homepage <head>' });\n } else {\n findings.push({ severity: 'high', detail: 'No RSS/Atom feed link tag in homepage', fix: 'Add <link rel=\"alternate\" type=\"application/rss+xml\" href=\"/feed\"> to your <head>' });\n }\n\n // Check for valid feed content\n const feed = data.rssFeed;\n if (feed && feed.status === 200) {\n const feedText = feed.text;\n const isValidFeed = feedText.includes('<rss') || feedText.includes('<feed') || feedText.includes('<channel');\n if (isValidFeed) {\n score += 3;\n findings.push({ severity: 'info', detail: 'Valid RSS/Atom feed content detected' });\n\n // Count items\n const itemCount = (feedText.match(/<item[\\s>]|<entry[\\s>]/gi) || []).length;\n if (itemCount >= 5) {\n score += 4;\n findings.push({ severity: 'info', detail: `Feed contains ${itemCount} items` });\n } else if (itemCount > 0) {\n score += 2;\n findings.push({ severity: 'low', detail: `Feed contains only ${itemCount} item(s)`, fix: 'Publish more content to populate your RSS feed with at least 5 items' });\n }\n } else {\n findings.push({ severity: 'medium', detail: 'Feed URL returned content but not valid RSS/Atom XML', fix: 'Ensure your feed outputs valid RSS 2.0 or Atom XML' });\n }\n } else if (!hasRssLink) {\n findings.push({ severity: 'medium', detail: 'No accessible RSS/Atom feed found', fix: 'Create an RSS feed to help AI engines discover and index new content automatically' });\n }\n\n return { criterion: 'rss_feed', criterion_label: 'RSS/Atom Feed', score: Math.min(10, score), status: score >= 7 ? 'pass' : score >= 4 ? 'partial' : 'fail', findings, fix_priority: score >= 4 ? 'P3' : 'P2' };\n}\n\n// Criterion 14: Table & List Extractability\nfunction checkTableListExtractability(data: SiteData): CriterionResult {\n const findings: AuditFinding[] = [];\n\n if (!data.homepage) {\n findings.push({ severity: 'critical', detail: 'Could not fetch homepage' });\n return { criterion: 'table_list_extractability', criterion_label: 'Table & List Extractability', score: 0, status: 'not_found', findings, fix_priority: 'P2' };\n }\n\n // Use combined HTML so blog tables/lists count\n const html = getCombinedHtml(data);\n let score = 0;\n\n // Tables with headers\n const tables = html.match(/<table[\\s>]/gi) || [];\n const tablesWithHeaders = (html.match(/<table[\\s\\S]*?<\\/table>/gi) || []).filter(t => /<th[\\s>]/i.test(t));\n if (tablesWithHeaders.length >= 1) {\n score += 3;\n findings.push({ severity: 'info', detail: `${tablesWithHeaders.length} table(s) with <th> headers found` });\n } else if (tables.length > 0) {\n score += 1;\n findings.push({ severity: 'medium', detail: `${tables.length} table(s) found but without <th> header cells`, fix: 'Add <th> header cells to tables for better AI extraction' });\n } else {\n findings.push({ severity: 'low', detail: 'No HTML tables found', fix: 'Use comparison tables with <th> headers for structured data AI engines can extract' });\n }\n if (tablesWithHeaders.length >= 2) {\n score += 1;\n findings.push({ severity: 'info', detail: 'Multiple well-structured tables present' });\n } else if (tablesWithHeaders.length === 1) {\n findings.push({ severity: 'low', detail: 'Only 1 table with headers found', fix: 'Add more comparison or data tables with <th> headers to increase extractable structured content' });\n }\n\n // Ordered lists\n const olCount = (html.match(/<ol[\\s>]/gi) || []).length;\n if (olCount >= 1) {\n score += 2;\n findings.push({ severity: 'info', detail: `${olCount} ordered list(s) found - good for step-by-step content` });\n } else {\n findings.push({ severity: 'low', detail: 'No ordered lists (<ol>) found', fix: 'Use <ol> for sequential content (steps, rankings, processes)' });\n }\n\n // Unordered lists\n const ulCount = (html.match(/<ul[\\s>]/gi) || []).length;\n if (ulCount >= 1) {\n score += 2;\n findings.push({ severity: 'info', detail: `${ulCount} unordered list(s) found` });\n } else {\n findings.push({ severity: 'low', detail: 'No unordered lists (<ul>) found', fix: 'Use <ul> for feature lists, benefits, and bullet-point content' });\n }\n\n // List items count\n const liCount = (html.match(/<li[\\s>]/gi) || []).length;\n if (liCount >= 10) {\n score += 1;\n findings.push({ severity: 'info', detail: `${liCount} list items - substantial extractable content` });\n }\n\n // Definition lists\n const dlCount = (html.match(/<dl[\\s>]/gi) || []).length;\n if (dlCount >= 1) {\n score += 1;\n findings.push({ severity: 'info', detail: `${dlCount} definition list(s) found` });\n } else {\n findings.push({ severity: 'low', detail: 'No definition lists (<dl>) found', fix: 'Use <dl>/<dt>/<dd> for term-definition pairs to improve AI extractability' });\n }\n\n return { criterion: 'table_list_extractability', criterion_label: 'Table & List Extractability', score: Math.min(10, score), status: score >= 7 ? 'pass' : score >= 4 ? 'partial' : 'fail', findings, fix_priority: score >= 7 ? 'P3' : 'P2' };\n}\n\n// Criterion 15: Definition Patterns\nfunction checkDefinitionPatterns(data: SiteData): CriterionResult {\n const findings: AuditFinding[] = [];\n\n if (!data.homepage) {\n findings.push({ severity: 'critical', detail: 'Could not fetch homepage' });\n return { criterion: 'definition_patterns', criterion_label: 'Definition Patterns', score: 0, status: 'not_found', findings, fix_priority: 'P2' };\n }\n\n // Use combined HTML for definition pattern detection\n const combinedHtml = getCombinedHtml(data);\n const text = combinedHtml.replace(/<[^>]*>/g, ' ').replace(/\\s+/g, ' ');\n const html = combinedHtml;\n let score = 0;\n\n // \"X is\" / \"X are\" / \"X refers to\" / \"defined as\" patterns\n const definitionPatterns = [\n /\\b\\w[\\w\\s]{2,30}\\bis\\s+(?:a|an|the)\\s/gi,\n /\\b\\w[\\w\\s]{2,30}\\bare\\s+(?:a|an|the)\\s/gi,\n /\\brefers?\\s+to\\b/gi,\n /\\bdefined\\s+as\\b/gi,\n /\\bknown\\s+as\\b/gi,\n /\\bmeans?\\s+that\\b/gi,\n ];\n\n let patternCount = 0;\n for (const pattern of definitionPatterns) {\n const matches = text.match(pattern) || [];\n patternCount += matches.length;\n }\n\n if (patternCount >= 3) {\n score += 5;\n findings.push({ severity: 'info', detail: `${patternCount} definition-style patterns found (e.g., \"X is a...\", \"refers to\", \"defined as\")` });\n } else if (patternCount >= 1) {\n score += 3;\n findings.push({ severity: 'low', detail: `Only ${patternCount} definition pattern(s) found`, fix: 'Start key descriptions with clear definition patterns like \"X is a...\" or \"X refers to...\"' });\n } else {\n findings.push({ severity: 'medium', detail: 'No definition patterns found', fix: 'Add clear definitions using patterns like \"[Term] is [definition]\" that AI engines can extract as snippets' });\n }\n\n // Early placement (in first 2000 chars of text content)\n const earlyText = text.slice(0, 2000);\n const earlyDefinitions = definitionPatterns.some(p => p.test(earlyText));\n // Reset lastIndex since we used global flags\n definitionPatterns.forEach(p => { p.lastIndex = 0; });\n if (earlyDefinitions) {\n score += 2;\n findings.push({ severity: 'info', detail: 'Definition patterns appear early in page content - good for snippet extraction' });\n } else {\n findings.push({ severity: 'low', detail: 'No definition patterns in the first 2000 characters of content', fix: 'Place key definitions early on the page where AI engines prioritize extraction' });\n }\n\n // <dfn> or <abbr> usage\n const hasDfn = /<dfn[\\s>]/i.test(html);\n const hasAbbr = /<abbr[\\s>]/i.test(html);\n if (hasDfn || hasAbbr) {\n score += 1;\n findings.push({ severity: 'info', detail: `Semantic definition elements found: ${[hasDfn && '<dfn>', hasAbbr && '<abbr>'].filter(Boolean).join(', ')}` });\n } else {\n findings.push({ severity: 'low', detail: 'No <dfn> or <abbr> elements found', fix: 'Use <dfn> for term definitions and <abbr> for abbreviations to help AI parse terminology' });\n }\n\n // Glossary or definition-list patterns\n if (/<dl[\\s>]/i.test(html) || /glossary|definitions|terminology/i.test(html)) {\n score += 2;\n findings.push({ severity: 'info', detail: 'Glossary or definition list structure detected' });\n } else {\n findings.push({ severity: 'low', detail: 'No glossary or definition list found', fix: 'Add a glossary section using <dl>/<dt>/<dd> for key industry terms' });\n }\n\n return { criterion: 'definition_patterns', criterion_label: 'Definition Patterns', score: Math.min(10, score), status: score >= 7 ? 'pass' : score >= 4 ? 'partial' : 'fail', findings, fix_priority: score >= 7 ? 'P3' : 'P2' };\n}\n\n// Criterion 16: Direct Answer Density\nfunction checkDirectAnswerDensity(data: SiteData): CriterionResult {\n const findings: AuditFinding[] = [];\n\n if (!data.homepage) {\n findings.push({ severity: 'critical', detail: 'Could not fetch homepage' });\n return { criterion: 'direct_answer_density', criterion_label: 'Direct Answer Paragraphs', score: 0, status: 'not_found', findings, fix_priority: 'P1' };\n }\n\n // Use combined HTML for Q&A pair and paragraph detection\n const html = getCombinedHtml(data);\n let score = 0;\n\n // Q&A pairs: question heading followed by paragraph\n const qaPairs = html.match(/<h[2-4][^>]*>[^<]*\\?<\\/h[2-4]>\\s*<p[^>]*>/gi) || [];\n if (qaPairs.length >= 3) {\n score += 6;\n findings.push({ severity: 'info', detail: `${qaPairs.length} question-answer pairs found (question heading + direct answer paragraph)` });\n } else if (qaPairs.length >= 1) {\n score += 3;\n findings.push({ severity: 'low', detail: `${qaPairs.length} question-answer pair(s) found`, fix: 'Add more question headings (H2/H3) immediately followed by concise answer paragraphs' });\n } else {\n findings.push({ severity: 'high', detail: 'No direct question-answer pairs found', fix: 'Structure content with question headings (e.g., \"What is X?\") immediately followed by a concise answer paragraph' });\n }\n\n // Snippet-zone paragraphs (40-150 words - ideal for AI extraction)\n const paragraphs = html.match(/<p[^>]*>([\\s\\S]*?)<\\/p>/gi) || [];\n const snippetZoneParagraphs = paragraphs.filter(p => {\n const text = p.replace(/<[^>]*>/g, '').trim();\n const wordCount = text.split(/\\s+/).length;\n return wordCount >= 40 && wordCount <= 150;\n });\n if (snippetZoneParagraphs.length >= 3) {\n score += 2;\n findings.push({ severity: 'info', detail: `${snippetZoneParagraphs.length} paragraphs in snippet zone (40-150 words) - ideal for AI extraction` });\n } else if (snippetZoneParagraphs.length >= 1) {\n score += 1;\n findings.push({ severity: 'low', detail: `Only ${snippetZoneParagraphs.length} paragraph(s) in optimal snippet length`, fix: 'Write more paragraphs in the 40-150 word range for AI snippet extraction' });\n } else {\n findings.push({ severity: 'medium', detail: 'No paragraphs in the optimal snippet zone (40-150 words)', fix: 'Write self-contained paragraphs of 40-150 words that directly answer common questions' });\n }\n\n // Direct answer openers\n const text = data.homepage.text.replace(/<[^>]*>/g, ' ').replace(/\\s+/g, ' ');\n const directOpeners = /\\b(yes|no|the answer is|in short|simply put|to summarize)\\b/gi;\n const openerCount = (text.match(directOpeners) || []).length;\n if (openerCount >= 2) {\n score += 2;\n findings.push({ severity: 'info', detail: 'Direct answer openers found (e.g., \"Yes,\", \"In short,\")' });\n } else {\n findings.push({ severity: 'low', detail: 'Few or no direct answer openers found', fix: 'Start answers with direct phrases like \"Yes,\", \"No,\", \"In short,\" to signal definitive answers to AI engines' });\n }\n\n return { criterion: 'direct_answer_density', criterion_label: 'Direct Answer Paragraphs', score: Math.min(10, score), status: score >= 7 ? 'pass' : score >= 4 ? 'partial' : 'fail', findings, fix_priority: score >= 7 ? 'P2' : 'P1' };\n}\n\n// Criterion 17: Content Licensing\nfunction checkContentLicensing(data: SiteData): CriterionResult {\n const findings: AuditFinding[] = [];\n let score = 0;\n\n // ai.txt exists (ignore HTML catch-all responses)\n const aiTxt = data.aiTxt;\n if (aiTxt && aiTxt.status === 200 && aiTxt.text.length > 20 && !isHtmlResponse(aiTxt)) {\n score += 4;\n findings.push({ severity: 'info', detail: `ai.txt file found (${aiTxt.text.length} characters)` });\n } else {\n findings.push({ severity: 'high', detail: 'No ai.txt file found', fix: 'Create /ai.txt to declare your AI usage policy and content permissions for AI crawlers' });\n }\n\n const html = data.homepage?.text || '';\n const text = html.replace(/<[^>]*>/g, ' ').replace(/\\s+/g, ' ');\n\n // Policy language on page\n const hasPolicyLanguage = /content\\s+policy|terms\\s+of\\s+use|usage\\s+rights|permission|copyright\\s+policy|licensing|creative\\s+commons/i.test(text);\n if (hasPolicyLanguage) {\n score += 2;\n findings.push({ severity: 'info', detail: 'Content policy or licensing language found on page' });\n } else {\n findings.push({ severity: 'low', detail: 'No content policy or licensing language visible', fix: 'Add clear content usage terms or licensing information' });\n }\n\n // Schema license property\n const hasLicenseSchema = /license|copyrightHolder|copyrightYear/i.test(html) && /application\\/ld\\+json/i.test(html);\n if (hasLicenseSchema) {\n score += 2;\n findings.push({ severity: 'info', detail: 'License or copyright properties found in schema markup' });\n } else {\n findings.push({ severity: 'low', detail: 'No license or copyright properties in schema', fix: 'Add license, copyrightHolder, and copyrightYear to your schema markup' });\n }\n\n // TDM (Text and Data Mining) or Creative Commons\n const hasTdmOrCC = /tdm|text\\s+and\\s+data\\s+mining|creative\\s+commons|CC\\s+BY|creativecommons\\.org/i.test(html + (aiTxt?.text || ''));\n if (hasTdmOrCC) {\n score += 2;\n findings.push({ severity: 'info', detail: 'TDM or Creative Commons licensing references found' });\n } else {\n findings.push({ severity: 'low', detail: 'No TDM or Creative Commons licensing references found', fix: 'Add Text and Data Mining (TDM) permissions or Creative Commons licensing to signal AI-friendly content use' });\n }\n\n return { criterion: 'content_licensing', criterion_label: 'Content Licensing & AI Permissions', score: Math.min(10, score), status: score >= 7 ? 'pass' : score >= 4 ? 'partial' : 'fail', findings, fix_priority: score >= 4 ? 'P3' : 'P2' };\n}\n\n// Criterion 18: Author Schema Depth\nfunction checkAuthorSchemaDepth(data: SiteData): CriterionResult {\n const findings: AuditFinding[] = [];\n\n if (!data.homepage) {\n findings.push({ severity: 'critical', detail: 'Could not fetch homepage' });\n return { criterion: 'author_schema_depth', criterion_label: 'Author & Expert Schema', score: 0, status: 'not_found', findings, fix_priority: 'P2' };\n }\n\n // Use combined HTML for author detection\n const combinedHtml = getCombinedHtml(data);\n const html = data.homepage.text;\n const text = combinedHtml.replace(/<[^>]*>/g, ' ').replace(/\\s+/g, ' ');\n let score = 0;\n\n // Person schema (check combined - blog posts often have author schema)\n const hasPersonSchema = /\"@type\"\\s*:\\s*\"Person\"/i.test(combinedHtml);\n if (hasPersonSchema) {\n score += 3;\n findings.push({ severity: 'info', detail: 'Person schema found in JSON-LD' });\n } else {\n findings.push({ severity: 'medium', detail: 'No Person schema found', fix: 'Add Person schema for authors with name, jobTitle, knowsAbout, and sameAs properties' });\n }\n\n // jobTitle or knowsAbout properties\n const hasJobTitle = /jobTitle|knowsAbout|expertise|hasCredential/i.test(combinedHtml);\n if (hasJobTitle) {\n score += 2;\n findings.push({ severity: 'info', detail: 'Author credential properties found (jobTitle/knowsAbout)' });\n } else {\n findings.push({ severity: 'low', detail: 'No jobTitle or knowsAbout in author schema', fix: 'Add jobTitle and knowsAbout to Person schema to establish expertise' });\n }\n\n // sameAs links (social profiles)\n const hasSameAs = /sameAs/i.test(combinedHtml) && hasPersonSchema;\n if (hasSameAs) {\n score += 2;\n findings.push({ severity: 'info', detail: 'Author sameAs social profile links found' });\n } else {\n findings.push({ severity: 'low', detail: 'No sameAs links to author social profiles', fix: 'Add sameAs URLs (LinkedIn, GitHub) to Person schema to strengthen entity connections' });\n }\n\n // Visible byline\n const hasByline = /written\\s+by|authored?\\s+by|by\\s+[A-Z][a-z]+\\s+[A-Z]/i.test(text) ||\n /class=\"[^\"]*author[^\"]*\"/i.test(html) ||\n /rel=\"author\"/i.test(html);\n if (hasByline) {\n score += 2;\n findings.push({ severity: 'info', detail: 'Visible author byline or attribution found' });\n } else {\n findings.push({ severity: 'medium', detail: 'No visible author byline found', fix: 'Add visible author names with credentials to establish E-E-A-T' });\n }\n\n // <address> element for contact\n if (/<address[\\s>]/i.test(combinedHtml)) {\n score += 1;\n findings.push({ severity: 'info', detail: '<address> element found for contact information' });\n } else {\n findings.push({ severity: 'low', detail: 'No <address> element found for contact information', fix: 'Add an <address> element with contact details to reinforce entity identity' });\n }\n\n return { criterion: 'author_schema_depth', criterion_label: 'Author & Expert Schema', score: Math.min(10, score), status: score >= 7 ? 'pass' : score >= 4 ? 'partial' : 'fail', findings, fix_priority: score >= 7 ? 'P3' : 'P2' };\n}\n\n// Criterion 19: Fact Density\nfunction checkFactDensity(data: SiteData): CriterionResult {\n const findings: AuditFinding[] = [];\n\n if (!data.homepage) {\n findings.push({ severity: 'critical', detail: 'Could not fetch homepage' });\n return { criterion: 'fact_density', criterion_label: 'Fact & Data Density', score: 0, status: 'not_found', findings, fix_priority: 'P2' };\n }\n\n const text = data.homepage.text.replace(/<[^>]*>/g, ' ').replace(/\\s+/g, ' ');\n let score = 0;\n\n // Numeric data points (percentages, money, counts)\n const dataPoints = text.match(/\\d+(?:\\.\\d+)?(?:\\s*%|\\s*\\$|\\s*USD|\\s*EUR)/g) || [];\n const countPhrases = text.match(/\\d+(?:,\\d{3})*\\+?\\s+(?:users?|clients?|customers?|companies|businesses|patients?|members?|employees?|projects?|downloads?)/gi) || [];\n const totalDataPoints = dataPoints.length + countPhrases.length;\n\n if (totalDataPoints >= 6) {\n score += 5;\n findings.push({ severity: 'info', detail: `${totalDataPoints} quantitative data points found on homepage` });\n } else if (totalDataPoints >= 3) {\n score += 3;\n findings.push({ severity: 'info', detail: `${totalDataPoints} quantitative data points found` });\n } else if (totalDataPoints >= 1) {\n score += 1;\n findings.push({ severity: 'low', detail: `Only ${totalDataPoints} quantitative data point(s) found`, fix: 'Add more specific numbers, percentages, and metrics to strengthen credibility' });\n } else {\n findings.push({ severity: 'high', detail: 'No quantitative data points found', fix: 'Add specific statistics (percentages, counts, comparisons) that AI engines can cite' });\n }\n\n // Year references (suggest sourced/dated claims)\n const yearRefs = text.match(/(?:19|20)\\d{2}/g) || [];\n const uniqueYears = [...new Set(yearRefs)];\n if (uniqueYears.length >= 2) {\n score += 2;\n findings.push({ severity: 'info', detail: `${uniqueYears.length} different year references found - suggests dated, verifiable claims` });\n } else if (uniqueYears.length === 1) {\n score += 1;\n findings.push({ severity: 'low', detail: 'Only 1 year reference found on page', fix: 'Add more dated references and timestamps to demonstrate current, verifiable information' });\n } else {\n findings.push({ severity: 'low', detail: 'No year references found on page', fix: 'Include specific years and dates to provide verifiable, time-anchored facts' });\n }\n\n // Attribution phrases (source citations)\n const attributions = text.match(/according\\s+to|source:|study\\s+(?:by|from)|research\\s+(?:by|from|shows)|data\\s+from|report\\s+(?:by|from)|published\\s+(?:by|in)/gi) || [];\n if (attributions.length >= 1) {\n score += 2;\n findings.push({ severity: 'info', detail: `${attributions.length} source attribution(s) found (e.g., \"according to\", \"study by\")` });\n } else {\n findings.push({ severity: 'low', detail: 'No source attributions found', fix: 'Add citations like \"According to [source]\" or \"Research from [org] shows\" for credibility' });\n }\n\n // Units of measurement\n const units = text.match(/\\d+\\s*(?:hours?|minutes?|days?|weeks?|months?|years?|miles?|km|lbs?|kg|mg|sq\\s*ft|acres?|gallons?|liters?)/gi) || [];\n if (units.length >= 2) {\n score += 1;\n findings.push({ severity: 'info', detail: `${units.length} measurement units found (hours, miles, etc.) - adds factual precision` });\n } else {\n findings.push({ severity: 'low', detail: 'Few or no units of measurement found', fix: 'Include specific measurements (hours, miles, sq ft, etc.) to add factual precision AI engines can extract' });\n }\n\n return { criterion: 'fact_density', criterion_label: 'Fact & Data Density', score: Math.min(10, score), status: score >= 7 ? 'pass' : score >= 4 ? 'partial' : 'fail', findings, fix_priority: score >= 7 ? 'P3' : 'P2' };\n}\n\n// Criterion 20: Canonical URL\nfunction checkCanonicalUrl(data: SiteData): CriterionResult {\n const findings: AuditFinding[] = [];\n\n if (!data.homepage) {\n findings.push({ severity: 'critical', detail: 'Could not fetch homepage' });\n return { criterion: 'canonical_url', criterion_label: 'Canonical URL Strategy', score: 0, status: 'not_found', findings, fix_priority: 'P1' };\n }\n\n const html = data.homepage.text;\n let score = 0;\n\n // Canonical link present (handle either attribute order: rel before href OR href before rel)\n const canonicalMatch = html.match(/<link[^>]*rel=\"canonical\"[^>]*href=\"([^\"]*)\"[^>]*>/i)\n || html.match(/<link[^>]*href=\"([^\"]*)\"[^>]*rel=\"canonical\"[^>]*>/i);\n if (canonicalMatch) {\n score += 4;\n findings.push({ severity: 'info', detail: `Canonical URL found: ${canonicalMatch[1].slice(0, 80)}` });\n\n // Self-referencing (canonical points to the same domain)\n const canonicalUrl = canonicalMatch[1];\n if (canonicalUrl.includes(data.domain)) {\n score += 3;\n findings.push({ severity: 'info', detail: 'Canonical URL is self-referencing (points to same domain)' });\n } else {\n findings.push({ severity: 'medium', detail: 'Canonical URL points to a different domain', fix: 'Ensure canonical URL points to the authoritative version of this page' });\n }\n\n // HTTPS canonical\n if (canonicalUrl.startsWith('https://')) {\n score += 2;\n findings.push({ severity: 'info', detail: 'Canonical URL uses HTTPS' });\n } else {\n findings.push({ severity: 'medium', detail: 'Canonical URL does not use HTTPS', fix: 'Update canonical URL to use https://' });\n }\n } else {\n findings.push({ severity: 'high', detail: 'No canonical URL tag found', fix: 'Add <link rel=\"canonical\" href=\"https://yoursite.com/page\"> to prevent duplicate content issues' });\n }\n\n // Check for duplicate canonical tags (match either attribute order)\n const allCanonicals = html.match(/<link[^>]*(?:rel=\"canonical\"|rel='canonical')[^>]*>/gi) || [];\n if (allCanonicals.length > 1) {\n score -= 1;\n findings.push({ severity: 'high', detail: `${allCanonicals.length} canonical tags found - must have exactly one`, fix: 'Remove duplicate canonical tags, keeping only one per page' });\n } else if (allCanonicals.length === 1) {\n score += 1;\n findings.push({ severity: 'info', detail: 'Single canonical tag present (no duplicates)' });\n }\n\n return { criterion: 'canonical_url', criterion_label: 'Canonical URL Strategy', score: Math.max(0, Math.min(10, score)), status: score >= 7 ? 'pass' : score >= 4 ? 'partial' : 'fail', findings, fix_priority: score >= 7 ? 'P3' : 'P1' };\n}\n\n// ─── Helper: analyze sitemap lastmod dates for content velocity ──────────────\n\nexport interface SitemapDateAnalysis {\n recentCount: number;\n isUniform: boolean;\n uniformDetail?: string;\n totalWithDates: number;\n distinctRecentDays: number;\n}\n\nexport function countRecentSitemapDates(sitemapText: string): SitemapDateAnalysis {\n const lastmodMatches = sitemapText.match(/<lastmod>([^<]+)<\\/lastmod>/gi) || [];\n if (lastmodMatches.length === 0) {\n return { recentCount: 0, isUniform: false, totalWithDates: 0, distinctRecentDays: 0 };\n }\n\n const now = new Date();\n const ninetyDaysAgo = new Date(now.getTime() - 90 * 24 * 60 * 60 * 1000);\n\n // Parse all dates and group by day\n const dayCounts: Record<string, number> = {};\n let recentCount = 0;\n const recentDays = new Set<string>();\n\n for (const match of lastmodMatches) {\n const dateStr = match.replace(/<\\/?lastmod>/gi, '').trim();\n const date = new Date(dateStr);\n if (isNaN(date.getTime())) continue;\n\n const dayKey = date.toISOString().split('T')[0];\n dayCounts[dayKey] = (dayCounts[dayKey] || 0) + 1;\n\n if (date >= ninetyDaysAgo) {\n recentCount++;\n recentDays.add(dayKey);\n }\n }\n\n // Detect uniform pattern: if most common day has >80% of all dated URLs\n const totalWithDates = Object.values(dayCounts).reduce((a, b) => a + b, 0);\n const maxDayCount = Math.max(...Object.values(dayCounts));\n const isUniform = totalWithDates >= 5 && maxDayCount / totalWithDates > 0.8;\n\n let uniformDetail: string | undefined;\n if (isUniform) {\n const topDay = Object.entries(dayCounts).find(([, count]) => count === maxDayCount)![0];\n uniformDetail = `${maxDayCount} of ${totalWithDates} URLs share lastmod date ${topDay} - likely auto-generated by build system`;\n }\n\n return {\n recentCount,\n isUniform,\n uniformDetail,\n totalWithDates,\n distinctRecentDays: recentDays.size,\n };\n}\n\n// ─── Blog URL extraction from sitemap ────────────────────────────────────────\n\nconst BLOG_PATH_PATTERNS = /\\/(?:blog|articles?|insights?|guides?|resources?|news|posts?|learn|help|how-?to|tutorials?|case-stud|whitepapers?)\\b/i;\n\nconst EXCLUDE_PATH_PATTERNS = /\\/(?:tag|category|author|page|feed|wp-content|wp-admin|wp-json|cart|checkout|login|search|api|static|assets|_next)\\b/i;\n\n/**\n * Extract blog/content URLs from a sitemap XML string.\n * Includes URLs matching common blog path patterns, plus deep paths (2+ segments).\n * Sorts by lastmod descending (newest first), returns top N.\n */\nexport function extractBlogUrlsFromSitemap(sitemapText: string, domain: string, limit: number = 5): string[] {\n const urlBlocks = sitemapText.match(/<url>([\\s\\S]*?)<\\/url>/gi) || [];\n const candidates: { url: string; lastmod: string }[] = [];\n const cleanDomain = domain.replace(/^www\\./, '').toLowerCase();\n\n for (const block of urlBlocks) {\n const locMatch = block.match(/<loc>([^<]+)<\\/loc>/i);\n if (!locMatch) continue;\n const url = locMatch[1].trim();\n\n // Must be same domain\n try {\n const parsed = new URL(url);\n const urlDomain = parsed.hostname.replace(/^www\\./, '').toLowerCase();\n if (urlDomain !== cleanDomain) continue;\n\n // Skip root URL\n if (parsed.pathname === '/' || parsed.pathname === '') continue;\n\n const path = parsed.pathname.toLowerCase();\n\n // Exclude unwanted paths\n if (EXCLUDE_PATH_PATTERNS.test(path)) continue;\n\n // Include blog-like paths OR deep paths (2+ segments)\n const segments = path.split('/').filter(Boolean);\n const isBlogPath = BLOG_PATH_PATTERNS.test(path);\n const isDeepPath = segments.length >= 2;\n\n if (!isBlogPath && !isDeepPath) continue;\n } catch {\n continue;\n }\n\n const lastmodMatch = block.match(/<lastmod>([^<]+)<\\/lastmod>/i);\n const lastmod = lastmodMatch ? lastmodMatch[1].trim() : '';\n\n candidates.push({ url, lastmod });\n }\n\n // Sort by lastmod descending (newest first), URLs without lastmod go last\n candidates.sort((a, b) => {\n if (a.lastmod && b.lastmod) return b.lastmod.localeCompare(a.lastmod);\n if (a.lastmod) return -1;\n if (b.lastmod) return 1;\n return 0;\n });\n\n return candidates.slice(0, limit).map(c => c.url);\n}\n\n/**\n * Extract the best sub-sitemap URL from a sitemapindex.\n * WordPress often uses sitemapindex pointing to post-sitemap.xml, page-sitemap.xml, etc.\n * Returns null if not a sitemapindex.\n */\nexport function extractSubSitemapUrl(sitemapText: string): string | null {\n if (!sitemapText.includes('<sitemapindex')) return null;\n\n const sitemapLocs = sitemapText.match(/<sitemap>[\\s\\S]*?<loc>([^<]+)<\\/loc>[\\s\\S]*?<\\/sitemap>/gi) || [];\n if (sitemapLocs.length === 0) return null;\n\n const urls = sitemapLocs.map(block => {\n const match = block.match(/<loc>([^<]+)<\\/loc>/i);\n return match ? match[1].trim() : '';\n }).filter(Boolean);\n\n // Prefer post/blog/article sub-sitemap\n const preferred = urls.find(u => /post|blog|article/i.test(u));\n return preferred || urls[0] || null;\n}\n\n// Criterion 21: Content Velocity\nfunction checkContentVelocity(data: SiteData): CriterionResult {\n const findings: AuditFinding[] = [];\n const sitemap = data.sitemapXml;\n let score = 0;\n\n if (!sitemap || sitemap.status !== 200) {\n findings.push({ severity: 'medium', detail: 'No sitemap available to assess content velocity', fix: 'Create a sitemap.xml with lastmod dates to signal content publishing frequency' });\n return { criterion: 'content_velocity', criterion_label: 'Content Publishing Velocity', score: 0, status: 'fail', findings, fix_priority: 'P2' };\n }\n\n const analysis = countRecentSitemapDates(sitemap.text);\n\n if (analysis.totalWithDates === 0) {\n findings.push({ severity: 'medium', detail: 'No lastmod dates in sitemap', fix: 'Add lastmod dates to sitemap entries to signal content freshness' });\n return { criterion: 'content_velocity', criterion_label: 'Content Publishing Velocity', score: 2, status: 'fail', findings, fix_priority: 'P2' };\n }\n\n score += 2;\n findings.push({ severity: 'info', detail: `${analysis.totalWithDates} pages have lastmod dates` });\n\n // Use distinct recent days when lastmod dates are uniform (build-system artifact)\n const effectiveCount = analysis.isUniform ? analysis.distinctRecentDays : analysis.recentCount;\n\n if (analysis.isUniform) {\n findings.push({ severity: 'medium', detail: analysis.uniformDetail!, fix: 'Set genuine lastmod dates per page reflecting actual content changes, not build timestamps' });\n }\n\n if (effectiveCount >= 20) {\n score += 8;\n findings.push({ severity: 'info', detail: `${effectiveCount} ${analysis.isUniform ? 'distinct dates' : 'pages updated'} in last 90 days - excellent content velocity` });\n } else if (effectiveCount >= 10) {\n score += 5;\n findings.push({ severity: 'info', detail: `${effectiveCount} ${analysis.isUniform ? 'distinct dates' : 'pages updated'} in last 90 days - good velocity` });\n } else if (effectiveCount >= 5) {\n score += 3;\n findings.push({ severity: 'info', detail: `${effectiveCount} ${analysis.isUniform ? 'distinct dates' : 'pages updated'} in last 90 days` });\n } else if (effectiveCount >= 1) {\n score += 1;\n findings.push({ severity: 'low', detail: `Only ${effectiveCount} ${analysis.isUniform ? 'distinct date(s)' : 'page(s) updated'} in last 90 days`, fix: 'Publish or update content more frequently to signal active maintenance' });\n } else {\n findings.push({ severity: 'medium', detail: 'No pages updated in the last 90 days', fix: 'Update existing content and publish new pages regularly' });\n }\n\n return { criterion: 'content_velocity', criterion_label: 'Content Publishing Velocity', score: Math.min(10, score), status: score >= 7 ? 'pass' : score >= 4 ? 'partial' : 'fail', findings, fix_priority: score >= 7 ? 'P3' : 'P2' };\n}\n\n// Criterion 22: Schema Coverage (depth across types)\nfunction checkSchemaCoverage(data: SiteData): CriterionResult {\n const findings: AuditFinding[] = [];\n\n if (!data.homepage) {\n findings.push({ severity: 'critical', detail: 'Could not fetch homepage' });\n return { criterion: 'schema_coverage', criterion_label: 'Schema Coverage & Depth', score: 0, status: 'not_found', findings, fix_priority: 'P2' };\n }\n\n // Use combined HTML for schema coverage (blog posts add Article, Person, FAQPage etc.)\n const combinedHtml = getCombinedHtml(data);\n const html = data.homepage.text;\n const ldJsonMatches = combinedHtml.match(/<script[^>]*type=\"application\\/ld\\+json\"[^>]*>([\\s\\S]*?)<\\/script>/gi) || [];\n let score = 0;\n\n if (ldJsonMatches.length === 0) {\n findings.push({ severity: 'critical', detail: 'No JSON-LD found - cannot assess schema coverage', fix: 'Add JSON-LD schema markup to improve AI engine understanding' });\n return { criterion: 'schema_coverage', criterion_label: 'Schema Coverage & Depth', score: 0, status: 'fail', findings, fix_priority: 'P1' };\n }\n\n const allSchemaText = ldJsonMatches.join(' ');\n const allSchemaLower = allSchemaText.toLowerCase();\n\n // Count distinct schema properties\n const propertyMatches = allSchemaText.match(/\"[a-zA-Z@]+\"\\s*:/g) || [];\n const uniqueProperties = new Set(propertyMatches.map(p => p.replace(/[\":\\s]/g, '').toLowerCase()));\n\n if (uniqueProperties.size >= 15) {\n score += 2;\n findings.push({ severity: 'info', detail: `${uniqueProperties.size} unique schema properties used - rich schema depth` });\n } else if (uniqueProperties.size >= 5) {\n score += 2;\n findings.push({ severity: 'info', detail: `${uniqueProperties.size} unique schema properties found` });\n } else {\n score += 1;\n findings.push({ severity: 'low', detail: `Only ${uniqueProperties.size} schema properties`, fix: 'Add more properties to your schema types for richer AI understanding' });\n }\n\n // Organization depth (name, url, logo, contactPoint, sameAs, address, etc.)\n const orgProps = ['name', 'url', 'logo', 'contactpoint', 'sameas', 'address', 'telephone', 'description', 'founder', 'foundingdate'];\n const orgPropsFound = orgProps.filter(p => allSchemaLower.includes(`\"${p}\"`));\n if (orgPropsFound.length >= 5) {\n score += 2;\n findings.push({ severity: 'info', detail: `Organization schema has ${orgPropsFound.length}/10 key properties` });\n } else if (orgPropsFound.length >= 3) {\n score += 1;\n findings.push({ severity: 'low', detail: `Organization schema has only ${orgPropsFound.length}/10 key properties`, fix: 'Add more Organization properties: logo, contactPoint, sameAs, address' });\n } else {\n findings.push({ severity: 'medium', detail: `Organization schema has only ${orgPropsFound.length} key properties`, fix: 'Add essential Organization properties: name, url, logo, contactPoint, sameAs, address, telephone' });\n }\n\n // Article schema depth\n const articleProps = ['headline', 'datepublished', 'datemodified', 'author', 'image', 'description', 'publisher'];\n const articlePropsFound = articleProps.filter(p => allSchemaLower.includes(`\"${p}\"`));\n if (articlePropsFound.length >= 4) {\n score += 2;\n findings.push({ severity: 'info', detail: `Article schema has ${articlePropsFound.length}/7 key properties` });\n } else if (articlePropsFound.length >= 2) {\n score += 1;\n findings.push({ severity: 'low', detail: `Article schema has only ${articlePropsFound.length}/7 key properties`, fix: 'Add headline, datePublished, dateModified, author, image, and publisher to Article schema' });\n } else {\n findings.push({ severity: 'medium', detail: 'Article schema missing or has fewer than 2 key properties', fix: 'Add Article schema with headline, datePublished, author, and publisher properties' });\n }\n\n // @id linking (connected schema graph)\n const hasIdLinking = /\"@id\"\\s*:/i.test(allSchemaText);\n if (hasIdLinking) {\n score += 2;\n findings.push({ severity: 'info', detail: '@id linking found - schema types are connected in a graph' });\n } else {\n findings.push({ severity: 'low', detail: 'No @id linking between schema types', fix: 'Use @id references to connect schema types (e.g., article.publisher -> organization)' });\n }\n\n // Number of distinct types\n const schemaTypes = ['organization', 'localbusiness', 'faqpage', 'service', 'article', 'webpage', 'website', 'breadcrumblist', 'howto', 'product', 'person', 'event', 'offer', 'review', 'aboutpage'];\n const foundTypes = schemaTypes.filter(t => allSchemaLower.includes(`\"${t}\"`));\n if (foundTypes.length >= 3) {\n score += 2;\n findings.push({ severity: 'info', detail: `${foundTypes.length} distinct schema types used: ${foundTypes.join(', ')}` });\n } else if (foundTypes.length >= 2) {\n score += 1;\n findings.push({ severity: 'low', detail: `Only ${foundTypes.length} distinct schema types used`, fix: 'Add more schema types (FAQPage, BreadcrumbList, Service) for comprehensive AI understanding' });\n } else {\n findings.push({ severity: 'medium', detail: `Only ${foundTypes.length} schema type(s) found - limited coverage`, fix: 'Add multiple schema types (Organization, WebSite, FAQPage, BreadcrumbList) for comprehensive AI understanding' });\n }\n\n return { criterion: 'schema_coverage', criterion_label: 'Schema Coverage & Depth', score: Math.min(10, score), status: score >= 7 ? 'pass' : score >= 4 ? 'partial' : 'fail', findings, fix_priority: score >= 7 ? 'P3' : 'P1' };\n}\n\n// Criterion 23: Speakable Schema (voice assistant readiness)\nfunction checkSpeakableSchema(data: SiteData): CriterionResult {\n const findings: AuditFinding[] = [];\n\n if (!data.homepage) {\n findings.push({ severity: 'critical', detail: 'Could not fetch homepage' });\n return { criterion: 'speakable_schema', criterion_label: 'Speakable Schema', score: 0, status: 'not_found', findings, fix_priority: 'P2' };\n }\n\n const combinedHtml = getCombinedHtml(data);\n const ldJsonMatches = combinedHtml.match(/<script[^>]*type=\"application\\/ld\\+json\"[^>]*>([\\s\\S]*?)<\\/script>/gi) || [];\n let score = 0;\n\n if (ldJsonMatches.length === 0) {\n findings.push({ severity: 'critical', detail: 'No JSON-LD found - cannot assess speakable schema', fix: 'Add JSON-LD schema markup with SpeakableSpecification to indicate voice-readable content sections' });\n return { criterion: 'speakable_schema', criterion_label: 'Speakable Schema', score: 0, status: 'fail', findings, fix_priority: 'P2' };\n }\n\n const allSchemaText = ldJsonMatches.join(' ');\n const allSchemaLower = allSchemaText.toLowerCase();\n\n // Detect SpeakableSpecification type or \"speakable\" property\n const hasSpeakableType = /speakablespecification/i.test(allSchemaLower);\n const hasSpeakableProperty = /\"speakable\"\\s*:/i.test(allSchemaText);\n const hasSpeakable = hasSpeakableType || hasSpeakableProperty;\n\n if (!hasSpeakable) {\n findings.push({ severity: 'medium', detail: 'No SpeakableSpecification schema found - voice assistants cannot identify readable sections', fix: 'Add SpeakableSpecification schema with cssSelector or xpath targeting key content sections (headlines, summaries, FAQ answers)' });\n return { criterion: 'speakable_schema', criterion_label: 'Speakable Schema', score: 0, status: 'fail', findings, fix_priority: 'P2' };\n }\n\n // Base: speakable detected\n score += 4;\n findings.push({ severity: 'info', detail: 'SpeakableSpecification schema detected - voice assistants can identify readable content' });\n\n // Check for cssSelector or xpath targeting\n const hasCssSelector = /\"cssselector\"/i.test(allSchemaLower);\n const hasXpath = /\"xpath\"/i.test(allSchemaLower);\n if (hasCssSelector || hasXpath) {\n score += 3;\n const targetType = hasCssSelector && hasXpath ? 'cssSelector and xpath' : hasCssSelector ? 'cssSelector' : 'xpath';\n findings.push({ severity: 'info', detail: `Speakable uses ${targetType} targeting for precise content selection` });\n } else {\n findings.push({ severity: 'low', detail: 'Speakable schema lacks cssSelector or xpath targeting', fix: 'Add cssSelector (e.g., \".article-headline, .article-summary\") or xpath to precisely target speakable sections' });\n }\n\n // Check blog sample coverage\n if (data.blogSample && data.blogSample.length > 0) {\n const blogHtml = data.blogSample.map(p => p.text).join('\\n');\n const blogHasSpeakable = /speakablespecification/i.test(blogHtml) || /\"speakable\"\\s*:/i.test(blogHtml);\n if (blogHasSpeakable) {\n score += 3;\n findings.push({ severity: 'info', detail: 'Speakable schema also found in blog/content pages - comprehensive voice coverage' });\n } else {\n findings.push({ severity: 'low', detail: 'Speakable schema only on homepage, not found in blog/content pages', fix: 'Add SpeakableSpecification to article pages to make blog content voice-assistant readable' });\n }\n } else {\n // No blog samples - can't check, give partial credit\n findings.push({ severity: 'info', detail: 'No blog pages sampled - blog speakable coverage not assessed' });\n }\n\n return { criterion: 'speakable_schema', criterion_label: 'Speakable Schema', score: Math.min(10, score), status: score >= 7 ? 'pass' : score >= 4 ? 'partial' : 'fail', findings, fix_priority: score >= 7 ? 'P3' : 'P2' };\n}\n\n// ─── Raw data summary extraction (for AI narrative) ─────────────────────────\n\nexport function extractRawDataSummary(data: SiteData): RawDataSummary {\n const html = data.homepage?.text || '';\n const text = html.replace(/<[^>]*>/g, ' ').replace(/\\s+/g, ' ');\n\n // Schema types\n const ldJsonMatches = html.match(/<script[^>]*type=\"application\\/ld\\+json\"[^>]*>([\\s\\S]*?)<\\/script>/gi) || [];\n const allSchemaText = ldJsonMatches.join(' ').toLowerCase();\n const schemaTypes = ['organization', 'localbusiness', 'faqpage', 'service', 'article', 'webpage', 'website', 'breadcrumblist', 'howto', 'product'];\n const foundSchemaTypes = schemaTypes.filter(t =>\n allSchemaText.includes(`\"${t}\"`) || allSchemaText.includes(`\"@type\":\"${t}\"`)\n );\n\n // Links\n const linkMatches = html.match(/<a[^>]*href=\"([^\"]*)\"[^>]*>/gi) || [];\n const internalLinks = linkMatches.filter(l => {\n const href = l.match(/href=\"([^\"]*)\"/)?.[1] || '';\n return href.startsWith('/') || href.includes(data.domain);\n });\n const externalLinks = linkMatches.filter(l => {\n const href = l.match(/href=\"([^\"]*)\"/)?.[1] || '';\n return href.startsWith('http') && !href.includes(data.domain);\n });\n\n // robots.txt AI crawlers\n const robotsText = (data.robotsTxt?.text || '').toLowerCase();\n const aiCrawlers = ['gptbot', 'claudebot', 'perplexitybot', 'anthropic', 'chatgpt'];\n const mentionedCrawlers = aiCrawlers.filter(c => robotsText.includes(c));\n const blockedCrawlers = mentionedCrawlers.filter(c => {\n const sectionRegex = new RegExp(`user-agent:\\\\s*${c}[^\\\\S\\\\n]*\\\\n([\\\\s\\\\S]*?)(?=user-agent:|$)`, 'i');\n const match = sectionRegex.exec(data.robotsTxt?.text || '');\n if (!match) return false;\n const section = match[1];\n if (/^allow:\\s*\\/\\s*$/im.test(section)) return false;\n return /^disallow:\\s*\\/\\s*$/im.test(section);\n });\n\n // Headings\n const hTagContent = (html.match(/<h[1-6][^>]*>([\\s\\S]*?)<\\/h[1-6]>/gi) || []).map(h => h.replace(/<[^>]*>/g, ''));\n const questionHeadings = hTagContent.filter(h => h.includes('?') || /^(what|how|why|when|who|where|can|do|does|is|are|should)\\s/i.test(h));\n const h1Count = (html.match(/<h1[\\s>]/gi) || []).length;\n\n // Images\n const images = html.match(/<img[^>]*>/gi) || [];\n const imagesWithAlt = images.filter(img => /alt=\"[^\"]+\"/i.test(img));\n\n // Semantic elements\n const semanticChecks = ['main', 'article', 'nav', 'header', 'footer', 'section', 'time'];\n const foundElements = semanticChecks.filter(el => new RegExp(`<${el}[\\\\s>]`, 'i').test(html));\n\n return {\n domain: data.domain,\n protocol: data.protocol,\n homepage_length: html.length,\n homepage_text_length: text.trim().length,\n has_https: data.protocol === 'https',\n llms_txt_status: data.llmsTxt && !isHtmlResponse(data.llmsTxt) ? data.llmsTxt.status : null,\n llms_txt_length: data.llmsTxt?.status === 200 && !isHtmlResponse(data.llmsTxt) ? (data.llmsTxt.text.length) : 0,\n robots_txt_status: data.robotsTxt && !isHtmlResponse(data.robotsTxt) ? data.robotsTxt.status : null,\n robots_txt_snippet: (data.robotsTxt?.text || '').slice(0, 500),\n robots_txt_ai_crawlers: mentionedCrawlers,\n robots_txt_blocked_crawlers: blockedCrawlers,\n schema_types_found: foundSchemaTypes,\n schema_block_count: ldJsonMatches.length,\n faq_page_status: data.faqPage?.status ?? null,\n faq_page_length: data.faqPage?.status === 200 ? data.faqPage.text.length : 0,\n sitemap_status: data.sitemapXml?.status ?? null,\n internal_link_count: internalLinks.length,\n external_link_count: externalLinks.length,\n question_headings_count: questionHeadings.length,\n h1_count: h1Count,\n has_meta_description: /<meta[^>]*name=\"description\"[^>]*>/i.test(html),\n has_title: /<title[^>]*>[^<]+<\\/title>/i.test(html),\n has_phone: (() => {\n const phoneMatch = /(?:\\+?1[-.\\s]?)?\\(?\\d{3}\\)?[-.\\s]?\\d{3}[-.\\s]?\\d{4}/.test(text);\n if (!phoneMatch) return false;\n // Context validation: tel: link, schema telephone, or nearby keywords\n return /href=\"tel:/i.test(html) || /\"telephone\"/i.test(html) ||\n /\\b(phone|call|tel:|contact\\s*us|fax|dial)\\b/i.test(text);\n })(),\n has_address: /\\d+\\s+\\w+\\s+(street|st|avenue|ave|road|rd|drive|dr|blvd|boulevard|lane|ln|way|court|ct)/i.test(text),\n has_org_schema: /organization|localbusiness/i.test(html),\n has_social_links: /sameas|linkedin\\.com|facebook\\.com|twitter\\.com|x\\.com/i.test(html),\n semantic_elements_found: foundElements,\n img_count: images.length,\n img_with_alt_count: imagesWithAlt.length,\n has_lang_attr: /lang=\"[a-z]{2}\"/i.test(html),\n has_aria: /role=\"|aria-/i.test(html),\n has_breadcrumbs: /breadcrumb|aria-label=\"breadcrumb\"/i.test(html),\n has_nav: /<nav[\\s>]/i.test(html),\n has_footer: /<footer[\\s>]/i.test(html),\n has_case_studies: /case\\s+stud|testimonial|success\\s+stor|client\\s+stor/i.test(text),\n has_statistics: /\\d+%|\\d+\\s*(patients|clients|customers|cases|years|professionals|specialists|companies|users|businesses|domains|audits)/i.test(text),\n has_expert_attribution: /written\\s+by|authored\\s+by|expert|specialist|board.certified|licensed/i.test(text),\n has_blog_section: /href=\"[^\"]*\\/(?:blog|articles|insights|guides|resources)\\b[^\"]*\"/i.test(html),\n // New criteria fields\n has_date_modified_schema: /dateModified/i.test(html),\n time_element_count: (html.match(/<time[\\s>]/gi) || []).length,\n sitemap_url_count: (data.sitemapXml?.text?.match(/<loc>/gi) || []).length,\n has_rss_feed: !!(data.rssFeed && data.rssFeed.status === 200 && !isHtmlResponse(data.rssFeed)),\n table_count: (html.match(/<table[\\s>]/gi) || []).length,\n ordered_list_count: (html.match(/<ol[\\s>]/gi) || []).length,\n unordered_list_count: (html.match(/<ul[\\s>]/gi) || []).length,\n definition_pattern_count: (text.match(/\\brefers?\\s+to\\b|\\bdefined\\s+as\\b|\\bknown\\s+as\\b/gi) || []).length,\n has_ai_txt: !!(data.aiTxt && data.aiTxt.status === 200 && !isHtmlResponse(data.aiTxt)),\n has_person_schema: /\"@type\"\\s*:\\s*\"Person\"/i.test(html),\n fact_data_point_count: (text.match(/\\d+(?:\\.\\d+)?(?:\\s*%|\\s*\\$|\\s*USD)/g) || []).length,\n has_canonical: /<link[^>]*rel=\"canonical\"/i.test(html),\n has_license_schema: /license|copyrightHolder/i.test(html) && /application\\/ld\\+json/i.test(html),\n sitemap_recent_lastmod_count: (() => {\n const analysis = countRecentSitemapDates(data.sitemapXml?.text || '');\n return analysis.isUniform ? analysis.distinctRecentDays : analysis.recentCount;\n })(),\n // Speakable schema fields\n has_speakable_schema: /speakablespecification/i.test(ldJsonMatches.join(' ')) || /\"speakable\"\\s*:/i.test(ldJsonMatches.join(' ')),\n speakable_selector_count: (ldJsonMatches.join(' ').match(/\"cssselector\"|\"xpath\"/gi) || []).length,\n // Blog sample fields\n blog_sample_count: data.blogSample?.length ?? 0,\n blog_sample_urls: data.blogSample?.map(p => p.finalUrl || '').filter(Boolean) ?? [],\n blog_sample_schema_types: (() => {\n if (!data.blogSample || data.blogSample.length === 0) return [];\n const blogHtml = data.blogSample.map(p => p.text).join('\\n');\n const blogLd = blogHtml.match(/<script[^>]*type=\"application\\/ld\\+json\"[^>]*>([\\s\\S]*?)<\\/script>/gi) || [];\n const blogSchema = blogLd.join(' ').toLowerCase();\n const types = ['organization', 'localbusiness', 'faqpage', 'service', 'article', 'webpage', 'website', 'breadcrumblist', 'howto', 'product', 'person'];\n return types.filter(t => blogSchema.includes(`\"${t}\"`));\n })(),\n blog_sample_question_headings: (() => {\n if (!data.blogSample || data.blogSample.length === 0) return 0;\n const blogHtml = data.blogSample.map(p => p.text).join('\\n');\n const hTags = (blogHtml.match(/<h[1-6][^>]*>([\\s\\S]*?)<\\/h[1-6]>/gi) || []).map(h => h.replace(/<[^>]*>/g, ''));\n return hTags.filter(h => h.includes('?') || /^(what|how|why|when|who|where|can|do|does|is|are|should)\\s/i.test(h)).length;\n })(),\n blog_sample_faq_schema_found: (() => {\n if (!data.blogSample || data.blogSample.length === 0) return false;\n const blogHtml = data.blogSample.map(p => p.text).join('\\n');\n return /faqpage/i.test(blogHtml) && /application\\/ld\\+json/i.test(blogHtml);\n })(),\n };\n}\n\n// ─── Main audit function ────────────────────────────────────────────────────\n\n/**\n * Run all 23 criteria checks using pre-fetched site data.\n * All functions are synchronous (no HTTP calls) - data was already fetched.\n */\nexport function auditSiteFromData(data: SiteData): CriterionResult[] {\n return [\n checkLlmsTxt(data),\n checkSchemaMarkup(data),\n checkQAFormat(data),\n checkCleanHTML(data),\n checkEntityConsistency(data),\n checkRobotsTxt(data),\n checkFAQSection(data),\n checkOriginalData(data),\n checkInternalLinking(data),\n checkSemanticHTML(data),\n checkContentFreshness(data),\n checkSitemapCompleteness(data),\n checkRssFeed(data),\n checkTableListExtractability(data),\n checkDefinitionPatterns(data),\n checkDirectAnswerDensity(data),\n checkContentLicensing(data),\n checkAuthorSchemaDepth(data),\n checkFactDensity(data),\n checkCanonicalUrl(data),\n checkContentVelocity(data),\n checkSchemaCoverage(data),\n checkSpeakableSchema(data),\n ];\n}\n\n/**\n * Legacy entry point: fetches data and runs all checks.\n * Used by analyzer.ts for the /api/aeo/analyze endpoint.\n */\nexport async function auditSite(targetUrl: string): Promise<CriterionResult[]> {\n const url = new URL(targetUrl.startsWith('http') ? targetUrl : `https://${targetUrl}`);\n const domain = url.hostname.replace(/^www\\./, '');\n const data = await prefetchSiteData(domain);\n return auditSiteFromData(data);\n}\n","import type { CriterionResult } from './site-crawler.js';\n\nconst WEIGHTS: Record<string, number> = {\n // Original 10\n llms_txt: 0.10,\n schema_markup: 0.15,\n qa_content_format: 0.15,\n clean_html: 0.10,\n entity_consistency: 0.10,\n robots_txt: 0.05,\n faq_section: 0.10,\n original_data: 0.10,\n internal_linking: 0.10,\n semantic_html: 0.05,\n // New 12\n content_freshness: 0.07,\n sitemap_completeness: 0.05,\n rss_feed: 0.03,\n table_list_extractability: 0.07,\n definition_patterns: 0.04,\n direct_answer_density: 0.07,\n content_licensing: 0.04,\n author_schema_depth: 0.04,\n fact_density: 0.05,\n canonical_url: 0.04,\n content_velocity: 0.03,\n schema_coverage: 0.03,\n speakable_schema: 0.03,\n};\n\nexport function calculateOverallScore(criteria: CriterionResult[]): number {\n let totalWeight = 0;\n let weightedSum = 0;\n\n for (const c of criteria) {\n const weight = WEIGHTS[c.criterion] ?? 0.10;\n weightedSum += (c.score / 10) * weight * 100;\n totalWeight += weight;\n }\n\n if (totalWeight === 0) return 0;\n return Math.round(weightedSum / totalWeight);\n}\n","/**\r\n * SPA detection and headless Chromium rendering for pre-crawl.\r\n *\r\n * When a site returns a thin JS-only shell (e.g. React CRA, Vite SPA),\r\n * the regular fetch() gets almost no text content, causing false low scores.\r\n * This module detects those shells and re-renders them with Puppeteer.\r\n */\r\n\r\nimport type { FetchResult } from './site-crawler.js';\r\n\r\n// ─── SPA classification ─────────────────────────────────────────────────────\r\n\r\nexport type RenderingMethod = 'server' | 'client-spa';\r\n\r\ninterface RenderingClassification {\r\n method: RenderingMethod;\r\n framework: string | null;\r\n}\r\n\r\n// ─── SPA shell detection ────────────────────────────────────────────────────\r\n\r\nconst SPA_INDICATORS = [\r\n // Root mount points (empty or nearly empty, including self-closing)\r\n /<div\\s+id=[\"'](root|app|__next|__nuxt|__vue)[\"'][^>]*(?:\\/>|>\\s*<\\/div>)/i,\r\n // Framework globals\r\n /__NEXT_DATA__/,\r\n /__NUXT__/,\r\n // CRA / Vite bundle patterns\r\n /src=[\"'][^\"']*\\/static\\/js\\/main\\.[a-f0-9]+\\.js[\"']/i,\r\n /src=[\"'][^\"']*\\/assets\\/index-[a-f0-9]+\\.js[\"']/i,\r\n // React markers\r\n /data-reactroot/i,\r\n // Angular\r\n /ng-version/i,\r\n // Noscript JS warnings\r\n /<noscript>[^<]*(?:javascript|enable\\s+js|requires?\\s+javascript)[^<]*<\\/noscript>/i,\r\n];\r\n\r\n/**\r\n * Detect whether raw HTML is a thin SPA shell that needs client-side rendering.\r\n * Both conditions required:\r\n * 1. Visible text content < 500 chars (thin page)\r\n * 2. At least one SPA framework indicator present\r\n */\r\nexport function isSpaShell(html: string): boolean {\r\n // Strip all tags and collapse whitespace to get visible text\r\n const text = html\r\n .replace(/<script[\\s\\S]*?<\\/script>/gi, '')\r\n .replace(/<style[\\s\\S]*?<\\/style>/gi, '')\r\n .replace(/<[^>]*>/g, ' ')\r\n .replace(/\\s+/g, ' ')\r\n .trim();\r\n\r\n if (text.length >= 500) return false;\r\n\r\n return SPA_INDICATORS.some((pattern) => pattern.test(html));\r\n}\r\n\r\n/**\r\n * Classify a page's rendering method from its raw (non-headless) HTML.\r\n * Returns the method ('server' | 'client-spa') and detected framework if any.\r\n */\r\nexport function classifyRendering(html: string): RenderingClassification {\r\n if (!isSpaShell(html)) return { method: 'server', framework: null };\r\n\r\n // Detect framework from SPA indicators\r\n const frameworkPatterns: [RegExp, string][] = [\r\n [/__NEXT_DATA__/, 'next'],\r\n [/__NUXT__/, 'nuxt'],\r\n [/<div\\s+id=[\"']__vue[\"']/i, 'vue'],\r\n [/ng-version/i, 'angular'],\r\n [/data-reactroot/i, 'react'],\r\n [/<div\\s+id=[\"'](root|app)[\"'][^>]*(?:\\/>|>\\s*<\\/div>)/i, 'react'],\r\n [/src=[\"'][^\"']*\\/static\\/js\\/main\\.[a-f0-9]+\\.js[\"']/i, 'react'],\r\n [/src=[\"'][^\"']*\\/assets\\/index-[a-f0-9]+\\.js[\"']/i, 'vite'],\r\n ];\r\n\r\n for (const [pattern, framework] of frameworkPatterns) {\r\n if (pattern.test(html)) return { method: 'client-spa', framework };\r\n }\r\n\r\n return { method: 'client-spa', framework: null };\r\n}\r\n\r\n// ─── Headless Chromium rendering ────────────────────────────────────────────\r\n\r\nexport interface HeadlessOptions {\r\n timeout?: number;\r\n}\r\n\r\n/**\r\n * Render a URL with headless Chromium and return the fully-rendered HTML.\r\n * Returns null if Puppeteer is not installed or any error occurs.\r\n * The caller should fall back to the raw HTML in that case.\r\n */\r\nexport async function fetchWithHeadless(\r\n url: string,\r\n options?: HeadlessOptions\r\n): Promise<FetchResult | null> {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n let puppeteer: any;\r\n try {\r\n // Dynamic import - puppeteer is an optional peer dependency\r\n const mod = 'puppeteer';\r\n puppeteer = await import(/* @vite-ignore */ mod);\r\n } catch {\r\n return null;\r\n }\r\n\r\n const timeout = options?.timeout ?? 25000;\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n let browser: any = null;\r\n\r\n try {\r\n browser = await puppeteer.launch({\r\n headless: true,\r\n args: [\r\n '--no-sandbox',\r\n '--disable-setuid-sandbox',\r\n '--disable-dev-shm-usage',\r\n '--disable-gpu',\r\n '--single-process',\r\n ],\r\n });\r\n\r\n const page = await browser.newPage();\r\n\r\n // Block heavy resources to speed up rendering\r\n await page.setRequestInterception(true);\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n page.on('request', (req: any) => {\r\n const type = req.resourceType();\r\n if (['image', 'font', 'media', 'stylesheet'].includes(type)) {\r\n req.abort();\r\n } else {\r\n req.continue();\r\n }\r\n });\r\n\r\n await page.setUserAgent('AEO-Visibility-Bot/1.0');\r\n await page.goto(url, { waitUntil: 'networkidle2', timeout });\r\n\r\n // Wait for JS to populate the body with real text\r\n try {\r\n await page.waitForFunction(\r\n 'document.body && document.body.innerText && document.body.innerText.replace(/\\\\s+/g, \" \").trim().length > 100',\r\n { timeout: 5000 }\r\n );\r\n } catch {\r\n // Body text never exceeded 100 chars - still return what we got\r\n }\r\n\r\n const html = await page.content();\r\n const finalUrl = page.url();\r\n\r\n return {\r\n text: html.slice(0, 500000),\r\n status: 200,\r\n finalUrl,\r\n };\r\n } catch {\r\n return null;\r\n } finally {\r\n if (browser) {\r\n try {\r\n await browser.close();\r\n } catch {\r\n // Ignore close errors\r\n }\r\n }\r\n }\r\n}\r\n","/**\n * Shared scorecard building functions.\n * Extracted from cli/pre-crawl.ts for reuse in instant-audit and other consumers.\n */\n\nimport type { CriterionResult } from './site-crawler.js';\nimport type { Status, FindingType, Severity, ScoreCardItem, CriterionDetail, DetailedFinding } from './types.js';\nimport type { AuditFinding } from './types.js';\n\n// ─── Criterion label mapping (site-crawler labels -> prompt-standard names) ──\n\nexport const CRITERION_LABELS: Record<string, string> = {\n 'llms.txt File': 'llms.txt File',\n 'Schema.org Structured Data': 'Schema.org Structured Data',\n 'Q&A Content Format': 'Q&A Content Format',\n 'Clean, Crawlable HTML': 'Clean, Crawlable HTML',\n 'Entity Authority & E-E-A-T': 'Entity Authority & NAP Consistency',\n 'robots.txt for AI Crawlers': 'robots.txt for AI Crawlers',\n 'Comprehensive FAQ Sections': 'Comprehensive FAQ Section',\n 'Original Data & Expert Content': 'Original Data & Expert Analysis',\n 'Internal Linking Architecture': 'Internal Linking Structure',\n 'Semantic HTML5 & Accessibility': 'Semantic HTML5 & Accessibility',\n 'Content Freshness Signals': 'Content Freshness Signals',\n 'Sitemap Completeness': 'Sitemap Completeness',\n 'RSS/Atom Feed': 'RSS/Atom Feed',\n 'Table & List Extractability': 'Table & List Extractability',\n 'Definition Patterns': 'Definition Patterns',\n 'Direct Answer Paragraphs': 'Direct Answer Paragraphs',\n 'Content Licensing & AI Permissions': 'Content Licensing & AI Permissions',\n 'Author & Expert Schema': 'Author & Expert Schema',\n 'Fact & Data Density': 'Fact & Data Density',\n 'Canonical URL Strategy': 'Canonical URL Strategy',\n 'Content Publishing Velocity': 'Content Publishing Velocity',\n 'Schema Coverage & Depth': 'Schema Coverage & Depth',\n 'Speakable Schema': 'Speakable Schema',\n};\n\n// ─── Score to Status mapping (matches AI prompt: 0=MISSING...8-10=STRONG) ────\n\nexport function scoreToStatus(score: number): Status {\n if (score === 0) return 'MISSING';\n if (score === 1) return 'NEARLY EMPTY';\n if (score === 2) return 'POOR';\n if (score === 3) return 'WEAK';\n if (score <= 5) return 'PARTIAL';\n if (score === 6) return 'MODERATE';\n if (score === 7) return 'GOOD';\n return 'STRONG';\n}\n\n// ─── Finding severity mapping (site-crawler -> audit format) ─────────────────\n\nexport function mapFindingSeverity(severity: AuditFinding['severity']): Severity {\n switch (severity) {\n case 'critical': return 'CRITICAL';\n case 'high': return 'MISSING';\n case 'medium': return 'ADD';\n case 'low': return 'PARTIAL';\n case 'info': return 'WORKING';\n default: return 'PARTIAL';\n }\n}\n\nexport function mapFindingType(severity: AuditFinding['severity'], hasFix: boolean): FindingType {\n if (severity === 'info') return 'Good';\n if (severity === 'critical') return 'Critical';\n if (severity === 'high') return 'Missing';\n if (hasFix) return 'Issue';\n return 'Note';\n}\n\n// ─── Convert CriterionResult to scorecard + detailedFindings format ──────────\n\nexport function buildScorecard(results: CriterionResult[]): ScoreCardItem[] {\n return results.map((r, i) => {\n const label = CRITERION_LABELS[r.criterion_label] || r.criterion_label;\n\n // Build keyFindings from the most important findings (2-3 sentences)\n const keyParts: string[] = [];\n for (const f of r.findings) {\n if (keyParts.length >= 3) break;\n keyParts.push(f.detail);\n }\n const keyFindings = keyParts.join('. ') + (keyParts.length > 0 && !keyParts[keyParts.length - 1].endsWith('.') ? '.' : '');\n\n return {\n id: i + 1,\n criterion: label,\n score: r.score,\n status: scoreToStatus(r.score),\n keyFindings,\n };\n });\n}\n\nexport function buildDetailedFindings(results: CriterionResult[]): CriterionDetail[] {\n return results.map((r, i) => {\n const label = CRITERION_LABELS[r.criterion_label] || r.criterion_label;\n\n const rawFindings: DetailedFinding[] = r.findings.map(f => ({\n type: mapFindingType(f.severity, !!f.fix),\n description: f.fix ? `${f.detail}. ${f.fix}` : f.detail,\n severity: mapFindingSeverity(f.severity),\n }));\n\n // Deduplicate findings by description\n const seen = new Set<string>();\n const findings: DetailedFinding[] = [];\n for (const f of rawFindings) {\n if (!seen.has(f.description)) {\n seen.add(f.description);\n findings.push(f);\n }\n }\n\n // Fallback: if a criterion somehow has fewer than 2 findings, add a single specific one\n if (findings.length < 2) {\n if (r.score >= 7) {\n findings.push({ type: 'Good', description: `${label} is well-implemented for AI engine visibility.`, severity: 'WORKING' });\n } else {\n findings.push({ type: 'Note', description: `${label} needs improvement - review specific issues above.`, severity: 'PARTIAL' });\n }\n }\n\n return {\n id: i + 1,\n name: label,\n findings,\n };\n });\n}\n","/**\n * Deterministic narrative generation from scorecard data.\n * Produces verdict, opportunities, pitchNumbers, and bottomLine\n * without any LLM calls - pure template-based generation.\n */\n\nimport type { ScoreCardItem, Deliverable, PitchMetric, ImpactLevel } from './types.js';\nimport type { CriterionResult } from './site-crawler.js';\nimport type { RawDataSummary } from './site-crawler.js';\n\n// ─── Scoring weights (mirrored from scoring.ts for impact calculation) ───────\n\nconst CRITERION_WEIGHTS: Record<string, number> = {\n llms_txt: 0.10,\n schema_markup: 0.15,\n qa_content_format: 0.15,\n clean_html: 0.10,\n entity_consistency: 0.10,\n robots_txt: 0.05,\n faq_section: 0.10,\n original_data: 0.10,\n internal_linking: 0.10,\n semantic_html: 0.05,\n content_freshness: 0.07,\n sitemap_completeness: 0.05,\n rss_feed: 0.03,\n table_list_extractability: 0.07,\n definition_patterns: 0.04,\n direct_answer_density: 0.07,\n content_licensing: 0.04,\n author_schema_depth: 0.04,\n fact_density: 0.05,\n canonical_url: 0.04,\n content_velocity: 0.03,\n schema_coverage: 0.03,\n speakable_schema: 0.03,\n};\n\n// ─── Opportunity templates (23 criteria) ─────────────────────────────────────\n\ninterface OpportunityTemplate {\n name: string;\n effort: string;\n description: string;\n}\n\nconst OPPORTUNITY_TEMPLATES: Record<string, OpportunityTemplate> = {\n llms_txt: {\n name: 'Create llms.txt File',\n effort: 'Low',\n description: 'Add a /llms.txt file that describes your site, core services, and key pages in markdown format. This helps AI engines like ChatGPT and Claude understand your site structure and content offerings.',\n },\n schema_markup: {\n name: 'Add Schema.org Structured Data',\n effort: 'Medium',\n description: 'Implement JSON-LD structured data (Organization, Service, Product, FAQPage) on key pages. Schema markup helps AI engines extract and cite your content accurately.',\n },\n qa_content_format: {\n name: 'Restructure Content as Q&A',\n effort: 'Medium',\n description: 'Add question-based headings (H2/H3) throughout your content. Use \"What is...\", \"How does...\", \"Why should...\" patterns that match how users query AI assistants.',\n },\n clean_html: {\n name: 'Fix HTML Structure & Enable HTTPS',\n effort: 'Medium',\n description: 'Ensure clean, well-structured HTML with proper meta tags, semantic elements, and HTTPS. Clean HTML makes your content more parseable by AI crawlers.',\n },\n entity_consistency: {\n name: 'Strengthen Entity Authority (NAP)',\n effort: 'Low',\n description: 'Add Organization schema with consistent name, address, phone (NAP). Include sameAs links to social profiles and authoritative directories to strengthen entity recognition.',\n },\n robots_txt: {\n name: 'Configure robots.txt for AI Crawlers',\n effort: 'Low',\n description: 'Update robots.txt to explicitly allow AI crawlers (GPTBot, ClaudeBot, PerplexityBot). Add a Sitemap directive to help crawlers discover your content.',\n },\n faq_section: {\n name: 'Build Comprehensive FAQ Section',\n effort: 'Medium',\n description: 'Create a dedicated FAQ page with FAQPage schema markup. Cover common questions about your products, services, and industry to become a direct answer source for AI engines.',\n },\n original_data: {\n name: 'Add Original Data & Case Studies',\n effort: 'High',\n description: 'Publish original research, statistics, case studies, or proprietary data that AI engines can cite. Unique data points make your content a primary source rather than a derivative one.',\n },\n internal_linking: {\n name: 'Improve Internal Linking Architecture',\n effort: 'Medium',\n description: 'Strengthen internal linking with descriptive anchor text between related pages. Add breadcrumb navigation and ensure every key page is reachable within 3 clicks from the homepage.',\n },\n semantic_html: {\n name: 'Implement Semantic HTML5',\n effort: 'Low',\n description: 'Use semantic HTML5 elements (main, article, nav, header, footer, section) to give AI parsers clear content structure. Add lang attribute and ARIA labels for accessibility.',\n },\n content_freshness: {\n name: 'Add Content Freshness Signals',\n effort: 'Low',\n description: 'Include dateModified schema, visible last-updated dates, and time elements on content pages. Fresh content signals help AI engines prioritize your pages over stale alternatives.',\n },\n sitemap_completeness: {\n name: 'Create Complete Sitemap',\n effort: 'Low',\n description: 'Generate a comprehensive sitemap.xml with lastmod dates for all important pages. A complete sitemap ensures AI crawlers can discover and prioritize your full content library.',\n },\n rss_feed: {\n name: 'Deploy RSS/Atom Feed',\n effort: 'Low',\n description: 'Add an RSS or Atom feed linked from your homepage. Feeds signal active content publishing and give AI engines a structured way to track your latest content.',\n },\n table_list_extractability: {\n name: 'Add Structured Tables & Lists',\n effort: 'Medium',\n description: 'Use HTML tables for comparison data and ordered/unordered lists for features, steps, and specifications. Structured data formats are directly extractable by AI engines for answers.',\n },\n definition_patterns: {\n name: 'Add Definition-Style Content',\n effort: 'Low',\n description: 'Include clear definition patterns (\"X refers to...\", \"X is defined as...\") for key terms and concepts. Definition-style content is highly citable by AI engines answering \"what is\" queries.',\n },\n direct_answer_density: {\n name: 'Add Direct Answer Paragraphs',\n effort: 'Medium',\n description: 'Write concise, standalone answer paragraphs (2-3 sentences) immediately after question headings. These \"snippet-ready\" paragraphs are ideal for AI engine citations.',\n },\n content_licensing: {\n name: 'Add Content Licensing & ai.txt',\n effort: 'Low',\n description: 'Create an /ai.txt file specifying AI usage permissions and add license schema to your structured data. Clear licensing signals help AI engines understand how they can use your content.',\n },\n author_schema_depth: {\n name: 'Enhance Author & Expert Schema',\n effort: 'Low',\n description: 'Add Person schema for content authors with credentials, expertise, and sameAs links. Expert attribution strengthens E-E-A-T signals that AI engines use to evaluate source credibility.',\n },\n fact_density: {\n name: 'Increase Fact & Data Density',\n effort: 'Medium',\n description: 'Add specific numbers, percentages, statistics, and data points throughout your content. Fact-dense content gives AI engines concrete data to cite rather than vague claims.',\n },\n canonical_url: {\n name: 'Fix Canonical URL Strategy',\n effort: 'Low',\n description: 'Add rel=\"canonical\" tags to all pages pointing to the preferred URL version. Canonical URLs prevent duplicate content confusion and consolidate AI engine citations to a single authoritative URL.',\n },\n content_velocity: {\n name: 'Increase Publishing Frequency',\n effort: 'High',\n description: 'Establish a regular content publishing cadence with dated entries in your sitemap. Consistent publishing signals to AI engines that your site is an active, current information source.',\n },\n schema_coverage: {\n name: 'Deepen Schema Coverage',\n effort: 'Medium',\n description: 'Extend structured data beyond the homepage to inner pages (articles, services, products). Consistent schema coverage across your site helps AI engines understand your full content depth.',\n },\n speakable_schema: {\n name: 'Add Speakable Schema',\n effort: 'Low',\n description: 'Add SpeakableSpecification schema with CSS selectors pointing to key content sections. This tells voice assistants and AI engines which parts of your page are most suitable for spoken answers.',\n },\n};\n\n// ─── Impact calculation ──────────────────────────────────────────────────────\n\nfunction calculateImpact(score: number, weight: number, effort: string): ImpactLevel {\n const impactScore = (10 - score) * weight * 100;\n\n // Quick win override: low effort + meaningful impact\n if (effort === 'Low' && impactScore >= 3) return 'QUICK WIN';\n\n if (impactScore >= 12) return 'CRITICAL';\n if (impactScore >= 8) return 'HIGH';\n if (impactScore >= 5) return 'CORE AEO';\n if (impactScore >= 3) return 'MEDIUM';\n return 'LOW';\n}\n\n// ─── Verdict generation ──────────────────────────────────────────────────────\n\nexport function generateVerdict(\n score: number,\n scorecard: ScoreCardItem[],\n rawData: RawDataSummary,\n domain: string\n): string {\n // Score-tier opening\n let opening: string;\n if (score >= 86) {\n opening = `Excellent AEO implementation scoring ${score}/100.`;\n } else if (score >= 71) {\n opening = `Strong AEO fundamentals scoring ${score}/100 with room for optimization.`;\n } else if (score >= 56) {\n opening = `Moderate AEO readiness at ${score}/100 with significant gaps to address.`;\n } else if (score >= 41) {\n opening = `Below-average AEO readiness at ${score}/100 - multiple areas need attention.`;\n } else {\n opening = `Critical AEO gaps at ${score}/100 - ${domain} is largely invisible to AI engines.`;\n }\n\n // Top 3 strengths (score >= 8)\n const strengths = scorecard\n .filter(s => s.score >= 8)\n .sort((a, b) => b.score - a.score)\n .slice(0, 3);\n\n // Bottom 3 weaknesses (score <= 4)\n const weaknesses = scorecard\n .filter(s => s.score <= 4)\n .sort((a, b) => a.score - b.score)\n .slice(0, 3);\n\n const parts = [opening];\n\n if (strengths.length > 0) {\n const names = strengths.map(s => s.criterion);\n parts.push(`Key strengths include ${formatList(names)}.`);\n }\n\n if (weaknesses.length > 0) {\n const names = weaknesses.map(s => s.criterion);\n parts.push(`Priority gaps: ${formatList(names)}.`);\n }\n\n // Protocol note\n if (!rawData.has_https) {\n parts.push('HTTPS is not enabled, which caps several criteria scores and reduces AI crawler trust.');\n }\n\n // SPA rendering note\n if (rawData.rendered_with_headless) {\n parts.push('Note: this site uses client-side JavaScript rendering. AI crawlers see an empty page shell instead of content, which is the primary factor limiting the score.');\n }\n\n return parts.join(' ');\n}\n\n// ─── Opportunities generation ────────────────────────────────────────────────\n\nexport function generateOpportunities(\n scorecard: ScoreCardItem[],\n criterionResults: CriterionResult[]\n): Deliverable[] {\n const candidates: Array<{\n criterion: string;\n score: number;\n weight: number;\n impactScore: number;\n template: OpportunityTemplate;\n impact: ImpactLevel;\n }> = [];\n\n for (const result of criterionResults) {\n if (result.score > 7) continue; // Only generate opportunities for scores <= 7\n\n const weight = CRITERION_WEIGHTS[result.criterion] ?? 0.05;\n const template = OPPORTUNITY_TEMPLATES[result.criterion];\n if (!template) continue;\n\n const impactScore = (10 - result.score) * weight * 100;\n const impact = calculateImpact(result.score, weight, template.effort);\n\n candidates.push({\n criterion: result.criterion,\n score: result.score,\n weight,\n impactScore,\n template,\n impact,\n });\n }\n\n // Sort by impact score descending (highest impact first)\n candidates.sort((a, b) => b.impactScore - a.impactScore);\n\n // Take top 8-10\n const top = candidates.slice(0, 10);\n\n return top.map((c, i) => ({\n id: i + 1,\n name: c.template.name,\n description: c.template.description,\n effort: c.template.effort,\n impact: c.impact,\n }));\n}\n\n// ─── Pitch numbers generation ────────────────────────────────────────────────\n\nexport function generatePitchNumbers(\n score: number,\n rawData: RawDataSummary,\n scorecard: ScoreCardItem[]\n): PitchMetric[] {\n const metrics: PitchMetric[] = [];\n\n // 0. Rendering method (SPA warning - prepended so it appears first)\n if (rawData.rendered_with_headless) {\n metrics.push({\n metric: 'Rendering Method',\n value: 'Client-Side Only',\n significance: 'AI crawlers see empty HTML. All content loads via JavaScript, making this site invisible to ChatGPT, Claude, and Perplexity.',\n });\n }\n\n // 1. Overall AEO Score\n metrics.push({\n metric: 'AEO Score',\n value: `${score}/100`,\n significance: score >= 70\n ? 'Above average AI engine visibility'\n : score >= 50\n ? 'Moderate AI visibility with clear improvement paths'\n : 'Below average - significant optimization needed',\n });\n\n // 2. Schema types found\n const schemaCount = rawData.schema_types_found.length;\n metrics.push({\n metric: 'Schema Types',\n value: `${schemaCount} found`,\n significance: schemaCount >= 4\n ? 'Rich structured data helps AI engines parse content'\n : schemaCount >= 1\n ? 'Basic schema present but more types would improve AI extraction'\n : 'No structured data - AI engines cannot reliably extract content',\n });\n\n // 3. AI crawler readiness\n const aiCrawlerCount = rawData.robots_txt_ai_crawlers.length;\n const blockedCount = rawData.robots_txt_blocked_crawlers.length;\n metrics.push({\n metric: 'AI Crawler Access',\n value: blockedCount > 0\n ? `${blockedCount} blocked`\n : aiCrawlerCount > 0\n ? `${aiCrawlerCount} configured`\n : 'Not configured',\n significance: blockedCount > 0\n ? 'Active AI crawlers are blocked from accessing content'\n : aiCrawlerCount > 0\n ? 'robots.txt explicitly addresses AI crawler access'\n : 'No AI-specific crawler directives in robots.txt',\n });\n\n // 4. Content pages indexed\n const sitemapUrls = rawData.sitemap_url_count;\n metrics.push({\n metric: 'Sitemap URLs',\n value: sitemapUrls > 0 ? `${sitemapUrls} pages` : 'No sitemap',\n significance: sitemapUrls >= 50\n ? 'Comprehensive content library discoverable by AI crawlers'\n : sitemapUrls >= 10\n ? 'Moderate content footprint in sitemap'\n : sitemapUrls > 0\n ? 'Small sitemap - expanding content improves AI coverage'\n : 'No sitemap means AI crawlers must discover pages via links only',\n });\n\n // 5. Internal linking\n const linkCount = rawData.internal_link_count;\n metrics.push({\n metric: 'Internal Links',\n value: `${linkCount} links`,\n significance: linkCount >= 30\n ? 'Strong internal linking supports AI content discovery'\n : linkCount >= 10\n ? 'Moderate linking - adding more cross-references improves navigability'\n : 'Weak internal linking limits AI crawler depth',\n });\n\n // 6. Question headings\n const questionCount = rawData.question_headings_count + (rawData.blog_sample_question_headings || 0);\n if (questionCount > 0) {\n metrics.push({\n metric: 'Question Headings',\n value: `${questionCount} found`,\n significance: 'Question-based headings match how users query AI assistants',\n });\n }\n\n // 7. Criteria passing (>= 7)\n const passing = scorecard.filter(s => s.score >= 7).length;\n metrics.push({\n metric: 'Criteria Passing',\n value: `${passing}/23`,\n significance: passing >= 18\n ? 'Excellent coverage across AEO dimensions'\n : passing >= 12\n ? 'Good foundation with room to improve remaining criteria'\n : `${23 - passing} criteria need attention for full AI visibility`,\n });\n\n return metrics;\n}\n\n// ─── Bottom line generation ──────────────────────────────────────────────────\n\nexport function generateBottomLine(\n score: number,\n opportunities: Deliverable[],\n scorecard: ScoreCardItem[],\n domain: string\n): string {\n const quickWins = opportunities.filter(o => o.impact === 'QUICK WIN');\n const criticalOps = opportunities.filter(o => o.impact === 'CRITICAL' || o.impact === 'HIGH');\n\n const passing = scorecard.filter(s => s.score >= 7).length;\n const total = scorecard.length;\n\n let summary: string;\n if (score >= 86) {\n summary = `${domain} demonstrates excellent AI engine optimization with ${passing}/${total} criteria at good or strong levels. Focus on maintaining content freshness and expanding structured data coverage to stay ahead.`;\n } else if (score >= 71) {\n summary = `${domain} has a solid AEO foundation with ${passing}/${total} criteria passing.`;\n if (quickWins.length > 0) {\n summary += ` ${quickWins.length} quick wins available: ${quickWins.slice(0, 3).map(q => q.name).join(', ')}.`;\n }\n if (criticalOps.length > 0) {\n summary += ` Address ${criticalOps.length} high-impact opportunities to push the score above 85.`;\n }\n } else if (score >= 56) {\n summary = `${domain} has moderate AI visibility with ${passing}/${total} criteria passing. ${opportunities.length} improvement opportunities identified.`;\n if (quickWins.length > 0) {\n summary += ` Start with quick wins: ${quickWins.slice(0, 3).map(q => q.name).join(', ')}.`;\n }\n } else if (score >= 41) {\n summary = `${domain} needs significant AEO work with only ${passing}/${total} criteria passing.`;\n if (criticalOps.length > 0) {\n summary += ` Priority: ${criticalOps.slice(0, 3).map(c => c.name).join(', ')}.`;\n }\n summary += ` Implementing the top ${Math.min(5, opportunities.length)} recommendations could improve the score by 15-25 points.`;\n } else {\n summary = `${domain} is largely invisible to AI engines with only ${passing}/${total} criteria passing. Fundamental AEO infrastructure is missing.`;\n if (opportunities.length > 0) {\n summary += ` Start with: ${opportunities.slice(0, 3).map(o => o.name).join(', ')}.`;\n }\n summary += ` A comprehensive AEO implementation could transform AI visibility from near-zero to competitive.`;\n }\n\n return summary;\n}\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\nfunction formatList(items: string[]): string {\n if (items.length === 0) return '';\n if (items.length === 1) return items[0];\n if (items.length === 2) return `${items[0]} and ${items[1]}`;\n return `${items.slice(0, -1).join(', ')}, and ${items[items.length - 1]}`;\n}\n","/**\n * Extended page discovery for instant audit.\n * Fetches additional pages beyond what prefetchSiteData provides,\n * including nav-linked pages, common paths, and content pages from sitemap.\n */\n\nimport type { FetchResult, SiteData, PageCategory } from './site-crawler.js';\n\n// ─── Fetch helper (matches site-crawler.ts fetchText) ────────────────────────\n\nasync function fetchPage(url: string, timeoutMs = 10000): Promise<FetchResult | null> {\n try {\n const res = await fetch(url, {\n signal: AbortSignal.timeout(timeoutMs),\n headers: { 'User-Agent': 'AEO-Visibility-Bot/1.0' },\n redirect: 'follow',\n });\n if (res.status !== 200) return null;\n const text = await res.text();\n if (text.length < 200) return null; // Skip trivially small pages\n return { text: text.slice(0, 500000), status: res.status, finalUrl: res.url };\n } catch {\n return null;\n }\n}\n\n// ─── Page variant paths ──────────────────────────────────────────────────────\n\nconst PAGE_VARIANTS: Record<string, string[]> = {\n about: ['/about', '/about-us', '/company', '/who-we-are'],\n pricing: ['/pricing', '/plans', '/packages'],\n services: ['/services', '/features', '/solutions', '/products', '/what-we-do'],\n contact: ['/contact', '/contact-us', '/get-in-touch'],\n team: ['/team', '/our-team', '/authors', '/people', '/leadership'],\n resources: ['/resources', '/resource-center', '/library'],\n docs: ['/docs', '/documentation', '/help', '/help-center', '/support'],\n cases: ['/case-studies', '/customers', '/success-stories', '/testimonials'],\n};\n\n// ─── Nav link extraction ─────────────────────────────────────────────────────\n\n/**\n * Extract internal page paths from <nav> elements in homepage HTML.\n * Returns deduplicated absolute paths (e.g. ['/about', '/pricing']).\n */\nexport function extractNavLinks(html: string, domain: string): string[] {\n // Extract links from <nav> elements\n const navBlocks = html.match(/<nav[\\s\\S]*?<\\/nav>/gi) || [];\n const navHtml = navBlocks.join('\\n');\n\n const hrefMatches = navHtml.match(/href=\"([^\"#]*)\"/gi) || [];\n const paths = new Set<string>();\n\n const cleanDomain = domain.replace(/^www\\./, '').toLowerCase();\n\n for (const match of hrefMatches) {\n const href = match.match(/href=\"([^\"#]*)\"/i)?.[1];\n if (!href) continue;\n\n let path: string;\n if (href.startsWith('/')) {\n path = href;\n } else if (href.startsWith('http')) {\n try {\n const url = new URL(href);\n const linkDomain = url.hostname.replace(/^www\\./, '').toLowerCase();\n if (linkDomain !== cleanDomain) continue;\n path = url.pathname;\n } catch {\n continue;\n }\n } else {\n continue;\n }\n\n // Normalize: strip trailing slash, skip root and fragments\n path = path.replace(/\\/+$/, '') || '/';\n if (path === '/') continue;\n if (path.includes('#')) continue;\n\n // Skip resource/utility paths\n if (/\\.(js|css|png|jpg|svg|ico|pdf|xml|txt)$/i.test(path)) continue;\n if (/^\\/(api|wp-|static|assets|_next|auth|login|signup|cart|checkout)\\b/i.test(path)) continue;\n\n paths.add(path);\n }\n\n return Array.from(paths);\n}\n\n// ─── Content page extraction from sitemap ────────────────────────────────────\n\n/**\n * Extract non-blog deep content pages from sitemap XML.\n * Targets service pages, product pages, etc. (not blog/article posts).\n */\nexport function extractContentPagesFromSitemap(\n sitemapText: string,\n domain: string,\n limit = 6\n): string[] {\n const urlBlocks = sitemapText.match(/<url>([\\s\\S]*?)<\\/url>/gi) || [];\n const cleanDomain = domain.replace(/^www\\./, '').toLowerCase();\n const candidates: string[] = [];\n\n // Paths to skip (already covered by blog sample or common pages)\n const skipPatterns = /\\/(?:blog|articles?|posts?|news|tag|category|author|feed|faq|about|pricing|contact|team|resources?|docs?|documentation|help|support|case-studies|customers|testimonials|sitemap|wp-|api|login|cart|checkout|search)\\b/i;\n\n for (const block of urlBlocks) {\n const locMatch = block.match(/<loc>([^<]+)<\\/loc>/i);\n if (!locMatch) continue;\n const url = locMatch[1].trim();\n\n try {\n const parsed = new URL(url);\n const urlDomain = parsed.hostname.replace(/^www\\./, '').toLowerCase();\n if (urlDomain !== cleanDomain) continue;\n\n if (parsed.pathname === '/' || parsed.pathname === '') continue;\n\n const path = parsed.pathname.toLowerCase();\n if (skipPatterns.test(path)) continue;\n\n // Want pages with 1-2 path segments (service pages, product pages)\n const segments = path.split('/').filter(Boolean);\n if (segments.length < 1 || segments.length > 3) continue;\n\n candidates.push(url);\n } catch {\n continue;\n }\n }\n\n // Return evenly spaced pages from the list for variety\n if (candidates.length <= limit) return candidates;\n\n const result: string[] = [];\n for (let i = 0; i < limit; i++) {\n const index = Math.round(i * (candidates.length - 1) / (limit - 1));\n result.push(candidates[index]);\n }\n return result;\n}\n\n// ─── Main multi-page fetcher ─────────────────────────────────────────────────\n\nexport interface MultiPageOptions {\n timeoutMs?: number;\n}\n\n/**\n * Fetch additional pages beyond what prefetchSiteData provides.\n * Discovers pages from nav links + common path variants + sitemap content pages.\n * All fetched pages are appended to siteData.blogSample so existing\n * getCombinedHtml() and criteria checks pick them up automatically.\n *\n * Mutates siteData in place and returns the count of new pages added.\n */\nexport async function fetchMultiPageData(\n siteData: SiteData,\n options?: MultiPageOptions\n): Promise<number> {\n if (!siteData.protocol || !siteData.homepage) return 0;\n\n const timeoutMs = options?.timeoutMs ?? 10000;\n const baseUrl = `${siteData.protocol}://${siteData.domain}`;\n const existingUrls = new Set<string>();\n\n // Track already-fetched URLs\n existingUrls.add(baseUrl + '/');\n existingUrls.add(baseUrl);\n if (siteData.blogSample) {\n for (const page of siteData.blogSample) {\n if (page.finalUrl) existingUrls.add(page.finalUrl);\n }\n }\n\n // Collect candidate URLs to fetch (URL -> category)\n const urlsToFetch = new Map<string, PageCategory>();\n\n // Source 1: Nav links from homepage\n const navPaths = extractNavLinks(siteData.homepage.text, siteData.domain);\n\n // Source 2: Common page variants (try nav links first, then fallback paths)\n for (const [category, variants] of Object.entries(PAGE_VARIANTS)) {\n // Check if any nav link matches this category\n const navMatch = navPaths.find(p =>\n variants.some(v => p.toLowerCase() === v || p.toLowerCase().startsWith(v + '/'))\n );\n\n if (navMatch) {\n const url = `${baseUrl}${navMatch}`;\n if (!existingUrls.has(url)) urlsToFetch.set(url, category as PageCategory);\n } else {\n // Try first variant as fallback\n const url = `${baseUrl}${variants[0]}`;\n if (!existingUrls.has(url)) urlsToFetch.set(url, category as PageCategory);\n }\n }\n\n // Source 3: Content pages from sitemap\n if (siteData.sitemapXml && siteData.sitemapXml.status === 200) {\n const contentUrls = extractContentPagesFromSitemap(\n siteData.sitemapXml.text,\n siteData.domain,\n 6\n );\n for (const url of contentUrls) {\n if (!existingUrls.has(url)) urlsToFetch.set(url, 'content');\n }\n }\n\n // Fetch all URLs in parallel\n const entries = Array.from(urlsToFetch.entries());\n if (entries.length === 0) return 0;\n\n const results = await Promise.all(entries.map(([url]) => fetchPage(url, timeoutMs)));\n\n // Append successful results to blogSample with category tags\n if (!siteData.blogSample) siteData.blogSample = [];\n\n let added = 0;\n for (let i = 0; i < results.length; i++) {\n const result = results[i];\n if (result && result.text.length > 500) {\n result.category = entries[i][1];\n siteData.blogSample.push(result);\n added++;\n }\n }\n\n return added;\n}\n","/**\n * Per-page analysis for instant audit.\n * Runs 12 deterministic checks on each crawled page (no LLM).\n */\n\nimport type { PageCategory, SiteData } from './site-crawler.js';\n\n// ─── Types ──────────────────────────────────────────────────────────────────\n\nexport interface PageIssue {\n check: string;\n label: string;\n severity: 'error' | 'warning' | 'info';\n}\n\nexport interface PageReview {\n url: string;\n title: string;\n category: PageCategory;\n wordCount: number;\n issues: PageIssue[];\n strengths: PageIssue[];\n}\n\n// ─── Helpers ────────────────────────────────────────────────────────────────\n\nfunction extractTitle(html: string): string {\n const match = html.match(/<title[^>]*>([\\s\\S]*?)<\\/title>/i);\n return match ? match[1].replace(/\\s+/g, ' ').trim() : '';\n}\n\nfunction getTextContent(html: string): string {\n return html\n .replace(/<script[\\s\\S]*?<\\/script>/gi, '')\n .replace(/<style[\\s\\S]*?<\\/style>/gi, '')\n .replace(/<[^>]*>/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim();\n}\n\nfunction countWords(text: string): number {\n if (!text) return 0;\n return text.split(/\\s+/).filter(w => w.length > 0).length;\n}\n\n// ─── Individual checks ──────────────────────────────────────────────────────\n\nfunction checkMissingTitle(html: string): PageIssue | null {\n const hasTitle = /<title[^>]*>[\\s\\S]*?<\\/title>/i.test(html);\n if (!hasTitle) {\n return { check: 'missing-title', label: 'Missing <title> tag', severity: 'error' };\n }\n const title = extractTitle(html);\n if (!title) {\n return { check: 'missing-title', label: 'Empty <title> tag', severity: 'error' };\n }\n return null;\n}\n\nfunction checkMissingMetaDescription(html: string): PageIssue | null {\n const hasDesc = /<meta\\s[^>]*name=[\"']description[\"'][^>]*content=[\"'][^\"']+[\"']/i.test(html)\n || /<meta\\s[^>]*content=[\"'][^\"']+[\"'][^>]*name=[\"']description[\"']/i.test(html);\n if (!hasDesc) {\n return { check: 'missing-meta-description', label: 'Missing meta description', severity: 'error' };\n }\n return null;\n}\n\nfunction checkNoH1(html: string): PageIssue | null {\n const h1Matches = html.match(/<h1[\\s>]/gi);\n if (!h1Matches || h1Matches.length === 0) {\n return { check: 'no-h1', label: 'No <h1> tag', severity: 'error' };\n }\n return null;\n}\n\nfunction checkMultipleH1(html: string): PageIssue | null {\n const h1Matches = html.match(/<h1[\\s>]/gi);\n if (h1Matches && h1Matches.length > 1) {\n return { check: 'multiple-h1', label: `Multiple <h1> tags (${h1Matches.length})`, severity: 'warning' };\n }\n return null;\n}\n\nfunction checkNoSchema(html: string): PageIssue | null {\n const hasLdJson = /<script[^>]*type=[\"']application\\/ld\\+json[\"'][^>]*>/i.test(html);\n if (!hasLdJson) {\n return { check: 'no-schema', label: 'No JSON-LD structured data', severity: 'warning' };\n }\n return null;\n}\n\nfunction checkMissingCanonical(html: string): PageIssue | null {\n const hasCanonical = /<link[^>]*rel=[\"']canonical[\"'][^>]*>/i.test(html);\n if (!hasCanonical) {\n return { check: 'missing-canonical', label: 'Missing canonical link', severity: 'warning' };\n }\n return null;\n}\n\nfunction checkMissingOgTags(html: string): PageIssue | null {\n const hasOg = /<meta\\s[^>]*property=[\"']og:/i.test(html);\n if (!hasOg) {\n return { check: 'missing-og-tags', label: 'No Open Graph tags', severity: 'warning' };\n }\n return null;\n}\n\nfunction checkThinContent(wordCount: number): PageIssue | null {\n if (wordCount < 300) {\n return { check: 'thin-content', label: `Thin content (${wordCount} words)`, severity: 'warning' };\n }\n return null;\n}\n\nfunction checkImagesMissingAlt(html: string): PageIssue | null {\n const imgTags = html.match(/<img\\s[^>]*>/gi) || [];\n if (imgTags.length === 0) return null;\n\n let missingAlt = 0;\n for (const img of imgTags) {\n const hasAlt = /\\salt=[\"'][^\"']+[\"']/i.test(img);\n const hasEmptyAlt = /\\salt=[\"'][\"']/i.test(img); // decorative\n if (!hasAlt && !hasEmptyAlt) missingAlt++;\n }\n\n if (missingAlt > 0) {\n return {\n check: 'images-missing-alt',\n label: `${missingAlt} image${missingAlt > 1 ? 's' : ''} missing alt text`,\n severity: 'warning',\n };\n }\n return null;\n}\n\nfunction checkNoInternalLinks(html: string, url: string): PageIssue | null {\n let domain: string;\n try {\n domain = new URL(url).hostname.replace(/^www\\./, '').toLowerCase();\n } catch {\n return null;\n }\n\n const links = html.match(/<a\\s[^>]*href=[\"']([^\"'#]*?)[\"'][^>]*>/gi) || [];\n let internalCount = 0;\n\n for (const link of links) {\n const hrefMatch = link.match(/href=[\"']([^\"'#]*?)[\"']/i);\n if (!hrefMatch) continue;\n const href = hrefMatch[1];\n\n if (href.startsWith('/') && !href.startsWith('//')) {\n internalCount++;\n } else if (href.startsWith('http')) {\n try {\n const linkDomain = new URL(href).hostname.replace(/^www\\./, '').toLowerCase();\n if (linkDomain === domain) internalCount++;\n } catch {\n // skip\n }\n }\n }\n\n if (internalCount === 0) {\n return { check: 'no-internal-links', label: 'No internal links found', severity: 'warning' };\n }\n return null;\n}\n\n// ─── Strength checks ────────────────────────────────────────────────────────\n\nfunction checkHasStructuredData(html: string): PageIssue | null {\n const ldBlocks = html.match(/<script[^>]*type=[\"']application\\/ld\\+json[\"'][^>]*>([\\s\\S]*?)<\\/script>/gi) || [];\n if (ldBlocks.length === 0) return null;\n\n const types = new Set<string>();\n for (const block of ldBlocks) {\n const content = block.replace(/<\\/?script[^>]*>/gi, '');\n const typeMatches = content.match(/\"@type\"\\s*:\\s*\"([^\"]+)\"/g) || [];\n for (const m of typeMatches) {\n const t = m.match(/\"@type\"\\s*:\\s*\"([^\"]+)\"/);\n if (t) types.add(t[1]);\n }\n }\n\n if (types.size > 0) {\n return {\n check: 'has-structured-data',\n label: `JSON-LD: ${Array.from(types).join(', ')}`,\n severity: 'info',\n };\n }\n return null;\n}\n\nfunction checkHasQuestionHeadings(html: string): PageIssue | null {\n const headings = html.match(/<h[2-4][^>]*>[\\s\\S]*?<\\/h[2-4]>/gi) || [];\n let questionCount = 0;\n\n for (const h of headings) {\n const text = h.replace(/<[^>]*>/g, '').trim();\n if (/\\?$/.test(text) || /^(what|how|why|when|where|who|which|can|do|does|is|are|should|will)\\b/i.test(text)) {\n questionCount++;\n }\n }\n\n if (questionCount > 0) {\n return {\n check: 'has-question-headings',\n label: `${questionCount} question-format heading${questionCount > 1 ? 's' : ''}`,\n severity: 'info',\n };\n }\n return null;\n}\n\n// ─── Main analyzers ─────────────────────────────────────────────────────────\n\nexport function analyzePage(html: string, url: string, category: PageCategory): PageReview {\n const title = extractTitle(html);\n const textContent = getTextContent(html);\n const wordCount = countWords(textContent);\n\n const issues: PageIssue[] = [];\n const strengths: PageIssue[] = [];\n\n // Issue checks\n const issueChecks = [\n checkMissingTitle(html),\n checkMissingMetaDescription(html),\n checkNoH1(html),\n checkMultipleH1(html),\n checkNoSchema(html),\n checkMissingCanonical(html),\n checkMissingOgTags(html),\n checkThinContent(wordCount),\n checkImagesMissingAlt(html),\n checkNoInternalLinks(html, url),\n ];\n\n for (const result of issueChecks) {\n if (result) issues.push(result);\n }\n\n // Strength checks\n const strengthChecks = [\n checkHasStructuredData(html),\n checkHasQuestionHeadings(html),\n ];\n\n for (const result of strengthChecks) {\n if (result) strengths.push(result);\n }\n\n return { url, title, category, wordCount, issues, strengths };\n}\n\nexport function analyzeAllPages(siteData: SiteData): PageReview[] {\n const reviews: PageReview[] = [];\n\n // Analyze homepage\n if (siteData.homepage) {\n const url = `${siteData.protocol}://${siteData.domain}`;\n reviews.push(analyzePage(siteData.homepage.text, url, siteData.homepage.category || 'homepage'));\n }\n\n // Analyze all pages in blogSample\n if (siteData.blogSample) {\n for (const page of siteData.blogSample) {\n const url = page.finalUrl || 'unknown';\n reviews.push(analyzePage(page.text, url, page.category || 'content'));\n }\n }\n\n return reviews;\n}\n","/**\n * Programmatic audit API.\n * Runs the full 7-phase AEO audit pipeline and returns structured results.\n */\n\nimport { prefetchSiteData, auditSiteFromData, extractRawDataSummary } from './site-crawler.js';\nimport { calculateOverallScore } from './scoring.js';\nimport { isSpaShell, fetchWithHeadless, classifyRendering } from './headless-fetch.js';\nimport { buildScorecard, buildDetailedFindings } from './scorecard-builder.js';\nimport { generateVerdict, generateOpportunities, generatePitchNumbers, generateBottomLine } from './narrative-generator.js';\nimport { fetchMultiPageData } from './multi-page-fetcher.js';\nimport { analyzeAllPages } from './page-analyzer.js';\nimport type { AuditData } from './types.js';\n\nexport interface AuditOptions {\n /** Skip Puppeteer SPA rendering (default: false) */\n noHeadless?: boolean;\n /** Homepage + blog only, skip extra page discovery (default: false) */\n noMultiPage?: boolean;\n /** Fetch timeout in ms (default: 15000) */\n timeout?: number;\n}\n\nexport interface AuditResult extends AuditData {\n /** True if headless browser was used for SPA rendering */\n renderedWithHeadless?: boolean;\n /** Wall-clock seconds */\n elapsed: number;\n}\n\nfunction getTextLength(html: string): number {\n return html\n .replace(/<script[\\s\\S]*?<\\/script>/gi, '')\n .replace(/<style[\\s\\S]*?<\\/style>/gi, '')\n .replace(/<[^>]*>/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim().length;\n}\n\n/**\n * Run a complete AEO audit on a domain.\n *\n * @example\n * ```ts\n * import { audit } from 'aeorank';\n * const result = await audit('example.com');\n * console.log(result.overallScore); // 0-100\n * ```\n */\nexport async function audit(domain: string, options?: AuditOptions): Promise<AuditResult> {\n const startTime = Date.now();\n let renderedWithHeadless = false;\n\n // Phase 1: Fetch site data\n const siteData = await prefetchSiteData(domain);\n\n if (!siteData.protocol) {\n throw new Error(`Could not connect to ${domain} (no HTTPS or HTTP response)`);\n }\n\n if (siteData.redirectedTo) {\n throw new Error(`${domain} redirects to ${siteData.redirectedTo} (hijacked domain)`);\n }\n\n if (siteData.parkedReason) {\n throw new Error(`${domain} is a parked/lost domain (${siteData.parkedReason})`);\n }\n\n // Phase 2: SPA detection + headless rendering\n if (!options?.noHeadless && siteData.homepage && isSpaShell(siteData.homepage.text)) {\n const rawTextLen = getTextLength(siteData.homepage.text);\n const url = `${siteData.protocol}://${domain}`;\n const rendered = await fetchWithHeadless(url);\n\n if (rendered) {\n const renderedTextLen = getTextLength(rendered.text);\n if (renderedTextLen > rawTextLen) {\n siteData.homepage = rendered;\n renderedWithHeadless = true;\n }\n }\n\n if (renderedWithHeadless && siteData.faqPage && isSpaShell(siteData.faqPage.text)) {\n const faqUrl = `${siteData.protocol}://${domain}/faq`;\n const renderedFaq = await fetchWithHeadless(faqUrl);\n if (renderedFaq && getTextLength(renderedFaq.text) > getTextLength(siteData.faqPage.text)) {\n siteData.faqPage = renderedFaq;\n }\n }\n }\n\n // Phase 3: Multi-page discovery\n if (!options?.noMultiPage) {\n await fetchMultiPageData(siteData);\n }\n\n // Phase 4: Score all 23 criteria\n const results = auditSiteFromData(siteData);\n const overallScore = calculateOverallScore(results);\n const rawData = extractRawDataSummary(siteData);\n if (renderedWithHeadless) rawData.rendered_with_headless = true;\n\n // Phase 5: Build scorecard + detailed findings\n const scorecard = buildScorecard(results);\n const detailedFindings = buildDetailedFindings(results);\n\n // Phase 6: Generate narrative\n const verdict = generateVerdict(overallScore, scorecard, rawData, domain);\n const opportunities = generateOpportunities(scorecard, results);\n const pitchNumbers = generatePitchNumbers(overallScore, rawData, scorecard);\n const bottomLine = generateBottomLine(overallScore, opportunities, scorecard, domain);\n\n // Phase 7: Per-page analysis\n const pagesReviewed = analyzeAllPages(siteData);\n\n const elapsed = Math.round((Date.now() - startTime) / 100) / 10;\n\n return {\n site: domain,\n auditDate: new Date().toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' }),\n auditor: 'AEORank',\n engine: 'instant',\n overallScore,\n verdict,\n scorecard,\n detailedFindings,\n opportunities,\n pitchNumbers,\n bottomLine,\n pagesReviewed,\n elapsed,\n ...(renderedWithHeadless && { renderedWithHeadless: true }),\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACWA,IAAM,gBAAgB,CAAC,WAAW,YAAY,SAAS,cAAc;AAGrE,IAAM,0BAA0B;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGA,IAAM,wBAAwB;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,SAAS,sBAAsB,aAAoC;AACjE,QAAM,mBAAmB,YAAY;AAAA,IACnC;AAAA,EACF;AACA,MAAI,CAAC,iBAAkB,QAAO;AAC9B,QAAM,OAAO,iBAAiB,CAAC,EAAE,YAAY,EAAE,QAAQ,UAAU,EAAE;AACnE,MAAI,cAAc,SAAS,IAAI,GAAG;AAChC,WAAO,kBAAkB,iBAAiB,CAAC,CAAC;AAAA,EAC9C;AACA,SAAO;AACT;AAEA,SAAS,qBAAqB,aAAoC;AAChE,QAAM,QAAQ,YAAY,YAAY;AACtC,aAAW,WAAW,yBAAyB;AAC7C,QAAI,MAAM,SAAS,OAAO,GAAG;AAC3B,aAAO,oBAAoB,OAAO;AAAA,IACpC;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,kBAAkB,aAAoC;AAC7D,aAAW,WAAW,uBAAuB;AAC3C,QAAI,QAAQ,KAAK,WAAW,GAAG;AAC7B,aAAO,iBAAiB,YAAY,MAAM,OAAO,IAAI,CAAC,CAAC;AAAA,IACzD;AAAA,EACF;AACA,SAAO;AACT;AAMO,SAAS,mBAAmB,aAAyC;AAC1E,QAAM,kBAAkB,sBAAsB,WAAW;AACzD,MAAI,gBAAiB,QAAO,EAAE,UAAU,MAAM,QAAQ,gBAAgB;AAEtE,QAAM,iBAAiB,qBAAqB,WAAW;AACvD,MAAI,eAAgB,QAAO,EAAE,UAAU,MAAM,QAAQ,eAAe;AAEpE,QAAM,cAAc,kBAAkB,WAAW;AACjD,MAAI,YAAa,QAAO,EAAE,UAAU,MAAM,QAAQ,YAAY;AAE9D,SAAO,EAAE,UAAU,MAAM;AAC3B;;;ACaA,eAAe,UAAU,KAA0C;AACjE,MAAI;AACF,UAAM,MAAM,MAAM,MAAM,KAAK;AAAA,MAC3B,QAAQ,YAAY,QAAQ,IAAK;AAAA,MACjC,SAAS,EAAE,cAAc,yBAAyB;AAAA,MAClD,UAAU;AAAA,IACZ,CAAC;AACD,UAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,WAAO,EAAE,MAAM,KAAK,MAAM,GAAG,GAAM,GAAG,QAAQ,IAAI,QAAQ,UAAU,IAAI,IAAI;AAAA,EAC9E,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGA,SAAS,cAAc,KAAqB;AAC1C,SAAO,IAAI,QAAQ,gBAAgB,EAAE,EAAE,QAAQ,QAAQ,EAAE,EAAE,QAAQ,YAAY,EAAE,EAAE,QAAQ,UAAU,EAAE,EAAE,YAAY;AACvH;AAGA,SAAS,iBAAiB,QAAwB;AAChD,QAAM,QAAQ,OAAO,MAAM,GAAG;AAC9B,QAAM,cAAc,CAAC,SAAS,UAAU,SAAS,UAAU,SAAS,OAAO;AAC3E,QAAM,UAAU,MAAM,MAAM,EAAE,EAAE,KAAK,GAAG;AACxC,MAAI,YAAY,SAAS,OAAO,KAAK,MAAM,SAAS,GAAG;AACrD,WAAO,MAAM,MAAM,GAAG,EAAE,EAAE,KAAK,GAAG;AAAA,EACpC;AACA,SAAO,MAAM,SAAS,IAAI,MAAM,MAAM,GAAG,EAAE,EAAE,KAAK,GAAG,IAAI;AAC3D;AAGA,SAAS,0BAA0B,gBAAwB,UAAsC;AAC/F,MAAI,CAAC,SAAS,SAAU,QAAO;AAC/B,QAAM,cAAc,cAAc,SAAS,QAAQ;AACnD,QAAM,gBAAgB,eAAe,QAAQ,UAAU,EAAE,EAAE,YAAY;AACvE,MACE,gBAAgB,iBAChB,gBAAgB,OAAO,aAAa,MACpC,iBAAiB,WAAW,MAAM,iBAAiB,aAAa,GAChE;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAGA,SAAS,iBAAiB,aAAqB,gBAAuC;AACpF,QAAM,UAAU,YAAY;AAAA,IAC1B;AAAA,EACF;AACA,MAAI,CAAC,QAAS,QAAO;AACrB,QAAM,WAAW,cAAc,aAAa,QAAQ,CAAC,CAAC;AACtD,QAAM,gBAAgB,eAAe,QAAQ,UAAU,EAAE,EAAE,YAAY;AACvE,MACE,aAAa,iBACb,aAAa,OAAO,aAAa,MACjC,iBAAiB,QAAQ,MAAM,iBAAiB,aAAa,GAC7D;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAGA,SAAS,eAAe,QAAqC;AAC3D,MAAI,CAAC,UAAU,OAAO,WAAW,IAAK,QAAO;AAC7C,QAAM,UAAU,OAAO,KAAK,UAAU,EAAE,MAAM,GAAG,GAAG,EAAE,YAAY;AAClE,SAAO,QAAQ,WAAW,gBAAgB,KAAK,QAAQ,WAAW,OAAO,KAAK,cAAc,KAAK,OAAO;AAC1G;AAMA,eAAsB,iBAAiB,QAAmC;AAExE,MAAI,WAAoC;AACxC,MAAI,WAA+B;AAEnC,aAAW,MAAM,UAAU,WAAW,MAAM,EAAE;AAC9C,MAAI,YAAY,SAAS,UAAU,OAAO,SAAS,SAAS,KAAK;AAC/D,eAAW;AAAA,EACb,OAAO;AACL,eAAW,MAAM,UAAU,UAAU,MAAM,EAAE;AAC7C,QAAI,YAAY,SAAS,UAAU,OAAO,SAAS,SAAS,KAAK;AAC/D,iBAAW;AAAA,IACb;AAAA,EACF;AAEA,MAAI,CAAC,UAAU;AACb,WAAO,EAAE,QAAQ,UAAU,MAAM,UAAU,MAAM,SAAS,MAAM,WAAW,MAAM,SAAS,MAAM,YAAY,MAAM,SAAS,MAAM,OAAO,MAAM,cAAc,MAAM,cAAc,MAAM,YAAY,CAAC,EAAE;AAAA,EACvM;AAGA,QAAM,eAAe,WAAW,0BAA0B,QAAQ,QAAQ,IAAI;AAC9E,QAAM,aAAa,WAAW,iBAAiB,SAAS,KAAK,MAAM,GAAG,IAAI,GAAG,MAAM,IAAI;AACvF,QAAM,eAAe,gBAAgB;AAErC,MAAI,cAAc;AAChB,WAAO,EAAE,QAAQ,UAAU,UAAU,SAAS,MAAM,WAAW,MAAM,SAAS,MAAM,YAAY,MAAM,SAAS,MAAM,OAAO,MAAM,cAAc,cAAc,MAAM,YAAY,CAAC,EAAE;AAAA,EACrL;AAGA,QAAM,eAAe,WAAW,mBAAmB,SAAS,KAAK,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,UAAU,MAAM;AACrG,MAAI,aAAa,UAAU;AACzB,WAAO,EAAE,QAAQ,UAAU,UAAU,SAAS,MAAM,WAAW,MAAM,SAAS,MAAM,YAAY,MAAM,SAAS,MAAM,OAAO,MAAM,cAAc,MAAM,cAAc,aAAa,UAAU,UAAU,YAAY,CAAC,EAAE;AAAA,EACtN;AAEA,QAAM,UAAU,GAAG,QAAQ,MAAM,MAAM;AAGvC,QAAM,CAAC,SAAS,WAAW,SAAS,YAAY,KAAK,IAAI,MAAM,QAAQ,IAAI;AAAA,IACzE,UAAU,GAAG,OAAO,WAAW;AAAA,IAC/B,UAAU,GAAG,OAAO,aAAa;AAAA,IACjC,UAAU,GAAG,OAAO,MAAM,EAAE,KAAK,OAAO,WAAW;AACjD,UAAI,UAAU,OAAO,WAAW,IAAK,QAAO;AAE5C,iBAAW,QAAQ,CAAC,+BAA+B,SAAS,YAAY,cAAc,GAAG;AACvF,cAAM,WAAW,MAAM,UAAU,GAAG,OAAO,GAAG,IAAI,EAAE;AACpD,YAAI,YAAY,SAAS,WAAW,IAAK,QAAO;AAAA,MAClD;AACA,aAAO;AAAA,IACT,CAAC;AAAA,IACD,UAAU,GAAG,OAAO,cAAc;AAAA,IAClC,UAAU,GAAG,OAAO,SAAS;AAAA,EAC/B,CAAC;AAGD,MAAI,UAA8B;AAClC,MAAI,UAAU;AACZ,UAAM,eAAe,SAAS,KAAK,MAAM,2EAA2E;AACpH,QAAI,cAAc;AAChB,YAAM,SAAS,aAAa,CAAC,EAAE,WAAW,MAAM,IAAI,aAAa,CAAC,IAAI,GAAG,OAAO,GAAG,aAAa,CAAC,CAAC;AAClG,gBAAU,MAAM,UAAU,MAAM;AAAA,IAClC;AACA,QAAI,CAAC,WAAW,QAAQ,WAAW,KAAK;AAEtC,iBAAW,QAAQ,CAAC,SAAS,YAAY,WAAW,GAAG;AACrD,kBAAU,MAAM,UAAU,GAAG,OAAO,GAAG,IAAI,EAAE;AAC7C,YAAI,WAAW,QAAQ,WAAW,QAAQ,QAAQ,KAAK,SAAS,MAAM,KAAK,QAAQ,KAAK,SAAS,OAAO,KAAK,QAAQ,KAAK,SAAS,UAAU,GAAI;AACjJ,kBAAU;AAAA,MACZ;AAAA,IACF;AAAA,EACF;AAGA,MAAI,aAA4B,CAAC;AACjC,MAAI,cAAc,WAAW,WAAW,KAAK;AAC3C,QAAI,iBAAiB,WAAW;AAGhC,UAAM,gBAAgB,qBAAqB,cAAc;AACzD,QAAI,eAAe;AACjB,YAAM,aAAa,MAAM,UAAU,aAAa;AAChD,UAAI,cAAc,WAAW,WAAW,KAAK;AAC3C,yBAAiB,WAAW;AAAA,MAC9B;AAAA,IACF;AAEA,UAAM,WAAW,2BAA2B,gBAAgB,QAAQ,EAAE;AACtE,QAAI,SAAS,SAAS,GAAG;AACvB,YAAM,UAAU,MAAM,QAAQ,IAAI,SAAS,IAAI,SAAO,UAAU,GAAG,CAAC,CAAC;AACrE,mBAAa,QAAQ;AAAA,QAAO,CAAC,MAC3B,MAAM,QAAQ,EAAE,WAAW,OAAO,EAAE,KAAK,SAAS;AAAA,MACpD;AAEA,iBAAW,QAAQ,YAAY;AAC7B,aAAK,WAAW;AAAA,MAClB;AAAA,IACF;AAAA,EACF;AAGA,MAAI,SAAU,UAAS,WAAW;AAElC,SAAO,EAAE,QAAQ,UAAU,UAAU,SAAS,WAAW,SAAS,YAAY,SAAS,OAAO,cAAc,MAAM,cAAc,MAAM,WAAW;AACnJ;AAKA,SAAS,gBAAgB,MAAwB;AAC/C,QAAM,QAAQ,CAAC,KAAK,UAAU,QAAQ,EAAE;AACxC,MAAI,KAAK,YAAY;AACnB,eAAW,QAAQ,KAAK,YAAY;AAClC,YAAM,KAAK,KAAK,IAAI;AAAA,IACtB;AAAA,EACF;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;AAGA,SAAS,YAAY,MAAwB;AAC3C,MAAI,CAAC,KAAK,cAAc,KAAK,WAAW,WAAW,EAAG,QAAO;AAC7D,SAAO,KAAK,WAAW,IAAI,OAAK,EAAE,IAAI,EAAE,KAAK,IAAI;AACnD;AAKA,SAAS,aAAa,MAAiC;AACrD,QAAM,WAA2B,CAAC;AAClC,QAAM,SAAS,KAAK;AAEpB,MAAI,CAAC,UAAU,OAAO,WAAW,OAAO,eAAe,MAAM,GAAG;AAC9D,UAAM,aAAa,SAAU,eAAe,MAAM,IAAI,6CAA6C,QAAQ,OAAO,MAAM,KAAM;AAC9H,aAAS,KAAK,EAAE,UAAU,YAAY,QAAQ,6BAA6B,KAAK,QAAQ,MAAM,KAAK,MAAM,cAAc,UAAU,KAAK,KAAK,+FAA+F,CAAC;AAC3O,WAAO,EAAE,WAAW,YAAY,iBAAiB,iBAAiB,OAAO,GAAG,QAAQ,QAAQ,UAAU,cAAc,KAAK;AAAA,EAC3H;AAEA,QAAM,OAAO,OAAO;AACpB,MAAI,QAAQ;AAEZ,MAAI,KAAK,SAAS,KAAK;AACrB,aAAS,KAAK,EAAE,UAAU,UAAU,QAAQ,sCAAsC,KAAK,MAAM,gBAAgB,KAAK,wEAAwE,CAAC;AAAA,EAC7L,OAAO;AACL,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,wBAAwB,KAAK,MAAM,eAAe,CAAC;AAAA,EAC/F;AAEA,MAAI,KAAK,SAAS,GAAG,KAAK,KAAK,SAAS,IAAI,GAAG;AAC7C,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,gDAAgD,CAAC;AAAA,EAC7F,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,qCAAqC,KAAK,mEAAmE,CAAC;AAAA,EACzJ;AAEA,MAAI,cAAc,KAAK,IAAI,GAAG;AAC5B,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,sCAAsC,CAAC;AAAA,EACnF,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,UAAU,QAAQ,uCAAuC,KAAK,+DAA+D,CAAC;AAAA,EAC1J;AAEA,SAAO,EAAE,WAAW,YAAY,iBAAiB,iBAAiB,OAAO,KAAK,IAAI,IAAI,KAAK,GAAG,QAAQ,SAAS,IAAI,SAAS,WAAW,UAAU,cAAc,SAAS,IAAI,OAAO,KAAK;AAC1L;AAGA,SAAS,kBAAkB,MAAiC;AAC1D,QAAM,WAA2B,CAAC;AAElC,MAAI,CAAC,KAAK,UAAU;AAClB,aAAS,KAAK,EAAE,UAAU,YAAY,QAAQ,kDAAkD,CAAC;AACjG,WAAO,EAAE,WAAW,iBAAiB,iBAAiB,8BAA8B,OAAO,GAAG,QAAQ,aAAa,UAAU,cAAc,KAAK;AAAA,EAClJ;AAEA,QAAM,OAAO,KAAK,SAAS;AAC3B,QAAM,gBAAgB,KAAK,MAAM,sEAAsE,KAAK,CAAC;AAC7G,MAAI,QAAQ;AAEZ,MAAI,cAAc,WAAW,GAAG;AAC9B,aAAS,KAAK,EAAE,UAAU,YAAY,QAAQ,gDAAgD,KAAK,kGAAkG,CAAC;AACtM,WAAO,EAAE,WAAW,iBAAiB,iBAAiB,8BAA8B,OAAO,GAAG,QAAQ,QAAQ,UAAU,cAAc,KAAK;AAAA,EAC7I;AAEA,WAAS;AACT,WAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,SAAS,cAAc,MAAM,gCAAgC,CAAC;AAExG,QAAM,gBAAgB,cAAc,KAAK,GAAG,EAAE,YAAY;AAC1D,QAAM,cAAc,CAAC,gBAAgB,iBAAiB,WAAW,WAAW,WAAW,WAAW,WAAW,kBAAkB,SAAS,SAAS;AACjJ,QAAM,aAAuB,CAAC;AAE9B,aAAW,QAAQ,aAAa;AAC9B,QAAI,cAAc,SAAS,IAAI,IAAI,GAAG,KAAK,cAAc,SAAS,YAAY,IAAI,GAAG,GAAG;AACtF,iBAAW,KAAK,IAAI;AAAA,IACtB;AAAA,EACF;AAEA,MAAI,WAAW,SAAS,GAAG;AACzB,aAAS,KAAK,IAAI,GAAG,WAAW,SAAS,CAAC;AAC1C,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,uBAAuB,WAAW,KAAK,IAAI,CAAC,GAAG,CAAC;AAAA,EAC5F;AAEA,MAAI,CAAC,WAAW,SAAS,cAAc,KAAK,CAAC,WAAW,SAAS,eAAe,GAAG;AACjF,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,gDAAgD,KAAK,oFAAoF,CAAC;AAAA,EACtL,OAAO;AACL,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,6CAA6C,CAAC;AAAA,EAC1F;AAEA,MAAI,CAAC,WAAW,SAAS,SAAS,GAAG;AACnC,aAAS,KAAK,EAAE,UAAU,UAAU,QAAQ,2BAA2B,KAAK,+CAA+C,CAAC;AAAA,EAC9H,OAAO;AACL,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,gCAAgC,CAAC;AAAA,EAC7E;AAGA,MAAI,KAAK,cAAc,KAAK,WAAW,SAAS,GAAG;AACjD,UAAM,WAAW,YAAY,IAAI;AACjC,UAAM,aAAa,SAAS,MAAM,sEAAsE,KAAK,CAAC;AAC9G,QAAI,WAAW,SAAS,GAAG;AACzB,YAAM,iBAAiB,WAAW,KAAK,GAAG,EAAE,YAAY;AACxD,YAAM,YAAY,YAAY;AAAA,QAAO,QAClC,eAAe,SAAS,IAAI,CAAC,GAAG,KAAK,eAAe,SAAS,YAAY,CAAC,GAAG,MAAM,CAAC,WAAW,SAAS,CAAC;AAAA,MAC5G;AACA,UAAI,UAAU,SAAS,GAAG;AACxB,iBAAS,KAAK,IAAI,GAAG,UAAU,MAAM;AACrC,iBAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,gDAAgD,UAAU,KAAK,IAAI,CAAC,GAAG,CAAC;AAAA,MACpH;AAEA,UAAI,CAAC,WAAW,SAAS,SAAS,KAAK,WAAW,KAAK,cAAc,GAAG;AACtE,iBAAS;AACT,iBAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,qCAAqC,CAAC;AAAA,MAClF;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,WAAW,iBAAiB,iBAAiB,8BAA8B,OAAO,KAAK,IAAI,IAAI,KAAK,GAAG,QAAQ,SAAS,IAAI,SAAS,SAAS,IAAI,YAAY,QAAQ,UAAU,cAAc,SAAS,IAAI,OAAO,KAAK;AAClO;AAGA,SAAS,cAAc,MAAiC;AACtD,QAAM,WAA2B,CAAC;AAElC,MAAI,CAAC,KAAK,UAAU;AAClB,aAAS,KAAK,EAAE,UAAU,YAAY,QAAQ,2BAA2B,CAAC;AAC1E,WAAO,EAAE,WAAW,qBAAqB,iBAAiB,sBAAsB,OAAO,GAAG,QAAQ,aAAa,UAAU,cAAc,KAAK;AAAA,EAC9I;AAEA,QAAM,OAAO,KAAK,SAAS;AAC3B,MAAI,QAAQ;AAGZ,QAAM,eAAe,gBAAgB,IAAI;AACzC,QAAM,eAAe,aAAa,MAAM,qCAAqC,KAAK,CAAC,GAAG,IAAI,OAAK,EAAE,QAAQ,YAAY,EAAE,CAAC;AACxH,QAAM,mBAAmB,YAAY,OAAO,OAAK,EAAE,SAAS,GAAG,KAAK,8DAA8D,KAAK,CAAC,CAAC;AAEzI,MAAI,iBAAiB,UAAU,IAAI;AACjC,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,SAAS,iBAAiB,MAAM,4BAA4B,CAAC;AAAA,EACzG,WAAW,iBAAiB,UAAU,GAAG;AACvC,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,SAAS,iBAAiB,MAAM,4BAA4B,CAAC;AAAA,EACzG,WAAW,iBAAiB,UAAU,GAAG;AACvC,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,QAAQ,iBAAiB,MAAM,qCAAqC,KAAK,0FAA0F,CAAC;AAAA,EAC/M,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,qCAAqC,KAAK,gGAAgG,CAAC;AAAA,EACvL;AAGA,QAAM,mBAAmB,gEAAgE,KAAK,YAAY;AAC1G,MAAI,kBAAkB;AACpB,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,4DAA4D,CAAC;AAAA,EACzG,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,UAAU,QAAQ,gDAAgD,KAAK,wFAAwF,CAAC;AAAA,EAC5L;AAEA,QAAM,WAAW,KAAK,MAAM,YAAY,KAAK,CAAC,GAAG;AACjD,MAAI,YAAY,GAAG;AACjB,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,iCAAiC,CAAC;AAAA,EAC9E,WAAW,YAAY,GAAG;AACxB,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,mBAAmB,KAAK,kDAAkD,CAAC;AAAA,EACvH,OAAO;AACL,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,UAAU,QAAQ,2BAA2B,OAAO,KAAK,KAAK,sDAAsD,CAAC;AAAA,EACjJ;AAEA,SAAO,EAAE,WAAW,qBAAqB,iBAAiB,sBAAsB,OAAO,KAAK,IAAI,IAAI,KAAK,GAAG,QAAQ,SAAS,IAAI,SAAS,SAAS,IAAI,YAAY,QAAQ,UAAU,cAAc,SAAS,IAAI,OAAO,KAAK;AAC9N;AAGA,SAAS,eAAe,MAAiC;AACvD,QAAM,WAA2B,CAAC;AAElC,MAAI,CAAC,KAAK,UAAU;AAClB,aAAS,KAAK,EAAE,UAAU,YAAY,QAAQ,2BAA2B,CAAC;AAC1E,WAAO,EAAE,WAAW,cAAc,iBAAiB,yBAAyB,OAAO,GAAG,QAAQ,aAAa,UAAU,cAAc,KAAK;AAAA,EAC1I;AAEA,QAAM,OAAO,KAAK,SAAS;AAC3B,MAAI,QAAQ;AACZ,QAAM,iBAAiB,KAAK,aAAa;AAGzC,MAAI,gBAAgB;AAClB,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,yBAAyB,CAAC;AAAA,EACtE,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,YAAY,QAAQ,+BAA+B,KAAK,+FAA+F,CAAC;AAAA,EACpL;AAGA,QAAM,UAAU,cAAc,KAAK,IAAI;AACvC,QAAM,aAAa,iBAAiB,KAAK,IAAI;AAC7C,QAAM,aAAa,iBAAiB,KAAK,IAAI;AAE7C,QAAM,gBAAgB,CAAC,SAAS,YAAY,UAAU,EAAE,OAAO,OAAO,EAAE;AACxE,WAAS,KAAK,IAAI,GAAG,gBAAgB,CAAC;AACtC,MAAI,iBAAiB,GAAG;AACtB,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,iCAAiC,CAAC,WAAW,QAAQ,cAAc,WAAW,cAAc,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI,CAAC,GAAG,CAAC;AAAA,EACjL,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,UAAU,QAAQ,gCAAgC,KAAK,mGAAmG,CAAC;AAAA,EACvL;AAGA,QAAM,WAAW,KAAK,MAAM,YAAY,KAAK,CAAC,GAAG;AACjD,MAAI,YAAY,GAAG;AACjB,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,kDAAkD,CAAC;AAAA,EAC/F,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,YAAY,IAAI,SAAS,UAAU,QAAQ,GAAG,YAAY,IAAI,OAAO,UAAU,qBAAqB,OAAO,KAAK,KAAK,8BAA8B,CAAC;AAAA,EAChL;AAGA,QAAM,cAAc,KAAK,QAAQ,YAAY,EAAE,EAAE,QAAQ,QAAQ,GAAG,EAAE,KAAK;AAC3E,MAAI,YAAY,SAAS,KAAK;AAC5B,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,kEAAkE,CAAC;AAAA,EAC/G,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,mDAAmD,KAAK,wEAAwE,CAAC;AAAA,EAC7K;AAGA,QAAM,cAAc,sCAAsC,KAAK,IAAI;AACnE,QAAM,WAAW,8BAA8B,KAAK,IAAI;AACxD,MAAI,eAAe,UAAU;AAC3B,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,sCAAsC,CAAC;AAAA,EACnF,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,UAAU,QAAQ,WAAW,CAAC,WAAW,cAAc,EAAE,GAAG,CAAC,YAAY,CAAC,cAAc,UAAU,EAAE,GAAG,CAAC,cAAc,qBAAqB,EAAE,IAAI,KAAK,iDAAiD,CAAC;AAAA,EACpO;AAGA,MAAI,CAAC,gBAAgB;AACnB,YAAQ,KAAK,IAAI,OAAO,CAAC;AAAA,EAC3B;AAEA,SAAO,EAAE,WAAW,cAAc,iBAAiB,yBAAyB,OAAO,KAAK,IAAI,IAAI,KAAK,GAAG,QAAQ,SAAS,IAAI,SAAS,SAAS,IAAI,YAAY,QAAQ,UAAU,cAAc,SAAS,IAAI,OAAO,KAAK;AAC1N;AAGA,SAAS,uBAAuB,MAAiC;AAC/D,QAAM,WAA2B,CAAC;AAElC,MAAI,CAAC,KAAK,UAAU;AAClB,aAAS,KAAK,EAAE,UAAU,YAAY,QAAQ,2BAA2B,CAAC;AAC1E,WAAO,EAAE,WAAW,sBAAsB,iBAAiB,8BAA8B,OAAO,GAAG,QAAQ,aAAa,UAAU,cAAc,KAAK;AAAA,EACvJ;AAEA,QAAM,OAAO,KAAK,SAAS;AAC3B,QAAM,OAAO,KAAK,QAAQ,YAAY,GAAG,EAAE,QAAQ,QAAQ,GAAG;AAC9D,MAAI,QAAQ;AAIZ,QAAM,aAAa,cAAc,KAAK,IAAI;AAC1C,QAAM,qBAAqB,eAAe,KAAK,IAAI;AACnD,QAAM,oBAAoB;AAE1B,QAAM,aAAa;AACnB,QAAM,SAAS,KAAK,MAAM,UAAU,KAAK,CAAC;AAC1C,QAAM,yBAAmC,CAAC;AAE1C,MAAI,cAAc,oBAAoB;AAEpC,2BAAuB,KAAK,GAAG,MAAM;AAAA,EACvC,OAAO;AAEL,QAAI;AACJ,UAAM,cAAc;AACpB,YAAQ,QAAQ,YAAY,KAAK,IAAI,OAAO,MAAM;AAChD,YAAM,QAAQ,KAAK,IAAI,GAAG,MAAM,QAAQ,GAAG;AAC3C,YAAM,MAAM,KAAK,IAAI,KAAK,QAAQ,MAAM,QAAQ,MAAM,CAAC,EAAE,SAAS,GAAG;AACrE,YAAM,cAAc,KAAK,MAAM,OAAO,GAAG;AACzC,UAAI,kBAAkB,KAAK,WAAW,GAAG;AACvC,+BAAuB,KAAK,MAAM,CAAC,CAAC;AAAA,MACtC;AAAA,IACF;AAAA,EACF;AAEA,QAAM,eAAe,CAAC,GAAG,IAAI,IAAI,uBAAuB,IAAI,OAAK,EAAE,QAAQ,OAAO,EAAE,CAAC,CAAC,CAAC;AACvF,MAAI,aAAa,WAAW,GAAG;AAC7B,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,uCAAuC,CAAC;AAAA,EACpF,WAAW,aAAa,SAAS,GAAG;AAClC,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,UAAU,QAAQ,iCAAiC,aAAa,MAAM,KAAK,KAAK,6DAA6D,CAAC;AAAA,EAC1K,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,oCAAoC,CAAC;AAC9E,aAAS;AAAA,EACX;AAGA,QAAM,aAAa,2FAA2F,KAAK,IAAI;AACvH,MAAI,YAAY;AACd,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,iCAAiC,CAAC;AAAA,EAC9E;AAGA,QAAM,eAAe,8BAA8B,KAAK,IAAI;AAC5D,MAAI,cAAc;AAChB,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,+DAA+D,CAAC;AAAA,EAC5G,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,uDAAuD,KAAK,kFAAkF,CAAC;AAAA,EAC3L;AAGA,QAAM,YAAY,0DAA0D,KAAK,IAAI;AACrF,MAAI,WAAW;AACb,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,yCAAyC,CAAC;AAAA,EACtF,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,yCAAyC,KAAK,6DAA6D,CAAC;AAAA,EACvJ;AAEA,SAAO,EAAE,WAAW,sBAAsB,iBAAiB,8BAA8B,OAAO,KAAK,IAAI,IAAI,KAAK,GAAG,QAAQ,SAAS,IAAI,SAAS,SAAS,IAAI,YAAY,QAAQ,UAAU,cAAc,SAAS,IAAI,OAAO,KAAK;AACvO;AAGA,SAAS,eAAe,MAAiC;AACvD,QAAM,WAA2B,CAAC;AAClC,QAAM,SAAS,KAAK;AAEpB,MAAI,CAAC,UAAU,OAAO,WAAW,OAAO,eAAe,MAAM,GAAG;AAC9D,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,4BAA4B,KAAK,yDAAyD,CAAC;AACrI,WAAO,EAAE,WAAW,cAAc,iBAAiB,8BAA8B,OAAO,GAAG,QAAQ,QAAQ,UAAU,cAAc,KAAK;AAAA,EAC1I;AAEA,QAAM,OAAO,OAAO,KAAK,YAAY;AACrC,MAAI,QAAQ;AAEZ,QAAM,aAAa,CAAC,UAAU,aAAa,iBAAiB,aAAa,SAAS;AAClF,QAAM,oBAAoB,WAAW,OAAO,OAAK,KAAK,SAAS,CAAC,CAAC;AAEjE,MAAI,kBAAkB,SAAS,GAAG;AAChC,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,0BAA0B,kBAAkB,KAAK,IAAI,CAAC,GAAG,CAAC;AAEpG,UAAM,UAAU,kBAAkB,OAAO,OAAK;AAI5C,YAAM,eAAe,IAAI,OAAO,kBAAkB,CAAC,8CAA8C,GAAG;AACpG,YAAM,QAAQ,aAAa,KAAK,OAAO,IAAI;AAC3C,UAAI,CAAC,MAAO,QAAO;AACnB,YAAM,UAAU,MAAM,CAAC;AAEvB,UAAI,qBAAqB,KAAK,OAAO,EAAG,QAAO;AAE/C,aAAO,wBAAwB,KAAK,OAAO;AAAA,IAC7C,CAAC;AACD,QAAI,QAAQ,SAAS,GAAG;AACtB,eAAS;AACT,eAAS,KAAK,EAAE,UAAU,YAAY,QAAQ,wBAAwB,QAAQ,KAAK,IAAI,CAAC,IAAI,KAAK,4DAA4D,CAAC;AAAA,IAChK,OAAO;AACL,eAAS;AACT,eAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,4CAA4C,CAAC;AAAA,IACzF;AAAA,EACF,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,UAAU,QAAQ,8CAA8C,KAAK,0EAA0E,CAAC;AAAA,EAC5K;AAEA,MAAI,KAAK,SAAS,UAAU,GAAG;AAC7B,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,uCAAuC,CAAC;AAAA,EACpF,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,sCAAsC,KAAK,8DAA8D,CAAC;AAAA,EACrJ;AAEA,SAAO,EAAE,WAAW,cAAc,iBAAiB,8BAA8B,OAAO,KAAK,IAAI,IAAI,KAAK,GAAG,QAAQ,SAAS,IAAI,SAAS,SAAS,IAAI,YAAY,QAAQ,UAAU,cAAc,SAAS,IAAI,OAAO,KAAK;AAC/N;AAGA,SAAS,gBAAgB,MAAiC;AACxD,QAAM,WAA2B,CAAC;AAClC,MAAI,QAAQ;AAEZ,QAAM,WAAW,KAAK;AACtB,QAAM,iBAAiB,YAAY,0BAA0B,KAAK,SAAS,IAAI;AAE/E,MAAI,gBAAgB;AAClB,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,gCAAgC,CAAC;AAAA,EAC7E,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,oCAAoC,KAAK,0EAA0E,CAAC;AAAA,EAC/J;AAEA,QAAM,UAAU,KAAK;AACrB,QAAM,aAAa,WAAW,QAAQ,WAAW,OAAO,QAAQ,KAAK,SAAS;AAE9E,MAAI,YAAY;AACd,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,4BAA4B,CAAC;AAEvE,QAAI,mCAAmC,KAAK,QAAQ,IAAI,GAAG;AACzD,eAAS;AACT,eAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,uCAAuC,CAAC;AAAA,IACpF;AAAA,EACF,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,uCAAuC,KAAK,uFAAuF,CAAC;AAAA,EAChL;AAGA,QAAM,WAAW,YAAY,IAAI;AACjC,QAAM,WAAW,UAAU,QAAQ,OAAO,SAAS,QAAQ,MAAM;AACjE,MAAI,WAAW,KAAK,OAAO,KAAK,yBAAyB,KAAK,OAAO,GAAG;AACtE,aAAS;AACT,UAAM,YAAY,YAAY,WAAW,KAAK,QAAQ,KAAK,yBAAyB,KAAK,QAAQ;AACjG,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,YAAY,8CAA8C,8BAA8B,CAAC;AAAA,EACrI,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,UAAU,QAAQ,4BAA4B,KAAK,uDAAuD,CAAC;AAAA,EACvI;AAEA,QAAM,iBAAiB,QAAQ,MAAM,kCAAkC,KAAK,CAAC,GAAG;AAChF,MAAI,iBAAiB,IAAI;AACvB,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,GAAG,aAAa,gDAAgD,CAAC;AAAA,EAC7G,WAAW,iBAAiB,GAAG;AAC7B,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,QAAQ,aAAa,4BAA4B,KAAK,sDAAsD,CAAC;AAAA,EACxJ;AAEA,SAAO,EAAE,WAAW,eAAe,iBAAiB,8BAA8B,OAAO,KAAK,IAAI,IAAI,KAAK,GAAG,QAAQ,SAAS,IAAI,SAAS,SAAS,IAAI,YAAY,QAAQ,UAAU,cAAc,SAAS,IAAI,OAAO,KAAK;AAChO;AAGA,SAAS,kBAAkB,MAAiC;AAC1D,QAAM,WAA2B,CAAC;AAElC,MAAI,CAAC,KAAK,UAAU;AAClB,aAAS,KAAK,EAAE,UAAU,YAAY,QAAQ,2BAA2B,CAAC;AAC1E,WAAO,EAAE,WAAW,iBAAiB,iBAAiB,kCAAkC,OAAO,GAAG,QAAQ,aAAa,UAAU,cAAc,KAAK;AAAA,EACtJ;AAEA,QAAM,OAAO,KAAK,SAAS;AAC3B,QAAM,OAAO,KAAK,QAAQ,YAAY,GAAG,EAAE,QAAQ,QAAQ,GAAG;AAC9D,MAAI,QAAQ;AAGZ,QAAM,eAAe;AACrB,MAAI,aAAa,KAAK,IAAI,GAAG;AAC3B,UAAM,kBAAkB;AACxB,QAAI,gBAAgB,KAAK,IAAI,GAAG;AAC9B,eAAS;AACT,eAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,iEAAiE,CAAC;AAAA,IAC9G,OAAO;AACL,eAAS;AACT,eAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,wEAAwE,KAAK,yFAAyF,CAAC;AAAA,IAClN;AAAA,EACF,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,UAAU,QAAQ,2CAA2C,KAAK,oGAAoG,CAAC;AAAA,EACnM;AAGA,QAAM,mBAAmB;AACzB,MAAI,iBAAiB,KAAK,IAAI,GAAG;AAE/B,UAAM,iBAAiB;AACvB,QAAI,kBAAkB;AACtB,QAAI;AACJ,YAAQ,UAAU,eAAe,KAAK,IAAI,OAAO,MAAM;AACrD,YAAM,QAAQ,KAAK,IAAI,GAAG,QAAQ,QAAQ,GAAG;AAC7C,YAAM,MAAM,KAAK,IAAI,KAAK,QAAQ,QAAQ,QAAQ,QAAQ,CAAC,EAAE,SAAS,GAAG;AACzE,YAAM,cAAc,KAAK,MAAM,OAAO,GAAG;AACzC,UAAI,wBAAwB,KAAK,WAAW,GAAG;AAC7C,0BAAkB;AAClB;AAAA,MACF;AAAA,IACF;AACA,QAAI,iBAAiB;AACnB,eAAS;AACT,eAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,2DAA2D,CAAC;AAAA,IACxG,OAAO;AACL,eAAS;AACT,eAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,uEAAuE,KAAK,6EAA6E,CAAC;AAAA,IACrM;AAAA,EACF,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,UAAU,QAAQ,yCAAyC,KAAK,sDAAsD,CAAC;AAAA,EACnJ;AAGA,QAAM,eAAe,KAAK,cAAc,KAAK,WAAW,SAAS,IAC7D,OAAO,MAAM,KAAK,WAAW,IAAI,OAAK,EAAE,KAAK,QAAQ,YAAY,GAAG,EAAE,QAAQ,QAAQ,GAAG,CAAC,EAAE,KAAK,GAAG,IACpG;AACJ,MAAI,yEAAyE,KAAK,YAAY,GAAG;AAC/F,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,0CAA0C,CAAC;AAAA,EACvF,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,gDAAgD,KAAK,gEAAgE,CAAC;AAAA,EACjK;AAGA,QAAM,qBAAqB;AAC3B,MAAI,mBAAmB,KAAK,IAAI,GAAG;AACjC,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,+CAA+C,CAAC;AAAA,EAC5F,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,UAAU,QAAQ,8CAA8C,KAAK,kFAAkF,CAAC;AAAA,EACpL;AAGA,MAAI,KAAK,cAAc,KAAK,WAAW,SAAS,KAAK,CAAC,iBAAiB,KAAK,IAAI,GAAG;AACjF,UAAM,WAAW,KAAK,WAAW,IAAI,OAAK,EAAE,KAAK,QAAQ,YAAY,GAAG,EAAE,QAAQ,QAAQ,GAAG,CAAC,EAAE,KAAK,GAAG;AACxG,QAAI,iBAAiB,KAAK,QAAQ,GAAG;AACnC,eAAS;AACT,eAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,mDAAmD,CAAC;AAAA,IAChG;AAAA,EACF;AAEA,SAAO,EAAE,WAAW,iBAAiB,iBAAiB,kCAAkC,OAAO,KAAK,IAAI,IAAI,KAAK,GAAG,QAAQ,SAAS,IAAI,SAAS,SAAS,IAAI,YAAY,QAAQ,UAAU,cAAc,SAAS,IAAI,OAAO,KAAK;AACtO;AAGA,SAAS,qBAAqB,MAAiC;AAC7D,QAAM,WAA2B,CAAC;AAElC,MAAI,CAAC,KAAK,UAAU;AAClB,aAAS,KAAK,EAAE,UAAU,YAAY,QAAQ,2BAA2B,CAAC;AAC1E,WAAO,EAAE,WAAW,oBAAoB,iBAAiB,iCAAiC,OAAO,GAAG,QAAQ,aAAa,UAAU,cAAc,KAAK;AAAA,EACxJ;AAEA,QAAM,OAAO,KAAK,SAAS;AAC3B,MAAI,QAAQ;AAEZ,QAAM,cAAc,KAAK,MAAM,+BAA+B,KAAK,CAAC;AACpE,QAAM,gBAAgB,YAAY,OAAO,OAAK;AAC5C,UAAM,OAAO,EAAE,MAAM,gBAAgB,IAAI,CAAC,KAAK;AAC/C,WAAO,KAAK,WAAW,GAAG,KAAK,KAAK,SAAS,KAAK,MAAM;AAAA,EAC1D,CAAC;AAED,MAAI,cAAc,UAAU,IAAI;AAC9B,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,GAAG,cAAc,MAAM,oCAAoC,CAAC;AAAA,EACxG,WAAW,cAAc,UAAU,IAAI;AACrC,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,GAAG,cAAc,MAAM,+BAA+B,KAAK,uDAAuD,CAAC;AAAA,EAC9J,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,QAAQ,cAAc,MAAM,+BAA+B,KAAK,4EAA4E,CAAC;AAAA,EACzL;AAEA,MAAI,sCAAsC,KAAK,IAAI,GAAG;AACpD,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,iCAAiC,CAAC;AAAA,EAC9E,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,UAAU,QAAQ,kCAAkC,KAAK,8DAA8D,CAAC;AAAA,EACpJ;AAEA,MAAI,aAAa,KAAK,IAAI,GAAG;AAC3B,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,6CAA6C,CAAC;AAAA,EAC1F,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,mCAAmC,KAAK,yEAAyE,CAAC;AAAA,EAC7J;AAEA,MAAI,4DAA4D,KAAK,IAAI,GAAG;AAC1E,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,kDAAkD,CAAC;AAAA,EAC/F,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,6CAA6C,KAAK,0EAA0E,CAAC;AAAA,EACxK;AAEA,MAAI,gBAAgB,KAAK,IAAI,GAAG;AAC9B,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,8CAA8C,CAAC;AAAA,EAC3F,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,6BAA6B,KAAK,yEAAyE,CAAC;AAAA,EACvJ;AAEA,SAAO,EAAE,WAAW,oBAAoB,iBAAiB,iCAAiC,OAAO,KAAK,IAAI,IAAI,KAAK,GAAG,QAAQ,SAAS,IAAI,SAAS,SAAS,IAAI,YAAY,QAAQ,UAAU,cAAc,SAAS,IAAI,OAAO,KAAK;AACxO;AAGA,SAAS,kBAAkB,MAAiC;AAC1D,QAAM,WAA2B,CAAC;AAElC,MAAI,CAAC,KAAK,UAAU;AAClB,aAAS,KAAK,EAAE,UAAU,YAAY,QAAQ,2BAA2B,CAAC;AAC1E,WAAO,EAAE,WAAW,iBAAiB,iBAAiB,kCAAkC,OAAO,GAAG,QAAQ,aAAa,UAAU,cAAc,KAAK;AAAA,EACtJ;AAGA,QAAM,eAAe,gBAAgB,IAAI;AACzC,QAAM,OAAO,KAAK,SAAS;AAC3B,MAAI,QAAQ;AAEZ,QAAM,SAAqC;AAAA,IACzC,CAAC,UAAU,eAAe,qCAAqC;AAAA,IAC/D,CAAC,aAAa,kBAAkB,6CAA6C;AAAA,IAC7E,CAAC,UAAU,eAAe,+BAA+B;AAAA,IACzD,CAAC,SAAS,cAAc,mCAAmC;AAAA,IAC3D,CAAC,YAAY,iBAAiB,uCAAuC;AAAA,IACrE,CAAC,YAAY,iBAAiB,uCAAuC;AAAA,EACvE;AAEA,MAAI,QAAQ;AACZ,aAAW,CAAC,MAAM,OAAO,GAAG,KAAK,QAAQ;AACvC,QAAI,MAAM,KAAK,YAAY,GAAG;AAC5B;AAAA,IACF,OAAO;AACL,eAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,WAAW,IAAI,YAAY,IAAI,CAAC;AAAA,IAC3E;AAAA,EACF;AACA,WAAS,KAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,GAAG,CAAC;AAC5C,MAAI,SAAS,EAAG,UAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,GAAG,KAAK,uCAAuC,CAAC;AAG1G,QAAM,SAAS,KAAK,MAAM,cAAc,KAAK,CAAC;AAC9C,QAAM,gBAAgB,OAAO,OAAO,SAAO,eAAe,KAAK,GAAG,CAAC;AACnE,MAAI,OAAO,SAAS,GAAG;AACrB,UAAM,QAAQ,cAAc,SAAS,OAAO;AAC5C,QAAI,SAAS,KAAK;AAChB,eAAS;AACT,eAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,GAAG,KAAK,MAAM,QAAQ,GAAG,CAAC,4BAA4B,CAAC;AAAA,IACnG,OAAO;AACL,eAAS,KAAK,EAAE,UAAU,UAAU,QAAQ,QAAQ,KAAK,MAAM,QAAQ,GAAG,CAAC,6BAA6B,KAAK,yCAAyC,CAAC;AAAA,IACzJ;AAAA,EACF;AAGA,MAAI,mBAAmB,KAAK,IAAI,GAAG;AACjC,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,0BAA0B,CAAC;AAAA,EACvE,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,UAAU,QAAQ,wCAAwC,KAAK,4DAA4D,CAAC;AAAA,EACxJ;AAGA,MAAI,gBAAgB,KAAK,IAAI,GAAG;AAC9B,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,0CAA0C,CAAC;AAAA,EACvF,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,qCAAqC,KAAK,0EAA0E,CAAC;AAAA,EAChK;AAEA,SAAO,EAAE,WAAW,iBAAiB,iBAAiB,kCAAkC,OAAO,KAAK,IAAI,IAAI,KAAK,GAAG,QAAQ,SAAS,IAAI,SAAS,SAAS,IAAI,YAAY,QAAQ,UAAU,cAAc,SAAS,IAAI,OAAO,KAAK;AACtO;AAGA,SAAS,sBAAsB,MAAiC;AAC9D,QAAM,WAA2B,CAAC;AAElC,MAAI,CAAC,KAAK,UAAU;AAClB,aAAS,KAAK,EAAE,UAAU,YAAY,QAAQ,2BAA2B,CAAC;AAC1E,WAAO,EAAE,WAAW,qBAAqB,iBAAiB,6BAA6B,OAAO,GAAG,QAAQ,aAAa,UAAU,cAAc,KAAK;AAAA,EACrJ;AAEA,QAAM,OAAO,KAAK,SAAS;AAC3B,MAAI,QAAQ;AAGZ,QAAM,mBAAmB,6BAA6B,KAAK,IAAI;AAC/D,QAAM,kBAAkB,gBAAgB,KAAK,IAAI;AACjD,MAAI,oBAAoB,iBAAiB;AACvC,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,kCAAkC,CAAC,oBAAoB,iBAAiB,mBAAmB,cAAc,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI,CAAC,GAAG,CAAC;AAAA,EACrL,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,iEAAiE,KAAK,kEAAkE,CAAC;AAAA,EACrL;AAGA,QAAM,eAAe,KAAK,MAAM,cAAc,KAAK,CAAC;AACpD,MAAI,aAAa,UAAU,GAAG;AAC5B,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,GAAG,aAAa,MAAM,yBAAyB,CAAC;AAAA,EAC5F,WAAW,aAAa,WAAW,GAAG;AACpC,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,+BAA+B,KAAK,6DAA6D,CAAC;AAAA,EAC7I,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,UAAU,QAAQ,4BAA4B,KAAK,4EAA4E,CAAC;AAAA,EAC5J;AAGA,QAAM,iBAAiB,gDAAgD,KAAK,IAAI;AAChF,MAAI,gBAAgB;AAClB,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,0CAA0C,CAAC;AAAA,EACvF,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,gEAAgE,KAAK,wCAAwC,CAAC;AAAA,EACzJ;AAGA,QAAM,eAAc,oBAAI,KAAK,GAAE,YAAY;AAC3C,QAAM,gBAAgB,KAAK,SAAS,OAAO,WAAW,CAAC,KAAK,KAAK,SAAS,OAAO,cAAc,CAAC,CAAC;AACjG,MAAI,eAAe;AACjB,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,iBAAiB,WAAW,OAAO,cAAc,CAAC,oCAAoC,CAAC;AAAA,EACnI,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,kDAAkD,CAAC;AAAA,EAC9F;AAEA,SAAO,EAAE,WAAW,qBAAqB,iBAAiB,6BAA6B,OAAO,KAAK,IAAI,IAAI,KAAK,GAAG,QAAQ,SAAS,IAAI,SAAS,SAAS,IAAI,YAAY,QAAQ,UAAU,cAAc,SAAS,IAAI,OAAO,KAAK;AACrO;AAGA,SAAS,yBAAyB,MAAiC;AACjE,QAAM,WAA2B,CAAC;AAClC,QAAM,UAAU,KAAK;AAErB,MAAI,CAAC,WAAW,QAAQ,WAAW,KAAK;AACtC,aAAS,KAAK,EAAE,UAAU,YAAY,QAAQ,wBAAwB,KAAK,6EAA6E,CAAC;AACzJ,WAAO,EAAE,WAAW,wBAAwB,iBAAiB,wBAAwB,OAAO,GAAG,QAAQ,QAAQ,UAAU,cAAc,KAAK;AAAA,EAC9I;AAEA,QAAM,OAAO,QAAQ;AACrB,MAAI,QAAQ;AAGZ,MAAI,KAAK,SAAS,SAAS,KAAK,KAAK,SAAS,eAAe,GAAG;AAC9D,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,uCAAuC,CAAC;AAAA,EACpF,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,oDAAoD,KAAK,mEAAmE,CAAC;AAAA,EACzK;AAGA,QAAM,YAAY,KAAK,MAAM,SAAS,KAAK,CAAC,GAAG;AAC/C,MAAI,YAAY,IAAI;AAClB,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,GAAG,QAAQ,mBAAmB,CAAC;AAAA,EAC3E,WAAW,YAAY,IAAI;AACzB,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,GAAG,QAAQ,mBAAmB,CAAC;AAAA,EAC3E,WAAW,WAAW,GAAG;AACvB,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,QAAQ,QAAQ,sBAAsB,KAAK,0CAA0C,CAAC;AAAA,EACjI;AAGA,QAAM,iBAAiB,KAAK,MAAM,+BAA+B,KAAK,CAAC;AACvE,MAAI,eAAe,SAAS,GAAG;AAC7B,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,GAAG,eAAe,MAAM,2BAA2B,CAAC;AAAA,EAChG,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,UAAU,QAAQ,+BAA+B,KAAK,+DAA+D,CAAC;AAAA,EAClJ;AAGA,MAAI,KAAK,SAAS,eAAe,GAAG;AAClC,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,8DAA8D,CAAC;AAAA,EAC3G,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,8BAA8B,KAAK,iGAAiG,CAAC;AAAA,EAChL;AAEA,SAAO,EAAE,WAAW,wBAAwB,iBAAiB,wBAAwB,OAAO,KAAK,IAAI,IAAI,KAAK,GAAG,QAAQ,SAAS,IAAI,SAAS,SAAS,IAAI,YAAY,QAAQ,UAAU,cAAc,SAAS,IAAI,OAAO,KAAK;AACnO;AAGA,SAAS,aAAa,MAAiC;AACrD,QAAM,WAA2B,CAAC;AAClC,MAAI,QAAQ;AAGZ,QAAM,aAAa,KAAK,YAAY,mDAAmD,KAAK,KAAK,SAAS,IAAI;AAC9G,MAAI,YAAY;AACd,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,kDAAkD,CAAC;AAAA,EAC/F,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,yCAAyC,KAAK,oFAAoF,CAAC;AAAA,EAC/K;AAGA,QAAM,OAAO,KAAK;AAClB,MAAI,QAAQ,KAAK,WAAW,KAAK;AAC/B,UAAM,WAAW,KAAK;AACtB,UAAM,cAAc,SAAS,SAAS,MAAM,KAAK,SAAS,SAAS,OAAO,KAAK,SAAS,SAAS,UAAU;AAC3G,QAAI,aAAa;AACf,eAAS;AACT,eAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,uCAAuC,CAAC;AAGlF,YAAM,aAAa,SAAS,MAAM,0BAA0B,KAAK,CAAC,GAAG;AACrE,UAAI,aAAa,GAAG;AAClB,iBAAS;AACT,iBAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,iBAAiB,SAAS,SAAS,CAAC;AAAA,MAChF,WAAW,YAAY,GAAG;AACxB,iBAAS;AACT,iBAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,sBAAsB,SAAS,YAAY,KAAK,uEAAuE,CAAC;AAAA,MACnK;AAAA,IACF,OAAO;AACL,eAAS,KAAK,EAAE,UAAU,UAAU,QAAQ,wDAAwD,KAAK,qDAAqD,CAAC;AAAA,IACjK;AAAA,EACF,WAAW,CAAC,YAAY;AACtB,aAAS,KAAK,EAAE,UAAU,UAAU,QAAQ,qCAAqC,KAAK,qFAAqF,CAAC;AAAA,EAC9K;AAEA,SAAO,EAAE,WAAW,YAAY,iBAAiB,iBAAiB,OAAO,KAAK,IAAI,IAAI,KAAK,GAAG,QAAQ,SAAS,IAAI,SAAS,SAAS,IAAI,YAAY,QAAQ,UAAU,cAAc,SAAS,IAAI,OAAO,KAAK;AAChN;AAGA,SAAS,6BAA6B,MAAiC;AACrE,QAAM,WAA2B,CAAC;AAElC,MAAI,CAAC,KAAK,UAAU;AAClB,aAAS,KAAK,EAAE,UAAU,YAAY,QAAQ,2BAA2B,CAAC;AAC1E,WAAO,EAAE,WAAW,6BAA6B,iBAAiB,+BAA+B,OAAO,GAAG,QAAQ,aAAa,UAAU,cAAc,KAAK;AAAA,EAC/J;AAGA,QAAM,OAAO,gBAAgB,IAAI;AACjC,MAAI,QAAQ;AAGZ,QAAM,SAAS,KAAK,MAAM,eAAe,KAAK,CAAC;AAC/C,QAAM,qBAAqB,KAAK,MAAM,2BAA2B,KAAK,CAAC,GAAG,OAAO,OAAK,YAAY,KAAK,CAAC,CAAC;AACzG,MAAI,kBAAkB,UAAU,GAAG;AACjC,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,GAAG,kBAAkB,MAAM,oCAAoC,CAAC;AAAA,EAC5G,WAAW,OAAO,SAAS,GAAG;AAC5B,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,UAAU,QAAQ,GAAG,OAAO,MAAM,iDAAiD,KAAK,2DAA2D,CAAC;AAAA,EAChL,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,wBAAwB,KAAK,qFAAqF,CAAC;AAAA,EAC9J;AACA,MAAI,kBAAkB,UAAU,GAAG;AACjC,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,0CAA0C,CAAC;AAAA,EACvF,WAAW,kBAAkB,WAAW,GAAG;AACzC,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,mCAAmC,KAAK,kGAAkG,CAAC;AAAA,EACtL;AAGA,QAAM,WAAW,KAAK,MAAM,YAAY,KAAK,CAAC,GAAG;AACjD,MAAI,WAAW,GAAG;AAChB,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,GAAG,OAAO,yDAAyD,CAAC;AAAA,EAChH,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,iCAAiC,KAAK,+DAA+D,CAAC;AAAA,EACjJ;AAGA,QAAM,WAAW,KAAK,MAAM,YAAY,KAAK,CAAC,GAAG;AACjD,MAAI,WAAW,GAAG;AAChB,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,GAAG,OAAO,2BAA2B,CAAC;AAAA,EAClF,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,mCAAmC,KAAK,iEAAiE,CAAC;AAAA,EACrJ;AAGA,QAAM,WAAW,KAAK,MAAM,YAAY,KAAK,CAAC,GAAG;AACjD,MAAI,WAAW,IAAI;AACjB,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,GAAG,OAAO,gDAAgD,CAAC;AAAA,EACvG;AAGA,QAAM,WAAW,KAAK,MAAM,YAAY,KAAK,CAAC,GAAG;AACjD,MAAI,WAAW,GAAG;AAChB,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,GAAG,OAAO,4BAA4B,CAAC;AAAA,EACnF,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,oCAAoC,KAAK,4EAA4E,CAAC;AAAA,EACjK;AAEA,SAAO,EAAE,WAAW,6BAA6B,iBAAiB,+BAA+B,OAAO,KAAK,IAAI,IAAI,KAAK,GAAG,QAAQ,SAAS,IAAI,SAAS,SAAS,IAAI,YAAY,QAAQ,UAAU,cAAc,SAAS,IAAI,OAAO,KAAK;AAC/O;AAGA,SAAS,wBAAwB,MAAiC;AAChE,QAAM,WAA2B,CAAC;AAElC,MAAI,CAAC,KAAK,UAAU;AAClB,aAAS,KAAK,EAAE,UAAU,YAAY,QAAQ,2BAA2B,CAAC;AAC1E,WAAO,EAAE,WAAW,uBAAuB,iBAAiB,uBAAuB,OAAO,GAAG,QAAQ,aAAa,UAAU,cAAc,KAAK;AAAA,EACjJ;AAGA,QAAM,eAAe,gBAAgB,IAAI;AACzC,QAAM,OAAO,aAAa,QAAQ,YAAY,GAAG,EAAE,QAAQ,QAAQ,GAAG;AACtE,QAAM,OAAO;AACb,MAAI,QAAQ;AAGZ,QAAM,qBAAqB;AAAA,IACzB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,MAAI,eAAe;AACnB,aAAW,WAAW,oBAAoB;AACxC,UAAM,UAAU,KAAK,MAAM,OAAO,KAAK,CAAC;AACxC,oBAAgB,QAAQ;AAAA,EAC1B;AAEA,MAAI,gBAAgB,GAAG;AACrB,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,GAAG,YAAY,kFAAkF,CAAC;AAAA,EAC9I,WAAW,gBAAgB,GAAG;AAC5B,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,QAAQ,YAAY,gCAAgC,KAAK,6FAA6F,CAAC;AAAA,EAClM,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,UAAU,QAAQ,gCAAgC,KAAK,6GAA6G,CAAC;AAAA,EACjM;AAGA,QAAM,YAAY,KAAK,MAAM,GAAG,GAAI;AACpC,QAAM,mBAAmB,mBAAmB,KAAK,OAAK,EAAE,KAAK,SAAS,CAAC;AAEvE,qBAAmB,QAAQ,OAAK;AAAE,MAAE,YAAY;AAAA,EAAG,CAAC;AACpD,MAAI,kBAAkB;AACpB,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,iFAAiF,CAAC;AAAA,EAC9H,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,kEAAkE,KAAK,iFAAiF,CAAC;AAAA,EACpM;AAGA,QAAM,SAAS,aAAa,KAAK,IAAI;AACrC,QAAM,UAAU,cAAc,KAAK,IAAI;AACvC,MAAI,UAAU,SAAS;AACrB,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,uCAAuC,CAAC,UAAU,SAAS,WAAW,QAAQ,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI,CAAC,GAAG,CAAC;AAAA,EAC1J,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,qCAAqC,KAAK,2FAA2F,CAAC;AAAA,EACjL;AAGA,MAAI,YAAY,KAAK,IAAI,KAAK,oCAAoC,KAAK,IAAI,GAAG;AAC5E,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,iDAAiD,CAAC;AAAA,EAC9F,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,wCAAwC,KAAK,qEAAqE,CAAC;AAAA,EAC9J;AAEA,SAAO,EAAE,WAAW,uBAAuB,iBAAiB,uBAAuB,OAAO,KAAK,IAAI,IAAI,KAAK,GAAG,QAAQ,SAAS,IAAI,SAAS,SAAS,IAAI,YAAY,QAAQ,UAAU,cAAc,SAAS,IAAI,OAAO,KAAK;AACjO;AAGA,SAAS,yBAAyB,MAAiC;AACjE,QAAM,WAA2B,CAAC;AAElC,MAAI,CAAC,KAAK,UAAU;AAClB,aAAS,KAAK,EAAE,UAAU,YAAY,QAAQ,2BAA2B,CAAC;AAC1E,WAAO,EAAE,WAAW,yBAAyB,iBAAiB,4BAA4B,OAAO,GAAG,QAAQ,aAAa,UAAU,cAAc,KAAK;AAAA,EACxJ;AAGA,QAAM,OAAO,gBAAgB,IAAI;AACjC,MAAI,QAAQ;AAGZ,QAAM,UAAU,KAAK,MAAM,6CAA6C,KAAK,CAAC;AAC9E,MAAI,QAAQ,UAAU,GAAG;AACvB,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,GAAG,QAAQ,MAAM,4EAA4E,CAAC;AAAA,EAC1I,WAAW,QAAQ,UAAU,GAAG;AAC9B,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,GAAG,QAAQ,MAAM,kCAAkC,KAAK,uFAAuF,CAAC;AAAA,EAC3L,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,yCAAyC,KAAK,mHAAmH,CAAC;AAAA,EAC9M;AAGA,QAAM,aAAa,KAAK,MAAM,2BAA2B,KAAK,CAAC;AAC/D,QAAM,wBAAwB,WAAW,OAAO,OAAK;AACnD,UAAMA,QAAO,EAAE,QAAQ,YAAY,EAAE,EAAE,KAAK;AAC5C,UAAM,YAAYA,MAAK,MAAM,KAAK,EAAE;AACpC,WAAO,aAAa,MAAM,aAAa;AAAA,EACzC,CAAC;AACD,MAAI,sBAAsB,UAAU,GAAG;AACrC,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,GAAG,sBAAsB,MAAM,uEAAuE,CAAC;AAAA,EACnJ,WAAW,sBAAsB,UAAU,GAAG;AAC5C,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,QAAQ,sBAAsB,MAAM,2CAA2C,KAAK,2EAA2E,CAAC;AAAA,EAC3M,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,UAAU,QAAQ,4DAA4D,KAAK,wFAAwF,CAAC;AAAA,EACxM;AAGA,QAAM,OAAO,KAAK,SAAS,KAAK,QAAQ,YAAY,GAAG,EAAE,QAAQ,QAAQ,GAAG;AAC5E,QAAM,gBAAgB;AACtB,QAAM,eAAe,KAAK,MAAM,aAAa,KAAK,CAAC,GAAG;AACtD,MAAI,eAAe,GAAG;AACpB,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,0DAA0D,CAAC;AAAA,EACvG,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,yCAAyC,KAAK,+GAA+G,CAAC;AAAA,EACzM;AAEA,SAAO,EAAE,WAAW,yBAAyB,iBAAiB,4BAA4B,OAAO,KAAK,IAAI,IAAI,KAAK,GAAG,QAAQ,SAAS,IAAI,SAAS,SAAS,IAAI,YAAY,QAAQ,UAAU,cAAc,SAAS,IAAI,OAAO,KAAK;AACxO;AAGA,SAAS,sBAAsB,MAAiC;AAC9D,QAAM,WAA2B,CAAC;AAClC,MAAI,QAAQ;AAGZ,QAAM,QAAQ,KAAK;AACnB,MAAI,SAAS,MAAM,WAAW,OAAO,MAAM,KAAK,SAAS,MAAM,CAAC,eAAe,KAAK,GAAG;AACrF,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,sBAAsB,MAAM,KAAK,MAAM,eAAe,CAAC;AAAA,EACnG,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,wBAAwB,KAAK,yFAAyF,CAAC;AAAA,EACnK;AAEA,QAAM,OAAO,KAAK,UAAU,QAAQ;AACpC,QAAM,OAAO,KAAK,QAAQ,YAAY,GAAG,EAAE,QAAQ,QAAQ,GAAG;AAG9D,QAAM,oBAAoB,+GAA+G,KAAK,IAAI;AAClJ,MAAI,mBAAmB;AACrB,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,qDAAqD,CAAC;AAAA,EAClG,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,mDAAmD,KAAK,yDAAyD,CAAC;AAAA,EAC7J;AAGA,QAAM,mBAAmB,yCAAyC,KAAK,IAAI,KAAK,yBAAyB,KAAK,IAAI;AAClH,MAAI,kBAAkB;AACpB,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,yDAAyD,CAAC;AAAA,EACtG,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,gDAAgD,KAAK,wEAAwE,CAAC;AAAA,EACzK;AAGA,QAAM,aAAa,kFAAkF,KAAK,QAAQ,OAAO,QAAQ,GAAG;AACpI,MAAI,YAAY;AACd,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,qDAAqD,CAAC;AAAA,EAClG,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,yDAAyD,KAAK,6GAA6G,CAAC;AAAA,EACvN;AAEA,SAAO,EAAE,WAAW,qBAAqB,iBAAiB,sCAAsC,OAAO,KAAK,IAAI,IAAI,KAAK,GAAG,QAAQ,SAAS,IAAI,SAAS,SAAS,IAAI,YAAY,QAAQ,UAAU,cAAc,SAAS,IAAI,OAAO,KAAK;AAC9O;AAGA,SAAS,uBAAuB,MAAiC;AAC/D,QAAM,WAA2B,CAAC;AAElC,MAAI,CAAC,KAAK,UAAU;AAClB,aAAS,KAAK,EAAE,UAAU,YAAY,QAAQ,2BAA2B,CAAC;AAC1E,WAAO,EAAE,WAAW,uBAAuB,iBAAiB,0BAA0B,OAAO,GAAG,QAAQ,aAAa,UAAU,cAAc,KAAK;AAAA,EACpJ;AAGA,QAAM,eAAe,gBAAgB,IAAI;AACzC,QAAM,OAAO,KAAK,SAAS;AAC3B,QAAM,OAAO,aAAa,QAAQ,YAAY,GAAG,EAAE,QAAQ,QAAQ,GAAG;AACtE,MAAI,QAAQ;AAGZ,QAAM,kBAAkB,0BAA0B,KAAK,YAAY;AACnE,MAAI,iBAAiB;AACnB,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,iCAAiC,CAAC;AAAA,EAC9E,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,UAAU,QAAQ,0BAA0B,KAAK,uFAAuF,CAAC;AAAA,EACrK;AAGA,QAAM,cAAc,+CAA+C,KAAK,YAAY;AACpF,MAAI,aAAa;AACf,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,2DAA2D,CAAC;AAAA,EACxG,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,8CAA8C,KAAK,sEAAsE,CAAC;AAAA,EACrK;AAGA,QAAM,YAAY,UAAU,KAAK,YAAY,KAAK;AAClD,MAAI,WAAW;AACb,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,2CAA2C,CAAC;AAAA,EACxF,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,6CAA6C,KAAK,uFAAuF,CAAC;AAAA,EACrL;AAGA,QAAM,YAAY,wDAAwD,KAAK,IAAI,KACjF,4BAA4B,KAAK,IAAI,KACrC,gBAAgB,KAAK,IAAI;AAC3B,MAAI,WAAW;AACb,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,6CAA6C,CAAC;AAAA,EAC1F,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,UAAU,QAAQ,kCAAkC,KAAK,iEAAiE,CAAC;AAAA,EACvJ;AAGA,MAAI,iBAAiB,KAAK,YAAY,GAAG;AACvC,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,kDAAkD,CAAC;AAAA,EAC/F,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,sDAAsD,KAAK,6EAA6E,CAAC;AAAA,EACpL;AAEA,SAAO,EAAE,WAAW,uBAAuB,iBAAiB,0BAA0B,OAAO,KAAK,IAAI,IAAI,KAAK,GAAG,QAAQ,SAAS,IAAI,SAAS,SAAS,IAAI,YAAY,QAAQ,UAAU,cAAc,SAAS,IAAI,OAAO,KAAK;AACpO;AAGA,SAAS,iBAAiB,MAAiC;AACzD,QAAM,WAA2B,CAAC;AAElC,MAAI,CAAC,KAAK,UAAU;AAClB,aAAS,KAAK,EAAE,UAAU,YAAY,QAAQ,2BAA2B,CAAC;AAC1E,WAAO,EAAE,WAAW,gBAAgB,iBAAiB,uBAAuB,OAAO,GAAG,QAAQ,aAAa,UAAU,cAAc,KAAK;AAAA,EAC1I;AAEA,QAAM,OAAO,KAAK,SAAS,KAAK,QAAQ,YAAY,GAAG,EAAE,QAAQ,QAAQ,GAAG;AAC5E,MAAI,QAAQ;AAGZ,QAAM,aAAa,KAAK,MAAM,4CAA4C,KAAK,CAAC;AAChF,QAAM,eAAe,KAAK,MAAM,8HAA8H,KAAK,CAAC;AACpK,QAAM,kBAAkB,WAAW,SAAS,aAAa;AAEzD,MAAI,mBAAmB,GAAG;AACxB,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,GAAG,eAAe,8CAA8C,CAAC;AAAA,EAC7G,WAAW,mBAAmB,GAAG;AAC/B,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,GAAG,eAAe,kCAAkC,CAAC;AAAA,EACjG,WAAW,mBAAmB,GAAG;AAC/B,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,QAAQ,eAAe,qCAAqC,KAAK,gFAAgF,CAAC;AAAA,EAC7L,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,qCAAqC,KAAK,sFAAsF,CAAC;AAAA,EAC7K;AAGA,QAAM,WAAW,KAAK,MAAM,iBAAiB,KAAK,CAAC;AACnD,QAAM,cAAc,CAAC,GAAG,IAAI,IAAI,QAAQ,CAAC;AACzC,MAAI,YAAY,UAAU,GAAG;AAC3B,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,GAAG,YAAY,MAAM,uEAAuE,CAAC;AAAA,EACzI,WAAW,YAAY,WAAW,GAAG;AACnC,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,uCAAuC,KAAK,0FAA0F,CAAC;AAAA,EAClL,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,oCAAoC,KAAK,8EAA8E,CAAC;AAAA,EACnK;AAGA,QAAM,eAAe,KAAK,MAAM,kIAAkI,KAAK,CAAC;AACxK,MAAI,aAAa,UAAU,GAAG;AAC5B,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,GAAG,aAAa,MAAM,kEAAkE,CAAC;AAAA,EACrI,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,gCAAgC,KAAK,4FAA4F,CAAC;AAAA,EAC7K;AAGA,QAAM,QAAQ,KAAK,MAAM,8GAA8G,KAAK,CAAC;AAC7I,MAAI,MAAM,UAAU,GAAG;AACrB,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,GAAG,MAAM,MAAM,yEAAyE,CAAC;AAAA,EACrI,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,wCAAwC,KAAK,4GAA4G,CAAC;AAAA,EACrM;AAEA,SAAO,EAAE,WAAW,gBAAgB,iBAAiB,uBAAuB,OAAO,KAAK,IAAI,IAAI,KAAK,GAAG,QAAQ,SAAS,IAAI,SAAS,SAAS,IAAI,YAAY,QAAQ,UAAU,cAAc,SAAS,IAAI,OAAO,KAAK;AAC1N;AAGA,SAAS,kBAAkB,MAAiC;AAC1D,QAAM,WAA2B,CAAC;AAElC,MAAI,CAAC,KAAK,UAAU;AAClB,aAAS,KAAK,EAAE,UAAU,YAAY,QAAQ,2BAA2B,CAAC;AAC1E,WAAO,EAAE,WAAW,iBAAiB,iBAAiB,0BAA0B,OAAO,GAAG,QAAQ,aAAa,UAAU,cAAc,KAAK;AAAA,EAC9I;AAEA,QAAM,OAAO,KAAK,SAAS;AAC3B,MAAI,QAAQ;AAGZ,QAAM,iBAAiB,KAAK,MAAM,qDAAqD,KAClF,KAAK,MAAM,qDAAqD;AACrE,MAAI,gBAAgB;AAClB,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,wBAAwB,eAAe,CAAC,EAAE,MAAM,GAAG,EAAE,CAAC,GAAG,CAAC;AAGpG,UAAM,eAAe,eAAe,CAAC;AACrC,QAAI,aAAa,SAAS,KAAK,MAAM,GAAG;AACtC,eAAS;AACT,eAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,4DAA4D,CAAC;AAAA,IACzG,OAAO;AACL,eAAS,KAAK,EAAE,UAAU,UAAU,QAAQ,8CAA8C,KAAK,wEAAwE,CAAC;AAAA,IAC1K;AAGA,QAAI,aAAa,WAAW,UAAU,GAAG;AACvC,eAAS;AACT,eAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,2BAA2B,CAAC;AAAA,IACxE,OAAO;AACL,eAAS,KAAK,EAAE,UAAU,UAAU,QAAQ,oCAAoC,KAAK,uCAAuC,CAAC;AAAA,IAC/H;AAAA,EACF,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,8BAA8B,KAAK,kGAAkG,CAAC;AAAA,EAClL;AAGA,QAAM,gBAAgB,KAAK,MAAM,uDAAuD,KAAK,CAAC;AAC9F,MAAI,cAAc,SAAS,GAAG;AAC5B,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,GAAG,cAAc,MAAM,iDAAiD,KAAK,6DAA6D,CAAC;AAAA,EACvL,WAAW,cAAc,WAAW,GAAG;AACrC,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,+CAA+C,CAAC;AAAA,EAC5F;AAEA,SAAO,EAAE,WAAW,iBAAiB,iBAAiB,0BAA0B,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,IAAI,KAAK,CAAC,GAAG,QAAQ,SAAS,IAAI,SAAS,SAAS,IAAI,YAAY,QAAQ,UAAU,cAAc,SAAS,IAAI,OAAO,KAAK;AAC3O;AAYO,SAAS,wBAAwB,aAA0C;AAChF,QAAM,iBAAiB,YAAY,MAAM,+BAA+B,KAAK,CAAC;AAC9E,MAAI,eAAe,WAAW,GAAG;AAC/B,WAAO,EAAE,aAAa,GAAG,WAAW,OAAO,gBAAgB,GAAG,oBAAoB,EAAE;AAAA,EACtF;AAEA,QAAM,MAAM,oBAAI,KAAK;AACrB,QAAM,gBAAgB,IAAI,KAAK,IAAI,QAAQ,IAAI,KAAK,KAAK,KAAK,KAAK,GAAI;AAGvE,QAAM,YAAoC,CAAC;AAC3C,MAAI,cAAc;AAClB,QAAM,aAAa,oBAAI,IAAY;AAEnC,aAAW,SAAS,gBAAgB;AAClC,UAAM,UAAU,MAAM,QAAQ,kBAAkB,EAAE,EAAE,KAAK;AACzD,UAAM,OAAO,IAAI,KAAK,OAAO;AAC7B,QAAI,MAAM,KAAK,QAAQ,CAAC,EAAG;AAE3B,UAAM,SAAS,KAAK,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC;AAC9C,cAAU,MAAM,KAAK,UAAU,MAAM,KAAK,KAAK;AAE/C,QAAI,QAAQ,eAAe;AACzB;AACA,iBAAW,IAAI,MAAM;AAAA,IACvB;AAAA,EACF;AAGA,QAAM,iBAAiB,OAAO,OAAO,SAAS,EAAE,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC;AACzE,QAAM,cAAc,KAAK,IAAI,GAAG,OAAO,OAAO,SAAS,CAAC;AACxD,QAAM,YAAY,kBAAkB,KAAK,cAAc,iBAAiB;AAExE,MAAI;AACJ,MAAI,WAAW;AACb,UAAM,SAAS,OAAO,QAAQ,SAAS,EAAE,KAAK,CAAC,CAAC,EAAE,KAAK,MAAM,UAAU,WAAW,EAAG,CAAC;AACtF,oBAAgB,GAAG,WAAW,OAAO,cAAc,4BAA4B,MAAM;AAAA,EACvF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,oBAAoB,WAAW;AAAA,EACjC;AACF;AAIA,IAAM,qBAAqB;AAE3B,IAAM,wBAAwB;AAOvB,SAAS,2BAA2B,aAAqB,QAAgB,QAAgB,GAAa;AAC3G,QAAM,YAAY,YAAY,MAAM,0BAA0B,KAAK,CAAC;AACpE,QAAM,aAAiD,CAAC;AACxD,QAAM,cAAc,OAAO,QAAQ,UAAU,EAAE,EAAE,YAAY;AAE7D,aAAW,SAAS,WAAW;AAC7B,UAAM,WAAW,MAAM,MAAM,sBAAsB;AACnD,QAAI,CAAC,SAAU;AACf,UAAM,MAAM,SAAS,CAAC,EAAE,KAAK;AAG7B,QAAI;AACF,YAAM,SAAS,IAAI,IAAI,GAAG;AAC1B,YAAM,YAAY,OAAO,SAAS,QAAQ,UAAU,EAAE,EAAE,YAAY;AACpE,UAAI,cAAc,YAAa;AAG/B,UAAI,OAAO,aAAa,OAAO,OAAO,aAAa,GAAI;AAEvD,YAAM,OAAO,OAAO,SAAS,YAAY;AAGzC,UAAI,sBAAsB,KAAK,IAAI,EAAG;AAGtC,YAAM,WAAW,KAAK,MAAM,GAAG,EAAE,OAAO,OAAO;AAC/C,YAAM,aAAa,mBAAmB,KAAK,IAAI;AAC/C,YAAM,aAAa,SAAS,UAAU;AAEtC,UAAI,CAAC,cAAc,CAAC,WAAY;AAAA,IAClC,QAAQ;AACN;AAAA,IACF;AAEA,UAAM,eAAe,MAAM,MAAM,8BAA8B;AAC/D,UAAM,UAAU,eAAe,aAAa,CAAC,EAAE,KAAK,IAAI;AAExD,eAAW,KAAK,EAAE,KAAK,QAAQ,CAAC;AAAA,EAClC;AAGA,aAAW,KAAK,CAAC,GAAG,MAAM;AACxB,QAAI,EAAE,WAAW,EAAE,QAAS,QAAO,EAAE,QAAQ,cAAc,EAAE,OAAO;AACpE,QAAI,EAAE,QAAS,QAAO;AACtB,QAAI,EAAE,QAAS,QAAO;AACtB,WAAO;AAAA,EACT,CAAC;AAED,SAAO,WAAW,MAAM,GAAG,KAAK,EAAE,IAAI,OAAK,EAAE,GAAG;AAClD;AAOO,SAAS,qBAAqB,aAAoC;AACvE,MAAI,CAAC,YAAY,SAAS,eAAe,EAAG,QAAO;AAEnD,QAAM,cAAc,YAAY,MAAM,2DAA2D,KAAK,CAAC;AACvG,MAAI,YAAY,WAAW,EAAG,QAAO;AAErC,QAAM,OAAO,YAAY,IAAI,WAAS;AACpC,UAAM,QAAQ,MAAM,MAAM,sBAAsB;AAChD,WAAO,QAAQ,MAAM,CAAC,EAAE,KAAK,IAAI;AAAA,EACnC,CAAC,EAAE,OAAO,OAAO;AAGjB,QAAM,YAAY,KAAK,KAAK,OAAK,qBAAqB,KAAK,CAAC,CAAC;AAC7D,SAAO,aAAa,KAAK,CAAC,KAAK;AACjC;AAGA,SAAS,qBAAqB,MAAiC;AAC7D,QAAM,WAA2B,CAAC;AAClC,QAAM,UAAU,KAAK;AACrB,MAAI,QAAQ;AAEZ,MAAI,CAAC,WAAW,QAAQ,WAAW,KAAK;AACtC,aAAS,KAAK,EAAE,UAAU,UAAU,QAAQ,mDAAmD,KAAK,iFAAiF,CAAC;AACtL,WAAO,EAAE,WAAW,oBAAoB,iBAAiB,+BAA+B,OAAO,GAAG,QAAQ,QAAQ,UAAU,cAAc,KAAK;AAAA,EACjJ;AAEA,QAAM,WAAW,wBAAwB,QAAQ,IAAI;AAErD,MAAI,SAAS,mBAAmB,GAAG;AACjC,aAAS,KAAK,EAAE,UAAU,UAAU,QAAQ,+BAA+B,KAAK,mEAAmE,CAAC;AACpJ,WAAO,EAAE,WAAW,oBAAoB,iBAAiB,+BAA+B,OAAO,GAAG,QAAQ,QAAQ,UAAU,cAAc,KAAK;AAAA,EACjJ;AAEA,WAAS;AACT,WAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,GAAG,SAAS,cAAc,4BAA4B,CAAC;AAGjG,QAAM,iBAAiB,SAAS,YAAY,SAAS,qBAAqB,SAAS;AAEnF,MAAI,SAAS,WAAW;AACtB,aAAS,KAAK,EAAE,UAAU,UAAU,QAAQ,SAAS,eAAgB,KAAK,6FAA6F,CAAC;AAAA,EAC1K;AAEA,MAAI,kBAAkB,IAAI;AACxB,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,GAAG,cAAc,IAAI,SAAS,YAAY,mBAAmB,eAAe,gDAAgD,CAAC;AAAA,EACzK,WAAW,kBAAkB,IAAI;AAC/B,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,GAAG,cAAc,IAAI,SAAS,YAAY,mBAAmB,eAAe,mCAAmC,CAAC;AAAA,EAC5J,WAAW,kBAAkB,GAAG;AAC9B,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,GAAG,cAAc,IAAI,SAAS,YAAY,mBAAmB,eAAe,mBAAmB,CAAC;AAAA,EAC5I,WAAW,kBAAkB,GAAG;AAC9B,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,QAAQ,cAAc,IAAI,SAAS,YAAY,qBAAqB,iBAAiB,oBAAoB,KAAK,yEAAyE,CAAC;AAAA,EACnO,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,UAAU,QAAQ,wCAAwC,KAAK,0DAA0D,CAAC;AAAA,EACtJ;AAEA,SAAO,EAAE,WAAW,oBAAoB,iBAAiB,+BAA+B,OAAO,KAAK,IAAI,IAAI,KAAK,GAAG,QAAQ,SAAS,IAAI,SAAS,SAAS,IAAI,YAAY,QAAQ,UAAU,cAAc,SAAS,IAAI,OAAO,KAAK;AACtO;AAGA,SAAS,oBAAoB,MAAiC;AAC5D,QAAM,WAA2B,CAAC;AAElC,MAAI,CAAC,KAAK,UAAU;AAClB,aAAS,KAAK,EAAE,UAAU,YAAY,QAAQ,2BAA2B,CAAC;AAC1E,WAAO,EAAE,WAAW,mBAAmB,iBAAiB,2BAA2B,OAAO,GAAG,QAAQ,aAAa,UAAU,cAAc,KAAK;AAAA,EACjJ;AAGA,QAAM,eAAe,gBAAgB,IAAI;AACzC,QAAM,OAAO,KAAK,SAAS;AAC3B,QAAM,gBAAgB,aAAa,MAAM,sEAAsE,KAAK,CAAC;AACrH,MAAI,QAAQ;AAEZ,MAAI,cAAc,WAAW,GAAG;AAC9B,aAAS,KAAK,EAAE,UAAU,YAAY,QAAQ,oDAAoD,KAAK,+DAA+D,CAAC;AACvK,WAAO,EAAE,WAAW,mBAAmB,iBAAiB,2BAA2B,OAAO,GAAG,QAAQ,QAAQ,UAAU,cAAc,KAAK;AAAA,EAC5I;AAEA,QAAM,gBAAgB,cAAc,KAAK,GAAG;AAC5C,QAAM,iBAAiB,cAAc,YAAY;AAGjD,QAAM,kBAAkB,cAAc,MAAM,mBAAmB,KAAK,CAAC;AACrE,QAAM,mBAAmB,IAAI,IAAI,gBAAgB,IAAI,OAAK,EAAE,QAAQ,WAAW,EAAE,EAAE,YAAY,CAAC,CAAC;AAEjG,MAAI,iBAAiB,QAAQ,IAAI;AAC/B,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,GAAG,iBAAiB,IAAI,qDAAqD,CAAC;AAAA,EAC1H,WAAW,iBAAiB,QAAQ,GAAG;AACrC,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,GAAG,iBAAiB,IAAI,kCAAkC,CAAC;AAAA,EACvG,OAAO;AACL,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,QAAQ,iBAAiB,IAAI,sBAAsB,KAAK,uEAAuE,CAAC;AAAA,EAC3K;AAGA,QAAM,WAAW,CAAC,QAAQ,OAAO,QAAQ,gBAAgB,UAAU,WAAW,aAAa,eAAe,WAAW,cAAc;AACnI,QAAM,gBAAgB,SAAS,OAAO,OAAK,eAAe,SAAS,IAAI,CAAC,GAAG,CAAC;AAC5E,MAAI,cAAc,UAAU,GAAG;AAC7B,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,2BAA2B,cAAc,MAAM,qBAAqB,CAAC;AAAA,EACjH,WAAW,cAAc,UAAU,GAAG;AACpC,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,gCAAgC,cAAc,MAAM,sBAAsB,KAAK,wEAAwE,CAAC;AAAA,EACnM,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,UAAU,QAAQ,gCAAgC,cAAc,MAAM,mBAAmB,KAAK,mGAAmG,CAAC;AAAA,EAC9N;AAGA,QAAM,eAAe,CAAC,YAAY,iBAAiB,gBAAgB,UAAU,SAAS,eAAe,WAAW;AAChH,QAAM,oBAAoB,aAAa,OAAO,OAAK,eAAe,SAAS,IAAI,CAAC,GAAG,CAAC;AACpF,MAAI,kBAAkB,UAAU,GAAG;AACjC,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,sBAAsB,kBAAkB,MAAM,oBAAoB,CAAC;AAAA,EAC/G,WAAW,kBAAkB,UAAU,GAAG;AACxC,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,2BAA2B,kBAAkB,MAAM,qBAAqB,KAAK,4FAA4F,CAAC;AAAA,EACrN,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,UAAU,QAAQ,6DAA6D,KAAK,oFAAoF,CAAC;AAAA,EACrM;AAGA,QAAM,eAAe,aAAa,KAAK,aAAa;AACpD,MAAI,cAAc;AAChB,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,4DAA4D,CAAC;AAAA,EACzG,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,uCAAuC,KAAK,uFAAuF,CAAC;AAAA,EAC/K;AAGA,QAAM,cAAc,CAAC,gBAAgB,iBAAiB,WAAW,WAAW,WAAW,WAAW,WAAW,kBAAkB,SAAS,WAAW,UAAU,SAAS,SAAS,UAAU,WAAW;AACpM,QAAM,aAAa,YAAY,OAAO,OAAK,eAAe,SAAS,IAAI,CAAC,GAAG,CAAC;AAC5E,MAAI,WAAW,UAAU,GAAG;AAC1B,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,GAAG,WAAW,MAAM,gCAAgC,WAAW,KAAK,IAAI,CAAC,GAAG,CAAC;AAAA,EACzH,WAAW,WAAW,UAAU,GAAG;AACjC,aAAS;AACT,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,QAAQ,WAAW,MAAM,+BAA+B,KAAK,8FAA8F,CAAC;AAAA,EACvM,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,UAAU,QAAQ,QAAQ,WAAW,MAAM,4CAA4C,KAAK,gHAAgH,CAAC;AAAA,EACzO;AAEA,SAAO,EAAE,WAAW,mBAAmB,iBAAiB,2BAA2B,OAAO,KAAK,IAAI,IAAI,KAAK,GAAG,QAAQ,SAAS,IAAI,SAAS,SAAS,IAAI,YAAY,QAAQ,UAAU,cAAc,SAAS,IAAI,OAAO,KAAK;AACjO;AAGA,SAAS,qBAAqB,MAAiC;AAC7D,QAAM,WAA2B,CAAC;AAElC,MAAI,CAAC,KAAK,UAAU;AAClB,aAAS,KAAK,EAAE,UAAU,YAAY,QAAQ,2BAA2B,CAAC;AAC1E,WAAO,EAAE,WAAW,oBAAoB,iBAAiB,oBAAoB,OAAO,GAAG,QAAQ,aAAa,UAAU,cAAc,KAAK;AAAA,EAC3I;AAEA,QAAM,eAAe,gBAAgB,IAAI;AACzC,QAAM,gBAAgB,aAAa,MAAM,sEAAsE,KAAK,CAAC;AACrH,MAAI,QAAQ;AAEZ,MAAI,cAAc,WAAW,GAAG;AAC9B,aAAS,KAAK,EAAE,UAAU,YAAY,QAAQ,qDAAqD,KAAK,oGAAoG,CAAC;AAC7M,WAAO,EAAE,WAAW,oBAAoB,iBAAiB,oBAAoB,OAAO,GAAG,QAAQ,QAAQ,UAAU,cAAc,KAAK;AAAA,EACtI;AAEA,QAAM,gBAAgB,cAAc,KAAK,GAAG;AAC5C,QAAM,iBAAiB,cAAc,YAAY;AAGjD,QAAM,mBAAmB,0BAA0B,KAAK,cAAc;AACtE,QAAM,uBAAuB,mBAAmB,KAAK,aAAa;AAClE,QAAM,eAAe,oBAAoB;AAEzC,MAAI,CAAC,cAAc;AACjB,aAAS,KAAK,EAAE,UAAU,UAAU,QAAQ,+FAA+F,KAAK,iIAAiI,CAAC;AAClR,WAAO,EAAE,WAAW,oBAAoB,iBAAiB,oBAAoB,OAAO,GAAG,QAAQ,QAAQ,UAAU,cAAc,KAAK;AAAA,EACtI;AAGA,WAAS;AACT,WAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,0FAA0F,CAAC;AAGrI,QAAM,iBAAiB,iBAAiB,KAAK,cAAc;AAC3D,QAAM,WAAW,WAAW,KAAK,cAAc;AAC/C,MAAI,kBAAkB,UAAU;AAC9B,aAAS;AACT,UAAM,aAAa,kBAAkB,WAAW,0BAA0B,iBAAiB,gBAAgB;AAC3G,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,kBAAkB,UAAU,2CAA2C,CAAC;AAAA,EACpH,OAAO;AACL,aAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,yDAAyD,KAAK,gHAAgH,CAAC;AAAA,EAC1N;AAGA,MAAI,KAAK,cAAc,KAAK,WAAW,SAAS,GAAG;AACjD,UAAM,WAAW,KAAK,WAAW,IAAI,OAAK,EAAE,IAAI,EAAE,KAAK,IAAI;AAC3D,UAAM,mBAAmB,0BAA0B,KAAK,QAAQ,KAAK,mBAAmB,KAAK,QAAQ;AACrG,QAAI,kBAAkB;AACpB,eAAS;AACT,eAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,mFAAmF,CAAC;AAAA,IAChI,OAAO;AACL,eAAS,KAAK,EAAE,UAAU,OAAO,QAAQ,sEAAsE,KAAK,4FAA4F,CAAC;AAAA,IACnN;AAAA,EACF,OAAO;AAEL,aAAS,KAAK,EAAE,UAAU,QAAQ,QAAQ,+DAA+D,CAAC;AAAA,EAC5G;AAEA,SAAO,EAAE,WAAW,oBAAoB,iBAAiB,oBAAoB,OAAO,KAAK,IAAI,IAAI,KAAK,GAAG,QAAQ,SAAS,IAAI,SAAS,SAAS,IAAI,YAAY,QAAQ,UAAU,cAAc,SAAS,IAAI,OAAO,KAAK;AAC3N;AAIO,SAAS,sBAAsB,MAAgC;AACpE,QAAM,OAAO,KAAK,UAAU,QAAQ;AACpC,QAAM,OAAO,KAAK,QAAQ,YAAY,GAAG,EAAE,QAAQ,QAAQ,GAAG;AAG9D,QAAM,gBAAgB,KAAK,MAAM,sEAAsE,KAAK,CAAC;AAC7G,QAAM,gBAAgB,cAAc,KAAK,GAAG,EAAE,YAAY;AAC1D,QAAM,cAAc,CAAC,gBAAgB,iBAAiB,WAAW,WAAW,WAAW,WAAW,WAAW,kBAAkB,SAAS,SAAS;AACjJ,QAAM,mBAAmB,YAAY;AAAA,IAAO,OAC1C,cAAc,SAAS,IAAI,CAAC,GAAG,KAAK,cAAc,SAAS,YAAY,CAAC,GAAG;AAAA,EAC7E;AAGA,QAAM,cAAc,KAAK,MAAM,+BAA+B,KAAK,CAAC;AACpE,QAAM,gBAAgB,YAAY,OAAO,OAAK;AAC5C,UAAM,OAAO,EAAE,MAAM,gBAAgB,IAAI,CAAC,KAAK;AAC/C,WAAO,KAAK,WAAW,GAAG,KAAK,KAAK,SAAS,KAAK,MAAM;AAAA,EAC1D,CAAC;AACD,QAAM,gBAAgB,YAAY,OAAO,OAAK;AAC5C,UAAM,OAAO,EAAE,MAAM,gBAAgB,IAAI,CAAC,KAAK;AAC/C,WAAO,KAAK,WAAW,MAAM,KAAK,CAAC,KAAK,SAAS,KAAK,MAAM;AAAA,EAC9D,CAAC;AAGD,QAAM,cAAc,KAAK,WAAW,QAAQ,IAAI,YAAY;AAC5D,QAAM,aAAa,CAAC,UAAU,aAAa,iBAAiB,aAAa,SAAS;AAClF,QAAM,oBAAoB,WAAW,OAAO,OAAK,WAAW,SAAS,CAAC,CAAC;AACvE,QAAM,kBAAkB,kBAAkB,OAAO,OAAK;AACpD,UAAM,eAAe,IAAI,OAAO,kBAAkB,CAAC,8CAA8C,GAAG;AACpG,UAAM,QAAQ,aAAa,KAAK,KAAK,WAAW,QAAQ,EAAE;AAC1D,QAAI,CAAC,MAAO,QAAO;AACnB,UAAM,UAAU,MAAM,CAAC;AACvB,QAAI,qBAAqB,KAAK,OAAO,EAAG,QAAO;AAC/C,WAAO,wBAAwB,KAAK,OAAO;AAAA,EAC7C,CAAC;AAGD,QAAM,eAAe,KAAK,MAAM,qCAAqC,KAAK,CAAC,GAAG,IAAI,OAAK,EAAE,QAAQ,YAAY,EAAE,CAAC;AAChH,QAAM,mBAAmB,YAAY,OAAO,OAAK,EAAE,SAAS,GAAG,KAAK,8DAA8D,KAAK,CAAC,CAAC;AACzI,QAAM,WAAW,KAAK,MAAM,YAAY,KAAK,CAAC,GAAG;AAGjD,QAAM,SAAS,KAAK,MAAM,cAAc,KAAK,CAAC;AAC9C,QAAM,gBAAgB,OAAO,OAAO,SAAO,eAAe,KAAK,GAAG,CAAC;AAGnE,QAAM,iBAAiB,CAAC,QAAQ,WAAW,OAAO,UAAU,UAAU,WAAW,MAAM;AACvF,QAAM,gBAAgB,eAAe,OAAO,QAAM,IAAI,OAAO,IAAI,EAAE,UAAU,GAAG,EAAE,KAAK,IAAI,CAAC;AAE5F,SAAO;AAAA,IACL,QAAQ,KAAK;AAAA,IACb,UAAU,KAAK;AAAA,IACf,iBAAiB,KAAK;AAAA,IACtB,sBAAsB,KAAK,KAAK,EAAE;AAAA,IAClC,WAAW,KAAK,aAAa;AAAA,IAC7B,iBAAiB,KAAK,WAAW,CAAC,eAAe,KAAK,OAAO,IAAI,KAAK,QAAQ,SAAS;AAAA,IACvF,iBAAiB,KAAK,SAAS,WAAW,OAAO,CAAC,eAAe,KAAK,OAAO,IAAK,KAAK,QAAQ,KAAK,SAAU;AAAA,IAC9G,mBAAmB,KAAK,aAAa,CAAC,eAAe,KAAK,SAAS,IAAI,KAAK,UAAU,SAAS;AAAA,IAC/F,qBAAqB,KAAK,WAAW,QAAQ,IAAI,MAAM,GAAG,GAAG;AAAA,IAC7D,wBAAwB;AAAA,IACxB,6BAA6B;AAAA,IAC7B,oBAAoB;AAAA,IACpB,oBAAoB,cAAc;AAAA,IAClC,iBAAiB,KAAK,SAAS,UAAU;AAAA,IACzC,iBAAiB,KAAK,SAAS,WAAW,MAAM,KAAK,QAAQ,KAAK,SAAS;AAAA,IAC3E,gBAAgB,KAAK,YAAY,UAAU;AAAA,IAC3C,qBAAqB,cAAc;AAAA,IACnC,qBAAqB,cAAc;AAAA,IACnC,yBAAyB,iBAAiB;AAAA,IAC1C,UAAU;AAAA,IACV,sBAAsB,sCAAsC,KAAK,IAAI;AAAA,IACrE,WAAW,8BAA8B,KAAK,IAAI;AAAA,IAClD,YAAY,MAAM;AAChB,YAAM,aAAa,sDAAsD,KAAK,IAAI;AAClF,UAAI,CAAC,WAAY,QAAO;AAExB,aAAO,cAAc,KAAK,IAAI,KAAK,eAAe,KAAK,IAAI,KACzD,+CAA+C,KAAK,IAAI;AAAA,IAC5D,GAAG;AAAA,IACH,aAAa,2FAA2F,KAAK,IAAI;AAAA,IACjH,gBAAgB,8BAA8B,KAAK,IAAI;AAAA,IACvD,kBAAkB,0DAA0D,KAAK,IAAI;AAAA,IACrF,yBAAyB;AAAA,IACzB,WAAW,OAAO;AAAA,IAClB,oBAAoB,cAAc;AAAA,IAClC,eAAe,mBAAmB,KAAK,IAAI;AAAA,IAC3C,UAAU,gBAAgB,KAAK,IAAI;AAAA,IACnC,iBAAiB,sCAAsC,KAAK,IAAI;AAAA,IAChE,SAAS,aAAa,KAAK,IAAI;AAAA,IAC/B,YAAY,gBAAgB,KAAK,IAAI;AAAA,IACrC,kBAAkB,wDAAwD,KAAK,IAAI;AAAA,IACnF,gBAAgB,2HAA2H,KAAK,IAAI;AAAA,IACpJ,wBAAwB,yEAAyE,KAAK,IAAI;AAAA,IAC1G,kBAAkB,oEAAoE,KAAK,IAAI;AAAA;AAAA,IAE/F,0BAA0B,gBAAgB,KAAK,IAAI;AAAA,IACnD,qBAAqB,KAAK,MAAM,cAAc,KAAK,CAAC,GAAG;AAAA,IACvD,oBAAoB,KAAK,YAAY,MAAM,MAAM,SAAS,KAAK,CAAC,GAAG;AAAA,IACnE,cAAc,CAAC,EAAE,KAAK,WAAW,KAAK,QAAQ,WAAW,OAAO,CAAC,eAAe,KAAK,OAAO;AAAA,IAC5F,cAAc,KAAK,MAAM,eAAe,KAAK,CAAC,GAAG;AAAA,IACjD,qBAAqB,KAAK,MAAM,YAAY,KAAK,CAAC,GAAG;AAAA,IACrD,uBAAuB,KAAK,MAAM,YAAY,KAAK,CAAC,GAAG;AAAA,IACvD,2BAA2B,KAAK,MAAM,oDAAoD,KAAK,CAAC,GAAG;AAAA,IACnG,YAAY,CAAC,EAAE,KAAK,SAAS,KAAK,MAAM,WAAW,OAAO,CAAC,eAAe,KAAK,KAAK;AAAA,IACpF,mBAAmB,0BAA0B,KAAK,IAAI;AAAA,IACtD,wBAAwB,KAAK,MAAM,qCAAqC,KAAK,CAAC,GAAG;AAAA,IACjF,eAAe,6BAA6B,KAAK,IAAI;AAAA,IACrD,oBAAoB,2BAA2B,KAAK,IAAI,KAAK,yBAAyB,KAAK,IAAI;AAAA,IAC/F,+BAA+B,MAAM;AACnC,YAAM,WAAW,wBAAwB,KAAK,YAAY,QAAQ,EAAE;AACpE,aAAO,SAAS,YAAY,SAAS,qBAAqB,SAAS;AAAA,IACrE,GAAG;AAAA;AAAA,IAEH,sBAAsB,0BAA0B,KAAK,cAAc,KAAK,GAAG,CAAC,KAAK,mBAAmB,KAAK,cAAc,KAAK,GAAG,CAAC;AAAA,IAChI,2BAA2B,cAAc,KAAK,GAAG,EAAE,MAAM,yBAAyB,KAAK,CAAC,GAAG;AAAA;AAAA,IAE3F,mBAAmB,KAAK,YAAY,UAAU;AAAA,IAC9C,kBAAkB,KAAK,YAAY,IAAI,OAAK,EAAE,YAAY,EAAE,EAAE,OAAO,OAAO,KAAK,CAAC;AAAA,IAClF,2BAA2B,MAAM;AAC/B,UAAI,CAAC,KAAK,cAAc,KAAK,WAAW,WAAW,EAAG,QAAO,CAAC;AAC9D,YAAM,WAAW,KAAK,WAAW,IAAI,OAAK,EAAE,IAAI,EAAE,KAAK,IAAI;AAC3D,YAAM,SAAS,SAAS,MAAM,sEAAsE,KAAK,CAAC;AAC1G,YAAM,aAAa,OAAO,KAAK,GAAG,EAAE,YAAY;AAChD,YAAM,QAAQ,CAAC,gBAAgB,iBAAiB,WAAW,WAAW,WAAW,WAAW,WAAW,kBAAkB,SAAS,WAAW,QAAQ;AACrJ,aAAO,MAAM,OAAO,OAAK,WAAW,SAAS,IAAI,CAAC,GAAG,CAAC;AAAA,IACxD,GAAG;AAAA,IACH,gCAAgC,MAAM;AACpC,UAAI,CAAC,KAAK,cAAc,KAAK,WAAW,WAAW,EAAG,QAAO;AAC7D,YAAM,WAAW,KAAK,WAAW,IAAI,OAAK,EAAE,IAAI,EAAE,KAAK,IAAI;AAC3D,YAAM,SAAS,SAAS,MAAM,qCAAqC,KAAK,CAAC,GAAG,IAAI,OAAK,EAAE,QAAQ,YAAY,EAAE,CAAC;AAC9G,aAAO,MAAM,OAAO,OAAK,EAAE,SAAS,GAAG,KAAK,8DAA8D,KAAK,CAAC,CAAC,EAAE;AAAA,IACrH,GAAG;AAAA,IACH,+BAA+B,MAAM;AACnC,UAAI,CAAC,KAAK,cAAc,KAAK,WAAW,WAAW,EAAG,QAAO;AAC7D,YAAM,WAAW,KAAK,WAAW,IAAI,OAAK,EAAE,IAAI,EAAE,KAAK,IAAI;AAC3D,aAAO,WAAW,KAAK,QAAQ,KAAK,yBAAyB,KAAK,QAAQ;AAAA,IAC5E,GAAG;AAAA,EACL;AACF;AAQO,SAAS,kBAAkB,MAAmC;AACnE,SAAO;AAAA,IACL,aAAa,IAAI;AAAA,IACjB,kBAAkB,IAAI;AAAA,IACtB,cAAc,IAAI;AAAA,IAClB,eAAe,IAAI;AAAA,IACnB,uBAAuB,IAAI;AAAA,IAC3B,eAAe,IAAI;AAAA,IACnB,gBAAgB,IAAI;AAAA,IACpB,kBAAkB,IAAI;AAAA,IACtB,qBAAqB,IAAI;AAAA,IACzB,kBAAkB,IAAI;AAAA,IACtB,sBAAsB,IAAI;AAAA,IAC1B,yBAAyB,IAAI;AAAA,IAC7B,aAAa,IAAI;AAAA,IACjB,6BAA6B,IAAI;AAAA,IACjC,wBAAwB,IAAI;AAAA,IAC5B,yBAAyB,IAAI;AAAA,IAC7B,sBAAsB,IAAI;AAAA,IAC1B,uBAAuB,IAAI;AAAA,IAC3B,iBAAiB,IAAI;AAAA,IACrB,kBAAkB,IAAI;AAAA,IACtB,qBAAqB,IAAI;AAAA,IACzB,oBAAoB,IAAI;AAAA,IACxB,qBAAqB,IAAI;AAAA,EAC3B;AACF;;;AC/+DA,IAAM,UAAkC;AAAA;AAAA,EAEtC,UAAU;AAAA,EACV,eAAe;AAAA,EACf,mBAAmB;AAAA,EACnB,YAAY;AAAA,EACZ,oBAAoB;AAAA,EACpB,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,eAAe;AAAA,EACf,kBAAkB;AAAA,EAClB,eAAe;AAAA;AAAA,EAEf,mBAAmB;AAAA,EACnB,sBAAsB;AAAA,EACtB,UAAU;AAAA,EACV,2BAA2B;AAAA,EAC3B,qBAAqB;AAAA,EACrB,uBAAuB;AAAA,EACvB,mBAAmB;AAAA,EACnB,qBAAqB;AAAA,EACrB,cAAc;AAAA,EACd,eAAe;AAAA,EACf,kBAAkB;AAAA,EAClB,iBAAiB;AAAA,EACjB,kBAAkB;AACpB;AAEO,SAAS,sBAAsB,UAAqC;AACzE,MAAI,cAAc;AAClB,MAAI,cAAc;AAElB,aAAW,KAAK,UAAU;AACxB,UAAM,SAAS,QAAQ,EAAE,SAAS,KAAK;AACvC,mBAAgB,EAAE,QAAQ,KAAM,SAAS;AACzC,mBAAe;AAAA,EACjB;AAEA,MAAI,gBAAgB,EAAG,QAAO;AAC9B,SAAO,KAAK,MAAM,cAAc,WAAW;AAC7C;;;ACrBA,IAAM,iBAAiB;AAAA;AAAA,EAErB;AAAA;AAAA,EAEA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AACF;AAQO,SAAS,WAAW,MAAuB;AAEhD,QAAM,OAAO,KACV,QAAQ,+BAA+B,EAAE,EACzC,QAAQ,6BAA6B,EAAE,EACvC,QAAQ,YAAY,GAAG,EACvB,QAAQ,QAAQ,GAAG,EACnB,KAAK;AAER,MAAI,KAAK,UAAU,IAAK,QAAO;AAE/B,SAAO,eAAe,KAAK,CAAC,YAAY,QAAQ,KAAK,IAAI,CAAC;AAC5D;AAMO,SAAS,kBAAkB,MAAuC;AACvE,MAAI,CAAC,WAAW,IAAI,EAAG,QAAO,EAAE,QAAQ,UAAU,WAAW,KAAK;AAGlE,QAAM,oBAAwC;AAAA,IAC5C,CAAC,iBAAiB,MAAM;AAAA,IACxB,CAAC,YAAY,MAAM;AAAA,IACnB,CAAC,4BAA4B,KAAK;AAAA,IAClC,CAAC,eAAe,SAAS;AAAA,IACzB,CAAC,mBAAmB,OAAO;AAAA,IAC3B,CAAC,yDAAyD,OAAO;AAAA,IACjE,CAAC,wDAAwD,OAAO;AAAA,IAChE,CAAC,oDAAoD,MAAM;AAAA,EAC7D;AAEA,aAAW,CAAC,SAAS,SAAS,KAAK,mBAAmB;AACpD,QAAI,QAAQ,KAAK,IAAI,EAAG,QAAO,EAAE,QAAQ,cAAc,UAAU;AAAA,EACnE;AAEA,SAAO,EAAE,QAAQ,cAAc,WAAW,KAAK;AACjD;AAaA,eAAsB,kBACpB,KACA,SAC6B;AAE7B,MAAI;AACJ,MAAI;AAEF,UAAM,MAAM;AACZ,gBAAY,MAAM;AAAA;AAAA,MAA0B;AAAA;AAAA,EAC9C,QAAQ;AACN,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,SAAS,WAAW;AAEpC,MAAI,UAAe;AAEnB,MAAI;AACF,cAAU,MAAM,UAAU,OAAO;AAAA,MAC/B,UAAU;AAAA,MACV,MAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF,CAAC;AAED,UAAM,OAAO,MAAM,QAAQ,QAAQ;AAGnC,UAAM,KAAK,uBAAuB,IAAI;AAEtC,SAAK,GAAG,WAAW,CAAC,QAAa;AAC/B,YAAM,OAAO,IAAI,aAAa;AAC9B,UAAI,CAAC,SAAS,QAAQ,SAAS,YAAY,EAAE,SAAS,IAAI,GAAG;AAC3D,YAAI,MAAM;AAAA,MACZ,OAAO;AACL,YAAI,SAAS;AAAA,MACf;AAAA,IACF,CAAC;AAED,UAAM,KAAK,aAAa,wBAAwB;AAChD,UAAM,KAAK,KAAK,KAAK,EAAE,WAAW,gBAAgB,QAAQ,CAAC;AAG3D,QAAI;AACF,YAAM,KAAK;AAAA,QACT;AAAA,QACA,EAAE,SAAS,IAAK;AAAA,MAClB;AAAA,IACF,QAAQ;AAAA,IAER;AAEA,UAAM,OAAO,MAAM,KAAK,QAAQ;AAChC,UAAM,WAAW,KAAK,IAAI;AAE1B,WAAO;AAAA,MACL,MAAM,KAAK,MAAM,GAAG,GAAM;AAAA,MAC1B,QAAQ;AAAA,MACR;AAAA,IACF;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT,UAAE;AACA,QAAI,SAAS;AACX,UAAI;AACF,cAAM,QAAQ,MAAM;AAAA,MACtB,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AACF;;;AChKO,IAAM,mBAA2C;AAAA,EACtD,iBAAiB;AAAA,EACjB,8BAA8B;AAAA,EAC9B,sBAAsB;AAAA,EACtB,yBAAyB;AAAA,EACzB,8BAA8B;AAAA,EAC9B,8BAA8B;AAAA,EAC9B,8BAA8B;AAAA,EAC9B,kCAAkC;AAAA,EAClC,iCAAiC;AAAA,EACjC,kCAAkC;AAAA,EAClC,6BAA6B;AAAA,EAC7B,wBAAwB;AAAA,EACxB,iBAAiB;AAAA,EACjB,+BAA+B;AAAA,EAC/B,uBAAuB;AAAA,EACvB,4BAA4B;AAAA,EAC5B,sCAAsC;AAAA,EACtC,0BAA0B;AAAA,EAC1B,uBAAuB;AAAA,EACvB,0BAA0B;AAAA,EAC1B,+BAA+B;AAAA,EAC/B,2BAA2B;AAAA,EAC3B,oBAAoB;AACtB;AAIO,SAAS,cAAc,OAAuB;AACnD,MAAI,UAAU,EAAG,QAAO;AACxB,MAAI,UAAU,EAAG,QAAO;AACxB,MAAI,UAAU,EAAG,QAAO;AACxB,MAAI,UAAU,EAAG,QAAO;AACxB,MAAI,SAAS,EAAG,QAAO;AACvB,MAAI,UAAU,EAAG,QAAO;AACxB,MAAI,UAAU,EAAG,QAAO;AACxB,SAAO;AACT;AAIO,SAAS,mBAAmB,UAA8C;AAC/E,UAAQ,UAAU;AAAA,IAChB,KAAK;AAAY,aAAO;AAAA,IACxB,KAAK;AAAQ,aAAO;AAAA,IACpB,KAAK;AAAU,aAAO;AAAA,IACtB,KAAK;AAAO,aAAO;AAAA,IACnB,KAAK;AAAQ,aAAO;AAAA,IACpB;AAAS,aAAO;AAAA,EAClB;AACF;AAEO,SAAS,eAAe,UAAoC,QAA8B;AAC/F,MAAI,aAAa,OAAQ,QAAO;AAChC,MAAI,aAAa,WAAY,QAAO;AACpC,MAAI,aAAa,OAAQ,QAAO;AAChC,MAAI,OAAQ,QAAO;AACnB,SAAO;AACT;AAIO,SAAS,eAAe,SAA6C;AAC1E,SAAO,QAAQ,IAAI,CAAC,GAAG,MAAM;AAC3B,UAAM,QAAQ,iBAAiB,EAAE,eAAe,KAAK,EAAE;AAGvD,UAAM,WAAqB,CAAC;AAC5B,eAAW,KAAK,EAAE,UAAU;AAC1B,UAAI,SAAS,UAAU,EAAG;AAC1B,eAAS,KAAK,EAAE,MAAM;AAAA,IACxB;AACA,UAAM,cAAc,SAAS,KAAK,IAAI,KAAK,SAAS,SAAS,KAAK,CAAC,SAAS,SAAS,SAAS,CAAC,EAAE,SAAS,GAAG,IAAI,MAAM;AAEvH,WAAO;AAAA,MACL,IAAI,IAAI;AAAA,MACR,WAAW;AAAA,MACX,OAAO,EAAE;AAAA,MACT,QAAQ,cAAc,EAAE,KAAK;AAAA,MAC7B;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAEO,SAAS,sBAAsB,SAA+C;AACnF,SAAO,QAAQ,IAAI,CAAC,GAAG,MAAM;AAC3B,UAAM,QAAQ,iBAAiB,EAAE,eAAe,KAAK,EAAE;AAEvD,UAAM,cAAiC,EAAE,SAAS,IAAI,QAAM;AAAA,MAC1D,MAAM,eAAe,EAAE,UAAU,CAAC,CAAC,EAAE,GAAG;AAAA,MACxC,aAAa,EAAE,MAAM,GAAG,EAAE,MAAM,KAAK,EAAE,GAAG,KAAK,EAAE;AAAA,MACjD,UAAU,mBAAmB,EAAE,QAAQ;AAAA,IACzC,EAAE;AAGF,UAAM,OAAO,oBAAI,IAAY;AAC7B,UAAM,WAA8B,CAAC;AACrC,eAAW,KAAK,aAAa;AAC3B,UAAI,CAAC,KAAK,IAAI,EAAE,WAAW,GAAG;AAC5B,aAAK,IAAI,EAAE,WAAW;AACtB,iBAAS,KAAK,CAAC;AAAA,MACjB;AAAA,IACF;AAGA,QAAI,SAAS,SAAS,GAAG;AACvB,UAAI,EAAE,SAAS,GAAG;AAChB,iBAAS,KAAK,EAAE,MAAM,QAAQ,aAAa,GAAG,KAAK,kDAAkD,UAAU,UAAU,CAAC;AAAA,MAC5H,OAAO;AACL,iBAAS,KAAK,EAAE,MAAM,QAAQ,aAAa,GAAG,KAAK,sDAAsD,UAAU,UAAU,CAAC;AAAA,MAChI;AAAA,IACF;AAEA,WAAO;AAAA,MACL,IAAI,IAAI;AAAA,MACR,MAAM;AAAA,MACN;AAAA,IACF;AAAA,EACF,CAAC;AACH;;;ACtHA,IAAM,oBAA4C;AAAA,EAChD,UAAU;AAAA,EACV,eAAe;AAAA,EACf,mBAAmB;AAAA,EACnB,YAAY;AAAA,EACZ,oBAAoB;AAAA,EACpB,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,eAAe;AAAA,EACf,kBAAkB;AAAA,EAClB,eAAe;AAAA,EACf,mBAAmB;AAAA,EACnB,sBAAsB;AAAA,EACtB,UAAU;AAAA,EACV,2BAA2B;AAAA,EAC3B,qBAAqB;AAAA,EACrB,uBAAuB;AAAA,EACvB,mBAAmB;AAAA,EACnB,qBAAqB;AAAA,EACrB,cAAc;AAAA,EACd,eAAe;AAAA,EACf,kBAAkB;AAAA,EAClB,iBAAiB;AAAA,EACjB,kBAAkB;AACpB;AAUA,IAAM,wBAA6D;AAAA,EACjE,UAAU;AAAA,IACR,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,aAAa;AAAA,EACf;AAAA,EACA,eAAe;AAAA,IACb,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,aAAa;AAAA,EACf;AAAA,EACA,mBAAmB;AAAA,IACjB,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,aAAa;AAAA,EACf;AAAA,EACA,YAAY;AAAA,IACV,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,aAAa;AAAA,EACf;AAAA,EACA,oBAAoB;AAAA,IAClB,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,aAAa;AAAA,EACf;AAAA,EACA,YAAY;AAAA,IACV,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,aAAa;AAAA,EACf;AAAA,EACA,aAAa;AAAA,IACX,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,aAAa;AAAA,EACf;AAAA,EACA,eAAe;AAAA,IACb,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,aAAa;AAAA,EACf;AAAA,EACA,kBAAkB;AAAA,IAChB,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,aAAa;AAAA,EACf;AAAA,EACA,eAAe;AAAA,IACb,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,aAAa;AAAA,EACf;AAAA,EACA,mBAAmB;AAAA,IACjB,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,aAAa;AAAA,EACf;AAAA,EACA,sBAAsB;AAAA,IACpB,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,aAAa;AAAA,EACf;AAAA,EACA,UAAU;AAAA,IACR,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,aAAa;AAAA,EACf;AAAA,EACA,2BAA2B;AAAA,IACzB,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,aAAa;AAAA,EACf;AAAA,EACA,qBAAqB;AAAA,IACnB,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,aAAa;AAAA,EACf;AAAA,EACA,uBAAuB;AAAA,IACrB,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,aAAa;AAAA,EACf;AAAA,EACA,mBAAmB;AAAA,IACjB,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,aAAa;AAAA,EACf;AAAA,EACA,qBAAqB;AAAA,IACnB,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,aAAa;AAAA,EACf;AAAA,EACA,cAAc;AAAA,IACZ,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,aAAa;AAAA,EACf;AAAA,EACA,eAAe;AAAA,IACb,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,aAAa;AAAA,EACf;AAAA,EACA,kBAAkB;AAAA,IAChB,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,aAAa;AAAA,EACf;AAAA,EACA,iBAAiB;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,aAAa;AAAA,EACf;AAAA,EACA,kBAAkB;AAAA,IAChB,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,aAAa;AAAA,EACf;AACF;AAIA,SAAS,gBAAgB,OAAe,QAAgB,QAA6B;AACnF,QAAM,eAAe,KAAK,SAAS,SAAS;AAG5C,MAAI,WAAW,SAAS,eAAe,EAAG,QAAO;AAEjD,MAAI,eAAe,GAAI,QAAO;AAC9B,MAAI,eAAe,EAAG,QAAO;AAC7B,MAAI,eAAe,EAAG,QAAO;AAC7B,MAAI,eAAe,EAAG,QAAO;AAC7B,SAAO;AACT;AAIO,SAAS,gBACd,OACA,WACA,SACA,QACQ;AAER,MAAI;AACJ,MAAI,SAAS,IAAI;AACf,cAAU,wCAAwC,KAAK;AAAA,EACzD,WAAW,SAAS,IAAI;AACtB,cAAU,mCAAmC,KAAK;AAAA,EACpD,WAAW,SAAS,IAAI;AACtB,cAAU,6BAA6B,KAAK;AAAA,EAC9C,WAAW,SAAS,IAAI;AACtB,cAAU,kCAAkC,KAAK;AAAA,EACnD,OAAO;AACL,cAAU,wBAAwB,KAAK,UAAU,MAAM;AAAA,EACzD;AAGA,QAAM,YAAY,UACf,OAAO,OAAK,EAAE,SAAS,CAAC,EACxB,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK,EAChC,MAAM,GAAG,CAAC;AAGb,QAAM,aAAa,UAChB,OAAO,OAAK,EAAE,SAAS,CAAC,EACxB,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK,EAChC,MAAM,GAAG,CAAC;AAEb,QAAM,QAAQ,CAAC,OAAO;AAEtB,MAAI,UAAU,SAAS,GAAG;AACxB,UAAM,QAAQ,UAAU,IAAI,OAAK,EAAE,SAAS;AAC5C,UAAM,KAAK,yBAAyB,WAAW,KAAK,CAAC,GAAG;AAAA,EAC1D;AAEA,MAAI,WAAW,SAAS,GAAG;AACzB,UAAM,QAAQ,WAAW,IAAI,OAAK,EAAE,SAAS;AAC7C,UAAM,KAAK,kBAAkB,WAAW,KAAK,CAAC,GAAG;AAAA,EACnD;AAGA,MAAI,CAAC,QAAQ,WAAW;AACtB,UAAM,KAAK,wFAAwF;AAAA,EACrG;AAGA,MAAI,QAAQ,wBAAwB;AAClC,UAAM,KAAK,gKAAgK;AAAA,EAC7K;AAEA,SAAO,MAAM,KAAK,GAAG;AACvB;AAIO,SAAS,sBACd,WACA,kBACe;AACf,QAAM,aAOD,CAAC;AAEN,aAAW,UAAU,kBAAkB;AACrC,QAAI,OAAO,QAAQ,EAAG;AAEtB,UAAM,SAAS,kBAAkB,OAAO,SAAS,KAAK;AACtD,UAAM,WAAW,sBAAsB,OAAO,SAAS;AACvD,QAAI,CAAC,SAAU;AAEf,UAAM,eAAe,KAAK,OAAO,SAAS,SAAS;AACnD,UAAM,SAAS,gBAAgB,OAAO,OAAO,QAAQ,SAAS,MAAM;AAEpE,eAAW,KAAK;AAAA,MACd,WAAW,OAAO;AAAA,MAClB,OAAO,OAAO;AAAA,MACd;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAGA,aAAW,KAAK,CAAC,GAAG,MAAM,EAAE,cAAc,EAAE,WAAW;AAGvD,QAAM,MAAM,WAAW,MAAM,GAAG,EAAE;AAElC,SAAO,IAAI,IAAI,CAAC,GAAG,OAAO;AAAA,IACxB,IAAI,IAAI;AAAA,IACR,MAAM,EAAE,SAAS;AAAA,IACjB,aAAa,EAAE,SAAS;AAAA,IACxB,QAAQ,EAAE,SAAS;AAAA,IACnB,QAAQ,EAAE;AAAA,EACZ,EAAE;AACJ;AAIO,SAAS,qBACd,OACA,SACA,WACe;AACf,QAAM,UAAyB,CAAC;AAGhC,MAAI,QAAQ,wBAAwB;AAClC,YAAQ,KAAK;AAAA,MACX,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,cAAc;AAAA,IAChB,CAAC;AAAA,EACH;AAGA,UAAQ,KAAK;AAAA,IACX,QAAQ;AAAA,IACR,OAAO,GAAG,KAAK;AAAA,IACf,cAAc,SAAS,KACnB,uCACA,SAAS,KACP,wDACA;AAAA,EACR,CAAC;AAGD,QAAM,cAAc,QAAQ,mBAAmB;AAC/C,UAAQ,KAAK;AAAA,IACX,QAAQ;AAAA,IACR,OAAO,GAAG,WAAW;AAAA,IACrB,cAAc,eAAe,IACzB,wDACA,eAAe,IACb,oEACA;AAAA,EACR,CAAC;AAGD,QAAM,iBAAiB,QAAQ,uBAAuB;AACtD,QAAM,eAAe,QAAQ,4BAA4B;AACzD,UAAQ,KAAK;AAAA,IACX,QAAQ;AAAA,IACR,OAAO,eAAe,IAClB,GAAG,YAAY,aACf,iBAAiB,IACf,GAAG,cAAc,gBACjB;AAAA,IACN,cAAc,eAAe,IACzB,0DACA,iBAAiB,IACf,sDACA;AAAA,EACR,CAAC;AAGD,QAAM,cAAc,QAAQ;AAC5B,UAAQ,KAAK;AAAA,IACX,QAAQ;AAAA,IACR,OAAO,cAAc,IAAI,GAAG,WAAW,WAAW;AAAA,IAClD,cAAc,eAAe,KACzB,8DACA,eAAe,KACb,0CACA,cAAc,IACZ,2DACA;AAAA,EACV,CAAC;AAGD,QAAM,YAAY,QAAQ;AAC1B,UAAQ,KAAK;AAAA,IACX,QAAQ;AAAA,IACR,OAAO,GAAG,SAAS;AAAA,IACnB,cAAc,aAAa,KACvB,0DACA,aAAa,KACX,0EACA;AAAA,EACR,CAAC;AAGD,QAAM,gBAAgB,QAAQ,2BAA2B,QAAQ,iCAAiC;AAClG,MAAI,gBAAgB,GAAG;AACrB,YAAQ,KAAK;AAAA,MACX,QAAQ;AAAA,MACR,OAAO,GAAG,aAAa;AAAA,MACvB,cAAc;AAAA,IAChB,CAAC;AAAA,EACH;AAGA,QAAM,UAAU,UAAU,OAAO,OAAK,EAAE,SAAS,CAAC,EAAE;AACpD,UAAQ,KAAK;AAAA,IACX,QAAQ;AAAA,IACR,OAAO,GAAG,OAAO;AAAA,IACjB,cAAc,WAAW,KACrB,6CACA,WAAW,KACT,4DACA,GAAG,KAAK,OAAO;AAAA,EACvB,CAAC;AAED,SAAO;AACT;AAIO,SAAS,mBACd,OACA,eACA,WACA,QACQ;AACR,QAAM,YAAY,cAAc,OAAO,OAAK,EAAE,WAAW,WAAW;AACpE,QAAM,cAAc,cAAc,OAAO,OAAK,EAAE,WAAW,cAAc,EAAE,WAAW,MAAM;AAE5F,QAAM,UAAU,UAAU,OAAO,OAAK,EAAE,SAAS,CAAC,EAAE;AACpD,QAAM,QAAQ,UAAU;AAExB,MAAI;AACJ,MAAI,SAAS,IAAI;AACf,cAAU,GAAG,MAAM,uDAAuD,OAAO,IAAI,KAAK;AAAA,EAC5F,WAAW,SAAS,IAAI;AACtB,cAAU,GAAG,MAAM,oCAAoC,OAAO,IAAI,KAAK;AACvE,QAAI,UAAU,SAAS,GAAG;AACxB,iBAAW,IAAI,UAAU,MAAM,0BAA0B,UAAU,MAAM,GAAG,CAAC,EAAE,IAAI,OAAK,EAAE,IAAI,EAAE,KAAK,IAAI,CAAC;AAAA,IAC5G;AACA,QAAI,YAAY,SAAS,GAAG;AAC1B,iBAAW,YAAY,YAAY,MAAM;AAAA,IAC3C;AAAA,EACF,WAAW,SAAS,IAAI;AACtB,cAAU,GAAG,MAAM,oCAAoC,OAAO,IAAI,KAAK,sBAAsB,cAAc,MAAM;AACjH,QAAI,UAAU,SAAS,GAAG;AACxB,iBAAW,2BAA2B,UAAU,MAAM,GAAG,CAAC,EAAE,IAAI,OAAK,EAAE,IAAI,EAAE,KAAK,IAAI,CAAC;AAAA,IACzF;AAAA,EACF,WAAW,SAAS,IAAI;AACtB,cAAU,GAAG,MAAM,yCAAyC,OAAO,IAAI,KAAK;AAC5E,QAAI,YAAY,SAAS,GAAG;AAC1B,iBAAW,cAAc,YAAY,MAAM,GAAG,CAAC,EAAE,IAAI,OAAK,EAAE,IAAI,EAAE,KAAK,IAAI,CAAC;AAAA,IAC9E;AACA,eAAW,yBAAyB,KAAK,IAAI,GAAG,cAAc,MAAM,CAAC;AAAA,EACvE,OAAO;AACL,cAAU,GAAG,MAAM,iDAAiD,OAAO,IAAI,KAAK;AACpF,QAAI,cAAc,SAAS,GAAG;AAC5B,iBAAW,gBAAgB,cAAc,MAAM,GAAG,CAAC,EAAE,IAAI,OAAK,EAAE,IAAI,EAAE,KAAK,IAAI,CAAC;AAAA,IAClF;AACA,eAAW;AAAA,EACb;AAEA,SAAO;AACT;AAIA,SAAS,WAAW,OAAyB;AAC3C,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,MAAI,MAAM,WAAW,EAAG,QAAO,MAAM,CAAC;AACtC,MAAI,MAAM,WAAW,EAAG,QAAO,GAAG,MAAM,CAAC,CAAC,QAAQ,MAAM,CAAC,CAAC;AAC1D,SAAO,GAAG,MAAM,MAAM,GAAG,EAAE,EAAE,KAAK,IAAI,CAAC,SAAS,MAAM,MAAM,SAAS,CAAC,CAAC;AACzE;;;ACzbA,eAAe,UAAU,KAAa,YAAY,KAAoC;AACpF,MAAI;AACF,UAAM,MAAM,MAAM,MAAM,KAAK;AAAA,MAC3B,QAAQ,YAAY,QAAQ,SAAS;AAAA,MACrC,SAAS,EAAE,cAAc,yBAAyB;AAAA,MAClD,UAAU;AAAA,IACZ,CAAC;AACD,QAAI,IAAI,WAAW,IAAK,QAAO;AAC/B,UAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,QAAI,KAAK,SAAS,IAAK,QAAO;AAC9B,WAAO,EAAE,MAAM,KAAK,MAAM,GAAG,GAAM,GAAG,QAAQ,IAAI,QAAQ,UAAU,IAAI,IAAI;AAAA,EAC9E,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAIA,IAAM,gBAA0C;AAAA,EAC9C,OAAO,CAAC,UAAU,aAAa,YAAY,aAAa;AAAA,EACxD,SAAS,CAAC,YAAY,UAAU,WAAW;AAAA,EAC3C,UAAU,CAAC,aAAa,aAAa,cAAc,aAAa,aAAa;AAAA,EAC7E,SAAS,CAAC,YAAY,eAAe,eAAe;AAAA,EACpD,MAAM,CAAC,SAAS,aAAa,YAAY,WAAW,aAAa;AAAA,EACjE,WAAW,CAAC,cAAc,oBAAoB,UAAU;AAAA,EACxD,MAAM,CAAC,SAAS,kBAAkB,SAAS,gBAAgB,UAAU;AAAA,EACrE,OAAO,CAAC,iBAAiB,cAAc,oBAAoB,eAAe;AAC5E;AAQO,SAAS,gBAAgB,MAAc,QAA0B;AAEtE,QAAM,YAAY,KAAK,MAAM,uBAAuB,KAAK,CAAC;AAC1D,QAAM,UAAU,UAAU,KAAK,IAAI;AAEnC,QAAM,cAAc,QAAQ,MAAM,mBAAmB,KAAK,CAAC;AAC3D,QAAM,QAAQ,oBAAI,IAAY;AAE9B,QAAM,cAAc,OAAO,QAAQ,UAAU,EAAE,EAAE,YAAY;AAE7D,aAAW,SAAS,aAAa;AAC/B,UAAM,OAAO,MAAM,MAAM,kBAAkB,IAAI,CAAC;AAChD,QAAI,CAAC,KAAM;AAEX,QAAI;AACJ,QAAI,KAAK,WAAW,GAAG,GAAG;AACxB,aAAO;AAAA,IACT,WAAW,KAAK,WAAW,MAAM,GAAG;AAClC,UAAI;AACF,cAAM,MAAM,IAAI,IAAI,IAAI;AACxB,cAAM,aAAa,IAAI,SAAS,QAAQ,UAAU,EAAE,EAAE,YAAY;AAClE,YAAI,eAAe,YAAa;AAChC,eAAO,IAAI;AAAA,MACb,QAAQ;AACN;AAAA,MACF;AAAA,IACF,OAAO;AACL;AAAA,IACF;AAGA,WAAO,KAAK,QAAQ,QAAQ,EAAE,KAAK;AACnC,QAAI,SAAS,IAAK;AAClB,QAAI,KAAK,SAAS,GAAG,EAAG;AAGxB,QAAI,2CAA2C,KAAK,IAAI,EAAG;AAC3D,QAAI,sEAAsE,KAAK,IAAI,EAAG;AAEtF,UAAM,IAAI,IAAI;AAAA,EAChB;AAEA,SAAO,MAAM,KAAK,KAAK;AACzB;AAQO,SAAS,+BACd,aACA,QACA,QAAQ,GACE;AACV,QAAM,YAAY,YAAY,MAAM,0BAA0B,KAAK,CAAC;AACpE,QAAM,cAAc,OAAO,QAAQ,UAAU,EAAE,EAAE,YAAY;AAC7D,QAAM,aAAuB,CAAC;AAG9B,QAAM,eAAe;AAErB,aAAW,SAAS,WAAW;AAC7B,UAAM,WAAW,MAAM,MAAM,sBAAsB;AACnD,QAAI,CAAC,SAAU;AACf,UAAM,MAAM,SAAS,CAAC,EAAE,KAAK;AAE7B,QAAI;AACF,YAAM,SAAS,IAAI,IAAI,GAAG;AAC1B,YAAM,YAAY,OAAO,SAAS,QAAQ,UAAU,EAAE,EAAE,YAAY;AACpE,UAAI,cAAc,YAAa;AAE/B,UAAI,OAAO,aAAa,OAAO,OAAO,aAAa,GAAI;AAEvD,YAAM,OAAO,OAAO,SAAS,YAAY;AACzC,UAAI,aAAa,KAAK,IAAI,EAAG;AAG7B,YAAM,WAAW,KAAK,MAAM,GAAG,EAAE,OAAO,OAAO;AAC/C,UAAI,SAAS,SAAS,KAAK,SAAS,SAAS,EAAG;AAEhD,iBAAW,KAAK,GAAG;AAAA,IACrB,QAAQ;AACN;AAAA,IACF;AAAA,EACF;AAGA,MAAI,WAAW,UAAU,MAAO,QAAO;AAEvC,QAAM,SAAmB,CAAC;AAC1B,WAAS,IAAI,GAAG,IAAI,OAAO,KAAK;AAC9B,UAAM,QAAQ,KAAK,MAAM,KAAK,WAAW,SAAS,MAAM,QAAQ,EAAE;AAClE,WAAO,KAAK,WAAW,KAAK,CAAC;AAAA,EAC/B;AACA,SAAO;AACT;AAgBA,eAAsB,mBACpB,UACA,SACiB;AACjB,MAAI,CAAC,SAAS,YAAY,CAAC,SAAS,SAAU,QAAO;AAErD,QAAM,YAAY,SAAS,aAAa;AACxC,QAAM,UAAU,GAAG,SAAS,QAAQ,MAAM,SAAS,MAAM;AACzD,QAAM,eAAe,oBAAI,IAAY;AAGrC,eAAa,IAAI,UAAU,GAAG;AAC9B,eAAa,IAAI,OAAO;AACxB,MAAI,SAAS,YAAY;AACvB,eAAW,QAAQ,SAAS,YAAY;AACtC,UAAI,KAAK,SAAU,cAAa,IAAI,KAAK,QAAQ;AAAA,IACnD;AAAA,EACF;AAGA,QAAM,cAAc,oBAAI,IAA0B;AAGlD,QAAM,WAAW,gBAAgB,SAAS,SAAS,MAAM,SAAS,MAAM;AAGxE,aAAW,CAAC,UAAU,QAAQ,KAAK,OAAO,QAAQ,aAAa,GAAG;AAEhE,UAAM,WAAW,SAAS;AAAA,MAAK,OAC7B,SAAS,KAAK,OAAK,EAAE,YAAY,MAAM,KAAK,EAAE,YAAY,EAAE,WAAW,IAAI,GAAG,CAAC;AAAA,IACjF;AAEA,QAAI,UAAU;AACZ,YAAM,MAAM,GAAG,OAAO,GAAG,QAAQ;AACjC,UAAI,CAAC,aAAa,IAAI,GAAG,EAAG,aAAY,IAAI,KAAK,QAAwB;AAAA,IAC3E,OAAO;AAEL,YAAM,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,CAAC;AACpC,UAAI,CAAC,aAAa,IAAI,GAAG,EAAG,aAAY,IAAI,KAAK,QAAwB;AAAA,IAC3E;AAAA,EACF;AAGA,MAAI,SAAS,cAAc,SAAS,WAAW,WAAW,KAAK;AAC7D,UAAM,cAAc;AAAA,MAClB,SAAS,WAAW;AAAA,MACpB,SAAS;AAAA,MACT;AAAA,IACF;AACA,eAAW,OAAO,aAAa;AAC7B,UAAI,CAAC,aAAa,IAAI,GAAG,EAAG,aAAY,IAAI,KAAK,SAAS;AAAA,IAC5D;AAAA,EACF;AAGA,QAAM,UAAU,MAAM,KAAK,YAAY,QAAQ,CAAC;AAChD,MAAI,QAAQ,WAAW,EAAG,QAAO;AAEjC,QAAM,UAAU,MAAM,QAAQ,IAAI,QAAQ,IAAI,CAAC,CAAC,GAAG,MAAM,UAAU,KAAK,SAAS,CAAC,CAAC;AAGnF,MAAI,CAAC,SAAS,WAAY,UAAS,aAAa,CAAC;AAEjD,MAAI,QAAQ;AACZ,WAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,UAAM,SAAS,QAAQ,CAAC;AACxB,QAAI,UAAU,OAAO,KAAK,SAAS,KAAK;AACtC,aAAO,WAAW,QAAQ,CAAC,EAAE,CAAC;AAC9B,eAAS,WAAW,KAAK,MAAM;AAC/B;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;;;AC9MA,SAAS,aAAa,MAAsB;AAC1C,QAAM,QAAQ,KAAK,MAAM,kCAAkC;AAC3D,SAAO,QAAQ,MAAM,CAAC,EAAE,QAAQ,QAAQ,GAAG,EAAE,KAAK,IAAI;AACxD;AAEA,SAAS,eAAe,MAAsB;AAC5C,SAAO,KACJ,QAAQ,+BAA+B,EAAE,EACzC,QAAQ,6BAA6B,EAAE,EACvC,QAAQ,YAAY,GAAG,EACvB,QAAQ,QAAQ,GAAG,EACnB,KAAK;AACV;AAEA,SAAS,WAAW,MAAsB;AACxC,MAAI,CAAC,KAAM,QAAO;AAClB,SAAO,KAAK,MAAM,KAAK,EAAE,OAAO,OAAK,EAAE,SAAS,CAAC,EAAE;AACrD;AAIA,SAAS,kBAAkB,MAAgC;AACzD,QAAM,WAAW,iCAAiC,KAAK,IAAI;AAC3D,MAAI,CAAC,UAAU;AACb,WAAO,EAAE,OAAO,iBAAiB,OAAO,uBAAuB,UAAU,QAAQ;AAAA,EACnF;AACA,QAAM,QAAQ,aAAa,IAAI;AAC/B,MAAI,CAAC,OAAO;AACV,WAAO,EAAE,OAAO,iBAAiB,OAAO,qBAAqB,UAAU,QAAQ;AAAA,EACjF;AACA,SAAO;AACT;AAEA,SAAS,4BAA4B,MAAgC;AACnE,QAAM,UAAU,mEAAmE,KAAK,IAAI,KACvF,mEAAmE,KAAK,IAAI;AACjF,MAAI,CAAC,SAAS;AACZ,WAAO,EAAE,OAAO,4BAA4B,OAAO,4BAA4B,UAAU,QAAQ;AAAA,EACnG;AACA,SAAO;AACT;AAEA,SAAS,UAAU,MAAgC;AACjD,QAAM,YAAY,KAAK,MAAM,YAAY;AACzC,MAAI,CAAC,aAAa,UAAU,WAAW,GAAG;AACxC,WAAO,EAAE,OAAO,SAAS,OAAO,eAAe,UAAU,QAAQ;AAAA,EACnE;AACA,SAAO;AACT;AAEA,SAAS,gBAAgB,MAAgC;AACvD,QAAM,YAAY,KAAK,MAAM,YAAY;AACzC,MAAI,aAAa,UAAU,SAAS,GAAG;AACrC,WAAO,EAAE,OAAO,eAAe,OAAO,uBAAuB,UAAU,MAAM,KAAK,UAAU,UAAU;AAAA,EACxG;AACA,SAAO;AACT;AAEA,SAAS,cAAc,MAAgC;AACrD,QAAM,YAAY,wDAAwD,KAAK,IAAI;AACnF,MAAI,CAAC,WAAW;AACd,WAAO,EAAE,OAAO,aAAa,OAAO,8BAA8B,UAAU,UAAU;AAAA,EACxF;AACA,SAAO;AACT;AAEA,SAAS,sBAAsB,MAAgC;AAC7D,QAAM,eAAe,yCAAyC,KAAK,IAAI;AACvE,MAAI,CAAC,cAAc;AACjB,WAAO,EAAE,OAAO,qBAAqB,OAAO,0BAA0B,UAAU,UAAU;AAAA,EAC5F;AACA,SAAO;AACT;AAEA,SAAS,mBAAmB,MAAgC;AAC1D,QAAM,QAAQ,gCAAgC,KAAK,IAAI;AACvD,MAAI,CAAC,OAAO;AACV,WAAO,EAAE,OAAO,mBAAmB,OAAO,sBAAsB,UAAU,UAAU;AAAA,EACtF;AACA,SAAO;AACT;AAEA,SAAS,iBAAiB,WAAqC;AAC7D,MAAI,YAAY,KAAK;AACnB,WAAO,EAAE,OAAO,gBAAgB,OAAO,iBAAiB,SAAS,WAAW,UAAU,UAAU;AAAA,EAClG;AACA,SAAO;AACT;AAEA,SAAS,sBAAsB,MAAgC;AAC7D,QAAM,UAAU,KAAK,MAAM,gBAAgB,KAAK,CAAC;AACjD,MAAI,QAAQ,WAAW,EAAG,QAAO;AAEjC,MAAI,aAAa;AACjB,aAAW,OAAO,SAAS;AACzB,UAAM,SAAS,wBAAwB,KAAK,GAAG;AAC/C,UAAM,cAAc,kBAAkB,KAAK,GAAG;AAC9C,QAAI,CAAC,UAAU,CAAC,YAAa;AAAA,EAC/B;AAEA,MAAI,aAAa,GAAG;AAClB,WAAO;AAAA,MACL,OAAO;AAAA,MACP,OAAO,GAAG,UAAU,SAAS,aAAa,IAAI,MAAM,EAAE;AAAA,MACtD,UAAU;AAAA,IACZ;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,qBAAqB,MAAc,KAA+B;AACzE,MAAI;AACJ,MAAI;AACF,aAAS,IAAI,IAAI,GAAG,EAAE,SAAS,QAAQ,UAAU,EAAE,EAAE,YAAY;AAAA,EACnE,QAAQ;AACN,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,KAAK,MAAM,0CAA0C,KAAK,CAAC;AACzE,MAAI,gBAAgB;AAEpB,aAAW,QAAQ,OAAO;AACxB,UAAM,YAAY,KAAK,MAAM,0BAA0B;AACvD,QAAI,CAAC,UAAW;AAChB,UAAM,OAAO,UAAU,CAAC;AAExB,QAAI,KAAK,WAAW,GAAG,KAAK,CAAC,KAAK,WAAW,IAAI,GAAG;AAClD;AAAA,IACF,WAAW,KAAK,WAAW,MAAM,GAAG;AAClC,UAAI;AACF,cAAM,aAAa,IAAI,IAAI,IAAI,EAAE,SAAS,QAAQ,UAAU,EAAE,EAAE,YAAY;AAC5E,YAAI,eAAe,OAAQ;AAAA,MAC7B,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AAEA,MAAI,kBAAkB,GAAG;AACvB,WAAO,EAAE,OAAO,qBAAqB,OAAO,2BAA2B,UAAU,UAAU;AAAA,EAC7F;AACA,SAAO;AACT;AAIA,SAAS,uBAAuB,MAAgC;AAC9D,QAAM,WAAW,KAAK,MAAM,4EAA4E,KAAK,CAAC;AAC9G,MAAI,SAAS,WAAW,EAAG,QAAO;AAElC,QAAM,QAAQ,oBAAI,IAAY;AAC9B,aAAW,SAAS,UAAU;AAC5B,UAAM,UAAU,MAAM,QAAQ,sBAAsB,EAAE;AACtD,UAAM,cAAc,QAAQ,MAAM,0BAA0B,KAAK,CAAC;AAClE,eAAW,KAAK,aAAa;AAC3B,YAAM,IAAI,EAAE,MAAM,yBAAyB;AAC3C,UAAI,EAAG,OAAM,IAAI,EAAE,CAAC,CAAC;AAAA,IACvB;AAAA,EACF;AAEA,MAAI,MAAM,OAAO,GAAG;AAClB,WAAO;AAAA,MACL,OAAO;AAAA,MACP,OAAO,YAAY,MAAM,KAAK,KAAK,EAAE,KAAK,IAAI,CAAC;AAAA,MAC/C,UAAU;AAAA,IACZ;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,yBAAyB,MAAgC;AAChE,QAAM,WAAW,KAAK,MAAM,mCAAmC,KAAK,CAAC;AACrE,MAAI,gBAAgB;AAEpB,aAAW,KAAK,UAAU;AACxB,UAAM,OAAO,EAAE,QAAQ,YAAY,EAAE,EAAE,KAAK;AAC5C,QAAI,MAAM,KAAK,IAAI,KAAK,yEAAyE,KAAK,IAAI,GAAG;AAC3G;AAAA,IACF;AAAA,EACF;AAEA,MAAI,gBAAgB,GAAG;AACrB,WAAO;AAAA,MACL,OAAO;AAAA,MACP,OAAO,GAAG,aAAa,2BAA2B,gBAAgB,IAAI,MAAM,EAAE;AAAA,MAC9E,UAAU;AAAA,IACZ;AAAA,EACF;AACA,SAAO;AACT;AAIO,SAAS,YAAY,MAAc,KAAa,UAAoC;AACzF,QAAM,QAAQ,aAAa,IAAI;AAC/B,QAAM,cAAc,eAAe,IAAI;AACvC,QAAM,YAAY,WAAW,WAAW;AAExC,QAAM,SAAsB,CAAC;AAC7B,QAAM,YAAyB,CAAC;AAGhC,QAAM,cAAc;AAAA,IAClB,kBAAkB,IAAI;AAAA,IACtB,4BAA4B,IAAI;AAAA,IAChC,UAAU,IAAI;AAAA,IACd,gBAAgB,IAAI;AAAA,IACpB,cAAc,IAAI;AAAA,IAClB,sBAAsB,IAAI;AAAA,IAC1B,mBAAmB,IAAI;AAAA,IACvB,iBAAiB,SAAS;AAAA,IAC1B,sBAAsB,IAAI;AAAA,IAC1B,qBAAqB,MAAM,GAAG;AAAA,EAChC;AAEA,aAAW,UAAU,aAAa;AAChC,QAAI,OAAQ,QAAO,KAAK,MAAM;AAAA,EAChC;AAGA,QAAM,iBAAiB;AAAA,IACrB,uBAAuB,IAAI;AAAA,IAC3B,yBAAyB,IAAI;AAAA,EAC/B;AAEA,aAAW,UAAU,gBAAgB;AACnC,QAAI,OAAQ,WAAU,KAAK,MAAM;AAAA,EACnC;AAEA,SAAO,EAAE,KAAK,OAAO,UAAU,WAAW,QAAQ,UAAU;AAC9D;AAEO,SAAS,gBAAgB,UAAkC;AAChE,QAAM,UAAwB,CAAC;AAG/B,MAAI,SAAS,UAAU;AACrB,UAAM,MAAM,GAAG,SAAS,QAAQ,MAAM,SAAS,MAAM;AACrD,YAAQ,KAAK,YAAY,SAAS,SAAS,MAAM,KAAK,SAAS,SAAS,YAAY,UAAU,CAAC;AAAA,EACjG;AAGA,MAAI,SAAS,YAAY;AACvB,eAAW,QAAQ,SAAS,YAAY;AACtC,YAAM,MAAM,KAAK,YAAY;AAC7B,cAAQ,KAAK,YAAY,KAAK,MAAM,KAAK,KAAK,YAAY,SAAS,CAAC;AAAA,IACtE;AAAA,EACF;AAEA,SAAO;AACT;;;ACtPA,SAAS,cAAc,MAAsB;AAC3C,SAAO,KACJ,QAAQ,+BAA+B,EAAE,EACzC,QAAQ,6BAA6B,EAAE,EACvC,QAAQ,YAAY,GAAG,EACvB,QAAQ,QAAQ,GAAG,EACnB,KAAK,EAAE;AACZ;AAYA,eAAsB,MAAM,QAAgB,SAA8C;AACxF,QAAM,YAAY,KAAK,IAAI;AAC3B,MAAI,uBAAuB;AAG3B,QAAM,WAAW,MAAM,iBAAiB,MAAM;AAE9C,MAAI,CAAC,SAAS,UAAU;AACtB,UAAM,IAAI,MAAM,wBAAwB,MAAM,8BAA8B;AAAA,EAC9E;AAEA,MAAI,SAAS,cAAc;AACzB,UAAM,IAAI,MAAM,GAAG,MAAM,iBAAiB,SAAS,YAAY,oBAAoB;AAAA,EACrF;AAEA,MAAI,SAAS,cAAc;AACzB,UAAM,IAAI,MAAM,GAAG,MAAM,6BAA6B,SAAS,YAAY,GAAG;AAAA,EAChF;AAGA,MAAI,CAAC,SAAS,cAAc,SAAS,YAAY,WAAW,SAAS,SAAS,IAAI,GAAG;AACnF,UAAM,aAAa,cAAc,SAAS,SAAS,IAAI;AACvD,UAAM,MAAM,GAAG,SAAS,QAAQ,MAAM,MAAM;AAC5C,UAAM,WAAW,MAAM,kBAAkB,GAAG;AAE5C,QAAI,UAAU;AACZ,YAAM,kBAAkB,cAAc,SAAS,IAAI;AACnD,UAAI,kBAAkB,YAAY;AAChC,iBAAS,WAAW;AACpB,+BAAuB;AAAA,MACzB;AAAA,IACF;AAEA,QAAI,wBAAwB,SAAS,WAAW,WAAW,SAAS,QAAQ,IAAI,GAAG;AACjF,YAAM,SAAS,GAAG,SAAS,QAAQ,MAAM,MAAM;AAC/C,YAAM,cAAc,MAAM,kBAAkB,MAAM;AAClD,UAAI,eAAe,cAAc,YAAY,IAAI,IAAI,cAAc,SAAS,QAAQ,IAAI,GAAG;AACzF,iBAAS,UAAU;AAAA,MACrB;AAAA,IACF;AAAA,EACF;AAGA,MAAI,CAAC,SAAS,aAAa;AACzB,UAAM,mBAAmB,QAAQ;AAAA,EACnC;AAGA,QAAM,UAAU,kBAAkB,QAAQ;AAC1C,QAAM,eAAe,sBAAsB,OAAO;AAClD,QAAM,UAAU,sBAAsB,QAAQ;AAC9C,MAAI,qBAAsB,SAAQ,yBAAyB;AAG3D,QAAM,YAAY,eAAe,OAAO;AACxC,QAAM,mBAAmB,sBAAsB,OAAO;AAGtD,QAAM,UAAU,gBAAgB,cAAc,WAAW,SAAS,MAAM;AACxE,QAAM,gBAAgB,sBAAsB,WAAW,OAAO;AAC9D,QAAM,eAAe,qBAAqB,cAAc,SAAS,SAAS;AAC1E,QAAM,aAAa,mBAAmB,cAAc,eAAe,WAAW,MAAM;AAGpF,QAAM,gBAAgB,gBAAgB,QAAQ;AAE9C,QAAM,UAAU,KAAK,OAAO,KAAK,IAAI,IAAI,aAAa,GAAG,IAAI;AAE7D,SAAO;AAAA,IACL,MAAM;AAAA,IACN,YAAW,oBAAI,KAAK,GAAE,mBAAmB,SAAS,EAAE,MAAM,WAAW,OAAO,QAAQ,KAAK,UAAU,CAAC;AAAA,IACpG,SAAS;AAAA,IACT,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAI,wBAAwB,EAAE,sBAAsB,KAAK;AAAA,EAC3D;AACF;","names":["text"]}
|