sakuga 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Adel Rodriguez
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,9 @@
1
+ <div align="center">
2
+ <h1 align="center">sakuga</h1>
3
+
4
+ <p align="center">
5
+ <strong>Create code animations</strong>
6
+ </p>
7
+ </div>
8
+
9
+ Made with [🥐 `pastry`](https://github.com/adelrodriguez/pastry)
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ declare const program: unknown;
2
+ export { program };
package/dist/cli.js ADDED
@@ -0,0 +1,233 @@
1
+ import {
2
+ DEFAULT_BLOCK_DURATION,
3
+ DEFAULT_FPS,
4
+ DEFAULT_HEIGHT,
5
+ DEFAULT_THEME,
6
+ DEFAULT_TRANSITION_DURATION_MS,
7
+ DEFAULT_WIDTH,
8
+ __require,
9
+ __toESM,
10
+ buildScene,
11
+ buildTransitionDiff,
12
+ buildTransitionTokens,
13
+ easeInOutCubic,
14
+ parseMarkdownCodeBlocks,
15
+ renderFrame,
16
+ resolveTheme
17
+ } from "./shared/chunk-ks7faw1s.js";
18
+
19
+ // src/cli.ts
20
+ import { Args, Command, Options } from "@effect/cli";
21
+ import { FileSystem, Path } from "@effect/platform";
22
+ import { NodeContext, NodeRuntime } from "@effect/platform-node";
23
+ import { Console, Effect as Effect3 } from "effect";
24
+
25
+ // src/lib/video.ts
26
+ import * as OS from "node:os";
27
+ import { createCanvas } from "@napi-rs/canvas";
28
+ import { Effect as Effect2, Ref, Stream } from "effect";
29
+ import {
30
+ FilePathTarget,
31
+ Mp4OutputFormat,
32
+ Output,
33
+ QUALITY_HIGH,
34
+ VideoSample,
35
+ VideoSampleSource
36
+ } from "mediabunny";
37
+
38
+ // src/lib/webcodecs.ts
39
+ import { Effect } from "effect";
40
+ var ensureWebCodecs = () => Effect.tryPromise({
41
+ catch: (error) => {
42
+ const message = error instanceof Error ? error.message : String(error);
43
+ const isMissingLibrary = message.includes("Library not loaded");
44
+ const baseMessage = "WebCodecs not available.";
45
+ const detailMessage = isMissingLibrary ? "Install FFmpeg (brew install ffmpeg) and ensure libavcodec is available." : "Install node-webcodecs plus FFmpeg (brew install ffmpeg pkg-config).";
46
+ return new Error(`${baseMessage} ${detailMessage}`, { cause: error });
47
+ },
48
+ try: async () => {
49
+ const globalScope = globalThis;
50
+ if (globalScope.VideoEncoder && globalScope.VideoFrame) {
51
+ return;
52
+ }
53
+ const webcodecs = await import("node-webcodecs");
54
+ const assignGlobal = (key, value) => {
55
+ if (globalScope[key]) {
56
+ return;
57
+ }
58
+ globalScope[key] = value;
59
+ };
60
+ assignGlobal("VideoEncoder", webcodecs.VideoEncoder);
61
+ assignGlobal("VideoFrame", webcodecs.VideoFrame);
62
+ assignGlobal("EncodedVideoChunk", webcodecs.EncodedVideoChunk);
63
+ assignGlobal("AudioEncoder", webcodecs.AudioEncoder);
64
+ assignGlobal("EncodedAudioChunk", webcodecs.EncodedAudioChunk);
65
+ assignGlobal("AudioData", webcodecs.AudioData);
66
+ }
67
+ });
68
+
69
+ // src/lib/video.ts
70
+ var resolveConcurrency = () => Effect2.sync(() => Math.min(4, OS.availableParallelism()));
71
+ var makeOutput = (outputPath) => Effect2.sync(() => new Output({
72
+ format: new Mp4OutputFormat,
73
+ target: new FilePathTarget(outputPath)
74
+ }));
75
+ var makeVideoSource = () => Effect2.sync(() => new VideoSampleSource({
76
+ bitrate: QUALITY_HIGH,
77
+ codec: "avc",
78
+ onEncoderConfig: (config) => {
79
+ const encoderConfig = config;
80
+ encoderConfig.useWorkerThread = false;
81
+ }
82
+ }));
83
+ var computeFrameCounts = (transitionDurationMs) => {
84
+ const frameDuration = 1 / DEFAULT_FPS;
85
+ const blockFrames = Math.max(1, Math.round(DEFAULT_BLOCK_DURATION * DEFAULT_FPS));
86
+ const transitionFrames = Math.max(1, Math.round(transitionDurationMs / 1000 * DEFAULT_FPS));
87
+ return {
88
+ blockFrames,
89
+ frameDuration,
90
+ transitionFrames
91
+ };
92
+ };
93
+ var renderAndWriteFrame = (context, output, videoSource, frameDuration, frameIndexRef) => (frame) => Effect2.gen(function* () {
94
+ const frameIndex = yield* Ref.get(frameIndexRef);
95
+ renderFrame(context, DEFAULT_WIDTH, DEFAULT_HEIGHT, frame);
96
+ const rgba = context.canvas.data();
97
+ const sample = new VideoSample(rgba, {
98
+ codedHeight: DEFAULT_HEIGHT,
99
+ codedWidth: DEFAULT_WIDTH,
100
+ duration: frameDuration,
101
+ format: "RGBA",
102
+ timestamp: frameIndex * frameDuration
103
+ });
104
+ yield* Effect2.tryPromise({
105
+ catch: (error) => error instanceof Error ? error : new Error(String(error)),
106
+ try: () => videoSource.add(sample)
107
+ });
108
+ sample.close();
109
+ yield* Ref.set(frameIndexRef, frameIndex + 1);
110
+ });
111
+ var buildSceneFrames = (scene, blockFrames) => Stream.range(1, blockFrames).pipe(Stream.map(() => ({
112
+ background: scene.background,
113
+ kind: "scene",
114
+ opacity: 1,
115
+ positionX: scene.blockX,
116
+ positionY: scene.blockY,
117
+ scene
118
+ })));
119
+ var buildTransitionFrames = (scene, nextScene, transitionFrames) => {
120
+ const diff = buildTransitionDiff(scene, nextScene);
121
+ return Stream.range(1, transitionFrames).pipe(Stream.map((index) => {
122
+ const rawProgress = index / transitionFrames;
123
+ const progress = easeInOutCubic(rawProgress);
124
+ const blendedBackground = blendColors(scene.background, nextScene.background, progress);
125
+ const tokens = buildTransitionTokens(diff, progress);
126
+ return {
127
+ background: blendedBackground,
128
+ kind: "transition",
129
+ tokens
130
+ };
131
+ }));
132
+ };
133
+ var buildFramesStream = (scenes, blockFrames, transitionFrames) => Stream.fromIterable(scenes).pipe(Stream.zipWithIndex, Stream.flatMap(([scene, index]) => {
134
+ const nextScene = scenes[index + 1];
135
+ const base = buildSceneFrames(scene, blockFrames);
136
+ return nextScene ? Stream.concat(base, buildTransitionFrames(scene, nextScene, transitionFrames)) : base;
137
+ }));
138
+ var blendColors = (from, to, progress) => {
139
+ const fromColor = parseHexColor(from);
140
+ const toColor = parseHexColor(to);
141
+ const blended = {
142
+ alpha: lerp(fromColor.alpha, toColor.alpha, progress),
143
+ blue: lerp(fromColor.blue, toColor.blue, progress),
144
+ green: lerp(fromColor.green, toColor.green, progress),
145
+ red: lerp(fromColor.red, toColor.red, progress)
146
+ };
147
+ return `rgba(${Math.round(blended.red)}, ${Math.round(blended.green)}, ${Math.round(blended.blue)}, ${blended.alpha.toFixed(3)})`;
148
+ };
149
+ var parseHexColor = (color) => {
150
+ const normalized = color.replace("#", "").trim();
151
+ if (normalized.length !== 6 && normalized.length !== 8) {
152
+ return {
153
+ alpha: 1,
154
+ blue: 11,
155
+ green: 11,
156
+ red: 11
157
+ };
158
+ }
159
+ const red = Number.parseInt(normalized.slice(0, 2), 16);
160
+ const green = Number.parseInt(normalized.slice(2, 4), 16);
161
+ const blue = Number.parseInt(normalized.slice(4, 6), 16);
162
+ const alpha = normalized.length === 8 ? Number.parseInt(normalized.slice(6, 8), 16) / 255 : 1;
163
+ return {
164
+ alpha,
165
+ blue,
166
+ green,
167
+ red
168
+ };
169
+ };
170
+ var lerp = (start, end, progress) => start + (end - start) * progress;
171
+ var renderVideo = (outputPath, theme, codeBlocks, options = {}) => Effect2.gen(function* () {
172
+ yield* ensureWebCodecs();
173
+ const concurrency = options.concurrency ?? (yield* resolveConcurrency());
174
+ const transitionDurationMs = options.transitionDurationMs ?? DEFAULT_TRANSITION_DURATION_MS;
175
+ const canvas = createCanvas(DEFAULT_WIDTH, DEFAULT_HEIGHT);
176
+ const context = canvas.getContext("2d");
177
+ const scenes = yield* Effect2.forEach(codeBlocks, (codeBlock) => buildScene(context, codeBlock, theme, DEFAULT_WIDTH, DEFAULT_HEIGHT), { concurrency });
178
+ const frameCounts = computeFrameCounts(transitionDurationMs);
179
+ const frameIndexRef = yield* Ref.make(0);
180
+ return yield* Effect2.scoped(Effect2.gen(function* () {
181
+ const output = yield* Effect2.acquireRelease(makeOutput(outputPath), (resource) => Effect2.tryPromise({
182
+ catch: (error) => error instanceof Error ? error : new Error(String(error)),
183
+ try: () => resource.finalize()
184
+ }).pipe(Effect2.orDie));
185
+ const videoSource = yield* Effect2.acquireRelease(makeVideoSource(), (resource) => Effect2.sync(() => {
186
+ resource.close();
187
+ }));
188
+ yield* Effect2.sync(() => {
189
+ output.addVideoTrack(videoSource, { frameRate: DEFAULT_FPS });
190
+ });
191
+ yield* Effect2.tryPromise({
192
+ catch: (error) => error instanceof Error ? error : new Error(String(error)),
193
+ try: () => output.start()
194
+ });
195
+ const frameStream = buildFramesStream(scenes, frameCounts.blockFrames, frameCounts.transitionFrames);
196
+ yield* Stream.runForEach(frameStream, renderAndWriteFrame(context, output, videoSource, frameCounts.frameDuration, frameIndexRef));
197
+ return outputPath;
198
+ }));
199
+ });
200
+
201
+ // src/cli.ts
202
+ var version = await "0.0.1";
203
+ var file = Args.file({ exists: "yes", name: "file" });
204
+ var theme = Options.text("theme").pipe(Options.withAlias("t"), Options.withDefault(DEFAULT_THEME), Options.withDescription("Shiki theme for syntax highlighting."));
205
+ var transition = Options.integer("transition").pipe(Options.withAlias("tr"), Options.withDefault(DEFAULT_TRANSITION_DURATION_MS), Options.withDescription("Transition duration between slides in milliseconds."));
206
+ var main = Command.make("looney", { file, theme, transition }).pipe(Command.withDescription("Create code animation videos from Markdown."), Command.withHandler(({ file: file2, theme: theme2, transition: transition2 }) => Effect3.gen(function* () {
207
+ const fs = yield* FileSystem.FileSystem;
208
+ const path = yield* Path.Path;
209
+ const markdown = yield* fs.readFileString(file2);
210
+ const blocks = yield* parseMarkdownCodeBlocks(markdown);
211
+ if (blocks.length === 0) {
212
+ yield* Effect3.fail(new Error("No fenced code blocks found."));
213
+ }
214
+ if (transition2 <= 0) {
215
+ yield* Effect3.fail(new Error("Transition duration must be greater than 0."));
216
+ }
217
+ const resolvedTheme = yield* resolveTheme(theme2);
218
+ const parsedOutputPath = path.parse(file2);
219
+ const outputPath = path.join(parsedOutputPath.dir, `${parsedOutputPath.name}.mp4`);
220
+ yield* Console.log(`Rendering ${blocks.length} code blocks...`);
221
+ yield* renderVideo(outputPath, resolvedTheme, blocks, {
222
+ transitionDurationMs: transition2
223
+ });
224
+ yield* Console.log(`Video created at ${outputPath}`);
225
+ })));
226
+ var program = Command.run(main, { name: "looney", version });
227
+ program(process.argv).pipe(Effect3.tapErrorCause(Effect3.logError), Effect3.provide(NodeContext.layer), NodeRuntime.runMain);
228
+ export {
229
+ program
230
+ };
231
+
232
+ //# debugId=327D1771FEFA40CD64756E2164756E21
233
+ //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsic3JjL2NsaS50cyIsICJzcmMvbGliL3ZpZGVvLnRzIiwgInNyYy9saWIvd2ViY29kZWNzLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWwogICAgImltcG9ydCB7IEFyZ3MsIENvbW1hbmQsIE9wdGlvbnMgfSBmcm9tIFwiQGVmZmVjdC9jbGlcIlxuaW1wb3J0IHsgRmlsZVN5c3RlbSwgUGF0aCB9IGZyb20gXCJAZWZmZWN0L3BsYXRmb3JtXCJcbmltcG9ydCB7IE5vZGVDb250ZXh0LCBOb2RlUnVudGltZSB9IGZyb20gXCJAZWZmZWN0L3BsYXRmb3JtLW5vZGVcIlxuaW1wb3J0IHsgQ29uc29sZSwgRWZmZWN0IH0gZnJvbSBcImVmZmVjdFwiXG5pbXBvcnQgeyBERUZBVUxUX1RIRU1FLCBERUZBVUxUX1RSQU5TSVRJT05fRFVSQVRJT05fTVMgfSBmcm9tIFwiLi9saWIvY29uc3RhbnRzXCJcbmltcG9ydCB7IHBhcnNlTWFya2Rvd25Db2RlQmxvY2tzIH0gZnJvbSBcIi4vbGliL21hcmtkb3duXCJcbmltcG9ydCB7IHJlc29sdmVUaGVtZSB9IGZyb20gXCIuL2xpYi90aGVtZVwiXG5pbXBvcnQgeyByZW5kZXJWaWRlbyB9IGZyb20gXCIuL2xpYi92aWRlb1wiXG5pbXBvcnQgeyByZWFkVmVyc2lvbiB9IGZyb20gXCIuL3ZlcnNpb25cIiB3aXRoIHsgdHlwZTogXCJtYWNyb1wiIH1cblxuY29uc3QgdmVyc2lvbiA9IGF3YWl0IHJlYWRWZXJzaW9uKClcblxuY29uc3QgZmlsZSA9IEFyZ3MuZmlsZSh7IGV4aXN0czogXCJ5ZXNcIiwgbmFtZTogXCJmaWxlXCIgfSlcbmNvbnN0IHRoZW1lID0gT3B0aW9ucy50ZXh0KFwidGhlbWVcIikucGlwZShcbiAgT3B0aW9ucy53aXRoQWxpYXMoXCJ0XCIpLFxuICBPcHRpb25zLndpdGhEZWZhdWx0KERFRkFVTFRfVEhFTUUpLFxuICBPcHRpb25zLndpdGhEZXNjcmlwdGlvbihcIlNoaWtpIHRoZW1lIGZvciBzeW50YXggaGlnaGxpZ2h0aW5nLlwiKVxuKVxuY29uc3QgdHJhbnNpdGlvbiA9IE9wdGlvbnMuaW50ZWdlcihcInRyYW5zaXRpb25cIikucGlwZShcbiAgT3B0aW9ucy53aXRoQWxpYXMoXCJ0clwiKSxcbiAgT3B0aW9ucy53aXRoRGVmYXVsdChERUZBVUxUX1RSQU5TSVRJT05fRFVSQVRJT05fTVMpLFxuICBPcHRpb25zLndpdGhEZXNjcmlwdGlvbihcIlRyYW5zaXRpb24gZHVyYXRpb24gYmV0d2VlbiBzbGlkZXMgaW4gbWlsbGlzZWNvbmRzLlwiKVxuKVxuXG5jb25zdCBtYWluID0gQ29tbWFuZC5tYWtlKFwibG9vbmV5XCIsIHsgZmlsZSwgdGhlbWUsIHRyYW5zaXRpb24gfSkucGlwZShcbiAgQ29tbWFuZC53aXRoRGVzY3JpcHRpb24oXCJDcmVhdGUgY29kZSBhbmltYXRpb24gdmlkZW9zIGZyb20gTWFya2Rvd24uXCIpLFxuICBDb21tYW5kLndpdGhIYW5kbGVyKCh7IGZpbGUsIHRoZW1lLCB0cmFuc2l0aW9uIH0pID0+XG4gICAgRWZmZWN0LmdlbihmdW5jdGlvbiogKCkge1xuICAgICAgY29uc3QgZnMgPSB5aWVsZCogRmlsZVN5c3RlbS5GaWxlU3lzdGVtXG4gICAgICBjb25zdCBwYXRoID0geWllbGQqIFBhdGguUGF0aFxuXG4gICAgICBjb25zdCBtYXJrZG93biA9IHlpZWxkKiBmcy5yZWFkRmlsZVN0cmluZyhmaWxlKVxuICAgICAgY29uc3QgYmxvY2tzID0geWllbGQqIHBhcnNlTWFya2Rvd25Db2RlQmxvY2tzKG1hcmtkb3duKVxuXG4gICAgICBpZiAoYmxvY2tzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICB5aWVsZCogRWZmZWN0LmZhaWwobmV3IEVycm9yKFwiTm8gZmVuY2VkIGNvZGUgYmxvY2tzIGZvdW5kLlwiKSlcbiAgICAgIH1cblxuICAgICAgaWYgKHRyYW5zaXRpb24gPD0gMCkge1xuICAgICAgICB5aWVsZCogRWZmZWN0LmZhaWwobmV3IEVycm9yKFwiVHJhbnNpdGlvbiBkdXJhdGlvbiBtdXN0IGJlIGdyZWF0ZXIgdGhhbiAwLlwiKSlcbiAgICAgIH1cblxuICAgICAgY29uc3QgcmVzb2x2ZWRUaGVtZSA9IHlpZWxkKiByZXNvbHZlVGhlbWUodGhlbWUpXG4gICAgICBjb25zdCBwYXJzZWRPdXRwdXRQYXRoID0gcGF0aC5wYXJzZShmaWxlKVxuICAgICAgY29uc3Qgb3V0cHV0UGF0aCA9IHBhdGguam9pbihwYXJzZWRPdXRwdXRQYXRoLmRpciwgYCR7cGFyc2VkT3V0cHV0UGF0aC5uYW1lfS5tcDRgKVxuXG4gICAgICB5aWVsZCogQ29uc29sZS5sb2coYFJlbmRlcmluZyAke2Jsb2Nrcy5sZW5ndGh9IGNvZGUgYmxvY2tzLi4uYClcbiAgICAgIHlpZWxkKiByZW5kZXJWaWRlbyhvdXRwdXRQYXRoLCByZXNvbHZlZFRoZW1lLCBibG9ja3MsIHtcbiAgICAgICAgdHJhbnNpdGlvbkR1cmF0aW9uTXM6IHRyYW5zaXRpb24sXG4gICAgICB9KVxuICAgICAgeWllbGQqIENvbnNvbGUubG9nKGBWaWRlbyBjcmVhdGVkIGF0ICR7b3V0cHV0UGF0aH1gKVxuICAgIH0pXG4gIClcbilcblxuZXhwb3J0IGNvbnN0IHByb2dyYW0gPSBDb21tYW5kLnJ1bihtYWluLCB7IG5hbWU6IFwibG9vbmV5XCIsIHZlcnNpb24gfSlcblxucHJvZ3JhbShwcm9jZXNzLmFyZ3YpLnBpcGUoXG4gIEVmZmVjdC50YXBFcnJvckNhdXNlKEVmZmVjdC5sb2dFcnJvciksXG4gIEVmZmVjdC5wcm92aWRlKE5vZGVDb250ZXh0LmxheWVyKSxcbiAgTm9kZVJ1bnRpbWUucnVuTWFpblxuKVxuIiwKICAgICJpbXBvcnQgKiBhcyBPUyBmcm9tIFwibm9kZTpvc1wiXG5pbXBvcnQgeyBjcmVhdGVDYW52YXMsIHR5cGUgU0tSU0NvbnRleHQyRCB9IGZyb20gXCJAbmFwaS1ycy9jYW52YXNcIlxuaW1wb3J0IHsgRWZmZWN0LCBSZWYsIFN0cmVhbSB9IGZyb20gXCJlZmZlY3RcIlxuaW1wb3J0IHtcbiAgRmlsZVBhdGhUYXJnZXQsXG4gIE1wNE91dHB1dEZvcm1hdCxcbiAgT3V0cHV0LFxuICBRVUFMSVRZX0hJR0gsXG4gIFZpZGVvU2FtcGxlLFxuICBWaWRlb1NhbXBsZVNvdXJjZSxcbn0gZnJvbSBcIm1lZGlhYnVubnlcIlxuaW1wb3J0IHR5cGUgeyBDYW52YXNDb250ZXh0IH0gZnJvbSBcIi4vY29udGV4dFwiXG5pbXBvcnQgdHlwZSB7IENvZGVCbG9jaywgUmVuZGVyRnJhbWUsIFNjZW5lIH0gZnJvbSBcIi4vdHlwZXNcIlxuaW1wb3J0IHtcbiAgREVGQVVMVF9CTE9DS19EVVJBVElPTixcbiAgREVGQVVMVF9GUFMsXG4gIERFRkFVTFRfSEVJR0hULFxuICBERUZBVUxUX1RSQU5TSVRJT05fRFVSQVRJT05fTVMsXG4gIERFRkFVTFRfV0lEVEgsXG59IGZyb20gXCIuL2NvbnN0YW50c1wiXG5pbXBvcnQgeyByZW5kZXJGcmFtZSB9IGZyb20gXCIuL3JlbmRlclwiXG5pbXBvcnQgeyBidWlsZFNjZW5lIH0gZnJvbSBcIi4vc2NlbmVcIlxuaW1wb3J0IHsgYnVpbGRUcmFuc2l0aW9uRGlmZiwgYnVpbGRUcmFuc2l0aW9uVG9rZW5zLCBlYXNlSW5PdXRDdWJpYyB9IGZyb20gXCIuL3RyYW5zaXRpb25cIlxuaW1wb3J0IHsgZW5zdXJlV2ViQ29kZWNzIH0gZnJvbSBcIi4vd2ViY29kZWNzXCJcblxuZXhwb3J0IHR5cGUgUmVuZGVyVmlkZW9PcHRpb25zID0ge1xuICBjb25jdXJyZW5jeT86IG51bWJlclxuICB0cmFuc2l0aW9uRHVyYXRpb25Ncz86IG51bWJlclxufVxuXG5jb25zdCByZXNvbHZlQ29uY3VycmVuY3kgPSAoKSA9PiBFZmZlY3Quc3luYygoKSA9PiBNYXRoLm1pbig0LCBPUy5hdmFpbGFibGVQYXJhbGxlbGlzbSgpKSlcblxuY29uc3QgbWFrZU91dHB1dCA9IChvdXRwdXRQYXRoOiBzdHJpbmcpID0+XG4gIEVmZmVjdC5zeW5jKFxuICAgICgpID0+XG4gICAgICBuZXcgT3V0cHV0KHtcbiAgICAgICAgZm9ybWF0OiBuZXcgTXA0T3V0cHV0Rm9ybWF0KCksXG4gICAgICAgIHRhcmdldDogbmV3IEZpbGVQYXRoVGFyZ2V0KG91dHB1dFBhdGgpLFxuICAgICAgfSlcbiAgKVxuXG5jb25zdCBtYWtlVmlkZW9Tb3VyY2UgPSAoKSA9PlxuICBFZmZlY3Quc3luYyhcbiAgICAoKSA9PlxuICAgICAgbmV3IFZpZGVvU2FtcGxlU291cmNlKHtcbiAgICAgICAgYml0cmF0ZTogUVVBTElUWV9ISUdILFxuICAgICAgICBjb2RlYzogXCJhdmNcIixcbiAgICAgICAgb25FbmNvZGVyQ29uZmlnOiAoY29uZmlnKSA9PiB7XG4gICAgICAgICAgY29uc3QgZW5jb2RlckNvbmZpZyA9IGNvbmZpZyBhcyB7IHVzZVdvcmtlclRocmVhZD86IGJvb2xlYW4gfVxuICAgICAgICAgIGVuY29kZXJDb25maWcudXNlV29ya2VyVGhyZWFkID0gZmFsc2VcbiAgICAgICAgfSxcbiAgICAgIH0pXG4gIClcblxuY29uc3QgY29tcHV0ZUZyYW1lQ291bnRzID0gKHRyYW5zaXRpb25EdXJhdGlvbk1zOiBudW1iZXIpID0+IHtcbiAgY29uc3QgZnJhbWVEdXJhdGlvbiA9IDEgLyBERUZBVUxUX0ZQU1xuICBjb25zdCBibG9ja0ZyYW1lcyA9IE1hdGgubWF4KDEsIE1hdGgucm91bmQoREVGQVVMVF9CTE9DS19EVVJBVElPTiAqIERFRkFVTFRfRlBTKSlcbiAgY29uc3QgdHJhbnNpdGlvbkZyYW1lcyA9IE1hdGgubWF4KDEsIE1hdGgucm91bmQoKHRyYW5zaXRpb25EdXJhdGlvbk1zIC8gMTAwMCkgKiBERUZBVUxUX0ZQUykpXG5cbiAgcmV0dXJuIHtcbiAgICBibG9ja0ZyYW1lcyxcbiAgICBmcmFtZUR1cmF0aW9uLFxuICAgIHRyYW5zaXRpb25GcmFtZXMsXG4gIH1cbn1cblxuY29uc3QgcmVuZGVyQW5kV3JpdGVGcmFtZSA9XG4gIChcbiAgICBjb250ZXh0OiBDYW52YXNDb250ZXh0LFxuICAgIG91dHB1dDogT3V0cHV0LFxuICAgIHZpZGVvU291cmNlOiBWaWRlb1NhbXBsZVNvdXJjZSxcbiAgICBmcmFtZUR1cmF0aW9uOiBudW1iZXIsXG4gICAgZnJhbWVJbmRleFJlZjogUmVmLlJlZjxudW1iZXI+XG4gICkgPT5cbiAgKGZyYW1lOiBSZW5kZXJGcmFtZSkgPT5cbiAgICBFZmZlY3QuZ2VuKGZ1bmN0aW9uKiAoKSB7XG4gICAgICBjb25zdCBmcmFtZUluZGV4ID0geWllbGQqIFJlZi5nZXQoZnJhbWVJbmRleFJlZilcbiAgICAgIHJlbmRlckZyYW1lKGNvbnRleHQsIERFRkFVTFRfV0lEVEgsIERFRkFVTFRfSEVJR0hULCBmcmFtZSlcblxuICAgICAgY29uc3QgcmdiYSA9IChjb250ZXh0IGFzIFNLUlNDb250ZXh0MkQpLmNhbnZhcy5kYXRhKClcbiAgICAgIGNvbnN0IHNhbXBsZSA9IG5ldyBWaWRlb1NhbXBsZShyZ2JhLCB7XG4gICAgICAgIGNvZGVkSGVpZ2h0OiBERUZBVUxUX0hFSUdIVCxcbiAgICAgICAgY29kZWRXaWR0aDogREVGQVVMVF9XSURUSCxcbiAgICAgICAgZHVyYXRpb246IGZyYW1lRHVyYXRpb24sXG4gICAgICAgIGZvcm1hdDogXCJSR0JBXCIsXG4gICAgICAgIHRpbWVzdGFtcDogZnJhbWVJbmRleCAqIGZyYW1lRHVyYXRpb24sXG4gICAgICB9KVxuXG4gICAgICB5aWVsZCogRWZmZWN0LnRyeVByb21pc2Uoe1xuICAgICAgICBjYXRjaDogKGVycm9yKSA9PiAoZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yIDogbmV3IEVycm9yKFN0cmluZyhlcnJvcikpKSxcbiAgICAgICAgdHJ5OiAoKSA9PiB2aWRlb1NvdXJjZS5hZGQoc2FtcGxlKSxcbiAgICAgIH0pXG5cbiAgICAgIHNhbXBsZS5jbG9zZSgpXG4gICAgICB5aWVsZCogUmVmLnNldChmcmFtZUluZGV4UmVmLCBmcmFtZUluZGV4ICsgMSlcbiAgICB9KVxuXG5jb25zdCBidWlsZFNjZW5lRnJhbWVzID0gKHNjZW5lOiBTY2VuZSwgYmxvY2tGcmFtZXM6IG51bWJlcikgPT5cbiAgU3RyZWFtLnJhbmdlKDEsIGJsb2NrRnJhbWVzKS5waXBlKFxuICAgIFN0cmVhbS5tYXAoXG4gICAgICAoKSA9PlxuICAgICAgICAoe1xuICAgICAgICAgIGJhY2tncm91bmQ6IHNjZW5lLmJhY2tncm91bmQsXG4gICAgICAgICAga2luZDogXCJzY2VuZVwiLFxuICAgICAgICAgIG9wYWNpdHk6IDEsXG4gICAgICAgICAgcG9zaXRpb25YOiBzY2VuZS5ibG9ja1gsXG4gICAgICAgICAgcG9zaXRpb25ZOiBzY2VuZS5ibG9ja1ksXG4gICAgICAgICAgc2NlbmUsXG4gICAgICAgIH0pIHNhdGlzZmllcyBSZW5kZXJGcmFtZVxuICAgIClcbiAgKVxuXG5jb25zdCBidWlsZFRyYW5zaXRpb25GcmFtZXMgPSAoc2NlbmU6IFNjZW5lLCBuZXh0U2NlbmU6IFNjZW5lLCB0cmFuc2l0aW9uRnJhbWVzOiBudW1iZXIpID0+IHtcbiAgY29uc3QgZGlmZiA9IGJ1aWxkVHJhbnNpdGlvbkRpZmYoc2NlbmUsIG5leHRTY2VuZSlcblxuICByZXR1cm4gU3RyZWFtLnJhbmdlKDEsIHRyYW5zaXRpb25GcmFtZXMpLnBpcGUoXG4gICAgU3RyZWFtLm1hcCgoaW5kZXgpID0+IHtcbiAgICAgIGNvbnN0IHJhd1Byb2dyZXNzID0gaW5kZXggLyB0cmFuc2l0aW9uRnJhbWVzXG4gICAgICBjb25zdCBwcm9ncmVzcyA9IGVhc2VJbk91dEN1YmljKHJhd1Byb2dyZXNzKVxuICAgICAgY29uc3QgYmxlbmRlZEJhY2tncm91bmQgPSBibGVuZENvbG9ycyhzY2VuZS5iYWNrZ3JvdW5kLCBuZXh0U2NlbmUuYmFja2dyb3VuZCwgcHJvZ3Jlc3MpXG4gICAgICBjb25zdCB0b2tlbnMgPSBidWlsZFRyYW5zaXRpb25Ub2tlbnMoZGlmZiwgcHJvZ3Jlc3MpXG5cbiAgICAgIHJldHVybiB7XG4gICAgICAgIGJhY2tncm91bmQ6IGJsZW5kZWRCYWNrZ3JvdW5kLFxuICAgICAgICBraW5kOiBcInRyYW5zaXRpb25cIixcbiAgICAgICAgdG9rZW5zLFxuICAgICAgfSBzYXRpc2ZpZXMgUmVuZGVyRnJhbWVcbiAgICB9KVxuICApXG59XG5cbmNvbnN0IGJ1aWxkRnJhbWVzU3RyZWFtID0gKHNjZW5lczogU2NlbmVbXSwgYmxvY2tGcmFtZXM6IG51bWJlciwgdHJhbnNpdGlvbkZyYW1lczogbnVtYmVyKSA9PlxuICBTdHJlYW0uZnJvbUl0ZXJhYmxlKHNjZW5lcykucGlwZShcbiAgICBTdHJlYW0uemlwV2l0aEluZGV4LFxuICAgIFN0cmVhbS5mbGF0TWFwKChbc2NlbmUsIGluZGV4XSkgPT4ge1xuICAgICAgY29uc3QgbmV4dFNjZW5lID0gc2NlbmVzW2luZGV4ICsgMV1cbiAgICAgIGNvbnN0IGJhc2UgPSBidWlsZFNjZW5lRnJhbWVzKHNjZW5lLCBibG9ja0ZyYW1lcylcbiAgICAgIHJldHVybiBuZXh0U2NlbmVcbiAgICAgICAgPyBTdHJlYW0uY29uY2F0KGJhc2UsIGJ1aWxkVHJhbnNpdGlvbkZyYW1lcyhzY2VuZSwgbmV4dFNjZW5lLCB0cmFuc2l0aW9uRnJhbWVzKSlcbiAgICAgICAgOiBiYXNlXG4gICAgfSlcbiAgKVxuXG5jb25zdCBibGVuZENvbG9ycyA9IChmcm9tOiBzdHJpbmcsIHRvOiBzdHJpbmcsIHByb2dyZXNzOiBudW1iZXIpID0+IHtcbiAgY29uc3QgZnJvbUNvbG9yID0gcGFyc2VIZXhDb2xvcihmcm9tKVxuICBjb25zdCB0b0NvbG9yID0gcGFyc2VIZXhDb2xvcih0bylcblxuICBjb25zdCBibGVuZGVkID0ge1xuICAgIGFscGhhOiBsZXJwKGZyb21Db2xvci5hbHBoYSwgdG9Db2xvci5hbHBoYSwgcHJvZ3Jlc3MpLFxuICAgIGJsdWU6IGxlcnAoZnJvbUNvbG9yLmJsdWUsIHRvQ29sb3IuYmx1ZSwgcHJvZ3Jlc3MpLFxuICAgIGdyZWVuOiBsZXJwKGZyb21Db2xvci5ncmVlbiwgdG9Db2xvci5ncmVlbiwgcHJvZ3Jlc3MpLFxuICAgIHJlZDogbGVycChmcm9tQ29sb3IucmVkLCB0b0NvbG9yLnJlZCwgcHJvZ3Jlc3MpLFxuICB9XG5cbiAgcmV0dXJuIGByZ2JhKCR7TWF0aC5yb3VuZChibGVuZGVkLnJlZCl9LCAke01hdGgucm91bmQoYmxlbmRlZC5ncmVlbil9LCAke01hdGgucm91bmQoXG4gICAgYmxlbmRlZC5ibHVlXG4gICl9LCAke2JsZW5kZWQuYWxwaGEudG9GaXhlZCgzKX0pYFxufVxuXG5jb25zdCBwYXJzZUhleENvbG9yID0gKGNvbG9yOiBzdHJpbmcpID0+IHtcbiAgY29uc3Qgbm9ybWFsaXplZCA9IGNvbG9yLnJlcGxhY2UoXCIjXCIsIFwiXCIpLnRyaW0oKVxuICBpZiAobm9ybWFsaXplZC5sZW5ndGggIT09IDYgJiYgbm9ybWFsaXplZC5sZW5ndGggIT09IDgpIHtcbiAgICByZXR1cm4ge1xuICAgICAgYWxwaGE6IDEsXG4gICAgICBibHVlOiAxMSxcbiAgICAgIGdyZWVuOiAxMSxcbiAgICAgIHJlZDogMTEsXG4gICAgfVxuICB9XG5cbiAgY29uc3QgcmVkID0gTnVtYmVyLnBhcnNlSW50KG5vcm1hbGl6ZWQuc2xpY2UoMCwgMiksIDE2KVxuICBjb25zdCBncmVlbiA9IE51bWJlci5wYXJzZUludChub3JtYWxpemVkLnNsaWNlKDIsIDQpLCAxNilcbiAgY29uc3QgYmx1ZSA9IE51bWJlci5wYXJzZUludChub3JtYWxpemVkLnNsaWNlKDQsIDYpLCAxNilcbiAgY29uc3QgYWxwaGEgPSBub3JtYWxpemVkLmxlbmd0aCA9PT0gOCA/IE51bWJlci5wYXJzZUludChub3JtYWxpemVkLnNsaWNlKDYsIDgpLCAxNikgLyAyNTUgOiAxXG5cbiAgcmV0dXJuIHtcbiAgICBhbHBoYSxcbiAgICBibHVlLFxuICAgIGdyZWVuLFxuICAgIHJlZCxcbiAgfVxufVxuXG5jb25zdCBsZXJwID0gKHN0YXJ0OiBudW1iZXIsIGVuZDogbnVtYmVyLCBwcm9ncmVzczogbnVtYmVyKSA9PiBzdGFydCArIChlbmQgLSBzdGFydCkgKiBwcm9ncmVzc1xuXG5leHBvcnQgY29uc3QgcmVuZGVyVmlkZW8gPSAoXG4gIG91dHB1dFBhdGg6IHN0cmluZyxcbiAgdGhlbWU6IHN0cmluZyxcbiAgY29kZUJsb2NrczogQ29kZUJsb2NrW10sXG4gIG9wdGlvbnM6IFJlbmRlclZpZGVvT3B0aW9ucyA9IHt9XG4pID0+XG4gIEVmZmVjdC5nZW4oZnVuY3Rpb24qICgpIHtcbiAgICB5aWVsZCogZW5zdXJlV2ViQ29kZWNzKClcblxuICAgIGNvbnN0IGNvbmN1cnJlbmN5ID0gb3B0aW9ucy5jb25jdXJyZW5jeSA/PyAoeWllbGQqIHJlc29sdmVDb25jdXJyZW5jeSgpKVxuICAgIGNvbnN0IHRyYW5zaXRpb25EdXJhdGlvbk1zID0gb3B0aW9ucy50cmFuc2l0aW9uRHVyYXRpb25NcyA/PyBERUZBVUxUX1RSQU5TSVRJT05fRFVSQVRJT05fTVNcblxuICAgIGNvbnN0IGNhbnZhcyA9IGNyZWF0ZUNhbnZhcyhERUZBVUxUX1dJRFRILCBERUZBVUxUX0hFSUdIVClcbiAgICBjb25zdCBjb250ZXh0ID0gY2FudmFzLmdldENvbnRleHQoXCIyZFwiKVxuXG4gICAgY29uc3Qgc2NlbmVzID0geWllbGQqIEVmZmVjdC5mb3JFYWNoKFxuICAgICAgY29kZUJsb2NrcyxcbiAgICAgIChjb2RlQmxvY2spID0+IGJ1aWxkU2NlbmUoY29udGV4dCwgY29kZUJsb2NrLCB0aGVtZSBhcyBuZXZlciwgREVGQVVMVF9XSURUSCwgREVGQVVMVF9IRUlHSFQpLFxuICAgICAgeyBjb25jdXJyZW5jeSB9XG4gICAgKVxuXG4gICAgY29uc3QgZnJhbWVDb3VudHMgPSBjb21wdXRlRnJhbWVDb3VudHModHJhbnNpdGlvbkR1cmF0aW9uTXMpXG4gICAgY29uc3QgZnJhbWVJbmRleFJlZiA9IHlpZWxkKiBSZWYubWFrZSgwKVxuXG4gICAgcmV0dXJuIHlpZWxkKiBFZmZlY3Quc2NvcGVkKFxuICAgICAgRWZmZWN0LmdlbihmdW5jdGlvbiogKCkge1xuICAgICAgICBjb25zdCBvdXRwdXQgPSB5aWVsZCogRWZmZWN0LmFjcXVpcmVSZWxlYXNlKG1ha2VPdXRwdXQob3V0cHV0UGF0aCksIChyZXNvdXJjZSkgPT5cbiAgICAgICAgICBFZmZlY3QudHJ5UHJvbWlzZSh7XG4gICAgICAgICAgICBjYXRjaDogKGVycm9yKSA9PiAoZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yIDogbmV3IEVycm9yKFN0cmluZyhlcnJvcikpKSxcbiAgICAgICAgICAgIHRyeTogKCkgPT4gcmVzb3VyY2UuZmluYWxpemUoKSxcbiAgICAgICAgICB9KS5waXBlKEVmZmVjdC5vckRpZSlcbiAgICAgICAgKVxuICAgICAgICBjb25zdCB2aWRlb1NvdXJjZSA9IHlpZWxkKiBFZmZlY3QuYWNxdWlyZVJlbGVhc2UobWFrZVZpZGVvU291cmNlKCksIChyZXNvdXJjZSkgPT5cbiAgICAgICAgICBFZmZlY3Quc3luYygoKSA9PiB7XG4gICAgICAgICAgICByZXNvdXJjZS5jbG9zZSgpXG4gICAgICAgICAgfSlcbiAgICAgICAgKVxuXG4gICAgICAgIHlpZWxkKiBFZmZlY3Quc3luYygoKSA9PiB7XG4gICAgICAgICAgb3V0cHV0LmFkZFZpZGVvVHJhY2sodmlkZW9Tb3VyY2UsIHsgZnJhbWVSYXRlOiBERUZBVUxUX0ZQUyB9KVxuICAgICAgICB9KVxuXG4gICAgICAgIHlpZWxkKiBFZmZlY3QudHJ5UHJvbWlzZSh7XG4gICAgICAgICAgY2F0Y2g6IChlcnJvcikgPT4gKGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvciA6IG5ldyBFcnJvcihTdHJpbmcoZXJyb3IpKSksXG4gICAgICAgICAgdHJ5OiAoKSA9PiBvdXRwdXQuc3RhcnQoKSxcbiAgICAgICAgfSlcblxuICAgICAgICBjb25zdCBmcmFtZVN0cmVhbSA9IGJ1aWxkRnJhbWVzU3RyZWFtKFxuICAgICAgICAgIHNjZW5lcyxcbiAgICAgICAgICBmcmFtZUNvdW50cy5ibG9ja0ZyYW1lcyxcbiAgICAgICAgICBmcmFtZUNvdW50cy50cmFuc2l0aW9uRnJhbWVzXG4gICAgICAgIClcblxuICAgICAgICB5aWVsZCogU3RyZWFtLnJ1bkZvckVhY2goXG4gICAgICAgICAgZnJhbWVTdHJlYW0sXG4gICAgICAgICAgcmVuZGVyQW5kV3JpdGVGcmFtZShcbiAgICAgICAgICAgIGNvbnRleHQsXG4gICAgICAgICAgICBvdXRwdXQsXG4gICAgICAgICAgICB2aWRlb1NvdXJjZSxcbiAgICAgICAgICAgIGZyYW1lQ291bnRzLmZyYW1lRHVyYXRpb24sXG4gICAgICAgICAgICBmcmFtZUluZGV4UmVmXG4gICAgICAgICAgKVxuICAgICAgICApXG5cbiAgICAgICAgcmV0dXJuIG91dHB1dFBhdGhcbiAgICAgIH0pXG4gICAgKVxuICB9KVxuIiwKICAgICJpbXBvcnQgeyBFZmZlY3QgfSBmcm9tIFwiZWZmZWN0XCJcblxuZXhwb3J0IHR5cGUgV2ViQ29kZWNzR2xvYmFscyA9IHtcbiAgQXVkaW9EYXRhPzogdW5rbm93blxuICBBdWRpb0VuY29kZXI/OiB1bmtub3duXG4gIEVuY29kZWRBdWRpb0NodW5rPzogdW5rbm93blxuICBFbmNvZGVkVmlkZW9DaHVuaz86IHVua25vd25cbiAgVmlkZW9FbmNvZGVyPzogdW5rbm93blxuICBWaWRlb0ZyYW1lPzogdW5rbm93blxufVxuXG5leHBvcnQgY29uc3QgZW5zdXJlV2ViQ29kZWNzID0gKCkgPT5cbiAgRWZmZWN0LnRyeVByb21pc2Uoe1xuICAgIGNhdGNoOiAoZXJyb3IpID0+IHtcbiAgICAgIGNvbnN0IG1lc3NhZ2UgPSBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcilcbiAgICAgIGNvbnN0IGlzTWlzc2luZ0xpYnJhcnkgPSBtZXNzYWdlLmluY2x1ZGVzKFwiTGlicmFyeSBub3QgbG9hZGVkXCIpXG4gICAgICBjb25zdCBiYXNlTWVzc2FnZSA9IFwiV2ViQ29kZWNzIG5vdCBhdmFpbGFibGUuXCJcbiAgICAgIGNvbnN0IGRldGFpbE1lc3NhZ2UgPSBpc01pc3NpbmdMaWJyYXJ5XG4gICAgICAgID8gXCJJbnN0YWxsIEZGbXBlZyAoYnJldyBpbnN0YWxsIGZmbXBlZykgYW5kIGVuc3VyZSBsaWJhdmNvZGVjIGlzIGF2YWlsYWJsZS5cIlxuICAgICAgICA6IFwiSW5zdGFsbCBub2RlLXdlYmNvZGVjcyBwbHVzIEZGbXBlZyAoYnJldyBpbnN0YWxsIGZmbXBlZyBwa2ctY29uZmlnKS5cIlxuXG4gICAgICByZXR1cm4gbmV3IEVycm9yKGAke2Jhc2VNZXNzYWdlfSAke2RldGFpbE1lc3NhZ2V9YCwgeyBjYXVzZTogZXJyb3IgfSlcbiAgICB9LFxuICAgIHRyeTogYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgZ2xvYmFsU2NvcGUgPSBnbG9iYWxUaGlzIGFzIHR5cGVvZiBnbG9iYWxUaGlzICYgV2ViQ29kZWNzR2xvYmFsc1xuICAgICAgaWYgKGdsb2JhbFNjb3BlLlZpZGVvRW5jb2RlciAmJiBnbG9iYWxTY29wZS5WaWRlb0ZyYW1lKSB7XG4gICAgICAgIHJldHVyblxuICAgICAgfVxuXG4gICAgICBjb25zdCB3ZWJjb2RlY3MgPSAoYXdhaXQgaW1wb3J0KFwibm9kZS13ZWJjb2RlY3NcIikpIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+XG5cbiAgICAgIGNvbnN0IGFzc2lnbkdsb2JhbCA9IChrZXk6IGtleW9mIFdlYkNvZGVjc0dsb2JhbHMsIHZhbHVlOiB1bmtub3duKSA9PiB7XG4gICAgICAgIGlmIChnbG9iYWxTY29wZVtrZXldKSB7XG4gICAgICAgICAgcmV0dXJuXG4gICAgICAgIH1cblxuICAgICAgICA7KGdsb2JhbFNjb3BlIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KVtrZXldID0gdmFsdWVcbiAgICAgIH1cblxuICAgICAgYXNzaWduR2xvYmFsKFwiVmlkZW9FbmNvZGVyXCIsIHdlYmNvZGVjcy5WaWRlb0VuY29kZXIpXG4gICAgICBhc3NpZ25HbG9iYWwoXCJWaWRlb0ZyYW1lXCIsIHdlYmNvZGVjcy5WaWRlb0ZyYW1lKVxuICAgICAgYXNzaWduR2xvYmFsKFwiRW5jb2RlZFZpZGVvQ2h1bmtcIiwgd2ViY29kZWNzLkVuY29kZWRWaWRlb0NodW5rKVxuICAgICAgYXNzaWduR2xvYmFsKFwiQXVkaW9FbmNvZGVyXCIsIHdlYmNvZGVjcy5BdWRpb0VuY29kZXIpXG4gICAgICBhc3NpZ25HbG9iYWwoXCJFbmNvZGVkQXVkaW9DaHVua1wiLCB3ZWJjb2RlY3MuRW5jb2RlZEF1ZGlvQ2h1bmspXG4gICAgICBhc3NpZ25HbG9iYWwoXCJBdWRpb0RhdGFcIiwgd2ViY29kZWNzLkF1ZGlvRGF0YSlcbiAgICB9LFxuICB9KVxuIgogIF0sCiAgIm1hcHBpbmdzIjogIjs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBO0FBQ0E7QUFDQTtBQUNBLDRCQUFrQjs7O0FDSGxCO0FBQ0E7QUFDQSxtQkFBUztBQUNUO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7OztBQ0hBO0FBV08sSUFBTSxrQkFBa0IsTUFDN0IsT0FBTyxXQUFXO0FBQUEsRUFDaEIsT0FBTyxDQUFDLFVBQVU7QUFBQSxJQUNoQixNQUFNLFVBQVUsaUJBQWlCLFFBQVEsTUFBTSxVQUFVLE9BQU8sS0FBSztBQUFBLElBQ3JFLE1BQU0sbUJBQW1CLFFBQVEsU0FBUyxvQkFBb0I7QUFBQSxJQUM5RCxNQUFNLGNBQWM7QUFBQSxJQUNwQixNQUFNLGdCQUFnQixtQkFDbEIsNkVBQ0E7QUFBQSxJQUVKLE9BQU8sSUFBSSxNQUFNLEdBQUcsZUFBZSxpQkFBaUIsRUFBRSxPQUFPLE1BQU0sQ0FBQztBQUFBO0FBQUEsRUFFdEUsS0FBSyxZQUFZO0FBQUEsSUFDZixNQUFNLGNBQWM7QUFBQSxJQUNwQixJQUFJLFlBQVksZ0JBQWdCLFlBQVksWUFBWTtBQUFBLE1BQ3REO0FBQUEsSUFDRjtBQUFBLElBRUEsTUFBTSxZQUFhLE1BQWE7QUFBQSxJQUVoQyxNQUFNLGVBQWUsQ0FBQyxLQUE2QixVQUFtQjtBQUFBLE1BQ3BFLElBQUksWUFBWSxNQUFNO0FBQUEsUUFDcEI7QUFBQSxNQUNGO0FBQUEsTUFFRSxZQUF3QyxPQUFPO0FBQUE7QUFBQSxJQUduRCxhQUFhLGdCQUFnQixV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LENBQUM7QUFDdEQsSUFBTSxRQUFRLFFBQVEsS0FBSyxPQUFPLEVBQUUsS0FDbEMsUUFBUSxVQUFVLEdBQUcsR0FDckIsUUFBUSxZQUFZLGFBQWEsR0FDakMsUUFBUSxnQkFBZ0Isc0NBQXNDLENBQ2hFO0FBQ0EsSUFBTSxhQUFhLFFBQVEsUUFBUSxZQUFZLEVBQUUsS0FDL0MsUUFBUSxVQUFVLElBQUksR0FDdEIsUUFBUSxZQUFZLDhCQUE4QixHQUNsRCxRQUFRLGdCQUFnQixxREFBcUQsQ0FDL0U7QUFFQSxJQUFNLE9BQU8sUUFBUSxLQUFLLFVBQVUsRUFBRSxNQUFNLE9BQU8sV0FBVyxDQUFDLEVBQUUsS0FDL0QsUUFBUSxnQkFBZ0IsNkNBQTZDLEdBQ3JFLFFBQVEsWUFBWSxHQUFHLGFBQU0sZUFBTyw4QkFDbEMsUUFBTyxJQUFJLFVBQVUsR0FBRztBQUFBLEVBQ3RCLE1BQU0sS0FBSyxPQUFPLFdBQVc7QUFBQSxFQUM3QixNQUFNLE9BQU8sT0FBTyxLQUFLO0FBQUEsRUFFekIsTUFBTSxXQUFXLE9BQU8sR0FBRyxlQUFlLEtBQUk7QUFBQSxFQUM5QyxNQUFNLFNBQVMsT0FBTyx3QkFBd0IsUUFBUTtBQUFBLEVBRXRELElBQUksT0FBTyxXQUFXLEdBQUc7QUFBQSxJQUN2QixPQUFPLFFBQU8sS0FBSyxJQUFJLE1BQU0sOEJBQThCLENBQUM7QUFBQSxFQUM5RDtBQUFBLEVBRUEsSUFBSSxlQUFjLEdBQUc7QUFBQSxJQUNuQixPQUFPLFFBQU8sS0FBSyxJQUFJLE1BQU0sNkNBQTZDLENBQUM7QUFBQSxFQUM3RTtBQUFBLEVBRUEsTUFBTSxnQkFBZ0IsT0FBTyxhQUFhLE1BQUs7QUFBQSxFQUMvQyxNQUFNLG1CQUFtQixLQUFLLE1BQU0sS0FBSTtBQUFBLEVBQ3hDLE1BQU0sYUFBYSxLQUFLLEtBQUssaUJBQWlCLEtBQUssR0FBRyxpQkFBaUIsVUFBVTtBQUFBLEVBRWpGLE9BQU8sUUFBUSxJQUFJLGFBQWEsT0FBTyx1QkFBdUI7QUFBQSxFQUM5RCxPQUFPLFlBQVksWUFBWSxlQUFlLFFBQVE7QUFBQSxJQUNwRCxzQkFBc0I7QUFBQSxFQUN4QixDQUFDO0FBQUEsRUFDRCxPQUFPLFFBQVEsSUFBSSxvQkFBb0IsWUFBWTtBQUFBLENBQ3BELENBQ0gsQ0FDRjtBQUVPLElBQU0sVUFBVSxRQUFRLElBQUksTUFBTSxFQUFFLE1BQU0sVUFBVSxRQUFRLENBQUM7QUFFcEUsUUFBUSxRQUFRLElBQUksRUFBRSxLQUNwQixRQUFPLGNBQWMsUUFBTyxRQUFRLEdBQ3BDLFFBQU8sUUFBUSxZQUFZLEtBQUssR0FDaEMsWUFBWSxPQUNkOyIsCiAgImRlYnVnSWQiOiAiMzI3RDE3NzFGRUZBNDBDRDY0NzU2RTIxNjQ3NTZFMjEiLAogICJuYW1lcyI6IFtdCn0=
@@ -0,0 +1,82 @@
1
+ type CanvasMeasure = {
2
+ font: string;
3
+ measureText: (text: string) => {
4
+ width: number;
5
+ };
6
+ };
7
+ type CanvasText = {
8
+ fillStyle: unknown;
9
+ font: string;
10
+ globalAlpha: number;
11
+ lineWidth: number;
12
+ strokeStyle: unknown;
13
+ textAlign: string;
14
+ textBaseline: string;
15
+ beginPath: () => void;
16
+ fillRect: (x: number, y: number, width: number, height: number) => void;
17
+ fillText: (text: string, x: number, y: number) => void;
18
+ getImageData: (x: number, y: number, width: number, height: number) => {
19
+ data: Uint8ClampedArray;
20
+ };
21
+ getTransform: () => unknown;
22
+ lineTo: (x: number, y: number) => void;
23
+ moveTo: (x: number, y: number) => void;
24
+ setTransform: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
25
+ setTransformMatrix?: (transform: unknown) => void;
26
+ stroke: () => void;
27
+ };
28
+ type CanvasContext = CanvasMeasure & CanvasText & {
29
+ canvas?: unknown;
30
+ };
31
+ type BrowserFormat = "mp4" | "webm" | "auto";
32
+ type CanvasLike = {
33
+ getContext: (type: "2d") => CanvasContext | null;
34
+ height: number;
35
+ width: number;
36
+ };
37
+ type CanvasFactory = (height: number, width: number) => CanvasLike;
38
+ type BrowserOutput = {
39
+ data: Uint8Array;
40
+ extension: "mp4" | "webm";
41
+ mimeType: string;
42
+ };
43
+ type RenderVideoBrowserOptions = {
44
+ canvas?: CanvasLike;
45
+ concurrency?: number;
46
+ createCanvas?: CanvasFactory;
47
+ format?: BrowserFormat;
48
+ height?: number;
49
+ transitionDurationMs?: number;
50
+ width?: number;
51
+ };
52
+ declare const renderVideoBrowser: unknown;
53
+ declare const parseMarkdownCodeBlocks: unknown;
54
+ import { Effect } from "effect";
55
+ type RenderOptions = RenderVideoBrowserOptions & {
56
+ markdown: string;
57
+ theme?: string;
58
+ };
59
+ type RenderResult = ReturnType<typeof renderVideoBrowser> extends Effect.Effect<infer A, unknown> ? A : never;
60
+ declare const render: unknown;
61
+ type CodeBlock = {
62
+ code: string;
63
+ language: string;
64
+ };
65
+ type LayoutToken = {
66
+ color: string;
67
+ content: string;
68
+ fontStyle: number;
69
+ width: number;
70
+ x: number;
71
+ y: number;
72
+ };
73
+ type TransitionDiff = {
74
+ added: LayoutToken[];
75
+ matched: Array<{
76
+ from: LayoutToken;
77
+ to: LayoutToken;
78
+ }>;
79
+ removed: LayoutToken[];
80
+ };
81
+ declare const diffLayoutTokens: (fromTokens: LayoutToken[], toTokens: LayoutToken[]) => {};
82
+ export { render, parseMarkdownCodeBlocks, diffLayoutTokens, TransitionDiff, RenderVideoBrowserOptions, RenderResult, RenderOptions, LayoutToken, CodeBlock, CanvasLike, CanvasFactory, BrowserOutput, BrowserFormat };