@martini-film/cli 0.4.0 → 0.4.2
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/README.md +15 -11
- package/dist/api.js +15 -7
- package/dist/api.js.map +1 -1
- package/dist/approve.js +14 -0
- package/dist/approve.js.map +1 -1
- package/dist/cli.js +78 -12
- package/dist/cli.js.map +1 -1
- package/dist/commands/assets.js +98 -60
- package/dist/commands/assets.js.map +1 -1
- package/dist/commands/call.js +56 -24
- package/dist/commands/call.js.map +1 -1
- package/dist/commands/captions.js +111 -0
- package/dist/commands/captions.js.map +1 -0
- package/dist/commands/context.js +3 -7
- package/dist/commands/context.js.map +1 -1
- package/dist/commands/files.js +19 -4
- package/dist/commands/files.js.map +1 -1
- package/dist/commands/graphics.js +1592 -0
- package/dist/commands/graphics.js.map +1 -0
- package/dist/commands/guide.js +12 -8
- package/dist/commands/guide.js.map +1 -1
- package/dist/commands/init.js +24 -7
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/login.js +34 -10
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/tools.js +27 -4
- package/dist/commands/tools.js.map +1 -1
- package/dist/commands/use.js +6 -1
- package/dist/commands/use.js.map +1 -1
- package/dist/config.js +6 -1
- package/dist/config.js.map +1 -1
- package/dist/desktop.js +49 -0
- package/dist/desktop.js.map +1 -0
- package/dist/generated/guide.json +8 -5
- package/dist/generated/manifest.json +14650 -9376
- package/dist/graphics/captionsState.js +24 -0
- package/dist/graphics/captionsState.js.map +1 -0
- package/dist/graphics/compress.js +103 -0
- package/dist/graphics/compress.js.map +1 -0
- package/dist/graphics/limits.js +67 -0
- package/dist/graphics/limits.js.map +1 -0
- package/dist/graphics/manifest.js +273 -0
- package/dist/graphics/manifest.js.map +1 -0
- package/dist/graphics/project.js +626 -0
- package/dist/graphics/project.js.map +1 -0
- package/dist/graphics/tar.js +152 -0
- package/dist/graphics/tar.js.map +1 -0
- package/dist/help.js +24 -7
- package/dist/help.js.map +1 -1
- package/dist/manifest.js +2 -1
- package/dist/manifest.js.map +1 -1
- package/dist/output.js +86 -9
- package/dist/output.js.map +1 -1
- package/dist/schema.js +184 -4
- package/dist/schema.js.map +1 -1
- package/dist/wait.js +2 -1
- package/dist/wait.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { ArgumentError } from '../schema.js';
|
|
4
|
+
export const CAPTIONS_STATE_FILE = '.martini/captions.json';
|
|
5
|
+
export function readCaptionsState(dir, scope) {
|
|
6
|
+
const path = join(dir, CAPTIONS_STATE_FILE);
|
|
7
|
+
if (!existsSync(path))
|
|
8
|
+
return undefined;
|
|
9
|
+
const state = JSON.parse(readFileSync(path, 'utf8'));
|
|
10
|
+
if (!state?.projectId || !state.sequenceId)
|
|
11
|
+
throw new ArgumentError('INVALID_CAPTIONS_STATE: Rebuild captions (martini captions build) to restore the project and sequence.');
|
|
12
|
+
if (state.projectId !== scope.projectId) {
|
|
13
|
+
scope.warn(`Captions in ${dir} were built for project ${state.projectId}; ignoring .martini/captions.json. Rebuild with martini captions build.`);
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
if (typeof state.revisionToken !== 'string' || !state.revisionToken)
|
|
17
|
+
throw new ArgumentError('INVALID_CAPTIONS_STATE: Rebuild captions to restore the timeline revision.');
|
|
18
|
+
return state;
|
|
19
|
+
}
|
|
20
|
+
export function writeCaptionsState(dir, state) {
|
|
21
|
+
mkdirSync(join(dir, '.martini'), { recursive: true });
|
|
22
|
+
writeFileSync(join(dir, CAPTIONS_STATE_FILE), JSON.stringify(state, null, 2) + '\n');
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=captionsState.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"captionsState.js","sourceRoot":"","sources":["../../src/graphics/captionsState.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC5E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAE5C,MAAM,CAAC,MAAM,mBAAmB,GAAG,wBAAwB,CAAA;AAY3D,MAAM,UAAU,iBAAiB,CAC/B,GAAW,EACX,KAA0D;IAE1D,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,mBAAmB,CAAC,CAAA;IAC3C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAA;IACvC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAkB,CAAA;IACrE,IAAI,CAAC,KAAK,EAAE,SAAS,IAAI,CAAC,KAAK,CAAC,UAAU;QACxC,MAAM,IAAI,aAAa,CACrB,wGAAwG,CACzG,CAAA;IACH,IAAI,KAAK,CAAC,SAAS,KAAK,KAAK,CAAC,SAAS,EAAE,CAAC;QACxC,KAAK,CAAC,IAAI,CACR,eAAe,GAAG,2BAA2B,KAAK,CAAC,SAAS,yEAAyE,CACtI,CAAA;QACD,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,IAAI,OAAO,KAAK,CAAC,aAAa,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,aAAa;QACjE,MAAM,IAAI,aAAa,CAAC,4EAA4E,CAAC,CAAA;IACvG,OAAO,KAAK,CAAA;AACd,CAAC;AACD,MAAM,UAAU,kBAAkB,CAAC,GAAW,EAAE,KAAoB;IAClE,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IACrD,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,mBAAmB,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAA;AACtF,CAAC"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { mkdtempSync, statSync } from 'node:fs';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { basename, extname, join } from 'node:path';
|
|
5
|
+
import { formatMB, mediaTypeOf, TIMELINE_FPS } from './limits.js';
|
|
6
|
+
const defaultRun = (command, args) => spawnSync(command, [...args], { encoding: 'utf8', maxBuffer: 16 * 1024 * 1024 });
|
|
7
|
+
const AUDIO_KBPS = 160;
|
|
8
|
+
const HEADROOM = 0.94;
|
|
9
|
+
const MIN_VIDEO_KBPS = 150;
|
|
10
|
+
export class CompressError extends Error {
|
|
11
|
+
code;
|
|
12
|
+
fix;
|
|
13
|
+
path;
|
|
14
|
+
constructor(code, message, fix, path) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.name = 'CompressError';
|
|
17
|
+
this.code = code;
|
|
18
|
+
this.fix = fix;
|
|
19
|
+
this.path = path;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function manualCommand(path, videoKbps, hasAudio = true) {
|
|
23
|
+
return `ffmpeg -i ${path} -r ${TIMELINE_FPS} -c:v libx264 -b:v ${videoKbps}k -g ${TIMELINE_FPS} -pix_fmt yuv420p -movflags +faststart ${hasAudio ? `-c:a aac -b:a ${AUDIO_KBPS}k` : '-an'} <out>${extname(path)}`;
|
|
24
|
+
}
|
|
25
|
+
function probe(run, path) {
|
|
26
|
+
const result = run('ffprobe', [
|
|
27
|
+
'-v',
|
|
28
|
+
'error',
|
|
29
|
+
'-show_entries',
|
|
30
|
+
'format=duration:stream=codec_type',
|
|
31
|
+
'-of',
|
|
32
|
+
'json',
|
|
33
|
+
path,
|
|
34
|
+
]);
|
|
35
|
+
if (result.error || result.status !== 0) {
|
|
36
|
+
const missing = result.error?.code === 'ENOENT';
|
|
37
|
+
throw new CompressError(missing ? 'FFMPEG_MISSING' : 'PROBE_FAILED', missing ? '--compress needs ffmpeg and ffprobe on PATH.' : `ffprobe could not read ${path}.`, missing
|
|
38
|
+
? `Install ffmpeg (brew install ffmpeg, apt install ffmpeg), or transcode by hand: ${manualCommand(path, '<kbps>')} and reference that file.`
|
|
39
|
+
: 'Check that the file is a playable video.', path);
|
|
40
|
+
}
|
|
41
|
+
let parsed;
|
|
42
|
+
try {
|
|
43
|
+
parsed = JSON.parse(result.stdout);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
parsed = {};
|
|
47
|
+
}
|
|
48
|
+
const durationSeconds = Number(parsed.format?.duration);
|
|
49
|
+
if (!Number.isFinite(durationSeconds) || durationSeconds <= 0)
|
|
50
|
+
throw new CompressError('PROBE_FAILED', `ffprobe found no duration for ${path}.`, 'Check that the file is a playable video.', path);
|
|
51
|
+
return { durationSeconds, hasAudio: (parsed.streams ?? []).some(stream => stream.codec_type === 'audio') };
|
|
52
|
+
}
|
|
53
|
+
export function compressMedia(path, targetBytes, run = defaultRun, label = path) {
|
|
54
|
+
const type = mediaTypeOf(label);
|
|
55
|
+
if (type?.kind === 'audio') {
|
|
56
|
+
const m4a = label.replace(/\.[^./]+$/, '.m4a');
|
|
57
|
+
throw new CompressError('AUDIO_COMPRESS_UNSUPPORTED', `--compress transcodes video only; ${label} is audio.`, `Convert it and reference the new path: ffmpeg -i ${label} -c:a aac -b:a 192k ${m4a} — then point the composition at ${m4a} and delete or exclude ${label}.`, label);
|
|
58
|
+
}
|
|
59
|
+
if (!/\.(mp4|mov)$/i.test(label))
|
|
60
|
+
throw new CompressError('COMPRESS_UNSUPPORTED', `--compress handles .mp4 and .mov clips; ${label} is neither.`, 'Downscale or re-export it yourself.', label);
|
|
61
|
+
const { durationSeconds, hasAudio } = probe(run, path);
|
|
62
|
+
const totalKbps = (targetBytes * 8 * HEADROOM) / durationSeconds / 1000;
|
|
63
|
+
let videoKbps = Math.floor(totalKbps - (hasAudio ? AUDIO_KBPS : 0));
|
|
64
|
+
if (videoKbps < MIN_VIDEO_KBPS)
|
|
65
|
+
throw new CompressError('COMPRESS_TARGET_TOO_SMALL', `${label} runs ${durationSeconds.toFixed(1)} s; fitting it in ${formatMB(targetBytes)} leaves ${Math.max(0, videoKbps)} kbps of video, too little to watch.`, 'Shorten the clip, lower its resolution, or free room by making other media smaller.', label);
|
|
66
|
+
const dir = mkdtempSync(join(tmpdir(), 'martini-compress-'));
|
|
67
|
+
const output = join(dir, basename(label));
|
|
68
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
69
|
+
const result = run('ffmpeg', [
|
|
70
|
+
'-y',
|
|
71
|
+
'-v',
|
|
72
|
+
'error',
|
|
73
|
+
'-i',
|
|
74
|
+
path,
|
|
75
|
+
'-r',
|
|
76
|
+
String(TIMELINE_FPS),
|
|
77
|
+
'-c:v',
|
|
78
|
+
'libx264',
|
|
79
|
+
'-b:v',
|
|
80
|
+
`${videoKbps}k`,
|
|
81
|
+
'-maxrate',
|
|
82
|
+
`${videoKbps}k`,
|
|
83
|
+
'-bufsize',
|
|
84
|
+
`${videoKbps * 2}k`,
|
|
85
|
+
'-g',
|
|
86
|
+
String(TIMELINE_FPS),
|
|
87
|
+
'-pix_fmt',
|
|
88
|
+
'yuv420p',
|
|
89
|
+
'-movflags',
|
|
90
|
+
'+faststart',
|
|
91
|
+
...(hasAudio ? ['-c:a', 'aac', '-b:a', `${AUDIO_KBPS}k`] : ['-an']),
|
|
92
|
+
output,
|
|
93
|
+
]);
|
|
94
|
+
if (result.error || result.status !== 0)
|
|
95
|
+
throw new CompressError(result.error?.code === 'ENOENT' ? 'FFMPEG_MISSING' : 'COMPRESS_FAILED', `ffmpeg could not transcode ${label}.`, `Run it by hand to see why: ${manualCommand(label, videoKbps, hasAudio)}`, label);
|
|
96
|
+
const bytes = statSync(output).size;
|
|
97
|
+
if (bytes <= targetBytes)
|
|
98
|
+
return { output, bytes, videoKbps, durationSeconds };
|
|
99
|
+
videoKbps = Math.floor(videoKbps * 0.8);
|
|
100
|
+
}
|
|
101
|
+
throw new CompressError('COMPRESS_OVER_TARGET', `${label} is still over ${formatMB(targetBytes)} after two passes.`, 'Lower its resolution or length, then push again.', label);
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=compress.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compress.js","sourceRoot":"","sources":["../../src/graphics/compress.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
const MiB = 1024 * 1024;
|
|
2
|
+
export const MAX_BUNDLE_BYTES = 16 * MiB;
|
|
3
|
+
export const MAX_BUNDLE_FILE_BYTES = 12 * MiB;
|
|
4
|
+
export const MAX_PROJECT_FILES = 200;
|
|
5
|
+
export const MAX_ASSET_REFS = 50;
|
|
6
|
+
export const MAX_TEXT_FILE_BYTES = 2 * MiB;
|
|
7
|
+
export const MIN_DURATION_SECONDS = 1;
|
|
8
|
+
export const MAX_DURATION_SECONDS = 90;
|
|
9
|
+
export const ARTIFACT_MIN_DURATION_SECONDS = 0.5;
|
|
10
|
+
export const ARTIFACT_MAX_DURATION_SECONDS = 90;
|
|
11
|
+
export const MIN_DIMENSION = 16;
|
|
12
|
+
export const MAX_DIMENSION = 4096;
|
|
13
|
+
export const HYPERFRAMES_PATH_SEGMENT = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
14
|
+
export const MAX_PATH_LENGTH = 200;
|
|
15
|
+
export function isSafeHyperframesPath(path) {
|
|
16
|
+
if (!path || path.length > MAX_PATH_LENGTH)
|
|
17
|
+
return false;
|
|
18
|
+
const segments = path.split('/');
|
|
19
|
+
return segments.every((segment, index) => (index === 0 && segment === '_vendor' && segments.length > 1) || HYPERFRAMES_PATH_SEGMENT.test(segment));
|
|
20
|
+
}
|
|
21
|
+
export const TIMELINE_FPS = 24;
|
|
22
|
+
export const SERVER_UPLOAD_CAP = { image: 25 * MiB, audio: 50 * MiB, video: 200 * MiB };
|
|
23
|
+
export const PRODUCT_VIDEO_CAP = 100 * MiB;
|
|
24
|
+
export const UPLOAD_CAP = {
|
|
25
|
+
image: SERVER_UPLOAD_CAP.image,
|
|
26
|
+
audio: SERVER_UPLOAD_CAP.audio,
|
|
27
|
+
video: Math.min(PRODUCT_VIDEO_CAP, SERVER_UPLOAD_CAP.video),
|
|
28
|
+
};
|
|
29
|
+
export const TOOL_BODY_LIMIT = 2 * MiB;
|
|
30
|
+
export const INLINE_BODY_MAX = Math.floor(1.9 * MiB);
|
|
31
|
+
export const RECIPE_MAX = 256 * MiB;
|
|
32
|
+
export const MAX_MEDIA_BYTES = 256 * MiB;
|
|
33
|
+
export const REFERENCED_MEDIA_RIDES_IN_BUNDLE = false;
|
|
34
|
+
export const MEDIA_TYPES = {
|
|
35
|
+
png: { kind: 'image', contentType: 'image/png' },
|
|
36
|
+
jpg: { kind: 'image', contentType: 'image/jpeg' },
|
|
37
|
+
jpeg: { kind: 'image', contentType: 'image/jpeg' },
|
|
38
|
+
webp: { kind: 'image', contentType: 'image/webp' },
|
|
39
|
+
mp4: { kind: 'video', contentType: 'video/mp4' },
|
|
40
|
+
mov: { kind: 'video', contentType: 'video/quicktime' },
|
|
41
|
+
mp3: { kind: 'audio', contentType: 'audio/mpeg' },
|
|
42
|
+
wav: { kind: 'audio', contentType: 'audio/wav' },
|
|
43
|
+
m4a: { kind: 'audio', contentType: 'audio/mp4' },
|
|
44
|
+
ogg: { kind: 'audio', contentType: 'audio/ogg' },
|
|
45
|
+
};
|
|
46
|
+
export const PROJECT_TEXT_EXTENSIONS = new Set(['html', 'css', 'js', 'mjs', 'json', 'svg']);
|
|
47
|
+
export const PROJECT_FONT_EXTENSIONS = new Set(['woff', 'woff2', 'ttf', 'otf']);
|
|
48
|
+
export function encodedBundleBytes(files) {
|
|
49
|
+
let total = 31;
|
|
50
|
+
for (const [index, file] of files.entries()) {
|
|
51
|
+
total += Buffer.byteLength(JSON.stringify(file.path)) + 3 + Math.ceil(file.bytes / 3) * 4 + (index > 0 ? 1 : 0);
|
|
52
|
+
}
|
|
53
|
+
return total;
|
|
54
|
+
}
|
|
55
|
+
export function extensionOf(path) {
|
|
56
|
+
const base = path.slice(path.lastIndexOf('/') + 1);
|
|
57
|
+
const dot = base.lastIndexOf('.');
|
|
58
|
+
return dot <= 0 ? '' : base.slice(dot + 1).toLowerCase();
|
|
59
|
+
}
|
|
60
|
+
export function mediaTypeOf(path) {
|
|
61
|
+
const ext = extensionOf(path);
|
|
62
|
+
return Object.hasOwn(MEDIA_TYPES, ext) ? MEDIA_TYPES[ext] : undefined;
|
|
63
|
+
}
|
|
64
|
+
export function formatMB(bytes) {
|
|
65
|
+
return `${(bytes / MiB).toFixed(1)} MB`;
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=limits.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"limits.js","sourceRoot":"","sources":["../../src/graphics/limits.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
export const GRAPHIC_MANIFEST_FILE = 'martini.graphic.json';
|
|
5
|
+
export const GRAPHIC_STATE_FILE = join('.martini', 'graphic.json');
|
|
6
|
+
export const GRAPHIC_REVIEW_NOTES_FILE = join('.martini', 'review-notes.md');
|
|
7
|
+
export const DOORS = ['hyperframes', 'artifact'];
|
|
8
|
+
export function issue(code, message, fix, path, severity = 'error') {
|
|
9
|
+
return { severity, code, ...(path !== undefined ? { path } : {}), message, fix };
|
|
10
|
+
}
|
|
11
|
+
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
12
|
+
const SHA256 = /^[a-f0-9]{64}$/;
|
|
13
|
+
const KNOWN_TOP = new Set(['version', 'door', 'name', 'description', 'backgroundMode', 'artifact', 'exclude', 'media']);
|
|
14
|
+
const KNOWN_MEDIA = new Set(['path', 'assetId', 'upload', 'recipe']);
|
|
15
|
+
const KNOWN_RECIPE = new Set(['dir', 'command', 'output', 'entry', 'tool', 'fps', 'notes', 'exclude', 'archive']);
|
|
16
|
+
function isRecord(value) {
|
|
17
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
18
|
+
}
|
|
19
|
+
function relativePathProblem(path) {
|
|
20
|
+
if (!path)
|
|
21
|
+
return 'is empty';
|
|
22
|
+
if (path.startsWith('/') || /^[A-Za-z]:/.test(path))
|
|
23
|
+
return 'must be relative to the project';
|
|
24
|
+
if (path.includes('\\'))
|
|
25
|
+
return 'must use forward slashes';
|
|
26
|
+
if (path.split('/').some(segment => segment === '..' || segment === '.' || segment === ''))
|
|
27
|
+
return 'must not contain empty, . or .. segments';
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
function stringList(value) {
|
|
31
|
+
return Array.isArray(value) && value.every(item => typeof item === 'string' && item.length > 0);
|
|
32
|
+
}
|
|
33
|
+
export function parseGraphicManifest(text) {
|
|
34
|
+
const file = GRAPHIC_MANIFEST_FILE;
|
|
35
|
+
const errors = [];
|
|
36
|
+
const warnings = [];
|
|
37
|
+
let raw;
|
|
38
|
+
try {
|
|
39
|
+
raw = JSON.parse(text);
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
return {
|
|
43
|
+
ok: false,
|
|
44
|
+
errors: [
|
|
45
|
+
issue('MANIFEST_INVALID_JSON', `${file} is not valid JSON (${error instanceof Error ? error.message : 'parse error'}).`, 'Fix the JSON syntax.', file),
|
|
46
|
+
],
|
|
47
|
+
warnings,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
if (!isRecord(raw)) {
|
|
51
|
+
return {
|
|
52
|
+
ok: false,
|
|
53
|
+
errors: [
|
|
54
|
+
issue('MANIFEST_INVALID', `${file} must be a JSON object.`, 'Write { "version": 1, "media": [] }.', file),
|
|
55
|
+
],
|
|
56
|
+
warnings,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
const bad = (field, fix) => errors.push(issue('MANIFEST_INVALID', `${file}: ${field} is invalid.`, fix, file));
|
|
60
|
+
for (const key of Object.keys(raw))
|
|
61
|
+
if (!KNOWN_TOP.has(key))
|
|
62
|
+
warnings.push(issue('MANIFEST_UNKNOWN_FIELD', `${file}: unknown field "${key}" is ignored.`, `Remove "${key}".`, file, 'warning'));
|
|
63
|
+
if (raw.version !== 1)
|
|
64
|
+
bad('version', 'Set "version": 1.');
|
|
65
|
+
if (raw.door !== undefined && !DOORS.includes(raw.door))
|
|
66
|
+
bad('door', 'Set "door" to "hyperframes" or "artifact", or remove it to detect.');
|
|
67
|
+
if (raw.name !== undefined && (typeof raw.name !== 'string' || !raw.name.trim() || raw.name.length > 120))
|
|
68
|
+
bad('name', 'Set "name" to 1–120 characters.');
|
|
69
|
+
if (raw.description !== undefined && (typeof raw.description !== 'string' || raw.description.length > 2000))
|
|
70
|
+
bad('description', 'Set "description" to at most 2000 characters.');
|
|
71
|
+
if (raw.backgroundMode !== undefined && raw.backgroundMode !== 'opaque' && raw.backgroundMode !== 'transparent')
|
|
72
|
+
bad('backgroundMode', 'Set "backgroundMode" to "opaque" or "transparent".');
|
|
73
|
+
if (raw.exclude !== undefined && !stringList(raw.exclude))
|
|
74
|
+
bad('exclude', 'Set "exclude" to an array of glob strings.');
|
|
75
|
+
if (raw.artifact !== undefined) {
|
|
76
|
+
const artifact = raw.artifact;
|
|
77
|
+
if (!isRecord(artifact))
|
|
78
|
+
bad('artifact', 'Set "artifact" to { "durationSeconds": <seconds> }.');
|
|
79
|
+
else {
|
|
80
|
+
if (artifact.durationSeconds !== undefined &&
|
|
81
|
+
(typeof artifact.durationSeconds !== 'number' || !Number.isFinite(artifact.durationSeconds)))
|
|
82
|
+
bad('artifact.durationSeconds', 'Set it to a number of seconds.');
|
|
83
|
+
if (artifact.autoStart !== undefined && typeof artifact.autoStart !== 'boolean')
|
|
84
|
+
bad('artifact.autoStart', 'Set it to true or false.');
|
|
85
|
+
for (const key of ['width', 'height'])
|
|
86
|
+
if (artifact[key] !== undefined && !Number.isInteger(artifact[key]))
|
|
87
|
+
bad(`artifact.${key}`, 'Set it to a whole number of pixels.');
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
const media = [];
|
|
91
|
+
if (raw.media !== undefined && !Array.isArray(raw.media))
|
|
92
|
+
bad('media', 'Set "media" to an array.');
|
|
93
|
+
const seen = new Set();
|
|
94
|
+
for (const [index, item] of (Array.isArray(raw.media) ? raw.media : []).entries()) {
|
|
95
|
+
const at = `media[${index}]`;
|
|
96
|
+
if (!isRecord(item) || typeof item.path !== 'string') {
|
|
97
|
+
bad(at, 'Give each media entry a "path" string.');
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
const problem = relativePathProblem(item.path);
|
|
101
|
+
if (problem)
|
|
102
|
+
bad(`${at}.path`, `The path ${problem}.`);
|
|
103
|
+
if (seen.has(item.path.toLowerCase()))
|
|
104
|
+
bad(`${at}.path`, `List ${item.path} once.`);
|
|
105
|
+
seen.add(item.path.toLowerCase());
|
|
106
|
+
for (const key of Object.keys(item))
|
|
107
|
+
if (!KNOWN_MEDIA.has(key))
|
|
108
|
+
warnings.push(issue('MANIFEST_UNKNOWN_FIELD', `${file}: unknown field "${at}.${key}" is ignored.`, `Remove "${key}".`, file, 'warning'));
|
|
109
|
+
if (item.assetId !== undefined && (typeof item.assetId !== 'string' || !UUID.test(item.assetId)))
|
|
110
|
+
bad(`${at}.assetId`, 'Set assetId to the UUID of a completed Martini asset, or remove it.');
|
|
111
|
+
if (item.upload !== undefined && !['auto', 'always', 'never'].includes(String(item.upload)))
|
|
112
|
+
bad(`${at}.upload`, 'Set upload to "auto", "always" or "never".');
|
|
113
|
+
const entry = { path: item.path };
|
|
114
|
+
if (typeof item.assetId === 'string')
|
|
115
|
+
entry.assetId = item.assetId;
|
|
116
|
+
if (typeof item.upload === 'string')
|
|
117
|
+
entry.upload = item.upload;
|
|
118
|
+
if (item.recipe !== undefined) {
|
|
119
|
+
const recipe = item.recipe;
|
|
120
|
+
if (!isRecord(recipe)) {
|
|
121
|
+
bad(`${at}.recipe`, 'Set recipe to { "dir", "command", "output" }.');
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
for (const key of Object.keys(recipe))
|
|
125
|
+
if (!KNOWN_RECIPE.has(key))
|
|
126
|
+
warnings.push(issue('MANIFEST_UNKNOWN_FIELD', `${file}: unknown field "${at}.recipe.${key}" is ignored.`, `Remove "${key}".`, file, 'warning'));
|
|
127
|
+
for (const key of ['dir', 'command', 'output'])
|
|
128
|
+
if (typeof recipe[key] !== 'string' || !recipe[key].trim())
|
|
129
|
+
bad(`${at}.recipe.${key}`, `Set recipe.${key} to a non-empty string.`);
|
|
130
|
+
for (const key of ['entry', 'tool', 'notes'])
|
|
131
|
+
if (recipe[key] !== undefined && typeof recipe[key] !== 'string')
|
|
132
|
+
bad(`${at}.recipe.${key}`, `Set recipe.${key} to a string.`);
|
|
133
|
+
if (recipe.fps !== undefined && (typeof recipe.fps !== 'number' || !(recipe.fps > 0)))
|
|
134
|
+
bad(`${at}.recipe.fps`, 'Set recipe.fps to a positive number (Graphics render at 24).');
|
|
135
|
+
if (recipe.exclude !== undefined && !stringList(recipe.exclude))
|
|
136
|
+
bad(`${at}.recipe.exclude`, 'Set recipe.exclude to an array of globs.');
|
|
137
|
+
const archive = recipe.archive;
|
|
138
|
+
if (archive !== undefined &&
|
|
139
|
+
(!isRecord(archive) ||
|
|
140
|
+
typeof archive.sha256 !== 'string' ||
|
|
141
|
+
!SHA256.test(archive.sha256) ||
|
|
142
|
+
!Number.isInteger(archive.bytes) ||
|
|
143
|
+
archive.bytes <= 0))
|
|
144
|
+
bad(`${at}.recipe.archive`, 'Leave recipe.archive to martini graphics push, or set it to { "sha256", "bytes" } of a stored archive.');
|
|
145
|
+
if (typeof recipe.dir === 'string' && typeof recipe.command === 'string' && typeof recipe.output === 'string') {
|
|
146
|
+
const out = { dir: recipe.dir, command: recipe.command, output: recipe.output };
|
|
147
|
+
for (const key of ['entry', 'tool', 'notes'])
|
|
148
|
+
if (typeof recipe[key] === 'string')
|
|
149
|
+
out[key] = recipe[key];
|
|
150
|
+
if (typeof recipe.fps === 'number')
|
|
151
|
+
out.fps = recipe.fps;
|
|
152
|
+
if (stringList(recipe.exclude))
|
|
153
|
+
out.exclude = recipe.exclude;
|
|
154
|
+
if (isRecord(archive) && typeof archive.sha256 === 'string' && typeof archive.bytes === 'number')
|
|
155
|
+
out.archive = { sha256: archive.sha256, bytes: archive.bytes };
|
|
156
|
+
if (out.fps !== undefined && out.fps !== 24)
|
|
157
|
+
warnings.push(issue('RECIPE_FPS_NOT_TIMELINE', `${at}.recipe renders at ${out.fps} fps; Martini's timeline is 24 fps and resamples the clip.`, 'Render the clip at 24 fps so no frame is dropped or doubled.', file, 'warning'));
|
|
158
|
+
entry.recipe = out;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
media.push(entry);
|
|
163
|
+
}
|
|
164
|
+
if (errors.length)
|
|
165
|
+
return { ok: false, errors, warnings };
|
|
166
|
+
const manifest = { version: 1, media };
|
|
167
|
+
if (raw.door !== undefined)
|
|
168
|
+
manifest.door = raw.door;
|
|
169
|
+
if (typeof raw.name === 'string')
|
|
170
|
+
manifest.name = raw.name;
|
|
171
|
+
if (typeof raw.description === 'string')
|
|
172
|
+
manifest.description = raw.description;
|
|
173
|
+
if (raw.backgroundMode === 'opaque' || raw.backgroundMode === 'transparent')
|
|
174
|
+
manifest.backgroundMode = raw.backgroundMode;
|
|
175
|
+
if (isRecord(raw.artifact)) {
|
|
176
|
+
const artifact = {};
|
|
177
|
+
const source = raw.artifact;
|
|
178
|
+
if (typeof source.durationSeconds === 'number')
|
|
179
|
+
artifact.durationSeconds = source.durationSeconds;
|
|
180
|
+
if (typeof source.autoStart === 'boolean')
|
|
181
|
+
artifact.autoStart = source.autoStart;
|
|
182
|
+
if (typeof source.width === 'number')
|
|
183
|
+
artifact.width = source.width;
|
|
184
|
+
if (typeof source.height === 'number')
|
|
185
|
+
artifact.height = source.height;
|
|
186
|
+
manifest.artifact = artifact;
|
|
187
|
+
}
|
|
188
|
+
if (stringList(raw.exclude))
|
|
189
|
+
manifest.exclude = raw.exclude;
|
|
190
|
+
return { ok: true, manifest, warnings };
|
|
191
|
+
}
|
|
192
|
+
export function resolveManifest(manifest, resolved) {
|
|
193
|
+
const media = manifest.media.map(entry => {
|
|
194
|
+
const next = { path: entry.path };
|
|
195
|
+
const assetId = resolved.assetIds?.get(entry.path) ?? entry.assetId;
|
|
196
|
+
if (assetId)
|
|
197
|
+
next.assetId = assetId;
|
|
198
|
+
if (entry.upload)
|
|
199
|
+
next.upload = entry.upload;
|
|
200
|
+
if (entry.recipe) {
|
|
201
|
+
const recipe = {
|
|
202
|
+
dir: resolved.recipeDirs?.get(entry.path) ?? entry.recipe.dir,
|
|
203
|
+
command: entry.recipe.command,
|
|
204
|
+
output: entry.recipe.output,
|
|
205
|
+
};
|
|
206
|
+
for (const key of ['entry', 'tool', 'fps', 'notes'])
|
|
207
|
+
if (entry.recipe[key] !== undefined)
|
|
208
|
+
Object.assign(recipe, { [key]: entry.recipe[key] });
|
|
209
|
+
if (entry.recipe.exclude?.length)
|
|
210
|
+
recipe.exclude = [...entry.recipe.exclude];
|
|
211
|
+
const archive = resolved.archives?.get(entry.path) ?? entry.recipe.archive;
|
|
212
|
+
if (archive)
|
|
213
|
+
recipe.archive = { sha256: archive.sha256, bytes: archive.bytes };
|
|
214
|
+
next.recipe = recipe;
|
|
215
|
+
}
|
|
216
|
+
return next;
|
|
217
|
+
});
|
|
218
|
+
return {
|
|
219
|
+
version: 1,
|
|
220
|
+
...(manifest.door ? { door: manifest.door } : {}),
|
|
221
|
+
...(manifest.name !== undefined ? { name: manifest.name } : {}),
|
|
222
|
+
...(manifest.description !== undefined ? { description: manifest.description } : {}),
|
|
223
|
+
...(manifest.backgroundMode ? { backgroundMode: manifest.backgroundMode } : {}),
|
|
224
|
+
...(manifest.artifact ? { artifact: { ...manifest.artifact } } : {}),
|
|
225
|
+
...(manifest.exclude?.length ? { exclude: [...manifest.exclude] } : {}),
|
|
226
|
+
media,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
export function serializeManifest(manifest) {
|
|
230
|
+
return `${JSON.stringify(manifest, null, 2)}\n`;
|
|
231
|
+
}
|
|
232
|
+
export function globToRegExp(glob) {
|
|
233
|
+
const anchored = glob.includes('/');
|
|
234
|
+
const body = glob.replace(/^\.\//, '').replace(/\/$/, '');
|
|
235
|
+
let pattern = '';
|
|
236
|
+
for (let i = 0; i < body.length; i += 1) {
|
|
237
|
+
const char = body[i];
|
|
238
|
+
if (char === '*') {
|
|
239
|
+
if (body[i + 1] === '*') {
|
|
240
|
+
const slash = body[i + 2] === '/';
|
|
241
|
+
pattern += slash ? '(?:.*/)?' : '.*';
|
|
242
|
+
i += slash ? 2 : 1;
|
|
243
|
+
}
|
|
244
|
+
else
|
|
245
|
+
pattern += '[^/]*';
|
|
246
|
+
}
|
|
247
|
+
else if (char === '?')
|
|
248
|
+
pattern += '[^/]';
|
|
249
|
+
else
|
|
250
|
+
pattern += char.replace(/[.+^${}()|[\]\\]/g, '\\$&');
|
|
251
|
+
}
|
|
252
|
+
return new RegExp(`^${anchored ? '' : '(?:.*/)?'}${pattern}(?:/.*)?$`);
|
|
253
|
+
}
|
|
254
|
+
export function matchesAny(path, globs) {
|
|
255
|
+
return (globs ?? []).some(glob => globToRegExp(glob).test(path));
|
|
256
|
+
}
|
|
257
|
+
export function readState(dir) {
|
|
258
|
+
const path = join(dir, GRAPHIC_STATE_FILE);
|
|
259
|
+
if (!existsSync(path))
|
|
260
|
+
return undefined;
|
|
261
|
+
const parsed = JSON.parse(readFileSync(path, 'utf8'));
|
|
262
|
+
if (parsed.version !== 1 || typeof parsed.projectId !== 'string')
|
|
263
|
+
return undefined;
|
|
264
|
+
return { media: {}, recipes: {}, ...parsed };
|
|
265
|
+
}
|
|
266
|
+
export function writeState(dir, state) {
|
|
267
|
+
const path = join(dir, GRAPHIC_STATE_FILE);
|
|
268
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
269
|
+
const temp = `${path}.${randomUUID()}.tmp`;
|
|
270
|
+
writeFileSync(temp, `${JSON.stringify(state, null, 2)}\n`, { flag: 'wx' });
|
|
271
|
+
renameSync(temp, path);
|
|
272
|
+
}
|
|
273
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/graphics/manifest.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AACxF,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEzC,MAAM,CAAC,MAAM,qBAAqB,GAAG,sBAAsB,CAAA;AAC3D,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,CAAA;AAElE,MAAM,CAAC,MAAM,yBAAyB,GAAG,IAAI,CAAC,UAAU,EAAE,iBAAiB,CAAC,CAAA;AAG5E,MAAM,CAAC,MAAM,KAAK,GAAoB,CAAC,aAAa,EAAE,UAAU,CAAC,CAAA;AAgEjE,MAAM,UAAU,KAAK,CACnB,IAAY,EACZ,OAAe,EACf,GAAW,EACX,IAAa,EACb,WAAqC,OAAO;IAE5C,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,CAAA;AAClF,CAAC;AAED,MAAM,IAAI,GAAG,iEAAiE,CAAA;AAC9E,MAAM,MAAM,GAAG,gBAAgB,CAAA;AAC/B,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,gBAAgB,EAAE,UAAU,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,CAAA;AACvH,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAA;AACpE,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,CAAA;AAEjH,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;AAC7E,CAAC;AAED,SAAS,mBAAmB,CAAC,IAAY;IACvC,IAAI,CAAC,IAAI;QAAE,OAAO,UAAU,CAAA;IAC5B,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,iCAAiC,CAAA;IAC7F,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,0BAA0B,CAAA;IAC1D,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,GAAG,IAAI,OAAO,KAAK,EAAE,CAAC;QACxF,OAAO,0CAA0C,CAAA;IACnD,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,SAAS,UAAU,CAAC,KAAc;IAChC,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;AACjG,CAAC;AAOD,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC/C,MAAM,IAAI,GAAG,qBAAqB,CAAA;IAClC,MAAM,MAAM,GAAmB,EAAE,CAAA;IACjC,MAAM,QAAQ,GAAmB,EAAE,CAAA;IACnC,IAAI,GAAY,CAAA;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IACxB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO;YACL,EAAE,EAAE,KAAK;YACT,MAAM,EAAE;gBACN,KAAK,CACH,uBAAuB,EACvB,GAAG,IAAI,uBAAuB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,IAAI,EACxF,sBAAsB,EACtB,IAAI,CACL;aACF;YACD,QAAQ;SACT,CAAA;IACH,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACnB,OAAO;YACL,EAAE,EAAE,KAAK;YACT,MAAM,EAAE;gBACN,KAAK,CAAC,kBAAkB,EAAE,GAAG,IAAI,yBAAyB,EAAE,sCAAsC,EAAE,IAAI,CAAC;aAC1G;YACD,QAAQ;SACT,CAAA;IACH,CAAC;IACD,MAAM,GAAG,GAAG,CAAC,KAAa,EAAE,GAAW,EAAE,EAAE,CACzC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,kBAAkB,EAAE,GAAG,IAAI,KAAK,KAAK,cAAc,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,CAAA;IACpF,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;QAChC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC;YACrB,QAAQ,CAAC,IAAI,CACX,KAAK,CACH,wBAAwB,EACxB,GAAG,IAAI,oBAAoB,GAAG,eAAe,EAC7C,WAAW,GAAG,IAAI,EAClB,IAAI,EACJ,SAAS,CACV,CACF,CAAA;IACL,IAAI,GAAG,CAAC,OAAO,KAAK,CAAC;QAAE,GAAG,CAAC,SAAS,EAAE,mBAAmB,CAAC,CAAA;IAC1D,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAY,CAAC;QAC7D,GAAG,CAAC,MAAM,EAAE,oEAAoE,CAAC,CAAA;IACnF,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC;QACvG,GAAG,CAAC,MAAM,EAAE,iCAAiC,CAAC,CAAA;IAChD,IAAI,GAAG,CAAC,WAAW,KAAK,SAAS,IAAI,CAAC,OAAO,GAAG,CAAC,WAAW,KAAK,QAAQ,IAAI,GAAG,CAAC,WAAW,CAAC,MAAM,GAAG,IAAI,CAAC;QACzG,GAAG,CAAC,aAAa,EAAE,+CAA+C,CAAC,CAAA;IACrE,IAAI,GAAG,CAAC,cAAc,KAAK,SAAS,IAAI,GAAG,CAAC,cAAc,KAAK,QAAQ,IAAI,GAAG,CAAC,cAAc,KAAK,aAAa;QAC7G,GAAG,CAAC,gBAAgB,EAAE,oDAAoD,CAAC,CAAA;IAC7E,IAAI,GAAG,CAAC,OAAO,KAAK,SAAS,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC;QACvD,GAAG,CAAC,SAAS,EAAE,4CAA4C,CAAC,CAAA;IAC9D,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC/B,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAA;QAC7B,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;YAAE,GAAG,CAAC,UAAU,EAAE,qDAAqD,CAAC,CAAA;aAC1F,CAAC;YACJ,IACE,QAAQ,CAAC,eAAe,KAAK,SAAS;gBACtC,CAAC,OAAO,QAAQ,CAAC,eAAe,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;gBAE5F,GAAG,CAAC,0BAA0B,EAAE,gCAAgC,CAAC,CAAA;YACnE,IAAI,QAAQ,CAAC,SAAS,KAAK,SAAS,IAAI,OAAO,QAAQ,CAAC,SAAS,KAAK,SAAS;gBAC7E,GAAG,CAAC,oBAAoB,EAAE,0BAA0B,CAAC,CAAA;YACvD,KAAK,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAU;gBAC5C,IAAI,QAAQ,CAAC,GAAG,CAAC,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;oBACjE,GAAG,CAAC,YAAY,GAAG,EAAE,EAAE,qCAAqC,CAAC,CAAA;QACnE,CAAC;IACH,CAAC;IACD,MAAM,KAAK,GAAoB,EAAE,CAAA;IACjC,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;QAAE,GAAG,CAAC,OAAO,EAAE,0BAA0B,CAAC,CAAA;IAClG,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAA;IAC9B,KAAK,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;QAClF,MAAM,EAAE,GAAG,SAAS,KAAK,GAAG,CAAA;QAC5B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACrD,GAAG,CAAC,EAAE,EAAE,wCAAwC,CAAC,CAAA;YACjD,SAAQ;QACV,CAAC;QACD,MAAM,OAAO,GAAG,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC9C,IAAI,OAAO;YAAE,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,YAAY,OAAO,GAAG,CAAC,CAAA;QACtD,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YAAE,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,QAAQ,IAAI,CAAC,IAAI,QAAQ,CAAC,CAAA;QACnF,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAA;QACjC,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;YACjC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC;gBACvB,QAAQ,CAAC,IAAI,CACX,KAAK,CACH,wBAAwB,EACxB,GAAG,IAAI,oBAAoB,EAAE,IAAI,GAAG,eAAe,EACnD,WAAW,GAAG,IAAI,EAClB,IAAI,EACJ,SAAS,CACV,CACF,CAAA;QACL,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC9F,GAAG,CAAC,GAAG,EAAE,UAAU,EAAE,qEAAqE,CAAC,CAAA;QAC7F,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACzF,GAAG,CAAC,GAAG,EAAE,SAAS,EAAE,4CAA4C,CAAC,CAAA;QACnE,MAAM,KAAK,GAAkB,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAA;QAChD,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ;YAAE,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAA;QAClE,IAAI,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ;YAAE,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,MAAoB,CAAA;QAC7E,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC9B,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAA;YAC1B,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;gBACtB,GAAG,CAAC,GAAG,EAAE,SAAS,EAAE,+CAA+C,CAAC,CAAA;YACtE,CAAC;iBAAM,CAAC;gBACN,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;oBACnC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC;wBACxB,QAAQ,CAAC,IAAI,CACX,KAAK,CACH,wBAAwB,EACxB,GAAG,IAAI,oBAAoB,EAAE,WAAW,GAAG,eAAe,EAC1D,WAAW,GAAG,IAAI,EAClB,IAAI,EACJ,SAAS,CACV,CACF,CAAA;gBACL,KAAK,MAAM,GAAG,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,CAAU;oBACrD,IAAI,OAAO,MAAM,CAAC,GAAG,CAAC,KAAK,QAAQ,IAAI,CAAE,MAAM,CAAC,GAAG,CAAY,CAAC,IAAI,EAAE;wBACpE,GAAG,CAAC,GAAG,EAAE,WAAW,GAAG,EAAE,EAAE,cAAc,GAAG,yBAAyB,CAAC,CAAA;gBAC1E,KAAK,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAU;oBACnD,IAAI,MAAM,CAAC,GAAG,CAAC,KAAK,SAAS,IAAI,OAAO,MAAM,CAAC,GAAG,CAAC,KAAK,QAAQ;wBAC9D,GAAG,CAAC,GAAG,EAAE,WAAW,GAAG,EAAE,EAAE,cAAc,GAAG,eAAe,CAAC,CAAA;gBAChE,IAAI,MAAM,CAAC,GAAG,KAAK,SAAS,IAAI,CAAC,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;oBACnF,GAAG,CAAC,GAAG,EAAE,aAAa,EAAE,8DAA8D,CAAC,CAAA;gBACzF,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC;oBAC7D,GAAG,CAAC,GAAG,EAAE,iBAAiB,EAAE,0CAA0C,CAAC,CAAA;gBACzE,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAA;gBAC9B,IACE,OAAO,KAAK,SAAS;oBACrB,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC;wBACjB,OAAO,OAAO,CAAC,MAAM,KAAK,QAAQ;wBAClC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;wBAC5B,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC;wBAC/B,OAAO,CAAC,KAAgB,IAAI,CAAC,CAAC;oBAEjC,GAAG,CACD,GAAG,EAAE,iBAAiB,EACtB,wGAAwG,CACzG,CAAA;gBACH,IAAI,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,IAAI,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;oBAC9G,MAAM,GAAG,GAAW,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAA;oBACvF,KAAK,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAU;wBACnD,IAAI,OAAO,MAAM,CAAC,GAAG,CAAC,KAAK,QAAQ;4BAAE,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAW,CAAA;oBACvE,IAAI,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ;wBAAE,GAAG,CAAC,GAAG,GAAG,MAAM,CAAC,GAAG,CAAA;oBACxD,IAAI,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC;wBAAE,GAAG,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAA;oBAC5D,IAAI,QAAQ,CAAC,OAAO,CAAC,IAAI,OAAO,OAAO,CAAC,MAAM,KAAK,QAAQ,IAAI,OAAO,OAAO,CAAC,KAAK,KAAK,QAAQ;wBAC9F,GAAG,CAAC,OAAO,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAA;oBAChE,IAAI,GAAG,CAAC,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,GAAG,KAAK,EAAE;wBACzC,QAAQ,CAAC,IAAI,CACX,KAAK,CACH,yBAAyB,EACzB,GAAG,EAAE,sBAAsB,GAAG,CAAC,GAAG,4DAA4D,EAC9F,8DAA8D,EAC9D,IAAI,EACJ,SAAS,CACV,CACF,CAAA;oBACH,KAAK,CAAC,MAAM,GAAG,GAAG,CAAA;gBACpB,CAAC;YACH,CAAC;QACH,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IACnB,CAAC;IACD,IAAI,MAAM,CAAC,MAAM;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAA;IACzD,MAAM,QAAQ,GAAoB,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,CAAA;IACvD,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS;QAAE,QAAQ,CAAC,IAAI,GAAG,GAAG,CAAC,IAAY,CAAA;IAC5D,IAAI,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ;QAAE,QAAQ,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,CAAA;IAC1D,IAAI,OAAO,GAAG,CAAC,WAAW,KAAK,QAAQ;QAAE,QAAQ,CAAC,WAAW,GAAG,GAAG,CAAC,WAAW,CAAA;IAC/E,IAAI,GAAG,CAAC,cAAc,KAAK,QAAQ,IAAI,GAAG,CAAC,cAAc,KAAK,aAAa;QACzE,QAAQ,CAAC,cAAc,GAAG,GAAG,CAAC,cAAc,CAAA;IAC9C,IAAI,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC3B,MAAM,QAAQ,GAAoB,EAAE,CAAA;QACpC,MAAM,MAAM,GAAG,GAAG,CAAC,QAAQ,CAAA;QAC3B,IAAI,OAAO,MAAM,CAAC,eAAe,KAAK,QAAQ;YAAE,QAAQ,CAAC,eAAe,GAAG,MAAM,CAAC,eAAe,CAAA;QACjG,IAAI,OAAO,MAAM,CAAC,SAAS,KAAK,SAAS;YAAE,QAAQ,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAA;QAChF,IAAI,OAAO,MAAM,CAAC,KAAK,KAAK,QAAQ;YAAE,QAAQ,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAA;QACnE,IAAI,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ;YAAE,QAAQ,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAA;QACtE,QAAQ,CAAC,QAAQ,GAAG,QAAQ,CAAA;IAC9B,CAAC;IACD,IAAI,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC;QAAE,QAAQ,CAAC,OAAO,GAAG,GAAG,CAAC,OAAO,CAAA;IAC3D,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAA;AACzC,CAAC;AAMD,MAAM,UAAU,eAAe,CAC7B,QAAyB,EACzB,QAIC;IAED,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;QACvC,MAAM,IAAI,GAAkB,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAA;QAChD,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,OAAO,CAAA;QACnE,IAAI,OAAO;YAAE,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;QACnC,IAAI,KAAK,CAAC,MAAM;YAAE,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAA;QAC5C,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;YACjB,MAAM,MAAM,GAAW;gBACrB,GAAG,EAAE,QAAQ,CAAC,UAAU,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG;gBAC7D,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,OAAO;gBAC7B,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM;aAC5B,CAAA;YACD,KAAK,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAU;gBAC1D,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,SAAS;oBAAE,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;YAC1F,IAAI,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM;gBAAE,MAAM,CAAC,OAAO,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;YAC5E,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,OAAO,CAAA;YAC1E,IAAI,OAAO;gBAAE,MAAM,CAAC,OAAO,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAA;YAC9E,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;QACtB,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC,CAAC,CAAA;IACF,OAAO;QACL,OAAO,EAAE,CAAC;QACV,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACjD,GAAG,CAAC,QAAQ,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/D,GAAG,CAAC,QAAQ,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACpF,GAAG,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,QAAQ,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/E,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,GAAG,QAAQ,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACpE,GAAG,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvE,KAAK;KACN,CAAA;AACH,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,QAAyB;IACzD,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAA;AACjD,CAAC;AAOD,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAA;IACnC,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;IACzD,IAAI,OAAO,GAAG,EAAE,CAAA;IAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAE,CAAA;QACrB,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YACjB,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;gBACxB,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,CAAA;gBACjC,OAAO,IAAI,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAA;gBACpC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;YACpB,CAAC;;gBAAM,OAAO,IAAI,OAAO,CAAA;QAC3B,CAAC;aAAM,IAAI,IAAI,KAAK,GAAG;YAAE,OAAO,IAAI,MAAM,CAAA;;YACrC,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAA;IAC3D,CAAC;IACD,OAAO,IAAI,MAAM,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,GAAG,OAAO,WAAW,CAAC,CAAA;AACxE,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,KAAoC;IAC3E,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;AAClE,CAAC;AAyCD,MAAM,UAAU,SAAS,CAAC,GAAW;IACnC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,kBAAkB,CAAC,CAAA;IAC1C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAA;IACvC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAA0B,CAAA;IAC9E,IAAI,MAAM,CAAC,OAAO,KAAK,CAAC,IAAI,OAAO,MAAM,CAAC,SAAS,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAA;IAClF,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,MAAM,EAAkB,CAAA;AAC9D,CAAC;AAOD,MAAM,UAAU,UAAU,CAAC,GAAW,EAAE,KAAmB;IACzD,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,kBAAkB,CAAC,CAAA;IAC1C,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAC7C,MAAM,IAAI,GAAG,GAAG,IAAI,IAAI,UAAU,EAAE,MAAM,CAAA;IAC1C,aAAa,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;IAC1E,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;AACxB,CAAC"}
|