recordable 0.1.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.
Files changed (140) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +303 -0
  3. package/dist/actions.d.ts +140 -0
  4. package/dist/actions.d.ts.map +1 -0
  5. package/dist/actions.js +184 -0
  6. package/dist/actions.js.map +1 -0
  7. package/dist/audio/track.d.ts +45 -0
  8. package/dist/audio/track.d.ts.map +1 -0
  9. package/dist/audio/track.js +61 -0
  10. package/dist/audio/track.js.map +1 -0
  11. package/dist/browser/cursor.d.ts +33 -0
  12. package/dist/browser/cursor.d.ts.map +1 -0
  13. package/dist/browser/cursor.js +118 -0
  14. package/dist/browser/cursor.js.map +1 -0
  15. package/dist/browser/dom.d.ts +31 -0
  16. package/dist/browser/dom.d.ts.map +1 -0
  17. package/dist/browser/dom.js +134 -0
  18. package/dist/browser/dom.js.map +1 -0
  19. package/dist/browser/play-button.d.ts +11 -0
  20. package/dist/browser/play-button.d.ts.map +1 -0
  21. package/dist/browser/play-button.js +87 -0
  22. package/dist/browser/play-button.js.map +1 -0
  23. package/dist/browser/runtime.d.ts +66 -0
  24. package/dist/browser/runtime.d.ts.map +1 -0
  25. package/dist/browser/runtime.js +271 -0
  26. package/dist/browser/runtime.js.map +1 -0
  27. package/dist/cli.d.ts +3 -0
  28. package/dist/cli.d.ts.map +1 -0
  29. package/dist/cli.js +131 -0
  30. package/dist/cli.js.map +1 -0
  31. package/dist/compose/mix.d.ts +13 -0
  32. package/dist/compose/mix.d.ts.map +1 -0
  33. package/dist/compose/mix.js +50 -0
  34. package/dist/compose/mix.js.map +1 -0
  35. package/dist/compose/recordable.d.ts +149 -0
  36. package/dist/compose/recordable.d.ts.map +1 -0
  37. package/dist/compose/recordable.js +337 -0
  38. package/dist/compose/recordable.js.map +1 -0
  39. package/dist/compose/session.d.ts +38 -0
  40. package/dist/compose/session.d.ts.map +1 -0
  41. package/dist/compose/session.js +122 -0
  42. package/dist/compose/session.js.map +1 -0
  43. package/dist/config.d.ts +93 -0
  44. package/dist/config.d.ts.map +1 -0
  45. package/dist/config.js +64 -0
  46. package/dist/config.js.map +1 -0
  47. package/dist/errors.d.ts +13 -0
  48. package/dist/errors.d.ts.map +1 -0
  49. package/dist/errors.js +21 -0
  50. package/dist/errors.js.map +1 -0
  51. package/dist/ffmpeg.d.ts +8 -0
  52. package/dist/ffmpeg.d.ts.map +1 -0
  53. package/dist/ffmpeg.js +55 -0
  54. package/dist/ffmpeg.js.map +1 -0
  55. package/dist/formats/json.d.ts +12 -0
  56. package/dist/formats/json.d.ts.map +1 -0
  57. package/dist/formats/json.js +20 -0
  58. package/dist/formats/json.js.map +1 -0
  59. package/dist/formats/markdown/method.d.ts +25 -0
  60. package/dist/formats/markdown/method.d.ts.map +1 -0
  61. package/dist/formats/markdown/method.js +48 -0
  62. package/dist/formats/markdown/method.js.map +1 -0
  63. package/dist/formats/markdown/parse.d.ts +44 -0
  64. package/dist/formats/markdown/parse.d.ts.map +1 -0
  65. package/dist/formats/markdown/parse.js +143 -0
  66. package/dist/formats/markdown/parse.js.map +1 -0
  67. package/dist/fs.d.ts +9 -0
  68. package/dist/fs.d.ts.map +1 -0
  69. package/dist/fs.js +30 -0
  70. package/dist/fs.js.map +1 -0
  71. package/dist/index.d.ts +10 -0
  72. package/dist/index.d.ts.map +1 -0
  73. package/dist/index.js +6 -0
  74. package/dist/index.js.map +1 -0
  75. package/dist/logger.d.ts +21 -0
  76. package/dist/logger.d.ts.map +1 -0
  77. package/dist/logger.js +45 -0
  78. package/dist/logger.js.map +1 -0
  79. package/dist/schema.d.ts +5 -0
  80. package/dist/schema.d.ts.map +1 -0
  81. package/dist/schema.js +100 -0
  82. package/dist/schema.js.map +1 -0
  83. package/dist/script.d.ts +21 -0
  84. package/dist/script.d.ts.map +1 -0
  85. package/dist/script.js +26 -0
  86. package/dist/script.js.map +1 -0
  87. package/dist/targets.d.ts +6 -0
  88. package/dist/targets.d.ts.map +1 -0
  89. package/dist/targets.js +13 -0
  90. package/dist/targets.js.map +1 -0
  91. package/dist/timing.d.ts +41 -0
  92. package/dist/timing.d.ts.map +1 -0
  93. package/dist/timing.js +149 -0
  94. package/dist/timing.js.map +1 -0
  95. package/dist/utils.d.ts +3 -0
  96. package/dist/utils.d.ts.map +1 -0
  97. package/dist/utils.js +8 -0
  98. package/dist/utils.js.map +1 -0
  99. package/dist/validate.d.ts +8 -0
  100. package/dist/validate.d.ts.map +1 -0
  101. package/dist/validate.js +54 -0
  102. package/dist/validate.js.map +1 -0
  103. package/dist/video/recorder.d.ts +57 -0
  104. package/dist/video/recorder.d.ts.map +1 -0
  105. package/dist/video/recorder.js +238 -0
  106. package/dist/video/recorder.js.map +1 -0
  107. package/dist/video/stitch.d.ts +15 -0
  108. package/dist/video/stitch.d.ts.map +1 -0
  109. package/dist/video/stitch.js +111 -0
  110. package/dist/video/stitch.js.map +1 -0
  111. package/dist/voiceover/alignment.d.ts +14 -0
  112. package/dist/voiceover/alignment.d.ts.map +1 -0
  113. package/dist/voiceover/alignment.js +13 -0
  114. package/dist/voiceover/alignment.js.map +1 -0
  115. package/dist/voiceover/cache.d.ts +22 -0
  116. package/dist/voiceover/cache.d.ts.map +1 -0
  117. package/dist/voiceover/cache.js +55 -0
  118. package/dist/voiceover/cache.js.map +1 -0
  119. package/dist/voiceover/compile.d.ts +35 -0
  120. package/dist/voiceover/compile.d.ts.map +1 -0
  121. package/dist/voiceover/compile.js +194 -0
  122. package/dist/voiceover/compile.js.map +1 -0
  123. package/dist/voiceover/elevenlabs.d.ts +16 -0
  124. package/dist/voiceover/elevenlabs.d.ts.map +1 -0
  125. package/dist/voiceover/elevenlabs.js +66 -0
  126. package/dist/voiceover/elevenlabs.js.map +1 -0
  127. package/dist/voiceover/index.d.ts +7 -0
  128. package/dist/voiceover/index.d.ts.map +1 -0
  129. package/dist/voiceover/index.js +8 -0
  130. package/dist/voiceover/index.js.map +1 -0
  131. package/dist/voiceover/mock.d.ts +15 -0
  132. package/dist/voiceover/mock.d.ts.map +1 -0
  133. package/dist/voiceover/mock.js +41 -0
  134. package/dist/voiceover/mock.js.map +1 -0
  135. package/dist/voiceover/types.d.ts +31 -0
  136. package/dist/voiceover/types.d.ts.map +1 -0
  137. package/dist/voiceover/types.js +10 -0
  138. package/dist/voiceover/types.js.map +1 -0
  139. package/package.json +86 -0
  140. package/recordable.schema.json +738 -0
@@ -0,0 +1,143 @@
1
+ import matter from "gray-matter";
2
+ import MarkdownIt from "markdown-it";
3
+ import { callToAction } from "../../actions.js";
4
+ import { parseVoiceover } from "../../validate.js";
5
+ import { isMethodCall, parseMethodCall, parseMethodCalls, } from "./method.js";
6
+ // ─── Markdown authoring surface ──────────────────────────────────────────────
7
+ //
8
+ // A recording can be authored as Markdown: fluent-API calls as inline backtick
9
+ // spans inside narration prose (voiceover/timed), or a fenced block of one call
10
+ // per line (a pure action list, no narration). It's a *surface* over the same
11
+ // keyed-action IR the JSON layer uses — every call goes through `callToAction`.
12
+ //
13
+ // markdown-it tokenises the document, so the awkward cases (blank-line
14
+ // boundaries, indented/`~~~` fences, code spans with commas or parens) are the
15
+ // library's problem; we only interpret the tokens.
16
+ //
17
+ // Pure and browser-free: no TTS, ffmpeg or runtime. The voiceover add-on consumes
18
+ // the offset-bearing narration blocks for timing; the core path extracts markers
19
+ // to a plain action list, exactly as JSON would run.
20
+ const md = new MarkdownIt();
21
+ // Sentinel marking a removed call-span while we normalise narration whitespace.
22
+ // A NUL never appears in prose and survives `\s+` collapsing (it isn't \s).
23
+ const SENTINEL = "\u0000";
24
+ /**
25
+ * Parse a Markdown document into config + ordered blocks. Pure: no audio, no
26
+ * network. Frontmatter (YAML, via gray-matter) carries recording config and an
27
+ * optional `voiceover` block; everything else is body content.
28
+ */
29
+ export function parseMarkdown(md) {
30
+ const { data, content } = matter(md);
31
+ const { voiceover, ...config } = (data ?? {});
32
+ // `voiceover: true` opts in with everything from the environment (provider,
33
+ // voice, model); `false`/absent stays a plain, audio-free recording. An object
34
+ // is validated so a typo'd key (e.g. `voicId`) fails clearly here.
35
+ const vo = voiceover === true
36
+ ? {}
37
+ : voiceover === false || voiceover === undefined
38
+ ? undefined
39
+ : parseVoiceover(voiceover);
40
+ return {
41
+ config: config,
42
+ voiceover: vo,
43
+ blocks: parseBlocks(content),
44
+ };
45
+ }
46
+ /**
47
+ * Tokenise the body and emit a block per top-level token: any fenced/indented
48
+ * code block becomes an action list (the language tag is a visual aid only and is
49
+ * ignored), and each paragraph becomes a narration block.
50
+ */
51
+ function parseBlocks(content) {
52
+ const blocks = [];
53
+ for (const t of md.parse(content, {})) {
54
+ if (t.type === "fence" || t.type === "code_block") {
55
+ const actions = parseMethodCalls(t.content).map((c) => callToAction(c.name, c.args));
56
+ if (actions.length)
57
+ blocks.push({ type: "actions", actions });
58
+ }
59
+ else if (t.type === "inline") {
60
+ // The `inline` token carries a paragraph's (or heading's) content.
61
+ const block = narrationFromInline(t.children ?? []);
62
+ if (block.narration || block.markers.length)
63
+ blocks.push(block);
64
+ }
65
+ }
66
+ return blocks;
67
+ }
68
+ /**
69
+ * Turn one prose paragraph into narration + markers. Call-shaped backtick spans
70
+ * are lifted out as markers; their character offset into the *stripped*
71
+ * narration (what TTS reads) is preserved for the compiler. Non-call backtick
72
+ * spans stay in the prose verbatim. Whitespace is collapsed without shifting any
73
+ * recorded offset.
74
+ */
75
+ export function narrationBlock(raw) {
76
+ return narrationFromInline(md.parseInline(raw, {})[0]?.children ?? []);
77
+ }
78
+ /** Build a narration block from a paragraph's inline tokens (markdown-it). */
79
+ function narrationFromInline(children) {
80
+ const calls = [];
81
+ // Flatten the inline tokens to text, replacing each method-call span with a
82
+ // single sentinel and keeping non-call code spans (and other prose) verbatim.
83
+ // Each span holds at most one call, so a call span maps to exactly one marker.
84
+ let s = "";
85
+ for (const tok of children) {
86
+ if (tok.type === "code_inline" && isMethodCall(tok.content)) {
87
+ calls.push(parseMethodCall(tok.content));
88
+ s += SENTINEL;
89
+ }
90
+ else if (tok.type === "code_inline") {
91
+ s += "`" + tok.content + "`";
92
+ }
93
+ else if (tok.type === "softbreak" || tok.type === "hardbreak") {
94
+ s += " ";
95
+ }
96
+ else if (tok.type === "text") {
97
+ s += tok.content;
98
+ }
99
+ // Emphasis/link wrappers (em_open, link_open, …) carry no text of their own;
100
+ // their text arrives as separate `text` children, so they're skipped here.
101
+ }
102
+ // Collapse all whitespace to single spaces, then drop a space immediately
103
+ // after a sentinel so removing it later never leaves a double space (a single
104
+ // leading space before the sentinel is kept as the word boundary).
105
+ s = s.replace(/\s+/g, " ").trim();
106
+ s = s.replace(new RegExp(SENTINEL + " ", "g"), SENTINEL);
107
+ let narration = "";
108
+ const markers = [];
109
+ let ci = 0;
110
+ for (const ch of s) {
111
+ if (ch === SENTINEL) {
112
+ const c = calls[ci++];
113
+ markers.push({
114
+ step: callToAction(c.name, c.args),
115
+ offset: narration.length,
116
+ });
117
+ }
118
+ else {
119
+ narration += ch;
120
+ }
121
+ }
122
+ // A trailing marker leaves a dangling space ("Lumen. ▮"); drop it and clamp
123
+ // any offset that now points past the end so it fires after the last word.
124
+ narration = narration.replace(/\s+$/, "");
125
+ for (const m of markers)
126
+ if (m.offset > narration.length)
127
+ m.offset = narration.length;
128
+ return { type: "narration", narration, markers };
129
+ }
130
+ /** Extract a plain action list from parsed blocks (markers in order, narration
131
+ * and timing discarded; no audio). */
132
+ export function extractActions(blocks) {
133
+ const actions = [];
134
+ for (const b of blocks) {
135
+ if (b.type === "actions")
136
+ actions.push(...b.actions);
137
+ else
138
+ for (const m of b.markers)
139
+ actions.push(m.step);
140
+ }
141
+ return actions;
142
+ }
143
+ //# sourceMappingURL=parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.js","sourceRoot":"","sources":["../../../src/formats/markdown/parse.ts"],"names":[],"mappings":"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"}
package/dist/fs.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ /** Move a file, falling back to copy+unlink across filesystem boundaries. */
2
+ export declare function moveFile(src: string, dest: string): void;
3
+ /** Build the timestamped output path and ensure its directory exists. */
4
+ export declare function getOutputPath(opts: {
5
+ outputDir: string;
6
+ outputName: string;
7
+ outputTimestamp: boolean;
8
+ }): string;
9
+ //# sourceMappingURL=fs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../src/fs.ts"],"names":[],"mappings":"AAKA,6EAA6E;AAC7E,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAYxD;AAED,yEAAyE;AACzE,wBAAgB,aAAa,CAAC,IAAI,EAAE;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,OAAO,CAAC;CAC1B,GAAG,MAAM,CAQT"}
package/dist/fs.js ADDED
@@ -0,0 +1,30 @@
1
+ // Filesystem helpers: cross-device-safe move and timestamped output-path build.
2
+ import { mkdirSync, renameSync, copyFileSync, unlinkSync } from "node:fs";
3
+ import { dirname } from "node:path";
4
+ /** Move a file, falling back to copy+unlink across filesystem boundaries. */
5
+ export function moveFile(src, dest) {
6
+ try {
7
+ renameSync(src, dest);
8
+ }
9
+ catch {
10
+ // Cross-device (tmp on a different filesystem) — copy then unlink.
11
+ copyFileSync(src, dest);
12
+ try {
13
+ unlinkSync(src);
14
+ }
15
+ catch {
16
+ /* best effort */
17
+ }
18
+ }
19
+ }
20
+ /** Build the timestamped output path and ensure its directory exists. */
21
+ export function getOutputPath(opts) {
22
+ const { outputDir, outputName, outputTimestamp } = opts;
23
+ const timestamp = outputTimestamp
24
+ ? "-" + new Date().toISOString().replace(/\D/g, "").slice(0, 14)
25
+ : "";
26
+ const out = `${outputDir}/${outputName}${timestamp}.mp4`;
27
+ mkdirSync(dirname(out), { recursive: true });
28
+ return out;
29
+ }
30
+ //# sourceMappingURL=fs.js.map
package/dist/fs.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs.js","sourceRoot":"","sources":["../src/fs.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAEhF,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC1E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,6EAA6E;AAC7E,MAAM,UAAU,QAAQ,CAAC,GAAW,EAAE,IAAY;IAChD,IAAI,CAAC;QACH,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,mEAAmE;QACnE,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACxB,IAAI,CAAC;YACH,UAAU,CAAC,GAAG,CAAC,CAAC;QAClB,CAAC;QAAC,MAAM,CAAC;YACP,iBAAiB;QACnB,CAAC;IACH,CAAC;AACH,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,aAAa,CAAC,IAI7B;IACC,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,EAAE,GAAG,IAAI,CAAC;IACxD,MAAM,SAAS,GAAG,eAAe;QAC/B,CAAC,CAAC,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;QAChE,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,GAAG,GAAG,GAAG,SAAS,IAAI,UAAU,GAAG,SAAS,MAAM,CAAC;IACzD,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7C,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,10 @@
1
+ export { Recordable } from "./compose/recordable.js";
2
+ export { ACTIONS, callToAction, validateAction } from "./actions.js";
3
+ export type { Action } from "./actions.js";
4
+ export type { Script } from "./script.js";
5
+ export { fromJSON, runScript } from "./formats/json.js";
6
+ export { buildSchema } from "./schema.js";
7
+ export { parseMarkdown } from "./formats/markdown/parse.js";
8
+ export type { ParsedMarkdown, MarkdownBlock, NarrationBlock, ActionsBlock, } from "./formats/markdown/parse.js";
9
+ export type { RecordableConfig, VoiceoverConfig, AudioOptions, InsertOptions, WaitForOptions, ResolvedConfig, } from "./config.js";
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACrE,YAAY,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,YAAY,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,YAAY,EACV,cAAc,EACd,aAAa,EACb,cAAc,EACd,YAAY,GACb,MAAM,6BAA6B,CAAC;AACrC,YAAY,EACV,gBAAgB,EAChB,eAAe,EACf,YAAY,EACZ,aAAa,EACb,cAAc,EACd,cAAc,GACf,MAAM,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export { Recordable } from "./compose/recordable.js";
2
+ export { ACTIONS, callToAction, validateAction } from "./actions.js";
3
+ export { fromJSON, runScript } from "./formats/json.js";
4
+ export { buildSchema } from "./schema.js";
5
+ export { parseMarkdown } from "./formats/markdown/parse.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAGrE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * A callable logger. Call it for a normal progress line — a padded `name` label
3
+ * plus an optional value — and use `.success` / `.warn` / `.error` for status,
4
+ * conveyed by the colour of the `[Recordable]` prefix: blue progress, green
5
+ * success, yellow warn, red error. Stream + `silent` behaviour per method below.
6
+ */
7
+ export interface Logger {
8
+ (name: string, value?: string): void;
9
+ /** Completion line, green prefix → stdout. Suppressed when `silent`. */
10
+ success(name: string, value?: string): void;
11
+ /** Non-fatal diagnostic → stderr. Suppressed when `silent`. */
12
+ warn(message: string): void;
13
+ /** Failure → stderr. Always printed, even when `silent`. */
14
+ error(message: string): void;
15
+ }
16
+ /**
17
+ * Build a logger. `isSilent` is read on every call so runtime `silent` changes
18
+ * (via `setConfig`) take effect immediately.
19
+ */
20
+ export declare function createLogger(isSilent: () => boolean): Logger;
21
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,WAAW,MAAM;IACrB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,wEAAwE;IACxE,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5C,+DAA+D;IAC/D,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,4DAA4D;IAC5D,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AA6BD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,OAAO,GAAG,MAAM,CAiB5D"}
package/dist/logger.js ADDED
@@ -0,0 +1,45 @@
1
+ // Console logger: a status-coloured `[Recordable]` prefix plus a message body.
2
+ const PREFIX = "[Recordable]";
3
+ // 256-colour codes for the prefix, keyed by status.
4
+ const COLOR = {
5
+ info: "38;5;111",
6
+ success: "38;5;114",
7
+ warn: "38;5;221",
8
+ error: "38;5;203",
9
+ };
10
+ /** Colour is on only for TTY streams, and never when NO_COLOR is set. */
11
+ function colorEnabled(stream) {
12
+ return !process.env.NO_COLOR && Boolean(stream.isTTY);
13
+ }
14
+ /** Format a line: a status-coloured prefix followed by the message body. */
15
+ function format(code, stream, label, value) {
16
+ const prefix = colorEnabled(stream) ? `\x1b[${code}m${PREFIX}\x1b[0m` : PREFIX;
17
+ const body = value !== undefined ? `${label.padEnd(8)}${value}` : label;
18
+ return `${prefix} ${body}`;
19
+ }
20
+ /**
21
+ * Build a logger. `isSilent` is read on every call so runtime `silent` changes
22
+ * (via `setConfig`) take effect immediately.
23
+ */
24
+ export function createLogger(isSilent) {
25
+ const log = ((name, value) => {
26
+ if (isSilent())
27
+ return;
28
+ console.log(format(COLOR.info, process.stdout, name, value));
29
+ });
30
+ log.success = (name, value) => {
31
+ if (isSilent())
32
+ return;
33
+ console.log(format(COLOR.success, process.stdout, name, value));
34
+ };
35
+ log.warn = (message) => {
36
+ if (isSilent())
37
+ return;
38
+ console.warn(format(COLOR.warn, process.stderr, message));
39
+ };
40
+ log.error = (message) => {
41
+ console.error(format(COLOR.error, process.stderr, message));
42
+ };
43
+ return log;
44
+ }
45
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAkB/E,MAAM,MAAM,GAAG,cAAc,CAAC;AAE9B,oDAAoD;AACpD,MAAM,KAAK,GAAG;IACZ,IAAI,EAAE,UAAU;IAChB,OAAO,EAAE,UAAU;IACnB,IAAI,EAAE,UAAU;IAChB,KAAK,EAAE,UAAU;CAClB,CAAC;AAEF,yEAAyE;AACzE,SAAS,YAAY,CAAC,MAA0B;IAC9C,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACxD,CAAC;AAED,4EAA4E;AAC5E,SAAS,MAAM,CACb,IAAY,EACZ,MAA0B,EAC1B,KAAa,EACb,KAAc;IAEd,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,IAAI,IAAI,MAAM,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;IAC/E,MAAM,IAAI,GAAG,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;IACxE,OAAO,GAAG,MAAM,IAAI,IAAI,EAAE,CAAC;AAC7B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,QAAuB;IAClD,MAAM,GAAG,GAAG,CAAC,CAAC,IAAY,EAAE,KAAc,EAAE,EAAE;QAC5C,IAAI,QAAQ,EAAE;YAAE,OAAO;QACvB,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;IAC/D,CAAC,CAAW,CAAC;IACb,GAAG,CAAC,OAAO,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QAC5B,IAAI,QAAQ,EAAE;YAAE,OAAO;QACvB,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;IAClE,CAAC,CAAC;IACF,GAAG,CAAC,IAAI,GAAG,CAAC,OAAO,EAAE,EAAE;QACrB,IAAI,QAAQ,EAAE;YAAE,OAAO;QACvB,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC5D,CAAC,CAAC;IACF,GAAG,CAAC,KAAK,GAAG,CAAC,OAAO,EAAE,EAAE;QACtB,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC9D,CAAC,CAAC;IACF,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,5 @@
1
+ type JSONSchema = Record<string, unknown>;
2
+ /** Build the full JSON Schema for a Recordable script file. */
3
+ export declare function buildSchema(): JSONSchema;
4
+ export {};
5
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAYA,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AA6E1C,+DAA+D;AAC/D,wBAAgB,WAAW,IAAI,UAAU,CA+BxC"}
package/dist/schema.js ADDED
@@ -0,0 +1,100 @@
1
+ import * as z from "zod";
2
+ import { ACTIONS } from "./actions.js";
3
+ import { ConfigSchema } from "./config.js";
4
+ const SCHEMA_URL = "https://json-schema.org/draft/2020-12/schema";
5
+ /** Recursively delete every `key` from a JSON Schema object tree. */
6
+ function stripKey(node, key) {
7
+ if (Array.isArray(node)) {
8
+ node.forEach((n) => stripKey(n, key));
9
+ }
10
+ else if (node && typeof node === "object") {
11
+ delete node[key];
12
+ Object.values(node).forEach((v) => stripKey(v, key));
13
+ }
14
+ }
15
+ /** The properties + required keys an action contributes (beyond `action`),
16
+ * read from its Zod schema. `setConfig`'s nested config points at the shared
17
+ * `$defs/config` rather than inlining the whole config schema. */
18
+ function actionShape(name) {
19
+ const js = z.toJSONSchema(ACTIONS[name], {
20
+ io: "input",
21
+ });
22
+ const properties = (js.properties ?? {});
23
+ const required = (js.required ?? []);
24
+ if ("config" in properties)
25
+ properties.config = { $ref: "#/$defs/config" };
26
+ return { properties, required };
27
+ }
28
+ /**
29
+ * The `action` schema: a single object whose `action` key enumerates every action,
30
+ * with one `if/then` per action applying that action's keys.
31
+ *
32
+ * This shape (rather than a `oneOf` of per-action objects) is what makes editor
33
+ * autocomplete offer *all* action names: VS Code only suggests `const` values
34
+ * from `oneOf` branches the current object already satisfies, so a `oneOf` lists
35
+ * just the no-arg actions until you've typed the other keys. The `enum` + `then`
36
+ * form keeps full autocomplete while preserving required-key and typo checks.
37
+ */
38
+ function actionSchema() {
39
+ const actions = Object.keys(ACTIONS);
40
+ const allOf = actions.map((action) => {
41
+ const { properties, required } = actionShape(action);
42
+ return {
43
+ if: { properties: { action: { const: action } }, required: ["action"] },
44
+ then: {
45
+ properties: { action: { const: action }, ...properties },
46
+ required: ["action", ...required],
47
+ additionalProperties: false,
48
+ },
49
+ };
50
+ });
51
+ return {
52
+ type: "object",
53
+ required: ["action"],
54
+ properties: {
55
+ action: { enum: actions, description: "The action to perform." },
56
+ },
57
+ allOf,
58
+ };
59
+ }
60
+ /** Schema for the `config` block — derived from the Zod {@link ConfigSchema}.
61
+ * Uses the input view (every field optional) and strips the emitted defaults so
62
+ * the authoring schema stays type-only. `baseDir` is set by the CLI/runtime, not
63
+ * authored in script files, so it's omitted. */
64
+ function configSchema() {
65
+ const schema = z.toJSONSchema(ConfigSchema, { io: "input" });
66
+ delete schema.$schema;
67
+ stripKey(schema, "default");
68
+ delete schema.properties.baseDir;
69
+ return schema;
70
+ }
71
+ /** Build the full JSON Schema for a Recordable script file. */
72
+ export function buildSchema() {
73
+ const action = actionSchema();
74
+ const objectForm = {
75
+ type: "object",
76
+ required: ["actions"],
77
+ additionalProperties: false,
78
+ properties: {
79
+ $schema: { type: "string" },
80
+ config: { $ref: "#/$defs/config" },
81
+ actions: { type: "array", items: { $ref: "#/$defs/action" } },
82
+ },
83
+ };
84
+ const arrayForm = {
85
+ type: "array",
86
+ items: { $ref: "#/$defs/action" },
87
+ };
88
+ return {
89
+ $schema: SCHEMA_URL,
90
+ $id: "https://raw.githubusercontent.com/paragramagency/recordable/main/recordable.schema.json",
91
+ title: "Recordable script",
92
+ description: "A declarative recording script: config + an array of actions.",
93
+ oneOf: [objectForm, arrayForm],
94
+ $defs: {
95
+ config: configSchema(),
96
+ action,
97
+ },
98
+ };
99
+ }
100
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type { Action } from "./actions.js";
2
+ import type { RecordableConfig } from "./config.js";
3
+ /** A whole script: a bare array of actions, or an object pairing config + actions. */
4
+ export type Script = Action[] | {
5
+ $schema?: string;
6
+ config?: RecordableConfig;
7
+ actions: Action[];
8
+ };
9
+ /** Split a `Script` into its optional config and action array. */
10
+ export declare function splitScript(script: Script): {
11
+ config?: RecordableConfig;
12
+ actions: Action[];
13
+ };
14
+ /**
15
+ * Resolve relative `visit` URLs (`./`, `../`) against `baseDir` so a script and
16
+ * its pages travel together regardless of cwd: each becomes a `file://` URL.
17
+ * Mutates the actions in place; a no-op when `baseDir` is empty.
18
+ * (Relative `outputDir`/`assetsDir` are resolved alongside, in the config.)
19
+ */
20
+ export declare function resolveVisitUrls(actions: Action[], baseDir: string): void;
21
+ //# sourceMappingURL=script.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"script.d.ts","sourceRoot":"","sources":["../src/script.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAsBpD,sFAAsF;AACtF,MAAM,MAAM,MAAM,GACd,MAAM,EAAE,GACR;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAEvE,kEAAkE;AAClE,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG;IAC3C,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,CAGA;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAWzE"}
package/dist/script.js ADDED
@@ -0,0 +1,26 @@
1
+ import { resolve } from "node:path";
2
+ import { pathToFileURL } from "node:url";
3
+ /** Split a `Script` into its optional config and action array. */
4
+ export function splitScript(script) {
5
+ if (Array.isArray(script))
6
+ return { actions: script };
7
+ return { config: script.config, actions: script.actions };
8
+ }
9
+ /**
10
+ * Resolve relative `visit` URLs (`./`, `../`) against `baseDir` so a script and
11
+ * its pages travel together regardless of cwd: each becomes a `file://` URL.
12
+ * Mutates the actions in place; a no-op when `baseDir` is empty.
13
+ * (Relative `outputDir`/`assetsDir` are resolved alongside, in the config.)
14
+ */
15
+ export function resolveVisitUrls(actions, baseDir) {
16
+ if (!baseDir)
17
+ return;
18
+ for (const step of actions) {
19
+ if (step.action === "visit" &&
20
+ typeof step.url === "string" &&
21
+ /^\.\.?\//.test(step.url)) {
22
+ step.url = pathToFileURL(resolve(baseDir, step.url)).href;
23
+ }
24
+ }
25
+ }
26
+ //# sourceMappingURL=script.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"script.js","sourceRoot":"","sources":["../src/script.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AA6BzC,kEAAkE;AAClE,MAAM,UAAU,WAAW,CAAC,MAAc;IAIxC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IACtD,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;AAC5D,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAiB,EAAE,OAAe;IACjE,IAAI,CAAC,OAAO;QAAE,OAAO;IACrB,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;QAC3B,IACE,IAAI,CAAC,MAAM,KAAK,OAAO;YACvB,OAAO,IAAI,CAAC,GAAG,KAAK,QAAQ;YAC5B,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EACzB,CAAC;YACD,IAAI,CAAC,GAAG,GAAG,aAAa,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;QAC5D,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,6 @@
1
+ /** Resolve a target string to a Puppeteer selector.
2
+ * Prefix with `text:` for plain-text matching; everything else is a CSS selector. */
3
+ export declare function resolveTarget(target: string): string;
4
+ /** Returns true if the string is a CSS position keyword or percentage. */
5
+ export declare function isPositionValue(value: string): boolean;
6
+ //# sourceMappingURL=targets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"targets.d.ts","sourceRoot":"","sources":["../src/targets.ts"],"names":[],"mappings":"AAGA;sFACsF;AACtF,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,0EAA0E;AAC1E,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAGtD"}
@@ -0,0 +1,13 @@
1
+ // Target resolution: author-facing target strings → Puppeteer selectors, plus
2
+ // the position-keyword test used by zoom/scroll origins.
3
+ /** Resolve a target string to a Puppeteer selector.
4
+ * Prefix with `text:` for plain-text matching; everything else is a CSS selector. */
5
+ export function resolveTarget(target) {
6
+ return target.startsWith("text:") ? `::-p-text(${target.slice(5)})` : target;
7
+ }
8
+ /** Returns true if the string is a CSS position keyword or percentage. */
9
+ export function isPositionValue(value) {
10
+ const token = "(top|bottom|left|right|center|\\d+%)";
11
+ return new RegExp(`^${token}(\\s+${token})?$`, "i").test(value.trim());
12
+ }
13
+ //# sourceMappingURL=targets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"targets.js","sourceRoot":"","sources":["../src/targets.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,yDAAyD;AAEzD;sFACsF;AACtF,MAAM,UAAU,aAAa,CAAC,MAAc;IAC1C,OAAO,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,aAAa,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;AAC/E,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,MAAM,KAAK,GAAG,sCAAsC,CAAC;IACrD,OAAO,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,KAAK,KAAK,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;AACzE,CAAC"}
@@ -0,0 +1,41 @@
1
+ import type { RecordableConfig } from "./config.js";
2
+ import type { Action } from "./actions.js";
3
+ /** Cursor "press" dip on click — scale down… */
4
+ export declare const PRESS_DOWN_MS = 120;
5
+ /** …then settle back. clickEffect spends their sum. */
6
+ export declare const PRESS_SETTLE_MS = 60;
7
+ /** Settle beat between arriving at a target and pressing (jitter base). */
8
+ export declare const PRE_CLICK_MS = 100;
9
+ /** Post-click probe: how long a click waits for a possible navigation to begin. */
10
+ export declare const NAV_PROBE_MS = 200;
11
+ /** Cursor-move duration for a known pixel distance — eased, clamped. */
12
+ export declare function cursorMoveMs(dist: number): number;
13
+ /** Estimated wall-clock an interactive action spends getting the cursor to its
14
+ * target and pressing — *before* its payload (the keystrokes of a `type`, the
15
+ * value-set of a `select`). The compiler adds this to elapsed so the next
16
+ * narrated word is placed after the gesture, not on top of it. With the cursor
17
+ * overlay off, only the real (non-animated) costs remain. */
18
+ export declare function gestureLeadMs(step: Action, cfg: RecordableConfig): number;
19
+ /** How long an action occupies the timeline, so the next wait measures from its end.
20
+ * Omitted durations use the config default, never an elastic fit. The cursor's
21
+ * travel-and-press to a target (`gestureLeadMs`) is added on top, so a click/type
22
+ * doesn't silently push the rest of the paragraph late. */
23
+ export declare function actionDurationMs(step: Action, cfg: RecordableConfig): Promise<number>;
24
+ /** Returns `base` ± `variance` (defaults to ±50% of base). */
25
+ export declare function jitter(base: number, variance?: number): number;
26
+ /** Deterministic 32-bit string hash (FNV-1a). Seeds the typing PRNG so the same
27
+ * text always types with the same rhythm (reproducible recordings). */
28
+ export declare function hashString(s: string): number;
29
+ /** mulberry32 PRNG → a function yielding floats in [0, 1). Pure integer math,
30
+ * platform-independent, so a given seed reproduces the same sequence anywhere. */
31
+ export declare function rng(seed: number): () => number;
32
+ /** Total time (ms) a `type` action occupies — a pure function of text length and
33
+ * speed (cps). This is the contract the voiceover compiler estimates against, so
34
+ * it MUST stay identical to the compiler's `type` estimate. Jitter never alters it. */
35
+ export declare function typingDuration(text: string, speed: number): number;
36
+ /** Per-keystroke delays (ms) that sum to exactly `total`, with seeded, zero-sum
37
+ * jitter. Returns `[leadPause, delayAfterChar1, …]` (lead beat + one per code
38
+ * point). Punctuation gets a heavier structural weight (a natural micro-pause),
39
+ * but all weights are normalised back onto `total` so the sum is invariant. */
40
+ export declare function typingGaps(text: string, speed: number, total?: number, amount?: number): number[];
41
+ //# sourceMappingURL=timing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timing.d.ts","sourceRoot":"","sources":["../src/timing.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAW3C,gDAAgD;AAChD,eAAO,MAAM,aAAa,MAAM,CAAC;AACjC,uDAAuD;AACvD,eAAO,MAAM,eAAe,KAAK,CAAC;AAIlC,2EAA2E;AAC3E,eAAO,MAAM,YAAY,MAAM,CAAC;AAEhC,mFAAmF;AACnF,eAAO,MAAM,YAAY,MAAM,CAAC;AAMhC,wEAAwE;AACxE,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEjD;AAQD;;;;8DAI8D;AAC9D,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,gBAAgB,GAAG,MAAM,CAmBzE;AAED;;;4DAG4D;AAC5D,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,gBAAgB,GACpB,OAAO,CAAC,MAAM,CAAC,CA8BjB;AAID,8DAA8D;AAC9D,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,SAAM,GAAG,MAAM,CAE3D;AAQD;wEACwE;AACxE,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAO5C;AAED;mFACmF;AACnF,wBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,MAAM,CAQ9C;AAED;;wFAEwF;AACxF,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAElE;AAED;;;gFAGgF;AAChF,wBAAgB,UAAU,CACxB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,KAAK,GAAE,MAAoC,EAC3C,MAAM,SAAO,GACZ,MAAM,EAAE,CAgBV"}