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 +21 -0
- package/README.md +9 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +233 -0
- package/dist/index.d.ts +82 -0
- package/dist/index.js +237 -0
- package/dist/shared/chunk-ks7faw1s.js +1782 -0
- package/package.json +69 -0
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
package/dist/cli.d.ts
ADDED
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=
|
package/dist/index.d.ts
ADDED
|
@@ -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 };
|