@ai-matrx/content-ir 0.15.1 → 0.16.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.
- package/CHANGELOG.md +49 -0
- package/dist/index.cjs +120 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +120 -9
- package/dist/index.js.map +1 -1
- package/dist/source.cjs +120 -8
- package/dist/source.cjs.map +1 -1
- package/dist/source.d.cts +19 -1
- package/dist/source.d.ts +19 -1
- package/dist/source.js +120 -9
- package/dist/source.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,54 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.16.1
|
|
4
|
+
|
|
5
|
+
Automatic changed-only republish (docs/metadata drift since the last tag — see
|
|
6
|
+
`git diff npm/content-ir-core/v0.16.0..npm/content-ir-core/v0.16.1 -- apps/shared/content-ir-core`).
|
|
7
|
+
No source changes intended and no consumer action required.
|
|
8
|
+
|
|
9
|
+
## Unreleased
|
|
10
|
+
|
|
11
|
+
**`/source` — a callout or `:::` directive nested in a list item stays in the
|
|
12
|
+
list's prose block** (verify-RC-B8 round 2, SAFETY). Guard:
|
|
13
|
+
`source-markdown-syntax-islands.test.ts` (3 cases red before).
|
|
14
|
+
|
|
15
|
+
**Consumer action:** none.
|
|
16
|
+
|
|
17
|
+
## 0.16.0 — 2026-09-25
|
|
18
|
+
|
|
19
|
+
**`/source` — a deterministic attack suite, and streaming that only ever
|
|
20
|
+
grows** (verify-RC-B3 § Re-verification (0.15.0): G3, G4, G5). The verifier's
|
|
21
|
+
planted mutations M1–M6 plus M7 (the trailing-`$` streaming guard removed)
|
|
22
|
+
and M8 (the footnote open-tail rule removed) each turn
|
|
23
|
+
`__tests__/source-attack.test.ts` red ON ITS OWN; unmutated code is green.
|
|
24
|
+
|
|
25
|
+
- **G3 — work, not wall-clock.** `tokenizeSource(text, { meter })` (diagnostic)
|
|
26
|
+
counts every character the tokenizer's own loops visit; the attack suite adds
|
|
27
|
+
native string / regex work (indexOf / includes / lastIndexOf spans, trim,
|
|
28
|
+
split, replace, regex exec / test to where they stop) under a V8 cost model,
|
|
29
|
+
and asserts work at 4× input stays under 6× — deterministic on any host. One
|
|
30
|
+
generous wall-clock smoke bound remains (1 MB mixed in < 20 s). The meter
|
|
31
|
+
immediately caught two real quadratics, both fixed: the new pending-`$$`
|
|
32
|
+
scan (206 s at 1 MB of `$$\n`, now linear) — and it replaced a timing
|
|
33
|
+
check that flaked 3 of 12 runs under load.
|
|
34
|
+
- **G4** — a streamed `$x$` that the next byte turns into currency (`$x$5`)
|
|
35
|
+
never settles as math first; guarded by a message in the suite.
|
|
36
|
+
- **G5 — trailing islands only grow.** The suite asserts that a line-grown
|
|
37
|
+
island (tree, callout, footnote, HTML block, directive) keeps its start and
|
|
38
|
+
type and never shrinks, at every next prefix, over random documents. Fixed
|
|
39
|
+
classes it found: a footnote absorbing an unterminated line that becomes
|
|
40
|
+
the next note (`[^n]: short\n[`); a one-tag HTML line still arriving; a
|
|
41
|
+
trailing lone CR (the first half of CRLF) counted as content; text after an
|
|
42
|
+
unclosed backtick run while its paragraph can still grow; an open last line
|
|
43
|
+
starting with `{`; and anything after a `$$` that could still find its
|
|
44
|
+
partner (`pendingDisplayMathOpener` — the earliest pairable unpaired token).
|
|
45
|
+
In streaming mode all of these are provisional prose until decided.
|
|
46
|
+
- Distinct-document counting: the structure attack counts the distinct
|
|
47
|
+
documents it tokenized (mulberry32) and requires ≥ 95% of its rounds.
|
|
48
|
+
|
|
49
|
+
**Consumer action:** none for stored text. Streaming callers see fewer
|
|
50
|
+
islands near the tail until the text decides them.
|
|
51
|
+
|
|
3
52
|
## 0.15.1
|
|
4
53
|
|
|
5
54
|
- **Fixed (`/source` `pairDisplayMath`):** a stray `$$` in prose paired with
|
package/dist/index.cjs
CHANGED
|
@@ -5321,6 +5321,50 @@ function codeRanges(text) {
|
|
|
5321
5321
|
}
|
|
5322
5322
|
return ranges.sort((a, b) => a[0] - b[0]);
|
|
5323
5323
|
}
|
|
5324
|
+
function pendingDisplayMathOpener(text) {
|
|
5325
|
+
if (!text.includes("$$")) return -1;
|
|
5326
|
+
const ranges = codeRanges(text);
|
|
5327
|
+
const tokens = [];
|
|
5328
|
+
let r = 0;
|
|
5329
|
+
let maxEnd = -1;
|
|
5330
|
+
for (let i = text.indexOf("$$"); i !== -1 && i < text.length - 1; i = text.indexOf("$$", i)) {
|
|
5331
|
+
while (r < ranges.length && ranges[r][0] <= i) {
|
|
5332
|
+
maxEnd = Math.max(maxEnd, ranges[r][1]);
|
|
5333
|
+
r++;
|
|
5334
|
+
}
|
|
5335
|
+
if (maxEnd <= i) tokens.push(i);
|
|
5336
|
+
i += 2;
|
|
5337
|
+
}
|
|
5338
|
+
const paired = /* @__PURE__ */ new Set();
|
|
5339
|
+
let j = 0;
|
|
5340
|
+
while (j < tokens.length) {
|
|
5341
|
+
const open = tokens[j];
|
|
5342
|
+
const close = tokens[j + 1];
|
|
5343
|
+
if (close === void 0) break;
|
|
5344
|
+
if (looksLikeDisplayMath(text.slice(open + 2, close), opensFlowBlock(text, open))) {
|
|
5345
|
+
paired.add(open);
|
|
5346
|
+
paired.add(close);
|
|
5347
|
+
j += 2;
|
|
5348
|
+
continue;
|
|
5349
|
+
}
|
|
5350
|
+
j += 1;
|
|
5351
|
+
}
|
|
5352
|
+
let trail = 0;
|
|
5353
|
+
while (trail < text.length && /\s/.test(text[text.length - 1 - trail])) trail++;
|
|
5354
|
+
for (const token of tokens) {
|
|
5355
|
+
if (paired.has(token)) continue;
|
|
5356
|
+
let lead = 0;
|
|
5357
|
+
while (lead <= MAX_MATH_SPAN && /\s/.test(text[token + 2 + lead] ?? "x")) lead++;
|
|
5358
|
+
if (text.length - (token + 2) - lead - trail > MAX_MATH_SPAN) continue;
|
|
5359
|
+
const inner = text.slice(token + 2);
|
|
5360
|
+
const s = inner.trim();
|
|
5361
|
+
if (STRUCTURAL_MARKDOWN.test(s) || s.length > MAX_MATH_SPAN) continue;
|
|
5362
|
+
if (!opensFlowBlock(text, token) && /\n[ \t]*\n/.test(inner)) continue;
|
|
5363
|
+
if ((s.match(PROSE_WORD) ?? []).length >= PROSE_WORD_LIMIT * 3) continue;
|
|
5364
|
+
return token;
|
|
5365
|
+
}
|
|
5366
|
+
return -1;
|
|
5367
|
+
}
|
|
5324
5368
|
function pairDisplayMath(text) {
|
|
5325
5369
|
const pairs = /* @__PURE__ */ new Map();
|
|
5326
5370
|
if (!text.includes("$$")) return pairs;
|
|
@@ -5669,11 +5713,15 @@ function isSplitterTreeLine(line) {
|
|
|
5669
5713
|
}
|
|
5670
5714
|
var MEDIA_REF_PREFIXES = ["[Image URL:", "[Video URL:", "[Audio URL:"];
|
|
5671
5715
|
var Tokenizer = class {
|
|
5672
|
-
constructor(text, streaming = false) {
|
|
5716
|
+
constructor(text, streaming = false, meter = void 0) {
|
|
5673
5717
|
this.text = text;
|
|
5674
5718
|
this.streaming = streaming;
|
|
5719
|
+
this.meter = meter;
|
|
5675
5720
|
this.n = text.length;
|
|
5721
|
+
this.tick(text.length);
|
|
5676
5722
|
this.mathPairs = pairDisplayMath(text);
|
|
5723
|
+
this.provisionalFrom = streaming ? pendingDisplayMathOpener(text) : -1;
|
|
5724
|
+
if (this.provisionalFrom === -1) this.provisionalFrom = Number.POSITIVE_INFINITY;
|
|
5677
5725
|
let start = 0;
|
|
5678
5726
|
for (let i = 0; i < text.length; i++) {
|
|
5679
5727
|
if (text.charCodeAt(i) === 10) {
|
|
@@ -5684,13 +5732,15 @@ var Tokenizer = class {
|
|
|
5684
5732
|
}
|
|
5685
5733
|
}
|
|
5686
5734
|
if (start < text.length || text.length === 0) {
|
|
5735
|
+
this.pendingCR = streaming && text.length > start && text.charCodeAt(text.length - 1) === 13;
|
|
5687
5736
|
this.lineStarts.push(start);
|
|
5688
|
-
this.contentEnds.push(text.length);
|
|
5737
|
+
this.contentEnds.push(this.pendingCR ? text.length - 1 : text.length);
|
|
5689
5738
|
this.lineEnds.push(text.length);
|
|
5690
5739
|
}
|
|
5691
5740
|
}
|
|
5692
5741
|
text;
|
|
5693
5742
|
streaming;
|
|
5743
|
+
meter;
|
|
5694
5744
|
n;
|
|
5695
5745
|
lineStarts = [];
|
|
5696
5746
|
contentEnds = [];
|
|
@@ -5705,6 +5755,23 @@ var Tokenizer = class {
|
|
|
5705
5755
|
/** `$$` opener → closer for the pairs the core renders as math. */
|
|
5706
5756
|
mathPairs;
|
|
5707
5757
|
finder = (needle, from) => this.next(needle, from);
|
|
5758
|
+
/** Streaming: where provisional text starts (a pending `$$`), or +∞. */
|
|
5759
|
+
provisionalFrom = Number.POSITIVE_INFINITY;
|
|
5760
|
+
/** Streaming: the text ends in a lone CR whose LF has not arrived yet. */
|
|
5761
|
+
pendingCR = false;
|
|
5762
|
+
/**
|
|
5763
|
+
* Streaming: an open last line that begins with `{` is undecided — each new
|
|
5764
|
+
* byte can balance or unbalance its braces and flip the whole line between
|
|
5765
|
+
* prose and a JSON island — so it is provisional until it ends (G5).
|
|
5766
|
+
*/
|
|
5767
|
+
markOpenJsonTail() {
|
|
5768
|
+
const last = this.lineStarts.length - 1;
|
|
5769
|
+
if (!this.isOpenTail(last)) return;
|
|
5770
|
+
const start = this.lineStarts[last];
|
|
5771
|
+
if (this.lineText(last).trimStart().startsWith("{")) {
|
|
5772
|
+
this.provisionalFrom = Math.min(this.provisionalFrom, start);
|
|
5773
|
+
}
|
|
5774
|
+
}
|
|
5708
5775
|
/**
|
|
5709
5776
|
* `text.indexOf(needle, from)` in O(log k): the first query for a needle
|
|
5710
5777
|
* indexes all of its occurrences once, so repeated searches for a closer
|
|
@@ -5728,9 +5795,21 @@ var Tokenizer = class {
|
|
|
5728
5795
|
}
|
|
5729
5796
|
return lo < list.length ? list[lo] : -1;
|
|
5730
5797
|
}
|
|
5798
|
+
/** Charge `n` visited characters to the diagnostic meter (complexity tests). */
|
|
5799
|
+
tick(n) {
|
|
5800
|
+
if (this.meter) this.meter.work += n;
|
|
5801
|
+
}
|
|
5802
|
+
/** Streaming only: a paragraph ending at `pe` may still be continued by a line not yet arrived. */
|
|
5803
|
+
paragraphMayGrow(pe) {
|
|
5804
|
+
if (!this.streaming) return false;
|
|
5805
|
+
const rest = this.n - pe;
|
|
5806
|
+
if (rest === 0) return true;
|
|
5807
|
+
const tail = this.text.slice(pe);
|
|
5808
|
+
return tail === "\n" || tail === "\r\n" || tail === "\r";
|
|
5809
|
+
}
|
|
5731
5810
|
/** Streaming only: the final line, still waiting for its terminator. */
|
|
5732
5811
|
isOpenTail(k) {
|
|
5733
|
-
return this.streaming && k === this.lineStarts.length - 1 && this.lineEnds[k] === this.contentEnds[k];
|
|
5812
|
+
return this.streaming && k === this.lineStarts.length - 1 && (this.lineEnds[k] === this.contentEnds[k] || this.pendingCR);
|
|
5734
5813
|
}
|
|
5735
5814
|
get lineCount() {
|
|
5736
5815
|
return this.lineStarts.length;
|
|
@@ -5755,6 +5834,7 @@ var Tokenizer = class {
|
|
|
5755
5834
|
return this.text.slice(this.lineStarts[li], this.contentEnds[li]);
|
|
5756
5835
|
}
|
|
5757
5836
|
run() {
|
|
5837
|
+
if (this.streaming) this.markOpenJsonTail();
|
|
5758
5838
|
let pos = 0;
|
|
5759
5839
|
while (pos < this.n) {
|
|
5760
5840
|
const li = this.lineOf(pos);
|
|
@@ -5763,6 +5843,10 @@ var Tokenizer = class {
|
|
|
5763
5843
|
pos = this.gap(pos, li);
|
|
5764
5844
|
continue;
|
|
5765
5845
|
}
|
|
5846
|
+
if (pos >= this.provisionalFrom) {
|
|
5847
|
+
this.push({ kind: "prose", start: pos, end: this.n, island: null, inlines: [] });
|
|
5848
|
+
break;
|
|
5849
|
+
}
|
|
5766
5850
|
const island = this.detectBlock(pos, li, true);
|
|
5767
5851
|
if (island) {
|
|
5768
5852
|
this.push({ kind: "island", start: island.start, end: island.end, island, inlines: [] });
|
|
@@ -5813,7 +5897,8 @@ var Tokenizer = class {
|
|
|
5813
5897
|
const fm = this.frontMatter(li, t);
|
|
5814
5898
|
if (fm) return fm;
|
|
5815
5899
|
}
|
|
5816
|
-
|
|
5900
|
+
const listNested = indent > 0 && this.inListContinuation(li);
|
|
5901
|
+
if (indent <= 3 && !listNested && t.startsWith("::")) {
|
|
5817
5902
|
const directive = this.directive(p, li, t);
|
|
5818
5903
|
if (directive) return directive;
|
|
5819
5904
|
}
|
|
@@ -5821,7 +5906,7 @@ var Tokenizer = class {
|
|
|
5821
5906
|
const admonition = this.mkdocsAdmonition(p, li, t);
|
|
5822
5907
|
if (admonition) return admonition;
|
|
5823
5908
|
}
|
|
5824
|
-
if (indent <= 3 && t.startsWith(">")) {
|
|
5909
|
+
if (indent <= 3 && !listNested && t.startsWith(">")) {
|
|
5825
5910
|
const callout = this.callout(p, li, t);
|
|
5826
5911
|
if (callout) return callout;
|
|
5827
5912
|
}
|
|
@@ -5862,6 +5947,17 @@ var Tokenizer = class {
|
|
|
5862
5947
|
}
|
|
5863
5948
|
return null;
|
|
5864
5949
|
}
|
|
5950
|
+
/** True when line `li` continues a list item (the nearest non-blank line above is a list item or indented text under one). */
|
|
5951
|
+
inListContinuation(li) {
|
|
5952
|
+
for (let k = li - 1; k >= 0; k--) {
|
|
5953
|
+
const line = this.lineText(k);
|
|
5954
|
+
if (!NOT_WHITESPACE.test(line)) continue;
|
|
5955
|
+
if (/^[ \t]*(?:[-*+]|\d{1,9}[.)])[ \t]/.test(line)) return true;
|
|
5956
|
+
if (/^[ \t]/.test(line)) continue;
|
|
5957
|
+
return false;
|
|
5958
|
+
}
|
|
5959
|
+
return false;
|
|
5960
|
+
}
|
|
5865
5961
|
island(type, start, end, complete, meta = {}) {
|
|
5866
5962
|
return { type, start, end, complete, meta };
|
|
5867
5963
|
}
|
|
@@ -5966,6 +6062,7 @@ var Tokenizer = class {
|
|
|
5966
6062
|
continue;
|
|
5967
6063
|
}
|
|
5968
6064
|
if (FOOTNOTE_DEF.test(line.trimStart()) || this.detectBlock(this.lineStarts[k], k, false)) break;
|
|
6065
|
+
if (this.isOpenTail(k)) break;
|
|
5969
6066
|
last = k;
|
|
5970
6067
|
}
|
|
5971
6068
|
return this.island("footnote_def", p, this.contentEnds[last], true, { id: open[1] });
|
|
@@ -6127,6 +6224,7 @@ var Tokenizer = class {
|
|
|
6127
6224
|
const li = this.lineOf(tp);
|
|
6128
6225
|
const ce = this.contentEnds[li];
|
|
6129
6226
|
const tag = readXmlTag(this.text, tp, this.finder);
|
|
6227
|
+
this.tick(tag ? tag.raw.length : 1);
|
|
6130
6228
|
let openEnd;
|
|
6131
6229
|
if (tag && !tag.isClosing) {
|
|
6132
6230
|
if (tag.isSelfClosing) {
|
|
@@ -6211,7 +6309,7 @@ var Tokenizer = class {
|
|
|
6211
6309
|
return this.island("html_block", p, close.index + close[0].length, true, { tag: name });
|
|
6212
6310
|
}
|
|
6213
6311
|
const typeSix = HTML_BLOCK_LEVEL_TAGS.has(name);
|
|
6214
|
-
const typeSeven = atParaStart && t.trimEnd() === tag.raw;
|
|
6312
|
+
const typeSeven = atParaStart && t.trimEnd() === tag.raw && !this.isOpenTail(li);
|
|
6215
6313
|
if (!typeSix && !typeSeven) return null;
|
|
6216
6314
|
let end = this.contentEnds[li];
|
|
6217
6315
|
for (let k = li + 1; k < this.lineCount && !this.lineIsBlank(k); k++) {
|
|
@@ -6303,6 +6401,10 @@ var Tokenizer = class {
|
|
|
6303
6401
|
let breakLine = -1;
|
|
6304
6402
|
for (let k = li + 1; k < this.lineCount; k++) {
|
|
6305
6403
|
if (this.lineIsBlank(k)) break;
|
|
6404
|
+
if (this.lineStarts[k] >= this.provisionalFrom) {
|
|
6405
|
+
end = this.n;
|
|
6406
|
+
break;
|
|
6407
|
+
}
|
|
6306
6408
|
if (this.detectBlock(this.lineStarts[k], k, false)) {
|
|
6307
6409
|
breakLine = k;
|
|
6308
6410
|
break;
|
|
@@ -6368,6 +6470,7 @@ var Tokenizer = class {
|
|
|
6368
6470
|
scanInline(ps, pe) {
|
|
6369
6471
|
const text = this.text;
|
|
6370
6472
|
const inlines = [];
|
|
6473
|
+
this.tick(pe - ps);
|
|
6371
6474
|
const hasKind = text.slice(ps, pe).includes("__kind");
|
|
6372
6475
|
let kindBudget = 4 * (pe - ps) + 65536;
|
|
6373
6476
|
const stop = (island, orphan = false) => ({ inlines, breakIsland: island, orphan });
|
|
@@ -6378,6 +6481,7 @@ var Tokenizer = class {
|
|
|
6378
6481
|
let runs = null;
|
|
6379
6482
|
const codeSpanClose = (n, from) => {
|
|
6380
6483
|
if (!runs) {
|
|
6484
|
+
this.tick(pe - ps);
|
|
6381
6485
|
runs = /* @__PURE__ */ new Map();
|
|
6382
6486
|
for (let k = ps; k < pe; ) {
|
|
6383
6487
|
if (text.charCodeAt(k) !== 96) {
|
|
@@ -6404,7 +6508,8 @@ var Tokenizer = class {
|
|
|
6404
6508
|
return at !== void 0 && at + n <= pe ? at : -1;
|
|
6405
6509
|
};
|
|
6406
6510
|
let i = ps;
|
|
6407
|
-
|
|
6511
|
+
const scanEnd = Math.min(pe, this.provisionalFrom);
|
|
6512
|
+
while (i < scanEnd) {
|
|
6408
6513
|
const ch = text[i];
|
|
6409
6514
|
if (ch === "\\") {
|
|
6410
6515
|
const nextCh = text[i + 1];
|
|
@@ -6422,6 +6527,9 @@ var Tokenizer = class {
|
|
|
6422
6527
|
if (ch === "`") {
|
|
6423
6528
|
const n = backtickRunLength(text, i);
|
|
6424
6529
|
const close = codeSpanClose(n, i + n);
|
|
6530
|
+
if (close === -1 && this.streaming && this.paragraphMayGrow(pe)) {
|
|
6531
|
+
return { inlines, breakIsland: null, orphan: false };
|
|
6532
|
+
}
|
|
6425
6533
|
i = close === -1 ? i + n : close + n;
|
|
6426
6534
|
continue;
|
|
6427
6535
|
}
|
|
@@ -6438,6 +6546,7 @@ var Tokenizer = class {
|
|
|
6438
6546
|
continue;
|
|
6439
6547
|
}
|
|
6440
6548
|
const end = singleDollarMathEnd(text, i, pe);
|
|
6549
|
+
this.tick(end > 0 ? end - i : Math.min(403, pe - i));
|
|
6441
6550
|
if (end > 0 && !(this.streaming && end === this.n)) {
|
|
6442
6551
|
inlines.push(this.island("math_inline", i, end, true, { delimiter: "$" }));
|
|
6443
6552
|
i = end;
|
|
@@ -6465,6 +6574,7 @@ var Tokenizer = class {
|
|
|
6465
6574
|
const limit = Math.min(pe, i + 65536);
|
|
6466
6575
|
const end = matchingJsonObjectEnd(text, i, limit);
|
|
6467
6576
|
kindBudget -= (end ?? limit) - i;
|
|
6577
|
+
this.tick((end ?? limit) - i);
|
|
6468
6578
|
if (end !== null) {
|
|
6469
6579
|
const kind = declaredKind(text.slice(i, end));
|
|
6470
6580
|
if (kind) {
|
|
@@ -6526,6 +6636,7 @@ var Tokenizer = class {
|
|
|
6526
6636
|
continue;
|
|
6527
6637
|
}
|
|
6528
6638
|
const tag = readXmlTag(text, i, this.finder);
|
|
6639
|
+
this.tick(tag ? tag.raw.length : 1);
|
|
6529
6640
|
if (tag && i + tag.raw.length <= pe) {
|
|
6530
6641
|
const name = tag.tagName;
|
|
6531
6642
|
const tagEnd = i + tag.raw.length;
|
|
@@ -6574,7 +6685,7 @@ var Tokenizer = class {
|
|
|
6574
6685
|
}
|
|
6575
6686
|
};
|
|
6576
6687
|
function tokenizeSource(text, options = {}) {
|
|
6577
|
-
const raw = new Tokenizer(text, options.streaming ?? false).run();
|
|
6688
|
+
const raw = new Tokenizer(text, options.streaming ?? false, options.meter).run();
|
|
6578
6689
|
const cp = buildCodePointIndex(text);
|
|
6579
6690
|
const inline = (island) => ({
|
|
6580
6691
|
islandType: island.type,
|
|
@@ -7037,6 +7148,7 @@ exports.openParseSession = openParseSession;
|
|
|
7037
7148
|
exports.pairDisplayMath = pairDisplayMath;
|
|
7038
7149
|
exports.parseDirectiveSlug = parseDirectiveSlug;
|
|
7039
7150
|
exports.parseFenceOpener = parseFenceOpener;
|
|
7151
|
+
exports.pendingDisplayMathOpener = pendingDisplayMathOpener;
|
|
7040
7152
|
exports.readEnvelope = readEnvelope;
|
|
7041
7153
|
exports.readNodeOutcomeValue = readNodeOutcomeValue;
|
|
7042
7154
|
exports.readObjectKind = readObjectKind;
|