kordoc 4.14.2 → 4.14.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -6
- package/dist/{-AQKXLFIM.js → -Z4TJ3QGK.js} +13 -11
- package/dist/{chunk-QOMNEWCQ.cjs → chunk-5LAZQCUJ.cjs} +305 -31
- package/dist/chunk-5LAZQCUJ.cjs.map +1 -0
- package/dist/{chunk-7IAQ4HOK.js → chunk-6BWU6SQX.js} +1 -1
- package/dist/chunk-6BWU6SQX.js.map +1 -0
- package/dist/{chunk-FOJZNMMK.js → chunk-6CUIXJOC.js} +1 -1
- package/dist/chunk-6CUIXJOC.js.map +1 -0
- package/dist/{chunk-ZWD734EY.js → chunk-7SE4EZ45.js} +2 -2
- package/dist/{chunk-TSFS5VKD.js → chunk-D4U2TXDC.js} +332 -141
- package/dist/chunk-D4U2TXDC.js.map +1 -0
- package/dist/chunk-DPWWXUOG.js +2222 -0
- package/dist/chunk-DPWWXUOG.js.map +1 -0
- package/dist/{chunk-GDW4YP7K.js → chunk-GLSBEEZJ.js} +2 -2
- package/dist/{chunk-JQEFP45L.js → chunk-GUJ4Q73I.js} +2 -2
- package/dist/{chunk-ZWOFQRIB.js → chunk-HIJUKZHM.js} +3 -3
- package/dist/chunk-IMAAFSAX.cjs +1352 -0
- package/dist/chunk-IMAAFSAX.cjs.map +1 -0
- package/dist/{chunk-TNCKOL2O.js → chunk-LCW7SEPG.js} +2 -2
- package/dist/chunk-LFSQAMSM.js +1352 -0
- package/dist/chunk-LFSQAMSM.js.map +1 -0
- package/dist/chunk-MG6DJEX4.js +1299 -0
- package/dist/chunk-MG6DJEX4.js.map +1 -0
- package/dist/{chunk-QC5T6D4J.js → chunk-NLU6LBLY.js} +299 -25
- package/dist/chunk-NLU6LBLY.js.map +1 -0
- package/dist/{chunk-EQZI77PP.cjs → chunk-QEJUY6SK.cjs} +3 -3
- package/dist/{chunk-EQZI77PP.cjs.map → chunk-QEJUY6SK.cjs.map} +1 -1
- package/dist/{chunk-VQ5W4MYO.js → chunk-QIF2VXBQ.js} +298 -24
- package/dist/chunk-QIF2VXBQ.js.map +1 -0
- package/dist/{chunk-UET462HB.js → chunk-TITDJWVZ.js} +2 -2
- package/dist/{chunk-247ANM72.cjs → chunk-USHQCF5T.cjs} +870 -147
- package/dist/chunk-USHQCF5T.cjs.map +1 -0
- package/dist/{chunk-C7FQBSON.js → chunk-V3DX4DUF.js} +2 -2
- package/dist/{chunk-DOGPOY4B.js → chunk-VDN7LMPL.js} +2 -2
- package/dist/{chunk-EDNJLUSE.js → chunk-VJIL6PIL.js} +2 -2
- package/dist/{chunk-L7DMSMAG.cjs → chunk-VWUYVEFN.cjs} +1 -1
- package/dist/chunk-VWUYVEFN.cjs.map +1 -0
- package/dist/{chunk-HR2XNERB.cjs → chunk-WJHAU73B.cjs} +2 -2
- package/dist/{chunk-HR2XNERB.cjs.map → chunk-WJHAU73B.cjs.map} +1 -1
- package/dist/{chunk-NS55SM7A.js → chunk-WJJGW5PL.js} +2 -2
- package/dist/{chunk-EISO3POT.js → chunk-XVXHXQIO.js} +788 -194
- package/dist/chunk-XVXHXQIO.js.map +1 -0
- package/dist/{chunk-ILU76UF3.js → chunk-YAKC46HZ.js} +2 -2
- package/dist/chunk-YAKC46HZ.js.map +1 -0
- package/dist/{chunk-3DUADAY2.js → chunk-YAVHVFRY.js} +851 -128
- package/dist/chunk-YAVHVFRY.js.map +1 -0
- package/dist/{chunk-A7QC2ZVP.js → chunk-YT3GC62E.js} +851 -128
- package/dist/chunk-YT3GC62E.js.map +1 -0
- package/dist/chunks-CCMRL4MJ.js +10 -0
- package/dist/cli.js +228 -97
- package/dist/cli.js.map +1 -1
- package/dist/{formula-PJJ6S3Z2.cjs → formula-5LOVHAKE.cjs} +9 -9
- package/dist/{formula-PJJ6S3Z2.cjs.map → formula-5LOVHAKE.cjs.map} +1 -1
- package/dist/{formula-JGFTXWYT.js → formula-7RANCW5L.js} +3 -3
- package/dist/{formula-5S7WWXGH.js → formula-7UYJOVTB.js} +4 -4
- package/dist/{image-ocr-WCAYXLOA.js → image-ocr-I6JOCATS.js} +34 -16
- package/dist/image-ocr-I6JOCATS.js.map +1 -0
- package/dist/{image-ocr-ZTYAGV3W.cjs → image-ocr-NYBJEOH2.cjs} +36 -18
- package/dist/image-ocr-NYBJEOH2.cjs.map +1 -0
- package/dist/{image-ocr-FLIL7MGN.js → image-ocr-ZV6PDBUQ.js} +32 -14
- package/dist/image-ocr-ZV6PDBUQ.js.map +1 -0
- package/dist/index.cjs +4048 -1216
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +66 -28
- package/dist/index.d.ts +66 -28
- package/dist/index.js +3487 -655
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +74 -53
- package/dist/mcp.js.map +1 -1
- package/dist/{model-bundle-FSPZZ2EM.js → model-bundle-2C5IYDLE.js} +5 -5
- package/dist/{models-CJPAQK5R.js → models-SEQZHZFT.js} +5 -5
- package/dist/{parser-SCUTZAIJ.js → parser-3FNXEP6T.js} +708 -250
- package/dist/parser-3FNXEP6T.js.map +1 -0
- package/dist/{parser-A4TMPJAM.js → parser-FJBJXRJK.js} +708 -250
- package/dist/parser-FJBJXRJK.js.map +1 -0
- package/dist/{parser-VCXE4I5A.cjs → parser-HVEKF73B.cjs} +733 -275
- package/dist/parser-HVEKF73B.cjs.map +1 -0
- package/dist/pdf-ocr-JRDBJ6TA.cjs +14 -0
- package/dist/{pdf-ocr-MBZZ57LD.cjs.map → pdf-ocr-JRDBJ6TA.cjs.map} +1 -1
- package/dist/pdf-ocr-UUBWBEHL.js +16 -0
- package/dist/pdf-ocr-VJSF2SQC.js +13 -0
- package/dist/{profile-io-LBM263K7.js → profile-io-RUFZOZO6.js} +3 -3
- package/dist/{rasterize-46RG4ZF6.js → rasterize-IOYXR5SI.js} +3 -3
- package/dist/redact-NMIKVHMP.js +18 -0
- package/dist/redact-doc-QBHNJ2BU.js +1284 -0
- package/dist/redact-doc-QBHNJ2BU.js.map +1 -0
- package/dist/{render-NGP5T24S.js → render-YZ2TEC3N.js} +7 -7
- package/dist/seal-ECV44TUH.js +10 -0
- package/dist/{setup-AU4OCHNH.js → setup-MPIEP6XT.js} +3 -3
- package/dist/visual-ICMOWUCR.js +19 -0
- package/dist/{watch-MKPUCPXM.js → watch-RYO7MN5B.js} +12 -12
- package/package.json +2 -2
- package/dist/chunk-247ANM72.cjs.map +0 -1
- package/dist/chunk-3DUADAY2.js.map +0 -1
- package/dist/chunk-422427XJ.cjs +0 -571
- package/dist/chunk-422427XJ.cjs.map +0 -1
- package/dist/chunk-7IAQ4HOK.js.map +0 -1
- package/dist/chunk-A7QC2ZVP.js.map +0 -1
- package/dist/chunk-DZIXKL7E.js +0 -145
- package/dist/chunk-DZIXKL7E.js.map +0 -1
- package/dist/chunk-EISO3POT.js.map +0 -1
- package/dist/chunk-EP7KOI2V.js +0 -571
- package/dist/chunk-EP7KOI2V.js.map +0 -1
- package/dist/chunk-FOJZNMMK.js.map +0 -1
- package/dist/chunk-ILU76UF3.js.map +0 -1
- package/dist/chunk-KVWV4ULP.js +0 -516
- package/dist/chunk-KVWV4ULP.js.map +0 -1
- package/dist/chunk-L7DMSMAG.cjs.map +0 -1
- package/dist/chunk-QC5T6D4J.js.map +0 -1
- package/dist/chunk-QOMNEWCQ.cjs.map +0 -1
- package/dist/chunk-TSFS5VKD.js.map +0 -1
- package/dist/chunk-VQ5W4MYO.js.map +0 -1
- package/dist/chunks-SX77P5CV.js +0 -10
- package/dist/image-ocr-FLIL7MGN.js.map +0 -1
- package/dist/image-ocr-WCAYXLOA.js.map +0 -1
- package/dist/image-ocr-ZTYAGV3W.cjs.map +0 -1
- package/dist/parser-A4TMPJAM.js.map +0 -1
- package/dist/parser-SCUTZAIJ.js.map +0 -1
- package/dist/parser-VCXE4I5A.cjs.map +0 -1
- package/dist/pdf-ocr-76SAUXMZ.js +0 -13
- package/dist/pdf-ocr-CPU55CVF.js +0 -16
- package/dist/pdf-ocr-MBZZ57LD.cjs +0 -14
- package/dist/redact-7ILEAUTS.js +0 -12
- package/dist/seal-RGUPOLXD.js +0 -10
- package/dist/visual-NZLYIYEM.js +0 -19
- /package/dist/{-AQKXLFIM.js.map → -Z4TJ3QGK.js.map} +0 -0
- /package/dist/{chunk-ZWD734EY.js.map → chunk-7SE4EZ45.js.map} +0 -0
- /package/dist/{chunk-GDW4YP7K.js.map → chunk-GLSBEEZJ.js.map} +0 -0
- /package/dist/{chunk-JQEFP45L.js.map → chunk-GUJ4Q73I.js.map} +0 -0
- /package/dist/{chunk-ZWOFQRIB.js.map → chunk-HIJUKZHM.js.map} +0 -0
- /package/dist/{chunk-TNCKOL2O.js.map → chunk-LCW7SEPG.js.map} +0 -0
- /package/dist/{chunk-UET462HB.js.map → chunk-TITDJWVZ.js.map} +0 -0
- /package/dist/{chunk-C7FQBSON.js.map → chunk-V3DX4DUF.js.map} +0 -0
- /package/dist/{chunk-DOGPOY4B.js.map → chunk-VDN7LMPL.js.map} +0 -0
- /package/dist/{chunk-EDNJLUSE.js.map → chunk-VJIL6PIL.js.map} +0 -0
- /package/dist/{chunk-NS55SM7A.js.map → chunk-WJJGW5PL.js.map} +0 -0
- /package/dist/{chunks-SX77P5CV.js.map → chunks-CCMRL4MJ.js.map} +0 -0
- /package/dist/{formula-JGFTXWYT.js.map → formula-7RANCW5L.js.map} +0 -0
- /package/dist/{formula-5S7WWXGH.js.map → formula-7UYJOVTB.js.map} +0 -0
- /package/dist/{model-bundle-FSPZZ2EM.js.map → model-bundle-2C5IYDLE.js.map} +0 -0
- /package/dist/{models-CJPAQK5R.js.map → models-SEQZHZFT.js.map} +0 -0
- /package/dist/{pdf-ocr-76SAUXMZ.js.map → pdf-ocr-UUBWBEHL.js.map} +0 -0
- /package/dist/{pdf-ocr-CPU55CVF.js.map → pdf-ocr-VJSF2SQC.js.map} +0 -0
- /package/dist/{profile-io-LBM263K7.js.map → profile-io-RUFZOZO6.js.map} +0 -0
- /package/dist/{rasterize-46RG4ZF6.js.map → rasterize-IOYXR5SI.js.map} +0 -0
- /package/dist/{redact-7ILEAUTS.js.map → redact-NMIKVHMP.js.map} +0 -0
- /package/dist/{render-NGP5T24S.js.map → render-YZ2TEC3N.js.map} +0 -0
- /package/dist/{seal-RGUPOLXD.js.map → seal-ECV44TUH.js.map} +0 -0
- /package/dist/{setup-AU4OCHNH.js.map → setup-MPIEP6XT.js.map} +0 -0
- /package/dist/{visual-NZLYIYEM.js.map → visual-ICMOWUCR.js.map} +0 -0
- /package/dist/{watch-MKPUCPXM.js.map → watch-RYO7MN5B.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/table/visual.ts","../src/index.ts","../src/hwpx/parser.ts","../src/hwpx/com-fallback.ts","../src/hwpx/crypto.ts","../src/hwpx/styles.ts","../src/hwpx/para-heading.ts","../src/hwpx/table-build.ts","../src/hwpx/page-boundary.ts","../src/hwpx/notes.ts","../src/hwpx/run-spans.ts","../src/hwpx/section-walker.ts","../src/hwpx/images.ts","../src/hwpx/metadata.ts","../src/hwpx/zip-sections.ts","../src/hwp3/parser.ts","../src/hwp3/reader.ts","../src/hwp3/drawing.ts","../src/hwp3/johab-symbols.ts","../src/hwp3/johab.ts","../src/hwp3/records.ts","../src/hwp3/crypto.ts","../src/hwp3/table.ts","../src/hwp5/sentinel.ts","../src/xlsx/parser.ts","../src/xls/record.ts","../src/xls/encoding.ts","../src/xls/sst.ts","../src/xls/cell.ts","../src/xls/parser.ts","../src/docx/parser.ts","../src/docx/equation.ts","../src/hwpml/parser.ts","../src/form/match.ts","../src/form/recognize.ts","../src/form/filler.ts","../src/form/filler-hwpx.ts","../src/form/click-here.ts","../src/table/classifier.ts","../src/table/analyze.ts","../src/page-markdown.ts","../src/hwpx/generator.ts","../src/hwpx/geometry.ts","../src/hwpx/gaejosik.ts","../src/hwpx/gongmun.ts","../src/hwpx/gen-ids.ts","../src/hwpx/md-runs.ts","../src/hwpx/gen-page.ts","../src/hwpx/gen-header.ts","../src/hwpx/chart-gen.ts","../src/hwpx/gen-gongmun-fit.ts","../src/hwpx/gen-gaejosik.ts","../src/diff/text-diff.ts","../src/roundtrip/markdown-units.ts","../src/hwpx/gen-table-bf.ts","../src/hwpx/gen-profile.ts","../src/hwpx/gen-image.ts","../src/hwpx/gen-table.ts","../src/hwpx/gen-gongmun-extra.ts","../src/hwpx/gen-docframe.ts","../src/hwpx/equation-generate.ts","../src/hwpx/gen-section.ts","../src/hwpx/gen-levels.ts","../src/hwpx/style-registry.ts","../src/hwpx/gongmun-scheme.ts","../src/hwpx/outline.ts","../src/hwpx/fit-line.ts","../src/hwpx/gen-marker.ts","../src/hwpx/gongmun-typo.ts","../src/hwpx/gen-frame-seoul.ts","../src/hwpx/gen-frame-ministry.ts","../src/hwpx/gen-gongmun.ts","../src/diff/compare.ts","../src/form/templates.ts","../src/hwpx/extract-profile.ts","../src/hwpx/font-catalog.ts","../src/hwpx/gongmun-lint.ts","../src/hwpx/munche-lint.ts","../src/roundtrip/patcher.ts","../src/roundtrip/table-rows.ts","../src/roundtrip/table-patch.ts","../src/roundtrip/table-insert.ts","../src/roundtrip/hwpx-entries.ts","../src/roundtrip/hwp5-patch.ts","../src/roundtrip/ole-surgeon.ts","../src/validate.ts","../src/roundtrip/session.ts"],"sourcesContent":["/**\n * 분류된 표 ↔ 렌더 region 조인 (#76 Task 6·7). bbox 는 여기서 계산하지 않는다 — #75 의 RenderRegion.sourceId 로 IRTable.sourceId 를 잇는다\n * (HWPX 는 `hp:tbl id`, HWP5 는 table-ids.ts 의 문서 순번 `t{N}` — 파서·렌더 어댑터가 같은 프리패스를 쓴다).\n */\n\nimport { readFile } from \"node:fs/promises\"\nimport { parse } from \"../index.js\"\nimport type { IRBlock, IRTable, TableClassificationSummary } from \"../types.js\"\nimport type { PageBBox } from \"../render/scene.js\"\nimport { renderDocumentToScene } from \"../render/document.js\"\nimport { extractRenderedRegions } from \"../render/regions.js\"\nimport { detectFormat } from \"../detect.js\"\nimport { KordocError, toArrayBuffer } from \"../utils.js\"\nimport { collectTableBlocks } from \"./classifier.js\"\n\nexport type TableVisualPolicy = \"none\" | \"non-tabular\" | \"non-tabular-and-uncertain\" | \"all\"\n\nexport interface ExtractTableVisualOptions {\n /** 어떤 분류에 crop 을 만들지 — 기본 non-tabular-and-uncertain. none 이면 분류·region 만 */\n policy?: TableVisualPolicy\n format?: \"png\" | \"jpeg\"\n paddingPt?: number\n /** 페이지 래스터 최대 폭 px */\n maxWidthPx?: number\n}\n\nexport interface ExtractedTableCrop { page: number; bbox: PageBBox; mimeType: \"image/png\" | \"image/jpeg\"; data: Buffer }\n\nexport interface ExtractedTable {\n /** sourceId(HWPX `hp:tbl id` · HWP5 `t{N}`) 또는 문서 순서 `tbl-N` */\n id: string\n page: number\n table: IRTable\n classification: TableClassificationSummary\n sourceId?: string\n regions: PageBBox[]\n crops: ExtractedTableCrop[]\n /** 표별 경고 — region 미매칭·중복 매칭·렌더 미지원 형식 */\n warnings: string[]\n}\n\nfunction wantsCrop(kind: TableClassificationSummary[\"kind\"], policy: TableVisualPolicy): boolean {\n if (policy === \"none\") return false\n if (policy === \"all\") return true\n if (kind === \"non-tabular-layout\") return true\n return policy === \"non-tabular-and-uncertain\" && kind === \"uncertain\"\n}\n\n/** 문서 → 분류된 표 목록(+HWPX·HWP 는 region·crop). 정상 parse 는 래스터하지 않는다 — 이 API 만 명시적으로 */\nexport async function extractTables(input: string | ArrayBuffer | Buffer, options: ExtractTableVisualOptions = {}): Promise<ExtractedTable[]> {\n const policy = options.policy ?? \"non-tabular-and-uncertain\"\n const buffer = typeof input === \"string\" ? toArrayBuffer(await readFile(input)) : Buffer.isBuffer(input) ? toArrayBuffer(input) : input\n const parsed = await parse(buffer, { classifyTables: true })\n if (!parsed.success) throw new KordocError(`파싱 실패: ${parsed.error}`)\n const blocks: IRBlock[] = collectTableBlocks(parsed.blocks)\n const out: ExtractedTable[] = blocks.map((b, i) => ({\n id: b.table!.sourceId ?? `tbl-${i + 1}`, page: b.pageNumber ?? 1, table: b.table!, classification: b.table!.classification!,\n sourceId: b.table!.sourceId, regions: [], crops: [], warnings: [],\n }))\n if (out.length === 0) return out\n const format = detectFormat(buffer)\n if (format !== \"hwpx\" && format !== \"hwp\") {\n for (const t of out) t.warnings.push(`${format} 은 렌더 미지원 — region·crop 없음`)\n return out\n }\n // region 조인 — sourceId 1:1. 중복·미매칭은 경고\n let scene\n try { scene = (await renderDocumentToScene(buffer, { reflow: true })).scene } catch (e) {\n for (const t of out) t.warnings.push(`렌더 실패 — region 없음: ${e instanceof Error ? e.message : String(e)}`)\n return out\n }\n const bySource = new Map<string, typeof scene.regions>()\n for (const r of scene.regions) if (r.type === \"table\" && r.sourceId) (bySource.get(r.sourceId) ?? bySource.set(r.sourceId, []).get(r.sourceId)!).push(r)\n const cropIds = new Set<string>()\n for (const t of out) {\n if (!t.sourceId) { t.warnings.push(\"sourceId 없음 — region 조인 불가\"); continue }\n const hits = bySource.get(t.sourceId) ?? []\n if (hits.length === 0) { t.warnings.push(`렌더 region 미매칭(sourceId ${t.sourceId})`); continue }\n if (hits.length > 1) { t.warnings.push(`렌더 region 중복 매칭(sourceId ${t.sourceId}, ${hits.length}개) — 첫 개체만`) }\n t.regions = hits[0].regions.map(b => ({ ...b }))\n t.page = hits[0].page\n t.table.regions = t.regions.map(b => ({ page: b.page, x: b.x, y: b.y, width: b.width, height: b.height }))\n if (wantsCrop(t.classification.kind, policy)) cropIds.add(hits[0].id)\n }\n if (cropIds.size === 0) return out\n const assets = await extractRenderedRegions(buffer, { types: [\"table\"], format: options.format, paddingPt: options.paddingPt, maxWidthPx: options.maxWidthPx, reflow: true, filter: r => cropIds.has(r.id) })\n for (const t of out) {\n if (!t.sourceId) continue\n for (const a of assets) if (a.region.sourceId === t.sourceId) t.crops.push({ page: a.page, bbox: a.bbox, mimeType: a.mimeType, data: a.data })\n }\n return out\n}\n","/**\n * kordoc — 모두 파싱해버리겠다\n *\n * HWP, HWPX, PDF → Markdown 변환 통합 라이브러리\n */\n\nimport { readFile } from \"fs/promises\"\nimport { detectFormat, detectOle2Format, detectZipFormat, isHwpxFile, isOldHwpFile, isPdfFile, isZipFile } from \"./detect.js\"\nimport { parseHwpxDocument } from \"./hwpx/parser.js\"\nimport { parseHwp5Document } from \"./hwp5/parser.js\"\nimport { parseHwp3Document } from \"./hwp3/parser.js\"\nimport { isComFallbackAvailable, extractTextViaCom, comResultToParseResult } from \"./hwpx/com-fallback.js\"\nimport { isDistributionSentinel } from \"./hwp5/sentinel.js\"\n// pdfjs-dist는 optional peer dep (37MB) — PDF 안 쓰는 사용자를 위해 dynamic import\n// import { parsePdfDocument } from \"./pdf/parser.js\"\nimport { parseXlsxDocument } from \"./xlsx/parser.js\"\nimport { parseXlsDocument } from \"./xls/parser.js\"\nimport { parseDocxDocument } from \"./docx/parser.js\"\nimport { parseHwpmlDocument } from \"./hwpml/parser.js\"\nimport type { ParseResult, ParseOptions, IRBlock } from \"./types.js\"\nimport { classifyError, sanitizeError, toArrayBuffer } from \"./utils.js\"\nimport { fillFormFields } from \"./form/filler.js\"\nimport type { FillResult } from \"./form/filler.js\"\nimport type { FillValue, FillInput } from \"./form/match.js\"\nimport { fillHwpx } from \"./form/filler-hwpx.js\"\nimport type { HwpxFillResult } from \"./form/filler-hwpx.js\"\nimport { blocksToMarkdown } from \"./table/builder.js\"\nimport { classifyTableTree } from \"./table/analyze.js\"\nimport { blocksToPages } from \"./page-markdown.js\"\nimport { markdownToHwpx } from \"./hwpx/generator.js\"\n\n// ─── 메인 API ────────────────────────────────────────\n\n/**\n * 파일 버퍼를 자동 감지하여 Markdown으로 변환\n *\n * @example\n * ```ts\n * import { parse } from \"kordoc\"\n * // 파일 경로로 파싱\n * const result = await parse(\"document.hwp\")\n * // 또는 Buffer로 파싱\n * const result = await parse(buffer)\n * ```\n */\nexport async function parse(input: string | ArrayBuffer | Buffer, options?: ParseOptions): Promise<ParseResult> {\n let buffer: ArrayBuffer\n // 파일 경로 입력 시 filePath를 options에 자동 설정 (DRM COM fallback에 필요)\n const opts = typeof input === \"string\" && !options?.filePath\n ? { ...options, filePath: input }\n : options\n if (typeof input === \"string\") {\n try {\n const buf = await readFile(input)\n buffer = toArrayBuffer(buf)\n } catch (err) {\n const msg = err instanceof Error && \"code\" in err && (err as NodeJS.ErrnoException).code === \"ENOENT\"\n ? `파일을 찾을 수 없습니다: ${input}`\n : `파일 읽기 실패: ${input}`\n return { success: false, fileType: \"unknown\", error: msg, code: \"PARSE_ERROR\" }\n }\n } else if (Buffer.isBuffer(input)) {\n buffer = toArrayBuffer(input)\n } else {\n buffer = input\n }\n\n if (!buffer || buffer.byteLength === 0) {\n return { success: false, fileType: \"unknown\", error: \"빈 버퍼이거나 유효하지 않은 입력입니다.\", code: \"EMPTY_INPUT\" }\n }\n const format = detectFormat(buffer)\n\n const result = await dispatch(format, buffer, opts)\n // images:false: 포맷별 파서가 풀어 둔 이미지 바이트를 결과에서 뗀다 (PDF 는 파서가 PNG 인코딩부터 건너뜀)\n if (result.success && opts?.images === false) {\n delete result.images\n dropImageBytes(result.blocks)\n }\n // opt-in 표 분류(#76) — 구조 파싱 뒤 메타만 붙인다. 기본(미지정/false)은 산출 불변\n if (result.success && opts?.classifyTables) classifyTableTree(result.blocks)\n // 페이지별 마크다운(#68)은 파서가 채운 pageNumber 의 사영이라 여기서 한 번에\n // 붙인다. 포맷별 파서를 직접 부르는 호출자는 `blocksToPages(result.blocks)` 로\n // 같은 값을 얻는다.\n if (result.success && !result.pages) {\n const pages = blocksToPages(result.blocks)\n if (pages) return { ...result, pages }\n }\n return result\n}\n\n/** 블록 트리(자식·표 셀·캡션)에서 이미지 바이트(imageData)를 뗀다. 그림 자리 표시 블록은 남긴다 */\nfunction dropImageBytes(blocks: IRBlock[] | undefined, depth = 0): void {\n if (!blocks || depth > 64) return\n for (const b of blocks) {\n if (b.imageData) delete b.imageData\n dropImageBytes(b.children, depth + 1)\n if (b.table) {\n for (const row of b.table.cells) for (const cell of row) dropImageBytes(cell.blocks, depth + 1)\n dropImageBytes(b.table.captionBlocks, depth + 1)\n }\n }\n}\n\nasync function dispatch(\n format: ReturnType<typeof detectFormat>,\n buffer: ArrayBuffer,\n opts: ParseOptions | undefined,\n): Promise<ParseResult> {\n switch (format) {\n case \"hwpx\": {\n // ZIP 기반 포맷 세분화: HWPX, XLSX, DOCX, PPTX 구분\n const zipFormat = await detectZipFormat(buffer)\n if (zipFormat === \"xlsx\") return parseXlsx(buffer, opts)\n if (zipFormat === \"docx\") return parseDocx(buffer, opts)\n if (zipFormat === \"pptx\") {\n return { success: false, fileType: \"pptx\", error: \"PPTX 파일은 지원하지 않는 파일 형식입니다.\", code: \"UNSUPPORTED_FORMAT\" }\n }\n // unknown은 손상 ZIP·비표준 섹션 경로의 HWPX 복구를 위해 기존 파서로 전달\n return parseHwpx(buffer, opts)\n }\n case \"hwp\": {\n // OLE2 기반 포맷 세분화: HWP 5.x vs XLS (Excel 97-2003)\n const ole2Format = detectOle2Format(buffer)\n if (ole2Format === \"xls\") return parseXls(buffer, opts)\n return parseHwp(buffer, opts)\n }\n case \"hwp3\":\n return parseHwp3(buffer, opts)\n case \"hwpml\":\n return parseHwpml(buffer, opts)\n case \"pdf\":\n return parsePdf(buffer, opts)\n case \"image\":\n return parseImage(buffer, opts)\n default:\n return { success: false, fileType: \"unknown\", error: \"지원하지 않는 파일 형식입니다.\", code: \"UNSUPPORTED_FORMAT\" }\n }\n}\n\n/** 이미지(PNG/JPEG/WebP)를 OCR 로 Markdown 변환 — 텍스트층이 없으므로 OCR 상시 적용 */\nexport async function parseImage(buffer: ArrayBuffer, options?: ParseOptions): Promise<ParseResult> {\n try {\n const { parseImageDocument } = await import(\"./ocr/image-ocr.js\")\n const { blocks, warnings } = await parseImageDocument(buffer, options)\n return {\n success: true,\n fileType: \"image\",\n markdown: blocksToMarkdown(blocks),\n blocks,\n warnings: warnings.length ? warnings : undefined,\n pageCount: 1,\n }\n } catch (err) {\n return { success: false, fileType: \"image\", error: sanitizeError(err), code: classifyError(err) }\n }\n}\n\n/** HWP 3.x (구버전 한컴 워드프로세서) 파일을 Markdown 으로 변환. */\nexport async function parseHwp3(buffer: ArrayBuffer, options?: ParseOptions): Promise<ParseResult> {\n try {\n const { markdown, blocks, metadata, outline, warnings } = parseHwp3Document(buffer, options)\n return { success: true, fileType: \"hwp3\", markdown, blocks, metadata, outline, warnings, pageCount: metadata?.pageCount }\n } catch (err) {\n // 에러 메시지 정제 — KordocError만 그대로, 내부 에러는 일반화 (MCP 노출 일관성)\n return { success: false, fileType: \"hwp3\", error: sanitizeError(err), code: classifyError(err) }\n }\n}\n\n// ─── 포맷별 API ──────────────────────────────────────\n\n/** HWPX 파일을 Markdown으로 변환 */\nexport async function parseHwpx(buffer: ArrayBuffer, options?: ParseOptions): Promise<ParseResult> {\n try {\n const { markdown, blocks, metadata, outline, warnings, images } = await parseHwpxDocument(buffer, options)\n return { success: true, fileType: \"hwpx\", markdown, blocks, metadata, outline, warnings, images: images?.length ? images : undefined, pageCount: metadata?.pageCount }\n } catch (err) {\n return { success: false, fileType: \"hwpx\", error: sanitizeError(err), code: classifyError(err) }\n }\n}\n\n/** HWP 5.x 바이너리 파일을 Markdown으로 변환 */\nexport async function parseHwp(buffer: ArrayBuffer, options?: ParseOptions): Promise<ParseResult> {\n try {\n const { markdown, blocks, metadata, outline, warnings, images } = parseHwp5Document(Buffer.from(buffer), options)\n\n // 배포용 HWP 5.x 감지 — 본문이 \"상위 버전의 배포용 문서입니다...\" 플레이스홀더뿐이면\n // COM fallback으로 재시도 (Windows + 한컴오피스 환경에서만). 이슈 #25 대응.\n if (isDistributionSentinel(markdown) && isComFallbackAvailable() && options?.filePath) {\n try {\n const { pages, pageCount, warnings: comWarns } = extractTextViaCom(options.filePath)\n if (pages.some(p => p && p.trim().length > 0)) {\n const com = comResultToParseResult(pages, pageCount, comWarns)\n return {\n success: true,\n fileType: \"hwp\",\n markdown: com.markdown,\n blocks: com.blocks,\n metadata: com.metadata,\n warnings: com.warnings,\n pageCount,\n }\n }\n } catch {\n // COM 실패 시 기존 결과(경고 문자열 포함) 그대로 반환\n }\n }\n\n return { success: true, fileType: \"hwp\", markdown, blocks, metadata, outline, warnings, images: images?.length ? images : undefined, pageCount: metadata?.pageCount }\n } catch (err) {\n return { success: false, fileType: \"hwp\", error: sanitizeError(err), code: classifyError(err) }\n }\n}\n\n/** PDF 파일에서 텍스트를 추출하여 Markdown으로 변환 */\nexport async function parsePdf(buffer: ArrayBuffer, options?: ParseOptions): Promise<ParseResult> {\n let parsePdfDocument: typeof import(\"./pdf/parser.js\").parsePdfDocument\n try {\n const mod = await import(\"./pdf/parser.js\")\n parsePdfDocument = mod.parsePdfDocument\n } catch {\n return {\n success: false, fileType: \"pdf\",\n error: \"PDF 파싱에 pdfjs-dist가 필요합니다. 설치: npm install pdfjs-dist\",\n code: \"MISSING_DEPENDENCY\",\n }\n }\n try {\n const { markdown, blocks, metadata, outline, warnings, isImageBased, pageQuality, qualitySummary, images } = await parsePdfDocument(buffer, options)\n return { success: true, fileType: \"pdf\", markdown, blocks, metadata, outline, warnings, isImageBased, pageQuality, qualitySummary, images, pageCount: metadata?.pageCount }\n } catch (err) {\n const isImageBased = err instanceof Error && \"isImageBased\" in err ? true : undefined\n return { success: false, fileType: \"pdf\", error: sanitizeError(err), code: classifyError(err), isImageBased }\n }\n}\n\n/** XLSX 파일을 Markdown으로 변환 */\nexport async function parseXlsx(buffer: ArrayBuffer, options?: ParseOptions): Promise<ParseResult> {\n try {\n const { markdown, blocks, metadata, warnings } = await parseXlsxDocument(buffer, options)\n return { success: true, fileType: \"xlsx\", markdown, blocks, metadata, warnings, pageCount: metadata?.pageCount }\n } catch (err) {\n return { success: false, fileType: \"xlsx\", error: sanitizeError(err), code: classifyError(err) }\n }\n}\n\n/** XLS (Excel 97-2003) 파일을 Markdown으로 변환 */\nexport async function parseXls(buffer: ArrayBuffer, options?: ParseOptions): Promise<ParseResult> {\n try {\n const { markdown, blocks, metadata, warnings } = await parseXlsDocument(buffer, options)\n return { success: true, fileType: \"xls\", markdown, blocks, metadata, warnings, pageCount: metadata?.pageCount }\n } catch (err) {\n return { success: false, fileType: \"xls\", error: sanitizeError(err), code: classifyError(err) }\n }\n}\n\n/** DOCX 파일을 Markdown으로 변환 */\nexport async function parseDocx(buffer: ArrayBuffer, options?: ParseOptions): Promise<ParseResult> {\n try {\n const { markdown, blocks, metadata, outline, warnings, images } = await parseDocxDocument(buffer, options)\n return { success: true, fileType: \"docx\", markdown, blocks, metadata, outline, warnings, images: images?.length ? images : undefined, pageCount: metadata?.pageCount }\n } catch (err) {\n return { success: false, fileType: \"docx\", error: sanitizeError(err), code: classifyError(err) }\n }\n}\n\n/** HWPML (XML 기반 한컴 문서) 파일을 Markdown으로 변환 */\nexport async function parseHwpml(buffer: ArrayBuffer, options?: ParseOptions): Promise<ParseResult> {\n try {\n const { markdown, blocks, metadata, outline, warnings } = parseHwpmlDocument(buffer, options)\n return { success: true, fileType: \"hwpml\", markdown, blocks, metadata, outline, warnings, pageCount: metadata?.pageCount }\n } catch (err) {\n return { success: false, fileType: \"hwpml\", error: sanitizeError(err), code: classifyError(err) }\n }\n}\n\n// ─── 서식 채우기 API ────────────────────────────────\n\n/**\n * 서식 채우기 출력 포맷\n * - \"markdown\": 마크다운 텍스트\n * - \"hwpx\": 새로 생성한 HWPX (스타일 초기화)\n * - \"hwpx-preserve\": 원본 HWPX ZIP 직접 수정 (스타일 100% 보존, HWPX 입력만 가능)\n */\nexport type FillOutputFormat = \"markdown\" | \"hwpx\" | \"hwpx-preserve\"\n\n/** 서식 채우기 결과 */\nexport interface FillFormOutput {\n /** 채워진 문서 (markdown: string, hwpx/hwpx-preserve: ArrayBuffer) */\n output: string | ArrayBuffer\n /** 출력 포맷 */\n format: FillOutputFormat\n /** 채우기 상세 — filled 필드 목록 + unmatched 라벨 */\n fill: { filled: import(\"./types.js\").FormField[]; unmatched: string[] }\n}\n\n/**\n * 서식 문서를 파싱하여 필드를 채우고, 원하는 포맷으로 출력.\n *\n * - \"hwpx-preserve\": HWPX 입력 → 원본 ZIP XML 직접 수정 (테두리/폰트/병합 등 100% 보존)\n * - \"hwpx\": 아무 포맷 → IRBlock → Markdown → HWPX 생성 (스타일 초기화됨)\n * - \"markdown\": 아무 포맷 → IRBlock → Markdown\n *\n * @example\n * ```ts\n * // HWPX 원본 스타일 보존 채우기\n * const result = await fillForm(\"신청서.hwpx\", { \"성명\": \"홍길동\" }, \"hwpx-preserve\")\n * writeFileSync(\"결과.hwpx\", Buffer.from(result.output as ArrayBuffer))\n *\n * // 아무 포맷 → 마크다운 채우기\n * const result = await fillForm(\"신청서.hwp\", { \"성명\": \"홍길동\" })\n * console.log(result.output) // 채워진 마크다운\n * ```\n */\nexport async function fillForm(\n input: string | ArrayBuffer | Buffer,\n values: Record<string, FillInput>,\n outputFormat: FillOutputFormat = \"markdown\",\n): Promise<FillFormOutput> {\n // 입력 버퍼 준비\n let buffer: ArrayBuffer\n if (typeof input === \"string\") {\n const buf = await readFile(input)\n buffer = toArrayBuffer(buf)\n } else if (Buffer.isBuffer(input)) {\n buffer = toArrayBuffer(input)\n } else {\n buffer = input\n }\n\n // hwpx-preserve: 원본 HWPX ZIP 직접 수정 (스타일 보존)\n if (outputFormat === \"hwpx-preserve\") {\n const format = detectFormat(buffer)\n // detectFormat은 ZIP이면 \"hwpx\" 반환 (XLSX/DOCX 포함), 세분화 필요\n if (format === \"hwpx\") {\n const zipFormat = await detectZipFormat(buffer)\n if (zipFormat !== \"hwpx\") {\n throw new Error(`hwpx-preserve 포맷은 HWPX 입력만 지원합니다 (감지된 포맷: ${zipFormat})`)\n }\n } else {\n throw new Error(`hwpx-preserve 포맷은 HWPX 입력만 지원합니다 (감지된 포맷: ${format})`)\n }\n const hwpxResult = await fillHwpx(buffer, values)\n return {\n output: hwpxResult.buffer,\n format: \"hwpx-preserve\",\n fill: { filled: hwpxResult.filled, unmatched: hwpxResult.unmatched },\n }\n }\n\n // 일반 경로: parse → IRBlock → fill → output\n const parsed = await parse(buffer)\n if (!parsed.success) {\n throw new Error(`서식 파싱 실패: ${parsed.error}`)\n }\n\n const fill = fillFormFields(parsed.blocks, values)\n const markdown = blocksToMarkdown(fill.blocks)\n\n if (outputFormat === \"hwpx\") {\n const hwpxBuffer = await markdownToHwpx(markdown)\n return { output: hwpxBuffer, format: \"hwpx\", fill }\n }\n\n return { output: markdown, format: \"markdown\", fill }\n}\n\n// ─── 게임체인저 API ─────────────────────────────────\n\nexport { compare, diffBlocks } from \"./diff/compare.js\"\nexport { extractFormFields, isLabelCell, extractFormSchema, inferFieldType } from \"./form/recognize.js\"\nexport type { FormFieldType, FormFieldSchema, FormSchemaResult } from \"./form/recognize.js\"\nexport { fillFormFields } from \"./form/filler.js\"\nexport { ValueCursor, formatFillValue, fillWithUniqueGuard } from \"./form/match.js\"\nexport type { FillValue, FillInput } from \"./form/match.js\"\nexport type { FillResult } from \"./form/filler.js\"\nexport { fillHwpx } from \"./form/filler-hwpx.js\"\nexport type { HwpxFillResult } from \"./form/filler-hwpx.js\"\nexport { extractClickHereFields } from \"./form/click-here.js\"\nexport type { ClickHereField } from \"./form/click-here.js\"\nexport { BUILTIN_TEMPLATES, resolveBuiltinTemplate, readBuiltinTemplate, readBuiltinTemplateSample } from \"./form/templates.js\"\nexport type { BuiltinTemplate } from \"./form/templates.js\"\nexport { placeSealHwpx } from \"./form/seal.js\"\nexport type { SealOp, SealPlacement, PlaceSealResult } from \"./form/seal.js\"\nexport { markdownToHwpx } from \"./hwpx/generator.js\"\nexport type { HwpxTheme, MarkdownToHwpxOptions } from \"./hwpx/generator.js\"\nexport type { PageOptions } from \"./hwpx/gen-page.js\"\nexport type {\n FormatProfile, TableProfile, CellProfile, BorderFillDef, BorderDef, CharPrDef,\n} from \"./hwpx/generator.js\"\nexport { hwpxToProfile } from \"./hwpx/extract-profile.js\"\nexport { normalizeGongmunPreset, PRESET_ALIAS, incompatibleGongmunWarnings } from \"./hwpx/gongmun.js\"\nexport { isKnownFont, unknownFontWarnings } from \"./hwpx/font-catalog.js\"\nexport { lintGongmunText, gongmunLintWarnings } from \"./hwpx/gongmun-lint.js\"\nexport type { GongmunLintFinding } from \"./hwpx/gongmun-lint.js\"\nexport { lintMuncheText, muncheLintWarnings, usesGaejosikMunche } from \"./hwpx/munche-lint.js\"\nexport type { MuncheLintFinding, MuncheLineKind } from \"./hwpx/munche-lint.js\"\nexport {\n charWidthEm1000, measureTextWidth, simulateWrap, simulateWrapKeepWord, fitRatioForFewerLines,\n SPACE_EM_FIXED, SPACE_EM_FONT,\n} from \"./hwpx/text-metrics.js\"\nexport type { MeasureOptions, WrapResult, WrapMode } from \"./hwpx/text-metrics.js\"\nexport type {\n GongmunOptions,\n GongmunPreset,\n GongmunPresetInput,\n GongmunNumbering,\n GongmunFont,\n} from \"./hwpx/gongmun.js\"\nexport { patchHwpx } from \"./roundtrip/patcher.js\"\nexport { patchHwp } from \"./roundtrip/hwp5-patch.js\"\nexport type { PatchResult, PatchSkip, PatchOptions } from \"./types.js\"\nexport { validateHwpx } from \"./validate.js\"\nexport type { ValidateResult, ValidateIssue } from \"./validate.js\"\nexport { redactText, redactMarkdown, DEFAULT_REDACT_RULES } from \"./redact.js\"\nexport type { RedactRule, RedactHit, RedactTextResult, RedactOptions } from \"./redact.js\"\nexport { blocksToChunks } from \"./chunks.js\"\nexport type { DocChunk, ChunkOptions } from \"./chunks.js\"\n\n// ─── 에디터 통합 API (v3.1) ─────────────────────────\n\nexport { HwpxSession, openHwpxDocument, patchHwpxBlocks } from \"./roundtrip/session.js\"\nexport type {\n BlockEdit, BlockCapability, BlockCapabilityInfo, CellCapability, BlockSourceRef,\n} from \"./roundtrip/session.js\"\n// 소스맵 저수준 API — 블록↔원본 바인딩을 직접 다루는 고급 사용자용\nexport { scanSectionXml, buildParagraphSplices, buildRangeSplices, applySplices } from \"./roundtrip/source-map.js\"\nexport type {\n SectionScan, ScanParagraph, ScanCell, ScanTable, ScanParaKind, SpliceEdit, TRange,\n} from \"./roundtrip/source-map.js\"\nexport { renderHtml, markdownToPdf, blocksToPdf } from \"./print/renderer.js\"\nexport type { PrintPreset, PrintOptions, PageMargin } from \"./print/renderer.js\"\nexport { renderHwpxToSvg, renderDocument, renderDocumentToScene, extractRenderedRegions, renderSceneToHtml, renderHwp5Pages } from \"./render/index.js\"\n// 표 분류·시각 추출 (#76)\nexport { classifyTable, collectTableBlocks } from \"./table/classifier.js\"\nexport type { ClassifyContext } from \"./table/classifier.js\"\nexport { classifyTableTree, chooseTableRepresentation } from \"./table/analyze.js\"\nexport type { TableRepresentation } from \"./table/analyze.js\"\nexport { hasStructuredCellContent, flattenLayoutTables } from \"./table/builder.js\"\nexport { extractTables } from \"./table/visual.js\"\nexport type { ExtractTableVisualOptions, ExtractedTable, ExtractedTableCrop, TableVisualPolicy } from \"./table/visual.js\"\nexport type {\n RenderSvgOptions, RenderSvgResult, RenderScene, ScenePage, RenderRegion, PageBBox, RenderObjectType, RenderSourceFormat,\n RenderFormat, RenderDocumentOptions, RenderDocumentResult, RenderAsset, SceneRenderOptions, SceneRenderResult,\n ExtractRegionOptions, RegionAsset,\n} from \"./render/index.js\"\n\n// ─── Re-exports ──────────────────────────────────────\n\nexport { detectFormat, detectOle2Format, detectZipFormat, isHwpxFile, isOldHwpFile, isPdfFile, isZipFile } from \"./detect.js\"\nexport type {\n ParseResult, ParseSuccess, ParseFailure, FileType,\n PageMarkdown, PageQuality, DocumentQualitySummary,\n IRBlock, IRBlockType, IRTable, IRCell, CellContext,\n BoundingBox, InlineStyle, ImageData, ExtractedImage,\n DocumentMetadata, ParseOptions, ErrorCode,\n ParseWarning, WarningCode, OutlineItem,\n DiffResult, BlockDiff, CellDiff, DiffChangeType,\n FormField, FormResult,\n OcrProvider, WatchOptions,\n} from \"./types.js\"\nexport { blocksToMarkdown } from \"./table/builder.js\"\nexport { blocksToPages } from \"./page-markdown.js\"\nexport { VERSION } from \"./utils.js\"\n","/**\n * HWPX 파서 — manifest 멀티섹션, colSpan/rowSpan, 중첩테이블\n *\n * lexdiff 기반 + edu-facility-ai 손상ZIP 복구\n *\n * 엔트리(parseHwpxDocument)와 재수출만 남김 — 구현은 목적별 모듈로 분리:\n * parser-shared.ts — 공유 상수(ZIP 한도)·타입(SectionShared/WalkCtx)·XML 유틸\n * styles.ts — head.xml 스타일/번호매기기 파싱 + 스타일 기반 헤딩 감지\n * para-heading.ts — 항목부호 자동번호 포맷 해석\n * section-walker.ts — 섹션 XML 워커 (상호재귀 클러스터)\n * table-build.ts — TableState → IRTable 구성\n * images.ts — 이미지 ref → ZIP 바이너리 해제\n * metadata.ts — Dublin Core 메타데이터\n * zip-sections.ts — 손상 ZIP 복구 + Manifest 섹션 경로 해석\n */\n\nimport JSZip from \"jszip\"\nimport { blocksToMarkdown } from \"../table/builder.js\"\nimport type { DocumentMetadata, InternalParseResult, IRBlock, OutlineItem, ParseOptions, ParseWarning } from \"../types.js\"\nimport { KordocError, precheckZipSize } from \"../utils.js\"\n// 테스트 호환성 re-export\nexport { precheckZipSize } from \"../utils.js\"\nimport { parsePageRange } from \"../page-range.js\"\nimport { isComFallbackAvailable, isEncryptedHwpx, extractTextViaCom, comResultToParseResult } from \"./com-fallback.js\"\nimport { decryptHwpxInPlace } from \"./crypto.js\"\nimport { applyPageText, createSectionShared, MAX_DECOMPRESS_SIZE, MAX_ZIP_ENTRIES, ZipBombError } from \"./parser-shared.js\"\nimport { extractHwpxStyles, detectHwpxHeadings } from \"./styles.js\"\nimport { parseSectionXml } from \"./section-walker.js\"\nimport { extractImagesFromZip } from \"./images.js\"\nimport { extractHwpxMetadata } from \"./metadata.js\"\nimport { extractFromBrokenZip, resolveSectionPaths, readKordocLayout } from \"./zip-sections.js\"\n\nexport { extractHwpxMetadataOnly } from \"./metadata.js\"\n\n/** Section fallback must replace provisional layout pages throughout the block tree. */\nfunction assignSectionPage(block: IRBlock, sectionNum: number): void {\n const pending = [block]\n while (pending.length > 0) {\n const current = pending.pop()!\n current.pageNumber = sectionNum\n for (const child of current.children ?? []) pending.push(child)\n for (const caption of current.table?.captionBlocks ?? []) pending.push(caption)\n for (const row of current.table?.cells ?? []) {\n for (const cell of row) {\n for (const child of cell.blocks ?? []) pending.push(child)\n }\n }\n }\n}\n\n// stripDtd는 utils.js에서 import\n\nexport async function parseHwpxDocument(buffer: ArrayBuffer, options?: ParseOptions): Promise<InternalParseResult> {\n // Best-effort 사전 검증 — CD 선언 크기 기반 (위조 가능, 실제 방어는 per-file 누적 체크)\n precheckZipSize(buffer, MAX_DECOMPRESS_SIZE, MAX_ZIP_ENTRIES)\n\n let zip: JSZip\n\n try {\n zip = await JSZip.loadAsync(buffer)\n } catch {\n return extractFromBrokenZip(buffer)\n }\n\n // loadAsync 후 실제 엔트리 수 검증 — CD 위조와 무관한 진짜 방어선\n const actualEntryCount = Object.keys(zip.files).length\n if (actualEntryCount > MAX_ZIP_ENTRIES) {\n throw new KordocError(\"ZIP 엔트리 수 초과 (ZIP bomb 의심)\")\n }\n\n // ── 암호 감지: manifest.xml에 encryption-data가 있으면 비밀번호 복호 → COM fallback ──\n const manifestFile = zip.file(\"META-INF/manifest.xml\")\n if (manifestFile) {\n const manifestXml = await manifestFile.async(\"text\")\n if (isEncryptedHwpx(manifestXml)) {\n // 비밀번호가 주어졌으면 제자리 복호 — 이후 경로는 평문 문서와 완전히 같다\n if (options?.password) {\n await decryptHwpxInPlace(zip, manifestXml, options.password)\n } else {\n // 파일 경로가 options에 있으면 COM fallback 시도\n if (isComFallbackAvailable() && options?.filePath) {\n const { pages, pageCount, warnings } = extractTextViaCom(options.filePath)\n if (pages.some(p => p && p.trim().length > 0)) {\n return comResultToParseResult(pages, pageCount, warnings)\n }\n }\n // 메시지에 \"DRM\"을 넣지 않는다 — classifyError가 DRM_PROTECTED(비밀번호로 못 여는\n // 문서보안)로 분류해, 정작 암호만 주면 열리는 문서를 호출자가 포기하게 만든다.\n throw new KordocError(\n \"암호로 보호된 HWPX 파일입니다. password 옵션에 열기 암호를 지정하세요.\",\n )\n }\n }\n }\n\n // ZIP 전체 파일 누적 압축해제 크기 추적 (비섹션 파일 포함)\n const decompressed = { total: 0 }\n\n // 메타데이터 추출 (best-effort)\n const metadata: DocumentMetadata = {}\n await extractHwpxMetadata(zip, metadata, decompressed)\n\n // 스타일 정보 추출 (best-effort)\n const styleMap = await extractHwpxStyles(zip, decompressed)\n const warnings: ParseWarning[] = []\n\n const sectionPaths = await resolveSectionPaths(zip)\n if (sectionPaths.length === 0) throw new KordocError(\"HWPX에서 섹션 파일을 찾을 수 없습니다\")\n\n // (#66) 실제 페이지 경계: 조판 캐시(linesegarray)가 있으면 pages 필터를 실제 페이지로\n // 적용해야 하므로 섹션을 미리 스킵할 수 없다 — 전 섹션 파싱 후 모드 확정, 블록 단위 필터.\n let allBlocks: IRBlock[] = []\n const shared = createSectionShared()\n // 자사 생성 파일 왕복 채널 게이트 — 인라인 강조 span·인용 복원은 default 레이아웃 한정\n shared.kordocLayout = await readKordocLayout(zip)\n shared.keepTrailingEmptyCols = options?.keepTrailingEmptyCols\n shared.keepEmptyParagraphs = options?.keepEmptyParagraphs\n // 섹션 근사 폴백 시 블록 pageNumber를 섹션 번호로 되돌리기 위한 구간 기록\n const sectionRanges: Array<{ sectionNum: number; start: number; end: number }> = []\n let parsedSections = 0\n for (let si = 0; si < sectionPaths.length; si++) {\n const file = zip.file(sectionPaths[si])\n if (!file) continue\n try {\n const xml = await file.async(\"text\")\n decompressed.total += xml.length * 2\n if (decompressed.total > MAX_DECOMPRESS_SIZE) throw new ZipBombError(\"ZIP 압축 해제 크기 초과 (ZIP bomb 의심)\")\n const start = allBlocks.length\n allBlocks.push(...parseSectionXml(xml, styleMap, warnings, si + 1, shared))\n sectionRanges.push({ sectionNum: si + 1, start, end: allBlocks.length })\n parsedSections++\n options?.onProgress?.(parsedSections, sectionPaths.length)\n } catch (secErr) {\n // bomb 가드만 전체 실패로 승격 — 한 섹션의 XML fatalError(KordocError)는\n // PARTIAL_PARSE로 강등해 나머지 섹션 파싱을 계속한다\n if (secErr instanceof ZipBombError) throw secErr\n warnings.push({ page: si + 1, message: `섹션 ${si + 1} 파싱 실패: ${secErr instanceof Error ? secErr.message : \"알 수 없는 오류\"}`, code: \"PARTIAL_PARSE\" })\n }\n }\n\n // 페이지 모드 확정 — 전 섹션의 조판 캐시가 신뢰 가능할 때만 실제 페이지(layout)\n const layoutPages = shared.pageState.allUsable && parsedSections > 0\n metadata.pageMode = layoutPages ? \"layout\" : \"section\"\n metadata.pageCount = layoutPages ? Math.max(shared.pageState.base, 1) : sectionPaths.length\n if (!layoutPages) {\n // 섹션 근사 — 종전(v4.7.2까지) 의미 그대로 pageNumber = 섹션 번호\n for (const r of sectionRanges) {\n for (let b = r.start; b < r.end; b++) assignSectionPage(allBlocks[b], r.sectionNum)\n }\n }\n\n // 페이지 범위 필터 — layout: 실제 페이지, section: 섹션 번호 (종전 섹션 스킵과 동일 결과)\n if (options?.pages) {\n const pageFilter = parsePageRange(options.pages, metadata.pageCount)\n allBlocks = allBlocks.filter(b => b.pageNumber != null && pageFilter.has(b.pageNumber))\n if (!layoutPages) {\n warnings.push({ code: \"PAGE_BOUNDARY_APPROXIMATE\", message: \"조판 캐시가 없어 pages 필터를 섹션 단위 근사로 적용했습니다\" })\n }\n }\n const blocks = allBlocks\n\n // 머리말/꼬리말 — 문서당 1회, 본문 앞/뒤에 자연스럽게 배치\n applyPageText(blocks, shared)\n\n // 이미지 블록에서 ZIP 바이너리 추출 — 전체 파싱 시 본문 미참조 BinData(꼬리말 그림·imgBrush 배경)도 스윕\n const images = await extractImagesFromZip(zip, blocks, decompressed, warnings, !options?.pages)\n\n // 스타일 기반 헤딩 감지\n detectHwpxHeadings(blocks, styleMap)\n\n // outline 구축\n const outline: OutlineItem[] = blocks\n .filter(b => b.type === \"heading\" && b.level && b.text)\n .map(b => ({ level: b.level!, text: b.text!, pageNumber: b.pageNumber }))\n\n const markdown = blocksToMarkdown(blocks)\n return { markdown, blocks, metadata, outline: outline.length > 0 ? outline : undefined, warnings: warnings.length > 0 ? warnings : undefined, images: images.length > 0 ? images : undefined }\n}\n\n","/**\n * HWPX DRM 문서 COM fallback — 한컴 오피스 COM API (GetPageText) 활용\n *\n * DRM 암호화된 HWPX 파일을 한컴 오피스의 HWPFrame.HwpObject COM으로 열어\n * 페이지별 텍스트를 추출한다. Windows + 한컴 오피스 설치 필수.\n *\n * 흐름: manifest.xml에 encryption-data 발견 → COM으로 Open → GetPageText(1..N) → Markdown\n */\n\nimport { execFileSync } from \"child_process\"\nimport { platform } from \"os\"\nimport type { InternalParseResult, ParseWarning, DocumentMetadata, IRBlock } from \"../types.js\"\n\n/** COM fallback 사용 가능 여부 (Windows만) */\nexport function isComFallbackAvailable(): boolean {\n return platform() === \"win32\"\n}\n\n/** manifest.xml 내용에서 encryption-data 존재 여부 확인 */\nexport function isEncryptedHwpx(manifestXml: string): boolean {\n return manifestXml.includes(\"encryption-data\")\n}\n\n/**\n * COM API로 DRM HWPX 파일의 텍스트를 추출\n * @param filePath 디스크 상의 HWPX 파일 절대 경로\n */\nexport function extractTextViaCom(filePath: string): { pages: string[]; pageCount: number; warnings: ParseWarning[] } {\n if (!isComFallbackAvailable()) {\n throw new Error(\"COM fallback은 Windows에서만 사용 가능합니다\")\n }\n\n // PowerShell 스크립트를 인라인으로 실행\n //\n // 핵심 우회: 파일을 %TEMP%로 복사한 뒤 해당 경로로 Open.\n // 한컴 오피스는 파일 경로가 \"신뢰 영역\"(사용자 Temp/AppData 등) 밖일 때\n // FilePathChecker가 경고 팝업을 띄운다. FilePathCheckerModuleExample DLL이\n // 등록된 개발 환경에서는 RegisterModule이 작동해 경고가 억제되지만, 일반\n // 사용자 환경에는 해당 DLL이 없다.\n // %TEMP% 하위 경로로 복사하면 신뢰 영역 규칙에 의해 경고가 나오지 않아\n // DLL 등록 없이도 안정적으로 DRM 텍스트를 추출할 수 있다.\n //\n // - RegisterModule: 보안 경고 1차 억제(DLL 없어도 해가 없음)\n // - GetPageText: DRM 우회 텍스트 추출\n // filePath를 single-quote로 이스케이프 (내부 ' → '')\n const escaped = filePath.replace(/'/g, \"''\")\n const ps1 = `\n[Console]::OutputEncoding = [System.Text.Encoding]::UTF8\n$ErrorActionPreference = 'Stop'\n\n$src = '${escaped}'\n$tmpDir = Join-Path $env:TEMP ('hwp-com-' + [guid]::NewGuid().ToString('N'))\n[void](New-Item -ItemType Directory -Path $tmpDir -Force)\n$tmpFile = Join-Path $tmpDir (Split-Path $src -Leaf)\nCopy-Item -LiteralPath $src -Destination $tmpFile -Force\n\ntry {\n $hwp = New-Object -ComObject HWPFrame.HwpObject\n $hwp.RegisterModule('FilePathCheckerModule', 'FilePathCheckerModuleExample') | Out-Null\n $hwp.Open($tmpFile, '', '') | Out-Null\n $pc = $hwp.PageCount\n $result = @{ pageCount = $pc; pages = @() }\n for ($p = 1; $p -le $pc; $p++) {\n $t = $hwp.GetPageText($p, 0)\n $result.pages += @($t)\n }\n $hwp.Clear(1) | Out-Null\n try { $hwp.Quit() | Out-Null } catch { }\n [System.Runtime.InteropServices.Marshal]::ReleaseComObject($hwp) | Out-Null\n [GC]::Collect()\n [GC]::WaitForPendingFinalizers()\n $result | ConvertTo-Json -Depth 3 -Compress\n} catch {\n @{ error = $_.Exception.Message } | ConvertTo-Json -Compress\n} finally {\n # 임시 파일 정리 + 좀비 Hwp.exe 방지용 garbage collect\n try { Remove-Item -LiteralPath $tmpDir -Recurse -Force -ErrorAction SilentlyContinue } catch { }\n [GC]::Collect()\n [GC]::WaitForPendingFinalizers()\n}\n`\n\n const stdout = execFileSync(\"powershell\", [\n \"-NoProfile\",\n \"-NonInteractive\",\n \"-ExecutionPolicy\", \"Bypass\",\n \"-Command\", ps1,\n ], {\n encoding: \"utf-8\",\n timeout: 120_000, // 2분 타임아웃\n windowsHide: true,\n maxBuffer: 50 * 1024 * 1024, // 50MB\n })\n\n // COM 메서드 반환값 등 JSON 앞의 garbage 제거\n const trimmed = stdout.trim()\n const jsonStart = trimmed.indexOf(\"{\")\n if (jsonStart < 0) throw new Error(`COM 출력에 JSON이 없습니다: ${trimmed.slice(0, 200)}`)\n const json = JSON.parse(trimmed.slice(jsonStart))\n if (json.error) {\n throw new Error(`COM 텍스트 추출 실패: ${json.error}`)\n }\n\n const warnings: ParseWarning[] = []\n const pages: string[] = Array.isArray(json.pages) ? json.pages : []\n const pageCount: number = json.pageCount ?? pages.length\n\n if (pages.length === 0) {\n warnings.push({ message: \"COM으로 텍스트를 추출하지 못했습니다\", code: \"COM_EMPTY\" })\n }\n\n return { pages, pageCount, warnings }\n}\n\n/**\n * COM 추출 결과를 InternalParseResult로 변환\n */\nexport function comResultToParseResult(\n pages: string[],\n pageCount: number,\n warnings: ParseWarning[],\n): InternalParseResult {\n const blocks: IRBlock[] = []\n const lines: string[] = []\n\n for (let i = 0; i < pages.length; i++) {\n const text = (pages[i] ?? \"\").trim()\n if (!text) continue\n\n // 페이지 텍스트를 paragraph 블록들로 변환\n const paragraphs = text.split(/\\n/)\n for (const para of paragraphs) {\n const trimmed = para.trim()\n if (!trimmed) continue\n blocks.push({ type: \"paragraph\", text: trimmed, pageNumber: i + 1 })\n lines.push(trimmed)\n }\n }\n\n const markdown = lines.join(\"\\n\\n\")\n // COM GetPageText는 실제 페이지 단위 (#66)\n const metadata: DocumentMetadata = { pageCount, pageMode: \"layout\" }\n\n warnings.push({\n message: \"DRM 문서: 한컴 COM API로 텍스트 추출 (서식/표 정보 제한적)\",\n code: \"DRM_COM_FALLBACK\",\n })\n\n return {\n markdown,\n blocks,\n metadata,\n warnings: warnings.length > 0 ? warnings : undefined,\n }\n}\n","/**\n * 비밀번호로 보호된 HWPX 문서 복호화.\n *\n * HWPX 암호화는 ECMA-376(MS Office) 방식이 아니라 **ODF(OpenDocument) 표준**을 따른다.\n * 각 ZIP 엔트리를 raw deflate 로 압축한 **뒤** AES-256-CBC 로 암호화하고, 평문으로 남는\n * `META-INF/manifest.xml` 의 `<odf:encryption-data>` 에 복호에 필요한 값을 적어 둔다.\n *\n * 키 = PBKDF2(SHA-256(비밀번호), salt, iteration-count) → key-size 바이트\n * 본문 = inflateRaw(AES-256-CBC-복호(엔트리))\n * 검증 = SHA-256(평문 앞 1024바이트) == manifest 의 checksum\n *\n * 알고리즘 참조: rhwp (MIT) src/parser/hwpx/crypto.rs\n * 포맷 참조: OASIS OpenDocument v1.2 §3.4 Encryption\n */\n\nimport { createDecipheriv, createHash, pbkdf2Sync, timingSafeEqual } from \"crypto\"\nimport { inflateRawSync } from \"zlib\"\nimport type JSZip from \"jszip\"\nimport { KordocError } from \"../utils.js\"\nimport { MAX_DECOMPRESS_SIZE } from \"./parser-shared.js\"\n\n/** PBKDF2 반복 횟수 상한 — 악성 manifest 가 CPU 를 무한히 태우는 것을 막는다.\n * 한컴 저장본의 실제 값은 1024. */\nconst MAX_ITERATION_COUNT = 1_000_000\n\nconst AES256_CBC = \"http://www.w3.org/2001/04/xmlenc#aes256-cbc\"\nconst START_KEY_SHA256 = \"http://www.w3.org/2000/09/xmldsig#sha256\"\nconst CHECKSUM_SHA256_1K = \"sha256-1k\"\n/** 체크섬 대상 — 평문 선두 1KB (checksum-type `…#sha256-1k`) */\nconst CHECKSUM_PREFIX_BYTES = 1024\n\n/** manifest 의 `<encryption-data>` 한 건 */\ninterface EntryCrypto {\n path: string\n checksum: Buffer\n iv: Buffer\n salt: Buffer\n iterations: number\n keySize: number\n}\n\n/** 암호 HWPX 여부 — manifest 에 encryption-data 가 하나라도 있으면 참 */\nexport function isEncryptedManifest(manifestXml: string): boolean {\n return manifestXml.includes(\"encryption-data\")\n}\n\nconst attrOf = (xml: string, name: string): string | undefined =>\n xml.match(new RegExp(`${name}=\"([^\"]*)\"`))?.[1]\n\n/**\n * manifest.xml 에서 암호화된 엔트리 목록을 뽑는다.\n * 선언된 알고리즘이 우리가 아는 조합과 다르면 조용히 건너뛰지 않고 던진다 —\n * 모르는 방식을 무시하면 \"복호 성공했는데 내용이 깨진\" 결과가 나온다.\n */\nexport function parseEncryptionManifest(manifestXml: string): EntryCrypto[] {\n const entries: EntryCrypto[] = []\n // 네임스페이스 접두사는 문서마다 다를 수 있어 `[^:>\\s]*:?file-entry` 로 받는다\n const entryRe = /<[^:>\\s]*:?file-entry\\b([^>]*)>([\\s\\S]*?)<\\/[^:>\\s]*:?file-entry>/g\n let m: RegExpExecArray | null\n while ((m = entryRe.exec(manifestXml)) !== null) {\n const [, attrs, inner] = m\n if (!inner.includes(\"encryption-data\")) continue\n\n const path = attrOf(attrs, \"full-path\")\n if (!path) continue\n\n const algorithm = attrOf(inner, \"algorithm-name\")\n const startKey = attrOf(inner, \"start-key-generation-name\")\n const checksumType = attrOf(inner, \"checksum-type\")\n if (algorithm !== AES256_CBC) {\n throw new KordocError(`지원하지 않는 HWPX 암호화 방식입니다: ${algorithm ?? \"(미상)\"}`)\n }\n if (startKey !== START_KEY_SHA256) {\n throw new KordocError(`지원하지 않는 HWPX 시작키 생성 방식입니다: ${startKey ?? \"(미상)\"}`)\n }\n if (!checksumType?.endsWith(CHECKSUM_SHA256_1K)) {\n throw new KordocError(`지원하지 않는 HWPX 체크섬 방식입니다: ${checksumType ?? \"(미상)\"}`)\n }\n\n const iterations = parseInt(attrOf(inner, \"iteration-count\") ?? \"\", 10)\n const keySize = parseInt(attrOf(inner, \"key-size\") ?? \"\", 10)\n const iv = Buffer.from(attrOf(inner, \"initialisation-vector\") ?? \"\", \"base64\")\n const salt = Buffer.from(attrOf(inner, \"salt\") ?? \"\", \"base64\")\n const checksum = Buffer.from(attrOf(inner, \"checksum\") ?? \"\", \"base64\")\n\n if (!(iterations > 0 && iterations <= MAX_ITERATION_COUNT)) {\n throw new KordocError(`HWPX 암호화 반복 횟수가 허용 범위를 벗어났습니다: ${iterations}`)\n }\n if (keySize !== 32 || iv.length !== 16 || salt.length === 0 || checksum.length !== 32) {\n throw new KordocError(`HWPX 암호화 파라미터가 올바르지 않습니다 (${path})`)\n }\n\n entries.push({ path, checksum, iv, salt, iterations, keySize })\n }\n return entries\n}\n\n/** manifest 에서 `<encryption-data>` 서브트리만 제거 — 복호 후에는 평문 문서이므로 */\nexport function stripEncryptionData(manifestXml: string): string {\n return manifestXml.replace(/<([^:>\\s]*:?)encryption-data\\b[\\s\\S]*?<\\/\\1encryption-data>/g, \"\")\n}\n\n/**\n * 엔트리 하나를 복호 + 압축 해제.\n * PBKDF2 의 PRF 는 manifest 에 적히지 않는다 — ODF 1.2 기본인 HMAC-SHA1 을 먼저 쓰고,\n * 실패하면 1.3+ 의 HMAC-SHA256 으로 재시도한다.\n * 체크섬이 맞지 않으면 undefined (비밀번호 오답 또는 손상).\n */\nfunction decryptEntry(cipher: Buffer, entry: EntryCrypto, startKey: Buffer): Buffer | undefined {\n if (cipher.length === 0 || cipher.length % 16 !== 0) return undefined\n\n for (const prf of [\"sha1\", \"sha256\"] as const) {\n try {\n const key = pbkdf2Sync(startKey, entry.salt, entry.iterations, entry.keySize, prf)\n const decipher = createDecipheriv(\"aes-256-cbc\", key, entry.iv)\n // 한컴은 PKCS#7 패딩을 붙이지 않고 전 블록을 그대로 deflate 스트림으로 넘긴다.\n // 표준대로 패딩을 벗기면 정상 문서가 손상된다.\n decipher.setAutoPadding(false)\n const raw = Buffer.concat([decipher.update(cipher), decipher.final()])\n const plain = inflateRawSync(raw, { maxOutputLength: MAX_DECOMPRESS_SIZE })\n\n const sum = createHash(\"sha256\")\n .update(plain.subarray(0, Math.min(CHECKSUM_PREFIX_BYTES, plain.length)))\n .digest()\n if (sum.length === entry.checksum.length && timingSafeEqual(sum, entry.checksum)) return plain\n } catch {\n // 이 PRF 로는 복호·압축 해제가 안 됨 — 다음 후보로\n }\n }\n return undefined\n}\n\n/**\n * 암호 HWPX 를 제자리에서 평문으로 되돌린다.\n * 복호한 내용을 같은 JSZip 인스턴스에 덮어써서, 이후 파싱 경로는 평문 문서와 완전히 같아진다.\n *\n * @returns 복호한 엔트리 수. 암호 엔트리가 없으면 0 (문서 불변).\n * @throws 비밀번호 불일치·손상, 미지원 암호화 방식\n */\nexport async function decryptHwpxInPlace(\n zip: JSZip,\n manifestXml: string,\n password: string,\n): Promise<number> {\n const entries = parseEncryptionManifest(manifestXml)\n if (entries.length === 0) return 0\n\n const startKey = createHash(\"sha256\").update(Buffer.from(password, \"utf8\")).digest()\n const decrypted: Array<{ path: string; plain: Buffer }> = []\n\n for (const entry of entries) {\n const file = zip.file(entry.path)\n if (!file) {\n throw new KordocError(`암호 목록에 있는 파일이 문서에 없습니다: ${entry.path}`)\n }\n const plain = decryptEntry(await file.async(\"nodebuffer\"), entry, startKey)\n if (!plain) {\n // 오답과 손상을 구분해 알리지 않는다 — 구분해 주면 비밀번호 추측의 신호가 된다\n throw new KordocError(\"비밀번호가 일치하지 않거나 암호화 데이터가 손상되었습니다.\")\n }\n decrypted.push({ path: entry.path, plain })\n }\n\n // 전부 복호에 성공한 뒤에 한꺼번에 반영 — 중간 실패로 반쪽짜리 문서가 남지 않게\n for (const { path, plain } of decrypted) zip.file(path, plain)\n zip.file(\"META-INF/manifest.xml\", stripEncryptionData(manifestXml))\n return decrypted.length\n}\n","/**\n * HWPX 스타일 정보 파싱 + 스타일 기반 헤딩 감지 (parser.ts에서 분리).\n * head.xml/header.xml의 charPr/style/numbering/bullet/paraHead 추출.\n */\n\nimport type JSZip from \"jszip\"\nimport { KordocError, stripDtd } from \"../utils.js\"\nimport type { IRBlock, ParseWarning } from \"../types.js\"\nimport { HEADING_RATIO_H1, HEADING_RATIO_H2, HEADING_RATIO_H3 } from \"../types.js\"\nimport { createXmlParser, findChildByLocalName, MAX_DECOMPRESS_SIZE } from \"./parser-shared.js\"\n\n// ─── HWPX 스타일 정보 ──────────────────────────────\n\nexport interface HwpxCharProperty {\n fontSize?: number // 단위: pt (hwpx는 centi-pt → /100)\n bold?: boolean\n italic?: boolean\n strike?: boolean\n underline?: boolean\n fontName?: string\n}\n\n/**\n * 취소선 모양이 실제 선 종류(OWPML LineSym2, 표 27)인지 whitelist 판정.\n * 한컴 익스포터가 취소선 없는 charPr 에도 `<hh:strikeout shape=\"3D\"/>` 류\n * placeholder 를 넣으므로, 존재 여부·비트만 믿으면 본문 전체가 취소선이 된다\n * (rhwp #154/0a967e0d 실측). 알 수 없는 값은 fail-closed 로 no-strike.\n */\nexport function isRealStrikeShape(shape: string): boolean {\n switch (shape) {\n case \"SOLID\": case \"DASH\": case \"DOT\": case \"DASH_DOT\": case \"DASH_DOT_DOT\":\n case \"LONG_DASH\": case \"CIRCLE\": case \"DOUBLE_SLIM\": case \"SLIM_THICK\":\n case \"THICK_SLIM\": case \"SLIM_THICK_SLIM\": case \"WAVE\": case \"DOUBLE_WAVE\":\n return true\n default:\n return false\n }\n}\n\n/** hh:numbering > hh:paraHead 한 수준의 정의 */\nexport interface ParaHeadDef {\n numFormat: string // DIGIT, HANGUL_SYLLABLE, CIRCLED_DIGIT 등\n text: string // \"^1.\" 같은 치환 형식 문자열\n start: number\n}\n\n/** hh:numbering 정의 — 레벨(1..10) → paraHead */\nexport interface NumberingDef {\n heads: Map<number, ParaHeadDef>\n}\n\n/** hh:paraPr > hh:heading — 문단의 자동번호/글머리표/개요 연결 정보 */\nexport interface ParaHeadingRef {\n type: \"NUMBER\" | \"BULLET\" | \"OUTLINE\"\n idRef: string\n level: number // 0-based (level=\"0\" → paraHead level 1)\n}\n\nexport interface HwpxStyleMap {\n charProperties: Map<string, HwpxCharProperty> // id → property\n styles: Map<string, { name: string; charPrId?: string; paraPrId?: string }> // id → style\n numberings: Map<string, NumberingDef> // numbering id → 정의\n bullets: Map<string, string> // bullet id → 글머리 문자\n paraHeadings: Map<string, ParaHeadingRef> // paraPr id → heading 참조\n paraIndents: Map<string, { left: number; intent: number }> // paraPr id → 들여쓰기(HWPUNIT, v4.0.4)\n}\n\n/** head.xml 또는 header.xml에서 스타일 정보 추출 */\nexport async function extractHwpxStyles(zip: JSZip, decompressed?: { total: number }): Promise<HwpxStyleMap> {\n const result: HwpxStyleMap = {\n charProperties: new Map(),\n styles: new Map(),\n numberings: new Map(),\n bullets: new Map(),\n paraHeadings: new Map(),\n paraIndents: new Map(),\n }\n\n const headerPaths = [\"Contents/header.xml\", \"header.xml\", \"Contents/head.xml\", \"head.xml\"]\n for (const hp of headerPaths) {\n const hpLower = hp.toLowerCase()\n const file = zip.file(hp) || Object.values(zip.files).find(f => f.name.toLowerCase() === hpLower) || null\n if (!file) continue\n\n try {\n const xml = await file.async(\"text\")\n if (decompressed) {\n decompressed.total += xml.length * 2\n if (decompressed.total > MAX_DECOMPRESS_SIZE) throw new KordocError(\"ZIP 압축 해제 크기 초과 (ZIP bomb 의심)\")\n }\n const parser = createXmlParser()\n const doc = parser.parseFromString(stripDtd(xml), \"text/xml\")\n if (!doc.documentElement) continue\n const domDoc = doc as unknown as Document\n\n // charProperties 파싱\n parseCharProperties(domDoc, result.charProperties)\n // styles 파싱\n parseStyleElements(domDoc, result.styles)\n // 자동번호/글머리표/개요 정의 파싱 (v3.0)\n parseNumberings(domDoc, result.numberings)\n parseBullets(domDoc, result.bullets)\n parseParaHeadings(domDoc, result.paraHeadings)\n parseParaIndents(domDoc, result.paraIndents)\n break\n } catch { continue }\n }\n\n return result\n}\n\nfunction parseCharProperties(doc: Document, map: Map<string, HwpxCharProperty>): void {\n // <hh:charPr> 또는 <charPr> 요소 탐색\n const tagNames = [\"hh:charPr\", \"charPr\", \"hp:charPr\"]\n for (const tagName of tagNames) {\n const elements = doc.getElementsByTagName(tagName)\n for (let i = 0; i < elements.length; i++) {\n const el = elements[i]\n const id = el.getAttribute(\"id\") || el.getAttribute(\"IDRef\") || \"\"\n if (!id) continue\n\n const prop: HwpxCharProperty = {}\n\n // height 속성 (centi-pt 단위)\n const height = el.getAttribute(\"height\")\n if (height) {\n const parsedHeight = parseInt(height, 10)\n if (!isNaN(parsedHeight) && parsedHeight > 0) {\n prop.fontSize = parsedHeight / 100\n }\n }\n\n // bold/italic — 정본은 자식 요소(<hh:bold/>) 존재. 속성형(bold=\"1\")은 구버전\n // HWPML 계열 잔재라 둘 다 인정한다 (실측 한컴 HWPX는 요소만 씀)\n const bold = el.getAttribute(\"bold\")\n if (bold === \"true\" || bold === \"1\") prop.bold = true\n const italic = el.getAttribute(\"italic\")\n if (italic === \"true\" || italic === \"1\") prop.italic = true\n const kids = el.childNodes\n for (let j = 0; j < (kids?.length ?? 0); j++) {\n const k = kids[j] as Element\n if (k.nodeType !== 1) continue\n const localTag = (k.tagName || \"\").replace(/^[^:]+:/, \"\")\n if (localTag === \"bold\") prop.bold = true\n else if (localTag === \"italic\") prop.italic = true\n else if (localTag === \"strikeout\") {\n // shape whitelist — placeholder(\"3D\"/\"NONE\" 등)는 취소선 아님\n const shape = k.getAttribute(\"shape\") || \"\"\n if (isRealStrikeShape(shape)) prop.strike = true\n }\n else if (localTag === \"underline\") {\n // 판별자는 type — 한컴은 밑줄 없는 charPr 에도 type=\"NONE\" 요소를 넣는다\n // (코퍼스 352파일 실측: NONE 15,603 / BOTTOM 156, TOP·CENTER 미관측).\n // BOTTOM 만 인정 — TOP(윗줄)·미지 값은 fail-closed\n if (k.getAttribute(\"type\") === \"BOTTOM\") prop.underline = true\n }\n }\n\n // 하위 요소에서 fontface 탐색\n const fontFaces = el.getElementsByTagName(\"*\")\n for (let j = 0; j < fontFaces.length; j++) {\n const ff = fontFaces[j]\n const localTag = (ff.tagName || \"\").replace(/^[^:]+:/, \"\")\n if (localTag === \"fontface\" || localTag === \"fontRef\") {\n const face = ff.getAttribute(\"face\") || ff.getAttribute(\"FontFace\")\n if (face) { prop.fontName = face; break }\n }\n }\n\n map.set(id, prop)\n }\n }\n}\n\nfunction parseStyleElements(doc: Document, map: Map<string, { name: string; charPrId?: string; paraPrId?: string }>): void {\n const tagNames = [\"hh:style\", \"style\", \"hp:style\"]\n for (const tagName of tagNames) {\n const elements = doc.getElementsByTagName(tagName)\n for (let i = 0; i < elements.length; i++) {\n const el = elements[i]\n const id = el.getAttribute(\"id\") || el.getAttribute(\"IDRef\") || String(i)\n const name = el.getAttribute(\"name\") || el.getAttribute(\"engName\") || \"\"\n const charPrId = el.getAttribute(\"charPrIDRef\") || undefined\n const paraPrId = el.getAttribute(\"paraPrIDRef\") || undefined\n map.set(id, { name, charPrId, paraPrId })\n }\n }\n}\n\n/** header.xml의 hh:numbering(paraHead 7수준) 파싱 */\nfunction parseNumberings(doc: Document, map: Map<string, NumberingDef>): void {\n const tagNames = [\"hh:numbering\", \"numbering\"]\n for (const tagName of tagNames) {\n const elements = doc.getElementsByTagName(tagName)\n for (let i = 0; i < elements.length; i++) {\n const el = elements[i]\n const id = el.getAttribute(\"id\") || \"\"\n if (!id) continue\n const def: NumberingDef = { heads: new Map() }\n const children = el.childNodes\n for (let j = 0; j < children.length; j++) {\n const ch = children[j] as Element\n if (ch.nodeType !== 1) continue\n const tag = (ch.tagName || ch.localName || \"\").replace(/^[^:]+:/, \"\")\n if (tag !== \"paraHead\") continue\n const level = parseInt(ch.getAttribute(\"level\") || \"\", 10)\n if (isNaN(level) || level < 1 || level > 10) continue\n const start = parseInt(ch.getAttribute(\"start\") || \"1\", 10)\n def.heads.set(level, {\n numFormat: ch.getAttribute(\"numFormat\") || \"DIGIT\",\n text: ch.textContent || \"\",\n start: isNaN(start) ? 1 : start,\n })\n }\n if (def.heads.size > 0) map.set(id, def)\n }\n if (map.size > 0) break\n }\n}\n\n/** header.xml의 hh:bullet 파싱 — id → 글머리 문자 (PUA는 builder의 mapPuaText가 치환) */\nfunction parseBullets(doc: Document, map: Map<string, string>): void {\n const tagNames = [\"hh:bullet\", \"bullet\"]\n for (const tagName of tagNames) {\n const elements = doc.getElementsByTagName(tagName)\n for (let i = 0; i < elements.length; i++) {\n const el = elements[i]\n const id = el.getAttribute(\"id\") || \"\"\n const char = el.getAttribute(\"char\") || \"\"\n if (id && char) map.set(id, char)\n }\n if (map.size > 0) break\n }\n}\n\n/**\n * header.xml의 hh:paraPr > hh:margin 파싱 — 문단 속성 id → 들여쓰기(HWPUNIT) (v4.0.4).\n * hc:left(단계 들여쓰기 누적)와 hc:intent(첫 줄 — 음수=내어쓰기)를 자식요소형에서 읽는다\n * (속성형 indent=\"…\"는 한컴이 무시하는 형식이라 여기서도 읽지 않음 — 생성기 규약과 동일).\n * IRBlock.indent 슬롯의 원료 — gongmun 리스트 depth 재유도 등 소비자 몫.\n */\nfunction parseParaIndents(doc: Document, map: Map<string, { left: number; intent: number }>): void {\n const tagNames = [\"hh:paraPr\", \"paraPr\"]\n for (const tagName of tagNames) {\n const elements = doc.getElementsByTagName(tagName)\n for (let i = 0; i < elements.length; i++) {\n const el = elements[i]\n const id = el.getAttribute(\"id\") || \"\"\n if (!id) continue\n const margin = findChildByLocalName(el, \"margin\")\n if (!margin) continue\n const readHu = (name: string): number => {\n const child = findChildByLocalName(margin, name)\n const v = parseInt(child?.getAttribute(\"value\") || child?.textContent || \"\", 10)\n return Number.isFinite(v) ? v : 0\n }\n const left = readHu(\"left\")\n const intent = readHu(\"intent\")\n if (left !== 0 || intent !== 0) map.set(id, { left, intent })\n }\n if (map.size > 0) break\n }\n}\n\n/** header.xml의 hh:paraPr > hh:heading 파싱 — 문단 속성 id → NUMBER/BULLET/OUTLINE 참조 */\nfunction parseParaHeadings(doc: Document, map: Map<string, ParaHeadingRef>): void {\n const tagNames = [\"hh:paraPr\", \"paraPr\"]\n for (const tagName of tagNames) {\n const elements = doc.getElementsByTagName(tagName)\n for (let i = 0; i < elements.length; i++) {\n const el = elements[i]\n const id = el.getAttribute(\"id\") || \"\"\n if (!id) continue\n const heading = findChildByLocalName(el, \"heading\")\n if (!heading) continue\n const type = heading.getAttribute(\"type\") || \"NONE\"\n if (type !== \"NUMBER\" && type !== \"BULLET\" && type !== \"OUTLINE\") continue\n const level = parseInt(heading.getAttribute(\"level\") || \"0\", 10)\n map.set(id, {\n type,\n idRef: heading.getAttribute(\"idRef\") || \"0\",\n level: isNaN(level) ? 0 : Math.max(0, Math.min(level, 9)),\n })\n }\n if (map.size > 0) break\n }\n}\n\n\n// ─── 헤딩 감지 (스타일 기반) ────────────────────────\n\n/** HWPX 스타일 기반 헤딩 감지 */\nexport function detectHwpxHeadings(blocks: IRBlock[], styleMap: HwpxStyleMap): void {\n // outline(개요) 기반 헤딩이 이미 감지된 문서는 폰트크기 휴리스틱 생략 — outline이 권위 정보\n if (blocks.some(b => b.type === \"heading\")) return\n\n // 본문 폰트 크기 결정\n let baseFontSize = 0\n const sizeFreq = new Map<number, number>()\n for (const b of blocks) {\n if (b.style?.fontSize) {\n sizeFreq.set(b.style.fontSize, (sizeFreq.get(b.style.fontSize) || 0) + 1)\n }\n }\n let maxCount = 0\n for (const [size, count] of sizeFreq) {\n if (count > maxCount) { maxCount = count; baseFontSize = size }\n }\n\n for (const block of blocks) {\n if (block.type !== \"paragraph\" || !block.text) continue\n const text = block.text.trim()\n if (text.length === 0 || text.length > 200 || /^\\d+$/.test(text)) continue\n\n let level = 0\n\n // 폰트 크기 기반\n if (baseFontSize > 0 && block.style?.fontSize) {\n const ratio = block.style.fontSize / baseFontSize\n if (ratio >= HEADING_RATIO_H1) level = 1\n else if (ratio >= HEADING_RATIO_H2) level = 2\n else if (ratio >= HEADING_RATIO_H3) level = 3\n }\n\n // \"제N조/장/절\" 패턴 — 균등배분 공백 허용 (\"제 1 장\" → \"제1장\")\n const compactText = text.replace(/\\s+/g, \"\")\n if (/^제\\d+[조장절편]/.test(compactText) && text.length <= 50) {\n if (level === 0) level = 3\n }\n\n if (level > 0) {\n block.type = \"heading\"\n block.level = level\n }\n }\n}\n","/**\n * 항목부호 자동번호 포맷 해석 (parser.ts에서 분리).\n * 한글 음절/자모·로마자·원숫자 시퀀스와 numbering 카운터로 문단머리 문자열 생성.\n */\n\nimport type { WalkCtx } from \"./parser-shared.js\"\nimport { hangulOrdinal, circledNumber, circledHangul, romanNumeral } from \"../shared/numbering.js\"\n\n// ─── 자동번호 포맷 ───────────────────────────────────\n\nconst HANGUL_JAMO_SEQ = \"ㄱㄴㄷㄹㅁㅂㅅㅇㅈㅊㅋㅌㅍㅎ\"\n\n/** 자동번호 카운터 값 → numFormat에 따른 표시 문자열 (각주·미주 번호 notes.ts 공용) */\nexport function formatHeadNumber(n: number, numFormat: string): string {\n if (n === 0 && numFormat === \"DIGIT\") return \"0\" // start=\"0\"은 유효값 — 시퀀스 포맷은 1-based라 아래 클램프 유지\n if (n <= 0) n = 1\n switch (numFormat) {\n case \"DIGIT\": return String(n)\n // 서수 시퀀스는 생성기(gongmun.ts)와 단일 소스 (v4.0.5) — 종전 mod-14 순환은\n // 15번째 형제를 다시 '가'로 만들어 한글 실렌더(가→하→거→너 단모음 연속)와 어긋났다\n case \"CIRCLED_DIGIT\": return n <= 50 ? circledNumber(n - 1) : `(${n})`\n case \"HANGUL_SYLLABLE\": return hangulOrdinal(n - 1)\n case \"CIRCLED_HANGUL_SYLLABLE\": return n <= 14 ? circledHangul(n - 1) : hangulOrdinal(n - 1)\n case \"HANGUL_JAMO\": return HANGUL_JAMO_SEQ[(n - 1) % HANGUL_JAMO_SEQ.length]\n case \"CIRCLED_HANGUL_JAMO\": return n <= 14 ? String.fromCodePoint(0x3260 + n - 1) : HANGUL_JAMO_SEQ[(n - 1) % 14]\n case \"LATIN_CAPITAL\": return String.fromCharCode(0x41 + ((n - 1) % 26))\n case \"LATIN_SMALL\": return String.fromCharCode(0x61 + ((n - 1) % 26))\n case \"CIRCLED_LATIN_CAPITAL\": return n <= 26 ? String.fromCodePoint(0x24b6 + n - 1) : String.fromCharCode(0x41 + ((n - 1) % 26))\n case \"CIRCLED_LATIN_SMALL\": return n <= 26 ? String.fromCodePoint(0x24d0 + n - 1) : String.fromCharCode(0x61 + ((n - 1) % 26))\n case \"ROMAN_CAPITAL\": return romanNumeral(n, true)\n case \"ROMAN_SMALL\": return romanNumeral(n, false)\n default: return String(n)\n }\n}\n\n/** 문단의 자동번호/글머리표/개요 해석 결과 */\nexport interface ResolvedParaHeading {\n /** 문단 텍스트 앞에 붙일 접두 (\"1.\", \"가.\", \"①\", \"-\" 등) */\n prefix?: string\n /** OUTLINE 문단의 헤딩 레벨 (1-6) */\n headingLevel?: number\n}\n\n/**\n * hp:p paraPrIDRef → paraPr heading(NUMBER/BULLET/OUTLINE) 해석.\n * NUMBER/OUTLINE은 7수준 카운터 상태기계 사용 — 같은 numbering id에서\n * 레벨별 카운터 증가, 상위 레벨 증가 시 하위 리셋. 한글은 빈 번호 문단도\n * 번호를 소비하므로 텍스트 없는 문단에서도 호출해 카운터를 진행시킨다\n * (v4.0.5 — 접두는 호출부가 텍스트 있을 때만 사용).\n */\nexport function resolveParaHeading(paraEl: Element, ctx: WalkCtx): ResolvedParaHeading | null {\n const sm = ctx.styleMap\n if (!sm) return null\n // 명명 스타일 기반 헤딩 — \"개요 N\" 스타일 참조 문단은 OUTLINE 없이도 헤딩.\n // (공문서 생성기가 개요 번호 렌더 결함을 피해 OUTLINE 대신 스타일명으로 의미 보존)\n const styleId = paraEl.getAttribute(\"styleIDRef\")\n let styleHeading: number | undefined\n if (styleId && styleId !== \"0\") {\n const st = sm.styles.get(styleId)\n const m = st && /^개요\\s*([1-6])$/.exec(st.name)\n if (m) styleHeading = Math.min(parseInt(m[1], 10), 6)\n }\n const prId = paraEl.getAttribute(\"paraPrIDRef\")\n if (!prId) return styleHeading ? { headingLevel: styleHeading } : null\n const ref = sm.paraHeadings.get(prId)\n if (!ref) return styleHeading ? { headingLevel: styleHeading } : null\n\n if (ref.type === \"BULLET\") {\n const char = sm.bullets.get(ref.idRef)\n return char ? { prefix: char } : null\n }\n\n // NUMBER는 idRef가 numbering id, OUTLINE은 secPr outlineShapeIDRef가 numbering id\n const numId = ref.type === \"OUTLINE\" ? (ctx.outlineNumId || \"1\") : ref.idRef\n const level = Math.min(ref.level + 1, 10) // 0-based 속성 → 1-based paraHead 레벨\n const headingLevel = ref.type === \"OUTLINE\" ? Math.min(ref.level + 1, 6) : undefined\n const numDef = sm.numberings.get(numId)\n if (!numDef) return headingLevel ? { headingLevel } : null\n\n let counters = ctx.shared.numState.get(numId)\n // 미사용 센티널은 -1 — 0을 쓰면 start=\"0\" numbering이 매번 미사용으로 오판돼 증가하지 않는다\n if (!counters) { counters = new Array(11).fill(-1); ctx.shared.numState.set(numId, counters) }\n const head = numDef.heads.get(level)\n counters[level] = counters[level] < 0 ? (head?.start ?? 1) : counters[level] + 1\n for (let l = level + 1; l <= 10; l++) counters[l] = -1\n\n // ^N 치환 — 참조 레벨의 카운터를 그 레벨의 numFormat으로 변환 (예: \"^1.\" → \"1.\")\n // 서식 텍스트가 명시적으로 빈 paraHead(한컴 \"번호 없음\" 개요, 생성기 왕복 포함)는\n // 접두를 발명하지 않는다 — 폴백 \"^N.\"은 해당 레벨 정의 자체가 없을 때만.\n const fmtText = head ? head.text.trim() : `^${level}.`\n const prefix = fmtText.replace(/\\^(10|[1-9])/g, (_, d) => {\n const lv = parseInt(d, 10)\n const refHead = numDef.heads.get(lv)\n // 카운터 0은 유효값(start=\"0\") — 미사용(-1)일 때만 start 폴백\n const n = counters![lv] >= 0 ? counters![lv] : (refHead?.start ?? 1)\n return formatHeadNumber(n, refHead?.numFormat || \"DIGIT\")\n })\n return { prefix: prefix || undefined, headingLevel }\n}\n\n","/**\n * HWPX 표 구성 (parser.ts에서 분리).\n * TableState → IRTable 변환(셀 메타 재부착)과 </tbl> 완료 공통 처리.\n */\n\nimport { buildTable, convertTableToText } from \"../table/builder.js\"\nimport type { IRBlock, IRCell, IRTable } from \"../types.js\"\nimport type { CellCtxEx, TableState, WalkCtx } from \"./parser-shared.js\"\n\n/**\n * TableState → IRTable 변환 — 캡션·셀 blocks(중첩표/이미지)·제목셀을 함께 attach (v3.0).\n * buildTable이 CellContext의 확장 필드를 복사하지 않으므로 cellAddr 좌표\n * (없으면 텍스트+스팬 매칭)로 결과 IRCell을 찾아 재부착한다.\n */\nfunction buildTableWithCellMeta(state: TableState, keepAnchoredEmptyCols?: boolean, keepEmptyParagraphs?: boolean): IRTable {\n const table = buildTable(state.rows, { keepAnchoredEmptyCols, keepEmptyParagraphs })\n if (state.caption) table.caption = state.caption\n if (state.sourceId) table.sourceId = state.sourceId\n // 캡션 안 중첩표는 구조도 병행 제공 — caption 문자열은 하위 호환 평탄화로 유지 (#55)\n if (state.captionBlocks?.length) table.captionBlocks = state.captionBlocks\n\n // 서수 폴백용 앵커 목록 (row-major, 병합 커버 칸 제외) — 소스 tc 수와 1:1일 때만 신뢰\n const anchors: IRCell[] = []\n {\n const covered = new Set<string>()\n for (let r = 0; r < table.rows; r++) {\n for (let c = 0; c < table.cols; c++) {\n if (covered.has(`${r},${c}`)) continue\n const cell = table.cells[r]?.[c]\n if (!cell) continue\n for (let dr = 0; dr < cell.rowSpan; dr++) {\n for (let dc = 0; dc < cell.colSpan; dc++) {\n if (dr === 0 && dc === 0) continue\n if (r + dr < table.rows && c + dc < table.cols) covered.add(`${r + dr},${c + dc}`)\n }\n }\n anchors.push(cell)\n c += cell.colSpan - 1\n }\n }\n }\n const srcCount = state.rows.reduce((s, r) => s + r.length, 0)\n const ordinalReliable = anchors.length === srcCount\n\n const claimed = new Set<IRCell>()\n let flatIdx = -1\n for (const row of state.rows) {\n for (const src of row as CellCtxEx[]) {\n flatIdx++\n // 구조(중첩표·이미지)·왕복 채널 span 문단(v4.0.4)·각주 문단이 있어야 blocks를 나른다 —\n // 평문 셀은 text 평탄화로 충분 (blocks 무게 억제). 각주 셀은 blocks 가 셀 글과 주석을\n // 나눠 가진다 (text 평탄화는 \"(주: …)\" 인라인 — 하위 호환)\n const needsBlocks = !!src.blocks && src.blocks.length > 0\n && (src.hasStructure || src.blocks.some(b => b.spans || b.footnoteText))\n if (!needsBlocks && !src.isHeader) continue\n\n // 1순위: cellAddr 절대좌표 (HWPX 표준은 항상 cellAddr 제공)\n let target: IRCell | undefined\n // keepEmptyParagraphs면 buildTable이 trim하지 않으므로 원문 그대로 비교 (#57)\n const trimmed = keepEmptyParagraphs ? src.text : src.text.trim()\n if (src.rowAddr !== undefined && src.colAddr !== undefined) {\n const cand = table.cells[src.rowAddr]?.[src.colAddr]\n if (cand && cand.text === trimmed && !claimed.has(cand)) target = cand\n }\n // 2순위: 텍스트+스팬 매칭 (cellAddr 없는 비표준 파일)\n if (!target) {\n outer: for (const irRow of table.cells) {\n for (const cand of irRow) {\n if (!claimed.has(cand) && cand.text === trimmed && cand.colSpan === src.colSpan && cand.rowSpan === src.rowSpan) {\n target = cand\n break outer\n }\n }\n }\n }\n // 3순위: 서수 폴백 — 동일 텍스트 중복/스팬 불일치로 못 찾은 셀의 blocks 유실 방지\n // (소스 tc 순서 ↔ 앵커 순서가 1:1일 때만 — 그 외엔 오부착이 유실보다 나쁨)\n if (!target && ordinalReliable) {\n const cand = anchors[flatIdx]\n if (cand && !claimed.has(cand)) target = cand\n }\n if (!target) continue\n claimed.add(target)\n if (needsBlocks) target.blocks = src.blocks\n if (src.isHeader) target.isHeader = true\n }\n }\n return table\n}\n\n/**\n * </tbl> 완료 처리 공통 로직 — walkSection/walkParagraphChildren 중복 제거.\n * 중첩표는 부모 IRCell.blocks에 IRBlock(type:'table')로 보존하고(v3.0 — 호이스팅/평탄화 제거),\n * 셀 텍스트에는 하위 호환용 평탄화 텍스트를 남긴다. 최상위 표는 블록으로 추가.\n */\nexport function completeTable(\n newTable: TableState,\n tableStack: TableState[],\n blocks: IRBlock[],\n ctx: WalkCtx\n): TableState | null {\n const parentTable = tableStack.length > 0 ? tableStack.pop()! : null\n if (newTable.rows.every(r => r.length === 0)) { // 셀 없는 표(빈 tr 만) — 캡션만 문단으로\n if (newTable.caption) blocks.push({ type: \"paragraph\", text: newTable.caption, pageNumber: ctx.page })\n return parentTable\n }\n const ir = buildTableWithCellMeta(newTable, ctx.shared.keepTrailingEmptyCols, ctx.shared.keepEmptyParagraphs)\n const block: IRBlock = { type: \"table\", table: ir, pageNumber: ctx.page }\n if (parentTable?.cell) {\n const cell = parentTable.cell\n ;(cell.blocks ??= []).push(block)\n cell.hasStructure = true\n // 하위 호환: IRCell.text는 blocks의 평탄화 텍스트를 포함한다\n let flat = convertTableToText(newTable.rows)\n if (newTable.caption) flat = newTable.caption + (flat ? \"\\n\" + flat : \"\")\n if (flat) {\n // 글자취급(treatAsChar=\"1\") 표는 앞뒤 텍스트와 같은 줄에 놓인다 — 인라인 줄이\n // 열려 있으면 공백으로 잇는다 (#52 후속). 블록/float 표(inline=false)나 문단\n // 첫 항목(lineOpen=false)은 종전대로 `\\n`으로 분리한다.\n const inlineJoin = newTable.inline === true && cell.lineOpen === true\n cell.text += (cell.text ? (inlineJoin ? \" \" : \"\\n\") : \"\") + flat\n cell.lineOpen = newTable.inline === true\n }\n } else {\n // 부모 표의 셀 밖(비정상 경로) 또는 최상위 — 블록으로 추가\n blocks.push(block)\n }\n return parentTable\n}\n","/**\n * HWPX 실제 페이지 경계 복원 (#66) — 한컴 저장본의 조판 캐시(linesegarray)로\n * 섹션 내 top-level 문단별 실제 페이지 배정을 계산한다.\n *\n * 신호 4종 (bench/corpus/pairs hwp↔hwpx↔pdf 6쌍 전수 일치로 검증):\n * 1. top-level 문단 lineseg vertpos 역행 — 페이지 로컬 좌표라 리셋 지점이 곧 경계.\n * 다단(colCount>1)은 단 이동도 리셋되므로 horzpos가 왼쪽으로 돌아올 때만 인정,\n * \"동일 v\"도 문단 첫 seg + horzpos 비전진이면 경계 (svg-render 프리패스와 동일 규칙)\n * 2. 명시적 쪽나눔 <hp:p pageBreak=\"1\"> — 같은 문단 첫 seg의 역행과 중복 시 1회만\n * 3. 페이지 걸침 표 내부 분할: 셀 직접 문단 흐름의 vertpos 리셋(셀 로컬 좌표도\n * 분할 시 0부터 재시작) — 행별 max 합산. top-level lineseg에 흔적 없는 경계 복원\n * 4. 분할 표 직후 top-level \"중간높이\"(v≥MIDPAGE_V) 역행 1회 억제 — 표 꼬리가\n * 다음 페이지 상단을 차지해 후속 텍스트가 중간 높이에서 재개되는 형태로,\n * 신호 3과 같은 경계의 이중 카운트를 막는다\n *\n * lineseg flags bit0(\"페이지의 첫 줄\", HWP5 스펙 표60)은 한컴 저장본에서 항상 0이라\n * 못 쓴다(실측). 렌더러(svg-render.ts)는 그리기용 seg 단위 배정이 필요해 이 모듈과\n * 별도 프리패스를 유지한다 — 신호 1 규칙을 고치면 양쪽을 함께 검토할 것.\n */\n\n/** 이 값 이상에서 시작하는 역행은 페이지 상단 리셋이 아니다 (신호 4 판별, HWPUNIT) */\nconst MIDPAGE_V = 2000\n\n/** 섹션 페이지 감지 결과 */\nexport interface SectionPageDetect {\n /** top-level <hp:p> → 섹션 내 0-based 페이지 (문단 시작 위치 기준) */\n paraPage: Map<Element, number>\n /** 섹션이 차지하는 페이지 수 (≥1) */\n pages: number\n /** 조판 캐시 신뢰 가능 여부 — top-level 문단 전부가 lineseg를 가질 때만 true */\n usable: boolean\n}\n\nconst localName = (el: Element): string => {\n const n = el.nodeName\n const i = n.indexOf(\":\")\n return i >= 0 ? n.slice(i + 1) : n\n}\n\nconst childElements = (parent: Node): Element[] => {\n const out: Element[] = []\n for (let c = parent.firstChild; c; c = c.nextSibling) {\n if (c.nodeType === 1) out.push(c as Element)\n }\n return out\n}\n\nconst numAttr = (el: Element, name: string): number => {\n const v = el.getAttribute(name)\n const n = v == null ? NaN : Number(v)\n return Number.isFinite(n) ? n : 0\n}\n\nconst findDescendant = (root: Element, local: string, maxDepth = 8): Element | null => {\n if (maxDepth < 0) return null\n for (const c of childElements(root)) {\n if (localName(c) === local) return c\n const found = findDescendant(c, local, maxDepth - 1)\n if (found) return found\n }\n return null\n}\n\n/** 문단의 linesegarray → lineseg 요소들 (없으면 빈 배열) */\nfunction linesegsOf(p: Element): Element[] {\n const lsa = childElements(p).find(c => localName(c) === \"linesegarray\")\n return lsa ? childElements(lsa).filter(s => localName(s) === \"lineseg\") : []\n}\n\n/** 셀 직접 문단 흐름의 vertpos 리셋 수 — 중첩 표의 문단은 세지 않는다 */\nfunction cellFlowResets(subList: Element): number {\n let prevV = Number.NEGATIVE_INFINITY\n let resets = 0\n for (const p of childElements(subList)) {\n if (localName(p) !== \"p\") continue\n for (const s of linesegsOf(p)) {\n const v = numAttr(s, \"vertpos\")\n if (v < prevV) resets++\n prevV = v\n }\n }\n return resets\n}\n\n/** 표의 내부 페이지 나눔 수 — 행별 max(셀 흐름 리셋) 합산 (같은 행 셀들은 같은 경계에서 분할) */\nfunction tableIntraBreaks(tbl: Element): number {\n const rowMax = new Map<number, number>()\n for (const tr of childElements(tbl)) {\n if (localName(tr) !== \"tr\") continue\n for (const tc of childElements(tr)) {\n if (localName(tc) !== \"tc\") continue\n const addr = childElements(tc).find(e => localName(e) === \"cellAddr\")\n const row = addr ? numAttr(addr, \"rowAddr\") : 0\n const sub = childElements(tc).find(e => localName(e) === \"subList\")\n if (!sub) continue\n const r = cellFlowResets(sub)\n rowMax.set(row, Math.max(rowMax.get(row) ?? 0, r))\n }\n }\n let sum = 0\n for (const v of rowMax.values()) sum += v\n return sum\n}\n\n/**\n * 섹션 루트에서 top-level 문단별 페이지 배정을 계산한다.\n * 문단의 페이지 = 그 문단 내용이 시작되는 페이지 (명시 쪽나눔·첫 seg 역행 반영 후).\n */\nexport function detectHwpxSectionPages(root: Element): SectionPageDetect {\n const colPr = findDescendant(root, \"colPr\")\n const multiCol = colPr ? numAttr(colPr, \"colCount\") > 1 : false\n\n const paraPage = new Map<Element, number>()\n let cur = 0\n let prevV = Number.NEGATIVE_INFINITY\n let prevH = Number.NEGATIVE_INFINITY\n let first = true\n let suppressMidReset = false\n let topParas = 0\n let parasWithSegs = 0\n\n for (const p of childElements(root)) {\n if (localName(p) !== \"p\") continue\n topParas++\n\n const explicit = p.getAttribute(\"pageBreak\") === \"1\"\n let brokeByExplicit = false\n if (explicit && !first) {\n cur++\n brokeByExplicit = true\n suppressMidReset = false\n }\n\n const segs = linesegsOf(p)\n if (segs.length > 0) parasWithSegs++\n let paraFirst = true\n let startPage = cur\n for (const s of segs) {\n const v = numAttr(s, \"vertpos\")\n const h = numAttr(s, \"horzpos\")\n const brk = v < prevV\n ? (!multiCol || h <= prevH)\n : (paraFirst && v === prevV && h <= prevH)\n if (brk && !(paraFirst && brokeByExplicit)) {\n // 신호 4: 직전 표의 셀 카운트가 소비한 경계 — 표 꼬리 아래 중간높이 재개는 억제\n if (paraFirst && suppressMidReset && v >= MIDPAGE_V) {\n // 같은 페이지 계속\n } else {\n cur++\n }\n }\n if (paraFirst) {\n suppressMidReset = false\n startPage = cur\n }\n paraFirst = false\n prevV = v\n prevH = h\n }\n // seg 없는 문단(빈 문단·캐시 누락)은 현재 페이지 상속\n paraPage.set(p, startPage)\n first = false\n\n // 신호 3: 이 문단이 호스트하는 top-level 표의 내부 분할 — 문단 뒤에 반영\n let add = 0\n for (const r of childElements(p)) {\n if (localName(r) !== \"run\") continue\n for (const t of childElements(r)) {\n if (localName(t) === \"tbl\") add += tableIntraBreaks(t)\n }\n }\n if (add > 0) {\n cur += add\n suppressMidReset = true\n }\n }\n\n return {\n paraPage,\n pages: cur + 1,\n usable: topParas > 0 && parasWithSegs === topParas,\n }\n}\n","/**\n * 각주·미주 번호 표기 (v4.14.3) — 본문 참조 부호(\"1)\"·\"문1)\"·\"*\")와 주석 본문 머리 번호.\n *\n * 한컴은 각주/미주 개체 자리에 참조 부호를 그리고, 주석 영역 첫머리에는 주석 본문 안의\n * hp:autoNum(numType=FOOTNOTE|ENDNOTE)이 같은 부호를 그린다. hp:t 원문엔 둘 다 없다\n * (한컴 PDF 실렌더: footnote-01 \"플라스틱 액체1)와 …\" / 주석 \"1) 플라스틱 액체란\",\n * 3-09월_교육_통합 본문 \"문1)\" / 미주 \"문1) ④\"). HWP5 파서(body.ts applyNoteEffect)와\n * 같은 표기라 hwp↔hwpx 쌍 대조가 맞는다.\n *\n * 파서(section-walker)와 패치 매퍼(roundtrip)가 같은 규칙을 쓰도록 DOM 비의존 순수 함수로 둔다 —\n * 매퍼는 파서가 끼운 부호를 문단 텍스트에서 되빼야 소스맵 대조가 된다.\n */\n\nimport { formatHeadNumber } from \"./para-heading.js\"\nimport { findChildByLocalName } from \"../shared/xml.js\"\n\n/** secPr footNotePr/endNotePr > autoNumFormat 또는 hp:autoNum > autoNumFormat — 리터럴 문자 속성 */\nexport interface NoteNumberFormat {\n /** DIGIT·USER_CHAR·CIRCLED_DIGIT 등 (para-heading numFormat 과 같은 이름) */\n type: string\n userChar: string\n prefixChar: string\n suffixChar: string\n}\n\n/** hp:footNote/hp:endNote 여는 태그 속성 — 코드포인트 10진 문자열 그대로 (없으면 null) */\nexport interface NoteAttrs {\n number?: string | null\n prefixChar?: string | null\n suffixChar?: string | null\n userChar?: string | null\n}\n\n/** 코드포인트 10진 속성 → 문자. 속성 없음은 undefined(구역 기본값으로), 0 은 \"\" */\nfunction codePointAttr(v: string | null | undefined): string | undefined {\n if (v == null || v === \"\") return undefined\n const n = parseInt(v, 10)\n if (!Number.isFinite(n) || n < 0 || n > 0x10ffff) return undefined\n return n === 0 ? \"\" : String.fromCodePoint(n)\n}\n\n/** 속성 조회 함수로 autoNumFormat 읽기 — DOM(getAttribute)·정규식 스캐너 공용 */\nexport function noteFormatFrom(get: (name: string) => string | null | undefined): NoteNumberFormat {\n return {\n type: get(\"type\") || \"DIGIT\",\n userChar: get(\"userChar\") ?? \"\",\n prefixChar: get(\"prefixChar\") ?? \"\",\n suffixChar: get(\"suffixChar\") ?? \"\",\n }\n}\n\n/** 번호 본체 — USER_CHAR 는 사용자 문자, 나머지는 자동번호 서식 */\nfunction noteCore(num: number, fmt: NoteNumberFormat, userChar?: string): string {\n if (fmt.type === \"USER_CHAR\") return userChar ?? fmt.userChar\n return formatHeadNumber(num, fmt.type)\n}\n\n/**\n * 본문 참조 부호 — 개체 속성(number·prefixChar·suffixChar·userChar)이 우선, 없으면 구역\n * 번호 모양(secPr footNotePr/endNotePr). 둘 다 없으면 한컴 기본 \"N)\".\n * (한컴은 기본값과 같은 장식 속성을 생략해 저장한다 — USER_CHAR \"*\" 각주는 suffixChar 없이\n * 구역 모양 suffixChar=\"\" 만 가진다, issue6044)\n */\nexport function noteRefMark(attrs: NoteAttrs, fmt?: NoteNumberFormat): string {\n const f = fmt ?? { type: \"DIGIT\", userChar: \"\", prefixChar: \"\", suffixChar: \")\" }\n const n = parseInt(attrs.number ?? \"\", 10)\n const prefix = codePointAttr(attrs.prefixChar) ?? f.prefixChar\n const suffix = codePointAttr(attrs.suffixChar) ?? f.suffixChar\n return prefix + noteCore(Number.isFinite(n) ? n : 1, f, codePointAttr(attrs.userChar)) + suffix\n}\n\n/** 주석 본문 안 hp:autoNum(FOOTNOTE|ENDNOTE) 표기 — autoNumFormat 리터럴 그대로 */\nexport function noteAutoNumText(num: string | null | undefined, fmt: NoteNumberFormat): string {\n const n = parseInt(num ?? \"\", 10)\n return fmt.prefixChar + noteCore(Number.isFinite(n) ? n : 1, fmt) + fmt.suffixChar\n}\n\n/**\n * 본문에 그리는 자동번호 종류 — 주석 머리 번호(FOOTNOTE·ENDNOTE)와 캡션 번호(PICTURE·TABLE·EQUATION,\n * \"<그림 1>\" — 한컴 실렌더·HWP5 파서 모두 방출). 쪽번호(PAGE·TOTAL_PAGE)는 머리말·꼬리말 쪽번호\n * 크롬이라 종전대로 미방출\n */\nexport function isRenderedAutoNum(numType: string | null | undefined): boolean {\n return numType === \"FOOTNOTE\" || numType === \"ENDNOTE\" || numType === \"PICTURE\" || numType === \"TABLE\" || numType === \"EQUATION\"\n}\n\n// ─── DOM 어댑터 (파서 전용) ───────────────────────────\n\n/** hp:footNote/hp:endNote 요소 → 속성 묶음 */\nexport function noteAttrsOf(el: Element): NoteAttrs {\n return {\n number: el.getAttribute(\"number\"),\n prefixChar: el.getAttribute(\"prefixChar\"),\n suffixChar: el.getAttribute(\"suffixChar\"),\n userChar: el.getAttribute(\"userChar\"),\n }\n}\n\n/** 구역 첫 secPr 의 footNotePr/endNotePr > autoNumFormat */\nexport function readSectionNoteFormats(root: Element): { footnote?: NoteNumberFormat; endnote?: NoteNumberFormat } {\n const out: { footnote?: NoteNumberFormat; endnote?: NoteNumberFormat } = {}\n const pick = (names: string[]): NoteNumberFormat | undefined => {\n for (const name of names) {\n const els = root.getElementsByTagName(name)\n if (els.length === 0) continue\n const f = findChildByLocalName(els[0], \"autoNumFormat\")\n return f ? noteFormatFrom(n => f.getAttribute(n)) : undefined\n }\n return undefined\n }\n out.footnote = pick([\"hp:footNotePr\", \"footNotePr\"])\n out.endnote = pick([\"hp:endNotePr\", \"endNotePr\"])\n return out\n}\n\n/** hp:autoNum 요소 → 표기 (주석·캡션 번호), 쪽번호 등 다른 종류면 \"\" */\nexport function noteAutoNumOf(el: Element): string {\n if (!isRenderedAutoNum(el.getAttribute(\"numType\"))) return \"\"\n const f = findChildByLocalName(el, \"autoNumFormat\")\n return noteAutoNumText(el.getAttribute(\"num\"), noteFormatFrom(n => f?.getAttribute(n)))\n}\n","/**\n * 왕복 채널 run-span 판독 (section-walker.ts에서 분리) — 인라인 강조 span·인용 paraPr·gongmun\n * 들여쓰기 depth 역산. 자사 생성 파일(content.hpf kordoc-layout) + 외래 실속성 볼드/이탤릭.\n */\n\nimport type { IRSpan } from \"../types.js\"\nimport { extractTextFromNode, type WalkCtx } from \"./parser-shared.js\"\nimport { escapeLiteralDollar } from \"../table/builder.js\"\n\n/** kordoc 생성 default 레이아웃의 인라인 코드 charPr id (gen-ids CHAR_CODE와 동기) */\nconst KORDOC_CHAR_CODE = \"4\"\n/** kordoc 생성 default 레이아웃의 인용문 paraPr id (gen-ids PARA_QUOTE와 동기) */\nexport const KORDOC_PARA_QUOTE = \"6\"\n\n/**\n * run-span 채널 모드 (v4.0.5 확장) — kordoc: 자사 default 레이아웃(고정 id 규약 전부),\n * gongmun: 자사 공문서 레이아웃(기본 charPr 0~10 블록은 default와 동일 — id4 code 유효.\n * 단 구조 볼드(report 1단계 □ 전체 CHAR_BOLD 등)가 있어 혼합 가드 필수),\n * foreign: 메타 없는 외래 한컴 문서(실속성 볼드/이탤릭만 — id 규약 없음).\n * 미지의 자사 레이아웃 값은 null — 채널 꺼짐 (id 재배치 오검출 가드).\n */\nexport type SpanMode = \"kordoc\" | \"gongmun\" | \"foreign\"\n\nexport function spanModeOf(layout: string | null | undefined): SpanMode | null {\n if (layout === \"default\") return \"kordoc\"\n if (layout === \"gongmun\") return \"gongmun\"\n if (!layout) return \"foreign\"\n return null\n}\n\n/**\n * 문단 직계 run들의 인라인 강조 span 추출. 볼드/이탤릭은 charPr id가\n * 아니라 styleMap 실속성(<hh:bold/> 등)으로 읽고, 코드만 고정 id로 식별한다(자사 한정).\n * 개체(표·이미지·수식 등)나 run 외 요소가 섞인 문단, 서식 span이 하나도 없는 문단은\n * null — 평문 경로 유지 (마커 재방출 이득이 없으면 켜지 않는다).\n * requireMixed: 무서식 span과 서식 span이 공존할 때만 인정 — 전체가 서식인 문단은\n * 구조적 서식(gongmun 1단계 볼드, 표 헤더행 볼드 등)일 개연성이 높아 마커를 억제한다.\n */\nexport function extractRunSpans(para: Element, ctx: WalkCtx, mode: SpanMode, requireMixed: boolean): IRSpan[] | null {\n const styleMap = ctx.styleMap\n if (!styleMap) return null\n const spans: IRSpan[] = []\n let styled = false\n const kids = para.childNodes\n if (!kids) return null\n for (let i = 0; i < kids.length; i++) {\n const child = kids[i] as Element\n if (child.nodeType !== 1) continue\n const tag = (child.tagName || child.localName || \"\").replace(/^[^:]+:/, \"\")\n if (tag === \"linesegarray\") continue // 조판 캐시 — 텍스트 무관\n if (tag !== \"run\" && tag !== \"r\") return null\n let text = \"\"\n const rkids = child.childNodes\n for (let j = 0; j < (rkids?.length ?? 0); j++) {\n const rc = rkids![j] as Element\n if (rc.nodeType !== 1) continue\n const rtag = (rc.tagName || rc.localName || \"\").replace(/^[^:]+:/, \"\")\n if (rtag === \"t\") {\n const tkids = rc.childNodes\n for (let k = 0; k < (tkids?.length ?? 0); k++) {\n const tk = tkids![k]\n if (tk.nodeType === 3 || tk.nodeType === 4) text += escapeLiteralDollar(tk.textContent || \"\") // 평문 경로와 같은 IR 규약\n else if (tk.nodeType === 1) {\n // 탭·빈칸 컨트롤은 공백(평문 경로와 같은 모델 — 항목부호 뒤 탭 run 이 강조 복원을 막지 않게),\n // 줄바꿈 등 나머지는 평문 경로\n const ttag = ((tk as Element).tagName || (tk as Element).localName || \"\").replace(/^[^:]+:/, \"\")\n if (ttag === \"tab\" || ttag === \"fwSpace\" || ttag === \"hwSpace\" || ttag === \"nbSpace\") text += \" \"\n else return null\n }\n }\n } else if (rtag === \"secPr\" || rtag === \"colPr\") {\n // 첫 run이 나르는 섹션 속성 — 텍스트 무관\n } else if (rtag === \"ctrl\") {\n if (extractTextFromNode(rc)) return null\n } else {\n return null // 표·이미지·수식 등 개체 동반 문단\n }\n }\n if (!text) continue\n const prId = child.getAttribute(\"charPrIDRef\") ?? \"\"\n const cp = styleMap.charProperties.get(prId)\n const span: IRSpan = { text }\n if (mode !== \"foreign\" && prId === KORDOC_CHAR_CODE) span.code = true\n else {\n if (cp?.bold) span.bold = true\n if (cp?.italic) span.italic = true\n if (cp?.strike) span.strike = true\n if (cp?.underline) span.underline = true\n }\n if (span.bold || span.italic || span.strike || span.underline || span.code) styled = true\n spans.push(span)\n }\n if (!styled || spans.length === 0) return null\n // 인접 동일 서식 span 병합 — 한컴은 편집 이력 경계에서 같은 서식 run을 임의 분할\n // 하므로(외래 문서) 그대로 두면 run마다 마커 쌍이 생긴다('**안****녕**' 오염)\n const merged: IRSpan[] = []\n for (const s of spans) {\n const last = merged[merged.length - 1]\n if (last && !!last.bold === !!s.bold && !!last.italic === !!s.italic && !!last.strike === !!s.strike && !!last.underline === !!s.underline && !!last.code === !!s.code) {\n last.text += s.text\n } else {\n merged.push(s)\n }\n }\n // requireMixed(구조적 서식 억제)는 bold/italic 에만 적용 — 취소선·밑줄은 전체 문단이\n // 통째로 그어진 경우(법령 개정문 삭제 조문·개정 표시)가 정상 패턴이라 억제하지 않는다\n if (requireMixed && !merged.some((s) => s.strike || s.underline) && !merged.some((s) => !(s.bold || s.italic || s.code))) return null\n return merged\n}\n\n/**\n * gongmun levelIndent 역산 (v4.0.5) — left = depth × 본문크기(standard/report) 또는\n * 개조식 반계단(1.0/1.5/2.0, 이후 +0.5/단계) × 본문크기 HWPUNIT. 단위는 문단 첫 run의\n * charPr 글자크기(pt×100 = HWPUNIT)로 도출 — 생성기 levelIndent가 bodyHeight를 쓰는\n * 것의 미러. 부호 시퀀스상 md 충돌 부호('-'·'*'·'N)')는 전부 법정 2단계에서만 나오므로\n * 역산 결과는 사실상 2 — 그래도 파일 자체가 정본이 되게 지문으로 산출한다.\n */\nexport function gongmunDepthFromIndent(para: Element, left: number, ctx: WalkCtx): number | null {\n const styleMap = ctx.styleMap\n if (!styleMap) return null\n let unit = 0\n const kids = para.childNodes\n for (let i = 0; i < (kids?.length ?? 0); i++) {\n const child = kids[i] as Element\n if (child.nodeType !== 1) continue\n const tag = (child.tagName || child.localName || \"\").replace(/^[^:]+:/, \"\")\n if (tag !== \"run\" && tag !== \"r\") continue\n const size = styleMap.charProperties.get(child.getAttribute(\"charPrIDRef\") ?? \"\")?.fontSize\n if (size) unit = size * 100\n break\n }\n if (!unit) return null\n const r = left / unit\n const nearInt = Math.round(r)\n // 정수배 = standard/report(depth=r), x.5 계단 = 개조식(depth = 2r-1: 1.5→2, 2.5→4)\n const depth = Math.abs(r - nearInt) < 0.2 ? nearInt : Math.round(2 * r - 1)\n return depth >= 1 && depth < 8 ? depth : null\n}\n","/**\n * HWPX 섹션 XML 워커 (parser.ts에서 분리).\n *\n * walkSection ↔ walkParagraphChildren ↔ extractParagraphInfo ↔ handleShape ↔\n * extractDrawTextBlocks가 상호재귀하는 클러스터라 한 파일로 유지한다 —\n * 더 쪼개면 인위적 경계에 순환 import만 생김.\n */\n\nimport { KordocError, sanitizeHref, stripDtd } from \"../utils.js\"\nimport { convertTableToText, escapeLiteralDollar, MAX_COLS, MAX_ROWS } from \"../table/builder.js\"\nimport type { IRBlock, IRCell, IRSpan, IRTable, InlineStyle, ParseWarning } from \"../types.js\"\nimport { hmlToLatex } from \"./equation.js\"\nimport {\n clampSpan,\n createSectionShared,\n createXmlParser,\n extractTextFromNode,\n findChildByLocalName,\n MAX_XML_DEPTH,\n type CellCtxEx,\n type SectionShared,\n type TableState,\n type WalkCtx,\n} from \"./parser-shared.js\"\nimport type { HwpxStyleMap } from \"./styles.js\"\nimport { resolveParaHeading } from \"./para-heading.js\"\nimport { completeTable } from \"./table-build.js\"\nimport { detectHwpxSectionPages } from \"./page-boundary.js\"\nimport { noteAttrsOf, noteAutoNumOf, noteRefMark, readSectionNoteFormats } from \"./notes.js\"\nimport { extractRunSpans, gongmunDepthFromIndent, KORDOC_PARA_QUOTE, spanModeOf } from \"./run-spans.js\"\n\n// ─── 섹션 XML 파싱 ──────────────────────────────────\n\nexport function parseSectionXml(xml: string, styleMap?: HwpxStyleMap, warnings?: ParseWarning[], sectionNum?: number, shared?: SectionShared): IRBlock[] {\n const parser = createXmlParser(warnings)\n const doc = parser.parseFromString(stripDtd(xml), \"text/xml\")\n if (!doc.documentElement) return []\n\n const ctx: WalkCtx = { styleMap, warnings, sectionNum, shared: shared ?? createSectionShared() }\n // 변경추적 삭제 구간은 섹션 경계를 넘지 않음 — 비정상 파일에서 본문 전체 소실 방지\n ctx.shared.track.deleteDepth = 0\n\n // 실제 페이지 프리패스 (#66) — 조판 캐시로 top-level 문단별 페이지 배정.\n // 신뢰 불가(usable=false) 섹션이 하나라도 있으면 호출자(parser.ts)가 섹션 근사로 되돌린다.\n const detect = detectHwpxSectionPages(doc.documentElement as unknown as Element)\n const ps = ctx.shared.pageState\n if (!detect.usable) ps.allUsable = false\n ctx.paraPage = detect.paraPage\n ctx.pageBase = ps.base\n ctx.page = ps.base + 1\n ps.base += detect.pages\n\n // secPr outlineShapeIDRef — 개요 문단의 자동번호 정의 참조\n for (const tagName of [\"hp:secPr\", \"secPr\"]) {\n const els = doc.getElementsByTagName(tagName)\n if (els.length > 0) {\n const v = els[0].getAttribute(\"outlineShapeIDRef\")\n if (v) ctx.outlineNumId = v\n break\n }\n }\n // 각주·미주 번호 모양 — 본문 참조 부호(\"1)\"·\"문1)\") 재구성 (notes.ts)\n ctx.noteFormats = readSectionNoteFormats(doc.documentElement as unknown as Element)\n\n const blocks: IRBlock[] = []\n walkSection(doc.documentElement as unknown as Node, blocks, null, [], ctx)\n return blocks\n}\n\n/** pic/shape 요소에서 이미지 참조 경로 추출 (binaryItemIDRef 또는 href) — MAX_XML_DEPTH 가드 */\nfunction extractImageRef(el: Element, depth: number = 0): string | null {\n if (depth > MAX_XML_DEPTH) return null\n // HWPX: <hp:imgRect> 또는 <hp:img> 내 binaryItemIDRef 속성\n // 또는 하위에서 img 관련 속성 탐색\n const children = el.childNodes\n if (!children) return null\n for (let i = 0; i < children.length; i++) {\n const child = children[i] as Element\n if (child.nodeType !== 1) continue\n const tag = (child.tagName || child.localName || \"\").replace(/^[^:]+:/, \"\")\n if (tag === \"imgRect\" || tag === \"img\" || tag === \"imgClip\") {\n const ref = child.getAttribute(\"binaryItemIDRef\") || child.getAttribute(\"href\") || \"\"\n if (ref) return ref\n }\n // lineShape > imgRect 같은 중첩 구조\n const nested = extractImageRef(child, depth + 1)\n if (nested) return nested\n }\n // 직접 속성 체크\n const directRef = el.getAttribute(\"binaryItemIDRef\") || \"\"\n if (directRef) return directRef\n return null\n}\n\nfunction walkSection(\n node: Node, blocks: IRBlock[],\n tableCtx: TableState | null, tableStack: TableState[],\n ctx: WalkCtx, depth: number = 0\n): void {\n if (depth > MAX_XML_DEPTH) return\n const children = node.childNodes\n if (!children) return\n\n for (let i = 0; i < children.length; i++) {\n const el = children[i] as Element\n if (el.nodeType !== 1) continue\n\n const tag = el.tagName || el.localName || \"\"\n const localTag = tag.replace(/^[^:]+:/, \"\")\n\n switch (localTag) {\n case \"tbl\": {\n // kordoc 왕복 채널 (v4.0.5 P2) — 생성기가 heading 의미를 장식표(개조식 표지·\n // 장헤더·1페이지형 제목박스)에 인코딩할 때 제목 셀 name 속성에 심은 마커.\n // 마커가 있으면 표 대신 heading으로 복원(h#), 파생물(목차·제목반복)은 스킵해\n // 재파싱 중복을 막는다. 최상위 표에서만 판독 — 셀 안 중첩표는 일반 표 취급.\n if (!tableCtx) {\n const chan = kordocTableChannel(el, ctx)\n if (chan) {\n if (chan.kind === \"heading\" && chan.text) {\n blocks.push({ type: \"heading\", level: chan.level, text: chan.text, pageNumber: ctx.page })\n }\n break\n }\n }\n if (tableCtx) tableStack.push(tableCtx)\n const newTable: TableState = { rows: [], currentRow: [], cell: null, sourceId: el.getAttribute(\"id\") ?? undefined }\n walkSection(el, blocks, newTable, tableStack, ctx, depth + 1)\n tableCtx = completeTable(newTable, tableStack, blocks, ctx)\n break\n }\n\n // 표/도표 캡션 — IRTable.caption으로 보존 (v3.0, 기존 무음 드롭 수정)\n case \"caption\": {\n const cap = collectSubListContent(el, ctx)\n if (cap.text) {\n if (tableCtx) {\n tableCtx.caption = (tableCtx.caption ? tableCtx.caption + \"\\n\" : \"\") + cap.text\n if (cap.hasStructure) (tableCtx.captionBlocks ??= []).push(...cap.blocks)\n } else {\n // 활성 표 컨텍스트 밖의 캡션 — 무음 드롭 대신 문단으로 보존 (#46)\n blocks.push({ type: \"paragraph\", text: cap.text, pageNumber: ctx.page })\n }\n }\n break\n }\n\n case \"tr\":\n if (tableCtx) {\n tableCtx.currentRow = []\n walkSection(el, blocks, tableCtx, tableStack, ctx, depth + 1)\n // 빈 <hp:tr/> 도 행이다 — 위 행 병합에 통째로 덮인 행을 한컴·rhwp 는 빈 tr 로 쓴다.\n // 버리면 행 수가 줄어 그 아래 앵커가 격자 밖으로 밀렸다 (builder 는 이제 앵커 행으로 격자를 늘림)\n tableCtx.rows.push(tableCtx.currentRow)\n tableCtx.currentRow = []\n }\n break\n\n case \"tc\":\n if (tableCtx) {\n tableCtx.cell = { text: \"\", colSpan: 1, rowSpan: 1 }\n if (el.getAttribute(\"header\") === \"1\" || el.getAttribute(\"header\") === \"true\") tableCtx.cell.isHeader = true\n walkSection(el, blocks, tableCtx, tableStack, ctx, depth + 1)\n if (tableCtx.cell) {\n tableCtx.currentRow.push(tableCtx.cell)\n tableCtx.cell = null\n }\n }\n break\n\n case \"cellAddr\":\n if (tableCtx?.cell) {\n const ca = parseInt(el.getAttribute(\"colAddr\") || \"\", 10)\n const ra = parseInt(el.getAttribute(\"rowAddr\") || \"\", 10)\n if (!isNaN(ca)) tableCtx.cell.colAddr = ca\n if (!isNaN(ra)) tableCtx.cell.rowAddr = ra\n }\n break\n\n case \"cellSpan\":\n if (tableCtx?.cell) {\n const rawCs = parseInt(el.getAttribute(\"colSpan\") || \"1\", 10)\n const cs = isNaN(rawCs) ? 1 : rawCs\n const rawRs = parseInt(el.getAttribute(\"rowSpan\") || \"1\", 10)\n const rs = isNaN(rawRs) ? 1 : rawRs\n tableCtx.cell.colSpan = clampSpan(cs, MAX_COLS)\n tableCtx.cell.rowSpan = clampSpan(rs, MAX_ROWS)\n }\n break\n\n case \"p\": {\n // 실제 페이지 갱신 (#66) — 프리패스 맵은 top-level 문단만 담아 중첩 문단은 자연 상속\n const paraPg = ctx.paraPage?.get(el)\n if (paraPg !== undefined && ctx.pageBase !== undefined) ctx.page = ctx.pageBase + paraPg + 1\n const { text: rawText, href, footnote, style, segments, placeholderSpans } = extractParagraphInfo(el, ctx.styleMap, ctx)\n let text = rawText\n let headingLevel: number | undefined\n // 자동번호/글머리표/개요 접두 재현 (v3.0). 텍스트 유무와 무관하게 호출 —\n // 한글은 빈 번호 문단도 번호를 소비하므로, 텍스트 있을 때만 advance하면\n // 빈 문단 이후 항목 전부가 1씩 낮게 재현된다 (v4.0.5 카운터 드리프트)\n const ph = resolveParaHeading(el, ctx)\n if (text) {\n if (ph?.prefix) text = ph.prefix + \" \" + text\n headingLevel = ph?.headingLevel\n }\n // 인라인 표 포함 문단 (#49/#50) — 문단 텍스트를 통째로 먼저 push하면 원문에서\n // 표가 앞설 때 순서가 역전된다. 표 경계 조각을 walkParagraphChildren의 onTbl\n // 콜백으로 표 직전마다 방출해 문서 순서를 보존한다 (treatAsChar inline 표 배치).\n if (segments) {\n const cell = tableCtx?.cell ?? null\n // 문단 시작 — 인라인 줄은 아직 닫힘. 첫 항목은 이전 문단과 `\\n`으로 분리되고,\n // 이후 같은 문단의 글자취급 표·텍스트끼리는 공백으로 이어진다 (#52 후속)\n if (cell) cell.lineOpen = false\n const segs = [...segments]\n if (ph?.prefix) {\n const fi = segs.findIndex(s => s)\n if (fi >= 0) segs[fi] = ph.prefix + \" \" + segs[fi]\n }\n let segIdx = 0\n let first = true\n let lastCellBlock: IRBlock | undefined\n const flush = () => {\n const s = segs[segIdx++]\n if (!s) return\n const block: IRBlock = { type: \"paragraph\", text: s, pageNumber: ctx.page }\n if (cell) lastCellBlock = block\n if (first && !cell) {\n first = false\n if (style) block.style = style\n if (href) block.href = href\n if (footnote) block.footnoteText = footnote\n }\n if (cell) {\n // IRCell.text 평탄화는 blocks 순서를 따라야 한다 (#52, 타입 계약). 종전엔\n // 문단 텍스트를 통째로 선append해 중첩표 평탄화(completeTable)보다 앞서\n // 역전됐다 — 세그먼트를 표와 교대로 나온 자리에서 이어붙여 문서 순서 보존.\n // 텍스트 조각은 인라인 흐름 — 줄이 열려 있으면(직전이 글자취급 표·텍스트)\n // 공백으로 잇고, 아니면 `\\n`(문단 첫 항목). 원문 \" 부터 \"가 cleanParaText로\n // 트림돼 공백 정보가 사라지므로 공백 연결로 원문 한 줄을 재현한다 (#52 후속).\n cell.text += (cell.text ? (cell.lineOpen ? \" \" : \"\\n\") : \"\") + s\n cell.lineOpen = true\n ;(cell.blocks ??= []).push(block)\n } else blocks.push(block)\n }\n tableCtx = walkParagraphChildren(el, blocks, tableCtx, tableStack, ctx, depth + 1, flush)\n while (segIdx < segs.length) flush()\n // 셀 각주(주석) — 세그먼트 평탄화 뒤 종전과 동일하게 보존 (희소 경로). 셀 blocks 도\n // 마지막 조각에 footnoteText 로 달아 HTML 셀 렌더가 주석을 잃지 않게 한다\n if (footnote && cell) {\n cell.text += (cell.text ? \"\\n\" : \"\") + `(주: ${footnote})`\n if (lastCellBlock) lastCellBlock.footnoteText = footnote\n }\n break\n }\n if (text) {\n if (tableCtx?.cell) {\n const cell = tableCtx.cell\n // 선두 빈 문단 뒤(keepEmptyParagraphs)엔 cell.text가 \"\"라도 문단 경계 `\\n` 필요 (#57).\n // 셀 각주는 평탄화 텍스트(GFM 셀)엔 인라인 \"(주: …)\", 셀 문단 블록엔 본문 문단과 같은\n // footnoteText 슬롯으로 — 블록 텍스트가 셀 글 그대로라 표 내용 대조·span 복원이 맞는다\n cell.text += ((cell.text || cell.paraSeen) ? \"\\n\" : \"\") + (footnote ? `${text} (주: ${footnote})` : text)\n cell.paraSeen = true\n const cellBlock: IRBlock = { type: \"paragraph\", text, pageNumber: ctx.page }\n if (footnote) cellBlock.footnoteText = footnote\n // 왕복 채널 — 셀 문단도 인라인 강조 span 복원 (v4.0.4: 최상위 한정 확장,\n // v4.0.5: gongmun·외래 확장). GFM 셀 방출이 마커를 재방출하고 generateRuns가\n // 되읽는다. 자사 default 외에는 혼합 가드 — 전체 볼드 셀은 헤더행·라벨열의\n // 구조 서식이 지배적이라 마커를 억제한다\n const cellSpanMode = spanModeOf(ctx.shared.kordocLayout)\n if (cellSpanMode && !ph?.prefix) {\n const spans = extractRunSpans(el, ctx, cellSpanMode, cellSpanMode !== \"kordoc\")\n if (spans && spans.map(s => s.text).join(\"\").replace(/[ \\t]+/g, \" \").trim() === text) {\n cellBlock.spans = spans\n }\n }\n if (!cellBlock.spans && placeholderSpans) cellBlock.spans = withPrefixSpan(placeholderSpans, ph?.prefix)\n ;(cell.blocks ??= []).push(cellBlock)\n } else if (!tableCtx) {\n // 구분선 문단('─' 연속 — kordoc 생성기의 hr 렌더) → separator 복원.\n // 재파싱 시 장식 대시가 본문 텍스트로 남던 왕복 비대칭 수정 (v4.0.5 P2).\n // kordocLayout 채널 있는 자사 생성 문서 한정 — 외래 문서의 실제 '─' 장식\n // 문단이 separator로 둔갑하는 것 방지\n if (ctx.shared.kordocLayout && /^─{10,}$/.test(text)) {\n blocks.push({ type: \"separator\", pageNumber: ctx.page })\n // p 내부 구조 자식 처리 경로 유지를 위해 아래 공통 처리로 진행\n tableCtx = walkParagraphChildren(el, blocks, tableCtx, tableStack, ctx, depth + 1)\n break\n }\n const block: IRBlock = { type: headingLevel ? \"heading\" : \"paragraph\", text, pageNumber: ctx.page }\n if (headingLevel) block.level = headingLevel\n if (style) block.style = style\n if (href) block.href = href\n if (footnote) block.footnoteText = footnote\n // 들여쓰기 관찰 슬롯 (v4.0.4) — paraPr hc:left + 양수 hc:intent(첫줄).\n // 마크다운 방출엔 불참 — gongmun 리스트 depth 재유도 등 소비자 몫\n const ind = ctx.styleMap?.paraIndents.get(el.getAttribute(\"paraPrIDRef\") ?? \"\")\n if (ind) {\n const eff = ind.left + Math.max(0, ind.intent)\n if (eff > 0) block.indent = eff\n }\n // indent 소비 (v4.0.5) — 자사 gongmun 파일의 md 리스트 충돌 부호('- '·'1) ')는\n // 재생성 시 md 파서가 list_item으로 선점해 리터럴 부호 재분류(gen-gongmun-fit)가\n // 못 받고 depth0으로 붕괴한다. paraPr 들여쓰기를 run 글자크기(=levelIndent\n // 단위)로 역산해 blocksToMarkdown이 2칸/단계 선행 공백을 방출하게 한다\n if (ctx.shared.kordocLayout === \"gongmun\" && block.indent && /^(?:-|\\d{1,3}\\)) /.test(text)) {\n const depth = gongmunDepthFromIndent(el, block.indent, ctx)\n if (depth) block.listDepth = depth\n }\n // 왕복 채널(자사 생성 파일 + 외래 실속성) — 인라인 강조 span·인용 복원\n const spanMode = spanModeOf(ctx.shared.kordocLayout)\n if (!headingLevel && spanMode) {\n if (!ph?.prefix) {\n const spans = extractRunSpans(el, ctx, spanMode, spanMode === \"gongmun\")\n // 무결성 가드: span 연결이 블록 텍스트와 일치할 때만 (cleanText 변형과\n // 어긋난 문단은 평문 유지 — 마커가 본문을 오염시키지 않게)\n if (spans && spans.map(s => s.text).join(\"\").replace(/[ \\t]+/g, \" \").trim() === text) {\n block.spans = spans\n }\n }\n // 인용 paraPr 규약은 자사 파일 한정(외래는 무규약) — gongmun도 기본\n // 0~7 paraPr 블록을 공유하므로 6번=인용 유효 (실측 프리셋 인용은 ※ 문단으로\n // 방출돼 여기 안 옴 — 글리프 재분류가 왕복 담당)\n if (spanMode !== \"foreign\" && el.getAttribute(\"paraPrIDRef\") === KORDOC_PARA_QUOTE) block.quote = true\n }\n if (!headingLevel && !block.spans && placeholderSpans) block.spans = withPrefixSpan(placeholderSpans, ph?.prefix)\n blocks.push(block)\n } else {\n // 표 내부지만 셀 밖(비정상 경로) — 무음 드롭 대신 본문 문단으로 보존\n blocks.push({ type: \"paragraph\", text, pageNumber: ctx.page })\n }\n } else if (ctx.shared.keepEmptyParagraphs && !hasObjectDescendant(el)) {\n // 빈 문단 보존 (#57, opt-in) — 본문은 text:\"\" 문단 블록, 셀은 빈 줄로 순서대로.\n // 개체(표·그림·글상자) 문단은 개체 출력이 따로 방출되므로 제외 (이중 줄 방지).\n // 기본(off)은 종전 동작 그대로 — 조판용 여백 문단이 지워진다.\n if (tableCtx?.cell) {\n const cell = tableCtx.cell\n if (cell.text || cell.paraSeen) cell.text += \"\\n\"\n cell.paraSeen = true\n cell.lineOpen = false // 문단 경계 — 인라인 흐름 닫힘\n ;(cell.blocks ??= []).push({ type: \"paragraph\", text: \"\", pageNumber: ctx.page })\n } else if (!tableCtx) {\n blocks.push({ type: \"paragraph\", text: \"\", pageNumber: ctx.page })\n }\n }\n // <p> 내부의 <tbl>만 별도 처리 — extractParagraphInfo가 이미 텍스트를 추출했으므로\n // 전체 walkSection 재귀 대신 테이블/이미지 자식만 선택적으로 처리\n tableCtx = walkParagraphChildren(el, blocks, tableCtx, tableStack, ctx, depth + 1)\n break\n }\n\n // 이미지/그림/글상자 — 이미지·텍스트·캡션 병행 추출\n case \"pic\": case \"shape\": case \"drawingObject\": {\n if (tableCtx?.cell) {\n const sink: IRBlock[] = []\n handleShape(el, sink, ctx)\n mergeBlocksIntoCell(tableCtx.cell, sink)\n } else {\n handleShape(el, blocks, ctx)\n }\n break\n }\n\n // 메모 — 본문 혼입 차단 (v3.0)\n case \"memogroup\": case \"memo\": {\n if (ctx.warnings && extractTextFromNode(el)) {\n ctx.warnings.push({ page: ctx.page, message: \"메모 텍스트 본문 제외: memogroup\", code: \"HIDDEN_TEXT_FILTERED\" })\n }\n break\n }\n\n default:\n walkSection(el, blocks, tableCtx, tableStack, ctx, depth + 1)\n break\n }\n }\n}\n\n/**\n * 도형/그림 공통 처리 — 글상자 텍스트와 이미지를 병행 추출하고(기존 상호배타 수정),\n * 도형 캡션은 문단으로 보존한다. 둘 다 없으면 SKIPPED_IMAGE 경고.\n */\nfunction handleShape(el: Element, sink: IRBlock[], ctx: WalkCtx): void {\n const imgRef = extractImageRef(el)\n const drawTextChild = findDescendant(el, \"drawText\")\n\n if (imgRef) {\n const block: IRBlock = { type: \"image\", text: imgRef, pageNumber: ctx.page }\n // 사용자 입력 그림 설명(alt) — builder가 image alt 출력을 지원할 때까지 IR에 보존,\n // 이미지 추출 실패 시 대체 문단의 각주로 표시된다\n const alt = userShapeComment(el)\n if (alt) block.footnoteText = alt\n sink.push(block)\n }\n if (drawTextChild) {\n extractDrawTextBlocks(drawTextChild, sink, ctx)\n }\n // 도형 캡션 (그림 캡션 등) — 이미지 아래 문단으로 보존\n const capEl = findChildByLocalName(el, \"caption\")\n if (capEl) {\n const capText = collectSubListText(capEl, ctx)\n if (capText) sink.push({ type: \"paragraph\", text: capText, pageNumber: ctx.page })\n }\n\n if (!imgRef && !drawTextChild && ctx.warnings && ctx.sectionNum) {\n const localTag = (el.tagName || el.localName || \"\").replace(/^[^:]+:/, \"\")\n ctx.warnings.push({ page: ctx.page, message: `스킵된 요소: ${localTag}`, code: \"SKIPPED_IMAGE\" })\n }\n}\n\n/** 도형의 사용자 입력 그림 설명 — 한컴 자동생성 대체텍스트(\"그림입니다.\" 등)는 제외 */\nfunction userShapeComment(el: Element): string | undefined {\n const commentEl = findChildByLocalName(el, \"shapeComment\")\n if (!commentEl) return undefined\n const text = extractTextFromNode(commentEl)\n if (!text) return undefined\n if (/^그림입니다/.test(text)) return undefined\n if (/^(?:모서리가 둥근 |둥근 )?[^\\n]{1,20}입니다\\.?$/.test(text)) return undefined\n return text\n}\n\n/** 도형/중첩 콘텐츠 블록을 셀에 병합 — 텍스트는 cell.text에, 구조는 cell.blocks에 보존 */\nfunction mergeBlocksIntoCell(cell: CellCtxEx, sink: IRBlock[]): void {\n for (const b of sink) {\n if ((b.type === \"paragraph\" || b.type === \"heading\") && b.text) {\n // 글상자 문단 각주도 셀 문단과 같은 모양 — 평탄화 text 엔 인라인 \"(주: …)\", 블록엔 footnoteText\n cell.text += (cell.text ? \"\\n\" : \"\") + b.text + (b.footnoteText ? ` (주: ${b.footnoteText})` : \"\")\n ;(cell.blocks ??= []).push(b)\n } else if (b.type === \"image\" || b.type === \"table\") {\n if (b.type === \"image\" && b.text) {\n // GFM 표 경로는 cell.text만 출력하므로 인라인 이미지 참조를 남긴다\n // (extractImagesFromZip이 추출 후 실제 파일명으로 치환)\n cell.text += (cell.text ? \"\\n\" : \"\") + ``\n }\n ;(cell.blocks ??= []).push(b)\n cell.hasStructure = true\n }\n }\n}\n\n/** kordoc 왕복 채널 판독 결과 — heading 복원 또는 파생물 스킵 */\ninterface KordocTableChannel {\n kind: \"heading\" | \"skip\"\n level?: number\n text?: string\n}\n\n/**\n * kordoc 생성기의 장식표 왕복 마커 판독 (v4.0.5 P2).\n * 제목 셀 `name=\"__kordoc_h1~6\"` → heading 복원, `__kordoc_toc`/`__kordoc_skip` →\n * 파생물(목차·표지 제목 반복)이므로 통째 스킵. 마커 없으면 null(일반 표).\n */\nfunction kordocTableChannel(tblEl: Element, ctx: WalkCtx): KordocTableChannel | null {\n const found = findKordocMarkedCell(tblEl, 0)\n if (!found) return null\n const m = found.name.match(/^__kordoc_(?:h([1-6])|(toc|skip))$/)\n if (!m) return null\n if (m[2]) return { kind: \"skip\" }\n const text = collectSubListText(found.cell, ctx).trim()\n return { kind: \"heading\", level: Number(m[1]), text }\n}\n\n/** tbl 하위에서 __kordoc_ 마커 셀 탐색 (중첩표 안까지는 내려가지 않음) */\nfunction findKordocMarkedCell(el: Node, depth: number): { cell: Element; name: string } | null {\n if (depth > 6) return null\n const children = el.childNodes\n if (!children) return null\n for (let i = 0; i < children.length; i++) {\n const ch = children[i] as Element\n if (ch.nodeType !== 1) continue\n const tag = (ch.tagName || ch.localName || \"\").replace(/^[^:]+:/, \"\")\n if (tag === \"tc\") {\n const name = ch.getAttribute(\"name\") || \"\"\n if (name.startsWith(\"__kordoc_\")) return { cell: ch, name }\n continue // 셀 내부(중첩표)는 탐색하지 않음 — 최상위 표의 셀만\n }\n if (tag === \"tbl\" && depth > 0) continue // 중첩표 진입 금지\n const found = findKordocMarkedCell(ch, depth + 1)\n if (found) return found\n }\n return null\n}\n\n/** 머리말/꼬리말 subList에 페이지 번호 autoNum(numType=PAGE)이 있는지 검사 */\nfunction hasPageAutoNum(el: Node, depth = 0): boolean {\n if (depth > 10) return false\n const children = el.childNodes\n if (!children) return false\n for (let i = 0; i < children.length; i++) {\n const ch = children[i] as Element\n if (ch.nodeType !== 1) continue\n const tag = (ch.tagName || ch.localName || \"\").replace(/^[^:]+:/, \"\")\n if (tag === \"autoNum\" && ch.getAttribute?.(\"numType\") === \"PAGE\") return true\n if (hasPageAutoNum(ch, depth + 1)) return true\n }\n return false\n}\n\n/** subList 내부 수집 결과 — 평탄화 텍스트와 구조 블록을 병행 제공 (#55) */\ninterface SubListContent {\n text: string\n /** 원문 순서의 문단/표 블록 — hasStructure일 때만 소비된다 */\n blocks: IRBlock[]\n /** 표가 하나라도 있었는지 (평문 캡션에 blocks를 달지 않기 위한 게이트) */\n hasStructure: boolean\n}\n\n/** caption/header/footer 등의 subList 내부 문단 텍스트 수집 */\nfunction collectSubListText(el: Node, ctx: WalkCtx, depth = 0): string {\n return collectSubListContent(el, ctx, depth).text\n}\n\n/**\n * subList 내부를 텍스트와 블록으로 동시 수집 — 캡션 안 중첩표를 구조로도 보존하기\n * 위해 collectSubListText를 확장 (#55). 텍스트 조립 규칙은 종전과 동일.\n */\nfunction collectSubListContent(el: Node, ctx: WalkCtx, depth = 0, sep = \"\\n\"): SubListContent {\n const out: SubListContent = { text: \"\", blocks: [], hasStructure: false }\n if (depth > 10) return out\n const parts: string[] = []\n const children = el.childNodes\n if (!children) return out\n for (let i = 0; i < children.length; i++) {\n const ch = children[i] as Element\n if (ch.nodeType !== 1) continue\n const tag = (ch.tagName || ch.localName || \"\").replace(/^[^:]+:/, \"\")\n if (tag === \"p\" || tag === \"para\") {\n let t = extractParagraphInfo(ch, ctx.styleMap, ctx).text\n // 캡션·머리말·주석 문단도 글머리표·번호를 한컴이 그린다 (추진일정 캡션 \"※ 상기 추진일정…\",\n // 한컴 PDF 실렌더). 본문·글상자 경로와 같이 텍스트 유무와 무관하게 불러 번호 카운터를 소비\n const ph = resolveParaHeading(ch, ctx)\n if (t && ph?.prefix) t = ph.prefix + \" \" + t\n if (t) {\n parts.push(t)\n out.blocks.push({ type: \"paragraph\", text: t, pageNumber: ctx.page })\n }\n // 문단 run 안의 중첩표 (hp:p > hp:run > hp:tbl — HWPX 표준 배치)\n const tbls: Element[] = []\n findTopLevelTbls(ch, tbls)\n for (const tbl of tbls) {\n const built = buildSubListTable(tbl, ctx, depth)\n if (built.text) parts.push(built.text)\n if (built.block) {\n out.blocks.push(built.block)\n out.hasStructure = true\n }\n }\n // 문단 안 글상자 글 (hp:rect > hp:drawText) — extractParagraphInfo 는 글상자를 건너뛰므로\n // 따로 모은다 (미주 풀이 박스·머리말 도형 글이 통째로 빠지던 것, 3-09월_교육_통합 미주)\n for (const t of drawTextParaTexts(ch, ctx)) {\n parts.push(t)\n out.blocks.push({ type: \"paragraph\", text: t, pageNumber: ctx.page })\n }\n } else if (tag === \"tbl\") {\n const built = buildSubListTable(ch, ctx, depth)\n if (built.text) parts.push(built.text)\n if (built.block) {\n out.blocks.push(built.block)\n out.hasStructure = true\n }\n } else {\n const sub = collectSubListContent(ch, ctx, depth + 1, sep)\n if (sub.text) parts.push(sub.text)\n out.blocks.push(...sub.blocks)\n if (sub.hasStructure) out.hasStructure = true\n }\n }\n out.text = parts.join(sep).trim()\n return out\n}\n\n/**\n * 문단 안 글상자(drawText) 문단 글 — 자동번호 접두 포함, 표 내부·중첩 글상자 미진입.\n * 글상자 안 표는 findTopLevelTbls 가 따로 모은다 (중복 방출·번호 이중 전진 방지)\n */\nfunction drawTextParaTexts(para: Element, ctx: WalkCtx): string[] {\n const out: string[] = []\n const visit = (node: Node, depth: number, inDrawText: boolean) => {\n if (depth > MAX_XML_DEPTH) return\n const kids = node.childNodes\n if (!kids) return\n for (let i = 0; i < kids.length; i++) {\n const ch = kids[i] as Element\n if (ch.nodeType !== 1) continue\n const tag = (ch.tagName || ch.localName || \"\").replace(/^[^:]+:/, \"\")\n if (tag === \"tbl\" || tag === \"footNote\" || tag === \"endNote\") continue\n if (tag === \"drawText\") { if (!inDrawText) visit(ch, depth + 1, true); continue }\n if (inDrawText && (tag === \"p\" || tag === \"para\")) {\n let t = extractParagraphInfo(ch, ctx.styleMap, ctx).text.trim()\n const ph = resolveParaHeading(ch, ctx)\n if (t && ph?.prefix) t = ph.prefix + \" \" + t\n if (t) out.push(t)\n continue\n }\n visit(ch, depth + 1, inDrawText)\n }\n }\n visit(para, 0, false)\n return out\n}\n\n/**\n * 캡션/머리말 내 중첩표 구성 — 셀 텍스트를 표 평탄화 규칙(\" / \" 구분·행별 줄바꿈)으로\n * 순서 보존 이어붙이고(#46), 같은 표를 IRBlock으로도 만들어 구조를 남긴다 (#55).\n * 스킵하면 캡션 표 내용이 통째로 무음 유실됨.\n */\nfunction buildSubListTable(el: Element, ctx: WalkCtx, depth: number): { text: string; block: IRBlock | null } {\n const sink: IRBlock[] = []\n const st: TableState = { rows: [], currentRow: [], cell: null, sourceId: el.getAttribute(\"id\") ?? undefined }\n walkSection(el, sink, st, [], ctx, depth + 1)\n let flat = convertTableToText(st.rows)\n if (st.caption) flat = st.caption + (flat ? \"\\n\" + flat : \"\")\n // completeTable은 부모 표가 없으면 IRTable 블록을 sink에 넣는다 (셀 blocks·제목셀 재부착 포함)\n const built: IRBlock[] = []\n completeTable(st, [], built, ctx)\n return { text: flat, block: built.find(b => b.type === \"table\") ?? null }\n}\n\n/** 노드 하위의 최상위 tbl 수집 — tbl 내부 미진입 (셀 안 중첩표는 표 워커가 처리) */\nfunction findTopLevelTbls(el: Node, out: Element[], depth = 0): void {\n if (depth > MAX_XML_DEPTH) return\n const kids = el.childNodes\n if (!kids) return\n for (let i = 0; i < kids.length; i++) {\n const ch = kids[i] as Element\n if (ch.nodeType !== 1) continue\n const tag = (ch.tagName || ch.localName || \"\").replace(/^[^:]+:/, \"\")\n if (tag === \"tbl\") { out.push(ch); continue }\n findTopLevelTbls(ch, out, depth + 1)\n }\n}\n\n/**\n * <p> 내부에서 텍스트가 아닌 구조적 자식만 처리 (tbl, pic, shape). tableCtx 반환으로 상태 전파.\n * onTbl: 각 표 처리 직전 호출 — 호출자가 표 앞 텍스트 조각을 먼저 방출해\n * 문서 순서를 보존한다 (#49/#50, extractParagraphInfo의 \\x1E 마커와 1:1 대응)\n */\nfunction walkParagraphChildren(\n node: Node, blocks: IRBlock[],\n tableCtx: TableState | null, tableStack: TableState[],\n ctx: WalkCtx, depth: number = 0, onTbl?: () => void\n): TableState | null {\n if (depth > MAX_XML_DEPTH) return tableCtx\n const children = node.childNodes\n if (!children) return tableCtx\n const walkChildren = (parent: Node, d: number, inShape = false) => {\n if (d > MAX_XML_DEPTH) return\n const kids = parent.childNodes\n if (!kids) return\n for (let i = 0; i < kids.length; i++) {\n const el = kids[i] as Element\n if (el.nodeType !== 1) continue\n const tag = el.tagName || el.localName || \"\"\n const localTag = tag.replace(/^[^:]+:/, \"\")\n\n if (localTag === \"tbl\") {\n // 표 앞 텍스트 조각 선방출 — 문서 순서 보존 (#49/#50/#53). inline·float 표\n // 모두 직전에 방출한다: float 표는 흐름 불참이지만 자기보다 앞선 텍스트를\n // 추월하면 안 된다 (#53 — 같은 문단에 inline 표가 있을 때, 텍스트 조각이 다음\n // inline 표 직전까지 미뤄져 그 사이 float 표가 텍스트를 건너뛰던 역전 수정).\n // flush는 세그먼트 소진(빈/undefined)에 안전한 no-op이라 float가 여럿이어도 무해.\n if (onTbl) onTbl()\n // kordoc 왕복 채널 (v4.0.5 P2) — walkSection tbl 케이스와 동일 판독.\n // 최상위(셀 밖) 표에서만: heading 복원 또는 파생물(목차·제목반복) 스킵\n if (!tableCtx) {\n const chan = kordocTableChannel(el, ctx)\n if (chan) {\n if (chan.kind === \"heading\" && chan.text) {\n blocks.push({ type: \"heading\", level: chan.level, text: chan.text, pageNumber: ctx.page })\n }\n continue\n }\n }\n // 테이블은 walkSection으로 위임. inline 플래그로 완료 시 부모 셀 텍스트를\n // 같은 줄(공백)로 이을지 결정한다 (#52 후속 — 글자취급 표는 앞뒤 텍스트와 한 줄)\n if (tableCtx) tableStack.push(tableCtx)\n const newTable: TableState = { rows: [], currentRow: [], cell: null, inline: isInlineTbl(el), sourceId: el.getAttribute(\"id\") ?? undefined }\n walkSection(el, blocks, newTable, tableStack, ctx, d + 1)\n tableCtx = completeTable(newTable, tableStack, blocks, ctx)\n } else if (localTag === \"caption\" && !inShape) {\n // ctrl 래핑 표 캡션 — 도형(rect 등) 자체 캡션은 기존 텍스트 추출 경로에 맡긴다.\n // 셀 안이면 표 caption이 아니라 개체 캡션이므로 셀 텍스트로 귀속 (오귀속 방지)\n const cap = collectSubListContent(el, ctx)\n if (cap.text) {\n if (tableCtx?.cell) mergeBlocksIntoCell(tableCtx.cell, [{ type: \"paragraph\", text: cap.text, pageNumber: ctx.page }])\n else if (tableCtx) {\n tableCtx.caption = (tableCtx.caption ? tableCtx.caption + \"\\n\" : \"\") + cap.text\n if (cap.hasStructure) (tableCtx.captionBlocks ??= []).push(...cap.blocks)\n }\n else blocks.push({ type: \"paragraph\", text: cap.text, pageNumber: ctx.page })\n }\n } else if (localTag === \"pic\" || localTag === \"shape\" || localTag === \"drawingObject\") {\n // 글상자 텍스트 + 이미지 병행 추출 — 셀 안이면 위치 보존을 위해 IRCell.blocks로\n if (tableCtx?.cell) {\n const sink: IRBlock[] = []\n handleShape(el, sink, ctx)\n mergeBlocksIntoCell(tableCtx.cell, sink)\n } else {\n handleShape(el, blocks, ctx)\n }\n } else if (localTag === \"drawText\") {\n // 글상자(TextBox) 안 텍스트 추출 — <hp:p> 순회\n if (tableCtx?.cell) {\n const sink: IRBlock[] = []\n extractDrawTextBlocks(el, sink, ctx)\n mergeBlocksIntoCell(tableCtx.cell, sink)\n } else {\n extractDrawTextBlocks(el, blocks, ctx)\n }\n } else if (localTag === \"r\" || localTag === \"run\" || localTag === \"ctrl\") {\n // <hp:run>, <hp:ctrl> 내부에 테이블/캡션이 포함될 수 있음 — 재귀\n walkChildren(el, d + 1, inShape)\n } else if (localTag === \"rect\" || localTag === \"ellipse\" || localTag === \"polygon\"\n || localTag === \"line\" || localTag === \"arc\" || localTag === \"curve\"\n || localTag === \"connectLine\" || localTag === \"container\") {\n // 도형 요소 내부에 테이블/이미지/글상자가 포함될 수 있음 — 재귀 (도형 자체 캡션은 제외)\n walkChildren(el, d + 1, true)\n }\n }\n }\n walkChildren(node, depth)\n return tableCtx\n}\n\n/** 개체 요소 태그 — 빈 문단 보존(#57) 제외 판정용. walkParagraphChildren이 별도 방출하는 것들 */\nconst OBJECT_TAGS = new Set([\"tbl\", \"pic\", \"shape\", \"drawingObject\", \"drawText\"])\n\n/** 문단 하위에 표·그림·글상자 등 개체가 있는지 — 있으면 \"빈 문단\"이 아니라 개체 문단 (#57) */\nfunction hasObjectDescendant(node: Node, depth = 0): boolean {\n if (depth > MAX_XML_DEPTH) return false\n const kids = node.childNodes\n if (!kids) return false\n for (let i = 0; i < kids.length; i++) {\n const ch = kids[i] as Element\n if (ch.nodeType !== 1) continue\n const tag = (ch.tagName || ch.localName || \"\").replace(/^[^:]+:/, \"\")\n if (OBJECT_TAGS.has(tag)) return true\n if (hasObjectDescendant(ch, depth + 1)) return true\n }\n return false\n}\n\n/**\n * 글자취급(treatAsChar) 인라인 표 여부 — <hp:pos treatAsChar=\"1\"> (#49/#50).\n * inline 표만 같은 줄 텍스트와 문서 순서로 읽는다 (reflow 개체 흐름 모델과 동일 구분)\n */\nfunction isInlineTbl(tbl: Element): boolean {\n return findChildByLocalName(tbl, \"pos\")?.getAttribute(\"treatAsChar\") === \"1\"\n}\n\n/** 자손에서 특정 태그명의 첫 번째 요소 탐색 (최대 깊이 5) */\nfunction findDescendant(node: Node, targetTag: string, depth = 0): Element | null {\n if (depth > 5) return null\n const children = node.childNodes\n if (!children) return null\n for (let i = 0; i < children.length; i++) {\n const child = children[i] as Element\n if (child.nodeType !== 1) continue\n const tag = (child.tagName || child.localName || \"\").replace(/^[^:]+:/, \"\")\n if (tag === targetTag) return child\n const found = findDescendant(child, targetTag, depth + 1)\n if (found) return found\n }\n return null\n}\n\n/** drawText(글상자) 내부의 <p> 요소들에서 텍스트를 추출하여 paragraph 블록 생성 */\nfunction extractDrawTextBlocks(drawTextNode: Node, blocks: IRBlock[], ctx: WalkCtx): void {\n const children = drawTextNode.childNodes\n if (!children) return\n for (let i = 0; i < children.length; i++) {\n const child = children[i] as Element\n if (child.nodeType !== 1) continue\n const tag = (child.tagName || child.localName || \"\").replace(/^[^:]+:/, \"\")\n if (tag === \"subList\" || tag === \"p\" || tag === \"para\") {\n // subList 안의 <p>들을 순회\n if (tag === \"subList\") {\n extractDrawTextBlocks(child, blocks, ctx)\n } else {\n const info = extractParagraphInfo(child, ctx.styleMap, ctx)\n let text = info.text.trim()\n // 텍스트 유무와 무관하게 호출 — 본문 경로와 동일. 빈 번호 문단도 카운터를\n // 소비하므로 텍스트 있을 때만 호출하면 이후 항목 번호가 낮게 재현된다\n const ph = resolveParaHeading(child, ctx)\n if (text) {\n if (ph?.prefix) text = ph.prefix + \" \" + text\n const block: IRBlock = { type: \"paragraph\", text, style: info.style ?? undefined, pageNumber: ctx.page }\n if (info.href) block.href = info.href\n if (info.footnote) block.footnoteText = info.footnote\n blocks.push(block)\n }\n // 글상자 안 문단에 포함된 표/도형도 재귀 처리 — 조직도용 \"글상자 안 표\" 보존\n // (실증: 국방부 TF 5×7 조직표가 rect>drawText>p>tbl 구조로 통째 소실되던 케이스)\n walkParagraphChildren(child, blocks, null, [], ctx)\n }\n }\n }\n}\n\ninterface ParagraphInfo {\n text: string\n href?: string\n footnote?: string\n style?: InlineStyle\n /**\n * 인라인 표 경계로 분할된 텍스트 조각 (#49/#50) — 문단 안에 표가 있을 때만 존재.\n * segments[i]는 i번째 표 앞의 텍스트, 마지막 조각은 마지막 표 뒤의 텍스트.\n * text는 기존과 동일한 전체 평탄화본 (하위 호환).\n */\n segments?: string[]\n /** 미기입 누름틀 안내문이 든 문단 — 안내문 조각만 placeholder 표시한 span (마크다운에서 뺀다, IR 글엔 남긴다) */\n placeholderSpans?: IRSpan[]\n}\n\n/** 누름틀 안내문 구간 표지 — 문단 글 정리(공백 붕괴·링크 삽입·절단)를 거친 뒤 span 으로 가른다 */\nconst PH_OPEN = \"\\x1C\"\nconst PH_CLOSE = \"\\x1D\"\n\n/**\n * 미기입 누름틀의 안내문 — CLICK_HERE 이고 수정 안 됨(dirty≠1)일 때만. 이런 필드의 값 자리 글이 안내문과\n * 같으면 한컴은 화면에만 흐리게 보이고 인쇄하지 않는다(한컴 PDF 실측, HWP5 body.ts 수정 비트 규칙과 같은 판정).\n * 안내문은 stringParam Direction, 없으면 Command 의 \"Direction:wstring:<N>:\" 뒤 N자.\n */\nfunction clickHereGuide(fieldBegin: Element): string | undefined {\n if ((fieldBegin.getAttribute(\"type\") || \"\").toUpperCase() !== \"CLICK_HERE\") return undefined\n if (fieldBegin.getAttribute(\"dirty\") === \"1\") return undefined\n const children = findChildByLocalName(fieldBegin, \"parameters\")?.childNodes\n if (!children) return undefined\n let fromCommand: string | undefined\n for (let i = 0; i < children.length; i++) {\n const ch = children[i] as Element\n if (ch.nodeType !== 1) continue\n const tag = (ch.tagName || ch.localName || \"\").replace(/^[^:]+:/, \"\")\n if (tag !== \"stringParam\") continue\n const name = ch.getAttribute(\"name\")\n if (name === \"Direction\") return ch.textContent || undefined\n if (name === \"Command\") {\n const cmd = ch.textContent || \"\"\n const m = /Direction:wstring:(\\d+):/.exec(cmd)\n if (m) fromCommand = cmd.slice(m.index + m[0].length, m.index + m[0].length + Number(m[1])) || undefined\n }\n }\n return fromCommand\n}\n\n/** fieldBegin이 HYPERLINK면 stringParam name=\"Path\"에서 URL 추출 (살균 포함) */\nfunction extractHyperlinkHref(fieldBegin: Element): string | undefined {\n if ((fieldBegin.getAttribute(\"type\") || \"\").toUpperCase() !== \"HYPERLINK\") return undefined\n const params = findChildByLocalName(fieldBegin, \"parameters\")\n if (!params) return undefined\n const children = params.childNodes\n if (!children) return undefined\n for (let i = 0; i < children.length; i++) {\n const ch = children[i] as Element\n if (ch.nodeType !== 1) continue\n const tag = (ch.tagName || ch.localName || \"\").replace(/^[^:]+:/, \"\")\n if (tag !== \"stringParam\" || ch.getAttribute(\"name\") !== \"Path\") continue\n let url = (ch.textContent || \"\").trim()\n if (!url) continue\n // 한컴이 중복 스킴을 저장하는 경우 정리 (\"http://https://...\" → \"https://...\")\n url = url.replace(/^https?:\\/\\/(?=https?:\\/\\/)/i, \"\")\n const safe = sanitizeHref(url)\n if (safe) return safe\n }\n return undefined\n}\n\n/** 변경추적 삭제 구간 내부 여부 */\nfunction isInDeletedRange(ctx?: WalkCtx): boolean {\n return (ctx?.shared.track.deleteDepth ?? 0) > 0\n}\n\nfunction extractParagraphInfo(para: Element, styleMap?: HwpxStyleMap, ctx?: WalkCtx): ParagraphInfo {\n let text = \"\"\n let href: string | undefined\n let footnote: string | undefined\n let charPrId: string | undefined\n\n // 하이퍼링크 필드 범위 — fieldBegin/fieldEnd의 텍스트 오프셋을 추적해 필드 extent만\n // 인라인 [anchor](url)로 방출 (HWP5 fieldRanges와 동일 모델). extent를 못 닫으면\n // (문단 경계 걸침 등) 기존 문단 전체 href로 폴백.\n const linkRanges: Array<{ url: string; start: number; end?: number }> = []\n const openFields: Array<{ rangeIdx?: number; guide?: string; start?: number }> = []\n const onFieldBegin = (el: Element) => {\n const url = extractHyperlinkHref(el)\n if (url) {\n linkRanges.push({ url, start: text.length })\n openFields.push({ rangeIdx: linkRanges.length - 1 })\n if (!href) href = url\n } else {\n const guide = clickHereGuide(el)\n openFields.push(guide ? { guide, start: text.length } : {})\n }\n }\n const onFieldEnd = () => {\n const open = openFields.pop()\n if (open?.rangeIdx !== undefined) linkRanges[open.rangeIdx].end = text.length\n // 미기입 누름틀: 값 자리 글이 안내문 그대로면 표지로 감싼다 (글은 IR 에 남고 마크다운에서만 빠진다)\n if (open?.guide !== undefined && open.start !== undefined) {\n const value = text.slice(open.start).replace(/\\\\\\$/g, \"$\")\n if (value && (value === open.guide || value.trimEnd() === open.guide)) {\n text = text.slice(0, open.start) + PH_OPEN + text.slice(open.start) + PH_CLOSE\n }\n }\n }\n\n // 문단의 스타일 참조 → charPr로 간접 조회\n // HWPX <p>에는 paraPrIDRef/styleIDRef가 있고, charPrIDRef는 <r> 요소에 있음\n // 여기서는 일단 null — <r> 요소에서 charPrIDRef를 가져옴\n\n // 각주/미주 — 개체 자리에 본문 참조 부호(한컴 실렌더 \"액체1)와\"), 주석 본문은 문단 모델로\n // (수식 LaTeX·필드 매개변수 제외·표 구분, HWP5 applyNoteEffect 와 같은 표기 — notes.ts)\n const addNote = (noteEl: Element, tag: string) => {\n if (isInDeletedRange(ctx)) return\n const endnote = tag === \"endNote\" || tag === \"en\"\n text += noteRefMark(noteAttrsOf(noteEl), endnote ? ctx?.noteFormats?.endnote : ctx?.noteFormats?.footnote)\n const noteText = ctx ? collectSubListContent(noteEl, ctx, 0, \" \").text : extractTextFromNode(noteEl)\n if (noteText) footnote = (footnote ? footnote + \"; \" : \"\") + noteText\n }\n\n /** <hp:ctrl> 자식 선별 순회 — 머리말/꼬리말/각주/미주/하이퍼링크/변경추적 (v3.0) */\n const handleCtrl = (ctrlEl: Element) => {\n const kids = ctrlEl.childNodes\n if (!kids) return\n for (let j = 0; j < kids.length; j++) {\n const k = kids[j] as Element\n if (k.nodeType !== 1) continue\n const ktag = (k.tagName || k.localName || \"\").replace(/^[^:]+:/, \"\")\n switch (ktag) {\n // 머리말/꼬리말 — 문서당 1회 수집, 본문 앞/뒤 배치\n // 페이지 번호 크롬(autoNum PAGE + 문자 없는 잔여 텍스트, 예: \"- 1 -\")은 본문 정보가\n // 아니므로 방출하지 않는다\n case \"header\": case \"footer\": {\n if (!ctx) break\n const t = collectSubListText(k, ctx)\n if (t && hasPageAutoNum(k) && !/\\p{L}/u.test(t)) break\n if (t) {\n const bucket = ktag === \"header\" ? ctx.shared.pageText.headers : ctx.shared.pageText.footers\n if (!bucket.includes(t)) bucket.push(t)\n }\n break\n }\n\n // 각주/미주 — 개체 자리에 참조 부호, 본문은 해당 문단의 footnote로 인라인 보존\n case \"footNote\": case \"endNote\": addNote(k, ktag); break\n\n // 하이퍼링크 — fieldBegin type=HYPERLINK의 Path 파라미터 (extent 오프셋 추적)\n case \"fieldBegin\": onFieldBegin(k); break\n case \"fieldEnd\": onFieldEnd(); break\n\n // 변경추적 — 삭제 구간(deleteBegin~End)의 텍스트는 출력 제외 (최종본 상태 재현)\n case \"deleteBegin\":\n if (ctx) ctx.shared.track.deleteDepth++\n break\n case \"deleteEnd\":\n if (ctx && ctx.shared.track.deleteDepth > 0) ctx.shared.track.deleteDepth--\n break\n case \"insertBegin\": case \"insertEnd\": break // 삽입분은 최종본에 포함\n\n // 숨은 설명 — 본문 혼입 차단\n case \"hiddenComment\": {\n if (ctx?.warnings && extractTextFromNode(k)) {\n ctx.warnings.push({ page: ctx.page, message: \"숨은 설명 텍스트 제외: hiddenComment\", code: \"HIDDEN_TEXT_FILTERED\" })\n }\n break\n }\n\n // 자동번호 — 주석 머리 번호(\"1)\"·\"문1)\")·캡션 번호(\"<그림 1>\")만 그린다. 쪽번호 등은 종전대로 미방출\n case \"autoNum\":\n if (!isInDeletedRange(ctx)) text += noteAutoNumOf(k)\n break\n\n // 콘텐츠 없는 제어 요소 — 스킵\n case \"bookmark\": case \"pageNum\": case \"pageNumCtrl\": case \"pageHiding\":\n case \"newNum\": case \"indexmark\": case \"colPr\":\n break\n\n // 캡션 — walkParagraphChildren의 caption 분기가 보존하므로 손실 경고 대상 아님\n case \"caption\":\n break\n\n // 미지원 요소 — 텍스트를 가졌으면 무음 손실 대신 경고\n default: {\n if (ctx?.warnings && extractTextFromNode(k)) {\n ctx.warnings.push({ page: ctx.page, message: `미지원 제어 요소의 텍스트 손실: ${ktag}`, code: \"UNSUPPORTED_ELEMENT\" })\n }\n }\n }\n }\n }\n\n const walk = (node: Node, depth: number = 0) => {\n if (depth > MAX_XML_DEPTH) return\n const children = node.childNodes\n if (!children) return\n for (let i = 0; i < children.length; i++) {\n const child = children[i] as Element\n // CDATA(4)도 텍스트 — 빠뜨리면 CDATA로 저장된 문단이 통째로 사라진다 (shared/xml.ts isTextNode 참조)\n if (child.nodeType === 3 || child.nodeType === 4) {\n const t = child.textContent || \"\"\n if (isInDeletedRange(ctx)) {\n if (t && ctx && !ctx.shared.track.warned) {\n ctx.shared.track.warned = true\n ctx.warnings?.push({ page: ctx.page, message: \"변경추적 삭제 텍스트 출력 제외\", code: \"HIDDEN_TEXT_FILTERED\" })\n }\n } else {\n // \\x1E는 인라인 표 경계 마커로 예약 — 원문 혼입 방지 (#49/#50).\n // 리터럴 $ 는 \\$ — $…$ 는 아래 수식 스팬 전용 (escapeLiteralDollar)\n text += escapeLiteralDollar(t.replace(/\\x1E/g, \"\"))\n }\n continue\n }\n if (child.nodeType !== 1) continue\n\n const tag = (child.tagName || child.localName || \"\").replace(/^[^:]+:/, \"\")\n switch (tag) {\n case \"t\": walk(child, depth + 1); break // 자식 순회 (tab 등 하위 요소 처리)\n case \"tab\": {\n const leader = child.getAttribute(\"leader\")\n if (leader && leader !== \"0\") {\n // 목차 리더 탭 (점선/실선 등) — 뒤에 페이지번호가 오므로 이후 텍스트 무시\n text += \"\\x1F\" // 특수 마커: 이후 텍스트 제거용\n } else {\n text += \"\\t\"\n }\n break\n }\n case \"br\":\n if ((child.getAttribute(\"type\") || \"line\") === \"line\") text += \"\\n\"\n break\n case \"lineBreak\": text += \"\\n\"; break // 강제 줄바꿈 — ref 추출기·소스맵 스캐너와 동일 모델\n // 고정폭·묶음 빈칸 — 묶음 빈칸(nbSpace)을 빠뜨리면 \"2026.<nbSpace/>9.\" 가 \"2026.9.\" 로 붙는다\n case \"fwSpace\": case \"hwSpace\": case \"nbSpace\": text += \" \"; break\n // 테이블 자체는 walkSection에서 처리 — 글자취급(inline) 표만 경계 마커를 남겨\n // 표 앞뒤 텍스트를 문서 순서대로 분할 방출할 수 있게 한다 (#49/#50).\n // float·페이지 앵커 표는 텍스트 흐름 불참(reflow 모델 정합) — 종전대로 텍스트 뒤 방출\n case \"tbl\":\n if (isInlineTbl(child)) text += \"\\x1E\"\n break\n\n // 하이퍼링크\n case \"hyperlink\": {\n const url = child.getAttribute(\"url\") || child.getAttribute(\"href\") || \"\"\n if (url) {\n // XSS 방지: 추출 시점에서 href 살균\n const safe = sanitizeHref(url)\n if (safe) href = safe\n }\n // 하이퍼링크 내 텍스트 추출\n walk(child, depth + 1)\n break\n }\n\n // 각주/미주\n case \"footNote\": case \"endNote\": case \"fn\": case \"en\": addNote(child, tag); break\n\n // 대체 표현 묶음 — 한컴은 지원하는 hp:case 하나만 그린다(차트, 없으면 hp:default 의 OLE).\n // 둘 다 순회하면 같은 캡션이 두 번 나온다 (1790387 [그림 5] 이중 방출)\n case \"switch\": {\n const branch = findChildByLocalName(child, \"case\") ?? findChildByLocalName(child, \"default\")\n if (branch) walk(branch, depth + 1)\n break\n }\n\n // 제어 요소 — 선별 순회 (머리말/꼬리말/각주/하이퍼링크/변경추적, v3.0)\n case \"ctrl\": handleCtrl(child); break\n\n // run 직계 fieldBegin (비표준 경로) — 하이퍼링크 URL·extent 추적\n case \"fieldBegin\": onFieldBegin(child); break\n\n // run 직계 변경추적 마커 (비표준 경로)\n case \"deleteBegin\": if (ctx) ctx.shared.track.deleteDepth++; break\n case \"deleteEnd\": if (ctx && ctx.shared.track.deleteDepth > 0) ctx.shared.track.deleteDepth--; break\n case \"insertBegin\": case \"insertEnd\": break\n\n case \"fieldEnd\": onFieldEnd(); break\n case \"parameters\": case \"stringParam\": case \"integerParam\":\n case \"boolParam\": case \"floatParam\":\n case \"secPr\": // 섹션 속성 (페이지 설정 등)\n case \"colPr\": // 다단 속성\n case \"linesegarray\": case \"lineseg\": // 레이아웃 정보\n // 도형/이미지 요소 — 대체텍스트(\"사각형입니다.\" 등) 누출 방지 (walkParagraphChildren에서 처리)\n case \"pic\": case \"shape\": case \"drawingObject\":\n case \"shapeComment\": case \"drawText\":\n break\n\n // 수식: <hp:equation> 내부의 <hp:script> 에 HULK-style equation\n // 스크립트가 담겨 있음. hml-equation-parser 로 LaTeX 변환 후 `$...$`\n // 로 래핑. 실패/빈 스크립트면 무시 (대체 텍스트 누출 방지).\n case \"equation\": {\n const script = findChildByLocalName(child, \"script\")\n const raw = script ? extractTextFromNode(script) : \"\"\n if (raw.trim()) {\n try {\n const latex = hmlToLatex(raw).trim()\n if (latex) text += \" $\" + latex.replace(/\\$/g, \"\\\\$\") + \"$ \"\n } catch {\n // 변환 실패 시 드롭 — 깨진 대체 텍스트 누출 방지. 드롭 사실은 경고로 남긴다\n if (ctx?.warnings) {\n ctx.warnings.push({\n page: ctx.page,\n message: `수식 LaTeX 변환 실패 — 수식 텍스트 제외: ${raw.trim().slice(0, 40)}`,\n code: \"PARTIAL_PARSE\",\n })\n }\n }\n }\n break\n }\n\n // run 요소에서 charPrIDRef 추출\n case \"r\": {\n const runCharPr = child.getAttribute(\"charPrIDRef\")\n if (runCharPr && !charPrId) charPrId = runCharPr\n walk(child, depth + 1)\n break\n }\n\n default: walk(child, depth + 1); break\n }\n }\n }\n walk(para)\n\n // 하이퍼링크 extent 인라인 적용 — 시작 내림차순 치환(HWP5와 동일), 겹침 금지.\n // anchor가 줄바꿈·리더마커·대괄호를 품으면 문법이 깨지므로 그 필드는 건너뛴다.\n {\n const applied: Array<[number, number]> = []\n const closed = linkRanges\n .filter(r => r.end !== undefined && r.end > r.start)\n .sort((a, b) => b.start - a.start)\n for (const r of closed) {\n if (applied.some(([s, e]) => r.start < e && r.end! > s)) continue\n const anchor = text.slice(r.start, r.end!)\n if (!anchor.trim() || /[\\n\\x1F\\x1E\\[\\]]/.test(anchor)) continue\n text = text.slice(0, r.start) + `[${anchor}](${r.url})` + text.slice(r.end!)\n applied.push([r.start, r.end!])\n }\n if (applied.length) href = undefined // 문단 전체 href 중복 방지\n }\n\n // 목차 리더 마커(\\x1F) 이후 텍스트(페이지번호) 제거\n const leaderIdx = text.indexOf(\"\\x1F\")\n if (leaderIdx >= 0) text = text.substring(0, leaderIdx)\n\n const cleanParaText = (raw: string): string => {\n let t = raw.replace(/[ \\t]+/g, \" \").trim()\n // 한글 이미지 OLE 대체 텍스트 필터링 (\"그림입니다. 원본 그림의 이름: ...\")\n if (/^그림입니다\\.?\\s*원본\\s*그림의\\s*(이름|크기)/.test(t)) t = \"\"\n // 멀티라인으로 삽입된 OLE 대체 텍스트도 제거\n t = t.replace(/그림입니다\\.?\\s*원본\\s*그림의\\s*(이름|크기)[^\\n]*(\\n[^\\n]*원본\\s*그림의\\s*(이름|크기)[^\\n]*)*/g, \"\").trim()\n // HWP 도형/개체 대체텍스트 제거 (\"사각형입니다.\", \"개체 입니다.\" 등)\n // 행 전체 일치(^…$m)로 한정 — 무앵커면 \"붙임 문서는 표 입니다.\" 같은 본문 중간을 오삭제한다.\n // NOTE: \"수식\" 은 제거 목록에서 빠져있음 — <hp:equation> 파싱으로 LaTeX 본문이 이미\n // `$...$` 형태로 삽입되기 때문에 여기서 지울 alt-text 는 존재하지 않는다.\n return t.replace(/^(?:모서리가 둥근 |둥근 )?(?:사각형|직사각형|정사각형|원|타원|삼각형|선|직선|곡선|화살표|오각형|육각형|팔각형|별|십자|구름|마름모|도넛|평행사변형|사다리꼴|개체|그리기\\s?개체|묶음\\s?개체|글상자|표|그림|OLE\\s?개체)\\s?입니다\\.?$/gm, \"\").trim()\n }\n\n // 인라인 표 경계(\\x1E)로 분할 — 표 전후 텍스트를 문서 순서대로 방출 (#49/#50).\n // text는 마커 제거 후 기존과 동일 파이프라인 (표 없는 문단은 바이트 동일)\n let segments: string[] | undefined\n if (text.includes(\"\\x1E\")) {\n // 인라인 표 문단은 조각 방출이라 안내문 표시 없이 원문 유지\n segments = text.split(\"\\x1E\").map(s => cleanParaText(stripPlaceholderMarks(s)))\n text = text.replace(/\\x1E/g, \"\")\n }\n let cleanText = cleanParaText(segments ? stripPlaceholderMarks(text) : text)\n let placeholderSpans: IRSpan[] | undefined\n if (cleanText.includes(PH_OPEN)) {\n placeholderSpans = []\n for (const part of cleanText.split(/(\\x1C[^\\x1C\\x1D]*\\x1D)/)) {\n if (!part) continue\n if (part.startsWith(PH_OPEN)) placeholderSpans.push({ text: part.slice(1, -1), placeholder: true })\n else placeholderSpans.push({ text: stripPlaceholderMarks(part) })\n }\n cleanText = stripPlaceholderMarks(cleanText)\n if (!placeholderSpans.some(s => s.placeholder && s.text)) placeholderSpans = undefined\n }\n\n // 스타일 정보 조회\n let style: InlineStyle | undefined\n if (styleMap && charPrId) {\n const charProp = styleMap.charProperties.get(charPrId)\n if (charProp) {\n style = {}\n if (charProp.fontSize) style.fontSize = charProp.fontSize\n if (charProp.bold) style.bold = true\n if (charProp.italic) style.italic = true\n if (charProp.fontName) style.fontName = charProp.fontName\n if (!style.fontSize && !style.bold && !style.italic) style = undefined\n }\n }\n\n return { text: cleanText, href, footnote, style, segments, placeholderSpans }\n}\n\n/** 자동번호 접두가 붙은 문단이면 접두를 평문 span 으로 앞에 — span 을 이으면 블록 글과 같다 */\nfunction withPrefixSpan(spans: IRSpan[], prefix?: string): IRSpan[] {\n return prefix ? [{ text: prefix + \" \" }, ...spans] : spans\n}\n\nfunction stripPlaceholderMarks(s: string): string {\n return s.includes(PH_OPEN) || s.includes(PH_CLOSE) ? s.replace(/[\\x1C\\x1D]/g, \"\") : s\n}\n","/**\n * HWPX 이미지 추출 (parser.ts에서 분리).\n * blocks의 image ref를 ZIP 바이너리로 해제 — ref 단위 dedupe·실패 캐시·ZIP bomb 가드.\n */\n\nimport type JSZip from \"jszip\"\nimport { KordocError, isPathTraversal } from \"../utils.js\"\nimport type { ExtractedImage, IRBlock, IRCell, ParseWarning } from \"../types.js\"\nimport { MAX_DECOMPRESS_SIZE, MAX_XML_DEPTH } from \"./parser-shared.js\"\nimport { detectImageMime } from \"../hwp5/images.js\"\n\n// ─── 이미지 추출 ───────────────────────────────────\n\n/** 확장자 → MIME 타입 */\nfunction imageExtToMime(ext: string): string {\n switch (ext.toLowerCase()) {\n case \"jpg\": case \"jpeg\": return \"image/jpeg\"\n case \"png\": return \"image/png\"\n case \"gif\": return \"image/gif\"\n case \"bmp\": return \"image/bmp\"\n case \"tif\": case \"tiff\": return \"image/tiff\"\n case \"wmf\": return \"image/wmf\"\n case \"emf\": return \"image/emf\"\n case \"svg\": return \"image/svg+xml\"\n default: return \"application/octet-stream\"\n }\n}\n\n/** MIME → 확장자 */\nfunction mimeToExt(mime: string): string {\n if (mime.includes(\"jpeg\")) return \"jpg\"\n if (mime.includes(\"png\")) return \"png\"\n if (mime.includes(\"gif\")) return \"gif\"\n if (mime.includes(\"bmp\")) return \"bmp\"\n if (mime.includes(\"tiff\")) return \"tif\"\n if (mime.includes(\"wmf\")) return \"wmf\"\n if (mime.includes(\"emf\")) return \"emf\"\n if (mime.includes(\"svg\")) return \"svg\"\n return \"bin\"\n}\n\n/** 이미지 블록 재귀 수집 — 표 셀 내부(IRCell.blocks)에 중첩된 이미지 포함 (v3.0).\n * hwp5 쪽과 안전장치 합집합: depth 가드 + children 순회 (둘 다 수행) */\nfunction collectImageBlocks(blocks: IRBlock[], out: { block: IRBlock; ownerCell?: IRCell }[], ownerCell?: IRCell, depth = 0): void {\n if (depth > MAX_XML_DEPTH) return\n for (const block of blocks) {\n if (block.type === \"image\") {\n out.push({ block, ownerCell })\n } else if (block.type === \"table\" && block.table) {\n for (const row of block.table.cells) {\n for (const cell of row) {\n if (cell.blocks?.length) collectImageBlocks(cell.blocks, out, cell, depth + 1)\n }\n }\n }\n if (block.children?.length) collectImageBlocks(block.children, out, ownerCell, depth + 1)\n }\n}\n\n/**\n * blocks에서 type=\"image\" 블록의 참조를 ZIP에서 실제 바이너리로 변환.\n *\n * sweepUnreferenced가 참이면(전체 문서 파싱 시) 본문 워크가 못 닿는 BinData\n * 이미지 — 머리말/꼬리말 안 그림, borderFill imgBrush(셀 배경 이미지) 등 — 를\n * 문서 끝에 image 블록으로 보강한다. 위치는 부정확하지만 바이트 무음 유실을 막는다.\n */\nexport async function extractImagesFromZip(\n zip: JSZip,\n blocks: IRBlock[],\n decompressed: { total: number },\n warnings?: ParseWarning[],\n sweepUnreferenced?: boolean,\n): Promise<ExtractedImage[]> {\n const images: ExtractedImage[] = []\n let imageIndex = 0\n // 본문 참조로 소비된 ZIP 경로 — 스윕 단계에서 중복 추출 방지\n const usedPaths = new Set<string>()\n\n const imageBlocks: { block: IRBlock; ownerCell?: IRCell }[] = []\n collectImageBlocks(blocks, imageBlocks)\n\n // 같은 ref를 참조하는 개체가 수천 개일 수 있다(도형 반복 등) — ref당 1회만\n // 해제·변환하고 데이터 버퍼를 공유한다 (블록마다 zip 재해제하면 메모리 폭발).\n // 실패도 캐시해 경고는 1회만. 캐시 히트는 새 해제가 아니므로 ZIP bomb 가드에 가산하지 않는다.\n const resolved = new Map<string, ExtractedImage | null>()\n\n for (const { block, ownerCell } of imageBlocks) {\n if (block.type !== \"image\" || !block.text) continue\n\n const ref = block.text\n let img = resolved.get(ref)\n if (img === undefined) {\n img = null\n // BinData/ 폴더 내에서 참조 파일 찾기\n // HWPX binaryItemIDRef는 확장자 없이 오는 경우가 많음 (예: \"image1\" → \"BinData/image1.bmp\")\n const candidates = [\n `BinData/${ref}`,\n `Contents/BinData/${ref}`,\n ref, // 절대 경로일 수도 있음\n ]\n\n // 확장자 없는 ref인 경우 ZIP에서 매칭 파일 탐색\n let resolvedPath: string | null = null\n if (!ref.includes(\".\")) {\n const prefixes = [`BinData/${ref}`, `Contents/BinData/${ref}`]\n for (const prefix of prefixes) {\n const match = zip.file(new RegExp(`^${prefix.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")}\\\\.[a-zA-Z0-9]+$`))\n if (match.length > 0) { resolvedPath = match[0].name; break }\n }\n }\n\n const allCandidates = resolvedPath ? [resolvedPath, ...candidates] : candidates\n for (const path of allCandidates) {\n if (isPathTraversal(path)) continue\n const file = zip.file(path)\n if (!file) continue\n\n try {\n const data = await file.async(\"uint8array\")\n decompressed.total += data.length\n if (decompressed.total > MAX_DECOMPRESS_SIZE) throw new KordocError(\"ZIP 압축 해제 크기 초과 (ZIP bomb 의심)\")\n\n const ext = path.includes(\".\") ? (path.split(\".\").pop() || \"png\") : \"png\"\n const mimeType = imageExtToMime(ext)\n imageIndex++\n const filename = `image_${String(imageIndex).padStart(3, \"0\")}.${mimeToExt(mimeType)}`\n\n img = { filename, data, mimeType, source: path }\n images.push(img)\n usedPaths.add(path)\n break\n } catch (err) {\n if (err instanceof KordocError) throw err\n // 개별 이미지 실패는 경고로 처리\n }\n }\n\n if (!img) warnings?.push({ page: block.pageNumber, message: `이미지 파일 없음: ${ref}`, code: \"SKIPPED_IMAGE\" })\n resolved.set(ref, img)\n }\n\n if (!img) {\n // image 블록을 paragraph로 전환 (참조만 남김 — 사용자 그림설명이 있으면 함께)\n block.type = \"paragraph\"\n block.text = `[이미지: ${ref}]`\n // 교체값은 함수로 — 문자열이면 ref 안의 $&, $' 등이 특수 패턴으로 확장된다\n if (ownerCell) ownerCell.text = ownerCell.text.replace(``, () => `[이미지: ${ref}]`)\n continue\n }\n\n // 블록 텍스트를 참조 파일명으로 교체\n const filename = img.filename\n block.text = filename\n block.imageData = { data: img.data, mimeType: img.mimeType, filename: ref }\n // 셀 내부 이미지 — 셀 평탄화 텍스트의 참조도 파일명으로 갱신 (교체값 함수 — $ 확장 방지)\n if (ownerCell) ownerCell.text = ownerCell.text.replace(``, () => ``)\n }\n\n // 본문 미참조 BinData 이미지 스윕 — 꼬리말/머리말 안 pic, imgBrush 배경 등.\n // 확장자 없거나 낯선 확장자는 매직바이트로 판별하고, 이미지가 아니면(OLE 등) 건너뛴다.\n if (sweepUnreferenced) {\n const binEntries = zip.file(/(?:^|\\/)BinData\\//i)\n for (const file of binEntries) {\n if (file.dir || usedPaths.has(file.name) || isPathTraversal(file.name)) continue\n try {\n const data = await file.async(\"uint8array\")\n decompressed.total += data.length\n if (decompressed.total > MAX_DECOMPRESS_SIZE) throw new KordocError(\"ZIP 압축 해제 크기 초과 (ZIP bomb 의심)\")\n\n const ext = file.name.includes(\".\") ? (file.name.split(\".\").pop() || \"\") : \"\"\n let mimeType = imageExtToMime(ext)\n if (mimeType === \"application/octet-stream\") {\n const sniffed = detectImageMime(data)\n if (!sniffed) continue // 이미지 아님 (OLE 개체 등)\n mimeType = sniffed\n }\n imageIndex++\n const filename = `image_${String(imageIndex).padStart(3, \"0\")}.${mimeToExt(mimeType)}`\n const img: ExtractedImage = { filename, data, mimeType, source: file.name }\n images.push(img)\n blocks.push({ type: \"image\", text: filename, imageData: { data, mimeType, filename: file.name } })\n } catch (err) {\n if (err instanceof KordocError) throw err\n warnings?.push({ message: `이미지 추출 실패: ${file.name}`, code: \"SKIPPED_IMAGE\" })\n }\n }\n }\n\n return images\n}\n","/**\n * HWPX 메타데이터 추출 (parser.ts에서 분리) — content.hpf(OPF)·Dublin Core best-effort.\n */\n\nimport JSZip from \"jszip\"\nimport { KordocError, stripDtd } from \"../utils.js\"\nimport type { DocumentMetadata } from \"../types.js\"\nimport { createXmlParser, MAX_DECOMPRESS_SIZE } from \"./parser-shared.js\"\nimport { resolveSectionPaths } from \"./zip-sections.js\"\nimport { elementChildren, findChildByLocalName, localName } from \"../shared/xml.js\"\n\n// ─── 메타데이터 추출 (best-effort) ───────────────────\n\n/**\n * HWPX ZIP 내 메타데이터 파일에서 문서 정보 추출.\n * 한컴 저장본은 패키지 문서 Contents/content.hpf(OPF)의 opf:metadata 에 둔다 — 먼저 읽고,\n * 제목·지은이가 없으면 Dublin Core 경로(meta.xml, docProps/core.xml)로 비는 필드를 채운다.\n */\nexport async function extractHwpxMetadata(zip: JSZip, metadata: DocumentMetadata, decompressed?: { total: number }): Promise<void> {\n try {\n const read = async (path: string): Promise<string | null> => {\n const file = zip.file(path) || Object.values(zip.files).find(f => f.name.toLowerCase() === path.toLowerCase()) || null\n if (!file) return null\n const xml = await file.async(\"text\")\n if (decompressed) {\n decompressed.total += xml.length * 2\n if (decompressed.total > MAX_DECOMPRESS_SIZE) throw new KordocError(\"ZIP 압축 해제 크기 초과 (ZIP bomb 의심)\")\n }\n return xml\n }\n for (const hp of [\"Contents/content.hpf\", \"content.hpf\"]) {\n const xml = await read(hp)\n if (!xml) continue\n parseOpfMetadata(xml, metadata)\n break\n }\n if (metadata.title || metadata.author) return\n // meta.xml (HWPX 표준) 또는 docProps/core.xml (OOXML 호환)\n const metaPaths = [\"meta.xml\", \"META-INF/meta.xml\", \"docProps/core.xml\"]\n for (const mp of metaPaths) {\n const xml = await read(mp)\n if (!xml) continue\n parseDublinCoreMetadata(xml, metadata)\n if (metadata.title || metadata.author) return\n }\n } catch {\n // best-effort\n }\n}\n\n/**\n * 한컴 패키지 문서(content.hpf) 메타 — opf:title 과 opf:meta name=creator·subject·description·keyword·\n * CreatedDate·ModifiedDate (값은 요소 글, content=\"text\" 는 형식 표지). HWP5 요약 정보(2 제목·4 지은이·\n * 6 설명|3 주제·5 키워드·12/13 날짜)와 같은 필드 — 한컴이 저장한 hwp↔hwpx 짝에서 값이 같다.\n * lastsaveby·date(한국어 날짜 글)는 HWP5 와 같이 싣지 않는다\n */\nfunction parseOpfMetadata(xml: string, metadata: DocumentMetadata): void {\n const root = createXmlParser().parseFromString(stripDtd(xml), \"text/xml\").documentElement as unknown as Element | null\n const md = root ? findChildByLocalName(root, \"metadata\") : null\n if (!md) return\n let title: string | undefined\n const meta = new Map<string, string>()\n for (const el of elementChildren(md)) {\n const text = el.textContent?.trim()\n if (!text) continue\n const tag = localName(el)\n if (tag === \"title\") title ??= text\n else if (tag === \"meta\") {\n const name = el.getAttribute(\"name\")\n if (name && !meta.has(name)) meta.set(name, text)\n }\n }\n const put = <K extends keyof DocumentMetadata>(k: K, v: DocumentMetadata[K] | undefined) => {\n if (v !== undefined && !metadata[k]) metadata[k] = v\n }\n const keywords = meta.get(\"keyword\")?.split(/[,;]/).map(k => k.trim()).filter(Boolean)\n put(\"title\", title)\n put(\"author\", meta.get(\"creator\"))\n put(\"description\", meta.get(\"description\") || meta.get(\"subject\"))\n put(\"keywords\", keywords?.length ? keywords : undefined)\n put(\"createdAt\", isoDate(meta.get(\"CreatedDate\")))\n put(\"modifiedAt\", isoDate(meta.get(\"ModifiedDate\")))\n}\n\n/**\n * content.hpf 날짜 → ISO 8601. 한컴은 보통 \"2023-07-14T02:14:57Z\"(UTC)로 쓰지만 T·Z 없는 \"2025-07-07 09:40:07\"\n * 저장본도 있다 — 이 꼴은 저장한 PC 의 현지 시각이다 (pairs/pair02 ModifiedDate \"1601-01-01 09:00:00\" = FILETIME 0\n * + KST 9시간). 시간대를 지어내지 않고 \"T\" 만 넣어 시간대 없는 ISO 8601 로 둔다. FILETIME 0(1601-01-01, 미기록)은\n * HWP5 요약 정보처럼 없음, 모르는 꼴은 그대로\n */\nfunction isoDate(s: string | undefined): string | undefined {\n if (!s || s.startsWith(\"1601-01-01\")) return undefined\n const m = /^(\\d{4}-\\d{2}-\\d{2}) (\\d{2}:\\d{2}:\\d{2})$/.exec(s)\n return m ? `${m[1]}T${m[2]}` : s\n}\n\n/** Dublin Core (dc:) 메타데이터 XML 파싱 */\nfunction parseDublinCoreMetadata(xml: string, metadata: DocumentMetadata): void {\n const parser = createXmlParser()\n const doc = parser.parseFromString(stripDtd(xml), \"text/xml\")\n if (!doc.documentElement) return\n\n const getText = (tagNames: string[]): string | undefined => {\n for (const tag of tagNames) {\n const els = doc.getElementsByTagName(tag)\n if (els.length > 0) {\n const text = els[0].textContent?.trim()\n if (text) return text\n }\n }\n return undefined\n }\n\n metadata.title = metadata.title || getText([\"dc:title\", \"title\"])\n metadata.author = metadata.author || getText([\"dc:creator\", \"creator\", \"cp:lastModifiedBy\"])\n metadata.description = metadata.description || getText([\"dc:description\", \"description\", \"dc:subject\", \"subject\"])\n metadata.createdAt = metadata.createdAt || getText([\"dcterms:created\", \"meta:creation-date\"])\n metadata.modifiedAt = metadata.modifiedAt || getText([\"dcterms:modified\", \"meta:date\"])\n\n const keywords = getText([\"dc:keyword\", \"cp:keywords\", \"meta:keyword\"])\n if (keywords && !metadata.keywords) {\n metadata.keywords = keywords.split(/[,;]/).map(k => k.trim()).filter(Boolean)\n }\n}\n\n/** 메타데이터만 추출 (전체 파싱 없이) — MCP parse_metadata용 */\nexport async function extractHwpxMetadataOnly(buffer: ArrayBuffer): Promise<DocumentMetadata> {\n let zip: JSZip\n try {\n zip = await JSZip.loadAsync(buffer)\n } catch {\n throw new KordocError(\"HWPX ZIP을 열 수 없습니다\")\n }\n\n const metadata: DocumentMetadata = {}\n await extractHwpxMetadata(zip, metadata)\n\n const sectionPaths = await resolveSectionPaths(zip)\n metadata.pageCount = sectionPaths.length\n\n return metadata\n}\n","/**\n * HWPX 손상 ZIP 복구 + Manifest 섹션 경로 해석 (parser.ts에서 분리).\n * Central Directory 손상 시 Local File Header(PK\\x03\\x04) 직접 스캔 (edu-facility-ai에서 포팅).\n */\n\nimport JSZip from \"jszip\"\nimport { inflateRawSync } from \"zlib\"\nimport { KordocError, isPathTraversal, stripDtd, normalizeSectionHref, compareSectionPaths } from \"../utils.js\"\nimport { blocksToMarkdown } from \"../table/builder.js\"\nimport type { InternalParseResult, IRBlock, ParseWarning } from \"../types.js\"\nimport { applyPageText, createSectionShared, createXmlParser, MAX_DECOMPRESS_SIZE, MAX_ZIP_ENTRIES } from \"./parser-shared.js\"\nimport { parseSectionXml } from \"./section-walker.js\"\n\n// ─── 손상 ZIP 복구 (edu-facility-ai에서 포팅) ──────────\n\nexport function extractFromBrokenZip(buffer: ArrayBuffer): InternalParseResult {\n const data = new Uint8Array(buffer)\n const view = new DataView(buffer)\n let pos = 0\n const blocks: IRBlock[] = []\n const warnings: ParseWarning[] = [\n { code: \"BROKEN_ZIP_RECOVERY\", message: \"손상된 ZIP 구조 — Local File Header 기반 복구 모드\" },\n ]\n let totalDecompressed = 0\n let entryCount = 0\n let sectionNum = 0\n const shared = createSectionShared()\n\n while (pos < data.length - 30) {\n // PK\\x03\\x04 시그니처 확인 — 미매칭 시 다음 PK 시그니처까지 스캔 (중간 손상 복구)\n if (data[pos] !== 0x50 || data[pos + 1] !== 0x4b || data[pos + 2] !== 0x03 || data[pos + 3] !== 0x04) {\n pos++\n while (pos < data.length - 30) {\n if (data[pos] === 0x50 && data[pos + 1] === 0x4b && data[pos + 2] === 0x03 && data[pos + 3] === 0x04) break\n pos++\n }\n continue\n }\n\n if (++entryCount > MAX_ZIP_ENTRIES) break\n\n const method = view.getUint16(pos + 8, true)\n const compSize = view.getUint32(pos + 18, true)\n const nameLen = view.getUint16(pos + 26, true)\n const extraLen = view.getUint16(pos + 28, true)\n\n // nameLen 상한 — 비정상 값에 의한 대규모 버퍼 할당 방지\n if (nameLen > 1024 || extraLen > 65535) { pos += 30 + nameLen + extraLen; continue }\n\n const fileStart = pos + 30 + nameLen + extraLen\n // 범위 초과 검증 — OOB 및 무한 루프 방지\n if (fileStart + compSize > data.length) break\n if (compSize === 0 && method !== 0) { pos = fileStart; continue }\n\n const nameBytes = data.slice(pos + 30, pos + 30 + nameLen)\n const name = new TextDecoder().decode(nameBytes)\n\n // 경로 순회 방지 — 상위 디렉토리 참조 및 절대 경로 차단\n if (isPathTraversal(name)) { pos = fileStart + compSize; continue }\n const fileData = data.slice(fileStart, fileStart + compSize)\n pos = fileStart + compSize\n\n if (!name.toLowerCase().includes(\"section\") || !name.endsWith(\".xml\")) continue\n\n try {\n let content: string\n if (method === 0) {\n content = new TextDecoder().decode(fileData)\n } else if (method === 8) {\n const decompressed = inflateRawSync(Buffer.from(fileData), { maxOutputLength: MAX_DECOMPRESS_SIZE })\n content = new TextDecoder().decode(decompressed)\n } else {\n continue\n }\n totalDecompressed += content.length * 2\n if (totalDecompressed > MAX_DECOMPRESS_SIZE) throw new KordocError(\"압축 해제 크기 초과\")\n sectionNum++\n const secBlocks = parseSectionXml(content, undefined, warnings, sectionNum, shared)\n // 복구 경로는 조판 캐시를 신뢰하지 않는다 — 섹션 근사 고정 (#66)\n for (const b of secBlocks) b.pageNumber = sectionNum\n blocks.push(...secBlocks)\n } catch {\n continue\n }\n }\n\n if (blocks.length === 0) throw new KordocError(\"손상된 HWPX에서 섹션 데이터를 복구할 수 없습니다\")\n applyPageText(blocks, shared)\n const markdown = blocksToMarkdown(blocks)\n return { markdown, blocks, warnings: warnings.length > 0 ? warnings : undefined }\n}\n\n// ─── Manifest 해석 ───────────────────────────────────\n\n/**\n * content.hpf의 kordoc 생성자 마커 판독 — 왕복 채널(자사 파일 한정 복원)의 게이트.\n * generator가 아닌 파일(한컴 산출물 등)은 null → id 기반 인라인 강조·인용 복원 꺼짐.\n */\nexport async function readKordocLayout(zip: JSZip): Promise<string | null> {\n const file = zip.file(\"Contents/content.hpf\") ?? zip.file(\"content.hpf\")\n if (!file) return null\n try {\n const xml = await file.async(\"text\")\n if (!/<opf:meta\\b[^>]*name=\"generator\"[^>]*content=\"kordoc\"/.test(xml)) return null\n return xml.match(/<opf:meta\\b[^>]*name=\"kordoc-layout\"[^>]*content=\"([^\"]*)\"/)?.[1] ?? null\n } catch {\n return null\n }\n}\n\nexport async function resolveSectionPaths(zip: JSZip): Promise<string[]> {\n const manifestPaths = [\"Contents/content.hpf\", \"content.hpf\"]\n for (const mp of manifestPaths) {\n const mpLower = mp.toLowerCase()\n const file = zip.file(mp) || Object.values(zip.files).find(f => f.name.toLowerCase() === mpLower) || null\n if (!file) continue\n const xml = await file.async(\"text\")\n const paths = parseSectionPathsFromManifest(xml)\n if (paths.length > 0) return paths\n }\n\n // fallback: section*.xml 직접 검색\n const sectionFiles = zip.file(/[Ss]ection\\d+\\.xml$/)\n return sectionFiles.map(f => f.name).sort(compareSectionPaths)\n}\n\nfunction parseSectionPathsFromManifest(xml: string): string[] {\n const parser = createXmlParser()\n const doc = parser.parseFromString(stripDtd(xml), \"text/xml\")\n const items = doc.getElementsByTagName(\"opf:item\")\n const spine = doc.getElementsByTagName(\"opf:itemref\")\n\n const idToHref = new Map<string, string>()\n for (let i = 0; i < items.length; i++) {\n const item = items[i]\n const id = item.getAttribute(\"id\") || \"\"\n const href = normalizeSectionHref(item.getAttribute(\"href\") || \"\")\n if (id && href) idToHref.set(id, href)\n }\n\n if (spine.length > 0) {\n const ordered: string[] = []\n for (let i = 0; i < spine.length; i++) {\n const href = idToHref.get(spine[i].getAttribute(\"idref\") || \"\")\n if (href) ordered.push(href)\n }\n if (ordered.length > 0) return ordered\n }\n return Array.from(idToHref.values()).sort(compareSectionPaths)\n}\n","/**\n * HWP 3.0 (한글 워드프로세서 3.x) 파서.\n *\n * 1996~2002년 한컴이 사용한 binary 포맷. CFB(OLE2) 컨테이너가 아닌 단일 binary stream.\n * 내부 구조 요약:\n * 30 byte signature\n * + 128 byte DocInfo (compressed/encrypted 플래그 + InfoBlock 길이)\n * + 1008 byte DocSummary (제목/저자/날짜)\n * + InfoBlock (가변 — 폰트/스타일 메타데이터)\n * + Body (compressed!=0 이면 raw deflate 압축)\n *\n * Body 는 paragraph 의 list. 각 paragraph 는 헤더 + LineInfos + (inline char shapes) + char stream.\n * char stream 은 hchar (u16 little-endian) 의 시퀀스로, 1..31 영역(13 제외) 은 제어 문자\n * (제어 문자별로 추가 byte 를 소비하고 일부는 nested paragraph list 가짐).\n *\n * IR 은 HWP5·HWPX 파서와 같은 모양으로 조립한다(hwp5/ir-assemble.ts 공용): 표·글상자·단추(ch=10)는 셀 기하로\n * 복원한 IRTable(hwp3/table.ts — 한컴 HWP3→HWPX 변환본도 글상자·단추를 1×1 표로 낸다), 수식은 LaTeX, 각주·미주는\n * 마커 + (주: …), 머리말·꼬리말은 본문 앞·뒤 1회, 개요 번호는 번호 글자, 숨은 설명은 제외. 글자 속성·레이아웃은 무시.\n *\n * 출처: rhwp/src/parser/hwp3/mod.rs (MIT). 바이트 소비 규칙은 1:1 포팅.\n */\n\nimport { inflateRawSync } from \"zlib\"\nimport type { DocumentMetadata, IRBlock, InternalParseResult, ParseOptions, ParseWarning } from \"../types.js\"\nimport { KordocError } from \"../utils.js\"\nimport { blocksToMarkdown, escapeLiteralDollar, flattenLayoutTables } from \"../table/builder.js\"\nimport { hwpEquationToLatex } from \"../hwp5/equation.js\"\nimport { formatNumber, type NumFmt } from \"../hwp5/numbering.js\"\nimport {\n INLINE_TABLE_MARK, blocksPlainText, buildAddressedTable, cellTextFromBlocks, emitParagraphBlocks,\n type AddressedCell, type ParaObject,\n} from \"../hwp5/ir-assemble.js\"\nimport { collectDrawingTextBoxLists } from \"./drawing.js\"\nimport { decodeJohabText } from \"./johab.js\"\nimport { Reader } from \"./reader.js\"\nimport { readHeader } from \"./records.js\"\nimport { decryptHwp3Document, isEncryptedHwp3 } from \"./crypto.js\"\nimport { hwp3CellGrid } from \"./table.js\"\n\n/** 압축 해제 최대 크기 (100MB) — decompression bomb 방지 (hwp5/record.ts와 동일 캡) */\nconst MAX_DECOMPRESS_SIZE = 100 * 1024 * 1024\n\n/** ch=11 그림 정보 offset 74 — 3 이면 확장 블록이 그리기 개체 트리다 (0/1/2 는 그림). */\nconst PIC_TYPE_DRAWING = 3\n\n/** ch=10 개체 종류(info[78]) — 0 표, 1 글상자, 2 수식, 3 단추 (rhwp parse_hwp3_object_dispatch) */\nconst OBJ_EQUATION = 2\n/** ch=10 기타 옵션(info[14]) bit 4 — 하이퍼텍스트 개체 */\nconst OPT_HYPERTEXT = 0x10\n\n/** 채움(점끌기) 탭 표지 — 뒤는 목차 쪽번호라 문단 글을 여기서 자른다 (HWPX \\x1F·HWP5 LEADER_TAB_MARK 와 같은 정책) */\nconst LEADER_TAB_MARK = \"\\x1F\"\n\n/**\n * 개요 번호(ch=28) 수준별 모양 — 한글 97 기본 개요 (rhwp ensure_hwp3_default_outline_numbering 과 같은 표).\n * 한컴 HWP3→HWPX 변환본 실측(SO-SUEOP): Ⅰ. / 1) / (1) / 가. / 가) / (가) / ①\n */\nconst OUTLINE_FORMATS: Array<{ fmt: NumFmt; before: string; after: string }> = [\n { fmt: \"romanUpper\", before: \"\", after: \".\" },\n { fmt: \"digit\", before: \"\", after: \")\" },\n { fmt: \"digit\", before: \"(\", after: \")\" },\n { fmt: \"ganada\", before: \"\", after: \".\" },\n { fmt: \"ganada\", before: \"\", after: \")\" },\n { fmt: \"ganada\", before: \"(\", after: \")\" },\n { fmt: \"circled\", before: \"\", after: \"\" },\n]\n\nconst PARA_SHAPE_SIZE = 187 // ParaShape 구조 (rhwp records.rs Hwp3ParaShape::read 합산)\nconst LINE_INFO_SIZE = 14 // Hwp3LineInfo (u16 × 7)\nconst INLINE_CHAR_SHAPE_SIZE = 31 // Hwp3CharShape (rep_char_shape 와 동일)\n// 제어 문자별 ch 외 추가 read byte 수. (ch 는 이미 paragraph loop 가 read 한 후라 여기엔 미포함.)\n// 단위: byte. 동시에 char_count 에서 차지하는 hchar 도 다름 — 아래 EXTRA_HCHAR.\n//\n// rhwp/src/parser/hwp3/mod.rs ch 분기 그대로 옮긴 표. 탭(9)·자동번호(18)·개요번호(28)는 내용을 읽어야 해서\n// parseCharStream 이 따로 처리한다:\n// 9 (Tab) : extra=6 byte, hchar=4 — spec §10.5 표 39: hchar+hunit 탭폭+word 점끌기+hchar 닫기\n// = 8 byte 구조 (rhwp d89b689 #929 정합 — 2 byte 소비 시 탭마다 desync)\n// 18~21 (각종 번호) : extra=6 byte, hchar=4\n// 22 (메일머지) : extra=22 byte, hchar=12\n// 23 (글자겹침) : extra=8 byte, hchar=5\n// 24 (하이픈) : extra=4 byte, hchar=3 — spec §10.18 표 59, 실제 하이픈 글리프\n// 25 (차례 표시) : extra=4 byte, hchar=3 — spec §10.19 표 60, 제목/표/그림 차례 표식.\n// 비가시 마크라 글리프를 방출하지 않는다 (rhwp #2765 정합 — 종전엔\n// 하이픈(24)과 같은 항목이라 차례 표식마다 잉여 '-' 가 본문에 삽입)\n// 26 (찾아보기) : extra=244 byte, hchar=123 (1 + 122 추가)\n// 28 (개요번호) : extra=62 byte, hchar=32 (1 + 31 추가)\n// 30 (묶음빈칸) : extra=2 byte, hchar=2\n// 31 (고정폭빈칸) : extra=2 byte, hchar=2\n// default (7/8/10/11/12/15/16/17/27/29 등): 8 byte 헤더 + 종류별 추가\n// 7,8 (날짜 형식/코드) 은 84/96 byte 가변폭 구조체라 simple 이 아니다 — 8 byte 헤더\n// 뒤 76/88 byte 를 더 소비해야 한다 (rhwp #2844 정합, 아래 switch 참조)\ntype CtrlSimple = { extraBytes: number; extraHchar: number; emit: string | null }\nconst SIMPLE_CTRL: ReadonlyMap<number, CtrlSimple> = new Map([\n // 19/20/21 (새 번호·쪽 번호 위치·쪽 감추기) 는 비가시 마커다 — 한글도 그 자리에\n // 아무 글자를 내지 않는다 (rhwp #4957). 종전엔 U+FFFC 를 본문에 심어 마크다운에\n // 대체 문자가 그대로 남았다 (samples 33개 중 6문서 11건). 차례 표식(25) 과 같은 계약.\n [19, { extraBytes: 6, extraHchar: 3, emit: null }],\n [20, { extraBytes: 6, extraHchar: 3, emit: null }],\n [21, { extraBytes: 6, extraHchar: 3, emit: null }],\n [22, { extraBytes: 22, extraHchar: 11, emit: \"\" }],\n [23, { extraBytes: 8, extraHchar: 4, emit: \"\" }],\n [24, { extraBytes: 4, extraHchar: 2, emit: \"-\" }],\n [25, { extraBytes: 4, extraHchar: 2, emit: null }], // 차례 표식 — 비가시 (rhwp #2765)\n [26, { extraBytes: 244, extraHchar: 122, emit: \"\" }],\n [30, { extraBytes: 2, extraHchar: 1, emit: \" \" }],\n [31, { extraBytes: 2, extraHchar: 1, emit: \" \" }],\n])\n\n/** 문서 전역 파싱 상태 */\ninterface ParaContext {\n warnings: ParseWarning[]\n /** 머리말·꼬리말 — 본문 앞·뒤에 1회 (HWP5 applyHeaderFooterEffect·HWPX applyPageText 와 같은 배치) */\n headerBlocks: IRBlock[]\n footerBlocks: IRBlock[]\n headerTexts: Set<string>\n /** 쪽 번호 자동번호(ch=18 종류 0)를 만난 횟수 — 쪽 번호뿐인 머리말(크롬) 판별 */\n pageNumbers: number\n /** 각주·미주 번호가 비었을 때의 순번 */\n noteSeq: [number, number]\n}\n\n/** 문단 1개의 파싱 누적 — 파싱이 중간에 깨져도 모은 만큼 방출한다 */\ninterface Hwp3Para {\n text: string\n objects: ParaObject[]\n footnotes: string[]\n /** 개요 번호 (ch=28 종류 1) — 수준 + 저장된 수준별 현재 번호 */\n outline?: { level: number; numbers: number[] }\n}\n\nexport interface Hwp3ParseOptions extends ParseOptions {\n /** 표/그림 nested paragraph 본문도 출력 (기본 true). */\n includeNested?: boolean\n}\n\n/**\n * HWP3 buffer → InternalParseResult.\n * 암호 문서는 options.password 로 복호한다 — 없으면 ENCRYPTED 코드로 throw.\n */\nexport function parseHwp3Document(\n buffer: ArrayBuffer,\n options?: Hwp3ParseOptions,\n): InternalParseResult {\n let source = Buffer.from(buffer)\n\n // 암호 문서는 복호해서 평문 바이트로 바꾼 뒤 아래 경로를 그대로 탄다.\n // KordocError 라야 sanitizeError 가 메시지를 보존하고 classifyError 가 ENCRYPTED 로 분류한다\n // (plain Error + e.code 는 둘 다 무시되어 PARSE_ERROR/일반 문구로 뭉개졌다)\n if (isEncryptedHwp3(source)) {\n if (!options?.password) {\n throw new KordocError(\n \"암호로 보호된 HWP3 문서입니다. password 옵션에 열기 암호를 지정하세요.\",\n )\n }\n source = decryptHwp3Document(source, options.password)\n }\n\n const headReader = new Reader(source)\n const header = readHeader(headReader)\n\n // InfoBlock skip — 폰트/스타일 메타데이터, 텍스트 추출엔 불필요.\n headReader.skip(header.infoBlockLength)\n\n // Body: compressed != 0 이면 raw deflate (zlib 헤더 없는 RFC 1951)\n const tail = headReader.readToEnd()\n let body: Buffer\n const warnings: ParseWarning[] = []\n if (header.compressed !== 0) {\n try {\n body = inflateRawSync(tail, { maxOutputLength: MAX_DECOMPRESS_SIZE })\n } catch (err) {\n if ((err as NodeJS.ErrnoException)?.code === \"ERR_BUFFER_TOO_LARGE\") {\n throw new KordocError(`HWP3 압축 해제 결과가 최대 허용 크기(${MAX_DECOMPRESS_SIZE / 1024 / 1024}MB)를 초과했습니다`)\n }\n const msg = err instanceof Error ? err.message : String(err)\n throw new KordocError(`HWP3 압축 해제 실패: ${msg}`)\n }\n } else {\n body = tail\n }\n\n const bodyReader = new Reader(body)\n const ctx: ParaContext = { warnings, headerBlocks: [], footerBlocks: [], headerTexts: new Set(), pageNumbers: 0, noteSeq: [0, 0] }\n const bodyBlocks: IRBlock[] = []\n try {\n skipFontFacesAndStyles(bodyReader)\n parseParagraphList(bodyReader, ctx, bodyBlocks)\n } catch (err) {\n // 부분 파싱 실패 — 모은 만큼이라도 반환. truncated 경고 추가.\n warnings.push({\n code: \"PARTIAL_PARSE\",\n message: `HWP3 paragraph stream 도중 파싱 중단: ${err instanceof Error ? err.message : String(err)}`,\n })\n }\n\n // 레이아웃 표 해체 — HWP5 와 같은 바이너리 계열 정책(표로 페이지를 짠 구형 문서). HWP5 쌍 벤치는 HWPX 쪽에도\n // 같은 함수를 적용해 대칭으로 비교한다\n const blocks = flattenLayoutTables([...ctx.headerBlocks, ...bodyBlocks, ...ctx.footerBlocks])\n\n const metadata: DocumentMetadata = {\n title: header.title || undefined,\n author: header.author || undefined,\n description: header.subject || undefined,\n createdAt: header.date || undefined,\n version: \"3.0\",\n }\n\n return {\n markdown: blocksToMarkdown(blocks),\n blocks,\n metadata,\n warnings: warnings.length ? warnings : undefined,\n }\n}\n\n/**\n * 본문 paragraph_list 진입 전 — 압축 해제된 body 의 앞쪽에는 font / style 메타데이터가 있다.\n * rhwp/src/parser/hwp3/mod.rs:1654~1700 흐름 그대로:\n * - 7개 언어별 font face: n_fonts(u16) + n_fonts × 40 byte name\n * - n_styles(u16) + n_styles × (20 byte name + 31 byte char_shape + 187 byte para_shape)\n */\nfunction skipFontFacesAndStyles(reader: Reader): void {\n const STYLE_RECORD_SIZE = 20 + 31 + 187 // = 238\n for (let lang = 0; lang < 7; lang++) {\n const n = reader.readU16()\n reader.skip(n * 40)\n }\n const nStyles = reader.readU16()\n reader.skip(nStyles * STYLE_RECORD_SIZE)\n}\n\n/**\n * char_count==0 빈 paragraph 가 list 끝. 블록은 sink 에 바로 쌓는다 — 스트림이 도중에 깨져 throw 해도\n * 모은 만큼은 호출자에게 남는다.\n */\nfunction parseParagraphList(reader: Reader, ctx: ParaContext, sink: IRBlock[]): void {\n for (;;) {\n if (reader.eof()) return\n\n // ParaInfo 헤더 (가변 size). list 끝 sentinel(empty para)이 아니어도 stream sync 가\n // 어긋난 이전 paragraph 의 잔재로 비정상 헤더가 들어올 수 있다. char_count 가\n // 1 paragraph 한도(64K) 를 넘는다거나 lineCount 가 비정상적이면 list 종료로 간주.\n const followPrev = reader.readU8()\n const charCount = reader.readU16()\n if (charCount === 0) {\n // 빈 paragraph: 이미 3 byte 읽었으므로 40 byte 더 read 후 종료\n reader.skip(40)\n return\n }\n const lineCount = reader.readU16()\n // 방어: 한 paragraph 의 line 수가 4096 을 넘는 건 stream 어긋남으로 간주.\n if (charCount > 60000 || lineCount > 4096) {\n ctx.warnings.push({\n code: \"PARTIAL_PARSE\",\n message: `HWP3 비정상 paragraph 헤더 (char_count=${charCount}, line_count=${lineCount}) → 이후 stream 포기`,\n })\n return\n }\n const includeCharShape = reader.readU8()\n reader.skip(1) // flags\n reader.skip(4) // special_char_flags\n reader.skip(1) // style_index\n reader.skip(31) // rep_char_shape\n if (followPrev === 0) reader.skip(PARA_SHAPE_SIZE)\n\n // LineInfos\n reader.skip(lineCount * LINE_INFO_SIZE)\n\n // Inline char shapes — char_count 만큼 (flag u8, flag != 1 이면 charshape 31 byte)\n if (includeCharShape !== 0) {\n for (let i = 0; i < charCount; i++) {\n const flag = reader.readU8()\n if (flag !== 1) reader.skip(INLINE_CHAR_SHAPE_SIZE)\n }\n }\n\n // Char stream — paragraph 단위로 try/catch 해서 한 paragraph 가 깨져도 list 전체는\n // 살리되, sync 가 어긋난 후의 후속 paragraph 들도 비정상 헤더가 나올 가능성이 커서\n // 헤더 sanity check 로 방어한다. 깨진 paragraph 도 모은 글·개체는 방출한다\n const para: Hwp3Para = { text: \"\", objects: [], footnotes: [] }\n try {\n parseCharStream(reader, charCount, ctx, para)\n } catch (err) {\n sink.push(...emitHwp3Paragraph(para))\n ctx.warnings.push({\n code: \"PARTIAL_PARSE\",\n message: `HWP3 paragraph char stream 파싱 실패: ${err instanceof Error ? err.message : String(err)}`,\n })\n return\n }\n sink.push(...emitHwp3Paragraph(para))\n }\n}\n\n/** 파싱을 마친 문단 → IR 블록 (HWP5 와 같은 조립기: 리더 절단 → 개요 번호 → 표 자리 분할) */\nfunction emitHwp3Paragraph(para: Hwp3Para): IRBlock[] {\n let text = para.text\n const leaderAt = text.indexOf(LEADER_TAB_MARK)\n if (leaderAt >= 0) text = text.slice(0, leaderAt)\n let headMarker: string | null = null\n if (para.outline) {\n const { level, numbers } = para.outline\n const f = OUTLINE_FORMATS[level]\n const n = numbers[level]\n if (f && n > 0) headMarker = f.before + formatNumber(n, f.fmt) + f.after\n // 개요 번호 뒤 글은 한글 97 이 번호와 한 칸 띄워 그린다 — 본문 앞 공백은 번호 자리 여백\n text = text.replace(/^ +/, \"\")\n }\n return emitParagraphBlocks({ text: text.trim(), headMarker, headingLevel: 0, footnotes: para.footnotes, objects: para.objects })\n}\n\n/**\n * paragraph 본문 char_count 개의 hchar 를 처리해 para 에 누적한다.\n * 제어 문자는 제어 byte 만큼 정확히 소비하고 일부 (10/11/15/16/17 등) 는 nested paragraph list 를 읽는다.\n */\nfunction parseCharStream(reader: Reader, charCount: number, ctx: ParaContext, para: Hwp3Para): void {\n let i = 0\n while (i < charCount) {\n const ch = reader.readU16()\n i += 1\n\n if (ch === 13) {\n para.text += \"\\n\"\n continue\n }\n if (ch === 0) {\n // 일부 패딩/오류 케이스 — 무시\n continue\n }\n if (ch >= 32) {\n // 일반 hchar (ASCII < 0x80 영역도 u16 으로 들어옴).\n // 아래아 음절은 자모 2~3개가 되므로 문자열 단위로 받는다\n para.text += escapeLiteralDollar(decodeJohabText(ch) ?? \"\") // 리터럴 $ 는 \\$ — $…$ 는 수식 전용\n continue\n }\n if (ch === 9) {\n // 탭 — hunit 탭폭 + word 점끌기 + hchar 닫기. 점끌기(채움)가 있으면 목차 쪽번호 탭\n reader.skip(2)\n const leader = reader.readU16()\n reader.skip(2)\n i += 3\n para.text += leader ? LEADER_TAB_MARK : \"\\t\"\n continue\n }\n if (ch === 18) {\n // 자동 번호 — 종류(u16: 0 쪽·1 각주·2 미주·3 그림·4 표·5 수식) + 번호(u16) + 닫기\n const info = reader.readBytes(6)\n i += 3\n para.text += autoNumberText(info.readUInt16LE(0), info.readUInt16LE(2), ctx)\n continue\n }\n if (ch === 28) {\n // 개요 번호 — 종류(u16: 1 = 번호) + 모양(u8) + 수준(u8) + 수준별 현재 번호 u16[7] + … (62 byte).\n // 번호 값이 파일에 저장돼 있다 (SO-SUEOP 실측 — 수준 2 \"(1)\"·\"(2)\" 가 [1,1,1]·[1,1,2])\n const info = reader.readBytes(62)\n i += 31\n if (info.readUInt16LE(0) === 1) {\n para.outline = { level: Math.min(info[3], 6), numbers: Array.from({ length: 7 }, (_, k) => info.readUInt16LE(4 + k * 2)) }\n }\n continue\n }\n\n // 1..31 (13 제외) 제어 문자\n const simple = SIMPLE_CTRL.get(ch)\n if (simple) {\n reader.skip(simple.extraBytes)\n i += simple.extraHchar\n if (simple.emit) para.text += simple.emit\n continue\n }\n\n // ch=5/6/7/8/10/11/14~17/29 + 예약(0~4/12/27): 8 byte 추가 헤더 + 종류별 추가 처리\n // 8 byte = u32 header_val1 + u16 ch2 + 2 byte (hchar 정렬)\n const headerVal1 = reader.readU32() // size 또는 type-specific\n reader.readU16() // ch2 (sanity, ch와 같아야 함)\n i += 3 // 8 byte 헤더는 char_count 에서 4 hchar 차지 (1 이미 + 3)\n\n // 종류별 분기\n switch (ch) {\n case 10:\n // 표 / 글상자 / 수식 / 버튼: 84 byte info + cells + caption\n parseTableLike(reader, ctx, para)\n break\n case 11:\n // 그림: 348 byte info + n_ext byte\n para.objects.push({ blocks: parsePicture(reader, ctx), table: false, inline: false })\n break\n case 14:\n // 선 (spec 표 31): 84 byte info\n reader.skip(84)\n break\n case 15: {\n // 숨은 설명: 8 byte info + nested paragraph list — 읽기만 하고 본문에 넣지 않는다\n // (HWP5 CTRL_TCMT·HWPX hiddenComment 와 같은 정책 — 한컴은 화면·인쇄에 그리지 않는다)\n reader.skip(8)\n const hidden: IRBlock[] = []\n parseParagraphList(reader, ctx, hidden)\n if (hidden.length > 0 && !ctx.warnings.some(w => w.code === \"HIDDEN_TEXT_FILTERED\")) {\n ctx.warnings.push({ code: \"HIDDEN_TEXT_FILTERED\", message: \"HWP3 숨은 설명 텍스트 본문 제외\" })\n }\n break\n }\n case 16: {\n // 머리말/꼬리말: 10 byte info(8 = 0 머리말·1 꼬리말) + nested\n const info = reader.readBytes(10)\n parseHeaderFooter(reader, ctx, info[8] === 1)\n break\n }\n case 17: {\n // 각주/미주: 14 byte info(8 = 번호, 10 = 1 미주) + nested\n const info = reader.readBytes(14)\n parseNote(reader, ctx, para, info.readUInt16LE(8), info.readUInt16LE(10) === 1 ? 1 : 0)\n break\n }\n case 5:\n // 필드 코드 (spec §10.1 표 33): 8 byte 헤더 + header_val1 byte 세부 정보\n // (rhwp dcf64b4 #877 정합 — 미소비 시 stream desync). 1MB 이상은 비정상.\n if (headerVal1 > 0 && headerVal1 < 1_000_000) reader.skip(headerVal1)\n break\n case 6:\n // 책갈피 (spec §10.2 표 36): 42 byte total = 8 byte 헤더 + 이름 32 + 종류 2\n // (rhwp dcf64b4 #877 정합 — 34 byte 미소비 시 이후 문단 전체 오염)\n reader.skip(34)\n break\n case 7:\n // 날짜 형식 (spec §10.3 표 37): 84 byte total = 8 byte 헤더 + 76\n // 2..82 hchar array[40] 형식 문자열, 82..84 닫는 ch=7\n // (rhwp #2844 정합 — 종전 simple 6 byte 처리는 76 byte desync 를 남겨\n // 날짜 필드 뒤 문단 전체를 오염시켰다. 공문서는 날짜가 거의 항상 들어간다.)\n reader.skip(76)\n break\n case 8:\n // 날짜 코드 (spec §10.4 표 38): 96 byte total = 8 byte 헤더 + 88\n // 2..82 형식, 82..90 날짜 word[4], 90..94 시각 word[2], 94..96 닫는 ch=8\n reader.skip(88)\n break\n case 29:\n // 상호참조: header_val1 size raw skip (1MB 이상 비정상)\n if (headerVal1 < 1_000_000) reader.skip(headerVal1)\n break\n default:\n // ch=0~4/12/27 등 예약 코드 (spec 표 31): rhwp 의 \"알 수 없음\" 분기에서\n // header_val1 을 길이로 사용하지 않는다고 명시 (\"ch=3 실증: 헤더 직후가 정상 단락\n // 내용이므로 추가 skip 없음\"). 즉 8 byte 헤더만 소비하고 다음 char 로.\n // (spec 표 32 는 예약 코드를 8+n byte 로 규정하지만, rhwp 실측이 이와 어긋나\n // 실증 쪽을 따른다. ch=12 는 '선' 이 아니라 예약 — 종전 84 byte skip 은\n // 선(14) 의 info 크기를 잘못 적용한 것이라 오히려 desync 를 만들었다.)\n // 경고는 첫 등장만 기록 — 본문에 페이지번호/필드코드가 많이 깔린 paragraph 가\n // 전형적인 케이스라 logging 폭주 방지.\n if (!ctx.warnings.some(w => w.code === \"UNSUPPORTED_ELEMENT\")) {\n ctx.warnings.push({\n code: \"UNSUPPORTED_ELEMENT\",\n message: `HWP3 부분 처리 제어 문자 ch=${ch} (이후 동일 코드 경고 생략)`,\n })\n }\n break\n }\n }\n para.text = para.text.trim()\n}\n\n/**\n * 자동 번호(ch=18) 표시 글자 — 각주·미주 번호는 \"N)\"(한컴 PDF 실측, 각주 내용 첫머리의 번호), 그림·표·수식\n * 번호는 저장된 번호(HWP5 CTRL_ATNO 가 번호를 내는 것과 같다). 쪽 번호는 조판 시점 값이라 내지 않는다\n */\nfunction autoNumberText(type: number, num: number, ctx: ParaContext): string {\n if (type === 0) {\n ctx.pageNumbers++\n return \"\"\n }\n if (num <= 0) return \" \"\n return type === 1 || type === 2 ? `${num})` : String(num)\n}\n\n/** 각주·미주 — 본문 자리에 마커 \"N)\", 내용은 \"N) 내용\" 으로 문단 footnoteText 에 (HWP5 applyNoteEffect 와 같은 모양) */\nfunction parseNote(reader: Reader, ctx: ParaContext, para: Hwp3Para, number: number, kind: 0 | 1): void {\n const blocks: IRBlock[] = []\n parseParagraphList(reader, ctx, blocks)\n const n = number > 0 ? number : ++ctx.noteSeq[kind]\n const marker = `${n})`\n para.text += marker\n const content = blocksPlainText(blocks, \" \")\n if (content) para.footnotes.push(content.startsWith(marker) ? content : `${marker} ${content}`)\n}\n\n/** 머리말·꼬리말 — 문서당 1회(같은 글 중복 제거), 쪽 번호뿐인 머리말은 크롬이라 버린다 (HWPX 와 같은 정책) */\nfunction parseHeaderFooter(reader: Reader, ctx: ParaContext, isFooter: boolean): void {\n const pagesBefore = ctx.pageNumbers\n const blocks: IRBlock[] = []\n parseParagraphList(reader, ctx, blocks)\n const text = blocksPlainText(blocks, \"\\n\")\n if (!text) return\n if (ctx.pageNumbers > pagesBefore && !/\\p{L}/u.test(text)) return\n const key = (isFooter ? \"f:\" : \"h:\") + text\n if (ctx.headerTexts.has(key)) return\n ctx.headerTexts.add(key)\n ;(isFooter ? ctx.footerBlocks : ctx.headerBlocks).push({ type: \"paragraph\", text })\n}\n\n/**\n * ch=10 표/글상자/수식/버튼 — 84 byte 정보 → 셀 정보 27 byte × n → 셀별 문단 리스트 → 캡션 문단 리스트.\n * 수식(개체 종류 2)은 첫 셀 글이 수식 스크립트 → 본문 자리에 $LaTeX$. 나머지는 셀 기하로 복원한 표 —\n * 한컴 HWP3→HWPX 변환본도 글상자·단추를 1×1 표로 낸다(SO-SUEOP 실측 3개). 글자처럼 취급(기준 위치 0)이면\n * 문단 글 흐름 안의 자리에 표지를 심는다\n */\nfunction parseTableLike(reader: Reader, ctx: ParaContext, para: Hwp3Para): void {\n // 84 byte info_buf\n const info = reader.readBytes(84)\n const cellCount = info.readUInt16LE(80) || 1\n // 방어: 셀 정보(27 byte × n)가 잔여 스트림보다 크면 손상된 헤더로 간주.\n // 종전의 고정 상한 256 은 실존 문서를 죽였다 — rhwp samples/hwp3-sample16 에\n // 367 셀 표가 실재한다 (rhwp 는 개수 상한 없이 버퍼 크기 캡만 둔다).\n if (27 * cellCount > reader.remaining()) {\n ctx.warnings.push({\n code: \"PARTIAL_PARSE\",\n message: `HWP3 표 cell_count=${cellCount} 비정상 — 표 본문 추출 포기`,\n })\n throw new Error(`HWP3 비정상 cell_count=${cellCount}`)\n }\n const cellInfo = reader.readBytes(27 * cellCount)\n\n // 셀별 문단 리스트 — 스트림이 셀 도중에 깨져도 읽은 셀 글은 표 밖 문단으로 남긴다\n const cellBlocks: IRBlock[][] = []\n try {\n for (let i = 0; i < cellCount; i++) {\n const blocks: IRBlock[] = []\n cellBlocks.push(blocks)\n parseParagraphList(reader, ctx, blocks)\n }\n } catch (err) {\n para.objects.push({ blocks: cellBlocks.flat(), table: false, inline: false })\n throw err\n }\n // 캡션 paragraph list 1회\n const captionBlocks: IRBlock[] = []\n parseParagraphList(reader, ctx, captionBlocks)\n const caption = blocksPlainText(captionBlocks, \" \")\n\n if (info.readUInt16LE(78) === OBJ_EQUATION) {\n const script = (cellBlocks[0] ?? []).map(b => b.text ?? \"\").join(\"\\n\").trim()\n const latex = script ? hwpEquationToLatex(script) : \"\"\n if (latex) para.text += `$${latex.replace(/\\$/g, \"\\\\$\")}$`\n if (caption) para.objects.push({ blocks: [{ type: \"paragraph\", text: caption }], table: false, inline: false })\n return\n }\n if (info.readUInt16LE(14) & OPT_HYPERTEXT) {\n // 하이퍼텍스트 개체(기타 옵션 bit 4) — 표가 아니라 연결 글자다(rhwp Hyperlink, 한컴 변환본에도 표 없음 —\n // sample16 단추 4개). 셀 글을 그 자리 본문으로\n para.text += blocksPlainText(cellBlocks.flat(), \" \")\n if (caption) para.objects.push({ blocks: [{ type: \"paragraph\", text: caption }], table: false, inline: false })\n return\n }\n\n const grid = hwp3CellGrid(cellInfo, cellCount)\n const cells: AddressedCell[] = cellBlocks.map((blocks, k) => {\n const pos = grid.cells[k]\n const { text, hasStructure } = cellTextFromBlocks(blocks)\n const cell: AddressedCell = { text, colSpan: pos.colSpan, rowSpan: pos.rowSpan, colAddr: pos.col, rowAddr: pos.row }\n if (hasStructure && blocks.length > 0) cell.blocks = blocks\n return cell\n })\n // 셀 스트림은 시각 배치 순서라 병합 행에서 행 우선이 깨질 수 있다 — 행 우선으로 (겹침 정리의 \"먼저 나온 셀\")\n cells.sort((a, b) => a.rowAddr! - b.rowAddr! || a.colAddr! - b.colAddr!)\n const table = buildAddressedTable(cells, grid.rows, grid.cols)\n if (!table) {\n // 표를 못 세우면 셀 글을 문단으로 — 글 손실 금지\n para.objects.push({ blocks: [...cellBlocks.flat(), ...captionBlocks], table: false, inline: false })\n return\n }\n if (caption) table.caption = caption\n const inline = info[8] === 0\n if (inline) para.text += INLINE_TABLE_MARK\n para.objects.push({ blocks: [{ type: \"table\", table }], table: true, inline })\n}\n\n/**\n * ch=11 그림 — info 348 byte + n_ext bytes (info[0..4] 가 n_ext) + 캡션 paragraph list.\n *\n * spec §10.7 그림: 식별 정보(8) → 그림 정보(348+n) → **캡션 문단 리스트**.\n * 캡션이 없어도 빈 문단 sentinel(43 byte)이 항상 뒤따른다 (rhwp 의 ch==11 분기도\n * pic_type 과 무관하게 무조건 캡션 리스트를 파싱한다 — 표(ch=10)와 같은 계약).\n *\n * 종전엔 이 리스트를 소비하지 않아 그림 하나당 최소 43 byte 가 어긋났고, 어긋난\n * 자리가 char_count=0 으로 읽히면 문단 리스트가 \"정상 종료\"로 판정돼 **경고 없이**\n * 본문 나머지를 통째로 버렸다 (rhwp samples/hwp3-sample10: 본문 4MB 중 99.7% 유실).\n *\n * `pic_type`(info[74])이 3 이면 확장 블록은 그림이 아니라 **그리기 개체 트리**다 (#73).\n * 글상자·캡션 글은 그림 뒤 문단 블록으로 돌려준다.\n */\nfunction parsePicture(reader: Reader, ctx: ParaContext): IRBlock[] {\n const info = reader.readBytes(348)\n const nExt = info.readUInt32LE(0)\n let ext: Buffer | null = null\n if (nExt > 0 && nExt < 100 * 1024 * 1024) ext = reader.readBytes(nExt)\n const blocks: IRBlock[] = []\n if (ext && info[74] === PIC_TYPE_DRAWING) parseDrawingObject(ext, ctx, blocks)\n parseParagraphList(reader, ctx, blocks)\n return blocks\n}\n\n/**\n * 그리기 개체 트리 안 글상자 텍스트를 회수한다 (#73).\n *\n * 본 스트림은 이미 확장 블록 길이만큼 전진했고 여기서는 그 **슬라이스만** 다루므로,\n * 트리 해석이 어긋나도 본문 문단 스트림의 동기는 깨지지 않는다. 그래서 실패는\n * 경고 한 줄로 삼키고 종전(통째로 건너뛰기) 동작으로 되돌아간다.\n */\nfunction parseDrawingObject(ext: Buffer, ctx: ParaContext, sink: IRBlock[]): void {\n let lists: Buffer[]\n try {\n lists = collectDrawingTextBoxLists(ext)\n } catch (err) {\n pushDrawingWarning(ctx, `HWP3 그리기 개체 트리 파싱 실패 — 글상자 텍스트 생략: ${errText(err)}`)\n return\n }\n for (const list of lists) {\n try {\n parseParagraphList(new Reader(list), ctx, sink)\n } catch (err) {\n pushDrawingWarning(ctx, `HWP3 글상자 문단 리스트 파싱 실패: ${errText(err)}`)\n }\n }\n}\n\n/** 그리기 개체 경고는 문서당 한 번만 — 도형이 많은 문서에서 경고가 폭주한다. */\nfunction pushDrawingWarning(ctx: ParaContext, message: string): void {\n if (ctx.warnings.some(w => w.code === \"UNSUPPORTED_ELEMENT\" && w.message.startsWith(\"HWP3 그리기\"))) return\n ctx.warnings.push({ code: \"UNSUPPORTED_ELEMENT\", message })\n}\n\nfunction errText(err: unknown): string {\n return err instanceof Error ? err.message : String(err)\n}\n","/**\n * HWP3 binary stream reader.\n * Buffer 기반 cursor 로 little-endian primitive 를 순차 read 한다.\n * 부족한 데이터에선 InsufficientData 를 throw 해서 상위 try/catch 가 partial-parse 모드로 전환할 수 있게 한다.\n */\n\nexport class InsufficientDataError extends Error {\n constructor(public requested: number, public available: number) {\n super(`HWP3: insufficient data (need ${requested}, have ${available})`)\n this.name = \"InsufficientDataError\"\n }\n}\n\nexport class Reader {\n private pos: number\n\n constructor(private readonly buf: Buffer, start = 0) {\n this.pos = start\n }\n\n position(): number {\n return this.pos\n }\n\n remaining(): number {\n return this.buf.length - this.pos\n }\n\n /** 버퍼 전체 길이. 선언 길이가 스트림 안인지 판정하는 데 쓴다. */\n length(): number {\n return this.buf.length\n }\n\n /** 절대 위치로 이동 (버퍼 밖이면 InsufficientData). */\n seek(pos: number): void {\n if (pos < 0 || pos > this.buf.length) {\n throw new InsufficientDataError(pos, this.buf.length)\n }\n this.pos = pos\n }\n\n eof(): boolean {\n return this.pos >= this.buf.length\n }\n\n skip(n: number): void {\n this.ensure(n)\n this.pos += n\n }\n\n private ensure(n: number) {\n if (this.pos + n > this.buf.length) {\n throw new InsufficientDataError(n, this.buf.length - this.pos)\n }\n }\n\n readU8(): number {\n this.ensure(1)\n const v = this.buf[this.pos]\n this.pos += 1\n return v\n }\n\n readU16(): number {\n this.ensure(2)\n const v = this.buf.readUInt16LE(this.pos)\n this.pos += 2\n return v\n }\n\n readU32(): number {\n this.ensure(4)\n const v = this.buf.readUInt32LE(this.pos)\n this.pos += 4\n return v\n }\n\n readBytes(n: number): Buffer {\n this.ensure(n)\n const slice = this.buf.subarray(this.pos, this.pos + n)\n this.pos += n\n return slice\n }\n\n /** 남은 모든 바이트를 새 Buffer 로 반환 (커서를 끝으로 이동). */\n readToEnd(): Buffer {\n const slice = this.buf.subarray(this.pos)\n this.pos = this.buf.length\n return slice\n }\n}\n","/**\n * HWP3 그리기 개체 트리 — **글상자 텍스트 회수 전용** 워커.\n *\n * ch=11(그림) 제어 문자의 확장 블록(`n_ext` 바이트)은 `pic_type`(info[74])이 3 이면\n * 그림이 아니라 **그리기 개체 트리**다. 표지 제목·순서도 라벨처럼 눈에 잘 띄는 본문이\n * 이 안 글상자에 들어간다. 종전에는 이 블록을 통째로 건너뛰어 그 텍스트가 통째로\n * 사라졌다 (hwp3-sample16 실측 618자, #73).\n *\n * 트리는 프레임 헤더 뒤에 도형 레코드가 이어지고, 각 레코드의 `connection_info`\n * bit0=형제·bit1=자식으로 연결된다. 여기서는 **소비할 바이트 수 계산에 필요한 만큼만**\n * 읽고 기하·채우기 속성은 버린다 — 목적이 텍스트 추출이라서다.\n *\n * 호출자는 이 함수를 `n_ext` 슬라이스에만 적용한다. 본 스트림은 이미 그 길이만큼\n * 전진했으므로, 여기서 어떤 실패가 나도 **본문 스트림 동기는 깨지지 않는다.**\n *\n * 출처: rhwp/src/parser/hwp3/drawing.rs (MIT). 구조 정의와 표 78 회수 규칙 동일.\n */\n\nimport { Reader } from \"./reader.js\"\n\n/** 자식 체인 재귀 상한. `has_child` 는 파일에서 온 값이라 상한이 없으면 중첩 컨테이너\n * 하나로 스택을 고갈시킬 수 있다 (rhwp #4285 — 최소 92바이트 레코드로 수만 겹 가능). */\nconst MAX_DEPTH = 256\n/** 도형 개수 상한 — 형제 체인이 손상된 파일에서 무한히 도는 것을 막는다. */\nconst MAX_OBJECTS = 4096\n/** 선언 길이와 플래그 유도 소비량이 어긋날 때 전진을 허용하는 상한 (rhwp #5141). */\nconst MAX_HEADER_SKIP = 64 * 1024\n/** 프레임 헤더 고정부: z_order(4) + object_count(4) + bounds(16). 선언이 이보다 크면\n * 하이퍼텍스트 정보가 뒤따른다. */\nconst FRAME_FIXED_LENGTH = 24\n/** 하이퍼텍스트 정보 = 길이(4) + 파일명 256 + 책갈피 32 + 매크로 325 + 종류 1 + 예약 3.\n * 책갈피는 hchar array[16] = 32바이트다 — 16으로 읽으면 이후 전체가 밀린다 (rhwp #2831). */\nconst HYPERTEXT_INFO_SIZE = 621\n/** 공통 헤더 basic_attr 중 options 앞까지: line_style~pattern_color(8×4) + textbox_margin(2×4) */\nconst BASIC_ATTR_BEFORE_OPTIONS = 40\n/** 공통 헤더에서 object_type/connection_info 뒤 좌표부: relative_pos+object_size+absolute_pos+bounds */\nconst HEADER_GEOMETRY = 40\n\nconst OPT_GRADIENT = 1 << 16\nconst OPT_ROTATION = 1 << 17\nconst OPT_BITMAP_PATTERN = 1 << 18\n\nconst TYPE_CONTAINER = 0\nconst TYPE_TEXTBOX = 6\n\n/**\n * 그리기 개체 트리를 훑어 글상자 문단 리스트 조각들을 순서대로 모은다.\n * 각 조각은 본문과 같은 형식의 paragraph list 바이트라 호출자가 그대로 파싱하면 된다.\n */\nexport function collectDrawingTextBoxLists(ext: Buffer): Buffer[] {\n const reader = new Reader(ext)\n const out: Buffer[] = []\n\n // 프레임 헤더 — 선언 길이가 고정부보다 크면 하이퍼텍스트 정보가 붙어 있다.\n const frameHeaderLength = reader.readU32()\n reader.skip(4) // z_order\n const objectCount = reader.readU32()\n reader.skip(16) // bounds\n if (frameHeaderLength > FRAME_FIXED_LENGTH) reader.skip(HYPERTEXT_INFO_SIZE)\n // 개체가 0 이면 트리가 없다 — 뒤 바이트를 도형으로 읽으면 쓰레기가 나온다 (rhwp 도 여기서 멈춘다)\n if (objectCount === 0) return []\n\n const budget = { objects: MAX_OBJECTS }\n walkShapeList(reader, out, 0, budget)\n return out\n}\n\n/** 형제 체인을 따라가며 자식이 있으면 내려간다 (rhwp parse_shape_list). */\nfunction walkShapeList(reader: Reader, out: Buffer[], depth: number, budget: { objects: number }): void {\n if (depth > MAX_DEPTH) throw new Error(`HWP3 그리기 개체 중첩이 ${MAX_DEPTH} 단계를 넘음`)\n for (;;) {\n if (budget.objects-- <= 0) throw new Error(`HWP3 그리기 개체가 ${MAX_OBJECTS}개를 넘음`)\n const connectionInfo = readObject(reader, out)\n if ((connectionInfo & 0x02) !== 0) walkShapeList(reader, out, depth + 1, budget)\n if ((connectionInfo & 0x01) === 0) return\n }\n}\n\n/** 도형 레코드 하나를 소비하고 connection_info 를 돌려준다. 글상자 문단 리스트는 out 에 모은다. */\nfunction readObject(reader: Reader, out: Buffer[]): number {\n const headerStart = reader.position()\n const headerLength = reader.readU32()\n const objectType = reader.readU16()\n const connectionInfo = reader.readU16()\n reader.skip(HEADER_GEOMETRY)\n reader.skip(BASIC_ATTR_BEFORE_OPTIONS)\n const options = reader.readU32()\n if (options & OPT_ROTATION) reader.skip(32) // center(2×4) + 평행사변형(6×4)\n if (options & OPT_GRADIENT) reader.skip(28) // 7×4\n if (options & OPT_BITMAP_PATTERN) reader.skip(278) // 좌표(4×4) + 파일명 261 + 옵션 1\n\n // [rhwp #5141/#5558] 빈티지 파일의 공통 헤더에는 이 파서가 모르는 확장 필드가 붙을 수\n // 있고 전체 길이는 header_length(자기 4바이트 제외)로 선언된다. 그 잉여 구간의 실체는\n // 대부분 스펙 11.3 의 optional 글상자 정보(표 78: [정보1 길이][정보2 길이][문단 리스트])라,\n // 잉여 길이가 표 78 과 정확히 맞아떨어지면 문단 리스트를 회수하고 아니면 건너뛴다.\n // 글상자(type 6)는 세부 정보 경로가 같은 구조를 읽으므로 제외한다.\n const consumedEnd = reader.position()\n const declaredEnd = headerStart + 4 + headerLength\n if (declaredEnd > consumedEnd && declaredEnd - consumedEnd <= MAX_HEADER_SKIP && declaredEnd <= reader.length()) {\n const surplus = declaredEnd - consumedEnd\n let recovered = false\n if (objectType !== TYPE_TEXTBOX && surplus >= 8) {\n const info1Len = reader.readU32()\n const info2Len = reader.readU32()\n if (info1Len + info2Len === surplus - 8 && info2Len > 0) {\n reader.skip(info1Len)\n out.push(reader.readBytes(info2Len))\n recovered = true\n }\n }\n if (!recovered) reader.seek(declaredEnd)\n }\n\n switch (objectType) {\n case TYPE_CONTAINER:\n case 2: // 사각형\n case 3: // 타원\n // 세부 정보가 없어도 길이 8바이트(정보1·정보2 = 0)가 자리를 차지한다.\n // 컨테이너에서 이를 빠뜨리면 첫 자식이 8바이트 밀려 묶음 전체가 소실된다 (rhwp #5141).\n reader.skip(8)\n break\n case 1: // 선\n case 4: // 호\n reader.skip(12)\n break\n case 5: // 다각형\n case 7: // 곡선\n skipPoints(reader, false)\n break\n case TYPE_TEXTBOX: {\n reader.skip(4) // 정보1 길이 — rhwp 도 내용을 소비하지 않는다\n const info2Len = reader.readU32()\n if (info2Len > 0) out.push(reader.readBytes(info2Len))\n break\n }\n case 8: // 수정된 타원\n reader.skip(24) // 정보1 길이 + 호 bounds(4×4) + 정보2 길이\n break\n case 9: // 수정된 호 — 회전 속성만으로 그리므로 세부 정보가 없다\n break\n case 10: // 확장된 곡선\n case 11: // 닫힌 다각형\n skipPoints(reader, true)\n break\n default: {\n const info1Len = reader.readU32()\n reader.skip(info1Len)\n const info2Len = reader.readU32()\n reader.skip(info2Len)\n break\n }\n }\n return connectionInfo\n}\n\n/** 점 배열을 가진 도형의 세부 정보를 소비한다. withLineAttrs 면 점마다 1바이트 속성이 뒤따른다. */\nfunction skipPoints(reader: Reader, withLineAttrs: boolean): void {\n reader.skip(4) // 정보1 길이\n const pointCount = reader.readU32()\n reader.skip(4) // 정보2 길이\n const bytes = pointCount * 8 + (withLineAttrs ? pointCount : 0)\n // 손상된 개수로 거대 skip 을 시도하지 않는다 — Reader 가 던지긴 하지만 의도를 남긴다.\n if (bytes > reader.remaining()) throw new Error(`HWP3 그리기 개체 점 개수 비정상 (${pointCount})`)\n reader.skip(bytes)\n}\n","// Auto-generated from rhwp/src/parser/hwp3/johab_map.rs — DO NOT EDIT.\n// Pairs of (johab-code, unicode-codepoint), sorted by key for binary search.\n// Total entries: 5893\n\nexport const JOHAB_SYMBOLS: ReadonlyArray<number> = Object.freeze([\n 0x8441,0x3000, 0x8442,0x3131, 0x8443,0x3132, 0x8444,0x3133, 0x8445,0x3134, 0x8446,0x3135, 0x8447,0x3136, 0x8448,0x3137,\n 0x8449,0x3139, 0x844A,0x313A, 0x844B,0x313B, 0x844C,0x313C, 0x844D,0x313D, 0x844E,0x313E, 0x844F,0x313F, 0x8450,0x3140,\n 0x8451,0x3141, 0x8453,0x3142, 0x8454,0x3144, 0x8455,0x3145, 0x8456,0x3146, 0x8457,0x3147, 0x8458,0x3148, 0x8459,0x314A,\n 0x845A,0x314B, 0x845B,0x314C, 0x845C,0x314D, 0x845D,0x314E, 0x8461,0x314F, 0x8481,0x3150, 0x84A1,0x3151, 0x84C1,0x3152,\n 0x84E1,0x3153, 0x8541,0x3154, 0x8561,0x3155, 0x8581,0x3156, 0x85A1,0x3157, 0x85C1,0x3158, 0x85E1,0x3159, 0x8641,0x315A,\n 0x8661,0x315B, 0x8681,0x315C, 0x86A1,0x315D, 0x86C1,0x315E, 0x86E1,0x315F, 0x8741,0x3160, 0x8761,0x3161, 0x8781,0x3162,\n 0x87A1,0x3163, 0x8841,0x3131, 0x8C41,0x3132, 0x9041,0x3134, 0x9441,0x3137, 0x9841,0x3138, 0x9C41,0x3139, 0xA041,0x3141,\n 0xA441,0x3142, 0xA841,0x3143, 0xAC41,0x3145, 0xB041,0x3146, 0xB441,0x3147, 0xB841,0x3148, 0xBC41,0x3149, 0xC041,0x314A,\n 0xC441,0x314B, 0xC841,0x314C, 0xCC41,0x314D, 0xD041,0x314E, 0xD931,0x3000, 0xD932,0x3001, 0xD933,0x3002, 0xD934,0x00B7,\n 0xD935,0x2025, 0xD936,0x2026, 0xD937,0x00A8, 0xD938,0x3003, 0xD939,0x00AD, 0xD93A,0x2015, 0xD93B,0x2225, 0xD93C,0xFF3C,\n 0xD93D,0x223C, 0xD93E,0x2018, 0xD93F,0x2019, 0xD940,0x201C, 0xD941,0x201D, 0xD942,0x3014, 0xD943,0x3015, 0xD944,0x3008,\n 0xD945,0x3009, 0xD946,0x300A, 0xD947,0x300B, 0xD948,0x300C, 0xD949,0x300D, 0xD94A,0x300E, 0xD94B,0x300F, 0xD94C,0x3010,\n 0xD94D,0x3011, 0xD94E,0x00B1, 0xD94F,0x00D7, 0xD950,0x00F7, 0xD951,0x2260, 0xD952,0x2264, 0xD953,0x2265, 0xD954,0x221E,\n 0xD955,0x2234, 0xD956,0x00B0, 0xD957,0x2032, 0xD958,0x2033, 0xD959,0x2103, 0xD95A,0x212B, 0xD95B,0xFFE0, 0xD95C,0xFFE1,\n 0xD95D,0xFFE5, 0xD95E,0x2642, 0xD95F,0x2640, 0xD960,0x2220, 0xD961,0x22A5, 0xD962,0x2312, 0xD963,0x2202, 0xD964,0x2207,\n 0xD965,0x2261, 0xD966,0x2252, 0xD967,0x00A7, 0xD968,0x203B, 0xD969,0x2606, 0xD96A,0x2605, 0xD96B,0x25CB, 0xD96C,0x25CF,\n 0xD96D,0x25CE, 0xD96E,0x25C7, 0xD96F,0x25C6, 0xD970,0x25A1, 0xD971,0x25A0, 0xD972,0x25B3, 0xD973,0x25B2, 0xD974,0x25BD,\n 0xD975,0x25BC, 0xD976,0x2192, 0xD977,0x2190, 0xD978,0x2191, 0xD979,0x2193, 0xD97A,0x2194, 0xD97B,0x3013, 0xD97C,0x226A,\n 0xD97D,0x226B, 0xD97E,0x221A, 0xD991,0x223D, 0xD992,0x221D, 0xD993,0x2235, 0xD994,0x222B, 0xD995,0x222C, 0xD996,0x2208,\n 0xD997,0x220B, 0xD998,0x2286, 0xD999,0x2287, 0xD99A,0x2282, 0xD99B,0x2283, 0xD99C,0x222A, 0xD99D,0x2229, 0xD99E,0x2227,\n 0xD99F,0x2228, 0xD9A0,0xFFE2, 0xD9A1,0x21D2, 0xD9A2,0x21D4, 0xD9A3,0x2200, 0xD9A4,0x2203, 0xD9A5,0x00B4, 0xD9A6,0xFF5E,\n 0xD9A7,0x02C7, 0xD9A8,0x02D8, 0xD9A9,0x02DD, 0xD9AA,0x02DA, 0xD9AB,0x02D9, 0xD9AC,0x00B8, 0xD9AD,0x02DB, 0xD9AE,0x00A1,\n 0xD9AF,0x00BF, 0xD9B0,0x02D0, 0xD9B1,0x222E, 0xD9B2,0x2211, 0xD9B3,0x220F, 0xD9B4,0x00A4, 0xD9B5,0x2109, 0xD9B6,0x2030,\n 0xD9B7,0x25C1, 0xD9B8,0x25C0, 0xD9B9,0x25B7, 0xD9BA,0x25B6, 0xD9BB,0x2664, 0xD9BC,0x2660, 0xD9BD,0x2661, 0xD9BE,0x2665,\n 0xD9BF,0x2667, 0xD9C0,0x2663, 0xD9C1,0x2299, 0xD9C2,0x25C8, 0xD9C3,0x25A3, 0xD9C4,0x25D0, 0xD9C5,0x25D1, 0xD9C6,0x2592,\n 0xD9C7,0x25A4, 0xD9C8,0x25A5, 0xD9C9,0x25A8, 0xD9CA,0x25A7, 0xD9CB,0x25A6, 0xD9CC,0x25A9, 0xD9CD,0x2668, 0xD9CE,0x260F,\n 0xD9CF,0x260E, 0xD9D0,0x261C, 0xD9D1,0x261E, 0xD9D2,0x00B6, 0xD9D3,0x2020, 0xD9D4,0x2021, 0xD9D5,0x2195, 0xD9D6,0x2197,\n 0xD9D7,0x2199, 0xD9D8,0x2196, 0xD9D9,0x2198, 0xD9DA,0x266D, 0xD9DB,0x2669, 0xD9DC,0x266A, 0xD9DD,0x266C, 0xD9DE,0x327F,\n 0xD9DF,0x321C, 0xD9E0,0x2116, 0xD9E1,0x33C7, 0xD9E2,0x2122, 0xD9E3,0x33C2, 0xD9E4,0x33D8, 0xD9E5,0x2121, 0xD9E6,0x20AC,\n 0xD9E7,0x00AE, 0xDA31,0xFF01, 0xDA32,0xFF02, 0xDA33,0xFF03, 0xDA34,0xFF04, 0xDA35,0xFF05, 0xDA36,0xFF06, 0xDA37,0xFF07,\n 0xDA38,0xFF08, 0xDA39,0xFF09, 0xDA3A,0xFF0A, 0xDA3B,0xFF0B, 0xDA3C,0xFF0C, 0xDA3D,0xFF0D, 0xDA3E,0xFF0E, 0xDA3F,0xFF0F,\n 0xDA40,0xFF10, 0xDA41,0xFF11, 0xDA42,0xFF12, 0xDA43,0xFF13, 0xDA44,0xFF14, 0xDA45,0xFF15, 0xDA46,0xFF16, 0xDA47,0xFF17,\n 0xDA48,0xFF18, 0xDA49,0xFF19, 0xDA4A,0xFF1A, 0xDA4B,0xFF1B, 0xDA4C,0xFF1C, 0xDA4D,0xFF1D, 0xDA4E,0xFF1E, 0xDA4F,0xFF1F,\n 0xDA50,0xFF20, 0xDA51,0xFF21, 0xDA52,0xFF22, 0xDA53,0xFF23, 0xDA54,0xFF24, 0xDA55,0xFF25, 0xDA56,0xFF26, 0xDA57,0xFF27,\n 0xDA58,0xFF28, 0xDA59,0xFF29, 0xDA5A,0xFF2A, 0xDA5B,0xFF2B, 0xDA5C,0xFF2C, 0xDA5D,0xFF2D, 0xDA5E,0xFF2E, 0xDA5F,0xFF2F,\n 0xDA60,0xFF30, 0xDA61,0xFF31, 0xDA62,0xFF32, 0xDA63,0xFF33, 0xDA64,0xFF34, 0xDA65,0xFF35, 0xDA66,0xFF36, 0xDA67,0xFF37,\n 0xDA68,0xFF38, 0xDA69,0xFF39, 0xDA6A,0xFF3A, 0xDA6B,0xFF3B, 0xDA6C,0xFFE6, 0xDA6D,0xFF3D, 0xDA6E,0xFF3E, 0xDA6F,0xFF3F,\n 0xDA70,0xFF40, 0xDA71,0xFF41, 0xDA72,0xFF42, 0xDA73,0xFF43, 0xDA74,0xFF44, 0xDA75,0xFF45, 0xDA76,0xFF46, 0xDA77,0xFF47,\n 0xDA78,0xFF48, 0xDA79,0xFF49, 0xDA7A,0xFF4A, 0xDA7B,0xFF4B, 0xDA7C,0xFF4C, 0xDA7D,0xFF4D, 0xDA7E,0xFF4E, 0xDA91,0xFF4F,\n 0xDA92,0xFF50, 0xDA93,0xFF51, 0xDA94,0xFF52, 0xDA95,0xFF53, 0xDA96,0xFF54, 0xDA97,0xFF55, 0xDA98,0xFF56, 0xDA99,0xFF57,\n 0xDA9A,0xFF58, 0xDA9B,0xFF59, 0xDA9C,0xFF5A, 0xDA9D,0xFF5B, 0xDA9E,0xFF5C, 0xDA9F,0xFF5D, 0xDAA0,0xFFE3, 0xDAD4,0x3164,\n 0xDAD5,0x3165, 0xDAD6,0x3166, 0xDAD7,0x3167, 0xDAD8,0x3168, 0xDAD9,0x3169, 0xDADA,0x316A, 0xDADB,0x316B, 0xDADC,0x316C,\n 0xDADD,0x316D, 0xDADE,0x316E, 0xDADF,0x316F, 0xDAE0,0x3170, 0xDAE1,0x3171, 0xDAE2,0x3172, 0xDAE3,0x3173, 0xDAE4,0x3174,\n 0xDAE5,0x3175, 0xDAE6,0x3176, 0xDAE7,0x3177, 0xDAE8,0x3178, 0xDAE9,0x3179, 0xDAEA,0x317A, 0xDAEB,0x317B, 0xDAEC,0x317C,\n 0xDAED,0x317D, 0xDAEE,0x317E, 0xDAEF,0x317F, 0xDAF0,0x3180, 0xDAF1,0x3181, 0xDAF2,0x3182, 0xDAF3,0x3183, 0xDAF4,0x3184,\n 0xDAF5,0x3185, 0xDAF6,0x3186, 0xDAF7,0x3187, 0xDAF8,0x3188, 0xDAF9,0x3189, 0xDAFA,0x318A, 0xDAFB,0x318B, 0xDAFC,0x318C,\n 0xDAFD,0x318D, 0xDAFE,0x318E, 0xDB31,0x2170, 0xDB32,0x2171, 0xDB33,0x2172, 0xDB34,0x2173, 0xDB35,0x2174, 0xDB36,0x2175,\n 0xDB37,0x2176, 0xDB38,0x2177, 0xDB39,0x2178, 0xDB3A,0x2179, 0xDB40,0x2160, 0xDB41,0x2161, 0xDB42,0x2162, 0xDB43,0x2163,\n 0xDB44,0x2164, 0xDB45,0x2165, 0xDB46,0x2166, 0xDB47,0x2167, 0xDB48,0x2168, 0xDB49,0x2169, 0xDB51,0x0391, 0xDB52,0x0392,\n 0xDB53,0x0393, 0xDB54,0x0394, 0xDB55,0x0395, 0xDB56,0x0396, 0xDB57,0x0397, 0xDB58,0x0398, 0xDB59,0x0399, 0xDB5A,0x039A,\n 0xDB5B,0x039B, 0xDB5C,0x039C, 0xDB5D,0x039D, 0xDB5E,0x039E, 0xDB5F,0x039F, 0xDB60,0x03A0, 0xDB61,0x03A1, 0xDB62,0x03A3,\n 0xDB63,0x03A4, 0xDB64,0x03A5, 0xDB65,0x03A6, 0xDB66,0x03A7, 0xDB67,0x03A8, 0xDB68,0x03A9, 0xDB71,0x03B1, 0xDB72,0x03B2,\n 0xDB73,0x03B3, 0xDB74,0x03B4, 0xDB75,0x03B5, 0xDB76,0x03B6, 0xDB77,0x03B7, 0xDB78,0x03B8, 0xDB79,0x03B9, 0xDB7A,0x03BA,\n 0xDB7B,0x03BB, 0xDB7C,0x03BC, 0xDB7D,0x03BD, 0xDB7E,0x03BE, 0xDB91,0x03BF, 0xDB92,0x03C0, 0xDB93,0x03C1, 0xDB94,0x03C3,\n 0xDB95,0x03C4, 0xDB96,0x03C5, 0xDB97,0x03C6, 0xDB98,0x03C7, 0xDB99,0x03C8, 0xDB9A,0x03C9, 0xDBA1,0x2500, 0xDBA2,0x2502,\n 0xDBA3,0x250C, 0xDBA4,0x2510, 0xDBA5,0x2518, 0xDBA6,0x2514, 0xDBA7,0x251C, 0xDBA8,0x252C, 0xDBA9,0x2524, 0xDBAA,0x2534,\n 0xDBAB,0x253C, 0xDBAC,0x2501, 0xDBAD,0x2503, 0xDBAE,0x250F, 0xDBAF,0x2513, 0xDBB0,0x251B, 0xDBB1,0x2517, 0xDBB2,0x2523,\n 0xDBB3,0x2533, 0xDBB4,0x252B, 0xDBB5,0x253B, 0xDBB6,0x254B, 0xDBB7,0x2520, 0xDBB8,0x252F, 0xDBB9,0x2528, 0xDBBA,0x2537,\n 0xDBBB,0x253F, 0xDBBC,0x251D, 0xDBBD,0x2530, 0xDBBE,0x2525, 0xDBBF,0x2538, 0xDBC0,0x2542, 0xDBC1,0x2512, 0xDBC2,0x2511,\n 0xDBC3,0x251A, 0xDBC4,0x2519, 0xDBC5,0x2516, 0xDBC6,0x2515, 0xDBC7,0x250E, 0xDBC8,0x250D, 0xDBC9,0x251E, 0xDBCA,0x251F,\n 0xDBCB,0x2521, 0xDBCC,0x2522, 0xDBCD,0x2526, 0xDBCE,0x2527, 0xDBCF,0x2529, 0xDBD0,0x252A, 0xDBD1,0x252D, 0xDBD2,0x252E,\n 0xDBD3,0x2531, 0xDBD4,0x2532, 0xDBD5,0x2535, 0xDBD6,0x2536, 0xDBD7,0x2539, 0xDBD8,0x253A, 0xDBD9,0x253D, 0xDBDA,0x253E,\n 0xDBDB,0x2540, 0xDBDC,0x2541, 0xDBDD,0x2543, 0xDBDE,0x2544, 0xDBDF,0x2545, 0xDBE0,0x2546, 0xDBE1,0x2547, 0xDBE2,0x2548,\n 0xDBE3,0x2549, 0xDBE4,0x254A, 0xDC31,0x3395, 0xDC32,0x3396, 0xDC33,0x3397, 0xDC34,0x2113, 0xDC35,0x3398, 0xDC36,0x33C4,\n 0xDC37,0x33A3, 0xDC38,0x33A4, 0xDC39,0x33A5, 0xDC3A,0x33A6, 0xDC3B,0x3399, 0xDC3C,0x339A, 0xDC3D,0x339B, 0xDC3E,0x339C,\n 0xDC3F,0x339D, 0xDC40,0x339E, 0xDC41,0x339F, 0xDC42,0x33A0, 0xDC43,0x33A1, 0xDC44,0x33A2, 0xDC45,0x33CA, 0xDC46,0x338D,\n 0xDC47,0x338E, 0xDC48,0x338F, 0xDC49,0x33CF, 0xDC4A,0x3388, 0xDC4B,0x3389, 0xDC4C,0x33C8, 0xDC4D,0x33A7, 0xDC4E,0x33A8,\n 0xDC4F,0x33B0, 0xDC50,0x33B1, 0xDC51,0x33B2, 0xDC52,0x33B3, 0xDC53,0x33B4, 0xDC54,0x33B5, 0xDC55,0x33B6, 0xDC56,0x33B7,\n 0xDC57,0x33B8, 0xDC58,0x33B9, 0xDC59,0x3380, 0xDC5A,0x3381, 0xDC5B,0x3382, 0xDC5C,0x3383, 0xDC5D,0x3384, 0xDC5E,0x33BA,\n 0xDC5F,0x33BB, 0xDC60,0x33BC, 0xDC61,0x33BD, 0xDC62,0x33BE, 0xDC63,0x33BF, 0xDC64,0x3390, 0xDC65,0x3391, 0xDC66,0x3392,\n 0xDC67,0x3393, 0xDC68,0x3394, 0xDC69,0x2126, 0xDC6A,0x33C0, 0xDC6B,0x33C1, 0xDC6C,0x338A, 0xDC6D,0x338B, 0xDC6E,0x338C,\n 0xDC6F,0x33D6, 0xDC70,0x33C5, 0xDC71,0x33AD, 0xDC72,0x33AE, 0xDC73,0x33AF, 0xDC74,0x33DB, 0xDC75,0x33A9, 0xDC76,0x33AA,\n 0xDC77,0x33AB, 0xDC78,0x33AC, 0xDC79,0x33DD, 0xDC7A,0x33D0, 0xDC7B,0x33D3, 0xDC7C,0x33C3, 0xDC7D,0x33C9, 0xDC7E,0x33DC,\n 0xDC91,0x33C6, 0xDCA1,0x00C6, 0xDCA2,0x00D0, 0xDCA3,0x00AA, 0xDCA4,0x0126, 0xDCA6,0x0132, 0xDCA8,0x013F, 0xDCA9,0x0141,\n 0xDCAA,0x00D8, 0xDCAB,0x0152, 0xDCAC,0x00BA, 0xDCAD,0x00DE, 0xDCAE,0x0166, 0xDCAF,0x014A, 0xDCB1,0x3260, 0xDCB2,0x3261,\n 0xDCB3,0x3262, 0xDCB4,0x3263, 0xDCB5,0x3264, 0xDCB6,0x3265, 0xDCB7,0x3266, 0xDCB8,0x3267, 0xDCB9,0x3268, 0xDCBA,0x3269,\n 0xDCBB,0x326A, 0xDCBC,0x326B, 0xDCBD,0x326C, 0xDCBE,0x326D, 0xDCBF,0x326E, 0xDCC0,0x326F, 0xDCC1,0x3270, 0xDCC2,0x3271,\n 0xDCC3,0x3272, 0xDCC4,0x3273, 0xDCC5,0x3274, 0xDCC6,0x3275, 0xDCC7,0x3276, 0xDCC8,0x3277, 0xDCC9,0x3278, 0xDCCA,0x3279,\n 0xDCCB,0x327A, 0xDCCC,0x327B, 0xDCCD,0x24D0, 0xDCCE,0x24D1, 0xDCCF,0x24D2, 0xDCD0,0x24D3, 0xDCD1,0x24D4, 0xDCD2,0x24D5,\n 0xDCD3,0x24D6, 0xDCD4,0x24D7, 0xDCD5,0x24D8, 0xDCD6,0x24D9, 0xDCD7,0x24DA, 0xDCD8,0x24DB, 0xDCD9,0x24DC, 0xDCDA,0x24DD,\n 0xDCDB,0x24DE, 0xDCDC,0x24DF, 0xDCDD,0x24E0, 0xDCDE,0x24E1, 0xDCDF,0x24E2, 0xDCE0,0x24E3, 0xDCE1,0x24E4, 0xDCE2,0x24E5,\n 0xDCE3,0x24E6, 0xDCE4,0x24E7, 0xDCE5,0x24E8, 0xDCE6,0x24E9, 0xDCE7,0x2460, 0xDCE8,0x2461, 0xDCE9,0x2462, 0xDCEA,0x2463,\n 0xDCEB,0x2464, 0xDCEC,0x2465, 0xDCED,0x2466, 0xDCEE,0x2467, 0xDCEF,0x2468, 0xDCF0,0x2469, 0xDCF1,0x246A, 0xDCF2,0x246B,\n 0xDCF3,0x246C, 0xDCF4,0x246D, 0xDCF5,0x246E, 0xDCF6,0x00BD, 0xDCF7,0x2153, 0xDCF8,0x2154, 0xDCF9,0x00BC, 0xDCFA,0x00BE,\n 0xDCFB,0x215B, 0xDCFC,0x215C, 0xDCFD,0x215D, 0xDCFE,0x215E, 0xDD31,0x00E6, 0xDD32,0x0111, 0xDD33,0x00F0, 0xDD34,0x0127,\n 0xDD35,0x0131, 0xDD36,0x0133, 0xDD37,0x0138, 0xDD38,0x0140, 0xDD39,0x0142, 0xDD3A,0x00F8, 0xDD3B,0x0153, 0xDD3C,0x00DF,\n 0xDD3D,0x00FE, 0xDD3E,0x0167, 0xDD3F,0x014B, 0xDD40,0x0149, 0xDD41,0x3200, 0xDD42,0x3201, 0xDD43,0x3202, 0xDD44,0x3203,\n 0xDD45,0x3204, 0xDD46,0x3205, 0xDD47,0x3206, 0xDD48,0x3207, 0xDD49,0x3208, 0xDD4A,0x3209, 0xDD4B,0x320A, 0xDD4C,0x320B,\n 0xDD4D,0x320C, 0xDD4E,0x320D, 0xDD4F,0x320E, 0xDD50,0x320F, 0xDD51,0x3210, 0xDD52,0x3211, 0xDD53,0x3212, 0xDD54,0x3213,\n 0xDD55,0x3214, 0xDD56,0x3215, 0xDD57,0x3216, 0xDD58,0x3217, 0xDD59,0x3218, 0xDD5A,0x3219, 0xDD5B,0x321A, 0xDD5C,0x321B,\n 0xDD5D,0x249C, 0xDD5E,0x249D, 0xDD5F,0x249E, 0xDD60,0x249F, 0xDD61,0x24A0, 0xDD62,0x24A1, 0xDD63,0x24A2, 0xDD64,0x24A3,\n 0xDD65,0x24A4, 0xDD66,0x24A5, 0xDD67,0x24A6, 0xDD68,0x24A7, 0xDD69,0x24A8, 0xDD6A,0x24A9, 0xDD6B,0x24AA, 0xDD6C,0x24AB,\n 0xDD6D,0x24AC, 0xDD6E,0x24AD, 0xDD6F,0x24AE, 0xDD70,0x24AF, 0xDD71,0x24B0, 0xDD72,0x24B1, 0xDD73,0x24B2, 0xDD74,0x24B3,\n 0xDD75,0x24B4, 0xDD76,0x24B5, 0xDD77,0x2474, 0xDD78,0x2475, 0xDD79,0x2476, 0xDD7A,0x2477, 0xDD7B,0x2478, 0xDD7C,0x2479,\n 0xDD7D,0x247A, 0xDD7E,0x247B, 0xDD91,0x247C, 0xDD92,0x247D, 0xDD93,0x247E, 0xDD94,0x247F, 0xDD95,0x2480, 0xDD96,0x2481,\n 0xDD97,0x2482, 0xDD98,0x00B9, 0xDD99,0x00B2, 0xDD9A,0x00B3, 0xDD9B,0x2074, 0xDD9C,0x207F, 0xDD9D,0x2081, 0xDD9E,0x2082,\n 0xDD9F,0x2083, 0xDDA0,0x2084, 0xDDA1,0x3041, 0xDDA2,0x3042, 0xDDA3,0x3043, 0xDDA4,0x3044, 0xDDA5,0x3045, 0xDDA6,0x3046,\n 0xDDA7,0x3047, 0xDDA8,0x3048, 0xDDA9,0x3049, 0xDDAA,0x304A, 0xDDAB,0x304B, 0xDDAC,0x304C, 0xDDAD,0x304D, 0xDDAE,0x304E,\n 0xDDAF,0x304F, 0xDDB0,0x3050, 0xDDB1,0x3051, 0xDDB2,0x3052, 0xDDB3,0x3053, 0xDDB4,0x3054, 0xDDB5,0x3055, 0xDDB6,0x3056,\n 0xDDB7,0x3057, 0xDDB8,0x3058, 0xDDB9,0x3059, 0xDDBA,0x305A, 0xDDBB,0x305B, 0xDDBC,0x305C, 0xDDBD,0x305D, 0xDDBE,0x305E,\n 0xDDBF,0x305F, 0xDDC0,0x3060, 0xDDC1,0x3061, 0xDDC2,0x3062, 0xDDC3,0x3063, 0xDDC4,0x3064, 0xDDC5,0x3065, 0xDDC6,0x3066,\n 0xDDC7,0x3067, 0xDDC8,0x3068, 0xDDC9,0x3069, 0xDDCA,0x306A, 0xDDCB,0x306B, 0xDDCC,0x306C, 0xDDCD,0x306D, 0xDDCE,0x306E,\n 0xDDCF,0x306F, 0xDDD0,0x3070, 0xDDD1,0x3071, 0xDDD2,0x3072, 0xDDD3,0x3073, 0xDDD4,0x3074, 0xDDD5,0x3075, 0xDDD6,0x3076,\n 0xDDD7,0x3077, 0xDDD8,0x3078, 0xDDD9,0x3079, 0xDDDA,0x307A, 0xDDDB,0x307B, 0xDDDC,0x307C, 0xDDDD,0x307D, 0xDDDE,0x307E,\n 0xDDDF,0x307F, 0xDDE0,0x3080, 0xDDE1,0x3081, 0xDDE2,0x3082, 0xDDE3,0x3083, 0xDDE4,0x3084, 0xDDE5,0x3085, 0xDDE6,0x3086,\n 0xDDE7,0x3087, 0xDDE8,0x3088, 0xDDE9,0x3089, 0xDDEA,0x308A, 0xDDEB,0x308B, 0xDDEC,0x308C, 0xDDED,0x308D, 0xDDEE,0x308E,\n 0xDDEF,0x308F, 0xDDF0,0x3090, 0xDDF1,0x3091, 0xDDF2,0x3092, 0xDDF3,0x3093, 0xDE31,0x30A1, 0xDE32,0x30A2, 0xDE33,0x30A3,\n 0xDE34,0x30A4, 0xDE35,0x30A5, 0xDE36,0x30A6, 0xDE37,0x30A7, 0xDE38,0x30A8, 0xDE39,0x30A9, 0xDE3A,0x30AA, 0xDE3B,0x30AB,\n 0xDE3C,0x30AC, 0xDE3D,0x30AD, 0xDE3E,0x30AE, 0xDE3F,0x30AF, 0xDE40,0x30B0, 0xDE41,0x30B1, 0xDE42,0x30B2, 0xDE43,0x30B3,\n 0xDE44,0x30B4, 0xDE45,0x30B5, 0xDE46,0x30B6, 0xDE47,0x30B7, 0xDE48,0x30B8, 0xDE49,0x30B9, 0xDE4A,0x30BA, 0xDE4B,0x30BB,\n 0xDE4C,0x30BC, 0xDE4D,0x30BD, 0xDE4E,0x30BE, 0xDE4F,0x30BF, 0xDE50,0x30C0, 0xDE51,0x30C1, 0xDE52,0x30C2, 0xDE53,0x30C3,\n 0xDE54,0x30C4, 0xDE55,0x30C5, 0xDE56,0x30C6, 0xDE57,0x30C7, 0xDE58,0x30C8, 0xDE59,0x30C9, 0xDE5A,0x30CA, 0xDE5B,0x30CB,\n 0xDE5C,0x30CC, 0xDE5D,0x30CD, 0xDE5E,0x30CE, 0xDE5F,0x30CF, 0xDE60,0x30D0, 0xDE61,0x30D1, 0xDE62,0x30D2, 0xDE63,0x30D3,\n 0xDE64,0x30D4, 0xDE65,0x30D5, 0xDE66,0x30D6, 0xDE67,0x30D7, 0xDE68,0x30D8, 0xDE69,0x30D9, 0xDE6A,0x30DA, 0xDE6B,0x30DB,\n 0xDE6C,0x30DC, 0xDE6D,0x30DD, 0xDE6E,0x30DE, 0xDE6F,0x30DF, 0xDE70,0x30E0, 0xDE71,0x30E1, 0xDE72,0x30E2, 0xDE73,0x30E3,\n 0xDE74,0x30E4, 0xDE75,0x30E5, 0xDE76,0x30E6, 0xDE77,0x30E7, 0xDE78,0x30E8, 0xDE79,0x30E9, 0xDE7A,0x30EA, 0xDE7B,0x30EB,\n 0xDE7C,0x30EC, 0xDE7D,0x30ED, 0xDE7E,0x30EE, 0xDE91,0x30EF, 0xDE92,0x30F0, 0xDE93,0x30F1, 0xDE94,0x30F2, 0xDE95,0x30F3,\n 0xDE96,0x30F4, 0xDE97,0x30F5, 0xDE98,0x30F6, 0xDEA1,0x0410, 0xDEA2,0x0411, 0xDEA3,0x0412, 0xDEA4,0x0413, 0xDEA5,0x0414,\n 0xDEA6,0x0415, 0xDEA7,0x0401, 0xDEA8,0x0416, 0xDEA9,0x0417, 0xDEAA,0x0418, 0xDEAB,0x0419, 0xDEAC,0x041A, 0xDEAD,0x041B,\n 0xDEAE,0x041C, 0xDEAF,0x041D, 0xDEB0,0x041E, 0xDEB1,0x041F, 0xDEB2,0x0420, 0xDEB3,0x0421, 0xDEB4,0x0422, 0xDEB5,0x0423,\n 0xDEB6,0x0424, 0xDEB7,0x0425, 0xDEB8,0x0426, 0xDEB9,0x0427, 0xDEBA,0x0428, 0xDEBB,0x0429, 0xDEBC,0x042A, 0xDEBD,0x042B,\n 0xDEBE,0x042C, 0xDEBF,0x042D, 0xDEC0,0x042E, 0xDEC1,0x042F, 0xDED1,0x0430, 0xDED2,0x0431, 0xDED3,0x0432, 0xDED4,0x0433,\n 0xDED5,0x0434, 0xDED6,0x0435, 0xDED7,0x0451, 0xDED8,0x0436, 0xDED9,0x0437, 0xDEDA,0x0438, 0xDEDB,0x0439, 0xDEDC,0x043A,\n 0xDEDD,0x043B, 0xDEDE,0x043C, 0xDEDF,0x043D, 0xDEE0,0x043E, 0xDEE1,0x043F, 0xDEE2,0x0440, 0xDEE3,0x0441, 0xDEE4,0x0442,\n 0xDEE5,0x0443, 0xDEE6,0x0444, 0xDEE7,0x0445, 0xDEE8,0x0446, 0xDEE9,0x0447, 0xDEEA,0x0448, 0xDEEB,0x0449, 0xDEEC,0x044A,\n 0xDEED,0x044B, 0xDEEE,0x044C, 0xDEEF,0x044D, 0xDEF0,0x044E, 0xDEF1,0x044F, 0xE031,0x4F3D, 0xE032,0x4F73, 0xE033,0x5047,\n 0xE034,0x50F9, 0xE035,0x52A0, 0xE036,0x53EF, 0xE037,0x5475, 0xE038,0x54E5, 0xE039,0x5609, 0xE03A,0x5AC1, 0xE03B,0x5BB6,\n 0xE03C,0x6687, 0xE03D,0x67B6, 0xE03E,0x67B7, 0xE03F,0x67EF, 0xE040,0x6B4C, 0xE041,0x73C2, 0xE042,0x75C2, 0xE043,0x7A3C,\n 0xE044,0x82DB, 0xE045,0x8304, 0xE046,0x8857, 0xE047,0x8888, 0xE048,0x8A36, 0xE049,0x8CC8, 0xE04A,0x8DCF, 0xE04B,0x8EFB,\n 0xE04C,0x8FE6, 0xE04D,0x99D5, 0xE04E,0x523B, 0xE04F,0x5374, 0xE050,0x5404, 0xE051,0x606A, 0xE052,0x6164, 0xE053,0x6BBC,\n 0xE054,0x73CF, 0xE055,0x811A, 0xE056,0x89BA, 0xE057,0x89D2, 0xE058,0x95A3, 0xE059,0x4F83, 0xE05A,0x520A, 0xE05B,0x58BE,\n 0xE05C,0x5978, 0xE05D,0x59E6, 0xE05E,0x5E72, 0xE05F,0x5E79, 0xE060,0x61C7, 0xE061,0x63C0, 0xE062,0x6746, 0xE063,0x67EC,\n 0xE064,0x687F, 0xE065,0x6F97, 0xE066,0x764E, 0xE067,0x770B, 0xE068,0x78F5, 0xE069,0x7A08, 0xE06A,0x7AFF, 0xE06B,0x7C21,\n 0xE06C,0x809D, 0xE06D,0x826E, 0xE06E,0x8271, 0xE06F,0x8AEB, 0xE070,0x9593, 0xE071,0x4E6B, 0xE072,0x559D, 0xE073,0x66F7,\n 0xE074,0x6E34, 0xE075,0x78A3, 0xE076,0x7AED, 0xE077,0x845B, 0xE078,0x8910, 0xE079,0x874E, 0xE07A,0x97A8, 0xE07B,0x52D8,\n 0xE07C,0x574E, 0xE07D,0x582A, 0xE07E,0x5D4C, 0xE091,0x611F, 0xE092,0x61BE, 0xE093,0x6221, 0xE094,0x6562, 0xE095,0x67D1,\n 0xE096,0x6A44, 0xE097,0x6E1B, 0xE098,0x7518, 0xE099,0x75B3, 0xE09A,0x76E3, 0xE09B,0x77B0, 0xE09C,0x7D3A, 0xE09D,0x90AF,\n 0xE09E,0x9451, 0xE09F,0x9452, 0xE0A0,0x9F95, 0xE0A1,0x5323, 0xE0A2,0x5CAC, 0xE0A3,0x7532, 0xE0A4,0x80DB, 0xE0A5,0x9240,\n 0xE0A6,0x9598, 0xE0A7,0x525B, 0xE0A8,0x5808, 0xE0A9,0x59DC, 0xE0AA,0x5CA1, 0xE0AB,0x5D17, 0xE0AC,0x5EB7, 0xE0AD,0x5F3A,\n 0xE0AE,0x5F4A, 0xE0AF,0x6177, 0xE0B0,0x6C5F, 0xE0B1,0x757A, 0xE0B2,0x7586, 0xE0B3,0x7CE0, 0xE0B4,0x7D73, 0xE0B5,0x7DB1,\n 0xE0B6,0x7F8C, 0xE0B7,0x8154, 0xE0B8,0x8221, 0xE0B9,0x8591, 0xE0BA,0x8941, 0xE0BB,0x8B1B, 0xE0BC,0x92FC, 0xE0BD,0x964D,\n 0xE0BE,0x9C47, 0xE0BF,0x4ECB, 0xE0C0,0x4EF7, 0xE0C1,0x500B, 0xE0C2,0x51F1, 0xE0C3,0x584F, 0xE0C4,0x6137, 0xE0C5,0x613E,\n 0xE0C6,0x6168, 0xE0C7,0x6539, 0xE0C8,0x69EA, 0xE0C9,0x6F11, 0xE0CA,0x75A5, 0xE0CB,0x7686, 0xE0CC,0x76D6, 0xE0CD,0x7B87,\n 0xE0CE,0x82A5, 0xE0CF,0x84CB, 0xE0D0,0xF900, 0xE0D1,0x93A7, 0xE0D2,0x958B, 0xE0D3,0x5580, 0xE0D4,0x5BA2, 0xE0D5,0x5751,\n 0xE0D6,0xF901, 0xE0D7,0x7CB3, 0xE0D8,0x7FB9, 0xE0D9,0x91B5, 0xE0DA,0x5028, 0xE0DB,0x53BB, 0xE0DC,0x5C45, 0xE0DD,0x5DE8,\n 0xE0DE,0x62D2, 0xE0DF,0x636E, 0xE0E0,0x64DA, 0xE0E1,0x64E7, 0xE0E2,0x6E20, 0xE0E3,0x70AC, 0xE0E4,0x795B, 0xE0E5,0x8DDD,\n 0xE0E6,0x8E1E, 0xE0E7,0xF902, 0xE0E8,0x907D, 0xE0E9,0x9245, 0xE0EA,0x92F8, 0xE0EB,0x4E7E, 0xE0EC,0x4EF6, 0xE0ED,0x5065,\n 0xE0EE,0x5DFE, 0xE0EF,0x5EFA, 0xE0F0,0x6106, 0xE0F1,0x6957, 0xE0F2,0x8171, 0xE0F3,0x8654, 0xE0F4,0x8E47, 0xE0F5,0x9375,\n 0xE0F6,0x9A2B, 0xE0F7,0x4E5E, 0xE0F8,0x5091, 0xE0F9,0x6770, 0xE0FA,0x6840, 0xE0FB,0x5109, 0xE0FC,0x528D, 0xE0FD,0x5292,\n 0xE0FE,0x6AA2, 0xE131,0x77BC, 0xE132,0x9210, 0xE133,0x9ED4, 0xE134,0x52AB, 0xE135,0x602F, 0xE136,0x8FF2, 0xE137,0x5048,\n 0xE138,0x61A9, 0xE139,0x63ED, 0xE13A,0x64CA, 0xE13B,0x683C, 0xE13C,0x6A84, 0xE13D,0x6FC0, 0xE13E,0x8188, 0xE13F,0x89A1,\n 0xE140,0x9694, 0xE141,0x5805, 0xE142,0x727D, 0xE143,0x72AC, 0xE144,0x7504, 0xE145,0x7D79, 0xE146,0x7E6D, 0xE147,0x80A9,\n 0xE148,0x898B, 0xE149,0x8B74, 0xE14A,0x9063, 0xE14B,0x9D51, 0xE14C,0x6289, 0xE14D,0x6C7A, 0xE14E,0x6F54, 0xE14F,0x7D50,\n 0xE150,0x7F3A, 0xE151,0x8A23, 0xE152,0x517C, 0xE153,0x614A, 0xE154,0x7B9D, 0xE155,0x8B19, 0xE156,0x9257, 0xE157,0x938C,\n 0xE158,0x4EAC, 0xE159,0x4FD3, 0xE15A,0x501E, 0xE15B,0x50BE, 0xE15C,0x5106, 0xE15D,0x52C1, 0xE15E,0x52CD, 0xE15F,0x537F,\n 0xE160,0x5770, 0xE161,0x5883, 0xE162,0x5E9A, 0xE163,0x5F91, 0xE164,0x6176, 0xE165,0x61AC, 0xE166,0x64CE, 0xE167,0x656C,\n 0xE168,0x666F, 0xE169,0x66BB, 0xE16A,0x66F4, 0xE16B,0x6897, 0xE16C,0x6D87, 0xE16D,0x7085, 0xE16E,0x70F1, 0xE16F,0x749F,\n 0xE170,0x74A5, 0xE171,0x74CA, 0xE172,0x75D9, 0xE173,0x786C, 0xE174,0x78EC, 0xE175,0x7ADF, 0xE176,0x7AF6, 0xE177,0x7D45,\n 0xE178,0x7D93, 0xE179,0x8015, 0xE17A,0x803F, 0xE17B,0x811B, 0xE17C,0x8396, 0xE17D,0x8B66, 0xE17E,0x8F15, 0xE191,0x9015,\n 0xE192,0x93E1, 0xE193,0x9803, 0xE194,0x9838, 0xE195,0x9A5A, 0xE196,0x9BE8, 0xE197,0x4FC2, 0xE198,0x5553, 0xE199,0x583A,\n 0xE19A,0x5951, 0xE19B,0x5B63, 0xE19C,0x5C46, 0xE19D,0x60B8, 0xE19E,0x6212, 0xE19F,0x6842, 0xE1A0,0x68B0, 0xE1A1,0x68E8,\n 0xE1A2,0x6EAA, 0xE1A3,0x754C, 0xE1A4,0x7678, 0xE1A5,0x78CE, 0xE1A6,0x7A3D, 0xE1A7,0x7CFB, 0xE1A8,0x7E6B, 0xE1A9,0x7E7C,\n 0xE1AA,0x8A08, 0xE1AB,0x8AA1, 0xE1AC,0x8C3F, 0xE1AD,0x968E, 0xE1AE,0x9DC4, 0xE1AF,0x53E4, 0xE1B0,0x53E9, 0xE1B1,0x544A,\n 0xE1B2,0x5471, 0xE1B3,0x56FA, 0xE1B4,0x59D1, 0xE1B5,0x5B64, 0xE1B6,0x5C3B, 0xE1B7,0x5EAB, 0xE1B8,0x62F7, 0xE1B9,0x6537,\n 0xE1BA,0x6545, 0xE1BB,0x6572, 0xE1BC,0x66A0, 0xE1BD,0x67AF, 0xE1BE,0x69C1, 0xE1BF,0x6CBD, 0xE1C0,0x75FC, 0xE1C1,0x7690,\n 0xE1C2,0x777E, 0xE1C3,0x7A3F, 0xE1C4,0x7F94, 0xE1C5,0x8003, 0xE1C6,0x80A1, 0xE1C7,0x818F, 0xE1C8,0x82E6, 0xE1C9,0x82FD,\n 0xE1CA,0x83F0, 0xE1CB,0x85C1, 0xE1CC,0x8831, 0xE1CD,0x88B4, 0xE1CE,0x8AA5, 0xE1CF,0xF903, 0xE1D0,0x8F9C, 0xE1D1,0x932E,\n 0xE1D2,0x96C7, 0xE1D3,0x9867, 0xE1D4,0x9AD8, 0xE1D5,0x9F13, 0xE1D6,0x54ED, 0xE1D7,0x659B, 0xE1D8,0x66F2, 0xE1D9,0x688F,\n 0xE1DA,0x7A40, 0xE1DB,0x8C37, 0xE1DC,0x9D60, 0xE1DD,0x56F0, 0xE1DE,0x5764, 0xE1DF,0x5D11, 0xE1E0,0x6606, 0xE1E1,0x68B1,\n 0xE1E2,0x68CD, 0xE1E3,0x6EFE, 0xE1E4,0x7428, 0xE1E5,0x889E, 0xE1E6,0x9BE4, 0xE1E7,0x6C68, 0xE1E8,0xF904, 0xE1E9,0x9AA8,\n 0xE1EA,0x4F9B, 0xE1EB,0x516C, 0xE1EC,0x5171, 0xE1ED,0x529F, 0xE1EE,0x5B54, 0xE1EF,0x5DE5, 0xE1F0,0x6050, 0xE1F1,0x606D,\n 0xE1F2,0x62F1, 0xE1F3,0x63A7, 0xE1F4,0x653B, 0xE1F5,0x73D9, 0xE1F6,0x7A7A, 0xE1F7,0x86A3, 0xE1F8,0x8CA2, 0xE1F9,0x978F,\n 0xE1FA,0x4E32, 0xE1FB,0x5BE1, 0xE1FC,0x6208, 0xE1FD,0x679C, 0xE1FE,0x74DC, 0xE231,0x79D1, 0xE232,0x83D3, 0xE233,0x8A87,\n 0xE234,0x8AB2, 0xE235,0x8DE8, 0xE236,0x904E, 0xE237,0x934B, 0xE238,0x9846, 0xE239,0x5ED3, 0xE23A,0x69E8, 0xE23B,0x85FF,\n 0xE23C,0x90ED, 0xE23D,0xF905, 0xE23E,0x51A0, 0xE23F,0x5B98, 0xE240,0x5BEC, 0xE241,0x6163, 0xE242,0x68FA, 0xE243,0x6B3E,\n 0xE244,0x704C, 0xE245,0x742F, 0xE246,0x74D8, 0xE247,0x7BA1, 0xE248,0x7F50, 0xE249,0x83C5, 0xE24A,0x89C0, 0xE24B,0x8CAB,\n 0xE24C,0x95DC, 0xE24D,0x9928, 0xE24E,0x522E, 0xE24F,0x605D, 0xE250,0x62EC, 0xE251,0x9002, 0xE252,0x4F8A, 0xE253,0x5149,\n 0xE254,0x5321, 0xE255,0x58D9, 0xE256,0x5EE3, 0xE257,0x66E0, 0xE258,0x6D38, 0xE259,0x709A, 0xE25A,0x72C2, 0xE25B,0x73D6,\n 0xE25C,0x7B50, 0xE25D,0x80F1, 0xE25E,0x945B, 0xE25F,0x5366, 0xE260,0x639B, 0xE261,0x7F6B, 0xE262,0x4E56, 0xE263,0x5080,\n 0xE264,0x584A, 0xE265,0x58DE, 0xE266,0x602A, 0xE267,0x6127, 0xE268,0x62D0, 0xE269,0x69D0, 0xE26A,0x9B41, 0xE26B,0x5B8F,\n 0xE26C,0x7D18, 0xE26D,0x80B1, 0xE26E,0x8F5F, 0xE26F,0x4EA4, 0xE270,0x50D1, 0xE271,0x54AC, 0xE272,0x55AC, 0xE273,0x5B0C,\n 0xE274,0x5DA0, 0xE275,0x5DE7, 0xE276,0x652A, 0xE277,0x654E, 0xE278,0x6821, 0xE279,0x6A4B, 0xE27A,0x72E1, 0xE27B,0x768E,\n 0xE27C,0x77EF, 0xE27D,0x7D5E, 0xE27E,0x7FF9, 0xE291,0x81A0, 0xE292,0x854E, 0xE293,0x86DF, 0xE294,0x8F03, 0xE295,0x8F4E,\n 0xE296,0x90CA, 0xE297,0x9903, 0xE298,0x9A55, 0xE299,0x9BAB, 0xE29A,0x4E18, 0xE29B,0x4E45, 0xE29C,0x4E5D, 0xE29D,0x4EC7,\n 0xE29E,0x4FF1, 0xE29F,0x5177, 0xE2A0,0x52FE, 0xE2A1,0x5340, 0xE2A2,0x53E3, 0xE2A3,0x53E5, 0xE2A4,0x548E, 0xE2A5,0x5614,\n 0xE2A6,0x5775, 0xE2A7,0x57A2, 0xE2A8,0x5BC7, 0xE2A9,0x5D87, 0xE2AA,0x5ED0, 0xE2AB,0x61FC, 0xE2AC,0x62D8, 0xE2AD,0x6551,\n 0xE2AE,0x67B8, 0xE2AF,0x67E9, 0xE2B0,0x69CB, 0xE2B1,0x6B50, 0xE2B2,0x6BC6, 0xE2B3,0x6BEC, 0xE2B4,0x6C42, 0xE2B5,0x6E9D,\n 0xE2B6,0x7078, 0xE2B7,0x72D7, 0xE2B8,0x7396, 0xE2B9,0x7403, 0xE2BA,0x77BF, 0xE2BB,0x77E9, 0xE2BC,0x7A76, 0xE2BD,0x7D7F,\n 0xE2BE,0x8009, 0xE2BF,0x81FC, 0xE2C0,0x8205, 0xE2C1,0x820A, 0xE2C2,0x82DF, 0xE2C3,0x8862, 0xE2C4,0x8B33, 0xE2C5,0x8CFC,\n 0xE2C6,0x8EC0, 0xE2C7,0x9011, 0xE2C8,0x90B1, 0xE2C9,0x9264, 0xE2CA,0x92B6, 0xE2CB,0x99D2, 0xE2CC,0x9A45, 0xE2CD,0x9CE9,\n 0xE2CE,0x9DD7, 0xE2CF,0x9F9C, 0xE2D0,0x570B, 0xE2D1,0x5C40, 0xE2D2,0x83CA, 0xE2D3,0x97A0, 0xE2D4,0x97AB, 0xE2D5,0x9EB4,\n 0xE2D6,0x541B, 0xE2D7,0x7A98, 0xE2D8,0x7FA4, 0xE2D9,0x88D9, 0xE2DA,0x8ECD, 0xE2DB,0x90E1, 0xE2DC,0x5800, 0xE2DD,0x5C48,\n 0xE2DE,0x6398, 0xE2DF,0x7A9F, 0xE2E0,0x5BAE, 0xE2E1,0x5F13, 0xE2E2,0x7A79, 0xE2E3,0x7AAE, 0xE2E4,0x828E, 0xE2E5,0x8EAC,\n 0xE2E6,0x5026, 0xE2E7,0x5238, 0xE2E8,0x52F8, 0xE2E9,0x5377, 0xE2EA,0x5708, 0xE2EB,0x62F3, 0xE2EC,0x6372, 0xE2ED,0x6B0A,\n 0xE2EE,0x6DC3, 0xE2EF,0x7737, 0xE2F0,0x53A5, 0xE2F1,0x7357, 0xE2F2,0x8568, 0xE2F3,0x8E76, 0xE2F4,0x95D5, 0xE2F5,0x673A,\n 0xE2F6,0x6AC3, 0xE2F7,0x6F70, 0xE2F8,0x8A6D, 0xE2F9,0x8ECC, 0xE2FA,0x994B, 0xE2FB,0xF906, 0xE2FC,0x6677, 0xE2FD,0x6B78,\n 0xE2FE,0x8CB4, 0xE331,0x9B3C, 0xE332,0xF907, 0xE333,0x53EB, 0xE334,0x572D, 0xE335,0x594E, 0xE336,0x63C6, 0xE337,0x69FB,\n 0xE338,0x73EA, 0xE339,0x7845, 0xE33A,0x7ABA, 0xE33B,0x7AC5, 0xE33C,0x7CFE, 0xE33D,0x8475, 0xE33E,0x898F, 0xE33F,0x8D73,\n 0xE340,0x9035, 0xE341,0x95A8, 0xE342,0x52FB, 0xE343,0x5747, 0xE344,0x7547, 0xE345,0x7B60, 0xE346,0x83CC, 0xE347,0x921E,\n 0xE348,0xF908, 0xE349,0x6A58, 0xE34A,0x514B, 0xE34B,0x524B, 0xE34C,0x5287, 0xE34D,0x621F, 0xE34E,0x68D8, 0xE34F,0x6975,\n 0xE350,0x9699, 0xE351,0x50C5, 0xE352,0x52A4, 0xE353,0x52E4, 0xE354,0x61C3, 0xE355,0x65A4, 0xE356,0x6839, 0xE357,0x69FF,\n 0xE358,0x747E, 0xE359,0x7B4B, 0xE35A,0x82B9, 0xE35B,0x83EB, 0xE35C,0x89B2, 0xE35D,0x8B39, 0xE35E,0x8FD1, 0xE35F,0x9949,\n 0xE360,0xF909, 0xE361,0x4ECA, 0xE362,0x5997, 0xE363,0x64D2, 0xE364,0x6611, 0xE365,0x6A8E, 0xE366,0x7434, 0xE367,0x7981,\n 0xE368,0x79BD, 0xE369,0x82A9, 0xE36A,0x887E, 0xE36B,0x887F, 0xE36C,0x895F, 0xE36D,0xF90A, 0xE36E,0x9326, 0xE36F,0x4F0B,\n 0xE370,0x53CA, 0xE371,0x6025, 0xE372,0x6271, 0xE373,0x6C72, 0xE374,0x7D1A, 0xE375,0x7D66, 0xE376,0x4E98, 0xE377,0x5162,\n 0xE378,0x77DC, 0xE379,0x80AF, 0xE37A,0x4F01, 0xE37B,0x4F0E, 0xE37C,0x5176, 0xE37D,0x5180, 0xE37E,0x55DC, 0xE391,0x5668,\n 0xE392,0x573B, 0xE393,0x57FA, 0xE394,0x57FC, 0xE395,0x5914, 0xE396,0x5947, 0xE397,0x5993, 0xE398,0x5BC4, 0xE399,0x5C90,\n 0xE39A,0x5D0E, 0xE39B,0x5DF1, 0xE39C,0x5E7E, 0xE39D,0x5FCC, 0xE39E,0x6280, 0xE39F,0x65D7, 0xE3A0,0x65E3, 0xE3A1,0x671E,\n 0xE3A2,0x671F, 0xE3A3,0x675E, 0xE3A4,0x68CB, 0xE3A5,0x68C4, 0xE3A6,0x6A5F, 0xE3A7,0x6B3A, 0xE3A8,0x6C23, 0xE3A9,0x6C7D,\n 0xE3AA,0x6C82, 0xE3AB,0x6DC7, 0xE3AC,0x7398, 0xE3AD,0x7426, 0xE3AE,0x742A, 0xE3AF,0x7482, 0xE3B0,0x74A3, 0xE3B1,0x7578,\n 0xE3B2,0x757F, 0xE3B3,0x7881, 0xE3B4,0x78EF, 0xE3B5,0x7941, 0xE3B6,0x7947, 0xE3B7,0x7948, 0xE3B8,0x797A, 0xE3B9,0x7B95,\n 0xE3BA,0x7D00, 0xE3BB,0x7DBA, 0xE3BC,0x7F88, 0xE3BD,0x8006, 0xE3BE,0x802D, 0xE3BF,0x808C, 0xE3C0,0x8A18, 0xE3C1,0x8B4F,\n 0xE3C2,0x8C48, 0xE3C3,0x8D77, 0xE3C4,0x9321, 0xE3C5,0x9324, 0xE3C6,0x98E2, 0xE3C7,0x9951, 0xE3C8,0x9A0E, 0xE3C9,0x9A0F,\n 0xE3CA,0x9A65, 0xE3CB,0x9E92, 0xE3CC,0x7DCA, 0xE3CD,0x4F76, 0xE3CE,0x5409, 0xE3CF,0x62EE, 0xE3D0,0x6854, 0xE3D1,0x91D1,\n 0xE3D2,0x55AB, 0xE3D3,0x513A, 0xE3D4,0xF90B, 0xE3D5,0xF90C, 0xE3D6,0x5A1C, 0xE3D7,0x61E6, 0xE3D8,0xF90D, 0xE3D9,0x62CF,\n 0xE3DA,0x62FF, 0xE3DB,0xF90E, 0xE3DC,0xF90F, 0xE3DD,0xF910, 0xE3DE,0xF911, 0xE3DF,0xF912, 0xE3E0,0xF913, 0xE3E1,0x90A3,\n 0xE3E2,0xF914, 0xE3E3,0xF915, 0xE3E4,0xF916, 0xE3E5,0xF917, 0xE3E6,0xF918, 0xE3E7,0x8AFE, 0xE3E8,0xF919, 0xE3E9,0xF91A,\n 0xE3EA,0xF91B, 0xE3EB,0xF91C, 0xE3EC,0x6696, 0xE3ED,0xF91D, 0xE3EE,0x7156, 0xE3EF,0xF91E, 0xE3F0,0xF91F, 0xE3F1,0x96E3,\n 0xE3F2,0xF920, 0xE3F3,0x634F, 0xE3F4,0x637A, 0xE3F5,0x5357, 0xE3F6,0xF921, 0xE3F7,0x678F, 0xE3F8,0x6960, 0xE3F9,0x6E73,\n 0xE3FA,0xF922, 0xE3FB,0x7537, 0xE3FC,0xF923, 0xE3FD,0xF924, 0xE3FE,0xF925, 0xE431,0x7D0D, 0xE432,0xF926, 0xE433,0xF927,\n 0xE434,0x8872, 0xE435,0x56CA, 0xE436,0x5A18, 0xE437,0xF928, 0xE438,0xF929, 0xE439,0xF92A, 0xE43A,0xF92B, 0xE43B,0xF92C,\n 0xE43C,0x4E43, 0xE43D,0xF92D, 0xE43E,0x5167, 0xE43F,0x5948, 0xE440,0x67F0, 0xE441,0x8010, 0xE442,0xF92E, 0xE443,0x5973,\n 0xE444,0x5E74, 0xE445,0x649A, 0xE446,0x79CA, 0xE447,0x5FF5, 0xE448,0x606C, 0xE449,0x62C8, 0xE44A,0x637B, 0xE44B,0x5BE7,\n 0xE44C,0x5BD7, 0xE44D,0x52AA, 0xE44E,0xF92F, 0xE44F,0x5974, 0xE450,0x5F29, 0xE451,0x6012, 0xE452,0xF930, 0xE453,0xF931,\n 0xE454,0xF932, 0xE455,0x7459, 0xE456,0xF933, 0xE457,0xF934, 0xE458,0xF935, 0xE459,0xF936, 0xE45A,0xF937, 0xE45B,0xF938,\n 0xE45C,0x99D1, 0xE45D,0xF939, 0xE45E,0xF93A, 0xE45F,0xF93B, 0xE460,0xF93C, 0xE461,0xF93D, 0xE462,0xF93E, 0xE463,0xF93F,\n 0xE464,0xF940, 0xE465,0xF941, 0xE466,0xF942, 0xE467,0xF943, 0xE468,0x6FC3, 0xE469,0xF944, 0xE46A,0xF945, 0xE46B,0x81BF,\n 0xE46C,0x8FB2, 0xE46D,0x60F1, 0xE46E,0xF946, 0xE46F,0xF947, 0xE470,0x8166, 0xE471,0xF948, 0xE472,0xF949, 0xE473,0x5C3F,\n 0xE474,0xF94A, 0xE475,0xF94B, 0xE476,0xF94C, 0xE477,0xF94D, 0xE478,0xF94E, 0xE479,0xF94F, 0xE47A,0xF950, 0xE47B,0xF951,\n 0xE47C,0x5AE9, 0xE47D,0x8A25, 0xE47E,0x677B, 0xE491,0x7D10, 0xE492,0xF952, 0xE493,0xF953, 0xE494,0xF954, 0xE495,0xF955,\n 0xE496,0xF956, 0xE497,0xF957, 0xE498,0x80FD, 0xE499,0xF958, 0xE49A,0xF959, 0xE49B,0x5C3C, 0xE49C,0x6CE5, 0xE49D,0x533F,\n 0xE49E,0x6EBA, 0xE49F,0x591A, 0xE4A0,0x8336, 0xE4A1,0x4E39, 0xE4A2,0x4EB6, 0xE4A3,0x4F46, 0xE4A4,0x55AE, 0xE4A5,0x5718,\n 0xE4A6,0x58C7, 0xE4A7,0x5F56, 0xE4A8,0x65B7, 0xE4A9,0x65E6, 0xE4AA,0x6A80, 0xE4AB,0x6BB5, 0xE4AC,0x6E4D, 0xE4AD,0x77ED,\n 0xE4AE,0x7AEF, 0xE4AF,0x7C1E, 0xE4B0,0x7DDE, 0xE4B1,0x86CB, 0xE4B2,0x8892, 0xE4B3,0x9132, 0xE4B4,0x935B, 0xE4B5,0x64BB,\n 0xE4B6,0x6FBE, 0xE4B7,0x737A, 0xE4B8,0x75B8, 0xE4B9,0x9054, 0xE4BA,0x5556, 0xE4BB,0x574D, 0xE4BC,0x61BA, 0xE4BD,0x64D4,\n 0xE4BE,0x66C7, 0xE4BF,0x6DE1, 0xE4C0,0x6E5B, 0xE4C1,0x6F6D, 0xE4C2,0x6FB9, 0xE4C3,0x75F0, 0xE4C4,0x8043, 0xE4C5,0x81BD,\n 0xE4C6,0x8541, 0xE4C7,0x8983, 0xE4C8,0x8AC7, 0xE4C9,0x8B5A, 0xE4CA,0x931F, 0xE4CB,0x6C93, 0xE4CC,0x7553, 0xE4CD,0x7B54,\n 0xE4CE,0x8E0F, 0xE4CF,0x905D, 0xE4D0,0x5510, 0xE4D1,0x5802, 0xE4D2,0x5858, 0xE4D3,0x5E62, 0xE4D4,0x6207, 0xE4D5,0x649E,\n 0xE4D6,0x68E0, 0xE4D7,0x7576, 0xE4D8,0x7CD6, 0xE4D9,0x87B3, 0xE4DA,0x9EE8, 0xE4DB,0x4EE3, 0xE4DC,0x5788, 0xE4DD,0x576E,\n 0xE4DE,0x5927, 0xE4DF,0x5C0D, 0xE4E0,0x5CB1, 0xE4E1,0x5E36, 0xE4E2,0x5F85, 0xE4E3,0x6234, 0xE4E4,0x64E1, 0xE4E5,0x73B3,\n 0xE4E6,0x81FA, 0xE4E7,0x888B, 0xE4E8,0x8CB8, 0xE4E9,0x968A, 0xE4EA,0x9EDB, 0xE4EB,0x5B85, 0xE4EC,0x5FB7, 0xE4ED,0x60B3,\n 0xE4EE,0x5012, 0xE4EF,0x5200, 0xE4F0,0x5230, 0xE4F1,0x5716, 0xE4F2,0x5835, 0xE4F3,0x5857, 0xE4F4,0x5C0E, 0xE4F5,0x5C60,\n 0xE4F6,0x5CF6, 0xE4F7,0x5D8B, 0xE4F8,0x5EA6, 0xE4F9,0x5F92, 0xE4FA,0x60BC, 0xE4FB,0x6311, 0xE4FC,0x6389, 0xE4FD,0x6417,\n 0xE4FE,0x6843, 0xE531,0x68F9, 0xE532,0x6AC2, 0xE533,0x6DD8, 0xE534,0x6E21, 0xE535,0x6ED4, 0xE536,0x6FE4, 0xE537,0x71FE,\n 0xE538,0x76DC, 0xE539,0x7779, 0xE53A,0x79B1, 0xE53B,0x7A3B, 0xE53C,0x8404, 0xE53D,0x89A9, 0xE53E,0x8CED, 0xE53F,0x8DF3,\n 0xE540,0x8E48, 0xE541,0x9003, 0xE542,0x9014, 0xE543,0x9053, 0xE544,0x90FD, 0xE545,0x934D, 0xE546,0x9676, 0xE547,0x97DC,\n 0xE548,0x6BD2, 0xE549,0x7006, 0xE54A,0x7258, 0xE54B,0x72A2, 0xE54C,0x7368, 0xE54D,0x7763, 0xE54E,0x79BF, 0xE54F,0x7BE4,\n 0xE550,0x7E9B, 0xE551,0x8B80, 0xE552,0x58A9, 0xE553,0x60C7, 0xE554,0x6566, 0xE555,0x65FD, 0xE556,0x66BE, 0xE557,0x6C8C,\n 0xE558,0x711E, 0xE559,0x71C9, 0xE55A,0x8C5A, 0xE55B,0x9813, 0xE55C,0x4E6D, 0xE55D,0x7A81, 0xE55E,0x4EDD, 0xE55F,0x51AC,\n 0xE560,0x51CD, 0xE561,0x52D5, 0xE562,0x540C, 0xE563,0x61A7, 0xE564,0x6771, 0xE565,0x6850, 0xE566,0x68DF, 0xE567,0x6D1E,\n 0xE568,0x6F7C, 0xE569,0x75BC, 0xE56A,0x77B3, 0xE56B,0x7AE5, 0xE56C,0x80F4, 0xE56D,0x8463, 0xE56E,0x9285, 0xE56F,0x515C,\n 0xE570,0x6597, 0xE571,0x675C, 0xE572,0x6793, 0xE573,0x75D8, 0xE574,0x7AC7, 0xE575,0x8373, 0xE576,0xF95A, 0xE577,0x8C46,\n 0xE578,0x9017, 0xE579,0x982D, 0xE57A,0x5C6F, 0xE57B,0x81C0, 0xE57C,0x829A, 0xE57D,0x9041, 0xE57E,0x906F, 0xE591,0x920D,\n 0xE592,0x5F97, 0xE593,0x5D9D, 0xE594,0x6A59, 0xE595,0x71C8, 0xE596,0x767B, 0xE597,0x7B49, 0xE598,0x85E4, 0xE599,0x8B04,\n 0xE59A,0x9127, 0xE59B,0x9A30, 0xE59C,0x5587, 0xE59D,0x61F6, 0xE59E,0xF95B, 0xE59F,0x7669, 0xE5A0,0x7F85, 0xE5A1,0x863F,\n 0xE5A2,0x87BA, 0xE5A3,0x88F8, 0xE5A4,0x908F, 0xE5A5,0xF95C, 0xE5A6,0x6D1B, 0xE5A7,0x70D9, 0xE5A8,0x73DE, 0xE5A9,0x7D61,\n 0xE5AA,0x843D, 0xE5AB,0xF95D, 0xE5AC,0x916A, 0xE5AD,0x99F1, 0xE5AE,0xF95E, 0xE5AF,0x4E82, 0xE5B0,0x5375, 0xE5B1,0x6B04,\n 0xE5B2,0x6B12, 0xE5B3,0x703E, 0xE5B4,0x721B, 0xE5B5,0x862D, 0xE5B6,0x9E1E, 0xE5B7,0x524C, 0xE5B8,0x8FA3, 0xE5B9,0x5D50,\n 0xE5BA,0x64E5, 0xE5BB,0x652C, 0xE5BC,0x6B16, 0xE5BD,0x6FEB, 0xE5BE,0x7C43, 0xE5BF,0x7E9C, 0xE5C0,0x85CD, 0xE5C1,0x8964,\n 0xE5C2,0x89BD, 0xE5C3,0x62C9, 0xE5C4,0x81D8, 0xE5C5,0x881F, 0xE5C6,0x5ECA, 0xE5C7,0x6717, 0xE5C8,0x6D6A, 0xE5C9,0x72FC,\n 0xE5CA,0x7405, 0xE5CB,0x746F, 0xE5CC,0x8782, 0xE5CD,0x90DE, 0xE5CE,0x4F86, 0xE5CF,0x5D0D, 0xE5D0,0x5FA0, 0xE5D1,0x840A,\n 0xE5D2,0x51B7, 0xE5D3,0x63A0, 0xE5D4,0x7565, 0xE5D5,0x4EAE, 0xE5D6,0x5006, 0xE5D7,0x5169, 0xE5D8,0x51C9, 0xE5D9,0x6881,\n 0xE5DA,0x6A11, 0xE5DB,0x7CAE, 0xE5DC,0x7CB1, 0xE5DD,0x7CE7, 0xE5DE,0x826F, 0xE5DF,0x8AD2, 0xE5E0,0x8F1B, 0xE5E1,0x91CF,\n 0xE5E2,0x4FB6, 0xE5E3,0x5137, 0xE5E4,0x52F5, 0xE5E5,0x5442, 0xE5E6,0x5EEC, 0xE5E7,0x616E, 0xE5E8,0x623E, 0xE5E9,0x65C5,\n 0xE5EA,0x6ADA, 0xE5EB,0x6FFE, 0xE5EC,0x792A, 0xE5ED,0x85DC, 0xE5EE,0x8823, 0xE5EF,0x95AD, 0xE5F0,0x9A62, 0xE5F1,0x9A6A,\n 0xE5F2,0x9E97, 0xE5F3,0x9ECE, 0xE5F4,0x529B, 0xE5F5,0x66C6, 0xE5F6,0x6B77, 0xE5F7,0x701D, 0xE5F8,0x792B, 0xE5F9,0x8F62,\n 0xE5FA,0x9742, 0xE5FB,0x6190, 0xE5FC,0x6200, 0xE5FD,0x6523, 0xE5FE,0x6F23, 0xE631,0x7149, 0xE632,0x7489, 0xE633,0x7DF4,\n 0xE634,0x806F, 0xE635,0x84EE, 0xE636,0x8F26, 0xE637,0x9023, 0xE638,0x934A, 0xE639,0x51BD, 0xE63A,0x5217, 0xE63B,0x52A3,\n 0xE63C,0x6D0C, 0xE63D,0x70C8, 0xE63E,0x88C2, 0xE63F,0x5EC9, 0xE640,0x6582, 0xE641,0x6BAE, 0xE642,0x6FC2, 0xE643,0x7C3E,\n 0xE644,0x7375, 0xE645,0x4EE4, 0xE646,0x4F36, 0xE647,0x56F9, 0xE648,0xF95F, 0xE649,0x5CBA, 0xE64A,0x5DBA, 0xE64B,0x601C,\n 0xE64C,0x73B2, 0xE64D,0x7B2D, 0xE64E,0x7F9A, 0xE64F,0x7FCE, 0xE650,0x8046, 0xE651,0x901E, 0xE652,0x9234, 0xE653,0x96F6,\n 0xE654,0x9748, 0xE655,0x9818, 0xE656,0x9F61, 0xE657,0x4F8B, 0xE658,0x6FA7, 0xE659,0x79AE, 0xE65A,0x91B4, 0xE65B,0x96B7,\n 0xE65C,0x52DE, 0xE65D,0xF960, 0xE65E,0x6488, 0xE65F,0x64C4, 0xE660,0x6AD3, 0xE661,0x6F5E, 0xE662,0x7018, 0xE663,0x7210,\n 0xE664,0x76E7, 0xE665,0x8001, 0xE666,0x8606, 0xE667,0x865C, 0xE668,0x8DEF, 0xE669,0x8F05, 0xE66A,0x9732, 0xE66B,0x9B6F,\n 0xE66C,0x9DFA, 0xE66D,0x9E75, 0xE66E,0x788C, 0xE66F,0x797F, 0xE670,0x7DA0, 0xE671,0x83C9, 0xE672,0x9304, 0xE673,0x9E7F,\n 0xE674,0x9E93, 0xE675,0x8AD6, 0xE676,0x58DF, 0xE677,0x5F04, 0xE678,0x6727, 0xE679,0x7027, 0xE67A,0x74CF, 0xE67B,0x7C60,\n 0xE67C,0x807E, 0xE67D,0x5121, 0xE67E,0x7028, 0xE691,0x7262, 0xE692,0x78CA, 0xE693,0x8CC2, 0xE694,0x8CDA, 0xE695,0x8CF4,\n 0xE696,0x96F7, 0xE697,0x4E86, 0xE698,0x50DA, 0xE699,0x5BEE, 0xE69A,0x5ED6, 0xE69B,0x6599, 0xE69C,0x71CE, 0xE69D,0x7642,\n 0xE69E,0x77AD, 0xE69F,0x804A, 0xE6A0,0x84FC, 0xE6A1,0x907C, 0xE6A2,0x9B27, 0xE6A3,0x9F8D, 0xE6A4,0x58D8, 0xE6A5,0x5A41,\n 0xE6A6,0x5C62, 0xE6A7,0x6A13, 0xE6A8,0x6DDA, 0xE6A9,0x6F0F, 0xE6AA,0x763B, 0xE6AB,0x7D2F, 0xE6AC,0x7E37, 0xE6AD,0x851E,\n 0xE6AE,0x8938, 0xE6AF,0x93E4, 0xE6B0,0x964B, 0xE6B1,0x5289, 0xE6B2,0x65D2, 0xE6B3,0x67F3, 0xE6B4,0x69B4, 0xE6B5,0x6D41,\n 0xE6B6,0x6E9C, 0xE6B7,0x700F, 0xE6B8,0x7409, 0xE6B9,0x7460, 0xE6BA,0x7559, 0xE6BB,0x7624, 0xE6BC,0x786B, 0xE6BD,0x8B2C,\n 0xE6BE,0x985E, 0xE6BF,0x516D, 0xE6C0,0x622E, 0xE6C1,0x9678, 0xE6C2,0x4F96, 0xE6C3,0x502B, 0xE6C4,0x5D19, 0xE6C5,0x6DEA,\n 0xE6C6,0x7DB8, 0xE6C7,0x8F2A, 0xE6C8,0x5F8B, 0xE6C9,0x6144, 0xE6CA,0x6817, 0xE6CB,0xF961, 0xE6CC,0x9686, 0xE6CD,0x52D2,\n 0xE6CE,0x808B, 0xE6CF,0x51DC, 0xE6D0,0x51CC, 0xE6D1,0x695E, 0xE6D2,0x7A1C, 0xE6D3,0x7DBE, 0xE6D4,0x83F1, 0xE6D5,0x9675,\n 0xE6D6,0x4FDA, 0xE6D7,0x5229, 0xE6D8,0x5398, 0xE6D9,0x540F, 0xE6DA,0x550E, 0xE6DB,0x5C65, 0xE6DC,0x60A7, 0xE6DD,0x674E,\n 0xE6DE,0x68A8, 0xE6DF,0x6D6C, 0xE6E0,0x7281, 0xE6E1,0x72F8, 0xE6E2,0x7406, 0xE6E3,0x7483, 0xE6E4,0xF962, 0xE6E5,0x75E2,\n 0xE6E6,0x7C6C, 0xE6E7,0x7F79, 0xE6E8,0x7FB8, 0xE6E9,0x8389, 0xE6EA,0x88CF, 0xE6EB,0x88E1, 0xE6EC,0x91CC, 0xE6ED,0x91D0,\n 0xE6EE,0x96E2, 0xE6EF,0x9BC9, 0xE6F0,0x541D, 0xE6F1,0x6F7E, 0xE6F2,0x71D0, 0xE6F3,0x7498, 0xE6F4,0x85FA, 0xE6F5,0x8EAA,\n 0xE6F6,0x96A3, 0xE6F7,0x9C57, 0xE6F8,0x9E9F, 0xE6F9,0x6797, 0xE6FA,0x6DCB, 0xE6FB,0x7433, 0xE6FC,0x81E8, 0xE6FD,0x9716,\n 0xE6FE,0x782C, 0xE731,0x7ACB, 0xE732,0x7B20, 0xE733,0x7C92, 0xE734,0x6469, 0xE735,0x746A, 0xE736,0x75F2, 0xE737,0x78BC,\n 0xE738,0x78E8, 0xE739,0x99AC, 0xE73A,0x9B54, 0xE73B,0x9EBB, 0xE73C,0x5BDE, 0xE73D,0x5E55, 0xE73E,0x6F20, 0xE73F,0x819C,\n 0xE740,0x83AB, 0xE741,0x9088, 0xE742,0x4E07, 0xE743,0x534D, 0xE744,0x5A29, 0xE745,0x5DD2, 0xE746,0x5F4E, 0xE747,0x6162,\n 0xE748,0x633D, 0xE749,0x6669, 0xE74A,0x66FC, 0xE74B,0x6EFF, 0xE74C,0x6F2B, 0xE74D,0x7063, 0xE74E,0x779E, 0xE74F,0x842C,\n 0xE750,0x8513, 0xE751,0x883B, 0xE752,0x8F13, 0xE753,0x9945, 0xE754,0x9C3B, 0xE755,0x551C, 0xE756,0x62B9, 0xE757,0x672B,\n 0xE758,0x6CAB, 0xE759,0x8309, 0xE75A,0x896A, 0xE75B,0x977A, 0xE75C,0x4EA1, 0xE75D,0x5984, 0xE75E,0x5FD8, 0xE75F,0x5FD9,\n 0xE760,0x671B, 0xE761,0x7DB2, 0xE762,0x7F54, 0xE763,0x8292, 0xE764,0x832B, 0xE765,0x83BD, 0xE766,0x8F1E, 0xE767,0x9099,\n 0xE768,0x57CB, 0xE769,0x59B9, 0xE76A,0x5A92, 0xE76B,0x5BD0, 0xE76C,0x6627, 0xE76D,0x679A, 0xE76E,0x6885, 0xE76F,0x6BCF,\n 0xE770,0x7164, 0xE771,0x7F75, 0xE772,0x8CB7, 0xE773,0x8CE3, 0xE774,0x9081, 0xE775,0x9B45, 0xE776,0x8108, 0xE777,0x8C8A,\n 0xE778,0x964C, 0xE779,0x9A40, 0xE77A,0x9EA5, 0xE77B,0x5B5F, 0xE77C,0x6C13, 0xE77D,0x731B, 0xE77E,0x76F2, 0xE791,0x76DF,\n 0xE792,0x840C, 0xE793,0x51AA, 0xE794,0x8993, 0xE795,0x514D, 0xE796,0x5195, 0xE797,0x52C9, 0xE798,0x68C9, 0xE799,0x6C94,\n 0xE79A,0x7704, 0xE79B,0x7720, 0xE79C,0x7DBF, 0xE79D,0x7DEC, 0xE79E,0x9762, 0xE79F,0x9EB5, 0xE7A0,0x6EC5, 0xE7A1,0x8511,\n 0xE7A2,0x51A5, 0xE7A3,0x540D, 0xE7A4,0x547D, 0xE7A5,0x660E, 0xE7A6,0x669D, 0xE7A7,0x6927, 0xE7A8,0x6E9F, 0xE7A9,0x76BF,\n 0xE7AA,0x7791, 0xE7AB,0x8317, 0xE7AC,0x84C2, 0xE7AD,0x879F, 0xE7AE,0x9169, 0xE7AF,0x9298, 0xE7B0,0x9CF4, 0xE7B1,0x8882,\n 0xE7B2,0x4FAE, 0xE7B3,0x5192, 0xE7B4,0x52DF, 0xE7B5,0x59C6, 0xE7B6,0x5E3D, 0xE7B7,0x6155, 0xE7B8,0x6478, 0xE7B9,0x6479,\n 0xE7BA,0x66AE, 0xE7BB,0x67D0, 0xE7BC,0x6A21, 0xE7BD,0x6BCD, 0xE7BE,0x6BDB, 0xE7BF,0x725F, 0xE7C0,0x7261, 0xE7C1,0x7441,\n 0xE7C2,0x7738, 0xE7C3,0x77DB, 0xE7C4,0x8017, 0xE7C5,0x82BC, 0xE7C6,0x8305, 0xE7C7,0x8B00, 0xE7C8,0x8B28, 0xE7C9,0x8C8C,\n 0xE7CA,0x6728, 0xE7CB,0x6C90, 0xE7CC,0x7267, 0xE7CD,0x76EE, 0xE7CE,0x7766, 0xE7CF,0x7A46, 0xE7D0,0x9DA9, 0xE7D1,0x6B7F,\n 0xE7D2,0x6C92, 0xE7D3,0x5922, 0xE7D4,0x6726, 0xE7D5,0x8499, 0xE7D6,0x536F, 0xE7D7,0x5893, 0xE7D8,0x5999, 0xE7D9,0x5EDF,\n 0xE7DA,0x63CF, 0xE7DB,0x6634, 0xE7DC,0x6773, 0xE7DD,0x6E3A, 0xE7DE,0x732B, 0xE7DF,0x7AD7, 0xE7E0,0x82D7, 0xE7E1,0x9328,\n 0xE7E2,0x52D9, 0xE7E3,0x5DEB, 0xE7E4,0x61AE, 0xE7E5,0x61CB, 0xE7E6,0x620A, 0xE7E7,0x62C7, 0xE7E8,0x64AB, 0xE7E9,0x65E0,\n 0xE7EA,0x6959, 0xE7EB,0x6B66, 0xE7EC,0x6BCB, 0xE7ED,0x7121, 0xE7EE,0x73F7, 0xE7EF,0x755D, 0xE7F0,0x7E46, 0xE7F1,0x821E,\n 0xE7F2,0x8302, 0xE7F3,0x856A, 0xE7F4,0x8AA3, 0xE7F5,0x8CBF, 0xE7F6,0x9727, 0xE7F7,0x9D61, 0xE7F8,0x58A8, 0xE7F9,0x9ED8,\n 0xE7FA,0x5011, 0xE7FB,0x520E, 0xE7FC,0x543B, 0xE7FD,0x554F, 0xE7FE,0x6587, 0xE831,0x6C76, 0xE832,0x7D0A, 0xE833,0x7D0B,\n 0xE834,0x805E, 0xE835,0x868A, 0xE836,0x9580, 0xE837,0x96EF, 0xE838,0x52FF, 0xE839,0x6C95, 0xE83A,0x7269, 0xE83B,0x5473,\n 0xE83C,0x5A9A, 0xE83D,0x5C3E, 0xE83E,0x5D4B, 0xE83F,0x5F4C, 0xE840,0x5FAE, 0xE841,0x672A, 0xE842,0x68B6, 0xE843,0x6963,\n 0xE844,0x6E3C, 0xE845,0x6E44, 0xE846,0x7709, 0xE847,0x7C73, 0xE848,0x7F8E, 0xE849,0x8587, 0xE84A,0x8B0E, 0xE84B,0x8FF7,\n 0xE84C,0x9761, 0xE84D,0x9EF4, 0xE84E,0x5CB7, 0xE84F,0x60B6, 0xE850,0x610D, 0xE851,0x61AB, 0xE852,0x654F, 0xE853,0x65FB,\n 0xE854,0x65FC, 0xE855,0x6C11, 0xE856,0x6CEF, 0xE857,0x739F, 0xE858,0x73C9, 0xE859,0x7DE1, 0xE85A,0x9594, 0xE85B,0x5BC6,\n 0xE85C,0x871C, 0xE85D,0x8B10, 0xE85E,0x525D, 0xE85F,0x535A, 0xE860,0x62CD, 0xE861,0x640F, 0xE862,0x64B2, 0xE863,0x6734,\n 0xE864,0x6A38, 0xE865,0x6CCA, 0xE866,0x73C0, 0xE867,0x749E, 0xE868,0x7B94, 0xE869,0x7C95, 0xE86A,0x7E1B, 0xE86B,0x818A,\n 0xE86C,0x8236, 0xE86D,0x8584, 0xE86E,0x8FEB, 0xE86F,0x96F9, 0xE870,0x99C1, 0xE871,0x4F34, 0xE872,0x534A, 0xE873,0x53CD,\n 0xE874,0x53DB, 0xE875,0x62CC, 0xE876,0x642C, 0xE877,0x6500, 0xE878,0x6591, 0xE879,0x69C3, 0xE87A,0x6CEE, 0xE87B,0x6F58,\n 0xE87C,0x73ED, 0xE87D,0x7554, 0xE87E,0x7622, 0xE891,0x76E4, 0xE892,0x76FC, 0xE893,0x78D0, 0xE894,0x78FB, 0xE895,0x792C,\n 0xE896,0x7D46, 0xE897,0x822C, 0xE898,0x87E0, 0xE899,0x8FD4, 0xE89A,0x9812, 0xE89B,0x98EF, 0xE89C,0x52C3, 0xE89D,0x62D4,\n 0xE89E,0x64A5, 0xE89F,0x6E24, 0xE8A0,0x6F51, 0xE8A1,0x767C, 0xE8A2,0x8DCB, 0xE8A3,0x91B1, 0xE8A4,0x9262, 0xE8A5,0x9AEE,\n 0xE8A6,0x9B43, 0xE8A7,0x5023, 0xE8A8,0x508D, 0xE8A9,0x574A, 0xE8AA,0x59A8, 0xE8AB,0x5C28, 0xE8AC,0x5E47, 0xE8AD,0x5F77,\n 0xE8AE,0x623F, 0xE8AF,0x653E, 0xE8B0,0x65B9, 0xE8B1,0x65C1, 0xE8B2,0x6609, 0xE8B3,0x678B, 0xE8B4,0x699C, 0xE8B5,0x6EC2,\n 0xE8B6,0x78C5, 0xE8B7,0x7D21, 0xE8B8,0x80AA, 0xE8B9,0x8180, 0xE8BA,0x822B, 0xE8BB,0x82B3, 0xE8BC,0x84A1, 0xE8BD,0x868C,\n 0xE8BE,0x8A2A, 0xE8BF,0x8B17, 0xE8C0,0x90A6, 0xE8C1,0x9632, 0xE8C2,0x9F90, 0xE8C3,0x500D, 0xE8C4,0x4FF3, 0xE8C5,0xF963,\n 0xE8C6,0x57F9, 0xE8C7,0x5F98, 0xE8C8,0x62DC, 0xE8C9,0x6392, 0xE8CA,0x676F, 0xE8CB,0x6E43, 0xE8CC,0x7119, 0xE8CD,0x76C3,\n 0xE8CE,0x80CC, 0xE8CF,0x80DA, 0xE8D0,0x88F4, 0xE8D1,0x88F5, 0xE8D2,0x8919, 0xE8D3,0x8CE0, 0xE8D4,0x8F29, 0xE8D5,0x914D,\n 0xE8D6,0x966A, 0xE8D7,0x4F2F, 0xE8D8,0x4F70, 0xE8D9,0x5E1B, 0xE8DA,0x67CF, 0xE8DB,0x6822, 0xE8DC,0x767D, 0xE8DD,0x767E,\n 0xE8DE,0x9B44, 0xE8DF,0x5E61, 0xE8E0,0x6A0A, 0xE8E1,0x7169, 0xE8E2,0x71D4, 0xE8E3,0x756A, 0xE8E4,0xF964, 0xE8E5,0x7E41,\n 0xE8E6,0x8543, 0xE8E7,0x85E9, 0xE8E8,0x98DC, 0xE8E9,0x4F10, 0xE8EA,0x7B4F, 0xE8EB,0x7F70, 0xE8EC,0x95A5, 0xE8ED,0x51E1,\n 0xE8EE,0x5E06, 0xE8EF,0x68B5, 0xE8F0,0x6C3E, 0xE8F1,0x6C4E, 0xE8F2,0x6CDB, 0xE8F3,0x72AF, 0xE8F4,0x7BC4, 0xE8F5,0x8303,\n 0xE8F6,0x6CD5, 0xE8F7,0x743A, 0xE8F8,0x50FB, 0xE8F9,0x5288, 0xE8FA,0x58C1, 0xE8FB,0x64D8, 0xE8FC,0x6A97, 0xE8FD,0x74A7,\n 0xE8FE,0x7656, 0xE931,0x78A7, 0xE932,0x8617, 0xE933,0x95E2, 0xE934,0x9739, 0xE935,0xF965, 0xE936,0x535E, 0xE937,0x5F01,\n 0xE938,0x8B8A, 0xE939,0x8FA8, 0xE93A,0x8FAF, 0xE93B,0x908A, 0xE93C,0x5225, 0xE93D,0x77A5, 0xE93E,0x9C49, 0xE93F,0x9F08,\n 0xE940,0x4E19, 0xE941,0x5002, 0xE942,0x5175, 0xE943,0x5C5B, 0xE944,0x5E77, 0xE945,0x661E, 0xE946,0x663A, 0xE947,0x67C4,\n 0xE948,0x68C5, 0xE949,0x70B3, 0xE94A,0x7501, 0xE94B,0x75C5, 0xE94C,0x79C9, 0xE94D,0x7ADD, 0xE94E,0x8F27, 0xE94F,0x9920,\n 0xE950,0x9A08, 0xE951,0x4FDD, 0xE952,0x5821, 0xE953,0x5831, 0xE954,0x5BF6, 0xE955,0x666E, 0xE956,0x6B65, 0xE957,0x6D11,\n 0xE958,0x6E7A, 0xE959,0x6F7D, 0xE95A,0x73E4, 0xE95B,0x752B, 0xE95C,0x83E9, 0xE95D,0x88DC, 0xE95E,0x8913, 0xE95F,0x8B5C,\n 0xE960,0x8F14, 0xE961,0x4F0F, 0xE962,0x50D5, 0xE963,0x5310, 0xE964,0x535C, 0xE965,0x5B93, 0xE966,0x5FA9, 0xE967,0x670D,\n 0xE968,0x798F, 0xE969,0x8179, 0xE96A,0x832F, 0xE96B,0x8514, 0xE96C,0x8907, 0xE96D,0x8986, 0xE96E,0x8F39, 0xE96F,0x8F3B,\n 0xE970,0x99A5, 0xE971,0x9C12, 0xE972,0x672C, 0xE973,0x4E76, 0xE974,0x4FF8, 0xE975,0x5949, 0xE976,0x5C01, 0xE977,0x5CEF,\n 0xE978,0x5CF0, 0xE979,0x6367, 0xE97A,0x68D2, 0xE97B,0x70FD, 0xE97C,0x71A2, 0xE97D,0x742B, 0xE97E,0x7E2B, 0xE991,0x84EC,\n 0xE992,0x8702, 0xE993,0x9022, 0xE994,0x92D2, 0xE995,0x9CF3, 0xE996,0x4E0D, 0xE997,0x4ED8, 0xE998,0x4FEF, 0xE999,0x5085,\n 0xE99A,0x5256, 0xE99B,0x526F, 0xE99C,0x5426, 0xE99D,0x5490, 0xE99E,0x57E0, 0xE99F,0x592B, 0xE9A0,0x5A66, 0xE9A1,0x5B5A,\n 0xE9A2,0x5B75, 0xE9A3,0x5BCC, 0xE9A4,0x5E9C, 0xE9A5,0xF966, 0xE9A6,0x6276, 0xE9A7,0x6577, 0xE9A8,0x65A7, 0xE9A9,0x6D6E,\n 0xE9AA,0x6EA5, 0xE9AB,0x7236, 0xE9AC,0x7B26, 0xE9AD,0x7C3F, 0xE9AE,0x7F36, 0xE9AF,0x8150, 0xE9B0,0x8151, 0xE9B1,0x819A,\n 0xE9B2,0x8240, 0xE9B3,0x8299, 0xE9B4,0x83A9, 0xE9B5,0x8A03, 0xE9B6,0x8CA0, 0xE9B7,0x8CE6, 0xE9B8,0x8CFB, 0xE9B9,0x8D74,\n 0xE9BA,0x8DBA, 0xE9BB,0x90E8, 0xE9BC,0x91DC, 0xE9BD,0x961C, 0xE9BE,0x9644, 0xE9BF,0x99D9, 0xE9C0,0x9CE7, 0xE9C1,0x5317,\n 0xE9C2,0x5206, 0xE9C3,0x5429, 0xE9C4,0x5674, 0xE9C5,0x58B3, 0xE9C6,0x5954, 0xE9C7,0x596E, 0xE9C8,0x5FFF, 0xE9C9,0x61A4,\n 0xE9CA,0x626E, 0xE9CB,0x6610, 0xE9CC,0x6C7E, 0xE9CD,0x711A, 0xE9CE,0x76C6, 0xE9CF,0x7C89, 0xE9D0,0x7CDE, 0xE9D1,0x7D1B,\n 0xE9D2,0x82AC, 0xE9D3,0x8CC1, 0xE9D4,0x96F0, 0xE9D5,0xF967, 0xE9D6,0x4F5B, 0xE9D7,0x5F17, 0xE9D8,0x5F7F, 0xE9D9,0x62C2,\n 0xE9DA,0x5D29, 0xE9DB,0x670B, 0xE9DC,0x68DA, 0xE9DD,0x787C, 0xE9DE,0x7E43, 0xE9DF,0x9D6C, 0xE9E0,0x4E15, 0xE9E1,0x5099,\n 0xE9E2,0x5315, 0xE9E3,0x532A, 0xE9E4,0x5351, 0xE9E5,0x5983, 0xE9E6,0x5A62, 0xE9E7,0x5E87, 0xE9E8,0x60B2, 0xE9E9,0x618A,\n 0xE9EA,0x6249, 0xE9EB,0x6279, 0xE9EC,0x6590, 0xE9ED,0x6787, 0xE9EE,0x69A7, 0xE9EF,0x6BD4, 0xE9F0,0x6BD6, 0xE9F1,0x6BD7,\n 0xE9F2,0x6BD8, 0xE9F3,0x6CB8, 0xE9F4,0xF968, 0xE9F5,0x7435, 0xE9F6,0x75FA, 0xE9F7,0x7812, 0xE9F8,0x7891, 0xE9F9,0x79D5,\n 0xE9FA,0x79D8, 0xE9FB,0x7C83, 0xE9FC,0x7DCB, 0xE9FD,0x7FE1, 0xE9FE,0x80A5, 0xEA31,0x813E, 0xEA32,0x81C2, 0xEA33,0x83F2,\n 0xEA34,0x871A, 0xEA35,0x88E8, 0xEA36,0x8AB9, 0xEA37,0x8B6C, 0xEA38,0x8CBB, 0xEA39,0x9119, 0xEA3A,0x975E, 0xEA3B,0x98DB,\n 0xEA3C,0x9F3B, 0xEA3D,0x56AC, 0xEA3E,0x5B2A, 0xEA3F,0x5F6C, 0xEA40,0x658C, 0xEA41,0x6AB3, 0xEA42,0x6BAF, 0xEA43,0x6D5C,\n 0xEA44,0x6FF1, 0xEA45,0x7015, 0xEA46,0x725D, 0xEA47,0x73AD, 0xEA48,0x8CA7, 0xEA49,0x8CD3, 0xEA4A,0x983B, 0xEA4B,0x6191,\n 0xEA4C,0x6C37, 0xEA4D,0x8058, 0xEA4E,0x9A01, 0xEA4F,0x4E4D, 0xEA50,0x4E8B, 0xEA51,0x4E9B, 0xEA52,0x4ED5, 0xEA53,0x4F3A,\n 0xEA54,0x4F3C, 0xEA55,0x4F7F, 0xEA56,0x4FDF, 0xEA57,0x50FF, 0xEA58,0x53F2, 0xEA59,0x53F8, 0xEA5A,0x5506, 0xEA5B,0x55E3,\n 0xEA5C,0x56DB, 0xEA5D,0x58EB, 0xEA5E,0x5962, 0xEA5F,0x5A11, 0xEA60,0x5BEB, 0xEA61,0x5BFA, 0xEA62,0x5C04, 0xEA63,0x5DF3,\n 0xEA64,0x5E2B, 0xEA65,0x5F99, 0xEA66,0x601D, 0xEA67,0x6368, 0xEA68,0x659C, 0xEA69,0x65AF, 0xEA6A,0x67F6, 0xEA6B,0x67FB,\n 0xEA6C,0x68AD, 0xEA6D,0x6B7B, 0xEA6E,0x6C99, 0xEA6F,0x6CD7, 0xEA70,0x6E23, 0xEA71,0x7009, 0xEA72,0x7345, 0xEA73,0x7802,\n 0xEA74,0x793E, 0xEA75,0x7940, 0xEA76,0x7960, 0xEA77,0x79C1, 0xEA78,0x7BE9, 0xEA79,0x7D17, 0xEA7A,0x7D72, 0xEA7B,0x8086,\n 0xEA7C,0x820D, 0xEA7D,0x838E, 0xEA7E,0x84D1, 0xEA91,0x86C7, 0xEA92,0x88DF, 0xEA93,0x8A50, 0xEA94,0x8A5E, 0xEA95,0x8B1D,\n 0xEA96,0x8CDC, 0xEA97,0x8D66, 0xEA98,0x8FAD, 0xEA99,0x90AA, 0xEA9A,0x98FC, 0xEA9B,0x99DF, 0xEA9C,0x9E9D, 0xEA9D,0x524A,\n 0xEA9E,0xF969, 0xEA9F,0x6714, 0xEAA0,0xF96A, 0xEAA1,0x5098, 0xEAA2,0x522A, 0xEAA3,0x5C71, 0xEAA4,0x6563, 0xEAA5,0x6C55,\n 0xEAA6,0x73CA, 0xEAA7,0x7523, 0xEAA8,0x759D, 0xEAA9,0x7B97, 0xEAAA,0x849C, 0xEAAB,0x9178, 0xEAAC,0x9730, 0xEAAD,0x4E77,\n 0xEAAE,0x6492, 0xEAAF,0x6BBA, 0xEAB0,0x715E, 0xEAB1,0x85A9, 0xEAB2,0x4E09, 0xEAB3,0xF96B, 0xEAB4,0x6749, 0xEAB5,0x68EE,\n 0xEAB6,0x6E17, 0xEAB7,0x829F, 0xEAB8,0x8518, 0xEAB9,0x886B, 0xEABA,0x63F7, 0xEABB,0x6F81, 0xEABC,0x9212, 0xEABD,0x98AF,\n 0xEABE,0x4E0A, 0xEABF,0x50B7, 0xEAC0,0x50CF, 0xEAC1,0x511F, 0xEAC2,0x5546, 0xEAC3,0x55AA, 0xEAC4,0x5617, 0xEAC5,0x5B40,\n 0xEAC6,0x5C19, 0xEAC7,0x5CE0, 0xEAC8,0x5E38, 0xEAC9,0x5E8A, 0xEACA,0x5EA0, 0xEACB,0x5EC2, 0xEACC,0x60F3, 0xEACD,0x6851,\n 0xEACE,0x6A61, 0xEACF,0x6E58, 0xEAD0,0x723D, 0xEAD1,0x7240, 0xEAD2,0x72C0, 0xEAD3,0x76F8, 0xEAD4,0x7965, 0xEAD5,0x7BB1,\n 0xEAD6,0x7FD4, 0xEAD7,0x88F3, 0xEAD8,0x89F4, 0xEAD9,0x8A73, 0xEADA,0x8C61, 0xEADB,0x8CDE, 0xEADC,0x971C, 0xEADD,0x585E,\n 0xEADE,0x74BD, 0xEADF,0x8CFD, 0xEAE0,0x55C7, 0xEAE1,0xF96C, 0xEAE2,0x7A61, 0xEAE3,0x7D22, 0xEAE4,0x8272, 0xEAE5,0x7272,\n 0xEAE6,0x751F, 0xEAE7,0x7525, 0xEAE8,0xF96D, 0xEAE9,0x7B19, 0xEAEA,0x5885, 0xEAEB,0x58FB, 0xEAEC,0x5DBC, 0xEAED,0x5E8F,\n 0xEAEE,0x5EB6, 0xEAEF,0x5F90, 0xEAF0,0x6055, 0xEAF1,0x6292, 0xEAF2,0x637F, 0xEAF3,0x654D, 0xEAF4,0x6691, 0xEAF5,0x66D9,\n 0xEAF6,0x66F8, 0xEAF7,0x6816, 0xEAF8,0x68F2, 0xEAF9,0x7280, 0xEAFA,0x745E, 0xEAFB,0x7B6E, 0xEAFC,0x7D6E, 0xEAFD,0x7DD6,\n 0xEAFE,0x7F72, 0xEB31,0x80E5, 0xEB32,0x8212, 0xEB33,0x85AF, 0xEB34,0x897F, 0xEB35,0x8A93, 0xEB36,0x901D, 0xEB37,0x92E4,\n 0xEB38,0x9ECD, 0xEB39,0x9F20, 0xEB3A,0x5915, 0xEB3B,0x596D, 0xEB3C,0x5E2D, 0xEB3D,0x60DC, 0xEB3E,0x6614, 0xEB3F,0x6673,\n 0xEB40,0x6790, 0xEB41,0x6C50, 0xEB42,0x6DC5, 0xEB43,0x6F5F, 0xEB44,0x77F3, 0xEB45,0x78A9, 0xEB46,0x84C6, 0xEB47,0x91CB,\n 0xEB48,0x932B, 0xEB49,0x4ED9, 0xEB4A,0x50CA, 0xEB4B,0x5148, 0xEB4C,0x5584, 0xEB4D,0x5B0B, 0xEB4E,0x5BA3, 0xEB4F,0x6247,\n 0xEB50,0x657E, 0xEB51,0x65CB, 0xEB52,0x6E32, 0xEB53,0x717D, 0xEB54,0x7401, 0xEB55,0x7444, 0xEB56,0x7487, 0xEB57,0x74BF,\n 0xEB58,0x766C, 0xEB59,0x79AA, 0xEB5A,0x7DDA, 0xEB5B,0x7E55, 0xEB5C,0x7FA8, 0xEB5D,0x817A, 0xEB5E,0x81B3, 0xEB5F,0x8239,\n 0xEB60,0x861A, 0xEB61,0x87EC, 0xEB62,0x8A75, 0xEB63,0x8DE3, 0xEB64,0x9078, 0xEB65,0x9291, 0xEB66,0x9425, 0xEB67,0x994D,\n 0xEB68,0x9BAE, 0xEB69,0x5368, 0xEB6A,0x5C51, 0xEB6B,0x6954, 0xEB6C,0x6CC4, 0xEB6D,0x6D29, 0xEB6E,0x6E2B, 0xEB6F,0x820C,\n 0xEB70,0x859B, 0xEB71,0x893B, 0xEB72,0x8A2D, 0xEB73,0x8AAA, 0xEB74,0x96EA, 0xEB75,0x9F67, 0xEB76,0x5261, 0xEB77,0x66B9,\n 0xEB78,0x6BB2, 0xEB79,0x7E96, 0xEB7A,0x87FE, 0xEB7B,0x8D0D, 0xEB7C,0x9583, 0xEB7D,0x965D, 0xEB7E,0x651D, 0xEB91,0x6D89,\n 0xEB92,0x71EE, 0xEB93,0xF96E, 0xEB94,0x57CE, 0xEB95,0x59D3, 0xEB96,0x5BAC, 0xEB97,0x6027, 0xEB98,0x60FA, 0xEB99,0x6210,\n 0xEB9A,0x661F, 0xEB9B,0x665F, 0xEB9C,0x7329, 0xEB9D,0x73F9, 0xEB9E,0x76DB, 0xEB9F,0x7701, 0xEBA0,0x7B6C, 0xEBA1,0x8056,\n 0xEBA2,0x8072, 0xEBA3,0x8165, 0xEBA4,0x8AA0, 0xEBA5,0x9192, 0xEBA6,0x4E16, 0xEBA7,0x52E2, 0xEBA8,0x6B72, 0xEBA9,0x6D17,\n 0xEBAA,0x7A05, 0xEBAB,0x7B39, 0xEBAC,0x7D30, 0xEBAD,0xF96F, 0xEBAE,0x8CB0, 0xEBAF,0x53EC, 0xEBB0,0x562F, 0xEBB1,0x5851,\n 0xEBB2,0x5BB5, 0xEBB3,0x5C0F, 0xEBB4,0x5C11, 0xEBB5,0x5DE2, 0xEBB6,0x6240, 0xEBB7,0x6383, 0xEBB8,0x6414, 0xEBB9,0x662D,\n 0xEBBA,0x68B3, 0xEBBB,0x6CBC, 0xEBBC,0x6D88, 0xEBBD,0x6EAF, 0xEBBE,0x701F, 0xEBBF,0x70A4, 0xEBC0,0x71D2, 0xEBC1,0x7526,\n 0xEBC2,0x758F, 0xEBC3,0x758E, 0xEBC4,0x7619, 0xEBC5,0x7B11, 0xEBC6,0x7BE0, 0xEBC7,0x7C2B, 0xEBC8,0x7D20, 0xEBC9,0x7D39,\n 0xEBCA,0x852C, 0xEBCB,0x856D, 0xEBCC,0x8607, 0xEBCD,0x8A34, 0xEBCE,0x900D, 0xEBCF,0x9061, 0xEBD0,0x90B5, 0xEBD1,0x92B7,\n 0xEBD2,0x97F6, 0xEBD3,0x9A37, 0xEBD4,0x4FD7, 0xEBD5,0x5C6C, 0xEBD6,0x675F, 0xEBD7,0x6D91, 0xEBD8,0x7C9F, 0xEBD9,0x7E8C,\n 0xEBDA,0x8B16, 0xEBDB,0x8D16, 0xEBDC,0x901F, 0xEBDD,0x5B6B, 0xEBDE,0x5DFD, 0xEBDF,0x640D, 0xEBE0,0x84C0, 0xEBE1,0x905C,\n 0xEBE2,0x98E1, 0xEBE3,0x7387, 0xEBE4,0x5B8B, 0xEBE5,0x609A, 0xEBE6,0x677E, 0xEBE7,0x6DDE, 0xEBE8,0x8A1F, 0xEBE9,0x8AA6,\n 0xEBEA,0x9001, 0xEBEB,0x980C, 0xEBEC,0x5237, 0xEBED,0xF970, 0xEBEE,0x7051, 0xEBEF,0x788E, 0xEBF0,0x9396, 0xEBF1,0x8870,\n 0xEBF2,0x91D7, 0xEBF3,0x4FEE, 0xEBF4,0x53D7, 0xEBF5,0x55FD, 0xEBF6,0x56DA, 0xEBF7,0x5782, 0xEBF8,0x58FD, 0xEBF9,0x5AC2,\n 0xEBFA,0x5B88, 0xEBFB,0x5CAB, 0xEBFC,0x5CC0, 0xEBFD,0x5E25, 0xEBFE,0x6101, 0xEC31,0x620D, 0xEC32,0x624B, 0xEC33,0x6388,\n 0xEC34,0x641C, 0xEC35,0x6536, 0xEC36,0x6578, 0xEC37,0x6A39, 0xEC38,0x6B8A, 0xEC39,0x6C34, 0xEC3A,0x6D19, 0xEC3B,0x6F31,\n 0xEC3C,0x71E7, 0xEC3D,0x72E9, 0xEC3E,0x7378, 0xEC3F,0x7407, 0xEC40,0x74B2, 0xEC41,0x7626, 0xEC42,0x7761, 0xEC43,0x79C0,\n 0xEC44,0x7A57, 0xEC45,0x7AEA, 0xEC46,0x7CB9, 0xEC47,0x7D8F, 0xEC48,0x7DAC, 0xEC49,0x7E61, 0xEC4A,0x7F9E, 0xEC4B,0x8129,\n 0xEC4C,0x8331, 0xEC4D,0x8490, 0xEC4E,0x84DA, 0xEC4F,0x85EA, 0xEC50,0x8896, 0xEC51,0x8AB0, 0xEC52,0x8B90, 0xEC53,0x8F38,\n 0xEC54,0x9042, 0xEC55,0x9083, 0xEC56,0x916C, 0xEC57,0x9296, 0xEC58,0x92B9, 0xEC59,0x968B, 0xEC5A,0x96A7, 0xEC5B,0x96A8,\n 0xEC5C,0x96D6, 0xEC5D,0x9700, 0xEC5E,0x9808, 0xEC5F,0x9996, 0xEC60,0x9AD3, 0xEC61,0x9B1A, 0xEC62,0x53D4, 0xEC63,0x587E,\n 0xEC64,0x5919, 0xEC65,0x5B70, 0xEC66,0x5BBF, 0xEC67,0x6DD1, 0xEC68,0x6F5A, 0xEC69,0x719F, 0xEC6A,0x7421, 0xEC6B,0x74B9,\n 0xEC6C,0x8085, 0xEC6D,0x83FD, 0xEC6E,0x5DE1, 0xEC6F,0x5F87, 0xEC70,0x5FAA, 0xEC71,0x6042, 0xEC72,0x65EC, 0xEC73,0x6812,\n 0xEC74,0x696F, 0xEC75,0x6A53, 0xEC76,0x6B89, 0xEC77,0x6D35, 0xEC78,0x6DF3, 0xEC79,0x73E3, 0xEC7A,0x76FE, 0xEC7B,0x77AC,\n 0xEC7C,0x7B4D, 0xEC7D,0x7D14, 0xEC7E,0x8123, 0xEC91,0x821C, 0xEC92,0x8340, 0xEC93,0x84F4, 0xEC94,0x8563, 0xEC95,0x8A62,\n 0xEC96,0x8AC4, 0xEC97,0x9187, 0xEC98,0x931E, 0xEC99,0x9806, 0xEC9A,0x99B4, 0xEC9B,0x620C, 0xEC9C,0x8853, 0xEC9D,0x8FF0,\n 0xEC9E,0x9265, 0xEC9F,0x5D07, 0xECA0,0x5D27, 0xECA1,0x5D69, 0xECA2,0x745F, 0xECA3,0x819D, 0xECA4,0x8768, 0xECA5,0x6FD5,\n 0xECA6,0x62FE, 0xECA7,0x7FD2, 0xECA8,0x8936, 0xECA9,0x8972, 0xECAA,0x4E1E, 0xECAB,0x4E58, 0xECAC,0x50E7, 0xECAD,0x52DD,\n 0xECAE,0x5347, 0xECAF,0x627F, 0xECB0,0x6607, 0xECB1,0x7E69, 0xECB2,0x8805, 0xECB3,0x965E, 0xECB4,0x4F8D, 0xECB5,0x5319,\n 0xECB6,0x5636, 0xECB7,0x59CB, 0xECB8,0x5AA4, 0xECB9,0x5C38, 0xECBA,0x5C4E, 0xECBB,0x5C4D, 0xECBC,0x5E02, 0xECBD,0x5F11,\n 0xECBE,0x6043, 0xECBF,0x65BD, 0xECC0,0x662F, 0xECC1,0x6642, 0xECC2,0x67BE, 0xECC3,0x67F4, 0xECC4,0x731C, 0xECC5,0x77E2,\n 0xECC6,0x793A, 0xECC7,0x7FC5, 0xECC8,0x8494, 0xECC9,0x84CD, 0xECCA,0x8996, 0xECCB,0x8A66, 0xECCC,0x8A69, 0xECCD,0x8AE1,\n 0xECCE,0x8C55, 0xECCF,0x8C7A, 0xECD0,0x57F4, 0xECD1,0x5BD4, 0xECD2,0x5F0F, 0xECD3,0x606F, 0xECD4,0x62ED, 0xECD5,0x690D,\n 0xECD6,0x6B96, 0xECD7,0x6E5C, 0xECD8,0x7184, 0xECD9,0x7BD2, 0xECDA,0x8755, 0xECDB,0x8B58, 0xECDC,0x8EFE, 0xECDD,0x98DF,\n 0xECDE,0x98FE, 0xECDF,0x4F38, 0xECE0,0x4F81, 0xECE1,0x4FE1, 0xECE2,0x547B, 0xECE3,0x5A20, 0xECE4,0x5BB8, 0xECE5,0x613C,\n 0xECE6,0x65B0, 0xECE7,0x6668, 0xECE8,0x71FC, 0xECE9,0x7533, 0xECEA,0x795E, 0xECEB,0x7D33, 0xECEC,0x814E, 0xECED,0x81E3,\n 0xECEE,0x8398, 0xECEF,0x85AA, 0xECF0,0x85CE, 0xECF1,0x8703, 0xECF2,0x8A0A, 0xECF3,0x8EAB, 0xECF4,0x8F9B, 0xECF5,0xF971,\n 0xECF6,0x8FC5, 0xECF7,0x5931, 0xECF8,0x5BA4, 0xECF9,0x5BE6, 0xECFA,0x6089, 0xECFB,0x5BE9, 0xECFC,0x5C0B, 0xECFD,0x5FC3,\n 0xECFE,0x6C81, 0xED31,0xF972, 0xED32,0x6DF1, 0xED33,0x700B, 0xED34,0x751A, 0xED35,0x82AF, 0xED36,0x8AF6, 0xED37,0x4EC0,\n 0xED38,0x5341, 0xED39,0xF973, 0xED3A,0x96D9, 0xED3B,0x6C0F, 0xED3C,0x4E9E, 0xED3D,0x4FC4, 0xED3E,0x5152, 0xED3F,0x555E,\n 0xED40,0x5A25, 0xED41,0x5CE8, 0xED42,0x6211, 0xED43,0x7259, 0xED44,0x82BD, 0xED45,0x83AA, 0xED46,0x86FE, 0xED47,0x8859,\n 0xED48,0x8A1D, 0xED49,0x963F, 0xED4A,0x96C5, 0xED4B,0x9913, 0xED4C,0x9D09, 0xED4D,0x9D5D, 0xED4E,0x580A, 0xED4F,0x5CB3,\n 0xED50,0x5DBD, 0xED51,0x5E44, 0xED52,0x60E1, 0xED53,0x6115, 0xED54,0x63E1, 0xED55,0x6A02, 0xED56,0x6E25, 0xED57,0x9102,\n 0xED58,0x9354, 0xED59,0x984E, 0xED5A,0x9C10, 0xED5B,0x9F77, 0xED5C,0x5B89, 0xED5D,0x5CB8, 0xED5E,0x6309, 0xED5F,0x664F,\n 0xED60,0x6848, 0xED61,0x773C, 0xED62,0x96C1, 0xED63,0x978D, 0xED64,0x9854, 0xED65,0x9B9F, 0xED66,0x65A1, 0xED67,0x8B01,\n 0xED68,0x8ECB, 0xED69,0x95BC, 0xED6A,0x5535, 0xED6B,0x5CA9, 0xED6C,0x5DD6, 0xED6D,0x5EB5, 0xED6E,0x6697, 0xED6F,0x764C,\n 0xED70,0x83F4, 0xED71,0x95C7, 0xED72,0x58D3, 0xED73,0x62BC, 0xED74,0x72CE, 0xED75,0x9D28, 0xED76,0x4EF0, 0xED77,0x592E,\n 0xED78,0x600F, 0xED79,0x663B, 0xED7A,0x6B83, 0xED7B,0x79E7, 0xED7C,0x9D26, 0xED7D,0x5393, 0xED7E,0x54C0, 0xED91,0x57C3,\n 0xED92,0x5D16, 0xED93,0x611B, 0xED94,0x66D6, 0xED95,0x6DAF, 0xED96,0x788D, 0xED97,0x827E, 0xED98,0x9698, 0xED99,0x9744,\n 0xED9A,0x5384, 0xED9B,0x627C, 0xED9C,0x6396, 0xED9D,0x6DB2, 0xED9E,0x7E0A, 0xED9F,0x814B, 0xEDA0,0x984D, 0xEDA1,0x6AFB,\n 0xEDA2,0x7F4C, 0xEDA3,0x9DAF, 0xEDA4,0x9E1A, 0xEDA5,0x4E5F, 0xEDA6,0x503B, 0xEDA7,0x51B6, 0xEDA8,0x591C, 0xEDA9,0x60F9,\n 0xEDAA,0x63F6, 0xEDAB,0x6930, 0xEDAC,0x723A, 0xEDAD,0x8036, 0xEDAE,0xF974, 0xEDAF,0x91CE, 0xEDB0,0x5F31, 0xEDB1,0xF975,\n 0xEDB2,0xF976, 0xEDB3,0x7D04, 0xEDB4,0x82E5, 0xEDB5,0x846F, 0xEDB6,0x84BB, 0xEDB7,0x85E5, 0xEDB8,0x8E8D, 0xEDB9,0xF977,\n 0xEDBA,0x4F6F, 0xEDBB,0xF978, 0xEDBC,0xF979, 0xEDBD,0x58E4, 0xEDBE,0x5B43, 0xEDBF,0x6059, 0xEDC0,0x63DA, 0xEDC1,0x6518,\n 0xEDC2,0x656D, 0xEDC3,0x6698, 0xEDC4,0xF97A, 0xEDC5,0x694A, 0xEDC6,0x6A23, 0xEDC7,0x6D0B, 0xEDC8,0x7001, 0xEDC9,0x716C,\n 0xEDCA,0x75D2, 0xEDCB,0x760D, 0xEDCC,0x79B3, 0xEDCD,0x7A70, 0xEDCE,0xF97B, 0xEDCF,0x7F8A, 0xEDD0,0xF97C, 0xEDD1,0x8944,\n 0xEDD2,0xF97D, 0xEDD3,0x8B93, 0xEDD4,0x91C0, 0xEDD5,0x967D, 0xEDD6,0xF97E, 0xEDD7,0x990A, 0xEDD8,0x5704, 0xEDD9,0x5FA1,\n 0xEDDA,0x65BC, 0xEDDB,0x6F01, 0xEDDC,0x7600, 0xEDDD,0x79A6, 0xEDDE,0x8A9E, 0xEDDF,0x99AD, 0xEDE0,0x9B5A, 0xEDE1,0x9F6C,\n 0xEDE2,0x5104, 0xEDE3,0x61B6, 0xEDE4,0x6291, 0xEDE5,0x6A8D, 0xEDE6,0x81C6, 0xEDE7,0x5043, 0xEDE8,0x5830, 0xEDE9,0x5F66,\n 0xEDEA,0x7109, 0xEDEB,0x8A00, 0xEDEC,0x8AFA, 0xEDED,0x5B7C, 0xEDEE,0x8616, 0xEDEF,0x4FFA, 0xEDF0,0x513C, 0xEDF1,0x56B4,\n 0xEDF2,0x5944, 0xEDF3,0x63A9, 0xEDF4,0x6DF9, 0xEDF5,0x5DAA, 0xEDF6,0x696D, 0xEDF7,0x5186, 0xEDF8,0x4E88, 0xEDF9,0x4F59,\n 0xEDFA,0xF97F, 0xEDFB,0xF980, 0xEDFC,0xF981, 0xEDFD,0x5982, 0xEDFE,0xF982, 0xEE31,0xF983, 0xEE32,0x6B5F, 0xEE33,0x6C5D,\n 0xEE34,0xF984, 0xEE35,0x74B5, 0xEE36,0x7916, 0xEE37,0xF985, 0xEE38,0x8207, 0xEE39,0x8245, 0xEE3A,0x8339, 0xEE3B,0x8F3F,\n 0xEE3C,0x8F5D, 0xEE3D,0xF986, 0xEE3E,0x9918, 0xEE3F,0xF987, 0xEE40,0xF988, 0xEE41,0xF989, 0xEE42,0x4EA6, 0xEE43,0xF98A,\n 0xEE44,0x57DF, 0xEE45,0x5F79, 0xEE46,0x6613, 0xEE47,0xF98B, 0xEE48,0xF98C, 0xEE49,0x75AB, 0xEE4A,0x7E79, 0xEE4B,0x8B6F,\n 0xEE4C,0xF98D, 0xEE4D,0x9006, 0xEE4E,0x9A5B, 0xEE4F,0x56A5, 0xEE50,0x5827, 0xEE51,0x59F8, 0xEE52,0x5A1F, 0xEE53,0x5BB4,\n 0xEE54,0xF98E, 0xEE55,0x5EF6, 0xEE56,0xF98F, 0xEE57,0xF990, 0xEE58,0x6350, 0xEE59,0x633B, 0xEE5A,0xF991, 0xEE5B,0x693D,\n 0xEE5C,0x6C87, 0xEE5D,0x6CBF, 0xEE5E,0x6D8E, 0xEE5F,0x6D93, 0xEE60,0x6DF5, 0xEE61,0x6F14, 0xEE62,0xF992, 0xEE63,0x70DF,\n 0xEE64,0x7136, 0xEE65,0x7159, 0xEE66,0xF993, 0xEE67,0x71C3, 0xEE68,0x71D5, 0xEE69,0xF994, 0xEE6A,0x784F, 0xEE6B,0x786F,\n 0xEE6C,0xF995, 0xEE6D,0x7B75, 0xEE6E,0x7DE3, 0xEE6F,0xF996, 0xEE70,0x7E2F, 0xEE71,0xF997, 0xEE72,0x884D, 0xEE73,0x8EDF,\n 0xEE74,0xF998, 0xEE75,0xF999, 0xEE76,0xF99A, 0xEE77,0x925B, 0xEE78,0xF99B, 0xEE79,0x9CF6, 0xEE7A,0xF99C, 0xEE7B,0xF99D,\n 0xEE7C,0xF99E, 0xEE7D,0x6085, 0xEE7E,0x6D85, 0xEE91,0xF99F, 0xEE92,0x71B1, 0xEE93,0xF9A0, 0xEE94,0xF9A1, 0xEE95,0x95B1,\n 0xEE96,0x53AD, 0xEE97,0xF9A2, 0xEE98,0xF9A3, 0xEE99,0xF9A4, 0xEE9A,0x67D3, 0xEE9B,0xF9A5, 0xEE9C,0x708E, 0xEE9D,0x7130,\n 0xEE9E,0x7430, 0xEE9F,0x8276, 0xEEA0,0x82D2, 0xEEA1,0xF9A6, 0xEEA2,0x95BB, 0xEEA3,0x9AE5, 0xEEA4,0x9E7D, 0xEEA5,0x66C4,\n 0xEEA6,0xF9A7, 0xEEA7,0x71C1, 0xEEA8,0x8449, 0xEEA9,0xF9A8, 0xEEAA,0xF9A9, 0xEEAB,0x584B, 0xEEAC,0xF9AA, 0xEEAD,0xF9AB,\n 0xEEAE,0x5DB8, 0xEEAF,0x5F71, 0xEEB0,0xF9AC, 0xEEB1,0x6620, 0xEEB2,0x668E, 0xEEB3,0x6979, 0xEEB4,0x69AE, 0xEEB5,0x6C38,\n 0xEEB6,0x6CF3, 0xEEB7,0x6E36, 0xEEB8,0x6F41, 0xEEB9,0x6FDA, 0xEEBA,0x701B, 0xEEBB,0x702F, 0xEEBC,0x7150, 0xEEBD,0x71DF,\n 0xEEBE,0x7370, 0xEEBF,0xF9AD, 0xEEC0,0x745B, 0xEEC1,0xF9AE, 0xEEC2,0x74D4, 0xEEC3,0x76C8, 0xEEC4,0x7A4E, 0xEEC5,0x7E93,\n 0xEEC6,0xF9AF, 0xEEC7,0xF9B0, 0xEEC8,0x82F1, 0xEEC9,0x8A60, 0xEECA,0x8FCE, 0xEECB,0xF9B1, 0xEECC,0x9348, 0xEECD,0xF9B2,\n 0xEECE,0x9719, 0xEECF,0xF9B3, 0xEED0,0xF9B4, 0xEED1,0x4E42, 0xEED2,0x502A, 0xEED3,0xF9B5, 0xEED4,0x5208, 0xEED5,0x53E1,\n 0xEED6,0x66F3, 0xEED7,0x6C6D, 0xEED8,0x6FCA, 0xEED9,0x730A, 0xEEDA,0x777F, 0xEEDB,0x7A62, 0xEEDC,0x82AE, 0xEEDD,0x85DD,\n 0xEEDE,0x8602, 0xEEDF,0xF9B6, 0xEEE0,0x88D4, 0xEEE1,0x8A63, 0xEEE2,0x8B7D, 0xEEE3,0x8C6B, 0xEEE4,0xF9B7, 0xEEE5,0x92B3,\n 0xEEE6,0xF9B8, 0xEEE7,0x9713, 0xEEE8,0x9810, 0xEEE9,0x4E94, 0xEEEA,0x4F0D, 0xEEEB,0x4FC9, 0xEEEC,0x50B2, 0xEEED,0x5348,\n 0xEEEE,0x543E, 0xEEEF,0x5433, 0xEEF0,0x55DA, 0xEEF1,0x5862, 0xEEF2,0x58BA, 0xEEF3,0x5967, 0xEEF4,0x5A1B, 0xEEF5,0x5BE4,\n 0xEEF6,0x609F, 0xEEF7,0xF9B9, 0xEEF8,0x61CA, 0xEEF9,0x6556, 0xEEFA,0x65FF, 0xEEFB,0x6664, 0xEEFC,0x68A7, 0xEEFD,0x6C5A,\n 0xEEFE,0x6FB3, 0xEF31,0x70CF, 0xEF32,0x71AC, 0xEF33,0x7352, 0xEF34,0x7B7D, 0xEF35,0x8708, 0xEF36,0x8AA4, 0xEF37,0x9C32,\n 0xEF38,0x9F07, 0xEF39,0x5C4B, 0xEF3A,0x6C83, 0xEF3B,0x7344, 0xEF3C,0x7389, 0xEF3D,0x923A, 0xEF3E,0x6EAB, 0xEF3F,0x7465,\n 0xEF40,0x761F, 0xEF41,0x7A69, 0xEF42,0x7E15, 0xEF43,0x860A, 0xEF44,0x5140, 0xEF45,0x58C5, 0xEF46,0x64C1, 0xEF47,0x74EE,\n 0xEF48,0x7515, 0xEF49,0x7670, 0xEF4A,0x7FC1, 0xEF4B,0x9095, 0xEF4C,0x96CD, 0xEF4D,0x9954, 0xEF4E,0x6E26, 0xEF4F,0x74E6,\n 0xEF50,0x7AA9, 0xEF51,0x7AAA, 0xEF52,0x81E5, 0xEF53,0x86D9, 0xEF54,0x8778, 0xEF55,0x8A1B, 0xEF56,0x5A49, 0xEF57,0x5B8C,\n 0xEF58,0x5B9B, 0xEF59,0x68A1, 0xEF5A,0x6900, 0xEF5B,0x6D63, 0xEF5C,0x73A9, 0xEF5D,0x7413, 0xEF5E,0x742C, 0xEF5F,0x7897,\n 0xEF60,0x7DE9, 0xEF61,0x7FEB, 0xEF62,0x8118, 0xEF63,0x8155, 0xEF64,0x839E, 0xEF65,0x8C4C, 0xEF66,0x962E, 0xEF67,0x9811,\n 0xEF68,0x66F0, 0xEF69,0x5F80, 0xEF6A,0x65FA, 0xEF6B,0x6789, 0xEF6C,0x6C6A, 0xEF6D,0x738B, 0xEF6E,0x502D, 0xEF6F,0x5A03,\n 0xEF70,0x6B6A, 0xEF71,0x77EE, 0xEF72,0x5916, 0xEF73,0x5D6C, 0xEF74,0x5DCD, 0xEF75,0x7325, 0xEF76,0x754F, 0xEF77,0xF9BA,\n 0xEF78,0xF9BB, 0xEF79,0x50E5, 0xEF7A,0x51F9, 0xEF7B,0x582F, 0xEF7C,0x592D, 0xEF7D,0x5996, 0xEF7E,0x59DA, 0xEF91,0x5BE5,\n 0xEF92,0xF9BC, 0xEF93,0xF9BD, 0xEF94,0x5DA2, 0xEF95,0x62D7, 0xEF96,0x6416, 0xEF97,0x6493, 0xEF98,0x64FE, 0xEF99,0xF9BE,\n 0xEF9A,0x66DC, 0xEF9B,0xF9BF, 0xEF9C,0x6A48, 0xEF9D,0xF9C0, 0xEF9E,0x71FF, 0xEF9F,0x7464, 0xEFA0,0xF9C1, 0xEFA1,0x7A88,\n 0xEFA2,0x7AAF, 0xEFA3,0x7E47, 0xEFA4,0x7E5E, 0xEFA5,0x8000, 0xEFA6,0x8170, 0xEFA7,0xF9C2, 0xEFA8,0x87EF, 0xEFA9,0x8981,\n 0xEFAA,0x8B20, 0xEFAB,0x9059, 0xEFAC,0xF9C3, 0xEFAD,0x9080, 0xEFAE,0x9952, 0xEFAF,0x617E, 0xEFB0,0x6B32, 0xEFB1,0x6D74,\n 0xEFB2,0x7E1F, 0xEFB3,0x8925, 0xEFB4,0x8FB1, 0xEFB5,0x4FD1, 0xEFB6,0x50AD, 0xEFB7,0x5197, 0xEFB8,0x52C7, 0xEFB9,0x57C7,\n 0xEFBA,0x5889, 0xEFBB,0x5BB9, 0xEFBC,0x5EB8, 0xEFBD,0x6142, 0xEFBE,0x6995, 0xEFBF,0x6D8C, 0xEFC0,0x6E67, 0xEFC1,0x6EB6,\n 0xEFC2,0x7194, 0xEFC3,0x7462, 0xEFC4,0x7528, 0xEFC5,0x752C, 0xEFC6,0x8073, 0xEFC7,0x8338, 0xEFC8,0x84C9, 0xEFC9,0x8E0A,\n 0xEFCA,0x9394, 0xEFCB,0x93DE, 0xEFCC,0xF9C4, 0xEFCD,0x4E8E, 0xEFCE,0x4F51, 0xEFCF,0x5076, 0xEFD0,0x512A, 0xEFD1,0x53C8,\n 0xEFD2,0x53CB, 0xEFD3,0x53F3, 0xEFD4,0x5B87, 0xEFD5,0x5BD3, 0xEFD6,0x5C24, 0xEFD7,0x611A, 0xEFD8,0x6182, 0xEFD9,0x65F4,\n 0xEFDA,0x725B, 0xEFDB,0x7397, 0xEFDC,0x7440, 0xEFDD,0x76C2, 0xEFDE,0x7950, 0xEFDF,0x7991, 0xEFE0,0x79B9, 0xEFE1,0x7D06,\n 0xEFE2,0x7FBD, 0xEFE3,0x828B, 0xEFE4,0x85D5, 0xEFE5,0x865E, 0xEFE6,0x8FC2, 0xEFE7,0x9047, 0xEFE8,0x90F5, 0xEFE9,0x91EA,\n 0xEFEA,0x9685, 0xEFEB,0x96E8, 0xEFEC,0x96E9, 0xEFED,0x52D6, 0xEFEE,0x5F67, 0xEFEF,0x65ED, 0xEFF0,0x6631, 0xEFF1,0x682F,\n 0xEFF2,0x715C, 0xEFF3,0x7A36, 0xEFF4,0x90C1, 0xEFF5,0x980A, 0xEFF6,0x4E91, 0xEFF7,0xF9C5, 0xEFF8,0x6A52, 0xEFF9,0x6B9E,\n 0xEFFA,0x6F90, 0xEFFB,0x7189, 0xEFFC,0x8018, 0xEFFD,0x82B8, 0xEFFE,0x8553, 0xF031,0x904B, 0xF032,0x9695, 0xF033,0x96F2,\n 0xF034,0x97FB, 0xF035,0x851A, 0xF036,0x9B31, 0xF037,0x4E90, 0xF038,0x718A, 0xF039,0x96C4, 0xF03A,0x5143, 0xF03B,0x539F,\n 0xF03C,0x54E1, 0xF03D,0x5713, 0xF03E,0x5712, 0xF03F,0x57A3, 0xF040,0x5A9B, 0xF041,0x5AC4, 0xF042,0x5BC3, 0xF043,0x6028,\n 0xF044,0x613F, 0xF045,0x63F4, 0xF046,0x6C85, 0xF047,0x6D39, 0xF048,0x6E72, 0xF049,0x6E90, 0xF04A,0x7230, 0xF04B,0x733F,\n 0xF04C,0x7457, 0xF04D,0x82D1, 0xF04E,0x8881, 0xF04F,0x8F45, 0xF050,0x9060, 0xF051,0xF9C6, 0xF052,0x9662, 0xF053,0x9858,\n 0xF054,0x9D1B, 0xF055,0x6708, 0xF056,0x8D8A, 0xF057,0x925E, 0xF058,0x4F4D, 0xF059,0x5049, 0xF05A,0x50DE, 0xF05B,0x5371,\n 0xF05C,0x570D, 0xF05D,0x59D4, 0xF05E,0x5A01, 0xF05F,0x5C09, 0xF060,0x6170, 0xF061,0x6690, 0xF062,0x6E2D, 0xF063,0x7232,\n 0xF064,0x744B, 0xF065,0x7DEF, 0xF066,0x80C3, 0xF067,0x840E, 0xF068,0x8466, 0xF069,0x853F, 0xF06A,0x875F, 0xF06B,0x885B,\n 0xF06C,0x8918, 0xF06D,0x8B02, 0xF06E,0x9055, 0xF06F,0x97CB, 0xF070,0x9B4F, 0xF071,0x4E73, 0xF072,0x4F91, 0xF073,0x5112,\n 0xF074,0x516A, 0xF075,0xF9C7, 0xF076,0x552F, 0xF077,0x55A9, 0xF078,0x5B7A, 0xF079,0x5BA5, 0xF07A,0x5E7C, 0xF07B,0x5E7D,\n 0xF07C,0x5EBE, 0xF07D,0x60A0, 0xF07E,0x60DF, 0xF091,0x6108, 0xF092,0x6109, 0xF093,0x63C4, 0xF094,0x6538, 0xF095,0x6709,\n 0xF096,0xF9C8, 0xF097,0x67D4, 0xF098,0x67DA, 0xF099,0xF9C9, 0xF09A,0x6961, 0xF09B,0x6962, 0xF09C,0x6CB9, 0xF09D,0x6D27,\n 0xF09E,0xF9CA, 0xF09F,0x6E38, 0xF0A0,0xF9CB, 0xF0A1,0x6FE1, 0xF0A2,0x7336, 0xF0A3,0x7337, 0xF0A4,0xF9CC, 0xF0A5,0x745C,\n 0xF0A6,0x7531, 0xF0A7,0xF9CD, 0xF0A8,0x7652, 0xF0A9,0xF9CE, 0xF0AA,0xF9CF, 0xF0AB,0x7DAD, 0xF0AC,0x81FE, 0xF0AD,0x8438,\n 0xF0AE,0x88D5, 0xF0AF,0x8A98, 0xF0B0,0x8ADB, 0xF0B1,0x8AED, 0xF0B2,0x8E30, 0xF0B3,0x8E42, 0xF0B4,0x904A, 0xF0B5,0x903E,\n 0xF0B6,0x907A, 0xF0B7,0x9149, 0xF0B8,0x91C9, 0xF0B9,0x936E, 0xF0BA,0xF9D0, 0xF0BB,0xF9D1, 0xF0BC,0x5809, 0xF0BD,0xF9D2,\n 0xF0BE,0x6BD3, 0xF0BF,0x8089, 0xF0C0,0x80B2, 0xF0C1,0xF9D3, 0xF0C2,0xF9D4, 0xF0C3,0x5141, 0xF0C4,0x596B, 0xF0C5,0x5C39,\n 0xF0C6,0xF9D5, 0xF0C7,0xF9D6, 0xF0C8,0x6F64, 0xF0C9,0x73A7, 0xF0CA,0x80E4, 0xF0CB,0x8D07, 0xF0CC,0xF9D7, 0xF0CD,0x9217,\n 0xF0CE,0x958F, 0xF0CF,0xF9D8, 0xF0D0,0xF9D9, 0xF0D1,0xF9DA, 0xF0D2,0xF9DB, 0xF0D3,0x807F, 0xF0D4,0x620E, 0xF0D5,0x701C,\n 0xF0D6,0x7D68, 0xF0D7,0x878D, 0xF0D8,0xF9DC, 0xF0D9,0x57A0, 0xF0DA,0x6069, 0xF0DB,0x6147, 0xF0DC,0x6BB7, 0xF0DD,0x8ABE,\n 0xF0DE,0x9280, 0xF0DF,0x96B1, 0xF0E0,0x4E59, 0xF0E1,0x541F, 0xF0E2,0x6DEB, 0xF0E3,0x852D, 0xF0E4,0x9670, 0xF0E5,0x97F3,\n 0xF0E6,0x98EE, 0xF0E7,0x63D6, 0xF0E8,0x6CE3, 0xF0E9,0x9091, 0xF0EA,0x51DD, 0xF0EB,0x61C9, 0xF0EC,0x81BA, 0xF0ED,0x9DF9,\n 0xF0EE,0x4F9D, 0xF0EF,0x501A, 0xF0F0,0x5100, 0xF0F1,0x5B9C, 0xF0F2,0x610F, 0xF0F3,0x61FF, 0xF0F4,0x64EC, 0xF0F5,0x6905,\n 0xF0F6,0x6BC5, 0xF0F7,0x7591, 0xF0F8,0x77E3, 0xF0F9,0x7FA9, 0xF0FA,0x8264, 0xF0FB,0x858F, 0xF0FC,0x87FB, 0xF0FD,0x8863,\n 0xF0FE,0x8ABC, 0xF131,0x8B70, 0xF132,0x91AB, 0xF133,0x4E8C, 0xF134,0x4EE5, 0xF135,0x4F0A, 0xF136,0xF9DD, 0xF137,0xF9DE,\n 0xF138,0x5937, 0xF139,0x59E8, 0xF13A,0xF9DF, 0xF13B,0x5DF2, 0xF13C,0x5F1B, 0xF13D,0x5F5B, 0xF13E,0x6021, 0xF13F,0xF9E0,\n 0xF140,0xF9E1, 0xF141,0xF9E2, 0xF142,0xF9E3, 0xF143,0x723E, 0xF144,0x73E5, 0xF145,0xF9E4, 0xF146,0x7570, 0xF147,0x75CD,\n 0xF148,0xF9E5, 0xF149,0x79FB, 0xF14A,0xF9E6, 0xF14B,0x800C, 0xF14C,0x8033, 0xF14D,0x8084, 0xF14E,0x82E1, 0xF14F,0x8351,\n 0xF150,0xF9E7, 0xF151,0xF9E8, 0xF152,0x8CBD, 0xF153,0x8CB3, 0xF154,0x9087, 0xF155,0xF9E9, 0xF156,0xF9EA, 0xF157,0x98F4,\n 0xF158,0x990C, 0xF159,0xF9EB, 0xF15A,0xF9EC, 0xF15B,0x7037, 0xF15C,0x76CA, 0xF15D,0x7FCA, 0xF15E,0x7FCC, 0xF15F,0x7FFC,\n 0xF160,0x8B1A, 0xF161,0x4EBA, 0xF162,0x4EC1, 0xF163,0x5203, 0xF164,0x5370, 0xF165,0xF9ED, 0xF166,0x54BD, 0xF167,0x56E0,\n 0xF168,0x59FB, 0xF169,0x5BC5, 0xF16A,0x5F15, 0xF16B,0x5FCD, 0xF16C,0x6E6E, 0xF16D,0xF9EE, 0xF16E,0xF9EF, 0xF16F,0x7D6A,\n 0xF170,0x8335, 0xF171,0xF9F0, 0xF172,0x8693, 0xF173,0x8A8D, 0xF174,0xF9F1, 0xF175,0x976D, 0xF176,0x9777, 0xF177,0xF9F2,\n 0xF178,0xF9F3, 0xF179,0x4E00, 0xF17A,0x4F5A, 0xF17B,0x4F7E, 0xF17C,0x58F9, 0xF17D,0x65E5, 0xF17E,0x6EA2, 0xF191,0x9038,\n 0xF192,0x93B0, 0xF193,0x99B9, 0xF194,0x4EFB, 0xF195,0x58EC, 0xF196,0x598A, 0xF197,0x59D9, 0xF198,0x6041, 0xF199,0xF9F4,\n 0xF19A,0xF9F5, 0xF19B,0x7A14, 0xF19C,0xF9F6, 0xF19D,0x834F, 0xF19E,0x8CC3, 0xF19F,0x5165, 0xF1A0,0x5344, 0xF1A1,0xF9F7,\n 0xF1A2,0xF9F8, 0xF1A3,0xF9F9, 0xF1A4,0x4ECD, 0xF1A5,0x5269, 0xF1A6,0x5B55, 0xF1A7,0x82BF, 0xF1A8,0x4ED4, 0xF1A9,0x523A,\n 0xF1AA,0x54A8, 0xF1AB,0x59C9, 0xF1AC,0x59FF, 0xF1AD,0x5B50, 0xF1AE,0x5B57, 0xF1AF,0x5B5C, 0xF1B0,0x6063, 0xF1B1,0x6148,\n 0xF1B2,0x6ECB, 0xF1B3,0x7099, 0xF1B4,0x716E, 0xF1B5,0x7386, 0xF1B6,0x74F7, 0xF1B7,0x75B5, 0xF1B8,0x78C1, 0xF1B9,0x7D2B,\n 0xF1BA,0x8005, 0xF1BB,0x81EA, 0xF1BC,0x8328, 0xF1BD,0x8517, 0xF1BE,0x85C9, 0xF1BF,0x8AEE, 0xF1C0,0x8CC7, 0xF1C1,0x96CC,\n 0xF1C2,0x4F5C, 0xF1C3,0x52FA, 0xF1C4,0x56BC, 0xF1C5,0x65AB, 0xF1C6,0x6628, 0xF1C7,0x707C, 0xF1C8,0x70B8, 0xF1C9,0x7235,\n 0xF1CA,0x7DBD, 0xF1CB,0x828D, 0xF1CC,0x914C, 0xF1CD,0x96C0, 0xF1CE,0x9D72, 0xF1CF,0x5B71, 0xF1D0,0x68E7, 0xF1D1,0x6B98,\n 0xF1D2,0x6F7A, 0xF1D3,0x76DE, 0xF1D4,0x5C91, 0xF1D5,0x66AB, 0xF1D6,0x6F5B, 0xF1D7,0x7BB4, 0xF1D8,0x7C2A, 0xF1D9,0x8836,\n 0xF1DA,0x96DC, 0xF1DB,0x4E08, 0xF1DC,0x4ED7, 0xF1DD,0x5320, 0xF1DE,0x5834, 0xF1DF,0x58BB, 0xF1E0,0x58EF, 0xF1E1,0x596C,\n 0xF1E2,0x5C07, 0xF1E3,0x5E33, 0xF1E4,0x5E84, 0xF1E5,0x5F35, 0xF1E6,0x638C, 0xF1E7,0x66B2, 0xF1E8,0x6756, 0xF1E9,0x6A1F,\n 0xF1EA,0x6AA3, 0xF1EB,0x6B0C, 0xF1EC,0x6F3F, 0xF1ED,0x7246, 0xF1EE,0xF9FA, 0xF1EF,0x7350, 0xF1F0,0x748B, 0xF1F1,0x7AE0,\n 0xF1F2,0x7CA7, 0xF1F3,0x8178, 0xF1F4,0x81DF, 0xF1F5,0x81E7, 0xF1F6,0x838A, 0xF1F7,0x846C, 0xF1F8,0x8523, 0xF1F9,0x8594,\n 0xF1FA,0x85CF, 0xF1FB,0x88DD, 0xF1FC,0x8D13, 0xF1FD,0x91AC, 0xF1FE,0x9577, 0xF231,0x969C, 0xF232,0x518D, 0xF233,0x54C9,\n 0xF234,0x5728, 0xF235,0x5BB0, 0xF236,0x624D, 0xF237,0x6750, 0xF238,0x683D, 0xF239,0x6893, 0xF23A,0x6E3D, 0xF23B,0x6ED3,\n 0xF23C,0x707D, 0xF23D,0x7E21, 0xF23E,0x88C1, 0xF23F,0x8CA1, 0xF240,0x8F09, 0xF241,0x9F4B, 0xF242,0x9F4E, 0xF243,0x722D,\n 0xF244,0x7B8F, 0xF245,0x8ACD, 0xF246,0x931A, 0xF247,0x4F47, 0xF248,0x4F4E, 0xF249,0x5132, 0xF24A,0x5480, 0xF24B,0x59D0,\n 0xF24C,0x5E95, 0xF24D,0x62B5, 0xF24E,0x6775, 0xF24F,0x696E, 0xF250,0x6A17, 0xF251,0x6CAE, 0xF252,0x6E1A, 0xF253,0x72D9,\n 0xF254,0x732A, 0xF255,0x75BD, 0xF256,0x7BB8, 0xF257,0x7D35, 0xF258,0x82E7, 0xF259,0x83F9, 0xF25A,0x8457, 0xF25B,0x85F7,\n 0xF25C,0x8A5B, 0xF25D,0x8CAF, 0xF25E,0x8E87, 0xF25F,0x9019, 0xF260,0x90B8, 0xF261,0x96CE, 0xF262,0x9F5F, 0xF263,0x52E3,\n 0xF264,0x540A, 0xF265,0x5AE1, 0xF266,0x5BC2, 0xF267,0x6458, 0xF268,0x6575, 0xF269,0x6EF4, 0xF26A,0x72C4, 0xF26B,0xF9FB,\n 0xF26C,0x7684, 0xF26D,0x7A4D, 0xF26E,0x7B1B, 0xF26F,0x7C4D, 0xF270,0x7E3E, 0xF271,0x7FDF, 0xF272,0x837B, 0xF273,0x8B2B,\n 0xF274,0x8CCA, 0xF275,0x8D64, 0xF276,0x8DE1, 0xF277,0x8E5F, 0xF278,0x8FEA, 0xF279,0x8FF9, 0xF27A,0x9069, 0xF27B,0x93D1,\n 0xF27C,0x4F43, 0xF27D,0x4F7A, 0xF27E,0x50B3, 0xF291,0x5168, 0xF292,0x5178, 0xF293,0x524D, 0xF294,0x526A, 0xF295,0x5861,\n 0xF296,0x587C, 0xF297,0x5960, 0xF298,0x5C08, 0xF299,0x5C55, 0xF29A,0x5EDB, 0xF29B,0x609B, 0xF29C,0x6230, 0xF29D,0x6813,\n 0xF29E,0x6BBF, 0xF29F,0x6C08, 0xF2A0,0x6FB1, 0xF2A1,0x714E, 0xF2A2,0x7420, 0xF2A3,0x7530, 0xF2A4,0x7538, 0xF2A5,0x7551,\n 0xF2A6,0x7672, 0xF2A7,0x7B4C, 0xF2A8,0x7B8B, 0xF2A9,0x7BAD, 0xF2AA,0x7BC6, 0xF2AB,0x7E8F, 0xF2AC,0x8A6E, 0xF2AD,0x8F3E,\n 0xF2AE,0x8F49, 0xF2AF,0x923F, 0xF2B0,0x9293, 0xF2B1,0x9322, 0xF2B2,0x942B, 0xF2B3,0x96FB, 0xF2B4,0x985A, 0xF2B5,0x986B,\n 0xF2B6,0x991E, 0xF2B7,0x5207, 0xF2B8,0x622A, 0xF2B9,0x6298, 0xF2BA,0x6D59, 0xF2BB,0x7664, 0xF2BC,0x7ACA, 0xF2BD,0x7BC0,\n 0xF2BE,0x7D76, 0xF2BF,0x5360, 0xF2C0,0x5CBE, 0xF2C1,0x5E97, 0xF2C2,0x6F38, 0xF2C3,0x70B9, 0xF2C4,0x7C98, 0xF2C5,0x9711,\n 0xF2C6,0x9B8E, 0xF2C7,0x9EDE, 0xF2C8,0x63A5, 0xF2C9,0x647A, 0xF2CA,0x8776, 0xF2CB,0x4E01, 0xF2CC,0x4E95, 0xF2CD,0x4EAD,\n 0xF2CE,0x505C, 0xF2CF,0x5075, 0xF2D0,0x5448, 0xF2D1,0x59C3, 0xF2D2,0x5B9A, 0xF2D3,0x5E40, 0xF2D4,0x5EAD, 0xF2D5,0x5EF7,\n 0xF2D6,0x5F81, 0xF2D7,0x60C5, 0xF2D8,0x633A, 0xF2D9,0x653F, 0xF2DA,0x6574, 0xF2DB,0x65CC, 0xF2DC,0x6676, 0xF2DD,0x6678,\n 0xF2DE,0x67FE, 0xF2DF,0x6968, 0xF2E0,0x6A89, 0xF2E1,0x6B63, 0xF2E2,0x6C40, 0xF2E3,0x6DC0, 0xF2E4,0x6DE8, 0xF2E5,0x6E1F,\n 0xF2E6,0x6E5E, 0xF2E7,0x701E, 0xF2E8,0x70A1, 0xF2E9,0x738E, 0xF2EA,0x73FD, 0xF2EB,0x753A, 0xF2EC,0x775B, 0xF2ED,0x7887,\n 0xF2EE,0x798E, 0xF2EF,0x7A0B, 0xF2F0,0x7A7D, 0xF2F1,0x7CBE, 0xF2F2,0x7D8E, 0xF2F3,0x8247, 0xF2F4,0x8A02, 0xF2F5,0x8AEA,\n 0xF2F6,0x8C9E, 0xF2F7,0x912D, 0xF2F8,0x914A, 0xF2F9,0x91D8, 0xF2FA,0x9266, 0xF2FB,0x92CC, 0xF2FC,0x9320, 0xF2FD,0x9706,\n 0xF2FE,0x9756, 0xF331,0x975C, 0xF332,0x9802, 0xF333,0x9F0E, 0xF334,0x5236, 0xF335,0x5291, 0xF336,0x557C, 0xF337,0x5824,\n 0xF338,0x5E1D, 0xF339,0x5F1F, 0xF33A,0x608C, 0xF33B,0x63D0, 0xF33C,0x68AF, 0xF33D,0x6FDF, 0xF33E,0x796D, 0xF33F,0x7B2C,\n 0xF340,0x81CD, 0xF341,0x85BA, 0xF342,0x88FD, 0xF343,0x8AF8, 0xF344,0x8E44, 0xF345,0x918D, 0xF346,0x9664, 0xF347,0x969B,\n 0xF348,0x973D, 0xF349,0x984C, 0xF34A,0x9F4A, 0xF34B,0x4FCE, 0xF34C,0x5146, 0xF34D,0x51CB, 0xF34E,0x52A9, 0xF34F,0x5632,\n 0xF350,0x5F14, 0xF351,0x5F6B, 0xF352,0x63AA, 0xF353,0x64CD, 0xF354,0x65E9, 0xF355,0x6641, 0xF356,0x66FA, 0xF357,0x66F9,\n 0xF358,0x671D, 0xF359,0x689D, 0xF35A,0x68D7, 0xF35B,0x69FD, 0xF35C,0x6F15, 0xF35D,0x6F6E, 0xF35E,0x7167, 0xF35F,0x71E5,\n 0xF360,0x722A, 0xF361,0x74AA, 0xF362,0x773A, 0xF363,0x7956, 0xF364,0x795A, 0xF365,0x79DF, 0xF366,0x7A20, 0xF367,0x7A95,\n 0xF368,0x7C97, 0xF369,0x7CDF, 0xF36A,0x7D44, 0xF36B,0x7E70, 0xF36C,0x8087, 0xF36D,0x85FB, 0xF36E,0x86A4, 0xF36F,0x8A54,\n 0xF370,0x8ABF, 0xF371,0x8D99, 0xF372,0x8E81, 0xF373,0x9020, 0xF374,0x906D, 0xF375,0x91E3, 0xF376,0x963B, 0xF377,0x96D5,\n 0xF378,0x9CE5, 0xF379,0x65CF, 0xF37A,0x7C07, 0xF37B,0x8DB3, 0xF37C,0x93C3, 0xF37D,0x5B58, 0xF37E,0x5C0A, 0xF391,0x5352,\n 0xF392,0x62D9, 0xF393,0x731D, 0xF394,0x5027, 0xF395,0x5B97, 0xF396,0x5F9E, 0xF397,0x60B0, 0xF398,0x616B, 0xF399,0x68D5,\n 0xF39A,0x6DD9, 0xF39B,0x742E, 0xF39C,0x7A2E, 0xF39D,0x7D42, 0xF39E,0x7D9C, 0xF39F,0x7E31, 0xF3A0,0x816B, 0xF3A1,0x8E2A,\n 0xF3A2,0x8E35, 0xF3A3,0x937E, 0xF3A4,0x9418, 0xF3A5,0x4F50, 0xF3A6,0x5750, 0xF3A7,0x5DE6, 0xF3A8,0x5EA7, 0xF3A9,0x632B,\n 0xF3AA,0x7F6A, 0xF3AB,0x4E3B, 0xF3AC,0x4F4F, 0xF3AD,0x4F8F, 0xF3AE,0x505A, 0xF3AF,0x59DD, 0xF3B0,0x80C4, 0xF3B1,0x546A,\n 0xF3B2,0x5468, 0xF3B3,0x55FE, 0xF3B4,0x594F, 0xF3B5,0x5B99, 0xF3B6,0x5DDE, 0xF3B7,0x5EDA, 0xF3B8,0x665D, 0xF3B9,0x6731,\n 0xF3BA,0x67F1, 0xF3BB,0x682A, 0xF3BC,0x6CE8, 0xF3BD,0x6D32, 0xF3BE,0x6E4A, 0xF3BF,0x6F8D, 0xF3C0,0x70B7, 0xF3C1,0x73E0,\n 0xF3C2,0x7587, 0xF3C3,0x7C4C, 0xF3C4,0x7D02, 0xF3C5,0x7D2C, 0xF3C6,0x7DA2, 0xF3C7,0x821F, 0xF3C8,0x86DB, 0xF3C9,0x8A3B,\n 0xF3CA,0x8A85, 0xF3CB,0x8D70, 0xF3CC,0x8E8A, 0xF3CD,0x8F33, 0xF3CE,0x9031, 0xF3CF,0x914E, 0xF3D0,0x9152, 0xF3D1,0x9444,\n 0xF3D2,0x99D0, 0xF3D3,0x7AF9, 0xF3D4,0x7CA5, 0xF3D5,0x4FCA, 0xF3D6,0x5101, 0xF3D7,0x51C6, 0xF3D8,0x57C8, 0xF3D9,0x5BEF,\n 0xF3DA,0x5CFB, 0xF3DB,0x6659, 0xF3DC,0x6A3D, 0xF3DD,0x6D5A, 0xF3DE,0x6E96, 0xF3DF,0x6FEC, 0xF3E0,0x710C, 0xF3E1,0x756F,\n 0xF3E2,0x7AE3, 0xF3E3,0x8822, 0xF3E4,0x9021, 0xF3E5,0x9075, 0xF3E6,0x96CB, 0xF3E7,0x99FF, 0xF3E8,0x8301, 0xF3E9,0x4E2D,\n 0xF3EA,0x4EF2, 0xF3EB,0x8846, 0xF3EC,0x91CD, 0xF3ED,0x537D, 0xF3EE,0x6ADB, 0xF3EF,0x696B, 0xF3F0,0x6C41, 0xF3F1,0x847A,\n 0xF3F2,0x589E, 0xF3F3,0x618E, 0xF3F4,0x66FE, 0xF3F5,0x62EF, 0xF3F6,0x70DD, 0xF3F7,0x7511, 0xF3F8,0x75C7, 0xF3F9,0x7E52,\n 0xF3FA,0x84B8, 0xF3FB,0x8B49, 0xF3FC,0x8D08, 0xF3FD,0x4E4B, 0xF3FE,0x53EA, 0xF431,0x54AB, 0xF432,0x5730, 0xF433,0x5740,\n 0xF434,0x5FD7, 0xF435,0x6301, 0xF436,0x6307, 0xF437,0x646F, 0xF438,0x652F, 0xF439,0x65E8, 0xF43A,0x667A, 0xF43B,0x679D,\n 0xF43C,0x67B3, 0xF43D,0x6B62, 0xF43E,0x6C60, 0xF43F,0x6C9A, 0xF440,0x6F2C, 0xF441,0x77E5, 0xF442,0x7825, 0xF443,0x7949,\n 0xF444,0x7957, 0xF445,0x7D19, 0xF446,0x80A2, 0xF447,0x8102, 0xF448,0x81F3, 0xF449,0x829D, 0xF44A,0x82B7, 0xF44B,0x8718,\n 0xF44C,0x8A8C, 0xF44D,0xF9FC, 0xF44E,0x8D04, 0xF44F,0x8DBE, 0xF450,0x9072, 0xF451,0x76F4, 0xF452,0x7A19, 0xF453,0x7A37,\n 0xF454,0x7E54, 0xF455,0x8077, 0xF456,0x5507, 0xF457,0x55D4, 0xF458,0x5875, 0xF459,0x632F, 0xF45A,0x6422, 0xF45B,0x6649,\n 0xF45C,0x664B, 0xF45D,0x686D, 0xF45E,0x699B, 0xF45F,0x6B84, 0xF460,0x6D25, 0xF461,0x6EB1, 0xF462,0x73CD, 0xF463,0x7468,\n 0xF464,0x74A1, 0xF465,0x755B, 0xF466,0x75B9, 0xF467,0x76E1, 0xF468,0x771E, 0xF469,0x778B, 0xF46A,0x79E6, 0xF46B,0x7E09,\n 0xF46C,0x7E1D, 0xF46D,0x81FB, 0xF46E,0x852F, 0xF46F,0x8897, 0xF470,0x8A3A, 0xF471,0x8CD1, 0xF472,0x8EEB, 0xF473,0x8FB0,\n 0xF474,0x9032, 0xF475,0x93AD, 0xF476,0x9663, 0xF477,0x9673, 0xF478,0x9707, 0xF479,0x4F84, 0xF47A,0x53F1, 0xF47B,0x59EA,\n 0xF47C,0x5AC9, 0xF47D,0x5E19, 0xF47E,0x684E, 0xF491,0x74C6, 0xF492,0x75BE, 0xF493,0x79E9, 0xF494,0x7A92, 0xF495,0x81A3,\n 0xF496,0x86ED, 0xF497,0x8CEA, 0xF498,0x8DCC, 0xF499,0x8FED, 0xF49A,0x659F, 0xF49B,0x6715, 0xF49C,0xF9FD, 0xF49D,0x57F7,\n 0xF49E,0x6F57, 0xF49F,0x7DDD, 0xF4A0,0x8F2F, 0xF4A1,0x93F6, 0xF4A2,0x96C6, 0xF4A3,0x5FB5, 0xF4A4,0x61F2, 0xF4A5,0x6F84,\n 0xF4A6,0x4E14, 0xF4A7,0x4F98, 0xF4A8,0x501F, 0xF4A9,0x53C9, 0xF4AA,0x55DF, 0xF4AB,0x5D6F, 0xF4AC,0x5DEE, 0xF4AD,0x6B21,\n 0xF4AE,0x6B64, 0xF4AF,0x78CB, 0xF4B0,0x7B9A, 0xF4B1,0xF9FE, 0xF4B2,0x8E49, 0xF4B3,0x8ECA, 0xF4B4,0x906E, 0xF4B5,0x6349,\n 0xF4B6,0x643E, 0xF4B7,0x7740, 0xF4B8,0x7A84, 0xF4B9,0x932F, 0xF4BA,0x947F, 0xF4BB,0x9F6A, 0xF4BC,0x64B0, 0xF4BD,0x6FAF,\n 0xF4BE,0x71E6, 0xF4BF,0x74A8, 0xF4C0,0x74DA, 0xF4C1,0x7AC4, 0xF4C2,0x7C12, 0xF4C3,0x7E82, 0xF4C4,0x7CB2, 0xF4C5,0x7E98,\n 0xF4C6,0x8B9A, 0xF4C7,0x8D0A, 0xF4C8,0x947D, 0xF4C9,0x9910, 0xF4CA,0x994C, 0xF4CB,0x5239, 0xF4CC,0x5BDF, 0xF4CD,0x64E6,\n 0xF4CE,0x672D, 0xF4CF,0x7D2E, 0xF4D0,0x50ED, 0xF4D1,0x53C3, 0xF4D2,0x5879, 0xF4D3,0x6158, 0xF4D4,0x6159, 0xF4D5,0x61FA,\n 0xF4D6,0x65AC, 0xF4D7,0x7AD9, 0xF4D8,0x8B92, 0xF4D9,0x8B96, 0xF4DA,0x5009, 0xF4DB,0x5021, 0xF4DC,0x5275, 0xF4DD,0x5531,\n 0xF4DE,0x5A3C, 0xF4DF,0x5EE0, 0xF4E0,0x5F70, 0xF4E1,0x6134, 0xF4E2,0x655E, 0xF4E3,0x660C, 0xF4E4,0x6636, 0xF4E5,0x66A2,\n 0xF4E6,0x69CD, 0xF4E7,0x6EC4, 0xF4E8,0x6F32, 0xF4E9,0x7316, 0xF4EA,0x7621, 0xF4EB,0x7A93, 0xF4EC,0x8139, 0xF4ED,0x8259,\n 0xF4EE,0x83D6, 0xF4EF,0x84BC, 0xF4F0,0x50B5, 0xF4F1,0x57F0, 0xF4F2,0x5BC0, 0xF4F3,0x5BE8, 0xF4F4,0x5F69, 0xF4F5,0x63A1,\n 0xF4F6,0x7826, 0xF4F7,0x7DB5, 0xF4F8,0x83DC, 0xF4F9,0x8521, 0xF4FA,0x91C7, 0xF4FB,0x91F5, 0xF4FC,0x518A, 0xF4FD,0x67F5,\n 0xF4FE,0x7B56, 0xF531,0x8CAC, 0xF532,0x51C4, 0xF533,0x59BB, 0xF534,0x60BD, 0xF535,0x8655, 0xF536,0x501C, 0xF537,0xF9FF,\n 0xF538,0x5254, 0xF539,0x5C3A, 0xF53A,0x617D, 0xF53B,0x621A, 0xF53C,0x62D3, 0xF53D,0x64F2, 0xF53E,0x65A5, 0xF53F,0x6ECC,\n 0xF540,0x7620, 0xF541,0x810A, 0xF542,0x8E60, 0xF543,0x965F, 0xF544,0x96BB, 0xF545,0x4EDF, 0xF546,0x5343, 0xF547,0x5598,\n 0xF548,0x5929, 0xF549,0x5DDD, 0xF54A,0x64C5, 0xF54B,0x6CC9, 0xF54C,0x6DFA, 0xF54D,0x7394, 0xF54E,0x7A7F, 0xF54F,0x821B,\n 0xF550,0x85A6, 0xF551,0x8CE4, 0xF552,0x8E10, 0xF553,0x9077, 0xF554,0x91E7, 0xF555,0x95E1, 0xF556,0x9621, 0xF557,0x97C6,\n 0xF558,0x51F8, 0xF559,0x54F2, 0xF55A,0x5586, 0xF55B,0x5FB9, 0xF55C,0x64A4, 0xF55D,0x6F88, 0xF55E,0x7DB4, 0xF55F,0x8F1F,\n 0xF560,0x8F4D, 0xF561,0x9435, 0xF562,0x50C9, 0xF563,0x5C16, 0xF564,0x6CBE, 0xF565,0x6DFB, 0xF566,0x751B, 0xF567,0x77BB,\n 0xF568,0x7C3D, 0xF569,0x7C64, 0xF56A,0x8A79, 0xF56B,0x8AC2, 0xF56C,0x581E, 0xF56D,0x59BE, 0xF56E,0x5E16, 0xF56F,0x6377,\n 0xF570,0x7252, 0xF571,0x758A, 0xF572,0x776B, 0xF573,0x8ADC, 0xF574,0x8CBC, 0xF575,0x8F12, 0xF576,0x5EF3, 0xF577,0x6674,\n 0xF578,0x6DF8, 0xF579,0x807D, 0xF57A,0x83C1, 0xF57B,0x8ACB, 0xF57C,0x9751, 0xF57D,0x9BD6, 0xF57E,0xFA00, 0xF591,0x5243,\n 0xF592,0x66FF, 0xF593,0x6D95, 0xF594,0x6EEF, 0xF595,0x7DE0, 0xF596,0x8AE6, 0xF597,0x902E, 0xF598,0x905E, 0xF599,0x9AD4,\n 0xF59A,0x521D, 0xF59B,0x527F, 0xF59C,0x54E8, 0xF59D,0x6194, 0xF59E,0x6284, 0xF59F,0x62DB, 0xF5A0,0x68A2, 0xF5A1,0x6912,\n 0xF5A2,0x695A, 0xF5A3,0x6A35, 0xF5A4,0x7092, 0xF5A5,0x7126, 0xF5A6,0x785D, 0xF5A7,0x7901, 0xF5A8,0x790E, 0xF5A9,0x79D2,\n 0xF5AA,0x7A0D, 0xF5AB,0x8096, 0xF5AC,0x8278, 0xF5AD,0x82D5, 0xF5AE,0x8349, 0xF5AF,0x8549, 0xF5B0,0x8C82, 0xF5B1,0x8D85,\n 0xF5B2,0x9162, 0xF5B3,0x918B, 0xF5B4,0x91AE, 0xF5B5,0x4FC3, 0xF5B6,0x56D1, 0xF5B7,0x71ED, 0xF5B8,0x77D7, 0xF5B9,0x8700,\n 0xF5BA,0x89F8, 0xF5BB,0x5BF8, 0xF5BC,0x5FD6, 0xF5BD,0x6751, 0xF5BE,0x90A8, 0xF5BF,0x53E2, 0xF5C0,0x585A, 0xF5C1,0x5BF5,\n 0xF5C2,0x60A4, 0xF5C3,0x6181, 0xF5C4,0x6460, 0xF5C5,0x7E3D, 0xF5C6,0x8070, 0xF5C7,0x8525, 0xF5C8,0x9283, 0xF5C9,0x64AE,\n 0xF5CA,0x50AC, 0xF5CB,0x5D14, 0xF5CC,0x6700, 0xF5CD,0x589C, 0xF5CE,0x62BD, 0xF5CF,0x63A8, 0xF5D0,0x690E, 0xF5D1,0x6978,\n 0xF5D2,0x6A1E, 0xF5D3,0x6E6B, 0xF5D4,0x76BA, 0xF5D5,0x79CB, 0xF5D6,0x82BB, 0xF5D7,0x8429, 0xF5D8,0x8ACF, 0xF5D9,0x8DA8,\n 0xF5DA,0x8FFD, 0xF5DB,0x9112, 0xF5DC,0x914B, 0xF5DD,0x919C, 0xF5DE,0x9310, 0xF5DF,0x9318, 0xF5E0,0x939A, 0xF5E1,0x96DB,\n 0xF5E2,0x9A36, 0xF5E3,0x9C0D, 0xF5E4,0x4E11, 0xF5E5,0x755C, 0xF5E6,0x795D, 0xF5E7,0x7AFA, 0xF5E8,0x7B51, 0xF5E9,0x7BC9,\n 0xF5EA,0x7E2E, 0xF5EB,0x84C4, 0xF5EC,0x8E59, 0xF5ED,0x8E74, 0xF5EE,0x8EF8, 0xF5EF,0x9010, 0xF5F0,0x6625, 0xF5F1,0x693F,\n 0xF5F2,0x7443, 0xF5F3,0x51FA, 0xF5F4,0x672E, 0xF5F5,0x9EDC, 0xF5F6,0x5145, 0xF5F7,0x5FE0, 0xF5F8,0x6C96, 0xF5F9,0x87F2,\n 0xF5FA,0x885D, 0xF5FB,0x8877, 0xF5FC,0x60B4, 0xF5FD,0x81B5, 0xF5FE,0x8403, 0xF631,0x8D05, 0xF632,0x53D6, 0xF633,0x5439,\n 0xF634,0x5634, 0xF635,0x5A36, 0xF636,0x5C31, 0xF637,0x708A, 0xF638,0x7FE0, 0xF639,0x805A, 0xF63A,0x8106, 0xF63B,0x81ED,\n 0xF63C,0x8DA3, 0xF63D,0x9189, 0xF63E,0x9A5F, 0xF63F,0x9DF2, 0xF640,0x5074, 0xF641,0x4EC4, 0xF642,0x53A0, 0xF643,0x60FB,\n 0xF644,0x6E2C, 0xF645,0x5C64, 0xF646,0x4F88, 0xF647,0x5024, 0xF648,0x55E4, 0xF649,0x5CD9, 0xF64A,0x5E5F, 0xF64B,0x6065,\n 0xF64C,0x6894, 0xF64D,0x6CBB, 0xF64E,0x6DC4, 0xF64F,0x71BE, 0xF650,0x75D4, 0xF651,0x75F4, 0xF652,0x7661, 0xF653,0x7A1A,\n 0xF654,0x7A49, 0xF655,0x7DC7, 0xF656,0x7DFB, 0xF657,0x7F6E, 0xF658,0x81F4, 0xF659,0x86A9, 0xF65A,0x8F1C, 0xF65B,0x96C9,\n 0xF65C,0x99B3, 0xF65D,0x9F52, 0xF65E,0x5247, 0xF65F,0x52C5, 0xF660,0x98ED, 0xF661,0x89AA, 0xF662,0x4E03, 0xF663,0x67D2,\n 0xF664,0x6F06, 0xF665,0x4FB5, 0xF666,0x5BE2, 0xF667,0x6795, 0xF668,0x6C88, 0xF669,0x6D78, 0xF66A,0x741B, 0xF66B,0x7827,\n 0xF66C,0x91DD, 0xF66D,0x937C, 0xF66E,0x87C4, 0xF66F,0x79E4, 0xF670,0x7A31, 0xF671,0x5FEB, 0xF672,0x4ED6, 0xF673,0x54A4,\n 0xF674,0x553E, 0xF675,0x58AE, 0xF676,0x59A5, 0xF677,0x60F0, 0xF678,0x6253, 0xF679,0x62D6, 0xF67A,0x6736, 0xF67B,0x6955,\n 0xF67C,0x8235, 0xF67D,0x9640, 0xF67E,0x99B1, 0xF691,0x99DD, 0xF692,0x502C, 0xF693,0x5353, 0xF694,0x5544, 0xF695,0x577C,\n 0xF696,0xFA01, 0xF697,0x6258, 0xF698,0xFA02, 0xF699,0x64E2, 0xF69A,0x666B, 0xF69B,0x67DD, 0xF69C,0x6FC1, 0xF69D,0x6FEF,\n 0xF69E,0x7422, 0xF69F,0x7438, 0xF6A0,0x8A17, 0xF6A1,0x9438, 0xF6A2,0x5451, 0xF6A3,0x5606, 0xF6A4,0x5766, 0xF6A5,0x5F48,\n 0xF6A6,0x619A, 0xF6A7,0x6B4E, 0xF6A8,0x7058, 0xF6A9,0x70AD, 0xF6AA,0x7DBB, 0xF6AB,0x8A95, 0xF6AC,0x596A, 0xF6AD,0x812B,\n 0xF6AE,0x63A2, 0xF6AF,0x7708, 0xF6B0,0x803D, 0xF6B1,0x8CAA, 0xF6B2,0x5854, 0xF6B3,0x642D, 0xF6B4,0x69BB, 0xF6B5,0x5B95,\n 0xF6B6,0x5E11, 0xF6B7,0x6E6F, 0xF6B8,0xFA03, 0xF6B9,0x8569, 0xF6BA,0x514C, 0xF6BB,0x53F0, 0xF6BC,0x592A, 0xF6BD,0x6020,\n 0xF6BE,0x614B, 0xF6BF,0x6B86, 0xF6C0,0x6C70, 0xF6C1,0x6CF0, 0xF6C2,0x7B1E, 0xF6C3,0x80CE, 0xF6C4,0x82D4, 0xF6C5,0x8DC6,\n 0xF6C6,0x90B0, 0xF6C7,0x98B1, 0xF6C8,0xFA04, 0xF6C9,0x64C7, 0xF6CA,0x6FA4, 0xF6CB,0x6491, 0xF6CC,0x6504, 0xF6CD,0x514E,\n 0xF6CE,0x5410, 0xF6CF,0x571F, 0xF6D0,0x8A0E, 0xF6D1,0x615F, 0xF6D2,0x6876, 0xF6D3,0xFA05, 0xF6D4,0x75DB, 0xF6D5,0x7B52,\n 0xF6D6,0x7D71, 0xF6D7,0x901A, 0xF6D8,0x5806, 0xF6D9,0x69CC, 0xF6DA,0x817F, 0xF6DB,0x892A, 0xF6DC,0x9000, 0xF6DD,0x9839,\n 0xF6DE,0x5078, 0xF6DF,0x5957, 0xF6E0,0x59AC, 0xF6E1,0x6295, 0xF6E2,0x900F, 0xF6E3,0x9B2A, 0xF6E4,0x615D, 0xF6E5,0x7279,\n 0xF6E6,0x95D6, 0xF6E7,0x5761, 0xF6E8,0x5A46, 0xF6E9,0x5DF4, 0xF6EA,0x628A, 0xF6EB,0x64AD, 0xF6EC,0x64FA, 0xF6ED,0x6777,\n 0xF6EE,0x6CE2, 0xF6EF,0x6D3E, 0xF6F0,0x722C, 0xF6F1,0x7436, 0xF6F2,0x7834, 0xF6F3,0x7F77, 0xF6F4,0x82AD, 0xF6F5,0x8DDB,\n 0xF6F6,0x9817, 0xF6F7,0x5224, 0xF6F8,0x5742, 0xF6F9,0x677F, 0xF6FA,0x7248, 0xF6FB,0x74E3, 0xF6FC,0x8CA9, 0xF6FD,0x8FA6,\n 0xF6FE,0x9211, 0xF731,0x962A, 0xF732,0x516B, 0xF733,0x53ED, 0xF734,0x634C, 0xF735,0x4F69, 0xF736,0x5504, 0xF737,0x6096,\n 0xF738,0x6557, 0xF739,0x6C9B, 0xF73A,0x6D7F, 0xF73B,0x724C, 0xF73C,0x72FD, 0xF73D,0x7A17, 0xF73E,0x8987, 0xF73F,0x8C9D,\n 0xF740,0x5F6D, 0xF741,0x6F8E, 0xF742,0x70F9, 0xF743,0x81A8, 0xF744,0x610E, 0xF745,0x4FBF, 0xF746,0x504F, 0xF747,0x6241,\n 0xF748,0x7247, 0xF749,0x7BC7, 0xF74A,0x7DE8, 0xF74B,0x7FE9, 0xF74C,0x904D, 0xF74D,0x97AD, 0xF74E,0x9A19, 0xF74F,0x8CB6,\n 0xF750,0x576A, 0xF751,0x5E73, 0xF752,0x67B0, 0xF753,0x840D, 0xF754,0x8A55, 0xF755,0x5420, 0xF756,0x5B16, 0xF757,0x5E63,\n 0xF758,0x5EE2, 0xF759,0x5F0A, 0xF75A,0x6583, 0xF75B,0x80BA, 0xF75C,0x853D, 0xF75D,0x9589, 0xF75E,0x965B, 0xF75F,0x4F48,\n 0xF760,0x5305, 0xF761,0x530D, 0xF762,0x530F, 0xF763,0x5486, 0xF764,0x54FA, 0xF765,0x5703, 0xF766,0x5E03, 0xF767,0x6016,\n 0xF768,0x629B, 0xF769,0x62B1, 0xF76A,0x6355, 0xF76B,0xFA06, 0xF76C,0x6CE1, 0xF76D,0x6D66, 0xF76E,0x75B1, 0xF76F,0x7832,\n 0xF770,0x80DE, 0xF771,0x812F, 0xF772,0x82DE, 0xF773,0x8461, 0xF774,0x84B2, 0xF775,0x888D, 0xF776,0x8912, 0xF777,0x900B,\n 0xF778,0x92EA, 0xF779,0x98FD, 0xF77A,0x9B91, 0xF77B,0x5E45, 0xF77C,0x66B4, 0xF77D,0x66DD, 0xF77E,0x7011, 0xF791,0x7206,\n 0xF792,0xFA07, 0xF793,0x4FF5, 0xF794,0x527D, 0xF795,0x5F6A, 0xF796,0x6153, 0xF797,0x6753, 0xF798,0x6A19, 0xF799,0x6F02,\n 0xF79A,0x74E2, 0xF79B,0x7968, 0xF79C,0x8868, 0xF79D,0x8C79, 0xF79E,0x98C7, 0xF79F,0x98C4, 0xF7A0,0x9A43, 0xF7A1,0x54C1,\n 0xF7A2,0x7A1F, 0xF7A3,0x6953, 0xF7A4,0x8AF7, 0xF7A5,0x8C4A, 0xF7A6,0x98A8, 0xF7A7,0x99AE, 0xF7A8,0x5F7C, 0xF7A9,0x62AB,\n 0xF7AA,0x75B2, 0xF7AB,0x76AE, 0xF7AC,0x88AB, 0xF7AD,0x907F, 0xF7AE,0x9642, 0xF7AF,0x5339, 0xF7B0,0x5F3C, 0xF7B1,0x5FC5,\n 0xF7B2,0x6CCC, 0xF7B3,0x73CC, 0xF7B4,0x7562, 0xF7B5,0x758B, 0xF7B6,0x7B46, 0xF7B7,0x82FE, 0xF7B8,0x999D, 0xF7B9,0x4E4F,\n 0xF7BA,0x903C, 0xF7BB,0x4E0B, 0xF7BC,0x4F55, 0xF7BD,0x53A6, 0xF7BE,0x590F, 0xF7BF,0x5EC8, 0xF7C0,0x6630, 0xF7C1,0x6CB3,\n 0xF7C2,0x7455, 0xF7C3,0x8377, 0xF7C4,0x8766, 0xF7C5,0x8CC0, 0xF7C6,0x9050, 0xF7C7,0x971E, 0xF7C8,0x9C15, 0xF7C9,0x58D1,\n 0xF7CA,0x5B78, 0xF7CB,0x8650, 0xF7CC,0x8B14, 0xF7CD,0x9DB4, 0xF7CE,0x5BD2, 0xF7CF,0x6068, 0xF7D0,0x608D, 0xF7D1,0x65F1,\n 0xF7D2,0x6C57, 0xF7D3,0x6F22, 0xF7D4,0x6FA3, 0xF7D5,0x701A, 0xF7D6,0x7F55, 0xF7D7,0x7FF0, 0xF7D8,0x9591, 0xF7D9,0x9592,\n 0xF7DA,0x9650, 0xF7DB,0x97D3, 0xF7DC,0x5272, 0xF7DD,0x8F44, 0xF7DE,0x51FD, 0xF7DF,0x542B, 0xF7E0,0x54B8, 0xF7E1,0x5563,\n 0xF7E2,0x558A, 0xF7E3,0x6ABB, 0xF7E4,0x6DB5, 0xF7E5,0x7DD8, 0xF7E6,0x8266, 0xF7E7,0x929C, 0xF7E8,0x9677, 0xF7E9,0x9E79,\n 0xF7EA,0x5408, 0xF7EB,0x54C8, 0xF7EC,0x76D2, 0xF7ED,0x86E4, 0xF7EE,0x95A4, 0xF7EF,0x95D4, 0xF7F0,0x965C, 0xF7F1,0x4EA2,\n 0xF7F2,0x4F09, 0xF7F3,0x59EE, 0xF7F4,0x5AE6, 0xF7F5,0x5DF7, 0xF7F6,0x6052, 0xF7F7,0x6297, 0xF7F8,0x676D, 0xF7F9,0x6841,\n 0xF7FA,0x6C86, 0xF7FB,0x6E2F, 0xF7FC,0x7F38, 0xF7FD,0x809B, 0xF7FE,0x822A, 0xF831,0xFA08, 0xF832,0xFA09, 0xF833,0x9805,\n 0xF834,0x4EA5, 0xF835,0x5055, 0xF836,0x54B3, 0xF837,0x5793, 0xF838,0x595A, 0xF839,0x5B69, 0xF83A,0x5BB3, 0xF83B,0x61C8,\n 0xF83C,0x6977, 0xF83D,0x6D77, 0xF83E,0x7023, 0xF83F,0x87F9, 0xF840,0x89E3, 0xF841,0x8A72, 0xF842,0x8AE7, 0xF843,0x9082,\n 0xF844,0x99ED, 0xF845,0x9AB8, 0xF846,0x52BE, 0xF847,0x6838, 0xF848,0x5016, 0xF849,0x5E78, 0xF84A,0x674F, 0xF84B,0x8347,\n 0xF84C,0x884C, 0xF84D,0x4EAB, 0xF84E,0x5411, 0xF84F,0x56AE, 0xF850,0x73E6, 0xF851,0x9115, 0xF852,0x97FF, 0xF853,0x9909,\n 0xF854,0x9957, 0xF855,0x9999, 0xF856,0x5653, 0xF857,0x589F, 0xF858,0x865B, 0xF859,0x8A31, 0xF85A,0x61B2, 0xF85B,0x6AF6,\n 0xF85C,0x737B, 0xF85D,0x8ED2, 0xF85E,0x6B47, 0xF85F,0x96AA, 0xF860,0x9A57, 0xF861,0x5955, 0xF862,0x7200, 0xF863,0x8D6B,\n 0xF864,0x9769, 0xF865,0x4FD4, 0xF866,0x5CF4, 0xF867,0x5F26, 0xF868,0x61F8, 0xF869,0x665B, 0xF86A,0x6CEB, 0xF86B,0x70AB,\n 0xF86C,0x7384, 0xF86D,0x73B9, 0xF86E,0x73FE, 0xF86F,0x7729, 0xF870,0x774D, 0xF871,0x7D43, 0xF872,0x7D62, 0xF873,0x7E23,\n 0xF874,0x8237, 0xF875,0x8852, 0xF876,0xFA0A, 0xF877,0x8CE2, 0xF878,0x9249, 0xF879,0x986F, 0xF87A,0x5B51, 0xF87B,0x7A74,\n 0xF87C,0x8840, 0xF87D,0x9801, 0xF87E,0x5ACC, 0xF891,0x4FE0, 0xF892,0x5354, 0xF893,0x593E, 0xF894,0x5CFD, 0xF895,0x633E,\n 0xF896,0x6D79, 0xF897,0x72F9, 0xF898,0x8105, 0xF899,0x8107, 0xF89A,0x83A2, 0xF89B,0x92CF, 0xF89C,0x9830, 0xF89D,0x4EA8,\n 0xF89E,0x5144, 0xF89F,0x5211, 0xF8A0,0x578B, 0xF8A1,0x5F62, 0xF8A2,0x6CC2, 0xF8A3,0x6ECE, 0xF8A4,0x7005, 0xF8A5,0x7050,\n 0xF8A6,0x70AF, 0xF8A7,0x7192, 0xF8A8,0x73E9, 0xF8A9,0x7469, 0xF8AA,0x834A, 0xF8AB,0x87A2, 0xF8AC,0x8861, 0xF8AD,0x9008,\n 0xF8AE,0x90A2, 0xF8AF,0x93A3, 0xF8B0,0x99A8, 0xF8B1,0x516E, 0xF8B2,0x5F57, 0xF8B3,0x60E0, 0xF8B4,0x6167, 0xF8B5,0x66B3,\n 0xF8B6,0x8559, 0xF8B7,0x8E4A, 0xF8B8,0x91AF, 0xF8B9,0x978B, 0xF8BA,0x4E4E, 0xF8BB,0x4E92, 0xF8BC,0x547C, 0xF8BD,0x58D5,\n 0xF8BE,0x58FA, 0xF8BF,0x597D, 0xF8C0,0x5CB5, 0xF8C1,0x5F27, 0xF8C2,0x6236, 0xF8C3,0x6248, 0xF8C4,0x660A, 0xF8C5,0x6667,\n 0xF8C6,0x6BEB, 0xF8C7,0x6D69, 0xF8C8,0x6DCF, 0xF8C9,0x6E56, 0xF8CA,0x6EF8, 0xF8CB,0x6F94, 0xF8CC,0x6FE0, 0xF8CD,0x6FE9,\n 0xF8CE,0x705D, 0xF8CF,0x72D0, 0xF8D0,0x7425, 0xF8D1,0x745A, 0xF8D2,0x74E0, 0xF8D3,0x7693, 0xF8D4,0x795C, 0xF8D5,0x7CCA,\n 0xF8D6,0x7E1E, 0xF8D7,0x80E1, 0xF8D8,0x82A6, 0xF8D9,0x846B, 0xF8DA,0x84BF, 0xF8DB,0x864E, 0xF8DC,0x865F, 0xF8DD,0x8774,\n 0xF8DE,0x8B77, 0xF8DF,0x8C6A, 0xF8E0,0x93AC, 0xF8E1,0x9800, 0xF8E2,0x9865, 0xF8E3,0x60D1, 0xF8E4,0x6216, 0xF8E5,0x9177,\n 0xF8E6,0x5A5A, 0xF8E7,0x660F, 0xF8E8,0x6DF7, 0xF8E9,0x6E3E, 0xF8EA,0x743F, 0xF8EB,0x9B42, 0xF8EC,0x5FFD, 0xF8ED,0x60DA,\n 0xF8EE,0x7B0F, 0xF8EF,0x54C4, 0xF8F0,0x5F18, 0xF8F1,0x6C5E, 0xF8F2,0x6CD3, 0xF8F3,0x6D2A, 0xF8F4,0x70D8, 0xF8F5,0x7D05,\n 0xF8F6,0x8679, 0xF8F7,0x8A0C, 0xF8F8,0x9D3B, 0xF8F9,0x5316, 0xF8FA,0x548C, 0xF8FB,0x5B05, 0xF8FC,0x6A3A, 0xF8FD,0x706B,\n 0xF8FE,0x7575, 0xF931,0x798D, 0xF932,0x79BE, 0xF933,0x82B1, 0xF934,0x83EF, 0xF935,0x8A71, 0xF936,0x8B41, 0xF937,0x8CA8,\n 0xF938,0x9774, 0xF939,0xFA0B, 0xF93A,0x64F4, 0xF93B,0x652B, 0xF93C,0x78BA, 0xF93D,0x78BB, 0xF93E,0x7A6B, 0xF93F,0x4E38,\n 0xF940,0x559A, 0xF941,0x5950, 0xF942,0x5BA6, 0xF943,0x5E7B, 0xF944,0x60A3, 0xF945,0x63DB, 0xF946,0x6B61, 0xF947,0x6665,\n 0xF948,0x6853, 0xF949,0x6E19, 0xF94A,0x7165, 0xF94B,0x74B0, 0xF94C,0x7D08, 0xF94D,0x9084, 0xF94E,0x9A69, 0xF94F,0x9C25,\n 0xF950,0x6D3B, 0xF951,0x6ED1, 0xF952,0x733E, 0xF953,0x8C41, 0xF954,0x95CA, 0xF955,0x51F0, 0xF956,0x5E4C, 0xF957,0x5FA8,\n 0xF958,0x604D, 0xF959,0x60F6, 0xF95A,0x6130, 0xF95B,0x614C, 0xF95C,0x6643, 0xF95D,0x6644, 0xF95E,0x69A5, 0xF95F,0x6CC1,\n 0xF960,0x6E5F, 0xF961,0x6EC9, 0xF962,0x6F62, 0xF963,0x714C, 0xF964,0x749C, 0xF965,0x7687, 0xF966,0x7BC1, 0xF967,0x7C27,\n 0xF968,0x8352, 0xF969,0x8757, 0xF96A,0x9051, 0xF96B,0x968D, 0xF96C,0x9EC3, 0xF96D,0x532F, 0xF96E,0x56DE, 0xF96F,0x5EFB,\n 0xF970,0x5F8A, 0xF971,0x6062, 0xF972,0x6094, 0xF973,0x61F7, 0xF974,0x6666, 0xF975,0x6703, 0xF976,0x6A9C, 0xF977,0x6DEE,\n 0xF978,0x6FAE, 0xF979,0x7070, 0xF97A,0x736A, 0xF97B,0x7E6A, 0xF97C,0x81BE, 0xF97D,0x8334, 0xF97E,0x86D4, 0xF991,0x8AA8,\n 0xF992,0x8CC4, 0xF993,0x5283, 0xF994,0x7372, 0xF995,0x5B96, 0xF996,0x6A6B, 0xF997,0x9404, 0xF998,0x54EE, 0xF999,0x5686,\n 0xF99A,0x5B5D, 0xF99B,0x6548, 0xF99C,0x6585, 0xF99D,0x66C9, 0xF99E,0x689F, 0xF99F,0x6D8D, 0xF9A0,0x6DC6, 0xF9A1,0x723B,\n 0xF9A2,0x80B4, 0xF9A3,0x9175, 0xF9A4,0x9A4D, 0xF9A5,0x4FAF, 0xF9A6,0x5019, 0xF9A7,0x539A, 0xF9A8,0x540E, 0xF9A9,0x543C,\n 0xF9AA,0x5589, 0xF9AB,0x55C5, 0xF9AC,0x5E3F, 0xF9AD,0x5F8C, 0xF9AE,0x673D, 0xF9AF,0x7166, 0xF9B0,0x73DD, 0xF9B1,0x9005,\n 0xF9B2,0x52DB, 0xF9B3,0x52F3, 0xF9B4,0x5864, 0xF9B5,0x58CE, 0xF9B6,0x7104, 0xF9B7,0x718F, 0xF9B8,0x71FB, 0xF9B9,0x85B0,\n 0xF9BA,0x8A13, 0xF9BB,0x6688, 0xF9BC,0x85A8, 0xF9BD,0x55A7, 0xF9BE,0x6684, 0xF9BF,0x714A, 0xF9C0,0x8431, 0xF9C1,0x5349,\n 0xF9C2,0x5599, 0xF9C3,0x6BC1, 0xF9C4,0x5F59, 0xF9C5,0x5FBD, 0xF9C6,0x63EE, 0xF9C7,0x6689, 0xF9C8,0x7147, 0xF9C9,0x8AF1,\n 0xF9CA,0x8F1D, 0xF9CB,0x9EBE, 0xF9CC,0x4F11, 0xF9CD,0x643A, 0xF9CE,0x70CB, 0xF9CF,0x7566, 0xF9D0,0x8667, 0xF9D1,0x6064,\n 0xF9D2,0x8B4E, 0xF9D3,0x9DF8, 0xF9D4,0x5147, 0xF9D5,0x51F6, 0xF9D6,0x5308, 0xF9D7,0x6D36, 0xF9D8,0x80F8, 0xF9D9,0x9ED1,\n 0xF9DA,0x6615, 0xF9DB,0x6B23, 0xF9DC,0x7098, 0xF9DD,0x75D5, 0xF9DE,0x5403, 0xF9DF,0x5C79, 0xF9E0,0x7D07, 0xF9E1,0x8A16,\n 0xF9E2,0x6B20, 0xF9E3,0x6B3D, 0xF9E4,0x6B46, 0xF9E5,0x5438, 0xF9E6,0x6070, 0xF9E7,0x6D3D, 0xF9E8,0x7FD5, 0xF9E9,0x8208,\n 0xF9EA,0x50D6, 0xF9EB,0x51DE, 0xF9EC,0x559C, 0xF9ED,0x566B, 0xF9EE,0x56CD, 0xF9EF,0x59EC, 0xF9F0,0x5B09, 0xF9F1,0x5E0C,\n 0xF9F2,0x6199, 0xF9F3,0x6198, 0xF9F4,0x6231, 0xF9F5,0x665E, 0xF9F6,0x66E6, 0xF9F7,0x7199, 0xF9F8,0x71B9, 0xF9F9,0x71BA,\n 0xF9FA,0x72A7, 0xF9FB,0x79A7, 0xF9FC,0x7A00, 0xF9FD,0x7FB2, 0xF9FE,0x8A70,\n])\n","/**\n * HWP 3.0 상용 조합형 → 유니코드 디코더.\n *\n * 한국어 한글은 cho/jung/jong 비트 분해로 0xAC00 한글 음절 영역에 직접 매핑되고,\n * 한자/기호 등 그 외 영역은 johab-symbols.ts 의 lookup table 로 처리한다.\n * 매핑되지 않는 코드는 '?' 로 fallback 한다.\n *\n * 출처: rhwp/src/parser/hwp3/johab.rs (MIT). 알고리즘 동일.\n */\n\nimport { JOHAB_SYMBOLS } from \"./johab-symbols.js\"\n\n// 인덱스 → 자모 위치. -1 은 invalid (KS X 1001 johab 정의).\nconst CHO_MAP: ReadonlyArray<number> = Object.freeze([\n -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,\n -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n])\nconst JUNG_MAP: ReadonlyArray<number> = Object.freeze([\n -1, -1, -1, 0, 1, 2, 3, 4, -1, -1, 5, 6, 7, 8, 9, 10, -1, -1, 11, 12, 13, 14,\n 15, 16, -1, -1, 17, 18, 19, 20, -1, -1,\n])\nconst JONG_MAP: ReadonlyArray<number> = Object.freeze([\n -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, -1, 17, 18, 19,\n 20, 21, 22, 23, 24, 25, 26, 27, -1, -1,\n])\n\n/** JOHAB_SYMBOLS flat array (key,val,key,val…) 에서 key 이진 탐색. */\nfunction lookupSymbol(ch: number): number | null {\n let lo = 0\n let hi = JOHAB_SYMBOLS.length / 2 - 1\n while (lo <= hi) {\n const mid = (lo + hi) >>> 1\n const k = JOHAB_SYMBOLS[mid * 2]\n if (k === ch) return JOHAB_SYMBOLS[mid * 2 + 1]\n if (k < ch) lo = mid + 1\n else hi = mid - 1\n }\n return null\n}\n\n/** 매핑 실패를 명확히 알리기 위한 sentinel. 호출자가 string 에 추가하지 않도록 skip. */\nexport const JOHAB_UNMAPPED = -1\n\n/** 옛한글 아래아 중성 인덱스 (KSSM 조합형) */\nconst JUNG_ARAEA = 30\n/** HANGUL JUNGSEONG ARAEA (U+119E) */\nconst ARAEA_JAMO = 0x119e\n\n/**\n * 아래아(ㆍ) 음절을 초성·아래아·종성 자모열로 푼다. 아래아가 아니면 null.\n *\n * HWP3 은 'ᄒᆞᆫ'(한글 97 안내문의 'ᄒᆞᆫ글') 같은 음절을 hchar 하나로 저장하지만,\n * 완성형 영역에는 대응 음절이 없어 `decodeJohab` 은 UNMAPPED 를 반환한다 — 그러면\n * 파서가 조용히 건너뛰어 글자가 사라진다. 한컴의 HWP5/HWPX 변환본도 자모열로\n * 보존하므로 같은 표현을 쓴다 (rhwp decode_johab_araea_jamo 포팅).\n */\nfunction decodeAraeaSyllable(ch: number): string | null {\n if (ch < 0x8000) return null\n if (((ch >> 5) & 0x1f) !== JUNG_ARAEA) return null\n\n const choIdx = (ch >> 10) & 0x1f\n const cho = CHO_MAP[choIdx]\n const jong = JONG_MAP[ch & 0x1f]\n if (jong === -1) return null\n // 초성 인덱스 1 은 '채움'(초성 없음) — 한컴 변환본은 아래아 자모 하나만 남긴다\n // (hwp3-sample16 0x87C1 ↔ 변환본 U+119E 실측). 그 외 무효 초성은 종전대로 미매핑.\n if (cho === -1) {\n if (choIdx !== 1) return null\n const bare = String.fromCodePoint(ARAEA_JAMO)\n return jong === 0 ? bare : bare + String.fromCodePoint(0x11a7 + jong)\n }\n\n // 초성은 U+1100 계열, 종성은 U+11A7 기준 (jong 0 = 받침 없음)\n const out = String.fromCodePoint(0x1100 + cho) + String.fromCodePoint(ARAEA_JAMO)\n return jong === 0 ? out : out + String.fromCodePoint(0x11a7 + jong)\n}\n\n/**\n * HWP3 hchar (u16) → 텍스트. 매핑 실패면 null (호출자가 건너뛴다).\n *\n * 대부분 한 글자지만 아래아 음절은 자모 2~3개가 되므로 문자열을 반환한다.\n * 단일 코드포인트가 필요한 곳은 `decodeJohab` 을 그대로 쓴다.\n */\nexport function decodeJohabText(ch: number): string | null {\n const araea = decodeAraeaSyllable(ch)\n if (araea) return araea\n const cp = decodeJohab(ch)\n return cp === JOHAB_UNMAPPED ? null : String.fromCodePoint(cp)\n}\n\n/**\n * HWP3 hchar (u16) → 유니코드 코드포인트. 매핑 실패 시 JOHAB_UNMAPPED.\n *\n * 매핑 실패 케이스를 '?' 로 fallback 시키면 검색 인덱스에 noise 가 누적된다 (특히\n * 메타 컨트롤이 가득한 paragraph 가 ??? 시퀀스를 생산). 호출자가 unmapped 를\n * 식별해서 silently skip 할 수 있도록 sentinel 을 반환한다.\n */\nexport function decodeJohab(ch: number): number {\n // ASCII 영역 — 1바이트 직접 사용\n if (ch < 0x80) return ch\n\n // 조합형 한글 (상위 비트 1): cho 5b | jung 5b | jong 5b\n if (ch >= 0x8000) {\n const choIdx = (ch >> 10) & 0x1f\n const jungIdx = (ch >> 5) & 0x1f\n const jongIdx = ch & 0x1f\n\n const cho = CHO_MAP[choIdx]\n const jung = JUNG_MAP[jungIdx]\n const jong = JONG_MAP[jongIdx]\n\n // jong === -1 은 예약/무효 종성 인덱스(0·18·30·31) — '받침 없음'(인덱스 1 → 값 0) 과\n // 구분해야 한다. 종전엔 -1 을 0 으로 치환해 원문에 없던 완성형 음절을 조용히 합성했다\n // (rhwp #2924 정합). 무효면 아래 한자/기호 lookup → JOHAB_UNMAPPED 경로로 넘긴다.\n if (cho !== -1 && jung !== -1 && jong !== -1) {\n // 0xAC00 + (cho * 21 * 28) + (jung * 28) + jong\n return 0xac00 + cho * 588 + jung * 28 + jong\n }\n\n // 한자/기호: lookup table\n const hit = lookupSymbol(ch)\n if (hit !== null) return hit\n return JOHAB_UNMAPPED\n }\n\n // 사적 graphic char 영역 (0x0080~0x7FFF) — rhwp decode_hwp3_extra 포팅\n // (HWP3↔한컴 HWP5 변환본 cross-ref로 도출된 매핑, rhwp e184718~aa8b47c).\n return decodeHwp3Extra(ch)\n}\n\n/**\n * KS X 1001(KS C 5601) 완성형 좌표 한 쌍 → 유니코드 코드포인트. 미배정 자리는 null.\n *\n * row/cell 은 EUC-KR 고위 바이트 표기(0xA1~0xFE). Node 가 small-icu 로 빌드돼\n * 'euc-kr' 을 모르면 디코더가 null 이 되고, 좌표 규칙 전체가 종전처럼 미매핑으로\n * 떨어진다 (xls/encoding.ts 의 CP949 폴백과 같은 계약).\n */\nlet eucKrDecoder: TextDecoder | null | undefined\nfunction kscChar(row: number, cell: number): number | null {\n if (eucKrDecoder === undefined) {\n try {\n eucKrDecoder = new TextDecoder(\"euc-kr\", { fatal: false })\n } catch {\n eucKrDecoder = null\n }\n }\n if (!eucKrDecoder) return null\n if (row < 0xa1 || row > 0xfe || cell < 0xa1 || cell > 0xfe) return null\n const text = eucKrDecoder.decode(Uint8Array.of(row, cell))\n if (text.length !== 1) return null\n const cp = text.codePointAt(0)!\n if (cp === 0xfffd) return null // 완성형에 배정되지 않은 자리\n return hancomVariant(cp)\n}\n\n/**\n * 표준 KS X 1001 매핑과 한컴 관행이 갈리는 자리 보정 (rhwp hancom_variant 포팅).\n * 한컴 변환본 대조에서 실측된 차이만 싣는다.\n */\nfunction hancomVariant(cp: number): number {\n // 0xA1AD: 표준 U+223C(∼) ↔ 한컴 U+FF5E(~). rhwp 실측 80건, kordoc sample11/14 실측 11건.\n if (cp === 0x223c) return 0xff5e\n // 0xA2C1: 표준 U+2299(⊙) ↔ 한컴 U+25C9(◉). sample11 ↔ hwp3-sample11-hwpx 문맥 정렬 2건.\n if (cp === 0x2299) return 0x25c9\n return cp\n}\n\n/**\n * HWP3 기호 영역: KS X 1001 기호행(0xA1~0xAC) 좌표를 **행 간격 96** 으로 편 코드.\n *\n * 기존 하드코딩이 이 식에서 그대로 유도된다 — `→`0x3446·`■`0x3441·`▷`0x3479·\n * `▶`0x347A·`─`0x35E1, 로마숫자 0x3590~0x3599, 원문자 0x36E7~0x36F0 전부 일치.\n * (rhwp decode_hwp3_ksc_symbol 포팅.)\n */\nfunction decodeHwp3KscSymbol(ch: number): number | null {\n if (ch < 0x3401) return null\n const idx = ch - 0x3401\n const row = 0xa1 + Math.floor(idx / 96)\n if (row > 0xac) return null\n return kscChar(row, 0xa1 + (idx % 96))\n}\n\n/**\n * HWP3 한자 영역: KS X 1001 한자행(0xCA~0xFD) 좌표를 **행 간격 94** 로 편 코드.\n * (rhwp decode_hwp3_ksc_hanja 포팅. 실측: `債`0x4F5D→0xF3F0, `權`0x4222→0xCFED.)\n */\nfunction decodeHwp3KscHanja(ch: number): number | null {\n if (ch < 0x4000) return null\n const idx = ch - 0x4000\n const row = 0xca + Math.floor(idx / 94)\n if (row > 0xfd) return null\n return kscChar(row, 0xa1 + (idx % 94))\n}\n\n/**\n * HWP3 사적 graphic char (0x0080~0x7FFF) → 유니코드. 매핑 없으면 JOHAB_UNMAPPED.\n *\n * 하드코딩 표를 **먼저** 보고, 없으면 완성형 좌표 규칙(기호 → 한자)으로 넘어간다.\n * 순서가 중요하다 — 회사명 graphic 0x37C0~0x37C5 는 기호 규칙으로는 가타카나가 된다.\n *\n * rhwp 는 한컴 PUA(U+F03C5 등)를 보존하고 렌더러가 표시값으로 확장하지만,\n * kordoc 은 렌더러 없이 markdown 으로 직행하므로 한컴오피스 표시값을 직접\n * 방출한다 (미매핑 Supplementary PUA 는 builder.sanitizeText 가 제거하므로\n * PUA 방출은 글자 증발로 이어짐). 관계도 선문자(0x301E/0x3024/0x3027)는\n * 표준 근사가 없어 미매핑 유지.\n */\nfunction decodeHwp3Extra(ch: number): number {\n // 라틴 확장(Latin-1 Supplement) — HWP3 은 ü·ö·ä·ß 를 유니코드 값 그대로 hchar 에\n // 담는다. 매핑이 없으면 파서가 조용히 버려 \"für\"→\"fr\" 처럼 글자가 삭제된다\n // (rhwp #5555 — 실측 8코드 ü·ö·ä·ß·Ö·Ü·Ä·é 전부 항등). 사적 따옴표(0x0081~0x0084)는\n // 구간 밖이라 아래 하드코딩이 담당한다.\n if (ch >= 0x00a0 && ch <= 0x00ff) return ch\n // 로마숫자 대문자 Ⅰ~Ⅹ (\"Ⅰ. 사업개요\" 류 장 제목)\n if (ch >= 0x3590 && ch <= 0x3599) return 0x2160 + (ch - 0x3590)\n // 원문자 ①~⑩\n if (ch >= 0x36e7 && ch <= 0x36f0) return 0x2460 + (ch - 0x36e7)\n // 머리말 회사명 그래픽 글자 \"한글과컴퓨터\" 6자 (rhwp 44cabad9 — HWP3 원본 0x37C0~0x37C5,\n // 같은 문서의 HWPX 변환본 U+F03EF~F03F4, 한컴 PDF 표시값 3자 대조로 확정).\n // rhwp 는 PUA 를 보존하고 렌더러가 표시값으로 펼치지만, kordoc 은 표시값 직행 정책.\n if (ch >= 0x37c0 && ch <= 0x37c5) return \"한글과컴퓨터\".codePointAt(ch - 0x37c0)!\n switch (ch) {\n case 0x0081: return 0x201c // 왼쪽 큰따옴표\n case 0x0082: return 0x201d // 오른쪽 큰따옴표\n case 0x301c: return 0x2501 // ━ 굵은 가로선 (rhwp: U+F080F, 표시값 직행)\n // 텍스트 다이어그램 괘선 조각 — 한컴은 U+F0806~F0810 으로 보존하고 rhwp 검증표가\n // ┌┬┐└┘│ 로 편다. HWP3 코드는 그 PUA 에서 상수 오프셋(0xC07F3)만큼 떨어져 있고\n // (0x301C→F080F 가 이미 그 관계), hwp3-sample11 ↔ 변환본 개수도 그대로 맞는다\n // (0x3013×3↔┌, 0x3014×1↔┬, 0x3015×10↔┐, 0x3019×6↔└, 0x301B×9↔┘, 0x301D×17↔│).\n case 0x3013: return 0x250c // ┌\n case 0x3014: return 0x252c // ┬\n case 0x3015: return 0x2510 // ┐\n case 0x3019: return 0x2514 // └\n case 0x301b: return 0x2518 // ┘\n case 0x301d: return 0x2502 // │\n case 0x303d: return 0x25a0 // ■ (rhwp: U+F0827, 표시값 직행)\n case 0x3366: return 0x25a1 // □ 글머리 (rhwp: U+F03C5, 한컴 표시값 직행)\n case 0x3404: return 0x2024 // 한 점 리더\n case 0x3441: return 0x25a0 // ■\n case 0x3446: return 0x2192 // → 오른쪽 화살표\n case 0x35e1: return 0x2500 // ─ 상자 그리기 가로선\n case 0x3479: return 0x25b7 // ▷\n case 0x347a: return 0x25b6 // ▶\n case 0x2f67: return 0x25b8 // ▸ 표 셀 글머리표 (rhwp 16db8260 — HWP5 변환본·한컴 PDF 대조)\n // 아래 항등 코드들은 rhwp #5860 실측표(한글 2022 오라클 위치 정렬) 이식.\n // 같은 0x20xx 대에 항등과 비항등이 섞여 있어 구간 통과는 하지 않는다.\n case 0x2010: return 0x2010 // ‐\n case 0x2013: return 0x2013 // –\n case 0x2103: return 0x2103 // ℃\n case 0x2113: return 0x2113 // ℓ\n case 0x2190: return 0x2190 // ←\n case 0x2192: return 0x2192 // →\n case 0x2193: return 0x2193 // ↓\n case 0x2219: return 0x2219 // ∙ (sample11 실측 11건)\n case 0x22c5: return 0x22c5 // ⋅\n case 0x203b: return 0x203b // ※ — 한자를 완성형 좌표로 담으면서 ※ 만 유니코드 값으로 담은 문서가 있다\n // 비항등 — 유니코드로 읽으면 ⁚·․·⁘ 같은 다른 글자가 된다 (rhwp #5860)\n case 0x2024: return 0x30fb // ・\n case 0x2058: return 0x25b3 // △\n case 0x205a: return 0x25cb // ○\n case 0x2f08: return 0x25aa // ▪\n case 0x2f11: return 0x25e6 // ◦ (sample16 실측 332건)\n case 0x2f14: return 0x25e6 // ◦\n case 0x3157: return 0x2027 // ‧\n case 0x0480: return 0x02d0 // ː\n case 0x1f2e: return 0x306e // の\n case 0x32b0: return 0xff70 // ー (반각)\n case 0x3067: return 0x2018 // ‘\n case 0x3068: return 0x2019 // ’\n case 0x309b: return 0xff62 // 「\n case 0x309d: return 0xff63 // 」\n case 0x0083: return 0x2018 // ‘ — 큰따옴표(0x0081/0x0082) 바로 다음 코드 (sample11/14 실측 18건)\n case 0x0084: return 0x2019 // ’\n // 아래 셋은 rhwp 표에 없는 값 — kordoc 이 rhwp 샘플 ↔ 한컴 변환본 문맥 정렬로 실측했다.\n case 0x2022: return 0x2022 // • hwp3-sample 글머리표 4건 (항등)\n case 0x2f17: return 0x2022 // • hwp3-sample10 글머리표 3건\n case 0x2f06: return 0x25a0 // ■ hwp3-sample10 \"제목차례\" 좌우 장식 2건\n // SO-SUEOP ↔ 한컴 HWP3→HWPX 변환본 문맥 정렬 — 코드 개수와 변환본 글자 증가분이 전부 일치\n // (“ 13·” 14·‧ 4·《 3·》 3·— 1·∣ 6·↳ 18). 앞 셋은 항등, 0x3062~0x30BD 는 사적 문장부호\n case 0x2014: return 0x2014 // —\n case 0x2223: return 0x2223 // ∣\n case 0x21b3: return 0x21b3 // ↳\n case 0x3062: return 0x201c // “\n case 0x3063: return 0x201d // ”\n case 0x3066: return 0x2027 // ‧\n case 0x30bb: return 0x300a // 《\n case 0x30bd: return 0x300b // 》\n // 관인·서명란 도장 기호. rhwp 는 U+F012B 로 보존하고 렌더러가 `(인)` 으로 편다 —\n // kordoc 도 PUA 를 그대로 내보내면 shared/pua.ts 의 검증표가 같은 문자열로 편다.\n case 0x2bce: return 0xf012b\n // ═ 겹줄. rhwp 는 0x3048 을 U+F0832(렌더 표시값 `═`)로 보존한다. 0x37ED 는 기호\n // 규칙으로는 가타카나 `ネ` 가 되는 사적 graphic 코드로, sample10(42건)·sample11(12건)\n // 두 문서에서 한컴 변환본의 `═` 개수와 정확히 일치해 표시값 직행으로 싣는다.\n case 0x3048: return 0x2550\n case 0x37ed: return 0x2550\n // 사적 원문자·괄호문자 계열. 사적 코드는 일반식이 없어 실측 문서에서 연속으로\n // 확인된 구간만 싣는다 (sample11 ↔ hwp3-sample11-hwpx 문맥 정렬).\n // 0x2E01~0x2E07 → ①~⑦ 7코드 연속 일치, 0x2C21~0x2C26 → ⓐ~ⓕ (ⓒ~ⓕ 개수 일치),\n // 0x2C40~0x2C42 → ㉠~㉢\n default:\n if (ch >= 0x2e01 && ch <= 0x2e07) return 0x2460 + (ch - 0x2e01)\n // 한컴이 PUA(U+F0288~F0291)로 보존하는 별도 원문자 글리프 계열. hwp3-sample11 의\n // NVRAM 라벨 줄에서 코드 개수와 변환본 PUA 개수가 정확히 일치한다\n // (0x2E00×2↔F0288×2, 0x2E0A×3↔F0289×3, 0x2E0B~0x2E12 각 1건↔F028A~F0291 각 1건).\n // kordoc 은 표시값 직행이라 rhwp 검증표의 표시 문자(⓪~⑨)를 바로 낸다.\n if (ch === 0x2e00) return 0x24ea // ⓪\n if (ch >= 0x2e0a && ch <= 0x2e12) return 0x2460 + (ch - 0x2e0a)\n if (ch >= 0x2c21 && ch <= 0x2c26) return 0x24d0 + (ch - 0x2c21)\n if (ch >= 0x2c40 && ch <= 0x2c42) return 0x3260 + (ch - 0x2c40)\n return decodeHwp3KscSymbol(ch) ?? decodeHwp3KscHanja(ch) ?? JOHAB_UNMAPPED\n }\n}\n\n/**\n * HWP3 hchar stream (u16 LE 순서) 를 string 으로 디코딩.\n *\n * DocSummary 의 56 hchar (112 byte) 영역에 사용. 본문 char stream 과 같은 단위인데\n * 그 영역은 ASCII 도 high byte 0 으로 padding 되어 있다 (\"C\\x00r\\x00...\"). byte 단위\n * 디코딩으로 처리하면 NUL 에서 break 되어 첫 글자만 남으므로, hchar 단위 LE u16 로\n * 읽고 그 값이 0 이면 종료한다.\n */\nexport function decodeHcharString(bytes: Uint8Array): string {\n let out = \"\"\n let i = 0\n while (i + 1 < bytes.length) {\n const ch = bytes[i] | (bytes[i + 1] << 8) // LE u16\n if (ch === 0) break\n out += decodeJohabText(ch) ?? \"\"\n i += 2\n }\n return out\n}\n\n/**\n * HWP3 byte sequence (1바이트 ASCII < 0x80, 2바이트 johab >= 0x80) 를 string 으로 디코딩.\n * NUL byte 만나면 종료. link_print_file/description 같은 짧은 byte string 영역에 사용.\n */\nfunction decodeHwp3String(bytes: Uint8Array): string {\n let out = \"\"\n let i = 0\n while (i < bytes.length) {\n const b1 = bytes[i]\n if (b1 === 0) break\n if (b1 < 0x80) {\n out += String.fromCharCode(b1)\n i += 1\n } else if (i + 1 < bytes.length) {\n const ch = (b1 << 8) | bytes[i + 1]\n out += decodeJohabText(ch) ?? \"\"\n i += 2\n } else {\n i += 1\n }\n }\n return out\n}\n","/**\n * HWP3 fixed-size record definitions.\n *\n * 모두 little-endian. 구조는 rhwp/src/parser/hwp3/records.rs 와 1:1 대응.\n * 텍스트 추출에 필요한 필드만 명시적으로 노출하고, 레이아웃 전용 필드 (margins,\n * tab stops 등) 는 단순 skip 한다.\n */\n\nimport { Reader } from \"./reader.js\"\nimport { decodeHcharString } from \"./johab.js\"\n\n// HWP3 file signature: \"HWP Document File V3.00 \" (24 bytes) + 6-byte tail (\\x1A\\x01\\x02\\x03\\x04\\x05)\n// 총 30 byte. 일부 실제 파일은 첫 30 byte 이내에 NUL pad 가 끼어있는 경우가 있어\n// 앞 23 byte 의 ASCII signature 만 strict 비교하고 나머지 7 byte 는 advisory.\nexport const SIGNATURE_PREFIX = Buffer.from(\"HWP Document File V3.00\", \"ascii\")\nexport const SIGNATURE_LEN = 30\n\n/** rhwp 와 같은 고정 byte size. cursor 가 정확히 이 만큼 advance 한다. */\nexport const DOC_INFO_SIZE = 128\nexport const DOC_SUMMARY_SIZE = 9 * 112 // 9 fields × 112 bytes (56 hchar each)\n\nexport interface Hwp3Header {\n /** DocInfo의 압축 플래그 (0이 아니면 InfoBlock 이후 raw deflate 압축). */\n compressed: number\n /** DocInfo 의 encrypted 플래그 (0 이 아니면 본문 암호화 → 복호화 못함). */\n encrypted: number\n /** InfoBlock 길이 (DocSummary 뒤 가변 길이 metadata). */\n infoBlockLength: number\n /** DocSummary 에서 추출한 메타데이터. */\n title: string\n subject: string\n author: string\n date: string\n}\n\n/**\n * 헤더 파싱: 30 byte signature + 128 byte DocInfo + 1008 byte DocSummary.\n * 호출 시 reader 위치는 0 이어야 하고, 반환 후엔 InfoBlock 시작점.\n */\nexport function readHeader(reader: Reader): Hwp3Header {\n // signature 30 byte — strict prefix check\n const sig = reader.readBytes(SIGNATURE_LEN)\n if (!sig.subarray(0, SIGNATURE_PREFIX.length).equals(SIGNATURE_PREFIX)) {\n throw new Error(\"HWP3: invalid file signature\")\n }\n\n // DocInfo 128 byte — 텍스트 추출에 필요한 3개 필드 외엔 skip.\n // 절대 offset 기준 (DocInfo 시작점 = docInfoStart):\n // encrypted : offset 96..97 (u16) — 0 이 아니면 본문 암호 보호\n // compressed : offset 124 (u8) — 0 이 아니면 InfoBlock 이후 raw deflate\n // info_block_length : offset 126..127 (u16) — 가변 InfoBlock 길이\n const docInfoStart = reader.position()\n reader.skip(96)\n const encrypted = reader.readU16() // 96..97\n reader.skip(124 - 98) // → 124\n const compressed = reader.readU8() // 124\n reader.skip(1) // sub_revision (125)\n const infoBlockLength = reader.readU16() // 126..127\n // DocInfo 끝까지 정확히 advance — sanity\n if (reader.position() !== docInfoStart + DOC_INFO_SIZE) {\n throw new Error(\n `HWP3: DocInfo size mismatch (got ${reader.position() - docInfoStart}, expected ${DOC_INFO_SIZE})`,\n )\n }\n\n // DocSummary 1008 byte — title/subject/author/date 만 추출, 나머지 (keywords, etc) skip.\n // DocSummary 의 string 은 56 hchar × 2 byte 로 구성 — byte 단위가 아닌 u16 hchar 단위로\n // 디코딩해야 ASCII 문자가 high byte 0 padding 으로 인해 잘리지 않는다.\n const summaryStart = reader.position()\n const title = decodeHcharString(reader.readBytes(112))\n const subject = decodeHcharString(reader.readBytes(112))\n const author = decodeHcharString(reader.readBytes(112))\n const date = decodeHcharString(reader.readBytes(112))\n // 나머지 (keywords ×2 + etc ×3 = 5 × 112 = 560 byte) skip\n reader.skip(5 * 112)\n if (reader.position() !== summaryStart + DOC_SUMMARY_SIZE) {\n throw new Error(\"HWP3: DocSummary size mismatch\")\n }\n\n return { compressed, encrypted, infoBlockLength, title, subject, author, date }\n}\n","/**\n * 비밀번호로 보호된 HWP3 문서 복호화.\n *\n * HWP3 은 CFB 컨테이너가 아니라 단일 스트림이라, 고정 헤더 뒤 전체가 **DES-ECB** 로\n * 암호화되어 있다.\n *\n * [0..30) 시그니처\n * [30..158) 문서 정보 128B — +96 암호 여부(u16), +124 압축 여부(u8), +126 정보블록 길이(u16)\n * [158..1166) 문서 요약 1008B\n * [1166..) 정보 블록(가변) → **여기서부터 끝까지가 암호문**\n *\n * 복호하면 raw deflate 스트림이 나오고, 압축을 풀면 선두 256바이트가 암호 확인용\n * prefix, 그 뒤가 실제 본문이다. 별도 검증 해시가 없어 **압축 무결성이 곧 인증**이다\n * (inflate 성공 + CRC32 + ISIZE 일치).\n *\n * 알고리즘 참조: rhwp (MIT) src/parser/hwp3/crypto.rs\n */\n\nimport { createDecipheriv } from \"crypto\"\nimport { inflateRawSync } from \"zlib\"\nimport { KordocError } from \"../utils.js\"\nimport { SIGNATURE_LEN, DOC_INFO_SIZE, DOC_SUMMARY_SIZE } from \"./records.js\"\n\nconst FIXED_HEADER_BYTES = SIGNATURE_LEN + DOC_INFO_SIZE + DOC_SUMMARY_SIZE\nconst PASSWORD_FLAG_OFFSET = SIGNATURE_LEN + 96\nconst COMPRESSION_FLAG_OFFSET = SIGNATURE_LEN + 124\nconst INFO_BLOCK_LENGTH_OFFSET = SIGNATURE_LEN + 126\n/** 복호·압축 해제한 본문 선두의 암호 확인 블록 — 파서에 넘기면 글꼴 테이블이 어긋난다 */\nconst PASSWORD_PREFIX_BYTES = 256\n/** 압축 해제 결과 상한 — deflate bomb 방어 (hwp3/parser.ts 와 같은 정책) */\nconst MAX_DECOMPRESSED_BYTES = 100 * 1024 * 1024\n\n/** 암호 문서 여부 — 문서 정보의 암호 플래그(u16) */\nexport function isEncryptedHwp3(data: Uint8Array): boolean {\n if (data.length < FIXED_HEADER_BYTES) return false\n return (data[PASSWORD_FLAG_OFFSET] | (data[PASSWORD_FLAG_OFFSET + 1] << 8)) !== 0\n}\n\n/**\n * 비밀번호 → DES 키 8바이트.\n *\n * 비밀번호를 UTF-16LE 바이트열로 펼쳐 7바이트 링 버퍼에 `slot = ROL1(slot ^ byte)` 로\n * 누적한 뒤, 그 56비트를 7비트씩 잘라 각 키 바이트의 상위 7비트에 배치한다\n * (최하위 비트는 DES 패리티 자리라 0으로 남는다).\n */\nexport function deriveDesKey(password: string): Buffer {\n const rolling = new Uint8Array(7)\n let index = 0\n for (let i = 0; i < password.length; i++) {\n const unit = password.charCodeAt(i) // UTF-16 코드 유닛 (서로게이트도 유닛 단위로 흐른다)\n for (const byte of [unit & 0xff, (unit >> 8) & 0xff]) {\n const slot = index % rolling.length\n const mixed = rolling[slot] ^ byte\n rolling[slot] = ((mixed << 1) | (mixed >> 7)) & 0xff // ROL 1\n index++\n }\n }\n\n const key = Buffer.alloc(8)\n for (let bit = 0; bit < 56; bit++) {\n const sourceBit = (rolling[Math.floor(bit / 8)] >> (7 - (bit % 8))) & 1\n key[Math.floor(bit / 7)] |= sourceBit << (7 - (bit % 7))\n }\n return key\n}\n\n/**\n * DES-ECB 복호.\n *\n * Node 는 OpenSSL 3 에서 단일 DES 가 legacy provider 로 빠져 `des-ecb` 를 제공하지 않는다.\n * 3DES 에 같은 키를 세 번 넣으면 EDE 구조상 단일 DES 와 결과가 같다(K1=K2=K3 → E-D-E = E).\n */\nfunction desEcbDecrypt(data: Buffer, key: Buffer): Buffer {\n const decipher = createDecipheriv(\"des-ede3-ecb\", Buffer.concat([key, key, key]), null)\n decipher.setAutoPadding(false)\n return Buffer.concat([decipher.update(data), decipher.final()])\n}\n\n/** 문서 정보에서 본문(암호문) 시작 위치와 압축 여부를 읽는다 */\nfunction readLayout(data: Uint8Array): { payloadOffset: number; compressed: boolean } {\n if (data.length < FIXED_HEADER_BYTES) {\n throw new KordocError(\"HWP3 암호 문서: 헤더가 잘렸습니다\")\n }\n const infoBlockLength =\n data[INFO_BLOCK_LENGTH_OFFSET] | (data[INFO_BLOCK_LENGTH_OFFSET + 1] << 8)\n const payloadOffset = FIXED_HEADER_BYTES + infoBlockLength\n if (payloadOffset >= data.length) {\n throw new KordocError(\"HWP3 암호 문서: 본문이 없습니다\")\n }\n return { payloadOffset, compressed: data[COMPRESSION_FLAG_OFFSET] !== 0 }\n}\n\n/**\n * 암호 HWP3 → 평문 HWP3 바이트.\n *\n * 반환값은 암호·압축 플래그를 0으로 지우고 본문을 평문으로 바꾼 것이라, 기존 HWP3\n * 파서에 그대로 넣을 수 있다.\n */\nexport function decryptHwp3Document(input: Uint8Array, password: string): Buffer<ArrayBuffer> {\n const { payloadOffset, compressed } = readLayout(input)\n if (!compressed) {\n // 실물 표본이 없어 검증할 수 없다 — 지어내기보다 명시적으로 거부한다\n throw new KordocError(\"지원하지 않는 HWP3 암호화 방식입니다 (압축되지 않은 암호 본문)\")\n }\n\n const source = Buffer.from(input)\n const payload = source.subarray(payloadOffset)\n // DES 는 8바이트 블록 — 끝의 정렬 패딩은 잘라낸다\n const aligned = payload.subarray(0, payload.length - (payload.length % 8))\n if (aligned.length === 0) {\n throw new KordocError(\"HWP3 암호 문서: 본문이 너무 짧습니다\")\n }\n\n const decrypted = desEcbDecrypt(aligned, deriveDesKey(password))\n\n let inflated: Buffer\n try {\n inflated = inflateRawSync(decrypted, { maxOutputLength: MAX_DECOMPRESSED_BYTES })\n } catch (err) {\n if ((err as NodeJS.ErrnoException)?.code === \"ERR_BUFFER_TOO_LARGE\") {\n throw new KordocError(\n `HWP3 암호 본문의 압축 해제 결과가 최대 허용 크기(${MAX_DECOMPRESSED_BYTES / 1024 / 1024}MB)를 초과했습니다`,\n )\n }\n // 비밀번호가 틀리면 복호 결과가 난수라 inflate 가 깨진다 — 압축 무결성이 곧 인증\n throw new KordocError(\"비밀번호가 일치하지 않거나 암호화 데이터가 손상되었습니다.\")\n }\n\n if (inflated.length <= PASSWORD_PREFIX_BYTES) {\n throw new KordocError(\"비밀번호가 일치하지 않거나 암호화 데이터가 손상되었습니다.\")\n }\n\n const body = inflated.subarray(PASSWORD_PREFIX_BYTES)\n const out = Buffer.concat([source.subarray(0, payloadOffset), body])\n out.writeUInt16LE(0, PASSWORD_FLAG_OFFSET) // 암호 플래그 해제\n out[COMPRESSION_FLAG_OFFSET] = 0 // 본문을 이미 풀었으므로 압축 플래그도 해제\n return out\n}\n","/**\n * HWP3 표 격자 복원 — 셀 정보(27바이트)의 기하로 행·열 좌표와 병합을 만든다.\n *\n * HWP3 셀 레코드에는 HWP5 LIST_HEADER 같은 격자 colAddr/rowAddr 가 없다(바이트 0·1 은 한글 97 자체 줄·칸 순번이라\n * 한컴 변환본 격자와 다르다). 셀마다 x·y·w·h(u16 @4·6·8·10, HWP3 단위)가 있어 다음 규칙으로 격자를 세운다 —\n * 한컴 HWP3→HWP5/HWPX 변환본 표 120개(hwp3-sample·10·11·16·19·SO-SUEOP)의 행·열·앵커를 전부 재현한 규칙:\n * - 열 경계 = 셀 왼쪽 변 x 의 서로 다른 값 전부(허용치 없음 — 1단위 차이도 별도 열) + 표 오른쪽 끝,\n * 행 경계 = 셀 위쪽 변 y 전부 + 표 아래쪽 끝. 오른쪽·아래쪽 변은 경계를 만들지 않는다\n * (셀 높이 합이 틀 높이보다 짧은 칸이 가짜 행을 만들지 않게 — sample16 접수 서식 16×4 → 15×4)\n * - 셀의 오른쪽 끝 = 같은 행에 걸친 오른쪽 이웃 셀의 왼쪽 변(없으면 표 오른쪽 끝), 아래쪽 끝 = 아래 이웃의 위쪽 변\n * (저장 좌표 1단위 어긋남으로 병합 폭이 한 칸 모자라지 않게 — sample16 인력 투입표)\n * 이 규칙은 rhwp(양쪽 변 + 허용치 40HU)와 다르다 — rhwp 규칙은 같은 120개 중 4개 표의 행·열이 어긋난다.\n * 겹침·빈 칸 처리는 호출측(ir-assemble.buildAddressedTable)이 맡는다.\n */\n\nimport { MAX_COLS, MAX_ROWS } from \"../table/builder.js\"\n\n/** 이웃 판정 허용치 — 이웃 셀 왼쪽 변이 이 셀 오른쪽 변보다 조금 안쪽에 있어도(저장 반올림) 이웃으로 본다 */\nconst NEIGHBOR_SLACK = 10\n/** 이웃 탐색 전진 상한 — 실측 최대 표(sample16 367셀)의 몇 배 */\nconst MAX_NEIGHBOR_SCAN = 2048\n\nexport interface Hwp3CellPos {\n row: number\n col: number\n rowSpan: number\n colSpan: number\n}\n\nexport interface Hwp3Grid {\n rows: number\n cols: number\n cells: Hwp3CellPos[]\n}\n\ninterface Geo { x: number; y: number; r: number; b: number }\n\nconst uniqSorted = (values: number[]): number[] => [...new Set(values)].sort((a, b) => a - b)\n\n/** 정렬된 경계 배열에서 v 의 위치 (v 는 경계에 있다) */\nfunction edgeAt(edges: number[], v: number): number {\n let lo = 0, hi = edges.length - 1\n while (lo < hi) {\n const mid = (lo + hi) >> 1\n if (edges[mid] < v) lo = mid + 1\n else hi = mid\n }\n return lo\n}\n\n/**\n * 각 셀의 \"다음 이웃 시작\" — axis 방향(x: 오른쪽, y: 아래)으로 끝 변 이후에 시작하면서 다른 축으로 겹치는\n * 셀 중 가장 가까운 시작 좌표. 없으면 undefined. 시작 좌표 정렬 + 이분 탐색 후 전진(표 크기 × 행 수 수준)\n */\nfunction nextStarts(geo: Geo[], axis: \"x\" | \"y\"): Array<number | undefined> {\n const start = axis === \"x\" ? (g: Geo) => g.x : (g: Geo) => g.y\n const end = axis === \"x\" ? (g: Geo) => g.r : (g: Geo) => g.b\n const overlap = axis === \"x\"\n ? (a: Geo, b: Geo) => b.y < a.b && b.b > a.y\n : (a: Geo, b: Geo) => b.x < a.r && b.r > a.x\n const order = geo.map((_, i) => i).sort((i, j) => start(geo[i]) - start(geo[j]))\n const starts = order.map(i => start(geo[i]))\n return geo.map(a => {\n // 끝 변 − 허용치 이상, 그리고 자기 시작보다 뒤에서 시작하는 첫 후보부터. 정상 표는 행(열) 수 안에서 찾는다 —\n // 손상 파일의 계단형 셀 수만 개가 O(n²) 로 도는 것을 막는 상한\n let k = edgeAt(starts, Math.max(end(a) - NEIGHBOR_SLACK, start(a) + 1))\n for (let steps = 0; k < order.length && steps < MAX_NEIGHBOR_SCAN; k++, steps++) {\n const b = geo[order[k]]\n if (start(b) <= start(a)) continue\n if (overlap(a, b)) return start(b)\n }\n return undefined\n })\n}\n\n/** 셀 정보 블록(27바이트 × count) → 행·열 수와 셀별 좌표·병합 (셀 스트림 순서 그대로) */\nexport function hwp3CellGrid(info: Buffer, count: number): Hwp3Grid {\n const geo: Geo[] = []\n let right = 0, bottom = 0 // 셀 수가 수만일 수 있어 Math.max(...spread) 대신 누적 (인자 수 한도)\n for (let k = 0; k < count; k++) {\n const o = k * 27\n const x = info.readUInt16LE(o + 4), y = info.readUInt16LE(o + 6)\n const g = { x, y, r: x + info.readUInt16LE(o + 8), b: y + info.readUInt16LE(o + 10) }\n geo.push(g)\n if (g.r > right) right = g.r\n if (g.b > bottom) bottom = g.b\n }\n const xs = uniqSorted([...geo.map(g => g.x), right])\n const ys = uniqSorted([...geo.map(g => g.y), bottom])\n const nextX = nextStarts(geo, \"x\")\n const nextY = nextStarts(geo, \"y\")\n const cells = geo.map((g, k) => {\n const col = edgeAt(xs, g.x), row = edgeAt(ys, g.y)\n const c2 = nextX[k] !== undefined ? edgeAt(xs, nextX[k]!) : xs.length - 1\n const r2 = nextY[k] !== undefined ? edgeAt(ys, nextY[k]!) : ys.length - 1\n // 행·열·병합 상한은 HWP5 표와 같은 값 (손상 파일의 쓰레기 기하가 격자를 폭주시키지 않게)\n return { row, col, rowSpan: Math.min(Math.max(1, r2 - row), MAX_ROWS), colSpan: Math.min(Math.max(1, c2 - col), MAX_COLS) }\n })\n return { rows: Math.min(Math.max(1, ys.length - 1), MAX_ROWS), cols: Math.min(Math.max(1, xs.length - 1), MAX_COLS), cells }\n}\n","/**\n * HWP 5.x 배포용 문서 \"상위 버전\" 경고 플레이스홀더 감지.\n *\n * 배포용(열람 제한) HWP 파일은 본문을 암호화하고, 복호화 실패 시 한컴에서 삽입한\n * 고정 경고 문자열이 노출된다. 이 문자열이 파싱 결과의 대부분을 차지하면 COM API\n * fallback으로 전환해야 한다.\n *\n * 이슈 #25 참고.\n */\n\n// 배포용 HWP의 고정 경고 문구 (버전·지역에 따라 미세 차이 가능 → 핵심 키만 매칭)\nconst SENTINEL_PATTERNS: RegExp[] = [\n /상위\\s*버전의\\s*배포용\\s*문서/,\n /최신\\s*버전의\\s*한글.*뷰어/,\n /문서를\\s*읽으려면/,\n]\n\n/**\n * 본문이 배포용 플레이스홀더로만 채워졌는지 판정.\n *\n * 기준:\n * - 패턴이 한 번 이상 매치\n * - 패턴을 제거한 나머지 의미 있는 텍스트가 매우 짧음 (공백·개행 제외 120자 미만)\n *\n * → 정상 본문이 섞여 있으면 false (COM fallback 불필요)\n */\nexport function isDistributionSentinel(markdown: string): boolean {\n if (!markdown) return false\n const hit = SENTINEL_PATTERNS.some(p => p.test(markdown))\n if (!hit) return false\n\n // 경고 문구 라인 제거 후 실질 내용이 짧은지\n const stripped = markdown\n .split(/\\r?\\n/)\n .filter(line => !SENTINEL_PATTERNS.some(p => p.test(line)))\n .join(\"\")\n .replace(/\\s+/g, \"\")\n\n return stripped.length < 120\n}\n","/**\n * XLSX (Office Open XML Spreadsheet) 파서\n *\n * ZIP + XML 구조를 jszip + xmldom으로 파싱하여 IRBlock[]로 변환.\n * 각 시트 → heading(시트명) + table(데이터) 블록.\n */\n\nimport JSZip from \"jszip\"\nimport { DOMParser } from \"@xmldom/xmldom\"\nimport type {\n IRBlock, IRTable, IRCell, CellContext, DocumentMetadata, InternalParseResult,\n ParseOptions, ParseWarning, ExtractedImage,\n} from \"../types.js\"\nimport { KordocError, precheckZipSize, stripDtd } from \"../utils.js\"\nimport { buildTable, blocksToMarkdown } from \"../table/builder.js\"\n\n// ─── 상수 ────────────────────────────────────────────\n\nconst MAX_SHEETS = 100\n/** ZIP 압축 해제 누적 최대 크기 (100MB) — ZIP bomb 방지 */\nconst MAX_DECOMPRESS_SIZE = 100 * 1024 * 1024\nconst MAX_ROWS = 10000\nconst MAX_COLS = 200\n\n// ─── 숫자값 정리 ──────────────────────────────────────\n\n/** 부동소수점 아티팩트 정리 (132.30000000000001 → 132.3) */\nfunction cleanNumericValue(raw: string): string {\n if (!/^-?\\d+\\.\\d+$/.test(raw)) return raw\n const num = parseFloat(raw)\n if (!isFinite(num)) return raw\n // toPrecision(15)로 IEEE 754 오차 제거 후 불필요한 후행 0 제거\n const cleaned = parseFloat(num.toPrecision(15)).toString()\n return cleaned\n}\n\n// ─── 셀 참조 파싱 ──────────────────────────────────────\n\n/** \"A1\" → { col: 0, row: 0 }, \"AB123\" → { col: 27, row: 122 } */\nfunction parseCellRef(ref: string): { col: number; row: number } | null {\n const m = ref.match(/^([A-Z]+)(\\d+)$/)\n if (!m) return null\n let col = 0\n for (const ch of m[1]) col = col * 26 + (ch.charCodeAt(0) - 64)\n return { col: col - 1, row: parseInt(m[2], 10) - 1 }\n}\n\n/** \"A1:C3\" → { startCol, startRow, endCol, endRow } */\nfunction parseMergeRef(ref: string): { startCol: number; startRow: number; endCol: number; endRow: number } | null {\n const parts = ref.split(\":\")\n if (parts.length !== 2) return null\n const start = parseCellRef(parts[0])\n const end = parseCellRef(parts[1])\n if (!start || !end) return null\n return { startCol: start.col, startRow: start.row, endCol: end.col, endRow: end.row }\n}\n\n// ─── XML 헬퍼 ──────────────────────────────────────────\n\nfunction getElements(parent: Element, tagName: string): Element[] {\n const nodes = parent.getElementsByTagName(tagName)\n const result: Element[] = []\n for (let i = 0; i < nodes.length; i++) result.push(nodes[i] as Element)\n if (result.length > 0) return result\n // 한셀(HCell) 등은 spreadsheetml을 접두사로 선언(<x:sheet>) — localName 폴백 매칭\n const nsNodes = parent.getElementsByTagNameNS?.(\"*\", tagName)\n if (nsNodes) for (let i = 0; i < nsNodes.length; i++) result.push(nsNodes[i] as Element)\n return result\n}\n\nfunction getTextContent(el: Element): string {\n return el.textContent?.trim() ?? \"\"\n}\n\nfunction parseXml(text: string): Document {\n return new DOMParser().parseFromString(stripDtd(text), \"text/xml\") as unknown as Document\n}\n\n// ─── 공유 문자열 파싱 ──────────────────────────────────\n\n/** si/is 하위 t 텍스트 수집 — rPh(후리가나) 하위 t는 본문이 아니므로 제외 */\nfunction collectRichText(root: Element): string {\n let out = \"\"\n const walk = (node: Element) => {\n const children = node.childNodes\n for (let i = 0; i < children.length; i++) {\n if (children[i].nodeType !== 1) continue\n const el = children[i] as Element\n const local = el.localName || el.tagName?.replace(/^[^:]+:/, \"\") || \"\"\n if (local === \"rPh\") continue\n if (local === \"t\") out += el.textContent ?? \"\"\n else walk(el)\n }\n }\n walk(root)\n return out\n}\n\nfunction parseSharedStrings(xml: string): string[] {\n const doc = parseXml(xml)\n const strings: string[] = []\n const siList = getElements(doc.documentElement, \"si\")\n for (const si of siList) {\n // <si><t>text</t></si> 또는 <si><r><t>text</t></r>...</si>\n strings.push(collectRichText(si))\n }\n return strings\n}\n\n// ─── 날짜 서식 판정 ────────────────────────────────────\n\nexport type DateKind = \"date\" | \"datetime\"\n\n/** ECMA-376 내장 날짜 numFmtId (14~17: 날짜, 18~22·45~47: 시각 포함) */\nconst BUILTIN_DATE_FMT: ReadonlyMap<number, DateKind> = new Map<number, DateKind>([\n [14, \"date\"], [15, \"date\"], [16, \"date\"], [17, \"date\"],\n [18, \"datetime\"], [19, \"datetime\"], [20, \"datetime\"], [21, \"datetime\"], [22, \"datetime\"],\n [45, \"datetime\"], [46, \"datetime\"], [47, \"datetime\"],\n])\n\n/**\n * 커스텀 formatCode의 날짜 패턴 감지.\n * 따옴표 리터럴·[조건/색상]·\\이스케이프를 제거한 뒤 y/m/d/h가 있으면 날짜,\n * 그중 h/s가 있으면 시간 포함(datetime)으로 분류. 날짜 아니면 null.\n */\nexport function classifyDateFormat(code: string): DateKind | null {\n const stripped = code.replace(/\"[^\"]*\"/g, \"\").replace(/\\[[^\\]]*\\]/g, \"\").replace(/\\\\./g, \"\")\n if (!/[ymdh]/i.test(stripped)) return null\n return /[hs]/i.test(stripped) ? \"datetime\" : \"date\"\n}\n\n/** 내장/커스텀 numFmtId → 날짜 종류 (날짜 아니면 null) */\nexport function dateKindOfFmt(fmtId: number, customFormats: Map<number, string>): DateKind | null {\n const builtin = BUILTIN_DATE_FMT.get(fmtId)\n if (builtin) return builtin\n const code = customFormats.get(fmtId)\n return code !== undefined ? classifyDateFormat(code) : null\n}\n\n/**\n * Excel 날짜 시리얼 → ISO 문자열 (date1904 반영).\n * 1900 체계는 존재하지 않는 1900-02-29(시리얼 60) 이전 구간 보정.\n * 범위 밖(음수·year>9999)이면 null → 호출자가 원시값 유지.\n */\nexport function dateSerialToIso(serial: number, date1904: boolean, kind: DateKind): string | null {\n if (!isFinite(serial) || serial < 0) return null\n let days = serial\n if (date1904) days += 1462\n else if (days < 60) days += 1\n // 기준일 1899-12-30 — epoch(1970-01-01)의 시리얼은 25569\n const ms = Math.round((days - 25569) * 86400000)\n const d = new Date(ms)\n if (isNaN(d.getTime()) || d.getUTCFullYear() > 9999) return null\n const iso = d.toISOString()\n return kind === \"datetime\" ? iso.slice(0, 19) : iso.slice(0, 10)\n}\n\n/** styles.xml → cellXfs 인덱스별 날짜 서식 종류 (날짜 아닌 xf는 미포함) */\nfunction parseStyleDateXfs(xml: string): Map<number, DateKind> {\n const doc = parseXml(xml)\n const customFormats = new Map<number, string>()\n for (const el of getElements(doc.documentElement, \"numFmt\")) {\n const id = parseInt(el.getAttribute(\"numFmtId\") ?? \"\", 10)\n if (isNaN(id)) continue\n customFormats.set(id, el.getAttribute(\"formatCode\") ?? \"\")\n }\n const dateXfs = new Map<number, DateKind>()\n const cellXfsEls = getElements(doc.documentElement, \"cellXfs\")\n if (cellXfsEls.length === 0) return dateXfs\n const xfs = getElements(cellXfsEls[0], \"xf\")\n for (let i = 0; i < xfs.length; i++) {\n const fmtId = parseInt(xfs[i].getAttribute(\"numFmtId\") ?? \"\", 10)\n if (isNaN(fmtId)) continue\n const kind = dateKindOfFmt(fmtId, customFormats)\n if (kind) dateXfs.set(i, kind)\n }\n return dateXfs\n}\n\n// ─── 시트 목록 파싱 ─────────────────────────────────────\n\ninterface SheetInfo {\n name: string\n sheetId: string\n rId: string\n}\n\nfunction parseWorkbook(xml: string): { sheets: SheetInfo[]; date1904: boolean } {\n const doc = parseXml(xml)\n const sheets: SheetInfo[] = []\n const sheetElements = getElements(doc.documentElement, \"sheet\")\n for (const el of sheetElements) {\n sheets.push({\n name: el.getAttribute(\"name\") ?? `Sheet${sheets.length + 1}`,\n sheetId: el.getAttribute(\"sheetId\") ?? \"\",\n rId: el.getAttribute(\"r:id\") ?? \"\",\n })\n }\n // workbookPr date1904 — 날짜 시리얼 기준 체계\n const prEls = getElements(doc.documentElement, \"workbookPr\")\n const d1904 = prEls.length > 0 ? prEls[0].getAttribute(\"date1904\") : null\n return { sheets, date1904: d1904 === \"1\" || d1904 === \"true\" }\n}\n\n/** workbook.xml.rels 파싱 → rId → target 매핑 */\nfunction parseRels(xml: string): Map<string, string> {\n const doc = parseXml(xml)\n const map = new Map<string, string>()\n const rels = getElements(doc.documentElement, \"Relationship\")\n for (const rel of rels) {\n const id = rel.getAttribute(\"Id\")\n const target = rel.getAttribute(\"Target\")\n if (id && target) map.set(id, target)\n }\n return map\n}\n\n// ─── 워크시트 파싱 ──────────────────────────────────────\n\ninterface MergeInfo {\n startCol: number\n startRow: number\n endCol: number\n endRow: number\n}\n\nfunction parseWorksheet(\n xml: string,\n sharedStrings: string[],\n dateXfs: Map<number, DateKind>,\n date1904: boolean,\n): { grid: string[][]; merges: MergeInfo[]; maxRow: number; maxCol: number } {\n const doc = parseXml(xml)\n const grid: string[][] = []\n let maxRow = 0\n let maxCol = 0\n\n // 데이터 행 파싱\n const rows = getElements(doc.documentElement, \"row\")\n let prevRow = -1 // 직전 행 번호 — r 부재 행의 순차 유도용 (ECMA-376: r은 optional)\n for (const rowEl of rows) {\n const rAttr = rowEl.getAttribute(\"r\")\n const rowNum = rAttr !== null ? parseInt(rAttr, 10) - 1 : prevRow + 1\n if (rowNum < 0 || rowNum >= MAX_ROWS) continue\n if (Number.isFinite(rowNum)) prevRow = rowNum\n\n const cells = getElements(rowEl, \"c\")\n let prevCol = -1 // 직전 셀 열 — r 부재 셀의 순차 유도용\n for (const cellEl of cells) {\n const ref = cellEl.getAttribute(\"r\")\n const pos = ref !== null ? parseCellRef(ref) : { col: prevCol + 1, row: rowNum }\n // row도 col처럼 상한 검증 — \"A5000000000\" 하나로 그리드 폭주 방지\n if (!pos || !Number.isFinite(pos.row) || pos.row < 0 || pos.row >= MAX_ROWS || pos.col >= MAX_COLS) continue\n prevCol = pos.col\n\n // 값 추출\n const type = cellEl.getAttribute(\"t\")\n const vElements = getElements(cellEl, \"v\")\n const fElements = getElements(cellEl, \"f\")\n let value = \"\"\n\n if (vElements.length > 0) {\n const raw = getTextContent(vElements[0])\n if (type === \"s\") {\n // shared string\n const idx = parseInt(raw, 10)\n value = sharedStrings[idx] ?? \"\"\n } else if (type === \"b\") {\n value = raw === \"1\" ? \"TRUE\" : \"FALSE\"\n } else {\n // 숫자값 부동소수점 아티팩트 정리 (9895607.8000000007 → 9895607.8)\n value = cleanNumericValue(raw)\n // 날짜 서식 셀(s → cellXfs 날짜 판정)은 시리얼 → ISO 문자열\n if (type === null || type === \"n\") {\n const sAttr = cellEl.getAttribute(\"s\")\n const kind = sAttr !== null ? dateXfs.get(parseInt(sAttr, 10)) : undefined\n if (kind) {\n const iso = dateSerialToIso(parseFloat(raw), date1904, kind)\n if (iso) value = iso\n }\n }\n }\n } else if (type === \"inlineStr\") {\n // <is><t>text</t></is>\n const isEl = getElements(cellEl, \"is\")\n if (isEl.length > 0) {\n value = collectRichText(isEl[0])\n }\n }\n\n // 수식이 있고 값이 없으면 수식 표시\n if (!value && fElements.length > 0) {\n value = `=${getTextContent(fElements[0])}`\n }\n\n // 그리드 확장\n while (grid.length <= pos.row) grid.push([])\n while (grid[pos.row].length <= pos.col) grid[pos.row].push(\"\")\n grid[pos.row][pos.col] = value\n\n if (pos.row > maxRow) maxRow = pos.row\n if (pos.col > maxCol) maxCol = pos.col\n }\n }\n\n // 병합 셀 파싱\n const merges: MergeInfo[] = []\n const mergeCellElements = getElements(doc.documentElement, \"mergeCell\")\n for (const el of mergeCellElements) {\n const ref = el.getAttribute(\"ref\")\n if (!ref) continue\n const m = parseMergeRef(ref)\n // 범위 클램프 — 거대 mergeCell 하나로 병합 맵 폭주 방지 (XLS 쪽과 동일)\n if (m) {\n merges.push({\n startCol: Math.min(m.startCol, MAX_COLS - 1),\n startRow: Math.min(m.startRow, MAX_ROWS - 1),\n endCol: Math.min(m.endCol, MAX_COLS - 1),\n endRow: Math.min(m.endRow, MAX_ROWS - 1),\n })\n }\n }\n\n return { grid, merges, maxRow, maxCol }\n}\n\n// ─── 시트 → IRBlock[] 변환 ────────────────────────────\n\nfunction sheetToBlocks(\n sheetName: string,\n grid: string[][],\n merges: MergeInfo[],\n maxRow: number,\n maxCol: number,\n sheetIndex: number,\n keepAnchoredEmptyCols?: boolean,\n): IRBlock[] {\n const blocks: IRBlock[] = []\n\n // 시트명 = heading\n if (sheetName) {\n blocks.push({\n type: \"heading\",\n text: sheetName,\n level: 2,\n pageNumber: sheetIndex + 1,\n })\n }\n\n // 빈 시트\n if (maxRow < 0 || maxCol < 0 || grid.length === 0) return blocks\n\n // 병합 맵: \"row,col\" → { colSpan, rowSpan }\n const mergeMap = new Map<string, { colSpan: number; rowSpan: number }>()\n const mergeSkip = new Set<string>()\n for (const m of merges) {\n const colSpan = m.endCol - m.startCol + 1\n const rowSpan = m.endRow - m.startRow + 1\n mergeMap.set(`${m.startRow},${m.startCol}`, { colSpan, rowSpan })\n for (let r = m.startRow; r <= m.endRow; r++) {\n for (let c = m.startCol; c <= m.endCol; c++) {\n if (r !== m.startRow || c !== m.startCol) {\n mergeSkip.add(`${r},${c}`)\n }\n }\n }\n }\n\n // 유효 행 범위 감지 (앞뒤 빈 행 제거)\n let firstRow = -1\n let lastRow = -1\n for (let r = 0; r <= maxRow; r++) {\n const row = grid[r]\n if (row && row.some(cell => cell !== \"\")) {\n if (firstRow === -1) firstRow = r\n lastRow = r\n }\n }\n if (firstRow === -1) return blocks\n\n // CellContext[][] → buildTable로 IRTable 생성 (2-pass 알고리즘 재사용)\n const cellRows: CellContext[][] = []\n\n for (let r = firstRow; r <= lastRow; r++) {\n const row: CellContext[] = []\n for (let c = 0; c <= maxCol; c++) {\n const key = `${r},${c}`\n if (mergeSkip.has(key)) continue\n\n const text = (grid[r] && grid[r][c]) ?? \"\"\n const merge = mergeMap.get(key)\n row.push({\n text,\n colSpan: merge?.colSpan ?? 1,\n rowSpan: merge?.rowSpan ?? 1,\n })\n }\n cellRows.push(row)\n }\n\n if (cellRows.length > 0) {\n const table = buildTable(cellRows, { keepAnchoredEmptyCols })\n if (table.rows > 0) {\n blocks.push({ type: \"table\", table, pageNumber: sheetIndex + 1 })\n }\n }\n\n return blocks\n}\n\n// ─── 메인 파서 ─────────────────────────────────────────\n\nexport async function parseXlsxDocument(\n buffer: ArrayBuffer,\n options?: ParseOptions,\n): Promise<InternalParseResult> {\n // ZIP bomb 사전 검사\n precheckZipSize(buffer, MAX_DECOMPRESS_SIZE)\n\n const zip = await JSZip.loadAsync(buffer)\n const warnings: ParseWarning[] = []\n\n // XLSX 구조 검증\n const workbookFile = zip.file(\"xl/workbook.xml\")\n if (!workbookFile) {\n throw new KordocError(\"유효하지 않은 XLSX 파일: xl/workbook.xml이 없습니다\")\n }\n\n // 1. 공유 문자열 로드\n let sharedStrings: string[] = []\n const ssFile = zip.file(\"xl/sharedStrings.xml\")\n if (ssFile) {\n sharedStrings = parseSharedStrings(await ssFile.async(\"text\"))\n }\n\n // 2. 시트 목록 로드\n const { sheets, date1904 } = parseWorkbook(await workbookFile.async(\"text\"))\n if (sheets.length === 0) {\n throw new KordocError(\"XLSX 파일에 시트가 없습니다\")\n }\n\n // 2.5 스타일 로드 — 날짜 서식 xf 판정 (실패 시 날짜 변환만 생략)\n let dateXfs = new Map<number, DateKind>()\n const stylesFile = zip.file(\"xl/styles.xml\")\n if (stylesFile) {\n try {\n dateXfs = parseStyleDateXfs(await stylesFile.async(\"text\"))\n } catch {\n // 날짜 판정 실패해도 파싱은 계속 — 대신 날짜 셀이 시리얼 숫자로 노출됨을 경고로 남긴다\n warnings.push({\n code: \"PARTIAL_PARSE\",\n message: \"xl/styles.xml 날짜 서식 판정 실패 — 날짜 셀이 시리얼 숫자로 출력될 수 있습니다\",\n })\n }\n }\n\n // 3. 관계 매핑 (rId → 파일 경로)\n let relsMap = new Map<string, string>()\n const relsFile = zip.file(\"xl/_rels/workbook.xml.rels\")\n if (relsFile) {\n relsMap = parseRels(await relsFile.async(\"text\"))\n }\n\n // 4. 페이지 필터\n let pageFilter: Set<number> | null = null\n if (options?.pages) {\n const { parsePageRange } = await import(\"../page-range.js\")\n pageFilter = parsePageRange(options.pages, sheets.length)\n }\n\n // 5. 각 시트 파싱\n const blocks: IRBlock[] = []\n const processedSheets = Math.min(sheets.length, MAX_SHEETS)\n\n for (let i = 0; i < processedSheets; i++) {\n if (pageFilter && !pageFilter.has(i + 1)) continue\n\n const sheet = sheets[i]\n options?.onProgress?.(i + 1, processedSheets)\n\n // 시트 파일 경로 결정\n let sheetPath = relsMap.get(sheet.rId)\n if (sheetPath) {\n // 상대 경로 → 절대 경로\n if (!sheetPath.startsWith(\"xl/\") && !sheetPath.startsWith(\"/\")) {\n sheetPath = `xl/${sheetPath}`\n } else if (sheetPath.startsWith(\"/\")) {\n sheetPath = sheetPath.slice(1)\n }\n } else {\n sheetPath = `xl/worksheets/sheet${i + 1}.xml`\n }\n\n const sheetFile = zip.file(sheetPath)\n if (!sheetFile) {\n warnings.push({\n page: i + 1,\n message: `시트 \"${sheet.name}\" 파일을 찾을 수 없습니다: ${sheetPath}`,\n code: \"PARTIAL_PARSE\",\n })\n continue\n }\n\n try {\n const sheetXml = await sheetFile.async(\"text\")\n const { grid, merges, maxRow, maxCol } = parseWorksheet(sheetXml, sharedStrings, dateXfs, date1904)\n const sheetBlocks = sheetToBlocks(sheet.name, grid, merges, maxRow, maxCol, i, options?.keepTrailingEmptyCols)\n blocks.push(...sheetBlocks)\n } catch (err) {\n warnings.push({\n page: i + 1,\n message: `시트 \"${sheet.name}\" 파싱 실패: ${err instanceof Error ? err.message : \"알 수 없는 오류\"}`,\n code: \"PARTIAL_PARSE\",\n })\n }\n }\n\n // 6. 메타데이터 추출\n const metadata: DocumentMetadata = {\n pageCount: processedSheets,\n }\n const coreFile = zip.file(\"docProps/core.xml\")\n if (coreFile) {\n try {\n const coreXml = await coreFile.async(\"text\")\n const doc = parseXml(coreXml)\n const getFirst = (tag: string) => {\n const els = doc.getElementsByTagName(tag)\n return els.length > 0 ? (els[0].textContent ?? \"\").trim() : undefined\n }\n metadata.title = getFirst(\"dc:title\") || getFirst(\"dcterms:title\")\n metadata.author = getFirst(\"dc:creator\")\n metadata.description = getFirst(\"dc:description\")\n const created = getFirst(\"dcterms:created\")\n if (created) metadata.createdAt = created\n const modified = getFirst(\"dcterms:modified\")\n if (modified) metadata.modifiedAt = modified\n } catch { /* 메타데이터 실패는 무시 */ }\n }\n\n const markdown = blocksToMarkdown(blocks)\n\n return { markdown, blocks, metadata, warnings: warnings.length > 0 ? warnings : undefined }\n}\n","/**\n * BIFF8 (Excel 97-2003) 레코드 리더.\n *\n * Workbook 스트림(OLE2 → cfb-lenient로 추출)에서 4바이트 헤더(opcode u16 + length u16)\n * 기반 레코드를 순차 읽어들인다. 길이가 8224를 초과하는 데이터는 직후 CONTINUE\n * 레코드로 분할되며, 본 모듈은 호출자가 원할 때 자동 결합 옵션을 제공한다.\n *\n * 참조: docs/biff8-spec.md §2~§3, [MS-XLS] §2.4\n */\n\n// ─── Opcode 상수 ─────────────────────────────────────\n\nexport const OP_BOF = 0x0809\nexport const OP_EOF = 0x000a\nexport const OP_CONTINUE = 0x003c\n\n// Globals 서브스트림\nexport const OP_BOUNDSHEET8 = 0x0085\nexport const OP_SST = 0x00fc\nexport const OP_EXTSST = 0x00ff\nexport const OP_CODEPAGE = 0x0042\nexport const OP_DATE1904 = 0x0022\nexport const OP_FILEPASS = 0x002f\nexport const OP_FORMAT = 0x041e\nexport const OP_XF = 0x00e0\n\n// Worksheet 서브스트림 — 셀\nexport const OP_NUMBER = 0x0203\nexport const OP_RK = 0x027e\nexport const OP_MULRK = 0x00bd\nexport const OP_LABELSST = 0x00fd\nexport const OP_LABEL = 0x0204\nexport const OP_FORMULA = 0x0006\nexport const OP_STRING = 0x0207\nexport const OP_BOOLERR = 0x0205\nexport const OP_BLANK = 0x0201\nexport const OP_MULBLANK = 0x00be\nexport const OP_MERGECELLS = 0x00e5\nexport const OP_ROW = 0x0208\nexport const OP_SHRFMLA = 0x04bc\nexport const OP_ARRAY = 0x0221\n\n// BOF dt 필드 값\nexport const DT_GLOBALS = 0x0005\nexport const DT_WORKSHEET = 0x0010\nexport const DT_CHART = 0x0020\nexport const DT_MACRO = 0x0040\n\n// ─── 타입 ──────────────────────────────────────────\n\nexport interface BiffRecord {\n opcode: number\n /** 본 레코드의 데이터 (CONTINUE 결합 안 한 raw) */\n data: Buffer\n /** Workbook 스트림 내 절대 오프셋 (헤더 시작 위치) — BoundSheet8 lbPlyPos 매칭용 */\n offset: number\n}\n\n// ─── 리더 ──────────────────────────────────────────\n\n/** 비정상 파일에 의한 메모리 폭주 방지 */\nconst MAX_RECORDS = 1_000_000\n\n/**\n * Workbook 스트림 전체에서 BIFF 레코드를 순차 읽는다.\n * CONTINUE 결합은 호출자 책임 (SST 디코딩 시점에서 처리).\n */\nexport function readRecords(stream: Buffer): BiffRecord[] {\n const out: BiffRecord[] = []\n let offset = 0\n\n while (offset + 4 <= stream.length && out.length < MAX_RECORDS) {\n const recOffset = offset\n const opcode = stream.readUInt16LE(offset)\n const length = stream.readUInt16LE(offset + 2)\n offset += 4\n\n if (offset + length > stream.length) {\n // 잘린 레코드 — lenient: 부분 데이터로 끊고 종료\n const data = stream.subarray(offset, stream.length)\n out.push({ opcode, data, offset: recOffset })\n break\n }\n\n const data = stream.subarray(offset, offset + length)\n out.push({ opcode, data, offset: recOffset })\n offset += length\n }\n\n return out\n}\n\n/**\n * 특정 레코드부터 직후 연속된 CONTINUE 레코드 데이터를 결합.\n * SST처럼 8224바이트를 초과해 분할되는 레코드 처리용.\n *\n * 반환: { combined: Buffer, segments: number[] }\n * - combined: 결합된 데이터\n * - segments: 각 CONTINUE 경계의 결합 후 오프셋 (디코딩 시 flags 재해석에 사용)\n */\nexport function combineWithContinue(\n records: BiffRecord[],\n startIndex: number,\n): { combined: Buffer; segments: number[]; nextIndex: number } {\n const first = records[startIndex]\n const chunks: Buffer[] = [first.data]\n const segments: number[] = [first.data.length] // 첫 CONTINUE 경계\n let i = startIndex + 1\n let total = first.data.length\n\n while (i < records.length && records[i].opcode === OP_CONTINUE) {\n chunks.push(records[i].data)\n total += records[i].data.length\n segments.push(total)\n i++\n }\n\n return {\n combined: Buffer.concat(chunks),\n segments,\n nextIndex: i,\n }\n}\n\n// ─── BOF 헬퍼 ──────────────────────────────────────\n\nexport interface BofInfo {\n vers: number\n /** 서브스트림 타입 (DT_*) */\n dt: number\n}\n\nexport function decodeBof(data: Buffer): BofInfo | null {\n if (data.length < 4) return null\n return {\n vers: data.readUInt16LE(0),\n dt: data.readUInt16LE(2),\n }\n}\n\n// ─── RK / MulRk 디코더 ─────────────────────────────\n\n/**\n * RK 32bit 압축 숫자 디코딩.\n *\n * 비트 0 (fDiv100): 1이면 결과를 100으로 나눔\n * 비트 1 (fInt): 1이면 정수, 0이면 double\n * 비트 2~31: 30비트 값\n *\n * 정수: 30비트 부호확장.\n * double: 30비트를 double의 상위 30비트(63..34)에 배치, 하위 34비트는 0.\n */\nexport function decodeRk(rk: number): number {\n const fDiv100 = (rk & 0x01) !== 0\n const fInt = (rk & 0x02) !== 0\n const val30 = rk >> 2 // signed 31-bit shift, 그러나 30bit 부호확장 별도 처리\n\n let num: number\n if (fInt) {\n // 30bit signed → 부호확장\n num = val30 // JS의 >> 2는 산술시프트라 부호 유지됨\n } else {\n // double 복원: 30bit가 double의 상위 30bit (63..34)\n // 하위 34bit는 0. JS bitwise는 32bit이므로 BigInt 사용.\n const high32 = (rk & 0xfffffffc) >>> 0 // 상위 30bit + 하위 2bit(0)\n // double 비트 패턴: high32 << 32 | 0\n const buf = Buffer.alloc(8)\n buf.writeUInt32LE(0, 0)\n buf.writeUInt32LE(high32, 4)\n num = buf.readDoubleLE(0)\n }\n\n return fDiv100 ? num / 100 : num\n}\n\nexport interface MulRkCell {\n col: number\n ixfe: number\n value: number\n}\n\n/**\n * MulRk 레코드 디코딩.\n * data 구조: [row u16][colFirst u16][rkrec_0]...[rkrec_n][colLast u16]\n * rkrec = [ixfe u16][rk u32] = 6바이트\n *\n * 반환: { row, cells: [{col, ixfe, value}, ...] }\n */\nexport function decodeMulRk(data: Buffer): { row: number; cells: MulRkCell[] } | null {\n if (data.length < 6) return null\n const row = data.readUInt16LE(0)\n const colFirst = data.readUInt16LE(2)\n const colLast = data.readUInt16LE(data.length - 2)\n const count = colLast - colFirst + 1\n if (count <= 0) return { row, cells: [] }\n\n const cells: MulRkCell[] = []\n let off = 4\n for (let i = 0; i < count && off + 6 <= data.length - 2; i++) {\n const ixfe = data.readUInt16LE(off)\n const rk = data.readUInt32LE(off + 2)\n cells.push({ col: colFirst + i, ixfe, value: decodeRk(rk) })\n off += 6\n }\n\n return { row, cells }\n}\n\n// ─── 일반 셀 헤더 (row, col, ixfe) ────────────────\n\nexport interface CellHeader {\n row: number\n col: number\n ixfe: number\n}\n\nexport function readCellHeader(data: Buffer): CellHeader | null {\n if (data.length < 6) return null\n return {\n row: data.readUInt16LE(0),\n col: data.readUInt16LE(2),\n ixfe: data.readUInt16LE(4),\n }\n}\n","/**\n * XLS 문자열 인코딩 디코더.\n *\n * BIFF8의 문자열은 다음 인코딩 중 하나:\n * - UTF-16LE (fHighByte=1)\n * - Compressed Unicode (fHighByte=0): 1바이트/문자, 상위 바이트는 0\n * - 구형 Label 레코드: CodePage 의존 (보통 CP949 또는 CP1200)\n *\n * 한국 공문서 .xls 우선 순위: UTF-16LE → Compressed → CP949\n *\n * 참조: docs/biff8-spec.md §3.3, §5\n */\n\n/**\n * UTF-16LE 디코딩 (Buffer.toString('utf16le')는 LE 가정으로 안전).\n */\nexport function decodeUtf16Le(buf: Buffer): string {\n return buf.toString(\"utf16le\")\n}\n\n/**\n * Compressed Unicode 디코딩.\n * 1바이트당 1문자, 각 바이트가 UTF-16 코드 포인트의 하위 바이트(상위 바이트=0).\n * 즉 ISO-8859-1 (Latin-1)과 동일.\n */\nexport function decodeCompressed(buf: Buffer): string {\n // Buffer.toString('latin1') == ISO-8859-1\n return buf.toString(\"latin1\")\n}\n\n/**\n * CP949 (EUC-KR 확장) 디코딩.\n * Node.js TextDecoder가 ICU 빌드일 때만 'euc-kr' 지원.\n * 미지원 환경에서는 latin1 폴백 (한글 깨짐, 영숫자만 보존).\n */\nfunction decodeCp949(buf: Buffer): string {\n try {\n // Node 18+ ICU 빌드: 'euc-kr', 'cp949' 모두 지원\n return new TextDecoder(\"euc-kr\", { fatal: false }).decode(buf)\n } catch {\n return buf.toString(\"latin1\")\n }\n}\n\n/**\n * 코드페이지 번호로 디코딩 (CodePage 레코드 0x0042 값).\n * 1200 = UTF-16LE\n * 949 = CP949\n * 1252 = Windows-1252\n * 기타 = latin1 폴백\n */\nfunction decodeByCodePage(buf: Buffer, codePage: number): string {\n if (codePage === 1200) return decodeUtf16Le(buf)\n if (codePage === 949) return decodeCp949(buf)\n if (codePage === 1252 || codePage === 65001) {\n try {\n return new TextDecoder(codePage === 65001 ? \"utf-8\" : \"windows-1252\", {\n fatal: false,\n }).decode(buf)\n } catch {\n return buf.toString(\"latin1\")\n }\n }\n return buf.toString(\"latin1\")\n}\n","/**\n * BIFF8 Shared String Table 디코더.\n *\n * SST 레코드(0x00FC)는 데이터가 8224B를 초과하면 직후 CONTINUE(0x003C) 레코드로 분할됨.\n * 단순히 데이터를 이어붙이는 게 아니라, **각 CONTINUE 경계의 첫 바이트는 새 flags\n * 바이트로 재해석**해야 한다 (MS-XLS §2.4.265 ~ §2.4.272).\n *\n * 본 모듈은 SST + 후속 CONTINUE를 통합 버퍼로 만든 후, segments 경계를 활용해\n * XLUnicodeRichExtendedString을 순차 디코딩한다.\n *\n * 참조: docs/biff8-spec.md §3.3\n */\n\nimport { decodeCompressed, decodeUtf16Le } from \"./encoding.js\"\nimport { combineWithContinue, type BiffRecord, OP_SST } from \"./record.js\"\n\ninterface ParseStringResult {\n text: string\n consumed: number\n}\n\n/**\n * 단일 XLUnicodeRichExtendedString 디코딩.\n *\n * 구조 (가변):\n * cch u16 문자 수\n * flags u8 bit 0 fHighByte (1=UTF-16LE, 0=compressed)\n * bit 2 fExtSt\n * bit 3 fRichSt\n * [cRun u16] rich text run 수 (fRichSt=1일 때만)\n * [cbExtRst u32] 확장 데이터 길이 (fExtSt=1일 때만)\n * rgb 가변 문자 데이터 (compressed: cch바이트, uncompressed: 2*cch바이트)\n * [richRuns 4*cRun] (fRichSt=1)\n * [extRst cbExtRst] (fExtSt=1)\n *\n * **CONTINUE 경계 처리**: 본 함수는 segments 정보를 받아 문자 데이터(rgb)가 경계를\n * 가로지르면 경계 직후 1바이트(새 flags)를 스킵하고 인코딩이 바뀌면 재해석한다.\n */\nfunction parseString(\n buf: Buffer,\n offset: number,\n segments: number[],\n segCursor: { idx: number },\n): ParseStringResult | null {\n if (offset + 3 > buf.length) return null\n\n const cch = buf.readUInt16LE(offset)\n let flags = buf.readUInt8(offset + 2)\n let off = offset + 3\n\n let highByte = (flags & 0x01) !== 0\n const extSt = (flags & 0x04) !== 0\n const richSt = (flags & 0x08) !== 0\n\n let cRun = 0\n let cbExtRst = 0\n if (richSt) {\n if (off + 2 > buf.length) return null\n cRun = buf.readUInt16LE(off)\n off += 2\n }\n if (extSt) {\n if (off + 4 > buf.length) return null\n cbExtRst = buf.readUInt32LE(off)\n off += 4\n }\n\n // 문자 데이터 읽기 — CONTINUE 경계마다 새 flags 재해석\n // segments는 결합 버퍼 기준 경계 오프셋들. 첫 segment는 SST의 끝, 그 다음부터 CONTINUE 경계.\n // segCursor는 문자열 간 단조 전진 커서 — 매 문자열 선형 스캔(O(n×m)) 방지.\n const charBytes: Buffer[] = []\n let charsRead = 0\n\n while (charsRead < cch) {\n // 지나온 경계 스킵 (off는 단조 증가)\n while (segCursor.idx < segments.length && segments[segCursor.idx] < off) segCursor.idx++\n // rgb가 CONTINUE 경계 정각에서 시작하면 첫 바이트는 새 flags — 선소비\n // (미소비 시 flags가 문자로 흡수돼 이후 전체 문자열 인덱스가 밀림)\n if (segCursor.idx < segments.length && segments[segCursor.idx] === off) {\n if (off >= buf.length) return null\n flags = buf.readUInt8(off)\n highByte = (flags & 0x01) !== 0\n off += 1\n segCursor.idx++\n }\n const nextBoundary = segCursor.idx < segments.length ? segments[segCursor.idx] : buf.length\n\n const remainChars = cch - charsRead\n const bytesPerChar = highByte ? 2 : 1\n const bytesAvail = nextBoundary - off\n const charsInThisRun = Math.min(remainChars, Math.floor(bytesAvail / bytesPerChar))\n const bytesToRead = charsInThisRun * bytesPerChar\n\n if (bytesToRead > 0) {\n const slice = buf.subarray(off, off + bytesToRead)\n // highByte=0 (compressed) 처리: utf16le 통일을 위해 0x00 패딩 후 합칠 수도 있으나\n // 디코딩은 latin1로 따로 처리 후 string concat이 명확.\n charBytes.push(highByte ? slice : padToUtf16(slice))\n off += bytesToRead\n charsRead += charsInThisRun\n } else if (nextBoundary < buf.length) {\n // 경계 직전 잔여 바이트(기형 파일) — 경계로 건너뛰어 진행 보장\n off = nextBoundary\n } else {\n // 더 읽을 데이터가 없음 — 무한 루프 방지\n return null\n }\n }\n\n // 모든 charBytes는 utf16le로 통일된 상태 → 합쳐서 디코딩\n const text = decodeUtf16Le(Buffer.concat(charBytes))\n\n // rich runs 스킵\n if (richSt) off += 4 * cRun\n // extRst 스킵\n if (extSt) off += cbExtRst\n\n // 안전장치: 경계 넘침 방지\n if (off > buf.length) off = buf.length\n\n return { text, consumed: off - offset }\n}\n\n/** compressed (1바이트/문자) → utf16le (2바이트/문자) 패딩. */\nfunction padToUtf16(compressed: Buffer): Buffer {\n const out = Buffer.alloc(compressed.length * 2)\n for (let i = 0; i < compressed.length; i++) {\n out[i * 2] = compressed[i]\n out[i * 2 + 1] = 0\n }\n return out\n}\n\n/**\n * 레코드 배열에서 SST를 찾아 디코딩한다.\n * SST가 없으면 빈 배열 반환.\n */\nexport function decodeSST(records: BiffRecord[]): string[] {\n const sstIndex = records.findIndex(r => r.opcode === OP_SST)\n if (sstIndex < 0) return []\n\n const { combined, segments } = combineWithContinue(records, sstIndex)\n if (combined.length < 8) return []\n\n // const cstTotal = combined.readUInt32LE(0) // 참조 횟수 (사용 안 함)\n const cstUnique = combined.readUInt32LE(4)\n\n const strings: string[] = []\n let off = 8\n const segCursor = { idx: 0 } // 문자열 간 공유 단조 커서\n for (let i = 0; i < cstUnique && off < combined.length; i++) {\n const r = parseString(combined, off, segments, segCursor)\n if (!r) break\n strings.push(r.text)\n off += r.consumed\n }\n\n return strings\n}\n\n// _ unused export silencer\nvoid decodeCompressed\n","/**\n * BIFF8 Worksheet 서브스트림의 셀 레코드 → RawCell 변환.\n *\n * 처리 대상: Number, RK, MulRk, LabelSst, BoolErr, Formula(+String), Label, Blank, MulBlank, MergeCells\n * 무시: Row 메타, GUTS, Header/Footer, Window 등\n *\n * 참조: docs/biff8-spec.md §3.4, §3.5\n */\n\nimport {\n OP_NUMBER,\n OP_RK,\n OP_MULRK,\n OP_LABELSST,\n OP_LABEL,\n OP_FORMULA,\n OP_STRING,\n OP_BOOLERR,\n OP_BLANK,\n OP_MULBLANK,\n OP_MERGECELLS,\n OP_SHRFMLA,\n OP_ARRAY,\n OP_BOF,\n OP_EOF,\n decodeMulRk,\n decodeRk,\n readCellHeader,\n type BiffRecord,\n} from \"./record.js\"\nimport { decodeUtf16Le } from \"./encoding.js\"\n\nexport type CellValue = string | number | boolean | null\n\nexport interface RawCell {\n row: number\n col: number\n value: CellValue\n}\n\nexport interface MergeRange {\n r1: number\n c1: number\n r2: number\n c2: number\n}\n\nexport interface RawSheet {\n /** 시트 시작 BOF의 절대 오프셋 */\n bofOffset: number\n cells: RawCell[]\n merges: MergeRange[]\n}\n\n/** BIFF8 표준 에러 코드 → 표시 문자열 */\nfunction errorCodeToText(code: number): string {\n switch (code) {\n case 0x00:\n return \"#NULL!\"\n case 0x07:\n return \"#DIV/0!\"\n case 0x0f:\n return \"#VALUE!\"\n case 0x17:\n return \"#REF!\"\n case 0x1d:\n return \"#NAME?\"\n case 0x24:\n return \"#NUM!\"\n case 0x2a:\n return \"#N/A\"\n default:\n return `#ERR${code}`\n }\n}\n\n/**\n * BIFF8 Label 레코드의 단순 문자열 디코딩.\n * 구조: row(2) col(2) ixfe(2) cch(2) flags(1) rgb(...)\n * - flags bit 0: 1=UTF-16LE, 0=compressed\n */\nfunction decodeLabelString(data: Buffer): string {\n if (data.length < 9) return \"\"\n const cch = data.readUInt16LE(6)\n const flags = data.readUInt8(8)\n const highByte = (flags & 0x01) !== 0\n const start = 9\n\n if (highByte) {\n const end = Math.min(start + cch * 2, data.length)\n return decodeUtf16Le(data.subarray(start, end))\n } else {\n const end = Math.min(start + cch, data.length)\n // compressed → utf16 패딩 후 디코딩\n const slice = data.subarray(start, end)\n const padded = Buffer.alloc(slice.length * 2)\n for (let i = 0; i < slice.length; i++) padded[i * 2] = slice[i]\n return decodeUtf16Le(padded)\n }\n}\n\n/**\n * Formula 레코드의 결과값 디코딩.\n * val 8바이트:\n * val[6..8] == 0xFFFF 이고:\n * val[0]=0x00: 결과가 문자열 → 직후 String 레코드 참조\n * val[0]=0x01: boolean → val[2] (0/1)\n * val[0]=0x02: error → val[2]\n * val[0]=0x03: empty\n * 그 외: double로 해석\n *\n * 반환:\n * - 문자열 결과 신호: { kind: 'stringRef' }\n * - 그 외: { kind: 'value', value: ... }\n */\ntype FormulaResult =\n | { kind: \"stringRef\" }\n | { kind: \"value\"; value: CellValue }\n\nfunction decodeFormulaResult(val: Buffer): FormulaResult {\n if (val.length < 8) return { kind: \"value\", value: null }\n const tail = val.readUInt16LE(6)\n if (tail === 0xffff) {\n const code = val.readUInt8(0)\n if (code === 0x00) return { kind: \"stringRef\" }\n if (code === 0x01) return { kind: \"value\", value: val.readUInt8(2) === 1 }\n if (code === 0x02) return { kind: \"value\", value: errorCodeToText(val.readUInt8(2)) }\n return { kind: \"value\", value: null } // empty\n }\n return { kind: \"value\", value: val.readDoubleLE(0) }\n}\n\n/**\n * Formula 직후의 String 레코드에서 결과 문자열 디코딩.\n * 구조: cch(2) flags(1) rgb(...)\n */\nfunction decodeFormulaStringRecord(data: Buffer): string {\n if (data.length < 3) return \"\"\n const cch = data.readUInt16LE(0)\n const flags = data.readUInt8(2)\n const highByte = (flags & 0x01) !== 0\n const start = 3\n\n if (highByte) {\n const end = Math.min(start + cch * 2, data.length)\n return decodeUtf16Le(data.subarray(start, end))\n } else {\n const end = Math.min(start + cch, data.length)\n const slice = data.subarray(start, end)\n const padded = Buffer.alloc(slice.length * 2)\n for (let i = 0; i < slice.length; i++) padded[i * 2] = slice[i]\n return decodeUtf16Le(padded)\n }\n}\n\n/**\n * 단일 Worksheet 서브스트림 (BOF~EOF) 의 셀 레코드 추출.\n * @param records 전체 레코드 배열\n * @param bofIndex 본 시트 BOF의 records 인덱스\n * @param sst 디코딩된 SST\n * @param convertNum 숫자 셀 변환 훅 (날짜 서식 xf → ISO 문자열) — 미지정 시 숫자 그대로\n * @returns RawSheet — 다음 시트로 넘어갈 수 있는 endIndex 포함\n */\nexport function extractSheetCells(\n records: BiffRecord[],\n bofIndex: number,\n sst: string[],\n convertNum?: (n: number, ixfe: number) => CellValue,\n): { sheet: RawSheet; endIndex: number } {\n const cells: RawCell[] = []\n const merges: MergeRange[] = []\n const bofOffset = records[bofIndex].offset\n\n let i = bofIndex + 1\n while (i < records.length) {\n const rec = records[i]\n if (rec.opcode === OP_EOF) {\n i++\n break\n }\n if (rec.opcode === OP_BOF) {\n // 새 서브스트림 시작 — 안전장치\n break\n }\n\n switch (rec.opcode) {\n case OP_NUMBER: {\n const h = readCellHeader(rec.data)\n if (h && rec.data.length >= 14) {\n const n = rec.data.readDoubleLE(6)\n cells.push({ row: h.row, col: h.col, value: convertNum ? convertNum(n, h.ixfe) : n })\n }\n break\n }\n case OP_RK: {\n const h = readCellHeader(rec.data)\n if (h && rec.data.length >= 10) {\n const n = decodeRk(rec.data.readInt32LE(6))\n cells.push({ row: h.row, col: h.col, value: convertNum ? convertNum(n, h.ixfe) : n })\n }\n break\n }\n case OP_MULRK: {\n const m = decodeMulRk(rec.data)\n if (m) {\n for (const c of m.cells) {\n cells.push({ row: m.row, col: c.col, value: convertNum ? convertNum(c.value, c.ixfe) : c.value })\n }\n }\n break\n }\n case OP_LABELSST: {\n const h = readCellHeader(rec.data)\n if (h && rec.data.length >= 10) {\n const isst = rec.data.readUInt32LE(6)\n cells.push({ row: h.row, col: h.col, value: sst[isst] ?? \"\" })\n }\n break\n }\n case OP_LABEL: {\n const h = readCellHeader(rec.data)\n if (h) {\n cells.push({ row: h.row, col: h.col, value: decodeLabelString(rec.data) })\n }\n break\n }\n case OP_FORMULA: {\n const h = readCellHeader(rec.data)\n if (h && rec.data.length >= 14) {\n const result = decodeFormulaResult(rec.data.subarray(6, 14))\n if (result.kind === \"stringRef\") {\n // 직후 String 레코드 찾기 — 공유수식 첫 셀은 ShrFmla/Array가 개재하므로 skip 탐색\n let j = i + 1\n while (j < records.length && (records[j].opcode === OP_SHRFMLA || records[j].opcode === OP_ARRAY)) j++\n const next = records[j]\n if (next && next.opcode === OP_STRING) {\n cells.push({\n row: h.row,\n col: h.col,\n value: decodeFormulaStringRecord(next.data),\n })\n i = j // String 레코드까지 건너뛰기\n } else {\n cells.push({ row: h.row, col: h.col, value: \"\" })\n }\n } else {\n const v = result.value\n cells.push({\n row: h.row,\n col: h.col,\n value: convertNum && typeof v === \"number\" ? convertNum(v, h.ixfe) : v,\n })\n }\n }\n break\n }\n case OP_BOOLERR: {\n const h = readCellHeader(rec.data)\n if (h && rec.data.length >= 8) {\n const v = rec.data.readUInt8(6)\n const isErr = rec.data.readUInt8(7) === 1\n if (isErr) {\n cells.push({ row: h.row, col: h.col, value: errorCodeToText(v) })\n } else {\n cells.push({ row: h.row, col: h.col, value: v === 1 })\n }\n }\n break\n }\n case OP_BLANK:\n case OP_MULBLANK: {\n // 빈 셀은 결과 그리드에서 자연 처리됨 — 명시적 추가 안 함\n break\n }\n case OP_MERGECELLS: {\n // [cmcs u16][Ref8U[cmcs] (각 8바이트: rwFirst rwLast colFirst colLast)]\n if (rec.data.length >= 2) {\n const cmcs = rec.data.readUInt16LE(0)\n let off = 2\n for (let k = 0; k < cmcs && off + 8 <= rec.data.length; k++) {\n const r1 = rec.data.readUInt16LE(off)\n const r2 = rec.data.readUInt16LE(off + 2)\n const c1 = rec.data.readUInt16LE(off + 4)\n const c2 = rec.data.readUInt16LE(off + 6)\n merges.push({ r1, c1, r2, c2 })\n off += 8\n }\n }\n break\n }\n default:\n // 무시 (Row, Window, GUTS, etc)\n break\n }\n\n i++\n }\n\n return {\n sheet: { bofOffset, cells, merges },\n endIndex: i,\n }\n}\n","/**\n * XLS (BIFF8) 파서 — Workbook 스트림 → IRBlock[].\n *\n * 흐름:\n * 1. cfb-lenient로 OLE2 컨테이너 → \"Workbook\" 스트림 추출\n * 2. readRecords로 BIFF 레코드 시퀀스 파싱\n * 3. Globals 서브스트림: BoundSheet8 수집 + SST 디코딩\n * 4. 각 시트 BOF 인덱스 찾기 → extractSheetCells\n * 5. RawSheet → heading + IRTable 블록 변환\n *\n * 참조: docs/biff8-spec.md\n */\n\nimport type {\n IRBlock,\n CellContext,\n DocumentMetadata,\n InternalParseResult,\n ParseOptions,\n ParseWarning,\n} from \"../types.js\"\nimport { KordocError } from \"../utils.js\"\nimport { buildTable, blocksToMarkdown } from \"../table/builder.js\"\nimport { parseLenientCfb } from \"../hwp5/cfb-lenient.js\"\nimport {\n readRecords,\n decodeBof,\n OP_BOF,\n OP_EOF,\n OP_BOUNDSHEET8,\n OP_FILEPASS,\n OP_CODEPAGE,\n OP_DATE1904,\n OP_FORMAT,\n OP_XF,\n DT_GLOBALS,\n DT_WORKSHEET,\n type BiffRecord,\n} from \"./record.js\"\nimport { decodeSST } from \"./sst.js\"\nimport { extractSheetCells, type RawSheet, type CellValue } from \"./cell.js\"\nimport { decodeUtf16Le } from \"./encoding.js\"\nimport { dateKindOfFmt, dateSerialToIso, type DateKind } from \"../xlsx/parser.js\"\n\n// ─── 상수 ─────────────────────────────────────────\n\nconst MAX_SHEETS = 100\n/** BIFF8 실제 최대 행 수 (u16 주소 공간) — 밀집 그리드 상한 */\nconst MAX_ROWS = 65536\nconst MAX_COLS = 1_000\n\n// ─── BoundSheet8 ─────────────────────────────────\n\ninterface BoundSheet {\n name: string\n /** Workbook 스트림 절대 오프셋 — 본 시트 BOF 위치 */\n lbPlyPos: number\n /** 0=Worksheet, 1=Chart, 2=Macro */\n dt: number\n}\n\n/**\n * BoundSheet8 레코드 디코딩.\n * 구조: lbPlyPos(4) hsState(1) dt(1) stName(ShortXLUnicodeString)\n * ShortXLUnicodeString: cch(1) flags(1) chars(...)\n * flags bit 0: 1=UTF-16LE, 0=compressed\n */\nfunction decodeBoundSheet(data: Buffer): BoundSheet | null {\n if (data.length < 8) return null\n const lbPlyPos = data.readUInt32LE(0)\n const dt = data.readUInt8(5)\n const cch = data.readUInt8(6)\n const flags = data.readUInt8(7)\n const highByte = (flags & 0x01) !== 0\n const start = 8\n\n let name: string\n if (highByte) {\n const end = Math.min(start + cch * 2, data.length)\n name = decodeUtf16Le(data.subarray(start, end))\n } else {\n const end = Math.min(start + cch, data.length)\n const slice = data.subarray(start, end)\n const padded = Buffer.alloc(slice.length * 2)\n for (let i = 0; i < slice.length; i++) padded[i * 2] = slice[i]\n name = decodeUtf16Le(padded)\n }\n\n return { name, lbPlyPos, dt }\n}\n\n// ─── Globals 처리 ────────────────────────────────\n\ninterface GlobalsResult {\n sheets: BoundSheet[]\n sst: string[]\n codePage: number\n encrypted: boolean\n /** XF 인덱스(ixfe) → 날짜 서식 종류 (날짜 아닌 xf는 미포함) */\n dateXfs: Map<number, DateKind>\n /** DATE1904 레코드 — 1904 날짜 체계 */\n date1904: boolean\n /** Globals 서브스트림이 끝난 records 인덱스 */\n endIndex: number\n}\n\n/** Format 레코드(0x041E) 디코딩 — ifmt(2) + XLUnicodeString(cch(2) flags(1) rgb) */\nfunction decodeFormatRecord(data: Buffer): { ifmt: number; code: string } | null {\n if (data.length < 5) return null\n const ifmt = data.readUInt16LE(0)\n const cch = data.readUInt16LE(2)\n const flags = data.readUInt8(4)\n const highByte = (flags & 0x01) !== 0\n const start = 5\n\n let code: string\n if (highByte) {\n const end = Math.min(start + cch * 2, data.length)\n code = decodeUtf16Le(data.subarray(start, end))\n } else {\n const end = Math.min(start + cch, data.length)\n const slice = data.subarray(start, end)\n const padded = Buffer.alloc(slice.length * 2)\n for (let i = 0; i < slice.length; i++) padded[i * 2] = slice[i]\n code = decodeUtf16Le(padded)\n }\n return { ifmt, code }\n}\n\nfunction processGlobals(records: BiffRecord[]): GlobalsResult {\n const sheets: BoundSheet[] = []\n let codePage = 1200\n let encrypted = false\n let date1904 = false\n const customFormats = new Map<number, string>()\n const xfFmtIds: number[] = [] // XF 레코드 순서 = ixfe 인덱스\n\n // 첫 BOF는 records[0]이어야 함\n const firstBof = records[0]\n if (!firstBof || firstBof.opcode !== OP_BOF) {\n throw new KordocError(\"XLS: 첫 레코드가 BOF가 아님\")\n }\n const bof = decodeBof(firstBof.data)\n if (!bof || bof.dt !== DT_GLOBALS) {\n throw new KordocError(\"XLS: Globals 서브스트림 BOF 누락\")\n }\n\n let i = 1\n while (i < records.length) {\n const r = records[i]\n if (r.opcode === OP_EOF) {\n i++\n break\n }\n if (r.opcode === OP_BOUNDSHEET8) {\n const bs = decodeBoundSheet(r.data)\n if (bs) sheets.push(bs)\n } else if (r.opcode === OP_CODEPAGE && r.data.length >= 2) {\n codePage = r.data.readUInt16LE(0)\n } else if (r.opcode === OP_FILEPASS) {\n encrypted = true\n } else if (r.opcode === OP_DATE1904 && r.data.length >= 2) {\n date1904 = r.data.readUInt16LE(0) === 1\n } else if (r.opcode === OP_FORMAT) {\n const f = decodeFormatRecord(r.data)\n if (f) customFormats.set(f.ifmt, f.code)\n } else if (r.opcode === OP_XF && r.data.length >= 4) {\n // XF 구조: ifnt(2) ifmt(2) ... — ifmt만 필요\n xfFmtIds.push(r.data.readUInt16LE(2))\n }\n i++\n }\n\n // XF 인덱스별 날짜 서식 판정 (내장 + 커스텀 Format)\n const dateXfs = new Map<number, DateKind>()\n for (let k = 0; k < xfFmtIds.length; k++) {\n const kind = dateKindOfFmt(xfFmtIds[k], customFormats)\n if (kind) dateXfs.set(k, kind)\n }\n\n // SST는 Globals 내부 어딘가 — 전체 records 검색하되 첫 EOF 이전만\n const globalsRecords = records.slice(0, i)\n const sst = decodeSST(globalsRecords)\n\n return { sheets, sst, codePage, encrypted, dateXfs, date1904, endIndex: i }\n}\n\n// ─── 시트 BOF 인덱스 찾기 ─────────────────────────\n\nexport function findSheetBofIndex(records: BiffRecord[], lbPlyPos: number): number {\n // 정확한 매칭 우선\n const exact = records.findIndex(\n r => r.opcode === OP_BOF && r.offset === lbPlyPos,\n )\n if (exact >= 0) return exact\n\n // 못 찾으면 최근접(오프셋 ≥ lbPlyPos) BOF — 일괄 두 번째 BOF 폴백은\n // 미매칭 시트가 전부 시트1 복제로 나오던 결함 (첫 BOF는 Globals라 제외)\n let best = -1\n let bestOffset = Infinity\n for (let idx = 1; idx < records.length; idx++) {\n const r = records[idx]\n if (r.opcode !== OP_BOF) continue\n if (r.offset >= lbPlyPos && r.offset < bestOffset) {\n best = idx\n bestOffset = r.offset\n }\n }\n return best\n}\n\n// ─── RawSheet → IRBlock[] ────────────────────────\n\nfunction cellValueToText(v: CellValue): string {\n if (v === null || v === undefined) return \"\"\n if (typeof v === \"number\") {\n // 부동소수점 아티팩트 정리\n if (Number.isInteger(v)) return v.toString()\n const cleaned = parseFloat(v.toPrecision(15)).toString()\n return cleaned\n }\n if (typeof v === \"boolean\") return v ? \"TRUE\" : \"FALSE\"\n return v\n}\n\nfunction sheetToBlocks(\n sheetName: string,\n sheet: RawSheet,\n sheetIndex: number,\n keepAnchoredEmptyCols?: boolean,\n): IRBlock[] {\n const blocks: IRBlock[] = []\n\n if (sheetName) {\n blocks.push({\n type: \"heading\",\n text: sheetName,\n level: 2,\n pageNumber: sheetIndex + 1,\n })\n }\n\n if (sheet.cells.length === 0) return blocks\n\n // 그리드 크기 계산\n let maxRow = -1\n let maxCol = -1\n for (const c of sheet.cells) {\n if (c.row > maxRow) maxRow = c.row\n if (c.col > maxCol) maxCol = c.col\n }\n for (const m of sheet.merges) {\n if (m.r2 > maxRow) maxRow = m.r2\n if (m.c2 > maxCol) maxCol = m.c2\n }\n if (maxRow < 0 || maxCol < 0) return blocks\n\n // DOS 방어\n if (maxRow >= MAX_ROWS || maxCol >= MAX_COLS) {\n maxRow = Math.min(maxRow, MAX_ROWS - 1)\n maxCol = Math.min(maxCol, MAX_COLS - 1)\n }\n\n // 그리드 채우기\n const grid: string[][] = Array.from({ length: maxRow + 1 }, () =>\n Array(maxCol + 1).fill(\"\"),\n )\n for (const c of sheet.cells) {\n if (c.row > maxRow || c.col > maxCol) continue\n grid[c.row][c.col] = cellValueToText(c.value)\n }\n\n // 병합 맵\n const mergeMap = new Map<string, { colSpan: number; rowSpan: number }>()\n const mergeSkip = new Set<string>()\n for (const m of sheet.merges) {\n const r1 = Math.min(m.r1, maxRow)\n const c1 = Math.min(m.c1, maxCol)\n const r2 = Math.min(m.r2, maxRow)\n const c2 = Math.min(m.c2, maxCol)\n mergeMap.set(`${r1},${c1}`, { colSpan: c2 - c1 + 1, rowSpan: r2 - r1 + 1 })\n for (let r = r1; r <= r2; r++) {\n for (let c = c1; c <= c2; c++) {\n if (r !== r1 || c !== c1) mergeSkip.add(`${r},${c}`)\n }\n }\n }\n\n // 유효 행 트리밍\n let firstRow = -1\n let lastRow = -1\n for (let r = 0; r <= maxRow; r++) {\n if (grid[r].some(v => v !== \"\")) {\n if (firstRow === -1) firstRow = r\n lastRow = r\n }\n }\n if (firstRow === -1) return blocks\n\n // CellContext[][] 빌드\n const cellRows: CellContext[][] = []\n for (let r = firstRow; r <= lastRow; r++) {\n const row: CellContext[] = []\n for (let c = 0; c <= maxCol; c++) {\n const key = `${r},${c}`\n if (mergeSkip.has(key)) continue\n const merge = mergeMap.get(key)\n row.push({\n text: grid[r][c],\n colSpan: merge?.colSpan ?? 1,\n rowSpan: merge?.rowSpan ?? 1,\n })\n }\n cellRows.push(row)\n }\n\n if (cellRows.length > 0) {\n const table = buildTable(cellRows, { keepAnchoredEmptyCols })\n if (table.rows > 0) {\n blocks.push({ type: \"table\", table, pageNumber: sheetIndex + 1 })\n }\n }\n\n return blocks\n}\n\n// ─── 메인 ─────────────────────────────────────────\n\nexport async function parseXlsDocument(\n buffer: ArrayBuffer,\n options?: ParseOptions,\n): Promise<InternalParseResult> {\n const buf = Buffer.from(buffer)\n\n // 1. OLE2 컨테이너 → Workbook 스트림\n let cfb\n try {\n cfb = parseLenientCfb(buf)\n } catch (e) {\n throw new KordocError(\n `XLS: OLE2 시그니처 검증 실패 — ${e instanceof Error ? e.message : \"알 수 없는 오류\"}`,\n )\n }\n\n const wb = cfb.findStream(\"/Workbook\") ?? cfb.findStream(\"/Book\")\n if (!wb) {\n throw new KordocError(\"XLS: Workbook 스트림이 없음 (BIFF5 또는 비표준 파일)\")\n }\n\n // 2. BIFF 레코드 시퀀스\n const records = readRecords(wb)\n if (records.length === 0) {\n throw new KordocError(\"XLS: 시그니처 레코드가 없음 (Workbook 스트림 손상)\")\n }\n\n // 3. BIFF 버전 체크\n const firstBof = decodeBof(records[0].data)\n if (firstBof && firstBof.vers !== 0x0600) {\n throw new KordocError(\n `XLS: BIFF8(0x0600)만 지원 — 본 파일은 0x${firstBof.vers.toString(16)}`,\n )\n }\n\n // 4. Globals 처리\n const globals = processGlobals(records)\n const warnings: ParseWarning[] = []\n\n // 다른 포맷(HWP5/HWP3/HWPX)과 동일하게 throw → success:false + ENCRYPTED.\n // 종전엔 success:true + 빈 markdown 을 돌려줘 호출자가 실패를 감지 못했다.\n if (globals.encrypted) {\n throw new KordocError(\"XLS 파일이 암호화되어 있어 파싱할 수 없습니다\")\n }\n\n // 날짜 서식 셀 변환 훅 — 숫자 시리얼 → ISO 문자열\n const convertNum = globals.dateXfs.size > 0\n ? (n: number, ixfe: number): CellValue => {\n const kind = globals.dateXfs.get(ixfe)\n if (kind) {\n const iso = dateSerialToIso(n, globals.date1904, kind)\n if (iso) return iso\n }\n return n\n }\n : undefined\n\n // 5. 페이지/시트 필터\n const totalSheets = Math.min(globals.sheets.length, MAX_SHEETS)\n let pageFilter: Set<number> | null = null\n if (options?.pages) {\n const { parsePageRange } = await import(\"../page-range.js\")\n pageFilter = parsePageRange(options.pages, totalSheets)\n }\n\n // 6. 각 시트 처리\n const allBlocks: IRBlock[] = []\n for (let i = 0; i < totalSheets; i++) {\n if (pageFilter && !pageFilter.has(i + 1)) continue\n const meta = globals.sheets[i]\n // BoundSheet8.dt: 0=Worksheet, 1=Macro, 2=Chart — 워크시트만 처리\n if (meta.dt !== 0) continue\n\n options?.onProgress?.(i + 1, totalSheets)\n\n const bofIdx = findSheetBofIndex(records, meta.lbPlyPos)\n if (bofIdx < 0) {\n warnings.push({\n page: i + 1,\n message: `시트 \"${meta.name}\" BOF를 찾을 수 없음 (lbPlyPos=${meta.lbPlyPos})`,\n code: \"PARTIAL_PARSE\",\n })\n continue\n }\n\n // 시트 BOF 검증\n const sheetBof = decodeBof(records[bofIdx].data)\n if (sheetBof && sheetBof.dt !== DT_WORKSHEET) {\n // 차트/매크로 등은 스킵\n continue\n }\n\n try {\n const { sheet } = extractSheetCells(records, bofIdx, globals.sst, convertNum)\n const blocks = sheetToBlocks(meta.name, sheet, i, options?.keepTrailingEmptyCols)\n allBlocks.push(...blocks)\n } catch (e) {\n warnings.push({\n page: i + 1,\n message: `시트 \"${meta.name}\" 파싱 실패: ${e instanceof Error ? e.message : \"알 수 없는 오류\"}`,\n code: \"PARTIAL_PARSE\",\n })\n }\n }\n\n // 7. 메타데이터\n const metadata: DocumentMetadata = {\n pageCount: totalSheets,\n }\n\n return {\n markdown: blocksToMarkdown(allBlocks),\n blocks: allBlocks,\n metadata,\n warnings: warnings.length > 0 ? warnings : undefined,\n }\n}\n","/**\n * DOCX (Office Open XML Document) 파서\n *\n * ZIP + XML 구조를 jszip + xmldom으로 파싱하여 IRBlock[]로 변환.\n * w:p → paragraph/heading, w:tbl → table, w:drawing → image.\n */\n\nimport JSZip from \"jszip\"\nimport { DOMParser } from \"@xmldom/xmldom\"\nimport type {\n CellContext, IRBlock, DocumentMetadata, InternalParseResult,\n ParseOptions, ParseWarning, ExtractedImage, InlineStyle,\n} from \"../types.js\"\nimport { KordocError, precheckZipSize, stripDtd, sanitizeHref } from \"../utils.js\"\nimport { blocksToMarkdown, buildTable } from \"../table/builder.js\"\nimport { ommlElementToLatex, isDisplayMath } from \"./equation.js\"\nimport { detectImageMime } from \"../hwp5/images.js\"\n\n/** ZIP 압축 해제 누적 최대 크기 (100MB) — ZIP bomb 방지 */\nconst MAX_DECOMPRESS_SIZE = 100 * 1024 * 1024\n\n// ─── XML 헬퍼 ──────────────────────────────────────────\n\nfunction matchesLocal(el: Element, localName: string): boolean {\n return el.localName === localName || (el.tagName?.endsWith(`:${localName}`) ?? false)\n}\n\n/**\n * sdt(콘텐츠 컨트롤)를 투명하게 평탄화한 직속 자식 엘리먼트.\n * `<w:sdt>`는 `<w:sdtContent>`로 실제 내용을 감싸므로(Google Docs 익스포트가\n * 본문 거의 전체를 sdt로 래핑), sdt를 만나면 sdtContent의 자식으로 펼쳐 본다.\n * 블록 sdt(문단/표 래핑)와 인라인 sdt(run 래핑) 모두 동일하게 처리.\n */\nfunction effectiveChildElements(parent: Element | Document): Element[] {\n const result: Element[] = []\n const children = parent.childNodes\n for (let i = 0; i < children.length; i++) {\n const node = children[i]\n if (node.nodeType !== 1) continue\n const el = node as Element\n if (matchesLocal(el, \"sdt\")) {\n // sdtContent 안으로 평탄화 (중첩 sdt 대비 재귀)\n for (let j = 0; j < el.childNodes.length; j++) {\n const c = el.childNodes[j]\n if (c.nodeType === 1 && matchesLocal(c as Element, \"sdtContent\")) {\n result.push(...effectiveChildElements(c as Element))\n }\n }\n } else if (matchesLocal(el, \"ins\") || matchesLocal(el, \"smartTag\")) {\n // w:ins(변경추적 삽입)·w:smartTag도 자식 run을 그대로 노출 — 안 펼치면 run 전량 소실.\n // w:del은 삭제된 텍스트이므로 계속 제외.\n result.push(...effectiveChildElements(el))\n } else {\n result.push(el)\n }\n }\n return result\n}\n\n/** 네임스페이스 무시 + sdt 투명 처리 직속 자식 검색 — DOCX는 네임스페이스가 많음 */\nfunction getChildElements(parent: Element | Document, localName: string): Element[] {\n return effectiveChildElements(parent).filter(el => matchesLocal(el, localName))\n}\n\n/** 재귀적으로 localName 매칭 — getElementsByTagName 대안 */\nfunction findElements(parent: Element | Document, localName: string): Element[] {\n const result: Element[] = []\n const walk = (node: Element | Document) => {\n const children = node.childNodes\n for (let i = 0; i < children.length; i++) {\n const child = children[i]\n if (child.nodeType === 1) {\n const el = child as Element\n if (el.localName === localName || el.tagName?.endsWith(`:${localName}`)) {\n result.push(el)\n }\n walk(el)\n }\n }\n }\n walk(parent)\n return result\n}\n\nfunction getAttr(el: Element, localName: string): string | null {\n // w:val, r:id 등 네임스페이스 포함 속성\n const attrs = el.attributes\n for (let i = 0; i < attrs.length; i++) {\n const attr = attrs[i]\n if (attr.localName === localName || attr.name === localName) return attr.value\n }\n return null\n}\n\nfunction parseXml(text: string): Document {\n return new DOMParser().parseFromString(stripDtd(text), \"text/xml\") as unknown as Document\n}\n\n// ─── 스타일 파싱 ────────────────────────────────────────\n\ninterface StyleInfo {\n name: string\n basedOn?: string\n outlineLevel?: number\n}\n\nfunction parseStyles(xml: string): Map<string, StyleInfo> {\n const doc = parseXml(xml)\n const styles = new Map<string, StyleInfo>()\n const styleElements = findElements(doc, \"style\")\n\n for (const el of styleElements) {\n const styleId = getAttr(el, \"styleId\")\n if (!styleId) continue\n\n const nameEls = getChildElements(el, \"name\")\n const name = nameEls.length > 0 ? (getAttr(nameEls[0], \"val\") ?? \"\") : \"\"\n const basedOnEls = getChildElements(el, \"basedOn\")\n const basedOn = basedOnEls.length > 0 ? (getAttr(basedOnEls[0], \"val\") ?? undefined) : undefined\n\n // outlineLevel으로 heading 감지\n const pPrEls = getChildElements(el, \"pPr\")\n let outlineLevel: number | undefined\n if (pPrEls.length > 0) {\n const outlineEls = getChildElements(pPrEls[0], \"outlineLvl\")\n if (outlineEls.length > 0) {\n const val = getAttr(outlineEls[0], \"val\")\n if (val !== null) outlineLevel = parseInt(val, 10)\n }\n }\n\n // Heading 패턴 매칭\n if (outlineLevel === undefined) {\n const headingMatch = name.match(/^(?:heading|Heading)\\s*(\\d+)$/i)\n if (headingMatch) outlineLevel = parseInt(headingMatch[1], 10) - 1\n }\n\n styles.set(styleId, { name, basedOn, outlineLevel })\n }\n\n // basedOn 체인 해석 — Heading 기반 사용자 스타일의 outlineLevel 상속 (사이클 가드)\n for (const [styleId, info] of styles) {\n if (info.outlineLevel !== undefined) continue\n const seen = new Set<string>([styleId])\n let cur = info.basedOn\n while (cur && !seen.has(cur)) {\n seen.add(cur)\n const parent = styles.get(cur)\n if (!parent) break\n if (parent.outlineLevel !== undefined) {\n info.outlineLevel = parent.outlineLevel\n break\n }\n cur = parent.basedOn\n }\n }\n return styles\n}\n\n// ─── 번호 매기기 파싱 ──────────────────────────────────\n\ninterface NumberingInfo {\n numFmt: string // \"decimal\", \"bullet\", etc.\n level: number\n}\n\nfunction parseNumbering(xml: string): Map<string, Map<number, NumberingInfo>> {\n const doc = parseXml(xml)\n const abstractNums = new Map<string, Map<number, NumberingInfo>>()\n\n // abstractNum 파싱\n const abstractElements = findElements(doc, \"abstractNum\")\n for (const el of abstractElements) {\n const abstractNumId = getAttr(el, \"abstractNumId\")\n if (!abstractNumId) continue\n const levels = new Map<number, NumberingInfo>()\n const lvlElements = getChildElements(el, \"lvl\")\n for (const lvl of lvlElements) {\n const ilvl = parseInt(getAttr(lvl, \"ilvl\") ?? \"0\", 10)\n const numFmtEls = getChildElements(lvl, \"numFmt\")\n const numFmt = numFmtEls.length > 0 ? (getAttr(numFmtEls[0], \"val\") ?? \"bullet\") : \"bullet\"\n levels.set(ilvl, { numFmt, level: ilvl })\n }\n abstractNums.set(abstractNumId, levels)\n }\n\n // num → abstractNum 매핑\n const nums = new Map<string, Map<number, NumberingInfo>>()\n const numElements = findElements(doc, \"num\")\n for (const el of numElements) {\n const numId = getAttr(el, \"numId\")\n if (!numId) continue\n const abstractRefs = getChildElements(el, \"abstractNumId\")\n if (abstractRefs.length > 0) {\n const ref = getAttr(abstractRefs[0], \"val\")\n if (ref && abstractNums.has(ref)) {\n nums.set(numId, abstractNums.get(ref)!)\n }\n }\n }\n return nums\n}\n\n// ─── 관계 파싱 ─────────────────────────────────────────\n\nfunction parseRels(xml: string): Map<string, string> {\n const doc = parseXml(xml)\n const map = new Map<string, string>()\n const rels = findElements(doc, \"Relationship\")\n for (const rel of rels) {\n const id = getAttr(rel, \"Id\")\n const target = getAttr(rel, \"Target\")\n if (id && target) map.set(id, target)\n }\n return map\n}\n\n// ─── 각주 파싱 ─────────────────────────────────────────\n\nfunction parseFootnotes(xml: string): Map<string, string> {\n const doc = parseXml(xml)\n const notes = new Map<string, string>()\n const fnElements = findElements(doc, \"footnote\")\n for (const fn of fnElements) {\n const id = getAttr(fn, \"id\")\n if (!id || id === \"0\" || id === \"-1\") continue // 0=separator, -1=continuation\n const texts: string[] = []\n const pElements = findElements(fn, \"p\")\n for (const p of pElements) {\n const runs = findElements(p, \"r\")\n for (const r of runs) {\n const tElements = getChildElements(r, \"t\")\n for (const t of tElements) texts.push(t.textContent ?? \"\")\n }\n }\n notes.set(id, texts.join(\"\").trim())\n }\n return notes\n}\n\n// ─── OMML 수집 ────────────────────────────────────────\n\n/**\n * paragraph 내부의 최상위 OMML 엘리먼트(`<m:oMath>` / `<m:oMathPara>`) 수집.\n * `<m:oMathPara>` 안의 중첩 `<m:oMath>` 는 중복 제외.\n */\nfunction collectOmmlRoots(p: Element): Element[] {\n const out: Element[] = []\n const walk = (node: Element) => {\n const children = node.childNodes\n if (!children) return\n for (let i = 0; i < children.length; i++) {\n const child = children[i]\n if (child.nodeType !== 1) continue\n const el = child as Element\n const tag = el.localName || el.tagName?.replace(/^[^:]+:/, \"\") || \"\"\n if (tag === \"oMath\" || tag === \"oMathPara\") {\n out.push(el)\n // 내부는 재귀하지 않음 (oMathPara 안의 oMath 중복 방지)\n } else if (tag === \"txbxContent\" || tag === \"Fallback\") {\n // 텍스트박스 내용은 별도 블록으로 처리되고 mc:Fallback은 mc:Choice의 사본 —\n // 여기서 재귀하면 같은 수식이 앵커 문단 + 텍스트박스 블록으로 이중/삼중 방출\n } else {\n walk(el)\n }\n }\n }\n walk(p)\n return out\n}\n\n// ─── Run 텍스트 추출 ──────────────────────────────────\n\ninterface RunResult {\n text: string\n bold: boolean\n italic: boolean\n}\n\nfunction extractRun(r: Element): RunResult {\n // t/br/cr/tab을 문서 순서대로 수집 — br·cr은 줄바꿈, tab은 공백 (무시하면 텍스트 융합)\n let text = \"\"\n for (const el of effectiveChildElements(r)) {\n if (matchesLocal(el, \"t\")) text += el.textContent ?? \"\"\n else if (matchesLocal(el, \"br\") || matchesLocal(el, \"cr\")) text += \"\\n\"\n else if (matchesLocal(el, \"tab\")) text += \" \"\n }\n\n let bold = false\n let italic = false\n const rPrEls = getChildElements(r, \"rPr\")\n if (rPrEls.length > 0) {\n bold = getChildElements(rPrEls[0], \"b\").length > 0\n italic = getChildElements(rPrEls[0], \"i\").length > 0\n }\n\n return { text, bold, italic }\n}\n\n// ─── 인라인 하이퍼링크 ─────────────────────────────────\n\n/**\n * 필드 코드 instr 문자열에서 HYPERLINK URL 추출.\n * ` HYPERLINK \"http://...\" `, ` HYPERLINK \"http://...\" \\l \"anchor\" `,\n * ` HYPERLINK \\l \"bookmark\" ` (문서 내부 앵커) 모두 처리. HYPERLINK 필드가\n * 아니면 null.\n */\nfunction fieldUrlFromInstr(instr: string): string | null {\n if (!/HYPERLINK\\b/i.test(instr)) return null\n const urlM = instr.match(/HYPERLINK\\s+\"([^\"]*)\"/i)\n const anchorM = instr.match(/\\\\l\\s+\"([^\"]*)\"/i)\n if (urlM && urlM[1]) {\n return anchorM && anchorM[1] ? `${urlM[1]}#${anchorM[1]}` : urlM[1]\n }\n if (anchorM && anchorM[1]) return `#${anchorM[1]}`\n return null\n}\n\n/** 표시 텍스트를 안전한 href로 감싸 마크다운 인라인 링크 생성 (스킴 미허용 시 평문) */\nfunction makeLink(text: string, rawHref: string | null | undefined): string {\n if (!text) return \"\"\n if (!rawHref) return text\n const href = sanitizeHref(rawHref)\n return href ? `[${text}](${href})` : text\n}\n\ninterface InlineResult {\n text: string\n bold: boolean\n italic: boolean\n footnoteText?: string\n}\n\n/**\n * 문단의 인라인 콘텐츠를 문서 순서대로 수집.\n * - `w:hyperlink` (r:id 외부링크 / w:anchor 내부링크) → `[text](url)`\n * - 필드 코드 HYPERLINK (`w:fldChar` begin/separate/end + `w:instrText`) → `[text](url)`\n * - `w:fldSimple`(instr=\"HYPERLINK ...\") → `[text](url)`\n * - 일반 `w:r` → 텍스트(+ bold/italic/각주)\n * 하나의 문단에 링크가 여러 개 있어도 각각 보존한다(문단당 1개 href 붕괴 수정).\n */\nfunction collectInline(\n p: Element,\n footnotes: Map<string, string>,\n rels: Map<string, string>,\n): InlineResult {\n const parts: string[] = []\n let bold = false\n let italic = false\n let footnoteText: string | undefined\n\n // 필드 코드 상태 머신 (fldChar begin~separate=instr, separate~end=display)\n let fieldActive = false\n let fieldStage: \"instr\" | \"display\" = \"instr\"\n let fieldInstr = \"\"\n let fieldDisplay = \"\"\n const flushField = () => {\n if (!fieldActive) return\n if (fieldDisplay) {\n const url = fieldUrlFromInstr(fieldInstr)\n parts.push(url ? makeLink(fieldDisplay, url) : fieldDisplay)\n }\n fieldActive = false\n fieldStage = \"instr\"\n fieldInstr = \"\"\n fieldDisplay = \"\"\n }\n\n for (const el of effectiveChildElements(p)) {\n if (matchesLocal(el, \"hyperlink\")) {\n const rId = getAttr(el, \"id\")\n const anchor = getAttr(el, \"anchor\")\n const t = findElements(el, \"r\").map(r => extractRun(r).text).join(\"\")\n if (!t) continue\n let raw: string | null = null\n if (rId && rels.has(rId)) raw = rels.get(rId)!\n else if (anchor) raw = `#${anchor}`\n // 필드 표시 구간 안이면 평문으로 합류(중첩 링크 방지), 아니면 인라인 링크\n if (fieldActive && fieldStage === \"display\") fieldDisplay += t\n else parts.push(makeLink(t, raw))\n continue\n }\n\n if (matchesLocal(el, \"fldSimple\")) {\n const t = findElements(el, \"r\").map(r => extractRun(r).text).join(\"\")\n if (!t) continue\n const url = fieldUrlFromInstr(getAttr(el, \"instr\") ?? \"\")\n parts.push(url ? makeLink(t, url) : t)\n continue\n }\n\n if (matchesLocal(el, \"r\")) {\n // fldChar 경계 처리\n for (const fc of getChildElements(el, \"fldChar\")) {\n const ty = getAttr(fc, \"fldCharType\")\n if (ty === \"begin\") { flushField(); fieldActive = true; fieldStage = \"instr\" }\n else if (ty === \"separate\") { if (fieldActive) fieldStage = \"display\" }\n else if (ty === \"end\") flushField()\n }\n // instr 텍스트 누적 (필드 지시부)\n if (fieldActive && fieldStage === \"instr\") {\n for (const it of getChildElements(el, \"instrText\")) fieldInstr += it.textContent ?? \"\"\n }\n\n const rr = extractRun(el)\n if (rr.bold) bold = true\n if (rr.italic) italic = true\n\n const fnRefEls = getChildElements(el, \"footnoteReference\")\n if (fnRefEls.length > 0) {\n const fnId = getAttr(fnRefEls[0], \"id\")\n if (fnId && footnotes.has(fnId)) footnoteText = footnotes.get(fnId)\n }\n\n if (rr.text) {\n if (fieldActive && fieldStage === \"display\") fieldDisplay += rr.text\n else if (fieldActive && fieldStage === \"instr\") { /* instrText로 처리됨 — 잔여 t 무시 */ }\n else parts.push(rr.text)\n }\n continue\n }\n }\n flushField() // 닫히지 않은 필드 방어\n\n // OMML 수식 — <m:oMath> / <m:oMathPara> 를 LaTeX 로 변환해 덧붙임.\n // 인라인 수식은 `$...$`, display 는 `$$...$$`. 순서는 run 뒤로 몰리지만\n // 대부분 한 단락 내 수식/텍스트가 분리돼 있어 실용상 무해.\n for (const om of collectOmmlRoots(p)) {\n const latex = ommlElementToLatex(om)\n if (!latex) continue\n if (isDisplayMath(om)) parts.push(\" $$\" + latex + \"$$ \")\n else parts.push(\" $\" + latex + \"$ \")\n }\n\n const text = parts.join(\"\").replace(/[ \\t]{2,}/g, \" \").trim()\n return { text, bold, italic, footnoteText }\n}\n\n// ─── 단락 파싱 ─────────────────────────────────────────\n\nfunction parseParagraph(\n p: Element,\n styles: Map<string, StyleInfo>,\n numbering: Map<string, Map<number, NumberingInfo>>,\n footnotes: Map<string, string>,\n rels: Map<string, string>,\n): IRBlock | null {\n // 스타일 확인\n const pPrEls = getChildElements(p, \"pPr\")\n let styleId = \"\"\n let numId = \"\"\n let ilvl = 0\n\n if (pPrEls.length > 0) {\n const pStyleEls = getChildElements(pPrEls[0], \"pStyle\")\n if (pStyleEls.length > 0) styleId = getAttr(pStyleEls[0], \"val\") ?? \"\"\n\n const numPrEls = getChildElements(pPrEls[0], \"numPr\")\n if (numPrEls.length > 0) {\n const numIdEls = getChildElements(numPrEls[0], \"numId\")\n const ilvlEls = getChildElements(numPrEls[0], \"ilvl\")\n numId = numIdEls.length > 0 ? (getAttr(numIdEls[0], \"val\") ?? \"\") : \"\"\n ilvl = ilvlEls.length > 0 ? parseInt(getAttr(ilvlEls[0], \"val\") ?? \"0\", 10) : 0\n }\n }\n\n const { text, bold: hasBold, italic: hasItalic, footnoteText } = collectInline(p, footnotes, rels)\n if (!text) return null\n\n // Heading 판별\n const style = styles.get(styleId)\n if (style?.outlineLevel !== undefined && style.outlineLevel >= 0 && style.outlineLevel <= 5) {\n return {\n type: \"heading\",\n text,\n level: style.outlineLevel + 1,\n }\n }\n\n // 리스트 판별\n if (numId && numId !== \"0\") {\n const numDef = numbering.get(numId)\n const levelInfo = numDef?.get(ilvl)\n const listType = levelInfo?.numFmt === \"bullet\" ? \"unordered\" : \"ordered\"\n return { type: \"list\", text, listType }\n }\n\n // 일반 단락\n const block: IRBlock = { type: \"paragraph\", text }\n if (hasBold || hasItalic) {\n block.style = { bold: hasBold || undefined, italic: hasItalic || undefined }\n }\n if (footnoteText) block.footnoteText = footnoteText\n return block\n}\n\n// ─── 테이블 파싱 ────────────────────────────────────────\n\n/**\n * 문단 하위 텍스트박스(w:txbxContent) 문단 수집.\n * mc:AlternateContent는 Choice(drawing)와 Fallback(pict)이 같은 텍스트박스를\n * 이중으로 담으므로 Fallback 서브트리는 스킵한다. 한 번의 워크로 중첩\n * 텍스트박스·텍스트박스 안 표 셀 문단까지 문서 순서대로 수집한다.\n */\nfunction collectTextboxParagraphs(node: Element, inTxbx = false, out: Element[] = [], depth = 0): Element[] {\n if (depth > 40) return out\n for (const el of effectiveChildElements(node)) {\n if (matchesLocal(el, \"Fallback\")) continue\n const nowIn = inTxbx || matchesLocal(el, \"txbxContent\")\n if (nowIn && matchesLocal(el, \"p\")) out.push(el)\n collectTextboxParagraphs(el, nowIn, out, depth + 1)\n }\n return out\n}\n\ninterface RawDocxCell {\n /** 그리드 열 주소 — gridSpan 누적 합 (배열 인덱스는 span 앞에서 어긋난다) */\n col: number\n colSpan: number\n vMerge: \"restart\" | \"continue\" | null\n text: string\n}\n\nfunction parseTable(\n tbl: Element,\n styles: Map<string, StyleInfo>,\n numbering: Map<string, Map<number, NumberingInfo>>,\n footnotes: Map<string, string>,\n rels: Map<string, string>,\n keepEmptyCols?: boolean,\n): IRBlock | null {\n const trElements = getChildElements(tbl, \"tr\")\n if (trElements.length === 0) return null\n\n const rawRows: RawDocxCell[][] = []\n for (const tr of trElements) {\n const row: RawDocxCell[] = []\n // w:trPr/w:gridBefore — 행 앞에서 건너뛴 그리드 열 수. 안 읽으면 그리드가 왼쪽으로\n // 밀려 셀이 다른 열에 무음 오배치된다(병합·들여쓴 행에서 흔함).\n let col = 0\n const trPrEls = getChildElements(tr, \"trPr\")\n if (trPrEls.length > 0) {\n const gridBeforeEls = getChildElements(trPrEls[0], \"gridBefore\")\n if (gridBeforeEls.length > 0) {\n // 음수 gridBefore(기형 docx) 클램프 — colAddr=-1 로 첫 셀이 무음 탈락하던 것 방지\n col = Math.max(0, parseInt(getAttr(gridBeforeEls[0], \"val\") ?? \"0\", 10) || 0)\n }\n }\n for (const tc of getChildElements(tr, \"tc\")) {\n let colSpan = 1\n let vMerge: RawDocxCell[\"vMerge\"] = null\n const tcPrEls = getChildElements(tc, \"tcPr\")\n if (tcPrEls.length > 0) {\n const gridSpanEls = getChildElements(tcPrEls[0], \"gridSpan\")\n if (gridSpanEls.length > 0) {\n colSpan = parseInt(getAttr(gridSpanEls[0], \"val\") ?? \"1\", 10) || 1\n }\n const vMergeEls = getChildElements(tcPrEls[0], \"vMerge\")\n if (vMergeEls.length > 0) {\n // val 없는 <w:vMerge/>는 계속 셀 (OOXML 기본값)\n vMerge = getAttr(vMergeEls[0], \"val\") === \"restart\" ? \"restart\" : \"continue\"\n }\n }\n // continue 셀도 텍스트를 수집한다 — 정상 Word는 빈 문단이지만 손상·타 생성기\n // docx는 내용이 있을 수 있고, 버리면 무음 소실 (리뷰 #18)\n const text = collectCellText(tc, styles, numbering, footnotes, rels, 0).join(\"\\n\")\n row.push({ col, colSpan, vMerge, text })\n col += colSpan\n }\n rawRows.push(row)\n }\n\n // 내용 있는 continue 셀 보존: 위쪽 시작 셀이 있으면 텍스트 합류, 없으면(restart\n // 없는 고아 continue) 일반 셀로 승격해 병합 흡수에서 제외\n for (let r = 0; r < rawRows.length; r++) {\n for (const cell of rawRows[r]) {\n if (cell.vMerge !== \"continue\" || !cell.text) continue\n let start: RawDocxCell | undefined\n for (let pr = r - 1; pr >= 0 && !start; pr--) {\n start = rawRows[pr].find(pc => pc.col === cell.col && pc.vMerge !== \"continue\")\n }\n if (start) {\n start.text = start.text ? `${start.text}\\n${cell.text}` : cell.text\n cell.text = \"\"\n } else {\n cell.vMerge = null\n }\n }\n }\n\n // vMerge 계속 셀은 같은 그리드 열의 시작 셀 rowSpan으로 흡수\n const cellRows: CellContext[][] = rawRows.map((row, r) =>\n row\n .filter(cell => cell.vMerge !== \"continue\")\n .map(cell => {\n let rowSpan = 1\n if (cell.vMerge === \"restart\") {\n for (let nr = r + 1; nr < rawRows.length; nr++) {\n if (!rawRows[nr].some(nc => nc.col === cell.col && nc.vMerge === \"continue\")) break\n rowSpan++\n }\n }\n return { text: cell.text, colSpan: cell.colSpan, rowSpan, colAddr: cell.col, rowAddr: r }\n })\n )\n\n const table = buildTable(cellRows, { keepAnchoredEmptyCols: keepEmptyCols })\n if (table.rows === 0 || table.cols === 0) return null\n return { type: \"table\", table }\n}\n\n/** 셀 내용 수집 — 문단 + 셀 안 중첩 표 텍스트 평탄화 (hml과 동일 규약, 문서 순서 유지) */\nfunction collectCellText(\n tc: Element,\n styles: Map<string, StyleInfo>,\n numbering: Map<string, Map<number, NumberingInfo>>,\n footnotes: Map<string, string>,\n rels: Map<string, string>,\n depth: number,\n): string[] {\n const parts: string[] = []\n if (depth > 20) return parts\n for (const el of effectiveChildElements(tc)) {\n if (matchesLocal(el, \"p\")) {\n const block = parseParagraph(el, styles, numbering, footnotes, rels)\n if (block?.text) parts.push(block.text)\n for (const tp of collectTextboxParagraphs(el)) {\n const tb = parseParagraph(tp, styles, numbering, footnotes, rels)\n if (tb?.text) parts.push(tb.text)\n }\n } else if (matchesLocal(el, \"tbl\")) {\n for (const tr of getChildElements(el, \"tr\")) {\n for (const nestedTc of getChildElements(tr, \"tc\")) {\n parts.push(...collectCellText(nestedTc, styles, numbering, footnotes, rels, depth + 1))\n }\n }\n }\n }\n return parts\n}\n\n// ─── 이미지 추출 ────────────────────────────────────────\n\n/**\n * 문서 전체를 훑어 embed(r:id) → 저장 파일명 맵을 구성하고 바이너리를 추출.\n * 같은 이미지(동일 embedId)는 한 번만 저장하되, 본문 여러 위치에서 참조될 수 있다.\n * 실제 본문 삽입은 emitParagraphImages가 문단 위치에 맞춰 수행한다(문서 순서 보존).\n */\nasync function buildImageMap(\n zip: JSZip,\n rels: Map<string, string>,\n doc: Document,\n warnings: ParseWarning[],\n): Promise<{ imageMap: Map<string, string>; images: ExtractedImage[] }> {\n const imageMap = new Map<string, string>()\n const images: ExtractedImage[] = []\n let imgIdx = 0\n\n // a:blip(r:embed) + Fallback 밖의 v:imagedata(r:id — w:object OLE 미리보기 등).\n // mc:Fallback 안 imagedata는 Choice(drawing) blip과 같은 내용의 사본이라 제외한다.\n const imageRefs: string[] = []\n for (const blip of findElements(doc.documentElement, \"blip\")) {\n const embedId = getAttr(blip, \"embed\")\n if (embedId) imageRefs.push(embedId)\n }\n for (const imagedata of collectNonFallbackImagedata(doc.documentElement)) {\n const embedId = getAttr(imagedata, \"id\")\n if (embedId) imageRefs.push(embedId)\n }\n\n for (const embedId of imageRefs) {\n if (imageMap.has(embedId)) continue\n const target = rels.get(embedId)\n if (!target) continue\n\n const imgPath = target.startsWith(\"/\") ? target.slice(1)\n : target.startsWith(\"word/\") ? target\n : `word/${target}`\n\n const imgFile = zip.file(imgPath)\n if (!imgFile) continue\n\n try {\n const data = await imgFile.async(\"uint8array\")\n imgIdx++\n const ext = imgPath.split(\".\").pop()?.toLowerCase() ?? \"png\"\n const mimeMap: Record<string, string> = {\n png: \"image/png\", jpg: \"image/jpeg\", jpeg: \"image/jpeg\",\n gif: \"image/gif\", bmp: \"image/bmp\", wmf: \"image/wmf\", emf: \"image/emf\",\n tif: \"image/tiff\", tiff: \"image/tiff\", svg: \"image/svg+xml\",\n }\n const filename = `image_${String(imgIdx).padStart(3, \"0\")}.${ext}`\n // 미지 확장자를 image/png 로 단정하던 폴백 제거 — 매직바이트 실측 후 그래도 모르면 octet-stream (#70)\n const mimeType = mimeMap[ext] ?? detectImageMime(data) ?? \"application/octet-stream\"\n images.push({ filename, data, mimeType, source: imgPath })\n imageMap.set(embedId, filename)\n } catch (err) {\n warnings.push({\n code: \"SKIPPED_IMAGE\",\n message: `DOCX 이미지 추출 실패 (${imgPath}): ${err instanceof Error ? err.message : String(err)}`,\n })\n }\n }\n return { imageMap, images }\n}\n\n/**\n * 문단 내 이미지(a:blip, Fallback 밖 v:imagedata)를 문서 순서대로 image 블록으로 방출.\n * txbxContent(텍스트박스)는 별도 문단으로 처리되므로 하강하지 않고,\n * mc:Fallback(pict 사본)은 blip 중복을 유발하므로 건너뛴다.\n */\nfunction collectParagraphBlips(node: Element, out: Element[] = [], depth = 0): Element[] {\n if (depth > 40) return out\n for (const el of effectiveChildElements(node)) {\n if (matchesLocal(el, \"txbxContent\") || matchesLocal(el, \"Fallback\")) continue\n if (matchesLocal(el, \"blip\") || matchesLocal(el, \"imagedata\")) out.push(el)\n else collectParagraphBlips(el, out, depth + 1)\n }\n return out\n}\n\n/** 문서 전체에서 mc:Fallback 서브트리 밖의 v:imagedata 수집 (w:object OLE 미리보기 등) */\nfunction collectNonFallbackImagedata(node: Element, out: Element[] = [], depth = 0): Element[] {\n if (depth > 60) return out\n const children = node.childNodes\n for (let i = 0; i < children.length; i++) {\n if (children[i].nodeType !== 1) continue\n const el = children[i] as Element\n if (matchesLocal(el, \"Fallback\")) continue\n if (matchesLocal(el, \"imagedata\")) out.push(el)\n else collectNonFallbackImagedata(el, out, depth + 1)\n }\n return out\n}\n\nfunction emitParagraphImages(\n p: Element,\n imageMap: Map<string, string>,\n linked: Set<string>,\n out: IRBlock[],\n): void {\n for (const blip of collectParagraphBlips(p)) {\n // a:blip은 r:embed, v:imagedata는 r:id\n const embedId = getAttr(blip, \"embed\") ?? getAttr(blip, \"id\")\n if (!embedId) continue\n const filename = imageMap.get(embedId)\n if (!filename) continue\n linked.add(embedId)\n out.push({ type: \"image\", text: filename })\n }\n}\n\n// ─── 메인 파서 ─────────────────────────────────────────\n\nexport async function parseDocxDocument(\n buffer: ArrayBuffer,\n options?: ParseOptions,\n): Promise<InternalParseResult> {\n // ZIP bomb 사전 검사\n precheckZipSize(buffer, MAX_DECOMPRESS_SIZE)\n\n const zip = await JSZip.loadAsync(buffer)\n const warnings: ParseWarning[] = []\n\n // DOCX 구조 검증\n const docFile = zip.file(\"word/document.xml\")\n if (!docFile) {\n throw new KordocError(\"유효하지 않은 DOCX 파일: word/document.xml이 없습니다\")\n }\n\n // 1. 관계 로드\n let rels = new Map<string, string>()\n const relsFile = zip.file(\"word/_rels/document.xml.rels\")\n if (relsFile) {\n rels = parseRels(await relsFile.async(\"text\"))\n }\n\n // 2. 스타일 로드\n let styles = new Map<string, StyleInfo>()\n const stylesFile = zip.file(\"word/styles.xml\")\n if (stylesFile) {\n try {\n styles = parseStyles(await stylesFile.async(\"text\"))\n } catch (err) {\n warnings.push({\n code: \"PARTIAL_PARSE\",\n message: `DOCX 스타일(styles.xml) 파싱 실패 — 기본 스타일로 계속: ${err instanceof Error ? err.message : String(err)}`,\n })\n }\n }\n\n // 3. 번호 매기기 로드\n let numbering = new Map<string, Map<number, NumberingInfo>>()\n const numFile = zip.file(\"word/numbering.xml\")\n if (numFile) {\n try {\n numbering = parseNumbering(await numFile.async(\"text\"))\n } catch (err) {\n warnings.push({\n code: \"PARTIAL_PARSE\",\n message: `DOCX 번호매기기(numbering.xml) 파싱 실패 — 목록 번호 생략: ${err instanceof Error ? err.message : String(err)}`,\n })\n }\n }\n\n // 4. 각주 로드\n let footnotes = new Map<string, string>()\n const fnFile = zip.file(\"word/footnotes.xml\")\n if (fnFile) {\n try {\n footnotes = parseFootnotes(await fnFile.async(\"text\"))\n } catch (err) {\n warnings.push({\n code: \"PARTIAL_PARSE\",\n message: `DOCX 각주(footnotes.xml) 파싱 실패 — 각주 생략: ${err instanceof Error ? err.message : String(err)}`,\n })\n }\n }\n\n // 5. 본문 파싱\n const docXml = await docFile.async(\"text\")\n const doc = parseXml(docXml)\n const body = findElements(doc, \"body\")\n if (body.length === 0) {\n throw new KordocError(\"DOCX 본문(w:body)을 찾을 수 없습니다\")\n }\n\n // 6. 이미지 맵 — 본문 워크에서 문단 위치에 맞춰 인라인 방출하려면 먼저 구성\n const { imageMap, images } = await buildImageMap(zip, rels, doc, warnings)\n const linkedImages = new Set<string>()\n\n const blocks: IRBlock[] = []\n const bodyEl = body[0]\n // sdt(콘텐츠 컨트롤)로 감싼 블록 문단/표도 펼쳐서 본다\n const topLevel = effectiveChildElements(bodyEl)\n\n for (const el of topLevel) {\n const localName = el.localName ?? el.tagName?.split(\":\").pop()\n\n if (localName === \"p\") {\n const block = parseParagraph(el, styles, numbering, footnotes, rels)\n if (block) blocks.push(block)\n // 문단 내 이미지를 문서 순서대로 본문에 삽입 (저장만 되고 링크 누락되던 버그 수정)\n if (imageMap.size > 0) emitParagraphImages(el, imageMap, linkedImages, blocks)\n // 텍스트박스(도형 안 글) 문단 — 앵커 문단 뒤에 별도 블록으로\n for (const tp of collectTextboxParagraphs(el)) {\n const tb = parseParagraph(tp, styles, numbering, footnotes, rels)\n if (tb) blocks.push(tb)\n if (imageMap.size > 0) emitParagraphImages(tp, imageMap, linkedImages, blocks)\n }\n } else if (localName === \"tbl\") {\n const block = parseTable(el, styles, numbering, footnotes, rels, options?.keepTrailingEmptyCols)\n if (block) blocks.push(block)\n }\n }\n\n // 본문 워크에서 링크되지 않은 이미지(표 셀 안 등)는 문서 끝에 참조 추가 —\n // 위치는 부정확하지만 \"파일만 저장되고 본문 링크 없음\"을 방지\n for (const [embedId, filename] of imageMap) {\n if (!linkedImages.has(embedId)) blocks.push({ type: \"image\", text: filename })\n }\n\n // 7. 메타데이터\n const metadata: DocumentMetadata = {}\n const coreFile = zip.file(\"docProps/core.xml\")\n if (coreFile) {\n try {\n const coreXml = await coreFile.async(\"text\")\n const coreDoc = parseXml(coreXml)\n const getFirst = (tag: string) => {\n const els = coreDoc.getElementsByTagName(tag)\n return els.length > 0 ? (els[0].textContent ?? \"\").trim() : undefined\n }\n metadata.title = getFirst(\"dc:title\") || getFirst(\"dcterms:title\")\n metadata.author = getFirst(\"dc:creator\")\n metadata.description = getFirst(\"dc:description\")\n const created = getFirst(\"dcterms:created\")\n if (created) metadata.createdAt = created\n const modified = getFirst(\"dcterms:modified\")\n if (modified) metadata.modifiedAt = modified\n } catch (err) {\n warnings.push({\n code: \"PARTIAL_PARSE\",\n message: `DOCX 메타데이터(core.xml) 파싱 실패: ${err instanceof Error ? err.message : String(err)}`,\n })\n }\n }\n\n // 8. 아웃라인\n const outline = blocks\n .filter(b => b.type === \"heading\")\n .map(b => ({ level: b.level ?? 2, text: b.text ?? \"\" }))\n\n const markdown = blocksToMarkdown(blocks)\n\n return {\n markdown,\n blocks,\n metadata,\n outline: outline.length > 0 ? outline : undefined,\n warnings: warnings.length > 0 ? warnings : undefined,\n images: images.length > 0 ? images : undefined,\n }\n}\n","/**\n * DOCX OMML (Office Math ML) → LaTeX\n *\n * OMML 루트 엘리먼트(`<m:oMath>`, `<m:oMathPara>`) 를 재귀적으로 훑어 LaTeX\n * 문자열을 생성한다. `<m:r>/<m:t>` 텍스트, 분수/근호/첨자/행렬/괄호/함수\n * /적분 등 실무에서 가장 흔한 OMML 18종 태그를 지원.\n *\n * 레퍼런스:\n * - Microsoft OMML2MML.xsl (Office 공식 XSLT 매핑)\n * - Pandoc texmath (Text.TeXMath.Readers.OMML)\n * 매핑 테이블은 CLAUDE plan `.claude/plans/auto-update-and-math.md` 참조.\n *\n * Entry points:\n * - ommlElementToLatex(el) — 하나의 <m:oMath> 또는 <m:oMathPara> 엘리먼트를\n * LaTeX 로 변환 (delim 은 호출자가 씌움).\n * - isOmmlRoot(el) — 엘리먼트가 OMML 최상위인지 판별.\n */\n\n// XML DOM 헬퍼는 shared/xml.ts 공용 — lname/kids/firstKid/eachChild 별칭으로 사용\nimport {\n localName as lname,\n childrenByLocalName as kids,\n findChildByLocalName as firstKid,\n elementChildren as eachChild,\n} from \"../shared/xml.js\"\n\n/** <m:r> 내부 <m:t> 텍스트 집계. 특수 연산자에 백슬래시 매핑. */\nfunction runToLatex(r: Element): string {\n let out = \"\"\n for (const t of kids(r, \"t\")) out += t.textContent ?? \"\"\n return out\n}\n\n/** 함수 이름(sin/cos/log/ln/exp/tan/…) → `\\sin` 식 매핑 */\nconst FUNC_NAMES = new Set([\n \"sin\", \"cos\", \"tan\", \"cot\", \"sec\", \"csc\",\n \"sinh\", \"cosh\", \"tanh\", \"coth\",\n \"arcsin\", \"arccos\", \"arctan\",\n \"log\", \"ln\", \"lg\", \"exp\",\n \"det\", \"dim\", \"gcd\", \"inf\", \"sup\", \"lim\", \"max\", \"min\",\n \"Pr\", \"arg\",\n])\n\n/** acc/char → LaTeX accent */\nconst ACCENT_MAP: Record<string, string> = {\n \"̂\": \"\\\\hat\", // U+0302 COMBINING CIRCUMFLEX\n \"̃\": \"\\\\tilde\", // U+0303\n \"̄\": \"\\\\bar\", // U+0304\n \"̇\": \"\\\\dot\", // U+0307\n \"̈\": \"\\\\ddot\", // U+0308\n \"́\": \"\\\\acute\", // U+0301\n \"̀\": \"\\\\grave\", // U+0300\n \"̆\": \"\\\\breve\", // U+0306\n \"̌\": \"\\\\check\", // U+030C\n \"⃗\": \"\\\\vec\", // U+20D7 COMBINING RIGHT ARROW ABOVE\n \"→\": \"\\\\vec\",\n}\n\n/** n-ary 연산자 (m:nary) chr → LaTeX */\nconst NARY_MAP: Record<string, string> = {\n \"∑\": \"\\\\sum\",\n \"∏\": \"\\\\prod\",\n \"∐\": \"\\\\coprod\",\n \"∫\": \"\\\\int\",\n \"∬\": \"\\\\iint\",\n \"∭\": \"\\\\iiint\",\n \"∮\": \"\\\\oint\",\n \"∯\": \"\\\\oiint\",\n \"∰\": \"\\\\oiiint\",\n \"⋃\": \"\\\\bigcup\",\n \"⋂\": \"\\\\bigcap\",\n \"⨁\": \"\\\\bigoplus\",\n \"⨂\": \"\\\\bigotimes\",\n \"⨀\": \"\\\\bigodot\",\n}\n\n/** OOXML on/off 값 — \"0\"/\"false\"/\"off\"는 false, 그 외(속성 생략 포함)는 true */\nfunction onOffVal(v: string | null): boolean {\n return v !== \"0\" && v !== \"false\" && v !== \"off\"\n}\n\n/** 괄호 문자 → LaTeX (좌/우) */\nfunction mapDelim(ch: string, isLeft: boolean): string {\n const l: Record<string, string> = {\n \"(\": \"(\", \"[\": \"[\", \"{\": \"\\\\{\", \"⟨\": \"\\\\langle\",\n \"|\": \"|\", \"‖\": \"\\\\|\", \"⌊\": \"\\\\lfloor\", \"⌈\": \"\\\\lceil\",\n \"\": \".\",\n }\n const r: Record<string, string> = {\n \")\": \")\", \"]\": \"]\", \"}\": \"\\\\}\", \"⟩\": \"\\\\rangle\",\n \"|\": \"|\", \"‖\": \"\\\\|\", \"⌋\": \"\\\\rfloor\", \"⌉\": \"\\\\rceil\",\n \"\": \".\",\n }\n const map = isLeft ? l : r\n return map[ch] ?? ch\n}\n\n/** 첫 `{`가 마지막 `}`와 밸런스 짝인지 — `{x}^{2}` 같은 다중 그룹 오판 방지 */\nfunction isBalancedWrap(s: string): boolean {\n let depth = 0\n for (let i = 0; i < s.length; i++) {\n const ch = s[i]\n if (ch === \"{\" && s[i - 1] !== \"\\\\\") depth++\n else if (ch === \"}\" && s[i - 1] !== \"\\\\\") {\n depth--\n if (depth === 0) return i === s.length - 1\n if (depth < 0) return false\n }\n }\n return false\n}\n\n/** 내용이 단일 문자거나 단순 원자면 `{}` 없이, 아니면 감싸서 반환 */\nfunction grp(body: string): string {\n const s = body.trim()\n if (s.length === 0) return \"{}\"\n // 이미 `{...}` 로 통짜 감싸진 경우만 그대로 (첫 `{`와 마지막 `}`가 짝일 때)\n if (s.startsWith(\"{\") && s.endsWith(\"}\") && isBalancedWrap(s)) return s\n return \"{\" + s + \"}\"\n}\n\n/** 엘리먼트 리스트를 연결한 LaTeX 문자열로 변환 */\nfunction childrenToLatex(parent: Element): string {\n let out = \"\"\n for (const ch of eachChild(parent)) {\n out += nodeToLatex(ch)\n }\n return out\n}\n\n/** 노드(Element) 하나 → LaTeX */\nfunction nodeToLatex(el: Element): string {\n const tag = lname(el)\n switch (tag) {\n case \"r\": return runToLatex(el)\n\n case \"e\": // generic container (인자로 쓰임) — 자식 연결\n case \"num\":\n case \"den\":\n case \"sub\":\n case \"sup\":\n case \"deg\":\n case \"lim\":\n case \"fName\":\n return childrenToLatex(el)\n\n // 분수\n case \"f\": {\n const n = firstKid(el, \"num\")\n const d = firstKid(el, \"den\")\n const num = n ? childrenToLatex(n) : \"\"\n const den = d ? childrenToLatex(d) : \"\"\n return \"\\\\frac\" + grp(num) + grp(den)\n }\n\n // 첨자\n case \"sSup\": {\n const e = firstKid(el, \"e\")\n const sup = firstKid(el, \"sup\")\n return grp(e ? childrenToLatex(e) : \"\") + \"^\" + grp(sup ? childrenToLatex(sup) : \"\")\n }\n case \"sSub\": {\n const e = firstKid(el, \"e\")\n const sub = firstKid(el, \"sub\")\n return grp(e ? childrenToLatex(e) : \"\") + \"_\" + grp(sub ? childrenToLatex(sub) : \"\")\n }\n case \"sSubSup\": {\n const e = firstKid(el, \"e\")\n const sub = firstKid(el, \"sub\")\n const sup = firstKid(el, \"sup\")\n return grp(e ? childrenToLatex(e) : \"\") +\n \"_\" + grp(sub ? childrenToLatex(sub) : \"\") +\n \"^\" + grp(sup ? childrenToLatex(sup) : \"\")\n }\n case \"sPre\": {\n // pre-superscript/subscript\n const sub = firstKid(el, \"sub\")\n const sup = firstKid(el, \"sup\")\n const e = firstKid(el, \"e\")\n const preSub = sub ? grp(childrenToLatex(sub)) : \"{}\"\n const preSup = sup ? grp(childrenToLatex(sup)) : \"{}\"\n const body = e ? childrenToLatex(e) : \"\"\n return \"{}_\" + preSub + \"^\" + preSup + grp(body)\n }\n\n // 근호\n case \"rad\": {\n const deg = firstKid(el, \"deg\")\n const e = firstKid(el, \"e\")\n const body = e ? childrenToLatex(e) : \"\"\n // degHide 속성이 있으면 degree 생략\n const radPr = firstKid(el, \"radPr\")\n let hide = false\n if (radPr) {\n const degHide = firstKid(radPr, \"degHide\")\n if (degHide) {\n const val = degHide.getAttribute(\"m:val\") ?? degHide.getAttribute(\"val\")\n hide = val === \"1\" || val === \"on\" || val === \"true\"\n }\n }\n const degStr = (!hide && deg) ? childrenToLatex(deg).trim() : \"\"\n return degStr ? \"\\\\sqrt[\" + degStr + \"]\" + grp(body) : \"\\\\sqrt\" + grp(body)\n }\n\n // n-ary 연산자 (sum, prod, int, …)\n case \"nary\": {\n const naryPr = firstKid(el, \"naryPr\")\n let op = \"\\\\int\"\n let subHide = false\n let supHide = false\n let limLoc = \"\"\n if (naryPr) {\n const chr = firstKid(naryPr, \"chr\")\n if (chr) {\n const v = chr.getAttribute(\"m:val\") ?? chr.getAttribute(\"val\") ?? \"\"\n if (v && NARY_MAP[v]) op = NARY_MAP[v]\n else if (v) op = v\n } else {\n // chr 생략 시 기본값은 integral (OMML 스펙)\n op = \"\\\\int\"\n }\n const sh = firstKid(naryPr, \"subHide\")\n const ph = firstKid(naryPr, \"supHide\")\n if (sh) subHide = onOffVal(sh.getAttribute(\"m:val\") ?? sh.getAttribute(\"val\"))\n if (ph) supHide = onOffVal(ph.getAttribute(\"m:val\") ?? ph.getAttribute(\"val\"))\n const ll = firstKid(naryPr, \"limLoc\")\n if (ll) limLoc = ll.getAttribute(\"m:val\") ?? ll.getAttribute(\"val\") ?? \"\"\n }\n const sub = firstKid(el, \"sub\")\n const sup = firstKid(el, \"sup\")\n const e = firstKid(el, \"e\")\n const subStr = (!subHide && sub) ? childrenToLatex(sub) : \"\"\n const supStr = (!supHide && sup) ? childrenToLatex(sup) : \"\"\n const body = e ? childrenToLatex(e) : \"\"\n\n let head = op\n if (limLoc === \"undOvr\") {\n // limit 위치를 연산자 아래/위 (sum/prod 기본)\n if (subStr) head += \"_\" + grp(subStr)\n if (supStr) head += \"^\" + grp(supStr)\n } else {\n if (subStr) head += \"_\" + grp(subStr)\n if (supStr) head += \"^\" + grp(supStr)\n }\n return head + \" \" + body\n }\n\n // 괄호 (delimiter)\n case \"d\": {\n const dPr = firstKid(el, \"dPr\")\n let beg = \"(\"\n let end = \")\"\n let sep = \",\"\n if (dPr) {\n const begChr = firstKid(dPr, \"begChr\")\n const endChr = firstKid(dPr, \"endChr\")\n const sepChr = firstKid(dPr, \"sepChr\")\n if (begChr) beg = begChr.getAttribute(\"m:val\") ?? begChr.getAttribute(\"val\") ?? beg\n if (endChr) end = endChr.getAttribute(\"m:val\") ?? endChr.getAttribute(\"val\") ?? end\n if (sepChr) sep = sepChr.getAttribute(\"m:val\") ?? sepChr.getAttribute(\"val\") ?? sep\n }\n const items = kids(el, \"e\").map(childrenToLatex)\n const body = items.join(sep)\n return \"\\\\left\" + mapDelim(beg, true) + body + \"\\\\right\" + mapDelim(end, false)\n }\n\n // 행렬\n case \"m\": {\n const rows: string[] = []\n for (const mr of kids(el, \"mr\")) {\n const cells = kids(mr, \"e\").map(childrenToLatex)\n rows.push(cells.join(\" & \"))\n }\n return \"\\\\begin{matrix}\" + rows.join(\" \\\\\\\\ \") + \"\\\\end{matrix}\"\n }\n\n // 상자/박스 (acc 와 유사하지만 bar 가 아닌 box)\n case \"box\":\n return childrenToLatex(el)\n\n // 함수 적용 (sin, cos, log …)\n case \"func\": {\n const fn = firstKid(el, \"fName\")\n const e = firstKid(el, \"e\")\n const fnStr = fn ? childrenToLatex(fn).trim() : \"\"\n const body = e ? childrenToLatex(e) : \"\"\n const fnLatex = FUNC_NAMES.has(fnStr) ? \"\\\\\" + fnStr : fnStr\n return fnLatex + grp(body)\n }\n\n // 악센트 (hat/bar/vec/…)\n case \"acc\": {\n const accPr = firstKid(el, \"accPr\")\n let chr = \"\"\n if (accPr) {\n const chrEl = firstKid(accPr, \"chr\")\n if (chrEl) chr = chrEl.getAttribute(\"m:val\") ?? chrEl.getAttribute(\"val\") ?? \"\"\n }\n // default accent = U+0302 (circumflex)\n if (!chr) chr = \"̂\"\n const e = firstKid(el, \"e\")\n const body = e ? childrenToLatex(e) : \"\"\n const cmd = ACCENT_MAP[chr] ?? \"\\\\hat\"\n return cmd + grp(body)\n }\n\n // bar (위/아래 줄)\n case \"bar\": {\n const barPr = firstKid(el, \"barPr\")\n let pos = \"top\"\n if (barPr) {\n const posEl = firstKid(barPr, \"pos\")\n if (posEl) pos = posEl.getAttribute(\"m:val\") ?? posEl.getAttribute(\"val\") ?? pos\n }\n const e = firstKid(el, \"e\")\n const body = e ? childrenToLatex(e) : \"\"\n return (pos === \"bot\" ? \"\\\\underline\" : \"\\\\overline\") + grp(body)\n }\n\n // lim 위/아래\n case \"limLow\": {\n const e = firstKid(el, \"e\")\n const lim = firstKid(el, \"lim\")\n const base = e ? childrenToLatex(e).trim() : \"\"\n const below = lim ? childrenToLatex(lim) : \"\"\n // 만약 base 가 \"lim\"/\"max\"/\"min\" 이면 \\lim_{...} 식으로\n if (FUNC_NAMES.has(base)) return \"\\\\\" + base + \"_\" + grp(below)\n return base + \"_\" + grp(below)\n }\n case \"limUpp\": {\n const e = firstKid(el, \"e\")\n const lim = firstKid(el, \"lim\")\n const base = e ? childrenToLatex(e).trim() : \"\"\n const above = lim ? childrenToLatex(lim) : \"\"\n if (FUNC_NAMES.has(base)) return \"\\\\\" + base + \"^\" + grp(above)\n return base + \"^\" + grp(above)\n }\n\n // group character (over/underset 비슷)\n case \"groupChr\":\n return childrenToLatex(firstKid(el, \"e\") ?? el)\n\n // box/borderBox/phantom/eqArr/… 는 자식 본문만 유지\n case \"borderBox\":\n case \"phant\":\n case \"eqArr\":\n return childrenToLatex(el)\n\n // 최상위 컨테이너\n case \"oMath\":\n case \"oMathPara\":\n return childrenToLatex(el)\n\n // 메타 — 속성만 들어있으므로 출력 제외\n case \"rPr\":\n case \"fPr\":\n case \"sSubPr\":\n case \"sSupPr\":\n case \"sSubSupPr\":\n case \"radPr\":\n case \"naryPr\":\n case \"dPr\":\n case \"accPr\":\n case \"barPr\":\n case \"funcPr\":\n case \"mPr\":\n case \"ctrlPr\":\n return \"\"\n\n default:\n // 자식 연결로 폴백 (모르면 재귀)\n return childrenToLatex(el)\n }\n}\n\n/** 최상위 OMML 엘리먼트인지 */\nexport function isOmmlRoot(el: Element): boolean {\n const t = lname(el)\n return t === \"oMath\" || t === \"oMathPara\"\n}\n\n/**\n * OMML 엘리먼트(`<m:oMath>` 또는 `<m:oMathPara>`) 를 LaTeX 로 변환.\n * 공백은 정규화(중복 제거 + trim)만 하고 delim($/$$)은 호출자가 추가.\n */\nexport function ommlElementToLatex(el: Element): string {\n if (!isOmmlRoot(el)) return \"\"\n const raw = childrenToLatex(el)\n return raw.replace(/\\s+/g, \" \").trim()\n}\n\n/** `<m:oMathPara>` 는 display mode */\nexport function isDisplayMath(el: Element): boolean {\n return lname(el) === \"oMathPara\"\n}\n","/** HWPML 2.x 파서 — XML 기반 한컴 문서 (.hwp with XML content) */\n\nimport { DOMParser } from \"@xmldom/xmldom\"\nimport type { IRBlock, IRCell, IRTable, InternalParseResult, ParseOptions, ParseWarning, DocumentMetadata, OutlineItem } from \"../types.js\"\nimport { blocksToMarkdown, buildTable } from \"../table/builder.js\"\nimport { parsePageRange } from \"../page-range.js\"\nimport { KordocError, stripDtd } from \"../utils.js\"\nimport type { CellContext } from \"../types.js\"\nimport { MAX_XML_DEPTH, localName, findChildByLocalName as findChild, rawTextContent as textContent } from \"../shared/xml.js\"\n\nconst MAX_TABLE_ROWS = 5000\nconst MAX_TABLE_COLS = 500\nconst MAX_HWPML_BYTES = 50 * 1024 * 1024 // 50MB 상한\n\n/** ParaShape 헤딩 정보 */\ninterface ParaShapeInfo {\n headingLevel: number | null // null = 일반 단락, 1-6 = 헤딩 레벨\n}\n\n/** HWPML 문서 파싱 진입점 */\nexport function parseHwpmlDocument(buffer: ArrayBuffer, options?: ParseOptions): InternalParseResult {\n if (buffer.byteLength > MAX_HWPML_BYTES) {\n throw new KordocError(`HWPML 파일 크기 초과 (${(buffer.byteLength / 1024 / 1024).toFixed(1)}MB > 50MB)`)\n }\n const text = new TextDecoder(\"utf-8\").decode(buffer).replace(/^\\uFEFF/, \"\")\n\n // 엔티티 치환 (DOCTYPE 제거 전에 처리)\n const normalized = text.replace(/ /g, \" \")\n const xml = stripDtd(normalized)\n\n const warnings: ParseWarning[] = []\n const parser = new DOMParser({\n onError: (_level: string, msg: string) => {\n warnings.push({ message: `HWPML XML 파싱 경고: ${msg}`, code: \"MALFORMED_XML\" })\n },\n } as ConstructorParameters<typeof DOMParser>[0])\n\n const doc = parser.parseFromString(xml, \"text/xml\")\n if (!doc.documentElement) {\n return { markdown: \"\", blocks: [], warnings }\n }\n\n const root = doc.documentElement as unknown as Element\n\n // ─── 메타데이터 추출 ──────────────────────────────────\n const metadata: DocumentMetadata = {}\n const docSummary = findChild(root, \"DOCSUMMARY\")\n if (docSummary) {\n const title = findChild(docSummary, \"TITLE\")\n const author = findChild(docSummary, \"AUTHOR\")\n const date = findChild(docSummary, \"DATE\")\n if (title) metadata.title = textContent(title).trim()\n if (author) metadata.author = textContent(author).trim()\n if (date) metadata.createdAt = textContent(date).trim() || undefined\n }\n\n // ─── HEAD: ParaShape 맵 구축 ──────────────────────────\n const paraShapeMap = buildParaShapeMap(root)\n\n // ─── BODY 파싱 ────────────────────────────────────────\n const body = findChild(root, \"BODY\")\n if (!body) {\n return { markdown: \"\", blocks: [], metadata, warnings }\n }\n\n const blocks: IRBlock[] = []\n const pageFilter = options?.pages ? parsePageRange(options.pages, countSections(body)) : null\n let sectionIdx = 0\n\n const children = body.childNodes\n for (let i = 0; i < children.length; i++) {\n const el = children[i] as Element\n if (el.nodeType !== 1) continue\n if (localName(el) !== \"SECTION\") continue\n\n sectionIdx++\n if (pageFilter && !pageFilter.has(sectionIdx)) continue\n\n parseSection(el, blocks, paraShapeMap, sectionIdx, warnings, options?.keepTrailingEmptyCols ?? false)\n }\n\n // ─── 헤딩 트리(outline) 구성 ──────────────────────────\n const outline: OutlineItem[] = blocks\n .filter(b => b.type === \"heading\" && b.text)\n .map(b => ({ level: b.level ?? 1, text: b.text!, pageNumber: b.pageNumber }))\n\n const markdown = blocksToMarkdown(blocks)\n return {\n markdown,\n blocks,\n metadata: Object.keys(metadata).length > 0 ? metadata : undefined,\n outline: outline.length > 0 ? outline : undefined,\n warnings: warnings.length > 0 ? warnings : undefined,\n }\n}\n\n// ─── ParaShape 맵 ────────────────────────────────────────\n\nfunction buildParaShapeMap(root: Element): Map<string, ParaShapeInfo> {\n const map = new Map<string, ParaShapeInfo>()\n const head = findChild(root, \"HEAD\")\n if (!head) return map\n\n const mappingTable = findChild(head, \"MAPPINGTABLE\")\n if (!mappingTable) return map\n\n const paraShapeList = findChild(mappingTable, \"PARASHAPELIST\")\n if (!paraShapeList) return map\n\n const children = paraShapeList.childNodes\n for (let i = 0; i < children.length; i++) {\n const el = children[i] as Element\n if (el.nodeType !== 1 || localName(el) !== \"PARASHAPE\") continue\n const id = el.getAttribute(\"Id\") ?? \"\"\n const headingType = el.getAttribute(\"HeadingType\") ?? \"None\"\n const level = parseInt(el.getAttribute(\"Level\") ?? \"0\", 10)\n let headingLevel: number | null = null\n if (headingType === \"Outline\") {\n const safeLevel = isNaN(level) ? 0 : Math.max(0, level)\n headingLevel = Math.min(safeLevel + 1, 6) // Level 0→H1, 1→H2, ..., 5→H6\n }\n map.set(id, { headingLevel })\n }\n\n return map\n}\n\n// ─── 섹션 파싱 ───────────────────────────────────────────\n\nfunction parseSection(\n section: Element,\n blocks: IRBlock[],\n paraShapeMap: Map<string, ParaShapeInfo>,\n sectionNum: number,\n warnings: ParseWarning[],\n keep: boolean,\n): void {\n walkContent(section, blocks, paraShapeMap, sectionNum, warnings, false, keep)\n}\n\n/**\n * 콘텐츠 노드를 재귀적으로 순회하여 IRBlock 생성.\n * inHeaderFooter=true일 때 단락/표 블록 출력 억제.\n */\nfunction walkContent(\n node: Element,\n blocks: IRBlock[],\n paraShapeMap: Map<string, ParaShapeInfo>,\n sectionNum: number,\n warnings: ParseWarning[],\n inHeaderFooter: boolean,\n keep: boolean,\n depth: number = 0,\n): void {\n if (depth > MAX_XML_DEPTH) return\n const children = node.childNodes\n for (let i = 0; i < children.length; i++) {\n const el = children[i] as Element\n if (el.nodeType !== 1) continue\n const tag = localName(el)\n\n if (tag === \"HEADER\" || tag === \"FOOTER\") {\n // 머리글/바닥글 — 텍스트 콘텐츠 무시\n continue\n }\n\n if (tag === \"P\") {\n if (!inHeaderFooter) {\n parseParagraph(el, blocks, paraShapeMap, sectionNum)\n // HML의 표는 <P><TEXT>… 안에 앵커로 들어있다 — 텍스트만 뽑고 지나치면\n // 표 전체가 소실된다 (해수부 공고 코퍼스에서 recall 0.23 실측)\n walkTablesInP(el, blocks, paraShapeMap, sectionNum, warnings, keep)\n }\n continue\n }\n\n if (tag === \"TABLE\") {\n if (!inHeaderFooter) {\n parseTable(el, blocks, paraShapeMap, sectionNum, warnings, keep)\n }\n continue\n }\n\n // PARALIST, SUBLIST, SECTION 내부 등 — 재귀\n if (tag === \"PARALIST\" || tag === \"SECTION\" || tag === \"COLDEF\") {\n walkContent(el, blocks, paraShapeMap, sectionNum, warnings, inHeaderFooter, keep, depth + 1)\n continue\n }\n\n // TEXT, SECDEF 등 내부에서도 P/TABLE이 중첩될 수 있음 — 재귀\n walkContent(el, blocks, paraShapeMap, sectionNum, warnings, inHeaderFooter, keep, depth + 1)\n }\n}\n\n/**\n * P 내부의 TABLE 앵커만 수집 (문단 텍스트는 parseParagraph 소관).\n * FOOTNOTE/ENDNOTE/HEADER/FOOTER 하위는 제외 — 그 텍스트는 collectCharText가\n * 문단 텍스트로 이미 수집하므로 내부 표까지 올리면 중복·순서 왜곡.\n */\nfunction walkTablesInP(\n node: Element,\n blocks: IRBlock[],\n paraShapeMap: Map<string, ParaShapeInfo>,\n sectionNum: number,\n warnings: ParseWarning[],\n keep: boolean,\n depth: number = 0,\n): void {\n if (depth > MAX_XML_DEPTH) return\n const children = node.childNodes\n for (let i = 0; i < children.length; i++) {\n const el = children[i] as Element\n if (el.nodeType !== 1) continue\n const tag = localName(el)\n if (tag === \"TABLE\") {\n parseTable(el, blocks, paraShapeMap, sectionNum, warnings, keep)\n continue\n }\n if (tag === \"FOOTNOTE\" || tag === \"ENDNOTE\" || tag === \"HEADER\" || tag === \"FOOTER\") continue\n walkTablesInP(el, blocks, paraShapeMap, sectionNum, warnings, keep, depth + 1)\n }\n}\n\n// ─── 단락 파싱 ───────────────────────────────────────────\n\nfunction parseParagraph(\n el: Element,\n blocks: IRBlock[],\n paraShapeMap: Map<string, ParaShapeInfo>,\n sectionNum: number,\n): void {\n const paraShapeId = el.getAttribute(\"ParaShape\") ?? \"\"\n const shapeInfo = paraShapeMap.get(paraShapeId)\n\n const text = extractParagraphText(el)\n if (!text) return\n\n if (shapeInfo?.headingLevel != null) {\n blocks.push({ type: \"heading\", text, level: shapeInfo.headingLevel, pageNumber: sectionNum })\n } else {\n blocks.push({ type: \"paragraph\", text, pageNumber: sectionNum })\n }\n}\n\n/** <P> 에서 텍스트 추출 — <TEXT><CHAR> 순회 */\nfunction extractParagraphText(p: Element): string {\n const parts: string[] = []\n collectCharText(p, parts)\n return parts.join(\"\").trim()\n}\n\nfunction collectCharText(node: Element, parts: string[], depth: number = 0): void {\n if (depth > MAX_XML_DEPTH) return\n const children = node.childNodes\n for (let i = 0; i < children.length; i++) {\n const el = children[i] as Element\n if (el.nodeType !== 1) continue\n const tag = localName(el)\n\n if (tag === \"CHAR\") {\n // textContent — 자식 텍스트 노드 직접 수집\n const t = textContent(el)\n if (t) parts.push(t)\n } else if (tag === \"TABLE\" || tag === \"PICTURE\" || tag === \"SHAPEOBJECT\") {\n // 단락 내 테이블/이미지는 별도 블록으로 처리되므로 스킵\n } else if (tag === \"AUTONUM\") {\n // 자동 번호 (페이지 번호 등) 스킵\n } else {\n collectCharText(el, parts, depth + 1)\n }\n }\n}\n\n// ─── 테이블 파싱 ─────────────────────────────────────────\n\nfunction parseTable(\n el: Element,\n blocks: IRBlock[],\n _paraShapeMap: Map<string, ParaShapeInfo>,\n sectionNum: number,\n warnings: ParseWarning[],\n keep: boolean,\n): void {\n const table = buildHmlTable(el, warnings, keep, 0)\n if (!table) return\n\n // 표 캡션(SHAPEOBJECT > CAPTION) — 파서가 이제껏 버리던 도형 캡션 텍스트를\n // 별도 문단으로 보존한다. collectCharText가 SHAPEOBJECT를 통째로 스킵해\n // 표 주석(\"※ …참조\" 등)이 소실됐다. Side=Top/Left면 표 앞, 그 외는 뒤.\n const caption = extractShapeCaption(el)\n if (caption.text && caption.before) {\n blocks.push({ type: \"paragraph\", text: caption.text, pageNumber: sectionNum })\n }\n blocks.push({ type: \"table\", table, pageNumber: sectionNum })\n if (caption.text && !caption.before) {\n blocks.push({ type: \"paragraph\", text: caption.text, pageNumber: sectionNum })\n }\n}\n\n/** 셀 안 중첩표 최대 단계 — hwp5 MAX_NEST_DEPTH와 같은 취지의 표 중첩 상한 */\nconst MAX_TABLE_NEST = 8\n\n/**\n * TABLE 요소 → IRTable. 셀 안 중첩표는 hwpx table-build 방식대로 IRCell.blocks에\n * IRBlock(type:'table')로 구조 보존하고, IRCell.text에는 하위 호환용 평탄화\n * 텍스트를 그대로 남긴다 (종전 전면 평탄화의 구조 소실 해소).\n */\nfunction buildHmlTable(\n el: Element,\n warnings: ParseWarning[],\n keep: boolean,\n tableDepth: number,\n): IRTable | null {\n const cells: CellContext[] = []\n const structured: { ctx: CellContext; cellBlocks: IRBlock[] }[] = []\n const rowCount = parseInt(el.getAttribute(\"RowCount\") ?? \"0\", 10)\n const colCount = parseInt(el.getAttribute(\"ColCount\") ?? \"0\", 10)\n if (isNaN(rowCount) || isNaN(colCount) || rowCount === 0 || colCount === 0) return null\n if (rowCount > MAX_TABLE_ROWS || colCount > MAX_TABLE_COLS) {\n warnings.push({ message: `테이블 크기 초과 (${rowCount}x${colCount}) — 스킵`, code: \"TRUNCATED_TABLE\" })\n return null\n }\n\n // <ROW> → <CELL> 순회\n const children = el.childNodes\n for (let i = 0; i < children.length; i++) {\n const rowEl = children[i] as Element\n if (rowEl.nodeType !== 1 || localName(rowEl) !== \"ROW\") continue\n\n const rowCells = rowEl.childNodes\n for (let j = 0; j < rowCells.length; j++) {\n const cellEl = rowCells[j] as Element\n if (cellEl.nodeType !== 1 || localName(cellEl) !== \"CELL\") continue\n\n const colAddr = parseInt(cellEl.getAttribute(\"ColAddr\") ?? \"0\", 10) || 0\n const rowAddr = parseInt(cellEl.getAttribute(\"RowAddr\") ?? \"0\", 10) || 0\n // colSpan/rowSpan 클램핑: NaN, 음수, 과대값 방어\n const colSpan = Math.min(Math.max(1, parseInt(cellEl.getAttribute(\"ColSpan\") ?? \"1\", 10) || 1), MAX_TABLE_COLS)\n const rowSpan = Math.min(Math.max(1, parseInt(cellEl.getAttribute(\"RowSpan\") ?? \"1\", 10) || 1), MAX_TABLE_ROWS)\n\n // 셀 텍스트: PARALIST > P 재귀 추출 (blocks 유무와 무관하게 종전 평탄화 유지)\n const cellText = extractCellText(cellEl)\n const ctx: CellContext = { text: cellText, colSpan, rowSpan, colAddr, rowAddr }\n cells.push(ctx)\n\n // 중첩표가 있는 셀만 blocks 구성 — 평문 셀은 text 평탄화로 충분 (blocks 무게 억제)\n if (tableDepth < MAX_TABLE_NEST && cellHasNestedTable(cellEl, 0)) {\n const cellBlocks: IRBlock[] = []\n collectCellBlocks(cellEl, cellBlocks, warnings, keep, 0, tableDepth)\n if (cellBlocks.some(b => b.type === \"table\")) structured.push({ ctx, cellBlocks })\n }\n }\n }\n\n if (cells.length === 0) return null\n\n // 셀은 colAddr/rowAddr 절대좌표를 가지므로 buildTable direct 모드에 그대로 위임.\n // (구 구현은 주소 없는 filler를 채운 수동 그리드를 넘겼는데, direct 모드가 filler의\n // 기본 주소 (0,0)으로 첫 셀을 덮어써 병합 헤더 텍스트가 증발했다)\n const cellRows: CellContext[][] = Array.from({ length: rowCount }, () => [])\n for (const cell of cells) {\n const r = Math.min(Math.max(cell.rowAddr ?? 0, 0), rowCount - 1)\n cellRows[r].push(cell)\n }\n\n const table = buildTable(cellRows, { keepAnchoredEmptyCols: keep })\n\n // 중첩표 blocks 부착 — HML CELL은 절대좌표가 항상 있으므로 좌표 우선,\n // 좌표 셀의 텍스트가 다르면(빌더 정규화 등) 텍스트+스팬 매칭 폴백.\n // 못 찾으면 미부착 — 평탄화 텍스트가 이미 내용을 보존하므로 유실은 없다.\n if (structured.length > 0) {\n const claimed = new Set<IRCell>()\n for (const { ctx, cellBlocks } of structured) {\n let target: IRCell | undefined = table.cells[ctx.rowAddr ?? -1]?.[ctx.colAddr ?? -1]\n if (!target || claimed.has(target) || target.text !== ctx.text) {\n target = undefined\n outer: for (const irRow of table.cells) {\n for (const cand of irRow) {\n if (!claimed.has(cand) && cand.text === ctx.text && cand.colSpan === ctx.colSpan && cand.rowSpan === ctx.rowSpan) {\n target = cand\n break outer\n }\n }\n }\n }\n if (!target) continue\n claimed.add(target)\n target.blocks = cellBlocks\n }\n }\n\n return table\n}\n\n/** 셀 하위에 TABLE 존재 여부 (각주류 제외) — blocks 구성 여부 사전 판별 */\nfunction cellHasNestedTable(node: Element, depth: number): boolean {\n if (depth > 20) return false\n const children = node.childNodes\n for (let i = 0; i < children.length; i++) {\n const el = children[i] as Element\n if (el.nodeType !== 1) continue\n const tag = localName(el)\n if (tag === \"TABLE\") return true\n if (tag === \"FOOTNOTE\" || tag === \"ENDNOTE\" || tag === \"HEADER\" || tag === \"FOOTER\") continue\n if (cellHasNestedTable(el, depth + 1)) return true\n }\n return false\n}\n\n/** 셀 내부를 DOM 순서대로 IRBlock 목록으로 — 문단 텍스트 + 중첩표(구조 보존) */\nfunction collectCellBlocks(\n node: Element,\n out: IRBlock[],\n warnings: ParseWarning[],\n keep: boolean,\n depth: number,\n tableDepth: number,\n): void {\n if (depth > 20) return\n const children = node.childNodes\n for (let i = 0; i < children.length; i++) {\n const el = children[i] as Element\n if (el.nodeType !== 1) continue\n const tag = localName(el)\n\n if (tag === \"P\") {\n const t = extractParagraphText(el)\n if (t) out.push({ type: \"paragraph\", text: t })\n collectNestedTableBlocks(el, out, warnings, keep, depth + 1, tableDepth)\n } else if (tag === \"TABLE\") {\n pushNestedTableBlock(el, out, warnings, keep, tableDepth)\n } else {\n collectCellBlocks(el, out, warnings, keep, depth + 1, tableDepth)\n }\n }\n}\n\n/** P 하위의 TABLE만 찾아 구조 블록으로 — 각주류는 extractParagraphText가 이미 수집 */\nfunction collectNestedTableBlocks(\n node: Element,\n out: IRBlock[],\n warnings: ParseWarning[],\n keep: boolean,\n depth: number,\n tableDepth: number,\n): void {\n if (depth > 20) return\n const children = node.childNodes\n for (let i = 0; i < children.length; i++) {\n const el = children[i] as Element\n if (el.nodeType !== 1) continue\n const tag = localName(el)\n if (tag === \"TABLE\") {\n pushNestedTableBlock(el, out, warnings, keep, tableDepth)\n continue\n }\n if (tag === \"FOOTNOTE\" || tag === \"ENDNOTE\" || tag === \"HEADER\" || tag === \"FOOTER\") continue\n collectNestedTableBlocks(el, out, warnings, keep, depth + 1, tableDepth)\n }\n}\n\n/** 중첩 TABLE → IRBlock(type:'table'). 빌드 불가(빈 표·크기 초과)면 평탄화 텍스트 폴백 */\nfunction pushNestedTableBlock(\n el: Element,\n out: IRBlock[],\n warnings: ParseWarning[],\n keep: boolean,\n tableDepth: number,\n): void {\n const nested = buildHmlTable(el, warnings, keep, tableDepth + 1)\n if (nested) {\n const cap = extractShapeCaption(el)\n if (cap.text) nested.caption = cap.text\n out.push({ type: \"table\", table: nested })\n return\n }\n const parts: string[] = []\n collectCellText(el, parts, 0)\n const flat = parts.filter(Boolean).join(\"\\n\").trim()\n if (flat) out.push({ type: \"paragraph\", text: flat })\n}\n\n/** 표의 SHAPEOBJECT > CAPTION 텍스트 + 배치(Side) 추출 */\nfunction extractShapeCaption(tableEl: Element): { text: string; before: boolean } {\n const shape = findChild(tableEl, \"SHAPEOBJECT\")\n const caption = shape && findChild(shape, \"CAPTION\")\n if (!caption) return { text: \"\", before: false }\n const parts: string[] = []\n collectCellText(caption, parts, 0)\n const side = caption.getAttribute(\"Side\") ?? \"\"\n return { text: parts.filter(Boolean).join(\"\\n\").trim(), before: side === \"Top\" || side === \"Left\" }\n}\n\n/** 셀 내부 텍스트 추출 — PARALIST > P 재귀, 중첩 테이블은 평탄화 */\nfunction extractCellText(cellEl: Element): string {\n const textParts: string[] = []\n collectCellText(cellEl, textParts, 0)\n return textParts.filter(Boolean).join(\"\\n\").trim()\n}\n\nfunction collectCellText(node: Element, parts: string[], depth: number): void {\n if (depth > 20) return\n const children = node.childNodes\n for (let i = 0; i < children.length; i++) {\n const el = children[i] as Element\n if (el.nodeType !== 1) continue\n const tag = localName(el)\n\n if (tag === \"P\") {\n const t = extractParagraphText(el)\n if (t) parts.push(t)\n // P 안에 앵커된 중첩표 — 텍스트 평탄화 (안내 박스가 1×1 표로 흔함)\n collectNestedTableText(el, parts, depth + 1)\n } else if (tag === \"TABLE\") {\n // 중첩 테이블 — 셀 문단 텍스트로 평탄화 (구 \"[중첩 테이블]\" 마커는 내용 소실)\n collectCellText(el, parts, depth + 1)\n } else {\n collectCellText(el, parts, depth + 1)\n }\n }\n}\n\n/** P 하위의 TABLE만 찾아 텍스트 평탄화 — 각주류는 extractParagraphText가 이미 수집 */\nfunction collectNestedTableText(node: Element, parts: string[], depth: number): void {\n if (depth > 20) return\n const children = node.childNodes\n for (let i = 0; i < children.length; i++) {\n const el = children[i] as Element\n if (el.nodeType !== 1) continue\n const tag = localName(el)\n if (tag === \"TABLE\") {\n collectCellText(el, parts, depth + 1)\n continue\n }\n if (tag === \"FOOTNOTE\" || tag === \"ENDNOTE\" || tag === \"HEADER\" || tag === \"FOOTER\") continue\n collectNestedTableText(el, parts, depth + 1)\n }\n}\n\n// ─── XML 유틸 ────────────────────────────────────────────\n// localName/findChild(=findChildByLocalName)/textContent(=rawTextContent)는 shared/xml.ts 공용\n\nfunction countSections(body: Element): number {\n let count = 0\n const children = body.childNodes\n for (let i = 0; i < children.length; i++) {\n const el = children[i] as Element\n if (el.nodeType === 1 && localName(el) === \"SECTION\") count++\n }\n return count\n}\n","/** 양식 필드 매칭 공용 유틸 — filler.ts, filler-hwpx.ts에서 공유 */\n\nimport { LABEL_KEYWORDS } from \"./recognize.js\"\n\n/**\n * 채울 값 — 문자열이면 같은 라벨 모든 등장에 동일값(단일 양식),\n * 배열이면 등장 순서대로 하나씩 소진(2~30장 반복 양식·명부형 표).\n */\nexport type FillValue = string | string[]\n\n/**\n * 채울 값 입력 — 값만 주거나, 서식 변환(format)을 함께 지정한다.\n * 프로필엔 정준값 하나(생년월일 \"19900315\"), 서식마다 모양이 다를 때\n * format이 도구 안에서 변환한다 (claw-hwp secure-fill 포맷엔진 이식).\n */\nexport type FillInput = FillValue | { value: FillValue; format?: string }\n\n// ─── 값 서식 변환 (claw-hwp secure-fill formatValue 이식) ─────────────\n\nfunction parseYMD(v: string): { y: string; yy: string; m: string; d: string } | null {\n let y: string, m: string, day: string\n // 구분자(. - / 년월일 등)로 분리된 3토큰이면 미패딩 날짜(2026.7.5·2026년 7월 5일)로 우선 해석\n const parts = v.split(/[^0-9]+/).filter(Boolean)\n if (parts.length === 3) {\n const [yp, mp, dp] = parts\n const yn = +yp\n y = yp.length >= 3 ? yp : String(yn <= 29 ? 2000 + yn : 1900 + yn)\n m = mp.padStart(2, \"0\")\n day = dp.padStart(2, \"0\")\n } else {\n const d = v.replace(/\\D/g, \"\")\n if (d.length >= 8) { y = d.slice(0, 4); m = d.slice(4, 6); day = d.slice(6, 8) }\n else if (d.length === 6) { const yy = +d.slice(0, 2); y = String(yy <= 29 ? 2000 + yy : 1900 + yy); m = d.slice(2, 4); day = d.slice(4, 6) }\n else return null\n }\n // 월 1-12·일 1-31 범위 밖이면 fail-open(쓰레기 날짜 무음 기입 방지)\n if (+m < 1 || +m > 12 || +day < 1 || +day > 31) return null\n return { y, yy: y.slice(2), m, d: day }\n}\n\nfunction fmtDate(v: string, style: string): string {\n const p = parseYMD(v)\n if (!p) return v\n // 토큰 치환(대소문자 무시 — yyyy-MM-dd 혼용 수용, 긴 것 우선). 단독 m/d(선행 0\n // 제거)는 영문 리터럴(예: \"amended\")을 오염시키지 않게 영문자에 비인접일 때만 치환.\n return (style || \"yyyy-mm-dd\")\n .replace(/yyyy/gi, p.y).replace(/yy/gi, p.yy)\n .replace(/mm/gi, p.m).replace(/dd/gi, p.d)\n .replace(/(?<![a-z])m(?![a-z])/gi, String(+p.m))\n .replace(/(?<![a-z])d(?![a-z])/gi, String(+p.d))\n}\n\n/** 숫자 마스크 — `#` 하나가 값의 다음 숫자 하나를 소비, 리터럴은 통과 */\nfunction maskDigits(v: string, pattern: string): string {\n const ds = v.replace(/\\D/g, \"\")\n const need = (pattern.match(/#/g) ?? []).length\n // # 개수와 숫자 개수가 다르거나 패턴에 # 가 없으면, 그럴듯한 오값·끝자리 폐기·\n // 값 삭제 대신 원형을 반환한다 (무음 왜곡 금지 — fail-open).\n if (need === 0 || ds.length !== need) return v\n let i = 0\n return pattern.replace(/#/g, () => ds[i++])\n}\n\nfunction fmtPhone(v: string, style: string): string {\n const d = v.replace(/\\D/g, \"\")\n if (d.length < 9) return v\n // 서울(02)은 2자리 지역번호, 그 외(휴대폰 010·지역 0XX)는 3자리\n const areaLen = d.startsWith(\"02\") ? 2 : 3\n const a = d.slice(0, areaLen), b = d.slice(areaLen, -4), c = d.slice(-4)\n switch (style) {\n case \"digits\": return d\n case \"dot\": return `${a}.${b}.${c}`\n case \"space\": return `${a} ${b} ${c}`\n case \"intl\": return `+82-${d.slice(1, areaLen)}-${b}-${c}`\n case \"intl-paren\": return `82)${d.slice(1, areaLen)}-${b}-${c}`\n default: return `${a}-${b}-${c}` // hyphen\n }\n}\n\nfunction fmtRRN(v: string, style: string): string {\n const d = v.replace(/\\D/g, \"\")\n if (d.length !== 13) return v\n switch (style) {\n case \"digits\": return d\n case \"front\": return d.slice(0, 6)\n case \"masked\": return `${d.slice(0, 6)}-${d[6]}******`\n default: return `${d.slice(0, 6)}-${d.slice(6)}` // hyphen\n }\n}\n\n/**\n * 값 서식 변환 — `종류:스타일` 접두형(date:/phone:/rrn:/mask:/digits/upper/lower/nospace)\n * 또는 접두 없는 자유 패턴(`#` 포함 → 숫자마스크, yyyy·yy·mm·dd 포함 → 날짜 토큰).\n * 모르는 포맷은 값 원형 반환 (fail-open — 채움 자체는 진행).\n */\nexport function formatFillValue(value: string, format?: string): string {\n if (!format) return value\n const ci = format.indexOf(\":\")\n const kind = ci >= 0 ? format.slice(0, ci) : format\n const style = ci >= 0 ? format.slice(ci + 1) : \"\"\n if (kind === \"date\") return fmtDate(value, style)\n if (kind === \"phone\") return fmtPhone(value, style)\n if (kind === \"rrn\") return fmtRRN(value, style)\n if (kind === \"mask\") return maskDigits(value, style)\n if (kind === \"digits\") { const only = value.replace(/\\D/g, \"\"); return only || value }\n if (kind === \"upper\") return value.toUpperCase()\n if (kind === \"lower\") return value.toLowerCase()\n if (kind === \"nospace\") return value.replace(/\\s+/g, \"\")\n if (format.includes(\"#\")) return maskDigits(value, format)\n if (/(yyyy|yy|mm|dd)/.test(format)) return fmtDate(value, format)\n return value\n}\n\n/**\n * 다중값 커서 — 라벨별 값 소비 상태를 추적한다.\n * 스칼라 값은 무한 반복(기존 동작), 배열 값은 적용 순서대로 소진되며\n * 다 쓰면 available=false가 되어 이후 등장은 채우지 않는다.\n */\nexport class ValueCursor {\n private nextIdx = new Map<string, number>()\n constructor(private values: Map<string, FillValue>) {}\n\n keys(): IterableIterator<string> {\n return this.values.keys()\n }\n\n has(key: string): boolean {\n return this.values.has(key)\n }\n\n isArray(key: string): boolean {\n return Array.isArray(this.values.get(key))\n }\n\n /** 남은 값이 있으면 true (스칼라는 항상 true) */\n available(key: string): boolean {\n const v = this.values.get(key)\n if (v === undefined) return false\n return typeof v === \"string\" || (this.nextIdx.get(key) ?? 0) < v.length\n }\n\n /** 현재 값 미리보기 (소진 없음) */\n peek(key: string): string | undefined {\n const v = this.values.get(key)\n if (v === undefined) return undefined\n if (typeof v === \"string\") return v\n const i = this.nextIdx.get(key) ?? 0\n return i < v.length ? v[i] : undefined\n }\n\n /** 값 소비 — 배열이면 커서 전진, 소진 시 undefined */\n consume(key: string): string | undefined {\n const v = this.values.get(key)\n if (v === undefined) return undefined\n if (typeof v === \"string\") return v\n const i = this.nextIdx.get(key) ?? 0\n if (i >= v.length) return undefined\n this.nextIdx.set(key, i + 1)\n return v[i]\n }\n}\n\n/** 라벨 정규화 — 콜론/공백/특수문자 제거, 비교용 */\nexport function normalizeLabel(label: string): string {\n return label.trim().replace(/[::\\s()()·]/g, \"\")\n}\n\n/**\n * 정규화된 셀 라벨과 입력 값 맵에서 최적 매칭 키를 찾음.\n *\n * 매칭 우선순위:\n * 1. 정확 매칭 (normalizedCellLabel === key)\n * 2. 접두사 기반 매칭 (60% 이상 겹침 필요)\n */\nexport function findMatchingKey(\n cellLabel: string,\n values: { has(key: string): boolean; keys(): Iterable<string> },\n): string | undefined {\n // 1) 정확 매칭\n if (values.has(cellLabel)) return cellLabel\n\n // 2) 접두사 기반 매칭 — 가장 긴 매칭 우선 (= 가장 구체적)\n // 단, 길이 비율 60% 이상 겹쳐야 매칭 (오탐 방지)\n let bestKey: string | undefined\n let bestLen = 0\n\n for (const key of values.keys()) {\n if (cellLabel.startsWith(key)) {\n if (key.length >= cellLabel.length * 0.6 && key.length > bestLen) {\n bestLen = key.length\n bestKey = key\n }\n } else if (key.startsWith(cellLabel)) {\n // 역방향(짧은 셀이 긴 키를 흡수)은 0.75 — 0.6이면 셀 \"대리인\"이 키\n // \"대리인성명\"을 흡수해 성명 값이 대리인 라벨 옆에 들어간다\n if (cellLabel.length >= key.length * 0.75 && cellLabel.length > bestLen) {\n bestLen = cellLabel.length\n bestKey = key\n }\n }\n }\n\n return bestKey\n}\n\n/**\n * 값 셀이 키워드 라벨(섹션 헤더의 하위 라벨)인지 판별.\n * \"성명\", \"주소\" 같은 키워드 라벨이면 true → 스킵 대상.\n * \"(한자:)\" 같은 어노테이션이면 false → 채울 수 있음.\n */\nexport function isKeywordLabel(text: string): boolean {\n const trimmed = text.trim().replace(/[¹²³⁴⁵⁶⁷⁸⁹⁰*※]+$/g, \"\").trim()\n if (!trimmed || trimmed.length > 15) return false\n for (const kw of LABEL_KEYWORDS) {\n if (trimmed.includes(kw)) return true\n }\n return false\n}\n\n/**\n * 셀 텍스트에서 인셀 패턴을 찾아 교체 — 체크박스 + 괄호 빈칸.\n *\n * 지원 패턴:\n * 1. 괄호 빈칸: `일반( )통` → 키 \"일반통\" 또는 \"일반\" 매칭 시 → `일반(값)통`\n * 2. 체크박스: `□부` → 키 \"부\" 매칭 시 → `☑부` (값이 \"☑\",\"✓\",\"v\",\"V\",\"true\",\"1\" 등)\n *\n * @returns 교체된 텍스트 + 매칭된 키 목록. null이면 교체 없음.\n */\nexport function fillInCellPatterns(\n cellText: string,\n values: ValueCursor,\n matchedLabels: Set<string>,\n /** require_unique 2차에서 거부된 라벨 셀 차단 (sfill-2 전략0) — 전략 1~3과 동일 계약 */\n blockedLabels?: Set<string>,\n): { text: string; matches: Array<{ key: string; label: string; value: string }> } | null {\n let text = cellText\n const matches: Array<{ key: string; label: string; value: string }> = []\n\n // 1) 괄호 빈칸: keyword(\\s+)suffix → keyword(value)suffix\n text = text.replace(\n /([가-힣A-Za-z]+)\\(\\s{1,}\\)([가-힣A-Za-z]*)/g,\n (match, prefix: string, suffix: string) => {\n const label = prefix + suffix // \"일반\" + \"통\" = \"일반통\"\n const normalizedLabel = normalizeLabel(label)\n // require_unique 2차: 이 라벨이 거부됐으면 접두사 폴백으로 남의 키에 재배정 금지 (sfill-2 전략0)\n if (blockedLabels?.has(normalizedLabel)) return match\n // 정확 매칭 → 접두사만 매칭 순\n const matchKey = values.available(normalizedLabel)\n ? normalizedLabel\n : values.available(normalizeLabel(prefix))\n ? normalizeLabel(prefix)\n : undefined\n if (matchKey === undefined) return match\n\n const newValue = values.consume(matchKey)!\n matchedLabels.add(matchKey)\n matches.push({ key: matchKey, label, value: newValue })\n return `${prefix}(${newValue})${suffix}`\n },\n )\n\n // 2) 체크박스: □keyword → ☑keyword (값이 truthy)\n text = text.replace(\n /□([가-힣A-Za-z]+)/g,\n (match, keyword: string) => {\n const normalizedKw = normalizeLabel(keyword)\n const matchKey = values.available(normalizedKw) ? normalizedKw : undefined\n if (matchKey === undefined) return match\n\n const val = values.peek(matchKey)!\n // 계약: 빈 문자열은 \"체크 안 함\" — 체크 의사는 ☑/true/1 등 명시 값으로만 표현한다\n const isTruthy = [\"☑\", \"✓\", \"✔\", \"v\", \"V\", \"true\", \"1\", \"yes\", \"o\", \"O\"].includes(val.trim())\n if (!isTruthy) return match\n\n values.consume(matchKey)\n matchedLabels.add(matchKey)\n matches.push({ key: matchKey, label: `□${keyword}`, value: \"☑\" })\n return `☑${keyword}`\n },\n )\n\n // 3) 어노테이션 빈칸: (keyword:\\s+) → (keyword:value)\n // 예: \"(한자: )\" → \"(한자:金民秀)\"\n // 예: \"(성명: )\" → \"(성명: 홍길동)\"\n text = text.replace(\n /\\(([가-힣A-Za-z]+)[::]\\s{1,}\\)/g,\n (match, keyword: string) => {\n const normalizedKw = normalizeLabel(keyword)\n const matchKey = values.available(normalizedKw) ? normalizedKw : undefined\n if (matchKey === undefined) return match\n\n const newValue = values.consume(matchKey)!\n matchedLabels.add(matchKey)\n matches.push({ key: matchKey, label: keyword, value: newValue })\n return `(${keyword}:${newValue})`\n },\n )\n\n return matches.length > 0 ? { text, matches } : null\n}\n\n// ─── 인라인 \"라벨: 값\" 세그먼트 분해 ─────────────────\n\nexport interface InlineSegment {\n /** 라벨 (콜론 제외) */\n label: string\n /** 라벨 시작 오프셋 */\n labelStart: number\n /** 값 시작 오프셋 (콜론·공백 뒤) */\n valueStart: number\n /** 값 끝 오프셋 (다음 라벨/구분자 직전, 우측 공백 제외) */\n valueEnd: number\n /** text.slice(valueStart, valueEnd) */\n value: string\n /**\n * 직전 어절을 포함한 확장 라벨 (\"신청인 성명\") — 정확 매칭 후보.\n * 직전 어절이 이전 라벨의 값(\"… 강남구 전화:\")일 수 있으므로 정확 매칭에만\n * 쓰고, 접두사 매칭은 핵심 라벨(label)로만 한다. 직전 어절이 없으면 undefined.\n */\n extLabel?: string\n /** 확장 라벨 시작 오프셋 (직전 어절 첫 글자) — extLabel 있을 때만 */\n extStart?: number\n}\n\nconst INLINE_LABEL_RE = /((?:[가-힣A-Za-z]{1,10} )?)([가-힣A-Za-z]{2,10})\\s*[::]/g\n\n/**\n * 인라인 양식 한 줄을 라벨 단위로 분해 — 한 줄에 라벨이 여러 개인 양식\n * (\"자문위원 성명: 작성일자: \") 지원. 값은 다음 라벨 직전(또는\n * 구분자 [,;\\n] / 100자 / 줄끝)에서 끝난다. 값이 빈 라벨도 세그먼트로\n * 반환한다 (value=\"\", valueStart===valueEnd — 채움 대상).\n * \"http://\" 류 URL 스킴의 콜론은 라벨로 보지 않는다.\n */\nexport function scanInlineSegments(text: string): InlineSegment[] {\n const labels: Array<{ label: string; ext?: string; extStart?: number; start: number; end: number }> = []\n INLINE_LABEL_RE.lastIndex = 0\n let m: RegExpExecArray | null\n while ((m = INLINE_LABEL_RE.exec(text)) !== null) {\n if (text[INLINE_LABEL_RE.lastIndex] === \"/\") continue // \"://\" — URL 스킴\n // m[1]=직전 어절(확장 라벨용, 공백 포함), m[2]=핵심 라벨. 세그먼트 좌표는\n // 핵심 라벨 기준(기존 값 경계 보존) — \"신청인 성명:\"과 \"대리인 성명:\"이 같은\n // \"성명\"으로 붕괴하지 않게 확장 라벨을 정확 매칭 후보로 함께 넘긴다.\n labels.push({\n label: m[2],\n ext: m[1] ? m[1] + m[2] : undefined,\n extStart: m[1] ? m.index : undefined,\n start: m.index + m[1].length,\n end: INLINE_LABEL_RE.lastIndex,\n })\n }\n\n const segments: InlineSegment[] = []\n for (let i = 0; i < labels.length; i++) {\n const cur = labels[i]\n let vs = cur.end\n while (vs < text.length && (text[vs] === \" \" || text[vs] === \"\\t\")) vs++\n let ve = i + 1 < labels.length ? labels[i + 1].start : text.length\n if (ve < vs) ve = vs // 다음 라벨이 공백 스킵 구간 안에서 시작하는 경우\n const sep = text.slice(vs, ve).search(/[\\n,;]/)\n if (sep !== -1) ve = vs + sep\n if (ve - vs > 100) ve = vs + 100\n while (ve > vs && /\\s/.test(text[ve - 1])) ve--\n segments.push({\n label: cur.label,\n labelStart: cur.start,\n valueStart: vs,\n valueEnd: ve,\n value: text.slice(vs, ve),\n ...(cur.ext !== undefined ? { extLabel: cur.ext, extStart: cur.extStart } : {}),\n })\n }\n return segments\n}\n\n/**\n * 인라인 세그먼트 매칭 키 결정 — 확장 라벨(\"신청인 성명\") 정확 매칭 우선,\n * 핵심 라벨(\"성명\")은 기존 findMatchingKey(정확+접두사) 폴백.\n * 확장 라벨은 직전 어절이 이전 라벨의 값일 수 있어 정확 매칭만 허용한다 (과탐 방지).\n * @returns 매칭 키 + filled 보고용 라벨 + 확장 매칭 여부. blockedLabels(sfill-2)에 걸리면 undefined.\n */\nexport function matchInlineSegment(\n seg: InlineSegment,\n values: { has(key: string): boolean; keys(): Iterable<string> },\n blockedLabels?: Set<string>,\n): { key: string; label: string; viaExt: boolean } | undefined {\n const nlabel = normalizeLabel(seg.label)\n if (seg.extLabel !== undefined) {\n const nExt = normalizeLabel(seg.extLabel)\n if (nExt !== nlabel && !blockedLabels?.has(nExt) && values.has(nExt)) {\n return { key: nExt, label: seg.extLabel, viaExt: true }\n }\n }\n if (blockedLabels?.has(nlabel)) return undefined\n const key = findMatchingKey(nlabel, values)\n return key !== undefined ? { key, label: seg.label, viaExt: false } : undefined\n}\n\n/**\n * 세그먼트 값의 유효 끝 — 다음 세그먼트가 확장 라벨로 매칭됐으면 값 범위가\n * 그 직전 어절(확장 라벨의 일부, \"대리인 성명\"의 \"대리인\")을 삼키지 않게 앞당긴다.\n */\nexport function clampSegmentEnd(\n text: string,\n seg: InlineSegment,\n next: InlineSegment | undefined,\n nextViaExt: boolean,\n): number {\n let ve = seg.valueEnd\n if (nextViaExt && next?.extStart !== undefined && next.extStart < ve) ve = next.extStart\n while (ve > seg.valueStart && /\\s/.test(text[ve - 1])) ve--\n return ve\n}\n\n/** 빈 자리(valueStart===valueEnd) 삽입 시 콜론·다음 라벨과 붙지 않게 공백 부착 */\nexport function padInsertion(text: string, pos: number, value: string): string {\n const lead = pos > 0 && !/\\s/.test(text[pos - 1]) ? \" \" : \"\"\n const trail = pos < text.length && !/\\s/.test(text[pos]) ? \" \" : \"\"\n return lead + value + trail\n}\n\n/**\n * 입력 values 맵을 정규화된 키로 변환 — format 지정(FillInput 객체형)은 여기서 값으로 변환.\n * @param warnings 정규화 후 키가 충돌하는 라벨(\"성 명\"과 \"성명\")의 무음 덮어쓰기 경고 수집\n */\nexport function normalizeValues(values: Record<string, FillInput>, warnings?: string[]): Map<string, FillValue> {\n const map = new Map<string, FillValue>()\n for (const [label, raw] of Object.entries(values)) {\n const { value, format } = typeof raw === \"object\" && !Array.isArray(raw)\n ? raw\n : { value: raw, format: undefined }\n const key = normalizeLabel(label)\n if (map.has(key)) {\n warnings?.push(`입력 라벨 \"${label}\"이 정규화 키 \"${key}\"에서 다른 라벨과 충돌 — 뒤 값으로 덮어씀`)\n }\n map.set(key, Array.isArray(value)\n ? value.map(v => formatFillValue(v, format))\n : formatFillValue(value, format))\n }\n return map\n}\n\n/**\n * 모호 라벨 거부 가드 — 한 입력 키(스칼라)가 서식의 2곳 이상에 채워지면 남의 블록\n * 오염 위험(대표자 행에 참여인력 값이 들어가는 류)이므로, 그 키는 채우지 않고\n * rejected로 보고한 뒤 나머지 키만으로 다시 채운다 (claw-hwp require_occurrence 이식).\n * 배열 값은 다중 등장 소진이 의도된 동작이라 거부 대상이 아니다.\n * @param run 같은 원본에 대해 결정적으로 재실행 가능한 채우기 함수\n */\nexport async function fillWithUniqueGuard<R extends { filled: Array<{ key?: string; label: string }> }>(\n values: Record<string, FillInput>,\n run: (vals: Record<string, FillInput>, blockedLabels?: Set<string>) => R | Promise<R>,\n): Promise<R & { rejected: string[] }> {\n const first = await run(values)\n const counts = new Map<string, number>()\n for (const f of first.filled) {\n // 누름틀(clickhere)은 이름 정확 일치라 다중 등장이 곧 서식의 설계다 — 집계에서 뺀다.\n // 세지 않으면 동명 누름틀 2곳짜리 서식이 통째로 rejected 되어 한 곳도 안 채워진다.\n if (f.key && (f as { source?: string }).source !== \"clickhere\") {\n counts.set(f.key, (counts.get(f.key) ?? 0) + 1)\n }\n }\n const isArrayValue = (normKey: string): boolean => {\n for (const [label, raw] of Object.entries(values)) {\n if (normalizeLabel(label) !== normKey) continue\n return Array.isArray(typeof raw === \"object\" && !Array.isArray(raw) ? raw.value : raw)\n }\n return false\n }\n const dup = new Set([...counts].filter(([k, n]) => n >= 2 && !isArrayValue(k)).map(([k]) => k))\n if (dup.size === 0) return { ...first, rejected: [] }\n // 거부된 키에 매칭됐던 셀 라벨들 — 2차에서 이 셀이 접두사 매칭으로 남은 다른 키에\n // 재배정되어 남의 값으로 오염되는 것을 차단한다 (sfill-2).\n const blockedLabels = new Set<string>()\n for (const f of first.filled) {\n if (f.key && dup.has(f.key)) blockedLabels.add(normalizeLabel(f.label))\n }\n const filtered = Object.fromEntries(Object.entries(values).filter(([label]) => !dup.has(normalizeLabel(label))))\n const second = await run(filtered, blockedLabels)\n const rejected = Object.keys(values).filter(label => dup.has(normalizeLabel(label)))\n return { ...second, rejected }\n}\n\n/** 매칭 안 된 라벨을 원본 키로 복원 */\nexport function resolveUnmatched(\n normalizedValues: Map<string, FillValue>,\n matchedLabels: Set<string>,\n originalValues: Record<string, FillInput>,\n): string[] {\n return [...normalizedValues.keys()]\n .filter(k => !matchedLabels.has(k))\n .map(k => {\n for (const orig of Object.keys(originalValues)) {\n if (normalizeLabel(orig) === k) return orig\n }\n return k\n })\n}\n","/** 양식(서식) 필드 인식 — 테이블 기반 label-value 패턴 매칭 */\n\nimport type { IRBlock, IRTable, FormField, FormResult } from \"../types.js\"\nimport { scanInlineSegments, normalizeLabel } from \"./match.js\"\n\n/** 한국 공문서 필드 라벨 키워드 */\nexport const LABEL_KEYWORDS = new Set([\n \"성명\", \"이름\", \"주소\", \"전화\", \"전화번호\", \"휴대폰\", \"핸드폰\", \"연락처\",\n \"생년월일\", \"주민등록번호\", \"소속\", \"직위\", \"직급\", \"부서\",\n \"이메일\", \"팩스\", \"학교\", \"학년\", \"반\", \"번호\",\n \"신청인\", \"대표자\", \"담당자\", \"작성자\", \"확인자\", \"승인자\",\n \"일시\", \"날짜\", \"기간\", \"장소\", \"목적\", \"사유\", \"비고\",\n \"금액\", \"수량\", \"단가\", \"합계\", \"계\", \"소계\",\n \"등록기준지\", \"본적\", \"위임인\", \"청구사유\", \"소명자료\",\n])\n\n/** 콜론 없는 영문 라벨로 인정하는 단어 (한국 공문서 병기 관행) */\nconst ENGLISH_LABEL_WORDS = new Set([\n \"name\", \"date\", \"address\", \"tel\", \"phone\", \"mobile\", \"fax\", \"email\", \"e-mail\",\n \"dept\", \"department\", \"division\", \"title\", \"position\", \"grade\", \"rank\",\n \"birth\", \"nationality\", \"sex\", \"gender\", \"signature\", \"sign\", \"seal\",\n \"remarks\", \"note\", \"period\", \"place\", \"purpose\", \"reason\", \"amount\", \"total\",\n \"sum\", \"qty\", \"quantity\", \"unit\", \"no\", \"id\", \"passport\",\n])\nconst ENGLISH_STOPWORDS = new Set([\"of\", \"the\", \"and\", \"or\", \"in\"])\n\n/** 수량/단위 값 형태 — \"6개월\"·\"1억원\"·\"5백만원\"·\"2026년\" 등은 라벨이 아님 */\nconst NUMERIC_VALUE_RE = /^제?\\d+(?:[.,]\\d+)*[십백천만억조]*(?:원|명|건|개|회|부|매|장|점|호|번|년|월|일|시|분|초|개월|주년|차례|퍼센트)?$/\n\n/** 서술형 문장 어미 — 셀에 든 안내 문구를 라벨로 오인하지 않기 위한 컷 */\nconst SENTENCE_ENDING_RE = /(?:입니다|합니다|습니다|하세요|십시오|시오|바랍니다|바람|할 것|할것|하며|하고|한다|된다|됨|음|임)$/\n\n/** 라벨처럼 보이는 셀인지 판별 */\nexport function isLabelCell(text: string): boolean {\n // 각주 번호/특수문자 제거 후 판별 (예: \"등록기준지²\" → \"등록기준지\")\n const trimmed = text.trim().replace(/[¹²³⁴⁵⁶⁷⁸⁹⁰*※]+$/g, \"\").trim()\n if (!trimmed || trimmed.length > 30) return false\n // 키워드 매칭\n for (const kw of LABEL_KEYWORDS) {\n if (trimmed.includes(kw)) return true\n }\n // 짧은 한글 텍스트 (2-12자, 공백/괄호/특수기호 허용) — 숫자는 낄 수 있으나\n // (\"연번1\"·\"제1항목\"·\"1차소속\") 수량/단위 값·서술형 문구·법인명은 라벨이 아님.\n // 9자 이상 확장 구간은 3어절 이상 제목성 문구를 컷 (자간 공백 라벨\n // \"업 체 명\"류가 있는 8자 이하 기존 구간에는 어절 제한을 걸지 않는다)\n const compact = trimmed.replace(/\\s/g, \"\")\n if (/^[가-힣0-9()()·::\\-]+$/.test(compact)\n && compact.length >= 2 && compact.length <= 12\n && (compact.match(/[가-힣]/g) ?? []).length >= 2\n && (compact.length <= 8 || trimmed.split(/\\s+/).length <= 2)\n && !NUMERIC_VALUE_RE.test(compact)\n && !SENTENCE_ENDING_RE.test(trimmed)\n && !/^[((]주[))]|^주식회사/.test(compact)) {\n return true\n }\n // \"라벨:\" 패턴\n if (/^[가-힣A-Za-z\\s]+[::]$/.test(trimmed)) return true\n // 콜론 없는 영문 라벨 (\"Name\"·\"Date of Birth\") — 관행 단어 목록으로 한정\n if (/^[A-Za-z][A-Za-z\\s./&-]*$/.test(trimmed) && trimmed.length <= 20) {\n const words = trimmed.toLowerCase().split(/[\\s/&]+/).filter(w => w && !ENGLISH_STOPWORDS.has(w))\n if (words.length >= 1 && words.length <= 3 && words.every(w => ENGLISH_LABEL_WORDS.has(w.replace(/\\.$/, \"\")))) {\n return true\n }\n }\n return false\n}\n\n/**\n * IRBlock[]에서 양식 필드를 인식하여 추출.\n * 테이블의 label-value 패턴을 감지.\n */\nexport function extractFormFields(blocks: IRBlock[]): FormResult {\n const fields: FormField[] = []\n let totalTables = 0\n let formTables = 0\n\n for (const table of collectTables(blocks)) {\n totalTables++\n\n const tableFields = extractFromTable(table)\n if (tableFields.length > 0) {\n formTables++\n fields.push(...tableFields)\n }\n }\n\n // 인라인 \"라벨: 값\" 패턴도 검사 (paragraph만 — heading/list는 양식 필드가 아님)\n for (const block of blocks) {\n if (block.type === \"paragraph\" && block.text) {\n const inlineFields = extractInlineFields(block.text)\n fields.push(...inlineFields)\n }\n }\n\n const confidence = totalTables > 0 ? formTables / totalTables : (fields.length > 0 ? 0.3 : 0)\n return { fields, confidence: Math.min(confidence, 1) }\n}\n\n/**\n * 문서 순서 표 수집 — 셀 blocks 의 중첩표 포함. 법령 별지서식은 1칸 틀 안에 신청인 정보·발신명의 표가\n * 중첩되어 있고(HWPX 파서·PDF 클립 셀 그리드 모두 셀 blocks 로 낸다) fillHwpx 도 중첩표를 DFS 로 훑으므로\n * 인식기도 같은 경계로 본다 — 최상위만 보면 틀 안 표의 라벨-값이 통째로 빠진다 (v4.12.2)\n */\nfunction collectTables(blocks: IRBlock[], out: IRTable[] = [], depth = 0): IRTable[] {\n if (depth > 12) return out\n for (const block of blocks) {\n if (block.type !== \"table\" || !block.table) continue\n out.push(block.table)\n for (const row of block.table.cells) {\n for (const cell of row) if (cell?.blocks?.length) collectTables(cell.blocks, out, depth + 1)\n }\n }\n return out\n}\n\nfunction extractFromTable(table: IRTable): FormField[] {\n const fields: FormField[] = []\n\n // 전략 1: 인접셀 label-value (2열 이상 테이블)\n if (table.cols >= 2) {\n for (let r = 0; r < table.rows; r++) {\n for (let c = 0; c < table.cols - 1; c++) {\n const labelCell = table.cells[r]?.[c]\n const valueCell = table.cells[r]?.[c + 1]\n if (!labelCell || !valueCell) continue\n if (isLabelCell(labelCell.text)) {\n fields.push({\n label: labelCell.text.trim().replace(/[::]\\s*$/, \"\"),\n value: valueCell.text.trim(),\n row: r,\n col: c,\n })\n }\n }\n }\n }\n\n // 전략 2: 헤더+데이터 행 (첫 행이 전부 라벨이면)\n if (fields.length === 0 && table.rows >= 2 && table.cols >= 2) {\n const headerRow = table.cells[0]\n const allLabels = headerRow?.every(cell => {\n const t = cell?.text.trim() ?? \"\"\n return t.length > 0 && t.length <= 20\n }) ?? false\n if (allLabels) {\n for (let r = 1; r < table.rows; r++) {\n for (let c = 0; c < table.cols; c++) {\n const label = headerRow[c]?.text.trim() ?? \"\"\n const value = table.cells[r]?.[c]?.text.trim() ?? \"\"\n if (label && value) {\n fields.push({ label, value, row: r, col: c })\n }\n }\n }\n }\n }\n\n return fields\n}\n\nfunction extractInlineFields(text: string): FormField[] {\n // \"라벨: 값\" — 한 줄 다중 라벨(\"성명: 작성일자: \")은 세그먼트 단위로 분해.\n // 값이 빈 라벨은 여기선 제외 (기존 계약 유지) — extractFormSchema가 수집한다.\n const fields: FormField[] = []\n for (const seg of scanInlineSegments(text)) {\n if (seg.value) {\n fields.push({ label: seg.label, value: seg.value, row: -1, col: -1 })\n }\n }\n return fields\n}\n\n// ─── 필드 스키마 (타입 추론) — v3.1 ─────────────────\n\n/** 양식 필드 타입 — 폼 UI 위젯 선택의 근거 (데이트피커/체크박스 등) */\nexport type FormFieldType = \"text\" | \"date\" | \"phone\" | \"email\" | \"amount\" | \"checkbox\" | \"idnum\"\n\n/** 타입이 추론된 양식 필드 */\nexport interface FormFieldSchema extends FormField {\n type: FormFieldType\n /** 라벨에 필수 표시(※·*·★·\"(필수)\")가 있을 때만 true */\n required?: boolean\n /** 값이 비어 있거나 플레이스홀더(밑줄/괄호 빈칸)뿐 — 채움 대상 */\n empty: boolean\n}\n\nexport interface FormSchemaResult {\n fields: FormFieldSchema[]\n /** 양식 확신도 (0-1, extractFormFields와 동일) */\n confidence: number\n}\n\n/** 라벨 키워드 → 타입 (값 패턴이 우선, 라벨은 폴백) */\nconst LABEL_TYPE_RULES: Array<[RegExp, FormFieldType]> = [\n [/주민등록번호|외국인등록번호/, \"idnum\"],\n [/생년월일|일시|날짜|일자|기간|연월일|년월일|신청일|작성일|발급일|접수일/, \"date\"],\n [/전화|연락처|휴대폰|핸드폰|팩스/, \"phone\"],\n [/이메일|전자우편|email/i, \"email\"],\n [/금액|단가|수량|합계|소계|예산|비용|인원|급여|연봉/, \"amount\"],\n]\n\n/** 필드 타입 추론 — 기존 값의 패턴 우선, 없으면 라벨 키워드 */\nexport function inferFieldType(label: string, value: string): FormFieldType {\n if (/[□☑✓✔]/.test(value) || /[□☑✓✔]/.test(label)) return \"checkbox\"\n\n const v = value.trim()\n if (v) {\n if (/^\\d{6}[-\\s]?[1-4]\\d{6}$/.test(v)) return \"idnum\"\n if (/^\\d{4}\\s*[-./년]\\s*\\d{1,2}\\s*[-./월]\\s*\\d{1,2}\\s*일?\\s*\\.?$/.test(v)) return \"date\"\n if (/^0\\d{1,2}[-.)\\s]?\\d{3,4}[-.\\s]?\\d{4}$/.test(v)) return \"phone\"\n if (/^[\\w.+-]+@[\\w-]+(?:\\.[\\w-]+)+$/.test(v)) return \"email\"\n // 단위 접미사 또는 천단위 콤마가 있을 때만 값 기반 amount — 맨 숫자\n // (우편번호/접수번호/연도 등)는 라벨 폴백으로 넘긴다\n if (/^[\\d,.\\s]+(?:원|명|건|개|회|부|매|%)$/.test(v) && /\\d/.test(v)) return \"amount\"\n if (/^\\d{1,3}(?:,\\d{3})+$/.test(v)) return \"amount\"\n }\n\n const norm = label.replace(/\\s/g, \"\")\n for (const [re, type] of LABEL_TYPE_RULES) {\n if (re.test(norm)) return type\n }\n return \"text\"\n}\n\n/** 라벨의 필수 표시 감지 (※·*·★·\"(필수)\") */\nfunction isRequiredLabel(label: string): boolean {\n return /[*※★]|\\(\\s*필수\\s*\\)|(\\s*필수\\s*)/.test(label)\n}\n\n/** 값이 비어 있거나 플레이스홀더(밑줄·괄호 빈칸·대시)뿐인지 */\nfunction isEmptyValue(value: string): boolean {\n const v = value.trim()\n if (!v) return true\n return /^[\\s_()()\\-—–~.·,]*$/.test(v)\n}\n\n/**\n * 양식 필드 인식 + 타입/필수/빈값 추론 — 폼 UI 자동 생성용 (v3.1).\n * extractFormFields 결과에 type(date/phone/amount/checkbox/...)·required·empty를 부여한다.\n */\nexport function extractFormSchema(blocks: IRBlock[]): FormSchemaResult {\n const { fields, confidence } = extractFormFields(blocks)\n const schemaFields: FormFieldSchema[] = fields.map(f => ({\n ...f,\n type: inferFieldType(f.label, f.value),\n required: isRequiredLabel(f.label) || undefined,\n empty: isEmptyValue(f.value),\n }))\n\n // 값이 빈 인라인 라벨(\"작성일자:\")도 채움 대상으로 노출 —\n // extractFormFields는 값 있는 필드만 수집하므로 여기서 보충한다\n const seen = new Set(schemaFields.map(f => normalizeLabel(f.label)))\n for (const block of blocks) {\n if (block.type !== \"paragraph\" || !block.text) continue\n for (const seg of scanInlineSegments(block.text)) {\n if (seg.value) continue\n const key = normalizeLabel(seg.label)\n if (seen.has(key)) continue\n seen.add(key)\n schemaFields.push({\n label: seg.label,\n value: \"\",\n row: -1,\n col: -1,\n type: inferFieldType(seg.label, \"\"),\n required: isRequiredLabel(seg.label) || undefined,\n empty: true,\n })\n }\n }\n\n return { confidence, fields: schemaFields }\n}\n","/** 양식 서식 필드 값 채우기 — IRBlock[] 기반 in-place 교체 */\n\nimport type { IRBlock, IRCell, IRTable, FormField } from \"../types.js\"\nimport { isLabelCell } from \"./recognize.js\"\nimport { normalizeLabel, findMatchingKey, normalizeValues, resolveUnmatched, isKeywordLabel, fillInCellPatterns, scanInlineSegments, matchInlineSegment, clampSegmentEnd, padInsertion, ValueCursor, type FillInput } from \"./match.js\"\n\n/** 필드 채우기 결과 */\nexport interface FillResult {\n /** 값이 교체된 IRBlock[] */\n blocks: IRBlock[]\n /** 실제 채워진 필드 목록 */\n filled: FormField[]\n /** 매칭 실패한 라벨 (입력에는 있지만 서식에서 못 찾은 것) */\n unmatched: string[]\n /** 비치명 경고 (입력 라벨 정규화 충돌 등) — 없으면 생략 */\n warnings?: string[]\n}\n\n/**\n * IRBlock[]에서 양식 필드를 찾아 값을 교체.\n *\n * @param blocks 원본 IRBlock[] (변경하지 않음 — deep clone)\n * @param values 채울 값 맵 (라벨 → 새 값). 라벨은 접두사 매칭 지원.\n * 값이 배열이면 같은 라벨의 등장 순서대로 하나씩 소진(반복 양식·명부형 표),\n * 문자열이면 모든 등장에 동일값.\n * @returns FillResult\n *\n * @example\n * ```ts\n * const result = await parse(\"신청서.hwp\")\n * if (!result.success) throw new Error(result.error)\n * const { blocks, filled } = fillFormFields(result.blocks, {\n * \"성명\": \"홍길동\",\n * \"전화번호\": \"010-1234-5678\",\n * \"주소\": \"서울시 강남구\",\n * })\n * ```\n */\nexport function fillFormFields(\n blocks: IRBlock[],\n values: Record<string, FillInput>,\n /** require_unique 2차에서 거부된 라벨 셀 차단 (sfill-2) — hwpx 경로와 동일 계약 */\n blockedLabels?: Set<string>,\n): FillResult {\n // deep clone — 원본 불변\n const cloned = structuredClone(blocks)\n const filled: FormField[] = []\n const matchedLabels = new Set<string>()\n const warnings: string[] = []\n\n const normalizedValues = normalizeValues(values, warnings)\n const cursor = new ValueCursor(normalizedValues)\n\n // 표 수집 — 중첩표 포함 DFS (hwpx 경로 collectTables와 동일하게 depth 16)\n const allTables = collectIRTables(cloned, 0)\n\n // 1) 인셀 패턴 먼저 (체크박스, 괄호 빈칸, 어노테이션) — 전략 2가 덮어쓰기 전에\n const patternFilledCells = new Set<IRCell>()\n for (const table of allTables) {\n for (let r = 0; r < table.rows; r++) {\n for (let c = 0; c < table.cols; c++) {\n const cell = table.cells[r]?.[c]\n if (!cell) continue\n const result = fillInCellPatterns(cell.text, cursor, matchedLabels, blockedLabels)\n if (result) {\n cell.text = result.text\n patternFilledCells.add(cell)\n for (const m of result.matches) {\n filled.push({ label: m.label, value: m.value, row: r, col: c, key: m.key })\n }\n }\n }\n }\n }\n\n // 2) 테이블 기반 필드 교체 (라벨-값 셀 패턴)\n for (const table of allTables) {\n fillTable(table, cursor, filled, matchedLabels, patternFilledCells, blockedLabels)\n }\n\n // 3) 인라인 \"라벨: 값\" 패턴 교체\n for (const block of cloned) {\n if (block.type !== \"paragraph\" || !block.text) continue\n const newText = fillInlineFields(block.text, cursor, filled, matchedLabels, blockedLabels)\n if (newText !== block.text) block.text = newText\n }\n\n const unmatched = resolveUnmatched(normalizedValues, matchedLabels, values)\n return { blocks: cloned, filled, unmatched, ...(warnings.length > 0 ? { warnings } : {}) }\n}\n\n/** 중첩표 포함 표 수집 — 문서 순서 DFS (hwpx 경로 collectTables와 동일 규칙) */\nfunction collectIRTables(blocks: IRBlock[], depth: number): IRTable[] {\n if (depth > 16) return []\n const out: IRTable[] = []\n for (const block of blocks) {\n if (block.type !== \"table\" || !block.table) continue\n out.push(block.table)\n for (const row of block.table.cells) {\n for (const cell of row) {\n if (cell?.blocks?.length) out.push(...collectIRTables(cell.blocks, depth + 1))\n }\n }\n }\n return out\n}\n\n/**\n * 병합으로 덮인 격자 좌표(\"r,c\") — 앵커가 아닌 플레이스홀더 위치.\n * builder 렌더는 이 칸을 그리지 않으므로 여기 쓴 값은 조용히 사라진다.\n */\nfunction coveredPositions(table: IRTable): Set<string> {\n const covered = new Set<string>()\n for (let r = 0; r < table.rows; r++) {\n for (let c = 0; c < table.cols; c++) {\n if (covered.has(`${r},${c}`)) continue\n const cell = table.cells[r]?.[c]\n if (!cell) continue\n for (let dr = 0; dr < cell.rowSpan; dr++) {\n for (let dc = 0; dc < cell.colSpan; dc++) {\n if (dr === 0 && dc === 0) continue\n if (r + dr < table.rows && c + dc < table.cols) covered.add(`${r + dr},${c + dc}`)\n }\n }\n c += cell.colSpan - 1\n }\n }\n return covered\n}\n\n/**\n * 헤더+데이터 표 판별 — 첫 행이 전부 라벨이고 둘째 행 첫 앵커 셀이 라벨이 아니면\n * 첫 행은 열 헤더(전략 2 대상)다. 둘째 행도 라벨로 시작하면 라벨-값 서식\n * (플레이스홀더 \"미기재\"류 포함)으로 보고 전략 1이 기존대로 채운다.\n */\nfunction isHeaderDataTable(table: IRTable, covered: Set<string>): boolean {\n if (table.rows < 2) return false\n const headerRow = table.cells[0]\n if (!headerRow?.length) return false\n const allLabels = headerRow.every(cell => {\n const t = cell?.text.trim() ?? \"\"\n return t.length > 0 && t.length <= 20 && isLabelCell(t)\n })\n if (!allLabels) return false\n for (let c = 0; c < table.cols; c++) {\n if (covered.has(`1,${c}`)) continue\n const cell = table.cells[1]?.[c]\n if (!cell) break\n return !isLabelCell(cell.text)\n }\n return true\n}\n\n/** 테이블 셀에서 라벨-값 패턴을 찾아 값 교체 */\nfunction fillTable(\n table: IRTable,\n values: ValueCursor,\n filled: FormField[],\n matchedLabels: Set<string>,\n patternFilledCells?: Set<IRCell>,\n blockedLabels?: Set<string>,\n): void {\n if (table.cols < 2) return\n const covered = coveredPositions(table)\n\n // 전략 1: 인접 라벨-값 셀 패턴 — 값 셀은 라벨 span 뒤 같은 행의 다음 앵커\n // (hwpx 경로의 '다음 tc'와 동일. 병합 플레이스홀더에 쓰면 렌더에서 사라짐)\n // 헤더+데이터 표의 헤더 행은 제외 — 헤더 이웃 셀(\"품명\"→\"규격\")을 값으로 덮는 오염 방지\n const skipHeaderRow = isHeaderDataTable(table, covered)\n for (let r = skipHeaderRow ? 1 : 0; r < table.rows; r++) {\n for (let c = 0; c < table.cols; c++) {\n if (covered.has(`${r},${c}`)) continue\n const labelCell = table.cells[r]?.[c]\n if (!labelCell) continue\n\n if (!isLabelCell(labelCell.text)) continue\n\n let vc = c + labelCell.colSpan\n while (vc < table.cols && covered.has(`${r},${vc}`)) vc++\n if (vc >= table.cols) continue\n const valueCell = table.cells[r][vc]\n if (!valueCell) continue\n\n if (isKeywordLabel(valueCell.text)) continue\n\n const normalizedCellLabel = normalizeLabel(labelCell.text)\n if (!normalizedCellLabel) continue\n if (blockedLabels?.has(normalizedCellLabel)) continue\n\n const matchKey = findMatchingKey(normalizedCellLabel, values)\n if (matchKey === undefined) continue\n\n const newValue = values.consume(matchKey)\n if (newValue === undefined) continue // 배열 값 소진 — 이후 등장은 채우지 않음\n // 이미 인셀 패턴이 처리된 셀이면 앞에 삽입 (어노테이션 보존)\n if (patternFilledCells?.has(valueCell)) {\n valueCell.text = newValue + \" \" + valueCell.text\n } else {\n valueCell.text = newValue\n }\n matchedLabels.add(matchKey)\n filled.push({\n label: labelCell.text.trim().replace(/[::]\\s*$/, \"\"),\n value: newValue,\n row: r,\n col: c,\n key: matchKey,\n })\n }\n }\n\n // 전략 2: 헤더+데이터 행 패턴 (첫 행이 전부 라벨이면)\n // 전략 1에서 이미 채운 필드는 스킵 (matchedLabels 검사)\n if (table.rows >= 2 && table.cols >= 2) {\n const headerRow = table.cells[0]\n const allLabels = headerRow?.every(cell => {\n const t = cell?.text.trim() ?? \"\"\n return t.length > 0 && t.length <= 20 && isLabelCell(t)\n }) ?? false\n if (!allLabels) return\n\n for (let r = 1; r < table.rows; r++) {\n for (let c = 0; c < table.cols; c++) {\n // 병합 플레이스홀더에 쓰면 사라지고 값만 소진됨 — 앵커만 채움\n if (covered.has(`${r},${c}`)) continue\n const headerCell = headerRow[c]\n const valueCell = table.cells[r]?.[c]\n if (!headerCell || !valueCell) continue\n const headerLabel = normalizeLabel(headerCell.text)\n if (blockedLabels?.has(headerLabel)) continue\n const matchKey = findMatchingKey(headerLabel, values)\n if (matchKey === undefined) continue\n // 스칼라: 첫 데이터 행만(기존 동작). 배열: 행마다 다음 값 소진(명부형 표)\n if (!values.isArray(matchKey) && matchedLabels.has(matchKey)) continue\n\n const newValue = values.consume(matchKey)\n if (newValue === undefined) continue // 배열 값 소진\n // 전략 0(인셀 패턴)이 편집한 셀은 폐기하지 않고 앞에 삽입 (전략 1과 동일 계약)\n if (patternFilledCells?.has(valueCell)) {\n valueCell.text = newValue + \" \" + valueCell.text\n } else {\n valueCell.text = newValue\n }\n matchedLabels.add(matchKey)\n filled.push({\n label: headerCell.text.trim(),\n value: newValue,\n row: r,\n col: c,\n key: matchKey,\n })\n }\n }\n }\n}\n\n/** 인라인 \"라벨: 값\" 패턴 교체 — 한 줄 다중 라벨은 세그먼트 단위로 처리 */\nfunction fillInlineFields(\n text: string,\n values: ValueCursor,\n filled: FormField[],\n matchedLabels: Set<string>,\n blockedLabels?: Set<string>,\n): string {\n const segments = scanInlineSegments(text)\n if (segments.length === 0) return text\n\n // 확장 라벨(\"신청인 성명\") 정확 매칭 우선 — \"성명\" 붕괴 방지 (blockedLabels 포함 판정).\n // 매칭을 선계산해 다음 세그먼트가 확장 매칭이면 이전 값 끝을 그 어절 앞으로 당긴다.\n const matches = segments.map(seg => matchInlineSegment(seg, values, blockedLabels))\n\n let out = \"\"\n let pos = 0\n for (let i = 0; i < segments.length; i++) {\n const seg = segments[i]\n const matched = matches[i]\n if (matched === undefined) continue\n const matchKey = matched.key\n\n const newValue = values.consume(matchKey)\n if (newValue === undefined) continue // 배열 값 소진\n matchedLabels.add(matchKey)\n filled.push({ label: matched.label.trim(), value: newValue, row: -1, col: -1, key: matchKey })\n const ve = clampSegmentEnd(text, seg, segments[i + 1], matches[i + 1]?.viaExt ?? false)\n out += text.slice(pos, seg.valueStart)\n // 빈 자리 삽입은 콜론·다음 라벨과 붙지 않게 공백 부착\n out += seg.valueStart === ve\n ? padInsertion(text, seg.valueStart, newValue)\n : newValue\n pos = ve\n }\n out += text.slice(pos)\n return out\n}\n","/**\n * HWPX 원본 서식 유지 채우기 — section XML 오프셋 splice (v3.1, 바이트 보존)\n *\n * v3.0까지는 xmldom 전체 재직렬화 방식이라 변경하지 않은 영역도 속성 순서·\n * 공백·자기닫힘 표기가 바뀔 수 있었다. v3.1부터 patchHwpx와 동일한\n * source-map splice + ZIP in-place 재조립을 사용해, 변경 문단 외 XML과\n * 비변경 ZIP 엔트리를 1바이트도 건드리지 않는다.\n *\n * 전략 (v3.0과 동일, 적용 순서 보존):\n * 0. 인셀 패턴 — 체크박스 □→☑, 괄호 빈칸 ( )→(값), 어노테이션 (한자:)→(한자:값)\n * 1. 인접 라벨-값 셀 — label | value (패턴 적용 셀은 값을 앞에 삽입해 어노테이션 보존)\n * 2. 헤더+데이터 행 — 첫 행이 전부 라벨이면 열 단위 매칭 (나중 쓰기 우선 — v3.0 동일)\n * 3. 인라인 \"라벨: 값\" — 표 밖 본문/글상자/머리말·꼬리말·각주 문단\n *\n * 적용 범위는 v3.0과 동일하게 머리말/꼬리말 등 ctrl 내부 표·문단을 포함하고\n * (scan.orphanTables/excludedParagraphs), 셀 라벨 판정은 v3.0과 동일하게\n * 글상자(drawText) 문단을 제외한다. 패턴 매칭·범위 치환은 hp:t 연결 텍스트\n * (t-도메인) 좌표로 수행해 사이에 끼인 tab/br 요소를 건드리지 않는다.\n *\n * v3.0과의 의도적 차이: 인셀 패턴(전략 0)은 문단 단위로 매칭한다 — 문단\n * 경계에 걸친 패턴(극히 드묾)은 채우지 않는다.\n */\n\nimport JSZip from \"jszip\"\nimport { isLabelCell } from \"./recognize.js\"\nimport { fillClickHereInXml } from \"./click-here.js\"\nimport { KordocError, precheckZipSize } from \"../utils.js\"\nimport { normalizeLabel, findMatchingKey, normalizeValues, resolveUnmatched, isKeywordLabel, fillInCellPatterns, scanInlineSegments, matchInlineSegment, clampSegmentEnd, padInsertion, ValueCursor, type FillValue , type FillInput } from \"./match.js\"\nimport type { FormField } from \"../types.js\"\nimport {\n scanSectionXml, buildParagraphSplices, buildRangeSplices, applySplices, paraTText, paraTextPureT,\n allLinesegRemovalSplices,\n type ScanParagraph, type ScanCell, type ScanTable, type SpliceEdit,\n} from \"../roundtrip/source-map.js\"\nimport { patchZipEntries } from \"../roundtrip/zip-patch.js\"\n\n/** 채우기 결과 */\nexport interface HwpxFillResult {\n /** 채워진 HWPX 바이너리 */\n buffer: ArrayBuffer\n /** 실제 채워진 필드 목록 */\n filled: FormField[]\n /** 매칭 실패한 라벨 */\n unmatched: string[]\n /** 비치명 경고 (입력 라벨 정규화 충돌 등) — 없으면 생략 */\n warnings?: string[]\n}\n\n/** 문단별 편집 원장 — 전략들이 의도를 누적하고 마지막에 splice로 변환 */\ninterface ParaEditLedger {\n /** 문단 전체 재작성 (우선 — 설정되면 ranges 무시, 나중 쓰기 우선) */\n fullText?: string\n /** 매칭 도메인(paraTText ?? para.text) 좌표의 부분 치환 (start===end는 삽입) */\n ranges: Array<{ start: number; end: number; replacement: string }>\n /** 이 문단 편집과 연결된 filled 레코드 인덱스 — splice 실패 시 회수 */\n filledIdx: number[]\n /** 이 문단 편집과 연결된 매칭 키 — splice 실패 시 unmatched 복원용 */\n matchKeys: string[]\n}\n\n/**\n * HWPX 원본을 직접 수정하여 서식 필드를 채움 — 스타일 100% 보존.\n *\n * @param hwpxBuffer 원본 HWPX 파일 버퍼\n * @param values 채울 값 맵 (라벨 → 값). 값이 배열이면 같은 라벨의 등장 순서대로\n * 하나씩 소진된다 — 2~30장 반복 양식·명부형 표(헤더+여러 데이터 행) 채우기용.\n * 문자열이면 기존처럼 모든 등장에 동일값.\n * @returns HwpxFillResult\n */\nexport async function fillHwpx(\n hwpxBuffer: ArrayBuffer,\n values: Record<string, FillInput>,\n /** 이 정규화 라벨의 셀은 어떤 키로도 채우지 않음 — require_unique 2차에서 거부된\n * 라벨 셀이 접두사 매칭으로 남의 값에 오염되는 것을 차단 (sfill-2) */\n blockedLabels?: Set<string>,\n): Promise<HwpxFillResult> {\n const u8 = new Uint8Array(hwpxBuffer)\n precheckZipSize(hwpxBuffer) // 파싱 경로와 같은 ZIP bomb 가드 — fill 은 parse 없이 직행할 수 있다\n const zip = await JSZip.loadAsync(hwpxBuffer)\n // v3.0과 동일한 글롭 — filler 매칭은 라벨 기반(국소적)이라 manifest 비등재\n // 섹션을 포함해도 안전하고, 빼면 그 섹션의 양식이 조용히 누락된다\n const sectionPaths = Object.keys(zip.files)\n .filter(name => /[Ss]ection\\d+\\.xml$/i.test(name))\n .sort()\n if (sectionPaths.length === 0) {\n throw new KordocError(\"HWPX에서 섹션 파일을 찾을 수 없습니다\")\n }\n\n const warnings: string[] = []\n const normalizedValues = normalizeValues(values, warnings)\n const cursor = new ValueCursor(normalizedValues)\n const matchedLabels = new Set<string>()\n /** splice 실패 회수를 위해 null 자리표시 허용 — 마지막에 filter */\n const filled: Array<FormField | null> = []\n /** splice 실패로 회수된 키 / 성공 적용된 키 — unmatched 복원 판단용 */\n const failedKeys = new Set<string>()\n const succeededKeys = new Set<string>()\n const replacements = new Map<string, Uint8Array>()\n const encoder = new TextEncoder()\n\n // ── 전략 F: 누름틀(CLICK_HERE) 우선 매칭 — 표준 서식(기안문 등) 지원 ──\n // 필드 name과 정규화 정확 일치한 키는 여기서 채워지고 라벨 매칭에서 제외된다\n // (누름틀은 서식 제작자의 명시적 계약이라 라벨 추정보다 우선).\n // 모든 섹션을 먼저 훑은 뒤에 키를 제거해야 섹션2+의 동명 누름틀이 굶지 않는다.\n const sectionXmls = new Map<string, string>()\n const fieldModified = new Set<string>()\n const fieldMatchedKeys = new Set<string>()\n for (const p of sectionPaths) {\n const xml = await zip.file(p)!.async(\"text\")\n const outcome = fillClickHereInXml(xml, cursor, blockedLabels)\n sectionXmls.set(p, outcome.xml ?? xml)\n if (outcome.xml !== null) fieldModified.add(p)\n for (const f of outcome.filled) filled.push(f)\n for (const k of outcome.matchedKeys) fieldMatchedKeys.add(k)\n }\n for (const k of fieldMatchedKeys) {\n matchedLabels.add(k)\n normalizedValues.delete(k)\n }\n\n for (let si = 0; si < sectionPaths.length; si++) {\n const xml = sectionXmls.get(sectionPaths[si])!\n const scan = scanSectionXml(xml, si)\n\n const ledger = new Map<ScanParagraph, ParaEditLedger>()\n const led = (p: ScanParagraph): ParaEditLedger => {\n let l = ledger.get(p)\n if (!l) ledger.set(p, (l = { ranges: [], filledIdx: [], matchKeys: [] }))\n return l\n }\n\n /** 매칭/치환 좌표 도메인 텍스트 — t-도메인 우선, 엔티티 포함 시 para.text */\n const matchText = (p: ScanParagraph): string => paraTText(p, xml) ?? p.text\n /** 라벨/값 판정용 셀 텍스트 — v3.0 extractCellText와 동일하게 글상자 제외,\n * 문단 경계 구분자 없이 연결 */\n const cellLabelText = (cell: ScanCell): string =>\n cell.paragraphs.filter(p => !p.inTextbox).map(p => matchText(p)).join(\"\")\n\n // 표 수집 — 문서 순서 DFS (중첩표 + 머리말 등 ctrl 내부 고아 표 포함)\n const allTables: ScanTable[] = []\n const collectTables = (tables: ScanTable[], depth: number): void => {\n if (depth > 16) return\n for (const t of tables) {\n allTables.push(t)\n for (const row of t.rows) {\n for (const cell of row) collectTables(cell.tables, depth + 1)\n }\n }\n }\n collectTables(scan.tables, 0)\n collectTables(scan.orphanTables, 0)\n\n // ── 전략 0: 인셀 패턴 (전략 1보다 먼저 — 어노테이션 보존 순서) ──\n const patternApplied = new Set<ScanCell>()\n for (const table of allTables) {\n for (const row of table.rows) {\n for (const cell of row) {\n for (const para of cell.paragraphs) {\n const text = matchText(para)\n const result = fillInCellPatterns(text, cursor, matchedLabels, blockedLabels)\n if (!result) continue\n const l = led(para)\n if (l.fullText !== undefined) continue\n // 최소 diff 범위만 치환 — 나머지 run 서식 보존\n const newT = result.text\n let s = 0\n while (s < text.length && s < newT.length && text[s] === newT[s]) s++\n let eo = text.length\n let en = newT.length\n while (eo > s && en > s && text[eo - 1] === newT[en - 1]) { eo--; en-- }\n l.ranges.push({ start: s, end: eo, replacement: newT.slice(s, en) })\n patternApplied.add(cell)\n for (const m of result.matches) {\n l.filledIdx.push(filled.length)\n l.matchKeys.push(m.key)\n filled.push({ label: m.label, value: m.value, row: -1, col: -1, key: m.key })\n }\n }\n }\n }\n }\n\n // ── 전략 1 + 2: 표 단위 인터리브 (v3.0 DOM 버전과 동일 순서) ──\n for (const table of allTables) {\n // 헤더+데이터 표(첫 행 전부 라벨 + 둘째 행 첫 셀이 라벨 아님)의 헤더 행은\n // 전략 1에서 제외 — 헤더 이웃 셀(\"품명\"→\"규격\") 오염 방지 (IR 경로 isHeaderDataTable과 동일 규칙)\n const skipHeaderRow = table.rows.length >= 2 && (() => {\n const first = table.rows[0]\n const allLabels = first.length > 0 && first.every(cell => {\n const t = cellLabelText(cell).trim()\n return t.length > 0 && t.length <= 20 && isLabelCell(t)\n })\n if (!allLabels) return false\n const d0 = table.rows[1][0]\n return d0 === undefined || !isLabelCell(cellLabelText(d0))\n })()\n\n // 전략 1: 인접 라벨-값 셀\n for (let rowIdx = skipHeaderRow ? 1 : 0; rowIdx < table.rows.length; rowIdx++) {\n const cells = table.rows[rowIdx]\n for (let colIdx = 0; colIdx < cells.length - 1; colIdx++) {\n const labelText = cellLabelText(cells[colIdx])\n if (!isLabelCell(labelText)) continue\n\n const valueCell = cells[colIdx + 1]\n if (isKeywordLabel(cellLabelText(valueCell))) continue\n\n const normalizedCellLabel = normalizeLabel(labelText)\n if (!normalizedCellLabel) continue\n if (blockedLabels?.has(normalizedCellLabel)) continue\n const matchKey = findMatchingKey(normalizedCellLabel, cursor)\n if (matchKey === undefined) continue\n\n if (patternApplied.has(valueCell)) {\n // 전략 0이 이미 어노테이션을 채움 — 값을 앞에 삽입 (어노테이션 보존)\n const target = valueCell.paragraphs.find(p => p.tRanges.length > 0) ?? valueCell.paragraphs[0]\n if (!target) continue\n const l = led(target)\n if (l.fullText !== undefined) continue\n const newValue = cursor.consume(matchKey)\n if (newValue === undefined) continue // 배열 값 소진 — 이후 등장은 채우지 않음\n l.ranges.push({ start: 0, end: 0, replacement: newValue + \" \" })\n l.filledIdx.push(filled.length)\n l.matchKeys.push(matchKey)\n matchedLabels.add(matchKey)\n filled.push({\n label: labelText.trim().replace(/[::]\\s*$/, \"\"),\n value: newValue,\n row: rowIdx,\n col: colIdx,\n key: matchKey,\n })\n } else {\n const paras = valueCell.paragraphs\n if (paras.length === 0) continue\n const newValue = cursor.consume(matchKey)\n if (newValue === undefined) continue // 배열 값 소진\n // 나중 쓰기 우선 (v3.0 replaceCellText와 동일) — 기존 원장 덮어쓰기\n const l0 = led(paras[0])\n l0.fullText = newValue\n l0.ranges = []\n l0.filledIdx.push(filled.length)\n l0.matchKeys.push(matchKey)\n for (let k = 1; k < paras.length; k++) {\n const lk = led(paras[k])\n lk.fullText = \"\"\n lk.ranges = []\n }\n matchedLabels.add(matchKey)\n filled.push({\n label: labelText.trim().replace(/[::]\\s*$/, \"\"),\n value: newValue,\n row: rowIdx,\n col: colIdx,\n key: matchKey,\n })\n }\n }\n }\n\n // 전략 2: 헤더+데이터 행 (첫 행이 전부 라벨이면)\n if (table.rows.length >= 2) {\n const headerCells = table.rows[0]\n const allLabels = headerCells.length > 0 && headerCells.every(cell => {\n const t = cellLabelText(cell).trim()\n return t.length > 0 && t.length <= 20 && isLabelCell(t)\n })\n if (allLabels) {\n for (let rowIdx = 1; rowIdx < table.rows.length; rowIdx++) {\n const dataCells = table.rows[rowIdx]\n for (let colIdx = 0; colIdx < Math.min(headerCells.length, dataCells.length); colIdx++) {\n const headerLabel = normalizeLabel(cellLabelText(headerCells[colIdx]))\n if (blockedLabels?.has(headerLabel)) continue\n const matchKey = findMatchingKey(headerLabel, cursor)\n if (matchKey === undefined) continue\n // 스칼라: 첫 데이터 행만(기존 동작). 배열: 행마다 다음 값 소진(명부형 표)\n if (!cursor.isArray(matchKey) && matchedLabels.has(matchKey)) continue\n\n const dataCell = dataCells[colIdx]\n if (patternApplied.has(dataCell)) {\n // 전략 0이 이미 인셀 패턴을 채움 — fullText로 폐기하지 않고 값을 앞에 삽입\n // (전략 1의 patternApplied 분기와 동일 계약: filled 기록·소비값 보존)\n const target = dataCell.paragraphs.find(p => p.tRanges.length > 0) ?? dataCell.paragraphs[0]\n if (!target) continue\n const l = led(target)\n if (l.fullText !== undefined) continue\n const newValue = cursor.consume(matchKey)\n if (newValue === undefined) continue // 배열 값 소진\n l.ranges.push({ start: 0, end: 0, replacement: newValue + \" \" })\n l.filledIdx.push(filled.length)\n l.matchKeys.push(matchKey)\n matchedLabels.add(matchKey)\n filled.push({\n label: cellLabelText(headerCells[colIdx]).trim(),\n value: newValue,\n row: rowIdx,\n col: colIdx,\n key: matchKey,\n })\n continue\n }\n\n const newValue = cursor.consume(matchKey)\n if (newValue === undefined) continue // 배열 값 소진\n\n const paras = dataCell.paragraphs\n if (paras.length === 0) continue\n // 나중 쓰기 우선 (v3.0과 동일)\n const l0 = led(paras[0])\n l0.fullText = newValue\n l0.ranges = []\n l0.filledIdx.push(filled.length)\n l0.matchKeys.push(matchKey)\n for (let k = 1; k < paras.length; k++) {\n const lk = led(paras[k])\n lk.fullText = \"\"\n lk.ranges = []\n }\n matchedLabels.add(matchKey)\n filled.push({\n label: cellLabelText(headerCells[colIdx]).trim(),\n value: newValue,\n row: rowIdx,\n col: colIdx,\n key: matchKey,\n })\n }\n }\n }\n }\n }\n\n // ── 전략 3: 인라인 \"라벨: 값\" (표 밖 본문/글상자 + 머리말·꼬리말 등) ──\n // 세그먼트 단위 분해 — 한 문단 다중 라벨(\"성명: 작성일자: \") 지원.\n // 좌표는 전부 원본 도메인이라 문단당 여러 range를 안전하게 누적할 수 있다\n // (겹침은 원장 변환 단계에서 앞선 전략 우선으로 제거).\n for (const para of [...scan.bodyParagraphs, ...scan.excludedParagraphs]) {\n const existing = ledger.get(para)\n if (existing?.fullText !== undefined) continue\n const text = matchText(para)\n // 확장 라벨(\"신청인 성명\") 정확 매칭 우선 — \"성명\" 붕괴 방지 (blockedLabels 포함 판정).\n // 매칭을 선계산해 다음 세그먼트가 확장 매칭이면 이전 값 끝을 그 어절 앞으로 당긴다.\n const segments = scanInlineSegments(text)\n const matches = segments.map(seg => matchInlineSegment(seg, cursor, blockedLabels))\n for (let i = 0; i < segments.length; i++) {\n const seg = segments[i]\n const matched = matches[i]\n if (matched === undefined) continue\n const matchKey = matched.key\n const newValue = cursor.consume(matchKey)\n if (newValue === undefined) continue // 배열 값 소진\n const ve = clampSegmentEnd(text, seg, segments[i + 1], matches[i + 1]?.viaExt ?? false)\n // 빈 자리 삽입은 콜론·다음 라벨과 붙지 않게 공백 부착\n const replacement = seg.valueStart === ve\n ? padInsertion(text, seg.valueStart, newValue)\n : newValue\n const l = led(para)\n l.ranges.push({ start: seg.valueStart, end: ve, replacement })\n matchedLabels.add(matchKey)\n l.filledIdx.push(filled.length)\n l.matchKeys.push(matchKey)\n filled.push({ label: matched.label.trim(), value: newValue, row: -1, col: -1, key: matchKey })\n }\n }\n\n // ── 원장 → splice 변환 ──\n const splices: SpliceEdit[] = []\n for (const [para, l] of ledger) {\n let paraSplices: SpliceEdit[] | null = null\n\n if (l.fullText !== undefined) {\n paraSplices = buildParagraphSplices(para, l.fullText, xml)\n } else if (l.ranges.length > 0) {\n // 겹침 제거 (앞선 전략 우선)\n const sorted = [...l.ranges].sort((a, b) => a.start - b.start || a.end - b.end)\n const merged: typeof sorted = []\n for (const r of sorted) {\n const prev = merged[merged.length - 1]\n if (prev && r.start < prev.end) continue\n merged.push(r)\n }\n if (paraTText(para, xml) !== null) {\n // t-도메인 정밀 치환 — tab/br 요소를 건드리지 않고 run 서식 보존\n const precise: SpliceEdit[] = []\n let ok = true\n for (const r of merged) {\n const sp = buildRangeSplices(para, xml, r.start, r.end, r.replacement)\n if (!sp) { ok = false; break }\n precise.push(...sp)\n }\n paraSplices = ok ? precise : null\n } else if (paraTextPureT(para, xml)) {\n // 엔티티 포함 문단 — para.text 좌표로 기록했으므로 문자열 적용 후\n // 전체 재작성 폴백 (tab/br 등 비-t 기여가 없을 때만 안전)\n let text = para.text\n for (let k = merged.length - 1; k >= 0; k--) {\n const r = merged[k]\n text = text.slice(0, r.start) + r.replacement + text.slice(r.end)\n }\n paraSplices = buildParagraphSplices(para, text, xml)\n } else {\n // 엔티티 + tab/br 동시 포함 — 안전한 치환 경로 없음, 채우기 포기\n paraSplices = null\n }\n }\n\n if (paraSplices === null) {\n // 적용할 수 없는 문단 — filled 레코드와 매칭 키를 회수해 unmatched로 복원\n for (const idx of l.filledIdx) filled[idx] = null\n for (const k of l.matchKeys) failedKeys.add(k)\n continue\n }\n for (const k of l.matchKeys) succeededKeys.add(k)\n splices.push(...paraSplices)\n }\n\n if (splices.length > 0 || fieldModified.has(sectionPaths[si])) {\n // 텍스트가 바뀐 섹션(누름틀 채움 포함)은 줄 레이아웃 캐시(linesegarray)를 전부\n // 비워 한컴 변조 경고·구버전 줄배치 렌더를 막는다 (patchHwpx와 동일 — 뷰어가 열 때 재계산)\n splices.push(...allLinesegRemovalSplices(xml))\n replacements.set(sectionPaths[si], encoder.encode(applySplices(xml, splices)))\n }\n }\n\n // splice 실패로만 쓰인 키는 unmatched로 복원 (다른 곳에 성공 적용됐으면 유지).\n // 배열 값은 실패분의 커서가 이미 전진해 그 값이 무음 소실되므로,\n // 부분 성공이어도 unmatched로 보고해 호출자가 유실을 알 수 있게 한다.\n for (const k of failedKeys) {\n if (!succeededKeys.has(k) || cursor.isArray(k)) matchedLabels.delete(k)\n }\n\n const cleanFilled = filled.filter((f): f is FormField => f !== null)\n const unmatched = resolveUnmatched(normalizedValues, matchedLabels, values)\n const out = replacements.size > 0 ? patchZipEntries(u8, replacements) : new Uint8Array(u8)\n return {\n buffer: out.buffer.slice(out.byteOffset, out.byteOffset + out.byteLength) as ArrayBuffer,\n filled: cleanFilled,\n unmatched,\n ...(warnings.length > 0 ? { warnings } : {}),\n }\n}\n","/**\n * 누름틀(CLICK_HERE fieldBegin) 인식·채우기 — 정부 표준 서식(기안문) 지원\n *\n * HWPX의 누름틀은 `<hp:ctrl><hp:fieldBegin type=\"CLICK_HERE\" name=\"…\">…</hp:fieldBegin>\n * </hp:ctrl>` 과 `<hp:ctrl><hp:fieldEnd beginIDRef=\"…\"/></hp:ctrl>` 쌍으로 표시되고,\n * 실제 값은 두 ctrl **사이의** run 콘텐츠다. 안내문(placeholder)은 fieldBegin의\n * Clickhere Command 파라미터에만 있고 본문 텍스트가 아니므로, 채우기는 안내문과\n * 값을 비교하지 않고 무조건 사이 영역을 값으로 치환한다 — 값이 안내문과 동일해도\n * 침묵 유실이 없다 (rhwp 코어 결함 #3380 교훈).\n *\n * 치환은 filler-hwpx와 같은 철학의 원본 XML splice — fieldEnd·안내문 파라미터·둘러싼\n * run(charPr)을 1바이트도 건드리지 않고 사이 영역만 바꾼다. 값을 넣으면 fieldBegin 의 수정\n * 표시(dirty)만 \"1\" 로 켠다 — 미수정(dirty=0) 필드의 값이 안내문과 같으면 한컴은 화면에만 흐리게\n * 보이고 인쇄하지 않으며 kordoc 파서도 그렇게 읽는다(v4.14.3). 한컴이 직접 채운 필드도 dirty=1.\n */\n\nimport JSZip from \"jszip\"\nimport { escapeXmlText, decodeXmlEntities } from \"../roundtrip/source-map.js\"\nimport { applySplices, type SpliceEdit } from \"../roundtrip/source-map.js\"\nimport { normalizeLabel, type ValueCursor } from \"./match.js\"\nimport type { FormField } from \"../types.js\"\nimport { precheckZipSize } from \"../utils.js\"\n\n/** 문서에서 발견한 누름틀 필드 */\nexport interface ClickHereField {\n /** 누름틀 이름 (fieldBegin name 속성) */\n name: string\n /** 안내문 — 필드가 비어 있을 때 한글이 표시하는 문구 (Clickhere Direction 파라미터) */\n placeholder?: string\n /** begin~end 사이 현재 텍스트 — 빈 서식이면 \"\" (안내문은 값이 아니다) */\n value: string\n /** 0-based 섹션 번호 */\n section: number\n}\n\n/** 스캔된 누름틀 영역 — start/end는 값이 들어가는 사이 영역의 원본 XML 오프셋 */\ninterface ClickHereRegion {\n name: string\n placeholder?: string\n /** 값 영역 시작 (fieldBegin ctrl 닫힘 직후) */\n start: number\n /** 값 영역 끝 (fieldEnd ctrl 열림 직전) */\n end: number\n /** 태그 네임스페이스 접두사 (예: \"hp:\") — 삽입 요소도 같은 접두사 사용 */\n prefix: string\n /** fieldBegin 여는 태그 범위 — 값을 넣을 때 수정 표시(dirty)만 켠다 */\n beginTagStart: number\n beginTagEnd: number\n}\n\nconst FIELD_BEGIN_RE = /<([A-Za-z0-9_]+:)?fieldBegin\\b([^>]*?)(\\/?)>/g\n\nfunction attrOf(attrs: string, name: string): string | undefined {\n const m = attrs.match(new RegExp(`(?:^|\\\\s)${name}=\"([^\"]*)\"`))\n return m ? m[1] : undefined\n}\n\n/** Clickhere Command 파라미터에서 안내문 추출 — `Direction:wstring:<N>:` 뒤 N자(UTF-16) */\nfunction extractPlaceholder(fieldBeginXml: string): string | undefined {\n const m = fieldBeginXml.match(/Direction:wstring:(\\d+):/)\n if (!m) return undefined\n const start = (m.index ?? 0) + m[0].length\n const n = parseInt(m[1], 10)\n if (!Number.isFinite(n) || n < 0 || n > 1000) return undefined\n return decodeXmlEntities(fieldBeginXml.slice(start, start + n))\n}\n\n/** 사이 영역의 표시 텍스트 — 태그 제거, lineBreak/br→\\n, tab→\\t */\nfunction regionText(inner: string): string {\n return decodeXmlEntities(\n inner\n .replace(/<(?:[A-Za-z0-9_]+:)?(?:lineBreak|br)\\b[^>]*\\/?>/g, \"\\n\")\n .replace(/<(?:[A-Za-z0-9_]+:)?tab\\b[^>]*\\/?>/g, \"\\t\")\n .replace(/<[^>]+>/g, \"\"),\n )\n}\n\n/**\n * 섹션 XML에서 CLICK_HERE 누름틀 영역을 문서 순서로 스캔.\n * 겹치는(중첩된) 영역은 뒤엣것을 버려 splice 충돌을 막는다.\n */\nexport function scanClickHereRegions(xml: string): ClickHereRegion[] {\n const regions: ClickHereRegion[] = []\n FIELD_BEGIN_RE.lastIndex = 0\n let m: RegExpExecArray | null\n let lastEnd = -1\n while ((m = FIELD_BEGIN_RE.exec(xml)) !== null) {\n const prefix = m[1] ?? \"\"\n const attrs = m[2]\n const selfClosed = m[3] === \"/\"\n if ((attrOf(attrs, \"type\") ?? \"\").toUpperCase() !== \"CLICK_HERE\") continue\n const name = attrOf(attrs, \"name\")\n if (name === undefined) continue\n const id = attrOf(attrs, \"id\")\n\n // fieldBegin 요소 끝 찾기 (파라미터 자식 포함)\n let beginElemEnd: number\n if (selfClosed) {\n beginElemEnd = FIELD_BEGIN_RE.lastIndex\n } else {\n const closeTag = `</${prefix}fieldBegin>`\n const ci = xml.indexOf(closeTag, FIELD_BEGIN_RE.lastIndex)\n if (ci < 0) continue\n beginElemEnd = ci + closeTag.length\n }\n const fieldBeginXml = xml.slice(m.index, beginElemEnd)\n\n // fieldBegin을 감싼 ctrl 닫힘 직후가 값 영역 시작 (ctrl 없는 비표준 배치도 허용)\n const ctrlClose = `</${prefix}ctrl>`\n let start = beginElemEnd\n let wrapped = false\n if (xml.startsWith(ctrlClose, beginElemEnd)) {\n start = beginElemEnd + ctrlClose.length\n wrapped = true\n }\n\n // 짝 fieldEnd 찾기 — id가 있으면 beginIDRef 일치 우선, 없으면 다음 fieldEnd\n const feRe = new RegExp(`<${prefix}fieldEnd\\\\b[^>]*>`, \"g\")\n feRe.lastIndex = start\n let end = -1\n let fe: RegExpExecArray | null\n while ((fe = feRe.exec(xml)) !== null) {\n const ref = attrOf(fe[0], \"beginIDRef\")\n if (id !== undefined && ref !== undefined && ref !== id) continue\n end = fe.index\n break\n }\n if (end < 0) continue\n\n // fieldEnd를 감싼 ctrl 열림까지 영역에 포함 (fieldBegin과 대칭)\n const ctrlOpen = `<${prefix}ctrl>`\n if (wrapped && xml.slice(end - ctrlOpen.length, end) === ctrlOpen) {\n end -= ctrlOpen.length\n }\n\n if (start > end) continue\n if (start < lastEnd) continue // 중첩/역전 — 앞선 영역 우선\n lastEnd = end\n regions.push({\n name: decodeXmlEntities(name),\n placeholder: extractPlaceholder(fieldBeginXml),\n start,\n end,\n prefix,\n beginTagStart: m.index,\n beginTagEnd: m.index + m[0].length,\n })\n }\n return regions\n}\n\n/** 채울 값의 XML 조각 — \\n은 문단 내 강제 줄바꿈(lineBreak)으로 (rhwp fill-fields 동일 계약) */\nfunction valueXml(value: string, prefix: string): string {\n if (value === \"\") return \"\"\n const lines = value.split(\"\\n\").map(escapeXmlText)\n return `<${prefix}t>${lines.join(`<${prefix}lineBreak/>`)}</${prefix}t>`\n}\n\n/** fillClickHereInXml 결과 */\nexport interface ClickHereFillOutcome {\n /** 치환 적용된 XML — 변경 없으면 null */\n xml: string | null\n /** 채운 필드 기록 (filler-hwpx filled와 동일 형태) */\n filled: FormField[]\n /** 매칭된 정규화 키 — 이후 라벨 매칭에서 제외할 대상 */\n matchedKeys: Set<string>\n}\n\n/**\n * 섹션 XML의 누름틀을 값으로 채움 — 누름틀 name(정규화)과 정확히 일치하는 키만.\n * 접두사 매칭은 하지 않는다: 누름틀 이름은 서식 제작자가 정한 명시적 계약이라\n * 근사 매칭이 오히려 오폭이다.\n */\nexport function fillClickHereInXml(\n xml: string,\n cursor: ValueCursor,\n blockedLabels?: Set<string>,\n): ClickHereFillOutcome {\n const filled: FormField[] = []\n const matchedKeys = new Set<string>()\n const splices: SpliceEdit[] = []\n\n for (const region of scanClickHereRegions(xml)) {\n const key = normalizeLabel(region.name)\n if (!key || blockedLabels?.has(key)) continue\n if (!cursor.has(key)) continue\n const value = cursor.consume(key)\n if (value === undefined) continue // 배열 값 소진 — 이후 등장은 채우지 않음\n\n const replacement = valueXml(value, region.prefix)\n const current = xml.slice(region.start, region.end)\n matchedKeys.add(key)\n filled.push({ label: region.name, value, row: -1, col: -1, key, source: \"clickhere\" })\n // 값을 넣은 필드는 수정됨 — 빈 값은 안내문 노출 그대로(미수정 유지)\n if (value !== \"\") {\n const tag = xml.slice(region.beginTagStart, region.beginTagEnd)\n if (attrOf(tag, \"dirty\") !== \"1\") {\n const dirtyTag = /\\sdirty=\"[^\"]*\"/.test(tag)\n ? tag.replace(/(\\sdirty=\")[^\"]*\"/, (_, head: string) => head + '1\"')\n : tag.replace(/(\\/?>)$/, ' dirty=\"1\"$1')\n splices.push({ start: region.beginTagStart, end: region.beginTagEnd, replacement: dirtyTag })\n }\n }\n if (current === replacement) continue // 이미 같은 내용 — 바이트 보존\n splices.push({ start: region.start, end: region.end, replacement })\n }\n\n return {\n xml: splices.length > 0 ? applySplices(xml, splices) : null,\n filled,\n matchedKeys,\n }\n}\n\n/**\n * HWPX의 CLICK_HERE 누름틀 필드 목록 — 이름·안내문·현재값을 문서 순서로 반환.\n * 표준 서식(기안문 등)이 요구하는 필드를 채우기 전에 조사하는 용도.\n */\nexport async function extractClickHereFields(hwpxBuffer: ArrayBuffer): Promise<ClickHereField[]> {\n precheckZipSize(hwpxBuffer) // 파싱 경로와 같은 ZIP bomb 가드\n const zip = await JSZip.loadAsync(hwpxBuffer)\n const sectionPaths = Object.keys(zip.files)\n .filter(name => /[Ss]ection\\d+\\.xml$/i.test(name))\n .sort()\n const fields: ClickHereField[] = []\n for (let si = 0; si < sectionPaths.length; si++) {\n const xml = await zip.file(sectionPaths[si])!.async(\"text\")\n for (const r of scanClickHereRegions(xml)) {\n fields.push({\n name: r.name,\n ...(r.placeholder !== undefined ? { placeholder: r.placeholder } : {}),\n value: regionText(xml.slice(r.start, r.end)),\n section: si,\n })\n }\n }\n return fields\n}\n","/**\n * 표 분류기 (#76) — IRTable 이 \"데이터 표\"인지 \"표를 레이아웃 캔버스로 쓴 것\"(조직도·비상연락망·체계도)인지 휴리스틱 판정.\n *\n * 신호는 두 축. 의미 신호: 반복 행 스키마·격자 규칙성·활성 밀도·열 타입 일관성. 비표 신호: 병합 불규칙·빈 띠(행/열)·\n * 극단적 희소·중첩 구조 래퍼. 도표 문맥 키워드(조직도 등)는 구조 증거가 있을 때만 가산한다 — \"조직도\" 한 단어가 정상 표를\n * 도표로 바꾸면 안 된다. LLM·네트워크 없음. confidence 는 확률이 아니라 두 점수의 격차.\n */\n\nimport type { IRBlock, IRCell, IRTable, TableClassificationReason, TableClassificationSummary } from \"../types.js\"\n\nexport interface ClassifyContext {\n /** 표 앞뒤 문단·캡션 텍스트 — 도표 문맥 키워드 판정용 */\n nearbyText?: string[]\n}\n\n/** 도표 문맥 키워드 — 구조 증거(nonTabular ≥ KEYWORD_GATE)가 있을 때만 가산 */\nconst DIAGRAM_KEYWORDS = /조직도|비상\\s*연락망|연락망|체계도|업무\\s*체계도|기구표|배치도|흐름도|추진\\s*체계/u\nconst KEYWORD_GATE = 0.3\n\ntype CellType = \"empty\" | \"number\" | \"date\" | \"short\" | \"long\"\n\nfunction cellType(cell: IRCell): CellType {\n const t = cell.text.trim()\n if (!t && !cell.blocks?.length) return \"empty\"\n if (!t) return \"short\"\n if (/^[-+]?[\\d,]+(\\.\\d+)?\\s*(%|원|명|건|개|천원|백만원|㎡|㎢|kg|km|시간|일)?$/u.test(t)) return \"number\"\n if (/^\\d{2,4}[.\\-/년]\\s*\\d{1,2}[.\\-/월]?(\\s*\\d{1,2}[.일]?)?\\.?$/u.test(t)) return \"date\"\n return [...t].length <= 12 ? \"short\" : \"long\"\n}\n\ninterface Anchor { r: number; c: number; cell: IRCell; type: CellType }\n\n/** 병합 커버 칸을 제외한 앵커 셀 목록 */\nfunction anchors(table: IRTable): Anchor[] {\n const out: Anchor[] = []\n const covered = new Set<string>()\n for (let r = 0; r < table.rows; r++) {\n for (let c = 0; c < table.cols; c++) {\n if (covered.has(`${r},${c}`)) continue\n const cell = table.cells[r]?.[c]\n if (!cell) continue\n for (let dr = 0; dr < cell.rowSpan; dr++) for (let dc = 0; dc < cell.colSpan; dc++) if (dr || dc) covered.add(`${r + dr},${c + dc}`)\n out.push({ r, c, cell, type: cellType(cell) })\n }\n }\n return out\n}\n\nfunction isWrapper(table: IRTable): boolean {\n if (table.rows !== 1 || table.cols !== 1) return false\n const cell = table.cells[0]?.[0]\n return !!cell?.blocks?.some(b => b.type === \"table\" && b.table)\n}\n\nfunction round2(v: number): number { return Math.round(v * 100) / 100 }\n\nexport function classifyTable(table: IRTable, ctx: ClassifyContext = {}): TableClassificationSummary {\n const reasons: TableClassificationReason[] = []\n const done = (kind: TableClassificationSummary[\"kind\"], semantic: number, nonTabular: number): TableClassificationSummary =>\n ({ kind, confidence: round2(Math.min(1, Math.abs(semantic - nonTabular))), semanticScore: round2(semantic), nonTabularScore: round2(nonTabular), reasons })\n\n // 1×1 래퍼(중첩표 포함) — 구조 래퍼 관행 유지. 평문 1×1 은 근거 부족 → uncertain\n if (isWrapper(table)) { reasons.push(\"nested-structure-wrapper\"); return done(\"non-tabular-layout\", 0.05, 0.85) }\n const slots = table.rows * table.cols\n const A = anchors(table)\n if (slots <= 4 || A.length <= 2) { reasons.push(\"low-evidence\"); return done(\"uncertain\", 0.2, 0.2) }\n\n // ── 신호 ──\n const activeSlots = A.filter(a => a.type !== \"empty\").reduce((s, a) => s + a.cell.colSpan * a.cell.rowSpan, 0)\n const activeRatio = activeSlots / slots\n const rowHasContent = Array.from({ length: table.rows }, () => false), colHasContent = Array.from({ length: table.cols }, () => false)\n for (const a of A) if (a.type !== \"empty\") { for (let dr = 0; dr < a.cell.rowSpan; dr++) rowHasContent[a.r + dr] = true; for (let dc = 0; dc < a.cell.colSpan; dc++) colHasContent[a.c + dc] = true }\n const spacerRows = rowHasContent.filter(x => !x).length, spacerCols = colHasContent.filter(x => !x).length\n const spacerBands = (spacerRows + spacerCols) / (table.rows + table.cols)\n // 병합 불규칙 — 헤더 행(0)의 가로 병합은 정상 관행이라 제외. 본문 앵커 중 병합 셀 비율 + 행별 앵커 수 편차\n const body = A.filter(a => a.r > 0)\n const bodyMerged = body.filter(a => a.cell.colSpan > 1 || a.cell.rowSpan > 1).length\n const anchorsPerRow = new Map<number, number>()\n for (const a of A) anchorsPerRow.set(a.r, (anchorsPerRow.get(a.r) ?? 0) + 1)\n const counts = [...anchorsPerRow.values()]\n const meanCnt = counts.reduce((s, v) => s + v, 0) / Math.max(1, counts.length)\n const rowVariance = counts.length > 1 ? counts.reduce((s, v) => s + Math.abs(v - meanCnt), 0) / counts.length / Math.max(1, meanCnt) : 0\n const spanIrregularity = Math.min(1, (body.length ? bodyMerged / body.length : 0) * 0.7 + Math.min(1, rowVariance) * 0.6)\n // 격자 규칙성 — 1×1 앵커 비율(헤더 가로 병합 허용)\n const gridRegularity = A.length ? A.filter(a => (a.cell.colSpan === 1 && a.cell.rowSpan === 1) || (a.r === 0 && a.cell.rowSpan === 1)).length / A.length : 0\n // 반복 행 스키마 — 내용이 있는 본문 행(1..) 의 \"채워진 칸 위치+타입\" 서명 최빈 비율 (3행 미만은 0).\n // 빈 행끼리는 서명이 같아 보이므로 제외 — 조직도의 빈 띠가 반복 스키마로 잡히지 않게\n let repeatedRowSchema = 0\n if (table.rows >= 3) {\n const sigs = new Map<string, number>()\n let n = 0\n for (let r = 1; r < table.rows; r++) {\n const rowA = A.filter(a => a.r === r && a.type !== \"empty\")\n if (!rowA.length) continue\n const sig = rowA.map(a => `${a.c}:${a.type === \"long\" ? \"short\" : a.type}`).join(\"|\")\n sigs.set(sig, (sigs.get(sig) ?? 0) + 1); n++\n }\n repeatedRowSchema = n ? Math.max(...sigs.values()) / n : 0\n if (n < 2) repeatedRowSchema *= 0.5\n }\n // 열 타입 일관성 — 열마다 본문 비어있지 않은 셀의 지배 타입 비율 평균\n let columnTypeConsistency = 0\n {\n const cols: number[] = []\n for (let c = 0; c < table.cols; c++) {\n const types = A.filter(a => a.r > 0 && a.c === c && a.cell.colSpan === 1 && a.type !== \"empty\").map(a => a.type)\n if (types.length < 2) continue\n const freq = new Map<string, number>()\n for (const t of types) freq.set(t, (freq.get(t) ?? 0) + 1)\n cols.push(Math.max(...freq.values()) / types.length)\n }\n columnTypeConsistency = cols.length ? cols.reduce((s, v) => s + v, 0) / cols.length : 0\n }\n const sparsity = Math.max(0, (0.6 - activeRatio) / 0.6) // 활성 60% 이상이면 0, 0% 면 1\n\n // ── 점수 ── 의미 점수는 빈 칸 비율·빈 띠·병합 불규칙으로 감쇠한다 — 규칙적 \"빈 격자\"가 데이터표로 읽히지 않게\n const emptyShare = 1 - activeRatio\n let semantic = (0.35 * repeatedRowSchema + 0.25 * gridRegularity + 0.2 * Math.min(1, activeRatio / 0.7) + 0.2 * columnTypeConsistency)\n * (1 - 0.6 * Math.max(0, emptyShare - 0.2) / 0.8) * (1 - spacerBands) * (1 - 0.5 * spanIrregularity)\n let nonTabular = 0.6 * spanIrregularity + 0.4 * spacerBands + 0.5 * sparsity\n // 중첩 구조 래퍼(셀 대부분이 중첩표) 는 비표 쪽\n const nestedCells = A.filter(a => a.cell.blocks?.some(b => b.type === \"table\" && b.table)).length\n if (nestedCells && nestedCells >= A.length * 0.5) { nonTabular += 0.25; reasons.push(\"nested-structure-wrapper\") }\n\n if (repeatedRowSchema >= 0.6) reasons.push(\"repeated-row-schema\")\n if (gridRegularity >= 0.9) reasons.push(\"grid-regularity\")\n if (activeRatio >= 0.7) reasons.push(\"high-active-density\")\n if (columnTypeConsistency >= 0.75) reasons.push(\"column-type-consistency\")\n if (spanIrregularity >= 0.35) reasons.push(\"span-irregularity\")\n if (spacerBands >= 0.25) reasons.push(\"spacer-bands\")\n if (sparsity >= 0.5) reasons.push(\"extreme-sparsity\")\n\n // 도표 키워드 — 구조 증거가 있을 때만 가산\n const text = [table.caption ?? \"\", ...(ctx.nearbyText ?? [])].join(\"\\n\")\n if (DIAGRAM_KEYWORDS.test(text) && nonTabular >= KEYWORD_GATE) { nonTabular += 0.15; reasons.push(\"diagram-context-keyword\") }\n\n semantic = Math.min(1, semantic); nonTabular = Math.min(1, nonTabular)\n if (semantic >= 0.55 && semantic - nonTabular >= 0.2) return done(\"semantic-table\", semantic, nonTabular)\n if (nonTabular >= 0.45 && nonTabular - semantic >= 0.15) return done(\"non-tabular-layout\", semantic, nonTabular)\n reasons.push(Math.max(semantic, nonTabular) < 0.35 ? \"low-evidence\" : \"ambiguous-scores\")\n return done(\"uncertain\", semantic, nonTabular)\n}\n\n/** 셀 안 블록에서 표 블록 재귀 수집 (문서 순서) — analyze·visual 이 공유 */\nexport function collectTableBlocks(blocks: IRBlock[], out: IRBlock[] = []): IRBlock[] {\n for (const b of blocks) {\n if (b.type === \"table\" && b.table) {\n out.push(b)\n for (const row of b.table.cells) for (const cell of row) if (cell.blocks) collectTableBlocks(cell.blocks, out)\n if (b.table.captionBlocks) collectTableBlocks(b.table.captionBlocks, out)\n }\n if (b.children) collectTableBlocks(b.children, out)\n }\n return out\n}\n","/**\n * 표 분류 배선 (#76 Task 3·5) — 파싱이 끝난 IRBlock 트리를 재귀하며 `IRTable.classification` 을 붙인다.\n * 원문 순서·셀 텍스트·캡션은 건드리지 않는다(메타만 추가). 기본 parse 는 이 함수를 부르지 않는다(opt-in).\n */\n\nimport type { IRBlock, IRTable } from \"../types.js\"\nimport { classifyTable } from \"./classifier.js\"\nimport { hasStructuredCellContent } from \"./builder.js\"\n\nfunction hasMerged(table: IRTable): boolean {\n return table.cells.some(row => row.some(c => c.colSpan > 1 || c.rowSpan > 1))\n}\n\n/** 앞뒤 문단 텍스트(도표 문맥) 를 모아 분류 — 형제 블록 기준 */\nfunction classifyInList(blocks: IRBlock[]): void {\n for (let i = 0; i < blocks.length; i++) {\n const b = blocks[i]\n if (b.type === \"table\" && b.table) {\n const near: string[] = []\n for (const j of [i - 2, i - 1, i + 1]) { const n = blocks[j]; if (n && n.type !== \"table\" && n.text) near.push(n.text) }\n b.table.classification = classifyTable(b.table, { nearbyText: near })\n // 재귀 — 셀 blocks·캡션 blocks. 부모 분류가 자식을 덮어쓰지 않는다\n for (const row of b.table.cells) for (const cell of row) if (cell.blocks) classifyInList(cell.blocks)\n if (b.table.captionBlocks) classifyInList(b.table.captionBlocks)\n }\n if (b.children) classifyInList(b.children)\n }\n}\n\n/** 트리 전체 분류(변경은 classification 필드 추가뿐). 같은 배열을 돌려준다 */\nexport function classifyTableTree(blocks: IRBlock[]): IRBlock[] {\n classifyInList(blocks)\n return blocks\n}\n\nexport type TableRepresentation = \"gfm\" | \"html\" | \"visual\"\n\n/**\n * 분류 인식 표현 정책 — `visual` 은 명시 요청(스마트 시각 출력)에서만 나온다. 기본 마크다운 경로는 이 함수를 쓰지 않는다.\n * 단순 의미표 → gfm(손실 없을 때) · 구조 셀/병합 → html · non-tabular(+smart) → visual · uncertain(+smart) → html(구조)+시각은 호출자\n */\nexport function chooseTableRepresentation(table: IRTable, opts: { smartVisual?: boolean } = {}): TableRepresentation {\n const structured = hasMerged(table) || hasStructuredCellContent(table)\n if (opts.smartVisual && table.classification?.kind === \"non-tabular-layout\") return \"visual\"\n return structured ? \"html\" : \"gfm\"\n}\n","/**\n * 페이지별 마크다운 사영 (#68)\n *\n * 문서를 다시 파싱하지 않고 이미 만들어진 `IRBlock.pageNumber` 로만 블록을 갈라\n * 페이지마다 `blocksToMarkdown()` 을 돌린다. 페이지 번호의 신뢰도는 파서가\n * 정하는 것이고(`metadata.pageMode` — \"layout\" 은 실제 페이지, \"section\" 은\n * 섹션 근사), 여기서는 그 값을 그대로 존중한다.\n */\n\nimport type { IRBlock, PageMarkdown } from \"./types.js\"\nimport { blocksToMarkdown } from \"./table/builder.js\"\n\n/**\n * 블록을 페이지 번호로 묶어 페이지별 마크다운을 만든다.\n *\n * - 어떤 블록에도 페이지 번호가 없으면 `undefined` — 페이지 개념이 없는 포맷에\n * \"전부 1페이지\" 같은 없는 사실을 만들어 내지 않는다.\n * - 번호가 없는 블록은 **직전 블록의 페이지로 이어붙인다.** 블록은 읽기 순서라\n * 이게 원문 위치에 가장 가깝고, 무엇보다 어느 페이지에도 안 실려 조용히\n * 사라지는 블록이 생기지 않는다. 선두의 번호 없는 블록은 첫 실번호 페이지로.\n * - 관측된 최소~최대 페이지 사이의 빈 페이지도 항목으로 낸다. 여러 페이지에\n * 걸친 표는 시작 페이지 한 블록이라 중간 페이지가 실제로 비어 있고, 이때\n * 항목을 빼면 소비자가 배열 길이로 페이지 수를 셀 수 없다.\n */\nexport function blocksToPages(blocks: IRBlock[]): PageMarkdown[] | undefined {\n const firstNumbered = blocks.find(b => typeof b.pageNumber === \"number\")?.pageNumber\n if (firstNumbered === undefined) return undefined\n\n const byPage = new Map<number, IRBlock[]>()\n let current = firstNumbered\n for (const block of blocks) {\n if (typeof block.pageNumber === \"number\") current = block.pageNumber\n const bucket = byPage.get(current)\n if (bucket) bucket.push(block)\n else byPage.set(current, [block])\n }\n\n const numbers = [...byPage.keys()]\n const min = Math.min(...numbers)\n const max = Math.max(...numbers)\n\n const pages: PageMarkdown[] = []\n for (let pageNumber = min; pageNumber <= max; pageNumber++) {\n const pageBlocks = byPage.get(pageNumber)\n pages.push({ pageNumber, markdown: pageBlocks ? blocksToMarkdown(pageBlocks) : \"\" })\n }\n return pages\n}\n","/**\n * Markdown → HWPX 역변환\n *\n * 지원: 헤딩(h1~h6), 단락, 볼드, 이탤릭, 인라인코드, 코드블록,\n * 순서/비순서 리스트, 수평선, 인용문, 테이블\n * jszip으로 HWPX ZIP 패키징.\n *\n * 엔트리(markdownToHwpx)와 재수출만 남김 — 구현은 목적별 모듈로 분리:\n * gen-ids.ts — NS/charPr/paraPr id 상수·테마 해석·XML 원자(escapeXml, charPr/paraPr)\n * md-runs.ts — 마크다운 블록/인라인 파싱 + run/문단 XML + PrvText\n * gen-header.ts — container/manifest/head.xml 생성\n * gen-gongmun-fit.ts — 공문 자동장평 계획 + 리스트 항목부호 선계산\n * gen-table.ts — GFM/HTML(병합) 표 XML\n * gen-table-bf.ts — 표 셀 위치별 borderFill 동적 레지스트리 (실측 테두리 위계)\n * gen-section.ts — secPr + 본문 section0.xml 조립\n * gen-profile.ts — 서식 프로필(#41) id 리맵·표 매칭\n */\n\nimport JSZip from \"jszip\"\nimport { type GongmunOptions, needsGaejosikAssets, resolveGongmun, usesReportFonts } from \"./gongmun.js\"\nimport { type HwpxTheme, resolveTheme, charVariantBase } from \"./gen-ids.js\"\nimport { buildPrvText, parseMarkdownToBlocks, beginInlineDoc, endInlineDoc, extractFootnoteDefs } from \"./md-runs.js\"\nimport { type PageOptions, resolvePage } from \"./gen-page.js\"\nimport { generateContainerXml, generateManifest, generateHeaderXml, staticBorderFillNext, staticFontNext } from \"./gen-header.js\"\nimport { computeGongmunFitPlan, precomputeGongmunList } from \"./gen-gongmun-fit.js\"\nimport { blocksToSectionXml, type ChartPart } from \"./gen-section.js\"\nimport { TableBfRegistry } from \"./gen-table-bf.js\"\nimport { buildProfileRemap, type FormatProfile } from \"./gen-profile.js\"\nimport { docframeActive, docframeCharPrXmls, docframeIds } from \"./gen-docframe.js\"\nimport { levelCharIds, levelFontFaces, levelCharPrXmls } from \"./gen-levels.js\"\nimport { ImageRegistry } from \"./gen-image.js\"\nimport { StyleRegistry } from \"./style-registry.js\"\nimport { buildGongmunSectionV5, usesV5Engine } from \"./gen-gongmun.js\"\nimport { polishGongmunBlock } from \"./gongmun-typo.js\"\n\nexport { type HwpxTheme } from \"./gen-ids.js\"\nexport {\n type FormatProfile, type TableProfile, type CellProfile,\n type BorderFillDef, type BorderDef, type CharPrDef,\n} from \"./gen-profile.js\"\n\n/** markdownToHwpx 옵션 */\nexport interface MarkdownToHwpxOptions {\n theme?: HwpxTheme\n /**\n * 공문서 모드 — 지정 시 한국 행정 공문서 표준 서식으로 렌더링한다.\n * (공식 여백, 프리셋별 본문 크기, 항목부호 체계, 행갈굼 정렬, 줄간격 등)\n * 미지정 시 기존 범용 마크다운 변환 동작 그대로 유지.\n */\n gongmun?: GongmunOptions\n /**\n * 서식 프로필 — 표의 borderFill(테두리·음영)·열 너비·셀 글꼴을 원본 문서 없이\n * 재현한다(이슈 #41). `hwpxToProfile()`로 추출하거나 직접 작성한 프로필을 넘기면,\n * 문서 내 표 등장 순서(table_index)로 매칭해 셀 좌표별 서식을 적용한다.\n * 미지정 시 기본 서식 — 공문서 모드는 실측 정부 표 문법, 그 외 단일 SOLID 테두리.\n */\n profile?: FormatProfile\n /**\n * 페이지 설정 (v4.5.0) — 용지 크기·가로 방향, 다단(columns), 머리말/꼬리말.\n * 미지정 시 기존과 동일한 A4 세로 1단.\n */\n page?: PageOptions\n /**\n * 이미지 실데이터 (v4.5.0) — ``의 url을 키로 바이트를 넘기면 BinData에\n * 실제로 임베드한다 (PNG/JPEG/GIF/BMP, 크기는 96dpi 환산·본문폭 캡). `data:image/...`\n * URI는 이 맵 없이도 임베드. 바이트가 없는 url은 종전 placeholder 참조 보존.\n */\n images?: Record<string, Uint8Array | ArrayBuffer>\n /**\n * 경고 수집 싱크 (v5) — 생성기가 조용히 처리한 것(□ 한 줄 축소 한계 초과·제목 축소 등)을\n * 여기에 push한다. 호출 표면(CLI stderr·MCP 응답)이 노출.\n */\n warnings?: string[]\n}\n\n\n/**\n * 마크다운 텍스트를 HWPX (ArrayBuffer)로 변환.\n */\nexport async function markdownToHwpx(\n markdown: string,\n options?: MarkdownToHwpxOptions,\n): Promise<ArrayBuffer> {\n const theme = resolveTheme(options?.theme)\n const gongmun = options?.gongmun ? resolveGongmun(options.gongmun) : null\n const page = resolvePage(options?.page)\n // 인라인 채널(하이퍼링크·각주, v4.5.0) — 각주 정의 걷어내고 문서 컨텍스트 오픈.\n // 섹션 조립이 끝나면 finally에서 닫는다 (모듈 상태 잔류 방지)\n const { md, defs } = extractFootnoteDefs(markdown)\n beginInlineDoc(defs)\n try {\n // ─── v5 엔진 (기안문·보고서·계획서·통지·회의록) — outline + scheme + StyleRegistry ───\n if (gongmun && usesV5Engine(gongmun.preset)) {\n const blocks = parseMarkdownToBlocks(md)\n const staticBfEnd = staticBorderFillNext(gongmun, true)\n const charBase = charVariantBase(false, true)\n const fontBase = staticFontNext(gongmun, true)\n const remap = options?.profile ? buildProfileRemap(options.profile, charBase, staticBfEnd, fontBase) : null\n const bfReg = new TableBfRegistry(staticBfEnd + (remap?.borderFillXmls.length ?? 0))\n const reg = new StyleRegistry(charBase + (remap?.charPrXmls.length ?? 0), 8, fontBase + (remap?.fontFaces.length ?? 0), [\"함초롬바탕\", \"함초롬돋움\", \"HY견고딕\"])\n const chartParts: ChartPart[] = []\n const supplied = options?.images\n ? new Map(Object.entries(options.images).map(([k, v]) => [k, v instanceof Uint8Array ? v : new Uint8Array(v)] as const))\n : undefined\n const images = new ImageRegistry(supplied)\n const res = buildGongmunSectionV5(blocks, gongmun, { reg, bfReg, remap, images, page, chartParts }, theme)\n if (options?.warnings) options.warnings.push(...res.warnings)\n if (remap && remap.tables.length > 0 && remap.tables.every(t => !t.used)) {\n // eslint-disable-next-line no-console\n console.warn(`[kordoc] format profile: 프로필 표 ${remap.tables.length}개가 문서 표와 매칭되지 않아 미적용 (행·열/첫 셀 텍스트 불일치)`)\n }\n const zip = new JSZip()\n zip.file(\"mimetype\", \"application/hwp+zip\", { compression: \"STORE\" })\n zip.file(\"META-INF/container.xml\", generateContainerXml())\n zip.file(\"Contents/content.hpf\", generateManifest(chartParts, images.manifestItems(), \"gongmun\"))\n for (const part of images.parts) zip.file(part.name, part.data)\n zip.file(\"Contents/header.xml\", generateHeaderXml(theme, gongmun, [],\n [...(remap?.borderFillXmls ?? []), ...bfReg.emit()],\n [...(remap?.charPrXmls ?? []), ...reg.charPrXmls],\n [], [...(remap?.fontFaces ?? []), ...reg.extraFonts],\n { paraPrXmls: reg.paraPrXmls, bodyFace: \"함초롬바탕\" }))\n zip.file(\"Contents/section0.xml\", res.xml)\n for (const part of chartParts) zip.file(part.name, part.xml)\n zip.file(\"Preview/PrvText.txt\", buildPrvText(blocks))\n return await zip.generateAsync({ type: \"arraybuffer\" })\n }\n // 실측 폰트 프리셋(개조식·보고서·계획서) — 전용 charPr 블록(11~25)이 먼저 온다 (QA-1)\n const measured = !!gongmun && usesReportFonts(gongmun.preset)\n const richAssets = !!gongmun && needsGaejosikAssets(gongmun)\n // 공문서(개조식·보도자료)는 날짜·금액 묶음 빈칸과 ‘’“” 로 다듬는다 — v5 는 gen-gongmun 이 아웃라인에서 같은 처리\n const blocks = gongmun ? parseMarkdownToBlocks(md).map(polishGongmunBlock) : parseMarkdownToBlocks(md)\n const gongmunList = gongmun ? precomputeGongmunList(blocks, gongmun) : null\n const fit = gongmun && gongmunList ? computeGongmunFitPlan(blocks, gongmun, gongmunList) : null\n // id 배치: 정적 borderFill(기본 2 + 개조식 7 + 공문서 헤더음영 1) → 프로필 → 표 레지스트리.\n // charPr는 기본(+실측 프리셋 전용) + 장평 variant 다음부터 프로필 할당.\n // 정적 개수는 gen-header의 실제 방출 목록에서 파생 (P0-1 — 하드코딩 11/4/3 제거)\n const staticBfEnd = staticBorderFillNext(gongmun)\n const remap = options?.profile\n ? buildProfileRemap(options.profile, charVariantBase(richAssets, !!gongmun) + (fit?.variants?.length ?? 0) * 4, staticBfEnd, staticFontNext(gongmun))\n : null\n // 표 테두리 위계 레지스트리 — 섹션 생성 중 등록된 조합을 header.xml에 함께 방출\n const bfReg = gongmun ? new TableBfRegistry(staticBfEnd + (remap?.borderFillXmls.length ?? 0)) : null\n // docframe(두문·결문·보고정보·공고두문·보도머리) charPr — variant·프로필 다음 id.\n // 기능이 꺼져 있으면 미방출(기존 산출물 불변)\n const dfActive = !!gongmun && docframeActive(gongmun)\n const dfBase = charVariantBase(richAssets, !!gongmun) + (fit?.variants?.length ?? 0) * 4 + (remap?.charPrXmls.length ?? 0)\n const dfIds = dfActive ? docframeIds(dfBase) : null\n const dfXmls = dfActive ? docframeCharPrXmls(dfBase, richAssets) : []\n // 단계별 위계 타이포(levels, v4.12.3) — docframe charPr 뒤 id, 글꼴은 프로필 append 뒤 id.\n // 옵션이 없으면 미방출(기존 산출물 불변)\n const lvBase = dfBase + dfXmls.length\n const lvIds = gongmun ? levelCharIds(gongmun, lvBase) : null\n const lvFonts = gongmun ? levelFontFaces(gongmun) : []\n const lvXmls = gongmun ? levelCharPrXmls(gongmun, lvBase, staticFontNext(gongmun) + (remap?.fontFaces.length ?? 0), richAssets ? 4 : 0) : []\n const chartParts: ChartPart[] = []\n // 이미지 레지스트리 (v4.0.5 placeholder → v4.5.0 실데이터) — images 옵션 바이트·\n // data: URI는 실제 임베드, 그 외 참조는 1×1 placeholder로 왕복 보존\n const supplied = options?.images\n ? new Map(Object.entries(options.images).map(([k, v]) =>\n [k, v instanceof Uint8Array ? v : new Uint8Array(v)] as const))\n : undefined\n const images = new ImageRegistry(supplied)\n const sectionXml = blocksToSectionXml(blocks, theme, gongmun, gongmunList, fit, chartParts, bfReg, remap, dfIds, images, page, lvIds)\n\n // 프로필이 있었는데 한 표에도 못 붙었으면 진단 경고 — 매칭은 보수적(불일치=미적용)이라\n // 마크다운을 크게 고쳐 쓴 경우 전멸할 수 있는데, 그걸 조용히 삼키지 않는다. 1회만.\n if (remap && remap.tables.length > 0) {\n const unused = remap.tables.filter(t => !t.used).length\n if (unused === remap.tables.length) {\n // eslint-disable-next-line no-console\n console.warn(`[kordoc] format profile: 프로필 표 ${unused}개가 문서 표와 매칭되지 않아 미적용 (행·열/첫 셀 텍스트 불일치)`)\n }\n }\n\n // borderFill 방출 순서 = id 발급 순서 (정적 → 프로필 → 레지스트리)\n const extraBorderFills = [...(remap?.borderFillXmls ?? []), ...(bfReg?.emit() ?? [])]\n\n const zip = new JSZip()\n zip.file(\"mimetype\", \"application/hwp+zip\", { compression: \"STORE\" })\n zip.file(\"META-INF/container.xml\", generateContainerXml())\n zip.file(\"Contents/content.hpf\", generateManifest(chartParts, images.manifestItems(), gongmun ? \"gongmun\" : \"default\"))\n for (const part of images.parts) zip.file(part.name, part.data)\n zip.file(\"Contents/header.xml\", generateHeaderXml(theme, gongmun, fit?.variants ?? [], extraBorderFills,\n [...(remap?.charPrXmls ?? []), ...dfXmls, ...lvXmls],\n gongmunList?.indentVariants ?? [], [...(remap?.fontFaces ?? []), ...lvFonts]))\n zip.file(\"Contents/section0.xml\", sectionXml)\n for (const part of chartParts) zip.file(part.name, part.xml)\n // Preview/ — 한글 프로그램의 일부 버전(특히 macOS)이 존재 여부를 확인함\n zip.file(\"Preview/PrvText.txt\", buildPrvText(blocks))\n\n return await zip.generateAsync({ type: \"arraybuffer\" })\n } finally {\n endInlineDoc()\n }\n}\n","/**\n * HWPX 생성 지오메트리·단위 상수 SSOT (v4.0.5 P0-3).\n *\n * 종전에는 A4 크기·mm→HWPUNIT 환산·본문폭·표 id 베이스가 gaejosik/gongmun/\n * chart-gen/gen-section/gen-table 등에 3중 이상 중복 인코딩돼 있었다.\n * 여기 값을 바꾸면 시각 baseline(한컴 실렌더 해시) 재박제가 필요하다 — 신중히.\n */\n\n// ─── 용지 (A4 세로, HWPUNIT) ─────────────────────────\n// 210mm × 297mm. 1 HWPUNIT = 1/7200 inch → 1mm = 7200/25.4 ≈ 283.46 HU.\n\nexport const A4_W_HU = 59528\nexport const A4_H_HU = 84188\n\n/** 1mm당 HWPUNIT (7200/25.4 ≈ 283.4646) — 반올림 없는 원시 배율 */\nexport const HU_PER_MM = 7200 / 25.4\n\n/**\n * 1mm → HWPUNIT (정수 반올림).\n * 주의: 수식 형태(`(mm*7200)/25.4`)를 바꾸지 말 것 — `mm*HU_PER_MM`과 부동소수점\n * 결합 순서가 달라 경계값에서 반올림이 갈릴 수 있다 (기존 산출물 바이트 보존).\n */\nexport function mmToHwpunit(mm: number): number {\n return Math.round((mm * 7200) / 25.4)\n}\n\n// ─── 본문폭 ──────────────────────────────────────────\n\n/**\n * 여백 좌우 20mm A4 본문폭 = mmToHwpunit(170) = 48189 (계산값).\n * 실측 개조식 장식표 기하(gaejosik.ts CHAPTER_GEOM 등)의 기준 폭.\n */\nexport const BODY_WIDTH_20MM = mmToHwpunit(170)\n\n/**\n * 표지·본문 제목박스 실측 폭 48180 (실물 t2 「2_보고서 양식」 저장값).\n * 계산 본문폭(48189)보다 9HU 좁다 — 한컴이 저장 시 스냅한 실측값이므로\n * 계산값으로 \"정정\"하면 실물과 달라진다. 구분 보존이 의도다.\n */\nexport const COVER_MEASURED_W = 48180\n\n// ─── 표 id 네임스페이스 ──────────────────────────────\n// <hp:tbl id>는 문서 내 유일하면 되지만, 모듈별 카운터가 겹치지 않게 구간을 파티션.\n// 각 모듈은 blocksToSectionXml 시작 시 reset되는 자기 카운터로 base부터 발급한다.\n\n/** 데이터 표(GFM·HTML) — gen-table */\nexport const DATA_TABLE_ID_BASE = 1000\n/** 차트 개체 — chart-gen (base + blockIdx, 카운터 아님) */\nexport const CHART_TABLE_ID_BASE = 9_100_000\n/** 개조식 장식표(표지·목차·장헤더·제목박스) — gen-gaejosik */\nexport const GJ_TABLE_ID_BASE = 9_200_000\n/** 공문서 부속표(결재란·제목박스) — gen-gongmun-extra */\nexport const EXTRA_TABLE_ID_BASE = 9_300_000\n/** 이미지 placeholder <hp:pic> — gen-image */\nexport const PIC_ID_BASE = 9_400_000\n","/**\n * 개조식(정부 표준 개조식 보고서) 프리셋 — 순수 로직 + 실측 스타일 상수\n *\n * 근거: 실제 정부 보고서 양식 hwpx(「2_보고서 양식」)를 디코드해 실측한 값.\n * 부호: □ HY헤드라인M 16pt(문단 위 15) / ○ 휴먼명조 15pt(10) / - 휴먼명조 15pt(6)\n * / ※ 한양중고딕 13pt(3) ※ 문단 위 간격 저장값 = UI(pt) × 200\n * (소분류 부호만 양식 저장값 ―(U+2015) 대신 실무 관행 하이픈 - 채택 — GAEJOSIK_BULLETS 주석)\n * 장 헤더: 1×3 표 — 로마숫자 셀(흰 글자 17pt·#193AAA 음영·#006699 테두리) +\n * 간격 셀(#006699 좌선) + 제목 셀(HY헤드라인M 17pt·#F2F2F2 음영·회색 상하선)\n * 표지: 파랑 장식 바(#193AAA/#A0B4E6) 사이 제목 30pt, 날짜·기관명 25pt\n * 목차: \"목 차\" 28pt bold + 0.4mm #514BAC 테두리 박스(로마 21pt 한양신명조 bold)\n *\n * 이 모듈은 순수 값/로직만 담는다. XML 조립은 gen-gaejosik.ts.\n */\n\nimport { markerWidth } from \"./gongmun.js\"\nimport { BODY_WIDTH_20MM, COVER_MEASURED_W } from \"./geometry.js\"\n\n// ─── 부호 ───────────────────────────────────────────\n\n/**\n * 개조식 단계별 부호: □(대) ○(중) -(소, 하이픈) ㆍ(세) — 3단계 초과는 ㆍ 고정.\n * 소분류는 실무 관행이 하이픈이다 — GT3 양식 저장값은 ―(U+2015)지만 실무자 확인\n * (2026-07-11 QA) + 부처별 양식 3종 중 2종(업무보고·보고서3)이 하이픈으로 실측됨.\n * 양식 파일 하나의 저장값보다 실무 관행 우선.\n */\nconst GAEJOSIK_BULLETS = [\"□\", \"○\", \"-\", \"ㆍ\"]\n\nexport function gaejosikMarker(depth: number, bullet2: \"ㅇ\" | \"○\" = \"○\"): string {\n if (depth === 1) return bullet2\n return GAEJOSIK_BULLETS[Math.min(depth, GAEJOSIK_BULLETS.length - 1)]\n}\n\n// ─── 크기 체계 (본문 15pt 기준 실측값 → bodyHeight 비례 스케일) ──\n\n/** 요소별 글자 크기(pt) 오버라이드 — 미지정 요소는 bodyHeight 비례 기본값 */\nexport type GaejosikSizeOverrides = Partial<{\n dae: number; cham: number; chapter: number; coverTitle: number; coverSub: number\n tocLabel: number; tocRoman: number; tocItem: number; table: number; bodyTitle: number\n}>\n\n/** bodyHeight(=bodyPt×100) 기준 각 요소의 charPr height. 실측은 body 1500 기준. ov는 pt 절대값 우선 */\nexport function gaejosikSizes(bodyHeight: number, ov: GaejosikSizeOverrides = {}) {\n const s = bodyHeight / 1500\n const r = (v: number, pt?: number) => (pt ? Math.round(pt * 100) : Math.round(v * s))\n return {\n /** □ 대항목 — HY헤드라인M 16pt */\n dae: r(1600, ov.dae),\n /** ※ 참고 — 한양중고딕 13pt */\n cham: r(1300, ov.cham),\n /** 장 헤더(로마숫자·제목) 17pt */\n chapter: r(1700, ov.chapter),\n /** 표지 제목 30pt */\n coverTitle: r(3000, ov.coverTitle),\n /** 표지 날짜·기관명 25pt */\n coverSub: r(2500, ov.coverSub),\n /** 목차 라벨 \"목 차\" 28pt */\n tocLabel: r(2800, ov.tocLabel),\n /** 목차 로마숫자 21pt(한양신명조) */\n tocRoman: r(2100, ov.tocRoman),\n /** 목차 항목 18pt */\n tocItem: r(1800, ov.tocItem),\n /** 표 셀 — 맑은 고딕 12pt (실측: 정부 양식 표) */\n table: r(1200, ov.table),\n /** 표지 장식 바 셀 빈 문단 — 6pt (실측: 바 높이 818 안에 줄높이 수납) */\n bar: r(600),\n /** 본문 첫 페이지 제목 박스 — HY헤드라인M 22pt (실측: GT3 표④) */\n bodyTitle: r(2200, ov.bodyTitle),\n }\n}\n\n/**\n * 단계별 문단 위 간격(HWPUNIT).\n *\n * 종전 값 15/10/6/3pt(×200 = 3000/2000/1200/600)는 「2_보고서 양식」 **한 파일**의\n * 저장값이었다. 코퍼스 555건 실측은 정반대다 — □ 582문단 중 88%, ○ 799문단 중 88%가\n * 문단 위 간격 **0**이고, 2000·3000은 상위 6위에도 들지 못한다(2위가 300). 줄간격\n * 160%(○ 최빈 35%)에 10pt가 더해지면 항목 사이가 1.4줄로 벌어져 실물보다 훨씬 성기다\n * (실렌더 확인).\n *\n * 이 파일 GAEJOSIK_BULLETS 주석에 이미 선언한 원칙 — \"양식 파일 하나의 저장값보다 실무\n * 관행 우선\" — 을 간격에도 적용한다. 실측 최빈값 0을 기본으로 하고, □ 대항목만 절 구분이\n * 필요해 실측 2위인 300(1.5pt)을 남긴다.\n */\nexport function gaejosikSpaceBefore(depth: number, bodyHeight: number): number {\n const s = bodyHeight / 1500\n const ui = [300, 0, 0, 0][Math.min(depth, 3)]\n return Math.round(ui * s)\n}\n\n/**\n * 단계별 들여쓰기 — 실측: 선행 공백 □=1 ○=2 -=3 (0.5em씩) ≈\n * □ left 0 / ○ 1자 / - 1.5자 / ㆍ 2자(+0.5자씩 누적). 내어쓰기는 부호 실폭.\n */\nexport function gaejosikLevelIndent(depth: number, bodyHeight: number, sizes: GaejosikSizeOverrides = {}, bullet2: \"ㅇ\" | \"○\" = \"○\"): { left: number; indent: number } {\n const lefts = [0, 1.0, 1.5, 2.0]\n const left = depth <= 3\n ? Math.round(lefts[depth] * bodyHeight)\n : Math.round((2.0 + (depth - 3) * 0.5) * bodyHeight)\n // □는 자기 크기(16pt 상당)로 부호폭 계산 — 둘째 줄이 내용 첫 글자에 정렬\n const h = depth === 0 ? gaejosikSizes(bodyHeight, sizes).dae : bodyHeight\n return { left, indent: -markerWidth(gaejosikMarker(depth, bullet2), h) }\n}\n\n/** ※ 참고 문단 들여쓰기 — 실측: 선행 공백 5칸(13pt) ≈ 2.5×cham폭 */\nexport function gaejosikChamIndent(bodyHeight: number, sizes: GaejosikSizeOverrides = {}): { left: number; indent: number } {\n const cham = gaejosikSizes(bodyHeight, sizes).cham\n return { left: Math.round(2.5 * cham), indent: -markerWidth(\"※\", cham) }\n}\n\n/**\n * 목차 항목 내어쓰기 — 제목이 길어 줄바꿈될 때 둘째 줄이 로마숫자 밑으로\n * 감기지 않고 제목 첫 글자에 정렬되도록. 내어쓰기 폭 = \"Ⅷ.\" 실폭(로마 크기 기준).\n */\nexport function gaejosikTocItemIndent(bodyHeight: number, sizes: GaejosikSizeOverrides = {}): { left: number; indent: number } {\n const sz = gaejosikSizes(bodyHeight, sizes)\n const hang = markerWidth(\"Ⅷ.\", sz.tocRoman)\n return { left: 2000 + hang, indent: -hang }\n}\n\n// ─── 표지 날짜 ──────────────────────────────────────\n\n/** 공문서 날짜 표기: `YYYY. M. D.` (월·일 앞자리 0 제거, 끝점 필수) */\nexport function formatGaejosikDate(d: Date): string {\n return `${d.getFullYear()}. ${d.getMonth() + 1}. ${d.getDate()}.`\n}\n\n// ─── 장 제목 정리 ────────────────────────────────────\n\n/**\n * h2 제목의 선행 번호(\"1. \"·\"0. \"·\"Ⅱ. \" 등) 제거 — 장 헤더 표가 로마숫자를\n * 자체 부여하므로 이중 번호 방지 (헤딩 자동번호 함정의 개조식 해법).\n */\nexport function stripChapterNumber(title: string): string {\n // 로마숫자는 Ⅰ~Ⅻ(U+2160~216B, chapterRoman 생성 범위) 전체. 소절형 선번호(\"1.5.\")는\n // 한 덩어리로 보아 뒤에 마침표가 있을 때만 제거 — \"1.5 개요\"가 \"5 개요\"로 잘리지 않게.\n // h2 말머리 문자(□·○·ㅇ·-·ㆍ)도 함께 벗긴다 (v4.0.5 P2) — box 모드 왕복 시\n // '□ 제목'이 '□ □ 제목'으로 단조 누적되던 비가역 열화 방지 (idempotency).\n return title\n .replace(/^\\s*[□○ㅇㆍ-]\\s+/u, \"\")\n .replace(/^\\s*(?:\\d+(?:\\.\\d+)*|[Ⅰ-Ⅻ]+)\\s*[.)]\\s*/u, \"\")\n .trim()\n}\n\n// ─── 실측 색상/기하 상수 (gen-gaejosik XML 조립용) ────\n\nexport const GAEJOSIK_COLORS = {\n /** 장헤더 로마숫자 셀·표지 진한 바 음영 */\n primary: \"#193AAA\",\n /** 장헤더 셀 테두리 */\n border: \"#006699\",\n /** 표지 연한 바 */\n accent: \"#A0B4E6\",\n /** 장헤더 제목 셀 음영 */\n titleFill: \"#F2F2F2\",\n /** 장헤더 제목 셀 상하선 */\n titleLine: \"#A6A6A6\",\n /** 목차 박스 테두리 */\n tocBorder: \"#514BAC\",\n /** 목차 배너 라벤더 스트라이프 (실측: GT3 표②) */\n tocStripe: \"#E0E5FA\",\n} as const\n\n/** 실측 개조식 장식표 기하의 기준 본문폭(HWPUNIT) — 여백 좌우 20mm A4(mmToHwpunit(170)=48189).\n * margins 오버라이드로 본문폭이 달라지면 이 값 대비 비율로 표 폭을 스케일해 페이지 밖 넘침 방지.\n * 정의는 geometry.ts SSOT (v4.0.5 P0-3) */\nexport const GAEJOSIK_BASE_WIDTH = BODY_WIDTH_20MM\n\n/** 장헤더 표 기하(HWPUNIT, 여백 20mm A4 본문폭 48189 기준 실측) */\nexport const CHAPTER_GEOM = { numW: 3327, gapW: 848, titleW: 43513, rowH: 2832 } as const\n\n/** 표지 장식 바 기하 — 상단(긴 진파랑+짧은 연파랑), 제목 칸, 하단(짧은 진파랑+긴 연파랑).\n * totalW는 계산 본문폭(48189)이 아닌 실물 저장값 48180 — geometry.ts COVER_MEASURED_W 주석 참조 */\nexport const COVER_GEOM = {\n totalW: COVER_MEASURED_W,\n topDarkW: 38219, topLightW: 9961, barH: 818,\n titleH: 11060,\n botDarkW: 10466, botLightW: 37714, botBarH: 812,\n} as const\n\n/** 목차 박스 기하 */\nexport const TOC_GEOM = { boxW: 46492, boxH: 57840 } as const\n\n// ─── 기하 크기연동 (A3) — sizes 오버라이드에 비례 스케일 ──\n// 실측 기준: 장헤더 rowH 2832@17pt, 표지 제목칸 11060@30pt, 본문 제목박스 3566@22pt,\n// 목차 배너 3931@28pt. 폭은 본문폭 고정(스케일 제외), 높이만 요소 크기에 비례.\n\n/** 장헤더 기하 — rowH를 chapter 크기(기본 17pt)에 비례 */\nexport function chapterGeom(bodyHeight: number, ov: GaejosikSizeOverrides = {}, bodyWidth: number = GAEJOSIK_BASE_WIDTH) {\n const s = gaejosikSizes(bodyHeight, ov).chapter / 1700\n const ws = bodyWidth / GAEJOSIK_BASE_WIDTH\n const numW = Math.round(CHAPTER_GEOM.numW * ws)\n const gapW = Math.round(CHAPTER_GEOM.gapW * ws)\n // 제목 열이 잔여를 흡수 — 세 열 합이 본문폭 비례를 정확히 유지\n const titleW = Math.round((CHAPTER_GEOM.numW + CHAPTER_GEOM.gapW + CHAPTER_GEOM.titleW) * ws) - numW - gapW\n return { numW, gapW, titleW, rowH: Math.round(CHAPTER_GEOM.rowH * s) }\n}\n\n/** 표지 기하 — 제목칸 높이를 coverTitle 크기(기본 30pt)에 비례. 장식 바 높이는 고정 */\nexport function coverGeom(bodyHeight: number, ov: GaejosikSizeOverrides = {}, bodyWidth: number = GAEJOSIK_BASE_WIDTH) {\n const s = gaejosikSizes(bodyHeight, ov).coverTitle / 3000\n // 폭은 본문폭 비례 스케일(잔여 열은 totalW에서 빼 정합 유지), 높이(titleH)는 크기 비례.\n // 기본 여백이면 bodyWidth=기준폭이라 scale=1 → 실측값 그대로(회귀 없음).\n const w = (v: number) => Math.round((v * bodyWidth) / GAEJOSIK_BASE_WIDTH)\n const totalW = w(COVER_GEOM.totalW)\n return {\n ...COVER_GEOM,\n totalW,\n topDarkW: w(COVER_GEOM.topDarkW), topLightW: totalW - w(COVER_GEOM.topDarkW),\n botDarkW: w(COVER_GEOM.botDarkW), botLightW: totalW - w(COVER_GEOM.botDarkW),\n titleH: Math.round(COVER_GEOM.titleH * s),\n }\n}\n\n// ─── 목차 장식 배너 (B7) — 실측: GT3 「2_보고서 양식」 표② 1×7 스트라이프 ──\n// 열폭 [565,565,1414,13191,1414,565,565] 좌우 대칭, h 3931@28pt.\n// 셀 채움: 네이비(#193AAA) | 무 | 라벤더(#E0E5FA) | 라벨 | 라벤더 | 무 | 네이비\nexport const TOC_BANNER_GEOM = {\n colWs: [565, 565, 1414, 13191, 1414, 565, 565] as readonly number[],\n h: 3931,\n} as const\n\n/** 목차 배너 기하 — 높이를 tocLabel 크기(기본 28pt)에 비례 */\nexport function tocBannerGeom(bodyHeight: number, ov: GaejosikSizeOverrides = {}) {\n const s = gaejosikSizes(bodyHeight, ov).tocLabel / 2800\n return { colWs: TOC_BANNER_GEOM.colWs, h: Math.round(TOC_BANNER_GEOM.h * s) }\n}\n\n// ─── 본문 첫 페이지 제목 박스 (B6) — 실측: GT3 표④ 3×3 투톤 바 샌드위치 ──\n// 표지 표①과 동일 그리드, 행높이 600/3566/600, 제목 HY헤드라인M 22pt\nexport const BODY_TITLE_GEOM = { barH: 600, titleH: 3566 } as const\n\n/** 본문 제목박스 기하 — 제목칸 높이를 bodyTitle 크기(기본 22pt)에 비례 */\nexport function bodyTitleGeom(bodyHeight: number, ov: GaejosikSizeOverrides = {}) {\n const s = gaejosikSizes(bodyHeight, ov).bodyTitle / 2200\n return { barH: BODY_TITLE_GEOM.barH, titleH: Math.round(BODY_TITLE_GEOM.titleH * s) }\n}\n","/**\n * 공문서(公文書) 모드 — 한국 행정 공문서 표준 서식 렌더링 로직\n *\n * 근거: 「행정업무의 운영 및 혁신에 관한 규정」 및 동 시행규칙(제2조 항목 표시),\n * 행정안전부 「2020 행정업무운영 편람」.\n * 자세한 표준은 docs/gongmunseo-reference.md, 구현 매핑은 docs/gongmunseo-engine-spec.md 참조.\n *\n * 이 모듈은 **순수 로직**만 담는다(항목부호 시퀀스 생성, 단계별 들여쓰기 계산,\n * 프리셋 해석). 실제 XML 조립은 generator.ts가 한다.\n */\n\nimport { charWidthEm1000, SPACE_EM_FIXED } from \"./text-metrics.js\"\nimport { gaejosikMarker, gaejosikLevelIndent, type GaejosikSizeOverrides } from \"./gaejosik.js\"\nimport { KordocError } from \"../utils.js\"\nimport { hangulOrdinal, circledNumber, circledHangul } from \"../shared/numbering.js\"\n\n// ─── 옵션 타입 ──────────────────────────────────────\n\nexport type GongmunPreset = \"official\" | \"report\" | \"plan\" | \"notice\" | \"minutes\" | \"gaejosik\" | \"press\" | \"ministry\"\nexport type GongmunNumbering = \"standard\" | \"report\" | \"gaejosik\"\nexport type GongmunFont = \"myeongjo\" | \"gothic\"\n\n/** 프리셋 입력값 — 영문 키 또는 한글 별칭(기안문·보고서·계획서·통지·회의록 등) */\nexport type GongmunPresetInput =\n | GongmunPreset\n | \"기안문\" | \"시행문\" | \"공문\" | \"공문서\"\n | \"보고서\"\n | \"계획서\" | \"계획\"\n | \"통지\" | \"알림\" | \"안내\"\n | \"회의록\"\n | \"개조식\" | \"개조식보고서\" | \"정부보고서\" | \"정부표준개조식보고서\"\n | \"보도자료\"\n | \"업무보고\" | \"부처업무보고\" | \"중앙부처보고서\"\n\n/** 항목부호 단계 하나의 타이포 — 셋 다 선택(미지정=본문 계열 유지) */\nexport interface GongmunLevelStyle {\n /** 글꼴명 (예: HY견고딕·한컴돋움·휴먼명조) */\n font?: string\n /** 글자 크기 pt (6~60) */\n pt?: number\n /** 굵게 */\n bold?: boolean\n}\n\n/** 해석된 단계 타이포 — height = pt×100 (미지정 pt는 본문), font null = 본문 글꼴 */\nexport interface ResolvedLevelStyle {\n font: string | null\n height: number\n bold: boolean\n}\n\n/** 공문서 모드 옵션 (전부 선택 — 프리셋 기본값을 개별 override) */\nexport interface GongmunOptions {\n /** 문서 종류 프리셋(영문 키 또는 한글 별칭). 기본 'official'(일반 기안문) */\n preset?: GongmunPresetInput\n /** 본문 글꼴. 'myeongjo'=함초롬바탕(명조, 보고서·대외공문 관행) / 'gothic'=맑은 고딕(전자결재 기본) */\n bodyFont?: GongmunFont\n /** 본문 글자 크기(pt). 기본: 기안문 12, 보고서·계획서·통지 15 */\n bodyPt?: number\n /** 본문 줄간격(%). 기본 160 (회의록 130) */\n lineSpacing?: number\n /** 항목부호 체계. 'standard'=법정 8단계(1. 가. 1) …) / 'report'=보고서 불릿(□ ○ - ㆍ) / 'gaejosik'=개조식(□ ○ - ㆍ + 부호별 폰트) */\n numbering?: GongmunNumbering\n /**\n * 표지 페이지(개조식·업무보고 프리셋 기본 켜짐) — 첫 h1을 제목으로, 파랑 장식 바 + 날짜 + 기관명.\n * false로 끄거나 {date, org}로 날짜(기본 오늘, 'YYYY. M. D.')·기관명(기본 생략) 지정.\n * label = 표지 우상단 취급 표시(\"대외주의\"·\"비공개\" — 업무보고 프리셋, 빨간 테두리 박스).\n */\n cover?: boolean | { date?: string; org?: string; dept?: string; label?: string }\n /** 목차 페이지(개조식 프리셋 기본 켜짐) — h2 목록을 Ⅰ Ⅱ Ⅲ…로 자동 생성. false로 끔 */\n toc?: boolean\n /** 용지 여백(mm). 기본 공식값 위20/아래10/좌20/우20 */\n margins?: { top: number; bottom: number; left: number; right: number }\n /** 문서 제목(첫 h1)을 가운데 정렬. 기본 true (행정기관명·보고서 제목) */\n centerTitle?: boolean\n /**\n * 문단별 자동 장평 — 한두 글자(짧은 꼬리)만 다음 줄로 넘어가는 문단의 장평을\n * 95→90%까지 자동 축소해 한 줄에 담는다(공무원 실무 관행의 자동화).\n * false로 끄거나 minRatio(기본 90)로 하한 조정. 기본 켜짐.\n */\n autoFit?: boolean | { minRatio?: number }\n /**\n * 요소별 글꼴 오버라이드 — 기관 표준 폰트 적용이나 미설치 폰트 대체용.\n * body=본문(개조식 ○·-) / heading=제목 계열(□·장헤더·표지·목차) / ref=※ 참고 / table=표 셀.\n * 실측 폰트 프리셋(개조식·보고서·계획서)은 네 역할 전부, 그 외 프리셋은 body만\n * 적용된다 (bodyFont보다 우선).\n */\n fonts?: { body?: string; heading?: string; ref?: string; table?: string }\n /** 개조식 요소별 글자 크기(pt) 오버라이드 — 미지정 요소는 bodyPt 비례 기본값 */\n sizes?: GaejosikSizeOverrides\n /**\n * 항목부호 단계별 위계 타이포(v4.12.3) — depth(0~7)마다 글꼴·크기(pt)·굵기를 지정한다.\n * 실측(실결재 기안문 206 + 보고서 337건): 법정 8단계(1. 가. 1))는 본문과 동일이 90%라 기본은\n * 무변경, □/ㅇ/- 계열 전자결재 기안문은 □=HY견고딕 +2~3pt bold·ㅇ=한컴돋움 bold·-=휴먼명조가\n * 지배 관행이다(docs/gongmunseo-reference.md 2.7). 지정한 단계만 바뀌고 나머지는 본문 계열.\n * 개조식·보고서의 실측 □(HY헤드라인M)·보도자료 각주보다 우선한다(명시 옵션).\n */\n levels?: Record<number | string, GongmunLevelStyle>\n /** 쪽번호(하단 중앙 \"- 1 -\", 표지·목차는 카운트 제외). 기본: 개조식·보고서·계획서 켜짐 */\n pageNumbers?: boolean\n /** 본문 끝 2타+\"끝.\" 표시(행정업무규정). 기본: 기안문(official)만 켜짐 */\n endMark?: boolean\n /** 결재란 — 직위 라벨 배열(예: [\"담당\",\"팀장\",\"과장\"]). 문서 최상단 우측 배치 */\n approval?: string[]\n /** 본문 첫 페이지 제목 박스(개조식) — 목차 뒤 본문 시작에 제목 반복(실측 관행). 기본: 표지 있으면 켜짐 */\n bodyTitleBox?: boolean\n /**\n * h2 장 제목 표기 (v5): 'band'=로마자 채움 칸 + 제목 띠 표(보고서·계획서 기본 — 계획서 장르 실측 37~39%) /\n * 'roman'=Ⅰ. Ⅱ. 텍스트 / 'number'=1. 2. (통지 기본) / 'box'=장 없이 □ 대항목으로 / 'none'=번호 없음.\n * 기안문 본문의 h2는 항상 법정 1. 항목.\n */\n h2Marker?: \"band\" | \"roman\" | \"box\" | \"number\" | \"none\"\n /**\n * 띠 제목(h2Marker 'band') 번호칸 채움색 `#RRGGBB` — 기본 #003366(서울 plan 띠 표 실측 최다).\n * 교육청형 밝은 띠는 `bandColor: \"#DFE6F7\", bandTextColor: \"#000000\"`.\n */\n bandColor?: string\n /** 띠 제목 번호 글자색 `#RRGGBB` — 기본 #FFFFFF */\n bandTextColor?: string\n /**\n * 2단계 항목부호 — 'ㅇ'(이응, 전자결재 기안문·공고문 실측 지배) / '○'(원, 보고서\n * 양식 계열 실측). 기본: notice·press 'ㅇ', 그 외 '○' (v4.1.0 실결재 60건 분포).\n */\n bullet2?: \"ㅇ\" | \"○\"\n /**\n * 단일 형제 항목 부호 생략(편람 규정: 항목이 하나면 부호 미부여). 기본 false —\n * 부호 없는 계단 들여쓰기가 실무 눈에 더 어색하다(실무자 QA, v4.0.2).\n * 규정 엄수가 필요하면 true. 법정 번호(standard) 전용 — 불릿 체계(report·gaejosik)엔\n * 적용되지 않으므로, 기본 numbering이 report인 plan 프리셋은 numbering:'standard' 병기 필요.\n */\n suppressSingle?: boolean\n /** 기안문 두문표 — 행정기관명·(원훈 slogan)·수신·경유·제목 (별지 제1호서식·서울 실결재 6행 표, official 전용) */\n docHead?: { org?: string; slogan?: string; to?: string; via?: string; title?: string }\n /**\n * 기안문 결문표 — 발신명의·결재선(기안/검토/결재 또는 approvers 배열 \"직위 성명\")·협조자·수신자·\n * 시행/접수·우편번호(zip)·주소·홈페이지·전화·전송·이메일·공개구분 (official 전용)\n */\n docFoot?: {\n sender?: string; drafter?: string; reviewer?: string; approver?: string\n approvers?: string[]; cooperator?: string; recipients?: string; docNum?: string; receive?: string\n zip?: string; address?: string; site?: string; phone?: string; fax?: string; email?: string; disclosure?: string\n }\n /** 보고서 요약 박스(제목표 아래 #DFE6F7 상자, 서울 실결재) — 마크다운 제목 직후 인용문(>)으로도 지정 가능 */\n summary?: string\n /** 보고서 표지 문서정보표 — 문서번호·결재일자·공개여부·방침번호 (cover와 함께) */\n docInfo?: { docNum?: string; date?: string; disclosure?: string; policyNo?: string }\n /** 업무보고 우상단 보고정보 행 — \"(보고일시, 보고자, 연락처)\" (실측 t3: 휴먼명조 12pt RIGHT) */\n reportInfo?: string\n /** 공고문 두문·결문 — 공고번호(본문 위)·날짜·발신명의(본문 아래 우측, 실측 바이오헬스 공고) */\n noticeHead?: { no?: string; date?: string; sender?: string }\n /** 보도자료(press) 머리·담당 — 보도시점/배포 행·부제·담당 부서 표 */\n press?: { release?: string; distribute?: string; sub?: string[]; contact?: { dept?: string; manager?: string; phone?: string } }\n}\n\nexport interface ResolvedGongmun {\n preset: GongmunPreset\n bodyFont: GongmunFont\n bodyHeight: number // charPr height = pt × 100\n lineSpacing: number\n numbering: GongmunNumbering\n margins: { top: number; bottom: number; left: number; right: number }\n centerTitle: boolean\n /** 자동 장평 하한(%) — null이면 끔 */\n autoFitMinRatio: number | null\n /** 표지 설정 — null이면 표지 없음 (개조식 외 프리셋 기본) */\n cover: { date: string | null; org: string; dept?: string; label?: string } | null\n /** 옵션이 명시됐는지 — v5 스킴이 실측 기본값(굴림 12·한컴돋움 15·160/180%)을 쓸지 판단 */\n bodyPtExplicit: boolean\n lineSpacingExplicit: boolean\n bodyFontExplicit: boolean\n /** 보고서 요약 박스 텍스트 — null이면 마크다운 인용문 자동 */\n summary: string | null\n /** 보고서 표지 문서정보표 */\n docInfo: NonNullable<GongmunOptions[\"docInfo\"]> | null\n /** 목차 자동 생성 여부 (개조식 프리셋 기본 true) */\n toc: boolean\n /** 요소별 글꼴 오버라이드 (GongmunOptions.fonts) */\n fonts: { body?: string; heading?: string; ref?: string; table?: string }\n /** 개조식 요소별 크기(pt) 오버라이드 (GongmunOptions.sizes) */\n sizes: GaejosikSizeOverrides\n /** 단계별 위계 타이포(depth → 스타일) — null이면 없음 (v4.12.3) */\n levels: Record<number, ResolvedLevelStyle> | null\n /** 쪽번호(하단 중앙 \"- 1 -\") — 개조식·보고서·계획서 기본 켜짐 */\n pageNumbers: boolean\n /** 머리말·꼬리말 영역(HWPUNIT) — 개조식 4251(15mm, 실측), 그 외 0(편람) */\n headerFooter: number\n /** 본문 끝 \"끝.\" 표시 — 기안문(official) 기본 켜짐 (규정) */\n endMark: boolean\n /** 결재란 직위 라벨(좌→우) — null이면 결재란 없음 */\n approval: string[] | null\n /** 본문 첫 페이지 제목 박스(개조식, 실측 GT3 표④) — 표지 있을 때 기본 켜짐 */\n bodyTitleBox: boolean\n /** h2 장 제목 표기 — 보고서·계획서 'roman', 통지·공고 'number' (v5) */\n h2Marker: \"band\" | \"roman\" | \"box\" | \"number\" | \"none\"\n /** 띠 제목 번호칸 채움색·글자색 (#RRGGBB, 대문자 정규화) */\n bandColor: string\n bandTextColor: string\n /** 2단계 항목부호 — notice·press 기본 'ㅇ', 그 외 '○' (실결재 60건 분포, v4.1.0) */\n bullet2: \"ㅇ\" | \"○\"\n /** 단일 형제 부호 생략(규정) — 기본 false (실무 관행: 하나여도 부호, v4.0.2) */\n suppressSingle: boolean\n /** 기안문 두문 — null이면 없음 */\n docHead: NonNullable<GongmunOptions[\"docHead\"]> | null\n /** 기안문 결문 — null이면 없음 */\n docFoot: NonNullable<GongmunOptions[\"docFoot\"]> | null\n /** 보고정보 행 — null이면 없음 */\n reportInfo: string | null\n /** 공고문 두문·결문 — null이면 없음 */\n noticeHead: { no?: string; date?: string; sender?: string } | null\n /** 보도자료 머리·담당 — press 프리셋이면 옵션 미지정이어도 빈 객체(머리박스는 항상) */\n press: NonNullable<GongmunOptions[\"press\"]> | null\n}\n\n/**\n * 기안문 여백(mm) — 실결재 지배값 t20/b15/l20/r15 (서울 정보소통광장 60건 중 41건,\n * v4.1.0 실측). 편람 공식값(위20/아래10/좌우20)보다 실무 관행 우선 — margins로 조정 가능.\n */\nconst OFFICIAL_MARGINS = { top: 20, bottom: 15, left: 20, right: 15 }\n\n/** 보고서 계열 여백(mm) — 실측: 「2_보고서 양식」·샘플양식1·공고문·보도자료 공통 상하 15mm */\nconst GAEJOSIK_MARGINS = { top: 15, bottom: 15, left: 20, right: 20 }\n\n/** 서울 보고서형 기안(간이기안) 여백(mm) — 실결재 개조식 문서 지배값 13/13/18/18·머리꼬리 13 (v5) */\nconst SEOUL_REPORT_MARGINS = { top: 13, bottom: 13, left: 18, right: 18 }\nconst SEOUL_REPORT_HEADER_FOOTER = 3600\n\n/** 개조식 머리말·꼬리말 영역(HWPUNIT) — 실측 4251(15mm). 쪽번호가 이 영역에 렌더 */\nconst GAEJOSIK_HEADER_FOOTER = 4251\n\n/**\n * 중앙부처 업무보고 여백(mm) — 재경부 2차 업무보고(2026-07-15) 실측: 본문 x 56.5~538pt(좌우 20mm),\n * 장 띠 상단 y56pt(위 20mm), 쪽번호 y803pt. 위·아래 10 + 머리말·꼬리말 10mm(2835)로 본문 시작 20mm를 맞춘다.\n */\nconst MINISTRY_MARGINS = { top: 10, bottom: 10, left: 20, right: 20 }\nconst MINISTRY_HEADER_FOOTER = 2835\n\nconst PRESET_DEFAULTS: Record<\n GongmunPreset,\n { bodyPt: number; lineSpacing: number; numbering: GongmunNumbering }\n> = {\n // 서울시 실결재 104건 중 12pt 64건(13pt 30, 15pt 5) — 지배값을 기본으로 사용.\n official: { bodyPt: 12, lineSpacing: 160, numbering: \"standard\" },\n report: { bodyPt: 15, lineSpacing: 160, numbering: \"report\" },\n // 실측 추진계획안: □ → ㅇ → * 계층.\n plan: { bodyPt: 15, lineSpacing: 160, numbering: \"report\" },\n notice: { bodyPt: 15, lineSpacing: 160, numbering: \"standard\" },\n minutes: { bodyPt: 14, lineSpacing: 130, numbering: \"standard\" },\n gaejosik: { bodyPt: 15, lineSpacing: 160, numbering: \"gaejosik\" },\n // 보도자료 — 실측(국토부 실물): 본문 바탕 14pt 160%, □→ㅇ→*(각주) 부호\n press: { bodyPt: 14, lineSpacing: 160, numbering: \"report\" },\n // 중앙부처 업무보고 — 실측(재경부 2차 업무보고): 함초롬바탕 15pt, 줄피치 21.7pt(≈145%), □→ㅇ→-→*(각주)\n ministry: { bodyPt: 15, lineSpacing: 145, numbering: \"report\" },\n}\n\n/** 프리셋 별칭(한글/영문) → 내부 preset 키. CLI·라이브러리 공용 */\nexport const PRESET_ALIAS: Record<string, GongmunPreset> = {\n official: \"official\", 기안문: \"official\", 시행문: \"official\", 공문: \"official\", 공문서: \"official\",\n report: \"report\", 보고서: \"report\",\n plan: \"plan\", 계획서: \"plan\", 계획: \"plan\",\n notice: \"notice\", 통지: \"notice\", 알림: \"notice\", 안내: \"notice\",\n minutes: \"minutes\", 회의록: \"minutes\",\n gaejosik: \"gaejosik\", 개조식: \"gaejosik\", 개조식보고서: \"gaejosik\", 정부보고서: \"gaejosik\", 정부표준개조식보고서: \"gaejosik\",\n press: \"press\", 보도자료: \"press\",\n ministry: \"ministry\", 업무보고: \"ministry\", 부처업무보고: \"ministry\", 중앙부처보고서: \"ministry\",\n}\n\n/** 프리셋 입력(영문 키 또는 한글 별칭)을 내부 GongmunPreset로 정규화. 미상은 'official' */\nexport function normalizeGongmunPreset(preset?: string): GongmunPreset {\n if (!preset) return \"official\"\n return PRESET_ALIAS[preset.trim()] ?? \"official\"\n}\n\n/**\n * 실측 보고서 폰트 세트(제목 HY헤드라인M·본문 휴먼명조·※ 한양중고딕·표 맑은 고딕)를\n * 쓰는 프리셋 — 부처별 실측 양식 3종(업무보고·보고서×2) 공통 스펙 (v4.0.1 QA-1).\n * 개조식만 받던 실측 폰트를 보고서·계획서로 확장. 기안문·통지·회의록은 함초롬 유지\n * (전자결재·일반 공문 관행).\n */\nexport function usesReportFonts(preset: GongmunPreset): boolean {\n return preset === \"gaejosik\" || preset === \"report\" || preset === \"plan\"\n}\n\n/** 3단계 부호로 *(참고)를 쓰는 프리셋인지 — 실측: 추진계획안·보도자료 공통 □→ㅇ→* 계층.\n * levelIndent(내어쓰기 폭)와 GongmunNumberer(마커)가 같은 판정을 공유해야 정렬이 맞는다. */\nexport function usesAsteriskThird(preset: GongmunPreset): boolean {\n return preset === \"plan\" || preset === \"press\"\n}\n\n/** 개조식 표지·목차용 정적 font/char/border 자산이 필요한 문서인지.\n * bodyTitleBox는 표지(cover) 없이는 렌더할 제목이 없어 단독으로는 자산을 요구하지 않는다. */\nexport function needsGaejosikAssets(gongmun: ResolvedGongmun): boolean {\n return usesReportFonts(gongmun.preset) || gongmun.cover !== null || gongmun.toc\n}\n\nfunction assertFiniteRange(name: string, value: number, min: number, max: number): void {\n if (!Number.isFinite(value) || value < min || value > max) {\n throw new KordocError(`${name} must be a finite number between ${min} and ${max}`)\n }\n}\n\n/** 공개 API·CLI가 공유하는 공문서 수치 옵션 방어선 — 잘못된 값이 XML의 NaN/Infinity로 번지는 것을 막는다. */\nfunction validateGongmunOptions(opts: GongmunOptions): void {\n if (opts.bodyPt !== undefined) assertFiniteRange(\"bodyPt\", opts.bodyPt, 6, 40)\n if (opts.lineSpacing !== undefined) assertFiniteRange(\"lineSpacing\", opts.lineSpacing, 50, 300)\n if (typeof opts.autoFit === \"object\" && opts.autoFit.minRatio !== undefined) {\n assertFiniteRange(\"autoFit.minRatio\", opts.autoFit.minRatio, 50, 99)\n }\n if (opts.margins) {\n for (const side of [\"top\", \"bottom\", \"left\", \"right\"] as const) {\n const value = opts.margins[side]\n assertFiniteRange(`margins.${side}`, value, 0, 200)\n }\n if (opts.margins.left + opts.margins.right >= 210) {\n throw new KordocError(\"margins.left + margins.right must be less than 210\")\n }\n if (opts.margins.top + opts.margins.bottom >= 297) {\n throw new KordocError(\"margins.top + margins.bottom must be less than 297\")\n }\n }\n if (opts.sizes) {\n for (const [key, value] of Object.entries(opts.sizes)) {\n if (value !== undefined) assertFiniteRange(`sizes.${key}`, value, 6, 60)\n }\n }\n if (opts.approval && opts.approval.length > 6) {\n throw new KordocError(\"approval must contain at most 6 labels\")\n }\n if (opts.levels) {\n for (const [key, st] of Object.entries(opts.levels)) {\n const depth = Number(key)\n if (!Number.isInteger(depth) || depth < 0 || depth >= GONGMUN_LEVEL_COUNT) {\n throw new KordocError(`levels: depth must be an integer between 0 and ${GONGMUN_LEVEL_COUNT - 1} (got \"${key}\")`)\n }\n if (!st || typeof st !== \"object\") throw new KordocError(`levels.${key} must be an object {font, pt, bold}`)\n if (st.pt !== undefined) assertFiniteRange(`levels.${key}.pt`, st.pt, 6, 60)\n if (st.font !== undefined && (typeof st.font !== \"string\" || !st.font.trim())) {\n throw new KordocError(`levels.${key}.font must be a non-empty string`)\n }\n }\n }\n}\n\n/** 항목부호 단계 수 — gen-ids GONGMUN_LIST_LEVELS(8)와 동일 값(순환 import 회피용 사본) */\nconst GONGMUN_LEVEL_COUNT = 8\n\n/** levels 옵션 해석 — 셋 다 비어 있는 항목은 버린다(무의미한 charPr 방출 방지) */\nfunction resolveLevels(levels: GongmunOptions[\"levels\"], bodyHeight: number): Record<number, ResolvedLevelStyle> | null {\n if (!levels) return null\n const out: Record<number, ResolvedLevelStyle> = {}\n for (const [key, st] of Object.entries(levels)) {\n if (st.font === undefined && st.pt === undefined && st.bold === undefined) continue\n out[Number(key)] = {\n font: st.font?.trim() || null,\n height: st.pt !== undefined ? Math.round(st.pt * 100) : bodyHeight,\n bold: !!st.bold,\n }\n }\n return Object.keys(out).length > 0 ? out : null\n}\n\n/** depth 단계 부호의 글자 높이 — levels 오버라이드가 있으면 그 크기, 없으면 본문 */\nexport function levelMarkerHeight(g: Pick<ResolvedGongmun, \"levels\" | \"bodyHeight\">, depth: number): number {\n return g.levels?.[depth]?.height ?? g.bodyHeight\n}\n\n/**\n * 프리셋과 비호환이라 resolveGongmun이 조용히 폐기/무시하는 옵션의 경고 목록 (v4.0.6).\n * 순수 함수 — 배선은 호출자 몫 (CLI stderr / MCP 응답 병기, unknownFontWarnings 관례).\n * 게이팅 조건은 resolveGongmun 본문과 1:1 — 여기 조건을 바꾸면 본문도 함께.\n */\nexport function incompatibleGongmunWarnings(opts: GongmunOptions): string[] {\n const warns: string[] = []\n const preset = normalizeGongmunPreset(opts.preset)\n if (opts.docHead && preset !== \"official\") warns.push(`doc_head(두문)는 기안문(official) 전용 — '${preset}' 프리셋에서 무시됨`)\n if (opts.docFoot && preset !== \"official\") warns.push(`doc_foot(결문)는 기안문(official) 전용 — '${preset}' 프리셋에서 무시됨`)\n if (opts.noticeHead && preset !== \"notice\") warns.push(`notice_head(공고번호·발신명의)는 통지(notice) 전용 — '${preset}' 프리셋에서 무시됨`)\n if (opts.press && preset !== \"press\") warns.push(`press(머리박스·부제·담당)는 보도자료(press) 전용 — '${preset}' 프리셋에서 무시됨`)\n if (preset === \"press\" && (opts.cover === true || typeof opts.cover === \"object\" || opts.toc === true)) {\n warns.push(\"보도자료는 머리박스 서식과 양립 불가라 표지·목차가 무시됨\")\n }\n if (opts.sizes && Object.keys(opts.sizes).length > 0 && !usesReportFonts(preset)) {\n warns.push(`sizes(개조식 요소 크기)는 개조식·보고서·계획서 전용 — '${preset}' 프리셋에서 무시됨`)\n }\n if (opts.suppressSingle && (opts.numbering ?? PRESET_DEFAULTS[preset].numbering) !== \"standard\") {\n warns.push(`suppress_single(단일 형제 부호 생략)은 법정 번호(standard) 전용 — '${preset}' 프리셋(불릿 체계)에서 무동작`)\n }\n return warns\n}\n\n/** `#RRGGBB` 색 옵션 검증·대문자 정규화 — 미지정은 undefined(기본값은 호출부) */\nfunction hexColorOption(name: string, value: string | undefined): string | undefined {\n if (value === undefined) return undefined\n const v = value.trim()\n if (!/^#[0-9a-fA-F]{6}$/.test(v)) throw new KordocError(`${name} must be a #RRGGBB color (got \"${value}\")`)\n return v.toUpperCase()\n}\n\nexport function resolveGongmun(opts: GongmunOptions): ResolvedGongmun {\n validateGongmunOptions(opts)\n const preset = normalizeGongmunPreset(opts.preset)\n const d = PRESET_DEFAULTS[preset]\n const bodyPt = opts.bodyPt ?? d.bodyPt\n const autoFitMinRatio =\n opts.autoFit === false ? null\n : typeof opts.autoFit === \"object\" ? Math.min(Math.max(opts.autoFit.minRatio ?? 90, 50), 99)\n : 90\n // 표지·목차 — 개조식 프리셋만 기본 켜짐. cover.date null이면 렌더 시점의 오늘 날짜\n const ministry = preset === \"ministry\"\n const coverOn = opts.cover !== undefined ? opts.cover !== false : preset === \"gaejosik\" || ministry\n const coverOpts = typeof opts.cover === \"object\" ? opts.cover : {}\n const gaejosik = preset === \"gaejosik\"\n // 여백 — 보고서 계열(개조식·보고서·계획서·공고문·보도자료)은 실측 상하 15mm,\n // 기안문·회의록은 실결재 지배값(20/15/20/15)\n const reportFamily = gaejosik || preset === \"report\" || preset === \"plan\" || preset === \"notice\" || preset === \"press\"\n return {\n preset,\n bodyFont: opts.bodyFont ?? \"myeongjo\",\n bodyHeight: Math.round(bodyPt * 100),\n lineSpacing: opts.lineSpacing ?? d.lineSpacing,\n numbering: opts.numbering ?? d.numbering,\n margins: opts.margins ?? (ministry ? MINISTRY_MARGINS : preset === \"report\" || preset === \"plan\" ? SEOUL_REPORT_MARGINS : reportFamily ? GAEJOSIK_MARGINS : OFFICIAL_MARGINS),\n centerTitle: opts.centerTitle ?? true,\n autoFitMinRatio,\n // 보도자료는 머리박스가 1페이지 최상단을 차지하는 서식이라 표지·목차와 양립 불가 —\n // 켜면 머리박스가 표지에 얹히고 25pt 제목·부제가 유실된다 (docHead 프리셋 게이팅과 동일 관례)\n cover: coverOn && preset !== \"press\" ? { date: coverOpts.date ?? null, org: coverOpts.org ?? \"\", ...(coverOpts.dept ? { dept: coverOpts.dept } : {}), ...(coverOpts.label ? { label: coverOpts.label } : {}) } : null,\n bodyPtExplicit: opts.bodyPt !== undefined,\n lineSpacingExplicit: opts.lineSpacing !== undefined,\n bodyFontExplicit: opts.bodyFont !== undefined,\n summary: opts.summary?.trim() || null,\n docInfo: opts.docInfo ?? null,\n toc: preset !== \"press\" && (opts.toc ?? (gaejosik || ministry)),\n fonts: opts.fonts ?? {},\n sizes: opts.sizes ?? {},\n levels: resolveLevels(opts.levels, Math.round(bodyPt * 100)),\n // 쪽번호 — 보고서 계열 관행(실측: 2_보고서 양식·추진계획·공고문 전부 하단 중앙)\n pageNumbers: opts.pageNumbers ?? (gaejosik || ministry || preset === \"report\" || preset === \"plan\"),\n // 머리말·꼬리말 — 실측: 보고서 계열 15mm(GT3·t2·춘천·브라더), 공고·보도 10mm,\n // 기안문 0(실결재 41/60건 h0/f0)\n headerFooter: ministry ? MINISTRY_HEADER_FOOTER\n : preset === \"report\" || preset === \"plan\" ? SEOUL_REPORT_HEADER_FOOTER\n : usesReportFonts(preset) ? GAEJOSIK_HEADER_FOOTER\n : preset === \"notice\" || preset === \"press\" ? 2835 : 0,\n // \"끝.\" — 기안문 규정(본문 끝 2타+\"끝.\"). 그 외는 opt-in\n endMark: opts.endMark ?? preset === \"official\",\n approval: opts.approval && opts.approval.length > 0 ? opts.approval : null,\n // 본문 제목박스 — 실측(GT3·GT12): 목차 뒤 본문 시작에 제목 반복. 표지 켜진 개조식 기본\n bodyTitleBox: opts.bodyTitleBox ?? (gaejosik && coverOn),\n // h2 말머리 — 실측: 보고서 양식 □ 대항목(QA-2), 공고문 아라비아(\"1. 사업개요\", 바이오헬스 실측)\n // v5 라운드 3: 보고서·계획서 기본 band(띠 표) — 서울 plan 7/19·교육청 7/18 실측, 실무자 요청\n h2Marker: opts.h2Marker ?? (preset === \"report\" || preset === \"plan\" ? \"band\" : preset === \"notice\" ? \"number\" : \"none\"),\n // 띠 제목 색 — 실측 최다 #003366/흰 글자(계획서 띠 표 14개). 교육청형 밝은 띠는 옵션으로\n bandColor: hexColorOption(\"bandColor\", opts.bandColor) ?? \"#003366\",\n bandTextColor: hexColorOption(\"bandTextColor\", opts.bandTextColor) ?? \"#FFFFFF\",\n // 2단계 부호 — 실결재 기안문·공고문 ㅇ 지배(60건 중 ㅇ134:○5), 보고서 양식 계열 ○\n // v5: 서울 실결재 ㅇ(이응) 지배 — 보고서·계획서·통지·보도자료 ㅇ, 중앙부처 개조식 양식만 ○\n bullet2: opts.bullet2 ?? (preset === \"gaejosik\" ? \"○\" : \"ㅇ\"),\n // 단일 형제 부호 생략 — 규정이지만 부호 없는 계단이 실무 눈에 어색 (실무자 QA)\n suppressSingle: opts.suppressSingle ?? false,\n docHead: preset === \"official\" && opts.docHead ? opts.docHead : null,\n docFoot: preset === \"official\" && opts.docFoot ? opts.docFoot : null,\n reportInfo: opts.reportInfo?.trim() || null,\n noticeHead: preset === \"notice\" && opts.noticeHead ? opts.noticeHead : null,\n // 보도자료 머리박스는 프리셋 자체가 요구 — 옵션 미지정이어도 빈 객체\n press: preset === \"press\" ? (opts.press ?? {}) : null,\n }\n}\n\n// ─── 항목부호 시퀀스 생성 ────────────────────────────\n\n// 시퀀스 포맷터 정본은 src/shared/numbering.ts — 여기서는 재수출로 하위호환 유지\n// (gen-gongmun-fit, section-walker, parser, tests가 이 모듈에서 import)\nexport { hangulOrdinal, circledNumber, circledHangul }\n\n/** 보고서 모드 단계별 불릿(정부 보고서 관행: □ 대 / ○·ㅇ 중 / - 소 / ㆍ 세) */\nconst REPORT_BULLETS = [\"□\", \"○\", \"-\", \"ㆍ\"]\n/** 계획서·보도자료 불릿 — 실측: □ → ㅇ → *(참고) */\nconst ASTERISK_BULLETS = [\"□\", \"○\", \"*\", \"ㆍ\"]\n\n/**\n * 'standard'(법정 8단계) 마커. depth 0~7, n은 해당 단계 형제 중 0-based 순번.\n * 5·6단계는 반드시 괄호 3글자 조합, 7·8단계는 단일 유니코드 문자.\n */\nexport function standardMarker(depth: number, n: number): string {\n switch (depth) {\n case 0: return `${n + 1}.`\n case 1: return `${hangulOrdinal(n)}.`\n case 2: return `${n + 1})`\n case 3: return `${hangulOrdinal(n)})`\n case 4: return `(${n + 1})`\n case 5: return `(${hangulOrdinal(n)})`\n case 6: return circledNumber(n)\n case 7: return circledHangul(n)\n default: return circledHangul(n) // 8단계 초과(실무상 없음)\n }\n}\n\n/** 'report' 모드 마커(불릿, 순번 무관). bullet2로 2단계 ㅇ/○ 전환. */\nexport function reportMarker(depth: number, bullet2: \"ㅇ\" | \"○\" = \"○\", asteriskThird = false): string {\n const bullets = asteriskThird ? ASTERISK_BULLETS : REPORT_BULLETS\n const m = bullets[Math.min(depth, bullets.length - 1)]\n return depth === 1 ? bullet2 : m\n}\n\n/**\n * 항목부호 문자열의 실제 렌더 폭(HWPUNIT) + 부호와 내용 사이 1타(공백 0.5em).\n * 내어쓰기(둘째 줄 정렬)의 기준값이다 — 실제 한컴 공문서를 디코드해 보면 |intent|가\n * 부호의 실제 폭과 같아야 둘째 줄이 첫 줄 내용 첫 글자에 맞는다. 부호마다 폭이 달라\n * (예: '1.'은 좁고 '가.'는 넓음) 고정값으로는 정렬을 맞출 수 없다.\n * 폭은 함초롬바탕 실측 advance 테이블(text-metrics)로 계산한다 — 한글·원문자 0.97em,\n * 숫자 0.55em, 온점 0.32em, 괄호 0.32em (기존 근사치는 괄호를 0.45em으로 과대평가).\n */\nexport function markerWidth(marker: string, bodyHeight: number): number {\n let em = SPACE_EM_FIXED // 1타(부호와 내용 사이 공백, 0.5em)\n for (const c of marker) em += charWidthEm1000(c.codePointAt(0)!)\n return Math.round((em / 1000) * bodyHeight)\n}\n\n// ─── 단계별 들여쓰기(left/내어쓰기 indent) 계산 ──────\n\nexport interface LevelIndent {\n /** 문단 왼쪽 여백(HWPUNIT) — 단계별 누적 들여쓰기. 첫 줄 부호가 여기서 시작 */\n left: number\n /**\n * 첫 줄 들여쓰기(HWPUNIT, hc:intent). **음수 = 내어쓰기**: 첫 줄은 left에서 시작하고\n * 둘째 줄부터 |intent| 만큼 오른쪽으로 들여쓴다(= 내용 첫 글자에 정렬). 한컴 실측 의미.\n */\n indent: number\n}\n\n/**\n * depth(0~)별 들여쓰기 계산. (한컴 OWPML 실측 모델)\n * - left = depth × bodyHeight (단계마다 한글 1자=2타씩 누적 — 첫 줄 부호 위치)\n * - intent = -(단계 대표 부호의 실제 렌더폭) (음수 내어쓰기 → 둘째 줄이\n * left+|intent| = 첫 줄 내용 첫 글자에 정렬). 부호폭은 markerWidth로 산출하므로\n * '1.'(좁음)·'가.'(넓음)이 각각 자기 폭만큼만 내어써진다(실측 한컴 공문서와 동일).\n */\nexport function levelIndent(\n depth: number,\n bodyHeight: number,\n numbering: GongmunNumbering,\n sizes: GaejosikSizeOverrides = {},\n bullet2: \"ㅇ\" | \"○\" = \"○\",\n asteriskThird = false,\n markerHeight: number = bodyHeight,\n): LevelIndent {\n // 개조식은 실측 양식의 들여쓰기 체계(□ 0 / ○ 1자 / - 1.5자 …)를 따른다.\n if (numbering === \"gaejosik\") return gaejosikLevelIndent(depth, bodyHeight, sizes, bullet2)\n // 같은 단계는 부호 종류가 일정하므로 대표 부호(순번 0)의 폭으로 내어쓰기를 정한다.\n // 부호폭은 그 단계의 글자 크기(levels 오버라이드면 그 크기)로 — 둘째 줄이 내용 첫 글자에 정렬\n const marker = numbering === \"report\" ? reportMarker(depth, bullet2, asteriskThird) : standardMarker(depth, 0)\n return { left: Math.round(depth * bodyHeight), indent: -markerWidth(marker, markerHeight) }\n}\n\n// ─── 단일 형제 부호 생략(2-pass) ─────────────────────\n\n/**\n * 리스트 항목들의 (depth) 시퀀스를 받아, 각 항목의 '형제 수'를 계산.\n * 규정: 항목이 하나만 있으면 부호를 부여하지 않는다.\n * 같은 부모 아래 같은 depth 형제가 1개뿐이면 true(=부호 생략) 반환 배열.\n * (불릿 'report' 모드에는 적용하지 않는다 — 호출 측에서 분기.)\n *\n * 입력은 하나의 연속된 리스트(run)의 depth 배열.\n */\nexport function computeSuppression(depths: number[]): boolean[] {\n // groupKey(부모 경로) → 형제 수\n const counts = new Map<string, number>()\n const keys: string[] = []\n const path: number[] = [] // path[d] = depth d에서 현재까지 등장한 형제 순번\n for (const depth of depths) {\n path.length = depth + 1\n path[depth] = (path[depth] ?? 0) + 1\n const parentKey = path.slice(0, depth).join(\".\") + \"|\" + depth\n keys.push(parentKey)\n counts.set(parentKey, (counts.get(parentKey) ?? 0) + 1)\n }\n return keys.map((k) => (counts.get(k) ?? 0) <= 1)\n}\n\n// ─── 마커 카운터(렌더 시 형제 순번 추적) ──────────────\n\n/**\n * 리스트 run을 순회하며 depth별 카운터를 유지, 각 항목의 마커 문자열을 산출.\n * 상위 depth가 진행되면 하위 카운터는 리셋된다.\n */\nexport class GongmunNumberer {\n private counts: number[] = []\n constructor(\n private numbering: GongmunNumbering,\n private bullet2: \"ㅇ\" | \"○\" = \"○\",\n private asteriskThird = false,\n ) {}\n\n /** depth 항목 하나에 대한 마커. suppress=true면 빈 문자열(부호 없음) */\n next(depth: number, suppress: boolean): string {\n // 하위 depth 카운터 리셋\n this.counts.length = depth + 1\n const n = (this.counts[depth] ?? 0)\n this.counts[depth] = n + 1\n if (suppress) return \"\"\n if (this.numbering === \"gaejosik\") return gaejosikMarker(depth, this.bullet2)\n return this.numbering === \"report\"\n ? reportMarker(depth, this.bullet2, this.asteriskThird)\n : standardMarker(depth, n)\n }\n\n reset(): void {\n this.counts = []\n }\n}\n\n// ─── HWPUNIT 환산 ───────────────────────────────────\n\n// 정의는 geometry.ts SSOT로 이동 (v4.0.5 P0-3) — 기존 소비처 호환 재수출\nexport { mmToHwpunit } from \"./geometry.js\"\n","/**\n * HWPX 생성 공유 상수·테마·XML 원자 (generator.ts에서 분리).\n * 네임스페이스, charPr/paraPr id 상수, 테마 해석, escapeXml, charPr/paraPr 조각.\n */\n\nexport const NS_SECTION = \"http://www.hancom.co.kr/hwpml/2011/section\"\nexport const NS_PARA = \"http://www.hancom.co.kr/hwpml/2011/paragraph\"\nexport const NS_HEAD = \"http://www.hancom.co.kr/hwpml/2011/head\"\nexport const NS_CORE = \"http://www.hancom.co.kr/hwpml/2011/core\"\nexport const NS_OPF = \"http://www.idpf.org/2007/opf/\"\nexport const NS_HPF = \"http://www.hancom.co.kr/schema/2011/hpf\"\nexport const NS_OCF = \"urn:oasis:names:tc:opendocument:xmlns:container\"\n\n// ─── 스타일 ID 매핑 ─────────────────────────────────\n// charPr: 0=본문, 1=볼드, 2=이탤릭, 3=볼드이탤릭, 4=인라인코드, 5=h1, 6=h2, 7=h3, 8=h4~h6, 9=표 헤더 셀, 10=인용문\n// paraPr: 0=본문, 1=h1, 2=h2, 3=h3, 4=h4~h6, 5=코드블록, 6=인용문, 7=리스트\n\nexport const CHAR_NORMAL = 0\nexport const CHAR_BOLD = 1\nexport const CHAR_ITALIC = 2\nexport const CHAR_BOLD_ITALIC = 3\nexport const CHAR_CODE = 4\nexport const CHAR_H1 = 5\nexport const CHAR_H2 = 6\nexport const CHAR_H3 = 7\nexport const CHAR_H4 = 8\nexport const CHAR_TABLE_HEADER = 9\nexport const CHAR_QUOTE = 10\n\nexport const PARA_NORMAL = 0\nexport const PARA_H1 = 1\nexport const PARA_H2 = 2\nexport const PARA_H3 = 3\nexport const PARA_H4 = 4\nexport const PARA_CODE = 5\nexport const PARA_QUOTE = 6\nexport const PARA_LIST = 7\n\n/** HWPX 생성 시 적용할 시각 테마 (모두 선택) */\nexport interface HwpxTheme {\n /**\n * 헤딩 레벨별 텍스트 색상. 미지정 시 검정.\n * 현재 charPr 매핑은 h1/h2/h3/h4 4단계 (h5, h6은 h4와 같은 charPr 공유)이므로\n * 키는 1~4만 받는다.\n */\n headingColors?: Partial<Record<1 | 2 | 3 | 4, string>>\n /** 본문 단락 텍스트 색상. 미지정 시 검정 */\n bodyColor?: string\n /**\n * 인용문 텍스트 색상. 미지정 시 검정.\n *\n * 주의: 이 옵션을 지정하면 인용문이 별도 charPr(이탤릭)로 렌더링된다.\n * 미지정 시 기존 동작 그대로 본문 charPr로 렌더링 (이탤릭 아님).\n */\n quoteColor?: string\n /** 표 첫 행 텍스트 색상. 미지정 시 본문과 동일 */\n tableHeaderColor?: string\n /** 표 첫 행 텍스트를 굵게 표시 (기본 false) */\n tableHeaderBold?: boolean\n}\n\nconst DEFAULT_TEXT_COLOR = \"#000000\"\n\nexport function resolveTheme(theme?: HwpxTheme) {\n return {\n h1: theme?.headingColors?.[1] ?? DEFAULT_TEXT_COLOR,\n h2: theme?.headingColors?.[2] ?? DEFAULT_TEXT_COLOR,\n h3: theme?.headingColors?.[3] ?? DEFAULT_TEXT_COLOR,\n h4: theme?.headingColors?.[4] ?? theme?.headingColors?.[3] ?? DEFAULT_TEXT_COLOR,\n body: theme?.bodyColor ?? DEFAULT_TEXT_COLOR,\n quote: theme?.quoteColor ?? DEFAULT_TEXT_COLOR,\n /** quoteColor가 명시되었는지 — blockquote charPr 분기에 사용 (baseline 호환) */\n hasQuoteOption: theme?.quoteColor !== undefined,\n tableHeader: theme?.tableHeaderColor ?? theme?.bodyColor ?? DEFAULT_TEXT_COLOR,\n tableHeaderBold: !!theme?.tableHeaderBold,\n }\n}\n\nexport type ResolvedTheme = ReturnType<typeof resolveTheme>\n\n// ─── XML 생성 헬퍼 ───────────────────────────────────\n\nexport function escapeXml(text: string): string {\n return text\n // XML 1.0 금지 C0 제어문자 제거(탭 0x09·개행 0x0A·CR 0x0D는 유지) — 옵션 필드(두문·\n // 결문·결재란 등)에 섞이면 well-formed가 깨져 한컴이 파일을 못 연다\n .replace(/[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F]/g, \"\")\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n}\n\n/**\n * `<hp:t>` 본문용 이스케이프 — U+00A0(묶음 빈칸)은 한글 묶음 빈칸 요소 `<hp:nbSpace/>` 로 방출한다\n * (줄 끝에서 갈라지지 않는 공백. 실결재 법제처 서식의 \"1.<hp:nbSpace/>허가신청\" 꼴). 속성값에는 escapeXml 을 쓸 것.\n */\nexport function escapeTextXml(text: string): string {\n return escapeXml(text).replace(/\\u00a0/g, \"<hp:nbSpace/>\")\n}\n\nexport function headingParaPrId(level: number): number {\n if (level === 1) return PARA_H1\n if (level === 2) return PARA_H2\n if (level === 3) return PARA_H3\n return PARA_H4\n}\n\nexport function headingCharPrId(level: number): number {\n if (level === 1) return CHAR_H1\n if (level === 2) return CHAR_H2\n if (level === 3) return CHAR_H3\n return CHAR_H4\n}\n\n\nexport function charPr(\n id: number,\n height: number,\n bold: boolean,\n italic: boolean,\n fontId: number = 0,\n textColor: string = DEFAULT_TEXT_COLOR,\n ratioPct: number = 100,\n restFont: number = fontId,\n spacingPct: number = 0,\n): string {\n const boldAttr = bold ? ` bold=\"1\"` : \"\"\n const italicAttr = italic ? ` italic=\"1\"` : \"\"\n // 볼드여도 폰트는 치환하지 않는다 — 종전의 bold variant(HY견고딕/Arial Black) 자동\n // 참조는 v4.0.1 QA에서 \"정체모를 폰트\"로 확정된 결함 (실측 양식들도 원 폰트에\n // bold 요소만 얹는다). 굵기는 아래 <hh:bold/> 정본 요소가 담당.\n const effFont = fontId\n // 볼드 정본은 <hh:bold/> 자식 요소 — 실측 한컴 파일은 속성 없이 요소만 쓴다.\n // 속성(bold=\"1\")은 하위 호환으로 병기 (Windows 한컴 구버전이 속성을 읽던 경로 유지).\n const boldEl = bold ? `<hh:bold/>` : \"\"\n // 장평(ratio): 공문서 본문은 95%로 가로 압축 — 한두 글자만 다음 줄로 넘어가는\n // orphan을 줄여 한 줄에 담는다(실제 공문서 관행). 한글·라틴만, 나머지는 100.\n return ` <hh:charPr id=\"${id}\" height=\"${height}\" textColor=\"${escapeXml(textColor)}\" shadeColor=\"none\" useFontSpace=\"0\" useKerning=\"0\" symMark=\"NONE\" borderFillIDRef=\"1\"${boldAttr}${italicAttr}>\n <hh:fontRef hangul=\"${effFont}\" latin=\"${effFont}\" hanja=\"${restFont}\" japanese=\"${restFont}\" other=\"${restFont}\" symbol=\"${restFont}\" user=\"${restFont}\"/>\n <hh:ratio hangul=\"${ratioPct}\" latin=\"${ratioPct}\" hanja=\"${ratioPct}\" japanese=\"100\" other=\"100\" symbol=\"100\" user=\"100\"/>\n <hh:spacing hangul=\"${spacingPct}\" latin=\"${spacingPct}\" hanja=\"${spacingPct}\" japanese=\"0\" other=\"0\" symbol=\"0\" user=\"0\"/>\n <hh:relSz hangul=\"100\" latin=\"100\" hanja=\"100\" japanese=\"100\" other=\"100\" symbol=\"100\" user=\"100\"/>\n <hh:offset hangul=\"0\" latin=\"0\" hanja=\"0\" japanese=\"0\" other=\"0\" symbol=\"0\" user=\"0\"/>${boldEl}\n </hh:charPr>`\n}\n\n// ─── paraPr 생성 헬퍼 ───────────────────────────────\n\nexport function paraPr(id: number, opts: { align?: string; spaceBefore?: number; spaceAfter?: number; lineSpacing?: number; indent?: number; left?: number; right?: number; keepWord?: boolean; keepWithNext?: boolean; outlineLevel?: number; autoTab?: boolean; widowOrphan?: boolean } = {}): string {\n const { align = \"JUSTIFY\", spaceBefore = 0, spaceAfter = 0, lineSpacing = 160, indent = 0, left = 0, right = 0, keepWord = false, keepWithNext = false, outlineLevel, autoTab = false, widowOrphan = false } = opts\n // keepWord=true면 한글도 어절(단어) 단위로만 줄바꿈 — 단어 중간에서 끊기지 않음.\n // 주의: breakNonLatinWord의 한컴 실구현 의미는 이름과 반대다 —\n // \"BREAK_WORD\"=어절 유지, \"KEEP_WORD\"=글자 단위 (2026-07 한글 COM 실렌더 A/B 실측.\n // 한글 기본값 '글자'가 KEEP_WORD로 저장되는 정본 양식과도 일치).\n // breakLatinWord는 이름대로 KEEP_WORD=단어 유지.\n // snapToGrid는 줄나눔과 무관함이 같은 실측에서 확인됨(섹션 격자 자체가 꺼져 있음).\n const breakNonLatin = keepWord ? \"BREAK_WORD\" : \"KEEP_WORD\"\n const snapGrid = keepWord ? \"0\" : \"1\"\n // outlineLevel(0-based) 지정 시 개요 문단 — 재파싱 헤딩 감지·한컴 문서 찾아가기의\n // 권위 정보. 번호 서식은 numbering id=1(빈 서식)이라 화면에 번호가 붙지 않는다.\n const heading = outlineLevel !== undefined\n ? `<hh:heading type=\"OUTLINE\" idRef=\"0\" level=\"${outlineLevel}\"/>`\n : `<hh:heading type=\"NONE\" idRef=\"0\" level=\"0\"/>`\n // autoTab: 내어쓰기용 자동 탭(tabPr 1, autoTabLeft) — 부호 뒤 탭이 내어쓰기 위치에 서서 첫 줄 내용이\n // 둘째 줄과 같은 x 에서 시작한다(양쪽 정렬이 부호 뒤 공백을 늘려 어긋나던 것 방지, v5 전용 — 헤더가 tabPr 을 방출할 때만)\n return ` <hh:paraPr id=\"${id}\" tabPrIDRef=\"${autoTab ? 1 : 0}\" condense=\"0\" fontLineHeight=\"0\" snapToGrid=\"${snapGrid}\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"AUTO\">\n <hh:align horizontal=\"${align}\" vertical=\"BASELINE\"/>\n ${heading}\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"${breakNonLatin}\" widowOrphan=\"${widowOrphan ? 1 : 0}\" keepWithNext=\"${keepWithNext ? 1 : 0}\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hh:margin><hc:intent value=\"${indent}\" unit=\"HWPUNIT\"/><hc:left value=\"${left}\" unit=\"HWPUNIT\"/><hc:right value=\"${right}\" unit=\"HWPUNIT\"/><hc:prev value=\"${spaceBefore}\" unit=\"HWPUNIT\"/><hc:next value=\"${spaceAfter}\" unit=\"HWPUNIT\"/></hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"${lineSpacing}\"/>\n <hh:border borderFillIDRef=\"1\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>`\n}\n\n// ─── 공문서 모드 paraPr ID 매핑 ──────────────────────\n// 공문서 모드에서는 기존 0~7 paraPr 뒤에 항목 단계별(8단계) paraPr를 추가한다.\n// 단계 d(0~7) → paraPrIDRef = GONGMUN_LIST_BASE + d\nexport const GONGMUN_LIST_BASE = 8\nexport const GONGMUN_LIST_LEVELS = 8\n// 본문 크기 가운데정렬 단락(발신명의 등) — 항목단계 paraPr 다음 id\nexport const GONGMUN_CENTER = GONGMUN_LIST_BASE + GONGMUN_LIST_LEVELS\n// 오른쪽정렬 단락(데이터 표 호스트·출처행 — 실측: GT6/GT7/GT11 표 우측 배치 관행) — CENTER 다음 id\nexport const GONGMUN_RIGHT = GONGMUN_CENTER + 1\n// 표 셀 전용 문단 — 실측(GT1 표⑪): 헤더 CENTER 130%·데이터 CENTER 120% 셀 압축 줄간격,\n// 장문 열은 LEFT(JUSTIFY 아님). 표 셀 CENTER 문단은 정답지 전반이 어절유지(BREAK_WORD)\nexport const GONGMUN_TBL_CENTER = GONGMUN_RIGHT + 1\nexport const GONGMUN_TBL_LEFT = GONGMUN_TBL_CENTER + 1\n\n// ─── 실측 폰트 프리셋(개조식·보고서·계획서) 전용 charPr id — 기본 11종(0~10) 뒤 11~25 ──\n// 부호·요소별 폰트/크기 분리 (실측: docs/gongmunseo-engine-spec.md, gaejosik.ts).\n// 보고서·계획서는 이 중 ※(13·14)·표 셀(22·23)·제목박스(25)를 사용 (id 공간은 통일 등록)\nexport const GJ_CHAR_DAE = 11 // □ 대항목 — HY헤드라인M 16pt\nexport const GJ_CHAR_DAE_BOLD = 12 // □ 안 강조 — HY헤드라인M 16pt bold\nexport const GJ_CHAR_CHAM = 13 // ※ 참고 — 한양중고딕 13pt\nexport const GJ_CHAR_CHAM_BOLD = 14 // ※ 안 강조 — 한양중고딕 13pt bold\nexport const GJ_CHAR_CHAPTER_NUM = 15 // 장 헤더 로마숫자 — 휴먼명조 17pt bold 흰색\nexport const GJ_CHAR_CHAPTER_TITLE = 16 // 장 헤더 제목 — HY헤드라인M 17pt\nexport const GJ_CHAR_COVER_TITLE = 17 // 표지 제목 — HY헤드라인M 30pt\nexport const GJ_CHAR_COVER_SUB = 18 // 표지 날짜·기관명 — HY헤드라인M 25pt\nexport const GJ_CHAR_TOC_LABEL = 19 // \"목 차\" — HY헤드라인M 28pt bold\nexport const GJ_CHAR_TOC_ROMAN = 20 // 목차 로마숫자 — 한양신명조 21pt bold\nexport const GJ_CHAR_TOC_ITEM = 21 // 목차 항목 — HY헤드라인M 18pt\nexport const GJ_CHAR_TABLE = 22 // 표 셀 본문 — 맑은 고딕 12pt (실측: 정부 양식 표)\nexport const GJ_CHAR_TABLE_BOLD = 23 // 표 셀 강조 — 맑은 고딕 12pt bold\nexport const GJ_CHAR_BAR = 24 // 표지 장식 바 셀 빈 문단 — 6pt (실측: 셀 높이 818 수납용)\nexport const GJ_CHAR_BODY_TITLE = 25 // 본문 첫 페이지 제목 박스 — HY헤드라인M 22pt (실측: GT3 표④)\nexport const GJ_CHAR_TITLE_BAR = 26 // 1페이지형 제목박스 382HU 바 스페이서 — 1pt\nexport const GJ_CHAR_APPROVAL = 27 // 결재란 직위 라벨 — 굴림 계열 10pt\nexport const GJ_CHAR_SRC = 28 // 출처행 캡션 — 한양중고딕 본문-3pt (srcCaptionPt)\nexport const GJ_CHAR_SRC_BOLD = 29 // 출처행 캡션 bold\n// 블록 크기는 첫·끝 명명 id에서 파생 — 수기 카운트 드리프트 방지 (v4.0.5 P0-1).\n// 새 GJ_CHAR_*를 끝에 추가하면 자동 반영되지만, buildCharProperties 방출 행과의\n// 일치는 charVariantBase 런타임 불변식(gen-header)이 검증한다.\nconst GJ_CHAR_COUNT = GJ_CHAR_SRC_BOLD - GJ_CHAR_DAE + 1\n\n// ─── 개조식 전용 paraPr id — 공통(0~7)+단계(8~15)+CENTER(16)+RIGHT(17)+표셀(18·19) 뒤 20~24 ──\n// v4.0.2부터 id 연속성을 위해 전 공문서 프리셋이 이 블록을 방출한다 (비개조식은 20만 사용)\nexport const GJ_PARA_CHAM = 20 // ※ 참고 문단 (들여쓰기 + 문단 위 3pt)\nexport const GJ_PARA_COVER = 21 // 표지 제목·날짜·기관명 (CENTER, 줄간격 130)\nexport const GJ_PARA_TOC_ITEM = 22 // 목차 항목\nexport const GJ_PARA_CHAPTER = 23 // 장 헤더 표 호스트 문단 (문단 위 간격)\nexport const GJ_PARA_BAR = 24 // 표지 장식 바 셀 빈 문단 (줄간격 70% — 실측 71%)\nexport const GJ_PARA_COUNT = 5\n\n// ─── 부호 생략 항목 전용 paraPr — 25~32 (v4.0.2) ──\n// 단일 형제 규정으로 부호가 생략된 항목이 depth 공용 paraPr(음수 내어쓰기)를 쓰면\n// 있지도 않은 부호 폭만큼 둘째 줄이 더 들어간다(유령 내어쓰기 — 실렌더 QA 확인).\n// left는 단계 동일, 내어쓰기 0인 전용 세트.\nexport const GONGMUN_LIST_PLAIN_BASE = 25\n\n// ─── 결재란 라벨 셀 paraPr — 33 (부호생략 25~32 뒤) ──\n// 실측 결재선(approval-main): 라벨 lineSp 100%. 1pt 바 스페이서용 GJ_PARA_BAR(70%)를\n// 재사용하면 긴 라벨 줄바꿈 시 줄이 겹친다 — 보이는 텍스트는 전용 100% paraPr로.\nexport const GONGMUN_PARA_APPROVAL = GONGMUN_LIST_PLAIN_BASE + GONGMUN_LIST_LEVELS\n\n// ─── 장문 <right> 폴백 왼쪽정렬 paraPr — 34 ──\n// 출처행 등 <right> 문단이 본문폭을 넘겨 줄바꿈되면 RIGHT 정렬은 왼쪽 끝이\n// 들쭉날쭉해져 들여쓰기가 깨진 듯 보인다(한글 실렌더 QA — 제주 보고서 출처 3줄).\n// 우측 배치 관행(GT6/GT7/GT11)은 한 줄 출처행 실측이므로, 넘치는 문단만 LEFT로.\nexport const GONGMUN_SRC_LEFT = GONGMUN_PARA_APPROVAL + 1\n\n// ─── (depth, 부호폭) 내어쓰기 변형 paraPr — 35~ (v4.0.5 P1-1) ──\n// 법정 번호 두 자리 이상('10.'·'10)'·'(10)') 항목 전용 — depth 공용 paraPr의 대표\n// 부호('1.') 내어쓰기로는 둘째 줄이 내용 첫 글자보다 ~0.55타 왼쪽으로 어긋난다.\n// 문서에 해당 항목이 있을 때만 발급(gongmunList.indentVariants — 기본 산출물 불변)\nexport const GONGMUN_LIST_VARIANT_BASE = GONGMUN_SRC_LEFT + 1\n\n// ─── 개조식 전용 borderFill id — 기본 2종(1·2) 뒤 3~9 ──\nexport const GJ_BF_CHAPTER_NUM = 3 // 장헤더 로마숫자 셀 — #193AAA 음영 + #006699 테두리\nexport const GJ_BF_CHAPTER_GAP = 4 // 장헤더 간격 셀 — #006699 좌선만\nexport const GJ_BF_CHAPTER_TITLE = 5 // 장헤더 제목 셀 — #F2F2F2 음영 + 회색 상하선\nexport const GJ_BF_BAR_DARK = 6 // 표지 진한 바 — #193AAA\nexport const GJ_BF_BAR_LIGHT = 7 // 표지 연한 바 — #A0B4E6\nexport const GJ_BF_TOC_BOX = 8 // 목차 박스 — 0.4mm #514BAC\nexport const GJ_BF_TOC_STRIPE = 9 // 목차 배너 라벤더 스트라이프 — #E0E5FA (실측: GT3 표②)\n\n// ─── 공문서 표 헤더행 음영 borderFill (실측: 정부 양식 표 헤더 #E6E6E6) ──\n// 개조식 자산(표지·목차 포함)을 쓰면 전용 3~9 뒤 10, 그 외는 기본 1·2 뒤 3\nexport function gongmunTableHeaderBf(richAssets: boolean): number {\n return richAssets ? 10 : 3\n}\n\n// ─── borderFill XML 원자 ─────────────────────────────\n\n/** 테두리 변 스펙 — [굵기, 색] 또는 [굵기, 색, 선종류(SOLID·DOUBLE_SLIM·DASH)] */\nexport type BorderSide = [string, string] | [string, string, string]\n\n/**\n * borderFill 한 항목 — 네 변 지정 + 선택적 채움(단색 또는 gradient).\n * gradient는 실측 정부 문서 제목박스 하단 바(RADIAL #0080C0→#3CBFFF, GT6 원문) 스펙.\n */\nexport function borderFillEntry(\n id: number,\n b: { l?: BorderSide; r?: BorderSide; t?: BorderSide; b?: BorderSide },\n fill?: string | { gradient: string[]; type?: \"LINEAR\" | \"RADIAL\"; angle?: number },\n): string {\n const side = (name: string, v?: BorderSide) =>\n v\n ? ` <hh:${name} type=\"${v[2] ?? \"SOLID\"}\" width=\"${v[0]}\" color=\"${v[1]}\"/>`\n : ` <hh:${name} type=\"NONE\" width=\"0.1 mm\" color=\"#000000\"/>`\n let brush = \"\"\n if (typeof fill === \"string\") {\n brush = `\\n <hc:fillBrush><hc:winBrush faceColor=\"${fill}\" hatchColor=\"#000000\" alpha=\"0\"/></hc:fillBrush>`\n } else if (fill) {\n // LINEAR angle 90 = 위→아래(업무보고 장 띠 #D6EAFE→#FFFFFF). 2색만 — colorNum 3 은 한글 2024 COM 실렌더에서\n // 셀이 검게 칠해진다(2026-09-15 A/B: 3색·step 255 ✗, 2색·step 50 ✓)\n const type = fill.type ?? \"RADIAL\"\n const colors = fill.gradient.slice(0, 2).map((c) => `<hc:color value=\"${c}\"/>`).join(\"\")\n brush = `\\n <hc:fillBrush><hc:gradation type=\"${type}\" angle=\"${fill.angle ?? 0}\" centerX=\"0\" centerY=\"0\" step=\"50\" colorNum=\"2\" stepCenter=\"50\" alpha=\"0\">${colors}</hc:gradation></hc:fillBrush>`\n }\n return ` <hh:borderFill id=\"${id}\" threeD=\"0\" shadow=\"0\" centerLine=\"NONE\" breakCellSeparateLine=\"0\">\n <hh:slash type=\"NONE\" Crooked=\"0\" isCounter=\"0\"/>\n <hh:backSlash type=\"NONE\" Crooked=\"0\" isCounter=\"0\"/>\n${side(\"leftBorder\", b.l)}\n${side(\"rightBorder\", b.r)}\n${side(\"topBorder\", b.t)}\n${side(\"bottomBorder\", b.b)}${brush}\n </hh:borderFill>`\n}\n\n// ─── 쪽번호·쪽번호 리셋 ctrl (실측: GT3 「2_보고서 양식」 원문) ──\n\n/** 쪽번호 매기기 ctrl — 하단 중앙 \"- 1 -\" 형식. run 안 secPr 뒤에 배치 */\nexport function pageNumCtrl(): string {\n return `<hp:ctrl><hp:pageNum pos=\"BOTTOM_CENTER\" formatType=\"DIGIT\" sideChar=\"-\"/></hp:ctrl>`\n}\n\n/** 새 쪽번호 시작 ctrl — 표지·목차를 카운트에서 제외하고 본문을 1쪽으로 */\nexport function newPageNumCtrl(num: number = 1): string {\n return `<hp:ctrl><hp:newNum num=\"${num}\" numType=\"PAGE\"/></hp:ctrl>`\n}\n\n/** 쪽번호 숨김 ctrl — 표지·목차 페이지 전용 (실측: GT3 pageHiding ×2) */\nexport function pageHidingCtrl(hideHeader: boolean = false): string {\n return `<hp:ctrl><hp:pageHiding hideHeader=\"${hideHeader ? 1 : 0}\" hideFooter=\"0\" hideMasterPage=\"0\" hideBorder=\"0\" hideFill=\"0\" hidePageNum=\"1\"/></hp:ctrl>`\n}\n\n// ─── 비실측 공문서 표 셀 charPr — 11·12 (v4.0.2) ──\n// 실결재 기안문 실측: 표 셀은 11~12pt가 지배(굴림체12·맑은고딕11).\n// 본문 크기 셀은 열폭이 부족해 서술 열이 세로로 길어진다 (실렌더 QA).\n// 실측 프리셋은 GJ_CHAR_TABLE(22·23, 맑은 고딕 12pt)을 그대로 쓴다.\nexport const GONGMUN_TBL_CHAR = 11\nexport const GONGMUN_TBL_CHAR_BOLD = 12\n/** 비실측 공문서 표 셀 크기 — 12pt (실결재 실측 지배값) */\nexport const GONGMUN_TBL_PT = 1200\nexport const GONGMUN_TITLE_BAR_CHAR = 13\nexport const GONGMUN_APPROVAL_CHAR = 14\n// 출처행(<right> '출처:'·'자료:') 전용 — 본문보다 3pt 작은 캡션체 (실무 보고서 관행:\n// 표 아래 출처는 본문과 구분되는 작은 글씨. 실측 프리셋은 한양중고딕, 비실측은 본문 폰트)\nexport const GONGMUN_SRC_CHAR = 15\nexport const GONGMUN_SRC_CHAR_BOLD = 16\n\n/** 출처행 캡션 크기 — 본문 -3pt, 하한 10pt (gen-header 방출·gen-section 폭 판정 공용) */\nexport function srcCaptionPt(bodyHeight: number): number {\n return Math.max(bodyHeight - 300, 1000)\n}\n\n// ─── 공문서 자동 장평(orphan 축소) ───────────────────\n// 기본 charPr 11종(0~10) 뒤에, 자동 장평이 필요한 문단용 변형 charPr를 붙인다.\n// 비공문서는 11부터(종전과 동일). 비실측 공문서는 표 셀 2종(11·12)이 먼저 와 13부터.\n// 실측 폰트 프리셋(개조식·보고서·계획서)은 전용 charPr 15종(11~25)이 먼저 오므로 26부터.\n// 변형 vi번째 장평 r → charPr id = charVariantBase + vi×4 + (0 본문|1 볼드|2 이탤릭|3 볼드이탤릭)\nexport const CHAR_VARIANT_BASE = CHAR_QUOTE + 1\nexport function charVariantBase(richAssets: boolean, isGongmun: boolean = true): number {\n if (!isGongmun) return CHAR_VARIANT_BASE\n // 비실측 공문서 전용 블록(표 셀 2 + 제목바 + 결재란 + 출처행 2) 크기도 명명 상수에서 파생\n return richAssets\n ? CHAR_VARIANT_BASE + GJ_CHAR_COUNT\n : CHAR_VARIANT_BASE + (GONGMUN_SRC_CHAR_BOLD - GONGMUN_TBL_CHAR + 1)\n}\n/** 공문서 본문 기본 장평(%) — 실제 공문서 관행 (v3.5.3) */\nexport const GONGMUN_BODY_RATIO = 95\n","/**\n * 마크다운 파싱 + hwpx run/문단 XML 생성 (generator.ts에서 분리).\n * 블록 분해(parseMarkdownToBlocks), 인라인 span, run/문단 조립, PrvText.\n */\n\nimport {\n CHAR_NORMAL, CHAR_BOLD, CHAR_ITALIC, CHAR_BOLD_ITALIC, CHAR_CODE,\n PARA_NORMAL, PARA_CODE,\n escapeXml, escapeTextXml,\n} from \"./gen-ids.js\"\nimport { sanitizeHref } from \"../utils.js\"\n\n// ─── 인라인 문서 컨텍스트 — 하이퍼링크·각주 (v4.5.0) ──\n//\n// markdownToHwpx가 문서 시작에 beginInlineDoc으로 열고 끝에 endInlineDoc으로 닫는다.\n// 컨텍스트가 없으면(직접 호출 경로) 종전 동작 그대로 — 링크는 anchor 텍스트로,\n// [^id]는 리터럴로 남는다. 카운터는 문서마다 리셋돼 출력이 결정적이다.\n\n/** HYPERLINK 필드 공통 fieldid — 실측 저장본 공통값 (nrich·seoul2) */\nconst HYPERLINK_FIELDID = 627600491\nconst FIELD_ID_BASE = 1_800_000_000\nconst FOOTNOTE_INST_BASE = 1_850_000_000\n\ninterface InlineDocCtx {\n footnotes: Map<string, string>\n fieldSeq: number\n noteSeq: number\n /** 각주 본문 렌더 중 — 중첩 각주 마커는 리터럴 유지 (자기참조 재귀 차단) */\n inNote: boolean\n}\n\nlet inlineDoc: InlineDocCtx | null = null\n\n/** 문서 단위 인라인 채널 시작 — 각주 정의 주입 + 필드/각주 카운터 리셋 */\nexport function beginInlineDoc(footnotes: Map<string, string>): void {\n inlineDoc = { footnotes, fieldSeq: 0, noteSeq: 0, inNote: false }\n}\n\nexport function endInlineDoc(): void {\n inlineDoc = null\n}\n\n/**\n * 각주 정의 수집 — `[^id]: 본문` 줄을 걷어내고 map으로 반환.\n * 본문 마커 `[^id]`는 parseInlineMarkdown이 footNote 개체로 방출한다.\n */\nexport function extractFootnoteDefs(md: string): { md: string; defs: Map<string, string> } {\n const defs = new Map<string, string>()\n const out = md.replace(/\\r\\n?/g, \"\\n\").split(\"\\n\").filter(line => {\n const m = /^\\[\\^([^\\]\\s]+)\\]:\\s?(.*)$/.exec(line)\n if (!m) return true\n defs.set(m[1], m[2].trim())\n return false\n }).join(\"\\n\")\n return { md: defs.size > 0 ? out : md, defs }\n}\n\n\n/** Preview/PrvText.txt — 문서 앞부분 텍스트 스냅샷 (최대 1KB) */\nexport function buildPrvText(blocks: MdBlock[]): string {\n const lines: string[] = []\n let bytes = 0\n for (const b of blocks) {\n let text = b.text || (b.rows ? b.rows.map(r => r.join(\" \")).join(\"\\n\") : \"\")\n if (b.type === \"code_block\" && (b.lang || \"\").toLowerCase() === \"chart\") text = \"[차트]\" // DSL 원문 노출 방지\n else if (b.type === \"html_table\") text = text.replace(/<[^>]+>/g, \" \").replace(/\\s+/g, \" \").trim()\n if (!text) continue\n lines.push(text)\n bytes += text.length * 3\n if (bytes > 1024) break\n }\n return lines.join(\"\\n\").slice(0, 1024)\n}\n\n\n\nexport interface MdBlock {\n type: \"paragraph\" | \"heading\" | \"table\" | \"html_table\" | \"code_block\" | \"equation\" | \"hr\" | \"blockquote\" | \"list_item\"\n text?: string\n level?: number\n rows?: string[][]\n lang?: string\n ordered?: boolean\n indent?: number\n /** 리스트 원본 마커 (\"2.\" \"3)\" \"-\" \"*\" 등) — 왕복 시 번호 재시작·기호 변형 방지 */\n marker?: string\n}\n\n/**\n * 붙임 머리 — 실측 표기는 \"붙임\", \"붙 임\"(글자 사이 띄움), \"붙임 :\" 세 꼴이다.\n * 편람은 붙임 뒤 쌍점을 쓰지 않지만(gongmun-lint BUNIM_COLON) 실물에 존재하므로\n * 검출은 받아들이고 교정은 표기법 검수에 맡긴다.\n */\nconst BUNIM_HEAD = /^붙\\s*임(?:\\s|:|$)/\n\n/** 이스케이프(\\$$) 아닌 \"$$\" 위치 탐색 — 백슬래시 홀수 개 선행이면 이스케이프로 본다 */\nfunction findMathDelim(s: string, from: number): number {\n let i = s.indexOf(\"$$\", from)\n while (i > 0) {\n let backslashes = 0\n for (let j = i - 1; j >= 0 && s[j] === \"\\\\\"; j--) backslashes++\n if (backslashes % 2 === 0) break\n i = s.indexOf(\"$$\", i + 1)\n }\n return i\n}\n\nexport function parseMarkdownToBlocks(md: string): MdBlock[] {\n // CRLF/CR(Windows·구 Mac 작성 .md) → LF 정규화 — \\r 잔류 시 fence/heading/list 정규식이\n // 줄 끝에서 매치 실패해 전멸한다 (chart-3: ```chart 원문이 본문으로 인쇄되는 광역 결함)\n const lines = md.replace(/\\r\\n?/g, \"\\n\").split(\"\\n\")\n const blocks: MdBlock[] = []\n let i = 0\n // 리스트 들여쓰기 스택 — depth별 물리 들여쓰기(칸 수)를 보관. 리스트 run이 끊기면 초기화 (v4.0.5)\n const listStack: number[] = []\n // 붙임 블록 안인지 — 붙임 머리부터 빈 줄까지 (리스트 재해석 중지 구간)\n let inBunim = false\n\n while (i < lines.length) {\n const line = lines[i]\n\n // 빈 줄 스킵\n if (!line.trim()) { inBunim = false; i++; continue }\n\n // Display math block: $$ ... $$ — 같은 줄 닫힘/멀티라인/닫는 $$ 뒤 잔여 텍스트를\n // 모두 처리하고, 미종결이면 아래 일반 파이프라인으로 폴백한다 (문서 통삼킴 방지,\n // 리뷰 #39 ·1/·6). 이스케이프된 \\$$ 는 여닫이로 세지 않는다 (escapeGfm 접점).\n const mathOpen = /^\\s*\\$\\$/.exec(line)\n if (mathOpen) {\n const afterOpen = line.slice(mathOpen[0].length)\n const closeSame = findMathDelim(afterOpen, 0)\n if (closeSame >= 0) {\n const inner = afterOpen.slice(0, closeSame).trim()\n const trailing = afterOpen.slice(closeSame + 2).trim()\n if (inner) blocks.push({ type: \"equation\", text: inner })\n if (trailing) blocks.push({ type: \"paragraph\", text: trailing })\n i++\n continue\n }\n // 멀티라인 수집 — 빈 줄/코드펜스를 만나면 미종결로 판정 (거리 무제한 삼킴 방지)\n const mathLines: string[] = []\n if (afterOpen.trim()) mathLines.push(afterOpen)\n let closed = false\n let trailing = \"\"\n let j = i + 1\n for (; j < lines.length; j++) {\n const l = lines[j]\n if (!l.trim() || /^\\s*(`{3,}|~{3,})/.test(l)) break\n const end = findMathDelim(l, 0)\n if (end >= 0) {\n const before = l.slice(0, end)\n if (before.trim()) mathLines.push(before)\n trailing = l.slice(end + 2).trim()\n closed = true\n j++\n break\n }\n mathLines.push(l)\n }\n if (closed) {\n const text = mathLines.join(\"\\n\").trim()\n if (text) blocks.push({ type: \"equation\", text })\n if (trailing) blocks.push({ type: \"paragraph\", text: trailing })\n i = j\n continue\n }\n // 미종결 — 수식 아님. 이 줄부터 일반 블록으로 처리 (통과)\n }\n\n // 코드블록\n const fenceMatch = line.match(/^ {0,3}(`{3,}|~{3,})(.*)$/)\n if (fenceMatch) {\n const fence = fenceMatch[1]\n const lang = fenceMatch[2].trim()\n const codeLines: string[] = []\n i++\n // 여는·닫는 펜스 모두 ≤3칸 들여쓰기 허용 (CommonMark — 리스트 하위 차트 관행)\n while (i < lines.length && !lines[i].replace(/^ {0,3}/, \"\").startsWith(fence)) {\n codeLines.push(lines[i])\n i++\n }\n if (i < lines.length) i++ // 닫는 fence\n blocks.push({ type: \"code_block\", text: codeLines.join(\"\\n\"), lang })\n continue\n }\n\n // 수평선\n if (/^(\\*{3,}|-{3,}|_{3,})\\s*$/.test(line.trim())) {\n blocks.push({ type: \"hr\" })\n i++; continue\n }\n\n // 헤딩\n const headingMatch = line.match(/^(#{1,6})\\s+(.+)$/)\n if (headingMatch) {\n blocks.push({ type: \"heading\", text: headingMatch[2].trim(), level: headingMatch[1].length })\n i++; continue\n }\n\n // HTML 표 (병합·중첩 — kordoc parse가 병합/중첩표를 내보내는 형식)\n // 짝이 안 맞으면(닫는 </table> 부재) 수식 블록 관례처럼 일반 파이프라인으로\n // 폴백 — 문서 잔여 전체가 EOF까지 통째로 삼켜지는 것 방지\n if (/^<table[\\s>]/i.test(line.trimStart())) {\n const htmlLines: string[] = []\n let depth = 0\n let closed = false\n let j = i\n while (j < lines.length) {\n const l = lines[j]\n htmlLines.push(l)\n depth += (l.match(/<table[\\s>]/gi) ?? []).length\n depth -= (l.match(/<\\/table>/gi) ?? []).length\n j++\n if (depth <= 0) { closed = true; break }\n }\n if (closed) {\n blocks.push({ type: \"html_table\", text: htmlLines.join(\"\\n\") })\n i = j\n continue\n }\n // 미종결 — HTML 표 아님. 이 줄부터 일반 블록으로 처리 (통과)\n }\n\n // 테이블\n if (line.trimStart().startsWith(\"|\")) {\n const tableRows: string[][] = []\n let sepSeen = false\n while (i < lines.length && lines[i].trimStart().startsWith(\"|\")) {\n const row = lines[i]\n // 구분행 판정 — GFM처럼 헤더 직후(2행째) 1회만 인정. 각 구분 셀은 `:?-+:?` 꼴\n // (- 최소 1개 — `:-:` 정렬 표기 허용). 전부 빈 데이터 행 `| | |` 오인 방지는\n // 유지되고(- 필수), 본문 위치의 `| - | - |`('해당없음' 표기)는 데이터 행으로 보존\n if (tableRows.length === 1 && !sepSeen) {\n const sepCells = row.trim().replace(/^\\|/, \"\").replace(/\\|$/, \"\").split(\"|\")\n if (sepCells.every(c => /^\\s*:?-+:?\\s*$/.test(c))) { sepSeen = true; i++; continue }\n }\n // 이스케이프되지 않은 | 로만 분할 + 셀 내 \\| → | 복원 (parseGfmTable과 동일)\n const cells = row.split(/(?<!\\\\)\\|/).slice(1, -1).map(c => c.trim().replace(/\\\\\\|/g, \"|\"))\n if (cells.length > 0) tableRows.push(cells)\n i++\n }\n if (tableRows.length > 0) blocks.push({ type: \"table\", rows: tableRows })\n continue\n }\n\n // 인용문 — 공백줄 없는 연속 > 라인은 한 블록으로 조인(개행 결합 — 줄 경계 보존),\n // 빈 > 줄에서만 분리. 개조식 프리셋에서 줄마다 ※ 참고로 쪼개지는 것 방지 (v4.0.5).\n // 렌더가 분기: 실측 프리셋은 ※ 1문단(공백 결합), 기본은 줄별 문단(종전 시각 유지)\n if (line.trimStart().startsWith(\"> \")) {\n const quoteLines: string[] = []\n while (i < lines.length && (lines[i].trimStart().startsWith(\"> \") || lines[i].trimStart().startsWith(\">\"))) {\n quoteLines.push(lines[i].replace(/^>\\s?/, \"\").trim())\n i++\n }\n let joined: string[] = []\n for (const ql of quoteLines) {\n if (ql) { joined.push(ql); continue }\n if (joined.length) blocks.push({ type: \"blockquote\", text: joined.join(\"\\n\") })\n joined = []\n }\n if (joined.length) blocks.push({ type: \"blockquote\", text: joined.join(\"\\n\") })\n continue\n }\n\n // ── 붙임 블록 (v4.10) ──────────────────────────────────────────────\n // 실측(코퍼스 343건): 붙임은 본문과 한 줄 띄우고(95%), 여러 건이면 '1. 2. 3.' 번호를\n // 그대로 쓴다 — 항목부호(ㆍ·○)로 치환된 사례는 0건이다. 아래 리스트 판정에 걸리면\n // 들여쓴 '2. …' 줄이 depth 리스트로 잡혀 번호가 부호로 바뀌며 사라지므로(실측 결함:\n // \"2. 건축물대장…\" → \"ㆍ 건축물대장…\"), 붙임 줄부터 빈 줄까지는 리스트 재해석을 멈춘다.\n if (BUNIM_HEAD.test(line.trim())) inBunim = true\n if (inBunim) {\n // 붙임 머리 앞은 빈 문단 한 줄 — 실측 관행(간격은 문단 속성이 아니라 빈 줄로 만든다)\n if (BUNIM_HEAD.test(line.trim())) {\n const prevBlock = blocks[blocks.length - 1]\n if (blocks.length && !(prevBlock.type === \"paragraph\" && !prevBlock.text)) {\n blocks.push({ type: \"paragraph\", text: \"\" })\n }\n }\n // 둘째 항목부터의 선행 공백은 지우지 않는다 — 실측 123건 중 122건(99%)이 '2.' 앞에\n // 공백을 넣어 '붙임 1.'의 번호와 세로로 맞춘다(대개 6칸: '붙임'2자+2타 ≈ 2.94em,\n // 공백 6칸 3.0em). paraPr 내어쓰기로 맞춘 사례는 사실상 없다. 후행 공백만 정리한다.\n blocks.push({ type: \"paragraph\", text: line.replace(/\\s+$/, \"\") })\n listStack.length = 0\n i++; continue\n }\n\n // 리스트 — 선두 탭은 2칸 상당으로 확장(이 코드베이스 그리드가 2칸 — CommonMark 4칸과 다름).\n // depth는 절대 그리드(÷2)가 아니라 들여쓰기 스택으로 산출: 물리 들여쓰기 증가=한 단계\n // down, 감소=매칭 조상 레벨로 복귀. 4칸 한 단계가 depth 2로 튀거나 탭 자식이\n // 형제로 붕괴하는 것 방지, 2칸 그리드 입력의 depth는 종전과 동일 (v4.0.5)\n const listLine = line.replace(/^[\\t ]+/, ws => ws.replace(/\\t/g, \" \"))\n const listMatch = listLine.match(/^(\\s*)([-*+]|\\d+[.)]) (.+)$/)\n if (listMatch) {\n // 리스트 run이 끊겼으면(직전 블록이 리스트 아님) 스택 초기화 — 빈 줄은 run 유지\n if (blocks.length === 0 || blocks[blocks.length - 1].type !== \"list_item\") listStack.length = 0\n const phys = listMatch[1].length\n let indent: number\n if (listStack.length === 0) {\n // run 첫 항목 — 기존 2칸 그리드로 시드 (들여쓰고 시작하는 입력의 depth 종전 유지)\n indent = Math.floor(phys / 2)\n for (let d = 0; d < indent; d++) listStack.push(d * 2)\n listStack.push(phys)\n } else {\n while (listStack.length > 1 && phys < listStack[listStack.length - 1]) listStack.pop()\n if (phys > listStack[listStack.length - 1]) listStack.push(phys)\n indent = listStack.length - 1\n }\n const ordered = /\\d/.test(listMatch[2])\n blocks.push({ type: \"list_item\", text: listMatch[3].trim(), ordered, indent, marker: listMatch[2] })\n i++; continue\n }\n\n // 일반 단락\n blocks.push({ type: \"paragraph\", text: line.trim() })\n i++\n }\n\n return blocks\n}\n\n// ─── 인라인 마크다운 → 멀티 run ─────────────────────\n\ninterface InlineSpan {\n text: string\n bold: boolean\n italic: boolean\n code: boolean\n /** 하이퍼링크 대상 (살균 후) — 연속 동일 href span이 한 필드 extent */\n href?: string\n /** 각주 본문 — 이 위치에 footNote 개체 방출 (text는 빈 문자열) */\n note?: string\n}\n\nexport function parseInlineMarkdown(text: string): InlineSpan[] {\n // 마크다운 백슬래시 이스케이프(\\* \\~ \\| \\< \\$ 등 — kordoc 파서 escapeGfm·escapeLiteralDollar 출력 포함)를\n // 센티널로 마스킹 — 강조/링크 정규식이 이스케이프된 문자를 델리미터로 오인해\n // 소비하는 것을 차단. span 조립 후 리터럴로 복원한다.\n const literals: string[] = []\n text = text.replace(/\\x00/g, \"\").replace(/\\\\([\\\\`*_{}[\\]()#+\\-.!|<>~$])/g, (_, c: string) => {\n literals.push(c)\n return `\\x00${literals.length - 1}\\x00` // 인덱스 내장 — 전처리가 일부 구간을 버려도 정렬 유지\n })\n // 전처리: 이미지 → alt 텍스트 (블록 단위 이미지는 gen-section이 pic으로 방출)\n text = text.replace(/!\\[([^\\]]*)\\]\\([^)]*\\)/g, \"$1\")\n // 전처리: ~~취소선~~ → 텍스트만\n text = text.replace(/~~([^~]+)~~/g, \"$1\")\n // 전처리: <u>밑줄</u> → 텍스트만 (취소선과 동일 정책 — 서식 마커는 생성 시 평문화)\n text = text.replace(/<u>([^<]*)<\\/u>/g, \"$1\")\n\n let spans: InlineSpan[]\n if (inlineDoc) {\n // 링크·각주 채널 (v4.5.0) — [text](url)은 href span 그룹으로, [^id]는 note span으로.\n // 세그먼트 단위로 강조를 파싱하므로 링크 경계를 걸치는 강조(**a [b](u)**)는 리터럴 유지.\n spans = []\n const re = /\\[\\^([^\\]\\s]+)\\]|\\[([^\\]]*)\\]\\(([^)]*)\\)/g\n let last = 0\n for (const m of text.matchAll(re)) {\n const idx = m.index!\n if (idx > last) spans.push(...emphasisSpans(text.slice(last, idx)))\n if (m[1] !== undefined) {\n const def = inlineDoc.inNote ? undefined : inlineDoc.footnotes.get(m[1])\n if (def !== undefined) spans.push({ text: \"\", bold: false, italic: false, code: false, note: def })\n else spans.push(...emphasisSpans(m[0])) // 정의 없는 마커 — 리터럴 보존\n } else {\n const anchor = m[2] || m[3]\n const href = sanitizeHref(m[3].trim()) ?? undefined\n const sub = emphasisSpans(anchor)\n if (href) for (const s of sub) s.href = href\n spans.push(...sub)\n }\n last = idx + m[0].length\n }\n if (last < text.length) spans.push(...emphasisSpans(text.slice(last)))\n if (spans.length === 0) spans.push({ text, bold: false, italic: false, code: false })\n } else {\n // 종전 경로 — 링크는 텍스트만 추출\n text = text.replace(/\\[([^\\]]*)\\]\\(([^)]*)\\)/g, (_, t, u) => t || u)\n spans = emphasisSpans(text)\n if (spans.length === 0) spans.push({ text, bold: false, italic: false, code: false })\n }\n // 센티널 → 리터럴 복원. 인라인 코드 안은 CommonMark처럼 이스케이프 처리가\n // 없으므로 백슬래시까지 원문 그대로 되살린다.\n for (const span of spans) {\n if (!span.text.includes(\"\\x00\")) continue\n span.text = span.text.replace(/\\x00(\\d+)\\x00/g, (_, i) => {\n const c = literals[+i] ?? \"\"\n return span.code ? \"\\\\\" + c : c\n })\n }\n return spans\n}\n\n// 패턴: `code`, ***bolditalic***, **bold**, *italic*, __bold__, _italic_\n// **/***/* 는 안쪽에 더 짧은 별 run 을 허용 — **굵게 *기울임*** 같은 중첩 강조가\n// 매칭에서 통째로 탈락해 별 하나짜리 두 개로 오인되던 것을 방지 (#61). 중첩 내용은\n// emphasisSpans 재귀로 분해해 겉 강조 플래그를 OR 한다.\n// 언더스코어 강조는 GFM처럼 단어 내부 비활성 (post_id·__init__ 오염 방지, v4.0.5):\n// 여는 _ 는 앞이 공백/구두점/문두 + 뒤가 비공백, 닫는 _ 는 앞이 비공백 + 뒤가\n// 공백/구두점/문미일 때만. (?<!_)/(?!_)는 _ run을 원자로 취급(_init_ 부분매칭 방지),\n// \\x00 은 이스케이프 센티널(마스킹된 구두점)이라 경계로 인정.\nconst INLINE_REGEX = /(`[^`]+`|\\*{3}(?:[^*]|\\*(?!\\*\\*))+\\*{3}|\\*{2}(?:[^*]|\\*(?!\\*))+\\*{2}|\\*(?:[^*]|\\*{2}(?:[^*]|\\*(?!\\*))+\\*{2})+\\*|(?<![^\\s\\p{P}\\p{S}\\x00])(?<!_)_{2}(?=\\S)[^_]+(?<=\\S)_{2}(?!_)(?![^\\s\\p{P}\\p{S}\\x00])|(?<![^\\s\\p{P}\\p{S}\\x00])(?<!_)_(?=\\S)[^_]+(?<=\\S)_(?!_)(?![^\\s\\p{P}\\p{S}\\x00]))/gu\n\n/**\n * 강조(`code` ** * __ _) 토크나이즈 — 마스킹된 세그먼트 텍스트 전용.\n * 강조 중첩은 한 단계씩 재귀로 벗긴다 — depth 는 병리적 입력 폭주 방지용 상한.\n */\nfunction emphasisSpans(text: string, depth = 0): InlineSpan[] {\n const spans: InlineSpan[] = []\n let lastIdx = 0\n\n for (const match of text.matchAll(INLINE_REGEX)) {\n const idx = match.index!\n if (idx > lastIdx) {\n spans.push({ text: text.slice(lastIdx, idx), bold: false, italic: false, code: false })\n }\n const raw = match[0]\n if (raw.startsWith(\"`\")) {\n spans.push({ text: raw.slice(1, -1), bold: false, italic: false, code: true })\n } else {\n let inner: string\n let bold = false\n let italic = false\n if (raw.startsWith(\"***\") || raw.startsWith(\"___\")) {\n inner = raw.slice(3, -3); bold = true; italic = true\n } else if (raw.startsWith(\"**\") || raw.startsWith(\"__\")) {\n inner = raw.slice(2, -2); bold = true\n } else {\n inner = raw.slice(1, -1); italic = true\n }\n if (depth < 3 && /[`*_]/.test(inner)) {\n for (const child of emphasisSpans(inner, depth + 1)) {\n spans.push(child.code ? child : { ...child, bold: child.bold || bold, italic: child.italic || italic })\n }\n } else {\n spans.push({ text: inner, bold, italic, code: false })\n }\n }\n lastIdx = idx + raw.length\n }\n if (lastIdx < text.length) {\n spans.push({ text: text.slice(lastIdx), bold: false, italic: false, code: false })\n }\n return spans\n}\n\nfunction spanToCharPrId(span: InlineSpan): number {\n if (span.code) return CHAR_CODE\n if (span.bold && span.italic) return CHAR_BOLD_ITALIC\n if (span.bold) return CHAR_BOLD\n if (span.italic) return CHAR_ITALIC\n return CHAR_NORMAL\n}\n\n\n/** HYPERLINK fieldBegin ctrl — 실측 저장본(seoul2 36266445) 6-param 형상 미러 */\nfunction hyperlinkBeginXml(fid: number, href: string): string {\n // Command의 ':'는 '\\:' 이스케이프 (실측: \"http\\://www.nrich.go.kr;1;0;0;\")\n const cmd = escapeXml(href.replace(/:/g, \"\\\\:\"))\n const path = escapeXml(href)\n return `<hp:ctrl><hp:fieldBegin id=\"${fid}\" type=\"HYPERLINK\" name=\"\" editable=\"0\" dirty=\"0\" zorder=\"-1\" fieldid=\"${HYPERLINK_FIELDID}\">` +\n `<hp:parameters cnt=\"6\" name=\"\"><hp:integerParam name=\"Prop\">0</hp:integerParam>` +\n `<hp:stringParam name=\"Command\">${cmd};1;0;0</hp:stringParam>` +\n `<hp:stringParam name=\"Path\">${path}</hp:stringParam>` +\n `<hp:stringParam name=\"Category\">HWPHYPERLINK_TYPE_URL</hp:stringParam>` +\n `<hp:stringParam name=\"TargetType\">HWPHYPERLINK_TARGET_BOOKMARK</hp:stringParam>` +\n `<hp:stringParam name=\"DocOpenType\">HWPHYPERLINK_JUMP_CURRENTTAB</hp:stringParam>` +\n `</hp:parameters></hp:fieldBegin></hp:ctrl>`\n}\n\n/** footNote ctrl — rhwp render_note_sublist 형상 (suffixChar 41=')' 상시 방출 계약) */\nfunction footnoteXml(note: string, mapCharId?: (id: number) => number): string {\n const d = inlineDoc!\n const n = ++d.noteSeq\n d.inNote = true\n let body: string\n try {\n body = generateRuns(note, CHAR_NORMAL, mapCharId)\n } finally {\n d.inNote = false\n }\n return `<hp:ctrl><hp:footNote number=\"${n}\" suffixChar=\"41\" instId=\"${FOOTNOTE_INST_BASE + n}\">` +\n `<hp:subList id=\"\" textDirection=\"HORIZONTAL\" lineWrap=\"BREAK\" vertAlign=\"TOP\" linkListIDRef=\"0\" linkListNextIDRef=\"0\" textWidth=\"0\" textHeight=\"0\" hasTextRef=\"0\" hasNumRef=\"0\">` +\n `<hp:p paraPrIDRef=\"0\" styleIDRef=\"0\">${body}</hp:p>` +\n `</hp:subList></hp:footNote></hp:ctrl>`\n}\n\nexport function generateRuns(text: string, defaultCharPr: number = CHAR_NORMAL, mapCharId?: (id: number) => number): string {\n const spans = parseInlineMarkdown(text)\n const mapped = (id: number) => (mapCharId ? mapCharId(id) : id)\n const out: string[] = []\n // 연속 동일 href span 묶음을 fieldBegin/fieldEnd ctrl-run으로 감싼다 (extent = anchor)\n let openHref: string | null = null\n let openFid = 0\n const closeField = () => {\n if (openHref === null) return\n out.push(`<hp:run charPrIDRef=\"${mapped(defaultCharPr)}\"><hp:ctrl><hp:fieldEnd beginIDRef=\"${openFid}\" fieldid=\"${HYPERLINK_FIELDID}\"/></hp:ctrl></hp:run>`)\n openHref = null\n }\n for (const span of spans) {\n if (span.note !== undefined && inlineDoc) {\n closeField()\n out.push(`<hp:run charPrIDRef=\"${mapped(defaultCharPr)}\">${footnoteXml(span.note, mapCharId)}</hp:run>`)\n continue\n }\n const href = inlineDoc ? (span.href ?? null) : null\n if (href !== openHref) {\n closeField()\n if (href !== null) {\n openFid = FIELD_ID_BASE + ++inlineDoc!.fieldSeq\n openHref = href\n out.push(`<hp:run charPrIDRef=\"${mapped(defaultCharPr)}\">${hyperlinkBeginXml(openFid, href)}</hp:run>`)\n }\n }\n const charId = span.code || span.bold || span.italic ? spanToCharPrId(span) : defaultCharPr\n out.push(`<hp:run charPrIDRef=\"${mapped(charId)}\"><hp:t>${escapeTextXml(span.text)}</hp:t></hp:run>`)\n }\n closeField()\n return out.join(\"\")\n}\n\nexport function generateParagraph(text: string, paraPrId: number = PARA_NORMAL, charPrId: number = CHAR_NORMAL, mapCharId?: (id: number) => number, styleId: number = 0): string {\n if (paraPrId === PARA_CODE) {\n // 코드블록은 인라인 파싱 안 함\n return `<hp:p paraPrIDRef=\"${paraPrId}\" styleIDRef=\"0\"><hp:run charPrIDRef=\"${CHAR_CODE}\"><hp:t>${escapeXml(text)}</hp:t></hp:run></hp:p>`\n }\n const runs = generateRuns(text, charPrId, mapCharId)\n return `<hp:p paraPrIDRef=\"${paraPrId}\" styleIDRef=\"${styleId}\">${runs}</hp:p>`\n}\n","/**\n * 페이지 옵션 (v4.5.0) — 용지 크기·방향, 다단, 머리말/꼬리말 생성.\n *\n * XML 형상 근거:\n * - landscape 속성: 코퍼스 실측 — 세로 문서 전수 WIDELY, 가로 문서(소방용수시설\n * 조사일정 2종)만 NARROWLY. 용지 width/height는 방향과 무관하게 용지 실치수 유지.\n * - 머리말/꼬리말·subList: rhwp serializer(한컴 저장본 필드 단위 전수 대조로 검증된\n * HWP5→HWPX 변환기)의 render_header_footer 형상 미러.\n * - colPr 다단: rhwp render_col_pr_ctrl — type NEWSPAPER, sameSz=1, sameGap(HWPUNIT).\n *\n * 옵션 미지정 시 이 모듈은 아무것도 방출하지 않는다 (기존 산출물 바이트 불변).\n */\n\nimport { A4_W_HU, A4_H_HU } from \"./geometry.js\"\nimport { generateRuns } from \"./md-runs.js\"\n\n/** markdownToHwpx `page` 옵션 */\nexport interface PageOptions {\n /** 용지 프리셋 또는 mm 실치수. 기본 A4 (210×297) */\n size?: \"A4\" | \"A3\" | \"B4\" | \"B5\" | \"Letter\" | { widthMm: number; heightMm: number }\n /** 용지 방향. 기본 portrait(세로) */\n orientation?: \"portrait\" | \"landscape\"\n /** 다단 개수 (1~8). 기본 1 */\n columns?: number\n /** 머리말 텍스트 — 모든 쪽, 인라인 마크다운(굵게 등) 허용 */\n header?: string\n /** 꼬리말 텍스트 */\n footer?: string\n}\n\nexport interface ResolvedPage {\n widthHU: number\n heightHU: number\n landscape: \"WIDELY\" | \"NARROWLY\"\n columns: number\n header: string | null\n footer: string | null\n}\n\n/** 용지 프리셋 (mm) — B계열은 한컴 용지 규격(JIS) */\nconst PAPER_MM: Record<string, [number, number]> = {\n A4: [210, 297],\n A3: [297, 420],\n B4: [257, 364],\n B5: [182, 257],\n Letter: [215.9, 279.4],\n}\n\n/**\n * 옵션 해석 — 전부 기본값이면 null (기존 방출 경로 유지, 바이트 불변 보장).\n * 잘못된 값은 조용히 접지 않고 throw — 생성 결과가 의도와 다르게 나가는 것 방지.\n */\nexport function resolvePage(opts?: PageOptions): ResolvedPage | null {\n if (!opts) return null\n const { size, orientation, columns, header, footer } = opts\n if (size === undefined && orientation === undefined && columns === undefined\n && header === undefined && footer === undefined) return null\n\n let wMm = 210, hMm = 297\n if (size !== undefined) {\n if (typeof size === \"string\") {\n const preset = PAPER_MM[size]\n if (!preset) throw new Error(`지원하지 않는 용지 프리셋: ${size} (A4·A3·B4·B5·Letter)`)\n ;[wMm, hMm] = preset\n } else {\n if (!(size.widthMm > 0) || !(size.heightMm > 0) || size.widthMm > 1000 || size.heightMm > 1000) {\n throw new Error(`용지 치수는 0~1000mm 범위여야 합니다: ${size.widthMm}×${size.heightMm}`)\n }\n wMm = size.widthMm\n hMm = size.heightMm\n }\n }\n const cols = columns ?? 1\n if (!Number.isInteger(cols) || cols < 1 || cols > 8) {\n throw new Error(`다단 개수는 1~8 정수여야 합니다: ${columns}`)\n }\n // 용지 치수는 내림 — 한컴 정준값과 일치 (A4 210→59528·297→84188, 반올림이면 84189로 어긋남)\n const paperHU = (mm: number) => Math.floor((mm * 7200) / 25.4)\n return {\n widthHU: size === undefined ? A4_W_HU : paperHU(wMm),\n heightHU: size === undefined ? A4_H_HU : paperHU(hMm),\n // 실측: 용지 치수는 방향과 무관하게 유지, 방향은 landscape 속성만 바뀐다\n landscape: orientation === \"landscape\" ? \"NARROWLY\" : \"WIDELY\",\n columns: cols,\n header: header?.trim() ? header.trim() : null,\n footer: footer?.trim() ? footer.trim() : null,\n }\n}\n\n/** 다단 colPr ctrl — rhwp render_col_pr_ctrl 형상 (간격 8mm = 한컴 기본) */\nexport function columnColPrXml(columns: number): string {\n const gap = columns > 1 ? 2268 : 0\n return `<hp:ctrl><hp:colPr id=\"\" type=\"NEWSPAPER\" layout=\"LEFT\" colCount=\"${columns}\" sameSz=\"1\" sameGap=\"${gap}\"/></hp:ctrl>`\n}\n\n/**\n * 머리말/꼬리말 ctrl — rhwp render_header_footer 형상 미러.\n * 첫 문단 첫 run(secPr 옆)에 방출한다. 텍스트는 인라인 마크다운 지원.\n */\nexport function headerFooterCtrl(\n tag: \"header\" | \"footer\",\n text: string,\n id: number,\n mapCharId?: (id: number) => number,\n): string {\n const runs = generateRuns(text, undefined, mapCharId)\n return `<hp:ctrl><hp:${tag} id=\"${id}\" applyPageType=\"BOTH\">` +\n `<hp:subList id=\"\" textDirection=\"HORIZONTAL\" lineWrap=\"BREAK\" vertAlign=\"TOP\" linkListIDRef=\"0\" linkListNextIDRef=\"0\" textWidth=\"0\" textHeight=\"0\" hasTextRef=\"0\" hasNumRef=\"0\">` +\n `<hp:p paraPrIDRef=\"0\" styleIDRef=\"0\">${runs}</hp:p>` +\n `</hp:subList></hp:${tag}></hp:ctrl>`\n}\n","/**\n * HWPX 패키지 구조 파일(container/manifest)과 head.xml 생성 (generator.ts에서 분리).\n */\n\nimport { type ResolvedGongmun, levelIndent, levelMarkerHeight, markerWidth, needsGaejosikAssets, usesAsteriskThird, usesReportFonts } from \"./gongmun.js\"\nimport { KordocError } from \"../utils.js\"\nimport { GJ_CHAR_APPROVAL, GJ_CHAR_TITLE_BAR, GONGMUN_APPROVAL_CHAR, GONGMUN_TBL_PT, GONGMUN_TITLE_BAR_CHAR, charVariantBase } from \"./gen-ids.js\"\nimport { gaejosikSizes, gaejosikSpaceBefore, gaejosikChamIndent, gaejosikTocItemIndent, GAEJOSIK_COLORS } from \"./gaejosik.js\"\nimport {\n NS_HEAD, NS_OPF, NS_HPF, NS_OCF, NS_PARA, NS_CORE,\n CHAR_TABLE_HEADER, CHAR_QUOTE,\n GONGMUN_BODY_RATIO, GONGMUN_LIST_BASE, GONGMUN_LIST_LEVELS, GONGMUN_LIST_PLAIN_BASE, GONGMUN_PARA_APPROVAL, GONGMUN_LIST_VARIANT_BASE,\n GONGMUN_CENTER, GONGMUN_RIGHT, GONGMUN_SRC_LEFT, GONGMUN_TBL_CENTER, GONGMUN_TBL_LEFT,\n GONGMUN_SRC_CHAR, GONGMUN_SRC_CHAR_BOLD, GJ_CHAR_SRC, GJ_CHAR_SRC_BOLD, srcCaptionPt,\n GJ_PARA_CHAM, GJ_PARA_COVER, GJ_PARA_TOC_ITEM, GJ_PARA_CHAPTER, GJ_PARA_BAR,\n charPr, paraPr, borderFillEntry, escapeXml, type BorderSide,\n type ResolvedTheme,\n} from \"./gen-ids.js\"\n\n// ─── HWPX 구조 파일 생성 ─────────────────────────────\n\nexport function generateContainerXml(): string {\n return `<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>\n<ocf:container xmlns:ocf=\"${NS_OCF}\" xmlns:hpf=\"${NS_HPF}\">\n <ocf:rootfiles>\n <ocf:rootfile full-path=\"Contents/content.hpf\" media-type=\"application/hwpml-package+xml\"/>\n </ocf:rootfiles>\n</ocf:container>`\n}\n\nexport function generateManifest(chartParts: Array<{ name: string }> = [], imageItems: string[] = [], layout = \"default\"): string {\n const chartItems = chartParts\n .map((p, i) => `\\n <opf:item id=\"chart${i + 1}\" href=\"${p.name}\" media-type=\"application/xml\"/>`)\n .join(\"\")\n const imgItems = imageItems.map((x) => `\\n ${x}`).join(\"\")\n // generator/kordoc-layout 메타 = 왕복 채널의 자사 파일 식별자 — 파서가 default\n // 레이아웃에서만 charPr id 기반 인라인 강조·인용 복원을 켠다 (외래 문서·gongmun\n // id 재배치 오검출 가드). opf:metadata는 한컴 표준 content.hpf에도 있는 요소.\n return `<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>\n<opf:package xmlns:opf=\"${NS_OPF}\" xmlns:hpf=\"${NS_HPF}\" xmlns:hh=\"${NS_HEAD}\">\n <opf:metadata>\n <opf:meta name=\"generator\" content=\"kordoc\"/>\n <opf:meta name=\"kordoc-layout\" content=\"${escapeXml(layout)}\"/>\n </opf:metadata>\n <opf:manifest>\n <opf:item id=\"header\" href=\"Contents/header.xml\" media-type=\"application/xml\"/>\n <opf:item id=\"section0\" href=\"Contents/section0.xml\" media-type=\"application/xml\"/>${chartItems}${imgItems}\n </opf:manifest>\n <opf:spine>\n <opf:itemref idref=\"header\" linear=\"no\"/>\n <opf:itemref idref=\"section0\" linear=\"yes\"/>\n </opf:spine>\n</opf:package>`\n}\n\n// ─── id 파티션 불변식 (v4.0.5 P0-1) ──────────────────\n// charPr/paraPr/borderFill id 공간은 여러 모듈(gen-ids 상수·variant·프로필·docframe·\n// 표 레지스트리)이 손계산으로 이어 쓴다 — 한 곳이 밀리면 run이 엉뚱한 서식을 가리켜도\n// well-formed라 조용히 렌더만 틀린다(무음 오염). 방출 직전에 \"중복·구멍 없는 연속 id\"를\n// 검증해 드리프트를 생성 시점의 loud error로 바꾼다.\n\n/** 방출 행들의 id 속성이 startId부터 연속(중복·구멍 없음)인지 검증 */\nfunction assertSequentialIds(rows: string[], label: string, startId: number): void {\n for (let i = 0; i < rows.length; i++) {\n const m = rows[i].match(/\\bid=\"(\\d+)\"/)\n const got = m ? Number(m[1]) : NaN\n if (got !== startId + i) {\n throw new KordocError(\n `내부 오류: ${label} id 파티션 드리프트 — ${startId + i} 위치에 id=${m ? m[1] : \"?\"} 방출. ` +\n `id 상수(gen-ids)와 실제 방출 수가 어긋났다 (GJ_CHAR_COUNT류 카운트·base 산술 확인)`,\n )\n }\n }\n}\n\n// ─── charPr 생성 헬퍼 ───────────────────────────────\n\n/** charProperties 블록 생성 — 공문서 모드면 본문/제목 height를 표준값으로 */\nfunction buildCharProperties(theme: ResolvedTheme, gongmun: ResolvedGongmun | null, ratioVariants: number[] = [], extraCharPrXmls: string[] = [], v5 = false): string {\n // 실측 폰트 프리셋(개조식·보고서·계획서) — 제목 HY헤드라인M·본문 휴먼명조 (QA-1, 부처별 양식 3종 실측)\n // v5 엔진은 정적 블록을 비실측 최소 세트로 고정하고 스킴 글꼴은 레지스트리가 발급한다\n const measured = !v5 && !!gongmun && usesReportFonts(gongmun.preset)\n const richAssets = !v5 && !!gongmun && needsGaejosikAssets(gongmun)\n // 비공문서(기존 동작): 본문 10pt\n let body = 1000, code = 900, h1 = 1800, h2 = 1400, h3 = 1200, h4 = 1100\n if (gongmun) {\n body = gongmun.bodyHeight\n code = Math.max(body - 200, 900)\n // 제목 계열은 본문보다 작아지지 않게 body를 하한으로 — bodyPt를 16pt↑로 크게 잡아도\n // 소제목(h3=본문)이 대분류(h2)·문서제목(h1)을 넘어 위계가 역전되지 않는다.\n h1 = Math.max(gongmun.preset === \"report\" || gongmun.preset === \"plan\" ? 2000 : 1700, body)\n h2 = Math.max(1600, body)\n h3 = body\n // h4 하한 1300은 15pt 본문 기준값 — 본문이 13pt 이하면 h3를 넘지 않게 캡 (위계 역전 방지)\n h4 = Math.min(h3, Math.max(body - 100, 1300))\n }\n // 실측 프리셋 본문 = 휴먼명조(fontface id 4). 비실측이라도 개조식 자산(표지·목차)을 쓰면\n // 폰트 테이블이 rich 8종(id 0=함초롬바탕 고정, 해석된 본문 폰트는 id 4)으로 바뀌므로\n // richAssets 기준으로 골라야 bodyFont/fonts.body 지정이 유지된다\n const bodyFont = richAssets ? 4 : 0\n // 제목 계열 — 실측 프리셋은 HY헤드라인M(id 3, 자체 굵기라 bold 없음. 실측: □·제목 전부\n // bold=0), 그 외는 함초롬돋움(id 1) bold (범용 헤딩 관행)\n const hFont = measured ? 3 : 1\n const hBold = !measured\n // 공문서 본문 장평 95%(orphan 압축). 비공문서·제목은 100 유지.\n const bodyRatio = gongmun ? GONGMUN_BODY_RATIO : 100\n const rows = [\n charPr(0, body, false, false, bodyFont, theme.body, bodyRatio),\n charPr(1, body, true, false, bodyFont, theme.body, bodyRatio),\n charPr(2, body, false, true, bodyFont, theme.body, bodyRatio),\n charPr(3, body, true, true, bodyFont, theme.body, bodyRatio),\n charPr(4, code, false, false, 1),\n charPr(5, h1, hBold, false, hFont, theme.h1),\n charPr(6, h2, hBold, false, hFont, theme.h2),\n charPr(7, h3, hBold, false, hFont, theme.h3),\n charPr(8, h4, hBold, false, hFont, theme.h4),\n charPr(CHAR_TABLE_HEADER, body, theme.tableHeaderBold, false, bodyFont, theme.tableHeader),\n charPr(CHAR_QUOTE, body, false, true, bodyFont, theme.quote),\n ]\n if (gongmun && !richAssets) {\n // 비실측 공문서 표 셀 11·12 — 12pt (실결재 실측: 표 셀은 본문보다 작은 11~12pt 지배.\n // 본문 크기 셀은 열폭 부족으로 서술 열이 세로로 길어진다 — v4.0.2 실렌더 QA)\n rows.push(\n charPr(11, GONGMUN_TBL_PT, false, false, bodyFont, theme.body),\n charPr(12, GONGMUN_TBL_PT, true, false, bodyFont, theme.body),\n charPr(GONGMUN_TITLE_BAR_CHAR, 100, false, false, bodyFont, theme.body),\n charPr(GONGMUN_APPROVAL_CHAR, 1000, false, false, bodyFont, theme.body),\n // 출처행 캡션 — 본문 폰트 -3pt (실무 보고서: 표 아래 출처는 본문과 구분되는 작은 글씨)\n charPr(GONGMUN_SRC_CHAR, srcCaptionPt(body), false, false, bodyFont, theme.body),\n charPr(GONGMUN_SRC_CHAR_BOLD, srcCaptionPt(body), true, false, bodyFont, theme.body),\n )\n }\n if (richAssets) {\n // 부호·요소별 전용 charPr 11~25 (gen-ids GJ_CHAR_*) — 실측 스펙 (gaejosik.ts).\n // 보고서·계획서도 ※(13·14)·표 셀(22·23)·제목박스(25)를 쓰므로 블록 전체를 공유 등록\n const sz = gaejosikSizes(body, gongmun!.sizes)\n rows.push(\n charPr(11, sz.dae, false, false, 3), // □ HY헤드라인M\n charPr(12, sz.dae, true, false, 3), // □ bold\n charPr(13, sz.cham, false, false, 5), // ※ 한양중고딕\n charPr(14, sz.cham, true, false, 5), // ※ bold\n charPr(15, sz.chapter, true, false, 4, \"#FFFFFF\"), // 장 로마숫자(흰)\n charPr(16, sz.chapter, false, false, 3), // 장 제목\n charPr(17, sz.coverTitle, false, false, 3), // 표지 제목\n charPr(18, sz.coverSub, false, false, 3), // 표지 날짜·기관명\n charPr(19, sz.tocLabel, true, false, 3), // 목 차\n charPr(20, sz.tocRoman, true, false, 6), // 목차 로마숫자(한양신명조)\n charPr(21, sz.tocItem, false, false, 3), // 목차 항목\n charPr(22, sz.table, false, false, 7), // 표 셀(맑은 고딕 12pt)\n charPr(23, sz.table, true, false, 7), // 표 셀 bold\n charPr(24, sz.bar, false, false, 4), // 표지 바 셀 빈 문단(6pt)\n charPr(25, sz.bodyTitle, false, false, 3), // 본문 제목박스(HY헤드라인M 22pt, 실측 GT3 표④)\n charPr(GJ_CHAR_TITLE_BAR, 100, false, false, 4), // 1페이지형 제목박스 바(1pt)\n charPr(GJ_CHAR_APPROVAL, 1000, false, false, 7), // 결재란 라벨(맑은 고딕 10pt)\n charPr(GJ_CHAR_SRC, srcCaptionPt(body), false, false, 5), // 출처행 캡션(한양중고딕 본문-3pt)\n charPr(GJ_CHAR_SRC_BOLD, srcCaptionPt(body), true, false, 5), // 출처행 캡션 bold\n )\n }\n // 불변식: 여기까지의 방출 수 == charVariantBase() — gen-section·generator가 이 값으로\n // variant/프로필/docframe id를 계산하므로, 어긋나면 run 참조가 통째로 밀린다 (P0-1)\n const expectedBase = charVariantBase(richAssets, !!gongmun)\n if (rows.length !== expectedBase) {\n throw new KordocError(\n `내부 오류: charPr 기본 블록 방출 수(${rows.length}) ≠ charVariantBase(${expectedBase}) — ` +\n `gen-header 방출 행과 gen-ids 카운트 상수가 어긋났다`,\n )\n }\n // 자동 장평 변형 — 본문 계열(0~3)의 장평만 바꾼 복제본\n for (const r of ratioVariants) {\n rows.push(\n charPr(rows.length, body, false, false, bodyFont, theme.body, r),\n charPr(rows.length + 1, body, true, false, bodyFont, theme.body, r),\n charPr(rows.length + 2, body, false, true, bodyFont, theme.body, r),\n charPr(rows.length + 3, body, true, true, bodyFont, theme.body, r),\n )\n }\n // 서식 프로필 charPr — variant 다음 id로 이미 부여됨(gen-profile.buildProfileRemap)\n rows.push(...extraCharPrXmls)\n assertSequentialIds(rows, \"charPr\", 0)\n return `<hh:charProperties itemCnt=\"${rows.length}\">\\n${rows.join(\"\\n\")}\\n </hh:charProperties>`\n}\n\n/** paraProperties 블록 생성 — 공문서 모드면 본문 줄간격·제목 가운데 + 항목단계 8종 추가 */\nfunction buildParaProperties(gongmun: ResolvedGongmun | null, listIndentVariants: Array<{ depth: number; widthHu: number }> = []): string {\n if (!gongmun) {\n // 일반 경로도 어절 단위 유지(keepWord) — 종전 산출물의 실제 조판(BREAK_WORD=어절,\n // gen-ids 매핑 역전 정정 전 값)과 동일한 행동 보존. 글자 단위가 필요하면 keepWord: false.\n const base = [\n paraPr(0, { keepWord: true }),\n paraPr(1, { align: \"LEFT\", spaceBefore: 800, spaceAfter: 200, lineSpacing: 180, outlineLevel: 0, keepWord: true }),\n paraPr(2, { align: \"LEFT\", spaceBefore: 600, spaceAfter: 150, lineSpacing: 170, outlineLevel: 1, keepWord: true }),\n paraPr(3, { align: \"LEFT\", spaceBefore: 400, spaceAfter: 100, lineSpacing: 160, outlineLevel: 2, keepWord: true }),\n paraPr(4, { align: \"LEFT\", spaceBefore: 300, spaceAfter: 100, lineSpacing: 160, outlineLevel: 3, keepWord: true }),\n paraPr(5, { align: \"LEFT\", lineSpacing: 130, indent: 400, keepWord: true }),\n paraPr(6, { align: \"LEFT\", lineSpacing: 150, indent: 600, keepWord: true }),\n paraPr(7, { align: \"LEFT\", lineSpacing: 160, indent: 600, keepWord: true }),\n ]\n assertSequentialIds(base, \"paraPr\", 0)\n return `<hh:paraProperties itemCnt=\"${base.length}\">\\n${base.join(\"\\n\")}\\n </hh:paraProperties>`\n }\n const ls = gongmun.lineSpacing\n const titleAlign = gongmun.centerTitle ? \"CENTER\" : \"LEFT\"\n // 공문서 모드 전 문단 어절 단위 줄바꿈(keepWord) — 한글이 단어 중간에서 끊기지 않음.\n // 헤딩에 outlineLevel(OUTLINE)을 주지 않는다 — 한글이 개요 번호(\"1.\", \"1.1.\")를\n // 화면에 덧붙여 제목이 \"1. 행정안전부\"로 렌더되는 결함 (COM 실렌더 확인).\n // 실측 정합: 실제 공문서(GT6/GT7 등)는 개요 스타일을 정의만 하고 쓰지 않는다.\n // h2 말머리(□/번호) 문단 — 실측 □ 대항목: 문단 위 15pt(=body×2)·내어쓰기 부호 실폭\n // (부처별 양식 3종, QA-2). 부호폭 기준 크기 1600 = buildCharProperties h2와 동기.\n const h2MarkerWidth = markerWidth(gongmun.h2Marker === \"box\" ? \"□\" : \"1.\", 1600)\n const h2Geom = gongmun.h2Marker !== \"none\"\n ? { spaceBefore: Math.round(gongmun.bodyHeight * 2), spaceAfter: 0, indent: -h2MarkerWidth, autoTab: true }\n : { spaceBefore: 600, spaceAfter: 150 }\n // h2 제목 글자가 시작하는 자리 — 부호를 안 쓰면(none) 들여쓸 기준이 없으므로 0\n const h3Left = gongmun.h2Marker !== \"none\" ? h2MarkerWidth : 0\n const base = [\n paraPr(0, { lineSpacing: ls, keepWord: true }),\n paraPr(1, { align: titleAlign, spaceBefore: 400, spaceAfter: 400, lineSpacing: ls, keepWord: true }),\n paraPr(2, { align: \"LEFT\", ...h2Geom, lineSpacing: ls, keepWord: true }),\n // h3·h4 소제목(\"가.\" \"1)\")은 h2(□) 대항목의 하위다 — 종전에는 left가 없어 h2 부호가\n // 내어쓰기로 왼쪽에 나간 뒤 소제목이 본문 경계에서 시작해, 실렌더상 소제목이 대항목보다\n // 왼쪽에 놓이며 계층이 사라졌다(실렌더 확인). h2 부호폭만큼 들여써 h2 제목 글자와 맞춘다.\n paraPr(3, { align: \"LEFT\", left: h3Left, spaceBefore: 400, spaceAfter: 100, lineSpacing: ls, keepWord: true }),\n paraPr(4, { align: \"LEFT\", left: h3Left + Math.round(gongmun.bodyHeight / 2), spaceBefore: 300, spaceAfter: 100, lineSpacing: ls, keepWord: true }),\n paraPr(5, { align: \"LEFT\", lineSpacing: 130, indent: 400, keepWord: true }),\n paraPr(6, { align: \"LEFT\", lineSpacing: ls, indent: 600, keepWord: true }),\n paraPr(7, { align: \"LEFT\", lineSpacing: ls, indent: 600, keepWord: true }),\n ]\n // 개조식·보고서 본문 리스트 정렬: LEFT (왼쪽정렬)\n // 편람 개조식 예시는 왼쪽정렬 — 어절유지(BREAK_WORD)+양쪽정렬이면 짧게 끊긴 항목 줄의\n // 어절 간격이 과하게 벌어져(실측 25자→34자폭 확장 시 공백 ~2.8배) 깨진 듯 보임.\n // 서술형 본문의 기안문(standard)은 종전 양쪽정렬 유지.\n const listAlign = gongmun.numbering === \"gaejosik\" || gongmun.numbering === \"report\" ? \"LEFT\" : \"JUSTIFY\"\n // 항목 단계별 paraPr (8 ~ 8+7): left/내어쓰기 indent\n for (let d = 0; d < GONGMUN_LIST_LEVELS; d++) {\n // 내어쓰기 폭은 그 단계 글자 크기 기준(levels 오버라이드 반영, v4.12.3)\n const { left, indent } = levelIndent(d, gongmun.bodyHeight, gongmun.numbering, gongmun.sizes, gongmun.bullet2, usesAsteriskThird(gongmun.preset), levelMarkerHeight(gongmun, d))\n // 단락 위 간격 — gaejosikSpaceBefore(□ 300/그 외 0). 종전 3000/2000/1200/600(□15/○10/-6/ㆍ3pt)은\n // 「2_보고서 양식」 한 파일의 저장값이었고 v4.9.1 에서 코퍼스 실측(88% 0)으로 교체됐다.\n // 2026-09-06 재검증(서울·gate-fill 428건, hp:case 우선 — default 는 2배 함정): □ 0 96%·200 2%,\n // ○ 0 96%·300 3%, ㅇ 0 84%, - 0 90%. 3000/2000 계열은 어느 스코프로 읽어도 나오지 않는다\n const sectionGap = gongmun.numbering === \"gaejosik\" || gongmun.numbering === \"report\"\n ? gaejosikSpaceBefore(d, gongmun.bodyHeight)\n : 0\n // □ 대항목은 다음 문단과 같은 쪽에 — 쪽 하단 고아 표제 방지 (장헤더와 동일 관행)\n const keepNext = (gongmun.numbering === \"gaejosik\" || gongmun.numbering === \"report\") && d === 0\n // 부호 뒤 탭이 내어쓰기 위치에 선다(autoTab) — 첫 줄 내용 = 둘째 줄 시작\n base.push(paraPr(GONGMUN_LIST_BASE + d, { align: listAlign, lineSpacing: ls, left, indent, spaceBefore: sectionGap, keepWord: true, keepWithNext: keepNext, autoTab: true }))\n }\n // 가운데정렬 본문 단락(발신명의 등)\n base.push(paraPr(GONGMUN_CENTER, { align: \"CENTER\", lineSpacing: ls, keepWord: true }))\n // 오른쪽정렬(데이터 표 호스트·출처행 — 실측: GT6/GT7/GT11 관행)\n base.push(paraPr(GONGMUN_RIGHT, { align: \"RIGHT\", lineSpacing: ls, keepWord: true }))\n // 표 셀 전용 — 실측(GT1 표⑪): CENTER 130% / 장문 열 LEFT 130%. 셀 문단은 어절유지\n base.push(paraPr(GONGMUN_TBL_CENTER, { align: \"CENTER\", lineSpacing: 130, keepWord: true }))\n base.push(paraPr(GONGMUN_TBL_LEFT, { align: \"LEFT\", lineSpacing: 130, keepWord: true }))\n // 개조식 전용 paraPr 20~24 (gen-ids GJ_PARA_*) — id 연속성 위해 전 프리셋 방출\n // (비개조식은 ※ 참고(20)만 참조. v4.0.2: 뒤에 부호생략 전용 25~32가 오므로 구멍 금지)\n {\n const cham = gaejosikChamIndent(gongmun.bodyHeight, gongmun.sizes)\n const toc = gaejosikTocItemIndent(gongmun.bodyHeight, gongmun.sizes)\n base.push(\n paraPr(GJ_PARA_CHAM, { align: \"LEFT\", lineSpacing: ls, left: cham.left, indent: cham.indent, spaceBefore: gaejosikSpaceBefore(3, gongmun.bodyHeight), keepWord: true, autoTab: true }),\n paraPr(GJ_PARA_COVER, { align: \"CENTER\", lineSpacing: 130, keepWord: true }),\n paraPr(GJ_PARA_TOC_ITEM, { align: \"LEFT\", lineSpacing: 160, left: toc.left, indent: toc.indent, spaceBefore: 1800, keepWord: true }),\n // 장 헤더는 다음 문단과 같은 쪽에 — 쪽 하단 고아 헤더 방지 (실렌더 확인 이슈)\n paraPr(GJ_PARA_CHAPTER, { align: \"LEFT\", lineSpacing: ls, spaceBefore: 2400, spaceAfter: 600, keepWord: true, keepWithNext: true }),\n // 표지 장식 바 셀 빈 문단 — 저줄간격(실측 71%)으로 바 높이 818 안에 수납\n paraPr(GJ_PARA_BAR, { align: \"CENTER\", lineSpacing: 70, keepWord: true }),\n )\n }\n // 부호 생략(단일 형제) 항목 전용 25~32 — left는 단계 동일·내어쓰기 0 (v4.0.2:\n // 유령 내어쓰기로 둘째 줄이 첫 줄보다 더 들어가던 결함 수정, 실렌더 QA)\n for (let d = 0; d < GONGMUN_LIST_LEVELS; d++) {\n const { left } = levelIndent(d, gongmun.bodyHeight, gongmun.numbering, gongmun.sizes, gongmun.bullet2, usesAsteriskThird(gongmun.preset))\n const sectionGap = gongmun.numbering === \"gaejosik\" || gongmun.numbering === \"report\"\n ? gaejosikSpaceBefore(d, gongmun.bodyHeight)\n : 0\n base.push(paraPr(GONGMUN_LIST_PLAIN_BASE + d, { align: listAlign, lineSpacing: ls, left, indent: 0, spaceBefore: sectionGap, keepWord: true }))\n }\n // 결재란 라벨 셀 — 실측 결재선 lineSp 100% (GJ_PARA_BAR 70%는 스페이서 전용)\n base.push(paraPr(GONGMUN_PARA_APPROVAL, { align: \"CENTER\", lineSpacing: 100, keepWord: true }))\n // 장문 <right> 폴백 — 본문폭 초과 출처행은 LEFT (RIGHT 다줄은 왼쪽 끝이 들쭉날쭉)\n base.push(paraPr(GONGMUN_SRC_LEFT, { align: \"LEFT\", lineSpacing: ls, keepWord: true }))\n // (depth, 부호폭) 내어쓰기 변형 34~ — 두 자리 부호('10.') 항목 전용 (v4.0.5 P1-1).\n // 간격·정렬은 해당 depth 공용 paraPr와 동일, 내어쓰기만 자기 부호폭\n for (let vi = 0; vi < listIndentVariants.length; vi++) {\n const { depth, widthHu } = listIndentVariants[vi]\n const { left } = levelIndent(depth, gongmun.bodyHeight, gongmun.numbering, gongmun.sizes, gongmun.bullet2, usesAsteriskThird(gongmun.preset))\n const sectionGap = gongmun.numbering === \"gaejosik\" || gongmun.numbering === \"report\"\n ? gaejosikSpaceBefore(depth, gongmun.bodyHeight)\n : 0\n const keepNext = (gongmun.numbering === \"gaejosik\" || gongmun.numbering === \"report\") && depth === 0\n base.push(paraPr(GONGMUN_LIST_VARIANT_BASE + vi, { align: listAlign, lineSpacing: ls, left, indent: -widthHu, spaceBefore: sectionGap, keepWord: true, keepWithNext: keepNext, autoTab: true }))\n }\n assertSequentialIds(base, \"paraPr\", 0)\n return `<hh:paraProperties itemCnt=\"${base.length}\">\\n${base.join(\"\\n\")}\\n </hh:paraProperties>`\n}\n\n/** v5 최소 paraPr — 기본 0~7(본문 줄간격은 스킴) + 레지스트리 발급분 */\nfunction buildParaPropertiesV5(gongmun: ResolvedGongmun, extra: string[]): string {\n const ls = gongmun.lineSpacing\n const base = [\n paraPr(0, { lineSpacing: ls, keepWord: true }),\n paraPr(1, { align: gongmun.centerTitle ? \"CENTER\" : \"LEFT\", spaceBefore: 400, spaceAfter: 400, lineSpacing: ls, keepWord: true }),\n paraPr(2, { align: \"LEFT\", spaceBefore: 600, spaceAfter: 150, lineSpacing: ls, keepWord: true }),\n paraPr(3, { align: \"LEFT\", spaceBefore: 400, spaceAfter: 100, lineSpacing: ls, keepWord: true }),\n paraPr(4, { align: \"LEFT\", spaceBefore: 300, spaceAfter: 100, lineSpacing: ls, keepWord: true }),\n paraPr(5, { align: \"LEFT\", lineSpacing: 130, indent: 400, keepWord: true }),\n paraPr(6, { align: \"LEFT\", lineSpacing: ls, indent: 600, keepWord: true }),\n paraPr(7, { align: \"LEFT\", lineSpacing: ls, indent: 600, keepWord: true }),\n ...extra,\n ]\n assertSequentialIds(base, \"paraPr\", 0)\n return `<hh:paraProperties itemCnt=\"${base.length}\">\\n${base.join(\"\\n\")}\\n </hh:paraProperties>`\n}\n\n/**\n * 개요(OUTLINE) 문단이 참조하는 numbering 정의 — 헤딩 paraPr(1~4)이 사용.\n * 실제 한컴 파일의 paraHead 속성을 미러하되 번호 서식 텍스트를 비워\n * 화면에는 번호가 붙지 않는다 (secPr outlineShapeIDRef=\"1\"이 이 정의를 가리킴).\n */\nfunction buildNumberings(): string {\n const heads = Array.from({ length: 7 }, (_, i) =>\n ` <hh:paraHead start=\"1\" level=\"${i + 1}\" align=\"LEFT\" useInstWidth=\"1\" autoIndent=\"1\" widthAdjust=\"0\" textOffsetType=\"PERCENT\" textOffset=\"50\" numFormat=\"DIGIT\" charPrIDRef=\"4294967295\" checkable=\"0\"/>`\n ).join(\"\\n\")\n return `<hh:numberings itemCnt=\"1\">\n <hh:numbering id=\"1\" start=\"0\">\n${heads}\n </hh:numbering>\n </hh:numberings>`\n}\n\n// ─── fontfaces / borderFills ─────────────────────────\n\n/** 한 폰트 항목 XML — typeInfo는 한컴 관례상 존재만 하면 됨(범용값) */\nfunction fontEntry(id: number, face: string, weight = 6): string {\n return ` <hh:font id=\"${id}\" face=\"${escapeXml(face)}\" type=\"TTF\" isEmbedded=\"0\">\n <hh:typeInfo familyType=\"FCAT_GOTHIC\" weight=\"${weight}\" proportion=\"4\" contrast=\"0\" strokeVariation=\"1\" armStyle=\"1\" letterform=\"1\" midline=\"1\" xHeight=\"1\"/>\n </hh:font>`\n}\n\n/**\n * 정적 fontface 다음 폰트 id — 프로필 append 글꼴(fontName_hangul, 0.3.0)이 여기서부터.\n * buildFontFaces의 실제 방출 개수에서 파생: 실측 프리셋 8종(0~7), 그 외 3종(0~2).\n */\nexport function staticFontNext(gongmun: ResolvedGongmun | null, v5 = false): number {\n return !v5 && gongmun && needsGaejosikAssets(gongmun) ? 8 : 3\n}\n\nfunction buildFontFaces(gongmun: ResolvedGongmun | null, bodyFace: string, extraFonts: string[] = [], v5 = false): string {\n if (!v5 && gongmun && needsGaejosikAssets(gongmun)) {\n // 실측 폰트 프리셋(개조식·보고서·계획서) — 실측 양식의 폰트 세트. 모든 언어에 동일\n // 목록(한글 폰트의 라틴 글리프 사용, 실제 정부 양식 hwpx도 전 언어 동일 id 참조).\n // fonts 옵션으로 역할별 오버라이드: id 3=heading(제목 계열) / 4=body(본문) / 5=ref(※) / 7=table(표 셀)\n const ov = gongmun.fonts\n // 본문 기본 휴먼명조(실측). 보고서·계획서는 bodyFont='gothic' 명시 시 맑은 고딕 존중\n const bodyDefault = usesReportFonts(gongmun.preset)\n ? (gongmun.preset !== \"gaejosik\" && gongmun.bodyFont === \"gothic\" ? \"맑은 고딕\" : \"휴먼명조\")\n : bodyFace\n const faces = [\n \"함초롬바탕\", \"함초롬돋움\", \"HY견고딕\",\n ov.heading ?? \"HY헤드라인M\", ov.body ?? bodyDefault, ov.ref ?? \"한양중고딕\",\n \"한양신명조\", ov.table ?? \"맑은 고딕\",\n ]\n if (faces.length !== staticFontNext(gongmun)) {\n throw new Error(`fontface 정적 개수 드리프트: ${faces.length} ≠ staticFontNext ${staticFontNext(gongmun)}`)\n }\n // weight는 위치 기준(2·3 = 견고딕·제목 계열 9) — 오버라이드 폰트명과 무관하게 유지.\n // 프로필 append 글꼴(0.3.0)은 정적 목록 뒤 — 전 언어 동일 목록이라 전부 append\n const list = faces.map((f, i) => fontEntry(i, f, i === 2 || i === 3 ? 9 : 6))\n .concat(extraFonts.map((f, i) => fontEntry(faces.length + i, f)))\n .join(\"\\n\")\n const langs = [\"HANGUL\", \"LATIN\", \"HANJA\", \"JAPANESE\", \"OTHER\", \"SYMBOL\", \"USER\"]\n return `<hh:fontfaces itemCnt=\"${langs.length}\">\\n` +\n langs.map((l) => ` <hh:fontface lang=\"${l}\" fontCnt=\"${faces.length + extraFonts.length}\">\\n${list}\\n </hh:fontface>`).join(\"\\n\") +\n `\\n </hh:fontfaces>`\n }\n // 7개 언어 목록을 전부 동일하게 — 한컴 툴바(\"대표\" 언어)는 charPr 의 7개 슬롯이 같은 글꼴로 풀릴 때만\n // 이름을 보여준다(맥 한컴 실렌더 A/B, 2026-09-06: 한글·영문만 지정하고 나머지를 굴림/Symbol 로 두면 글꼴 칸이\n // 빈칸). 한컴 기본 템플릿·실결재도 라틴 슬롯에 같은 한글 글꼴을 쓴다 — 종전 Times New Roman/Consolas/Arial Black\n // 라틴 슬롯은 제거. 프로필 append 글꼴(0.3.0)은 정적 3종 뒤 id 3+ 로 전 언어에 붙는다.\n const list = [fontEntry(0, bodyFace), fontEntry(1, \"함초롬돋움\"), fontEntry(2, \"HY견고딕\", 9)]\n .concat(extraFonts.map((f, i) => fontEntry(3 + i, f)))\n .join(\"\\n\")\n const langs = [\"HANGUL\", \"LATIN\", \"HANJA\", \"JAPANESE\", \"OTHER\", \"SYMBOL\", \"USER\"]\n return `<hh:fontfaces itemCnt=\"${langs.length}\">\\n` +\n langs.map((l) => ` <hh:fontface lang=\"${l}\" fontCnt=\"${3 + extraFonts.length}\">\\n${list}\\n </hh:fontface>`).join(\"\\n\") +\n `\\n </hh:fontfaces>`\n}\n\n/**\n * 정적 borderFill 목록 — 기본 2종(1·2) + 개조식 7종(3~9) + 공문서 표 헤더 음영.\n * generator의 동적 id 배치(프로필·표 레지스트리 시작점)가 이 목록의 길이에서 파생되므로\n * (staticBorderFillNext) 여기가 정적 borderFill 개수의 단일 진실원천이다 (v4.0.5 P0-1).\n */\nfunction staticBorderFillItems(gongmun: ResolvedGongmun | null, v5 = false): string[] {\n const thin: BorderSide = [\"0.12 mm\", \"#000000\"]\n const items = [\n borderFillEntry(1, {}),\n borderFillEntry(2, { l: thin, r: thin, t: thin, b: thin }),\n ]\n if (!v5 && gongmun && needsGaejosikAssets(gongmun)) {\n // 개조식 전용 3~9 (gen-ids GJ_BF_*) — 실측 색상 (gaejosik.ts GAEJOSIK_COLORS)\n const c = GAEJOSIK_COLORS\n const edge: BorderSide = [\"0.12 mm\", c.border]\n const grayLine: BorderSide = [\"0.1 mm\", c.titleLine]\n const tocEdge: BorderSide = [\"0.4 mm\", c.tocBorder]\n items.push(\n borderFillEntry(3, { l: edge, r: edge, t: edge, b: edge }, c.primary), // 장 로마숫자 셀\n borderFillEntry(4, { l: edge }), // 장 간격 셀(좌선)\n borderFillEntry(5, { t: grayLine, b: grayLine }, c.titleFill), // 장 제목 셀\n borderFillEntry(6, {}, c.primary), // 표지 진한 바\n borderFillEntry(7, {}, c.accent), // 표지 연한 바\n borderFillEntry(8, { l: tocEdge, r: tocEdge, t: tocEdge, b: tocEdge }), // 목차 박스\n borderFillEntry(9, {}, c.tocStripe), // 목차 배너 라벤더 스트라이프\n )\n }\n if (gongmun) {\n // 표 헤더행 음영 — 실측: 정부 양식 표 헤더 #E6E6E6 (gen-ids gongmunTableHeaderBf)\n items.push(borderFillEntry(items.length + 1, { l: thin, r: thin, t: thin, b: thin }, \"#E6E6E6\"))\n }\n return items\n}\n\n/** 정적 borderFill 다음 발급 id — 프로필·표 레지스트리가 여기서부터 이어 쓴다 */\nexport function staticBorderFillNext(gongmun: ResolvedGongmun | null, v5 = false): number {\n return staticBorderFillItems(gongmun, v5).length + 1\n}\n\nfunction buildBorderFills(gongmun: ResolvedGongmun | null, extra: string[] = [], v5 = false): string {\n // 섹션 생성 중 등록된 표 위치별 borderFill (gen-table-bf TableBfRegistry)을 정적 목록 뒤에\n const items = [...staticBorderFillItems(gongmun, v5), ...extra]\n assertSequentialIds(items, \"borderFill\", 1)\n return `<hh:borderFills itemCnt=\"${items.length}\">\\n${items.join(\"\\n\")}\\n </hh:borderFills>`\n}\n\n/**\n * styles 블록 — 공문서 모드는 \"개요 1~4\" 명명 스타일 추가 (헤딩 문단이 styleIDRef로 참조).\n * OUTLINE paraPr 없이 스타일 이름만으로 헤딩 의미를 보존한다 — 한글이 OUTLINE 문단에\n * 개요 번호(\"1.\", \"1.1.\")를 강제 렌더하는 결함(COM 실렌더 확인) 회피.\n */\nfunction buildStyles(gongmun: ResolvedGongmun | null): string {\n const items = [\n `<hh:style id=\"0\" type=\"PARA\" name=\"바탕글\" engName=\"Normal\" paraPrIDRef=\"0\" charPrIDRef=\"0\" nextStyleIDRef=\"0\" langID=\"1042\" lockForm=\"0\"/>`,\n ]\n if (gongmun) {\n for (let lvl = 1; lvl <= 4; lvl++) {\n items.push(`<hh:style id=\"${lvl}\" type=\"PARA\" name=\"개요 ${lvl}\" engName=\"Outline ${lvl}\" paraPrIDRef=\"${lvl}\" charPrIDRef=\"${4 + lvl}\" nextStyleIDRef=\"0\" langID=\"1042\" lockForm=\"0\"/>`)\n }\n }\n return `<hh:styles itemCnt=\"${items.length}\">\\n ${items.join(\"\\n \")}\\n </hh:styles>`\n}\n\n/**\n * 공문서 탭 정의 — 한글 기본 서식과 같은 꼴. id 1 = 내어쓰기용 자동 탭(autoTabLeft): 항목부호 뒤 탭이\n * 내어쓰기 위치에 정확히 서서 첫 줄 내용 시작 = 둘째 줄 시작(법제처 서식 \"(a)⇥\" 실측: 부호폭 + 탭폭 = 내어쓰기)\n */\nconst TAB_PROPS_GONGMUN = `<hh:tabProperties itemCnt=\"2\">\n <hh:tabPr id=\"0\" autoTabLeft=\"0\" autoTabRight=\"0\"/>\n <hh:tabPr id=\"1\" autoTabLeft=\"1\" autoTabRight=\"0\"/>\n </hh:tabProperties>`\n\n/**\n * v5 엔진(gen-gongmun.ts) 헤더 모드 — 정적 블록은 비실측 공문서 최소 세트(charPr 0~16·paraPr 0~7·\n * 정적 글꼴 3종)만 두고, 나머지는 StyleRegistry가 발급한 XML을 이어붙인다.\n */\nexport interface HeaderV5 {\n paraPrXmls: string[]\n /** 본문 한글 글꼴(정적 fontface id 0) — 스킴 본문 글꼴 */\n bodyFace: string\n}\n\nexport function generateHeaderXml(theme: ResolvedTheme, gongmun: ResolvedGongmun | null, ratioVariants: number[] = [], extraBorderFills: string[] = [], extraCharPrXmls: string[] = [], listIndentVariants: Array<{ depth: number; widthHu: number }> = [], extraFonts: string[] = [], v5: HeaderV5 | null = null): string {\n // 본문 한글 글꼴 — fonts.body 오버라이드 > bodyFont 프리셋(gothic=맑은 고딕)\n const bodyFace = v5?.bodyFace ?? gongmun?.fonts.body ?? (gongmun?.bodyFont === \"gothic\" ? \"맑은 고딕\" : \"함초롬바탕\")\n const charPropsXml = buildCharProperties(theme, gongmun, ratioVariants, extraCharPrXmls, !!v5)\n const paraPropsXml = v5 ? buildParaPropertiesV5(gongmun!, v5.paraPrXmls) : buildParaProperties(gongmun, gongmun ? listIndentVariants : [])\n return `<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>\n<hh:head xmlns:hh=\"${NS_HEAD}\" xmlns:hp=\"${NS_PARA}\" xmlns:hc=\"${NS_CORE}\" version=\"1.4\" secCnt=\"1\">\n <hh:beginNum page=\"1\" footnote=\"1\" endnote=\"1\" pic=\"1\" tbl=\"1\" equation=\"1\"/>\n <hh:refList>\n ${buildFontFaces(gongmun, bodyFace, extraFonts, !!v5)}\n ${buildBorderFills(gongmun, extraBorderFills, !!v5)}\n ${charPropsXml}\n ${v5 || gongmun ? TAB_PROPS_GONGMUN : `<hh:tabProperties itemCnt=\"0\"/>`}\n ${buildNumberings()}\n <hh:bullets itemCnt=\"0\"/>\n ${paraPropsXml}\n ${buildStyles(gongmun)}\n </hh:refList>\n <hh:compatibleDocument targetProgram=\"HWP2018\"><hh:layoutCompatibility/></hh:compatibleDocument>\n</hh:head>`\n}\n","/**\n * 차트 생성 (P5) — ```chart 펜스 → OOXML chartSpace 파트 + <hp:chart> 참조\n *\n * HWPX 차트는 OLE가 아니라 Chart/chartN.xml(OOXML DrawingML chartSpace)을\n * manifest에 등재하고 본문에서 <hp:chart chartIDRef=\"…\">로 참조하는 구조다.\n * chartSpace 조립·타입 테이블은 claw-hwp(DoHyun468, MIT)의 한컴독스 GT 검증\n * 구현(hwpx-edit.js buildChartSpace/opInsertChart)을 TS로 이식했다.\n *\n * 펜스 규약 (콜론 구분 라인, 순서 무관):\n * ```chart\n * type: column ← column|bar|line|area|pie|doughnut|scatter|radar\n * (+_stacked, 3d 변형 — CHART_ALIAS), 생략 시 column\n * cat: 1분기, 2분기, 3분기\n * size: 120x70 ← mm (선택, 기본 113.8×66.1)\n * colors: #304D68, accent2 ← 계열 색 (pie는 조각 색, 선택)\n * 예산: 10, 20, 30 ← 그 외 \"이름: 숫자들\" 라인 = 데이터 계열\n * 집행: 5, 15, 25\n * ```\n */\n\nimport { HU_PER_MM } from \"./geometry.js\"\n\nconst XML_ESC: Record<string, string> = { \"&\": \"&\", \"<\": \"<\", \">\": \">\" }\nconst xmlEscape = (s: string): string => s.replace(/[&<>]/g, c => XML_ESC[c])\n\ninterface ChartTypeSpec {\n el: string\n dir?: \"col\" | \"bar\"\n grp?: \"clustered\" | \"stacked\" | \"standard\"\n overlap?: number\n marker?: boolean\n scatter?: boolean\n pie?: boolean\n explode?: boolean\n hole?: number\n radar?: boolean\n}\n\n/** 한컴독스 차트 20종 (claw-hwp GT) */\nconst CHART_TYPES: Record<number, ChartTypeSpec> = {\n 0: { el: \"barChart\", dir: \"col\", grp: \"clustered\" },\n 1: { el: \"barChart\", dir: \"col\", grp: \"stacked\", overlap: 100 },\n 2: { el: \"lineChart\", grp: \"standard\", marker: true },\n 3: { el: \"barChart\", dir: \"bar\", grp: \"clustered\" },\n 4: { el: \"barChart\", dir: \"bar\", grp: \"stacked\", overlap: 100 },\n 5: { el: \"scatterChart\", scatter: true },\n 6: { el: \"pieChart\", pie: true },\n 7: { el: \"pieChart\", pie: true, explode: true },\n 8: { el: \"doughnutChart\", pie: true, hole: 50 },\n 9: { el: \"areaChart\", grp: \"standard\" },\n 10: { el: \"areaChart\", grp: \"stacked\" },\n 11: { el: \"radarChart\", radar: true },\n 12: { el: \"bar3DChart\", dir: \"col\", grp: \"clustered\" },\n 13: { el: \"bar3DChart\", dir: \"col\", grp: \"stacked\", overlap: 100 },\n 14: { el: \"bar3DChart\", dir: \"bar\", grp: \"clustered\" },\n 15: { el: \"bar3DChart\", dir: \"bar\", grp: \"stacked\", overlap: 100 },\n 16: { el: \"pie3DChart\", pie: true },\n 17: { el: \"pie3DChart\", pie: true, explode: true },\n 18: { el: \"area3DChart\", grp: \"standard\" },\n 19: { el: \"area3DChart\", grp: \"stacked\" },\n}\n\nconst CHART_ALIAS: Record<string, number> = {\n column: 0, col: 0, 세로막대: 0, 막대: 0,\n column_stacked: 1, 세로막대_누적: 1,\n line: 2, 선: 2, 꺾은선: 2,\n bar: 3, 가로막대: 3,\n bar_stacked: 4,\n scatter: 5, 분산: 5,\n pie: 6, 원: 6, 파이: 6,\n pie_explode: 7,\n doughnut: 8, donut: 8, 도넛: 8,\n area: 9, 영역: 9,\n area_stacked: 10,\n radar: 11, 방사형: 11,\n bar3d: 12, column3d: 12,\n pie3d: 16,\n}\n\nfunction chartSpec(t: string | undefined): ChartTypeSpec {\n if (!t) return CHART_TYPES[0]\n const key = CHART_ALIAS[t.toLowerCase()] ?? Number(t)\n return CHART_TYPES[key] ?? CHART_TYPES[0]\n}\n\n/** 파싱된 차트 펜스 */\nexport interface ChartFence {\n spec: ChartTypeSpec\n cat: string[]\n series: Array<{ name: string; values: number[]; color?: string; pointColors?: string[] }>\n widthHu: number\n heightHu: number\n}\n\n// HU_PER_MM은 geometry.ts SSOT (v4.0.5 P0-3)\n\n/** 예약 키 — 계열 이름으로 쓸 수 없는 라인 */\nconst RESERVED_KEYS = new Set([\"type\", \"cat\", \"size\", \"colors\", \"point_colors\", \"title\"])\n\n/**\n * ```chart 펜스 본문 파싱. 계열이 하나도 없으면 null (호출부가 일반 코드블록으로 폴백).\n */\nexport function parseChartFence(text: string): ChartFence | null {\n let type: string | undefined\n let cat: string[] | null = null\n let widthMm = 32250 / HU_PER_MM\n let heightMm = 18750 / HU_PER_MM\n let colors: string[] | null = null\n let pointColors: string[] | null = null\n const series: Array<{ name: string; values: number[] }> = []\n\n for (const rawLine of text.split(\"\\n\")) {\n const line = rawLine.trim()\n if (!line || line.startsWith(\"#\")) continue\n const colon = line.search(/[::]/)\n if (colon <= 0) continue\n const key = line.slice(0, colon).trim()\n const value = line.slice(colon + 1).trim()\n const keyLower = key.toLowerCase()\n\n if (keyLower === \"type\") {\n type = value\n } else if (keyLower === \"cat\") {\n cat = value.split(\",\").map(s => s.trim()).filter(Boolean)\n } else if (keyLower === \"size\") {\n const m = value.match(/^(\\d+(?:\\.\\d+)?)\\s*[x×]\\s*(\\d+(?:\\.\\d+)?)$/i)\n if (m) {\n // 0·거대 치수 클램프 — 크기 0 개체·본문폭 초과 레이아웃 파괴 방지 (10~500mm)\n const clamp = (n: number): number => Math.min(500, Math.max(10, n))\n widthMm = clamp(Number(m[1]))\n heightMm = clamp(Number(m[2]))\n }\n } else if (keyLower === \"colors\") {\n colors = value.split(\",\").map(s => s.trim()).filter(Boolean)\n } else if (keyLower === \"point_colors\") {\n pointColors = value.split(\",\").map(s => s.trim()).filter(Boolean)\n } else if (keyLower === \"title\") {\n // 차트 제목은 본문 텍스트로 쓰는 것을 권장 — 호환 위해 무시(에러 아님)\n } else if (!RESERVED_KEYS.has(keyLower)) {\n // 천단위 콤마(1,000)를 한 숫자로 흡수(자릿수 패턴) 후 구분자 콤마로 분리, 빈 세그먼트 거부(cat 대칭)\n const segs = value.replace(/(\\d),(?=\\d{3}(?:\\D|$))/g, \"$1\").split(\",\").map(s => s.trim()).filter(Boolean)\n if (segs.length === 0) continue // 값 없는 라인 — Number(\"\")===0 [0] 계열 둔갑 금지\n const nums = segs.map(Number)\n if (nums.every(n => Number.isFinite(n))) {\n series.push({ name: key, values: nums })\n } else {\n return null // 비숫자 토큰 — 부분 손실(무통보 드랍) 대신 코드블록 폴백(원문 노출로 사용자 인지)\n }\n }\n }\n\n if (series.length === 0) return null\n const spec = chartSpec(type)\n let finalSeries: ChartFence[\"series\"] = spec.pie ? [series[0]] : series\n finalSeries = finalSeries.map(s => ({ ...s }))\n // cat 라벨 길이 = max(명시 cat, 최장 계열). 계열이 라벨보다 길어도 꼬리 값을\n // 절단하지 않고 `항목 N`으로 라벨을 확장해 보존한다(무음 데이터 손실 금지 — 리뷰 chart-5).\n const ptLen = Math.max(cat?.length ?? 0, ...finalSeries.map(s => s.values.length))\n const catFinal = Array.from({ length: ptLen }, (_, i) => cat?.[i] ?? `항목 ${i + 1}`)\n // cat/values 개수 일치 — strCache/numCache ptCount 불일치(OOXML 계약 위반) 방지.\n // scatter 는 xVal/yVal 독립 축이라 제외.\n if (!spec.scatter) {\n finalSeries = finalSeries.map(s => ({ ...s, values: catFinal.map((_, i) => s.values[i] ?? 0) }))\n }\n if (spec.pie) {\n const slice = colors ?? pointColors\n if (slice) finalSeries[0].pointColors = slice\n } else {\n if (colors) finalSeries.forEach((s, i) => { s.color = colors![i % colors!.length] })\n if (pointColors && finalSeries[0]) finalSeries[0].pointColors = pointColors\n }\n return {\n spec,\n cat: catFinal,\n series: finalSeries,\n widthHu: Math.round(widthMm * HU_PER_MM),\n heightHu: Math.round(heightMm * HU_PER_MM),\n }\n}\n\n// ─── chartSpace OOXML 조립 (claw-hwp buildChartSpace 이식) ───\n\nconst colLetter = (i: number): string => String.fromCharCode(66 + i) // 0→B\n\nfunction strCachePts(vals: string[]): string {\n return `<c:ptCount val=\"${vals.length}\"/>` +\n vals.map((v, i) => `<c:pt idx=\"${i}\"><c:v>${xmlEscape(v)}</c:v></c:pt>`).join(\"\")\n}\n\nfunction numCachePts(vals: number[]): string {\n return `<c:formatCode>General</c:formatCode><c:ptCount val=\"${vals.length}\"/>` +\n vals.map((v, i) => `<c:pt idx=\"${i}\"><c:v>${Number(v) || 0}</c:v></c:pt>`).join(\"\")\n}\n\n/** 색 → solidFill. accent1~6=한컴 내장 팔레트, #RRGGBB=리터럴. 그 외 무시 */\nfunction chartColorFill(color: string | undefined): string | null {\n if (color == null) return null\n const c = color.trim()\n if (/^accent[1-6]$/i.test(c)) return `<a:solidFill><a:schemeClr val=\"${c.toLowerCase()}\"/></a:solidFill>`\n const hex = c.replace(/^#/, \"\").toUpperCase()\n if (/^[0-9A-F]{6}$/.test(hex)) return `<a:solidFill><a:srgbClr val=\"${hex}\"/></a:solidFill>`\n return null\n}\n\n/** 선형(line/radar) 계열 색은 <a:ln> 안에, 면형은 맨 solidFill (claw-hwp GT) */\nfunction serSpPr(color: string | undefined, stroke: boolean): string {\n const f = chartColorFill(color)\n if (!f) return \"<c:spPr/>\"\n return stroke\n ? `<c:spPr><a:ln w=\"28575\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\">${f}<a:prstDash val=\"solid\"/><a:round/></a:ln></c:spPr>`\n : `<c:spPr>${f}</c:spPr>`\n}\n\n/** 포인트(막대/조각)별 색 오버라이드 */\nfunction dPtXml(pointColors: string[] | undefined, pie: boolean): string {\n if (!pointColors?.length) return \"\"\n return pointColors.map((col, i) => {\n const f = chartColorFill(col)\n if (!f) return \"\"\n const mid = pie\n ? '<c:invertIfNegative val=\"0\"/><c:bubble3D val=\"0\"/><c:explosion val=\"0\"/>'\n : '<c:bubble3D val=\"0\"/>'\n return `<c:dPt><c:idx val=\"${i}\"/>${mid}<c:spPr>${f}</c:spPr></c:dPt>`\n }).join(\"\")\n}\n\nfunction stdSer(\n idx: number, name: string, cat: string[], values: number[],\n explode: boolean, color: string | undefined, pointColors: string[] | undefined,\n stroke: boolean, pie: boolean,\n): string {\n const cl = colLetter(idx)\n return `<c:ser><c:idx val=\"${idx}\"/><c:order val=\"${idx}\"/>` +\n `<c:tx><c:strRef><c:f>Sheet1!$${cl}$1</c:f><c:strCache><c:ptCount val=\"1\"/><c:pt idx=\"0\"><c:v>${xmlEscape(name)}</c:v></c:pt></c:strCache></c:strRef></c:tx>` +\n `${serSpPr(color, stroke)}<c:invertIfNegative val=\"0\"/>` +\n (explode ? `<c:explosion val=\"25\"/>` : \"\") +\n dPtXml(pointColors, pie) +\n `<c:cat><c:strRef><c:f>Sheet1!$A$2:$A$${cat.length + 1}</c:f><c:strCache>${strCachePts(cat)}</c:strCache></c:strRef></c:cat>` +\n `<c:val><c:numRef><c:f>Sheet1!$${cl}$2:$${cl}$${values.length + 1}</c:f><c:numCache>${numCachePts(values)}</c:numCache></c:numRef></c:val>` +\n `</c:ser>`\n}\n\nfunction scatterSer(idx: number, name: string, xvals: number[], yvals: number[]): string {\n const cl = colLetter(idx)\n return `<c:ser><c:idx val=\"${idx}\"/><c:order val=\"${idx}\"/>` +\n `<c:tx><c:strRef><c:f>Sheet1!$${cl}$1</c:f><c:strCache><c:ptCount val=\"1\"/><c:pt idx=\"0\"><c:v>${xmlEscape(name)}</c:v></c:pt></c:strCache></c:strRef></c:tx>` +\n `<c:spPr><a:ln w=\"28575\"><a:noFill/></a:ln></c:spPr><c:marker><c:symbol val=\"circle\"/><c:size val=\"7\"/></c:marker>` +\n `<c:xVal><c:numRef><c:f>Sheet1!$A$2:$A$${xvals.length + 1}</c:f><c:numCache>${numCachePts(xvals)}</c:numCache></c:numRef></c:xVal>` +\n `<c:yVal><c:numRef><c:f>Sheet1!$${cl}$2:$${cl}$${yvals.length + 1}</c:f><c:numCache>${numCachePts(yvals)}</c:numCache></c:numRef></c:yVal>` +\n `</c:ser>`\n}\n\nfunction catAxXml(id: string, pos: string, cross: string): string {\n return `<c:catAx><c:axId val=\"${id}\"/><c:scaling><c:orientation val=\"minMax\"/></c:scaling><c:axPos val=\"${pos}\"/><c:crossAx val=\"${cross}\"/><c:delete val=\"0\"/><c:majorTickMark val=\"out\"/><c:minorTickMark val=\"none\"/><c:tickLblPos val=\"nextTo\"/><c:crosses val=\"autoZero\"/><c:auto val=\"1\"/><c:lblAlgn val=\"ctr\"/><c:lblOffset val=\"100\"/><c:noMultiLvlLbl val=\"0\"/></c:catAx>`\n}\n\nfunction valAxXml(id: string, pos: string, cross: string): string {\n return `<c:valAx><c:axId val=\"${id}\"/><c:scaling><c:orientation val=\"minMax\"/></c:scaling><c:axPos val=\"${pos}\"/><c:majorGridlines/><c:numFmt formatCode=\"General\" sourceLinked=\"1\"/><c:crossAx val=\"${cross}\"/><c:delete val=\"0\"/><c:majorTickMark val=\"out\"/><c:minorTickMark val=\"none\"/><c:tickLblPos val=\"nextTo\"/><c:crosses val=\"autoZero\"/><c:crossBetween val=\"between\"/></c:valAx>`\n}\n\n/** 차트 펜스 → chartSpace XML 전문 */\nexport function buildChartSpaceXml(fence: ChartFence): string {\n const { spec, cat, series } = fence\n const NS = 'xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\" xmlns:c=\"http://schemas.openxmlformats.org/drawingml/2006/chart\"'\n const ax1 = \"111111111\"\n const ax2 = \"222222222\"\n let plot: string\n if (spec.scatter) {\n // X값: 숫자 카테고리면 그대로, 아니면 1-based 인덱스 (가장 긴 계열 길이에 맞춤)\n const n = Math.max(0, ...series.map(s => s.values.length))\n const xs = Array.from({ length: n }, (_, i) => {\n const c = cat[i]\n const v = Number(c)\n return c !== undefined && c !== \"\" && Number.isFinite(v) ? v : i + 1\n })\n const sers = series.map((s, i) => scatterSer(i, s.name, xs, s.values)).join(\"\")\n plot = `<c:scatterChart><c:scatterStyle val=\"lineMarker\"/><c:varyColors val=\"0\"/>${sers}<c:axId val=\"${ax1}\"/><c:axId val=\"${ax2}\"/></c:scatterChart>` +\n valAxXml(ax1, \"b\", ax2) + valAxXml(ax2, \"l\", ax1)\n } else if (spec.pie) {\n const s0 = series[0]\n plot = `<c:${spec.el}><c:varyColors val=\"1\"/>${stdSer(0, s0.name, cat, s0.values, !!spec.explode, s0.color, s0.pointColors, false, true)}<c:firstSliceAng val=\"0\"/>` +\n (spec.hole != null ? `<c:holeSize val=\"${spec.hole}\"/>` : \"\") + `</c:${spec.el}>`\n } else {\n const stroke = spec.el === \"lineChart\" || spec.el === \"radarChart\" || !!spec.radar\n const sers = series.map((s, i) => stdSer(i, s.name, cat, s.values, false, s.color, s.pointColors, stroke, false)).join(\"\")\n const horiz = spec.dir === \"bar\"\n let inner = \"\"\n if (spec.dir) inner += `<c:barDir val=\"${spec.dir}\"/>`\n if (spec.grp) inner += `<c:grouping val=\"${spec.grp}\"/>`\n if (spec.radar) inner += `<c:radarStyle val=\"standard\"/>`\n inner += `<c:varyColors val=\"0\"/>${sers}`\n if (spec.marker) inner += `<c:marker val=\"1\"/>`\n if (spec.el.startsWith(\"bar\")) inner += `<c:gapWidth val=\"150\"/><c:overlap val=\"${spec.overlap ?? 0}\"/>`\n inner += `<c:axId val=\"${ax1}\"/><c:axId val=\"${ax2}\"/>`\n plot = `<c:${spec.el}>${inner}</c:${spec.el}>` + catAxXml(ax1, horiz ? \"l\" : \"b\", ax2) + valAxXml(ax2, horiz ? \"b\" : \"l\", ax1)\n }\n return `<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>` +\n `<c:chartSpace ${NS}><c:date1904 val=\"0\"/><c:roundedCorners val=\"0\"/>` +\n `<c:chart><c:autoTitleDeleted val=\"0\"/><c:plotArea><c:layout/>${plot}</c:plotArea>` +\n `<c:legend><c:legendPos val=\"r\"/><c:overlay val=\"0\"/></c:legend>` +\n `<c:plotVisOnly val=\"1\"/><c:dispBlanksAs val=\"gap\"/></c:chart></c:chartSpace>`\n}\n\n/**\n * 본문용 <hp:chart> — 글자처럼 취급(treatAsChar=1)이라 삽입 위치에 그대로 앉고\n * 다른 페이지로 떠내려가지 않는다 (claw-hwp GT 규약).\n */\nexport function buildChartElementXml(partName: string, widthHu: number, heightHu: number, id: number): string {\n return `<hp:chart id=\"${id}\" zOrder=\"0\" numberingType=\"PICTURE\" textWrap=\"TOP_AND_BOTTOM\" textFlow=\"BOTH_SIDES\" lock=\"0\" dropcapstyle=\"None\" chartIDRef=\"${partName}\">` +\n `<hp:sz width=\"${widthHu}\" widthRelTo=\"ABSOLUTE\" height=\"${heightHu}\" heightRelTo=\"ABSOLUTE\" protect=\"0\"/>` +\n `<hp:pos treatAsChar=\"1\" affectLSpacing=\"0\" flowWithText=\"1\" allowOverlap=\"0\" holdAnchorAndSO=\"0\" vertRelTo=\"PARA\" horzRelTo=\"PARA\" vertAlign=\"TOP\" horzAlign=\"LEFT\" vertOffset=\"0\" horzOffset=\"0\"/>` +\n `<hp:outMargin left=\"709\" right=\"709\" top=\"709\" bottom=\"709\"/></hp:chart>`\n}\n","/**\n * 공문서 모드 선계산 (generator.ts에서 분리).\n * 자동장평(orphan 줄 축소) 계획과 리스트 항목부호/깊이 사전 산출.\n */\n\nimport { type ResolvedGongmun, GongmunNumberer, computeSuppression, levelMarkerHeight, hangulOrdinal, levelIndent, markerWidth, mmToHwpunit, usesAsteriskThird, usesReportFonts } from \"./gongmun.js\"\nimport { fitRatioForFewerLines } from \"./text-metrics.js\"\nimport { type MdBlock, parseInlineMarkdown } from \"./md-runs.js\"\nimport { CHAR_VARIANT_BASE, GONGMUN_BODY_RATIO, GONGMUN_LIST_LEVELS } from \"./gen-ids.js\"\nimport { A4_W_HU } from \"./geometry.js\"\nimport { parseChartFence } from \"./chart-gen.js\"\n\nexport interface GongmunFitPlan {\n /** blockIdx → 축소 장평(%) */\n ratioByBlock: Map<number, number>\n /** 등장한 고유 장평 목록(변형 charPr 발급 순서) */\n variants: number[]\n}\n\n/** 리스트 항목 하나의 선계산 결과 */\nexport interface GongmunListItem {\n marker: string\n depth: number\n /**\n * (depth, 부호폭) 전용 내어쓰기 paraPr 변형 인덱스 (GONGMUN_LIST_VARIANT_BASE + n).\n * depth 대표 부호('1.')보다 넓은 부호('10.'·'(10)')를 단 항목에만 부여 —\n * 공용 paraPr의 고정 내어쓰기로는 둘째 줄이 내용 첫 글자보다 왼쪽으로 어긋난다 (v4.0.5 P1-1)\n */\n indentVariant?: number\n}\n\n/** precomputeGongmunList 결과 — 항목 매핑 + 내어쓰기 변형 paraPr 스펙 */\nexport interface GongmunListPlan {\n items: Map<number, GongmunListItem>\n /** 변형 paraPr 발급 목록 (등장 순) — gen-header가 GONGMUN_LIST_VARIANT_BASE부터 방출 */\n indentVariants: Array<{ depth: number; widthHu: number }>\n}\n\n/** 렌더될 문자열(마크다운 강조 문법 제거) — 폭 계산용 */\nfunction plainRenderText(text: string): string {\n return parseInlineMarkdown(text).map(s => s.text).join(\"\")\n}\n\n/**\n * 문단별 자동 장평 계획 — 어절 줄바꿈 시뮬레이션으로 \"장평을 줄이면 한 줄을\n * 아낄 수 있는\" 문단을 찾아 95→minRatio 범위의 가장 큰 장평을 배정한다.\n * 대상: 일반 문단·항목(list_item). 제목/가운데정렬/코드/인용/표는 제외.\n */\nexport function computeGongmunFitPlan(\n blocks: MdBlock[],\n gongmun: ResolvedGongmun,\n gongmunList: GongmunListPlan,\n): GongmunFitPlan | null {\n const minRatio = gongmun.autoFitMinRatio\n if (minRatio === null || minRatio >= GONGMUN_BODY_RATIO) return null\n const pageW = A4_W_HU - mmToHwpunit(gongmun.margins.left) - mmToHwpunit(gongmun.margins.right)\n const ratioByBlock = new Map<number, number>()\n const variants: number[] = []\n\n for (let i = 0; i < blocks.length; i++) {\n const block = blocks[i]\n let text: string\n let firstW: number\n let contW: number\n if (block.type === \"list_item\" && gongmunList.items.has(i)) {\n const { marker, depth, indentVariant } = gongmunList.items.get(i)!\n // 개조식 □(16pt)·※(13pt)는 본문 charPr(15pt) 계열이 아니라 변형 제외\n if (gongmun.numbering === \"gaejosik\" && (depth === 0 || (block.text || \"\").trimStart().startsWith(\"※\"))) continue\n // levels 오버라이드 단계는 전용 charPr(다른 크기·글꼴) — 본문 장평 변형 대상 아님 (v4.12.3)\n if (gongmun.levels?.[depth]) continue\n const content = plainRenderText(block.text || \"\")\n text = marker ? `${marker} ${content}` : content\n const li = levelIndent(depth, gongmun.bodyHeight, gongmun.numbering, gongmun.sizes, gongmun.bullet2, usesAsteriskThird(gongmun.preset))\n // 부호 생략 항목은 내어쓰기 없는 전용 paraPr(GONGMUN_LIST_PLAIN_BASE) — indent 0.\n // 내어쓰기 변형('10.'류)은 자기 부호폭 기준 (P1-1)\n const left = li.left\n const indent = marker\n ? (indentVariant !== undefined ? -gongmunList.indentVariants[indentVariant].widthHu : li.indent)\n : 0\n // 음수 intent(내어쓰기): 첫 줄은 left에서, 둘째 줄부터 left+|intent|에서 시작\n firstW = pageW - left - Math.max(indent, 0)\n contW = pageW - left - Math.max(-indent, 0)\n } else if (block.type === \"paragraph\") {\n const raw = (block.text || \"\").trim()\n if (/^<center>[\\s\\S]*<\\/center>$/i.test(raw)) continue // 가운데정렬 — 대상 아님\n if (gongmun.numbering === \"gaejosik\" && raw.startsWith(\"※\")) continue // ※ 참고(13pt) 제외\n text = plainRenderText(raw)\n firstW = contW = pageW\n } else {\n continue\n }\n if (!text) continue\n const r = fitRatioForFewerLines(text, firstW, contW, gongmun.bodyHeight, GONGMUN_BODY_RATIO, minRatio)\n if (r === null) continue\n ratioByBlock.set(i, r)\n if (!variants.includes(r)) variants.push(r)\n }\n return ratioByBlock.size > 0 ? { ratioByBlock, variants } : null\n}\n\n/** fit 계획에 따른 charPr id 매퍼 — 본문 계열(0~3)만 변형으로 치환.\n * base: 변형 charPr 시작 id (개조식은 전용 charPr 뒤 — gen-ids charVariantBase) */\nexport function variantMapper(fit: GongmunFitPlan, blockIdx: number, base: number = CHAR_VARIANT_BASE): ((id: number) => number) | undefined {\n const r = fit.ratioByBlock.get(blockIdx)\n if (r === undefined) return undefined\n const vi = fit.variants.indexOf(r)\n return (id) => (id >= 0 && id <= 3 ? base + vi * 4 + id : id)\n}\n\n// 법정 8단계·보고서 불릿의 리터럴 부호 → depth 역산 테이블 (P2 재분류용).\n// 한글 서수는 hangulOrdinal 정규 시퀀스(초성14×단모음6 조합 84자)만 인정 —\n// '는.'·'를.' 같은 일반 음절 문두 오검출 방지.\nconst ORDINAL_SYLLABLES = new Set(Array.from({ length: 84 }, (_, i) => hangulOrdinal(i)))\n\n/** 문단 선두 리터럴 부호 판독 — {depth, 부호 제거한 내용} 또는 null */\nfunction literalMarkerDepth(text: string): { depth: number; content: string } | null {\n const t = text.trimStart()\n let m: RegExpExecArray | null\n if ((m = /^([가-힣])\\.\\s+(.*)$/s.exec(t)) && ORDINAL_SYLLABLES.has(m[1])) return { depth: 1, content: m[2] }\n if ((m = /^(\\d{1,3})\\)\\s+(.*)$/s.exec(t))) return { depth: 2, content: m[2] }\n if ((m = /^([가-힣])\\)\\s+(.*)$/s.exec(t)) && ORDINAL_SYLLABLES.has(m[1])) return { depth: 3, content: m[2] }\n if ((m = /^\\((\\d{1,3})\\)\\s+(.*)$/s.exec(t))) return { depth: 4, content: m[2] }\n if ((m = /^\\(([가-힣])\\)\\s+(.*)$/s.exec(t)) && ORDINAL_SYLLABLES.has(m[1])) return { depth: 5, content: m[2] }\n if ((m = /^([①-⑳㉑-㉟㊱-㊿])\\s+(.*)$/s.exec(t))) return { depth: 6, content: m[2] }\n if ((m = /^([㉮-㉻])\\s+(.*)$/s.exec(t))) return { depth: 7, content: m[2] }\n if ((m = /^□\\s+(.*)$/s.exec(t))) return { depth: 0, content: m[1] }\n if ((m = /^[○ㅇ]\\s+(.*)$/s.exec(t))) return { depth: 1, content: m[1] }\n if ((m = /^ㆍ\\s+(.*)$/s.exec(t))) return { depth: 3, content: m[1] }\n return null\n}\n\n/**\n * 리터럴 부호 문단 → list_item 재분류 (blocks in-place, gongmun 모드 전용).\n * ※ 참고·<center>/<right> 지시 문단은 제외. depthOffset(공고문 h2 번호 등)을\n * 되돌려 최종 depth == 부호 종류의 법정 depth가 되게 한다.\n */\nfunction reclassifyLiteralItems(blocks: MdBlock[], depthOffset: number): void {\n for (const b of blocks) {\n if (b.type !== \"paragraph\") continue\n const raw = (b.text || \"\").trimStart()\n if (!raw || raw.startsWith(\"※\") || /^\\*\\s/.test(raw) || /^<(center|right)>/i.test(raw)) continue\n const lit = literalMarkerDepth(raw)\n if (!lit || !lit.content.trim()) continue\n b.type = \"list_item\"\n b.text = lit.content\n b.indent = Math.max(lit.depth - depthOffset, 0)\n b.ordered = lit.depth !== 0 // □만 불릿 취급 (renumber는 depth 기반이라 영향 없음)\n }\n}\n\n/**\n * 공문서 모드 리스트 사전 처리 — 연속된 list_item run마다 단계별 부호 산출 +\n * 단일 형제 부호 생략. block 인덱스 → {marker, depth} 매핑 반환.\n */\nexport function precomputeGongmunList(\n blocks: MdBlock[],\n gongmun: ResolvedGongmun,\n): GongmunListPlan {\n const result = new Map<number, GongmunListItem>()\n // (depth, 부호폭) 내어쓰기 변형 — depth 대표 부호폭과 다른 항목('10.' 등 두 자리)에만.\n // key `${depth}:${width}` → indentVariants 인덱스\n const indentVariants: Array<{ depth: number; widthHu: number }> = []\n const variantIdx = new Map<string, number>()\n const variantOf = (marker: string, depth: number): number | undefined => {\n // 순번에 따라 부호폭이 변하는 체계는 법정 번호(standard)뿐 — 불릿(report·gaejosik)은\n // depth당 부호가 고정이고, 개조식 indent는 실측 체계(gaejosikLevelIndent)가 정본이다\n if (!marker || gongmun.numbering !== \"standard\") return undefined\n // 부호폭은 그 단계의 글자 크기(levels 오버라이드 반영)로 — 대표 부호와 같은 기준\n const h = levelMarkerHeight(gongmun, depth)\n const w = markerWidth(marker, h)\n const rep = -levelIndent(depth, gongmun.bodyHeight, gongmun.numbering, gongmun.sizes, gongmun.bullet2, usesAsteriskThird(gongmun.preset), h).indent\n if (w === rep) return undefined\n const key = `${depth}:${w}`\n let vi = variantIdx.get(key)\n if (vi === undefined) {\n vi = indentVariants.length\n indentVariants.push({ depth, widthHu: w })\n variantIdx.set(key, vi)\n }\n return vi\n }\n // 개조식 적응 시프트 — h3가 □ 대항목을 차지하는 문서는 리스트가 ○부터 시작.\n // 법정 8단계 + h2 말머리 'number'(공고문)는 h2가 1단계(1. 2.)를 차지하므로\n // 리스트를 한 단계 내림(가.부터 + 1자 들여쓰기) — \"1. 제목 / 1. 본문\" 동일 부호\n // 중복은 규정 위계 위반 (v4.0.2 실무자 QA)\n const depthOffset =\n (gongmun.numbering === \"gaejosik\" && blocks.some((b) => b.type === \"heading\" && b.level === 3)) ||\n (gongmun.numbering === \"standard\" && gongmun.h2Marker === \"number\" && blocks.some((b) => b.type === \"heading\" && b.level === 2))\n ? 1\n : 0\n // 리터럴 부호 문단 재분류 (v4.0.5 P2) — parse가 방출한 기존 공문서의 항목이\n // '가. 내용'·'1) 내용'·'□ 내용' 리터럴 문단으로 고착되면 2차 생성에서 8단계\n // 자동 재번호가 안 걸린다. 부호 종류로 depth를 역산해 list_item으로 복원한다.\n reclassifyLiteralItems(blocks, depthOffset)\n let i = 0\n while (i < blocks.length) {\n if (blocks[i].type !== \"list_item\") { i++; continue }\n // 연속 run 수집 — 항목 사이에 낀 표/수식은 run을 끊지 않는다 (공문 관행: 항목\n // 아래 근거 표·수식을 붙이고 다음 항목 번호가 이어짐 — 리뷰 #39 ·5).\n // 표/수식 뒤에 항목이 없으면 거기서 종료.\n // 항목 사이에 낀 표·수식·차트(실변환되는 chart 펜스)는 run 을 끊지 않는다. 변환 실패\n // (계열 0)한 chart 펜스는 일반 코드블록이므로 run 절단이 맞다 (gen-section 판정과 일치).\n const passThrough = (b: MdBlock): boolean =>\n b.type === \"table\" || b.type === \"html_table\" || b.type === \"equation\" ||\n (b.type === \"code_block\" && (b.lang || \"\").toLowerCase() === \"chart\" && parseChartFence(b.text || \"\") !== null)\n const run: number[] = []\n while (i < blocks.length) {\n const b = blocks[i]\n if (b.type === \"list_item\") { run.push(i); i++; continue }\n if (passThrough(b)) {\n let j = i + 1\n while (j < blocks.length && passThrough(blocks[j])) j++\n if (j < blocks.length && blocks[j].type === \"list_item\") { i = j; continue }\n }\n break\n }\n const depths = run.map((bi) => Math.min(Math.max((blocks[bi].indent || 0) + depthOffset, 0), GONGMUN_LIST_LEVELS - 1))\n // 실측 프리셋(measured)에서 ※ 시작 항목·'*' 마커 항목은 렌더가 참고(※) 문단으로\n // 빼내며 번호를 버린다(gen-section). 그 항목이 법정번호(standard) 카운터를 소비하면\n // 뒤 항목 번호가 건너뛰므로(1. → ※ → 3.), 번호매김·형제집계에서 함께 제외한다.\n const measured = usesReportFonts(gongmun.preset)\n const isRef = (bi: number): boolean =>\n measured && ((blocks[bi].text || \"\").trimStart().startsWith(\"※\") || blocks[bi].marker === \"*\")\n const activeK = run.map((_, k) => k).filter((k) => !isRef(run[k]))\n const activeDepths = activeK.map((k) => depths[k])\n // 단일 형제 부호 생략(편람 규정)은 suppressSingle 옵트인 + 법정 번호(standard)에만.\n // 기본은 하나여도 부호 부여 — 부호 없는 계단 들여쓰기가 실무 눈에 어색 (v4.0.2 QA)\n const suppress = gongmun.suppressSingle && gongmun.numbering === \"standard\"\n ? computeSuppression(activeDepths)\n : activeDepths.map(() => false)\n const numberer = new GongmunNumberer(gongmun.numbering, gongmun.bullet2, usesAsteriskThird(gongmun.preset))\n // 참고 항목은 번호 없이 depth만 기록(fit 계획용), 비참고 항목만 순번 부여\n run.forEach((bi, k) => { if (isRef(run[k])) result.set(bi, { marker: \"\", depth: depths[k] }) })\n activeK.forEach((k, j) => {\n const marker = numberer.next(activeDepths[j], suppress[j])\n result.set(run[k], { marker, depth: depths[k], indentVariant: variantOf(marker, depths[k]) })\n })\n }\n return { items: result, indentVariants }\n}\n","/**\n * 개조식 보고서 전용 XML 조립 — 표지·목차·장 헤더 표 (gen-section에서 사용).\n * 스타일 값·기하는 실측 상수(gaejosik.ts), id 매핑은 gen-ids.ts.\n */\n\nimport { type ResolvedGongmun } from \"./gongmun.js\"\nimport { TOC_GEOM, formatGaejosikDate, gaejosikSizes, coverGeom, chapterGeom, tocBannerGeom, bodyTitleGeom, GAEJOSIK_BASE_WIDTH } from \"./gaejosik.js\"\nimport { simulateWrap } from \"./text-metrics.js\"\nimport { GJ_TABLE_ID_BASE } from \"./geometry.js\"\nimport {\n GONGMUN_CENTER, PARA_NORMAL, CHAR_NORMAL,\n GJ_CHAR_CHAPTER_NUM, GJ_CHAR_CHAPTER_TITLE, GJ_CHAR_COVER_TITLE, GJ_CHAR_COVER_SUB,\n GJ_CHAR_TOC_LABEL, GJ_CHAR_TOC_ROMAN, GJ_CHAR_TOC_ITEM, GJ_CHAR_BAR, GJ_CHAR_BODY_TITLE,\n GJ_PARA_COVER, GJ_PARA_TOC_ITEM, GJ_PARA_CHAPTER, GJ_PARA_BAR,\n GJ_BF_CHAPTER_NUM, GJ_BF_CHAPTER_GAP, GJ_BF_CHAPTER_TITLE,\n GJ_BF_BAR_DARK, GJ_BF_BAR_LIGHT, GJ_BF_TOC_BOX, GJ_BF_TOC_STRIPE,\n escapeTextXml,\n} from \"./gen-ids.js\"\n\n// ─── 공통 조각 ──────────────────────────────────────\n\n/** 장 로마숫자 — 정본 단일 문자 Ⅰ~Ⅻ(U+2160~), 초과 시 조합 */\nexport function chapterRoman(n: number): string {\n if (n >= 1 && n <= 12) return String.fromCodePoint(0x215f + n)\n const t: [number, string][] = [[10, \"Ⅹ\"], [9, \"Ⅸ\"], [5, \"Ⅴ\"], [4, \"Ⅳ\"], [1, \"Ⅰ\"]]\n let s = \"\"\n for (const [v, r] of t) while (n >= v) { s += r; n -= v }\n return s\n}\n\nfunction emptyPara(paraPrId: number = PARA_NORMAL, pageBreak = false, charPrId: number = CHAR_NORMAL): string {\n const brk = pageBreak ? ` pageBreak=\"1\"` : \"\"\n return `<hp:p paraPrIDRef=\"${paraPrId}\" styleIDRef=\"0\"${brk}><hp:run charPrIDRef=\"${charPrId}\"><hp:t></hp:t></hp:run></hp:p>`\n}\n\nlet gjTableId = GJ_TABLE_ID_BASE\n/** 문서 생성마다 개조식 표 id 카운터 리셋 (결정적 출력) */\nexport function resetGjTableIds(): void { gjTableId = GJ_TABLE_ID_BASE }\nfunction cell(opts: {\n bf: number; col: number; w: number; h: number\n row?: number; colSpan?: number; paras?: string; vertAlign?: string\n /** 왕복 채널 셀 이름 (v4.0.5 P2) — `__kordoc_h1`류. 한컴 렌더에는 영향 없는 메타데이터 */\n name?: string\n}): string {\n const paras = opts.paras ?? emptyPara()\n return `<hp:tc name=\"${opts.name ?? \"\"}\" header=\"0\" hasMargin=\"0\" protect=\"0\" editable=\"1\" dirty=\"0\" borderFillIDRef=\"${opts.bf}\">`\n + `<hp:subList id=\"\" textDirection=\"HORIZONTAL\" lineWrap=\"BREAK\" vertAlign=\"${opts.vertAlign ?? \"CENTER\"}\" linkListIDRef=\"0\" linkListNextIDRef=\"0\" textWidth=\"0\" textHeight=\"0\" hasTextRef=\"0\" hasNumRef=\"0\">${paras}</hp:subList>`\n + `<hp:cellAddr colAddr=\"${opts.col}\" rowAddr=\"${opts.row ?? 0}\"/>`\n + `<hp:cellSpan colSpan=\"${opts.colSpan ?? 1}\" rowSpan=\"1\"/>`\n + `<hp:cellSz width=\"${opts.w}\" height=\"${opts.h}\"/>`\n + `<hp:cellMargin left=\"141\" right=\"141\" top=\"141\" bottom=\"141\"/>`\n + `</hp:tc>`\n}\n\nfunction table(rows: string[], w: number, h: number, cols: number, tblBf: number = 1, bodyWidth: number = GAEJOSIK_BASE_WIDTH): string {\n // 본문폭급 표(표지·본문 제목박스)는 outMargin 좌우 0 — 실측(t2): 283을 주면\n // treatAsChar 진행폭(w+566)이 컬럼폭을 넘어 좌우 1mm씩 밀려 우측 여백을 침범한다 (GAP-01 잔여).\n // 실물도 48180 표지 표 2개만 0, 좁은 표(배너·목차박스·장헤더)는 283.\n // 판정은 실제 컬럼폭(bodyWidth) 기준 — 절대 임계 48000은 커스텀 여백(예: 좌우 35mm,\n // 본문폭 39685)에서 본문폭급 표에 283이 붙어 우측 침범을 재현시켰다 (v4.0.5 영역6).\n const outLR = w + 566 > bodyWidth ? 0 : 283\n return `<hp:tbl id=\"${++gjTableId}\" zOrder=\"0\" numberingType=\"TABLE\" textWrap=\"TOP_AND_BOTTOM\" textFlow=\"BOTH_SIDES\" lock=\"0\" dropcapstyle=\"None\" pageBreak=\"CELL\" repeatHeader=\"0\" rowCnt=\"${rows.length}\" colCnt=\"${cols}\" cellSpacing=\"0\" borderFillIDRef=\"${tblBf}\" noAdjust=\"1\">`\n + `<hp:sz width=\"${w}\" widthRelTo=\"ABSOLUTE\" height=\"${h}\" heightRelTo=\"ABSOLUTE\" protect=\"0\"/>`\n + `<hp:pos treatAsChar=\"1\" affectLSpacing=\"0\" flowWithText=\"1\" allowOverlap=\"0\" holdAnchorAndSO=\"0\" vertRelTo=\"PARA\" horzRelTo=\"PARA\" vertAlign=\"TOP\" horzAlign=\"LEFT\" vertOffset=\"0\" horzOffset=\"0\"/>`\n + `<hp:outMargin left=\"${outLR}\" right=\"${outLR}\" top=\"283\" bottom=\"283\"/>`\n + `<hp:inMargin left=\"141\" right=\"141\" top=\"141\" bottom=\"141\"/>`\n + rows.map((r) => `<hp:tr>${r}</hp:tr>`).join(\"\")\n + `</hp:tbl>`\n}\n\n// ─── 표지 ───────────────────────────────────────────\n\n/**\n * 표지 페이지 문단들 — 파랑 장식 바(상: 긴 진파랑+짧은 연파랑 / 하: 반전) 사이\n * 제목 30pt, 아래에 날짜·기관명 25pt (실측 양식 구조 재현).\n */\nexport function buildGaejosikCover(title: string, gongmun: ResolvedGongmun, bodyWidth: number = GAEJOSIK_BASE_WIDTH): string[] {\n // 제목칸 높이는 coverTitle 크기에, 폭은 본문폭에 비례 스케일 (A3 기하연동 + margins 대응)\n const g = coverGeom(gongmun.bodyHeight, gongmun.sizes, bodyWidth)\n // 긴 제목 자동 축소 — 30pt로 2줄을 넘으면(꼬리 한두 글자 3줄행 방지) 25pt로.\n // 실측 관행: 원본 양식도 제목 1줄 30pt / 길면 25pt (report-template 역분석과 일치)\n const sz = gaejosikSizes(gongmun.bodyHeight, gongmun.sizes)\n const innerW = g.totalW - 282 // 셀 좌우 마진 제외\n const titleCharPr = simulateWrap(title, innerW, innerW, sz.coverTitle, 100, \"keep\").lines > 2\n ? GJ_CHAR_COVER_SUB\n : GJ_CHAR_COVER_TITLE\n const titlePara = `<hp:p paraPrIDRef=\"${GJ_PARA_COVER}\" styleIDRef=\"0\"><hp:run charPrIDRef=\"${titleCharPr}\"><hp:t>${escapeTextXml(title)}</hp:t></hp:run></hp:p>`\n // 장식 바 셀 빈 문단 — 전용 소형 charPr(6pt)·저줄간격 paraPr. 기본(15pt·160%)이면\n // 줄높이가 바 높이 818을 넘어 한컴이 행을 3배로 확장한다 (실측 원본도 전용 소형 charPr 사용)\n const barEmpty = emptyPara(GJ_PARA_BAR, false, GJ_CHAR_BAR)\n // 실측 양식과 동일한 3열 그리드 + colSpan 배열 — 행별 셀 폭이 달라도 열 정합 유지\n // (열폭: 10466 / 27753 / 9961 → 상단 바 = 열0+1, 하단 연한 바 = 열1+2)\n const topRow = cell({ bf: GJ_BF_BAR_DARK, col: 0, colSpan: 2, row: 0, w: g.topDarkW, h: g.barH, paras: barEmpty })\n + cell({ bf: GJ_BF_BAR_LIGHT, col: 2, row: 0, w: g.topLightW, h: g.barH, paras: barEmpty })\n // 왕복 채널 (P2) — 표지 제목 셀에 h1 마커. 재파싱 시 장식표 대신 h1 헤딩으로 복원\n const titleRow = cell({ bf: 1, col: 0, colSpan: 3, row: 1, w: g.totalW, h: g.titleH, paras: titlePara, name: \"__kordoc_h1\" })\n const botRow = cell({ bf: GJ_BF_BAR_DARK, col: 0, row: 2, w: g.botDarkW, h: g.botBarH, paras: barEmpty })\n + cell({ bf: GJ_BF_BAR_LIGHT, col: 1, colSpan: 2, row: 2, w: g.botLightW, h: g.botBarH, paras: barEmpty })\n const tbl = table([topRow, titleRow, botRow], g.totalW, g.barH + g.titleH + g.botBarH, 3, 1, bodyWidth)\n const host = `<hp:p paraPrIDRef=\"${PARA_NORMAL}\" styleIDRef=\"0\"><hp:run charPrIDRef=\"${CHAR_NORMAL}\">${tbl}</hp:run></hp:p>`\n const date = gongmun.cover?.date ?? formatGaejosikDate(new Date())\n const org = gongmun.cover?.org ?? \"\"\n const sub = (t: string) =>\n `<hp:p paraPrIDRef=\"${GJ_PARA_COVER}\" styleIDRef=\"0\"><hp:run charPrIDRef=\"${GJ_CHAR_COVER_SUB}\"><hp:t>${escapeTextXml(t)}</hp:t></hp:run></hp:p>`\n // 실측 양식 수직 배치: 빈 5 → 제목 표 → 빈 5 → 날짜 → 빈 4(25pt 행) → 기관명\n // (날짜~기관명 사이 빈 문단은 원본이 25pt charPr — 본문 빈 줄보다 간격이 넓다)\n const subEmpty = emptyPara(GJ_PARA_COVER, false, GJ_CHAR_COVER_SUB)\n return [\n ...Array(5).fill(emptyPara()),\n host,\n ...Array(5).fill(emptyPara()),\n sub(date),\n ...(org ? [...Array(4).fill(subEmpty), sub(org)] : []),\n ]\n}\n\n// ─── 목차 ───────────────────────────────────────────\n\n/**\n * \"목 차\" 장식 배너 — 실측(GT3 표②) 1×7 스트라이프 표:\n * 네이비(#193AAA) | 무 | 라벤더(#E0E5FA) | 라벨 | 라벤더 | 무 | 네이비,\n * 열폭 [565,565,1414,13191,1414,565,565] 좌우 대칭, 표 외곽 0.12mm 검정.\n */\nfunction buildTocBanner(gongmun: ResolvedGongmun, bodyWidth: number = GAEJOSIK_BASE_WIDTH): string {\n const g = tocBannerGeom(gongmun.bodyHeight, gongmun.sizes)\n const bfs = [GJ_BF_BAR_DARK, 1, GJ_BF_TOC_STRIPE, 1, GJ_BF_TOC_STRIPE, 1, GJ_BF_BAR_DARK]\n const filler = emptyPara(GJ_PARA_BAR, false, GJ_CHAR_BAR)\n const label = `<hp:p paraPrIDRef=\"${GONGMUN_CENTER}\" styleIDRef=\"0\"><hp:run charPrIDRef=\"${GJ_CHAR_TOC_LABEL}\"><hp:t>목 차</hp:t></hp:run></hp:p>`\n // 왕복 채널 (P2) — 목차는 h2 파생물이므로 non-authoritative: 재파싱 시 통째 스킵(중복 방지)\n const row = g.colWs.map((w, c) =>\n cell({ bf: bfs[c], col: c, w, h: g.h, paras: c === 3 ? label : filler, name: c === 3 ? \"__kordoc_toc\" : undefined }),\n ).join(\"\")\n const banner = table([row], g.colWs.reduce((a, b) => a + b, 0), g.h, 7, 2, bodyWidth)\n // 호스트 저줄간격(GJ_PARA_BAR 70%) — 160% 줄간격이 표 줄높이에 곱해져\n // 배너+박스가 한 페이지를 넘는 문제 방지 (실렌더 확인)\n return `<hp:p paraPrIDRef=\"${GJ_PARA_BAR}\" styleIDRef=\"0\" pageBreak=\"1\"><hp:run charPrIDRef=\"${CHAR_NORMAL}\">${banner}</hp:run></hp:p>`\n}\n\n/** 목차 페이지 문단들 — 스트라이프 배너 라벨 + 보라 테두리 박스 안 Ⅰ Ⅱ Ⅲ… 항목 */\nexport function buildGaejosikToc(chapters: string[], gongmun: ResolvedGongmun, bodyWidth: number = GAEJOSIK_BASE_WIDTH): string[] {\n const boxW = Math.round((TOC_GEOM.boxW * bodyWidth) / GAEJOSIK_BASE_WIDTH)\n const label = buildTocBanner(gongmun, bodyWidth)\n const items = chapters.map((title, i) =>\n `<hp:p paraPrIDRef=\"${GJ_PARA_TOC_ITEM}\" styleIDRef=\"0\">`\n + `<hp:run charPrIDRef=\"${GJ_CHAR_TOC_ROMAN}\"><hp:t>${chapterRoman(i + 1)}</hp:t></hp:run>`\n + `<hp:run charPrIDRef=\"${GJ_CHAR_TOC_ITEM}\"><hp:t>. ${escapeTextXml(title)}</hp:t></hp:run>`\n + `</hp:p>`,\n ).join(\"\")\n // 실측: 박스 셀 수직 CENTER — 항목 블록이 고정 높이 박스 안에서 가운데 배치\n const box = table(\n [cell({ bf: GJ_BF_TOC_BOX, col: 0, w: boxW, h: TOC_GEOM.boxH, paras: items, name: \"__kordoc_toc\" })],\n boxW, TOC_GEOM.boxH, 1, 1, bodyWidth,\n )\n // 박스 호스트·간격 문단도 저줄간격 — 배너와 같은 페이지 유지 (실렌더 확인)\n const host = `<hp:p paraPrIDRef=\"${GJ_PARA_BAR}\" styleIDRef=\"0\"><hp:run charPrIDRef=\"${CHAR_NORMAL}\">${box}</hp:run></hp:p>`\n return [label, emptyPara(GJ_PARA_BAR, false, GJ_CHAR_BAR), host]\n}\n\n// ─── 본문 첫 페이지 제목 박스 (B6) ────────────────────\n\n/**\n * 본문 첫 페이지 제목 반복 박스 — 실측(GT3 표④): 표지 표①의 축소판 3×3\n * (투톤 바 600 + 제목칸 3566 + 투톤 바 600), 제목 HY헤드라인M 22pt.\n * 목차 뒤·첫 장 앞에 배치. 실무(GT12)는 실제 문서 제목을 넣는다.\n */\nexport function buildGaejosikBodyTitle(title: string, gongmun: ResolvedGongmun, bodyWidth: number = GAEJOSIK_BASE_WIDTH): string {\n const g = coverGeom(gongmun.bodyHeight, gongmun.sizes, bodyWidth)\n const bt = bodyTitleGeom(gongmun.bodyHeight, gongmun.sizes)\n const barEmpty = emptyPara(GJ_PARA_BAR, false, GJ_CHAR_BAR)\n const titlePara = `<hp:p paraPrIDRef=\"${GONGMUN_CENTER}\" styleIDRef=\"0\"><hp:run charPrIDRef=\"${GJ_CHAR_BODY_TITLE}\"><hp:t>${escapeTextXml(title)}</hp:t></hp:run></hp:p>`\n const topRow = cell({ bf: GJ_BF_BAR_DARK, col: 0, colSpan: 2, row: 0, w: g.topDarkW, h: bt.barH, paras: barEmpty })\n + cell({ bf: GJ_BF_BAR_LIGHT, col: 2, row: 0, w: g.topLightW, h: bt.barH, paras: barEmpty })\n // 왕복 채널 (P2) — 표지 제목의 반복(파생물): 재파싱 시 스킵해 h1 중복 방지\n const titleRow = cell({ bf: 1, col: 0, colSpan: 3, row: 1, w: g.totalW, h: bt.titleH, paras: titlePara, name: \"__kordoc_skip\" })\n const botRow = cell({ bf: GJ_BF_BAR_DARK, col: 0, row: 2, w: g.botDarkW, h: bt.barH, paras: barEmpty })\n + cell({ bf: GJ_BF_BAR_LIGHT, col: 1, colSpan: 2, row: 2, w: g.botLightW, h: bt.barH, paras: barEmpty })\n const box = table([topRow, titleRow, botRow], g.totalW, bt.barH * 2 + bt.titleH, 3, 1, bodyWidth)\n return `<hp:p paraPrIDRef=\"${PARA_NORMAL}\" styleIDRef=\"0\"><hp:run charPrIDRef=\"${CHAR_NORMAL}\">${box}</hp:run></hp:p>`\n}\n\n// ─── 장 헤더 표 ─────────────────────────────────────\n\n/**\n * 장 헤더 — [Ⅰ(흰 글자·파랑 음영)] [간격(좌선)] [제 목(회색 상하선·연회색 음영)]\n * 1×3 표, 실측 기하. n은 1-based 장 번호.\n */\nexport function buildGaejosikChapter(n: number, title: string, gongmun?: ResolvedGongmun, bodyWidth: number = GAEJOSIK_BASE_WIDTH, srcLevel: number = 2): string {\n // 행높이는 chapter 크기에, 폭은 본문폭에 비례 스케일 (A3 기하연동 + margins 대응)\n const g = gongmun ? chapterGeom(gongmun.bodyHeight, gongmun.sizes, bodyWidth) : chapterGeom(1500, {}, bodyWidth)\n const numPara = `<hp:p paraPrIDRef=\"${GONGMUN_CENTER}\" styleIDRef=\"0\"><hp:run charPrIDRef=\"${GJ_CHAR_CHAPTER_NUM}\"><hp:t>${chapterRoman(n)}</hp:t></hp:run></hp:p>`\n const titlePara = `<hp:p paraPrIDRef=\"${PARA_NORMAL}\" styleIDRef=\"0\"><hp:run charPrIDRef=\"${GJ_CHAR_CHAPTER_TITLE}\"><hp:t> ${escapeTextXml(title)}</hp:t></hp:run></hp:p>`\n // 왕복 채널 (P2) — 제목 셀에 원본 헤딩 레벨 마커. 재파싱 시 장식표 대신 헤딩으로 복원\n const row = cell({ bf: GJ_BF_CHAPTER_NUM, col: 0, w: g.numW, h: g.rowH, paras: numPara })\n + cell({ bf: GJ_BF_CHAPTER_GAP, col: 1, w: g.gapW, h: g.rowH })\n + cell({ bf: GJ_BF_CHAPTER_TITLE, col: 2, w: g.titleW, h: g.rowH, paras: titlePara, name: `__kordoc_h${Math.min(Math.max(srcLevel, 1), 6)}` })\n const tbl = table([row], g.numW + g.gapW + g.titleW, g.rowH, 3, 1, bodyWidth)\n return `<hp:p paraPrIDRef=\"${GJ_PARA_CHAPTER}\" styleIDRef=\"0\"><hp:run charPrIDRef=\"${CHAR_NORMAL}\">${tbl}</hp:run></hp:p>`\n}\n","/** 텍스트 유사도 및 diff 유틸리티 — 외부 의존성 없음 */\n\nexport interface TextChange {\n type: \"equal\" | \"insert\" | \"delete\"\n text: string\n}\n\n/** 두 문자열의 유사도 (0-1). 1 = 동일, 0 = 완전히 다름 */\nexport function similarity(a: string, b: string): number {\n if (a === b) return 1\n if (!a || !b) return 0\n const maxLen = Math.max(a.length, b.length)\n if (maxLen === 0) return 1\n return 1 - levenshtein(a, b) / maxLen\n}\n\n/** 공백 정규화 후 유사도 비교 (HWP/HWPX 포맷 차이 흡수) */\nexport function normalizedSimilarity(a: string, b: string): number {\n return similarity(normalize(a), normalize(b))\n}\n\nfunction normalize(s: string): string {\n return s.replace(/\\s+/g, \" \").trim()\n}\n\n/** 최대 입력 길이 합 — 초과 시 길이 차이 기반 빠른 추정 (O(m*n) CPU 폭발 방지) */\nconst MAX_LEVENSHTEIN_LEN = 10_000\n\n/**\n * 초과 길이 근사 거리 — 문자 bigram(shingle) 다중집합의 Dice 유사도 기반.\n * 위치 정렬 샘플 비교는 접두 삽입/삭제(shift)에 전량 불일치로 폭주하던 것을 교정.\n */\nfunction approxDistance(a: string, b: string): number {\n const bigramCounts = (s: string): Map<string, number> => {\n const m = new Map<string, number>()\n for (let i = 0; i < s.length - 1; i++) {\n const g = s.slice(i, i + 2)\n m.set(g, (m.get(g) ?? 0) + 1)\n }\n return m\n }\n const ca = bigramCounts(a)\n const cb = bigramCounts(b)\n let inter = 0\n for (const [g, n] of ca) inter += Math.min(n, cb.get(g) ?? 0)\n const total = Math.max(a.length - 1, 0) + Math.max(b.length - 1, 0)\n const dice = total > 0 ? (2 * inter) / total : 1\n return Math.round(Math.max(a.length, b.length) * (1 - dice))\n}\n\n/** Levenshtein 편집 거리 — O(min(m,n)) 공간 최적화 */\nfunction levenshtein(a: string, b: string): number {\n if (a.length + b.length > MAX_LEVENSHTEIN_LEN) {\n return approxDistance(a, b)\n }\n if (a.length > b.length) [a, b] = [b, a]\n const m = a.length\n const n = b.length\n let prev = Array.from({ length: m + 1 }, (_, i) => i)\n let curr = new Array(m + 1)\n\n for (let j = 1; j <= n; j++) {\n curr[0] = j\n for (let i = 1; i <= m; i++) {\n if (a[i - 1] === b[j - 1]) {\n curr[i] = prev[i - 1]\n } else {\n curr[i] = 1 + Math.min(prev[i - 1], prev[i], curr[i - 1])\n }\n }\n ;[prev, curr] = [curr, prev]\n }\n return prev[m]\n}\n\n/** 단어 단위 diff — LCS 기반 */\nexport function textDiff(a: string, b: string): TextChange[] {\n const wordsA = a.split(/(\\s+)/)\n const wordsB = b.split(/(\\s+)/)\n const lcs = lcsWords(wordsA, wordsB)\n\n const changes: TextChange[] = []\n let ia = 0, ib = 0, il = 0\n\n while (il < lcs.length) {\n // lcs 원소 이전에 있는 것들\n while (ia < wordsA.length && wordsA[ia] !== lcs[il]) {\n changes.push({ type: \"delete\", text: wordsA[ia++] })\n }\n while (ib < wordsB.length && wordsB[ib] !== lcs[il]) {\n changes.push({ type: \"insert\", text: wordsB[ib++] })\n }\n changes.push({ type: \"equal\", text: lcs[il] })\n ia++; ib++; il++\n }\n // 나머지\n while (ia < wordsA.length) changes.push({ type: \"delete\", text: wordsA[ia++] })\n while (ib < wordsB.length) changes.push({ type: \"insert\", text: wordsB[ib++] })\n\n return mergeChanges(changes)\n}\n\nfunction lcsWords(a: string[], b: string[]): string[] {\n const m = a.length, n = b.length\n // 대형 문서 보호: 5000 단어 초과 시 간이 비교\n if (m * n > 25_000_000) return simpleIntersect(a, b)\n\n const dp: number[][] = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0))\n for (let i = 1; i <= m; i++) {\n for (let j = 1; j <= n; j++) {\n dp[i][j] = a[i - 1] === b[j - 1]\n ? dp[i - 1][j - 1] + 1\n : Math.max(dp[i - 1][j], dp[i][j - 1])\n }\n }\n\n const result: string[] = []\n let i = m, j = n\n while (i > 0 && j > 0) {\n if (a[i - 1] === b[j - 1]) { result.push(a[i - 1]); i--; j-- }\n else if (dp[i - 1][j] >= dp[i][j - 1]) i--\n else j--\n }\n return result.reverse()\n}\n\n/**\n * 대형 입력 LCS 폴백 — 그리디 순서 매칭. 결과가 a·b 양쪽의 부분수열이 되도록\n * b에서 항상 앞으로만 전진한다 (집합 교집합은 b의 순서를 무시해 textDiff 재생 시\n * 가짜 equal을 만들던 계약 위반 교정). O(m+n) 상각.\n */\nfunction simpleIntersect(a: string[], b: string[]): string[] {\n const pos = new Map<string, number[]>()\n for (let i = 0; i < b.length; i++) {\n let list = pos.get(b[i])\n if (!list) pos.set(b[i], (list = []))\n list.push(i)\n }\n const ptr = new Map<string, number>()\n const result: string[] = []\n let j = 0\n for (const w of a) {\n const list = pos.get(w)\n if (!list) continue\n let k = ptr.get(w) ?? 0\n while (k < list.length && list[k] < j) k++\n if (k < list.length) {\n result.push(w)\n j = list[k] + 1\n ptr.set(w, k + 1)\n } else {\n ptr.set(w, k)\n }\n }\n return result\n}\n\nfunction mergeChanges(changes: TextChange[]): TextChange[] {\n if (changes.length === 0) return changes\n const merged: TextChange[] = [changes[0]]\n for (let i = 1; i < changes.length; i++) {\n const last = merged[merged.length - 1]\n if (last.type === changes[i].type) {\n last.text += changes[i].text\n } else {\n merged.push({ ...changes[i] })\n }\n }\n return merged\n}\n","/**\n * 라운드트립 마크다운 유닛 — blocksToMarkdown 출력과 호환되는 블록 단위 분할.\n *\n * 원본 마크다운(=blocksToMarkdown 출력)과 편집된 마크다운을 같은 규칙으로\n * 분할해 유닛 단위 diff를 수행한다. 표는 builder.ts의 GFM/HTML 렌더링을\n * 좌표 추적(provenance) 버전으로 재현해, 편집된 셀 → IRTable 격자 좌표를\n * 역산한다. 재현 결과가 원본 마크다운과 다르면 해당 표는 graceful skip\n * 대상이 된다 (builder와의 드리프트 자기 검증).\n */\n\nimport type { IRTable } from \"../types.js\"\nimport { MAX_COLS, MAX_ROWS, escapeGfm, noteSuffix } from \"../table/builder.js\"\nimport { clampSpan } from \"../hwpx/parser-shared.js\"\nimport { mapPuaText } from \"../shared/pua.js\"\nimport { normalizedSimilarity } from \"../diff/text-diff.js\"\n\n// ─── 유닛 분할 ───────────────────────────────────────\n\nexport type UnitKind = \"text\" | \"gfm-table\" | \"html-table\" | \"separator\" | \"image\"\n\nexport interface MdUnit {\n kind: UnitKind\n /** 원문 그대로 (트림된 라인 조인) */\n raw: string\n /** 라인 배열 */\n lines: string[]\n}\n\n/** blocksToMarkdown 출력 호환 마크다운 블록 분할 */\nexport function splitMarkdownUnits(md: string): MdUnit[] {\n const lines = md.split(\"\\n\")\n const units: MdUnit[] = []\n let i = 0\n\n while (i < lines.length) {\n const line = lines[i]\n if (!line.trim()) { i++; continue }\n\n // HTML 표 — <table> ~ 짝이 맞는 </table>\n if (line.trim().startsWith(\"<table>\")) {\n const collected: string[] = []\n let depth = 0\n while (i < lines.length) {\n const l = lines[i]\n collected.push(l)\n depth += (l.match(/<table>/g) || []).length\n depth -= (l.match(/<\\/table>/g) || []).length\n i++\n if (depth <= 0) break\n }\n units.push({ kind: \"html-table\", raw: collected.join(\"\\n\"), lines: collected })\n continue\n }\n\n // GFM 표 — 연속된 | 시작 라인\n if (line.trimStart().startsWith(\"|\")) {\n const collected: string[] = []\n while (i < lines.length && lines[i].trimStart().startsWith(\"|\")) {\n collected.push(lines[i])\n i++\n }\n units.push({ kind: \"gfm-table\", raw: collected.join(\"\\n\"), lines: collected })\n continue\n }\n\n // 구분선\n if (/^-{3,}\\s*$/.test(line.trim())) {\n units.push({ kind: \"separator\", raw: line.trim(), lines: [line.trim()] })\n i++\n continue\n }\n\n // 이미지 단독 라인\n if (/^!\\[image\\]\\([^)]*\\)\\s*$/.test(line.trim())) {\n units.push({ kind: \"image\", raw: line.trim(), lines: [line.trim()] })\n i++\n continue\n }\n\n // 일반 텍스트 — 연속 비공백 라인 묶음 (1x1/1열 표 청크 포함)\n const collected: string[] = []\n while (i < lines.length && lines[i].trim()\n && !lines[i].trimStart().startsWith(\"|\")\n && !lines[i].trim().startsWith(\"<table>\")) {\n collected.push(lines[i].trim())\n i++\n }\n units.push({ kind: \"text\", raw: collected.join(\"\\n\"), lines: collected })\n }\n\n return units\n}\n\n// ─── 정렬 (정확 일치 LCS + 갭 유사도 페어링) ─────────\n// 유닛(블록)과 표 행 양쪽에서 공용 — patcher.ts에서 이동 (v3.7)\n\nexport type AlignedPair = [number | null, number | null]\n\nexport function alignUnits(a: string[], b: string[]): AlignedPair[] {\n const m = a.length, n = b.length\n if (m * n > 4_000_000) {\n // 대형 문서 보호 — dense LCS 불가. 공통 prefix/suffix만 정확 일치로 페어링하고\n // 가운데 구간은 길이가 같을 때만 인덱스 페어링, 다르면(블록 추가/삭제) 전부\n // 추가/삭제로 보고해 시프트 오적용(전 문단이 한 칸씩 밀려 덮어써짐)을 차단한다.\n const result: AlignedPair[] = []\n let pre = 0\n while (pre < m && pre < n && a[pre] === b[pre]) { result.push([pre, pre]); pre++ }\n let suf = 0\n while (suf < m - pre && suf < n - pre && a[m - 1 - suf] === b[n - 1 - suf]) suf++\n const aMid = m - pre - suf, bMid = n - pre - suf\n if (aMid === bMid) {\n for (let i = 0; i < aMid; i++) result.push([pre + i, pre + i])\n } else {\n for (let i = 0; i < aMid; i++) result.push([pre + i, null])\n for (let j = 0; j < bMid; j++) result.push([null, pre + j])\n }\n for (let s = suf - 1; s >= 0; s--) result.push([m - 1 - s, n - 1 - s])\n return result\n }\n\n // 정확 일치 LCS\n const dp: Int32Array[] = Array.from({ length: m + 1 }, () => new Int32Array(n + 1))\n for (let i = 1; i <= m; i++) {\n for (let j = 1; j <= n; j++) {\n dp[i][j] = a[i - 1] === b[j - 1]\n ? dp[i - 1][j - 1] + 1\n : Math.max(dp[i - 1][j], dp[i][j - 1])\n }\n }\n const matches: [number, number][] = []\n let i = m, j = n\n while (i > 0 && j > 0) {\n if (a[i - 1] === b[j - 1] && dp[i][j] === dp[i - 1][j - 1] + 1) {\n matches.push([i - 1, j - 1]); i--; j--\n } else if (dp[i - 1][j] >= dp[i][j - 1]) i--\n else j--\n }\n matches.reverse()\n\n // 갭 구간 페어링 — 양쪽 갭 크기가 같으면 위치 기반(전면 재작성 인정),\n // 다르면 유사도 기반으로 수정/추가/삭제 구분\n const result: AlignedPair[] = []\n let ai = 0, bi = 0\n const flushGap = (aEnd: number, bEnd: number) => {\n if (aEnd - ai === bEnd - bi) {\n while (ai < aEnd) result.push([ai++, bi++])\n return\n }\n while (ai < aEnd && bi < bEnd) {\n const sim = normalizedSimilarity(a[ai], b[bi])\n if (sim >= 0.4) {\n // 갭이 긴 쪽에 더 나은 후보가 있으면 현재 항목은 삭제/추가로 밀어낸다 —\n // 비슷한 두 문단 중 하나를 지운 편집에서 남은 문단이 덮어써지는 것을 방지\n if (aEnd - ai > bEnd - bi && bestSimInRange(a, ai + 1, ai + (aEnd - ai) - (bEnd - bi), b[bi]) > sim) {\n result.push([ai++, null])\n } else if (bEnd - bi > aEnd - ai && bestSimInRange(b, bi + 1, bi + (bEnd - bi) - (aEnd - ai), a[ai]) > sim) {\n result.push([null, bi++])\n } else {\n result.push([ai++, bi++])\n }\n } else if (aEnd - ai >= bEnd - bi) result.push([ai++, null])\n else result.push([null, bi++])\n }\n while (ai < aEnd) result.push([ai++, null])\n while (bi < bEnd) result.push([null, bi++])\n }\n for (const [pi, pj] of matches) {\n flushGap(pi, pj)\n result.push([ai++, bi++])\n }\n flushGap(m, n)\n return result\n}\n\n/** [from, to] 범위에서 target과의 최고 유사도 */\nfunction bestSimInRange(arr: string[], from: number, to: number, target: string): number {\n let best = 0\n for (let k = from; k <= to && k < arr.length; k++) {\n const s = normalizedSimilarity(arr[k], target)\n if (s > best) best = s\n }\n return best\n}\n\n// ─── builder.ts 텍스트 변환 재현 (드리프트 시 자기 검증으로 skip) ─────\n\n/** GFM 특수문자 이스케이프 — builder.ts escapeGfm 이 SSOT (재현 드리프트 방지, 사본 두지 않음) */\nexport { escapeGfm }\n\n/** builder.ts HWP_SHAPE_ALT_TEXT_RE와 동일 (행 전체 일치 ^…$m — 본문 중간 오삭제 방지) */\nconst HWP_SHAPE_ALT_TEXT_RE = /^(?:모서리가 둥근 |둥근 )?(?:사각형|직사각형|정사각형|원|타원|삼각형|이등변 삼각형|직각 삼각형|선|직선|곡선|화살표|굵은 화살표|이중 화살표|오각형|육각형|팔각형|별|[4-8]점별|십자|십자형|구름|구름형|마름모|도넛|평행사변형|사다리꼴|부채꼴|호|반원|물결|번개|하트|빗금|블록 화살표|수식|표|그림|개체|그리기\\s?개체|묶음\\s?개체|글상자|수식\\s?개체|OLE\\s?개체)\\s?입니다\\.?$/gm\n\n/** builder.ts sanitizeText와 동일 (PUA 매핑 + 대체텍스트 제거 + 균등배분 정리) */\nexport function sanitizeText(text: string): string {\n let result = mapPuaText(text)\n .replace(/[\\u{F0000}-\\u{FFFFD}]/gu, \"\")\n .replace(HWP_SHAPE_ALT_TEXT_RE, \"\")\n .replace(/ +/g, \" \")\n .trim()\n if (result.length <= 30 && result.includes(\" \")) {\n const tokens = result.split(\" \")\n const koreanSingleCharCount = tokens.filter(t => t.length === 1 && /[가-ㄱ-ㆎ]/.test(t)).length\n if (tokens.length >= 3 && koreanSingleCharCount / tokens.length >= 0.7) {\n result = tokens.join(\"\")\n }\n }\n return result\n}\n\n/** 매칭용 정규화 — sanitize + 공백 붕괴. 스캔 텍스트(IR 변환 전)와 IR 텍스트 양쪽에 적용.\n * IR 은 리터럴 $ 를 \\$ 로 담으므로(escapeLiteralDollar) 원문 쪽과 같게 푼다 */\nexport function normForMatch(text: string): string {\n return sanitizeText(text.replace(/\\\\\\$/g, \"$\")).replace(/\\s+/g, \" \").trim()\n}\n\n/** 편집된 마크다운 텍스트 → 평문 (escapeGfm 역변환 — \\| \\# \\< \\$ \\\\ 포함, 없으면 hp:t 에 백슬래시가 샌다) */\nexport function unescapeGfm(text: string): string {\n return text.replace(/\\\\([~*_`|#<$\\\\])/g, \"$1\")\n}\n\n/** 스킵 보고용 내용 요약 (최대 80자) */\nexport function summarize(text: string): string {\n const t = text.replace(/\\s+/g, \" \").trim()\n return t.length > 80 ? t.slice(0, 77) + \"...\" : t\n}\n\n// ─── GFM 표 — 좌표 추적 렌더 재현 + 파서 ────────────\n\nexport interface MappedCell {\n text: string\n gridR: number\n gridC: number\n}\n\n/**\n * builder.ts tableToMarkdown의 GFM 경로 재현 — 출력 셀마다 격자 좌표 기록.\n * (병합/중첩 표는 HTML 경로이므로 여기 오지 않음. 1x1/1열 표는 별도 처리)\n * 반환 null이면 GFM 경로가 아니라는 뜻.\n */\nexport function replicateGfmTable(table: IRTable): MappedCell[][] | null {\n const { cells, rows: numRows, cols: numCols } = table\n if (numRows === 0 || numCols === 0) return null\n if (numRows === 1 && numCols === 1) return null\n if (numCols === 1) return null\n\n const display: MappedCell[][] = Array.from({ length: numRows }, (_, r) =>\n Array.from({ length: numCols }, (_, c) => ({ text: \"\", gridR: r, gridC: c })))\n const skip = new Set<string>()\n\n for (let r = 0; r < numRows; r++) {\n for (let c = 0; c < numCols; c++) {\n if (skip.has(`${r},${c}`)) continue\n const cell = cells[r]?.[c]\n if (!cell) continue\n display[r][c] = {\n text: escapeGfm(sanitizeText(cell.text)).replace(/(?<!\\\\)\\|/g, \"\\\\|\").replace(/\\n/g, \"<br>\"),\n gridR: r,\n gridC: c,\n }\n for (let dr = 0; dr < cell.rowSpan; dr++) {\n for (let dc = 0; dc < cell.colSpan; dc++) {\n if (dr === 0 && dc === 0) continue\n if (r + dr < numRows && c + dc < numCols) skip.add(`${r + dr},${c + dc}`)\n }\n }\n c += cell.colSpan - 1\n }\n }\n\n // builder.ts와 동일한 빈 행 제거/첫 열 전파 (보류 행 소실 방지 포함)\n const uniqueRows: MappedCell[][] = []\n let pendingLabelRow: MappedCell[] | null = null\n for (let r = 0; r < display.length; r++) {\n const row = display[r]\n if (row.every(cell => cell.text === \"\")) continue\n\n const nonEmptyCols = row.filter(cell => cell.text !== \"\")\n const hasSkipInRow = row.some((_, c) => skip.has(`${r},${c}`))\n if (!hasSkipInRow && nonEmptyCols.length === 1 && row[0].text !== \"\" && row.slice(1).every(c => c.text === \"\")) {\n if (pendingLabelRow) uniqueRows.push(pendingLabelRow)\n pendingLabelRow = row\n continue\n }\n if (pendingLabelRow) {\n if (row[0].text === \"\") row[0] = pendingLabelRow[0]\n else uniqueRows.push(pendingLabelRow)\n pendingLabelRow = null\n }\n uniqueRows.push(row)\n }\n if (pendingLabelRow) uniqueRows.push(pendingLabelRow)\n return uniqueRows.length > 0 ? uniqueRows : null\n}\n\n/** GFM 표 유닛 파싱 — 구분 행 제거, 이스케이프된 파이프 보존 분할 */\nexport function parseGfmTable(lines: string[]): string[][] {\n const rows: string[][] = []\n for (const line of lines) {\n const trimmed = line.trim()\n if (!trimmed.startsWith(\"|\")) continue\n // 이스케이프되지 않은 | 로만 분할\n const cells = trimmed.split(/(?<!\\\\)\\|/).slice(1, -1).map(c => c.trim())\n if (cells.length === 0) continue\n // 구분 행 — builder는 셀당 '---'만 방출. '| - | - |' 같은 단일 대시 데이터 행\n // ('해당없음' 표기)을 구분 행으로 오인하지 않도록 셀 패턴으로 판정\n if (cells.every(c => /^:?-{3,}:?$/.test(c))) continue\n rows.push(cells)\n }\n return rows\n}\n\n/** GFM 셀 텍스트 → 평문 */\nexport function unescapeGfmCell(text: string): string {\n return text.replace(/(?<!\\\\)<br\\s*\\/?>/gi, \"\\n\").replace(/\\\\\\|/g, \"|\").replace(/\\\\([~*_`#<$\\\\])/g, \"$1\")\n}\n\n// ─── HTML 표 — 좌표 추적 렌더 재현 + 파서 ───────────\n\nexport interface HtmlCellInfo {\n /** 태그 안 콘텐츠 원문 */\n inner: string\n colSpan: number\n rowSpan: number\n /** 재현 시에만: 격자 좌표 */\n gridR?: number\n gridC?: number\n}\n\n/** 셀 내부 콘텐츠 → HTML — builder.ts cellInnerHtml과 동일 */\nfunction replicateCellInnerHtml(cell: IRTable[\"cells\"][number][number]): string {\n if (cell.blocks?.length) {\n return cell.blocks\n .map(b => {\n if (b.type === \"table\" && b.table) {\n const cap = b.table.caption ? sanitizeText(b.table.caption) : \"\"\n return (cap ? cap + \"<br>\" : \"\") + replicateTableToHtml(b.table)\n }\n if (b.type === \"image\" && b.text) return `<img src=\"${b.text}\" alt=\"image\">`\n const t = sanitizeText(b.text ?? \"\")\n return t ? (t + noteSuffix(b)).replace(/\\n/g, \"<br>\") : \"\"\n })\n .filter(Boolean)\n .join(\"<br>\")\n }\n return sanitizeText(cell.text).replace(/\\n/g, \"<br>\")\n}\n\n/** builder.ts tableToHtml과 동일한 문자열 출력 (자기 검증용) */\nexport function replicateTableToHtml(table: IRTable): string {\n const rows = replicateHtmlTable(table)\n const lines: string[] = [\"<table>\"]\n for (let r = 0; r < rows.length; r++) {\n const tag = rows[r].tag\n const rowHtml = rows[r].cells.map(cell => {\n const attrs: string[] = []\n if (cell.colSpan > 1) attrs.push(`colspan=\"${cell.colSpan}\"`)\n if (cell.rowSpan > 1) attrs.push(`rowspan=\"${cell.rowSpan}\"`)\n const attrStr = attrs.length ? \" \" + attrs.join(\" \") : \"\"\n return `<${tag}${attrStr}>${cell.inner}</${tag}>`\n })\n lines.push(`<tr>${rowHtml.join(\"\")}</tr>`) // 덮인 행도 빈 <tr></tr> (builder tableToHtml 동일)\n }\n lines.push(\"</table>\")\n return lines.join(\"\\n\")\n}\n\nexport interface HtmlRowInfo {\n tag: \"th\" | \"td\"\n cells: HtmlCellInfo[]\n}\n\n/** builder.ts tableToHtml의 셀 방출 순서 재현 — 좌표 포함 */\nexport function replicateHtmlTable(table: IRTable): HtmlRowInfo[] {\n const { cells, rows: numRows, cols: numCols } = table\n const skip = new Set<string>()\n const result: HtmlRowInfo[] = []\n\n for (let r = 0; r < numRows; r++) {\n const tag = r === 0 ? \"th\" : \"td\"\n const rowCells: HtmlCellInfo[] = []\n for (let c = 0; c < numCols; c++) {\n if (skip.has(`${r},${c}`)) continue\n const cell = cells[r]?.[c]\n if (!cell) continue\n for (let dr = 0; dr < cell.rowSpan; dr++) {\n for (let dc = 0; dc < cell.colSpan; dc++) {\n if (dr === 0 && dc === 0) continue\n if (r + dr < numRows && c + dc < numCols) skip.add(`${r + dr},${c + dc}`)\n }\n }\n rowCells.push({\n inner: replicateCellInnerHtml(cell),\n colSpan: cell.colSpan,\n rowSpan: cell.rowSpan,\n gridR: r,\n gridC: c,\n })\n }\n result.push({ tag, cells: rowCells }) // 덮인 행도 빈 행 (builder tableToHtml·parseHtmlTable 과 행 수 정합)\n }\n return result\n}\n\n/**\n * HTML 표 유닛 파싱 — 중첩 <table> 인지 토크나이저.\n * 최상위 표의 <tr>/<td|th>만 행/셀로 취급하고 중첩 표는 셀 inner에 원문 보존.\n */\nexport function parseHtmlTable(raw: string): HtmlRowInfo[] | null {\n const re = /<(\\/?)(table|tr|td|th)((?:\"[^\"]*\"|'[^']*'|[^>\"'])*?)>/gi\n let depth = 0\n let currentRow: HtmlCellInfo[] | null = null\n let cellStart = -1\n let cellInfo: { colSpan: number; rowSpan: number } | null = null\n const rows: HtmlRowInfo[] = []\n let m: RegExpExecArray | null\n\n while ((m = re.exec(raw)) !== null) {\n const isClose = m[1] === \"/\"\n const tag = m[2].toLowerCase()\n const attrs = m[3] || \"\"\n\n if (tag === \"table\") {\n depth += isClose ? -1 : 1\n if (depth < 0) return null\n continue\n }\n if (depth !== 1) continue // 중첩 표 내부는 inner 원문으로 흡수\n\n if (tag === \"tr\") {\n if (!isClose) currentRow = []\n else if (currentRow) {\n rows.push({ tag: rows.length === 0 ? \"th\" : \"td\", cells: currentRow })\n currentRow = null\n }\n } else { // td | th\n if (!isClose) {\n // 속성값은 큰따옴표·작은따옴표·무따옴표 모두 허용, 파서 쪽(clampSpan)과 동일 한도로 클램핑\n const cs = parseInt(attrs.match(/colspan\\s*=\\s*[\"']?(\\d+)/i)?.[1] || \"1\", 10)\n const rs = parseInt(attrs.match(/rowspan\\s*=\\s*[\"']?(\\d+)/i)?.[1] || \"1\", 10)\n cellStart = m.index + m[0].length\n cellInfo = { colSpan: clampSpan(isNaN(cs) ? 1 : cs, MAX_COLS), rowSpan: clampSpan(isNaN(rs) ? 1 : rs, MAX_ROWS) }\n } else if (cellStart >= 0 && cellInfo && currentRow) {\n currentRow.push({ inner: raw.slice(cellStart, m.index), colSpan: cellInfo.colSpan, rowSpan: cellInfo.rowSpan })\n cellStart = -1\n cellInfo = null\n }\n }\n }\n if (depth !== 0) return null\n return rows\n}\n\n/**\n * 자동번호/글머리 접두 형식 — 끝 구두점 필수(\"1.\" \"가)\" \"(2)\") 또는 단일 원문자/로마자.\n * 맨 단어 오인 방지. patcher/hwp5-patch/session이 공유한다 (편집 텍스트에서 접두 제거 판별).\n */\nexport const AUTONUM_PREFIX_RE =\n /^(?:[0-90-9a-zA-Z가-힣]{1,6}[.)\\]:]|[([][0-90-9a-zA-Z가-힣]{1,6}[)\\]][.:]?|[ⅰ-ⅹⅠ-Ⅹ①-⑮][.)\\]:]?)$/u\n\n/** HTML 셀 inner → 평문 라인 — <br> 분리, <img>/중첩표 토큰 제외 */\nexport function htmlCellInnerToLines(inner: string): { lines: string[]; hadNonText: boolean; imgSrcs: string[] } {\n let hadNonText = false\n let work = inner\n const imgSrcs: string[] = []\n if (/<table[\\s>]/i.test(work)) {\n hadNonText = true\n // 중첩 표 통째 제거 (짝 맞는 닫힘까지)\n work = removeNestedTables(work)\n }\n if (/<img\\s/i.test(work)) {\n hadNonText = true\n // src는 걷어 반환 — 생성기가 placeholder <hp:pic>로 이미지 존재를 보존 (v4.0.5).\n // 종전 무흔적 제거는 이미지 열이 빈 열이 되어 재파싱 후행 열 트림을 유발했다\n work = work.replace(/<img\\s(?:\"[^\"]*\"|'[^']*'|[^>\"'])*?>/gi, (tag) => {\n const m = /\\bsrc\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)')/i.exec(tag)\n const src = m?.[1] ?? m?.[2]\n if (src) imgSrcs.push(src)\n return \"\"\n })\n }\n const lines = work.split(/<br\\s*\\/?>/gi).map(s => s.trim()).filter(s => s.length > 0)\n return { lines, hadNonText, imgSrcs }\n}\n\n/**\n * 셀 inner를 최상위 표 경계로 분할 — texts[i]는 i번째 표 앞 텍스트, 마지막은 뒤 텍스트\n * (texts.length === tables.length + 1). 표·텍스트가 번갈아 놓인 셀의 원문 배치 순서를\n * 생성기가 보존할 수 있게 한다 (#49 — 표 뒤 텍스트가 표 앞으로 역전되던 것 수정)\n */\nexport function splitCellByTopLevelTables(html: string): { texts: string[]; tables: string[] } {\n const tables = extractTopLevelTables(html)\n const texts: string[] = []\n let rest = html\n for (const t of tables) {\n const i = rest.indexOf(t)\n texts.push(rest.slice(0, i))\n rest = rest.slice(i + t.length)\n }\n texts.push(rest)\n return { texts, tables }\n}\n\n/** 셀 inner의 최상위 <table>...</table> 부분문자열들 (문서 순서, 짝 맞는 닫힘까지) */\nexport function extractTopLevelTables(html: string): string[] {\n const result: string[] = []\n let depth = 0\n let start = -1\n const re = /<(\\/?)table(?:[\\s>]|>)/gi\n let m: RegExpExecArray | null\n while ((m = re.exec(html)) !== null) {\n if (m[1] !== \"/\") {\n if (depth === 0) start = m.index\n depth++\n } else {\n depth--\n if (depth === 0 && start >= 0) {\n result.push(html.slice(start, m.index + m[0].length))\n start = -1\n }\n if (depth < 0) depth = 0\n }\n }\n return result\n}\n\nfunction removeNestedTables(html: string): string {\n let result = \"\"\n let depth = 0\n const re = /<(\\/?)table(?:[\\s>]|>)/gi\n let last = 0\n let m: RegExpExecArray | null\n while ((m = re.exec(html)) !== null) {\n if (m[1] !== \"/\") {\n if (depth === 0) result += html.slice(last, m.index)\n depth++\n } else {\n depth--\n if (depth === 0) last = m.index + m[0].length\n if (depth < 0) depth = 0\n }\n }\n if (depth === 0) result += html.slice(last)\n return result\n}\n","/**\n * 표 셀 위치별 borderFill 동적 레지스트리 — 정부 실무 표 테두리 위계 재현.\n *\n * 실측 문법 (GT6/7/8/10/11/15 공통, gap_tables.md TBL-01·02):\n * 외곽 0.4mm 굵은선 / 내부 0.12mm 가는선 / 헤더행 하변 DOUBLE_SLIM 0.5mm 이중선.\n * 셀 위치(첫행·끝행·첫열·끝열)와 채움색 조합마다 borderFill이 달라지므로\n * 섹션 생성 중 필요한 조합을 등록하고, header.xml 생성 시 일괄 방출한다.\n * (blocksToSectionXml이 header보다 먼저 실행되는 조립 순서를 이용)\n */\n\nimport { borderFillEntry, type BorderSide } from \"./gen-ids.js\"\n\nconst THIN: BorderSide = [\"0.12 mm\", \"#000000\"]\nconst THICK: BorderSide = [\"0.4 mm\", \"#000000\"]\nconst DOUBLE: BorderSide = [\"0.5 mm\", \"#000000\", \"DOUBLE_SLIM\"]\n/** 0.15mm 중간선 — 서울 보고서 제목표 제목/담당자 행 경계 실측 */\nconst MID: BorderSide = [\"0.15 mm\", \"#000000\"]\n\n/** 셀 한 변의 선 종류 — 이름 있는 위계 또는 직접 지정([굵기, 색, 선종류], 색 띠 표용) */\nexport type EdgeKind = \"thin\" | \"thick\" | \"double\" | \"mid\" | \"none\" | BorderSide\n\n/** 셀 테두리+채움 스펙 — 위치별 조합 키로 dedupe */\nexport interface CellBfSpec {\n t: EdgeKind\n b: EdgeKind\n l: EdgeKind\n r: EdgeKind\n /** 단색 채움(#RRGGBB) 또는 gradient(기본 RADIAL 2색 — LINEAR·다색은 type/angle 지정) */\n fill?: string | GradientFill\n}\n\nexport type GradientFill = { gradient: string[]; type?: \"LINEAR\" | \"RADIAL\"; angle?: number }\n\nconst EDGE: Record<Exclude<EdgeKind, \"none\" | BorderSide>, BorderSide> = { thin: THIN, thick: THICK, double: DOUBLE, mid: MID }\n\nfunction sideOf(kind: EdgeKind): BorderSide | undefined {\n if (Array.isArray(kind)) return kind\n return kind === \"none\" ? undefined : EDGE[kind]\n}\n\nfunction edgeKey(kind: EdgeKind): string {\n return Array.isArray(kind) ? kind.join(\"/\") : kind\n}\n\n/**\n * borderFill 동적 레지스트리. startId부터 발급, 동일 스펙은 같은 id 재사용.\n * emit()은 header.xml refList의 borderFills 블록에 이어붙일 XML 목록을 반환.\n */\nexport class TableBfRegistry {\n private map = new Map<string, number>()\n private xmls: string[] = []\n constructor(private nextId: number) {}\n\n get(spec: CellBfSpec): number {\n const fillKey = typeof spec.fill === \"string\" ? spec.fill : spec.fill ? `${spec.fill.type ?? \"RADIAL\"}@${spec.fill.angle ?? 0}:${spec.fill.gradient.join(\"-\")}` : \"\"\n const key = `${edgeKey(spec.t)}|${edgeKey(spec.b)}|${edgeKey(spec.l)}|${edgeKey(spec.r)}|${fillKey}`\n const hit = this.map.get(key)\n if (hit !== undefined) return hit\n const id = this.nextId++\n this.map.set(key, id)\n this.xmls.push(\n borderFillEntry(id, { t: sideOf(spec.t), b: sideOf(spec.b), l: sideOf(spec.l), r: sideOf(spec.r) }, spec.fill),\n )\n return id\n }\n\n /** 등록된 borderFill XML 목록 (등록 순서 = id 순서) */\n emit(): string[] {\n return this.xmls\n }\n\n get count(): number {\n return this.xmls.length\n }\n}\n\n/**\n * 데이터 표 셀의 위치별 테두리 스펙 — 실측 위계.\n * - 표 최상단 변 thick(0.4), 최하단 변 thick, 좌우 끝열 바깥 변 thick\n * - 헤더행 하변 double(0.5 이중선) — 헤더가 있을 때만\n * - 그 외 내부 변 thin(0.12)\n */\nexport function dataCellSpec(opts: {\n row: number\n rowEnd: number // row + rowSpan - 1\n col: number\n colEnd: number // col + colSpan - 1\n rowCnt: number\n colCnt: number\n headerRows: number // 헤더 행 수 (0이면 이중선 없음)\n fill?: string\n}): CellBfSpec {\n const { row, rowEnd, col, colEnd, rowCnt, colCnt, headerRows, fill } = opts\n const isTop = row === 0\n const isBottom = rowEnd === rowCnt - 1\n const isHeaderBottom = headerRows > 0 && rowEnd === headerRows - 1\n const isBelowHeader = headerRows > 0 && row === headerRows\n return {\n t: isTop ? \"thick\" : isBelowHeader ? \"double\" : \"thin\",\n b: isBottom ? \"thick\" : isHeaderBottom ? \"double\" : \"thin\",\n l: col === 0 ? \"thick\" : \"thin\",\n r: colEnd === colCnt - 1 ? \"thick\" : \"thin\",\n fill,\n }\n}\n","/**\n * 서식 프로필(Format Profile) — generate 시각 서식 재현 (이슈 #41 / PR #42).\n *\n * markdownToHwpx가 표의 위상(병합 구조)뿐 아니라 음영·괘선·열 너비·셀 글꼴까지\n * 재현할 수 있도록, 원본 문서 없이 서식만 실어 나르는 프로필의 타입·리맵·XML 빌더.\n *\n * 파서 IR(IRCell/IRTable)에는 서식 필드가 없으므로 프로필은 IR과 독립된 통로다.\n * 프로필의 borderFill/charPr id는 표별 로컬 네임스페이스라, 여기서 문서 전역 id로\n * 재할당(remap)한 뒤 header에 정의를 등록하고 셀에 연결한다.\n */\n\nimport { CHAR_VARIANT_BASE, escapeXml } from \"./gen-ids.js\"\n\n// ─── 스키마 타입 (PR #42 예시 확정본) ────────────────\n\n/** 한 변의 괘선 정의 */\nexport interface BorderDef {\n /** SOLID | NONE | DASH | DOT ... (HWPX border type) */\n type: string\n /** \"0.12 mm\" 등 HWPX width 문자열 */\n width: string\n /** \"#RRGGBB\" */\n color: string\n}\n\n/** 셀 테두리+음영 정의 (표별 로컬 id로 참조됨) */\nexport interface BorderFillDef {\n leftBorder?: BorderDef\n rightBorder?: BorderDef\n topBorder?: BorderDef\n bottomBorder?: BorderDef\n /** 셀 음영 — winBrush faceColor. 채움 없으면 생략 */\n fill?: { faceColor: string }\n}\n\n/** 셀 글꼴 정의 (표별 로컬 id로 참조됨) */\nexport interface CharPrDef {\n /** \"1100\" (= 11pt × 100) */\n height_hwpunit?: string\n textColor?: string\n bold?: boolean\n italic?: boolean\n underline?: boolean\n /** fontfaces HANGUL 순번. render는 이름표로 손실하므로 원본 순번 보존용 */\n fontRef_hangul?: string\n /**\n * HANGUL 글꼴 이름 (스키마 0.3.0) — 순번(fontRef_hangul)은 원본 fontfaces에서만\n * 유효하므로, 이름을 실어 생성 문서 header에 fontface를 append + 리맵해 재현한다.\n * 없으면(구버전 프로필) 생성 header 범위 내 순번만 존중, 밖이면 기본(0) 폴딩.\n */\n fontName_hangul?: string\n}\n\n/** 셀 하나의 서식 참조 (좌표 = 병합 셀 좌상단 앵커) */\nexport interface CellProfile {\n row: number\n col: number\n rowSpan?: number\n colSpan?: number\n width_hwpunit?: string\n height_hwpunit?: string\n /** used_border_fills 키 */\n borderFillIDRef?: string\n /** used_char_prs 키 */\n charPrIDRef?: string\n}\n\n/** 표 하나의 서식 프로필 */\nexport interface TableProfile {\n /** 문서 내 표 등장 순서 (0-기준) */\n table_index: number\n rows: number\n cols: number\n /**\n * 첫 셀(0,0) 텍스트의 정규화 앵커(normalizeAnchor) — 소비 시 표 대응의 보조 키.\n * parse 가 마크다운으로 방출하지 않는 표(1×1 제목박스·머리말 표 등) 때문에 순번이\n * 어긋나도, 앵커+치수가 맞는 프로필만 골라 적용해 남의 서식 오적용을 막는다(v3.18.1).\n */\n anchor_text?: string\n /**\n * 첫 행 전체 텍스트의 정규화 지문(normalizeRowAnchor) — 다중 지문 2순위 키 (0.3.0).\n * (0,0)이 빈 셀인 크로스탭은 anchor_text가 비어 순번 폴백뿐이었는데, 첫 행 전체를\n * 이어붙인 지문으로 동형 쌍둥이 표를 가른다.\n */\n anchor_row?: string\n width_hwpunit?: string\n col_widths_hwpunit?: string[]\n cells: CellProfile[]\n /** 로컬 id → 정의. 표별 독립 네임스페이스 */\n used_border_fills: Record<string, BorderFillDef>\n used_char_prs?: Record<string, CharPrDef>\n}\n\n/** 문서 전체 서식 프로필 */\nexport interface FormatProfile {\n schema_version?: string\n tables: TableProfile[]\n}\n\n// ─── 리맵 자료구조 ──────────────────────────────────\n\n/** 표별 셀 서식 조회 테이블 (전역 id로 해석됨) */\nexport interface TableRemap {\n /** 프로필 table_index — 앵커 없는(손편집·구버전) 프로필의 순번 매칭 키 */\n index: number\n rows: number\n cols: number\n /** 프로필 anchor_text (정규화됨) — takeProfile 매칭 1순위 키 */\n anchor?: string\n /** 프로필 anchor_row (정규화됨) — 첫 행 전체 지문, 매칭 2순위 키 (0.3.0) */\n anchorRow?: string\n /** takeProfile 이 소비했는지 — 한 프로필이 여러 표에 재적용되는 것 방지 */\n used?: boolean\n width?: number\n colWidths?: number[]\n /** \"r,c\" → 전역 borderFill id */\n cellBf: Map<string, number>\n /** \"r,c\" → 전역 charPr id */\n cellChar: Map<string, number>\n /** \"r,c\" → 셀 높이 (HWPUNIT) */\n cellH: Map<string, number>\n}\n\n/** 프로필 → 문서 전역 리맵 결과 */\nexport interface ProfileRemap {\n /** header borderFills에 추가할 XML (인덱스 i → 전역 id borderFillBase+i) */\n borderFillXmls: string[]\n /** header charProperties에 추가할 XML (인덱스 i → 전역 id charPrBase+i) */\n charPrXmls: string[]\n /**\n * header fontfaces에 append할 글꼴 이름 (인덱스 i → 폰트 id fontBase+i) —\n * 프로필 fontName_hangul 채널 (스키마 0.3.0). 이름 dedupe 완료 상태.\n */\n fontFaces: string[]\n /** 프로필 표 목록 — 원본 등장 순서. 매칭은 takeProfile(순번 아님)로 한다 */\n tables: TableRemap[]\n}\n\n// ─── 표 대응 매칭 ────────────────────────────────────\n\n/**\n * 앵커 정규화 — 문자·숫자만 남기고 소문자화, 24자 절단.\n * 추출(원본 XML 첫 셀 텍스트)과 소비(마크다운/HTML 첫 셀) 양쪽이 같은 규칙을 써서\n * 굵게(**)·공백·구두점 차이에 흔들리지 않는 비교 키를 만든다.\n */\nexport function normalizeAnchor(s: string): string {\n return s.toLowerCase().replace(/[^\\p{L}\\p{N}]/gu, \"\").slice(0, 24)\n}\n\n/**\n * 첫 행 전체 지문 정규화 — 셀별 normalizeAnchor(24자 캡, 추출·소비 동일 키 공간)를\n * '|'로 이어붙인다 (0.3.0). 셀 경계를 보존해 \"a|bc\"와 \"ab|c\"를 가르고 64자 절단.\n */\nexport function normalizeRowAnchor(cells: string[]): string {\n const j = cells.map(normalizeAnchor).join(\"|\")\n return /[\\p{L}\\p{N}]/u.test(j) ? j.slice(0, 64) : \"\" // 전부 빈 셀이면 지문 없음\n}\n\n/**\n * 방출되는 표 하나에 적용할 프로필 선택.\n *\n * parse 는 원본의 모든 top-level 표를 마크다운 표로 방출하지 않는다(1×1 제목박스는\n * 문단으로, 머리말/꼬리말 표는 본문 제외 등). 순번(tableSeq) 단독 매칭은 이때 어긋나\n * **다른 표의 서식이 무경고로 적용**됐다(v3.18.0). 규칙:\n *\n * 1. 행·열 일치는 언제나 필수 (cellBf 가 \"r,c\" 좌표 키라 치수가 다르면 무의미)\n * 2. 앵커가 양쪽 다 있으면 앵커 일치가 유일한 근거 — 미사용 첫 일치 항목 소비.\n * 앵커 불일치 항목에는 순번 매칭도 허용하지 않는다(동형 쌍둥이 표 오적용 방지).\n * 3. 앵커가 없으면 첫 행 전체 지문(anchor_row, 0.3.0)이 양쪽 다 있을 때 같은 규칙 —\n * (0,0) 빈 셀 크로스탭의 동형 쌍둥이를 가른다.\n * 4. 둘 다 한쪽이라도 없으면 table_index === 방출 순번(시도 기준)일 때만 소비 —\n * 손편집 sparse 프로필(\"두 번째 표만\")과 구버전(0.1.0) 프로필의 의미 보존.\n *\n * 매칭 실패는 null — 서식 없음이 잘못된 서식보다 안전하다.\n */\nexport function takeProfile(\n remap: ProfileRemap | null | undefined,\n rows: number,\n cols: number,\n anchor: string,\n seq: number,\n rowAnchor = \"\",\n): TableRemap | null {\n if (!remap) return null\n for (const t of remap.tables) {\n if (t.used) continue\n if (t.rows !== rows || t.cols !== cols) continue\n if (t.anchor && anchor) {\n if (t.anchor !== anchor) continue\n } else if (t.anchorRow && rowAnchor) {\n if (t.anchorRow !== rowAnchor) continue\n } else if (t.index !== seq) {\n continue\n }\n t.used = true\n return t\n }\n return null\n}\n\n// ─── 파싱 유틸 ──────────────────────────────────────\n\n/** \"12750\" / \"1500 hwpunit\" → 12750. 그 이상 단위변환은 하지 않음(스키마가 hwpunit 확정본). */\nexport function parseHu(s?: string): number | undefined {\n if (s == null) return undefined\n const n = parseInt(String(s).trim(), 10)\n return Number.isFinite(n) ? n : undefined\n}\n\n// ─── XML 빌더 ──────────────────────────────────────\n\n/** 한 변 괘선 → XML. 정의 없으면 NONE (기본 borderFill id=1과 동일 형식). */\nfunction edgeXml(tag: string, d?: BorderDef): string {\n return d\n ? `<hh:${tag} type=\"${escapeXml(d.type)}\" width=\"${escapeXml(d.width)}\" color=\"${escapeXml(d.color)}\"/>`\n : `<hh:${tag} type=\"NONE\" width=\"0.1 mm\" color=\"#000000\"/>`\n}\n\n/**\n * BorderFillDef → `<hh:borderFill>` XML. gen-header.ts:198-213 형식 미러.\n * fill(음영)이 있으면 border들 뒤에 fillBrush>winBrush를 붙인다(HWPX 자식 순서).\n */\nexport function borderFillDefToXml(id: number, def: BorderFillDef): string {\n const fill = def.fill?.faceColor\n ? `<hh:fillBrush><hh:winBrush faceColor=\"${escapeXml(def.fill.faceColor)}\" hatchColor=\"#000000\" alpha=\"0\"/></hh:fillBrush>`\n : \"\"\n return ` <hh:borderFill id=\"${id}\" threeD=\"0\" shadow=\"0\" centerLine=\"NONE\" breakCellSeparateLine=\"0\">\n <hh:slash type=\"NONE\" Crooked=\"0\" isCounter=\"0\"/>\n <hh:backSlash type=\"NONE\" Crooked=\"0\" isCounter=\"0\"/>\n ${edgeXml(\"leftBorder\", def.leftBorder)}\n ${edgeXml(\"rightBorder\", def.rightBorder)}\n ${edgeXml(\"topBorder\", def.topBorder)}\n ${edgeXml(\"bottomBorder\", def.bottomBorder)}${fill ? `\\n ${fill}` : \"\"}\n </hh:borderFill>`\n}\n\n/**\n * CharPrDef → `<hh:charPr>` XML. gen-ids.ts:123-129 형식 미러.\n * charPr() 헬퍼와 달리 볼드라도 fontRef를 강제 치환하지 않고(프로필 순번 존중),\n * underline을 지원한다.\n *\n * 글꼴 해석 (0.3.0): fontName_hangul이 있으면 리맵된 append 글꼴 id(namedFontId)를\n * 쓴다 — 전 언어 목록이 동일하므로(gen-header) 나머지 슬롯도 같은 id. 이름이 없는\n * 구버전 프로필은 fontRef_hangul 순번이 생성 header 범위(0~2) 안일 때만 존중,\n * 밖이면 dangling IDREF 방지를 위해 기본 글꼴(0)로 접는다.\n */\nconst LEGACY_PROFILE_FONT_MAX = 2\n\nexport function profileCharPrXml(id: number, def: CharPrDef, namedFontId?: number): string {\n const height = Math.max(parseHu(def.height_hwpunit) ?? 1000, 100)\n const color = escapeXml(def.textColor ?? \"#000000\")\n let font = 0\n let restFont = 0 // hanja/japanese/other/symbol/user — 7슬롯 동일해야 한컴 툴바가 글꼴명을 보여준다\n if (namedFontId != null) {\n font = namedFontId\n restFont = font\n } else {\n const rawFont = def.fontRef_hangul != null ? parseInt(def.fontRef_hangul, 10) || 0 : 0\n font = rawFont >= 0 && rawFont <= LEGACY_PROFILE_FONT_MAX ? rawFont : 0\n restFont = font\n }\n const boldAttr = def.bold ? ` bold=\"1\"` : \"\"\n const italicAttr = def.italic ? ` italic=\"1\"` : \"\"\n const underline = def.underline\n ? `\\n <hh:underline type=\"BOTTOM\" shape=\"SOLID\" color=\"${color}\"/>`\n : \"\"\n return ` <hh:charPr id=\"${id}\" height=\"${height}\" textColor=\"${color}\" shadeColor=\"none\" useFontSpace=\"0\" useKerning=\"0\" symMark=\"NONE\" borderFillIDRef=\"1\"${boldAttr}${italicAttr}>\n <hh:fontRef hangul=\"${font}\" latin=\"${font}\" hanja=\"${restFont}\" japanese=\"${restFont}\" other=\"${restFont}\" symbol=\"${restFont}\" user=\"${restFont}\"/>\n <hh:ratio hangul=\"100\" latin=\"100\" hanja=\"100\" japanese=\"100\" other=\"100\" symbol=\"100\" user=\"100\"/>\n <hh:spacing hangul=\"0\" latin=\"0\" hanja=\"0\" japanese=\"0\" other=\"0\" symbol=\"0\" user=\"0\"/>\n <hh:relSz hangul=\"100\" latin=\"100\" hanja=\"100\" japanese=\"100\" other=\"100\" symbol=\"100\" user=\"100\"/>\n <hh:offset hangul=\"0\" latin=\"0\" hanja=\"0\" japanese=\"0\" other=\"0\" symbol=\"0\" user=\"0\"/>${underline}\n </hh:charPr>`\n}\n\n// ─── 리맵 빌더 ──────────────────────────────────────\n\n/**\n * 프로필의 표별 로컬 borderFill/charPr을 문서 전역 id로 재할당한다.\n * 표별 독립 네임스페이스이므로 표마다 새 전역 id를 뽑는다(크로스-테이블 dedup 안 함 — 단순성).\n *\n * @param charPrBase 프로필 charPr 시작 전역 id (기본 charPr 0~10 + gongmun variant 다음)\n * @param borderFillBase 프로필 borderFill 시작 전역 id (기본 1=NONE,2=SOLID 다음)\n * @param fontBase 프로필 append 글꼴 시작 id (생성 header 정적 fontface 개수 —\n * gen-header.staticFontNext). fontName_hangul(0.3.0) 글꼴이 여기서부터 발급된다.\n */\nexport function buildProfileRemap(\n profile: FormatProfile,\n charPrBase: number,\n borderFillBase = 3,\n fontBase = 3,\n): ProfileRemap {\n const remap: ProfileRemap = { borderFillXmls: [], charPrXmls: [], fontFaces: [], tables: [] }\n let bfNext = borderFillBase\n let charNext = charPrBase\n // 글꼴 이름 → append 글꼴 id — 표·charPr 넘어 문서 전역 dedupe\n const fontIds = new Map<string, number>()\n const fontIdOf = (name: string): number => {\n let id = fontIds.get(name)\n if (id == null) {\n id = fontBase + remap.fontFaces.length\n remap.fontFaces.push(name)\n fontIds.set(name, id)\n }\n return id\n }\n\n for (const t of profile.tables) {\n // 표별 로컬 키 → 전역 id\n const localBf: Record<string, number> = {}\n for (const [key, def] of Object.entries(t.used_border_fills ?? {})) {\n const gid = bfNext++\n remap.borderFillXmls.push(borderFillDefToXml(gid, def))\n localBf[key] = gid\n }\n const localChar: Record<string, number> = {}\n for (const [key, def] of Object.entries(t.used_char_prs ?? {})) {\n const gid = charNext++\n remap.charPrXmls.push(profileCharPrXml(gid, def, def.fontName_hangul ? fontIdOf(def.fontName_hangul) : undefined))\n localChar[key] = gid\n }\n\n // col_widths — 전부 유효 숫자이고 길이가 cols와 맞을 때만 채택(부분 데이터 오배치 방지)\n let colWidths: number[] | undefined\n if (t.col_widths_hwpunit && t.col_widths_hwpunit.length === t.cols) {\n const parsed = t.col_widths_hwpunit.map(parseHu)\n if (parsed.every(n => n != null)) colWidths = parsed as number[]\n }\n const tr: TableRemap = {\n index: t.table_index,\n rows: t.rows,\n cols: t.cols,\n // 재정규화 — 추출기는 정규화해 담지만 손편집된 프로필 JSON도 같은 키 공간으로\n anchor: t.anchor_text ? normalizeAnchor(t.anchor_text) : undefined,\n anchorRow: t.anchor_row ? normalizeRowAnchor(t.anchor_row.split(\"|\")) || undefined : undefined,\n width: parseHu(t.width_hwpunit),\n colWidths,\n cellBf: new Map(),\n cellChar: new Map(),\n cellH: new Map(),\n }\n\n for (const cell of t.cells) {\n const k = `${cell.row},${cell.col}`\n if (cell.borderFillIDRef != null && cell.borderFillIDRef in localBf) {\n tr.cellBf.set(k, localBf[cell.borderFillIDRef])\n }\n if (cell.charPrIDRef != null && cell.charPrIDRef in localChar) {\n tr.cellChar.set(k, localChar[cell.charPrIDRef])\n }\n const h = parseHu(cell.height_hwpunit)\n if (h != null) tr.cellH.set(k, h)\n }\n remap.tables.push(tr)\n }\n return remap\n}\n\n/**\n * markdownToHwpx가 넘겨줄 charPr 시작 id 계산.\n * 기본 charPr 0~10(11종) + 공문서 자동장평 variant(변형당 4종) 다음.\n */\nexport function profileCharPrBase(ratioVariantCount: number): number {\n return CHAR_VARIANT_BASE + ratioVariantCount * 4\n}\n","/**\n * 이미지 placeholder 방출 (v4.0.5) — 마크다운 ``·HTML `<img>` 참조를\n * 텍스트로 뭉개지 않고 1×1 placeholder 바이너리 + <hp:pic>로 방출한다.\n *\n * 배경: 종전에는 이미지 참조가 alt 텍스트(\"image\")로 각인돼 (1) 재파싱 시 이미지\n * 존재 자체가 소실되고 (2) 이미지 열이 빈 열이 되어 후행 열 트림으로 표 구조가\n * 붕괴했다(라운드트립 tableExact 최대 결손). 바이너리 원본이 없어도 참조와 위치를\n * 보존하는 것이 목적 — 실제 픽셀은 1×1 placeholder다.\n *\n * <hp:pic> 형상은 실측 한컴 저장본(corpus 10772982)을 미러 — 필수 자식 전부 포함.\n */\n\nimport { PIC_ID_BASE } from \"./geometry.js\"\n\n/** 1×1 24bit 흰색 BMP (58바이트) — .bmp 참조용 */\nconst PLACEHOLDER_BMP = Uint8Array.from([\n 0x42, 0x4d, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,\n 0x28, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,\n 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00,\n 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n 0xff, 0xff, 0xff, 0x00,\n])\n\n/** 1×1 투명 PNG (68바이트) — bmp 외 확장자 참조용 */\nconst PLACEHOLDER_PNG = Uint8Array.from([\n 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48,\n 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x06, 0x00, 0x00,\n 0x00, 0x1f, 0x15, 0xc4, 0x89, 0x00, 0x00, 0x00, 0x0b, 0x49, 0x44, 0x41, 0x54, 0x78,\n 0x9c, 0x63, 0x00, 0x01, 0x00, 0x00, 0x05, 0x00, 0x01, 0x0d, 0x0a, 0x2d, 0xb4, 0x00,\n 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,\n])\n\nconst IMAGE_EXT_MIME: Record<string, string> = {\n png: \"image/png\", jpg: \"image/jpeg\", jpeg: \"image/jpeg\", gif: \"image/gif\",\n bmp: \"image/bmp\", tif: \"image/tiff\", tiff: \"image/tiff\",\n}\n\n/** 등록된 이미지 파트 — ZIP·manifest 등재용 */\nexport interface ImagePart {\n /** ZIP 경로 (BinData/xxx.ext) */\n name: string\n /** manifest item id == binaryItemIDRef (확장자 없는 basename) */\n itemId: string\n mime: string\n data: Uint8Array\n /** 실데이터 표기 크기 (HWPUNIT) — 없으면 placeholder 크기(1130) */\n wHU?: number\n hHU?: number\n}\n\n/** 매직바이트 → mime/확장자 (HWPX가 소화하는 래스터 포맷만 — webp 등은 미지원 폴백) */\nfunction sniffImage(b: Uint8Array): { mime: string; ext: string } | null {\n if (b.length >= 8 && b[0] === 0x89 && b[1] === 0x50 && b[2] === 0x4e && b[3] === 0x47) return { mime: \"image/png\", ext: \"png\" }\n if (b.length >= 3 && b[0] === 0xff && b[1] === 0xd8 && b[2] === 0xff) return { mime: \"image/jpeg\", ext: \"jpg\" }\n if (b.length >= 6 && b[0] === 0x47 && b[1] === 0x49 && b[2] === 0x46) return { mime: \"image/gif\", ext: \"gif\" }\n if (b.length >= 2 && b[0] === 0x42 && b[1] === 0x4d) return { mime: \"image/bmp\", ext: \"bmp\" }\n return null\n}\n\n/** 픽셀 치수 프로브 (PNG/JPEG/GIF/BMP) — 실패 시 null (placeholder 크기 폴백) */\nexport function probeImageSize(b: Uint8Array): { w: number; h: number } | null {\n const dv = new DataView(b.buffer, b.byteOffset, b.byteLength)\n try {\n if (b[0] === 0x89 && b[1] === 0x50) {\n // PNG — IHDR은 시그니처(8)+길이(4)+\"IHDR\"(4) 뒤 고정 오프셋\n return { w: dv.getUint32(16), h: dv.getUint32(20) }\n }\n if (b[0] === 0xff && b[1] === 0xd8) {\n // JPEG — SOF0~SOF15(0xC0~0xCF, C4/C8/CC 제외) 마커의 height/width\n let i = 2\n while (i + 9 < b.length) {\n if (b[i] !== 0xff) { i++; continue }\n const marker = b[i + 1]\n if (marker >= 0xc0 && marker <= 0xcf && marker !== 0xc4 && marker !== 0xc8 && marker !== 0xcc) {\n return { w: dv.getUint16(i + 7), h: dv.getUint16(i + 5) }\n }\n i += 2 + dv.getUint16(i + 2)\n }\n return null\n }\n if (b[0] === 0x47 && b[1] === 0x49) {\n // GIF — logical screen descriptor (LE)\n return { w: dv.getUint16(6, true), h: dv.getUint16(8, true) }\n }\n if (b[0] === 0x42 && b[1] === 0x4d) {\n // BMP — BITMAPINFOHEADER (LE, height는 절대값)\n return { w: dv.getUint32(18, true), h: Math.abs(dv.getInt32(22, true)) }\n }\n } catch { /* 손상 헤더 — 크기 미상 */ }\n return null\n}\n\n/** px → HWPUNIT (96dpi 기준: 1px = 75HU), 본문폭(170mm) 초과 시 비례 축소 */\nconst PX_TO_HU = 75\nconst MAX_IMG_W_HU = 48189 // 170mm — 공문서 본문폭과 동일한 보수적 상한\n\n/**\n * 문서 단위 이미지 레지스트리 — url 기준 dedupe, 안전한 상대 파일명만 수용.\n * 수용 불가 url(스킴·경로 구분자·미지의 확장자)은 null — 호출부가 종전 alt 텍스트 폴백.\n */\nexport class ImageRegistry {\n private byUrl = new Map<string, ImagePart | null>()\n private ids = new Set<string>()\n readonly parts: ImagePart[] = []\n private picSeq = 0\n private binSeq = 0\n\n /** @param supplied url → 실데이터 바이트 (markdownToHwpx images 옵션) */\n constructor(private readonly supplied?: Map<string, Uint8Array>) {}\n\n /** url 등록(중복 시 기존 파트) — 수용 불가면 null */\n take(url: string): ImagePart | null {\n const cached = this.byUrl.get(url)\n if (cached !== undefined) return cached\n // 실데이터 경로 (v4.5.0) — images 옵션 바이트 또는 data: URI를 실제로 임베드\n const real = this.takeReal(url)\n if (real) {\n this.byUrl.set(url, real)\n return real\n }\n let part: ImagePart | null = null\n // 파일명만 허용 — 경로 구분자·스킴 배제 (ZIP 경로 주입 방지)\n const m = /^([A-Za-z0-9._-]+)\\.([A-Za-z0-9]+)$/.exec(url)\n const mime = m ? IMAGE_EXT_MIME[m[2].toLowerCase()] : undefined\n if (m && mime && !url.includes(\"..\")) {\n let itemId = m[1].replace(/[^A-Za-z0-9_]/g, \"_\")\n // itemId 충돌(a.png vs a.bmp) 시 접미 부여\n let n = 1\n while (this.ids.has(itemId)) itemId = `${m[1].replace(/[^A-Za-z0-9_]/g, \"_\")}_${n++}`\n this.ids.add(itemId)\n part = {\n name: `BinData/${url}`,\n itemId,\n mime,\n data: m[2].toLowerCase() === \"bmp\" ? PLACEHOLDER_BMP : PLACEHOLDER_PNG,\n }\n this.parts.push(part)\n }\n this.byUrl.set(url, part)\n return part\n }\n\n /** 실데이터 등록 — images 맵 바이트·data: URI. 포맷 미상(webp 등)은 null → placeholder 폴백 */\n private takeReal(url: string): ImagePart | null {\n let bytes = this.supplied?.get(url)\n if (!bytes && url.startsWith(\"data:\")) {\n const m = /^data:image\\/[a-z+]+;base64,([A-Za-z0-9+/=\\s]+)$/i.exec(url)\n if (m) {\n try { bytes = new Uint8Array(Buffer.from(m[1].replace(/\\s+/g, \"\"), \"base64\")) } catch { /* 손상 base64 */ }\n }\n }\n if (!bytes || bytes.length === 0) return null\n const sniffed = sniffImage(bytes)\n if (!sniffed) return null\n // ZIP 파트명 — 안전한 원본 파일명이면 유지, 아니면(경로·data URI) 순번 파일명\n const safe = /^([A-Za-z0-9._-]+)\\.([A-Za-z0-9]+)$/.exec(url)\n const base = safe && !url.includes(\"..\") ? safe[1] : `image${++this.binSeq}`\n let itemId = base.replace(/[^A-Za-z0-9_]/g, \"_\")\n let n = 1\n while (this.ids.has(itemId)) itemId = `${base.replace(/[^A-Za-z0-9_]/g, \"_\")}_${n++}`\n this.ids.add(itemId)\n const dim = probeImageSize(bytes)\n let wHU: number | undefined, hHU: number | undefined\n if (dim && dim.w > 0 && dim.h > 0) {\n wHU = dim.w * PX_TO_HU\n hHU = dim.h * PX_TO_HU\n if (wHU > MAX_IMG_W_HU) {\n hHU = Math.round(hHU * (MAX_IMG_W_HU / wHU))\n wHU = MAX_IMG_W_HU\n }\n }\n const part: ImagePart = { name: `BinData/${itemId}.${sniffed.ext}`, itemId, mime: sniffed.mime, data: bytes, wHU, hHU }\n this.parts.push(part)\n return part\n }\n\n /** manifest <opf:item> 조각들 (실측: isEmbeded=\"1\") */\n manifestItems(): string[] {\n return this.parts.map((p) => `<opf:item id=\"${p.itemId}\" href=\"${p.name}\" media-type=\"${p.mime}\" isEmbeded=\"1\"/>`)\n }\n\n /** 인라인 <hp:pic> XML — 실측 저장본 미러, treatAsChar=1 (셀·문단 안 배치) */\n inlinePicXml(part: ImagePart): string {\n const id = PIC_ID_BASE + ++this.picSeq\n // placeholder는 ≈4mm 정사각, 실데이터는 실치수(96dpi 환산·본문폭 캡)\n const w = part.wHU ?? 1130\n const h = part.hHU ?? 1130\n // xmlns:hc는 pic 요소에 인라인 선언 — 섹션 루트는 hs/hp만 선언하므로(기존 산출물\n // 바이트 보존) hc: 자식(transMatrix·img 등)이 여기서 네임스페이스를 얻는다\n return `<hp:pic id=\"${id}\" zOrder=\"0\" numberingType=\"PICTURE\" textWrap=\"TOP_AND_BOTTOM\" textFlow=\"BOTH_SIDES\" lock=\"0\" dropcapstyle=\"None\" href=\"\" groupLevel=\"0\" instid=\"${id}\" reverse=\"0\" xmlns:hc=\"http://www.hancom.co.kr/hwpml/2011/core\">`\n + `<hp:offset x=\"0\" y=\"0\"/><hp:orgSz width=\"${w}\" height=\"${h}\"/><hp:curSz width=\"${w}\" height=\"${h}\"/>`\n + `<hp:flip horizontal=\"0\" vertical=\"0\"/><hp:rotationInfo angle=\"0\" centerX=\"${Math.floor(w / 2)}\" centerY=\"${Math.floor(h / 2)}\" rotateimage=\"1\"/>`\n + `<hp:renderingInfo><hc:transMatrix e1=\"1\" e2=\"0\" e3=\"0\" e4=\"0\" e5=\"1\" e6=\"0\"/><hc:scaMatrix e1=\"1\" e2=\"0\" e3=\"0\" e4=\"0\" e5=\"1\" e6=\"0\"/><hc:rotMatrix e1=\"1\" e2=\"0\" e3=\"0\" e4=\"0\" e5=\"1\" e6=\"0\"/></hp:renderingInfo>`\n + `<hp:imgRect><hc:pt0 x=\"0\" y=\"0\"/><hc:pt1 x=\"${w}\" y=\"0\"/><hc:pt2 x=\"${w}\" y=\"${h}\"/><hc:pt3 x=\"0\" y=\"${h}\"/></hp:imgRect>`\n + `<hp:imgClip left=\"0\" right=\"${w}\" top=\"0\" bottom=\"${h}\"/><hp:inMargin left=\"0\" right=\"0\" top=\"0\" bottom=\"0\"/>`\n + `<hp:imgDim dimwidth=\"${w}\" dimheight=\"${h}\"/>`\n + `<hc:img binaryItemIDRef=\"${part.itemId}\" bright=\"0\" contrast=\"0\" effect=\"REAL_PIC\" alpha=\"0\"/><hp:effects/>`\n + `<hp:sz width=\"${w}\" widthRelTo=\"ABSOLUTE\" height=\"${h}\" heightRelTo=\"ABSOLUTE\" protect=\"0\"/>`\n + `<hp:pos treatAsChar=\"1\" affectLSpacing=\"0\" flowWithText=\"1\" allowOverlap=\"0\" holdAnchorAndSO=\"0\" vertRelTo=\"PARA\" horzRelTo=\"PARA\" vertAlign=\"TOP\" horzAlign=\"LEFT\" vertOffset=\"0\" horzOffset=\"0\"/>`\n + `<hp:outMargin left=\"0\" right=\"0\" top=\"0\" bottom=\"0\"/>`\n + `</hp:pic>`\n }\n}\n\n/** 마크다운 이미지 참조 정규식 — `` */\nexport const MD_IMAGE_RE = /!\\[[^\\]]*\\]\\(([^)\\s]+)\\)/g\n\n/**\n * 텍스트에서 이미지 참조를 걷어내고 url 목록 반환 — 셀·문단 공용.\n * (레지스트리 수용 여부와 무관하게 걷는다 — 수용 실패 url은 호출부가 alt로 폴백)\n */\nexport function splitImageRefs(text: string): { text: string; urls: string[] } {\n const urls: string[] = []\n const out = text.replace(MD_IMAGE_RE, (_, url: string) => { urls.push(url); return \"\" })\n return { text: out, urls }\n}\n","/**\n * HWPX 표 XML 생성 (generator.ts에서 분리) — GFM 그리드 표와\n * 병합(colspan/rowspan) HTML 표 경로.\n *\n * 열폭은 내용 실폭(text-metrics) 비례 배분 — 균등 1/n 분할 아님.\n * 공문서 모드는 실측 정부 양식 표 문법(헤더 음영·bold·하변 이중선, 외곽 0.4mm\n * 위계, 라벨열, 셀 CENTER 130%/LEFT, 축폭+우측 배치)을 적용한다 (style 인자).\n * 서식 프로필(#41, remap)이 표에 매칭되면 셀 좌표별 실측 서식(bf·charPr·행높이·열폭)이\n * 최우선 — 프로필 미매칭 셀만 기본/공문서 문법으로 채운다.\n */\n\nimport { parseHtmlTable, htmlCellInnerToLines, splitCellByTopLevelTables, type HtmlRowInfo } from \"../roundtrip/markdown-units.js\"\nimport { MAX_COLS, MAX_ROWS } from \"../table/builder.js\"\nimport { clampSpan } from \"./parser-shared.js\"\nimport { CHAR_NORMAL, CHAR_BOLD, CHAR_TABLE_HEADER, PARA_NORMAL, escapeXml, escapeTextXml, type ResolvedTheme } from \"./gen-ids.js\"\nimport { generateRuns } from \"./md-runs.js\"\nimport { measureTextWidth } from \"./text-metrics.js\"\nimport { TableBfRegistry, dataCellSpec } from \"./gen-table-bf.js\"\nimport { takeProfile, normalizeAnchor, normalizeRowAnchor, type ProfileRemap, type TableRemap } from \"./gen-profile.js\"\nimport { DATA_TABLE_ID_BASE } from \"./geometry.js\"\nimport { ImageRegistry, splitImageRefs } from \"./gen-image.js\"\n\n// 표 id 네임스페이스는 geometry.ts SSOT (v4.0.5 P0-3)\nconst TABLE_ID_BASE = DATA_TABLE_ID_BASE\nlet tableIdCounter = TABLE_ID_BASE\nfunction nextTableId(): number { return ++tableIdCounter }\n/** 문서 생성마다 표 id 카운터 리셋 — 같은 프로세스 연속 호출에도 결정적 출력 유지 */\nexport function resetTableIds(): void { tableIdCounter = TABLE_ID_BASE }\n\n/** 공문서 표 스타일 — gen-section이 ResolvedGongmun에서 해석해 전달 */\nexport interface GongmunTableStyle {\n /** 표 전체 폭(HWPUNIT) — 본문 폭 맞춤 */\n totalWidth: number\n /** 셀 본문 charPr (개조식: 맑은 고딕 12pt) */\n charPr: number\n /** 셀 안 강조 charPr */\n boldCharPr: number\n /** 폭·행높이 측정용 글자 높이(charPr height) */\n charHeight: number\n /** 헤더행 음영 borderFill (#E6E6E6) — bfRegistry 부재 시 폴백 */\n headerBf: number\n /** 가운데정렬 paraPr */\n centerParaPr: number\n /** 표 셀 전용 paraPr — CENTER 130% (실측 GT1 표⑪). 미지정 시 centerParaPr */\n tblCenterParaPr?: number\n /** 표 셀 장문 열 paraPr — LEFT 130%. 미지정 시 PARA_NORMAL */\n tblLeftParaPr?: number\n /**\n * 표 테두리 위계 레지스트리 — 지정 시 실측 문법 적용:\n * 외곽 0.4mm / 내부 0.12mm / 헤더행 하변 DOUBLE_SLIM 0.5mm / 헤더 bold /\n * 라벨열 음영 / 축폭(본문폭 −1800) + 호스트 우측정렬 (gap_tables TBL-01~11)\n */\n bfRegistry?: TableBfRegistry\n /** 데이터 표 호스트 문단 paraPr(RIGHT) — bfRegistry와 함께 지정 */\n rightParaPr?: number\n /** 헤더행 음영색 (기본 #E6E6E6 — 실측 GT1·샘플양식1) */\n headerFill?: string\n /** 라벨열 음영색 (기본 #E7E7E7 — 실측 GT6/GT7 표3) */\n labelFill?: string\n /** 셀 글꼴 폭 클래스(v5) — 열폭·행높이 측정에 사용. 미지정 hcr */\n faceClass?: import(\"./text-metrics.js\").FaceClass\n}\n\n/** 현재 표의 폭 측정 클래스 — generateTable/generateHtmlTableXml 진입 시 style에서 설정 */\nlet curFace: import(\"./text-metrics.js\").FaceClass = \"hcr\"\n\n/** 실측 데이터 표 폭 여유 — GT6 46194·GT7 46372·GT11 46544 ≈ 본문폭 −1800 */\nexport const DATA_TABLE_INSET = 1800\n\n/**\n * 표 `<hp:pos>` — 2행 이상 최상위 표는 부유(treatAsChar=0, 자리차지)로 앵커한다.\n *\n * 한글은 글자처럼 취급(treatAsChar=1) 표를 한 줄의 글자로 보아 `pageBreak=\"CELL\"`이어도\n * 쪽 경계에서 나누지 않는다 — 표 전체가 다음 쪽으로 넘어가 앞 쪽이 비고, 한 쪽을 넘는\n * 표는 하단이 잘린다 (한글 2024 COM 실렌더: 한컴 저장본 표를 부풀려도 동일, treatAsChar=0\n * 으로만 셀 단위 분할·헤더 반복이 동작). 1행 표(밴드 박스 등)와 중첩표는 나눌 일이 없어\n * 글자처럼 취급을 유지한다. 부유 표의 좌우 정렬은 호스트 문단 정렬 대신 horzAlign이 맡는다.\n */\nfunction tablePosXml(float: boolean, right: boolean): string {\n return float\n ? `<hp:pos treatAsChar=\"0\" affectLSpacing=\"0\" flowWithText=\"1\" allowOverlap=\"0\" holdAnchorAndSO=\"0\" vertRelTo=\"PARA\" horzRelTo=\"COLUMN\" vertAlign=\"TOP\" horzAlign=\"${right ? \"RIGHT\" : \"LEFT\"}\" vertOffset=\"0\" horzOffset=\"0\"/>`\n : `<hp:pos treatAsChar=\"1\" affectLSpacing=\"0\" flowWithText=\"0\" allowOverlap=\"0\" holdAnchorAndSO=\"0\" vertRelTo=\"PARA\" horzRelTo=\"PARA\" vertAlign=\"TOP\" horzAlign=\"LEFT\" vertOffset=\"0\" horzOffset=\"0\"/>`\n}\n\n/**\n * 표 `<hp:outMargin>` — 부유 표는 아래 여백을 한 줄 피치(글자높이×1.6)로 둔다.\n * 글자처럼 취급일 때는 호스트 문단의 줄 leading이 표 아래 간격이 됐지만, 부유 표는 본문이\n * 표 바닥에 바로 붙고 다음 문단의 '문단 위' 간격도 호스트 문단 기준이라 흡수된다\n * (한글 2024 실렌더: 띠 제목·ㅇ 항목이 표 괘선에 밀착). 실측 2000HU(7mm) 전후가 자연스러움.\n */\nfunction tableOutMarginXml(float: boolean, charHeight: number): string {\n const bottom = float ? Math.round(charHeight * 1.6) : 0\n return `<hp:outMargin left=\"0\" right=\"0\" top=\"0\" bottom=\"${bottom}\"/>`\n}\n\n/** 부유 표의 `<hp:tbl>` 배치 속성 — 자리차지(TOP_AND_BOTTOM)라 본문이 표 옆으로 흐르지 않는다 */\nconst FLOAT_TBL_ATTRS = ` textWrap=\"TOP_AND_BOTTOM\" textFlow=\"BOTH_SIDES\" lock=\"0\" dropcapstyle=\"None\"`\n\n// ─── 서식 프로필 매칭 헬퍼 (#41) ─────────────────────\n\n/** 마크다운 셀 → 매칭 앵커. 이미지 참조는 원본 XML 텍스트에 없으므로 제거 후 정규화. */\nfunction anchorOfMarkdownCell(cell: string): string {\n return normalizeAnchor(cell.replace(/!\\[[^\\]]*\\]\\([^)]*\\)/g, \"\"))\n}\n\n/** HTML 셀 inner → 매칭 앵커. 중첩표 내용은 추출기 직속 텍스트 규칙에 맞춰 제외. */\nfunction anchorOfHtmlCell(inner: string): string {\n const noNested = inner.replace(/<table[\\s\\S]*?<\\/table>/gi, \"\")\n const { lines } = htmlCellInnerToLines(noNested)\n return normalizeAnchor(lines.join(\"\"))\n}\n\n/** 프로필 열폭 — col_widths > width/cols. 없으면 null(호출부가 내용 비례 계산) */\nfunction profileColWidths(tp: TableRemap | null, colCnt: number): number[] | null {\n if (!tp) return null\n if (tp.colWidths && tp.colWidths.length === colCnt) return tp.colWidths\n if (tp.width) return Array(colCnt).fill(Math.floor(tp.width / colCnt))\n return null\n}\n\n// ─── 열폭 계산 (내용 비례) ───────────────────────────\n\n/** 셀 좌우 마진(141×2) + 조판 여유 */\n// 셀 좌우 실패딩 = tbl inMargin 510×2(hasMargin=0이라 cellMargin 아닌 inMargin 적용)\n// + 여유 180. 종전 582는 실패딩(1020)보다 작아 짧은 열(\"구분\"·\"단기\")이 필요폭보다\n// 좁게 배분돼 한 글자씩 세로로 갈라졌다 (v4.0.2 실렌더 QA 확인)\nconst CELL_PAD = 1200\n\n/** 셀 텍스트 실폭 — 인라인 마크다운 부호·이미지 참조 제거, <br> 분리 후 최장 줄 기준 */\nfunction cellContentWidth(text: string, charHeight: number): number {\n let max = 0\n for (const seg of text.replace(/!\\[[^\\]]*\\]\\([^)\\s]+\\)/g, \"\").replace(/\\*\\*|__|`/g, \"\").split(/<br\\s*\\/?>/i)) {\n const w = measureTextWidth(seg.trim(), charHeight, 100, { faceClass: curFace })\n if (w > max) max = w\n }\n return max\n}\n\n/** 셀 최장 '어절' 폭 — 열 하한의 기준. 이보다 좁으면 어절이 글자 단위로 세로 분해된다 */\nfunction cellMinWordWidth(text: string, charHeight: number): number {\n let max = 0\n for (const seg of text.replace(/!\\[[^\\]]*\\]\\([^)\\s]+\\)/g, \"\").replace(/\\*\\*|__|`/g, \"\").split(/<br\\s*\\/?>/i)) {\n // 일반 공백에서만 끊는다 — 묶음 빈칸(U+00A0, 날짜·금액)은 JS \\s 에 걸리지만 한 어절이다\n for (const word of seg.trim().split(/[ \\t]+/)) {\n const w = measureTextWidth(word, charHeight, 100, { faceClass: curFace })\n if (w > max) max = w\n }\n }\n return max\n}\n\n/** 열 역할 — 헤더 텍스트로 판정. content(주요 내용 열)는 넓게, remark(비고·근거·마지막 보조 열)는 좁게 */\nexport type ColRole = \"content\" | \"remark\" | null\n\n// 실측(서울 실결재 데이터표 462개, 3열+): 내용·사항류 열 폭 중앙값 51%(p75 63%), 비고 열 21%(p75 26%),\n// 마지막 열 26%. 최협 헤더는 구분·연번·비고·시간. 비고를 먼저 보고(참고사항·비고사항) 내용류를 본다.\nconst REMARK_HEAD = /^(비고|비고란|비고사항|참고|참고사항|출처|(관련|법적|추진)?근거|근거법령|담당(자|부서)?|연락처)$/u\nconst CONTENT_HEAD = /(내용|사항|실적|계획|방안|사유|개요|설명|임무|역할|현황|성과)$/u\n/** 비고류 열 폭 상한(전체 대비) — 실측 p75 26% */\nconst REMARK_SHARE = 0.25\n/** 내용류 열 비례 배분 가중 — 3열 all-short 표에서 25/50/25(실측 중앙값 51%) */\nconst CONTENT_WEIGHT = 2\n\nexport function colRoles(headers: string[]): ColRole[] {\n const clean = headers.map((h) => (h ?? \"\").replace(/!\\[[^\\]]*\\]\\([^)\\s]+\\)/g, \"\").replace(/\\*\\*|__|`|\\s+/g, \"\"))\n const roles: ColRole[] = clean.map((h) => (REMARK_HEAD.test(h) ? \"remark\" : h.length <= 12 && CONTENT_HEAD.test(h) ? \"content\" : null))\n // 내용 열이 있는 3열+ 표의 마지막 열(근거·일정 등)은 비고처럼 좁게 — 실측 마지막 열 중앙값 26%\n const last = roles.length - 1\n if (roles.length >= 3 && roles.includes(\"content\") && roles[last] === null) roles[last] = \"remark\"\n return roles\n}\n\n/**\n * 열폭 배분 — 짧은 열은 실폭 고정, 긴 열이 잔여를 내용폭 비례로 가져간다\n * (실제 공문서 표 관행: 라벨·수치 열은 한 줄에 딱 맞고 서술 열이 넓다).\n *\n * 1) 실폭(내용+패딩)이 균등분할분 이하인 열은 실폭으로 확정 — 수치 열이\n * 긴 서술 열에 밀려 \"4,673\"이 두 줄로 꺾이는 협착 방지 (실렌더 확인)\n * 2) 나머지 열은 잔여 폭을 내용폭 비례 배분. 최소폭(전체 6%) 보장·80% 캡.\n * 확정 열이 각자 균등분할분 이하만 가져가므로 잔여 ≥ 남은 열 수 × 균등분할분\n * ≥ 남은 열 수 × minW — 음수 폭 불가 불변식 유지.\n */\n/** 짧은 열 실폭 여유 — 근사 폭 클래스는 12%(실제 셀 글꼴이 더 넓을 수 있음), 실측 폭표 글꼴은 반올림 여유 3% */\nexport function colSlack(faceClass: import(\"./text-metrics.js\").FaceClass): number {\n return faceClass.startsWith(\"font:\") ? 1.03 : 1.12\n}\n\nexport function computeColWidths(colMax: number[], totalWidth: number, colMinWord: number[] = [], roles: ColRole[] = [], slack = 1.12): number[] {\n const colCnt = colMax.length\n const minW = Math.min(Math.max(2000, Math.round(totalWidth * 0.06)), Math.floor(totalWidth / colCnt))\n const cap = Math.round(totalWidth * 0.8)\n // 열별 상한 — remark 열은 25%(최장 어절보다는 좁아지지 않게), 나머지 80%. 역할 미지정이면 종전과 동일\n const capOf = colMax.map((_, i) => (roles[i] === \"remark\" ? Math.min(cap, Math.max(Math.round(totalWidth * REMARK_SHARE), (colMinWord[i] ?? 0) + CELL_PAD)) : cap))\n const raw = colMax.map((w, i) => Math.min(Math.max(w + CELL_PAD, minW), capOf[i]))\n // 비례 배분 가중 — content 열은 같은 내용폭이라도 2배 몫\n const wgt = raw.map((r, i) => (roles[i] === \"content\" ? r * CONTENT_WEIGHT : r))\n // 열 하한 = 최장 어절 폭 + 실패딩 — 이보다 좁으면 어절이 글자 단위로 세로 분해\n // (\"구/분\", \"소요예/산\" — v4.0.2 실렌더 QA). 어절 경계 줄바꿈은 허용.\n const floor = raw.map((r, i) => Math.min(Math.max(minW, (colMinWord[i] ?? 0) + CELL_PAD), r, capOf[i]))\n const widths = Array<number>(colCnt).fill(0)\n const free = new Set(raw.map((_, i) => i))\n let budget = totalWidth\n let sumFloorFree = floor.reduce((a, b) => a + b, 0)\n // 1) 짧은 열부터 실폭(×slack 여유 — 근사 폭 클래스는 실제 셀 폰트가 더 넓을 수\n // 있음) 확정하고 최장 열(서술 열)만 유연하게 남긴다 — 실측 관행: 라벨·수치·날짜\n // 열은 한 줄에 딱 맞고 서술 열이 잔여를 흡수하며 줄바꿈. 종전 \"균등분할분 이하만\n // 확정\"은 \"소요예산(백만원)\"류 중간 폭 헤더가 비례 배분에 밀려 세로로 갈라지는\n // 결함. 남은 열들이 각자 하한을 못 받게 되면 확정 중단.\n for (const i of [...raw.keys()].sort((a, b) => raw[a] - raw[b])) {\n if (free.size <= 1) break\n // remark 열은 여유를 줘도 상한을 넘지 않는다\n const fixed = roles[i] === \"remark\" ? Math.min(Math.round(raw[i] * slack), capOf[i]) : Math.round(raw[i] * slack)\n if (budget - fixed < sumFloorFree - floor[i]) break\n widths[i] = fixed; free.delete(i); budget -= fixed; sumFloorFree -= floor[i]\n }\n const sumFreeRaw = [...free].reduce((a, i) => a + raw[i], 0)\n if (budget > sumFreeRaw * 1.6) {\n // 전 열이 짧은 표(잔여 과잉) — 확정을 버리고 내용폭 비례로 전폭 배분\n // (마지막 한 열만 비대해지는 것 방지, 표 폭은 totalWidth 유지)\n const sumRaw = raw.reduce((a, b) => a + b, 0)\n const sumWgt = wgt.reduce((a, b) => a + b, 0)\n // raw[i]는 measureTextWidth의 float — 다른 분기(round/floor)와 달리 정수화가 빠져\n // 소수 폭이 XML로 새면 HWPUNIT 정수 규약 위반·합 불변식 붕괴. round + 열별 캡 재적용.\n // 잔여는 가중(content ×2) 비례 — 비고 열이 캡을 넘긴 몫은 아래 잔여 정산이 내용폭 큰 열로 돌린다.\n for (let i = 0; i < colCnt; i++) widths[i] = Math.min(capOf[i], Math.round(raw[i]) + Math.floor((wgt[i] / sumWgt) * (totalWidth - sumRaw)))\n free.clear()\n } else {\n // 2) 긴 열 비례 배분 — 하한(최장 어절) 미달 열은 하한 확정 후 재배분.\n // 잔여가 하한 합보다 작으면 하한 비례 축소(표 폭 불변식 유지)\n for (;;) {\n const sum = [...free].reduce((a, i) => a + wgt[i], 0)\n const short = [...free].filter((i) => (wgt[i] / sum) * budget < floor[i])\n if (short.length === 0) break\n const shortSum = short.reduce((a, i) => a + floor[i], 0)\n const scale = Math.min(1, (budget - (free.size - short.length) * minW) / shortSum)\n for (const i of short) { widths[i] = Math.max(minW, Math.floor(floor[i] * scale)); free.delete(i); budget -= widths[i] }\n if (free.size === 0) break\n }\n const sum = [...free].reduce((a, i) => a + wgt[i], 0)\n for (const i of free) widths[i] = Math.min(capOf[i], Math.floor((wgt[i] / sum) * budget))\n }\n // 잔여 정산 — sum == totalWidth 불변식 (v4.0.5 P1-3: 음수 잔여도 정산).\n // 양수 잔여(내림 손실·remark 캡 회수분)는 가중 내용폭 큰 열부터 1씩 — 단 열별 캡 초과 열은 건너뛴다\n // (전 열 캡 도달 시엔 합 불변식이 캡보다 우선). all-short 분기의 round 상향으로\n // sum > totalWidth가 되던 케이스는 음수 잔여 루프가 최광열부터 1씩 회수한다.\n let rem = totalWidth - widths.reduce((a, b) => a + b, 0)\n const order = [...raw.keys()].sort((a, b) => wgt[b] - wgt[a])\n for (let k = 0, skipped = 0; rem > 0; k = (k + 1) % colCnt, rem--) {\n // 캡 존중: colCnt회 연속 스킵이면 전 열 캡 — 그때만 캡 초과 허용\n while (widths[order[k]] >= capOf[order[k]] && skipped < colCnt) { skipped++; k = (k + 1) % colCnt }\n skipped = 0\n widths[order[k]]++\n }\n for (let k = 0, spins = 0; rem < 0; k = (k + 1) % colCnt, rem++) {\n while (widths[order[k]] <= 1 && spins < colCnt) { spins++; k = (k + 1) % colCnt }\n if (widths[order[k]] <= 1) break // 전 열 1 이하(degenerate) — 더 회수 불가\n spins = 0\n widths[order[k]]--\n }\n return widths\n}\n\n/** 행 높이 추정 — 각 셀의 줄바꿈 수 시뮬레이션(최다 줄 기준) */\nfunction estimateRowHeight(cells: string[], widths: number[], charHeight: number): number {\n let maxLines = 1\n cells.forEach((cell, c) => {\n const usable = Math.max((widths[c] ?? widths[widths.length - 1]) - CELL_PAD, 1000)\n let lines = 0\n for (const seg of cell.replace(/\\*\\*|__|`/g, \"\").split(/<br\\s*\\/?>/i)) {\n lines += Math.max(1, Math.ceil(measureTextWidth(seg.trim(), charHeight, 100, { faceClass: curFace }) / usable))\n }\n if (lines > maxLines) maxLines = lines\n })\n return maxLines * Math.round(charHeight * 1.6) + 282\n}\n\n// ─── GFM 그리드 표 ──────────────────────────────────\n\n/**\n * 표가 한 줄 셀로 다 들어가기 위한 자연 폭(HWPUNIT) — 열별 최장 내용 + 패딩(×colSlack 여유) 합.\n * v5 엔진이 셀 글자 크기 자동 축소(12→11→10pt, 실측 셀 pt 분포) 판단에 쓴다.\n */\nexport function requiredTableWidth(rows: string[][], charHeight: number, faceClass: import(\"./text-metrics.js\").FaceClass = \"hcr\"): number {\n const prev = curFace\n curFace = faceClass\n const colCnt = Math.max(...rows.map((r) => r.length), 1)\n const colMax = Array<number>(colCnt).fill(0)\n for (const row of rows) row.forEach((cell, c) => { const w = cellContentWidth(cell, charHeight); if (w > colMax[c]) colMax[c] = w })\n curFace = prev\n return colMax.reduce((a, w) => a + Math.round((w + CELL_PAD) * colSlack(faceClass)), 0)\n}\n\nexport function generateTable(rows: string[][], theme: ResolvedTheme, style: GongmunTableStyle | null = null, remap: ProfileRemap | null = null, seq = 0, images: ImageRegistry | null = null): string {\n curFace = style?.faceClass ?? \"hcr\"\n const rowCnt = rows.length\n const colCnt = Math.max(...rows.map(r => r.length), 1)\n const reg = style?.bfRegistry ?? null\n // 실측 모드: 데이터 표는 본문폭보다 좁게 + 호스트 우측정렬 (TBL-09)\n const totalW = style ? (reg ? style.totalWidth - DATA_TABLE_INSET : style.totalWidth) : 44000\n const measureH = style?.charHeight ?? 1000\n\n // 서식 프로필 매칭 (#41) — 매칭되면 셀 좌표별 실측 서식 최우선.\n // 첫 행 전체 지문(0.3.0)은 (0,0) 빈 셀일 때의 2순위 키 (이미지 참조는 앵커와 동일 규칙 제거)\n const rowAnchor = normalizeRowAnchor((rows[0] ?? []).map(c => c.replace(/!\\[[^\\]]*\\]\\([^)]*\\)/g, \"\")))\n const prof = takeProfile(remap, rowCnt, colCnt, anchorOfMarkdownCell(rows[0]?.[0] ?? \"\"), seq, rowAnchor)\n\n // 열별 최대 내용폭 (헤더 포함 / 본문만) → 비례 열폭 + 짧은 열 가운데 정렬 판단\n const colMax = Array(colCnt).fill(0)\n const colMaxBody = Array(colCnt).fill(0)\n const colMinWord = Array(colCnt).fill(0)\n rows.forEach((row, r) => row.forEach((cell, c) => {\n const w = cellContentWidth(cell, measureH)\n if (w > colMax[c]) colMax[c] = w\n if (r > 0 && w > colMaxBody[c]) colMaxBody[c] = w\n const mw = cellMinWordWidth(cell, measureH)\n if (mw > colMinWord[c]) colMinWord[c] = mw\n }))\n // 열 역할(내용 넓게·비고 좁게)은 공문서 모드만 — 범용 경로 산출물 바이트 불변\n const roles = style ? colRoles(rows[0] ?? []) : []\n const colWidths = profileColWidths(prof, colCnt) ?? computeColWidths(colMax, totalW, colMinWord, roles, colSlack(curFace))\n // 본문 셀이 전부 한 줄에 들어가는 열은 가운데 정렬 (숫자·라벨 열 관행) — 내용(서술) 열은 넓혀서 한 줄에\n // 들어가도 LEFT (실측 TBL-11 장문 열 LEFT, 2026-09-06 실렌더: 가운데 정렬된 서술 셀이 떠 보임)\n const colCentered = colWidths.map((w, c) => roles[c] !== \"content\" && colMaxBody[c] + CELL_PAD <= w)\n // 라벨열 감지 — 2열 표에서 1열이 짧은 라벨이면 음영+bold (실측: GT6/GT7 표3 라벨|값 패턴)\n const labelCol0 = !!reg && colCnt === 2 && colCentered[0] && rows.every((r) => (r[0] ?? \"\").replace(/\\*\\*|__|`/g, \"\").length <= 12)\n\n const tblId = nextTableId()\n\n // theme.tableHeaderColor 또는 tableHeaderBold가 설정되면 첫 행 셀에 별도 charPr 사용\n // (공문서 style이 있으면 style이 우선 — charPr 9는 표 전용 폰트·크기와 어긋난다)\n const useHeaderStyle =\n !style && (theme.tableHeader !== theme.body || theme.tableHeaderBold)\n\n const mapId = style\n ? (id: number) => (id === CHAR_NORMAL ? style.charPr : id === CHAR_BOLD ? style.boldCharPr : id)\n : undefined\n\n const rowHeights = rows.map((row) => style ? estimateRowHeight(row, colWidths, measureH) : 1500)\n\n const trElements = rows.map((row, rowIdx) => {\n // 부족한 셀은 빈 문자열로 채워 colCnt 맞춤\n const cells: string[] = row.length < colCnt ? [...row, ...Array<string>(colCnt - row.length).fill(\"\")] : row\n const isHeaderRow = rowIdx === 0\n const cellH = rowHeights[rowIdx]\n const baseCharPr = style ? style.charPr : CHAR_NORMAL\n const headerCharPr = isHeaderRow && useHeaderStyle ? CHAR_TABLE_HEADER : baseCharPr\n const tdElements = cells.map((cell, colIdx) => {\n const k = `${rowIdx},${colIdx}`\n const isLabelCell = labelCol0 && colIdx === 0\n // 헤더행·라벨열은 bold (실측: GT1 표⑪ 헤더 bold, GT6/GT7 라벨열 bold — TBL-05·06)\n const defaultCharPr = style\n ? (reg && (isHeaderRow || isLabelCell) ? style.boldCharPr : style.charPr)\n : (isHeaderRow ? headerCharPr : baseCharPr)\n const cellCharPr = prof?.cellChar.get(k) ?? defaultCharPr\n // 셀 문단 — 실측: 헤더·짧은 열 CENTER 130%, 장문 열 LEFT (JUSTIFY 아님, TBL-11)\n const centered = isHeaderRow || colCentered[colIdx]\n const paraPrId = style\n ? (centered ? (style.tblCenterParaPr ?? style.centerParaPr) : (reg ? (style.tblLeftParaPr ?? PARA_NORMAL) : PARA_NORMAL))\n : PARA_NORMAL\n // <br>은 kordoc GFM 셀 규약(파서가 셀 내 개행을 <br>로 방출) — 문단 분리로 복원.\n // 셀 안 이미지 참조는 placeholder <hp:pic>로 보존 (v4.0.5 — alt 텍스트 각인이\n // 이미지 열을 빈 열로 만들어 재파싱 후행 열 트림을 유발하던 결함)\n const p = cell.split(/<br\\s*\\/?>/i).map((seg) => {\n let picRuns = \"\"\n if (images) {\n const { text: rest, urls } = splitImageRefs(seg)\n if (urls.length > 0) {\n const pics = urls.map((u) => { const part = images.take(u); return part ? images.inlinePicXml(part) : null })\n if (pics.every(Boolean)) {\n seg = rest\n picRuns = `<hp:run charPrIDRef=\"${cellCharPr}\">${pics.join(\"\")}</hp:run>`\n }\n }\n }\n const runs = generateRuns(seg, cellCharPr, prof?.cellChar.has(k) ? undefined : mapId)\n const body = (runs || (picRuns ? \"\" : `<hp:run charPrIDRef=\"${cellCharPr}\"><hp:t></hp:t></hp:run>`)) + picRuns\n return `<hp:p paraPrIDRef=\"${paraPrId}\" styleIDRef=\"0\">${body}</hp:p>`\n }).join(\"\")\n // 테두리 — 프로필 실측 최우선, 다음 위계 레지스트리(TBL-01·02), 폴백 기본\n const bf = prof?.cellBf.get(k)\n ?? (reg\n ? reg.get(dataCellSpec({\n row: rowIdx, rowEnd: rowIdx, col: colIdx, colEnd: colIdx,\n rowCnt, colCnt, headerRows: 1,\n fill: isHeaderRow ? (style!.headerFill ?? \"#E6E6E6\") : isLabelCell ? (style!.labelFill ?? \"#E7E7E7\") : undefined,\n }))\n : style && isHeaderRow ? style.headerBf : 2)\n const h = prof?.cellH.get(k) ?? cellH\n // <hp:tc> 필수 속성 + subList + cellAddr + cellSpan + cellSz + cellMargin\n return `<hp:tc name=\"\" header=\"${isHeaderRow ? 1 : 0}\" hasMargin=\"0\" protect=\"0\" editable=\"1\" dirty=\"0\" borderFillIDRef=\"${bf}\">`\n + `<hp:subList id=\"\" textDirection=\"HORIZONTAL\" lineWrap=\"BREAK\" vertAlign=\"${style ? \"CENTER\" : \"TOP\"}\" linkListIDRef=\"0\" linkListNextIDRef=\"0\" textWidth=\"0\" textHeight=\"0\" hasTextRef=\"0\" hasNumRef=\"0\">${p}</hp:subList>`\n + `<hp:cellAddr colAddr=\"${colIdx}\" rowAddr=\"${rowIdx}\"/>`\n + `<hp:cellSpan colSpan=\"1\" rowSpan=\"1\"/>`\n + `<hp:cellSz width=\"${colWidths[colIdx]}\" height=\"${h}\"/>`\n + `<hp:cellMargin left=\"141\" right=\"141\" top=\"141\" bottom=\"141\"/>`\n + `</hp:tc>`\n }).join(\"\")\n return `<hp:tr>${tdElements}</hp:tr>`\n }).join(\"\")\n\n const tblW = colWidths.reduce((a, b) => a + b, 0)\n const tblH = rowHeights.reduce((a, b) => a + b, 0)\n\n // 실측 모드: 데이터 표 호스트 문단 RIGHT (실측: GT6/GT7/GT11 관행, TBL-09)\n const hostPr = reg && style?.rightParaPr !== undefined ? style.rightParaPr : 0\n // 2행 이상은 부유 앵커 — 한글이 쪽 경계에서 나눌 수 있도록 (tablePosXml 참조)\n const float = rowCnt >= 2\n\n // <hp:tbl>에 필수 속성 + <hp:sz>/<hp:outMargin>/<hp:inMargin>\n const tblInner = `<hp:sz width=\"${tblW}\" widthRelTo=\"ABSOLUTE\" height=\"${tblH}\" heightRelTo=\"ABSOLUTE\" protect=\"0\"/>`\n + tablePosXml(float, hostPr !== 0)\n + tableOutMarginXml(float, measureH)\n + `<hp:inMargin left=\"510\" right=\"510\" top=\"141\" bottom=\"141\"/>`\n + trElements\n\n // 공문서: 쪽 넘어가면 헤더행 반복 (repeatHeader)\n const tbl = `<hp:tbl id=\"${tblId}\" zOrder=\"0\" numberingType=\"TABLE\"${float ? FLOAT_TBL_ATTRS : \"\"} pageBreak=\"CELL\" repeatHeader=\"${style ? 1 : 0}\" rowCnt=\"${rowCnt}\" colCnt=\"${colCnt}\" cellSpacing=\"0\" borderFillIDRef=\"2\" noShading=\"0\">${tblInner}</hp:tbl>`\n\n return `<hp:p paraPrIDRef=\"${hostPr}\" styleIDRef=\"0\"><hp:run charPrIDRef=\"0\">${tbl}</hp:run></hp:p>`\n}\n\n// ─── HTML 표 생성 (병합셀 colspan/rowspan + 중첩표 재귀) ───\n//\n\n// kordoc parse는 병합/중첩표를 <table><tr><th|td colspan rowspan>…</table> HTML로\n// 내보낸다. 그 출력을 다시 HWPX로 만들 때 구조를 보존한다 — parse → 편집 →\n// markdownToHwpx 라운드트립의 표 구멍을 막는 경로.\n\ninterface PlacedHtmlCell {\n r: number\n c: number\n colSpan: number\n rowSpan: number\n inner: string\n isHeader: boolean\n}\n\n/** HTML 행 목록 → 그리드 배치 (colspan/rowspan 점유 반영) */\nfunction layoutHtmlRows(rows: HtmlRowInfo[]): { placed: PlacedHtmlCell[]; rowCnt: number; colCnt: number } {\n const occupied = new Set<string>()\n const placed: PlacedHtmlCell[] = []\n let colCnt = 0\n for (let r = 0; r < rows.length; r++) {\n let c = 0\n for (const cell of rows[r].cells) {\n while (occupied.has(`${r},${c}`)) c++\n // 파서 쪽(section-walker clampSpan)과 동일 한도 — 무클램프 시 거대 span이 점유 루프를 폭주시킨다\n const colSpan = clampSpan(cell.colSpan, MAX_COLS)\n const rowSpan = clampSpan(cell.rowSpan, MAX_ROWS)\n placed.push({ r, c, colSpan, rowSpan, inner: cell.inner, isHeader: rows[r].tag === \"th\" })\n for (let dr = 0; dr < rowSpan; dr++) {\n for (let dc = 0; dc < colSpan; dc++) occupied.add(`${r + dr},${c + dc}`)\n }\n c += colSpan\n colCnt = Math.max(colCnt, c)\n }\n }\n // 격자 구멍 충전 (v4.0.5 P1-2) — colCnt보다 짧은 <tr>(rowspan 미커버)은 tc가 누락된\n // malformed 표가 된다(행 셀폭 합 ≠ tblW → 한컴 거부/오배치). GFM 경로의 빈 셀 패딩과\n // 대칭으로, 미점유 좌표를 빈 셀로 채워 \"모든 행의 tc 폭 합 == tblW\"를 보장한다.\n for (let r = 0; r < rows.length; r++) {\n for (let c = 0; c < colCnt; c++) {\n if (!occupied.has(`${r},${c}`)) {\n placed.push({ r, c, colSpan: 1, rowSpan: 1, inner: \"\", isHeader: rows[r].tag === \"th\" })\n occupied.add(`${r},${c}`)\n }\n }\n }\n placed.sort((a, b) => a.r - b.r || a.c - b.c)\n return { placed, rowCnt: rows.length, colCnt }\n}\n\n/** HTML 엔티티 복원 (sanitizeText 이스케이프의 역변환) — &는 마지막에 */\nfunction unescapeHtml(s: string): string {\n return s\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/"/g, '\"')\n .replace(/'/g, \"'\")\n .replace(/&/g, \"&\")\n}\n\n/**\n * HTML 표 원문 → <hp:tbl> XML. 병합셀은 cellSpan/cellAddr로, 셀 안 중첩표는\n * subList 안에 재귀 생성한다. 파싱 불가면 null (호출부가 문단 폴백).\n * @param totalWidth 표 전체 폭(HWPUNIT) — 중첩표는 부모 셀폭에 맞춰 축소\n */\nexport function generateHtmlTableXml(rawHtml: string, theme: ResolvedTheme, totalWidth: number = 44000, style: GongmunTableStyle | null = null, remap: ProfileRemap | null = null, seq = 0, images: ImageRegistry | null = null, nested = false): string | null {\n const rows = parseHtmlTable(rawHtml)\n if (!rows || rows.length === 0) return null\n const { placed, rowCnt, colCnt } = layoutHtmlRows(rows)\n if (rowCnt === 0 || colCnt === 0) return null\n\n const measureH = style?.charHeight ?? 1000\n // 폭 클래스 — 종전엔 설정하지 않아 직전 GFM 표의 값(또는 초기 hcr)을 물려받았다\n curFace = style?.faceClass ?? \"hcr\"\n // 서식 프로필 매칭 (#41) — 첫 행 전체 지문(0.3.0)은 병합 셀의 시작 열 위치에 텍스트,\n // 커버 열은 빈 문자열 (추출기의 row0Texts 키 공간과 동일)\n const first = placed.find(p => p.r === 0 && p.c === 0) ?? placed[0]\n const row0 = Array.from({ length: colCnt }, () => \"\")\n for (const cell of placed) {\n if (cell.r === 0 && cell.c < colCnt) row0[cell.c] = anchorOfHtmlCell(cell.inner)\n }\n const prof = takeProfile(remap, rowCnt, colCnt, first ? anchorOfHtmlCell(first.inner) : \"\", seq, normalizeRowAnchor(row0))\n\n // 열별 최대 내용폭 — colSpan 셀은 폭/span 만큼 각 열에 기여\n const colMax = Array(colCnt).fill(0)\n const colMaxBody = Array(colCnt).fill(0)\n const colMinWord = Array(colCnt).fill(0)\n const cellParsed = placed.map((cell) => htmlCellInnerToLines(cell.inner))\n const cellLines = cellParsed.map((p) => p.lines)\n placed.forEach((cell, i) => {\n const w = Math.max(...cellLines[i].map((l) => measureTextWidth(unescapeHtml(l).trim(), measureH, 100, { faceClass: curFace })), 0) / cell.colSpan\n // 최장 어절(열 하한) — 병합 셀은 첫 열에만 기여 (분할 배분 시 하한 과대 방지)\n const mw = cell.colSpan === 1 ? Math.max(...cellLines[i].map((l) => cellMinWordWidth(unescapeHtml(l), measureH)), 0) : 0\n for (let dc = 0; dc < cell.colSpan; dc++) {\n const c = cell.c + dc\n if (w > colMax[c]) colMax[c] = w\n if (!cell.isHeader && w > colMaxBody[c]) colMaxBody[c] = w\n if (dc === 0 && mw > colMinWord[c]) colMinWord[c] = mw\n }\n })\n const headers = Array.from({ length: colCnt }, () => \"\")\n for (const [i, cell] of placed.entries()) if (cell.r === 0 && cell.c < colCnt) headers[cell.c] = unescapeHtml(cellLines[i].join(\" \"))\n const roles = style ? colRoles(headers) : []\n const colWidths = profileColWidths(prof, colCnt) ?? computeColWidths(colMax, totalWidth, colMinWord, roles, colSlack(curFace))\n const colCentered = colWidths.map((w, c) => roles[c] !== \"content\" && colMaxBody[c] + CELL_PAD <= w)\n\n const cellH = style ? Math.round(measureH * 1.6) + 282 : 1500\n const tblW = colWidths.reduce((a, b) => a + b, 0)\n const tblId = nextTableId()\n const useHeaderStyle = !style && (theme.tableHeader !== theme.body || theme.tableHeaderBold)\n const spanW = (cell: PlacedHtmlCell) => colWidths.slice(cell.c, cell.c + cell.colSpan).reduce((a, b) => a + b, 0)\n\n const reg = style?.bfRegistry ?? null\n // 헤더 행 수 — 연속된 th 행 (이중선 경계 판정용)\n let htmlHeaderRows = 0\n while (htmlHeaderRows < rows.length && rows[htmlHeaderRows].tag === \"th\") htmlHeaderRows++\n\n // Pass 1 — 셀별 내용 높이를 재고 행별 최대치(tableRowHeights)를 확정한다.\n // · rowSpan은 실제 그리드 행수로 클램프 — 오버스팬은 무효 HWPX + 맨아랫줄 병합셀\n // 하변 위계(thick) 오판을 부른다.\n // · 높이는 명시 <br> 줄 수가 아니라 셀폭 기준 줄바꿈까지 시뮬 — GFM estimateRowHeight와\n // 정합(명시 개행 없는 긴 서술 셀이 타 뷰어에서 잘리는 것 방지).\n const tableRowHeights = Array<number>(rowCnt).fill(cellH)\n const meta = placed.map((cell, i) => {\n const rowSpan = Math.min(cell.rowSpan, rowCnt - cell.r)\n const lines = cellLines[i]\n // 중첩표 — 셀폭(마진 제외)에 맞춰 1회 재귀 생성, Pass 2에서 재사용(재호출 방지).\n // texts[i]는 i번째 표 앞 텍스트 — Pass 2가 원문 배치 순서대로 방출한다 (#49).\n // 생성 실패 표는 null로 자리를 지켜 텍스트 조각과의 인덱스 정합 유지\n let nestedH = 0\n const { texts: segTexts, tables: nestedTables } = splitCellByTopLevelTables(cell.inner)\n const nestedXmls: (string | null)[] = nestedTables.map((nested) => {\n // 중첩표 폭 = 부모 셀폭 − 여유(1020), 가독 하한 4000 — 단 하한이 부모 셀폭을\n // 넘으면 셀 경계를 침범하므로 상한(셀폭 − 마진 282)에 양보한다 (v4.0.5 P1-3)\n const sw = spanW(cell)\n const nestedW = Math.max(Math.min(Math.max(sw - 1020, 4000), sw - 282), 500)\n const nestedXml = generateHtmlTableXml(nested, theme, nestedW, style ? { ...style, totalWidth: nestedW } : null, null, 0, null, true)\n if (nestedXml) {\n // 재귀가 확정한 실높이(hp:sz — 셀 성장·줄바꿈 반영)를 재사용. 행수×cellH 추정은\n // 중첩 셀이 접히면(긴 텍스트 wrap) 과소해 호스트 행이 중첩표를 못 담았다 (v4.0.4)\n const szH = nestedXml.match(/<hp:sz [^>]*height=\"(\\d+)\"/)?.[1]\n nestedH += (szH ? Number(szH) : ((nested.match(/<tr[\\s>]/gi) ?? []).length) * cellH) + 300\n }\n return nestedXml\n })\n const segLines = segTexts.map((t) => htmlCellInnerToLines(t).lines)\n // 셀폭 기준 줄바꿈 수 — <br> 분리 각 줄이 폭을 넘으면 추가로 접힌다\n const usable = Math.max(spanW(cell) - CELL_PAD, 1000)\n let wrapLines = 0\n for (const line of lines) wrapLines += Math.max(1, Math.ceil(measureTextWidth(unescapeHtml(line).trim(), measureH, 100, { faceClass: curFace }) / usable))\n const lineH = style ? Math.round(measureH * 1.6) : 800\n const contentH = Math.max(cellH * rowSpan, Math.max(wrapLines, 1) * lineH + nestedH)\n const cellHeight = Math.max(prof?.cellH.get(`${cell.r},${cell.c}`) ?? 0, contentH)\n const perRow = Math.ceil(cellHeight / rowSpan)\n for (let r = cell.r; r < cell.r + rowSpan; r++) tableRowHeights[r] = Math.max(tableRowHeights[r], perRow)\n return { cell, rowSpan, lines, nestedXmls, segLines, imgSrcs: cellParsed[i].imgSrcs }\n })\n\n // Pass 2 — 확정된 행높이로 셀 XML 생성. 셀 높이 = 점유 행들의 확정 높이 합이라\n // 같은 행 셀들의 높이가 일치하고 열별 합이 hp:sz(tableH)와 정확히 맞는다.\n const tcXmls = meta.map(({ cell, rowSpan, nestedXmls, segLines, imgSrcs }) => {\n const k = `${cell.r},${cell.c}`\n const isHeader = cell.isHeader\n const baseCharPr = style ? style.charPr : CHAR_NORMAL\n const headerCharPr = isHeader && useHeaderStyle ? CHAR_TABLE_HEADER : baseCharPr\n const defaultCharPr = style && reg && isHeader ? style.boldCharPr : isHeader ? headerCharPr : baseCharPr\n const charPrId = prof?.cellChar.get(k) ?? defaultCharPr\n const centered = isHeader || colCentered[cell.c]\n const paraPrId = style\n ? (centered ? (reg ? (style.tblCenterParaPr ?? style.centerParaPr) : style.centerParaPr) : (reg ? (style.tblLeftParaPr ?? PARA_NORMAL) : PARA_NORMAL))\n : PARA_NORMAL\n // 셀 이미지 — <img src>(imgSrcs)와 라인 내 마크다운 참조를 placeholder pic으로 (v4.0.5)\n const picUrls: string[] = images ? [...imgSrcs] : []\n const paras: string[] = []\n const pushTextLine = (line: string) => {\n let text = unescapeHtml(line)\n if (images) {\n const { text: rest, urls } = splitImageRefs(text)\n if (urls.length > 0) { picUrls.push(...urls); text = rest }\n }\n // 이미지 참조만으로 구성된 라인은 텍스트 문단 생략 — 아래 pic 문단이 대체\n if (!images || text.trim() || picUrls.length === 0) {\n paras.push(`<hp:p paraPrIDRef=\"${paraPrId}\" styleIDRef=\"0\"><hp:run charPrIDRef=\"${charPrId}\"><hp:t>${escapeTextXml(text)}</hp:t></hp:run></hp:p>`)\n }\n }\n // 텍스트 조각·중첩표를 원문 배치 순서대로 방출 (#49) — 종전 텍스트 전량 선방출은\n // 표가 앞선 원문에서 순서를 역전시켰다. segLines[i] = i번째 중첩표 앞 텍스트\n segLines.forEach((seg, si) => {\n for (const line of seg) pushTextLine(line)\n const nestedXml = nestedXmls[si]\n if (nestedXml) {\n paras.push(`<hp:p paraPrIDRef=\"0\" styleIDRef=\"0\"><hp:run charPrIDRef=\"0\">${nestedXml}</hp:run></hp:p>`)\n }\n })\n if (images && picUrls.length > 0) {\n const pics = picUrls.map((u) => { const part = images.take(u); return part ? images.inlinePicXml(part) : null }).filter(Boolean)\n if (pics.length > 0) {\n paras.push(`<hp:p paraPrIDRef=\"${paraPrId}\" styleIDRef=\"0\"><hp:run charPrIDRef=\"${charPrId}\">${pics.join(\"\")}</hp:run></hp:p>`)\n }\n }\n if (paras.length === 0) {\n paras.push(`<hp:p paraPrIDRef=\"${paraPrId}\" styleIDRef=\"0\"><hp:run charPrIDRef=\"${charPrId}\"><hp:t></hp:t></hp:run></hp:p>`)\n }\n // 셀 높이 = 점유 행들의 확정 높이 합 (같은 행 셀 높이 일치, 합 = hp:sz)\n let cellHeight = 0\n for (let r = cell.r; r < cell.r + rowSpan; r++) cellHeight += tableRowHeights[r]\n const rowEnd = cell.r + rowSpan - 1\n // 테두리 — 프로필 최우선, 다음 위계(병합 셀은 끝 행·열 기준 — 클램프된 rowSpan), 폴백 기본\n const bf = prof?.cellBf.get(k)\n ?? (reg\n ? reg.get(dataCellSpec({\n row: cell.r, rowEnd, col: cell.c, colEnd: cell.c + cell.colSpan - 1,\n rowCnt, colCnt, headerRows: htmlHeaderRows,\n fill: isHeader ? (style!.headerFill ?? \"#E6E6E6\") : undefined,\n }))\n : style && isHeader ? style.headerBf : 2)\n return `<hp:tc name=\"\" header=\"${isHeader ? 1 : 0}\" hasMargin=\"0\" protect=\"0\" editable=\"1\" dirty=\"0\" borderFillIDRef=\"${bf}\">`\n + `<hp:subList id=\"\" textDirection=\"HORIZONTAL\" lineWrap=\"BREAK\" vertAlign=\"${style ? \"CENTER\" : \"TOP\"}\" linkListIDRef=\"0\" linkListNextIDRef=\"0\" textWidth=\"0\" textHeight=\"0\" hasTextRef=\"0\" hasNumRef=\"0\">${paras.join(\"\")}</hp:subList>`\n + `<hp:cellAddr colAddr=\"${cell.c}\" rowAddr=\"${cell.r}\"/>`\n + `<hp:cellSpan colSpan=\"${cell.colSpan}\" rowSpan=\"${rowSpan}\"/>`\n + `<hp:cellSz width=\"${spanW(cell)}\" height=\"${cellHeight}\"/>`\n + `<hp:cellMargin left=\"141\" right=\"141\" top=\"141\" bottom=\"141\"/>`\n + `</hp:tc>`\n })\n\n // 행별로 tr 묶기 (placed는 행 순서 유지)\n const trXmls: string[] = []\n for (let r = 0; r < rowCnt; r++) {\n const rowTcs = tcXmls.filter((_, i) => placed[i].r === r)\n trXmls.push(`<hp:tr>${rowTcs.join(\"\")}</hp:tr>`)\n }\n\n const tableH = tableRowHeights.reduce((sum, height) => sum + height, 0)\n // 2행 이상 최상위 표는 부유 앵커 (tablePosXml 참조) — 호스트 문단은 호출자가 감싸며\n // 실측 모드(bfRegistry)에서 우측정렬이라 horzAlign도 같이 맞춘다\n const float = !nested && rowCnt >= 2\n\n return `<hp:tbl id=\"${tblId}\" zOrder=\"0\" numberingType=\"TABLE\"${float ? FLOAT_TBL_ATTRS : \"\"} pageBreak=\"CELL\" repeatHeader=\"${style ? 1 : 0}\" rowCnt=\"${rowCnt}\" colCnt=\"${colCnt}\" cellSpacing=\"0\" borderFillIDRef=\"2\" noShading=\"0\">`\n + `<hp:sz width=\"${tblW}\" widthRelTo=\"ABSOLUTE\" height=\"${tableH}\" heightRelTo=\"ABSOLUTE\" protect=\"0\"/>`\n + tablePosXml(float, !!reg && style?.rightParaPr !== undefined)\n + tableOutMarginXml(float, measureH)\n + `<hp:inMargin left=\"510\" right=\"510\" top=\"141\" bottom=\"141\"/>`\n + trXmls.join(\"\")\n + `</hp:tbl>`\n}\n","/**\n * 공문서 부속 요소 XML 조립 — 결재란·\"끝.\" 표시·1페이지형 제목박스.\n *\n * 실측 근거:\n * 결재란 — GT12 「발행 계획안」 결재선(주무관 라벨 + 서명 공란, 외곽 0.4mm·내부 0.12mm,\n * 굴림체 10pt CENTER, 전 셀 vAlign CENTER)의 간이형. 문서 최상단 우측 배치 관행.\n * 제목박스 — GT2/GT6/GT7 공통 3단(색상 바 #0080C0 + 제목 HY헤드라인M + gradient 바\n * #0080C0→#3CBFFF RADIAL, 외곽 0.12mm). 1페이지 계획·요약보고서 서두 골격.\n * \"끝.\" — 행정업무규정(본문 끝 2타+\"끝.\") + GT12 실측(단독 문단).\n */\n\nimport { PARA_NORMAL, CHAR_NORMAL, GONGMUN_RIGHT, GONGMUN_TBL_CENTER, GONGMUN_PARA_APPROVAL, GJ_PARA_BAR, escapeXml, escapeTextXml } from \"./gen-ids.js\"\nimport { TableBfRegistry } from \"./gen-table-bf.js\"\nimport { EXTRA_TABLE_ID_BASE } from \"./geometry.js\"\n\nlet extraTableId = EXTRA_TABLE_ID_BASE\n/** 문서 생성마다 부속 표 id 카운터 리셋 (결정적 출력) */\nexport function resetExtraTableIds(): void { extraTableId = EXTRA_TABLE_ID_BASE }\n\nexport function tbl(rows: string[], w: number, h: number, cols: number): string {\n return `<hp:tbl id=\"${++extraTableId}\" zOrder=\"0\" numberingType=\"TABLE\" textWrap=\"TOP_AND_BOTTOM\" textFlow=\"BOTH_SIDES\" lock=\"0\" dropcapstyle=\"None\" pageBreak=\"CELL\" repeatHeader=\"0\" rowCnt=\"${rows.length}\" colCnt=\"${cols}\" cellSpacing=\"0\" borderFillIDRef=\"1\" noAdjust=\"1\">`\n + `<hp:sz width=\"${w}\" widthRelTo=\"ABSOLUTE\" height=\"${h}\" heightRelTo=\"ABSOLUTE\" protect=\"0\"/>`\n + `<hp:pos treatAsChar=\"1\" affectLSpacing=\"0\" flowWithText=\"1\" allowOverlap=\"0\" holdAnchorAndSO=\"0\" vertRelTo=\"PARA\" horzRelTo=\"PARA\" vertAlign=\"TOP\" horzAlign=\"LEFT\" vertOffset=\"0\" horzOffset=\"0\"/>`\n + `<hp:outMargin left=\"283\" right=\"283\" top=\"283\" bottom=\"283\"/>`\n + `<hp:inMargin left=\"141\" right=\"141\" top=\"141\" bottom=\"141\"/>`\n + rows.map((r) => `<hp:tr>${r}</hp:tr>`).join(\"\")\n + `</hp:tbl>`\n}\n\nexport function tc(opts: { bf: number; row: number; col: number; w: number; h: number; colSpan?: number; rowSpan?: number; paras: string; name?: string; vAlign?: \"TOP\" | \"CENTER\" | \"BOTTOM\" }): string {\n return `<hp:tc name=\"${opts.name ?? \"\"}\" header=\"0\" hasMargin=\"0\" protect=\"0\" editable=\"1\" dirty=\"0\" borderFillIDRef=\"${opts.bf}\">`\n + `<hp:subList id=\"\" textDirection=\"HORIZONTAL\" lineWrap=\"BREAK\" vertAlign=\"${opts.vAlign ?? \"CENTER\"}\" linkListIDRef=\"0\" linkListNextIDRef=\"0\" textWidth=\"0\" textHeight=\"0\" hasTextRef=\"0\" hasNumRef=\"0\">${opts.paras}</hp:subList>`\n + `<hp:cellAddr colAddr=\"${opts.col}\" rowAddr=\"${opts.row}\"/>`\n + `<hp:cellSpan colSpan=\"${opts.colSpan ?? 1}\" rowSpan=\"${opts.rowSpan ?? 1}\"/>`\n + `<hp:cellSz width=\"${opts.w}\" height=\"${opts.h}\"/>`\n + `<hp:cellMargin left=\"141\" right=\"141\" top=\"141\" bottom=\"141\"/>`\n + `</hp:tc>`\n}\n\nexport function para(text: string, paraPrId: number, charPrId: number): string {\n return `<hp:p paraPrIDRef=\"${paraPrId}\" styleIDRef=\"0\"><hp:run charPrIDRef=\"${charPrId}\"><hp:t>${escapeTextXml(text)}</hp:t></hp:run></hp:p>`\n}\n\n// ─── 결재란 (B5) ────────────────────────────────────\n\n/** 결재란 칸 폭 — 25mm(실무 서명칸 관행) */\nconst APPROVAL_COL_W = 7085\n/** 라벨 행·서명 행 높이 — 라벨은 10pt 100% 줄박스 + 상하 여백(141×2)이 들어가는 1300 */\nconst APPROVAL_LABEL_H = 1300\nconst APPROVAL_SIGN_H = 4200\n\n/**\n * 간이 결재란 — 직위 라벨 행 + 서명 공란 행 (2×N). 호스트 문단 RIGHT 정렬.\n * 실측(GT12 결재선)의 간이형: 외곽 0.4mm·내부 0.12mm, 라벨 CENTER.\n */\nexport function buildApprovalTable(labels: string[], reg: TableBfRegistry, approvalCharPr: number): string {\n const n = labels.length\n const w = APPROVAL_COL_W * n\n const bfAt = (row: number, col: number) =>\n reg.get({\n t: row === 0 ? \"thick\" : \"thin\",\n b: row === 1 ? \"thick\" : \"thin\",\n l: col === 0 ? \"thick\" : \"thin\",\n r: col === n - 1 ? \"thick\" : \"thin\",\n })\n const labelRow = labels.map((label, c) =>\n tc({ bf: bfAt(0, c), row: 0, col: c, w: APPROVAL_COL_W, h: APPROVAL_LABEL_H, paras: para(label, GONGMUN_PARA_APPROVAL, approvalCharPr) }),\n ).join(\"\")\n const signRow = labels.map((_, c) =>\n tc({ bf: bfAt(1, c), row: 1, col: c, w: APPROVAL_COL_W, h: APPROVAL_SIGN_H, paras: para(\"\", GONGMUN_PARA_APPROVAL, approvalCharPr) }),\n ).join(\"\")\n const table = tbl([labelRow, signRow], w, APPROVAL_LABEL_H + APPROVAL_SIGN_H, n)\n return `<hp:p paraPrIDRef=\"${GONGMUN_RIGHT}\" styleIDRef=\"0\"><hp:run charPrIDRef=\"${CHAR_NORMAL}\">${table}</hp:run></hp:p>`\n}\n\n// ─── \"끝.\" 표시 (B11) ────────────────────────────────\n\n/**\n * 본문이 이미 \"끝.\"으로 마감되었는지 — 중복 방지.\n * 규정 관용구는 마침표를 동반한 \"끝.\"이다 — 마침표 없는 \"…성황리에 끝\" 같은 정상\n * 본문 꼬리를 끝표시로 오인해 필수 \"끝.\" 방출이 무음 누락되던 결함 수정 (v4.0.5).\n * 독립 토큰(문두 또는 공백 뒤) \"끝.\" / \"끝 .\"만 인정한다.\n */\nexport function hasEndMark(lastText: string): boolean {\n return /(^|\\s)끝\\s*\\.\\s*$/.test(lastText.trim())\n}\n\n/** \"끝.\" 문단 — 규정(2타 공백 후 \"끝.\") 반영, 단독 문단(실측 GT12 변형) */\nexport function buildEndMark(): string {\n return para(\" 끝.\", PARA_NORMAL, CHAR_NORMAL)\n}\n\n// ─── 1페이지형 제목박스 (G04 — report/plan/notice 서두) ──\n\n/** 제목박스 기하 — 실측 GT6/GT7: 바 h382, 전체폭 47907(본문폭 −280여) */\nconst TITLE_BOX = { barH: 382, titleH: 2850, color: \"#0080C0\", gradient: [\"#0080C0\", \"#3CBFFF\"] as [string, string] }\n\n/**\n * 색상 바 + 제목 + gradient 바 3단 제목박스 — GT2/GT6/GT7 공통 서두 골격.\n * 제목 문단은 CENTER, 헤딩 h1 charPr(호출부 전달)로 렌더.\n */\nexport function buildTitleBox(title: string, titleCharPr: number, barCharPr: number, bodyWidth: number, reg: TableBfRegistry): string {\n const w = bodyWidth - 280\n const outer = { t: \"thin\", b: \"thin\", l: \"thin\", r: \"thin\" } as const\n const barTop = reg.get({ ...outer, fill: TITLE_BOX.color })\n const barBottom = reg.get({ ...outer, fill: { gradient: TITLE_BOX.gradient } })\n const mid = reg.get(outer)\n // 바 셀 빈 문단 — 1pt 극소 스페이서(실측: GT6/GT7 함초롬바탕 1pt 빈런, TBL-12).\n // 전용 1pt charPr를 사용하고 행높이는 셀 h로 강제한다.\n const barPara = para(\"\", GJ_PARA_BAR, barCharPr)\n // 왕복 채널 (P2) — 제목박스가 소비한 첫 h1을 재파싱 시 헤딩으로 복원\n const rows = [\n tc({ bf: barTop, row: 0, col: 0, w, h: TITLE_BOX.barH, paras: barPara }),\n tc({ bf: mid, row: 1, col: 0, w, h: TITLE_BOX.titleH, paras: para(title, GONGMUN_TBL_CENTER, titleCharPr), name: \"__kordoc_h1\" }),\n tc({ bf: barBottom, row: 2, col: 0, w, h: TITLE_BOX.barH, paras: barPara }),\n ]\n const table = tbl(rows, w, TITLE_BOX.barH * 2 + TITLE_BOX.titleH, 1)\n return `<hp:p paraPrIDRef=\"${PARA_NORMAL}\" styleIDRef=\"0\"><hp:run charPrIDRef=\"${CHAR_NORMAL}\">${table}</hp:run></hp:p>`\n}\n","/**\n * 공문서 부속 골격(docframe) — 기안문 두문·결문, 보고정보 행, 공고문 두문·결문,\n * 보도자료 머리박스·담당 표 (v4.1.0 GAP-02/03/04/08).\n *\n * 실측 근거:\n * (기안문 두문·결문은 v5 gen-frame-seoul.ts 서울 실결재 표 골격으로 이전)\n * 보고정보 행 — 「3_보고서 양식」 휴먼명조 12pt RIGHT \"(보고일시, 보고자(과장), 연락처)\"\n * 공고문 — 바이오헬스 공고문 실물: 공고번호 본문크기 bold 좌 / 날짜 RIGHT / 발신명의 bold RIGHT\n * 보도자료 — 국토부 실물(bodojaryo-reference): 머리박스 + 보도시점/배포(돋움 10pt bold)\n * + 제목 25pt bold + 본문 □→ㅇ→*(각주 12pt) + 담당 표\n *\n * charPr id는 정적 블록·장평 variant·서식 프로필 뒤 동적 base에서 할당 — generator가 배선.\n */\n\nimport { type ResolvedGongmun } from \"./gongmun.js\"\nimport { charPr, escapeXml, CHAR_NORMAL, CHAR_BOLD, PARA_NORMAL, GONGMUN_CENTER, GONGMUN_RIGHT, GONGMUN_TBL_CENTER, GONGMUN_TBL_LEFT } from \"./gen-ids.js\"\nimport { tbl, tc, para } from \"./gen-gongmun-extra.js\"\nimport { TableBfRegistry } from \"./gen-table-bf.js\"\n\n// ─── charPr 슬롯 (base + 오프셋, 고정 순서) ───────────\n\nexport const DOCFRAME_CHAR_COUNT = 9\n\nexport interface DocframeIds {\n org: number // 기안문 기관명 — 18pt bold\n sender: number // 발신명의 — 22pt bold\n foot: number // 결문 — 9pt\n small: number // 보고정보 행·보도자료 각주 — 12pt\n pressLabel: number // \"보도자료\" — 20pt bold\n pressHead: number // 보도시점/배포 — 10pt bold\n pressTitle: number // 보도자료 제목 — 25pt bold\n pressSub: number // 보도자료 부제 — 15pt bold\n pressContact: number // 담당 표 값 — 10pt\n}\n\nexport function docframeIds(base: number): DocframeIds {\n return { org: base, sender: base + 1, foot: base + 2, small: base + 3, pressLabel: base + 4, pressHead: base + 5, pressTitle: base + 6, pressSub: base + 7, pressContact: base + 8 }\n}\n\n/** docframe 기능이 하나라도 켜졌는지 — 꺼져 있으면 charPr 미방출(기존 산출물 불변) */\nexport function docframeActive(g: ResolvedGongmun): boolean {\n return !!(g.docHead || g.docFoot || g.reportInfo || g.noticeHead || g.press)\n}\n\n/** docframe 전용 charPr 9종 — rich 폰트세트(실측 프리셋·표지·목차)는 본문=id 4, 그 외 id 0 */\nexport function docframeCharPrXmls(base: number, richAssets: boolean): string[] {\n const body = richAssets ? 4 : 0\n const ids = docframeIds(base)\n return [\n charPr(ids.org, 1800, true, false, body),\n charPr(ids.sender, 2200, true, false, body),\n charPr(ids.foot, 900, false, false, body),\n charPr(ids.small, 1200, false, false, body),\n charPr(ids.pressLabel, 2000, true, false, body),\n charPr(ids.pressHead, 1000, true, false, body),\n charPr(ids.pressTitle, 2500, true, false, body),\n charPr(ids.pressSub, 1500, true, false, body),\n charPr(ids.pressContact, 1000, false, false, body),\n ]\n}\n\n// ─── 문단 헬퍼 ──────────────────────────────────────\n\nfunction blank(): string {\n return `<hp:p paraPrIDRef=\"${PARA_NORMAL}\" styleIDRef=\"0\"><hp:run charPrIDRef=\"${CHAR_NORMAL}\"><hp:t></hp:t></hp:run></hp:p>`\n}\n\n// 기안문 두문·결문 문단 빌더는 v5(gen-frame-seoul.ts 두문표·결문표)로 대체돼 제거됨\n\n/** 수신이 \"내부결재\" 인 문서는 발신명의를 적지 않는다 (행정업무규정 시행규칙 제4조 — 내부결재 문서의 결문) */\nexport function isInternalApproval(to: string | undefined): boolean {\n return !!to && /^\\s*내\\s*부\\s*결\\s*재/.test(to)\n}\n\n// ─── 업무보고 보고정보 행 (실측 t3: 휴먼명조 12pt RIGHT) ──\n\nexport function buildReportInfo(g: ResolvedGongmun, ids: DocframeIds): string {\n return para(g.reportInfo!, GONGMUN_RIGHT, ids.small)\n}\n\n// ─── 공고문 두문·결문 (실측: 바이오헬스 공고문) ─────────\n\nexport function buildNoticeHead(g: ResolvedGongmun): string[] {\n const n = g.noticeHead!\n return n.no ? [para(n.no, PARA_NORMAL, CHAR_BOLD), blank()] : []\n}\n\nexport function buildNoticeFoot(g: ResolvedGongmun): string[] {\n const n = g.noticeHead!\n const out: string[] = []\n if (n.date) out.push(blank(), para(n.date, GONGMUN_RIGHT, CHAR_NORMAL))\n if (n.sender) out.push(blank(), para(n.sender, GONGMUN_RIGHT, CHAR_BOLD))\n return out\n}\n\n// ─── 보도자료 머리박스·담당 표 ────────────────────────\n\nconst PRESS_LABEL_H = 3200\nconst PRESS_HEAD_H = 900\n\n/** 머리박스 — \"보도자료\" 라벨 행 + 보도시점/배포 행 (외곽 0.4mm, 실물 골격 단순화) */\nexport function buildPressHead(g: ResolvedGongmun, ids: DocframeIds, bodyWidth: number, reg: TableBfRegistry): string[] {\n const p = g.press!\n const w = bodyWidth - 280\n const thick = { t: \"thick\", b: \"thick\", l: \"thick\", r: \"thick\" } as const\n const rows = [tc({ bf: reg.get({ ...thick, b: \"thin\" }), row: 0, col: 0, w, h: PRESS_LABEL_H, paras: para(\"보도자료\", GONGMUN_TBL_CENTER, ids.pressLabel) })]\n const headLine = [\n p.release ? `보도시점 : ${p.release}` : \"\",\n p.distribute ? `배포 : ${p.distribute}` : \"\",\n ].filter(Boolean).join(\" / \")\n if (headLine) rows.push(tc({ bf: reg.get({ ...thick, t: \"thin\" }), row: 1, col: 0, w, h: PRESS_HEAD_H, paras: para(headLine, GONGMUN_TBL_CENTER, ids.pressHead) }))\n const table = tbl(rows, w, PRESS_LABEL_H + (headLine ? PRESS_HEAD_H : 0), 1)\n return [`<hp:p paraPrIDRef=\"${PARA_NORMAL}\" styleIDRef=\"0\"><hp:run charPrIDRef=\"${CHAR_NORMAL}\">${table}</hp:run></hp:p>`, blank()]\n}\n\n/** 담당 표 — 담당 부서 | 담당자 | 연락처 1행 (실물 표3의 단순화) */\nexport function buildPressContact(g: ResolvedGongmun, ids: DocframeIds, bodyWidth: number, reg: TableBfRegistry): string[] {\n const c = g.press?.contact\n if (!c || (!c.dept && !c.manager && !c.phone)) return []\n const w = bodyWidth - 280\n const cells = [[\"담당 부서\", c.dept ?? \"\"], [\"담당자\", c.manager ?? \"\"], [\"연락처\", c.phone ?? \"\"]]\n const labelW = Math.round(w * 0.14)\n const valueW = Math.round(w / 3) - labelW\n let col = 0\n const row = cells.flatMap(([label, value], i) => {\n const bf = (first: boolean) => reg.get({\n t: \"thick\", b: \"thick\",\n l: first && i === 0 ? \"thick\" : \"thin\",\n r: !first && i === cells.length - 1 ? \"thick\" : \"thin\",\n fill: first ? \"#E6E6E6\" : undefined,\n })\n return [\n tc({ bf: bf(true), row: 0, col: col++, w: labelW, h: 1100, paras: para(label, GONGMUN_TBL_CENTER, ids.pressHead) }),\n tc({ bf: bf(false), row: 0, col: col++, w: valueW, h: 1100, paras: para(value, GONGMUN_TBL_CENTER, ids.pressContact) }),\n ]\n })\n const table = tbl([row.join(\"\")], w, 1100, cells.length * 2)\n return [blank(), `<hp:p paraPrIDRef=\"${PARA_NORMAL}\" styleIDRef=\"0\"><hp:run charPrIDRef=\"${CHAR_NORMAL}\">${table}</hp:run></hp:p>`]\n}\n","/**\n * Markdown display math (LaTeX-like subset) → Hancom EqEdit script + <hp:equation> XML.\n *\n * 읽기 경로(equation.ts hmlToLatex)의 역방향. 어휘는 equation.ts의 토큰 맵과\n * 양방향 정합을 유지한다 — 여기서 뿜는 모든 토큰은 hmlToLatex가 같은 LaTeX로\n * 되읽어야 하며, 전 토큰 왕복 테스트(hwpx-equation-generation.test.ts)가 잠근다.\n */\n\nimport { CHAR_NORMAL, PARA_NORMAL, escapeXml } from \"./gen-ids.js\"\nimport { CONVERT_MAP, MIDDLE_CONVERT_MAP } from \"./equation.js\"\n\n// 비신뢰 입력 가드 — markdownToHwpx는 MCP/CLI로 임의 입력을 받는다 (리뷰 #39 ·2).\nconst MAX_EQUATION_SOURCE = 10_000\nconst MAX_GROUP_DEPTH = 64\n\n// LaTeX 명령 → EqEdit 토큰. 값은 반드시 읽기 맵(CONVERT_MAP)이 같은 LaTeX로\n// 되돌리는 토큰이어야 한다 (왕복 테스트가 전 항목 검증 — 리뷰 #39 ·3).\nexport const COMMAND_MAP: Record<string, string> = {\n alpha: \"alpha\",\n beta: \"beta\",\n gamma: \"gamma\",\n delta: \"delta\",\n epsilon: \"epsilon\",\n zeta: \"zeta\",\n eta: \"eta\",\n theta: \"theta\",\n iota: \"iota\",\n kappa: \"kappa\",\n lambda: \"lambda\",\n mu: \"mu\",\n nu: \"nu\",\n xi: \"xi\",\n pi: \"pi\",\n rho: \"rho\",\n sigma: \"sigma\",\n tau: \"tau\",\n upsilon: \"upsilon\",\n phi: \"phi\",\n chi: \"chi\",\n psi: \"psi\",\n omega: \"omega\",\n Gamma: \"GAMMA\",\n Delta: \"DELTA\",\n Theta: \"THETA\",\n Lambda: \"LAMBDA\",\n Xi: \"XI\",\n Pi: \"PI\",\n Sigma: \"SIGMA\",\n Upsilon: \"UPSILON\",\n Phi: \"PHI\",\n Psi: \"PSI\",\n Omega: \"OMEGA\",\n le: \"LEQ\",\n leq: \"LEQ\",\n ge: \"GEQ\",\n geq: \"GEQ\",\n ne: \"!=\",\n neq: \"!=\",\n pm: \"+-\",\n mp: \"-+\",\n times: \"TIMES\",\n cdot: \"cdot\",\n ast: \"AST\",\n circ: \"CIRC\",\n bullet: \"BULLET\",\n in: \"IN\",\n notin: \"NOTIN\",\n subset: \"SUBSET\",\n subseteq: \"SUBSETEQ\",\n supset: \"SUPERSET\",\n supseteq: \"SUPSETEQ\",\n cup: \"CUP\",\n cap: \"SMALLINTER\",\n emptyset: \"EMPTYSET\",\n forall: \"FORALL\",\n exists: \"EXIST\",\n infinity: \"INF\",\n infty: \"INF\",\n partial: \"Partial\",\n nabla: \"NABLA\",\n int: \"int\",\n iint: \"dint\",\n iiint: \"tint\",\n oint: \"oint\",\n sum: \"sum\",\n prod: \"prod\",\n lim: \"lim\",\n to: \"->\",\n rightarrow: \"->\",\n leftarrow: \"larrow\",\n leftrightarrow: \"<->\",\n Rightarrow: \"RARROW\",\n Leftarrow: \"LARROW\",\n Leftrightarrow: \"LRARROW\",\n cdots: \"CDOTS\",\n ldots: \"LDOTS\",\n vdots: \"VDOTS\",\n ddots: \"DDOTS\",\n}\n\n/**\n * EqEdit 함수 키워드 — 렌더러가 로만체 함수명으로 아는 어휘. 되읽기(hmlToLatex)가\n * 명령이 아닌 평문(sin)이라 COMMAND_MAP 고정점 검증 대상이 아니며, 미지원 명령\n * 따옴표 폴백에서 이들을 \"sin\" 리터럴로 감싸지 않기 위한 명단이다 (identity 통과).\n */\nconst EQEDIT_FUNCTIONS = new Set([\n \"sin\", \"cos\", \"tan\", \"cot\", \"sec\", \"csc\",\n \"arcsin\", \"arccos\", \"arctan\", \"sinh\", \"cosh\", \"tanh\", \"coth\",\n \"log\", \"ln\", \"exp\", \"det\", \"gcd\", \"mod\",\n \"max\", \"min\", \"arg\", \"deg\", \"hom\", \"ker\", \"Pr\",\n])\n\n// CONVERT_MAP 역인덱스 충전 (v4.0.6) — 읽기맵(~150 연산자)에 있는데 쓰기맵에 없던\n// 명령(\\div \\approx \\therefore \\because \\oplus \\uparrow \\propto \\cong \\equiv \\sim\n// \\angle \\mapsto \\ll \\gg \\dagger \\models \\owns 등 ~60개)이 백슬래시만 벗겨진\n// '맨 알파벳'으로 EqEdit에 누출되던 것을 봉합. 단일 명령 값(^\\[A-Za-z]+$)만\n// 역매핑 — 합성 값(\\mathop ∯·{\\Large\\ominus}·^{\\circ}C 등 읽기전용)은 제외.\n// 명시 항목이 항상 우선(leq→LEQ 등 기존 정준형 유지). 같은 LaTeX의 후보 토큰이\n// 여럿이면 이름 일치 > 영문 토큰 > 사전순으로 정준형을 고정한다.\n// 왕복은 구성상 보장: 방출 토큰 T의 CONVERT_MAP[T]가 곧 원 명령이다.\n{\n const reverse = new Map<string, string>()\n const prefer = (name: string, a: string, b: string): string => {\n if (a === name) return a\n if (b === name) return b\n const aAlpha = /^[A-Za-z]+$/.test(a)\n const bAlpha = /^[A-Za-z]+$/.test(b)\n if (aAlpha !== bAlpha) return aAlpha ? a : b\n return a < b ? a : b\n }\n for (const [token, latex] of Object.entries(CONVERT_MAP)) {\n const m = /^\\\\([A-Za-z]+)$/.exec(latex)\n if (!m) continue\n const name = m[1]\n if (name in COMMAND_MAP) continue\n const prev = reverse.get(name)\n reverse.set(name, prev === undefined ? token : prefer(name, token, prev))\n }\n for (const [name, token] of reverse) COMMAND_MAP[name] = token\n}\n\n// 악센트도 왕복 정합: 값 토큰을 hmlToLatex가 되돌린 명령이 다시 이 맵의 키여야\n// 한다 (bar → \\overline → bar 고정점. overrightarrow는 vec의 되읽기 별칭).\nexport const ACCENT_COMMANDS: Record<string, string> = {\n bar: \"bar\",\n overline: \"bar\",\n vec: \"vec\",\n overrightarrow: \"vec\",\n hat: \"hat\",\n widehat: \"hat\",\n tilde: \"tilde\",\n widetilde: \"tilde\",\n dot: \"dot\",\n ddot: \"ddot\",\n underline: \"under\",\n}\n\n// EqEdit이 명령으로 해석하는 어휘 = 읽기 맵 키 + 구조 키워드. 첨자/위첨자의\n// 리터럴 단어가 이와 충돌하면 따옴표 보호 (T_{int}의 int가 ∫로 렌더되는 것 방지).\n// 구 하드코딩 18단어는 실제 토큰맵과 무관해 폐기 (리뷰 #39 ·8).\nconst RESERVED_WORDS = new Set(\n [...Object.keys(CONVERT_MAP), ...Object.keys(MIDDLE_CONVERT_MAP), \"over\", \"root\", \"of\"]\n .filter((w) => /^[A-Za-z]+$/.test(w)),\n)\n\ninterface ReadResult {\n value: string\n next: number\n}\n\nfunction skipSpaces(input: string, idx: number): number {\n while (idx < input.length && /\\s/.test(input[idx])) idx++\n return idx\n}\n\n// 공백 정리만 한다. 구두점/괄호 접합은 금지 — \"RIGHT )\"를 \"RIGHT)\"로 붙이면\n// 공백 토크나이저인 hmlToLatex가 토큰을 못 읽어 왕복이 붕괴한다 (리뷰 #39 ·4).\nfunction normalizeEqEdit(input: string): string {\n return input.replace(/\\s+/g, \" \").trim()\n}\n\nfunction stripMathDelimiters(input: string): string {\n let s = input.trim()\n if (s.startsWith(\"$$\") && s.endsWith(\"$$\")) s = s.slice(2, -2).trim()\n if (s.startsWith(\"\\\\[\") && s.endsWith(\"\\\\]\")) s = s.slice(2, -2).trim()\n return s\n}\n\nfunction readBalanced(input: string, idx: number, open: string, close: string): ReadResult {\n let depth = 1\n let cursor = idx + 1\n while (cursor < input.length) {\n const ch = input[cursor]\n if (ch === \"\\\\\") {\n cursor += 2\n continue\n }\n if (ch === open) depth++\n else if (ch === close) depth--\n if (depth === 0) {\n return { value: input.slice(idx + 1, cursor), next: cursor + 1 }\n }\n cursor++\n }\n return { value: input.slice(idx + 1), next: input.length }\n}\n\nfunction readGroupOrToken(input: string, idx: number, depth: number): ReadResult {\n const start = skipSpaces(input, idx)\n // 중첩 상한 초과 — 남은 입력을 리터럴로 폴백 (스택 오버플로 가드, 리뷰 #39 ·2)\n if (depth > MAX_GROUP_DEPTH) return { value: input.slice(start), next: input.length }\n if (input[start] === \"{\") {\n const group = readBalanced(input, start, \"{\", \"}\")\n return { value: convertLatexFragment(group.value, depth + 1), next: group.next }\n }\n if (input[start] === \"\\\\\") {\n const cmd = readCommand(input, start, depth + 1)\n return { value: cmd.value, next: cmd.next }\n }\n return { value: input[start] ?? \"\", next: Math.min(start + 1, input.length) }\n}\n\nfunction readCommandName(input: string, idx: number): ReadResult {\n if (input[idx + 1] === \"\\\\\") return { value: \"\\\\\", next: idx + 2 }\n const match = /^[A-Za-z]+/.exec(input.slice(idx + 1))\n if (match) return { value: match[0], next: idx + 1 + match[0].length }\n return { value: input[idx + 1] ?? \"\", next: Math.min(idx + 2, input.length) }\n}\n\nfunction readCommand(input: string, idx: number, depth: number): ReadResult {\n const name = readCommandName(input, idx)\n const command = name.value\n\n if (command === \"\\\\\") return { value: \"#\", next: name.next }\n\n if (command === \"frac\") {\n const num = readGroupOrToken(input, name.next, depth)\n const den = readGroupOrToken(input, num.next, depth)\n return { value: `{${num.value}} over {${den.value}}`, next: den.next }\n }\n\n if (command === \"sqrt\") {\n let cursor = skipSpaces(input, name.next)\n let root: ReadResult | null = null\n if (input[cursor] === \"[\") {\n const opt = readBalanced(input, cursor, \"[\", \"]\")\n root = { value: convertLatexFragment(opt.value, depth + 1), next: opt.next }\n cursor = opt.next\n }\n const body = readGroupOrToken(input, cursor, depth)\n if (root) return { value: `root {${root.value}} of {${body.value}}`, next: body.next }\n return { value: `sqrt{${body.value}}`, next: body.next }\n }\n\n if (command === \"begin\") {\n const env = readGroupOrToken(input, name.next, depth)\n const endTag = `\\\\end{${env.value}}`\n const endIdx = input.indexOf(endTag, env.next)\n if (endIdx === -1) return { value: env.value, next: env.next }\n const body = convertLatexFragment(input.slice(env.next, endIdx), depth + 1)\n // 환경 → EqEdit 네이티브 토큰 화이트리스트 — LEFT (/RIGHT ) 합성보다 왕복이 정확.\n // 고정점: matrix/pmatrix/bmatrix 원 환경 복원, cases→HULKCASE→\\begin{cases},\n // vmatrix→dmatrix→\\begin{vmatrix}. align 계열은 eqalign으로 렌더 보존\n // (되읽기는 \\eqalign — plain TeX 어휘라 고정점은 아님, 렌더·내용 무손실).\n const ENV_TOKEN: Record<string, string> = {\n matrix: \"matrix\", pmatrix: \"pmatrix\", bmatrix: \"bmatrix\",\n vmatrix: \"dmatrix\", cases: \"cases\",\n align: \"eqalign\", \"align*\": \"eqalign\", aligned: \"eqalign\",\n }\n const tok = ENV_TOKEN[env.value]\n if (tok) return { value: `{${tok}{${body}}}`, next: endIdx + endTag.length }\n // Bmatrix(중괄호 행렬) — 전용 토큰이 없어 LEFT {/RIGHT } 합성 (되읽기\n // \\left\\{\\begin{matrix}…\\end{matrix}\\right\\} — 렌더·내용 보존)\n if (env.value === \"Bmatrix\") {\n return { value: `LEFT { {matrix{${body}}} RIGHT }`, next: endIdx + endTag.length }\n }\n // 미지원 환경(vmatrix* 등) — 종전대로 래퍼만 벗기고 본문 보존\n return { value: body, next: endIdx + endTag.length }\n }\n\n if (command === \"left\" || command === \"right\") {\n const kw = command === \"left\" ? \"LEFT\" : \"RIGHT\"\n const cursor = skipSpaces(input, name.next)\n let delimiter = input[cursor] ?? \"\"\n let next = delimiter ? cursor + 1 : cursor\n if (delimiter === \"\\\\\") {\n // \\{ \\} \\| 등 이스케이프 구분자 — 백슬래시 잔재 없이 원 문자만 (리뷰 #39 ·7).\n // \"LEFT {\"는 hmlToLatex replaceBracket이 \\left \\{ 로 복원하는 실파일 어휘.\n const escaped = readCommandName(input, cursor)\n delimiter = escaped.value === \"\\\\\" ? \"\\\\\" : (COMMAND_MAP[escaped.value] ?? escaped.value)\n next = escaped.next\n }\n return { value: delimiter ? `${kw} ${delimiter}` : kw, next }\n }\n\n if (command in ACCENT_COMMANDS) {\n const body = readGroupOrToken(input, name.next, depth)\n return { value: `${ACCENT_COMMANDS[command]}{${body.value}}`, next: body.next }\n }\n\n // LaTeX 공백 매크로 → EqEdit 공백 어휘 (리터럴 , ; : ! 로 주입되면 한글에 보이는\n // 구두점으로 렌더된다). `=1/4 공백, ~=공백. \\!(음수 공백)는 EqEdit 대응 없어 제거.\n if (command === \",\") return { value: \"`\", next: name.next }\n if (command === \";\" || command === \":\") return { value: \"~\", next: name.next }\n if (command === \"!\") return { value: \"\", next: name.next }\n\n if (command === \"mathrm\" || command === \"text\") {\n // 리터럴 텍스트 — 변환하지 않고 EqEdit 따옴표로 보호 (int가 ∫로 렌더 방지).\n // hmlToLatex는 단일 토큰 따옴표를 \\text{...}로 되읽어 고정점이 된다.\n const start = skipSpaces(input, name.next)\n if (input[start] === \"{\") {\n const group = readBalanced(input, start, \"{\", \"}\")\n return { value: `\"${group.value}\"`, next: group.next }\n }\n const tok = readGroupOrToken(input, start, depth)\n return { value: `\"${tok.value}\"`, next: tok.next }\n }\n\n const mapped = COMMAND_MAP[command]\n if (mapped !== undefined) return { value: mapped, next: name.next }\n if (EQEDIT_FUNCTIONS.has(command)) return { value: command, next: name.next }\n // 미지원 명령 — 백슬래시만 벗긴 '맨 알파벳'은 EqEdit이 변수 나열(이탤릭 d·i·v)로\n // 렌더해 조용한 오염이 된다. 리터럴 따옴표로 보호해 손실을 가시화·안정화한다\n // (hmlToLatex가 \"...\"를 \\text{...}로 되읽는 안정 어휘). 단일 문자(\\, 구분자 등)는\n // 종전대로 통과 — 구조 어휘 훼손 방지.\n if (/^[A-Za-z]{2,}$/.test(command)) return { value: `\"${command}\"`, next: name.next }\n return { value: command, next: name.next }\n}\n\nfunction convertLatexFragment(input: string, depth: number): string {\n // 중괄호 폭탄 등 기형 입력 — 상한 초과 시 리터럴 폴백 (리뷰 #39 ·2)\n if (depth > MAX_GROUP_DEPTH) return normalizeEqEdit(input)\n\n let out = \"\"\n let idx = 0\n\n while (idx < input.length) {\n const ch = input[idx]\n if (ch === \"\\\\\") {\n const cmd = readCommand(input, idx, depth + 1)\n out += ` ${cmd.value} `\n idx = cmd.next\n continue\n }\n if (ch === \"{\") {\n const group = readBalanced(input, idx, \"{\", \"}\")\n out += `{${convertLatexFragment(group.value, depth + 1)}}`\n idx = group.next\n continue\n }\n if (ch === \"_\" || ch === \"^\") {\n const script = readGroupOrToken(input, idx + 1, depth)\n out += ` ${ch}{${script.value}}`\n idx = script.next\n continue\n }\n if (ch === \"&\") {\n out += \" & \"\n idx++\n continue\n }\n out += ch\n idx++\n }\n\n return normalizeEqEdit(out)\n}\n\n/**\n * LaTeX 원문 단계에서 첨자/위첨자의 리터럴 예약어를 따옴표 보호.\n * 변환 전에만 적용 — 변환 산출물(\\pi→pi 등)을 재따옴표하지 않기 위함 (리뷰 #39 ·8).\n */\nexport function quoteReservedKeywords(latex: string): string {\n return latex.replace(/([_^])\\s*\\{\\s*([A-Za-z]+)\\s*\\}/g, (match, op: string, word: string) =>\n RESERVED_WORDS.has(word) ? `${op}{\"${word}\"}` : match)\n}\n\nexport function latexLikeToEqEdit(input: string): string {\n const src = stripMathDelimiters(input)\n if (src.length > MAX_EQUATION_SOURCE) return normalizeEqEdit(src)\n return convertLatexFragment(quoteReservedKeywords(src), 0)\n}\n\ninterface EquationMetrics {\n width: number\n height: number\n baseline: number\n}\n\nfunction estimateEquationMetrics(script: string): EquationMetrics {\n const cleaned = script.replace(/[{}\\\\^_]/g, \"\").replace(/\\s+/g, \" \").trim()\n const width = Math.min(Math.max(cleaned.length, 5) * 700 + 2000, 40000)\n const rowCount = Math.max(1, (script.match(/#/g) ?? []).length + 1)\n\n if (/\\bmatrix\\b|#/.test(script)) {\n if (rowCount >= 4) return { width, height: 5500, baseline: 55 }\n if (rowCount === 3) return { width, height: 4500, baseline: 60 }\n return { width, height: 3260, baseline: 63 }\n }\n if (/\\bover\\b|\\broot\\b|\\bsqrt\\b/.test(script)) return { width, height: 3010, baseline: 69 }\n return { width, height: 1450, baseline: 71 }\n}\n\nexport function generateEquationXml(script: string, zOrder: number = 0): string {\n const { width, height, baseline } = estimateEquationMetrics(script)\n const eqId = 2_000_000_001 + zOrder\n\n return `<hp:equation id=\"${eqId}\" zOrder=\"${zOrder}\" numberingType=\"EQUATION\" ` +\n `textWrap=\"TOP_AND_BOTTOM\" textFlow=\"BOTH_SIDES\" lock=\"0\" dropcapstyle=\"None\" ` +\n `version=\"Equation Version 60\" baseLine=\"${baseline}\" textColor=\"#000000\" ` +\n `baseUnit=\"1200\" lineMode=\"CHAR\" font=\"HYhwpEQ\">` +\n `<hp:sz width=\"${width}\" widthRelTo=\"ABSOLUTE\" height=\"${height}\" heightRelTo=\"ABSOLUTE\" protect=\"0\"/>` +\n `<hp:pos treatAsChar=\"1\" affectLSpacing=\"0\" flowWithText=\"1\" allowOverlap=\"0\" holdAnchorAndSO=\"0\" ` +\n `vertRelTo=\"PARA\" horzRelTo=\"PARA\" vertAlign=\"TOP\" horzAlign=\"LEFT\" vertOffset=\"0\" horzOffset=\"0\"/>` +\n `<hp:outMargin left=\"56\" right=\"56\" top=\"0\" bottom=\"0\"/>` +\n `<hp:shapeComment>수식입니다.</hp:shapeComment>` +\n `<hp:script>${escapeXml(script)}</hp:script>` +\n `</hp:equation>`\n}\n\nexport function generateEquationParagraph(input: string, zOrder: number = 0): string {\n const script = latexLikeToEqEdit(input)\n // 다른 생성 문단과 같은 최소 셸 — lineseg/고정 id 없이 한컴 재계산에 맡긴다\n // (gen-table.ts 표 래핑과 동일 규약)\n return `<hp:p paraPrIDRef=\"${PARA_NORMAL}\" styleIDRef=\"0\">` +\n `<hp:run charPrIDRef=\"${CHAR_NORMAL}\">${generateEquationXml(script, zOrder)}</hp:run></hp:p>`\n}\n","/**\n * HWPX 섹션 XML 조립 (generator.ts에서 분리).\n * 섹션 속성(공문서 표준 여백)과 블록 목록 → section0.xml 본문.\n *\n * v4.0.5 P0-2: 갓함수 분리 — \"첫 run이 secPr/colPr/쪽번호를 나른다\"는 계약을\n * SectionOpener 한 지점으로 응집(종전 6회 복붙), 프리앰블 적층은 buildPreamble,\n * 블록 변환은 타입별 render* 핸들러로 분해. 방출 바이트는 종전과 동일(해시 대조 검증).\n */\n\nimport { type ResolvedGongmun, levelIndent, mmToHwpunit, needsGaejosikAssets, usesReportFonts } from \"./gongmun.js\"\nimport { stripChapterNumber, gaejosikSizes, GAEJOSIK_BASE_WIDTH } from \"./gaejosik.js\"\nimport { buildGaejosikCover, buildGaejosikToc, buildGaejosikChapter, buildGaejosikBodyTitle, resetGjTableIds } from \"./gen-gaejosik.js\"\nimport {\n NS_SECTION, NS_PARA,\n CHAR_NORMAL, CHAR_BOLD, CHAR_QUOTE, CHAR_H1, PARA_NORMAL, PARA_QUOTE, PARA_CODE, PARA_LIST,\n GONGMUN_CENTER, GONGMUN_RIGHT, GONGMUN_SRC_LEFT, GONGMUN_TBL_CENTER, GONGMUN_TBL_LEFT, GONGMUN_LIST_BASE, GONGMUN_LIST_PLAIN_BASE, GONGMUN_LIST_VARIANT_BASE,\n GJ_CHAR_DAE, GJ_CHAR_DAE_BOLD, GJ_CHAR_CHAM, GJ_CHAR_CHAM_BOLD, GJ_PARA_CHAM,\n GJ_CHAR_TABLE, GJ_CHAR_TABLE_BOLD, GJ_CHAR_BODY_TITLE, gongmunTableHeaderBf,\n GJ_CHAR_APPROVAL, GJ_CHAR_TITLE_BAR, GONGMUN_APPROVAL_CHAR,\n GONGMUN_TBL_CHAR, GONGMUN_TBL_CHAR_BOLD, GONGMUN_TBL_PT, GONGMUN_TITLE_BAR_CHAR, GONGMUN_BODY_RATIO,\n GONGMUN_SRC_CHAR, GONGMUN_SRC_CHAR_BOLD, GJ_CHAR_SRC, GJ_CHAR_SRC_BOLD, srcCaptionPt,\n charVariantBase, pageNumCtrl, newPageNumCtrl, pageHidingCtrl,\n escapeXml, escapeTextXml, headingParaPrId, headingCharPrId,\n type ResolvedTheme,\n} from \"./gen-ids.js\"\nimport { type MdBlock, generateParagraph, generateRuns } from \"./md-runs.js\"\nimport { measureTextWidth } from \"./text-metrics.js\"\nimport { type GongmunFitPlan, type GongmunListPlan, variantMapper, precomputeGongmunList } from \"./gen-gongmun-fit.js\"\nimport { generateTable, generateHtmlTableXml, DATA_TABLE_INSET, resetTableIds, type GongmunTableStyle } from \"./gen-table.js\"\nimport { TableBfRegistry } from \"./gen-table-bf.js\"\nimport { type ProfileRemap } from \"./gen-profile.js\"\nimport { buildApprovalTable, buildEndMark, hasEndMark, buildTitleBox, resetExtraTableIds } from \"./gen-gongmun-extra.js\"\nimport { type LevelCharIds } from \"./gen-levels.js\"\nimport { type DocframeIds, buildReportInfo, buildNoticeHead, buildNoticeFoot, buildPressHead, buildPressContact } from \"./gen-docframe.js\"\nimport { generateEquationParagraph } from \"./equation-generate.js\"\nimport { parseChartFence, buildChartSpaceXml, buildChartElementXml } from \"./chart-gen.js\"\nimport { A4_W_HU, A4_H_HU, CHART_TABLE_ID_BASE } from \"./geometry.js\"\nimport { ImageRegistry, splitImageRefs } from \"./gen-image.js\"\nimport { type ResolvedPage, columnColPrXml, headerFooterCtrl } from \"./gen-page.js\"\n\n/** 생성 중 수집된 차트 파트 — 호출부(generator)가 ZIP·manifest에 등재 */\nexport interface ChartPart {\n /** ZIP 파트 경로 (Chart/chartN.xml) */\n name: string\n /** chartSpace XML 전문 */\n xml: string\n}\n\n// ─── 섹션 속성 (공문서 표준 여백) ────────────────────\n\nexport function generateSecPr(gongmun: ResolvedGongmun | null, page: ResolvedPage | null = null): string {\n // A4: 210mm × 297mm → 59528 × 84188 HWPUNIT (1mm ≈ 283.46 HWPUNIT)\n // 비공문서(기존): 위 30 / 아래 15 / 좌 20 / 우 15mm, 머리말·꼬리말 10mm.\n // 공문서 표준(편람 서식 작성방법 해설·시행규칙 별표4): 위 20 / 아래 10 / 좌 20 / 우 20mm,\n // 머리말·꼬리말·제본 0mm. (기존 위30 등은 권위 출처 없는 값이라 공문서 모드에서만 교체)\n const m = gongmun\n ? {\n top: mmToHwpunit(gongmun.margins.top),\n bottom: mmToHwpunit(gongmun.margins.bottom),\n left: mmToHwpunit(gongmun.margins.left),\n right: mmToHwpunit(gongmun.margins.right),\n header: 0,\n footer: 0,\n }\n : { top: 8504, bottom: 4252, left: 5670, right: 4252, header: 2835, footer: 2835 }\n // 개조식 실측(GT3): 머리말·꼬리말 영역 15mm — 쪽번호가 이 영역에 렌더\n if (gongmun) { m.header = gongmun.headerFooter; m.footer = gongmun.headerFooter }\n // outlineShapeIDRef=\"1\" — 헤딩 paraPr(OUTLINE)이 쓰는 빈 서식 numbering (gen-header buildNumberings)\n const secPr = `<hp:secPr textDirection=\"HORIZONTAL\" spaceColumns=\"1134\" tabStop=\"8000\" outlineShapeIDRef=\"1\" memoShapeIDRef=\"0\" textVerticalWidthHead=\"0\" masterPageCnt=\"0\">` +\n `<hp:grid lineGrid=\"0\" charGrid=\"0\" wonggojiFormat=\"0\"/>` +\n `<hp:startNum pageStartsOn=\"BOTH\" page=\"0\" pic=\"0\" tbl=\"0\" equation=\"0\"/>` +\n `<hp:visibility hideFirstHeader=\"0\" hideFirstFooter=\"0\" hideFirstMasterPage=\"0\" border=\"SHOW_ALL\" fill=\"SHOW_ALL\" hideFirstPageNum=\"0\" hideFirstEmptyLine=\"0\" showLineNumber=\"0\"/>` +\n `<hp:pagePr landscape=\"${page?.landscape ?? \"WIDELY\"}\" width=\"${page?.widthHU ?? A4_W_HU}\" height=\"${page?.heightHU ?? A4_H_HU}\" gutterType=\"LEFT_ONLY\">` +\n `<hp:margin header=\"${m.header}\" footer=\"${m.footer}\" gutter=\"0\" left=\"${m.left}\" right=\"${m.right}\" top=\"${m.top}\" bottom=\"${m.bottom}\"/>` +\n `</hp:pagePr>` +\n `<hp:footNotePr><hp:autoNumFormat type=\"DIGIT\" userChar=\"\" prefixChar=\"\" suffixChar=\")\" supscript=\"0\"/><hp:noteLine length=\"-1\" type=\"SOLID\" width=\"0.12 mm\" color=\"#000000\"/><hp:noteSpacing betweenNotes=\"283\" belowLine=\"567\" aboveLine=\"850\"/><hp:numbering type=\"CONTINUOUS\" newNum=\"1\"/><hp:placement place=\"EACH_COLUMN\" beneathText=\"0\"/></hp:footNotePr>` +\n `<hp:endNotePr><hp:autoNumFormat type=\"DIGIT\" userChar=\"\" prefixChar=\"\" suffixChar=\")\" supscript=\"0\"/><hp:noteLine length=\"14692344\" type=\"SOLID\" width=\"0.12 mm\" color=\"#000000\"/><hp:noteSpacing betweenNotes=\"0\" belowLine=\"567\" aboveLine=\"850\"/><hp:numbering type=\"CONTINUOUS\" newNum=\"1\"/><hp:placement place=\"END_OF_DOCUMENT\" beneathText=\"0\"/></hp:endNotePr>` +\n `</hp:secPr>`\n // 단 컬럼 정의(colPr) — 반드시 secPr 뒤 같은 run에 방출한다. 없으면 한글이 컬럼\n // 영역을 좌우 10mm(2835HU)씩 좁게 잡아 본문이 우측 여백에 못 미치고, 컬럼보다\n // 넓은 treatAsChar 표(제목박스·데이터표·목차박스)는 우측 여백을 침범한다\n // (v4.1.0 GAP-01 — COM 실렌더 실측: colPr 주입만으로 본문 190mm 정합·초과 0 확인).\n // columns=1이면 columnColPrXml이 종전 하드코딩과 동일 바이트를 방출한다.\n const colPr = columnColPrXml(page?.columns ?? 1)\n // 머리말/꼬리말 (v4.5.0) — 첫 문단 첫 run에 ctrl로 방출 (rhwp 형상)\n const hf = (page?.header ? headerFooterCtrl(\"header\", page.header, 1) : \"\") +\n (page?.footer ? headerFooterCtrl(\"footer\", page.footer, 2) : \"\")\n // 쪽번호 — 실측(GT3·GT6·GT7·GT9·GT11): 하단 중앙 \"- 1 -\". secPr·colPr과 같은 run에 배치\n return secPr + colPr + hf + (gongmun?.pageNumbers ? pageNumCtrl() : \"\")\n}\n\n// ─── SectionOpener — \"첫 run이 secPr/colPr/쪽번호를 나른다\" 계약의 단일 지점 ──\n//\n// HWPX는 섹션 첫 문단의 첫 run에 페이지 설정(secPr)이 실려야 한다. 종전에는 이\n// 주입이 프리앰블·차트·수식·표·HTML표·일반 문단 여섯 곳에 복붙돼 있었다 (P0-2).\nclass SectionOpener {\n private pending = true\n constructor(private readonly gongmun: ResolvedGongmun | null, private readonly page: ResolvedPage | null = null) {}\n\n /** 아직 secPr를 나를 첫 문단이 안 나왔는가 */\n get isFirst(): boolean { return this.pending }\n\n /** 일반 문단 XML의 첫 run에 secPr 주입 (소비) */\n inject(xml: string): string {\n this.pending = false\n return xml.replace(\n /<hp:run charPrIDRef=\"(\\d+)\">/,\n `<hp:run charPrIDRef=\"$1\">${generateSecPr(this.gongmun, this.page)}`,\n )\n }\n\n /**\n * 표·차트·수식처럼 첫 run에 직접 못 싣는 블록 앞에 secPr 전용 빈 문단을 방출 (소비).\n * 이미 소비됐으면 아무것도 안 한다.\n */\n emitCarrier(paraXmls: string[]): void {\n if (!this.pending) return\n this.pending = false\n const secRun = `<hp:run charPrIDRef=\"0\">${generateSecPr(this.gongmun, this.page)}<hp:t></hp:t></hp:run>`\n paraXmls.push(`<hp:p paraPrIDRef=\"0\" styleIDRef=\"0\">${secRun}</hp:p>`)\n }\n\n /** 빈 문서 폴백 — secPr를 실은 빈 단락 XML */\n emptyDoc(): string {\n this.pending = false\n return `<hp:p paraPrIDRef=\"0\" styleIDRef=\"0\"><hp:run charPrIDRef=\"0\">${generateSecPr(this.gongmun, this.page)}<hp:t></hp:t></hp:run></hp:p>`\n }\n}\n\n// ─── 섹션 조립 컨텍스트 — 핸들러 간 공유 상태 ─────────\n\ninterface SectionCtx {\n theme: ResolvedTheme\n gongmun: ResolvedGongmun | null\n gongmunList: GongmunListPlan | null\n fit: GongmunFitPlan | null\n chartParts: ChartPart[] | null\n bfReg: TableBfRegistry | null\n remap: ProfileRemap | null\n dfIds: DocframeIds | null\n /** 단계별 위계 타이포 charPr (levels 옵션, v4.12.3) — null이면 없음 */\n levelIds: LevelCharIds | null\n /** 이미지 placeholder 레지스트리 (v4.0.5) — null이면 종전 alt 텍스트 폴백 */\n images: ImageRegistry | null\n /** 파생 플래그·스타일 */\n gaejosik: boolean\n measured: boolean\n richAssets: boolean\n vBase: number\n tableStyle: GongmunTableStyle | null\n gjBodyW: number\n chamMap: (id: number) => number\n /** secPr 계약 */\n opener: SectionOpener\n paraXmls: string[]\n /** 가변 카운터·인덱스 */\n tableSeq: number\n chapterNo: number\n h2Seq: number\n coverH1Idx: number\n titleBoxH1Idx: number\n pressH1Idx: number\n /** 개조식 장 목록 SSOT — 목차·본문 로마 장헤더가 공유하는 heading blockIdx 배열 (P1-3) */\n gjChapterIdxs: number[]\n pendingPageBreak: boolean\n pendingNewNum: boolean\n orderedCounters: Record<number, number>\n prevWasOrdered: boolean\n}\n\n// ─── 프리앰블 (보고정보·결재란·두문·표지·목차·제목박스) ─\n\n/**\n * 공문서 전면부를 조립해 ctx.paraXmls에 적재하고, 본문 렌더가 참조할 인덱스\n * (표지 소비 h1, 제목박스/보도자료 h1)와 쪽나눔·쪽번호 재시작 플래그를 ctx에 설정.\n */\nfunction buildPreamble(blocks: MdBlock[], ctx: SectionCtx): void {\n const { gongmun, dfIds, bfReg, tableStyle, richAssets, gjBodyW } = ctx\n const preamble: string[] = []\n let hasFrontPages = false // 표지·목차 등 본문과 페이지가 분리되는 전면부 존재 여부\n // 보고정보 행 — 최상단 우측 (실측 t1: 보고일시·보고자·연락처가 문서 첫 줄)\n if (gongmun?.reportInfo && dfIds) {\n preamble.push(buildReportInfo(gongmun, dfIds))\n }\n // 결재란 — 문서 최상단 우측 (실측 GT12: 결재선이 표지 최상단)\n if (gongmun?.approval && bfReg) {\n preamble.push(buildApprovalTable(gongmun.approval, bfReg, richAssets ? GJ_CHAR_APPROVAL : GONGMUN_APPROVAL_CHAR))\n }\n // 공고문 공고번호 (실측: 바이오헬스 공고문 최상단 좌측 bold)\n if (gongmun?.noticeHead && dfIds) {\n preamble.push(...buildNoticeHead(gongmun))\n }\n // 보도자료 머리박스 — \"보도자료\" 라벨 + 보도시점/배포\n if (gongmun?.press && dfIds && bfReg && tableStyle) {\n preamble.push(...buildPressHead(gongmun, dfIds, tableStyle.totalWidth, bfReg))\n }\n if (gongmun && (gongmun.cover || gongmun.toc)) {\n const h1Idx = blocks.findIndex((b) => b.type === \"heading\" && (b.level ?? 1) === 1)\n let coverTitle = \"\"\n // 표지·목차 페이지 쪽번호 숨김 (실측 GT3: pageHiding hidePageNum=1 ×2) — 페이지 첫 문단 run에 주입\n const hide = (xml: string, hideHeader: boolean) =>\n gongmun!.pageNumbers ? xml.replace(/<hp:run charPrIDRef=\"(\\d+)\">/, `<hp:run charPrIDRef=\"$1\">${pageHidingCtrl(hideHeader)}`) : xml\n if (gongmun.cover && h1Idx >= 0) {\n coverTitle = (blocks[h1Idx].text || \"\").trim()\n const coverPart = buildGaejosikCover(coverTitle, gongmun, gjBodyW)\n coverPart[0] = hide(coverPart[0], true)\n preamble.push(...coverPart)\n ctx.coverH1Idx = h1Idx\n hasFrontPages = true\n }\n // 장 목록 SSOT (v4.0.5 P1-3) — 목차와 본문 로마 장헤더가 같은 배열·같은 번호를\n // 공유한다. 종전엔 목차=h2만, 본문=표지 제외 h1+h2로 서로 다른 규칙이라 표지가\n // 못 삼킨 둘째 h1이 있으면 본문 번호가 목차보다 +1씩 밀렸다.\n ctx.gjChapterIdxs = blocks\n .map((b, i) => (b.type === \"heading\" && (b.level ?? 1) <= 2 && i !== ctx.coverH1Idx ? i : -1))\n .filter((i) => i >= 0)\n if (gongmun.toc && ctx.gjChapterIdxs.length > 0) {\n const chapters = ctx.gjChapterIdxs.map((i) => stripChapterNumber(blocks[i].text || \"\"))\n const tocPart = buildGaejosikToc(chapters, gongmun, gjBodyW)\n tocPart[0] = hide(tocPart[0], false)\n preamble.push(...tocPart)\n hasFrontPages = true\n }\n // 본문 첫 페이지 제목 반복 박스 (실측 GT3 표④·GT12) — 표지/목차 뒤 새 페이지 선두\n if (gongmun.bodyTitleBox && coverTitle && hasFrontPages) {\n preamble.push(buildGaejosikBodyTitle(coverTitle, gongmun, gjBodyW).replace(/^<hp:p /, `<hp:p pageBreak=\"1\" `))\n }\n }\n if (gongmun && !ctx.gaejosik && ctx.coverH1Idx < 0 && bfReg && (gongmun.preset === \"report\" || gongmun.preset === \"plan\" || gongmun.preset === \"notice\")) {\n // 1페이지형 제목박스 (실측 GT2/GT6/GT7: 색상바+제목+gradient바) — 첫 h1을 박스로\n ctx.titleBoxH1Idx = blocks.findIndex((b) => b.type === \"heading\" && (b.level ?? 1) === 1)\n } else if (gongmun?.press && ctx.coverH1Idx < 0 && dfIds) {\n // 보도자료 — 첫 h1을 제목 25pt bold CENTER + 부제(- … -)로 (실측: 국토부 실물 표2)\n ctx.pressH1Idx = blocks.findIndex((b) => b.type === \"heading\" && (b.level ?? 1) === 1)\n }\n if (preamble.length > 0) {\n // 섹션 첫 문단이 페이지 설정(secPr)을 지니므로 여기서 주입, 선두 쪽나눔은 제거\n preamble[0] = ctx.opener.inject(preamble[0].replace(` pageBreak=\"1\"`, \"\"))\n // 본문 첫 블록 쪽나눔 — 전면부가 있고, 제목박스가 그 쪽나눔을 이미 소화하지 않았을 때만\n ctx.pendingPageBreak = hasFrontPages && !preamble[preamble.length - 1].includes(`pageBreak=\"1\"`)\n // 표지·목차가 있으면 본문에서 쪽번호 1 재시작 (실측 GT3 newNum)\n ctx.pendingNewNum = !!gongmun!.pageNumbers && hasFrontPages\n ctx.paraXmls.push(...preamble)\n }\n}\n\n// ─── 블록 타입별 렌더 핸들러 ─────────────────────────\n\n/**\n * 부호 문단 — 부호 run(부호 + 탭) + 내용 run. 공문서 항목 paraPr 는 내어쓰기용 자동 탭(tabPr 1)이라 탭이\n * 내어쓰기 위치에 서서 첫 줄 내용이 둘째 줄과 같은 x 에서 시작한다(v5 와 같은 방식 — 부호 폭 추정과 무관).\n * 탭 폭 속성은 한컴이 조판 때 다시 잰다(값은 반각 근사).\n */\nfunction markedParagraph(marker: string, content: string, paraPrId: number, charPrId: number, halfEm: number, mapCharId?: (id: number) => number, styleId = 0): string {\n const cid = mapCharId ? mapCharId(charPrId) : charPrId\n const run = `<hp:run charPrIDRef=\"${cid}\"><hp:t>${escapeTextXml(marker)}<hp:tab width=\"${Math.round(halfEm)}\" leader=\"0\" type=\"1\"/></hp:t></hp:run>`\n return `<hp:p paraPrIDRef=\"${paraPrId}\" styleIDRef=\"${styleId}\">${run}${generateRuns(content, charPrId, mapCharId)}</hp:p>`\n}\n\n/** \"※ 내용\"·\"* 내용\" → [부호, 내용]. \"**강조**\" 의 별표는 부호가 아니다(뒤가 공백일 때만) */\nfunction refParagraph(text: string, ctx: SectionCtx): string {\n const m = /^(※|\\*(?=\\s))\\s*/.exec(text)\n const [mk, rest] = m ? [m[1], text.slice(m[0].length)] : [\"※\", text]\n return markedParagraph(mk, rest, GJ_PARA_CHAM, GJ_CHAR_CHAM, ctx.gongmun!.bodyHeight / 2, ctx.chamMap)\n}\n\nfunction renderHeading(block: MdBlock, blockIdx: number, ctx: SectionCtx): string {\n const { gongmun, dfIds, tableStyle, bfReg, measured, richAssets, gjBodyW } = ctx\n if (gongmun && blockIdx === ctx.coverH1Idx) return \"\" // 표지가 소비한 h1\n if (gongmun && blockIdx === ctx.pressH1Idx && dfIds) {\n // 보도자료 제목 + 부제 \"- … -\" (실측: 국토부 실물 25pt bold / 부제 15pt bold)\n const parts = [generateParagraph((block.text || \"\").trim(), GONGMUN_CENTER, dfIds.pressTitle)]\n for (const s of gongmun.press?.sub ?? []) {\n parts.push(generateParagraph(`- ${s} -`, GONGMUN_CENTER, dfIds.pressSub))\n }\n return parts.join(\"\\n \")\n }\n if (gongmun && blockIdx === ctx.titleBoxH1Idx && tableStyle && bfReg) {\n // 1페이지형 제목박스 (실측 GT2/GT6/GT7) — report/plan/notice 첫 h1.\n // 실측 프리셋은 제목박스 전용 HY헤드라인M 22pt(GJ_CHAR_BODY_TITLE, 실측 GT2 표④)\n return buildTitleBox(\n (block.text || \"\").trim(), measured ? GJ_CHAR_BODY_TITLE : CHAR_H1,\n richAssets ? GJ_CHAR_TITLE_BAR : GONGMUN_TITLE_BAR_CHAR,\n tableStyle.totalWidth, bfReg,\n )\n }\n if (ctx.gaejosik) {\n const lvl = block.level || 1\n if (lvl <= 2) {\n // h1(표지 아님)·h2 → 로마숫자 장 헤더 표 (선행 번호는 로마숫자로 대체).\n // 번호는 장 목록 SSOT(gjChapterIdxs — 목차와 공유)에서 조회 (P1-3)\n const no = ctx.gjChapterIdxs.indexOf(blockIdx)\n ctx.chapterNo = no >= 0 ? no + 1 : ctx.chapterNo + 1\n return buildGaejosikChapter(ctx.chapterNo, stripChapterNumber(block.text || \"\"), gongmun!, gjBodyW, lvl)\n } else if (lvl === 3) {\n // h3 → □ 대항목 (HY헤드라인M 16pt)\n return markedParagraph(\"□\", block.text || \"\", GONGMUN_LIST_BASE, GJ_CHAR_DAE, gongmun!.bodyHeight / 2,\n (id) => (id === CHAR_BOLD ? GJ_CHAR_DAE_BOLD : id))\n }\n // h4~h6 → ○/ㅇ 중항목 (bullet2)\n return markedParagraph(gongmun!.bullet2, block.text || \"\", GONGMUN_LIST_BASE + 1, CHAR_NORMAL, gongmun!.bodyHeight / 2)\n }\n const pId = headingParaPrId(block.level || 1)\n const cId = headingCharPrId(block.level || 1)\n // 공문서 모드: OUTLINE 대신 명명 스타일(\"개요 N\")로 헤딩 의미 보존 —\n // 한글이 개요 번호(\"1.\")를 강제 렌더하는 결함 회피 + 재파싱 헤딩 감지 유지\n const styleId = gongmun ? Math.min(block.level || 1, 4) : 0\n if (gongmun && (block.level || 1) === 2 && gongmun.h2Marker !== \"none\") {\n // h2 섹션 제목 말머리 (QA-2) — OUTLINE 번호 제거의 대체. 실측: □ 대항목(보고서\n // 양식 3종) 기본 / 아라비아 번호(공고문 관행) 옵션. 선행 번호는 제거 후 재부여\n const title = stripChapterNumber(block.text || \"\")\n const mk = gongmun.h2Marker === \"box\" ? \"□\" : `${++ctx.h2Seq}.`\n // 두 자리 번호(\"10.\")는 내어쓰기(\"1.\" 폭 기준)보다 넓어 탭이 다음 기본 탭(40pt)까지 튄다 — 공백으로 잇는다\n if (mk.length > 2) return generateParagraph(`${mk} ${title}`, pId, cId, undefined, styleId)\n return markedParagraph(mk, title, pId, cId, gongmun.bodyHeight / 2, undefined, styleId)\n }\n return generateParagraph(block.text || \"\", pId, cId, undefined, styleId)\n}\n\nfunction renderParagraph(block: MdBlock, blockIdx: number, ctx: SectionCtx): string {\n const { gongmun, measured, fit, vBase } = ctx\n // 이미지 참조 문단 (v4.0.5) — ``만으로 구성된 문단은 placeholder\n // <hp:pic>로 방출해 참조·순서를 왕복 보존. 텍스트 혼재·수용 불가 url은 종전 폴백\n if (ctx.images) {\n const { text: rest, urls } = splitImageRefs(block.text || \"\")\n if (urls.length > 0 && !rest.trim()) {\n const pics = urls.map((u) => {\n const part = ctx.images!.take(u)\n return part ? ctx.images!.inlinePicXml(part) : null\n })\n if (pics.every(Boolean)) {\n return `<hp:p paraPrIDRef=\"${PARA_NORMAL}\" styleIDRef=\"0\"><hp:run charPrIDRef=\"${CHAR_NORMAL}\">${pics.join(\"\")}</hp:run></hp:p>`\n }\n }\n }\n // 실측 프리셋(개조식·보고서·계획서): ※/'* '로 시작하는 문단 → 참고 스타일\n // (한양중고딕 13pt — 실측 t1·t3·실결재 다수가 참고를 *로 표기, v4.1.0 GAP-15)\n const pTrim = (block.text || \"\").trimStart()\n if (measured && (pTrim.startsWith(\"※\") || /^\\*\\s/.test(pTrim))) {\n return refParagraph((block.text || \"\").trim(), ctx)\n }\n // 공문서 모드: <center>…</center> → 가운데 정렬 (행정기관명·발신명의)\n const ctr = gongmun && /^<center>([\\s\\S]*)<\\/center>$/i.exec((block.text || \"\").trim())\n // <right>…</right> → 우측 정렬 (출처행·발신일자 — 실측 GT2/GT6/GT7/GT9 관행)\n const rgt = gongmun && /^<right>([\\s\\S]*)<\\/right>$/i.exec((block.text || \"\").trim())\n if (ctr) return generateParagraph(ctr[1].trim(), GONGMUN_CENTER)\n if (rgt) {\n const t = rgt[1].trim()\n // '출처:'·'자료:' 캡션은 본문-3pt 전용체(실측 한양중고딕/비실측 본문 폰트)로 —\n // 표 아래 출처를 본문과 구분하는 실무 관행. 그 외 <right>(발신일자 등)는 본문 크기 유지.\n const isSrc = /^(출처|자료)\\s*[::]/.test(t)\n const srcChar = ctx.richAssets ? GJ_CHAR_SRC : GONGMUN_SRC_CHAR\n const srcBold = ctx.richAssets ? GJ_CHAR_SRC_BOLD : GONGMUN_SRC_CHAR_BOLD\n const h = isSrc ? srcCaptionPt(gongmun!.bodyHeight) : gongmun!.bodyHeight\n // 본문폭을 넘겨 줄바꿈되는 <right>는 왼쪽 끝이 들쭉날쭉해 들여쓰기가 깨진 듯\n // 보인다(한글 실렌더 QA — 다줄 출처행). 우측 배치 관행은 한 줄일 때만 유지.\n const fits = measureTextWidth(t, h, isSrc ? 100 : GONGMUN_BODY_RATIO) <= ctx.gjBodyW + 0.5\n const paraId = fits ? GONGMUN_RIGHT : GONGMUN_SRC_LEFT\n if (!isSrc) return generateParagraph(t, paraId)\n return generateParagraph(t, paraId, srcChar, (id) => (id === CHAR_BOLD ? srcBold : id))\n }\n return generateParagraph(block.text || \"\", PARA_NORMAL, CHAR_NORMAL, fit ? variantMapper(fit, blockIdx, vBase) : undefined)\n}\n\nfunction renderCodeBlock(block: MdBlock, blockIdx: number, ctx: SectionCtx): string {\n // ```chart 펜스 → 차트 파트 + <hp:chart> (파싱 실패 시 일반 코드블록 폴백)\n if (ctx.chartParts !== null && (block.lang || \"\").toLowerCase() === \"chart\") {\n const fence = parseChartFence(block.text || \"\")\n if (fence) {\n const partName = `Chart/chart${ctx.chartParts.length + 1}.xml`\n ctx.chartParts.push({ name: partName, xml: buildChartSpaceXml(fence) })\n const chartEl = buildChartElementXml(partName, fence.widthHu, fence.heightHu, CHART_TABLE_ID_BASE + blockIdx)\n ctx.opener.emitCarrier(ctx.paraXmls)\n return `<hp:p paraPrIDRef=\"${PARA_NORMAL}\" styleIDRef=\"0\"><hp:run charPrIDRef=\"${CHAR_NORMAL}\">${chartEl}</hp:run></hp:p>`\n }\n }\n const codeLines = (block.text || \"\").split(\"\\n\")\n return codeLines.map(line => generateParagraph(line || \" \", PARA_CODE)).join(\"\\n \")\n}\n\nfunction renderEquation(block: MdBlock, blockIdx: number, ctx: SectionCtx): string {\n ctx.opener.emitCarrier(ctx.paraXmls)\n return generateEquationParagraph(block.text || \"\", blockIdx)\n}\n\nfunction renderBlockquote(block: MdBlock, ctx: SectionCtx): string {\n // 블록 텍스트는 개행 결합(md-runs — 줄 경계 보존). 실측 프리셋은 블록당 ※ 1문단\n // (공백 결합 — 줄마다 ※가 붙는 쪼개짐 방지), 기본 경로는 줄별 문단(종전 시각 유지)\n if (ctx.measured) {\n const t = (block.text || \"\").replace(/\\n+/g, \" \").trim()\n return t ? refParagraph(t, ctx) : \"\"\n }\n // baseline 호환: quoteColor 옵션 없으면 기존처럼 CHAR_NORMAL (이탤릭 아님)\n const quoteChar = ctx.theme.hasQuoteOption ? CHAR_QUOTE : CHAR_NORMAL\n return (block.text || \"\").split(\"\\n\")\n .map((line) => generateParagraph(line, PARA_QUOTE, quoteChar))\n .join(\"\\n \")\n}\n\nfunction renderListItem(block: MdBlock, blockIdx: number, ctx: SectionCtx): string {\n const { gongmun, gongmunList, measured, fit, vBase, dfIds } = ctx\n // 공문서 모드: 항목부호 8단계 + paraPr 단계별 들여쓰기/내어쓰기\n if (gongmun && gongmunList) {\n const info = gongmunList.items.get(blockIdx)\n const depth = info?.depth ?? 0\n const marker = info?.marker ?? \"\"\n const content = block.text || \"\"\n // 실측 프리셋: ※ 시작 항목·'*' 마커 항목은 참고 스타일 (v4.1.0 GAP-15 —\n // 실결재·부처별 양식(t1·t3)에서 참고를 '*'로 표기하는 관행이 ※보다 많음.\n // 공문서 모드에서 '* 항목'은 □ 리스트가 아니라 참고 문단으로 해석)\n if (measured && content.trimStart().startsWith(\"※\")) {\n return refParagraph(content.trim(), ctx)\n }\n if (measured && block.marker === \"*\") {\n return refParagraph(`* ${content.trim()}`, ctx)\n }\n // 부호 + 탭(내어쓰기용 자동 탭) + 내용 (부호 없으면 내용만).\n // 부호 생략 항목은 내어쓰기 없는 전용 paraPr — depth 공용을 쓰면 유령\n // 내어쓰기로 둘째 줄이 첫 줄보다 더 들어간다 (v4.0.2 실렌더 QA)\n // 두 자리 부호('10.')는 자기 부호폭 내어쓰기 전용 paraPr (v4.0.5 P1-1)\n const listParaPr = marker\n ? (info?.indentVariant !== undefined ? GONGMUN_LIST_VARIANT_BASE + info.indentVariant : GONGMUN_LIST_BASE + depth)\n : GONGMUN_LIST_PLAIN_BASE + depth\n // 비실측 보고서(□○-) 모드의 1단계 □ 대제목은 굵게 — 정부 보고서 관행.\n // 실측 프리셋의 □(개조식·보고서 numbering) 1단계는 전용 HY헤드라인M 16pt\n // (실측: 부처별 양식 3종 전부 □=HY헤드라인M. fit 변형 제외 대상이라 매퍼 불필요)\n let listCharPr = gongmun.numbering === \"report\" && depth === 0 ? CHAR_BOLD : CHAR_NORMAL\n let mapId = fit ? variantMapper(fit, blockIdx, vBase) : undefined\n if (measured && depth === 0 && gongmun.numbering !== \"standard\") {\n listCharPr = GJ_CHAR_DAE\n mapId = (id) => (id === CHAR_BOLD ? GJ_CHAR_DAE_BOLD : id)\n }\n if (gongmun.preset === \"press\") {\n // 보도자료 실측: □ 문단은 본문과 동일(plain), 3단계 *는 각주 12pt\n if (depth === 0) listCharPr = CHAR_NORMAL\n if (depth >= 2 && dfIds) { listCharPr = dfIds.small; mapId = undefined }\n }\n // 단계별 위계 타이포(levels, v4.12.3) — 명시 옵션이라 프리셋 실측값보다 우선.\n // fit 변형은 이 depth 를 제외하므로(gen-gongmun-fit) 본문·굵게만 전용 쌍으로 치환\n const lv = ctx.levelIds?.[depth]\n if (lv) {\n listCharPr = lv.normal\n mapId = (id) => (id === CHAR_BOLD ? lv.bold : id === CHAR_NORMAL ? lv.normal : id)\n }\n return marker\n ? markedParagraph(marker, content, listParaPr, listCharPr, gongmun.bodyHeight / 2, mapId)\n : generateParagraph(content, listParaPr, listCharPr, mapId)\n }\n const indent = block.indent || 0\n let marker: string\n if (block.marker) {\n // 원본 마커 보존 — \"2.\" 번호 재시작·\"-\"→\"·\" 기호 변형 방지 (왕복 충실도)\n marker = `${block.marker} `\n ctx.prevWasOrdered = !!block.ordered\n } else if (block.ordered) {\n // 러닝 카운터: indent 레벨별로 증가. 하위 레벨(더 깊은 indent)은 별도 세퀀스.\n ctx.orderedCounters[indent] = (ctx.orderedCounters[indent] || 0) + 1\n // 상위 레벨 번호가 바뀌면 하위는 자동 리셋되어야 함 — 한 레벨 위로 올라갈 때 하위 카운터 초기화\n for (const k of Object.keys(ctx.orderedCounters)) {\n if (+k > indent) delete ctx.orderedCounters[+k]\n }\n marker = `${ctx.orderedCounters[indent]}. `\n ctx.prevWasOrdered = true\n } else {\n marker = \"· \"\n if (ctx.prevWasOrdered) {\n for (const k of Object.keys(ctx.orderedCounters)) delete ctx.orderedCounters[+k]\n }\n ctx.prevWasOrdered = false\n }\n const indentPrefix = \" \".repeat(indent)\n return generateParagraph(indentPrefix + marker + (block.text || \"\"), PARA_LIST)\n}\n\nfunction renderHr(ctx: SectionCtx): string {\n // 수평선 — 공문서 모드는 간격 문단 (실측: 정부 문서에 문자 구분선 0건 — G17),\n // 비공문서(기존)는 긴 대시 유지\n return ctx.gongmun\n ? `<hp:p paraPrIDRef=\"${PARA_NORMAL}\" styleIDRef=\"0\"><hp:run charPrIDRef=\"${CHAR_NORMAL}\"><hp:t></hp:t></hp:run></hp:p>`\n : `<hp:p paraPrIDRef=\"0\" styleIDRef=\"0\"><hp:run charPrIDRef=\"0\"><hp:t>────────────────────────────────────────</hp:t></hp:run></hp:p>`\n}\n\nfunction renderTable(block: MdBlock, ctx: SectionCtx): string {\n if (!block.rows) return \"\"\n // 테이블이 첫 블록이면 빈 단락에 secPr\n ctx.opener.emitCarrier(ctx.paraXmls)\n // 프로필 대응은 takeProfile(행·열+앵커 매칭, 순번은 앵커 없을 때 폴백) —\n // parse 가 방출하지 않는 표(1×1 제목박스 등)가 있어도 서식이 밀리지 않는다.\n return generateTable(block.rows, ctx.theme, ctx.tableStyle, ctx.remap, ctx.tableSeq++, ctx.images)\n}\n\nfunction renderHtmlTable(block: MdBlock, ctx: SectionCtx): string {\n const { tableStyle, bfReg } = ctx\n // 실측 모드(bfReg): 데이터 표 축폭 + 호스트 우측정렬 (TBL-09) — 중첩표는 재귀에서 자체 폭 계산\n const htmlW = tableStyle ? (bfReg ? tableStyle.totalWidth - DATA_TABLE_INSET : tableStyle.totalWidth) : 44000\n const tbl = generateHtmlTableXml(block.text || \"\", ctx.theme, htmlW, tableStyle, ctx.remap, ctx.tableSeq++, ctx.images)\n if (tbl) {\n ctx.opener.emitCarrier(ctx.paraXmls)\n return `<hp:p paraPrIDRef=\"${tableStyle && bfReg ? GONGMUN_RIGHT : 0}\" styleIDRef=\"0\"><hp:run charPrIDRef=\"0\">${tbl}</hp:run></hp:p>`\n }\n // 파싱 불가 — 태그 제거한 텍스트 문단 폴백 (원문 HTML을 그대로 싣지 않음)\n const plain = (block.text || \"\").replace(/<[^>]+>/g, \" \").replace(/\\s+/g, \" \").trim()\n return plain ? generateParagraph(plain) : \"\"\n}\n\n// ─── 본문 뒤 후면부 (공고 결문·끝표시·기안 결문·보도 담당) ─\n\nfunction appendPostamble(blocks: MdBlock[], ctx: SectionCtx): void {\n const { gongmun, dfIds, bfReg, tableStyle, paraXmls } = ctx\n // 공고문 결문 — 날짜·발신명의 우측 (실측: 바이오헬스 공고문)\n if (gongmun?.noticeHead && dfIds) {\n paraXmls.push(...buildNoticeFoot(gongmun))\n }\n // 본문 끝 \"끝.\" 표시 (행정업무규정 — 기안문 기본, 그 외 opt-in). 이미 있으면 중복 방지.\n // 판정 대상은 '마지막 렌더 블록' — 말미가 표면 표 뒤에 \"끝.\"이 와야 하므로,\n // 표 앞 문단의 \"끝.\" 우연 매칭으로 방출이 억제되면 안 된다 (v4.0.5 영역5)\n if (gongmun?.endMark && paraXmls.length > 0) {\n const lastBlock = [...blocks].reverse().find((b) =>\n (b.text || \"\").trim() || (b.type === \"table\" && b.rows?.length))\n const lastText = lastBlock && (lastBlock.type === \"paragraph\" || lastBlock.type === \"list_item\")\n ? lastBlock.text || \"\"\n : \"\"\n if (!hasEndMark(lastText)) paraXmls.push(buildEndMark())\n }\n // 보도자료 담당 표 — 문서 말미\n if (gongmun?.press && dfIds && bfReg && tableStyle) {\n paraXmls.push(...buildPressContact(gongmun, dfIds, tableStyle.totalWidth, bfReg))\n }\n}\n\n// ─── 메인 조립 ───────────────────────────────────────\n\nexport function blocksToSectionXml(\n blocks: MdBlock[],\n theme: ResolvedTheme,\n gongmun: ResolvedGongmun | null,\n gongmunList: GongmunListPlan | null = gongmun ? precomputeGongmunList(blocks, gongmun) : null,\n fit: GongmunFitPlan | null = null,\n chartParts: ChartPart[] | null = null,\n bfReg: TableBfRegistry | null = null,\n remap: ProfileRemap | null = null,\n dfIds: DocframeIds | null = null,\n images: ImageRegistry | null = null,\n page: ResolvedPage | null = null,\n levelIds: LevelCharIds | null = null,\n): string {\n // 문서 생성마다 전역 표 id 카운터 리셋 — 같은 프로세스 연속 생성에도 결정적 출력\n resetTableIds(); resetGjTableIds(); resetExtraTableIds()\n // 실측 폰트 프리셋(개조식·보고서·계획서) — 표 셀 맑은 고딕 12pt·※ 한양중고딕 공유 (QA-1)\n const measured = !!gongmun && usesReportFonts(gongmun.preset)\n const richAssets = !!gongmun && needsGaejosikAssets(gongmun)\n const ctx: SectionCtx = {\n theme, gongmun, gongmunList, fit, chartParts, bfReg, remap, dfIds, images, levelIds,\n gaejosik: gongmun?.preset === \"gaejosik\",\n measured, richAssets,\n vBase: charVariantBase(richAssets, !!gongmun),\n // 공문서 표 스타일 — 본문 폭 맞춤 + 실측 정부 양식(헤더 음영·실측 프리셋 맑은 고딕 12pt)\n // bfReg가 있으면 실측 테두리 위계(외곽 0.4/내부 0.12/헤더 이중선)·셀 문단·우측 배치 적용\n tableStyle: gongmun\n ? {\n totalWidth: mmToHwpunit(210 - gongmun.margins.left - gongmun.margins.right),\n // 표 셀 크기 — 실측: 실측 프리셋 맑은 고딕 12pt(22·23), 비실측도 12pt(11·12,\n // 실결재 지배값 — 본문 크기 셀은 열폭 부족으로 서술 열 세로 신장, v4.0.2 QA)\n charPr: richAssets ? GJ_CHAR_TABLE : GONGMUN_TBL_CHAR,\n boldCharPr: richAssets ? GJ_CHAR_TABLE_BOLD : GONGMUN_TBL_CHAR_BOLD,\n charHeight: richAssets ? gaejosikSizes(gongmun.bodyHeight, gongmun.sizes).table : GONGMUN_TBL_PT,\n headerBf: gongmunTableHeaderBf(richAssets),\n centerParaPr: GONGMUN_CENTER,\n tblCenterParaPr: GONGMUN_TBL_CENTER,\n tblLeftParaPr: GONGMUN_TBL_LEFT,\n bfRegistry: bfReg ?? undefined,\n rightParaPr: GONGMUN_RIGHT,\n }\n : null,\n // 개조식 장식표(표지·목차·장헤더·제목박스) 폭 스케일용 본문폭 — margins 오버라이드 대응\n gjBodyW: gongmun ? mmToHwpunit(210 - gongmun.margins.left - gongmun.margins.right) : GAEJOSIK_BASE_WIDTH,\n chamMap: (id: number) => (id === CHAR_BOLD ? GJ_CHAR_CHAM_BOLD : id),\n opener: new SectionOpener(gongmun, page),\n paraXmls: [],\n // 표 방출 순번 — 생성 성공 여부와 무관하게 '시도' 기준으로 센다. 실패한 표가 이후\n // 표들의 순번을 밀면 앵커 없는 프로필(손편집·구버전)의 table_index 매칭이 어긋난다.\n tableSeq: 0,\n chapterNo: 0,\n h2Seq: 0, // h2 말머리 'number' 모드 아라비아 순번 (QA-2)\n coverH1Idx: -1,\n titleBoxH1Idx: -1,\n pressH1Idx: -1,\n gjChapterIdxs: [],\n pendingPageBreak: false,\n pendingNewNum: false,\n // 순서 있는 목록 카운터 — indent 레벨별 별도 유지. 다른 블록 만나면 해당 레벨 리셋.\n orderedCounters: {},\n prevWasOrdered: false,\n }\n\n buildPreamble(blocks, ctx)\n\n for (let blockIdx = 0; blockIdx < blocks.length; blockIdx++) {\n const block = blocks[blockIdx]\n\n // 순서 있는 list_item이 아니면 카운터 전부 리셋 (연속되지 않은 목록은 다시 1부터)\n if (block.type !== \"list_item\" || !block.ordered) {\n if (ctx.prevWasOrdered) {\n for (const k of Object.keys(ctx.orderedCounters)) delete ctx.orderedCounters[+k]\n }\n ctx.prevWasOrdered = false\n }\n\n let xml = \"\"\n switch (block.type) {\n case \"heading\": xml = renderHeading(block, blockIdx, ctx); break\n case \"paragraph\": xml = renderParagraph(block, blockIdx, ctx); break\n case \"code_block\": xml = renderCodeBlock(block, blockIdx, ctx); break\n case \"equation\": xml = renderEquation(block, blockIdx, ctx); break\n case \"blockquote\": xml = renderBlockquote(block, ctx); break\n case \"list_item\": xml = renderListItem(block, blockIdx, ctx); break\n case \"hr\": xml = renderHr(ctx); break\n case \"table\": xml = renderTable(block, ctx); break\n case \"html_table\": xml = renderHtmlTable(block, ctx); break\n }\n\n if (!xml) continue\n\n // 첫 번째 단락에 secPr 주입 — 표는 전용 캐리어 문단(renderTable)이 담당\n if (ctx.opener.isFirst && block.type !== \"table\") {\n xml = ctx.opener.inject(xml)\n }\n\n // 개조식 전면부(표지·목차) 뒤 본문 첫 블록은 새 페이지에서\n if (ctx.pendingPageBreak) {\n xml = xml.replace(/^<hp:p /, `<hp:p pageBreak=\"1\" `)\n ctx.pendingPageBreak = false\n }\n\n // 본문 첫 블록에서 쪽번호 1 재시작 — 표지·목차를 카운트에서 제외 (실측 GT3 newNum)\n if (ctx.pendingNewNum) {\n xml = xml.replace(/<hp:run charPrIDRef=\"(\\d+)\">/, `<hp:run charPrIDRef=\"$1\">${newPageNumCtrl(1)}`)\n ctx.pendingNewNum = false\n }\n\n ctx.paraXmls.push(xml)\n }\n\n appendPostamble(blocks, ctx)\n\n // 블록이 없으면 빈 단락\n if (ctx.paraXmls.length === 0) {\n ctx.paraXmls.push(ctx.opener.emptyDoc())\n }\n\n return `<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>\n<hs:sec xmlns:hs=\"${NS_SECTION}\" xmlns:hp=\"${NS_PARA}\">\n ${ctx.paraXmls.join(\"\\n \")}\n</hs:sec>`\n}\n","/**\n * 항목부호 단계별 위계 타이포(levels 옵션, v4.12.3) — 단계 전용 charPr·fontface 계획.\n *\n * 실측 근거(docs/gongmunseo-reference.md 2.7): 실결재 기안문의 □/ㅇ/- 계열은 □=HY견고딕\n * +2~3pt bold, ㅇ=한컴돋움 bold, -=휴먼명조 본문이 지배 관행이지만 법정 8단계(1. 가. 1))는\n * 본문과 동일이 90%다. 그래서 기본값은 손대지 않고, 지정한 단계만 전용 charPr 한 쌍\n * (보통·굵게)을 docframe charPr 뒤 id 에 방출한다. 글꼴은 정적 fontface 뒤에 append 하고\n * 한글·라틴만 참조(그 외 언어는 본문 글꼴) — 비실측 프리셋의 HANJA 이하 1종 언어 테이블에\n * 없는 id 를 가리키지 않는다(프로필 append 글꼴과 같은 규약).\n */\n\nimport { charPr, GONGMUN_BODY_RATIO } from \"./gen-ids.js\"\nimport type { ResolvedGongmun } from \"./gongmun.js\"\n\n/** depth → 전용 charPr id (보통·굵게) */\nexport type LevelCharIds = Record<number, { normal: number; bold: number }>\n\n/** levels 가 지정된 depth 오름차순 목록 */\nexport function levelDepths(g: ResolvedGongmun): number[] {\n return g.levels ? Object.keys(g.levels).map(Number).sort((a, b) => a - b) : []\n}\n\n/** append 할 글꼴명(중복 제거, depth 순) — fontface id = fontBase + 인덱스 */\nexport function levelFontFaces(g: ResolvedGongmun): string[] {\n const out: string[] = []\n for (const d of levelDepths(g)) {\n const f = g.levels![d].font\n if (f && !out.includes(f)) out.push(f)\n }\n return out\n}\n\n/** depth → charPr id 배정 — base 부터 depth 순으로 2개씩 */\nexport function levelCharIds(g: ResolvedGongmun, base: number): LevelCharIds | null {\n const depths = levelDepths(g)\n if (depths.length === 0) return null\n const ids: LevelCharIds = {}\n depths.forEach((d, i) => { ids[d] = { normal: base + i * 2, bold: base + i * 2 + 1 } })\n return ids\n}\n\n/**\n * 단계 전용 charPr XML — levelCharIds 와 같은 순서. bodyFontId 는 본문 글꼴(비실측 0·rich 4),\n * fontBase 는 append 글꼴 첫 id. 장평은 본문 항목과 같은 95%(bold 만 바꿔도 줄 길이 불변).\n */\nexport function levelCharPrXmls(g: ResolvedGongmun, base: number, fontBase: number, bodyFontId: number): string[] {\n const ids = levelCharIds(g, base)\n if (!ids) return []\n const faces = levelFontFaces(g)\n const out: string[] = []\n for (const d of levelDepths(g)) {\n const st = g.levels![d]\n const fontId = st.font ? fontBase + faces.indexOf(st.font) : bodyFontId\n // 굵기 오버라이드가 없는 단계도 인라인 **강조** 용 bold 짝을 낸다\n // 나머지 언어 슬롯도 단계 글꼴 — 7슬롯 동일해야 한컴 툴바 글꼴명 표시(전 언어 목록 동일)\n out.push(charPr(ids[d].normal, st.height, st.bold, false, fontId, undefined, GONGMUN_BODY_RATIO, fontId))\n out.push(charPr(ids[d].bold, st.height, true, false, fontId, undefined, GONGMUN_BODY_RATIO, fontId))\n }\n return out\n}\n","/**\n * 생성용 charPr/paraPr/글꼴 동적 레지스트리 (v5).\n *\n * 종전에는 charPr·paraPr id를 모듈마다 손계산(정적 블록 + variant×4 + 프로필 + docframe +\n * levels …)으로 이어 써서 한 칸 밀리면 무음 서식 오염이 났다(P0-1). 여기서는 필요한\n * 스타일을 스펙으로 요청하면 같은 스펙은 같은 id를 돌려주고, header.xml 조립 때 방출\n * 순서 = id 순서로 일괄 붙인다. 시작 id는 호출자가 정적 블록 크기에서 넘긴다.\n */\n\nimport { charPr as charPrXml, paraPr as paraPrXml, CHAR_NORMAL, CHAR_BOLD, CHAR_ITALIC, CHAR_BOLD_ITALIC } from \"./gen-ids.js\"\n\nexport interface CharSpec {\n font: string\n pt: number\n bold?: boolean\n italic?: boolean\n /** 장평 % (기본 100) */\n ratio?: number\n /** 자간 % (기본 0) */\n spacing?: number\n color?: string\n}\n\nexport interface ParaSpec {\n align?: \"LEFT\" | \"CENTER\" | \"RIGHT\" | \"JUSTIFY\" | \"DISTRIBUTE\"\n left?: number\n /** 오른쪽 여백(HWPUNIT) — 요약박스 등 셀 안 문단 좌우 여백 */\n right?: number\n indent?: number\n before?: number\n after?: number\n lineSp?: number\n keepWithNext?: boolean\n /** 어절 단위 줄바꿈(공문서 기본 true) */\n keepWord?: boolean\n /** 내어쓰기용 자동 탭(tabPr 1) — 부호 뒤 탭이 내어쓰기 위치에 선다 */\n autoTab?: boolean\n /** 외톨이줄 보호 — 문단 첫·끝 줄이 쪽 끝·머리에 홀로 남지 않게 */\n widowOrphan?: boolean\n}\n\nexport class StyleRegistry {\n private chars = new Map<string, number>()\n private charXmls: string[] = []\n private paras = new Map<string, number>()\n private paraXmls: string[] = []\n private fonts = new Map<string, number>()\n private fontList: string[] = []\n\n /**\n * @param charBase 첫 charPr id (정적 charPr 블록 다음)\n * @param paraBase 첫 paraPr id\n * @param fontBase 첫 append 글꼴 id (정적 fontface 다음 — HANGUL·LATIN에만 append)\n * @param staticFonts 정적 fontface 목록 (id 순) — 같은 이름이면 정적 id 재사용\n */\n constructor(private charBase: number, private paraBase: number, private fontBase: number, staticFonts: string[] = []) {\n staticFonts.forEach((f, i) => { if (!this.fonts.has(f)) this.fonts.set(f, i) })\n }\n\n font(face: string): number {\n const hit = this.fonts.get(face)\n if (hit !== undefined) return hit\n const id = this.fontBase + this.fontList.length\n this.fonts.set(face, id)\n this.fontList.push(face)\n return id\n }\n\n char(spec: CharSpec): number {\n const key = `${spec.font}|${spec.pt}|${spec.bold ? 1 : 0}|${spec.italic ? 1 : 0}|${spec.ratio ?? 100}|${spec.spacing ?? 0}|${spec.color ?? \"#000000\"}`\n const hit = this.chars.get(key)\n if (hit !== undefined) return hit\n const id = this.charBase + this.charXmls.length\n const fontId = this.font(spec.font)\n // 한글·라틴만 지정 글꼴, 그 외 언어는 0 (HANJA 이하 fontface는 1종만 있어 append id가 없다)\n // 나머지 언어 슬롯도 같은 글꼴 — 7슬롯이 같아야 한컴 툴바가 글꼴명을 보여준다(전 언어 목록 동일, gen-header)\n this.charXmls.push(charPrXml(id, Math.round(spec.pt * 100), !!spec.bold, !!spec.italic, fontId, spec.color ?? \"#000000\", spec.ratio ?? 100, fontId, spec.spacing ?? 0))\n this.chars.set(key, id)\n return id\n }\n\n para(spec: ParaSpec): number {\n const key = `${spec.align ?? \"JUSTIFY\"}|${spec.left ?? 0}|${spec.right ?? 0}|${spec.indent ?? 0}|${spec.before ?? 0}|${spec.after ?? 0}|${spec.lineSp ?? 160}|${spec.keepWithNext ? 1 : 0}|${spec.keepWord === false ? 0 : 1}|${spec.autoTab ? 1 : 0}|${spec.widowOrphan ? 1 : 0}`\n const hit = this.paras.get(key)\n if (hit !== undefined) return hit\n const id = this.paraBase + this.paraXmls.length\n this.paraXmls.push(paraPrXml(id, {\n align: spec.align ?? \"JUSTIFY\", left: spec.left ?? 0, right: spec.right ?? 0, indent: spec.indent ?? 0,\n spaceBefore: spec.before ?? 0, spaceAfter: spec.after ?? 0, lineSpacing: spec.lineSp ?? 160,\n keepWithNext: !!spec.keepWithNext, keepWord: spec.keepWord !== false, autoTab: !!spec.autoTab, widowOrphan: !!spec.widowOrphan,\n }))\n this.paras.set(key, id)\n return id\n }\n\n get charPrXmls(): string[] { return this.charXmls }\n get paraPrXmls(): string[] { return this.paraXmls }\n /** append 글꼴(정적 목록 제외) — fontBase부터 순서대로 */\n get extraFonts(): string[] { return this.fontList }\n}\n\n/**\n * 인라인 **굵게**·*기울임* → 레지스트리 변형 매핑 — md-runs 가 정적 id(CHAR_BOLD…)로 낸 run 을\n * 문단 기본 스펙(글꼴·크기·장평·자간)의 변형으로 바꾼다. emphasisColor 를 주면 굵게가 그 색이 된다\n * (업무보고 항목 띠: 강조 = 파랑, 굵기는 글꼴이 이미 굵어 그대로).\n */\nexport function inlineMapper(reg: StyleRegistry, base: { font: string; pt: number; bold: boolean; ratio?: number; spacing?: number; color?: string }, emphasisColor?: string): (id: number) => number {\n const norm = reg.char({ font: base.font, pt: base.pt, bold: base.bold, ratio: base.ratio, spacing: base.spacing, color: base.color })\n const emColor = emphasisColor ?? base.color\n return (id) => {\n if (id === CHAR_BOLD) return reg.char({ font: base.font, pt: base.pt, bold: true, ratio: base.ratio, spacing: base.spacing, color: emColor })\n if (id === CHAR_ITALIC) return reg.char({ font: base.font, pt: base.pt, bold: base.bold, italic: true, ratio: base.ratio, spacing: base.spacing, color: base.color })\n if (id === CHAR_BOLD_ITALIC) return reg.char({ font: base.font, pt: base.pt, bold: true, italic: true, ratio: base.ratio, spacing: base.spacing, color: emColor })\n if (id === CHAR_NORMAL) return norm\n return id\n }\n}\n","/**\n * 공문서 위계 스킴 SSOT (v5, 2026-09-06) — 항목 단계별 부호·글꼴·크기·굵기·선행 타·줄간격.\n *\n * 실측 근거: 서울 정보소통광장 결재문서본문 코퍼스(bench/corpus seoul·seoul2·seoul-old·\n * gate-fill·gate-fill3·review + corpus-gen/opengov-2609, 629건 분류) 전수 디코드 — docs/gongmunseo-reference.md 2.8.\n *\n * 법정형(기안문 본문, 484건): 굴림체 12pt 160% / 1. 0타 · 가. 2타(70%) · 1) 4타 …(2타 계단)\n * 개조식형(보고서·계획서·개조식 기안문, 145건):\n * □ HY견고딕 17 bold 0타 (한 줄 95%) · ㅇ 한컴돋움 15 bold 1타(66%) · - 휴먼명조 14 3타(53%)\n * ㆍ 휴먼명조 14 4타 · ※ 한컴돋움 14 · 소제목(가.) 한컴돋움 13 · 표 한컴돋움 12 헤더 #DFE6F7\n *\n * \"타\" = 반각 1자 = 그 단계 글자 크기의 절반(HWPUNIT = pt×50). 내어쓰기(둘째 줄 정렬)는\n * 부호 실폭 + 1타 — 편람 규정. 실결재는 선행 공백으로 들여쓰지만 시각 결과는 동일하다.\n *\n * 이 모듈은 순수 값/함수만 담는다. XML 조립은 gen-gongmun.ts.\n */\n\nimport type { GongmunOptions, ResolvedGongmun } from \"./gongmun.js\"\nimport { markerWidth, standardMarker } from \"./gongmun.js\"\n\nexport type SchemeKind = \"legal\" | \"gaejosik\"\n\n/** 한 단계(또는 역할)의 타이포 */\nexport interface LevelStyle {\n font: string\n pt: number\n bold: boolean\n /** 선행 들여쓰기(타) — 부호가 시작하는 위치. 1타 = pt×50 HWPUNIT */\n leadTa: number\n /** 줄간격(%) — 미지정이면 문서 기본 */\n lineSp?: number\n /** 한 줄 강제(□·제목류) — 넘치면 장평→자간→pt 축소 */\n oneLine?: boolean\n /** 다음 문단과 같은 쪽 (쪽 하단 고아 표제 방지) */\n keepWithNext?: boolean\n /** 앞에 빈 줄 한 줄(실결재 □ 74%) */\n blankBefore?: boolean\n}\n\nexport interface TableStyleSpec {\n font: string\n pt: number\n headerFill: string\n labelFill: string\n}\n\nexport interface FrameSpec {\n /** 두문·결문·결재선·제목표 공통 글꼴 */\n font: string\n /** 보고서 제목표 제목 글꼴/크기 */\n titleFont: string\n titlePt: number\n /** 보고서 담당자 연락처 행 */\n contactFont: string\n contactPt: number\n /** 요약 박스 */\n summaryFont: string\n summaryPt: number\n summaryFill: string\n}\n\nexport interface Scheme {\n kind: SchemeKind\n /** 본문(서술 문단) 기본 */\n body: LevelStyle\n /** 항목 단계 0~7 */\n levels: LevelStyle[]\n /** ※ 참고 */\n ref: LevelStyle\n /** 개조식 문서 안의 법정 부호 소제목(가. 기술인력) — legal 스킴은 levels가 담당 */\n sub: LevelStyle\n /** 붙임 */\n attach: LevelStyle\n /** 장 제목(h2) — \"Ⅰ. 제목\" */\n chapter: LevelStyle\n /** 문서 기본 줄간격(%) */\n lineSp: number\n /** 마커 문자열 (depth, 형제순번) */\n marker: (depth: number, n: number) => string\n table: TableStyleSpec\n frame: FrameSpec\n /** 최상위 항목(1.) 사이 빈 줄 — 법정형 실측 27%라 기본 false */\n blankBetweenTop: boolean\n}\n\nexport const SEOUL_FRAME: FrameSpec = {\n font: \"굴림체\",\n titleFont: \"HY헤드라인M\", titlePt: 25,\n contactFont: \"휴먼명조\", contactPt: 12,\n summaryFont: \"한컴돋움\", summaryPt: 15, summaryFill: \"#DFE6F7\",\n}\n\nexport const SEOUL_TABLE: TableStyleSpec = { font: \"한컴돋움\", pt: 12, headerFill: \"#DFE6F7\", labelFill: \"#F2F2F2\" }\n\n/** 개조식 부호 — bullet2로 2단계 ㅇ/○ 전환 */\nexport function gaejosikMarkerOf(bullet2: \"ㅇ\" | \"○\"): Scheme[\"marker\"] {\n return (depth) => (depth === 0 ? \"□\" : depth === 1 ? bullet2 : depth === 2 ? \"-\" : \"ㆍ\")\n}\n\n/**\n * 서울 실측 개조식 스킴. bodyPt는 ㅇ(중항목) 크기 기준(실측 15) — 다른 단계는 실측 차이만큼 이동.\n */\nexport function seoulGaejosikScheme(bodyPt = 15, lineSp = 180, bullet2: \"ㅇ\" | \"○\" = \"ㅇ\"): Scheme {\n const d = bodyPt - 15\n const lv = (font: string, pt: number, bold: boolean, leadTa: number, extra: Partial<LevelStyle> = {}): LevelStyle =>\n ({ font, pt: pt + d, bold, leadTa, ...extra })\n return {\n kind: \"gaejosik\",\n lineSp,\n body: lv(\"한컴돋움\", 15, false, 0),\n levels: [\n lv(\"HY견고딕\", 17, true, 0, { oneLine: true, keepWithNext: true, blankBefore: true }),\n lv(\"한컴돋움\", 15, true, 1),\n lv(\"휴먼명조\", 14, false, 3),\n lv(\"휴먼명조\", 14, false, 4),\n lv(\"휴먼명조\", 14, false, 5),\n lv(\"휴먼명조\", 14, false, 6),\n lv(\"휴먼명조\", 14, false, 7),\n lv(\"휴먼명조\", 14, false, 8),\n ],\n // ※·출처는 본문보다 작게(실측 14~15 혼재, 실무자 요청으로 13 — 한 단계 아래로 확실히 구분)\n ref: lv(\"한컴돋움\", 13, false, 0),\n sub: lv(\"한컴돋움\", 13, false, 2),\n attach: lv(\"한컴돋움\", 15, false, 0),\n chapter: lv(\"HY헤드라인M\", 20, false, 0, { oneLine: true, keepWithNext: true }),\n marker: gaejosikMarkerOf(bullet2),\n table: { ...SEOUL_TABLE, pt: SEOUL_TABLE.pt + d },\n frame: SEOUL_FRAME,\n blankBetweenTop: false,\n }\n}\n\n/**\n * 중앙부처 업무보고 스킴 — 재경부 「2차 업무보고 서면보고자료」(2026-07-15, 17쪽) PDF 전수 실측\n * (docs/gongmunseo-engine-spec.md (j)장):\n * □·ㅇ·- 함초롬바탕 15 regular(강조만 bold, □ 뒤 괄호 키워드 bold #0000FF) · 줄피치 21.7pt ≈ 145%\n * ㅇ 1타(둘째 줄 x86.6 = 30pt) · - 3타(둘째 줄 x95.5) · * 각주 맑은 고딕 12 · 표 맑은 고딕 12/11.5 헤더 #DFE6F7\n * 장 띠 HY헤드라인M 16 · 절 숫자칸/소제목 박스 HY헤드라인M 15 · ① 항목 띠 HY중고딕 15(원본 HaanYGodic24)\n * 요약박스 #FFF7CC 함초롬바탕 13 · 표지 HY헤드라인M 32 / 날짜 24\n * 서울 개조식(HY견고딕 17 bold □)과 달리 부호 단계의 글꼴·크기가 전부 같고 색으로 위계를 낸다.\n */\nexport const MINISTRY_FRAME: FrameSpec = {\n font: \"함초롬바탕\",\n titleFont: \"HY헤드라인M\", titlePt: 32,\n contactFont: \"함초롬바탕\", contactPt: 12,\n summaryFont: \"함초롬바탕\", summaryPt: 13, summaryFill: \"#FFF7CC\",\n}\n\nexport function ministryScheme(bodyPt = 15, lineSp = 145): Scheme {\n const d = bodyPt - 15\n const lv = (font: string, pt: number, bold: boolean, leadTa: number, extra: Partial<LevelStyle> = {}): LevelStyle =>\n ({ font, pt: pt + d, bold, leadTa, ...extra })\n return {\n kind: \"gaejosik\",\n lineSp,\n body: lv(\"함초롬바탕\", 15, false, 0),\n levels: [\n // □ 는 한 줄 강제 안 함 — 실측 □ 문장의 절반이 두 줄(pg3·pg6). 앞 빈 줄은 스킴 공통 로직(BOX_BLANK_HU)\n lv(\"함초롬바탕\", 15, false, 0, { keepWithNext: true, blankBefore: true }),\n lv(\"함초롬바탕\", 15, false, 1),\n lv(\"함초롬바탕\", 15, false, 3),\n lv(\"함초롬바탕\", 15, false, 4),\n lv(\"함초롬바탕\", 15, false, 5),\n lv(\"함초롬바탕\", 15, false, 6),\n lv(\"함초롬바탕\", 15, false, 7),\n lv(\"함초롬바탕\", 15, false, 8),\n ],\n // * 각주 — 맑은 고딕 12(n=124), 선두 4칸 공백 ≈ ㅇ 본문 시작(x80)에 맞춘다\n ref: lv(\"맑은 고딕\", 12, false, 3),\n sub: lv(\"함초롬바탕\", 15, false, 2),\n attach: lv(\"함초롬바탕\", 15, false, 0),\n chapter: lv(\"HY헤드라인M\", 16, false, 0, { oneLine: true, keepWithNext: true }),\n marker: (depth) => (depth === 0 ? \"□\" : depth === 1 ? \"ㅇ\" : depth === 2 ? \"-\" : \"ㆍ\"),\n table: { font: \"맑은 고딕\", pt: 12 + d, headerFill: \"#DFE6F7\", labelFill: \"#F2F2F2\" },\n frame: MINISTRY_FRAME,\n blankBetweenTop: false,\n }\n}\n\n/** 서울 실측 법정형(기안문 본문) 스킴 — 전 단계 본문 글꼴·크기 동일, 2타 계단 */\nexport function seoulLegalScheme(bodyFont = \"굴림체\", bodyPt = 12, lineSp = 160): Scheme {\n const lv = (leadTa: number, extra: Partial<LevelStyle> = {}): LevelStyle => ({ font: bodyFont, pt: bodyPt, bold: false, leadTa, ...extra })\n return {\n kind: \"legal\",\n lineSp,\n body: lv(0),\n levels: [0, 2, 4, 6, 8, 10, 12, 14].map((t) => lv(t)),\n ref: lv(0),\n sub: lv(2),\n attach: lv(0),\n chapter: { font: bodyFont, pt: bodyPt + 2, bold: true, leadTa: 0, keepWithNext: true },\n marker: (depth, n) => standardMarker(depth, n),\n table: { ...SEOUL_TABLE, pt: Math.min(SEOUL_TABLE.pt, bodyPt) },\n frame: SEOUL_FRAME,\n blankBetweenTop: false,\n }\n}\n\n/** 옵션(levels·fonts) 오버레이 — 지정한 단계·역할만 바꾼다 */\nexport function applySchemeOverrides(s: Scheme, g: ResolvedGongmun): Scheme {\n const out: Scheme = { ...s, levels: s.levels.map((l) => ({ ...l })), body: { ...s.body }, ref: { ...s.ref }, table: { ...s.table } }\n if (g.fonts.heading) { out.levels[0].font = g.fonts.heading; out.chapter = { ...out.chapter, font: g.fonts.heading } }\n if (g.fonts.body) { out.body.font = g.fonts.body; if (s.kind === \"legal\") for (const l of out.levels) l.font = g.fonts.body; else out.levels[1].font = g.fonts.body }\n if (g.fonts.ref) out.ref.font = g.fonts.ref\n if (g.fonts.table) out.table.font = g.fonts.table\n if (g.levels) {\n for (const [k, st] of Object.entries(g.levels)) {\n const l = out.levels[Number(k)]\n if (!l) continue\n if (st.font) l.font = st.font\n // pt 미지정(resolveLevels 가 프리셋 bodyHeight 로 채움)이면 스킴 단계 크기 유지 — 프리셋 bodyPt(통지 15)와\n // v5 스킴 기본(법정 12)이 다를 때 15pt 로 튀지 않게\n if (st.height !== g.bodyHeight) l.pt = st.height / 100\n l.bold = st.bold\n }\n }\n return out\n}\n\n/** 1타(HWPUNIT) — 그 글자 크기의 반각 */\nexport function taHu(pt: number): number { return Math.round(pt * 50) }\n\n/** 단계 들여쓰기 — left(부호 시작), indent(음수 내어쓰기 = 부호폭+1타) */\nexport function levelGeometry(style: LevelStyle, marker: string): { left: number; indent: number } {\n const left = style.leadTa * taHu(style.pt)\n const indent = marker ? -markerWidth(marker, style.pt * 100) : 0\n return { left, indent }\n}\n\n/** 스킴 선택 — 옵션·프리셋·본문 부호 자동감지 */\nexport function pickScheme(g: ResolvedGongmun, bodyHasBoxMarkers: boolean): Scheme {\n if (g.preset === \"ministry\") {\n return applySchemeOverrides(ministryScheme(g.bodyPtExplicit ? g.bodyHeight / 100 : 15, g.lineSpacingExplicit ? g.lineSpacing : 145), g)\n }\n const gaejosik = g.numbering !== \"standard\" || bodyHasBoxMarkers\n const base = gaejosik\n ? seoulGaejosikScheme(g.bodyPtExplicit ? g.bodyHeight / 100 : 15, g.lineSpacingExplicit ? g.lineSpacing : 180, g.bullet2)\n : seoulLegalScheme(g.fonts.body ?? (g.bodyFontExplicit ? (g.bodyFont === \"gothic\" ? \"맑은 고딕\" : \"함초롬바탕\") : \"굴림체\"), g.bodyPtExplicit ? g.bodyHeight / 100 : 12, g.lineSpacingExplicit ? g.lineSpacing : 160)\n return applySchemeOverrides(base, g)\n}\n\n/** 옵션 타입 재수출(순환 import 회피용 얇은 별칭) */\nexport type { GongmunOptions }\n","/**\n * 마크다운 블록 → 공문서 의미 아웃라인 (v5).\n *\n * 입력이 #/##/###·리스트 깊이·명시 부호(□ ㅇ - ㆍ ※ 1. 가.) 어느 꼴이든 하나의 depth로\n * 정규화한다 — 같은 내용이면 같은 결과. 규칙:\n * - 첫 h1 → 제목. h2 → 장(chapter). h3~h6 → 항목 depth (level-3).\n * - 리스트 항목 depth = (현재 장 안의 마지막 h3+ 항목 depth + 1) + 리스트 들여쓰기.\n * h3+가 없으면 리스트 들여쓰기 그대로 (□부터).\n * - 문단·항목 선두의 명시 부호는 depth를 강제한다(□0 ㅇ○1 -2 ㆍ3 / 1.→0 가.→1 1)→2 …).\n * 개조식 스킴에서 법정 부호는 \"소제목(sub)\"으로 남긴다(실측: ○ 아래 '가. 기술인력' 한컴돋움 13).\n * - ※·'* ' 선두 → 참고(ref). 붙임 → attach. 제목 직후 인용문 → 요약 박스(summary), 그 외 인용 → ref.\n * - <center>/<right> 문단은 정렬만 붙여 para.\n */\n\nimport type { MdBlock } from \"./md-runs.js\"\nimport { stripChapterNumber } from \"./gaejosik.js\"\n\nexport type OutlineNode =\n | { kind: \"title\"; text: string }\n | { kind: \"chapter\"; text: string; index: number }\n | { kind: \"item\"; depth: number; text: string; /** 명시 법정 부호(개조식 문서 안 소제목) */ legalMarker?: string; /** 헤딩(h3+)에서 온 항목 — 사이 문단이 번호를 끊지 않는다 */ fromHeading?: boolean; /** 보존할 선두 부호(❶➊⇒↳ — 업무보고 9대 과제·결론 줄) */ marker?: string }\n /** h3~h6 헤딩을 항목이 아니라 서식 틀(절 띠·소제목 박스·항목 띠)로 남긴 것 — headingFrames 옵션 */\n | { kind: \"heading\"; level: number; text: string }\n | { kind: \"ref\"; depth: number; text: string }\n | { kind: \"para\"; depth: number; text: string; align?: \"CENTER\" | \"RIGHT\" }\n | { kind: \"attach\"; text: string }\n | { kind: \"summary\"; text: string }\n | { kind: \"block\"; depth: number; block: MdBlock }\n\n// 부호 → 단계. ❑❏ㅁ(0)·◎(1)·ㅡ‣▪▫(2)는 실무 문서(교육청·학교 결재문)에 섞여 쓰이는 변형 —\n// 영문 `o`/`O`/`0`은 영문 문장 선두 오탐이라 넣지 않는다 (v4.13.0)\nconst BOX_MARKERS: Record<string, number> = {\n \"□\": 0, \"■\": 0, \"❑\": 0, \"❏\": 0, \"ㅁ\": 0,\n \"○\": 1, \"ㅇ\": 1, \"◦\": 1, \"●\": 1, \"❍\": 1, \"◎\": 1,\n \"-\": 2, \"–\": 2, \"―\": 2, \"—\": 2, \"ㅡ\": 2, \"‣\": 2, \"▪\": 2, \"▫\": 2,\n \"ㆍ\": 3, \"·\": 3, \"•\": 3, \"∙\": 3,\n}\nconst LEGAL_RE = /^(\\d{1,2}\\.|[가-힣]\\.|\\d{1,2}\\)|[가-힣]\\)|\\(\\d{1,2}\\)|\\([가-힣]\\)|[①-⑳]|[㉮-㉻])\\s+/u\n/**\n * 부호를 그대로 남기는 선두 글리프 — 중앙부처 업무보고 실측: 9대 과제 ❶~❿(U+2776~)·➊~➓(U+278A~) 0단계,\n * ⇒ 결론 0단계, ↳ 부연 1단계. 스킴 marker 로 바꾸지 않고 depth 만 강제한다(keepMarkers 옵션).\n */\nconst KEEP_MARKERS: Record<string, number> = { \"⇒\": 0, \"↳\": 1, \"☞\": 0 }\nconst KEEP_RE = /^([❶-❿➊-➓⇒↳☞])\\s*/u\nconst BOX_RE = /^([□■❑❏ㅁ○ㅇ◦●❍◎\\-–―—ㅡ‣▪▫ㆍ·•∙])\\s+/u\n/** ※·* 선두, 또는 '* ' (별표 뒤 공백). `**굵게**:` 로 시작하는 항목의 `**` 는 참고 부호가 아니다 */\nconst REF_RE = /^(※|*|\\*(?=\\s))\\s*/u\nconst BUNIM_RE = /^붙\\s*임(?:\\s|:|$)/\n/** 출처·자료·근거 표기 항목 — 본문 항목이 아니라 ※ 참고(작은 글씨)로 */\nconst SOURCE_RE = /^(출처|자료|근거|참고)\\s*[::]/\n/** 법령 인용 뒤 붙는 법제처 MST·ID 코드 \"(282791)\" — 공문에 쓰지 않는 내부 식별자라 벗긴다 */\nconst LAW_CODE_RE = /((?:법률|기본법|특별법|법|령|규칙|조례|규정|고시|훈령|예규|지침)[」』]?)\\s*\\((\\d{5,8})\\)/gu\n\n/**\n * 공문에 남으면 안 되는 내부 식별자·도구 흔적: 법령 코드 \"(282791)\", KOSIS 표 ID \"DT_1YL21161\",\n * \"(법정동코드 11215-10700)\", \"…, 통계 MCP 조회\"류 도구 언급. 출처는 기관·자료명만 남긴다.\n */\nexport function stripLawCodes(text: string): string {\n return text\n .replace(LAW_CODE_RE, \"$1\")\n .replace(/[,,]?\\s*\\(?\\bDT_[A-Z0-9_]+\\)?/g, \"\")\n .replace(/\\s*\\((?:법정동|행정동|시군구|지역)?\\s*코드\\s*[\\d-]+\\)/g, \"\")\n .replace(/[,,]?\\s*[가-힣A-Za-z·]*\\s*MCP\\s*(?:조회|호출|응답)?/g, \"\")\n .replace(/\\s+([,,.])/g, \"$1\")\n .replace(/[,,]\\s*$/g, \"\")\n .replace(/ {2,}/g, \" \")\n .trim()\n}\n\nexport function legalMarkerDepth(marker: string): number {\n if (/^\\d{1,2}\\.$/.test(marker)) return 0\n if (/^[가-힣]\\.$/.test(marker)) return 1\n if (/^\\d{1,2}\\)$/.test(marker)) return 2\n if (/^[가-힣]\\)$/.test(marker)) return 3\n if (/^\\(\\d{1,2}\\)$/.test(marker)) return 4\n if (/^\\([가-힣]\\)$/.test(marker)) return 5\n if (/^[①-⑳]$/u.test(marker)) return 6\n return 7\n}\n\n/** 선두 명시 부호 해석 — {kind, depth, marker, rest}. keep = ❶⇒↳ 등 글리프 보존 부호(keepMarkers 옵션일 때만) */\nexport function parseLeadingMarker(text: string, keepMarkers = false): { kind: \"box\" | \"legal\" | \"ref\" | \"keep\" | null; depth: number; marker: string; rest: string } {\n const t = text.replace(/^[\\s ]+/, \"\")\n const ref = REF_RE.exec(t)\n if (ref) return { kind: \"ref\", depth: 0, marker: ref[1], rest: t.slice(ref[0].length).trim() }\n if (keepMarkers) {\n const keep = KEEP_RE.exec(t)\n if (keep) return { kind: \"keep\", depth: KEEP_MARKERS[keep[1]] ?? 0, marker: keep[1], rest: t.slice(keep[0].length).trim() }\n }\n const box = BOX_RE.exec(t)\n if (box) return { kind: \"box\", depth: BOX_MARKERS[box[1]] ?? 3, marker: box[1], rest: t.slice(box[0].length).trim() }\n const legal = LEGAL_RE.exec(t)\n if (legal) return { kind: \"legal\", depth: legalMarkerDepth(legal[1]), marker: legal[1], rest: t.slice(legal[0].length).trim() }\n return { kind: null, depth: 0, marker: \"\", rest: t }\n}\n\nexport interface OutlineOptions {\n /** 개조식 스킴이면 명시 법정 부호를 소제목으로 보존, 법정 스킴이면 항목으로 재부호 */\n gaejosik: boolean\n /** 제목(h1)을 아웃라인에서 소비할지 — 기안문은 두문 제목으로 쓴다 */\n consumeTitle: boolean\n /** 제목 직후 인용문을 요약 박스로 (보고서형) */\n summaryFromQuote: boolean\n /** 인용문을 위치와 무관하게 전부 요약 박스로 (업무보고형 — 장·절마다 성과 요약 박스) */\n quoteBox?: boolean\n /** h3~h6 을 항목이 아니라 heading 노드로 남기고 리스트 깊이에도 영향을 주지 않는다 (업무보고형 절·소제목·항목 띠) */\n headingFrames?: boolean\n /** ❶➊⇒↳ 선두 글리프를 보존한 항목으로 (업무보고형) */\n keepMarkers?: boolean\n}\n\nexport interface Outline {\n title: string | null\n nodes: OutlineNode[]\n /** 본문에 □/ㅇ 명시 부호가 있었는지 — 기안문 개조식형 자동감지 */\n hasBoxMarkers: boolean\n /** 장(h2) 수 */\n chapters: number\n}\n\nexport function buildOutline(blocks: MdBlock[], opts: OutlineOptions): Outline {\n const nodes: OutlineNode[] = []\n let title: string | null = null\n let chapters = 0\n let headingDepth = -1 // 현재 장 안의 마지막 h3+ 항목 depth (-1 = 없음)\n let lastItemDepth = -1 // 마지막 항목 depth (참고·표 들여쓰기 기준)\n let seenBody = false // 제목·요약 이후 본문(항목·장) 시작 여부\n let hasBoxMarkers = false\n\n /**\n * 업무보고(headingFrames): 부호 없는 마크다운 리스트는 직전 명시 부호 항목의 한 단계 아래에서 시작한다\n * (\"ㅇ (먹거리) …\" 문단 뒤 \"- 신선란 …\" → -(2단계)). 명시 부호·문단·헤딩이 나오면 리셋. 값 -1 = 미확정\n */\n let listBase = -1\n let lastExplicitDepth = -1\n const pushItem = (depth: number, text: string, legalMarker?: string, fromHeading = false, marker?: string, explicit = true) => {\n nodes.push({ kind: \"item\", depth, text, ...(legalMarker ? { legalMarker } : {}), ...(fromHeading ? { fromHeading: true } : {}), ...(marker ? { marker } : {}) })\n lastItemDepth = depth\n seenBody = true\n if (explicit) { lastExplicitDepth = depth; listBase = -1 }\n }\n const keep = !!opts.keepMarkers\n\n for (let i = 0; i < blocks.length; i++) {\n const b = blocks[i]\n switch (b.type) {\n case \"heading\": {\n const lvl = b.level ?? 1\n const raw = stripLawCodes((b.text ?? \"\").trim())\n if (lvl === 1 && title === null && opts.consumeTitle) { title = stripChapterNumber(raw) || raw; break }\n if (lvl <= 2) {\n nodes.push({ kind: \"chapter\", text: stripChapterNumber(raw) || raw, index: ++chapters })\n lastExplicitDepth = -1; listBase = -1\n // 법정 스킴: h2가 1단계(1.)를 차지하므로 아래 리스트는 가.부터 (개조식은 장이 별도 층)\n headingDepth = opts.gaejosik ? -1 : 0; lastItemDepth = opts.gaejosik ? -1 : 0; seenBody = true\n break\n }\n // 업무보고형: h3~h6 은 서식 틀(절 띠·소제목 박스·항목 띠) — 리스트 깊이는 그대로 □부터\n if (opts.headingFrames) {\n const lm = parseLeadingMarker(raw, keep)\n nodes.push({ kind: \"heading\", level: lvl, text: lm.kind === \"legal\" || lm.kind === \"keep\" ? lm.rest : raw })\n lastItemDepth = -1; lastExplicitDepth = -1; listBase = -1; seenBody = true\n break\n }\n // h3+ → 항목. 선두 법정 부호(\"가. \")는 벗긴다 — 스킴이 부호를 다시 붙인다\n const depth = Math.min(lvl - 3, 7)\n const lm = parseLeadingMarker(raw)\n pushItem(depth, lm.kind ? lm.rest : raw, undefined, true)\n headingDepth = depth\n break\n }\n case \"list_item\": {\n const text = stripLawCodes((b.text ?? \"\").trim())\n const lm = parseLeadingMarker(text, keep)\n if (SOURCE_RE.test(lm.kind === \"box\" || lm.kind === \"legal\" ? lm.rest : text)) { nodes.push({ kind: \"ref\", depth: lastItemDepth + 1, text: lm.kind ? lm.rest : text }); break }\n if (b.marker === \"*\" && !/^\\*/.test(text) && opts.gaejosik) { nodes.push({ kind: \"ref\", depth: lastItemDepth + 1, text }); break }\n if (lm.kind === \"ref\") { nodes.push({ kind: \"ref\", depth: lastItemDepth + 1, text: lm.rest }); break }\n if (lm.kind === \"box\") { hasBoxMarkers = true; pushItem(lm.depth, lm.rest); break }\n if (lm.kind === \"keep\") { pushItem(lm.depth, lm.rest, undefined, false, lm.marker); break }\n if (lm.kind === \"legal\" && opts.gaejosik) { pushItem(Math.max(lastItemDepth, 0), lm.rest, lm.marker); break }\n let base = headingDepth >= 0 ? headingDepth + 1 : 0\n if (opts.headingFrames) {\n if (listBase < 0) listBase = lastExplicitDepth + 1\n base = listBase\n }\n pushItem(Math.min(base + (b.indent ?? 0), 7), lm.kind === \"legal\" ? lm.rest : text, undefined, false, undefined, false)\n break\n }\n case \"paragraph\": {\n const text = stripLawCodes((b.text ?? \"\").trim())\n if (!text) break\n if (BUNIM_RE.test(text) || (nodes.length && nodes[nodes.length - 1].kind === \"attach\" && /^\\s/.test(b.text ?? \"\"))) {\n nodes.push({ kind: \"attach\", text: b.text ?? \"\" }); break\n }\n const ctr = /^<center>([\\s\\S]*)<\\/center>$/i.exec(text)\n if (ctr) { nodes.push({ kind: \"para\", depth: 0, text: ctr[1].trim(), align: \"CENTER\" }); break }\n const rgt = /^<right>([\\s\\S]*)<\\/right>$/i.exec(text)\n if (rgt) { nodes.push({ kind: \"para\", depth: 0, text: rgt[1].trim(), align: \"RIGHT\" }); break }\n const lm = parseLeadingMarker(text, keep)\n if (lm.kind === \"ref\") { nodes.push({ kind: \"ref\", depth: lastItemDepth + 1, text: lm.rest }); break }\n if (SOURCE_RE.test(lm.kind ? lm.rest : text)) { nodes.push({ kind: \"ref\", depth: lastItemDepth + 1, text: lm.kind ? lm.rest : text }); break }\n if (lm.kind === \"box\") { hasBoxMarkers = true; pushItem(lm.depth, lm.rest); break }\n if (lm.kind === \"keep\") { pushItem(lm.depth, lm.rest, undefined, false, lm.marker); break }\n if (lm.kind === \"legal\") {\n if (opts.gaejosik) pushItem(Math.max(lastItemDepth, 0), lm.rest, lm.marker)\n else pushItem(lm.depth, lm.rest)\n break\n }\n nodes.push({ kind: \"para\", depth: 0, text })\n seenBody = true\n lastExplicitDepth = -1; listBase = -1\n break\n }\n case \"blockquote\": {\n const lines = stripLawCodes(b.text ?? \"\").split(\"\\n\").map((l) => l.trim()).filter(Boolean)\n if (!lines.length) break\n // 요약박스는 줄 경계 보존(3줄 개조식 요약), 참고는 한 문단. quoteBox(업무보고)는 위치 무관 전부 박스\n if (opts.quoteBox || (opts.summaryFromQuote && !seenBody)) nodes.push({ kind: \"summary\", text: lines.join(\"\\n\") })\n else nodes.push({ kind: \"ref\", depth: lastItemDepth + 1, text: lines.join(\" \").replace(/^※\\s*/, \"\") })\n break\n }\n default:\n nodes.push({ kind: \"block\", depth: lastItemDepth, block: b })\n seenBody = true\n }\n }\n return { title, nodes, hasBoxMarkers, chapters }\n}\n","/**\n * 한 줄 강제·문단 압축 (v5) — 한컴 조판을 재현(실글꼴 폭·어절 줄바꿈)해 판정한다.\n *\n * 실측(서울 결재문서 □ 150건): 한 줄 95%, 장평 96/95·자간 -4/-5로 줄여 넣는 관행.\n * 폭은 font-metrics.ts 실측표(한글 2024 실렌더 본문 154줄 줄바꿈 전부 재현) — 표가 없는 글꼴만\n * 근사 클래스라 여유를 더 둔다.\n */\n\nimport { measureTextWidth, faceClassForGen, simulateWrap, type FaceClass } from \"./text-metrics.js\"\n\nexport interface FitResult {\n pt: number\n ratio: number\n spacing: number\n /** 마지막 조합으로도 한 줄에 못 담음 */\n overflow: boolean\n}\n\nconst RATIOS = [100, 97, 95, 92, 90, 87, 85]\nconst SPACINGS = [0, -3, -5]\n\n/**\n * 가용폭 안전계수 — 실폭표도 한컴 조판과 줄마다 조금씩 어긋난다(코퍼스 한컴 저장본 대조: 모델이 틀린 문단 대부분이 폭 ±0.2~3%\n * 보정으로 맞음, 한컴이 더 넓게 잡는 쪽이 최대 +3%). \"한 줄에 들어간다\"는 판단은 2% 여유를 둔다(여유 0.6% 로 한 줄에 맞춘\n * 압축 문단이 한컴에서 넘친 실사고, 2026-09-23). 근사 클래스는 호출부 값(2~5%).\n */\nfunction safety(faceClass: FaceClass, approx: number): number {\n return faceClass.startsWith(\"font:\") ? 0.98 : approx\n}\n\n/**\n * @param minPt 글자 크기 하한 — pt 와 같으면 크기는 줄이지 않는다(□ 항목: 형제끼리 크기가 달라 들쭉날쭉해 보이는 것 방지)\n * @param minRatio 장평 하한(기본 85) — □ 는 90 (실측 96/95 관행, 85 는 눈에 띄게 납작함)\n */\nexport function fitOneLine(text: string, font: string, pt: number, availHu: number, minPt: number = Math.max(pt - 3, 10), minRatio = 85): FitResult {\n const faceClass = faceClassForGen(font)\n const avail = availHu * safety(faceClass, 0.98)\n const fits = (p: number, r: number, s: number) => measureTextWidth(text, p * 100, r, { spacingPct: s, faceClass }) <= avail\n if (fits(pt, 100, 0)) return { pt, ratio: 100, spacing: 0, overflow: false }\n const ratios = RATIOS.filter((r) => r >= minRatio)\n for (let p = pt; p >= minPt; p--) {\n for (const r of ratios) for (const s of SPACINGS) {\n if (fits(p, r, s)) return { pt: p, ratio: r, spacing: s, overflow: false }\n }\n }\n return { pt: minPt, ratio: ratios[ratios.length - 1], spacing: SPACINGS[SPACINGS.length - 1], overflow: true }\n}\n\n/** 고아 줄·한 줄 근접용 압축 사다리 — 자간 -1…-12(실무 Shift+Alt+N 반복) → 장평 97~88 조합 */\nconst SQUEEZE: Array<[number, number]> = (() => {\n const out: Array<[number, number]> = []\n for (let sp = -1; sp >= -12; sp--) out.push([100, sp])\n for (const r of [97, 95, 92, 90, 88]) for (let sp = 0; sp >= -12; sp--) out.push([r, sp])\n return out\n})()\n\n/** 양쪽 정렬 공백 한 칸이 원래 폭의 몇 배 넘게 늘어나면 \"벌어진 줄\"인가 (1.0 = 두 배) */\nconst LOOSE_LIMIT = 1.0\n\n/**\n * 짧은 꼬리 줄 올리기 — 마지막 줄이 가용폭의 절반 이하이고 압축 15% 이내로 줄 수가 하나 줄면 가장 적은 압축으로 줄인다(실무: 짧은\n * 꼬리 줄은 자간·장평을 줄여 올린다. \"…안양 / AI전략국(2026. 1.)\" 은 11.7% 면 한 줄). 단 줄인 결과에 벌어진 줄이 생기면 안 한다\n * (묶음 빈칸으로 묶은 긴 날짜 덩어리가 다음 줄로 밀려 앞 줄이 벌어지는 경우).\n */\nconst PULL_TAIL = 0.5\nconst PULL_MAX = 0.15\nconst squeezeOf = (r: number, sp: number): number => 1 - (r / 100) * (1 + sp / 100)\n\n/**\n * 고아 줄 — 마지막 줄이 가용폭의 이 비율 이하. 종전 \"한 줄 근접 122%\"(글자 단위에선 둘째 줄 = 넘친 양)를\n * 어절 단위 조판에 맞춰 마지막 줄 길이로 판정한다(긴 어절이 통째로 넘어가 둘째 줄이 넉넉하면 고아가 아니다).\n */\nconst ORPHAN_RATIO = 0.22\n\n/**\n * 조판 비용 — 벌어짐(두 배 초과분) + 고아 줄 + 압축량. 고아 줄 하나 = 압축 15%(실무 요청 관행: 고아 줄은\n * 자간·장평을 꽤 줄여서라도 올린다), 공백이 세 배로 벌어진 줄 하나 = 압축 10%.\n */\nconst ORPHAN_COST = 1.5\nconst COMPRESS_COST = 10\n\n/**\n * 줄마다 양쪽 정렬로 공백이 늘어나는 정도 — (가용폭 − 자연폭) / (공백 수 × 공백폭), 마지막 줄 제외.\n * 공백 없는 줄은 글자 사이로 벌어지므로 여유를 반각 공백 1칸 기준으로 본다.\n */\nfunction worstLooseness(text: string, starts: number[], firstW: number, contW: number, h: number, ratio: number, spacing: number, faceClass: FaceClass): number {\n const spaceW = 0.5 * h * (ratio / 100) * (1 + spacing / 100)\n let worst = 0\n for (let i = 0; i + 1 < starts.length; i++) {\n const seg = text.slice(starts[i], starts[i + 1]).replace(/ +$/, \"\")\n const slack = (i === 0 ? firstW : contW) - measureTextWidth(seg, h, ratio, { faceClass, spacingPct: spacing })\n const spaces = (seg.match(/ /g) ?? []).length\n worst = Math.max(worst, slack / (Math.max(spaces, 1) * spaceW))\n }\n return worst\n}\n\n/**\n * 문단 압축 결정 (본문·항목 문단) — 어절 줄바꿈(BREAK_WORD)으로 조판을 재현하고, 무압축과 압축 사다리\n * (자간 -1…-12 → 장평 97~88, 실무 Shift+Alt+N 관행) 가운데 조판 비용이 가장 낮은 조합을 고른다.\n * 비용 = 벌어진 줄(양쪽 정렬로 공백이 두 배 넘게 늘어나는 줄 — 긴 어절이 통째로 넘어간 자리)의 초과분\n * + 고아 줄(마지막 줄 ≤ 가용폭 22%) + 압축량. 줄 수는 늘리지 않는다. 무압축이 최선이면 null.\n * @param minRatio 장평 하한 — 공문서 `autoFit.minRatio`(기본 90). 사다리에서 이보다 납작한 장평은 쓰지 않는다\n */\nexport function fitParagraph(text: string, font: string, pt: number, firstW: number, contW: number, minRatio = 88, orphanRatio = ORPHAN_RATIO): { ratio: number; spacing: number } | null {\n const faceClass = faceClassForGen(font)\n const h = pt * 100\n const k = safety(faceClass, 0.95)\n const f = firstW * k, c = contW * k\n const ladder: Array<[number, number]> = [[100, 0], ...SQUEEZE.filter(([r]) => r >= minRatio)]\n const base = simulateWrap(text, f, c, h, 100, \"keep\", { faceClass })\n if (base.lines < 2) return null\n if (base.lastLineWidth <= c * PULL_TAIL) {\n let pull: { r: number; sp: number; amt: number } | null = null\n for (const [r, sp] of ladder) {\n const amt = squeezeOf(r, sp)\n if (amt > PULL_MAX + 1e-9 || (pull && amt >= pull.amt - 1e-9)) continue\n const w = simulateWrap(text, f, c, h, r, \"keep\", { faceClass, spacingPct: sp })\n if (w.lines < base.lines && worstLooseness(text, w.starts, f, c, h, r, sp, faceClass) <= LOOSE_LIMIT) pull = { r, sp, amt }\n }\n if (pull) return { ratio: pull.r, spacing: pull.sp }\n }\n let baseLines = 0\n let best: { r: number; sp: number; cost: number } | null = null\n for (const [r, sp] of ladder) {\n const w = simulateWrap(text, f, c, h, r, \"keep\", { faceClass, spacingPct: sp })\n if (!best) { if (w.lines < 2) return null; baseLines = w.lines }\n if (w.lines > baseLines) continue\n const orphan = w.lines > 1 && w.lastLineWidth <= contW * orphanRatio\n const loose = worstLooseness(text, w.starts, f, c, h, r, sp, faceClass)\n const cost = Math.max(0, loose - LOOSE_LIMIT) + (orphan ? ORPHAN_COST : 0) + squeezeOf(r, sp) * COMPRESS_COST\n if (!best || cost < best.cost - 1e-9) best = { r, sp, cost }\n }\n return best && (best.r !== 100 || best.sp !== 0) ? { ratio: best.r, spacing: best.sp } : null\n}\n\n/** 글자 단위에서 줄을 끊어도 되는 자리 — 공백 뒤, 또는 목록 구분자(· , 、 /) 뒤. 낱말 가운데는 안 된다 */\nconst LIST_BREAK = new Set([...\"·,、/\"])\n\n/**\n * 한 줄보다 긴 어절(공백 없는 가운뎃점 목록 \"구(강남·강서·…·종로)가\" 등)이 있는 문단 — 어절 단위면 한컴이 그 어절을 다음 줄로\n * 넘긴 뒤 쪼개 앞 줄이 크게 벌어진다. 글자 단위로 조판하되 모든 줄 끝이 공백이나 목록 구분자 뒤에 오고, 폭 오차 ±1% 에서도 같은\n * 자리에서 끊기며, 벌어진 줄이 없는 가장 적은 압축(15% 이내, 장평 하한 minRatio)을 고른다. 해당 없거나 그런 압축이 없으면 null\n * (어절 단위 유지). 반환값이 있으면 문단을 글자 단위(keepWord false)로 낸다.\n * ±1% 인 까닭: 글자 단위는 한 글자(1em ≈ 줄폭 3%)만 어긋나도 끊는 자리가 바뀐다. ±2% 면 허용 구간이 한 글자 폭보다 넓어\n * 후보가 거의 없다(서울시 11개 구 목록 문단 실측: ±2% 0건, ±1% 자간 -12 에서 \"서초·|성동\").\n */\nexport function fitCharBreaks(text: string, font: string, pt: number, firstW: number, contW: number, minRatio = 88): { ratio: number; spacing: number } | null {\n const faceClass = faceClassForGen(font)\n const h = pt * 100\n const k = safety(faceClass, 0.95)\n if (!text.split(/ +/).some((w) => measureTextWidth(w, h, 100, { faceClass }) > contW * k)) return null\n let best: { r: number; sp: number; amt: number } | null = null\n for (const [r, sp] of [[100, 0] as [number, number], ...SQUEEZE.filter(([r]) => r >= minRatio)]) {\n const amt = squeezeOf(r, sp)\n if (amt > PULL_MAX + 1e-9 || (best && amt >= best.amt - 1e-9)) continue\n const wrapAt = (s: number) => simulateWrap(text, firstW * s, contW * s, h, r, \"charAll\", { faceClass, spacingPct: sp }).starts\n const starts = wrapAt(1)\n if (wrapAt(0.99).join() !== starts.join() || wrapAt(1.01).join() !== starts.join()) continue\n if (!starts.slice(1).every((s) => text[s - 1] === \" \" || LIST_BREAK.has(text[s - 1]))) continue\n if (worstLooseness(text, starts, firstW, contW, h, r, sp, faceClass) > LOOSE_LIMIT) continue\n best = { r, sp, amt }\n }\n return best ? { ratio: best.r, spacing: best.sp } : null\n}\n","/**\n * 항목부호 + 탭 — v5 공문서의 \"첫 줄 내용 = 둘째 줄\" 정렬 원자 (gen-gongmun 항목·참고 문단, 업무보고 요약박스).\n * paraPr 는 autoTab(내어쓰기용 자동 탭, tabPr 1)·indent = -hang 과 짝으로 써야 한다.\n */\n\nimport { measureTextWidth, faceClassForGen } from \"./text-metrics.js\"\nimport { taHu } from \"./gongmun-scheme.js\"\nimport { escapeTextXml } from \"./gen-ids.js\"\n\n/**\n * 항목부호 문단 기하 — left = 부호 시작, hang = 내어쓰기 = 부호 실폭 + 1타(편람 \"부호 뒤 1타\").\n * 부호 뒤는 공백이 아니라 탭(내어쓰기용 자동 탭)이라 첫 줄 내용도 둘째 줄과 같은 left+hang 에서 시작한다\n * — 양쪽 정렬이 부호 뒤 공백을 늘리던 어긋남, 압축(장평·자간)이 부호 폭을 줄이던 어긋남이 구조적으로 없다.\n */\nexport function markerLayout(font: string, pt: number, leadTa: number, marker: string): { left: number; hang: number; markerW: number } {\n const left = leadTa * taHu(pt)\n if (!marker) return { left, hang: 0, markerW: 0 }\n const markerW = Math.round(measureTextWidth(marker, pt * 100, 100, { faceClass: faceClassForGen(font) }))\n return { left, hang: markerW + taHu(pt), markerW }\n}\n\n/** 부호 run — 부호 + 탭. 탭 폭은 한컴이 조판 때 다시 계산한다(값은 1타 근사) */\nexport function markerRunXml(marker: string, charPr: number, lay: { hang: number; markerW: number }): string {\n return `<hp:run charPrIDRef=\"${charPr}\"><hp:t>${escapeTextXml(marker)}<hp:tab width=\"${lay.hang - lay.markerW}\" leader=\"0\" type=\"1\"/></hp:t></hp:run>`\n}\n","/**\n * 공문서 v5 문자 다듬기 — 조판(폭 계산) 전에 본문 문자열에 적용한다.\n *\n * 1) 묶음 빈칸: 날짜(2026. 9. 23.)·연월(2026. 9.)·월일(9. 23.)·시각 범위(14:00 ~ 16:00)·금액의 \"원\" 앞\n * 공백(3억 원)을 U+00A0 으로 바꾼다. 생성기가 `<hp:nbSpace/>`(한글 묶음 빈칸)로 방출해 줄 끝에서\n * \"2026. 1. / 22.\" 처럼 갈라지지 않는다(한글 2024 실렌더 참조 PDF의 날짜 분리 4건).\n * 2) 따옴표: 곧은따옴표 ' \" → ‘ ’ “ ” — 한글 입력 자동 고침과 같은 꼴. 휴먼명조·HY 글꼴의 곧은따옴표는\n * 여닫음 구분 없이 ’ 로 그려진다. 연도 약식 '26 은 ’26.\n *\n * 인라인 코드(`…`)·링크 URL(](…))은 건드리지 않는다. 순수 함수 — XML 은 모른다.\n */\n\nimport type { MdBlock } from \"./md-runs.js\"\n\nexport const NBSP = \"\\u00a0\"\n\n/** 앞 글자가 이 중 하나(또는 문두)면 여는 따옴표 — \">\" 는 `<center>\"…\"` 같은 태그 뒤 */\nconst OPENER_BEFORE = /[\\s(\\[{>「『〈《【〔‘“·/:,~—–-]/u\n\nfunction bindSpaces(s: string): string {\n return s\n // 연월일 — 연도는 4자리 또는 약식('26·’26)\n .replace(/(\\d{4}|['’]\\d{2})\\. (\\d{1,2})\\. (\\d{1,2})\\.(?!\\d)/g, `$1.${NBSP}$2.${NBSP}$3.`)\n // 연월 (위에서 연월일은 이미 묶였으므로 일반 공백이 남은 것만)\n .replace(/(\\d{4}|['’]\\d{2})\\. (\\d{1,2})\\.(?!\\d)/g, `$1.${NBSP}$2.`)\n // 월일 — 앞이 숫자·마침표가 아닐 때만(소수·버전 번호 제외)\n .replace(/(?<![\\d.])(\\d{1,2})\\. (\\d{1,2})\\.(?!\\d)/g, `$1.${NBSP}$2.`)\n // 시각 범위\n .replace(/(\\d{1,2}:\\d{2}) ([~∼-]) (\\d{1,2}:\\d{2})/g, `$1${NBSP}$2${NBSP}$3`)\n // 금액 — 숫자(+조·억·만·천) 뒤 \" 원\"\n .replace(/(\\d(?:조|억|만|천)?) 원/g, `$1${NBSP}원`)\n}\n\n/** 강조 부호(* _ ~)를 건너뛴 앞뒤 실글자 */\nfunction neighbor(s: string, i: number, dir: -1 | 1): string {\n for (let k = i + dir; k >= 0 && k < s.length; k += dir) if (!/[*_~]/.test(s[k])) return s[k]\n return \"\"\n}\n\n/** @param before 앞 구간(코드·링크)의 끝 글자 — 구간 첫머리 따옴표의 여닫음을 이어서 판정 */\nfunction curlQuotes(s: string, before = \"\"): string {\n let out = \"\"\n for (let i = 0; i < s.length; i++) {\n const c = s[i]\n if (c !== \"'\" && c !== '\"') { out += c; continue }\n const prev = neighbor(s, i, -1) || before\n const opening = prev === \"\" || OPENER_BEFORE.test(prev)\n if (c === \"'\") {\n // 연도 약식 '26 — 숫자 두 자리 뒤에 닫는 따옴표가 없으면 아포스트로피\n if (opening && /^\\d{2}(?![\\d'])/.test(s.slice(i + 1))) { out += \"’\"; continue }\n out += opening ? \"‘\" : \"’\"\n } else {\n out += opening ? \"“\" : \"”\"\n }\n }\n return out\n}\n\n/** 본문 문자열 다듬기 — 코드·링크 URL 구간은 그대로 */\nexport function polishGongmunText(text: string): string {\n if (!text) return text\n let out = \"\"\n for (const [i, seg] of text.split(/(`[^`]*`|\\]\\([^)]*\\))/).entries()) {\n // \"'[링크](url)'\" 의 닫는 따옴표처럼 구간 첫머리 따옴표는 앞 구간 끝 글자로 판정한다\n out += i % 2 === 1 ? seg : curlQuotes(bindSpaces(seg), out.replace(/[*_~]+$/, \"\").slice(-1))\n }\n return out\n}\n\n/** 마크다운 블록 다듬기 — 문단·헤딩·항목·인용·GFM 표 셀만(코드·수식·HTML 표 원문은 그대로). 개조식·보도자료 경로용 */\nexport function polishGongmunBlock(b: MdBlock): MdBlock {\n if (b.type === \"table\") return b.rows ? { ...b, rows: b.rows.map((r) => r.map(polishGongmunText)) } : b\n if (b.type === \"paragraph\" || b.type === \"heading\" || b.type === \"list_item\" || b.type === \"blockquote\") return b.text ? { ...b, text: polishGongmunText(b.text) } : b\n return b\n}\n","/**\n * 서울 실결재 골격 표(v5) — 기안문 두문표·결문표, 보고서 제목표·요약박스·결재선표·표지.\n *\n * 실측 근거(정보소통광장 결재문서본문, docs/gongmunseo-reference.md 2.8):\n * 두문표 6행×3열 w 49240: 슬로건(굴림 10) / [로고 6949 | 기관명 굴림 20b 자간띄움 | 7223] h5608 /\n * 간격 h1563 / 수신·(경유)·제목 라벨 굴림 14 + 값 14 (라벨열 6949), 제목행 하변 0.12mm만 테두리.\n * 결문표 w 49520: 발신명의 18b 행 / 수신자 / 회색 띠 #CCCCCC h1146 / 결재선(직위 10·성명 11b·일자 9b) /\n * 협조자 / 시행·접수 / 우·주소·홈페이지 / 전화·전송·이메일·공개구분 — 전부 굴림 10, 테두리 없음.\n * 보고서 제목표 w 48758: 제목 HY헤드라인M 25~27b(상 0.4mm·하 0.15mm) + 담당자 행 휴먼명조 12(하 0.4mm).\n * 요약박스 1×1 #DFE6F7 0.4mm, 한컴돋움 15b. 결재선표: 직위행 + 서명행(외곽 0.4·내부 0.12).\n * 열폭은 실측 비율을 본문폭에 맞춰 스케일한다(hwpx-skill 원칙: 좌표를 베끼지 말고 계산).\n */\n\nimport { tc, para } from \"./gen-gongmun-extra.js\"\nimport { TableBfRegistry } from \"./gen-table-bf.js\"\nimport { escapeXml } from \"./gen-ids.js\"\nimport { StyleRegistry } from \"./style-registry.js\"\nimport { fitOneLine, fitParagraph } from \"./fit-line.js\"\nimport { simulateWrap, measureTextWidth, faceClassForGen } from \"./text-metrics.js\"\nimport { EXTRA_TABLE_ID_BASE } from \"./geometry.js\"\nimport type { FrameSpec } from \"./gongmun-scheme.js\"\nimport type { ResolvedGongmun } from \"./gongmun.js\"\n\nlet frameTableId = EXTRA_TABLE_ID_BASE + 500\nexport function resetFrameTableIds(): void { frameTableId = EXTRA_TABLE_ID_BASE + 500 }\n\nconst BF_NONE = 1\n\ninterface FrameCtx {\n reg: StyleRegistry\n bf: TableBfRegistry\n frame: FrameSpec\n /** 본문 폭 (HWPUNIT) */\n W: number\n}\n\n/** 골격표 — treatAsChar, 셀 여백 실측(140), outMargin 좌우 0 (gen-frame-ministry 도 같은 골격을 쓴다) */\nexport function ftbl(rows: string[], w: number, h: number, cols: number, opts: { bottomGap?: number; bf?: number } = {}): string {\n return `<hp:tbl id=\"${++frameTableId}\" zOrder=\"0\" numberingType=\"TABLE\" textWrap=\"TOP_AND_BOTTOM\" textFlow=\"BOTH_SIDES\" lock=\"0\" dropcapstyle=\"None\" pageBreak=\"CELL\" repeatHeader=\"0\" rowCnt=\"${rows.length}\" colCnt=\"${cols}\" cellSpacing=\"0\" borderFillIDRef=\"${opts.bf ?? BF_NONE}\" noAdjust=\"1\">`\n + `<hp:sz width=\"${w}\" widthRelTo=\"ABSOLUTE\" height=\"${h}\" heightRelTo=\"ABSOLUTE\" protect=\"0\"/>`\n + `<hp:pos treatAsChar=\"1\" affectLSpacing=\"0\" flowWithText=\"1\" allowOverlap=\"0\" holdAnchorAndSO=\"0\" vertRelTo=\"PARA\" horzRelTo=\"PARA\" vertAlign=\"TOP\" horzAlign=\"LEFT\" vertOffset=\"0\" horzOffset=\"0\"/>`\n + `<hp:outMargin left=\"0\" right=\"0\" top=\"0\" bottom=\"${opts.bottomGap ?? 0}\"/>`\n + `<hp:inMargin left=\"140\" right=\"140\" top=\"140\" bottom=\"140\"/>`\n + rows.map((r) => `<hp:tr>${r}</hp:tr>`).join(\"\")\n + `</hp:tbl>`\n}\n\nexport function host(tableXml: string, paraPrId: number, charPrId: number, extra = \"\"): string {\n return `<hp:p paraPrIDRef=\"${paraPrId}\" styleIDRef=\"0\"${extra}><hp:run charPrIDRef=\"${charPrId}\">${tableXml}</hp:run></hp:p>`\n}\n\n/** 실측 열폭 배열을 목표 폭으로 비례 스케일(합 = w, 마지막 열이 잔여 흡수) */\nfunction scale(cols: number[], w: number): number[] {\n const sum = cols.reduce((a, b) => a + b, 0)\n const out = cols.map((c) => Math.round((c / sum) * w))\n out[out.length - 1] += w - out.reduce((a, b) => a + b, 0)\n return out\n}\n\n/** 기관명 자간 띄움 — 실결재 \"종 로 소 방 서\"(6자 이하, 공백 없는 기관명) */\nexport function spacedOrgName(org: string): string {\n const t = org.trim()\n if (/\\s/.test(t) || [...t].length > 6) return t\n return [...t].join(\" \")\n}\n\n// ─── 기안문 두문표 ─────────────────────────────────\n\nexport interface DocHeadInput { org?: string; slogan?: string; to?: string; via?: string; title?: string }\n\nexport function buildDocHeadTable(h: DocHeadInput, ctx: FrameCtx): string {\n const { reg, bf, frame } = ctx\n const w = ctx.W - 366\n const [cLabel, cValue, cPad] = scale([6949, 35068, 7223], w)\n const center = reg.para({ align: \"CENTER\", lineSp: 160 })\n const left = reg.para({ align: \"LEFT\", lineSp: 160 })\n const c10 = reg.char({ font: frame.font, pt: 10 })\n const c10b = reg.char({ font: frame.font, pt: 10, bold: true })\n const c20b = reg.char({ font: frame.font, pt: 20, bold: true })\n const c14 = reg.char({ font: frame.font, pt: 14 })\n const bottomLine = bf.get({ t: \"none\", b: \"thin\", l: \"none\", r: \"none\" })\n const rows: string[] = []\n let r = 0\n if (h.slogan) {\n rows.push(tc({ bf: BF_NONE, row: r++, col: 0, w, h: 2416, colSpan: 3, paras: para(h.slogan, center, c10) }))\n }\n rows.push(\n tc({ bf: BF_NONE, row: r, col: 0, w: cLabel, h: 5608, paras: para(\"\", center, c10) })\n + tc({ bf: BF_NONE, row: r, col: 1, w: cValue, h: 5608, paras: para(spacedOrgName(h.org ?? \"\"), center, c20b) })\n + tc({ bf: BF_NONE, row: r, col: 2, w: cPad, h: 5608, paras: para(\"\", center, c10) }),\n )\n r++\n rows.push(tc({ bf: BF_NONE, row: r++, col: 0, w, h: 1563, colSpan: 3, paras: para(\"\", left, c10b) }))\n const labeled = (label: string, value: string, height: number, bfId: number) =>\n tc({ bf: bfId, row: r, col: 0, w: cLabel, h: height, paras: para(label, left, c14) })\n + tc({ bf: bfId, row: r, col: 1, w: cValue + cPad, h: height, colSpan: 2, paras: para(value, left, c14) })\n rows.push(labeled(\" 수신 \", h.to ?? \"\", 2097, BF_NONE)); r++\n rows.push(labeled(\"(경유)\", h.via ?? \"\", 2380, BF_NONE)); r++\n rows.push(labeled(\" 제목 \", h.title ?? \"\", 2248, bottomLine)); r++\n const height = rows.length === 6 ? 16312 : 13896\n return host(ftbl(rows, w, height, 3, { bottomGap: 852 }), reg.para({ align: \"LEFT\", lineSp: 100 }), c10)\n}\n\n// ─── 기안문 결문표 ─────────────────────────────────\n\nexport interface Approver { title: string; name: string; date?: string }\nexport interface DocFootInput {\n sender?: string\n approvers: Approver[]\n cooperators: Approver[]\n recipients?: string\n docNum?: string; receive?: string\n zip?: string; address?: string; site?: string\n phone?: string; fax?: string; email?: string; disclosure?: string\n}\n\n/** \"주무관 홍길동\" → {title, name} (마지막 어절이 성명) */\nexport function splitTitleName(s: string): Approver {\n const t = s.trim()\n const i = t.lastIndexOf(\" \")\n return i > 0 ? { title: t.slice(0, i).trim(), name: t.slice(i + 1).trim() } : { title: \"\", name: t }\n}\n\nexport function buildDocFootTable(f: DocFootInput, ctx: FrameCtx, internal: boolean): string {\n const { reg, bf, frame } = ctx\n const w = ctx.W - 86\n // 공통 격자 — 실결재 결문표는 41열 미세 격자 위에 colSpan으로 행마다 다른 칸을 얹는다.\n // 행별로 임의 폭을 주면 한컴이 열 경계를 맞추다 표가 뒤틀린다(실렌더 확인) → 48열 격자.\n const GRID = 48\n const unit = Math.floor(w / GRID)\n const c10 = reg.char({ font: frame.font, pt: 10 })\n const c11b = reg.char({ font: frame.font, pt: 11, bold: true })\n const c9b = reg.char({ font: frame.font, pt: 9, bold: true })\n const c18b = reg.char({ font: frame.font, pt: 18, bold: true })\n const c3 = reg.char({ font: frame.font, pt: 3 })\n const center = reg.para({ align: \"CENTER\", lineSp: 100 })\n const left = reg.para({ align: \"LEFT\", lineSp: 100 })\n const gray = bf.get({ t: \"none\", b: \"none\", l: \"none\", r: \"none\", fill: \"#CCCCCC\" })\n /** 실측 폭 배열 → 격자 span 배열(합 GRID) */\n const spans = (widths: number[]): number[] => {\n const sum = widths.reduce((a, b) => a + b, 0)\n const out = widths.map((x) => Math.max(1, Math.round((x / sum) * GRID)))\n let diff = GRID - out.reduce((a, b) => a + b, 0)\n for (let i = out.length - 1; diff !== 0 && i >= 0; i = (i - 1 + out.length) % out.length) {\n if (diff > 0) { out[i]++; diff-- } else if (out[i] > 1) { out[i]--; diff++ }\n }\n return out\n }\n interface Spec { span: number; text: string; cp?: number; pp?: number; rowSpan?: number; bf?: number; vAlign?: \"TOP\" | \"CENTER\" | \"BOTTOM\" }\n const rows: string[] = []\n let r = 0\n /** 한 행 — span 합이 GRID가 되도록 마지막 칸이 잔여 흡수, 폭은 격자 단위×span(마지막은 w 잔여) */\n const row = (h: number, specs: Spec[]) => {\n let col = 0\n let xml = \"\"\n specs.forEach((sp, i) => {\n const last = i === specs.length - 1\n const span = last ? GRID - col : sp.span\n const cw = last ? w - col * unit : span * unit\n xml += tc({ bf: sp.bf ?? BF_NONE, row: r, col, w: cw, h, colSpan: span, rowSpan: sp.rowSpan, vAlign: sp.vAlign, paras: para(sp.text, sp.pp ?? left, sp.cp ?? c10) })\n col += span\n })\n rows.push(xml)\n r++\n }\n // 발신명의 (대외) — 내부결재는 빈 행 유지(실측 기하)\n {\n const [a, b, c] = spans([7981, 32099, 9440])\n row(4042, [{ span: a, text: \"\" }, { span: b, text: internal ? \"\" : (f.sender ?? \"\"), cp: c18b, pp: center }, { span: c, text: \"\" }])\n }\n if (f.recipients) {\n const [a] = spans([4843, 44677])\n row(2880, [{ span: a, text: \"수신자\", vAlign: \"TOP\" }, { span: GRID - a, text: f.recipients, vAlign: \"TOP\" }])\n } else {\n row(1280, [{ span: GRID, text: \"\" }])\n }\n row(1146, [{ span: GRID, text: \"\", cp: c3, pp: center, bf: gray }])\n // 결재선 — 직위(2행 병합) | 일자/성명, 실측 폭 6909/4625 + 칸 사이 983\n {\n const n = Math.max(f.approvers.length, 1)\n const unitW = [6909, 4625, 983]\n // 직위칸은 내용 폭으로 — 실측 6909(6자)는 최소값, 「스마트도시과장」(7자)은 넘친다 (hwpx-skill 원칙)\n // 격자 양자화(48열, 1칸≈1030)로 한 칸 깎일 수 있어 여백을 격자 한 칸 이상 준다 (「스마트도시과장」 7자 실렌더 꺾임)\n const titleW = (t: string) => Math.max(unitW[0], Math.round(measureTextWidth(t, 1000, 100, { faceClass: \"fixedPitch\" })) + 280 + unit + 300)\n const widths: number[] = []\n for (let i = 0; i < n; i++) { widths.push(titleW(f.approvers[i]?.title ?? \"\"), unitW[1]); if (i < n - 1) widths.push(unitW[2]) }\n const used = widths.reduce((a, b) => a + b, 0)\n if (used < w) widths.push(w - used)\n const sp = spans(widths)\n const top: Spec[] = [], bottom: Spec[] = []\n let k = 0\n for (let i = 0; i < n; i++) {\n const ap = f.approvers[i] ?? { title: \"\", name: \"\" }\n top.push({ span: sp[k++], text: ap.title, pp: center, rowSpan: 2 })\n const signSpan = sp[k++]\n top.push({ span: signSpan, text: ap.date ?? \"\", cp: c9b, pp: center })\n bottom.push({ span: signSpan, text: ap.name, cp: c11b, pp: center })\n if (i < n - 1) top.push({ span: sp[k++], text: \"\", rowSpan: 2 })\n }\n if (k < sp.length) top.push({ span: sp[k], text: \"\", rowSpan: 2 })\n // 두 행을 직접 조립 — 병합 셀은 위 행에만, 아래 행은 서명 칸만 (열 위치는 위 행과 동일)\n let col = 0, xmlTop = \"\", xmlBottom = \"\"\n let bi = 0\n top.forEach((s, i) => {\n const last = i === top.length - 1\n const span = last ? GRID - col : s.span\n const cw = last ? w - col * unit : span * unit\n xmlTop += tc({ bf: BF_NONE, row: r, col, w: cw, h: s.rowSpan ? 2198 : 1100, colSpan: span, rowSpan: s.rowSpan, paras: para(s.text, s.pp ?? left, s.cp ?? c10) })\n if (!s.rowSpan) { const b = bottom[bi++]; xmlBottom += tc({ bf: BF_NONE, row: r + 1, col, w: cw, h: 1098, colSpan: span, paras: para(b.text, b.pp ?? center, b.cp ?? c11b) }) }\n col += span\n })\n rows.push(xmlTop, xmlBottom); r += 2\n }\n // 협조자\n {\n const [a] = spans([4455, 45065])\n const coop = f.cooperators.map((c) => `${c.title} ${c.name}`.trim()).join(\" \")\n row(2700, [{ span: a, text: \"협조자\" }, { span: GRID - a, text: coop }])\n }\n row(1400, [{ span: GRID, text: \"\" }])\n // 시행 / 접수\n {\n const [a, b, c] = spans([3340, 21532, 3301, 21347])\n row(2280, [{ span: a, text: \"시행\" }, { span: b, text: f.docNum ?? \"\" }, { span: c, text: \"접수\" }, { span: 0, text: f.receive ?? \"\" }])\n }\n // 우 우편번호 주소 / 홈페이지\n {\n const [a, b, c, d] = spans([1597, 3902, 21934, 761, 21326])\n row(1280, [{ span: a, text: \"우\" }, { span: b, text: f.zip ?? \"\" }, { span: c, text: f.address ?? \"\" }, { span: d, text: \"/\" }, { span: 0, text: f.site ?? \"\" }])\n }\n // 전화 / 전송 / 이메일 / 공개구분\n {\n const sp = spans([2750, 8006, 3196, 8311, 899, 14327, 792, 11239])\n const vals = [\"전화\", f.phone ?? \"\", \"/전송\", f.fax ?? \"\", \"/\", f.email ?? \"\", \"/\", f.disclosure ?? \"\"]\n row(2000, vals.map((v, i) => ({ span: sp[i], text: v })))\n }\n row(1000, [{ span: GRID, text: \"\" }])\n const height = rows.length * 1500\n return host(ftbl(rows, w, height, GRID), reg.para({ align: \"LEFT\", lineSp: 100 }), c10)\n}\n\n// ─── 보고서 제목표 ────────────────────────────────\n\nexport function buildReportTitleTable(title: string, contact: string | null, ctx: FrameCtx): { xml: string; overflow: boolean } {\n const { reg, bf, frame } = ctx\n const w = ctx.W - 566\n const fit = fitOneLine(title, frame.titleFont, frame.titlePt, w - 2 * 140 - 400, 20)\n const cTitle = reg.char({ font: frame.titleFont, pt: fit.pt, bold: true, ratio: fit.ratio, spacing: fit.spacing })\n const center = reg.para({ align: \"CENTER\", lineSp: 130 })\n const rows: string[] = []\n const titleBf = bf.get({ t: \"thick\", b: contact ? \"mid\" : \"thick\", l: \"none\", r: \"none\" })\n rows.push(tc({ bf: titleBf, row: 0, col: 0, w, h: 4084, paras: para(title, center, cTitle), name: \"__kordoc_h1\" }))\n let h = 4084\n if (contact) {\n const cContact = reg.char({ font: frame.contactFont, pt: frame.contactPt })\n rows.push(tc({ bf: bf.get({ t: \"mid\", b: \"thick\", l: \"none\", r: \"none\" }), row: 1, col: 0, w, h: 1943, paras: para(contact, center, cContact) }))\n h += 1943\n }\n return { xml: host(ftbl(rows, w, h, 1, { bottomGap: 600 }), reg.para({ align: \"CENTER\", lineSp: 100 }), cTitle), overflow: fit.overflow }\n}\n\n// ─── 장 제목 띠 표 (h2Marker \"band\") ─────────────────\n// 실측(2026-09-06): 계획서 장르에서 장 제목을 \"1행 ≤3열 표, 첫 셀 채움 + 로마자 흰 글자\" 로 쓰는 문서가\n// 서울 plan 36.8%(7/19)·교육청 38.9%(7/18). 번호칸 폭 2,500~3,700 HU, 채움 짙은 파랑(#003366 최다),\n// HY견고딕/HY헤드라인M 15~20 bold 흰색. 제목칸은 하변 룰. (docs/gongmunseo-reference.md 2.9)\n\nexport interface ChapterBandSpec {\n color: string\n textColor: string\n numFont: string\n numPt: number\n titleFont: string\n titlePt: number\n}\n\nexport const CHAPTER_BAND_DEFAULT: Pick<ChapterBandSpec, \"color\" | \"textColor\" | \"numFont\" | \"numPt\"> = { color: \"#003366\", textColor: \"#FFFFFF\", numFont: \"HY헤드라인M\", numPt: 17 }\n\n/** 번호칸 | 간격 | 제목칸(하변 0.4mm, `__kordoc_h2` 왕복 채널 — 파서가 heading 2로 복원) */\nexport function buildChapterBand(roman: string, title: string, ctx: FrameCtx, spec: ChapterBandSpec, before: number): { xml: string; overflow: boolean } {\n const { reg, bf } = ctx\n const w = ctx.W\n const numW = 3100, gap = 400, h = 2600\n const titleW = w - numW - gap\n const fit = fitOneLine(title, spec.titleFont, spec.titlePt, titleW - 700, spec.titlePt - 3)\n const numBf = bf.get({ t: \"none\", b: \"none\", l: \"none\", r: \"none\", fill: spec.color })\n const gapBf = bf.get({ t: \"none\", b: \"none\", l: \"none\", r: \"none\" })\n const titleBf = bf.get({ t: \"none\", b: \"thick\", l: \"none\", r: \"none\" })\n const cNum = reg.char({ font: spec.numFont, pt: spec.numPt, bold: true, color: spec.textColor })\n const cTitle = reg.char({ font: spec.titleFont, pt: fit.pt, bold: true, ratio: fit.ratio, spacing: fit.spacing })\n const center = reg.para({ align: \"CENTER\", lineSp: 130 })\n const left = reg.para({ align: \"LEFT\", lineSp: 130, left: 300 })\n const row = tc({ bf: numBf, row: 0, col: 0, w: numW, h, paras: para(roman, center, cNum), vAlign: \"CENTER\" })\n + tc({ bf: gapBf, row: 0, col: 1, w: gap, h, paras: para(\"\", center, cNum), vAlign: \"CENTER\" })\n + tc({ bf: titleBf, row: 0, col: 2, w: titleW, h, paras: para(title, left, cTitle), name: \"__kordoc_h2\", vAlign: \"CENTER\" })\n return { xml: host(ftbl([row], w, h, 3, { bottomGap: 1000 }), reg.para({ align: \"LEFT\", lineSp: 100, before, keepWithNext: true }), cTitle), overflow: fit.overflow }\n}\n\n// ─── 요약 박스 ─────────────────────────────────────\n\n/** 요약박스 문단 좌우 여백(HWPUNIT) — 실측 1000/1000 55% */\nconst SUMMARY_PAD = 1000\n\nexport function buildSummaryBox(text: string, ctx: FrameCtx): { xml: string; lines: number } {\n const { reg, bf, frame } = ctx\n const w = ctx.W - 566\n // 실측(요약박스 133건): 셀 여백은 141 이지만 문단 좌우 여백 1000/1000 이 55%(0/0 35%·2000 7%) — 글자가 테두리에\n // 붙지 않게 문단 여백으로 띄운다(선두 공백 0 이 53%라 종전 2칸 선두 공백은 뺀다). 줄바꿈은 본문과 같은 어절 단위.\n const avail = w - 280 - SUMMARY_PAD * 2\n const p = reg.para({ align: \"JUSTIFY\", lineSp: 160, left: SUMMARY_PAD, right: SUMMARY_PAD })\n // 요약은 한 문장(쉼표 허용) 3줄 이내 \"…하고자 함\" — 선두 □·ㅇ·- 부호는 벗긴다. 줄이 넘어오면 호출부가 경고.\n // 문장 꼬리 고아 줄(\"함\" 한 글자)은 자간 축소로 끌어올린다\n const bodies = text.split(\"\\n\").map((l) => l.trim().replace(/^[□■○ㅇ◦●\\-–ㆍ·•]\\s*/u, \"\")).filter(Boolean)\n let lines = 0\n const paras = bodies.map((b) => {\n const f = fitParagraph(b, frame.summaryFont, frame.summaryPt, avail, avail)\n const c = reg.char({ font: frame.summaryFont, pt: frame.summaryPt, bold: true, ratio: f?.ratio ?? 100, spacing: f?.spacing ?? 0 })\n lines += simulateWrap(b, avail * 0.995, avail * 0.995, frame.summaryPt * 100, f?.ratio ?? 100, \"keep\", { faceClass: faceClassForGen(frame.summaryFont), spacingPct: f?.spacing ?? 0 }).lines\n return para(b, p, c)\n })\n const h = lines * Math.round(frame.summaryPt * 100 * 1.6) + 280 + 600\n const box = bf.get({ t: \"thick\", b: \"thick\", l: \"thick\", r: \"thick\", fill: frame.summaryFill })\n const row = tc({ bf: box, row: 0, col: 0, w, h, paras: paras.join(\"\"), name: \"__kordoc_summary\" })\n return { xml: host(ftbl([row], w, h, 1, { bottomGap: 600 }), reg.para({ align: \"CENTER\", lineSp: 100 }), reg.char({ font: frame.summaryFont, pt: frame.summaryPt, bold: true })), lines }\n}\n\n// ─── 결재선표 (보고서 우상단) ─────────────────────\n\nexport function buildApprovalSeoul(labels: string[], names: string[] | null, ctx: FrameCtx): string {\n const { reg, bf } = ctx\n const n = labels.length\n const colW = Math.min(8600, Math.floor((ctx.W * 0.55) / n))\n const w = colW * n\n const c12 = reg.char({ font: \"한컴돋움\", pt: 12 })\n const c12b = reg.char({ font: \"한컴돋움\", pt: 12, bold: true })\n const center = reg.para({ align: \"CENTER\", lineSp: 100 })\n const edge = (row: number, col: number) => bf.get({\n t: row === 0 ? \"thick\" : \"thin\", b: row === 1 ? \"thick\" : \"thin\",\n l: col === 0 ? \"thick\" : \"thin\", r: col === n - 1 ? \"thick\" : \"thin\",\n })\n const top = labels.map((l, c) => tc({ bf: edge(0, c), row: 0, col: c, w: colW, h: 1765, paras: para(l, center, c12) })).join(\"\")\n const sign = labels.map((_, c) => tc({ bf: edge(1, c), row: 1, col: c, w: colW, h: 4200, paras: para(names?.[c] ?? \"\", center, c12b) })).join(\"\")\n return host(ftbl([top, sign], w, 5965, n, { bottomGap: 600 }), reg.para({ align: \"RIGHT\", lineSp: 100 }), c12)\n}\n\n// ─── 보고서 표지 (서울형) ──────────────────────────\n\nexport interface ReportCoverInput {\n title: string\n date: string\n org?: string\n dept?: string\n docInfo?: { docNum?: string; date?: string; disclosure?: string; policyNo?: string }\n approval?: string[]\n}\n\n/** 표지 — 좌 문서정보표·우 결재선표(양끝 배치) → 파랑 띠 제목 → 날짜 → 기관·부서명 */\nexport function buildReportCover(inp: ReportCoverInput, ctx: FrameCtx): string[] {\n const { reg, bf, frame } = ctx\n const out: string[] = []\n const c12 = reg.char({ font: \"한컴돋움\", pt: 12 })\n const c12b = reg.char({ font: \"한컴돋움\", pt: 12, bold: true })\n const center = reg.para({ align: \"CENTER\", lineSp: 100 })\n const blank = (pt = 15) => para(\"\", reg.para({ align: \"LEFT\", lineSp: 160 }), reg.char({ font: \"한컴돋움\", pt }))\n // 문서정보표 (4×2)\n const infoRows = [[\"문서번호\", inp.docInfo?.docNum ?? \"\"], [\"결재일자\", inp.docInfo?.date ?? \"\"], [\"공개여부\", inp.docInfo?.disclosure ?? \"\"], [\"방침번호\", inp.docInfo?.policyNo ?? \"\"]]\n const infoW = Math.round(ctx.W * 0.36)\n const [lw, vw] = scale([4200, 12800], infoW)\n const infoXml = ftbl(infoRows.map(([l, v], r) =>\n tc({ bf: bf.get({ t: r === 0 ? \"thick\" : \"thin\", b: r === 3 ? \"thick\" : \"thin\", l: \"thick\", r: \"thin\" }), row: r, col: 0, w: lw, h: 1850, paras: para(l, center, c12b) })\n + tc({ bf: bf.get({ t: r === 0 ? \"thick\" : \"thin\", b: r === 3 ? \"thick\" : \"thin\", l: \"thin\", r: \"thick\" }), row: r, col: 1, w: vw, h: 1850, paras: para(v, center, c12) }),\n ), infoW, 1850 * 4, 2)\n let line = infoXml\n if (inp.approval && inp.approval.length) {\n const n = inp.approval.length\n const colW = Math.min(7600, Math.floor((ctx.W * 0.5) / n))\n const edge = (row: number, col: number) => bf.get({ t: row === 0 ? \"thick\" : \"thin\", b: row === 1 ? \"thick\" : \"thin\", l: col === 0 ? \"thick\" : \"thin\", r: col === n - 1 ? \"thick\" : \"thin\" })\n const top = inp.approval.map((l, c) => tc({ bf: edge(0, c), row: 0, col: c, w: colW, h: 1765, paras: para(l, center, c12) })).join(\"\")\n const sign = inp.approval.map((_, c) => tc({ bf: edge(1, c), row: 1, col: c, w: colW, h: 3600, paras: para(\"\", center, c12b) })).join(\"\")\n line += `</hp:run><hp:run charPrIDRef=\"${c12}\"><hp:t> </hp:t></hp:run><hp:run charPrIDRef=\"${c12}\">` + ftbl([top, sign], colW * n, 5365, n)\n }\n out.push(`<hp:p paraPrIDRef=\"${reg.para({ align: \"DISTRIBUTE\", lineSp: 100 })}\" styleIDRef=\"0\"><hp:run charPrIDRef=\"${c12}\">${line}</hp:run></hp:p>`)\n for (let i = 0; i < 4; i++) out.push(blank(20))\n // 파랑 띠 제목\n const w = ctx.W - 1200\n const bar = bf.get({ t: \"none\", b: \"none\", l: \"none\", r: \"none\", fill: \"#1F2FD6\" })\n const fit = fitOneLine(inp.title, frame.titleFont, 27, w - 800, 22)\n const cT = reg.char({ font: frame.titleFont, pt: fit.pt, bold: true, ratio: fit.ratio, spacing: fit.spacing })\n const c1 = reg.char({ font: \"한컴돋움\", pt: 1 })\n const barP = reg.para({ align: \"CENTER\", lineSp: 70 })\n const rows = [\n tc({ bf: bar, row: 0, col: 0, w, h: 200, paras: para(\"\", barP, c1) }),\n tc({ bf: BF_NONE, row: 1, col: 0, w, h: 6000, paras: para(inp.title, center, cT), name: \"__kordoc_skip\" }),\n tc({ bf: bar, row: 2, col: 0, w, h: 200, paras: para(\"\", barP, c1) }),\n ]\n out.push(host(ftbl(rows, w, 6400, 1), reg.para({ align: \"CENTER\", lineSp: 100 }), cT))\n for (let i = 0; i < 2; i++) out.push(blank(20))\n out.push(para(inp.date, center, reg.char({ font: frame.titleFont, pt: 22, bold: true })))\n for (let i = 0; i < 8; i++) out.push(blank(20))\n if (inp.org) out.push(para(spacedOrgName(inp.org), center, reg.char({ font: frame.titleFont, pt: 24, bold: true })))\n if (inp.dept) out.push(para(`(${inp.dept.replace(/^\\(|\\)$/g, \"\")})`, center, reg.char({ font: \"한컴돋움\", pt: 22, bold: true })))\n return out\n}\n\nexport type { FrameCtx }\nexport { escapeXml }\n","/**\n * 중앙부처 업무보고 골격(v5, preset `ministry`) — 표지·목차·장 띠·절 띠·소제목 박스·항목 띠·요약박스·별첨 띠.\n *\n * 실측 근거: 재정경제부 「2차 업무보고 서면보고자료」(2026-07-15, A4 17쪽) PDF 를 PyMuPDF 로 글꼴·크기·색·\n * 도형(채움·선·좌표) 전수 덤프 — docs/gongmunseo-engine-spec.md (j)장. 1pt = 100 HWPUNIT.\n *\n * 표지 대외주의 빨강 박스(0.36pt, 74.7×22.4pt) 우상단 / 파란 바 #0C3DCA·#0A33A9 5.9pt 두 줄 사이 HY헤드라인M 32 / 날짜 24pt\n * 장 띠 본문폭×26.5pt, 세로 그라데이션 #D6EAFE→#FFF(원본은 →#D6EAFE 3색), 상·하 이중선 #0000FF, \"Ⅰ. 제목\" HY헤드라인M 16\n * 절 띠 [29.7×23.4pt #3057B9 0.4mm 검정 테두리 흰 숫자] [제목 하변 0.5mm, 폭=글폭] HY헤드라인M 15\n * 소제목 #203A7B 24.1pt 높이·폭=글폭, HY헤드라인M 15 흰 글자 (\"1. 민생경제 안정화\")\n * 항목 띠 본문폭×23.5pt #E8F7FC 상·하 0.4mm #00ACFF, \"① (키워드) 제목\" HY중고딕 15 — 키워드·강조 파랑\n * 요약박스 #FFF7CC 0.12mm 검정, ▪ 함초롬바탕 13(키워드 파랑 bold) / * 맑은 고딕 11\n * 별첨 띠 [61.3×26.3pt #0066FF \"별 첨\" HY헤드라인M 16 흰] [5.9pt] [제목 HY헤드라인M 16, 상·좌 0.12 / 하·우 0.4mm]\n *\n * 열폭·높이는 실측 pt 그대로(HWPUNIT ×100), 본문폭에 걸리는 것만 폭을 W 에 맞춘다.\n */\n\nimport { tc, para } from \"./gen-gongmun-extra.js\"\nimport { ftbl, host, type FrameCtx } from \"./gen-frame-seoul.js\"\nimport { generateRuns } from \"./md-runs.js\"\nimport { escapeXml, escapeTextXml, type BorderSide } from \"./gen-ids.js\"\nimport { fitOneLine } from \"./fit-line.js\"\nimport { markerLayout, markerRunXml } from \"./gen-marker.js\"\nimport { measureTextWidth, faceClassForGen, simulateWrap } from \"./text-metrics.js\"\nimport { inlineMapper } from \"./style-registry.js\"\nimport { circledNumber } from \"../shared/numbering.js\"\n\n/** 실측 색·기하 (재경부 2차 업무보고) */\nexport const MINISTRY = {\n blue: \"#0000FF\",\n headFont: \"HY헤드라인M\",\n bandFont: \"HY중고딕\",\n bodyFont: \"함초롬바탕\",\n refFont: \"맑은 고딕\",\n cover: { barDark: \"#0C3DCA\", barLight: \"#0A33A9\", barH: 590, titleH: 9500, titlePt: 32, datePt: 24, labelW: 7470, labelH: 2240, labelPt: 14 },\n toc: { labelPt: 24, labelColor: \"#000080\", chapterPt: 17, subPt: 15, border: [\"0.7 mm\", \"#999999\"] as BorderSide },\n // 원본은 위·아래 #D6EAFE·가운데 흰 3색 그라데이션 — 한글 gradation 은 2색만 안전(gen-ids)해서 위→아래 2색으로\n chapter: { h: 2650, pt: 16, fill: [\"#D6EAFE\", \"#FFFFFF\"], line: [\"0.5 mm\", \"#0000FF\", \"DOUBLE_SLIM\"] as BorderSide },\n section: { numW: 2970, h: 2340, pt: 15, fill: \"#3057B9\", border: [\"0.4 mm\", \"#000000\"] as BorderSide, underline: [\"0.5 mm\", \"#000000\"] as BorderSide },\n subhead: { h: 2410, pt: 15, fill: \"#203A7B\" },\n item: { h: 2350, pt: 15, fill: \"#E8F7FC\", line: [\"0.4 mm\", \"#00ACFF\"] as BorderSide },\n summary: { fill: \"#FFF7CC\", pt: 13, refPt: 11 },\n attach: { labelW: 6130, gap: 590, h: 2630, pt: 16, fill: \"#0066FF\", thick: [\"0.4 mm\", \"#000000\"] as BorderSide },\n} as const\n\nconst NONE = \"none\" as const\n\n/** 선두 (키워드)·[키워드] — 실측: □ 뒤 파랑 bold, ㅇ 뒤 검정 bold, 9대 과제 [ ] 파랑 bold. 20자 이내 */\nconst KEYWORD_RE = /^(\\([^()\\n]{1,24}\\)|\\[[^[\\]\\n]{1,24}\\])\\s*/u\n\nexport interface KeywordRunStyle {\n font: string\n pt: number\n bold: boolean\n ratio?: number\n spacing?: number\n color?: string\n}\n\n/**\n * 부호 + (키워드) + 나머지 인라인 마크다운 → run XML.\n * keywordColor null 이면 키워드는 굵게만(ㅇ 단계), 문자열이면 그 색 굵게(□·띠·요약).\n * emphasisColor 는 **굵게** 의 색(항목 띠: 파랑).\n */\nexport function ministryRuns(marker: string, text: string, ctx: FrameCtx, base: KeywordRunStyle, keywordColor: string | null, emphasisColor?: string): string {\n const { reg } = ctx\n const baseId = reg.char(base)\n const mapper = inlineMapper(reg, base, emphasisColor)\n let out = marker ? `<hp:run charPrIDRef=\"${baseId}\"><hp:t>${escapeTextXml(marker + \" \")}</hp:t></hp:run>` : \"\"\n const m = KEYWORD_RE.exec(text)\n if (m) {\n const kw = reg.char({ ...base, bold: true, color: keywordColor ?? base.color })\n out += `<hp:run charPrIDRef=\"${kw}\"><hp:t>${escapeTextXml(m[1] + \" \")}</hp:t></hp:run>`\n text = text.slice(m[0].length)\n }\n return out + generateRuns(text, baseId, mapper)\n}\n\n/** 렌더 텍스트(강조 문법 제거) — 폭 계산용 */\nfunction plain(text: string): string {\n return text.replace(/\\*\\*([^*]+)\\*\\*/g, \"$1\").replace(/\\*([^*]+)\\*/g, \"$1\").replace(/`([^`]+)`/g, \"$1\")\n}\n\nfunction textW(text: string, font: string, pt: number): number {\n return measureTextWidth(text, pt * 100, 100, { faceClass: faceClassForGen(font) })\n}\n\n// ─── 표지 ───────────────────────────────────────────\n\nexport interface MinistryCoverInput { title: string; date: string; org?: string; label?: string }\n\n/**\n * 표지 — [대외주의 박스 우상단] → 빈 줄 → [파란 바 / 제목 HY헤드라인M 32 / 파란 바] → 빈 줄 → 날짜 24 → 기관명.\n * 실측 세로 배치: 라벨 y59.5, 바 y228.5·329.5, 날짜 y651 (본문 상단 y56.7 기준).\n */\nexport function buildMinistryCover(inp: MinistryCoverInput, ctx: FrameCtx): string[] {\n const { reg, bf } = ctx\n const c = MINISTRY.cover\n const out: string[] = []\n const blank = (pt = 15) => para(\"\", reg.para({ align: \"LEFT\", lineSp: 145 }), reg.char({ font: MINISTRY.bodyFont, pt }))\n const center = reg.para({ align: \"CENTER\", lineSp: 130 })\n if (inp.label) {\n const red: BorderSide = [\"0.12 mm\", \"#FF0000\"]\n const box = bf.get({ t: red, b: red, l: red, r: red })\n const cL = reg.char({ font: MINISTRY.bodyFont, pt: c.labelPt, color: \"#FF0000\" })\n const cell = tc({ bf: box, row: 0, col: 0, w: c.labelW, h: c.labelH, paras: para(inp.label, center, cL) })\n out.push(host(ftbl([cell], c.labelW, c.labelH, 1), reg.para({ align: \"RIGHT\", lineSp: 100 }), cL))\n } else {\n out.push(blank())\n }\n for (let i = 0; i < 6; i++) out.push(blank())\n // 제목 표 — 바 두 줄은 본문폭(실측 476pt ≈ W−566), 제목칸 95pt\n const w = ctx.W - 566\n const barTop = bf.get({ t: NONE, b: NONE, l: NONE, r: NONE, fill: c.barDark })\n const barBot = bf.get({ t: NONE, b: NONE, l: NONE, r: NONE, fill: c.barLight })\n const fit = fitOneLine(inp.title, MINISTRY.headFont, c.titlePt, w - 800, 24)\n const cT = reg.char({ font: MINISTRY.headFont, pt: fit.pt, ratio: fit.ratio, spacing: fit.spacing })\n const c1 = reg.char({ font: MINISTRY.bodyFont, pt: 1 })\n const barP = reg.para({ align: \"CENTER\", lineSp: 70 })\n const rows = [\n tc({ bf: barTop, row: 0, col: 0, w, h: c.barH, paras: para(\"\", barP, c1) }),\n tc({ bf: 1, row: 1, col: 0, w, h: c.titleH, paras: para(inp.title, center, cT), name: \"__kordoc_h1\" }),\n tc({ bf: barBot, row: 2, col: 0, w, h: c.barH, paras: para(\"\", barP, c1) }),\n ]\n out.push(host(ftbl(rows, w, c.barH * 2 + c.titleH, 1), reg.para({ align: \"CENTER\", lineSp: 100 }), cT))\n for (let i = 0; i < 13; i++) out.push(blank())\n out.push(para(inp.date, center, reg.char({ font: MINISTRY.bodyFont, pt: c.datePt })))\n if (inp.org) {\n for (let i = 0; i < 3; i++) out.push(blank())\n out.push(para(inp.org, center, reg.char({ font: MINISTRY.headFont, pt: c.datePt })))\n }\n return out\n}\n\n// ─── 목차 ───────────────────────────────────────────\n\nexport interface MinistryTocChapter { title: string; subs: string[]; attach?: boolean }\n\n/**\n * 목차 — 회색 테두리 박스 안에 \"목 차\"(HY헤드라인M 24 #000080) + \"Ⅰ. 제목\"(17) + \"1. 절\"(15) + \"[별첨] 제목\".\n * 원본 박스(둥근 모서리·탭)는 그림이라 테두리 표로 대신한다. 쪽번호는 조판 전에 알 수 없어 넣지 않는다.\n */\nexport function buildMinistryToc(chapters: MinistryTocChapter[], ctx: FrameCtx): string[] {\n const { reg, bf } = ctx\n const t = MINISTRY.toc\n const w = ctx.W - 1200\n const pad = 2000\n const cLabel = reg.char({ font: MINISTRY.headFont, pt: t.labelPt, color: t.labelColor })\n const cCh = reg.char({ font: MINISTRY.headFont, pt: t.chapterPt })\n const cSub = reg.char({ font: MINISTRY.headFont, pt: t.subPt })\n const pLabel = reg.para({ align: \"LEFT\", lineSp: 130, left: pad, before: 1200, after: 2400 })\n const pCh = reg.para({ align: \"LEFT\", lineSp: 130, left: pad, before: 2000 })\n const pSub = reg.para({ align: \"LEFT\", lineSp: 130, left: pad + 1400, before: 1200 })\n const paras: string[] = [para(\"목 차\", pLabel, cLabel)]\n let h = 1200 + Math.round(t.labelPt * 130) + 2400\n let roman = 0\n for (const ch of chapters) {\n if (ch.attach) {\n paras.push(para(`[별첨] ${stripAttachPrefix(ch.title)}`, pCh, cCh))\n } else {\n roman++\n paras.push(para(`${romanOf(roman)}. ${ch.title}`, pCh, cCh))\n }\n h += 2000 + Math.round(t.chapterPt * 130)\n for (let i = 0; i < ch.subs.length; i++) {\n paras.push(para(`${i + 1}. ${ch.subs[i]}`, pSub, cSub))\n h += 1200 + Math.round(t.subPt * 130)\n }\n }\n // 실측 목차 박스는 쪽 높이의 82% — 항목이 적어도 박스는 쪽을 채운다(A4 본문 257mm 기준 220mm)\n h = Math.max(h + 3000, TOC_MIN_H)\n const box = bf.get({ t: t.border, b: t.border, l: t.border, r: t.border })\n const cell = tc({ bf: box, row: 0, col: 0, w, h, paras: paras.join(\"\"), vAlign: \"TOP\", name: \"__kordoc_toc\" })\n const hostP = reg.para({ align: \"CENTER\", lineSp: 100 })\n return [host(ftbl([cell], w, h, 1), hostP, cCh, ` pageBreak=\"1\"`)]\n}\n\nconst TOC_MIN_H = 62000\n\n/** \"별첨\"·\"[별첨]\"·\"별 첨 :\" 선두 표시 제거 */\nexport function stripAttachPrefix(title: string): string {\n return title.replace(/^\\[?\\s*별\\s*첨\\s*\\]?\\s*[::]?\\s*/u, \"\")\n}\n\n/** 로마숫자 Ⅰ~Ⅻ 단일 문자, 초과는 조합 */\nexport function romanOf(n: number): string {\n if (n >= 1 && n <= 12) return String.fromCodePoint(0x215f + n)\n const t: [number, string][] = [[10, \"Ⅹ\"], [9, \"Ⅸ\"], [5, \"Ⅴ\"], [4, \"Ⅳ\"], [1, \"Ⅰ\"]]\n let s = \"\"\n for (const [v, r] of t) while (n >= v) { s += r; n -= v }\n return s\n}\n\n// ─── 장 띠 (h2) ─────────────────────────────────────\n\nexport function buildMinistryChapterBand(roman: string, title: string, ctx: FrameCtx, before: number): { xml: string; overflow: boolean } {\n const { reg, bf } = ctx\n const c = MINISTRY.chapter\n const w = ctx.W\n const text = `${roman}. ${plain(title)}`\n const fit = fitOneLine(text, MINISTRY.headFont, c.pt, w - 1400, c.pt - 2)\n const band = bf.get({ t: c.line, b: c.line, l: NONE, r: NONE, fill: { gradient: [...c.fill], type: \"LINEAR\", angle: 90 } })\n const cT = reg.char({ font: MINISTRY.headFont, pt: fit.pt, ratio: fit.ratio, spacing: fit.spacing })\n const p = reg.para({ align: \"LEFT\", lineSp: 130, left: 500 })\n const cell = tc({ bf: band, row: 0, col: 0, w, h: c.h, paras: para(text, p, cT), name: \"__kordoc_h2\" })\n return { xml: host(ftbl([cell], w, c.h, 1, { bottomGap: 800 }), reg.para({ align: \"LEFT\", lineSp: 100, before, keepWithNext: true }), cT), overflow: fit.overflow }\n}\n\n// ─── 절 띠 (h3) — 파란 숫자칸 + 밑줄 제목 ───────────\n\nexport function buildMinistrySectionBand(n: number, title: string, ctx: FrameCtx, before: number): string {\n const { reg, bf } = ctx\n const s = MINISTRY.section\n const t = plain(title)\n const titleW = Math.min(ctx.W - s.numW, Math.max(6000, textW(t, MINISTRY.headFont, s.pt) + 1600))\n const numBf = bf.get({ t: s.border, b: s.border, l: s.border, r: s.border, fill: s.fill })\n const titleBf = bf.get({ t: NONE, b: s.underline, l: NONE, r: NONE })\n const cNum = reg.char({ font: MINISTRY.headFont, pt: s.pt, color: \"#FFFFFF\" })\n const cT = reg.char({ font: MINISTRY.headFont, pt: s.pt })\n const center = reg.para({ align: \"CENTER\", lineSp: 130 })\n const left = reg.para({ align: \"LEFT\", lineSp: 130, left: 300 })\n const row = tc({ bf: numBf, row: 0, col: 0, w: s.numW, h: s.h, paras: para(String(n), center, cNum) })\n + tc({ bf: titleBf, row: 0, col: 1, w: titleW, h: s.h, paras: para(t, left, cT), name: \"__kordoc_h3\" })\n return host(ftbl([row], s.numW + titleW, s.h, 2, { bottomGap: 900 }), reg.para({ align: \"LEFT\", lineSp: 100, before, keepWithNext: true }), cT)\n}\n\n// ─── 소제목 박스 (h4) — 남색 채움 흰 글자 ─────────────\n\nexport function buildMinistrySubheadBox(n: number, title: string, ctx: FrameCtx, before: number): string {\n const { reg, bf } = ctx\n const s = MINISTRY.subhead\n const text = `${n}. ${plain(title)}`\n const w = Math.min(ctx.W, textW(text, MINISTRY.headFont, s.pt) + 1400)\n const box = bf.get({ t: NONE, b: NONE, l: NONE, r: NONE, fill: s.fill })\n const cT = reg.char({ font: MINISTRY.headFont, pt: s.pt, color: \"#FFFFFF\" })\n const p = reg.para({ align: \"LEFT\", lineSp: 130, left: 400 })\n const cell = tc({ bf: box, row: 0, col: 0, w, h: s.h, paras: para(text, p, cT), name: \"__kordoc_h4\" })\n return host(ftbl([cell], w, s.h, 1, { bottomGap: 900 }), reg.para({ align: \"LEFT\", lineSp: 100, before, keepWithNext: true }), cT)\n}\n\n// ─── 항목 띠 (h5) — 하늘색 띠 + ① ─────────────────────\n\nexport function buildMinistryItemBand(n: number, text: string, ctx: FrameCtx, before: number): string {\n const { reg, bf } = ctx\n const s = MINISTRY.item\n const w = ctx.W\n const band = bf.get({ t: s.line, b: s.line, l: NONE, r: NONE, fill: s.fill })\n const base: KeywordRunStyle = { font: MINISTRY.bandFont, pt: s.pt, bold: false }\n // 한 줄 초과 방어 — 원본 띠 글은 전부 한 줄. 넘치면 장평·자간만 줄인다(글꼴 크기 유지)\n const f = fitOneLine(plain(text), MINISTRY.bandFont, s.pt, w - 1800, s.pt)\n const styled = f.overflow || (f.ratio === 100 && f.spacing === 0) ? base : { ...base, ratio: f.ratio, spacing: f.spacing }\n const runs = ministryRuns(circledNumber(n - 1), text, ctx, styled, MINISTRY.blue, MINISTRY.blue)\n const p = reg.para({ align: \"LEFT\", lineSp: 130, left: 300 })\n const cell = tc({ bf: band, row: 0, col: 0, w, h: s.h, paras: `<hp:p paraPrIDRef=\"${p}\" styleIDRef=\"0\">${runs}</hp:p>`, name: \"__kordoc_h5\" })\n return host(ftbl([cell], w, s.h, 1, { bottomGap: 700 }), reg.para({ align: \"LEFT\", lineSp: 100, before, keepWithNext: true }), reg.char(base))\n}\n\n// ─── 요약박스 (인용문) ──────────────────────────────\n\n/**\n * 연노랑 요약박스 — 줄마다 ▪ 함초롬바탕 13(선두 키워드 파랑 bold, **굵게** 검정 bold), `*`·※ 줄은 맑은 고딕 11 각주.\n * 실측: 박스 476×89.5pt(3줄 + 각주 1줄), 문단 좌우 여백 ≈ 3pt.\n */\nexport function buildMinistrySummaryBox(text: string, ctx: FrameCtx): string {\n const { reg, bf } = ctx\n const s = MINISTRY.summary\n const w = ctx.W - 600\n const avail = w - 280 - 600\n // ▪ 부호 + 탭(내어쓰기용 자동 탭) — 둘째 줄이 첫 줄 내용과 같은 x 에서 시작\n const lay = markerLayout(MINISTRY.bodyFont, s.pt, 0, \"▪\")\n const pItem = reg.para({ align: \"LEFT\", lineSp: 140, left: 300, right: 300, indent: -lay.hang, autoTab: true })\n const pRef = reg.para({ align: \"LEFT\", lineSp: 130, left: 300 + lay.hang, right: 300 })\n const baseItem: KeywordRunStyle = { font: MINISTRY.bodyFont, pt: s.pt, bold: false }\n const cRef = reg.char({ font: MINISTRY.refFont, pt: s.refPt })\n let h = 0\n const paras = text.split(\"\\n\").map((raw) => raw.trim()).filter(Boolean).map((line) => {\n const isRef = /^(\\*|※)/.test(line)\n if (isRef) {\n h += Math.round(s.refPt * 100 * 1.3) * simulateWrap(line, avail - lay.hang, avail - lay.hang, s.refPt * 100, 100, \"keep\", { faceClass: faceClassForGen(MINISTRY.refFont) }).lines\n return `<hp:p paraPrIDRef=\"${pRef}\" styleIDRef=\"0\">${generateRuns(line, cRef, inlineMapper(reg, { font: MINISTRY.refFont, pt: s.refPt, bold: false }))}</hp:p>`\n }\n const body = line.replace(/^[▪■□○ㅇ●\\-–ㆍ·•]\\s*/u, \"\")\n h += Math.round(s.pt * 100 * 1.4) * simulateWrap(plain(body), avail - lay.hang, avail - lay.hang, s.pt * 100, 100, \"keep\", { faceClass: faceClassForGen(MINISTRY.bodyFont) }).lines\n return `<hp:p paraPrIDRef=\"${pItem}\" styleIDRef=\"0\">${markerRunXml(\"▪\", reg.char(baseItem), lay)}${ministryRuns(\"\", body, ctx, baseItem, MINISTRY.blue)}</hp:p>`\n })\n h += 280 + 600\n const box = bf.get({ t: \"thin\", b: \"thin\", l: \"thin\", r: \"thin\", fill: s.fill })\n const cell = tc({ bf: box, row: 0, col: 0, w, h, paras: paras.join(\"\"), vAlign: \"TOP\", name: \"__kordoc_summary\" })\n return host(ftbl([cell], w, h, 1, { bottomGap: 900 }), reg.para({ align: \"CENTER\", lineSp: 100, before: 400 }), reg.char(baseItem))\n}\n\n// ─── 별첨 띠 (h2 \"별첨 …\") ──────────────────────────\n\nexport function buildMinistryAttachBand(title: string, ctx: FrameCtx, before: number): string {\n const { reg, bf } = ctx\n const a = MINISTRY.attach\n const w = ctx.W\n const titleW = w - a.labelW - a.gap\n const labelBf = bf.get({ t: \"thin\", b: a.thick, l: \"thin\", r: a.thick, fill: a.fill })\n const gapBf = bf.get({ t: NONE, b: NONE, l: NONE, r: NONE })\n const titleBf = bf.get({ t: \"thin\", b: a.thick, l: \"thin\", r: a.thick })\n const t = stripAttachPrefix(plain(title))\n const fit = fitOneLine(t, MINISTRY.headFont, a.pt, titleW - 800, a.pt - 3)\n const cLabel = reg.char({ font: MINISTRY.headFont, pt: a.pt, color: \"#FFFFFF\" })\n const cT = reg.char({ font: MINISTRY.headFont, pt: fit.pt, ratio: fit.ratio, spacing: fit.spacing })\n const center = reg.para({ align: \"CENTER\", lineSp: 130 })\n const row = tc({ bf: labelBf, row: 0, col: 0, w: a.labelW, h: a.h, paras: para(\"별 첨\", center, cLabel) })\n + tc({ bf: gapBf, row: 0, col: 1, w: a.gap, h: a.h, paras: para(\"\", center, cT) })\n + tc({ bf: titleBf, row: 0, col: 2, w: titleW, h: a.h, paras: para(t, center, cT), name: \"__kordoc_h2\" })\n return host(ftbl([row], w, a.h, 3, { bottomGap: 900 }), reg.para({ align: \"LEFT\", lineSp: 100, before, keepWithNext: true }), cT)\n}\n\n/** h2 텍스트가 별첨 띠인지 — \"별첨\", \"[별첨]\", \"별 첨 : …\" */\nexport function isAttachHeading(text: string): boolean {\n return /^\\[?\\s*별\\s*첨\\s*\\]?/u.test(text.trim())\n}\n","/**\n * 공문서 생성 엔진 v5 — 아웃라인(outline.ts) + 위계 스킴(gongmun-scheme.ts) → section0.xml.\n *\n * 담당 프리셋: 기안문(official)·보고서(report)·계획서(plan)·통지(notice)·회의록(minutes)·업무보고(ministry).\n * (개조식 gaejosik = 중앙부처 표지·목차 양식, 보도자료 press, 범용 마크다운은 gen-section.ts)\n * 업무보고(ministry)는 재경부 실측 골격(gen-frame-ministry.ts) — 장 띠·절 띠·소제목 박스·항목 띠·요약박스·별첨 띠.\n *\n * 원칙\n * - 입력 형태(#/##/-/□/1.)와 무관하게 아웃라인 depth 하나로 정규화하고 스킴이 부호·글꼴을 정한다.\n * - □ 대항목·제목·장 제목은 한 줄 강제(fit-line). 실측 95%가 한 줄.\n * - 두문·결문·제목표·요약박스는 실측 골격표(gen-frame-seoul.ts).\n * - charPr/paraPr는 StyleRegistry 동적 발급 — 손계산 id 파티션 없음.\n */\n\nimport { type MdBlock, generateParagraph, generateRuns } from \"./md-runs.js\"\nimport { type ResolvedGongmun, GongmunNumberer, computeSuppression, mmToHwpunit } from \"./gongmun.js\"\nimport { type Scheme, type LevelStyle, pickScheme, taHu } from \"./gongmun-scheme.js\"\nimport { buildOutline, type Outline, type OutlineNode } from \"./outline.js\"\nimport { StyleRegistry, inlineMapper } from \"./style-registry.js\"\nimport { TableBfRegistry } from \"./gen-table-bf.js\"\nimport { fitOneLine, fitParagraph, fitCharBreaks } from \"./fit-line.js\"\nimport { faceClassForGen } from \"./text-metrics.js\"\nimport { markerLayout, markerRunXml } from \"./gen-marker.js\"\nimport { polishGongmunText } from \"./gongmun-typo.js\"\nimport { generateTable, generateHtmlTableXml, requiredTableWidth, DATA_TABLE_INSET, resetTableIds, type GongmunTableStyle } from \"./gen-table.js\"\nimport { type ProfileRemap } from \"./gen-profile.js\"\nimport { ImageRegistry, splitImageRefs } from \"./gen-image.js\"\nimport { type ResolvedPage } from \"./gen-page.js\"\nimport { type ChartPart, generateSecPr } from \"./gen-section.js\"\nimport { generateEquationParagraph } from \"./equation-generate.js\"\nimport { parseChartFence, buildChartSpaceXml, buildChartElementXml } from \"./chart-gen.js\"\nimport { CHART_TABLE_ID_BASE } from \"./geometry.js\"\nimport { PARA_CODE, CHAR_CODE, NS_SECTION, NS_PARA, escapeXml, newPageNumCtrl, pageHidingCtrl } from \"./gen-ids.js\"\nimport { hasEndMark } from \"./gen-gongmun-extra.js\"\nimport { buildNoticeHead, buildNoticeFoot, isInternalApproval } from \"./gen-docframe.js\"\nimport {\n type FrameCtx, buildDocHeadTable, buildDocFootTable, buildReportTitleTable, buildSummaryBox,\n buildApprovalSeoul, buildReportCover, splitTitleName, resetFrameTableIds, buildChapterBand, CHAPTER_BAND_DEFAULT,\n} from \"./gen-frame-seoul.js\"\nimport { formatGaejosikDate } from \"./gaejosik.js\"\nimport {\n buildMinistryCover, buildMinistryToc, buildMinistryChapterBand, buildMinistrySectionBand, buildMinistrySubheadBox,\n buildMinistryItemBand, buildMinistrySummaryBox, buildMinistryAttachBand, isAttachHeading, ministryRuns, romanOf, MINISTRY,\n type MinistryTocChapter,\n} from \"./gen-frame-ministry.js\"\n\nexport const V5_PRESETS = new Set([\"official\", \"report\", \"plan\", \"notice\", \"minutes\", \"ministry\"])\nexport function usesV5Engine(preset: string): boolean { return V5_PRESETS.has(preset) }\n\nexport interface GongmunEngineDeps {\n reg: StyleRegistry\n bfReg: TableBfRegistry\n remap: ProfileRemap | null\n images: ImageRegistry | null\n page: ResolvedPage | null\n chartParts: ChartPart[]\n}\n\nexport interface GongmunEngineResult {\n xml: string\n warnings: string[]\n /** 실제 적용된 스킴 (헤더 본문 글꼴 결정용) */\n scheme: Scheme\n}\n\nconst ROMAN = [\"Ⅰ\", \"Ⅱ\", \"Ⅲ\", \"Ⅳ\", \"Ⅴ\", \"Ⅵ\", \"Ⅶ\", \"Ⅷ\", \"Ⅸ\", \"Ⅹ\", \"Ⅺ\", \"Ⅻ\"]\nexport function chapterLabel(index: number, style: \"roman\" | \"number\"): string {\n return style === \"roman\" ? `${ROMAN[(index - 1) % 12]}.` : `${index}.`\n}\n\n/** 렌더 텍스트(강조 문법 제거) — 폭 계산용 */\nfunction plain(text: string): string {\n return text.replace(/\\*\\*([^*]+)\\*\\*/g, \"$1\").replace(/\\*([^*]+)\\*/g, \"$1\").replace(/`([^`]+)`/g, \"$1\").replace(/!\\[[^\\]]*\\]\\([^)]*\\)/g, \"\")\n}\n\nexport function buildGongmunSectionV5(blocks: MdBlock[], gongmun: ResolvedGongmun, deps: GongmunEngineDeps, theme: import(\"./gen-ids.js\").ResolvedTheme): GongmunEngineResult {\n resetTableIds(); resetFrameTableIds()\n const { reg, bfReg, remap, images, page } = deps\n const warnings: string[] = []\n const g = gongmun\n const preset = g.preset\n const isReport = preset === \"report\" || preset === \"plan\"\n const isMinistry = preset === \"ministry\"\n const W = mmToHwpunit(210 - g.margins.left - g.margins.right)\n // 1차 아웃라인(스킴 미정) — 본문 □ 부호 자동감지용. 업무보고는 h3~h6 을 서식 틀로, 인용문은 어디서나 요약박스로\n const pre = buildOutline(blocks, isMinistry\n ? { gaejosik: true, consumeTitle: true, summaryFromQuote: true, quoteBox: true, headingFrames: true, keepMarkers: true }\n : { gaejosik: true, consumeTitle: true, summaryFromQuote: isReport })\n const scheme = pickScheme(g, pre.hasBoxMarkers)\n const gaejosik = scheme.kind === \"gaejosik\"\n const raw: Outline = gaejosik ? pre : buildOutline(blocks, { gaejosik: false, consumeTitle: true, summaryFromQuote: false })\n // 문자 다듬기(날짜·금액 묶음 빈칸, ‘’“”) — 폭 계산·방출이 같은 문자열을 보도록 조판 전에\n const outline: Outline = { ...raw, title: raw.title && polishGongmunText(raw.title), nodes: raw.nodes.map(polishNode) }\n const frame: FrameCtx = { reg, bf: bfReg, frame: scheme.frame, W }\n const lineHu = (st: LevelStyle) => Math.round(st.pt * 100 * ((st.lineSp ?? scheme.lineSp) / 100))\n const paras: string[] = []\n let pendingPageBreak = false\n\n // 표 스타일 (실측: 한컴돋움 12 헤더 bold·#DFE6F7·라벨열 #F2F2F2, 외곽 0.4/내부 0.12/헤더 이중선)\n const tblCharPr = reg.char({ font: scheme.table.font, pt: scheme.table.pt })\n const tableStyle: GongmunTableStyle = {\n totalWidth: W,\n charPr: tblCharPr,\n boldCharPr: reg.char({ font: scheme.table.font, pt: scheme.table.pt, bold: true }),\n charHeight: scheme.table.pt * 100,\n headerBf: bfReg.get({ t: \"thin\", b: \"thin\", l: \"thin\", r: \"thin\", fill: scheme.table.headerFill }),\n centerParaPr: reg.para({ align: \"CENTER\", lineSp: scheme.lineSp }),\n tblCenterParaPr: reg.para({ align: \"CENTER\", lineSp: 130 }),\n tblLeftParaPr: reg.para({ align: \"LEFT\", lineSp: 130 }),\n bfRegistry: bfReg,\n rightParaPr: reg.para({ align: \"RIGHT\", lineSp: scheme.lineSp }),\n headerFill: scheme.table.headerFill,\n labelFill: scheme.table.labelFill,\n faceClass: faceClassForGen(scheme.table.font),\n }\n\n /** 전면부가 남긴 직전 요소 — 본문 첫 □ 의 앞 간격 판정(제목표 바로 아래 첫 □ 는 반 줄) */\n let frontKind: \"start\" | \"title\" | \"summary\" = \"start\"\n // 요약박스 — 한 문장 3줄 이내, 넘치면 경고\n const pushSummary = (t: string) => {\n frontKind = \"summary\"\n const box = buildSummaryBox(polishGongmunText(t), frame)\n if (box.lines > 3) warnings.push(`요약박스가 ${box.lines}줄입니다 — 보고 목적을 한 문장(쉼표 허용) 3줄 이내 \"…하고자 함\"으로 줄이세요`)\n paras.push(box.xml)\n }\n // ─── 전면부 ───────────────────────────────────────\n const docTitle = polishGongmunText(g.docHead?.title ?? outline.title ?? \"\")\n const reportInfo = g.reportInfo && polishGongmunText(g.reportInfo)\n if (preset === \"official\") {\n if (g.docHead) paras.push(buildDocHeadTable({ ...g.docHead, title: docTitle }, frame))\n else if (outline.title) paras.push(generateParagraph(outline.title, reg.para({ align: \"CENTER\", lineSp: scheme.lineSp, after: lineHu(scheme.body) }), reg.char({ font: scheme.body.font, pt: scheme.body.pt + 2, bold: true }), undefined, 1))\n if (reportInfo) paras.push(generateParagraph(reportInfo, reg.para({ align: \"RIGHT\", lineSp: scheme.lineSp }), reg.char({ font: scheme.body.font, pt: 12 })))\n if (g.approval) paras.push(buildApprovalSeoul(g.approval, null, frame))\n } else if (isMinistry) {\n // 표지 → 목차 → 첫 장 띠(쪽번호 1). 표지·목차는 쪽번호 숨김\n if (g.cover) {\n const cover = buildMinistryCover({ title: docTitle, date: g.cover.date ?? formatGaejosikDate(new Date()), org: g.cover.org || undefined, label: g.cover.label }, frame)\n if (g.pageNumbers) cover[0] = cover[0].replace(/<hp:run charPrIDRef=\"(\\d+)\">/, `<hp:run charPrIDRef=\"$1\">${pageHidingCtrl()}`)\n paras.push(...cover)\n pendingPageBreak = true\n }\n if (g.toc && outline.chapters > 0) {\n const tocChapters: MinistryTocChapter[] = []\n for (const n of outline.nodes) {\n if (n.kind === \"chapter\") tocChapters.push({ title: plain(n.text), subs: [], attach: isAttachHeading(n.text) })\n else if (n.kind === \"heading\" && n.level === 3 && tocChapters.length) tocChapters[tocChapters.length - 1].subs.push(plain(n.text))\n }\n const toc = buildMinistryToc(tocChapters, frame)\n if (g.pageNumbers) toc[0] = toc[0].replace(/<hp:run charPrIDRef=\"(\\d+)\">/, `<hp:run charPrIDRef=\"$1\">${pageHidingCtrl()}`)\n paras.push(...toc)\n pendingPageBreak = true\n }\n if (!g.cover && !g.toc && docTitle) {\n paras.push(generateParagraph(docTitle, reg.para({ align: \"CENTER\", lineSp: scheme.lineSp, after: lineHu(scheme.body) }), reg.char({ font: scheme.frame.titleFont, pt: 20 }), undefined, 1))\n frontKind = \"title\"\n }\n } else if (isReport) {\n if (g.cover) {\n paras.push(...buildReportCover({\n title: docTitle, date: g.cover.date ?? formatGaejosikDate(new Date()).replace(/\\s\\d+\\.$/, \".\"), org: g.cover.org || undefined,\n dept: g.cover.dept, docInfo: g.docInfo ?? undefined, approval: g.approval ?? undefined,\n }, frame))\n pendingPageBreak = true\n } else if (g.approval) {\n paras.push(buildApprovalSeoul(g.approval, null, frame))\n }\n if (docTitle) {\n const t = buildReportTitleTable(docTitle, reportInfo, frame)\n if (t.overflow) warnings.push(`제목이 길어 한 줄에 담지 못했습니다(20pt·장평 85%까지 축소) — 제목을 줄이세요: \"${docTitle.slice(0, 30)}…\"`)\n if (pendingPageBreak) { paras.push(t.xml.replace(/^<hp:p /, `<hp:p pageBreak=\"1\" `).replace(/<hp:run charPrIDRef=\"(\\d+)\">/, `<hp:run charPrIDRef=\"$1\">${newPageNumCtrl(1)}`)); pendingPageBreak = false }\n else paras.push(t.xml)\n frontKind = \"title\"\n }\n // 제목 없는 보고서의 담당자 행 — 우상단 12pt (기안문 보고정보 행과 동일)\n if (!docTitle && reportInfo) paras.push(generateParagraph(reportInfo, reg.para({ align: \"RIGHT\", lineSp: scheme.lineSp }), reg.char({ font: scheme.body.font, pt: 12 })))\n if (g.summary) pushSummary(g.summary)\n else if (!outline.nodes.some((n) => n.kind === \"summary\")) warnings.push(\"보고서 요약박스가 없습니다 — 제목 직후 인용문(>)에 보고 목적을 한 문장(쉼표 허용) 3줄 이내 \\\"…하고자 함\\\"으로 넣거나 summary 옵션을 지정하세요\")\n } else {\n // 통지·회의록 — 제목 가운데 굵게, 공고번호\n if (g.noticeHead) paras.push(...buildNoticeHead(g))\n if (g.approval) paras.push(buildApprovalSeoul(g.approval, null, frame))\n if (outline.title) paras.push(generateParagraph(outline.title, reg.para({ align: \"CENTER\", lineSp: scheme.lineSp, before: 400, after: lineHu(scheme.body) }), reg.char({ font: scheme.frame.titleFont, pt: 20, bold: true }), undefined, 1))\n }\n\n // ─── 본문 ─────────────────────────────────────────\n const numberer = new GongmunNumberer(\"standard\", g.bullet2)\n const itemDepths = outline.nodes.filter((n): n is Extract<OutlineNode, { kind: \"item\" }> => n.kind === \"item\" && !n.legalMarker).map((n) => n.depth)\n const suppress = !gaejosik && g.suppressSingle ? computeSuppression(itemDepths) : null\n let itemSeq = 0\n /** □ 앞 간격(HWPUNIT). 빈 문단(15pt×180%=27pt)을 두면 ㅇ→□ 기준선 55pt 로 본문 행간(30pt)의 1.8배 구멍이 난다(실렌더 캡처).\n * 10pt 면 ㅇ→□ 37pt·잉크 간격 22pt — 실결재의 그룹 사이 흰 공간(본문 13~17pt 대비 23~25pt, 1.5배) 비율 */\n const BOX_BLANK_HU = 1000\n /** 띠 제목 아래 첫 □·요약박스 뒤 띠 간격 */\n const BOX_GAP_AFTER_BAND = 1200\n /** 본문 뒤 띠 제목 앞 간격 */\n const BAND_BEFORE_HU = 2000\n let prevKind: OutlineNode[\"kind\"] | \"start\" = frontKind\n /** 직전 항목의 depth — 연속 □(하위 항목 없이 □ 다음 □) 사이엔 빈 줄을 넣지 않는다 (실측 52:48 반반, 실무자 요청) */\n let prevItemDepth = -1\n /** 다음 노드 — □ 의 keepWithNext 는 다음이 하위 항목·※ 일 때만. □→□→□→표 사슬이 이어지면 표가 안 들어갈 때 장 전체가 다음 쪽으로 밀린다(실렌더) */\n let nextNode: OutlineNode | undefined\n let tableSeq = 0\n /** 업무보고 서식 틀 번호 — 절(장마다 리셋)·소제목(절마다)·항목 띠(소제목마다) */\n let sectionSeq = 0, subheadSeq = 0, itemBandSeq = 0\n /** 업무보고 첫 본문 문단에 쪽번호 1 리셋 */\n let pendingNewPageNum = isMinistry && (!!g.cover || !!g.toc)\n let chapterStyle: \"band\" | \"roman\" | \"number\" | \"box\" | \"none\" = g.h2Marker === \"box\" || g.h2Marker === \"number\" || g.h2Marker === \"none\" || g.h2Marker === \"band\" ? g.h2Marker : \"roman\"\n if (!gaejosik) chapterStyle = \"number\" // 기안문 본문의 h2는 1. 항목이 된다 (아래 chapter 분기)\n\n const leadLeft = (depth: number, pt: number) => (scheme.levels[Math.min(depth, 7)]?.leadTa ?? 0) * taHu(pt)\n\n const renderItem = (node: Extract<OutlineNode, { kind: \"item\" }>, styleId = 0): string => {\n const depth = Math.min(node.depth, 7)\n const sub = gaejosik && node.legalMarker\n const st: LevelStyle = sub ? { ...scheme.sub, leadTa: (() => { const d = node.legalMarker ? legalDepthOf(node.legalMarker) : 0; return 2 * d })() } : scheme.levels[depth]\n let marker: string\n if (sub) marker = node.legalMarker!\n else if (gaejosik) marker = scheme.marker(depth, 0)\n else { const sup = suppress ? suppress[itemSeq] : false; marker = numberer.next(depth, sup); itemSeq++ }\n // ❶⇒↳(업무보고 보존 부호)는 스킴 부호 대신 그 글리프\n const mk = isMinistry && node.marker ? node.marker : marker\n const lay = markerLayout(st.font, st.pt, st.leadTa, mk)\n // 첫 줄(탭 뒤)과 둘째 줄 이후 내용 폭이 같다 — 둘 다 left + hang 에서 시작\n const textW = W - lay.left - lay.hang\n let ratio = 100, spacing = 0, charBreaks = false\n if (st.oneLine) {\n // □ 는 크기를 줄이지 않는다(형제 □ 끼리 크기·굵기가 달라 보이던 결함, 라운드 3) — 장평 90·자간 -5 까지만.\n // 그래도 넘치면 억지로 우겨넣지 않고 자연 줄바꿈(내어쓰기) + 경고: 문장을 줄이는 게 정답\n const fit = fitOneLine(plain(node.text), st.font, st.pt, textW, st.pt, 90)\n if (fit.overflow) warnings.push(`□ 항목이 한 줄에 담기지 않아 두 줄로 꺾입니다 — 문장을 줄이세요(장평 90%·자간 -5 로도 초과): \"${node.text.slice(0, 30)}…\"`)\n else { ratio = fit.ratio; spacing = fit.spacing }\n } else {\n // 한 줄보다 긴 어절(가운뎃점 목록 등)이 있으면 글자 단위 + 목록 구분자 뒤에서만 끊는 압축. 그 밖엔 짧은 꼬리 줄 올리기·\n // 벌어진 줄 완화(자간 -1%씩 Shift+Alt+N 관행·장평 조합). autoFit false 면 압축 없이 줄나눔만 고른다\n const t = plain(node.text)\n const cb = fitCharBreaks(t, st.font, st.pt, textW, textW, g.autoFitMinRatio ?? 101)\n const f = cb ?? (g.autoFitMinRatio !== null ? fitParagraph(t, st.font, st.pt, textW, textW, g.autoFitMinRatio) : null)\n if (f) { ratio = f.ratio; spacing = f.spacing }\n charBreaks = !!cb\n }\n // 압축은 내용 run 에만 — 부호는 형제 항목과 같은 모양(부호 폭이 줄어도 내용 시작은 탭이 고정)\n const base = { font: st.font, pt: st.pt, bold: st.bold, ratio, spacing }\n // □ 앞 빈 줄(실측 76%) — 장·제목·요약 직후 첫 □ 와 **연속 □**(직전이 하위 항목 없는 □, 실측 52%·실무자 요청) 는 제외.\n // 띠 표 장 제목 바로 아래 첫 □ 는 밑줄에 붙지 않게 반 줄\n const consecutiveBox = prevKind === \"item\" && prevItemDepth === 0 && depth === 0\n // 하위 항목 뒤 □ 앞 간격은 BOX_BLANK_HU(10pt) — 빈 문단 27pt 는 본문 행간의 1.8배 구멍(실렌더, 라운드 3).\n // 띠 제목·제목표 바로 아래 첫 □ 는 반 줄(12pt): 제목표 하변 괘선에 □ 가 붙어 보이는 것을 막는다(시각 픽스처 gongmun-report)\n const afterBand = depth === 0 && ((prevKind === \"chapter\" && chapterStyle === \"band\") || (prevKind === \"title\" && !!st.blankBefore))\n const before = afterBand ? BOX_GAP_AFTER_BAND\n : st.blankBefore && !consecutiveBox && prevKind !== \"chapter\" && prevKind !== \"start\" && prevKind !== \"summary\" ? BOX_BLANK_HU : 0\n // 어절 줄바꿈(BREAK_WORD — 이름 역전 주의) + 양쪽정렬 + 외톨이줄 보호. 글자 단위(라운드 2)는 \"동대/문\"·\"실/국\"처럼\n // 낱말을 쪼갰다(유저 지시 2026-09-23). 긴 어절이 넘어가 앞 줄이 벌어지는 것은 fitParagraph 가 자간으로 완화한다.\n const keepNext = !!st.keepWithNext && !!nextNode && ((nextNode.kind === \"item\" && nextNode.depth > depth) || nextNode.kind === \"ref\")\n const paraSpec = { align: \"JUSTIFY\" as const, left: lay.left, indent: -lay.hang, before, lineSp: st.lineSp ?? scheme.lineSp, keepWithNext: keepNext, keepWord: !charBreaks, autoTab: lay.hang > 0, widowOrphan: true }\n const markerRun = mk ? markerRunXml(mk, reg.char({ font: st.font, pt: st.pt, bold: st.bold }), lay) : \"\"\n if (isMinistry) {\n // 실측: 문단 뒤 6~7pt(줄피치 21.7 → 문단 간 27.6~29). (키워드)는 □·❶ 파랑 bold / ㅇ 이하 검정 bold\n const paraId = reg.para({ ...paraSpec, after: 600 })\n const runs = markerRun + ministryRuns(\"\", node.text, frame, base, depth === 0 ? MINISTRY.blue : null)\n return `<hp:p paraPrIDRef=\"${paraId}\" styleIDRef=\"${styleId}\">${runs}</hp:p>`\n }\n const paraId = reg.para(paraSpec)\n return `<hp:p paraPrIDRef=\"${paraId}\" styleIDRef=\"${styleId}\">${markerRun}${generateRuns(node.text, reg.char(base), inlineMapper(reg, base))}</hp:p>`\n }\n\n const renderRef = (node: Extract<OutlineNode, { kind: \"ref\" }>): string => {\n const st = scheme.ref\n // 업무보고 각주는 * (실측 맑은 고딕 12, 선두 4칸) — ※ 는 원문에 없다\n const marker = isMinistry ? \"*\" : \"※\"\n const lay = markerLayout(st.font, st.pt, 0, marker)\n const left = isMinistry ? st.leadTa * taHu(st.pt) : leadLeft(node.depth, st.pt)\n const textW = W - left - lay.hang\n const t = plain(node.text)\n const cb = fitCharBreaks(t, st.font, st.pt, textW, textW, g.autoFitMinRatio ?? 101)\n const f = cb ?? (g.autoFitMinRatio !== null ? fitParagraph(t, st.font, st.pt, textW, textW, g.autoFitMinRatio) : null)\n const base = { font: st.font, pt: st.pt, bold: st.bold, ratio: f?.ratio ?? 100, spacing: f?.spacing ?? 0 }\n const paraId = reg.para({ align: \"JUSTIFY\", left, indent: -lay.hang, after: isMinistry ? 400 : 0, lineSp: isMinistry ? 130 : st.lineSp ?? scheme.lineSp, keepWord: !cb, autoTab: true, widowOrphan: true })\n const markerRun = markerRunXml(marker, reg.char({ font: st.font, pt: st.pt, bold: st.bold }), lay)\n return `<hp:p paraPrIDRef=\"${paraId}\" styleIDRef=\"0\">${markerRun}${generateRuns(node.text, reg.char(base), inlineMapper(reg, base))}</hp:p>`\n }\n\n const renderPara = (node: Extract<OutlineNode, { kind: \"para\" }>): string => {\n const st = scheme.body\n if (images) {\n const { text: rest, urls } = splitImageRefs(node.text)\n if (urls.length > 0 && !rest.trim()) {\n const pics = urls.map((u) => { const part = images.take(u); return part ? images.inlinePicXml(part) : null })\n if (pics.every(Boolean)) return `<hp:p paraPrIDRef=\"${reg.para({ align: \"CENTER\", lineSp: scheme.lineSp })}\" styleIDRef=\"0\"><hp:run charPrIDRef=\"${reg.char({ font: st.font, pt: st.pt })}\">${pics.join(\"\")}</hp:run></hp:p>`\n }\n }\n let ratio = 100, spacing = 0, charBreaks = false\n if (!node.align) {\n const t = plain(node.text)\n const cb = fitCharBreaks(t, st.font, st.pt, W, W, g.autoFitMinRatio ?? 101)\n const f = cb ?? (g.autoFitMinRatio !== null ? fitParagraph(t, st.font, st.pt, W, W, g.autoFitMinRatio) : null)\n if (f) { ratio = f.ratio; spacing = f.spacing }\n charBreaks = !!cb\n }\n const base = { font: st.font, pt: st.pt, bold: st.bold, ratio, spacing }\n const paraId = reg.para({ align: node.align ?? \"JUSTIFY\", lineSp: scheme.lineSp, keepWord: !charBreaks, widowOrphan: true })\n return generateParagraph(node.text, paraId, reg.char(base), inlineMapper(reg, base))\n }\n\n const renderChapter = (node: Extract<OutlineNode, { kind: \"chapter\" }>): string => {\n const st = scheme.chapter\n if (isMinistry) {\n sectionSeq = 0; subheadSeq = 0; itemBandSeq = 0\n // 실측: 장(Ⅰ·Ⅱ·Ⅲ)·별첨은 전부 새 쪽 첫머리 — 첫 장 외엔 쪽 나눔\n const first = prevKind === \"start\" || prevKind === \"title\"\n const xml = isAttachHeading(node.text)\n ? buildMinistryAttachBand(node.text, frame, 0)\n : (() => {\n const band = buildMinistryChapterBand(romanOf(node.index), node.text, frame, 0)\n if (band.overflow) warnings.push(`장 제목이 띠 한 줄에 담기지 않아 축소했습니다 — 제목을 줄이세요: \"${node.text.slice(0, 30)}…\"`)\n return band.xml\n })()\n return first ? xml : xml.replace(/^<hp:p /, `<hp:p pageBreak=\"1\" `)\n }\n if (chapterStyle === \"band\") {\n // 요약박스 직후엔 반 줄(붙지 않게), 본문 뒤엔 실측 빈 줄보다 조금 넉넉히(20pt)\n const before = prevKind === \"start\" || prevKind === \"title\" ? 0 : prevKind === \"summary\" ? BOX_GAP_AFTER_BAND : BAND_BEFORE_HU\n const band = buildChapterBand(chapterLabel(node.index, \"roman\").replace(/\\.$/, \"\"), plain(node.text), frame, { ...CHAPTER_BAND_DEFAULT, color: g.bandColor, textColor: g.bandTextColor, titleFont: st.font, titlePt: st.pt }, before)\n if (band.overflow) warnings.push(`장 제목이 띠 표 한 줄에 담기지 않아 축소했습니다 — 제목을 줄이세요: \"${node.text.slice(0, 30)}…\"`)\n return band.xml\n }\n const label = chapterStyle === \"none\" ? \"\" : chapterLabel(node.index, chapterStyle === \"number\" ? \"number\" : \"roman\")\n const text = label ? `${label} ${node.text}` : node.text\n const fit = fitOneLine(plain(text), st.font, st.pt, W, st.pt - 2)\n const base = { font: st.font, pt: fit.pt, bold: st.bold, ratio: fit.ratio, spacing: fit.spacing }\n const before = prevKind === \"start\" || prevKind === \"title\" || prevKind === \"summary\" ? 0 : lineHu(scheme.body)\n const paraId = reg.para({ align: \"LEFT\", before, after: Math.round(lineHu(scheme.body) * 0.3), lineSp: st.lineSp ?? scheme.lineSp, keepWithNext: true })\n return generateParagraph(text, paraId, reg.char(base), inlineMapper(reg, base), 2)\n }\n\n const renderAttach = (node: Extract<OutlineNode, { kind: \"attach\" }>, first: boolean): string => {\n const st = scheme.attach\n // 편람: '붙임' 뒤 쌍점 없이 2타. 둘째 줄부터의 선행 공백은 실측(99%) 그대로 보존\n let text = node.text\n if (/^\\s*붙\\s*임/.test(text)) text = text.replace(/^\\s*붙\\s*임\\s*[::]?\\s*/, \"붙임 \")\n else text = text.replace(/\\s+$/, \"\")\n const paraId = reg.para({ align: \"LEFT\", before: first ? lineHu(scheme.body) : 0, lineSp: st.lineSp ?? scheme.lineSp })\n const base = { font: st.font, pt: st.pt, bold: st.bold }\n return generateParagraph(text, paraId, reg.char(base), inlineMapper(reg, base))\n }\n\n const renderBlock = (node: Extract<OutlineNode, { kind: \"block\" }>, idx: number): string => {\n const b = node.block\n switch (b.type) {\n case \"table\": {\n if (!b.rows) return \"\"\n // 셀 글자 자동 축소 — 12pt로 한 줄에 안 들어가면 11·10pt (실측 셀 pt 분포 10:44·11:40·12:33)\n let style = tableStyle\n const face = faceClassForGen(scheme.table.font)\n const avail = W - DATA_TABLE_INSET\n for (const pt of [scheme.table.pt, scheme.table.pt - 1, scheme.table.pt - 2]) {\n if (pt < 9) break\n if (requiredTableWidth(b.rows, pt * 100, face) <= avail || pt === scheme.table.pt - 2) {\n if (pt !== scheme.table.pt) style = { ...tableStyle, charPr: reg.char({ font: scheme.table.font, pt }), boldCharPr: reg.char({ font: scheme.table.font, pt, bold: true }), charHeight: pt * 100 }\n break\n }\n }\n return generateTable(b.rows, theme, style, remap, tableSeq++, images)\n }\n case \"html_table\": {\n const tbl = generateHtmlTableXml(b.text || \"\", theme, tableStyle.totalWidth - DATA_TABLE_INSET, tableStyle, remap, tableSeq++, images)\n if (tbl) return `<hp:p paraPrIDRef=\"${tableStyle.rightParaPr}\" styleIDRef=\"0\"><hp:run charPrIDRef=\"${tblCharPr}\">${tbl}</hp:run></hp:p>`\n const txt = (b.text || \"\").replace(/<[^>]+>/g, \" \").replace(/\\s+/g, \" \").trim()\n return txt ? renderPara({ kind: \"para\", depth: 0, text: txt }) : \"\"\n }\n case \"code_block\": {\n if ((b.lang || \"\").toLowerCase() === \"chart\") {\n const fence = parseChartFence(b.text || \"\")\n if (fence) {\n const partName = `Chart/chart${deps.chartParts.length + 1}.xml`\n deps.chartParts.push({ name: partName, xml: buildChartSpaceXml(fence) })\n const el = buildChartElementXml(partName, fence.widthHu, fence.heightHu, CHART_TABLE_ID_BASE + idx)\n return `<hp:p paraPrIDRef=\"${tableStyle.centerParaPr}\" styleIDRef=\"0\"><hp:run charPrIDRef=\"${tblCharPr}\">${el}</hp:run></hp:p>`\n }\n }\n return (b.text || \"\").split(\"\\n\").map((line) => `<hp:p paraPrIDRef=\"${PARA_CODE}\" styleIDRef=\"0\"><hp:run charPrIDRef=\"${CHAR_CODE}\"><hp:t>${escapeXml(line || \" \")}</hp:t></hp:run></hp:p>`).join(\"\\n \")\n }\n case \"equation\": return generateEquationParagraph(b.text || \"\", idx)\n case \"hr\": return `<hp:p paraPrIDRef=\"${reg.para({ lineSp: scheme.lineSp })}\" styleIDRef=\"0\"><hp:run charPrIDRef=\"${reg.char({ font: scheme.body.font, pt: scheme.body.pt })}\"><hp:t></hp:t></hp:run></hp:p>`\n default: return \"\"\n }\n }\n\n // forEach 콜백 안에서 대입되므로 흐름 분석이 null 로 좁히지 않게 as 로 선언\n let lastTextNode = null as OutlineNode | null\n let prevAttach = false\n let lastItemFromHeading = false\n outline.nodes.forEach((node, idx) => {\n nextNode = outline.nodes[idx + 1]\n let xml = \"\"\n switch (node.kind) {\n case \"title\": break\n case \"summary\":\n if (isMinistry) { xml = buildMinistrySummaryBox(node.text, frame); break }\n if (isReport && !g.summary) { pushSummary(node.text); prevKind = node.kind; return }\n xml = renderRef({ kind: \"ref\", depth: 0, text: node.text })\n break\n case \"heading\": {\n // 업무보고 서식 틀 — h3 절 띠(숫자칸) / h4 소제목 박스 / h5+ 항목 띠 ①. 다른 프리셋은 outline 이 heading 을 내지 않는다\n const before = prevKind === \"chapter\" || prevKind === \"heading\" || prevKind === \"start\" ? 0 : BAND_BEFORE_HU\n if (node.level <= 3) { subheadSeq = 0; itemBandSeq = 0; xml = buildMinistrySectionBand(++sectionSeq, node.text, frame, before) }\n else if (node.level === 4) { itemBandSeq = 0; xml = buildMinistrySubheadBox(++subheadSeq, node.text, frame, before) }\n else xml = buildMinistryItemBand(++itemBandSeq, node.text, frame, before)\n lastItemFromHeading = true\n lastTextNode = node\n break\n }\n case \"chapter\":\n lastItemFromHeading = true\n if (!gaejosik) {\n // 기안문 본문: 장 제목은 1. 항목 (법정 8단계 최상위) — 스타일 \"개요 2\"로 h2 왕복 보존\n xml = renderItem({ kind: \"item\", depth: 0, text: node.text }, 2)\n } else if (chapterStyle === \"box\") {\n xml = renderItem({ kind: \"item\", depth: 0, text: node.text })\n } else xml = renderChapter(node)\n lastTextNode = node\n break\n case \"item\": xml = renderItem(node); lastTextNode = node; lastItemFromHeading = !!node.fromHeading; break\n case \"ref\": xml = renderRef(node); lastTextNode = node; break\n // 마크다운 리스트 사이에 본문 문단이 끼면 번호 재시작(리스트 run 종료). 헤딩(##/###)에서 온\n // 항목은 그 아래 서술 문단이 내용이므로 번호를 잇는다 (기안문 \"1. 개요 / 내용 / 2. 성과\")\n case \"para\": xml = renderPara(node); if (!node.align && !lastItemFromHeading) numberer.reset(); lastTextNode = node; break\n case \"attach\": xml = renderAttach(node, !prevAttach); lastTextNode = node; break\n case \"block\": xml = renderBlock(node, idx); if (node.block.type === \"table\" || node.block.type === \"html_table\") lastTextNode = node; break\n }\n prevAttach = node.kind === \"attach\"\n if (!xml) return\n if (pendingPageBreak) { xml = xml.replace(/^<hp:p /, `<hp:p pageBreak=\"1\" `); pendingPageBreak = false }\n if (pendingNewPageNum) { xml = xml.replace(/<hp:run charPrIDRef=\"(\\d+)\">/, `<hp:run charPrIDRef=\"$1\">${newPageNumCtrl(1)}`); pendingNewPageNum = false }\n paras.push(xml)\n prevKind = node.kind\n if (node.kind === \"item\") prevItemDepth = node.depth\n else if (node.kind === \"chapter\" && gaejosik && chapterStyle === \"box\") prevItemDepth = 0\n })\n\n // ─── 후면부 ───────────────────────────────────────\n if (g.noticeHead) paras.push(...buildNoticeFoot(g))\n if (g.endMark && paras.length > 0) {\n const lastText = lastTextNode && (lastTextNode.kind === \"item\" || lastTextNode.kind === \"para\" || lastTextNode.kind === \"attach\" || lastTextNode.kind === \"ref\") ? lastTextNode.text : \"\"\n if (!hasEndMark(lastText)) {\n const st = scheme.body\n paras.push(generateParagraph(\" 끝.\", reg.para({ align: \"LEFT\", lineSp: scheme.lineSp }), reg.char({ font: st.font, pt: st.pt })))\n }\n }\n if (preset === \"official\" && g.docFoot) {\n const f = g.docFoot\n const approvers = (f.approvers ?? [f.drafter, f.reviewer, f.approver].filter((x): x is string => !!x)).map(splitTitleName)\n const cooperators = (f.cooperator ? f.cooperator.split(/[,、·]/).map((s) => s.trim()).filter(Boolean) : []).map(splitTitleName)\n paras.push(buildDocFootTable({\n sender: f.sender, approvers, cooperators, recipients: f.recipients,\n docNum: f.docNum, receive: f.receive, zip: f.zip, address: f.address, site: f.site,\n phone: f.phone, fax: f.fax, email: f.email, disclosure: f.disclosure,\n }, frame, isInternalApproval(g.docHead?.to)))\n }\n\n if (paras.length === 0) paras.push(`<hp:p paraPrIDRef=\"0\" styleIDRef=\"0\"><hp:run charPrIDRef=\"0\"><hp:t></hp:t></hp:run></hp:p>`)\n // 섹션 첫 문단 첫 run에 페이지 설정 — 실결재도 두문표와 같은 run에 secPr·colPr을 싣는다\n paras[0] = paras[0].replace(/<hp:run charPrIDRef=\"(\\d+)\">/, `<hp:run charPrIDRef=\"$1\">${generateSecPr(g, page)}`)\n\n return {\n xml: `<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>\\n<hs:sec xmlns:hs=\"${NS_SECTION}\" xmlns:hp=\"${NS_PARA}\">\\n ${paras.join(\"\\n \")}\\n</hs:sec>`,\n warnings,\n scheme,\n }\n}\n\n/** 노드 텍스트·GFM 표 셀에 문자 다듬기 — HTML 표 원문(태그 속성 따옴표)은 건드리지 않는다 */\nfunction polishNode(n: OutlineNode): OutlineNode {\n if (n.kind === \"block\") {\n const b = n.block\n return b.type === \"table\" && b.rows ? { ...n, block: { ...b, rows: b.rows.map((r) => r.map(polishGongmunText)) } } : n\n }\n return { ...n, text: polishGongmunText(n.text) }\n}\n\nfunction legalDepthOf(marker: string): number {\n if (/^\\d{1,2}\\.$/.test(marker)) return 0\n if (/^[가-힣]\\.$/.test(marker)) return 1\n if (/^\\d{1,2}\\)$/.test(marker)) return 2\n if (/^[가-힣]\\)$/.test(marker)) return 3\n if (/^\\(\\d{1,2}\\)$/.test(marker)) return 4\n if (/^\\([가-힣]\\)$/.test(marker)) return 5\n return 6\n}\n\n","/** 문서 비교 엔진 — IR 레벨 블록 비교로 신구대조표 생성 */\n\nimport { parse } from \"../index.js\"\nimport { normalizedSimilarity } from \"./text-diff.js\"\nimport type { IRBlock, IRTable, DiffResult, BlockDiff, CellDiff, DiffChangeType, ParseOptions } from \"../types.js\"\n\n/** 유사도 임계값 — 이 이상이면 modified, 미만이면 removed+added */\nconst SIMILARITY_THRESHOLD = 0.4\n\n/**\n * 두 문서를 비교하여 블록 단위 diff 생성.\n * 크로스 포맷 지원 — HWP vs HWPX 비교 가능 (IR 레벨).\n */\nexport async function compare(\n bufferA: ArrayBuffer,\n bufferB: ArrayBuffer,\n options?: ParseOptions\n): Promise<DiffResult> {\n const [resultA, resultB] = await Promise.all([\n parse(bufferA, options),\n parse(bufferB, options),\n ])\n\n if (!resultA.success) throw new Error(`문서A 파싱 실패: ${resultA.error}`)\n if (!resultB.success) throw new Error(`문서B 파싱 실패: ${resultB.error}`)\n\n return diffBlocks(resultA.blocks, resultB.blocks)\n}\n\n/** IRBlock[] 간 diff — LCS 기반 정렬 */\nexport function diffBlocks(blocksA: IRBlock[], blocksB: IRBlock[]): DiffResult {\n const aligned = alignBlocks(blocksA, blocksB)\n const stats = { added: 0, removed: 0, modified: 0, unchanged: 0 }\n const diffs: BlockDiff[] = []\n\n for (const [a, b] of aligned) {\n if (a && b) {\n const sim = blockSimilarity(a, b)\n if (sim >= 0.99) {\n diffs.push({ type: \"unchanged\", before: a, after: b, similarity: 1 })\n stats.unchanged++\n } else {\n const diff: BlockDiff = { type: \"modified\", before: a, after: b, similarity: sim }\n if (a.type === \"table\" && b.type === \"table\" && a.table && b.table) {\n diff.cellDiffs = diffTableCells(a.table, b.table)\n }\n diffs.push(diff)\n stats.modified++\n }\n } else if (a) {\n diffs.push({ type: \"removed\", before: a })\n stats.removed++\n } else if (b) {\n diffs.push({ type: \"added\", after: b })\n stats.added++\n }\n }\n\n return { stats, diffs }\n}\n\n// ─── 블록 정렬 (LCS 기반) ───────────────────────────\n\nfunction alignBlocks(a: IRBlock[], b: IRBlock[]): [IRBlock | null, IRBlock | null][] {\n const m = a.length, n = b.length\n\n // 대형 문서 보호\n if (m * n > 10_000_000) return fallbackAlign(a, b)\n\n // 길이비 프리필터용 정규화 길이 — normalizedSimilarity와 같은 공백 정규화 기준\n const lenOf = (blk: IRBlock): number => {\n const t = blk.text !== undefined\n ? blk.text\n : blk.type === \"table\" && blk.table ? blk.table.cells.flat().map(c => c?.text ?? \"\").join(\" \") : \"\"\n return t.replace(/\\s+/g, \" \").trim().length\n }\n const aLen = a.map(lenOf)\n const bLen = b.map(lenOf)\n\n // 유사도 매트릭스 캐시\n const simCache = new Map<string, number>()\n const getSim = (i: number, j: number): number => {\n const key = `${i},${j}`\n let v = simCache.get(key)\n if (v === undefined) {\n // 길이비 프리필터 — Levenshtein 하한(sim ≤ 1 − 길이차/max)으로 임계 미달이\n // 확정인 쌍은 계산 없이 0 (전쌍 O(len²) 캡). 표는 dimSim 0.3 가중이 있어\n // 6/7 초과일 때만 확정 (0.3 + 0.7×(1/7) = 0.4 = 임계).\n const mx = Math.max(aLen[i], bLen[j])\n const cut = a[i].type === \"table\" || b[j].type === \"table\" ? 6 / 7 : 1 - SIMILARITY_THRESHOLD\n v = mx > 0 && (mx - Math.min(aLen[i], bLen[j])) / mx > cut\n ? 0\n : blockSimilarity(a[i], b[j])\n simCache.set(key, v)\n }\n return v\n }\n\n // LCS with similarity threshold\n const dp: number[][] = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0))\n for (let i = 1; i <= m; i++) {\n for (let j = 1; j <= n; j++) {\n if (getSim(i - 1, j - 1) >= SIMILARITY_THRESHOLD) {\n dp[i][j] = dp[i - 1][j - 1] + 1\n } else {\n dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1])\n }\n }\n }\n\n // 역추적\n const pairs: [number, number][] = []\n let i = m, j = n\n while (i > 0 && j > 0) {\n if (getSim(i - 1, j - 1) >= SIMILARITY_THRESHOLD && dp[i][j] === dp[i - 1][j - 1] + 1) {\n pairs.push([i - 1, j - 1]); i--; j--\n } else if (dp[i - 1][j] >= dp[i][j - 1]) {\n i--\n } else {\n j--\n }\n }\n pairs.reverse()\n\n // 정렬 결과 조립\n const result: [IRBlock | null, IRBlock | null][] = []\n let ai = 0, bi = 0\n for (const [pi, pj] of pairs) {\n while (ai < pi) result.push([a[ai++], null])\n while (bi < pj) result.push([null, b[bi++]])\n result.push([a[ai++], b[bi++]])\n }\n while (ai < m) result.push([a[ai++], null])\n while (bi < n) result.push([null, b[bi++]])\n\n return result\n}\n\nfunction fallbackAlign(a: IRBlock[], b: IRBlock[]): [IRBlock | null, IRBlock | null][] {\n const result: [IRBlock | null, IRBlock | null][] = []\n const len = Math.max(a.length, b.length)\n for (let i = 0; i < len; i++) {\n result.push([a[i] || null, b[i] || null])\n }\n return result\n}\n\n// ─── 블록 유사도 ────────────────────────────────────\n\nfunction blockSimilarity(a: IRBlock, b: IRBlock): number {\n if (a.type !== b.type) return 0\n\n // 텍스트 기반 블록: paragraph, heading, list, image(alt text)\n if (a.text !== undefined && b.text !== undefined) {\n return normalizedSimilarity(a.text || \"\", b.text || \"\")\n }\n\n if (a.type === \"table\" && a.table && b.table) {\n return tableSimilarity(a.table, b.table)\n }\n\n // separator 등 텍스트 없는 동일 타입 → 완전 일치\n if (a.type === b.type) return 1\n\n return 0\n}\n\nfunction tableSimilarity(a: IRTable, b: IRTable): number {\n // 구조 유사도 (차원)\n const dimSim = 1 - Math.abs(a.rows * a.cols - b.rows * b.cols) / Math.max(a.rows * a.cols, b.rows * b.cols, 1)\n\n // 내용 유사도 (셀 텍스트) — ragged 입력 방어(?.)\n const textsA = a.cells.flat().map(c => c?.text ?? \"\").join(\" \")\n const textsB = b.cells.flat().map(c => c?.text ?? \"\").join(\" \")\n const contentSim = normalizedSimilarity(textsA, textsB)\n\n return dimSim * 0.3 + contentSim * 0.7\n}\n\n// ─── 테이블 셀 diff ─────────────────────────────────\n\nfunction diffTableCells(a: IRTable, b: IRTable): CellDiff[][] {\n const maxRows = Math.max(a.rows, b.rows)\n const maxCols = Math.max(a.cols, b.cols)\n const result: CellDiff[][] = []\n\n for (let r = 0; r < maxRows; r++) {\n const row: CellDiff[] = []\n for (let c = 0; c < maxCols; c++) {\n // 선언 rows/cols보다 실제 cells가 짧은 비정합(ragged) 입력 방어\n const cellA = r < a.rows && c < a.cols ? a.cells[r]?.[c]?.text : undefined\n const cellB = r < b.rows && c < b.cols ? b.cells[r]?.[c]?.text : undefined\n\n let type: DiffChangeType\n if (cellA === undefined) type = \"added\"\n else if (cellB === undefined) type = \"removed\"\n else if (cellA === cellB) type = \"unchanged\"\n else type = \"modified\"\n\n row.push({ type, before: cellA, after: cellB })\n }\n result.push(row)\n }\n return result\n}\n","/**\n * 내장 표준 서식 템플릿 — 정부 표준 기안문 (rhwp tools/forms 자산, MIT)\n *\n * templates/ 디렉토리의 누름틀(CLICK_HERE) 내장 HWPX 서식을 이름으로 제공한다.\n * 서식 원본은 「행정 효율과 협업 촉진에 관한 규정 시행규칙」 별지 제1·2호서식\n * (어트리뷰션: THIRD_PARTY/rhwp-forms.txt).\n */\n\nimport { existsSync, readFileSync } from \"fs\"\nimport { fileURLToPath } from \"url\"\nimport { dirname, join } from \"path\"\nimport { KordocError } from \"../utils.js\"\n\n/** 내장 템플릿 메타데이터 */\nexport interface BuiltinTemplate {\n /** 영문 식별자 — CLI/MCP에서 쓰는 정식 이름 */\n id: string\n /** 한글 별칭 (`templates:일반기안문` 표기 포함 매칭) */\n aliases: string[]\n /** templates/ 안의 서식 파일명 */\n file: string\n /** templates/ 안의 예시값 JSON 파일명 */\n sampleFile: string\n /** 한 줄 소개 */\n title: string\n}\n\nexport const BUILTIN_TEMPLATES: readonly BuiltinTemplate[] = [\n {\n id: \"gian\",\n aliases: [\"일반기안문\", \"기안문\", \"일반기안문_서식\"],\n file: \"일반기안문_서식.hwpx\",\n sampleFile: \"일반기안문_예시값.json\",\n title: \"일반기안문 — 별지 제1호서식 (대외 시행문·협조문, 누름틀 23곳)\",\n },\n {\n id: \"gian-simple\",\n aliases: [\"간이기안문\", \"간이기안문_서식\"],\n file: \"간이기안문_서식.hwpx\",\n sampleFile: \"간이기안문_예시값.json\",\n title: \"간이기안문 — 별지 제2호서식 (내부결재 보고서·계획서, 결재란 표, 누름틀 13곳)\",\n },\n]\n\n/**\n * 이름/별칭으로 내장 템플릿 해석 — `templates:` 접두사 허용.\n * 예: \"gian\", \"gian-simple\", \"일반기안문\", \"templates:간이기안문\"\n */\nexport function resolveBuiltinTemplate(name: string): BuiltinTemplate | undefined {\n const n = name.trim().replace(/^templates?:/i, \"\").trim()\n if (!n) return undefined\n const low = n.toLowerCase()\n return BUILTIN_TEMPLATES.find(t => t.id === low || t.aliases.includes(n))\n}\n\n/**\n * templates/ 디렉토리 위치 — 소스 실행(src/form/ → ../../templates)과\n * 번들 실행(dist/ → ../templates)을 모두 지원한다.\n */\nexport function builtinTemplateDir(): string {\n const here = dirname(fileURLToPath(import.meta.url))\n const candidates = [\n join(here, \"..\", \"..\", \"templates\"), // src/form/templates.ts → 패키지 루트\n join(here, \"..\", \"templates\"), // dist/*.js (tsup 번들) → 패키지 루트\n ]\n for (const c of candidates) {\n if (existsSync(join(c, BUILTIN_TEMPLATES[0].file))) return c\n }\n throw new KordocError(\"내장 templates 디렉토리를 찾을 수 없습니다 (패키지 설치가 손상되었을 수 있습니다)\")\n}\n\n/** 내장 템플릿 HWPX 버퍼 읽기 */\nexport function readBuiltinTemplate(t: BuiltinTemplate): ArrayBuffer {\n const buf = readFileSync(join(builtinTemplateDir(), t.file))\n return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength) as ArrayBuffer\n}\n\n/** 내장 템플릿 예시값 JSON 읽기 */\nexport function readBuiltinTemplateSample(t: BuiltinTemplate): Record<string, string> {\n return JSON.parse(readFileSync(join(builtinTemplateDir(), t.sampleFile), \"utf-8\"))\n}\n","/**\n * 서식 프로필 추출 (hwpx → FormatProfile) — 이슈 #41 / PR #42 Part B.\n *\n * 원본 hwpx에서 표의 borderFill(테두리·음영)·열너비·셀 글꼴을 읽어\n * FormatProfile JSON으로 뽑는다. 이 프로필을 `markdownToHwpx(md, { profile })`에\n * 넘기면 원본 없이 같은 시각 서식을 재현한다(진짜 라운드트립).\n *\n * render 경로(head-styles/svg-render)는 mm→pt·font→family 손실 변환이라\n * 프로필 충실 추출엔 부적합. 여기서는 header/section XML을 원문 그대로 읽는\n * 얇은 전용 파서를 쓴다.\n */\n\nimport JSZip from \"jszip\"\nimport { createXmlParser, findChildByLocalName } from \"./parser-shared.js\"\nimport { toArrayBuffer } from \"../utils.js\"\nimport { normalizeAnchor, normalizeRowAnchor } from \"./gen-profile.js\"\nimport type { FormatProfile, TableProfile, CellProfile, BorderFillDef, BorderDef, CharPrDef } from \"./gen-profile.js\"\n\n/** localName(접두사 제거)으로 자손 요소 전부 — 문서 순서 보존 */\nfunction elemsByLocal(root: Element | Document, name: string): Element[] {\n const all = root.getElementsByTagName(\"*\")\n const out: Element[] = []\n for (let i = 0; i < all.length; i++) {\n const el = all[i] as Element\n const tag = (el.tagName || el.localName || \"\").replace(/^[^:]+:/, \"\")\n if (tag === name) out.push(el)\n }\n return out\n}\n\nfunction borderDefOf(el: Element | null): BorderDef | undefined {\n if (!el) return undefined\n const type = el.getAttribute(\"type\") || \"NONE\"\n const width = el.getAttribute(\"width\") || \"0.1 mm\"\n const color = el.getAttribute(\"color\") || \"#000000\"\n return { type, width, color }\n}\n\n/** header.xml → borderFill id → 정의 (원문 그대로) */\nfunction parseBorderFills(headerDoc: Document): Map<string, BorderFillDef> {\n const map = new Map<string, BorderFillDef>()\n for (const bf of elemsByLocal(headerDoc, \"borderFill\")) {\n const id = bf.getAttribute(\"id\")\n if (!id) continue\n const def: BorderFillDef = {\n leftBorder: borderDefOf(findChildByLocalName(bf, \"leftBorder\")),\n rightBorder: borderDefOf(findChildByLocalName(bf, \"rightBorder\")),\n topBorder: borderDefOf(findChildByLocalName(bf, \"topBorder\")),\n bottomBorder: borderDefOf(findChildByLocalName(bf, \"bottomBorder\")),\n }\n const fillBrush = findChildByLocalName(bf, \"fillBrush\")\n const winBrush = fillBrush ? findChildByLocalName(fillBrush, \"winBrush\") : null\n const face = winBrush?.getAttribute(\"faceColor\")\n if (face && face !== \"none\") def.fill = { faceColor: face }\n map.set(id, def)\n }\n return map\n}\n\n/** header.xml → HANGUL fontface의 font id → 이름 (fontName_hangul 왕복 원료, 0.3.0) */\nfunction parseHangulFonts(headerDoc: Document): Map<string, string> {\n const map = new Map<string, string>()\n for (const ff of elemsByLocal(headerDoc, \"fontface\")) {\n if (ff.getAttribute(\"lang\") !== \"HANGUL\") continue\n for (const font of elemsByLocal(ff, \"font\")) {\n const id = font.getAttribute(\"id\")\n const face = font.getAttribute(\"face\")\n if (id && face) map.set(id, face)\n }\n }\n return map\n}\n\n/** header.xml → charPr id → 정의 */\nfunction parseCharPrs(headerDoc: Document, hangulFonts: Map<string, string>): Map<string, CharPrDef> {\n const map = new Map<string, CharPrDef>()\n for (const cp of elemsByLocal(headerDoc, \"charPr\")) {\n const id = cp.getAttribute(\"id\")\n if (!id) continue\n const def: CharPrDef = {}\n const h = cp.getAttribute(\"height\")\n if (h) def.height_hwpunit = h\n const color = cp.getAttribute(\"textColor\")\n if (color) def.textColor = color\n if (cp.getAttribute(\"bold\") === \"1\") def.bold = true\n if (cp.getAttribute(\"italic\") === \"1\") def.italic = true\n if (findChildByLocalName(cp, \"underline\")) def.underline = true\n const fontRef = findChildByLocalName(cp, \"fontRef\")\n const hangul = fontRef?.getAttribute(\"hangul\")\n if (hangul) {\n def.fontRef_hangul = hangul\n // 순번은 원본 fontfaces에서만 의미가 있다 — 이름을 함께 실어 생성 문서에서\n // 원본 글꼴 목록 없이도 글꼴이 재현되게 한다 (스키마 0.3.0)\n const face = hangulFonts.get(hangul)\n if (face) def.fontName_hangul = face\n }\n map.set(id, def)\n }\n return map\n}\n\n/** tbl 조상에 다른 tbl이 있으면 중첩표 — top-level만 문서 표로 센다(generate tableSeq와 정합) */\nfunction isTopLevelTable(tbl: Element): boolean {\n let p = tbl.parentNode as Element | null\n while (p) {\n const tag = ((p as Element).tagName || (p as Element).localName || \"\").replace(/^[^:]+:/, \"\")\n if (tag === \"tbl\") return false\n p = p.parentNode as Element | null\n }\n return true\n}\n\nfunction num(s: string | null | undefined): number | undefined {\n if (s == null) return undefined\n const n = parseInt(s, 10)\n return Number.isFinite(n) ? n : undefined\n}\n\n/** 한 <hp:tbl> → TableProfile. 셀이 참조하는 borderFill/charPr만 used_*에 담는다. */\nfunction parseTable(\n tbl: Element,\n tableIndex: number,\n borderFills: Map<string, BorderFillDef>,\n charPrs: Map<string, CharPrDef>,\n): TableProfile {\n const rows = num(tbl.getAttribute(\"rowCnt\")) ?? 0\n const cols = num(tbl.getAttribute(\"colCnt\")) ?? 0\n const sz = findChildByLocalName(tbl, \"sz\")\n const width = sz?.getAttribute(\"width\") || undefined\n\n const cells: CellProfile[] = []\n const usedBf = new Set<string>()\n const usedCp = new Set<string>()\n // 열 너비 — 어느 행이든 span-1 셀이 확정 (그리드 표는 행 무관 동일 열폭),\n // 남는 열은 병합 셀 폭에서 분배 (행0이 전부 병합이던 표의 col_widths 소실 방지)\n const colWidths: (number | undefined)[] = new Array(cols).fill(undefined)\n const spanCells: Array<{ col: number; colSpan: number; w: number }> = []\n // 첫 행 전체 지문(anchor_row, 0.3.0) — (0,0) 빈 셀 크로스탭 대응\n const row0Texts = new Map<number, string>()\n\n let anchorText = \"\"\n\n for (const tc of elemsByLocal(tbl, \"tc\")) {\n // 중첩표 셀 제외 — 이 tbl 직속 tc만\n if (nearestTable(tc) !== tbl) continue\n const addr = findChildByLocalName(tc, \"cellAddr\")\n const span = findChildByLocalName(tc, \"cellSpan\")\n const csz = findChildByLocalName(tc, \"cellSz\")\n const row = num(addr?.getAttribute(\"rowAddr\")) ?? 0\n const col = num(addr?.getAttribute(\"colAddr\")) ?? 0\n if (row === 0 && col === 0 && !anchorText) anchorText = directCellText(tc)\n if (row === 0) row0Texts.set(col, directCellText(tc))\n const colSpan = num(span?.getAttribute(\"colSpan\")) ?? 1\n const rowSpan = num(span?.getAttribute(\"rowSpan\")) ?? 1\n const bfId = tc.getAttribute(\"borderFillIDRef\") || undefined\n const cpId = firstRunCharPr(tc)\n\n const cell: CellProfile = { row, col, rowSpan, colSpan }\n const w = csz?.getAttribute(\"width\")\n const hh = csz?.getAttribute(\"height\")\n if (w) cell.width_hwpunit = w\n if (hh) cell.height_hwpunit = hh\n if (bfId) { cell.borderFillIDRef = bfId; usedBf.add(bfId) }\n if (cpId) { cell.charPrIDRef = cpId; usedCp.add(cpId) }\n cells.push(cell)\n\n const wNum = num(w)\n if (wNum != null && col < cols) {\n if (colSpan === 1) { if (colWidths[col] == null) colWidths[col] = wNum }\n else spanCells.push({ col, colSpan, w: wNum })\n }\n }\n\n // 병합 셀 폭 분배 — span-1 셀로 확정 못 한 열만, 알려진 열을 뺀 잔여를 균등 분배\n for (const s of spanCells) {\n const covered = Array.from({ length: s.colSpan }, (_, i) => s.col + i).filter(c => c < cols)\n const unknown = covered.filter(c => colWidths[c] == null)\n if (unknown.length === 0) continue\n const known = covered.reduce((sum, c) => sum + (colWidths[c] ?? 0), 0)\n const each = Math.floor((s.w - known) / unknown.length)\n if (each > 0) for (const c of unknown) colWidths[c] = each\n }\n\n const table: TableProfile = {\n table_index: tableIndex,\n rows, cols,\n cells,\n used_border_fills: pick(borderFills, usedBf),\n }\n const anchor = normalizeAnchor(anchorText)\n if (anchor) table.anchor_text = anchor\n const rowAnchor = normalizeRowAnchor(Array.from({ length: cols }, (_, c) => row0Texts.get(c) ?? \"\"))\n if (rowAnchor) table.anchor_row = rowAnchor\n if (width) table.width_hwpunit = width\n if (colWidths.every(w => w != null)) table.col_widths_hwpunit = colWidths.map(String)\n const cp = pick(charPrs, usedCp)\n if (Object.keys(cp).length) table.used_char_prs = cp\n return table\n}\n\n/** tc를 감싸는 가장 가까운 tbl (중첩 구분용) */\nfunction nearestTable(tc: Element): Element | null {\n let p = tc.parentNode as Element | null\n while (p) {\n const tag = ((p as Element).tagName || (p as Element).localName || \"\").replace(/^[^:]+:/, \"\")\n if (tag === \"tbl\") return p\n p = p.parentNode as Element | null\n }\n return null\n}\n\n/** 셀 내부(중첩표 제외) 첫 run의 charPrIDRef */\nfunction firstRunCharPr(tc: Element): string | undefined {\n for (const run of elemsByLocal(tc, \"run\")) {\n // 중첩표 안 run 건너뛰기 — run의 조상 tc가 이 tc여야\n if (nearestCell(run) !== tc) continue\n const id = run.getAttribute(\"charPrIDRef\")\n if (id) return id\n }\n return undefined\n}\n\nfunction nearestCell(el: Element): Element | null {\n let p = el.parentNode as Element | null\n while (p) {\n const tag = ((p as Element).tagName || (p as Element).localName || \"\").replace(/^[^:]+:/, \"\")\n if (tag === \"tc\") return p\n p = p.parentNode as Element | null\n }\n return null\n}\n\n/** 셀 직속(중첩표 제외) hp:t 텍스트 연결 — anchor_text 원료 */\nfunction directCellText(tc: Element): string {\n let out = \"\"\n for (const t of elemsByLocal(tc, \"t\")) {\n if (nearestCell(t) !== tc) continue\n out += t.textContent ?? \"\"\n if (out.length >= 64) break // 정규화 후 24자 절단 — 원료도 적당히서 끊는다\n }\n return out\n}\n\nfunction pick<T>(map: Map<string, T>, keys: Set<string>): Record<string, T> {\n const out: Record<string, T> = {}\n for (const k of keys) {\n const v = map.get(k)\n if (v !== undefined) out[k] = v\n }\n return out\n}\n\n/**\n * hwpx → FormatProfile. 문서 내 top-level 표를 등장 순서대로 추출한다.\n * @param input hwpx ArrayBuffer 또는 Buffer\n */\nexport async function hwpxToProfile(input: ArrayBuffer | Buffer): Promise<FormatProfile> {\n const buf = input instanceof ArrayBuffer ? input : toArrayBuffer(input)\n const zip = await JSZip.loadAsync(buf)\n const parser = createXmlParser()\n\n const headerFile = zip.file(\"Contents/header.xml\") ?? zip.file(/[Hh]eader\\.xml$/)?.[0]\n let headerXml = \"<root/>\"\n if (headerFile) headerXml = await headerFile.async(\"text\")\n const headerDoc = parser.parseFromString(headerXml, \"text/xml\") as unknown as Document\n const borderFills = parseBorderFills(headerDoc)\n const charPrs = parseCharPrs(headerDoc, parseHangulFonts(headerDoc))\n\n // section*.xml 을 번호 순서로\n const sectionFiles = zip.file(/[Ss]ection\\d+\\.xml$/)\n .sort((a, b) => (num(a.name.match(/(\\d+)\\.xml$/)?.[1] ?? null) ?? 0) - (num(b.name.match(/(\\d+)\\.xml$/)?.[1] ?? null) ?? 0))\n\n const tables: TableProfile[] = []\n let tableIndex = 0\n for (const f of sectionFiles) {\n const doc = parser.parseFromString(await f.async(\"text\"), \"text/xml\") as unknown as Document\n for (const tbl of elemsByLocal(doc, \"tbl\")) {\n if (!isTopLevelTable(tbl)) continue\n tables.push(parseTable(tbl, tableIndex++, borderFills, charPrs))\n }\n }\n\n return { schema_version: \"0.3.0\", tables }\n}\n","/**\n * 폰트 카탈로그 — fonts 오버라이드 오타·미설치 경고용 (A2).\n *\n * 생성은 항상 진행하고 경고만 낸다: HWPX는 폰트명을 문자열로 참조하므로\n * 미설치 폰트를 지정해도 파일은 유효하지만, 한컴이 무경고로 기본 폰트로\n * 대체 렌더해 \"지정한 폰트가 안 먹는\" 원인 파악이 어렵다.\n * 여기 목록은 한컴오피스 번들 + Windows 한글판 기본 + 통상 설치 무료 폰트.\n * 목록에 없다고 오류는 아니다 — 경고 문구도 그렇게 안내한다.\n */\n\n/** 한컴오피스 번들 폰트 (2018~2024 공통 코어) */\nconst HANCOM_BUNDLED = [\n \"함초롬바탕\", \"함초롬돋움\",\n \"한컴바탕\", \"한컴돋움\", \"한컴 고딕\", \"한컴고딕\", \"한컴 말랑말랑\", \"한컴산뜻돋움\", \"한컴솔잎\",\n \"HY헤드라인M\", \"HY견고딕\", \"HY견명조\", \"HY중고딕\", \"HY신명조\", \"HY명조\",\n \"HY그래픽M\", \"HY궁서\", \"HY강M\", \"HY강B\", \"HY울릉도M\", \"HY울릉도B\",\n \"HY태백B\", \"HY수평선M\", \"HY수평선B\", \"HY센스L\", \"HY얕은샘물M\", \"HY목판L\", \"HY엽서M\", \"HY엽서L\", \"HY동녘M\", \"HY동녘B\",\n \"한양신명조\", \"한양중고딕\", \"한양견명조\", \"한양견고딕\", \"한양궁서\", \"한양그래픽\",\n \"휴먼명조\", \"휴먼고딕\", \"휴먼굵은팸체\", \"휴먼가는팸체\", \"휴먼굵은샘체\", \"휴먼가는샘체\",\n \"휴먼옛체\", \"휴먼아미체\", \"휴먼편지체\", \"휴먼둥근헤드라인\", \"휴먼모음T\",\n \"태 나무\", \"태 그늘\", \"양재깨비체B\", \"양재난초체M\", \"양재둘기체M\", \"양재블럭체\",\n \"문체부 궁체 정자체\", \"문체부 궁체 흘림체\", \"문체부 돋움체\", \"문체부 바탕체\", \"문체부 쓰기 정체\", \"문체부 제목 돋움체\", \"문체부 제목 바탕체\",\n \"신명 신명조\", \"신명 신신명조\", \"신명 견명조\", \"신명 중고딕\", \"신명 태고딕\", \"신명 견고딕\", \"신명 신문명조\",\n \"MD개성체\", \"MD아롱체\", \"MD솔체\", \"MD이솝체\", \"MD아트체\",\n \"가는안상수체\", \"중간안상수체\", \"굵은안상수체\",\n \"HCI Poppy\", \"HCI Tulip\", \"-아이리스M\",\n]\n\n/** Windows 한글판 기본 폰트 */\nconst WINDOWS_DEFAULT = [\n \"맑은 고딕\", \"맑은고딕\", \"Malgun Gothic\",\n \"굴림\", \"굴림체\", \"돋움\", \"돋움체\", \"바탕\", \"바탕체\", \"궁서\", \"궁서체\",\n \"Arial\", \"Arial Black\", \"Times New Roman\", \"Courier New\", \"Consolas\",\n \"Calibri\", \"Cambria\", \"Segoe UI\", \"Tahoma\", \"Verdana\", \"Georgia\", \"Symbol\",\n]\n\n/** 통상 설치 무료 한글 폰트 (관공서·기관 PC에 흔함) */\nconst COMMON_FREE = [\n \"나눔고딕\", \"나눔명조\", \"나눔바른고딕\", \"나눔스퀘어\", \"나눔손글씨 붓\", \"나눔손글씨 펜\",\n \"NanumGothic\", \"NanumMyeongjo\",\n \"Noto Sans KR\", \"Noto Serif KR\", \"본고딕\", \"본명조\",\n \"Pretendard\", \"프리텐다드\",\n \"KoPub돋움\", \"KoPub바탕\", \"KoPubWorld돋움\", \"KoPubWorld바탕\",\n \"에스코어 드림\", \"S-Core Dream\", \"G마켓 산스\", \"Gmarket Sans\",\n \"윤고딕\", \"윤고딕320\", \"윤고딕330\", \"윤고딕340\", \"윤명조\",\n]\n\n/** 비교 정규화 — 공백 제거 + 소문자화 (\"맑은 고딕\"=\"맑은고딕\", \"noto sans kr\"=\"Noto Sans KR\") */\nfunction norm(name: string): string {\n return name.normalize(\"NFC\").replace(/\\s+/g, \"\").toLowerCase()\n}\n\nconst KNOWN = new Set([...HANCOM_BUNDLED, ...WINDOWS_DEFAULT, ...COMMON_FREE].map(norm))\n\n/** 카탈로그에 있는 폰트인가 */\nexport function isKnownFont(name: string): boolean {\n return KNOWN.has(norm(name))\n}\n\n/**\n * fonts 오버라이드 경고 목록 — 카탈로그에 없는 폰트명마다 경고 1건.\n * 빈 배열이면 전부 알려진 폰트. 경고는 생성을 막지 않는다.\n */\nexport function unknownFontWarnings(fonts: Record<string, string | undefined>): string[] {\n const warnings: string[] = []\n for (const [role, name] of Object.entries(fonts)) {\n if (!name || isKnownFont(name)) continue\n warnings.push(\n `폰트 경고: ${role}=\"${name}\" — 한컴 번들·통상 설치 목록에 없는 폰트명입니다. `\n + `오타이거나 대상 PC에 미설치면 한글이 기본 폰트로 대체 렌더합니다 (생성은 진행됨)`,\n )\n }\n return warnings\n}\n","/**\n * 공문서 표기법 검수기 — 「행정업무의 운영 및 혁신에 관한 규정」 시행규칙 및\n * 행정안전부 행정업무운영 편람의 날짜·시간·금액·기호 표기법을 정규식으로 검사.\n *\n * 원전: jkf87/hwpx-skill gonmun_lint.py(2025 편람 기준 13룰)를 kordoc에 맞게 이식\n * (v4.0.1). URL 쌍점 오탐 가드 등 일부 보강. v4.12.1 에 금액 한글 병기·물결표·두음법칙·\n * 외래어·차별 표현·\"끝.\" 누락 6룰 보강 (pyhwpxlib Gongmun 검사 항목 대조). 검사는 조언용이다 — 생성은 막지 않고\n * 경고만 낸다 (A2 폰트경고와 같은 원칙). 별도 CLI `kordoc lint`는 error 시 exit 1.\n * v4.13.0: 하이픈 날짜(2026-07-18) 룰, 금액 한글 병기·하이픈 날짜는 실제 변환값을 제안.\n */\n\nimport { hangulAmount } from \"../shared/numbering.js\"\n\nexport interface GongmunLintFinding {\n /** 1-based 줄 번호 */\n line: number\n /** 걸린 원문 조각 */\n match: string\n /** 규칙 코드 (DATE_NO_SPACE 등) */\n rule: string\n severity: \"error\" | \"warning\"\n message: string\n suggest?: string\n}\n\ninterface LintRule {\n code: string\n severity: \"error\" | \"warning\"\n pattern: RegExp\n message: string\n suggest?: string\n /** 표 줄(GFM `|` 행·HTML td/th)은 건너뜀 — 서식 라벨 셀 오탐 방지 */\n skipTable?: boolean\n}\n\n/** 외래어 오기 → 표준 표기 (국립국어원 외래어 표기법 용례) — 순서 무관, 긴 형태 우선 매칭 */\nexport const LOANWORD_FIXES: ReadonlyArray<readonly [string, string]> = [\n [\"컨텐츠\", \"콘텐츠\"], [\"어플리케이션\", \"애플리케이션\"], [\"메세지\", \"메시지\"], [\"리더쉽\", \"리더십\"],\n [\"워크샵\", \"워크숍\"], [\"스케쥴\", \"스케줄\"], [\"악세사리\", \"액세서리\"], [\"네비게이션\", \"내비게이션\"],\n [\"타겟\", \"타깃\"], [\"화이팅\", \"파이팅\"], [\"비지니스\", \"비즈니스\"], [\"프리젠테이션\", \"프레젠테이션\"],\n [\"라이센스\", \"라이선스\"], [\"캐비넷\", \"캐비닛\"], [\"렌트카\", \"렌터카\"], [\"플랭카드\", \"플래카드\"],\n [\"플랜카드\", \"플래카드\"], [\"컨셉\", \"콘셉트\"], [\"심볼\", \"심벌\"], [\"카달로그\", \"카탈로그\"],\n [\"팜플렛\", \"팸플릿\"], [\"팜플릿\", \"팸플릿\"], [\"리모콘\", \"리모컨\"], [\"에어콘\", \"에어컨\"], [\"알콜\", \"알코올\"],\n [\"발란스\", \"밸런스\"], [\"매니아\", \"마니아\"], [\"코메디\", \"코미디\"], [\"판넬\", \"패널\"], [\"앵콜\", \"앙코르\"],\n [\"로보트\", \"로봇\"], [\"바베큐\", \"바비큐\"], [\"부페\", \"뷔페\"], [\"초코렛\", \"초콜릿\"], [\"카페트\", \"카펫\"],\n [\"케잌\", \"케이크\"], [\"도너츠\", \"도넛\"], [\"슈퍼마켙\", \"슈퍼마켓\"], [\"써비스\", \"서비스\"], [\"센타\", \"센터\"],\n]\nconst LOANWORD_RE = new RegExp(LOANWORD_FIXES.map(([w]) => w).sort((a, b) => b.length - a.length).join(\"|\"), \"g\")\n\n/** 차별·비하 표현 → 순화어 (행안부 공문서 작성 지침·국립국어원) */\nexport const DISCRIM_FIXES: ReadonlyArray<readonly [string, string]> = [\n [\"장애자\", \"장애인\"], [\"장애우\", \"장애인\"], [\"불구자\", \"장애인\"], [\"정신박약\", \"지적장애\"], [\"정상인\", \"비장애인\"],\n [\"편부모\", \"한부모\"], [\"결손가정\", \"한부모가정\"], [\"미망인\", \"고인의 배우자\"], [\"학부형\", \"학부모\"],\n [\"불우이웃\", \"어려운 이웃\"], [\"유모차\", \"유아차\"], [\"저출산\", \"저출생\"], [\"잡상인\", \"이동상인\"],\n [\"파출부\", \"가사도우미\"], [\"청소부\", \"환경미화원\"], [\"간호원\", \"간호사\"], [\"운전수\", \"운전기사\"],\n [\"노가다\", \"건설노동자\"], [\"조선족\", \"중국동포\"], [\"매매춘\", \"성매매\"], [\"사생아\", \"혼외자\"],\n [\"벙어리\", \"언어장애인\"], [\"절름발이\", \"지체장애인\"], [\"애꾸눈\", \"시각장애인\"], [\"귀머거리\", \"청각장애인\"],\n]\nconst DISCRIM_RE = new RegExp(DISCRIM_FIXES.map(([w]) => w).sort((a, b) => b.length - a.length).join(\"|\"), \"g\")\n\n// 규칙 순서·코드·문구는 편람 기준 원전(gonmun_lint.py) 유지 — 대조 검증 용이성\nconst RULES: LintRule[] = [\n // 날짜 ─ 온점 뒤 한 칸, 0 패딩 금지, 연도 4자리, 끝 마침표\n // 법령 연혁 표기 `<개정 2012.2.14>`·`삭제 <2016.2.29.>`·`[시행일:2017.9.8.]` 는 법제처 정본 형식(별지서식 표제) —\n // 편람 날짜 규칙 대상이 아니다 (v4.12.3: 서식 595건 DATE 156건 전부 이 꼴, 기안문 0건)\n { code: \"DATE_NO_SPACE\", severity: \"error\",\n pattern: /(?<!<(?:개정|신설|전문개정|전부개정|일부개정|제정)\\s*)(?<!삭제\\s*<)(?<!시행일\\s*:\\s*)\\b\\d{4}\\.\\d{1,2}\\.\\d{1,2}\\.?/g,\n message: \"날짜 온점 뒤에 한 칸씩 띄워야 함\", suggest: \"예) 2025. 1. 6.\" },\n { code: \"DATE_ZERO_PAD\", severity: \"error\", pattern: /\\b\\d{4}\\.\\s*0\\d\\.|\\b\\d{4}\\.\\s*\\d{1,2}\\.\\s*0\\d/g,\n message: \"월·일 앞의 '0'은 표기하지 않음\", suggest: \"예) 2025. 1. 6. (2025. 01. 06. ✕)\" },\n { code: \"DATE_2DIGIT_YR\", severity: \"error\", pattern: /(?<!\\d)['’]\\d{2}\\.\\s*\\d/g,\n message: \"연도는 네 자리로 표기('24 ✕)\", suggest: \"예) 2025. 1. 6.\" },\n { code: \"DATE_NO_END_DOT\", severity: \"warning\", pattern: /\\b\\d{4}\\.\\s\\d{1,2}\\.\\s\\d{1,2}(?!\\s*[.\\d(])/g,\n message: \"날짜의 '일' 다음에 마침표(.)를 찍어야 함\", suggest: \"예) 2025. 1. 6.\" },\n // 하이픈·ISO 날짜(2026-07-18) — 편람은 온점 구분만 인정. URL 경로·파일명·코드 안(앞뒤에 / = & ? # % . - 영숫자)은\n // 제외, 표 셀은 서식 기입란 관행이 섞여 건너뜀. 제안은 실제 변환값(0 패딩 제거)\n { code: \"DATE_HYPHEN\", severity: \"warning\", skipTable: true,\n pattern: /(?<![\\/=&?#%.\\w-])(?:19|20)\\d{2}-\\d{1,2}-\\d{1,2}(?![\\/\\w-])/g,\n message: \"날짜는 하이픈(-) 대신 온점으로 구분하고 온점 뒤 한 칸 띄움\", suggest: \"예) 2026. 7. 18.\" },\n // 시간 ─ 24시각제, 쌍점 붙여쓰기\n { code: \"TIME_AMPM\", severity: \"error\", pattern: /(오전|오후|아침|밤|낮)\\s*\\d{1,2}\\s*시/g,\n message: \"24시각제 숫자로 표기(오전/오후 사용 안 함)\", suggest: \"예) 09:00, 15:30\" },\n { code: \"TIME_24H\", severity: \"warning\", pattern: /(?<!\\d)24\\s*시(?!각)/g,\n message: \"'24시'보다 익일 00:00 또는 '18:00까지' 권장\", suggest: \"예) 18:00\" },\n { code: \"TIME_COLON_SP\", severity: \"error\", pattern: /\\b\\d{1,2}\\s+:\\s*\\d{2}\\b|\\b\\d{1,2}:\\s+\\d{2}\\b/g,\n message: \"시와 분 사이 쌍점은 양쪽을 붙여 씀\", suggest: \"예) 13:20\" },\n // 금액 ─ '천원' 금지, 금+숫자 붙여쓰기\n { code: \"MONEY_CHEONWON\", severity: \"error\", pattern: /\\d+\\s*천\\s*원/g,\n message: \"금액은 '천원'으로 줄이지 않고 아라비아 숫자로\", suggest: \"예) 345,000원\" },\n { code: \"MONEY_GEUM_SP\", severity: \"warning\", pattern: /금\\s+\\d/g,\n message: \"'금'과 숫자 사이는 붙여 쓰는 것이 원칙\", suggest: \"예) 금113,560원\" },\n // 붙임 ─ 쌍점 금지(2타 띄움)\n { code: \"BUNIM_COLON\", severity: \"error\", pattern: /붙\\s*임\\s*:/g,\n message: \"'붙임' 다음에 쌍점(:)을 붙이지 않음(2타 띄움)\", suggest: \"예) 붙임 계획서 1부.\" },\n // 표기 ─ 물결표+까지 중복, 한글 먼저, 쌍점 띄어쓰기\n { code: \"KKAJI_DUP\", severity: \"error\", pattern: /[∼~~][^\\n]{0,20}?까지/g,\n message: \"물결표(∼)와 '까지'를 함께 쓰지 않음\", suggest: \"예) 2. 20.∼2. 24.\" },\n { code: \"FOREIGN_FIRST\", severity: \"warning\", pattern: /\\b[A-Z]{2,5}\\s*\\([가-힣]/g,\n message: \"한글을 먼저 쓰고 괄호 안에 외국어를 병기\", suggest: \"예) 업무 협약(MOU)\" },\n // 쌍점 — URL(https:// 등)·시각(13:20)은 제외\n // 편람: 쌍점은 앞말에 붙이고 뒤는 1타(원장: 김갑동). 표 셀은 제외(skipTable) — 법정 별지서식\n // 자체가 \"성 명 :\"·\"주 소 :\" 라벨 셀을 쓰므로 서식 라벨은 이 규칙의 대상이 아니다(v4.12.3 실측:\n // 서식 595건의 표 셀 801건 전부 라벨, 기안문 206건은 본문 414건이 \"일 시 : 값\" 꼴 — 편람상 위반).\n // 뒤 글자에서 `<`(HTML 태그)·`*`·`_`(마크다운 강조 닫힘)는 제외 — \"성명:</td>\"·\"과정:** 붙임\" 오탐\n { code: \"COLON_SPACE\", severity: \"warning\", skipTable: true,\n pattern: /\\S\\s+:(?!\\/\\/)|\\S:(?!\\/\\/)[^\\s\\d<*_]/g,\n message: \"쌍점은 앞말에 붙이고 뒤는 한 칸 띄움\", suggest: \"예) 원장: 김갑동\" },\n // ── 편람 보강 (v4.12.1) — pyhwpxlib Gongmun 검사·hwpx-skill gonmun_lint 대조로 빈 축 보충 ──\n // 금액 한글 병기 — 규정 시행규칙 제2조: 아라비아 숫자 다음 괄호 안에 한글로 적는다\n { code: \"MONEY_NO_HANGUL\", severity: \"warning\", pattern: /금\\d[\\d,]*원(?![\\s]*[((])/g,\n message: \"금액은 숫자 다음 괄호 안에 한글 병기\", suggest: \"예) 금113,560원(금일십일만삼천오백육십원)\" },\n // 물결표 앞뒤 붙여쓰기 — 기간·범위는 \"2. 20.∼2. 24.\" 처럼 붙여 씀. 숫자·날짜·시각 범위(앞은 숫자·\n // 온점·괄호·년월일시분, 뒤는 숫자·연도 생략부호)에만 건다 — \"기간( 부터 ~ 까지)\" 기입란·\"~ ※ 비고\"·\n // \"~ 수리완료시까지\" 처럼 낱말이 붙는 물결표는 범위 표기가 아니다 (v4.12.2, 별지서식 47→30·기안문 32→27 실측)\n { code: \"TILDE_SPACE\", severity: \"warning\", pattern: /(?<=[\\d.)일월년시분’'])[ \\t]+[∼~~]|[∼~~][ \\t]+(?=[\\d'’])/g,\n message: \"물결표(∼) 앞뒤는 붙여 씀\", suggest: \"예) 2. 20.∼2. 24., 09:00∼18:00\" },\n // 두음법칙 — 어두의 \"년도·년간·년말…\" 은 \"연도·연간·연말\" (숫자 뒤 '2026년도' 는 정상). 서식의\n // 기입란(\" 년도\", \"( 년간)\", \"2026 년도\")과 셀 하나가 \"년도\" 뿐인 표 머리글은 어두가 아니라\n // 빈칸 뒤 접미라 제외한다 (v4.12.2, 별지서식 실측 28건 전부 이 꼴·기안문 0건)\n { code: \"DUEUM_ERROR\", severity: \"warning\",\n pattern: /(?<![가-힣\\d])(?<!\\d[ \\t]{1,3})(?<![((>|][ \\t]*)(?<![ \\t][ \\t])년(?:도별|도|간|말|초|차|세|내)(?![가-힣])(?![ \\t]*(?:<\\/t[dh]>|\\|))/g,\n message: \"어두의 '년'은 두음법칙에 따라 '연'으로 적음\", suggest: \"예) 연도, 연간, 연말, 연초\" },\n // 외래어 표기 — 국립국어원 표기법 기준 흔한 오기 (사전 매칭)\n { code: \"LOANWORD_ERROR\", severity: \"warning\", pattern: LOANWORD_RE,\n message: \"외래어 표기법에 맞지 않는 표기\", suggest: \"예) 콘텐츠·애플리케이션·메시지·워크숍·스케줄·콘셉트\" },\n // 차별·비하 표현 — 행안부 공문서 작성 지침·국립국어원 순화어\n { code: \"DISCRIMINATORY_TERM\", severity: \"warning\", pattern: DISCRIM_RE,\n message: \"차별·비하 표현은 순화어로\", suggest: \"예) 장애자→장애인, 편부모→한부모, 학부형→학부모, 미망인→고인의 배우자\" },\n // ── AI 문체 흔적(슬롭) — 편람 원전 외 kordoc 자체 룰 (v4.9.0) ──────────────\n // 생성형 AI 초안이 공문서로 흘러들 때 남는 기계 문체를 걸러낸다. 조언용 warning.\n { code: \"AI_EM_DASH\", severity: \"warning\", pattern: /[—–―]/g,\n message: \"줄표(— – ―)는 공문서 표기 관행에 맞지 않음(생성형 AI 문체 흔적)\", suggest: \"쉼표·괄호·가운뎃점(·)으로 풀어쓰기\" },\n { code: \"AI_BOLD_OVERUSE\", severity: \"warning\", pattern: /(?:\\*\\*[^*\\n]+\\*\\*[^*\\n]*){3}/g,\n message: \"한 줄에 강조(**) 3회 이상 — 강조 남발은 생성형 AI 문체 흔적\", suggest: \"리드어·핵심 수치 한 곳만 강조\" },\n]\n\n/**\n * 텍스트(마크다운 포함) 표기법 검수. 마크다운 펜스 코드블록(``` ~ ```) 안은\n * 건너뛴다 — 코드·URL이 날짜/쌍점 규칙에 오탐되는 것 방지.\n */\nexport function lintGongmunText(text: string, opts?: { document?: boolean }): GongmunLintFinding[] {\n const findings: GongmunLintFinding[] = []\n // 펜스는 같은 마커 종류(``` 또는 ~~~)로만 닫힌다 — 다른 마커 줄이 안쪽에 있어도\n // 조기에 열리거나 닫히지 않게 여는 마커 종류를 기억한다.\n let fenceMarker: string | null = null\n const lines = text.split(/\\r?\\n/)\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]\n const fence = line.match(/^\\s*(```+|~~~+)/)\n if (fence) {\n const kind = fence[1][0]\n if (fenceMarker === null) fenceMarker = kind\n else if (kind === fenceMarker) fenceMarker = null\n continue\n }\n if (fenceMarker !== null) continue\n const tableLine = /^\\s*\\|/.test(line) || /<t[dhr][\\s>]/i.test(line)\n for (const r of RULES) {\n if (r.skipTable && tableLine) continue\n r.pattern.lastIndex = 0\n for (const m of line.matchAll(r.pattern)) {\n findings.push({\n line: i + 1, match: m[0].trim(), rule: r.code,\n severity: r.severity, message: r.message, suggest: dictSuggest(r.code, m[0]) ?? r.suggest,\n })\n }\n }\n }\n // 문서 단위(opts.document) — 붙임이 있는데 \"끝.\" 표시가 없다 (규정: 본문·붙임 표시 끝에 \"끝.\").\n // 생성 경로는 official 프리셋이 endMark 로 자동 방출하므로 기본(generate 경고)에서는 끄고\n // `kordoc lint` 완성 원고 검사에서만 켠다\n if (opts?.document && /^\\s*붙\\s*임(?![가-힣])/m.test(text) && !/끝\\.\\s*$/m.test(text)) {\n findings.push({ line: lines.length, match: \"붙임\", rule: \"END_MARK_MISSING\", severity: \"warning\",\n message: \"붙임 표시 뒤에 '끝.' 표시가 없음\", suggest: \"예) 붙임 계획서 1부. 끝.\" })\n }\n return findings\n}\n\n/** 사전 규칙(외래어·차별 표현)은 걸린 낱말의 표준 표기를, 금액·하이픈 날짜는 실제 변환값을 바로 제안 */\nfunction dictSuggest(code: string, match: string): string | undefined {\n const m = match.trim()\n if (code === \"MONEY_NO_HANGUL\") return `${m} → ${m}(금${hangulAmount(m)}원)`\n if (code === \"DATE_HYPHEN\") {\n const d = m.match(/^(\\d{4})-(\\d{1,2})-(\\d{1,2})$/)\n if (d) return `${m} → ${d[1]}. ${Number(d[2])}. ${Number(d[3])}.`\n }\n const table = code === \"LOANWORD_ERROR\" ? LOANWORD_FIXES : code === \"DISCRIMINATORY_TERM\" ? DISCRIM_FIXES : null\n if (!table) return undefined\n const hit = table.find(([w]) => w === match.trim())\n return hit ? `${hit[0]} → ${hit[1]}` : undefined\n}\n\n/** 검수 결과를 사람이 읽는 경고 문자열 배열로 — generate 경고 채널(A2와 동일)용 */\nexport function gongmunLintWarnings(text: string, limit: number = 10): string[] {\n const findings = lintGongmunText(text)\n const shown = findings.slice(0, limit).map(\n (f) => `표기법 [${f.rule}] L${f.line} \"${f.match}\" — ${f.message}${f.suggest ? ` (${f.suggest})` : \"\"}`,\n )\n if (findings.length > limit) shown.push(`표기법 경고 ${findings.length - limit}건 더 있음 — kordoc lint로 전체 확인`)\n return shown\n}\n","/**\n * 개조식 보고서 문체 검수기 — 서식이 맞아도 문체가 다르면 그 부서 문서로 읽히지 않는다.\n *\n * 표기법 검수(gongmun-lint.ts)가 \"어떻게 적는가\"를 본다면 이 모듈은 \"어떤 꼴로 끝나는가\"를\n * 본다. 개조식은 서술형 문장이 아니라 명사구로 끝나는 짧은 줄을 층층이 쌓는 문체다.\n *\n * 근거: 지자체 실무부서의 요약보고·기본계획·검토보고 15건(2,288줄) 실측 통계 —\n * jkf87/hwpx-skill v1.17.0 이 references/bogo-munche.md 로 공개한 수치를 임계값 근거로\n * 삼았다(서술형 `~다` 종결 0/264 항목, 항목 중앙 31자, 결론 중앙 30자, 물음표·느낌표\n * 본문 0건). 규칙 코드·정규식·판정 로직은 kordoc 자체 구현이다.\n *\n * 범위: 검수는 조언용이다 — 생성은 막지 않고 경고만 낸다(표기법 검수·폰트 경고와 같은\n * 원칙). 문체 *변환*은 여전히 엔진 범위 밖이다(gongmunseo-engine-spec.md).\n * 상세 규칙과 예문은 docs/gaejosik-munche.md.\n */\n\nimport { normalizeGongmunPreset } from \"./gongmun.js\"\n\nexport interface MuncheLintFinding {\n /** 1-based 줄 번호 */\n line: number\n /** 걸린 원문 조각 */\n match: string\n /** 규칙 코드 (DA_ENDING 등) */\n rule: string\n severity: \"error\" | \"warning\"\n /** 판정된 줄 종류 — 같은 문장도 층에 따라 허용 여부가 다르다 */\n kind: MuncheLineKind\n message: string\n suggest?: string\n}\n\n/**\n * 개조식 문체를 쓰는 프리셋 — 보고서·계획서·개조식보고서.\n * 기안문·시행문(official)은 경어 종결(`~하시기 바랍니다`), 통지·회의록·보도자료도\n * 각기 다른 문체 관행이라 이 검수를 적용하지 않는다. 적용 범위를 좁히는 것이\n * 오탐을 막는 가장 확실한 수단이다.\n */\nexport function usesGaejosikMunche(preset?: string): boolean {\n const p = normalizeGongmunPreset(preset)\n return p === \"gaejosik\" || p === \"report\" || p === \"plan\" || p === \"ministry\"\n}\n\n// ─── 줄 종류 ────────────────────────────────────────\n\n/** □ 소제목 / ❍ 항목 / - 세부 / ⇒ 결론 / > 리드문 / ※ 참고 / 그 밖 */\nexport type MuncheLineKind = \"dae\" | \"item\" | \"sub\" | \"concl\" | \"lead\" | \"note\" | \"para\"\n\n/** 실측 길이 임계 — 항목 중앙 31자(2줄 한계), 결론 중앙 30자, 리드문 40~120자 */\nconst ITEM_MAX = 70\nconst CONCL_MAX = 60\nconst LEAD_MAX = 140\n\n/**\n * 줄 종류 판정. 원고는 두 가지 꼴로 온다 — 개조식 부호를 직접 쓴 것(□ ○ ❍ - ⇒ ※)과\n * 마크다운 목록으로 계층을 표현한 것(들여쓰기 깊이). 둘 다 받는다.\n * null 은 검사 대상 아님(빈 줄·헤딩·표·이미지).\n */\nfunction classify(raw: string): { kind: MuncheLineKind; body: string } | null {\n const indent = raw.length - raw.trimStart().length\n const t = raw.trim()\n if (!t) return null\n // 헤딩·표·구분선·이미지는 문체 검사 대상이 아니다\n if (t.startsWith(\"#\") || t.startsWith(\"|\") || t.startsWith(\"![\") || /^[-=*_]{3,}$/.test(t)) return null\n if (t.startsWith(\">\")) return { kind: \"lead\", body: t.slice(1).trim() }\n if (/^(?:⇒|=>|➡|→)/.test(t)) return { kind: \"concl\", body: t.replace(/^(?:⇒|=>|➡|→)\\s*/, \"\") }\n if (/^(?:※|\\*\\s)/.test(t)) return { kind: \"note\", body: t.replace(/^(?:※|\\*)\\s*/, \"\") }\n if (t.startsWith(\"□\")) return { kind: \"dae\", body: t.slice(1).trim() }\n if (/^(?:○|❍|ㅇ|◦)/.test(t)) return { kind: \"item\", body: t.slice(1).trim() }\n // 하이픈·중점 목록과 마크다운 목록은 들여쓰기로 항목/세부를 가른다\n const li = /^(?:[-•ㆍ·]|\\d+[.)])\\s+(.*)$/.exec(t)\n if (li) return { kind: indent >= 2 ? \"sub\" : \"item\", body: li[1].trim() }\n return { kind: \"para\", body: t }\n}\n\n/** 마크다운 강조·링크 껍데기를 걷어낸 알맹이 — 길이 판정과 종결 판정 모두 본문 기준 */\nfunction plain(s: string): string {\n return s\n .replace(/!?\\[([^\\]]*)\\]\\([^)]*\\)/g, \"$1\")\n .replace(/(\\*\\*|__|~~|`)/g, \"\")\n .trim()\n}\n\n/** 인용부호·괄호 안은 원문 인용이라 문체 판정에서 제외한다 (실측도 인용문 안에만 ?! 존재) */\nfunction stripQuoted(s: string): string {\n return s.replace(/[“\"'‘][^”\"'’]{0,80}[”\"'’]/g, \"\").replace(/\\([^)]{0,80}\\)/g, \"\")\n}\n\n// ─── 종결 판정 ──────────────────────────────────────\n\n/**\n * 서술형 종결 — 명사·명사구로 끝나야 할 자리에서 `~다`로 끝나는 줄.\n * 명사형 종결(`~함/됨/임/음/있음/없음`)은 `다`로 끝나지 않으므로 자연히 통과한다.\n */\nconst DA_ENDING = /[가-힣]다\\.?$/\n/** 당위 종결 — 개조식은 판단을 `⇒ ○○ 필요`로 적지 `~해야 한다`로 적지 않는다 */\nconst DEONTIC = /(?:해야|하여야|되어야|돼야|필요가 있)\\s*(?:한다|함|합니다|하겠음)\\.?$|할 것\\.?$/\n/** `~것이다/것임` — 실측 1건뿐인 꼴 */\nconst GEOSIDA = /것(?:이다|임)\\.?$/\n/** 리드문 종결 — `~하고자 함.` 한 문장 */\nconst LEAD_ENDING = /(?:하고자|하려|고자)\\s*함\\.?$/\n\n/**\n * `A가 아니라 B` 대조. B 자리에 구체 명사(제도·장소·절차)가 오면 두 선택지를 가르는\n * 정상 표현이고, 추상어·가치어가 오면 수사(修辭)다 — 실측에서 수사는 0건이다.\n */\nconst NOT_A_BUT = /(?:아니라|아닌|아니고|아니며)\\s*,?\\s*([가-힣]{1,12})/g\n/** 가치어·추상어 — 이 자리에 오면 수사로 본다 */\nconst ABSTRACT = [\n \"사람\", \"마음\", \"본질\", \"전환\", \"태도\", \"문화\", \"철학\", \"가치\", \"정신\", \"관계\",\n \"신뢰\", \"과정\", \"질문\", \"이야기\", \"경험\", \"시간\", \"공간\", \"연결\", \"변화\", \"미래\",\n \"시작\", \"용기\", \"의지\", \"방법\", \"자세\", \"의식\", \"역량\",\n]\n\n/** 대구(對句) — 쉼표로 가른 두 구절이 같은 주격·주제 조사로 대칭을 이루는 슬로건 꼴 */\nconst COUPLET = /[은는이가]\\s*[^,]{2,15},\\s*[^,]{2,15}[은는이가]\\s*[^,]{2,15}$/\n\n/** 연·월·일을 글자로 적은 날짜 — 실측 표기는 `2026. 8. 22.` */\nconst DATE_KOREAN = /\\d{4}년\\s*\\d{1,2}월/\n\n// ─── 검수 ───────────────────────────────────────────\n\n/**\n * 원고(마크다운/텍스트) 문체 검수. 코드펜스 안은 건너뛴다 — 예시 코드가 종결·대조\n * 규칙에 오탐되는 것 방지(표기법 검수와 같은 원칙).\n */\nexport function lintMuncheText(text: string): MuncheLintFinding[] {\n const findings: MuncheLintFinding[] = []\n const lines = text.split(/\\r?\\n/)\n let fenceMarker: string | null = null\n let frontMatter = false\n /** 연속된 `>` 줄은 리드문 한 덩어리 — 마지막 줄에서 통째로 판정한다 */\n let leadBuf: { line: number; body: string }[] = []\n\n const add = (\n line: number, kind: MuncheLineKind, severity: \"error\" | \"warning\",\n rule: string, match: string, message: string, suggest?: string,\n ) => {\n findings.push({ line, kind, severity, rule, match: match.slice(0, 60), message, suggest })\n }\n\n const flushLead = () => {\n if (!leadBuf.length) return\n const block = leadBuf.map((l) => l.body).join(\" \").trim()\n const at = leadBuf[0].line\n // 줄마다 부호(▪ □ ㅇ - * ※)로 시작하는 인용은 리드문이 아니라 성과 요약 박스(업무보고 프리셋) — 종결·길이 규칙 밖\n const bulleted = leadBuf.every((l) => /^[▪■□○ㅇ●\\-–ㆍ·•*※]/u.test(l.body))\n leadBuf = []\n if (bulleted) return\n if (block.length < 20) return // 짧은 인용은 리드문이 아니다\n if (!LEAD_ENDING.test(block)) {\n add(at, \"lead\", \"warning\", \"LEAD_ENDING\", block,\n \"리드문은 '~하고자 함.' 한 문장\", \"[수단]하고, [수단]하여 [목적]하고자 함.\")\n }\n const sentences = (block.match(/\\./g) ?? []).length\n if (block.length > LEAD_MAX || sentences > 1) {\n add(at, \"lead\", \"warning\", \"LEAD_LONG\", block,\n `리드문 ${block.length}자·문장 ${sentences}개 — 실측은 한 문장 40~120자`, \"수단 둘·목적 하나로 압축\")\n }\n }\n\n for (let i = 0; i < lines.length; i++) {\n const raw = lines[i]\n const no = i + 1\n // YAML 프런트매터는 본문이 아니다 (문서 앞머리의 --- ~ --- 만)\n if (raw.trim() === \"---\" && (frontMatter || no <= 3)) {\n if (no <= 3 || frontMatter) frontMatter = !frontMatter\n continue\n }\n if (frontMatter) continue\n const fence = raw.match(/^\\s*(```+|~~~+)/)\n if (fence) {\n const kind = fence[1][0]\n if (fenceMarker === null) fenceMarker = kind\n else if (kind === fenceMarker) fenceMarker = null\n continue\n }\n if (fenceMarker !== null) continue\n\n const c = classify(raw)\n if (!c) {\n flushLead()\n continue\n }\n if (c.kind === \"lead\") {\n leadBuf.push({ line: no, body: plain(c.body) })\n continue\n }\n flushLead()\n\n const b = plain(c.body)\n if (!b) continue\n const q = stripQuoted(b) // 인용 제외 본문 — 종결·수사 판정용\n\n // 1) 종결 — 항목·세부·결론·본문 (□ 소제목과 ※ 참고는 명사구 제약 밖)\n if (c.kind === \"item\" || c.kind === \"sub\" || c.kind === \"concl\" || c.kind === \"para\") {\n if (DA_ENDING.test(q)) {\n add(no, c.kind, \"error\", \"DA_ENDING\", b,\n \"'~다' 서술형 종결 — 실측 0%(항목 0/264)\", \"명사·명사구 또는 '~함/있음'으로\")\n }\n if (GEOSIDA.test(q)) {\n add(no, c.kind, \"warning\", \"GEOSIDA\", b, \"'~것이다/것임' — 실측 1건뿐\", \"명사 종결로\")\n }\n }\n if (DEONTIC.test(q)) {\n add(no, c.kind, \"error\", \"DEONTIC\", b,\n \"'~해야 한다' 당위 종결 — 판단은 명사로 끝맺음\", \"예) ⇒ 지역맞춤형 보급 필요\")\n }\n\n // 2) 수사 — `A가 아니라 B`의 B가 추상어면 수사, 구체 선택지면 정상\n NOT_A_BUT.lastIndex = 0\n for (const m of q.matchAll(NOT_A_BUT)) {\n const tail = m[1] ?? \"\"\n if (ABSTRACT.some((w) => tail.includes(w))) {\n add(no, c.kind, \"error\", \"RHETORIC_CONTRAST\", m[0].trim(),\n `'아니라 ${tail}' — B가 추상어·가치어면 수사(실측 0건)`, \"두 구체 선택지를 가르는 경우만 허용\")\n } else {\n add(no, c.kind, \"warning\", \"CONTRAST_CHECK\", m[0].trim(),\n `'아니라 ${tail}' — B가 구체 선택지(제도·장소·절차)인지 확인`)\n }\n }\n\n // 3) 물음표·느낌표 — 본문 실측 0건 (인용문 안은 stripQuoted로 이미 제외)\n if (c.kind !== \"note\" && /[?!?!]/.test(q)) {\n add(no, c.kind, \"error\", \"QUESTION_EXCLAIM\", b, \"물음표·느낌표 — 본문 실측 0건\")\n }\n\n // 4) 대구·슬로건\n if ((c.kind === \"item\" || c.kind === \"para\" || c.kind === \"dae\") && COUPLET.test(q)) {\n add(no, c.kind, \"warning\", \"COUPLET\", b, \"대구(對句)로 보임 — 슬로건 문장은 실측 0건\", \"목표 수치·명사로\")\n }\n\n // 5) 길이 — 항목은 제목처럼 짧게, 세부는 설명처럼\n if (c.kind === \"item\" && b.length > ITEM_MAX) {\n add(no, c.kind, \"warning\", \"ITEM_LONG\", b,\n `항목 ${b.length}자 — 실측 중앙 31자, 2줄 한계`, \"근거·예시는 세부(-)로 내림\")\n }\n if (c.kind === \"concl\" && b.length > CONCL_MAX) {\n add(no, c.kind, \"warning\", \"CONCL_LONG\", b,\n `결론 ${b.length}자 — 실측 중앙 30자`, \"판단 하나만 남김\")\n }\n\n // 6) 날짜 글자 표기 (표기법 룰은 gongmun-lint 가 SSOT — 여기서는 문체 원고에 잦은 꼴만)\n if (DATE_KOREAN.test(b)) {\n add(no, c.kind, \"warning\", \"DATE_KOREAN\", b, \"연·월을 글자로 표기\", \"예) 2026. 8. 22.\")\n }\n }\n flushLead()\n return findings\n}\n\n/** 검수 결과를 사람이 읽는 경고 문자열 배열로 — generate 경고 채널(표기법과 동일)용 */\nexport function muncheLintWarnings(text: string, limit: number = 10): string[] {\n const findings = lintMuncheText(text)\n const shown = findings.slice(0, limit).map(\n (f) => `문체 [${f.rule}] L${f.line} \"${f.match}\" — ${f.message}${f.suggest ? ` (${f.suggest})` : \"\"}`,\n )\n if (findings.length > limit) shown.push(`문체 경고 ${findings.length - limit}건 더 있음 — kordoc lint --munche로 전체 확인`)\n return shown\n}\n","/**\n * HWPX 서식 보존 무손실 라운드트립 패치 — v3.0 킬러기능.\n *\n * parse()로 얻은 마크다운을 편집한 뒤 patchHwpx()에 넘기면, 원본 HWPX의\n * ZIP/XML 구조를 그대로 두고 변경된 문단/셀의 텍스트만 in-place 치환한다.\n * 스타일·이미지·표 구조·설정은 1바이트도 건드리지 않는다 (section XML 외\n * ZIP 엔트리는 원본 바이트 그대로, 변경 문단도 run 구조·charPr 보존).\n *\n * 지원: 문단/헤딩 텍스트 수정, 표 셀 텍스트 수정 (GFM·HTML·1x1·1열 표),\n * 문단 → GFM 표 인플레이스 변환 (v3.5 — table-insert.ts),\n * GFM/HTML 표 행 추가/삭제 (v3.7 — table-rows.ts, 병합 교차·개체 포함 행은 skip).\n * 미지원(graceful skip): 블록 추가/삭제/순서 변경, 표 열/병합 변경,\n * 캡션·각주·머리말/꼬리말·이미지 변경. skipped[]에 사유와 함께 보고된다.\n */\n\nimport JSZip from \"jszip\"\nimport { parseHwpxDocument } from \"../hwpx/parser.js\"\nimport { blocksToMarkdown } from \"../table/builder.js\"\nimport { normalizedSimilarity } from \"../diff/text-diff.js\"\nimport type { IRBlock, PatchOptions, PatchResult, PatchSkip, DiffResult, BlockDiff } from \"../types.js\"\nimport {\n scanSectionXml, buildParagraphSplices, markerRunSplices, applySplices, allLinesegRemovalSplices, findElementEnd, decodeXmlEntities,\n type SectionScan, type ScanParagraph, type ScanCell, type ScanTable, type SpliceEdit,\n} from \"./source-map.js\"\nimport { noteFormatFrom, noteRefMark, type NoteNumberFormat } from \"../hwpx/notes.js\"\nimport { patchZipEntries } from \"./zip-patch.js\"\nimport { AUTONUM_PREFIX_RE,\n splitMarkdownUnits, normForMatch, sanitizeText, unescapeGfm, summarize, parseGfmTable,\n alignUnits,\n type MdUnit,\n} from \"./markdown-units.js\"\nimport { patchGfmTable, patchHtmlTable, patchTextChunkTable } from \"./table-patch.js\"\nimport { collectMaxNumericId, injectCellBorderFill, buildTableParagraphXml } from \"./table-insert.js\"\nimport { resolveSectionEntryNames } from \"./hwpx-entries.js\"\n\nexport type { PatchOptions, PatchResult, PatchSkip } from \"../types.js\"\n\n// ─── 메인 API ────────────────────────────────────────\n\n/**\n * 원본 HWPX와 편집된 마크다운으로 서식 보존 패치본을 만든다.\n *\n * @param original 원본 HWPX 바이트\n * @param editedMarkdown parse(original).markdown을 편집한 마크다운\n */\nexport async function patchHwpx(\n original: Uint8Array,\n editedMarkdown: string,\n options?: PatchOptions,\n): Promise<PatchResult> {\n const skipped: PatchSkip[] = []\n let applied = 0\n\n // 1) 원본 파싱 (기존 파서 그대로 — IR 블록과 마크다운 확보)\n let origBlocks: IRBlock[]\n try {\n const parsed = await parseHwpxDocument(u8ToArrayBuffer(original))\n origBlocks = parsed.blocks\n } catch (err) {\n return { success: false, applied: 0, skipped, error: `원본 HWPX 파싱 실패: ${err instanceof Error ? err.message : String(err)}` }\n }\n\n // 2) 소스맵 — section XML 직접 스캔 (DOM 재직렬화 없음)\n let zip: JSZip\n try {\n zip = await JSZip.loadAsync(original)\n } catch {\n return { success: false, applied: 0, skipped, error: \"ZIP 로드 실패\" }\n }\n const sectionPaths = await resolveSectionEntryNames(zip)\n if (sectionPaths.length === 0) {\n return { success: false, applied: 0, skipped, error: \"HWPX 섹션 파일을 찾을 수 없습니다\" }\n }\n const scans: SectionScan[] = []\n for (let i = 0; i < sectionPaths.length; i++) {\n const xml = await zip.file(sectionPaths[i])!.async(\"text\")\n scans.push(scanSectionXml(xml, i))\n }\n\n // 2b) header.xml 로드 — 문단→표 변환 시 셀 테두리 borderFill 주입 대상\n // (header 엔트리를 못 찾으면 tableInsert undefined → 문단→표 변환만 graceful skip)\n let tableInsert: TableInsertState | undefined\n const headerEntryName = await resolveHeaderEntryName(zip)\n if (headerEntryName) {\n const headerXml = await zip.file(headerEntryName)!.async(\"text\")\n const maxId = collectMaxNumericId([...scans.map(s => s.xml), headerXml])\n tableInsert = { headerEntryName, headerXml, headerSplices: [], borderFillId: null, nextId: maxId + 1 }\n }\n\n // 3) 유닛 구성 + 정렬 (마크다운 도메인 diff)\n const origUnits = buildOrigUnits(origBlocks)\n const editedUnits = splitMarkdownUnits(editedMarkdown)\n const pairs = alignUnits(origUnits.map(u => u.raw), editedUnits.map(u => u.raw))\n\n // 4) 본문 문단 ↔ 소스맵 문단 매핑 (정규화 텍스트 + 등장 순서)\n const paraMap = resolveParagraphMappings(origBlocks, scans)\n const scanTables = scans.flatMap(s => s.tables.filter(t => t.rows.length > 0))\n const obTableOrdinals = buildTableOrdinals(origBlocks)\n\n // 5) 변경 적용\n const sectionSplices: SpliceEdit[][] = scans.map(() => [])\n for (const [oi, ei] of pairs) {\n if (oi !== null && ei !== null) {\n const orig = origUnits[oi]\n const edited = editedUnits[ei]\n if (orig.raw === edited.raw) continue\n applied += handleModifiedUnit(orig, edited, {\n origBlocks, paraMap, scans, scanTables, obTableOrdinals, sectionSplices, skipped, tableInsert,\n })\n } else if (oi !== null) {\n skipped.push({ reason: \"블록 삭제는 미지원 (v1) — 원본 유지\", before: summarize(origUnits[oi].raw) })\n } else if (ei !== null) {\n skipped.push({ reason: \"블록 추가는 미지원 (v1)\", after: summarize(editedUnits[ei].raw) })\n }\n }\n\n // 6) ZIP 재조립 — 수정된 섹션만 교체, 나머지는 원본 바이트 그대로\n const replacements = new Map<string, Uint8Array>()\n const encoder = new TextEncoder()\n try {\n for (let i = 0; i < scans.length; i++) {\n if (sectionSplices[i].length === 0) continue\n // 텍스트가 바뀐 섹션은 줄 레이아웃 캐시(linesegarray)를 전부 비워 한컴 변조\n // 경고를 막는다 (텍스트 변경으로 캐시가 어긋남 — 뷰어가 열 때 재계산).\n // 삭제된 행(<hp:tr>) 범위 안의 linesegarray는 삭제 splice에 포함되므로 제외\n const claimed = sectionSplices[i].filter(s => s.end > s.start)\n sectionSplices[i].push(...allLinesegRemovalSplices(scans[i].xml)\n .filter(ls => !claimed.some(c => ls.start >= c.start && ls.end <= c.end)))\n const newXml = applySplices(scans[i].xml, sectionSplices[i])\n replacements.set(sectionPaths[i], encoder.encode(newXml))\n }\n // header.xml 변경 — 문단→표 변환으로 셀 테두리 borderFill이 주입된 경우만\n if (tableInsert && tableInsert.headerSplices.length > 0) {\n const newHeader = applySplices(tableInsert.headerXml, tableInsert.headerSplices)\n replacements.set(tableInsert.headerEntryName, encoder.encode(newHeader))\n }\n } catch (err) {\n return { success: false, applied: 0, skipped, error: `소스맵 splice 실패: ${err instanceof Error ? err.message : String(err)}` }\n }\n\n let data: Uint8Array\n if (replacements.size === 0) {\n data = new Uint8Array(original) // Buffer.slice는 view라 명시적 복사\n } else {\n try {\n data = patchZipEntries(original, replacements)\n } catch (err) {\n return { success: false, applied: 0, skipped, error: `ZIP 재조립 실패: ${err instanceof Error ? err.message : String(err)}` }\n }\n }\n\n // 7) 자동 검증 — 패치본 재파싱 vs 편집 마크다운\n let verification: DiffResult | undefined\n if (options?.verify !== false) {\n try {\n const reparsed = await parseHwpxDocument(u8ToArrayBuffer(data))\n verification = diffUnitLists(splitMarkdownUnits(reparsed.markdown), editedUnits)\n } catch (err) {\n return { success: false, applied, skipped, error: `패치본 재파싱 실패 — 패치 중단: ${err instanceof Error ? err.message : String(err)}` }\n }\n }\n\n return { success: true, data, applied, skipped, verification }\n}\n\n// ─── 유닛 구성 ───────────────────────────────────────\n\nexport interface OrigUnit extends MdUnit {\n /** 출처 IR 블록 인덱스 */\n blockIdx: number\n role?: \"caption\"\n /** 한 문단 블록이 여러 유닛으로 갈라짐 (강제 줄바꿈 \\n\\n, 문단 내 '|' 줄, [별표] 2블록\n * 병합) — 유닛 하나의 수정이 문단 전체를 덮어쓰므로 부분 수정 미지원 처리 */\n fragment?: boolean\n}\n\n/**\n * IR 블록별 개별 렌더링으로 유닛 생성 — blocksToMarkdown의 [별표 N] 2블록\n * 병합 규칙을 재현해 전체 렌더와 동일한 분할을 보장한다.\n */\nexport function buildOrigUnits(blocks: IRBlock[]): OrigUnit[] {\n const units: OrigUnit[] = []\n for (let i = 0; i < blocks.length; i++) {\n const block = blocks[i]\n let consume = 1\n let chunk: string\n if (block.type === \"paragraph\" && block.text && /^\\[별표\\s*\\d+/.test(sanitizeText(block.text))) {\n const next = blocks[i + 1]\n if (next?.type === \"paragraph\" && next.text && /관련\\)?$/.test(next.text)) consume = 2\n chunk = blocksToMarkdown(blocks.slice(i, i + consume))\n } else {\n chunk = blocksToMarkdown([block])\n }\n if (chunk) {\n const subUnits = splitMarkdownUnits(chunk)\n // 문단/헤딩 블록이 여러 유닛으로 갈라지거나 [별표] 2블록 병합이면 부분 수정 불가\n const isFragment = consume === 2\n || ((block.type === \"paragraph\" || block.type === \"heading\") && subUnits.length > 1)\n for (let s = 0; s < subUnits.length; s++) {\n const u: OrigUnit = { ...subUnits[s], blockIdx: i, fragment: isFragment || undefined }\n // 표 캡션 — 표 유닛 앞의 **...** 텍스트 유닛\n if (block.type === \"table\" && block.table?.caption && s === 0 && subUnits.length > 1 && u.kind === \"text\" && u.raw.startsWith(\"**\")) {\n u.role = \"caption\"\n }\n units.push(u)\n }\n }\n i += consume - 1\n }\n return units\n}\n\n/** OB 표 블록 인덱스 → 최상위 표 서수 */\nexport function buildTableOrdinals(blocks: IRBlock[]): Map<number, number> {\n const map = new Map<number, number>()\n let ordinal = 0\n for (let i = 0; i < blocks.length; i++) {\n if (blocks[i].type === \"table\" && blocks[i].table) map.set(i, ordinal++)\n }\n return map\n}\n\n// ─── 유닛 정렬 — markdown-units.ts로 이동 (표 행 정렬과 공용), re-export로 하위 호환 유지\n\nexport { alignUnits, type AlignedPair } from \"./markdown-units.js\"\n\n// ─── 문단 매핑 ───────────────────────────────────────\n\nexport interface ParaMapping {\n para?: ScanParagraph\n /** 자동번호 접두가 IR 텍스트에 붙어 있었음 (스캔 텍스트에는 없음) */\n prefixStripped?: boolean\n /** 파서가 본문에 끼운 각주·미주 참조 부호(문서 순서) — hp:t 에 없으므로 편집 텍스트에서 뺀다 */\n noteMarks?: string[]\n}\n\n/**\n * OB 문단/헤딩 블록 → 스캔 문단 매핑.\n * 같은 정규화 텍스트끼리 등장 순서대로 페어링 (중복 문단 대응).\n * 머리말/꼬리말로 배치된 선두/말미 블록은 매핑에서 제외.\n */\nexport function resolveParagraphMappings(blocks: IRBlock[], scans: SectionScan[]): Map<number, ParaMapping> {\n const buckets = new Map<string, ScanParagraph[]>()\n for (const scan of scans) {\n for (const para of scan.bodyParagraphs) {\n const key = normForMatch(para.text)\n if (!key) continue\n let list = buckets.get(key)\n if (!list) buckets.set(key, (list = []))\n list.push(para)\n }\n }\n const headerNorms = new Set(scans.flatMap(s => s.headerTexts.map(normForMatch)).filter(Boolean))\n const footerNorms = new Set(scans.flatMap(s => s.footerTexts.map(normForMatch)).filter(Boolean))\n\n // applyPageText가 선두/말미에 배치한 머리말/꼬리말 블록 식별\n // (detectHwpxHeadings가 pageText 블록을 heading으로 재타입할 수 있어 heading도 검사)\n const pageText = new Set<number>()\n for (let i = 0; i < blocks.length; i++) {\n const b = blocks[i]\n if ((b.type !== \"paragraph\" && b.type !== \"heading\") || !b.text || !headerNorms.has(normForMatch(b.text))) break\n pageText.add(i)\n }\n for (let i = blocks.length - 1; i >= 0; i--) {\n const b = blocks[i]\n if ((b.type !== \"paragraph\" && b.type !== \"heading\") || !b.text || !footerNorms.has(normForMatch(b.text))) break\n pageText.add(i)\n }\n\n // 각주·미주 문단 — 파서가 본문에 끼운 참조 부호(\"1)\"·\"문1)\")만큼 IR 텍스트가 스캔 텍스트보다 길다.\n // 부호는 그 문단 XML 의 개체 속성·구역 번호 모양에서 파서와 같은 함수(notes.ts noteRefMark)로 재구성\n const noted = scans.flatMap(scan => {\n if (!/<(?:\\w+:)?(?:footNote|endNote)\\b/.test(scan.xml)) return []\n const fmts = sectionNoteFormats(scan.xml)\n return scan.bodyParagraphs\n .map(p => ({ key: normForMatch(p.text), marks: paraNoteMarks(scan.xml, p, fmts) }))\n .filter(x => x.key && x.marks.length > 0)\n })\n\n const counters = new Map<string, number>()\n const result = new Map<number, ParaMapping>()\n for (let i = 0; i < blocks.length; i++) {\n const b = blocks[i]\n if ((b.type !== \"paragraph\" && b.type !== \"heading\") || !b.text) continue\n if (pageText.has(i)) { result.set(i, {}); continue }\n\n let key = normForMatch(b.text)\n let prefixStripped = false\n let noteMarks: string[] | undefined\n if (!buckets.has(key)) {\n // 자동번호/글머리 접두 제거 후 재시도 (resolveParaHeading가 붙인 prefix)\n const sp = b.text.indexOf(\" \")\n const alt = sp > 0 ? normForMatch(b.text.slice(sp + 1)) : \"\"\n if (alt && buckets.has(alt)) { key = alt; prefixStripped = true }\n else {\n // 각주·미주 참조 부호를 뺀 텍스트가 그 문단 스캔 텍스트와 같으면 그 문단 (접두 제거와도 조합)\n for (const n of noted) {\n if (textWithoutMarks(key, n.key, n.marks)) { key = n.key; noteMarks = n.marks; break }\n if (alt && textWithoutMarks(alt, n.key, n.marks)) { key = n.key; noteMarks = n.marks; prefixStripped = true; break }\n }\n }\n }\n const list = buckets.get(key)\n if (!list) { result.set(i, {}); continue }\n const occ = counters.get(key) ?? 0\n counters.set(key, occ + 1)\n result.set(i, occ < list.length ? { para: list[occ], prefixStripped, noteMarks } : {})\n }\n return result\n}\n\n/** 구역 첫 secPr 의 footNotePr/endNotePr > autoNumFormat — 파서 notes.readSectionNoteFormats 의 정규식판 */\nfunction sectionNoteFormats(xml: string): { footnote?: NoteNumberFormat; endnote?: NoteNumberFormat } {\n const pick = (tag: string): NoteNumberFormat | undefined => {\n const m = new RegExp(`<(?:\\\\w+:)?${tag}\\\\b[^>]*>\\\\s*<(?:\\\\w+:)?autoNumFormat\\\\b([^>]*?)/?>`).exec(xml)\n return m ? noteFormatFrom(n => xmlAttr(m[1], n)) : undefined\n }\n return { footnote: pick(\"footNotePr\"), endnote: pick(\"endNotePr\") }\n}\n\nfunction xmlAttr(attrs: string, name: string): string | undefined {\n const m = new RegExp(`(?:^|\\\\s)${name}\\\\s*=\\\\s*\"([^\"]*)\"`).exec(attrs)\n return m ? decodeXmlEntities(m[1]) : undefined\n}\n\n/**\n * 문단 자신의 각주·미주 본문 참조 부호(문서 순서) — 문단 안 표·글상자·캡션·주석 본문 속 주석은\n * 각자 다른 문단 소관이라 세지 않는다 (파서 extractParagraphInfo 가 부호를 끼우는 범위와 같다)\n */\nexport function paraNoteMarks(xml: string, para: ScanParagraph, fmts: { footnote?: NoteNumberFormat; endnote?: NoteNumberFormat }): string[] {\n const end = findElementEnd(xml, para.start)\n if (end < 0) return []\n const seg = xml.slice(para.start, end)\n if (!/<(?:\\w+:)?(?:footNote|endNote)\\b/.test(seg)) return []\n const marks: string[] = []\n let depth = 0\n for (const m of seg.matchAll(/<(\\/?)(?:\\w+:)?(tbl|drawText|caption|footNote|endNote|header|footer|memo|hiddenComment)\\b([^>]*?)(\\/?)>/g)) {\n const [, close, tag, attrs, selfClose] = m\n if (selfClose) continue\n if (close) { depth = Math.max(0, depth - 1); continue }\n if (depth === 0 && (tag === \"footNote\" || tag === \"endNote\")) {\n const get = (n: string) => xmlAttr(attrs, n)\n marks.push(noteRefMark(\n { number: get(\"number\"), prefixChar: get(\"prefixChar\"), suffixChar: get(\"suffixChar\"), userChar: get(\"userChar\") },\n tag === \"endNote\" ? fmts.endnote : fmts.footnote,\n ))\n }\n depth++\n }\n return marks\n}\n\n/** IR 정규화 텍스트에서 부호를 (순서대로) 빼면 스캔 정규화 텍스트와 같은가 — 글자 우선 두 포인터 */\nfunction textWithoutMarks(irKey: string, scanKey: string, marks: string[]): boolean {\n let i = 0, j = 0, k = 0\n while (i < irKey.length) {\n if (j < scanKey.length && irKey[i] === scanKey[j]) { i++; j++; continue }\n if (k < marks.length && marks[k] && irKey.startsWith(marks[k], i)) { i += marks[k].length; k++; continue }\n if (irKey[i] === \" \" && (j === 0 || scanKey[j - 1] === \" \")) { i++; continue } // 부호 앞뒤 공백 붕괴 차이\n return false\n }\n return j === scanKey.length && k === marks.length\n}\n\n/**\n * 편집 텍스트에서 각주·미주 참조 부호를 뺀다 — 부호는 앞 낱말에 붙어 나오므로(“액체1)와”) 앞 글자가\n * 공백이 아닌 등장을 우선하고, 문단 첫머리 부호(“문1)”)는 0 위치로 인정. 못 찾은 부호는 사용자가\n * 지운 것 — 주석 개체는 XML 에 그대로 남는다(삭제 미지원)\n */\nexport function removeNoteMarks(text: string, marks: string[]): { text: string; missing: string[] } {\n let out = text\n let cursor = 0\n const missing: string[] = []\n for (const mark of marks) {\n if (!mark) continue\n let at = -1\n for (let p = out.indexOf(mark, cursor); p !== -1; p = out.indexOf(mark, p + 1)) {\n if (p === 0 || !/\\s/.test(out[p - 1])) { at = p; break }\n if (at === -1) at = p\n }\n if (at === -1) { missing.push(mark); continue }\n out = out.slice(0, at) + out.slice(at + mark.length)\n cursor = at\n }\n return { text: out, missing }\n}\n\n// ─── 변경 처리 ───────────────────────────────────────\n\n/**\n * 문단→표 인플레이스 변환 상태 — header.xml에 셀 테두리 borderFill을 1회 주입하고\n * 표 instId를 문서 전역 유니크하게 발급한다. header 엔트리를 못 찾으면 null\n * (그 경우 문단→표 변환은 graceful skip).\n */\ninterface TableInsertState {\n headerEntryName: string\n headerXml: string\n headerSplices: SpliceEdit[]\n /** 첫 표 삽입 시 header에 추가한 셀 테두리 borderFill id (없으면 아직 미주입) */\n borderFillId: number | null\n /** 다음 발급할 instId (문서 전역 max+1부터 증가) */\n nextId: number\n}\n\ninterface PatchCtx {\n origBlocks: IRBlock[]\n paraMap: Map<number, ParaMapping>\n scans: SectionScan[]\n scanTables: ScanTable[]\n obTableOrdinals: Map<number, number>\n sectionSplices: SpliceEdit[][]\n skipped: PatchSkip[]\n /** 문단→표 인플레이스 변환용 (header 엔트리 해석 실패 시 undefined) */\n tableInsert?: TableInsertState\n}\n\n/** 변경된 유닛 쌍 처리 — 적용 건수 반환 */\nfunction handleModifiedUnit(orig: OrigUnit, edited: MdUnit, ctx: PatchCtx): number {\n const block = ctx.origBlocks[orig.blockIdx]\n const skip = (reason: string) => {\n ctx.skipped.push({ reason, before: summarize(orig.raw), after: summarize(edited.raw) })\n return 0\n }\n\n if (orig.role === \"caption\") return skip(\"표 캡션 수정은 미지원 (v1)\")\n if (orig.kind === \"separator\" || orig.kind === \"image\") return skip(\"이미지/구분선 변경은 미지원\")\n if (!block) return skip(\"블록 매핑 실패\")\n if (orig.fragment) return skip(\"문단 분절(강제 줄바꿈/병합 유닛) — 부분 수정은 미지원 (v1)\")\n\n if (block.type === \"table\" && block.table) {\n if (orig.kind !== edited.kind) return skip(\"표 ↔ 비표 변경은 미지원 (표 구조 변경)\")\n // IR 최상위 표 수 ≠ 스캔 최상위 표 수면 서수가 밀려 엉뚱한 표가 수정될 수 있음\n if (ctx.obTableOrdinals.size !== ctx.scanTables.length) return skip(\"표 개수 불일치 — 소스맵 신뢰 불가\")\n const ordinal = ctx.obTableOrdinals.get(orig.blockIdx)\n const scanTable = ordinal !== undefined ? ctx.scanTables[ordinal] : undefined\n if (!scanTable) return skip(\"표 소스맵 매핑 실패\")\n if (orig.kind === \"gfm-table\") return patchGfmTable(block.table, scanTable, orig, edited, ctx, skip)\n if (orig.kind === \"html-table\") return patchHtmlTable(block.table, scanTable, orig, edited, ctx, skip)\n return patchTextChunkTable(block.table, scanTable, orig, edited, ctx, skip)\n }\n\n if ((block.type === \"paragraph\" || block.type === \"heading\") && orig.kind === \"text\") {\n if (edited.kind === \"text\") return patchParagraphUnit(block, orig, edited, ctx, skip)\n // 문단/헤딩 → 표 인플레이스 변환 (v3.5) — 원본 문단을 그 자리에서 표로 치환\n if (edited.kind === \"gfm-table\") return convertParagraphToTable(block, orig, edited, ctx, skip)\n if (edited.kind === \"html-table\") return skip(\"문단→병합표(HTML) 변환은 미지원 — GFM 표(| 헤더 | … |)로 작성하세요\")\n }\n\n return skip(\"지원하지 않는 블록 유형 변경\")\n}\n\n// ── 문단 → 표 인플레이스 변환 ──\n\n/** 문단 여는 태그에서 paraPrIDRef 추출 (표를 담는 바깥 문단에 승계) */\nfunction extractParaPrIdRef(xml: string, start: number): number | null {\n const gt = xml.indexOf(\">\", start)\n if (gt < 0) return null\n const m = xml.slice(start, gt + 1).match(/paraPrIDRef=\"(\\d+)\"/)\n return m ? parseInt(m[1], 10) : null\n}\n\n/**\n * 원본 문단(text)을 편집된 GFM 표로 그 자리에서 치환한다.\n * 문단 <hp:p> 전체 범위를 표 문단 XML로 splice 교체하고, 셀 테두리용 borderFill을\n * header.xml에 (문서당 1회) 주입한다. 원본의 다른 문단·표·서식은 보존된다.\n */\nfunction convertParagraphToTable(\n block: IRBlock, orig: OrigUnit, edited: MdUnit, ctx: PatchCtx,\n skip: (reason: string) => number,\n): number {\n const ti = ctx.tableInsert\n if (!ti) return skip(\"문단→표 변환 불가 — header 엔트리(borderFills) 해석 실패\")\n\n const mapping = ctx.paraMap.get(orig.blockIdx)\n if (!mapping?.para) return skip(\"문단 소스맵 매핑 실패 (머리말/글상자/캡션 영역) — 표 변환 불가\")\n const para = mapping.para\n if (para.kind !== \"body\") return skip(\"본문 외 영역(표 셀/글상자) 문단의 표 변환은 미지원\")\n\n const scan = ctx.scans[para.sectionIndex]\n if (!scan) return skip(\"섹션 매핑 실패\")\n const pEnd = findElementEnd(scan.xml, para.start)\n if (pEnd < 0) return skip(\"문단 끝 위치 탐색 실패\")\n\n // 편집 GFM 표 → 행렬\n const rows = parseGfmTable(edited.lines)\n if (rows.length === 0 || rows.every(r => r.length === 0)) return skip(\"표 내용이 비어 있음\")\n\n // 셀 테두리 borderFill 확보 (문서당 1회) — header.xml에 append splice 기록\n if (ti.borderFillId === null) {\n const inj = injectCellBorderFill(ti.headerXml, ti.nextId++)\n if (!inj) return skip(\"header <hh:borderFills> 구조를 찾을 수 없어 표 테두리 생성 불가\")\n ti.borderFillId = inj.borderFillId\n ti.headerSplices.push(...inj.headerSplices)\n }\n\n const outerParaPrId = extractParaPrIdRef(scan.xml, para.start) ?? 0\n const tableXml = buildTableParagraphXml(rows, {\n borderFillId: ti.borderFillId,\n outerParaPrId,\n cellParaPrId: 0,\n cellCharPrId: 0,\n tableId: ti.nextId++,\n })\n\n ctx.sectionSplices[para.sectionIndex].push({ start: para.start, end: pEnd, replacement: tableXml })\n return 1\n}\n\n// ── 문단 ──\n\nfunction patchParagraphUnit(\n block: IRBlock, orig: OrigUnit, edited: MdUnit, ctx: PatchCtx,\n skip: (reason: string) => number,\n): number {\n const mapping = ctx.paraMap.get(orig.blockIdx)\n if (!mapping?.para) return skip(\"문단 소스맵 매핑 실패 (머리말/글상자/캡션 영역이거나 텍스트 불일치)\")\n\n // 문단 내 강제 줄바꿈(<hp:br/>/<hp:lineBreak/>) — 평문 치환 시 줄바꿈이 공백으로\n // 변해 무손실 약속이 깨지므로 미지원 (v1)\n if (block.text && block.text.includes(\"\\n\")) {\n return skip(\"문단 내 강제 줄바꿈 포함 — 수정 시 줄바꿈 보존 불가로 미지원 (v1)\")\n }\n\n // 편집 마크다운 → 평문\n const origPlain = textUnitToPlain(orig.raw, block)\n let newPlain = textUnitToPlain(edited.raw, block)\n\n // 각주 표기 처리 — 본문이 아닌 각주 ctrl에 있으므로 분리\n if (block.footnoteText) {\n const noteMatch = newPlain.match(/\\s*\\(주: ([\\s\\S]*)\\)$/)\n if (noteMatch) {\n newPlain = newPlain.slice(0, noteMatch.index).trimEnd()\n if (normForMatch(noteMatch[1]) !== normForMatch(block.footnoteText)) {\n ctx.skipped.push({ reason: \"각주 텍스트 수정은 미지원 — 본문만 적용\", before: block.footnoteText, after: noteMatch[1] })\n }\n } else {\n ctx.skipped.push({ reason: \"각주 표기 삭제는 미지원 — 각주 유지, 본문만 적용\", before: `(주: ${block.footnoteText})` })\n }\n }\n\n // 각주·미주 참조 부호 — 개체가 그리는 글이라 hp:t 에 쓰지 않는다\n if (mapping.noteMarks?.length) {\n const r = removeNoteMarks(newPlain, mapping.noteMarks)\n newPlain = r.text\n if (r.missing.length) ctx.skipped.push({ reason: \"각주 참조 부호 삭제는 미지원 — 각주 유지, 본문만 적용\", before: r.missing.join(\" \") })\n }\n\n // 자동번호 접두 — XML에 없는 텍스트이므로 떼고 기록\n if (mapping.prefixStripped) {\n const origPrefix = block.text!.split(\" \", 1)[0]\n const sp = newPlain.indexOf(\" \")\n const newFirst = sp > 0 ? newPlain.slice(0, sp) : newPlain\n // 번호 형식: 끝 구두점 필수(\"1.\" \"가)\" \"(2)\") 또는 단일 원문자/로마자 — 맨 단어 오인 방지\n if (newFirst === origPrefix || AUTONUM_PREFIX_RE.test(newFirst)) {\n newPlain = sp > 0 ? newPlain.slice(sp + 1) : \"\"\n } else {\n ctx.skipped.push({ reason: \"자동번호 접두 식별 실패 — 번호 포함 텍스트로 적용 (뷰어에서 중복 표시 가능)\", after: summarize(newPlain) })\n }\n }\n\n if (newPlain === origPlain) return skip(\"텍스트 외 변경(헤딩 레벨/서식)만 감지 — 스타일 변경은 미지원\")\n\n // 단일 hp:t로 합쳐 기록하면 재파싱 sanitize에서 변형되는 텍스트(run 경계 이중 공백 등)\n // — 기록 후 동일 렌더가 보장되지 않으므로 미지원\n if (sanitizeText(newPlain) !== newPlain) {\n return skip(\"공백 정규화 불안정 텍스트 — 패치 시 원문 보존 불가로 미지원\")\n }\n\n const xml = ctx.scans[mapping.para.sectionIndex]?.xml\n const splices = (xml ? markerRunSplices(mapping.para, xml, newPlain) : null) ?? buildParagraphSplices(mapping.para, newPlain, xml)\n if (splices === null) return skip(\"문단에 텍스트 노드를 만들 수 없음\")\n ctx.sectionSplices[mapping.para.sectionIndex].push(...splices)\n return 1\n}\n\n/** 텍스트 유닛 마크다운 → 평문 (builder 렌더링의 역변환) */\nexport function textUnitToPlain(raw: string, block: IRBlock): string {\n // 여러 줄(soft-wrap)은 한 문단으로\n let text = raw.split(\"\\n\").map(l => l.trim()).filter(Boolean).join(\" \")\n // 헤딩 접두 — 헤딩/[별표] 블록만 (리터럴 '# '로 시작하는 일반 문단은 보존)\n if (block.type === \"heading\" || (block.text && /^\\[별표\\s*\\d+/.test(sanitizeText(block.text)))) {\n text = text.replace(/^#{1,6}\\s+/, \"\")\n }\n // 링크 — 원본이 href 블록일 때 표시 텍스트만\n if (block.href) {\n const linkMatch = text.match(/^\\[([\\s\\S]*)\\]\\([^)]*\\)$/)\n if (linkMatch) text = linkMatch[1]\n }\n // *(...관련)* 이탤릭 래핑\n if (/^\\*[^*][\\s\\S]*\\*$/.test(text) && block.text && /^\\([^)]*조[^)]*관련\\)$/.test(sanitizeText(block.text))) {\n text = text.slice(1, -1)\n }\n return unescapeGfm(text)\n}\n\n// ─── 검증 diff ───────────────────────────────────────\n\n/** 유닛 목록 diff → DiffResult (검증 리포트용) */\nexport function diffUnitLists(a: MdUnit[], b: MdUnit[]): DiffResult {\n const pairs = alignUnits(a.map(u => u.raw), b.map(u => u.raw))\n const stats = { added: 0, removed: 0, modified: 0, unchanged: 0 }\n const diffs: BlockDiff[] = []\n for (const [ai, bi] of pairs) {\n if (ai !== null && bi !== null) {\n if (a[ai].raw === b[bi].raw) { stats.unchanged++; continue }\n stats.modified++\n diffs.push({ type: \"modified\", before: unitToBlock(a[ai]), after: unitToBlock(b[bi]), similarity: normalizedSimilarity(a[ai].raw, b[bi].raw) })\n } else if (ai !== null) {\n stats.removed++\n diffs.push({ type: \"removed\", before: unitToBlock(a[ai]) })\n } else if (bi !== null) {\n stats.added++\n diffs.push({ type: \"added\", after: unitToBlock(b[bi]) })\n }\n }\n return { stats, diffs }\n}\n\nfunction unitToBlock(u: MdUnit): IRBlock {\n return { type: \"paragraph\", text: u.raw }\n}\n\n// ─── 헬퍼 ────────────────────────────────────────────\n\nfunction u8ToArrayBuffer(u8: Uint8Array): ArrayBuffer {\n return u8.buffer.slice(u8.byteOffset, u8.byteOffset + u8.byteLength) as ArrayBuffer\n}\n\n/** header.xml ZIP 엔트리 경로 해석 — 대부분 Contents/header.xml, manifest/스캔 fallback */\nasync function resolveHeaderEntryName(zip: JSZip): Promise<string | null> {\n for (const p of [\"Contents/header.xml\", \"header.xml\"]) {\n if (zip.file(p)) return p\n }\n for (const mp of [\"Contents/content.hpf\", \"content.hpf\"]) {\n const f = zip.file(mp)\n if (!f) continue\n const xml = await f.async(\"text\")\n const m = xml.match(/<opf:item\\b[^>]*\\bid=\"header\"[^>]*\\bhref=\"([^\"]+)\"/i)\n || xml.match(/<opf:item\\b[^>]*\\bhref=\"([^\"]*header[^\"]*\\.xml)\"/i)\n if (m) {\n let href = m[1]\n if (!href.startsWith(\"/\") && !href.startsWith(\"Contents/\")) href = \"Contents/\" + href\n if (zip.file(href)) return href\n }\n }\n const found = Object.keys(zip.files).find(n => /header\\.xml$/i.test(n))\n return found ?? null\n}\n\n// 섹션 엔트리 해석은 hwpx-entries.ts로 이동 (session/filler 공용) — re-export로 하위 호환 유지\nexport { resolveSectionEntryNames } from \"./hwpx-entries.js\"\n","/**\n * 라운드트립 표 행 추가/삭제 (HWPX 전용, v3.7).\n *\n * 편집된 마크다운의 표 행 수가 원본과 다를 때, alignUnits로 행을 정렬해\n * 삽입/삭제/수정을 구분하고 <hp:tr> 단위 splice로 반영한다.\n * 행 추가 = 인접 행 <hp:tr> 복제 → 셀 텍스트 교체 → rowAddr 재계산,\n * 행 삭제 = <hp:tr> 제거. 양쪽 모두 rowCnt·이후 행 rowAddr·표 sz height를 갱신한다.\n *\n * 보수적 게이트(전부 통과해야 행 연산 수행, 실패 시 표 전체 skip):\n * 세로 병합(rowSpan)이 변경 지점을 가로지르면 미지원, 삭제/템플릿 행에\n * 개체(중첩표·이미지·수식·필드)가 있으면 미지원, 셀 주소 표기 혼재 미지원.\n */\n\nimport type { IRTable } from \"../types.js\"\nimport {\n scanSectionXml, buildParagraphSplices, applySplices, allLinesegRemovalSplices,\n type ScanTable, type ScanCell, type SpliceEdit,\n} from \"./source-map.js\"\nimport { alignUnits, sanitizeText, summarize } from \"./markdown-units.js\"\nimport type { TablePatchCtx } from \"./table-patch.js\"\n\n/** 삽입될 행의 셀 하나 — 마크다운에서 추출한 평문 라인들과 병합 시그니처 */\nexport interface InsertCell {\n lines: string[]\n colSpan: number\n rowSpan: number\n}\n\nexport interface RowOpsInput {\n table: IRTable\n scanTable: ScanTable\n ctx: TablePatchCtx\n skip: (reason: string) => number\n /** 원본 마크다운 행 직렬화 키 (격자 행과 1:1 — 호출자가 보장) */\n origKeys: string[]\n /** 편집 마크다운 행 직렬화 키 */\n editedKeys: string[]\n /** 편집 행 ei의 셀 콘텐츠 (셀 순서). null = 삽입 불가 콘텐츠(이미지/중첩표 포함) */\n editedCells: (ei: number) => InsertCell[] | null\n /** 정렬된 행 쌍의 셀 단위 패치 (기존 경로 재사용) — 적용 건수 반환 */\n patchMatched: (oi: number, ei: number) => number\n}\n\n/** 행에 복제/삭제 불가능한 개체가 있는지 — 중첩표·그림·수식·글상자·필드·ctrl */\nconst ROW_OBJECT_RE = /<(?:[A-Za-z0-9_]+:)?(?:tbl|pic|equation|ole|container|shape|drawingObject|drawText|video|chart|fieldBegin|fieldEnd|ctrl)\\b/\n\n/** 태그 하나를 quote-aware로 읽는 sticky 정규식 (속성 값 내 '>' 안전) */\nconst TAG_AT_RE = /<[A-Za-z0-9_:]+(?:\"[^\"]*\"|'[^']*'|[^>\"'])*>/y\n\ninterface SeqEntry {\n kind: \"keep\" | \"del\" | \"ins\"\n oi?: number\n ei?: number\n /** ins 전용: 원본 격자 기준 삽입 위치 (이 인덱스의 행 앞) */\n insertAt?: number\n}\n\n/**\n * 표 행 추가/삭제 수행 — 게이트 전체 통과 시에만 splice를 기록한다.\n * 반환: 적용 건수 (행 연산 + 매칭 행 셀 패치 합).\n */\nexport function patchTableRows(input: RowOpsInput): number {\n const { table, scanTable, ctx, skip, origKeys, editedKeys } = input\n const xml = ctx.scans[scanTable.sectionIndex]?.xml\n if (!xml) return skip(\"섹션 XML 매핑 실패\")\n\n // ── 구조 게이트: 격자 행 ↔ 마크다운 행 ↔ <hp:tr> 1:1 정렬 ──\n const numRows = table.rows\n if (origKeys.length !== numRows) return skip(\"표 행 좌표 불일치 — 행 추가/삭제 미지원\")\n if (scanTable.rows.length !== numRows || scanTable.rowRanges.length !== numRows) {\n return skip(\"표 행 구조 좌표 불일치 (빈 행/병합 소실) — 행 추가/삭제 미지원\")\n }\n for (let r = 0; r < numRows; r++) {\n if (scanTable.rows[r].some(c => c.rowAddr !== r)) {\n return skip(\"행 주소 비연속 — 행 추가/삭제 미지원\")\n }\n }\n\n // 셀 주소 표기 all-or-none — 혼재하면 한컴 해석이 불명확\n const allCells = scanTable.rows.flat()\n const explicitAddr = (c: ScanCell) =>\n !!c.addrTagRange && /\\browAddr\\s*=\\s*\"/.test(xml.slice(c.addrTagRange.start, c.addrTagRange.end))\n const explicitCount = allCells.filter(explicitAddr).length\n if (explicitCount !== 0 && explicitCount !== allCells.length) {\n return skip(\"셀 주소(cellAddr) 표기 혼재 — 행 추가/삭제 미지원\")\n }\n const hasExplicitAddr = explicitCount > 0\n\n // ── 행 정렬 → 연산 시퀀스 ──\n const pairs = alignUnits(origKeys, editedKeys)\n const seq: SeqEntry[] = []\n let lastOrig = -1\n for (const [oi, ei] of pairs) {\n if (oi !== null && ei !== null) { seq.push({ kind: \"keep\", oi, ei }); lastOrig = oi }\n else if (oi !== null) { seq.push({ kind: \"del\", oi }); lastOrig = oi }\n else if (ei !== null) seq.push({ kind: \"ins\", ei, insertAt: lastOrig + 1 })\n }\n const dels = seq.filter(e => e.kind === \"del\")\n const inss = seq.filter(e => e.kind === \"ins\")\n const keeps = seq.filter(e => e.kind === \"keep\")\n if (dels.length === 0 && inss.length === 0) {\n // 행 수가 달랐는데 정렬 결과 연산이 없을 수는 없음 — 방어\n return skip(\"표 행 정렬 실패 — 행 추가/삭제 미지원\")\n }\n if (keeps.length + inss.length === 0) return skip(\"모든 행 삭제는 미지원\")\n if (keeps.length === 0) return skip(\"행 전면 교체 — 서식 기준 행이 없어 미지원\")\n\n // ── rowSpan 교차 게이트 ──\n const spans = allCells.filter(c => (c.rowSpan ?? 1) > 1)\n for (const d of dels) {\n if (spans.some(s => s.rowAddr! <= d.oi! && s.rowAddr! + s.rowSpan > d.oi!)) {\n return skip(`표 ${d.oi! + 1}행 삭제가 세로 병합과 겹침 — 미지원`)\n }\n }\n for (const ins of inss) {\n const p = ins.insertAt!\n if (spans.some(s => s.rowAddr! < p && s.rowAddr! + s.rowSpan > p)) {\n return skip(\"행 삽입 위치가 세로 병합 내부 — 미지원\")\n }\n }\n\n // ── 삭제 행 게이트: 개체 포함 금지 ──\n for (const d of dels) {\n const rr = scanTable.rowRanges[d.oi!]\n if (ROW_OBJECT_RE.test(xml.slice(rr.start, rr.end))) {\n return skip(`표 ${d.oi! + 1}행에 개체(중첩표/이미지/필드) 포함 — 행 삭제 미지원`)\n }\n }\n\n // ── 삽입 계획: 템플릿 선정 + 콘텐츠/구조 게이트 ──\n const keptSet = new Set(keeps.map(k => k.oi!))\n interface InsertPlan { entry: SeqEntry; template: number; cells: InsertCell[] }\n const insertPlans: InsertPlan[] = []\n for (const ins of inss) {\n const p = ins.insertAt!\n const kept = [...keptSet].sort((a, b) => a - b)\n let template = -1\n for (const k of kept) { if (k < p) template = k }\n // 헤더 행(0)은 데이터 행 서식이 아님 — 위 삽입이 아니면 다음 유지 행을 우선\n if (template <= 0 && p >= 1) {\n const following = kept.find(k => k >= 1)\n if (following !== undefined) template = following\n }\n if (template < 0) template = kept[0]\n\n const cells = input.editedCells(ins.ei!)\n if (!cells) return skip(\"삽입 행에 이미지/중첩표 포함 — 행 추가 미지원\")\n for (const cell of cells) {\n const unstable = cell.lines.find(l => sanitizeText(l) !== l)\n if (unstable !== undefined) return skip(\"삽입 행에 공백 정규화 불안정 텍스트 — 미지원\")\n }\n\n const tmplCells = scanTable.rows[template]\n const rr = scanTable.rowRanges[template]\n if (ROW_OBJECT_RE.test(xml.slice(rr.start, rr.end))) {\n return skip(\"서식 기준 행에 개체(중첩표/이미지/필드) 포함 — 행 추가 미지원\")\n }\n if (tmplCells.some(c => c.rowSpan > 1)) return skip(\"서식 기준 행에 세로 병합 — 행 추가 미지원\")\n const tmplWidth = tmplCells.reduce((s, c) => s + c.colSpan, 0)\n if (tmplWidth !== table.cols) return skip(\"서식 기준 행이 격자 전체를 덮지 않음 — 행 추가 미지원\")\n if (cells.length !== tmplCells.length) {\n return skip(`삽입 행 셀 수(${cells.length}) ≠ 기준 행 셀 수(${tmplCells.length}) — 미지원`)\n }\n for (let i = 0; i < cells.length; i++) {\n if (cells[i].rowSpan !== 1 || cells[i].colSpan !== tmplCells[i].colSpan) {\n return skip(\"삽입 행 병합 구조가 기준 행과 다름 — 미지원\")\n }\n }\n insertPlans.push({ entry: ins, template, cells })\n }\n\n // ── rowCnt 재작성 준비 (필수 — 없으면 구조 불신) ──\n const net = inss.length - dels.length\n TAG_AT_RE.lastIndex = scanTable.start\n const tblOpen = TAG_AT_RE.exec(xml)\n if (!tblOpen || tblOpen.index !== scanTable.start) return skip(\"표 여는 태그 해석 실패\")\n const rowCntM = tblOpen[0].match(/\\browCnt\\s*=\\s*\"(\\d+)\"/)\n if (!rowCntM || rowCntM.index === undefined) return skip(\"표 rowCnt 속성 없음 — 행 추가/삭제 미지원\")\n if (parseInt(rowCntM[1], 10) !== numRows) return skip(\"rowCnt와 실제 행 수 불일치 — 행 추가/삭제 미지원\")\n\n // ── 최종 행 인덱스 계산 ──\n const finalIndex = new Map<SeqEntry, number>()\n {\n let fi = 0\n for (const e of seq) { if (e.kind !== \"del\") finalIndex.set(e, fi++) }\n }\n\n // ── 여기서부터 splice 기록 (게이트 전체 통과) ──\n const splices: SpliceEdit[] = []\n let applied = 0\n\n // 삭제\n for (const d of dels) {\n const rr = scanTable.rowRanges[d.oi!]\n splices.push({ start: rr.start, end: rr.end, replacement: \"\" })\n applied++\n }\n\n // 삽입 — 같은 앵커의 연속 삽입은 시퀀스 순서로 이어붙여 한 splice로\n const fragmentsByAnchor = new Map<number, string[]>()\n let heightDelta = 0\n for (const plan of insertPlans) {\n const finalRow = finalIndex.get(plan.entry)!\n const fragment = buildRowFragment(xml, scanTable, plan.template, plan.cells, finalRow, hasExplicitAddr, ctx)\n if (fragment === null) return skip(\"행 복제 실패 (셀 문단 구조 미지원)\")\n const p = plan.entry.insertAt!\n const anchor = p === 0 ? scanTable.rowRanges[0].start : scanTable.rowRanges[p - 1].end\n let list = fragmentsByAnchor.get(anchor)\n if (!list) fragmentsByAnchor.set(anchor, (list = []))\n list.push(fragment)\n heightDelta += rowHeightOf(fragment)\n applied++\n }\n for (const [anchor, fragments] of fragmentsByAnchor) {\n splices.push({ start: anchor, end: anchor, replacement: fragments.join(\"\") })\n }\n for (const d of dels) {\n const rr = scanTable.rowRanges[d.oi!]\n heightDelta -= rowHeightOf(xml.slice(rr.start, rr.end))\n }\n\n // 유지 행 rowAddr 재작성 (명시 주소일 때만 — 미표기 표는 tr 순서가 곧 격자)\n if (hasExplicitAddr) {\n for (const k of keeps) {\n const fi = finalIndex.get(k)!\n if (fi === k.oi) continue\n for (const cell of scanTable.rows[k.oi!]) {\n const sp = rowAddrRewrite(xml, cell, fi)\n if (sp) splices.push(sp)\n }\n }\n }\n\n // rowCnt 갱신\n {\n const valStart = scanTable.start + rowCntM.index + rowCntM[0].indexOf('\"') + 1\n splices.push({ start: valStart, end: valStart + rowCntM[1].length, replacement: String(numRows + net) })\n }\n\n // 표 sz height 갱신 (선택적 — 못 찾으면 뷰어 재계산에 맡김)\n if (heightDelta !== 0) {\n const sp = tableSzHeightSplice(xml, scanTable, tblOpen[0].length, heightDelta)\n if (sp) splices.push(sp)\n }\n\n ctx.sectionSplices[scanTable.sectionIndex].push(...splices)\n\n // 매칭 행 셀 패치 (기존 경로 — 셀 단위 best-effort)\n for (const k of keeps) {\n if (origKeys[k.oi!] !== editedKeys[k.ei!]) applied += input.patchMatched(k.oi!, k.ei!)\n }\n return applied\n}\n\n// ─── 조각 빌더 ───────────────────────────────────────\n\nconst FRAG_OPEN = \"<hp:tbl>\"\nconst FRAG_CLOSE = \"</hp:tbl>\"\n\n/**\n * 템플릿 행 <hp:tr>을 복제해 셀 텍스트를 교체한 XML 조각을 만든다.\n * linesegarray는 제거(레이아웃 캐시 — 새 텍스트와 불일치), rowAddr는 최종 인덱스로.\n */\nfunction buildRowFragment(\n xml: string, scanTable: ScanTable, template: number, cells: InsertCell[],\n finalRow: number, hasExplicitAddr: boolean, ctx: TablePatchCtx,\n): string | null {\n const rr = scanTable.rowRanges[template]\n const wrapped = FRAG_OPEN + xml.slice(rr.start, rr.end) + FRAG_CLOSE\n const scan = scanSectionXml(wrapped, 0)\n const row = scan.tables[0]?.rows[0]\n if (!row || row.length !== cells.length) return null\n\n const splices: SpliceEdit[] = allLinesegRemovalSplices(wrapped)\n for (let i = 0; i < cells.length; i++) {\n const paras = row[i].paragraphs\n let lines = cells[i].lines\n if (lines.length > 0 && paras.length === 0) return null\n if (lines.length > paras.length) {\n // 넘치는 줄은 마지막 문단에 병합 (applyCellEdit와 동일한 관행)\n lines = [...lines.slice(0, paras.length - 1), lines.slice(paras.length - 1).join(\" \")]\n ctx.skipped.push({ reason: \"삽입 행 셀의 줄 수가 문단 수 초과 — 마지막 문단에 병합 적용\", after: summarize(cells[i].lines.join(\" \")), partial: true })\n }\n for (let p = 0; p < paras.length; p++) {\n const sp = buildParagraphSplices(paras[p], lines[p] ?? \"\", wrapped)\n if (sp === null) return null\n splices.push(...sp)\n }\n if (hasExplicitAddr) {\n const sp = rowAddrRewrite(wrapped, row[i], finalRow)\n if (sp) splices.push(sp)\n }\n }\n const patched = applySplices(wrapped, splices)\n return patched.slice(FRAG_OPEN.length, patched.length - FRAG_CLOSE.length)\n}\n\n/** 셀의 <hp:cellAddr> 태그에서 rowAddr 값만 교체하는 splice */\nfunction rowAddrRewrite(xml: string, cell: ScanCell, newRow: number): SpliceEdit | null {\n if (!cell.addrTagRange) return null\n const tag = xml.slice(cell.addrTagRange.start, cell.addrTagRange.end)\n const m = tag.match(/\\browAddr\\s*=\\s*\"(\\d+)\"/)\n if (!m || m.index === undefined) return null\n if (parseInt(m[1], 10) === newRow) return null\n const valStart = cell.addrTagRange.start + m.index + m[0].indexOf('\"') + 1\n return { start: valStart, end: valStart + m[1].length, replacement: String(newRow) }\n}\n\n/** tr 조각의 행 높이 — 셀 cellSz height의 최댓값 (없으면 0) */\nfunction rowHeightOf(fragment: string): number {\n let max = 0\n for (const m of fragment.matchAll(/<(?:[A-Za-z0-9_]+:)?cellSz\\b(?:\"[^\"]*\"|'[^']*'|[^>\"'])*>/g)) {\n const h = m[0].match(/\\bheight\\s*=\\s*\"(\\d+)\"/)\n if (h) max = Math.max(max, parseInt(h[1], 10))\n }\n return max\n}\n\n/**\n * 표 자체 <hp:sz>의 height를 delta만큼 조정하는 splice.\n * 첫 tr 앞 구간에서 첫 sz 태그를 찾는다 (스키마상 tbl 첫 자식). 못 찾으면 null.\n */\nfunction tableSzHeightSplice(\n xml: string, scanTable: ScanTable, tblOpenLen: number, delta: number,\n): SpliceEdit | null {\n const from = scanTable.start + tblOpenLen\n const to = scanTable.rowRanges[0]?.start ?? from\n const slice = xml.slice(from, to)\n const szM = slice.match(/<(?:[A-Za-z0-9_]+:)?sz\\b(?:\"[^\"]*\"|'[^']*'|[^>\"'])*>/)\n if (!szM || szM.index === undefined) return null\n const hM = szM[0].match(/\\bheight\\s*=\\s*\"(\\d+)\"/)\n if (!hM || hM.index === undefined) return null\n const oldH = parseInt(hM[1], 10)\n const newH = Math.max(0, oldH + delta)\n const valStart = from + szM.index + hM.index + hM[0].indexOf('\"') + 1\n return { start: valStart, end: valStart + hM[1].length, replacement: String(newH) }\n}\n","/**\n * 라운드트립 표 패치 — GFM/HTML/1x1/1열 표의 셀 단위 텍스트 치환\n * + GFM/HTML 표 행 추가/삭제 (v3.7, table-rows.ts).\n *\n * builder.ts 렌더링을 좌표 추적 버전으로 재현(markdown-units.ts)해 편집된 셀의\n * 격자 좌표를 역산하고, 소스맵의 cellAddr 앵커로 XML 셀을 찾아 문단 단위로\n * 치환한다. 재현 결과가 원본 마크다운과 불일치하면 graceful skip.\n * 중첩표 셀은 재귀 패치, 이미지는 변경 불가(텍스트만 적용).\n */\n\nimport type { IRTable, PatchSkip } from \"../types.js\"\nimport {\n buildParagraphSplices, buildRangeSplices, paraTText,\n type SectionScan, type ScanTable, type SpliceEdit,\n} from \"./source-map.js\"\nimport {\n normForMatch, sanitizeText, escapeGfm, unescapeGfm, summarize,\n replicateGfmTable, parseGfmTable, unescapeGfmCell,\n replicateHtmlTable, replicateTableToHtml, parseHtmlTable, htmlCellInnerToLines, extractTopLevelTables,\n type MdUnit, type HtmlRowInfo, type MappedCell,\n} from \"./markdown-units.js\"\nimport { patchTableRows, type InsertCell } from \"./table-rows.js\"\n\n/** 표 패치에 필요한 컨텍스트 (patcher.ts PatchCtx의 부분집합) */\nexport interface TablePatchCtx {\n scans: SectionScan[]\n sectionSplices: SpliceEdit[][]\n skipped: PatchSkip[]\n}\n\n// ── GFM 표 ──\n\nexport function patchGfmTable(\n table: IRTable, scanTable: ScanTable, orig: MdUnit, edited: MdUnit, ctx: TablePatchCtx,\n skip: (reason: string) => number,\n): number {\n const replica = replicateGfmTable(table)\n if (!replica) return skip(\"표 렌더 경로 식별 실패\")\n const origRows = parseGfmTable(orig.lines)\n const editedRows = parseGfmTable(edited.lines)\n\n // 자기 검증 — 재현 결과가 원본 마크다운과 다르면 매핑 신뢰 불가\n if (replica.length !== origRows.length || replica.some((row, r) => row.length !== origRows[r].length || row.some((c, j) => c.text !== origRows[r][j]))) {\n return skip(\"표 좌표 재현 불일치 — 매핑 신뢰 불가\")\n }\n if (editedRows.length !== origRows.length) {\n return patchGfmTableRows(table, scanTable, origRows, editedRows, replica, ctx, skip)\n }\n\n let applied = 0\n for (let r = 0; r < origRows.length; r++) {\n applied += patchGfmRowPair(table, scanTable, origRows, editedRows, replica, r, r, ctx, skip)\n }\n return applied\n}\n\n/** GFM 행 쌍 하나의 셀 단위 패치 (행 수 동일 경로와 행 연산의 매칭 행 공용) */\nfunction patchGfmRowPair(\n table: IRTable, scanTable: ScanTable, origRows: string[][], editedRows: string[][],\n replica: MappedCell[][], r: number, er: number, ctx: TablePatchCtx,\n skip: (reason: string) => number,\n): number {\n if (editedRows[er].length !== origRows[r].length) {\n skip(`표 ${r + 1}행 열 수 변경은 미지원`)\n return 0\n }\n let applied = 0\n for (let c = 0; c < origRows[r].length; c++) {\n if (origRows[r][c] === editedRows[er][c]) continue\n const { gridR, gridC } = replica[r][c]\n // 이미지/플레이스홀더 토큰은 본문 텍스트가 아님 — 변경 불가, 적용 시 제외\n const origTokens = extractCellTokens(origRows[r][c])\n const editedTokens = extractCellTokens(editedRows[er][c])\n if (origTokens !== editedTokens) {\n skip(\"셀 내 이미지 변경은 미지원\")\n continue\n }\n const newLines = unescapeGfmCell(stripCellTokens(editedRows[er][c]))\n .split(\"\\n\").map(s => s.trim()).filter(Boolean)\n const origLines = unescapeGfmCell(stripCellTokens(origRows[r][c]))\n .split(\"\\n\").map(s => s.trim()).filter(Boolean)\n const n = applyCellEdit(table, scanTable, gridR, gridC, newLines, ctx, origRows[r][c], editedRows[er][c], origLines.length)\n if (n > 0 && origTokens) {\n ctx.skipped.push({\n reason: \"셀 내 이미지·텍스트 혼재 — 텍스트만 적용 (이미지 인접 배치는 <br> 분리로 재현됨)\",\n before: summarize(origRows[r][c]), after: summarize(editedRows[er][c]), partial: true,\n })\n }\n applied += n\n }\n return applied\n}\n\n/** GFM 표 행 추가/삭제 — table-rows 엔진에 GFM 도메인을 연결 */\nfunction patchGfmTableRows(\n table: IRTable, scanTable: ScanTable, origRows: string[][], editedRows: string[][],\n replica: MappedCell[][], ctx: TablePatchCtx,\n skip: (reason: string) => number,\n): number {\n // 행 연산은 마크다운 행 ↔ 격자 행 1:1일 때만 (빈 행 소실/라벨 전파/병합 없음)\n if (replica.length !== table.rows || replica.some((row, r) => row.some(c => c.gridR !== r))) {\n return skip(\"표 렌더 행과 격자 행 불일치 (빈 행/병합) — 행 추가/삭제 미지원\")\n }\n if (table.cells.some(row => row.some(c => c && (c.colSpan > 1 || c.rowSpan > 1)))) {\n return skip(\"병합 셀 표 — GFM 행 추가/삭제 미지원\")\n }\n // 편집 결과가 builder 렌더로 안정 재현되는지 (빈 행 드롭/첫 열 전파가 일어나면 무손실 불가)\n if (!gfmRenderStable(editedRows, table.cols)) {\n return skip(\"행 변경 결과가 표 렌더에서 변형됨 (빈 행/첫 열 전파/열 수 불일치) — 미지원\")\n }\n const key = (row: string[]) => row.join(\"\\u0000\")\n return patchTableRows({\n table, scanTable, ctx, skip,\n origKeys: origRows.map(key),\n editedKeys: editedRows.map(key),\n editedCells: ei => {\n const cells: InsertCell[] = []\n for (const cellMd of editedRows[ei]) {\n if (extractCellTokens(cellMd)) return null\n const lines = unescapeGfmCell(cellMd).split(\"\\n\").map(s => s.trim()).filter(Boolean)\n cells.push({ lines, colSpan: 1, rowSpan: 1 })\n }\n return cells\n },\n patchMatched: (oi, ei) => patchGfmRowPair(table, scanTable, origRows, editedRows, replica, oi, ei, ctx, skip),\n })\n}\n\n/** 편집된 GFM 행렬이 builder 렌더에서 그대로 재현되는지 (행 연산 사전 검증) */\nfunction gfmRenderStable(editedRows: string[][], cols: number): boolean {\n const sim: IRTable = {\n rows: editedRows.length,\n cols,\n hasHeader: editedRows.length > 1,\n cells: editedRows.map(row => {\n const padded = row.length < cols ? [...row, ...Array(cols - row.length).fill(\"\")] : row\n return padded.map(md => ({ text: unescapeGfmCell(md), colSpan: 1, rowSpan: 1 }))\n }),\n }\n const replica = replicateGfmTable(sim)\n if (!replica || replica.length !== editedRows.length) return false\n return replica.every((row, r) => row.length === editedRows[r].length && row.every((c, j) => c.text === editedRows[r][j]))\n}\n\n// ── HTML 표 ──\n\nexport function patchHtmlTable(\n table: IRTable, scanTable: ScanTable, orig: MdUnit, edited: MdUnit, ctx: TablePatchCtx,\n skip: (reason: string) => number,\n): number {\n return patchHtmlTableRaw(table, scanTable, orig.raw, edited.raw, ctx, skip, 0)\n}\n\n/** HTML 표 패치 본체 — 중첩표 셀은 재귀 */\nfunction patchHtmlTableRaw(\n table: IRTable, scanTable: ScanTable, origRaw: string, editedRaw: string, ctx: TablePatchCtx,\n skip: (reason: string) => number, depth: number,\n): number {\n if (depth > 8) return skip(\"중첩표 깊이 초과\")\n // 자기 검증 — builder 렌더와 동일해야 좌표 신뢰 가능\n if (replicateTableToHtml(table) !== origRaw) return skip(\"표 좌표 재현 불일치 — 매핑 신뢰 불가\")\n const replica = replicateHtmlTable(table)\n // 되읽기 대칭 검증 — 셀 텍스트에 리터럴 '</td>' 등이 있으면 parseHtmlTable의 셀 경계가\n // 렌더와 어긋나 미편집 셀이 잘려 저장될 수 있음. 원본을 되읽어 replica와 대조한다.\n const origRows = parseHtmlTable(origRaw)\n if (!origRows || origRows.length !== replica.length\n || origRows.some((r, i) => r.cells.length !== replica[i].cells.length\n || r.cells.some((c, j) => c.inner !== replica[i].cells[j].inner))) {\n return skip(\"셀 경계 모호 (리터럴 태그 의심) — 매핑 신뢰 불가\")\n }\n const editedRows = parseHtmlTable(editedRaw)\n if (!editedRows) return skip(\"편집된 HTML 표 파싱 실패\")\n if (editedRows.length !== replica.length) {\n return patchHtmlTableRows(table, scanTable, replica, editedRows, ctx, skip, depth)\n }\n\n let applied = 0\n for (let r = 0; r < replica.length; r++) {\n applied += patchHtmlRowPair(table, scanTable, replica, editedRows, r, r, ctx, skip, depth)\n }\n return applied\n}\n\n/** HTML 행 쌍 하나의 셀 단위 패치 (행 수 동일 경로와 행 연산의 매칭 행 공용) */\nfunction patchHtmlRowPair(\n table: IRTable, scanTable: ScanTable, replica: HtmlRowInfo[], editedRows: HtmlRowInfo[],\n r: number, er: number, ctx: TablePatchCtx,\n skip: (reason: string) => number, depth: number,\n): number {\n if (editedRows[er].cells.length !== replica[r].cells.length) {\n skip(`표 ${r + 1}행 셀 수 변경은 미지원`)\n return 0\n }\n let applied = 0\n for (let c = 0; c < replica[r].cells.length; c++) {\n const oc = replica[r].cells[c]\n const ec = editedRows[er].cells[c]\n if (oc.colSpan !== ec.colSpan || oc.rowSpan !== ec.rowSpan) {\n skip(`셀 병합(colspan/rowspan) 변경은 미지원`)\n continue\n }\n if (oc.inner === ec.inner) continue\n\n const origContent = htmlCellInnerToLines(oc.inner)\n const editedContent = htmlCellInnerToLines(ec.inner)\n if (origContent.hadNonText || editedContent.hadNonText) {\n // 이미지 변경 불가\n if (extractImgTags(oc.inner) !== extractImgTags(ec.inner)) {\n skip(\"셀 내 이미지 변경은 미지원\")\n continue\n }\n // 중첩표 변경 → 셀의 중첩 소스맵으로 재귀 패치\n const origTables = extractTopLevelTables(oc.inner)\n const editedTables = extractTopLevelTables(ec.inner)\n if (origTables.length !== editedTables.length) {\n skip(\"셀 내 중첩표 추가/삭제는 미지원\")\n continue\n }\n if (origTables.join(\"\\n\") !== editedTables.join(\"\\n\")) {\n applied += patchNestedTables(table, scanTable, oc, origTables, editedTables, ctx, skip, depth)\n }\n }\n // 텍스트 라인 변경 (중첩표/이미지 제외분)\n if (origContent.lines.join(\"\\n\") !== editedContent.lines.join(\"\\n\")) {\n const newLines = editedContent.lines.map(l => unescapeGfm(l))\n applied += applyCellEdit(table, scanTable, oc.gridR!, oc.gridC!, newLines, ctx, oc.inner, ec.inner, origContent.lines.length)\n }\n }\n return applied\n}\n\n/** HTML 표 행 추가/삭제 — table-rows 엔진에 HTML 도메인을 연결 */\nfunction patchHtmlTableRows(\n table: IRTable, scanTable: ScanTable, replica: HtmlRowInfo[], editedRows: HtmlRowInfo[],\n ctx: TablePatchCtx, skip: (reason: string) => number, depth: number,\n): number {\n // 행 연산은 렌더 행 ↔ 격자 행 1:1일 때만 (병합으로 소실된 행 없음)\n if (replica.length !== table.rows || replica.some((row, r) => row.cells.some(c => c.gridR !== r))) {\n return skip(\"표 렌더 행과 격자 행 불일치 (병합 소실 행) — 행 추가/삭제 미지원\")\n }\n const key = (row: HtmlRowInfo) =>\n row.cells.map(c => `${c.colSpan}x${c.rowSpan}:${c.inner}`).join(\"\\u0000\")\n return patchTableRows({\n table, scanTable, ctx, skip,\n origKeys: replica.map(key),\n editedKeys: editedRows.map(key),\n editedCells: ei => {\n const cells: InsertCell[] = []\n for (const cell of editedRows[ei].cells) {\n const content = htmlCellInnerToLines(cell.inner)\n if (content.hadNonText) return null\n cells.push({ lines: content.lines.map(l => unescapeGfm(l)), colSpan: cell.colSpan, rowSpan: cell.rowSpan })\n }\n return cells\n },\n patchMatched: (oi, ei) => patchHtmlRowPair(table, scanTable, replica, editedRows, oi, ei, ctx, skip, depth),\n })\n}\n\n/** 셀 내 중첩표 k번째 IRTable/ScanTable 쌍을 찾아 재귀 패치 */\nfunction patchNestedTables(\n table: IRTable, scanTable: ScanTable, oc: { gridR?: number; gridC?: number },\n origTables: string[], editedTables: string[], ctx: TablePatchCtx,\n skip: (reason: string) => number, depth: number,\n): number {\n const irCell = table.cells[oc.gridR!]?.[oc.gridC!]\n const scanCell = scanTable.cellByAnchor.get(`${oc.gridR},${oc.gridC}`)\n const nestedIRs = (irCell?.blocks ?? []).filter(b => b.type === \"table\" && b.table).map(b => b.table!)\n if (!scanCell || nestedIRs.length !== origTables.length || scanCell.tables.length !== origTables.length) {\n return skip(\"중첩표 소스맵 매핑 실패\")\n }\n let applied = 0\n for (let k = 0; k < origTables.length; k++) {\n if (origTables[k] === editedTables[k]) continue\n applied += patchHtmlTableRaw(nestedIRs[k], scanCell.tables[k], origTables[k], editedTables[k], ctx, skip, depth + 1)\n }\n return applied\n}\n\nexport function extractImgTags(inner: string): string {\n return (inner.match(/<img\\s(?:\"[^\"]*\"|'[^']*'|[^>\"'])*?>/gi) || []).join(\" \")\n}\n\n/** GFM 셀의 비텍스트 토큰 — 이미지 참조/추출실패 플레이스홀더 */\nconst CELL_TOKEN_RE = /!\\[image\\]\\([^)]*\\)|\\[이미지: [^\\]]*\\]/g\n\nexport function extractCellTokens(text: string): string {\n return (text.match(CELL_TOKEN_RE) || []).join(\" \")\n}\n\nexport function stripCellTokens(text: string): string {\n return text.replace(CELL_TOKEN_RE, \"\")\n}\n\n// ── 1x1 / 1열 표 (텍스트 청크 렌더) ──\n\nexport function patchTextChunkTable(\n table: IRTable, scanTable: ScanTable, orig: MdUnit, edited: MdUnit, ctx: TablePatchCtx,\n skip: (reason: string) => number,\n): number {\n if (table.rows === 1 && table.cols === 1) {\n // builder 1x1 경로 재현 (라인별 장식 포함, 유닛 분할 시 트림됨)\n const content = sanitizeText(table.cells[0][0].text)\n const replicaLines = content.split(/\\n/).map(line => {\n const t = line.trim()\n if (!t) return \"\"\n if (/^\\d+\\.\\s/.test(t)) return `**${escapeGfm(t)}**`\n return escapeGfm(t)\n }).filter(Boolean)\n if (replicaLines.join(\"\\n\") !== orig.lines.join(\"\\n\")) return skip(\"표 좌표 재현 불일치 — 매핑 신뢰 불가\")\n if (extractCellTokens(orig.raw) !== extractCellTokens(edited.raw)) return skip(\"셀 내 이미지 변경은 미지원\")\n const newLines = edited.lines.map(l => {\n // builder는 /^\\d+\\.\\s/ 라인에만 '**' 볼드를 부여 — 그 경우만 벗기고\n // 리터럴 '**...**' 텍스트는 보존\n const m = l.match(/^\\*\\*([\\s\\S]*)\\*\\*$/)\n const unwrap = m && /^\\d+\\.\\s/.test(unescapeGfm(m[1]))\n return stripCellTokens(unescapeGfm(unwrap ? m![1] : l)).trim()\n }).filter(Boolean)\n return applyCellEdit(table, scanTable, 0, 0, newLines, ctx, orig.raw, edited.raw, orig.lines.length)\n }\n\n if (table.cols === 1 && table.rows >= 2) {\n const replica: { line: string; gridR: number }[] = []\n for (let r = 0; r < table.rows; r++) {\n const line = escapeGfm(sanitizeText(table.cells[r][0].text)).replace(/\\n/g, \" \")\n if (line) replica.push({ line, gridR: r })\n }\n if (replica.map(x => x.line).join(\"\\n\") !== orig.lines.join(\"\\n\")) return skip(\"표 좌표 재현 불일치 — 매핑 신뢰 불가\")\n if (edited.lines.length !== replica.length) return skip(\"표 행 추가/삭제는 미지원 (표 구조 변경)\")\n let applied = 0\n for (let i = 0; i < replica.length; i++) {\n if (replica[i].line === edited.lines[i]) continue\n if (extractCellTokens(replica[i].line) !== extractCellTokens(edited.lines[i])) {\n skip(\"셀 내 이미지 변경은 미지원\")\n continue\n }\n const newLines = [stripCellTokens(unescapeGfm(edited.lines[i])).trim()].filter(Boolean)\n applied += applyCellEdit(table, scanTable, replica[i].gridR, 0, newLines, ctx, replica[i].line, edited.lines[i], 1)\n }\n return applied\n }\n\n return skip(\"표 렌더 경로 식별 실패\")\n}\n\n// ── 셀 공통 적용 ──\n\n/**\n * 격자 좌표 (gridR, gridC)의 셀에 새 텍스트 라인들을 적용.\n * 라인 ↔ 셀 내 비어있지 않은 문단 순서 매핑 (filler-hwpx 치환 전략).\n * (session.ts 블록 단위 셀 편집에서도 공용)\n */\nexport function applyCellEdit(\n table: IRTable, scanTable: ScanTable, gridR: number, gridC: number,\n newLines: string[], ctx: TablePatchCtx, before: string, after: string,\n origLineCount?: number,\n): number {\n const skip = (reason: string) => {\n ctx.skipped.push({ reason, before: summarize(before), after: summarize(after) })\n return 0\n }\n const cell = scanTable.cellByAnchor.get(`${gridR},${gridC}`)\n if (!cell) return skip(\"셀 좌표 매핑 실패 (병합 영역의 빈 칸이거나 좌표 불일치)\")\n\n // 셀 콘텐츠 검증 — 스캔 문단 합산과 IR 셀 텍스트의 정규화 일치\n // (IR 셀 텍스트의 이미지 토큰은 스캔 문단에 없는 평탄화 산물이므로 제외)\n const irCell = table.cells[gridR]?.[gridC]\n const scanJoined = cell.paragraphs.map(p => p.text).filter(t => normForMatch(t)).join(\"\\n\")\n if (irCell && normForMatch(scanJoined) !== normForMatch(stripCellTokens(irCell.text))) {\n // 중첩표/글상자 등 구조 셀 — 평탄화 텍스트가 섞여 1:1 치환 불가\n if (normForMatch(irCell.text) !== \"\" || normForMatch(scanJoined) !== \"\") {\n const flatBlocks = (irCell.blocks ?? []).filter(b => b.type === \"paragraph\" || b.type === \"heading\")\n const flatJoined = flatBlocks.map(b => b.text ?? \"\").join(\"\\n\")\n if (normForMatch(scanJoined) !== normForMatch(flatJoined)) {\n return skip(\"셀 콘텐츠 구조 복잡 (중첩표/글상자) — 매핑 신뢰 불가\")\n }\n }\n }\n\n const nonEmpty = cell.paragraphs.filter(p => normForMatch(p.text) !== \"\")\n // 원본 마크다운 라인 수 ≠ 실제 문단 수면 셀 텍스트에 리터럴 '<br>'(또는 문단 내\n // 강제 줄바꿈)이 있다는 뜻 — 라인↔문단 매핑이 모호하므로 정직하게 skip\n if (origLineCount !== undefined && nonEmpty.length > 0 && origLineCount !== nonEmpty.length) {\n return skip(\"셀 줄 경계 매핑 모호 (리터럴 <br>/문단 내 줄바꿈) — 미지원\")\n }\n const splices: SpliceEdit[] = []\n let sectionIndex = -1\n\n // 기록될 텍스트가 재파싱 sanitize에서 변형되면(이중 공백 등) 무손실이 깨짐\n const unstable = newLines.find(l => sanitizeText(l) !== l)\n if (unstable !== undefined) return skip(\"공백 정규화 불안정 텍스트 — 패치 시 원문 보존 불가로 미지원\")\n\n if (nonEmpty.length === 0) {\n // 빈 셀에 텍스트 채우기 — 첫 문단에 삽입\n if (newLines.length === 0) return 0\n const target = cell.paragraphs[0]\n if (!target) return skip(\"빈 셀에 문단이 없어 텍스트 삽입 불가\")\n const value = newLines.join(\" \")\n const xml = ctx.scans[target.sectionIndex]?.xml\n // 문단 raw t-도메인이 공백만일 때(IR상 빈 셀이나 XML엔 공백 문자 존재):\n // buildParagraphSplices는 그 공백 t를 통째 교체 대상으로 삼아 제거한다 —\n // 요청한 삽입 경계 밖의 원문 손실(#54). t 맨 앞에 zero-length 삽입해 보존한다.\n const rawT = xml ? paraTText(target, xml) : null\n let sp: SpliceEdit[] | null\n // rawT === null 은 t 안에 엔티티(` ` 등)나 태그가 있다는 뜻 — 통째 교체하면\n // IR 에 안 잡힌 그 원문이 사라진다(#54와 같은 손실이 엔티티 표기에서 재현).\n // 삽입 경계를 t-좌표로 특정할 수 없으므로 조용한 성공 대신 정직하게 skip 한다.\n if (xml && rawT === null) {\n return skip(\"빈 셀 문단에 엔티티·태그가 있어 삽입 경계를 특정할 수 없음 — 원문 손실 방지로 미적용\")\n }\n if (xml && rawT !== null && rawT.length > 0 && rawT.trim() === \"\") {\n sp = buildRangeSplices(target, xml, 0, 0, value)\n // 삽입 경계를 유일하게 정할 수 없으면(엔티티/내부 태그로 t-좌표 불일치) 조용한\n // 성공 대신 정직하게 skip — 원문 손실 방지(fail-closed)\n if (sp === null) return skip(\"빈 셀 공백 보존 삽입 경계 모호 — 원문 손실 방지로 미적용\")\n } else {\n sp = buildParagraphSplices(target, value, xml)\n if (sp === null) return skip(\"셀 문단에 텍스트 노드를 만들 수 없음\")\n }\n splices.push(...sp)\n sectionIndex = target.sectionIndex\n if (newLines.length > 1) {\n ctx.skipped.push({ reason: \"셀 내 줄 추가는 문단 생성 미지원 — 한 문단으로 병합 적용\", after: summarize(after), partial: true })\n }\n } else {\n // 라인 → 문단 순서 매핑\n const assigned: string[] = []\n for (let i = 0; i < nonEmpty.length; i++) {\n if (i < newLines.length) {\n assigned.push(i === nonEmpty.length - 1 && newLines.length > nonEmpty.length\n ? newLines.slice(i).join(\" \") // 넘치는 줄은 마지막 문단에 병합\n : newLines[i])\n } else {\n assigned.push(\"\") // 줄이 줄어든 경우 비움\n }\n }\n if (newLines.length > nonEmpty.length) {\n ctx.skipped.push({ reason: \"셀 내 줄 추가는 문단 생성 미지원 — 마지막 문단에 병합 적용\", after: summarize(after), partial: true })\n } else if (newLines.length < nonEmpty.length && nonEmpty.length > 1) {\n // 텍스트는 편집대로 반영되지만 문단 자체는 제거하지 못함 — 뷰어에서 빈 줄로 보일 수 있음\n ctx.skipped.push({ reason: \"셀 내 줄 삭제는 문단 제거 미지원 — 빈 문단 잔존(뷰어에 빈 줄 표시 가능)\", before: summarize(before), after: summarize(after), partial: true })\n }\n for (let i = 0; i < nonEmpty.length; i++) {\n // assigned는 sanitize된 마크다운 도메인, nonEmpty[i].text는 XML 원문 — 정규화\n // 동치면 미편집 문단이므로 재작성하지 않는다 (공백·run 서식 보존)\n if (assigned[i] === nonEmpty[i].text || normForMatch(assigned[i]) === normForMatch(nonEmpty[i].text)) continue\n const sp = buildParagraphSplices(nonEmpty[i], assigned[i], ctx.scans[nonEmpty[i].sectionIndex]?.xml)\n if (sp === null) return skip(\"셀 문단에 텍스트 노드를 만들 수 없음\")\n splices.push(...sp)\n sectionIndex = nonEmpty[i].sectionIndex\n }\n }\n\n if (splices.length === 0) return 0\n ctx.sectionSplices[sectionIndex].push(...splices)\n return 1\n}\n","/**\n * 라운드트립 표 삽입 — 문단(텍스트)을 표로 인플레이스 변환할 때 쓰는 표 XML 빌더.\n *\n * patchHwpx에서 편집된 마크다운의 한 문단이 표(GFM/HTML)로 바뀐 경우, 원본\n * <hp:p> 범위를 여기서 만든 표 문단 XML로 splice 치환한다. 표 셀 테두리는\n * 원본 header.xml의 <hh:borderFills>에 실선 borderFill을 1개 append해 참조한다\n * (기존 리소스는 1바이트도 건드리지 않고 새 id만 추가).\n *\n * 표 XML 골격은 generator.ts generateTable과 동일(한컴이 거부하지 않는 필수\n * 속성 세트 — 이슈 #4)하되, borderFill/charPr/paraPr/instId를 원본 문서 좌표에\n * 맞춰 파라미터화한다.\n */\n\nimport { escapeXmlText, type SpliceEdit } from \"./source-map.js\"\nimport { unescapeGfmCell } from \"./markdown-units.js\"\n\n// 표 기본 치수 (HWPUnit) — generator.ts generateTable과 동일\nconst TABLE_USABLE_WIDTH = 44000 // A4 portrait 본문 폭 근사\nconst TABLE_ROW_HEIGHT = 1500\n\n/** 문서 내 `id=\"<숫자>\"` 속성의 최댓값 — 새 instId/borderFill id 충돌 회피용 */\nexport function collectMaxNumericId(xmls: string[]): number {\n let max = -1\n for (const xml of xmls) {\n for (const m of xml.matchAll(/\\bid(?:Ref)?=\"(\\d{1,10})\"/g)) {\n const v = parseInt(m[1], 10)\n if (!isNaN(v) && v > max) max = v\n }\n }\n return max\n}\n\n/** 표 셀 실선 테두리 borderFill 정의 (generator.ts header id=1과 동일 구조) */\nfunction cellBorderFillXml(id: number): string {\n return `<hh:borderFill id=\"${id}\" threeD=\"0\" shadow=\"0\" centerLine=\"0\" breakCellSeparateLine=\"0\">`\n + `<hh:slash type=\"NONE\" Crooked=\"0\" isCounter=\"0\"/>`\n + `<hh:backSlash type=\"NONE\" Crooked=\"0\" isCounter=\"0\"/>`\n + `<hh:leftBorder type=\"SOLID\" width=\"0.12 mm\" color=\"#000000\"/>`\n + `<hh:rightBorder type=\"SOLID\" width=\"0.12 mm\" color=\"#000000\"/>`\n + `<hh:topBorder type=\"SOLID\" width=\"0.12 mm\" color=\"#000000\"/>`\n + `<hh:bottomBorder type=\"SOLID\" width=\"0.12 mm\" color=\"#000000\"/>`\n + `<hh:diagonal type=\"NONE\" width=\"0.1 mm\" color=\"#000000\"/>`\n + `<hh:fillInfo/>`\n + `</hh:borderFill>`\n}\n\nexport interface BorderFillInjection {\n /** 새로 추가된 borderFill의 id (표 셀이 참조) */\n borderFillId: number\n /** header.xml에 적용할 splice들 (itemCnt 증가 + borderFill append) */\n headerSplices: SpliceEdit[]\n}\n\n/**\n * header.xml의 <hh:borderFills>에 실선 borderFill을 1개 추가하는 splice를 만든다.\n * 기존 borderFill은 그대로 두고 새 id만 append. 구조를 못 찾으면 null.\n *\n * @param headerXml 원본 header.xml\n * @param newId 부여할 borderFill id (문서 전역 max+1 등 충돌 없는 값)\n */\nexport function injectCellBorderFill(headerXml: string, newId: number): BorderFillInjection | null {\n const openM = headerXml.match(/<hh:borderFills\\b([^>]*)>/)\n if (!openM || openM.index === undefined) return null\n const closeIdx = headerXml.indexOf(\"</hh:borderFills>\")\n if (closeIdx < 0) return null\n\n const splices: SpliceEdit[] = []\n\n // itemCnt 1 증가 (있으면) — 없으면 한컴이 자식 수로 추정하므로 생략 가능\n const itemCntM = openM[1].match(/\\bitemCnt=\"(\\d+)\"/)\n if (itemCntM && itemCntM.index !== undefined) {\n const cnt = parseInt(itemCntM[1], 10)\n const attrStart = openM.index + \"<hh:borderFills\".length + itemCntM.index\n const valStart = attrStart + itemCntM[0].indexOf('\"') + 1\n const valEnd = valStart + String(cnt).length\n splices.push({ start: valStart, end: valEnd, replacement: String(cnt + 1) })\n }\n\n // 닫는 태그 앞에 새 borderFill append\n splices.push({ start: closeIdx, end: closeIdx, replacement: cellBorderFillXml(newId) })\n\n return { borderFillId: newId, headerSplices: splices }\n}\n\n/** GFM/HTML 셀 마크다운 → 셀 평문 (인라인 서식 제거, 줄바꿈은 공백 병합) */\nfunction cellPlainText(raw: string): string {\n let t = unescapeGfmCell(raw) // <br>→\\n, \\|→|, \\~→~\n // 인라인 마크다운 평문화 — 원본 header에 대응 charPr가 없으므로 서식 없이 텍스트만\n t = t.replace(/\\*\\*\\*([^*]+)\\*\\*\\*/g, \"$1\")\n .replace(/\\*\\*([^*]+)\\*\\*/g, \"$1\")\n .replace(/\\*([^*]+)\\*/g, \"$1\")\n .replace(/`([^`]+)`/g, \"$1\")\n // 셀 내 줄바꿈은 한 문단으로 (셀당 단일 hp:p)\n return t.replace(/\\s*\\n\\s*/g, \" \").trim()\n}\n\nexport interface BuildTableOptions {\n borderFillId: number\n /** 표를 담는 바깥 문단의 paraPrIDRef (원본 문단 속성 승계) */\n outerParaPrId: number\n /** 셀 내부 문단/런이 참조할 paraPr·charPr id (원본에 존재하는 기본값, 보통 0) */\n cellParaPrId: number\n cellCharPrId: number\n /** 표 instId (문서 전역 유니크) */\n tableId: number\n}\n\n/**\n * 표 행렬 → 인플레이스 삽입용 표 문단 XML.\n * generator.ts generateTable과 동일한 필수 속성 골격(한컴 호환), 리소스 id만 원본 좌표.\n */\nexport function buildTableParagraphXml(rows: string[][], opts: BuildTableOptions): string {\n const { borderFillId, outerParaPrId, cellParaPrId, cellCharPrId, tableId } = opts\n const rowCnt = rows.length\n const colCnt = Math.max(...rows.map(r => r.length), 1)\n const cellW = Math.floor(TABLE_USABLE_WIDTH / colCnt)\n const cellH = TABLE_ROW_HEIGHT\n const tblW = cellW * colCnt\n const tblH = cellH * rowCnt\n\n const trElements = rows.map((row, rowIdx) => {\n const cells = row.length < colCnt ? [...row, ...Array(colCnt - row.length).fill(\"\")] : row\n const isHeaderRow = rowIdx === 0\n const tdElements = cells.map((cell, colIdx) => {\n const text = escapeXmlText(cellPlainText(cell))\n const cellP = `<hp:p paraPrIDRef=\"${cellParaPrId}\" styleIDRef=\"0\"><hp:run charPrIDRef=\"${cellCharPrId}\"><hp:t>${text}</hp:t></hp:run></hp:p>`\n return `<hp:tc name=\"\" header=\"${isHeaderRow ? 1 : 0}\" hasMargin=\"0\" protect=\"0\" editable=\"1\" dirty=\"0\" borderFillIDRef=\"${borderFillId}\">`\n + `<hp:subList id=\"\" textDirection=\"HORIZONTAL\" lineWrap=\"BREAK\" vertAlign=\"TOP\" linkListIDRef=\"0\" linkListNextIDRef=\"0\" textWidth=\"0\" textHeight=\"0\" hasTextRef=\"0\" hasNumRef=\"0\">${cellP}</hp:subList>`\n + `<hp:cellAddr colAddr=\"${colIdx}\" rowAddr=\"${rowIdx}\"/>`\n + `<hp:cellSpan colSpan=\"1\" rowSpan=\"1\"/>`\n + `<hp:cellSz width=\"${cellW}\" height=\"${cellH}\"/>`\n + `<hp:cellMargin left=\"141\" right=\"141\" top=\"141\" bottom=\"141\"/>`\n + `</hp:tc>`\n }).join(\"\")\n return `<hp:tr>${tdElements}</hp:tr>`\n }).join(\"\")\n\n const tblInner = `<hp:sz width=\"${tblW}\" widthRelTo=\"ABSOLUTE\" height=\"${tblH}\" heightRelTo=\"ABSOLUTE\" protect=\"0\"/>`\n + `<hp:pos treatAsChar=\"1\" affectLSpacing=\"0\" flowWithText=\"0\" allowOverlap=\"0\" holdAnchorAndSO=\"0\" vertRelTo=\"PARA\" horzRelTo=\"PARA\" vertAlign=\"TOP\" horzAlign=\"LEFT\" vertOffset=\"0\" horzOffset=\"0\"/>`\n + `<hp:outMargin left=\"0\" right=\"0\" top=\"0\" bottom=\"0\"/>`\n + `<hp:inMargin left=\"510\" right=\"510\" top=\"141\" bottom=\"141\"/>`\n + trElements\n\n const tbl = `<hp:tbl id=\"${tableId}\" zOrder=\"0\" numberingType=\"TABLE\" pageBreak=\"CELL\" repeatHeader=\"0\" rowCnt=\"${rowCnt}\" colCnt=\"${colCnt}\" cellSpacing=\"0\" borderFillIDRef=\"${borderFillId}\" noShading=\"0\">${tblInner}</hp:tbl>`\n\n // 표는 문단 안의 run에 inline-anchored (generator.ts와 동일)\n return `<hp:p paraPrIDRef=\"${outerParaPrId}\" styleIDRef=\"0\"><hp:run charPrIDRef=\"${cellCharPrId}\">${tbl}</hp:run></hp:p>`\n}\n","/**\n * HWPX ZIP 섹션 엔트리 해석 — patcher/session/filler 공용.\n *\n * manifest(content.hpf) 기반으로 파서(parser.ts resolveSectionPaths)와 동일한\n * 섹션 목록을 만든다. zip 엔트리 정확 일치만 포함 (대소문자 보정 금지 — 파서가\n * 못 본 섹션이 스캔에 끼면 중복 텍스트 문단 수정이 비가시 섹션에 적용되는\n * cross-section bleed 발생).\n */\n\nimport type JSZip from \"jszip\"\nimport { normalizeSectionHref, compareSectionPaths } from \"../utils.js\"\n\nexport async function resolveSectionEntryNames(zip: JSZip): Promise<string[]> {\n for (const mp of [\"Contents/content.hpf\", \"content.hpf\"]) {\n const f = zip.file(mp)\n if (!f) continue\n const xml = await f.async(\"text\")\n const paths = sectionPathsFromManifest(xml).filter(p => zip.file(p) !== null)\n if (paths.length > 0) return paths\n }\n return Object.keys(zip.files).filter(n => /[Ss]ection\\d+\\.xml$/.test(n)).sort(compareSectionPaths)\n}\n\nfunction sectionPathsFromManifest(xml: string): string[] {\n const attr = (tag: string, name: string): string => {\n const m = tag.match(new RegExp(`(?:^|\\\\s)${name}\\\\s*=\\\\s*(?:\"([^\"]*)\"|'([^']*)')`))\n return m ? (m[1] ?? m[2]) : \"\"\n }\n const idToHref = new Map<string, string>()\n for (const m of xml.matchAll(/<opf:item(\\s(?:\"[^\"]*\"|'[^']*'|[^>\"'])*?)\\/?>/g)) {\n const id = attr(m[1], \"id\")\n const href = normalizeSectionHref(attr(m[1], \"href\"))\n if (id && href) idToHref.set(id, href)\n }\n const ordered: string[] = []\n for (const m of xml.matchAll(/<opf:itemref(\\s(?:\"[^\"]*\"|'[^']*'|[^>\"'])*?)\\/?>/g)) {\n const href = idToHref.get(attr(m[1], \"idref\"))\n if (href) ordered.push(href)\n }\n if (ordered.length > 0) return ordered\n return Array.from(idToHref.values()).sort(compareSectionPaths)\n}\n","/**\n * HWP 5.x 바이너리 서식 보존 무손실 라운드트립 패치 — patchHwpx의 HWP5 대응.\n *\n * parse()로 얻은 마크다운을 편집한 뒤 patchHwp()에 넘기면, 원본 HWP의\n * CFB/레코드 구조를 그대로 두고 변경된 문단/표 셀의 PARA_TEXT만 치환한다.\n * 연쇄 갱신: PARA_HEADER nChars, CHAR_SHAPE 위치, LINE_SEG 재구성, 레코드\n * 크기 재계산 → 섹션 스트림 재직렬화 → deflate 재압축 → CFB 재조립.\n *\n * 안전 게이트 (하나라도 깨지면 해당 수정은 graceful skip — 파일 무결성 우선):\n * - 섹션 레코드 재직렬화가 원본과 바이트 동일해야 패치 허용\n * - ctrlMask=0(순수 텍스트) + PARA_TEXT 1개 + 레코드 텍스트 재구성 일치 문단만 수정\n * - 배포용/암호화/DRM 문서는 전체 거부\n *\n * 지원: 본문 문단/헤딩 텍스트 수정, GFM 표 셀 텍스트 수정 (좌표 기반).\n * 미지원(graceful skip): 블록 추가/삭제, 표 구조 변경, HTML 표 셀, 캡션·각주·\n * 머리말/꼬리말, 컨트롤(탭/개체/필드) 포함 문단. skipped[]에 사유 보고.\n */\n\nimport { deflateRawSync } from \"zlib\"\nimport { createRequire } from \"module\"\nimport { parseHwp5Document } from \"../hwp5/parser.js\"\nimport {\n decompressStream, parseFileHeader, createParaTextState, appendParaText, isExtendedOnlyCtrlChar,\n TAG_PARA_HEADER, TAG_PARA_TEXT, TAG_CHAR_SHAPE, TAG_CTRL_HEADER, TAG_LIST_HEADER, TAG_TABLE,\n FLAG_COMPRESSED, FLAG_ENCRYPTED, FLAG_DISTRIBUTION, FLAG_DRM,\n} from \"../hwp5/record.js\"\nimport type { IRBlock, IRTable, PatchOptions, PatchResult, PatchSkip, DiffResult } from \"../types.js\"\nimport {\n buildOrigUnits, alignUnits, diffUnitLists, textUnitToPlain, type OrigUnit,\n} from \"./patcher.js\"\nimport {\n splitMarkdownUnits, normForMatch, sanitizeText, parseGfmTable, unescapeGfmCell, unescapeGfm, escapeGfm, summarize,\n replicateTableToHtml, replicateHtmlTable, parseHtmlTable, htmlCellInnerToLines, extractTopLevelTables,\n AUTONUM_PREFIX_RE,\n type MdUnit,\n} from \"./markdown-units.js\"\nimport { stripCellTokens, extractCellTokens, extractImgTags } from \"./table-patch.js\"\nimport { replaceOleStream } from \"./ole-surgeon.js\"\n\nconst require = createRequire(import.meta.url)\nconst CFB: CfbModule = require(\"cfb\")\n\ninterface CfbEntry { name?: string; content?: Buffer | Uint8Array; size?: number }\ninterface CfbContainer { FileIndex: CfbEntry[]; FullPaths: string[] }\ninterface CfbModule {\n parse(data: Buffer): CfbContainer\n find(cfb: CfbContainer, path: string): CfbEntry | null\n write(cfb: CfbContainer, opts: { type: \"buffer\" }): Buffer\n}\n\n// 본문 레코드 태그 — record.ts의 TAG_PARA_SHAPE(0x45)는 본문 맥락에선 LINE_SEG\nconst TAG_PARA_LINE_SEG = 0x0045\n\n/** 4바이트 ASCII → u32 컨트롤 ID (\"tbl \" → 0x74626c20) — parser.ts cid와 동일 */\nfunction cid(s: string): number {\n return ((s.charCodeAt(0) << 24) | (s.charCodeAt(1) << 16) | (s.charCodeAt(2) << 8) | s.charCodeAt(3)) >>> 0\n}\nconst CTRL_TBL = cid(\"tbl \")\nconst CTRL_GSO = cid(\"gso \")\n\nfunction swap32(id: number): number {\n return (((id & 0xff) << 24) | (((id >>> 8) & 0xff) << 16) | (((id >>> 16) & 0xff) << 8) | ((id >>> 24) & 0xff)) >>> 0\n}\nfunction isCtrl(rec: RawRecord, id: number): boolean {\n if (rec.tagId !== TAG_CTRL_HEADER || rec.data.length < 4) return false\n const raw = rec.data.readUInt32LE(0)\n return raw === id || swap32(raw) === id\n}\n\n// ─── 레코드 입출력 (엄격 모드 + 재직렬화 동일성 게이트) ──\n\ninterface RawRecord { tagId: number; level: number; data: Buffer }\n\n/** 스트림 끝까지 정확히 소비될 때만 성공 — 잔여/비정형 바이트가 있으면 null */\nfunction readRecordsStrict(stream: Buffer): RawRecord[] | null {\n const recs: RawRecord[] = []\n let off = 0\n while (off < stream.length) {\n if (off + 4 > stream.length) return null\n const h = stream.readUInt32LE(off); off += 4\n const tagId = h & 0x3ff\n const level = (h >>> 10) & 0x3ff\n let size = (h >>> 20) & 0xfff\n if (size === 0xfff) {\n if (off + 4 > stream.length) return null\n size = stream.readUInt32LE(off); off += 4\n }\n if (off + size > stream.length) return null\n recs.push({ tagId, level, data: stream.subarray(off, off + size) })\n off += size\n }\n return recs\n}\n\nfunction serializeRecords(recs: RawRecord[], repl?: Map<number, Buffer>, inserts?: Map<number, RawRecord[]>): Buffer {\n const parts: Buffer[] = []\n const push = (tagId: number, level: number, data: Buffer) => {\n const ext = data.length >= 0xfff\n const header = Buffer.alloc(ext ? 8 : 4)\n header.writeUInt32LE(((tagId & 0x3ff) | ((level & 0x3ff) << 10) | ((ext ? 0xfff : data.length) << 20)) >>> 0, 0)\n if (ext) header.writeUInt32LE(data.length, 4)\n parts.push(header, data)\n }\n for (let i = 0; i < recs.length; i++) {\n for (const ins of inserts?.get(i) ?? []) push(ins.tagId, ins.level, ins.data)\n push(recs[i].tagId, recs[i].level, repl?.get(i) ?? recs[i].data)\n }\n return Buffer.concat(parts)\n}\n\n// ─── 섹션 스캔 ───────────────────────────────────────\n\ninterface ScanPara5 {\n sectionIndex: number\n headerIdx: number\n kind: \"body\" | \"cell\" | \"other\"\n /** PARA_TEXT 레코드 인덱스: -1=없음(빈 문단), -2=복수(미지원) */\n textIdx: number\n charShapeIdx: number\n lineSegIdx: number\n rangeTagCount: number\n ctrlMask: number\n nCharsRaw: number\n /** extractText 결과 (트림 전 원문) */\n rawText: string\n}\n\ninterface ScanCell5 { paras: ScanPara5[] }\n\ninterface ScanTable5 {\n sectionIndex: number\n rows: number\n cols: number\n /** \"row,col\" → 셀 (앵커 좌표 기준) */\n cells: Map<string, ScanCell5>\n}\n\ninterface SectionScan5 {\n records: RawRecord[]\n /** 재직렬화 바이트 동일성 통과 여부 — 실패 시 이 섹션 패치 금지 */\n safe: boolean\n paras: ScanPara5[]\n tables: ScanTable5[]\n compressed: boolean\n /** 수정 스테이징: 레코드 인덱스 → 새 데이터 */\n repl: Map<number, Buffer>\n /** 삽입 스테이징: 레코드 인덱스 → 그 레코드 앞에 삽입할 신규 레코드들 */\n inserts: Map<number, RawRecord[]>\n}\n\nfunction scanSection(stream: Buffer, sectionIndex: number, compressed: boolean): SectionScan5 {\n const records = readRecordsStrict(stream)\n if (!records) return { records: [], safe: false, paras: [], tables: [], compressed, repl: new Map(), inserts: new Map() }\n const safe = serializeRecords(records).equals(stream)\n\n // 부모 인덱스 계산 (level 기반 스택)\n const parent = new Int32Array(records.length).fill(-1)\n const stack: number[] = []\n for (let i = 0; i < records.length; i++) {\n while (stack.length > 0 && records[stack[stack.length - 1]].level >= records[i].level) stack.pop()\n parent[i] = stack.length > 0 ? stack[stack.length - 1] : -1\n stack.push(i)\n }\n const ancestorCtrl = (i: number, id: number): boolean => {\n for (let p = parent[i]; p >= 0; p = parent[p]) if (isCtrl(records[p], id)) return true\n return false\n }\n\n // 문단 수집\n const paras: ScanPara5[] = []\n const parasByHeader = new Map<number, ScanPara5>()\n for (let i = 0; i < records.length; i++) {\n const rec = records[i]\n if (rec.tagId !== TAG_PARA_HEADER || rec.data.length < 18) continue\n let textIdx = -1\n let charShapeIdx = -1\n let lineSegIdx = -1\n const state = createParaTextState()\n for (let j = i + 1; j < records.length && records[j].level > rec.level; j++) {\n if (records[j].level !== rec.level + 1) continue\n const t = records[j].tagId\n if (t === TAG_PARA_TEXT) {\n textIdx = textIdx === -1 ? j : -2\n appendParaText(state, records[j].data)\n } else if (t === TAG_CHAR_SHAPE && charShapeIdx === -1) charShapeIdx = j\n else if (t === TAG_PARA_LINE_SEG && lineSegIdx === -1) lineSegIdx = j\n }\n\n // 분류: 컨트롤 무관(또는 글상자 내부) → body, 그 외 → other.\n // 표 셀 문단은 아래 표 수집 패스에서 \"cell\"로 재분류된다 (셀 문단은\n // LIST_HEADER의 자식이 아니라 같은 레벨 형제 — 부모 체인으론 식별 불가).\n let ctrlSeen = false, nonGso = false\n for (let a = parent[i]; a >= 0; a = parent[a]) {\n if (records[a].tagId === TAG_CTRL_HEADER) {\n ctrlSeen = true\n if (!isCtrl(records[a], CTRL_GSO)) nonGso = true\n }\n }\n const kind: ScanPara5[\"kind\"] = !ctrlSeen || !nonGso ? \"body\" : \"other\"\n\n const para: ScanPara5 = {\n sectionIndex, headerIdx: i, kind, textIdx, charShapeIdx, lineSegIdx,\n rangeTagCount: rec.data.readUInt16LE(14),\n ctrlMask: rec.data.readUInt32LE(4),\n nCharsRaw: rec.data.readUInt32LE(0),\n rawText: state.text,\n }\n paras.push(para)\n parasByHeader.set(i, para)\n }\n\n // 최상위 표 수집 (다른 tbl 내부에 중첩된 표 제외 — IR 최상위 표 서수와 정렬)\n const tables: ScanTable5[] = []\n for (let i = 0; i < records.length; i++) {\n if (!isCtrl(records[i], CTRL_TBL) || ancestorCtrl(i, CTRL_TBL)) continue\n const ctrlLevel = records[i].level\n let rows = 0, cols = 0, tableIdx = -1\n for (let j = i + 1; j < records.length && records[j].level > ctrlLevel; j++) {\n if (records[j].level === ctrlLevel + 1 && records[j].tagId === TAG_TABLE && records[j].data.length >= 8) {\n rows = records[j].data.readUInt16LE(4)\n cols = records[j].data.readUInt16LE(6)\n tableIdx = j\n break\n }\n }\n if (tableIdx < 0 || rows === 0 || cols === 0) continue\n // 셀 문단은 LIST_HEADER와 같은 레벨의 후속 형제 — parser.ts parseCell과 동일 경계\n const cells = new Map<string, ScanCell5>()\n let j = tableIdx + 1\n while (j < records.length && records[j].level > ctrlLevel) {\n if (records[j].tagId !== TAG_LIST_HEADER) { j++; continue }\n const lh = records[j]\n const cellLevel = lh.level\n const cellParas: ScanPara5[] = []\n let k = j + 1\n while (k < records.length) {\n const r = records[k]\n if (r.level < cellLevel) break\n if (r.level === cellLevel && (r.tagId === TAG_LIST_HEADER || r.tagId === TAG_TABLE)) break\n if (r.level === cellLevel && r.tagId === TAG_PARA_HEADER) {\n const cp = parasByHeader.get(k)\n if (cp) { cp.kind = \"cell\"; cellParas.push(cp) }\n }\n k++\n }\n if (lh.data.length >= 16) {\n cells.set(`${lh.data.readUInt16LE(10)},${lh.data.readUInt16LE(8)}`, { paras: cellParas })\n }\n j = k\n }\n tables.push({ sectionIndex, rows, cols, cells })\n }\n\n return { records, safe, paras, tables, compressed, repl: new Map(), inserts: new Map() }\n}\n\n// ─── 메인 API ────────────────────────────────────────\n\n/**\n * 원본 HWP 5.x와 편집된 마크다운으로 서식 보존 패치본을 만든다.\n *\n * @param original 원본 HWP 바이트 (OLE2/CFB)\n * @param editedMarkdown parse(original).markdown을 편집한 마크다운\n */\nexport async function patchHwp(\n original: Uint8Array,\n editedMarkdown: string,\n options?: PatchOptions,\n): Promise<PatchResult> {\n const skipped: PatchSkip[] = []\n let applied = 0\n const originalBuf = Buffer.from(original.buffer, original.byteOffset, original.byteLength)\n\n // 1) CFB + FileHeader — 배포용/암호화 거부\n let cfb: CfbContainer\n try {\n cfb = CFB.parse(originalBuf)\n } catch (err) {\n return fail(`CFB 컨테이너 파싱 실패: ${msg(err)}`)\n }\n const fhEntry = CFB.find(cfb, \"/FileHeader\")\n if (!fhEntry?.content) return fail(\"FileHeader 스트림이 없습니다 — HWP 5.x 파일이 아닙니다\")\n let flags: number\n try {\n flags = parseFileHeader(Buffer.from(fhEntry.content)).flags\n } catch (err) {\n return fail(`FileHeader 파싱 실패: ${msg(err)}`)\n }\n if (flags & (FLAG_ENCRYPTED | FLAG_DISTRIBUTION | FLAG_DRM)) {\n return fail(\"암호화/배포용/DRM 문서는 패치를 지원하지 않습니다\")\n }\n const compressed = (flags & FLAG_COMPRESSED) !== 0\n\n // 2) 원본 파싱 (기존 파서 그대로 — IR 블록 확보)\n let origBlocks: IRBlock[]\n try {\n origBlocks = parseHwp5Document(originalBuf).blocks\n } catch (err) {\n return fail(`원본 HWP 파싱 실패: ${msg(err)}`)\n }\n\n // 3) 섹션 스트림 스캔\n const sectionPaths = cfb.FullPaths\n .map(p => p.replace(/^Root Entry/, \"\"))\n .filter(p => /^\\/BodyText\\/Section\\d+$/.test(p))\n .sort((a, b) => Number(a.match(/\\d+$/)![0]) - Number(b.match(/\\d+$/)![0]))\n if (sectionPaths.length === 0) return fail(\"BodyText 섹션 스트림을 찾을 수 없습니다\")\n\n const scans: SectionScan5[] = []\n for (let i = 0; i < sectionPaths.length; i++) {\n const entry = CFB.find(cfb, sectionPaths[i])\n if (!entry?.content) return fail(`섹션 스트림 읽기 실패: ${sectionPaths[i]}`)\n let stream: Buffer\n try {\n stream = compressed ? decompressStream(Buffer.from(entry.content)) : Buffer.from(entry.content)\n } catch (err) {\n return fail(`섹션 압축 해제 실패: ${msg(err)}`)\n }\n scans.push(scanSection(stream, i, compressed))\n }\n\n // 4) 유닛 구성 + 정렬 (HWPX 패처와 동일한 마크다운 도메인 diff)\n const origUnits = buildOrigUnits(origBlocks)\n const editedUnits = splitMarkdownUnits(editedMarkdown)\n const pairs = alignUnits(origUnits.map(u => u.raw), editedUnits.map(u => u.raw))\n\n const paraMap = resolveParaMappings(origBlocks, scans)\n const tableMap = resolveTableMappings(origBlocks, scans.flatMap(s => s.tables))\n\n // 5) 변경 적용 (스테이징)\n for (const [oi, ei] of pairs) {\n if (oi !== null && ei !== null) {\n const orig = origUnits[oi]\n const edited = editedUnits[ei]\n if (orig.raw === edited.raw) continue\n applied += handleModified(orig, edited, {\n origBlocks, paraMap, scans, tableMap, skipped,\n })\n } else if (oi !== null) {\n skipped.push({ reason: \"블록 삭제는 미지원 (v1) — 원본 유지\", before: summarize(origUnits[oi].raw) })\n } else if (ei !== null) {\n skipped.push({ reason: \"블록 추가는 미지원 (v1)\", after: summarize(editedUnits[ei].raw) })\n }\n }\n\n // 6) 섹션 재직렬화 + 재압축 + 섹터 레벨 in-place 교체 — 컨테이너 전체 재조립 없음\n // (수정된 섹션의 데이터 섹터/FAT 체인/디렉토리 start·size 외에는 원본 바이트 유지)\n let data: Uint8Array\n const dirty = scans.some(s => s.repl.size > 0 || s.inserts.size > 0)\n if (!dirty) {\n data = new Uint8Array(original)\n } else {\n try {\n let out = originalBuf\n for (let i = 0; i < scans.length; i++) {\n if (scans[i].repl.size === 0 && scans[i].inserts.size === 0) continue\n const newStream = serializeRecords(scans[i].records, scans[i].repl, scans[i].inserts)\n const content = compressed ? compressWithTail(newStream) : newStream\n out = replaceOleStream(out, sectionPaths[i], content)\n }\n data = new Uint8Array(out)\n } catch (err) {\n return { success: false, applied: 0, skipped, error: `HWP 섹터 수술 실패: ${msg(err)}` }\n }\n }\n\n // 7) 자동 검증 — 패치본 재파싱 vs 편집 마크다운\n let verification: DiffResult | undefined\n if (options?.verify !== false) {\n try {\n const reparsed = parseHwp5Document(Buffer.from(data))\n // 본문 문단은 \\n(재파싱 방출)과 <br>(편집)로 강제 줄바꿈 표기 규약이 달라 raw 비교가\n // 항상 잔차를 낸다 — 표기를 통일해 완전 적용된 패치를 '잔차'로 오보고하지 않게 한다 (hwp5-2)\n const normBr = (u: MdUnit): MdUnit => ({ ...u, raw: u.raw.replace(/<br\\s*\\/?\\s*>/gi, \"\\n\") })\n verification = diffUnitLists(splitMarkdownUnits(reparsed.markdown).map(normBr), editedUnits.map(normBr))\n } catch (err) {\n return { success: false, applied, skipped, error: `패치본 재파싱 실패 — 패치 중단: ${msg(err)}` }\n }\n }\n\n return { success: true, data, applied, skipped, verification }\n\n function fail(error: string): PatchResult {\n return { success: false, applied: 0, skipped, error }\n }\n}\n\nfunction msg(err: unknown): string {\n return err instanceof Error ? err.message : String(err)\n}\n\n// ─── 문단 매핑 (IR 블록 ↔ 스캔 문단) ─────────────────\n\ninterface ParaMapping5 {\n para?: ScanPara5\n /** 자동번호/글머리 접두가 IR 텍스트에 붙어 있었음 (레코드 텍스트에는 없음) */\n prefixStripped?: boolean\n}\n\n/**\n * 같은 정규화 텍스트끼리 등장 순서대로 페어링 (중복 문단 대응) — HWPX 패처와 동일 방식.\n * 셀 문단도 버킷에 포함 (flattenLayoutTables로 해체된 레이아웃 표 문단이 IR에선 문단 블록).\n * 단, 같은 텍스트가 여러 위치에 있고 본문 문단만으로 구성되지 않으면 모호 — 매핑 포기.\n */\nfunction resolveParaMappings(blocks: IRBlock[], scans: SectionScan5[]): Map<number, ParaMapping5> {\n const buckets = new Map<string, ScanPara5[]>()\n for (const scan of scans) {\n for (const para of scan.paras) {\n if (para.kind === \"other\") continue\n const key = normForMatch(para.rawText)\n if (!key) continue\n let list = buckets.get(key)\n if (!list) buckets.set(key, (list = []))\n list.push(para)\n }\n }\n /** 중복 텍스트는 전부 본문 문단일 때만 등장 순서 페어링 신뢰 가능 */\n const usable = (list: ScanPara5[]): boolean =>\n list.length === 1 || list.every(p => p.kind === \"body\")\n\n const counters = new Map<string, number>()\n const result = new Map<number, ParaMapping5>()\n for (let i = 0; i < blocks.length; i++) {\n const b = blocks[i]\n if ((b.type !== \"paragraph\" && b.type !== \"heading\") || !b.text) continue\n let key = normForMatch(b.text)\n let prefixStripped = false\n if (!buckets.has(key)) {\n // 자동번호/글머리 접두 제거 후 재시도 (파서가 붙인 headMarker)\n const sp = b.text.indexOf(\" \")\n if (sp > 0) {\n const alt = normForMatch(b.text.slice(sp + 1))\n if (alt && buckets.has(alt)) { key = alt; prefixStripped = true }\n }\n }\n const list = buckets.get(key)\n if (!list || !usable(list)) { result.set(i, {}); continue }\n const occ = counters.get(key) ?? 0\n counters.set(key, occ + 1)\n result.set(i, occ < list.length ? { para: list[occ], prefixStripped } : {})\n }\n return result\n}\n\n/**\n * IR 표 블록 ↔ 스캔 표 매핑. flattenLayoutTables가 일부 표를 문단으로 해체하면\n * IR 표 수 < 바이너리 표 수가 되어 단순 서수 인덱싱이 밀린다(엉뚱한 표 수정 위험).\n * 문서 순서를 보존한 채 rows×cols 시그니처로 매칭하고, 같은 시그니처 표가 여러 개면\n * 셀 텍스트 정합 점수로 택일한다. 매핑 못 한 표는 누락(조회 시 skip → 안전).\n */\nfunction resolveTableMappings(blocks: IRBlock[], scanTables: ScanTable5[]): Map<number, ScanTable5> {\n const result = new Map<number, ScanTable5>()\n let si = 0\n for (let i = 0; i < blocks.length; i++) {\n const table = blocks[i].table\n if (blocks[i].type !== \"table\" || !table) continue\n const cands: number[] = []\n for (let k = si; k < scanTables.length; k++) {\n if (scanTables[k].rows === table.rows && scanTables[k].cols === table.cols) cands.push(k)\n }\n // IR 은 후행 빈 열을 자른다(#47 기본 계약) — 열이 더 많은 스캔 표도 후보. 잘린 열은 항상 뒤쪽이라 (행, 열) 좌표가 그대로다\n if (cands.length === 0) {\n for (let k = si; k < scanTables.length; k++) {\n if (scanTables[k].rows === table.rows && scanTables[k].cols > table.cols) cands.push(k)\n }\n }\n if (cands.length === 0) continue\n let pick = cands[0]\n if (cands.length > 1) {\n let best = tableContentScore(table, scanTables[cands[0]])\n for (let ci = 1; ci < cands.length; ci++) {\n const sc = tableContentScore(table, scanTables[cands[ci]])\n if (sc > best) { best = sc; pick = cands[ci] }\n }\n }\n result.set(i, scanTables[pick])\n si = pick + 1\n }\n return result\n}\n\n/** 앵커 셀 좌표가 겹치는 셀들의 정규화 텍스트 일치 개수 (표 디스앰비규에이션용) */\nfunction tableContentScore(irTable: IRTable, scanTable: ScanTable5): number {\n let matched = 0\n for (const [key, scanCell] of scanTable.cells) {\n const comma = key.indexOf(\",\")\n const r = Number(key.slice(0, comma)), c = Number(key.slice(comma + 1))\n const irCell = irTable.cells[r]?.[c]\n if (!irCell) continue\n const a = normForMatch(scanCell.paras.map(p => p.rawText).join(\" \"))\n const b = normForMatch(stripCellTokens(irCell.text))\n if (a && a === b) matched++\n }\n return matched\n}\n\n// ─── 변경 처리 ───────────────────────────────────────\n\ninterface PatchCtx5 {\n origBlocks: IRBlock[]\n paraMap: Map<number, ParaMapping5>\n scans: SectionScan5[]\n tableMap: Map<number, ScanTable5>\n skipped: PatchSkip[]\n}\n\nfunction handleModified(orig: OrigUnit, edited: MdUnit, ctx: PatchCtx5): number {\n const block = ctx.origBlocks[orig.blockIdx]\n const skip = (reason: string) => {\n ctx.skipped.push({ reason, before: summarize(orig.raw), after: summarize(edited.raw) })\n return 0\n }\n\n if (orig.role === \"caption\") return skip(\"표 캡션 수정은 미지원 (v1)\")\n if (orig.kind === \"separator\" || orig.kind === \"image\") return skip(\"이미지/구분선 변경은 미지원\")\n if (!block) return skip(\"블록 매핑 실패\")\n if (orig.fragment) return skip(\"문단 분절(강제 줄바꿈/병합 유닛) — 부분 수정은 미지원 (v1)\")\n\n if (block.type === \"table\" && block.table) {\n if (orig.kind !== edited.kind) return skip(\"표 ↔ 비표 변경은 미지원 (표 구조 변경)\")\n const scanTable = ctx.tableMap.get(orig.blockIdx)\n if (!scanTable) return skip(\"표 소스맵 매핑 실패 — 표 개수/구조 불일치로 신뢰 불가\")\n if (orig.kind === \"gfm-table\") return patchGfmCells(scanTable, orig, edited, ctx, skip)\n if (orig.kind === \"html-table\") return patchHtmlCells5(block.table, scanTable, orig, edited, ctx, skip)\n return patchTextChunk5(block.table, scanTable, orig, edited, ctx, skip)\n }\n\n if ((block.type === \"paragraph\" || block.type === \"heading\") && orig.kind === \"text\") {\n if (edited.kind === \"text\") return patchParagraph(block, orig, edited, ctx, skip)\n // 문단→표 인플레이스 변환은 HWPX만 지원. HWP5 바이너리는 표 레코드 트리(+DocInfo\n // borderFill) 삽입이 무손실 게이트와 충돌하므로 미지원 — 대안을 안내하고 skip.\n if (edited.kind === \"gfm-table\" || edited.kind === \"html-table\") {\n return skip(\"HWP5(.hwp) 바이너리는 문단→표 인플레이스 변환 미지원 — generate로 새 문서를 만들거나, HWPX(.hwpx)로 저장 후 patch하세요\")\n }\n }\n\n return skip(\"지원하지 않는 블록 유형 변경\")\n}\n\n// ── 문단 ──\n\nfunction patchParagraph(\n block: IRBlock, orig: OrigUnit, edited: MdUnit, ctx: PatchCtx5,\n skip: (reason: string) => number,\n): number {\n const mapping = ctx.paraMap.get(orig.blockIdx)\n if (!mapping?.para) return skip(\"문단 소스맵 매핑 실패 (머리말/글상자/캡션 영역이거나 텍스트 불일치)\")\n\n // <br> 명시 줄바꿈 → \\n 복원 (셀 규약과 동일). md의 bare 개행은 soft-wrap이라\n // textUnitToPlain이 공백으로 접으므로, 본문 문단의 강제 줄바꿈은 <br>로만 표현·수정한다.\n // 연속 <br> 는 단일 \\n 으로 접는다 — <br><br>(빈 줄)이 \\n\\n 으로 기록되면 재파싱 시\n // 한 문단이 둘로 분열돼 이후 영구 수정불가(fragment)가 되는 것을 방지 (hwp5-4)\n const restoreBr = (s: string): string => s.replace(/(?:\\s*<br\\s*\\/?\\s*>\\s*)+/gi, \"\\n\")\n let newPlain = restoreBr(textUnitToPlain(edited.raw, block))\n // 원본이 다중줄인데 새 값에 줄바꿈 표기가 없으면 — soft-wrap 접힘과 줄바꿈 제거 의도를\n // 구분할 수 없어 줄바꿈 위치 보존 불가 (기존 v1 전면 가드의 정밀화)\n if (block.text && block.text.includes(\"\\n\") && !newPlain.includes(\"\\n\")) {\n return skip(\"다중줄 문단 수정에 <br> 없음 — 줄바꿈 위치 보존 불가로 미지원 (줄바꿈은 <br>로 표기)\")\n }\n\n // 각주 표기 — 본문이 아닌 각주 컨트롤에 있으므로 분리\n if (block.footnoteText) {\n const noteMatch = newPlain.match(/\\s*\\(주: ([\\s\\S]*)\\)$/)\n if (noteMatch) {\n newPlain = newPlain.slice(0, noteMatch.index).trimEnd()\n if (normForMatch(noteMatch[1]) !== normForMatch(block.footnoteText)) {\n ctx.skipped.push({ reason: \"각주 텍스트 수정은 미지원 — 본문만 적용\", before: block.footnoteText, after: noteMatch[1] })\n }\n } else {\n ctx.skipped.push({ reason: \"각주 표기 삭제는 미지원 — 각주 유지, 본문만 적용\", before: `(주: ${block.footnoteText})` })\n }\n }\n\n // 자동번호 접두 — 레코드에 없는 텍스트이므로 떼고 기록\n if (mapping.prefixStripped) {\n const origPrefix = block.text!.split(\" \", 1)[0]\n const sp = newPlain.indexOf(\" \")\n const newFirst = sp > 0 ? newPlain.slice(0, sp) : newPlain\n if (newFirst === origPrefix || AUTONUM_PREFIX_RE.test(newFirst)) {\n newPlain = sp > 0 ? newPlain.slice(sp + 1) : \"\"\n } else {\n ctx.skipped.push({ reason: \"자동번호 접두 식별 실패 — 번호 포함 텍스트로 적용 (뷰어에서 중복 표시 가능)\", after: summarize(newPlain) })\n }\n }\n\n // 원본 비교는 block.text(강제 줄바꿈 \\n 보존) 기준 — textUnitToPlain 은 \\n 을 공백으로\n // 접어 <br>→\\n 복원본과 절대 같아질 수 없어, 표기만 바꾼(\\n↔<br>) no-op 편집을 수정으로\n // 오판하고 문단을 재기록해 중간 서식(CHAR_SHAPE 다중 런)을 파괴했다 (hwp5-1)\n const origPlain = block.text != null ? block.text : restoreBr(textUnitToPlain(orig.raw, block))\n if (newPlain === origPlain) return skip(\"텍스트 외 변경(헤딩 레벨/서식)만 감지 — 스타일 변경은 미지원\")\n if (sanitizeText(newPlain) !== newPlain) {\n return skip(\"공백 정규화 불안정 텍스트 — 패치 시 원문 보존 불가로 미지원\")\n }\n\n return stageParaPatch(ctx.scans[mapping.para.sectionIndex], mapping.para, newPlain, skip)\n}\n\n// ── GFM 표 셀 ──\n\nfunction patchGfmCells(\n scanTable: ScanTable5, orig: OrigUnit, edited: MdUnit, ctx: PatchCtx5,\n skip: (reason: string) => number,\n): number {\n const origRows = parseGfmTable(orig.lines)\n const editedRows = parseGfmTable(edited.lines)\n if (origRows.length !== editedRows.length || origRows.some((r, i) => r.length !== editedRows[i].length)) {\n return skip(\"표 구조 변경(행/열 수)은 미지원 (v1)\")\n }\n\n let applied = 0\n for (let r = 0; r < origRows.length; r++) {\n for (let c = 0; c < origRows[r].length; c++) {\n if (origRows[r][c] === editedRows[r][c]) continue\n const cellSkip = (reason: string) => {\n ctx.skipped.push({ reason, before: summarize(origRows[r][c]), after: summarize(editedRows[r][c]) })\n return 0\n }\n const cell = scanTable.cells.get(`${r},${c}`)\n if (!cell) { cellSkip(\"병합 영역 셀 — 앵커 셀이 아니므로 미지원\"); continue }\n\n // 셀 내 여러 문단은 GFM에서 <br>로 이어진다 — 분할해 각 문단과 1:1 매핑한다.\n // (단일 문단 셀도 분할 1개로 동일 경로. 문단 수가 다르면 추가/삭제이므로 미지원.)\n const beforeParts = origRows[r][c].split(/<br\\s*\\/?>/i)\n const afterParts = editedRows[r][c].split(/<br\\s*\\/?>/i)\n // 단일 문단 셀: <br>로 나뉜 여러 줄을 문단 추가 없이 한 문단 안 강제 줄바꿈(\\n)으로 채운다.\n // (다중 문단 셀은 아래 1:1 매핑 유지 — 문단 구조를 보존해야 하므로.)\n if (cell.paras.length === 1) {\n const beforeEach = beforeParts.map(gfmCellToPlain)\n const afterEach = afterParts.map(gfmCellToPlain)\n if (beforeEach.some(p => p === null) || afterEach.some(p => p === null)) { cellSkip(\"서식/링크/이미지 포함 셀 수정은 미지원 (v1)\"); continue }\n const before = beforeEach.join(\"\\n\")\n const after = afterEach.join(\"\\n\")\n if (before === after) continue\n const para = cell.paras[0]\n if (normForMatch(para.rawText) !== normForMatch(before)) { cellSkip(\"셀 텍스트 불일치 — 소스맵 신뢰 불가\"); continue }\n if (afterEach.some(l => sanitizeText(l!) !== l)) { cellSkip(\"공백 정규화 불안정 텍스트 — 미지원\"); continue }\n applied += stageParaPatch(ctx.scans[para.sectionIndex], para, after, cellSkip)\n continue\n }\n if (beforeParts.length !== cell.paras.length || afterParts.length !== cell.paras.length) {\n cellSkip(\"셀 문단 수 변경 — 미지원 (문단 추가/삭제)\"); continue\n }\n for (let k = 0; k < cell.paras.length; k++) {\n const before = gfmCellToPlain(beforeParts[k])\n const after = gfmCellToPlain(afterParts[k])\n if (before === null || after === null) { cellSkip(\"서식/링크/이미지 포함 셀 수정은 미지원 (v1)\"); break }\n if (before === after) continue\n if (after.includes(\"\\n\")) { cellSkip(\"셀 내 줄바꿈 추가는 미지원 (v1)\"); break }\n const para = cell.paras[k]\n if (normForMatch(para.rawText) !== normForMatch(before)) { cellSkip(\"셀 텍스트 불일치 — 소스맵 신뢰 불가\"); break }\n if (sanitizeText(after) !== after) { cellSkip(\"공백 정규화 불안정 텍스트 — 미지원\"); break }\n applied += stageParaPatch(ctx.scans[para.sectionIndex], para, after, cellSkip)\n }\n }\n }\n return applied\n}\n\n// ── HTML 표 (병합셀/줄바꿈 셀) — HWPX patchHtmlTableRaw 미러 ──\n\n/**\n * 병합셀/줄바꿈 셀 표 패치. builder의 tableToHtml 렌더를 좌표 추적 버전으로 재현해\n * 편집된 셀의 격자 좌표(=앵커 좌표)를 역산, scanTable.cells 앵커로 셀 문단을 치환한다.\n * 자기검증(replicateTableToHtml===원문) + 셀 경계 되읽기 대칭 검증으로 오매핑을 차단.\n * 중첩표 셀은 HWP5 스캔이 중첩표를 수집하지 않으므로 미지원(skip).\n */\nfunction patchHtmlCells5(\n table: IRTable, scanTable: ScanTable5, orig: OrigUnit, edited: MdUnit, ctx: PatchCtx5,\n skip: (reason: string) => number,\n): number {\n // 자기검증 — builder 렌더와 동일해야 좌표 신뢰 가능\n if (replicateTableToHtml(table) !== orig.raw) return skip(\"표 좌표 재현 불일치 — 매핑 신뢰 불가\")\n const replica = replicateHtmlTable(table)\n // 되읽기 대칭 검증 — 셀 텍스트에 리터럴 '</td>' 등이 있으면 셀 경계가 어긋나 미편집 셀이\n // 잘려 저장될 수 있음. 원문을 되읽어 replica와 대조한다.\n const origRows = parseHtmlTable(orig.raw)\n if (!origRows || origRows.length !== replica.length\n || origRows.some((r, i) => r.cells.length !== replica[i].cells.length\n || r.cells.some((c, j) => c.inner !== replica[i].cells[j].inner))) {\n return skip(\"셀 경계 모호 (리터럴 태그 의심) — 매핑 신뢰 불가\")\n }\n const editedRows = parseHtmlTable(edited.raw)\n if (!editedRows) return skip(\"편집된 HTML 표 파싱 실패\")\n if (editedRows.length !== replica.length) return skip(\"표 행 추가/삭제는 미지원 (표 구조 변경)\")\n\n let applied = 0\n for (let r = 0; r < replica.length; r++) {\n if (editedRows[r].cells.length !== replica[r].cells.length) {\n skip(`표 ${r + 1}행 셀 수 변경은 미지원`)\n continue\n }\n for (let c = 0; c < replica[r].cells.length; c++) {\n const oc = replica[r].cells[c]\n const ec = editedRows[r].cells[c]\n if (oc.colSpan !== ec.colSpan || oc.rowSpan !== ec.rowSpan) {\n skip(\"셀 병합(colspan/rowspan) 변경은 미지원\")\n continue\n }\n if (oc.inner === ec.inner) continue\n\n const origContent = htmlCellInnerToLines(oc.inner)\n const editedContent = htmlCellInnerToLines(ec.inner)\n if (origContent.hadNonText || editedContent.hadNonText) {\n if (extractImgTags(oc.inner) !== extractImgTags(ec.inner)) {\n skip(\"셀 내 이미지 변경은 미지원\")\n continue\n }\n if (extractTopLevelTables(oc.inner).join(\"\\n\") !== extractTopLevelTables(ec.inner).join(\"\\n\")) {\n skip(\"셀 내 중첩표 수정은 HWP5 미지원 (v1)\")\n continue\n }\n }\n // 텍스트 라인 변경 (중첩표/이미지 제외분)\n if (origContent.lines.join(\"\\n\") !== editedContent.lines.join(\"\\n\")) {\n const newLines = editedContent.lines.map(l => unescapeGfm(l))\n applied += applyCellEdit5(table, scanTable, oc.gridR!, oc.gridC!, newLines, ctx, oc.inner, ec.inner, origContent.lines.length)\n }\n }\n }\n return applied\n}\n\n// ── 1x1 / 1열 표 (텍스트 청크 렌더) — HWPX patchTextChunkTable 미러 ──\n\nfunction patchTextChunk5(\n table: IRTable, scanTable: ScanTable5, orig: OrigUnit, edited: MdUnit, ctx: PatchCtx5,\n skip: (reason: string) => number,\n): number {\n if (table.rows === 1 && table.cols === 1) {\n // builder 1x1 경로 재현 (라인별 장식 포함, 유닛 분할 시 트림됨)\n const content = sanitizeText(table.cells[0][0].text)\n const replicaLines = content.split(/\\n/).map(line => {\n const t = line.trim()\n if (!t) return \"\"\n if (/^\\d+\\.\\s/.test(t)) return `**${escapeGfm(t)}**`\n return escapeGfm(t)\n }).filter(Boolean)\n if (replicaLines.join(\"\\n\") !== orig.lines.join(\"\\n\")) return skip(\"표 좌표 재현 불일치 — 매핑 신뢰 불가\")\n if (extractCellTokens(orig.raw) !== extractCellTokens(edited.raw)) return skip(\"셀 내 이미지 변경은 미지원\")\n const newLines = edited.lines.map(l => {\n // builder는 /^\\d+\\.\\s/ 라인에만 '**' 볼드를 부여 — 그 경우만 벗기고 리터럴 '**...**'는 보존\n const m = l.match(/^\\*\\*([\\s\\S]*)\\*\\*$/)\n const unwrap = m && /^\\d+\\.\\s/.test(unescapeGfm(m[1]))\n return stripCellTokens(unescapeGfm(unwrap ? m![1] : l)).trim()\n }).filter(Boolean)\n return applyCellEdit5(table, scanTable, 0, 0, newLines, ctx, orig.raw, edited.raw, orig.lines.length)\n }\n\n if (table.cols === 1 && table.rows >= 2) {\n const replica: { line: string; gridR: number }[] = []\n for (let r = 0; r < table.rows; r++) {\n const line = escapeGfm(sanitizeText(table.cells[r][0].text)).replace(/\\n/g, \" \")\n if (line) replica.push({ line, gridR: r })\n }\n if (replica.map(x => x.line).join(\"\\n\") !== orig.lines.join(\"\\n\")) return skip(\"표 좌표 재현 불일치 — 매핑 신뢰 불가\")\n if (edited.lines.length !== replica.length) return skip(\"표 행 추가/삭제는 미지원 (표 구조 변경)\")\n let applied = 0\n for (let i = 0; i < replica.length; i++) {\n if (replica[i].line === edited.lines[i]) continue\n if (extractCellTokens(replica[i].line) !== extractCellTokens(edited.lines[i])) {\n skip(\"셀 내 이미지 변경은 미지원\")\n continue\n }\n const newLines = [stripCellTokens(unescapeGfm(edited.lines[i])).trim()].filter(Boolean)\n applied += applyCellEdit5(table, scanTable, replica[i].gridR, 0, newLines, ctx, replica[i].line, edited.lines[i], 1)\n }\n return applied\n }\n\n return skip(\"표 렌더 경로 식별 실패\")\n}\n\n/**\n * 격자 좌표 (gridR, gridC) 셀에 새 텍스트 라인 적용 — 라인 ↔ 셀 내 비어있지 않은\n * 문단 순서 매핑 (HWPX applyCellEdit과 동일 정책, 바이너리 스테이징판).\n */\nfunction applyCellEdit5(\n table: IRTable, scanTable: ScanTable5, gridR: number, gridC: number,\n newLines: string[], ctx: PatchCtx5, before: string, after: string,\n origLineCount?: number,\n): number {\n const skip = (reason: string) => {\n ctx.skipped.push({ reason, before: summarize(before), after: summarize(after) })\n return 0\n }\n const cell = scanTable.cells.get(`${gridR},${gridC}`)\n if (!cell) return skip(\"셀 좌표 매핑 실패 (병합 영역의 빈 칸이거나 좌표 불일치)\")\n\n // 셀 콘텐츠 검증 — 스캔 문단 합산과 IR 셀 텍스트의 정규화 일치\n const irCell = table.cells[gridR]?.[gridC]\n const scanJoined = cell.paras.map(p => p.rawText).filter(t => normForMatch(t)).join(\"\\n\")\n if (irCell && normForMatch(scanJoined) !== normForMatch(stripCellTokens(irCell.text))) {\n if (normForMatch(irCell.text) !== \"\" || normForMatch(scanJoined) !== \"\") {\n const flatBlocks = (irCell.blocks ?? []).filter(b => b.type === \"paragraph\" || b.type === \"heading\")\n const flatJoined = flatBlocks.map(b => b.text ?? \"\").join(\"\\n\")\n if (normForMatch(scanJoined) !== normForMatch(flatJoined)) {\n return skip(\"셀 콘텐츠 구조 복잡 (중첩표/글상자) — 매핑 신뢰 불가\")\n }\n }\n }\n\n const nonEmpty = cell.paras.filter(p => normForMatch(p.rawText) !== \"\")\n if (origLineCount !== undefined && nonEmpty.length > 0 && origLineCount !== nonEmpty.length) {\n return skip(\"셀 줄 경계 매핑 모호 (문단 내 줄바꿈) — 미지원\")\n }\n const unstable = newLines.find(l => sanitizeText(l) !== l)\n if (unstable !== undefined) return skip(\"공백 정규화 불안정 텍스트 — 패치 시 원문 보존 불가로 미지원\")\n\n // 빈 셀(모든 문단이 빈)은 빈 문단들 자체가 채움 대상 — stageParaPatch가 빈 문단 채우기를 지원\n const targets = nonEmpty.length > 0 ? nonEmpty : cell.paras\n if (targets.length === 0) return skip(\"셀에 문단이 없음 — 미지원\")\n\n // 라인 → 문단 순서 매핑 (넘치는 줄은 마지막 문단에 강제 줄바꿈으로 병합, 줄어든 줄은 비움)\n const assigned: string[] = []\n for (let i = 0; i < targets.length; i++) {\n if (i < newLines.length) {\n assigned.push(i === targets.length - 1 && newLines.length > targets.length\n ? newLines.slice(i).join(\"\\n\")\n : newLines[i])\n } else {\n assigned.push(\"\")\n }\n }\n if (newLines.length > targets.length) {\n ctx.skipped.push({ reason: \"셀 내 추가 줄을 마지막 문단에 강제 줄바꿈으로 병합(문단 생성 대신)\", after: summarize(after), partial: true })\n } else if (newLines.length < nonEmpty.length && nonEmpty.length > 1) {\n ctx.skipped.push({ reason: \"셀 내 줄 삭제는 문단 제거 미지원 — 빈 문단 잔존(뷰어에 빈 줄 표시 가능)\", before: summarize(before), after: summarize(after), partial: true })\n }\n let staged = 0\n for (let i = 0; i < targets.length; i++) {\n if (assigned[i] === targets[i].rawText || normForMatch(assigned[i]) === normForMatch(targets[i].rawText)) continue\n staged += stageParaPatch(ctx.scans[targets[i].sectionIndex], targets[i], assigned[i], skip)\n }\n return staged > 0 ? 1 : 0\n}\n\n/** GFM 셀 마크다운 → 평문. 굵게 래핑(**…**)은 벗기되 내부 서식은 미지원(null) */\nfunction gfmCellToPlain(md: string): string | null {\n let t = md.trim()\n const bold = t.match(/^\\*\\*([\\s\\S]+)\\*\\*$/)\n if (bold) t = bold[1]\n if (/[*`]|!\\[|\\]\\(/.test(t)) return null\n // '<'는 HTML 태그/autolink 시작(뒤에 영문자·'/')일 때만 서식으로 간주.\n // 통계표의 부등호 셀(\"<0.01\", \"≤5\") 등 평문 '<'는 허용. ('<br>'은 줄바꿈 셀로 별도 게이트가 처리)\n if (/<(?!br\\s*\\/?>)[a-zA-Z/]/i.test(t)) return null\n return unescapeGfm(unescapeGfmCell(t))\n}\n\n// ─── 바이너리 패치 스테이징 ──────────────────────────\n\n/**\n * PARA_TEXT를 [선두 비가시 control][순수 텍스트 코어][말미 비가시 control/문단끝]로 분해.\n * - 코어는 0x20+ 일반 문자(서로게이트 포함)와 강제 줄바꿈(0x000a)만. 탭·하이픈·NBSP 등 그 외\n * \"가시 control\"이 코어 안이나 가장자리에 있으면 텍스트 재매핑이 모호하므로 null(미지원).\n * - 선두/말미에는 개체 앵커(0x0b)·필드(0x03/0x04)·자동번호 등 \"비가시 control\"과 문단끝(0x0d)만 허용.\n * appendParaText(record.ts)의 바이트 전진 규칙을 그대로 미러한다 — 어긋나면 한컴 변조감지.\n */\nexport function splitParaText(data: Buffer):\n | { prefix: Buffer; prefixUnits: number; core: string; suffix: Buffer; suffixUnits: number }\n | null {\n interface Tok { start: number; end: number; units: number; plain: boolean; visible: boolean }\n const toks: Tok[] = []\n let i = 0\n while (i + 1 < data.length) {\n const ch = data.readUInt16LE(i)\n const start = i\n i += 2\n if (ch >= 0x20) {\n let units = 1\n if (ch >= 0xd800 && ch <= 0xdbff && i + 1 < data.length) {\n const lo = data.readUInt16LE(i)\n if (lo >= 0xdc00 && lo <= 0xdfff) { i += 2; units = 2 }\n }\n toks.push({ start, end: i, units, plain: true, visible: true })\n continue\n }\n switch (ch) {\n case 0x00: case 0x18: case 0x19: case 0x1e: case 0x1f:\n // 줄바꿈/고정폭·비분리 공백/하이픈 — 가시(텍스트에 기여), 2바이트\n toks.push({ start, end: i, units: 1, plain: false, visible: true }); break\n case 0x09: // 탭 — 가시, 2+14바이트\n if (i + 14 <= data.length) i += 14\n toks.push({ start, end: i, units: 1, plain: false, visible: true }); break\n case 0x0d: // 문단끝 — 비가시\n toks.push({ start, end: i, units: 1, plain: false, visible: false }); break\n case 0x0a: // 강제 줄바꿈(char 2바이트) — 단, 뒤에 0x000b 수식 래퍼면 확장 처리\n if (i + 16 <= data.length && data.readUInt16LE(i) === 0x000b) {\n i += 16; toks.push({ start, end: i, units: 1, plain: false, visible: false }) // 수식 등 비가시\n } else {\n // bare 0x000a = 2바이트 줄바꿈. 14바이트 소비 금지(appendParaText와 대칭 — 어긋나면 한컴 변조감지).\n toks.push({ start, end: i, units: 1, plain: true, visible: true }) // \"\\n\" 가시, 2바이트\n }\n break\n default: {\n const ext = isExtendedOnlyCtrlChar(ch)\n const inl = (ch >= 4 && ch <= 9) || (ch >= 19 && ch <= 20)\n if ((ext || inl) && i + 14 <= data.length) i += 14\n toks.push({ start, end: i, units: 1, plain: false, visible: false }) // 개체/필드 등 비가시\n break\n }\n }\n }\n if (i !== data.length) return null // 토큰화가 데이터를 정확히 소비 못함 — 안전상 미지원\n\n let firstP = -1, lastP = -1\n for (let k = 0; k < toks.length; k++) if (toks[k].plain) { if (firstP < 0) firstP = k; lastP = k }\n if (firstP < 0) {\n // 일반 텍스트가 전혀 없는 문단(빈/개체만) — 가시 control이 있으면 위치 모호로 미지원.\n // 문단끝(0x0d)부터를 suffix로 삼아 새 텍스트가 [선두 개체 뒤, 문단끝 앞]에 들어가게 한다.\n if (toks.some(t => t.visible)) return null\n let cut = data.length\n for (const t of toks) if (data.readUInt16LE(t.start) === 0x0d) { cut = t.start; break }\n return {\n prefix: data.subarray(0, cut),\n prefixUnits: cut / 2,\n core: \"\",\n suffix: data.subarray(cut),\n suffixUnits: (data.length - cut) / 2,\n }\n }\n for (let k = firstP; k <= lastP; k++) if (!toks[k].plain) return null // 코어 내부에 control\n for (let k = 0; k < firstP; k++) if (toks[k].visible) return null // 선두에 가시 control\n for (let k = lastP + 1; k < toks.length; k++) if (toks[k].visible) return null // 말미에 가시 control\n\n const prefixEnd = toks[firstP].start\n const coreEnd = toks[lastP].end\n // nChars·char shape position은 WCHAR 개수 단위 — control의 확장 WCHAR(개체/필드=8 WCHAR 등)도\n // 모두 포함한다. 바이트÷2로 계산해야 한컴의 nChars(=PARA_TEXT WCHAR 총수)와 일치한다.\n const prefixUnits = prefixEnd / 2\n const suffixUnits = (data.length - coreEnd) / 2\n return {\n prefix: data.subarray(0, prefixEnd),\n prefixUnits,\n core: data.subarray(prefixEnd, coreEnd).toString(\"utf16le\"),\n suffix: data.subarray(coreEnd),\n suffixUnits,\n }\n}\n\n/**\n * CHAR_SHAPE(글자모양 run) 레코드를 코어 시작 위치 기준으로 재구성.\n * 선두 control 영역의 run은 보존하고 코어 이후는 코어 첫 글자 서식으로 단일화한다\n * — 텍스트 길이가 바뀌어도 position이 안정 (기존 \"첫 run 통일\" 정책의 일반화).\n */\nfunction rebuildCharShape(csData: Buffer, coreStartUnit: number): { buf: Buffer; count: number } {\n const pairs: Array<[number, number]> = []\n for (let o = 0; o + 8 <= csData.length; o += 8) pairs.push([csData.readUInt32LE(o), csData.readUInt32LE(o + 4)])\n if (pairs.length === 0) return { buf: Buffer.from(csData.subarray(0, 8)), count: 1 }\n let coreId = pairs[0][1]\n for (const [p, id] of pairs) if (p <= coreStartUnit) coreId = id\n const kept = pairs.filter(([p]) => p < coreStartUnit)\n if (kept.length === 0 || kept[kept.length - 1][1] !== coreId) kept.push([coreStartUnit, coreId])\n const buf = Buffer.alloc(kept.length * 8)\n kept.forEach(([p, id], k) => { buf.writeUInt32LE(p >>> 0, k * 8); buf.writeUInt32LE(id >>> 0, k * 8 + 4) })\n return { buf, count: kept.length }\n}\n\n// ─── 한컴 압축 스트림 꼬리 ───────────────────────────\n\n// CRC-32 (IEEE) — zlib.crc32 는 Node 22.2+ 전용이라 engines(>=18) 범위에서 직접 계산한다\nconst CRC_TABLE = (() => {\n const t = new Uint32Array(256)\n for (let n = 0; n < 256; n++) {\n let c = n\n for (let k = 0; k < 8; k++) c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1\n t[n] = c >>> 0\n }\n return t\n})()\n\nfunction crc32(buf: Buffer): number {\n let c = 0xffffffff\n for (let i = 0; i < buf.length; i++) c = CRC_TABLE[(c ^ buf[i]) & 0xff] ^ (c >>> 8)\n return (c ^ 0xffffffff) >>> 0\n}\n\n/**\n * 한컴 압축 스트림 재현 — raw deflate 뒤 8바이트 꼬리(CRC32(비압축) LE + 비압축 크기 LE).\n * 한컴 실저장본의 BodyText/DocInfo 압축 스트림 전수에서 확인된 형식(#71, 코퍼스 실측 7/7).\n * 꼬리 없이도 inflateRawSync 는 열리지만, 원본 충실성을 위해 재작성 스트림에도 복원한다.\n */\nexport function compressWithTail(raw: Buffer): Buffer {\n const tail = Buffer.alloc(8)\n tail.writeUInt32LE(crc32(raw), 0)\n tail.writeUInt32LE(raw.length >>> 0, 4)\n return Buffer.concat([deflateRawSync(raw), tail])\n}\n\n/**\n * LINE_SEG(0x45, 36B/세그) 다중줄 합성 — HWP5 binary 구조 실측(kordoc 최초 파싱):\n * [textpos, vPos, lineH, textH, baseline, lineSpc, hStart, width, tag] 각 int32.\n * 실파일은 세그먼트마다 vPos만 pitch(=lineH+lineSpc)씩 증가하고 나머지 기하는 전 세그\n * 동일 → seg0을 통째 복사해 textpos·vPos만 줄마다 바꾼다. 한컴은 LINE_SEG를 재계산하지\n * 않고 그대로 렌더하므로 1세그면 줄바꿈(0x000a)을 한 줄로 씹는다(실측) — 줄 수만큼\n * 합성해야 실제로 나뉜다. pitch를 모르는 기하(전부 0 등)면 null — 호출부는 원본 유지.\n * @param startUnits 코어 시작 WCHAR 위치(선두 control 포함) — 둘째 줄부터의 textpos 기준\n */\nfunction synthesizeLineSegs(lineSegData: Buffer, newRaw: string, startUnits: number): { buf: Buffer; count: number } | null {\n if (lineSegData.length < 36) return null\n const seg0 = lineSegData.subarray(0, 36)\n const vPos0 = seg0.readInt32LE(4)\n const pitch = seg0.readInt32LE(8) + seg0.readInt32LE(20) // lineH + lineSpc\n if (pitch <= 0) return null\n const lines = newRaw.split(\"\\n\")\n const segs: Buffer[] = []\n let pos = startUnits\n for (let k = 0; k < lines.length; k++) {\n const s = Buffer.from(seg0)\n s.writeUInt32LE((k === 0 ? 0 : pos) >>> 0, 0) // textpos: 첫 줄은 문단 처음(prefix 포함)\n s.writeInt32LE(vPos0 + k * pitch, 4) // vPos: 줄마다 한 줄 아래로\n segs.push(s)\n pos += lines[k].length + 1 // 다음 줄 시작 = 이 줄 문자수 + 줄바꿈 1\n }\n return { buf: Buffer.concat(segs), count: lines.length }\n}\n\n/**\n * 문단 텍스트 교체를 섹션 repl 맵에 스테이징.\n * PARA_TEXT 치환 + PARA_HEADER nChars + CHAR_SHAPE/LINE_SEG 정합화.\n * 개체 앵커·필드 등 비가시 control이 문단 가장자리에 있어도 그 블록은 보존하고 코어만 교체한다.\n */\nfunction stageParaPatch(\n scan: SectionScan5, para: ScanPara5, newPlain: string,\n skip: (reason: string) => number,\n): number {\n if (!scan.safe) return skip(\"섹션 레코드 재직렬화 불일치 — 안전을 위해 이 섹션은 미지원\")\n if (para.textIdx === -2) return skip(\"복수 PARA_TEXT 레코드 문단 — 미지원 (v1)\")\n // 컨트롤 문자(개체 앵커/필드 등)는 splitParaText에서 가장자리 보존 가능 여부를 판정한다.\n if (para.rangeTagCount > 0) return skip(\"범위 태그(형광펜/교정부호) 문단 — 미지원 (v1)\")\n if (para.charShapeIdx < 0 || para.lineSegIdx < 0) return skip(\"문단 레코드 구성 비정형 — 미지원\")\n if (scan.repl.has(para.headerIdx)) return skip(\"동일 문단 중복 수정 — 첫 수정만 적용\")\n // \\n(0x000a, 강제 줄바꿈)은 허용 — 코어에 2바이트 char 컨트롤로 기록해 다중줄 값을 지원한다.\n // 그 외 제어문자(탭·필드·특수공백 등)는 재매핑이 모호하므로 거부.\n if (/[\\u0000-\\u0009\\u000b-\\u001f]/.test(newPlain)) return skip(\"새 텍스트에 제어문자 포함 — 미지원\")\n\n const records = scan.records\n const headerRec = records[para.headerIdx]\n const charShapeRec = records[para.charShapeIdx]\n if (charShapeRec.data.length < 8) {\n return skip(\"CHAR_SHAPE 레코드 비정형 — 미지원\")\n }\n\n // PARA_TEXT 레코드가 없는 빈 문단(한컴 생략 저장형) — PARA_HEADER 직후에 신규 삽입.\n // 원본 nChars(하위 31비트)가 1이면 문단끝 1자를 계상한 것이므로 0x0d를 붙여 정합 유지.\n if (para.textIdx === -1) {\n const nCharsLow = para.nCharsRaw & 0x7fffffff\n if (nCharsLow > 1) return skip(\"PARA_TEXT 없는 문단의 nChars 비정형 — 미지원\")\n const paraEnd = nCharsLow === 1 ? Buffer.from([0x0d, 0x00]) : Buffer.alloc(0)\n const at = para.headerIdx + 1\n const list = scan.inserts.get(at) ?? []\n list.push({ tagId: TAG_PARA_TEXT, level: headerRec.level + 1, data: Buffer.concat([Buffer.from(newPlain, \"utf16le\"), paraEnd]) })\n scan.inserts.set(at, list)\n\n const newHeader = Buffer.from(headerRec.data)\n newHeader.writeUInt32LE(((para.nCharsRaw & 0x80000000) | (newPlain.length + nCharsLow)) >>> 0, 0)\n const cs = rebuildCharShape(charShapeRec.data, 0)\n scan.repl.set(para.charShapeIdx, cs.buf)\n newHeader.writeUInt16LE(cs.count, 12)\n // 다중줄 값이면 LINE_SEG도 줄 수만큼 합성 (1세그면 한컴이 flat 렌더 — 셀 경로와 동일).\n // 빈 문단 LINE_SEG 기하가 0(pitch 불명)이면 원본 유지 — 값은 들어가고 렌더만 한 줄 폴백.\n if (newPlain.includes(\"\\n\")) {\n const synth = synthesizeLineSegs(records[para.lineSegIdx].data, newPlain, 0)\n if (synth) {\n scan.repl.set(para.lineSegIdx, synth.buf)\n newHeader.writeUInt16LE(synth.count, 16) // lineSegCount\n }\n }\n scan.repl.set(para.headerIdx, newHeader)\n return 1\n }\n\n const textRec = records[para.textIdx]\n\n // PARA_TEXT를 [선두 control][텍스트 코어][말미 control/문단끝]로 분해\n const seg = splitParaText(textRec.data)\n if (!seg) {\n return skip(para.ctrlMask !== 0\n ? \"컨트롤 문자(탭/필드/특수공백 등 텍스트 중간) 포함 문단 — 미지원 (v1)\"\n : \"PARA_TEXT 재구성 불일치 — 원문 보존 불가로 미지원\")\n }\n // 코어가 추출 텍스트(rawText)와 일치해야 안전 (가시 control 없음 보장)\n if (seg.core !== para.rawText) return skip(\"PARA_TEXT 재구성 불일치 — 원문 보존 불가로 미지원\")\n\n // 원문 leading/trailing 공백 보존 (IR은 트림된 텍스트)\n const lead = para.rawText.match(/^\\s*/)![0]\n const trail = para.rawText.match(/\\s*$/)![0]\n const newRaw = para.rawText.trim() === para.rawText ? newPlain : lead + newPlain + trail\n\n // PARA_TEXT = 선두 control + 새 텍스트 + 말미 control/문단끝 (control 블록 바이트 보존)\n const newText = Buffer.concat([seg.prefix, Buffer.from(newRaw, \"utf16le\"), seg.suffix])\n scan.repl.set(para.textIdx, newText)\n\n // PARA_HEADER — nChars(상위 플래그 비트 보존) + charShapeCount/lineSegCount\n const newHeader = Buffer.from(headerRec.data)\n const nChars = seg.prefixUnits + newRaw.length + seg.suffixUnits\n newHeader.writeUInt32LE(((para.nCharsRaw & 0x80000000) | nChars) >>> 0, 0)\n\n // CHAR_SHAPE — 선두 control run 보존 + 코어는 첫 글자 서식으로 단일화\n const cs = rebuildCharShape(charShapeRec.data, seg.prefixUnits)\n scan.repl.set(para.charShapeIdx, cs.buf)\n newHeader.writeUInt16LE(cs.count, 12)\n\n // LINE_SEG — 강제 줄바꿈(0x000a)이 없으면 원본 유지(한컴은 LINE_SEG를 재계산하지 않고 그대로\n // 렌더하므로 세그먼트 축소는 글자 겹침 유발 → 원본 유지가 안전). 줄바꿈이 있으면 한컴이\n // 1세그먼트를 한 줄로 렌더해 줄바꿈을 씹으므로, 줄 수만큼 세그먼트를 합성해 실제로 나눈다.\n if (newRaw.includes(\"\\n\")) {\n const synth = synthesizeLineSegs(records[para.lineSegIdx].data, newRaw, seg.prefixUnits)\n if (synth) {\n scan.repl.set(para.lineSegIdx, synth.buf)\n newHeader.writeUInt16LE(synth.count, 16) // lineSegCount\n }\n } else {\n // 자동 줄바꿈(soft-wrap)으로 2+세그먼트였던 문단을 더 짧은 한 줄로 치환하면 뒤쪽\n // 세그먼트의 textpos 가 새 nChars 밖을 가리킨 채 남아 한컴 무결성 검사가 \"손상/변조\"로\n // 판정한다(#71). 범위를 벗어난 꼬리 세그먼트만 잘라내고 lineSegCount 를 맞춘다 —\n // 유효 범위(textpos < nChars)의 세그먼트는 원본 유지가 렌더에 안전하므로 남긴다.\n const lineSegData = records[para.lineSegIdx].data\n const segCount = Math.floor(lineSegData.length / 36)\n let keep = 1\n while (keep < segCount && lineSegData.readUInt32LE(keep * 36) < nChars) keep++\n if (keep < segCount) {\n scan.repl.set(para.lineSegIdx, Buffer.from(lineSegData.subarray(0, keep * 36)))\n newHeader.writeUInt16LE(keep, 16) // lineSegCount\n }\n }\n\n scan.repl.set(para.headerIdx, newHeader)\n return 1\n}\n","/**\n * OLE2/CFB 섹터 레벨 스트림 교체 — 컨테이너 전체 재조립 없이 in-place 수술.\n *\n * 전체 재작성(SheetJS CFB.write 등)은 섹터 배치/FAT/디렉토리를 전부 다시 만들어\n * 한/글의 엄격한 OLE 파서가 거부할 수 있다. 이 모듈은 원본 파일 바이트를 그대로\n * 두고 다음만 수정한다:\n * - 대상 스트림의 데이터 섹터 (재사용/추가 할당)\n * - FAT/miniFAT의 해당 체인 엔트리\n * - 디렉토리 엔트리의 start/size 8바이트\n * - (필요 시) 파일 끝에 새 섹터 추가 + FAT/DIFAT/miniFAT 확장\n * 나머지 영역은 바이트 단위로 원본과 동일하게 유지된다.\n *\n * 지원: CFB v3 (512B 섹터). HWP 5.x는 전부 v3.\n */\n\nconst SECTOR = 512\nconst MINI_SECTOR = 64\nconst MINI_CUTOFF = 4096\nconst FREESECT = 0xffffffff\nconst ENDOFCHAIN = 0xfffffffe\nconst FATSECT = 0xfffffffd\nconst DIFSECT = 0xfffffffc\n\nexport class OleSurgeonError extends Error {}\n\ninterface DirEntry {\n /** 디렉토리 배열 내 인덱스 */\n index: number\n name: string\n type: number\n left: number\n right: number\n child: number\n start: number\n size: number\n}\n\n/**\n * OLE 컨테이너의 스트림 1개를 새 내용으로 교체한 새 버퍼를 반환.\n * @param file 원본 OLE 파일 전체\n * @param path \"/\" 구분 경로 (예: \"BodyText/Section0\")\n */\nexport function replaceOleStream(file: Buffer, path: string, newData: Buffer): Buffer {\n const surgeon = new Surgeon(file)\n surgeon.replace(path, newData)\n return surgeon.finish()\n}\n\n/**\n * 미할당 영역 바이트를 0으로 — 어느 체인(디렉토리·FAT·DIFAT·miniFAT·미니 스트림·스트림)에도 닿지 않는\n * 섹터·미니섹터, 각 스트림 마지막 섹터의 크기 너머 꼬리. 한컴이 저장하며 남긴 옛 스트림 사본(실측:\n * PrvText 옛 사본이 FREESECT 섹터에 잔존)을 지운다 — 개인정보 마스킹(redact)용. 할당된 스트림 내용·\n * FAT·디렉토리는 그대로다.\n */\nexport function wipeFreeSectors(file: Buffer): Buffer {\n const surgeon = new Surgeon(file)\n surgeon.wipeUnallocated()\n return surgeon.finish()\n}\n\nclass Surgeon {\n private buf: Buffer\n /** 논리 파일 길이 — buf는 성장 시 기하급수 capacity로 재할당되므로 buf.length와 다를 수 있음 */\n private len: number\n private fat: number[] = []\n /** FAT 배열을 구성하는 섹터 번호들 (DIFAT 순서) */\n private fatSectors: number[] = []\n private miniFat: number[] = []\n private miniFatSectors: number[] = []\n private dirSectors: number[] = []\n private entries: DirEntry[] = []\n /** replace()가 FREESECT로 해제한 섹터 — finish()에서 재할당 안 된 것만 0으로 지움 (데이터 잔존 방지) */\n private freedSectors: number[] = []\n private freedMiniSectors: number[] = []\n\n constructor(file: Buffer) {\n if (file.length < SECTOR || file.readUInt32LE(0) !== 0xe011cfd0) {\n throw new OleSurgeonError(\"OLE 시그니처가 아닙니다\")\n }\n if (file.readUInt16LE(26) !== 3 || file.readUInt16LE(30) !== 9) {\n throw new OleSurgeonError(\"CFB v3(512B 섹터)만 지원합니다\")\n }\n // 섹터 경계로 패딩된 사본에서 작업\n const padded = Math.ceil((file.length - SECTOR) / SECTOR) * SECTOR + SECTOR\n this.buf = Buffer.alloc(padded)\n this.len = padded\n file.copy(this.buf)\n this.loadFat()\n this.loadMiniFat()\n this.loadDirectory()\n }\n\n // ── 로드 ──\n\n private loadFat(): void {\n const difat: number[] = []\n for (let i = 0; i < 109; i++) difat.push(this.buf.readUInt32LE(76 + i * 4))\n let difatSector = this.buf.readUInt32LE(68)\n let guard = 0\n while (difatSector !== ENDOFCHAIN && difatSector !== FREESECT && guard++ < 1_000_000) {\n const off = this.sectorOffset(difatSector)\n for (let i = 0; i < 127; i++) difat.push(this.buf.readUInt32LE(off + i * 4))\n difatSector = this.buf.readUInt32LE(off + 127 * 4)\n }\n this.fatSectors = difat.filter(s => s !== FREESECT)\n for (const s of this.fatSectors) {\n const off = this.sectorOffset(s)\n for (let i = 0; i < 128; i++) this.fat.push(this.buf.readUInt32LE(off + i * 4))\n }\n }\n\n private loadMiniFat(): void {\n const start = this.buf.readUInt32LE(60)\n this.miniFatSectors = start === ENDOFCHAIN || start === FREESECT ? [] : this.chain(start)\n for (const s of this.miniFatSectors) {\n const off = this.sectorOffset(s)\n for (let i = 0; i < 128; i++) this.miniFat.push(this.buf.readUInt32LE(off + i * 4))\n }\n }\n\n private loadDirectory(): void {\n this.dirSectors = this.chain(this.buf.readUInt32LE(48))\n for (let si = 0; si < this.dirSectors.length; si++) {\n const off = this.sectorOffset(this.dirSectors[si])\n for (let i = 0; i < 4; i++) {\n const e = off + i * 128\n const nameLen = this.buf.readUInt16LE(e + 64)\n const name = nameLen >= 2 ? this.buf.subarray(e, e + nameLen - 2).toString(\"utf16le\") : \"\"\n this.entries.push({\n index: si * 4 + i,\n name,\n type: this.buf[e + 66],\n left: this.buf.readInt32LE(e + 68),\n right: this.buf.readInt32LE(e + 72),\n child: this.buf.readInt32LE(e + 76),\n start: this.buf.readUInt32LE(e + 116),\n size: this.buf.readUInt32LE(e + 120),\n })\n }\n }\n }\n\n // ── 헬퍼 ──\n\n private sectorOffset(n: number): number {\n const off = SECTOR + n * SECTOR\n if (n >= 0xfffffffa || off + SECTOR > this.len) throw new OleSurgeonError(`섹터 범위 초과: ${n}`)\n return off\n }\n\n private chain(start: number): number[] {\n const out: number[] = []\n let s = start\n while (s !== ENDOFCHAIN) {\n if (s === FREESECT || s >= this.fat.length || out.length > this.fat.length) {\n throw new OleSurgeonError(\"FAT 체인 손상\")\n }\n out.push(s)\n s = this.fat[s]\n }\n return out\n }\n\n private miniChain(start: number): number[] {\n const out: number[] = []\n let s = start\n while (s !== ENDOFCHAIN) {\n if (s === FREESECT || s >= this.miniFat.length || out.length > this.miniFat.length) {\n throw new OleSurgeonError(\"miniFAT 체인 손상\")\n }\n out.push(s)\n s = this.miniFat[s]\n }\n return out\n }\n\n /** 디렉토리 트리에서 경로 해석 (형제 = L/R 이진 트리, 자식 = child) */\n private findEntry(path: string): DirEntry {\n const parts = path.replace(/^\\//, \"\").split(\"/\")\n let scope = this.entries[0]?.child ?? -1\n let current: DirEntry | undefined\n for (const part of parts) {\n // 빨강-검정 형제 트리를 순회해 이름이 일치하는 엔트리를 찾는다\n const search = (idx: number): DirEntry | undefined => {\n if (idx < 0 || idx >= this.entries.length) return undefined\n const e = this.entries[idx]\n return search(e.left) ?? (e.name === part ? e : undefined) ?? search(e.right)\n }\n current = search(scope)\n if (!current) throw new OleSurgeonError(`스트림 없음: ${path}`)\n scope = current.child\n }\n if (!current || current.type !== 2) throw new OleSurgeonError(`스트림이 아님: ${path}`)\n return current\n }\n\n private rootEntry(): DirEntry {\n return this.entries[0]\n }\n\n // ── 할당 ──\n\n /**\n * FAT에서 빈 섹터 n개 확보 (부족하면 파일 끝에 추가) — 섹터 번호 목록 반환.\n * 확보 즉시 ENDOFCHAIN으로 마킹해 같은 수술 내 중복 할당을 방지한다 (체인 링크는\n * 호출자가 덮어씀).\n */\n private allocSectors(n: number): number[] {\n const out: number[] = []\n for (let i = 0; i < this.fat.length && out.length < n; i++) {\n if (this.fat[i] !== FREESECT) continue\n // FAT가 파일보다 길게 패딩된 영역은 건너뜀 (백킹 바이트 없음)\n if (SECTOR + (i + 1) * SECTOR > this.len) continue\n this.fat[i] = ENDOFCHAIN\n // 재사용 free 섹터는 즉시 0 초기화 — 부분 기록(mini stream 64B 단위 등) 시\n // 이전 스트림 바이트가 슬랙에 남는 remanence 방지\n const off = this.sectorOffset(i)\n this.buf.fill(0, off, off + SECTOR)\n out.push(i)\n }\n while (out.length < n) {\n // FAT 확장이 파일 끝에 FAT 섹터를 추가할 수 있으므로 인덱스는 확장 후 재계산\n this.ensureFatCapacity((this.len - SECTOR) / SECTOR + 2)\n const idx = this.appendSector()\n this.fat[idx] = ENDOFCHAIN\n out.push(idx)\n }\n return out\n }\n\n /**\n * 파일 끝에 빈 섹터 1개 추가 — 새 섹터 번호 반환.\n * 섹터마다 Buffer.concat(전체 복사)하면 대형 스트림 삽입이 O(n²)이라,\n * capacity를 기하급수(×2)로 재할당하고 논리 길이(len)만 늘린다 (amortized O(n)).\n * Buffer.alloc은 0으로 채워지고 len 너머엔 아무도 쓰지 않으므로 새 섹터는 항상 0.\n */\n private appendSector(): number {\n const idx = (this.len - SECTOR) / SECTOR\n if (this.len + SECTOR > this.buf.length) {\n const grown = Buffer.alloc(Math.max(this.buf.length * 2, this.len + SECTOR))\n this.buf.copy(grown, 0, 0, this.len)\n this.buf = grown\n }\n this.len += SECTOR\n return idx\n }\n\n /** FAT 배열이 sectorCount개 엔트리를 담도록 확장 (FAT 섹터 추가 + DIFAT 갱신) */\n private ensureFatCapacity(sectorCount: number): void {\n while (this.fat.length < sectorCount) {\n // 새 FAT 섹터는 파일 끝에 추가 (할당 재귀 방지)\n const idx = this.appendSector()\n for (let i = 0; i < 128; i++) this.fat.push(FREESECT)\n this.fat[idx] = FATSECT\n this.fatSectors.push(idx)\n // DIFAT 헤더 슬롯(109개)에 등록 — 초과(FAT 109섹터 ≈ 7MB)는 미지원\n const slot = this.fatSectors.length - 1\n if (slot >= 109) throw new OleSurgeonError(\"DIFAT 체인 확장은 미지원 (7MB 초과 컨테이너 성장)\")\n this.buf.writeUInt32LE(idx, 76 + slot * 4)\n this.buf.writeUInt32LE(this.fatSectors.length, 44) // header fatSectors\n }\n }\n\n /** miniFAT에서 빈 미니섹터 n개 확보 (mini stream 용량/miniFAT 확장 포함) */\n private allocMiniSectors(n: number): number[] {\n const root = this.rootEntry()\n const rootChain = root.start === ENDOFCHAIN || root.size === 0 ? [] : this.chain(root.start)\n let capacity = rootChain.length * (SECTOR / MINI_SECTOR)\n\n const out: number[] = []\n // 빈 엔트리 재사용 — 백킹 바이트(root 체인 용량) 있는 범위만\n for (let i = 0; i < Math.min(this.miniFat.length, capacity) && out.length < n; i++) {\n if (this.miniFat[i] === FREESECT) { this.miniFat[i] = ENDOFCHAIN; out.push(i) }\n }\n let nextIdx = capacity\n while (out.length < n) {\n // miniFAT 엔트리 공간 확장\n if (nextIdx >= this.miniFat.length) {\n const [s] = this.allocSectors(1)\n if (this.miniFatSectors.length > 0) this.fat[this.miniFatSectors[this.miniFatSectors.length - 1]] = s\n else this.buf.writeUInt32LE(s, 60) // header miniFatStart\n this.miniFatSectors.push(s)\n this.buf.writeUInt32LE(this.miniFatSectors.length, 64) // header miniFatCnt\n for (let i = 0; i < 128; i++) this.miniFat.push(FREESECT)\n }\n // mini stream 데이터 용량 확장 (root 체인 연장)\n if (nextIdx >= capacity) {\n const [s] = this.allocSectors(1)\n if (rootChain.length > 0) this.fat[rootChain[rootChain.length - 1]] = s\n else { root.start = s }\n rootChain.push(s)\n capacity = rootChain.length * (SECTOR / MINI_SECTOR)\n root.size = Math.max(root.size, rootChain.length * SECTOR)\n this.writeDirEntry(root)\n }\n this.miniFat[nextIdx] = ENDOFCHAIN\n out.push(nextIdx)\n nextIdx++\n }\n return out\n }\n\n // ── 기록 ──\n\n private writeDirEntry(e: DirEntry): void {\n const sector = this.dirSectors[Math.floor(e.index / 4)]\n const off = this.sectorOffset(sector) + (e.index % 4) * 128\n this.buf.writeUInt32LE(e.start, off + 116)\n this.buf.writeUInt32LE(e.size, off + 120)\n }\n\n private flushFat(): void {\n for (let i = 0; i < this.fatSectors.length; i++) {\n const off = this.sectorOffset(this.fatSectors[i])\n for (let j = 0; j < 128; j++) {\n const idx = i * 128 + j\n this.buf.writeUInt32LE(idx < this.fat.length ? this.fat[idx] : FREESECT, off + j * 4)\n }\n }\n for (let i = 0; i < this.miniFatSectors.length; i++) {\n const off = this.sectorOffset(this.miniFatSectors[i])\n for (let j = 0; j < 128; j++) {\n const idx = i * 128 + j\n this.buf.writeUInt32LE(idx < this.miniFat.length ? this.miniFat[idx] : FREESECT, off + j * 4)\n }\n }\n }\n\n /** 미니섹터 k의 파일 내 바이트 오프셋 (root 체인 경유) */\n private miniOffset(k: number, rootChain: number[]): number {\n const within = k * MINI_SECTOR\n const sec = rootChain[Math.floor(within / SECTOR)]\n if (sec === undefined) throw new OleSurgeonError(\"mini stream 범위 초과\")\n return this.sectorOffset(sec) + (within % SECTOR)\n }\n\n // ── 메인 ──\n\n replace(path: string, newData: Buffer): void {\n const entry = this.findEntry(path)\n\n // 1) 기존 체인 해제 — 해제 섹터는 기록해 finish()에서 바이트를 지운다 (삭제 전 데이터 잔존 방지)\n if (entry.size > 0 && entry.start !== ENDOFCHAIN) {\n if (entry.size < MINI_CUTOFF) {\n for (const s of this.miniChain(entry.start)) {\n this.miniFat[s] = FREESECT\n this.freedMiniSectors.push(s)\n }\n } else {\n for (const s of this.chain(entry.start)) {\n this.fat[s] = FREESECT\n this.freedSectors.push(s)\n }\n }\n }\n\n // 2) 새 체인 할당 + 데이터 기록\n if (newData.length < MINI_CUTOFF) {\n const count = Math.ceil(newData.length / MINI_SECTOR) || 1\n const sectors = this.allocMiniSectors(count)\n const rootChain = this.chain(this.rootEntry().start)\n for (let i = 0; i < sectors.length; i++) {\n this.miniFat[sectors[i]] = i + 1 < sectors.length ? sectors[i + 1] : ENDOFCHAIN\n const off = this.miniOffset(sectors[i], rootChain)\n this.buf.fill(0, off, off + MINI_SECTOR)\n newData.copy(this.buf, off, i * MINI_SECTOR, Math.min((i + 1) * MINI_SECTOR, newData.length))\n }\n entry.start = sectors[0]\n } else {\n const count = Math.ceil(newData.length / SECTOR)\n const sectors = this.allocSectors(count)\n for (let i = 0; i < sectors.length; i++) {\n this.fat[sectors[i]] = i + 1 < sectors.length ? sectors[i + 1] : ENDOFCHAIN\n const off = this.sectorOffset(sectors[i])\n this.buf.fill(0, off, off + SECTOR)\n newData.copy(this.buf, off, i * SECTOR, Math.min((i + 1) * SECTOR, newData.length))\n }\n entry.start = sectors[0]\n }\n entry.size = newData.length\n this.writeDirEntry(entry)\n }\n\n /**\n * wipeFreeSectors 본체 — 어느 체인에도 닿지 않는 섹터·미니섹터와 스트림 꼬리 슬랙을 0으로.\n * FREESECT 표시를 믿지 않고 도달성으로 판정한다(쓰는 쪽에 따라 빈 FAT 칸을 ENDOFCHAIN 으로 채우기도 한다).\n */\n wipeUnallocated(): void {\n const used = new Set<number>([...this.fatSectors, ...this.miniFatSectors, ...this.dirSectors])\n let d = this.buf.readUInt32LE(68)\n for (let guard = 0; d !== ENDOFCHAIN && d !== FREESECT && guard < 1_000_000; guard++) {\n used.add(d)\n d = this.buf.readUInt32LE(this.sectorOffset(d) + 127 * 4)\n }\n const root = this.rootEntry()\n const rootChain = root.start === ENDOFCHAIN || root.size === 0 ? [] : this.chain(root.start)\n for (const s of rootChain) used.add(s)\n const usedMini = new Set<number>()\n for (const e of this.entries) {\n if (e.type !== 2 || e.size === 0 || e.start === ENDOFCHAIN) continue\n if (e.size < MINI_CUTOFF) {\n const chain = this.miniChain(e.start)\n for (const s of chain) usedMini.add(s)\n const tail = e.size - (chain.length - 1) * MINI_SECTOR\n const off = this.miniOffset(chain[chain.length - 1], rootChain)\n if (tail > 0 && tail < MINI_SECTOR) this.buf.fill(0, off + tail, off + MINI_SECTOR)\n } else {\n const chain = this.chain(e.start)\n for (const s of chain) used.add(s)\n const tail = e.size - (chain.length - 1) * SECTOR\n const off = this.sectorOffset(chain[chain.length - 1])\n if (tail > 0 && tail < SECTOR) this.buf.fill(0, off + tail, off + SECTOR)\n }\n }\n for (let i = 0; SECTOR + (i + 1) * SECTOR <= this.len; i++) {\n if (!used.has(i)) this.buf.fill(0, SECTOR + i * SECTOR, SECTOR + (i + 1) * SECTOR)\n }\n const capacity = rootChain.length * (SECTOR / MINI_SECTOR)\n for (let i = 0; i < capacity; i++) {\n if (usedMini.has(i)) continue\n const off = this.miniOffset(i, rootChain)\n this.buf.fill(0, off, off + MINI_SECTOR)\n }\n }\n\n finish(): Buffer {\n this.wipeFreedSectors()\n this.flushFat()\n // 기하급수 성장으로 capacity가 논리 길이보다 클 수 있음 — 논리 길이만 반환\n return this.len === this.buf.length ? this.buf : this.buf.subarray(0, this.len)\n }\n\n /** 해제 후 재할당되지 않고 남은 FREESECT 섹터의 바이트를 0으로 채움 (데이터 remanence 제거) */\n private wipeFreedSectors(): void {\n for (const s of this.freedSectors) {\n if (this.fat[s] !== FREESECT) continue // 새 체인에 재사용됨 — 이미 새 데이터 기록\n const off = this.sectorOffset(s)\n this.buf.fill(0, off, off + SECTOR)\n }\n if (this.freedMiniSectors.length > 0) {\n const root = this.rootEntry()\n const rootChain = root.start === ENDOFCHAIN || root.size === 0 ? [] : this.chain(root.start)\n for (const s of this.freedMiniSectors) {\n if (this.miniFat[s] !== FREESECT) continue\n const off = this.miniOffset(s, rootChain)\n this.buf.fill(0, off, off + MINI_SECTOR)\n }\n }\n }\n}\n","/**\n * HWPX 구조 검증 — 한컴오피스/한컴독스가 열기를 거부하는 컨테이너 결함을 사전에 잡는다.\n *\n * 검사 항목 (claw-hwp validate.py의 실측 검사셋 이식 — MIT © DoHyun468/claw-hwp):\n * - 유효한 ZIP인지, mimetype이 첫 엔트리이고 내용이 application/hwp+zip인지\n * - 필수 파일 존재 (META-INF/container.xml, content.hpf, header.xml, section0.xml)\n * - XML/HPF/RDF 엔트리 웰폼드\n * - header.xml secCnt == 실제 Contents/sectionN.xml 수\n * (한컴독스는 실제 파일 목록이 아니라 secCnt를 신뢰하고, 불일치 시 열기를 거부한다)\n * - content.hpf manifest의 <opf:item href>가 전부 실존하는지\n */\n\nimport JSZip from \"jszip\"\nimport { DOMParser } from \"@xmldom/xmldom\"\n\n/** 검증에서 발견된 문제 하나 */\nexport interface ValidateIssue {\n /** 문제가 발견된 zip 내부 경로 (컨테이너 전역 문제면 생략) */\n path?: string\n message: string\n}\n\n/** validateHwpx 결과 */\nexport interface ValidateResult {\n ok: boolean\n issues: ValidateIssue[]\n /** 검사한 zip 엔트리 수 (디렉토리 제외) */\n entryCount: number\n}\n\nconst REQUIRED_FILES = [\n \"mimetype\",\n \"META-INF/container.xml\",\n \"Contents/content.hpf\",\n \"Contents/header.xml\",\n \"Contents/section0.xml\",\n]\nconst EXPECTED_MIMETYPE = \"application/hwp+zip\"\nconst XML_SUFFIXES = [\".xml\", \".hpf\", \".rdf\"]\nconst SECTION_FILE_RE = /^Contents\\/section\\d+\\.xml$/\nconst SECCNT_RE = /<(?:\\w+:)?head\\b[^>]*?\\bsecCnt=\"(\\d+)\"/\nconst OPF_HREF_RE = /<opf:item\\b[^>]*?\\bhref=\"([^\"]*)\"/g\n\n/** HWPX 버퍼의 컨테이너 구조를 검증한다. 문제가 없으면 ok=true. */\nexport async function validateHwpx(buffer: ArrayBuffer | Uint8Array): Promise<ValidateResult> {\n const issues: ValidateIssue[] = []\n\n let zip: JSZip\n try {\n zip = await JSZip.loadAsync(buffer)\n } catch (err) {\n return {\n ok: false,\n issues: [{ message: `유효한 ZIP이 아님: ${err instanceof Error ? err.message : String(err)}` }],\n entryCount: 0,\n }\n }\n\n // 중앙 디렉토리 순서 그대로 (첫 엔트리 검사에 필요), 파일 목록은 디렉토리 엔트리 제외\n const rawNames = Object.keys(zip.files)\n const names = rawNames.filter(n => !zip.files[n].dir)\n if (names.length === 0) return { ok: false, issues: [{ message: \"빈 ZIP\" }], entryCount: 0 }\n\n if (rawNames[0] !== \"mimetype\") {\n issues.push({ message: `첫 zip 엔트리가 '${rawNames[0]}' — 'mimetype'이어야 함` })\n }\n\n const nameset = new Set(names)\n if (nameset.has(\"mimetype\")) {\n const mt = (await zip.files[\"mimetype\"].async(\"string\")).trim()\n if (mt !== EXPECTED_MIMETYPE) {\n issues.push({ path: \"mimetype\", message: `내용이 '${mt}' — '${EXPECTED_MIMETYPE}'이어야 함` })\n }\n }\n\n for (const req of REQUIRED_FILES) {\n if (!nameset.has(req)) issues.push({ message: `필수 파일 누락: ${req}` })\n }\n\n // XML 웰폼드 — warn 수준은 무시, error/fatalError만 문제로 취급\n for (const name of names) {\n if (!XML_SUFFIXES.some(s => name.endsWith(s))) continue\n const text = await zip.files[name].async(\"string\")\n let firstError: string | null = null\n try {\n new DOMParser({\n onError(level, msg) {\n // xmldom ErrorHandlerFunction의 level은 \"warning\" | \"error\" | \"fatalError\"\n if (level !== \"warning\" && firstError === null) firstError = String(msg)\n },\n }).parseFromString(text, \"text/xml\")\n } catch (err) {\n firstError ??= err instanceof Error ? err.message : String(err)\n }\n if (firstError !== null) {\n issues.push({ path: name, message: `XML 웰폼드 위반: ${(firstError as string).split(\"\\n\")[0]}` })\n }\n }\n\n // secCnt ↔ 실제 섹션 파일 수\n if (nameset.has(\"Contents/header.xml\")) {\n const header = await zip.files[\"Contents/header.xml\"].async(\"string\")\n const m = SECCNT_RE.exec(header)\n if (m) {\n const declared = Number(m[1])\n const actual = names.filter(n => SECTION_FILE_RE.test(n)).length\n if (declared !== actual) {\n issues.push({\n path: \"Contents/header.xml\",\n message: `secCnt=${declared}인데 실제 sectionN.xml은 ${actual}개 — 한컴독스가 열기를 거부함`,\n })\n }\n }\n }\n\n // manifest href 실존 — content.hpf는 Contents/ 안에 있어 href는 그 위치 기준 상대경로(\"section0.xml\")가\n // 표준(OCF)이지만, kordoc 생성기는 루트 기준 full path(\"Contents/section0.xml\")로 쓴다. 두 관례 모두 유효로\n // 인정한다(한컴 원본은 상대경로 — 안 그러면 정상 파일에 오탐).\n if (nameset.has(\"Contents/content.hpf\")) {\n const hpf = await zip.files[\"Contents/content.hpf\"].async(\"string\")\n for (const m of hpf.matchAll(OPF_HREF_RE)) {\n const href = m[1]\n if (!nameset.has(href) && !nameset.has(`Contents/${href}`)) {\n issues.push({ path: \"Contents/content.hpf\", message: `manifest가 없는 파일을 참조: ${href}` })\n }\n }\n }\n\n return { ok: issues.length === 0, issues, entryCount: names.length }\n}\n","/**\n * HWPX 문서 세션 — 에디터 통합용 블록 단위 증분 패치 API (v3.1).\n *\n * patchHwpx가 \"편집된 마크다운 전체\"를 받아 내부에서 LCS 정렬하는 것과 달리,\n * 세션은 블록 인덱스로 직접 편집을 지정한다 (에디터의 블록 클릭-편집에 대응).\n *\n * 설계 원칙:\n * - 매핑은 patcher와 동일한 알고리즘 재사용 (정규화 텍스트 버킷 + 표 서수) —\n * \"n회 연속 patchBlocks ≡ 일괄 patchHwpx\" 동등성이 성립하는 근거.\n * - 패치 후 상태는 새 바이트에서 전체 재구축 (오프셋 리베이스 대신 재스캔 —\n * 성능보다 정합성). patchBlocks 호출 후 이전 블록 인덱스는 무효이며\n * session.blocks를 다시 읽어야 한다.\n * - capability()는 patcher의 graceful-skip 게이트를 사전 판정으로 노출 —\n * 에디터가 편집 전에 잠금 UI를 띄울 수 있는 단일 진실 소스.\n */\n\nimport JSZip from \"jszip\"\nimport { parseHwpxDocument } from \"../hwpx/parser.js\"\nimport type { IRBlock, IRTable, PatchOptions, PatchResult, PatchSkip, DiffResult } from \"../types.js\"\nimport {\n scanSectionXml, buildParagraphSplices, applySplices, allLinesegRemovalSplices,\n type SectionScan, type ScanTable, type SpliceEdit,\n} from \"./source-map.js\"\nimport { patchZipEntries } from \"./zip-patch.js\"\nimport { resolveSectionEntryNames } from \"./hwpx-entries.js\"\nimport {\n resolveParagraphMappings, removeNoteMarks, buildTableOrdinals, buildOrigUnits, diffUnitLists,\n type ParaMapping,\n} from \"./patcher.js\"\nimport { applyCellEdit, stripCellTokens, extractCellTokens } from \"./table-patch.js\"\nimport { splitMarkdownUnits, normForMatch, sanitizeText, summarize, AUTONUM_PREFIX_RE } from \"./markdown-units.js\"\n\n// ─── 공개 타입 ───────────────────────────────────────\n\n/** 블록 편집 가능성 — 에디터 잠금 UI의 근거 */\nexport type BlockCapability = \"text\" | \"cell-text\" | \"locked\"\n\nexport interface CellCapability {\n editable: boolean\n /** 편집 불가 사유 (한국어) */\n reason?: string\n}\n\nexport interface BlockCapabilityInfo {\n capability: BlockCapability\n /** locked 사유 (한국어) */\n reason?: string\n /** 표 블록: IRTable 격자 좌표(row×col)별 셀 편집 가능 여부 */\n cells?: CellCapability[][]\n}\n\n/** 블록 → 원본 위치 참조 (에디터 하이라이트/점프용) */\nexport interface BlockSourceRef {\n kind: \"paragraph\" | \"table\"\n /** 0-based 섹션 인덱스 */\n sectionIndex: number\n /** 섹션 XML 내 시작 문자 오프셋 (<hp:p>/<hp:tbl> 여는 태그) */\n xmlStart: number\n}\n\n/** 블록 단위 편집 — patchBlocks 입력 */\nexport interface BlockEdit {\n /** session.blocks 기준 0-based 블록 인덱스 */\n blockIndex: number\n /**\n * 문단/헤딩 블록의 새 텍스트 (평문).\n * 빈 문자열(비우기)은 미지원 — patchHwpx의 \"블록 삭제 미지원\"과 정합\n * (비우면 재파싱 시 블록 핸들이 사라져 세션으로 복구 불가).\n */\n newText?: string\n /** 표 블록의 셀 편집 (IRTable 격자 좌표 기준). 이미지가 든 셀은 이미지\n * 토큰(``/`[이미지: ...]`)을 유지한 채 텍스트만 수정해야 한다. */\n cells?: Array<{ row: number; col: number; text: string }>\n}\n\n// ─── 내부 상태 ───────────────────────────────────────\n\ninterface SessionState {\n bytes: Uint8Array\n blocks: IRBlock[]\n markdown: string\n sectionPaths: string[]\n scans: SectionScan[]\n paraMap: Map<number, ParaMapping>\n scanTables: ScanTable[]\n tableOrdinals: Map<number, number>\n /** 여러 마크다운 유닛으로 갈라지는 블록 (부분 수정 불가) */\n fragmentBlocks: Set<number>\n}\n\nasync function buildState(bytes: Uint8Array): Promise<SessionState> {\n const parsed = await parseHwpxDocument(u8ToArrayBuffer(bytes))\n const zip = await JSZip.loadAsync(bytes)\n const sectionPaths = await resolveSectionEntryNames(zip)\n if (sectionPaths.length === 0) {\n throw new Error(\"HWPX 섹션 파일을 찾을 수 없습니다\")\n }\n const scans: SectionScan[] = []\n for (let i = 0; i < sectionPaths.length; i++) {\n const xml = await zip.file(sectionPaths[i])!.async(\"text\")\n scans.push(scanSectionXml(xml, i))\n }\n const paraMap = resolveParagraphMappings(parsed.blocks, scans)\n const scanTables = scans.flatMap(s => s.tables.filter(t => t.rows.length > 0))\n const tableOrdinals = buildTableOrdinals(parsed.blocks)\n const fragmentBlocks = new Set<number>()\n const unitBlocks = new Set<number>()\n for (const u of buildOrigUnits(parsed.blocks)) {\n unitBlocks.add(u.blockIdx)\n if (u.fragment) fragmentBlocks.add(u.blockIdx)\n }\n // 유닛이 없는 문단/헤딩 블록 = [별표] 병합 등으로 다른 블록 유닛에 흡수됨 —\n // patchHwpx가 fragment로 skip하는 영역이므로 세션도 잠가 동등성 유지\n for (let i = 0; i < parsed.blocks.length; i++) {\n const b = parsed.blocks[i]\n if ((b.type === \"paragraph\" || b.type === \"heading\") && b.text && !unitBlocks.has(i)) {\n fragmentBlocks.add(i)\n }\n }\n return {\n bytes, blocks: parsed.blocks, markdown: parsed.markdown,\n sectionPaths, scans, paraMap, scanTables, tableOrdinals, fragmentBlocks,\n }\n}\n\nfunction u8ToArrayBuffer(u8: Uint8Array): ArrayBuffer {\n return u8.buffer.slice(u8.byteOffset, u8.byteOffset + u8.byteLength) as ArrayBuffer\n}\n\n/** IR 셀 텍스트 → 마크다운 렌더와 동일 규칙의 비어있지 않은 라인들 */\nfunction irCellLines(text: string): string[] {\n return stripCellTokens(sanitizeText(text)).split(\"\\n\").map(s => s.trim()).filter(Boolean)\n}\n\n// ─── 세션 ────────────────────────────────────────────\n\nexport class HwpxSession {\n private state: SessionState\n\n private constructor(state: SessionState) {\n this.state = state\n }\n\n /** HWPX 바이트로 세션을 연다 (입력은 복사되어 외부 변이와 격리) */\n static async open(input: Uint8Array | ArrayBuffer): Promise<HwpxSession> {\n // 주의: new Uint8Array(ArrayBuffer)는 복사가 아닌 뷰 — slice로 명시 복사\n const bytes = input instanceof Uint8Array ? new Uint8Array(input) : new Uint8Array(input.slice(0))\n return new HwpxSession(await buildState(bytes))\n }\n\n /** 현재 문서의 IR 블록 — patchBlocks 후 갱신되므로 호출마다 다시 읽을 것 */\n get blocks(): IRBlock[] {\n return this.state.blocks\n }\n\n /** 현재 문서의 마크다운 */\n get markdown(): string {\n return this.state.markdown\n }\n\n /** 현재 문서 바이트 (복사본) */\n get bytes(): Uint8Array {\n return new Uint8Array(this.state.bytes)\n }\n\n /** 블록 → 원본 위치 참조. 매핑 실패 시 undefined */\n sourceRef(blockIndex: number): BlockSourceRef | undefined {\n const st = this.state\n const block = st.blocks[blockIndex]\n if (!block) return undefined\n if (block.type === \"paragraph\" || block.type === \"heading\") {\n const para = st.paraMap.get(blockIndex)?.para\n if (!para) return undefined\n return { kind: \"paragraph\", sectionIndex: para.sectionIndex, xmlStart: para.start }\n }\n if (block.type === \"table\" && block.table) {\n if (st.tableOrdinals.size !== st.scanTables.length) return undefined\n const ordinal = st.tableOrdinals.get(blockIndex)\n const t = ordinal !== undefined ? st.scanTables[ordinal] : undefined\n if (!t) return undefined\n return { kind: \"table\", sectionIndex: t.sectionIndex, xmlStart: t.start }\n }\n return undefined\n }\n\n /** 블록 편집 가능성 사전 판정 — patcher graceful-skip 게이트의 사전 버전 */\n capability(blockIndex: number): BlockCapabilityInfo {\n const st = this.state\n const block = st.blocks[blockIndex]\n if (!block) return { capability: \"locked\", reason: \"블록 인덱스 범위 밖\" }\n\n if (block.type === \"paragraph\" || block.type === \"heading\") {\n if (st.fragmentBlocks.has(blockIndex)) {\n return { capability: \"locked\", reason: \"문단 분절(강제 줄바꿈/병합 유닛) — 부분 수정은 미지원 (v1)\" }\n }\n if (block.text && block.text.includes(\"\\n\")) {\n return { capability: \"locked\", reason: \"문단 내 강제 줄바꿈 포함 — 수정 시 줄바꿈 보존 불가로 미지원 (v1)\" }\n }\n if (!st.paraMap.get(blockIndex)?.para) {\n return { capability: \"locked\", reason: \"문단 소스맵 매핑 실패 (머리말/글상자/캡션 영역이거나 텍스트 불일치)\" }\n }\n return { capability: \"text\" }\n }\n\n if (block.type === \"table\" && block.table) {\n if (st.tableOrdinals.size !== st.scanTables.length) {\n return { capability: \"locked\", reason: \"표 개수 불일치 — 소스맵 신뢰 불가\" }\n }\n const ordinal = st.tableOrdinals.get(blockIndex)\n const scanTable = ordinal !== undefined ? st.scanTables[ordinal] : undefined\n if (!scanTable) {\n return { capability: \"locked\", reason: \"표 소스맵 매핑 실패\" }\n }\n const table = block.table\n const cells: CellCapability[][] = []\n let anyEditable = false\n for (let r = 0; r < table.rows; r++) {\n const row: CellCapability[] = []\n for (let c = 0; c < table.cols; c++) {\n const info = cellStaticCheck(table, scanTable, r, c)\n if (info.editable) anyEditable = true\n row.push(info)\n }\n cells.push(row)\n }\n if (!anyEditable) return { capability: \"locked\", reason: \"편집 가능한 셀 없음\", cells }\n return { capability: \"cell-text\", cells }\n }\n\n return { capability: \"locked\", reason: `${block.type} 블록 편집은 미지원 (v1)` }\n }\n\n /** 전 블록의 편집 가능성 */\n capabilities(): BlockCapabilityInfo[] {\n return this.state.blocks.map((_, i) => this.capability(i))\n }\n\n /**\n * 블록 단위 증분 패치 — 적용 후 세션 상태가 새 바이트로 갱신된다.\n *\n * - 호출은 내부적으로 직렬화된다 (동시 호출 시 도착 순서대로 누적 적용)\n * - 무변경 편집(현재 텍스트와 동일)은 조용히 건너뜀 (applied/skipped 모두 제외)\n * - 변경이 하나도 적용되지 않으면 반환 data는 현재 문서와 바이트 동일\n * - changes는 \"패치 전 → 후\" 문서 diff — modified 수가 기대 편집 수와\n * 일치하는지 확인 용도. patchHwpx의 verification(잔차 검증)과 의미가 다르다.\n */\n async patchBlocks(edits: BlockEdit[], options?: PatchOptions): Promise<PatchResult> {\n // 재진입 직렬화 — 겹치는 호출이 서로의 상태 갱신을 덮어쓰는 lost-update 방지\n const run = this.opQueue.then(() => this.patchBlocksInner(edits, options))\n this.opQueue = run.then(() => undefined, () => undefined)\n return run\n }\n\n private opQueue: Promise<void> = Promise.resolve()\n\n private async patchBlocksInner(edits: BlockEdit[], options?: PatchOptions): Promise<PatchResult> {\n const st = this.state\n const skipped: PatchSkip[] = []\n let applied = 0\n const sectionSplices: SpliceEdit[][] = st.scans.map(() => [])\n const cellCtx = { scans: st.scans, sectionSplices, skipped }\n const seenParas = new Set<number>()\n const seenCells = new Set<string>()\n\n for (const edit of edits) {\n const i = edit.blockIndex\n const block = st.blocks[i]\n if (!block) {\n skipped.push({ reason: `블록 인덱스 범위 밖: ${i}` })\n continue\n }\n\n // ── 표 셀 편집 ──\n if (block.type === \"table\" && block.table) {\n if (!edit.cells?.length) {\n skipped.push({ reason: \"표 블록에는 cells 편집만 지원\", before: summarize(block.table.caption ?? \"(표)\") })\n continue\n }\n if (st.tableOrdinals.size !== st.scanTables.length) {\n skipped.push({ reason: \"표 개수 불일치 — 소스맵 신뢰 불가\" })\n continue\n }\n const ordinal = st.tableOrdinals.get(i)\n const scanTable = ordinal !== undefined ? st.scanTables[ordinal] : undefined\n if (!scanTable) {\n skipped.push({ reason: \"표 소스맵 매핑 실패\" })\n continue\n }\n for (const cellEdit of edit.cells) {\n const key = `${i}:${cellEdit.row},${cellEdit.col}`\n if (seenCells.has(key)) {\n skipped.push({ reason: \"같은 셀에 중복 편집 — 먼저 적용된 편집 유지\", after: summarize(cellEdit.text) })\n continue\n }\n const irCell = block.table.cells[cellEdit.row]?.[cellEdit.col]\n if (!irCell) {\n skipped.push({ reason: `셀 좌표 범위 밖: ${cellEdit.row},${cellEdit.col}`, after: summarize(cellEdit.text) })\n continue\n }\n // 이미지 토큰은 본문 텍스트가 아님 — 변경 불가, 기록 전 제거\n if (extractCellTokens(irCell.text) !== extractCellTokens(cellEdit.text)) {\n skipped.push({ reason: \"셀 내 이미지 변경은 미지원\", before: summarize(irCell.text), after: summarize(cellEdit.text) })\n continue\n }\n const newLines = stripCellTokens(cellEdit.text).split(\"\\n\").map(s => s.trim()).filter(Boolean)\n const origLines = irCellLines(irCell.text)\n if (newLines.join(\"\\n\") === origLines.join(\"\\n\")) continue // 무변경\n const n = applyCellEdit(\n block.table, scanTable, cellEdit.row, cellEdit.col, newLines, cellCtx,\n irCell.text, cellEdit.text, origLines.length,\n )\n // splice가 실제 생성된 편집만 슬롯 점유 (no-op/skip은 후속 편집 허용)\n if (n > 0) seenCells.add(key)\n applied += n\n }\n continue\n }\n\n // ── 문단/헤딩 텍스트 편집 ──\n if ((block.type === \"paragraph\" || block.type === \"heading\") && edit.newText !== undefined) {\n if (seenParas.has(i)) {\n skipped.push({ reason: \"같은 블록에 중복 편집 — 먼저 적용된 편집 유지\", after: summarize(edit.newText) })\n continue\n }\n const n = this.patchParagraphPlain(i, block, edit.newText, sectionSplices, skipped)\n // splice가 실제 생성된 편집만 슬롯 점유 (no-op/skip은 후속 편집 허용)\n if (n > 0) seenParas.add(i)\n applied += n\n continue\n }\n\n skipped.push({\n reason: `지원하지 않는 블록 유형(${block.type}) 또는 편집 형식`,\n before: summarize(block.text ?? \"\"),\n })\n }\n\n // ── splice 적용 + ZIP 재조립 (patcher와 동일 경로) ──\n const replacements = new Map<string, Uint8Array>()\n const encoder = new TextEncoder()\n try {\n for (let s = 0; s < st.scans.length; s++) {\n if (sectionSplices[s].length === 0) continue\n // 텍스트가 바뀐 섹션은 줄 레이아웃 캐시(linesegarray)를 전부 비워 한컴 변조\n // 경고·구버전 줄배치 렌더를 막는다 (patchHwpx와 동일 — 뷰어가 열 때 재계산)\n sectionSplices[s].push(...allLinesegRemovalSplices(st.scans[s].xml))\n replacements.set(st.sectionPaths[s], encoder.encode(applySplices(st.scans[s].xml, sectionSplices[s])))\n }\n } catch (err) {\n return { success: false, applied: 0, skipped, error: `소스맵 splice 실패: ${err instanceof Error ? err.message : String(err)}` }\n }\n\n if (replacements.size === 0) {\n // 무변경 — patchHwpx와 결과 형태를 맞추기 위해 changes(전부 unchanged)도 채운다\n let changes: DiffResult | undefined\n if (options?.verify !== false) {\n const units = splitMarkdownUnits(st.markdown)\n changes = diffUnitLists(units, units)\n }\n return { success: true, data: new Uint8Array(st.bytes), applied, skipped, changes }\n }\n\n let data: Uint8Array\n try {\n data = patchZipEntries(st.bytes, replacements)\n } catch (err) {\n return { success: false, applied: 0, skipped, error: `ZIP 재조립 실패: ${err instanceof Error ? err.message : String(err)}` }\n }\n\n // ── 상태 재구축 + 검증 ──\n const beforeMarkdown = st.markdown\n let newState: SessionState\n try {\n newState = await buildState(data)\n } catch (err) {\n // 세션은 이전 상태 유지 — 깨진 바이트를 노출하지 않는다\n return { success: false, applied, skipped, error: `패치본 재파싱 실패 — 패치 중단: ${err instanceof Error ? err.message : String(err)}` }\n }\n this.state = newState\n\n let changes: DiffResult | undefined\n if (options?.verify !== false) {\n changes = diffUnitLists(splitMarkdownUnits(beforeMarkdown), splitMarkdownUnits(newState.markdown))\n }\n\n // 반환 버퍼는 내부 상태와 분리 (호출자 변조가 후속 패치를 오염시키지 않도록)\n return { success: true, data: new Uint8Array(data), applied, skipped, changes }\n }\n\n /** 문단/헤딩 평문 편집 — patcher.patchParagraphUnit의 평문 입력 버전 */\n private patchParagraphPlain(\n blockIndex: number, block: IRBlock, newTextRaw: string,\n sectionSplices: SpliceEdit[][], skipped: PatchSkip[],\n ): number {\n const skip = (reason: string) => {\n skipped.push({ reason, before: summarize(block.text ?? \"\"), after: summarize(newTextRaw) })\n return 0\n }\n const st = this.state\n\n // 무변경 — 조용히 통과\n if (newTextRaw === (block.text ?? \"\")) return 0\n\n if (st.fragmentBlocks.has(blockIndex)) {\n return skip(\"문단 분절(강제 줄바꿈/병합 유닛) — 부분 수정은 미지원 (v1)\")\n }\n if (block.text && block.text.includes(\"\\n\")) {\n return skip(\"문단 내 강제 줄바꿈 포함 — 수정 시 줄바꿈 보존 불가로 미지원 (v1)\")\n }\n const mapping = st.paraMap.get(blockIndex)\n if (!mapping?.para) {\n return skip(\"문단 소스맵 매핑 실패 (머리말/글상자/캡션 영역이거나 텍스트 불일치)\")\n }\n\n // 여러 줄 입력은 한 문단으로 (마크다운 soft-wrap과 동일 규칙)\n let newPlain = newTextRaw.split(\"\\n\").map(l => l.trim()).filter(Boolean).join(\" \")\n\n // 각주·미주 참조 부호 — 개체가 그리는 글이라 hp:t 에 쓰지 않는다 (patcher 와 동일 규칙)\n if (mapping.noteMarks?.length) {\n const r = removeNoteMarks(newPlain, mapping.noteMarks)\n newPlain = r.text\n if (r.missing.length) skipped.push({ reason: \"각주 참조 부호 삭제는 미지원 — 각주 유지, 본문만 적용\", before: r.missing.join(\" \") })\n }\n\n // 자동번호 접두 — XML에 없는 텍스트이므로 떼고 기록 (patcher와 동일 규칙)\n if (mapping.prefixStripped) {\n const origPrefix = block.text!.split(\" \", 1)[0]\n const sp = newPlain.indexOf(\" \")\n const newFirst = sp > 0 ? newPlain.slice(0, sp) : newPlain\n if (newFirst === origPrefix || AUTONUM_PREFIX_RE.test(newFirst)) {\n newPlain = sp > 0 ? newPlain.slice(sp + 1) : \"\"\n } else {\n skipped.push({ reason: \"자동번호 접두 식별 실패 — 번호 포함 텍스트로 적용 (뷰어에서 중복 표시 가능)\", after: summarize(newPlain) })\n }\n }\n\n // 빈 문자열 비우기 — 재파싱 시 블록이 사라져 핸들이 영구 소실되고,\n // patchHwpx는 같은 의도(유닛 삭제)를 \"블록 삭제 미지원\"으로 skip하므로\n // 동등성을 위해 세션도 동일하게 거부한다\n if (newPlain === \"\") {\n return skip(\"블록 비우기/삭제는 미지원 (v1) — 원본 유지\")\n }\n\n // 기록 후 재파싱 sanitize에서 변형되는 텍스트는 무손실 약속이 깨짐\n if (sanitizeText(newPlain) !== newPlain) {\n return skip(\"공백 정규화 불안정 텍스트 — 패치 시 원문 보존 불가로 미지원\")\n }\n\n const splices = buildParagraphSplices(mapping.para, newPlain, st.scans[mapping.para.sectionIndex]?.xml)\n if (splices === null) return skip(\"문단에 텍스트 노드를 만들 수 없음\")\n sectionSplices[mapping.para.sectionIndex].push(...splices)\n return 1\n }\n}\n\n/** 셀 정적 편집 가능성 — table-patch applyCellEdit의 정적 게이트 사전 판정 */\nfunction cellStaticCheck(table: IRTable, scanTable: ScanTable, r: number, c: number): CellCapability {\n const irCell = table.cells[r]?.[c]\n if (!irCell) return { editable: false, reason: \"셀 좌표 범위 밖\" }\n\n const cell = scanTable.cellByAnchor.get(`${r},${c}`)\n if (!cell) return { editable: false, reason: \"병합 영역의 빈 칸이거나 좌표 불일치\" }\n\n // 스캔 문단 합산 ↔ IR 셀 텍스트 정규화 일치 (applyCellEdit와 동일 게이트)\n const scanJoined = cell.paragraphs.map(p => p.text).filter(t => normForMatch(t)).join(\"\\n\")\n if (normForMatch(scanJoined) !== normForMatch(stripCellTokens(irCell.text))) {\n if (normForMatch(irCell.text) !== \"\" || normForMatch(scanJoined) !== \"\") {\n const flatBlocks = (irCell.blocks ?? []).filter(b => b.type === \"paragraph\" || b.type === \"heading\")\n const flatJoined = flatBlocks.map(b => b.text ?? \"\").join(\"\\n\")\n if (normForMatch(scanJoined) !== normForMatch(flatJoined)) {\n return { editable: false, reason: \"셀 콘텐츠 구조 복잡 (중첩표/글상자) — 매핑 신뢰 불가\" }\n }\n }\n }\n\n const nonEmpty = cell.paragraphs.filter(p => normForMatch(p.text) !== \"\")\n if (nonEmpty.length === 0) {\n // 빈 셀 — 삽입 가능한 문단이 있어야 채울 수 있음\n if (cell.paragraphs.length === 0) {\n return { editable: false, reason: \"빈 셀에 문단이 없어 텍스트 삽입 불가\" }\n }\n return { editable: true }\n }\n const lines = irCellLines(irCell.text)\n if (lines.length !== nonEmpty.length) {\n return { editable: false, reason: \"셀 줄 경계 매핑 모호 (리터럴 <br>/문단 내 줄바꿈) — 미지원\" }\n }\n return { editable: true }\n}\n\n// ─── 편의 API ────────────────────────────────────────\n\n/** HWPX 문서 세션 열기 */\nexport async function openHwpxDocument(input: Uint8Array | ArrayBuffer): Promise<HwpxSession> {\n return HwpxSession.open(input)\n}\n\n/** 원샷 블록 패치 — 세션 없이 한 번에 (stateless RPC용) */\nexport async function patchHwpxBlocks(\n original: Uint8Array | ArrayBuffer,\n edits: BlockEdit[],\n options?: PatchOptions,\n): Promise<PatchResult> {\n const session = await HwpxSession.open(original)\n return session.patchBlocks(edits, options)\n}\n"],"mappings":"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;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAChH;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ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AA;AAAA;AAAA;AAAA;AAAA,IAKpB,KAAK;AAAQ,aAAO;AAAA;AAAA,IACpB,KAAK;AAAQ,aAAO;AAAA;AAAA,IACpB,KAAK;AAAQ,aAAO;AAAA;AAAA,IACpB,KAAK;AAAQ,aAAO;AAAA;AAAA,IACpB,KAAK;AAAQ,aAAO;AAAA;AAAA,IACpB,KAAK;AAAQ,aAAO;AAAA;AAAA,IACpB,KAAK;AAAQ,aAAO;AAAA;AAAA,IACpB,KAAK;AAAQ,aAAO;AAAA;AAAA,IACpB,KAAK;AAAQ,aAAO;AAAA;AAAA,IACpB,KAAK;AAAQ,aAAO;AAAA;AAAA,IACpB,KAAK;AAAQ,aAAO;AAAA;AAAA,IACpB,KAAK;AAAQ,aAAO;AAAA;AAAA,IACpB,KAAK;AAAQ,aAAO;AAAA;AAAA,IACpB,KAAK;AAAQ,aAAO;AAAA;AAAA,IACpB,KAAK;AAAQ,aAAO;AAAA;AAAA;AAAA;AAAA,IAGpB,KAAK;AAAQ,aAAO;AAAA;AAAA,IACpB,KAAK;AAAQ,aAAO;AAAA;AAAA,IACpB,KAAK;AAAQ,aAAO;AAAA;AAAA,IACpB,KAAK;AAAQ,aAAO;AAAA;AAAA,IACpB,KAAK;AAAQ,aAAO;AAAA;AAAA,IACpB,KAAK;AAAQ,aAAO;AAAA;AAAA,IACpB,KAAK;AAAQ,aAAO;AAAA;AAAA,IACpB,KAAK;AAAQ,aAAO;AAAA;AAAA,IACpB,KAAK;AAAQ,aAAO;AAAA;AAAA,IACpB,KAAK;AAAQ,aAAO;AAAA;AAAA;AAAA,IAEpB,KAAK;AAAQ,aAAO;AAAA;AAAA,IACpB,KAAK;AAAQ,aAAO;AAAA;AAAA,IACpB,KAAK;AAAQ,aAAO;AAAA;AAAA,IACpB,KAAK;AAAQ,aAAO;AAAA;AAAA,IACpB,KAAK;AAAQ,aAAO;AAAA;AAAA,IACpB,KAAK;AAAQ,aAAO;AAAA;AAAA,IACpB,KAAK;AAAQ,aAAO;AAAA;AAAA,IACpB,KAAK;AAAQ,aAAO;AAAA;AAAA,IACpB,KAAK;AAAQ,aAAO;AAAA;AAAA,IACpB,KAAK;AAAQ,aAAO;AAAA;AAAA,IACpB,KAAK;AAAQ,aAAO;AAAA;AAAA,IACpB,KAAK;AAAQ,aAAO;AAAA;AAAA,IACpB,KAAK;AAAQ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","names":["readFile","JSZip","para","plain","table","anchors","cell","localName","tbl","tc","num","pick","para","cell","depth","findDescendant","tbl","t","para","cell","filename","inflateRawSync","inflateRawSync","cell","JSZip","warnings","inflateRawSync","cell","createDecipheriv","inflateRawSync","createDecipheriv","inflateRawSync","MAX_DECOMPRESS_SIZE","inflateRawSync","msg","para","num","cell","table","JSZip","MAX_DECOMPRESS_SIZE","MAX_ROWS","MAX_COLS","num","cell","table","JSZip","parsePageRange","data","num","MAX_SHEETS","MAX_ROWS","MAX_COLS","sheetToBlocks","table","parsePageRange","JSZip","DOMParser","num","MAX_DECOMPRESS_SIZE","localName","parseXml","DOMParser","parseRels","tbl","tc","cell","table","JSZip","DOMParser","DOMParser","msg","parseParagraph","parseTable","table","cell","collectCellText","table","cell","norm","table","cell","JSZip","JSZip","attrOf","JSZip","JSZip","cell","collectTables","table","para","newValue","cell","table","semantic","nonTabular","table","cell","JSZip","num","trailing","base","list","langs","tbl","host","collected","result","i","j","table","_","cell","cell","cell","sum","scale","isLabelCell","tbl","nested","table","table","num","cid","marker","tbl","plain","norm","lm","r","charPr","height","blank","blank","cell","plain","textW","paraId","before","tbl","blocks","staticBfEnd","remap","bfReg","chartParts","supplied","images","zip","JSZip","i","j","JSZip","tbl","parseTable","tc","cell","table","JSZip","table","plain","JSZip","table","cell","table","cell","cell","tbl","JSZip","para","pick","require","para","j","table","pick","cell","newHeader","cs","JSZip","DOMParser","msg","JSZip","u8ToArrayBuffer","JSZip","para","table","changes","cell","msg","cell","readFile"]}
|