@bendyline/squisq-formats 1.4.2 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/README.md +48 -2
  2. package/dist/chunk-2KPARF2P.js +99 -0
  3. package/dist/chunk-2KPARF2P.js.map +1 -0
  4. package/dist/{chunk-5LSSWZPU.js → chunk-4VUWTSGM.js} +72 -25
  5. package/dist/chunk-4VUWTSGM.js.map +1 -0
  6. package/dist/{chunk-YESS7VY3.js → chunk-ABVI556T.js} +154 -39
  7. package/dist/chunk-ABVI556T.js.map +1 -0
  8. package/dist/{chunk-WWBIKRNP.js → chunk-CRAVSMPZ.js} +13 -11
  9. package/dist/chunk-CRAVSMPZ.js.map +1 -0
  10. package/dist/chunk-FE6OJV6O.js +560 -0
  11. package/dist/chunk-FE6OJV6O.js.map +1 -0
  12. package/dist/{chunk-D7IFPWNZ.js → chunk-GVS2XXV6.js} +27 -26
  13. package/dist/chunk-GVS2XXV6.js.map +1 -0
  14. package/dist/{chunk-RTS5XBZ7.js → chunk-HTW2M27H.js} +341 -100
  15. package/dist/chunk-HTW2M27H.js.map +1 -0
  16. package/dist/{chunk-46FMDOWZ.js → chunk-LXYLOOST.js} +49 -17
  17. package/dist/chunk-LXYLOOST.js.map +1 -0
  18. package/dist/{chunk-MJGRI6XR.js → chunk-MLX2BOJC.js} +12 -7
  19. package/dist/chunk-MLX2BOJC.js.map +1 -0
  20. package/dist/chunk-NKAJPJ4G.js +106 -0
  21. package/dist/chunk-NKAJPJ4G.js.map +1 -0
  22. package/dist/{chunk-DQAZR57U.js → chunk-O3GVVND4.js} +1 -1
  23. package/dist/chunk-ODL3SSPT.js +18 -0
  24. package/dist/chunk-ODL3SSPT.js.map +1 -0
  25. package/dist/chunk-QRVN6A6E.js +127 -0
  26. package/dist/chunk-QRVN6A6E.js.map +1 -0
  27. package/dist/chunk-U32AG3G3.js +195 -0
  28. package/dist/chunk-U32AG3G3.js.map +1 -0
  29. package/dist/{chunk-EHLGMSTE.js → chunk-VJJM2SSH.js} +10 -8
  30. package/dist/chunk-VJJM2SSH.js.map +1 -0
  31. package/dist/chunk-VSYHZECT.js +778 -0
  32. package/dist/chunk-VSYHZECT.js.map +1 -0
  33. package/dist/{chunk-SHLPSADL.js → chunk-WC7WULGV.js} +81 -189
  34. package/dist/chunk-WC7WULGV.js.map +1 -0
  35. package/dist/chunk-XKUMNGBW.js +131 -0
  36. package/dist/chunk-XKUMNGBW.js.map +1 -0
  37. package/dist/chunk-YRT7GQ5Y.js +28 -0
  38. package/dist/chunk-YRT7GQ5Y.js.map +1 -0
  39. package/dist/container/index.d.ts +13 -3
  40. package/dist/container/index.js +23 -20
  41. package/dist/container/index.js.map +1 -1
  42. package/dist/docx/index.d.ts +6 -2
  43. package/dist/docx/index.js +5 -3
  44. package/dist/epub/index.d.ts +3 -1
  45. package/dist/epub/index.js +3 -3
  46. package/dist/export-D2NkylDT.d.ts +69 -0
  47. package/dist/extract-H6RXJMHP.js +15 -0
  48. package/dist/extract-H6RXJMHP.js.map +1 -0
  49. package/dist/html/index.d.ts +15 -85
  50. package/dist/html/index.js +3 -3
  51. package/dist/images-7FBWPKE3.js +7 -0
  52. package/dist/images-7FBWPKE3.js.map +1 -0
  53. package/dist/import-DTkDxHmZ.d.ts +84 -0
  54. package/dist/import-K8mfc0fz.d.ts +136 -0
  55. package/dist/index.d.ts +14 -4
  56. package/dist/index.js +33 -12
  57. package/dist/infer/index.d.ts +138 -0
  58. package/dist/infer/index.js +28 -0
  59. package/dist/infer/index.js.map +1 -0
  60. package/dist/layouts-BHrgZ5FS.d.ts +150 -0
  61. package/dist/layouts-QVPK3ZCU.js +12 -0
  62. package/dist/layouts-QVPK3ZCU.js.map +1 -0
  63. package/dist/mapTheme-IR27S6IV.js +11 -0
  64. package/dist/mapTheme-IR27S6IV.js.map +1 -0
  65. package/dist/ooxml/index.d.ts +21 -127
  66. package/dist/ooxml/index.js +31 -9
  67. package/dist/pdf/index.d.ts +3 -1
  68. package/dist/pdf/index.js +1 -1
  69. package/dist/pptx/index.d.ts +8 -108
  70. package/dist/pptx/index.js +13 -4
  71. package/dist/reader-B9L8Ucbj.d.ts +140 -0
  72. package/dist/registry/index.d.ts +60 -8
  73. package/dist/registry/index.js +9 -4
  74. package/dist/themeReader-DJKErl_j.d.ts +56 -0
  75. package/dist/xlsx/index.d.ts +6 -66
  76. package/dist/xlsx/index.js +4 -2
  77. package/dist/zipLimits-BOKCB7qk.d.ts +31 -0
  78. package/package.json +8 -2
  79. package/src/__tests__/container.test.ts +41 -0
  80. package/src/__tests__/convert.test.ts +310 -1
  81. package/src/__tests__/epub.test.ts +102 -1
  82. package/src/__tests__/html.test.ts +62 -0
  83. package/src/__tests__/inferTheme.test.ts +135 -0
  84. package/src/__tests__/lossyWarnings.test.ts +41 -0
  85. package/src/__tests__/ooxml.test.ts +76 -2
  86. package/src/__tests__/ooxmlCancellation.test.ts +113 -0
  87. package/src/__tests__/ooxmlThemeReader.test.ts +92 -0
  88. package/src/__tests__/plainHtml.test.ts +15 -1
  89. package/src/__tests__/plainHtmlBundle.test.ts +18 -0
  90. package/src/__tests__/pptxImport.test.ts +30 -0
  91. package/src/__tests__/pptxInferFixtures.ts +314 -0
  92. package/src/__tests__/pptxLayoutInfer.test.ts +395 -0
  93. package/src/__tests__/zipSafety.test.ts +317 -0
  94. package/src/container/index.ts +37 -32
  95. package/src/docx/export.ts +4 -2
  96. package/src/docx/import.ts +4 -3
  97. package/src/epub/export.ts +94 -25
  98. package/src/html/docsHtmlBundle.ts +6 -2
  99. package/src/html/htmlTemplate.ts +31 -6
  100. package/src/html/imageUtils.ts +14 -5
  101. package/src/html/index.ts +12 -1
  102. package/src/html/plainHtml.ts +7 -3
  103. package/src/html/plainHtmlBundle.ts +11 -9
  104. package/src/index.ts +23 -0
  105. package/src/infer/extract.ts +127 -0
  106. package/src/infer/index.ts +199 -0
  107. package/src/infer/mapTheme.ts +176 -0
  108. package/src/infer/types.ts +27 -0
  109. package/src/ooxml/index.ts +14 -0
  110. package/src/ooxml/readUtils.ts +44 -0
  111. package/src/ooxml/reader.ts +129 -29
  112. package/src/ooxml/themeReader.ts +197 -0
  113. package/src/ooxml/types.ts +8 -9
  114. package/src/ooxml/writer.ts +28 -10
  115. package/src/pdf/export.ts +4 -2
  116. package/src/pdf/import.ts +40 -34
  117. package/src/pptx/export.ts +4 -2
  118. package/src/pptx/import.ts +214 -32
  119. package/src/pptx/index.ts +14 -0
  120. package/src/pptx/layouts.ts +1222 -0
  121. package/src/registry/convert.ts +168 -53
  122. package/src/registry/defaultFormats.ts +135 -45
  123. package/src/registry/index.ts +6 -1
  124. package/src/registry/types.ts +69 -6
  125. package/src/shared/boundedZipArchive.ts +383 -0
  126. package/src/shared/fidelity.ts +130 -0
  127. package/src/shared/zipEntryCount.ts +151 -0
  128. package/src/shared/zipLimits.ts +296 -0
  129. package/src/shared/zipSafety.ts +19 -0
  130. package/src/xlsx/import.ts +3 -2
  131. package/dist/chunk-46FMDOWZ.js.map +0 -1
  132. package/dist/chunk-5LSSWZPU.js.map +0 -1
  133. package/dist/chunk-D7IFPWNZ.js.map +0 -1
  134. package/dist/chunk-EHLGMSTE.js.map +0 -1
  135. package/dist/chunk-MJGRI6XR.js.map +0 -1
  136. package/dist/chunk-RTS5XBZ7.js.map +0 -1
  137. package/dist/chunk-SHLPSADL.js.map +0 -1
  138. package/dist/chunk-WWBIKRNP.js.map +0 -1
  139. package/dist/chunk-YESS7VY3.js.map +0 -1
  140. /package/dist/{chunk-DQAZR57U.js.map → chunk-O3GVVND4.js.map} +0 -0
@@ -0,0 +1,778 @@
1
+ import {
2
+ attrNS,
3
+ baseDirOf,
4
+ findRelByType,
5
+ resolveTarget
6
+ } from "./chunk-YRT7GQ5Y.js";
7
+ import {
8
+ CONTENT_TYPE_PPTX_SLIDE_LAYOUT,
9
+ NS_DRAWINGML,
10
+ NS_PML,
11
+ NS_R,
12
+ REL_SLIDE_LAYOUT,
13
+ REL_SLIDE_MASTER,
14
+ getPartRelationships,
15
+ getPartXml,
16
+ openPackage,
17
+ throwIfOoxmlAborted
18
+ } from "./chunk-WC7WULGV.js";
19
+
20
+ // src/pptx/layouts.ts
21
+ var DEFAULT_SLIDE_SIZE = { cx: 12192e3, cy: 6858e3 };
22
+ var CHROME_PH_TYPES = /* @__PURE__ */ new Set(["dt", "ftr", "sldNum", "hdr"]);
23
+ var MAX_INFERRED_TEMPLATES = 12;
24
+ var MAX_DECORATIONS = 4;
25
+ var CANCELLATION_CHECKPOINT_INTERVAL = 128;
26
+ var MIN_DECORATION_AREA_PCT = 2;
27
+ var DEFAULT_TITLE_RECT = { x: 5, y: 4, w: 90, h: 16.7 };
28
+ var DEFAULT_BODY_RECT = { x: 5, y: 23.3, w: 90, h: 66 };
29
+ var DEFAULT_TITLE_PT = 44;
30
+ var DEFAULT_SUBTITLE_PT = 24;
31
+ var DEFAULT_BODY_PT = 22;
32
+ async function cancellationCheckpoint(index, signal) {
33
+ throwIfOoxmlAborted(signal);
34
+ if (index > 0 && index % CANCELLATION_CHECKPOINT_INTERVAL === 0) {
35
+ await new Promise((resolve) => setTimeout(resolve, 0));
36
+ throwIfOoxmlAborted(signal);
37
+ }
38
+ }
39
+ function firstPml(parent, local) {
40
+ const els = parent.getElementsByTagNameNS(NS_PML, local);
41
+ return els.length > 0 ? els[0] : null;
42
+ }
43
+ function firstDml(parent, local) {
44
+ const els = parent.getElementsByTagNameNS(NS_DRAWINGML, local);
45
+ return els.length > 0 ? els[0] : null;
46
+ }
47
+ function intAttr(el, name) {
48
+ const raw = el?.getAttribute(name);
49
+ if (!raw) return void 0;
50
+ const n = parseInt(raw, 10);
51
+ return Number.isFinite(n) ? n : void 0;
52
+ }
53
+ function pct(value, total) {
54
+ const raw = value / total * 100;
55
+ const clamped = Math.max(-10, Math.min(110, raw));
56
+ return Math.round(clamped * 100) / 100;
57
+ }
58
+ function emuToPct(rect, sldSz) {
59
+ return {
60
+ x: pct(rect.x, sldSz.cx),
61
+ y: pct(rect.y, sldSz.cy),
62
+ w: pct(rect.cx, sldSz.cx),
63
+ h: pct(rect.cy, sldSz.cy)
64
+ };
65
+ }
66
+ function readXfrm(sp) {
67
+ const spPr = firstPml(sp, "spPr");
68
+ if (!spPr) return null;
69
+ const xfrm = firstDml(spPr, "xfrm");
70
+ if (!xfrm) return null;
71
+ const off = firstDml(xfrm, "off");
72
+ const ext = firstDml(xfrm, "ext");
73
+ const x = intAttr(off, "x");
74
+ const y = intAttr(off, "y");
75
+ const cx = intAttr(ext, "cx");
76
+ const cy = intAttr(ext, "cy");
77
+ if (x === void 0 || y === void 0 || cx === void 0 || cy === void 0) return null;
78
+ if (cx <= 0 || cy <= 0) return null;
79
+ return { x, y, cx, cy };
80
+ }
81
+ function placeholderKind(rawType) {
82
+ switch (rawType) {
83
+ case "title":
84
+ case "ctrTitle":
85
+ return "title";
86
+ case "subTitle":
87
+ return "subtitle";
88
+ case "":
89
+ case "body":
90
+ case "obj":
91
+ return "text";
92
+ case "pic":
93
+ case "clipArt":
94
+ case "media":
95
+ return "picture";
96
+ case "tbl":
97
+ return "table";
98
+ case "chart":
99
+ case "dgm":
100
+ return "chart";
101
+ default:
102
+ return "other";
103
+ }
104
+ }
105
+ function basePhType(rawType) {
106
+ switch (rawType) {
107
+ case "ctrTitle":
108
+ return "title";
109
+ case "":
110
+ case "subTitle":
111
+ case "obj":
112
+ case "pic":
113
+ case "clipArt":
114
+ case "media":
115
+ case "tbl":
116
+ case "chart":
117
+ case "dgm":
118
+ return "body";
119
+ default:
120
+ return rawType;
121
+ }
122
+ }
123
+ function parseLvl1Style(container) {
124
+ const lvl1 = firstDml(container, "lvl1pPr");
125
+ if (!lvl1) return void 0;
126
+ const style = {};
127
+ const algn = lvl1.getAttribute("algn");
128
+ if (algn === "ctr") style.align = "center";
129
+ else if (algn === "r") style.align = "right";
130
+ else if (algn === "l") style.align = "left";
131
+ const defRPr = firstDml(lvl1, "defRPr");
132
+ const sz = intAttr(defRPr, "sz");
133
+ if (sz !== void 0 && sz > 0) style.fontSizePt = sz / 100;
134
+ const b = defRPr?.getAttribute("b");
135
+ if (b === "1" || b === "true") style.bold = true;
136
+ else if (b === "0" || b === "false") style.bold = false;
137
+ return Object.keys(style).length > 0 ? style : void 0;
138
+ }
139
+ function mergeTextStyle(primary, fallback) {
140
+ if (!primary) return fallback;
141
+ if (!fallback) return primary;
142
+ return {
143
+ fontSizePt: primary.fontSizePt ?? fallback.fontSizePt,
144
+ bold: primary.bold ?? fallback.bold,
145
+ align: primary.align ?? fallback.align,
146
+ anchor: primary.anchor ?? fallback.anchor
147
+ };
148
+ }
149
+ async function readMasterIndex(pkg, masterPath, signal) {
150
+ throwIfOoxmlAborted(signal);
151
+ const index = { name: "", exact: /* @__PURE__ */ new Map(), baseIdx: /* @__PURE__ */ new Map(), base: /* @__PURE__ */ new Map() };
152
+ const doc = await getPartXml(pkg, masterPath);
153
+ if (!doc) return index;
154
+ index.name = firstPml(doc, "cSld")?.getAttribute("name")?.trim() ?? "";
155
+ const txStyles = firstPml(doc, "txStyles");
156
+ if (txStyles) {
157
+ const titleStyle = firstPml(txStyles, "titleStyle");
158
+ const bodyStyle = firstPml(txStyles, "bodyStyle");
159
+ if (titleStyle) index.titleStyle = parseLvl1Style(titleStyle);
160
+ if (bodyStyle) index.bodyStyle = parseLvl1Style(bodyStyle);
161
+ }
162
+ const shapes = doc.getElementsByTagNameNS(NS_PML, "sp");
163
+ for (let i = 0; i < shapes.length; i++) {
164
+ await cancellationCheckpoint(i, signal);
165
+ const sp = shapes[i];
166
+ const ph = firstPml(sp, "ph");
167
+ if (!ph) continue;
168
+ const rawType = ph.getAttribute("type") ?? "";
169
+ const idx = intAttr(ph, "idx") ?? 0;
170
+ const entry = { rect: readXfrm(sp) };
171
+ const txBody = firstPml(sp, "txBody");
172
+ const lstStyle = txBody ? firstDml(txBody, "lstStyle") : null;
173
+ if (lstStyle) entry.style = parseLvl1Style(lstStyle);
174
+ const typeKey = `${rawType || "body"}:${idx}`;
175
+ if (!index.exact.has(typeKey)) index.exact.set(typeKey, entry);
176
+ const base = basePhType(rawType);
177
+ const baseIdxKey = `${base}:${idx}`;
178
+ if (!index.baseIdx.has(baseIdxKey)) index.baseIdx.set(baseIdxKey, entry);
179
+ if (!index.base.has(base)) index.base.set(base, entry);
180
+ }
181
+ return index;
182
+ }
183
+ function resolveFillColor(solidFill, hints) {
184
+ const srgb = firstDml(solidFill, "srgbClr");
185
+ const srgbVal = srgb?.getAttribute("val");
186
+ if (srgbVal && /^[0-9a-fA-F]{6}$/.test(srgbVal)) return `#${srgbVal.toLowerCase()}`;
187
+ const scheme = firstDml(solidFill, "schemeClr");
188
+ const schemeVal = scheme?.getAttribute("val");
189
+ if (schemeVal && hints.schemeColors?.[schemeVal]) return hints.schemeColors[schemeVal];
190
+ return void 0;
191
+ }
192
+ function directDmlChild(parent, local) {
193
+ for (let i = 0; i < parent.childNodes.length; i++) {
194
+ const child = parent.childNodes[i];
195
+ if (child && child.nodeType === 1 && child.localName === local) {
196
+ const el = child;
197
+ if (el.namespaceURI === NS_DRAWINGML) return el;
198
+ }
199
+ }
200
+ return null;
201
+ }
202
+ function extractDecoration(sp, sldSz, pxPerPt, hints) {
203
+ const rectEmu = readXfrm(sp);
204
+ if (!rectEmu) return null;
205
+ const spPr = firstPml(sp, "spPr");
206
+ if (!spPr) return null;
207
+ const prst = firstDml(spPr, "prstGeom")?.getAttribute("prst");
208
+ if (prst === "line" || prst === "straightConnector1") {
209
+ const ln = directDmlChild(spPr, "ln");
210
+ const lnFill = ln ? directDmlChild(ln, "solidFill") : null;
211
+ const stroke = lnFill ? resolveFillColor(lnFill, hints) : void 0;
212
+ if (!stroke) return null;
213
+ const wEmu = intAttr(ln, "w");
214
+ const strokeWidthPx = wEmu ? Math.max(1, Math.min(40, Math.round(wEmu / 12700 * pxPerPt))) : 2;
215
+ return { shape: "line", rect: emuToPct(rectEmu, sldSz), stroke, strokeWidthPx };
216
+ }
217
+ if (prst === "rect" || prst === "roundRect") {
218
+ const solidFill = directDmlChild(spPr, "solidFill");
219
+ const fill = solidFill ? resolveFillColor(solidFill, hints) : void 0;
220
+ if (!fill) return null;
221
+ const areaPct = rectEmu.cx * rectEmu.cy / (sldSz.cx * sldSz.cy) * 100;
222
+ if (areaPct < MIN_DECORATION_AREA_PCT) return null;
223
+ return {
224
+ shape: "rect",
225
+ rect: emuToPct(rectEmu, sldSz),
226
+ fill,
227
+ ...prst === "roundRect" ? { borderRadius: 8 } : {}
228
+ };
229
+ }
230
+ return null;
231
+ }
232
+ async function extractLayout(pkg, layoutPath, sldSz, pxPerPt, hints, masterCache, signal) {
233
+ throwIfOoxmlAborted(signal);
234
+ const doc = await getPartXml(pkg, layoutPath);
235
+ if (!doc) return null;
236
+ const name = firstPml(doc, "cSld")?.getAttribute("name")?.trim() ?? "";
237
+ const typeAttr = doc.documentElement?.getAttribute("type") ?? void 0;
238
+ let masterPath;
239
+ let master;
240
+ const layoutRels = await getPartRelationships(pkg, layoutPath);
241
+ const masterRel = findRelByType(layoutRels, REL_SLIDE_MASTER);
242
+ if (masterRel) {
243
+ masterPath = resolveTarget(baseDirOf(layoutPath), masterRel.target);
244
+ let cached = masterCache.get(masterPath);
245
+ if (!cached) {
246
+ cached = readMasterIndex(pkg, masterPath, signal);
247
+ masterCache.set(masterPath, cached);
248
+ }
249
+ master = await cached;
250
+ }
251
+ const placeholders = [];
252
+ const decorations = [];
253
+ const shapes = doc.getElementsByTagNameNS(NS_PML, "sp");
254
+ for (let i = 0; i < shapes.length; i++) {
255
+ await cancellationCheckpoint(i, signal);
256
+ const sp = shapes[i];
257
+ const ph = firstPml(sp, "ph");
258
+ if (!ph) {
259
+ if (decorations.length < MAX_DECORATIONS) {
260
+ const decoration = extractDecoration(sp, sldSz, pxPerPt, hints);
261
+ if (decoration) decorations.push(decoration);
262
+ }
263
+ continue;
264
+ }
265
+ const rawType = ph.getAttribute("type") ?? "";
266
+ if (CHROME_PH_TYPES.has(rawType)) continue;
267
+ const idx = intAttr(ph, "idx") ?? 0;
268
+ const kind = placeholderKind(rawType);
269
+ const own = readXfrm(sp);
270
+ let rectEmu = own;
271
+ let inheritedFromMaster = false;
272
+ if (!rectEmu && master) {
273
+ const base = basePhType(rawType);
274
+ const entry = master.exact.get(`${rawType || "body"}:${idx}`) ?? master.baseIdx.get(`${base}:${idx}`) ?? master.base.get(base);
275
+ if (entry?.rect) {
276
+ rectEmu = entry.rect;
277
+ inheritedFromMaster = true;
278
+ }
279
+ }
280
+ const rect = rectEmu ? emuToPct(rectEmu, sldSz) : kind === "title" ? { ...DEFAULT_TITLE_RECT } : { ...DEFAULT_BODY_RECT };
281
+ const txBody = firstPml(sp, "txBody");
282
+ const lstStyle = txBody ? firstDml(txBody, "lstStyle") : null;
283
+ let textStyle = lstStyle ? parseLvl1Style(lstStyle) : void 0;
284
+ if (master) {
285
+ const base = basePhType(rawType);
286
+ const masterEntry = master.exact.get(`${rawType || "body"}:${idx}`) ?? master.baseIdx.get(`${base}:${idx}`);
287
+ textStyle = mergeTextStyle(textStyle, masterEntry?.style);
288
+ textStyle = mergeTextStyle(
289
+ textStyle,
290
+ kind === "title" || kind === "subtitle" ? master.titleStyle : master.bodyStyle
291
+ );
292
+ }
293
+ const bodyPr = txBody ? firstDml(txBody, "bodyPr") : null;
294
+ const anchor = bodyPr?.getAttribute("anchor");
295
+ if (anchor === "t" || anchor === "ctr" || anchor === "b") {
296
+ textStyle = {
297
+ ...textStyle ?? {},
298
+ anchor: anchor === "t" ? "top" : anchor === "ctr" ? "middle" : "bottom"
299
+ };
300
+ }
301
+ const orient = ph.getAttribute("orient");
302
+ const vert = bodyPr?.getAttribute("vert");
303
+ const vertical = orient === "vert" || !!vert && vert !== "horz";
304
+ placeholders.push({
305
+ kind,
306
+ rawType,
307
+ idx,
308
+ rect,
309
+ inheritedFromMaster,
310
+ vertical,
311
+ ...textStyle ? { textStyle } : {}
312
+ });
313
+ }
314
+ return {
315
+ partPath: layoutPath,
316
+ name,
317
+ ...typeAttr ? { typeAttr } : {},
318
+ ...masterPath ? { masterPath } : {},
319
+ ...master?.name ? { masterName: master.name } : {},
320
+ placeholders,
321
+ decorations,
322
+ slideCount: 0
323
+ };
324
+ }
325
+ function overlap1D(aStart, aLen, bStart, bLen) {
326
+ return Math.max(0, Math.min(aStart + aLen, bStart + bLen) - Math.max(aStart, bStart));
327
+ }
328
+ function sideBySide(a, b) {
329
+ const xOverlap = overlap1D(a.x, a.w, b.x, b.w);
330
+ const yOverlap = overlap1D(a.y, a.h, b.y, b.h);
331
+ return xOverlap <= 0.15 * Math.min(a.w, b.w) && yOverlap >= 0.5 * Math.min(a.h, b.h) && a.w >= 25 && b.w >= 25;
332
+ }
333
+ function stackedAbove(a, b) {
334
+ const xOverlap = overlap1D(a.x, a.w, b.x, b.w);
335
+ const yOverlap = overlap1D(a.y, a.h, b.y, b.h);
336
+ return yOverlap <= 0.15 * Math.min(a.h, b.h) && xOverlap >= 0.5 * Math.min(a.w, b.w) && a.y < b.y;
337
+ }
338
+ function fullBleed(p) {
339
+ return p.w >= 85 && p.h >= 80;
340
+ }
341
+ function nearEqualWidth(a, b) {
342
+ return Math.abs(a.w - b.w) <= 0.15 * Math.max(a.w, b.w);
343
+ }
344
+ function rectsOverlap(a, b) {
345
+ return overlap1D(a.x, a.w, b.x, b.w) > 2 && overlap1D(a.y, a.h, b.y, b.h) > 2;
346
+ }
347
+ function centerX(r) {
348
+ return r.x + r.w / 2;
349
+ }
350
+ var PLAIN_LAYOUT_TYPES = /* @__PURE__ */ new Set([
351
+ "titleOnly",
352
+ "tx",
353
+ "obj",
354
+ "objOnly",
355
+ "objTx",
356
+ "txOverObj",
357
+ "objOverTx",
358
+ "tbl",
359
+ "chart",
360
+ "dgm",
361
+ "txAndChart",
362
+ "chartAndTx",
363
+ "vertTitleAndTxOverChart",
364
+ "txAndTwoObj",
365
+ "twoObjAndTx",
366
+ "twoObjOverTx",
367
+ "objAndTwoObj",
368
+ "twoObjAndObj",
369
+ "fourObj",
370
+ "vertTx",
371
+ "vertTitleAndTx",
372
+ "clipArtAndVertTx"
373
+ ]);
374
+ function stage1(typeAttr) {
375
+ if (!typeAttr || typeAttr === "cust") return null;
376
+ if (typeAttr === "title")
377
+ return { kind: "builtin", template: "title", paramSpec: "titleSubtitle" };
378
+ if (typeAttr === "secHead") return { kind: "builtin", template: "sectionHeader" };
379
+ if (typeAttr === "blank") return { kind: "skip" };
380
+ if (PLAIN_LAYOUT_TYPES.has(typeAttr)) return { kind: "plain" };
381
+ if (typeAttr === "picTx") return { kind: "feature-by-geometry" };
382
+ if (typeAttr === "clipArtAndTx" || typeAttr === "mediaAndTx") {
383
+ return { kind: "builtin", template: "leftFeature", paramSpec: "featureImage" };
384
+ }
385
+ if (typeAttr === "txAndClipArt" || typeAttr === "txAndMedia") {
386
+ return { kind: "builtin", template: "rightFeature", paramSpec: "featureImage" };
387
+ }
388
+ if (typeAttr === "twoColTx" || typeAttr === "twoObj" || typeAttr === "txAndObj" || typeAttr === "objAndTx") {
389
+ return { kind: "custom-two-column" };
390
+ }
391
+ if (typeAttr === "twoTxTwoObj") return { kind: "comparison" };
392
+ return null;
393
+ }
394
+ var WELL_KNOWN_NAMES = {
395
+ "title slide": { kind: "builtin", template: "title", paramSpec: "titleSubtitle" },
396
+ "section header": { kind: "builtin", template: "sectionHeader" },
397
+ "two content": { kind: "custom-two-column" },
398
+ comparison: { kind: "comparison" },
399
+ "content with caption": { kind: "custom-caption" },
400
+ "picture with caption": { kind: "feature-by-geometry" },
401
+ "title and content": { kind: "plain" },
402
+ "title only": { kind: "plain" },
403
+ blank: { kind: "skip" },
404
+ "vertical title and text": { kind: "plain" },
405
+ "title and vertical text": { kind: "plain" }
406
+ };
407
+ function stage2(name) {
408
+ return WELL_KNOWN_NAMES[name.trim().toLowerCase()] ?? null;
409
+ }
410
+ function contentPlaceholders(layout) {
411
+ return layout.placeholders.filter((p) => p.kind !== "title" && p.kind !== "subtitle");
412
+ }
413
+ function stage3(layout) {
414
+ if (layout.placeholders.some((p) => p.vertical)) return { kind: "plain" };
415
+ const hasTitle = layout.placeholders.some((p) => p.kind === "title");
416
+ const content = contentPlaceholders(layout);
417
+ if (content.length === 0) return hasTitle ? { kind: "plain" } : { kind: "skip" };
418
+ const texts = content.filter((p) => p.kind === "text");
419
+ const pictures = content.filter((p) => p.kind === "picture");
420
+ const others = content.filter((p) => p.kind !== "text" && p.kind !== "picture");
421
+ if (pictures.length === 0 && others.length === 0) {
422
+ if (texts.length === 1) return { kind: "plain" };
423
+ if (texts.length === 2 && sideBySide(texts[0].rect, texts[1].rect)) {
424
+ return nearEqualWidth(texts[0].rect, texts[1].rect) ? { kind: "custom-two-column" } : { kind: "custom-caption" };
425
+ }
426
+ if (texts.length === 4 && findComparisonColumns(texts)) return { kind: "comparison" };
427
+ return { kind: "plain" };
428
+ }
429
+ if (pictures.length === 1 && others.length === 0) {
430
+ if (texts.length === 0) {
431
+ return fullBleed(pictures[0].rect) ? { kind: "builtin", template: "imageWithCaption", paramSpec: "featureImage" } : { kind: "custom-generic" };
432
+ }
433
+ return { kind: "feature-by-geometry" };
434
+ }
435
+ if (pictures.length >= 2 && pictures.length <= 4 && texts.length === 0 && others.length === 0 && pictures.every((a, i) => pictures.every((b, j) => i === j || !rectsOverlap(a.rect, b.rect)))) {
436
+ return { kind: "builtin", template: "photoGrid", paramSpec: "photoGridGate" };
437
+ }
438
+ return { kind: "plain" };
439
+ }
440
+ function findComparisonColumns(texts) {
441
+ if (texts.length !== 4) return null;
442
+ const sorted = [...texts].sort((a, b) => centerX(a.rect) - centerX(b.rect));
443
+ const leftPair = [sorted[0], sorted[1]];
444
+ const rightPair = [sorted[2], sorted[3]];
445
+ const columnWidth = (pair) => Math.abs(centerX(pair[0].rect) - centerX(pair[1].rect));
446
+ if (columnWidth(leftPair) > 10 || columnWidth(rightPair) > 10) return null;
447
+ if (centerX(rightPair[0].rect) - centerX(leftPair[1].rect) <= 10) return null;
448
+ const orderColumn = (pair) => {
449
+ const byY = [...pair].sort((a, b) => a.rect.y - b.rect.y);
450
+ const header = byY[0];
451
+ const body = byY[1];
452
+ if (header.rect.h > 20 || header.rect.y + header.rect.h > body.rect.y + 2) return null;
453
+ return [header.idx, body.idx];
454
+ };
455
+ const left = orderColumn(leftPair);
456
+ const right = orderColumn(rightPair);
457
+ return left && right ? { left, right } : null;
458
+ }
459
+ function slugify(name) {
460
+ const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
461
+ return slug;
462
+ }
463
+ function pctPosition(rect) {
464
+ return { x: `${rect.x}%`, y: `${rect.y}%`, width: `${rect.w}%`, height: `${rect.h}%` };
465
+ }
466
+ function fontPx(pt, defaultPt, pxPerPt) {
467
+ const sizePt = pt && pt > 0 ? pt : defaultPt;
468
+ return Math.max(16, Math.min(140, Math.round(sizePt * pxPerPt)));
469
+ }
470
+ function textLayerFor(id, ph, text, role, gen) {
471
+ const defaultPt = role === "title" ? DEFAULT_TITLE_PT : role === "subtitle" ? DEFAULT_SUBTITLE_PT : DEFAULT_BODY_PT;
472
+ const style = {
473
+ fontSize: fontPx(ph.textStyle?.fontSizePt, defaultPt, gen.pxPerPt),
474
+ color: gen.hints.text ?? "#1a1a1a",
475
+ lineHeight: role === "title" ? 1.15 : 1.4,
476
+ ...role === "title" ? { fontWeight: ph.textStyle?.bold === false ? "normal" : "bold" } : ph.textStyle?.bold ? { fontWeight: "bold" } : {},
477
+ ...ph.textStyle?.align ? { textAlign: ph.textStyle.align } : {},
478
+ ...ph.textStyle?.anchor ? { verticalAlign: ph.textStyle.anchor } : {}
479
+ };
480
+ return { id, type: "text", position: pctPosition(ph.rect), content: { text, style } };
481
+ }
482
+ function imageLayerFor(id, ph, imageIndex) {
483
+ return {
484
+ id,
485
+ type: "image",
486
+ position: pctPosition(ph.rect),
487
+ content: { src: `{image:${imageIndex}}`, alt: `{image:${imageIndex}}`, fit: "cover" }
488
+ };
489
+ }
490
+ function decorationLayers(layout) {
491
+ return layout.decorations.map((d, i) => ({
492
+ id: `decor-${i + 1}`,
493
+ type: "shape",
494
+ position: pctPosition(d.rect),
495
+ content: d.shape === "line" ? { shape: "line", stroke: d.stroke, strokeWidth: d.strokeWidthPx ?? 2 } : {
496
+ shape: "rect",
497
+ fill: d.fill,
498
+ ...d.borderRadius ? { borderRadius: d.borderRadius } : {}
499
+ }
500
+ }));
501
+ }
502
+ function titlePlaceholder(layout) {
503
+ return layout.placeholders.find((p) => p.kind === "title");
504
+ }
505
+ function defaultTitlePlaceholder() {
506
+ return {
507
+ kind: "title",
508
+ rawType: "title",
509
+ idx: 0,
510
+ rect: { ...DEFAULT_TITLE_RECT },
511
+ inheritedFromMaster: false,
512
+ vertical: false
513
+ };
514
+ }
515
+ function buildTwoColumnDef(layout, gen) {
516
+ const texts = contentPlaceholders(layout).filter((p) => p.kind === "text");
517
+ let left;
518
+ let right;
519
+ const sorted = [...texts].sort((a, b) => a.rect.x - b.rect.x);
520
+ if (sorted.length >= 2 && sideBySide(sorted[0].rect, sorted[sorted.length - 1].rect)) {
521
+ left = sorted[0];
522
+ right = sorted[sorted.length - 1];
523
+ } else {
524
+ left = {
525
+ ...defaultTitlePlaceholder(),
526
+ kind: "text",
527
+ rawType: "body",
528
+ rect: { x: 5, y: 23.3, w: 43, h: 66 }
529
+ };
530
+ right = { ...left, rect: { x: 52, y: 23.3, w: 43, h: 66 } };
531
+ }
532
+ const gap = Math.max(0, Math.round((right.rect.x - (left.rect.x + left.rect.w)) * 100) / 100);
533
+ const layers = [...decorationLayers(layout)];
534
+ const title = titlePlaceholder(layout) ?? defaultTitlePlaceholder();
535
+ layers.push(textLayerFor("title", title, "{title}", "title", gen));
536
+ const itemLayer = {
537
+ ...textLayerFor("column", left, "{item}", "body", gen),
538
+ // gap is in percentage points because the layer's width is a %-string;
539
+ // the repeat resolver offsets clones by width + gap in the same unit.
540
+ repeat: { source: "listItems", direction: "row", gap, max: 2 }
541
+ };
542
+ layers.push(itemLayer);
543
+ return layers;
544
+ }
545
+ function buildCaptionDef(layout, gen) {
546
+ const texts = contentPlaceholders(layout).filter((p) => p.kind === "text");
547
+ const byWidth = [...texts].sort((a, b) => b.rect.w - a.rect.w);
548
+ const wide = byWidth[0];
549
+ const narrow = byWidth[1];
550
+ const layers = [...decorationLayers(layout)];
551
+ const title = titlePlaceholder(layout) ?? defaultTitlePlaceholder();
552
+ layers.push(textLayerFor("title", title, "{title}", "title", gen));
553
+ if (wide) layers.push(textLayerFor("body", wide, "{content}", "body", gen));
554
+ if (narrow) {
555
+ layers.push(textLayerFor("caption", narrow, "{attr:caption|}", "body", gen));
556
+ }
557
+ return layers;
558
+ }
559
+ function buildGenericDef(layout, gen) {
560
+ const layers = [...decorationLayers(layout)];
561
+ const title = titlePlaceholder(layout);
562
+ if (title) layers.push(textLayerFor("title", title, "{title}", "title", gen));
563
+ const content = contentPlaceholders(layout);
564
+ const pictures = content.filter((p) => p.kind === "picture").sort((a, b) => a.idx - b.idx || a.rect.y - b.rect.y);
565
+ pictures.forEach((ph, k) => layers.push(imageLayerFor(`image-${k}`, ph, k)));
566
+ const texts = content.filter((p) => p.kind === "text");
567
+ if (texts.length > 0) layers.push(textLayerFor("body", texts[0], "{content}", "body", gen));
568
+ if (texts.length > 1) {
569
+ gen.notes.push(
570
+ `${texts.length - 1} additional text region(s) could not be bound \u2014 the token grammar has no per-region address; full text stays in the markdown body.`
571
+ );
572
+ }
573
+ const dropped = content.filter(
574
+ (p) => p.kind === "table" || p.kind === "chart" || p.kind === "other"
575
+ );
576
+ if (dropped.length > 0) {
577
+ gen.notes.push(
578
+ `${dropped.length} table/chart placeholder(s) dropped (content flows as markdown).`
579
+ );
580
+ }
581
+ return layers;
582
+ }
583
+ function hasContentLayer(layers) {
584
+ return layers.some((l) => l.type === "text" || l.type === "image");
585
+ }
586
+ function resolveFeatureByGeometry(layout) {
587
+ const content = contentPlaceholders(layout);
588
+ const pic = content.find((p) => p.kind === "picture");
589
+ if (!pic) return { kind: "plain" };
590
+ const texts = content.filter((p) => p.kind === "text");
591
+ const beside = texts.find((t) => sideBySide(pic.rect, t.rect));
592
+ if (beside) {
593
+ const template = centerX(pic.rect) < centerX(beside.rect) ? "leftFeature" : "rightFeature";
594
+ return { kind: "builtin", template, paramSpec: "featureImage" };
595
+ }
596
+ if (texts.some((t) => stackedAbove(pic.rect, t.rect)) || fullBleed(pic.rect)) {
597
+ return { kind: "builtin", template: "imageWithCaption", paramSpec: "featureImage" };
598
+ }
599
+ return { kind: "builtin", template: "leftFeature", paramSpec: "featureImage" };
600
+ }
601
+ function classifyLayout(layout) {
602
+ return stage1(layout.typeAttr) ?? stage2(layout.name) ?? stage3(layout);
603
+ }
604
+ function resolveVerdict(layout, directive, gen, templateName) {
605
+ switch (directive.kind) {
606
+ case "plain":
607
+ case "skip":
608
+ return { kind: directive.kind };
609
+ case "builtin":
610
+ return directive;
611
+ case "feature-by-geometry":
612
+ return resolveFeatureByGeometry(layout);
613
+ case "comparison": {
614
+ const texts = contentPlaceholders(layout).filter((p) => p.kind === "text");
615
+ const columns = findComparisonColumns(texts);
616
+ if (!columns) return { kind: "plain" };
617
+ return { kind: "builtin", template: "twoColumn", paramSpec: "comparisonPairs", columns };
618
+ }
619
+ case "custom-two-column":
620
+ case "custom-caption":
621
+ case "custom-generic":
622
+ case "by-geometry": {
623
+ const layers = directive.kind === "custom-two-column" ? buildTwoColumnDef(layout, gen) : directive.kind === "custom-caption" ? buildCaptionDef(layout, gen) : buildGenericDef(layout, gen);
624
+ if (!hasContentLayer(layers)) return { kind: "plain" };
625
+ const def = {
626
+ name: templateName,
627
+ label: layout.name || "Imported layout",
628
+ description: `Imported from PowerPoint layout "${layout.name || templateName}"${layout.masterName ? ` (master "${layout.masterName}")` : ""}`,
629
+ viewport: gen.viewport,
630
+ layers
631
+ };
632
+ return { kind: "custom", def };
633
+ }
634
+ }
635
+ }
636
+ async function readSlideSize(pkg, signal) {
637
+ throwIfOoxmlAborted(signal);
638
+ const pres = await getPartXml(pkg, "ppt/presentation.xml");
639
+ const sldSz = pres ? firstPml(pres, "sldSz") : null;
640
+ const cx = intAttr(sldSz, "cx");
641
+ const cy = intAttr(sldSz, "cy");
642
+ if (cx && cy && cx > 0 && cy > 0) return { cx, cy };
643
+ return { ...DEFAULT_SLIDE_SIZE };
644
+ }
645
+ async function orderedSlidePathsForLayouts(pkg, signal) {
646
+ throwIfOoxmlAborted(signal);
647
+ const pres = await getPartXml(pkg, "ppt/presentation.xml");
648
+ if (!pres) return [];
649
+ const rels = await getPartRelationships(pkg, "ppt/presentation.xml");
650
+ const relById = new Map(rels.map((r) => [r.id, r.target]));
651
+ const out = [];
652
+ const ids = pres.getElementsByTagNameNS(NS_PML, "sldId");
653
+ for (let i = 0; i < ids.length; i++) {
654
+ await cancellationCheckpoint(i, signal);
655
+ const rid = attrNS(ids[i], NS_R, "id", "r:id");
656
+ const target = rid ? relById.get(rid) : void 0;
657
+ if (target) out.push(resolveTarget("ppt", target));
658
+ }
659
+ return out;
660
+ }
661
+ function viewportFor(sldSz) {
662
+ if (sldSz.cy > sldSz.cx) {
663
+ return { width: 1080, height: Math.round(1080 * sldSz.cy / sldSz.cx) };
664
+ }
665
+ return { width: Math.round(1080 * sldSz.cx / sldSz.cy), height: 1080 };
666
+ }
667
+ async function analyzePptxLayouts(pkg, options = {}) {
668
+ throwIfOoxmlAborted(options.signal);
669
+ const warnings = [];
670
+ const hints = options.colors ?? {};
671
+ const maxTemplates = options.maxTemplates ?? MAX_INFERRED_TEMPLATES;
672
+ const sldSz = await readSlideSize(pkg, options.signal);
673
+ const viewport = viewportFor(sldSz);
674
+ const pxPerPt = viewport.height / (sldSz.cy / 12700);
675
+ const slidePaths = await orderedSlidePathsForLayouts(pkg, options.signal);
676
+ const layoutPathBySlide = /* @__PURE__ */ new Map();
677
+ const usage = /* @__PURE__ */ new Map();
678
+ const orderedLayoutPaths = [];
679
+ for (let slideIndex = 0; slideIndex < slidePaths.length; slideIndex++) {
680
+ await cancellationCheckpoint(slideIndex, options.signal);
681
+ const slidePath = slidePaths[slideIndex];
682
+ const rels = await getPartRelationships(pkg, slidePath);
683
+ const layoutRel = findRelByType(rels, REL_SLIDE_LAYOUT);
684
+ if (!layoutRel) continue;
685
+ const layoutPath = resolveTarget(baseDirOf(slidePath), layoutRel.target);
686
+ layoutPathBySlide.set(slidePath, layoutPath);
687
+ if (!usage.has(layoutPath)) orderedLayoutPaths.push(layoutPath);
688
+ usage.set(layoutPath, (usage.get(layoutPath) ?? 0) + 1);
689
+ }
690
+ if (options.includeUnused) {
691
+ const unused = [];
692
+ let partIndex = 0;
693
+ for (const [partPath, contentType] of pkg.contentTypes.overrides) {
694
+ await cancellationCheckpoint(partIndex++, options.signal);
695
+ if (contentType === CONTENT_TYPE_PPTX_SLIDE_LAYOUT && !usage.has(partPath)) {
696
+ unused.push(partPath);
697
+ }
698
+ }
699
+ unused.sort();
700
+ orderedLayoutPaths.push(...unused);
701
+ }
702
+ const masterCache = /* @__PURE__ */ new Map();
703
+ const layouts = [];
704
+ const usedNames = /* @__PURE__ */ new Set();
705
+ for (let i = 0; i < orderedLayoutPaths.length; i++) {
706
+ await cancellationCheckpoint(i, options.signal);
707
+ const layoutPath = orderedLayoutPaths[i];
708
+ const extracted = await extractLayout(
709
+ pkg,
710
+ layoutPath,
711
+ sldSz,
712
+ pxPerPt,
713
+ hints,
714
+ masterCache,
715
+ options.signal
716
+ );
717
+ if (!extracted) {
718
+ warnings.push(`layout ${layoutPath} could not be read; its slides import plain`);
719
+ continue;
720
+ }
721
+ extracted.slideCount = usage.get(layoutPath) ?? 0;
722
+ const baseSlug = slugify(extracted.name) || `layout-${i + 1}`;
723
+ let templateName = `pptx-${baseSlug}`;
724
+ for (let n = 2; usedNames.has(templateName); n++) templateName = `pptx-${baseSlug}-${n}`;
725
+ const notes = [];
726
+ const gen = { hints, pxPerPt, viewport, notes };
727
+ const directive = classifyLayout(extracted);
728
+ const verdict = resolveVerdict(extracted, directive, gen, templateName);
729
+ if (verdict.kind === "custom") usedNames.add(templateName);
730
+ layouts.push({ extracted, verdict, notes });
731
+ }
732
+ const customs = layouts.filter((l) => l.verdict.kind === "custom");
733
+ if (customs.length > maxTemplates) {
734
+ const ranked = [...customs].sort((a, b) => b.extracted.slideCount - a.extracted.slideCount);
735
+ const excess = ranked.slice(maxTemplates);
736
+ for (let index = 0; index < excess.length; index++) {
737
+ await cancellationCheckpoint(index, options.signal);
738
+ const layout = excess[index];
739
+ layout.verdict = { kind: "plain" };
740
+ layout.notes.push("dropped: more inferred layouts than the template cap");
741
+ }
742
+ warnings.push(
743
+ `deck defines ${customs.length} distinctive layouts; kept the ${maxTemplates} most used as custom templates`
744
+ );
745
+ }
746
+ const byLayoutPath = new Map(layouts.map((l) => [l.extracted.partPath, l]));
747
+ throwIfOoxmlAborted(options.signal);
748
+ return { slideSize: sldSz, layouts, byLayoutPath, layoutPathBySlide, warnings };
749
+ }
750
+ async function inspectPptxLayouts(data, options = {}) {
751
+ throwIfOoxmlAborted(options.signal);
752
+ const pkg = await openPackage(data, options);
753
+ const analysis = await analyzePptxLayouts(pkg, options);
754
+ const layouts = [];
755
+ for (let i = 0; i < analysis.layouts.length; i++) {
756
+ await cancellationCheckpoint(i, options.signal);
757
+ const l = analysis.layouts[i];
758
+ const { extracted, verdict, notes } = l;
759
+ layouts.push({
760
+ layoutPath: extracted.partPath,
761
+ name: extracted.name || `Layout ${i + 1}`,
762
+ ...extracted.masterName ? { masterName: extracted.masterName } : {},
763
+ ...extracted.typeAttr ? { typeAttr: extracted.typeAttr } : {},
764
+ slideCount: extracted.slideCount,
765
+ verdict: verdict.kind,
766
+ ...verdict.kind === "builtin" ? { builtinTemplate: verdict.template } : {},
767
+ ...verdict.kind === "custom" ? { customTemplate: verdict.def } : {},
768
+ ...notes.length > 0 ? { notes } : {}
769
+ });
770
+ }
771
+ return { layouts, slideSize: analysis.slideSize };
772
+ }
773
+
774
+ export {
775
+ analyzePptxLayouts,
776
+ inspectPptxLayouts
777
+ };
778
+ //# sourceMappingURL=chunk-VSYHZECT.js.map