@shbernal/ts-pptx 3.4.0 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.d.ts +2 -2
- package/dist/browser.js +1 -1
- package/dist/{diagnostics-B0OmTOoz.d.ts → diagnostics-BDuR8UkG.d.ts} +3 -3
- package/dist/{diagnostics-B0OmTOoz.d.ts.map → diagnostics-BDuR8UkG.d.ts.map} +1 -1
- package/dist/{errors-fB1KDJKQ.d.ts → errors-CgnueTYL.d.ts} +3 -3
- package/dist/{errors-fB1KDJKQ.d.ts.map → errors-CgnueTYL.d.ts.map} +1 -1
- package/dist/html.d.ts +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/inspect.d.ts +28 -4
- package/dist/inspect.d.ts.map +1 -1
- package/dist/inspect.js +41 -9
- package/dist/inspect.js.map +1 -1
- package/dist/math.d.ts +1 -1
- package/dist/measure.d.ts +1 -1
- package/dist/{namespaces-Sy_m7Nhd.js → namespaces-CcKuzeuE.js} +5 -2
- package/dist/{namespaces-Sy_m7Nhd.js.map → namespaces-CcKuzeuE.js.map} +1 -1
- package/dist/node.d.ts +2 -2
- package/dist/node.js +1 -1
- package/dist/{notes-bWApshah.js → notes-DNqAggXx.js} +2 -2
- package/dist/{notes-bWApshah.js.map → notes-DNqAggXx.js.map} +1 -1
- package/dist/{presentation-3rAKKRfm.js → presentation-VfJ_FT7E.js} +156 -8
- package/dist/presentation-VfJ_FT7E.js.map +1 -0
- package/dist/{presentation-types-D7cgT-eG.d.ts → presentation-types-CpkTx9Xa.d.ts} +165 -4
- package/dist/presentation-types-CpkTx9Xa.d.ts.map +1 -0
- package/dist/read.d.ts +3 -3
- package/dist/read.js +3 -3
- package/dist/script.d.ts +2 -2
- package/dist/script.d.ts.map +1 -1
- package/dist/script.js +68 -30
- package/dist/script.js.map +1 -1
- package/dist/{shapes-Dyw5bxwO.js → shapes-Kt51vry6.js} +357 -13
- package/dist/shapes-Kt51vry6.js.map +1 -0
- package/dist/{text-DSN3anEh.js → text-D04NUMvA.js} +4 -4
- package/dist/{text-DSN3anEh.js.map → text-D04NUMvA.js.map} +1 -1
- package/dist/zip.d.ts +1 -1
- package/package.json +1 -1
- package/dist/presentation-3rAKKRfm.js.map +0 -1
- package/dist/presentation-types-D7cgT-eG.d.ts.map +0 -1
- package/dist/shapes-Dyw5bxwO.js.map +0 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { i as PackageReadError, n as InvalidOptionError, o as UnsupportedFeatureError, t as InternalError } from "./errors-Bvln0H-7.js";
|
|
2
2
|
import { mt as emuToInches } from "./units-internal-DNvK2I6o.js";
|
|
3
|
-
import { D as voidEl, E as raw, T as el, g as FONT_REL_TYPE, h as FONT_DATA_EXTENSION, m as FONT_DATA_CONTENT_TYPE, n as makeXmlNotesMaster, o as makeXmlNotesSlideSkeleton, p as EMBEDDED_FONT_SLOTS } from "./notes-
|
|
4
|
-
import { _ as
|
|
3
|
+
import { D as voidEl, E as raw, T as el, g as FONT_REL_TYPE, h as FONT_DATA_EXTENSION, m as FONT_DATA_CONTENT_TYPE, n as makeXmlNotesMaster, o as makeXmlNotesSlideSkeleton, p as EMBEDDED_FONT_SLOTS } from "./notes-DNqAggXx.js";
|
|
4
|
+
import { _ as THEME_CONTENT_TYPE, a as NOTES_MASTER_REL, c as OFFICE_DOCUMENT_REL, d as SLIDE_CONTENT_TYPE, f as SLIDE_LAYOUT_CONTENT_TYPE, g as SLIDE_REL, h as SLIDE_MASTER_REL, i as NOTES_MASTER_CONTENT_TYPE, l as OFFICE_REL, m as SLIDE_MASTER_CONTENT_TYPE, o as NOTES_SLIDE_CONTENT_TYPE, p as SLIDE_LAYOUT_REL, r as IMAGE_REL, s as NOTES_SLIDE_REL, t as OOXML_NS, v as THEME_REL } from "./namespaces-CcKuzeuE.js";
|
|
5
5
|
import { ZipWriter, readZip } from "./zip.js";
|
|
6
|
-
import { $ as
|
|
6
|
+
import { $ as carriedDecorations, A as spPrXfrmEmu, At as resolveSingleRel, Bt as getElements, Ct as SPPR_SCENE3D_AFTER, Dt as relativePartName, Et as partNameToZipPath, F as resolveLayoutColorContext, Ft as createElement, G as placeholderInheritedListStyles, Gt as parseXml, H as RUN_PROP_NAMES, Ht as insertInOrder, I as resolveMasterColorContext, It as descendantsByTag, J as placeholderOf, Jt as replaceInParent, K as placeholderInheritedRunProps, Kt as removeAttr, L as resolveNotesColorContext, Lt as escapeXmlAttribute, M as readPictureFill, Mt as attr, N as readGradientFill, Nt as boolValue, Ot as relsPartNameFor, P as resolveColorElement, Pt as childElements, Q as cSldOf, R as resolveSlideColorContext, Rt as firstChild, St as SPPR_LN_AFTER, T as AutoShape, Tt as partNameExtension, U as placeholderInheritedAnchor, Ut as intValue, V as LST_STYLE_LEVELS, Vt as getOrAddChild, W as placeholderInheritedColor, Wt as ownerDocumentOf, X as slideDefinesProp, Xt as setAttr, Y as slideDefinesColor, Yt as serializeXml, Z as cSldName, _t as RPR_FILL_AFTER, at as SCHEME_SLOTS, bt as SPPR_EFFECT_AFTER, ct as isA, dt as resolveColor, et as collectElements, ft as resolveSchemeToken, gt as FILL_CHOICES, ht as substitutePhClr, it as spTreeOf, j as readPatternFill, jt as zipPathToPartName, k as TextFrame, kt as resolveRelativePartName, l as wrapShapeElement, lt as parseClrMap, mt as styleRefLine, n as buildShapes, nt as nthShapeChild, ot as fmtEntry, pt as styleRefFill, q as placeholderInheritedXfrm, qt as removeChildrenByQName, r as findShapeByIdDeep, rt as nvPrOf, st as intAttr, t as GroupShape, tt as firstShapeChild, u as GraphicFrame, ut as parseClrScheme, vt as SHAPE_AFTER_SPPR, w as Picture, wt as SPPR_SP3D_AFTER, xt as SPPR_FILL_AFTER, yt as SPPR_AFTER_XFRM, z as resolveSlideThemeParts, zt as firstChildElement } from "./shapes-Kt51vry6.js";
|
|
7
7
|
//#region src/read/opc/content-types.ts
|
|
8
8
|
/**
|
|
9
9
|
* Overlay over `[Content_Types].xml`, used to resolve part content types at
|
|
@@ -1391,6 +1391,148 @@ function duplicateSubtree(opc, partName, copies) {
|
|
|
1391
1391
|
return fresh;
|
|
1392
1392
|
}
|
|
1393
1393
|
//#endregion
|
|
1394
|
+
//#region src/read/api/ops/part-reuse.ts
|
|
1395
|
+
/**
|
|
1396
|
+
* Recognising a part the destination deck **already holds**, so an import binds to it
|
|
1397
|
+
* instead of copying it in again.
|
|
1398
|
+
*
|
|
1399
|
+
* The case this exists for is the deck templated from its own source. `fromTemplate`
|
|
1400
|
+
* keeps a package's masters, layouts and theme byte-identical and strips only its
|
|
1401
|
+
* slides, so a script that then imports a slide back out of that same file hands
|
|
1402
|
+
* `copyPart` a `slideLayout -> slideMaster -> theme` subgraph whose every part is
|
|
1403
|
+
* already in the destination under its own partname. The copy registry maps *source*
|
|
1404
|
+
* partnames to copies this import made and knows nothing about what the destination
|
|
1405
|
+
* arrived with, so each of those parts was copied again: the output grew a duplicate
|
|
1406
|
+
* layout and master per imported slide, visible in PowerPoint's layout picker and
|
|
1407
|
+
* enough to make a later `appendSlides({ layout: <name> })` ambiguous.
|
|
1408
|
+
*
|
|
1409
|
+
* The test is deliberately strict, because the cost of getting it wrong is a slide
|
|
1410
|
+
* bound to chrome that only resembles what it asked for. A part is reusable only when
|
|
1411
|
+
* the destination holds it at the *same partname*, with the same content type, the same
|
|
1412
|
+
* bytes (as they would be written, so an edited destination part disqualifies itself),
|
|
1413
|
+
* the same relationships, and the same rule applied recursively to everything those
|
|
1414
|
+
* relationships reach. Byte-equality all the way down means "reuse" and "copy" produce
|
|
1415
|
+
* the same rendering; anything less falls back to the copy, which is always correct and
|
|
1416
|
+
* merely wasteful.
|
|
1417
|
+
*
|
|
1418
|
+
* Two further conditions have nothing to do with identity and everything to do with the
|
|
1419
|
+
* destination being a real deck: a reused master must already be registered in
|
|
1420
|
+
* `presentation.xml`, and a reused layout must already sit in a registered master's
|
|
1421
|
+
* `p:sldLayoutIdLst`. An identical part that is an orphan in the destination is not
|
|
1422
|
+
* something to bind a slide to, and the copy path (which registers and links what it
|
|
1423
|
+
* copies) is the right answer there.
|
|
1424
|
+
*
|
|
1425
|
+
* Reuse mutates nothing, which is what lets it hold across repeated imports: the
|
|
1426
|
+
* destination's chrome stays byte-identical, so the second import recognises it exactly
|
|
1427
|
+
* as the first one did.
|
|
1428
|
+
*/
|
|
1429
|
+
/**
|
|
1430
|
+
* Whether the destination already holds `sourcePartName`'s subgraph, part for part and
|
|
1431
|
+
* byte for byte, in a state an imported slide can bind to.
|
|
1432
|
+
*
|
|
1433
|
+
* @param dest the deck being imported into
|
|
1434
|
+
* @param source the package being imported out of
|
|
1435
|
+
* @param sourcePartName the part the copy is about to make
|
|
1436
|
+
* @return `true` when the copy can be skipped and the existing part used
|
|
1437
|
+
*/
|
|
1438
|
+
function destinationAlreadyHolds(dest, source, sourcePartName) {
|
|
1439
|
+
const part = dest.opc.part(sourcePartName);
|
|
1440
|
+
if (!part || part.contentType === "application/vnd.openxmlformats-officedocument.presentationml.slide+xml") return false;
|
|
1441
|
+
if (!identicalSubgraph(dest.opc, source, sourcePartName, /* @__PURE__ */ new Set())) return false;
|
|
1442
|
+
return wiredIntoDeck(dest, sourcePartName);
|
|
1443
|
+
}
|
|
1444
|
+
/**
|
|
1445
|
+
* `partName` and everything it reaches are the same in both packages: same content type,
|
|
1446
|
+
* same body bytes, same relationships, recursively.
|
|
1447
|
+
*
|
|
1448
|
+
* The destination side is compared as it would be **written** (`serialize()`), not as it
|
|
1449
|
+
* was read, so a part some earlier edit marked dirty is treated as different even when
|
|
1450
|
+
* the edit was a no-op. Under-reusing costs a duplicated part; over-reusing binds a slide
|
|
1451
|
+
* to something else's chrome.
|
|
1452
|
+
*
|
|
1453
|
+
* The traversal skips exactly what `copyPart` skips — the notes relationship, and a
|
|
1454
|
+
* master's relationships to its layouts — so it asks about the subgraph the copy would
|
|
1455
|
+
* actually have made. Skipping the master's layout list is what keeps one edited layout
|
|
1456
|
+
* from disqualifying every *other* layout that shares its master.
|
|
1457
|
+
*/
|
|
1458
|
+
function identicalSubgraph(dest, source, partName, visited) {
|
|
1459
|
+
if (visited.has(partName)) return true;
|
|
1460
|
+
visited.add(partName);
|
|
1461
|
+
const sourcePart = source.part(partName);
|
|
1462
|
+
const destPart = dest.part(partName);
|
|
1463
|
+
if (!sourcePart || !destPart) return false;
|
|
1464
|
+
if (sourcePart.contentType !== destPart.contentType) return false;
|
|
1465
|
+
if (!bytesEqual(sourcePart.bytes, destPart.serialize())) return false;
|
|
1466
|
+
const sourceRels = [...source.relationshipsFor(partName)];
|
|
1467
|
+
const destRels = [...dest.relationshipsFor(partName)];
|
|
1468
|
+
if (sourceRels.length !== destRels.length) return false;
|
|
1469
|
+
const isMaster = sourcePart.contentType === SLIDE_MASTER_CONTENT_TYPE;
|
|
1470
|
+
const destById = new Map(destRels.map((rel) => [rel.id, rel]));
|
|
1471
|
+
for (const rel of sourceRels) {
|
|
1472
|
+
const counterpart = destById.get(rel.id);
|
|
1473
|
+
if (!counterpart) return false;
|
|
1474
|
+
if (counterpart.type !== rel.type || counterpart.targetMode !== rel.targetMode) return false;
|
|
1475
|
+
if (rel.targetMode === "External") {
|
|
1476
|
+
if (counterpart.target !== rel.target) return false;
|
|
1477
|
+
continue;
|
|
1478
|
+
}
|
|
1479
|
+
const target = source.relationshipsFor(partName).resolveTarget(rel.id);
|
|
1480
|
+
if (dest.relationshipsFor(partName).resolveTarget(rel.id) !== target) return false;
|
|
1481
|
+
if (rel.type === "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide") continue;
|
|
1482
|
+
if (isMaster && rel.type === "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout") continue;
|
|
1483
|
+
if (!identicalSubgraph(dest, source, target, visited)) return false;
|
|
1484
|
+
}
|
|
1485
|
+
return true;
|
|
1486
|
+
}
|
|
1487
|
+
/**
|
|
1488
|
+
* Whether the destination's copy of this part is wired into the deck, for the two kinds
|
|
1489
|
+
* where "present in the package" is not the same as "usable".
|
|
1490
|
+
*
|
|
1491
|
+
* A master absent from `p:sldMasterIdLst` is inert: renderers ignore its background and
|
|
1492
|
+
* shape tree, so a slide bound through it renders blank. A layout absent from a
|
|
1493
|
+
* registered master's `p:sldLayoutIdLst` is not in the deck's gallery, so `layouts()`
|
|
1494
|
+
* cannot name it and `appendSlides` cannot bind to it. Every other kind (theme, media,
|
|
1495
|
+
* table styles) is reached by relationship alone and needs no registration.
|
|
1496
|
+
*/
|
|
1497
|
+
function wiredIntoDeck(dest, partName) {
|
|
1498
|
+
const contentType = dest.opc.part(partName)?.contentType;
|
|
1499
|
+
if (contentType === "application/vnd.openxmlformats-officedocument.presentationml.slideMaster+xml") return registeredMasters(dest).includes(partName);
|
|
1500
|
+
if (contentType === "application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml") return registeredMasters(dest).some((master) => galleryOf(dest, master).includes(partName));
|
|
1501
|
+
return true;
|
|
1502
|
+
}
|
|
1503
|
+
/** The destination's masters in `p:sldMasterIdLst` order — the ones renderers treat as active. */
|
|
1504
|
+
function registeredMasters(dest) {
|
|
1505
|
+
const root = dest.presentationPart.dom.documentElement;
|
|
1506
|
+
const lst = root && firstChild(root, "p:sldMasterIdLst");
|
|
1507
|
+
if (!lst) return [];
|
|
1508
|
+
const rels = presentationRels(dest);
|
|
1509
|
+
return idListTargets(lst, "p:sldMasterId", (relId) => rels.resolveTarget(relId));
|
|
1510
|
+
}
|
|
1511
|
+
/** One master's layouts in `p:sldLayoutIdLst` order — its slice of the deck's gallery. */
|
|
1512
|
+
function galleryOf(dest, masterPartName) {
|
|
1513
|
+
const root = dest.opc.part(masterPartName)?.dom.documentElement;
|
|
1514
|
+
const lst = root && firstChild(root, "p:sldLayoutIdLst");
|
|
1515
|
+
if (!lst) return [];
|
|
1516
|
+
const rels = dest.opc.relationshipsFor(masterPartName);
|
|
1517
|
+
return idListTargets(lst, "p:sldLayoutId", (relId) => rels.resolveTarget(relId));
|
|
1518
|
+
}
|
|
1519
|
+
/** Resolve every `@r:id` in an id list to its partname, skipping entries that carry none. */
|
|
1520
|
+
function idListTargets(lst, qname, resolve) {
|
|
1521
|
+
const out = [];
|
|
1522
|
+
for (const entry of getElements(lst, qname)) {
|
|
1523
|
+
const relId = attr(entry, "r:id");
|
|
1524
|
+
if (relId) out.push(resolve(relId));
|
|
1525
|
+
}
|
|
1526
|
+
return out;
|
|
1527
|
+
}
|
|
1528
|
+
/** Byte-for-byte equality of two part bodies. */
|
|
1529
|
+
function bytesEqual(a, b) {
|
|
1530
|
+
if (a === b) return true;
|
|
1531
|
+
if (a.length !== b.length) return false;
|
|
1532
|
+
for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
|
|
1533
|
+
return true;
|
|
1534
|
+
}
|
|
1535
|
+
//#endregion
|
|
1394
1536
|
//#region src/read/api/ops/part-copy.ts
|
|
1395
1537
|
/** Open an ownership scope for one page copy. */
|
|
1396
1538
|
function newOwnedScope() {
|
|
@@ -1448,7 +1590,7 @@ function copySlidePart(ctx, sourcePartName) {
|
|
|
1448
1590
|
* from outside, as the rebinding import paths do for the page they build
|
|
1449
1591
|
* themselves.
|
|
1450
1592
|
*/
|
|
1451
|
-
function copyPart(ctx, sourcePartName, owned) {
|
|
1593
|
+
function copyPart(ctx, sourcePartName, owned, allowReuse = false) {
|
|
1452
1594
|
if (owned) {
|
|
1453
1595
|
const alreadyOwned = owned.get(sourcePartName);
|
|
1454
1596
|
if (alreadyOwned !== void 0) return alreadyOwned;
|
|
@@ -1457,6 +1599,12 @@ function copyPart(ctx, sourcePartName, owned) {
|
|
|
1457
1599
|
const selectedDest = ctx.selection?.destinations.get(sourcePartName);
|
|
1458
1600
|
if (existing && (selectedDest === void 0 || existing === selectedDest)) return existing;
|
|
1459
1601
|
}
|
|
1602
|
+
if (allowReuse && !owned && !ctx.selection?.destinations.has(sourcePartName)) {
|
|
1603
|
+
if (destinationAlreadyHolds(ctx.dest, ctx.source, sourcePartName)) {
|
|
1604
|
+
ctx.registry.set(sourcePartName, sourcePartName);
|
|
1605
|
+
return sourcePartName;
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1460
1608
|
const sourcePart = ctx.source.part(sourcePartName);
|
|
1461
1609
|
if (!sourcePart) throw new PackageReadError("package/part-missing", `importSlide: source package has no part ${sourcePartName}`);
|
|
1462
1610
|
const newPartName = owned ? ctx.dest.opc.reservePartNameLike(sourcePartName) : ctx.selection?.destinations.get(sourcePartName) ?? ctx.dest.opc.reservePartNameLike(sourcePartName);
|
|
@@ -1465,6 +1613,7 @@ function copyPart(ctx, sourcePartName, owned) {
|
|
|
1465
1613
|
else ctx.registry.set(sourcePartName, newPartName);
|
|
1466
1614
|
const scope = owned ?? (ctx.selection?.destinations.has(sourcePartName) ? newOwnedScope() : void 0);
|
|
1467
1615
|
const isMaster = sourcePart.contentType === SLIDE_MASTER_CONTENT_TYPE;
|
|
1616
|
+
const isPage = sourcePart.contentType === SLIDE_CONTENT_TYPE;
|
|
1468
1617
|
const sourceRels = ctx.source.relationshipsFor(sourcePartName);
|
|
1469
1618
|
const targetRels = ctx.dest.opc.relationshipsFor(newPartName);
|
|
1470
1619
|
for (const rel of sourceRels) {
|
|
@@ -1474,7 +1623,7 @@ function copyPart(ctx, sourcePartName, owned) {
|
|
|
1474
1623
|
targetRels.addWithId(rel.id, rel.type, rel.target, "External");
|
|
1475
1624
|
continue;
|
|
1476
1625
|
}
|
|
1477
|
-
const newTargetPartName = copyPart(ctx, sourceRels.resolveTarget(rel.id), isSharedByPageCopies(rel.type) ? void 0 : scope);
|
|
1626
|
+
const newTargetPartName = copyPart(ctx, sourceRels.resolveTarget(rel.id), isSharedByPageCopies(rel.type) ? void 0 : scope, isPage);
|
|
1478
1627
|
targetRels.addWithId(rel.id, rel.type, relativePartName(newPartName, newTargetPartName));
|
|
1479
1628
|
}
|
|
1480
1629
|
if (isMaster) {
|
|
@@ -4299,7 +4448,7 @@ function importSlideRebind(dest, ctx, source, sourceSlide, carryGraphics) {
|
|
|
4299
4448
|
targetRels.addWithId(rel.id, rel.type, rel.target, "External");
|
|
4300
4449
|
continue;
|
|
4301
4450
|
}
|
|
4302
|
-
const newTarget = copyPart(ctx, sourceRels.resolveTarget(rel.id), isSharedByPageCopies(rel.type) ? void 0 : owned);
|
|
4451
|
+
const newTarget = copyPart(ctx, sourceRels.resolveTarget(rel.id), isSharedByPageCopies(rel.type) ? void 0 : owned, true);
|
|
4303
4452
|
targetRels.addWithId(rel.id, rel.type, relativePartName(newPartName, newTarget));
|
|
4304
4453
|
}
|
|
4305
4454
|
if (carryGraphics) carryMasterGraphics(dest, ctx, slideRoot, newPartName, sourceSlide.partName, owned);
|
|
@@ -4487,7 +4636,6 @@ const PACKAGE_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relat
|
|
|
4487
4636
|
const AUDIO_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/audio";
|
|
4488
4637
|
const VIDEO_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/video";
|
|
4489
4638
|
const MS_MEDIA_REL = "http://schemas.microsoft.com/office/2007/relationships/media";
|
|
4490
|
-
const SLIDE_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.presentationml.slide+xml";
|
|
4491
4639
|
const CHART_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.drawingml.chart+xml";
|
|
4492
4640
|
const CHARTEX_CONTENT_TYPE = "application/vnd.ms-office.chartex+xml";
|
|
4493
4641
|
const CHART_STYLE_CONTENT_TYPE = "application/vnd.ms-office.chartstyle+xml";
|
|
@@ -5377,4 +5525,4 @@ var Presentation = class Presentation {
|
|
|
5377
5525
|
//#endregion
|
|
5378
5526
|
export { Placeholder as a, Theme as c, NotesSlide as d, OpcPackage as f, ContentTypes as h, Slide as i, readTagsForPart as l, Part as m, readCoreProperties as n, SlideLayout as o, Relationships as p, readCustomProperties as r, SlideMaster as s, Presentation as t, NotesPlaceholder as u };
|
|
5379
5527
|
|
|
5380
|
-
//# sourceMappingURL=presentation-
|
|
5528
|
+
//# sourceMappingURL=presentation-VfJ_FT7E.js.map
|