@poe-platform/safe-bash 0.1.839 → 0.1.841
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/audio-ast/binary.d.ts +19 -0
- package/dist/audio-ast/index.d.ts +1 -0
- package/dist/audio-ast/index.js +92 -91
- package/dist/audio-ast/mpeg.d.ts +23 -0
- package/dist/mp4-ast/containers/adapters.d.ts +1 -0
- package/dist/mp4-ast/types.d.ts +8 -2
- package/dist/pdf-ast/cos/security.d.ts +10 -0
- package/dist/pdf-ast/edit/retained-attachment-edits.d.ts +4 -0
- package/dist/pdf-ast/edit/retained-graph.d.ts +1 -1
- package/dist/pdf-ast/image.js +1 -1
- package/dist/pdf-ast/index.d.ts +2 -1
- package/dist/pdf-ast/index.js +7 -1
- package/dist/pdf-ast/vendor/pdfjs-fonts.d.mts +8 -0
- package/dist/pdf-ast/vendor/pdfjs-fonts.mjs +28 -0
- package/dist/safe-bash/audio-ast.browser.js +2 -1
- package/dist/safe-bash/audio-ast.js +1 -1
- package/dist/safe-bash/command-chunks/{chunk-SG2KOOD4.js → chunk-3SAYZFMD.js} +2 -2
- package/dist/safe-bash/command-chunks/{chunk-T6OXG7QQ.js → chunk-AAOPVEPF.js} +66 -1
- package/dist/safe-bash/command-chunks/{chunk-FH5VMAPS.js → chunk-BZW25LNV.js} +420 -131
- package/dist/safe-bash/command-chunks/{chunk-DQVOBGI2.js → chunk-CIV3GER2.js} +6770 -6523
- package/dist/safe-bash/command-chunks/{chunk-46GA576V.js → chunk-CPKVUB7S.js} +2 -2
- package/dist/safe-bash/command-chunks/{chunk-MBXNG6C3.js → chunk-DLLN3C3Q.js} +1 -1
- package/dist/safe-bash/command-chunks/{chunk-ZSQCROFE.js → chunk-DM5T5D2K.js} +5 -1
- package/dist/safe-bash/command-chunks/{chunk-3EAZRKI4.js → chunk-G7HQYFIU.js} +10 -1
- package/dist/safe-bash/command-chunks/{chunk-GYKQ3IOV.js → chunk-LMYQMJYY.js} +94 -18
- package/dist/safe-bash/command-chunks/{chunk-DX7KU6YU.js → chunk-N52AHO6S.js} +1 -1
- package/dist/safe-bash/command-chunks/{chunk-4BSD2RGK.js → chunk-QPKL5GWH.js} +102 -42
- package/dist/safe-bash/command-chunks/{chunk-Z2T7E4ID.js → chunk-R7QLP5RH.js} +1212 -1119
- package/dist/safe-bash/command-chunks/{chunk-77ROD2TR.js → chunk-X3WNWRVT.js} +11 -5
- package/dist/safe-bash/command-chunks/{chunk-RSFKQE2U.js → chunk-YAXP4EHP.js} +19 -10
- package/dist/safe-bash/command-chunks/{chunk-TCXM7BSZ.js → chunk-YFMNXPLP.js} +4 -4
- package/dist/safe-bash-command-exiftool/index.js +25 -1
- package/dist/safe-bash-command-ffmpeg/index.js +191 -49
- package/dist/safe-bash-command-ffprobe/index.js +2 -2
- package/dist/safe-bash-command-ffprobe/media.js +2 -2
- package/dist/safe-bash-command-imagemagick/index.js +498 -101
- package/dist/safe-bash-command-mdq/index.js +2 -0
- package/dist/safe-bash-command-pandoc/citeproc-filters.js +7 -7
- package/dist/safe-bash-command-pandoc/command.js +8 -8
- package/dist/safe-bash-command-pandoc/index.js +52 -52
- package/dist/safe-bash-command-qpdf/index.js +1037 -654
- package/dist/safe-bash-command-qpdf/page-range.d.ts +2 -0
- package/dist/safe-bash-command-soffice/index.js +28 -8
- package/dist/safe-bash-command-sqlite3/btree.d.ts +2 -1
- package/dist/safe-bash-command-sqlite3/engine.d.ts +15 -1
- package/dist/safe-bash-command-sqlite3/index.js +294 -68
- package/dist/safe-bash-command-tar/create.js +2 -2
- package/dist/safe-bash-command-tar/extract.js +2 -2
- package/dist/safe-bash-command-tar/format.js +1 -1
- package/dist/safe-bash-command-tar/index.js +4 -4
- package/dist/safe-bash-command-tar/modes.js +4 -4
- package/dist/safe-bash-command-unzip/index.js +1 -1
- package/dist/safe-bash-command-unzip/unzip.js +1 -1
- package/dist/safe-bash-markdown-engine/commonmark-blocks.d.ts +17 -1
- package/dist/safe-bash-markdown-engine/commonmark-blocks.js +3 -3
- package/dist/safe-bash-markdown-engine/commonmark-inlines.d.ts +1 -1
- package/dist/safe-bash-markdown-engine/commonmark-inlines.js +3 -3
- package/dist/safe-bash-markdown-engine/commonmark-syntax.d.ts +5 -0
- package/dist/safe-bash-markdown-engine/commonmark-syntax.js +5 -1
- package/dist/safe-bash-markdown-engine/gfm-syntax.js +2 -2
- package/dist/safe-bash-markdown-engine/index.js +4 -4
- package/dist/safe-bash-zip-engine/index.js +1 -1
- package/dist/safe-bash-zip-engine/zip/repair.js +1 -1
- package/dist/safe-bash-zip-engine/zip/sfx.js +1 -1
- package/dist/safe-bash-zip-engine/zip-format.d.ts +2 -0
- package/dist/safe-bash-zip-engine/zip-format.js +1 -1
- package/package.json +2 -2
- package/third-party/pdf-ast/THIRD_PARTY_NOTICES.md +2 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare class Reader {
|
|
2
|
+
readonly bytes: Uint8Array;
|
|
3
|
+
readonly view: DataView;
|
|
4
|
+
constructor(bytes: Uint8Array);
|
|
5
|
+
check(offset: number, size: number): void;
|
|
6
|
+
slice(offset: number, size: number): Uint8Array;
|
|
7
|
+
text(offset: number, size: number): string;
|
|
8
|
+
u8(offset: number): number;
|
|
9
|
+
u16(offset: number, little?: boolean): number;
|
|
10
|
+
u24(offset: number, little?: boolean): number;
|
|
11
|
+
u32(offset: number, little?: boolean): number;
|
|
12
|
+
u64(offset: number, little?: boolean): bigint;
|
|
13
|
+
safe64(offset: number, little?: boolean): number;
|
|
14
|
+
}
|
|
15
|
+
export declare function join(parts: Uint8Array[]): Uint8Array;
|
|
16
|
+
export declare function ascii(text: string): Uint8Array;
|
|
17
|
+
export declare function uint32(value: number, little?: boolean): Uint8Array;
|
|
18
|
+
export declare function cleanText(text: string): string;
|
|
19
|
+
export declare function duration(samples: number, sampleRate: number): number;
|
package/dist/audio-ast/index.js
CHANGED
|
@@ -74,6 +74,97 @@ function duration(samples, sampleRate) {
|
|
|
74
74
|
return samples / sampleRate;
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
+
// packages/audio-ast/src/mpeg.ts
|
|
78
|
+
function mpegFrame(header, offset, end) {
|
|
79
|
+
const versionBits = header >>> 19 & 3, layer = header >>> 17 & 3, bitrateIndex = header >>> 12 & 15, rateIndex = header >>> 10 & 3;
|
|
80
|
+
if (header >>> 21 !== 2047 || versionBits === 1 || layer !== 1 || !bitrateIndex || bitrateIndex === 15 || rateIndex === 3)
|
|
81
|
+
throw new Error(`Invalid MPEG Layer III frame at ${offset}`);
|
|
82
|
+
const version = versionBits === 3 ? 1 : versionBits === 2 ? 2 : 2.5;
|
|
83
|
+
const rate = [44100, 48e3, 32e3][rateIndex] / (version === 1 ? 1 : version === 2 ? 2 : 4);
|
|
84
|
+
const bitrate = (version === 1 ? [0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320] : [0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160])[bitrateIndex] * 1e3;
|
|
85
|
+
const count = version === 1 ? 1152 : 576, frameSize = Math.floor((version === 1 ? 144 : 72) * bitrate / rate) + (header >>> 9 & 1), ch = header >>> 6 & 3;
|
|
86
|
+
if (frameSize > end - offset) throw new Error("Truncated MPEG frame");
|
|
87
|
+
const channels = ch === 3 ? 1 : 2;
|
|
88
|
+
const fields = {
|
|
89
|
+
version,
|
|
90
|
+
layer: 3,
|
|
91
|
+
bitrate,
|
|
92
|
+
sampleRate: rate,
|
|
93
|
+
channels,
|
|
94
|
+
samples: count,
|
|
95
|
+
padding: header >>> 9 & 1
|
|
96
|
+
};
|
|
97
|
+
return { version, rate, count, frameSize, channels, fields };
|
|
98
|
+
}
|
|
99
|
+
function mpegVbr(r, offset, frameSize, header, fields) {
|
|
100
|
+
const version = Number(fields.version), channels = Number(fields.channels);
|
|
101
|
+
const side = version === 1 ? channels === 1 ? 17 : 32 : channels === 1 ? 9 : 17, crc = header & 65536 ? 0 : 2;
|
|
102
|
+
const xing = offset + 4 + crc + side;
|
|
103
|
+
if (xing + 8 <= offset + frameSize && ["Xing", "Info"].includes(r.text(xing, 4))) {
|
|
104
|
+
const flags = r.u32(xing + 4);
|
|
105
|
+
let pos = xing + 8;
|
|
106
|
+
const vbr = { type: r.text(xing, 4), flags };
|
|
107
|
+
if (flags & 1) {
|
|
108
|
+
vbr.frames = r.u32(pos);
|
|
109
|
+
pos += 4;
|
|
110
|
+
}
|
|
111
|
+
if (flags & 2) {
|
|
112
|
+
vbr.bytes = r.u32(pos);
|
|
113
|
+
pos += 4;
|
|
114
|
+
}
|
|
115
|
+
if (flags & 4) {
|
|
116
|
+
vbr.toc = r.slice(pos, 100);
|
|
117
|
+
pos += 100;
|
|
118
|
+
}
|
|
119
|
+
if (flags & 8) {
|
|
120
|
+
vbr.quality = r.u32(pos);
|
|
121
|
+
pos += 4;
|
|
122
|
+
}
|
|
123
|
+
if (pos > offset + frameSize) throw new Error("Xing header exceeds frame");
|
|
124
|
+
fields.vbr = vbr;
|
|
125
|
+
if (pos + 24 <= offset + frameSize && ["LAME", "Lavc", "Lavf"].includes(r.text(pos, 4))) {
|
|
126
|
+
const packed = r.u24(pos + 21);
|
|
127
|
+
fields.encoderDelay = packed >>> 12;
|
|
128
|
+
fields.encoderPadding = packed & 4095;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
const vbri = offset + 36;
|
|
132
|
+
if (vbri + 26 <= offset + frameSize && r.text(vbri, 4) === "VBRI")
|
|
133
|
+
fields.vbr = {
|
|
134
|
+
type: "VBRI",
|
|
135
|
+
version: r.u16(vbri + 4),
|
|
136
|
+
delay: r.u16(vbri + 6),
|
|
137
|
+
quality: r.u16(vbri + 8),
|
|
138
|
+
bytes: r.u32(vbri + 10),
|
|
139
|
+
frames: r.u32(vbri + 14),
|
|
140
|
+
entries: r.u16(vbri + 18),
|
|
141
|
+
scale: r.u16(vbri + 20),
|
|
142
|
+
entryBytes: r.u16(vbri + 22),
|
|
143
|
+
framesPerEntry: r.u16(vbri + 24)
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
function mpegStream(state, first) {
|
|
147
|
+
let { samples, seconds: seconds2, audioBytes } = state;
|
|
148
|
+
const { sampleRate, channels, frames } = state;
|
|
149
|
+
if (!frames) throw new Error("MP3 contains no MPEG frames");
|
|
150
|
+
const vbr = first.fields?.vbr;
|
|
151
|
+
const declared = vbr?.frames;
|
|
152
|
+
if (typeof declared === "number" && declared > 0) {
|
|
153
|
+
if (declared !== frames && declared !== frames - 1)
|
|
154
|
+
throw new Error("MPEG VBR frame count mismatch");
|
|
155
|
+
const encodedSamples = declared * (sampleRate >= 32e3 ? 1152 : 576);
|
|
156
|
+
const delay = Number(first.fields?.encoderDelay ?? 0), padding = Number(first.fields?.encoderPadding ?? 0);
|
|
157
|
+
if (delay + padding > encodedSamples) throw new Error("Invalid MPEG encoder delay/padding");
|
|
158
|
+
samples = encodedSamples - delay - padding;
|
|
159
|
+
seconds2 = duration(samples, sampleRate);
|
|
160
|
+
if (declared === frames - 1) audioBytes -= first.size;
|
|
161
|
+
first.fields.encodedSamples = encodedSamples;
|
|
162
|
+
}
|
|
163
|
+
const encodedSeconds = duration(Number(first.fields?.encodedSamples ?? samples), sampleRate);
|
|
164
|
+
const bitrate = encodedSeconds ? audioBytes * 8 / encodedSeconds : 0;
|
|
165
|
+
return { codec: "mp3", sampleRate, channels, samples, duration: seconds2, bitrate };
|
|
166
|
+
}
|
|
167
|
+
|
|
77
168
|
// packages/audio-ast/src/ogg-stream.ts
|
|
78
169
|
function oggIdentification(head, size = head.length) {
|
|
79
170
|
const r = new Reader(head);
|
|
@@ -883,97 +974,6 @@ async function probeId3Source(source, options = {}) {
|
|
|
883
974
|
return { size, version, tags };
|
|
884
975
|
}
|
|
885
976
|
|
|
886
|
-
// packages/audio-ast/src/mpeg.ts
|
|
887
|
-
function mpegFrame(header, offset, end) {
|
|
888
|
-
const versionBits = header >>> 19 & 3, layer = header >>> 17 & 3, bitrateIndex = header >>> 12 & 15, rateIndex = header >>> 10 & 3;
|
|
889
|
-
if (header >>> 21 !== 2047 || versionBits === 1 || layer !== 1 || !bitrateIndex || bitrateIndex === 15 || rateIndex === 3)
|
|
890
|
-
throw new Error(`Invalid MPEG Layer III frame at ${offset}`);
|
|
891
|
-
const version = versionBits === 3 ? 1 : versionBits === 2 ? 2 : 2.5;
|
|
892
|
-
const rate = [44100, 48e3, 32e3][rateIndex] / (version === 1 ? 1 : version === 2 ? 2 : 4);
|
|
893
|
-
const bitrate = (version === 1 ? [0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320] : [0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160])[bitrateIndex] * 1e3;
|
|
894
|
-
const count = version === 1 ? 1152 : 576, frameSize = Math.floor((version === 1 ? 144 : 72) * bitrate / rate) + (header >>> 9 & 1), ch = header >>> 6 & 3;
|
|
895
|
-
if (frameSize > end - offset) throw new Error("Truncated MPEG frame");
|
|
896
|
-
const channels = ch === 3 ? 1 : 2;
|
|
897
|
-
const fields = {
|
|
898
|
-
version,
|
|
899
|
-
layer: 3,
|
|
900
|
-
bitrate,
|
|
901
|
-
sampleRate: rate,
|
|
902
|
-
channels,
|
|
903
|
-
samples: count,
|
|
904
|
-
padding: header >>> 9 & 1
|
|
905
|
-
};
|
|
906
|
-
return { version, rate, count, frameSize, channels, fields };
|
|
907
|
-
}
|
|
908
|
-
function mpegVbr(r, offset, frameSize, header, fields) {
|
|
909
|
-
const version = Number(fields.version), channels = Number(fields.channels);
|
|
910
|
-
const side = version === 1 ? channels === 1 ? 17 : 32 : channels === 1 ? 9 : 17, crc = header & 65536 ? 0 : 2;
|
|
911
|
-
const xing = offset + 4 + crc + side;
|
|
912
|
-
if (xing + 8 <= offset + frameSize && ["Xing", "Info"].includes(r.text(xing, 4))) {
|
|
913
|
-
const flags = r.u32(xing + 4);
|
|
914
|
-
let pos = xing + 8;
|
|
915
|
-
const vbr = { type: r.text(xing, 4), flags };
|
|
916
|
-
if (flags & 1) {
|
|
917
|
-
vbr.frames = r.u32(pos);
|
|
918
|
-
pos += 4;
|
|
919
|
-
}
|
|
920
|
-
if (flags & 2) {
|
|
921
|
-
vbr.bytes = r.u32(pos);
|
|
922
|
-
pos += 4;
|
|
923
|
-
}
|
|
924
|
-
if (flags & 4) {
|
|
925
|
-
vbr.toc = r.slice(pos, 100);
|
|
926
|
-
pos += 100;
|
|
927
|
-
}
|
|
928
|
-
if (flags & 8) {
|
|
929
|
-
vbr.quality = r.u32(pos);
|
|
930
|
-
pos += 4;
|
|
931
|
-
}
|
|
932
|
-
if (pos > offset + frameSize) throw new Error("Xing header exceeds frame");
|
|
933
|
-
fields.vbr = vbr;
|
|
934
|
-
if (pos + 24 <= offset + frameSize && ["LAME", "Lavc", "Lavf"].includes(r.text(pos, 4))) {
|
|
935
|
-
const packed = r.u24(pos + 21);
|
|
936
|
-
fields.encoderDelay = packed >>> 12;
|
|
937
|
-
fields.encoderPadding = packed & 4095;
|
|
938
|
-
}
|
|
939
|
-
}
|
|
940
|
-
const vbri = offset + 36;
|
|
941
|
-
if (vbri + 26 <= offset + frameSize && r.text(vbri, 4) === "VBRI")
|
|
942
|
-
fields.vbr = {
|
|
943
|
-
type: "VBRI",
|
|
944
|
-
version: r.u16(vbri + 4),
|
|
945
|
-
delay: r.u16(vbri + 6),
|
|
946
|
-
quality: r.u16(vbri + 8),
|
|
947
|
-
bytes: r.u32(vbri + 10),
|
|
948
|
-
frames: r.u32(vbri + 14),
|
|
949
|
-
entries: r.u16(vbri + 18),
|
|
950
|
-
scale: r.u16(vbri + 20),
|
|
951
|
-
entryBytes: r.u16(vbri + 22),
|
|
952
|
-
framesPerEntry: r.u16(vbri + 24)
|
|
953
|
-
};
|
|
954
|
-
}
|
|
955
|
-
function mpegStream(state, first) {
|
|
956
|
-
let { samples, seconds: seconds2, audioBytes } = state;
|
|
957
|
-
const { sampleRate, channels, frames } = state;
|
|
958
|
-
if (!frames) throw new Error("MP3 contains no MPEG frames");
|
|
959
|
-
const vbr = first.fields?.vbr;
|
|
960
|
-
const declared = vbr?.frames;
|
|
961
|
-
if (typeof declared === "number" && declared > 0) {
|
|
962
|
-
if (declared !== frames && declared !== frames - 1)
|
|
963
|
-
throw new Error("MPEG VBR frame count mismatch");
|
|
964
|
-
const encodedSamples = declared * (sampleRate >= 32e3 ? 1152 : 576);
|
|
965
|
-
const delay = Number(first.fields?.encoderDelay ?? 0), padding = Number(first.fields?.encoderPadding ?? 0);
|
|
966
|
-
if (delay + padding > encodedSamples) throw new Error("Invalid MPEG encoder delay/padding");
|
|
967
|
-
samples = encodedSamples - delay - padding;
|
|
968
|
-
seconds2 = duration(samples, sampleRate);
|
|
969
|
-
if (declared === frames - 1) audioBytes -= first.size;
|
|
970
|
-
first.fields.encodedSamples = encodedSamples;
|
|
971
|
-
}
|
|
972
|
-
const encodedSeconds = duration(Number(first.fields?.encodedSamples ?? samples), sampleRate);
|
|
973
|
-
const bitrate = encodedSeconds ? audioBytes * 8 / encodedSeconds : 0;
|
|
974
|
-
return { codec: "mp3", sampleRate, channels, samples, duration: seconds2, bitrate };
|
|
975
|
-
}
|
|
976
|
-
|
|
977
977
|
// packages/audio-ast/src/mp3-source.ts
|
|
978
978
|
async function probeMp3Source(source, options = {}) {
|
|
979
979
|
const read = async (offset2, length) => {
|
|
@@ -2092,6 +2092,7 @@ export {
|
|
|
2092
2092
|
encodeWav,
|
|
2093
2093
|
extractChannels,
|
|
2094
2094
|
fade,
|
|
2095
|
+
mpegFrame,
|
|
2095
2096
|
normalize,
|
|
2096
2097
|
normalizeVorbisCommentKey,
|
|
2097
2098
|
pad,
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Reader } from "./binary.js";
|
|
2
|
+
import type { AudioStream } from "./types.js";
|
|
3
|
+
/** Shared strict frame validation for resident parsing and bounded source probing. */
|
|
4
|
+
export declare function mpegFrame(header: number, offset: number, end: number): {
|
|
5
|
+
version: number;
|
|
6
|
+
rate: number;
|
|
7
|
+
count: number;
|
|
8
|
+
frameSize: number;
|
|
9
|
+
channels: number;
|
|
10
|
+
fields: Record<string, unknown>;
|
|
11
|
+
};
|
|
12
|
+
export declare function mpegVbr(r: Reader, offset: number, frameSize: number, header: number, fields: Record<string, unknown>): void;
|
|
13
|
+
export declare function mpegStream(state: {
|
|
14
|
+
samples: number;
|
|
15
|
+
seconds: number;
|
|
16
|
+
audioBytes: number;
|
|
17
|
+
sampleRate: number;
|
|
18
|
+
channels: number;
|
|
19
|
+
frames: number;
|
|
20
|
+
}, first: {
|
|
21
|
+
size: number;
|
|
22
|
+
fields: Record<string, unknown>;
|
|
23
|
+
}): AudioStream;
|
|
@@ -9,6 +9,7 @@ export declare function parseAacAdts(bytes: Uint8Array): MediaDocument;
|
|
|
9
9
|
export declare function serializeAacAdts(doc: MediaDocument): Uint8Array;
|
|
10
10
|
export declare function aacAst(): MediaAstPlugin;
|
|
11
11
|
export declare function isWavSignature(bytes: Uint8Array): boolean;
|
|
12
|
+
export declare function wavPacketFrames(sampleRate: number, block: number): number;
|
|
12
13
|
export declare function parseWav(bytes: Uint8Array, options?: ParseMediaOptions): MediaDocument;
|
|
13
14
|
export declare function serializeWav(doc: MediaDocument): Uint8Array;
|
|
14
15
|
type WavMetadataOnlyOptions = MediaSourceProbeOptions & {
|
package/dist/mp4-ast/types.d.ts
CHANGED
|
@@ -84,6 +84,8 @@ export interface MediaAudioData {
|
|
|
84
84
|
readonly startSeconds?: number | undefined;
|
|
85
85
|
}
|
|
86
86
|
export interface MediaSample {
|
|
87
|
+
/** Absolute source file offset when the sample was parsed from a container. */
|
|
88
|
+
readonly offset?: number;
|
|
87
89
|
readonly data: Uint8Array;
|
|
88
90
|
readonly dts: number;
|
|
89
91
|
readonly pts: number;
|
|
@@ -305,6 +307,8 @@ export interface MediaProbeStream {
|
|
|
305
307
|
readonly duration: string;
|
|
306
308
|
readonly bit_rate?: string | undefined;
|
|
307
309
|
readonly nb_frames?: string | undefined;
|
|
310
|
+
readonly nb_read_packets?: string | undefined;
|
|
311
|
+
readonly nb_read_frames?: string | undefined;
|
|
308
312
|
readonly disposition: Readonly<Record<string, number>>;
|
|
309
313
|
readonly tags?: Readonly<Record<string, string>> | undefined;
|
|
310
314
|
readonly side_data_list?: readonly Readonly<Record<string, unknown>>[] | undefined;
|
|
@@ -345,8 +349,10 @@ export interface MediaProbeFrame {
|
|
|
345
349
|
readonly pkt_dts_time: string;
|
|
346
350
|
readonly best_effort_timestamp: number;
|
|
347
351
|
readonly best_effort_timestamp_time: string;
|
|
348
|
-
readonly
|
|
349
|
-
readonly
|
|
352
|
+
readonly duration?: number;
|
|
353
|
+
readonly duration_time?: string;
|
|
354
|
+
readonly pkt_duration?: number;
|
|
355
|
+
readonly pkt_duration_time?: string;
|
|
350
356
|
readonly pkt_size: string;
|
|
351
357
|
readonly width?: number | undefined;
|
|
352
358
|
readonly height?: number | undefined;
|
|
@@ -15,6 +15,16 @@ export declare function derivePdfEncryptionKey(encryptDict: PdfCosDict, document
|
|
|
15
15
|
resolve?: (node: PdfCosNode) => PdfCosNode | undefined;
|
|
16
16
|
maxRecursionDepth?: number | undefined;
|
|
17
17
|
}): PdfEncryptionState;
|
|
18
|
+
/** Inspection metadata from the authenticated security handler. */
|
|
19
|
+
export declare function getPdfEncryptionInfo(state: PdfEncryptionState): {
|
|
20
|
+
permissionsMask: number;
|
|
21
|
+
ownerPasswordMatched: boolean;
|
|
22
|
+
userPasswordMatched: boolean;
|
|
23
|
+
userPassword: string;
|
|
24
|
+
streamMethod: string;
|
|
25
|
+
stringMethod: string;
|
|
26
|
+
fileMethod: string;
|
|
27
|
+
};
|
|
18
28
|
export declare function decryptPdfBuffer(state: PdfEncryptionState, objectNumber: number, generationNumber: number, data: Uint8Array): Uint8Array;
|
|
19
29
|
/** Decrypt strings in one retained object's direct COS value. Stream bytes
|
|
20
30
|
* remain external; signature contents and security references stay plaintext. */
|
|
@@ -15,6 +15,10 @@ export declare class PdfDuplicateAttachment extends PdfError {
|
|
|
15
15
|
readonly key: string;
|
|
16
16
|
constructor(key: string);
|
|
17
17
|
}
|
|
18
|
+
export declare class PdfMissingAttachment extends PdfError {
|
|
19
|
+
readonly key: string;
|
|
20
|
+
constructor(key: string);
|
|
21
|
+
}
|
|
18
22
|
/** Flatten the edited name tree without collecting its pairs or new payloads. */
|
|
19
23
|
export declare function editRetainedAttachments(document: PdfRetainedDocument, target: PdfMutableObjectStore, storage: PdfIndexStorage, remove: Iterable<string> | AsyncIterable<string>, additions: Iterable<RetainedAttachmentInput> | AsyncIterable<RetainedAttachmentInput>, signal: AbortSignal, preserveTree?: boolean): Promise<void>;
|
|
20
24
|
export declare function retainedAttachmentNameTokens(document: PdfRetainedDocument, storage: PdfIndexStorage, root: PdfCosNode | undefined, signal: AbortSignal, recursive?: boolean): AsyncGenerator<PdfCosNode>;
|
|
@@ -9,7 +9,7 @@ export type { RetainedStampInput } from "./retained-stamps.js";
|
|
|
9
9
|
import { type RetainedInlineImageOptions } from "./retained-inline-images.js";
|
|
10
10
|
export type { RetainedInlineImageOptions } from "./retained-inline-images.js";
|
|
11
11
|
import { type RetainedAttachmentInput } from "./retained-attachment-edits.js";
|
|
12
|
-
export { PdfDuplicateAttachment, type RetainedAttachmentInput } from "./retained-attachment-edits.js";
|
|
12
|
+
export { PdfDuplicateAttachment, PdfMissingAttachment, type RetainedAttachmentInput } from "./retained-attachment-edits.js";
|
|
13
13
|
import { type RetainedPageLabel } from "./retained-merge-labels.js";
|
|
14
14
|
export type { RetainedPageLabel } from "./retained-merge-labels.js";
|
|
15
15
|
import type { PdfIndexStorage } from "../cos/object-index.js";
|
package/dist/pdf-ast/image.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
PdfRetainedReader,
|
|
6
6
|
renderPdfPageToPng,
|
|
7
7
|
renderRetainedPagePixels
|
|
8
|
-
} from "../safe-bash/command-chunks/chunk-
|
|
8
|
+
} from "../safe-bash/command-chunks/chunk-QPKL5GWH.js";
|
|
9
9
|
import "../safe-bash/command-chunks/chunk-E6SK3OU2.js";
|
|
10
10
|
import "../safe-bash/command-chunks/chunk-NUGQQDGE.js";
|
|
11
11
|
import "../safe-bash/command-chunks/chunk-65DS4IOB.js";
|
package/dist/pdf-ast/index.d.ts
CHANGED
|
@@ -75,7 +75,7 @@ export { createRetainedPageCopy, type PdfRetainedPageCopy, copyRetainedPageChunk
|
|
|
75
75
|
export { PdfRawTextIndex, type PdfRawTextGlyph, type PdfRawTextIndexOptions, type PdfStoredTextWord, type PdfStoredTextLine, type PdfStoredTextBlock } from "./extract/raw-text-index.js";
|
|
76
76
|
export { retainedCosObjects, type PdfRetainedObjectsOptions } from "./cos/retained-objects.js";
|
|
77
77
|
export { saveRetainedDocumentChunks, type SaveRetainedDocumentOptions, type RetainedPageRotation } from "./edit/retained-save.js";
|
|
78
|
-
export { editRetainedDocument, PdfDuplicateAttachment, type RetainedAttachmentInput, type EditRetainedDocumentOptions, type RetainedBookmark, type RetainedFormUpdate, type RetainedInfoUpdate, type RetainedStampInput, type RetainedPageLabel } from "./edit/retained-graph.js";
|
|
78
|
+
export { editRetainedDocument, PdfDuplicateAttachment, PdfMissingAttachment, type RetainedAttachmentInput, type EditRetainedDocumentOptions, type RetainedBookmark, type RetainedFormUpdate, type RetainedInfoUpdate, type RetainedStampInput, type RetainedPageLabel } from "./edit/retained-graph.js";
|
|
79
79
|
export { copyRetainedAttachments } from "./edit/retained-attachment-copies.js";
|
|
80
80
|
export { retainedObjectOrder } from "./cos/retained-object-order.js";
|
|
81
81
|
export { encryptRetainedPdfChunks } from "./cos/retained-encryption.js";
|
|
@@ -88,3 +88,4 @@ export { streamLogicalTextChunks, type PdfLogicalTextOptions } from "./extract/l
|
|
|
88
88
|
export { encodePostscriptPageChunks } from "./render/postscript.js";
|
|
89
89
|
export { CompactPdfNumber } from "./cos/compact-number.js";
|
|
90
90
|
export { serializeRetainedCosNodeChunks } from "./cos/retained-node-writer.js";
|
|
91
|
+
export { retainedStampTransform } from "./edit/retained-stamps.js";
|
package/dist/pdf-ast/index.js
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
PdfDuplicateAttachment,
|
|
9
9
|
PdfError,
|
|
10
10
|
PdfFileSource,
|
|
11
|
+
PdfMissingAttachment,
|
|
11
12
|
PdfMutableObjectStore,
|
|
12
13
|
PdfNameIndex,
|
|
13
14
|
PdfObjectIndex,
|
|
@@ -164,6 +165,7 @@ import {
|
|
|
164
165
|
getBitmapCropRect,
|
|
165
166
|
getDisplayListCropBox,
|
|
166
167
|
getDocumentFormFields,
|
|
168
|
+
getPdfEncryptionInfo,
|
|
167
169
|
glyphNameToUnicode,
|
|
168
170
|
imageColorSpaceProgram,
|
|
169
171
|
inflatePdfChunks,
|
|
@@ -233,6 +235,7 @@ import {
|
|
|
233
235
|
resolveRetainedMaskParameters,
|
|
234
236
|
retainedCosObjects,
|
|
235
237
|
retainedObjectOrder,
|
|
238
|
+
retainedStampTransform,
|
|
236
239
|
rgb,
|
|
237
240
|
rotateRgbaBitmapQuarterTurns,
|
|
238
241
|
rotateRgbaBitmapQuarterTurnsSteps,
|
|
@@ -257,7 +260,7 @@ import {
|
|
|
257
260
|
transformNodeStringsAndStreamsSteps,
|
|
258
261
|
transformPathSegment,
|
|
259
262
|
transformPoint
|
|
260
|
-
} from "../safe-bash/command-chunks/chunk-
|
|
263
|
+
} from "../safe-bash/command-chunks/chunk-QPKL5GWH.js";
|
|
261
264
|
import "../safe-bash/command-chunks/chunk-E6SK3OU2.js";
|
|
262
265
|
import "../safe-bash/command-chunks/chunk-NUGQQDGE.js";
|
|
263
266
|
import "../safe-bash/command-chunks/chunk-65DS4IOB.js";
|
|
@@ -271,6 +274,7 @@ export {
|
|
|
271
274
|
PdfDuplicateAttachment,
|
|
272
275
|
PdfError,
|
|
273
276
|
PdfFileSource,
|
|
277
|
+
PdfMissingAttachment,
|
|
274
278
|
PdfMutableObjectStore,
|
|
275
279
|
PdfNameIndex,
|
|
276
280
|
PdfObjectIndex,
|
|
@@ -428,6 +432,7 @@ export {
|
|
|
428
432
|
getBitmapCropRect,
|
|
429
433
|
getDisplayListCropBox,
|
|
430
434
|
getDocumentFormFields,
|
|
435
|
+
getPdfEncryptionInfo,
|
|
431
436
|
glyphNameToUnicode,
|
|
432
437
|
imageColorSpaceProgram,
|
|
433
438
|
inflatePdfChunks,
|
|
@@ -497,6 +502,7 @@ export {
|
|
|
497
502
|
resolveRetainedMaskParameters,
|
|
498
503
|
retainedCosObjects,
|
|
499
504
|
retainedObjectOrder,
|
|
505
|
+
retainedStampTransform,
|
|
500
506
|
rgb,
|
|
501
507
|
rotateRgbaBitmapQuarterTurns,
|
|
502
508
|
rotateRgbaBitmapQuarterTurnsSteps,
|
|
@@ -157,6 +157,14 @@ export function saslPrep(value: string): string;
|
|
|
157
157
|
export function buildPostScriptJsFunction(source: string, domain: readonly number[], range: readonly number[]):
|
|
158
158
|
(src: readonly number[], srcOffset: number, dest: number[], destOffset: number) => void;
|
|
159
159
|
export class CipherTransformFactory {
|
|
160
|
+
matchesOwnerPassword(): boolean;
|
|
161
|
+
readonly passwordType: "user" | "owner" | undefined;
|
|
162
|
+
readonly userPasswordBytes: Uint8Array | undefined;
|
|
163
|
+
readonly dict: Dict;
|
|
164
|
+
readonly cf: Dict | null;
|
|
165
|
+
readonly stmf: Name;
|
|
166
|
+
readonly strf: Name;
|
|
167
|
+
readonly eff: Name;
|
|
160
168
|
constructor(dict: Dict, fileId: string, password?: string);
|
|
161
169
|
readonly encryptionKey: Uint8Array | null;
|
|
162
170
|
readonly encryptMetadata: boolean;
|
|
@@ -15090,6 +15090,8 @@ function utf8PasswordToBytes(password) {
|
|
|
15090
15090
|
}
|
|
15091
15091
|
var CipherTransformFactory = class _CipherTransformFactory {
|
|
15092
15092
|
#fileId;
|
|
15093
|
+
passwordType;
|
|
15094
|
+
userPasswordBytes;
|
|
15093
15095
|
static get _defaultPasswordBytes() {
|
|
15094
15096
|
return shadow(
|
|
15095
15097
|
this,
|
|
@@ -15130,6 +15132,21 @@ var CipherTransformFactory = class _CipherTransformFactory {
|
|
|
15130
15132
|
])
|
|
15131
15133
|
);
|
|
15132
15134
|
}
|
|
15135
|
+
matchesOwnerPassword() {
|
|
15136
|
+
if (this.passwordType === "owner") return true;
|
|
15137
|
+
if (this.passwordType !== "user") return false;
|
|
15138
|
+
const dict = this.dict, revision = dict.get("R");
|
|
15139
|
+
const owner = stringToBytes(dict.get("O"));
|
|
15140
|
+
const user = stringToBytes(dict.get("U"));
|
|
15141
|
+
const password = this.userPasswordBytes;
|
|
15142
|
+
if (revision >= 5) {
|
|
15143
|
+
const algorithm = revision === 6 ? new PDF20() : new PDF17();
|
|
15144
|
+
return algorithm.checkOwnerPassword(password, owner.subarray(32, 40), user.subarray(0, 48), owner.subarray(0, 32));
|
|
15145
|
+
}
|
|
15146
|
+
const keyLength = this.encryptionKey.length * 8;
|
|
15147
|
+
const decoded = this.#decodeUserPassword(password, owner, revision, keyLength);
|
|
15148
|
+
return !!this.#prepareKeyData(stringToBytes(this.#fileId), decoded, owner, user, dict.get("P"), revision, keyLength, this.encryptMetadata);
|
|
15149
|
+
}
|
|
15133
15150
|
#createEncryptionKey20(revision, password, ownerPassword, ownerValidationSalt, ownerKeySalt, uBytes, userPassword, userValidationSalt, userKeySalt, ownerEncryption, userEncryption, perms) {
|
|
15134
15151
|
if (password) {
|
|
15135
15152
|
const passwordLength = Math.min(127, password.length);
|
|
@@ -15139,6 +15156,8 @@ var CipherTransformFactory = class _CipherTransformFactory {
|
|
|
15139
15156
|
}
|
|
15140
15157
|
const pdfAlgorithm = revision === 6 ? new PDF20() : new PDF17();
|
|
15141
15158
|
if (pdfAlgorithm.checkUserPassword(password, userValidationSalt, userPassword)) {
|
|
15159
|
+
this.passwordType = "user";
|
|
15160
|
+
this.userPasswordBytes = Uint8Array.from(password);
|
|
15142
15161
|
return pdfAlgorithm.getUserKey(password, userKeySalt, userEncryption);
|
|
15143
15162
|
} else if (password.length && pdfAlgorithm.checkOwnerPassword(
|
|
15144
15163
|
password,
|
|
@@ -15146,6 +15165,7 @@ var CipherTransformFactory = class _CipherTransformFactory {
|
|
|
15146
15165
|
uBytes,
|
|
15147
15166
|
ownerPassword
|
|
15148
15167
|
)) {
|
|
15168
|
+
this.passwordType = "owner";
|
|
15149
15169
|
return pdfAlgorithm.getOwnerKey(
|
|
15150
15170
|
password,
|
|
15151
15171
|
ownerKeySalt,
|
|
@@ -15353,6 +15373,10 @@ var CipherTransformFactory = class _CipherTransformFactory {
|
|
|
15353
15373
|
keyLength,
|
|
15354
15374
|
encryptMetadata
|
|
15355
15375
|
);
|
|
15376
|
+
if (encryptionKey) {
|
|
15377
|
+
this.passwordType = "user";
|
|
15378
|
+
this.userPasswordBytes = passwordBytes ?? new Uint8Array();
|
|
15379
|
+
}
|
|
15356
15380
|
} else {
|
|
15357
15381
|
const ownerValidationSalt = ownerBytes.subarray(32, 40);
|
|
15358
15382
|
const ownerKeySalt = ownerBytes.subarray(40, 48);
|
|
@@ -15413,6 +15437,10 @@ var CipherTransformFactory = class _CipherTransformFactory {
|
|
|
15413
15437
|
keyLength,
|
|
15414
15438
|
encryptMetadata
|
|
15415
15439
|
);
|
|
15440
|
+
if (encryptionKey) {
|
|
15441
|
+
this.passwordType = "owner";
|
|
15442
|
+
this.userPasswordBytes = decodedPassword;
|
|
15443
|
+
}
|
|
15416
15444
|
}
|
|
15417
15445
|
if (!encryptionKey) {
|
|
15418
15446
|
throw new PasswordException(
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
// packages/safe-bash/src/audio-ast.ts
|
|
2
|
-
import { concat, decodePcm, encodeWav, extractChannels, fade, normalize, normalizeVorbisCommentKey, pad, parseAudio, probeAudio, probeFlacSource, probeId3Source, probeMp3Source, probeOggStreamSource, probeWavSource, readId3Text, remix, resample, scanOggPages, stats, transformAudio, trim, writeAudioMetadata } from "../audio-ast/index.js";
|
|
2
|
+
import { concat, decodePcm, encodeWav, extractChannels, fade, mpegFrame, normalize, normalizeVorbisCommentKey, pad, parseAudio, probeAudio, probeFlacSource, probeId3Source, probeMp3Source, probeOggStreamSource, probeWavSource, readId3Text, remix, resample, scanOggPages, stats, transformAudio, trim, writeAudioMetadata } from "../audio-ast/index.js";
|
|
3
3
|
export {
|
|
4
4
|
concat,
|
|
5
5
|
decodePcm,
|
|
6
6
|
encodeWav,
|
|
7
7
|
extractChannels,
|
|
8
8
|
fade,
|
|
9
|
+
mpegFrame,
|
|
9
10
|
normalize,
|
|
10
11
|
normalizeVorbisCommentKey,
|
|
11
12
|
pad,
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { "concat", "decodePcm", "encodeWav", "extractChannels", "fade", "normalize", "normalizeVorbisCommentKey", "pad", "parseAudio", "probeAudio", "probeFlacSource", "probeId3Source", "probeMp3Source", "probeOggStreamSource", "probeWavSource", "readId3Text", "remix", "resample", "scanOggPages", "stats", "transformAudio", "trim", "writeAudioMetadata" } from "../audio-ast/index.js";
|
|
1
|
+
export { "concat", "decodePcm", "encodeWav", "extractChannels", "fade", "mpegFrame", "normalize", "normalizeVorbisCommentKey", "pad", "parseAudio", "probeAudio", "probeFlacSource", "probeId3Source", "probeMp3Source", "probeOggStreamSource", "probeWavSource", "readId3Text", "remix", "resample", "scanOggPages", "stats", "transformAudio", "trim", "writeAudioMetadata" } from "../audio-ast/index.js";
|
|
2
2
|
//# sourceMappingURL=audio-ast.js.map
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
numberField,
|
|
16
16
|
parseHeader,
|
|
17
17
|
parsePax
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-YFMNXPLP.js";
|
|
19
19
|
|
|
20
20
|
// packages/safe-bash-command-tar/src/extract.ts
|
|
21
21
|
import { compareIdentity } from "@poe-platform/safe-fs/contracts";
|
|
@@ -381,7 +381,7 @@ async function readArchive(context, source, options, budget, visitor) {
|
|
|
381
381
|
if (options.mode === "x") relative = relativeName(effectiveEntryName, options.strip);
|
|
382
382
|
const name = entry.name.replace(/^\/+/u, "");
|
|
383
383
|
const normalizedName = name.replace(/^(?:\.\/)+/u, "");
|
|
384
|
-
let selected = options.operands.length === 0;
|
|
384
|
+
let selected = options.operands.length === 0 && options.mode !== "delete";
|
|
385
385
|
let root = resolvePath(options.cwd);
|
|
386
386
|
for (let index = 0; index < options.operands.length; index++) {
|
|
387
387
|
const operand = options.operands[index];
|
|
@@ -150,6 +150,69 @@ function readTitle(text, start, context) {
|
|
|
150
150
|
i++;
|
|
151
151
|
}
|
|
152
152
|
}
|
|
153
|
+
function romanListNumber(label) {
|
|
154
|
+
if (!label || label.length > 15 || label !== label.toLowerCase() && label !== label.toUpperCase()) return;
|
|
155
|
+
const lower = label.toLowerCase();
|
|
156
|
+
const values = { i: 1, v: 5, x: 10, l: 50, c: 100, d: 500, m: 1e3 };
|
|
157
|
+
let number = 0;
|
|
158
|
+
for (let i = 0; i < lower.length; i++) {
|
|
159
|
+
const value = values[lower[i]];
|
|
160
|
+
if (value === void 0) return;
|
|
161
|
+
number += value < (values[lower[i + 1]] ?? 0) ? -value : value;
|
|
162
|
+
}
|
|
163
|
+
if (number < 1 || number > 3999) return;
|
|
164
|
+
let canonical = "", remaining = number;
|
|
165
|
+
for (const [value, numeral] of [[1e3, "m"], [900, "cm"], [500, "d"], [400, "cd"], [100, "c"], [90, "xc"], [50, "l"], [40, "xl"], [10, "x"], [9, "ix"], [5, "v"], [4, "iv"], [1, "i"]]) {
|
|
166
|
+
while (remaining >= value) {
|
|
167
|
+
canonical += numeral;
|
|
168
|
+
remaining -= value;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return canonical === lower ? number : void 0;
|
|
172
|
+
}
|
|
173
|
+
function fencedDivAttributes(text, context) {
|
|
174
|
+
text = text.trim();
|
|
175
|
+
while (text.endsWith(":")) text = text.slice(0, -1);
|
|
176
|
+
text = text.trimEnd();
|
|
177
|
+
if (!text) return;
|
|
178
|
+
const attr = ["", [], []];
|
|
179
|
+
if (!text.startsWith("{")) {
|
|
180
|
+
for (const char of text) {
|
|
181
|
+
context.checkpoint();
|
|
182
|
+
if (whitespace(char)) return;
|
|
183
|
+
}
|
|
184
|
+
attr[1].push(text);
|
|
185
|
+
return attr;
|
|
186
|
+
}
|
|
187
|
+
if (!text.endsWith("}")) return;
|
|
188
|
+
let at = 1;
|
|
189
|
+
const end = text.length - 1;
|
|
190
|
+
while (at < end) {
|
|
191
|
+
context.checkpoint();
|
|
192
|
+
while (at < end && whitespace(text[at])) at++;
|
|
193
|
+
if (at === end) break;
|
|
194
|
+
const start = at;
|
|
195
|
+
while (at < end && !whitespace(text[at]) && text[at] !== "=") at++;
|
|
196
|
+
const name = text.slice(start, at);
|
|
197
|
+
if (!name) return;
|
|
198
|
+
if (text[at] === "=") {
|
|
199
|
+
at++;
|
|
200
|
+
const quote = text[at] === '"' || text[at] === "'" ? text[at++] : void 0;
|
|
201
|
+
let value = "";
|
|
202
|
+
while (at < end && (quote ? text[at] !== quote : !whitespace(text[at]))) {
|
|
203
|
+
context.checkpoint();
|
|
204
|
+
if (text[at] === "\\" && at + 1 < end && (text[at + 1] === quote || text[at + 1] === "\\")) at++;
|
|
205
|
+
value += text[at++];
|
|
206
|
+
}
|
|
207
|
+
if (quote && text[at++] !== quote) return;
|
|
208
|
+
attr[2].push([name, value]);
|
|
209
|
+
} else if (name.startsWith("#") && name.length > 1) attr[0] = name.slice(1);
|
|
210
|
+
else if (name.startsWith(".") && name.length > 1) attr[1].push(name.slice(1));
|
|
211
|
+
else return;
|
|
212
|
+
if (at < end && !whitespace(text[at])) return;
|
|
213
|
+
}
|
|
214
|
+
return attr;
|
|
215
|
+
}
|
|
153
216
|
|
|
154
217
|
export {
|
|
155
218
|
asciiPunctuation,
|
|
@@ -162,5 +225,7 @@ export {
|
|
|
162
225
|
normalizeUri,
|
|
163
226
|
readLabel,
|
|
164
227
|
readDestination,
|
|
165
|
-
readTitle
|
|
228
|
+
readTitle,
|
|
229
|
+
romanListNumber,
|
|
230
|
+
fencedDivAttributes
|
|
166
231
|
};
|