@clazic/kordoc 2.2.4 → 2.2.6
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/dist/{chunk-FRUOLYOA.js → chunk-BU42ZFTN.js} +2 -2
- package/dist/{chunk-RY4EXD2W.js → chunk-KHUTUB7G.js} +3 -3
- package/dist/cli.js +5 -5
- package/dist/index.cjs +17 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +17 -7
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +2 -2
- package/dist/{resolve-C5F2MXLL.js → resolve-77C5OWLO.js} +17 -7
- package/dist/resolve-77C5OWLO.js.map +1 -0
- package/dist/{utils-HOTLMIQL.js → utils-PGXOUDRW.js} +2 -2
- package/dist/{watch-E2YLCDHY.js → watch-VDBYOMEJ.js} +3 -3
- package/package.json +1 -1
- package/dist/resolve-C5F2MXLL.js.map +0 -1
- /package/dist/{chunk-FRUOLYOA.js.map → chunk-BU42ZFTN.js.map} +0 -0
- /package/dist/{chunk-RY4EXD2W.js.map → chunk-KHUTUB7G.js.map} +0 -0
- /package/dist/{utils-HOTLMIQL.js.map → utils-PGXOUDRW.js.map} +0 -0
- /package/dist/{watch-E2YLCDHY.js.map → watch-VDBYOMEJ.js.map} +0 -0
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/page-range.ts","../node_modules/cfb/cfb.js","../src/ocr/auto-detect.ts","../src/ocr/cli-provider.ts","../src/ocr/tesseract-provider.ts","../src/ocr/resolve.ts","../src/ocr/markdown-to-blocks.ts","../src/ocr/provider.ts","../src/index.ts","../src/detect.ts","../src/hwpx/parser.ts","../src/utils.ts","../src/table/builder.ts","../src/types.ts","../src/hwp5/record.ts","../src/hwp5/aes.ts","../src/hwp5/crypto.ts","../src/hwp5/cfb-lenient.ts","../src/hwp5/parser.ts","../src/pdf/parser.ts","../src/pdf/line-detector.ts","../src/pdf/cluster-detector.ts","../src/pdf/polyfill.ts","../src/xlsx/parser.ts","../src/docx/parser.ts","../src/diff/text-diff.ts","../src/diff/compare.ts","../src/form/recognize.ts","../src/hwpx/generator.ts","../src/hwpx/template-content.ts","../src/hwpx/template-analyzer.ts","../src/hwpx/style-matcher.ts","../src/xlsx/generator.ts"],"sourcesContent":["/** 페이지/섹션 범위 파싱 유틸리티 */\n\n/**\n * 페이지 범위 지정을 1-based Set<number>로 변환.\n *\n * @param spec - [1,2,3] 또는 \"1-3\" 또는 \"1,3,5-7\"\n * @param maxPages - 최대 페이지 수 (클램핑 상한)\n * @returns 1-based 페이지 번호 Set\n */\nexport function parsePageRange(spec: number[] | string, maxPages: number): Set<number> {\n const result = new Set<number>()\n if (maxPages <= 0) return result\n\n if (Array.isArray(spec)) {\n for (const n of spec) {\n const page = Math.round(n)\n if (page >= 1 && page <= maxPages) result.add(page)\n }\n return result\n }\n\n if (typeof spec !== \"string\" || spec.trim() === \"\") return result\n\n const parts = spec.split(\",\")\n for (const part of parts) {\n const trimmed = part.trim()\n if (!trimmed) continue\n\n const rangeMatch = trimmed.match(/^(\\d+)\\s*-\\s*(\\d+)$/)\n if (rangeMatch) {\n const start = Math.max(1, parseInt(rangeMatch[1], 10))\n const end = Math.min(maxPages, parseInt(rangeMatch[2], 10))\n for (let i = start; i <= end; i++) result.add(i)\n } else {\n const page = parseInt(trimmed, 10)\n if (!isNaN(page) && page >= 1 && page <= maxPages) result.add(page)\n }\n }\n\n return result\n}\n","/* cfb.js (C) 2013-present SheetJS -- http://sheetjs.com */\n/* vim: set ts=2: */\n/*jshint eqnull:true */\n/*exported CFB */\n/*global module, require:false, process:false, Buffer:false, Uint8Array:false, Uint16Array:false */\n\nvar Base64_map = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\";\nfunction Base64_encode(input) {\n\tvar o = \"\";\n\tvar c1 = 0, c2 = 0, c3 = 0, e1 = 0, e2 = 0, e3 = 0, e4 = 0;\n\tfor (var i = 0; i < input.length; ) {\n\t\tc1 = input.charCodeAt(i++);\n\t\te1 = (c1 >> 2);\n\t\tc2 = input.charCodeAt(i++);\n\t\te2 = ((c1 & 3) << 4) | (c2 >> 4);\n\t\tc3 = input.charCodeAt(i++);\n\t\te3 = ((c2 & 15) << 2) | (c3 >> 6);\n\t\te4 = (c3 & 63);\n\t\tif (isNaN(c2)) e3 = e4 = 64;\n\t\telse if (isNaN(c3)) e4 = 64;\n\t\to += Base64_map.charAt(e1) + Base64_map.charAt(e2) + Base64_map.charAt(e3) + Base64_map.charAt(e4);\n\t}\n\treturn o;\n}\nfunction Base64_decode(input) {\n\tvar o = \"\";\n\tvar c1 = 0, c2 = 0, c3 = 0, e1 = 0, e2 = 0, e3 = 0, e4 = 0;\n\tinput = input.replace(/[^\\w\\+\\/\\=]/g, \"\");\n\tfor (var i = 0; i < input.length;) {\n\t\te1 = Base64_map.indexOf(input.charAt(i++));\n\t\te2 = Base64_map.indexOf(input.charAt(i++));\n\t\tc1 = (e1 << 2) | (e2 >> 4);\n\t\to += String.fromCharCode(c1);\n\t\te3 = Base64_map.indexOf(input.charAt(i++));\n\t\tc2 = ((e2 & 15) << 4) | (e3 >> 2);\n\t\tif (e3 !== 64) o += String.fromCharCode(c2);\n\t\te4 = Base64_map.indexOf(input.charAt(i++));\n\t\tc3 = ((e3 & 3) << 6) | e4;\n\t\tif (e4 !== 64) o += String.fromCharCode(c3);\n\t}\n\treturn o;\n}\nvar has_buf = (function() { return typeof Buffer !== 'undefined' && typeof process !== 'undefined' && typeof process.versions !== 'undefined' && !!process.versions.node; })();\n\nvar Buffer_from = (function() {\n\tif(typeof Buffer !== 'undefined') {\n\t\tvar nbfs = !Buffer.from;\n\t\tif(!nbfs) try { Buffer.from(\"foo\", \"utf8\"); } catch(e) { nbfs = true; }\n\t\treturn nbfs ? function(buf, enc) { return (enc) ? new Buffer(buf, enc) : new Buffer(buf); } : Buffer.from.bind(Buffer);\n\t}\n\treturn function() {};\n})();\n\n\nfunction new_raw_buf(len) {\n\t/* jshint -W056 */\n\tif(has_buf) {\n\t\tif(Buffer.alloc) return Buffer.alloc(len);\n\t\tvar b = new Buffer(len); b.fill(0); return b;\n\t}\n\treturn typeof Uint8Array != \"undefined\" ? new Uint8Array(len) : new Array(len);\n\t/* jshint +W056 */\n}\n\nfunction new_unsafe_buf(len) {\n\t/* jshint -W056 */\n\tif(has_buf) return Buffer.allocUnsafe ? Buffer.allocUnsafe(len) : new Buffer(len);\n\treturn typeof Uint8Array != \"undefined\" ? new Uint8Array(len) : new Array(len);\n\t/* jshint +W056 */\n}\n\nvar s2a = function s2a(s) {\n\tif(has_buf) return Buffer_from(s, \"binary\");\n\treturn s.split(\"\").map(function(x){ return x.charCodeAt(0) & 0xff; });\n};\n\nvar chr0 = /\\u0000/g, chr1 = /[\\u0001-\\u0006]/g;\nvar __toBuffer = function(bufs) { var x = []; for(var i = 0; i < bufs[0].length; ++i) { x.push.apply(x, bufs[0][i]); } return x; };\nvar ___toBuffer = __toBuffer;\nvar __utf16le = function(b,s,e) { var ss=[]; for(var i=s; i<e; i+=2) ss.push(String.fromCharCode(__readUInt16LE(b,i))); return ss.join(\"\").replace(chr0,''); };\nvar ___utf16le = __utf16le;\nvar __hexlify = function(b,s,l) { var ss=[]; for(var i=s; i<s+l; ++i) ss.push((\"0\" + b[i].toString(16)).slice(-2)); return ss.join(\"\"); };\nvar ___hexlify = __hexlify;\nvar __bconcat = function(bufs) {\n\tif(Array.isArray(bufs[0])) return [].concat.apply([], bufs);\n\tvar maxlen = 0, i = 0;\n\tfor(i = 0; i < bufs.length; ++i) maxlen += bufs[i].length;\n\tvar o = new Uint8Array(maxlen);\n\tfor(i = 0, maxlen = 0; i < bufs.length; maxlen += bufs[i].length, ++i) o.set(bufs[i], maxlen);\n\treturn o;\n};\nvar bconcat = __bconcat;\n\n\nif(has_buf) {\n\t__utf16le = function(b,s,e) {\n\t\tif(!Buffer.isBuffer(b)) return ___utf16le(b,s,e);\n\t\treturn b.toString('utf16le',s,e).replace(chr0,'')/*.replace(chr1,'!')*/;\n\t};\n\t__hexlify = function(b,s,l) { return Buffer.isBuffer(b) ? b.toString('hex',s,s+l) : ___hexlify(b,s,l); };\n\t__toBuffer = function(bufs) { return (bufs[0].length > 0 && Buffer.isBuffer(bufs[0][0])) ? Buffer.concat((bufs[0])) : ___toBuffer(bufs);};\n\ts2a = function(s) { return Buffer_from(s, \"binary\"); };\n\tbconcat = function(bufs) { return Buffer.isBuffer(bufs[0]) ? Buffer.concat(bufs) : __bconcat(bufs); };\n}\n\n\nvar __readUInt8 = function(b, idx) { return b[idx]; };\nvar __readUInt16LE = function(b, idx) { return b[idx+1]*(1<<8)+b[idx]; };\nvar __readInt16LE = function(b, idx) { var u = b[idx+1]*(1<<8)+b[idx]; return (u < 0x8000) ? u : (0xffff - u + 1) * -1; };\nvar __readUInt32LE = function(b, idx) { return b[idx+3]*(1<<24)+(b[idx+2]<<16)+(b[idx+1]<<8)+b[idx]; };\nvar __readInt32LE = function(b, idx) { return (b[idx+3]<<24)+(b[idx+2]<<16)+(b[idx+1]<<8)+b[idx]; };\n\nfunction ReadShift(size, t) {\n\tvar oI, oS, type = 0;\n\tswitch(size) {\n\t\tcase 1: oI = __readUInt8(this, this.l); break;\n\t\tcase 2: oI = (t !== 'i' ? __readUInt16LE : __readInt16LE)(this, this.l); break;\n\t\tcase 4: oI = __readInt32LE(this, this.l); break;\n\t\tcase 16: type = 2; oS = __hexlify(this, this.l, size);\n\t}\n\tthis.l += size; if(type === 0) return oI; return oS;\n}\n\nvar __writeUInt32LE = function(b, val, idx) { b[idx] = (val & 0xFF); b[idx+1] = ((val >>> 8) & 0xFF); b[idx+2] = ((val >>> 16) & 0xFF); b[idx+3] = ((val >>> 24) & 0xFF); };\nvar __writeInt32LE = function(b, val, idx) { b[idx] = (val & 0xFF); b[idx+1] = ((val >> 8) & 0xFF); b[idx+2] = ((val >> 16) & 0xFF); b[idx+3] = ((val >> 24) & 0xFF); };\n\nfunction WriteShift(t, val, f) {\n\tvar size = 0, i = 0;\n\tswitch(f) {\n\t\tcase \"hex\": for(; i < t; ++i) {\nthis[this.l++] = parseInt(val.slice(2*i, 2*i+2), 16)||0;\n\t\t} return this;\n\t\tcase \"utf16le\":\nvar end = this.l + t;\n\t\t\tfor(i = 0; i < Math.min(val.length, t); ++i) {\n\t\t\t\tvar cc = val.charCodeAt(i);\n\t\t\t\tthis[this.l++] = cc & 0xff;\n\t\t\t\tthis[this.l++] = cc >> 8;\n\t\t\t}\n\t\t\twhile(this.l < end) this[this.l++] = 0;\n\t\t\treturn this;\n\t}\nswitch(t) {\n\t\tcase 1: size = 1; this[this.l] = val&0xFF; break;\n\t\tcase 2: size = 2; this[this.l] = val&0xFF; val >>>= 8; this[this.l+1] = val&0xFF; break;\n\t\tcase 4: size = 4; __writeUInt32LE(this, val, this.l); break;\n\t\tcase -4: size = 4; __writeInt32LE(this, val, this.l); break;\n\t}\n\tthis.l += size; return this;\n}\n\nfunction CheckField(hexstr, fld) {\n\tvar m = __hexlify(this,this.l,hexstr.length>>1);\n\tif(m !== hexstr) throw new Error(fld + 'Expected ' + hexstr + ' saw ' + m);\n\tthis.l += hexstr.length>>1;\n}\n\nfunction prep_blob(blob, pos) {\n\tblob.l = pos;\n\tblob.read_shift = ReadShift;\n\tblob.chk = CheckField;\n\tblob.write_shift = WriteShift;\n}\n\nfunction new_buf(sz) {\n\tvar o = (new_raw_buf(sz));\n\tprep_blob(o, 0);\n\treturn o;\n}\n\n/*! crc32.js (C) 2014-present SheetJS -- http://sheetjs.com */\n/* vim: set ts=2: */\n/*exported CRC32 */\nvar CRC32 = (function() {\nvar CRC32 = {};\nCRC32.version = '1.2.1';\n/*global Int32Array */\nfunction signed_crc_table() {\n\tvar c = 0, table = new Array(256);\n\n\tfor(var n =0; n != 256; ++n){\n\t\tc = n;\n\t\tc = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));\n\t\tc = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));\n\t\tc = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));\n\t\tc = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));\n\t\tc = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));\n\t\tc = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));\n\t\tc = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));\n\t\tc = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));\n\t\ttable[n] = c;\n\t}\n\n\treturn typeof Int32Array !== 'undefined' ? new Int32Array(table) : table;\n}\n\nvar T0 = signed_crc_table();\nfunction slice_by_16_tables(T) {\n\tvar c = 0, v = 0, n = 0, table = typeof Int32Array !== 'undefined' ? new Int32Array(4096) : new Array(4096) ;\n\n\tfor(n = 0; n != 256; ++n) table[n] = T[n];\n\tfor(n = 0; n != 256; ++n) {\n\t\tv = T[n];\n\t\tfor(c = 256 + n; c < 4096; c += 256) v = table[c] = (v >>> 8) ^ T[v & 0xFF];\n\t}\n\tvar out = [];\n\tfor(n = 1; n != 16; ++n) out[n - 1] = typeof Int32Array !== 'undefined' ? table.subarray(n * 256, n * 256 + 256) : table.slice(n * 256, n * 256 + 256);\n\treturn out;\n}\nvar TT = slice_by_16_tables(T0);\nvar T1 = TT[0], T2 = TT[1], T3 = TT[2], T4 = TT[3], T5 = TT[4];\nvar T6 = TT[5], T7 = TT[6], T8 = TT[7], T9 = TT[8], Ta = TT[9];\nvar Tb = TT[10], Tc = TT[11], Td = TT[12], Te = TT[13], Tf = TT[14];\nfunction crc32_bstr(bstr, seed) {\n\tvar C = seed ^ -1;\n\tfor(var i = 0, L = bstr.length; i < L;) C = (C>>>8) ^ T0[(C^bstr.charCodeAt(i++))&0xFF];\n\treturn ~C;\n}\n\nfunction crc32_buf(B, seed) {\n\tvar C = seed ^ -1, L = B.length - 15, i = 0;\n\tfor(; i < L;) C =\n\t\tTf[B[i++] ^ (C & 255)] ^\n\t\tTe[B[i++] ^ ((C >> 8) & 255)] ^\n\t\tTd[B[i++] ^ ((C >> 16) & 255)] ^\n\t\tTc[B[i++] ^ (C >>> 24)] ^\n\t\tTb[B[i++]] ^ Ta[B[i++]] ^ T9[B[i++]] ^ T8[B[i++]] ^\n\t\tT7[B[i++]] ^ T6[B[i++]] ^ T5[B[i++]] ^ T4[B[i++]] ^\n\t\tT3[B[i++]] ^ T2[B[i++]] ^ T1[B[i++]] ^ T0[B[i++]];\n\tL += 15;\n\twhile(i < L) C = (C>>>8) ^ T0[(C^B[i++])&0xFF];\n\treturn ~C;\n}\n\nfunction crc32_str(str, seed) {\n\tvar C = seed ^ -1;\n\tfor(var i = 0, L = str.length, c = 0, d = 0; i < L;) {\n\t\tc = str.charCodeAt(i++);\n\t\tif(c < 0x80) {\n\t\t\tC = (C>>>8) ^ T0[(C^c)&0xFF];\n\t\t} else if(c < 0x800) {\n\t\t\tC = (C>>>8) ^ T0[(C ^ (192|((c>>6)&31)))&0xFF];\n\t\t\tC = (C>>>8) ^ T0[(C ^ (128|(c&63)))&0xFF];\n\t\t} else if(c >= 0xD800 && c < 0xE000) {\n\t\t\tc = (c&1023)+64; d = str.charCodeAt(i++)&1023;\n\t\t\tC = (C>>>8) ^ T0[(C ^ (240|((c>>8)&7)))&0xFF];\n\t\t\tC = (C>>>8) ^ T0[(C ^ (128|((c>>2)&63)))&0xFF];\n\t\t\tC = (C>>>8) ^ T0[(C ^ (128|((d>>6)&15)|((c&3)<<4)))&0xFF];\n\t\t\tC = (C>>>8) ^ T0[(C ^ (128|(d&63)))&0xFF];\n\t\t} else {\n\t\t\tC = (C>>>8) ^ T0[(C ^ (224|((c>>12)&15)))&0xFF];\n\t\t\tC = (C>>>8) ^ T0[(C ^ (128|((c>>6)&63)))&0xFF];\n\t\t\tC = (C>>>8) ^ T0[(C ^ (128|(c&63)))&0xFF];\n\t\t}\n\t}\n\treturn ~C;\n}\nCRC32.table = T0;\nCRC32.bstr = crc32_bstr;\nCRC32.buf = crc32_buf;\nCRC32.str = crc32_str;\nreturn CRC32;\n})();\n/* [MS-CFB] v20171201 */\nvar CFB = (function _CFB(){\nvar exports = {};\nexports.version = '1.2.2';\n/* [MS-CFB] 2.6.4 */\nfunction namecmp(l, r) {\n\tvar L = l.split(\"/\"), R = r.split(\"/\");\n\tfor(var i = 0, c = 0, Z = Math.min(L.length, R.length); i < Z; ++i) {\n\t\tif((c = L[i].length - R[i].length)) return c;\n\t\tif(L[i] != R[i]) return L[i] < R[i] ? -1 : 1;\n\t}\n\treturn L.length - R.length;\n}\nfunction dirname(p) {\n\tif(p.charAt(p.length - 1) == \"/\") return (p.slice(0,-1).indexOf(\"/\") === -1) ? p : dirname(p.slice(0, -1));\n\tvar c = p.lastIndexOf(\"/\");\n\treturn (c === -1) ? p : p.slice(0, c+1);\n}\n\nfunction filename(p) {\n\tif(p.charAt(p.length - 1) == \"/\") return filename(p.slice(0, -1));\n\tvar c = p.lastIndexOf(\"/\");\n\treturn (c === -1) ? p : p.slice(c+1);\n}\n/* -------------------------------------------------------------------------- */\n/* DOS Date format:\n high|YYYYYYYm.mmmddddd.HHHHHMMM.MMMSSSSS|low\n add 1980 to stored year\n stored second should be doubled\n*/\n\n/* write JS date to buf as a DOS date */\nfunction write_dos_date(buf, date) {\n\tif(typeof date === \"string\") date = new Date(date);\n\tvar hms = date.getHours();\n\thms = hms << 6 | date.getMinutes();\n\thms = hms << 5 | (date.getSeconds()>>>1);\n\tbuf.write_shift(2, hms);\n\tvar ymd = (date.getFullYear() - 1980);\n\tymd = ymd << 4 | (date.getMonth()+1);\n\tymd = ymd << 5 | date.getDate();\n\tbuf.write_shift(2, ymd);\n}\n\n/* read four bytes from buf and interpret as a DOS date */\nfunction parse_dos_date(buf) {\n\tvar hms = buf.read_shift(2) & 0xFFFF;\n\tvar ymd = buf.read_shift(2) & 0xFFFF;\n\tvar val = new Date();\n\tvar d = ymd & 0x1F; ymd >>>= 5;\n\tvar m = ymd & 0x0F; ymd >>>= 4;\n\tval.setMilliseconds(0);\n\tval.setFullYear(ymd + 1980);\n\tval.setMonth(m-1);\n\tval.setDate(d);\n\tvar S = hms & 0x1F; hms >>>= 5;\n\tvar M = hms & 0x3F; hms >>>= 6;\n\tval.setHours(hms);\n\tval.setMinutes(M);\n\tval.setSeconds(S<<1);\n\treturn val;\n}\nfunction parse_extra_field(blob) {\n\tprep_blob(blob, 0);\n\tvar o = {};\n\tvar flags = 0;\n\twhile(blob.l <= blob.length - 4) {\n\t\tvar type = blob.read_shift(2);\n\t\tvar sz = blob.read_shift(2), tgt = blob.l + sz;\n\t\tvar p = {};\n\t\tswitch(type) {\n\t\t\t/* UNIX-style Timestamps */\n\t\t\tcase 0x5455: {\n\t\t\t\tflags = blob.read_shift(1);\n\t\t\t\tif(flags & 1) p.mtime = blob.read_shift(4);\n\t\t\t\t/* for some reason, CD flag corresponds to LFH */\n\t\t\t\tif(sz > 5) {\n\t\t\t\t\tif(flags & 2) p.atime = blob.read_shift(4);\n\t\t\t\t\tif(flags & 4) p.ctime = blob.read_shift(4);\n\t\t\t\t}\n\t\t\t\tif(p.mtime) p.mt = new Date(p.mtime*1000);\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tblob.l = tgt;\n\t\to[type] = p;\n\t}\n\treturn o;\n}\nvar fs;\nfunction get_fs() { return fs || (fs = require('fs')); }\nfunction parse(file, options) {\nif(file[0] == 0x50 && file[1] == 0x4b) return parse_zip(file, options);\nif((file[0] | 0x20) == 0x6d && (file[1]|0x20) == 0x69) return parse_mad(file, options);\nif(file.length < 512) throw new Error(\"CFB file size \" + file.length + \" < 512\");\nvar mver = 3;\nvar ssz = 512;\nvar nmfs = 0; // number of mini FAT sectors\nvar difat_sec_cnt = 0;\nvar dir_start = 0;\nvar minifat_start = 0;\nvar difat_start = 0;\n\nvar fat_addrs = []; // locations of FAT sectors\n\n/* [MS-CFB] 2.2 Compound File Header */\nvar blob = file.slice(0,512);\nprep_blob(blob, 0);\n\n/* major version */\nvar mv = check_get_mver(blob);\nmver = mv[0];\nswitch(mver) {\n\tcase 3: ssz = 512; break; case 4: ssz = 4096; break;\n\tcase 0: if(mv[1] == 0) return parse_zip(file, options);\n\t/* falls through */\n\tdefault: throw new Error(\"Major Version: Expected 3 or 4 saw \" + mver);\n}\n\n/* reprocess header */\nif(ssz !== 512) { blob = file.slice(0,ssz); prep_blob(blob, 28 /* blob.l */); }\n/* Save header for final object */\nvar header = file.slice(0,ssz);\n\ncheck_shifts(blob, mver);\n\n// Number of Directory Sectors\nvar dir_cnt = blob.read_shift(4, 'i');\nif(mver === 3 && dir_cnt !== 0) throw new Error('# Directory Sectors: Expected 0 saw ' + dir_cnt);\n\n// Number of FAT Sectors\nblob.l += 4;\n\n// First Directory Sector Location\ndir_start = blob.read_shift(4, 'i');\n\n// Transaction Signature\nblob.l += 4;\n\n// Mini Stream Cutoff Size\nblob.chk('00100000', 'Mini Stream Cutoff Size: ');\n\n// First Mini FAT Sector Location\nminifat_start = blob.read_shift(4, 'i');\n\n// Number of Mini FAT Sectors\nnmfs = blob.read_shift(4, 'i');\n\n// First DIFAT sector location\ndifat_start = blob.read_shift(4, 'i');\n\n// Number of DIFAT Sectors\ndifat_sec_cnt = blob.read_shift(4, 'i');\n\n// Grab FAT Sector Locations\nfor(var q = -1, j = 0; j < 109; ++j) { /* 109 = (512 - blob.l)>>>2; */\n\tq = blob.read_shift(4, 'i');\n\tif(q<0) break;\n\tfat_addrs[j] = q;\n}\n\n/** Break the file up into sectors */\nvar sectors = sectorify(file, ssz);\n\nsleuth_fat(difat_start, difat_sec_cnt, sectors, ssz, fat_addrs);\n\n/** Chains */\nvar sector_list = make_sector_list(sectors, dir_start, fat_addrs, ssz);\n\nsector_list[dir_start].name = \"!Directory\";\nif(nmfs > 0 && minifat_start !== ENDOFCHAIN) sector_list[minifat_start].name = \"!MiniFAT\";\nsector_list[fat_addrs[0]].name = \"!FAT\";\nsector_list.fat_addrs = fat_addrs;\nsector_list.ssz = ssz;\n\n/* [MS-CFB] 2.6.1 Compound File Directory Entry */\nvar files = {}, Paths = [], FileIndex = [], FullPaths = [];\nread_directory(dir_start, sector_list, sectors, Paths, nmfs, files, FileIndex, minifat_start);\n\nbuild_full_paths(FileIndex, FullPaths, Paths);\nPaths.shift();\n\nvar o = {\n\tFileIndex: FileIndex,\n\tFullPaths: FullPaths\n};\n\n// $FlowIgnore\nif(options && options.raw) o.raw = {header: header, sectors: sectors};\nreturn o;\n} // parse\n\n/* [MS-CFB] 2.2 Compound File Header -- read up to major version */\nfunction check_get_mver(blob) {\n\tif(blob[blob.l] == 0x50 && blob[blob.l + 1] == 0x4b) return [0, 0];\n\t// header signature 8\n\tblob.chk(HEADER_SIGNATURE, 'Header Signature: ');\n\n\t// clsid 16\n\t//blob.chk(HEADER_CLSID, 'CLSID: ');\n\tblob.l += 16;\n\n\t// minor version 2\n\tvar mver = blob.read_shift(2, 'u');\n\n\treturn [blob.read_shift(2,'u'), mver];\n}\nfunction check_shifts(blob, mver) {\n\tvar shift = 0x09;\n\n\t// Byte Order\n\t//blob.chk('feff', 'Byte Order: '); // note: some writers put 0xffff\n\tblob.l += 2;\n\n\t// Sector Shift\n\tswitch((shift = blob.read_shift(2))) {\n\t\tcase 0x09: if(mver != 3) throw new Error('Sector Shift: Expected 9 saw ' + shift); break;\n\t\tcase 0x0c: if(mver != 4) throw new Error('Sector Shift: Expected 12 saw ' + shift); break;\n\t\tdefault: throw new Error('Sector Shift: Expected 9 or 12 saw ' + shift);\n\t}\n\n\t// Mini Sector Shift\n\tblob.chk('0600', 'Mini Sector Shift: ');\n\n\t// Reserved\n\tblob.chk('000000000000', 'Reserved: ');\n}\n\n/** Break the file up into sectors */\nfunction sectorify(file, ssz) {\n\tvar nsectors = Math.ceil(file.length/ssz)-1;\n\tvar sectors = [];\n\tfor(var i=1; i < nsectors; ++i) sectors[i-1] = file.slice(i*ssz,(i+1)*ssz);\n\tsectors[nsectors-1] = file.slice(nsectors*ssz);\n\treturn sectors;\n}\n\n/* [MS-CFB] 2.6.4 Red-Black Tree */\nfunction build_full_paths(FI, FP, Paths) {\n\tvar i = 0, L = 0, R = 0, C = 0, j = 0, pl = Paths.length;\n\tvar dad = [], q = [];\n\n\tfor(; i < pl; ++i) { dad[i]=q[i]=i; FP[i]=Paths[i]; }\n\n\tfor(; j < q.length; ++j) {\n\t\ti = q[j];\n\t\tL = FI[i].L; R = FI[i].R; C = FI[i].C;\n\t\tif(dad[i] === i) {\n\t\t\tif(L !== -1 /*NOSTREAM*/ && dad[L] !== L) dad[i] = dad[L];\n\t\t\tif(R !== -1 && dad[R] !== R) dad[i] = dad[R];\n\t\t}\n\t\tif(C !== -1 /*NOSTREAM*/) dad[C] = i;\n\t\tif(L !== -1 && i != dad[i]) { dad[L] = dad[i]; if(q.lastIndexOf(L) < j) q.push(L); }\n\t\tif(R !== -1 && i != dad[i]) { dad[R] = dad[i]; if(q.lastIndexOf(R) < j) q.push(R); }\n\t}\n\tfor(i=1; i < pl; ++i) if(dad[i] === i) {\n\t\tif(R !== -1 /*NOSTREAM*/ && dad[R] !== R) dad[i] = dad[R];\n\t\telse if(L !== -1 && dad[L] !== L) dad[i] = dad[L];\n\t}\n\n\tfor(i=1; i < pl; ++i) {\n\t\tif(FI[i].type === 0 /* unknown */) continue;\n\t\tj = i;\n\t\tif(j != dad[j]) do {\n\t\t\tj = dad[j];\n\t\t\tFP[i] = FP[j] + \"/\" + FP[i];\n\t\t} while (j !== 0 && -1 !== dad[j] && j != dad[j]);\n\t\tdad[i] = -1;\n\t}\n\n\tFP[0] += \"/\";\n\tfor(i=1; i < pl; ++i) {\n\t\tif(FI[i].type !== 2 /* stream */) FP[i] += \"/\";\n\t}\n}\n\nfunction get_mfat_entry(entry, payload, mini) {\n\tvar start = entry.start, size = entry.size;\n\t//return (payload.slice(start*MSSZ, start*MSSZ + size));\n\tvar o = [];\n\tvar idx = start;\n\twhile(mini && size > 0 && idx >= 0) {\n\t\to.push(payload.slice(idx * MSSZ, idx * MSSZ + MSSZ));\n\t\tsize -= MSSZ;\n\t\tidx = __readInt32LE(mini, idx * 4);\n\t}\n\tif(o.length === 0) return (new_buf(0));\n\treturn (bconcat(o).slice(0, entry.size));\n}\n\n/** Chase down the rest of the DIFAT chain to build a comprehensive list\n DIFAT chains by storing the next sector number as the last 32 bits */\nfunction sleuth_fat(idx, cnt, sectors, ssz, fat_addrs) {\n\tvar q = ENDOFCHAIN;\n\tif(idx === ENDOFCHAIN) {\n\t\tif(cnt !== 0) throw new Error(\"DIFAT chain shorter than expected\");\n\t} else if(idx !== -1 /*FREESECT*/) {\n\t\tvar sector = sectors[idx], m = (ssz>>>2)-1;\n\t\tif(!sector) return;\n\t\tfor(var i = 0; i < m; ++i) {\n\t\t\tif((q = __readInt32LE(sector,i*4)) === ENDOFCHAIN) break;\n\t\t\tfat_addrs.push(q);\n\t\t}\n\t\tif(cnt >= 1) sleuth_fat(__readInt32LE(sector,ssz-4),cnt - 1, sectors, ssz, fat_addrs);\n\t}\n}\n\n/** Follow the linked list of sectors for a given starting point */\nfunction get_sector_list(sectors, start, fat_addrs, ssz, chkd) {\n\tvar buf = [], buf_chain = [];\n\tif(!chkd) chkd = [];\n\tvar modulus = ssz - 1, j = 0, jj = 0;\n\tfor(j=start; j>=0;) {\n\t\tchkd[j] = true;\n\t\tbuf[buf.length] = j;\n\t\tbuf_chain.push(sectors[j]);\n\t\tvar addr = fat_addrs[Math.floor(j*4/ssz)];\n\t\tjj = ((j*4) & modulus);\n\t\tif(ssz < 4 + jj) throw new Error(\"FAT boundary crossed: \" + j + \" 4 \"+ssz);\n\t\tif(!sectors[addr]) break;\n\t\tj = __readInt32LE(sectors[addr], jj);\n\t}\n\treturn {nodes: buf, data:__toBuffer([buf_chain])};\n}\n\n/** Chase down the sector linked lists */\nfunction make_sector_list(sectors, dir_start, fat_addrs, ssz) {\n\tvar sl = sectors.length, sector_list = ([]);\n\tvar chkd = [], buf = [], buf_chain = [];\n\tvar modulus = ssz - 1, i=0, j=0, k=0, jj=0;\n\tfor(i=0; i < sl; ++i) {\n\t\tbuf = ([]);\n\t\tk = (i + dir_start); if(k >= sl) k-=sl;\n\t\tif(chkd[k]) continue;\n\t\tbuf_chain = [];\n\t\tvar seen = [];\n\t\tfor(j=k; j>=0;) {\n\t\t\tseen[j] = true;\n\t\t\tchkd[j] = true;\n\t\t\tbuf[buf.length] = j;\n\t\t\tbuf_chain.push(sectors[j]);\n\t\t\tvar addr = fat_addrs[Math.floor(j*4/ssz)];\n\t\t\tjj = ((j*4) & modulus);\n\t\t\tif(ssz < 4 + jj) throw new Error(\"FAT boundary crossed: \" + j + \" 4 \"+ssz);\n\t\t\tif(!sectors[addr]) break;\n\t\t\tj = __readInt32LE(sectors[addr], jj);\n\t\t\tif(seen[j]) break;\n\t\t}\n\t\tsector_list[k] = ({nodes: buf, data:__toBuffer([buf_chain])});\n\t}\n\treturn sector_list;\n}\n\n/* [MS-CFB] 2.6.1 Compound File Directory Entry */\nfunction read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, FileIndex, mini) {\n\tvar minifat_store = 0, pl = (Paths.length?2:0);\n\tvar sector = sector_list[dir_start].data;\n\tvar i = 0, namelen = 0, name;\n\tfor(; i < sector.length; i+= 128) {\n\t\tvar blob = sector.slice(i, i+128);\n\t\tprep_blob(blob, 64);\n\t\tnamelen = blob.read_shift(2);\n\t\tname = __utf16le(blob,0,namelen-pl);\n\t\tPaths.push(name);\n\t\tvar o = ({\n\t\t\tname: name,\n\t\t\ttype: blob.read_shift(1),\n\t\t\tcolor: blob.read_shift(1),\n\t\t\tL: blob.read_shift(4, 'i'),\n\t\t\tR: blob.read_shift(4, 'i'),\n\t\t\tC: blob.read_shift(4, 'i'),\n\t\t\tclsid: blob.read_shift(16),\n\t\t\tstate: blob.read_shift(4, 'i'),\n\t\t\tstart: 0,\n\t\t\tsize: 0\n\t\t});\n\t\tvar ctime = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2);\n\t\tif(ctime !== 0) o.ct = read_date(blob, blob.l-8);\n\t\tvar mtime = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2);\n\t\tif(mtime !== 0) o.mt = read_date(blob, blob.l-8);\n\t\to.start = blob.read_shift(4, 'i');\n\t\to.size = blob.read_shift(4, 'i');\n\t\tif(o.size < 0 && o.start < 0) { o.size = o.type = 0; o.start = ENDOFCHAIN; o.name = \"\"; }\n\t\tif(o.type === 5) { /* root */\n\t\t\tminifat_store = o.start;\n\t\t\tif(nmfs > 0 && minifat_store !== ENDOFCHAIN) sector_list[minifat_store].name = \"!StreamData\";\n\t\t\t/*minifat_size = o.size;*/\n\t\t} else if(o.size >= 4096 /* MSCSZ */) {\n\t\t\to.storage = 'fat';\n\t\t\tif(sector_list[o.start] === undefined) sector_list[o.start] = get_sector_list(sectors, o.start, sector_list.fat_addrs, sector_list.ssz);\n\t\t\tsector_list[o.start].name = o.name;\n\t\t\to.content = (sector_list[o.start].data.slice(0,o.size));\n\t\t} else {\n\t\t\to.storage = 'minifat';\n\t\t\tif(o.size < 0) o.size = 0;\n\t\t\telse if(minifat_store !== ENDOFCHAIN && o.start !== ENDOFCHAIN && sector_list[minifat_store]) {\n\t\t\t\to.content = get_mfat_entry(o, sector_list[minifat_store].data, (sector_list[mini]||{}).data);\n\t\t\t}\n\t\t}\n\t\tif(o.content) prep_blob(o.content, 0);\n\t\tfiles[name] = o;\n\t\tFileIndex.push(o);\n\t}\n}\n\nfunction read_date(blob, offset) {\n\treturn new Date(( ( (__readUInt32LE(blob,offset+4)/1e7)*Math.pow(2,32)+__readUInt32LE(blob,offset)/1e7 ) - 11644473600)*1000);\n}\n\nfunction read_file(filename, options) {\n\tget_fs();\n\treturn parse(fs.readFileSync(filename), options);\n}\n\nfunction read(blob, options) {\n\tvar type = options && options.type;\n\tif(!type) {\n\t\tif(has_buf && Buffer.isBuffer(blob)) type = \"buffer\";\n\t}\n\tswitch(type || \"base64\") {\n\t\tcase \"file\": return read_file(blob, options);\n\t\tcase \"base64\": return parse(s2a(Base64_decode(blob)), options);\n\t\tcase \"binary\": return parse(s2a(blob), options);\n\t}\n\treturn parse(blob, options);\n}\n\nfunction init_cfb(cfb, opts) {\n\tvar o = opts || {}, root = o.root || \"Root Entry\";\n\tif(!cfb.FullPaths) cfb.FullPaths = [];\n\tif(!cfb.FileIndex) cfb.FileIndex = [];\n\tif(cfb.FullPaths.length !== cfb.FileIndex.length) throw new Error(\"inconsistent CFB structure\");\n\tif(cfb.FullPaths.length === 0) {\n\t\tcfb.FullPaths[0] = root + \"/\";\n\t\tcfb.FileIndex[0] = ({ name: root, type: 5 });\n\t}\n\tif(o.CLSID) cfb.FileIndex[0].clsid = o.CLSID;\n\tseed_cfb(cfb);\n}\nfunction seed_cfb(cfb) {\n\tvar nm = \"\\u0001Sh33tJ5\";\n\tif(CFB.find(cfb, \"/\" + nm)) return;\n\tvar p = new_buf(4); p[0] = 55; p[1] = p[3] = 50; p[2] = 54;\n\tcfb.FileIndex.push(({ name: nm, type: 2, content:p, size:4, L:69, R:69, C:69 }));\n\tcfb.FullPaths.push(cfb.FullPaths[0] + nm);\n\trebuild_cfb(cfb);\n}\nfunction rebuild_cfb(cfb, f) {\n\tinit_cfb(cfb);\n\tvar gc = false, s = false;\n\tfor(var i = cfb.FullPaths.length - 1; i >= 0; --i) {\n\t\tvar _file = cfb.FileIndex[i];\n\t\tswitch(_file.type) {\n\t\t\tcase 0:\n\t\t\t\tif(s) gc = true;\n\t\t\t\telse { cfb.FileIndex.pop(); cfb.FullPaths.pop(); }\n\t\t\t\tbreak;\n\t\t\tcase 1: case 2: case 5:\n\t\t\t\ts = true;\n\t\t\t\tif(isNaN(_file.R * _file.L * _file.C)) gc = true;\n\t\t\t\tif(_file.R > -1 && _file.L > -1 && _file.R == _file.L) gc = true;\n\t\t\t\tbreak;\n\t\t\tdefault: gc = true; break;\n\t\t}\n\t}\n\tif(!gc && !f) return;\n\n\tvar now = new Date(1987, 1, 19), j = 0;\n\t// Track which names exist\n\tvar fullPaths = Object.create ? Object.create(null) : {};\n\tvar data = [];\n\tfor(i = 0; i < cfb.FullPaths.length; ++i) {\n\t\tfullPaths[cfb.FullPaths[i]] = true;\n\t\tif(cfb.FileIndex[i].type === 0) continue;\n\t\tdata.push([cfb.FullPaths[i], cfb.FileIndex[i]]);\n\t}\n\tfor(i = 0; i < data.length; ++i) {\n\t\tvar dad = dirname(data[i][0]);\n\t\ts = fullPaths[dad];\n\t\twhile(!s) {\n\t\t\twhile(dirname(dad) && !fullPaths[dirname(dad)]) dad = dirname(dad);\n\n\t\t\tdata.push([dad, ({\n\t\t\t\tname: filename(dad).replace(\"/\",\"\"),\n\t\t\t\ttype: 1,\n\t\t\t\tclsid: HEADER_CLSID,\n\t\t\t\tct: now, mt: now,\n\t\t\t\tcontent: null\n\t\t\t})]);\n\n\t\t\t// Add name to set\n\t\t\tfullPaths[dad] = true;\n\n\t\t\tdad = dirname(data[i][0]);\n\t\t\ts = fullPaths[dad];\n\t\t}\n\t}\n\n\tdata.sort(function(x,y) { return namecmp(x[0], y[0]); });\n\tcfb.FullPaths = []; cfb.FileIndex = [];\n\tfor(i = 0; i < data.length; ++i) { cfb.FullPaths[i] = data[i][0]; cfb.FileIndex[i] = data[i][1]; }\n\tfor(i = 0; i < data.length; ++i) {\n\t\tvar elt = cfb.FileIndex[i];\n\t\tvar nm = cfb.FullPaths[i];\n\n\t\telt.name = filename(nm).replace(\"/\",\"\");\n\t\telt.L = elt.R = elt.C = -(elt.color = 1);\n\t\telt.size = elt.content ? elt.content.length : 0;\n\t\telt.start = 0;\n\t\telt.clsid = (elt.clsid || HEADER_CLSID);\n\t\tif(i === 0) {\n\t\t\telt.C = data.length > 1 ? 1 : -1;\n\t\t\telt.size = 0;\n\t\t\telt.type = 5;\n\t\t} else if(nm.slice(-1) == \"/\") {\n\t\t\tfor(j=i+1;j < data.length; ++j) if(dirname(cfb.FullPaths[j])==nm) break;\n\t\t\telt.C = j >= data.length ? -1 : j;\n\t\t\tfor(j=i+1;j < data.length; ++j) if(dirname(cfb.FullPaths[j])==dirname(nm)) break;\n\t\t\telt.R = j >= data.length ? -1 : j;\n\t\t\telt.type = 1;\n\t\t} else {\n\t\t\tif(dirname(cfb.FullPaths[i+1]||\"\") == dirname(nm)) elt.R = i + 1;\n\t\t\telt.type = 2;\n\t\t}\n\t}\n\n}\n\nfunction _write(cfb, options) {\n\tvar _opts = options || {};\n\t/* MAD is order-sensitive, skip rebuild and sort */\n\tif(_opts.fileType == 'mad') return write_mad(cfb, _opts);\n\trebuild_cfb(cfb);\n\tswitch(_opts.fileType) {\n\t\tcase 'zip': return write_zip(cfb, _opts);\n\t\t//case 'mad': return write_mad(cfb, _opts);\n\t}\n\tvar L = (function(cfb){\n\t\tvar mini_size = 0, fat_size = 0;\n\t\tfor(var i = 0; i < cfb.FileIndex.length; ++i) {\n\t\t\tvar file = cfb.FileIndex[i];\n\t\t\tif(!file.content) continue;\n\t\t\tvar flen = file.content.length;\n\t\t\tif(flen > 0){\n\t\t\t\tif(flen < 0x1000) mini_size += (flen + 0x3F) >> 6;\n\t\t\t\telse fat_size += (flen + 0x01FF) >> 9;\n\t\t\t}\n\t\t}\n\t\tvar dir_cnt = (cfb.FullPaths.length +3) >> 2;\n\t\tvar mini_cnt = (mini_size + 7) >> 3;\n\t\tvar mfat_cnt = (mini_size + 0x7F) >> 7;\n\t\tvar fat_base = mini_cnt + fat_size + dir_cnt + mfat_cnt;\n\t\tvar fat_cnt = (fat_base + 0x7F) >> 7;\n\t\tvar difat_cnt = fat_cnt <= 109 ? 0 : Math.ceil((fat_cnt-109)/0x7F);\n\t\twhile(((fat_base + fat_cnt + difat_cnt + 0x7F) >> 7) > fat_cnt) difat_cnt = ++fat_cnt <= 109 ? 0 : Math.ceil((fat_cnt-109)/0x7F);\n\t\tvar L = [1, difat_cnt, fat_cnt, mfat_cnt, dir_cnt, fat_size, mini_size, 0];\n\t\tcfb.FileIndex[0].size = mini_size << 6;\n\t\tL[7] = (cfb.FileIndex[0].start=L[0]+L[1]+L[2]+L[3]+L[4]+L[5])+((L[6]+7) >> 3);\n\t\treturn L;\n\t})(cfb);\n\tvar o = new_buf(L[7] << 9);\n\tvar i = 0, T = 0;\n\t{\n\t\tfor(i = 0; i < 8; ++i) o.write_shift(1, HEADER_SIG[i]);\n\t\tfor(i = 0; i < 8; ++i) o.write_shift(2, 0);\n\t\to.write_shift(2, 0x003E);\n\t\to.write_shift(2, 0x0003);\n\t\to.write_shift(2, 0xFFFE);\n\t\to.write_shift(2, 0x0009);\n\t\to.write_shift(2, 0x0006);\n\t\tfor(i = 0; i < 3; ++i) o.write_shift(2, 0);\n\t\to.write_shift(4, 0);\n\t\to.write_shift(4, L[2]);\n\t\to.write_shift(4, L[0] + L[1] + L[2] + L[3] - 1);\n\t\to.write_shift(4, 0);\n\t\to.write_shift(4, 1<<12);\n\t\to.write_shift(4, L[3] ? L[0] + L[1] + L[2] - 1: ENDOFCHAIN);\n\t\to.write_shift(4, L[3]);\n\t\to.write_shift(-4, L[1] ? L[0] - 1: ENDOFCHAIN);\n\t\to.write_shift(4, L[1]);\n\t\tfor(i = 0; i < 109; ++i) o.write_shift(-4, i < L[2] ? L[1] + i : -1);\n\t}\n\tif(L[1]) {\n\t\tfor(T = 0; T < L[1]; ++T) {\n\t\t\tfor(; i < 236 + T * 127; ++i) o.write_shift(-4, i < L[2] ? L[1] + i : -1);\n\t\t\to.write_shift(-4, T === L[1] - 1 ? ENDOFCHAIN : T + 1);\n\t\t}\n\t}\n\tvar chainit = function(w) {\n\t\tfor(T += w; i<T-1; ++i) o.write_shift(-4, i+1);\n\t\tif(w) { ++i; o.write_shift(-4, ENDOFCHAIN); }\n\t};\n\tT = i = 0;\n\tfor(T+=L[1]; i<T; ++i) o.write_shift(-4, consts.DIFSECT);\n\tfor(T+=L[2]; i<T; ++i) o.write_shift(-4, consts.FATSECT);\n\tchainit(L[3]);\n\tchainit(L[4]);\n\tvar j = 0, flen = 0;\n\tvar file = cfb.FileIndex[0];\n\tfor(; j < cfb.FileIndex.length; ++j) {\n\t\tfile = cfb.FileIndex[j];\n\t\tif(!file.content) continue;\nflen = file.content.length;\n\t\tif(flen < 0x1000) continue;\n\t\tfile.start = T;\n\t\tchainit((flen + 0x01FF) >> 9);\n\t}\n\tchainit((L[6] + 7) >> 3);\n\twhile(o.l & 0x1FF) o.write_shift(-4, consts.ENDOFCHAIN);\n\tT = i = 0;\n\tfor(j = 0; j < cfb.FileIndex.length; ++j) {\n\t\tfile = cfb.FileIndex[j];\n\t\tif(!file.content) continue;\nflen = file.content.length;\n\t\tif(!flen || flen >= 0x1000) continue;\n\t\tfile.start = T;\n\t\tchainit((flen + 0x3F) >> 6);\n\t}\n\twhile(o.l & 0x1FF) o.write_shift(-4, consts.ENDOFCHAIN);\n\tfor(i = 0; i < L[4]<<2; ++i) {\n\t\tvar nm = cfb.FullPaths[i];\n\t\tif(!nm || nm.length === 0) {\n\t\t\tfor(j = 0; j < 17; ++j) o.write_shift(4, 0);\n\t\t\tfor(j = 0; j < 3; ++j) o.write_shift(4, -1);\n\t\t\tfor(j = 0; j < 12; ++j) o.write_shift(4, 0);\n\t\t\tcontinue;\n\t\t}\n\t\tfile = cfb.FileIndex[i];\n\t\tif(i === 0) file.start = file.size ? file.start - 1 : ENDOFCHAIN;\n\t\tvar _nm = (i === 0 && _opts.root) || file.name;\n\t\tif(_nm.length > 32) {\n\t\t\tconsole.error(\"Name \" + _nm + \" will be truncated to \" + _nm.slice(0,32));\n\t\t\t_nm = _nm.slice(0, 32);\n\t\t}\n\t\tflen = 2*(_nm.length+1);\n\t\to.write_shift(64, _nm, \"utf16le\");\n\t\to.write_shift(2, flen);\n\t\to.write_shift(1, file.type);\n\t\to.write_shift(1, file.color);\n\t\to.write_shift(-4, file.L);\n\t\to.write_shift(-4, file.R);\n\t\to.write_shift(-4, file.C);\n\t\tif(!file.clsid) for(j = 0; j < 4; ++j) o.write_shift(4, 0);\n\t\telse o.write_shift(16, file.clsid, \"hex\");\n\t\to.write_shift(4, file.state || 0);\n\t\to.write_shift(4, 0); o.write_shift(4, 0);\n\t\to.write_shift(4, 0); o.write_shift(4, 0);\n\t\to.write_shift(4, file.start);\n\t\to.write_shift(4, file.size); o.write_shift(4, 0);\n\t}\n\tfor(i = 1; i < cfb.FileIndex.length; ++i) {\n\t\tfile = cfb.FileIndex[i];\nif(file.size >= 0x1000) {\n\t\t\to.l = (file.start+1) << 9;\n\t\t\tif (has_buf && Buffer.isBuffer(file.content)) {\n\t\t\t\tfile.content.copy(o, o.l, 0, file.size);\n\t\t\t\t// o is a 0-filled Buffer so just set next offset\n\t\t\t\to.l += (file.size + 511) & -512;\n\t\t\t} else {\n\t\t\t\tfor(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]);\n\t\t\t\tfor(; j & 0x1FF; ++j) o.write_shift(1, 0);\n\t\t\t}\n\t\t}\n\t}\n\tfor(i = 1; i < cfb.FileIndex.length; ++i) {\n\t\tfile = cfb.FileIndex[i];\nif(file.size > 0 && file.size < 0x1000) {\n\t\t\tif (has_buf && Buffer.isBuffer(file.content)) {\n\t\t\t\tfile.content.copy(o, o.l, 0, file.size);\n\t\t\t\t// o is a 0-filled Buffer so just set next offset\n\t\t\t\to.l += (file.size + 63) & -64;\n\t\t\t} else {\n\t\t\t\tfor(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]);\n\t\t\t\tfor(; j & 0x3F; ++j) o.write_shift(1, 0);\n\t\t\t}\n\t\t}\n\t}\n\tif (has_buf) {\n\t\to.l = o.length;\n\t} else {\n\t\t// When using Buffer, already 0-filled\n\t\twhile(o.l < o.length) o.write_shift(1, 0);\n\t}\n\treturn o;\n}\n/* [MS-CFB] 2.6.4 (Unicode 3.0.1 case conversion) */\nfunction find(cfb, path) {\n\tvar UCFullPaths = cfb.FullPaths.map(function(x) { return x.toUpperCase(); });\n\tvar UCPaths = UCFullPaths.map(function(x) { var y = x.split(\"/\"); return y[y.length - (x.slice(-1) == \"/\" ? 2 : 1)]; });\n\tvar k = false;\n\tif(path.charCodeAt(0) === 47 /* \"/\" */) { k = true; path = UCFullPaths[0].slice(0, -1) + path; }\n\telse k = path.indexOf(\"/\") !== -1;\n\tvar UCPath = path.toUpperCase();\n\tvar w = k === true ? UCFullPaths.indexOf(UCPath) : UCPaths.indexOf(UCPath);\n\tif(w !== -1) return cfb.FileIndex[w];\n\n\tvar m = !UCPath.match(chr1);\n\tUCPath = UCPath.replace(chr0,'');\n\tif(m) UCPath = UCPath.replace(chr1,'!');\n\tfor(w = 0; w < UCFullPaths.length; ++w) {\n\t\tif((m ? UCFullPaths[w].replace(chr1,'!') : UCFullPaths[w]).replace(chr0,'') == UCPath) return cfb.FileIndex[w];\n\t\tif((m ? UCPaths[w].replace(chr1,'!') : UCPaths[w]).replace(chr0,'') == UCPath) return cfb.FileIndex[w];\n\t}\n\treturn null;\n}\n/** CFB Constants */\nvar MSSZ = 64; /* Mini Sector Size = 1<<6 */\n//var MSCSZ = 4096; /* Mini Stream Cutoff Size */\n/* 2.1 Compound File Sector Numbers and Types */\nvar ENDOFCHAIN = -2;\n/* 2.2 Compound File Header */\nvar HEADER_SIGNATURE = 'd0cf11e0a1b11ae1';\nvar HEADER_SIG = [0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1];\nvar HEADER_CLSID = '00000000000000000000000000000000';\nvar consts = {\n\t/* 2.1 Compund File Sector Numbers and Types */\n\tMAXREGSECT: -6,\n\tDIFSECT: -4,\n\tFATSECT: -3,\n\tENDOFCHAIN: ENDOFCHAIN,\n\tFREESECT: -1,\n\t/* 2.2 Compound File Header */\n\tHEADER_SIGNATURE: HEADER_SIGNATURE,\n\tHEADER_MINOR_VERSION: '3e00',\n\tMAXREGSID: -6,\n\tNOSTREAM: -1,\n\tHEADER_CLSID: HEADER_CLSID,\n\t/* 2.6.1 Compound File Directory Entry */\n\tEntryTypes: ['unknown','storage','stream','lockbytes','property','root']\n};\n\nfunction write_file(cfb, filename, options) {\n\tget_fs();\n\tvar o = _write(cfb, options);\nfs.writeFileSync(filename, o);\n}\n\nfunction a2s(o) {\n\tvar out = new Array(o.length);\n\tfor(var i = 0; i < o.length; ++i) out[i] = String.fromCharCode(o[i]);\n\treturn out.join(\"\");\n}\n\nfunction write(cfb, options) {\n\tvar o = _write(cfb, options);\n\tswitch(options && options.type || \"buffer\") {\n\t\tcase \"file\": get_fs(); fs.writeFileSync(options.filename, (o)); return o;\n\t\tcase \"binary\": return typeof o == \"string\" ? o : a2s(o);\n\t\tcase \"base64\": return Base64_encode(typeof o == \"string\" ? o : a2s(o));\n\t\tcase \"buffer\": if(has_buf) return Buffer.isBuffer(o) ? o : Buffer_from(o);\n\t\t\t/* falls through */\n\t\tcase \"array\": return typeof o == \"string\" ? s2a(o) : o;\n\t}\n\treturn o;\n}\n/* node < 8.1 zlib does not expose bytesRead, so default to pure JS */\nvar _zlib;\nfunction use_zlib(zlib) { try {\n\tvar InflateRaw = zlib.InflateRaw;\n\tvar InflRaw = new InflateRaw();\n\tInflRaw._processChunk(new Uint8Array([3, 0]), InflRaw._finishFlushFlag);\n\tif(InflRaw.bytesRead) _zlib = zlib;\n\telse throw new Error(\"zlib does not expose bytesRead\");\n} catch(e) {console.error(\"cannot use native zlib: \" + (e.message || e)); } }\n\nfunction _inflateRawSync(payload, usz) {\n\tif(!_zlib) return _inflate(payload, usz);\n\tvar InflateRaw = _zlib.InflateRaw;\n\tvar InflRaw = new InflateRaw();\n\tvar out = InflRaw._processChunk(payload.slice(payload.l), InflRaw._finishFlushFlag);\n\tpayload.l += InflRaw.bytesRead;\n\treturn out;\n}\n\nfunction _deflateRawSync(payload) {\n\treturn _zlib ? _zlib.deflateRawSync(payload) : _deflate(payload);\n}\nvar CLEN_ORDER = [ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ];\n\n/* LEN_ID = [ 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285 ]; */\nvar LEN_LN = [ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13 , 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258 ];\n\n/* DST_ID = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29 ]; */\nvar DST_LN = [ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 ];\n\nfunction bit_swap_8(n) { var t = (((((n<<1)|(n<<11)) & 0x22110) | (((n<<5)|(n<<15)) & 0x88440))); return ((t>>16) | (t>>8) |t)&0xFF; }\n\nvar use_typed_arrays = typeof Uint8Array !== 'undefined';\n\nvar bitswap8 = use_typed_arrays ? new Uint8Array(1<<8) : [];\nfor(var q = 0; q < (1<<8); ++q) bitswap8[q] = bit_swap_8(q);\n\nfunction bit_swap_n(n, b) {\n\tvar rev = bitswap8[n & 0xFF];\n\tif(b <= 8) return rev >>> (8-b);\n\trev = (rev << 8) | bitswap8[(n>>8)&0xFF];\n\tif(b <= 16) return rev >>> (16-b);\n\trev = (rev << 8) | bitswap8[(n>>16)&0xFF];\n\treturn rev >>> (24-b);\n}\n\n/* helpers for unaligned bit reads */\nfunction read_bits_2(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 6 ? 0 : buf[h+1]<<8))>>>w)& 0x03; }\nfunction read_bits_3(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 5 ? 0 : buf[h+1]<<8))>>>w)& 0x07; }\nfunction read_bits_4(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 4 ? 0 : buf[h+1]<<8))>>>w)& 0x0F; }\nfunction read_bits_5(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 3 ? 0 : buf[h+1]<<8))>>>w)& 0x1F; }\nfunction read_bits_7(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 1 ? 0 : buf[h+1]<<8))>>>w)& 0x7F; }\n\n/* works up to n = 3 * 8 + 1 = 25 */\nfunction read_bits_n(buf, bl, n) {\n\tvar w = (bl&7), h = (bl>>>3), f = ((1<<n)-1);\n\tvar v = buf[h] >>> w;\n\tif(n < 8 - w) return v & f;\n\tv |= buf[h+1]<<(8-w);\n\tif(n < 16 - w) return v & f;\n\tv |= buf[h+2]<<(16-w);\n\tif(n < 24 - w) return v & f;\n\tv |= buf[h+3]<<(24-w);\n\treturn v & f;\n}\n\n/* helpers for unaligned bit writes */\nfunction write_bits_3(buf, bl, v) { var w = bl & 7, h = bl >>> 3;\n\tif(w <= 5) buf[h] |= (v & 7) << w;\n\telse {\n\t\tbuf[h] |= (v << w) & 0xFF;\n\t\tbuf[h+1] = (v&7) >> (8-w);\n\t}\n\treturn bl + 3;\n}\n\nfunction write_bits_1(buf, bl, v) {\n\tvar w = bl & 7, h = bl >>> 3;\n\tv = (v&1) << w;\n\tbuf[h] |= v;\n\treturn bl + 1;\n}\nfunction write_bits_8(buf, bl, v) {\n\tvar w = bl & 7, h = bl >>> 3;\n\tv <<= w;\n\tbuf[h] |= v & 0xFF; v >>>= 8;\n\tbuf[h+1] = v;\n\treturn bl + 8;\n}\nfunction write_bits_16(buf, bl, v) {\n\tvar w = bl & 7, h = bl >>> 3;\n\tv <<= w;\n\tbuf[h] |= v & 0xFF; v >>>= 8;\n\tbuf[h+1] = v & 0xFF;\n\tbuf[h+2] = v >>> 8;\n\treturn bl + 16;\n}\n\n/* until ArrayBuffer#realloc is a thing, fake a realloc */\nfunction realloc(b, sz) {\n\tvar L = b.length, M = 2*L > sz ? 2*L : sz + 5, i = 0;\n\tif(L >= sz) return b;\n\tif(has_buf) {\n\t\tvar o = new_unsafe_buf(M);\n\t\t// $FlowIgnore\n\t\tif(b.copy) b.copy(o);\n\t\telse for(; i < b.length; ++i) o[i] = b[i];\n\t\treturn o;\n\t} else if(use_typed_arrays) {\n\t\tvar a = new Uint8Array(M);\n\t\tif(a.set) a.set(b);\n\t\telse for(; i < L; ++i) a[i] = b[i];\n\t\treturn a;\n\t}\n\tb.length = M;\n\treturn b;\n}\n\n/* zero-filled arrays for older browsers */\nfunction zero_fill_array(n) {\n\tvar o = new Array(n);\n\tfor(var i = 0; i < n; ++i) o[i] = 0;\n\treturn o;\n}\n\n/* build tree (used for literals and lengths) */\nfunction build_tree(clens, cmap, MAX) {\n\tvar maxlen = 1, w = 0, i = 0, j = 0, ccode = 0, L = clens.length;\n\n\tvar bl_count = use_typed_arrays ? new Uint16Array(32) : zero_fill_array(32);\n\tfor(i = 0; i < 32; ++i) bl_count[i] = 0;\n\n\tfor(i = L; i < MAX; ++i) clens[i] = 0;\n\tL = clens.length;\n\n\tvar ctree = use_typed_arrays ? new Uint16Array(L) : zero_fill_array(L); // []\n\n\t/* build code tree */\n\tfor(i = 0; i < L; ++i) {\n\t\tbl_count[(w = clens[i])]++;\n\t\tif(maxlen < w) maxlen = w;\n\t\tctree[i] = 0;\n\t}\n\tbl_count[0] = 0;\n\tfor(i = 1; i <= maxlen; ++i) bl_count[i+16] = (ccode = (ccode + bl_count[i-1])<<1);\n\tfor(i = 0; i < L; ++i) {\n\t\tccode = clens[i];\n\t\tif(ccode != 0) ctree[i] = bl_count[ccode+16]++;\n\t}\n\n\t/* cmap[maxlen + 4 bits] = (off&15) + (lit<<4) reverse mapping */\n\tvar cleni = 0;\n\tfor(i = 0; i < L; ++i) {\n\t\tcleni = clens[i];\n\t\tif(cleni != 0) {\n\t\t\tccode = bit_swap_n(ctree[i], maxlen)>>(maxlen-cleni);\n\t\t\tfor(j = (1<<(maxlen + 4 - cleni)) - 1; j>=0; --j)\n\t\t\t\tcmap[ccode|(j<<cleni)] = (cleni&15) | (i<<4);\n\t\t}\n\t}\n\treturn maxlen;\n}\n\n/* Fixed Huffman */\nvar fix_lmap = use_typed_arrays ? new Uint16Array(512) : zero_fill_array(512);\nvar fix_dmap = use_typed_arrays ? new Uint16Array(32) : zero_fill_array(32);\nif(!use_typed_arrays) {\n\tfor(var i = 0; i < 512; ++i) fix_lmap[i] = 0;\n\tfor(i = 0; i < 32; ++i) fix_dmap[i] = 0;\n}\n(function() {\n\tvar dlens = [];\n\tvar i = 0;\n\tfor(;i<32; i++) dlens.push(5);\n\tbuild_tree(dlens, fix_dmap, 32);\n\n\tvar clens = [];\n\ti = 0;\n\tfor(; i<=143; i++) clens.push(8);\n\tfor(; i<=255; i++) clens.push(9);\n\tfor(; i<=279; i++) clens.push(7);\n\tfor(; i<=287; i++) clens.push(8);\n\tbuild_tree(clens, fix_lmap, 288);\n})();var _deflateRaw = (function _deflateRawIIFE() {\n\tvar DST_LN_RE = use_typed_arrays ? new Uint8Array(0x8000) : [];\n\tvar j = 0, k = 0;\n\tfor(; j < DST_LN.length - 1; ++j) {\n\t\tfor(; k < DST_LN[j+1]; ++k) DST_LN_RE[k] = j;\n\t}\n\tfor(;k < 32768; ++k) DST_LN_RE[k] = 29;\n\n\tvar LEN_LN_RE = use_typed_arrays ? new Uint8Array(0x103) : [];\n\tfor(j = 0, k = 0; j < LEN_LN.length - 1; ++j) {\n\t\tfor(; k < LEN_LN[j+1]; ++k) LEN_LN_RE[k] = j;\n\t}\n\n\tfunction write_stored(data, out) {\n\t\tvar boff = 0;\n\t\twhile(boff < data.length) {\n\t\t\tvar L = Math.min(0xFFFF, data.length - boff);\n\t\t\tvar h = boff + L == data.length;\n\t\t\tout.write_shift(1, +h);\n\t\t\tout.write_shift(2, L);\n\t\t\tout.write_shift(2, (~L) & 0xFFFF);\n\t\t\twhile(L-- > 0) out[out.l++] = data[boff++];\n\t\t}\n\t\treturn out.l;\n\t}\n\n\t/* Fixed Huffman */\n\tfunction write_huff_fixed(data, out) {\n\t\tvar bl = 0;\n\t\tvar boff = 0;\n\t\tvar addrs = use_typed_arrays ? new Uint16Array(0x8000) : [];\n\t\twhile(boff < data.length) {\n\t\t\tvar L = /* data.length - boff; */ Math.min(0xFFFF, data.length - boff);\n\n\t\t\t/* write a stored block for short data */\n\t\t\tif(L < 10) {\n\t\t\t\tbl = write_bits_3(out, bl, +!!(boff + L == data.length)); // jshint ignore:line\n\t\t\t\tif(bl & 7) bl += 8 - (bl & 7);\n\t\t\t\tout.l = (bl / 8) | 0;\n\t\t\t\tout.write_shift(2, L);\n\t\t\t\tout.write_shift(2, (~L) & 0xFFFF);\n\t\t\t\twhile(L-- > 0) out[out.l++] = data[boff++];\n\t\t\t\tbl = out.l * 8;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tbl = write_bits_3(out, bl, +!!(boff + L == data.length) + 2); // jshint ignore:line\n\t\t\tvar hash = 0;\n\t\t\twhile(L-- > 0) {\n\t\t\t\tvar d = data[boff];\n\t\t\t\thash = ((hash << 5) ^ d) & 0x7FFF;\n\n\t\t\t\tvar match = -1, mlen = 0;\n\n\t\t\t\tif((match = addrs[hash])) {\n\t\t\t\t\tmatch |= boff & ~0x7FFF;\n\t\t\t\t\tif(match > boff) match -= 0x8000;\n\t\t\t\t\tif(match < boff) while(data[match + mlen] == data[boff + mlen] && mlen < 250) ++mlen;\n\t\t\t\t}\n\n\t\t\t\tif(mlen > 2) {\n\t\t\t\t\t/* Copy Token */\n\t\t\t\t\td = LEN_LN_RE[mlen];\n\t\t\t\t\tif(d <= 22) bl = write_bits_8(out, bl, bitswap8[d+1]>>1) - 1;\n\t\t\t\t\telse {\n\t\t\t\t\t\twrite_bits_8(out, bl, 3);\n\t\t\t\t\t\tbl += 5;\n\t\t\t\t\t\twrite_bits_8(out, bl, bitswap8[d-23]>>5);\n\t\t\t\t\t\tbl += 3;\n\t\t\t\t\t}\n\t\t\t\t\tvar len_eb = (d < 8) ? 0 : ((d - 4)>>2);\n\t\t\t\t\tif(len_eb > 0) {\n\t\t\t\t\t\twrite_bits_16(out, bl, mlen - LEN_LN[d]);\n\t\t\t\t\t\tbl += len_eb;\n\t\t\t\t\t}\n\n\t\t\t\t\td = DST_LN_RE[boff - match];\n\t\t\t\t\tbl = write_bits_8(out, bl, bitswap8[d]>>3);\n\t\t\t\t\tbl -= 3;\n\n\t\t\t\t\tvar dst_eb = d < 4 ? 0 : (d-2)>>1;\n\t\t\t\t\tif(dst_eb > 0) {\n\t\t\t\t\t\twrite_bits_16(out, bl, boff - match - DST_LN[d]);\n\t\t\t\t\t\tbl += dst_eb;\n\t\t\t\t\t}\n\t\t\t\t\tfor(var q = 0; q < mlen; ++q) {\n\t\t\t\t\t\taddrs[hash] = boff & 0x7FFF;\n\t\t\t\t\t\thash = ((hash << 5) ^ data[boff]) & 0x7FFF;\n\t\t\t\t\t\t++boff;\n\t\t\t\t\t}\n\t\t\t\t\tL-= mlen - 1;\n\t\t\t\t} else {\n\t\t\t\t\t/* Literal Token */\n\t\t\t\t\tif(d <= 143) d = d + 48;\n\t\t\t\t\telse bl = write_bits_1(out, bl, 1);\n\t\t\t\t\tbl = write_bits_8(out, bl, bitswap8[d]);\n\t\t\t\t\taddrs[hash] = boff & 0x7FFF;\n\t\t\t\t\t++boff;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tbl = write_bits_8(out, bl, 0) - 1;\n\t\t}\n\t\tout.l = ((bl + 7)/8)|0;\n\t\treturn out.l;\n\t}\n\treturn function _deflateRaw(data, out) {\n\t\tif(data.length < 8) return write_stored(data, out);\n\t\treturn write_huff_fixed(data, out);\n\t};\n})();\n\nfunction _deflate(data) {\n\tvar buf = new_buf(50+Math.floor(data.length*1.1));\n\tvar off = _deflateRaw(data, buf);\n\treturn buf.slice(0, off);\n}\n/* modified inflate function also moves original read head */\n\nvar dyn_lmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);\nvar dyn_dmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);\nvar dyn_cmap = use_typed_arrays ? new Uint16Array(128) : zero_fill_array(128);\nvar dyn_len_1 = 1, dyn_len_2 = 1;\n\n/* 5.5.3 Expanding Huffman Codes */\nfunction dyn(data, boff) {\n\t/* nomenclature from RFC1951 refers to bit values; these are offset by the implicit constant */\n\tvar _HLIT = read_bits_5(data, boff) + 257; boff += 5;\n\tvar _HDIST = read_bits_5(data, boff) + 1; boff += 5;\n\tvar _HCLEN = read_bits_4(data, boff) + 4; boff += 4;\n\tvar w = 0;\n\n\t/* grab and store code lengths */\n\tvar clens = use_typed_arrays ? new Uint8Array(19) : zero_fill_array(19);\n\tvar ctree = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];\n\tvar maxlen = 1;\n\tvar bl_count = use_typed_arrays ? new Uint8Array(8) : zero_fill_array(8);\n\tvar next_code = use_typed_arrays ? new Uint8Array(8) : zero_fill_array(8);\n\tvar L = clens.length; /* 19 */\n\tfor(var i = 0; i < _HCLEN; ++i) {\n\t\tclens[CLEN_ORDER[i]] = w = read_bits_3(data, boff);\n\t\tif(maxlen < w) maxlen = w;\n\t\tbl_count[w]++;\n\t\tboff += 3;\n\t}\n\n\t/* build code tree */\n\tvar ccode = 0;\n\tbl_count[0] = 0;\n\tfor(i = 1; i <= maxlen; ++i) next_code[i] = ccode = (ccode + bl_count[i-1])<<1;\n\tfor(i = 0; i < L; ++i) if((ccode = clens[i]) != 0) ctree[i] = next_code[ccode]++;\n\t/* cmap[7 bits from stream] = (off&7) + (lit<<3) */\n\tvar cleni = 0;\n\tfor(i = 0; i < L; ++i) {\n\t\tcleni = clens[i];\n\t\tif(cleni != 0) {\n\t\t\tccode = bitswap8[ctree[i]]>>(8-cleni);\n\t\t\tfor(var j = (1<<(7-cleni))-1; j>=0; --j) dyn_cmap[ccode|(j<<cleni)] = (cleni&7) | (i<<3);\n\t\t}\n\t}\n\n\t/* read literal and dist codes at once */\n\tvar hcodes = [];\n\tmaxlen = 1;\n\tfor(; hcodes.length < _HLIT + _HDIST;) {\n\t\tccode = dyn_cmap[read_bits_7(data, boff)];\n\t\tboff += ccode & 7;\n\t\tswitch((ccode >>>= 3)) {\n\t\t\tcase 16:\n\t\t\t\tw = 3 + read_bits_2(data, boff); boff += 2;\n\t\t\t\tccode = hcodes[hcodes.length - 1];\n\t\t\t\twhile(w-- > 0) hcodes.push(ccode);\n\t\t\t\tbreak;\n\t\t\tcase 17:\n\t\t\t\tw = 3 + read_bits_3(data, boff); boff += 3;\n\t\t\t\twhile(w-- > 0) hcodes.push(0);\n\t\t\t\tbreak;\n\t\t\tcase 18:\n\t\t\t\tw = 11 + read_bits_7(data, boff); boff += 7;\n\t\t\t\twhile(w -- > 0) hcodes.push(0);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\thcodes.push(ccode);\n\t\t\t\tif(maxlen < ccode) maxlen = ccode;\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\t/* build literal / length trees */\n\tvar h1 = hcodes.slice(0, _HLIT), h2 = hcodes.slice(_HLIT);\n\tfor(i = _HLIT; i < 286; ++i) h1[i] = 0;\n\tfor(i = _HDIST; i < 30; ++i) h2[i] = 0;\n\tdyn_len_1 = build_tree(h1, dyn_lmap, 286);\n\tdyn_len_2 = build_tree(h2, dyn_dmap, 30);\n\treturn boff;\n}\n\n/* return [ data, bytesRead ] */\nfunction inflate(data, usz) {\n\t/* shortcircuit for empty buffer [0x03, 0x00] */\n\tif(data[0] == 3 && !(data[1] & 0x3)) { return [new_raw_buf(usz), 2]; }\n\n\t/* bit offset */\n\tvar boff = 0;\n\n\t/* header includes final bit and type bits */\n\tvar header = 0;\n\n\tvar outbuf = new_unsafe_buf(usz ? usz : (1<<18));\n\tvar woff = 0;\n\tvar OL = outbuf.length>>>0;\n\tvar max_len_1 = 0, max_len_2 = 0;\n\n\twhile((header&1) == 0) {\n\t\theader = read_bits_3(data, boff); boff += 3;\n\t\tif((header >>> 1) == 0) {\n\t\t\t/* Stored block */\n\t\t\tif(boff & 7) boff += 8 - (boff&7);\n\t\t\t/* 2 bytes sz, 2 bytes bit inverse */\n\t\t\tvar sz = data[boff>>>3] | data[(boff>>>3)+1]<<8;\n\t\t\tboff += 32;\n\t\t\t/* push sz bytes */\n\t\t\tif(sz > 0) {\n\t\t\t\tif(!usz && OL < woff + sz) { outbuf = realloc(outbuf, woff + sz); OL = outbuf.length; }\n\t\t\t\twhile(sz-- > 0) { outbuf[woff++] = data[boff>>>3]; boff += 8; }\n\t\t\t}\n\t\t\tcontinue;\n\t\t} else if((header >> 1) == 1) {\n\t\t\t/* Fixed Huffman */\n\t\t\tmax_len_1 = 9; max_len_2 = 5;\n\t\t} else {\n\t\t\t/* Dynamic Huffman */\n\t\t\tboff = dyn(data, boff);\n\t\t\tmax_len_1 = dyn_len_1; max_len_2 = dyn_len_2;\n\t\t}\n\t\tfor(;;) { // while(true) is apparently out of vogue in modern JS circles\n\t\t\tif(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; }\n\t\t\t/* ingest code and move read head */\n\t\t\tvar bits = read_bits_n(data, boff, max_len_1);\n\t\t\tvar code = (header>>>1) == 1 ? fix_lmap[bits] : dyn_lmap[bits];\n\t\t\tboff += code & 15; code >>>= 4;\n\t\t\t/* 0-255 are literals, 256 is end of block token, 257+ are copy tokens */\n\t\t\tif(((code>>>8)&0xFF) === 0) outbuf[woff++] = code;\n\t\t\telse if(code == 256) break;\n\t\t\telse {\n\t\t\t\tcode -= 257;\n\t\t\t\tvar len_eb = (code < 8) ? 0 : ((code-4)>>2); if(len_eb > 5) len_eb = 0;\n\t\t\t\tvar tgt = woff + LEN_LN[code];\n\t\t\t\t/* length extra bits */\n\t\t\t\tif(len_eb > 0) {\n\t\t\t\t\ttgt += read_bits_n(data, boff, len_eb);\n\t\t\t\t\tboff += len_eb;\n\t\t\t\t}\n\n\t\t\t\t/* dist code */\n\t\t\t\tbits = read_bits_n(data, boff, max_len_2);\n\t\t\t\tcode = (header>>>1) == 1 ? fix_dmap[bits] : dyn_dmap[bits];\n\t\t\t\tboff += code & 15; code >>>= 4;\n\t\t\t\tvar dst_eb = (code < 4 ? 0 : (code-2)>>1);\n\t\t\t\tvar dst = DST_LN[code];\n\t\t\t\t/* dist extra bits */\n\t\t\t\tif(dst_eb > 0) {\n\t\t\t\t\tdst += read_bits_n(data, boff, dst_eb);\n\t\t\t\t\tboff += dst_eb;\n\t\t\t\t}\n\n\t\t\t\t/* in the common case, manual byte copy is faster than TA set / Buffer copy */\n\t\t\t\tif(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt + 100); OL = outbuf.length; }\n\t\t\t\twhile(woff < tgt) { outbuf[woff] = outbuf[woff - dst]; ++woff; }\n\t\t\t}\n\t\t}\n\t}\n\tif(usz) return [outbuf, (boff+7)>>>3];\n\treturn [outbuf.slice(0, woff), (boff+7)>>>3];\n}\n\nfunction _inflate(payload, usz) {\n\tvar data = payload.slice(payload.l||0);\n\tvar out = inflate(data, usz);\n\tpayload.l += out[1];\n\treturn out[0];\n}\n\nfunction warn_or_throw(wrn, msg) {\n\tif(wrn) { if(typeof console !== 'undefined') console.error(msg); }\n\telse throw new Error(msg);\n}\n\nfunction parse_zip(file, options) {\n\tvar blob = file;\n\tprep_blob(blob, 0);\n\n\tvar FileIndex = [], FullPaths = [];\n\tvar o = {\n\t\tFileIndex: FileIndex,\n\t\tFullPaths: FullPaths\n\t};\n\tinit_cfb(o, { root: options.root });\n\n\t/* find end of central directory, start just after signature */\n\tvar i = blob.length - 4;\n\twhile((blob[i] != 0x50 || blob[i+1] != 0x4b || blob[i+2] != 0x05 || blob[i+3] != 0x06) && i >= 0) --i;\n\tblob.l = i + 4;\n\n\t/* parse end of central directory */\n\tblob.l += 4;\n\tvar fcnt = blob.read_shift(2);\n\tblob.l += 6;\n\tvar start_cd = blob.read_shift(4);\n\n\t/* parse central directory */\n\tblob.l = start_cd;\n\n\tfor(i = 0; i < fcnt; ++i) {\n\t\t/* trust local file header instead of CD entry */\n\t\tblob.l += 20;\n\t\tvar csz = blob.read_shift(4);\n\t\tvar usz = blob.read_shift(4);\n\t\tvar namelen = blob.read_shift(2);\n\t\tvar efsz = blob.read_shift(2);\n\t\tvar fcsz = blob.read_shift(2);\n\t\tblob.l += 8;\n\t\tvar offset = blob.read_shift(4);\n\t\tvar EF = parse_extra_field(blob.slice(blob.l+namelen, blob.l+namelen+efsz));\n\t\tblob.l += namelen + efsz + fcsz;\n\n\t\tvar L = blob.l;\n\t\tblob.l = offset + 4;\n\t\tparse_local_file(blob, csz, usz, o, EF);\n\t\tblob.l = L;\n\t}\n\n\treturn o;\n}\n\n\n/* head starts just after local file header signature */\nfunction parse_local_file(blob, csz, usz, o, EF) {\n\t/* [local file header] */\n\tblob.l += 2;\n\tvar flags = blob.read_shift(2);\n\tvar meth = blob.read_shift(2);\n\tvar date = parse_dos_date(blob);\n\n\tif(flags & 0x2041) throw new Error(\"Unsupported ZIP encryption\");\n\tvar crc32 = blob.read_shift(4);\n\tvar _csz = blob.read_shift(4);\n\tvar _usz = blob.read_shift(4);\n\n\tvar namelen = blob.read_shift(2);\n\tvar efsz = blob.read_shift(2);\n\n\t// TODO: flags & (1<<11) // UTF8\n\tvar name = \"\"; for(var i = 0; i < namelen; ++i) name += String.fromCharCode(blob[blob.l++]);\n\tif(efsz) {\n\t\tvar ef = parse_extra_field(blob.slice(blob.l, blob.l + efsz));\n\t\tif((ef[0x5455]||{}).mt) date = ef[0x5455].mt;\n\t\tif(((EF||{})[0x5455]||{}).mt) date = EF[0x5455].mt;\n\t}\n\tblob.l += efsz;\n\n\t/* [encryption header] */\n\n\t/* [file data] */\n\tvar data = blob.slice(blob.l, blob.l + _csz);\n\tswitch(meth) {\n\t\tcase 8: data = _inflateRawSync(blob, _usz); break;\n\t\tcase 0: break; // TODO: scan for magic number\n\t\tdefault: throw new Error(\"Unsupported ZIP Compression method \" + meth);\n\t}\n\n\t/* [data descriptor] */\n\tvar wrn = false;\n\tif(flags & 8) {\n\t\tcrc32 = blob.read_shift(4);\n\t\tif(crc32 == 0x08074b50) { crc32 = blob.read_shift(4); wrn = true; }\n\t\t_csz = blob.read_shift(4);\n\t\t_usz = blob.read_shift(4);\n\t}\n\n\tif(_csz != csz) warn_or_throw(wrn, \"Bad compressed size: \" + csz + \" != \" + _csz);\n\tif(_usz != usz) warn_or_throw(wrn, \"Bad uncompressed size: \" + usz + \" != \" + _usz);\n\tvar _crc32 = CRC32.buf(data, 0);\n\tif((crc32>>0) != (_crc32>>0)) warn_or_throw(wrn, \"Bad CRC32 checksum: \" + crc32 + \" != \" + _crc32);\n\tcfb_add(o, name, data, {unsafe: true, mt: date});\n}\nfunction write_zip(cfb, options) {\n\tvar _opts = options || {};\n\tvar out = [], cdirs = [];\n\tvar o = new_buf(1);\n\tvar method = (_opts.compression ? 8 : 0), flags = 0;\n\tvar desc = false;\n\tif(desc) flags |= 8;\n\tvar i = 0, j = 0;\n\n\tvar start_cd = 0, fcnt = 0;\n\tvar root = cfb.FullPaths[0], fp = root, fi = cfb.FileIndex[0];\n\tvar crcs = [];\n\tvar sz_cd = 0;\n\n\tfor(i = 1; i < cfb.FullPaths.length; ++i) {\n\t\tfp = cfb.FullPaths[i].slice(root.length); fi = cfb.FileIndex[i];\n\t\tif(!fi.size || !fi.content || fp == \"\\u0001Sh33tJ5\") continue;\n\t\tvar start = start_cd;\n\n\t\t/* TODO: CP437 filename */\n\t\tvar namebuf = new_buf(fp.length);\n\t\tfor(j = 0; j < fp.length; ++j) namebuf.write_shift(1, fp.charCodeAt(j) & 0x7F);\n\t\tnamebuf = namebuf.slice(0, namebuf.l);\n\t\tcrcs[fcnt] = CRC32.buf(fi.content, 0);\n\n\t\tvar outbuf = fi.content;\n\t\tif(method == 8) outbuf = _deflateRawSync(outbuf);\n\n\t\t/* local file header */\n\t\to = new_buf(30);\n\t\to.write_shift(4, 0x04034b50);\n\t\to.write_shift(2, 20);\n\t\to.write_shift(2, flags);\n\t\to.write_shift(2, method);\n\t\t/* TODO: last mod file time/date */\n\t\tif(fi.mt) write_dos_date(o, fi.mt);\n\t\telse o.write_shift(4, 0);\n\t\to.write_shift(-4, (flags & 8) ? 0 : crcs[fcnt]);\n\t\to.write_shift(4, (flags & 8) ? 0 : outbuf.length);\n\t\to.write_shift(4, (flags & 8) ? 0 : fi.content.length);\n\t\to.write_shift(2, namebuf.length);\n\t\to.write_shift(2, 0);\n\n\t\tstart_cd += o.length;\n\t\tout.push(o);\n\t\tstart_cd += namebuf.length;\n\t\tout.push(namebuf);\n\n\t\t/* TODO: extra fields? */\n\n\t\t/* TODO: encryption header ? */\n\n\t\tstart_cd += outbuf.length;\n\t\tout.push(outbuf);\n\n\t\t/* data descriptor */\n\t\tif(flags & 8) {\n\t\t\to = new_buf(12);\n\t\t\to.write_shift(-4, crcs[fcnt]);\n\t\t\to.write_shift(4, outbuf.length);\n\t\t\to.write_shift(4, fi.content.length);\n\t\t\tstart_cd += o.l;\n\t\t\tout.push(o);\n\t\t}\n\n\t\t/* central directory */\n\t\to = new_buf(46);\n\t\to.write_shift(4, 0x02014b50);\n\t\to.write_shift(2, 0);\n\t\to.write_shift(2, 20);\n\t\to.write_shift(2, flags);\n\t\to.write_shift(2, method);\n\t\to.write_shift(4, 0); /* TODO: last mod file time/date */\n\t\to.write_shift(-4, crcs[fcnt]);\n\n\t\to.write_shift(4, outbuf.length);\n\t\to.write_shift(4, fi.content.length);\n\t\to.write_shift(2, namebuf.length);\n\t\to.write_shift(2, 0);\n\t\to.write_shift(2, 0);\n\t\to.write_shift(2, 0);\n\t\to.write_shift(2, 0);\n\t\to.write_shift(4, 0);\n\t\to.write_shift(4, start);\n\n\t\tsz_cd += o.l;\n\t\tcdirs.push(o);\n\t\tsz_cd += namebuf.length;\n\t\tcdirs.push(namebuf);\n\t\t++fcnt;\n\t}\n\n\t/* end of central directory */\n\to = new_buf(22);\n\to.write_shift(4, 0x06054b50);\n\to.write_shift(2, 0);\n\to.write_shift(2, 0);\n\to.write_shift(2, fcnt);\n\to.write_shift(2, fcnt);\n\to.write_shift(4, sz_cd);\n\to.write_shift(4, start_cd);\n\to.write_shift(2, 0);\n\n\treturn bconcat(([bconcat((out)), bconcat(cdirs), o]));\n}\nvar ContentTypeMap = ({\n\t\"htm\": \"text/html\",\n\t\"xml\": \"text/xml\",\n\n\t\"gif\": \"image/gif\",\n\t\"jpg\": \"image/jpeg\",\n\t\"png\": \"image/png\",\n\n\t\"mso\": \"application/x-mso\",\n\t\"thmx\": \"application/vnd.ms-officetheme\",\n\t\"sh33tj5\": \"application/octet-stream\"\n});\n\nfunction get_content_type(fi, fp) {\n\tif(fi.ctype) return fi.ctype;\n\n\tvar ext = fi.name || \"\", m = ext.match(/\\.([^\\.]+)$/);\n\tif(m && ContentTypeMap[m[1]]) return ContentTypeMap[m[1]];\n\n\tif(fp) {\n\t\tm = (ext = fp).match(/[\\.\\\\]([^\\.\\\\])+$/);\n\t\tif(m && ContentTypeMap[m[1]]) return ContentTypeMap[m[1]];\n\t}\n\n\treturn \"application/octet-stream\";\n}\n\n/* 76 character chunks TODO: intertwine encoding */\nfunction write_base64_76(bstr) {\n\tvar data = Base64_encode(bstr);\n\tvar o = [];\n\tfor(var i = 0; i < data.length; i+= 76) o.push(data.slice(i, i+76));\n\treturn o.join(\"\\r\\n\") + \"\\r\\n\";\n}\n\n/*\nRules for QP:\n\t- escape =## applies for all non-display characters and literal \"=\"\n\t- space or tab at end of line must be encoded\n\t- \\r\\n newlines can be preserved, but bare \\r and \\n must be escaped\n\t- lines must not exceed 76 characters, use soft breaks =\\r\\n\n\nTODO: Some files from word appear to write line extensions with bare equals:\n\n```\n<table class=3DMsoTableGrid border=3D1 cellspacing=3D0 cellpadding=3D0 width=\n=\"70%\"\n```\n*/\nfunction write_quoted_printable(text) {\n\tvar encoded = text.replace(/[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7E-\\xFF=]/g, function(c) {\n\t\tvar w = c.charCodeAt(0).toString(16).toUpperCase();\n\t\treturn \"=\" + (w.length == 1 ? \"0\" + w : w);\n\t});\n\n\tencoded = encoded.replace(/ $/mg, \"=20\").replace(/\\t$/mg, \"=09\");\n\n\tif(encoded.charAt(0) == \"\\n\") encoded = \"=0D\" + encoded.slice(1);\n\tencoded = encoded.replace(/\\r(?!\\n)/mg, \"=0D\").replace(/\\n\\n/mg, \"\\n=0A\").replace(/([^\\r\\n])\\n/mg, \"$1=0A\");\n\n\tvar o = [], split = encoded.split(\"\\r\\n\");\n\tfor(var si = 0; si < split.length; ++si) {\n\t\tvar str = split[si];\n\t\tif(str.length == 0) { o.push(\"\"); continue; }\n\t\tfor(var i = 0; i < str.length;) {\n\t\t\tvar end = 76;\n\t\t\tvar tmp = str.slice(i, i + end);\n\t\t\tif(tmp.charAt(end - 1) == \"=\") end --;\n\t\t\telse if(tmp.charAt(end - 2) == \"=\") end -= 2;\n\t\t\telse if(tmp.charAt(end - 3) == \"=\") end -= 3;\n\t\t\ttmp = str.slice(i, i + end);\n\t\t\ti += end;\n\t\t\tif(i < str.length) tmp += \"=\";\n\t\t\to.push(tmp);\n\t\t}\n\t}\n\n\treturn o.join(\"\\r\\n\");\n}\nfunction parse_quoted_printable(data) {\n\tvar o = [];\n\n\t/* unify long lines */\n\tfor(var di = 0; di < data.length; ++di) {\n\t\tvar line = data[di];\n\t\twhile(di <= data.length && line.charAt(line.length - 1) == \"=\") line = line.slice(0, line.length - 1) + data[++di];\n\t\to.push(line);\n\t}\n\n\t/* decode */\n\tfor(var oi = 0; oi < o.length; ++oi) o[oi] = o[oi].replace(/[=][0-9A-Fa-f]{2}/g, function($$) { return String.fromCharCode(parseInt($$.slice(1), 16)); });\n\treturn s2a(o.join(\"\\r\\n\"));\n}\n\n\nfunction parse_mime(cfb, data, root) {\n\tvar fname = \"\", cte = \"\", ctype = \"\", fdata;\n\tvar di = 0;\n\tfor(;di < 10; ++di) {\n\t\tvar line = data[di];\n\t\tif(!line || line.match(/^\\s*$/)) break;\n\t\tvar m = line.match(/^(.*?):\\s*([^\\s].*)$/);\n\t\tif(m) switch(m[1].toLowerCase()) {\n\t\t\tcase \"content-location\": fname = m[2].trim(); break;\n\t\t\tcase \"content-type\": ctype = m[2].trim(); break;\n\t\t\tcase \"content-transfer-encoding\": cte = m[2].trim(); break;\n\t\t}\n\t}\n\t++di;\n\tswitch(cte.toLowerCase()) {\n\t\tcase 'base64': fdata = s2a(Base64_decode(data.slice(di).join(\"\"))); break;\n\t\tcase 'quoted-printable': fdata = parse_quoted_printable(data.slice(di)); break;\n\t\tdefault: throw new Error(\"Unsupported Content-Transfer-Encoding \" + cte);\n\t}\n\tvar file = cfb_add(cfb, fname.slice(root.length), fdata, {unsafe: true});\n\tif(ctype) file.ctype = ctype;\n}\n\nfunction parse_mad(file, options) {\n\tif(a2s(file.slice(0,13)).toLowerCase() != \"mime-version:\") throw new Error(\"Unsupported MAD header\");\n\tvar root = (options && options.root || \"\");\n\t// $FlowIgnore\n\tvar data = (has_buf && Buffer.isBuffer(file) ? file.toString(\"binary\") : a2s(file)).split(\"\\r\\n\");\n\tvar di = 0, row = \"\";\n\n\t/* if root is not specified, scan for the common prefix */\n\tfor(di = 0; di < data.length; ++di) {\n\t\trow = data[di];\n\t\tif(!/^Content-Location:/i.test(row)) continue;\n\t\trow = row.slice(row.indexOf(\"file\"));\n\t\tif(!root) root = row.slice(0, row.lastIndexOf(\"/\") + 1);\n\t\tif(row.slice(0, root.length) == root) continue;\n\t\twhile(root.length > 0) {\n\t\t\troot = root.slice(0, root.length - 1);\n\t\t\troot = root.slice(0, root.lastIndexOf(\"/\") + 1);\n\t\t\tif(row.slice(0,root.length) == root) break;\n\t\t}\n\t}\n\n\tvar mboundary = (data[1] || \"\").match(/boundary=\"(.*?)\"/);\n\tif(!mboundary) throw new Error(\"MAD cannot find boundary\");\n\tvar boundary = \"--\" + (mboundary[1] || \"\");\n\n\tvar FileIndex = [], FullPaths = [];\n\tvar o = {\n\t\tFileIndex: FileIndex,\n\t\tFullPaths: FullPaths\n\t};\n\tinit_cfb(o);\n\tvar start_di, fcnt = 0;\n\tfor(di = 0; di < data.length; ++di) {\n\t\tvar line = data[di];\n\t\tif(line !== boundary && line !== boundary + \"--\") continue;\n\t\tif(fcnt++) parse_mime(o, data.slice(start_di, di), root);\n\t\tstart_di = di;\n\t}\n\treturn o;\n}\n\nfunction write_mad(cfb, options) {\n\tvar opts = options || {};\n\tvar boundary = opts.boundary || \"SheetJS\";\n\tboundary = '------=' + boundary;\n\n\tvar out = [\n\t\t'MIME-Version: 1.0',\n\t\t'Content-Type: multipart/related; boundary=\"' + boundary.slice(2) + '\"',\n\t\t'',\n\t\t'',\n\t\t''\n\t];\n\n\tvar root = cfb.FullPaths[0], fp = root, fi = cfb.FileIndex[0];\n\tfor(var i = 1; i < cfb.FullPaths.length; ++i) {\n\t\tfp = cfb.FullPaths[i].slice(root.length);\n\t\tfi = cfb.FileIndex[i];\n\t\tif(!fi.size || !fi.content || fp == \"\\u0001Sh33tJ5\") continue;\n\n\t\t/* Normalize filename */\n\t\tfp = fp.replace(/[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7E-\\xFF]/g, function(c) {\n\t\t\treturn \"_x\" + c.charCodeAt(0).toString(16) + \"_\";\n\t\t}).replace(/[\\u0080-\\uFFFF]/g, function(u) {\n\t\t\treturn \"_u\" + u.charCodeAt(0).toString(16) + \"_\";\n\t\t});\n\n\t\t/* Extract content as binary string */\n\t\tvar ca = fi.content;\n\t\t// $FlowIgnore\n\t\tvar cstr = has_buf && Buffer.isBuffer(ca) ? ca.toString(\"binary\") : a2s(ca);\n\n\t\t/* 4/5 of first 1024 chars ascii -> quoted printable, else base64 */\n\t\tvar dispcnt = 0, L = Math.min(1024, cstr.length), cc = 0;\n\t\tfor(var csl = 0; csl <= L; ++csl) if((cc=cstr.charCodeAt(csl)) >= 0x20 && cc < 0x80) ++dispcnt;\n\t\tvar qp = dispcnt >= L * 4 / 5;\n\n\t\tout.push(boundary);\n\t\tout.push('Content-Location: ' + (opts.root || 'file:///C:/SheetJS/') + fp);\n\t\tout.push('Content-Transfer-Encoding: ' + (qp ? 'quoted-printable' : 'base64'));\n\t\tout.push('Content-Type: ' + get_content_type(fi, fp));\n\t\tout.push('');\n\n\t\tout.push(qp ? write_quoted_printable(cstr) : write_base64_76(cstr));\n\t}\n\tout.push(boundary + '--\\r\\n');\n\treturn out.join(\"\\r\\n\");\n}\nfunction cfb_new(opts) {\n\tvar o = ({});\n\tinit_cfb(o, opts);\n\treturn o;\n}\n\nfunction cfb_add(cfb, name, content, opts) {\n\tvar unsafe = opts && opts.unsafe;\n\tif(!unsafe) init_cfb(cfb);\n\tvar file = !unsafe && CFB.find(cfb, name);\n\tif(!file) {\n\t\tvar fpath = cfb.FullPaths[0];\n\t\tif(name.slice(0, fpath.length) == fpath) fpath = name;\n\t\telse {\n\t\t\tif(fpath.slice(-1) != \"/\") fpath += \"/\";\n\t\t\tfpath = (fpath + name).replace(\"//\",\"/\");\n\t\t}\n\t\tfile = ({name: filename(name), type: 2});\n\t\tcfb.FileIndex.push(file);\n\t\tcfb.FullPaths.push(fpath);\n\t\tif(!unsafe) CFB.utils.cfb_gc(cfb);\n\t}\nfile.content = (content);\n\tfile.size = content ? content.length : 0;\n\tif(opts) {\n\t\tif(opts.CLSID) file.clsid = opts.CLSID;\n\t\tif(opts.mt) file.mt = opts.mt;\n\t\tif(opts.ct) file.ct = opts.ct;\n\t}\n\treturn file;\n}\n\nfunction cfb_del(cfb, name) {\n\tinit_cfb(cfb);\n\tvar file = CFB.find(cfb, name);\n\tif(file) for(var j = 0; j < cfb.FileIndex.length; ++j) if(cfb.FileIndex[j] == file) {\n\t\tcfb.FileIndex.splice(j, 1);\n\t\tcfb.FullPaths.splice(j, 1);\n\t\treturn true;\n\t}\n\treturn false;\n}\n\nfunction cfb_mov(cfb, old_name, new_name) {\n\tinit_cfb(cfb);\n\tvar file = CFB.find(cfb, old_name);\n\tif(file) for(var j = 0; j < cfb.FileIndex.length; ++j) if(cfb.FileIndex[j] == file) {\n\t\tcfb.FileIndex[j].name = filename(new_name);\n\t\tcfb.FullPaths[j] = new_name;\n\t\treturn true;\n\t}\n\treturn false;\n}\n\nfunction cfb_gc(cfb) { rebuild_cfb(cfb, true); }\n\nexports.find = find;\nexports.read = read;\nexports.parse = parse;\nexports.write = write;\nexports.writeFile = write_file;\nexports.utils = {\n\tcfb_new: cfb_new,\n\tcfb_add: cfb_add,\n\tcfb_del: cfb_del,\n\tcfb_mov: cfb_mov,\n\tcfb_gc: cfb_gc,\n\tReadShift: ReadShift,\n\tCheckField: CheckField,\n\tprep_blob: prep_blob,\n\tbconcat: bconcat,\n\tuse_zlib: use_zlib,\n\t_deflateRaw: _deflate,\n\t_inflateRaw: _inflate,\n\tconsts: consts\n};\n\nreturn exports;\n})();\n\nif(typeof require !== 'undefined' && typeof module !== 'undefined' && typeof DO_NOT_EXPORT_CFB === 'undefined') { module.exports = CFB; }\n","/**\n * OCR CLI 자동 탐색\n *\n * 탐색 순서: gemini → claude → codex → ollama → tesseract.js\n * CLI는 which(unix) / where(win) 명령어로 PATH 존재 확인.\n * tesseract.js는 bundled 의존성이므로 항상 사용 가능 (최후 fallback).\n */\n\nimport { execSync } from \"child_process\"\nimport type { OcrMode } from \"../types.js\"\n\n/** CLI 탐색 우선순위 */\nconst CLI_PRIORITY = [\"gemini\", \"claude\", \"codex\", \"ollama\"] as const\n\n/**\n * 시스템에 설치된 OCR 도구를 우선순위대로 탐색.\n * tesseract.js는 bundled 의존성이므로 CLI를 찾지 못해도 항상 \"tesseract\" 반환.\n * @returns 사용 가능한 OcrMode (null 반환 없음)\n */\nexport function detectAvailableOcr(): OcrMode {\n // 1. CLI 프로그램 탐색 (gemini → claude → codex → ollama)\n for (const cli of CLI_PRIORITY) {\n if (isCliInstalled(cli)) return cli\n }\n\n // 2. tesseract.js — bundled 의존성, 항상 사용 가능\n return \"tesseract\"\n}\n\n/**\n * 특정 CLI가 시스템 PATH에 있는지 확인.\n * which(unix) 또는 where(win32) 사용.\n */\nfunction isCliInstalled(name: string): boolean {\n try {\n const cmd = process.platform === \"win32\" ? \"where\" : \"which\"\n execSync(`${cmd} ${name}`, { stdio: \"ignore\", timeout: 3000 })\n return true\n } catch {\n return false\n }\n}\n\n/**\n * 수동 지정된 OcrMode 유효성 검증.\n * --ocr gemini 등 강제 지정 시 호출.\n * @throws 해당 CLI가 설치되지 않은 경우 Error (tesseract는 항상 통과)\n */\nexport function validateOcrMode(mode: OcrMode): void {\n if (mode === \"auto\" || mode === \"off\" || mode === \"tesseract\") return\n\n if (!isCliInstalled(mode)) {\n throw new Error(`'${mode}' CLI가 설치되지 않았습니다.\\n${getInstallGuide(mode)}`)\n }\n}\n\n/** CLI별 설치 안내 메시지 */\nfunction getInstallGuide(mode: string): string {\n const guides: Record<string, string> = {\n gemini: \"설치: https://ai.google.dev/gemini-api/docs/cli\",\n claude: \"설치: npm install -g @anthropic-ai/claude-code 또는 https://claude.ai/code\",\n codex: \"설치: npm install -g @openai/codex 또는 https://github.com/openai/codex\",\n ollama: \"설치: brew install ollama 또는 https://ollama.com/download\",\n }\n return guides[mode] || `'${mode}'을(를) 설치해주세요.`\n}\n\n/**\n * AI CLI가 없어 tesseract.js로 fallback할 때 표시할 안내 메시지.\n */\nexport function getTesseractFallbackMessage(): string {\n return [\n \"설치된 AI CLI가 없어 내장 tesseract.js로 OCR을 수행합니다.\",\n \"더 나은 품질(테이블/헤딩 구조 보존)을 위해 AI CLI 설치를 권장합니다:\",\n \"\",\n \" [권장] Gemini CLI: https://ai.google.dev/gemini-api/docs/cli\",\n \" Claude CLI: npm install -g @anthropic-ai/claude-code\",\n \" Codex CLI: npm install -g @openai/codex\",\n \" Ollama: brew install ollama (+ ollama pull gemma4:27b)\",\n ].join(\"\\n\")\n}\n","/**\n * CLI 기반 OCR 프로바이더\n *\n * gemini / claude / codex / ollama CLI를 subprocess로 호출하여\n * PDF 페이지 이미지를 Markdown으로 변환.\n *\n * 이미지 전달 방식:\n * - gemini: -p \"프롬프트 @이미지경로\" (@ 파일 참조)\n * - claude: -p \"프롬프트 @이미지경로\" (@ 파일 참조, --print 모드)\n * - codex: exec -i 이미지경로 \"프롬프트\" (-i/--image 플래그)\n * - ollama: REST API (localhost:11434) — CLI는 이미지 입력 미지원\n */\n\nimport { spawnSync } from \"child_process\"\nimport { writeFileSync, readFileSync, unlinkSync, mkdirSync } from \"fs\"\nimport { join } from \"path\"\nimport { tmpdir } from \"os\"\nimport type { OcrMode, StructuredOcrResult } from \"../types.js\"\n\n/** OCR 프롬프트 — 모든 CLI 공통 */\nconst OCR_PROMPT =\n \"이 PDF 페이지 이미지에서 텍스트와 테이블을 추출하여 순수 Markdown으로 변환하세요.\\n\" +\n \"규칙:\\n\" +\n \"- 테이블은 Markdown 테이블 문법 사용 (| 구분, |---|---| 헤더 구분선 포함)\\n\" +\n \"- 병합된 셀은 해당 위치에 내용 기재\\n\" +\n \"- 헤딩은 글자 크기에 따라 ## ~ ###### 사용\\n\" +\n \"- 리스트는 - 또는 1. 사용\\n\" +\n \"- 이미지, 도형 등 비텍스트 요소는 무시\\n\" +\n \"- 원문의 읽기 순서와 구조를 유지\\n\" +\n \"- ```로 감싸지 말고 순수 Markdown만 출력\"\n\n/** 임시 디렉토리 (프로세스당 1회 생성)\n *\n * gemini CLI는 /tmp/ 등 시스템 임시 디렉토리를 워크스페이스 외부로 간주하여\n * @파일참조 시 접근을 거부할 수 있음. cwd 하위 폴더를 사용하면 모든 CLI에서 접근 가능.\n */\nlet _tempDir: string | null = null\nfunction getTempDir(): string {\n if (!_tempDir) {\n _tempDir = join(process.cwd(), \".kordoc-tmp\")\n mkdirSync(_tempDir, { recursive: true })\n }\n return _tempDir\n}\n\n/**\n * CLI OcrProvider 생성.\n *\n * @param mode - 사용할 CLI (gemini, claude, codex, ollama)\n * @returns OcrProvider 함수 (StructuredOcrResult 반환)\n */\nexport function createCliOcrProvider(\n mode: Exclude<OcrMode, \"auto\" | \"off\" | \"tesseract\">\n): (pageImage: Uint8Array, pageNumber: number, mimeType: \"image/png\") => Promise<StructuredOcrResult> {\n return async (pageImage: Uint8Array, pageNumber: number): Promise<StructuredOcrResult> => {\n const tempPath = join(getTempDir(), `page-${pageNumber}.png`)\n\n try {\n writeFileSync(tempPath, pageImage)\n\n let output: string\n if (mode === \"ollama\") {\n output = await callOllamaApi(tempPath)\n } else {\n output = callCli(mode, tempPath)\n }\n\n return { markdown: stripCodeFence(output.trim()) }\n } finally {\n try { unlinkSync(tempPath) } catch { /* 임시 파일 정리 실패 무시 */ }\n }\n }\n}\n\n/**\n * CLI 실행 — gemini / claude / codex\n *\n * @throws CLI 실행 실패 또는 타임아웃(60초) 시 Error\n */\nfunction callCli(mode: string, imagePath: string): string {\n // codex는 --output-last-message로 대화 헤더 없는 깔끔한 출력 사용\n if (mode === \"codex\") {\n return callCodexCli(imagePath)\n }\n\n const args = buildCliArgs(mode, imagePath)\n\n const result = spawnSync(mode, args, {\n encoding: \"utf-8\",\n timeout: 60_000,\n maxBuffer: 10 * 1024 * 1024,\n })\n\n if (result.error) {\n throw new Error(`${mode} CLI 실행 실패: ${result.error.message}`)\n }\n if (result.status !== 0) {\n const errMsg = result.stderr?.trim() || `exit code ${result.status}`\n throw new Error(`${mode} OCR 실패: ${errMsg}`)\n }\n\n return result.stdout || \"\"\n}\n\n/**\n * codex exec 실행 — --output-last-message로 대화 헤더 없는 깔끔한 출력.\n * 인자 순서: `codex exec <prompt> --image <file> --output-last-message <outfile>`\n */\nfunction callCodexCli(imagePath: string): string {\n // 출력 파일은 /tmp/ 사용 — codex sandbox는 cwd 내 쓰기를 막을 수 있음\n const outPath = join(tmpdir(), `kordoc-codex-out-${Date.now()}.txt`)\n try {\n const args = [\"exec\", OCR_PROMPT, \"--image\", imagePath, \"--output-last-message\", outPath]\n\n const result = spawnSync(\"codex\", args, {\n encoding: \"utf-8\",\n timeout: 180_000,\n maxBuffer: 10 * 1024 * 1024,\n input: \"\", // stdin EOF 즉시 전달 (대화형 입력 차단)\n })\n\n if (result.error) {\n throw new Error(`codex CLI 실행 실패: ${result.error.message}`)\n }\n if (result.status !== 0) {\n const errMsg = result.stderr?.trim() || `exit code ${result.status}`\n throw new Error(`codex OCR 실패: ${errMsg}`)\n }\n\n // --output-last-message 파일에서 읽기 (없으면 stdout 폴백)\n try {\n return readFileSync(outPath, \"utf-8\")\n } catch {\n return result.stdout || \"\"\n }\n } finally {\n try { unlinkSync(outPath) } catch { /* 무시 */ }\n }\n}\n\n/**\n * CLI별 인자 배열 생성.\n *\n * gemini: [\"--prompt\", \"프롬프트 @이미지경로\", \"--yolo\"]\n * - -y/--yolo: 자동 승인 (OCR은 도구 사용 없으므로 실질적 영향 없음)\n * - @ 파일 참조로 이미지를 컨텍스트에 포함\n *\n * claude: [\"--print\", \"프롬프트 @이미지경로\"]\n * - --print(-p): 비대화형 출력 모드\n * - @ 파일 참조로 이미지를 컨텍스트에 포함\n *\n * codex: callCodexCli()에서 별도 처리\n * - `codex exec <prompt> --image <file> --output-last-message <outfile>`\n * - 프롬프트가 --image보다 앞에 위치해야 함 (인자 순서 중요)\n *\n * ⚠️ CLI 버전에 따라 문법이 다를 수 있음. 업데이트 시 --help 재확인 필요.\n */\nfunction buildCliArgs(mode: string, imagePath: string): string[] {\n const promptWithImage = `${OCR_PROMPT}\\n\\n이미지: @${imagePath}`\n\n switch (mode) {\n case \"gemini\":\n return [\"--prompt\", promptWithImage, \"--yolo\"]\n\n case \"claude\":\n return [\"--print\", promptWithImage]\n\n default:\n throw new Error(`지원하지 않는 CLI: ${mode}`)\n }\n}\n\n/**\n * Ollama REST API 호출 — CLI는 이미지 입력을 지원하지 않으므로 API 직접 사용.\n *\n * 기본 모델: KORDOC_OLLAMA_MODEL 환경변수 또는 \"gemma4:27b\"\n * 기본 호스트: KORDOC_OLLAMA_HOST 환경변수 또는 \"http://localhost:11434\"\n *\n * @throws Ollama 서버 미실행 또는 응답 오류 시 Error\n */\nasync function callOllamaApi(imagePath: string): Promise<string> {\n const { readFileSync } = await import(\"fs\")\n const imageBase64 = readFileSync(imagePath).toString(\"base64\")\n\n const model = process.env.KORDOC_OLLAMA_MODEL || \"qwen3-vl:8b\"\n const host = process.env.KORDOC_OLLAMA_HOST || \"http://localhost:11434\"\n const timeoutMs = Number(process.env.KORDOC_OLLAMA_TIMEOUT) || 120_000\n\n const response = await fetch(`${host}/api/chat`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n model,\n messages: [{\n role: \"user\",\n content: OCR_PROMPT,\n images: [imageBase64],\n }],\n stream: false,\n }),\n signal: AbortSignal.timeout(timeoutMs),\n })\n\n if (!response.ok) {\n throw new Error(`Ollama API 오류: ${response.status} ${response.statusText}`)\n }\n\n const data = await response.json() as { message?: { content?: string } }\n return data.message?.content || \"\"\n}\n\n/**\n * LLM 출력에서 코드 펜스 제거.\n * LLM이 가끔 결과를 ```markdown ... ``` 으로 감싸는 경우 처리.\n */\nfunction stripCodeFence(text: string): string {\n const match = text.match(/^```(?:markdown|md)?\\s*\\n([\\s\\S]*?)\\n```\\s*$/m)\n return match ? match[1].trim() : text\n}\n","/**\n * Tesseract.js 기반 OCR 프로바이더\n *\n * tesseract.js는 bundled 의존성으로 별도 설치 불필요.\n * Vision LLM CLI가 없을 때의 최후 fallback으로 자동 사용.\n *\n * 특성:\n * - 순수 텍스트만 반환 (테이블/헤딩 구조 복원 불가)\n * - 한글 인식률 약 85-90% (깨끗한 이미지 기준)\n * - 완전 오프라인 동작 (API 키 불필요)\n */\n\nimport { createWorker } from \"tesseract.js\"\nimport type { OcrProvider } from \"../types.js\"\n\n/**\n * Tesseract.js OcrProvider 생성.\n *\n * 워커를 1회 생성하여 재사용 (매 페이지마다 초기화 방지).\n * 문서 처리 완료 후 terminate()로 워커 정리.\n *\n * @returns OcrProvider 함수 (+ terminate 메서드)\n */\nexport async function createTesseractProvider(): Promise<OcrProvider & { terminate: () => Promise<void> }> {\n // kor+eng: 한글 + 영문 동시 인식 (한국 공문서 특성)\n const worker = await createWorker(\"kor+eng\")\n let terminated = false\n\n const provider = async (\n pageImage: Uint8Array,\n _pageNumber: number,\n _mimeType: \"image/png\"\n ): Promise<string> => {\n const { data } = await worker.recognize(pageImage)\n return data.text\n }\n\n ;(provider as OcrProvider & { terminate: () => Promise<void> }).terminate = async () => {\n if (!terminated) {\n await worker.terminate()\n terminated = true\n }\n }\n\n return provider as OcrProvider & { terminate: () => Promise<void> }\n}\n","/**\n * OCR 프로바이더 팩토리\n *\n * ocrMode에 따라 적절한 OcrProvider를 생성하여 반환.\n * - \"auto\": 설치된 CLI 자동 탐색 (gemini → claude → codex → ollama → tesseract)\n * tesseract.js는 bundled 의존성이므로 항상 사용 가능 (null 반환 없음)\n * - 특정 CLI: 해당 CLI 사용 (미설치 시 에러)\n * - \"tesseract\": 내장 tesseract.js 직접 사용\n * - \"off\": 에러 throw\n */\n\nimport type { OcrMode, OcrProvider, ParseWarning } from \"../types.js\"\nimport { detectAvailableOcr, validateOcrMode, getTesseractFallbackMessage } from \"./auto-detect.js\"\nimport { createCliOcrProvider } from \"./cli-provider.js\"\n\n/**\n * ocrMode에 따라 OcrProvider를 생성.\n *\n * @param mode - OCR 모드\n * @param warnings - 경고 수집 배열 (fallback 발생 시 경고 추가)\n * @returns OcrProvider 함수\n * @throws mode=\"off\"이거나 지정 CLI 미설치 시 Error\n */\nexport async function resolveOcrProvider(\n mode: OcrMode,\n warnings?: ParseWarning[]\n): Promise<OcrProvider> {\n if (mode === \"off\") {\n throw new Error(\"OCR이 비활성화되어 있습니다 (--ocr off).\")\n }\n\n // ── 수동 지정 모드 ──────────────────────────────────\n if (mode !== \"auto\") {\n validateOcrMode(mode) // tesseract는 항상 통과\n\n if (mode === \"tesseract\") {\n const { createTesseractProvider } = await import(\"./tesseract-provider.js\")\n return createTesseractProvider()\n }\n\n return createCliOcrProvider(mode)\n }\n\n // ── 자동 탐색 모드 ───────────────────────────────────\n // detectAvailableOcr()는 항상 값을 반환 (tesseract fallback으로 null 없음)\n const detected = detectAvailableOcr()\n\n // gemini가 아닌 경우 fallback 경고\n if (detected !== \"gemini\") {\n if (detected === \"tesseract\") {\n // 내장 tesseract로 fallback — 구조 복원 제한 안내\n warnings?.push({\n message: getTesseractFallbackMessage(),\n code: \"OCR_CLI_FALLBACK\",\n })\n } else {\n warnings?.push({\n message: `OCR: '${detected}' 사용 중 (gemini CLI가 없어 fallback). 더 나은 품질을 위해 gemini CLI 설치를 권장합니다.`,\n code: \"OCR_CLI_FALLBACK\",\n })\n }\n }\n\n if (detected === \"tesseract\") {\n const { createTesseractProvider } = await import(\"./tesseract-provider.js\")\n return createTesseractProvider()\n }\n\n return createCliOcrProvider(detected)\n}\n","/**\n * Markdown → IRBlock[] 역파싱\n *\n * Vision LLM(gemini/claude/codex 등)이 반환한 Markdown 문자열을\n * kordoc의 IRBlock[] 중간 표현으로 변환.\n * 기존 blocksToMarkdown()의 역방향 처리.\n */\n\nimport type { IRBlock, IRTable, IRCell } from \"../types.js\"\n\n/**\n * Markdown 문자열을 IRBlock[] 배열로 변환.\n *\n * 지원 요소:\n * - 헤딩: # ~ ######\n * - 테이블: | col1 | col2 | (파이프 구분, |---|---| 구분선 포함)\n * - 순서/비순서 리스트: - / 1.\n * - 구분선: ---, ***, ___\n * - 일반 텍스트 (paragraph)\n */\nexport function markdownToBlocks(markdown: string, pageNumber: number): IRBlock[] {\n const blocks: IRBlock[] = []\n const lines = markdown.split(\"\\n\")\n let i = 0\n\n while (i < lines.length) {\n const line = lines[i]\n\n // 빈 줄 스킵\n if (line.trim() === \"\") {\n i++\n continue\n }\n\n // 1. 헤딩: # ~ ######\n const headingMatch = line.match(/^(#{1,6})\\s+(.+)$/)\n if (headingMatch) {\n blocks.push({\n type: \"heading\",\n level: headingMatch[1].length,\n text: headingMatch[2].trim(),\n pageNumber,\n })\n i++\n continue\n }\n\n // 2. 구분선: ---, ***, ___\n if (/^[-*_]{3,}\\s*$/.test(line.trim())) {\n blocks.push({ type: \"separator\", pageNumber })\n i++\n continue\n }\n\n // 3. 테이블: | 로 시작하는 연속 행 수집\n if (line.trim().startsWith(\"|\")) {\n const tableLines: string[] = []\n while (i < lines.length && lines[i].trim().startsWith(\"|\")) {\n tableLines.push(lines[i])\n i++\n }\n const table = parseMarkdownTable(tableLines)\n if (table) {\n blocks.push({ type: \"table\", table, pageNumber })\n }\n continue\n }\n\n // 4. 비순서 리스트: -, *, +\n const ulMatch = line.match(/^(\\s*)[-*+]\\s+(.+)$/)\n if (ulMatch) {\n blocks.push({\n type: \"list\",\n listType: \"unordered\",\n text: ulMatch[2].trim(),\n pageNumber,\n })\n i++\n continue\n }\n\n // 5. 순서 리스트: 1.\n const olMatch = line.match(/^(\\s*)\\d+\\.\\s+(.+)$/)\n if (olMatch) {\n blocks.push({\n type: \"list\",\n listType: \"ordered\",\n text: olMatch[2].trim(),\n pageNumber,\n })\n i++\n continue\n }\n\n // 6. 일반 텍스트 — 구조적 행이 나올 때까지 병합\n const paraLines: string[] = []\n while (i < lines.length && lines[i].trim() !== \"\" && !isStructuralLine(lines[i])) {\n paraLines.push(lines[i].trim())\n i++\n }\n if (paraLines.length > 0) {\n blocks.push({\n type: \"paragraph\",\n text: paraLines.join(\"\\n\"),\n pageNumber,\n })\n }\n }\n\n return blocks\n}\n\n/**\n * 구조적 행 판별 — paragraph 병합 중단 트리거.\n */\nfunction isStructuralLine(line: string): boolean {\n if (/^#{1,6}\\s+/.test(line)) return true\n if (line.trim().startsWith(\"|\")) return true\n if (/^[-*_]{3,}\\s*$/.test(line.trim())) return true\n if (/^\\s*[-*+]\\s+/.test(line)) return true\n if (/^\\s*\\d+\\.\\s+/.test(line)) return true\n return false\n}\n\n/**\n * Markdown 테이블 행 배열을 IRTable로 변환.\n *\n * 구분선 행(|---|---|)은 제거 후 데이터 행만 파싱.\n * hasHeader: 구분선이 있었으면 true.\n */\nfunction parseMarkdownTable(lines: string[]): IRTable | null {\n const hasSeparator = lines.some(line => /^\\|[\\s:|-]+\\|$/.test(line.trim()))\n\n const rows: IRCell[][] = []\n let maxCols = 0\n\n for (const line of lines) {\n // 구분선 행 스킵: |---|---| 패턴\n if (/^\\|\\s*:?-+:?\\s*(\\|\\s*:?-+:?\\s*)+\\|?\\s*$/.test(line.trim())) continue\n\n const parts = line.split(\"|\")\n // 앞뒤 빈 요소 제거 (| 로 시작/종료하는 행)\n const cells: IRCell[] = parts\n .slice(1, parts[parts.length - 1].trim() === \"\" ? -1 : undefined)\n .map(cell => ({\n text: cell.trim(),\n colSpan: 1,\n rowSpan: 1,\n }))\n\n if (cells.length > 0) {\n rows.push(cells)\n maxCols = Math.max(maxCols, cells.length)\n }\n }\n\n if (rows.length === 0) return null\n\n // 열 수 통일 (부족한 셀은 빈 셀로 채움)\n for (const row of rows) {\n while (row.length < maxCols) {\n row.push({ text: \"\", colSpan: 1, rowSpan: 1 })\n }\n }\n\n return {\n rows: rows.length,\n cols: maxCols,\n cells: rows,\n hasHeader: hasSeparator && rows.length > 1,\n }\n}\n","/**\n * OCR 프로바이더 브릿지 — PDF 페이지를 이미지로 렌더링하여 OCR 호출\n *\n * kordoc은 OCR 라이브러리를 번들하지 않음.\n * 사용자가 OcrProvider 함수를 제공하면 이미지 기반 PDF도 텍스트 추출 가능.\n *\n * @example\n * ```ts\n * import { parse } from \"kordoc\"\n *\n * const result = await parse(buffer, {\n * ocr: async (pageImage, pageNumber, mimeType) => {\n * // Tesseract, Claude Vision, Google Vision 등 사용\n * return await myOcrService.recognize(pageImage)\n * }\n * })\n * ```\n */\n\nimport type { OcrProvider, IRBlock, ParseWarning, StructuredOcrResult } from \"../types.js\"\nimport { markdownToBlocks } from \"./markdown-to-blocks.js\"\n\n/**\n * 이미지 기반 PDF 페이지에 OCR을 적용하여 IRBlock[] 반환.\n *\n * pdfjs page 객체에서 viewport + render를 통해 PNG 생성 후\n * 사용자 제공 OcrProvider 호출.\n *\n * - string 반환: 단순 텍스트 → paragraph 블록\n * - StructuredOcrResult 반환: Markdown → markdownToBlocks()로 구조화\n *\n * canvas 미설치 시 pdfjs render 불가하므로 에러 반환.\n */\nexport async function ocrPages(\n doc: { numPages: number; getPage(n: number): Promise<PdfPageProxy> },\n provider: OcrProvider,\n pageFilter: Set<number> | null,\n effectivePageCount: number,\n warnings?: ParseWarning[]\n): Promise<IRBlock[]> {\n const blocks: IRBlock[] = []\n\n for (let i = 1; i <= effectivePageCount; i++) {\n if (pageFilter && !pageFilter.has(i)) continue\n const page = await doc.getPage(i)\n try {\n const imageData = await renderPageToPng(page)\n const result = await provider(imageData, i, \"image/png\")\n\n if (typeof result === \"string\") {\n // 기존 동작: 순수 텍스트 → paragraph 블록\n if (result.trim()) {\n blocks.push({ type: \"paragraph\", text: result.trim(), pageNumber: i })\n }\n } else if (result && typeof result === \"object\" && \"markdown\" in result) {\n // 신규: 구조화된 결과 → Markdown → IRBlock[]\n const structured = result as StructuredOcrResult\n if (structured.markdown.trim()) {\n const pageBlocks = markdownToBlocks(structured.markdown, i)\n for (const b of pageBlocks) blocks.push(b)\n }\n }\n } catch (err) {\n // 개별 페이지 실패 시 경고 발행 후 계속 진행\n warnings?.push({\n page: i,\n message: `페이지 ${i} OCR 실패: ${err instanceof Error ? err.message : \"알 수 없는 오류\"}`,\n code: \"OCR_PAGE_FAILED\",\n })\n }\n }\n\n return blocks\n}\n\ninterface PdfPageProxy {\n getViewport(params: { scale: number }): { width: number; height: number }\n render(params: { canvasContext: unknown; viewport: unknown }): { promise: Promise<void> }\n}\n\n/**\n * PDF 페이지를 PNG로 렌더링.\n * @napi-rs/canvas 사용 (kordoc 번들 의존성, 별도 설치 불필요)\n */\nasync function renderPageToPng(page: PdfPageProxy): Promise<Uint8Array> {\n const { createCanvas } = await import(\"@napi-rs/canvas\")\n\n const scale = 2.0 // 300 DPI 근사\n const viewport = page.getViewport({ scale })\n const canvas = createCanvas(Math.floor(viewport.width), Math.floor(viewport.height))\n const ctx = canvas.getContext(\"2d\")\n\n await page.render({ canvasContext: ctx as unknown, viewport }).promise\n return new Uint8Array(canvas.toBuffer(\"image/png\"))\n}\n","/**\n * kordoc — 모두 파싱해버리겠다\n *\n * HWP, HWPX, PDF → Markdown 변환 통합 라이브러리\n */\n\nimport { readFile } from \"fs/promises\"\nimport { detectFormat, detectZipFormat, isHwpxFile, isOldHwpFile, isPdfFile, isZipFile } from \"./detect.js\"\nimport { parseHwpxDocument } from \"./hwpx/parser.js\"\nimport { parseHwp5Document } from \"./hwp5/parser.js\"\nimport { parsePdfDocument } from \"./pdf/parser.js\"\nimport { parseXlsxDocument } from \"./xlsx/parser.js\"\nimport { parseDocxDocument } from \"./docx/parser.js\"\nimport type { ParseResult, ParseOptions } from \"./types.js\"\nimport { classifyError, toArrayBuffer } from \"./utils.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 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 switch (format) {\n case \"hwpx\": {\n // ZIP 기반 포맷 세분화: HWPX, XLSX, DOCX 구분\n const zipFormat = await detectZipFormat(buffer)\n if (zipFormat === \"xlsx\") return parseXlsx(buffer, options)\n if (zipFormat === \"docx\") return parseDocx(buffer, options)\n return parseHwpx(buffer, options)\n }\n case \"hwp\":\n return parseHwp(buffer, options)\n case \"pdf\":\n return parsePdf(buffer, options)\n default:\n return { success: false, fileType: \"unknown\", error: \"지원하지 않는 파일 형식입니다.\", code: \"UNSUPPORTED_FORMAT\" }\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 }\n } catch (err) {\n return { success: false, fileType: \"hwpx\", error: err instanceof Error ? err.message : \"HWPX 파싱 실패\", 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 return { success: true, fileType: \"hwp\", markdown, blocks, metadata, outline, warnings, images: images?.length ? images : undefined }\n } catch (err) {\n return { success: false, fileType: \"hwp\", error: err instanceof Error ? err.message : \"HWP 파싱 실패\", code: classifyError(err) }\n }\n}\n\n/** PDF 파일에서 텍스트를 추출하여 Markdown으로 변환 */\nexport async function parsePdf(buffer: ArrayBuffer, options?: ParseOptions): Promise<ParseResult> {\n try {\n const { markdown, blocks, metadata, outline, warnings, isImageBased } = await parsePdfDocument(buffer, options)\n return { success: true, fileType: \"pdf\", markdown, blocks, metadata, outline, warnings, isImageBased }\n } catch (err) {\n const isImageBased = err instanceof Error && \"isImageBased\" in err ? true : undefined\n return { success: false, fileType: \"pdf\", error: err instanceof Error ? err.message : \"PDF 파싱 실패\", 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 }\n } catch (err) {\n return { success: false, fileType: \"xlsx\", error: err instanceof Error ? err.message : \"XLSX 파싱 실패\", 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 }\n } catch (err) {\n return { success: false, fileType: \"docx\", error: err instanceof Error ? err.message : \"DOCX 파싱 실패\", code: classifyError(err) }\n }\n}\n\n// ─── 게임체인저 API ─────────────────────────────────\n\nexport { compare, diffBlocks } from \"./diff/compare.js\"\nexport { extractFormFields } from \"./form/recognize.js\"\nexport { markdownToHwpx } from \"./hwpx/generator.js\"\nexport { markdownToXlsx } from \"./xlsx/generator.js\"\nexport type { MarkdownToXlsxOptions } from \"./xlsx/generator.js\"\n\n// ─── Re-exports ──────────────────────────────────────\n\nexport { detectFormat, detectZipFormat, isHwpxFile, isOldHwpFile, isPdfFile, isZipFile } from \"./detect.js\"\nexport type {\n ParseResult, ParseSuccess, ParseFailure, FileType,\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, OcrMode, StructuredOcrResult, WatchOptions,\n} from \"./types.js\"\nexport { blocksToMarkdown } from \"./table/builder.js\"\nexport { VERSION } from \"./utils.js\"\n","/** 매직 바이트 기반 파일 포맷 감지 */\n\nimport JSZip from \"jszip\"\nimport type { FileType } from \"./types.js\"\n\n/** 매직 바이트 뷰 생성 (복사 없이 view) */\nfunction magicBytes(buffer: ArrayBuffer): Uint8Array {\n return new Uint8Array(buffer, 0, Math.min(4, buffer.byteLength))\n}\n\n/** ZIP 파일 여부: PK\\x03\\x04 */\nexport function isZipFile(buffer: ArrayBuffer): boolean {\n const b = magicBytes(buffer)\n return b[0] === 0x50 && b[1] === 0x4b && b[2] === 0x03 && b[3] === 0x04\n}\n\n/** HWPX (ZIP 기반 한컴 문서): PK\\x03\\x04 — 하위 호환용 */\nexport function isHwpxFile(buffer: ArrayBuffer): boolean {\n return isZipFile(buffer)\n}\n\n/** HWP 5.x (OLE2 바이너리 한컴 문서): \\xD0\\xCF\\x11\\xE0 */\nexport function isOldHwpFile(buffer: ArrayBuffer): boolean {\n const b = magicBytes(buffer)\n return b[0] === 0xd0 && b[1] === 0xcf && b[2] === 0x11 && b[3] === 0xe0\n}\n\n/** PDF 문서: %PDF */\nexport function isPdfFile(buffer: ArrayBuffer): boolean {\n const b = magicBytes(buffer)\n return b[0] === 0x25 && b[1] === 0x50 && b[2] === 0x44 && b[3] === 0x46\n}\n\n/** 동기 포맷 감지 — ZIP은 모두 \"hwpx\"로 반환 (하위 호환) */\nexport function detectFormat(buffer: ArrayBuffer): FileType {\n if (buffer.byteLength < 4) return \"unknown\"\n if (isZipFile(buffer)) return \"hwpx\"\n if (isOldHwpFile(buffer)) return \"hwp\"\n if (isPdfFile(buffer)) return \"pdf\"\n return \"unknown\"\n}\n\n/**\n * ZIP 내부 구조 기반 포맷 세분화.\n * HWPX, XLSX, DOCX 모두 ZIP이므로 내부 파일로 구분.\n */\nexport async function detectZipFormat(buffer: ArrayBuffer): Promise<\"hwpx\" | \"xlsx\" | \"docx\" | \"unknown\"> {\n try {\n const zip = await JSZip.loadAsync(buffer)\n // XLSX: xl/workbook.xml\n if (zip.file(\"xl/workbook.xml\")) return \"xlsx\"\n // DOCX: word/document.xml\n if (zip.file(\"word/document.xml\")) return \"docx\"\n // HWPX: Contents/ 또는 content.hpf 또는 mimetype\n if (zip.file(\"Contents/content.hpf\") || zip.file(\"mimetype\")) return \"hwpx\"\n // 기타 ZIP 내에 section 파일이 있으면 HWPX로 추정\n const hasSection = Object.keys(zip.files).some(f => f.startsWith(\"Contents/\"))\n if (hasSection) return \"hwpx\"\n return \"unknown\"\n } catch {\n return \"unknown\"\n }\n}\n","/**\n * HWPX 파서 — manifest 멀티섹션, colSpan/rowSpan, 중첩테이블\n *\n * lexdiff 기반 + edu-facility-ai 손상ZIP 복구\n */\n\nimport JSZip from \"jszip\"\n\nimport { DOMParser } from \"@xmldom/xmldom\"\nimport { buildTable, convertTableToText, blocksToMarkdown, MAX_COLS, MAX_ROWS } from \"../table/builder.js\"\nimport type { CellContext, IRBlock, DocumentMetadata, InternalParseResult, ParseOptions, ParseWarning, OutlineItem, InlineStyle, ExtractedImage } from \"../types.js\"\nimport { HEADING_RATIO_H1, HEADING_RATIO_H2, HEADING_RATIO_H3 } from \"../types.js\"\nimport { KordocError, isPathTraversal, sanitizeHref, precheckZipSize } from \"../utils.js\"\n// 테스트 호환성 re-export\nexport { precheckZipSize } from \"../utils.js\"\nimport { parsePageRange } from \"../page-range.js\"\n\n/** 압축 해제 최대 크기 (500MB) — ZIP bomb 방지 */\nconst MAX_DECOMPRESS_SIZE = 500 * 1024 * 1024\n/** 손상 ZIP 복구 시 최대 엔트리 수 */\nconst MAX_ZIP_ENTRIES = 2000\n\n/** colSpan/rowSpan을 안전한 범위로 클램핑 */\nfunction clampSpan(val: number, max: number): number {\n return Math.max(1, Math.min(val, max))\n}\n\n/** XML DOM 재귀 최대 깊이 — 악성 파일의 스택 오버플로 방지 */\nconst MAX_XML_DEPTH = 200\n\ninterface TableState { rows: CellContext[][]; currentRow: CellContext[]; cell: CellContext | null }\n\n/** xmldom DOMParser 생성 — onError 콜백으로 malformed XML 경고 수집 */\nfunction createXmlParser(warnings?: ParseWarning[]): DOMParser {\n return new DOMParser({\n onError(level: \"warn\" | \"error\" | \"fatalError\", msg: string) {\n if (level === \"fatalError\") throw new KordocError(`XML 파싱 실패: ${msg}`)\n warnings?.push({ code: \"MALFORMED_XML\", message: `XML ${level === \"warn\" ? \"경고\" : \"오류\"}: ${msg}` })\n },\n })\n}\n\n// ─── HWPX 스타일 정보 ──────────────────────────────\n\ninterface HwpxCharProperty {\n fontSize?: number // 단위: pt (hwpx는 centi-pt → /100)\n bold?: boolean\n italic?: boolean\n fontName?: string\n}\n\ninterface HwpxStyleMap {\n charProperties: Map<string, HwpxCharProperty> // id → property\n styles: Map<string, { name: string; charPrId?: string; paraPrId?: string }> // id → style\n}\n\n/** head.xml 또는 header.xml에서 스타일 정보 추출 */\nasync function extractHwpxStyles(zip: JSZip, decompressed?: { total: number }): Promise<HwpxStyleMap> {\n const result: HwpxStyleMap = {\n charProperties: new Map(),\n styles: 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\n // charProperties 파싱\n parseCharProperties(doc, result.charProperties)\n // styles 파싱\n parseStyleElements(doc, result.styles)\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) prop.fontSize = parseInt(height, 10) / 100\n\n // bold/italic\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\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/** XXE/Billion Laughs 방지 — DOCTYPE 제거 (내부 DTD 서브셋 포함) */\nfunction stripDtd(xml: string): string {\n return xml.replace(/<!DOCTYPE\\s[^[>]*(\\[[\\s\\S]*?\\])?\\s*>/gi, \"\")\n}\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 await 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 // 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 metadata.pageCount = sectionPaths.length\n\n // 페이지 범위 필터링 (섹션 단위 근사치)\n const pageFilter = options?.pages ? parsePageRange(options.pages, sectionPaths.length) : null\n const totalTarget = pageFilter ? pageFilter.size : sectionPaths.length\n const blocks: IRBlock[] = []\n let parsedSections = 0\n for (let si = 0; si < sectionPaths.length; si++) {\n if (pageFilter && !pageFilter.has(si + 1)) continue\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 KordocError(\"ZIP 압축 해제 크기 초과 (ZIP bomb 의심)\")\n blocks.push(...parseSectionXml(xml, styleMap, warnings, si + 1))\n parsedSections++\n options?.onProgress?.(parsedSections, totalTarget)\n } catch (secErr) {\n if (secErr instanceof KordocError) throw secErr\n warnings.push({ page: si + 1, message: `섹션 ${si + 1} 파싱 실패: ${secErr instanceof Error ? secErr.message : \"알 수 없는 오류\"}`, code: \"PARTIAL_PARSE\" })\n }\n }\n\n // 이미지 블록에서 ZIP 바이너리 추출\n const images = await extractImagesFromZip(zip, blocks, decompressed, warnings)\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\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 detectImageMimeFromBytes(data: Uint8Array): string {\n if (data.length >= 3 && data[0] === 0xFF && data[1] === 0xD8 && data[2] === 0xFF) return \"image/jpeg\"\n if (data.length >= 4 && data[0] === 0x89 && data[1] === 0x50 && data[2] === 0x4E && data[3] === 0x47) return \"image/png\"\n if (data.length >= 3 && data[0] === 0x47 && data[1] === 0x49 && data[2] === 0x46) return \"image/gif\"\n if (data.length >= 2 && data[0] === 0x42 && data[1] === 0x4D) return \"image/bmp\"\n // WMF Placeable: D7 CD C6 9A\n if (data.length >= 4 && data[0] === 0xD7 && data[1] === 0xCD && data[2] === 0xC6 && data[3] === 0x9A) return \"image/wmf\"\n // WMF Standard: type(01/02) + 00 + 09 + 00\n if (data.length >= 4 && (data[0] === 0x01 || data[0] === 0x02) && data[1] === 0x00 && data[2] === 0x09 && data[3] === 0x00) return \"image/wmf\"\n // EMF: 01 00 00 00\n if (data.length >= 4 && data[0] === 0x01 && data[1] === 0x00 && data[2] === 0x00 && data[3] === 0x00) return \"image/emf\"\n return \"image/png\"\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/** blocks에서 type=\"image\" 블록의 참조를 ZIP에서 실제 바이너리로 변환 */\nasync function extractImagesFromZip(\n zip: JSZip,\n blocks: IRBlock[],\n decompressed: { total: number },\n warnings?: ParseWarning[],\n): Promise<ExtractedImage[]> {\n const images: ExtractedImage[] = []\n let imageIndex = 0\n\n for (const block of blocks) {\n if (block.type !== \"image\" || !block.text) continue\n\n const ref = block.text\n // BinData/ 폴더 내에서 참조 파일 찾기\n // ref에 확장자가 없는 경우 ZIP 목록에서 일치하는 파일 탐색\n const exts = ref.includes(\".\") ? [\"\"] : [\".jpg\", \".jpeg\", \".png\", \".bmp\", \".gif\", \".wmf\", \".emf\", \".tif\", \"\"]\n const candidates = exts.flatMap(ext => [\n `BinData/${ref}${ext}`,\n `Contents/BinData/${ref}${ext}`,\n `${ref}${ext}`,\n ])\n\n let found = false\n for (const path of candidates) {\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 // ref에 확장자가 없으면 실제 발견된 path의 확장자 사용 (WMF 등 올바른 분류)\n const refExt = ref.includes(\".\") ? ref.split(\".\").pop()!.toLowerCase() : \"\"\n const pathExt = !refExt && path.includes(\".\") ? path.split(\".\").pop()!.toLowerCase() : \"\"\n const ext = refExt || pathExt\n const mimeType = ext ? imageExtToMime(ext) : detectImageMimeFromBytes(data)\n imageIndex++\n const filename = `image_${String(imageIndex).padStart(3, \"0\")}.${mimeToExt(mimeType)}`\n\n images.push({ filename, data, mimeType })\n // 블록 텍스트를 참조 파일명으로 교체\n block.text = filename\n block.imageData = { data, mimeType, filename: ref }\n found = true\n break\n } catch (err) {\n if (err instanceof KordocError) throw err\n // 개별 이미지 실패는 경고로 처리\n }\n }\n\n if (!found) {\n warnings?.push({ page: block.pageNumber, message: `이미지 파일 없음: ${ref}`, code: \"SKIPPED_IMAGE\" })\n // image 블록을 paragraph로 전환 (참조만 남김)\n block.type = \"paragraph\"\n block.text = `[이미지: ${ref}]`\n }\n }\n\n return images\n}\n\n// ─── 메타데이터 추출 (best-effort) ───────────────────\n\n/**\n * HWPX ZIP 내 메타데이터 파일에서 Dublin Core 정보 추출.\n * 표준 경로: meta.xml, docProps/core.xml, META-INF/container.xml\n */\nasync function extractHwpxMetadata(zip: JSZip, metadata: DocumentMetadata, decompressed?: { total: number }): Promise<void> {\n try {\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 file = zip.file(mp) || Object.values(zip.files).find(f => f.name.toLowerCase() === mp.toLowerCase()) || null\n if (!file) continue\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 parseDublinCoreMetadata(xml, metadata)\n if (metadata.title || metadata.author) return\n }\n } catch {\n // best-effort\n }\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// ─── 손상 ZIP 복구 (edu-facility-ai에서 포팅) ──────────\n\n/** Web Standard DecompressionStream 기반 raw deflate 압축 해제 (Node.js zlib 대체, CF Workers 호환) */\nasync function inflateRawCompat(data: Uint8Array, maxSize: number): Promise<Uint8Array> {\n const ds = new DecompressionStream(\"deflate-raw\")\n const writer = ds.writable.getWriter()\n await writer.write(data)\n await writer.close()\n const reader = ds.readable.getReader()\n const chunks: Uint8Array[] = []\n let total = 0\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n total += value.length\n if (total > maxSize) throw new KordocError(\"압축 해제 크기 초과\")\n chunks.push(value)\n }\n const out = new Uint8Array(total)\n let offset = 0\n for (const c of chunks) { out.set(c, offset); offset += c.length }\n return out\n}\n\nasync function extractFromBrokenZip(buffer: ArrayBuffer): Promise<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\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 = await inflateRawCompat(fileData, 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 blocks.push(...parseSectionXml(content, undefined, warnings, sectionNum))\n } catch {\n continue\n }\n }\n\n if (blocks.length === 0) throw new KordocError(\"손상된 HWPX에서 섹션 데이터를 복구할 수 없습니다\")\n const markdown = blocksToMarkdown(blocks)\n return { markdown, blocks, warnings: warnings.length > 0 ? warnings : undefined }\n}\n\n// ─── Manifest 해석 ───────────────────────────────────\n\nasync 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()\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 isSectionId = (id: string) => /^s/i.test(id) || id.toLowerCase().includes(\"section\")\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 let href = item.getAttribute(\"href\") || \"\"\n const mediaType = item.getAttribute(\"media-type\") || \"\"\n if (!isSectionId(id) && !mediaType.includes(\"xml\")) continue\n if (!href.startsWith(\"/\") && !href.startsWith(\"Contents/\") && isSectionId(id))\n href = \"Contents/\" + href\n 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.entries())\n .filter(([id]) => isSectionId(id))\n .sort((a, b) => a[0].localeCompare(b[0]))\n .map(([, href]) => href)\n}\n\n// ─── 헤딩 감지 (스타일 기반) ────────────────────────\n\n/** HWPX 스타일 기반 헤딩 감지 */\nfunction detectHwpxHeadings(blocks: IRBlock[], styleMap: HwpxStyleMap): void {\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// ─── 섹션 XML 파싱 ──────────────────────────────────\n\nfunction parseSectionXml(xml: string, styleMap?: HwpxStyleMap, warnings?: ParseWarning[], sectionNum?: number): IRBlock[] {\n const parser = createXmlParser(warnings)\n const doc = parser.parseFromString(stripDtd(xml), \"text/xml\")\n if (!doc.documentElement) return []\n\n const blocks: IRBlock[] = []\n walkSection(doc.documentElement, blocks, null, [], styleMap, warnings, sectionNum)\n return blocks\n}\n\n/** pic/shape 요소에서 이미지 참조 경로 추출 (binaryItemIDRef 또는 href) */\nfunction extractImageRef(el: Element): string | 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)\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 styleMap?: HwpxStyleMap, warnings?: ParseWarning[], sectionNum?: number,\n 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 if (tableCtx) tableStack.push(tableCtx)\n const newTable: TableState = { rows: [], currentRow: [], cell: null }\n walkSection(el, blocks, newTable, tableStack, styleMap, warnings, sectionNum, depth + 1)\n\n if (newTable.rows.length > 0) {\n if (tableStack.length > 0) {\n const parentTable = tableStack.pop()!\n // 중첩 표가 충분히 크면 (3행+, 2열+) 별도 블록으로 분리\n const nestedCols = Math.max(...newTable.rows.map(r => r.length))\n if (newTable.rows.length >= 3 && nestedCols >= 2) {\n blocks.push({ type: \"table\", table: buildTable(newTable.rows), pageNumber: sectionNum })\n } else {\n const nestedText = convertTableToText(newTable.rows)\n if (parentTable.cell) {\n parentTable.cell.text += (parentTable.cell.text ? \"\\n\" : \"\") + nestedText\n }\n }\n tableCtx = parentTable\n } else {\n blocks.push({ type: \"table\", table: buildTable(newTable.rows), pageNumber: sectionNum })\n tableCtx = null\n }\n } else {\n tableCtx = tableStack.length > 0 ? tableStack.pop()! : null\n }\n break\n }\n\n case \"tr\":\n if (tableCtx) {\n tableCtx.currentRow = []\n walkSection(el, blocks, tableCtx, tableStack, styleMap, warnings, sectionNum, depth + 1)\n if (tableCtx.currentRow.length > 0) 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 walkSection(el, blocks, tableCtx, tableStack, styleMap, warnings, sectionNum, 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 cs = parseInt(el.getAttribute(\"colSpan\") || \"1\", 10)\n const rs = parseInt(el.getAttribute(\"rowSpan\") || \"1\", 10)\n tableCtx.cell.colSpan = clampSpan(cs, MAX_COLS)\n tableCtx.cell.rowSpan = clampSpan(rs, MAX_ROWS)\n }\n break\n\n case \"p\": {\n const { text, href, footnote, style, headingLevel } = extractParagraphInfo(el, styleMap)\n if (text) {\n if (tableCtx?.cell) {\n tableCtx.cell.text += (tableCtx.cell.text ? \"\\n\" : \"\") + text\n } else if (!tableCtx) {\n let block: IRBlock\n if (headingLevel) {\n block = { type: \"heading\", text, level: headingLevel, pageNumber: sectionNum }\n } else {\n block = { type: \"paragraph\", text, pageNumber: sectionNum }\n if (style) block.style = style\n }\n if (href) block.href = href\n if (footnote) block.footnoteText = footnote\n blocks.push(block)\n }\n }\n // <p> 내부의 <tbl>만 별도 처리 — extractParagraphInfo가 이미 텍스트를 추출했으므로\n // 전체 walkSection 재귀 대신 테이블/이미지 자식만 선택적으로 처리\n tableCtx = walkParagraphChildren(el, blocks, tableCtx, tableStack, styleMap, warnings, sectionNum, depth + 1)\n break\n }\n\n // 이미지/그림 — 경로 추출 또는 경고\n case \"pic\": case \"shape\": case \"drawingObject\": {\n const imgRef = extractImageRef(el)\n if (imgRef) {\n blocks.push({ type: \"image\", text: imgRef, pageNumber: sectionNum })\n } else if (warnings && sectionNum) {\n warnings.push({ page: sectionNum, message: `스킵된 요소: ${localTag}`, code: \"SKIPPED_IMAGE\" })\n }\n break\n }\n\n default:\n walkSection(el, blocks, tableCtx, tableStack, styleMap, warnings, sectionNum, depth + 1)\n break\n }\n }\n}\n\n/** <p> 내부에서 텍스트가 아닌 구조적 자식만 처리 (tbl, pic, shape). tableCtx 반환으로 상태 전파 */\nfunction walkParagraphChildren(\n node: Node, blocks: IRBlock[],\n tableCtx: TableState | null, tableStack: TableState[],\n styleMap?: HwpxStyleMap, warnings?: ParseWarning[], sectionNum?: number,\n depth: number = 0\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) => {\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 // 테이블은 walkSection으로 위임\n if (tableCtx) tableStack.push(tableCtx)\n const newTable: TableState = { rows: [], currentRow: [], cell: null }\n walkSection(el, blocks, newTable, tableStack, styleMap, warnings, sectionNum, d + 1)\n if (newTable.rows.length > 0) {\n if (tableStack.length > 0) {\n const parentTable = tableStack.pop()!\n const nestedCols = Math.max(...newTable.rows.map(r => r.length))\n if (newTable.rows.length >= 3 && nestedCols >= 2) {\n blocks.push({ type: \"table\", table: buildTable(newTable.rows), pageNumber: sectionNum })\n } else {\n const nestedText = convertTableToText(newTable.rows)\n if (parentTable.cell) {\n parentTable.cell.text += (parentTable.cell.text ? \"\\n\" : \"\") + nestedText\n }\n }\n tableCtx = parentTable\n } else {\n blocks.push({ type: \"table\", table: buildTable(newTable.rows), pageNumber: sectionNum })\n tableCtx = null\n }\n } else {\n tableCtx = tableStack.length > 0 ? tableStack.pop()! : null\n }\n } else if (localTag === \"pic\" || localTag === \"shape\" || localTag === \"drawingObject\") {\n // 도형/이미지 안에 drawText(글상자)가 있으면 텍스트 추출 우선\n const drawTextChild = findDescendant(el, \"drawText\")\n if (drawTextChild) {\n extractDrawTextBlocks(drawTextChild, blocks, styleMap, sectionNum)\n } else {\n const imgRef = extractImageRef(el)\n if (imgRef) {\n blocks.push({ type: \"image\", text: imgRef, pageNumber: sectionNum })\n } else if (warnings && sectionNum) {\n warnings.push({ page: sectionNum, message: `스킵된 요소: ${localTag}`, code: \"SKIPPED_IMAGE\" })\n }\n }\n } else if (localTag === \"drawText\") {\n // 글상자(TextBox) 안 텍스트 추출 — <hp:p> 순회\n extractDrawTextBlocks(el, blocks, styleMap, sectionNum)\n } else if (localTag === \"r\" || localTag === \"run\" || localTag === \"ctrl\"\n || localTag === \"rect\" || localTag === \"ellipse\" || localTag === \"polygon\"\n || localTag === \"line\" || localTag === \"arc\" || localTag === \"curve\"\n || localTag === \"connectLine\" || localTag === \"container\") {\n // <hp:run>, <hp:ctrl>, 도형 요소 내부에 테이블/이미지/글상자가 포함될 수 있음 — 재귀\n walkChildren(el, d + 1)\n }\n }\n }\n walkChildren(node, depth)\n return tableCtx\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[], styleMap?: HwpxStyleMap, sectionNum?: number): 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, styleMap, sectionNum)\n } else {\n const info = extractParagraphInfo(child, styleMap)\n const text = info.text.trim()\n if (text) {\n blocks.push({ type: \"paragraph\", text, style: info.style ?? undefined, pageNumber: sectionNum })\n }\n }\n }\n }\n}\n\ninterface ParagraphInfo {\n text: string\n href?: string\n footnote?: string\n style?: InlineStyle\n headingLevel?: number\n}\n\nfunction extractParagraphInfo(para: Element, styleMap?: HwpxStyleMap): ParagraphInfo {\n let text = \"\"\n let href: string | undefined\n let footnote: string | undefined\n let charPrId: string | undefined\n\n // 문단의 스타일 참조 → charPr로 간접 조회\n // HWPX <p>에는 paraPrIDRef/styleIDRef가 있고, charPrIDRef는 <r> 요소에 있음\n // 여기서는 일단 null — <r> 요소에서 charPrIDRef를 가져옴\n\n const walk = (node: Node) => {\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 if (child.nodeType === 3) { text += child.textContent || \"\"; continue }\n if (child.nodeType !== 1) continue\n\n const tag = (child.tagName || child.localName || \"\").replace(/^[^:]+:/, \"\")\n switch (tag) {\n case \"t\": walk(child); 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 \"fwSpace\": case \"hwSpace\": text += \" \"; break\n case \"tbl\": break // 테이블은 walkSection에서 처리\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)\n break\n }\n\n // 각주/미주\n case \"footNote\": case \"endNote\": case \"fn\": case \"en\": {\n const noteText = extractTextFromNode(child)\n if (noteText) footnote = (footnote ? footnote + \"; \" : \"\") + noteText\n break\n }\n\n // 제어 요소 — 필드, 컨트롤, 매개변수 등 스킵\n case \"ctrl\": case \"fieldBegin\": case \"fieldEnd\":\n case \"parameters\": case \"stringParam\": case \"integerParam\":\n case \"boolParam\": case \"floatParam\":\n case \"secPr\": // 섹션 속성 (페이지 설정 등)\n case \"colPr\": // 다단 속성\n case \"linesegarray\": case \"lineseg\": // 레이아웃 정보\n // 도형/이미지 요소 — 대체텍스트(\"사각형입니다.\" 등) 누출 방지\n case \"pic\": case \"shape\": case \"drawingObject\":\n case \"shapeComment\": case \"drawText\":\n break\n\n // run 요소에서 charPrIDRef 추출\n case \"r\": {\n const runCharPr = child.getAttribute(\"charPrIDRef\")\n if (runCharPr && !charPrId) charPrId = runCharPr\n walk(child)\n break\n }\n\n default: walk(child); break\n }\n }\n }\n walk(para)\n\n // 목차 리더 마커(\\x1F) 이후 텍스트(페이지번호) 제거\n const leaderIdx = text.indexOf(\"\\x1F\")\n if (leaderIdx >= 0) text = text.substring(0, leaderIdx)\n\n let cleanText = text.replace(/[ \\t]+/g, \" \").trim()\n\n // 한글 이미지 OLE 대체 텍스트 필터링 (\"그림입니다. 원본 그림의 이름: ...\")\n if (/^그림입니다\\.?\\s*원본\\s*그림의\\s*(이름|크기)/.test(cleanText)) cleanText = \"\"\n // 멀티라인으로 삽입된 OLE 대체 텍스트도 제거\n cleanText = cleanText.replace(/그림입니다\\.?\\s*원본\\s*그림의\\s*(이름|크기)[^\\n]*(\\n[^\\n]*원본\\s*그림의\\s*(이름|크기)[^\\n]*)*/g, \"\").trim()\n // HWP 도형/개체 대체텍스트 제거 (\"사각형입니다.\", \"개체 입니다.\" 등)\n cleanText = cleanText.replace(/(?:모서리가 둥근 |둥근 )?(?:사각형|직사각형|정사각형|원|타원|삼각형|선|직선|곡선|화살표|오각형|육각형|팔각형|별|십자|구름|마름모|도넛|평행사변형|사다리꼴|개체|그리기\\s?개체|묶음\\s?개체|글상자|수식|표|그림|OLE\\s?개체)\\s?입니다\\.?/g, \"\").trim()\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 // styleIDRef 기반 헤딩 레벨 감지 (스타일명 매칭)\n let headingLevel: number | undefined\n const styleIdRef = para.getAttribute(\"styleIDRef\")\n if (styleMap && styleIdRef) {\n const styleDef = styleMap.styles.get(styleIdRef)\n if (styleDef?.name) {\n const sn = styleDef.name\n if (/장제목|대제목|간지제목|제목[\\s_]?1|개요[\\s_]?1|heading[\\s_]?1/i.test(sn)) headingLevel = 1\n else if (/절제목|제목[\\s_]?2|개요[\\s_]?2|heading[\\s_]?2|^B-1\\.$|[\\s(]1\\.$/i.test(sn)) headingLevel = 2\n else if (/제목[\\s_]?3|개요[\\s_]?3|heading[\\s_]?3|1\\.1\\s*제목|1\\.1[\\s_]|^B-1\\.1/i.test(sn)) headingLevel = 3\n else if (/제목[\\s_]?4|개요[\\s_]?4|heading[\\s_]?4/i.test(sn)) headingLevel = 4\n }\n }\n\n return { text: cleanText, href, footnote, style, headingLevel }\n}\n\n/** 노드 내 모든 텍스트를 재귀적으로 추출 */\nfunction extractTextFromNode(node: Node): string {\n let result = \"\"\n const children = node.childNodes\n if (!children) return result\n for (let i = 0; i < children.length; i++) {\n const child = children[i]\n if (child.nodeType === 3) result += child.textContent || \"\"\n else if (child.nodeType === 1) result += extractTextFromNode(child)\n }\n return result.trim()\n}\n","/** kordoc 공용 유틸리티 */\n\n/** 빌드 타임에 tsup define으로 주입되는 버전 */\ndeclare const __KORDOC_VERSION__: string\nexport const VERSION: string = typeof __KORDOC_VERSION__ !== \"undefined\" ? __KORDOC_VERSION__ : \"0.0.0-dev\"\n\n/**\n * Node.js Buffer → ArrayBuffer 변환\n * pool Buffer의 공유 ArrayBuffer 문제를 안전하게 처리.\n * offset=0이고 전체 ArrayBuffer를 차지하면 복사 없이 직접 반환.\n */\nexport function toArrayBuffer(buf: Buffer): ArrayBuffer {\n if (buf.byteOffset === 0 && buf.byteLength === buf.buffer.byteLength) {\n return buf.buffer as ArrayBuffer\n }\n return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength) as ArrayBuffer\n}\n\n/**\n * kordoc 내부 에러 클래스 — 사용자에게 노출해도 안전한 메시지만 포함.\n * MCP 에러 정제에서 instanceof로 판별하여 allowlist 패턴 매칭 없이 안전하게 통과.\n */\nexport class KordocError extends Error {\n constructor(message: string) {\n super(message)\n this.name = \"KordocError\"\n }\n}\n\n/**\n * 에러 메시지 정제 — KordocError는 그대로, 나머지는 일반 메시지로 대체.\n * 파일시스템 경로, 스택 트레이스 등 내부 정보 노출 방지.\n */\nexport function sanitizeError(err: unknown): string {\n if (err instanceof KordocError) return err.message\n return \"문서 처리 중 오류가 발생했습니다\"\n}\n\n/**\n * ZIP 엔트리 경로의 경로 순회 여부 판별.\n * 백슬래시 정규화, .., 절대경로, Windows 드라이브 문자 모두 차단.\n */\nexport function isPathTraversal(name: string): boolean {\n if (name.includes(\"\\x00\")) return true\n const normalized = name.replace(/\\\\/g, \"/\")\n return normalized.includes(\"..\") || normalized.startsWith(\"/\") || /^[A-Za-z]:/.test(normalized)\n}\n\n// ─── ZIP 안전 로딩 (ZIP bomb 방지) ────────────────────\n\n/**\n * ZIP bomb 사전 검사 — Central Directory에서 비압축 합계와 엔트리 수 확인.\n * HWPX/XLSX/DOCX 등 모든 ZIP 기반 포맷에서 공통 사용.\n */\nexport function precheckZipSize(\n buffer: ArrayBuffer,\n maxUncompressedSize = 100 * 1024 * 1024,\n maxEntries = 500,\n): { totalUncompressed: number; entryCount: number } {\n try {\n const data = new DataView(buffer)\n const len = buffer.byteLength\n // EOCD 시그니처 역방향 스캔\n let eocdOffset = -1\n for (let i = len - 22; i >= Math.max(0, len - 65557); i--) {\n if (data.getUint32(i, true) === 0x06054b50) { eocdOffset = i; break }\n }\n if (eocdOffset < 0) return { totalUncompressed: 0, entryCount: 0 }\n\n const entryCount = data.getUint16(eocdOffset + 10, true)\n if (entryCount > maxEntries) {\n throw new KordocError(`ZIP 엔트리 수 초과: ${entryCount} (최대 ${maxEntries})`)\n }\n\n const cdSize = data.getUint32(eocdOffset + 12, true)\n const cdOffset = data.getUint32(eocdOffset + 16, true)\n if (cdOffset + cdSize > len) return { totalUncompressed: 0, entryCount }\n\n let totalUncompressed = 0\n let pos = cdOffset\n for (let i = 0; i < entryCount && pos + 46 <= cdOffset + cdSize; i++) {\n if (data.getUint32(pos, true) !== 0x02014b50) break\n totalUncompressed += data.getUint32(pos + 24, true)\n const nameLen = data.getUint16(pos + 28, true)\n const extraLen = data.getUint16(pos + 30, true)\n const commentLen = data.getUint16(pos + 32, true)\n pos += 46 + nameLen + extraLen + commentLen\n }\n\n if (totalUncompressed > maxUncompressedSize) {\n throw new KordocError(`ZIP 비압축 크기 초과: ${(totalUncompressed / 1024 / 1024).toFixed(1)}MB (최대 ${maxUncompressedSize / 1024 / 1024}MB)`)\n }\n\n return { totalUncompressed, entryCount }\n } catch (err) {\n if (err instanceof KordocError) throw err\n return { totalUncompressed: 0, entryCount: 0 }\n }\n}\n\n/** 하이퍼링크 URL 살균 — javascript: 등 XSS 위험 스킴 차단 */\nconst SAFE_HREF_RE = /^(?:https?:|mailto:|tel:|#)/i\nexport function sanitizeHref(href: string): string | null {\n const trimmed = href.trim()\n if (!trimmed || !SAFE_HREF_RE.test(trimmed)) return null\n return trimmed\n}\n\n// ─── 에러 분류 ──────────────────────────────────────\n\nimport type { ErrorCode } from \"./types.js\"\n\n/** 에러를 구조화된 ErrorCode로 분류 — KordocError 메시지 패턴 매칭 */\nexport function classifyError(err: unknown): ErrorCode {\n if (!(err instanceof Error)) return \"PARSE_ERROR\"\n const msg = err.message\n if (msg.includes(\"암호화\")) return \"ENCRYPTED\"\n if (msg.includes(\"DRM\")) return \"DRM_PROTECTED\"\n if (msg.includes(\"ZIP bomb\") || msg.includes(\"ZIP 비압축 크기 초과\") || msg.includes(\"ZIP 엔트리 수 초과\")) return \"ZIP_BOMB\"\n if (msg.includes(\"bomb\") || msg.includes(\"크기 초과\") || msg.includes(\"압축 해제\")) return \"DECOMPRESSION_BOMB\"\n if (msg.includes(\"이미지 기반\")) return \"IMAGE_BASED_PDF\"\n if (msg.includes(\"섹션\") && (msg.includes(\"찾을 수 없\") || msg.includes(\"없음\"))) return \"NO_SECTIONS\"\n if (msg.includes(\"시그니처\") || msg.includes(\"복구할 수 없\")) return \"CORRUPTED\"\n return \"PARSE_ERROR\"\n}\n","/** 2-pass colSpan/rowSpan 테이블 빌더 및 Markdown 변환 */\n\nimport type { CellContext, IRBlock, IRCell, IRTable } from \"../types.js\"\nimport { sanitizeHref } from \"../utils.js\"\n\n/** 테이블 열 수 상한 — 한국 공공문서 기준 충분한 값 */\nexport const MAX_COLS = 200\n/** 테이블 행 수 상한 — 메모리 폭주 방지 */\nexport const MAX_ROWS = 10000\n\nexport function buildTable(rows: CellContext[][]): IRTable {\n if (rows.length > MAX_ROWS) rows = rows.slice(0, MAX_ROWS)\n const numRows = rows.length\n\n // colAddr/rowAddr가 있으면 직접 배치 (HWPX cellAddr, HWP5 colAddr/rowAddr)\n const hasAddr = rows.some(row => row.some(c => c.colAddr !== undefined && c.rowAddr !== undefined))\n if (hasAddr) return buildTableDirect(rows, numRows)\n\n // Pass 1: maxCols 계산 — 2D 배열 사용 (동적 확장)\n let maxCols = 0\n const tempOccupied: boolean[][] = Array.from({ length: numRows }, () => [])\n\n for (let rowIdx = 0; rowIdx < numRows; rowIdx++) {\n let colIdx = 0\n for (const cell of rows[rowIdx]) {\n while (colIdx < MAX_COLS && tempOccupied[rowIdx][colIdx]) colIdx++\n if (colIdx >= MAX_COLS) break\n\n for (let r = rowIdx; r < Math.min(rowIdx + cell.rowSpan, numRows); r++) {\n for (let c = colIdx; c < Math.min(colIdx + cell.colSpan, MAX_COLS); c++) {\n tempOccupied[r][c] = true\n }\n }\n colIdx += cell.colSpan\n if (colIdx > maxCols) maxCols = colIdx\n }\n }\n\n if (maxCols === 0) return { rows: 0, cols: 0, cells: [], hasHeader: false }\n\n // Pass 2: 실제 배치\n const grid: IRCell[][] = Array.from({ length: numRows }, () =>\n Array.from({ length: maxCols }, () => ({ text: \"\", colSpan: 1, rowSpan: 1 }))\n )\n const occupied: boolean[][] = Array.from({ length: numRows }, () => Array(maxCols).fill(false))\n\n for (let rowIdx = 0; rowIdx < numRows; rowIdx++) {\n let colIdx = 0\n let cellIdx = 0\n\n while (colIdx < maxCols && cellIdx < rows[rowIdx].length) {\n while (colIdx < maxCols && occupied[rowIdx][colIdx]) colIdx++\n if (colIdx >= maxCols) break\n\n const cell = rows[rowIdx][cellIdx]\n grid[rowIdx][colIdx] = {\n text: cell.text.trim(),\n colSpan: cell.colSpan,\n rowSpan: cell.rowSpan,\n }\n\n for (let r = rowIdx; r < Math.min(rowIdx + cell.rowSpan, numRows); r++) {\n for (let c = colIdx; c < Math.min(colIdx + cell.colSpan, maxCols); c++) {\n occupied[r][c] = true\n }\n }\n\n colIdx += cell.colSpan\n cellIdx++\n }\n }\n\n return trimAndReturn(grid, numRows, maxCols)\n}\n\n/** colAddr/rowAddr 절대 좌표 기반 직접 배치 */\nfunction buildTableDirect(rows: CellContext[][], numRows: number): IRTable {\n // 전체 셀에서 maxCols 계산\n let maxCols = 0\n for (const row of rows) {\n for (const cell of row) {\n const end = (cell.colAddr ?? 0) + cell.colSpan\n if (end > maxCols) maxCols = end\n }\n }\n if (maxCols === 0) return { rows: 0, cols: 0, cells: [], hasHeader: false }\n\n const grid: IRCell[][] = Array.from({ length: numRows }, () =>\n Array.from({ length: maxCols }, () => ({ text: \"\", colSpan: 1, rowSpan: 1 }))\n )\n\n for (const row of rows) {\n for (const cell of row) {\n const r = cell.rowAddr ?? 0\n const c = cell.colAddr ?? 0\n if (r >= numRows || c >= maxCols) continue\n\n grid[r][c] = { text: cell.text.trim(), colSpan: cell.colSpan, rowSpan: cell.rowSpan }\n\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 < maxCols) {\n grid[r + dr][c + dc] = { text: \"\", colSpan: 1, rowSpan: 1 }\n }\n }\n }\n }\n }\n\n return trimAndReturn(grid, numRows, maxCols)\n}\n\n/** 빈 후행 열 제거 후 IRTable 반환 */\nfunction trimAndReturn(grid: IRCell[][], numRows: number, maxCols: number): IRTable {\n let effectiveCols = maxCols\n while (effectiveCols > 0) {\n const colEmpty = grid.every(row => !row[effectiveCols - 1]?.text?.trim())\n if (!colEmpty) break\n effectiveCols--\n }\n if (effectiveCols < maxCols && effectiveCols > 0) {\n const trimmed = grid.map(row => row.slice(0, effectiveCols))\n return { rows: numRows, cols: effectiveCols, cells: trimmed, hasHeader: numRows > 1 }\n }\n return { rows: numRows, cols: maxCols, cells: grid, hasHeader: numRows > 1 }\n}\n\nexport function convertTableToText(rows: CellContext[][]): string {\n return rows\n .map(row =>\n row\n .map(c => c.text.trim().replace(/\\n/g, \" \"))\n .filter(Boolean)\n .join(\" | \")\n )\n .filter(Boolean)\n .join(\"\\n\")\n}\n\n/** HWP 자동생성 도형/개체 대체텍스트 정규식 — 한컴오피스가 삽입하는 모든 알려진 패턴 */\nconst HWP_SHAPE_ALT_TEXT_RE = /(?:모서리가 둥근 |둥근 )?(?:사각형|직사각형|정사각형|원|타원|삼각형|이등변 삼각형|직각 삼각형|선|직선|곡선|화살표|굵은 화살표|이중 화살표|오각형|육각형|팔각형|별|[4-8]점별|십자|십자형|구름|구름형|마름모|도넛|평행사변형|사다리꼴|부채꼴|호|반원|물결|번개|하트|빗금|블록 화살표|수식|표|그림|개체|그리기\\s?개체|묶음\\s?개체|글상자|수식\\s?개체|OLE\\s?개체)\\s?입니다\\.?/g\n\n/** HWP PUA 특수문자 및 도형 대체텍스트 제거 — 모든 포맷 공통 */\nfunction sanitizeText(text: string): string {\n let result = text\n // Supplementary Private Use Area (U+F0000-U+FFFFD) — HWP 전용 기호\n .replace(/[\\u{F0000}-\\u{FFFFD}]/gu, \"\")\n // HWP 도형/개체 자동생성 대체텍스트 제거\n .replace(HWP_SHAPE_ALT_TEXT_RE, \"\")\n .replace(/ +/g, \" \")\n .trim()\n // 균등배분 스페이스 정리 (\"현 장 대 응 단 장\" → \"현장대응단장\")\n // 짧은 텍스트(30자 이하)에서 70%+ 토큰이 한글 1글자면 균등배분으로 판단\n if (result.length <= 30 && result.includes(\" \")) {\n const tokens = result.split(\" \")\n // 한글 1글자 토큰만 카운트 — ASCII 특수문자(< > & 등)는 균등배분이 아님\n const koreanSingleCharCount = tokens.filter(t => t.length === 1 && /[\\uAC00-\\uD7AF\\u3131-\\u318E]/.test(t)).length\n if (tokens.length >= 3 && koreanSingleCharCount / tokens.length >= 0.7) {\n result = tokens.join(\"\")\n }\n }\n return result\n}\n\nexport function blocksToMarkdown(blocks: IRBlock[]): string {\n const lines: string[] = []\n\n for (let i = 0; i < blocks.length; i++) {\n const block = blocks[i]\n\n // 헤딩 블록\n if (block.type === \"heading\" && block.text) {\n const prefix = \"#\".repeat(Math.min(block.level || 2, 6))\n const headingText = sanitizeText(block.text)\n if (headingText) lines.push(\"\", `${prefix} ${headingText}`, \"\")\n continue\n }\n\n // 이미지 블록 —  참조\n if (block.type === \"image\" && block.text) {\n lines.push(\"\", ``, \"\")\n continue\n }\n\n // 구분선 블록\n if (block.type === \"separator\") {\n lines.push(\"\", \"---\", \"\")\n continue\n }\n\n // 리스트 블록\n if (block.type === \"list\" && block.text) {\n const listText = sanitizeText(block.text)\n if (!listText) continue\n // 텍스트가 이미 번호로 시작하면 그대로 출력 (원래 번호 보존)\n const alreadyNumbered = block.listType === \"ordered\" && /^\\d+\\.\\s/.test(listText)\n const prefix = alreadyNumbered ? \"\" : block.listType === \"ordered\" ? \"1. \" : \"- \"\n lines.push(`${prefix}${listText}`)\n if (block.children) {\n for (const child of block.children) {\n const childPrefix = child.listType === \"ordered\" ? \"1.\" : \"-\"\n lines.push(` ${childPrefix} ${child.text || \"\"}`)\n }\n }\n continue\n }\n\n if (block.type === \"paragraph\" && block.text) {\n let text = sanitizeText(block.text)\n if (!text) continue\n\n // 별표 패턴 (기존 호환)\n if (/^\\[별표\\s*\\d+/.test(text)) {\n const nextBlock = blocks[i + 1]\n if (nextBlock?.type === \"paragraph\" && nextBlock.text && /관련\\)?$/.test(nextBlock.text)) {\n lines.push(\"\", `## ${text} ${nextBlock.text}`, \"\")\n i++\n } else {\n lines.push(\"\", `## ${text}`, \"\")\n }\n continue\n }\n\n if (/^\\([^)]*조[^)]*관련\\)$/.test(text)) {\n lines.push(`*${text}*`, \"\")\n continue\n }\n\n // 하이퍼링크가 있으면 텍스트에 링크 삽입 (javascript: 등 위험 스킴 제거)\n if (block.href) {\n const href = sanitizeHref(block.href)\n if (href) text = `[${text}](${href})`\n }\n\n // 각주가 있으면 괄호로 인라인 삽입\n if (block.footnoteText) {\n text += ` (주: ${block.footnoteText})`\n }\n\n lines.push(text)\n } else if (block.type === \"table\" && block.table) {\n // 테이블 앞에 빈 줄 보장 (마크다운 렌더링 필수)\n if (lines.length > 0 && lines[lines.length - 1] !== \"\") {\n lines.push(\"\")\n }\n const tableMd = tableToMarkdown(block.table)\n if (tableMd) {\n lines.push(tableMd)\n lines.push(\"\")\n }\n }\n }\n\n return lines.join(\"\\n\").trim()\n}\n\nfunction tableToMarkdown(table: IRTable): string {\n if (table.rows === 0 || table.cols === 0) return \"\"\n\n const { cells, rows: numRows, cols: numCols } = table\n\n // 1행 1열 → 구조화된 텍스트 (빈 셀이면 스킵)\n if (numRows === 1 && numCols === 1) {\n const content = sanitizeText(cells[0][0].text)\n if (!content) return \"\"\n return content\n .split(/\\n/)\n .map(line => {\n const trimmed = line.trim()\n if (!trimmed) return \"\"\n if (/^\\d+\\.\\s/.test(trimmed)) return `**${trimmed}**`\n if (/^[가-힣]\\.\\s/.test(trimmed)) return ` ${trimmed}`\n return trimmed\n })\n .filter(Boolean)\n .join(\"\\n\")\n }\n\n // 1열 다행 테이블 → 각 행을 별도 라인으로 출력 (목록성 데이터)\n if (numCols === 1 && numRows >= 2) {\n return cells\n .map(row => sanitizeText(row[0].text).replace(/\\n/g, \" \"))\n .filter(Boolean)\n .join(\"\\n\")\n }\n\n // 병합 셀: 행/열 병합된 셀은 빈 칸으로\n const display: string[][] = Array.from({ length: numRows }, () => Array(numCols).fill(\"\"))\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] = sanitizeText(cell.text).replace(/\\n/g, \"<br>\")\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) {\n skip.add(`${r + dr},${c + dc}`)\n }\n }\n }\n // colSpan > 1이면 display 열 인덱스를 건너뜀\n c += cell.colSpan - 1\n }\n }\n\n // rowSpan 잔류 처리:\n // 1) 완전 빈 행 제거\n // 2) \"첫 열만 값, 나머지 빈\" 행 → 다음 데이터 행의 첫 열에 값을 전파\n // 단, colSpan으로 인한 빈 열(skip 셀)은 이 대상이 아님\n const uniqueRows: string[][] = []\n let pendingFirstCol = \"\"\n for (let r = 0; r < display.length; r++) {\n const row = display[r]\n const isEmptyPlaceholder = row.every(cell => cell === \"\")\n if (isEmptyPlaceholder) continue\n\n // 첫 열만 값이 있고 나머지 모두 빈 행 → 다음 데이터 행의 첫 열에 전파\n // 단, colSpan으로 인한 빈 열(skip 셀)은 \"진짜 빈\"이 아니므로 제외\n const nonEmptyCols = row.filter(cell => cell !== \"\")\n const hasSkipInRow = row.some((_, c) => skip.has(`${r},${c}`))\n if (!hasSkipInRow && nonEmptyCols.length === 1 && row[0] !== \"\" && row.slice(1).every(c => c === \"\")) {\n pendingFirstCol = row[0]\n continue\n }\n\n // 저장된 첫 열 값을 현재 행의 빈 첫 열에 전파\n if (pendingFirstCol && row[0] === \"\") {\n row[0] = pendingFirstCol\n pendingFirstCol = \"\"\n } else {\n pendingFirstCol = \"\"\n }\n uniqueRows.push(row)\n }\n\n if (uniqueRows.length === 0) return \"\"\n\n const md: string[] = []\n md.push(\"| \" + uniqueRows[0].join(\" | \") + \" |\")\n md.push(\"| \" + uniqueRows[0].map(() => \"---\").join(\" | \") + \" |\")\n for (let i = 1; i < uniqueRows.length; i++) {\n md.push(\"| \" + uniqueRows[i].join(\" | \") + \" |\")\n }\n return md.join(\"\\n\")\n}\n","/** kordoc 공통 타입 정의 */\n\n// ─── 중간 표현 (Intermediate Representation) ─────────\n\nexport interface CellContext {\n text: string\n colSpan: number\n rowSpan: number\n /** HWP5 셀 열 주소 (0-based) — 병합 테이블 배치용 */\n colAddr?: number\n /** HWP5 셀 행 주소 (0-based) — 병합 테이블 배치용 */\n rowAddr?: number\n}\n\n/** 블록 타입 — v2.0에서 heading, list, image, separator 추가 */\nexport type IRBlockType = \"paragraph\" | \"table\" | \"heading\" | \"list\" | \"image\" | \"separator\"\n\nexport interface IRBlock {\n type: IRBlockType\n text?: string\n table?: IRTable\n /** 헤딩 레벨 (1-6), type=\"heading\"일 때 사용 */\n level?: number\n /** 원본 페이지 번호 (1-based) */\n pageNumber?: number\n /** 바운딩 박스 — PDF에서만 제공 */\n bbox?: BoundingBox\n /** 텍스트 스타일 정보 (선택) */\n style?: InlineStyle\n /** 리스트 타입, type=\"list\"일 때 사용 */\n listType?: \"ordered\" | \"unordered\"\n /** 중첩 리스트 아이템 */\n children?: IRBlock[]\n /** 하이퍼링크 URL */\n href?: string\n /** 각주/미주 텍스트 (인라인 삽입용) */\n footnoteText?: string\n /** 이미지 데이터 (type=\"image\"일 때) */\n imageData?: ImageData\n}\n\n/** 추출된 이미지 바이너리 데이터 */\nexport interface ImageData {\n /** 이미지 바이너리 */\n data: Uint8Array\n /** MIME 타입 (image/png, image/jpeg, image/gif, image/bmp, image/wmf, image/emf) */\n mimeType: string\n /** 원본 파일명 (있는 경우) */\n filename?: string\n}\n\n/** 바운딩 박스 — PDF 포인트 단위 (72pt = 1인치) */\nexport interface BoundingBox {\n page: number\n x: number\n y: number\n width: number\n height: number\n}\n\n/** 인라인 텍스트 스타일 */\nexport interface InlineStyle {\n bold?: boolean\n italic?: boolean\n fontSize?: number\n fontName?: string\n}\n\nexport interface IRTable {\n rows: number\n cols: number\n cells: IRCell[][]\n /** 첫 행을 헤더로 렌더링할지 여부 (현재: rows > 1이면 true — 의미적 감지가 아닌 레이아웃 힌트) */\n hasHeader: boolean\n}\n\nexport interface IRCell {\n text: string\n colSpan: number\n rowSpan: number\n}\n\n// ─── 메타데이터 ─────────────────────────────────────\n\n/** 문서 메타데이터 — 각 포맷에서 추출 가능한 필드만 채워짐 */\nexport interface DocumentMetadata {\n /** 문서 제목 */\n title?: string\n /** 작성자 */\n author?: string\n /** 작성 프로그램 (예: \"한글 2020\", \"Adobe Acrobat\") */\n creator?: string\n /** 생성일시 (ISO 8601) */\n createdAt?: string\n /** 수정일시 (ISO 8601) */\n modifiedAt?: string\n /** 페이지/섹션 수 */\n pageCount?: number\n /** 문서 포맷 버전 (예: HWP \"5.1.0.1\") */\n version?: string\n /** 설명 */\n description?: string\n /** 키워드 */\n keywords?: string[]\n}\n\n// ─── 파싱 옵션 ──────────────────────────────────────\n\n/** 파싱 옵션 — parse() 함수에 전달 */\nexport interface ParseOptions {\n /**\n * 파싱할 페이지/섹션 범위 (1-based).\n * - 배열: [1, 2, 3]\n * - 문자열: \"1-3\", \"1,3,5-7\"\n *\n * PDF: 정확한 페이지 단위. HWP/HWPX: 섹션 단위 근사치.\n */\n pages?: number[] | string\n /** 이미지 기반 PDF용 OCR 프로바이더 (선택) */\n ocr?: OcrProvider\n /**\n * OCR 모드 (CLI 자동 탐색용).\n * - \"auto\": 설치된 CLI 자동 탐색 (gemini→claude→codex→ollama→tesseract)\n * - \"gemini\"|\"claude\"|\"codex\"|\"ollama\"|\"tesseract\": 특정 도구 강제 지정\n * - \"off\": OCR 비활성화 (이미지 기반 PDF면 에러)\n * - undefined: 라이브러리 API 기존 동작 유지 (자동 탐색 안 함)\n */\n ocrMode?: OcrMode\n /** 진행률 콜백 — current: 현재 페이지/섹션, total: 전체 수 */\n onProgress?: (current: number, total: number) => void\n /** PDF 머리글/바닥글 자동 제거 */\n removeHeaderFooter?: boolean\n}\n\n// ─── 파싱 경고 ──────────────────────────────────────\n\n/** 파싱 중 스킵/실패한 요소 보고 */\nexport interface ParseWarning {\n /** 관련 페이지 번호 (알 수 있는 경우) */\n page?: number\n /** 경고 메시지 */\n message: string\n /** 구조화된 경고 코드 */\n code: WarningCode\n}\n\nexport type WarningCode =\n | \"SKIPPED_IMAGE\"\n | \"SKIPPED_OLE\"\n | \"TRUNCATED_TABLE\"\n | \"OCR_FALLBACK\"\n | \"UNSUPPORTED_ELEMENT\"\n | \"BROKEN_ZIP_RECOVERY\"\n | \"HIDDEN_TEXT_FILTERED\"\n | \"MALFORMED_XML\"\n | \"PARTIAL_PARSE\"\n | \"LENIENT_CFB_RECOVERY\"\n | \"OCR_PAGE_FAILED\"\n | \"OCR_CLI_FALLBACK\"\n\n/** 문서 구조 (헤딩 트리) */\nexport interface OutlineItem {\n level: number\n text: string\n pageNumber?: number\n}\n\n// ─── 에러 코드 ──────────────────────────────────────\n\n/** 구조화된 에러 코드 — 프로그래밍적 에러 핸들링용 */\nexport type ErrorCode =\n | \"EMPTY_INPUT\"\n | \"UNSUPPORTED_FORMAT\"\n | \"ENCRYPTED\"\n | \"DRM_PROTECTED\"\n | \"CORRUPTED\"\n | \"DECOMPRESSION_BOMB\"\n | \"ZIP_BOMB\"\n | \"IMAGE_BASED_PDF\"\n | \"NO_SECTIONS\"\n | \"PARSE_ERROR\"\n\n// ─── 파싱 결과 (discriminated union) ────────────────\n\nexport type FileType = \"hwpx\" | \"hwp\" | \"pdf\" | \"xlsx\" | \"docx\" | \"unknown\"\n\ninterface ParseResultBase {\n fileType: FileType\n /** 페이지/섹션 수 — PDF: 실제 페이지 수, HWP/HWPX: 섹션 수, XLSX: 시트 수 */\n pageCount?: number\n /** 이미지 기반 PDF 여부 (텍스트 추출 불가) */\n isImageBased?: boolean\n}\n\nexport interface ParseSuccess extends ParseResultBase {\n success: true\n /** 추출된 마크다운 텍스트 */\n markdown: string\n /** 중간 표현 블록 (구조화된 데이터 접근용) */\n blocks: IRBlock[]\n /** 문서 메타데이터 */\n metadata?: DocumentMetadata\n /** 문서 구조 (헤딩 트리) — v2.0 */\n outline?: OutlineItem[]\n /** 파싱 중 발생한 경고 — v2.0 */\n warnings?: ParseWarning[]\n /** 추출된 이미지 목록 — 마크다운에서 파일명으로 참조됨 */\n images?: ExtractedImage[]\n}\n\n/** 추출된 이미지 — ParseSuccess.images에 포함 */\nexport interface ExtractedImage {\n /** 마크다운에서 참조되는 파일명 (예: image_001.png) */\n filename: string\n /** 이미지 바이너리 */\n data: Uint8Array\n /** MIME 타입 */\n mimeType: string\n}\n\nexport interface ParseFailure extends ParseResultBase {\n success: false\n /** 오류 메시지 */\n error: string\n /** 구조화된 에러 코드 */\n code?: ErrorCode\n}\n\nexport type ParseResult = ParseSuccess | ParseFailure\n\n// ─── 문서 비교 (Diff) ───────────────────────────────\n\nexport type DiffChangeType = \"added\" | \"removed\" | \"modified\" | \"unchanged\"\n\nexport interface BlockDiff {\n type: DiffChangeType\n /** 원본 블록 (added이면 undefined) */\n before?: IRBlock\n /** 변경 후 블록 (removed이면 undefined) */\n after?: IRBlock\n /** modified 테이블의 셀 단위 diff */\n cellDiffs?: CellDiff[][]\n /** 유사도 (0-1) */\n similarity?: number\n}\n\nexport interface CellDiff {\n type: DiffChangeType\n before?: string\n after?: string\n}\n\nexport interface DiffResult {\n stats: { added: number; removed: number; modified: number; unchanged: number }\n diffs: BlockDiff[]\n}\n\n// ─── 양식 인식 ──────────────────────────────────────\n\nexport interface FormField {\n label: string\n value: string\n /** 0-based 소스 행 */\n row: number\n /** 0-based 소스 열 */\n col: number\n}\n\nexport interface FormResult {\n fields: FormField[]\n /** 양식 확신도 (0-1) */\n confidence: number\n}\n\n// ─── OCR 프로바이더 ─────────────────────────────────\n\n/** Vision LLM이 반환하는 구조화된 OCR 결과 */\nexport interface StructuredOcrResult {\n /** 구조화된 Markdown (테이블/헤딩/리스트 포함) */\n markdown: string\n}\n\n/** OCR 모드 — CLI --ocr 옵션 허용값 */\nexport type OcrMode = \"auto\" | \"gemini\" | \"claude\" | \"codex\" | \"ollama\" | \"tesseract\" | \"off\"\n\n/** 사용자 제공 OCR 함수 — 페이지 이미지를 받아 텍스트 또는 구조화된 결과 반환 */\nexport type OcrProvider = (\n pageImage: Uint8Array,\n pageNumber: number,\n mimeType: \"image/png\"\n) => Promise<string | StructuredOcrResult>\n\n// ─── Watch 모드 ─────────────────────────────────────\n\nexport interface WatchOptions {\n dir: string\n outDir?: string\n webhook?: string\n format?: \"markdown\" | \"json\"\n pages?: string\n silent?: boolean\n}\n\n// ─── 헤딩 감지 공통 임계값 ──────────────────────────\n\n/** 폰트 크기 비율 → heading level (전 파서 공통) */\nexport const HEADING_RATIO_H1 = 1.5\nexport const HEADING_RATIO_H2 = 1.3\nexport const HEADING_RATIO_H3 = 1.15\n\n// ─── 내부 파서 반환 타입 ─────────────────────────────\n\n/** 내부 파서가 index.ts에 반환하는 공통 타입 (HWP5/HWPX/PDF/XLSX/DOCX) */\nexport interface InternalParseResult {\n markdown: string\n blocks: IRBlock[]\n metadata?: DocumentMetadata\n outline?: OutlineItem[]\n warnings?: ParseWarning[]\n images?: ExtractedImage[]\n /** PDF 전용: 이미지 기반 PDF 여부 */\n isImageBased?: boolean\n}\n","/** HWP 5.x 레코드 리더, UTF-16LE 텍스트 추출, 스트림 압축해제 */\n\nimport { inflateRawSync, inflateSync } from \"zlib\"\nimport { KordocError } from \"../utils.js\"\n\n// ─── 레코드 태그 상수 ────────────────────────────────\n\nexport const TAG_PARA_HEADER = 0x0042\nexport const TAG_PARA_TEXT = 0x0043\nexport const TAG_CHAR_SHAPE = 0x0044\nexport const TAG_PARA_SHAPE = 0x0045\nexport const TAG_CTRL_HEADER = 0x0047\nexport const TAG_LIST_HEADER = 0x0048\nexport const TAG_TABLE = 0x004d\n\n// DocInfo 태그 (스타일 정보 해석용)\nexport const TAG_ID_MAPPINGS = 0x0032\nexport const TAG_FACE_NAME = 0x0033\nexport const TAG_DOC_CHAR_SHAPE = 0x0037\nexport const TAG_DOC_PARA_SHAPE = 0x0039\nexport const TAG_DOC_STYLE = 0x003a\n\n// 특수 문자 코드 (UTF-16LE) — HWP 5.0 바이너리 스펙 + rhwp 검증\n// 3가지 카테고리: char(2바이트), inline(16바이트), extended(16바이트)\n// char: 0, 13, 24-31 — 제어문자만, 확장 데이터 없음\n// inline: 4-9, 19-20 — 제어문자(2) + 확장(14) = 16바이트\n// extended: 1-3, 10-12, 14-18, 21-23 — 제어문자(2) + 확장(14) = 16바이트\nconst CHAR_LINE = 0x0000 // char: 줄바꿈\nconst CHAR_SECTION_BREAK = 0x000a // extended: 구역/단 정의 (14바이트 확장 데이터)\nconst CHAR_PARA = 0x000d // char: 문단 끝\nconst CHAR_TAB = 0x0009 // inline: 탭\nconst CHAR_HYPHEN = 0x001e // char: 하이픈\nconst CHAR_NBSP = 0x001f // char: 비분리 공백\nconst CHAR_FIXED_NBSP = 0x0018 // char: 고정 비분리 공백\nconst CHAR_FIXED_WIDTH = 0x0019 // char: 고정폭 공백\n\n// FileHeader 플래그\nexport const FLAG_COMPRESSED = 1 << 0\nexport const FLAG_ENCRYPTED = 1 << 1\nexport const FLAG_DISTRIBUTION = 1 << 2\nexport const FLAG_DRM = 1 << 4\n\n// ─── 레코드 구조 ─────────────────────────────────────\n\nexport interface HwpRecord {\n tagId: number\n level: number\n size: number\n data: Buffer\n}\n\nexport interface HwpFileHeader {\n signature: string\n versionMajor: number\n flags: number\n}\n\n// ─── 레코드 리더 ─────────────────────────────────────\n\n/** 최대 레코드 수 — 비정상 파일에 의한 메모리 폭주 방지 */\nconst MAX_RECORDS = 500_000\n\nexport function readRecords(data: Buffer): HwpRecord[] {\n const records: HwpRecord[] = []\n let offset = 0\n\n while (offset + 4 <= data.length && records.length < MAX_RECORDS) {\n const header = data.readUInt32LE(offset)\n offset += 4\n\n const tagId = header & 0x3ff\n const level = (header >> 10) & 0x3ff\n let size = (header >> 20) & 0xfff\n\n // 확장 크기\n if (size === 0xfff) {\n if (offset + 4 > data.length) break\n size = data.readUInt32LE(offset)\n offset += 4\n }\n\n if (offset + size > data.length) break\n records.push({ tagId, level, size, data: data.subarray(offset, offset + size) })\n offset += size\n }\n\n return records\n}\n\n// ─── 스트림 압축 해제 ────────────────────────────────\n\n/** 압축 해제 최대 크기 (500MB) — decompression bomb 방지 */\nconst MAX_DECOMPRESS_SIZE = 500 * 1024 * 1024\n\nexport function decompressStream(data: Buffer): Buffer {\n const opts = { maxOutputLength: MAX_DECOMPRESS_SIZE }\n if (data.length >= 2 && data[0] === 0x78) {\n try { return inflateSync(data, opts) } catch { /* fallback to raw */ }\n }\n return inflateRawSync(data, opts)\n}\n\n// ─── FileHeader 파싱 ─────────────────────────────────\n\nexport function parseFileHeader(data: Buffer): HwpFileHeader {\n if (data.length < 40) throw new KordocError(\"FileHeader가 너무 짧습니다 (최소 40바이트)\")\n const sig = data.subarray(0, 32).toString(\"utf8\").replace(/\\0+$/, \"\")\n return {\n signature: sig,\n versionMajor: data[35],\n flags: data.readUInt32LE(36),\n }\n}\n\n// ─── 스타일 정보 구조 ────────────────────────────────\n\n/** DocInfo에서 추출한 글자 모양 (CHAR_SHAPE) */\nexport interface HwpCharShape {\n /** 글꼴 크기 (단위: 0.1pt, 예: 100 = 10pt) */\n fontSize: number\n /**\n * 속성 플래그 (HWP5 바이너리 스펙 1.1 기준):\n * bit 0 = italic, bit 1 = bold, bit 2 = underline, bit 3 = outline\n * 검증 완료: 공식 스펙 + pyhwp/hwp.js 등 오픈소스 파서와 일치 (v1.7)\n */\n attrFlags: number\n}\n\n/** DocInfo에서 추출한 스타일 */\nexport interface HwpStyle {\n name: string\n /** 한글 이름 (UTF-16LE) */\n nameKo: string\n /** 연결된 charShape 인덱스 */\n charShapeId: number\n /** 연결된 paraShape 인덱스 */\n paraShapeId: number\n /** 스타일 타입: 0=paragraph, 1=character */\n type: number\n}\n\n/** DocInfo 파싱 결과 */\nexport interface HwpDocInfo {\n charShapes: HwpCharShape[]\n styles: HwpStyle[]\n}\n\n/** DocInfo 레코드들에서 스타일 정보 추출 */\nexport function parseDocInfo(records: HwpRecord[]): HwpDocInfo {\n const charShapes: HwpCharShape[] = []\n const styles: HwpStyle[] = []\n\n for (const rec of records) {\n if (rec.tagId === TAG_DOC_CHAR_SHAPE && rec.data.length >= 18) {\n // HWP5 CHAR_SHAPE 구조 (바이너리 스펙 1.1 기준):\n // faceId: 7개 언어 * u16 = 14바이트 (offset 0-13)\n // ratio: 7개 언어 * u8 = 7바이트 (offset 14-20)\n // spacing: 7개 언어 * s8 = 7바이트 (offset 21-27)\n // relSize: 7개 언어 * u8 = 7바이트 (offset 28-34)\n // charOffset: 7개 언어 * s8 = 7바이트 (offset 35-41)\n // baseSize: u32 at offset 42 (단위: 0.1pt)\n // attrFlags: u32 at offset 46 (bit0=italic, bit1=bold) — 공식 스펙 검증 완료\n if (rec.data.length >= 50) {\n const fontSize = rec.data.readUInt32LE(42) // 단위: 0.1pt\n const attrFlags = rec.data.readUInt32LE(46)\n charShapes.push({ fontSize, attrFlags })\n } else {\n // 짧은 레코드 — 스타일 정보 없음\n charShapes.push({ fontSize: 0, attrFlags: 0 })\n }\n }\n\n if (rec.tagId === TAG_DOC_STYLE && rec.data.length >= 8) {\n try {\n // STYLE 구조: nameLen(u16) + name(UTF-16LE) + nameKoLen(u16) + nameKo(UTF-16LE)\n // + type(u8) + nextStyleId(u16) + langId(s16) + paraShapeId(u16) + charShapeId(u16)\n let offset = 0\n const nameLen = rec.data.readUInt16LE(offset); offset += 2\n const nameBytes = nameLen * 2\n const name = nameBytes > 0 && offset + nameBytes <= rec.data.length\n ? rec.data.subarray(offset, offset + nameBytes).toString(\"utf16le\")\n : \"\"\n offset += nameBytes\n\n let nameKo = \"\"\n if (offset + 2 <= rec.data.length) {\n const nameKoLen = rec.data.readUInt16LE(offset); offset += 2\n const nameKoBytes = nameKoLen * 2\n if (nameKoBytes > 0 && offset + nameKoBytes <= rec.data.length) {\n nameKo = rec.data.subarray(offset, offset + nameKoBytes).toString(\"utf16le\")\n }\n offset += nameKoBytes\n }\n\n // type(u8) + nextStyleId(u16) + langId(s16) + paraShapeId(u16) + charShapeId(u16)\n const type = offset < rec.data.length ? rec.data.readUInt8(offset) : 0; offset += 1\n offset += 2 // nextStyleId\n offset += 2 // langId\n const paraShapeId = offset + 2 <= rec.data.length ? rec.data.readUInt16LE(offset) : 0; offset += 2\n const charShapeId = offset + 2 <= rec.data.length ? rec.data.readUInt16LE(offset) : 0\n\n styles.push({ name, nameKo, charShapeId, paraShapeId, type })\n } catch {\n // 파싱 실패 — 스킵\n }\n }\n }\n\n return { charShapes, styles }\n}\n\n// ─── UTF-16LE 텍스트 추출 (21가지 제어문자 처리) ─────\n\nexport function extractText(data: Buffer): string {\n let result = \"\"\n let i = 0\n\n while (i + 1 < data.length) {\n const ch = data.readUInt16LE(i)\n i += 2\n\n switch (ch) {\n // ── char 타입 (2바이트만, 확장 데이터 없음) ──\n case CHAR_LINE: result += \"\\n\"; break\n case CHAR_SECTION_BREAK: // 구역/단 정의 — extended(14바이트 스킵)\n result += \"\\n\"\n if (i + 14 <= data.length) i += 14\n break\n case CHAR_PARA: break // 문단 끝\n case CHAR_HYPHEN: result += \"-\"; break\n case CHAR_NBSP: result += \" \"; break\n case CHAR_FIXED_NBSP: result += \"\\u00a0\"; break // 진짜 NBSP\n case CHAR_FIXED_WIDTH: result += \" \"; break // 고정폭 공백\n\n // ── inline 타입 (2바이트 + 14바이트 확장) ──\n case CHAR_TAB:\n result += \"\\t\"\n if (i + 14 <= data.length) i += 14\n break\n\n default:\n if (ch >= 0x0001 && ch <= 0x001f) {\n // rhwp 기준 3-카테고리 분류:\n // extended(1-3, 11-12, 14-18, 21-23) + inline(4-9, 19-20) → 14바이트 스킵\n // char(24-31) → 스킵 없음 (이미 switch에서 24,25,30,31 처리됨)\n const isExtended = (ch >= 1 && ch <= 3) || (ch >= 11 && ch <= 12) || (ch >= 14 && ch <= 18) || (ch >= 21 && ch <= 23)\n const isInline = (ch >= 4 && ch <= 9) || (ch >= 19 && ch <= 20)\n if ((isExtended || isInline) && i + 14 <= data.length) i += 14\n } else if (ch >= 0x0020) {\n // UTF-16 surrogate pair 처리 (BMP 외 문자: 이모지, CJK 확장 등)\n if (ch >= 0xd800 && ch <= 0xdbff && i + 1 < data.length) {\n const lo = data.readUInt16LE(i)\n if (lo >= 0xdc00 && lo <= 0xdfff) {\n i += 2\n const codePoint = ((ch - 0xd800) << 10) + (lo - 0xdc00) + 0x10000\n result += String.fromCodePoint(codePoint)\n break\n }\n }\n result += String.fromCharCode(ch)\n }\n break\n }\n }\n\n return result\n}\n","/**\n * AES-128 ECB 순수 JS 구현 — 배포용 HWP 복호화 전용.\n * 외부 의존성 없음 (kordoc 제로 네이티브 의존성 원칙 유지).\n * 참조: rhwp (MIT) src/parser/crypto.rs + FIPS-197 (AES 표준)\n */\n\n// ── S-Box & 역 S-Box ──\n\nconst S_BOX = new Uint8Array([\n 0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,\n 0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,\n 0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,\n 0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,\n 0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,\n 0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,\n 0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,\n 0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,\n 0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,\n 0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,\n 0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,\n 0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,\n 0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,\n 0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,\n 0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,\n 0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16,\n])\n\nconst INV_S_BOX = new Uint8Array([\n 0x52,0x09,0x6a,0xd5,0x30,0x36,0xa5,0x38,0xbf,0x40,0xa3,0x9e,0x81,0xf3,0xd7,0xfb,\n 0x7c,0xe3,0x39,0x82,0x9b,0x2f,0xff,0x87,0x34,0x8e,0x43,0x44,0xc4,0xde,0xe9,0xcb,\n 0x54,0x7b,0x94,0x32,0xa6,0xc2,0x23,0x3d,0xee,0x4c,0x95,0x0b,0x42,0xfa,0xc3,0x4e,\n 0x08,0x2e,0xa1,0x66,0x28,0xd9,0x24,0xb2,0x76,0x5b,0xa2,0x49,0x6d,0x8b,0xd1,0x25,\n 0x72,0xf8,0xf6,0x64,0x86,0x68,0x98,0x16,0xd4,0xa4,0x5c,0xcc,0x5d,0x65,0xb6,0x92,\n 0x6c,0x70,0x48,0x50,0xfd,0xed,0xb9,0xda,0x5e,0x15,0x46,0x57,0xa7,0x8d,0x9d,0x84,\n 0x90,0xd8,0xab,0x00,0x8c,0xbc,0xd3,0x0a,0xf7,0xe4,0x58,0x05,0xb8,0xb3,0x45,0x06,\n 0xd0,0x2c,0x1e,0x8f,0xca,0x3f,0x0f,0x02,0xc1,0xaf,0xbd,0x03,0x01,0x13,0x8a,0x6b,\n 0x3a,0x91,0x11,0x41,0x4f,0x67,0xdc,0xea,0x97,0xf2,0xcf,0xce,0xf0,0xb4,0xe6,0x73,\n 0x96,0xac,0x74,0x22,0xe7,0xad,0x35,0x85,0xe2,0xf9,0x37,0xe8,0x1c,0x75,0xdf,0x6e,\n 0x47,0xf1,0x1a,0x71,0x1d,0x29,0xc5,0x89,0x6f,0xb7,0x62,0x0e,0xaa,0x18,0xbe,0x1b,\n 0xfc,0x56,0x3e,0x4b,0xc6,0xd2,0x79,0x20,0x9a,0xdb,0xc0,0xfe,0x78,0xcd,0x5a,0xf4,\n 0x1f,0xdd,0xa8,0x33,0x88,0x07,0xc7,0x31,0xb1,0x12,0x10,0x59,0x27,0x80,0xec,0x5f,\n 0x60,0x51,0x7f,0xa9,0x19,0xb5,0x4a,0x0d,0x2d,0xe5,0x7a,0x9f,0x93,0xc9,0x9c,0xef,\n 0xa0,0xe0,0x3b,0x4d,0xae,0x2a,0xf5,0xb0,0xc8,0xeb,0xbb,0x3c,0x83,0x53,0x99,0x61,\n 0x17,0x2b,0x04,0x7e,0xba,0x77,0xd6,0x26,0xe1,0x69,0x14,0x63,0x55,0x21,0x0c,0x7d,\n])\n\n// ── RCON (라운드 상수) ──\n\nconst RCON = new Uint8Array([0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36])\n\n// ── GF(2^8) 곱셈 ──\n\nfunction gmul(a: number, b: number): number {\n let p = 0\n for (let i = 0; i < 8; i++) {\n if (b & 1) p ^= a\n const hi = a & 0x80\n a = (a << 1) & 0xff\n if (hi) a ^= 0x1b\n b >>= 1\n }\n return p\n}\n\n// ── 키 확장 (AES-128: 4 words → 44 words) ──\n\nfunction expandKey(key: Uint8Array): Uint32Array {\n const w = new Uint32Array(44)\n\n // 첫 4 words: 원본 키\n for (let i = 0; i < 4; i++) {\n w[i] = (key[4 * i] << 24) | (key[4 * i + 1] << 16) | (key[4 * i + 2] << 8) | key[4 * i + 3]\n }\n\n for (let i = 4; i < 44; i++) {\n let temp = w[i - 1]\n if (i % 4 === 0) {\n // RotWord + SubWord + RCON\n temp = ((temp << 8) | (temp >>> 24)) >>> 0\n temp = (S_BOX[(temp >>> 24) & 0xff] << 24) |\n (S_BOX[(temp >>> 16) & 0xff] << 16) |\n (S_BOX[(temp >>> 8) & 0xff] << 8) |\n S_BOX[temp & 0xff]\n temp = (temp ^ (RCON[i / 4 - 1] << 24)) >>> 0\n }\n w[i] = (w[i - 4] ^ temp) >>> 0\n }\n\n return w\n}\n\n// ── AES-128 단일 블록 복호화 (16바이트) ──\n\nfunction decryptBlock(block: Uint8Array, roundKeys: Uint32Array): Uint8Array {\n // state를 4x4 column-major 배열로 로드\n const s = new Uint8Array(16)\n for (let i = 0; i < 16; i++) s[i] = block[i]\n\n // AddRoundKey (round 10)\n addRoundKey(s, roundKeys, 10)\n\n // Rounds 9 → 1\n for (let round = 9; round >= 1; round--) {\n invShiftRows(s)\n invSubBytes(s)\n addRoundKey(s, roundKeys, round)\n invMixColumns(s)\n }\n\n // Final round (round 0)\n invShiftRows(s)\n invSubBytes(s)\n addRoundKey(s, roundKeys, 0)\n\n return s\n}\n\nfunction addRoundKey(s: Uint8Array, w: Uint32Array, round: number): void {\n const base = round * 4\n for (let c = 0; c < 4; c++) {\n const k = w[base + c]\n s[c * 4] ^= (k >>> 24) & 0xff\n s[c * 4 + 1] ^= (k >>> 16) & 0xff\n s[c * 4 + 2] ^= (k >>> 8) & 0xff\n s[c * 4 + 3] ^= k & 0xff\n }\n}\n\nfunction invSubBytes(s: Uint8Array): void {\n for (let i = 0; i < 16; i++) s[i] = INV_S_BOX[s[i]]\n}\n\nfunction invShiftRows(s: Uint8Array): void {\n // Row 0: no shift\n // Row 1: shift right 1\n let t = s[13]; s[13] = s[9]; s[9] = s[5]; s[5] = s[1]; s[1] = t\n // Row 2: shift right 2\n t = s[2]; s[2] = s[10]; s[10] = t\n t = s[6]; s[6] = s[14]; s[14] = t\n // Row 3: shift right 3 (= left 1)\n t = s[3]; s[3] = s[7]; s[7] = s[11]; s[11] = s[15]; s[15] = t\n}\n\nfunction invMixColumns(s: Uint8Array): void {\n for (let c = 0; c < 4; c++) {\n const i = c * 4\n const a0 = s[i], a1 = s[i + 1], a2 = s[i + 2], a3 = s[i + 3]\n s[i] = gmul(a0, 0x0e) ^ gmul(a1, 0x0b) ^ gmul(a2, 0x0d) ^ gmul(a3, 0x09)\n s[i + 1] = gmul(a0, 0x09) ^ gmul(a1, 0x0e) ^ gmul(a2, 0x0b) ^ gmul(a3, 0x0d)\n s[i + 2] = gmul(a0, 0x0d) ^ gmul(a1, 0x09) ^ gmul(a2, 0x0e) ^ gmul(a3, 0x0b)\n s[i + 3] = gmul(a0, 0x0b) ^ gmul(a1, 0x0d) ^ gmul(a2, 0x09) ^ gmul(a3, 0x0e)\n }\n}\n\n// ── 공개 API ──\n\n/** AES-128 ECB 복호화. data 길이는 16의 배수여야 함. */\nexport function aes128EcbDecrypt(data: Uint8Array, key: Uint8Array): Uint8Array {\n if (key.length !== 16) throw new Error(\"AES-128 키는 16바이트여야 합니다\")\n if (data.length % 16 !== 0) throw new Error(\"AES ECB 입력은 16바이트의 배수여야 합니다\")\n\n const roundKeys = expandKey(key)\n const out = new Uint8Array(data.length)\n\n for (let offset = 0; offset < data.length; offset += 16) {\n const block = data.subarray(offset, offset + 16)\n const decrypted = decryptBlock(block, roundKeys)\n out.set(decrypted, offset)\n }\n\n return out\n}\n","/**\n * HWP 배포용(distribution) 문서 복호화.\n *\n * 배포용 HWP는 ViewText/Section{N} 스트림에 암호화된 본문을 저장.\n * 첫 레코드(HWPTAG_DISTRIBUTE_DOC_DATA)의 256바이트 payload에서 AES 키를 추출한 뒤\n * 나머지 데이터를 AES-128 ECB로 복호화.\n *\n * 알고리즘 참조: rhwp (MIT) src/parser/crypto.rs\n * 포맷 참조: HWP 5.0 바이너리 스펙 — 배포용 문서 구조\n */\n\nimport { aes128EcbDecrypt } from \"./aes.js\"\nimport { decompressStream } from \"./record.js\"\n\n// ── MSVC LCG (Linear Congruential Generator) ──\n\n/** MSVC CRT rand() 호환 LCG */\nclass MsvcLcg {\n private seed: number\n\n constructor(seed: number) {\n this.seed = seed >>> 0 // u32로 강제\n }\n\n /** 0 ~ 0x7FFF 범위 난수 반환 (MSVC rand() 호환) */\n rand(): number {\n // MSVC LCG: seed = seed * 214013 + 2531011\n // JS에서 32bit 정수 오버플로우를 정확히 재현하기 위해 Math.imul 사용\n this.seed = (Math.imul(this.seed, 214013) + 2531011) >>> 0\n return (this.seed >>> 16) & 0x7fff\n }\n}\n\n// ── 배포용 문서 256바이트 payload 복호화 ──\n\n/**\n * DISTRIBUTE_DOC_DATA 레코드의 256바이트 payload를 LCG+XOR로 복호화.\n *\n * 구조:\n * - bytes[0..4]: LCG seed (u32 LE)\n * - bytes[4..256]: XOR 암호화된 데이터\n *\n * XOR 규칙: LCG에서 키 바이트를 뽑고, n = (lcg.rand() & 0xF) + 1 바이트마다 키 교체\n */\nfunction decryptDistributePayload(payload: Uint8Array): Uint8Array {\n if (payload.length < 256) throw new Error(\"배포용 payload가 256바이트 미만입니다\")\n\n const seed = (payload[0] | (payload[1] << 8) | (payload[2] << 16) | (payload[3] << 24)) >>> 0\n const lcg = new MsvcLcg(seed)\n\n const result = new Uint8Array(payload.subarray(0, 256)) // 원본 복사\n\n // rhwp 호환: i=0부터 시작하여 n 카운터를 소비하되, i<4는 XOR 스킵 (seed 보존)\n // i=4부터 시작하면 LCG 시퀀스가 어긋남 — i=0~3에서도 n을 소비해야 정확함\n let i = 0\n let n = 0\n let key = 0\n\n while (i < 256) {\n if (n === 0) {\n key = lcg.rand() & 0xff\n n = (lcg.rand() & 0x0f) + 1\n }\n if (i >= 4) {\n result[i] ^= key\n }\n i++\n n--\n }\n\n return result\n}\n\n// ── AES 키 추출 ──\n\n/**\n * 복호화된 256바이트 payload에서 AES-128 키(16바이트) 추출.\n * offset = 4 + (decrypted[0] & 0x0F)\n */\nfunction extractAesKey(decryptedPayload: Uint8Array): Uint8Array {\n const offset = 4 + (decryptedPayload[0] & 0x0f)\n if (offset + 16 > decryptedPayload.length) {\n throw new Error(\"AES 키 추출 실패: 오프셋이 payload 범위를 초과합니다\")\n }\n return decryptedPayload.slice(offset, offset + 16)\n}\n\n// ── 레코드 헤더 파싱 ──\n\n/** HWP 레코드 헤더에서 tag_id와 size 추출 */\nfunction parseRecordHeader(data: Uint8Array, offset: number): { tagId: number; size: number; headerSize: number } {\n if (offset + 4 > data.length) throw new Error(\"레코드 헤더 파싱 실패: 데이터 부족\")\n\n const header = (data[offset] | (data[offset + 1] << 8) | (data[offset + 2] << 16) | (data[offset + 3] << 24)) >>> 0\n const tagId = header & 0x3ff\n let size = (header >>> 20) & 0xfff\n let headerSize = 4\n\n if (size === 0xfff) {\n if (offset + 8 > data.length) throw new Error(\"확장 레코드 크기 파싱 실패: 데이터 부족\")\n size = (data[offset + 4] | (data[offset + 5] << 8) | (data[offset + 6] << 16) | (data[offset + 7] << 24)) >>> 0\n headerSize = 8\n }\n\n return { tagId, size, headerSize }\n}\n\n// ── 공개 API ──\n\n/** HWPTAG_DISTRIBUTE_DOC_DATA 태그 ID (HWPTAG_BEGIN + 12 = 0x10 + 12 = 0x1C = 28) */\nconst TAG_DISTRIBUTE_DOC_DATA = 0x10 + 12 // = 28\n\n/**\n * ViewText 스트림을 복호화하여 일반 BodyText 레코드 데이터로 변환.\n *\n * @param viewTextRaw ViewText/Section{N} 스트림의 원본 바이트\n * @param compressed FileHeader의 compressed 플래그\n * @returns 복호화된 레코드 데이터 (readRecords()로 파싱 가능)\n */\nexport function decryptViewText(viewTextRaw: Buffer, compressed: boolean): Buffer {\n const data = new Uint8Array(viewTextRaw)\n\n // 1. 첫 레코드 파싱 (DISTRIBUTE_DOC_DATA)\n const rec = parseRecordHeader(data, 0)\n if (rec.tagId !== TAG_DISTRIBUTE_DOC_DATA) {\n throw new Error(`배포용 문서의 첫 레코드가 DISTRIBUTE_DOC_DATA(${TAG_DISTRIBUTE_DOC_DATA})가 아닙니다 (실제: ${rec.tagId})`)\n }\n\n const payloadStart = rec.headerSize\n const payloadEnd = payloadStart + rec.size\n if (payloadEnd > data.length || rec.size < 256) {\n throw new Error(\"배포용 payload가 유효하지 않습니다\")\n }\n\n // 2. 256바이트 payload 복호화 (LCG + XOR)\n const payload = data.subarray(payloadStart, payloadStart + 256)\n const decryptedPayload = decryptDistributePayload(payload)\n\n // 3. AES-128 키 추출\n const aesKey = extractAesKey(decryptedPayload)\n\n // 4. 나머지 데이터를 AES-128 ECB 복호화\n const encryptedStart = payloadEnd\n const encryptedData = data.subarray(encryptedStart)\n\n if (encryptedData.length === 0) {\n throw new Error(\"배포용 문서에 암호화된 본문 데이터가 없습니다\")\n }\n\n // AES ECB는 16바이트 블록 단위 — 패딩 처리\n const alignedLen = encryptedData.length - (encryptedData.length % 16)\n if (alignedLen === 0) {\n throw new Error(\"암호화된 데이터가 너무 짧습니다 (16바이트 미만)\")\n }\n\n const alignedData = encryptedData.subarray(0, alignedLen)\n const decrypted = aes128EcbDecrypt(alignedData, aesKey)\n\n // 5. 압축 해제 (compressed 플래그가 설정된 경우)\n if (compressed) {\n try {\n return decompressStream(Buffer.from(decrypted))\n } catch {\n // 압축이 아닐 수도 있음 — 그대로 반환\n return Buffer.from(decrypted)\n }\n }\n\n return Buffer.from(decrypted)\n}\n\n// 테스트용 내부 함수 export\nexport { MsvcLcg as _MsvcLcg, decryptDistributePayload as _decryptDistributePayload, extractAesKey as _extractAesKey }\n","/**\n * Lenient CFB (Compound File Binary / OLE2) 파서.\n *\n * 표준 cfb 모듈이 FAT 검증 실패로 거부하는 손상된 HWP 파일을 열기 위한 폴백.\n * 직접 헤더/FAT/디렉토리를 파싱하여 스트림 데이터를 추출.\n *\n * 참조: rhwp (MIT) src/parser/cfb_reader.rs (LenientCfbReader)\n * 참조: MS-CFB spec (https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cfb)\n */\n\nimport { decompressStream } from \"./record.js\"\n\n// ── 상수 ──\n\nconst CFB_MAGIC = Buffer.from([0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1])\nconst END_OF_CHAIN = 0xfffffffe\nconst FREE_SECT = 0xffffffff\n\n/** 순환 감지용 최대 체인 길이 */\nconst MAX_CHAIN_LENGTH = 1_000_000\n/** 최대 디렉토리 엔트리 수 */\nconst MAX_DIR_ENTRIES = 100_000\n/** 최대 스트림 크기 (100MB) */\nconst MAX_STREAM_SIZE = 500 * 1024 * 1024\n\n// ── 디렉토리 엔트리 ──\n\ninterface DirEntry {\n name: string\n type: number // 0=unknown, 1=storage, 2=stream, 5=root\n startSector: number\n size: number\n}\n\n// ── CFB 컨테이너 ──\n\nexport interface LenientCfbContainer {\n /** 이름 기반 스트림 탐색 */\n findStream(path: string): Buffer | null\n /** 디렉토리 엔트리 목록 */\n entries(): DirEntry[]\n}\n\n// ── 구현 ──\n\nexport function parseLenientCfb(data: Buffer): LenientCfbContainer {\n if (data.length < 512) throw new Error(\"CFB 파일이 너무 짧습니다 (최소 512바이트)\")\n if (!data.subarray(0, 8).equals(CFB_MAGIC)) throw new Error(\"CFB 매직 바이트 불일치\")\n\n // ── 헤더 파싱 ──\n\n const sectorSizeShift = data.readUInt16LE(30)\n if (sectorSizeShift < 7 || sectorSizeShift > 16) throw new Error(\"유효하지 않은 섹터 크기 시프트: \" + sectorSizeShift)\n const sectorSize = 1 << sectorSizeShift // 보통 512\n const miniSectorSizeShift = data.readUInt16LE(32)\n if (miniSectorSizeShift > 16) throw new Error(\"유효하지 않은 미니 섹터 크기 시프트: \" + miniSectorSizeShift)\n const miniSectorSize = 1 << miniSectorSizeShift // 보통 64\n\n const fatSectorCount = data.readUInt32LE(44)\n const firstDirSector = data.readUInt32LE(48)\n const miniStreamCutoff = data.readUInt32LE(56) // 보통 4096\n const firstMiniFatSector = data.readUInt32LE(60)\n const miniFatSectorCount = data.readUInt32LE(64)\n const firstDifatSector = data.readUInt32LE(68)\n const difatSectorCount = data.readUInt32LE(72)\n\n // ── 유틸 ──\n\n function sectorOffset(id: number): number {\n return 512 + id * sectorSize\n }\n\n function readSectorData(id: number): Buffer {\n const off = sectorOffset(id)\n if (off + sectorSize > data.length) return Buffer.alloc(0)\n return data.subarray(off, off + sectorSize)\n }\n\n // ── DIFAT → FAT 섹터 목록 ──\n\n const fatSectors: number[] = []\n\n // 헤더 내 DIFAT (최대 109개)\n for (let i = 0; i < 109 && fatSectors.length < fatSectorCount; i++) {\n const sid = data.readUInt32LE(76 + i * 4)\n if (sid === FREE_SECT || sid === END_OF_CHAIN) break\n fatSectors.push(sid)\n }\n\n // 추가 DIFAT 섹터 체인\n let difatSector = firstDifatSector\n const visitedDifat = new Set<number>()\n for (let d = 0; d < difatSectorCount && difatSector !== END_OF_CHAIN && difatSector !== FREE_SECT; d++) {\n if (visitedDifat.has(difatSector)) break\n visitedDifat.add(difatSector)\n\n const buf = readSectorData(difatSector)\n const entriesPerSector = (sectorSize / 4) - 1 // 마지막 4바이트는 다음 DIFAT 포인터\n for (let i = 0; i < entriesPerSector && fatSectors.length < fatSectorCount; i++) {\n const sid = buf.readUInt32LE(i * 4)\n if (sid === FREE_SECT || sid === END_OF_CHAIN) continue\n fatSectors.push(sid)\n }\n difatSector = buf.readUInt32LE(entriesPerSector * 4)\n }\n\n // ── FAT 테이블 구축 ──\n\n const entriesPerFatSector = sectorSize / 4\n const fatTable = new Uint32Array(fatSectors.length * entriesPerFatSector)\n\n for (let fi = 0; fi < fatSectors.length; fi++) {\n const buf = readSectorData(fatSectors[fi])\n for (let i = 0; i < entriesPerFatSector; i++) {\n fatTable[fi * entriesPerFatSector + i] = i * 4 + 3 < buf.length\n ? buf.readUInt32LE(i * 4)\n : FREE_SECT\n }\n }\n\n // ── 체인 리더 (순환 방지) ──\n\n function readChain(startSector: number, maxBytes: number): Buffer {\n if (startSector === END_OF_CHAIN || startSector === FREE_SECT) return Buffer.alloc(0)\n if (maxBytes > MAX_STREAM_SIZE) throw new Error(\"스트림이 너무 큽니다\")\n\n const chunks: Buffer[] = []\n let current = startSector\n let totalRead = 0\n const visited = new Set<number>()\n\n while (current !== END_OF_CHAIN && current !== FREE_SECT && totalRead < maxBytes) {\n if (visited.has(current)) break // 순환 감지\n if (visited.size > MAX_CHAIN_LENGTH) break\n visited.add(current)\n\n const buf = readSectorData(current)\n const remaining = maxBytes - totalRead\n chunks.push(remaining < sectorSize ? buf.subarray(0, remaining) : buf)\n totalRead += Math.min(buf.length, remaining)\n\n current = current < fatTable.length ? fatTable[current] : END_OF_CHAIN\n }\n\n return Buffer.concat(chunks)\n }\n\n // ── Mini-FAT 테이블 ──\n\n let miniFatTable: Uint32Array | null = null\n\n function getMiniFatTable(): Uint32Array {\n if (miniFatTable) return miniFatTable\n\n if (miniFatSectorCount === 0 || firstMiniFatSector === END_OF_CHAIN) {\n miniFatTable = new Uint32Array(0)\n return miniFatTable\n }\n\n const miniFatData = readChain(firstMiniFatSector, miniFatSectorCount * sectorSize)\n const entries = miniFatData.length / 4\n miniFatTable = new Uint32Array(entries)\n for (let i = 0; i < entries; i++) {\n miniFatTable[i] = miniFatData.readUInt32LE(i * 4)\n }\n return miniFatTable\n }\n\n // ── 디렉토리 엔트리 파싱 ──\n\n const dirData = readChain(firstDirSector, MAX_DIR_ENTRIES * 128)\n const dirEntries: DirEntry[] = []\n\n for (let offset = 0; offset + 128 <= dirData.length && dirEntries.length < MAX_DIR_ENTRIES; offset += 128) {\n const nameLen = dirData.readUInt16LE(offset + 64) // 바이트 수 (null 포함)\n if (nameLen <= 0 || nameLen > 64) {\n dirEntries.push({ name: \"\", type: 0, startSector: 0, size: 0 })\n continue\n }\n\n const nameBytes = nameLen - 2 // null terminator 제외\n const name = nameBytes > 0\n ? dirData.subarray(offset, offset + nameBytes).toString(\"utf16le\")\n : \"\"\n\n const type = dirData[offset + 66]\n const startSector = dirData.readUInt32LE(offset + 116)\n // CFBv3에서는 size가 u32 (offset 120), v4에서는 u64\n const size = dirData.readUInt32LE(offset + 120)\n\n dirEntries.push({ name, type, startSector, size })\n }\n\n // ── Root 엔트리에서 미니 스트림 추출 ──\n\n let miniStreamData: Buffer | null = null\n\n function getMiniStream(): Buffer {\n if (miniStreamData) return miniStreamData\n const root = dirEntries[0]\n if (!root || root.type !== 5) {\n miniStreamData = Buffer.alloc(0)\n return miniStreamData\n }\n miniStreamData = readChain(root.startSector, root.size || MAX_STREAM_SIZE)\n return miniStreamData\n }\n\n // ── 미니 스트림에서 읽기 ──\n\n function readMiniStream(startSector: number, size: number): Buffer {\n const mft = getMiniFatTable()\n const ms = getMiniStream()\n if (mft.length === 0 || ms.length === 0) return Buffer.alloc(0)\n\n const chunks: Buffer[] = []\n let current = startSector\n let totalRead = 0\n const visited = new Set<number>()\n\n while (current !== END_OF_CHAIN && current !== FREE_SECT && totalRead < size) {\n if (visited.has(current)) break\n if (visited.size > MAX_CHAIN_LENGTH) break\n visited.add(current)\n\n const off = current * miniSectorSize\n const remaining = size - totalRead\n const chunkSize = Math.min(miniSectorSize, remaining)\n if (off + chunkSize <= ms.length) {\n chunks.push(ms.subarray(off, off + chunkSize))\n }\n totalRead += chunkSize\n\n current = current < mft.length ? mft[current] : END_OF_CHAIN\n }\n\n return Buffer.concat(chunks)\n }\n\n // ── 스트림 읽기 (일반/미니 자동 분기) ──\n\n function readStreamData(entry: DirEntry): Buffer {\n if (entry.size === 0) return Buffer.alloc(0)\n if (entry.size < miniStreamCutoff) {\n const miniResult = readMiniStream(entry.startSector, entry.size)\n // 미니스트림이 비어있으면 일반 체인으로 폴백 (lenient)\n if (miniResult.length > 0) return miniResult\n }\n return readChain(entry.startSector, entry.size)\n }\n\n // ── 경로 기반 탐색 ──\n\n // 전체 경로 맵 구축 (간이: 이름 기반 flat lookup)\n // HWP 파일의 디렉토리 구조는 보통 1~2 depth이므로 이름 매칭으로 충분\n function findEntryByPath(path: string): DirEntry | null {\n // \"/FileHeader\" → \"FileHeader\"\n // \"/BodyText/Section0\" → path component matching\n const parts = path.replace(/^\\//, \"\").split(\"/\")\n\n if (parts.length === 1) {\n // 단일 이름 매칭\n return dirEntries.find(e => e.name === parts[0] && e.type === 2) ?? null\n }\n\n // 2-depth: storage/stream\n // HWP 구조: Root/BodyText/Section0, Root/DocInfo, Root/BinData/BIN0001 등\n const storageName = parts[0]\n const streamName = parts.slice(1).join(\"/\")\n\n // 디렉토리 구조 대신 이름 패턴으로 찾기 (lenient)\n for (const e of dirEntries) {\n if (e.type === 2 && e.name === streamName) {\n // 부모 확인은 생략 (lenient) — 중복 이름 시 첫 번째 반환\n return e\n }\n }\n\n // 정확한 이름이 아닌 경우 (ViewText/Section0 등)\n const lastPart = parts[parts.length - 1]\n return dirEntries.find(e => e.type === 2 && e.name === lastPart) ?? null\n }\n\n // ── 공개 API ──\n\n return {\n findStream(path: string): Buffer | null {\n // \\005 prefix 처리 (SummaryInformation)\n const normalized = path.replace(/^\\//, \"\")\n const entry = findEntryByPath(normalized)\n if (!entry || entry.type !== 2) return null\n const stream = readStreamData(entry)\n return stream.length > 0 ? stream : null\n },\n\n entries(): DirEntry[] {\n return dirEntries.filter(e => e.type === 2) // stream만\n },\n }\n}\n","/** HWP 5.x 바이너리 파서 — OLE2 컨테이너 → 섹션 → Markdown */\n\nimport {\n readRecords, decompressStream, parseFileHeader, extractText, parseDocInfo,\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 type HwpRecord, type HwpDocInfo, type HwpCharShape,\n} from \"./record.js\"\nimport { decryptViewText } from \"./crypto.js\"\nimport { parseLenientCfb, type LenientCfbContainer } from \"./cfb-lenient.js\"\nimport { buildTable, blocksToMarkdown, MAX_COLS, MAX_ROWS } from \"../table/builder.js\"\nimport type { CellContext, IRBlock, IRTable, DocumentMetadata, InternalParseResult, ParseOptions, ParseWarning, OutlineItem, InlineStyle, ExtractedImage } from \"../types.js\"\nimport { HEADING_RATIO_H1, HEADING_RATIO_H2, HEADING_RATIO_H3 } from \"../types.js\"\nimport { KordocError, sanitizeHref } from \"../utils.js\"\nimport { parsePageRange } from \"../page-range.js\"\n\nimport * as CFB from \"cfb\"\n\ninterface CfbEntry { name?: string; content?: Buffer | Uint8Array }\ninterface CfbContainer { FileIndex?: CfbEntry[] }\ninterface CfbModule {\n parse(data: Buffer): CfbContainer\n find(cfb: CfbContainer, path: string): CfbEntry | null\n}\n\n/** 최대 섹션 수 — 비정상 파일에 의한 무한 루프 방지 */\nconst MAX_SECTIONS = 100\n/** 누적 압축 해제 최대 크기 (100MB) */\nconst MAX_TOTAL_DECOMPRESS = 500 * 1024 * 1024\n\nexport function parseHwp5Document(buffer: Buffer, options?: ParseOptions): InternalParseResult {\n // CFB 파싱: strict 먼저, 실패 시 lenient 폴백\n let cfb: CfbContainer | null = null\n let lenientCfb: LenientCfbContainer | null = null\n const warnings: ParseWarning[] = []\n\n try {\n cfb = CFB.parse(buffer)\n } catch {\n try {\n lenientCfb = parseLenientCfb(buffer)\n warnings.push({ message: \"손상된 CFB 컨테이너 — lenient 모드로 복구\", code: \"LENIENT_CFB_RECOVERY\" })\n } catch {\n throw new KordocError(\"CFB 컨테이너 파싱 실패 (strict 및 lenient 모두)\")\n }\n }\n\n // CFB 래퍼: strict/lenient 통합 인터페이스\n const findStream = (path: string): Buffer | null => {\n if (cfb) {\n const entry = CFB.find(cfb, path)\n return entry?.content ? Buffer.from(entry.content) : null\n }\n return lenientCfb!.findStream(path)\n }\n\n const headerData = findStream(\"/FileHeader\")\n if (!headerData) throw new KordocError(\"FileHeader 스트림 없음\")\n const header = parseFileHeader(headerData)\n if (header.signature !== \"HWP Document File\") throw new KordocError(\"HWP 시그니처 불일치\")\n if (header.flags & FLAG_ENCRYPTED) throw new KordocError(\"암호화된 HWP는 지원하지 않습니다\")\n if (header.flags & FLAG_DRM) throw new KordocError(\"DRM 보호된 HWP는 지원하지 않습니다\")\n const compressed = (header.flags & FLAG_COMPRESSED) !== 0\n const distribution = (header.flags & FLAG_DISTRIBUTION) !== 0\n\n const metadata: DocumentMetadata = {\n version: `${header.versionMajor}.x`,\n }\n if (cfb) extractHwp5Metadata(cfb, metadata)\n\n // DocInfo 파싱 (스타일 정보 추출)\n const docInfo = cfb\n ? parseDocInfoStream(cfb, compressed)\n : parseDocInfoFromStream(findStream(\"/DocInfo\"), compressed)\n\n const sections = distribution\n ? (cfb ? findViewTextSections(cfb, compressed) : findViewTextSectionsLenient(lenientCfb!, compressed))\n : (cfb ? findSections(cfb) : findSectionsLenient(lenientCfb!, compressed))\n if (sections.length === 0) throw new KordocError(\"섹션 스트림을 찾을 수 없습니다\")\n\n metadata.pageCount = sections.length\n\n // 페이지 범위 필터링 (섹션 단위 근사치)\n const pageFilter = options?.pages ? parsePageRange(options.pages, sections.length) : null\n const totalTarget = pageFilter ? pageFilter.size : sections.length\n\n const blocks: IRBlock[] = []\n let totalDecompressed = 0\n let parsedSections = 0\n for (let si = 0; si < sections.length; si++) {\n if (pageFilter && !pageFilter.has(si + 1)) continue\n try {\n const sectionData = sections[si]\n // 배포용 문서는 findViewTextSections에서 이미 복호화+압축해제 완료\n const data = (!distribution && compressed) ? decompressStream(Buffer.from(sectionData)) : Buffer.from(sectionData)\n totalDecompressed += data.length\n if (totalDecompressed > MAX_TOTAL_DECOMPRESS) throw new KordocError(\"총 압축 해제 크기 초과 (decompression bomb 의심)\")\n const records = readRecords(data)\n const sectionBlocks = parseSection(records, docInfo, warnings, si + 1)\n blocks.push(...sectionBlocks)\n parsedSections++\n options?.onProgress?.(parsedSections, totalTarget)\n } catch (secErr) {\n if (secErr instanceof KordocError) throw secErr\n warnings.push({ page: si + 1, message: `섹션 ${si + 1} 파싱 실패: ${secErr instanceof Error ? secErr.message : \"알 수 없는 오류\"}`, code: \"PARTIAL_PARSE\" })\n }\n }\n\n // BinData에서 이미지 추출\n const images = cfb\n ? extractHwp5Images(cfb, blocks, compressed, warnings)\n : extractHwp5ImagesLenient(lenientCfb!, blocks, compressed, warnings)\n\n // 스타일 기반 헤딩 감지\n if (docInfo) {\n detectHwp5Headings(blocks, docInfo)\n }\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/** DocInfo 스트림 파싱 (best-effort) */\nfunction parseDocInfoStream(cfb: CfbContainer, compressed: boolean): HwpDocInfo | null {\n try {\n const entry = CFB.find(cfb, \"/DocInfo\")\n if (!entry?.content) return null\n const data = compressed ? decompressStream(Buffer.from(entry.content)) : Buffer.from(entry.content)\n const records = readRecords(data)\n return parseDocInfo(records)\n } catch {\n return null\n }\n}\n\n/** DocInfo — Buffer에서 직접 파싱 (lenient용) */\nfunction parseDocInfoFromStream(raw: Buffer | null, compressed: boolean): HwpDocInfo | null {\n if (!raw) return null\n try {\n const data = compressed ? decompressStream(raw) : raw\n return parseDocInfo(readRecords(data))\n } catch {\n return null\n }\n}\n\n/** 스타일 기반 헤딩 감지 — 큰 폰트 + 짧은 텍스트 → heading */\nfunction detectHwp5Headings(blocks: IRBlock[], docInfo: HwpDocInfo): void {\n // 기본 폰트 크기 결정 (본문 스타일 또는 가장 많이 사용되는 크기)\n let baseFontSize = 0\n\n // \"바탕글\", \"본문\" 등 본문 스타일 찾기\n for (const style of docInfo.styles) {\n const name = (style.nameKo || style.name).toLowerCase()\n if (name.includes(\"바탕\") || name.includes(\"본문\") || name === \"normal\" || name === \"body\") {\n const cs = docInfo.charShapes[style.charShapeId]\n // cs.fontSize는 0.1pt 단위 → pt로 변환 (블록의 style.fontSize와 동일 단위)\n if (cs?.fontSize > 0) { baseFontSize = cs.fontSize / 10; break }\n }\n }\n\n // 본문 스타일 못 찾으면 블록의 폰트 크기 중 최빈값 사용\n if (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\n if (baseFontSize <= 0) return\n\n for (const block of blocks) {\n if (block.type !== \"paragraph\" || !block.text || !block.style?.fontSize) continue\n const text = block.text.trim()\n if (text.length === 0 || text.length > 200) continue\n if (/^\\d+$/.test(text)) continue\n\n const ratio = block.style.fontSize / baseFontSize\n let level = 0\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장\" 패턴은 heading으로 강제 지정\n if (/^제\\d+[조장절편]/.test(text) && 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// ─── 메타데이터 추출 (best-effort) ───────────────────\n\n/**\n * OLE2 SummaryInformation 스트림에서 제목/작성자 추출.\n * HWP5는 \\005HwpSummaryInformation 또는 \\005SummaryInformation에 저장.\n * OLE2 Property Set 포맷의 간이 파싱 — 실패 시 조용히 무시.\n */\nfunction extractHwp5Metadata(cfb: CfbContainer, metadata: DocumentMetadata): void {\n try {\n // HWP 전용 SummaryInformation 먼저, 없으면 표준 OLE2\n const summaryEntry =\n CFB.find(cfb, \"/\\x05HwpSummaryInformation\") ||\n CFB.find(cfb, \"/\\x05SummaryInformation\")\n if (!summaryEntry?.content) return\n\n const data = Buffer.from(summaryEntry.content)\n if (data.length < 48) return\n\n // OLE2 Property Set Header: byte order(2) + version(2) + OS(4) + CLSID(16) + numSets(4) = 28\n // Then FMTID(16) + offset(4)\n const numSets = data.readUInt32LE(24)\n if (numSets === 0) return\n\n const setOffset = data.readUInt32LE(44)\n if (setOffset >= data.length - 8) return\n\n // Property Set: size(4) + numProperties(4) + [propertyId(4) + offset(4)] * N\n const numProps = data.readUInt32LE(setOffset + 4)\n if (numProps === 0 || numProps > 100) return\n\n for (let i = 0; i < numProps; i++) {\n const entryOffset = setOffset + 8 + i * 8\n if (entryOffset + 8 > data.length) break\n\n const propId = data.readUInt32LE(entryOffset)\n const propOffset = setOffset + data.readUInt32LE(entryOffset + 4)\n if (propOffset + 8 > data.length) continue\n\n // Property ID: 2=Title, 4=Author, 6=Subject/Description\n if (propId !== 2 && propId !== 4 && propId !== 6) continue\n\n const propType = data.readUInt32LE(propOffset)\n // Type 0x1E = VT_LPSTR (ANSI string)\n if (propType !== 0x1e) continue\n\n const strLen = data.readUInt32LE(propOffset + 4)\n if (strLen === 0 || strLen > 10000 || propOffset + 8 + strLen > data.length) continue\n\n const str = data.subarray(propOffset + 8, propOffset + 8 + strLen).toString(\"utf8\").replace(/\\0+$/, \"\").trim()\n if (!str) continue\n\n if (propId === 2) metadata.title = str\n else if (propId === 4) metadata.author = str\n else if (propId === 6) metadata.description = str\n }\n } catch {\n // best-effort — 실패 시 조용히 무시\n }\n}\n\n/** 메타데이터만 추출 (전체 파싱 없이) — MCP parse_metadata용 */\nexport function extractHwp5MetadataOnly(buffer: Buffer): DocumentMetadata {\n const cfb = CFB.parse(buffer)\n const headerEntry = CFB.find(cfb, \"/FileHeader\")\n if (!headerEntry?.content) throw new KordocError(\"FileHeader 스트림 없음\")\n const header = parseFileHeader(Buffer.from(headerEntry.content))\n if (header.signature !== \"HWP Document File\") throw new KordocError(\"HWP 시그니처 불일치\")\n\n const metadata: DocumentMetadata = {\n version: `${header.versionMajor}.x`,\n }\n extractHwp5Metadata(cfb, metadata)\n\n const sections = findSections(cfb)\n metadata.pageCount = sections.length\n\n return metadata\n}\n\n/** 배포용 문서: ViewText/Section{N} 스트림을 복호화하여 반환 */\nfunction findViewTextSections(cfb: CfbContainer, compressed: boolean): Buffer[] {\n const sections: Array<{ idx: number; content: Buffer }> = []\n\n for (let i = 0; i < MAX_SECTIONS; i++) {\n const entry = CFB.find(cfb, `/ViewText/Section${i}`)\n if (!entry?.content) break\n try {\n const decrypted = decryptViewText(Buffer.from(entry.content), compressed)\n sections.push({ idx: i, content: decrypted })\n } catch {\n // 복호화 실패 시 해당 섹션 스킵\n break\n }\n }\n\n return sections.sort((a, b) => a.idx - b.idx).map(s => s.content)\n}\n\nfunction findSections(cfb: CfbContainer): Buffer[] {\n const sections: Array<{ idx: number; content: Buffer }> = []\n\n for (let i = 0; i < MAX_SECTIONS; i++) {\n const entry = CFB.find(cfb, `/BodyText/Section${i}`)\n if (!entry?.content) break\n sections.push({ idx: i, content: Buffer.from(entry.content) })\n }\n\n if (sections.length === 0 && cfb.FileIndex) {\n for (const entry of cfb.FileIndex) {\n if (sections.length >= MAX_SECTIONS) break\n if (entry.name?.startsWith(\"Section\") && entry.content) {\n const idx = parseInt(entry.name.replace(\"Section\", \"\"), 10) || 0\n sections.push({ idx, content: Buffer.from(entry.content) })\n }\n }\n }\n\n return sections.sort((a, b) => a.idx - b.idx).map(s => s.content)\n}\n\n/** Lenient CFB: BodyText/Section{N} 탐색 */\nfunction findSectionsLenient(lcfb: LenientCfbContainer, compressed: boolean): Buffer[] {\n const sections: Array<{ idx: number; content: Buffer }> = []\n for (let i = 0; i < MAX_SECTIONS; i++) {\n const raw = lcfb.findStream(`/BodyText/Section${i}`) ?? lcfb.findStream(`Section${i}`)\n if (!raw) break\n sections.push({ idx: i, content: compressed ? decompressStream(raw) : raw })\n }\n if (sections.length === 0) {\n // fallback: 이름에 \"Section\" 포함된 스트림\n for (const e of lcfb.entries()) {\n if (sections.length >= MAX_SECTIONS) break\n if (e.name.startsWith(\"Section\")) {\n const idx = parseInt(e.name.replace(\"Section\", \"\"), 10) || 0\n const raw = lcfb.findStream(e.name)\n if (raw) sections.push({ idx, content: compressed ? decompressStream(raw) : raw })\n }\n }\n }\n return sections.sort((a, b) => a.idx - b.idx).map(s => s.content)\n}\n\n/** Lenient CFB: ViewText/Section{N} 복호화 */\nfunction findViewTextSectionsLenient(lcfb: LenientCfbContainer, compressed: boolean): Buffer[] {\n const sections: Array<{ idx: number; content: Buffer }> = []\n for (let i = 0; i < MAX_SECTIONS; i++) {\n const raw = lcfb.findStream(`/ViewText/Section${i}`) ?? lcfb.findStream(`Section${i}`)\n if (!raw) break\n try {\n sections.push({ idx: i, content: decryptViewText(raw, compressed) })\n } catch { break }\n }\n return sections.sort((a, b) => a.idx - b.idx).map(s => s.content)\n}\n\n// ─── BinData ���미지 추출 ─────��─────────────────��────\n\n/** SHAPE_COMPONENT 태그 — HWP5 스펙 */\nconst TAG_SHAPE_COMPONENT = 0x004a\n\n/** gso 제어 뒤의 하위 레코드에서 binDataId 추출 (best-effort) */\nfunction extractBinDataId(records: HwpRecord[], ctrlIdx: number): number {\n const ctrlLevel = records[ctrlIdx].level\n // CTRL_HEADER 이후의 하위 레코드들을 순회\n for (let j = ctrlIdx + 1; j < records.length && j < ctrlIdx + 50; j++) {\n const r = records[j]\n if (r.level <= ctrlLevel) break // 같은/상위 레벨이면 이 제어 블록 끝\n // SHAPE_COMPONENT에서 picture 타입이면 binDataId 추출\n // picture 데이터는 SHAPE_COMPONENT 뒤에 오는 하위 레코드에 있음\n // HWP5에서 그림 정보는 level이 높은 하위 레코드에 binDataId가 uint16LE로 저장\n if (r.data.length >= 2) {\n // 매직바이트로 이미지인지 확인하는 대신, SHAPE_COMPONENT 뒤의 하위 레코드에서 binDataId를 읽음\n // HWP5 picture 구조: CTRL_HEADER(gso) → LIST_HEADER → SHAPE_COMPONENT → [picture data record]\n // picture data record에서 offset 0부터 uint16LE = binDataId\n if (r.tagId > TAG_SHAPE_COMPONENT && r.level > ctrlLevel + 1 && r.data.length >= 4) {\n const possibleId = r.data.readUInt16LE(0)\n if (possibleId < 10000) return possibleId // 합리적 범위\n }\n }\n }\n return -1\n}\n\n/** MIME 타입 매직바이트 판별 */\nfunction detectImageMime(data: Buffer | Uint8Array): string | null {\n if (data.length < 4) return null\n if (data[0] === 0x89 && data[1] === 0x50 && data[2] === 0x4e && data[3] === 0x47) return \"image/png\"\n if (data[0] === 0xff && data[1] === 0xd8 && data[2] === 0xff) return \"image/jpeg\"\n if (data[0] === 0x47 && data[1] === 0x49 && data[2] === 0x46) return \"image/gif\"\n if (data[0] === 0x42 && data[1] === 0x4d) return \"image/bmp\"\n if (data[0] === 0xd7 && data[1] === 0xcd && data[2] === 0xc6 && data[3] === 0x9a) return \"image/wmf\"\n if (data[0] === 0x01 && data[1] === 0x00 && data[2] === 0x00 && data[3] === 0x00) return \"image/emf\"\n return null\n}\n\n/** OLE2 BinData 스토리지에서 이미지 추출, blocks의 image 블록과 매핑 */\nfunction extractHwp5Images(\n cfb: CfbContainer,\n blocks: IRBlock[],\n compressed: boolean,\n warnings: ParseWarning[],\n): ExtractedImage[] {\n // BinData 스토리지의 모든 파일을 FileIndex 순회로 수집 (O(n), 기존 O(20000) CFB.find 제거)\n const binDataMap = new Map<number, { data: Buffer; name: string }>()\n const binDataRe = /\\/BinData\\/[Bb][Ii][Nn](\\d{4})$/\n if (cfb.FileIndex) {\n for (const entry of cfb.FileIndex) {\n if (!entry?.name || !entry.content) continue\n const match = entry.name.match(binDataRe)\n if (!match) continue\n const idx = parseInt(match[1], 10)\n let data = Buffer.from(entry.content)\n if (compressed) {\n try { data = decompressStream(data) } catch { /* 이미 비압축일 수 있음 */ }\n }\n binDataMap.set(idx, { data, name: entry.name })\n }\n }\n\n if (binDataMap.size === 0) return []\n\n const images: ExtractedImage[] = []\n let imageIndex = 0\n\n for (const block of blocks) {\n if (block.type !== \"image\" || !block.text) continue\n const binId = parseInt(block.text, 10)\n if (isNaN(binId)) continue\n\n const bin = binDataMap.get(binId)\n if (!bin) {\n warnings.push({ page: block.pageNumber, message: `BinData ${binId} 없음`, code: \"SKIPPED_IMAGE\" })\n block.type = \"paragraph\"\n block.text = `[이미지: BinData ${binId}]`\n continue\n }\n\n const mime = detectImageMime(bin.data)\n if (!mime) {\n warnings.push({ page: block.pageNumber, message: `BinData ${binId}: 알 수 없는 이미지 형식`, code: \"SKIPPED_IMAGE\" })\n block.type = \"paragraph\"\n block.text = `[이미지: ${bin.name}]`\n continue\n }\n\n imageIndex++\n const ext = mime.includes(\"jpeg\") ? \"jpg\" : mime.includes(\"png\") ? \"png\" : mime.includes(\"gif\") ? \"gif\" : mime.includes(\"bmp\") ? \"bmp\" : \"bin\"\n const filename = `image_${String(imageIndex).padStart(3, \"0\")}.${ext}`\n\n images.push({ filename, data: new Uint8Array(bin.data), mimeType: mime })\n block.text = filename\n block.imageData = { data: new Uint8Array(bin.data), mimeType: mime, filename: bin.name }\n }\n\n return images\n}\n\n/** Lenient CFB: BinData 이미지 추출 */\nfunction extractHwp5ImagesLenient(\n lcfb: LenientCfbContainer,\n blocks: IRBlock[],\n compressed: boolean,\n warnings: ParseWarning[],\n): ExtractedImage[] {\n // BinData 엔트리 수집\n const binDataMap = new Map<number, { data: Buffer; name: string }>()\n const binRe = /^BIN(\\d{4})/i\n for (const e of lcfb.entries()) {\n const match = e.name.match(binRe)\n if (!match) continue\n const idx = parseInt(match[1], 10)\n let raw = lcfb.findStream(e.name)\n if (!raw) continue\n if (compressed) {\n try { raw = decompressStream(raw) } catch { /* 이미 비압축일 수 있음 */ }\n }\n binDataMap.set(idx, { data: raw, name: e.name })\n }\n if (binDataMap.size === 0) return []\n\n const images: ExtractedImage[] = []\n let imageIndex = 0\n for (const block of blocks) {\n if (block.type !== \"image\" || !block.text) continue\n const binId = parseInt(block.text, 10)\n if (isNaN(binId)) continue\n const bin = binDataMap.get(binId)\n if (!bin) {\n warnings.push({ page: block.pageNumber, message: `BinData ${binId} ���음`, code: \"SKIPPED_IMAGE\" })\n block.type = \"paragraph\"; block.text = `[이미지: BinData ${binId}]`; continue\n }\n const mime = detectImageMime(bin.data)\n if (!mime) {\n warnings.push({ page: block.pageNumber, message: `BinData ${binId}: 알 수 없는 이미지 형식`, code: \"SKIPPED_IMAGE\" })\n block.type = \"paragraph\"; block.text = `[이미지: ${bin.name}]`; continue\n }\n imageIndex++\n const ext = mime.includes(\"jpeg\") ? \"jpg\" : mime.includes(\"png\") ? \"png\" : mime.includes(\"gif\") ? \"gif\" : mime.includes(\"bmp\") ? \"bmp\" : \"bin\"\n const filename = `image_${String(imageIndex).padStart(3, \"0\")}.${ext}`\n images.push({ filename, data: new Uint8Array(bin.data), mimeType: mime })\n block.text = filename\n block.imageData = { data: new Uint8Array(bin.data), mimeType: mime, filename: bin.name }\n }\n return images\n}\n\nfunction parseSection(records: HwpRecord[], docInfo: HwpDocInfo | null, warnings: ParseWarning[], sectionNum: number): IRBlock[] {\n const blocks: IRBlock[] = []\n let i = 0\n\n while (i < records.length) {\n const rec = records[i]\n\n if (rec.tagId === TAG_PARA_HEADER && rec.level === 0) {\n const { paragraph, tables, nextIdx, charShapeIds } = parseParagraphWithTables(records, i)\n if (paragraph) {\n const block: IRBlock = { type: \"paragraph\", text: paragraph, pageNumber: sectionNum }\n // CHAR_SHAPE 기반 스타일 정보 추가\n if (docInfo && charShapeIds.length > 0) {\n const style = resolveCharStyle(charShapeIds, docInfo)\n if (style) block.style = style\n }\n blocks.push(block)\n }\n for (const t of tables) blocks.push({ type: \"table\", table: t, pageNumber: sectionNum })\n i = nextIdx\n continue\n }\n\n if (rec.tagId === TAG_CTRL_HEADER && rec.level <= 1 && rec.data.length >= 4) {\n const ctrlId = rec.data.subarray(0, 4).toString(\"ascii\")\n if (ctrlId === \" lbt\" || ctrlId === \"tbl \") {\n const { table, nextIdx } = parseTableBlock(records, i)\n if (table) blocks.push({ type: \"table\", table, pageNumber: sectionNum })\n i = nextIdx\n continue\n }\n // 그리기 객체(gso) — 이미지 또는 글상자\n if (ctrlId === \"gso \" || ctrlId === \" osg\") {\n const binId = extractBinDataId(records, i)\n if (binId >= 0) {\n blocks.push({ type: \"image\", text: String(binId), pageNumber: sectionNum })\n } else {\n // 이미지가 아니면 글상자(TextBox) 텍스트 추출 시도\n const boxText = extractTextBoxText(records, i)\n if (boxText) {\n blocks.push({ type: \"paragraph\", text: boxText, pageNumber: sectionNum })\n }\n // 텍스트도 없으면 조용히 스킵 (장식용 도형)\n }\n } else if (ctrlId === \" elo\" || ctrlId === \"ole \") {\n warnings.push({ page: sectionNum, message: `스킵된 제어 요소: ${ctrlId.trim()}`, code: \"SKIPPED_IMAGE\" })\n }\n // 각주/미주 — CTRL_HEADER 아래의 텍스트를 추출하여 footnoteText로 연결\n else if (ctrlId === \"fn \" || ctrlId === \" nf \" || ctrlId === \"en \" || ctrlId === \" ne \") {\n const noteText = extractNoteText(records, i)\n if (noteText && blocks.length > 0) {\n // 직전 paragraph 블록에 footnoteText 연결\n const lastBlock = blocks[blocks.length - 1]\n if (lastBlock.type === \"paragraph\") {\n lastBlock.footnoteText = lastBlock.footnoteText\n ? lastBlock.footnoteText + \"; \" + noteText\n : noteText\n }\n }\n }\n // 하이퍼링크 — CTRL_HEADER 데이터에서 URL 추출\n else if (ctrlId === \"%tok\" || ctrlId === \"klnk\") {\n const url = extractHyperlinkUrl(rec.data)\n if (url && blocks.length > 0) {\n const lastBlock = blocks[blocks.length - 1]\n if (lastBlock.type === \"paragraph\" && !lastBlock.href) {\n lastBlock.href = sanitizeHref(url) ?? undefined\n }\n }\n }\n }\n\n i++\n }\n\n return blocks\n}\n\n/** 각주/미주 CTRL_HEADER 아래의 본문 텍스트 추출 */\nfunction extractNoteText(records: HwpRecord[], ctrlIdx: number): string | null {\n const ctrlLevel = records[ctrlIdx].level\n const texts: string[] = []\n\n for (let j = ctrlIdx + 1; j < records.length && j < ctrlIdx + 100; j++) {\n const r = records[j]\n if (r.level <= ctrlLevel) break // 상위 레벨 도달 → 이 컨트롤 블록 끝\n\n if (r.tagId === TAG_PARA_TEXT) {\n const t = extractText(r.data).trim()\n if (t) texts.push(t)\n }\n }\n\n return texts.length > 0 ? texts.join(\" \") : null\n}\n\n/** 글상자(TextBox) 제어 요소 아래의 텍스트 추출 — extractNoteText와 동일 패턴 */\nfunction extractTextBoxText(records: HwpRecord[], ctrlIdx: number): string | null {\n const ctrlLevel = records[ctrlIdx].level\n const texts: string[] = []\n\n for (let j = ctrlIdx + 1; j < records.length && j < ctrlIdx + 200; j++) {\n const r = records[j]\n if (r.level <= ctrlLevel) break\n\n if (r.tagId === TAG_PARA_TEXT) {\n const t = extractText(r.data).trim()\n if (t) texts.push(t)\n }\n }\n\n return texts.length > 0 ? texts.join(\"\\n\") : null\n}\n\n/** 하이퍼링크 CTRL_HEADER에서 URL 추출 (best-effort) */\nfunction extractHyperlinkUrl(data: Buffer): string | null {\n // HWP5 하이퍼링크 CTRL_HEADER 구조:\n // ctrlId(4) + 기타 필드들... + URL 문자열 (UTF-16LE, length-prefixed)\n // 정확한 오프셋은 버전마다 다를 수 있으므로 URL 패턴 스캔으로 폴백\n try {\n // UTF-16LE에서 \"http\" 시그니처 스캔\n const httpSig = Buffer.from(\"http\", \"utf16le\") // \"h\\0t\\0t\\0p\\0\"\n const idx = data.indexOf(httpSig)\n if (idx >= 0) {\n // null terminator(0x0000 0x0000)까지 UTF-16LE로 읽기\n let end = idx\n while (end + 1 < data.length) {\n const ch = data.readUInt16LE(end)\n if (ch === 0) break\n end += 2\n }\n const url = data.subarray(idx, end).toString(\"utf16le\")\n // 기본 URL 검증\n if (/^https?:\\/\\/.+/.test(url) && url.length < 2000) {\n return url\n }\n }\n } catch { /* best-effort */ }\n return null\n}\n\n/** CHAR_SHAPE ID 배열에서 대표 스타일 결정 (최빈값) */\nfunction resolveCharStyle(charShapeIds: number[], docInfo: HwpDocInfo): InlineStyle | undefined {\n if (charShapeIds.length === 0 || docInfo.charShapes.length === 0) return undefined\n\n // 가장 많이 나타나는 charShapeId 사용\n const freq = new Map<number, number>()\n let maxCount = 0, dominantId = charShapeIds[0]\n for (const id of charShapeIds) {\n const count = (freq.get(id) || 0) + 1\n freq.set(id, count)\n if (count > maxCount) { maxCount = count; dominantId = id }\n }\n\n const cs = docInfo.charShapes[dominantId]\n if (!cs) return undefined\n\n const style: InlineStyle = {}\n if (cs.fontSize > 0) style.fontSize = cs.fontSize / 10 // 0.1pt → pt\n if (cs.attrFlags & 0x01) style.italic = true\n if (cs.attrFlags & 0x02) style.bold = true\n\n return (style.fontSize || style.bold || style.italic) ? style : undefined\n}\n\nfunction parseParagraphWithTables(records: HwpRecord[], startIdx: number) {\n const startLevel = records[startIdx].level\n let text = \"\"\n const tables: ReturnType<typeof buildTable>[] = []\n const charShapeIds: number[] = []\n let i = startIdx + 1\n\n while (i < records.length) {\n const rec = records[i]\n if (rec.tagId === TAG_PARA_HEADER && rec.level <= startLevel) break\n\n if (rec.tagId === TAG_PARA_TEXT) {\n text = extractText(rec.data)\n }\n\n // CHAR_SHAPE 레코드 — 문단 내 글자 모양 인덱스 배열\n if (rec.tagId === TAG_CHAR_SHAPE && rec.data.length >= 8) {\n // 구조: [position(u32) + charShapeId(u32)] * N\n for (let offset = 0; offset + 7 < rec.data.length; offset += 8) {\n charShapeIds.push(rec.data.readUInt32LE(offset + 4))\n }\n }\n\n if (rec.tagId === TAG_CTRL_HEADER && rec.data.length >= 4) {\n const ctrlId = rec.data.subarray(0, 4).toString(\"ascii\")\n if (ctrlId === \" lbt\" || ctrlId === \"tbl \") {\n const { table, nextIdx } = parseTableBlock(records, i)\n if (table) tables.push(table)\n i = nextIdx\n continue\n }\n }\n i++\n }\n\n const trimmed = text.trim()\n return { paragraph: trimmed || null, tables, nextIdx: i, charShapeIds }\n}\n\nfunction parseTableBlock(records: HwpRecord[], startIdx: number) {\n const tableLevel = records[startIdx].level\n let i = startIdx + 1\n let rows = 0, cols = 0\n const cells: CellContext[] = []\n\n while (i < records.length) {\n const rec = records[i]\n if (rec.tagId === TAG_PARA_HEADER && rec.level <= tableLevel) break\n if (rec.tagId === TAG_CTRL_HEADER && rec.level <= tableLevel) break\n\n if (rec.tagId === TAG_TABLE && rec.data.length >= 8) {\n rows = Math.min(rec.data.readUInt16LE(4), MAX_ROWS)\n cols = Math.min(rec.data.readUInt16LE(6), MAX_COLS)\n }\n\n if (rec.tagId === TAG_LIST_HEADER) {\n const { cell, nextIdx } = parseCellBlock(records, i, tableLevel)\n if (cell) cells.push(cell)\n i = nextIdx\n continue\n }\n i++\n }\n\n if (rows === 0 || cols === 0 || cells.length === 0) return { table: null, nextIdx: i }\n\n // colAddr/rowAddr가 있으면 arrangeCells가 이미 완성된 그리드를 반환하므로\n // buildTable(2-pass) 없이 직접 IRTable 생성 — 이중 colSpan 확장 방지\n const hasAddr = cells.some(c => c.colAddr !== undefined && c.rowAddr !== undefined)\n if (hasAddr) {\n const cellRows = arrangeCells(rows, cols, cells)\n const irCells = cellRows.map(row => row.map(c => ({\n text: c.text.trim(),\n colSpan: c.colSpan,\n rowSpan: c.rowSpan,\n })))\n return { table: { rows, cols, cells: irCells, hasHeader: rows > 1 }, nextIdx: i }\n }\n\n const cellRows = arrangeCells(rows, cols, cells)\n return { table: buildTable(cellRows), nextIdx: i }\n}\n\nfunction parseCellBlock(records: HwpRecord[], startIdx: number, tableLevel: number) {\n const rec = records[startIdx]\n const cellLevel = rec.level\n const texts: string[] = []\n\n // LIST_HEADER에서 셀 위치 및 병합 정보 추출\n // HWP5 셀 LIST_HEADER 구조:\n // paraCount(u16) + flags(u32) + width(u16) + colAddr(u16) + rowAddr(u16) + colSpan(u16) + rowSpan(u16)\n // offset: 0 2 6 8 10 12 14\n let colSpan = 1\n let rowSpan = 1\n let colAddr: number | undefined\n let rowAddr: number | undefined\n if (rec.data.length >= 16) {\n colAddr = rec.data.readUInt16LE(8)\n rowAddr = rec.data.readUInt16LE(10)\n const cs = rec.data.readUInt16LE(12)\n const rs = rec.data.readUInt16LE(14)\n if (cs > 0) colSpan = Math.min(cs, MAX_COLS)\n if (rs > 0) rowSpan = Math.min(rs, MAX_ROWS)\n }\n\n let i = startIdx + 1\n\n while (i < records.length) {\n const r = records[i]\n if (r.tagId === TAG_LIST_HEADER && r.level <= cellLevel) break\n if (r.level <= tableLevel && (r.tagId === TAG_PARA_HEADER || r.tagId === TAG_CTRL_HEADER)) break\n\n if (r.tagId === TAG_PARA_TEXT) {\n const t = extractText(r.data).trim()\n if (t) texts.push(t)\n }\n i++\n }\n\n return { cell: { text: texts.join(\"\\n\"), colSpan, rowSpan, colAddr, rowAddr } as CellContext, nextIdx: i }\n}\n\nfunction arrangeCells(rows: number, cols: number, cells: CellContext[]): CellContext[][] {\n const grid: (CellContext | null)[][] = Array.from({ length: rows }, () => Array(cols).fill(null))\n\n // colAddr/rowAddr가 있으면 직접 배치 (HWP5 병합 테이블 정확도 향상)\n const hasAddr = cells.some(c => c.colAddr !== undefined && c.rowAddr !== undefined)\n\n if (hasAddr) {\n for (const cell of cells) {\n const r = cell.rowAddr ?? 0\n const c = cell.colAddr ?? 0\n if (r >= rows || c >= cols) continue\n grid[r][c] = cell\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 < rows && c + dc < cols)\n grid[r + dr][c + dc] = { text: \"\", colSpan: 1, rowSpan: 1 }\n }\n }\n }\n } else {\n // fallback: 순차 배치 (colAddr 없는 경우)\n let cellIdx = 0\n for (let r = 0; r < rows && cellIdx < cells.length; r++) {\n for (let c = 0; c < cols && cellIdx < cells.length; c++) {\n if (grid[r][c] !== null) continue\n const cell = cells[cellIdx++]\n grid[r][c] = cell\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 < rows && c + dc < cols)\n grid[r + dr][c + dc] = { text: \"\", colSpan: 1, rowSpan: 1 }\n }\n }\n }\n }\n }\n\n return grid.map(row => row.map(c => c || { text: \"\", colSpan: 1, rowSpan: 1 }))\n}\n","/**\n * PDF 텍스트 추출 (pdfjs-dist static import 기반)\n *\n * polyfill을 먼저 import해야 DOMMatrix/Path2D/pdfjsWorker가 주입됨.\n * ES 모듈 호이스팅 때문에 별도 파일로 분리되어 있음.\n */\n\nimport type { ParseResult, InternalParseResult, IRBlock, IRTable, DocumentMetadata, ParseOptions, BoundingBox, ParseWarning, OutlineItem } from \"../types.js\"\nimport { HEADING_RATIO_H1, HEADING_RATIO_H2, HEADING_RATIO_H3 } from \"../types.js\"\nimport { KordocError } from \"../utils.js\"\nimport { parsePageRange } from \"../page-range.js\"\nimport { blocksToMarkdown } from \"../table/builder.js\"\nimport { extractLines, filterPageBorderLines, buildTableGrids, extractCells, mapTextToCells, cellTextToString, type TextItem, type TableGrid, type ExtractedCell } from \"./line-detector.js\"\nimport { detectClusterTables, type ClusterItem } from \"./cluster-detector.js\"\n// polyfill 먼저 (ES 모듈 호이스팅되므로 별도 파일 필수)\nimport \"./polyfill.js\"\nimport { getDocument, OPS, GlobalWorkerOptions } from \"pdfjs-dist/legacy/build/pdf.mjs\"\n\n// worker 비활성화 (polyfill에서 pdfjsWorker를 이미 주입했으므로)\nGlobalWorkerOptions.workerSrc = \"\"\n\n// ─── 안전 한계값 (구조적 파싱과 무관) ────────────────\nconst MAX_PAGES = 5000\nconst MAX_TOTAL_TEXT = 500 * 1024 * 1024 // 500MB\n/** PDF 로딩 타임아웃 (30초) — 악성/대용량 PDF 무한 대기 방지 */\nconst PDF_LOAD_TIMEOUT_MS = 30_000\n\n/** getDocument + 타임아웃 래퍼 */\nasync function loadPdfWithTimeout(buffer: ArrayBuffer) {\n const loadingTask = getDocument({\n data: new Uint8Array(buffer),\n useSystemFonts: true,\n disableFontFace: true,\n isEvalSupported: false,\n })\n let timer: ReturnType<typeof setTimeout> | undefined\n try {\n return await Promise.race([\n loadingTask.promise,\n new Promise<never>((_, reject) => {\n timer = setTimeout(() => { loadingTask.destroy(); reject(new KordocError(\"PDF 로딩 타임아웃 (30초 초과)\")) }, PDF_LOAD_TIMEOUT_MS)\n }),\n ])\n } finally {\n if (timer !== undefined) clearTimeout(timer)\n }\n}\n\ninterface PdfTextItem {\n str: string\n transform: number[]\n width: number\n height: number\n fontName?: string\n}\n\ninterface NormItem {\n text: string\n x: number\n y: number\n w: number\n h: number\n /** 폰트 높이(≈폰트 크기) — 헤딩 감지용 */\n fontSize: number\n fontName: string\n /** hidden text 여부 (투명/0pt) */\n isHidden: boolean\n}\n\nexport async function parsePdfDocument(buffer: ArrayBuffer, options?: ParseOptions): Promise<InternalParseResult> {\n const doc = await loadPdfWithTimeout(buffer)\n\n try {\n const pageCount = doc.numPages\n if (pageCount === 0) throw new KordocError(\"PDF에 페이지가 없습니다.\")\n\n // 메타데이터 추출 (best-effort)\n const metadata: DocumentMetadata = { pageCount }\n await extractPdfMetadata(doc, metadata)\n\n const blocks: IRBlock[] = []\n const warnings: ParseWarning[] = []\n let totalChars = 0\n let totalTextBytes = 0\n const effectivePageCount = Math.min(pageCount, MAX_PAGES)\n\n // 페이지 범위 필터링\n const pageFilter = options?.pages ? parsePageRange(options.pages, effectivePageCount) : null\n const totalTarget = pageFilter ? pageFilter.size : effectivePageCount\n\n // 전체 문서의 폰트 크기 통계 수집 (헤딩 감지용)\n const allFontSizes: number[] = []\n const pageHeights = new Map<number, number>()\n\n let parsedPages = 0\n for (let i = 1; i <= effectivePageCount; i++) {\n if (pageFilter && !pageFilter.has(i)) continue\n try {\n const page = await doc.getPage(i)\n const tc = await page.getTextContent()\n const viewport = page.getViewport({ scale: 1 })\n pageHeights.set(i, viewport.height)\n const rawItems = tc.items as PdfTextItem[]\n const items = normalizeItems(rawItems)\n\n // hidden text 필터링 + 경고 수집\n const { visible, hiddenCount } = filterHiddenText(items, viewport.width, viewport.height)\n if (hiddenCount > 0) {\n warnings.push({ page: i, message: `${hiddenCount}개 숨겨진 텍스트 요소 필터링됨`, code: \"HIDDEN_TEXT_FILTERED\" })\n }\n\n // 폰트 크기 통계 수집\n for (const item of visible) {\n if (item.fontSize > 0) allFontSizes.push(item.fontSize)\n }\n\n // 선 기반 테이블 감지를 위한 operatorList\n const opList = await page.getOperatorList()\n\n const pageBlocks = extractPageBlocksWithLines(visible, i, opList, viewport.width, viewport.height)\n for (const b of pageBlocks) blocks.push(b)\n\n // 이미지 기반 PDF 감지 + 크기 제한용 문자 수 집계\n for (const b of pageBlocks) {\n const t = b.text || \"\"\n totalChars += t.replace(/\\s/g, \"\").length\n totalTextBytes += t.length * 2\n }\n if (totalTextBytes > MAX_TOTAL_TEXT) throw new KordocError(\"텍스트 추출 크기 초과\")\n parsedPages++\n options?.onProgress?.(parsedPages, totalTarget)\n } catch (pageErr) {\n // 크기 초과는 전체 중단\n if (pageErr instanceof KordocError) throw pageErr\n warnings.push({ page: i, message: `페이지 ${i} 파싱 실패: ${pageErr instanceof Error ? pageErr.message : \"알 수 없는 오류\"}`, code: \"PARTIAL_PARSE\" })\n }\n }\n\n const parsedPageCount = parsedPages || (pageFilter ? pageFilter.size : effectivePageCount)\n if (totalChars / Math.max(parsedPageCount, 1) < 10) {\n // OCR 프로바이더 결정: 사용자 콜백 > ocrMode 지정 > 자동 탐색(CLI)\n let ocrProvider = options?.ocr ?? null\n const ocrMode = options?.ocrMode\n\n if (!ocrProvider && ocrMode && ocrMode !== \"off\") {\n try {\n const { resolveOcrProvider } = await import(\"../ocr/resolve.js\")\n ocrProvider = await resolveOcrProvider(ocrMode, warnings)\n } catch (resolveErr) {\n if (ocrMode !== \"auto\") {\n // 수동 지정 시 실패하면 바로 에러\n throw Object.assign(\n new KordocError(resolveErr instanceof Error ? resolveErr.message : \"OCR 프로바이더 초기화 실패\"),\n { isImageBased: true }\n )\n }\n // auto 모드에서 탐색 실패는 아래 에러 메시지로 처리\n }\n }\n\n if (ocrProvider) {\n try {\n const { ocrPages } = await import(\"../ocr/provider.js\")\n const ocrBlocks = await ocrPages(doc, ocrProvider, pageFilter, effectivePageCount, warnings)\n if (ocrBlocks.length > 0) {\n // blocksToMarkdown()으로 테이블/헤딩 등 구조 반영\n const ocrMarkdown = blocksToMarkdown(ocrBlocks)\n return {\n markdown: ocrMarkdown,\n blocks: ocrBlocks,\n metadata,\n warnings: warnings.length > 0 ? warnings : undefined,\n isImageBased: true,\n }\n }\n } catch {\n // OCR 실패 시 아래 에러로 fall through\n }\n }\n\n if (ocrMode === \"off\") {\n throw Object.assign(new KordocError(`이미지 기반 PDF (${pageCount}페이지, ${totalChars}자)`), { isImageBased: true })\n }\n\n // OCR 도구 없음 또는 전체 실패\n const errMsg = ocrMode\n ? `이미지 기반 PDF — OCR 실패 (${pageCount}페이지, ${totalChars}자)`\n : `이미지 기반 PDF (${pageCount}페이지, ${totalChars}자)`\n throw Object.assign(new KordocError(errMsg), { isImageBased: true })\n }\n\n // 머리글/바닥글 필터링 (기본 ON — 명시적 false일 때만 비활성화)\n if (options?.removeHeaderFooter !== false && parsedPageCount >= 3) {\n const removed = removeHeaderFooterBlocks(blocks, pageHeights, warnings)\n // 필터링된 블록 제거 (뒤에서부터 삭제)\n for (let ri = removed.length - 1; ri >= 0; ri--) {\n blocks.splice(removed[ri], 1)\n }\n }\n\n // 헤딩 감지: 폰트 크기 기반\n const medianFontSize = computeMedianFontSize(allFontSizes)\n if (medianFontSize > 0) {\n detectHeadings(blocks, medianFontSize)\n }\n\n // □/■ 마커 기반 서브헤딩 감지 (ODL 패턴)\n detectMarkerHeadings(blocks)\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 // blocksToMarkdown로 통일 — 헤딩 마크다운 반영 (HWP5/HWPX와 일관성)\n let markdown = cleanPdfText(blocksToMarkdown(blocks))\n\n return { markdown, blocks, metadata, outline: outline.length > 0 ? outline : undefined, warnings: warnings.length > 0 ? warnings : undefined }\n } finally {\n await doc.destroy().catch(() => {})\n }\n}\n\n// ─── PDF 메타데이터 추출 ────────────────────────────\n\nasync function extractPdfMetadata(doc: { getMetadata(): Promise<unknown> }, metadata: DocumentMetadata): Promise<void> {\n try {\n const result = await doc.getMetadata() as { info?: Record<string, unknown> } | null\n if (!result?.info) return\n const info = result.info\n\n if (typeof info.Title === \"string\" && info.Title.trim()) metadata.title = info.Title.trim()\n if (typeof info.Author === \"string\" && info.Author.trim()) metadata.author = info.Author.trim()\n if (typeof info.Creator === \"string\" && info.Creator.trim()) metadata.creator = info.Creator.trim()\n if (typeof info.Subject === \"string\" && info.Subject.trim()) metadata.description = info.Subject.trim()\n if (typeof info.Keywords === \"string\" && info.Keywords.trim()) {\n metadata.keywords = info.Keywords.split(/[,;]/).map((k: string) => k.trim()).filter(Boolean)\n }\n if (typeof info.CreationDate === \"string\") metadata.createdAt = parsePdfDate(info.CreationDate)\n if (typeof info.ModDate === \"string\") metadata.modifiedAt = parsePdfDate(info.ModDate)\n } catch {\n // best-effort\n }\n}\n\n/** PDF 날짜 형식 (D:YYYYMMDDHHmmSS) → ISO 8601 변환 */\nfunction parsePdfDate(dateStr: string): string | undefined {\n const m = dateStr.match(/D:(\\d{4})(\\d{2})?(\\d{2})?(\\d{2})?(\\d{2})?(\\d{2})?/)\n if (!m) return undefined\n const [, year, month = \"01\", day = \"01\", hour = \"00\", min = \"00\", sec = \"00\"] = m\n return `${year}-${month}-${day}T${hour}:${min}:${sec}`\n}\n\n/** 메타데이터만 추출 (전체 파싱 없이) — MCP parse_metadata용 */\nexport async function extractPdfMetadataOnly(buffer: ArrayBuffer): Promise<DocumentMetadata> {\n const doc = await loadPdfWithTimeout(buffer)\n\n try {\n const metadata: DocumentMetadata = { pageCount: doc.numPages }\n await extractPdfMetadata(doc, metadata)\n return metadata\n } finally {\n await doc.destroy().catch(() => {})\n }\n}\n\n// ═══════════════════════════════════════════════════════\n// Hidden text 필터링 (prompt injection 방어)\n// ═══════════════════════════════════════════════════════\n\nfunction filterHiddenText(items: NormItem[], pageWidth: number, pageHeight: number): { visible: NormItem[]; hiddenCount: number } {\n let hiddenCount = 0\n const visible: NormItem[] = []\n\n for (const item of items) {\n // 0pt 폰트 / 너비 0 → 숨겨진 텍스트\n if (item.isHidden) { hiddenCount++; continue }\n // 페이지 범위 밖 (여백 10% 허용)\n const margin = Math.max(pageWidth, pageHeight) * 0.1\n if (item.x < -margin || item.x > pageWidth + margin || item.y < -margin || item.y > pageHeight + margin) {\n hiddenCount++; continue\n }\n visible.push(item)\n }\n\n return { visible, hiddenCount }\n}\n\n// ═══════════════════════════════════════════════════════\n// 헤딩 감지 (폰트 크기 기반)\n// ═══════════════════════════════════════════════════════\n\nfunction computeMedianFontSize(sizes: number[]): number {\n if (sizes.length === 0) return 0\n const sorted = [...sizes].sort((a, b) => a - b)\n const mid = Math.floor(sorted.length / 2)\n return sorted.length % 2 === 0 ? (sorted[mid - 1] + sorted[mid]) / 2 : sorted[mid]\n}\n\n/**\n * 블록의 폰트 크기를 median과 비교하여 헤딩으로 승격.\n * - 150%+ → heading level 1\n * - 130%+ → heading level 2\n * - 115%+ → heading level 3\n * 조건: 짧은 텍스트 (200자 미만), 숫자만으로 구성되지 않음\n */\nfunction detectHeadings(blocks: IRBlock[], medianFontSize: number): void {\n for (const block of blocks) {\n if (block.type !== \"paragraph\" || !block.text || !block.style?.fontSize) continue\n const text = block.text.trim()\n if (text.length === 0 || text.length > 200) continue\n // 숫자만이면 헤딩 아님\n if (/^\\d+$/.test(text)) continue\n\n const ratio = block.style.fontSize / medianFontSize\n let level = 0\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 if (level > 0) {\n block.type = \"heading\"\n block.level = level\n // PDF 균등배분 스페이스 제거 (\"기 본 현 황\" → \"기본현황\")\n // 한글 글자 사이에 단독 공백이 반복되면 균등배분으로 판단\n block.text = collapseEvenSpacing(text)\n }\n }\n}\n\n/** 한글 균등배분 레이아웃의 글자 간 공백 제거 (\"기 본 현 황\" → \"기본현황\") */\nfunction collapseEvenSpacing(text: string): string {\n const tokens = text.split(\" \")\n // 토큰의 70% 이상이 1글자(한글/숫자/기호)면 균등배분으로 판단\n const singleCharCount = tokens.filter(t => t.length === 1).length\n if (tokens.length >= 3 && singleCharCount / tokens.length >= 0.7) {\n return tokens.join(\"\")\n }\n return text\n}\n\n/**\n * 의사 테이블 감지: 실제 데이터 테이블이 아닌 텍스트가 우연히 테이블로 감지된 경우.\n */\nfunction shouldDemoteTable(table: IRTable): boolean {\n const allCells = table.cells.flatMap(row => row.map(c => c.text.trim())).filter(Boolean)\n const allText = allCells.join(\" \")\n if (allText.length > 200) return false\n // □, ○, ■ 마커 포함 + 3행 이하 → 텍스트성\n if (/[□■◆○●▶]/.test(allText) && table.rows <= 3) return true\n // 빈 셀이 과반 → 의사 테이블 (텍스트가 우연히 선으로 둘러싸인 경우)\n const totalCells = table.rows * table.cols\n const emptyCells = totalCells - allCells.length\n if (table.rows <= 2 && emptyCells > totalCells * 0.5) return true\n // 1행 + 숫자 데이터 없음 → 의사 테이블\n if (table.rows === 1 && !/\\d{2,}/.test(allText)) return true\n return false\n}\n\n/** demote된 테이블을 구조화된 텍스트로 변환 (2열 → \"key: value\", 그 외 → 줄바꿈) */\nfunction demoteTableToText(table: IRTable): string {\n const lines: string[] = []\n for (let r = 0; r < table.rows; r++) {\n const cells = table.cells[r].map(c => c.text.trim()).filter(Boolean)\n if (cells.length === 0) continue\n if (table.cols === 2 && cells.length === 2) {\n // 2열 테이블 → KV 형식 보존\n lines.push(`${cells[0]} : ${cells[1]}`)\n } else {\n lines.push(cells.join(\" \"))\n }\n }\n return lines.join(\"\\n\")\n}\n\n/** □/■ 마커 및 짧은 섹션명을 서브헤딩으로 변환 */\nfunction detectMarkerHeadings(blocks: IRBlock[]): void {\n for (let i = 0; i < blocks.length; i++) {\n const block = blocks[i]\n if (block.type !== \"paragraph\" || !block.text) continue\n const text = block.text.trim()\n // □/■ + 한글로 시작하는 짧은 텍스트 (50자 미만)\n if (text.length < 50 && /^[□■◆◇▶]\\s*[가-힣]/.test(text)) {\n block.type = \"heading\"\n block.level = 4\n continue\n }\n // 순수 한글 2-6자 + 앞뒤가 표/헤딩/빈블록 → 섹션 제목으로 추정\n // (예: \"사업설명\", \"사업효과\", \"추진경위\")\n if (/^[가-힣]{2,6}$/.test(text) && block.style?.fontSize) {\n const prev = blocks[i - 1]\n const next = blocks[i + 1]\n const prevIsStructural = !prev || prev.type === \"table\" || prev.type === \"heading\" || prev.type === \"separator\"\n const nextIsStructural = !next || next.type === \"table\" || next.type === \"heading\" || (next.type === \"paragraph\" && next.text && /^[□■◆○●]/.test(next.text.trim()))\n if (prevIsStructural || nextIsStructural) {\n block.type = \"heading\"\n block.level = 3\n }\n }\n }\n}\n\n// ═══════════════════════════════════════════════════════\n// XY-Cut 읽기 순서 알고리즘\n// ═══════════════════════════════════════════════════════\n\ninterface TextRegion {\n items: NormItem[]\n minX: number; minY: number; maxX: number; maxY: number\n}\n\n/**\n * XY-Cut: 페이지를 재귀적으로 X/Y축 공백으로 분할하여 읽기 순서 결정.\n * - Y축 분할 (수평 공백 감지) → 위에서 아래\n * - X축 분할 (수직 공백 감지) → 왼쪽에서 오른쪽\n * - 분할 불가능하면 리프 노드 (하나의 텍스트 블록)\n */\n/** 재귀 깊이 제한 — 수천 아이템의 pathological 레이아웃에서 스택 오버플로 방지 */\nconst MAX_XYCUT_DEPTH = 50\n\nfunction xyCutOrder(items: NormItem[], gapThreshold: number, depth = 0): NormItem[][] {\n if (items.length === 0) return []\n if (items.length <= 2 || depth >= MAX_XYCUT_DEPTH) return [items]\n\n const region = computeRegion(items)\n\n // Y축 분할 시도 (수평 공백 감지)\n const ySplit = findYSplit(items, region, gapThreshold)\n if (ySplit !== null) {\n const upper = items.filter(i => i.y > ySplit)\n const lower = items.filter(i => i.y <= ySplit)\n // 빈 파티션 방어 — 한쪽이 비면 분할 의미 없음\n if (upper.length > 0 && lower.length > 0 && upper.length < items.length) {\n return [...xyCutOrder(upper, gapThreshold, depth + 1), ...xyCutOrder(lower, gapThreshold, depth + 1)]\n }\n }\n\n // X축 분할 시도 (수직 공백 감지)\n const xSplit = findXSplit(items, region, gapThreshold)\n if (xSplit !== null) {\n const left = items.filter(i => i.x + i.w / 2 < xSplit)\n const right = items.filter(i => i.x + i.w / 2 >= xSplit)\n if (left.length > 0 && right.length > 0 && left.length < items.length) {\n return [...xyCutOrder(left, gapThreshold, depth + 1), ...xyCutOrder(right, gapThreshold, depth + 1)]\n }\n }\n\n // 분할 불가 → 리프 노드\n return [items]\n}\n\nfunction computeRegion(items: NormItem[]): TextRegion {\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity\n for (const i of items) {\n if (i.x < minX) minX = i.x\n if (i.y < minY) minY = i.y\n if (i.x + i.w > maxX) maxX = i.x + i.w\n if (i.y + i.h > maxY) maxY = i.y + i.h\n }\n return { items, minX, minY, maxX, maxY }\n}\n\n/** Y축 분할점 찾기 — 수평 공백 밴드 중 가장 넓은 갭 */\nfunction findYSplit(items: NormItem[], _region: TextRegion, gapThreshold: number): number | null {\n // 아이템을 Y좌표로 정렬 (내림차순 — 위에서 아래)\n const sorted = [...items].sort((a, b) => b.y - a.y)\n let bestGap = gapThreshold\n let bestSplit: number | null = null\n\n for (let i = 1; i < sorted.length; i++) {\n const prevBottom = sorted[i - 1].y - sorted[i - 1].h\n const currTop = sorted[i].y\n const gap = prevBottom - currTop\n if (gap > bestGap) {\n bestGap = gap\n bestSplit = (prevBottom + currTop) / 2\n }\n }\n return bestSplit\n}\n\n/** X축 분할점 찾기 — 수직 공백 밴드 중 가장 넓은 갭 */\nfunction findXSplit(items: NormItem[], _region: TextRegion, gapThreshold: number): number | null {\n const sorted = [...items].sort((a, b) => a.x - b.x)\n let bestGap = gapThreshold\n let bestSplit: number | null = null\n\n for (let i = 1; i < sorted.length; i++) {\n const prevRight = sorted[i - 1].x + sorted[i - 1].w\n const currLeft = sorted[i].x\n const gap = currLeft - prevRight\n if (gap > bestGap) {\n bestGap = gap\n bestSplit = (prevRight + currLeft) / 2\n }\n }\n return bestSplit\n}\n\n// ═══════════════════════════════════════════════════════\n// 페이지 콘텐츠 추출 → IRBlock[] (v2: 바운딩 박스 + 페이지 번호)\n// ═══════════════════════════════════════════════════════\n\n/**\n * 선 기반 테이블 감지를 우선 시도, 실패 시 기존 휴리스틱 fallback.\n */\nfunction extractPageBlocksWithLines(\n items: NormItem[],\n pageNum: number,\n opList: { fnArray: Uint32Array | number[]; argsArray: unknown[][] },\n pageWidth: number,\n pageHeight: number,\n): IRBlock[] {\n if (items.length === 0) return []\n\n // 1단계: PDF 그래픽 명령에서 선 추출\n let { horizontals, verticals } = extractLines(opList.fnArray, opList.argsArray)\n ;({ horizontals, verticals } = filterPageBorderLines(horizontals, verticals, pageWidth, pageHeight))\n\n // 2단계: 선으로 테이블 그리드 구성\n const grids = buildTableGrids(horizontals, verticals)\n\n if (grids.length > 0) {\n return extractBlocksWithGrids(items, pageNum, grids, horizontals, verticals)\n }\n\n // Fallback: 기존 휴리스틱 (선이 없는 PDF)\n return extractPageBlocksFallback(items, pageNum)\n}\n\n/**\n * 선 기반 그리드가 감지된 경우: 테이블 영역의 텍스트는 셀에 매핑,\n * 나머지는 일반 텍스트 블록으로 처리.\n */\nfunction extractBlocksWithGrids(\n items: NormItem[],\n pageNum: number,\n grids: TableGrid[],\n horizontals: import(\"./line-detector.js\").LineSegment[],\n verticals: import(\"./line-detector.js\").LineSegment[],\n): IRBlock[] {\n const blocks: IRBlock[] = []\n const usedItems = new Set<NormItem>()\n\n // 그리드를 Y좌표 내림차순 정렬 (위→아래)\n const sortedGrids = [...grids].sort((a, b) => b.bbox.y2 - a.bbox.y2)\n\n for (const grid of sortedGrids) {\n // 그리드 영역 내 텍스트 아이템 수집\n const tableItems: NormItem[] = []\n const pad = 3\n for (const item of items) {\n if (usedItems.has(item)) continue\n if (item.x >= grid.bbox.x1 - pad && item.x + item.w <= grid.bbox.x2 + pad &&\n item.y >= grid.bbox.y1 - pad && item.y <= grid.bbox.y2 + pad) {\n tableItems.push(item)\n usedItems.add(item)\n }\n }\n\n // 셀 추출\n const cells = extractCells(grid, horizontals, verticals)\n if (cells.length === 0) continue\n\n // 텍스트→셀 매핑\n const textItems: TextItem[] = tableItems.map(i => ({\n text: i.text, x: i.x, y: i.y, w: i.w, h: i.h,\n fontSize: i.fontSize, fontName: i.fontName,\n }))\n const cellTextMap = mapTextToCells(textItems, cells)\n\n // IRTable 구성\n const numRows = grid.rowYs.length - 1\n const numCols = grid.colXs.length - 1\n const irGrid: import(\"../types.js\").IRCell[][] = Array.from(\n { length: numRows },\n () => Array.from({ length: numCols }, () => ({ text: \"\", colSpan: 1, rowSpan: 1 })),\n )\n\n for (const cell of cells) {\n const cellItems = cellTextMap.get(cell) || []\n let text = cellTextToString(cellItems)\n // 셀 안의 페이지 번호 표시 제거 (\"- 2 -\" 등)\n text = text.replace(/^[\\s]*[-–—]\\s*\\d+\\s*[-–—][\\s]*$/gm, \"\").trim()\n irGrid[cell.row][cell.col] = {\n text,\n colSpan: cell.colSpan,\n rowSpan: cell.rowSpan,\n }\n }\n\n const irTable: IRTable = {\n rows: numRows,\n cols: numCols,\n cells: irGrid,\n hasHeader: numRows > 1,\n }\n\n // 빈 테이블(모든 셀이 빈 문자열) 스킵\n const hasContent = irGrid.some(row => row.some(cell => cell.text.trim() !== \"\"))\n if (!hasContent) continue\n\n const tableBbox: BoundingBox = {\n page: pageNum,\n x: grid.bbox.x1, y: grid.bbox.y1,\n width: grid.bbox.x2 - grid.bbox.x1, height: grid.bbox.y2 - grid.bbox.y1,\n }\n\n // 의사 테이블 필터: 텍스트성 내용 → paragraph로 복원 (구조 보존)\n if (shouldDemoteTable(irTable)) {\n const demoted = demoteTableToText(irTable)\n if (demoted) {\n blocks.push({ type: \"paragraph\", text: demoted, pageNumber: pageNum, bbox: tableBbox, style: dominantStyle(tableItems) })\n }\n continue\n }\n\n blocks.push({ type: \"table\", table: irTable, pageNumber: pageNum, bbox: tableBbox })\n }\n\n // 테이블에 속하지 않은 나머지 텍스트 → 일반 블록\n const remaining = items.filter(i => !usedItems.has(i))\n if (remaining.length > 0) {\n // 위→아래 순서로 정렬\n remaining.sort((a, b) => b.y - a.y || a.x - b.x)\n\n // 테이블 전/후 텍스트를 Y좌표 기준으로 적절히 배치\n const textBlocks = detectListBlocks(extractPageBlocksFallback(remaining, pageNum))\n\n // Y좌표 기반으로 테이블과 텍스트를 올바른 순서로 병합\n const allBlocks = [...blocks, ...textBlocks]\n allBlocks.sort((a, b) => {\n const ay = a.bbox ? (a.bbox.y + a.bbox.height) : 0\n const by = b.bbox ? (b.bbox.y + b.bbox.height) : 0\n return by - ay // PDF는 y가 위가 큼 → 내림차순\n })\n return mergeAdjacentTableBlocks(allBlocks)\n }\n\n return mergeAdjacentTableBlocks(blocks)\n}\n\n/** 같은 열 수의 연속 테이블 블록을 하나로 합침 */\nfunction mergeAdjacentTableBlocks(blocks: IRBlock[]): IRBlock[] {\n if (blocks.length <= 1) return blocks\n const result: IRBlock[] = [blocks[0]]\n for (let i = 1; i < blocks.length; i++) {\n const prev = result[result.length - 1]\n const curr = blocks[i]\n if (prev.type === \"table\" && curr.type === \"table\" && prev.table && curr.table &&\n prev.table.cols === curr.table.cols) {\n // 합치기: prev의 cells에 curr의 cells 추가\n const merged: IRTable = {\n rows: prev.table.rows + curr.table.rows,\n cols: prev.table.cols,\n cells: [...prev.table.cells, ...curr.table.cells],\n hasHeader: prev.table.hasHeader,\n }\n result[result.length - 1] = { ...prev, table: merged }\n } else {\n result.push(curr)\n }\n }\n return result\n}\n\n/**\n * 기존 휴리스틱 기반 페이지 블록 추출 (선이 없는 PDF 대비 fallback).\n */\nfunction extractPageBlocksFallback(items: NormItem[], pageNum: number): IRBlock[] {\n if (items.length === 0) return []\n\n const blocks: IRBlock[] = []\n\n // 1단계: 페이지 전체에서 컬럼 감지 (테이블 우선)\n const allYLines = groupByY(items)\n const columns = detectColumns(allYLines)\n\n if (columns && columns.length >= 3) {\n // 테이블 감지됨 → 기존 extractWithColumns 로직 사용 (XY-Cut 스킵)\n const tableText = extractWithColumns(allYLines, columns)\n const bbox = computeBBox(items, pageNum)\n blocks.push({ type: \"paragraph\", text: tableText, pageNumber: pageNum, bbox, style: dominantStyle(items) })\n } else {\n // 2단계: 클러스터 기반 테이블 감지 (2열 이상, 선 없는 PDF)\n const clusterItems: ClusterItem[] = items.map(i => ({\n text: i.text, x: i.x, y: i.y, w: i.w, h: i.h,\n fontSize: i.fontSize, fontName: i.fontName,\n }))\n const clusterResults = detectClusterTables(clusterItems, pageNum)\n\n if (clusterResults.length > 0) {\n // 클러스터 테이블로 소비된 아이템 추적 (Map 기반 O(n) — 기존 indexOf O(n²) 제거)\n const ciToIdx = new Map<ClusterItem, number>()\n for (let ci = 0; ci < clusterItems.length; ci++) ciToIdx.set(clusterItems[ci], ci)\n const usedIndices = new Set<number>()\n for (const cr of clusterResults) {\n for (const ci of cr.usedItems) {\n const idx = ciToIdx.get(ci)\n if (idx !== undefined) usedIndices.add(idx)\n }\n blocks.push({ type: \"table\", table: cr.table, pageNumber: pageNum, bbox: cr.bbox })\n }\n\n // 테이블에 속하지 않은 나머지 텍스트 → 일반 블록\n const remaining = items.filter((_, idx) => !usedIndices.has(idx))\n if (remaining.length > 0) {\n const yLines = groupByY(remaining)\n for (const line of yLines) {\n const text = mergeLineSimple(line)\n if (!text.trim()) continue\n const bbox = computeBBox(line, pageNum)\n blocks.push({ type: \"paragraph\", text, pageNumber: pageNum, bbox, style: dominantStyle(line) })\n }\n }\n\n // Y좌표 기준 정렬\n blocks.sort((a, b) => {\n const ay = a.bbox ? (a.bbox.y + a.bbox.height) : 0\n const by = b.bbox ? (b.bbox.y + b.bbox.height) : 0\n return by - ay\n })\n } else {\n // 3단계: XY-Cut으로 읽기 순서 결정\n const allY = items.map(i => i.y)\n const pageHeight = Math.max(...allY) - Math.min(...allY)\n const gapThreshold = Math.max(15, pageHeight * 0.03)\n\n const orderedGroups = xyCutOrder(items, gapThreshold)\n\n for (const group of orderedGroups) {\n if (group.length === 0) continue\n const yLines = groupByY(group)\n\n // 그룹 내에서도 컬럼 감지 시도 (소형 테이블)\n const groupColumns = detectColumns(yLines)\n if (groupColumns && groupColumns.length >= 3) {\n const tableText = extractWithColumns(yLines, groupColumns)\n const bbox = computeBBox(group, pageNum)\n blocks.push({ type: \"paragraph\", text: tableText, pageNumber: pageNum, bbox, style: dominantStyle(group) })\n } else {\n for (const line of yLines) {\n const text = mergeLineSimple(line)\n if (!text.trim()) continue\n const bbox = computeBBox(line, pageNum)\n blocks.push({ type: \"paragraph\", text, pageNumber: pageNum, bbox, style: dominantStyle(line) })\n }\n }\n }\n }\n }\n\n // 한국어 특수 테이블 감지 (구분/항목/종류 패턴)\n return detectSpecialKoreanTables(blocks)\n}\n\n/** 아이템 그룹에서 바운딩 박스 계산 */\nfunction computeBBox(items: NormItem[], pageNum: number): BoundingBox {\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity\n for (const i of items) {\n if (i.x < minX) minX = i.x\n if (i.y < minY) minY = i.y\n if (i.x + i.w > maxX) maxX = i.x + i.w\n // h가 0인 경우 fontSize를 높이 대용으로 사용 (pdfjs가 height를 제공하지 않는 경우)\n const effectiveH = i.h > 0 ? i.h : i.fontSize\n if (i.y + effectiveH > maxY) maxY = i.y + effectiveH\n }\n return { page: pageNum, x: minX, y: minY, width: maxX - minX, height: maxY - minY }\n}\n\n/** 아이템 그룹의 대표 스타일 (최빈 폰트 크기) */\nfunction dominantStyle(items: NormItem[]): { fontSize: number; fontName: string } | undefined {\n if (items.length === 0) return undefined\n // 최빈 폰트 크기 찾기\n const freq = new Map<number, number>()\n let maxCount = 0, dominantSize = 0\n for (const i of items) {\n if (i.fontSize <= 0) continue\n const count = (freq.get(i.fontSize) || 0) + 1\n freq.set(i.fontSize, count)\n if (count > maxCount) { maxCount = count; dominantSize = i.fontSize }\n }\n if (dominantSize === 0) return undefined\n // 대표 폰트명 (빈 문자열은 undefined로)\n const fontName = items.find(i => i.fontSize === dominantSize)?.fontName || undefined\n return { fontSize: dominantSize, fontName }\n}\n\nfunction normalizeItems(rawItems: PdfTextItem[]): NormItem[] {\n return rawItems\n .filter(i => typeof i.str === \"string\" && i.str.trim() !== \"\")\n .map(i => {\n // transform matrix: [scaleX, skewY, skewX, scaleY, translateX, translateY]\n // 폰트 크기 ≈ scaleY의 절대값 (일반적으로 transform[3])\n const scaleY = Math.abs(i.transform[3])\n const scaleX = Math.abs(i.transform[0])\n const fontSize = Math.round(Math.max(scaleY, scaleX))\n\n return {\n text: i.str.trim(),\n x: Math.round(i.transform[4]),\n y: Math.round(i.transform[5]),\n w: Math.round(i.width),\n h: Math.round(i.height),\n fontSize,\n fontName: i.fontName || \"\",\n // 0pt 폰트이거나 너비 0 → hidden text (prompt injection 의심)\n isHidden: fontSize === 0 || (i.width === 0 && i.str.trim().length > 0),\n }\n })\n .sort((a, b) => b.y - a.y || a.x - b.x)\n}\n\nfunction groupByY(items: NormItem[]): NormItem[][] {\n if (items.length === 0) return []\n const lines: NormItem[][] = []\n let curY = items[0].y\n let curLine: NormItem[] = [items[0]]\n\n for (let i = 1; i < items.length; i++) {\n // Y좌표 허용 오차 3px — PDF 렌더링 미세 오차 보정, 별표 행 경계 감지에 최적화된 값\n if (Math.abs(items[i].y - curY) > 3) {\n lines.push(curLine)\n curLine = []\n curY = items[i].y\n }\n curLine.push(items[i])\n }\n if (curLine.length > 0) lines.push(curLine)\n return lines\n}\n\n// ═══════════════════════════════════════════════════════\n// 열 경계 감지 — 빈도 기반 x-히스토그램 클러스터링\n// ═══════════════════════════════════════════════════════\n\n/** prose 라인 판별: 아이템 간 gap이 모두 작으면 문장 (단어 나열) */\nfunction isProseSpread(items: NormItem[]): boolean {\n if (items.length < 4) return false\n const sorted = [...items].sort((a, b) => a.x - b.x)\n const gaps: number[] = []\n for (let i = 1; i < sorted.length; i++) {\n gaps.push(sorted[i].x - (sorted[i - 1].x + sorted[i - 1].w))\n }\n // gap의 최대값이 작고 평균 단어 길이가 짧으면 prose\n const maxGap = Math.max(...gaps)\n const avgLen = items.reduce((s, i) => s + i.text.length, 0) / items.length\n // 짧은 단어들이 좁은 간격으로 나열 = prose (예: \"위 표 제3호나목에서 남은 유효기간...\")\n return maxGap < 40 && avgLen < 5\n}\n\nfunction detectColumns(yLines: NormItem[][]): number[] | null {\n const allItems = yLines.flat()\n if (allItems.length === 0) return null\n const pageWidth = Math.max(...allItems.map(i => i.x + i.w)) - Math.min(...allItems.map(i => i.x))\n if (pageWidth < 100) return null\n\n // \"비고\" 이전 아이템만 사용 (비고 이후는 prose)\n let bigoLineIdx = -1\n for (let i = 0; i < yLines.length; i++) {\n if (yLines[i].length <= 2 && yLines[i].some(item => item.text === \"비고\")) {\n bigoLineIdx = i\n break\n }\n }\n const tableYLines = bigoLineIdx >= 0 ? yLines.slice(0, bigoLineIdx) : yLines\n\n // Step 1: 모든 아이템의 x를 수집 (prose 라인 제외)\n // CLUSTER_TOL 22px — 한국 공문서 PDF 열 간격에 최적화, 별표 표 열 감지 핵심값\n const CLUSTER_TOL = 22\n const xClusters: { center: number; count: number; minX: number }[] = []\n\n for (const line of tableYLines) {\n if (isProseSpread(line)) continue\n for (const item of line) {\n let found = false\n for (const c of xClusters) {\n if (Math.abs(item.x - c.center) <= CLUSTER_TOL) {\n c.center = Math.round((c.center * c.count + item.x) / (c.count + 1))\n c.minX = Math.min(c.minX, item.x)\n c.count++\n found = true\n break\n }\n }\n if (!found) {\n xClusters.push({ center: item.x, count: 1, minX: item.x })\n }\n }\n }\n\n // Step 2: 빈도 피크 — 최소 3회 이상 등장 (단발성 텍스트 노이즈 제거)\n const peaks = xClusters\n .filter(c => c.count >= 3)\n .sort((a, b) => a.minX - b.minX)\n\n // 최소 3개 열이 있어야 테이블로 판별 — 2열은 일반 2단 레이아웃과 구분 불가\n if (peaks.length < 3) return null\n\n // Step 3: 가까운 피크 병합 — MERGE_TOL 30px (같은 논리 열의 미세 위치 차이 흡수)\n const MERGE_TOL = 30\n const merged: { center: number; count: number; minX: number }[] = [peaks[0]]\n for (let i = 1; i < peaks.length; i++) {\n const prev = merged[merged.length - 1]\n if (peaks[i].minX - prev.minX < MERGE_TOL) {\n // 빈도 높은 쪽 유지, 최소 x는 작은 값\n if (peaks[i].count > prev.count) {\n prev.center = peaks[i].center\n }\n prev.count += peaks[i].count\n prev.minX = Math.min(prev.minX, peaks[i].minX)\n } else {\n merged.push({ ...peaks[i] })\n }\n }\n\n // 열 경계 = 각 클러스터의 minX (왼쪽 정렬 기준), 병합 후 재검증\n const columns = merged.filter(c => c.count >= 3).map(c => c.minX)\n return columns.length >= 3 ? columns : null\n}\n\nfunction findColumn(x: number, columns: number[]): number {\n for (let i = columns.length - 1; i >= 0; i--) {\n // 10px 왼쪽 허용 오차 — 셀 내 텍스트 미세 좌측 이탈 보정\n if (x >= columns[i] - 10) return i\n }\n return 0\n}\n\n// ═══════════════════════════════════════════════════════\n// 열 기반 추출 — 테이블/텍스트 영역 분리\n// ═══════════════════════════════════════════════════════\n\nfunction extractWithColumns(yLines: NormItem[][], columns: number[]): string {\n const result: string[] = []\n const colMin = columns[0]\n const colMax = columns[columns.length - 1]\n\n // \"비고\" 라인 감지 — 이후는 텍스트로 처리\n let bigoIdx = -1\n for (let i = 0; i < yLines.length; i++) {\n if (yLines[i].length <= 2 && yLines[i].some(item => item.text === \"비고\")) {\n bigoIdx = i\n break\n }\n }\n\n // 테이블 시작: 첫 번째 다열(3+ 열 사용) 라인\n let tableStart = -1\n for (let i = 0; i < (bigoIdx >= 0 ? bigoIdx : yLines.length); i++) {\n const usedCols = new Set(yLines[i].map(item => findColumn(item.x, columns)))\n if (usedCols.size >= 3) {\n tableStart = i\n break\n }\n }\n\n const tableEnd = bigoIdx >= 0 ? bigoIdx : yLines.length\n\n // 테이블 시작 이전 = 텍스트\n for (let i = 0; i < (tableStart >= 0 ? tableStart : tableEnd); i++) {\n result.push(mergeLineSimple(yLines[i]))\n }\n\n // 테이블 영역: 모든 라인을 그리드에 포함 (단일 아이템 라인도)\n if (tableStart >= 0) {\n const tableLines = yLines.slice(tableStart, tableEnd)\n // 테이블 x범위 밖의 라인만 텍스트로 분리\n // 좌측 20px, 우측 200px 허용 — 비고/주석 열이 오른쪽에 넓게 위치하는 공문서 특성 반영\n const gridLines: NormItem[][] = []\n for (const line of tableLines) {\n const inRange = line.some(item =>\n item.x >= colMin - 20 && item.x <= colMax + 200\n )\n if (inRange && !isProseSpread(line)) {\n gridLines.push(line)\n } else {\n // 그리드 밖 라인은 현재까지 축적된 그리드 출력 후 텍스트로\n if (gridLines.length > 0) {\n result.push(buildGridTable(gridLines.splice(0), columns))\n }\n result.push(mergeLineSimple(line))\n }\n }\n if (gridLines.length > 0) {\n result.push(buildGridTable(gridLines, columns))\n }\n }\n\n // 비고 영역\n if (bigoIdx >= 0) {\n result.push(\"\")\n for (let i = bigoIdx; i < yLines.length; i++) {\n result.push(mergeLineSimple(yLines[i]))\n }\n }\n\n return result.join(\"\\n\")\n}\n\n// ═══════════════════════════════════════════════════════\n// 그리드 테이블 빌더 — y-라인을 열에 배치 후 행 병합\n// ═══════════════════════════════════════════════════════\n\nfunction buildGridTable(lines: NormItem[][], columns: number[]): string {\n const numCols = columns.length\n\n // Step 1: 각 y-라인을 열에 배치\n const yRows: string[][] = lines.map(items => {\n const row = Array(numCols).fill(\"\")\n for (const item of items) {\n const col = findColumn(item.x, columns)\n row[col] = row[col] ? row[col] + \" \" + item.text : item.text\n }\n return row\n })\n\n // Step 2: 행 병합 — 새 논리적 행 판별\n // 데이터 열 기준점 (가격 등이 들어가는 오른쪽 열들)\n const dataColStart = Math.max(2, Math.floor(numCols / 2))\n const merged: string[][] = []\n\n for (const row of yRows) {\n if (row.every(c => c === \"\")) continue\n\n if (merged.length === 0) {\n merged.push([...row])\n continue\n }\n\n const prev = merged[merged.length - 1]\n const filledCols = row.map((c, i) => c ? i : -1).filter(i => i >= 0)\n const filledCount = filledCols.length\n\n let isNewRow = false\n\n // Rule 1: col 0에 텍스트 (3글자 이상) → 새 행 (단, \"권\"처럼 짧은 건 continuation)\n if (row[0] && row[0].length >= 3) {\n isNewRow = true\n }\n\n // Rule 2: col 1에 텍스트 → 항상 새 행 (새 항목 시작)\n if (!isNewRow && numCols > 1 && row[1]) {\n isNewRow = true\n }\n\n // Rule 3: 데이터 열(3+)에 새 값이 있고 이전 행 데이터 열에도 이미 값 있음 → 새 가격 행\n if (!isNewRow) {\n const hasData = row.slice(dataColStart).some(c => c !== \"\")\n const prevHasData = prev.slice(dataColStart).some(c => c !== \"\")\n if (hasData && prevHasData) {\n isNewRow = true\n }\n }\n\n // Exception: filledCount=1이고 col 0에 짧은 텍스트(≤2자) → word continuation (예: \"권\", \"여권\")\n if (isNewRow && filledCount === 1 && row[0] && row[0].length <= 2) {\n isNewRow = false\n }\n\n if (isNewRow) {\n merged.push([...row])\n } else {\n for (let c = 0; c < numCols; c++) {\n if (row[c]) {\n prev[c] = prev[c] ? prev[c] + \" \" + row[c] : row[c]\n }\n }\n }\n }\n\n if (merged.length < 2) {\n return merged.map(r => r.filter(c => c).join(\" \")).join(\"\\n\")\n }\n\n // Step 3: 헤더 행 병합 — 첫 N행이 모두 데이터열(dataColStart+)에 값이 없으면 헤더\n let headerEnd = 0\n for (let r = 0; r < merged.length; r++) {\n const hasDataValues = merged[r].slice(dataColStart).some(c => c && /\\d/.test(c))\n if (hasDataValues) break\n headerEnd = r + 1\n }\n\n if (headerEnd > 1) {\n // 헤더 행들을 하나로 합침\n const headerRow = Array(numCols).fill(\"\")\n for (let r = 0; r < headerEnd; r++) {\n for (let c = 0; c < numCols; c++) {\n if (merged[r][c]) {\n headerRow[c] = headerRow[c] ? headerRow[c] + \" \" + merged[r][c] : merged[r][c]\n }\n }\n }\n merged.splice(0, headerEnd, headerRow)\n }\n\n // Step 4: 마크다운 테이블\n const md: string[] = []\n md.push(\"| \" + merged[0].join(\" | \") + \" |\")\n md.push(\"| \" + merged[0].map(() => \"---\").join(\" | \") + \" |\")\n for (let r = 1; r < merged.length; r++) {\n md.push(\"| \" + merged[r].join(\" | \") + \" |\")\n }\n return md.join(\"\\n\")\n}\n\n// ═══════════════════════════════════════════════════════\n// 유틸\n// ═══════════════════════════════════════════════════════\n\nfunction mergeLineSimple(items: NormItem[]): string {\n if (items.length <= 1) return items[0]?.text || \"\"\n const sorted = [...items].sort((a, b) => a.x - b.x)\n let result = sorted[0].text\n for (let i = 1; i < sorted.length; i++) {\n const gap = sorted[i].x - (sorted[i - 1].x + sorted[i - 1].w)\n const avgFs = (sorted[i].fontSize + sorted[i - 1].fontSize) / 2\n // 15px+ 갭 = 탭 (열 구분)\n if (gap > 15) result += \"\\t\"\n // 매우 작은 갭 — 모든 문자 타입에서 공백 없이 붙임\n else if (gap < avgFs * 0.15) { /* no space */ }\n // 한글 관련 작은 갭 — PDF 문자 개별 배치 잔재\n else if (gap < avgFs * 0.35 && (/[가-힣]$/.test(result) || /^[가-힣]/.test(sorted[i].text))) { /* no space */ }\n // 3px+ 갭 = 공백 (단어 구분)\n else if (gap > 3) result += \" \"\n result += sorted[i].text\n }\n return result\n}\n\nexport function cleanPdfText(text: string): string {\n return mergeKoreanLines(\n text\n // \"- 2 -\" 스타일 페이지 번호 (독립 라인 및 목록 항목 형태 포함)\n .replace(/^[\\s]*[-–—]\\s*[-–—]?\\d+[-–—]?[\\s]*[-–—]?[\\s]*$/gm, \"\")\n // \"1 / 5\" 스타일 페이지 번호\n .replace(/^\\s*\\d+\\s*\\/\\s*\\d+\\s*$/gm, \"\")\n // 단독 페이지 번호 (줄 끝에 혼자 있는 숫자)\n .replace(/\\n\\d{1,4}\\n/g, \"\\n\")\n // 문서 마지막 단독 페이지 번호\n .replace(/\\n\\d{1,4}$/, \"\")\n )\n // 본문의 균등배분 스페이스 정리 (테이블/구분선 행 제외)\n .replace(/^(?!\\|).{3,30}$/gm, line => collapseEvenSpacing(line))\n .replace(/\\n{3,}/g, \"\\n\\n\")\n .trim()\n}\n\nfunction startsWithMarker(line: string): boolean {\n const t = line.trimStart()\n return /^[가-힣ㄱ-ㅎ][.)]/.test(t) || /^\\d+[.)]/.test(t) || /^\\([가-힣ㄱ-ㅎ\\d]+\\)/.test(t) ||\n /^[○●※▶▷◆◇■□★☆\\-·]\\s/.test(t) || /^제\\d+[조항호장절]/.test(t)\n}\n\nfunction isStandaloneHeader(line: string): boolean {\n return /^제\\d+[조항호장절](\\([^)]*\\))?(\\s+\\S+){0,7}$/.test(line.trim())\n}\n\n// ═══════════════════════════════════════════════════════\n// 리스트 감지 — paragraph 블록 중 번호 패턴을 list 블록으로 변환\n// ═══════════════════════════════════════════════════════\n\n/**\n * 연속된 paragraph 블록에서 번호 리스트 패턴을 감지하여 list 블록으로 변환.\n * \"비고\" 헤더 뒤에 오는 \"1.\", \"2.\" 패턴이 대표적.\n */\nfunction detectListBlocks(blocks: IRBlock[]): IRBlock[] {\n const result: IRBlock[] = []\n\n for (let i = 0; i < blocks.length; i++) {\n const block = blocks[i]\n\n if (block.type === \"paragraph\" && block.text) {\n const text = block.text.trim()\n // 번호 리스트: \"1.\", \"2.\" 등\n if (/^\\d+\\.\\s/.test(text)) {\n result.push({ ...block, type: \"list\", listType: \"ordered\", text: block.text })\n continue\n }\n // 비번호 리스트: ○, -, ·, ※, ▶ 등\n if (/^[○●·※▶▷◆◇\\-]\\s/.test(text)) {\n result.push({ ...block, type: \"list\", listType: \"unordered\", text: block.text })\n continue\n }\n }\n\n result.push(block)\n }\n\n return result\n}\n\n// ═══════════════════════════════════════════════════════\n// 한국어 특수 테이블 감지 — \"구분/항목/종류\" 패턴 기반 key-value 테이블\n// ═══════════════════════════════════════════════════════\n\n/**\n * ODL SpecialTableProcessor 포팅: 연속된 \"구분:\", \"항목:\", \"종류:\" 등\n * 한국어 key-value 패턴을 2열 테이블로 변환.\n *\n * 동작:\n * 1) paragraph 블록의 텍스트에서 한국어 key-value 패턴 감지\n * 2) \":\"가 있으면 key | value 2열, 없으면 colSpan=2 (전체 행)\n * 3) 연속된 패턴을 하나의 테이블로 그룹화\n */\nconst KOREAN_TABLE_HEADER_RE = /^\\(?(구분|항목|종류|분류|유형|대상|내용|기간|금액|비율|방법|절차|요건|조건|근거|목적|범위|기준)\\)?[:\\s]/\n\n/** KV 오탐 패턴: 시간(14:30), URL(://), 숫자:숫자(3:2) */\nconst KV_FALSE_POSITIVE_RE = /\\d{1,2}:\\d{2}|:\\/\\/|\\d+:\\d+/\n\nfunction detectSpecialKoreanTables(blocks: IRBlock[]): IRBlock[] {\n const result: IRBlock[] = []\n let kvLines: { key: string; value: string; block: IRBlock }[] = []\n\n const flushKvTable = () => {\n if (kvLines.length < 2) {\n // 2행 미만이면 테이블로 만들 가치 없음 → 원래 블록 복원\n for (const kv of kvLines) result.push(kv.block)\n kvLines = []\n return\n }\n\n // 2열 테이블 생성\n const cells: import(\"../types.js\").IRCell[][] = kvLines.map(kv => {\n if (kv.value) {\n return [\n { text: kv.key, colSpan: 1, rowSpan: 1 },\n { text: kv.value, colSpan: 1, rowSpan: 1 },\n ]\n }\n // \":\" 없는 줄 → 전체 행 (colSpan=2)\n return [\n { text: kv.key, colSpan: 2, rowSpan: 1 },\n { text: \"\", colSpan: 1, rowSpan: 1 },\n ]\n })\n\n const irTable: IRTable = {\n rows: cells.length,\n cols: 2,\n cells,\n hasHeader: true,\n }\n\n // 첫 블록의 위치 정보 사용\n const firstBlock = kvLines[0].block\n result.push({\n type: \"table\",\n table: irTable,\n pageNumber: firstBlock.pageNumber,\n bbox: firstBlock.bbox,\n })\n kvLines = []\n }\n\n for (const block of blocks) {\n if (block.type !== \"paragraph\" || !block.text) {\n flushKvTable()\n result.push(block)\n continue\n }\n\n const text = block.text.trim()\n\n // \"구분: xxx\" 또는 \"항목: xxx\" 패턴 매칭\n if (KOREAN_TABLE_HEADER_RE.test(text)) {\n const colonIdx = text.indexOf(\":\")\n if (colonIdx >= 0) {\n kvLines.push({\n key: text.slice(0, colonIdx).trim(),\n value: text.slice(colonIdx + 1).trim(),\n block,\n })\n } else {\n // \":\" 없이 공백으로 구분된 경우: \"구분 xxx\"\n const spaceIdx = text.search(/\\s/)\n if (spaceIdx > 0) {\n kvLines.push({\n key: text.slice(0, spaceIdx).trim(),\n value: text.slice(spaceIdx + 1).trim(),\n block,\n })\n } else {\n kvLines.push({ key: text, value: \"\", block })\n }\n }\n continue\n }\n\n // key-value 패턴이 아닌 블록이 나오면 축적된 것을 flush\n // 단, 이미 수집 중이고 현재 블록이 \"label: value\" 형태면 계속 수집\n if (kvLines.length > 0 && text.includes(\":\")) {\n // 오탐 제외: 시간(14:30), URL(http://), 숫자:숫자(3:2), 괄호 포함\n if (!KV_FALSE_POSITIVE_RE.test(text) && !text.includes(\"(\") && !text.includes(\")\")) {\n const colonIdx = text.indexOf(\":\")\n const key = text.slice(0, colonIdx).trim()\n // key가 순수 한글 2~8자 (공백/괄호 없음)면 유효한 key-value 라인\n if (/^[가-힣]+$/.test(key) && key.length >= 2 && key.length <= 8) {\n kvLines.push({\n key,\n value: text.slice(colonIdx + 1).trim(),\n block,\n })\n continue\n }\n }\n }\n\n flushKvTable()\n result.push(block)\n }\n\n flushKvTable()\n return result\n}\n\n// ─── 머리글/바닥글 감지 ────────────────────────────\n\n/** 상단/하단 10% 영역에서 페이지간 반복 텍스트를 감지하여 제거 대상 인덱스 반환 */\nfunction removeHeaderFooterBlocks(\n blocks: IRBlock[],\n pageHeights: Map<number, number>,\n warnings: ParseWarning[],\n): number[] {\n const ZONE_RATIO = 0.1 // 상하 10%\n const MIN_REPEAT = 3 // 최소 3페이지에서 반복\n\n // 페이지별 상단/하단 텍스트 수집\n const headerTexts = new Map<number, string[]>() // page → texts\n const footerTexts = new Map<number, string[]>()\n\n for (let bi = 0; bi < blocks.length; bi++) {\n const b = blocks[bi]\n if (!b.bbox || !b.pageNumber || !b.text?.trim()) continue\n const ph = pageHeights.get(b.bbox.page) || pageHeights.get(b.pageNumber)\n if (!ph) continue\n\n const blockTop = ph - (b.bbox.y + b.bbox.height) // PDF Y좌표는 아래가 0\n const blockBottom = ph - b.bbox.y\n\n if (blockBottom <= ph * ZONE_RATIO) {\n // 하단 영역\n const arr = footerTexts.get(b.pageNumber) || []\n arr.push(b.text.trim())\n footerTexts.set(b.pageNumber, arr)\n } else if (blockTop >= ph * (1 - ZONE_RATIO)) {\n // 상단 영역\n const arr = headerTexts.get(b.pageNumber) || []\n arr.push(b.text.trim())\n headerTexts.set(b.pageNumber, arr)\n }\n }\n\n // 반복 패턴 찾기: 페이지 번호 변동 허용 (숫자만 다른 경우)\n const repeatedPatterns = new Set<string>()\n for (const textsMap of [headerTexts, footerTexts]) {\n const patternCount = new Map<string, number>()\n for (const [, texts] of textsMap) {\n for (const t of texts) {\n // 숫자를 와일드카드로 치환하여 \"- 1 -\", \"- 2 -\" 같은 패턴 통합\n const normalized = t.replace(/\\d+/g, \"#\")\n patternCount.set(normalized, (patternCount.get(normalized) || 0) + 1)\n }\n }\n for (const [pattern, count] of patternCount) {\n if (count >= MIN_REPEAT) repeatedPatterns.add(pattern)\n }\n }\n\n if (repeatedPatterns.size === 0) return []\n\n // 반복 패턴에 매칭되는 블록 인덱스 수집\n const removeIndices: number[] = []\n for (let bi = 0; bi < blocks.length; bi++) {\n const b = blocks[bi]\n if (!b.bbox || !b.pageNumber || !b.text?.trim()) continue\n const ph = pageHeights.get(b.bbox.page) || pageHeights.get(b.pageNumber)\n if (!ph) continue\n\n const blockTop = ph - (b.bbox.y + b.bbox.height)\n const blockBottom = ph - b.bbox.y\n const inZone = blockBottom <= ph * ZONE_RATIO || blockTop >= ph * (1 - ZONE_RATIO)\n if (!inZone) continue\n\n const normalized = b.text.trim().replace(/\\d+/g, \"#\")\n if (repeatedPatterns.has(normalized)) {\n removeIndices.push(bi)\n }\n }\n\n if (removeIndices.length > 0) {\n warnings.push({ message: `${removeIndices.length}개 머리글/바닥글 요소 제거됨`, code: \"HIDDEN_TEXT_FILTERED\" })\n }\n\n return removeIndices\n}\n\nfunction mergeKoreanLines(text: string): string {\n if (!text) return \"\"\n const lines = text.split(\"\\n\")\n if (lines.length <= 1) return text\n const result: string[] = [lines[0]]\n\n for (let i = 1; i < lines.length; i++) {\n const prev = result[result.length - 1]\n const curr = lines[i]\n const currTrimmed = curr.trim()\n // 마크다운 헤딩/테이블/구분선은 병합하지 않음\n if (/^#{1,6}\\s/.test(prev) || /^#{1,6}\\s/.test(curr) || /^\\|/.test(currTrimmed) || /^---/.test(currTrimmed)) {\n result.push(curr)\n continue\n }\n // 쉼표로 끝나는 줄 + 다음 줄 = 연속 문장\n if (/,$/.test(prev.trim()) && currTrimmed.length > 0) {\n result[result.length - 1] = prev + \"\\n\" + curr\n continue\n }\n // (※ 로 시작하는 줄 = 이전 줄의 부연설명\n if (/^\\(※/.test(currTrimmed)) {\n result[result.length - 1] = prev + \" \" + currTrimmed\n continue\n }\n // 기존 한글 줄바꿈 병합\n if (/[가-힣·,\\-]$/.test(prev) && /^[가-힣(]/.test(curr) && !startsWithMarker(curr) && !isStandaloneHeader(prev)) {\n result[result.length - 1] = prev + \" \" + curr\n } else {\n result.push(curr)\n }\n }\n return result.join(\"\\n\")\n}\n","/**\n * PDF 그래픽 명령에서 수평/수직 선을 추출하고,\n * 선 교차점 기반으로 테이블 그리드를 구성하는 모듈.\n *\n * 이 파일의 테이블 감지 알고리즘은 OpenDataLoader PDF의\n * TableBorderBuilder를 참고하여 TypeScript로 재구현한 것입니다.\n *\n * Original work: Copyright 2025-2026 Hancom, Inc.\n * Licensed under the Apache License, Version 2.0\n * https://github.com/opendataloader-project/opendataloader-pdf\n *\n * Modifications: TypeScript 포팅, pdfjs-dist v4/v5 호환,\n * 한국어 PDF 특화 최적화 (문자 간격, 셀 텍스트 병합)\n */\n\nimport { OPS } from \"pdfjs-dist/legacy/build/pdf.mjs\"\n\n// ─── pdfjs-dist v5 DrawOPS (v5에서 constructPath 형식 변경) ──\n// v4: args = [subOps: number[], coords: number[], minMax]\n// subOps uses OPS.moveTo(13), OPS.lineTo(14), OPS.rectangle(19)\n// v5: args = [afterOp: number, [pathData: object], minMax]\n// pathData is flat array using DrawOPS: moveTo=0, lineTo=1, curveTo=2, closePath=4\nconst enum DrawOPS {\n moveTo = 0,\n lineTo = 1,\n curveTo = 2,\n quadraticCurveTo = 3,\n closePath = 4,\n}\n\n// ─── 타입 ─────────────────────────────────────────────\n\nexport interface LineSegment {\n x1: number; y1: number\n x2: number; y2: number\n lineWidth: number\n}\n\nexport interface TableGrid {\n /** 행 Y 좌표 경계 (위→아래 내림차순) */\n rowYs: number[]\n /** 열 X 좌표 경계 (좌→우 오름차순) */\n colXs: number[]\n /** 테이블 바운딩 박스 */\n bbox: { x1: number; y1: number; x2: number; y2: number }\n}\n\nexport interface ExtractedCell {\n row: number; col: number\n rowSpan: number; colSpan: number\n /** 셀 바운딩 박스 */\n bbox: { x1: number; y1: number; x2: number; y2: number }\n}\n\n// ─── 상수 ─────────────────────────────────────────────\n\n/** 수평/수직 판별 허용 오차 (pt) */\nconst ORIENTATION_TOL = 2\n/** 최소 선 길이 (너무 짧은 장식선 무시) */\nconst MIN_LINE_LENGTH = 10\n/** 좌표 병합 tolerance — ODL: 4 * vertexRadius, 여기선 고정 3pt */\nconst COORD_MERGE_TOL = 3\n/** 두 선이 같은 테이블에 속하는지 판별하는 거리 */\nconst CONNECT_TOL = 5\n/** 셀 경계 내부 판별 여유 (텍스트 매핑용) */\nconst CELL_PADDING = 2\n\n// ─── 선 추출 ──────────────────────────────────────────\n\n/**\n * pdfjs operatorList에서 수평/수직 선을 추출.\n * constructPath(91) 내의 moveTo→lineTo, rectangle 패턴을 인식.\n */\nexport function extractLines(\n fnArray: Uint32Array | number[],\n argsArray: unknown[][],\n): { horizontals: LineSegment[]; verticals: LineSegment[] } {\n const horizontals: LineSegment[] = []\n const verticals: LineSegment[] = []\n let lineWidth = 1\n\n // 현재 path의 세그먼트를 수집\n let currentPath: Array<{ x1: number; y1: number; x2: number; y2: number }> = []\n let pathStartX = 0, pathStartY = 0\n let curX = 0, curY = 0\n\n function pushRectangle(\n path: Array<{ x1: number; y1: number; x2: number; y2: number }>,\n rx: number, ry: number, rw: number, rh: number,\n ) {\n if (Math.abs(rh) < ORIENTATION_TOL * 2) {\n path.push({ x1: rx, y1: ry + rh / 2, x2: rx + rw, y2: ry + rh / 2 })\n } else if (Math.abs(rw) < ORIENTATION_TOL * 2) {\n path.push({ x1: rx + rw / 2, y1: ry, x2: rx + rw / 2, y2: ry + rh })\n } else {\n path.push(\n { x1: rx, y1: ry, x2: rx + rw, y2: ry },\n { x1: rx + rw, y1: ry, x2: rx + rw, y2: ry + rh },\n { x1: rx + rw, y1: ry + rh, x2: rx, y2: ry + rh },\n { x1: rx, y1: ry + rh, x2: rx, y2: ry },\n )\n }\n }\n\n function flushPath(isStroke: boolean) {\n if (!isStroke) { currentPath = []; return }\n for (const seg of currentPath) {\n classifyAndAdd(seg, lineWidth, horizontals, verticals)\n }\n currentPath = []\n }\n\n for (let i = 0; i < fnArray.length; i++) {\n const op = fnArray[i]\n const args = argsArray[i]\n\n switch (op) {\n case OPS.setLineWidth:\n lineWidth = (args as number[])[0] || 1\n break\n\n case OPS.constructPath: {\n const arg0 = args[0]\n\n if (Array.isArray(arg0)) {\n // ── pdfjs-dist v4 형식 ──\n // args = [subOps: number[], coords: number[], minMax]\n // subOps uses OPS constants: moveTo=13, lineTo=14, rectangle=19\n const subOps = arg0 as number[]\n const coords = (args as [number[], number[]])[1]\n let ci = 0\n\n for (const subOp of subOps) {\n if (subOp === OPS.moveTo) {\n curX = coords[ci++]; curY = coords[ci++]\n pathStartX = curX; pathStartY = curY\n } else if (subOp === OPS.lineTo) {\n const x2 = coords[ci++], y2 = coords[ci++]\n currentPath.push({ x1: curX, y1: curY, x2, y2 })\n curX = x2; curY = y2\n } else if (subOp === OPS.rectangle) {\n const rx = coords[ci++], ry = coords[ci++]\n const rw = coords[ci++], rh = coords[ci++]\n pushRectangle(currentPath, rx, ry, rw, rh)\n } else if (subOp === OPS.closePath) {\n if (curX !== pathStartX || curY !== pathStartY) {\n currentPath.push({ x1: curX, y1: curY, x2: pathStartX, y2: pathStartY })\n }\n curX = pathStartX; curY = pathStartY\n } else if (subOp === OPS.curveTo) {\n ci += 6\n } else if (subOp === OPS.curveTo2 || subOp === OPS.curveTo3) {\n ci += 4\n }\n }\n } else {\n // ── pdfjs-dist v5 형식 ──\n // args = [afterOp: number, [pathData: object], minMax]\n // afterOp = OPS.stroke(20), OPS.endPath(28), OPS.fill(22), etc.\n // pathData uses DrawOPS: moveTo=0, lineTo=1, curveTo=2, closePath=4\n const afterOp = arg0 as number\n const dataArr = args[1] as unknown[]\n const pathData = dataArr?.[0] as Record<number, number> | undefined\n if (pathData && typeof pathData === \"object\") {\n // pathData is an object with numeric keys: {0: op, 1: x, 2: y, ...}\n const len = Object.keys(pathData).length\n let di = 0\n while (di < len) {\n const drawOp = pathData[di++]\n if (drawOp === DrawOPS.moveTo) {\n curX = pathData[di++]; curY = pathData[di++]\n pathStartX = curX; pathStartY = curY\n } else if (drawOp === DrawOPS.lineTo) {\n const x2 = pathData[di++], y2 = pathData[di++]\n currentPath.push({ x1: curX, y1: curY, x2, y2 })\n curX = x2; curY = y2\n } else if (drawOp === DrawOPS.curveTo) {\n di += 6\n } else if (drawOp === DrawOPS.quadraticCurveTo) {\n di += 4\n } else if (drawOp === DrawOPS.closePath) {\n if (curX !== pathStartX || curY !== pathStartY) {\n currentPath.push({ x1: curX, y1: curY, x2: pathStartX, y2: pathStartY })\n }\n curX = pathStartX; curY = pathStartY\n } else {\n break // unknown op\n }\n }\n }\n\n // v5: afterOp이 stroke/fill이면 즉시 flush\n if (afterOp === OPS.stroke || afterOp === OPS.closeStroke) {\n flushPath(true)\n } else if (afterOp === OPS.fill || afterOp === OPS.eoFill ||\n afterOp === OPS.fillStroke || afterOp === OPS.eoFillStroke ||\n afterOp === OPS.closeFillStroke || afterOp === OPS.closeEOFillStroke) {\n flushPath(true)\n } else if (afterOp === OPS.endPath) {\n flushPath(false)\n }\n }\n break\n }\n\n case OPS.stroke:\n case OPS.closeStroke:\n flushPath(true)\n break\n\n case OPS.fill:\n case OPS.eoFill:\n case OPS.fillStroke:\n case OPS.eoFillStroke:\n case OPS.closeFillStroke:\n case OPS.closeEOFillStroke:\n // fill된 사각형도 테이블 선으로 처리 (셀 배경이 아닌 경우)\n flushPath(true)\n break\n\n case OPS.endPath:\n flushPath(false)\n break\n }\n }\n\n return { horizontals, verticals }\n}\n\nfunction classifyAndAdd(\n seg: { x1: number; y1: number; x2: number; y2: number },\n lineWidth: number,\n horizontals: LineSegment[],\n verticals: LineSegment[],\n) {\n const dx = Math.abs(seg.x2 - seg.x1)\n const dy = Math.abs(seg.y2 - seg.y1)\n const length = Math.sqrt(dx * dx + dy * dy)\n\n if (length < MIN_LINE_LENGTH) return\n\n if (dy <= ORIENTATION_TOL) {\n // 수평선\n const y = (seg.y1 + seg.y2) / 2\n const x1 = Math.min(seg.x1, seg.x2)\n const x2 = Math.max(seg.x1, seg.x2)\n horizontals.push({ x1, y1: y, x2, y2: y, lineWidth })\n } else if (dx <= ORIENTATION_TOL) {\n // 수직선\n const x = (seg.x1 + seg.x2) / 2\n const y1 = Math.min(seg.y1, seg.y2)\n const y2 = Math.max(seg.y1, seg.y2)\n verticals.push({ x1: x, y1, x2: x, y2, lineWidth })\n }\n // 대각선은 무시 (테이블 경계가 아님)\n}\n\n// ─── 페이지 경계(클립) 선 필터링 ──────────────────────\n\n/** 페이지 전체를 감싸는 클립 경계 선 제거 */\nexport function filterPageBorderLines(\n horizontals: LineSegment[],\n verticals: LineSegment[],\n pageWidth: number,\n pageHeight: number,\n): { horizontals: LineSegment[]; verticals: LineSegment[] } {\n const margin = 5\n return {\n horizontals: horizontals.filter(l =>\n !(Math.abs(l.y1) < margin || Math.abs(l.y1 - pageHeight) < margin) ||\n (l.x2 - l.x1) < pageWidth * 0.9\n ),\n verticals: verticals.filter(l =>\n !(Math.abs(l.x1) < margin || Math.abs(l.x1 - pageWidth) < margin) ||\n (l.y2 - l.y1) < pageHeight * 0.9\n ),\n }\n}\n\n// ─── 테이블 그리드 구성 ────────────────────────────────\n\n/**\n * 수평/수직 선에서 테이블 그리드를 추출.\n * 1. 교차하는 선들을 그룹화 (연결 컴포넌트)\n * 2. 각 그룹에서 X/Y 좌표를 클러스터링하여 그리드 구성\n */\nexport function buildTableGrids(\n horizontals: LineSegment[],\n verticals: LineSegment[],\n): TableGrid[] {\n if (horizontals.length < 2 || verticals.length < 2) return []\n\n // 1. 선들을 교차 관계로 그룹화\n const allLines = [\n ...horizontals.map((l, i) => ({ ...l, type: \"h\" as const, id: i })),\n ...verticals.map((l, i) => ({ ...l, type: \"v\" as const, id: i + horizontals.length })),\n ]\n\n const groups = groupConnectedLines(allLines)\n\n const grids: TableGrid[] = []\n\n for (const group of groups) {\n const hLines = group.filter(l => l.type === \"h\")\n const vLines = group.filter(l => l.type === \"v\")\n\n // 최소 2개 수평 + 2개 수직 선이 있어야 테이블\n if (hLines.length < 2 || vLines.length < 2) continue\n\n // 2. Y 좌표 클러스터링 (수평선의 y 값)\n const rawYs = hLines.map(l => l.y1)\n const rowYs = clusterCoordinates(rawYs).sort((a, b) => b - a) // 위→아래 (PDF는 y가 위가 큼)\n\n // 3. X 좌표 클러스터링 (수직선의 x 값)\n const rawXs = vLines.map(l => l.x1)\n const colXs = clusterCoordinates(rawXs).sort((a, b) => a - b)\n\n // 최소 2행 2열\n if (rowYs.length < 2 || colXs.length < 2) continue\n\n // 그리드에 실제로 셀이 형성되는지 검증\n const bbox = {\n x1: colXs[0], y1: rowYs[rowYs.length - 1],\n x2: colXs[colXs.length - 1], y2: rowYs[0],\n }\n\n grids.push({ rowYs, colXs, bbox })\n }\n\n // 인접 그리드 병합: 같은 열 구조 + 수직으로 가까운 그리드 합치기\n return mergeAdjacentGrids(grids)\n}\n\n/** 같은 열 구조를 가진 인접 그리드를 병합 (테이블 분리 방지) */\nfunction mergeAdjacentGrids(grids: TableGrid[]): TableGrid[] {\n if (grids.length <= 1) return grids\n // Y 좌표 기준 정렬 (위→아래 = y2 내림차순)\n const sorted = [...grids].sort((a, b) => b.bbox.y2 - a.bbox.y2)\n const merged: TableGrid[] = [sorted[0]]\n\n for (let i = 1; i < sorted.length; i++) {\n const prev = merged[merged.length - 1]\n const curr = sorted[i]\n\n // 같은 열 수 + 열 위치가 비슷한지 확인\n if (prev.colXs.length === curr.colXs.length) {\n const colMatch = prev.colXs.every((x, ci) => Math.abs(x - curr.colXs[ci]) <= COORD_MERGE_TOL * 3)\n // 수직으로 인접 (갭 < 20pt ≈ 7mm)\n const verticalGap = prev.bbox.y1 - curr.bbox.y2\n if (colMatch && verticalGap >= -COORD_MERGE_TOL && verticalGap <= 20) {\n // 병합: rowYs 합치기 (중복 제거), bbox 확장\n const allRowYs = [...new Set([...prev.rowYs, ...curr.rowYs])].sort((a, b) => b - a)\n merged[merged.length - 1] = {\n rowYs: allRowYs,\n colXs: prev.colXs,\n bbox: {\n x1: Math.min(prev.bbox.x1, curr.bbox.x1),\n y1: Math.min(prev.bbox.y1, curr.bbox.y1),\n x2: Math.max(prev.bbox.x2, curr.bbox.x2),\n y2: Math.max(prev.bbox.y2, curr.bbox.y2),\n },\n }\n continue\n }\n }\n merged.push(curr)\n }\n return merged\n}\n\n/** 좌표값 클러스터링 — 가까운 값끼리 병합 */\nfunction clusterCoordinates(values: number[]): number[] {\n if (values.length === 0) return []\n const sorted = [...values].sort((a, b) => a - b)\n const clusters: { sum: number; count: number }[] = [{ sum: sorted[0], count: 1 }]\n\n for (let i = 1; i < sorted.length; i++) {\n const last = clusters[clusters.length - 1]\n const avg = last.sum / last.count\n if (Math.abs(sorted[i] - avg) <= COORD_MERGE_TOL) {\n last.sum += sorted[i]\n last.count++\n } else {\n clusters.push({ sum: sorted[i], count: 1 })\n }\n }\n\n return clusters.map(c => c.sum / c.count)\n}\n\ntype TypedLine = LineSegment & { type: \"h\" | \"v\"; id: number }\n\n/** 교차하는 선들을 Union-Find로 그룹화 */\nfunction groupConnectedLines(lines: TypedLine[]): TypedLine[][] {\n const parent = lines.map((_, i) => i)\n\n function find(x: number): number {\n while (parent[x] !== x) { parent[x] = parent[parent[x]]; x = parent[x] }\n return x\n }\n function union(a: number, b: number) {\n const ra = find(a), rb = find(b)\n if (ra !== rb) parent[ra] = rb\n }\n\n // O(n²) 교차 검사 — 선 수가 수백 수준이므로 충분\n for (let i = 0; i < lines.length; i++) {\n for (let j = i + 1; j < lines.length; j++) {\n if (linesIntersect(lines[i], lines[j])) {\n union(i, j)\n }\n }\n }\n\n const groups = new Map<number, TypedLine[]>()\n for (let i = 0; i < lines.length; i++) {\n const root = find(i)\n if (!groups.has(root)) groups.set(root, [])\n groups.get(root)!.push(lines[i])\n }\n\n return [...groups.values()]\n}\n\n/** 수평선과 수직선의 교차 판정 (tolerance 포함) */\nfunction linesIntersect(a: TypedLine, b: TypedLine): boolean {\n // 같은 방향이면 교차 안 함 (평행)\n if (a.type === b.type) {\n // 같은 방향이라도 연결된 선일 수 있음 (끝점이 가까운 경우)\n if (a.type === \"h\") {\n if (Math.abs(a.y1 - b.y1) > CONNECT_TOL) return false\n // X 범위 겹침\n return Math.min(a.x2, b.x2) >= Math.max(a.x1, b.x1) - CONNECT_TOL\n } else {\n if (Math.abs(a.x1 - b.x1) > CONNECT_TOL) return false\n return Math.min(a.y2, b.y2) >= Math.max(a.y1, b.y1) - CONNECT_TOL\n }\n }\n\n // 수평 + 수직 교차\n const h = a.type === \"h\" ? a : b\n const v = a.type === \"h\" ? b : a\n const tol = CONNECT_TOL\n\n return (\n v.x1 >= h.x1 - tol && v.x1 <= h.x2 + tol &&\n h.y1 >= v.y1 - tol && h.y1 <= v.y2 + tol\n )\n}\n\n// ─── 셀 구조 추출 (colspan/rowspan 감지) ──────────────\n\n/**\n * 테이블 그리드에서 셀 목록을 추출.\n * 수평/수직 선의 존재 여부로 셀 병합(colspan/rowspan)을 감지.\n */\nexport function extractCells(\n grid: TableGrid,\n horizontals: LineSegment[],\n verticals: LineSegment[],\n): ExtractedCell[] {\n const { rowYs, colXs } = grid\n const numRows = rowYs.length - 1\n const numCols = colXs.length - 1\n if (numRows <= 0 || numCols <= 0) return []\n\n // 셀이 이미 병합된 셀에 포함되는지 추적\n const occupied = Array.from({ length: numRows }, () => Array(numCols).fill(false))\n const cells: ExtractedCell[] = []\n\n for (let r = 0; r < numRows; r++) {\n for (let c = 0; c < numCols; c++) {\n if (occupied[r][c]) continue\n\n // 이 셀에서 오른쪽/아래로 병합 가능한 범위 찾기\n let colSpan = 1\n let rowSpan = 1\n\n // colSpan: 오른쪽 경계에 수직선이 없으면 병합\n while (c + colSpan < numCols) {\n const borderX = colXs[c + colSpan]\n const topY = rowYs[r]\n const botY = rowYs[r + 1]\n if (hasVerticalLine(verticals, borderX, topY, botY)) break\n colSpan++\n }\n\n // rowSpan: 아래쪽 경계에 수평선이 없으면 병합\n while (r + rowSpan < numRows) {\n const borderY = rowYs[r + rowSpan]\n const leftX = colXs[c]\n const rightX = colXs[c + colSpan]\n if (hasHorizontalLine(horizontals, borderY, leftX, rightX)) break\n rowSpan++\n }\n\n // 병합 영역 마킹\n for (let dr = 0; dr < rowSpan; dr++) {\n for (let dc = 0; dc < colSpan; dc++) {\n occupied[r + dr][c + dc] = true\n }\n }\n\n cells.push({\n row: r, col: c, rowSpan, colSpan,\n bbox: {\n x1: colXs[c], y1: rowYs[r + rowSpan],\n x2: colXs[c + colSpan], y2: rowYs[r],\n },\n })\n }\n }\n\n return cells\n}\n\n/** 특정 X 위치에 수직선이 Y 범위를 커버하는지 확인 */\nfunction hasVerticalLine(verticals: LineSegment[], x: number, topY: number, botY: number): boolean {\n const tol = COORD_MERGE_TOL + 1\n for (const v of verticals) {\n if (Math.abs(v.x1 - x) <= tol) {\n // 선의 Y 범위가 셀 경계의 상당 부분(50%)을 커버하는지\n const cellH = Math.abs(topY - botY)\n const overlapTop = Math.min(v.y2, topY)\n const overlapBot = Math.max(v.y1, botY)\n const overlap = overlapTop - overlapBot\n if (overlap >= cellH * 0.5) return true\n }\n }\n return false\n}\n\n/** 특정 Y 위치에 수평선이 X 범위를 커버하는지 확인 */\nfunction hasHorizontalLine(horizontals: LineSegment[], y: number, leftX: number, rightX: number): boolean {\n const tol = COORD_MERGE_TOL + 1\n for (const h of horizontals) {\n if (Math.abs(h.y1 - y) <= tol) {\n const cellW = Math.abs(rightX - leftX)\n const overlapLeft = Math.max(h.x1, leftX)\n const overlapRight = Math.min(h.x2, rightX)\n const overlap = overlapRight - overlapLeft\n if (overlap >= cellW * 0.5) return true\n }\n }\n return false\n}\n\n// ─── 텍스트→셀 매핑 ──────────────────────────────────\n\nexport interface TextItem {\n text: string\n x: number; y: number; w: number; h: number\n fontSize: number; fontName: string\n}\n\n/**\n * 텍스트 아이템을 셀에 매핑.\n * 각 텍스트의 중심점이 어떤 셀의 bbox 안에 있는지로 판별.\n */\nexport function mapTextToCells(\n items: TextItem[],\n cells: ExtractedCell[],\n): Map<ExtractedCell, TextItem[]> {\n const result = new Map<ExtractedCell, TextItem[]>()\n for (const cell of cells) {\n result.set(cell, [])\n }\n\n for (const item of items) {\n const cx = item.x + item.w / 2\n const cy = item.y\n const pad = CELL_PADDING\n\n let bestCell: ExtractedCell | null = null\n let bestDist = Infinity\n\n for (const cell of cells) {\n // 중심점이 셀 bbox 안에 있는지 (패딩 포함)\n if (cx >= cell.bbox.x1 - pad && cx <= cell.bbox.x2 + pad &&\n cy >= cell.bbox.y1 - pad && cy <= cell.bbox.y2 + pad) {\n // 여러 셀에 해당하면 가장 가까운 셀 중심에 배정\n const cellCx = (cell.bbox.x1 + cell.bbox.x2) / 2\n const cellCy = (cell.bbox.y1 + cell.bbox.y2) / 2\n const dist = Math.abs(cx - cellCx) + Math.abs(cy - cellCy)\n if (dist < bestDist) {\n bestDist = dist\n bestCell = cell\n }\n }\n }\n\n if (bestCell) {\n result.get(bestCell)!.push(item)\n }\n }\n\n return result\n}\n\n/**\n * 셀 내 텍스트 아이템을 읽기 순서로 정렬 후 합치기.\n * Y 내림차순 (위→아래) → X 오름차순 (좌→우)\n */\nexport function cellTextToString(items: TextItem[]): string {\n if (items.length === 0) return \"\"\n if (items.length === 1) return items[0].text\n\n // Y좌표로 행 그룹핑 (tolerance: max(3, fontSize*0.6))\n const sorted = [...items].sort((a, b) => b.y - a.y || a.x - b.x)\n const lines: TextItem[][] = []\n let curLine: TextItem[] = [sorted[0]]\n let curY = sorted[0].y\n\n for (let i = 1; i < sorted.length; i++) {\n const tol = Math.max(3, Math.min(sorted[i].fontSize, curLine[0].fontSize) * 0.6)\n if (Math.abs(sorted[i].y - curY) <= tol) {\n curLine.push(sorted[i])\n } else {\n lines.push(curLine)\n curLine = [sorted[i]]\n curY = sorted[i].y\n }\n }\n lines.push(curLine)\n\n // 각 행을 텍스트로 변환 — 한글 간 작은 갭은 공백 없이 붙임\n const textLines = lines.map(line => {\n const s = line.sort((a, b) => a.x - b.x)\n if (s.length === 1) return s[0].text\n let result = s[0].text\n for (let j = 1; j < s.length; j++) {\n const gap = s[j].x - (s[j - 1].x + s[j - 1].w)\n const avgFs = (s[j].fontSize + s[j - 1].fontSize) / 2\n // 한글 관련 문자 전환 시 작은 갭 → 공백 없이 붙임\n // (한글-한글, ASCII→한글, 한글→ASCII 모두 포함)\n const prevIsKorean = /[가-힣]$/.test(result)\n const currIsKorean = /^[가-힣]/.test(s[j].text)\n if (gap < avgFs * 0.15) {\n // 매우 작은 갭 — 모든 문자 타입에서 공백 없이 붙임\n result += s[j].text\n } else if (gap < avgFs * 0.35 && (prevIsKorean || currIsKorean)) {\n // 한글 관련 작은 갭 — PDF 문자 개별 배치 잔재\n result += s[j].text\n } else {\n result += \" \" + s[j].text\n }\n }\n return result\n })\n\n // 셀 내 줄바꿈 병합 — 잘린 단어/숫자 조각 복구\n if (textLines.length <= 1) return textLines[0] || \"\"\n const merged: string[] = [textLines[0]]\n for (let i = 1; i < textLines.length; i++) {\n const prev = merged[merged.length - 1]\n const curr = textLines[i]\n // 짧은 순수 한글 (8자 이하) = 잘린 단어 조각\n if (/[가-힣]$/.test(prev) && /^[가-힣]+$/.test(curr) && curr.length <= 8 && !curr.includes(\" \")) {\n merged[merged.length - 1] = prev + curr\n }\n // 닫는 괄호/기호 포함 짧은 줄 (3자 이하) = 이전 줄에 붙임 (예: \")\", \"%)\", \"%) 별도\")\n else if (curr.trim().length <= 3 && /^[)\\]%}]/.test(curr.trim())) {\n merged[merged.length - 1] = prev + curr.trim()\n }\n // 이전 줄이 여는 괄호나 쉼표로 끝남 = 다음 줄 붙임 (예: \"(x15,232,700,\" + \"000)\")\n else if (/[,(]$/.test(prev.trim()) && curr.trim().length <= 15) {\n merged[merged.length - 1] = prev + curr.trim()\n }\n // 숫자 줄바꿈 복구: 이전 줄이 숫자/쉼표로 끝나고 다음 줄이 숫자로 시작하는 짧은 조각\n else if (/[\\d,]$/.test(prev) && /^[\\d,]+[)\\]]?$/.test(curr.trim()) && curr.trim().length <= 10) {\n merged[merged.length - 1] = prev + curr.trim()\n }\n else {\n merged.push(curr)\n }\n }\n return merged.join(\"\\n\")\n}\n","/**\n * 클러스터 기반 테이블 감지 — 선이 없는 PDF에서 텍스트 정렬 패턴으로 테이블 구조 추론.\n *\n * Original work: Copyright 2025-2026 Hancom, Inc.\n * Licensed under the Apache License, Version 2.0\n * https://github.com/opendataloader-project/opendataloader-pdf\n *\n * ODL의 ClusterTableConsumer를 kordoc 컨텍스트에 맞게 단순화한 구현.\n * Modifications: TypeScript 재구현, 최소 2열 감지, 한국어 PDF 특화 최적화.\n *\n * 핵심 아이디어:\n * 1. 텍스트 아이템을 baseline(Y좌표)으로 그룹핑하여 행(row) 구성\n * 2. 각 행의 아이템 X좌표를 수집, 행 간 공통 X좌표 클러스터(열) 감지\n * 3. 2+ 열이 3+ 행에 걸쳐 일관되면 테이블로 판정\n * 4. 기존 detectColumns(min 3열)보다 느슨한 기준(min 2열)으로\n * 2열 테이블(key-value 등)도 감지\n */\n\nimport type { IRBlock, IRTable, IRCell, BoundingBox } from \"../types.js\"\n\n/** parser.ts의 NormItem과 동일한 인터페이스 */\nexport interface ClusterItem {\n text: string\n x: number\n y: number\n w: number\n h: number\n fontSize: number\n fontName: string\n}\n\n// ─── 상수 ──────────────────────────────────────────────\n/** baseline 그룹핑 허용 오차 (pt) */\nconst Y_TOL = 3\n/** 열 클러스터링 허용 오차 (pt) — detectColumns의 CLUSTER_TOL=22보다 엄격 */\nconst COL_CLUSTER_TOL = 15\n/** 테이블로 인정하기 위한 최소 행 수 */\nconst MIN_ROWS = 3\n/** 테이블로 인정하기 위한 최소 열 수 */\nconst MIN_COLS = 2\n/** 같은 행 내 아이템 간 최소 갭 (테이블 컬럼 구분) — fontSize 배수 */\nconst MIN_GAP_FACTOR = 1.5\n/** 열에 값이 있는 행의 비율 최소 기준 */\nconst MIN_COL_FILL_RATIO = 0.3\n\ninterface RowGroup {\n y: number // 대표 Y좌표 (평균 baseline)\n items: ClusterItem[]\n}\n\ninterface ColCluster {\n x: number // 열 X좌표 (왼쪽 경계)\n count: number // 이 열에 속한 아이템 수\n}\n\nexport interface ClusterTableResult {\n table: IRTable\n bbox: BoundingBox\n usedItems: Set<ClusterItem>\n}\n\n/**\n * 클러스터 기반 테이블 감지. 선이 없는 PDF의 fallback 경로에서 호출.\n *\n * @param items 페이지의 텍스트 아이템 (Y 내림차순 정렬)\n * @param pageNum 페이지 번호\n * @returns 감지된 테이블들 (없으면 빈 배열)\n */\nexport function detectClusterTables(items: ClusterItem[], pageNum: number): ClusterTableResult[] {\n if (items.length < MIN_ROWS * MIN_COLS) return []\n\n // 1. Y좌표로 행 그룹핑\n const rows = groupByBaseline(items)\n if (rows.length < MIN_ROWS) return []\n\n // 2. \"의심스러운\" 행 식별 — 아이템 간 큰 갭이 있는 행\n const suspiciousRows = rows.filter(row => hasSuspiciousGaps(row))\n if (suspiciousRows.length < MIN_ROWS) return []\n\n // 3. 의심스러운 행들의 X좌표에서 열 클러스터 추출\n const columns = extractColumnClusters(suspiciousRows)\n if (columns.length < MIN_COLS) return []\n\n // 4. 연속된 의심스러운 행들을 테이블 영역으로 그룹화\n const tableRegions = findTableRegions(rows, columns)\n const results: ClusterTableResult[] = []\n\n for (const region of tableRegions) {\n const table = buildClusterTable(region.rows, columns, pageNum)\n if (table) results.push(table)\n }\n\n return results\n}\n\n/** 아이템을 baseline(Y좌표)으로 그룹핑 */\nfunction groupByBaseline(items: ClusterItem[]): RowGroup[] {\n if (items.length === 0) return []\n\n const sorted = [...items].sort((a, b) => b.y - a.y || a.x - b.x)\n const rows: RowGroup[] = []\n let curItems: ClusterItem[] = [sorted[0]]\n let curY = sorted[0].y\n\n for (let i = 1; i < sorted.length; i++) {\n if (Math.abs(sorted[i].y - curY) <= Y_TOL) {\n curItems.push(sorted[i])\n } else {\n rows.push({ y: curY, items: curItems })\n curItems = [sorted[i]]\n curY = sorted[i].y\n }\n }\n if (curItems.length > 0) rows.push({ y: curY, items: curItems })\n\n return rows\n}\n\n/** 행 내 아이템 간 \"의심스러운\" 갭 존재 여부 (테이블 열 구분 후보) */\nfunction hasSuspiciousGaps(row: RowGroup): boolean {\n if (row.items.length < 2) return false\n\n const sorted = [...row.items].sort((a, b) => a.x - b.x)\n const avgFontSize = sorted.reduce((s, i) => s + i.fontSize, 0) / sorted.length\n const minGap = avgFontSize * MIN_GAP_FACTOR\n\n for (let i = 1; i < sorted.length; i++) {\n const gap = sorted[i].x - (sorted[i - 1].x + sorted[i - 1].w)\n if (gap >= minGap) return true\n }\n return false\n}\n\n/** 의심스러운 행들의 X좌표에서 열 클러스터 추출 (sort-and-split 방식, 순서 무관) */\nfunction extractColumnClusters(rows: RowGroup[]): ColCluster[] {\n // 모든 X좌표 수집\n const allX: number[] = []\n for (const row of rows) {\n for (const item of row.items) allX.push(item.x)\n }\n if (allX.length === 0) return []\n\n // 정렬 후 갭 기반 분할\n allX.sort((a, b) => a - b)\n\n const clusters: ColCluster[] = []\n let clusterStart = 0\n\n for (let i = 1; i <= allX.length; i++) {\n if (i === allX.length || allX[i] - allX[i - 1] > COL_CLUSTER_TOL) {\n // 클러스터 완성: [clusterStart, i)\n const slice = allX.slice(clusterStart, i)\n const avg = Math.round(slice.reduce((s, v) => s + v, 0) / slice.length)\n clusters.push({ x: avg, count: slice.length })\n clusterStart = i\n }\n }\n\n // 최소 빈도 필터 — 행 수의 30% 이상 등장해야 유효한 열\n const minCount = Math.max(2, Math.floor(rows.length * MIN_COL_FILL_RATIO))\n return clusters\n .filter(c => c.count >= minCount)\n .sort((a, b) => a.x - b.x)\n}\n\n/** 연속된 테이블 행 영역 찾기 */\nfunction findTableRegions(allRows: RowGroup[], columns: ColCluster[]): { rows: RowGroup[] }[] {\n const regions: { rows: RowGroup[] }[] = []\n let currentRegion: RowGroup[] = []\n\n for (const row of allRows) {\n // 이 행이 열 구조에 맞는지 확인\n const matchedCols = countMatchedColumns(row, columns)\n if (matchedCols >= MIN_COLS) {\n currentRegion.push(row)\n } else if (row.items.length === 1) {\n // 단일 아이템 행 — 병합 셀이거나 헤더일 수 있음\n if (currentRegion.length > 0) {\n currentRegion.push(row)\n }\n } else {\n // 비테이블 행 → 현재 영역 종료\n if (currentRegion.length >= MIN_ROWS) {\n regions.push({ rows: [...currentRegion] })\n }\n currentRegion = []\n }\n }\n\n if (currentRegion.length >= MIN_ROWS) {\n regions.push({ rows: currentRegion })\n }\n\n return regions\n}\n\n/** 행의 아이템이 몇 개의 열에 매칭되는지 */\nfunction countMatchedColumns(row: RowGroup, columns: ColCluster[]): number {\n const matched = new Set<number>()\n for (const item of row.items) {\n for (let ci = 0; ci < columns.length; ci++) {\n if (Math.abs(item.x - columns[ci].x) <= COL_CLUSTER_TOL * 2) {\n matched.add(ci)\n break\n }\n }\n }\n return matched.size\n}\n\n/** 아이템을 열에 배정. 거리 제한 초과 시 -1 반환. */\nfunction assignToColumn(item: ClusterItem, columns: ColCluster[]): number {\n const MAX_DIST = COL_CLUSTER_TOL * 3\n let bestCol = -1\n let bestDist = Infinity\n for (let ci = 0; ci < columns.length; ci++) {\n const dist = Math.abs(item.x - columns[ci].x)\n if (dist < bestDist) {\n bestDist = dist\n bestCol = ci\n }\n }\n return bestDist <= MAX_DIST ? bestCol : -1\n}\n\n/** 클러스터 테이블을 IRTable로 구성 */\nfunction buildClusterTable(\n rows: RowGroup[],\n columns: ColCluster[],\n pageNum: number,\n): ClusterTableResult | null {\n const numCols = columns.length\n const numRows = rows.length\n\n if (numRows < MIN_ROWS || numCols < MIN_COLS) return null\n\n // 셀 그리드 구성\n const cells: IRCell[][] = Array.from(\n { length: numRows },\n () => Array.from({ length: numCols }, () => ({ text: \"\", colSpan: 1, rowSpan: 1 })),\n )\n\n const usedItems = new Set<ClusterItem>()\n\n for (let r = 0; r < numRows; r++) {\n const row = rows[r]\n // 단일 아이템 행 → 전체 행 병합 (colSpan)\n if (row.items.length === 1 && numCols > 1) {\n cells[r][0] = { text: row.items[0].text, colSpan: numCols, rowSpan: 1 }\n usedItems.add(row.items[0])\n continue\n }\n\n for (const item of row.items) {\n const col = assignToColumn(item, columns)\n if (col < 0) continue // 열에 매칭 안 되는 아이템은 무시\n const existing = cells[r][col].text\n cells[r][col].text = existing ? existing + \" \" + item.text : item.text\n usedItems.add(item)\n }\n }\n\n // 검증: 빈 행이 너무 많으면 테이블 아님\n let emptyRows = 0\n for (const row of cells) {\n if (row.every(c => c.text === \"\")) emptyRows++\n }\n if (emptyRows > numRows * 0.5) return null\n\n // 검증: 모든 열에 최소 1개 값이 있어야 함\n for (let c = 0; c < numCols; c++) {\n const hasValue = cells.some(row => row[c].text !== \"\")\n if (!hasValue) return null\n }\n\n const irTable: IRTable = {\n rows: numRows,\n cols: numCols,\n cells,\n hasHeader: numRows > 1,\n }\n\n // BBox 계산\n const allItems = rows.flatMap(r => r.items)\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity\n for (const i of allItems) {\n if (i.x < minX) minX = i.x\n if (i.y < minY) minY = i.y\n if (i.x + i.w > maxX) maxX = i.x + i.w\n const h = i.h > 0 ? i.h : i.fontSize\n if (i.y + h > maxY) maxY = i.y + h\n }\n\n return {\n table: irTable,\n bbox: { page: pageNum, x: minX, y: minY, width: maxX - minX, height: maxY - minY },\n usedItems,\n }\n}\n","/**\n * 서버리스/Node.js 환경에서 pdfjs-dist가 요구하는 브라우저 API polyfill.\n * pdfjs-dist import보다 먼저 실행되어야 함 (ES 모듈 호이스팅 대응으로 별도 파일 분리).\n *\n * 1. DOMMatrix / Path2D polyfill — pdfjs-dist가 참조하지만 Node.js에 없음\n * 2. pdfjsWorker 사전 주입 — fake worker의 동적 import를 우회\n */\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst g = globalThis as any\n\nif (typeof g.DOMMatrix === \"undefined\") {\n g.DOMMatrix = class DOMMatrix {\n m: number[] = [1, 0, 0, 1, 0, 0]\n constructor(init?: number[]) { if (init) this.m = init }\n }\n}\n\nif (typeof g.Path2D === \"undefined\") {\n g.Path2D = class Path2D {}\n}\n\n// worker 모듈 static import → fake worker가 동적 import를 건너뜀\n// @ts-expect-error pdfjs-dist worker has no type declarations\nimport * as pdfjsWorker from \"pdfjs-dist/legacy/build/pdf.worker.mjs\"\ng.pdfjsWorker = pdfjsWorker\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 } from \"../utils.js\"\nimport { buildTable, blocksToMarkdown } from \"../table/builder.js\"\n\n// ─── 상수 ────────────────────────────────────────────\n\nconst MAX_SHEETS = 100\n/** ZIP 압축 해제 누적 최대 크기 (500MB) — ZIP bomb 방지 */\nconst MAX_DECOMPRESS_SIZE = 500 * 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 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(text, \"text/xml\")\n}\n\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 const tElements = getElements(si, \"t\")\n strings.push(tElements.map(t => t.textContent ?? \"\").join(\"\"))\n }\n return strings\n}\n\n// ─── 시트 목록 파싱 ─────────────────────────────────────\n\ninterface SheetInfo {\n name: string\n sheetId: string\n rId: string\n}\n\nfunction parseWorkbook(xml: string): SheetInfo[] {\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 return sheets\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): { 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 for (const rowEl of rows) {\n const rowNum = parseInt(rowEl.getAttribute(\"r\") ?? \"0\", 10) - 1\n if (rowNum < 0 || rowNum >= MAX_ROWS) continue\n\n const cells = getElements(rowEl, \"c\")\n for (const cellEl of cells) {\n const ref = cellEl.getAttribute(\"r\")\n if (!ref) continue\n const pos = parseCellRef(ref)\n if (!pos || pos.col >= MAX_COLS) continue\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 }\n } else if (type === \"inlineStr\") {\n // <is><t>text</t></is>\n const isEl = getElements(cellEl, \"is\")\n if (isEl.length > 0) {\n const tElements = getElements(isEl[0], \"t\")\n value = tElements.map(t => t.textContent ?? \"\").join(\"\")\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 if (m) merges.push(m)\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): 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)\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 = parseWorkbook(await workbookFile.async(\"text\"))\n if (sheets.length === 0) {\n throw new KordocError(\"XLSX 파일에 시트가 없습니다\")\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)\n const sheetBlocks = sheetToBlocks(sheet.name, grid, merges, maxRow, maxCol, i)\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 * 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 IRBlock, IRTable, IRCell, DocumentMetadata, InternalParseResult,\n ParseOptions, ParseWarning, ExtractedImage, InlineStyle,\n} from \"../types.js\"\nimport { KordocError, precheckZipSize } from \"../utils.js\"\nimport { blocksToMarkdown } from \"../table/builder.js\"\n\n/** ZIP 압축 해제 누적 최대 크기 (500MB) — ZIP bomb 방지 */\nconst MAX_DECOMPRESS_SIZE = 500 * 1024 * 1024\n\n// ─── XML 헬퍼 ──────────────────────────────────────────\n\n/** 네임스페이스 무시 태그 검색 — DOCX는 네임스페이스가 많음 */\nfunction getChildElements(parent: Element | Document, localName: string): 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) {\n const el = node as Element\n if (el.localName === localName || el.tagName?.endsWith(`:${localName}`)) {\n result.push(el)\n }\n }\n }\n return result\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(text, \"text/xml\")\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 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// ─── Run 텍스트 추출 ──────────────────────────────────\n\ninterface RunResult {\n text: string\n bold: boolean\n italic: boolean\n}\n\nfunction extractRun(r: Element): RunResult {\n const tElements = getChildElements(r, \"t\")\n const text = tElements.map(t => t.textContent ?? \"\").join(\"\")\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\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 // 텍스트 수집\n const parts: string[] = []\n let hasBold = false\n let hasItalic = false\n let href: string | undefined\n let footnoteText: string | undefined\n\n // 하이퍼링크 처리\n const hyperlinks = getChildElements(p, \"hyperlink\")\n const hyperlinkTexts = new Set<string>()\n\n for (const hl of hyperlinks) {\n const rId = getAttr(hl, \"id\")\n const hlText: string[] = []\n const runs = findElements(hl, \"r\")\n for (const r of runs) {\n const result = extractRun(r)\n hlText.push(result.text)\n }\n const text = hlText.join(\"\")\n if (text) {\n hyperlinkTexts.add(text)\n if (rId && rels.has(rId)) {\n href = rels.get(rId)\n parts.push(text)\n } else {\n parts.push(text)\n }\n }\n }\n\n // 일반 run 처리\n const runs = getChildElements(p, \"r\")\n for (const r of runs) {\n // 하이퍼링크 내부 run은 이미 처리됨 — 부모가 hyperlink이면 스킵\n if (r.parentNode && (r.parentNode as Element).localName === \"hyperlink\") continue\n\n const result = extractRun(r)\n if (result.bold) hasBold = true\n if (result.italic) hasItalic = true\n\n // 각주 참조 확인\n const fnRefEls = getChildElements(r, \"footnoteReference\")\n if (fnRefEls.length > 0) {\n const fnId = getAttr(fnRefEls[0], \"id\")\n if (fnId && footnotes.has(fnId)) {\n footnoteText = footnotes.get(fnId)\n }\n }\n\n if (result.text) parts.push(result.text)\n }\n\n const text = parts.join(\"\").trim()\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 (href) block.href = href\n if (footnoteText) block.footnoteText = footnoteText\n return block\n}\n\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): IRBlock | null {\n const trElements = getChildElements(tbl, \"tr\")\n if (trElements.length === 0) return null\n\n const rows: IRCell[][] = []\n let maxCols = 0\n\n for (const tr of trElements) {\n const tcElements = getChildElements(tr, \"tc\")\n const row: IRCell[] = []\n\n for (const tc of tcElements) {\n // 셀 속성\n let colSpan = 1\n let rowSpan = 1\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)\n }\n const vMergeEls = getChildElements(tcPrEls[0], \"vMerge\")\n if (vMergeEls.length > 0) {\n const val = getAttr(vMergeEls[0], \"val\")\n if (val !== \"restart\" && val !== null) {\n // 병합 계속 셀 — 스킵 마커\n row.push({ text: \"\", colSpan, rowSpan: 0 })\n continue\n }\n }\n }\n\n // 셀 텍스트\n const cellTexts: string[] = []\n const pElements = getChildElements(tc, \"p\")\n for (const p of pElements) {\n const block = parseParagraph(p, styles, numbering, footnotes, rels)\n if (block?.text) cellTexts.push(block.text)\n }\n\n row.push({ text: cellTexts.join(\"\\n\"), colSpan, rowSpan })\n }\n rows.push(row)\n if (row.length > maxCols) maxCols = row.length\n }\n\n // vMerge rowSpan 후처리: restart에서 아래로 연속되는 rowSpan=0 카운트\n for (let c = 0; c < maxCols; c++) {\n for (let r = 0; r < rows.length; r++) {\n const cell = rows[r][c]\n if (!cell || cell.rowSpan === 0) continue\n let span = 1\n for (let nr = r + 1; nr < rows.length; nr++) {\n if (rows[nr][c]?.rowSpan === 0) span++\n else break\n }\n cell.rowSpan = span\n }\n }\n\n // rowSpan=0인 placeholder 제거\n const cleanRows: IRCell[][] = []\n for (const row of rows) {\n const clean = row.filter(cell => cell.rowSpan !== 0)\n cleanRows.push(clean)\n }\n\n // 빈 테이블 체크\n if (cleanRows.length === 0) return null\n\n // 컬럼 수 재계산\n let cols = 0\n for (const row of cleanRows) {\n let c = 0\n for (const cell of row) c += cell.colSpan\n if (c > cols) cols = c\n }\n\n const table: IRTable = {\n rows: cleanRows.length,\n cols,\n cells: cleanRows,\n hasHeader: cleanRows.length > 1,\n }\n return { type: \"table\", table }\n}\n\n// ─── 이미지 추출 ────────────────────────────────────────\n\nasync function extractImages(\n zip: JSZip,\n rels: Map<string, string>,\n doc: Document,\n): Promise<{ blocks: IRBlock[]; images: ExtractedImage[] }> {\n const blocks: IRBlock[] = []\n const images: ExtractedImage[] = []\n\n const drawingElements = findElements(doc.documentElement, \"drawing\")\n let imgIdx = 0\n\n for (const drawing of drawingElements) {\n // a:blip → r:embed\n const blips = findElements(drawing, \"blip\")\n for (const blip of blips) {\n const embedId = getAttr(blip, \"embed\")\n if (!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 }\n const filename = `image_${String(imgIdx).padStart(3, \"0\")}.${ext}`\n images.push({ filename, data, mimeType: mimeMap[ext] ?? \"image/png\" })\n blocks.push({ type: \"image\", text: filename })\n } catch { /* 이미지 실패 무시 */ }\n }\n }\n return { blocks, images }\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 { /* 스타일 실패 무시 */ }\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 { /* 번호 매기기 실패 무시 */ }\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 { /* 각주 실패 무시 */ }\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 const blocks: IRBlock[] = []\n const bodyEl = body[0]\n const children = bodyEl.childNodes\n\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 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 } else if (localName === \"tbl\") {\n const block = parseTable(el, styles, numbering, footnotes, rels)\n if (block) blocks.push(block)\n }\n }\n\n // 6. 이미지 추출\n const { blocks: imgBlocks, images } = await extractImages(zip, rels, doc)\n // 이미지 블록은 본문에 이미 포함되어야 하지만, 누락된 것 추가\n // (drawing이 paragraph 내에 있으므로 대부분 이미 포함됨)\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 { /* 메타데이터 실패 무시 */ }\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","/** 텍스트 유사도 및 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/** Levenshtein 편집 거리 — O(min(m,n)) 공간 최적화 */\nfunction levenshtein(a: string, b: string): number {\n if (a.length + b.length > MAX_LEVENSHTEIN_LEN) return Math.abs(a.length - b.length)\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\nfunction simpleIntersect(a: string[], b: string[]): string[] {\n const setB = new Set(b)\n return a.filter(w => setB.has(w))\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","/** 문서 비교 엔진 — 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 // 유사도 매트릭스 캐시\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) { v = blockSimilarity(a[i], b[j]); simCache.set(key, v) }\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 // 내용 유사도 (셀 텍스트)\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 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","/** 양식(서식) 필드 인식 — 테이블 기반 label-value 패턴 매칭 */\n\nimport type { IRBlock, IRTable, FormField, FormResult } from \"../types.js\"\n\n/** 한국 공문서 필드 라벨 키워드 */\nconst LABEL_KEYWORDS = new Set([\n \"성명\", \"이름\", \"주소\", \"전화\", \"전화번호\", \"휴대폰\", \"핸드폰\", \"연락처\",\n \"생년월일\", \"주민등록번호\", \"소속\", \"직위\", \"직급\", \"부서\",\n \"이메일\", \"팩스\", \"학교\", \"학년\", \"반\", \"번호\",\n \"신청인\", \"대표자\", \"담당자\", \"작성자\", \"확인자\", \"승인자\",\n \"일시\", \"날짜\", \"기간\", \"장소\", \"목적\", \"사유\", \"비고\",\n \"금액\", \"수량\", \"단가\", \"합계\", \"계\", \"소계\",\n])\n\n/** 라벨처럼 보이는 셀인지 판별 */\nfunction isLabelCell(text: string): boolean {\n const trimmed = text.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-8자) + 숫자 없음\n if (/^[가-힣\\s()·:]{2,8}$/.test(trimmed) && !/\\d/.test(trimmed)) return true\n // \"라벨:\" 패턴\n if (/^[가-힣A-Za-z\\s]+[::]$/.test(trimmed)) return true\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 block of blocks) {\n if (block.type !== \"table\" || !block.table) continue\n totalTables++\n\n const tableFields = extractFromTable(block.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\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 (isLabelCell(labelCell.text) && valueCell.text.trim()) {\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 })\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 const fields: FormField[] = []\n // \"라벨: 값\" 또는 \"라벨 : 값\" 패턴\n const pattern = /([가-힣A-Za-z]{2,10})\\s*[::]\\s*([^\\n,;]{1,100})/g\n let match\n while ((match = pattern.exec(text)) !== null) {\n const label = match[1].trim()\n const value = match[2].trim()\n if (value) {\n fields.push({ label, value, row: -1, col: -1 })\n }\n }\n return fields\n}\n","/**\n * Markdown → HWPX 역변환\n *\n * 지원: 단락, 헤딩(1-6), 테이블, 목록(ul/ol), 볼드/이탤릭 인라인, 코드\n * hwpxskill 검증 템플릿 기반 — 실제 한/글과 동일한 파일 구조 사용\n */\n\nimport JSZip from \"jszip\"\nimport {\n HEADER_XML,\n CONTENT_HPF,\n CONTAINER_XML,\n CONTAINER_RDF,\n MANIFEST_XML,\n VERSION_XML,\n SETTINGS_XML,\n} from \"./template-content.js\"\nimport { extractTemplateStyles } from \"./template-analyzer.js\"\nimport { createStyleMap, getStyleForBlock, getCharPrForInline } from \"./style-matcher.js\"\nimport type { StyleMap } from \"./style-matcher.js\"\nimport type { ExtractedImage } from \"../types.js\"\n\n// ─── charPr ID 상수 (template/Contents/header.xml과 일치) ──\n\nconst CHAR_NORMAL = \"0\" // 10pt 기본\nconst CHAR_H1 = \"7\" // 20pt 볼드\nconst CHAR_H2 = \"8\" // 14pt 볼드\nconst CHAR_H3 = \"9\" // 12pt 볼드\nconst CHAR_H456 = \"10\" // 11pt 볼드\nconst CHAR_BOLD = \"11\" // 10pt 볼드 인라인\nconst CHAR_ITALIC = \"12\" // 10pt 이탤릭 인라인\nconst CHAR_BOLD_ITALIC = \"13\" // 10pt 볼드+이탤릭 인라인\nconst CHAR_CODE = \"14\" // 9pt 코드 (회색 음영)\nconst CHAR_STRIKETHROUGH = \"15\" // 10pt 취소선\n\nconst PARA_NORMAL = \"0\"\nconst PARA_BLOCKQUOTE = \"20\"\nconst PARA_HR = \"21\"\n\n// ─── section0.xml 네임스페이스 (hwpxskill 템플릿과 동일) ──\n\nconst SEC_NS = [\n `xmlns:ha=\"http://www.hancom.co.kr/hwpml/2011/app\"`,\n `xmlns:hp=\"http://www.hancom.co.kr/hwpml/2011/paragraph\"`,\n `xmlns:hp10=\"http://www.hancom.co.kr/hwpml/2016/paragraph\"`,\n `xmlns:hs=\"http://www.hancom.co.kr/hwpml/2011/section\"`,\n `xmlns:hc=\"http://www.hancom.co.kr/hwpml/2011/core\"`,\n `xmlns:hh=\"http://www.hancom.co.kr/hwpml/2011/head\"`,\n `xmlns:hhs=\"http://www.hancom.co.kr/hwpml/2011/history\"`,\n `xmlns:hm=\"http://www.hancom.co.kr/hwpml/2011/master-page\"`,\n `xmlns:hpf=\"http://www.hancom.co.kr/schema/2011/hpf\"`,\n `xmlns:dc=\"http://purl.org/dc/elements/1.1/\"`,\n `xmlns:opf=\"http://www.idpf.org/2007/opf/\"`,\n `xmlns:ooxmlchart=\"http://www.hancom.co.kr/hwpml/2016/ooxmlchart\"`,\n `xmlns:hwpunitchar=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\"`,\n `xmlns:epub=\"http://www.idpf.org/2007/ops\"`,\n `xmlns:config=\"urn:oasis:names:tc:opendocument:xmlns:config:1.0\"`,\n].join(\" \")\n\n// ─── ID 생성 ─────────────────────────────────────────────\n\nfunction makeIdGen(): () => string {\n let counter = 1_000_000_001\n return () => String(counter++)\n}\n\n// ─── XML 이스케이프 ──────────────────────────────────────\n\nfunction escapeXml(text: string): string {\n return text\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n}\n\n// ─── 인라인 마크다운 파싱 ────────────────────────────────\n\ninterface InlineRun {\n text: string\n bold?: boolean\n italic?: boolean\n code?: boolean\n strikethrough?: boolean\n url?: string // 링크인 경우 URL\n}\n\nfunction parseInlineRuns(text: string): InlineRun[] {\n const runs: InlineRun[] = []\n // 순서 중요: ***>**>*>_>`>링크 순으로 매칭\n const re = /\\*\\*\\*(.+?)\\*\\*\\*|\\*\\*(.+?)\\*\\*|\\*(.+?)\\*|_(.+?)_|`(.+?)`|~~(.+?)~~|\\[([^\\]]+)\\]\\(([^)]+)\\)/g\n let last = 0\n let m: RegExpExecArray | null\n\n while ((m = re.exec(text)) !== null) {\n if (m.index > last) runs.push({ text: text.slice(last, m.index) })\n if (m[1]) runs.push({ text: m[1], bold: true, italic: true })\n else if (m[2]) runs.push({ text: m[2], bold: true })\n else if (m[3]) runs.push({ text: m[3], italic: true })\n else if (m[4]) runs.push({ text: m[4], italic: true })\n else if (m[5]) runs.push({ text: m[5], code: true })\n else if (m[6]) runs.push({ text: m[6], strikethrough: true })\n else if (m[7]) runs.push({ text: m[7], url: m[8] }) // [text](url)\n last = m.index + m[0].length\n }\n if (last < text.length) runs.push({ text: text.slice(last) })\n return runs.filter(r => r.text.length > 0)\n}\n\nfunction charPrForRun(run: InlineRun): string {\n if (run.code) return CHAR_CODE\n if (run.strikethrough) return CHAR_STRIKETHROUGH\n if (run.bold && run.italic) return CHAR_BOLD_ITALIC\n if (run.bold) return CHAR_BOLD\n if (run.italic) return CHAR_ITALIC\n return CHAR_NORMAL\n}\n\n// ─── 런/문단 XML 생성 ────────────────────────────────────\n\nfunction makeRun(text: string, charPrId: string): string {\n return `<hp:run charPrIDRef=\"${charPrId}\"><hp:t${text ? `>${escapeXml(text)}</hp:t` : \"/\"}></hp:run>`\n}\n\nfunction makeHyperlinkRun(text: string, url: string, charPrId: string, nextId: () => string): string {\n const subId = nextId()\n const paraId = nextId()\n // HWPX hyperLink control — subList 안에 텍스트 단락 포함\n return [\n `<hp:run charPrIDRef=\"${charPrId}\">`,\n ` <hp:ctrl>`,\n ` <hp:hyperLink url=\"${escapeXml(url)}\" macro=\"\" visitedStyle=\"UNKNOWN\" visitedStyleIDRef=\"4294967295\">`,\n ` <hp:subList id=\"${subId}\" textDirection=\"HORIZONTAL\" lineWrap=\"BREAK\" vertAlign=\"TOP\"`,\n ` linkListIDRef=\"0\" linkListNextIDRef=\"0\" textWidth=\"0\" textHeight=\"0\"`,\n ` hasTextRef=\"0\" hasNumRef=\"0\">`,\n ` <hp:p id=\"${paraId}\" paraPrIDRef=\"0\" styleIDRef=\"0\" pageBreak=\"0\" columnBreak=\"0\" merged=\"0\">`,\n ` <hp:run charPrIDRef=\"${charPrId}\"><hp:t>${escapeXml(text)}</hp:t></hp:run>`,\n ` </hp:p>`,\n ` </hp:subList>`,\n ` </hp:hyperLink>`,\n ` </hp:ctrl>`,\n `</hp:run>`,\n ].join(\"\\n\")\n}\n\nfunction makeRunsFromText(text: string, defaultCharPr: string, nextId?: () => string): string {\n // <br> → HWPX 줄바꿈(hp:lf)으로 분할 처리\n if (/<br\\s*\\/?>/i.test(text)) {\n const parts = text.split(/<br\\s*\\/?>/i)\n return parts.map((part, i) => {\n const seg = makeRunsFromText(part, defaultCharPr, nextId)\n return i < parts.length - 1\n ? seg + `<hp:run charPrIDRef=\"${defaultCharPr}\"><hp:lf/></hp:run>`\n : seg\n }).join(\"\")\n }\n const runs = parseInlineRuns(text)\n if (runs.length === 0) return makeRun(\"\", defaultCharPr)\n const isPlain = runs.length === 1 && !runs[0].bold && !runs[0].italic && !runs[0].code && !runs[0].strikethrough && !runs[0].url\n if (isPlain) return makeRun(runs[0].text, defaultCharPr)\n return runs.map(r => {\n if (r.url && nextId) return makeHyperlinkRun(r.text, r.url, CHAR_NORMAL, nextId)\n return makeRun(r.text, charPrForRun(r))\n }).join(\"\")\n}\n\n// linesegarray — 한/글 렌더링 캐시\nfunction makeLineseg(horzsize: number, vertsize: number): string {\n const baseline = Math.round(vertsize * 0.85)\n return ` <hp:linesegarray>\n <hp:lineseg textpos=\"0\" vertpos=\"0\" vertsize=\"${vertsize}\" textheight=\"${vertsize}\" baseline=\"${baseline}\" spacing=\"600\" horzpos=\"0\" horzsize=\"${horzsize}\" flags=\"393216\"/>\n </hp:linesegarray>`\n}\n\n// 셀 단락 lineseg: 줄마다 hp:lineseg 하나씩 필요\n// (하나만 넣으면 한/글이 모든 텍스트를 한 줄로 렌더링 → 겹침 발생)\nconst CHAR_HWP = 1000 // 10pt 한글 1자 너비(HWP 단위)\nconst LINE_HWP = 1400 // 10pt 줄 높이 (폰트+행간)\nconst BASELINE_RATIO = 0.85\n\nfunction estimateCellLineseg(plainText: string, cellHorzsize: number): string {\n const stripped = plainText.replace(/<[^>]*>/g, \"\").replace(/\\s+/g, \" \").trim()\n const charsPerLine = Math.max(1, Math.floor(cellHorzsize / CHAR_HWP))\n const lineCount = Math.max(1, Math.ceil(stripped.length / charsPerLine))\n const baseline = Math.round(LINE_HWP * BASELINE_RATIO)\n const segs = Array.from({ length: lineCount }, (_, i) => {\n const textpos = i * charsPerLine\n const vertpos = i * LINE_HWP\n return ` <hp:lineseg textpos=\"${textpos}\" vertpos=\"${vertpos}\" vertsize=\"${LINE_HWP}\" textheight=\"${LINE_HWP}\" baseline=\"${vertpos + baseline}\" spacing=\"600\" horzpos=\"0\" horzsize=\"${cellHorzsize}\" flags=\"393216\"/>`\n })\n return ` <hp:linesegarray>\\n${segs.join(\"\\n\")}\\n </hp:linesegarray>`\n}\n\nfunction makeParagraph(text: string, charPrId: string, paraPrId: string, nextId: () => string, styleId = \"0\"): string {\n const id = nextId()\n const runs = makeRunsFromText(text, charPrId, nextId)\n return [\n `<hp:p id=\"${id}\" paraPrIDRef=\"${paraPrId}\" styleIDRef=\"${styleId}\" pageBreak=\"0\" columnBreak=\"0\" merged=\"0\">`,\n ` ${runs}`,\n `</hp:p>`,\n ].join(\"\\n\")\n}\n\nfunction makeEmptyParagraph(nextId: () => string): string {\n const id = nextId()\n return [\n `<hp:p id=\"${id}\" paraPrIDRef=\"${PARA_NORMAL}\" styleIDRef=\"0\" pageBreak=\"0\" columnBreak=\"0\" merged=\"0\">`,\n ` <hp:run charPrIDRef=\"${CHAR_NORMAL}\"><hp:t/></hp:run>`,\n `</hp:p>`,\n ].join(\"\\n\")\n}\n\nfunction makeBlockquoteParagraph(text: string, nextId: () => string): string {\n const id = nextId()\n const runs = makeRunsFromText(text, CHAR_ITALIC, nextId)\n return [\n `<hp:p id=\"${id}\" paraPrIDRef=\"${PARA_BLOCKQUOTE}\" styleIDRef=\"0\" pageBreak=\"0\" columnBreak=\"0\" merged=\"0\">`,\n ` ${runs}`,\n `</hp:p>`,\n ].join(\"\\n\")\n}\n\nfunction makeHrParagraph(nextId: () => string): string {\n const id = nextId()\n return [\n `<hp:p id=\"${id}\" paraPrIDRef=\"${PARA_HR}\" styleIDRef=\"0\" pageBreak=\"0\" columnBreak=\"0\" merged=\"0\">`,\n ` <hp:run charPrIDRef=\"${CHAR_NORMAL}\"><hp:t/></hp:run>`,\n `</hp:p>`,\n ].join(\"\\n\")\n}\n\nfunction headingCharPr(level: number): string {\n if (level === 1) return CHAR_H1\n if (level === 2) return CHAR_H2\n if (level === 3) return CHAR_H3\n return CHAR_H456\n}\n\n// ─── 테이블 XML ─────────────────────────────────────────\n\nconst BODY_WIDTH = 42520\nconst ROW_HEIGHT = 2400\n\nfunction countBr(text: string): number {\n return (text.match(/<br\\s*\\/?>/gi) || []).length\n}\n\nfunction makeTableCell(\n text: string,\n colAddr: number,\n rowAddr: number,\n colWidth: number,\n cellHeight: number,\n isHeader: boolean,\n nextId: () => string,\n styleMap?: StyleMap,\n): string {\n let charPr: string\n let borderFill = \"3\"\n\n if (styleMap) {\n const cellStyle = getStyleForBlock(styleMap, isHeader ? \"table_header\" : \"table_cell\")\n charPr = cellStyle.charPr\n borderFill = cellStyle.borderFill || \"3\"\n } else {\n charPr = isHeader ? CHAR_BOLD : CHAR_NORMAL\n }\n\n const subId = nextId()\n // <br>을 별도 <hp:p>로 분리 (hp:lf는 한/글 셀에서 동작하지 않음)\n // 각 단락의 lineseg vertsize: 예상 줄 수 기반으로 계산 (자동줄바꿈 포함)\n const cellHorzsize = Math.max(1000, colWidth - 2000)\n const segments = text.split(/<br\\s*\\/?>/i)\n const cellParas = segments.map(seg => {\n const pid = nextId()\n return [\n ` <hp:p id=\"${pid}\" paraPrIDRef=\"0\" styleIDRef=\"0\" pageBreak=\"0\" columnBreak=\"0\" merged=\"0\">`,\n ` ${makeRunsFromText(seg, charPr, nextId)}`,\n estimateCellLineseg(seg, cellHorzsize),\n ` </hp:p>`,\n ].join(\"\\n\")\n }).join(\"\\n\")\n return [\n `<hp:tc name=\"\" header=\"${isHeader ? 1 : 0}\" hasMargin=\"0\" protect=\"0\" editable=\"0\" dirty=\"1\" borderFillIDRef=\"${borderFill}\">`,\n ` <hp:subList id=\"${subId}\" textDirection=\"HORIZONTAL\" lineWrap=\"BREAK\" vertAlign=\"CENTER\"`,\n ` linkListIDRef=\"0\" linkListNextIDRef=\"0\" textWidth=\"0\" textHeight=\"0\"`,\n ` hasTextRef=\"0\" hasNumRef=\"0\">`,\n cellParas,\n ` </hp:subList>`,\n ` <hp:cellAddr colAddr=\"${colAddr}\" rowAddr=\"${rowAddr}\"/>`,\n ` <hp:cellSpan colSpan=\"1\" rowSpan=\"1\"/>`,\n ` <hp:cellSz width=\"${colWidth}\" height=\"${cellHeight}\"/>`,\n ` <hp:cellMargin left=\"1000\" right=\"1000\" top=\"500\" bottom=\"500\"/>`,\n `</hp:tc>`,\n ].join(\"\\n\")\n}\n\nfunction makeTable(rows: string[][], nextId: () => string, styleMap?: StyleMap): string {\n if (rows.length === 0) return \"\"\n const colCnt = rows[0].length\n const colWidth = Math.floor(BODY_WIDTH / colCnt)\n const totalWidth = colWidth * colCnt\n\n // 각 행의 높이 = 셀 내 텍스트 줄바꿈(br) + 자동줄바꿈(wrapping) 모두 고려\n const cellHorzsize = Math.max(1000, colWidth - 2000)\n const rowHeights = rows.map(row => {\n const maxTotalLines = Math.max(1, ...row.map(cell => {\n return cell.split(/<br\\s*\\/?>/i).reduce((sum, seg) => {\n const plain = seg.replace(/<[^>]*>/g, \"\").replace(/\\s+/g, \" \").trim()\n const charsPerLine = Math.max(1, Math.floor(cellHorzsize / CHAR_HWP))\n return sum + Math.max(1, Math.ceil(plain.length / charsPerLine))\n }, 0)\n }))\n return maxTotalLines * LINE_HWP + 1000 // 상하 마진 여유\n })\n const totalHeight = rowHeights.reduce((s, h) => s + h, 0)\n\n const trElements = rows.map((row, rowIdx) =>\n `<hp:tr>\\n${row.map((cell, colIdx) => makeTableCell(cell, colIdx, rowIdx, colWidth, rowHeights[rowIdx], rowIdx === 0, nextId, styleMap)).join(\"\\n\")}\\n</hp:tr>`\n ).join(\"\\n\")\n\n const tableId = nextId()\n const paraId = nextId()\n\n return [\n `<hp:p id=\"${paraId}\" paraPrIDRef=\"0\" styleIDRef=\"0\" pageBreak=\"0\" columnBreak=\"0\" merged=\"0\">`,\n `<hp:run charPrIDRef=\"0\">`,\n `<hp:tbl id=\"${tableId}\" zOrder=\"0\" numberingType=\"TABLE\" textWrap=\"TOP_AND_BOTTOM\"`,\n ` textFlow=\"BOTH_SIDES\" lock=\"0\" dropcapstyle=\"None\" pageBreak=\"CELL\"`,\n ` repeatHeader=\"1\" rowCnt=\"${rows.length}\" colCnt=\"${colCnt}\" cellSpacing=\"0\"`,\n ` borderFillIDRef=\"3\" noAdjust=\"0\">`,\n ` <hp:sz width=\"${totalWidth}\" widthRelTo=\"ABSOLUTE\" height=\"${totalHeight}\" heightRelTo=\"ABSOLUTE\" protect=\"0\"/>`,\n ` <hp:pos treatAsChar=\"1\" affectLSpacing=\"0\" flowWithText=\"1\" allowOverlap=\"0\"`,\n ` holdAnchorAndSO=\"0\" vertRelTo=\"PARA\" horzRelTo=\"COLUMN\" vertAlign=\"TOP\"`,\n ` horzAlign=\"LEFT\" vertOffset=\"0\" horzOffset=\"0\"/>`,\n ` <hp:outMargin left=\"0\" right=\"0\" top=\"0\" bottom=\"0\"/>`,\n ` <hp:inMargin left=\"0\" right=\"0\" top=\"0\" bottom=\"0\"/>`,\n trElements,\n `</hp:tbl>`,\n `</hp:run>`,\n makeLineseg(totalWidth, totalHeight),\n `</hp:p>`,\n ].join(\"\\n\")\n}\n\n// ─── 마크다운 파싱 ───────────────────────────────────────\n\nexport interface MdBlock {\n type: \"paragraph\" | \"heading\" | \"table\" | \"list\" | \"empty\" | \"image\" | \"code\" | \"blockquote\" | \"hr\"\n text?: string\n level?: number\n rows?: string[][]\n items?: ListItem[]\n listType?: \"ordered\" | \"unordered\"\n // image\n alt?: string\n src?: string // 파일명 또는 data URI\n // code\n lang?: string\n}\n\ninterface ListItem {\n text: string\n indent: number // 0=최상위, 1=1단계 들여쓰기 등\n}\n\nfunction getIndent(line: string): number {\n let spaces = 0\n for (const ch of line) {\n if (ch === \" \") spaces++\n else if (ch === \"\\t\") spaces += 2\n else break\n }\n return Math.floor(spaces / 2) // 2칸 또는 탭당 indent 1\n}\n\nexport function parseMarkdownToBlocks(md: string): MdBlock[] {\n const lines = md.split(\"\\n\")\n const blocks: MdBlock[] = []\n let i = 0\n\n while (i < lines.length) {\n const line = lines[i]\n const trimmed = line.trim()\n\n if (!trimmed) { blocks.push({ type: \"empty\" }); i++; continue }\n\n // 수평선\n if (/^(-{3,}|\\*{3,}|_{3,})$/.test(trimmed)) {\n blocks.push({ type: \"hr\" })\n i++\n continue\n }\n\n // blockquote\n if (trimmed.startsWith(\">\")) {\n const quoteLines: string[] = []\n while (i < lines.length && lines[i].trim().startsWith(\">\")) {\n quoteLines.push(lines[i].trim().replace(/^>\\s?/, \"\"))\n i++\n }\n blocks.push({ type: \"blockquote\", text: quoteLines.join(\" \") })\n continue\n }\n\n // 헤딩\n const hm = trimmed.match(/^(#{1,6})\\s+(.+)$/)\n if (hm) { blocks.push({ type: \"heading\", text: hm[2].trim(), level: hm[1].length }); i++; continue }\n\n // 이미지 (단독 줄)\n const imgm = trimmed.match(/^!\\[([^\\]]*)\\]\\(([^)]+)\\)$/)\n if (imgm) { blocks.push({ type: \"image\", alt: imgm[1], src: imgm[2] }); i++; continue }\n\n // 테이블\n if (trimmed.startsWith(\"|\")) {\n const tableRows: string[][] = []\n while (i < lines.length && lines[i].trim().startsWith(\"|\")) {\n const row = lines[i].trim()\n if (/^[\\s|:\\-]+$/.test(row)) { i++; continue }\n const cells = row.split(\"|\").slice(1, -1).map(c => c.trim())\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 if (/^\\s*[-*+]\\s/.test(line)) {\n const items: ListItem[] = []\n while (i < lines.length && /^\\s*[-*+]\\s/.test(lines[i])) {\n const indent = getIndent(lines[i])\n const text = lines[i].trim().replace(/^[-*+]\\s+/, \"\")\n items.push({ text, indent })\n i++\n }\n blocks.push({ type: \"list\", listType: \"unordered\", items })\n continue\n }\n\n // 순서 있는 목록 (중첩 지원)\n if (/^\\s*\\d+\\.\\s/.test(line)) {\n const items: ListItem[] = []\n while (i < lines.length && /^\\s*\\d+\\.\\s/.test(lines[i])) {\n const indent = getIndent(lines[i])\n const text = lines[i].trim().replace(/^\\d+\\.\\s+/, \"\")\n items.push({ text, indent })\n i++\n }\n blocks.push({ type: \"list\", listType: \"ordered\", items })\n continue\n }\n\n // 코드 블록\n if (trimmed.startsWith(\"```\")) {\n const lang = trimmed.slice(3).trim()\n i++\n const codeLines: string[] = []\n while (i < lines.length && !lines[i].trim().startsWith(\"```\")) codeLines.push(lines[i++])\n if (i < lines.length) i++\n if (codeLines.length > 0) blocks.push({ type: \"code\", text: codeLines.join(\"\\n\"), lang })\n continue\n }\n\n // 일반 단락 (인접한 여러 줄 하나로 합치기)\n const paraLines: string[] = []\n while (i < lines.length && lines[i].trim()\n && !lines[i].trim().startsWith(\"#\")\n && !lines[i].trim().startsWith(\"|\")\n && !lines[i].trim().startsWith(\">\")\n && !/^\\s*[-*+]\\s/.test(lines[i])\n && !/^\\s*\\d+\\.\\s/.test(lines[i])\n && !lines[i].trim().startsWith(\"```\")\n && !lines[i].trim().match(/^!\\[[^\\]]*\\]\\([^)]+\\)$/)\n && !/^(-{3,}|\\*{3,}|_{3,})$/.test(lines[i].trim())\n ) paraLines.push(lines[i++].trim())\n if (paraLines.length > 0) blocks.push({ type: \"paragraph\", text: paraLines.join(\" \") })\n }\n\n return blocks\n}\n\n// ─── 이미지 크기 계산 ──────────────────────────────────\n\nfunction getImageDimensions(data: Uint8Array): { width: number; height: number } | null {\n // PNG: \\x89PNG 시그니처, IHDR에 width/height (offset 16, 20)\n if (data[0] === 0x89 && data[1] === 0x50 && data[2] === 0x4E && data[3] === 0x47) {\n if (data.length < 24) return null\n const w = (data[16] << 24 | data[17] << 16 | data[18] << 8 | data[19]) >>> 0\n const h = (data[20] << 24 | data[21] << 16 | data[22] << 8 | data[23]) >>> 0\n return w > 0 && h > 0 ? { width: w, height: h } : null\n }\n // JPEG: FF D8 — SOF0/SOF1/SOF2 마커 스캔\n if (data[0] === 0xFF && data[1] === 0xD8) {\n let i = 2\n while (i < data.length - 8) {\n if (data[i] !== 0xFF) break\n const marker = data[i + 1]\n if (marker >= 0xC0 && marker <= 0xC3) {\n const h = (data[i + 5] << 8) | data[i + 6]\n const w = (data[i + 7] << 8) | data[i + 8]\n return w > 0 && h > 0 ? { width: w, height: h } : null\n }\n // 길이 없는 단독 마커 (SOI=D8, EOI=D9, RST0~7=D0~D7, TEM=01)\n if (marker === 0xD9 || marker === 0x01 || (marker >= 0xD0 && marker <= 0xD7)) {\n i += 2\n continue\n }\n const segLen = (data[i + 2] << 8) | data[i + 3]\n if (segLen < 2) break // 손상된 파일 방어\n i += 2 + segLen\n }\n }\n return null\n}\n\n// 96 DPI 기준 자연 크기로 HWPUNIT 계산 (1인치 = 7200 HWP units)\n// 10cm(28346 HWP)보다 큰 경우에만 축소, 작은 이미지는 뻥튀기하지 않음\nfunction calcHwpSize(width: number, height: number): { widthHwp: number; heightHwp: number } {\n if (width <= 0 || height <= 0) return { widthHwp: 28346, heightHwp: 19843 }\n const HWP_PER_PIXEL = 7200 / 96 // 96 DPI 기준 픽셀당 HWP units = 75\n const naturalW = Math.round(width * HWP_PER_PIXEL)\n const naturalH = Math.round(height * HWP_PER_PIXEL)\n const maxWidthHwp = 28346 // 10cm\n if (naturalW <= maxWidthHwp) {\n return { widthHwp: naturalW, heightHwp: naturalH }\n }\n // 최대 10cm로 비율 유지 축소\n const ratio = height / width\n return { widthHwp: maxWidthHwp, heightHwp: Math.round(maxWidthHwp * ratio) }\n}\n\n// ─── 이미지 단락 XML ─────────────────────────────────────\n\ninterface BinDataEntry {\n ref: string // binaryItemIDRef 값 (확장자 없는 파일명, e.g. \"image_001\")\n zipPath: string // ZIP 내 경로 (e.g. \"BinData/image_001.png\")\n data?: Uint8Array // 이미지 바이너리 데이터\n dims?: { width: number; height: number } // 원본 픽셀 크기\n}\n\nfunction mimeToFormat(mimeType: string): string {\n if (mimeType.includes(\"jpeg\") || mimeType.includes(\"jpg\")) return \"JPG\"\n if (mimeType.includes(\"gif\")) return \"GIF\"\n if (mimeType.includes(\"bmp\")) return \"BMP\"\n return \"PNG\"\n}\n\nfunction makeImageParagraph(\n ref: string, // binaryItemIDRef (확장자 없는 파일명, e.g. \"image_001\")\n nextId: () => string,\n widthHwp = 28346, // 표시 너비 (HWP units)\n heightHwp = 19843, // 표시 높이 (HWP units)\n naturalWidth?: number, // 원본 픽셀너비 × 75 (imgClip/imgDim용)\n naturalHeight?: number, // 원본 픽셀높이 × 75\n): string {\n const paraId = nextId()\n const picId = nextId()\n const natW = naturalWidth || widthHwp\n const natH = naturalHeight || heightHwp\n const cx = Math.round(widthHwp / 2)\n const cy = Math.round(heightHwp / 2)\n const imgLineseg = [\n ` <hp:linesegarray>`,\n ` <hp:lineseg textpos=\"0\" vertpos=\"0\" vertsize=\"${heightHwp}\" textheight=\"${heightHwp}\"`,\n ` baseline=\"${Math.round(heightHwp * 0.85)}\" spacing=\"600\"`,\n ` horzpos=\"0\" horzsize=\"42520\" flags=\"393216\"/>`,\n ` </hp:linesegarray>`,\n ].join(\"\\n\")\n const pic = [\n ` <hp:pic id=\"${picId}\" zOrder=\"0\" numberingType=\"NONE\" textWrap=\"SQUARE\" textFlow=\"BOTH_SIDES\"`,\n ` lock=\"0\" dropcapstyle=\"None\" href=\"\" groupLevel=\"0\" instid=\"0\" reverse=\"0\">`,\n ` <hp:offset x=\"0\" y=\"0\"/>`,\n ` <hp:orgSz width=\"${widthHwp}\" height=\"${heightHwp}\"/>`,\n ` <hp:curSz width=\"${widthHwp}\" height=\"${heightHwp}\"/>`,\n ` <hp:flip horizontal=\"0\" vertical=\"0\"/>`,\n ` <hp:rotationInfo angle=\"0\" centerX=\"${cx}\" centerY=\"${cy}\" rotateimage=\"1\"/>`,\n ` <hp:renderingInfo>`,\n ` <hc:transMatrix e1=\"1\" e2=\"0\" e3=\"0\" e4=\"0\" e5=\"1\" e6=\"0\"/>`,\n ` <hc:scaMatrix e1=\"1\" e2=\"0\" e3=\"0\" e4=\"0\" e5=\"1\" e6=\"0\"/>`,\n ` <hc:rotMatrix e1=\"1\" e2=\"0\" e3=\"0\" e4=\"0\" e5=\"1\" e6=\"0\"/>`,\n ` </hp:renderingInfo>`,\n ` <hc:img binaryItemIDRef=\"${ref}\" bright=\"0\" contrast=\"0\" effect=\"REAL_PIC\" alpha=\"0\"/>`,\n ` <hp:imgRect>`,\n ` <hc:pt0 x=\"0\" y=\"0\"/>`,\n ` <hc:pt1 x=\"${widthHwp}\" y=\"0\"/>`,\n ` <hc:pt2 x=\"${widthHwp}\" y=\"${heightHwp}\"/>`,\n ` <hc:pt3 x=\"0\" y=\"${heightHwp}\"/>`,\n ` </hp:imgRect>`,\n ` <hp:imgClip left=\"0\" right=\"${natW}\" top=\"0\" bottom=\"${natH}\"/>`,\n ` <hp:inMargin left=\"0\" right=\"0\" top=\"0\" bottom=\"0\"/>`,\n ` <hp:imgDim dimwidth=\"${natW}\" dimheight=\"${natH}\"/>`,\n ` <hp:effects/>`,\n ` <hp:sz width=\"${widthHwp}\" widthRelTo=\"ABSOLUTE\" height=\"${heightHwp}\" heightRelTo=\"ABSOLUTE\" protect=\"0\"/>`,\n ` <hp:pos treatAsChar=\"1\" affectLSpacing=\"0\" flowWithText=\"1\" allowOverlap=\"0\"`,\n ` holdAnchorAndSO=\"0\" vertRelTo=\"PARA\" horzRelTo=\"PARA\"`,\n ` vertAlign=\"TOP\" horzAlign=\"LEFT\" vertOffset=\"0\" horzOffset=\"0\"/>`,\n ` <hp:outMargin left=\"0\" right=\"0\" top=\"0\" bottom=\"0\"/>`,\n ` </hp:pic>`,\n ].join(\"\\n\")\n return [\n `<hp:p id=\"${paraId}\" paraPrIDRef=\"0\" styleIDRef=\"0\" pageBreak=\"0\" columnBreak=\"0\" merged=\"0\">`,\n ` <hp:run charPrIDRef=\"0\">`,\n pic,\n ` </hp:run>`,\n imgLineseg,\n `</hp:p>`,\n ].join(\"\\n\")\n}\n\n// ─── 코드 블록 단락 ─────────────────────────────────────\n\nfunction makeCodeParagraphs(code: string, nextId: () => string): string {\n // 각 줄을 별도 단락으로 (코드 charPr 사용)\n const lines = code.split(\"\\n\")\n return lines.map(line => {\n const id = nextId()\n const safe = escapeXml(line || \" \")\n return [\n `<hp:p id=\"${id}\" paraPrIDRef=\"0\" styleIDRef=\"0\" pageBreak=\"0\" columnBreak=\"0\" merged=\"0\">`,\n ` <hp:run charPrIDRef=\"${CHAR_CODE}\"><hp:t>${safe}</hp:t></hp:run>`,\n `</hp:p>`,\n ].join(\"\\n\")\n }).join(\"\\n\")\n}\n\n// ─── section0.xml 생성 ──────────────────────────────────\n\nfunction generateSectionXml(\n blocks: MdBlock[],\n styleMap?: StyleMap,\n imageMap?: Map<string, string>, // src → ref (binaryItemIDRef)\n imageDimsMap?: Map<string, { width: number; height: number }>, // ref → 픽셀 크기\n secPrXml?: string, // 템플릿에서 추출한 <hp:secPr>...</hp:secPr>\n colPrXml?: string, // 템플릿에서 추출한 <hp:ctrl>...</hp:ctrl>\n masterPageCnt = 0, // 마스터페이지 수\n): string {\n const nextId = makeIdGen()\n const firstId = nextId()\n\n // 스타일맵이 없으면 기본값 사용\n const defaultCharPr = styleMap ? styleMap.body.charPr : CHAR_NORMAL\n const defaultParaPr = styleMap ? styleMap.body.paraPr : PARA_NORMAL\n\n // secPr: 템플릿 XML 우선, 없으면 기본값\n const secPrContent = secPrXml\n ? secPrXml.replace(/masterPageCnt=\"\\d+\"/, `masterPageCnt=\"${masterPageCnt}\"`)\n : [\n `<hp:secPr id=\"\" textDirection=\"HORIZONTAL\" spaceColumns=\"1134\" tabStop=\"8000\" tabStopVal=\"4000\" tabStopUnit=\"HWPUNIT\" outlineShapeIDRef=\"1\" memoShapeIDRef=\"0\" textVerticalWidthHead=\"0\" masterPageCnt=\"${masterPageCnt}\">`,\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:lineNumberShape restartType=\"0\" countBy=\"0\" distance=\"0\" startNumber=\"0\"/>`,\n ` <hp:pagePr landscape=\"WIDELY\" width=\"59528\" height=\"84186\" gutterType=\"LEFT_ONLY\">`,\n ` <hp:margin header=\"4252\" footer=\"4252\" gutter=\"0\" left=\"8504\" right=\"8504\" top=\"8504\" bottom=\"8504\"/>`,\n ` </hp:pagePr>`,\n ` <hp:footNotePr>`,\n ` <hp:autoNumFormat type=\"DIGIT\" userChar=\"\" prefixChar=\"\" suffixChar=\")\" supscript=\"0\"/>`,\n ` <hp:noteLine length=\"-1\" type=\"SOLID\" width=\"0.12 mm\" color=\"#000000\"/>`,\n ` <hp:noteSpacing betweenNotes=\"283\" belowLine=\"567\" aboveLine=\"850\"/>`,\n ` <hp:numbering type=\"CONTINUOUS\" newNum=\"1\"/>`,\n ` <hp:placement place=\"EACH_COLUMN\" beneathText=\"0\"/>`,\n ` </hp:footNotePr>`,\n ` <hp:endNotePr>`,\n ` <hp:autoNumFormat type=\"DIGIT\" userChar=\"\" prefixChar=\"\" suffixChar=\")\" supscript=\"0\"/>`,\n ` <hp:noteLine length=\"14692344\" type=\"SOLID\" width=\"0.12 mm\" color=\"#000000\"/>`,\n ` <hp:noteSpacing betweenNotes=\"0\" belowLine=\"567\" aboveLine=\"850\"/>`,\n ` <hp:numbering type=\"CONTINUOUS\" newNum=\"1\"/>`,\n ` <hp:placement place=\"END_OF_DOCUMENT\" beneathText=\"0\"/>`,\n ` </hp:endNotePr>`,\n `</hp:secPr>`,\n ].join(\"\\n\")\n\n const colPrContent = colPrXml ||\n `<hp:ctrl>\\n <hp:colPr id=\"\" type=\"NEWSPAPER\" layout=\"LEFT\" colCount=\"1\" sameSz=\"1\" sameGap=\"0\"/>\\n</hp:ctrl>`\n\n const secPrBlock = [\n `<hp:p id=\"${firstId}\" paraPrIDRef=\"0\" styleIDRef=\"0\" pageBreak=\"0\" columnBreak=\"0\" merged=\"0\">`,\n ` <hp:run charPrIDRef=\"0\">`,\n secPrContent,\n colPrContent,\n ` </hp:run>`,\n ` <hp:run charPrIDRef=\"0\"><hp:t/></hp:run>`,\n makeLineseg(42520, 1000),\n `</hp:p>`,\n ].join(\"\\n\")\n\n const bodyParts: string[] = []\n\n // 순서 있는 목록 번호 카운터 (indent 레벨별)\n const orderedCounters = new Map<number, number>()\n\n for (const block of blocks) {\n // 목록이 아니면 카운터 초기화\n if (block.type !== \"list\") orderedCounters.clear()\n\n switch (block.type) {\n case \"heading\": {\n const level = block.level || 1\n let charPrId: string\n let paraPrId: string\n let styleId = \"0\"\n\n if (styleMap) {\n const blockType = level === 1 ? \"h1\" : level === 2 ? \"h2\" : level === 3 ? \"h3\" : \"h4\"\n const style = getStyleForBlock(styleMap, blockType as any)\n charPrId = style.charPr\n paraPrId = style.paraPr || defaultParaPr\n styleId = (style as any).styleId ?? \"0\"\n } else {\n charPrId = headingCharPr(level)\n paraPrId = PARA_NORMAL\n }\n\n bodyParts.push(makeParagraph(block.text || \"\", charPrId, paraPrId, nextId, styleId))\n break\n }\n case \"paragraph\": {\n if (block.text) {\n const charPrId = styleMap ? styleMap.body.charPr : CHAR_NORMAL\n const paraPrId = styleMap ? styleMap.body.paraPr : PARA_NORMAL\n const styleId = styleMap ? (styleMap.body as any).styleId ?? \"0\" : \"0\"\n bodyParts.push(makeParagraph(block.text, charPrId, paraPrId, nextId, styleId))\n } else {\n bodyParts.push(makeEmptyParagraph(nextId))\n }\n break\n }\n case \"code\": {\n bodyParts.push(makeCodeParagraphs(block.text || \"\", nextId))\n break\n }\n case \"blockquote\":\n if (block.text) bodyParts.push(makeBlockquoteParagraph(block.text, nextId))\n break\n case \"hr\":\n bodyParts.push(makeHrParagraph(nextId))\n break\n case \"empty\":\n bodyParts.push(makeEmptyParagraph(nextId))\n break\n case \"list\": {\n const charPrId = styleMap ? styleMap.body.charPr : CHAR_NORMAL\n const paraPrId = styleMap ? styleMap.body.paraPr : PARA_NORMAL\n const items = block.items || []\n\n if (block.listType === \"ordered\") {\n for (const item of items) {\n const cnt = (orderedCounters.get(item.indent) || 0) + 1\n orderedCounters.set(item.indent, cnt)\n // 하위 레벨 카운터 초기화\n for (const [k] of orderedCounters) {\n if (k > item.indent) orderedCounters.set(k, 0)\n }\n const indent = \" \".repeat(item.indent)\n bodyParts.push(makeParagraph(`${indent}${cnt}. ${item.text}`, charPrId, paraPrId, nextId))\n }\n } else {\n for (const item of items) {\n const bullets = [\"•\", \"◦\", \"▪\"]\n const bullet = bullets[Math.min(item.indent, bullets.length - 1)]\n const indent = \" \".repeat(item.indent)\n bodyParts.push(makeParagraph(`${indent}${bullet} ${item.text}`, charPrId, paraPrId, nextId))\n }\n }\n break\n }\n case \"table\":\n if (block.rows?.length) bodyParts.push(makeTable(block.rows, nextId, styleMap))\n break\n case \"image\": {\n const src = block.src || \"\"\n // WMF/EMF는 원본 좌표 없이 재배치 불가 → 삽입 시 텍스트 겹침 발생하므로 스킵\n const srcBasename = src.includes(\"/\") || src.includes(\"\\\\\") ? src.split(/[\\\\/]/).pop()! : src\n const extLower = srcBasename.toLowerCase()\n if (extLower.endsWith(\".wmf\") || extLower.endsWith(\".emf\")) break\n const ref = imageMap?.get(src) ?? imageMap?.get(srcBasename)\n if (ref !== undefined) {\n const dims = imageDimsMap?.get(ref)\n const { widthHwp, heightHwp } = dims\n ? calcHwpSize(dims.width, dims.height)\n : { widthHwp: 28346, heightHwp: 19843 }\n const natW = dims ? Math.round(dims.width * 75) : widthHwp\n const natH = dims ? Math.round(dims.height * 75) : heightHwp\n bodyParts.push(makeImageParagraph(ref, nextId, widthHwp, heightHwp, natW, natH))\n } else {\n const alt = block.alt || src || \"(이미지)\"\n bodyParts.push(makeParagraph(`[이미지: ${alt}]`, CHAR_NORMAL, PARA_NORMAL, nextId))\n }\n break\n }\n }\n }\n\n return [\n `<?xml version=\"1.0\" encoding=\"UTF-8\"?>`,\n `<hs:sec ${SEC_NS}>`,\n secPrBlock,\n ...bodyParts,\n `</hs:sec>`,\n ].join(\"\\n\")\n}\n\n// ─── 공개 API ────────────────────────────────────────────\n\nexport interface MarkdownToHwpxOptions {\n templateArrayBuffer?: ArrayBuffer // 사용자 제공 HWPX 템플릿\n warnings?: string[] // 경고 메시지 수집\n images?: ExtractedImage[] // 포함할 이미지 파일 (filename, data, mimeType)\n}\n\n/**\n * 마크다운 텍스트를 HWPX (ArrayBuffer)로 변환.\n * @param markdown 마크다운 텍스트\n * @param options 템플릿, 경고 수집 등\n */\nexport async function markdownToHwpx(\n markdown: string,\n options?: MarkdownToHwpxOptions | ArrayBuffer\n): Promise<ArrayBuffer> {\n // 하위 호환성: 두 번째 인자가 ArrayBuffer이면 templateArrayBuffer로 처리\n let opts: MarkdownToHwpxOptions = {}\n if (options instanceof ArrayBuffer) {\n opts.templateArrayBuffer = options\n } else if (options) {\n opts = options\n }\n\n const warnings = opts.warnings || []\n let styleMap: StyleMap | null = null\n let headerXml = HEADER_XML\n let secPrXml: string | undefined\n let colPrXml: string | undefined\n let masterpages: Array<{ filename: string; content: string }> = []\n\n // 템플릿 처리\n if (opts.templateArrayBuffer) {\n try {\n const templateStyles = await extractTemplateStyles(opts.templateArrayBuffer)\n styleMap = createStyleMap(templateStyles, warnings)\n if (templateStyles.headerXml) headerXml = templateStyles.headerXml\n if (templateStyles.secPrXml) secPrXml = templateStyles.secPrXml\n if (templateStyles.colPrXml) colPrXml = templateStyles.colPrXml\n if (templateStyles.masterpages?.length) masterpages = templateStyles.masterpages\n } catch (err) {\n const msg = err instanceof Error ? err.message : \"알 수 없는 오류\"\n warnings.push(`[warn] 템플릿 처리 실패: ${msg}. 기본 스타일 사용`)\n }\n }\n\n // 이미지 처리: filename → ref(binaryItemIDRef) 매핑 (중복제거 없이 파일명 기반)\n const imageMap = new Map<string, string>() // src filename → ref\n const imageDimsMap = new Map<string, { width: number; height: number }>() // ref → 픽셀 크기\n const binDataEntries: BinDataEntry[] = []\n const usedRefs = new Set<string>() // ref 이름 충돌 방지용\n\n if (opts.images && opts.images.length > 0) {\n for (const img of opts.images) {\n const nameWithoutExt = img.filename.replace(/\\.[^.]+$/, \"\")\n const format = mimeToFormat(img.mimeType)\n const ext = format.toLowerCase() === \"jpg\" ? \"jpg\" : format.toLowerCase()\n // ref 충돌 방지: 같은 이름이 이미 있으면 카운터 추가\n let ref = nameWithoutExt\n let counter = 1\n while (usedRefs.has(ref)) ref = `${nameWithoutExt}_${counter++}`\n usedRefs.add(ref)\n const dims = getImageDimensions(img.data) || undefined\n binDataEntries.push({ ref, zipPath: `BinData/${ref}.${ext}`, data: img.data, dims })\n if (dims) imageDimsMap.set(ref, dims)\n imageMap.set(img.filename, ref)\n }\n }\n\n // data URI 이미지 처리\n const allBlocks = parseMarkdownToBlocks(markdown)\n for (const block of allBlocks) {\n if (block.type === \"image\" && block.src?.startsWith(\"data:\") && !imageMap.has(block.src)) {\n const commaIdx = block.src.indexOf(\",\")\n if (commaIdx === -1) continue\n const header = block.src.slice(0, commaIdx)\n const b64 = block.src.slice(commaIdx + 1)\n const mimeMatch = header.match(/data:([^;]+)/)\n const mimeType = mimeMatch?.[1] || \"image/png\"\n const format = mimeToFormat(mimeType)\n const ext = format.toLowerCase() === \"jpg\" ? \"jpg\" : format.toLowerCase()\n const data = Buffer.from(b64, \"base64\") as unknown as Uint8Array\n const ref = `datauri_${binDataEntries.length + 1}`\n const dims = getImageDimensions(data) || undefined\n imageMap.set(block.src, ref)\n binDataEntries.push({ ref, zipPath: `BinData/${ref}.${ext}`, data, dims })\n if (dims) imageDimsMap.set(ref, dims)\n }\n }\n\n const sectionXml = generateSectionXml(\n allBlocks,\n styleMap || undefined,\n imageMap.size > 0 ? imageMap : undefined,\n imageDimsMap.size > 0 ? imageDimsMap : undefined,\n secPrXml,\n colPrXml,\n masterpages.length,\n )\n\n // content.hpf manifest에 이미지 항목 동적 추가\n // id = binaryItemIDRef 값, href = ZIP 내 경로\n const formatToMediaType = (zipPath: string): string => {\n const ext = zipPath.split(\".\").pop()?.toLowerCase() || \"\"\n if (ext === \"png\") return \"image/png\"\n if (ext === \"gif\") return \"image/gif\"\n if (ext === \"bmp\") return \"image/bmp\"\n return \"image/jpg\" // jpg/jpeg 모두 image/jpg (원본 HWPX 형식)\n }\n // content.hpf 동적 생성: 이미지 + 마스터페이지 항목 주입\n const imageItems = binDataEntries\n .map(e => ` <opf:item id=\"${e.ref}\" href=\"${e.zipPath}\" media-type=\"${formatToMediaType(e.zipPath)}\" isEmbeded=\"1\"/>`)\n .join(\"\\n\")\n const masterpageItems = masterpages\n .map(mp => {\n const id = mp.filename.replace(\"Contents/\", \"\").replace(\".xml\", \"\")\n return ` <opf:item id=\"${id}\" href=\"${mp.filename}\" media-type=\"application/xml\"/>`\n })\n .join(\"\\n\")\n const extraItems = [imageItems, masterpageItems].filter(Boolean).join(\"\\n\")\n const contentHpf = CONTENT_HPF.replace(\n ` <opf:item id=\"header\"`,\n extraItems ? `${extraItems}\\n <opf:item id=\"header\"` : ` <opf:item id=\"header\"`,\n )\n\n const zip = new JSZip()\n\n zip.file(\"mimetype\", \"application/hwp+zip\", { compression: \"STORE\" })\n zip.file(\"META-INF/container.xml\", CONTAINER_XML)\n zip.file(\"META-INF/container.rdf\", CONTAINER_RDF)\n zip.file(\"META-INF/manifest.xml\", MANIFEST_XML)\n zip.file(\"version.xml\", VERSION_XML)\n zip.file(\"settings.xml\", SETTINGS_XML)\n zip.file(\"Preview/PrvText.txt\", \"\")\n zip.file(\"Contents/content.hpf\", contentHpf)\n zip.file(\"Contents/header.xml\", headerXml)\n zip.file(\"Contents/section0.xml\", sectionXml)\n\n // 마스터페이지 파일 추가\n for (const mp of masterpages) {\n zip.file(mp.filename, mp.content)\n }\n\n // 중복 제거된 이미지 + data URI 이미지를 BinData/ 폴더에 추가\n for (const entry of binDataEntries) {\n if (entry.data) {\n zip.file(entry.zipPath, entry.data)\n }\n }\n\n return await zip.generateAsync({ type: \"arraybuffer\" })\n}\n","// 자동 생성 — hwpxskill 베이스 템플릿 임베드\n// generator.ts 에서 import 해서 사용\n\nexport const HEADER_XML = `<?xml version='1.0' encoding='UTF-8'?>\n<hh:head xmlns:ha=\"http://www.hancom.co.kr/hwpml/2011/app\" xmlns:hp=\"http://www.hancom.co.kr/hwpml/2011/paragraph\" xmlns:hp10=\"http://www.hancom.co.kr/hwpml/2016/paragraph\" xmlns:hs=\"http://www.hancom.co.kr/hwpml/2011/section\" xmlns:hc=\"http://www.hancom.co.kr/hwpml/2011/core\" xmlns:hh=\"http://www.hancom.co.kr/hwpml/2011/head\" xmlns:hhs=\"http://www.hancom.co.kr/hwpml/2011/history\" xmlns:hm=\"http://www.hancom.co.kr/hwpml/2011/master-page\" xmlns:hpf=\"http://www.hancom.co.kr/schema/2011/hpf\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:opf=\"http://www.idpf.org/2007/opf/\" xmlns:ooxmlchart=\"http://www.hancom.co.kr/hwpml/2016/ooxmlchart\" xmlns:hwpunitchar=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\" xmlns:epub=\"http://www.idpf.org/2007/ops\" xmlns:config=\"urn:oasis:names:tc:opendocument:xmlns:config:1.0\" version=\"1.5\" secCnt=\"1\">\n <hh:beginNum page=\"1\" footnote=\"1\" endnote=\"1\" pic=\"1\" tbl=\"1\" equation=\"1\"/>\n <hh:refList>\n <hh:fontfaces itemCnt=\"7\">\n <hh:fontface lang=\"HANGUL\" fontCnt=\"2\">\n <hh:font id=\"0\" face=\"함초롬돋움\" type=\"TTF\" isEmbedded=\"0\">\n <hh:typeInfo familyType=\"FCAT_GOTHIC\" weight=\"6\" proportion=\"4\" contrast=\"0\" strokeVariation=\"1\" armStyle=\"1\" letterform=\"1\" midline=\"1\" xHeight=\"1\"/>\n </hh:font>\n <hh:font id=\"1\" face=\"함초롬바탕\" type=\"TTF\" isEmbedded=\"0\">\n <hh:typeInfo familyType=\"FCAT_GOTHIC\" weight=\"6\" proportion=\"4\" contrast=\"0\" strokeVariation=\"1\" armStyle=\"1\" letterform=\"1\" midline=\"1\" xHeight=\"1\"/>\n </hh:font>\n </hh:fontface>\n <hh:fontface lang=\"LATIN\" fontCnt=\"2\">\n <hh:font id=\"0\" face=\"함초롬돋움\" type=\"TTF\" isEmbedded=\"0\">\n <hh:typeInfo familyType=\"FCAT_GOTHIC\" weight=\"6\" proportion=\"4\" contrast=\"0\" strokeVariation=\"1\" armStyle=\"1\" letterform=\"1\" midline=\"1\" xHeight=\"1\"/>\n </hh:font>\n <hh:font id=\"1\" face=\"함초롬바탕\" type=\"TTF\" isEmbedded=\"0\">\n <hh:typeInfo familyType=\"FCAT_GOTHIC\" weight=\"6\" proportion=\"4\" contrast=\"0\" strokeVariation=\"1\" armStyle=\"1\" letterform=\"1\" midline=\"1\" xHeight=\"1\"/>\n </hh:font>\n </hh:fontface>\n <hh:fontface lang=\"HANJA\" fontCnt=\"2\">\n <hh:font id=\"0\" face=\"함초롬돋움\" type=\"TTF\" isEmbedded=\"0\">\n <hh:typeInfo familyType=\"FCAT_GOTHIC\" weight=\"6\" proportion=\"4\" contrast=\"0\" strokeVariation=\"1\" armStyle=\"1\" letterform=\"1\" midline=\"1\" xHeight=\"1\"/>\n </hh:font>\n <hh:font id=\"1\" face=\"함초롬바탕\" type=\"TTF\" isEmbedded=\"0\">\n <hh:typeInfo familyType=\"FCAT_GOTHIC\" weight=\"6\" proportion=\"4\" contrast=\"0\" strokeVariation=\"1\" armStyle=\"1\" letterform=\"1\" midline=\"1\" xHeight=\"1\"/>\n </hh:font>\n </hh:fontface>\n <hh:fontface lang=\"JAPANESE\" fontCnt=\"2\">\n <hh:font id=\"0\" face=\"함초롬돋움\" type=\"TTF\" isEmbedded=\"0\">\n <hh:typeInfo familyType=\"FCAT_GOTHIC\" weight=\"6\" proportion=\"4\" contrast=\"0\" strokeVariation=\"1\" armStyle=\"1\" letterform=\"1\" midline=\"1\" xHeight=\"1\"/>\n </hh:font>\n <hh:font id=\"1\" face=\"함초롬바탕\" type=\"TTF\" isEmbedded=\"0\">\n <hh:typeInfo familyType=\"FCAT_GOTHIC\" weight=\"6\" proportion=\"4\" contrast=\"0\" strokeVariation=\"1\" armStyle=\"1\" letterform=\"1\" midline=\"1\" xHeight=\"1\"/>\n </hh:font>\n </hh:fontface>\n <hh:fontface lang=\"OTHER\" fontCnt=\"2\">\n <hh:font id=\"0\" face=\"함초롬돋움\" type=\"TTF\" isEmbedded=\"0\">\n <hh:typeInfo familyType=\"FCAT_GOTHIC\" weight=\"6\" proportion=\"4\" contrast=\"0\" strokeVariation=\"1\" armStyle=\"1\" letterform=\"1\" midline=\"1\" xHeight=\"1\"/>\n </hh:font>\n <hh:font id=\"1\" face=\"함초롬바탕\" type=\"TTF\" isEmbedded=\"0\">\n <hh:typeInfo familyType=\"FCAT_GOTHIC\" weight=\"6\" proportion=\"4\" contrast=\"0\" strokeVariation=\"1\" armStyle=\"1\" letterform=\"1\" midline=\"1\" xHeight=\"1\"/>\n </hh:font>\n </hh:fontface>\n <hh:fontface lang=\"SYMBOL\" fontCnt=\"2\">\n <hh:font id=\"0\" face=\"함초롬돋움\" type=\"TTF\" isEmbedded=\"0\">\n <hh:typeInfo familyType=\"FCAT_GOTHIC\" weight=\"6\" proportion=\"4\" contrast=\"0\" strokeVariation=\"1\" armStyle=\"1\" letterform=\"1\" midline=\"1\" xHeight=\"1\"/>\n </hh:font>\n <hh:font id=\"1\" face=\"함초롬바탕\" type=\"TTF\" isEmbedded=\"0\">\n <hh:typeInfo familyType=\"FCAT_GOTHIC\" weight=\"6\" proportion=\"4\" contrast=\"0\" strokeVariation=\"1\" armStyle=\"1\" letterform=\"1\" midline=\"1\" xHeight=\"1\"/>\n </hh:font>\n </hh:fontface>\n <hh:fontface lang=\"USER\" fontCnt=\"2\">\n <hh:font id=\"0\" face=\"함초롬돋움\" type=\"TTF\" isEmbedded=\"0\">\n <hh:typeInfo familyType=\"FCAT_GOTHIC\" weight=\"6\" proportion=\"4\" contrast=\"0\" strokeVariation=\"1\" armStyle=\"1\" letterform=\"1\" midline=\"1\" xHeight=\"1\"/>\n </hh:font>\n <hh:font id=\"1\" face=\"함초롬바탕\" type=\"TTF\" isEmbedded=\"0\">\n <hh:typeInfo familyType=\"FCAT_GOTHIC\" weight=\"6\" proportion=\"4\" contrast=\"0\" strokeVariation=\"1\" armStyle=\"1\" letterform=\"1\" midline=\"1\" xHeight=\"1\"/>\n </hh:font>\n </hh:fontface>\n </hh:fontfaces>\n <hh:borderFills itemCnt=\"5\">\n <hh:borderFill id=\"1\" 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 <hh:leftBorder type=\"NONE\" width=\"0.1 mm\" color=\"#000000\"/>\n <hh:rightBorder type=\"NONE\" width=\"0.1 mm\" color=\"#000000\"/>\n <hh:topBorder type=\"NONE\" width=\"0.1 mm\" color=\"#000000\"/>\n <hh:bottomBorder type=\"NONE\" width=\"0.1 mm\" color=\"#000000\"/>\n <hh:diagonal type=\"SOLID\" width=\"0.1 mm\" color=\"#000000\"/>\n </hh:borderFill>\n <hh:borderFill id=\"2\" 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 <hh:leftBorder type=\"NONE\" width=\"0.1 mm\" color=\"#000000\"/>\n <hh:rightBorder type=\"NONE\" width=\"0.1 mm\" color=\"#000000\"/>\n <hh:topBorder type=\"NONE\" width=\"0.1 mm\" color=\"#000000\"/>\n <hh:bottomBorder type=\"NONE\" width=\"0.1 mm\" color=\"#000000\"/>\n <hh:diagonal type=\"SOLID\" width=\"0.1 mm\" color=\"#000000\"/>\n <hc:fillBrush>\n <hc:winBrush faceColor=\"none\" hatchColor=\"#999999\" alpha=\"0\"/>\n </hc:fillBrush>\n </hh:borderFill>\n <hh:borderFill id=\"3\" 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 <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=\"SOLID\" width=\"0.1 mm\" color=\"#000000\"/>\n </hh:borderFill>\n <hh:borderFill id=\"4\" 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 <hh:leftBorder type=\"SOLID\" width=\"0.5 mm\" color=\"#AAAAAA\"/>\n <hh:rightBorder type=\"NONE\" width=\"0.1 mm\" color=\"#000000\"/>\n <hh:topBorder type=\"NONE\" width=\"0.1 mm\" color=\"#000000\"/>\n <hh:bottomBorder type=\"NONE\" width=\"0.1 mm\" color=\"#000000\"/>\n <hh:diagonal type=\"SOLID\" width=\"0.1 mm\" color=\"#000000\"/>\n </hh:borderFill>\n <hh:borderFill id=\"5\" 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 <hh:leftBorder type=\"NONE\" width=\"0.1 mm\" color=\"#000000\"/>\n <hh:rightBorder type=\"NONE\" width=\"0.1 mm\" color=\"#000000\"/>\n <hh:topBorder type=\"NONE\" width=\"0.1 mm\" color=\"#000000\"/>\n <hh:bottomBorder type=\"SOLID\" width=\"0.4 mm\" color=\"#888888\"/>\n <hh:diagonal type=\"SOLID\" width=\"0.1 mm\" color=\"#000000\"/>\n </hh:borderFill>\n </hh:borderFills>\n <hh:charProperties itemCnt=\"16\">\n <hh:charPr id=\"0\" height=\"1000\" textColor=\"#000000\" shadeColor=\"none\" useFontSpace=\"0\" useKerning=\"0\" symMark=\"NONE\" borderFillIDRef=\"2\">\n <hh:fontRef hangul=\"1\" latin=\"1\" hanja=\"1\" japanese=\"1\" other=\"1\" symbol=\"1\" user=\"1\"/>\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\"/>\n <hh:underline type=\"NONE\" shape=\"SOLID\" color=\"#000000\"/>\n <hh:strikeout shape=\"NONE\" color=\"#000000\"/>\n <hh:outline type=\"NONE\"/>\n <hh:shadow type=\"NONE\" color=\"#C0C0C0\" offsetX=\"10\" offsetY=\"10\"/>\n </hh:charPr>\n <hh:charPr id=\"1\" height=\"1000\" textColor=\"#000000\" shadeColor=\"none\" useFontSpace=\"0\" useKerning=\"0\" symMark=\"NONE\" borderFillIDRef=\"2\">\n <hh:fontRef hangul=\"0\" latin=\"0\" hanja=\"0\" japanese=\"0\" other=\"0\" symbol=\"0\" user=\"0\"/>\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\"/>\n <hh:underline type=\"NONE\" shape=\"SOLID\" color=\"#000000\"/>\n <hh:strikeout shape=\"NONE\" color=\"#000000\"/>\n <hh:outline type=\"NONE\"/>\n <hh:shadow type=\"NONE\" color=\"#C0C0C0\" offsetX=\"10\" offsetY=\"10\"/>\n </hh:charPr>\n <hh:charPr id=\"2\" height=\"900\" textColor=\"#000000\" shadeColor=\"none\" useFontSpace=\"0\" useKerning=\"0\" symMark=\"NONE\" borderFillIDRef=\"2\">\n <hh:fontRef hangul=\"0\" latin=\"0\" hanja=\"0\" japanese=\"0\" other=\"0\" symbol=\"0\" user=\"0\"/>\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\"/>\n <hh:underline type=\"NONE\" shape=\"SOLID\" color=\"#000000\"/>\n <hh:strikeout shape=\"NONE\" color=\"#000000\"/>\n <hh:outline type=\"NONE\"/>\n <hh:shadow type=\"NONE\" color=\"#C0C0C0\" offsetX=\"10\" offsetY=\"10\"/>\n </hh:charPr>\n <hh:charPr id=\"3\" height=\"900\" textColor=\"#000000\" shadeColor=\"none\" useFontSpace=\"0\" useKerning=\"0\" symMark=\"NONE\" borderFillIDRef=\"2\">\n <hh:fontRef hangul=\"1\" latin=\"1\" hanja=\"1\" japanese=\"1\" other=\"1\" symbol=\"1\" user=\"1\"/>\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\"/>\n <hh:underline type=\"NONE\" shape=\"SOLID\" color=\"#000000\"/>\n <hh:strikeout shape=\"NONE\" color=\"#000000\"/>\n <hh:outline type=\"NONE\"/>\n <hh:shadow type=\"NONE\" color=\"#C0C0C0\" offsetX=\"10\" offsetY=\"10\"/>\n </hh:charPr>\n <hh:charPr id=\"4\" height=\"900\" textColor=\"#000000\" shadeColor=\"none\" useFontSpace=\"0\" useKerning=\"0\" symMark=\"NONE\" borderFillIDRef=\"2\">\n <hh:fontRef hangul=\"0\" latin=\"0\" hanja=\"0\" japanese=\"0\" other=\"0\" symbol=\"0\" user=\"0\"/>\n <hh:ratio hangul=\"100\" latin=\"100\" hanja=\"100\" japanese=\"100\" other=\"100\" symbol=\"100\" user=\"100\"/>\n <hh:spacing hangul=\"-5\" latin=\"-5\" hanja=\"-5\" japanese=\"-5\" other=\"-5\" symbol=\"-5\" user=\"-5\"/>\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\"/>\n <hh:underline type=\"NONE\" shape=\"SOLID\" color=\"#000000\"/>\n <hh:strikeout shape=\"NONE\" color=\"#000000\"/>\n <hh:outline type=\"NONE\"/>\n <hh:shadow type=\"NONE\" color=\"#C0C0C0\" offsetX=\"10\" offsetY=\"10\"/>\n </hh:charPr>\n <hh:charPr id=\"5\" height=\"1600\" textColor=\"#2E74B5\" shadeColor=\"none\" useFontSpace=\"0\" useKerning=\"0\" symMark=\"NONE\" borderFillIDRef=\"2\">\n <hh:fontRef hangul=\"0\" latin=\"0\" hanja=\"0\" japanese=\"0\" other=\"0\" symbol=\"0\" user=\"0\"/>\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\"/>\n <hh:underline type=\"NONE\" shape=\"SOLID\" color=\"#000000\"/>\n <hh:strikeout shape=\"NONE\" color=\"#000000\"/>\n <hh:outline type=\"NONE\"/>\n <hh:shadow type=\"NONE\" color=\"#C0C0C0\" offsetX=\"10\" offsetY=\"10\"/>\n </hh:charPr>\n <hh:charPr id=\"6\" height=\"1100\" textColor=\"#000000\" shadeColor=\"none\" useFontSpace=\"0\" useKerning=\"0\" symMark=\"NONE\" borderFillIDRef=\"2\">\n <hh:fontRef hangul=\"0\" latin=\"0\" hanja=\"0\" japanese=\"0\" other=\"0\" symbol=\"0\" user=\"0\"/>\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\"/>\n <hh:underline type=\"NONE\" shape=\"SOLID\" color=\"#000000\"/>\n <hh:strikeout shape=\"NONE\" color=\"#000000\"/>\n <hh:outline type=\"NONE\"/>\n <hh:shadow type=\"NONE\" color=\"#C0C0C0\" offsetX=\"10\" offsetY=\"10\"/>\n </hh:charPr>\n\n <hh:charPr id=\"7\" height=\"2000\" textColor=\"#000000\" shadeColor=\"none\" useFontSpace=\"0\" useKerning=\"0\" symMark=\"NONE\" borderFillIDRef=\"2\">\n <hh:fontRef hangul=\"1\" latin=\"1\" hanja=\"1\" japanese=\"1\" other=\"1\" symbol=\"1\" user=\"1\"/>\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\"/>\n <hh:bold/>\n <hh:underline type=\"NONE\" shape=\"SOLID\" color=\"#000000\"/>\n <hh:strikeout shape=\"NONE\" color=\"#000000\"/>\n <hh:outline type=\"NONE\"/>\n <hh:shadow type=\"NONE\" color=\"#C0C0C0\" offsetX=\"10\" offsetY=\"10\"/>\n </hh:charPr>\n <hh:charPr id=\"8\" height=\"1400\" textColor=\"#000000\" shadeColor=\"none\" useFontSpace=\"0\" useKerning=\"0\" symMark=\"NONE\" borderFillIDRef=\"2\">\n <hh:fontRef hangul=\"1\" latin=\"1\" hanja=\"1\" japanese=\"1\" other=\"1\" symbol=\"1\" user=\"1\"/>\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\"/>\n <hh:bold/>\n <hh:underline type=\"NONE\" shape=\"SOLID\" color=\"#000000\"/>\n <hh:strikeout shape=\"NONE\" color=\"#000000\"/>\n <hh:outline type=\"NONE\"/>\n <hh:shadow type=\"NONE\" color=\"#C0C0C0\" offsetX=\"10\" offsetY=\"10\"/>\n </hh:charPr>\n <hh:charPr id=\"9\" height=\"1200\" textColor=\"#000000\" shadeColor=\"none\" useFontSpace=\"0\" useKerning=\"0\" symMark=\"NONE\" borderFillIDRef=\"2\">\n <hh:fontRef hangul=\"1\" latin=\"1\" hanja=\"1\" japanese=\"1\" other=\"1\" symbol=\"1\" user=\"1\"/>\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\"/>\n <hh:bold/>\n <hh:underline type=\"NONE\" shape=\"SOLID\" color=\"#000000\"/>\n <hh:strikeout shape=\"NONE\" color=\"#000000\"/>\n <hh:outline type=\"NONE\"/>\n <hh:shadow type=\"NONE\" color=\"#C0C0C0\" offsetX=\"10\" offsetY=\"10\"/>\n </hh:charPr>\n <hh:charPr id=\"10\" height=\"1100\" textColor=\"#000000\" shadeColor=\"none\" useFontSpace=\"0\" useKerning=\"0\" symMark=\"NONE\" borderFillIDRef=\"2\">\n <hh:fontRef hangul=\"1\" latin=\"1\" hanja=\"1\" japanese=\"1\" other=\"1\" symbol=\"1\" user=\"1\"/>\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\"/>\n <hh:bold/>\n <hh:underline type=\"NONE\" shape=\"SOLID\" color=\"#000000\"/>\n <hh:strikeout shape=\"NONE\" color=\"#000000\"/>\n <hh:outline type=\"NONE\"/>\n <hh:shadow type=\"NONE\" color=\"#C0C0C0\" offsetX=\"10\" offsetY=\"10\"/>\n </hh:charPr>\n <hh:charPr id=\"11\" height=\"1000\" textColor=\"#000000\" shadeColor=\"none\" useFontSpace=\"0\" useKerning=\"0\" symMark=\"NONE\" borderFillIDRef=\"2\">\n <hh:fontRef hangul=\"1\" latin=\"1\" hanja=\"1\" japanese=\"1\" other=\"1\" symbol=\"1\" user=\"1\"/>\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\"/>\n <hh:bold/>\n <hh:underline type=\"NONE\" shape=\"SOLID\" color=\"#000000\"/>\n <hh:strikeout shape=\"NONE\" color=\"#000000\"/>\n <hh:outline type=\"NONE\"/>\n <hh:shadow type=\"NONE\" color=\"#C0C0C0\" offsetX=\"10\" offsetY=\"10\"/>\n </hh:charPr>\n <hh:charPr id=\"12\" height=\"1000\" textColor=\"#000000\" shadeColor=\"none\" useFontSpace=\"0\" useKerning=\"0\" symMark=\"NONE\" borderFillIDRef=\"2\">\n <hh:fontRef hangul=\"0\" latin=\"0\" hanja=\"0\" japanese=\"0\" other=\"0\" symbol=\"0\" user=\"0\"/>\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\"/>\n <hh:italic/>\n <hh:underline type=\"NONE\" shape=\"SOLID\" color=\"#000000\"/>\n <hh:strikeout shape=\"NONE\" color=\"#000000\"/>\n <hh:outline type=\"NONE\"/>\n <hh:shadow type=\"NONE\" color=\"#C0C0C0\" offsetX=\"10\" offsetY=\"10\"/>\n </hh:charPr>\n <hh:charPr id=\"13\" height=\"1000\" textColor=\"#000000\" shadeColor=\"none\" useFontSpace=\"0\" useKerning=\"0\" symMark=\"NONE\" borderFillIDRef=\"2\">\n <hh:fontRef hangul=\"1\" latin=\"1\" hanja=\"1\" japanese=\"1\" other=\"1\" symbol=\"1\" user=\"1\"/>\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\"/>\n <hh:bold/>\n <hh:italic/>\n <hh:underline type=\"NONE\" shape=\"SOLID\" color=\"#000000\"/>\n <hh:strikeout shape=\"NONE\" color=\"#000000\"/>\n <hh:outline type=\"NONE\"/>\n <hh:shadow type=\"NONE\" color=\"#C0C0C0\" offsetX=\"10\" offsetY=\"10\"/>\n </hh:charPr>\n <hh:charPr id=\"14\" height=\"900\" textColor=\"#333333\" shadeColor=\"#F0F0F0\" useFontSpace=\"0\" useKerning=\"0\" symMark=\"NONE\" borderFillIDRef=\"2\">\n <hh:fontRef hangul=\"1\" latin=\"1\" hanja=\"1\" japanese=\"1\" other=\"1\" symbol=\"1\" user=\"1\"/>\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\"/>\n <hh:underline type=\"NONE\" shape=\"SOLID\" color=\"#000000\"/>\n <hh:strikeout shape=\"NONE\" color=\"#000000\"/>\n <hh:outline type=\"NONE\"/>\n <hh:shadow type=\"NONE\" color=\"#C0C0C0\" offsetX=\"10\" offsetY=\"10\"/>\n </hh:charPr>\n <hh:charPr id=\"15\" height=\"1000\" textColor=\"#000000\" shadeColor=\"none\" useFontSpace=\"0\" useKerning=\"0\" symMark=\"NONE\" borderFillIDRef=\"2\">\n <hh:fontRef hangul=\"1\" latin=\"1\" hanja=\"1\" japanese=\"1\" other=\"1\" symbol=\"1\" user=\"1\"/>\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\"/>\n <hh:underline type=\"NONE\" shape=\"SOLID\" color=\"#000000\"/>\n <hh:strikeout shape=\"SINGLE\" color=\"#000000\"/>\n <hh:outline type=\"NONE\"/>\n <hh:shadow type=\"NONE\" color=\"#C0C0C0\" offsetX=\"10\" offsetY=\"10\"/>\n </hh:charPr>\n </hh:charProperties>\n <hh:tabProperties itemCnt=\"3\">\n <hh:tabPr id=\"0\" autoTabLeft=\"0\" autoTabRight=\"0\"/>\n <hh:tabPr id=\"1\" autoTabLeft=\"1\" autoTabRight=\"0\"/>\n <hh:tabPr id=\"2\" autoTabLeft=\"0\" autoTabRight=\"1\"/>\n </hh:tabProperties>\n <hh:numberings itemCnt=\"1\">\n <hh:numbering id=\"1\" start=\"0\">\n <hh:paraHead start=\"1\" level=\"1\" align=\"LEFT\" useInstWidth=\"1\" autoIndent=\"1\" widthAdjust=\"0\" textOffsetType=\"PERCENT\" textOffset=\"50\" numFormat=\"DIGIT\" charPrIDRef=\"4294967295\" checkable=\"0\">^1.</hh:paraHead>\n <hh:paraHead start=\"1\" level=\"2\" align=\"LEFT\" useInstWidth=\"1\" autoIndent=\"1\" widthAdjust=\"0\" textOffsetType=\"PERCENT\" textOffset=\"50\" numFormat=\"HANGUL_SYLLABLE\" charPrIDRef=\"4294967295\" checkable=\"0\">^2.</hh:paraHead>\n <hh:paraHead start=\"1\" level=\"3\" align=\"LEFT\" useInstWidth=\"1\" autoIndent=\"1\" widthAdjust=\"0\" textOffsetType=\"PERCENT\" textOffset=\"50\" numFormat=\"DIGIT\" charPrIDRef=\"4294967295\" checkable=\"0\">^3)</hh:paraHead>\n <hh:paraHead start=\"1\" level=\"4\" align=\"LEFT\" useInstWidth=\"1\" autoIndent=\"1\" widthAdjust=\"0\" textOffsetType=\"PERCENT\" textOffset=\"50\" numFormat=\"HANGUL_SYLLABLE\" charPrIDRef=\"4294967295\" checkable=\"0\">^4)</hh:paraHead>\n <hh:paraHead start=\"1\" level=\"5\" align=\"LEFT\" useInstWidth=\"1\" autoIndent=\"1\" widthAdjust=\"0\" textOffsetType=\"PERCENT\" textOffset=\"50\" numFormat=\"DIGIT\" charPrIDRef=\"4294967295\" checkable=\"0\">(^5)</hh:paraHead>\n <hh:paraHead start=\"1\" level=\"6\" align=\"LEFT\" useInstWidth=\"1\" autoIndent=\"1\" widthAdjust=\"0\" textOffsetType=\"PERCENT\" textOffset=\"50\" numFormat=\"HANGUL_SYLLABLE\" charPrIDRef=\"4294967295\" checkable=\"0\">(^6)</hh:paraHead>\n <hh:paraHead start=\"1\" level=\"7\" align=\"LEFT\" useInstWidth=\"1\" autoIndent=\"1\" widthAdjust=\"0\" textOffsetType=\"PERCENT\" textOffset=\"50\" numFormat=\"CIRCLED_DIGIT\" charPrIDRef=\"4294967295\" checkable=\"1\">^7</hh:paraHead>\n <hh:paraHead start=\"1\" level=\"8\" align=\"LEFT\" useInstWidth=\"1\" autoIndent=\"1\" widthAdjust=\"0\" textOffsetType=\"PERCENT\" textOffset=\"50\" numFormat=\"CIRCLED_HANGUL_SYLLABLE\" charPrIDRef=\"4294967295\" checkable=\"1\">^8</hh:paraHead>\n <hh:paraHead start=\"1\" level=\"9\" align=\"LEFT\" useInstWidth=\"1\" autoIndent=\"1\" widthAdjust=\"0\" textOffsetType=\"PERCENT\" textOffset=\"50\" numFormat=\"HANGUL_JAMO\" charPrIDRef=\"4294967295\" checkable=\"0\"/>\n <hh:paraHead start=\"1\" level=\"10\" align=\"LEFT\" useInstWidth=\"1\" autoIndent=\"1\" widthAdjust=\"0\" textOffsetType=\"PERCENT\" textOffset=\"50\" numFormat=\"ROMAN_SMALL\" charPrIDRef=\"4294967295\" checkable=\"1\"/>\n </hh:numbering>\n </hh:numberings>\n <hh:paraProperties itemCnt=\"22\">\n <hh:paraPr id=\"0\" tabPrIDRef=\"0\" condense=\"0\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"JUSTIFY\" vertical=\"BASELINE\"/>\n <hh:heading type=\"NONE\" idRef=\"0\" level=\"0\"/>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"BREAK_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"0\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"0\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"1\" tabPrIDRef=\"0\" condense=\"0\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"JUSTIFY\" vertical=\"BASELINE\"/>\n <hh:heading type=\"NONE\" idRef=\"0\" level=\"0\"/>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"KEEP_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"1500\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"3000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"2\" tabPrIDRef=\"1\" condense=\"20\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"JUSTIFY\" vertical=\"BASELINE\"/>\n <hh:heading type=\"OUTLINE\" idRef=\"0\" level=\"0\"/>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"KEEP_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"1000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"2000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"3\" tabPrIDRef=\"1\" condense=\"20\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"JUSTIFY\" vertical=\"BASELINE\"/>\n <hh:heading type=\"OUTLINE\" idRef=\"0\" level=\"1\"/>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"KEEP_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"2000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"4000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"4\" tabPrIDRef=\"1\" condense=\"20\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"JUSTIFY\" vertical=\"BASELINE\"/>\n <hh:heading type=\"OUTLINE\" idRef=\"0\" level=\"2\"/>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"KEEP_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"3000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"6000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"5\" tabPrIDRef=\"1\" condense=\"20\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"JUSTIFY\" vertical=\"BASELINE\"/>\n <hh:heading type=\"OUTLINE\" idRef=\"0\" level=\"3\"/>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"KEEP_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"4000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"8000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"6\" tabPrIDRef=\"1\" condense=\"20\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"JUSTIFY\" vertical=\"BASELINE\"/>\n <hh:heading type=\"OUTLINE\" idRef=\"0\" level=\"4\"/>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"KEEP_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"5000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"10000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"7\" tabPrIDRef=\"1\" condense=\"20\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"JUSTIFY\" vertical=\"BASELINE\"/>\n <hh:heading type=\"OUTLINE\" idRef=\"0\" level=\"5\"/>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"KEEP_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"6000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"12000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"8\" tabPrIDRef=\"1\" condense=\"20\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"JUSTIFY\" vertical=\"BASELINE\"/>\n <hh:heading type=\"OUTLINE\" idRef=\"0\" level=\"6\"/>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"KEEP_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"7000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"14000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"9\" tabPrIDRef=\"0\" condense=\"0\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"JUSTIFY\" vertical=\"BASELINE\"/>\n <hh:heading type=\"NONE\" idRef=\"0\" level=\"0\"/>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"BREAK_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"0\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"150\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"0\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"150\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"10\" tabPrIDRef=\"0\" condense=\"0\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"JUSTIFY\" vertical=\"BASELINE\"/>\n <hh:heading type=\"NONE\" idRef=\"0\" level=\"0\"/>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"KEEP_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"-1310\" unit=\"HWPUNIT\"/>\n <hc:left value=\"0\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"130\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"-2620\" unit=\"HWPUNIT\"/>\n <hc:left value=\"0\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"130\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"11\" tabPrIDRef=\"0\" condense=\"0\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"LEFT\" vertical=\"BASELINE\"/>\n <hh:heading type=\"NONE\" idRef=\"0\" level=\"0\"/>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"BREAK_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"0\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"130\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"0\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"130\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"12\" tabPrIDRef=\"1\" condense=\"20\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"LEFT\" vertical=\"BASELINE\"/>\n <hh:heading type=\"NONE\" idRef=\"0\" level=\"0\"/>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"BREAK_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"0\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"1200\" unit=\"HWPUNIT\"/>\n <hc:next value=\"300\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"0\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"2400\" unit=\"HWPUNIT\"/>\n <hc:next value=\"600\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"13\" tabPrIDRef=\"2\" condense=\"0\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"LEFT\" vertical=\"BASELINE\"/>\n <hh:heading type=\"NONE\" idRef=\"0\" level=\"0\"/>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"BREAK_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"0\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"700\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"0\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"1400\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"14\" tabPrIDRef=\"2\" condense=\"0\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"LEFT\" vertical=\"BASELINE\"/>\n <hh:heading type=\"NONE\" idRef=\"0\" level=\"0\"/>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"BREAK_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"1100\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"700\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"2200\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"1400\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"15\" tabPrIDRef=\"2\" condense=\"0\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"LEFT\" vertical=\"BASELINE\"/>\n <hh:heading type=\"NONE\" idRef=\"0\" level=\"0\"/>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"BREAK_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"2200\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"700\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"4400\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"1400\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"16\" tabPrIDRef=\"1\" condense=\"0\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"JUSTIFY\" vertical=\"BASELINE\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/paragraph\">\n <hh:heading type=\"OUTLINE\" idRef=\"0\" level=\"8\"/>\n </hp:case>\n <hp:default>\n <hh:heading type=\"NONE\" idRef=\"0\" level=\"0\"/>\n </hp:default>\n </hp:switch>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"KEEP_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"9000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"18000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"17\" tabPrIDRef=\"1\" condense=\"0\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"JUSTIFY\" vertical=\"BASELINE\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/paragraph\">\n <hh:heading type=\"OUTLINE\" idRef=\"0\" level=\"9\"/>\n </hp:case>\n <hp:default>\n <hh:heading type=\"NONE\" idRef=\"0\" level=\"0\"/>\n </hp:default>\n </hp:switch>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"KEEP_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"10000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"20000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"18\" tabPrIDRef=\"1\" condense=\"0\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"JUSTIFY\" vertical=\"BASELINE\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/paragraph\">\n <hh:heading type=\"OUTLINE\" idRef=\"0\" level=\"7\"/>\n </hp:case>\n <hp:default>\n <hh:heading type=\"NONE\" idRef=\"0\" level=\"0\"/>\n </hp:default>\n </hp:switch>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"KEEP_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"8000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"16000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"19\" tabPrIDRef=\"0\" condense=\"0\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"JUSTIFY\" vertical=\"BASELINE\"/>\n <hh:heading type=\"NONE\" idRef=\"0\" level=\"0\"/>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"KEEP_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"0\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"800\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"150\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"0\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"1600\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"150\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"20\" tabPrIDRef=\"0\" condense=\"0\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"JUSTIFY\" vertical=\"BASELINE\"/>\n <hh:heading type=\"NONE\" idRef=\"0\" level=\"0\"/>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"BREAK_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"4252\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"4252\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"4\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"21\" tabPrIDRef=\"0\" condense=\"0\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"JUSTIFY\" vertical=\"BASELINE\"/>\n <hh:heading type=\"NONE\" idRef=\"0\" level=\"0\"/>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"BREAK_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"0\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"0\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"5\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n </hh:paraProperties>\n <hh:styles itemCnt=\"23\">\n <hh:style id=\"0\" type=\"PARA\" name=\"바탕글\" engName=\"Normal\" paraPrIDRef=\"0\" charPrIDRef=\"0\" nextStyleIDRef=\"0\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"1\" type=\"PARA\" name=\"본문\" engName=\"Body\" paraPrIDRef=\"1\" charPrIDRef=\"0\" nextStyleIDRef=\"1\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"2\" type=\"PARA\" name=\"개요 1\" engName=\"Outline 1\" paraPrIDRef=\"2\" charPrIDRef=\"0\" nextStyleIDRef=\"2\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"3\" type=\"PARA\" name=\"개요 2\" engName=\"Outline 2\" paraPrIDRef=\"3\" charPrIDRef=\"0\" nextStyleIDRef=\"3\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"4\" type=\"PARA\" name=\"개요 3\" engName=\"Outline 3\" paraPrIDRef=\"4\" charPrIDRef=\"0\" nextStyleIDRef=\"4\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"5\" type=\"PARA\" name=\"개요 4\" engName=\"Outline 4\" paraPrIDRef=\"5\" charPrIDRef=\"0\" nextStyleIDRef=\"5\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"6\" type=\"PARA\" name=\"개요 5\" engName=\"Outline 5\" paraPrIDRef=\"6\" charPrIDRef=\"0\" nextStyleIDRef=\"6\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"7\" type=\"PARA\" name=\"개요 6\" engName=\"Outline 6\" paraPrIDRef=\"7\" charPrIDRef=\"0\" nextStyleIDRef=\"7\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"8\" type=\"PARA\" name=\"개요 7\" engName=\"Outline 7\" paraPrIDRef=\"8\" charPrIDRef=\"0\" nextStyleIDRef=\"8\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"9\" type=\"PARA\" name=\"개요 8\" engName=\"Outline 8\" paraPrIDRef=\"18\" charPrIDRef=\"0\" nextStyleIDRef=\"9\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"10\" type=\"PARA\" name=\"개요 9\" engName=\"Outline 9\" paraPrIDRef=\"16\" charPrIDRef=\"0\" nextStyleIDRef=\"10\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"11\" type=\"PARA\" name=\"개요 10\" engName=\"Outline 10\" paraPrIDRef=\"17\" charPrIDRef=\"0\" nextStyleIDRef=\"11\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"12\" type=\"CHAR\" name=\"쪽 번호\" engName=\"Page Number\" paraPrIDRef=\"0\" charPrIDRef=\"1\" nextStyleIDRef=\"0\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"13\" type=\"CHAR\" name=\"줄 번호\" engName=\"Line Number\" paraPrIDRef=\"0\" charPrIDRef=\"0\" nextStyleIDRef=\"0\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"14\" type=\"PARA\" name=\"머리말\" engName=\"Header\" paraPrIDRef=\"9\" charPrIDRef=\"2\" nextStyleIDRef=\"14\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"15\" type=\"PARA\" name=\"각주\" engName=\"Footnote\" paraPrIDRef=\"10\" charPrIDRef=\"3\" nextStyleIDRef=\"15\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"16\" type=\"PARA\" name=\"미주\" engName=\"Endnote\" paraPrIDRef=\"10\" charPrIDRef=\"3\" nextStyleIDRef=\"16\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"17\" type=\"PARA\" name=\"메모\" engName=\"Memo\" paraPrIDRef=\"11\" charPrIDRef=\"4\" nextStyleIDRef=\"17\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"18\" type=\"PARA\" name=\"차례 제목\" engName=\"TOC Heading\" paraPrIDRef=\"12\" charPrIDRef=\"5\" nextStyleIDRef=\"18\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"19\" type=\"PARA\" name=\"차례 1\" engName=\"TOC 1\" paraPrIDRef=\"13\" charPrIDRef=\"6\" nextStyleIDRef=\"19\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"20\" type=\"PARA\" name=\"차례 2\" engName=\"TOC 2\" paraPrIDRef=\"14\" charPrIDRef=\"6\" nextStyleIDRef=\"20\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"21\" type=\"PARA\" name=\"차례 3\" engName=\"TOC 3\" paraPrIDRef=\"15\" charPrIDRef=\"6\" nextStyleIDRef=\"21\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"22\" type=\"PARA\" name=\"캡션\" engName=\"Caption\" paraPrIDRef=\"19\" charPrIDRef=\"0\" nextStyleIDRef=\"22\" langID=\"1042\" lockForm=\"0\"/>\n </hh:styles>\n </hh:refList>\n <hh:compatibleDocument targetProgram=\"HWP201X\">\n <hh:layoutCompatibility/>\n </hh:compatibleDocument>\n <hh:docOption>\n <hh:linkinfo path=\"\" pageInherit=\"0\" footnoteInherit=\"0\"/>\n </hh:docOption>\n <hh:metaTag>{\"name\":\"\"}</hh:metaTag>\n <hh:trackchageConfig flags=\"56\"/>\n</hh:head>\n`\n\nexport const CONTENT_HPF = `<?xml version='1.0' encoding='UTF-8'?>\n<opf:package xmlns:ha=\"http://www.hancom.co.kr/hwpml/2011/app\" xmlns:hp=\"http://www.hancom.co.kr/hwpml/2011/paragraph\" xmlns:hp10=\"http://www.hancom.co.kr/hwpml/2016/paragraph\" xmlns:hs=\"http://www.hancom.co.kr/hwpml/2011/section\" xmlns:hc=\"http://www.hancom.co.kr/hwpml/2011/core\" xmlns:hh=\"http://www.hancom.co.kr/hwpml/2011/head\" xmlns:hhs=\"http://www.hancom.co.kr/hwpml/2011/history\" xmlns:hm=\"http://www.hancom.co.kr/hwpml/2011/master-page\" xmlns:hpf=\"http://www.hancom.co.kr/schema/2011/hpf\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:opf=\"http://www.idpf.org/2007/opf/\" xmlns:ooxmlchart=\"http://www.hancom.co.kr/hwpml/2016/ooxmlchart\" xmlns:hwpunitchar=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\" xmlns:epub=\"http://www.idpf.org/2007/ops\" xmlns:config=\"urn:oasis:names:tc:opendocument:xmlns:config:1.0\" version=\"\" unique-identifier=\"\" id=\"\">\n <opf:metadata>\n <opf:title/>\n <opf:language>ko</opf:language>\n <opf:meta name=\"creator\" content=\"text\"/>\n <opf:meta name=\"subject\" content=\"text\"/>\n <opf:meta name=\"description\" content=\"text\"/>\n <opf:meta name=\"lastsaveby\" content=\"text\"/>\n <opf:meta name=\"CreatedDate\" content=\"text\"/>\n <opf:meta name=\"ModifiedDate\" content=\"text\"/>\n <opf:meta name=\"date\" content=\"text\"/>\n <opf:meta name=\"keyword\" content=\"text\"/>\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\"/>\n <opf:item id=\"settings\" href=\"settings.xml\" media-type=\"application/xml\"/>\n </opf:manifest>\n <opf:spine>\n <opf:itemref idref=\"header\" linear=\"yes\"/>\n <opf:itemref idref=\"section0\" linear=\"yes\"/>\n </opf:spine>\n</opf:package>\n`\n\nexport const CONTAINER_XML = `<?xml version='1.0' encoding='UTF-8'?>\n<ocf:container xmlns:ocf=\"urn:oasis:names:tc:opendocument:xmlns:container\" xmlns:hpf=\"http://www.hancom.co.kr/schema/2011/hpf\">\n <ocf:rootfiles>\n <ocf:rootfile full-path=\"Contents/content.hpf\" media-type=\"application/hwpml-package+xml\"/>\n <ocf:rootfile full-path=\"Preview/PrvText.txt\" media-type=\"text/plain\"/>\n <ocf:rootfile full-path=\"META-INF/container.rdf\" media-type=\"application/rdf+xml\"/>\n </ocf:rootfiles>\n</ocf:container>\n`\n\nexport const CONTAINER_RDF = `<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?><rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"><rdf:Description rdf:about=\"\"><ns0:hasPart xmlns:ns0=\"http://www.hancom.co.kr/hwpml/2016/meta/pkg#\" rdf:resource=\"Contents/header.xml\"/></rdf:Description><rdf:Description rdf:about=\"Contents/header.xml\"><rdf:type rdf:resource=\"http://www.hancom.co.kr/hwpml/2016/meta/pkg#HeaderFile\"/></rdf:Description><rdf:Description rdf:about=\"\"><ns0:hasPart xmlns:ns0=\"http://www.hancom.co.kr/hwpml/2016/meta/pkg#\" rdf:resource=\"Contents/section0.xml\"/></rdf:Description><rdf:Description rdf:about=\"Contents/section0.xml\"><rdf:type rdf:resource=\"http://www.hancom.co.kr/hwpml/2016/meta/pkg#SectionFile\"/></rdf:Description><rdf:Description rdf:about=\"\"><rdf:type rdf:resource=\"http://www.hancom.co.kr/hwpml/2016/meta/pkg#Document\"/></rdf:Description></rdf:RDF>`\n\nexport const MANIFEST_XML = `<?xml version='1.0' encoding='UTF-8'?>\n<odf:manifest xmlns:odf=\"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0\"/>\n`\n\nexport const VERSION_XML = `<?xml version='1.0' encoding='UTF-8'?>\n<hv:HCFVersion xmlns:hv=\"http://www.hancom.co.kr/hwpml/2011/version\" tagetApplication=\"WORDPROCESSOR\" major=\"5\" minor=\"1\" micro=\"1\" buildNumber=\"0\" os=\"1\" xmlVersion=\"1.5\" application=\"Hancom Office Hangul\" appVersion=\"13, 0, 0, 1408 WIN32LEWindows_10\"/>\n`\n\nexport const SETTINGS_XML = `<?xml version='1.0' encoding='UTF-8'?>\n<ha:HWPApplicationSetting xmlns:ha=\"http://www.hancom.co.kr/hwpml/2011/app\" xmlns:config=\"urn:oasis:names:tc:opendocument:xmlns:config:1.0\">\n <ha:CaretPosition listIDRef=\"0\" paraIDRef=\"0\" pos=\"16\"/>\n</ha:HWPApplicationSetting>\n`\n\n","/**\n * Template Analyzer — HWPX 템플릿에서 스타일 정보 추출\n * 사용자가 제공한 template.hwpx에서 charPr, paraPr, borderFill 등 추출\n */\n\nimport JSZip from \"jszip\"\nimport { DOMParser } from \"@xmldom/xmldom\"\n\nexport interface CharacterProperty {\n id: string\n height?: number // 글자 크기 (HWPUNIT, 1000 = 10pt)\n fontName?: string // 폰트명\n bold?: boolean\n italic?: boolean\n underline?: boolean\n strikethrough?: boolean\n color?: string // 색상 (#RRGGBB)\n}\n\nexport interface ParagraphProperty {\n id: string\n align?: \"LEFT\" | \"RIGHT\" | \"CENTER\" | \"JUSTIFY\"\n indent?: {\n before?: number // 왼쪽 들여쓰기 (HWPUNIT)\n after?: number // 오른쪽 들여쓰기\n }\n spacing?: {\n before?: number // 위 간격 (HWPUNIT)\n after?: number // 아래 간격\n line?: number // 줄간격\n }\n}\n\nexport interface BorderFill {\n id: string\n type?: \"SOLID\" | \"DOTTED\" | \"DASHED\"\n color?: string // 선 색상\n width?: string // 선 굵기 (예: \"0.12 mm\")\n fillColor?: string // 채우기 색상\n}\n\nexport interface StyleDef {\n id: string\n name: string\n engName: string\n charPrIDRef: string\n paraPrIDRef: string\n}\n\nexport interface TemplateStyle {\n charPr?: Map<string, CharacterProperty>\n paraPr?: Map<string, ParagraphProperty>\n borderFill?: Map<string, BorderFill>\n fontfaces?: Map<string, string> // fontID → fontName\n styles?: Map<string, StyleDef> // 스타일명 → StyleDef\n stylesById?: Map<string, StyleDef> // 스타일 id → StyleDef\n secPrXml?: string // 원본 <hp:secPr>...</hp:secPr> XML\n colPrXml?: string // 원본 <hp:ctrl>...</hp:ctrl> XML (단 설정)\n masterpages?: Array<{ filename: string; content: string }>\n headerXml?: string // 원본 Contents/header.xml 전체\n}\n\n/**\n * HWPX 파일(ZIP)에서 header.xml을 추출하고 스타일 정보를 파싱\n */\nexport async function extractTemplateStyles(templateArrayBuffer: ArrayBuffer): Promise<TemplateStyle> {\n const zip = new JSZip()\n await zip.loadAsync(templateArrayBuffer)\n\n // header.xml 추출\n const headerFile = zip.file(\"Contents/header.xml\")\n if (!headerFile) {\n throw new Error(\"템플릿 파일이 유효하지 않습니다: Contents/header.xml 없음\")\n }\n\n const headerXmlText = await headerFile.async(\"text\")\n const doc = new DOMParser().parseFromString(headerXmlText, \"text/xml\")\n\n // namespace 정의\n const ns = {\n hh: \"http://www.hancom.co.kr/hwpml/2011/head\"\n }\n\n const template: TemplateStyle = {\n charPr: new Map(),\n paraPr: new Map(),\n borderFill: new Map(),\n fontfaces: new Map(),\n styles: new Map(),\n stylesById: new Map(),\n masterpages: [],\n headerXml: headerXmlText,\n }\n\n // ─── 폰트 추출 ─────────────────────────────────────────────────\n const fontfaces = doc.getElementsByTagNameNS(ns.hh, \"fontFamily\")\n for (let i = 0; i < fontfaces.length; i++) {\n const ff = fontfaces.item(i) as any\n const id = ff.getAttribute(\"id\")\n const name = ff.getAttribute(\"name\")\n if (id && name) {\n template.fontfaces!.set(id, name)\n }\n }\n\n // ─── charPr 추출 (문자 속성) ───────────────────────────────────\n const charPrs = doc.getElementsByTagNameNS(ns.hh, \"charPr\")\n for (let i = 0; i < charPrs.length; i++) {\n const cp = charPrs.item(i) as any\n const id = cp.getAttribute(\"id\")\n\n if (!id) continue\n\n const charProp: CharacterProperty = { id }\n\n // 글자 크기 (height는 HWPUNIT, 1000 = 10pt)\n const height = cp.getAttribute(\"height\")\n if (height) charProp.height = parseInt(height)\n\n // 기본 폰트 (fontRef)\n const fontRef = cp.getElementsByTagNameNS(ns.hh, \"fontRef\").item(0) as any\n if (fontRef) {\n charProp.fontName = fontRef.getAttribute(\"name\")\n }\n\n // 스타일\n charProp.bold = cp.getAttribute(\"bold\") === \"1\"\n charProp.italic = cp.getAttribute(\"italic\") === \"1\"\n charProp.underline = cp.getAttribute(\"underline\") === \"1\"\n charProp.strikethrough = cp.getAttribute(\"strikethrough\") === \"1\"\n\n // 색상\n const textColor = cp.getAttribute(\"textColor\")\n if (textColor) charProp.color = textColor\n\n template.charPr!.set(id, charProp)\n }\n\n // ─── paraPr 추출 (단락 속성) ───────────────────────────────────\n const paraPrs = doc.getElementsByTagNameNS(ns.hh, \"paraPr\")\n for (let i = 0; i < paraPrs.length; i++) {\n const pp = paraPrs.item(i) as any\n const id = pp.getAttribute(\"id\")\n\n if (!id) continue\n\n const paraProp: ParagraphProperty = { id }\n\n // 정렬\n const align = pp.getAttribute(\"align\")\n if (align) paraProp.align = align as any\n\n // 들여쓰기\n const indentBefore = pp.getAttribute(\"indentBefore\")\n const indentAfter = pp.getAttribute(\"indentAfter\")\n if (indentBefore || indentAfter) {\n paraProp.indent = {\n before: indentBefore ? parseInt(indentBefore) : 0,\n after: indentAfter ? parseInt(indentAfter) : 0\n }\n }\n\n // 간격\n const spacingBefore = pp.getAttribute(\"spacingBefore\")\n const spacingAfter = pp.getAttribute(\"spacingAfter\")\n const lineSpacing = pp.getAttribute(\"lineSpacing\")\n if (spacingBefore || spacingAfter || lineSpacing) {\n paraProp.spacing = {\n before: spacingBefore ? parseInt(spacingBefore) : 0,\n after: spacingAfter ? parseInt(spacingAfter) : 0,\n line: lineSpacing ? parseInt(lineSpacing) : 0\n }\n }\n\n template.paraPr!.set(id, paraProp)\n }\n\n // ─── borderFill 추출 (테두리/채우기) ─────────────────────────────\n const borderFills = doc.getElementsByTagNameNS(ns.hh, \"borderFill\")\n for (let i = 0; i < borderFills.length; i++) {\n const bf = borderFills.item(i) as any\n const id = bf.getAttribute(\"id\")\n\n if (!id) continue\n\n const borderFillProp: BorderFill = { id }\n\n // 선 종류\n const borderType = bf.getAttribute(\"type\")\n if (borderType) borderFillProp.type = borderType as any\n\n // 선 색상\n const borderColor = bf.getAttribute(\"color\")\n if (borderColor) borderFillProp.color = borderColor\n\n // 선 굵기\n const borderWidth = bf.getAttribute(\"width\")\n if (borderWidth) borderFillProp.width = borderWidth\n\n // 채우기 색상\n const fillColor = bf.getAttribute(\"fillColor\")\n if (fillColor) borderFillProp.fillColor = fillColor\n\n template.borderFill!.set(id, borderFillProp)\n }\n\n // ─── style 추출 (스타일명 → id/charPr/paraPr 매핑) ────────────\n const styleEls = doc.getElementsByTagNameNS(ns.hh, \"style\")\n for (let i = 0; i < styleEls.length; i++) {\n const el = styleEls.item(i) as any\n const id = el.getAttribute(\"id\")\n const name = el.getAttribute(\"name\") || \"\"\n const engName = el.getAttribute(\"engName\") || \"\"\n const charPrIDRef = el.getAttribute(\"charPrIDRef\") || \"0\"\n const paraPrIDRef = el.getAttribute(\"paraPrIDRef\") || \"0\"\n if (!id) continue\n const def: StyleDef = { id, name, engName, charPrIDRef, paraPrIDRef }\n template.styles!.set(name, def)\n template.stylesById!.set(id, def)\n }\n\n // ─── secPr / colPr 추출 (section0.xml에서) ──────────────────\n const section0File = zip.file(\"Contents/section0.xml\")\n if (section0File) {\n const sec0 = await section0File.async(\"text\")\n const secPrMatch = sec0.match(/<hp:secPr[\\s\\S]*?<\\/hp:secPr>/)\n if (secPrMatch) template.secPrXml = secPrMatch[0]\n const colPrMatch = sec0.match(/<hp:ctrl>[\\s\\S]*?<\\/hp:ctrl>/)\n if (colPrMatch) template.colPrXml = colPrMatch[0]\n }\n\n // ─── masterpage 파일 추출 ─────────────────────────────────────\n for (const [path, file] of Object.entries(zip.files)) {\n if (/^Contents\\/masterpage\\d+\\.xml$/.test(path)) {\n const content = await file.async(\"text\")\n template.masterpages!.push({ filename: path, content })\n }\n }\n template.masterpages!.sort((a, b) => a.filename.localeCompare(b.filename))\n\n return template\n}\n\n/**\n * 템플릿 스타일에서 특정 특성을 만족하는 charPr ID 찾기\n * (휴리스틱 기반 자동 감지)\n */\nexport function findCharPrByCharacteristic(\n charPrMap: Map<string, CharacterProperty>,\n characteristic: \"heading1\" | \"heading2\" | \"heading3\" | \"bold\" | \"italic\" | \"normal\"\n): string | null {\n // 크기 범위 (HWPUNIT 기준, 1000 = 10pt)\n const ranges: Record<string, { minHeight: number; maxHeight: number; needBold?: boolean }> = {\n heading1: { minHeight: 1800, maxHeight: 2500, needBold: true },\n heading2: { minHeight: 1200, maxHeight: 1700, needBold: true },\n heading3: { minHeight: 1000, maxHeight: 1199, needBold: true },\n bold: { minHeight: 800, maxHeight: 1100, needBold: true },\n italic: { minHeight: 800, maxHeight: 1100, needBold: false },\n normal: { minHeight: 900, maxHeight: 1100, needBold: false }\n }\n\n const range = ranges[characteristic]\n if (!range) return null\n\n // 가장 잘 맞는 charPr 찾기\n let bestMatch: [string, CharacterProperty] | null = null\n let bestScore = 0\n\n for (const [id, prop] of charPrMap) {\n let score = 0\n\n // 높이 일치도\n if (prop.height) {\n if (prop.height >= range.minHeight && prop.height <= range.maxHeight) {\n score += 50\n } else if (Math.abs(prop.height - (range.minHeight + range.maxHeight) / 2) < 100) {\n score += 20 // 약간 다르지만 가까운 경우\n }\n }\n\n // bold 요구사항\n if (range.needBold !== undefined) {\n if (range.needBold && prop.bold) score += 30\n else if (!range.needBold && !prop.bold) score += 20\n }\n\n // italic 요구사항 (italic의 경우만)\n if (characteristic === \"italic\" && prop.italic) score += 20\n\n if (score > bestScore) {\n bestScore = score\n bestMatch = [id, prop]\n }\n }\n\n return bestMatch ? bestMatch[0] : null\n}\n\n/**\n * 템플릿에서 기본값 charPr ID 찾기 (보통 ID \"0\")\n */\nexport function getDefaultCharPrId(charPrMap: Map<string, CharacterProperty>): string {\n // ID \"0\"을 먼저 확인\n if (charPrMap.has(\"0\")) return \"0\"\n\n // 없으면 첫 번째 항목\n if (charPrMap.size > 0) {\n return charPrMap.keys().next().value\n }\n\n return \"0\" // 폴백\n}\n\n/**\n * 템플릿에서 기본값 paraPr ID 찾기\n */\nexport function getDefaultParaPrId(paraPrMap: Map<string, ParagraphProperty>): string {\n if (paraPrMap.has(\"0\")) return \"0\"\n if (paraPrMap.size > 0) {\n return paraPrMap.keys().next().value\n }\n return \"0\"\n}\n\n/**\n * 템플릿에서 기본값 borderFill ID 찾기\n */\nexport function getDefaultBorderFillId(borderFillMap: Map<string, BorderFill>): string {\n // 보통 ID \"1\" 또는 \"3\"이 기본값\n if (borderFillMap.has(\"1\")) return \"1\"\n if (borderFillMap.has(\"3\")) return \"3\"\n if (borderFillMap.size > 0) {\n return borderFillMap.keys().next().value\n }\n return \"1\"\n}\n","/**\n * Style Matcher — 마크다운 블록을 템플릿 스타일에 매칭\n */\n\nimport type { TemplateStyle, StyleDef } from \"./template-analyzer.js\"\nimport {\n findCharPrByCharacteristic,\n getDefaultCharPrId,\n getDefaultParaPrId,\n getDefaultBorderFillId\n} from \"./template-analyzer.js\"\n\nexport interface StyleEntry {\n charPr: string\n paraPr: string\n styleId: string // styleIDRef 값 (paraPrIDRef보다 우선)\n}\n\nexport interface StyleMap {\n h1: StyleEntry\n h2: StyleEntry\n h3: StyleEntry\n h456: StyleEntry\n body: StyleEntry\n bold: { charPr: string }\n italic: { charPr: string }\n tableCell: StyleEntry & { borderFill: string }\n tableHeader: StyleEntry & { borderFill: string }\n}\n\n/** 스타일명 후보 목록에서 첫 번째 매칭 StyleDef 반환 */\nfunction findStyleByName(\n styles: Map<string, StyleDef>,\n candidates: string[],\n): StyleDef | null {\n // 1순위: 정확히 일치\n for (const cand of candidates) {\n if (styles.has(cand)) return styles.get(cand)!\n }\n // 2순위: 단어 경계 포함 (접두 \"B-\" 뒤에 정확히 일치, 또는 끝에 일치)\n for (const cand of candidates) {\n for (const [name, def] of styles) {\n if (name === `B-${cand}` || name.endsWith(` ${cand}`) || name.endsWith(`-${cand}`)) return def\n }\n }\n // 3순위: 부분 일치 — 이름이 짧은 것 우선 (예: \"B-1.\"이 \"B-1.1 제목\"보다 먼저)\n for (const cand of candidates) {\n let best: [string, StyleDef] | null = null\n for (const [name, def] of styles) {\n if (name.includes(cand)) {\n if (!best || name.length < best[0].length) best = [name, def]\n }\n }\n if (best) return best[1]\n }\n return null\n}\n\n/**\n * 템플릿을 분석하고 자동으로 마크다운 블록과 매칭하는 StyleMap 생성\n * 1순위: 스타일명 직접 매칭 / 2순위: 글자 크기 휴리스틱\n */\nexport function createStyleMap(template: TemplateStyle, warnings: string[] = []): StyleMap {\n const charPrMap = template.charPr || new Map()\n const borderFillMap = template.borderFill || new Map()\n const styles = template.styles || new Map<string, StyleDef>()\n\n const defaultCharPr = getDefaultCharPrId(charPrMap)\n const defaultParaPr = getDefaultParaPrId(template.paraPr || new Map())\n const defaultBorderFill = getDefaultBorderFillId(borderFillMap)\n const defaultStyleId = \"0\"\n\n const toEntry = (def: StyleDef | null, fallbackCharPr: string): StyleEntry => ({\n charPr: def?.charPrIDRef ?? fallbackCharPr,\n paraPr: def?.paraPrIDRef ?? defaultParaPr,\n styleId: def?.id ?? defaultStyleId,\n })\n\n // ── 스타일명 직접 매칭 ──────────────────────────────────────\n const bodyDef =\n findStyleByName(styles, [\"바탕글\", \"Normal\", \"본문\", \"바탕\"]) ||\n findStyleByName(styles, [\"body\", \"normal\"])\n const h1Def =\n findStyleByName(styles, [\"제목1\", \"제목 1\", \"개요 1\", \"개요1\", \"Heading 1\"]) ||\n findStyleByName(styles, [\"장제목\", \"대제목\", \"제목\"])\n const h2Def =\n findStyleByName(styles, [\"제목2\", \"제목 2\", \"개요 2\", \"개요2\", \"Heading 2\"]) ||\n findStyleByName(styles, [\"절제목\", \"1.\", \"1 \"])\n const h3Def =\n findStyleByName(styles, [\"제목3\", \"제목 3\", \"개요 3\", \"개요3\", \"Heading 3\"]) ||\n findStyleByName(styles, [\"1.1\", \"항목\"])\n const tableCellDef =\n findStyleByName(styles, [\"표 내용\", \"표내용\", \"B-표내용\", \"표 내용(일반)\"]) ||\n findStyleByName(styles, [\"표\", \"table\"])\n const tableHeaderDef =\n findStyleByName(styles, [\"표제목\", \"표 제목\", \"B-표제목\", \"표 내용(강조)\"]) ||\n tableCellDef\n\n // ── 휴리스틱 폴백 (charPr 크기 기반) ─────────────────────────\n const bodyCharPr = bodyDef?.charPrIDRef ?? findCharPrByCharacteristic(charPrMap, \"normal\") ?? defaultCharPr\n const h1CharPr = h1Def?.charPrIDRef ?? findCharPrByCharacteristic(charPrMap, \"heading1\") ?? defaultCharPr\n const h2CharPr = h2Def?.charPrIDRef ?? findCharPrByCharacteristic(charPrMap, \"heading2\") ?? defaultCharPr\n const h3CharPr = h3Def?.charPrIDRef ?? findCharPrByCharacteristic(charPrMap, \"heading3\") ?? defaultCharPr\n const boldCharPr = findCharPrByCharacteristic(charPrMap, \"bold\") ?? defaultCharPr\n const italicCharPr = findCharPrByCharacteristic(charPrMap, \"italic\") ?? defaultCharPr\n\n return {\n h1: { charPr: h1CharPr, paraPr: h1Def?.paraPrIDRef ?? defaultParaPr, styleId: h1Def?.id ?? defaultStyleId },\n h2: { charPr: h2CharPr, paraPr: h2Def?.paraPrIDRef ?? defaultParaPr, styleId: h2Def?.id ?? defaultStyleId },\n h3: { charPr: h3CharPr, paraPr: h3Def?.paraPrIDRef ?? defaultParaPr, styleId: h3Def?.id ?? defaultStyleId },\n h456: { charPr: h3CharPr, paraPr: h3Def?.paraPrIDRef ?? defaultParaPr, styleId: h3Def?.id ?? defaultStyleId },\n body: { charPr: bodyCharPr, paraPr: bodyDef?.paraPrIDRef ?? defaultParaPr, styleId: bodyDef?.id ?? defaultStyleId },\n bold: { charPr: boldCharPr },\n italic: { charPr: italicCharPr },\n tableCell: { charPr: tableCellDef?.charPrIDRef ?? bodyCharPr, paraPr: tableCellDef?.paraPrIDRef ?? defaultParaPr, styleId: tableCellDef?.id ?? defaultStyleId, borderFill: defaultBorderFill },\n tableHeader: { charPr: tableHeaderDef?.charPrIDRef ?? bodyCharPr, paraPr: tableHeaderDef?.paraPrIDRef ?? defaultParaPr, styleId: tableHeaderDef?.id ?? defaultStyleId, borderFill: defaultBorderFill },\n }\n}\n\n/**\n * 마크다운 블록 타입으로 스타일 ID 조회\n */\nexport function getStyleForBlock(\n styleMap: StyleMap,\n blockType: \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"body\" | \"table_header\" | \"table_cell\",\n inlineStyle?: \"bold\" | \"italic\"\n): { charPr: string; paraPr?: string; borderFill?: string } {\n let baseStyle: any = styleMap.body\n\n // 헤딩 레벨별\n if (blockType === \"h1\") baseStyle = styleMap.h1\n else if (blockType === \"h2\") baseStyle = styleMap.h2\n else if (blockType === \"h3\") baseStyle = styleMap.h3\n else if (blockType === \"h4\" || blockType === \"h5\" || blockType === \"h6\") baseStyle = styleMap.h456\n else if (blockType === \"table_header\") baseStyle = styleMap.tableHeader\n else if (blockType === \"table_cell\") baseStyle = styleMap.tableCell\n\n // 인라인 스타일 적용\n if (inlineStyle === \"bold\") {\n return {\n charPr: styleMap.bold.charPr,\n paraPr: baseStyle.paraPr\n }\n }\n if (inlineStyle === \"italic\") {\n return {\n charPr: styleMap.italic.charPr,\n paraPr: baseStyle.paraPr\n }\n }\n\n return baseStyle\n}\n\n/**\n * 인라인 텍스트에 대한 charPr ID 결정\n */\nexport function getCharPrForInline(\n styleMap: StyleMap,\n bold?: boolean,\n italic?: boolean\n): string {\n if (bold && italic) return styleMap.bold.charPr // 둘 다이면 bold 우선\n if (bold) return styleMap.bold.charPr\n if (italic) return styleMap.italic.charPr\n return styleMap.body.charPr\n}\n","/**\n * Markdown → XLSX 변환기\n *\n * 지원: 헤딩, 단락, 코드, blockquote, hr, 테이블(별도 시트), 이미지\n */\n\nimport ExcelJS from \"exceljs\"\nimport { parseMarkdownToBlocks } from \"../hwpx/generator.js\"\nimport type { MdBlock } from \"../hwpx/generator.js\"\nimport type { ExtractedImage } from \"../types.js\"\n\n// ─── 공개 타입 ──────────────────────────────────────────\n\nexport interface MarkdownToXlsxOptions {\n warnings?: string[]\n images?: ExtractedImage[]\n}\n\n// ─── 헬퍼 ──────────────────────────────────────────────\n\nfunction mimeToExtension(mimeType: string): \"png\" | \"jpeg\" | \"gif\" {\n if (mimeType.includes(\"jpeg\") || mimeType.includes(\"jpg\")) return \"jpeg\"\n if (mimeType.includes(\"gif\")) return \"gif\"\n return \"png\"\n}\n\nfunction buildImageMap(images?: ExtractedImage[]): Map<string, ExtractedImage> {\n const map = new Map<string, ExtractedImage>()\n if (!images) return map\n for (const img of images) map.set(img.filename, img)\n return map\n}\n\n// ─── 시트 구성 ──────────────────────────────────────────\n\n/** 본문 시트에 비테이블 요소 추가. 이미지는 exceljs addImage로 삽입. */\nasync function fillBodySheet(\n sheet: ExcelJS.Worksheet,\n workbook: ExcelJS.Workbook,\n blocks: MdBlock[],\n imageMap: Map<string, ExtractedImage>,\n): Promise<void> {\n sheet.getColumn(1).width = 80\n\n for (const block of blocks) {\n switch (block.type) {\n case \"heading\": {\n const level = block.level || 1\n const size = level === 1 ? 20 : level === 2 ? 16 : level === 3 ? 14 : 12\n const row = sheet.addRow([block.text || \"\"])\n row.getCell(1).font = { bold: true, size }\n row.getCell(1).alignment = { wrapText: true }\n break\n }\n case \"paragraph\": {\n const row = sheet.addRow([block.text || \"\"])\n row.getCell(1).alignment = { wrapText: true }\n break\n }\n case \"code\": {\n const lines = (block.text || \"\").split(\"\\n\")\n for (const line of lines) {\n const row = sheet.addRow([line || \" \"])\n row.getCell(1).font = { name: \"Courier New\", size: 9 }\n row.getCell(1).fill = {\n type: \"pattern\", pattern: \"solid\",\n fgColor: { argb: \"FFF2F2F2\" },\n }\n }\n break\n }\n case \"blockquote\": {\n const row = sheet.addRow([block.text || \"\"])\n row.getCell(1).font = { italic: true, color: { argb: \"FF888888\" } }\n row.getCell(1).alignment = { wrapText: true }\n break\n }\n case \"hr\": {\n const row = sheet.addRow([\"\"])\n row.getCell(1).border = {\n bottom: { style: \"medium\", color: { argb: \"FF888888\" } },\n }\n break\n }\n case \"empty\": {\n sheet.addRow([\"\"])\n break\n }\n case \"list\": {\n for (const item of block.items || []) {\n const indent = \" \".repeat(item.indent)\n const bullet = block.listType === \"ordered\"\n ? `${item.indent + 1}. `\n : [\"• \", \"◦ \", \"▪ \"][Math.min(item.indent, 2)]\n const row = sheet.addRow([`${indent}${bullet}${item.text}`])\n row.getCell(1).alignment = { wrapText: true }\n }\n break\n }\n case \"image\": {\n const src = block.src || \"\"\n const img = imageMap.get(src)\n if (img) {\n const currentRow = sheet.rowCount + 1\n const ext = mimeToExtension(img.mimeType)\n const imageId = workbook.addImage({ base64: Buffer.from(img.data).toString(\"base64\"), extension: ext })\n sheet.addRow([\"\"]) // 이미지 앵커용 빈 행\n sheet.addImage(imageId, {\n tl: { col: 0, row: currentRow - 1 },\n ext: { width: 300, height: 200 },\n })\n sheet.getRow(currentRow).height = 155 // 200px ≒ 155pt\n } else {\n const alt = block.alt || src || \"(이미지)\"\n const row = sheet.addRow([`[이미지: ${alt}]`])\n row.getCell(1).font = { italic: true, color: { argb: \"FF999999\" } }\n }\n break\n }\n // table은 별도 시트에서 처리\n }\n }\n}\n\n/** 테이블 시트 생성 */\nfunction fillTableSheet(sheet: ExcelJS.Worksheet, rows: string[][]): void {\n for (let rowIdx = 0; rowIdx < rows.length; rowIdx++) {\n const cells = rows[rowIdx]\n const row = sheet.addRow(cells)\n\n // 열 너비 자동 조정\n cells.forEach((cell, colIdx) => {\n const col = sheet.getColumn(colIdx + 1)\n col.width = Math.max(col.width ?? 10, Math.min(cell.length + 4, 40))\n })\n\n if (rowIdx === 0) {\n // 헤더 행\n row.eachCell(cell => {\n cell.font = { bold: true }\n cell.fill = { type: \"pattern\", pattern: \"solid\", fgColor: { argb: \"FFD9E1F2\" } }\n cell.border = {\n top: { style: \"thin\" }, bottom: { style: \"thin\" },\n left: { style: \"thin\" }, right: { style: \"thin\" },\n }\n cell.alignment = { wrapText: true }\n })\n } else {\n row.eachCell(cell => {\n cell.border = {\n top: { style: \"thin\" }, bottom: { style: \"thin\" },\n left: { style: \"thin\" }, right: { style: \"thin\" },\n }\n cell.alignment = { wrapText: true }\n })\n }\n }\n}\n\n// ─── 공개 API ────────────────────────────────────────────\n\n/**\n * 마크다운 텍스트를 XLSX (ArrayBuffer)로 변환.\n * @param markdown 마크다운 텍스트\n * @param options 경고 수집, 이미지 데이터 등\n */\nexport async function markdownToXlsx(\n markdown: string,\n options?: MarkdownToXlsxOptions,\n): Promise<ArrayBuffer> {\n const warnings = options?.warnings || []\n const imageMap = buildImageMap(options?.images)\n const blocks = parseMarkdownToBlocks(markdown)\n\n const workbook = new ExcelJS.Workbook()\n workbook.created = new Date()\n\n // 테이블 블록과 비테이블 블록 분리\n const tableBlocks = blocks.filter(b => b.type === \"table\")\n const bodyBlocks = blocks.filter(b => b.type !== \"table\")\n\n // 본문 시트 (비테이블 요소가 있을 때만 생성)\n const hasBodyContent = bodyBlocks.some(b => b.type !== \"empty\")\n if (hasBodyContent) {\n const bodySheet = workbook.addWorksheet(\"본문\")\n await fillBodySheet(bodySheet, workbook, bodyBlocks, imageMap)\n }\n\n // 테이블 시트\n tableBlocks.forEach((block, idx) => {\n if (!block.rows?.length) return\n const sheet = workbook.addWorksheet(`Table ${idx + 1}`)\n fillTableSheet(sheet, block.rows)\n })\n\n // 시트가 하나도 없으면 빈 본문 시트 추가\n if (workbook.worksheets.length === 0) {\n workbook.addWorksheet(\"본문\")\n warnings.push(\"[warn] 변환할 내용이 없어 빈 시트를 생성했습니다.\")\n }\n\n const buffer = await workbook.xlsx.writeBuffer() as unknown as Buffer\n return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength) as ArrayBuffer\n}\n"],"mappings":"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EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAC7E,CAAC;AAED,IAAM,YAAY,IAAI,WAAW;AAAA,EAC/B;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EA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AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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","names":["s2a","CRC32","CFB","exports","i","parse","q","filename","cfb","file","flen","L","find","_deflateRaw","readFileSync","createTesseractProvider","JSZip","JSZip","MAX_DECOMPRESS_SIZE","cellRows","find","resolveOcrProvider","ocrPages","JSZip","DOMParser","MAX_DECOMPRESS_SIZE","MAX_ROWS","MAX_COLS","DOMParser","JSZip","parsePageRange","JSZip","DOMParser","MAX_DECOMPRESS_SIZE","parseXml","DOMParser","parseRels","runs","text","JSZip","parse","i","j","JSZip","JSZip","DOMParser","JSZip","parse"]}
|
|
1
|
+
{"version":3,"sources":["../src/page-range.ts","../node_modules/cfb/cfb.js","../src/ocr/auto-detect.ts","../src/ocr/cli-provider.ts","../src/ocr/tesseract-provider.ts","../src/ocr/resolve.ts","../src/ocr/markdown-to-blocks.ts","../src/ocr/provider.ts","../src/index.ts","../src/detect.ts","../src/hwpx/parser.ts","../src/utils.ts","../src/table/builder.ts","../src/types.ts","../src/hwp5/record.ts","../src/hwp5/aes.ts","../src/hwp5/crypto.ts","../src/hwp5/cfb-lenient.ts","../src/hwp5/parser.ts","../src/pdf/parser.ts","../src/pdf/line-detector.ts","../src/pdf/cluster-detector.ts","../src/pdf/polyfill.ts","../src/xlsx/parser.ts","../src/docx/parser.ts","../src/diff/text-diff.ts","../src/diff/compare.ts","../src/form/recognize.ts","../src/hwpx/generator.ts","../src/hwpx/template-content.ts","../src/hwpx/template-analyzer.ts","../src/hwpx/style-matcher.ts","../src/xlsx/generator.ts"],"sourcesContent":["/** 페이지/섹션 범위 파싱 유틸리티 */\n\n/**\n * 페이지 범위 지정을 1-based Set<number>로 변환.\n *\n * @param spec - [1,2,3] 또는 \"1-3\" 또는 \"1,3,5-7\"\n * @param maxPages - 최대 페이지 수 (클램핑 상한)\n * @returns 1-based 페이지 번호 Set\n */\nexport function parsePageRange(spec: number[] | string, maxPages: number): Set<number> {\n const result = new Set<number>()\n if (maxPages <= 0) return result\n\n if (Array.isArray(spec)) {\n for (const n of spec) {\n const page = Math.round(n)\n if (page >= 1 && page <= maxPages) result.add(page)\n }\n return result\n }\n\n if (typeof spec !== \"string\" || spec.trim() === \"\") return result\n\n const parts = spec.split(\",\")\n for (const part of parts) {\n const trimmed = part.trim()\n if (!trimmed) continue\n\n const rangeMatch = trimmed.match(/^(\\d+)\\s*-\\s*(\\d+)$/)\n if (rangeMatch) {\n const start = Math.max(1, parseInt(rangeMatch[1], 10))\n const end = Math.min(maxPages, parseInt(rangeMatch[2], 10))\n for (let i = start; i <= end; i++) result.add(i)\n } else {\n const page = parseInt(trimmed, 10)\n if (!isNaN(page) && page >= 1 && page <= maxPages) result.add(page)\n }\n }\n\n return result\n}\n","/* cfb.js (C) 2013-present SheetJS -- http://sheetjs.com */\n/* vim: set ts=2: */\n/*jshint eqnull:true */\n/*exported CFB */\n/*global module, require:false, process:false, Buffer:false, Uint8Array:false, Uint16Array:false */\n\nvar Base64_map = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\";\nfunction Base64_encode(input) {\n\tvar o = \"\";\n\tvar c1 = 0, c2 = 0, c3 = 0, e1 = 0, e2 = 0, e3 = 0, e4 = 0;\n\tfor (var i = 0; i < input.length; ) {\n\t\tc1 = input.charCodeAt(i++);\n\t\te1 = (c1 >> 2);\n\t\tc2 = input.charCodeAt(i++);\n\t\te2 = ((c1 & 3) << 4) | (c2 >> 4);\n\t\tc3 = input.charCodeAt(i++);\n\t\te3 = ((c2 & 15) << 2) | (c3 >> 6);\n\t\te4 = (c3 & 63);\n\t\tif (isNaN(c2)) e3 = e4 = 64;\n\t\telse if (isNaN(c3)) e4 = 64;\n\t\to += Base64_map.charAt(e1) + Base64_map.charAt(e2) + Base64_map.charAt(e3) + Base64_map.charAt(e4);\n\t}\n\treturn o;\n}\nfunction Base64_decode(input) {\n\tvar o = \"\";\n\tvar c1 = 0, c2 = 0, c3 = 0, e1 = 0, e2 = 0, e3 = 0, e4 = 0;\n\tinput = input.replace(/[^\\w\\+\\/\\=]/g, \"\");\n\tfor (var i = 0; i < input.length;) {\n\t\te1 = Base64_map.indexOf(input.charAt(i++));\n\t\te2 = Base64_map.indexOf(input.charAt(i++));\n\t\tc1 = (e1 << 2) | (e2 >> 4);\n\t\to += String.fromCharCode(c1);\n\t\te3 = Base64_map.indexOf(input.charAt(i++));\n\t\tc2 = ((e2 & 15) << 4) | (e3 >> 2);\n\t\tif (e3 !== 64) o += String.fromCharCode(c2);\n\t\te4 = Base64_map.indexOf(input.charAt(i++));\n\t\tc3 = ((e3 & 3) << 6) | e4;\n\t\tif (e4 !== 64) o += String.fromCharCode(c3);\n\t}\n\treturn o;\n}\nvar has_buf = (function() { return typeof Buffer !== 'undefined' && typeof process !== 'undefined' && typeof process.versions !== 'undefined' && !!process.versions.node; })();\n\nvar Buffer_from = (function() {\n\tif(typeof Buffer !== 'undefined') {\n\t\tvar nbfs = !Buffer.from;\n\t\tif(!nbfs) try { Buffer.from(\"foo\", \"utf8\"); } catch(e) { nbfs = true; }\n\t\treturn nbfs ? function(buf, enc) { return (enc) ? new Buffer(buf, enc) : new Buffer(buf); } : Buffer.from.bind(Buffer);\n\t}\n\treturn function() {};\n})();\n\n\nfunction new_raw_buf(len) {\n\t/* jshint -W056 */\n\tif(has_buf) {\n\t\tif(Buffer.alloc) return Buffer.alloc(len);\n\t\tvar b = new Buffer(len); b.fill(0); return b;\n\t}\n\treturn typeof Uint8Array != \"undefined\" ? new Uint8Array(len) : new Array(len);\n\t/* jshint +W056 */\n}\n\nfunction new_unsafe_buf(len) {\n\t/* jshint -W056 */\n\tif(has_buf) return Buffer.allocUnsafe ? Buffer.allocUnsafe(len) : new Buffer(len);\n\treturn typeof Uint8Array != \"undefined\" ? new Uint8Array(len) : new Array(len);\n\t/* jshint +W056 */\n}\n\nvar s2a = function s2a(s) {\n\tif(has_buf) return Buffer_from(s, \"binary\");\n\treturn s.split(\"\").map(function(x){ return x.charCodeAt(0) & 0xff; });\n};\n\nvar chr0 = /\\u0000/g, chr1 = /[\\u0001-\\u0006]/g;\nvar __toBuffer = function(bufs) { var x = []; for(var i = 0; i < bufs[0].length; ++i) { x.push.apply(x, bufs[0][i]); } return x; };\nvar ___toBuffer = __toBuffer;\nvar __utf16le = function(b,s,e) { var ss=[]; for(var i=s; i<e; i+=2) ss.push(String.fromCharCode(__readUInt16LE(b,i))); return ss.join(\"\").replace(chr0,''); };\nvar ___utf16le = __utf16le;\nvar __hexlify = function(b,s,l) { var ss=[]; for(var i=s; i<s+l; ++i) ss.push((\"0\" + b[i].toString(16)).slice(-2)); return ss.join(\"\"); };\nvar ___hexlify = __hexlify;\nvar __bconcat = function(bufs) {\n\tif(Array.isArray(bufs[0])) return [].concat.apply([], bufs);\n\tvar maxlen = 0, i = 0;\n\tfor(i = 0; i < bufs.length; ++i) maxlen += bufs[i].length;\n\tvar o = new Uint8Array(maxlen);\n\tfor(i = 0, maxlen = 0; i < bufs.length; maxlen += bufs[i].length, ++i) o.set(bufs[i], maxlen);\n\treturn o;\n};\nvar bconcat = __bconcat;\n\n\nif(has_buf) {\n\t__utf16le = function(b,s,e) {\n\t\tif(!Buffer.isBuffer(b)) return ___utf16le(b,s,e);\n\t\treturn b.toString('utf16le',s,e).replace(chr0,'')/*.replace(chr1,'!')*/;\n\t};\n\t__hexlify = function(b,s,l) { return Buffer.isBuffer(b) ? b.toString('hex',s,s+l) : ___hexlify(b,s,l); };\n\t__toBuffer = function(bufs) { return (bufs[0].length > 0 && Buffer.isBuffer(bufs[0][0])) ? Buffer.concat((bufs[0])) : ___toBuffer(bufs);};\n\ts2a = function(s) { return Buffer_from(s, \"binary\"); };\n\tbconcat = function(bufs) { return Buffer.isBuffer(bufs[0]) ? Buffer.concat(bufs) : __bconcat(bufs); };\n}\n\n\nvar __readUInt8 = function(b, idx) { return b[idx]; };\nvar __readUInt16LE = function(b, idx) { return b[idx+1]*(1<<8)+b[idx]; };\nvar __readInt16LE = function(b, idx) { var u = b[idx+1]*(1<<8)+b[idx]; return (u < 0x8000) ? u : (0xffff - u + 1) * -1; };\nvar __readUInt32LE = function(b, idx) { return b[idx+3]*(1<<24)+(b[idx+2]<<16)+(b[idx+1]<<8)+b[idx]; };\nvar __readInt32LE = function(b, idx) { return (b[idx+3]<<24)+(b[idx+2]<<16)+(b[idx+1]<<8)+b[idx]; };\n\nfunction ReadShift(size, t) {\n\tvar oI, oS, type = 0;\n\tswitch(size) {\n\t\tcase 1: oI = __readUInt8(this, this.l); break;\n\t\tcase 2: oI = (t !== 'i' ? __readUInt16LE : __readInt16LE)(this, this.l); break;\n\t\tcase 4: oI = __readInt32LE(this, this.l); break;\n\t\tcase 16: type = 2; oS = __hexlify(this, this.l, size);\n\t}\n\tthis.l += size; if(type === 0) return oI; return oS;\n}\n\nvar __writeUInt32LE = function(b, val, idx) { b[idx] = (val & 0xFF); b[idx+1] = ((val >>> 8) & 0xFF); b[idx+2] = ((val >>> 16) & 0xFF); b[idx+3] = ((val >>> 24) & 0xFF); };\nvar __writeInt32LE = function(b, val, idx) { b[idx] = (val & 0xFF); b[idx+1] = ((val >> 8) & 0xFF); b[idx+2] = ((val >> 16) & 0xFF); b[idx+3] = ((val >> 24) & 0xFF); };\n\nfunction WriteShift(t, val, f) {\n\tvar size = 0, i = 0;\n\tswitch(f) {\n\t\tcase \"hex\": for(; i < t; ++i) {\nthis[this.l++] = parseInt(val.slice(2*i, 2*i+2), 16)||0;\n\t\t} return this;\n\t\tcase \"utf16le\":\nvar end = this.l + t;\n\t\t\tfor(i = 0; i < Math.min(val.length, t); ++i) {\n\t\t\t\tvar cc = val.charCodeAt(i);\n\t\t\t\tthis[this.l++] = cc & 0xff;\n\t\t\t\tthis[this.l++] = cc >> 8;\n\t\t\t}\n\t\t\twhile(this.l < end) this[this.l++] = 0;\n\t\t\treturn this;\n\t}\nswitch(t) {\n\t\tcase 1: size = 1; this[this.l] = val&0xFF; break;\n\t\tcase 2: size = 2; this[this.l] = val&0xFF; val >>>= 8; this[this.l+1] = val&0xFF; break;\n\t\tcase 4: size = 4; __writeUInt32LE(this, val, this.l); break;\n\t\tcase -4: size = 4; __writeInt32LE(this, val, this.l); break;\n\t}\n\tthis.l += size; return this;\n}\n\nfunction CheckField(hexstr, fld) {\n\tvar m = __hexlify(this,this.l,hexstr.length>>1);\n\tif(m !== hexstr) throw new Error(fld + 'Expected ' + hexstr + ' saw ' + m);\n\tthis.l += hexstr.length>>1;\n}\n\nfunction prep_blob(blob, pos) {\n\tblob.l = pos;\n\tblob.read_shift = ReadShift;\n\tblob.chk = CheckField;\n\tblob.write_shift = WriteShift;\n}\n\nfunction new_buf(sz) {\n\tvar o = (new_raw_buf(sz));\n\tprep_blob(o, 0);\n\treturn o;\n}\n\n/*! crc32.js (C) 2014-present SheetJS -- http://sheetjs.com */\n/* vim: set ts=2: */\n/*exported CRC32 */\nvar CRC32 = (function() {\nvar CRC32 = {};\nCRC32.version = '1.2.1';\n/*global Int32Array */\nfunction signed_crc_table() {\n\tvar c = 0, table = new Array(256);\n\n\tfor(var n =0; n != 256; ++n){\n\t\tc = n;\n\t\tc = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));\n\t\tc = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));\n\t\tc = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));\n\t\tc = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));\n\t\tc = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));\n\t\tc = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));\n\t\tc = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));\n\t\tc = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));\n\t\ttable[n] = c;\n\t}\n\n\treturn typeof Int32Array !== 'undefined' ? new Int32Array(table) : table;\n}\n\nvar T0 = signed_crc_table();\nfunction slice_by_16_tables(T) {\n\tvar c = 0, v = 0, n = 0, table = typeof Int32Array !== 'undefined' ? new Int32Array(4096) : new Array(4096) ;\n\n\tfor(n = 0; n != 256; ++n) table[n] = T[n];\n\tfor(n = 0; n != 256; ++n) {\n\t\tv = T[n];\n\t\tfor(c = 256 + n; c < 4096; c += 256) v = table[c] = (v >>> 8) ^ T[v & 0xFF];\n\t}\n\tvar out = [];\n\tfor(n = 1; n != 16; ++n) out[n - 1] = typeof Int32Array !== 'undefined' ? table.subarray(n * 256, n * 256 + 256) : table.slice(n * 256, n * 256 + 256);\n\treturn out;\n}\nvar TT = slice_by_16_tables(T0);\nvar T1 = TT[0], T2 = TT[1], T3 = TT[2], T4 = TT[3], T5 = TT[4];\nvar T6 = TT[5], T7 = TT[6], T8 = TT[7], T9 = TT[8], Ta = TT[9];\nvar Tb = TT[10], Tc = TT[11], Td = TT[12], Te = TT[13], Tf = TT[14];\nfunction crc32_bstr(bstr, seed) {\n\tvar C = seed ^ -1;\n\tfor(var i = 0, L = bstr.length; i < L;) C = (C>>>8) ^ T0[(C^bstr.charCodeAt(i++))&0xFF];\n\treturn ~C;\n}\n\nfunction crc32_buf(B, seed) {\n\tvar C = seed ^ -1, L = B.length - 15, i = 0;\n\tfor(; i < L;) C =\n\t\tTf[B[i++] ^ (C & 255)] ^\n\t\tTe[B[i++] ^ ((C >> 8) & 255)] ^\n\t\tTd[B[i++] ^ ((C >> 16) & 255)] ^\n\t\tTc[B[i++] ^ (C >>> 24)] ^\n\t\tTb[B[i++]] ^ Ta[B[i++]] ^ T9[B[i++]] ^ T8[B[i++]] ^\n\t\tT7[B[i++]] ^ T6[B[i++]] ^ T5[B[i++]] ^ T4[B[i++]] ^\n\t\tT3[B[i++]] ^ T2[B[i++]] ^ T1[B[i++]] ^ T0[B[i++]];\n\tL += 15;\n\twhile(i < L) C = (C>>>8) ^ T0[(C^B[i++])&0xFF];\n\treturn ~C;\n}\n\nfunction crc32_str(str, seed) {\n\tvar C = seed ^ -1;\n\tfor(var i = 0, L = str.length, c = 0, d = 0; i < L;) {\n\t\tc = str.charCodeAt(i++);\n\t\tif(c < 0x80) {\n\t\t\tC = (C>>>8) ^ T0[(C^c)&0xFF];\n\t\t} else if(c < 0x800) {\n\t\t\tC = (C>>>8) ^ T0[(C ^ (192|((c>>6)&31)))&0xFF];\n\t\t\tC = (C>>>8) ^ T0[(C ^ (128|(c&63)))&0xFF];\n\t\t} else if(c >= 0xD800 && c < 0xE000) {\n\t\t\tc = (c&1023)+64; d = str.charCodeAt(i++)&1023;\n\t\t\tC = (C>>>8) ^ T0[(C ^ (240|((c>>8)&7)))&0xFF];\n\t\t\tC = (C>>>8) ^ T0[(C ^ (128|((c>>2)&63)))&0xFF];\n\t\t\tC = (C>>>8) ^ T0[(C ^ (128|((d>>6)&15)|((c&3)<<4)))&0xFF];\n\t\t\tC = (C>>>8) ^ T0[(C ^ (128|(d&63)))&0xFF];\n\t\t} else {\n\t\t\tC = (C>>>8) ^ T0[(C ^ (224|((c>>12)&15)))&0xFF];\n\t\t\tC = (C>>>8) ^ T0[(C ^ (128|((c>>6)&63)))&0xFF];\n\t\t\tC = (C>>>8) ^ T0[(C ^ (128|(c&63)))&0xFF];\n\t\t}\n\t}\n\treturn ~C;\n}\nCRC32.table = T0;\nCRC32.bstr = crc32_bstr;\nCRC32.buf = crc32_buf;\nCRC32.str = crc32_str;\nreturn CRC32;\n})();\n/* [MS-CFB] v20171201 */\nvar CFB = (function _CFB(){\nvar exports = {};\nexports.version = '1.2.2';\n/* [MS-CFB] 2.6.4 */\nfunction namecmp(l, r) {\n\tvar L = l.split(\"/\"), R = r.split(\"/\");\n\tfor(var i = 0, c = 0, Z = Math.min(L.length, R.length); i < Z; ++i) {\n\t\tif((c = L[i].length - R[i].length)) return c;\n\t\tif(L[i] != R[i]) return L[i] < R[i] ? -1 : 1;\n\t}\n\treturn L.length - R.length;\n}\nfunction dirname(p) {\n\tif(p.charAt(p.length - 1) == \"/\") return (p.slice(0,-1).indexOf(\"/\") === -1) ? p : dirname(p.slice(0, -1));\n\tvar c = p.lastIndexOf(\"/\");\n\treturn (c === -1) ? p : p.slice(0, c+1);\n}\n\nfunction filename(p) {\n\tif(p.charAt(p.length - 1) == \"/\") return filename(p.slice(0, -1));\n\tvar c = p.lastIndexOf(\"/\");\n\treturn (c === -1) ? p : p.slice(c+1);\n}\n/* -------------------------------------------------------------------------- */\n/* DOS Date format:\n high|YYYYYYYm.mmmddddd.HHHHHMMM.MMMSSSSS|low\n add 1980 to stored year\n stored second should be doubled\n*/\n\n/* write JS date to buf as a DOS date */\nfunction write_dos_date(buf, date) {\n\tif(typeof date === \"string\") date = new Date(date);\n\tvar hms = date.getHours();\n\thms = hms << 6 | date.getMinutes();\n\thms = hms << 5 | (date.getSeconds()>>>1);\n\tbuf.write_shift(2, hms);\n\tvar ymd = (date.getFullYear() - 1980);\n\tymd = ymd << 4 | (date.getMonth()+1);\n\tymd = ymd << 5 | date.getDate();\n\tbuf.write_shift(2, ymd);\n}\n\n/* read four bytes from buf and interpret as a DOS date */\nfunction parse_dos_date(buf) {\n\tvar hms = buf.read_shift(2) & 0xFFFF;\n\tvar ymd = buf.read_shift(2) & 0xFFFF;\n\tvar val = new Date();\n\tvar d = ymd & 0x1F; ymd >>>= 5;\n\tvar m = ymd & 0x0F; ymd >>>= 4;\n\tval.setMilliseconds(0);\n\tval.setFullYear(ymd + 1980);\n\tval.setMonth(m-1);\n\tval.setDate(d);\n\tvar S = hms & 0x1F; hms >>>= 5;\n\tvar M = hms & 0x3F; hms >>>= 6;\n\tval.setHours(hms);\n\tval.setMinutes(M);\n\tval.setSeconds(S<<1);\n\treturn val;\n}\nfunction parse_extra_field(blob) {\n\tprep_blob(blob, 0);\n\tvar o = {};\n\tvar flags = 0;\n\twhile(blob.l <= blob.length - 4) {\n\t\tvar type = blob.read_shift(2);\n\t\tvar sz = blob.read_shift(2), tgt = blob.l + sz;\n\t\tvar p = {};\n\t\tswitch(type) {\n\t\t\t/* UNIX-style Timestamps */\n\t\t\tcase 0x5455: {\n\t\t\t\tflags = blob.read_shift(1);\n\t\t\t\tif(flags & 1) p.mtime = blob.read_shift(4);\n\t\t\t\t/* for some reason, CD flag corresponds to LFH */\n\t\t\t\tif(sz > 5) {\n\t\t\t\t\tif(flags & 2) p.atime = blob.read_shift(4);\n\t\t\t\t\tif(flags & 4) p.ctime = blob.read_shift(4);\n\t\t\t\t}\n\t\t\t\tif(p.mtime) p.mt = new Date(p.mtime*1000);\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tblob.l = tgt;\n\t\to[type] = p;\n\t}\n\treturn o;\n}\nvar fs;\nfunction get_fs() { return fs || (fs = require('fs')); }\nfunction parse(file, options) {\nif(file[0] == 0x50 && file[1] == 0x4b) return parse_zip(file, options);\nif((file[0] | 0x20) == 0x6d && (file[1]|0x20) == 0x69) return parse_mad(file, options);\nif(file.length < 512) throw new Error(\"CFB file size \" + file.length + \" < 512\");\nvar mver = 3;\nvar ssz = 512;\nvar nmfs = 0; // number of mini FAT sectors\nvar difat_sec_cnt = 0;\nvar dir_start = 0;\nvar minifat_start = 0;\nvar difat_start = 0;\n\nvar fat_addrs = []; // locations of FAT sectors\n\n/* [MS-CFB] 2.2 Compound File Header */\nvar blob = file.slice(0,512);\nprep_blob(blob, 0);\n\n/* major version */\nvar mv = check_get_mver(blob);\nmver = mv[0];\nswitch(mver) {\n\tcase 3: ssz = 512; break; case 4: ssz = 4096; break;\n\tcase 0: if(mv[1] == 0) return parse_zip(file, options);\n\t/* falls through */\n\tdefault: throw new Error(\"Major Version: Expected 3 or 4 saw \" + mver);\n}\n\n/* reprocess header */\nif(ssz !== 512) { blob = file.slice(0,ssz); prep_blob(blob, 28 /* blob.l */); }\n/* Save header for final object */\nvar header = file.slice(0,ssz);\n\ncheck_shifts(blob, mver);\n\n// Number of Directory Sectors\nvar dir_cnt = blob.read_shift(4, 'i');\nif(mver === 3 && dir_cnt !== 0) throw new Error('# Directory Sectors: Expected 0 saw ' + dir_cnt);\n\n// Number of FAT Sectors\nblob.l += 4;\n\n// First Directory Sector Location\ndir_start = blob.read_shift(4, 'i');\n\n// Transaction Signature\nblob.l += 4;\n\n// Mini Stream Cutoff Size\nblob.chk('00100000', 'Mini Stream Cutoff Size: ');\n\n// First Mini FAT Sector Location\nminifat_start = blob.read_shift(4, 'i');\n\n// Number of Mini FAT Sectors\nnmfs = blob.read_shift(4, 'i');\n\n// First DIFAT sector location\ndifat_start = blob.read_shift(4, 'i');\n\n// Number of DIFAT Sectors\ndifat_sec_cnt = blob.read_shift(4, 'i');\n\n// Grab FAT Sector Locations\nfor(var q = -1, j = 0; j < 109; ++j) { /* 109 = (512 - blob.l)>>>2; */\n\tq = blob.read_shift(4, 'i');\n\tif(q<0) break;\n\tfat_addrs[j] = q;\n}\n\n/** Break the file up into sectors */\nvar sectors = sectorify(file, ssz);\n\nsleuth_fat(difat_start, difat_sec_cnt, sectors, ssz, fat_addrs);\n\n/** Chains */\nvar sector_list = make_sector_list(sectors, dir_start, fat_addrs, ssz);\n\nsector_list[dir_start].name = \"!Directory\";\nif(nmfs > 0 && minifat_start !== ENDOFCHAIN) sector_list[minifat_start].name = \"!MiniFAT\";\nsector_list[fat_addrs[0]].name = \"!FAT\";\nsector_list.fat_addrs = fat_addrs;\nsector_list.ssz = ssz;\n\n/* [MS-CFB] 2.6.1 Compound File Directory Entry */\nvar files = {}, Paths = [], FileIndex = [], FullPaths = [];\nread_directory(dir_start, sector_list, sectors, Paths, nmfs, files, FileIndex, minifat_start);\n\nbuild_full_paths(FileIndex, FullPaths, Paths);\nPaths.shift();\n\nvar o = {\n\tFileIndex: FileIndex,\n\tFullPaths: FullPaths\n};\n\n// $FlowIgnore\nif(options && options.raw) o.raw = {header: header, sectors: sectors};\nreturn o;\n} // parse\n\n/* [MS-CFB] 2.2 Compound File Header -- read up to major version */\nfunction check_get_mver(blob) {\n\tif(blob[blob.l] == 0x50 && blob[blob.l + 1] == 0x4b) return [0, 0];\n\t// header signature 8\n\tblob.chk(HEADER_SIGNATURE, 'Header Signature: ');\n\n\t// clsid 16\n\t//blob.chk(HEADER_CLSID, 'CLSID: ');\n\tblob.l += 16;\n\n\t// minor version 2\n\tvar mver = blob.read_shift(2, 'u');\n\n\treturn [blob.read_shift(2,'u'), mver];\n}\nfunction check_shifts(blob, mver) {\n\tvar shift = 0x09;\n\n\t// Byte Order\n\t//blob.chk('feff', 'Byte Order: '); // note: some writers put 0xffff\n\tblob.l += 2;\n\n\t// Sector Shift\n\tswitch((shift = blob.read_shift(2))) {\n\t\tcase 0x09: if(mver != 3) throw new Error('Sector Shift: Expected 9 saw ' + shift); break;\n\t\tcase 0x0c: if(mver != 4) throw new Error('Sector Shift: Expected 12 saw ' + shift); break;\n\t\tdefault: throw new Error('Sector Shift: Expected 9 or 12 saw ' + shift);\n\t}\n\n\t// Mini Sector Shift\n\tblob.chk('0600', 'Mini Sector Shift: ');\n\n\t// Reserved\n\tblob.chk('000000000000', 'Reserved: ');\n}\n\n/** Break the file up into sectors */\nfunction sectorify(file, ssz) {\n\tvar nsectors = Math.ceil(file.length/ssz)-1;\n\tvar sectors = [];\n\tfor(var i=1; i < nsectors; ++i) sectors[i-1] = file.slice(i*ssz,(i+1)*ssz);\n\tsectors[nsectors-1] = file.slice(nsectors*ssz);\n\treturn sectors;\n}\n\n/* [MS-CFB] 2.6.4 Red-Black Tree */\nfunction build_full_paths(FI, FP, Paths) {\n\tvar i = 0, L = 0, R = 0, C = 0, j = 0, pl = Paths.length;\n\tvar dad = [], q = [];\n\n\tfor(; i < pl; ++i) { dad[i]=q[i]=i; FP[i]=Paths[i]; }\n\n\tfor(; j < q.length; ++j) {\n\t\ti = q[j];\n\t\tL = FI[i].L; R = FI[i].R; C = FI[i].C;\n\t\tif(dad[i] === i) {\n\t\t\tif(L !== -1 /*NOSTREAM*/ && dad[L] !== L) dad[i] = dad[L];\n\t\t\tif(R !== -1 && dad[R] !== R) dad[i] = dad[R];\n\t\t}\n\t\tif(C !== -1 /*NOSTREAM*/) dad[C] = i;\n\t\tif(L !== -1 && i != dad[i]) { dad[L] = dad[i]; if(q.lastIndexOf(L) < j) q.push(L); }\n\t\tif(R !== -1 && i != dad[i]) { dad[R] = dad[i]; if(q.lastIndexOf(R) < j) q.push(R); }\n\t}\n\tfor(i=1; i < pl; ++i) if(dad[i] === i) {\n\t\tif(R !== -1 /*NOSTREAM*/ && dad[R] !== R) dad[i] = dad[R];\n\t\telse if(L !== -1 && dad[L] !== L) dad[i] = dad[L];\n\t}\n\n\tfor(i=1; i < pl; ++i) {\n\t\tif(FI[i].type === 0 /* unknown */) continue;\n\t\tj = i;\n\t\tif(j != dad[j]) do {\n\t\t\tj = dad[j];\n\t\t\tFP[i] = FP[j] + \"/\" + FP[i];\n\t\t} while (j !== 0 && -1 !== dad[j] && j != dad[j]);\n\t\tdad[i] = -1;\n\t}\n\n\tFP[0] += \"/\";\n\tfor(i=1; i < pl; ++i) {\n\t\tif(FI[i].type !== 2 /* stream */) FP[i] += \"/\";\n\t}\n}\n\nfunction get_mfat_entry(entry, payload, mini) {\n\tvar start = entry.start, size = entry.size;\n\t//return (payload.slice(start*MSSZ, start*MSSZ + size));\n\tvar o = [];\n\tvar idx = start;\n\twhile(mini && size > 0 && idx >= 0) {\n\t\to.push(payload.slice(idx * MSSZ, idx * MSSZ + MSSZ));\n\t\tsize -= MSSZ;\n\t\tidx = __readInt32LE(mini, idx * 4);\n\t}\n\tif(o.length === 0) return (new_buf(0));\n\treturn (bconcat(o).slice(0, entry.size));\n}\n\n/** Chase down the rest of the DIFAT chain to build a comprehensive list\n DIFAT chains by storing the next sector number as the last 32 bits */\nfunction sleuth_fat(idx, cnt, sectors, ssz, fat_addrs) {\n\tvar q = ENDOFCHAIN;\n\tif(idx === ENDOFCHAIN) {\n\t\tif(cnt !== 0) throw new Error(\"DIFAT chain shorter than expected\");\n\t} else if(idx !== -1 /*FREESECT*/) {\n\t\tvar sector = sectors[idx], m = (ssz>>>2)-1;\n\t\tif(!sector) return;\n\t\tfor(var i = 0; i < m; ++i) {\n\t\t\tif((q = __readInt32LE(sector,i*4)) === ENDOFCHAIN) break;\n\t\t\tfat_addrs.push(q);\n\t\t}\n\t\tif(cnt >= 1) sleuth_fat(__readInt32LE(sector,ssz-4),cnt - 1, sectors, ssz, fat_addrs);\n\t}\n}\n\n/** Follow the linked list of sectors for a given starting point */\nfunction get_sector_list(sectors, start, fat_addrs, ssz, chkd) {\n\tvar buf = [], buf_chain = [];\n\tif(!chkd) chkd = [];\n\tvar modulus = ssz - 1, j = 0, jj = 0;\n\tfor(j=start; j>=0;) {\n\t\tchkd[j] = true;\n\t\tbuf[buf.length] = j;\n\t\tbuf_chain.push(sectors[j]);\n\t\tvar addr = fat_addrs[Math.floor(j*4/ssz)];\n\t\tjj = ((j*4) & modulus);\n\t\tif(ssz < 4 + jj) throw new Error(\"FAT boundary crossed: \" + j + \" 4 \"+ssz);\n\t\tif(!sectors[addr]) break;\n\t\tj = __readInt32LE(sectors[addr], jj);\n\t}\n\treturn {nodes: buf, data:__toBuffer([buf_chain])};\n}\n\n/** Chase down the sector linked lists */\nfunction make_sector_list(sectors, dir_start, fat_addrs, ssz) {\n\tvar sl = sectors.length, sector_list = ([]);\n\tvar chkd = [], buf = [], buf_chain = [];\n\tvar modulus = ssz - 1, i=0, j=0, k=0, jj=0;\n\tfor(i=0; i < sl; ++i) {\n\t\tbuf = ([]);\n\t\tk = (i + dir_start); if(k >= sl) k-=sl;\n\t\tif(chkd[k]) continue;\n\t\tbuf_chain = [];\n\t\tvar seen = [];\n\t\tfor(j=k; j>=0;) {\n\t\t\tseen[j] = true;\n\t\t\tchkd[j] = true;\n\t\t\tbuf[buf.length] = j;\n\t\t\tbuf_chain.push(sectors[j]);\n\t\t\tvar addr = fat_addrs[Math.floor(j*4/ssz)];\n\t\t\tjj = ((j*4) & modulus);\n\t\t\tif(ssz < 4 + jj) throw new Error(\"FAT boundary crossed: \" + j + \" 4 \"+ssz);\n\t\t\tif(!sectors[addr]) break;\n\t\t\tj = __readInt32LE(sectors[addr], jj);\n\t\t\tif(seen[j]) break;\n\t\t}\n\t\tsector_list[k] = ({nodes: buf, data:__toBuffer([buf_chain])});\n\t}\n\treturn sector_list;\n}\n\n/* [MS-CFB] 2.6.1 Compound File Directory Entry */\nfunction read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, FileIndex, mini) {\n\tvar minifat_store = 0, pl = (Paths.length?2:0);\n\tvar sector = sector_list[dir_start].data;\n\tvar i = 0, namelen = 0, name;\n\tfor(; i < sector.length; i+= 128) {\n\t\tvar blob = sector.slice(i, i+128);\n\t\tprep_blob(blob, 64);\n\t\tnamelen = blob.read_shift(2);\n\t\tname = __utf16le(blob,0,namelen-pl);\n\t\tPaths.push(name);\n\t\tvar o = ({\n\t\t\tname: name,\n\t\t\ttype: blob.read_shift(1),\n\t\t\tcolor: blob.read_shift(1),\n\t\t\tL: blob.read_shift(4, 'i'),\n\t\t\tR: blob.read_shift(4, 'i'),\n\t\t\tC: blob.read_shift(4, 'i'),\n\t\t\tclsid: blob.read_shift(16),\n\t\t\tstate: blob.read_shift(4, 'i'),\n\t\t\tstart: 0,\n\t\t\tsize: 0\n\t\t});\n\t\tvar ctime = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2);\n\t\tif(ctime !== 0) o.ct = read_date(blob, blob.l-8);\n\t\tvar mtime = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2);\n\t\tif(mtime !== 0) o.mt = read_date(blob, blob.l-8);\n\t\to.start = blob.read_shift(4, 'i');\n\t\to.size = blob.read_shift(4, 'i');\n\t\tif(o.size < 0 && o.start < 0) { o.size = o.type = 0; o.start = ENDOFCHAIN; o.name = \"\"; }\n\t\tif(o.type === 5) { /* root */\n\t\t\tminifat_store = o.start;\n\t\t\tif(nmfs > 0 && minifat_store !== ENDOFCHAIN) sector_list[minifat_store].name = \"!StreamData\";\n\t\t\t/*minifat_size = o.size;*/\n\t\t} else if(o.size >= 4096 /* MSCSZ */) {\n\t\t\to.storage = 'fat';\n\t\t\tif(sector_list[o.start] === undefined) sector_list[o.start] = get_sector_list(sectors, o.start, sector_list.fat_addrs, sector_list.ssz);\n\t\t\tsector_list[o.start].name = o.name;\n\t\t\to.content = (sector_list[o.start].data.slice(0,o.size));\n\t\t} else {\n\t\t\to.storage = 'minifat';\n\t\t\tif(o.size < 0) o.size = 0;\n\t\t\telse if(minifat_store !== ENDOFCHAIN && o.start !== ENDOFCHAIN && sector_list[minifat_store]) {\n\t\t\t\to.content = get_mfat_entry(o, sector_list[minifat_store].data, (sector_list[mini]||{}).data);\n\t\t\t}\n\t\t}\n\t\tif(o.content) prep_blob(o.content, 0);\n\t\tfiles[name] = o;\n\t\tFileIndex.push(o);\n\t}\n}\n\nfunction read_date(blob, offset) {\n\treturn new Date(( ( (__readUInt32LE(blob,offset+4)/1e7)*Math.pow(2,32)+__readUInt32LE(blob,offset)/1e7 ) - 11644473600)*1000);\n}\n\nfunction read_file(filename, options) {\n\tget_fs();\n\treturn parse(fs.readFileSync(filename), options);\n}\n\nfunction read(blob, options) {\n\tvar type = options && options.type;\n\tif(!type) {\n\t\tif(has_buf && Buffer.isBuffer(blob)) type = \"buffer\";\n\t}\n\tswitch(type || \"base64\") {\n\t\tcase \"file\": return read_file(blob, options);\n\t\tcase \"base64\": return parse(s2a(Base64_decode(blob)), options);\n\t\tcase \"binary\": return parse(s2a(blob), options);\n\t}\n\treturn parse(blob, options);\n}\n\nfunction init_cfb(cfb, opts) {\n\tvar o = opts || {}, root = o.root || \"Root Entry\";\n\tif(!cfb.FullPaths) cfb.FullPaths = [];\n\tif(!cfb.FileIndex) cfb.FileIndex = [];\n\tif(cfb.FullPaths.length !== cfb.FileIndex.length) throw new Error(\"inconsistent CFB structure\");\n\tif(cfb.FullPaths.length === 0) {\n\t\tcfb.FullPaths[0] = root + \"/\";\n\t\tcfb.FileIndex[0] = ({ name: root, type: 5 });\n\t}\n\tif(o.CLSID) cfb.FileIndex[0].clsid = o.CLSID;\n\tseed_cfb(cfb);\n}\nfunction seed_cfb(cfb) {\n\tvar nm = \"\\u0001Sh33tJ5\";\n\tif(CFB.find(cfb, \"/\" + nm)) return;\n\tvar p = new_buf(4); p[0] = 55; p[1] = p[3] = 50; p[2] = 54;\n\tcfb.FileIndex.push(({ name: nm, type: 2, content:p, size:4, L:69, R:69, C:69 }));\n\tcfb.FullPaths.push(cfb.FullPaths[0] + nm);\n\trebuild_cfb(cfb);\n}\nfunction rebuild_cfb(cfb, f) {\n\tinit_cfb(cfb);\n\tvar gc = false, s = false;\n\tfor(var i = cfb.FullPaths.length - 1; i >= 0; --i) {\n\t\tvar _file = cfb.FileIndex[i];\n\t\tswitch(_file.type) {\n\t\t\tcase 0:\n\t\t\t\tif(s) gc = true;\n\t\t\t\telse { cfb.FileIndex.pop(); cfb.FullPaths.pop(); }\n\t\t\t\tbreak;\n\t\t\tcase 1: case 2: case 5:\n\t\t\t\ts = true;\n\t\t\t\tif(isNaN(_file.R * _file.L * _file.C)) gc = true;\n\t\t\t\tif(_file.R > -1 && _file.L > -1 && _file.R == _file.L) gc = true;\n\t\t\t\tbreak;\n\t\t\tdefault: gc = true; break;\n\t\t}\n\t}\n\tif(!gc && !f) return;\n\n\tvar now = new Date(1987, 1, 19), j = 0;\n\t// Track which names exist\n\tvar fullPaths = Object.create ? Object.create(null) : {};\n\tvar data = [];\n\tfor(i = 0; i < cfb.FullPaths.length; ++i) {\n\t\tfullPaths[cfb.FullPaths[i]] = true;\n\t\tif(cfb.FileIndex[i].type === 0) continue;\n\t\tdata.push([cfb.FullPaths[i], cfb.FileIndex[i]]);\n\t}\n\tfor(i = 0; i < data.length; ++i) {\n\t\tvar dad = dirname(data[i][0]);\n\t\ts = fullPaths[dad];\n\t\twhile(!s) {\n\t\t\twhile(dirname(dad) && !fullPaths[dirname(dad)]) dad = dirname(dad);\n\n\t\t\tdata.push([dad, ({\n\t\t\t\tname: filename(dad).replace(\"/\",\"\"),\n\t\t\t\ttype: 1,\n\t\t\t\tclsid: HEADER_CLSID,\n\t\t\t\tct: now, mt: now,\n\t\t\t\tcontent: null\n\t\t\t})]);\n\n\t\t\t// Add name to set\n\t\t\tfullPaths[dad] = true;\n\n\t\t\tdad = dirname(data[i][0]);\n\t\t\ts = fullPaths[dad];\n\t\t}\n\t}\n\n\tdata.sort(function(x,y) { return namecmp(x[0], y[0]); });\n\tcfb.FullPaths = []; cfb.FileIndex = [];\n\tfor(i = 0; i < data.length; ++i) { cfb.FullPaths[i] = data[i][0]; cfb.FileIndex[i] = data[i][1]; }\n\tfor(i = 0; i < data.length; ++i) {\n\t\tvar elt = cfb.FileIndex[i];\n\t\tvar nm = cfb.FullPaths[i];\n\n\t\telt.name = filename(nm).replace(\"/\",\"\");\n\t\telt.L = elt.R = elt.C = -(elt.color = 1);\n\t\telt.size = elt.content ? elt.content.length : 0;\n\t\telt.start = 0;\n\t\telt.clsid = (elt.clsid || HEADER_CLSID);\n\t\tif(i === 0) {\n\t\t\telt.C = data.length > 1 ? 1 : -1;\n\t\t\telt.size = 0;\n\t\t\telt.type = 5;\n\t\t} else if(nm.slice(-1) == \"/\") {\n\t\t\tfor(j=i+1;j < data.length; ++j) if(dirname(cfb.FullPaths[j])==nm) break;\n\t\t\telt.C = j >= data.length ? -1 : j;\n\t\t\tfor(j=i+1;j < data.length; ++j) if(dirname(cfb.FullPaths[j])==dirname(nm)) break;\n\t\t\telt.R = j >= data.length ? -1 : j;\n\t\t\telt.type = 1;\n\t\t} else {\n\t\t\tif(dirname(cfb.FullPaths[i+1]||\"\") == dirname(nm)) elt.R = i + 1;\n\t\t\telt.type = 2;\n\t\t}\n\t}\n\n}\n\nfunction _write(cfb, options) {\n\tvar _opts = options || {};\n\t/* MAD is order-sensitive, skip rebuild and sort */\n\tif(_opts.fileType == 'mad') return write_mad(cfb, _opts);\n\trebuild_cfb(cfb);\n\tswitch(_opts.fileType) {\n\t\tcase 'zip': return write_zip(cfb, _opts);\n\t\t//case 'mad': return write_mad(cfb, _opts);\n\t}\n\tvar L = (function(cfb){\n\t\tvar mini_size = 0, fat_size = 0;\n\t\tfor(var i = 0; i < cfb.FileIndex.length; ++i) {\n\t\t\tvar file = cfb.FileIndex[i];\n\t\t\tif(!file.content) continue;\n\t\t\tvar flen = file.content.length;\n\t\t\tif(flen > 0){\n\t\t\t\tif(flen < 0x1000) mini_size += (flen + 0x3F) >> 6;\n\t\t\t\telse fat_size += (flen + 0x01FF) >> 9;\n\t\t\t}\n\t\t}\n\t\tvar dir_cnt = (cfb.FullPaths.length +3) >> 2;\n\t\tvar mini_cnt = (mini_size + 7) >> 3;\n\t\tvar mfat_cnt = (mini_size + 0x7F) >> 7;\n\t\tvar fat_base = mini_cnt + fat_size + dir_cnt + mfat_cnt;\n\t\tvar fat_cnt = (fat_base + 0x7F) >> 7;\n\t\tvar difat_cnt = fat_cnt <= 109 ? 0 : Math.ceil((fat_cnt-109)/0x7F);\n\t\twhile(((fat_base + fat_cnt + difat_cnt + 0x7F) >> 7) > fat_cnt) difat_cnt = ++fat_cnt <= 109 ? 0 : Math.ceil((fat_cnt-109)/0x7F);\n\t\tvar L = [1, difat_cnt, fat_cnt, mfat_cnt, dir_cnt, fat_size, mini_size, 0];\n\t\tcfb.FileIndex[0].size = mini_size << 6;\n\t\tL[7] = (cfb.FileIndex[0].start=L[0]+L[1]+L[2]+L[3]+L[4]+L[5])+((L[6]+7) >> 3);\n\t\treturn L;\n\t})(cfb);\n\tvar o = new_buf(L[7] << 9);\n\tvar i = 0, T = 0;\n\t{\n\t\tfor(i = 0; i < 8; ++i) o.write_shift(1, HEADER_SIG[i]);\n\t\tfor(i = 0; i < 8; ++i) o.write_shift(2, 0);\n\t\to.write_shift(2, 0x003E);\n\t\to.write_shift(2, 0x0003);\n\t\to.write_shift(2, 0xFFFE);\n\t\to.write_shift(2, 0x0009);\n\t\to.write_shift(2, 0x0006);\n\t\tfor(i = 0; i < 3; ++i) o.write_shift(2, 0);\n\t\to.write_shift(4, 0);\n\t\to.write_shift(4, L[2]);\n\t\to.write_shift(4, L[0] + L[1] + L[2] + L[3] - 1);\n\t\to.write_shift(4, 0);\n\t\to.write_shift(4, 1<<12);\n\t\to.write_shift(4, L[3] ? L[0] + L[1] + L[2] - 1: ENDOFCHAIN);\n\t\to.write_shift(4, L[3]);\n\t\to.write_shift(-4, L[1] ? L[0] - 1: ENDOFCHAIN);\n\t\to.write_shift(4, L[1]);\n\t\tfor(i = 0; i < 109; ++i) o.write_shift(-4, i < L[2] ? L[1] + i : -1);\n\t}\n\tif(L[1]) {\n\t\tfor(T = 0; T < L[1]; ++T) {\n\t\t\tfor(; i < 236 + T * 127; ++i) o.write_shift(-4, i < L[2] ? L[1] + i : -1);\n\t\t\to.write_shift(-4, T === L[1] - 1 ? ENDOFCHAIN : T + 1);\n\t\t}\n\t}\n\tvar chainit = function(w) {\n\t\tfor(T += w; i<T-1; ++i) o.write_shift(-4, i+1);\n\t\tif(w) { ++i; o.write_shift(-4, ENDOFCHAIN); }\n\t};\n\tT = i = 0;\n\tfor(T+=L[1]; i<T; ++i) o.write_shift(-4, consts.DIFSECT);\n\tfor(T+=L[2]; i<T; ++i) o.write_shift(-4, consts.FATSECT);\n\tchainit(L[3]);\n\tchainit(L[4]);\n\tvar j = 0, flen = 0;\n\tvar file = cfb.FileIndex[0];\n\tfor(; j < cfb.FileIndex.length; ++j) {\n\t\tfile = cfb.FileIndex[j];\n\t\tif(!file.content) continue;\nflen = file.content.length;\n\t\tif(flen < 0x1000) continue;\n\t\tfile.start = T;\n\t\tchainit((flen + 0x01FF) >> 9);\n\t}\n\tchainit((L[6] + 7) >> 3);\n\twhile(o.l & 0x1FF) o.write_shift(-4, consts.ENDOFCHAIN);\n\tT = i = 0;\n\tfor(j = 0; j < cfb.FileIndex.length; ++j) {\n\t\tfile = cfb.FileIndex[j];\n\t\tif(!file.content) continue;\nflen = file.content.length;\n\t\tif(!flen || flen >= 0x1000) continue;\n\t\tfile.start = T;\n\t\tchainit((flen + 0x3F) >> 6);\n\t}\n\twhile(o.l & 0x1FF) o.write_shift(-4, consts.ENDOFCHAIN);\n\tfor(i = 0; i < L[4]<<2; ++i) {\n\t\tvar nm = cfb.FullPaths[i];\n\t\tif(!nm || nm.length === 0) {\n\t\t\tfor(j = 0; j < 17; ++j) o.write_shift(4, 0);\n\t\t\tfor(j = 0; j < 3; ++j) o.write_shift(4, -1);\n\t\t\tfor(j = 0; j < 12; ++j) o.write_shift(4, 0);\n\t\t\tcontinue;\n\t\t}\n\t\tfile = cfb.FileIndex[i];\n\t\tif(i === 0) file.start = file.size ? file.start - 1 : ENDOFCHAIN;\n\t\tvar _nm = (i === 0 && _opts.root) || file.name;\n\t\tif(_nm.length > 32) {\n\t\t\tconsole.error(\"Name \" + _nm + \" will be truncated to \" + _nm.slice(0,32));\n\t\t\t_nm = _nm.slice(0, 32);\n\t\t}\n\t\tflen = 2*(_nm.length+1);\n\t\to.write_shift(64, _nm, \"utf16le\");\n\t\to.write_shift(2, flen);\n\t\to.write_shift(1, file.type);\n\t\to.write_shift(1, file.color);\n\t\to.write_shift(-4, file.L);\n\t\to.write_shift(-4, file.R);\n\t\to.write_shift(-4, file.C);\n\t\tif(!file.clsid) for(j = 0; j < 4; ++j) o.write_shift(4, 0);\n\t\telse o.write_shift(16, file.clsid, \"hex\");\n\t\to.write_shift(4, file.state || 0);\n\t\to.write_shift(4, 0); o.write_shift(4, 0);\n\t\to.write_shift(4, 0); o.write_shift(4, 0);\n\t\to.write_shift(4, file.start);\n\t\to.write_shift(4, file.size); o.write_shift(4, 0);\n\t}\n\tfor(i = 1; i < cfb.FileIndex.length; ++i) {\n\t\tfile = cfb.FileIndex[i];\nif(file.size >= 0x1000) {\n\t\t\to.l = (file.start+1) << 9;\n\t\t\tif (has_buf && Buffer.isBuffer(file.content)) {\n\t\t\t\tfile.content.copy(o, o.l, 0, file.size);\n\t\t\t\t// o is a 0-filled Buffer so just set next offset\n\t\t\t\to.l += (file.size + 511) & -512;\n\t\t\t} else {\n\t\t\t\tfor(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]);\n\t\t\t\tfor(; j & 0x1FF; ++j) o.write_shift(1, 0);\n\t\t\t}\n\t\t}\n\t}\n\tfor(i = 1; i < cfb.FileIndex.length; ++i) {\n\t\tfile = cfb.FileIndex[i];\nif(file.size > 0 && file.size < 0x1000) {\n\t\t\tif (has_buf && Buffer.isBuffer(file.content)) {\n\t\t\t\tfile.content.copy(o, o.l, 0, file.size);\n\t\t\t\t// o is a 0-filled Buffer so just set next offset\n\t\t\t\to.l += (file.size + 63) & -64;\n\t\t\t} else {\n\t\t\t\tfor(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]);\n\t\t\t\tfor(; j & 0x3F; ++j) o.write_shift(1, 0);\n\t\t\t}\n\t\t}\n\t}\n\tif (has_buf) {\n\t\to.l = o.length;\n\t} else {\n\t\t// When using Buffer, already 0-filled\n\t\twhile(o.l < o.length) o.write_shift(1, 0);\n\t}\n\treturn o;\n}\n/* [MS-CFB] 2.6.4 (Unicode 3.0.1 case conversion) */\nfunction find(cfb, path) {\n\tvar UCFullPaths = cfb.FullPaths.map(function(x) { return x.toUpperCase(); });\n\tvar UCPaths = UCFullPaths.map(function(x) { var y = x.split(\"/\"); return y[y.length - (x.slice(-1) == \"/\" ? 2 : 1)]; });\n\tvar k = false;\n\tif(path.charCodeAt(0) === 47 /* \"/\" */) { k = true; path = UCFullPaths[0].slice(0, -1) + path; }\n\telse k = path.indexOf(\"/\") !== -1;\n\tvar UCPath = path.toUpperCase();\n\tvar w = k === true ? UCFullPaths.indexOf(UCPath) : UCPaths.indexOf(UCPath);\n\tif(w !== -1) return cfb.FileIndex[w];\n\n\tvar m = !UCPath.match(chr1);\n\tUCPath = UCPath.replace(chr0,'');\n\tif(m) UCPath = UCPath.replace(chr1,'!');\n\tfor(w = 0; w < UCFullPaths.length; ++w) {\n\t\tif((m ? UCFullPaths[w].replace(chr1,'!') : UCFullPaths[w]).replace(chr0,'') == UCPath) return cfb.FileIndex[w];\n\t\tif((m ? UCPaths[w].replace(chr1,'!') : UCPaths[w]).replace(chr0,'') == UCPath) return cfb.FileIndex[w];\n\t}\n\treturn null;\n}\n/** CFB Constants */\nvar MSSZ = 64; /* Mini Sector Size = 1<<6 */\n//var MSCSZ = 4096; /* Mini Stream Cutoff Size */\n/* 2.1 Compound File Sector Numbers and Types */\nvar ENDOFCHAIN = -2;\n/* 2.2 Compound File Header */\nvar HEADER_SIGNATURE = 'd0cf11e0a1b11ae1';\nvar HEADER_SIG = [0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1];\nvar HEADER_CLSID = '00000000000000000000000000000000';\nvar consts = {\n\t/* 2.1 Compund File Sector Numbers and Types */\n\tMAXREGSECT: -6,\n\tDIFSECT: -4,\n\tFATSECT: -3,\n\tENDOFCHAIN: ENDOFCHAIN,\n\tFREESECT: -1,\n\t/* 2.2 Compound File Header */\n\tHEADER_SIGNATURE: HEADER_SIGNATURE,\n\tHEADER_MINOR_VERSION: '3e00',\n\tMAXREGSID: -6,\n\tNOSTREAM: -1,\n\tHEADER_CLSID: HEADER_CLSID,\n\t/* 2.6.1 Compound File Directory Entry */\n\tEntryTypes: ['unknown','storage','stream','lockbytes','property','root']\n};\n\nfunction write_file(cfb, filename, options) {\n\tget_fs();\n\tvar o = _write(cfb, options);\nfs.writeFileSync(filename, o);\n}\n\nfunction a2s(o) {\n\tvar out = new Array(o.length);\n\tfor(var i = 0; i < o.length; ++i) out[i] = String.fromCharCode(o[i]);\n\treturn out.join(\"\");\n}\n\nfunction write(cfb, options) {\n\tvar o = _write(cfb, options);\n\tswitch(options && options.type || \"buffer\") {\n\t\tcase \"file\": get_fs(); fs.writeFileSync(options.filename, (o)); return o;\n\t\tcase \"binary\": return typeof o == \"string\" ? o : a2s(o);\n\t\tcase \"base64\": return Base64_encode(typeof o == \"string\" ? o : a2s(o));\n\t\tcase \"buffer\": if(has_buf) return Buffer.isBuffer(o) ? o : Buffer_from(o);\n\t\t\t/* falls through */\n\t\tcase \"array\": return typeof o == \"string\" ? s2a(o) : o;\n\t}\n\treturn o;\n}\n/* node < 8.1 zlib does not expose bytesRead, so default to pure JS */\nvar _zlib;\nfunction use_zlib(zlib) { try {\n\tvar InflateRaw = zlib.InflateRaw;\n\tvar InflRaw = new InflateRaw();\n\tInflRaw._processChunk(new Uint8Array([3, 0]), InflRaw._finishFlushFlag);\n\tif(InflRaw.bytesRead) _zlib = zlib;\n\telse throw new Error(\"zlib does not expose bytesRead\");\n} catch(e) {console.error(\"cannot use native zlib: \" + (e.message || e)); } }\n\nfunction _inflateRawSync(payload, usz) {\n\tif(!_zlib) return _inflate(payload, usz);\n\tvar InflateRaw = _zlib.InflateRaw;\n\tvar InflRaw = new InflateRaw();\n\tvar out = InflRaw._processChunk(payload.slice(payload.l), InflRaw._finishFlushFlag);\n\tpayload.l += InflRaw.bytesRead;\n\treturn out;\n}\n\nfunction _deflateRawSync(payload) {\n\treturn _zlib ? _zlib.deflateRawSync(payload) : _deflate(payload);\n}\nvar CLEN_ORDER = [ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ];\n\n/* LEN_ID = [ 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285 ]; */\nvar LEN_LN = [ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13 , 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258 ];\n\n/* DST_ID = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29 ]; */\nvar DST_LN = [ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 ];\n\nfunction bit_swap_8(n) { var t = (((((n<<1)|(n<<11)) & 0x22110) | (((n<<5)|(n<<15)) & 0x88440))); return ((t>>16) | (t>>8) |t)&0xFF; }\n\nvar use_typed_arrays = typeof Uint8Array !== 'undefined';\n\nvar bitswap8 = use_typed_arrays ? new Uint8Array(1<<8) : [];\nfor(var q = 0; q < (1<<8); ++q) bitswap8[q] = bit_swap_8(q);\n\nfunction bit_swap_n(n, b) {\n\tvar rev = bitswap8[n & 0xFF];\n\tif(b <= 8) return rev >>> (8-b);\n\trev = (rev << 8) | bitswap8[(n>>8)&0xFF];\n\tif(b <= 16) return rev >>> (16-b);\n\trev = (rev << 8) | bitswap8[(n>>16)&0xFF];\n\treturn rev >>> (24-b);\n}\n\n/* helpers for unaligned bit reads */\nfunction read_bits_2(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 6 ? 0 : buf[h+1]<<8))>>>w)& 0x03; }\nfunction read_bits_3(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 5 ? 0 : buf[h+1]<<8))>>>w)& 0x07; }\nfunction read_bits_4(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 4 ? 0 : buf[h+1]<<8))>>>w)& 0x0F; }\nfunction read_bits_5(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 3 ? 0 : buf[h+1]<<8))>>>w)& 0x1F; }\nfunction read_bits_7(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 1 ? 0 : buf[h+1]<<8))>>>w)& 0x7F; }\n\n/* works up to n = 3 * 8 + 1 = 25 */\nfunction read_bits_n(buf, bl, n) {\n\tvar w = (bl&7), h = (bl>>>3), f = ((1<<n)-1);\n\tvar v = buf[h] >>> w;\n\tif(n < 8 - w) return v & f;\n\tv |= buf[h+1]<<(8-w);\n\tif(n < 16 - w) return v & f;\n\tv |= buf[h+2]<<(16-w);\n\tif(n < 24 - w) return v & f;\n\tv |= buf[h+3]<<(24-w);\n\treturn v & f;\n}\n\n/* helpers for unaligned bit writes */\nfunction write_bits_3(buf, bl, v) { var w = bl & 7, h = bl >>> 3;\n\tif(w <= 5) buf[h] |= (v & 7) << w;\n\telse {\n\t\tbuf[h] |= (v << w) & 0xFF;\n\t\tbuf[h+1] = (v&7) >> (8-w);\n\t}\n\treturn bl + 3;\n}\n\nfunction write_bits_1(buf, bl, v) {\n\tvar w = bl & 7, h = bl >>> 3;\n\tv = (v&1) << w;\n\tbuf[h] |= v;\n\treturn bl + 1;\n}\nfunction write_bits_8(buf, bl, v) {\n\tvar w = bl & 7, h = bl >>> 3;\n\tv <<= w;\n\tbuf[h] |= v & 0xFF; v >>>= 8;\n\tbuf[h+1] = v;\n\treturn bl + 8;\n}\nfunction write_bits_16(buf, bl, v) {\n\tvar w = bl & 7, h = bl >>> 3;\n\tv <<= w;\n\tbuf[h] |= v & 0xFF; v >>>= 8;\n\tbuf[h+1] = v & 0xFF;\n\tbuf[h+2] = v >>> 8;\n\treturn bl + 16;\n}\n\n/* until ArrayBuffer#realloc is a thing, fake a realloc */\nfunction realloc(b, sz) {\n\tvar L = b.length, M = 2*L > sz ? 2*L : sz + 5, i = 0;\n\tif(L >= sz) return b;\n\tif(has_buf) {\n\t\tvar o = new_unsafe_buf(M);\n\t\t// $FlowIgnore\n\t\tif(b.copy) b.copy(o);\n\t\telse for(; i < b.length; ++i) o[i] = b[i];\n\t\treturn o;\n\t} else if(use_typed_arrays) {\n\t\tvar a = new Uint8Array(M);\n\t\tif(a.set) a.set(b);\n\t\telse for(; i < L; ++i) a[i] = b[i];\n\t\treturn a;\n\t}\n\tb.length = M;\n\treturn b;\n}\n\n/* zero-filled arrays for older browsers */\nfunction zero_fill_array(n) {\n\tvar o = new Array(n);\n\tfor(var i = 0; i < n; ++i) o[i] = 0;\n\treturn o;\n}\n\n/* build tree (used for literals and lengths) */\nfunction build_tree(clens, cmap, MAX) {\n\tvar maxlen = 1, w = 0, i = 0, j = 0, ccode = 0, L = clens.length;\n\n\tvar bl_count = use_typed_arrays ? new Uint16Array(32) : zero_fill_array(32);\n\tfor(i = 0; i < 32; ++i) bl_count[i] = 0;\n\n\tfor(i = L; i < MAX; ++i) clens[i] = 0;\n\tL = clens.length;\n\n\tvar ctree = use_typed_arrays ? new Uint16Array(L) : zero_fill_array(L); // []\n\n\t/* build code tree */\n\tfor(i = 0; i < L; ++i) {\n\t\tbl_count[(w = clens[i])]++;\n\t\tif(maxlen < w) maxlen = w;\n\t\tctree[i] = 0;\n\t}\n\tbl_count[0] = 0;\n\tfor(i = 1; i <= maxlen; ++i) bl_count[i+16] = (ccode = (ccode + bl_count[i-1])<<1);\n\tfor(i = 0; i < L; ++i) {\n\t\tccode = clens[i];\n\t\tif(ccode != 0) ctree[i] = bl_count[ccode+16]++;\n\t}\n\n\t/* cmap[maxlen + 4 bits] = (off&15) + (lit<<4) reverse mapping */\n\tvar cleni = 0;\n\tfor(i = 0; i < L; ++i) {\n\t\tcleni = clens[i];\n\t\tif(cleni != 0) {\n\t\t\tccode = bit_swap_n(ctree[i], maxlen)>>(maxlen-cleni);\n\t\t\tfor(j = (1<<(maxlen + 4 - cleni)) - 1; j>=0; --j)\n\t\t\t\tcmap[ccode|(j<<cleni)] = (cleni&15) | (i<<4);\n\t\t}\n\t}\n\treturn maxlen;\n}\n\n/* Fixed Huffman */\nvar fix_lmap = use_typed_arrays ? new Uint16Array(512) : zero_fill_array(512);\nvar fix_dmap = use_typed_arrays ? new Uint16Array(32) : zero_fill_array(32);\nif(!use_typed_arrays) {\n\tfor(var i = 0; i < 512; ++i) fix_lmap[i] = 0;\n\tfor(i = 0; i < 32; ++i) fix_dmap[i] = 0;\n}\n(function() {\n\tvar dlens = [];\n\tvar i = 0;\n\tfor(;i<32; i++) dlens.push(5);\n\tbuild_tree(dlens, fix_dmap, 32);\n\n\tvar clens = [];\n\ti = 0;\n\tfor(; i<=143; i++) clens.push(8);\n\tfor(; i<=255; i++) clens.push(9);\n\tfor(; i<=279; i++) clens.push(7);\n\tfor(; i<=287; i++) clens.push(8);\n\tbuild_tree(clens, fix_lmap, 288);\n})();var _deflateRaw = (function _deflateRawIIFE() {\n\tvar DST_LN_RE = use_typed_arrays ? new Uint8Array(0x8000) : [];\n\tvar j = 0, k = 0;\n\tfor(; j < DST_LN.length - 1; ++j) {\n\t\tfor(; k < DST_LN[j+1]; ++k) DST_LN_RE[k] = j;\n\t}\n\tfor(;k < 32768; ++k) DST_LN_RE[k] = 29;\n\n\tvar LEN_LN_RE = use_typed_arrays ? new Uint8Array(0x103) : [];\n\tfor(j = 0, k = 0; j < LEN_LN.length - 1; ++j) {\n\t\tfor(; k < LEN_LN[j+1]; ++k) LEN_LN_RE[k] = j;\n\t}\n\n\tfunction write_stored(data, out) {\n\t\tvar boff = 0;\n\t\twhile(boff < data.length) {\n\t\t\tvar L = Math.min(0xFFFF, data.length - boff);\n\t\t\tvar h = boff + L == data.length;\n\t\t\tout.write_shift(1, +h);\n\t\t\tout.write_shift(2, L);\n\t\t\tout.write_shift(2, (~L) & 0xFFFF);\n\t\t\twhile(L-- > 0) out[out.l++] = data[boff++];\n\t\t}\n\t\treturn out.l;\n\t}\n\n\t/* Fixed Huffman */\n\tfunction write_huff_fixed(data, out) {\n\t\tvar bl = 0;\n\t\tvar boff = 0;\n\t\tvar addrs = use_typed_arrays ? new Uint16Array(0x8000) : [];\n\t\twhile(boff < data.length) {\n\t\t\tvar L = /* data.length - boff; */ Math.min(0xFFFF, data.length - boff);\n\n\t\t\t/* write a stored block for short data */\n\t\t\tif(L < 10) {\n\t\t\t\tbl = write_bits_3(out, bl, +!!(boff + L == data.length)); // jshint ignore:line\n\t\t\t\tif(bl & 7) bl += 8 - (bl & 7);\n\t\t\t\tout.l = (bl / 8) | 0;\n\t\t\t\tout.write_shift(2, L);\n\t\t\t\tout.write_shift(2, (~L) & 0xFFFF);\n\t\t\t\twhile(L-- > 0) out[out.l++] = data[boff++];\n\t\t\t\tbl = out.l * 8;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tbl = write_bits_3(out, bl, +!!(boff + L == data.length) + 2); // jshint ignore:line\n\t\t\tvar hash = 0;\n\t\t\twhile(L-- > 0) {\n\t\t\t\tvar d = data[boff];\n\t\t\t\thash = ((hash << 5) ^ d) & 0x7FFF;\n\n\t\t\t\tvar match = -1, mlen = 0;\n\n\t\t\t\tif((match = addrs[hash])) {\n\t\t\t\t\tmatch |= boff & ~0x7FFF;\n\t\t\t\t\tif(match > boff) match -= 0x8000;\n\t\t\t\t\tif(match < boff) while(data[match + mlen] == data[boff + mlen] && mlen < 250) ++mlen;\n\t\t\t\t}\n\n\t\t\t\tif(mlen > 2) {\n\t\t\t\t\t/* Copy Token */\n\t\t\t\t\td = LEN_LN_RE[mlen];\n\t\t\t\t\tif(d <= 22) bl = write_bits_8(out, bl, bitswap8[d+1]>>1) - 1;\n\t\t\t\t\telse {\n\t\t\t\t\t\twrite_bits_8(out, bl, 3);\n\t\t\t\t\t\tbl += 5;\n\t\t\t\t\t\twrite_bits_8(out, bl, bitswap8[d-23]>>5);\n\t\t\t\t\t\tbl += 3;\n\t\t\t\t\t}\n\t\t\t\t\tvar len_eb = (d < 8) ? 0 : ((d - 4)>>2);\n\t\t\t\t\tif(len_eb > 0) {\n\t\t\t\t\t\twrite_bits_16(out, bl, mlen - LEN_LN[d]);\n\t\t\t\t\t\tbl += len_eb;\n\t\t\t\t\t}\n\n\t\t\t\t\td = DST_LN_RE[boff - match];\n\t\t\t\t\tbl = write_bits_8(out, bl, bitswap8[d]>>3);\n\t\t\t\t\tbl -= 3;\n\n\t\t\t\t\tvar dst_eb = d < 4 ? 0 : (d-2)>>1;\n\t\t\t\t\tif(dst_eb > 0) {\n\t\t\t\t\t\twrite_bits_16(out, bl, boff - match - DST_LN[d]);\n\t\t\t\t\t\tbl += dst_eb;\n\t\t\t\t\t}\n\t\t\t\t\tfor(var q = 0; q < mlen; ++q) {\n\t\t\t\t\t\taddrs[hash] = boff & 0x7FFF;\n\t\t\t\t\t\thash = ((hash << 5) ^ data[boff]) & 0x7FFF;\n\t\t\t\t\t\t++boff;\n\t\t\t\t\t}\n\t\t\t\t\tL-= mlen - 1;\n\t\t\t\t} else {\n\t\t\t\t\t/* Literal Token */\n\t\t\t\t\tif(d <= 143) d = d + 48;\n\t\t\t\t\telse bl = write_bits_1(out, bl, 1);\n\t\t\t\t\tbl = write_bits_8(out, bl, bitswap8[d]);\n\t\t\t\t\taddrs[hash] = boff & 0x7FFF;\n\t\t\t\t\t++boff;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tbl = write_bits_8(out, bl, 0) - 1;\n\t\t}\n\t\tout.l = ((bl + 7)/8)|0;\n\t\treturn out.l;\n\t}\n\treturn function _deflateRaw(data, out) {\n\t\tif(data.length < 8) return write_stored(data, out);\n\t\treturn write_huff_fixed(data, out);\n\t};\n})();\n\nfunction _deflate(data) {\n\tvar buf = new_buf(50+Math.floor(data.length*1.1));\n\tvar off = _deflateRaw(data, buf);\n\treturn buf.slice(0, off);\n}\n/* modified inflate function also moves original read head */\n\nvar dyn_lmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);\nvar dyn_dmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);\nvar dyn_cmap = use_typed_arrays ? new Uint16Array(128) : zero_fill_array(128);\nvar dyn_len_1 = 1, dyn_len_2 = 1;\n\n/* 5.5.3 Expanding Huffman Codes */\nfunction dyn(data, boff) {\n\t/* nomenclature from RFC1951 refers to bit values; these are offset by the implicit constant */\n\tvar _HLIT = read_bits_5(data, boff) + 257; boff += 5;\n\tvar _HDIST = read_bits_5(data, boff) + 1; boff += 5;\n\tvar _HCLEN = read_bits_4(data, boff) + 4; boff += 4;\n\tvar w = 0;\n\n\t/* grab and store code lengths */\n\tvar clens = use_typed_arrays ? new Uint8Array(19) : zero_fill_array(19);\n\tvar ctree = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];\n\tvar maxlen = 1;\n\tvar bl_count = use_typed_arrays ? new Uint8Array(8) : zero_fill_array(8);\n\tvar next_code = use_typed_arrays ? new Uint8Array(8) : zero_fill_array(8);\n\tvar L = clens.length; /* 19 */\n\tfor(var i = 0; i < _HCLEN; ++i) {\n\t\tclens[CLEN_ORDER[i]] = w = read_bits_3(data, boff);\n\t\tif(maxlen < w) maxlen = w;\n\t\tbl_count[w]++;\n\t\tboff += 3;\n\t}\n\n\t/* build code tree */\n\tvar ccode = 0;\n\tbl_count[0] = 0;\n\tfor(i = 1; i <= maxlen; ++i) next_code[i] = ccode = (ccode + bl_count[i-1])<<1;\n\tfor(i = 0; i < L; ++i) if((ccode = clens[i]) != 0) ctree[i] = next_code[ccode]++;\n\t/* cmap[7 bits from stream] = (off&7) + (lit<<3) */\n\tvar cleni = 0;\n\tfor(i = 0; i < L; ++i) {\n\t\tcleni = clens[i];\n\t\tif(cleni != 0) {\n\t\t\tccode = bitswap8[ctree[i]]>>(8-cleni);\n\t\t\tfor(var j = (1<<(7-cleni))-1; j>=0; --j) dyn_cmap[ccode|(j<<cleni)] = (cleni&7) | (i<<3);\n\t\t}\n\t}\n\n\t/* read literal and dist codes at once */\n\tvar hcodes = [];\n\tmaxlen = 1;\n\tfor(; hcodes.length < _HLIT + _HDIST;) {\n\t\tccode = dyn_cmap[read_bits_7(data, boff)];\n\t\tboff += ccode & 7;\n\t\tswitch((ccode >>>= 3)) {\n\t\t\tcase 16:\n\t\t\t\tw = 3 + read_bits_2(data, boff); boff += 2;\n\t\t\t\tccode = hcodes[hcodes.length - 1];\n\t\t\t\twhile(w-- > 0) hcodes.push(ccode);\n\t\t\t\tbreak;\n\t\t\tcase 17:\n\t\t\t\tw = 3 + read_bits_3(data, boff); boff += 3;\n\t\t\t\twhile(w-- > 0) hcodes.push(0);\n\t\t\t\tbreak;\n\t\t\tcase 18:\n\t\t\t\tw = 11 + read_bits_7(data, boff); boff += 7;\n\t\t\t\twhile(w -- > 0) hcodes.push(0);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\thcodes.push(ccode);\n\t\t\t\tif(maxlen < ccode) maxlen = ccode;\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\t/* build literal / length trees */\n\tvar h1 = hcodes.slice(0, _HLIT), h2 = hcodes.slice(_HLIT);\n\tfor(i = _HLIT; i < 286; ++i) h1[i] = 0;\n\tfor(i = _HDIST; i < 30; ++i) h2[i] = 0;\n\tdyn_len_1 = build_tree(h1, dyn_lmap, 286);\n\tdyn_len_2 = build_tree(h2, dyn_dmap, 30);\n\treturn boff;\n}\n\n/* return [ data, bytesRead ] */\nfunction inflate(data, usz) {\n\t/* shortcircuit for empty buffer [0x03, 0x00] */\n\tif(data[0] == 3 && !(data[1] & 0x3)) { return [new_raw_buf(usz), 2]; }\n\n\t/* bit offset */\n\tvar boff = 0;\n\n\t/* header includes final bit and type bits */\n\tvar header = 0;\n\n\tvar outbuf = new_unsafe_buf(usz ? usz : (1<<18));\n\tvar woff = 0;\n\tvar OL = outbuf.length>>>0;\n\tvar max_len_1 = 0, max_len_2 = 0;\n\n\twhile((header&1) == 0) {\n\t\theader = read_bits_3(data, boff); boff += 3;\n\t\tif((header >>> 1) == 0) {\n\t\t\t/* Stored block */\n\t\t\tif(boff & 7) boff += 8 - (boff&7);\n\t\t\t/* 2 bytes sz, 2 bytes bit inverse */\n\t\t\tvar sz = data[boff>>>3] | data[(boff>>>3)+1]<<8;\n\t\t\tboff += 32;\n\t\t\t/* push sz bytes */\n\t\t\tif(sz > 0) {\n\t\t\t\tif(!usz && OL < woff + sz) { outbuf = realloc(outbuf, woff + sz); OL = outbuf.length; }\n\t\t\t\twhile(sz-- > 0) { outbuf[woff++] = data[boff>>>3]; boff += 8; }\n\t\t\t}\n\t\t\tcontinue;\n\t\t} else if((header >> 1) == 1) {\n\t\t\t/* Fixed Huffman */\n\t\t\tmax_len_1 = 9; max_len_2 = 5;\n\t\t} else {\n\t\t\t/* Dynamic Huffman */\n\t\t\tboff = dyn(data, boff);\n\t\t\tmax_len_1 = dyn_len_1; max_len_2 = dyn_len_2;\n\t\t}\n\t\tfor(;;) { // while(true) is apparently out of vogue in modern JS circles\n\t\t\tif(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; }\n\t\t\t/* ingest code and move read head */\n\t\t\tvar bits = read_bits_n(data, boff, max_len_1);\n\t\t\tvar code = (header>>>1) == 1 ? fix_lmap[bits] : dyn_lmap[bits];\n\t\t\tboff += code & 15; code >>>= 4;\n\t\t\t/* 0-255 are literals, 256 is end of block token, 257+ are copy tokens */\n\t\t\tif(((code>>>8)&0xFF) === 0) outbuf[woff++] = code;\n\t\t\telse if(code == 256) break;\n\t\t\telse {\n\t\t\t\tcode -= 257;\n\t\t\t\tvar len_eb = (code < 8) ? 0 : ((code-4)>>2); if(len_eb > 5) len_eb = 0;\n\t\t\t\tvar tgt = woff + LEN_LN[code];\n\t\t\t\t/* length extra bits */\n\t\t\t\tif(len_eb > 0) {\n\t\t\t\t\ttgt += read_bits_n(data, boff, len_eb);\n\t\t\t\t\tboff += len_eb;\n\t\t\t\t}\n\n\t\t\t\t/* dist code */\n\t\t\t\tbits = read_bits_n(data, boff, max_len_2);\n\t\t\t\tcode = (header>>>1) == 1 ? fix_dmap[bits] : dyn_dmap[bits];\n\t\t\t\tboff += code & 15; code >>>= 4;\n\t\t\t\tvar dst_eb = (code < 4 ? 0 : (code-2)>>1);\n\t\t\t\tvar dst = DST_LN[code];\n\t\t\t\t/* dist extra bits */\n\t\t\t\tif(dst_eb > 0) {\n\t\t\t\t\tdst += read_bits_n(data, boff, dst_eb);\n\t\t\t\t\tboff += dst_eb;\n\t\t\t\t}\n\n\t\t\t\t/* in the common case, manual byte copy is faster than TA set / Buffer copy */\n\t\t\t\tif(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt + 100); OL = outbuf.length; }\n\t\t\t\twhile(woff < tgt) { outbuf[woff] = outbuf[woff - dst]; ++woff; }\n\t\t\t}\n\t\t}\n\t}\n\tif(usz) return [outbuf, (boff+7)>>>3];\n\treturn [outbuf.slice(0, woff), (boff+7)>>>3];\n}\n\nfunction _inflate(payload, usz) {\n\tvar data = payload.slice(payload.l||0);\n\tvar out = inflate(data, usz);\n\tpayload.l += out[1];\n\treturn out[0];\n}\n\nfunction warn_or_throw(wrn, msg) {\n\tif(wrn) { if(typeof console !== 'undefined') console.error(msg); }\n\telse throw new Error(msg);\n}\n\nfunction parse_zip(file, options) {\n\tvar blob = file;\n\tprep_blob(blob, 0);\n\n\tvar FileIndex = [], FullPaths = [];\n\tvar o = {\n\t\tFileIndex: FileIndex,\n\t\tFullPaths: FullPaths\n\t};\n\tinit_cfb(o, { root: options.root });\n\n\t/* find end of central directory, start just after signature */\n\tvar i = blob.length - 4;\n\twhile((blob[i] != 0x50 || blob[i+1] != 0x4b || blob[i+2] != 0x05 || blob[i+3] != 0x06) && i >= 0) --i;\n\tblob.l = i + 4;\n\n\t/* parse end of central directory */\n\tblob.l += 4;\n\tvar fcnt = blob.read_shift(2);\n\tblob.l += 6;\n\tvar start_cd = blob.read_shift(4);\n\n\t/* parse central directory */\n\tblob.l = start_cd;\n\n\tfor(i = 0; i < fcnt; ++i) {\n\t\t/* trust local file header instead of CD entry */\n\t\tblob.l += 20;\n\t\tvar csz = blob.read_shift(4);\n\t\tvar usz = blob.read_shift(4);\n\t\tvar namelen = blob.read_shift(2);\n\t\tvar efsz = blob.read_shift(2);\n\t\tvar fcsz = blob.read_shift(2);\n\t\tblob.l += 8;\n\t\tvar offset = blob.read_shift(4);\n\t\tvar EF = parse_extra_field(blob.slice(blob.l+namelen, blob.l+namelen+efsz));\n\t\tblob.l += namelen + efsz + fcsz;\n\n\t\tvar L = blob.l;\n\t\tblob.l = offset + 4;\n\t\tparse_local_file(blob, csz, usz, o, EF);\n\t\tblob.l = L;\n\t}\n\n\treturn o;\n}\n\n\n/* head starts just after local file header signature */\nfunction parse_local_file(blob, csz, usz, o, EF) {\n\t/* [local file header] */\n\tblob.l += 2;\n\tvar flags = blob.read_shift(2);\n\tvar meth = blob.read_shift(2);\n\tvar date = parse_dos_date(blob);\n\n\tif(flags & 0x2041) throw new Error(\"Unsupported ZIP encryption\");\n\tvar crc32 = blob.read_shift(4);\n\tvar _csz = blob.read_shift(4);\n\tvar _usz = blob.read_shift(4);\n\n\tvar namelen = blob.read_shift(2);\n\tvar efsz = blob.read_shift(2);\n\n\t// TODO: flags & (1<<11) // UTF8\n\tvar name = \"\"; for(var i = 0; i < namelen; ++i) name += String.fromCharCode(blob[blob.l++]);\n\tif(efsz) {\n\t\tvar ef = parse_extra_field(blob.slice(blob.l, blob.l + efsz));\n\t\tif((ef[0x5455]||{}).mt) date = ef[0x5455].mt;\n\t\tif(((EF||{})[0x5455]||{}).mt) date = EF[0x5455].mt;\n\t}\n\tblob.l += efsz;\n\n\t/* [encryption header] */\n\n\t/* [file data] */\n\tvar data = blob.slice(blob.l, blob.l + _csz);\n\tswitch(meth) {\n\t\tcase 8: data = _inflateRawSync(blob, _usz); break;\n\t\tcase 0: break; // TODO: scan for magic number\n\t\tdefault: throw new Error(\"Unsupported ZIP Compression method \" + meth);\n\t}\n\n\t/* [data descriptor] */\n\tvar wrn = false;\n\tif(flags & 8) {\n\t\tcrc32 = blob.read_shift(4);\n\t\tif(crc32 == 0x08074b50) { crc32 = blob.read_shift(4); wrn = true; }\n\t\t_csz = blob.read_shift(4);\n\t\t_usz = blob.read_shift(4);\n\t}\n\n\tif(_csz != csz) warn_or_throw(wrn, \"Bad compressed size: \" + csz + \" != \" + _csz);\n\tif(_usz != usz) warn_or_throw(wrn, \"Bad uncompressed size: \" + usz + \" != \" + _usz);\n\tvar _crc32 = CRC32.buf(data, 0);\n\tif((crc32>>0) != (_crc32>>0)) warn_or_throw(wrn, \"Bad CRC32 checksum: \" + crc32 + \" != \" + _crc32);\n\tcfb_add(o, name, data, {unsafe: true, mt: date});\n}\nfunction write_zip(cfb, options) {\n\tvar _opts = options || {};\n\tvar out = [], cdirs = [];\n\tvar o = new_buf(1);\n\tvar method = (_opts.compression ? 8 : 0), flags = 0;\n\tvar desc = false;\n\tif(desc) flags |= 8;\n\tvar i = 0, j = 0;\n\n\tvar start_cd = 0, fcnt = 0;\n\tvar root = cfb.FullPaths[0], fp = root, fi = cfb.FileIndex[0];\n\tvar crcs = [];\n\tvar sz_cd = 0;\n\n\tfor(i = 1; i < cfb.FullPaths.length; ++i) {\n\t\tfp = cfb.FullPaths[i].slice(root.length); fi = cfb.FileIndex[i];\n\t\tif(!fi.size || !fi.content || fp == \"\\u0001Sh33tJ5\") continue;\n\t\tvar start = start_cd;\n\n\t\t/* TODO: CP437 filename */\n\t\tvar namebuf = new_buf(fp.length);\n\t\tfor(j = 0; j < fp.length; ++j) namebuf.write_shift(1, fp.charCodeAt(j) & 0x7F);\n\t\tnamebuf = namebuf.slice(0, namebuf.l);\n\t\tcrcs[fcnt] = CRC32.buf(fi.content, 0);\n\n\t\tvar outbuf = fi.content;\n\t\tif(method == 8) outbuf = _deflateRawSync(outbuf);\n\n\t\t/* local file header */\n\t\to = new_buf(30);\n\t\to.write_shift(4, 0x04034b50);\n\t\to.write_shift(2, 20);\n\t\to.write_shift(2, flags);\n\t\to.write_shift(2, method);\n\t\t/* TODO: last mod file time/date */\n\t\tif(fi.mt) write_dos_date(o, fi.mt);\n\t\telse o.write_shift(4, 0);\n\t\to.write_shift(-4, (flags & 8) ? 0 : crcs[fcnt]);\n\t\to.write_shift(4, (flags & 8) ? 0 : outbuf.length);\n\t\to.write_shift(4, (flags & 8) ? 0 : fi.content.length);\n\t\to.write_shift(2, namebuf.length);\n\t\to.write_shift(2, 0);\n\n\t\tstart_cd += o.length;\n\t\tout.push(o);\n\t\tstart_cd += namebuf.length;\n\t\tout.push(namebuf);\n\n\t\t/* TODO: extra fields? */\n\n\t\t/* TODO: encryption header ? */\n\n\t\tstart_cd += outbuf.length;\n\t\tout.push(outbuf);\n\n\t\t/* data descriptor */\n\t\tif(flags & 8) {\n\t\t\to = new_buf(12);\n\t\t\to.write_shift(-4, crcs[fcnt]);\n\t\t\to.write_shift(4, outbuf.length);\n\t\t\to.write_shift(4, fi.content.length);\n\t\t\tstart_cd += o.l;\n\t\t\tout.push(o);\n\t\t}\n\n\t\t/* central directory */\n\t\to = new_buf(46);\n\t\to.write_shift(4, 0x02014b50);\n\t\to.write_shift(2, 0);\n\t\to.write_shift(2, 20);\n\t\to.write_shift(2, flags);\n\t\to.write_shift(2, method);\n\t\to.write_shift(4, 0); /* TODO: last mod file time/date */\n\t\to.write_shift(-4, crcs[fcnt]);\n\n\t\to.write_shift(4, outbuf.length);\n\t\to.write_shift(4, fi.content.length);\n\t\to.write_shift(2, namebuf.length);\n\t\to.write_shift(2, 0);\n\t\to.write_shift(2, 0);\n\t\to.write_shift(2, 0);\n\t\to.write_shift(2, 0);\n\t\to.write_shift(4, 0);\n\t\to.write_shift(4, start);\n\n\t\tsz_cd += o.l;\n\t\tcdirs.push(o);\n\t\tsz_cd += namebuf.length;\n\t\tcdirs.push(namebuf);\n\t\t++fcnt;\n\t}\n\n\t/* end of central directory */\n\to = new_buf(22);\n\to.write_shift(4, 0x06054b50);\n\to.write_shift(2, 0);\n\to.write_shift(2, 0);\n\to.write_shift(2, fcnt);\n\to.write_shift(2, fcnt);\n\to.write_shift(4, sz_cd);\n\to.write_shift(4, start_cd);\n\to.write_shift(2, 0);\n\n\treturn bconcat(([bconcat((out)), bconcat(cdirs), o]));\n}\nvar ContentTypeMap = ({\n\t\"htm\": \"text/html\",\n\t\"xml\": \"text/xml\",\n\n\t\"gif\": \"image/gif\",\n\t\"jpg\": \"image/jpeg\",\n\t\"png\": \"image/png\",\n\n\t\"mso\": \"application/x-mso\",\n\t\"thmx\": \"application/vnd.ms-officetheme\",\n\t\"sh33tj5\": \"application/octet-stream\"\n});\n\nfunction get_content_type(fi, fp) {\n\tif(fi.ctype) return fi.ctype;\n\n\tvar ext = fi.name || \"\", m = ext.match(/\\.([^\\.]+)$/);\n\tif(m && ContentTypeMap[m[1]]) return ContentTypeMap[m[1]];\n\n\tif(fp) {\n\t\tm = (ext = fp).match(/[\\.\\\\]([^\\.\\\\])+$/);\n\t\tif(m && ContentTypeMap[m[1]]) return ContentTypeMap[m[1]];\n\t}\n\n\treturn \"application/octet-stream\";\n}\n\n/* 76 character chunks TODO: intertwine encoding */\nfunction write_base64_76(bstr) {\n\tvar data = Base64_encode(bstr);\n\tvar o = [];\n\tfor(var i = 0; i < data.length; i+= 76) o.push(data.slice(i, i+76));\n\treturn o.join(\"\\r\\n\") + \"\\r\\n\";\n}\n\n/*\nRules for QP:\n\t- escape =## applies for all non-display characters and literal \"=\"\n\t- space or tab at end of line must be encoded\n\t- \\r\\n newlines can be preserved, but bare \\r and \\n must be escaped\n\t- lines must not exceed 76 characters, use soft breaks =\\r\\n\n\nTODO: Some files from word appear to write line extensions with bare equals:\n\n```\n<table class=3DMsoTableGrid border=3D1 cellspacing=3D0 cellpadding=3D0 width=\n=\"70%\"\n```\n*/\nfunction write_quoted_printable(text) {\n\tvar encoded = text.replace(/[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7E-\\xFF=]/g, function(c) {\n\t\tvar w = c.charCodeAt(0).toString(16).toUpperCase();\n\t\treturn \"=\" + (w.length == 1 ? \"0\" + w : w);\n\t});\n\n\tencoded = encoded.replace(/ $/mg, \"=20\").replace(/\\t$/mg, \"=09\");\n\n\tif(encoded.charAt(0) == \"\\n\") encoded = \"=0D\" + encoded.slice(1);\n\tencoded = encoded.replace(/\\r(?!\\n)/mg, \"=0D\").replace(/\\n\\n/mg, \"\\n=0A\").replace(/([^\\r\\n])\\n/mg, \"$1=0A\");\n\n\tvar o = [], split = encoded.split(\"\\r\\n\");\n\tfor(var si = 0; si < split.length; ++si) {\n\t\tvar str = split[si];\n\t\tif(str.length == 0) { o.push(\"\"); continue; }\n\t\tfor(var i = 0; i < str.length;) {\n\t\t\tvar end = 76;\n\t\t\tvar tmp = str.slice(i, i + end);\n\t\t\tif(tmp.charAt(end - 1) == \"=\") end --;\n\t\t\telse if(tmp.charAt(end - 2) == \"=\") end -= 2;\n\t\t\telse if(tmp.charAt(end - 3) == \"=\") end -= 3;\n\t\t\ttmp = str.slice(i, i + end);\n\t\t\ti += end;\n\t\t\tif(i < str.length) tmp += \"=\";\n\t\t\to.push(tmp);\n\t\t}\n\t}\n\n\treturn o.join(\"\\r\\n\");\n}\nfunction parse_quoted_printable(data) {\n\tvar o = [];\n\n\t/* unify long lines */\n\tfor(var di = 0; di < data.length; ++di) {\n\t\tvar line = data[di];\n\t\twhile(di <= data.length && line.charAt(line.length - 1) == \"=\") line = line.slice(0, line.length - 1) + data[++di];\n\t\to.push(line);\n\t}\n\n\t/* decode */\n\tfor(var oi = 0; oi < o.length; ++oi) o[oi] = o[oi].replace(/[=][0-9A-Fa-f]{2}/g, function($$) { return String.fromCharCode(parseInt($$.slice(1), 16)); });\n\treturn s2a(o.join(\"\\r\\n\"));\n}\n\n\nfunction parse_mime(cfb, data, root) {\n\tvar fname = \"\", cte = \"\", ctype = \"\", fdata;\n\tvar di = 0;\n\tfor(;di < 10; ++di) {\n\t\tvar line = data[di];\n\t\tif(!line || line.match(/^\\s*$/)) break;\n\t\tvar m = line.match(/^(.*?):\\s*([^\\s].*)$/);\n\t\tif(m) switch(m[1].toLowerCase()) {\n\t\t\tcase \"content-location\": fname = m[2].trim(); break;\n\t\t\tcase \"content-type\": ctype = m[2].trim(); break;\n\t\t\tcase \"content-transfer-encoding\": cte = m[2].trim(); break;\n\t\t}\n\t}\n\t++di;\n\tswitch(cte.toLowerCase()) {\n\t\tcase 'base64': fdata = s2a(Base64_decode(data.slice(di).join(\"\"))); break;\n\t\tcase 'quoted-printable': fdata = parse_quoted_printable(data.slice(di)); break;\n\t\tdefault: throw new Error(\"Unsupported Content-Transfer-Encoding \" + cte);\n\t}\n\tvar file = cfb_add(cfb, fname.slice(root.length), fdata, {unsafe: true});\n\tif(ctype) file.ctype = ctype;\n}\n\nfunction parse_mad(file, options) {\n\tif(a2s(file.slice(0,13)).toLowerCase() != \"mime-version:\") throw new Error(\"Unsupported MAD header\");\n\tvar root = (options && options.root || \"\");\n\t// $FlowIgnore\n\tvar data = (has_buf && Buffer.isBuffer(file) ? file.toString(\"binary\") : a2s(file)).split(\"\\r\\n\");\n\tvar di = 0, row = \"\";\n\n\t/* if root is not specified, scan for the common prefix */\n\tfor(di = 0; di < data.length; ++di) {\n\t\trow = data[di];\n\t\tif(!/^Content-Location:/i.test(row)) continue;\n\t\trow = row.slice(row.indexOf(\"file\"));\n\t\tif(!root) root = row.slice(0, row.lastIndexOf(\"/\") + 1);\n\t\tif(row.slice(0, root.length) == root) continue;\n\t\twhile(root.length > 0) {\n\t\t\troot = root.slice(0, root.length - 1);\n\t\t\troot = root.slice(0, root.lastIndexOf(\"/\") + 1);\n\t\t\tif(row.slice(0,root.length) == root) break;\n\t\t}\n\t}\n\n\tvar mboundary = (data[1] || \"\").match(/boundary=\"(.*?)\"/);\n\tif(!mboundary) throw new Error(\"MAD cannot find boundary\");\n\tvar boundary = \"--\" + (mboundary[1] || \"\");\n\n\tvar FileIndex = [], FullPaths = [];\n\tvar o = {\n\t\tFileIndex: FileIndex,\n\t\tFullPaths: FullPaths\n\t};\n\tinit_cfb(o);\n\tvar start_di, fcnt = 0;\n\tfor(di = 0; di < data.length; ++di) {\n\t\tvar line = data[di];\n\t\tif(line !== boundary && line !== boundary + \"--\") continue;\n\t\tif(fcnt++) parse_mime(o, data.slice(start_di, di), root);\n\t\tstart_di = di;\n\t}\n\treturn o;\n}\n\nfunction write_mad(cfb, options) {\n\tvar opts = options || {};\n\tvar boundary = opts.boundary || \"SheetJS\";\n\tboundary = '------=' + boundary;\n\n\tvar out = [\n\t\t'MIME-Version: 1.0',\n\t\t'Content-Type: multipart/related; boundary=\"' + boundary.slice(2) + '\"',\n\t\t'',\n\t\t'',\n\t\t''\n\t];\n\n\tvar root = cfb.FullPaths[0], fp = root, fi = cfb.FileIndex[0];\n\tfor(var i = 1; i < cfb.FullPaths.length; ++i) {\n\t\tfp = cfb.FullPaths[i].slice(root.length);\n\t\tfi = cfb.FileIndex[i];\n\t\tif(!fi.size || !fi.content || fp == \"\\u0001Sh33tJ5\") continue;\n\n\t\t/* Normalize filename */\n\t\tfp = fp.replace(/[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7E-\\xFF]/g, function(c) {\n\t\t\treturn \"_x\" + c.charCodeAt(0).toString(16) + \"_\";\n\t\t}).replace(/[\\u0080-\\uFFFF]/g, function(u) {\n\t\t\treturn \"_u\" + u.charCodeAt(0).toString(16) + \"_\";\n\t\t});\n\n\t\t/* Extract content as binary string */\n\t\tvar ca = fi.content;\n\t\t// $FlowIgnore\n\t\tvar cstr = has_buf && Buffer.isBuffer(ca) ? ca.toString(\"binary\") : a2s(ca);\n\n\t\t/* 4/5 of first 1024 chars ascii -> quoted printable, else base64 */\n\t\tvar dispcnt = 0, L = Math.min(1024, cstr.length), cc = 0;\n\t\tfor(var csl = 0; csl <= L; ++csl) if((cc=cstr.charCodeAt(csl)) >= 0x20 && cc < 0x80) ++dispcnt;\n\t\tvar qp = dispcnt >= L * 4 / 5;\n\n\t\tout.push(boundary);\n\t\tout.push('Content-Location: ' + (opts.root || 'file:///C:/SheetJS/') + fp);\n\t\tout.push('Content-Transfer-Encoding: ' + (qp ? 'quoted-printable' : 'base64'));\n\t\tout.push('Content-Type: ' + get_content_type(fi, fp));\n\t\tout.push('');\n\n\t\tout.push(qp ? write_quoted_printable(cstr) : write_base64_76(cstr));\n\t}\n\tout.push(boundary + '--\\r\\n');\n\treturn out.join(\"\\r\\n\");\n}\nfunction cfb_new(opts) {\n\tvar o = ({});\n\tinit_cfb(o, opts);\n\treturn o;\n}\n\nfunction cfb_add(cfb, name, content, opts) {\n\tvar unsafe = opts && opts.unsafe;\n\tif(!unsafe) init_cfb(cfb);\n\tvar file = !unsafe && CFB.find(cfb, name);\n\tif(!file) {\n\t\tvar fpath = cfb.FullPaths[0];\n\t\tif(name.slice(0, fpath.length) == fpath) fpath = name;\n\t\telse {\n\t\t\tif(fpath.slice(-1) != \"/\") fpath += \"/\";\n\t\t\tfpath = (fpath + name).replace(\"//\",\"/\");\n\t\t}\n\t\tfile = ({name: filename(name), type: 2});\n\t\tcfb.FileIndex.push(file);\n\t\tcfb.FullPaths.push(fpath);\n\t\tif(!unsafe) CFB.utils.cfb_gc(cfb);\n\t}\nfile.content = (content);\n\tfile.size = content ? content.length : 0;\n\tif(opts) {\n\t\tif(opts.CLSID) file.clsid = opts.CLSID;\n\t\tif(opts.mt) file.mt = opts.mt;\n\t\tif(opts.ct) file.ct = opts.ct;\n\t}\n\treturn file;\n}\n\nfunction cfb_del(cfb, name) {\n\tinit_cfb(cfb);\n\tvar file = CFB.find(cfb, name);\n\tif(file) for(var j = 0; j < cfb.FileIndex.length; ++j) if(cfb.FileIndex[j] == file) {\n\t\tcfb.FileIndex.splice(j, 1);\n\t\tcfb.FullPaths.splice(j, 1);\n\t\treturn true;\n\t}\n\treturn false;\n}\n\nfunction cfb_mov(cfb, old_name, new_name) {\n\tinit_cfb(cfb);\n\tvar file = CFB.find(cfb, old_name);\n\tif(file) for(var j = 0; j < cfb.FileIndex.length; ++j) if(cfb.FileIndex[j] == file) {\n\t\tcfb.FileIndex[j].name = filename(new_name);\n\t\tcfb.FullPaths[j] = new_name;\n\t\treturn true;\n\t}\n\treturn false;\n}\n\nfunction cfb_gc(cfb) { rebuild_cfb(cfb, true); }\n\nexports.find = find;\nexports.read = read;\nexports.parse = parse;\nexports.write = write;\nexports.writeFile = write_file;\nexports.utils = {\n\tcfb_new: cfb_new,\n\tcfb_add: cfb_add,\n\tcfb_del: cfb_del,\n\tcfb_mov: cfb_mov,\n\tcfb_gc: cfb_gc,\n\tReadShift: ReadShift,\n\tCheckField: CheckField,\n\tprep_blob: prep_blob,\n\tbconcat: bconcat,\n\tuse_zlib: use_zlib,\n\t_deflateRaw: _deflate,\n\t_inflateRaw: _inflate,\n\tconsts: consts\n};\n\nreturn exports;\n})();\n\nif(typeof require !== 'undefined' && typeof module !== 'undefined' && typeof DO_NOT_EXPORT_CFB === 'undefined') { module.exports = CFB; }\n","/**\n * OCR CLI 자동 탐색\n *\n * 탐색 순서: gemini → codex → claude → ollama → tesseract.js\n * CLI는 which(unix) / where(win) 명령어로 PATH 존재 확인.\n * tesseract.js는 bundled 의존성이므로 항상 사용 가능 (최후 fallback).\n */\n\nimport { execSync } from \"child_process\"\nimport type { OcrMode } from \"../types.js\"\n\n/** CLI 탐색 우선순위 */\nconst CLI_PRIORITY = [\"gemini\", \"codex\", \"claude\", \"ollama\"] as const\n\n/**\n * 시스템에 설치된 OCR 도구를 우선순위대로 탐색.\n * tesseract.js는 bundled 의존성이므로 CLI를 찾지 못해도 항상 \"tesseract\" 반환.\n * @returns 사용 가능한 OcrMode (null 반환 없음)\n */\nexport function detectAvailableOcr(): OcrMode {\n // 1. CLI 프로그램 탐색 (gemini → codex → claude → ollama)\n for (const cli of CLI_PRIORITY) {\n if (isCliInstalled(cli)) return cli\n }\n\n // 2. tesseract.js — bundled 의존성, 항상 사용 가능\n return \"tesseract\"\n}\n\n/**\n * 특정 CLI가 시스템 PATH에 있는지 확인.\n * which(unix) 또는 where(win32) 사용.\n */\nfunction isCliInstalled(name: string): boolean {\n try {\n const cmd = process.platform === \"win32\" ? \"where\" : \"which\"\n execSync(`${cmd} ${name}`, { stdio: \"ignore\", timeout: 3000 })\n return true\n } catch {\n return false\n }\n}\n\n/**\n * 수동 지정된 OcrMode 유효성 검증.\n * --ocr gemini 등 강제 지정 시 호출.\n * @throws 해당 CLI가 설치되지 않은 경우 Error (tesseract는 항상 통과)\n */\nexport function validateOcrMode(mode: OcrMode): void {\n if (mode === \"auto\" || mode === \"off\" || mode === \"tesseract\") return\n\n if (!isCliInstalled(mode)) {\n throw new Error(`'${mode}' CLI가 설치되지 않았습니다.\\n${getInstallGuide(mode)}`)\n }\n}\n\n/** CLI별 설치 안내 메시지 */\nfunction getInstallGuide(mode: string): string {\n const guides: Record<string, string> = {\n gemini: \"설치: https://ai.google.dev/gemini-api/docs/cli\",\n claude: \"설치: npm install -g @anthropic-ai/claude-code 또는 https://claude.ai/code\",\n codex: \"설치: npm install -g @openai/codex 또는 https://github.com/openai/codex\",\n ollama: \"설치: brew install ollama 또는 https://ollama.com/download\",\n }\n return guides[mode] || `'${mode}'을(를) 설치해주세요.`\n}\n\n/**\n * AI CLI가 없어 tesseract.js로 fallback할 때 표시할 안내 메시지.\n */\nexport function getTesseractFallbackMessage(): string {\n return [\n \"설치된 AI CLI가 없어 내장 tesseract.js로 OCR을 수행합니다.\",\n \"더 나은 품질(테이블/헤딩 구조 보존)을 위해 AI CLI 설치를 권장합니다:\",\n \"\",\n \" [권장] Gemini CLI: https://ai.google.dev/gemini-api/docs/cli\",\n \" Codex CLI: npm install -g @openai/codex\",\n \" Claude CLI: npm install -g @anthropic-ai/claude-code\",\n \" Ollama: brew install ollama (+ ollama pull gemma4:27b)\",\n ].join(\"\\n\")\n}\n","/**\n * CLI 기반 OCR 프로바이더\n *\n * gemini / claude / codex / ollama CLI를 subprocess로 호출하여\n * PDF 페이지 이미지를 Markdown으로 변환.\n *\n * 이미지 전달 방식:\n * - gemini: -p \"프롬프트 @이미지경로\" (@ 파일 참조)\n * - claude: -p \"프롬프트 @이미지경로\" (@ 파일 참조, --print 모드)\n * - codex: exec -i 이미지경로 \"프롬프트\" (-i/--image 플래그)\n * - ollama: REST API (localhost:11434) — CLI는 이미지 입력 미지원\n */\n\nimport { spawnSync } from \"child_process\"\nimport { writeFileSync, readFileSync, unlinkSync, mkdirSync } from \"fs\"\nimport { join } from \"path\"\nimport { tmpdir } from \"os\"\nimport type { OcrMode, StructuredOcrResult } from \"../types.js\"\n\n/** OCR 프롬프트 — 모든 CLI 공통 */\nconst OCR_PROMPT =\n \"이 PDF 페이지 이미지에서 텍스트와 테이블을 추출하여 순수 Markdown으로 변환하세요.\\n\" +\n \"규칙:\\n\" +\n \"- 테이블은 Markdown 테이블 문법 사용 (| 구분, |---|---| 헤더 구분선 포함)\\n\" +\n \"- 병합된 셀은 해당 위치에 내용 기재\\n\" +\n \"- 헤딩은 글자 크기에 따라 ## ~ ###### 사용\\n\" +\n \"- 리스트는 - 또는 1. 사용\\n\" +\n \"- 이미지, 도형 등 비텍스트 요소는 무시\\n\" +\n \"- 원문의 읽기 순서와 구조를 유지\\n\" +\n \"- ```로 감싸지 말고 순수 Markdown만 출력\"\n\n/** 임시 디렉토리 (프로세스당 1회 생성)\n *\n * gemini CLI는 /tmp/ 등 시스템 임시 디렉토리를 워크스페이스 외부로 간주하여\n * @파일참조 시 접근을 거부할 수 있음. cwd 하위 폴더를 사용하면 모든 CLI에서 접근 가능.\n */\nlet _tempDir: string | null = null\nfunction getTempDir(): string {\n if (!_tempDir) {\n _tempDir = join(process.cwd(), \".kordoc-tmp\")\n mkdirSync(_tempDir, { recursive: true })\n }\n return _tempDir\n}\n\n/**\n * CLI OcrProvider 생성.\n *\n * @param mode - 사용할 CLI (gemini, claude, codex, ollama)\n * @returns OcrProvider 함수 (StructuredOcrResult 반환)\n */\nexport function createCliOcrProvider(\n mode: Exclude<OcrMode, \"auto\" | \"off\" | \"tesseract\">\n): (pageImage: Uint8Array, pageNumber: number, mimeType: \"image/png\") => Promise<StructuredOcrResult> {\n return async (pageImage: Uint8Array, pageNumber: number): Promise<StructuredOcrResult> => {\n const tempPath = join(getTempDir(), `page-${pageNumber}.png`)\n\n try {\n writeFileSync(tempPath, pageImage)\n\n let output: string\n if (mode === \"ollama\") {\n output = await callOllamaApi(tempPath)\n } else {\n output = callCli(mode, tempPath)\n }\n\n return { markdown: stripCodeFence(output.trim()) }\n } finally {\n try { unlinkSync(tempPath) } catch { /* 임시 파일 정리 실패 무시 */ }\n }\n }\n}\n\n/**\n * CLI 실행 — gemini / claude / codex\n *\n * @throws CLI 실행 실패 또는 타임아웃(60초) 시 Error\n */\nfunction callCli(mode: string, imagePath: string): string {\n // codex는 --output-last-message로 대화 헤더 없는 깔끔한 출력 사용\n if (mode === \"codex\") {\n return callCodexCli(imagePath)\n }\n\n const args = buildCliArgs(mode, imagePath)\n\n const result = spawnSync(mode, args, {\n encoding: \"utf-8\",\n timeout: 60_000,\n maxBuffer: 10 * 1024 * 1024,\n })\n\n if (result.error) {\n throw new Error(`${mode} CLI 실행 실패: ${result.error.message}`)\n }\n if (result.status !== 0) {\n const errMsg = result.stderr?.trim() || `exit code ${result.status}`\n throw new Error(`${mode} OCR 실패: ${errMsg}`)\n }\n\n return result.stdout || \"\"\n}\n\n/**\n * codex exec 실행 — --output-last-message로 대화 헤더 없는 깔끔한 출력.\n * 인자 순서: `codex exec <prompt> --image <file> --output-last-message <outfile>`\n */\nfunction callCodexCli(imagePath: string): string {\n // 출력 파일은 /tmp/ 사용 — codex sandbox는 cwd 내 쓰기를 막을 수 있음\n const outPath = join(tmpdir(), `kordoc-codex-out-${Date.now()}.txt`)\n try {\n const args = [\"exec\", OCR_PROMPT, \"--image\", imagePath, \"--output-last-message\", outPath]\n const model = process.env.KORDOC_CODEX_MODEL\n if (model) args.push(\"--model\", model)\n\n const result = spawnSync(\"codex\", args, {\n encoding: \"utf-8\",\n timeout: 180_000,\n maxBuffer: 10 * 1024 * 1024,\n input: \"\", // stdin EOF 즉시 전달 (대화형 입력 차단)\n })\n\n if (result.error) {\n throw new Error(`codex CLI 실행 실패: ${result.error.message}`)\n }\n if (result.status !== 0) {\n const errMsg = result.stderr?.trim() || `exit code ${result.status}`\n throw new Error(`codex OCR 실패: ${errMsg}`)\n }\n\n // --output-last-message 파일에서 읽기 (없으면 stdout 폴백)\n try {\n return readFileSync(outPath, \"utf-8\")\n } catch {\n return result.stdout || \"\"\n }\n } finally {\n try { unlinkSync(outPath) } catch { /* 무시 */ }\n }\n}\n\n/**\n * CLI별 인자 배열 생성.\n *\n * gemini: [\"--prompt\", \"프롬프트 @이미지경로\", \"--yolo\"]\n * - -y/--yolo: 자동 승인 (OCR은 도구 사용 없으므로 실질적 영향 없음)\n * - @ 파일 참조로 이미지를 컨텍스트에 포함\n *\n * claude: [\"--print\", \"프롬프트 @이미지경로\"]\n * - --print(-p): 비대화형 출력 모드\n * - @ 파일 참조로 이미지를 컨텍스트에 포함\n *\n * codex: callCodexCli()에서 별도 처리\n * - `codex exec <prompt> --image <file> --output-last-message <outfile>`\n * - 프롬프트가 --image보다 앞에 위치해야 함 (인자 순서 중요)\n *\n * ⚠️ CLI 버전에 따라 문법이 다를 수 있음. 업데이트 시 --help 재확인 필요.\n */\nfunction buildCliArgs(mode: string, imagePath: string): string[] {\n const promptWithImage = `${OCR_PROMPT}\\n\\n이미지: @${imagePath}`\n\n switch (mode) {\n case \"gemini\": {\n const args = [\"--prompt\", promptWithImage, \"--yolo\"]\n const model = process.env.KORDOC_GEMINI_MODEL\n if (model) args.push(\"--model\", model)\n return args\n }\n\n case \"claude\": {\n const args = [\"--print\", promptWithImage]\n const model = process.env.KORDOC_CLAUDE_MODEL\n if (model) args.push(\"--model\", model)\n return args\n }\n\n default:\n throw new Error(`지원하지 않는 CLI: ${mode}`)\n }\n}\n\n/**\n * Ollama REST API 호출 — CLI는 이미지 입력을 지원하지 않으므로 API 직접 사용.\n *\n * 기본 모델: KORDOC_OLLAMA_MODEL 환경변수 또는 \"gemma4:27b\"\n * 기본 호스트: KORDOC_OLLAMA_HOST 환경변수 또는 \"http://localhost:11434\"\n *\n * @throws Ollama 서버 미실행 또는 응답 오류 시 Error\n */\nasync function callOllamaApi(imagePath: string): Promise<string> {\n const { readFileSync } = await import(\"fs\")\n const imageBase64 = readFileSync(imagePath).toString(\"base64\")\n\n const model = process.env.KORDOC_OLLAMA_MODEL || \"qwen3-vl:8b\"\n const host = process.env.KORDOC_OLLAMA_HOST || \"http://localhost:11434\"\n const timeoutMs = Number(process.env.KORDOC_OLLAMA_TIMEOUT) || 120_000\n\n const response = await fetch(`${host}/api/chat`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n model,\n messages: [{\n role: \"user\",\n content: OCR_PROMPT,\n images: [imageBase64],\n }],\n stream: false,\n }),\n signal: AbortSignal.timeout(timeoutMs),\n })\n\n if (!response.ok) {\n throw new Error(`Ollama API 오류: ${response.status} ${response.statusText}`)\n }\n\n const data = await response.json() as { message?: { content?: string } }\n return data.message?.content || \"\"\n}\n\n/**\n * LLM 출력에서 코드 펜스 제거.\n * LLM이 가끔 결과를 ```markdown ... ``` 으로 감싸는 경우 처리.\n */\nfunction stripCodeFence(text: string): string {\n const match = text.match(/^```(?:markdown|md)?\\s*\\n([\\s\\S]*?)\\n```\\s*$/m)\n return match ? match[1].trim() : text\n}\n","/**\n * Tesseract.js 기반 OCR 프로바이더\n *\n * tesseract.js는 bundled 의존성으로 별도 설치 불필요.\n * Vision LLM CLI가 없을 때의 최후 fallback으로 자동 사용.\n *\n * 특성:\n * - 순수 텍스트만 반환 (테이블/헤딩 구조 복원 불가)\n * - 한글 인식률 약 85-90% (깨끗한 이미지 기준)\n * - 완전 오프라인 동작 (API 키 불필요)\n */\n\nimport { createWorker } from \"tesseract.js\"\nimport type { OcrProvider } from \"../types.js\"\n\n/**\n * Tesseract.js OcrProvider 생성.\n *\n * 워커를 1회 생성하여 재사용 (매 페이지마다 초기화 방지).\n * 문서 처리 완료 후 terminate()로 워커 정리.\n *\n * @returns OcrProvider 함수 (+ terminate 메서드)\n */\nexport async function createTesseractProvider(): Promise<OcrProvider & { terminate: () => Promise<void> }> {\n // kor+eng: 한글 + 영문 동시 인식 (한국 공문서 특성)\n const worker = await createWorker(\"kor+eng\")\n let terminated = false\n\n const provider = async (\n pageImage: Uint8Array,\n _pageNumber: number,\n _mimeType: \"image/png\"\n ): Promise<string> => {\n const { data } = await worker.recognize(pageImage)\n return data.text\n }\n\n ;(provider as OcrProvider & { terminate: () => Promise<void> }).terminate = async () => {\n if (!terminated) {\n await worker.terminate()\n terminated = true\n }\n }\n\n return provider as OcrProvider & { terminate: () => Promise<void> }\n}\n","/**\n * OCR 프로바이더 팩토리\n *\n * ocrMode에 따라 적절한 OcrProvider를 생성하여 반환.\n * - \"auto\": 설치된 CLI 자동 탐색 (gemini → claude → codex → ollama → tesseract)\n * tesseract.js는 bundled 의존성이므로 항상 사용 가능 (null 반환 없음)\n * - 특정 CLI: 해당 CLI 사용 (미설치 시 에러)\n * - \"tesseract\": 내장 tesseract.js 직접 사용\n * - \"off\": 에러 throw\n */\n\nimport type { OcrMode, OcrProvider, ParseWarning } from \"../types.js\"\nimport { detectAvailableOcr, validateOcrMode, getTesseractFallbackMessage } from \"./auto-detect.js\"\nimport { createCliOcrProvider } from \"./cli-provider.js\"\n\n/**\n * ocrMode에 따라 OcrProvider를 생성.\n *\n * @param mode - OCR 모드\n * @param warnings - 경고 수집 배열 (fallback 발생 시 경고 추가)\n * @returns OcrProvider 함수\n * @throws mode=\"off\"이거나 지정 CLI 미설치 시 Error\n */\nexport async function resolveOcrProvider(\n mode: OcrMode,\n warnings?: ParseWarning[]\n): Promise<OcrProvider> {\n if (mode === \"off\") {\n throw new Error(\"OCR이 비활성화되어 있습니다 (--ocr off).\")\n }\n\n // ── 수동 지정 모드 ──────────────────────────────────\n if (mode !== \"auto\") {\n validateOcrMode(mode) // tesseract는 항상 통과\n\n if (mode === \"tesseract\") {\n const { createTesseractProvider } = await import(\"./tesseract-provider.js\")\n return createTesseractProvider()\n }\n\n return createCliOcrProvider(mode)\n }\n\n // ── 자동 탐색 모드 ───────────────────────────────────\n // detectAvailableOcr()는 항상 값을 반환 (tesseract fallback으로 null 없음)\n const detected = detectAvailableOcr()\n\n // gemini가 아닌 경우 fallback 경고\n if (detected !== \"gemini\") {\n if (detected === \"tesseract\") {\n // 내장 tesseract로 fallback — 구조 복원 제한 안내\n warnings?.push({\n message: getTesseractFallbackMessage(),\n code: \"OCR_CLI_FALLBACK\",\n })\n } else {\n warnings?.push({\n message: `OCR: '${detected}' 사용 중 (gemini CLI가 없어 fallback). 더 나은 품질을 위해 gemini CLI 설치를 권장합니다.`,\n code: \"OCR_CLI_FALLBACK\",\n })\n }\n }\n\n if (detected === \"tesseract\") {\n const { createTesseractProvider } = await import(\"./tesseract-provider.js\")\n return createTesseractProvider()\n }\n\n return createCliOcrProvider(detected)\n}\n","/**\n * Markdown → IRBlock[] 역파싱\n *\n * Vision LLM(gemini/claude/codex 등)이 반환한 Markdown 문자열을\n * kordoc의 IRBlock[] 중간 표현으로 변환.\n * 기존 blocksToMarkdown()의 역방향 처리.\n */\n\nimport type { IRBlock, IRTable, IRCell } from \"../types.js\"\n\n/**\n * Markdown 문자열을 IRBlock[] 배열로 변환.\n *\n * 지원 요소:\n * - 헤딩: # ~ ######\n * - 테이블: | col1 | col2 | (파이프 구분, |---|---| 구분선 포함)\n * - 순서/비순서 리스트: - / 1.\n * - 구분선: ---, ***, ___\n * - 일반 텍스트 (paragraph)\n */\nexport function markdownToBlocks(markdown: string, pageNumber: number): IRBlock[] {\n const blocks: IRBlock[] = []\n const lines = markdown.split(\"\\n\")\n let i = 0\n\n while (i < lines.length) {\n const line = lines[i]\n\n // 빈 줄 스킵\n if (line.trim() === \"\") {\n i++\n continue\n }\n\n // 1. 헤딩: # ~ ######\n const headingMatch = line.match(/^(#{1,6})\\s+(.+)$/)\n if (headingMatch) {\n blocks.push({\n type: \"heading\",\n level: headingMatch[1].length,\n text: headingMatch[2].trim(),\n pageNumber,\n })\n i++\n continue\n }\n\n // 2. 구분선: ---, ***, ___\n if (/^[-*_]{3,}\\s*$/.test(line.trim())) {\n blocks.push({ type: \"separator\", pageNumber })\n i++\n continue\n }\n\n // 3. 테이블: | 로 시작하는 연속 행 수집\n if (line.trim().startsWith(\"|\")) {\n const tableLines: string[] = []\n while (i < lines.length && lines[i].trim().startsWith(\"|\")) {\n tableLines.push(lines[i])\n i++\n }\n const table = parseMarkdownTable(tableLines)\n if (table) {\n blocks.push({ type: \"table\", table, pageNumber })\n }\n continue\n }\n\n // 4. 비순서 리스트: -, *, +\n const ulMatch = line.match(/^(\\s*)[-*+]\\s+(.+)$/)\n if (ulMatch) {\n blocks.push({\n type: \"list\",\n listType: \"unordered\",\n text: ulMatch[2].trim(),\n pageNumber,\n })\n i++\n continue\n }\n\n // 5. 순서 리스트: 1.\n const olMatch = line.match(/^(\\s*)\\d+\\.\\s+(.+)$/)\n if (olMatch) {\n blocks.push({\n type: \"list\",\n listType: \"ordered\",\n text: olMatch[2].trim(),\n pageNumber,\n })\n i++\n continue\n }\n\n // 6. 일반 텍스트 — 구조적 행이 나올 때까지 병합\n const paraLines: string[] = []\n while (i < lines.length && lines[i].trim() !== \"\" && !isStructuralLine(lines[i])) {\n paraLines.push(lines[i].trim())\n i++\n }\n if (paraLines.length > 0) {\n blocks.push({\n type: \"paragraph\",\n text: paraLines.join(\"\\n\"),\n pageNumber,\n })\n }\n }\n\n return blocks\n}\n\n/**\n * 구조적 행 판별 — paragraph 병합 중단 트리거.\n */\nfunction isStructuralLine(line: string): boolean {\n if (/^#{1,6}\\s+/.test(line)) return true\n if (line.trim().startsWith(\"|\")) return true\n if (/^[-*_]{3,}\\s*$/.test(line.trim())) return true\n if (/^\\s*[-*+]\\s+/.test(line)) return true\n if (/^\\s*\\d+\\.\\s+/.test(line)) return true\n return false\n}\n\n/**\n * Markdown 테이블 행 배열을 IRTable로 변환.\n *\n * 구분선 행(|---|---|)은 제거 후 데이터 행만 파싱.\n * hasHeader: 구분선이 있었으면 true.\n */\nfunction parseMarkdownTable(lines: string[]): IRTable | null {\n const hasSeparator = lines.some(line => /^\\|[\\s:|-]+\\|$/.test(line.trim()))\n\n const rows: IRCell[][] = []\n let maxCols = 0\n\n for (const line of lines) {\n // 구분선 행 스킵: |---|---| 패턴\n if (/^\\|\\s*:?-+:?\\s*(\\|\\s*:?-+:?\\s*)+\\|?\\s*$/.test(line.trim())) continue\n\n const parts = line.split(\"|\")\n // 앞뒤 빈 요소 제거 (| 로 시작/종료하는 행)\n const cells: IRCell[] = parts\n .slice(1, parts[parts.length - 1].trim() === \"\" ? -1 : undefined)\n .map(cell => ({\n text: cell.trim(),\n colSpan: 1,\n rowSpan: 1,\n }))\n\n if (cells.length > 0) {\n rows.push(cells)\n maxCols = Math.max(maxCols, cells.length)\n }\n }\n\n if (rows.length === 0) return null\n\n // 열 수 통일 (부족한 셀은 빈 셀로 채움)\n for (const row of rows) {\n while (row.length < maxCols) {\n row.push({ text: \"\", colSpan: 1, rowSpan: 1 })\n }\n }\n\n return {\n rows: rows.length,\n cols: maxCols,\n cells: rows,\n hasHeader: hasSeparator && rows.length > 1,\n }\n}\n","/**\n * OCR 프로바이더 브릿지 — PDF 페이지를 이미지로 렌더링하여 OCR 호출\n *\n * kordoc은 OCR 라이브러리를 번들하지 않음.\n * 사용자가 OcrProvider 함수를 제공하면 이미지 기반 PDF도 텍스트 추출 가능.\n *\n * @example\n * ```ts\n * import { parse } from \"kordoc\"\n *\n * const result = await parse(buffer, {\n * ocr: async (pageImage, pageNumber, mimeType) => {\n * // Tesseract, Claude Vision, Google Vision 등 사용\n * return await myOcrService.recognize(pageImage)\n * }\n * })\n * ```\n */\n\nimport type { OcrProvider, IRBlock, ParseWarning, StructuredOcrResult } from \"../types.js\"\nimport { markdownToBlocks } from \"./markdown-to-blocks.js\"\n\n/**\n * 이미지 기반 PDF 페이지에 OCR을 적용하여 IRBlock[] 반환.\n *\n * pdfjs page 객체에서 viewport + render를 통해 PNG 생성 후\n * 사용자 제공 OcrProvider 호출.\n *\n * - string 반환: 단순 텍스트 → paragraph 블록\n * - StructuredOcrResult 반환: Markdown → markdownToBlocks()로 구조화\n *\n * canvas 미설치 시 pdfjs render 불가하므로 에러 반환.\n */\nexport async function ocrPages(\n doc: { numPages: number; getPage(n: number): Promise<PdfPageProxy> },\n provider: OcrProvider,\n pageFilter: Set<number> | null,\n effectivePageCount: number,\n warnings?: ParseWarning[]\n): Promise<IRBlock[]> {\n const blocks: IRBlock[] = []\n\n for (let i = 1; i <= effectivePageCount; i++) {\n if (pageFilter && !pageFilter.has(i)) continue\n const page = await doc.getPage(i)\n try {\n const imageData = await renderPageToPng(page)\n const result = await provider(imageData, i, \"image/png\")\n\n if (typeof result === \"string\") {\n // 기존 동작: 순수 텍스트 → paragraph 블록\n if (result.trim()) {\n blocks.push({ type: \"paragraph\", text: result.trim(), pageNumber: i })\n }\n } else if (result && typeof result === \"object\" && \"markdown\" in result) {\n // 신규: 구조화된 결과 → Markdown → IRBlock[]\n const structured = result as StructuredOcrResult\n if (structured.markdown.trim()) {\n const pageBlocks = markdownToBlocks(structured.markdown, i)\n for (const b of pageBlocks) blocks.push(b)\n }\n }\n } catch (err) {\n // 개별 페이지 실패 시 경고 발행 후 계속 진행\n warnings?.push({\n page: i,\n message: `페이지 ${i} OCR 실패: ${err instanceof Error ? err.message : \"알 수 없는 오류\"}`,\n code: \"OCR_PAGE_FAILED\",\n })\n }\n }\n\n return blocks\n}\n\ninterface PdfPageProxy {\n getViewport(params: { scale: number }): { width: number; height: number }\n render(params: { canvasContext: unknown; viewport: unknown }): { promise: Promise<void> }\n}\n\n/**\n * PDF 페이지를 PNG로 렌더링.\n * @napi-rs/canvas 사용 (kordoc 번들 의존성, 별도 설치 불필요)\n */\nasync function renderPageToPng(page: PdfPageProxy): Promise<Uint8Array> {\n const { createCanvas } = await import(\"@napi-rs/canvas\")\n\n const scale = 2.0 // 300 DPI 근사\n const viewport = page.getViewport({ scale })\n const canvas = createCanvas(Math.floor(viewport.width), Math.floor(viewport.height))\n const ctx = canvas.getContext(\"2d\")\n\n await page.render({ canvasContext: ctx as unknown, viewport }).promise\n return new Uint8Array(canvas.toBuffer(\"image/png\"))\n}\n","/**\n * kordoc — 모두 파싱해버리겠다\n *\n * HWP, HWPX, PDF → Markdown 변환 통합 라이브러리\n */\n\nimport { readFile } from \"fs/promises\"\nimport { detectFormat, detectZipFormat, isHwpxFile, isOldHwpFile, isPdfFile, isZipFile } from \"./detect.js\"\nimport { parseHwpxDocument } from \"./hwpx/parser.js\"\nimport { parseHwp5Document } from \"./hwp5/parser.js\"\nimport { parsePdfDocument } from \"./pdf/parser.js\"\nimport { parseXlsxDocument } from \"./xlsx/parser.js\"\nimport { parseDocxDocument } from \"./docx/parser.js\"\nimport type { ParseResult, ParseOptions } from \"./types.js\"\nimport { classifyError, toArrayBuffer } from \"./utils.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 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 switch (format) {\n case \"hwpx\": {\n // ZIP 기반 포맷 세분화: HWPX, XLSX, DOCX 구분\n const zipFormat = await detectZipFormat(buffer)\n if (zipFormat === \"xlsx\") return parseXlsx(buffer, options)\n if (zipFormat === \"docx\") return parseDocx(buffer, options)\n return parseHwpx(buffer, options)\n }\n case \"hwp\":\n return parseHwp(buffer, options)\n case \"pdf\":\n return parsePdf(buffer, options)\n default:\n return { success: false, fileType: \"unknown\", error: \"지원하지 않는 파일 형식입니다.\", code: \"UNSUPPORTED_FORMAT\" }\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 }\n } catch (err) {\n return { success: false, fileType: \"hwpx\", error: err instanceof Error ? err.message : \"HWPX 파싱 실패\", 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 return { success: true, fileType: \"hwp\", markdown, blocks, metadata, outline, warnings, images: images?.length ? images : undefined }\n } catch (err) {\n return { success: false, fileType: \"hwp\", error: err instanceof Error ? err.message : \"HWP 파싱 실패\", code: classifyError(err) }\n }\n}\n\n/** PDF 파일에서 텍스트를 추출하여 Markdown으로 변환 */\nexport async function parsePdf(buffer: ArrayBuffer, options?: ParseOptions): Promise<ParseResult> {\n try {\n const { markdown, blocks, metadata, outline, warnings, isImageBased } = await parsePdfDocument(buffer, options)\n return { success: true, fileType: \"pdf\", markdown, blocks, metadata, outline, warnings, isImageBased }\n } catch (err) {\n const isImageBased = err instanceof Error && \"isImageBased\" in err ? true : undefined\n return { success: false, fileType: \"pdf\", error: err instanceof Error ? err.message : \"PDF 파싱 실패\", 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 }\n } catch (err) {\n return { success: false, fileType: \"xlsx\", error: err instanceof Error ? err.message : \"XLSX 파싱 실패\", 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 }\n } catch (err) {\n return { success: false, fileType: \"docx\", error: err instanceof Error ? err.message : \"DOCX 파싱 실패\", code: classifyError(err) }\n }\n}\n\n// ─── 게임체인저 API ─────────────────────────────────\n\nexport { compare, diffBlocks } from \"./diff/compare.js\"\nexport { extractFormFields } from \"./form/recognize.js\"\nexport { markdownToHwpx } from \"./hwpx/generator.js\"\nexport { markdownToXlsx } from \"./xlsx/generator.js\"\nexport type { MarkdownToXlsxOptions } from \"./xlsx/generator.js\"\n\n// ─── Re-exports ──────────────────────────────────────\n\nexport { detectFormat, detectZipFormat, isHwpxFile, isOldHwpFile, isPdfFile, isZipFile } from \"./detect.js\"\nexport type {\n ParseResult, ParseSuccess, ParseFailure, FileType,\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, OcrMode, StructuredOcrResult, WatchOptions,\n} from \"./types.js\"\nexport { blocksToMarkdown } from \"./table/builder.js\"\nexport { VERSION } from \"./utils.js\"\n","/** 매직 바이트 기반 파일 포맷 감지 */\n\nimport JSZip from \"jszip\"\nimport type { FileType } from \"./types.js\"\n\n/** 매직 바이트 뷰 생성 (복사 없이 view) */\nfunction magicBytes(buffer: ArrayBuffer): Uint8Array {\n return new Uint8Array(buffer, 0, Math.min(4, buffer.byteLength))\n}\n\n/** ZIP 파일 여부: PK\\x03\\x04 */\nexport function isZipFile(buffer: ArrayBuffer): boolean {\n const b = magicBytes(buffer)\n return b[0] === 0x50 && b[1] === 0x4b && b[2] === 0x03 && b[3] === 0x04\n}\n\n/** HWPX (ZIP 기반 한컴 문서): PK\\x03\\x04 — 하위 호환용 */\nexport function isHwpxFile(buffer: ArrayBuffer): boolean {\n return isZipFile(buffer)\n}\n\n/** HWP 5.x (OLE2 바이너리 한컴 문서): \\xD0\\xCF\\x11\\xE0 */\nexport function isOldHwpFile(buffer: ArrayBuffer): boolean {\n const b = magicBytes(buffer)\n return b[0] === 0xd0 && b[1] === 0xcf && b[2] === 0x11 && b[3] === 0xe0\n}\n\n/** PDF 문서: %PDF */\nexport function isPdfFile(buffer: ArrayBuffer): boolean {\n const b = magicBytes(buffer)\n return b[0] === 0x25 && b[1] === 0x50 && b[2] === 0x44 && b[3] === 0x46\n}\n\n/** 동기 포맷 감지 — ZIP은 모두 \"hwpx\"로 반환 (하위 호환) */\nexport function detectFormat(buffer: ArrayBuffer): FileType {\n if (buffer.byteLength < 4) return \"unknown\"\n if (isZipFile(buffer)) return \"hwpx\"\n if (isOldHwpFile(buffer)) return \"hwp\"\n if (isPdfFile(buffer)) return \"pdf\"\n return \"unknown\"\n}\n\n/**\n * ZIP 내부 구조 기반 포맷 세분화.\n * HWPX, XLSX, DOCX 모두 ZIP이므로 내부 파일로 구분.\n */\nexport async function detectZipFormat(buffer: ArrayBuffer): Promise<\"hwpx\" | \"xlsx\" | \"docx\" | \"unknown\"> {\n try {\n const zip = await JSZip.loadAsync(buffer)\n // XLSX: xl/workbook.xml\n if (zip.file(\"xl/workbook.xml\")) return \"xlsx\"\n // DOCX: word/document.xml\n if (zip.file(\"word/document.xml\")) return \"docx\"\n // HWPX: Contents/ 또는 content.hpf 또는 mimetype\n if (zip.file(\"Contents/content.hpf\") || zip.file(\"mimetype\")) return \"hwpx\"\n // 기타 ZIP 내에 section 파일이 있으면 HWPX로 추정\n const hasSection = Object.keys(zip.files).some(f => f.startsWith(\"Contents/\"))\n if (hasSection) return \"hwpx\"\n return \"unknown\"\n } catch {\n return \"unknown\"\n }\n}\n","/**\n * HWPX 파서 — manifest 멀티섹션, colSpan/rowSpan, 중첩테이블\n *\n * lexdiff 기반 + edu-facility-ai 손상ZIP 복구\n */\n\nimport JSZip from \"jszip\"\n\nimport { DOMParser } from \"@xmldom/xmldom\"\nimport { buildTable, convertTableToText, blocksToMarkdown, MAX_COLS, MAX_ROWS } from \"../table/builder.js\"\nimport type { CellContext, IRBlock, DocumentMetadata, InternalParseResult, ParseOptions, ParseWarning, OutlineItem, InlineStyle, ExtractedImage } from \"../types.js\"\nimport { HEADING_RATIO_H1, HEADING_RATIO_H2, HEADING_RATIO_H3 } from \"../types.js\"\nimport { KordocError, isPathTraversal, sanitizeHref, precheckZipSize } from \"../utils.js\"\n// 테스트 호환성 re-export\nexport { precheckZipSize } from \"../utils.js\"\nimport { parsePageRange } from \"../page-range.js\"\n\n/** 압축 해제 최대 크기 (500MB) — ZIP bomb 방지 */\nconst MAX_DECOMPRESS_SIZE = 500 * 1024 * 1024\n/** 손상 ZIP 복구 시 최대 엔트리 수 */\nconst MAX_ZIP_ENTRIES = 2000\n\n/** colSpan/rowSpan을 안전한 범위로 클램핑 */\nfunction clampSpan(val: number, max: number): number {\n return Math.max(1, Math.min(val, max))\n}\n\n/** XML DOM 재귀 최대 깊이 — 악성 파일의 스택 오버플로 방지 */\nconst MAX_XML_DEPTH = 200\n\ninterface TableState { rows: CellContext[][]; currentRow: CellContext[]; cell: CellContext | null }\n\n/** xmldom DOMParser 생성 — onError 콜백으로 malformed XML 경고 수집 */\nfunction createXmlParser(warnings?: ParseWarning[]): DOMParser {\n return new DOMParser({\n onError(level: \"warn\" | \"error\" | \"fatalError\", msg: string) {\n if (level === \"fatalError\") throw new KordocError(`XML 파싱 실패: ${msg}`)\n warnings?.push({ code: \"MALFORMED_XML\", message: `XML ${level === \"warn\" ? \"경고\" : \"오류\"}: ${msg}` })\n },\n })\n}\n\n// ─── HWPX 스타일 정보 ──────────────────────────────\n\ninterface HwpxCharProperty {\n fontSize?: number // 단위: pt (hwpx는 centi-pt → /100)\n bold?: boolean\n italic?: boolean\n fontName?: string\n}\n\ninterface HwpxStyleMap {\n charProperties: Map<string, HwpxCharProperty> // id → property\n styles: Map<string, { name: string; charPrId?: string; paraPrId?: string }> // id → style\n}\n\n/** head.xml 또는 header.xml에서 스타일 정보 추출 */\nasync function extractHwpxStyles(zip: JSZip, decompressed?: { total: number }): Promise<HwpxStyleMap> {\n const result: HwpxStyleMap = {\n charProperties: new Map(),\n styles: 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\n // charProperties 파싱\n parseCharProperties(doc, result.charProperties)\n // styles 파싱\n parseStyleElements(doc, result.styles)\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) prop.fontSize = parseInt(height, 10) / 100\n\n // bold/italic\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\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/** XXE/Billion Laughs 방지 — DOCTYPE 제거 (내부 DTD 서브셋 포함) */\nfunction stripDtd(xml: string): string {\n return xml.replace(/<!DOCTYPE\\s[^[>]*(\\[[\\s\\S]*?\\])?\\s*>/gi, \"\")\n}\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 await 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 // 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 metadata.pageCount = sectionPaths.length\n\n // 페이지 범위 필터링 (섹션 단위 근사치)\n const pageFilter = options?.pages ? parsePageRange(options.pages, sectionPaths.length) : null\n const totalTarget = pageFilter ? pageFilter.size : sectionPaths.length\n const blocks: IRBlock[] = []\n let parsedSections = 0\n for (let si = 0; si < sectionPaths.length; si++) {\n if (pageFilter && !pageFilter.has(si + 1)) continue\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 KordocError(\"ZIP 압축 해제 크기 초과 (ZIP bomb 의심)\")\n blocks.push(...parseSectionXml(xml, styleMap, warnings, si + 1))\n parsedSections++\n options?.onProgress?.(parsedSections, totalTarget)\n } catch (secErr) {\n if (secErr instanceof KordocError) throw secErr\n warnings.push({ page: si + 1, message: `섹션 ${si + 1} 파싱 실패: ${secErr instanceof Error ? secErr.message : \"알 수 없는 오류\"}`, code: \"PARTIAL_PARSE\" })\n }\n }\n\n // 이미지 블록에서 ZIP 바이너리 추출\n const images = await extractImagesFromZip(zip, blocks, decompressed, warnings)\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\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 detectImageMimeFromBytes(data: Uint8Array): string {\n if (data.length >= 3 && data[0] === 0xFF && data[1] === 0xD8 && data[2] === 0xFF) return \"image/jpeg\"\n if (data.length >= 4 && data[0] === 0x89 && data[1] === 0x50 && data[2] === 0x4E && data[3] === 0x47) return \"image/png\"\n if (data.length >= 3 && data[0] === 0x47 && data[1] === 0x49 && data[2] === 0x46) return \"image/gif\"\n if (data.length >= 2 && data[0] === 0x42 && data[1] === 0x4D) return \"image/bmp\"\n // WMF Placeable: D7 CD C6 9A\n if (data.length >= 4 && data[0] === 0xD7 && data[1] === 0xCD && data[2] === 0xC6 && data[3] === 0x9A) return \"image/wmf\"\n // WMF Standard: type(01/02) + 00 + 09 + 00\n if (data.length >= 4 && (data[0] === 0x01 || data[0] === 0x02) && data[1] === 0x00 && data[2] === 0x09 && data[3] === 0x00) return \"image/wmf\"\n // EMF: 01 00 00 00\n if (data.length >= 4 && data[0] === 0x01 && data[1] === 0x00 && data[2] === 0x00 && data[3] === 0x00) return \"image/emf\"\n return \"image/png\"\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/** blocks에서 type=\"image\" 블록의 참조를 ZIP에서 실제 바이너리로 변환 */\nasync function extractImagesFromZip(\n zip: JSZip,\n blocks: IRBlock[],\n decompressed: { total: number },\n warnings?: ParseWarning[],\n): Promise<ExtractedImage[]> {\n const images: ExtractedImage[] = []\n let imageIndex = 0\n\n for (const block of blocks) {\n if (block.type !== \"image\" || !block.text) continue\n\n const ref = block.text\n // BinData/ 폴더 내에서 참조 파일 찾기\n // ref에 확장자가 없는 경우 ZIP 목록에서 일치하는 파일 탐색\n const exts = ref.includes(\".\") ? [\"\"] : [\".jpg\", \".jpeg\", \".png\", \".bmp\", \".gif\", \".wmf\", \".emf\", \".tif\", \"\"]\n const candidates = exts.flatMap(ext => [\n `BinData/${ref}${ext}`,\n `Contents/BinData/${ref}${ext}`,\n `${ref}${ext}`,\n ])\n\n let found = false\n for (const path of candidates) {\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 // ref에 확장자가 없으면 실제 발견된 path의 확장자 사용 (WMF 등 올바른 분류)\n const refExt = ref.includes(\".\") ? ref.split(\".\").pop()!.toLowerCase() : \"\"\n const pathExt = !refExt && path.includes(\".\") ? path.split(\".\").pop()!.toLowerCase() : \"\"\n const ext = refExt || pathExt\n const mimeType = ext ? imageExtToMime(ext) : detectImageMimeFromBytes(data)\n imageIndex++\n const filename = `image_${String(imageIndex).padStart(3, \"0\")}.${mimeToExt(mimeType)}`\n\n images.push({ filename, data, mimeType })\n // 블록 텍스트를 참조 파일명으로 교체\n block.text = filename\n block.imageData = { data, mimeType, filename: ref }\n found = true\n break\n } catch (err) {\n if (err instanceof KordocError) throw err\n // 개별 이미지 실패는 경고로 처리\n }\n }\n\n if (!found) {\n warnings?.push({ page: block.pageNumber, message: `이미지 파일 없음: ${ref}`, code: \"SKIPPED_IMAGE\" })\n // image 블록을 paragraph로 전환 (참조만 남김)\n block.type = \"paragraph\"\n block.text = `[이미지: ${ref}]`\n }\n }\n\n return images\n}\n\n// ─── 메타데이터 추출 (best-effort) ───────────────────\n\n/**\n * HWPX ZIP 내 메타데이터 파일에서 Dublin Core 정보 추출.\n * 표준 경로: meta.xml, docProps/core.xml, META-INF/container.xml\n */\nasync function extractHwpxMetadata(zip: JSZip, metadata: DocumentMetadata, decompressed?: { total: number }): Promise<void> {\n try {\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 file = zip.file(mp) || Object.values(zip.files).find(f => f.name.toLowerCase() === mp.toLowerCase()) || null\n if (!file) continue\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 parseDublinCoreMetadata(xml, metadata)\n if (metadata.title || metadata.author) return\n }\n } catch {\n // best-effort\n }\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// ─── 손상 ZIP 복구 (edu-facility-ai에서 포팅) ──────────\n\n/** Web Standard DecompressionStream 기반 raw deflate 압축 해제 (Node.js zlib 대체, CF Workers 호환) */\nasync function inflateRawCompat(data: Uint8Array, maxSize: number): Promise<Uint8Array> {\n const ds = new DecompressionStream(\"deflate-raw\")\n const writer = ds.writable.getWriter()\n await writer.write(data)\n await writer.close()\n const reader = ds.readable.getReader()\n const chunks: Uint8Array[] = []\n let total = 0\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n total += value.length\n if (total > maxSize) throw new KordocError(\"압축 해제 크기 초과\")\n chunks.push(value)\n }\n const out = new Uint8Array(total)\n let offset = 0\n for (const c of chunks) { out.set(c, offset); offset += c.length }\n return out\n}\n\nasync function extractFromBrokenZip(buffer: ArrayBuffer): Promise<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\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 = await inflateRawCompat(fileData, 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 blocks.push(...parseSectionXml(content, undefined, warnings, sectionNum))\n } catch {\n continue\n }\n }\n\n if (blocks.length === 0) throw new KordocError(\"손상된 HWPX에서 섹션 데이터를 복구할 수 없습니다\")\n const markdown = blocksToMarkdown(blocks)\n return { markdown, blocks, warnings: warnings.length > 0 ? warnings : undefined }\n}\n\n// ─── Manifest 해석 ───────────────────────────────────\n\nasync 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()\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 isSectionId = (id: string) => /^s/i.test(id) || id.toLowerCase().includes(\"section\")\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 let href = item.getAttribute(\"href\") || \"\"\n const mediaType = item.getAttribute(\"media-type\") || \"\"\n if (!isSectionId(id) && !mediaType.includes(\"xml\")) continue\n if (!href.startsWith(\"/\") && !href.startsWith(\"Contents/\") && isSectionId(id))\n href = \"Contents/\" + href\n 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.entries())\n .filter(([id]) => isSectionId(id))\n .sort((a, b) => a[0].localeCompare(b[0]))\n .map(([, href]) => href)\n}\n\n// ─── 헤딩 감지 (스타일 기반) ────────────────────────\n\n/** HWPX 스타일 기반 헤딩 감지 */\nfunction detectHwpxHeadings(blocks: IRBlock[], styleMap: HwpxStyleMap): void {\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// ─── 섹션 XML 파싱 ──────────────────────────────────\n\nfunction parseSectionXml(xml: string, styleMap?: HwpxStyleMap, warnings?: ParseWarning[], sectionNum?: number): IRBlock[] {\n const parser = createXmlParser(warnings)\n const doc = parser.parseFromString(stripDtd(xml), \"text/xml\")\n if (!doc.documentElement) return []\n\n const blocks: IRBlock[] = []\n walkSection(doc.documentElement, blocks, null, [], styleMap, warnings, sectionNum)\n return blocks\n}\n\n/** pic/shape 요소에서 이미지 참조 경로 추출 (binaryItemIDRef 또는 href) */\nfunction extractImageRef(el: Element): string | 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)\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 styleMap?: HwpxStyleMap, warnings?: ParseWarning[], sectionNum?: number,\n 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 if (tableCtx) tableStack.push(tableCtx)\n const newTable: TableState = { rows: [], currentRow: [], cell: null }\n walkSection(el, blocks, newTable, tableStack, styleMap, warnings, sectionNum, depth + 1)\n\n if (newTable.rows.length > 0) {\n if (tableStack.length > 0) {\n const parentTable = tableStack.pop()!\n // 중첩 표가 충분히 크면 (3행+, 2열+) 별도 블록으로 분리\n const nestedCols = Math.max(...newTable.rows.map(r => r.length))\n if (newTable.rows.length >= 3 && nestedCols >= 2) {\n blocks.push({ type: \"table\", table: buildTable(newTable.rows), pageNumber: sectionNum })\n } else {\n const nestedText = convertTableToText(newTable.rows)\n if (parentTable.cell) {\n parentTable.cell.text += (parentTable.cell.text ? \"\\n\" : \"\") + nestedText\n }\n }\n tableCtx = parentTable\n } else {\n blocks.push({ type: \"table\", table: buildTable(newTable.rows), pageNumber: sectionNum })\n tableCtx = null\n }\n } else {\n tableCtx = tableStack.length > 0 ? tableStack.pop()! : null\n }\n break\n }\n\n case \"tr\":\n if (tableCtx) {\n tableCtx.currentRow = []\n walkSection(el, blocks, tableCtx, tableStack, styleMap, warnings, sectionNum, depth + 1)\n if (tableCtx.currentRow.length > 0) 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 walkSection(el, blocks, tableCtx, tableStack, styleMap, warnings, sectionNum, 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 cs = parseInt(el.getAttribute(\"colSpan\") || \"1\", 10)\n const rs = parseInt(el.getAttribute(\"rowSpan\") || \"1\", 10)\n tableCtx.cell.colSpan = clampSpan(cs, MAX_COLS)\n tableCtx.cell.rowSpan = clampSpan(rs, MAX_ROWS)\n }\n break\n\n case \"p\": {\n const { text, href, footnote, style, headingLevel } = extractParagraphInfo(el, styleMap)\n if (text) {\n if (tableCtx?.cell) {\n tableCtx.cell.text += (tableCtx.cell.text ? \"\\n\" : \"\") + text\n } else if (!tableCtx) {\n let block: IRBlock\n if (headingLevel) {\n block = { type: \"heading\", text, level: headingLevel, pageNumber: sectionNum }\n } else {\n block = { type: \"paragraph\", text, pageNumber: sectionNum }\n if (style) block.style = style\n }\n if (href) block.href = href\n if (footnote) block.footnoteText = footnote\n blocks.push(block)\n }\n }\n // <p> 내부의 <tbl>만 별도 처리 — extractParagraphInfo가 이미 텍스트를 추출했으므로\n // 전체 walkSection 재귀 대신 테이블/이미지 자식만 선택적으로 처리\n tableCtx = walkParagraphChildren(el, blocks, tableCtx, tableStack, styleMap, warnings, sectionNum, depth + 1)\n break\n }\n\n // 이미지/그림 — 경로 추출 또는 경고\n case \"pic\": case \"shape\": case \"drawingObject\": {\n const imgRef = extractImageRef(el)\n if (imgRef) {\n blocks.push({ type: \"image\", text: imgRef, pageNumber: sectionNum })\n } else if (warnings && sectionNum) {\n warnings.push({ page: sectionNum, message: `스킵된 요소: ${localTag}`, code: \"SKIPPED_IMAGE\" })\n }\n break\n }\n\n default:\n walkSection(el, blocks, tableCtx, tableStack, styleMap, warnings, sectionNum, depth + 1)\n break\n }\n }\n}\n\n/** <p> 내부에서 텍스트가 아닌 구조적 자식만 처리 (tbl, pic, shape). tableCtx 반환으로 상태 전파 */\nfunction walkParagraphChildren(\n node: Node, blocks: IRBlock[],\n tableCtx: TableState | null, tableStack: TableState[],\n styleMap?: HwpxStyleMap, warnings?: ParseWarning[], sectionNum?: number,\n depth: number = 0\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) => {\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 // 테이블은 walkSection으로 위임\n if (tableCtx) tableStack.push(tableCtx)\n const newTable: TableState = { rows: [], currentRow: [], cell: null }\n walkSection(el, blocks, newTable, tableStack, styleMap, warnings, sectionNum, d + 1)\n if (newTable.rows.length > 0) {\n if (tableStack.length > 0) {\n const parentTable = tableStack.pop()!\n const nestedCols = Math.max(...newTable.rows.map(r => r.length))\n if (newTable.rows.length >= 3 && nestedCols >= 2) {\n blocks.push({ type: \"table\", table: buildTable(newTable.rows), pageNumber: sectionNum })\n } else {\n const nestedText = convertTableToText(newTable.rows)\n if (parentTable.cell) {\n parentTable.cell.text += (parentTable.cell.text ? \"\\n\" : \"\") + nestedText\n }\n }\n tableCtx = parentTable\n } else {\n blocks.push({ type: \"table\", table: buildTable(newTable.rows), pageNumber: sectionNum })\n tableCtx = null\n }\n } else {\n tableCtx = tableStack.length > 0 ? tableStack.pop()! : null\n }\n } else if (localTag === \"pic\" || localTag === \"shape\" || localTag === \"drawingObject\") {\n // 도형/이미지 안에 drawText(글상자)가 있으면 텍스트 추출 우선\n const drawTextChild = findDescendant(el, \"drawText\")\n if (drawTextChild) {\n extractDrawTextBlocks(drawTextChild, blocks, styleMap, sectionNum)\n } else {\n const imgRef = extractImageRef(el)\n if (imgRef) {\n blocks.push({ type: \"image\", text: imgRef, pageNumber: sectionNum })\n } else if (warnings && sectionNum) {\n warnings.push({ page: sectionNum, message: `스킵된 요소: ${localTag}`, code: \"SKIPPED_IMAGE\" })\n }\n }\n } else if (localTag === \"drawText\") {\n // 글상자(TextBox) 안 텍스트 추출 — <hp:p> 순회\n extractDrawTextBlocks(el, blocks, styleMap, sectionNum)\n } else if (localTag === \"r\" || localTag === \"run\" || localTag === \"ctrl\"\n || localTag === \"rect\" || localTag === \"ellipse\" || localTag === \"polygon\"\n || localTag === \"line\" || localTag === \"arc\" || localTag === \"curve\"\n || localTag === \"connectLine\" || localTag === \"container\") {\n // <hp:run>, <hp:ctrl>, 도형 요소 내부에 테이블/이미지/글상자가 포함될 수 있음 — 재귀\n walkChildren(el, d + 1)\n }\n }\n }\n walkChildren(node, depth)\n return tableCtx\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[], styleMap?: HwpxStyleMap, sectionNum?: number): 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, styleMap, sectionNum)\n } else {\n const info = extractParagraphInfo(child, styleMap)\n const text = info.text.trim()\n if (text) {\n blocks.push({ type: \"paragraph\", text, style: info.style ?? undefined, pageNumber: sectionNum })\n }\n }\n }\n }\n}\n\ninterface ParagraphInfo {\n text: string\n href?: string\n footnote?: string\n style?: InlineStyle\n headingLevel?: number\n}\n\nfunction extractParagraphInfo(para: Element, styleMap?: HwpxStyleMap): ParagraphInfo {\n let text = \"\"\n let href: string | undefined\n let footnote: string | undefined\n let charPrId: string | undefined\n\n // 문단의 스타일 참조 → charPr로 간접 조회\n // HWPX <p>에는 paraPrIDRef/styleIDRef가 있고, charPrIDRef는 <r> 요소에 있음\n // 여기서는 일단 null — <r> 요소에서 charPrIDRef를 가져옴\n\n const walk = (node: Node) => {\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 if (child.nodeType === 3) { text += child.textContent || \"\"; continue }\n if (child.nodeType !== 1) continue\n\n const tag = (child.tagName || child.localName || \"\").replace(/^[^:]+:/, \"\")\n switch (tag) {\n case \"t\": walk(child); 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 \"fwSpace\": case \"hwSpace\": text += \" \"; break\n case \"tbl\": break // 테이블은 walkSection에서 처리\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)\n break\n }\n\n // 각주/미주\n case \"footNote\": case \"endNote\": case \"fn\": case \"en\": {\n const noteText = extractTextFromNode(child)\n if (noteText) footnote = (footnote ? footnote + \"; \" : \"\") + noteText\n break\n }\n\n // 제어 요소 — 필드, 컨트롤, 매개변수 등 스킵\n case \"ctrl\": case \"fieldBegin\": case \"fieldEnd\":\n case \"parameters\": case \"stringParam\": case \"integerParam\":\n case \"boolParam\": case \"floatParam\":\n case \"secPr\": // 섹션 속성 (페이지 설정 등)\n case \"colPr\": // 다단 속성\n case \"linesegarray\": case \"lineseg\": // 레이아웃 정보\n // 도형/이미지 요소 — 대체텍스트(\"사각형입니다.\" 등) 누출 방지\n case \"pic\": case \"shape\": case \"drawingObject\":\n case \"shapeComment\": case \"drawText\":\n break\n\n // run 요소에서 charPrIDRef 추출\n case \"r\": {\n const runCharPr = child.getAttribute(\"charPrIDRef\")\n if (runCharPr && !charPrId) charPrId = runCharPr\n walk(child)\n break\n }\n\n default: walk(child); break\n }\n }\n }\n walk(para)\n\n // 목차 리더 마커(\\x1F) 이후 텍스트(페이지번호) 제거\n const leaderIdx = text.indexOf(\"\\x1F\")\n if (leaderIdx >= 0) text = text.substring(0, leaderIdx)\n\n let cleanText = text.replace(/[ \\t]+/g, \" \").trim()\n\n // 한글 이미지 OLE 대체 텍스트 필터링 (\"그림입니다. 원본 그림의 이름: ...\")\n if (/^그림입니다\\.?\\s*원본\\s*그림의\\s*(이름|크기)/.test(cleanText)) cleanText = \"\"\n // 멀티라인으로 삽입된 OLE 대체 텍스트도 제거\n cleanText = cleanText.replace(/그림입니다\\.?\\s*원본\\s*그림의\\s*(이름|크기)[^\\n]*(\\n[^\\n]*원본\\s*그림의\\s*(이름|크기)[^\\n]*)*/g, \"\").trim()\n // HWP 도형/개체 대체텍스트 제거 (\"사각형입니다.\", \"개체 입니다.\" 등)\n cleanText = cleanText.replace(/(?:모서리가 둥근 |둥근 )?(?:사각형|직사각형|정사각형|원|타원|삼각형|선|직선|곡선|화살표|오각형|육각형|팔각형|별|십자|구름|마름모|도넛|평행사변형|사다리꼴|개체|그리기\\s?개체|묶음\\s?개체|글상자|수식|표|그림|OLE\\s?개체)\\s?입니다\\.?/g, \"\").trim()\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 // styleIDRef 기반 헤딩 레벨 감지 (스타일명 매칭)\n let headingLevel: number | undefined\n const styleIdRef = para.getAttribute(\"styleIDRef\")\n if (styleMap && styleIdRef) {\n const styleDef = styleMap.styles.get(styleIdRef)\n if (styleDef?.name) {\n const sn = styleDef.name\n if (/장제목|대제목|간지제목|제목[\\s_]?1|개요[\\s_]?1|heading[\\s_]?1/i.test(sn)) headingLevel = 1\n else if (/절제목|제목[\\s_]?2|개요[\\s_]?2|heading[\\s_]?2|^B-1\\.$|[\\s(]1\\.$/i.test(sn)) headingLevel = 2\n else if (/제목[\\s_]?3|개요[\\s_]?3|heading[\\s_]?3|1\\.1\\s*제목|1\\.1[\\s_]|^B-1\\.1/i.test(sn)) headingLevel = 3\n else if (/제목[\\s_]?4|개요[\\s_]?4|heading[\\s_]?4/i.test(sn)) headingLevel = 4\n }\n }\n\n return { text: cleanText, href, footnote, style, headingLevel }\n}\n\n/** 노드 내 모든 텍스트를 재귀적으로 추출 */\nfunction extractTextFromNode(node: Node): string {\n let result = \"\"\n const children = node.childNodes\n if (!children) return result\n for (let i = 0; i < children.length; i++) {\n const child = children[i]\n if (child.nodeType === 3) result += child.textContent || \"\"\n else if (child.nodeType === 1) result += extractTextFromNode(child)\n }\n return result.trim()\n}\n","/** kordoc 공용 유틸리티 */\n\n/** 빌드 타임에 tsup define으로 주입되는 버전 */\ndeclare const __KORDOC_VERSION__: string\nexport const VERSION: string = typeof __KORDOC_VERSION__ !== \"undefined\" ? __KORDOC_VERSION__ : \"0.0.0-dev\"\n\n/**\n * Node.js Buffer → ArrayBuffer 변환\n * pool Buffer의 공유 ArrayBuffer 문제를 안전하게 처리.\n * offset=0이고 전체 ArrayBuffer를 차지하면 복사 없이 직접 반환.\n */\nexport function toArrayBuffer(buf: Buffer): ArrayBuffer {\n if (buf.byteOffset === 0 && buf.byteLength === buf.buffer.byteLength) {\n return buf.buffer as ArrayBuffer\n }\n return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength) as ArrayBuffer\n}\n\n/**\n * kordoc 내부 에러 클래스 — 사용자에게 노출해도 안전한 메시지만 포함.\n * MCP 에러 정제에서 instanceof로 판별하여 allowlist 패턴 매칭 없이 안전하게 통과.\n */\nexport class KordocError extends Error {\n constructor(message: string) {\n super(message)\n this.name = \"KordocError\"\n }\n}\n\n/**\n * 에러 메시지 정제 — KordocError는 그대로, 나머지는 일반 메시지로 대체.\n * 파일시스템 경로, 스택 트레이스 등 내부 정보 노출 방지.\n */\nexport function sanitizeError(err: unknown): string {\n if (err instanceof KordocError) return err.message\n return \"문서 처리 중 오류가 발생했습니다\"\n}\n\n/**\n * ZIP 엔트리 경로의 경로 순회 여부 판별.\n * 백슬래시 정규화, .., 절대경로, Windows 드라이브 문자 모두 차단.\n */\nexport function isPathTraversal(name: string): boolean {\n if (name.includes(\"\\x00\")) return true\n const normalized = name.replace(/\\\\/g, \"/\")\n return normalized.includes(\"..\") || normalized.startsWith(\"/\") || /^[A-Za-z]:/.test(normalized)\n}\n\n// ─── ZIP 안전 로딩 (ZIP bomb 방지) ────────────────────\n\n/**\n * ZIP bomb 사전 검사 — Central Directory에서 비압축 합계와 엔트리 수 확인.\n * HWPX/XLSX/DOCX 등 모든 ZIP 기반 포맷에서 공통 사용.\n */\nexport function precheckZipSize(\n buffer: ArrayBuffer,\n maxUncompressedSize = 100 * 1024 * 1024,\n maxEntries = 500,\n): { totalUncompressed: number; entryCount: number } {\n try {\n const data = new DataView(buffer)\n const len = buffer.byteLength\n // EOCD 시그니처 역방향 스캔\n let eocdOffset = -1\n for (let i = len - 22; i >= Math.max(0, len - 65557); i--) {\n if (data.getUint32(i, true) === 0x06054b50) { eocdOffset = i; break }\n }\n if (eocdOffset < 0) return { totalUncompressed: 0, entryCount: 0 }\n\n const entryCount = data.getUint16(eocdOffset + 10, true)\n if (entryCount > maxEntries) {\n throw new KordocError(`ZIP 엔트리 수 초과: ${entryCount} (최대 ${maxEntries})`)\n }\n\n const cdSize = data.getUint32(eocdOffset + 12, true)\n const cdOffset = data.getUint32(eocdOffset + 16, true)\n if (cdOffset + cdSize > len) return { totalUncompressed: 0, entryCount }\n\n let totalUncompressed = 0\n let pos = cdOffset\n for (let i = 0; i < entryCount && pos + 46 <= cdOffset + cdSize; i++) {\n if (data.getUint32(pos, true) !== 0x02014b50) break\n totalUncompressed += data.getUint32(pos + 24, true)\n const nameLen = data.getUint16(pos + 28, true)\n const extraLen = data.getUint16(pos + 30, true)\n const commentLen = data.getUint16(pos + 32, true)\n pos += 46 + nameLen + extraLen + commentLen\n }\n\n if (totalUncompressed > maxUncompressedSize) {\n throw new KordocError(`ZIP 비압축 크기 초과: ${(totalUncompressed / 1024 / 1024).toFixed(1)}MB (최대 ${maxUncompressedSize / 1024 / 1024}MB)`)\n }\n\n return { totalUncompressed, entryCount }\n } catch (err) {\n if (err instanceof KordocError) throw err\n return { totalUncompressed: 0, entryCount: 0 }\n }\n}\n\n/** 하이퍼링크 URL 살균 — javascript: 등 XSS 위험 스킴 차단 */\nconst SAFE_HREF_RE = /^(?:https?:|mailto:|tel:|#)/i\nexport function sanitizeHref(href: string): string | null {\n const trimmed = href.trim()\n if (!trimmed || !SAFE_HREF_RE.test(trimmed)) return null\n return trimmed\n}\n\n// ─── 에러 분류 ──────────────────────────────────────\n\nimport type { ErrorCode } from \"./types.js\"\n\n/** 에러를 구조화된 ErrorCode로 분류 — KordocError 메시지 패턴 매칭 */\nexport function classifyError(err: unknown): ErrorCode {\n if (!(err instanceof Error)) return \"PARSE_ERROR\"\n const msg = err.message\n if (msg.includes(\"암호화\")) return \"ENCRYPTED\"\n if (msg.includes(\"DRM\")) return \"DRM_PROTECTED\"\n if (msg.includes(\"ZIP bomb\") || msg.includes(\"ZIP 비압축 크기 초과\") || msg.includes(\"ZIP 엔트리 수 초과\")) return \"ZIP_BOMB\"\n if (msg.includes(\"bomb\") || msg.includes(\"크기 초과\") || msg.includes(\"압축 해제\")) return \"DECOMPRESSION_BOMB\"\n if (msg.includes(\"이미지 기반\")) return \"IMAGE_BASED_PDF\"\n if (msg.includes(\"섹션\") && (msg.includes(\"찾을 수 없\") || msg.includes(\"없음\"))) return \"NO_SECTIONS\"\n if (msg.includes(\"시그니처\") || msg.includes(\"복구할 수 없\")) return \"CORRUPTED\"\n return \"PARSE_ERROR\"\n}\n","/** 2-pass colSpan/rowSpan 테이블 빌더 및 Markdown 변환 */\n\nimport type { CellContext, IRBlock, IRCell, IRTable } from \"../types.js\"\nimport { sanitizeHref } from \"../utils.js\"\n\n/** 테이블 열 수 상한 — 한국 공공문서 기준 충분한 값 */\nexport const MAX_COLS = 200\n/** 테이블 행 수 상한 — 메모리 폭주 방지 */\nexport const MAX_ROWS = 10000\n\nexport function buildTable(rows: CellContext[][]): IRTable {\n if (rows.length > MAX_ROWS) rows = rows.slice(0, MAX_ROWS)\n const numRows = rows.length\n\n // colAddr/rowAddr가 있으면 직접 배치 (HWPX cellAddr, HWP5 colAddr/rowAddr)\n const hasAddr = rows.some(row => row.some(c => c.colAddr !== undefined && c.rowAddr !== undefined))\n if (hasAddr) return buildTableDirect(rows, numRows)\n\n // Pass 1: maxCols 계산 — 2D 배열 사용 (동적 확장)\n let maxCols = 0\n const tempOccupied: boolean[][] = Array.from({ length: numRows }, () => [])\n\n for (let rowIdx = 0; rowIdx < numRows; rowIdx++) {\n let colIdx = 0\n for (const cell of rows[rowIdx]) {\n while (colIdx < MAX_COLS && tempOccupied[rowIdx][colIdx]) colIdx++\n if (colIdx >= MAX_COLS) break\n\n for (let r = rowIdx; r < Math.min(rowIdx + cell.rowSpan, numRows); r++) {\n for (let c = colIdx; c < Math.min(colIdx + cell.colSpan, MAX_COLS); c++) {\n tempOccupied[r][c] = true\n }\n }\n colIdx += cell.colSpan\n if (colIdx > maxCols) maxCols = colIdx\n }\n }\n\n if (maxCols === 0) return { rows: 0, cols: 0, cells: [], hasHeader: false }\n\n // Pass 2: 실제 배치\n const grid: IRCell[][] = Array.from({ length: numRows }, () =>\n Array.from({ length: maxCols }, () => ({ text: \"\", colSpan: 1, rowSpan: 1 }))\n )\n const occupied: boolean[][] = Array.from({ length: numRows }, () => Array(maxCols).fill(false))\n\n for (let rowIdx = 0; rowIdx < numRows; rowIdx++) {\n let colIdx = 0\n let cellIdx = 0\n\n while (colIdx < maxCols && cellIdx < rows[rowIdx].length) {\n while (colIdx < maxCols && occupied[rowIdx][colIdx]) colIdx++\n if (colIdx >= maxCols) break\n\n const cell = rows[rowIdx][cellIdx]\n grid[rowIdx][colIdx] = {\n text: cell.text.trim(),\n colSpan: cell.colSpan,\n rowSpan: cell.rowSpan,\n }\n\n for (let r = rowIdx; r < Math.min(rowIdx + cell.rowSpan, numRows); r++) {\n for (let c = colIdx; c < Math.min(colIdx + cell.colSpan, maxCols); c++) {\n occupied[r][c] = true\n }\n }\n\n colIdx += cell.colSpan\n cellIdx++\n }\n }\n\n return trimAndReturn(grid, numRows, maxCols)\n}\n\n/** colAddr/rowAddr 절대 좌표 기반 직접 배치 */\nfunction buildTableDirect(rows: CellContext[][], numRows: number): IRTable {\n // 전체 셀에서 maxCols 계산\n let maxCols = 0\n for (const row of rows) {\n for (const cell of row) {\n const end = (cell.colAddr ?? 0) + cell.colSpan\n if (end > maxCols) maxCols = end\n }\n }\n if (maxCols === 0) return { rows: 0, cols: 0, cells: [], hasHeader: false }\n\n const grid: IRCell[][] = Array.from({ length: numRows }, () =>\n Array.from({ length: maxCols }, () => ({ text: \"\", colSpan: 1, rowSpan: 1 }))\n )\n\n for (const row of rows) {\n for (const cell of row) {\n const r = cell.rowAddr ?? 0\n const c = cell.colAddr ?? 0\n if (r >= numRows || c >= maxCols) continue\n\n grid[r][c] = { text: cell.text.trim(), colSpan: cell.colSpan, rowSpan: cell.rowSpan }\n\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 < maxCols) {\n grid[r + dr][c + dc] = { text: \"\", colSpan: 1, rowSpan: 1 }\n }\n }\n }\n }\n }\n\n return trimAndReturn(grid, numRows, maxCols)\n}\n\n/** 빈 후행 열 제거 후 IRTable 반환 */\nfunction trimAndReturn(grid: IRCell[][], numRows: number, maxCols: number): IRTable {\n let effectiveCols = maxCols\n while (effectiveCols > 0) {\n const colEmpty = grid.every(row => !row[effectiveCols - 1]?.text?.trim())\n if (!colEmpty) break\n effectiveCols--\n }\n if (effectiveCols < maxCols && effectiveCols > 0) {\n const trimmed = grid.map(row => row.slice(0, effectiveCols))\n return { rows: numRows, cols: effectiveCols, cells: trimmed, hasHeader: numRows > 1 }\n }\n return { rows: numRows, cols: maxCols, cells: grid, hasHeader: numRows > 1 }\n}\n\nexport function convertTableToText(rows: CellContext[][]): string {\n return rows\n .map(row =>\n row\n .map(c => c.text.trim().replace(/\\n/g, \" \"))\n .filter(Boolean)\n .join(\" | \")\n )\n .filter(Boolean)\n .join(\"\\n\")\n}\n\n/** HWP 자동생성 도형/개체 대체텍스트 정규식 — 한컴오피스가 삽입하는 모든 알려진 패턴 */\nconst HWP_SHAPE_ALT_TEXT_RE = /(?:모서리가 둥근 |둥근 )?(?:사각형|직사각형|정사각형|원|타원|삼각형|이등변 삼각형|직각 삼각형|선|직선|곡선|화살표|굵은 화살표|이중 화살표|오각형|육각형|팔각형|별|[4-8]점별|십자|십자형|구름|구름형|마름모|도넛|평행사변형|사다리꼴|부채꼴|호|반원|물결|번개|하트|빗금|블록 화살표|수식|표|그림|개체|그리기\\s?개체|묶음\\s?개체|글상자|수식\\s?개체|OLE\\s?개체)\\s?입니다\\.?/g\n\n/** HWP PUA 특수문자 및 도형 대체텍스트 제거 — 모든 포맷 공통 */\nfunction sanitizeText(text: string): string {\n let result = text\n // Supplementary Private Use Area (U+F0000-U+FFFFD) — HWP 전용 기호\n .replace(/[\\u{F0000}-\\u{FFFFD}]/gu, \"\")\n // HWP 도형/개체 자동생성 대체텍스트 제거\n .replace(HWP_SHAPE_ALT_TEXT_RE, \"\")\n .replace(/ +/g, \" \")\n .trim()\n // 균등배분 스페이스 정리 (\"현 장 대 응 단 장\" → \"현장대응단장\")\n // 짧은 텍스트(30자 이하)에서 70%+ 토큰이 한글 1글자면 균등배분으로 판단\n if (result.length <= 30 && result.includes(\" \")) {\n const tokens = result.split(\" \")\n // 한글 1글자 토큰만 카운트 — ASCII 특수문자(< > & 등)는 균등배분이 아님\n const koreanSingleCharCount = tokens.filter(t => t.length === 1 && /[\\uAC00-\\uD7AF\\u3131-\\u318E]/.test(t)).length\n if (tokens.length >= 3 && koreanSingleCharCount / tokens.length >= 0.7) {\n result = tokens.join(\"\")\n }\n }\n return result\n}\n\nexport function blocksToMarkdown(blocks: IRBlock[]): string {\n const lines: string[] = []\n\n for (let i = 0; i < blocks.length; i++) {\n const block = blocks[i]\n\n // 헤딩 블록\n if (block.type === \"heading\" && block.text) {\n const prefix = \"#\".repeat(Math.min(block.level || 2, 6))\n const headingText = sanitizeText(block.text)\n if (headingText) lines.push(\"\", `${prefix} ${headingText}`, \"\")\n continue\n }\n\n // 이미지 블록 —  참조\n if (block.type === \"image\" && block.text) {\n lines.push(\"\", ``, \"\")\n continue\n }\n\n // 구분선 블록\n if (block.type === \"separator\") {\n lines.push(\"\", \"---\", \"\")\n continue\n }\n\n // 리스트 블록\n if (block.type === \"list\" && block.text) {\n const listText = sanitizeText(block.text)\n if (!listText) continue\n // 텍스트가 이미 번호로 시작하면 그대로 출력 (원래 번호 보존)\n const alreadyNumbered = block.listType === \"ordered\" && /^\\d+\\.\\s/.test(listText)\n const prefix = alreadyNumbered ? \"\" : block.listType === \"ordered\" ? \"1. \" : \"- \"\n lines.push(`${prefix}${listText}`)\n if (block.children) {\n for (const child of block.children) {\n const childPrefix = child.listType === \"ordered\" ? \"1.\" : \"-\"\n lines.push(` ${childPrefix} ${child.text || \"\"}`)\n }\n }\n continue\n }\n\n if (block.type === \"paragraph\" && block.text) {\n let text = sanitizeText(block.text)\n if (!text) continue\n\n // 별표 패턴 (기존 호환)\n if (/^\\[별표\\s*\\d+/.test(text)) {\n const nextBlock = blocks[i + 1]\n if (nextBlock?.type === \"paragraph\" && nextBlock.text && /관련\\)?$/.test(nextBlock.text)) {\n lines.push(\"\", `## ${text} ${nextBlock.text}`, \"\")\n i++\n } else {\n lines.push(\"\", `## ${text}`, \"\")\n }\n continue\n }\n\n if (/^\\([^)]*조[^)]*관련\\)$/.test(text)) {\n lines.push(`*${text}*`, \"\")\n continue\n }\n\n // 하이퍼링크가 있으면 텍스트에 링크 삽입 (javascript: 등 위험 스킴 제거)\n if (block.href) {\n const href = sanitizeHref(block.href)\n if (href) text = `[${text}](${href})`\n }\n\n // 각주가 있으면 괄호로 인라인 삽입\n if (block.footnoteText) {\n text += ` (주: ${block.footnoteText})`\n }\n\n lines.push(text)\n } else if (block.type === \"table\" && block.table) {\n // 테이블 앞에 빈 줄 보장 (마크다운 렌더링 필수)\n if (lines.length > 0 && lines[lines.length - 1] !== \"\") {\n lines.push(\"\")\n }\n const tableMd = tableToMarkdown(block.table)\n if (tableMd) {\n lines.push(tableMd)\n lines.push(\"\")\n }\n }\n }\n\n return lines.join(\"\\n\").trim()\n}\n\nfunction tableToMarkdown(table: IRTable): string {\n if (table.rows === 0 || table.cols === 0) return \"\"\n\n const { cells, rows: numRows, cols: numCols } = table\n\n // 1행 1열 → 구조화된 텍스트 (빈 셀이면 스킵)\n if (numRows === 1 && numCols === 1) {\n const content = sanitizeText(cells[0][0].text)\n if (!content) return \"\"\n return content\n .split(/\\n/)\n .map(line => {\n const trimmed = line.trim()\n if (!trimmed) return \"\"\n if (/^\\d+\\.\\s/.test(trimmed)) return `**${trimmed}**`\n if (/^[가-힣]\\.\\s/.test(trimmed)) return ` ${trimmed}`\n return trimmed\n })\n .filter(Boolean)\n .join(\"\\n\")\n }\n\n // 1열 다행 테이블 → 각 행을 별도 라인으로 출력 (목록성 데이터)\n if (numCols === 1 && numRows >= 2) {\n return cells\n .map(row => sanitizeText(row[0].text).replace(/\\n/g, \" \"))\n .filter(Boolean)\n .join(\"\\n\")\n }\n\n // 병합 셀: 행/열 병합된 셀은 빈 칸으로\n const display: string[][] = Array.from({ length: numRows }, () => Array(numCols).fill(\"\"))\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] = sanitizeText(cell.text).replace(/\\n/g, \"<br>\")\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) {\n skip.add(`${r + dr},${c + dc}`)\n }\n }\n }\n // colSpan > 1이면 display 열 인덱스를 건너뜀\n c += cell.colSpan - 1\n }\n }\n\n // rowSpan 잔류 처리:\n // 1) 완전 빈 행 제거\n // 2) \"첫 열만 값, 나머지 빈\" 행 → 다음 데이터 행의 첫 열에 값을 전파\n // 단, colSpan으로 인한 빈 열(skip 셀)은 이 대상이 아님\n const uniqueRows: string[][] = []\n let pendingFirstCol = \"\"\n for (let r = 0; r < display.length; r++) {\n const row = display[r]\n const isEmptyPlaceholder = row.every(cell => cell === \"\")\n if (isEmptyPlaceholder) continue\n\n // 첫 열만 값이 있고 나머지 모두 빈 행 → 다음 데이터 행의 첫 열에 전파\n // 단, colSpan으로 인한 빈 열(skip 셀)은 \"진짜 빈\"이 아니므로 제외\n const nonEmptyCols = row.filter(cell => cell !== \"\")\n const hasSkipInRow = row.some((_, c) => skip.has(`${r},${c}`))\n if (!hasSkipInRow && nonEmptyCols.length === 1 && row[0] !== \"\" && row.slice(1).every(c => c === \"\")) {\n pendingFirstCol = row[0]\n continue\n }\n\n // 저장된 첫 열 값을 현재 행의 빈 첫 열에 전파\n if (pendingFirstCol && row[0] === \"\") {\n row[0] = pendingFirstCol\n pendingFirstCol = \"\"\n } else {\n pendingFirstCol = \"\"\n }\n uniqueRows.push(row)\n }\n\n if (uniqueRows.length === 0) return \"\"\n\n const md: string[] = []\n md.push(\"| \" + uniqueRows[0].join(\" | \") + \" |\")\n md.push(\"| \" + uniqueRows[0].map(() => \"---\").join(\" | \") + \" |\")\n for (let i = 1; i < uniqueRows.length; i++) {\n md.push(\"| \" + uniqueRows[i].join(\" | \") + \" |\")\n }\n return md.join(\"\\n\")\n}\n","/** kordoc 공통 타입 정의 */\n\n// ─── 중간 표현 (Intermediate Representation) ─────────\n\nexport interface CellContext {\n text: string\n colSpan: number\n rowSpan: number\n /** HWP5 셀 열 주소 (0-based) — 병합 테이블 배치용 */\n colAddr?: number\n /** HWP5 셀 행 주소 (0-based) — 병합 테이블 배치용 */\n rowAddr?: number\n}\n\n/** 블록 타입 — v2.0에서 heading, list, image, separator 추가 */\nexport type IRBlockType = \"paragraph\" | \"table\" | \"heading\" | \"list\" | \"image\" | \"separator\"\n\nexport interface IRBlock {\n type: IRBlockType\n text?: string\n table?: IRTable\n /** 헤딩 레벨 (1-6), type=\"heading\"일 때 사용 */\n level?: number\n /** 원본 페이지 번호 (1-based) */\n pageNumber?: number\n /** 바운딩 박스 — PDF에서만 제공 */\n bbox?: BoundingBox\n /** 텍스트 스타일 정보 (선택) */\n style?: InlineStyle\n /** 리스트 타입, type=\"list\"일 때 사용 */\n listType?: \"ordered\" | \"unordered\"\n /** 중첩 리스트 아이템 */\n children?: IRBlock[]\n /** 하이퍼링크 URL */\n href?: string\n /** 각주/미주 텍스트 (인라인 삽입용) */\n footnoteText?: string\n /** 이미지 데이터 (type=\"image\"일 때) */\n imageData?: ImageData\n}\n\n/** 추출된 이미지 바이너리 데이터 */\nexport interface ImageData {\n /** 이미지 바이너리 */\n data: Uint8Array\n /** MIME 타입 (image/png, image/jpeg, image/gif, image/bmp, image/wmf, image/emf) */\n mimeType: string\n /** 원본 파일명 (있는 경우) */\n filename?: string\n}\n\n/** 바운딩 박스 — PDF 포인트 단위 (72pt = 1인치) */\nexport interface BoundingBox {\n page: number\n x: number\n y: number\n width: number\n height: number\n}\n\n/** 인라인 텍스트 스타일 */\nexport interface InlineStyle {\n bold?: boolean\n italic?: boolean\n fontSize?: number\n fontName?: string\n}\n\nexport interface IRTable {\n rows: number\n cols: number\n cells: IRCell[][]\n /** 첫 행을 헤더로 렌더링할지 여부 (현재: rows > 1이면 true — 의미적 감지가 아닌 레이아웃 힌트) */\n hasHeader: boolean\n}\n\nexport interface IRCell {\n text: string\n colSpan: number\n rowSpan: number\n}\n\n// ─── 메타데이터 ─────────────────────────────────────\n\n/** 문서 메타데이터 — 각 포맷에서 추출 가능한 필드만 채워짐 */\nexport interface DocumentMetadata {\n /** 문서 제목 */\n title?: string\n /** 작성자 */\n author?: string\n /** 작성 프로그램 (예: \"한글 2020\", \"Adobe Acrobat\") */\n creator?: string\n /** 생성일시 (ISO 8601) */\n createdAt?: string\n /** 수정일시 (ISO 8601) */\n modifiedAt?: string\n /** 페이지/섹션 수 */\n pageCount?: number\n /** 문서 포맷 버전 (예: HWP \"5.1.0.1\") */\n version?: string\n /** 설명 */\n description?: string\n /** 키워드 */\n keywords?: string[]\n}\n\n// ─── 파싱 옵션 ──────────────────────────────────────\n\n/** 파싱 옵션 — parse() 함수에 전달 */\nexport interface ParseOptions {\n /**\n * 파싱할 페이지/섹션 범위 (1-based).\n * - 배열: [1, 2, 3]\n * - 문자열: \"1-3\", \"1,3,5-7\"\n *\n * PDF: 정확한 페이지 단위. HWP/HWPX: 섹션 단위 근사치.\n */\n pages?: number[] | string\n /** 이미지 기반 PDF용 OCR 프로바이더 (선택) */\n ocr?: OcrProvider\n /**\n * OCR 모드 (CLI 자동 탐색용).\n * - \"auto\": 설치된 CLI 자동 탐색 (gemini→claude→codex→ollama→tesseract)\n * - \"gemini\"|\"claude\"|\"codex\"|\"ollama\"|\"tesseract\": 특정 도구 강제 지정\n * - \"off\": OCR 비활성화 (이미지 기반 PDF면 에러)\n * - undefined: 라이브러리 API 기존 동작 유지 (자동 탐색 안 함)\n */\n ocrMode?: OcrMode\n /** 진행률 콜백 — current: 현재 페이지/섹션, total: 전체 수 */\n onProgress?: (current: number, total: number) => void\n /** PDF 머리글/바닥글 자동 제거 */\n removeHeaderFooter?: boolean\n}\n\n// ─── 파싱 경고 ──────────────────────────────────────\n\n/** 파싱 중 스킵/실패한 요소 보고 */\nexport interface ParseWarning {\n /** 관련 페이지 번호 (알 수 있는 경우) */\n page?: number\n /** 경고 메시지 */\n message: string\n /** 구조화된 경고 코드 */\n code: WarningCode\n}\n\nexport type WarningCode =\n | \"SKIPPED_IMAGE\"\n | \"SKIPPED_OLE\"\n | \"TRUNCATED_TABLE\"\n | \"OCR_FALLBACK\"\n | \"UNSUPPORTED_ELEMENT\"\n | \"BROKEN_ZIP_RECOVERY\"\n | \"HIDDEN_TEXT_FILTERED\"\n | \"MALFORMED_XML\"\n | \"PARTIAL_PARSE\"\n | \"LENIENT_CFB_RECOVERY\"\n | \"OCR_PAGE_FAILED\"\n | \"OCR_CLI_FALLBACK\"\n\n/** 문서 구조 (헤딩 트리) */\nexport interface OutlineItem {\n level: number\n text: string\n pageNumber?: number\n}\n\n// ─── 에러 코드 ──────────────────────────────────────\n\n/** 구조화된 에러 코드 — 프로그래밍적 에러 핸들링용 */\nexport type ErrorCode =\n | \"EMPTY_INPUT\"\n | \"UNSUPPORTED_FORMAT\"\n | \"ENCRYPTED\"\n | \"DRM_PROTECTED\"\n | \"CORRUPTED\"\n | \"DECOMPRESSION_BOMB\"\n | \"ZIP_BOMB\"\n | \"IMAGE_BASED_PDF\"\n | \"NO_SECTIONS\"\n | \"PARSE_ERROR\"\n\n// ─── 파싱 결과 (discriminated union) ────────────────\n\nexport type FileType = \"hwpx\" | \"hwp\" | \"pdf\" | \"xlsx\" | \"docx\" | \"unknown\"\n\ninterface ParseResultBase {\n fileType: FileType\n /** 페이지/섹션 수 — PDF: 실제 페이지 수, HWP/HWPX: 섹션 수, XLSX: 시트 수 */\n pageCount?: number\n /** 이미지 기반 PDF 여부 (텍스트 추출 불가) */\n isImageBased?: boolean\n}\n\nexport interface ParseSuccess extends ParseResultBase {\n success: true\n /** 추출된 마크다운 텍스트 */\n markdown: string\n /** 중간 표현 블록 (구조화된 데이터 접근용) */\n blocks: IRBlock[]\n /** 문서 메타데이터 */\n metadata?: DocumentMetadata\n /** 문서 구조 (헤딩 트리) — v2.0 */\n outline?: OutlineItem[]\n /** 파싱 중 발생한 경고 — v2.0 */\n warnings?: ParseWarning[]\n /** 추출된 이미지 목록 — 마크다운에서 파일명으로 참조됨 */\n images?: ExtractedImage[]\n}\n\n/** 추출된 이미지 — ParseSuccess.images에 포함 */\nexport interface ExtractedImage {\n /** 마크다운에서 참조되는 파일명 (예: image_001.png) */\n filename: string\n /** 이미지 바이너리 */\n data: Uint8Array\n /** MIME 타입 */\n mimeType: string\n}\n\nexport interface ParseFailure extends ParseResultBase {\n success: false\n /** 오류 메시지 */\n error: string\n /** 구조화된 에러 코드 */\n code?: ErrorCode\n}\n\nexport type ParseResult = ParseSuccess | ParseFailure\n\n// ─── 문서 비교 (Diff) ───────────────────────────────\n\nexport type DiffChangeType = \"added\" | \"removed\" | \"modified\" | \"unchanged\"\n\nexport interface BlockDiff {\n type: DiffChangeType\n /** 원본 블록 (added이면 undefined) */\n before?: IRBlock\n /** 변경 후 블록 (removed이면 undefined) */\n after?: IRBlock\n /** modified 테이블의 셀 단위 diff */\n cellDiffs?: CellDiff[][]\n /** 유사도 (0-1) */\n similarity?: number\n}\n\nexport interface CellDiff {\n type: DiffChangeType\n before?: string\n after?: string\n}\n\nexport interface DiffResult {\n stats: { added: number; removed: number; modified: number; unchanged: number }\n diffs: BlockDiff[]\n}\n\n// ─── 양식 인식 ──────────────────────────────────────\n\nexport interface FormField {\n label: string\n value: string\n /** 0-based 소스 행 */\n row: number\n /** 0-based 소스 열 */\n col: number\n}\n\nexport interface FormResult {\n fields: FormField[]\n /** 양식 확신도 (0-1) */\n confidence: number\n}\n\n// ─── OCR 프로바이더 ─────────────────────────────────\n\n/** Vision LLM이 반환하는 구조화된 OCR 결과 */\nexport interface StructuredOcrResult {\n /** 구조화된 Markdown (테이블/헤딩/리스트 포함) */\n markdown: string\n}\n\n/** OCR 모드 — CLI --ocr 옵션 허용값 */\nexport type OcrMode = \"auto\" | \"gemini\" | \"claude\" | \"codex\" | \"ollama\" | \"tesseract\" | \"off\"\n\n/** 사용자 제공 OCR 함수 — 페이지 이미지를 받아 텍스트 또는 구조화된 결과 반환 */\nexport type OcrProvider = (\n pageImage: Uint8Array,\n pageNumber: number,\n mimeType: \"image/png\"\n) => Promise<string | StructuredOcrResult>\n\n// ─── Watch 모드 ─────────────────────────────────────\n\nexport interface WatchOptions {\n dir: string\n outDir?: string\n webhook?: string\n format?: \"markdown\" | \"json\"\n pages?: string\n silent?: boolean\n}\n\n// ─── 헤딩 감지 공통 임계값 ──────────────────────────\n\n/** 폰트 크기 비율 → heading level (전 파서 공통) */\nexport const HEADING_RATIO_H1 = 1.5\nexport const HEADING_RATIO_H2 = 1.3\nexport const HEADING_RATIO_H3 = 1.15\n\n// ─── 내부 파서 반환 타입 ─────────────────────────────\n\n/** 내부 파서가 index.ts에 반환하는 공통 타입 (HWP5/HWPX/PDF/XLSX/DOCX) */\nexport interface InternalParseResult {\n markdown: string\n blocks: IRBlock[]\n metadata?: DocumentMetadata\n outline?: OutlineItem[]\n warnings?: ParseWarning[]\n images?: ExtractedImage[]\n /** PDF 전용: 이미지 기반 PDF 여부 */\n isImageBased?: boolean\n}\n","/** HWP 5.x 레코드 리더, UTF-16LE 텍스트 추출, 스트림 압축해제 */\n\nimport { inflateRawSync, inflateSync } from \"zlib\"\nimport { KordocError } from \"../utils.js\"\n\n// ─── 레코드 태그 상수 ────────────────────────────────\n\nexport const TAG_PARA_HEADER = 0x0042\nexport const TAG_PARA_TEXT = 0x0043\nexport const TAG_CHAR_SHAPE = 0x0044\nexport const TAG_PARA_SHAPE = 0x0045\nexport const TAG_CTRL_HEADER = 0x0047\nexport const TAG_LIST_HEADER = 0x0048\nexport const TAG_TABLE = 0x004d\n\n// DocInfo 태그 (스타일 정보 해석용)\nexport const TAG_ID_MAPPINGS = 0x0032\nexport const TAG_FACE_NAME = 0x0033\nexport const TAG_DOC_CHAR_SHAPE = 0x0037\nexport const TAG_DOC_PARA_SHAPE = 0x0039\nexport const TAG_DOC_STYLE = 0x003a\n\n// 특수 문자 코드 (UTF-16LE) — HWP 5.0 바이너리 스펙 + rhwp 검증\n// 3가지 카테고리: char(2바이트), inline(16바이트), extended(16바이트)\n// char: 0, 13, 24-31 — 제어문자만, 확장 데이터 없음\n// inline: 4-9, 19-20 — 제어문자(2) + 확장(14) = 16바이트\n// extended: 1-3, 10-12, 14-18, 21-23 — 제어문자(2) + 확장(14) = 16바이트\nconst CHAR_LINE = 0x0000 // char: 줄바꿈\nconst CHAR_SECTION_BREAK = 0x000a // extended: 구역/단 정의 (14바이트 확장 데이터)\nconst CHAR_PARA = 0x000d // char: 문단 끝\nconst CHAR_TAB = 0x0009 // inline: 탭\nconst CHAR_HYPHEN = 0x001e // char: 하이픈\nconst CHAR_NBSP = 0x001f // char: 비분리 공백\nconst CHAR_FIXED_NBSP = 0x0018 // char: 고정 비분리 공백\nconst CHAR_FIXED_WIDTH = 0x0019 // char: 고정폭 공백\n\n// FileHeader 플래그\nexport const FLAG_COMPRESSED = 1 << 0\nexport const FLAG_ENCRYPTED = 1 << 1\nexport const FLAG_DISTRIBUTION = 1 << 2\nexport const FLAG_DRM = 1 << 4\n\n// ─── 레코드 구조 ─────────────────────────────────────\n\nexport interface HwpRecord {\n tagId: number\n level: number\n size: number\n data: Buffer\n}\n\nexport interface HwpFileHeader {\n signature: string\n versionMajor: number\n flags: number\n}\n\n// ─── 레코드 리더 ─────────────────────────────────────\n\n/** 최대 레코드 수 — 비정상 파일에 의한 메모리 폭주 방지 */\nconst MAX_RECORDS = 500_000\n\nexport function readRecords(data: Buffer): HwpRecord[] {\n const records: HwpRecord[] = []\n let offset = 0\n\n while (offset + 4 <= data.length && records.length < MAX_RECORDS) {\n const header = data.readUInt32LE(offset)\n offset += 4\n\n const tagId = header & 0x3ff\n const level = (header >> 10) & 0x3ff\n let size = (header >> 20) & 0xfff\n\n // 확장 크기\n if (size === 0xfff) {\n if (offset + 4 > data.length) break\n size = data.readUInt32LE(offset)\n offset += 4\n }\n\n if (offset + size > data.length) break\n records.push({ tagId, level, size, data: data.subarray(offset, offset + size) })\n offset += size\n }\n\n return records\n}\n\n// ─── 스트림 압축 해제 ────────────────────────────────\n\n/** 압축 해제 최대 크기 (500MB) — decompression bomb 방지 */\nconst MAX_DECOMPRESS_SIZE = 500 * 1024 * 1024\n\nexport function decompressStream(data: Buffer): Buffer {\n const opts = { maxOutputLength: MAX_DECOMPRESS_SIZE }\n if (data.length >= 2 && data[0] === 0x78) {\n try { return inflateSync(data, opts) } catch { /* fallback to raw */ }\n }\n return inflateRawSync(data, opts)\n}\n\n// ─── FileHeader 파싱 ─────────────────────────────────\n\nexport function parseFileHeader(data: Buffer): HwpFileHeader {\n if (data.length < 40) throw new KordocError(\"FileHeader가 너무 짧습니다 (최소 40바이트)\")\n const sig = data.subarray(0, 32).toString(\"utf8\").replace(/\\0+$/, \"\")\n return {\n signature: sig,\n versionMajor: data[35],\n flags: data.readUInt32LE(36),\n }\n}\n\n// ─── 스타일 정보 구조 ────────────────────────────────\n\n/** DocInfo에서 추출한 글자 모양 (CHAR_SHAPE) */\nexport interface HwpCharShape {\n /** 글꼴 크기 (단위: 0.1pt, 예: 100 = 10pt) */\n fontSize: number\n /**\n * 속성 플래그 (HWP5 바이너리 스펙 1.1 기준):\n * bit 0 = italic, bit 1 = bold, bit 2 = underline, bit 3 = outline\n * 검증 완료: 공식 스펙 + pyhwp/hwp.js 등 오픈소스 파서와 일치 (v1.7)\n */\n attrFlags: number\n}\n\n/** DocInfo에서 추출한 스타일 */\nexport interface HwpStyle {\n name: string\n /** 한글 이름 (UTF-16LE) */\n nameKo: string\n /** 연결된 charShape 인덱스 */\n charShapeId: number\n /** 연결된 paraShape 인덱스 */\n paraShapeId: number\n /** 스타일 타입: 0=paragraph, 1=character */\n type: number\n}\n\n/** DocInfo 파싱 결과 */\nexport interface HwpDocInfo {\n charShapes: HwpCharShape[]\n styles: HwpStyle[]\n}\n\n/** DocInfo 레코드들에서 스타일 정보 추출 */\nexport function parseDocInfo(records: HwpRecord[]): HwpDocInfo {\n const charShapes: HwpCharShape[] = []\n const styles: HwpStyle[] = []\n\n for (const rec of records) {\n if (rec.tagId === TAG_DOC_CHAR_SHAPE && rec.data.length >= 18) {\n // HWP5 CHAR_SHAPE 구조 (바이너리 스펙 1.1 기준):\n // faceId: 7개 언어 * u16 = 14바이트 (offset 0-13)\n // ratio: 7개 언어 * u8 = 7바이트 (offset 14-20)\n // spacing: 7개 언어 * s8 = 7바이트 (offset 21-27)\n // relSize: 7개 언어 * u8 = 7바이트 (offset 28-34)\n // charOffset: 7개 언어 * s8 = 7바이트 (offset 35-41)\n // baseSize: u32 at offset 42 (단위: 0.1pt)\n // attrFlags: u32 at offset 46 (bit0=italic, bit1=bold) — 공식 스펙 검증 완료\n if (rec.data.length >= 50) {\n const fontSize = rec.data.readUInt32LE(42) // 단위: 0.1pt\n const attrFlags = rec.data.readUInt32LE(46)\n charShapes.push({ fontSize, attrFlags })\n } else {\n // 짧은 레코드 — 스타일 정보 없음\n charShapes.push({ fontSize: 0, attrFlags: 0 })\n }\n }\n\n if (rec.tagId === TAG_DOC_STYLE && rec.data.length >= 8) {\n try {\n // STYLE 구조: nameLen(u16) + name(UTF-16LE) + nameKoLen(u16) + nameKo(UTF-16LE)\n // + type(u8) + nextStyleId(u16) + langId(s16) + paraShapeId(u16) + charShapeId(u16)\n let offset = 0\n const nameLen = rec.data.readUInt16LE(offset); offset += 2\n const nameBytes = nameLen * 2\n const name = nameBytes > 0 && offset + nameBytes <= rec.data.length\n ? rec.data.subarray(offset, offset + nameBytes).toString(\"utf16le\")\n : \"\"\n offset += nameBytes\n\n let nameKo = \"\"\n if (offset + 2 <= rec.data.length) {\n const nameKoLen = rec.data.readUInt16LE(offset); offset += 2\n const nameKoBytes = nameKoLen * 2\n if (nameKoBytes > 0 && offset + nameKoBytes <= rec.data.length) {\n nameKo = rec.data.subarray(offset, offset + nameKoBytes).toString(\"utf16le\")\n }\n offset += nameKoBytes\n }\n\n // type(u8) + nextStyleId(u16) + langId(s16) + paraShapeId(u16) + charShapeId(u16)\n const type = offset < rec.data.length ? rec.data.readUInt8(offset) : 0; offset += 1\n offset += 2 // nextStyleId\n offset += 2 // langId\n const paraShapeId = offset + 2 <= rec.data.length ? rec.data.readUInt16LE(offset) : 0; offset += 2\n const charShapeId = offset + 2 <= rec.data.length ? rec.data.readUInt16LE(offset) : 0\n\n styles.push({ name, nameKo, charShapeId, paraShapeId, type })\n } catch {\n // 파싱 실패 — 스킵\n }\n }\n }\n\n return { charShapes, styles }\n}\n\n// ─── UTF-16LE 텍스트 추출 (21가지 제어문자 처리) ─────\n\nexport function extractText(data: Buffer): string {\n let result = \"\"\n let i = 0\n\n while (i + 1 < data.length) {\n const ch = data.readUInt16LE(i)\n i += 2\n\n switch (ch) {\n // ── char 타입 (2바이트만, 확장 데이터 없음) ──\n case CHAR_LINE: result += \"\\n\"; break\n case CHAR_SECTION_BREAK: // 구역/단 정의 — extended(14바이트 스킵)\n result += \"\\n\"\n if (i + 14 <= data.length) i += 14\n break\n case CHAR_PARA: break // 문단 끝\n case CHAR_HYPHEN: result += \"-\"; break\n case CHAR_NBSP: result += \" \"; break\n case CHAR_FIXED_NBSP: result += \"\\u00a0\"; break // 진짜 NBSP\n case CHAR_FIXED_WIDTH: result += \" \"; break // 고정폭 공백\n\n // ── inline 타입 (2바이트 + 14바이트 확장) ──\n case CHAR_TAB:\n result += \"\\t\"\n if (i + 14 <= data.length) i += 14\n break\n\n default:\n if (ch >= 0x0001 && ch <= 0x001f) {\n // rhwp 기준 3-카테고리 분류:\n // extended(1-3, 11-12, 14-18, 21-23) + inline(4-9, 19-20) → 14바이트 스킵\n // char(24-31) → 스킵 없음 (이미 switch에서 24,25,30,31 처리됨)\n const isExtended = (ch >= 1 && ch <= 3) || (ch >= 11 && ch <= 12) || (ch >= 14 && ch <= 18) || (ch >= 21 && ch <= 23)\n const isInline = (ch >= 4 && ch <= 9) || (ch >= 19 && ch <= 20)\n if ((isExtended || isInline) && i + 14 <= data.length) i += 14\n } else if (ch >= 0x0020) {\n // UTF-16 surrogate pair 처리 (BMP 외 문자: 이모지, CJK 확장 등)\n if (ch >= 0xd800 && ch <= 0xdbff && i + 1 < data.length) {\n const lo = data.readUInt16LE(i)\n if (lo >= 0xdc00 && lo <= 0xdfff) {\n i += 2\n const codePoint = ((ch - 0xd800) << 10) + (lo - 0xdc00) + 0x10000\n result += String.fromCodePoint(codePoint)\n break\n }\n }\n result += String.fromCharCode(ch)\n }\n break\n }\n }\n\n return result\n}\n","/**\n * AES-128 ECB 순수 JS 구현 — 배포용 HWP 복호화 전용.\n * 외부 의존성 없음 (kordoc 제로 네이티브 의존성 원칙 유지).\n * 참조: rhwp (MIT) src/parser/crypto.rs + FIPS-197 (AES 표준)\n */\n\n// ── S-Box & 역 S-Box ──\n\nconst S_BOX = new Uint8Array([\n 0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,\n 0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,\n 0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,\n 0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,\n 0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,\n 0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,\n 0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,\n 0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,\n 0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,\n 0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,\n 0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,\n 0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,\n 0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,\n 0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,\n 0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,\n 0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16,\n])\n\nconst INV_S_BOX = new Uint8Array([\n 0x52,0x09,0x6a,0xd5,0x30,0x36,0xa5,0x38,0xbf,0x40,0xa3,0x9e,0x81,0xf3,0xd7,0xfb,\n 0x7c,0xe3,0x39,0x82,0x9b,0x2f,0xff,0x87,0x34,0x8e,0x43,0x44,0xc4,0xde,0xe9,0xcb,\n 0x54,0x7b,0x94,0x32,0xa6,0xc2,0x23,0x3d,0xee,0x4c,0x95,0x0b,0x42,0xfa,0xc3,0x4e,\n 0x08,0x2e,0xa1,0x66,0x28,0xd9,0x24,0xb2,0x76,0x5b,0xa2,0x49,0x6d,0x8b,0xd1,0x25,\n 0x72,0xf8,0xf6,0x64,0x86,0x68,0x98,0x16,0xd4,0xa4,0x5c,0xcc,0x5d,0x65,0xb6,0x92,\n 0x6c,0x70,0x48,0x50,0xfd,0xed,0xb9,0xda,0x5e,0x15,0x46,0x57,0xa7,0x8d,0x9d,0x84,\n 0x90,0xd8,0xab,0x00,0x8c,0xbc,0xd3,0x0a,0xf7,0xe4,0x58,0x05,0xb8,0xb3,0x45,0x06,\n 0xd0,0x2c,0x1e,0x8f,0xca,0x3f,0x0f,0x02,0xc1,0xaf,0xbd,0x03,0x01,0x13,0x8a,0x6b,\n 0x3a,0x91,0x11,0x41,0x4f,0x67,0xdc,0xea,0x97,0xf2,0xcf,0xce,0xf0,0xb4,0xe6,0x73,\n 0x96,0xac,0x74,0x22,0xe7,0xad,0x35,0x85,0xe2,0xf9,0x37,0xe8,0x1c,0x75,0xdf,0x6e,\n 0x47,0xf1,0x1a,0x71,0x1d,0x29,0xc5,0x89,0x6f,0xb7,0x62,0x0e,0xaa,0x18,0xbe,0x1b,\n 0xfc,0x56,0x3e,0x4b,0xc6,0xd2,0x79,0x20,0x9a,0xdb,0xc0,0xfe,0x78,0xcd,0x5a,0xf4,\n 0x1f,0xdd,0xa8,0x33,0x88,0x07,0xc7,0x31,0xb1,0x12,0x10,0x59,0x27,0x80,0xec,0x5f,\n 0x60,0x51,0x7f,0xa9,0x19,0xb5,0x4a,0x0d,0x2d,0xe5,0x7a,0x9f,0x93,0xc9,0x9c,0xef,\n 0xa0,0xe0,0x3b,0x4d,0xae,0x2a,0xf5,0xb0,0xc8,0xeb,0xbb,0x3c,0x83,0x53,0x99,0x61,\n 0x17,0x2b,0x04,0x7e,0xba,0x77,0xd6,0x26,0xe1,0x69,0x14,0x63,0x55,0x21,0x0c,0x7d,\n])\n\n// ── RCON (라운드 상수) ──\n\nconst RCON = new Uint8Array([0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36])\n\n// ── GF(2^8) 곱셈 ──\n\nfunction gmul(a: number, b: number): number {\n let p = 0\n for (let i = 0; i < 8; i++) {\n if (b & 1) p ^= a\n const hi = a & 0x80\n a = (a << 1) & 0xff\n if (hi) a ^= 0x1b\n b >>= 1\n }\n return p\n}\n\n// ── 키 확장 (AES-128: 4 words → 44 words) ──\n\nfunction expandKey(key: Uint8Array): Uint32Array {\n const w = new Uint32Array(44)\n\n // 첫 4 words: 원본 키\n for (let i = 0; i < 4; i++) {\n w[i] = (key[4 * i] << 24) | (key[4 * i + 1] << 16) | (key[4 * i + 2] << 8) | key[4 * i + 3]\n }\n\n for (let i = 4; i < 44; i++) {\n let temp = w[i - 1]\n if (i % 4 === 0) {\n // RotWord + SubWord + RCON\n temp = ((temp << 8) | (temp >>> 24)) >>> 0\n temp = (S_BOX[(temp >>> 24) & 0xff] << 24) |\n (S_BOX[(temp >>> 16) & 0xff] << 16) |\n (S_BOX[(temp >>> 8) & 0xff] << 8) |\n S_BOX[temp & 0xff]\n temp = (temp ^ (RCON[i / 4 - 1] << 24)) >>> 0\n }\n w[i] = (w[i - 4] ^ temp) >>> 0\n }\n\n return w\n}\n\n// ── AES-128 단일 블록 복호화 (16바이트) ──\n\nfunction decryptBlock(block: Uint8Array, roundKeys: Uint32Array): Uint8Array {\n // state를 4x4 column-major 배열로 로드\n const s = new Uint8Array(16)\n for (let i = 0; i < 16; i++) s[i] = block[i]\n\n // AddRoundKey (round 10)\n addRoundKey(s, roundKeys, 10)\n\n // Rounds 9 → 1\n for (let round = 9; round >= 1; round--) {\n invShiftRows(s)\n invSubBytes(s)\n addRoundKey(s, roundKeys, round)\n invMixColumns(s)\n }\n\n // Final round (round 0)\n invShiftRows(s)\n invSubBytes(s)\n addRoundKey(s, roundKeys, 0)\n\n return s\n}\n\nfunction addRoundKey(s: Uint8Array, w: Uint32Array, round: number): void {\n const base = round * 4\n for (let c = 0; c < 4; c++) {\n const k = w[base + c]\n s[c * 4] ^= (k >>> 24) & 0xff\n s[c * 4 + 1] ^= (k >>> 16) & 0xff\n s[c * 4 + 2] ^= (k >>> 8) & 0xff\n s[c * 4 + 3] ^= k & 0xff\n }\n}\n\nfunction invSubBytes(s: Uint8Array): void {\n for (let i = 0; i < 16; i++) s[i] = INV_S_BOX[s[i]]\n}\n\nfunction invShiftRows(s: Uint8Array): void {\n // Row 0: no shift\n // Row 1: shift right 1\n let t = s[13]; s[13] = s[9]; s[9] = s[5]; s[5] = s[1]; s[1] = t\n // Row 2: shift right 2\n t = s[2]; s[2] = s[10]; s[10] = t\n t = s[6]; s[6] = s[14]; s[14] = t\n // Row 3: shift right 3 (= left 1)\n t = s[3]; s[3] = s[7]; s[7] = s[11]; s[11] = s[15]; s[15] = t\n}\n\nfunction invMixColumns(s: Uint8Array): void {\n for (let c = 0; c < 4; c++) {\n const i = c * 4\n const a0 = s[i], a1 = s[i + 1], a2 = s[i + 2], a3 = s[i + 3]\n s[i] = gmul(a0, 0x0e) ^ gmul(a1, 0x0b) ^ gmul(a2, 0x0d) ^ gmul(a3, 0x09)\n s[i + 1] = gmul(a0, 0x09) ^ gmul(a1, 0x0e) ^ gmul(a2, 0x0b) ^ gmul(a3, 0x0d)\n s[i + 2] = gmul(a0, 0x0d) ^ gmul(a1, 0x09) ^ gmul(a2, 0x0e) ^ gmul(a3, 0x0b)\n s[i + 3] = gmul(a0, 0x0b) ^ gmul(a1, 0x0d) ^ gmul(a2, 0x09) ^ gmul(a3, 0x0e)\n }\n}\n\n// ── 공개 API ──\n\n/** AES-128 ECB 복호화. data 길이는 16의 배수여야 함. */\nexport function aes128EcbDecrypt(data: Uint8Array, key: Uint8Array): Uint8Array {\n if (key.length !== 16) throw new Error(\"AES-128 키는 16바이트여야 합니다\")\n if (data.length % 16 !== 0) throw new Error(\"AES ECB 입력은 16바이트의 배수여야 합니다\")\n\n const roundKeys = expandKey(key)\n const out = new Uint8Array(data.length)\n\n for (let offset = 0; offset < data.length; offset += 16) {\n const block = data.subarray(offset, offset + 16)\n const decrypted = decryptBlock(block, roundKeys)\n out.set(decrypted, offset)\n }\n\n return out\n}\n","/**\n * HWP 배포용(distribution) 문서 복호화.\n *\n * 배포용 HWP는 ViewText/Section{N} 스트림에 암호화된 본문을 저장.\n * 첫 레코드(HWPTAG_DISTRIBUTE_DOC_DATA)의 256바이트 payload에서 AES 키를 추출한 뒤\n * 나머지 데이터를 AES-128 ECB로 복호화.\n *\n * 알고리즘 참조: rhwp (MIT) src/parser/crypto.rs\n * 포맷 참조: HWP 5.0 바이너리 스펙 — 배포용 문서 구조\n */\n\nimport { aes128EcbDecrypt } from \"./aes.js\"\nimport { decompressStream } from \"./record.js\"\n\n// ── MSVC LCG (Linear Congruential Generator) ──\n\n/** MSVC CRT rand() 호환 LCG */\nclass MsvcLcg {\n private seed: number\n\n constructor(seed: number) {\n this.seed = seed >>> 0 // u32로 강제\n }\n\n /** 0 ~ 0x7FFF 범위 난수 반환 (MSVC rand() 호환) */\n rand(): number {\n // MSVC LCG: seed = seed * 214013 + 2531011\n // JS에서 32bit 정수 오버플로우를 정확히 재현하기 위해 Math.imul 사용\n this.seed = (Math.imul(this.seed, 214013) + 2531011) >>> 0\n return (this.seed >>> 16) & 0x7fff\n }\n}\n\n// ── 배포용 문서 256바이트 payload 복호화 ──\n\n/**\n * DISTRIBUTE_DOC_DATA 레코드의 256바이트 payload를 LCG+XOR로 복호화.\n *\n * 구조:\n * - bytes[0..4]: LCG seed (u32 LE)\n * - bytes[4..256]: XOR 암호화된 데이터\n *\n * XOR 규칙: LCG에서 키 바이트를 뽑고, n = (lcg.rand() & 0xF) + 1 바이트마다 키 교체\n */\nfunction decryptDistributePayload(payload: Uint8Array): Uint8Array {\n if (payload.length < 256) throw new Error(\"배포용 payload가 256바이트 미만입니다\")\n\n const seed = (payload[0] | (payload[1] << 8) | (payload[2] << 16) | (payload[3] << 24)) >>> 0\n const lcg = new MsvcLcg(seed)\n\n const result = new Uint8Array(payload.subarray(0, 256)) // 원본 복사\n\n // rhwp 호환: i=0부터 시작하여 n 카운터를 소비하되, i<4는 XOR 스킵 (seed 보존)\n // i=4부터 시작하면 LCG 시퀀스가 어긋남 — i=0~3에서도 n을 소비해야 정확함\n let i = 0\n let n = 0\n let key = 0\n\n while (i < 256) {\n if (n === 0) {\n key = lcg.rand() & 0xff\n n = (lcg.rand() & 0x0f) + 1\n }\n if (i >= 4) {\n result[i] ^= key\n }\n i++\n n--\n }\n\n return result\n}\n\n// ── AES 키 추출 ──\n\n/**\n * 복호화된 256바이트 payload에서 AES-128 키(16바이트) 추출.\n * offset = 4 + (decrypted[0] & 0x0F)\n */\nfunction extractAesKey(decryptedPayload: Uint8Array): Uint8Array {\n const offset = 4 + (decryptedPayload[0] & 0x0f)\n if (offset + 16 > decryptedPayload.length) {\n throw new Error(\"AES 키 추출 실패: 오프셋이 payload 범위를 초과합니다\")\n }\n return decryptedPayload.slice(offset, offset + 16)\n}\n\n// ── 레코드 헤더 파싱 ──\n\n/** HWP 레코드 헤더에서 tag_id와 size 추출 */\nfunction parseRecordHeader(data: Uint8Array, offset: number): { tagId: number; size: number; headerSize: number } {\n if (offset + 4 > data.length) throw new Error(\"레코드 헤더 파싱 실패: 데이터 부족\")\n\n const header = (data[offset] | (data[offset + 1] << 8) | (data[offset + 2] << 16) | (data[offset + 3] << 24)) >>> 0\n const tagId = header & 0x3ff\n let size = (header >>> 20) & 0xfff\n let headerSize = 4\n\n if (size === 0xfff) {\n if (offset + 8 > data.length) throw new Error(\"확장 레코드 크기 파싱 실패: 데이터 부족\")\n size = (data[offset + 4] | (data[offset + 5] << 8) | (data[offset + 6] << 16) | (data[offset + 7] << 24)) >>> 0\n headerSize = 8\n }\n\n return { tagId, size, headerSize }\n}\n\n// ── 공개 API ──\n\n/** HWPTAG_DISTRIBUTE_DOC_DATA 태그 ID (HWPTAG_BEGIN + 12 = 0x10 + 12 = 0x1C = 28) */\nconst TAG_DISTRIBUTE_DOC_DATA = 0x10 + 12 // = 28\n\n/**\n * ViewText 스트림을 복호화하여 일반 BodyText 레코드 데이터로 변환.\n *\n * @param viewTextRaw ViewText/Section{N} 스트림의 원본 바이트\n * @param compressed FileHeader의 compressed 플래그\n * @returns 복호화된 레코드 데이터 (readRecords()로 파싱 가능)\n */\nexport function decryptViewText(viewTextRaw: Buffer, compressed: boolean): Buffer {\n const data = new Uint8Array(viewTextRaw)\n\n // 1. 첫 레코드 파싱 (DISTRIBUTE_DOC_DATA)\n const rec = parseRecordHeader(data, 0)\n if (rec.tagId !== TAG_DISTRIBUTE_DOC_DATA) {\n throw new Error(`배포용 문서의 첫 레코드가 DISTRIBUTE_DOC_DATA(${TAG_DISTRIBUTE_DOC_DATA})가 아닙니다 (실제: ${rec.tagId})`)\n }\n\n const payloadStart = rec.headerSize\n const payloadEnd = payloadStart + rec.size\n if (payloadEnd > data.length || rec.size < 256) {\n throw new Error(\"배포용 payload가 유효하지 않습니다\")\n }\n\n // 2. 256바이트 payload 복호화 (LCG + XOR)\n const payload = data.subarray(payloadStart, payloadStart + 256)\n const decryptedPayload = decryptDistributePayload(payload)\n\n // 3. AES-128 키 추출\n const aesKey = extractAesKey(decryptedPayload)\n\n // 4. 나머지 데이터를 AES-128 ECB 복호화\n const encryptedStart = payloadEnd\n const encryptedData = data.subarray(encryptedStart)\n\n if (encryptedData.length === 0) {\n throw new Error(\"배포용 문서에 암호화된 본문 데이터가 없습니다\")\n }\n\n // AES ECB는 16바이트 블록 단위 — 패딩 처리\n const alignedLen = encryptedData.length - (encryptedData.length % 16)\n if (alignedLen === 0) {\n throw new Error(\"암호화된 데이터가 너무 짧습니다 (16바이트 미만)\")\n }\n\n const alignedData = encryptedData.subarray(0, alignedLen)\n const decrypted = aes128EcbDecrypt(alignedData, aesKey)\n\n // 5. 압축 해제 (compressed 플래그가 설정된 경우)\n if (compressed) {\n try {\n return decompressStream(Buffer.from(decrypted))\n } catch {\n // 압축이 아닐 수도 있음 — 그대로 반환\n return Buffer.from(decrypted)\n }\n }\n\n return Buffer.from(decrypted)\n}\n\n// 테스트용 내부 함수 export\nexport { MsvcLcg as _MsvcLcg, decryptDistributePayload as _decryptDistributePayload, extractAesKey as _extractAesKey }\n","/**\n * Lenient CFB (Compound File Binary / OLE2) 파서.\n *\n * 표준 cfb 모듈이 FAT 검증 실패로 거부하는 손상된 HWP 파일을 열기 위한 폴백.\n * 직접 헤더/FAT/디렉토리를 파싱하여 스트림 데이터를 추출.\n *\n * 참조: rhwp (MIT) src/parser/cfb_reader.rs (LenientCfbReader)\n * 참조: MS-CFB spec (https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cfb)\n */\n\nimport { decompressStream } from \"./record.js\"\n\n// ── 상수 ──\n\nconst CFB_MAGIC = Buffer.from([0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1])\nconst END_OF_CHAIN = 0xfffffffe\nconst FREE_SECT = 0xffffffff\n\n/** 순환 감지용 최대 체인 길이 */\nconst MAX_CHAIN_LENGTH = 1_000_000\n/** 최대 디렉토리 엔트리 수 */\nconst MAX_DIR_ENTRIES = 100_000\n/** 최대 스트림 크기 (100MB) */\nconst MAX_STREAM_SIZE = 500 * 1024 * 1024\n\n// ── 디렉토리 엔트리 ──\n\ninterface DirEntry {\n name: string\n type: number // 0=unknown, 1=storage, 2=stream, 5=root\n startSector: number\n size: number\n}\n\n// ── CFB 컨테이너 ──\n\nexport interface LenientCfbContainer {\n /** 이름 기반 스트림 탐색 */\n findStream(path: string): Buffer | null\n /** 디렉토리 엔트리 목록 */\n entries(): DirEntry[]\n}\n\n// ── 구현 ──\n\nexport function parseLenientCfb(data: Buffer): LenientCfbContainer {\n if (data.length < 512) throw new Error(\"CFB 파일이 너무 짧습니다 (최소 512바이트)\")\n if (!data.subarray(0, 8).equals(CFB_MAGIC)) throw new Error(\"CFB 매직 바이트 불일치\")\n\n // ── 헤더 파싱 ──\n\n const sectorSizeShift = data.readUInt16LE(30)\n if (sectorSizeShift < 7 || sectorSizeShift > 16) throw new Error(\"유효하지 않은 섹터 크기 시프트: \" + sectorSizeShift)\n const sectorSize = 1 << sectorSizeShift // 보통 512\n const miniSectorSizeShift = data.readUInt16LE(32)\n if (miniSectorSizeShift > 16) throw new Error(\"유효하지 않은 미니 섹터 크기 시프트: \" + miniSectorSizeShift)\n const miniSectorSize = 1 << miniSectorSizeShift // 보통 64\n\n const fatSectorCount = data.readUInt32LE(44)\n const firstDirSector = data.readUInt32LE(48)\n const miniStreamCutoff = data.readUInt32LE(56) // 보통 4096\n const firstMiniFatSector = data.readUInt32LE(60)\n const miniFatSectorCount = data.readUInt32LE(64)\n const firstDifatSector = data.readUInt32LE(68)\n const difatSectorCount = data.readUInt32LE(72)\n\n // ── 유틸 ──\n\n function sectorOffset(id: number): number {\n return 512 + id * sectorSize\n }\n\n function readSectorData(id: number): Buffer {\n const off = sectorOffset(id)\n if (off + sectorSize > data.length) return Buffer.alloc(0)\n return data.subarray(off, off + sectorSize)\n }\n\n // ── DIFAT → FAT 섹터 목록 ──\n\n const fatSectors: number[] = []\n\n // 헤더 내 DIFAT (최대 109개)\n for (let i = 0; i < 109 && fatSectors.length < fatSectorCount; i++) {\n const sid = data.readUInt32LE(76 + i * 4)\n if (sid === FREE_SECT || sid === END_OF_CHAIN) break\n fatSectors.push(sid)\n }\n\n // 추가 DIFAT 섹터 체인\n let difatSector = firstDifatSector\n const visitedDifat = new Set<number>()\n for (let d = 0; d < difatSectorCount && difatSector !== END_OF_CHAIN && difatSector !== FREE_SECT; d++) {\n if (visitedDifat.has(difatSector)) break\n visitedDifat.add(difatSector)\n\n const buf = readSectorData(difatSector)\n const entriesPerSector = (sectorSize / 4) - 1 // 마지막 4바이트는 다음 DIFAT 포인터\n for (let i = 0; i < entriesPerSector && fatSectors.length < fatSectorCount; i++) {\n const sid = buf.readUInt32LE(i * 4)\n if (sid === FREE_SECT || sid === END_OF_CHAIN) continue\n fatSectors.push(sid)\n }\n difatSector = buf.readUInt32LE(entriesPerSector * 4)\n }\n\n // ── FAT 테이블 구축 ──\n\n const entriesPerFatSector = sectorSize / 4\n const fatTable = new Uint32Array(fatSectors.length * entriesPerFatSector)\n\n for (let fi = 0; fi < fatSectors.length; fi++) {\n const buf = readSectorData(fatSectors[fi])\n for (let i = 0; i < entriesPerFatSector; i++) {\n fatTable[fi * entriesPerFatSector + i] = i * 4 + 3 < buf.length\n ? buf.readUInt32LE(i * 4)\n : FREE_SECT\n }\n }\n\n // ── 체인 리더 (순환 방지) ──\n\n function readChain(startSector: number, maxBytes: number): Buffer {\n if (startSector === END_OF_CHAIN || startSector === FREE_SECT) return Buffer.alloc(0)\n if (maxBytes > MAX_STREAM_SIZE) throw new Error(\"스트림이 너무 큽니다\")\n\n const chunks: Buffer[] = []\n let current = startSector\n let totalRead = 0\n const visited = new Set<number>()\n\n while (current !== END_OF_CHAIN && current !== FREE_SECT && totalRead < maxBytes) {\n if (visited.has(current)) break // 순환 감지\n if (visited.size > MAX_CHAIN_LENGTH) break\n visited.add(current)\n\n const buf = readSectorData(current)\n const remaining = maxBytes - totalRead\n chunks.push(remaining < sectorSize ? buf.subarray(0, remaining) : buf)\n totalRead += Math.min(buf.length, remaining)\n\n current = current < fatTable.length ? fatTable[current] : END_OF_CHAIN\n }\n\n return Buffer.concat(chunks)\n }\n\n // ── Mini-FAT 테이블 ──\n\n let miniFatTable: Uint32Array | null = null\n\n function getMiniFatTable(): Uint32Array {\n if (miniFatTable) return miniFatTable\n\n if (miniFatSectorCount === 0 || firstMiniFatSector === END_OF_CHAIN) {\n miniFatTable = new Uint32Array(0)\n return miniFatTable\n }\n\n const miniFatData = readChain(firstMiniFatSector, miniFatSectorCount * sectorSize)\n const entries = miniFatData.length / 4\n miniFatTable = new Uint32Array(entries)\n for (let i = 0; i < entries; i++) {\n miniFatTable[i] = miniFatData.readUInt32LE(i * 4)\n }\n return miniFatTable\n }\n\n // ── 디렉토리 엔트리 파싱 ──\n\n const dirData = readChain(firstDirSector, MAX_DIR_ENTRIES * 128)\n const dirEntries: DirEntry[] = []\n\n for (let offset = 0; offset + 128 <= dirData.length && dirEntries.length < MAX_DIR_ENTRIES; offset += 128) {\n const nameLen = dirData.readUInt16LE(offset + 64) // 바이트 수 (null 포함)\n if (nameLen <= 0 || nameLen > 64) {\n dirEntries.push({ name: \"\", type: 0, startSector: 0, size: 0 })\n continue\n }\n\n const nameBytes = nameLen - 2 // null terminator 제외\n const name = nameBytes > 0\n ? dirData.subarray(offset, offset + nameBytes).toString(\"utf16le\")\n : \"\"\n\n const type = dirData[offset + 66]\n const startSector = dirData.readUInt32LE(offset + 116)\n // CFBv3에서는 size가 u32 (offset 120), v4에서는 u64\n const size = dirData.readUInt32LE(offset + 120)\n\n dirEntries.push({ name, type, startSector, size })\n }\n\n // ── Root 엔트리에서 미니 스트림 추출 ──\n\n let miniStreamData: Buffer | null = null\n\n function getMiniStream(): Buffer {\n if (miniStreamData) return miniStreamData\n const root = dirEntries[0]\n if (!root || root.type !== 5) {\n miniStreamData = Buffer.alloc(0)\n return miniStreamData\n }\n miniStreamData = readChain(root.startSector, root.size || MAX_STREAM_SIZE)\n return miniStreamData\n }\n\n // ── 미니 스트림에서 읽기 ──\n\n function readMiniStream(startSector: number, size: number): Buffer {\n const mft = getMiniFatTable()\n const ms = getMiniStream()\n if (mft.length === 0 || ms.length === 0) return Buffer.alloc(0)\n\n const chunks: Buffer[] = []\n let current = startSector\n let totalRead = 0\n const visited = new Set<number>()\n\n while (current !== END_OF_CHAIN && current !== FREE_SECT && totalRead < size) {\n if (visited.has(current)) break\n if (visited.size > MAX_CHAIN_LENGTH) break\n visited.add(current)\n\n const off = current * miniSectorSize\n const remaining = size - totalRead\n const chunkSize = Math.min(miniSectorSize, remaining)\n if (off + chunkSize <= ms.length) {\n chunks.push(ms.subarray(off, off + chunkSize))\n }\n totalRead += chunkSize\n\n current = current < mft.length ? mft[current] : END_OF_CHAIN\n }\n\n return Buffer.concat(chunks)\n }\n\n // ── 스트림 읽기 (일반/미니 자동 분기) ──\n\n function readStreamData(entry: DirEntry): Buffer {\n if (entry.size === 0) return Buffer.alloc(0)\n if (entry.size < miniStreamCutoff) {\n const miniResult = readMiniStream(entry.startSector, entry.size)\n // 미니스트림이 비어있으면 일반 체인으로 폴백 (lenient)\n if (miniResult.length > 0) return miniResult\n }\n return readChain(entry.startSector, entry.size)\n }\n\n // ── 경로 기반 탐색 ──\n\n // 전체 경로 맵 구축 (간이: 이름 기반 flat lookup)\n // HWP 파일의 디렉토리 구조는 보통 1~2 depth이므로 이름 매칭으로 충분\n function findEntryByPath(path: string): DirEntry | null {\n // \"/FileHeader\" → \"FileHeader\"\n // \"/BodyText/Section0\" → path component matching\n const parts = path.replace(/^\\//, \"\").split(\"/\")\n\n if (parts.length === 1) {\n // 단일 이름 매칭\n return dirEntries.find(e => e.name === parts[0] && e.type === 2) ?? null\n }\n\n // 2-depth: storage/stream\n // HWP 구조: Root/BodyText/Section0, Root/DocInfo, Root/BinData/BIN0001 등\n const storageName = parts[0]\n const streamName = parts.slice(1).join(\"/\")\n\n // 디렉토리 구조 대신 이름 패턴으로 찾기 (lenient)\n for (const e of dirEntries) {\n if (e.type === 2 && e.name === streamName) {\n // 부모 확인은 생략 (lenient) — 중복 이름 시 첫 번째 반환\n return e\n }\n }\n\n // 정확한 이름이 아닌 경우 (ViewText/Section0 등)\n const lastPart = parts[parts.length - 1]\n return dirEntries.find(e => e.type === 2 && e.name === lastPart) ?? null\n }\n\n // ── 공개 API ──\n\n return {\n findStream(path: string): Buffer | null {\n // \\005 prefix 처리 (SummaryInformation)\n const normalized = path.replace(/^\\//, \"\")\n const entry = findEntryByPath(normalized)\n if (!entry || entry.type !== 2) return null\n const stream = readStreamData(entry)\n return stream.length > 0 ? stream : null\n },\n\n entries(): DirEntry[] {\n return dirEntries.filter(e => e.type === 2) // stream만\n },\n }\n}\n","/** HWP 5.x 바이너리 파서 — OLE2 컨테이너 → 섹션 → Markdown */\n\nimport {\n readRecords, decompressStream, parseFileHeader, extractText, parseDocInfo,\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 type HwpRecord, type HwpDocInfo, type HwpCharShape,\n} from \"./record.js\"\nimport { decryptViewText } from \"./crypto.js\"\nimport { parseLenientCfb, type LenientCfbContainer } from \"./cfb-lenient.js\"\nimport { buildTable, blocksToMarkdown, MAX_COLS, MAX_ROWS } from \"../table/builder.js\"\nimport type { CellContext, IRBlock, IRTable, DocumentMetadata, InternalParseResult, ParseOptions, ParseWarning, OutlineItem, InlineStyle, ExtractedImage } from \"../types.js\"\nimport { HEADING_RATIO_H1, HEADING_RATIO_H2, HEADING_RATIO_H3 } from \"../types.js\"\nimport { KordocError, sanitizeHref } from \"../utils.js\"\nimport { parsePageRange } from \"../page-range.js\"\n\nimport * as CFB from \"cfb\"\n\ninterface CfbEntry { name?: string; content?: Buffer | Uint8Array }\ninterface CfbContainer { FileIndex?: CfbEntry[] }\ninterface CfbModule {\n parse(data: Buffer): CfbContainer\n find(cfb: CfbContainer, path: string): CfbEntry | null\n}\n\n/** 최대 섹션 수 — 비정상 파일에 의한 무한 루프 방지 */\nconst MAX_SECTIONS = 100\n/** 누적 압축 해제 최대 크기 (100MB) */\nconst MAX_TOTAL_DECOMPRESS = 500 * 1024 * 1024\n\nexport function parseHwp5Document(buffer: Buffer, options?: ParseOptions): InternalParseResult {\n // CFB 파싱: strict 먼저, 실패 시 lenient 폴백\n let cfb: CfbContainer | null = null\n let lenientCfb: LenientCfbContainer | null = null\n const warnings: ParseWarning[] = []\n\n try {\n cfb = CFB.parse(buffer)\n } catch {\n try {\n lenientCfb = parseLenientCfb(buffer)\n warnings.push({ message: \"손상된 CFB 컨테이너 — lenient 모드로 복구\", code: \"LENIENT_CFB_RECOVERY\" })\n } catch {\n throw new KordocError(\"CFB 컨테이너 파싱 실패 (strict 및 lenient 모두)\")\n }\n }\n\n // CFB 래퍼: strict/lenient 통합 인터페이스\n const findStream = (path: string): Buffer | null => {\n if (cfb) {\n const entry = CFB.find(cfb, path)\n return entry?.content ? Buffer.from(entry.content) : null\n }\n return lenientCfb!.findStream(path)\n }\n\n const headerData = findStream(\"/FileHeader\")\n if (!headerData) throw new KordocError(\"FileHeader 스트림 없음\")\n const header = parseFileHeader(headerData)\n if (header.signature !== \"HWP Document File\") throw new KordocError(\"HWP 시그니처 불일치\")\n if (header.flags & FLAG_ENCRYPTED) throw new KordocError(\"암호화된 HWP는 지원하지 않습니다\")\n if (header.flags & FLAG_DRM) throw new KordocError(\"DRM 보호된 HWP는 지원하지 않습니다\")\n const compressed = (header.flags & FLAG_COMPRESSED) !== 0\n const distribution = (header.flags & FLAG_DISTRIBUTION) !== 0\n\n const metadata: DocumentMetadata = {\n version: `${header.versionMajor}.x`,\n }\n if (cfb) extractHwp5Metadata(cfb, metadata)\n\n // DocInfo 파싱 (스타일 정보 추출)\n const docInfo = cfb\n ? parseDocInfoStream(cfb, compressed)\n : parseDocInfoFromStream(findStream(\"/DocInfo\"), compressed)\n\n const sections = distribution\n ? (cfb ? findViewTextSections(cfb, compressed) : findViewTextSectionsLenient(lenientCfb!, compressed))\n : (cfb ? findSections(cfb) : findSectionsLenient(lenientCfb!, compressed))\n if (sections.length === 0) throw new KordocError(\"섹션 스트림을 찾을 수 없습니다\")\n\n metadata.pageCount = sections.length\n\n // 페이지 범위 필터링 (섹션 단위 근사치)\n const pageFilter = options?.pages ? parsePageRange(options.pages, sections.length) : null\n const totalTarget = pageFilter ? pageFilter.size : sections.length\n\n const blocks: IRBlock[] = []\n let totalDecompressed = 0\n let parsedSections = 0\n for (let si = 0; si < sections.length; si++) {\n if (pageFilter && !pageFilter.has(si + 1)) continue\n try {\n const sectionData = sections[si]\n // 배포용 문서는 findViewTextSections에서 이미 복호화+압축해제 완료\n const data = (!distribution && compressed) ? decompressStream(Buffer.from(sectionData)) : Buffer.from(sectionData)\n totalDecompressed += data.length\n if (totalDecompressed > MAX_TOTAL_DECOMPRESS) throw new KordocError(\"총 압축 해제 크기 초과 (decompression bomb 의심)\")\n const records = readRecords(data)\n const sectionBlocks = parseSection(records, docInfo, warnings, si + 1)\n blocks.push(...sectionBlocks)\n parsedSections++\n options?.onProgress?.(parsedSections, totalTarget)\n } catch (secErr) {\n if (secErr instanceof KordocError) throw secErr\n warnings.push({ page: si + 1, message: `섹션 ${si + 1} 파싱 실패: ${secErr instanceof Error ? secErr.message : \"알 수 없는 오류\"}`, code: \"PARTIAL_PARSE\" })\n }\n }\n\n // BinData에서 이미지 추출\n const images = cfb\n ? extractHwp5Images(cfb, blocks, compressed, warnings)\n : extractHwp5ImagesLenient(lenientCfb!, blocks, compressed, warnings)\n\n // 스타일 기반 헤딩 감지\n if (docInfo) {\n detectHwp5Headings(blocks, docInfo)\n }\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/** DocInfo 스트림 파싱 (best-effort) */\nfunction parseDocInfoStream(cfb: CfbContainer, compressed: boolean): HwpDocInfo | null {\n try {\n const entry = CFB.find(cfb, \"/DocInfo\")\n if (!entry?.content) return null\n const data = compressed ? decompressStream(Buffer.from(entry.content)) : Buffer.from(entry.content)\n const records = readRecords(data)\n return parseDocInfo(records)\n } catch {\n return null\n }\n}\n\n/** DocInfo — Buffer에서 직접 파싱 (lenient용) */\nfunction parseDocInfoFromStream(raw: Buffer | null, compressed: boolean): HwpDocInfo | null {\n if (!raw) return null\n try {\n const data = compressed ? decompressStream(raw) : raw\n return parseDocInfo(readRecords(data))\n } catch {\n return null\n }\n}\n\n/** 스타일 기반 헤딩 감지 — 큰 폰트 + 짧은 텍스트 → heading */\nfunction detectHwp5Headings(blocks: IRBlock[], docInfo: HwpDocInfo): void {\n // 기본 폰트 크기 결정 (본문 스타일 또는 가장 많이 사용되는 크기)\n let baseFontSize = 0\n\n // \"바탕글\", \"본문\" 등 본문 스타일 찾기\n for (const style of docInfo.styles) {\n const name = (style.nameKo || style.name).toLowerCase()\n if (name.includes(\"바탕\") || name.includes(\"본문\") || name === \"normal\" || name === \"body\") {\n const cs = docInfo.charShapes[style.charShapeId]\n // cs.fontSize는 0.1pt 단위 → pt로 변환 (블록의 style.fontSize와 동일 단위)\n if (cs?.fontSize > 0) { baseFontSize = cs.fontSize / 10; break }\n }\n }\n\n // 본문 스타일 못 찾으면 블록의 폰트 크기 중 최빈값 사용\n if (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\n if (baseFontSize <= 0) return\n\n for (const block of blocks) {\n if (block.type !== \"paragraph\" || !block.text || !block.style?.fontSize) continue\n const text = block.text.trim()\n if (text.length === 0 || text.length > 200) continue\n if (/^\\d+$/.test(text)) continue\n\n const ratio = block.style.fontSize / baseFontSize\n let level = 0\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장\" 패턴은 heading으로 강제 지정\n if (/^제\\d+[조장절편]/.test(text) && 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// ─── 메타데이터 추출 (best-effort) ───────────────────\n\n/**\n * OLE2 SummaryInformation 스트림에서 제목/작성자 추출.\n * HWP5는 \\005HwpSummaryInformation 또는 \\005SummaryInformation에 저장.\n * OLE2 Property Set 포맷의 간이 파싱 — 실패 시 조용히 무시.\n */\nfunction extractHwp5Metadata(cfb: CfbContainer, metadata: DocumentMetadata): void {\n try {\n // HWP 전용 SummaryInformation 먼저, 없으면 표준 OLE2\n const summaryEntry =\n CFB.find(cfb, \"/\\x05HwpSummaryInformation\") ||\n CFB.find(cfb, \"/\\x05SummaryInformation\")\n if (!summaryEntry?.content) return\n\n const data = Buffer.from(summaryEntry.content)\n if (data.length < 48) return\n\n // OLE2 Property Set Header: byte order(2) + version(2) + OS(4) + CLSID(16) + numSets(4) = 28\n // Then FMTID(16) + offset(4)\n const numSets = data.readUInt32LE(24)\n if (numSets === 0) return\n\n const setOffset = data.readUInt32LE(44)\n if (setOffset >= data.length - 8) return\n\n // Property Set: size(4) + numProperties(4) + [propertyId(4) + offset(4)] * N\n const numProps = data.readUInt32LE(setOffset + 4)\n if (numProps === 0 || numProps > 100) return\n\n for (let i = 0; i < numProps; i++) {\n const entryOffset = setOffset + 8 + i * 8\n if (entryOffset + 8 > data.length) break\n\n const propId = data.readUInt32LE(entryOffset)\n const propOffset = setOffset + data.readUInt32LE(entryOffset + 4)\n if (propOffset + 8 > data.length) continue\n\n // Property ID: 2=Title, 4=Author, 6=Subject/Description\n if (propId !== 2 && propId !== 4 && propId !== 6) continue\n\n const propType = data.readUInt32LE(propOffset)\n // Type 0x1E = VT_LPSTR (ANSI string)\n if (propType !== 0x1e) continue\n\n const strLen = data.readUInt32LE(propOffset + 4)\n if (strLen === 0 || strLen > 10000 || propOffset + 8 + strLen > data.length) continue\n\n const str = data.subarray(propOffset + 8, propOffset + 8 + strLen).toString(\"utf8\").replace(/\\0+$/, \"\").trim()\n if (!str) continue\n\n if (propId === 2) metadata.title = str\n else if (propId === 4) metadata.author = str\n else if (propId === 6) metadata.description = str\n }\n } catch {\n // best-effort — 실패 시 조용히 무시\n }\n}\n\n/** 메타데이터만 추출 (전체 파싱 없이) — MCP parse_metadata용 */\nexport function extractHwp5MetadataOnly(buffer: Buffer): DocumentMetadata {\n const cfb = CFB.parse(buffer)\n const headerEntry = CFB.find(cfb, \"/FileHeader\")\n if (!headerEntry?.content) throw new KordocError(\"FileHeader 스트림 없음\")\n const header = parseFileHeader(Buffer.from(headerEntry.content))\n if (header.signature !== \"HWP Document File\") throw new KordocError(\"HWP 시그니처 불일치\")\n\n const metadata: DocumentMetadata = {\n version: `${header.versionMajor}.x`,\n }\n extractHwp5Metadata(cfb, metadata)\n\n const sections = findSections(cfb)\n metadata.pageCount = sections.length\n\n return metadata\n}\n\n/** 배포용 문서: ViewText/Section{N} 스트림을 복호화하여 반환 */\nfunction findViewTextSections(cfb: CfbContainer, compressed: boolean): Buffer[] {\n const sections: Array<{ idx: number; content: Buffer }> = []\n\n for (let i = 0; i < MAX_SECTIONS; i++) {\n const entry = CFB.find(cfb, `/ViewText/Section${i}`)\n if (!entry?.content) break\n try {\n const decrypted = decryptViewText(Buffer.from(entry.content), compressed)\n sections.push({ idx: i, content: decrypted })\n } catch {\n // 복호화 실패 시 해당 섹션 스킵\n break\n }\n }\n\n return sections.sort((a, b) => a.idx - b.idx).map(s => s.content)\n}\n\nfunction findSections(cfb: CfbContainer): Buffer[] {\n const sections: Array<{ idx: number; content: Buffer }> = []\n\n for (let i = 0; i < MAX_SECTIONS; i++) {\n const entry = CFB.find(cfb, `/BodyText/Section${i}`)\n if (!entry?.content) break\n sections.push({ idx: i, content: Buffer.from(entry.content) })\n }\n\n if (sections.length === 0 && cfb.FileIndex) {\n for (const entry of cfb.FileIndex) {\n if (sections.length >= MAX_SECTIONS) break\n if (entry.name?.startsWith(\"Section\") && entry.content) {\n const idx = parseInt(entry.name.replace(\"Section\", \"\"), 10) || 0\n sections.push({ idx, content: Buffer.from(entry.content) })\n }\n }\n }\n\n return sections.sort((a, b) => a.idx - b.idx).map(s => s.content)\n}\n\n/** Lenient CFB: BodyText/Section{N} 탐색 */\nfunction findSectionsLenient(lcfb: LenientCfbContainer, compressed: boolean): Buffer[] {\n const sections: Array<{ idx: number; content: Buffer }> = []\n for (let i = 0; i < MAX_SECTIONS; i++) {\n const raw = lcfb.findStream(`/BodyText/Section${i}`) ?? lcfb.findStream(`Section${i}`)\n if (!raw) break\n sections.push({ idx: i, content: compressed ? decompressStream(raw) : raw })\n }\n if (sections.length === 0) {\n // fallback: 이름에 \"Section\" 포함된 스트림\n for (const e of lcfb.entries()) {\n if (sections.length >= MAX_SECTIONS) break\n if (e.name.startsWith(\"Section\")) {\n const idx = parseInt(e.name.replace(\"Section\", \"\"), 10) || 0\n const raw = lcfb.findStream(e.name)\n if (raw) sections.push({ idx, content: compressed ? decompressStream(raw) : raw })\n }\n }\n }\n return sections.sort((a, b) => a.idx - b.idx).map(s => s.content)\n}\n\n/** Lenient CFB: ViewText/Section{N} 복호화 */\nfunction findViewTextSectionsLenient(lcfb: LenientCfbContainer, compressed: boolean): Buffer[] {\n const sections: Array<{ idx: number; content: Buffer }> = []\n for (let i = 0; i < MAX_SECTIONS; i++) {\n const raw = lcfb.findStream(`/ViewText/Section${i}`) ?? lcfb.findStream(`Section${i}`)\n if (!raw) break\n try {\n sections.push({ idx: i, content: decryptViewText(raw, compressed) })\n } catch { break }\n }\n return sections.sort((a, b) => a.idx - b.idx).map(s => s.content)\n}\n\n// ─── BinData ���미지 추출 ─────��─────────────────��────\n\n/** SHAPE_COMPONENT 태그 — HWP5 스펙 */\nconst TAG_SHAPE_COMPONENT = 0x004a\n\n/** gso 제어 뒤의 하위 레코드에서 binDataId 추출 (best-effort) */\nfunction extractBinDataId(records: HwpRecord[], ctrlIdx: number): number {\n const ctrlLevel = records[ctrlIdx].level\n // CTRL_HEADER 이후의 하위 레코드들을 순회\n for (let j = ctrlIdx + 1; j < records.length && j < ctrlIdx + 50; j++) {\n const r = records[j]\n if (r.level <= ctrlLevel) break // 같은/상위 레벨이면 이 제어 블록 끝\n // SHAPE_COMPONENT에서 picture 타입이면 binDataId 추출\n // picture 데이터는 SHAPE_COMPONENT 뒤에 오는 하위 레코드에 있음\n // HWP5에서 그림 정보는 level이 높은 하위 레코드에 binDataId가 uint16LE로 저장\n if (r.data.length >= 2) {\n // 매직바이트로 이미지인지 확인하는 대신, SHAPE_COMPONENT 뒤의 하위 레코드에서 binDataId를 읽음\n // HWP5 picture 구조: CTRL_HEADER(gso) → LIST_HEADER → SHAPE_COMPONENT → [picture data record]\n // picture data record에서 offset 0부터 uint16LE = binDataId\n if (r.tagId > TAG_SHAPE_COMPONENT && r.level > ctrlLevel + 1 && r.data.length >= 4) {\n const possibleId = r.data.readUInt16LE(0)\n if (possibleId < 10000) return possibleId // 합리적 범위\n }\n }\n }\n return -1\n}\n\n/** MIME 타입 매직바이트 판별 */\nfunction detectImageMime(data: Buffer | Uint8Array): string | null {\n if (data.length < 4) return null\n if (data[0] === 0x89 && data[1] === 0x50 && data[2] === 0x4e && data[3] === 0x47) return \"image/png\"\n if (data[0] === 0xff && data[1] === 0xd8 && data[2] === 0xff) return \"image/jpeg\"\n if (data[0] === 0x47 && data[1] === 0x49 && data[2] === 0x46) return \"image/gif\"\n if (data[0] === 0x42 && data[1] === 0x4d) return \"image/bmp\"\n if (data[0] === 0xd7 && data[1] === 0xcd && data[2] === 0xc6 && data[3] === 0x9a) return \"image/wmf\"\n if (data[0] === 0x01 && data[1] === 0x00 && data[2] === 0x00 && data[3] === 0x00) return \"image/emf\"\n return null\n}\n\n/** OLE2 BinData 스토리지에서 이미지 추출, blocks의 image 블록과 매핑 */\nfunction extractHwp5Images(\n cfb: CfbContainer,\n blocks: IRBlock[],\n compressed: boolean,\n warnings: ParseWarning[],\n): ExtractedImage[] {\n // BinData 스토리지의 모든 파일을 FileIndex 순회로 수집 (O(n), 기존 O(20000) CFB.find 제거)\n const binDataMap = new Map<number, { data: Buffer; name: string }>()\n const binDataRe = /\\/BinData\\/[Bb][Ii][Nn](\\d{4})$/\n if (cfb.FileIndex) {\n for (const entry of cfb.FileIndex) {\n if (!entry?.name || !entry.content) continue\n const match = entry.name.match(binDataRe)\n if (!match) continue\n const idx = parseInt(match[1], 10)\n let data = Buffer.from(entry.content)\n if (compressed) {\n try { data = decompressStream(data) } catch { /* 이미 비압축일 수 있음 */ }\n }\n binDataMap.set(idx, { data, name: entry.name })\n }\n }\n\n if (binDataMap.size === 0) return []\n\n const images: ExtractedImage[] = []\n let imageIndex = 0\n\n for (const block of blocks) {\n if (block.type !== \"image\" || !block.text) continue\n const binId = parseInt(block.text, 10)\n if (isNaN(binId)) continue\n\n const bin = binDataMap.get(binId)\n if (!bin) {\n warnings.push({ page: block.pageNumber, message: `BinData ${binId} 없음`, code: \"SKIPPED_IMAGE\" })\n block.type = \"paragraph\"\n block.text = `[이미지: BinData ${binId}]`\n continue\n }\n\n const mime = detectImageMime(bin.data)\n if (!mime) {\n warnings.push({ page: block.pageNumber, message: `BinData ${binId}: 알 수 없는 이미지 형식`, code: \"SKIPPED_IMAGE\" })\n block.type = \"paragraph\"\n block.text = `[이미지: ${bin.name}]`\n continue\n }\n\n imageIndex++\n const ext = mime.includes(\"jpeg\") ? \"jpg\" : mime.includes(\"png\") ? \"png\" : mime.includes(\"gif\") ? \"gif\" : mime.includes(\"bmp\") ? \"bmp\" : \"bin\"\n const filename = `image_${String(imageIndex).padStart(3, \"0\")}.${ext}`\n\n images.push({ filename, data: new Uint8Array(bin.data), mimeType: mime })\n block.text = filename\n block.imageData = { data: new Uint8Array(bin.data), mimeType: mime, filename: bin.name }\n }\n\n return images\n}\n\n/** Lenient CFB: BinData 이미지 추출 */\nfunction extractHwp5ImagesLenient(\n lcfb: LenientCfbContainer,\n blocks: IRBlock[],\n compressed: boolean,\n warnings: ParseWarning[],\n): ExtractedImage[] {\n // BinData 엔트리 수집\n const binDataMap = new Map<number, { data: Buffer; name: string }>()\n const binRe = /^BIN(\\d{4})/i\n for (const e of lcfb.entries()) {\n const match = e.name.match(binRe)\n if (!match) continue\n const idx = parseInt(match[1], 10)\n let raw = lcfb.findStream(e.name)\n if (!raw) continue\n if (compressed) {\n try { raw = decompressStream(raw) } catch { /* 이미 비압축일 수 있음 */ }\n }\n binDataMap.set(idx, { data: raw, name: e.name })\n }\n if (binDataMap.size === 0) return []\n\n const images: ExtractedImage[] = []\n let imageIndex = 0\n for (const block of blocks) {\n if (block.type !== \"image\" || !block.text) continue\n const binId = parseInt(block.text, 10)\n if (isNaN(binId)) continue\n const bin = binDataMap.get(binId)\n if (!bin) {\n warnings.push({ page: block.pageNumber, message: `BinData ${binId} ���음`, code: \"SKIPPED_IMAGE\" })\n block.type = \"paragraph\"; block.text = `[이미지: BinData ${binId}]`; continue\n }\n const mime = detectImageMime(bin.data)\n if (!mime) {\n warnings.push({ page: block.pageNumber, message: `BinData ${binId}: 알 수 없는 이미지 형식`, code: \"SKIPPED_IMAGE\" })\n block.type = \"paragraph\"; block.text = `[이미지: ${bin.name}]`; continue\n }\n imageIndex++\n const ext = mime.includes(\"jpeg\") ? \"jpg\" : mime.includes(\"png\") ? \"png\" : mime.includes(\"gif\") ? \"gif\" : mime.includes(\"bmp\") ? \"bmp\" : \"bin\"\n const filename = `image_${String(imageIndex).padStart(3, \"0\")}.${ext}`\n images.push({ filename, data: new Uint8Array(bin.data), mimeType: mime })\n block.text = filename\n block.imageData = { data: new Uint8Array(bin.data), mimeType: mime, filename: bin.name }\n }\n return images\n}\n\nfunction parseSection(records: HwpRecord[], docInfo: HwpDocInfo | null, warnings: ParseWarning[], sectionNum: number): IRBlock[] {\n const blocks: IRBlock[] = []\n let i = 0\n\n while (i < records.length) {\n const rec = records[i]\n\n if (rec.tagId === TAG_PARA_HEADER && rec.level === 0) {\n const { paragraph, tables, nextIdx, charShapeIds } = parseParagraphWithTables(records, i)\n if (paragraph) {\n const block: IRBlock = { type: \"paragraph\", text: paragraph, pageNumber: sectionNum }\n // CHAR_SHAPE 기반 스타일 정보 추가\n if (docInfo && charShapeIds.length > 0) {\n const style = resolveCharStyle(charShapeIds, docInfo)\n if (style) block.style = style\n }\n blocks.push(block)\n }\n for (const t of tables) blocks.push({ type: \"table\", table: t, pageNumber: sectionNum })\n i = nextIdx\n continue\n }\n\n if (rec.tagId === TAG_CTRL_HEADER && rec.level <= 1 && rec.data.length >= 4) {\n const ctrlId = rec.data.subarray(0, 4).toString(\"ascii\")\n if (ctrlId === \" lbt\" || ctrlId === \"tbl \") {\n const { table, nextIdx } = parseTableBlock(records, i)\n if (table) blocks.push({ type: \"table\", table, pageNumber: sectionNum })\n i = nextIdx\n continue\n }\n // 그리기 객체(gso) — 이미지 또는 글상자\n if (ctrlId === \"gso \" || ctrlId === \" osg\") {\n const binId = extractBinDataId(records, i)\n if (binId >= 0) {\n blocks.push({ type: \"image\", text: String(binId), pageNumber: sectionNum })\n } else {\n // 이미지가 아니면 글상자(TextBox) 텍스트 추출 시도\n const boxText = extractTextBoxText(records, i)\n if (boxText) {\n blocks.push({ type: \"paragraph\", text: boxText, pageNumber: sectionNum })\n }\n // 텍스트도 없으면 조용히 스킵 (장식용 도형)\n }\n } else if (ctrlId === \" elo\" || ctrlId === \"ole \") {\n warnings.push({ page: sectionNum, message: `스킵된 제어 요소: ${ctrlId.trim()}`, code: \"SKIPPED_IMAGE\" })\n }\n // 각주/미주 — CTRL_HEADER 아래의 텍스트를 추출하여 footnoteText로 연결\n else if (ctrlId === \"fn \" || ctrlId === \" nf \" || ctrlId === \"en \" || ctrlId === \" ne \") {\n const noteText = extractNoteText(records, i)\n if (noteText && blocks.length > 0) {\n // 직전 paragraph 블록에 footnoteText 연결\n const lastBlock = blocks[blocks.length - 1]\n if (lastBlock.type === \"paragraph\") {\n lastBlock.footnoteText = lastBlock.footnoteText\n ? lastBlock.footnoteText + \"; \" + noteText\n : noteText\n }\n }\n }\n // 하이퍼링크 — CTRL_HEADER 데이터에서 URL 추출\n else if (ctrlId === \"%tok\" || ctrlId === \"klnk\") {\n const url = extractHyperlinkUrl(rec.data)\n if (url && blocks.length > 0) {\n const lastBlock = blocks[blocks.length - 1]\n if (lastBlock.type === \"paragraph\" && !lastBlock.href) {\n lastBlock.href = sanitizeHref(url) ?? undefined\n }\n }\n }\n }\n\n i++\n }\n\n return blocks\n}\n\n/** 각주/미주 CTRL_HEADER 아래의 본문 텍스트 추출 */\nfunction extractNoteText(records: HwpRecord[], ctrlIdx: number): string | null {\n const ctrlLevel = records[ctrlIdx].level\n const texts: string[] = []\n\n for (let j = ctrlIdx + 1; j < records.length && j < ctrlIdx + 100; j++) {\n const r = records[j]\n if (r.level <= ctrlLevel) break // 상위 레벨 도달 → 이 컨트롤 블록 끝\n\n if (r.tagId === TAG_PARA_TEXT) {\n const t = extractText(r.data).trim()\n if (t) texts.push(t)\n }\n }\n\n return texts.length > 0 ? texts.join(\" \") : null\n}\n\n/** 글상자(TextBox) 제어 요소 아래의 텍스트 추출 — extractNoteText와 동일 패턴 */\nfunction extractTextBoxText(records: HwpRecord[], ctrlIdx: number): string | null {\n const ctrlLevel = records[ctrlIdx].level\n const texts: string[] = []\n\n for (let j = ctrlIdx + 1; j < records.length && j < ctrlIdx + 200; j++) {\n const r = records[j]\n if (r.level <= ctrlLevel) break\n\n if (r.tagId === TAG_PARA_TEXT) {\n const t = extractText(r.data).trim()\n if (t) texts.push(t)\n }\n }\n\n return texts.length > 0 ? texts.join(\"\\n\") : null\n}\n\n/** 하이퍼링크 CTRL_HEADER에서 URL 추출 (best-effort) */\nfunction extractHyperlinkUrl(data: Buffer): string | null {\n // HWP5 하이퍼링크 CTRL_HEADER 구조:\n // ctrlId(4) + 기타 필드들... + URL 문자열 (UTF-16LE, length-prefixed)\n // 정확한 오프셋은 버전마다 다를 수 있으므로 URL 패턴 스캔으로 폴백\n try {\n // UTF-16LE에서 \"http\" 시그니처 스캔\n const httpSig = Buffer.from(\"http\", \"utf16le\") // \"h\\0t\\0t\\0p\\0\"\n const idx = data.indexOf(httpSig)\n if (idx >= 0) {\n // null terminator(0x0000 0x0000)까지 UTF-16LE로 읽기\n let end = idx\n while (end + 1 < data.length) {\n const ch = data.readUInt16LE(end)\n if (ch === 0) break\n end += 2\n }\n const url = data.subarray(idx, end).toString(\"utf16le\")\n // 기본 URL 검증\n if (/^https?:\\/\\/.+/.test(url) && url.length < 2000) {\n return url\n }\n }\n } catch { /* best-effort */ }\n return null\n}\n\n/** CHAR_SHAPE ID 배열에서 대표 스타일 결정 (최빈값) */\nfunction resolveCharStyle(charShapeIds: number[], docInfo: HwpDocInfo): InlineStyle | undefined {\n if (charShapeIds.length === 0 || docInfo.charShapes.length === 0) return undefined\n\n // 가장 많이 나타나는 charShapeId 사용\n const freq = new Map<number, number>()\n let maxCount = 0, dominantId = charShapeIds[0]\n for (const id of charShapeIds) {\n const count = (freq.get(id) || 0) + 1\n freq.set(id, count)\n if (count > maxCount) { maxCount = count; dominantId = id }\n }\n\n const cs = docInfo.charShapes[dominantId]\n if (!cs) return undefined\n\n const style: InlineStyle = {}\n if (cs.fontSize > 0) style.fontSize = cs.fontSize / 10 // 0.1pt → pt\n if (cs.attrFlags & 0x01) style.italic = true\n if (cs.attrFlags & 0x02) style.bold = true\n\n return (style.fontSize || style.bold || style.italic) ? style : undefined\n}\n\nfunction parseParagraphWithTables(records: HwpRecord[], startIdx: number) {\n const startLevel = records[startIdx].level\n let text = \"\"\n const tables: ReturnType<typeof buildTable>[] = []\n const charShapeIds: number[] = []\n let i = startIdx + 1\n\n while (i < records.length) {\n const rec = records[i]\n if (rec.tagId === TAG_PARA_HEADER && rec.level <= startLevel) break\n\n if (rec.tagId === TAG_PARA_TEXT) {\n text = extractText(rec.data)\n }\n\n // CHAR_SHAPE 레코드 — 문단 내 글자 모양 인덱스 배열\n if (rec.tagId === TAG_CHAR_SHAPE && rec.data.length >= 8) {\n // 구조: [position(u32) + charShapeId(u32)] * N\n for (let offset = 0; offset + 7 < rec.data.length; offset += 8) {\n charShapeIds.push(rec.data.readUInt32LE(offset + 4))\n }\n }\n\n if (rec.tagId === TAG_CTRL_HEADER && rec.data.length >= 4) {\n const ctrlId = rec.data.subarray(0, 4).toString(\"ascii\")\n if (ctrlId === \" lbt\" || ctrlId === \"tbl \") {\n const { table, nextIdx } = parseTableBlock(records, i)\n if (table) tables.push(table)\n i = nextIdx\n continue\n }\n }\n i++\n }\n\n const trimmed = text.trim()\n return { paragraph: trimmed || null, tables, nextIdx: i, charShapeIds }\n}\n\nfunction parseTableBlock(records: HwpRecord[], startIdx: number) {\n const tableLevel = records[startIdx].level\n let i = startIdx + 1\n let rows = 0, cols = 0\n const cells: CellContext[] = []\n\n while (i < records.length) {\n const rec = records[i]\n if (rec.tagId === TAG_PARA_HEADER && rec.level <= tableLevel) break\n if (rec.tagId === TAG_CTRL_HEADER && rec.level <= tableLevel) break\n\n if (rec.tagId === TAG_TABLE && rec.data.length >= 8) {\n rows = Math.min(rec.data.readUInt16LE(4), MAX_ROWS)\n cols = Math.min(rec.data.readUInt16LE(6), MAX_COLS)\n }\n\n if (rec.tagId === TAG_LIST_HEADER) {\n const { cell, nextIdx } = parseCellBlock(records, i, tableLevel)\n if (cell) cells.push(cell)\n i = nextIdx\n continue\n }\n i++\n }\n\n if (rows === 0 || cols === 0 || cells.length === 0) return { table: null, nextIdx: i }\n\n // colAddr/rowAddr가 있으면 arrangeCells가 이미 완성된 그리드를 반환하므로\n // buildTable(2-pass) 없이 직접 IRTable 생성 — 이중 colSpan 확장 방지\n const hasAddr = cells.some(c => c.colAddr !== undefined && c.rowAddr !== undefined)\n if (hasAddr) {\n const cellRows = arrangeCells(rows, cols, cells)\n const irCells = cellRows.map(row => row.map(c => ({\n text: c.text.trim(),\n colSpan: c.colSpan,\n rowSpan: c.rowSpan,\n })))\n return { table: { rows, cols, cells: irCells, hasHeader: rows > 1 }, nextIdx: i }\n }\n\n const cellRows = arrangeCells(rows, cols, cells)\n return { table: buildTable(cellRows), nextIdx: i }\n}\n\nfunction parseCellBlock(records: HwpRecord[], startIdx: number, tableLevel: number) {\n const rec = records[startIdx]\n const cellLevel = rec.level\n const texts: string[] = []\n\n // LIST_HEADER에서 셀 위치 및 병합 정보 추출\n // HWP5 셀 LIST_HEADER 구조:\n // paraCount(u16) + flags(u32) + width(u16) + colAddr(u16) + rowAddr(u16) + colSpan(u16) + rowSpan(u16)\n // offset: 0 2 6 8 10 12 14\n let colSpan = 1\n let rowSpan = 1\n let colAddr: number | undefined\n let rowAddr: number | undefined\n if (rec.data.length >= 16) {\n colAddr = rec.data.readUInt16LE(8)\n rowAddr = rec.data.readUInt16LE(10)\n const cs = rec.data.readUInt16LE(12)\n const rs = rec.data.readUInt16LE(14)\n if (cs > 0) colSpan = Math.min(cs, MAX_COLS)\n if (rs > 0) rowSpan = Math.min(rs, MAX_ROWS)\n }\n\n let i = startIdx + 1\n\n while (i < records.length) {\n const r = records[i]\n if (r.tagId === TAG_LIST_HEADER && r.level <= cellLevel) break\n if (r.level <= tableLevel && (r.tagId === TAG_PARA_HEADER || r.tagId === TAG_CTRL_HEADER)) break\n\n if (r.tagId === TAG_PARA_TEXT) {\n const t = extractText(r.data).trim()\n if (t) texts.push(t)\n }\n i++\n }\n\n return { cell: { text: texts.join(\"\\n\"), colSpan, rowSpan, colAddr, rowAddr } as CellContext, nextIdx: i }\n}\n\nfunction arrangeCells(rows: number, cols: number, cells: CellContext[]): CellContext[][] {\n const grid: (CellContext | null)[][] = Array.from({ length: rows }, () => Array(cols).fill(null))\n\n // colAddr/rowAddr가 있으면 직접 배치 (HWP5 병합 테이블 정확도 향상)\n const hasAddr = cells.some(c => c.colAddr !== undefined && c.rowAddr !== undefined)\n\n if (hasAddr) {\n for (const cell of cells) {\n const r = cell.rowAddr ?? 0\n const c = cell.colAddr ?? 0\n if (r >= rows || c >= cols) continue\n grid[r][c] = cell\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 < rows && c + dc < cols)\n grid[r + dr][c + dc] = { text: \"\", colSpan: 1, rowSpan: 1 }\n }\n }\n }\n } else {\n // fallback: 순차 배치 (colAddr 없는 경우)\n let cellIdx = 0\n for (let r = 0; r < rows && cellIdx < cells.length; r++) {\n for (let c = 0; c < cols && cellIdx < cells.length; c++) {\n if (grid[r][c] !== null) continue\n const cell = cells[cellIdx++]\n grid[r][c] = cell\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 < rows && c + dc < cols)\n grid[r + dr][c + dc] = { text: \"\", colSpan: 1, rowSpan: 1 }\n }\n }\n }\n }\n }\n\n return grid.map(row => row.map(c => c || { text: \"\", colSpan: 1, rowSpan: 1 }))\n}\n","/**\n * PDF 텍스트 추출 (pdfjs-dist static import 기반)\n *\n * polyfill을 먼저 import해야 DOMMatrix/Path2D/pdfjsWorker가 주입됨.\n * ES 모듈 호이스팅 때문에 별도 파일로 분리되어 있음.\n */\n\nimport type { ParseResult, InternalParseResult, IRBlock, IRTable, DocumentMetadata, ParseOptions, BoundingBox, ParseWarning, OutlineItem } from \"../types.js\"\nimport { HEADING_RATIO_H1, HEADING_RATIO_H2, HEADING_RATIO_H3 } from \"../types.js\"\nimport { KordocError } from \"../utils.js\"\nimport { parsePageRange } from \"../page-range.js\"\nimport { blocksToMarkdown } from \"../table/builder.js\"\nimport { extractLines, filterPageBorderLines, buildTableGrids, extractCells, mapTextToCells, cellTextToString, type TextItem, type TableGrid, type ExtractedCell } from \"./line-detector.js\"\nimport { detectClusterTables, type ClusterItem } from \"./cluster-detector.js\"\n// polyfill 먼저 (ES 모듈 호이스팅되므로 별도 파일 필수)\nimport \"./polyfill.js\"\nimport { getDocument, OPS, GlobalWorkerOptions } from \"pdfjs-dist/legacy/build/pdf.mjs\"\n\n// worker 비활성화 (polyfill에서 pdfjsWorker를 이미 주입했으므로)\nGlobalWorkerOptions.workerSrc = \"\"\n\n// ─── 안전 한계값 (구조적 파싱과 무관) ────────────────\nconst MAX_PAGES = 5000\nconst MAX_TOTAL_TEXT = 500 * 1024 * 1024 // 500MB\n/** PDF 로딩 타임아웃 (30초) — 악성/대용량 PDF 무한 대기 방지 */\nconst PDF_LOAD_TIMEOUT_MS = 30_000\n\n/** getDocument + 타임아웃 래퍼 */\nasync function loadPdfWithTimeout(buffer: ArrayBuffer) {\n const loadingTask = getDocument({\n data: new Uint8Array(buffer),\n useSystemFonts: true,\n disableFontFace: true,\n isEvalSupported: false,\n })\n let timer: ReturnType<typeof setTimeout> | undefined\n try {\n return await Promise.race([\n loadingTask.promise,\n new Promise<never>((_, reject) => {\n timer = setTimeout(() => { loadingTask.destroy(); reject(new KordocError(\"PDF 로딩 타임아웃 (30초 초과)\")) }, PDF_LOAD_TIMEOUT_MS)\n }),\n ])\n } finally {\n if (timer !== undefined) clearTimeout(timer)\n }\n}\n\ninterface PdfTextItem {\n str: string\n transform: number[]\n width: number\n height: number\n fontName?: string\n}\n\ninterface NormItem {\n text: string\n x: number\n y: number\n w: number\n h: number\n /** 폰트 높이(≈폰트 크기) — 헤딩 감지용 */\n fontSize: number\n fontName: string\n /** hidden text 여부 (투명/0pt) */\n isHidden: boolean\n}\n\nexport async function parsePdfDocument(buffer: ArrayBuffer, options?: ParseOptions): Promise<InternalParseResult> {\n const doc = await loadPdfWithTimeout(buffer)\n\n try {\n const pageCount = doc.numPages\n if (pageCount === 0) throw new KordocError(\"PDF에 페이지가 없습니다.\")\n\n // 메타데이터 추출 (best-effort)\n const metadata: DocumentMetadata = { pageCount }\n await extractPdfMetadata(doc, metadata)\n\n const blocks: IRBlock[] = []\n const warnings: ParseWarning[] = []\n let totalChars = 0\n let totalTextBytes = 0\n const effectivePageCount = Math.min(pageCount, MAX_PAGES)\n\n // 페이지 범위 필터링\n const pageFilter = options?.pages ? parsePageRange(options.pages, effectivePageCount) : null\n const totalTarget = pageFilter ? pageFilter.size : effectivePageCount\n\n // 전체 문서의 폰트 크기 통계 수집 (헤딩 감지용)\n const allFontSizes: number[] = []\n const pageHeights = new Map<number, number>()\n\n let parsedPages = 0\n for (let i = 1; i <= effectivePageCount; i++) {\n if (pageFilter && !pageFilter.has(i)) continue\n try {\n const page = await doc.getPage(i)\n const tc = await page.getTextContent()\n const viewport = page.getViewport({ scale: 1 })\n pageHeights.set(i, viewport.height)\n const rawItems = tc.items as PdfTextItem[]\n const items = normalizeItems(rawItems)\n\n // hidden text 필터링 + 경고 수집\n const { visible, hiddenCount } = filterHiddenText(items, viewport.width, viewport.height)\n if (hiddenCount > 0) {\n warnings.push({ page: i, message: `${hiddenCount}개 숨겨진 텍스트 요소 필터링됨`, code: \"HIDDEN_TEXT_FILTERED\" })\n }\n\n // 폰트 크기 통계 수집\n for (const item of visible) {\n if (item.fontSize > 0) allFontSizes.push(item.fontSize)\n }\n\n // 선 기반 테이블 감지를 위한 operatorList\n const opList = await page.getOperatorList()\n\n const pageBlocks = extractPageBlocksWithLines(visible, i, opList, viewport.width, viewport.height)\n for (const b of pageBlocks) blocks.push(b)\n\n // 이미지 기반 PDF 감지 + 크기 제한용 문자 수 집계\n for (const b of pageBlocks) {\n const t = b.text || \"\"\n totalChars += t.replace(/\\s/g, \"\").length\n totalTextBytes += t.length * 2\n }\n if (totalTextBytes > MAX_TOTAL_TEXT) throw new KordocError(\"텍스트 추출 크기 초과\")\n parsedPages++\n options?.onProgress?.(parsedPages, totalTarget)\n } catch (pageErr) {\n // 크기 초과는 전체 중단\n if (pageErr instanceof KordocError) throw pageErr\n warnings.push({ page: i, message: `페이지 ${i} 파싱 실패: ${pageErr instanceof Error ? pageErr.message : \"알 수 없는 오류\"}`, code: \"PARTIAL_PARSE\" })\n }\n }\n\n const parsedPageCount = parsedPages || (pageFilter ? pageFilter.size : effectivePageCount)\n if (totalChars / Math.max(parsedPageCount, 1) < 10) {\n // OCR 프로바이더 결정: 사용자 콜백 > ocrMode 지정 > 자동 탐색(CLI)\n let ocrProvider = options?.ocr ?? null\n const ocrMode = options?.ocrMode\n\n if (!ocrProvider && ocrMode && ocrMode !== \"off\") {\n try {\n const { resolveOcrProvider } = await import(\"../ocr/resolve.js\")\n ocrProvider = await resolveOcrProvider(ocrMode, warnings)\n } catch (resolveErr) {\n if (ocrMode !== \"auto\") {\n // 수동 지정 시 실패하면 바로 에러\n throw Object.assign(\n new KordocError(resolveErr instanceof Error ? resolveErr.message : \"OCR 프로바이더 초기화 실패\"),\n { isImageBased: true }\n )\n }\n // auto 모드에서 탐색 실패는 아래 에러 메시지로 처리\n }\n }\n\n if (ocrProvider) {\n try {\n const { ocrPages } = await import(\"../ocr/provider.js\")\n const ocrBlocks = await ocrPages(doc, ocrProvider, pageFilter, effectivePageCount, warnings)\n if (ocrBlocks.length > 0) {\n // blocksToMarkdown()으로 테이블/헤딩 등 구조 반영\n const ocrMarkdown = blocksToMarkdown(ocrBlocks)\n return {\n markdown: ocrMarkdown,\n blocks: ocrBlocks,\n metadata,\n warnings: warnings.length > 0 ? warnings : undefined,\n isImageBased: true,\n }\n }\n } catch {\n // OCR 실패 시 아래 에러로 fall through\n }\n }\n\n if (ocrMode === \"off\") {\n throw Object.assign(new KordocError(`이미지 기반 PDF (${pageCount}페이지, ${totalChars}자)`), { isImageBased: true })\n }\n\n // OCR 도구 없음 또는 전체 실패\n const errMsg = ocrMode\n ? `이미지 기반 PDF — OCR 실패 (${pageCount}페이지, ${totalChars}자)`\n : `이미지 기반 PDF (${pageCount}페이지, ${totalChars}자)`\n throw Object.assign(new KordocError(errMsg), { isImageBased: true })\n }\n\n // 머리글/바닥글 필터링 (기본 ON — 명시적 false일 때만 비활성화)\n if (options?.removeHeaderFooter !== false && parsedPageCount >= 3) {\n const removed = removeHeaderFooterBlocks(blocks, pageHeights, warnings)\n // 필터링된 블록 제거 (뒤에서부터 삭제)\n for (let ri = removed.length - 1; ri >= 0; ri--) {\n blocks.splice(removed[ri], 1)\n }\n }\n\n // 헤딩 감지: 폰트 크기 기반\n const medianFontSize = computeMedianFontSize(allFontSizes)\n if (medianFontSize > 0) {\n detectHeadings(blocks, medianFontSize)\n }\n\n // □/■ 마커 기반 서브헤딩 감지 (ODL 패턴)\n detectMarkerHeadings(blocks)\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 // blocksToMarkdown로 통일 — 헤딩 마크다운 반영 (HWP5/HWPX와 일관성)\n let markdown = cleanPdfText(blocksToMarkdown(blocks))\n\n return { markdown, blocks, metadata, outline: outline.length > 0 ? outline : undefined, warnings: warnings.length > 0 ? warnings : undefined }\n } finally {\n await doc.destroy().catch(() => {})\n }\n}\n\n// ─── PDF 메타데이터 추출 ────────────────────────────\n\nasync function extractPdfMetadata(doc: { getMetadata(): Promise<unknown> }, metadata: DocumentMetadata): Promise<void> {\n try {\n const result = await doc.getMetadata() as { info?: Record<string, unknown> } | null\n if (!result?.info) return\n const info = result.info\n\n if (typeof info.Title === \"string\" && info.Title.trim()) metadata.title = info.Title.trim()\n if (typeof info.Author === \"string\" && info.Author.trim()) metadata.author = info.Author.trim()\n if (typeof info.Creator === \"string\" && info.Creator.trim()) metadata.creator = info.Creator.trim()\n if (typeof info.Subject === \"string\" && info.Subject.trim()) metadata.description = info.Subject.trim()\n if (typeof info.Keywords === \"string\" && info.Keywords.trim()) {\n metadata.keywords = info.Keywords.split(/[,;]/).map((k: string) => k.trim()).filter(Boolean)\n }\n if (typeof info.CreationDate === \"string\") metadata.createdAt = parsePdfDate(info.CreationDate)\n if (typeof info.ModDate === \"string\") metadata.modifiedAt = parsePdfDate(info.ModDate)\n } catch {\n // best-effort\n }\n}\n\n/** PDF 날짜 형식 (D:YYYYMMDDHHmmSS) → ISO 8601 변환 */\nfunction parsePdfDate(dateStr: string): string | undefined {\n const m = dateStr.match(/D:(\\d{4})(\\d{2})?(\\d{2})?(\\d{2})?(\\d{2})?(\\d{2})?/)\n if (!m) return undefined\n const [, year, month = \"01\", day = \"01\", hour = \"00\", min = \"00\", sec = \"00\"] = m\n return `${year}-${month}-${day}T${hour}:${min}:${sec}`\n}\n\n/** 메타데이터만 추출 (전체 파싱 없이) — MCP parse_metadata용 */\nexport async function extractPdfMetadataOnly(buffer: ArrayBuffer): Promise<DocumentMetadata> {\n const doc = await loadPdfWithTimeout(buffer)\n\n try {\n const metadata: DocumentMetadata = { pageCount: doc.numPages }\n await extractPdfMetadata(doc, metadata)\n return metadata\n } finally {\n await doc.destroy().catch(() => {})\n }\n}\n\n// ═══════════════════════════════════════════════════════\n// Hidden text 필터링 (prompt injection 방어)\n// ═══════════════════════════════════════════════════════\n\nfunction filterHiddenText(items: NormItem[], pageWidth: number, pageHeight: number): { visible: NormItem[]; hiddenCount: number } {\n let hiddenCount = 0\n const visible: NormItem[] = []\n\n for (const item of items) {\n // 0pt 폰트 / 너비 0 → 숨겨진 텍스트\n if (item.isHidden) { hiddenCount++; continue }\n // 페이지 범위 밖 (여백 10% 허용)\n const margin = Math.max(pageWidth, pageHeight) * 0.1\n if (item.x < -margin || item.x > pageWidth + margin || item.y < -margin || item.y > pageHeight + margin) {\n hiddenCount++; continue\n }\n visible.push(item)\n }\n\n return { visible, hiddenCount }\n}\n\n// ═══════════════════════════════════════════════════════\n// 헤딩 감지 (폰트 크기 기반)\n// ═══════════════════════════════════════════════════════\n\nfunction computeMedianFontSize(sizes: number[]): number {\n if (sizes.length === 0) return 0\n const sorted = [...sizes].sort((a, b) => a - b)\n const mid = Math.floor(sorted.length / 2)\n return sorted.length % 2 === 0 ? (sorted[mid - 1] + sorted[mid]) / 2 : sorted[mid]\n}\n\n/**\n * 블록의 폰트 크기를 median과 비교하여 헤딩으로 승격.\n * - 150%+ → heading level 1\n * - 130%+ → heading level 2\n * - 115%+ → heading level 3\n * 조건: 짧은 텍스트 (200자 미만), 숫자만으로 구성되지 않음\n */\nfunction detectHeadings(blocks: IRBlock[], medianFontSize: number): void {\n for (const block of blocks) {\n if (block.type !== \"paragraph\" || !block.text || !block.style?.fontSize) continue\n const text = block.text.trim()\n if (text.length === 0 || text.length > 200) continue\n // 숫자만이면 헤딩 아님\n if (/^\\d+$/.test(text)) continue\n\n const ratio = block.style.fontSize / medianFontSize\n let level = 0\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 if (level > 0) {\n block.type = \"heading\"\n block.level = level\n // PDF 균등배분 스페이스 제거 (\"기 본 현 황\" → \"기본현황\")\n // 한글 글자 사이에 단독 공백이 반복되면 균등배분으로 판단\n block.text = collapseEvenSpacing(text)\n }\n }\n}\n\n/** 한글 균등배분 레이아웃의 글자 간 공백 제거 (\"기 본 현 황\" → \"기본현황\") */\nfunction collapseEvenSpacing(text: string): string {\n const tokens = text.split(\" \")\n // 토큰의 70% 이상이 1글자(한글/숫자/기호)면 균등배분으로 판단\n const singleCharCount = tokens.filter(t => t.length === 1).length\n if (tokens.length >= 3 && singleCharCount / tokens.length >= 0.7) {\n return tokens.join(\"\")\n }\n return text\n}\n\n/**\n * 의사 테이블 감지: 실제 데이터 테이블이 아닌 텍스트가 우연히 테이블로 감지된 경우.\n */\nfunction shouldDemoteTable(table: IRTable): boolean {\n const allCells = table.cells.flatMap(row => row.map(c => c.text.trim())).filter(Boolean)\n const allText = allCells.join(\" \")\n if (allText.length > 200) return false\n // □, ○, ■ 마커 포함 + 3행 이하 → 텍스트성\n if (/[□■◆○●▶]/.test(allText) && table.rows <= 3) return true\n // 빈 셀이 과반 → 의사 테이블 (텍스트가 우연히 선으로 둘러싸인 경우)\n const totalCells = table.rows * table.cols\n const emptyCells = totalCells - allCells.length\n if (table.rows <= 2 && emptyCells > totalCells * 0.5) return true\n // 1행 + 숫자 데이터 없음 → 의사 테이블\n if (table.rows === 1 && !/\\d{2,}/.test(allText)) return true\n return false\n}\n\n/** demote된 테이블을 구조화된 텍스트로 변환 (2열 → \"key: value\", 그 외 → 줄바꿈) */\nfunction demoteTableToText(table: IRTable): string {\n const lines: string[] = []\n for (let r = 0; r < table.rows; r++) {\n const cells = table.cells[r].map(c => c.text.trim()).filter(Boolean)\n if (cells.length === 0) continue\n if (table.cols === 2 && cells.length === 2) {\n // 2열 테이블 → KV 형식 보존\n lines.push(`${cells[0]} : ${cells[1]}`)\n } else {\n lines.push(cells.join(\" \"))\n }\n }\n return lines.join(\"\\n\")\n}\n\n/** □/■ 마커 및 짧은 섹션명을 서브헤딩으로 변환 */\nfunction detectMarkerHeadings(blocks: IRBlock[]): void {\n for (let i = 0; i < blocks.length; i++) {\n const block = blocks[i]\n if (block.type !== \"paragraph\" || !block.text) continue\n const text = block.text.trim()\n // □/■ + 한글로 시작하는 짧은 텍스트 (50자 미만)\n if (text.length < 50 && /^[□■◆◇▶]\\s*[가-힣]/.test(text)) {\n block.type = \"heading\"\n block.level = 4\n continue\n }\n // 순수 한글 2-6자 + 앞뒤가 표/헤딩/빈블록 → 섹션 제목으로 추정\n // (예: \"사업설명\", \"사업효과\", \"추진경위\")\n if (/^[가-힣]{2,6}$/.test(text) && block.style?.fontSize) {\n const prev = blocks[i - 1]\n const next = blocks[i + 1]\n const prevIsStructural = !prev || prev.type === \"table\" || prev.type === \"heading\" || prev.type === \"separator\"\n const nextIsStructural = !next || next.type === \"table\" || next.type === \"heading\" || (next.type === \"paragraph\" && next.text && /^[□■◆○●]/.test(next.text.trim()))\n if (prevIsStructural || nextIsStructural) {\n block.type = \"heading\"\n block.level = 3\n }\n }\n }\n}\n\n// ═══════════════════════════════════════════════════════\n// XY-Cut 읽기 순서 알고리즘\n// ═══════════════════════════════════════════════════════\n\ninterface TextRegion {\n items: NormItem[]\n minX: number; minY: number; maxX: number; maxY: number\n}\n\n/**\n * XY-Cut: 페이지를 재귀적으로 X/Y축 공백으로 분할하여 읽기 순서 결정.\n * - Y축 분할 (수평 공백 감지) → 위에서 아래\n * - X축 분할 (수직 공백 감지) → 왼쪽에서 오른쪽\n * - 분할 불가능하면 리프 노드 (하나의 텍스트 블록)\n */\n/** 재귀 깊이 제한 — 수천 아이템의 pathological 레이아웃에서 스택 오버플로 방지 */\nconst MAX_XYCUT_DEPTH = 50\n\nfunction xyCutOrder(items: NormItem[], gapThreshold: number, depth = 0): NormItem[][] {\n if (items.length === 0) return []\n if (items.length <= 2 || depth >= MAX_XYCUT_DEPTH) return [items]\n\n const region = computeRegion(items)\n\n // Y축 분할 시도 (수평 공백 감지)\n const ySplit = findYSplit(items, region, gapThreshold)\n if (ySplit !== null) {\n const upper = items.filter(i => i.y > ySplit)\n const lower = items.filter(i => i.y <= ySplit)\n // 빈 파티션 방어 — 한쪽이 비면 분할 의미 없음\n if (upper.length > 0 && lower.length > 0 && upper.length < items.length) {\n return [...xyCutOrder(upper, gapThreshold, depth + 1), ...xyCutOrder(lower, gapThreshold, depth + 1)]\n }\n }\n\n // X축 분할 시도 (수직 공백 감지)\n const xSplit = findXSplit(items, region, gapThreshold)\n if (xSplit !== null) {\n const left = items.filter(i => i.x + i.w / 2 < xSplit)\n const right = items.filter(i => i.x + i.w / 2 >= xSplit)\n if (left.length > 0 && right.length > 0 && left.length < items.length) {\n return [...xyCutOrder(left, gapThreshold, depth + 1), ...xyCutOrder(right, gapThreshold, depth + 1)]\n }\n }\n\n // 분할 불가 → 리프 노드\n return [items]\n}\n\nfunction computeRegion(items: NormItem[]): TextRegion {\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity\n for (const i of items) {\n if (i.x < minX) minX = i.x\n if (i.y < minY) minY = i.y\n if (i.x + i.w > maxX) maxX = i.x + i.w\n if (i.y + i.h > maxY) maxY = i.y + i.h\n }\n return { items, minX, minY, maxX, maxY }\n}\n\n/** Y축 분할점 찾기 — 수평 공백 밴드 중 가장 넓은 갭 */\nfunction findYSplit(items: NormItem[], _region: TextRegion, gapThreshold: number): number | null {\n // 아이템을 Y좌표로 정렬 (내림차순 — 위에서 아래)\n const sorted = [...items].sort((a, b) => b.y - a.y)\n let bestGap = gapThreshold\n let bestSplit: number | null = null\n\n for (let i = 1; i < sorted.length; i++) {\n const prevBottom = sorted[i - 1].y - sorted[i - 1].h\n const currTop = sorted[i].y\n const gap = prevBottom - currTop\n if (gap > bestGap) {\n bestGap = gap\n bestSplit = (prevBottom + currTop) / 2\n }\n }\n return bestSplit\n}\n\n/** X축 분할점 찾기 — 수직 공백 밴드 중 가장 넓은 갭 */\nfunction findXSplit(items: NormItem[], _region: TextRegion, gapThreshold: number): number | null {\n const sorted = [...items].sort((a, b) => a.x - b.x)\n let bestGap = gapThreshold\n let bestSplit: number | null = null\n\n for (let i = 1; i < sorted.length; i++) {\n const prevRight = sorted[i - 1].x + sorted[i - 1].w\n const currLeft = sorted[i].x\n const gap = currLeft - prevRight\n if (gap > bestGap) {\n bestGap = gap\n bestSplit = (prevRight + currLeft) / 2\n }\n }\n return bestSplit\n}\n\n// ═══════════════════════════════════════════════════════\n// 페이지 콘텐츠 추출 → IRBlock[] (v2: 바운딩 박스 + 페이지 번호)\n// ═══════════════════════════════════════════════════════\n\n/**\n * 선 기반 테이블 감지를 우선 시도, 실패 시 기존 휴리스틱 fallback.\n */\nfunction extractPageBlocksWithLines(\n items: NormItem[],\n pageNum: number,\n opList: { fnArray: Uint32Array | number[]; argsArray: unknown[][] },\n pageWidth: number,\n pageHeight: number,\n): IRBlock[] {\n if (items.length === 0) return []\n\n // 1단계: PDF 그래픽 명령에서 선 추출\n let { horizontals, verticals } = extractLines(opList.fnArray, opList.argsArray)\n ;({ horizontals, verticals } = filterPageBorderLines(horizontals, verticals, pageWidth, pageHeight))\n\n // 2단계: 선으로 테이블 그리드 구성\n const grids = buildTableGrids(horizontals, verticals)\n\n if (grids.length > 0) {\n return extractBlocksWithGrids(items, pageNum, grids, horizontals, verticals)\n }\n\n // Fallback: 기존 휴리스틱 (선이 없는 PDF)\n return extractPageBlocksFallback(items, pageNum)\n}\n\n/**\n * 선 기반 그리드가 감지된 경우: 테이블 영역의 텍스트는 셀에 매핑,\n * 나머지는 일반 텍스트 블록으로 처리.\n */\nfunction extractBlocksWithGrids(\n items: NormItem[],\n pageNum: number,\n grids: TableGrid[],\n horizontals: import(\"./line-detector.js\").LineSegment[],\n verticals: import(\"./line-detector.js\").LineSegment[],\n): IRBlock[] {\n const blocks: IRBlock[] = []\n const usedItems = new Set<NormItem>()\n\n // 그리드를 Y좌표 내림차순 정렬 (위→아래)\n const sortedGrids = [...grids].sort((a, b) => b.bbox.y2 - a.bbox.y2)\n\n for (const grid of sortedGrids) {\n // 그리드 영역 내 텍스트 아이템 수집\n const tableItems: NormItem[] = []\n const pad = 3\n for (const item of items) {\n if (usedItems.has(item)) continue\n if (item.x >= grid.bbox.x1 - pad && item.x + item.w <= grid.bbox.x2 + pad &&\n item.y >= grid.bbox.y1 - pad && item.y <= grid.bbox.y2 + pad) {\n tableItems.push(item)\n usedItems.add(item)\n }\n }\n\n // 셀 추출\n const cells = extractCells(grid, horizontals, verticals)\n if (cells.length === 0) continue\n\n // 텍스트→셀 매핑\n const textItems: TextItem[] = tableItems.map(i => ({\n text: i.text, x: i.x, y: i.y, w: i.w, h: i.h,\n fontSize: i.fontSize, fontName: i.fontName,\n }))\n const cellTextMap = mapTextToCells(textItems, cells)\n\n // IRTable 구성\n const numRows = grid.rowYs.length - 1\n const numCols = grid.colXs.length - 1\n const irGrid: import(\"../types.js\").IRCell[][] = Array.from(\n { length: numRows },\n () => Array.from({ length: numCols }, () => ({ text: \"\", colSpan: 1, rowSpan: 1 })),\n )\n\n for (const cell of cells) {\n const cellItems = cellTextMap.get(cell) || []\n let text = cellTextToString(cellItems)\n // 셀 안의 페이지 번호 표시 제거 (\"- 2 -\" 등)\n text = text.replace(/^[\\s]*[-–—]\\s*\\d+\\s*[-–—][\\s]*$/gm, \"\").trim()\n irGrid[cell.row][cell.col] = {\n text,\n colSpan: cell.colSpan,\n rowSpan: cell.rowSpan,\n }\n }\n\n const irTable: IRTable = {\n rows: numRows,\n cols: numCols,\n cells: irGrid,\n hasHeader: numRows > 1,\n }\n\n // 빈 테이블(모든 셀이 빈 문자열) 스킵\n const hasContent = irGrid.some(row => row.some(cell => cell.text.trim() !== \"\"))\n if (!hasContent) continue\n\n const tableBbox: BoundingBox = {\n page: pageNum,\n x: grid.bbox.x1, y: grid.bbox.y1,\n width: grid.bbox.x2 - grid.bbox.x1, height: grid.bbox.y2 - grid.bbox.y1,\n }\n\n // 의사 테이블 필터: 텍스트성 내용 → paragraph로 복원 (구조 보존)\n if (shouldDemoteTable(irTable)) {\n const demoted = demoteTableToText(irTable)\n if (demoted) {\n blocks.push({ type: \"paragraph\", text: demoted, pageNumber: pageNum, bbox: tableBbox, style: dominantStyle(tableItems) })\n }\n continue\n }\n\n blocks.push({ type: \"table\", table: irTable, pageNumber: pageNum, bbox: tableBbox })\n }\n\n // 테이블에 속하지 않은 나머지 텍스트 → 일반 블록\n const remaining = items.filter(i => !usedItems.has(i))\n if (remaining.length > 0) {\n // 위→아래 순서로 정렬\n remaining.sort((a, b) => b.y - a.y || a.x - b.x)\n\n // 테이블 전/후 텍스트를 Y좌표 기준으로 적절히 배치\n const textBlocks = detectListBlocks(extractPageBlocksFallback(remaining, pageNum))\n\n // Y좌표 기반으로 테이블과 텍스트를 올바른 순서로 병합\n const allBlocks = [...blocks, ...textBlocks]\n allBlocks.sort((a, b) => {\n const ay = a.bbox ? (a.bbox.y + a.bbox.height) : 0\n const by = b.bbox ? (b.bbox.y + b.bbox.height) : 0\n return by - ay // PDF는 y가 위가 큼 → 내림차순\n })\n return mergeAdjacentTableBlocks(allBlocks)\n }\n\n return mergeAdjacentTableBlocks(blocks)\n}\n\n/** 같은 열 수의 연속 테이블 블록을 하나로 합침 */\nfunction mergeAdjacentTableBlocks(blocks: IRBlock[]): IRBlock[] {\n if (blocks.length <= 1) return blocks\n const result: IRBlock[] = [blocks[0]]\n for (let i = 1; i < blocks.length; i++) {\n const prev = result[result.length - 1]\n const curr = blocks[i]\n if (prev.type === \"table\" && curr.type === \"table\" && prev.table && curr.table &&\n prev.table.cols === curr.table.cols) {\n // 합치기: prev의 cells에 curr의 cells 추가\n const merged: IRTable = {\n rows: prev.table.rows + curr.table.rows,\n cols: prev.table.cols,\n cells: [...prev.table.cells, ...curr.table.cells],\n hasHeader: prev.table.hasHeader,\n }\n result[result.length - 1] = { ...prev, table: merged }\n } else {\n result.push(curr)\n }\n }\n return result\n}\n\n/**\n * 기존 휴리스틱 기반 페이지 블록 추출 (선이 없는 PDF 대비 fallback).\n */\nfunction extractPageBlocksFallback(items: NormItem[], pageNum: number): IRBlock[] {\n if (items.length === 0) return []\n\n const blocks: IRBlock[] = []\n\n // 1단계: 페이지 전체에서 컬럼 감지 (테이블 우선)\n const allYLines = groupByY(items)\n const columns = detectColumns(allYLines)\n\n if (columns && columns.length >= 3) {\n // 테이블 감지됨 → 기존 extractWithColumns 로직 사용 (XY-Cut 스킵)\n const tableText = extractWithColumns(allYLines, columns)\n const bbox = computeBBox(items, pageNum)\n blocks.push({ type: \"paragraph\", text: tableText, pageNumber: pageNum, bbox, style: dominantStyle(items) })\n } else {\n // 2단계: 클러스터 기반 테이블 감지 (2열 이상, 선 없는 PDF)\n const clusterItems: ClusterItem[] = items.map(i => ({\n text: i.text, x: i.x, y: i.y, w: i.w, h: i.h,\n fontSize: i.fontSize, fontName: i.fontName,\n }))\n const clusterResults = detectClusterTables(clusterItems, pageNum)\n\n if (clusterResults.length > 0) {\n // 클러스터 테이블로 소비된 아이템 추적 (Map 기반 O(n) — 기존 indexOf O(n²) 제거)\n const ciToIdx = new Map<ClusterItem, number>()\n for (let ci = 0; ci < clusterItems.length; ci++) ciToIdx.set(clusterItems[ci], ci)\n const usedIndices = new Set<number>()\n for (const cr of clusterResults) {\n for (const ci of cr.usedItems) {\n const idx = ciToIdx.get(ci)\n if (idx !== undefined) usedIndices.add(idx)\n }\n blocks.push({ type: \"table\", table: cr.table, pageNumber: pageNum, bbox: cr.bbox })\n }\n\n // 테이블에 속하지 않은 나머지 텍스트 → 일반 블록\n const remaining = items.filter((_, idx) => !usedIndices.has(idx))\n if (remaining.length > 0) {\n const yLines = groupByY(remaining)\n for (const line of yLines) {\n const text = mergeLineSimple(line)\n if (!text.trim()) continue\n const bbox = computeBBox(line, pageNum)\n blocks.push({ type: \"paragraph\", text, pageNumber: pageNum, bbox, style: dominantStyle(line) })\n }\n }\n\n // Y좌표 기준 정렬\n blocks.sort((a, b) => {\n const ay = a.bbox ? (a.bbox.y + a.bbox.height) : 0\n const by = b.bbox ? (b.bbox.y + b.bbox.height) : 0\n return by - ay\n })\n } else {\n // 3단계: XY-Cut으로 읽기 순서 결정\n const allY = items.map(i => i.y)\n const pageHeight = Math.max(...allY) - Math.min(...allY)\n const gapThreshold = Math.max(15, pageHeight * 0.03)\n\n const orderedGroups = xyCutOrder(items, gapThreshold)\n\n for (const group of orderedGroups) {\n if (group.length === 0) continue\n const yLines = groupByY(group)\n\n // 그룹 내에서도 컬럼 감지 시도 (소형 테이블)\n const groupColumns = detectColumns(yLines)\n if (groupColumns && groupColumns.length >= 3) {\n const tableText = extractWithColumns(yLines, groupColumns)\n const bbox = computeBBox(group, pageNum)\n blocks.push({ type: \"paragraph\", text: tableText, pageNumber: pageNum, bbox, style: dominantStyle(group) })\n } else {\n for (const line of yLines) {\n const text = mergeLineSimple(line)\n if (!text.trim()) continue\n const bbox = computeBBox(line, pageNum)\n blocks.push({ type: \"paragraph\", text, pageNumber: pageNum, bbox, style: dominantStyle(line) })\n }\n }\n }\n }\n }\n\n // 한국어 특수 테이블 감지 (구분/항목/종류 패턴)\n return detectSpecialKoreanTables(blocks)\n}\n\n/** 아이템 그룹에서 바운딩 박스 계산 */\nfunction computeBBox(items: NormItem[], pageNum: number): BoundingBox {\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity\n for (const i of items) {\n if (i.x < minX) minX = i.x\n if (i.y < minY) minY = i.y\n if (i.x + i.w > maxX) maxX = i.x + i.w\n // h가 0인 경우 fontSize를 높이 대용으로 사용 (pdfjs가 height를 제공하지 않는 경우)\n const effectiveH = i.h > 0 ? i.h : i.fontSize\n if (i.y + effectiveH > maxY) maxY = i.y + effectiveH\n }\n return { page: pageNum, x: minX, y: minY, width: maxX - minX, height: maxY - minY }\n}\n\n/** 아이템 그룹의 대표 스타일 (최빈 폰트 크기) */\nfunction dominantStyle(items: NormItem[]): { fontSize: number; fontName: string } | undefined {\n if (items.length === 0) return undefined\n // 최빈 폰트 크기 찾기\n const freq = new Map<number, number>()\n let maxCount = 0, dominantSize = 0\n for (const i of items) {\n if (i.fontSize <= 0) continue\n const count = (freq.get(i.fontSize) || 0) + 1\n freq.set(i.fontSize, count)\n if (count > maxCount) { maxCount = count; dominantSize = i.fontSize }\n }\n if (dominantSize === 0) return undefined\n // 대표 폰트명 (빈 문자열은 undefined로)\n const fontName = items.find(i => i.fontSize === dominantSize)?.fontName || undefined\n return { fontSize: dominantSize, fontName }\n}\n\nfunction normalizeItems(rawItems: PdfTextItem[]): NormItem[] {\n return rawItems\n .filter(i => typeof i.str === \"string\" && i.str.trim() !== \"\")\n .map(i => {\n // transform matrix: [scaleX, skewY, skewX, scaleY, translateX, translateY]\n // 폰트 크기 ≈ scaleY의 절대값 (일반적으로 transform[3])\n const scaleY = Math.abs(i.transform[3])\n const scaleX = Math.abs(i.transform[0])\n const fontSize = Math.round(Math.max(scaleY, scaleX))\n\n return {\n text: i.str.trim(),\n x: Math.round(i.transform[4]),\n y: Math.round(i.transform[5]),\n w: Math.round(i.width),\n h: Math.round(i.height),\n fontSize,\n fontName: i.fontName || \"\",\n // 0pt 폰트이거나 너비 0 → hidden text (prompt injection 의심)\n isHidden: fontSize === 0 || (i.width === 0 && i.str.trim().length > 0),\n }\n })\n .sort((a, b) => b.y - a.y || a.x - b.x)\n}\n\nfunction groupByY(items: NormItem[]): NormItem[][] {\n if (items.length === 0) return []\n const lines: NormItem[][] = []\n let curY = items[0].y\n let curLine: NormItem[] = [items[0]]\n\n for (let i = 1; i < items.length; i++) {\n // Y좌표 허용 오차 3px — PDF 렌더링 미세 오차 보정, 별표 행 경계 감지에 최적화된 값\n if (Math.abs(items[i].y - curY) > 3) {\n lines.push(curLine)\n curLine = []\n curY = items[i].y\n }\n curLine.push(items[i])\n }\n if (curLine.length > 0) lines.push(curLine)\n return lines\n}\n\n// ═══════════════════════════════════════════════════════\n// 열 경계 감지 — 빈도 기반 x-히스토그램 클러스터링\n// ═══════════════════════════════════════════════════════\n\n/** prose 라인 판별: 아이템 간 gap이 모두 작으면 문장 (단어 나열) */\nfunction isProseSpread(items: NormItem[]): boolean {\n if (items.length < 4) return false\n const sorted = [...items].sort((a, b) => a.x - b.x)\n const gaps: number[] = []\n for (let i = 1; i < sorted.length; i++) {\n gaps.push(sorted[i].x - (sorted[i - 1].x + sorted[i - 1].w))\n }\n // gap의 최대값이 작고 평균 단어 길이가 짧으면 prose\n const maxGap = Math.max(...gaps)\n const avgLen = items.reduce((s, i) => s + i.text.length, 0) / items.length\n // 짧은 단어들이 좁은 간격으로 나열 = prose (예: \"위 표 제3호나목에서 남은 유효기간...\")\n return maxGap < 40 && avgLen < 5\n}\n\nfunction detectColumns(yLines: NormItem[][]): number[] | null {\n const allItems = yLines.flat()\n if (allItems.length === 0) return null\n const pageWidth = Math.max(...allItems.map(i => i.x + i.w)) - Math.min(...allItems.map(i => i.x))\n if (pageWidth < 100) return null\n\n // \"비고\" 이전 아이템만 사용 (비고 이후는 prose)\n let bigoLineIdx = -1\n for (let i = 0; i < yLines.length; i++) {\n if (yLines[i].length <= 2 && yLines[i].some(item => item.text === \"비고\")) {\n bigoLineIdx = i\n break\n }\n }\n const tableYLines = bigoLineIdx >= 0 ? yLines.slice(0, bigoLineIdx) : yLines\n\n // Step 1: 모든 아이템의 x를 수집 (prose 라인 제외)\n // CLUSTER_TOL 22px — 한국 공문서 PDF 열 간격에 최적화, 별표 표 열 감지 핵심값\n const CLUSTER_TOL = 22\n const xClusters: { center: number; count: number; minX: number }[] = []\n\n for (const line of tableYLines) {\n if (isProseSpread(line)) continue\n for (const item of line) {\n let found = false\n for (const c of xClusters) {\n if (Math.abs(item.x - c.center) <= CLUSTER_TOL) {\n c.center = Math.round((c.center * c.count + item.x) / (c.count + 1))\n c.minX = Math.min(c.minX, item.x)\n c.count++\n found = true\n break\n }\n }\n if (!found) {\n xClusters.push({ center: item.x, count: 1, minX: item.x })\n }\n }\n }\n\n // Step 2: 빈도 피크 — 최소 3회 이상 등장 (단발성 텍스트 노이즈 제거)\n const peaks = xClusters\n .filter(c => c.count >= 3)\n .sort((a, b) => a.minX - b.minX)\n\n // 최소 3개 열이 있어야 테이블로 판별 — 2열은 일반 2단 레이아웃과 구분 불가\n if (peaks.length < 3) return null\n\n // Step 3: 가까운 피크 병합 — MERGE_TOL 30px (같은 논리 열의 미세 위치 차이 흡수)\n const MERGE_TOL = 30\n const merged: { center: number; count: number; minX: number }[] = [peaks[0]]\n for (let i = 1; i < peaks.length; i++) {\n const prev = merged[merged.length - 1]\n if (peaks[i].minX - prev.minX < MERGE_TOL) {\n // 빈도 높은 쪽 유지, 최소 x는 작은 값\n if (peaks[i].count > prev.count) {\n prev.center = peaks[i].center\n }\n prev.count += peaks[i].count\n prev.minX = Math.min(prev.minX, peaks[i].minX)\n } else {\n merged.push({ ...peaks[i] })\n }\n }\n\n // 열 경계 = 각 클러스터의 minX (왼쪽 정렬 기준), 병합 후 재검증\n const columns = merged.filter(c => c.count >= 3).map(c => c.minX)\n return columns.length >= 3 ? columns : null\n}\n\nfunction findColumn(x: number, columns: number[]): number {\n for (let i = columns.length - 1; i >= 0; i--) {\n // 10px 왼쪽 허용 오차 — 셀 내 텍스트 미세 좌측 이탈 보정\n if (x >= columns[i] - 10) return i\n }\n return 0\n}\n\n// ═══════════════════════════════════════════════════════\n// 열 기반 추출 — 테이블/텍스트 영역 분리\n// ═══════════════════════════════════════════════════════\n\nfunction extractWithColumns(yLines: NormItem[][], columns: number[]): string {\n const result: string[] = []\n const colMin = columns[0]\n const colMax = columns[columns.length - 1]\n\n // \"비고\" 라인 감지 — 이후는 텍스트로 처리\n let bigoIdx = -1\n for (let i = 0; i < yLines.length; i++) {\n if (yLines[i].length <= 2 && yLines[i].some(item => item.text === \"비고\")) {\n bigoIdx = i\n break\n }\n }\n\n // 테이블 시작: 첫 번째 다열(3+ 열 사용) 라인\n let tableStart = -1\n for (let i = 0; i < (bigoIdx >= 0 ? bigoIdx : yLines.length); i++) {\n const usedCols = new Set(yLines[i].map(item => findColumn(item.x, columns)))\n if (usedCols.size >= 3) {\n tableStart = i\n break\n }\n }\n\n const tableEnd = bigoIdx >= 0 ? bigoIdx : yLines.length\n\n // 테이블 시작 이전 = 텍스트\n for (let i = 0; i < (tableStart >= 0 ? tableStart : tableEnd); i++) {\n result.push(mergeLineSimple(yLines[i]))\n }\n\n // 테이블 영역: 모든 라인을 그리드에 포함 (단일 아이템 라인도)\n if (tableStart >= 0) {\n const tableLines = yLines.slice(tableStart, tableEnd)\n // 테이블 x범위 밖의 라인만 텍스트로 분리\n // 좌측 20px, 우측 200px 허용 — 비고/주석 열이 오른쪽에 넓게 위치하는 공문서 특성 반영\n const gridLines: NormItem[][] = []\n for (const line of tableLines) {\n const inRange = line.some(item =>\n item.x >= colMin - 20 && item.x <= colMax + 200\n )\n if (inRange && !isProseSpread(line)) {\n gridLines.push(line)\n } else {\n // 그리드 밖 라인은 현재까지 축적된 그리드 출력 후 텍스트로\n if (gridLines.length > 0) {\n result.push(buildGridTable(gridLines.splice(0), columns))\n }\n result.push(mergeLineSimple(line))\n }\n }\n if (gridLines.length > 0) {\n result.push(buildGridTable(gridLines, columns))\n }\n }\n\n // 비고 영역\n if (bigoIdx >= 0) {\n result.push(\"\")\n for (let i = bigoIdx; i < yLines.length; i++) {\n result.push(mergeLineSimple(yLines[i]))\n }\n }\n\n return result.join(\"\\n\")\n}\n\n// ═══════════════════════════════════════════════════════\n// 그리드 테이블 빌더 — y-라인을 열에 배치 후 행 병합\n// ═══════════════════════════════════════════════════════\n\nfunction buildGridTable(lines: NormItem[][], columns: number[]): string {\n const numCols = columns.length\n\n // Step 1: 각 y-라인을 열에 배치\n const yRows: string[][] = lines.map(items => {\n const row = Array(numCols).fill(\"\")\n for (const item of items) {\n const col = findColumn(item.x, columns)\n row[col] = row[col] ? row[col] + \" \" + item.text : item.text\n }\n return row\n })\n\n // Step 2: 행 병합 — 새 논리적 행 판별\n // 데이터 열 기준점 (가격 등이 들어가는 오른쪽 열들)\n const dataColStart = Math.max(2, Math.floor(numCols / 2))\n const merged: string[][] = []\n\n for (const row of yRows) {\n if (row.every(c => c === \"\")) continue\n\n if (merged.length === 0) {\n merged.push([...row])\n continue\n }\n\n const prev = merged[merged.length - 1]\n const filledCols = row.map((c, i) => c ? i : -1).filter(i => i >= 0)\n const filledCount = filledCols.length\n\n let isNewRow = false\n\n // Rule 1: col 0에 텍스트 (3글자 이상) → 새 행 (단, \"권\"처럼 짧은 건 continuation)\n if (row[0] && row[0].length >= 3) {\n isNewRow = true\n }\n\n // Rule 2: col 1에 텍스트 → 항상 새 행 (새 항목 시작)\n if (!isNewRow && numCols > 1 && row[1]) {\n isNewRow = true\n }\n\n // Rule 3: 데이터 열(3+)에 새 값이 있고 이전 행 데이터 열에도 이미 값 있음 → 새 가격 행\n if (!isNewRow) {\n const hasData = row.slice(dataColStart).some(c => c !== \"\")\n const prevHasData = prev.slice(dataColStart).some(c => c !== \"\")\n if (hasData && prevHasData) {\n isNewRow = true\n }\n }\n\n // Exception: filledCount=1이고 col 0에 짧은 텍스트(≤2자) → word continuation (예: \"권\", \"여권\")\n if (isNewRow && filledCount === 1 && row[0] && row[0].length <= 2) {\n isNewRow = false\n }\n\n if (isNewRow) {\n merged.push([...row])\n } else {\n for (let c = 0; c < numCols; c++) {\n if (row[c]) {\n prev[c] = prev[c] ? prev[c] + \" \" + row[c] : row[c]\n }\n }\n }\n }\n\n if (merged.length < 2) {\n return merged.map(r => r.filter(c => c).join(\" \")).join(\"\\n\")\n }\n\n // Step 3: 헤더 행 병합 — 첫 N행이 모두 데이터열(dataColStart+)에 값이 없으면 헤더\n let headerEnd = 0\n for (let r = 0; r < merged.length; r++) {\n const hasDataValues = merged[r].slice(dataColStart).some(c => c && /\\d/.test(c))\n if (hasDataValues) break\n headerEnd = r + 1\n }\n\n if (headerEnd > 1) {\n // 헤더 행들을 하나로 합침\n const headerRow = Array(numCols).fill(\"\")\n for (let r = 0; r < headerEnd; r++) {\n for (let c = 0; c < numCols; c++) {\n if (merged[r][c]) {\n headerRow[c] = headerRow[c] ? headerRow[c] + \" \" + merged[r][c] : merged[r][c]\n }\n }\n }\n merged.splice(0, headerEnd, headerRow)\n }\n\n // Step 4: 마크다운 테이블\n const md: string[] = []\n md.push(\"| \" + merged[0].join(\" | \") + \" |\")\n md.push(\"| \" + merged[0].map(() => \"---\").join(\" | \") + \" |\")\n for (let r = 1; r < merged.length; r++) {\n md.push(\"| \" + merged[r].join(\" | \") + \" |\")\n }\n return md.join(\"\\n\")\n}\n\n// ═══════════════════════════════════════════════════════\n// 유틸\n// ═══════════════════════════════════════════════════════\n\nfunction mergeLineSimple(items: NormItem[]): string {\n if (items.length <= 1) return items[0]?.text || \"\"\n const sorted = [...items].sort((a, b) => a.x - b.x)\n let result = sorted[0].text\n for (let i = 1; i < sorted.length; i++) {\n const gap = sorted[i].x - (sorted[i - 1].x + sorted[i - 1].w)\n const avgFs = (sorted[i].fontSize + sorted[i - 1].fontSize) / 2\n // 15px+ 갭 = 탭 (열 구분)\n if (gap > 15) result += \"\\t\"\n // 매우 작은 갭 — 모든 문자 타입에서 공백 없이 붙임\n else if (gap < avgFs * 0.15) { /* no space */ }\n // 한글 관련 작은 갭 — PDF 문자 개별 배치 잔재\n else if (gap < avgFs * 0.35 && (/[가-힣]$/.test(result) || /^[가-힣]/.test(sorted[i].text))) { /* no space */ }\n // 3px+ 갭 = 공백 (단어 구분)\n else if (gap > 3) result += \" \"\n result += sorted[i].text\n }\n return result\n}\n\nexport function cleanPdfText(text: string): string {\n return mergeKoreanLines(\n text\n // \"- 2 -\" 스타일 페이지 번호 (독립 라인 및 목록 항목 형태 포함)\n .replace(/^[\\s]*[-–—]\\s*[-–—]?\\d+[-–—]?[\\s]*[-–—]?[\\s]*$/gm, \"\")\n // \"1 / 5\" 스타일 페이지 번호\n .replace(/^\\s*\\d+\\s*\\/\\s*\\d+\\s*$/gm, \"\")\n // 단독 페이지 번호 (줄 끝에 혼자 있는 숫자)\n .replace(/\\n\\d{1,4}\\n/g, \"\\n\")\n // 문서 마지막 단독 페이지 번호\n .replace(/\\n\\d{1,4}$/, \"\")\n )\n // 본문의 균등배분 스페이스 정리 (테이블/구분선 행 제외)\n .replace(/^(?!\\|).{3,30}$/gm, line => collapseEvenSpacing(line))\n .replace(/\\n{3,}/g, \"\\n\\n\")\n .trim()\n}\n\nfunction startsWithMarker(line: string): boolean {\n const t = line.trimStart()\n return /^[가-힣ㄱ-ㅎ][.)]/.test(t) || /^\\d+[.)]/.test(t) || /^\\([가-힣ㄱ-ㅎ\\d]+\\)/.test(t) ||\n /^[○●※▶▷◆◇■□★☆\\-·]\\s/.test(t) || /^제\\d+[조항호장절]/.test(t)\n}\n\nfunction isStandaloneHeader(line: string): boolean {\n return /^제\\d+[조항호장절](\\([^)]*\\))?(\\s+\\S+){0,7}$/.test(line.trim())\n}\n\n// ═══════════════════════════════════════════════════════\n// 리스트 감지 — paragraph 블록 중 번호 패턴을 list 블록으로 변환\n// ═══════════════════════════════════════════════════════\n\n/**\n * 연속된 paragraph 블록에서 번호 리스트 패턴을 감지하여 list 블록으로 변환.\n * \"비고\" 헤더 뒤에 오는 \"1.\", \"2.\" 패턴이 대표적.\n */\nfunction detectListBlocks(blocks: IRBlock[]): IRBlock[] {\n const result: IRBlock[] = []\n\n for (let i = 0; i < blocks.length; i++) {\n const block = blocks[i]\n\n if (block.type === \"paragraph\" && block.text) {\n const text = block.text.trim()\n // 번호 리스트: \"1.\", \"2.\" 등\n if (/^\\d+\\.\\s/.test(text)) {\n result.push({ ...block, type: \"list\", listType: \"ordered\", text: block.text })\n continue\n }\n // 비번호 리스트: ○, -, ·, ※, ▶ 등\n if (/^[○●·※▶▷◆◇\\-]\\s/.test(text)) {\n result.push({ ...block, type: \"list\", listType: \"unordered\", text: block.text })\n continue\n }\n }\n\n result.push(block)\n }\n\n return result\n}\n\n// ═══════════════════════════════════════════════════════\n// 한국어 특수 테이블 감지 — \"구분/항목/종류\" 패턴 기반 key-value 테이블\n// ═══════════════════════════════════════════════════════\n\n/**\n * ODL SpecialTableProcessor 포팅: 연속된 \"구분:\", \"항목:\", \"종류:\" 등\n * 한국어 key-value 패턴을 2열 테이블로 변환.\n *\n * 동작:\n * 1) paragraph 블록의 텍스트에서 한국어 key-value 패턴 감지\n * 2) \":\"가 있으면 key | value 2열, 없으면 colSpan=2 (전체 행)\n * 3) 연속된 패턴을 하나의 테이블로 그룹화\n */\nconst KOREAN_TABLE_HEADER_RE = /^\\(?(구분|항목|종류|분류|유형|대상|내용|기간|금액|비율|방법|절차|요건|조건|근거|목적|범위|기준)\\)?[:\\s]/\n\n/** KV 오탐 패턴: 시간(14:30), URL(://), 숫자:숫자(3:2) */\nconst KV_FALSE_POSITIVE_RE = /\\d{1,2}:\\d{2}|:\\/\\/|\\d+:\\d+/\n\nfunction detectSpecialKoreanTables(blocks: IRBlock[]): IRBlock[] {\n const result: IRBlock[] = []\n let kvLines: { key: string; value: string; block: IRBlock }[] = []\n\n const flushKvTable = () => {\n if (kvLines.length < 2) {\n // 2행 미만이면 테이블로 만들 가치 없음 → 원래 블록 복원\n for (const kv of kvLines) result.push(kv.block)\n kvLines = []\n return\n }\n\n // 2열 테이블 생성\n const cells: import(\"../types.js\").IRCell[][] = kvLines.map(kv => {\n if (kv.value) {\n return [\n { text: kv.key, colSpan: 1, rowSpan: 1 },\n { text: kv.value, colSpan: 1, rowSpan: 1 },\n ]\n }\n // \":\" 없는 줄 → 전체 행 (colSpan=2)\n return [\n { text: kv.key, colSpan: 2, rowSpan: 1 },\n { text: \"\", colSpan: 1, rowSpan: 1 },\n ]\n })\n\n const irTable: IRTable = {\n rows: cells.length,\n cols: 2,\n cells,\n hasHeader: true,\n }\n\n // 첫 블록의 위치 정보 사용\n const firstBlock = kvLines[0].block\n result.push({\n type: \"table\",\n table: irTable,\n pageNumber: firstBlock.pageNumber,\n bbox: firstBlock.bbox,\n })\n kvLines = []\n }\n\n for (const block of blocks) {\n if (block.type !== \"paragraph\" || !block.text) {\n flushKvTable()\n result.push(block)\n continue\n }\n\n const text = block.text.trim()\n\n // \"구분: xxx\" 또는 \"항목: xxx\" 패턴 매칭\n if (KOREAN_TABLE_HEADER_RE.test(text)) {\n const colonIdx = text.indexOf(\":\")\n if (colonIdx >= 0) {\n kvLines.push({\n key: text.slice(0, colonIdx).trim(),\n value: text.slice(colonIdx + 1).trim(),\n block,\n })\n } else {\n // \":\" 없이 공백으로 구분된 경우: \"구분 xxx\"\n const spaceIdx = text.search(/\\s/)\n if (spaceIdx > 0) {\n kvLines.push({\n key: text.slice(0, spaceIdx).trim(),\n value: text.slice(spaceIdx + 1).trim(),\n block,\n })\n } else {\n kvLines.push({ key: text, value: \"\", block })\n }\n }\n continue\n }\n\n // key-value 패턴이 아닌 블록이 나오면 축적된 것을 flush\n // 단, 이미 수집 중이고 현재 블록이 \"label: value\" 형태면 계속 수집\n if (kvLines.length > 0 && text.includes(\":\")) {\n // 오탐 제외: 시간(14:30), URL(http://), 숫자:숫자(3:2), 괄호 포함\n if (!KV_FALSE_POSITIVE_RE.test(text) && !text.includes(\"(\") && !text.includes(\")\")) {\n const colonIdx = text.indexOf(\":\")\n const key = text.slice(0, colonIdx).trim()\n // key가 순수 한글 2~8자 (공백/괄호 없음)면 유효한 key-value 라인\n if (/^[가-힣]+$/.test(key) && key.length >= 2 && key.length <= 8) {\n kvLines.push({\n key,\n value: text.slice(colonIdx + 1).trim(),\n block,\n })\n continue\n }\n }\n }\n\n flushKvTable()\n result.push(block)\n }\n\n flushKvTable()\n return result\n}\n\n// ─── 머리글/바닥글 감지 ────────────────────────────\n\n/** 상단/하단 10% 영역에서 페이지간 반복 텍스트를 감지하여 제거 대상 인덱스 반환 */\nfunction removeHeaderFooterBlocks(\n blocks: IRBlock[],\n pageHeights: Map<number, number>,\n warnings: ParseWarning[],\n): number[] {\n const ZONE_RATIO = 0.1 // 상하 10%\n const MIN_REPEAT = 3 // 최소 3페이지에서 반복\n\n // 페이지별 상단/하단 텍스트 수집\n const headerTexts = new Map<number, string[]>() // page → texts\n const footerTexts = new Map<number, string[]>()\n\n for (let bi = 0; bi < blocks.length; bi++) {\n const b = blocks[bi]\n if (!b.bbox || !b.pageNumber || !b.text?.trim()) continue\n const ph = pageHeights.get(b.bbox.page) || pageHeights.get(b.pageNumber)\n if (!ph) continue\n\n const blockTop = ph - (b.bbox.y + b.bbox.height) // PDF Y좌표는 아래가 0\n const blockBottom = ph - b.bbox.y\n\n if (blockBottom <= ph * ZONE_RATIO) {\n // 하단 영역\n const arr = footerTexts.get(b.pageNumber) || []\n arr.push(b.text.trim())\n footerTexts.set(b.pageNumber, arr)\n } else if (blockTop >= ph * (1 - ZONE_RATIO)) {\n // 상단 영역\n const arr = headerTexts.get(b.pageNumber) || []\n arr.push(b.text.trim())\n headerTexts.set(b.pageNumber, arr)\n }\n }\n\n // 반복 패턴 찾기: 페이지 번호 변동 허용 (숫자만 다른 경우)\n const repeatedPatterns = new Set<string>()\n for (const textsMap of [headerTexts, footerTexts]) {\n const patternCount = new Map<string, number>()\n for (const [, texts] of textsMap) {\n for (const t of texts) {\n // 숫자를 와일드카드로 치환하여 \"- 1 -\", \"- 2 -\" 같은 패턴 통합\n const normalized = t.replace(/\\d+/g, \"#\")\n patternCount.set(normalized, (patternCount.get(normalized) || 0) + 1)\n }\n }\n for (const [pattern, count] of patternCount) {\n if (count >= MIN_REPEAT) repeatedPatterns.add(pattern)\n }\n }\n\n if (repeatedPatterns.size === 0) return []\n\n // 반복 패턴에 매칭되는 블록 인덱스 수집\n const removeIndices: number[] = []\n for (let bi = 0; bi < blocks.length; bi++) {\n const b = blocks[bi]\n if (!b.bbox || !b.pageNumber || !b.text?.trim()) continue\n const ph = pageHeights.get(b.bbox.page) || pageHeights.get(b.pageNumber)\n if (!ph) continue\n\n const blockTop = ph - (b.bbox.y + b.bbox.height)\n const blockBottom = ph - b.bbox.y\n const inZone = blockBottom <= ph * ZONE_RATIO || blockTop >= ph * (1 - ZONE_RATIO)\n if (!inZone) continue\n\n const normalized = b.text.trim().replace(/\\d+/g, \"#\")\n if (repeatedPatterns.has(normalized)) {\n removeIndices.push(bi)\n }\n }\n\n if (removeIndices.length > 0) {\n warnings.push({ message: `${removeIndices.length}개 머리글/바닥글 요소 제거됨`, code: \"HIDDEN_TEXT_FILTERED\" })\n }\n\n return removeIndices\n}\n\nfunction mergeKoreanLines(text: string): string {\n if (!text) return \"\"\n const lines = text.split(\"\\n\")\n if (lines.length <= 1) return text\n const result: string[] = [lines[0]]\n\n for (let i = 1; i < lines.length; i++) {\n const prev = result[result.length - 1]\n const curr = lines[i]\n const currTrimmed = curr.trim()\n // 마크다운 헤딩/테이블/구분선은 병합하지 않음\n if (/^#{1,6}\\s/.test(prev) || /^#{1,6}\\s/.test(curr) || /^\\|/.test(currTrimmed) || /^---/.test(currTrimmed)) {\n result.push(curr)\n continue\n }\n // 쉼표로 끝나는 줄 + 다음 줄 = 연속 문장\n if (/,$/.test(prev.trim()) && currTrimmed.length > 0) {\n result[result.length - 1] = prev + \"\\n\" + curr\n continue\n }\n // (※ 로 시작하는 줄 = 이전 줄의 부연설명\n if (/^\\(※/.test(currTrimmed)) {\n result[result.length - 1] = prev + \" \" + currTrimmed\n continue\n }\n // 기존 한글 줄바꿈 병합\n if (/[가-힣·,\\-]$/.test(prev) && /^[가-힣(]/.test(curr) && !startsWithMarker(curr) && !isStandaloneHeader(prev)) {\n result[result.length - 1] = prev + \" \" + curr\n } else {\n result.push(curr)\n }\n }\n return result.join(\"\\n\")\n}\n","/**\n * PDF 그래픽 명령에서 수평/수직 선을 추출하고,\n * 선 교차점 기반으로 테이블 그리드를 구성하는 모듈.\n *\n * 이 파일의 테이블 감지 알고리즘은 OpenDataLoader PDF의\n * TableBorderBuilder를 참고하여 TypeScript로 재구현한 것입니다.\n *\n * Original work: Copyright 2025-2026 Hancom, Inc.\n * Licensed under the Apache License, Version 2.0\n * https://github.com/opendataloader-project/opendataloader-pdf\n *\n * Modifications: TypeScript 포팅, pdfjs-dist v4/v5 호환,\n * 한국어 PDF 특화 최적화 (문자 간격, 셀 텍스트 병합)\n */\n\nimport { OPS } from \"pdfjs-dist/legacy/build/pdf.mjs\"\n\n// ─── pdfjs-dist v5 DrawOPS (v5에서 constructPath 형식 변경) ──\n// v4: args = [subOps: number[], coords: number[], minMax]\n// subOps uses OPS.moveTo(13), OPS.lineTo(14), OPS.rectangle(19)\n// v5: args = [afterOp: number, [pathData: object], minMax]\n// pathData is flat array using DrawOPS: moveTo=0, lineTo=1, curveTo=2, closePath=4\nconst enum DrawOPS {\n moveTo = 0,\n lineTo = 1,\n curveTo = 2,\n quadraticCurveTo = 3,\n closePath = 4,\n}\n\n// ─── 타입 ─────────────────────────────────────────────\n\nexport interface LineSegment {\n x1: number; y1: number\n x2: number; y2: number\n lineWidth: number\n}\n\nexport interface TableGrid {\n /** 행 Y 좌표 경계 (위→아래 내림차순) */\n rowYs: number[]\n /** 열 X 좌표 경계 (좌→우 오름차순) */\n colXs: number[]\n /** 테이블 바운딩 박스 */\n bbox: { x1: number; y1: number; x2: number; y2: number }\n}\n\nexport interface ExtractedCell {\n row: number; col: number\n rowSpan: number; colSpan: number\n /** 셀 바운딩 박스 */\n bbox: { x1: number; y1: number; x2: number; y2: number }\n}\n\n// ─── 상수 ─────────────────────────────────────────────\n\n/** 수평/수직 판별 허용 오차 (pt) */\nconst ORIENTATION_TOL = 2\n/** 최소 선 길이 (너무 짧은 장식선 무시) */\nconst MIN_LINE_LENGTH = 10\n/** 좌표 병합 tolerance — ODL: 4 * vertexRadius, 여기선 고정 3pt */\nconst COORD_MERGE_TOL = 3\n/** 두 선이 같은 테이블에 속하는지 판별하는 거리 */\nconst CONNECT_TOL = 5\n/** 셀 경계 내부 판별 여유 (텍스트 매핑용) */\nconst CELL_PADDING = 2\n\n// ─── 선 추출 ──────────────────────────────────────────\n\n/**\n * pdfjs operatorList에서 수평/수직 선을 추출.\n * constructPath(91) 내의 moveTo→lineTo, rectangle 패턴을 인식.\n */\nexport function extractLines(\n fnArray: Uint32Array | number[],\n argsArray: unknown[][],\n): { horizontals: LineSegment[]; verticals: LineSegment[] } {\n const horizontals: LineSegment[] = []\n const verticals: LineSegment[] = []\n let lineWidth = 1\n\n // 현재 path의 세그먼트를 수집\n let currentPath: Array<{ x1: number; y1: number; x2: number; y2: number }> = []\n let pathStartX = 0, pathStartY = 0\n let curX = 0, curY = 0\n\n function pushRectangle(\n path: Array<{ x1: number; y1: number; x2: number; y2: number }>,\n rx: number, ry: number, rw: number, rh: number,\n ) {\n if (Math.abs(rh) < ORIENTATION_TOL * 2) {\n path.push({ x1: rx, y1: ry + rh / 2, x2: rx + rw, y2: ry + rh / 2 })\n } else if (Math.abs(rw) < ORIENTATION_TOL * 2) {\n path.push({ x1: rx + rw / 2, y1: ry, x2: rx + rw / 2, y2: ry + rh })\n } else {\n path.push(\n { x1: rx, y1: ry, x2: rx + rw, y2: ry },\n { x1: rx + rw, y1: ry, x2: rx + rw, y2: ry + rh },\n { x1: rx + rw, y1: ry + rh, x2: rx, y2: ry + rh },\n { x1: rx, y1: ry + rh, x2: rx, y2: ry },\n )\n }\n }\n\n function flushPath(isStroke: boolean) {\n if (!isStroke) { currentPath = []; return }\n for (const seg of currentPath) {\n classifyAndAdd(seg, lineWidth, horizontals, verticals)\n }\n currentPath = []\n }\n\n for (let i = 0; i < fnArray.length; i++) {\n const op = fnArray[i]\n const args = argsArray[i]\n\n switch (op) {\n case OPS.setLineWidth:\n lineWidth = (args as number[])[0] || 1\n break\n\n case OPS.constructPath: {\n const arg0 = args[0]\n\n if (Array.isArray(arg0)) {\n // ── pdfjs-dist v4 형식 ──\n // args = [subOps: number[], coords: number[], minMax]\n // subOps uses OPS constants: moveTo=13, lineTo=14, rectangle=19\n const subOps = arg0 as number[]\n const coords = (args as [number[], number[]])[1]\n let ci = 0\n\n for (const subOp of subOps) {\n if (subOp === OPS.moveTo) {\n curX = coords[ci++]; curY = coords[ci++]\n pathStartX = curX; pathStartY = curY\n } else if (subOp === OPS.lineTo) {\n const x2 = coords[ci++], y2 = coords[ci++]\n currentPath.push({ x1: curX, y1: curY, x2, y2 })\n curX = x2; curY = y2\n } else if (subOp === OPS.rectangle) {\n const rx = coords[ci++], ry = coords[ci++]\n const rw = coords[ci++], rh = coords[ci++]\n pushRectangle(currentPath, rx, ry, rw, rh)\n } else if (subOp === OPS.closePath) {\n if (curX !== pathStartX || curY !== pathStartY) {\n currentPath.push({ x1: curX, y1: curY, x2: pathStartX, y2: pathStartY })\n }\n curX = pathStartX; curY = pathStartY\n } else if (subOp === OPS.curveTo) {\n ci += 6\n } else if (subOp === OPS.curveTo2 || subOp === OPS.curveTo3) {\n ci += 4\n }\n }\n } else {\n // ── pdfjs-dist v5 형식 ──\n // args = [afterOp: number, [pathData: object], minMax]\n // afterOp = OPS.stroke(20), OPS.endPath(28), OPS.fill(22), etc.\n // pathData uses DrawOPS: moveTo=0, lineTo=1, curveTo=2, closePath=4\n const afterOp = arg0 as number\n const dataArr = args[1] as unknown[]\n const pathData = dataArr?.[0] as Record<number, number> | undefined\n if (pathData && typeof pathData === \"object\") {\n // pathData is an object with numeric keys: {0: op, 1: x, 2: y, ...}\n const len = Object.keys(pathData).length\n let di = 0\n while (di < len) {\n const drawOp = pathData[di++]\n if (drawOp === DrawOPS.moveTo) {\n curX = pathData[di++]; curY = pathData[di++]\n pathStartX = curX; pathStartY = curY\n } else if (drawOp === DrawOPS.lineTo) {\n const x2 = pathData[di++], y2 = pathData[di++]\n currentPath.push({ x1: curX, y1: curY, x2, y2 })\n curX = x2; curY = y2\n } else if (drawOp === DrawOPS.curveTo) {\n di += 6\n } else if (drawOp === DrawOPS.quadraticCurveTo) {\n di += 4\n } else if (drawOp === DrawOPS.closePath) {\n if (curX !== pathStartX || curY !== pathStartY) {\n currentPath.push({ x1: curX, y1: curY, x2: pathStartX, y2: pathStartY })\n }\n curX = pathStartX; curY = pathStartY\n } else {\n break // unknown op\n }\n }\n }\n\n // v5: afterOp이 stroke/fill이면 즉시 flush\n if (afterOp === OPS.stroke || afterOp === OPS.closeStroke) {\n flushPath(true)\n } else if (afterOp === OPS.fill || afterOp === OPS.eoFill ||\n afterOp === OPS.fillStroke || afterOp === OPS.eoFillStroke ||\n afterOp === OPS.closeFillStroke || afterOp === OPS.closeEOFillStroke) {\n flushPath(true)\n } else if (afterOp === OPS.endPath) {\n flushPath(false)\n }\n }\n break\n }\n\n case OPS.stroke:\n case OPS.closeStroke:\n flushPath(true)\n break\n\n case OPS.fill:\n case OPS.eoFill:\n case OPS.fillStroke:\n case OPS.eoFillStroke:\n case OPS.closeFillStroke:\n case OPS.closeEOFillStroke:\n // fill된 사각형도 테이블 선으로 처리 (셀 배경이 아닌 경우)\n flushPath(true)\n break\n\n case OPS.endPath:\n flushPath(false)\n break\n }\n }\n\n return { horizontals, verticals }\n}\n\nfunction classifyAndAdd(\n seg: { x1: number; y1: number; x2: number; y2: number },\n lineWidth: number,\n horizontals: LineSegment[],\n verticals: LineSegment[],\n) {\n const dx = Math.abs(seg.x2 - seg.x1)\n const dy = Math.abs(seg.y2 - seg.y1)\n const length = Math.sqrt(dx * dx + dy * dy)\n\n if (length < MIN_LINE_LENGTH) return\n\n if (dy <= ORIENTATION_TOL) {\n // 수평선\n const y = (seg.y1 + seg.y2) / 2\n const x1 = Math.min(seg.x1, seg.x2)\n const x2 = Math.max(seg.x1, seg.x2)\n horizontals.push({ x1, y1: y, x2, y2: y, lineWidth })\n } else if (dx <= ORIENTATION_TOL) {\n // 수직선\n const x = (seg.x1 + seg.x2) / 2\n const y1 = Math.min(seg.y1, seg.y2)\n const y2 = Math.max(seg.y1, seg.y2)\n verticals.push({ x1: x, y1, x2: x, y2, lineWidth })\n }\n // 대각선은 무시 (테이블 경계가 아님)\n}\n\n// ─── 페이지 경계(클립) 선 필터링 ──────────────────────\n\n/** 페이지 전체를 감싸는 클립 경계 선 제거 */\nexport function filterPageBorderLines(\n horizontals: LineSegment[],\n verticals: LineSegment[],\n pageWidth: number,\n pageHeight: number,\n): { horizontals: LineSegment[]; verticals: LineSegment[] } {\n const margin = 5\n return {\n horizontals: horizontals.filter(l =>\n !(Math.abs(l.y1) < margin || Math.abs(l.y1 - pageHeight) < margin) ||\n (l.x2 - l.x1) < pageWidth * 0.9\n ),\n verticals: verticals.filter(l =>\n !(Math.abs(l.x1) < margin || Math.abs(l.x1 - pageWidth) < margin) ||\n (l.y2 - l.y1) < pageHeight * 0.9\n ),\n }\n}\n\n// ─── 테이블 그리드 구성 ────────────────────────────────\n\n/**\n * 수평/수직 선에서 테이블 그리드를 추출.\n * 1. 교차하는 선들을 그룹화 (연결 컴포넌트)\n * 2. 각 그룹에서 X/Y 좌표를 클러스터링하여 그리드 구성\n */\nexport function buildTableGrids(\n horizontals: LineSegment[],\n verticals: LineSegment[],\n): TableGrid[] {\n if (horizontals.length < 2 || verticals.length < 2) return []\n\n // 1. 선들을 교차 관계로 그룹화\n const allLines = [\n ...horizontals.map((l, i) => ({ ...l, type: \"h\" as const, id: i })),\n ...verticals.map((l, i) => ({ ...l, type: \"v\" as const, id: i + horizontals.length })),\n ]\n\n const groups = groupConnectedLines(allLines)\n\n const grids: TableGrid[] = []\n\n for (const group of groups) {\n const hLines = group.filter(l => l.type === \"h\")\n const vLines = group.filter(l => l.type === \"v\")\n\n // 최소 2개 수평 + 2개 수직 선이 있어야 테이블\n if (hLines.length < 2 || vLines.length < 2) continue\n\n // 2. Y 좌표 클러스터링 (수평선의 y 값)\n const rawYs = hLines.map(l => l.y1)\n const rowYs = clusterCoordinates(rawYs).sort((a, b) => b - a) // 위→아래 (PDF는 y가 위가 큼)\n\n // 3. X 좌표 클러스터링 (수직선의 x 값)\n const rawXs = vLines.map(l => l.x1)\n const colXs = clusterCoordinates(rawXs).sort((a, b) => a - b)\n\n // 최소 2행 2열\n if (rowYs.length < 2 || colXs.length < 2) continue\n\n // 그리드에 실제로 셀이 형성되는지 검증\n const bbox = {\n x1: colXs[0], y1: rowYs[rowYs.length - 1],\n x2: colXs[colXs.length - 1], y2: rowYs[0],\n }\n\n grids.push({ rowYs, colXs, bbox })\n }\n\n // 인접 그리드 병합: 같은 열 구조 + 수직으로 가까운 그리드 합치기\n return mergeAdjacentGrids(grids)\n}\n\n/** 같은 열 구조를 가진 인접 그리드를 병합 (테이블 분리 방지) */\nfunction mergeAdjacentGrids(grids: TableGrid[]): TableGrid[] {\n if (grids.length <= 1) return grids\n // Y 좌표 기준 정렬 (위→아래 = y2 내림차순)\n const sorted = [...grids].sort((a, b) => b.bbox.y2 - a.bbox.y2)\n const merged: TableGrid[] = [sorted[0]]\n\n for (let i = 1; i < sorted.length; i++) {\n const prev = merged[merged.length - 1]\n const curr = sorted[i]\n\n // 같은 열 수 + 열 위치가 비슷한지 확인\n if (prev.colXs.length === curr.colXs.length) {\n const colMatch = prev.colXs.every((x, ci) => Math.abs(x - curr.colXs[ci]) <= COORD_MERGE_TOL * 3)\n // 수직으로 인접 (갭 < 20pt ≈ 7mm)\n const verticalGap = prev.bbox.y1 - curr.bbox.y2\n if (colMatch && verticalGap >= -COORD_MERGE_TOL && verticalGap <= 20) {\n // 병합: rowYs 합치기 (중복 제거), bbox 확장\n const allRowYs = [...new Set([...prev.rowYs, ...curr.rowYs])].sort((a, b) => b - a)\n merged[merged.length - 1] = {\n rowYs: allRowYs,\n colXs: prev.colXs,\n bbox: {\n x1: Math.min(prev.bbox.x1, curr.bbox.x1),\n y1: Math.min(prev.bbox.y1, curr.bbox.y1),\n x2: Math.max(prev.bbox.x2, curr.bbox.x2),\n y2: Math.max(prev.bbox.y2, curr.bbox.y2),\n },\n }\n continue\n }\n }\n merged.push(curr)\n }\n return merged\n}\n\n/** 좌표값 클러스터링 — 가까운 값끼리 병합 */\nfunction clusterCoordinates(values: number[]): number[] {\n if (values.length === 0) return []\n const sorted = [...values].sort((a, b) => a - b)\n const clusters: { sum: number; count: number }[] = [{ sum: sorted[0], count: 1 }]\n\n for (let i = 1; i < sorted.length; i++) {\n const last = clusters[clusters.length - 1]\n const avg = last.sum / last.count\n if (Math.abs(sorted[i] - avg) <= COORD_MERGE_TOL) {\n last.sum += sorted[i]\n last.count++\n } else {\n clusters.push({ sum: sorted[i], count: 1 })\n }\n }\n\n return clusters.map(c => c.sum / c.count)\n}\n\ntype TypedLine = LineSegment & { type: \"h\" | \"v\"; id: number }\n\n/** 교차하는 선들을 Union-Find로 그룹화 */\nfunction groupConnectedLines(lines: TypedLine[]): TypedLine[][] {\n const parent = lines.map((_, i) => i)\n\n function find(x: number): number {\n while (parent[x] !== x) { parent[x] = parent[parent[x]]; x = parent[x] }\n return x\n }\n function union(a: number, b: number) {\n const ra = find(a), rb = find(b)\n if (ra !== rb) parent[ra] = rb\n }\n\n // O(n²) 교차 검사 — 선 수가 수백 수준이므로 충분\n for (let i = 0; i < lines.length; i++) {\n for (let j = i + 1; j < lines.length; j++) {\n if (linesIntersect(lines[i], lines[j])) {\n union(i, j)\n }\n }\n }\n\n const groups = new Map<number, TypedLine[]>()\n for (let i = 0; i < lines.length; i++) {\n const root = find(i)\n if (!groups.has(root)) groups.set(root, [])\n groups.get(root)!.push(lines[i])\n }\n\n return [...groups.values()]\n}\n\n/** 수평선과 수직선의 교차 판정 (tolerance 포함) */\nfunction linesIntersect(a: TypedLine, b: TypedLine): boolean {\n // 같은 방향이면 교차 안 함 (평행)\n if (a.type === b.type) {\n // 같은 방향이라도 연결된 선일 수 있음 (끝점이 가까운 경우)\n if (a.type === \"h\") {\n if (Math.abs(a.y1 - b.y1) > CONNECT_TOL) return false\n // X 범위 겹침\n return Math.min(a.x2, b.x2) >= Math.max(a.x1, b.x1) - CONNECT_TOL\n } else {\n if (Math.abs(a.x1 - b.x1) > CONNECT_TOL) return false\n return Math.min(a.y2, b.y2) >= Math.max(a.y1, b.y1) - CONNECT_TOL\n }\n }\n\n // 수평 + 수직 교차\n const h = a.type === \"h\" ? a : b\n const v = a.type === \"h\" ? b : a\n const tol = CONNECT_TOL\n\n return (\n v.x1 >= h.x1 - tol && v.x1 <= h.x2 + tol &&\n h.y1 >= v.y1 - tol && h.y1 <= v.y2 + tol\n )\n}\n\n// ─── 셀 구조 추출 (colspan/rowspan 감지) ──────────────\n\n/**\n * 테이블 그리드에서 셀 목록을 추출.\n * 수평/수직 선의 존재 여부로 셀 병합(colspan/rowspan)을 감지.\n */\nexport function extractCells(\n grid: TableGrid,\n horizontals: LineSegment[],\n verticals: LineSegment[],\n): ExtractedCell[] {\n const { rowYs, colXs } = grid\n const numRows = rowYs.length - 1\n const numCols = colXs.length - 1\n if (numRows <= 0 || numCols <= 0) return []\n\n // 셀이 이미 병합된 셀에 포함되는지 추적\n const occupied = Array.from({ length: numRows }, () => Array(numCols).fill(false))\n const cells: ExtractedCell[] = []\n\n for (let r = 0; r < numRows; r++) {\n for (let c = 0; c < numCols; c++) {\n if (occupied[r][c]) continue\n\n // 이 셀에서 오른쪽/아래로 병합 가능한 범위 찾기\n let colSpan = 1\n let rowSpan = 1\n\n // colSpan: 오른쪽 경계에 수직선이 없으면 병합\n while (c + colSpan < numCols) {\n const borderX = colXs[c + colSpan]\n const topY = rowYs[r]\n const botY = rowYs[r + 1]\n if (hasVerticalLine(verticals, borderX, topY, botY)) break\n colSpan++\n }\n\n // rowSpan: 아래쪽 경계에 수평선이 없으면 병합\n while (r + rowSpan < numRows) {\n const borderY = rowYs[r + rowSpan]\n const leftX = colXs[c]\n const rightX = colXs[c + colSpan]\n if (hasHorizontalLine(horizontals, borderY, leftX, rightX)) break\n rowSpan++\n }\n\n // 병합 영역 마킹\n for (let dr = 0; dr < rowSpan; dr++) {\n for (let dc = 0; dc < colSpan; dc++) {\n occupied[r + dr][c + dc] = true\n }\n }\n\n cells.push({\n row: r, col: c, rowSpan, colSpan,\n bbox: {\n x1: colXs[c], y1: rowYs[r + rowSpan],\n x2: colXs[c + colSpan], y2: rowYs[r],\n },\n })\n }\n }\n\n return cells\n}\n\n/** 특정 X 위치에 수직선이 Y 범위를 커버하는지 확인 */\nfunction hasVerticalLine(verticals: LineSegment[], x: number, topY: number, botY: number): boolean {\n const tol = COORD_MERGE_TOL + 1\n for (const v of verticals) {\n if (Math.abs(v.x1 - x) <= tol) {\n // 선의 Y 범위가 셀 경계의 상당 부분(50%)을 커버하는지\n const cellH = Math.abs(topY - botY)\n const overlapTop = Math.min(v.y2, topY)\n const overlapBot = Math.max(v.y1, botY)\n const overlap = overlapTop - overlapBot\n if (overlap >= cellH * 0.5) return true\n }\n }\n return false\n}\n\n/** 특정 Y 위치에 수평선이 X 범위를 커버하는지 확인 */\nfunction hasHorizontalLine(horizontals: LineSegment[], y: number, leftX: number, rightX: number): boolean {\n const tol = COORD_MERGE_TOL + 1\n for (const h of horizontals) {\n if (Math.abs(h.y1 - y) <= tol) {\n const cellW = Math.abs(rightX - leftX)\n const overlapLeft = Math.max(h.x1, leftX)\n const overlapRight = Math.min(h.x2, rightX)\n const overlap = overlapRight - overlapLeft\n if (overlap >= cellW * 0.5) return true\n }\n }\n return false\n}\n\n// ─── 텍스트→셀 매핑 ──────────────────────────────────\n\nexport interface TextItem {\n text: string\n x: number; y: number; w: number; h: number\n fontSize: number; fontName: string\n}\n\n/**\n * 텍스트 아이템을 셀에 매핑.\n * 각 텍스트의 중심점이 어떤 셀의 bbox 안에 있는지로 판별.\n */\nexport function mapTextToCells(\n items: TextItem[],\n cells: ExtractedCell[],\n): Map<ExtractedCell, TextItem[]> {\n const result = new Map<ExtractedCell, TextItem[]>()\n for (const cell of cells) {\n result.set(cell, [])\n }\n\n for (const item of items) {\n const cx = item.x + item.w / 2\n const cy = item.y\n const pad = CELL_PADDING\n\n let bestCell: ExtractedCell | null = null\n let bestDist = Infinity\n\n for (const cell of cells) {\n // 중심점이 셀 bbox 안에 있는지 (패딩 포함)\n if (cx >= cell.bbox.x1 - pad && cx <= cell.bbox.x2 + pad &&\n cy >= cell.bbox.y1 - pad && cy <= cell.bbox.y2 + pad) {\n // 여러 셀에 해당하면 가장 가까운 셀 중심에 배정\n const cellCx = (cell.bbox.x1 + cell.bbox.x2) / 2\n const cellCy = (cell.bbox.y1 + cell.bbox.y2) / 2\n const dist = Math.abs(cx - cellCx) + Math.abs(cy - cellCy)\n if (dist < bestDist) {\n bestDist = dist\n bestCell = cell\n }\n }\n }\n\n if (bestCell) {\n result.get(bestCell)!.push(item)\n }\n }\n\n return result\n}\n\n/**\n * 셀 내 텍스트 아이템을 읽기 순서로 정렬 후 합치기.\n * Y 내림차순 (위→아래) → X 오름차순 (좌→우)\n */\nexport function cellTextToString(items: TextItem[]): string {\n if (items.length === 0) return \"\"\n if (items.length === 1) return items[0].text\n\n // Y좌표로 행 그룹핑 (tolerance: max(3, fontSize*0.6))\n const sorted = [...items].sort((a, b) => b.y - a.y || a.x - b.x)\n const lines: TextItem[][] = []\n let curLine: TextItem[] = [sorted[0]]\n let curY = sorted[0].y\n\n for (let i = 1; i < sorted.length; i++) {\n const tol = Math.max(3, Math.min(sorted[i].fontSize, curLine[0].fontSize) * 0.6)\n if (Math.abs(sorted[i].y - curY) <= tol) {\n curLine.push(sorted[i])\n } else {\n lines.push(curLine)\n curLine = [sorted[i]]\n curY = sorted[i].y\n }\n }\n lines.push(curLine)\n\n // 각 행을 텍스트로 변환 — 한글 간 작은 갭은 공백 없이 붙임\n const textLines = lines.map(line => {\n const s = line.sort((a, b) => a.x - b.x)\n if (s.length === 1) return s[0].text\n let result = s[0].text\n for (let j = 1; j < s.length; j++) {\n const gap = s[j].x - (s[j - 1].x + s[j - 1].w)\n const avgFs = (s[j].fontSize + s[j - 1].fontSize) / 2\n // 한글 관련 문자 전환 시 작은 갭 → 공백 없이 붙임\n // (한글-한글, ASCII→한글, 한글→ASCII 모두 포함)\n const prevIsKorean = /[가-힣]$/.test(result)\n const currIsKorean = /^[가-힣]/.test(s[j].text)\n if (gap < avgFs * 0.15) {\n // 매우 작은 갭 — 모든 문자 타입에서 공백 없이 붙임\n result += s[j].text\n } else if (gap < avgFs * 0.35 && (prevIsKorean || currIsKorean)) {\n // 한글 관련 작은 갭 — PDF 문자 개별 배치 잔재\n result += s[j].text\n } else {\n result += \" \" + s[j].text\n }\n }\n return result\n })\n\n // 셀 내 줄바꿈 병합 — 잘린 단어/숫자 조각 복구\n if (textLines.length <= 1) return textLines[0] || \"\"\n const merged: string[] = [textLines[0]]\n for (let i = 1; i < textLines.length; i++) {\n const prev = merged[merged.length - 1]\n const curr = textLines[i]\n // 짧은 순수 한글 (8자 이하) = 잘린 단어 조각\n if (/[가-힣]$/.test(prev) && /^[가-힣]+$/.test(curr) && curr.length <= 8 && !curr.includes(\" \")) {\n merged[merged.length - 1] = prev + curr\n }\n // 닫는 괄호/기호 포함 짧은 줄 (3자 이하) = 이전 줄에 붙임 (예: \")\", \"%)\", \"%) 별도\")\n else if (curr.trim().length <= 3 && /^[)\\]%}]/.test(curr.trim())) {\n merged[merged.length - 1] = prev + curr.trim()\n }\n // 이전 줄이 여는 괄호나 쉼표로 끝남 = 다음 줄 붙임 (예: \"(x15,232,700,\" + \"000)\")\n else if (/[,(]$/.test(prev.trim()) && curr.trim().length <= 15) {\n merged[merged.length - 1] = prev + curr.trim()\n }\n // 숫자 줄바꿈 복구: 이전 줄이 숫자/쉼표로 끝나고 다음 줄이 숫자로 시작하는 짧은 조각\n else if (/[\\d,]$/.test(prev) && /^[\\d,]+[)\\]]?$/.test(curr.trim()) && curr.trim().length <= 10) {\n merged[merged.length - 1] = prev + curr.trim()\n }\n else {\n merged.push(curr)\n }\n }\n return merged.join(\"\\n\")\n}\n","/**\n * 클러스터 기반 테이블 감지 — 선이 없는 PDF에서 텍스트 정렬 패턴으로 테이블 구조 추론.\n *\n * Original work: Copyright 2025-2026 Hancom, Inc.\n * Licensed under the Apache License, Version 2.0\n * https://github.com/opendataloader-project/opendataloader-pdf\n *\n * ODL의 ClusterTableConsumer를 kordoc 컨텍스트에 맞게 단순화한 구현.\n * Modifications: TypeScript 재구현, 최소 2열 감지, 한국어 PDF 특화 최적화.\n *\n * 핵심 아이디어:\n * 1. 텍스트 아이템을 baseline(Y좌표)으로 그룹핑하여 행(row) 구성\n * 2. 각 행의 아이템 X좌표를 수집, 행 간 공통 X좌표 클러스터(열) 감지\n * 3. 2+ 열이 3+ 행에 걸쳐 일관되면 테이블로 판정\n * 4. 기존 detectColumns(min 3열)보다 느슨한 기준(min 2열)으로\n * 2열 테이블(key-value 등)도 감지\n */\n\nimport type { IRBlock, IRTable, IRCell, BoundingBox } from \"../types.js\"\n\n/** parser.ts의 NormItem과 동일한 인터페이스 */\nexport interface ClusterItem {\n text: string\n x: number\n y: number\n w: number\n h: number\n fontSize: number\n fontName: string\n}\n\n// ─── 상수 ──────────────────────────────────────────────\n/** baseline 그룹핑 허용 오차 (pt) */\nconst Y_TOL = 3\n/** 열 클러스터링 허용 오차 (pt) — detectColumns의 CLUSTER_TOL=22보다 엄격 */\nconst COL_CLUSTER_TOL = 15\n/** 테이블로 인정하기 위한 최소 행 수 */\nconst MIN_ROWS = 3\n/** 테이블로 인정하기 위한 최소 열 수 */\nconst MIN_COLS = 2\n/** 같은 행 내 아이템 간 최소 갭 (테이블 컬럼 구분) — fontSize 배수 */\nconst MIN_GAP_FACTOR = 1.5\n/** 열에 값이 있는 행의 비율 최소 기준 */\nconst MIN_COL_FILL_RATIO = 0.3\n\ninterface RowGroup {\n y: number // 대표 Y좌표 (평균 baseline)\n items: ClusterItem[]\n}\n\ninterface ColCluster {\n x: number // 열 X좌표 (왼쪽 경계)\n count: number // 이 열에 속한 아이템 수\n}\n\nexport interface ClusterTableResult {\n table: IRTable\n bbox: BoundingBox\n usedItems: Set<ClusterItem>\n}\n\n/**\n * 클러스터 기반 테이블 감지. 선이 없는 PDF의 fallback 경로에서 호출.\n *\n * @param items 페이지의 텍스트 아이템 (Y 내림차순 정렬)\n * @param pageNum 페이지 번호\n * @returns 감지된 테이블들 (없으면 빈 배열)\n */\nexport function detectClusterTables(items: ClusterItem[], pageNum: number): ClusterTableResult[] {\n if (items.length < MIN_ROWS * MIN_COLS) return []\n\n // 1. Y좌표로 행 그룹핑\n const rows = groupByBaseline(items)\n if (rows.length < MIN_ROWS) return []\n\n // 2. \"의심스러운\" 행 식별 — 아이템 간 큰 갭이 있는 행\n const suspiciousRows = rows.filter(row => hasSuspiciousGaps(row))\n if (suspiciousRows.length < MIN_ROWS) return []\n\n // 3. 의심스러운 행들의 X좌표에서 열 클러스터 추출\n const columns = extractColumnClusters(suspiciousRows)\n if (columns.length < MIN_COLS) return []\n\n // 4. 연속된 의심스러운 행들을 테이블 영역으로 그룹화\n const tableRegions = findTableRegions(rows, columns)\n const results: ClusterTableResult[] = []\n\n for (const region of tableRegions) {\n const table = buildClusterTable(region.rows, columns, pageNum)\n if (table) results.push(table)\n }\n\n return results\n}\n\n/** 아이템을 baseline(Y좌표)으로 그룹핑 */\nfunction groupByBaseline(items: ClusterItem[]): RowGroup[] {\n if (items.length === 0) return []\n\n const sorted = [...items].sort((a, b) => b.y - a.y || a.x - b.x)\n const rows: RowGroup[] = []\n let curItems: ClusterItem[] = [sorted[0]]\n let curY = sorted[0].y\n\n for (let i = 1; i < sorted.length; i++) {\n if (Math.abs(sorted[i].y - curY) <= Y_TOL) {\n curItems.push(sorted[i])\n } else {\n rows.push({ y: curY, items: curItems })\n curItems = [sorted[i]]\n curY = sorted[i].y\n }\n }\n if (curItems.length > 0) rows.push({ y: curY, items: curItems })\n\n return rows\n}\n\n/** 행 내 아이템 간 \"의심스러운\" 갭 존재 여부 (테이블 열 구분 후보) */\nfunction hasSuspiciousGaps(row: RowGroup): boolean {\n if (row.items.length < 2) return false\n\n const sorted = [...row.items].sort((a, b) => a.x - b.x)\n const avgFontSize = sorted.reduce((s, i) => s + i.fontSize, 0) / sorted.length\n const minGap = avgFontSize * MIN_GAP_FACTOR\n\n for (let i = 1; i < sorted.length; i++) {\n const gap = sorted[i].x - (sorted[i - 1].x + sorted[i - 1].w)\n if (gap >= minGap) return true\n }\n return false\n}\n\n/** 의심스러운 행들의 X좌표에서 열 클러스터 추출 (sort-and-split 방식, 순서 무관) */\nfunction extractColumnClusters(rows: RowGroup[]): ColCluster[] {\n // 모든 X좌표 수집\n const allX: number[] = []\n for (const row of rows) {\n for (const item of row.items) allX.push(item.x)\n }\n if (allX.length === 0) return []\n\n // 정렬 후 갭 기반 분할\n allX.sort((a, b) => a - b)\n\n const clusters: ColCluster[] = []\n let clusterStart = 0\n\n for (let i = 1; i <= allX.length; i++) {\n if (i === allX.length || allX[i] - allX[i - 1] > COL_CLUSTER_TOL) {\n // 클러스터 완성: [clusterStart, i)\n const slice = allX.slice(clusterStart, i)\n const avg = Math.round(slice.reduce((s, v) => s + v, 0) / slice.length)\n clusters.push({ x: avg, count: slice.length })\n clusterStart = i\n }\n }\n\n // 최소 빈도 필터 — 행 수의 30% 이상 등장해야 유효한 열\n const minCount = Math.max(2, Math.floor(rows.length * MIN_COL_FILL_RATIO))\n return clusters\n .filter(c => c.count >= minCount)\n .sort((a, b) => a.x - b.x)\n}\n\n/** 연속된 테이블 행 영역 찾기 */\nfunction findTableRegions(allRows: RowGroup[], columns: ColCluster[]): { rows: RowGroup[] }[] {\n const regions: { rows: RowGroup[] }[] = []\n let currentRegion: RowGroup[] = []\n\n for (const row of allRows) {\n // 이 행이 열 구조에 맞는지 확인\n const matchedCols = countMatchedColumns(row, columns)\n if (matchedCols >= MIN_COLS) {\n currentRegion.push(row)\n } else if (row.items.length === 1) {\n // 단일 아이템 행 — 병합 셀이거나 헤더일 수 있음\n if (currentRegion.length > 0) {\n currentRegion.push(row)\n }\n } else {\n // 비테이블 행 → 현재 영역 종료\n if (currentRegion.length >= MIN_ROWS) {\n regions.push({ rows: [...currentRegion] })\n }\n currentRegion = []\n }\n }\n\n if (currentRegion.length >= MIN_ROWS) {\n regions.push({ rows: currentRegion })\n }\n\n return regions\n}\n\n/** 행의 아이템이 몇 개의 열에 매칭되는지 */\nfunction countMatchedColumns(row: RowGroup, columns: ColCluster[]): number {\n const matched = new Set<number>()\n for (const item of row.items) {\n for (let ci = 0; ci < columns.length; ci++) {\n if (Math.abs(item.x - columns[ci].x) <= COL_CLUSTER_TOL * 2) {\n matched.add(ci)\n break\n }\n }\n }\n return matched.size\n}\n\n/** 아이템을 열에 배정. 거리 제한 초과 시 -1 반환. */\nfunction assignToColumn(item: ClusterItem, columns: ColCluster[]): number {\n const MAX_DIST = COL_CLUSTER_TOL * 3\n let bestCol = -1\n let bestDist = Infinity\n for (let ci = 0; ci < columns.length; ci++) {\n const dist = Math.abs(item.x - columns[ci].x)\n if (dist < bestDist) {\n bestDist = dist\n bestCol = ci\n }\n }\n return bestDist <= MAX_DIST ? bestCol : -1\n}\n\n/** 클러스터 테이블을 IRTable로 구성 */\nfunction buildClusterTable(\n rows: RowGroup[],\n columns: ColCluster[],\n pageNum: number,\n): ClusterTableResult | null {\n const numCols = columns.length\n const numRows = rows.length\n\n if (numRows < MIN_ROWS || numCols < MIN_COLS) return null\n\n // 셀 그리드 구성\n const cells: IRCell[][] = Array.from(\n { length: numRows },\n () => Array.from({ length: numCols }, () => ({ text: \"\", colSpan: 1, rowSpan: 1 })),\n )\n\n const usedItems = new Set<ClusterItem>()\n\n for (let r = 0; r < numRows; r++) {\n const row = rows[r]\n // 단일 아이템 행 → 전체 행 병합 (colSpan)\n if (row.items.length === 1 && numCols > 1) {\n cells[r][0] = { text: row.items[0].text, colSpan: numCols, rowSpan: 1 }\n usedItems.add(row.items[0])\n continue\n }\n\n for (const item of row.items) {\n const col = assignToColumn(item, columns)\n if (col < 0) continue // 열에 매칭 안 되는 아이템은 무시\n const existing = cells[r][col].text\n cells[r][col].text = existing ? existing + \" \" + item.text : item.text\n usedItems.add(item)\n }\n }\n\n // 검증: 빈 행이 너무 많으면 테이블 아님\n let emptyRows = 0\n for (const row of cells) {\n if (row.every(c => c.text === \"\")) emptyRows++\n }\n if (emptyRows > numRows * 0.5) return null\n\n // 검증: 모든 열에 최소 1개 값이 있어야 함\n for (let c = 0; c < numCols; c++) {\n const hasValue = cells.some(row => row[c].text !== \"\")\n if (!hasValue) return null\n }\n\n const irTable: IRTable = {\n rows: numRows,\n cols: numCols,\n cells,\n hasHeader: numRows > 1,\n }\n\n // BBox 계산\n const allItems = rows.flatMap(r => r.items)\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity\n for (const i of allItems) {\n if (i.x < minX) minX = i.x\n if (i.y < minY) minY = i.y\n if (i.x + i.w > maxX) maxX = i.x + i.w\n const h = i.h > 0 ? i.h : i.fontSize\n if (i.y + h > maxY) maxY = i.y + h\n }\n\n return {\n table: irTable,\n bbox: { page: pageNum, x: minX, y: minY, width: maxX - minX, height: maxY - minY },\n usedItems,\n }\n}\n","/**\n * 서버리스/Node.js 환경에서 pdfjs-dist가 요구하는 브라우저 API polyfill.\n * pdfjs-dist import보다 먼저 실행되어야 함 (ES 모듈 호이스팅 대응으로 별도 파일 분리).\n *\n * 1. DOMMatrix / Path2D polyfill — pdfjs-dist가 참조하지만 Node.js에 없음\n * 2. pdfjsWorker 사전 주입 — fake worker의 동적 import를 우회\n */\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst g = globalThis as any\n\nif (typeof g.DOMMatrix === \"undefined\") {\n g.DOMMatrix = class DOMMatrix {\n m: number[] = [1, 0, 0, 1, 0, 0]\n constructor(init?: number[]) { if (init) this.m = init }\n }\n}\n\nif (typeof g.Path2D === \"undefined\") {\n g.Path2D = class Path2D {}\n}\n\n// worker 모듈 static import → fake worker가 동적 import를 건너뜀\n// @ts-expect-error pdfjs-dist worker has no type declarations\nimport * as pdfjsWorker from \"pdfjs-dist/legacy/build/pdf.worker.mjs\"\ng.pdfjsWorker = pdfjsWorker\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 } from \"../utils.js\"\nimport { buildTable, blocksToMarkdown } from \"../table/builder.js\"\n\n// ─── 상수 ────────────────────────────────────────────\n\nconst MAX_SHEETS = 100\n/** ZIP 압축 해제 누적 최대 크기 (500MB) — ZIP bomb 방지 */\nconst MAX_DECOMPRESS_SIZE = 500 * 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 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(text, \"text/xml\")\n}\n\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 const tElements = getElements(si, \"t\")\n strings.push(tElements.map(t => t.textContent ?? \"\").join(\"\"))\n }\n return strings\n}\n\n// ─── 시트 목록 파싱 ─────────────────────────────────────\n\ninterface SheetInfo {\n name: string\n sheetId: string\n rId: string\n}\n\nfunction parseWorkbook(xml: string): SheetInfo[] {\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 return sheets\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): { 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 for (const rowEl of rows) {\n const rowNum = parseInt(rowEl.getAttribute(\"r\") ?? \"0\", 10) - 1\n if (rowNum < 0 || rowNum >= MAX_ROWS) continue\n\n const cells = getElements(rowEl, \"c\")\n for (const cellEl of cells) {\n const ref = cellEl.getAttribute(\"r\")\n if (!ref) continue\n const pos = parseCellRef(ref)\n if (!pos || pos.col >= MAX_COLS) continue\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 }\n } else if (type === \"inlineStr\") {\n // <is><t>text</t></is>\n const isEl = getElements(cellEl, \"is\")\n if (isEl.length > 0) {\n const tElements = getElements(isEl[0], \"t\")\n value = tElements.map(t => t.textContent ?? \"\").join(\"\")\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 if (m) merges.push(m)\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): 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)\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 = parseWorkbook(await workbookFile.async(\"text\"))\n if (sheets.length === 0) {\n throw new KordocError(\"XLSX 파일에 시트가 없습니다\")\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)\n const sheetBlocks = sheetToBlocks(sheet.name, grid, merges, maxRow, maxCol, i)\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 * 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 IRBlock, IRTable, IRCell, DocumentMetadata, InternalParseResult,\n ParseOptions, ParseWarning, ExtractedImage, InlineStyle,\n} from \"../types.js\"\nimport { KordocError, precheckZipSize } from \"../utils.js\"\nimport { blocksToMarkdown } from \"../table/builder.js\"\n\n/** ZIP 압축 해제 누적 최대 크기 (500MB) — ZIP bomb 방지 */\nconst MAX_DECOMPRESS_SIZE = 500 * 1024 * 1024\n\n// ─── XML 헬퍼 ──────────────────────────────────────────\n\n/** 네임스페이스 무시 태그 검색 — DOCX는 네임스페이스가 많음 */\nfunction getChildElements(parent: Element | Document, localName: string): 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) {\n const el = node as Element\n if (el.localName === localName || el.tagName?.endsWith(`:${localName}`)) {\n result.push(el)\n }\n }\n }\n return result\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(text, \"text/xml\")\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 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// ─── Run 텍스트 추출 ──────────────────────────────────\n\ninterface RunResult {\n text: string\n bold: boolean\n italic: boolean\n}\n\nfunction extractRun(r: Element): RunResult {\n const tElements = getChildElements(r, \"t\")\n const text = tElements.map(t => t.textContent ?? \"\").join(\"\")\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\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 // 텍스트 수집\n const parts: string[] = []\n let hasBold = false\n let hasItalic = false\n let href: string | undefined\n let footnoteText: string | undefined\n\n // 하이퍼링크 처리\n const hyperlinks = getChildElements(p, \"hyperlink\")\n const hyperlinkTexts = new Set<string>()\n\n for (const hl of hyperlinks) {\n const rId = getAttr(hl, \"id\")\n const hlText: string[] = []\n const runs = findElements(hl, \"r\")\n for (const r of runs) {\n const result = extractRun(r)\n hlText.push(result.text)\n }\n const text = hlText.join(\"\")\n if (text) {\n hyperlinkTexts.add(text)\n if (rId && rels.has(rId)) {\n href = rels.get(rId)\n parts.push(text)\n } else {\n parts.push(text)\n }\n }\n }\n\n // 일반 run 처리\n const runs = getChildElements(p, \"r\")\n for (const r of runs) {\n // 하이퍼링크 내부 run은 이미 처리됨 — 부모가 hyperlink이면 스킵\n if (r.parentNode && (r.parentNode as Element).localName === \"hyperlink\") continue\n\n const result = extractRun(r)\n if (result.bold) hasBold = true\n if (result.italic) hasItalic = true\n\n // 각주 참조 확인\n const fnRefEls = getChildElements(r, \"footnoteReference\")\n if (fnRefEls.length > 0) {\n const fnId = getAttr(fnRefEls[0], \"id\")\n if (fnId && footnotes.has(fnId)) {\n footnoteText = footnotes.get(fnId)\n }\n }\n\n if (result.text) parts.push(result.text)\n }\n\n const text = parts.join(\"\").trim()\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 (href) block.href = href\n if (footnoteText) block.footnoteText = footnoteText\n return block\n}\n\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): IRBlock | null {\n const trElements = getChildElements(tbl, \"tr\")\n if (trElements.length === 0) return null\n\n const rows: IRCell[][] = []\n let maxCols = 0\n\n for (const tr of trElements) {\n const tcElements = getChildElements(tr, \"tc\")\n const row: IRCell[] = []\n\n for (const tc of tcElements) {\n // 셀 속성\n let colSpan = 1\n let rowSpan = 1\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)\n }\n const vMergeEls = getChildElements(tcPrEls[0], \"vMerge\")\n if (vMergeEls.length > 0) {\n const val = getAttr(vMergeEls[0], \"val\")\n if (val !== \"restart\" && val !== null) {\n // 병합 계속 셀 — 스킵 마커\n row.push({ text: \"\", colSpan, rowSpan: 0 })\n continue\n }\n }\n }\n\n // 셀 텍스트\n const cellTexts: string[] = []\n const pElements = getChildElements(tc, \"p\")\n for (const p of pElements) {\n const block = parseParagraph(p, styles, numbering, footnotes, rels)\n if (block?.text) cellTexts.push(block.text)\n }\n\n row.push({ text: cellTexts.join(\"\\n\"), colSpan, rowSpan })\n }\n rows.push(row)\n if (row.length > maxCols) maxCols = row.length\n }\n\n // vMerge rowSpan 후처리: restart에서 아래로 연속되는 rowSpan=0 카운트\n for (let c = 0; c < maxCols; c++) {\n for (let r = 0; r < rows.length; r++) {\n const cell = rows[r][c]\n if (!cell || cell.rowSpan === 0) continue\n let span = 1\n for (let nr = r + 1; nr < rows.length; nr++) {\n if (rows[nr][c]?.rowSpan === 0) span++\n else break\n }\n cell.rowSpan = span\n }\n }\n\n // rowSpan=0인 placeholder 제거\n const cleanRows: IRCell[][] = []\n for (const row of rows) {\n const clean = row.filter(cell => cell.rowSpan !== 0)\n cleanRows.push(clean)\n }\n\n // 빈 테이블 체크\n if (cleanRows.length === 0) return null\n\n // 컬럼 수 재계산\n let cols = 0\n for (const row of cleanRows) {\n let c = 0\n for (const cell of row) c += cell.colSpan\n if (c > cols) cols = c\n }\n\n const table: IRTable = {\n rows: cleanRows.length,\n cols,\n cells: cleanRows,\n hasHeader: cleanRows.length > 1,\n }\n return { type: \"table\", table }\n}\n\n// ─── 이미지 추출 ────────────────────────────────────────\n\nasync function extractImages(\n zip: JSZip,\n rels: Map<string, string>,\n doc: Document,\n): Promise<{ blocks: IRBlock[]; images: ExtractedImage[] }> {\n const blocks: IRBlock[] = []\n const images: ExtractedImage[] = []\n\n const drawingElements = findElements(doc.documentElement, \"drawing\")\n let imgIdx = 0\n\n for (const drawing of drawingElements) {\n // a:blip → r:embed\n const blips = findElements(drawing, \"blip\")\n for (const blip of blips) {\n const embedId = getAttr(blip, \"embed\")\n if (!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 }\n const filename = `image_${String(imgIdx).padStart(3, \"0\")}.${ext}`\n images.push({ filename, data, mimeType: mimeMap[ext] ?? \"image/png\" })\n blocks.push({ type: \"image\", text: filename })\n } catch { /* 이미지 실패 무시 */ }\n }\n }\n return { blocks, images }\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 { /* 스타일 실패 무시 */ }\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 { /* 번호 매기기 실패 무시 */ }\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 { /* 각주 실패 무시 */ }\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 const blocks: IRBlock[] = []\n const bodyEl = body[0]\n const children = bodyEl.childNodes\n\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 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 } else if (localName === \"tbl\") {\n const block = parseTable(el, styles, numbering, footnotes, rels)\n if (block) blocks.push(block)\n }\n }\n\n // 6. 이미지 추출\n const { blocks: imgBlocks, images } = await extractImages(zip, rels, doc)\n // 이미지 블록은 본문에 이미 포함되어야 하지만, 누락된 것 추가\n // (drawing이 paragraph 내에 있으므로 대부분 이미 포함됨)\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 { /* 메타데이터 실패 무시 */ }\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","/** 텍스트 유사도 및 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/** Levenshtein 편집 거리 — O(min(m,n)) 공간 최적화 */\nfunction levenshtein(a: string, b: string): number {\n if (a.length + b.length > MAX_LEVENSHTEIN_LEN) return Math.abs(a.length - b.length)\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\nfunction simpleIntersect(a: string[], b: string[]): string[] {\n const setB = new Set(b)\n return a.filter(w => setB.has(w))\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","/** 문서 비교 엔진 — 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 // 유사도 매트릭스 캐시\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) { v = blockSimilarity(a[i], b[j]); simCache.set(key, v) }\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 // 내용 유사도 (셀 텍스트)\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 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","/** 양식(서식) 필드 인식 — 테이블 기반 label-value 패턴 매칭 */\n\nimport type { IRBlock, IRTable, FormField, FormResult } from \"../types.js\"\n\n/** 한국 공문서 필드 라벨 키워드 */\nconst LABEL_KEYWORDS = new Set([\n \"성명\", \"이름\", \"주소\", \"전화\", \"전화번호\", \"휴대폰\", \"핸드폰\", \"연락처\",\n \"생년월일\", \"주민등록번호\", \"소속\", \"직위\", \"직급\", \"부서\",\n \"이메일\", \"팩스\", \"학교\", \"학년\", \"반\", \"번호\",\n \"신청인\", \"대표자\", \"담당자\", \"작성자\", \"확인자\", \"승인자\",\n \"일시\", \"날짜\", \"기간\", \"장소\", \"목적\", \"사유\", \"비고\",\n \"금액\", \"수량\", \"단가\", \"합계\", \"계\", \"소계\",\n])\n\n/** 라벨처럼 보이는 셀인지 판별 */\nfunction isLabelCell(text: string): boolean {\n const trimmed = text.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-8자) + 숫자 없음\n if (/^[가-힣\\s()·:]{2,8}$/.test(trimmed) && !/\\d/.test(trimmed)) return true\n // \"라벨:\" 패턴\n if (/^[가-힣A-Za-z\\s]+[::]$/.test(trimmed)) return true\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 block of blocks) {\n if (block.type !== \"table\" || !block.table) continue\n totalTables++\n\n const tableFields = extractFromTable(block.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\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 (isLabelCell(labelCell.text) && valueCell.text.trim()) {\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 })\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 const fields: FormField[] = []\n // \"라벨: 값\" 또는 \"라벨 : 값\" 패턴\n const pattern = /([가-힣A-Za-z]{2,10})\\s*[::]\\s*([^\\n,;]{1,100})/g\n let match\n while ((match = pattern.exec(text)) !== null) {\n const label = match[1].trim()\n const value = match[2].trim()\n if (value) {\n fields.push({ label, value, row: -1, col: -1 })\n }\n }\n return fields\n}\n","/**\n * Markdown → HWPX 역변환\n *\n * 지원: 단락, 헤딩(1-6), 테이블, 목록(ul/ol), 볼드/이탤릭 인라인, 코드\n * hwpxskill 검증 템플릿 기반 — 실제 한/글과 동일한 파일 구조 사용\n */\n\nimport JSZip from \"jszip\"\nimport {\n HEADER_XML,\n CONTENT_HPF,\n CONTAINER_XML,\n CONTAINER_RDF,\n MANIFEST_XML,\n VERSION_XML,\n SETTINGS_XML,\n} from \"./template-content.js\"\nimport { extractTemplateStyles } from \"./template-analyzer.js\"\nimport { createStyleMap, getStyleForBlock, getCharPrForInline } from \"./style-matcher.js\"\nimport type { StyleMap } from \"./style-matcher.js\"\nimport type { ExtractedImage } from \"../types.js\"\n\n// ─── charPr ID 상수 (template/Contents/header.xml과 일치) ──\n\nconst CHAR_NORMAL = \"0\" // 10pt 기본\nconst CHAR_H1 = \"7\" // 20pt 볼드\nconst CHAR_H2 = \"8\" // 14pt 볼드\nconst CHAR_H3 = \"9\" // 12pt 볼드\nconst CHAR_H456 = \"10\" // 11pt 볼드\nconst CHAR_BOLD = \"11\" // 10pt 볼드 인라인\nconst CHAR_ITALIC = \"12\" // 10pt 이탤릭 인라인\nconst CHAR_BOLD_ITALIC = \"13\" // 10pt 볼드+이탤릭 인라인\nconst CHAR_CODE = \"14\" // 9pt 코드 (회색 음영)\nconst CHAR_STRIKETHROUGH = \"15\" // 10pt 취소선\n\nconst PARA_NORMAL = \"0\"\nconst PARA_BLOCKQUOTE = \"20\"\nconst PARA_HR = \"21\"\n\n// ─── section0.xml 네임스페이스 (hwpxskill 템플릿과 동일) ──\n\nconst SEC_NS = [\n `xmlns:ha=\"http://www.hancom.co.kr/hwpml/2011/app\"`,\n `xmlns:hp=\"http://www.hancom.co.kr/hwpml/2011/paragraph\"`,\n `xmlns:hp10=\"http://www.hancom.co.kr/hwpml/2016/paragraph\"`,\n `xmlns:hs=\"http://www.hancom.co.kr/hwpml/2011/section\"`,\n `xmlns:hc=\"http://www.hancom.co.kr/hwpml/2011/core\"`,\n `xmlns:hh=\"http://www.hancom.co.kr/hwpml/2011/head\"`,\n `xmlns:hhs=\"http://www.hancom.co.kr/hwpml/2011/history\"`,\n `xmlns:hm=\"http://www.hancom.co.kr/hwpml/2011/master-page\"`,\n `xmlns:hpf=\"http://www.hancom.co.kr/schema/2011/hpf\"`,\n `xmlns:dc=\"http://purl.org/dc/elements/1.1/\"`,\n `xmlns:opf=\"http://www.idpf.org/2007/opf/\"`,\n `xmlns:ooxmlchart=\"http://www.hancom.co.kr/hwpml/2016/ooxmlchart\"`,\n `xmlns:hwpunitchar=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\"`,\n `xmlns:epub=\"http://www.idpf.org/2007/ops\"`,\n `xmlns:config=\"urn:oasis:names:tc:opendocument:xmlns:config:1.0\"`,\n].join(\" \")\n\n// ─── ID 생성 ─────────────────────────────────────────────\n\nfunction makeIdGen(): () => string {\n let counter = 1_000_000_001\n return () => String(counter++)\n}\n\n// ─── XML 이스케이프 ──────────────────────────────────────\n\nfunction escapeXml(text: string): string {\n return text\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n}\n\n// ─── 인라인 마크다운 파싱 ────────────────────────────────\n\ninterface InlineRun {\n text: string\n bold?: boolean\n italic?: boolean\n code?: boolean\n strikethrough?: boolean\n url?: string // 링크인 경우 URL\n}\n\nfunction parseInlineRuns(text: string): InlineRun[] {\n const runs: InlineRun[] = []\n // 순서 중요: ***>**>*>_>`>링크 순으로 매칭\n const re = /\\*\\*\\*(.+?)\\*\\*\\*|\\*\\*(.+?)\\*\\*|\\*(.+?)\\*|_(.+?)_|`(.+?)`|~~(.+?)~~|\\[([^\\]]+)\\]\\(([^)]+)\\)/g\n let last = 0\n let m: RegExpExecArray | null\n\n while ((m = re.exec(text)) !== null) {\n if (m.index > last) runs.push({ text: text.slice(last, m.index) })\n if (m[1]) runs.push({ text: m[1], bold: true, italic: true })\n else if (m[2]) runs.push({ text: m[2], bold: true })\n else if (m[3]) runs.push({ text: m[3], italic: true })\n else if (m[4]) runs.push({ text: m[4], italic: true })\n else if (m[5]) runs.push({ text: m[5], code: true })\n else if (m[6]) runs.push({ text: m[6], strikethrough: true })\n else if (m[7]) runs.push({ text: m[7], url: m[8] }) // [text](url)\n last = m.index + m[0].length\n }\n if (last < text.length) runs.push({ text: text.slice(last) })\n return runs.filter(r => r.text.length > 0)\n}\n\nfunction charPrForRun(run: InlineRun): string {\n if (run.code) return CHAR_CODE\n if (run.strikethrough) return CHAR_STRIKETHROUGH\n if (run.bold && run.italic) return CHAR_BOLD_ITALIC\n if (run.bold) return CHAR_BOLD\n if (run.italic) return CHAR_ITALIC\n return CHAR_NORMAL\n}\n\n// ─── 런/문단 XML 생성 ────────────────────────────────────\n\nfunction makeRun(text: string, charPrId: string): string {\n return `<hp:run charPrIDRef=\"${charPrId}\"><hp:t${text ? `>${escapeXml(text)}</hp:t` : \"/\"}></hp:run>`\n}\n\nfunction makeHyperlinkRun(text: string, url: string, charPrId: string, nextId: () => string): string {\n const subId = nextId()\n const paraId = nextId()\n // HWPX hyperLink control — subList 안에 텍스트 단락 포함\n return [\n `<hp:run charPrIDRef=\"${charPrId}\">`,\n ` <hp:ctrl>`,\n ` <hp:hyperLink url=\"${escapeXml(url)}\" macro=\"\" visitedStyle=\"UNKNOWN\" visitedStyleIDRef=\"4294967295\">`,\n ` <hp:subList id=\"${subId}\" textDirection=\"HORIZONTAL\" lineWrap=\"BREAK\" vertAlign=\"TOP\"`,\n ` linkListIDRef=\"0\" linkListNextIDRef=\"0\" textWidth=\"0\" textHeight=\"0\"`,\n ` hasTextRef=\"0\" hasNumRef=\"0\">`,\n ` <hp:p id=\"${paraId}\" paraPrIDRef=\"0\" styleIDRef=\"0\" pageBreak=\"0\" columnBreak=\"0\" merged=\"0\">`,\n ` <hp:run charPrIDRef=\"${charPrId}\"><hp:t>${escapeXml(text)}</hp:t></hp:run>`,\n ` </hp:p>`,\n ` </hp:subList>`,\n ` </hp:hyperLink>`,\n ` </hp:ctrl>`,\n `</hp:run>`,\n ].join(\"\\n\")\n}\n\nfunction makeRunsFromText(text: string, defaultCharPr: string, nextId?: () => string): string {\n // <br> → HWPX 줄바꿈(hp:lf)으로 분할 처리\n if (/<br\\s*\\/?>/i.test(text)) {\n const parts = text.split(/<br\\s*\\/?>/i)\n return parts.map((part, i) => {\n const seg = makeRunsFromText(part, defaultCharPr, nextId)\n return i < parts.length - 1\n ? seg + `<hp:run charPrIDRef=\"${defaultCharPr}\"><hp:lf/></hp:run>`\n : seg\n }).join(\"\")\n }\n const runs = parseInlineRuns(text)\n if (runs.length === 0) return makeRun(\"\", defaultCharPr)\n const isPlain = runs.length === 1 && !runs[0].bold && !runs[0].italic && !runs[0].code && !runs[0].strikethrough && !runs[0].url\n if (isPlain) return makeRun(runs[0].text, defaultCharPr)\n return runs.map(r => {\n if (r.url && nextId) return makeHyperlinkRun(r.text, r.url, CHAR_NORMAL, nextId)\n return makeRun(r.text, charPrForRun(r))\n }).join(\"\")\n}\n\n// linesegarray — 한/글 렌더링 캐시\nfunction makeLineseg(horzsize: number, vertsize: number): string {\n const baseline = Math.round(vertsize * 0.85)\n return ` <hp:linesegarray>\n <hp:lineseg textpos=\"0\" vertpos=\"0\" vertsize=\"${vertsize}\" textheight=\"${vertsize}\" baseline=\"${baseline}\" spacing=\"600\" horzpos=\"0\" horzsize=\"${horzsize}\" flags=\"393216\"/>\n </hp:linesegarray>`\n}\n\n// 셀 단락 lineseg: 줄마다 hp:lineseg 하나씩 필요\n// (하나만 넣으면 한/글이 모든 텍스트를 한 줄로 렌더링 → 겹침 발생)\nconst CHAR_HWP = 1000 // 10pt 한글 1자 너비(HWP 단위)\nconst LINE_HWP = 1400 // 10pt 줄 높이 (폰트+행간)\nconst BASELINE_RATIO = 0.85\n\nfunction estimateCellLineseg(plainText: string, cellHorzsize: number): string {\n const stripped = plainText.replace(/<[^>]*>/g, \"\").replace(/\\s+/g, \" \").trim()\n const charsPerLine = Math.max(1, Math.floor(cellHorzsize / CHAR_HWP))\n const lineCount = Math.max(1, Math.ceil(stripped.length / charsPerLine))\n const baseline = Math.round(LINE_HWP * BASELINE_RATIO)\n const segs = Array.from({ length: lineCount }, (_, i) => {\n const textpos = i * charsPerLine\n const vertpos = i * LINE_HWP\n return ` <hp:lineseg textpos=\"${textpos}\" vertpos=\"${vertpos}\" vertsize=\"${LINE_HWP}\" textheight=\"${LINE_HWP}\" baseline=\"${vertpos + baseline}\" spacing=\"600\" horzpos=\"0\" horzsize=\"${cellHorzsize}\" flags=\"393216\"/>`\n })\n return ` <hp:linesegarray>\\n${segs.join(\"\\n\")}\\n </hp:linesegarray>`\n}\n\nfunction makeParagraph(text: string, charPrId: string, paraPrId: string, nextId: () => string, styleId = \"0\"): string {\n const id = nextId()\n const runs = makeRunsFromText(text, charPrId, nextId)\n return [\n `<hp:p id=\"${id}\" paraPrIDRef=\"${paraPrId}\" styleIDRef=\"${styleId}\" pageBreak=\"0\" columnBreak=\"0\" merged=\"0\">`,\n ` ${runs}`,\n `</hp:p>`,\n ].join(\"\\n\")\n}\n\nfunction makeEmptyParagraph(nextId: () => string): string {\n const id = nextId()\n return [\n `<hp:p id=\"${id}\" paraPrIDRef=\"${PARA_NORMAL}\" styleIDRef=\"0\" pageBreak=\"0\" columnBreak=\"0\" merged=\"0\">`,\n ` <hp:run charPrIDRef=\"${CHAR_NORMAL}\"><hp:t/></hp:run>`,\n `</hp:p>`,\n ].join(\"\\n\")\n}\n\nfunction makeBlockquoteParagraph(text: string, nextId: () => string): string {\n const id = nextId()\n const runs = makeRunsFromText(text, CHAR_ITALIC, nextId)\n return [\n `<hp:p id=\"${id}\" paraPrIDRef=\"${PARA_BLOCKQUOTE}\" styleIDRef=\"0\" pageBreak=\"0\" columnBreak=\"0\" merged=\"0\">`,\n ` ${runs}`,\n `</hp:p>`,\n ].join(\"\\n\")\n}\n\nfunction makeHrParagraph(nextId: () => string): string {\n const id = nextId()\n return [\n `<hp:p id=\"${id}\" paraPrIDRef=\"${PARA_HR}\" styleIDRef=\"0\" pageBreak=\"0\" columnBreak=\"0\" merged=\"0\">`,\n ` <hp:run charPrIDRef=\"${CHAR_NORMAL}\"><hp:t/></hp:run>`,\n `</hp:p>`,\n ].join(\"\\n\")\n}\n\nfunction headingCharPr(level: number): string {\n if (level === 1) return CHAR_H1\n if (level === 2) return CHAR_H2\n if (level === 3) return CHAR_H3\n return CHAR_H456\n}\n\n// ─── 테이블 XML ─────────────────────────────────────────\n\nconst BODY_WIDTH = 42520\nconst ROW_HEIGHT = 2400\n\nfunction countBr(text: string): number {\n return (text.match(/<br\\s*\\/?>/gi) || []).length\n}\n\nfunction makeTableCell(\n text: string,\n colAddr: number,\n rowAddr: number,\n colWidth: number,\n cellHeight: number,\n isHeader: boolean,\n nextId: () => string,\n styleMap?: StyleMap,\n): string {\n let charPr: string\n let borderFill = \"3\"\n\n if (styleMap) {\n const cellStyle = getStyleForBlock(styleMap, isHeader ? \"table_header\" : \"table_cell\")\n charPr = cellStyle.charPr\n borderFill = cellStyle.borderFill || \"3\"\n } else {\n charPr = isHeader ? CHAR_BOLD : CHAR_NORMAL\n }\n\n const subId = nextId()\n // <br>을 별도 <hp:p>로 분리 (hp:lf는 한/글 셀에서 동작하지 않음)\n // 각 단락의 lineseg vertsize: 예상 줄 수 기반으로 계산 (자동줄바꿈 포함)\n const cellHorzsize = Math.max(1000, colWidth - 2000)\n const segments = text.split(/<br\\s*\\/?>/i)\n const cellParas = segments.map(seg => {\n const pid = nextId()\n return [\n ` <hp:p id=\"${pid}\" paraPrIDRef=\"0\" styleIDRef=\"0\" pageBreak=\"0\" columnBreak=\"0\" merged=\"0\">`,\n ` ${makeRunsFromText(seg, charPr, nextId)}`,\n estimateCellLineseg(seg, cellHorzsize),\n ` </hp:p>`,\n ].join(\"\\n\")\n }).join(\"\\n\")\n return [\n `<hp:tc name=\"\" header=\"${isHeader ? 1 : 0}\" hasMargin=\"0\" protect=\"0\" editable=\"0\" dirty=\"1\" borderFillIDRef=\"${borderFill}\">`,\n ` <hp:subList id=\"${subId}\" textDirection=\"HORIZONTAL\" lineWrap=\"BREAK\" vertAlign=\"CENTER\"`,\n ` linkListIDRef=\"0\" linkListNextIDRef=\"0\" textWidth=\"0\" textHeight=\"0\"`,\n ` hasTextRef=\"0\" hasNumRef=\"0\">`,\n cellParas,\n ` </hp:subList>`,\n ` <hp:cellAddr colAddr=\"${colAddr}\" rowAddr=\"${rowAddr}\"/>`,\n ` <hp:cellSpan colSpan=\"1\" rowSpan=\"1\"/>`,\n ` <hp:cellSz width=\"${colWidth}\" height=\"${cellHeight}\"/>`,\n ` <hp:cellMargin left=\"1000\" right=\"1000\" top=\"500\" bottom=\"500\"/>`,\n `</hp:tc>`,\n ].join(\"\\n\")\n}\n\nfunction makeTable(rows: string[][], nextId: () => string, styleMap?: StyleMap): string {\n if (rows.length === 0) return \"\"\n const colCnt = rows[0].length\n const colWidth = Math.floor(BODY_WIDTH / colCnt)\n const totalWidth = colWidth * colCnt\n\n // 각 행의 높이 = 셀 내 텍스트 줄바꿈(br) + 자동줄바꿈(wrapping) 모두 고려\n const cellHorzsize = Math.max(1000, colWidth - 2000)\n const rowHeights = rows.map(row => {\n const maxTotalLines = Math.max(1, ...row.map(cell => {\n return cell.split(/<br\\s*\\/?>/i).reduce((sum, seg) => {\n const plain = seg.replace(/<[^>]*>/g, \"\").replace(/\\s+/g, \" \").trim()\n const charsPerLine = Math.max(1, Math.floor(cellHorzsize / CHAR_HWP))\n return sum + Math.max(1, Math.ceil(plain.length / charsPerLine))\n }, 0)\n }))\n return maxTotalLines * LINE_HWP + 1000 // 상하 마진 여유\n })\n const totalHeight = rowHeights.reduce((s, h) => s + h, 0)\n\n const trElements = rows.map((row, rowIdx) =>\n `<hp:tr>\\n${row.map((cell, colIdx) => makeTableCell(cell, colIdx, rowIdx, colWidth, rowHeights[rowIdx], rowIdx === 0, nextId, styleMap)).join(\"\\n\")}\\n</hp:tr>`\n ).join(\"\\n\")\n\n const tableId = nextId()\n const paraId = nextId()\n\n return [\n `<hp:p id=\"${paraId}\" paraPrIDRef=\"0\" styleIDRef=\"0\" pageBreak=\"0\" columnBreak=\"0\" merged=\"0\">`,\n `<hp:run charPrIDRef=\"0\">`,\n `<hp:tbl id=\"${tableId}\" zOrder=\"0\" numberingType=\"TABLE\" textWrap=\"TOP_AND_BOTTOM\"`,\n ` textFlow=\"BOTH_SIDES\" lock=\"0\" dropcapstyle=\"None\" pageBreak=\"CELL\"`,\n ` repeatHeader=\"1\" rowCnt=\"${rows.length}\" colCnt=\"${colCnt}\" cellSpacing=\"0\"`,\n ` borderFillIDRef=\"3\" noAdjust=\"0\">`,\n ` <hp:sz width=\"${totalWidth}\" widthRelTo=\"ABSOLUTE\" height=\"${totalHeight}\" heightRelTo=\"ABSOLUTE\" protect=\"0\"/>`,\n ` <hp:pos treatAsChar=\"1\" affectLSpacing=\"0\" flowWithText=\"1\" allowOverlap=\"0\"`,\n ` holdAnchorAndSO=\"0\" vertRelTo=\"PARA\" horzRelTo=\"COLUMN\" vertAlign=\"TOP\"`,\n ` horzAlign=\"LEFT\" vertOffset=\"0\" horzOffset=\"0\"/>`,\n ` <hp:outMargin left=\"0\" right=\"0\" top=\"0\" bottom=\"0\"/>`,\n ` <hp:inMargin left=\"0\" right=\"0\" top=\"0\" bottom=\"0\"/>`,\n trElements,\n `</hp:tbl>`,\n `</hp:run>`,\n makeLineseg(totalWidth, totalHeight),\n `</hp:p>`,\n ].join(\"\\n\")\n}\n\n// ─── 마크다운 파싱 ───────────────────────────────────────\n\nexport interface MdBlock {\n type: \"paragraph\" | \"heading\" | \"table\" | \"list\" | \"empty\" | \"image\" | \"code\" | \"blockquote\" | \"hr\"\n text?: string\n level?: number\n rows?: string[][]\n items?: ListItem[]\n listType?: \"ordered\" | \"unordered\"\n // image\n alt?: string\n src?: string // 파일명 또는 data URI\n // code\n lang?: string\n}\n\ninterface ListItem {\n text: string\n indent: number // 0=최상위, 1=1단계 들여쓰기 등\n}\n\nfunction getIndent(line: string): number {\n let spaces = 0\n for (const ch of line) {\n if (ch === \" \") spaces++\n else if (ch === \"\\t\") spaces += 2\n else break\n }\n return Math.floor(spaces / 2) // 2칸 또는 탭당 indent 1\n}\n\nexport function parseMarkdownToBlocks(md: string): MdBlock[] {\n const lines = md.split(\"\\n\")\n const blocks: MdBlock[] = []\n let i = 0\n\n while (i < lines.length) {\n const line = lines[i]\n const trimmed = line.trim()\n\n if (!trimmed) { blocks.push({ type: \"empty\" }); i++; continue }\n\n // 수평선\n if (/^(-{3,}|\\*{3,}|_{3,})$/.test(trimmed)) {\n blocks.push({ type: \"hr\" })\n i++\n continue\n }\n\n // blockquote\n if (trimmed.startsWith(\">\")) {\n const quoteLines: string[] = []\n while (i < lines.length && lines[i].trim().startsWith(\">\")) {\n quoteLines.push(lines[i].trim().replace(/^>\\s?/, \"\"))\n i++\n }\n blocks.push({ type: \"blockquote\", text: quoteLines.join(\" \") })\n continue\n }\n\n // 헤딩\n const hm = trimmed.match(/^(#{1,6})\\s+(.+)$/)\n if (hm) { blocks.push({ type: \"heading\", text: hm[2].trim(), level: hm[1].length }); i++; continue }\n\n // 이미지 (단독 줄)\n const imgm = trimmed.match(/^!\\[([^\\]]*)\\]\\(([^)]+)\\)$/)\n if (imgm) { blocks.push({ type: \"image\", alt: imgm[1], src: imgm[2] }); i++; continue }\n\n // 테이블\n if (trimmed.startsWith(\"|\")) {\n const tableRows: string[][] = []\n while (i < lines.length && lines[i].trim().startsWith(\"|\")) {\n const row = lines[i].trim()\n if (/^[\\s|:\\-]+$/.test(row)) { i++; continue }\n const cells = row.split(\"|\").slice(1, -1).map(c => c.trim())\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 if (/^\\s*[-*+]\\s/.test(line)) {\n const items: ListItem[] = []\n while (i < lines.length && /^\\s*[-*+]\\s/.test(lines[i])) {\n const indent = getIndent(lines[i])\n const text = lines[i].trim().replace(/^[-*+]\\s+/, \"\")\n items.push({ text, indent })\n i++\n }\n blocks.push({ type: \"list\", listType: \"unordered\", items })\n continue\n }\n\n // 순서 있는 목록 (중첩 지원)\n if (/^\\s*\\d+\\.\\s/.test(line)) {\n const items: ListItem[] = []\n while (i < lines.length && /^\\s*\\d+\\.\\s/.test(lines[i])) {\n const indent = getIndent(lines[i])\n const text = lines[i].trim().replace(/^\\d+\\.\\s+/, \"\")\n items.push({ text, indent })\n i++\n }\n blocks.push({ type: \"list\", listType: \"ordered\", items })\n continue\n }\n\n // 코드 블록\n if (trimmed.startsWith(\"```\")) {\n const lang = trimmed.slice(3).trim()\n i++\n const codeLines: string[] = []\n while (i < lines.length && !lines[i].trim().startsWith(\"```\")) codeLines.push(lines[i++])\n if (i < lines.length) i++\n if (codeLines.length > 0) blocks.push({ type: \"code\", text: codeLines.join(\"\\n\"), lang })\n continue\n }\n\n // 일반 단락 (인접한 여러 줄 하나로 합치기)\n const paraLines: string[] = []\n while (i < lines.length && lines[i].trim()\n && !lines[i].trim().startsWith(\"#\")\n && !lines[i].trim().startsWith(\"|\")\n && !lines[i].trim().startsWith(\">\")\n && !/^\\s*[-*+]\\s/.test(lines[i])\n && !/^\\s*\\d+\\.\\s/.test(lines[i])\n && !lines[i].trim().startsWith(\"```\")\n && !lines[i].trim().match(/^!\\[[^\\]]*\\]\\([^)]+\\)$/)\n && !/^(-{3,}|\\*{3,}|_{3,})$/.test(lines[i].trim())\n ) paraLines.push(lines[i++].trim())\n if (paraLines.length > 0) blocks.push({ type: \"paragraph\", text: paraLines.join(\" \") })\n }\n\n return blocks\n}\n\n// ─── 이미지 크기 계산 ──────────────────────────────────\n\nfunction getImageDimensions(data: Uint8Array): { width: number; height: number } | null {\n // PNG: \\x89PNG 시그니처, IHDR에 width/height (offset 16, 20)\n if (data[0] === 0x89 && data[1] === 0x50 && data[2] === 0x4E && data[3] === 0x47) {\n if (data.length < 24) return null\n const w = (data[16] << 24 | data[17] << 16 | data[18] << 8 | data[19]) >>> 0\n const h = (data[20] << 24 | data[21] << 16 | data[22] << 8 | data[23]) >>> 0\n return w > 0 && h > 0 ? { width: w, height: h } : null\n }\n // JPEG: FF D8 — SOF0/SOF1/SOF2 마커 스캔\n if (data[0] === 0xFF && data[1] === 0xD8) {\n let i = 2\n while (i < data.length - 8) {\n if (data[i] !== 0xFF) break\n const marker = data[i + 1]\n if (marker >= 0xC0 && marker <= 0xC3) {\n const h = (data[i + 5] << 8) | data[i + 6]\n const w = (data[i + 7] << 8) | data[i + 8]\n return w > 0 && h > 0 ? { width: w, height: h } : null\n }\n // 길이 없는 단독 마커 (SOI=D8, EOI=D9, RST0~7=D0~D7, TEM=01)\n if (marker === 0xD9 || marker === 0x01 || (marker >= 0xD0 && marker <= 0xD7)) {\n i += 2\n continue\n }\n const segLen = (data[i + 2] << 8) | data[i + 3]\n if (segLen < 2) break // 손상된 파일 방어\n i += 2 + segLen\n }\n }\n return null\n}\n\n// 96 DPI 기준 자연 크기로 HWPUNIT 계산 (1인치 = 7200 HWP units)\n// 10cm(28346 HWP)보다 큰 경우에만 축소, 작은 이미지는 뻥튀기하지 않음\nfunction calcHwpSize(width: number, height: number): { widthHwp: number; heightHwp: number } {\n if (width <= 0 || height <= 0) return { widthHwp: 28346, heightHwp: 19843 }\n const HWP_PER_PIXEL = 7200 / 96 // 96 DPI 기준 픽셀당 HWP units = 75\n const naturalW = Math.round(width * HWP_PER_PIXEL)\n const naturalH = Math.round(height * HWP_PER_PIXEL)\n const maxWidthHwp = 28346 // 10cm\n if (naturalW <= maxWidthHwp) {\n return { widthHwp: naturalW, heightHwp: naturalH }\n }\n // 최대 10cm로 비율 유지 축소\n const ratio = height / width\n return { widthHwp: maxWidthHwp, heightHwp: Math.round(maxWidthHwp * ratio) }\n}\n\n// ─── 이미지 단락 XML ─────────────────────────────────────\n\ninterface BinDataEntry {\n ref: string // binaryItemIDRef 값 (확장자 없는 파일명, e.g. \"image_001\")\n zipPath: string // ZIP 내 경로 (e.g. \"BinData/image_001.png\")\n data?: Uint8Array // 이미지 바이너리 데이터\n dims?: { width: number; height: number } // 원본 픽셀 크기\n}\n\nfunction mimeToFormat(mimeType: string): string {\n if (mimeType.includes(\"jpeg\") || mimeType.includes(\"jpg\")) return \"JPG\"\n if (mimeType.includes(\"gif\")) return \"GIF\"\n if (mimeType.includes(\"bmp\")) return \"BMP\"\n return \"PNG\"\n}\n\nfunction makeImageParagraph(\n ref: string, // binaryItemIDRef (확장자 없는 파일명, e.g. \"image_001\")\n nextId: () => string,\n widthHwp = 28346, // 표시 너비 (HWP units)\n heightHwp = 19843, // 표시 높이 (HWP units)\n naturalWidth?: number, // 원본 픽셀너비 × 75 (imgClip/imgDim용)\n naturalHeight?: number, // 원본 픽셀높이 × 75\n): string {\n const paraId = nextId()\n const picId = nextId()\n const natW = naturalWidth || widthHwp\n const natH = naturalHeight || heightHwp\n const cx = Math.round(widthHwp / 2)\n const cy = Math.round(heightHwp / 2)\n const imgLineseg = [\n ` <hp:linesegarray>`,\n ` <hp:lineseg textpos=\"0\" vertpos=\"0\" vertsize=\"${heightHwp}\" textheight=\"${heightHwp}\"`,\n ` baseline=\"${Math.round(heightHwp * 0.85)}\" spacing=\"600\"`,\n ` horzpos=\"0\" horzsize=\"42520\" flags=\"393216\"/>`,\n ` </hp:linesegarray>`,\n ].join(\"\\n\")\n const pic = [\n ` <hp:pic id=\"${picId}\" zOrder=\"0\" numberingType=\"NONE\" textWrap=\"SQUARE\" textFlow=\"BOTH_SIDES\"`,\n ` lock=\"0\" dropcapstyle=\"None\" href=\"\" groupLevel=\"0\" instid=\"0\" reverse=\"0\">`,\n ` <hp:offset x=\"0\" y=\"0\"/>`,\n ` <hp:orgSz width=\"${widthHwp}\" height=\"${heightHwp}\"/>`,\n ` <hp:curSz width=\"${widthHwp}\" height=\"${heightHwp}\"/>`,\n ` <hp:flip horizontal=\"0\" vertical=\"0\"/>`,\n ` <hp:rotationInfo angle=\"0\" centerX=\"${cx}\" centerY=\"${cy}\" rotateimage=\"1\"/>`,\n ` <hp:renderingInfo>`,\n ` <hc:transMatrix e1=\"1\" e2=\"0\" e3=\"0\" e4=\"0\" e5=\"1\" e6=\"0\"/>`,\n ` <hc:scaMatrix e1=\"1\" e2=\"0\" e3=\"0\" e4=\"0\" e5=\"1\" e6=\"0\"/>`,\n ` <hc:rotMatrix e1=\"1\" e2=\"0\" e3=\"0\" e4=\"0\" e5=\"1\" e6=\"0\"/>`,\n ` </hp:renderingInfo>`,\n ` <hc:img binaryItemIDRef=\"${ref}\" bright=\"0\" contrast=\"0\" effect=\"REAL_PIC\" alpha=\"0\"/>`,\n ` <hp:imgRect>`,\n ` <hc:pt0 x=\"0\" y=\"0\"/>`,\n ` <hc:pt1 x=\"${widthHwp}\" y=\"0\"/>`,\n ` <hc:pt2 x=\"${widthHwp}\" y=\"${heightHwp}\"/>`,\n ` <hc:pt3 x=\"0\" y=\"${heightHwp}\"/>`,\n ` </hp:imgRect>`,\n ` <hp:imgClip left=\"0\" right=\"${natW}\" top=\"0\" bottom=\"${natH}\"/>`,\n ` <hp:inMargin left=\"0\" right=\"0\" top=\"0\" bottom=\"0\"/>`,\n ` <hp:imgDim dimwidth=\"${natW}\" dimheight=\"${natH}\"/>`,\n ` <hp:effects/>`,\n ` <hp:sz width=\"${widthHwp}\" widthRelTo=\"ABSOLUTE\" height=\"${heightHwp}\" heightRelTo=\"ABSOLUTE\" protect=\"0\"/>`,\n ` <hp:pos treatAsChar=\"1\" affectLSpacing=\"0\" flowWithText=\"1\" allowOverlap=\"0\"`,\n ` holdAnchorAndSO=\"0\" vertRelTo=\"PARA\" horzRelTo=\"PARA\"`,\n ` vertAlign=\"TOP\" horzAlign=\"LEFT\" vertOffset=\"0\" horzOffset=\"0\"/>`,\n ` <hp:outMargin left=\"0\" right=\"0\" top=\"0\" bottom=\"0\"/>`,\n ` </hp:pic>`,\n ].join(\"\\n\")\n return [\n `<hp:p id=\"${paraId}\" paraPrIDRef=\"0\" styleIDRef=\"0\" pageBreak=\"0\" columnBreak=\"0\" merged=\"0\">`,\n ` <hp:run charPrIDRef=\"0\">`,\n pic,\n ` </hp:run>`,\n imgLineseg,\n `</hp:p>`,\n ].join(\"\\n\")\n}\n\n// ─── 코드 블록 단락 ─────────────────────────────────────\n\nfunction makeCodeParagraphs(code: string, nextId: () => string): string {\n // 각 줄을 별도 단락으로 (코드 charPr 사용)\n const lines = code.split(\"\\n\")\n return lines.map(line => {\n const id = nextId()\n const safe = escapeXml(line || \" \")\n return [\n `<hp:p id=\"${id}\" paraPrIDRef=\"0\" styleIDRef=\"0\" pageBreak=\"0\" columnBreak=\"0\" merged=\"0\">`,\n ` <hp:run charPrIDRef=\"${CHAR_CODE}\"><hp:t>${safe}</hp:t></hp:run>`,\n `</hp:p>`,\n ].join(\"\\n\")\n }).join(\"\\n\")\n}\n\n// ─── section0.xml 생성 ──────────────────────────────────\n\nfunction generateSectionXml(\n blocks: MdBlock[],\n styleMap?: StyleMap,\n imageMap?: Map<string, string>, // src → ref (binaryItemIDRef)\n imageDimsMap?: Map<string, { width: number; height: number }>, // ref → 픽셀 크기\n secPrXml?: string, // 템플릿에서 추출한 <hp:secPr>...</hp:secPr>\n colPrXml?: string, // 템플릿에서 추출한 <hp:ctrl>...</hp:ctrl>\n masterPageCnt = 0, // 마스터페이지 수\n): string {\n const nextId = makeIdGen()\n const firstId = nextId()\n\n // 스타일맵이 없으면 기본값 사용\n const defaultCharPr = styleMap ? styleMap.body.charPr : CHAR_NORMAL\n const defaultParaPr = styleMap ? styleMap.body.paraPr : PARA_NORMAL\n\n // secPr: 템플릿 XML 우선, 없으면 기본값\n const secPrContent = secPrXml\n ? secPrXml.replace(/masterPageCnt=\"\\d+\"/, `masterPageCnt=\"${masterPageCnt}\"`)\n : [\n `<hp:secPr id=\"\" textDirection=\"HORIZONTAL\" spaceColumns=\"1134\" tabStop=\"8000\" tabStopVal=\"4000\" tabStopUnit=\"HWPUNIT\" outlineShapeIDRef=\"1\" memoShapeIDRef=\"0\" textVerticalWidthHead=\"0\" masterPageCnt=\"${masterPageCnt}\">`,\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:lineNumberShape restartType=\"0\" countBy=\"0\" distance=\"0\" startNumber=\"0\"/>`,\n ` <hp:pagePr landscape=\"WIDELY\" width=\"59528\" height=\"84186\" gutterType=\"LEFT_ONLY\">`,\n ` <hp:margin header=\"4252\" footer=\"4252\" gutter=\"0\" left=\"8504\" right=\"8504\" top=\"8504\" bottom=\"8504\"/>`,\n ` </hp:pagePr>`,\n ` <hp:footNotePr>`,\n ` <hp:autoNumFormat type=\"DIGIT\" userChar=\"\" prefixChar=\"\" suffixChar=\")\" supscript=\"0\"/>`,\n ` <hp:noteLine length=\"-1\" type=\"SOLID\" width=\"0.12 mm\" color=\"#000000\"/>`,\n ` <hp:noteSpacing betweenNotes=\"283\" belowLine=\"567\" aboveLine=\"850\"/>`,\n ` <hp:numbering type=\"CONTINUOUS\" newNum=\"1\"/>`,\n ` <hp:placement place=\"EACH_COLUMN\" beneathText=\"0\"/>`,\n ` </hp:footNotePr>`,\n ` <hp:endNotePr>`,\n ` <hp:autoNumFormat type=\"DIGIT\" userChar=\"\" prefixChar=\"\" suffixChar=\")\" supscript=\"0\"/>`,\n ` <hp:noteLine length=\"14692344\" type=\"SOLID\" width=\"0.12 mm\" color=\"#000000\"/>`,\n ` <hp:noteSpacing betweenNotes=\"0\" belowLine=\"567\" aboveLine=\"850\"/>`,\n ` <hp:numbering type=\"CONTINUOUS\" newNum=\"1\"/>`,\n ` <hp:placement place=\"END_OF_DOCUMENT\" beneathText=\"0\"/>`,\n ` </hp:endNotePr>`,\n `</hp:secPr>`,\n ].join(\"\\n\")\n\n const colPrContent = colPrXml ||\n `<hp:ctrl>\\n <hp:colPr id=\"\" type=\"NEWSPAPER\" layout=\"LEFT\" colCount=\"1\" sameSz=\"1\" sameGap=\"0\"/>\\n</hp:ctrl>`\n\n const secPrBlock = [\n `<hp:p id=\"${firstId}\" paraPrIDRef=\"0\" styleIDRef=\"0\" pageBreak=\"0\" columnBreak=\"0\" merged=\"0\">`,\n ` <hp:run charPrIDRef=\"0\">`,\n secPrContent,\n colPrContent,\n ` </hp:run>`,\n ` <hp:run charPrIDRef=\"0\"><hp:t/></hp:run>`,\n makeLineseg(42520, 1000),\n `</hp:p>`,\n ].join(\"\\n\")\n\n const bodyParts: string[] = []\n\n // 순서 있는 목록 번호 카운터 (indent 레벨별)\n const orderedCounters = new Map<number, number>()\n\n for (const block of blocks) {\n // 목록이 아니면 카운터 초기화\n if (block.type !== \"list\") orderedCounters.clear()\n\n switch (block.type) {\n case \"heading\": {\n const level = block.level || 1\n let charPrId: string\n let paraPrId: string\n let styleId = \"0\"\n\n if (styleMap) {\n const blockType = level === 1 ? \"h1\" : level === 2 ? \"h2\" : level === 3 ? \"h3\" : \"h4\"\n const style = getStyleForBlock(styleMap, blockType as any)\n charPrId = style.charPr\n paraPrId = style.paraPr || defaultParaPr\n styleId = (style as any).styleId ?? \"0\"\n } else {\n charPrId = headingCharPr(level)\n paraPrId = PARA_NORMAL\n }\n\n bodyParts.push(makeParagraph(block.text || \"\", charPrId, paraPrId, nextId, styleId))\n break\n }\n case \"paragraph\": {\n if (block.text) {\n const charPrId = styleMap ? styleMap.body.charPr : CHAR_NORMAL\n const paraPrId = styleMap ? styleMap.body.paraPr : PARA_NORMAL\n const styleId = styleMap ? (styleMap.body as any).styleId ?? \"0\" : \"0\"\n bodyParts.push(makeParagraph(block.text, charPrId, paraPrId, nextId, styleId))\n } else {\n bodyParts.push(makeEmptyParagraph(nextId))\n }\n break\n }\n case \"code\": {\n bodyParts.push(makeCodeParagraphs(block.text || \"\", nextId))\n break\n }\n case \"blockquote\":\n if (block.text) bodyParts.push(makeBlockquoteParagraph(block.text, nextId))\n break\n case \"hr\":\n bodyParts.push(makeHrParagraph(nextId))\n break\n case \"empty\":\n bodyParts.push(makeEmptyParagraph(nextId))\n break\n case \"list\": {\n const charPrId = styleMap ? styleMap.body.charPr : CHAR_NORMAL\n const paraPrId = styleMap ? styleMap.body.paraPr : PARA_NORMAL\n const items = block.items || []\n\n if (block.listType === \"ordered\") {\n for (const item of items) {\n const cnt = (orderedCounters.get(item.indent) || 0) + 1\n orderedCounters.set(item.indent, cnt)\n // 하위 레벨 카운터 초기화\n for (const [k] of orderedCounters) {\n if (k > item.indent) orderedCounters.set(k, 0)\n }\n const indent = \" \".repeat(item.indent)\n bodyParts.push(makeParagraph(`${indent}${cnt}. ${item.text}`, charPrId, paraPrId, nextId))\n }\n } else {\n for (const item of items) {\n const bullets = [\"•\", \"◦\", \"▪\"]\n const bullet = bullets[Math.min(item.indent, bullets.length - 1)]\n const indent = \" \".repeat(item.indent)\n bodyParts.push(makeParagraph(`${indent}${bullet} ${item.text}`, charPrId, paraPrId, nextId))\n }\n }\n break\n }\n case \"table\":\n if (block.rows?.length) bodyParts.push(makeTable(block.rows, nextId, styleMap))\n break\n case \"image\": {\n const src = block.src || \"\"\n // WMF/EMF는 원본 좌표 없이 재배치 불가 → 삽입 시 텍스트 겹침 발생하므로 스킵\n const srcBasename = src.includes(\"/\") || src.includes(\"\\\\\") ? src.split(/[\\\\/]/).pop()! : src\n const extLower = srcBasename.toLowerCase()\n if (extLower.endsWith(\".wmf\") || extLower.endsWith(\".emf\")) break\n const ref = imageMap?.get(src) ?? imageMap?.get(srcBasename)\n if (ref !== undefined) {\n const dims = imageDimsMap?.get(ref)\n const { widthHwp, heightHwp } = dims\n ? calcHwpSize(dims.width, dims.height)\n : { widthHwp: 28346, heightHwp: 19843 }\n const natW = dims ? Math.round(dims.width * 75) : widthHwp\n const natH = dims ? Math.round(dims.height * 75) : heightHwp\n bodyParts.push(makeImageParagraph(ref, nextId, widthHwp, heightHwp, natW, natH))\n } else {\n const alt = block.alt || src || \"(이미지)\"\n bodyParts.push(makeParagraph(`[이미지: ${alt}]`, CHAR_NORMAL, PARA_NORMAL, nextId))\n }\n break\n }\n }\n }\n\n return [\n `<?xml version=\"1.0\" encoding=\"UTF-8\"?>`,\n `<hs:sec ${SEC_NS}>`,\n secPrBlock,\n ...bodyParts,\n `</hs:sec>`,\n ].join(\"\\n\")\n}\n\n// ─── 공개 API ────────────────────────────────────────────\n\nexport interface MarkdownToHwpxOptions {\n templateArrayBuffer?: ArrayBuffer // 사용자 제공 HWPX 템플릿\n warnings?: string[] // 경고 메시지 수집\n images?: ExtractedImage[] // 포함할 이미지 파일 (filename, data, mimeType)\n}\n\n/**\n * 마크다운 텍스트를 HWPX (ArrayBuffer)로 변환.\n * @param markdown 마크다운 텍스트\n * @param options 템플릿, 경고 수집 등\n */\nexport async function markdownToHwpx(\n markdown: string,\n options?: MarkdownToHwpxOptions | ArrayBuffer\n): Promise<ArrayBuffer> {\n // 하위 호환성: 두 번째 인자가 ArrayBuffer이면 templateArrayBuffer로 처리\n let opts: MarkdownToHwpxOptions = {}\n if (options instanceof ArrayBuffer) {\n opts.templateArrayBuffer = options\n } else if (options) {\n opts = options\n }\n\n const warnings = opts.warnings || []\n let styleMap: StyleMap | null = null\n let headerXml = HEADER_XML\n let secPrXml: string | undefined\n let colPrXml: string | undefined\n let masterpages: Array<{ filename: string; content: string }> = []\n\n // 템플릿 처리\n if (opts.templateArrayBuffer) {\n try {\n const templateStyles = await extractTemplateStyles(opts.templateArrayBuffer)\n styleMap = createStyleMap(templateStyles, warnings)\n if (templateStyles.headerXml) headerXml = templateStyles.headerXml\n if (templateStyles.secPrXml) secPrXml = templateStyles.secPrXml\n if (templateStyles.colPrXml) colPrXml = templateStyles.colPrXml\n if (templateStyles.masterpages?.length) masterpages = templateStyles.masterpages\n } catch (err) {\n const msg = err instanceof Error ? err.message : \"알 수 없는 오류\"\n warnings.push(`[warn] 템플릿 처리 실패: ${msg}. 기본 스타일 사용`)\n }\n }\n\n // 이미지 처리: filename → ref(binaryItemIDRef) 매핑 (중복제거 없이 파일명 기반)\n const imageMap = new Map<string, string>() // src filename → ref\n const imageDimsMap = new Map<string, { width: number; height: number }>() // ref → 픽셀 크기\n const binDataEntries: BinDataEntry[] = []\n const usedRefs = new Set<string>() // ref 이름 충돌 방지용\n\n if (opts.images && opts.images.length > 0) {\n for (const img of opts.images) {\n const nameWithoutExt = img.filename.replace(/\\.[^.]+$/, \"\")\n const format = mimeToFormat(img.mimeType)\n const ext = format.toLowerCase() === \"jpg\" ? \"jpg\" : format.toLowerCase()\n // ref 충돌 방지: 같은 이름이 이미 있으면 카운터 추가\n let ref = nameWithoutExt\n let counter = 1\n while (usedRefs.has(ref)) ref = `${nameWithoutExt}_${counter++}`\n usedRefs.add(ref)\n const dims = getImageDimensions(img.data) || undefined\n binDataEntries.push({ ref, zipPath: `BinData/${ref}.${ext}`, data: img.data, dims })\n if (dims) imageDimsMap.set(ref, dims)\n imageMap.set(img.filename, ref)\n }\n }\n\n // data URI 이미지 처리\n const allBlocks = parseMarkdownToBlocks(markdown)\n for (const block of allBlocks) {\n if (block.type === \"image\" && block.src?.startsWith(\"data:\") && !imageMap.has(block.src)) {\n const commaIdx = block.src.indexOf(\",\")\n if (commaIdx === -1) continue\n const header = block.src.slice(0, commaIdx)\n const b64 = block.src.slice(commaIdx + 1)\n const mimeMatch = header.match(/data:([^;]+)/)\n const mimeType = mimeMatch?.[1] || \"image/png\"\n const format = mimeToFormat(mimeType)\n const ext = format.toLowerCase() === \"jpg\" ? \"jpg\" : format.toLowerCase()\n const data = Buffer.from(b64, \"base64\") as unknown as Uint8Array\n const ref = `datauri_${binDataEntries.length + 1}`\n const dims = getImageDimensions(data) || undefined\n imageMap.set(block.src, ref)\n binDataEntries.push({ ref, zipPath: `BinData/${ref}.${ext}`, data, dims })\n if (dims) imageDimsMap.set(ref, dims)\n }\n }\n\n const sectionXml = generateSectionXml(\n allBlocks,\n styleMap || undefined,\n imageMap.size > 0 ? imageMap : undefined,\n imageDimsMap.size > 0 ? imageDimsMap : undefined,\n secPrXml,\n colPrXml,\n masterpages.length,\n )\n\n // content.hpf manifest에 이미지 항목 동적 추가\n // id = binaryItemIDRef 값, href = ZIP 내 경로\n const formatToMediaType = (zipPath: string): string => {\n const ext = zipPath.split(\".\").pop()?.toLowerCase() || \"\"\n if (ext === \"png\") return \"image/png\"\n if (ext === \"gif\") return \"image/gif\"\n if (ext === \"bmp\") return \"image/bmp\"\n return \"image/jpg\" // jpg/jpeg 모두 image/jpg (원본 HWPX 형식)\n }\n // content.hpf 동적 생성: 이미지 + 마스터페이지 항목 주입\n const imageItems = binDataEntries\n .map(e => ` <opf:item id=\"${e.ref}\" href=\"${e.zipPath}\" media-type=\"${formatToMediaType(e.zipPath)}\" isEmbeded=\"1\"/>`)\n .join(\"\\n\")\n const masterpageItems = masterpages\n .map(mp => {\n const id = mp.filename.replace(\"Contents/\", \"\").replace(\".xml\", \"\")\n return ` <opf:item id=\"${id}\" href=\"${mp.filename}\" media-type=\"application/xml\"/>`\n })\n .join(\"\\n\")\n const extraItems = [imageItems, masterpageItems].filter(Boolean).join(\"\\n\")\n const contentHpf = CONTENT_HPF.replace(\n ` <opf:item id=\"header\"`,\n extraItems ? `${extraItems}\\n <opf:item id=\"header\"` : ` <opf:item id=\"header\"`,\n )\n\n const zip = new JSZip()\n\n zip.file(\"mimetype\", \"application/hwp+zip\", { compression: \"STORE\" })\n zip.file(\"META-INF/container.xml\", CONTAINER_XML)\n zip.file(\"META-INF/container.rdf\", CONTAINER_RDF)\n zip.file(\"META-INF/manifest.xml\", MANIFEST_XML)\n zip.file(\"version.xml\", VERSION_XML)\n zip.file(\"settings.xml\", SETTINGS_XML)\n zip.file(\"Preview/PrvText.txt\", \"\")\n zip.file(\"Contents/content.hpf\", contentHpf)\n zip.file(\"Contents/header.xml\", headerXml)\n zip.file(\"Contents/section0.xml\", sectionXml)\n\n // 마스터페이지 파일 추가\n for (const mp of masterpages) {\n zip.file(mp.filename, mp.content)\n }\n\n // 중복 제거된 이미지 + data URI 이미지를 BinData/ 폴더에 추가\n for (const entry of binDataEntries) {\n if (entry.data) {\n zip.file(entry.zipPath, entry.data)\n }\n }\n\n return await zip.generateAsync({ type: \"arraybuffer\" })\n}\n","// 자동 생성 — hwpxskill 베이스 템플릿 임베드\n// generator.ts 에서 import 해서 사용\n\nexport const HEADER_XML = `<?xml version='1.0' encoding='UTF-8'?>\n<hh:head xmlns:ha=\"http://www.hancom.co.kr/hwpml/2011/app\" xmlns:hp=\"http://www.hancom.co.kr/hwpml/2011/paragraph\" xmlns:hp10=\"http://www.hancom.co.kr/hwpml/2016/paragraph\" xmlns:hs=\"http://www.hancom.co.kr/hwpml/2011/section\" xmlns:hc=\"http://www.hancom.co.kr/hwpml/2011/core\" xmlns:hh=\"http://www.hancom.co.kr/hwpml/2011/head\" xmlns:hhs=\"http://www.hancom.co.kr/hwpml/2011/history\" xmlns:hm=\"http://www.hancom.co.kr/hwpml/2011/master-page\" xmlns:hpf=\"http://www.hancom.co.kr/schema/2011/hpf\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:opf=\"http://www.idpf.org/2007/opf/\" xmlns:ooxmlchart=\"http://www.hancom.co.kr/hwpml/2016/ooxmlchart\" xmlns:hwpunitchar=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\" xmlns:epub=\"http://www.idpf.org/2007/ops\" xmlns:config=\"urn:oasis:names:tc:opendocument:xmlns:config:1.0\" version=\"1.5\" secCnt=\"1\">\n <hh:beginNum page=\"1\" footnote=\"1\" endnote=\"1\" pic=\"1\" tbl=\"1\" equation=\"1\"/>\n <hh:refList>\n <hh:fontfaces itemCnt=\"7\">\n <hh:fontface lang=\"HANGUL\" fontCnt=\"2\">\n <hh:font id=\"0\" face=\"함초롬돋움\" type=\"TTF\" isEmbedded=\"0\">\n <hh:typeInfo familyType=\"FCAT_GOTHIC\" weight=\"6\" proportion=\"4\" contrast=\"0\" strokeVariation=\"1\" armStyle=\"1\" letterform=\"1\" midline=\"1\" xHeight=\"1\"/>\n </hh:font>\n <hh:font id=\"1\" face=\"함초롬바탕\" type=\"TTF\" isEmbedded=\"0\">\n <hh:typeInfo familyType=\"FCAT_GOTHIC\" weight=\"6\" proportion=\"4\" contrast=\"0\" strokeVariation=\"1\" armStyle=\"1\" letterform=\"1\" midline=\"1\" xHeight=\"1\"/>\n </hh:font>\n </hh:fontface>\n <hh:fontface lang=\"LATIN\" fontCnt=\"2\">\n <hh:font id=\"0\" face=\"함초롬돋움\" type=\"TTF\" isEmbedded=\"0\">\n <hh:typeInfo familyType=\"FCAT_GOTHIC\" weight=\"6\" proportion=\"4\" contrast=\"0\" strokeVariation=\"1\" armStyle=\"1\" letterform=\"1\" midline=\"1\" xHeight=\"1\"/>\n </hh:font>\n <hh:font id=\"1\" face=\"함초롬바탕\" type=\"TTF\" isEmbedded=\"0\">\n <hh:typeInfo familyType=\"FCAT_GOTHIC\" weight=\"6\" proportion=\"4\" contrast=\"0\" strokeVariation=\"1\" armStyle=\"1\" letterform=\"1\" midline=\"1\" xHeight=\"1\"/>\n </hh:font>\n </hh:fontface>\n <hh:fontface lang=\"HANJA\" fontCnt=\"2\">\n <hh:font id=\"0\" face=\"함초롬돋움\" type=\"TTF\" isEmbedded=\"0\">\n <hh:typeInfo familyType=\"FCAT_GOTHIC\" weight=\"6\" proportion=\"4\" contrast=\"0\" strokeVariation=\"1\" armStyle=\"1\" letterform=\"1\" midline=\"1\" xHeight=\"1\"/>\n </hh:font>\n <hh:font id=\"1\" face=\"함초롬바탕\" type=\"TTF\" isEmbedded=\"0\">\n <hh:typeInfo familyType=\"FCAT_GOTHIC\" weight=\"6\" proportion=\"4\" contrast=\"0\" strokeVariation=\"1\" armStyle=\"1\" letterform=\"1\" midline=\"1\" xHeight=\"1\"/>\n </hh:font>\n </hh:fontface>\n <hh:fontface lang=\"JAPANESE\" fontCnt=\"2\">\n <hh:font id=\"0\" face=\"함초롬돋움\" type=\"TTF\" isEmbedded=\"0\">\n <hh:typeInfo familyType=\"FCAT_GOTHIC\" weight=\"6\" proportion=\"4\" contrast=\"0\" strokeVariation=\"1\" armStyle=\"1\" letterform=\"1\" midline=\"1\" xHeight=\"1\"/>\n </hh:font>\n <hh:font id=\"1\" face=\"함초롬바탕\" type=\"TTF\" isEmbedded=\"0\">\n <hh:typeInfo familyType=\"FCAT_GOTHIC\" weight=\"6\" proportion=\"4\" contrast=\"0\" strokeVariation=\"1\" armStyle=\"1\" letterform=\"1\" midline=\"1\" xHeight=\"1\"/>\n </hh:font>\n </hh:fontface>\n <hh:fontface lang=\"OTHER\" fontCnt=\"2\">\n <hh:font id=\"0\" face=\"함초롬돋움\" type=\"TTF\" isEmbedded=\"0\">\n <hh:typeInfo familyType=\"FCAT_GOTHIC\" weight=\"6\" proportion=\"4\" contrast=\"0\" strokeVariation=\"1\" armStyle=\"1\" letterform=\"1\" midline=\"1\" xHeight=\"1\"/>\n </hh:font>\n <hh:font id=\"1\" face=\"함초롬바탕\" type=\"TTF\" isEmbedded=\"0\">\n <hh:typeInfo familyType=\"FCAT_GOTHIC\" weight=\"6\" proportion=\"4\" contrast=\"0\" strokeVariation=\"1\" armStyle=\"1\" letterform=\"1\" midline=\"1\" xHeight=\"1\"/>\n </hh:font>\n </hh:fontface>\n <hh:fontface lang=\"SYMBOL\" fontCnt=\"2\">\n <hh:font id=\"0\" face=\"함초롬돋움\" type=\"TTF\" isEmbedded=\"0\">\n <hh:typeInfo familyType=\"FCAT_GOTHIC\" weight=\"6\" proportion=\"4\" contrast=\"0\" strokeVariation=\"1\" armStyle=\"1\" letterform=\"1\" midline=\"1\" xHeight=\"1\"/>\n </hh:font>\n <hh:font id=\"1\" face=\"함초롬바탕\" type=\"TTF\" isEmbedded=\"0\">\n <hh:typeInfo familyType=\"FCAT_GOTHIC\" weight=\"6\" proportion=\"4\" contrast=\"0\" strokeVariation=\"1\" armStyle=\"1\" letterform=\"1\" midline=\"1\" xHeight=\"1\"/>\n </hh:font>\n </hh:fontface>\n <hh:fontface lang=\"USER\" fontCnt=\"2\">\n <hh:font id=\"0\" face=\"함초롬돋움\" type=\"TTF\" isEmbedded=\"0\">\n <hh:typeInfo familyType=\"FCAT_GOTHIC\" weight=\"6\" proportion=\"4\" contrast=\"0\" strokeVariation=\"1\" armStyle=\"1\" letterform=\"1\" midline=\"1\" xHeight=\"1\"/>\n </hh:font>\n <hh:font id=\"1\" face=\"함초롬바탕\" type=\"TTF\" isEmbedded=\"0\">\n <hh:typeInfo familyType=\"FCAT_GOTHIC\" weight=\"6\" proportion=\"4\" contrast=\"0\" strokeVariation=\"1\" armStyle=\"1\" letterform=\"1\" midline=\"1\" xHeight=\"1\"/>\n </hh:font>\n </hh:fontface>\n </hh:fontfaces>\n <hh:borderFills itemCnt=\"5\">\n <hh:borderFill id=\"1\" 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 <hh:leftBorder type=\"NONE\" width=\"0.1 mm\" color=\"#000000\"/>\n <hh:rightBorder type=\"NONE\" width=\"0.1 mm\" color=\"#000000\"/>\n <hh:topBorder type=\"NONE\" width=\"0.1 mm\" color=\"#000000\"/>\n <hh:bottomBorder type=\"NONE\" width=\"0.1 mm\" color=\"#000000\"/>\n <hh:diagonal type=\"SOLID\" width=\"0.1 mm\" color=\"#000000\"/>\n </hh:borderFill>\n <hh:borderFill id=\"2\" 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 <hh:leftBorder type=\"NONE\" width=\"0.1 mm\" color=\"#000000\"/>\n <hh:rightBorder type=\"NONE\" width=\"0.1 mm\" color=\"#000000\"/>\n <hh:topBorder type=\"NONE\" width=\"0.1 mm\" color=\"#000000\"/>\n <hh:bottomBorder type=\"NONE\" width=\"0.1 mm\" color=\"#000000\"/>\n <hh:diagonal type=\"SOLID\" width=\"0.1 mm\" color=\"#000000\"/>\n <hc:fillBrush>\n <hc:winBrush faceColor=\"none\" hatchColor=\"#999999\" alpha=\"0\"/>\n </hc:fillBrush>\n </hh:borderFill>\n <hh:borderFill id=\"3\" 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 <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=\"SOLID\" width=\"0.1 mm\" color=\"#000000\"/>\n </hh:borderFill>\n <hh:borderFill id=\"4\" 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 <hh:leftBorder type=\"SOLID\" width=\"0.5 mm\" color=\"#AAAAAA\"/>\n <hh:rightBorder type=\"NONE\" width=\"0.1 mm\" color=\"#000000\"/>\n <hh:topBorder type=\"NONE\" width=\"0.1 mm\" color=\"#000000\"/>\n <hh:bottomBorder type=\"NONE\" width=\"0.1 mm\" color=\"#000000\"/>\n <hh:diagonal type=\"SOLID\" width=\"0.1 mm\" color=\"#000000\"/>\n </hh:borderFill>\n <hh:borderFill id=\"5\" 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 <hh:leftBorder type=\"NONE\" width=\"0.1 mm\" color=\"#000000\"/>\n <hh:rightBorder type=\"NONE\" width=\"0.1 mm\" color=\"#000000\"/>\n <hh:topBorder type=\"NONE\" width=\"0.1 mm\" color=\"#000000\"/>\n <hh:bottomBorder type=\"SOLID\" width=\"0.4 mm\" color=\"#888888\"/>\n <hh:diagonal type=\"SOLID\" width=\"0.1 mm\" color=\"#000000\"/>\n </hh:borderFill>\n </hh:borderFills>\n <hh:charProperties itemCnt=\"16\">\n <hh:charPr id=\"0\" height=\"1000\" textColor=\"#000000\" shadeColor=\"none\" useFontSpace=\"0\" useKerning=\"0\" symMark=\"NONE\" borderFillIDRef=\"2\">\n <hh:fontRef hangul=\"1\" latin=\"1\" hanja=\"1\" japanese=\"1\" other=\"1\" symbol=\"1\" user=\"1\"/>\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\"/>\n <hh:underline type=\"NONE\" shape=\"SOLID\" color=\"#000000\"/>\n <hh:strikeout shape=\"NONE\" color=\"#000000\"/>\n <hh:outline type=\"NONE\"/>\n <hh:shadow type=\"NONE\" color=\"#C0C0C0\" offsetX=\"10\" offsetY=\"10\"/>\n </hh:charPr>\n <hh:charPr id=\"1\" height=\"1000\" textColor=\"#000000\" shadeColor=\"none\" useFontSpace=\"0\" useKerning=\"0\" symMark=\"NONE\" borderFillIDRef=\"2\">\n <hh:fontRef hangul=\"0\" latin=\"0\" hanja=\"0\" japanese=\"0\" other=\"0\" symbol=\"0\" user=\"0\"/>\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\"/>\n <hh:underline type=\"NONE\" shape=\"SOLID\" color=\"#000000\"/>\n <hh:strikeout shape=\"NONE\" color=\"#000000\"/>\n <hh:outline type=\"NONE\"/>\n <hh:shadow type=\"NONE\" color=\"#C0C0C0\" offsetX=\"10\" offsetY=\"10\"/>\n </hh:charPr>\n <hh:charPr id=\"2\" height=\"900\" textColor=\"#000000\" shadeColor=\"none\" useFontSpace=\"0\" useKerning=\"0\" symMark=\"NONE\" borderFillIDRef=\"2\">\n <hh:fontRef hangul=\"0\" latin=\"0\" hanja=\"0\" japanese=\"0\" other=\"0\" symbol=\"0\" user=\"0\"/>\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\"/>\n <hh:underline type=\"NONE\" shape=\"SOLID\" color=\"#000000\"/>\n <hh:strikeout shape=\"NONE\" color=\"#000000\"/>\n <hh:outline type=\"NONE\"/>\n <hh:shadow type=\"NONE\" color=\"#C0C0C0\" offsetX=\"10\" offsetY=\"10\"/>\n </hh:charPr>\n <hh:charPr id=\"3\" height=\"900\" textColor=\"#000000\" shadeColor=\"none\" useFontSpace=\"0\" useKerning=\"0\" symMark=\"NONE\" borderFillIDRef=\"2\">\n <hh:fontRef hangul=\"1\" latin=\"1\" hanja=\"1\" japanese=\"1\" other=\"1\" symbol=\"1\" user=\"1\"/>\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\"/>\n <hh:underline type=\"NONE\" shape=\"SOLID\" color=\"#000000\"/>\n <hh:strikeout shape=\"NONE\" color=\"#000000\"/>\n <hh:outline type=\"NONE\"/>\n <hh:shadow type=\"NONE\" color=\"#C0C0C0\" offsetX=\"10\" offsetY=\"10\"/>\n </hh:charPr>\n <hh:charPr id=\"4\" height=\"900\" textColor=\"#000000\" shadeColor=\"none\" useFontSpace=\"0\" useKerning=\"0\" symMark=\"NONE\" borderFillIDRef=\"2\">\n <hh:fontRef hangul=\"0\" latin=\"0\" hanja=\"0\" japanese=\"0\" other=\"0\" symbol=\"0\" user=\"0\"/>\n <hh:ratio hangul=\"100\" latin=\"100\" hanja=\"100\" japanese=\"100\" other=\"100\" symbol=\"100\" user=\"100\"/>\n <hh:spacing hangul=\"-5\" latin=\"-5\" hanja=\"-5\" japanese=\"-5\" other=\"-5\" symbol=\"-5\" user=\"-5\"/>\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\"/>\n <hh:underline type=\"NONE\" shape=\"SOLID\" color=\"#000000\"/>\n <hh:strikeout shape=\"NONE\" color=\"#000000\"/>\n <hh:outline type=\"NONE\"/>\n <hh:shadow type=\"NONE\" color=\"#C0C0C0\" offsetX=\"10\" offsetY=\"10\"/>\n </hh:charPr>\n <hh:charPr id=\"5\" height=\"1600\" textColor=\"#2E74B5\" shadeColor=\"none\" useFontSpace=\"0\" useKerning=\"0\" symMark=\"NONE\" borderFillIDRef=\"2\">\n <hh:fontRef hangul=\"0\" latin=\"0\" hanja=\"0\" japanese=\"0\" other=\"0\" symbol=\"0\" user=\"0\"/>\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\"/>\n <hh:underline type=\"NONE\" shape=\"SOLID\" color=\"#000000\"/>\n <hh:strikeout shape=\"NONE\" color=\"#000000\"/>\n <hh:outline type=\"NONE\"/>\n <hh:shadow type=\"NONE\" color=\"#C0C0C0\" offsetX=\"10\" offsetY=\"10\"/>\n </hh:charPr>\n <hh:charPr id=\"6\" height=\"1100\" textColor=\"#000000\" shadeColor=\"none\" useFontSpace=\"0\" useKerning=\"0\" symMark=\"NONE\" borderFillIDRef=\"2\">\n <hh:fontRef hangul=\"0\" latin=\"0\" hanja=\"0\" japanese=\"0\" other=\"0\" symbol=\"0\" user=\"0\"/>\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\"/>\n <hh:underline type=\"NONE\" shape=\"SOLID\" color=\"#000000\"/>\n <hh:strikeout shape=\"NONE\" color=\"#000000\"/>\n <hh:outline type=\"NONE\"/>\n <hh:shadow type=\"NONE\" color=\"#C0C0C0\" offsetX=\"10\" offsetY=\"10\"/>\n </hh:charPr>\n\n <hh:charPr id=\"7\" height=\"2000\" textColor=\"#000000\" shadeColor=\"none\" useFontSpace=\"0\" useKerning=\"0\" symMark=\"NONE\" borderFillIDRef=\"2\">\n <hh:fontRef hangul=\"1\" latin=\"1\" hanja=\"1\" japanese=\"1\" other=\"1\" symbol=\"1\" user=\"1\"/>\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\"/>\n <hh:bold/>\n <hh:underline type=\"NONE\" shape=\"SOLID\" color=\"#000000\"/>\n <hh:strikeout shape=\"NONE\" color=\"#000000\"/>\n <hh:outline type=\"NONE\"/>\n <hh:shadow type=\"NONE\" color=\"#C0C0C0\" offsetX=\"10\" offsetY=\"10\"/>\n </hh:charPr>\n <hh:charPr id=\"8\" height=\"1400\" textColor=\"#000000\" shadeColor=\"none\" useFontSpace=\"0\" useKerning=\"0\" symMark=\"NONE\" borderFillIDRef=\"2\">\n <hh:fontRef hangul=\"1\" latin=\"1\" hanja=\"1\" japanese=\"1\" other=\"1\" symbol=\"1\" user=\"1\"/>\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\"/>\n <hh:bold/>\n <hh:underline type=\"NONE\" shape=\"SOLID\" color=\"#000000\"/>\n <hh:strikeout shape=\"NONE\" color=\"#000000\"/>\n <hh:outline type=\"NONE\"/>\n <hh:shadow type=\"NONE\" color=\"#C0C0C0\" offsetX=\"10\" offsetY=\"10\"/>\n </hh:charPr>\n <hh:charPr id=\"9\" height=\"1200\" textColor=\"#000000\" shadeColor=\"none\" useFontSpace=\"0\" useKerning=\"0\" symMark=\"NONE\" borderFillIDRef=\"2\">\n <hh:fontRef hangul=\"1\" latin=\"1\" hanja=\"1\" japanese=\"1\" other=\"1\" symbol=\"1\" user=\"1\"/>\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\"/>\n <hh:bold/>\n <hh:underline type=\"NONE\" shape=\"SOLID\" color=\"#000000\"/>\n <hh:strikeout shape=\"NONE\" color=\"#000000\"/>\n <hh:outline type=\"NONE\"/>\n <hh:shadow type=\"NONE\" color=\"#C0C0C0\" offsetX=\"10\" offsetY=\"10\"/>\n </hh:charPr>\n <hh:charPr id=\"10\" height=\"1100\" textColor=\"#000000\" shadeColor=\"none\" useFontSpace=\"0\" useKerning=\"0\" symMark=\"NONE\" borderFillIDRef=\"2\">\n <hh:fontRef hangul=\"1\" latin=\"1\" hanja=\"1\" japanese=\"1\" other=\"1\" symbol=\"1\" user=\"1\"/>\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\"/>\n <hh:bold/>\n <hh:underline type=\"NONE\" shape=\"SOLID\" color=\"#000000\"/>\n <hh:strikeout shape=\"NONE\" color=\"#000000\"/>\n <hh:outline type=\"NONE\"/>\n <hh:shadow type=\"NONE\" color=\"#C0C0C0\" offsetX=\"10\" offsetY=\"10\"/>\n </hh:charPr>\n <hh:charPr id=\"11\" height=\"1000\" textColor=\"#000000\" shadeColor=\"none\" useFontSpace=\"0\" useKerning=\"0\" symMark=\"NONE\" borderFillIDRef=\"2\">\n <hh:fontRef hangul=\"1\" latin=\"1\" hanja=\"1\" japanese=\"1\" other=\"1\" symbol=\"1\" user=\"1\"/>\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\"/>\n <hh:bold/>\n <hh:underline type=\"NONE\" shape=\"SOLID\" color=\"#000000\"/>\n <hh:strikeout shape=\"NONE\" color=\"#000000\"/>\n <hh:outline type=\"NONE\"/>\n <hh:shadow type=\"NONE\" color=\"#C0C0C0\" offsetX=\"10\" offsetY=\"10\"/>\n </hh:charPr>\n <hh:charPr id=\"12\" height=\"1000\" textColor=\"#000000\" shadeColor=\"none\" useFontSpace=\"0\" useKerning=\"0\" symMark=\"NONE\" borderFillIDRef=\"2\">\n <hh:fontRef hangul=\"0\" latin=\"0\" hanja=\"0\" japanese=\"0\" other=\"0\" symbol=\"0\" user=\"0\"/>\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\"/>\n <hh:italic/>\n <hh:underline type=\"NONE\" shape=\"SOLID\" color=\"#000000\"/>\n <hh:strikeout shape=\"NONE\" color=\"#000000\"/>\n <hh:outline type=\"NONE\"/>\n <hh:shadow type=\"NONE\" color=\"#C0C0C0\" offsetX=\"10\" offsetY=\"10\"/>\n </hh:charPr>\n <hh:charPr id=\"13\" height=\"1000\" textColor=\"#000000\" shadeColor=\"none\" useFontSpace=\"0\" useKerning=\"0\" symMark=\"NONE\" borderFillIDRef=\"2\">\n <hh:fontRef hangul=\"1\" latin=\"1\" hanja=\"1\" japanese=\"1\" other=\"1\" symbol=\"1\" user=\"1\"/>\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\"/>\n <hh:bold/>\n <hh:italic/>\n <hh:underline type=\"NONE\" shape=\"SOLID\" color=\"#000000\"/>\n <hh:strikeout shape=\"NONE\" color=\"#000000\"/>\n <hh:outline type=\"NONE\"/>\n <hh:shadow type=\"NONE\" color=\"#C0C0C0\" offsetX=\"10\" offsetY=\"10\"/>\n </hh:charPr>\n <hh:charPr id=\"14\" height=\"900\" textColor=\"#333333\" shadeColor=\"#F0F0F0\" useFontSpace=\"0\" useKerning=\"0\" symMark=\"NONE\" borderFillIDRef=\"2\">\n <hh:fontRef hangul=\"1\" latin=\"1\" hanja=\"1\" japanese=\"1\" other=\"1\" symbol=\"1\" user=\"1\"/>\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\"/>\n <hh:underline type=\"NONE\" shape=\"SOLID\" color=\"#000000\"/>\n <hh:strikeout shape=\"NONE\" color=\"#000000\"/>\n <hh:outline type=\"NONE\"/>\n <hh:shadow type=\"NONE\" color=\"#C0C0C0\" offsetX=\"10\" offsetY=\"10\"/>\n </hh:charPr>\n <hh:charPr id=\"15\" height=\"1000\" textColor=\"#000000\" shadeColor=\"none\" useFontSpace=\"0\" useKerning=\"0\" symMark=\"NONE\" borderFillIDRef=\"2\">\n <hh:fontRef hangul=\"1\" latin=\"1\" hanja=\"1\" japanese=\"1\" other=\"1\" symbol=\"1\" user=\"1\"/>\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\"/>\n <hh:underline type=\"NONE\" shape=\"SOLID\" color=\"#000000\"/>\n <hh:strikeout shape=\"SINGLE\" color=\"#000000\"/>\n <hh:outline type=\"NONE\"/>\n <hh:shadow type=\"NONE\" color=\"#C0C0C0\" offsetX=\"10\" offsetY=\"10\"/>\n </hh:charPr>\n </hh:charProperties>\n <hh:tabProperties itemCnt=\"3\">\n <hh:tabPr id=\"0\" autoTabLeft=\"0\" autoTabRight=\"0\"/>\n <hh:tabPr id=\"1\" autoTabLeft=\"1\" autoTabRight=\"0\"/>\n <hh:tabPr id=\"2\" autoTabLeft=\"0\" autoTabRight=\"1\"/>\n </hh:tabProperties>\n <hh:numberings itemCnt=\"1\">\n <hh:numbering id=\"1\" start=\"0\">\n <hh:paraHead start=\"1\" level=\"1\" align=\"LEFT\" useInstWidth=\"1\" autoIndent=\"1\" widthAdjust=\"0\" textOffsetType=\"PERCENT\" textOffset=\"50\" numFormat=\"DIGIT\" charPrIDRef=\"4294967295\" checkable=\"0\">^1.</hh:paraHead>\n <hh:paraHead start=\"1\" level=\"2\" align=\"LEFT\" useInstWidth=\"1\" autoIndent=\"1\" widthAdjust=\"0\" textOffsetType=\"PERCENT\" textOffset=\"50\" numFormat=\"HANGUL_SYLLABLE\" charPrIDRef=\"4294967295\" checkable=\"0\">^2.</hh:paraHead>\n <hh:paraHead start=\"1\" level=\"3\" align=\"LEFT\" useInstWidth=\"1\" autoIndent=\"1\" widthAdjust=\"0\" textOffsetType=\"PERCENT\" textOffset=\"50\" numFormat=\"DIGIT\" charPrIDRef=\"4294967295\" checkable=\"0\">^3)</hh:paraHead>\n <hh:paraHead start=\"1\" level=\"4\" align=\"LEFT\" useInstWidth=\"1\" autoIndent=\"1\" widthAdjust=\"0\" textOffsetType=\"PERCENT\" textOffset=\"50\" numFormat=\"HANGUL_SYLLABLE\" charPrIDRef=\"4294967295\" checkable=\"0\">^4)</hh:paraHead>\n <hh:paraHead start=\"1\" level=\"5\" align=\"LEFT\" useInstWidth=\"1\" autoIndent=\"1\" widthAdjust=\"0\" textOffsetType=\"PERCENT\" textOffset=\"50\" numFormat=\"DIGIT\" charPrIDRef=\"4294967295\" checkable=\"0\">(^5)</hh:paraHead>\n <hh:paraHead start=\"1\" level=\"6\" align=\"LEFT\" useInstWidth=\"1\" autoIndent=\"1\" widthAdjust=\"0\" textOffsetType=\"PERCENT\" textOffset=\"50\" numFormat=\"HANGUL_SYLLABLE\" charPrIDRef=\"4294967295\" checkable=\"0\">(^6)</hh:paraHead>\n <hh:paraHead start=\"1\" level=\"7\" align=\"LEFT\" useInstWidth=\"1\" autoIndent=\"1\" widthAdjust=\"0\" textOffsetType=\"PERCENT\" textOffset=\"50\" numFormat=\"CIRCLED_DIGIT\" charPrIDRef=\"4294967295\" checkable=\"1\">^7</hh:paraHead>\n <hh:paraHead start=\"1\" level=\"8\" align=\"LEFT\" useInstWidth=\"1\" autoIndent=\"1\" widthAdjust=\"0\" textOffsetType=\"PERCENT\" textOffset=\"50\" numFormat=\"CIRCLED_HANGUL_SYLLABLE\" charPrIDRef=\"4294967295\" checkable=\"1\">^8</hh:paraHead>\n <hh:paraHead start=\"1\" level=\"9\" align=\"LEFT\" useInstWidth=\"1\" autoIndent=\"1\" widthAdjust=\"0\" textOffsetType=\"PERCENT\" textOffset=\"50\" numFormat=\"HANGUL_JAMO\" charPrIDRef=\"4294967295\" checkable=\"0\"/>\n <hh:paraHead start=\"1\" level=\"10\" align=\"LEFT\" useInstWidth=\"1\" autoIndent=\"1\" widthAdjust=\"0\" textOffsetType=\"PERCENT\" textOffset=\"50\" numFormat=\"ROMAN_SMALL\" charPrIDRef=\"4294967295\" checkable=\"1\"/>\n </hh:numbering>\n </hh:numberings>\n <hh:paraProperties itemCnt=\"22\">\n <hh:paraPr id=\"0\" tabPrIDRef=\"0\" condense=\"0\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"JUSTIFY\" vertical=\"BASELINE\"/>\n <hh:heading type=\"NONE\" idRef=\"0\" level=\"0\"/>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"BREAK_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"0\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"0\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"1\" tabPrIDRef=\"0\" condense=\"0\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"JUSTIFY\" vertical=\"BASELINE\"/>\n <hh:heading type=\"NONE\" idRef=\"0\" level=\"0\"/>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"KEEP_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"1500\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"3000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"2\" tabPrIDRef=\"1\" condense=\"20\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"JUSTIFY\" vertical=\"BASELINE\"/>\n <hh:heading type=\"OUTLINE\" idRef=\"0\" level=\"0\"/>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"KEEP_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"1000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"2000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"3\" tabPrIDRef=\"1\" condense=\"20\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"JUSTIFY\" vertical=\"BASELINE\"/>\n <hh:heading type=\"OUTLINE\" idRef=\"0\" level=\"1\"/>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"KEEP_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"2000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"4000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"4\" tabPrIDRef=\"1\" condense=\"20\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"JUSTIFY\" vertical=\"BASELINE\"/>\n <hh:heading type=\"OUTLINE\" idRef=\"0\" level=\"2\"/>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"KEEP_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"3000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"6000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"5\" tabPrIDRef=\"1\" condense=\"20\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"JUSTIFY\" vertical=\"BASELINE\"/>\n <hh:heading type=\"OUTLINE\" idRef=\"0\" level=\"3\"/>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"KEEP_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"4000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"8000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"6\" tabPrIDRef=\"1\" condense=\"20\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"JUSTIFY\" vertical=\"BASELINE\"/>\n <hh:heading type=\"OUTLINE\" idRef=\"0\" level=\"4\"/>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"KEEP_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"5000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"10000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"7\" tabPrIDRef=\"1\" condense=\"20\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"JUSTIFY\" vertical=\"BASELINE\"/>\n <hh:heading type=\"OUTLINE\" idRef=\"0\" level=\"5\"/>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"KEEP_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"6000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"12000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"8\" tabPrIDRef=\"1\" condense=\"20\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"JUSTIFY\" vertical=\"BASELINE\"/>\n <hh:heading type=\"OUTLINE\" idRef=\"0\" level=\"6\"/>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"KEEP_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"7000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"14000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"9\" tabPrIDRef=\"0\" condense=\"0\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"JUSTIFY\" vertical=\"BASELINE\"/>\n <hh:heading type=\"NONE\" idRef=\"0\" level=\"0\"/>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"BREAK_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"0\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"150\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"0\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"150\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"10\" tabPrIDRef=\"0\" condense=\"0\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"JUSTIFY\" vertical=\"BASELINE\"/>\n <hh:heading type=\"NONE\" idRef=\"0\" level=\"0\"/>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"KEEP_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"-1310\" unit=\"HWPUNIT\"/>\n <hc:left value=\"0\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"130\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"-2620\" unit=\"HWPUNIT\"/>\n <hc:left value=\"0\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"130\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"11\" tabPrIDRef=\"0\" condense=\"0\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"LEFT\" vertical=\"BASELINE\"/>\n <hh:heading type=\"NONE\" idRef=\"0\" level=\"0\"/>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"BREAK_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"0\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"130\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"0\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"130\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"12\" tabPrIDRef=\"1\" condense=\"20\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"LEFT\" vertical=\"BASELINE\"/>\n <hh:heading type=\"NONE\" idRef=\"0\" level=\"0\"/>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"BREAK_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"0\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"1200\" unit=\"HWPUNIT\"/>\n <hc:next value=\"300\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"0\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"2400\" unit=\"HWPUNIT\"/>\n <hc:next value=\"600\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"13\" tabPrIDRef=\"2\" condense=\"0\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"LEFT\" vertical=\"BASELINE\"/>\n <hh:heading type=\"NONE\" idRef=\"0\" level=\"0\"/>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"BREAK_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"0\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"700\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"0\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"1400\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"14\" tabPrIDRef=\"2\" condense=\"0\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"LEFT\" vertical=\"BASELINE\"/>\n <hh:heading type=\"NONE\" idRef=\"0\" level=\"0\"/>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"BREAK_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"1100\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"700\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"2200\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"1400\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"15\" tabPrIDRef=\"2\" condense=\"0\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"LEFT\" vertical=\"BASELINE\"/>\n <hh:heading type=\"NONE\" idRef=\"0\" level=\"0\"/>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"BREAK_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"2200\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"700\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"4400\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"1400\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"16\" tabPrIDRef=\"1\" condense=\"0\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"JUSTIFY\" vertical=\"BASELINE\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/paragraph\">\n <hh:heading type=\"OUTLINE\" idRef=\"0\" level=\"8\"/>\n </hp:case>\n <hp:default>\n <hh:heading type=\"NONE\" idRef=\"0\" level=\"0\"/>\n </hp:default>\n </hp:switch>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"KEEP_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"9000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"18000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"17\" tabPrIDRef=\"1\" condense=\"0\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"JUSTIFY\" vertical=\"BASELINE\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/paragraph\">\n <hh:heading type=\"OUTLINE\" idRef=\"0\" level=\"9\"/>\n </hp:case>\n <hp:default>\n <hh:heading type=\"NONE\" idRef=\"0\" level=\"0\"/>\n </hp:default>\n </hp:switch>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"KEEP_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"10000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"20000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"18\" tabPrIDRef=\"1\" condense=\"0\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"JUSTIFY\" vertical=\"BASELINE\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/paragraph\">\n <hh:heading type=\"OUTLINE\" idRef=\"0\" level=\"7\"/>\n </hp:case>\n <hp:default>\n <hh:heading type=\"NONE\" idRef=\"0\" level=\"0\"/>\n </hp:default>\n </hp:switch>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"KEEP_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"8000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"16000\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"19\" tabPrIDRef=\"0\" condense=\"0\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"JUSTIFY\" vertical=\"BASELINE\"/>\n <hh:heading type=\"NONE\" idRef=\"0\" level=\"0\"/>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"KEEP_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"0\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"800\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"150\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"0\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"1600\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"150\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"2\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"20\" tabPrIDRef=\"0\" condense=\"0\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"JUSTIFY\" vertical=\"BASELINE\"/>\n <hh:heading type=\"NONE\" idRef=\"0\" level=\"0\"/>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"BREAK_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"4252\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"4252\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"4\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n <hh:paraPr id=\"21\" tabPrIDRef=\"0\" condense=\"0\" fontLineHeight=\"0\" snapToGrid=\"1\" suppressLineNumbers=\"0\" checked=\"0\" textDir=\"LTR\">\n <hh:align horizontal=\"JUSTIFY\" vertical=\"BASELINE\"/>\n <hh:heading type=\"NONE\" idRef=\"0\" level=\"0\"/>\n <hh:breakSetting breakLatinWord=\"KEEP_WORD\" breakNonLatinWord=\"BREAK_WORD\" widowOrphan=\"0\" keepWithNext=\"0\" keepLines=\"0\" pageBreakBefore=\"0\" lineWrap=\"BREAK\"/>\n <hh:autoSpacing eAsianEng=\"0\" eAsianNum=\"0\"/>\n <hp:switch>\n <hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\">\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"0\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:case>\n <hp:default>\n <hh:margin>\n <hc:intent value=\"0\" unit=\"HWPUNIT\"/>\n <hc:left value=\"0\" unit=\"HWPUNIT\"/>\n <hc:right value=\"0\" unit=\"HWPUNIT\"/>\n <hc:prev value=\"0\" unit=\"HWPUNIT\"/>\n <hc:next value=\"0\" unit=\"HWPUNIT\"/>\n </hh:margin>\n <hh:lineSpacing type=\"PERCENT\" value=\"160\" unit=\"HWPUNIT\"/>\n </hp:default>\n </hp:switch>\n <hh:border borderFillIDRef=\"5\" offsetLeft=\"0\" offsetRight=\"0\" offsetTop=\"0\" offsetBottom=\"0\" connect=\"0\" ignoreMargin=\"0\"/>\n </hh:paraPr>\n </hh:paraProperties>\n <hh:styles itemCnt=\"23\">\n <hh:style id=\"0\" type=\"PARA\" name=\"바탕글\" engName=\"Normal\" paraPrIDRef=\"0\" charPrIDRef=\"0\" nextStyleIDRef=\"0\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"1\" type=\"PARA\" name=\"본문\" engName=\"Body\" paraPrIDRef=\"1\" charPrIDRef=\"0\" nextStyleIDRef=\"1\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"2\" type=\"PARA\" name=\"개요 1\" engName=\"Outline 1\" paraPrIDRef=\"2\" charPrIDRef=\"0\" nextStyleIDRef=\"2\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"3\" type=\"PARA\" name=\"개요 2\" engName=\"Outline 2\" paraPrIDRef=\"3\" charPrIDRef=\"0\" nextStyleIDRef=\"3\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"4\" type=\"PARA\" name=\"개요 3\" engName=\"Outline 3\" paraPrIDRef=\"4\" charPrIDRef=\"0\" nextStyleIDRef=\"4\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"5\" type=\"PARA\" name=\"개요 4\" engName=\"Outline 4\" paraPrIDRef=\"5\" charPrIDRef=\"0\" nextStyleIDRef=\"5\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"6\" type=\"PARA\" name=\"개요 5\" engName=\"Outline 5\" paraPrIDRef=\"6\" charPrIDRef=\"0\" nextStyleIDRef=\"6\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"7\" type=\"PARA\" name=\"개요 6\" engName=\"Outline 6\" paraPrIDRef=\"7\" charPrIDRef=\"0\" nextStyleIDRef=\"7\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"8\" type=\"PARA\" name=\"개요 7\" engName=\"Outline 7\" paraPrIDRef=\"8\" charPrIDRef=\"0\" nextStyleIDRef=\"8\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"9\" type=\"PARA\" name=\"개요 8\" engName=\"Outline 8\" paraPrIDRef=\"18\" charPrIDRef=\"0\" nextStyleIDRef=\"9\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"10\" type=\"PARA\" name=\"개요 9\" engName=\"Outline 9\" paraPrIDRef=\"16\" charPrIDRef=\"0\" nextStyleIDRef=\"10\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"11\" type=\"PARA\" name=\"개요 10\" engName=\"Outline 10\" paraPrIDRef=\"17\" charPrIDRef=\"0\" nextStyleIDRef=\"11\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"12\" type=\"CHAR\" name=\"쪽 번호\" engName=\"Page Number\" paraPrIDRef=\"0\" charPrIDRef=\"1\" nextStyleIDRef=\"0\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"13\" type=\"CHAR\" name=\"줄 번호\" engName=\"Line Number\" paraPrIDRef=\"0\" charPrIDRef=\"0\" nextStyleIDRef=\"0\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"14\" type=\"PARA\" name=\"머리말\" engName=\"Header\" paraPrIDRef=\"9\" charPrIDRef=\"2\" nextStyleIDRef=\"14\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"15\" type=\"PARA\" name=\"각주\" engName=\"Footnote\" paraPrIDRef=\"10\" charPrIDRef=\"3\" nextStyleIDRef=\"15\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"16\" type=\"PARA\" name=\"미주\" engName=\"Endnote\" paraPrIDRef=\"10\" charPrIDRef=\"3\" nextStyleIDRef=\"16\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"17\" type=\"PARA\" name=\"메모\" engName=\"Memo\" paraPrIDRef=\"11\" charPrIDRef=\"4\" nextStyleIDRef=\"17\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"18\" type=\"PARA\" name=\"차례 제목\" engName=\"TOC Heading\" paraPrIDRef=\"12\" charPrIDRef=\"5\" nextStyleIDRef=\"18\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"19\" type=\"PARA\" name=\"차례 1\" engName=\"TOC 1\" paraPrIDRef=\"13\" charPrIDRef=\"6\" nextStyleIDRef=\"19\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"20\" type=\"PARA\" name=\"차례 2\" engName=\"TOC 2\" paraPrIDRef=\"14\" charPrIDRef=\"6\" nextStyleIDRef=\"20\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"21\" type=\"PARA\" name=\"차례 3\" engName=\"TOC 3\" paraPrIDRef=\"15\" charPrIDRef=\"6\" nextStyleIDRef=\"21\" langID=\"1042\" lockForm=\"0\"/>\n <hh:style id=\"22\" type=\"PARA\" name=\"캡션\" engName=\"Caption\" paraPrIDRef=\"19\" charPrIDRef=\"0\" nextStyleIDRef=\"22\" langID=\"1042\" lockForm=\"0\"/>\n </hh:styles>\n </hh:refList>\n <hh:compatibleDocument targetProgram=\"HWP201X\">\n <hh:layoutCompatibility/>\n </hh:compatibleDocument>\n <hh:docOption>\n <hh:linkinfo path=\"\" pageInherit=\"0\" footnoteInherit=\"0\"/>\n </hh:docOption>\n <hh:metaTag>{\"name\":\"\"}</hh:metaTag>\n <hh:trackchageConfig flags=\"56\"/>\n</hh:head>\n`\n\nexport const CONTENT_HPF = `<?xml version='1.0' encoding='UTF-8'?>\n<opf:package xmlns:ha=\"http://www.hancom.co.kr/hwpml/2011/app\" xmlns:hp=\"http://www.hancom.co.kr/hwpml/2011/paragraph\" xmlns:hp10=\"http://www.hancom.co.kr/hwpml/2016/paragraph\" xmlns:hs=\"http://www.hancom.co.kr/hwpml/2011/section\" xmlns:hc=\"http://www.hancom.co.kr/hwpml/2011/core\" xmlns:hh=\"http://www.hancom.co.kr/hwpml/2011/head\" xmlns:hhs=\"http://www.hancom.co.kr/hwpml/2011/history\" xmlns:hm=\"http://www.hancom.co.kr/hwpml/2011/master-page\" xmlns:hpf=\"http://www.hancom.co.kr/schema/2011/hpf\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:opf=\"http://www.idpf.org/2007/opf/\" xmlns:ooxmlchart=\"http://www.hancom.co.kr/hwpml/2016/ooxmlchart\" xmlns:hwpunitchar=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\" xmlns:epub=\"http://www.idpf.org/2007/ops\" xmlns:config=\"urn:oasis:names:tc:opendocument:xmlns:config:1.0\" version=\"\" unique-identifier=\"\" id=\"\">\n <opf:metadata>\n <opf:title/>\n <opf:language>ko</opf:language>\n <opf:meta name=\"creator\" content=\"text\"/>\n <opf:meta name=\"subject\" content=\"text\"/>\n <opf:meta name=\"description\" content=\"text\"/>\n <opf:meta name=\"lastsaveby\" content=\"text\"/>\n <opf:meta name=\"CreatedDate\" content=\"text\"/>\n <opf:meta name=\"ModifiedDate\" content=\"text\"/>\n <opf:meta name=\"date\" content=\"text\"/>\n <opf:meta name=\"keyword\" content=\"text\"/>\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\"/>\n <opf:item id=\"settings\" href=\"settings.xml\" media-type=\"application/xml\"/>\n </opf:manifest>\n <opf:spine>\n <opf:itemref idref=\"header\" linear=\"yes\"/>\n <opf:itemref idref=\"section0\" linear=\"yes\"/>\n </opf:spine>\n</opf:package>\n`\n\nexport const CONTAINER_XML = `<?xml version='1.0' encoding='UTF-8'?>\n<ocf:container xmlns:ocf=\"urn:oasis:names:tc:opendocument:xmlns:container\" xmlns:hpf=\"http://www.hancom.co.kr/schema/2011/hpf\">\n <ocf:rootfiles>\n <ocf:rootfile full-path=\"Contents/content.hpf\" media-type=\"application/hwpml-package+xml\"/>\n <ocf:rootfile full-path=\"Preview/PrvText.txt\" media-type=\"text/plain\"/>\n <ocf:rootfile full-path=\"META-INF/container.rdf\" media-type=\"application/rdf+xml\"/>\n </ocf:rootfiles>\n</ocf:container>\n`\n\nexport const CONTAINER_RDF = `<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?><rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"><rdf:Description rdf:about=\"\"><ns0:hasPart xmlns:ns0=\"http://www.hancom.co.kr/hwpml/2016/meta/pkg#\" rdf:resource=\"Contents/header.xml\"/></rdf:Description><rdf:Description rdf:about=\"Contents/header.xml\"><rdf:type rdf:resource=\"http://www.hancom.co.kr/hwpml/2016/meta/pkg#HeaderFile\"/></rdf:Description><rdf:Description rdf:about=\"\"><ns0:hasPart xmlns:ns0=\"http://www.hancom.co.kr/hwpml/2016/meta/pkg#\" rdf:resource=\"Contents/section0.xml\"/></rdf:Description><rdf:Description rdf:about=\"Contents/section0.xml\"><rdf:type rdf:resource=\"http://www.hancom.co.kr/hwpml/2016/meta/pkg#SectionFile\"/></rdf:Description><rdf:Description rdf:about=\"\"><rdf:type rdf:resource=\"http://www.hancom.co.kr/hwpml/2016/meta/pkg#Document\"/></rdf:Description></rdf:RDF>`\n\nexport const MANIFEST_XML = `<?xml version='1.0' encoding='UTF-8'?>\n<odf:manifest xmlns:odf=\"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0\"/>\n`\n\nexport const VERSION_XML = `<?xml version='1.0' encoding='UTF-8'?>\n<hv:HCFVersion xmlns:hv=\"http://www.hancom.co.kr/hwpml/2011/version\" tagetApplication=\"WORDPROCESSOR\" major=\"5\" minor=\"1\" micro=\"1\" buildNumber=\"0\" os=\"1\" xmlVersion=\"1.5\" application=\"Hancom Office Hangul\" appVersion=\"13, 0, 0, 1408 WIN32LEWindows_10\"/>\n`\n\nexport const SETTINGS_XML = `<?xml version='1.0' encoding='UTF-8'?>\n<ha:HWPApplicationSetting xmlns:ha=\"http://www.hancom.co.kr/hwpml/2011/app\" xmlns:config=\"urn:oasis:names:tc:opendocument:xmlns:config:1.0\">\n <ha:CaretPosition listIDRef=\"0\" paraIDRef=\"0\" pos=\"16\"/>\n</ha:HWPApplicationSetting>\n`\n\n","/**\n * Template Analyzer — HWPX 템플릿에서 스타일 정보 추출\n * 사용자가 제공한 template.hwpx에서 charPr, paraPr, borderFill 등 추출\n */\n\nimport JSZip from \"jszip\"\nimport { DOMParser } from \"@xmldom/xmldom\"\n\nexport interface CharacterProperty {\n id: string\n height?: number // 글자 크기 (HWPUNIT, 1000 = 10pt)\n fontName?: string // 폰트명\n bold?: boolean\n italic?: boolean\n underline?: boolean\n strikethrough?: boolean\n color?: string // 색상 (#RRGGBB)\n}\n\nexport interface ParagraphProperty {\n id: string\n align?: \"LEFT\" | \"RIGHT\" | \"CENTER\" | \"JUSTIFY\"\n indent?: {\n before?: number // 왼쪽 들여쓰기 (HWPUNIT)\n after?: number // 오른쪽 들여쓰기\n }\n spacing?: {\n before?: number // 위 간격 (HWPUNIT)\n after?: number // 아래 간격\n line?: number // 줄간격\n }\n}\n\nexport interface BorderFill {\n id: string\n type?: \"SOLID\" | \"DOTTED\" | \"DASHED\"\n color?: string // 선 색상\n width?: string // 선 굵기 (예: \"0.12 mm\")\n fillColor?: string // 채우기 색상\n}\n\nexport interface StyleDef {\n id: string\n name: string\n engName: string\n charPrIDRef: string\n paraPrIDRef: string\n}\n\nexport interface TemplateStyle {\n charPr?: Map<string, CharacterProperty>\n paraPr?: Map<string, ParagraphProperty>\n borderFill?: Map<string, BorderFill>\n fontfaces?: Map<string, string> // fontID → fontName\n styles?: Map<string, StyleDef> // 스타일명 → StyleDef\n stylesById?: Map<string, StyleDef> // 스타일 id → StyleDef\n secPrXml?: string // 원본 <hp:secPr>...</hp:secPr> XML\n colPrXml?: string // 원본 <hp:ctrl>...</hp:ctrl> XML (단 설정)\n masterpages?: Array<{ filename: string; content: string }>\n headerXml?: string // 원본 Contents/header.xml 전체\n}\n\n/**\n * HWPX 파일(ZIP)에서 header.xml을 추출하고 스타일 정보를 파싱\n */\nexport async function extractTemplateStyles(templateArrayBuffer: ArrayBuffer): Promise<TemplateStyle> {\n const zip = new JSZip()\n await zip.loadAsync(templateArrayBuffer)\n\n // header.xml 추출\n const headerFile = zip.file(\"Contents/header.xml\")\n if (!headerFile) {\n throw new Error(\"템플릿 파일이 유효하지 않습니다: Contents/header.xml 없음\")\n }\n\n const headerXmlText = await headerFile.async(\"text\")\n const doc = new DOMParser().parseFromString(headerXmlText, \"text/xml\")\n\n // namespace 정의\n const ns = {\n hh: \"http://www.hancom.co.kr/hwpml/2011/head\"\n }\n\n const template: TemplateStyle = {\n charPr: new Map(),\n paraPr: new Map(),\n borderFill: new Map(),\n fontfaces: new Map(),\n styles: new Map(),\n stylesById: new Map(),\n masterpages: [],\n headerXml: headerXmlText,\n }\n\n // ─── 폰트 추출 ─────────────────────────────────────────────────\n const fontfaces = doc.getElementsByTagNameNS(ns.hh, \"fontFamily\")\n for (let i = 0; i < fontfaces.length; i++) {\n const ff = fontfaces.item(i) as any\n const id = ff.getAttribute(\"id\")\n const name = ff.getAttribute(\"name\")\n if (id && name) {\n template.fontfaces!.set(id, name)\n }\n }\n\n // ─── charPr 추출 (문자 속성) ───────────────────────────────────\n const charPrs = doc.getElementsByTagNameNS(ns.hh, \"charPr\")\n for (let i = 0; i < charPrs.length; i++) {\n const cp = charPrs.item(i) as any\n const id = cp.getAttribute(\"id\")\n\n if (!id) continue\n\n const charProp: CharacterProperty = { id }\n\n // 글자 크기 (height는 HWPUNIT, 1000 = 10pt)\n const height = cp.getAttribute(\"height\")\n if (height) charProp.height = parseInt(height)\n\n // 기본 폰트 (fontRef)\n const fontRef = cp.getElementsByTagNameNS(ns.hh, \"fontRef\").item(0) as any\n if (fontRef) {\n charProp.fontName = fontRef.getAttribute(\"name\")\n }\n\n // 스타일\n charProp.bold = cp.getAttribute(\"bold\") === \"1\"\n charProp.italic = cp.getAttribute(\"italic\") === \"1\"\n charProp.underline = cp.getAttribute(\"underline\") === \"1\"\n charProp.strikethrough = cp.getAttribute(\"strikethrough\") === \"1\"\n\n // 색상\n const textColor = cp.getAttribute(\"textColor\")\n if (textColor) charProp.color = textColor\n\n template.charPr!.set(id, charProp)\n }\n\n // ─── paraPr 추출 (단락 속성) ───────────────────────────────────\n const paraPrs = doc.getElementsByTagNameNS(ns.hh, \"paraPr\")\n for (let i = 0; i < paraPrs.length; i++) {\n const pp = paraPrs.item(i) as any\n const id = pp.getAttribute(\"id\")\n\n if (!id) continue\n\n const paraProp: ParagraphProperty = { id }\n\n // 정렬\n const align = pp.getAttribute(\"align\")\n if (align) paraProp.align = align as any\n\n // 들여쓰기\n const indentBefore = pp.getAttribute(\"indentBefore\")\n const indentAfter = pp.getAttribute(\"indentAfter\")\n if (indentBefore || indentAfter) {\n paraProp.indent = {\n before: indentBefore ? parseInt(indentBefore) : 0,\n after: indentAfter ? parseInt(indentAfter) : 0\n }\n }\n\n // 간격\n const spacingBefore = pp.getAttribute(\"spacingBefore\")\n const spacingAfter = pp.getAttribute(\"spacingAfter\")\n const lineSpacing = pp.getAttribute(\"lineSpacing\")\n if (spacingBefore || spacingAfter || lineSpacing) {\n paraProp.spacing = {\n before: spacingBefore ? parseInt(spacingBefore) : 0,\n after: spacingAfter ? parseInt(spacingAfter) : 0,\n line: lineSpacing ? parseInt(lineSpacing) : 0\n }\n }\n\n template.paraPr!.set(id, paraProp)\n }\n\n // ─── borderFill 추출 (테두리/채우기) ─────────────────────────────\n const borderFills = doc.getElementsByTagNameNS(ns.hh, \"borderFill\")\n for (let i = 0; i < borderFills.length; i++) {\n const bf = borderFills.item(i) as any\n const id = bf.getAttribute(\"id\")\n\n if (!id) continue\n\n const borderFillProp: BorderFill = { id }\n\n // 선 종류\n const borderType = bf.getAttribute(\"type\")\n if (borderType) borderFillProp.type = borderType as any\n\n // 선 색상\n const borderColor = bf.getAttribute(\"color\")\n if (borderColor) borderFillProp.color = borderColor\n\n // 선 굵기\n const borderWidth = bf.getAttribute(\"width\")\n if (borderWidth) borderFillProp.width = borderWidth\n\n // 채우기 색상\n const fillColor = bf.getAttribute(\"fillColor\")\n if (fillColor) borderFillProp.fillColor = fillColor\n\n template.borderFill!.set(id, borderFillProp)\n }\n\n // ─── style 추출 (스타일명 → id/charPr/paraPr 매핑) ────────────\n const styleEls = doc.getElementsByTagNameNS(ns.hh, \"style\")\n for (let i = 0; i < styleEls.length; i++) {\n const el = styleEls.item(i) as any\n const id = el.getAttribute(\"id\")\n const name = el.getAttribute(\"name\") || \"\"\n const engName = el.getAttribute(\"engName\") || \"\"\n const charPrIDRef = el.getAttribute(\"charPrIDRef\") || \"0\"\n const paraPrIDRef = el.getAttribute(\"paraPrIDRef\") || \"0\"\n if (!id) continue\n const def: StyleDef = { id, name, engName, charPrIDRef, paraPrIDRef }\n template.styles!.set(name, def)\n template.stylesById!.set(id, def)\n }\n\n // ─── secPr / colPr 추출 (section0.xml에서) ──────────────────\n const section0File = zip.file(\"Contents/section0.xml\")\n if (section0File) {\n const sec0 = await section0File.async(\"text\")\n const secPrMatch = sec0.match(/<hp:secPr[\\s\\S]*?<\\/hp:secPr>/)\n if (secPrMatch) template.secPrXml = secPrMatch[0]\n const colPrMatch = sec0.match(/<hp:ctrl>[\\s\\S]*?<\\/hp:ctrl>/)\n if (colPrMatch) template.colPrXml = colPrMatch[0]\n }\n\n // ─── masterpage 파일 추출 ─────────────────────────────────────\n for (const [path, file] of Object.entries(zip.files)) {\n if (/^Contents\\/masterpage\\d+\\.xml$/.test(path)) {\n const content = await file.async(\"text\")\n template.masterpages!.push({ filename: path, content })\n }\n }\n template.masterpages!.sort((a, b) => a.filename.localeCompare(b.filename))\n\n return template\n}\n\n/**\n * 템플릿 스타일에서 특정 특성을 만족하는 charPr ID 찾기\n * (휴리스틱 기반 자동 감지)\n */\nexport function findCharPrByCharacteristic(\n charPrMap: Map<string, CharacterProperty>,\n characteristic: \"heading1\" | \"heading2\" | \"heading3\" | \"bold\" | \"italic\" | \"normal\"\n): string | null {\n // 크기 범위 (HWPUNIT 기준, 1000 = 10pt)\n const ranges: Record<string, { minHeight: number; maxHeight: number; needBold?: boolean }> = {\n heading1: { minHeight: 1800, maxHeight: 2500, needBold: true },\n heading2: { minHeight: 1200, maxHeight: 1700, needBold: true },\n heading3: { minHeight: 1000, maxHeight: 1199, needBold: true },\n bold: { minHeight: 800, maxHeight: 1100, needBold: true },\n italic: { minHeight: 800, maxHeight: 1100, needBold: false },\n normal: { minHeight: 900, maxHeight: 1100, needBold: false }\n }\n\n const range = ranges[characteristic]\n if (!range) return null\n\n // 가장 잘 맞는 charPr 찾기\n let bestMatch: [string, CharacterProperty] | null = null\n let bestScore = 0\n\n for (const [id, prop] of charPrMap) {\n let score = 0\n\n // 높이 일치도\n if (prop.height) {\n if (prop.height >= range.minHeight && prop.height <= range.maxHeight) {\n score += 50\n } else if (Math.abs(prop.height - (range.minHeight + range.maxHeight) / 2) < 100) {\n score += 20 // 약간 다르지만 가까운 경우\n }\n }\n\n // bold 요구사항\n if (range.needBold !== undefined) {\n if (range.needBold && prop.bold) score += 30\n else if (!range.needBold && !prop.bold) score += 20\n }\n\n // italic 요구사항 (italic의 경우만)\n if (characteristic === \"italic\" && prop.italic) score += 20\n\n if (score > bestScore) {\n bestScore = score\n bestMatch = [id, prop]\n }\n }\n\n return bestMatch ? bestMatch[0] : null\n}\n\n/**\n * 템플릿에서 기본값 charPr ID 찾기 (보통 ID \"0\")\n */\nexport function getDefaultCharPrId(charPrMap: Map<string, CharacterProperty>): string {\n // ID \"0\"을 먼저 확인\n if (charPrMap.has(\"0\")) return \"0\"\n\n // 없으면 첫 번째 항목\n if (charPrMap.size > 0) {\n return charPrMap.keys().next().value\n }\n\n return \"0\" // 폴백\n}\n\n/**\n * 템플릿에서 기본값 paraPr ID 찾기\n */\nexport function getDefaultParaPrId(paraPrMap: Map<string, ParagraphProperty>): string {\n if (paraPrMap.has(\"0\")) return \"0\"\n if (paraPrMap.size > 0) {\n return paraPrMap.keys().next().value\n }\n return \"0\"\n}\n\n/**\n * 템플릿에서 기본값 borderFill ID 찾기\n */\nexport function getDefaultBorderFillId(borderFillMap: Map<string, BorderFill>): string {\n // 보통 ID \"1\" 또는 \"3\"이 기본값\n if (borderFillMap.has(\"1\")) return \"1\"\n if (borderFillMap.has(\"3\")) return \"3\"\n if (borderFillMap.size > 0) {\n return borderFillMap.keys().next().value\n }\n return \"1\"\n}\n","/**\n * Style Matcher — 마크다운 블록을 템플릿 스타일에 매칭\n */\n\nimport type { TemplateStyle, StyleDef } from \"./template-analyzer.js\"\nimport {\n findCharPrByCharacteristic,\n getDefaultCharPrId,\n getDefaultParaPrId,\n getDefaultBorderFillId\n} from \"./template-analyzer.js\"\n\nexport interface StyleEntry {\n charPr: string\n paraPr: string\n styleId: string // styleIDRef 값 (paraPrIDRef보다 우선)\n}\n\nexport interface StyleMap {\n h1: StyleEntry\n h2: StyleEntry\n h3: StyleEntry\n h456: StyleEntry\n body: StyleEntry\n bold: { charPr: string }\n italic: { charPr: string }\n tableCell: StyleEntry & { borderFill: string }\n tableHeader: StyleEntry & { borderFill: string }\n}\n\n/** 스타일명 후보 목록에서 첫 번째 매칭 StyleDef 반환 */\nfunction findStyleByName(\n styles: Map<string, StyleDef>,\n candidates: string[],\n): StyleDef | null {\n // 1순위: 정확히 일치\n for (const cand of candidates) {\n if (styles.has(cand)) return styles.get(cand)!\n }\n // 2순위: 단어 경계 포함 (접두 \"B-\" 뒤에 정확히 일치, 또는 끝에 일치)\n for (const cand of candidates) {\n for (const [name, def] of styles) {\n if (name === `B-${cand}` || name.endsWith(` ${cand}`) || name.endsWith(`-${cand}`)) return def\n }\n }\n // 3순위: 부분 일치 — 이름이 짧은 것 우선 (예: \"B-1.\"이 \"B-1.1 제목\"보다 먼저)\n for (const cand of candidates) {\n let best: [string, StyleDef] | null = null\n for (const [name, def] of styles) {\n if (name.includes(cand)) {\n if (!best || name.length < best[0].length) best = [name, def]\n }\n }\n if (best) return best[1]\n }\n return null\n}\n\n/**\n * 템플릿을 분석하고 자동으로 마크다운 블록과 매칭하는 StyleMap 생성\n * 1순위: 스타일명 직접 매칭 / 2순위: 글자 크기 휴리스틱\n */\nexport function createStyleMap(template: TemplateStyle, warnings: string[] = []): StyleMap {\n const charPrMap = template.charPr || new Map()\n const borderFillMap = template.borderFill || new Map()\n const styles = template.styles || new Map<string, StyleDef>()\n\n const defaultCharPr = getDefaultCharPrId(charPrMap)\n const defaultParaPr = getDefaultParaPrId(template.paraPr || new Map())\n const defaultBorderFill = getDefaultBorderFillId(borderFillMap)\n const defaultStyleId = \"0\"\n\n const toEntry = (def: StyleDef | null, fallbackCharPr: string): StyleEntry => ({\n charPr: def?.charPrIDRef ?? fallbackCharPr,\n paraPr: def?.paraPrIDRef ?? defaultParaPr,\n styleId: def?.id ?? defaultStyleId,\n })\n\n // ── 스타일명 직접 매칭 ──────────────────────────────────────\n const bodyDef =\n findStyleByName(styles, [\"바탕글\", \"Normal\", \"본문\", \"바탕\"]) ||\n findStyleByName(styles, [\"body\", \"normal\"])\n const h1Def =\n findStyleByName(styles, [\"제목1\", \"제목 1\", \"개요 1\", \"개요1\", \"Heading 1\"]) ||\n findStyleByName(styles, [\"장제목\", \"대제목\", \"제목\"])\n const h2Def =\n findStyleByName(styles, [\"제목2\", \"제목 2\", \"개요 2\", \"개요2\", \"Heading 2\"]) ||\n findStyleByName(styles, [\"절제목\", \"1.\", \"1 \"])\n const h3Def =\n findStyleByName(styles, [\"제목3\", \"제목 3\", \"개요 3\", \"개요3\", \"Heading 3\"]) ||\n findStyleByName(styles, [\"1.1\", \"항목\"])\n const tableCellDef =\n findStyleByName(styles, [\"표 내용\", \"표내용\", \"B-표내용\", \"표 내용(일반)\"]) ||\n findStyleByName(styles, [\"표\", \"table\"])\n const tableHeaderDef =\n findStyleByName(styles, [\"표제목\", \"표 제목\", \"B-표제목\", \"표 내용(강조)\"]) ||\n tableCellDef\n\n // ── 휴리스틱 폴백 (charPr 크기 기반) ─────────────────────────\n const bodyCharPr = bodyDef?.charPrIDRef ?? findCharPrByCharacteristic(charPrMap, \"normal\") ?? defaultCharPr\n const h1CharPr = h1Def?.charPrIDRef ?? findCharPrByCharacteristic(charPrMap, \"heading1\") ?? defaultCharPr\n const h2CharPr = h2Def?.charPrIDRef ?? findCharPrByCharacteristic(charPrMap, \"heading2\") ?? defaultCharPr\n const h3CharPr = h3Def?.charPrIDRef ?? findCharPrByCharacteristic(charPrMap, \"heading3\") ?? defaultCharPr\n const boldCharPr = findCharPrByCharacteristic(charPrMap, \"bold\") ?? defaultCharPr\n const italicCharPr = findCharPrByCharacteristic(charPrMap, \"italic\") ?? defaultCharPr\n\n return {\n h1: { charPr: h1CharPr, paraPr: h1Def?.paraPrIDRef ?? defaultParaPr, styleId: h1Def?.id ?? defaultStyleId },\n h2: { charPr: h2CharPr, paraPr: h2Def?.paraPrIDRef ?? defaultParaPr, styleId: h2Def?.id ?? defaultStyleId },\n h3: { charPr: h3CharPr, paraPr: h3Def?.paraPrIDRef ?? defaultParaPr, styleId: h3Def?.id ?? defaultStyleId },\n h456: { charPr: h3CharPr, paraPr: h3Def?.paraPrIDRef ?? defaultParaPr, styleId: h3Def?.id ?? defaultStyleId },\n body: { charPr: bodyCharPr, paraPr: bodyDef?.paraPrIDRef ?? defaultParaPr, styleId: bodyDef?.id ?? defaultStyleId },\n bold: { charPr: boldCharPr },\n italic: { charPr: italicCharPr },\n tableCell: { charPr: tableCellDef?.charPrIDRef ?? bodyCharPr, paraPr: tableCellDef?.paraPrIDRef ?? defaultParaPr, styleId: tableCellDef?.id ?? defaultStyleId, borderFill: defaultBorderFill },\n tableHeader: { charPr: tableHeaderDef?.charPrIDRef ?? bodyCharPr, paraPr: tableHeaderDef?.paraPrIDRef ?? defaultParaPr, styleId: tableHeaderDef?.id ?? defaultStyleId, borderFill: defaultBorderFill },\n }\n}\n\n/**\n * 마크다운 블록 타입으로 스타일 ID 조회\n */\nexport function getStyleForBlock(\n styleMap: StyleMap,\n blockType: \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"body\" | \"table_header\" | \"table_cell\",\n inlineStyle?: \"bold\" | \"italic\"\n): { charPr: string; paraPr?: string; borderFill?: string } {\n let baseStyle: any = styleMap.body\n\n // 헤딩 레벨별\n if (blockType === \"h1\") baseStyle = styleMap.h1\n else if (blockType === \"h2\") baseStyle = styleMap.h2\n else if (blockType === \"h3\") baseStyle = styleMap.h3\n else if (blockType === \"h4\" || blockType === \"h5\" || blockType === \"h6\") baseStyle = styleMap.h456\n else if (blockType === \"table_header\") baseStyle = styleMap.tableHeader\n else if (blockType === \"table_cell\") baseStyle = styleMap.tableCell\n\n // 인라인 스타일 적용\n if (inlineStyle === \"bold\") {\n return {\n charPr: styleMap.bold.charPr,\n paraPr: baseStyle.paraPr\n }\n }\n if (inlineStyle === \"italic\") {\n return {\n charPr: styleMap.italic.charPr,\n paraPr: baseStyle.paraPr\n }\n }\n\n return baseStyle\n}\n\n/**\n * 인라인 텍스트에 대한 charPr ID 결정\n */\nexport function getCharPrForInline(\n styleMap: StyleMap,\n bold?: boolean,\n italic?: boolean\n): string {\n if (bold && italic) return styleMap.bold.charPr // 둘 다이면 bold 우선\n if (bold) return styleMap.bold.charPr\n if (italic) return styleMap.italic.charPr\n return styleMap.body.charPr\n}\n","/**\n * Markdown → XLSX 변환기\n *\n * 지원: 헤딩, 단락, 코드, blockquote, hr, 테이블(별도 시트), 이미지\n */\n\nimport ExcelJS from \"exceljs\"\nimport { parseMarkdownToBlocks } from \"../hwpx/generator.js\"\nimport type { MdBlock } from \"../hwpx/generator.js\"\nimport type { ExtractedImage } from \"../types.js\"\n\n// ─── 공개 타입 ──────────────────────────────────────────\n\nexport interface MarkdownToXlsxOptions {\n warnings?: string[]\n images?: ExtractedImage[]\n}\n\n// ─── 헬퍼 ──────────────────────────────────────────────\n\nfunction mimeToExtension(mimeType: string): \"png\" | \"jpeg\" | \"gif\" {\n if (mimeType.includes(\"jpeg\") || mimeType.includes(\"jpg\")) return \"jpeg\"\n if (mimeType.includes(\"gif\")) return \"gif\"\n return \"png\"\n}\n\nfunction buildImageMap(images?: ExtractedImage[]): Map<string, ExtractedImage> {\n const map = new Map<string, ExtractedImage>()\n if (!images) return map\n for (const img of images) map.set(img.filename, img)\n return map\n}\n\n// ─── 시트 구성 ──────────────────────────────────────────\n\n/** 본문 시트에 비테이블 요소 추가. 이미지는 exceljs addImage로 삽입. */\nasync function fillBodySheet(\n sheet: ExcelJS.Worksheet,\n workbook: ExcelJS.Workbook,\n blocks: MdBlock[],\n imageMap: Map<string, ExtractedImage>,\n): Promise<void> {\n sheet.getColumn(1).width = 80\n\n for (const block of blocks) {\n switch (block.type) {\n case \"heading\": {\n const level = block.level || 1\n const size = level === 1 ? 20 : level === 2 ? 16 : level === 3 ? 14 : 12\n const row = sheet.addRow([block.text || \"\"])\n row.getCell(1).font = { bold: true, size }\n row.getCell(1).alignment = { wrapText: true }\n break\n }\n case \"paragraph\": {\n const row = sheet.addRow([block.text || \"\"])\n row.getCell(1).alignment = { wrapText: true }\n break\n }\n case \"code\": {\n const lines = (block.text || \"\").split(\"\\n\")\n for (const line of lines) {\n const row = sheet.addRow([line || \" \"])\n row.getCell(1).font = { name: \"Courier New\", size: 9 }\n row.getCell(1).fill = {\n type: \"pattern\", pattern: \"solid\",\n fgColor: { argb: \"FFF2F2F2\" },\n }\n }\n break\n }\n case \"blockquote\": {\n const row = sheet.addRow([block.text || \"\"])\n row.getCell(1).font = { italic: true, color: { argb: \"FF888888\" } }\n row.getCell(1).alignment = { wrapText: true }\n break\n }\n case \"hr\": {\n const row = sheet.addRow([\"\"])\n row.getCell(1).border = {\n bottom: { style: \"medium\", color: { argb: \"FF888888\" } },\n }\n break\n }\n case \"empty\": {\n sheet.addRow([\"\"])\n break\n }\n case \"list\": {\n for (const item of block.items || []) {\n const indent = \" \".repeat(item.indent)\n const bullet = block.listType === \"ordered\"\n ? `${item.indent + 1}. `\n : [\"• \", \"◦ \", \"▪ \"][Math.min(item.indent, 2)]\n const row = sheet.addRow([`${indent}${bullet}${item.text}`])\n row.getCell(1).alignment = { wrapText: true }\n }\n break\n }\n case \"image\": {\n const src = block.src || \"\"\n const img = imageMap.get(src)\n if (img) {\n const currentRow = sheet.rowCount + 1\n const ext = mimeToExtension(img.mimeType)\n const imageId = workbook.addImage({ base64: Buffer.from(img.data).toString(\"base64\"), extension: ext })\n sheet.addRow([\"\"]) // 이미지 앵커용 빈 행\n sheet.addImage(imageId, {\n tl: { col: 0, row: currentRow - 1 },\n ext: { width: 300, height: 200 },\n })\n sheet.getRow(currentRow).height = 155 // 200px ≒ 155pt\n } else {\n const alt = block.alt || src || \"(이미지)\"\n const row = sheet.addRow([`[이미지: ${alt}]`])\n row.getCell(1).font = { italic: true, color: { argb: \"FF999999\" } }\n }\n break\n }\n // table은 별도 시트에서 처리\n }\n }\n}\n\n/** 테이블 시트 생성 */\nfunction fillTableSheet(sheet: ExcelJS.Worksheet, rows: string[][]): void {\n for (let rowIdx = 0; rowIdx < rows.length; rowIdx++) {\n const cells = rows[rowIdx]\n const row = sheet.addRow(cells)\n\n // 열 너비 자동 조정\n cells.forEach((cell, colIdx) => {\n const col = sheet.getColumn(colIdx + 1)\n col.width = Math.max(col.width ?? 10, Math.min(cell.length + 4, 40))\n })\n\n if (rowIdx === 0) {\n // 헤더 행\n row.eachCell(cell => {\n cell.font = { bold: true }\n cell.fill = { type: \"pattern\", pattern: \"solid\", fgColor: { argb: \"FFD9E1F2\" } }\n cell.border = {\n top: { style: \"thin\" }, bottom: { style: \"thin\" },\n left: { style: \"thin\" }, right: { style: \"thin\" },\n }\n cell.alignment = { wrapText: true }\n })\n } else {\n row.eachCell(cell => {\n cell.border = {\n top: { style: \"thin\" }, bottom: { style: \"thin\" },\n left: { style: \"thin\" }, right: { style: \"thin\" },\n }\n cell.alignment = { wrapText: true }\n })\n }\n }\n}\n\n// ─── 공개 API ────────────────────────────────────────────\n\n/**\n * 마크다운 텍스트를 XLSX (ArrayBuffer)로 변환.\n * @param markdown 마크다운 텍스트\n * @param options 경고 수집, 이미지 데이터 등\n */\nexport async function markdownToXlsx(\n markdown: string,\n options?: MarkdownToXlsxOptions,\n): Promise<ArrayBuffer> {\n const warnings = options?.warnings || []\n const imageMap = buildImageMap(options?.images)\n const blocks = parseMarkdownToBlocks(markdown)\n\n const workbook = new ExcelJS.Workbook()\n workbook.created = new Date()\n\n // 테이블 블록과 비테이블 블록 분리\n const tableBlocks = blocks.filter(b => b.type === \"table\")\n const bodyBlocks = blocks.filter(b => b.type !== \"table\")\n\n // 본문 시트 (비테이블 요소가 있을 때만 생성)\n const hasBodyContent = bodyBlocks.some(b => b.type !== \"empty\")\n if (hasBodyContent) {\n const bodySheet = workbook.addWorksheet(\"본문\")\n await fillBodySheet(bodySheet, workbook, bodyBlocks, imageMap)\n }\n\n // 테이블 시트\n tableBlocks.forEach((block, idx) => {\n if (!block.rows?.length) return\n const sheet = workbook.addWorksheet(`Table ${idx + 1}`)\n fillTableSheet(sheet, block.rows)\n })\n\n // 시트가 하나도 없으면 빈 본문 시트 추가\n if (workbook.worksheets.length === 0) {\n workbook.addWorksheet(\"본문\")\n warnings.push(\"[warn] 변환할 내용이 없어 빈 시트를 생성했습니다.\")\n }\n\n const buffer = await workbook.xlsx.writeBuffer() as unknown as Buffer\n return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength) as ArrayBuffer\n}\n"],"mappings":"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AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAC7E,CAAC;AAED,IAAM,YAAY,IAAI,WAAW;AAAA,EAC/B;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AA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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAw/BnB,IAAM,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;A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","names":["s2a","CRC32","CFB","exports","i","parse","q","filename","cfb","file","flen","L","find","_deflateRaw","readFileSync","createTesseractProvider","JSZip","JSZip","MAX_DECOMPRESS_SIZE","cellRows","find","resolveOcrProvider","ocrPages","JSZip","DOMParser","MAX_DECOMPRESS_SIZE","MAX_ROWS","MAX_COLS","DOMParser","JSZip","parsePageRange","JSZip","DOMParser","MAX_DECOMPRESS_SIZE","parseXml","DOMParser","parseRels","runs","text","JSZip","parse","i","j","JSZip","JSZip","DOMParser","JSZip","parse"]}
|