@macrulez/mediatoolz 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +182 -2
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.js +243 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/commands/image-batch/backup.d.ts +22 -0
  7. package/dist/commands/image-batch/backup.js +55 -0
  8. package/dist/commands/image-batch/backup.js.map +1 -0
  9. package/dist/commands/image-batch/cache.d.ts +15 -0
  10. package/dist/commands/image-batch/cache.js +38 -0
  11. package/dist/commands/image-batch/cache.js.map +1 -0
  12. package/dist/commands/image-batch/cli.d.ts +15 -0
  13. package/dist/commands/image-batch/cli.js +323 -0
  14. package/dist/commands/image-batch/cli.js.map +1 -0
  15. package/dist/commands/image-batch/codecs.d.ts +38 -0
  16. package/dist/commands/image-batch/codecs.js +366 -0
  17. package/dist/commands/image-batch/codecs.js.map +1 -0
  18. package/dist/commands/image-batch/config.d.ts +121 -0
  19. package/dist/commands/image-batch/config.js +690 -0
  20. package/dist/commands/image-batch/config.js.map +1 -0
  21. package/dist/commands/image-batch/errors.d.ts +5 -0
  22. package/dist/commands/image-batch/errors.js +8 -0
  23. package/dist/commands/image-batch/errors.js.map +1 -0
  24. package/dist/commands/image-batch/geometry.d.ts +26 -0
  25. package/dist/commands/image-batch/geometry.js +90 -0
  26. package/dist/commands/image-batch/geometry.js.map +1 -0
  27. package/dist/commands/image-batch/inputs.d.ts +22 -0
  28. package/dist/commands/image-batch/inputs.js +87 -0
  29. package/dist/commands/image-batch/inputs.js.map +1 -0
  30. package/dist/commands/image-batch/manage-cli.d.ts +2 -0
  31. package/dist/commands/image-batch/manage-cli.js +276 -0
  32. package/dist/commands/image-batch/manage-cli.js.map +1 -0
  33. package/dist/commands/image-batch/manage.d.ts +51 -0
  34. package/dist/commands/image-batch/manage.js +1041 -0
  35. package/dist/commands/image-batch/manage.js.map +1 -0
  36. package/dist/commands/image-batch/overwrite.d.ts +14 -0
  37. package/dist/commands/image-batch/overwrite.js +31 -0
  38. package/dist/commands/image-batch/overwrite.js.map +1 -0
  39. package/dist/commands/image-batch/plan.d.ts +86 -0
  40. package/dist/commands/image-batch/plan.js +396 -0
  41. package/dist/commands/image-batch/plan.js.map +1 -0
  42. package/dist/commands/image-batch/process.d.ts +8 -0
  43. package/dist/commands/image-batch/process.js +97 -0
  44. package/dist/commands/image-batch/process.js.map +1 -0
  45. package/dist/commands/image-batch/report.d.ts +6 -0
  46. package/dist/commands/image-batch/report.js +251 -0
  47. package/dist/commands/image-batch/report.js.map +1 -0
  48. package/dist/commands/image-batch/restore.d.ts +29 -0
  49. package/dist/commands/image-batch/restore.js +125 -0
  50. package/dist/commands/image-batch/restore.js.map +1 -0
  51. package/dist/commands/image-batch/run.d.ts +127 -0
  52. package/dist/commands/image-batch/run.js +656 -0
  53. package/dist/commands/image-batch/run.js.map +1 -0
  54. package/dist/commands/image-batch/sharpen-ask.d.ts +6 -0
  55. package/dist/commands/image-batch/sharpen-ask.js +53 -0
  56. package/dist/commands/image-batch/sharpen-ask.js.map +1 -0
  57. package/dist/commands/image-batch/sharpen-manage.d.ts +26 -0
  58. package/dist/commands/image-batch/sharpen-manage.js +238 -0
  59. package/dist/commands/image-batch/sharpen-manage.js.map +1 -0
  60. package/dist/commands/image-batch/sharpen-presets.d.ts +24 -0
  61. package/dist/commands/image-batch/sharpen-presets.js +145 -0
  62. package/dist/commands/image-batch/sharpen-presets.js.map +1 -0
  63. package/dist/commands/image-batch/sharpen.d.ts +46 -0
  64. package/dist/commands/image-batch/sharpen.js +159 -0
  65. package/dist/commands/image-batch/sharpen.js.map +1 -0
  66. package/dist/commands/image-batch/template.d.ts +45 -0
  67. package/dist/commands/image-batch/template.js +142 -0
  68. package/dist/commands/image-batch/template.js.map +1 -0
  69. package/dist/commands/image-hash/cache.d.ts +14 -0
  70. package/dist/commands/image-hash/cache.js +40 -0
  71. package/dist/commands/image-hash/cache.js.map +1 -0
  72. package/dist/commands/image-hash/core.d.ts +61 -0
  73. package/dist/commands/image-hash/core.js +302 -0
  74. package/dist/commands/image-hash/core.js.map +1 -0
  75. package/dist/commands/image-hash/hash.d.ts +21 -0
  76. package/dist/commands/image-hash/hash.js +104 -0
  77. package/dist/commands/image-hash/hash.js.map +1 -0
  78. package/dist/commands/image-hash/report.d.ts +3 -0
  79. package/dist/commands/image-hash/report.js +96 -0
  80. package/dist/commands/image-hash/report.js.map +1 -0
  81. package/dist/commands/image-hash/run.d.ts +61 -0
  82. package/dist/commands/image-hash/run.js +317 -0
  83. package/dist/commands/image-hash/run.js.map +1 -0
  84. package/dist/commands/image-hash/sharp-loader.d.ts +64 -0
  85. package/dist/commands/image-hash/sharp-loader.js +81 -0
  86. package/dist/commands/image-hash/sharp-loader.js.map +1 -0
  87. package/dist/commands/ui/cli.d.ts +2 -0
  88. package/dist/commands/ui/cli.js +78 -0
  89. package/dist/commands/ui/cli.js.map +1 -0
  90. package/dist/commands/ui/fs-routes.d.ts +7 -0
  91. package/dist/commands/ui/fs-routes.js +135 -0
  92. package/dist/commands/ui/fs-routes.js.map +1 -0
  93. package/dist/commands/ui/http.d.ts +41 -0
  94. package/dist/commands/ui/http.js +81 -0
  95. package/dist/commands/ui/http.js.map +1 -0
  96. package/dist/commands/ui/jobs.d.ts +15 -0
  97. package/dist/commands/ui/jobs.js +73 -0
  98. package/dist/commands/ui/jobs.js.map +1 -0
  99. package/dist/commands/ui/modules/image-batch-backups.d.ts +2 -0
  100. package/dist/commands/ui/modules/image-batch-backups.js +116 -0
  101. package/dist/commands/ui/modules/image-batch-backups.js.map +1 -0
  102. package/dist/commands/ui/modules/image-batch-manage.d.ts +2 -0
  103. package/dist/commands/ui/modules/image-batch-manage.js +245 -0
  104. package/dist/commands/ui/modules/image-batch-manage.js.map +1 -0
  105. package/dist/commands/ui/modules/image-batch.d.ts +2 -0
  106. package/dist/commands/ui/modules/image-batch.js +225 -0
  107. package/dist/commands/ui/modules/image-batch.js.map +1 -0
  108. package/dist/commands/ui/modules/image-hash.d.ts +2 -0
  109. package/dist/commands/ui/modules/image-hash.js +158 -0
  110. package/dist/commands/ui/modules/image-hash.js.map +1 -0
  111. package/dist/commands/ui/modules/index.d.ts +2 -0
  112. package/dist/commands/ui/modules/index.js +4 -0
  113. package/dist/commands/ui/modules/index.js.map +1 -0
  114. package/dist/commands/ui/open-browser.d.ts +1 -0
  115. package/dist/commands/ui/open-browser.js +18 -0
  116. package/dist/commands/ui/open-browser.js.map +1 -0
  117. package/dist/commands/ui/scan.d.ts +20 -0
  118. package/dist/commands/ui/scan.js +57 -0
  119. package/dist/commands/ui/scan.js.map +1 -0
  120. package/dist/commands/ui/server.d.ts +18 -0
  121. package/dist/commands/ui/server.js +196 -0
  122. package/dist/commands/ui/server.js.map +1 -0
  123. package/dist/format/bytes.d.ts +2 -0
  124. package/dist/format/bytes.js +17 -0
  125. package/dist/format/bytes.js.map +1 -0
  126. package/dist/format/colors.d.ts +12 -0
  127. package/dist/format/colors.js +15 -0
  128. package/dist/format/colors.js.map +1 -0
  129. package/dist/format/diff-render.d.ts +2 -0
  130. package/dist/format/diff-render.js +35 -0
  131. package/dist/format/diff-render.js.map +1 -0
  132. package/dist/format/file-list.d.ts +6 -0
  133. package/dist/format/file-list.js +15 -0
  134. package/dist/format/file-list.js.map +1 -0
  135. package/dist/format/findings-list.d.ts +7 -0
  136. package/dist/format/findings-list.js +14 -0
  137. package/dist/format/findings-list.js.map +1 -0
  138. package/dist/format/style.d.ts +20 -0
  139. package/dist/format/style.js +36 -0
  140. package/dist/format/style.js.map +1 -0
  141. package/dist/format/table.d.ts +8 -0
  142. package/dist/format/table.js +44 -0
  143. package/dist/format/table.js.map +1 -0
  144. package/dist/format/vibes.d.ts +13 -0
  145. package/dist/format/vibes.js +82 -0
  146. package/dist/format/vibes.js.map +1 -0
  147. package/dist/index.d.ts +9 -0
  148. package/dist/index.js +6 -0
  149. package/dist/index.js.map +1 -0
  150. package/dist/ui/assets/ImageBatchPage-D3f4z6YA.js +4 -0
  151. package/dist/ui/assets/ImageBatchPage-DwaunraE.css +1 -0
  152. package/dist/ui/assets/ImageHashPage-D0xZlLGw.css +1 -0
  153. package/dist/ui/assets/ImageHashPage-DjIlDPu-.js +1 -0
  154. package/dist/ui/assets/SourcePicker-D8aZjDwP.css +1 -0
  155. package/dist/ui/assets/SourcePicker-Db0dG6zc.js +1 -0
  156. package/dist/ui/assets/index-D1s-23_t.css +1 -0
  157. package/dist/ui/assets/index-yiehSw5D.js +3 -0
  158. package/dist/ui/index.html +17 -0
  159. package/dist/utils/closest.d.ts +2 -0
  160. package/dist/utils/closest.js +35 -0
  161. package/dist/utils/closest.js.map +1 -0
  162. package/dist/utils/glob.d.ts +4 -0
  163. package/dist/utils/glob.js +86 -0
  164. package/dist/utils/glob.js.map +1 -0
  165. package/dist/utils/split-list.d.ts +1 -0
  166. package/dist/utils/split-list.js +4 -0
  167. package/dist/utils/split-list.js.map +1 -0
  168. package/dist/utils/tty.d.ts +60 -0
  169. package/dist/utils/tty.js +390 -0
  170. package/dist/utils/tty.js.map +1 -0
  171. package/dist/utils/walk.d.ts +21 -0
  172. package/dist/utils/walk.js +116 -0
  173. package/dist/utils/walk.js.map +1 -0
  174. package/package.json +82 -4
@@ -0,0 +1,302 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { basename } from 'node:path';
3
+ import { splitList } from '../../utils/split-list.js';
4
+ export const ALL_TYPES = ['hazehash', 'blurhash', 'thumbhash', 'color', 'preview'];
5
+ export const OUTPUT_FORMATS = ['json', 'plain', 'csv', 'ts', 'js'];
6
+ export const DEFAULT_IMAGE_EXTENSIONS = [
7
+ '.jpg',
8
+ '.jpeg',
9
+ '.png',
10
+ '.webp',
11
+ '.gif',
12
+ '.avif',
13
+ '.tif',
14
+ '.tiff',
15
+ ];
16
+ export const DEFAULT_EXPORT_NAME = 'imageHashes';
17
+ export const DEFAULT_BLURHASH_COMPONENTS = { x: 4, y: 3 };
18
+ export const DEFAULT_HAZEHASH_BUDGET = 28;
19
+ export const MIN_HAZEHASH_BUDGET = 7;
20
+ export const MAX_HAZEHASH_BUDGET = 48;
21
+ export const DEFAULT_SAMPLE_SIZE = 100;
22
+ export const MAX_SAMPLE_SIZE = 100;
23
+ export const DEFAULT_CACHE_FILE = '.mediatoolz-image-hash-cache.json';
24
+ export class ImageHashUsageError extends Error {
25
+ }
26
+ export function parseTypes(value) {
27
+ const names = splitList(value).map((name) => name.toLowerCase());
28
+ const selected = new Set();
29
+ for (const name of names) {
30
+ if (name === 'both') {
31
+ selected.add('blurhash');
32
+ selected.add('thumbhash');
33
+ }
34
+ else if (name === 'all') {
35
+ ALL_TYPES.forEach((type) => selected.add(type));
36
+ }
37
+ else if (ALL_TYPES.includes(name)) {
38
+ selected.add(name);
39
+ }
40
+ else {
41
+ throw new ImageHashUsageError(`--type takes a comma-separated list of ${ALL_TYPES.join(', ')}, or both / all (got "${value}")`);
42
+ }
43
+ }
44
+ if (selected.size === 0) {
45
+ throw new ImageHashUsageError('--type needs at least one of hazehash, blurhash, thumbhash, color, preview');
46
+ }
47
+ return ALL_TYPES.filter((type) => selected.has(type));
48
+ }
49
+ export function orderTypes(types) {
50
+ const set = new Set(types);
51
+ return ALL_TYPES.filter((type) => set.has(type));
52
+ }
53
+ export function parseFormat(value) {
54
+ const normalized = value.trim().toLowerCase();
55
+ const found = OUTPUT_FORMATS.find((format) => format === normalized);
56
+ if (!found) {
57
+ throw new ImageHashUsageError(`--format must be one of ${OUTPUT_FORMATS.join(', ')} (got "${value}")`);
58
+ }
59
+ return found;
60
+ }
61
+ export function parseComponents(value) {
62
+ if (value.trim().toLowerCase() === 'auto')
63
+ return 'auto';
64
+ const match = /^(\d+)x(\d+)$/i.exec(value.trim());
65
+ const x = match ? Number(match[1]) : 0;
66
+ const y = match ? Number(match[2]) : 0;
67
+ if (!match || x < 1 || x > 9 || y < 1 || y > 9) {
68
+ throw new ImageHashUsageError(`--components must look like 4x3 (each side from 1 to 9) or be "auto" (got "${value}")`);
69
+ }
70
+ return { x, y };
71
+ }
72
+ export function resolveComponents(components, width, height) {
73
+ if (components !== 'auto')
74
+ return components;
75
+ const aspect = width >= height ? width / height : height / width;
76
+ const long = 4;
77
+ const short = Math.min(4, Math.max(2, Math.round(long / Math.sqrt(aspect))));
78
+ return width >= height ? { x: long, y: short } : { x: short, y: long };
79
+ }
80
+ export function componentsLabel(components) {
81
+ return components === 'auto' ? 'auto' : `${components.x}x${components.y}`;
82
+ }
83
+ export function parseBudget(value) {
84
+ const budget = Number(value);
85
+ if (!Number.isInteger(budget) || budget < MIN_HAZEHASH_BUDGET || budget > MAX_HAZEHASH_BUDGET) {
86
+ throw new ImageHashUsageError(`--budget must be a whole number of bytes from ${MIN_HAZEHASH_BUDGET} to ${MAX_HAZEHASH_BUDGET} (got "${value}")`);
87
+ }
88
+ return budget;
89
+ }
90
+ export function parseSampleSize(value) {
91
+ const size = Number(value);
92
+ if (!Number.isInteger(size) || size < 1 || size > MAX_SAMPLE_SIZE) {
93
+ throw new ImageHashUsageError(`--size must be a whole number from 1 to ${MAX_SAMPLE_SIZE} (got "${value}")`);
94
+ }
95
+ return size;
96
+ }
97
+ export function parseMaxPixels(value) {
98
+ const pixels = Number(value);
99
+ if (!Number.isInteger(pixels) || pixels < 0) {
100
+ throw new ImageHashUsageError(`--max-pixels must be a whole number, 0 for no limit (got "${value}")`);
101
+ }
102
+ return pixels;
103
+ }
104
+ export function parseExtensions(value) {
105
+ return splitList(value).map((ext) => (ext.startsWith('.') ? ext : `.${ext}`).toLowerCase());
106
+ }
107
+ export function withUpperCaseVariants(extensions) {
108
+ return [...new Set(extensions.flatMap((ext) => [ext, ext.toUpperCase()]))];
109
+ }
110
+ export function validateExportName(name) {
111
+ if (!/^[A-Za-z_$][\w$]*$/.test(name)) {
112
+ throw new ImageHashUsageError(`--name must be a valid identifier (got "${name}")`);
113
+ }
114
+ return name;
115
+ }
116
+ export function isUrl(value) {
117
+ return /^https?:\/\//i.test(value);
118
+ }
119
+ export function splitPathArguments(args, exists = existsSync) {
120
+ const out = [];
121
+ for (const arg of args) {
122
+ if (isUrl(arg) || exists(arg)) {
123
+ out.push(arg);
124
+ continue;
125
+ }
126
+ if (arg.includes(',')) {
127
+ for (const part of arg.split(',')) {
128
+ const trimmed = part.trim();
129
+ if (trimmed)
130
+ out.push(trimmed);
131
+ }
132
+ continue;
133
+ }
134
+ const words = arg.split(/\s+/).filter(Boolean);
135
+ out.push(...(words.length > 1 && words.every((word) => exists(word)) ? words : [arg]));
136
+ }
137
+ return out;
138
+ }
139
+ export function parseFileList(text) {
140
+ return text
141
+ .split(/\r?\n/)
142
+ .map((line) => line.trim())
143
+ .filter((line) => line !== '' && !line.startsWith('#'));
144
+ }
145
+ export function defaultOutExtension(format) {
146
+ return format === 'plain' ? '.txt' : `.${format}`;
147
+ }
148
+ export function normalizeOutExtension(value, format) {
149
+ if (value === undefined)
150
+ return defaultOutExtension(format);
151
+ const trimmed = value.trim();
152
+ if (trimmed === '')
153
+ return '';
154
+ return trimmed.startsWith('.') ? trimmed : `.${trimmed}`;
155
+ }
156
+ export function validateSuffix(suffix, types, format) {
157
+ const resolved = suffix ?? '.{type}';
158
+ if (format === 'plain' && types.length > 1 && !resolved.includes('{type}')) {
159
+ throw new ImageHashUsageError('--suffix must contain {type} when --format plain writes several hashes per image, ' +
160
+ 'otherwise the files would overwrite each other');
161
+ }
162
+ return resolved;
163
+ }
164
+ function csvField(value) {
165
+ return /[",\n]/.test(value) ? `"${value.replace(/"/g, '""')}"` : value;
166
+ }
167
+ function structured(entry, types) {
168
+ const out = { width: entry.width, height: entry.height };
169
+ for (const type of types) {
170
+ const value = entry[type];
171
+ if (value !== undefined)
172
+ out[type] = value;
173
+ }
174
+ return out;
175
+ }
176
+ function csvHeader(types, withFile) {
177
+ return [...(withFile ? ['file'] : []), 'width', 'height', ...types].join(',');
178
+ }
179
+ function csvRow(entry, types, withFile) {
180
+ return [
181
+ ...(withFile ? [csvField(entry.file)] : []),
182
+ String(entry.width),
183
+ String(entry.height),
184
+ ...types.map((type) => csvField(entry[type] ?? '')),
185
+ ].join(',');
186
+ }
187
+ export function formatAggregate(entries, types, format, exportName) {
188
+ if (format === 'csv') {
189
+ return [csvHeader(types, true), ...entries.map((e) => csvRow(e, types, true))].join('\n') + '\n';
190
+ }
191
+ if (format === 'plain') {
192
+ return (entries.map((e) => [e.file, ...types.map((type) => e[type] ?? '')].join('\t')).join('\n') +
193
+ (entries.length > 0 ? '\n' : ''));
194
+ }
195
+ const map = {};
196
+ for (const entry of entries)
197
+ map[entry.file] = structured(entry, types);
198
+ const json = JSON.stringify(map, null, 2);
199
+ if (format === 'json')
200
+ return `${json}\n`;
201
+ const suffix = format === 'ts' ? ' as const' : '';
202
+ return `export const ${exportName} = ${json}${suffix}\n`;
203
+ }
204
+ export function formatPerFile(entry, types, format) {
205
+ if (format === 'plain') {
206
+ return types.map((type) => ({ token: type, content: entry[type] ?? '' }));
207
+ }
208
+ const token = types.length > 1 ? 'hash' : types[0];
209
+ const object = structured(entry, types);
210
+ if (format === 'csv') {
211
+ return [{ token, content: `${csvHeader(types, false)}\n${csvRow(entry, types, false)}\n` }];
212
+ }
213
+ const json = JSON.stringify(object, null, 2);
214
+ if (format === 'json')
215
+ return [{ token, content: `${json}\n` }];
216
+ const suffix = format === 'ts' ? ' as const' : '';
217
+ return [{ token, content: `export default ${json}${suffix}\n` }];
218
+ }
219
+ export function outputFileName(imagePath, suffix, token, extension) {
220
+ return `${basename(imagePath)}${suffix.replace(/\{type\}/g, token)}${extension}`;
221
+ }
222
+ function parseCsvLine(line) {
223
+ const fields = [];
224
+ let current = '';
225
+ let quoted = false;
226
+ for (let i = 0; i < line.length; i++) {
227
+ const char = line[i];
228
+ if (quoted) {
229
+ if (char === '"' && line[i + 1] === '"') {
230
+ current += '"';
231
+ i++;
232
+ }
233
+ else if (char === '"') {
234
+ quoted = false;
235
+ }
236
+ else {
237
+ current += char;
238
+ }
239
+ }
240
+ else if (char === '"') {
241
+ quoted = true;
242
+ }
243
+ else if (char === ',') {
244
+ fields.push(current);
245
+ current = '';
246
+ }
247
+ else {
248
+ current += char;
249
+ }
250
+ }
251
+ fields.push(current);
252
+ return fields;
253
+ }
254
+ function entryFromRecord(file, record) {
255
+ const entry = {
256
+ file,
257
+ width: Number(record.width) || 0,
258
+ height: Number(record.height) || 0,
259
+ };
260
+ for (const type of ALL_TYPES) {
261
+ const value = record[type];
262
+ if (typeof value === 'string' && value !== '')
263
+ entry[type] = value;
264
+ }
265
+ return entry;
266
+ }
267
+ export function parseAggregate(content, format) {
268
+ const fail = () => {
269
+ throw new ImageHashUsageError('could not read the existing output file for --update; it must be a file this command ' +
270
+ 'generated (json, ts, js or csv), not reformatted by hand or by Prettier');
271
+ };
272
+ if (format === 'plain') {
273
+ throw new ImageHashUsageError('--update works with --format json, ts, js or csv, not plain');
274
+ }
275
+ if (format === 'csv') {
276
+ const lines = content.split(/\r?\n/).filter((line) => line !== '');
277
+ const header = parseCsvLine(lines[0] ?? '');
278
+ if (header[0] !== 'file')
279
+ return fail();
280
+ return lines.slice(1).map((line) => {
281
+ const fields = parseCsvLine(line);
282
+ const record = {};
283
+ header.forEach((name, i) => (record[name] = fields[i]));
284
+ return entryFromRecord(fields[0], record);
285
+ });
286
+ }
287
+ let body = content.trim();
288
+ if (format !== 'json') {
289
+ const match = /^[^{]*(\{[\s\S]*\})\s*(?:as\s+const)?\s*;?\s*$/.exec(body);
290
+ if (!match)
291
+ return fail();
292
+ body = match[1];
293
+ }
294
+ try {
295
+ const parsed = JSON.parse(body);
296
+ return Object.entries(parsed).map(([file, record]) => entryFromRecord(file, record));
297
+ }
298
+ catch {
299
+ return fail();
300
+ }
301
+ }
302
+ //# sourceMappingURL=core.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.js","sourceRoot":"","sources":["../../../src/commands/image-hash/core.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAA;AAIrD,MAAM,CAAC,MAAM,SAAS,GAAe,CAAC,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,OAAO,EAAE,SAAS,CAAC,CAAA;AAE9F,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,CAAU,CAAA;AAG3E,MAAM,CAAC,MAAM,wBAAwB,GAAG;IACtC,MAAM;IACN,OAAO;IACP,MAAM;IACN,OAAO;IACP,MAAM;IACN,OAAO;IACP,MAAM;IACN,OAAO;CACR,CAAA;AAED,MAAM,CAAC,MAAM,mBAAmB,GAAG,aAAa,CAAA;AAChD,MAAM,CAAC,MAAM,2BAA2B,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAA;AACzD,MAAM,CAAC,MAAM,uBAAuB,GAAG,EAAE,CAAA;AACzC,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAA;AACpC,MAAM,CAAC,MAAM,mBAAmB,GAAG,EAAE,CAAA;AACrC,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAG,CAAA;AACtC,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,CAAA;AAClC,MAAM,CAAC,MAAM,kBAAkB,GAAG,mCAAmC,CAAA;AAIrE,MAAM,OAAO,mBAAoB,SAAQ,KAAK;CAAG;AAkBjD,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAA;IAChE,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAY,CAAA;IACpC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;YACpB,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,CAAA;YACxB,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;QAC3B,CAAC;aAAM,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;YAC1B,SAAS,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAA;QACjD,CAAC;aAAM,IAAK,SAAsB,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YAClD,QAAQ,CAAC,GAAG,CAAC,IAAgB,CAAC,CAAA;QAChC,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,mBAAmB,CAC3B,0CAA0C,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,yBAAyB,KAAK,IAAI,CACjG,CAAA;QACH,CAAC;IACH,CAAC;IACD,IAAI,QAAQ,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,mBAAmB,CAC3B,4EAA4E,CAC7E,CAAA;IACH,CAAC;IACD,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAA;AACvD,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAyB;IAClD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAA;IAC1B,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAA;AAClD,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IAC7C,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,KAAK,UAAU,CAAC,CAAA;IACpE,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,mBAAmB,CAC3B,2BAA2B,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,KAAK,IAAI,CACxE,CAAA;IACH,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,MAAM;QAAE,OAAO,MAAM,CAAA;IACxD,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAA;IACjD,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IACtC,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IACtC,IAAI,CAAC,KAAK,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/C,MAAM,IAAI,mBAAmB,CAC3B,8EAA8E,KAAK,IAAI,CACxF,CAAA;IACH,CAAC;IACD,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAA;AACjB,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,UAAsB,EACtB,KAAa,EACb,MAAc;IAEd,IAAI,UAAU,KAAK,MAAM;QAAE,OAAO,UAAU,CAAA;IAC5C,MAAM,MAAM,GAAG,KAAK,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,GAAG,KAAK,CAAA;IAChE,MAAM,IAAI,GAAG,CAAC,CAAA;IACd,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;IAC5E,OAAO,KAAK,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAA;AACxE,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,UAAsB;IACpD,OAAO,UAAU,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,IAAI,UAAU,CAAC,CAAC,EAAE,CAAA;AAC3E,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;IAC5B,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,mBAAmB,IAAI,MAAM,GAAG,mBAAmB,EAAE,CAAC;QAC9F,MAAM,IAAI,mBAAmB,CAC3B,iDAAiD,mBAAmB,OAAO,mBAAmB,UAAU,KAAK,IAAI,CAClH,CAAA;IACH,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;IAC1B,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,eAAe,EAAE,CAAC;QAClE,MAAM,IAAI,mBAAmB,CAC3B,2CAA2C,eAAe,UAAU,KAAK,IAAI,CAC9E,CAAA;IACH,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAa;IAC1C,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;IAC5B,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5C,MAAM,IAAI,mBAAmB,CAC3B,6DAA6D,KAAK,IAAI,CACvE,CAAA;IACH,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,OAAO,SAAS,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAA;AAC7F,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,UAAoB;IACxD,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;AAC5E,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,mBAAmB,CAAC,2CAA2C,IAAI,IAAI,CAAC,CAAA;IACpF,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,KAAa;IACjC,OAAO,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;AACpC,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,IAAc,EACd,SAAoC,UAAU;IAE9C,MAAM,GAAG,GAAa,EAAE,CAAA;IACxB,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;YAC9B,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YACb,SAAQ;QACV,CAAC;QACD,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACtB,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;gBAClC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;gBAC3B,IAAI,OAAO;oBAAE,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;YAChC,CAAC;YACD,SAAQ;QACV,CAAC;QACD,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;QAC9C,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;IACxF,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,IAAI;SACR,KAAK,CAAC,OAAO,CAAC;SACd,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SAC1B,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAA;AAC3D,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,MAAoB;IACtD,OAAO,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,MAAM,EAAE,CAAA;AACnD,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,KAAyB,EAAE,MAAoB;IACnF,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,mBAAmB,CAAC,MAAM,CAAC,CAAA;IAC3D,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAA;IAC5B,IAAI,OAAO,KAAK,EAAE;QAAE,OAAO,EAAE,CAAA;IAC7B,OAAO,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,OAAO,EAAE,CAAA;AAC1D,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,MAA0B,EAC1B,KAAiB,EACjB,MAAoB;IAEpB,MAAM,QAAQ,GAAG,MAAM,IAAI,SAAS,CAAA;IACpC,IAAI,MAAM,KAAK,OAAO,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC3E,MAAM,IAAI,mBAAmB,CAC3B,oFAAoF;YAClF,gDAAgD,CACnD,CAAA;IACH,CAAC;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED,SAAS,QAAQ,CAAC,KAAa;IAC7B,OAAO,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAA;AACxE,CAAC;AAED,SAAS,UAAU,CAAC,KAAgB,EAAE,KAAiB;IACrD,MAAM,GAAG,GAAoC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAA;IACzF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CAAA;QACzB,IAAI,KAAK,KAAK,SAAS;YAAE,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,CAAA;IAC5C,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,SAAS,SAAS,CAAC,KAAiB,EAAE,QAAiB;IACrD,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAC/E,CAAC;AAED,SAAS,MAAM,CAAC,KAAgB,EAAE,KAAiB,EAAE,QAAiB;IACpE,OAAO;QACL,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3C,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC;QACnB,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;QACpB,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;KACpD,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AACb,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,OAAoB,EACpB,KAAiB,EACjB,MAAoB,EACpB,UAAkB;IAElB,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;QACrB,OAAO,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IAClG,CAAC;IACD,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;QACvB,OAAO,CACL,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;YACzF,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CACjC,CAAA;IACH,CAAC;IACD,MAAM,GAAG,GAAoD,EAAE,CAAA;IAC/D,KAAK,MAAM,KAAK,IAAI,OAAO;QAAE,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;IACvE,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;IACzC,IAAI,MAAM,KAAK,MAAM;QAAE,OAAO,GAAG,IAAI,IAAI,CAAA;IACzC,MAAM,MAAM,GAAG,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAA;IACjD,OAAO,gBAAgB,UAAU,MAAM,IAAI,GAAG,MAAM,IAAI,CAAA;AAC1D,CAAC;AAED,MAAM,UAAU,aAAa,CAC3B,KAAgB,EAChB,KAAiB,EACjB,MAAoB;IAEpB,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;QACvB,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAA;IAC3E,CAAC;IACD,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAE,KAAK,CAAC,CAAC,CAAc,CAAA;IAChE,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;IACvC,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;QACrB,OAAO,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAA;IAC7F,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;IAC5C,IAAI,MAAM,KAAK,MAAM;QAAE,OAAO,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC,CAAA;IAC/D,MAAM,MAAM,GAAG,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAA;IACjD,OAAO,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,kBAAkB,IAAI,GAAG,MAAM,IAAI,EAAE,CAAC,CAAA;AAClE,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,SAAiB,EACjB,MAAc,EACd,KAAa,EACb,SAAiB;IAEjB,OAAO,GAAG,QAAQ,CAAC,SAAS,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,CAAC,GAAG,SAAS,EAAE,CAAA;AAClF,CAAC;AAED,SAAS,YAAY,CAAC,IAAY;IAChC,MAAM,MAAM,GAAa,EAAE,CAAA;IAC3B,IAAI,OAAO,GAAG,EAAE,CAAA;IAChB,IAAI,MAAM,GAAG,KAAK,CAAA;IAClB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAW,CAAA;QAC9B,IAAI,MAAM,EAAE,CAAC;YACX,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;gBACxC,OAAO,IAAI,GAAG,CAAA;gBACd,CAAC,EAAE,CAAA;YACL,CAAC;iBAAM,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;gBACxB,MAAM,GAAG,KAAK,CAAA;YAChB,CAAC;iBAAM,CAAC;gBACN,OAAO,IAAI,IAAI,CAAA;YACjB,CAAC;QACH,CAAC;aAAM,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YACxB,MAAM,GAAG,IAAI,CAAA;QACf,CAAC;aAAM,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YACxB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;YACpB,OAAO,GAAG,EAAE,CAAA;QACd,CAAC;aAAM,CAAC;YACN,OAAO,IAAI,IAAI,CAAA;QACjB,CAAC;IACH,CAAC;IACD,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACpB,OAAO,MAAM,CAAA;AACf,CAAC;AAED,SAAS,eAAe,CAAC,IAAY,EAAE,MAA+B;IACpE,MAAM,KAAK,GAAc;QACvB,IAAI;QACJ,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC;QAChC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;KACnC,CAAA;IACD,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC7B,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAA;QAC1B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,EAAE;YAAE,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAA;IACpE,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,OAAe,EAAE,MAAoB;IAClE,MAAM,IAAI,GAAG,GAAU,EAAE;QACvB,MAAM,IAAI,mBAAmB,CAC3B,uFAAuF;YACrF,yEAAyE,CAC5E,CAAA;IACH,CAAC,CAAA;IACD,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;QACvB,MAAM,IAAI,mBAAmB,CAAC,6DAA6D,CAAC,CAAA;IAC9F,CAAC;IACD,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;QACrB,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,EAAE,CAAC,CAAA;QAClE,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAA;QAC3C,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM;YAAE,OAAO,IAAI,EAAE,CAAA;QACvC,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;YACjC,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,CAAA;YACjC,MAAM,MAAM,GAA4B,EAAE,CAAA;YAC1C,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;YACvD,OAAO,eAAe,CAAC,MAAM,CAAC,CAAC,CAAW,EAAE,MAAM,CAAC,CAAA;QACrD,CAAC,CAAC,CAAA;IACJ,CAAC;IACD,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,EAAE,CAAA;IACzB,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACtB,MAAM,KAAK,GAAG,gDAAgD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACzE,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,EAAE,CAAA;QACzB,IAAI,GAAG,KAAK,CAAC,CAAC,CAAW,CAAA;IAC3B,CAAC;IACD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAA4C,CAAA;QAC1E,OAAO,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAA;IACtF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,EAAE,CAAA;IACf,CAAC;AACH,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { type Components, type HashType } from './core.js';
2
+ import type { SharpFactory } from './sharp-loader.js';
3
+ export interface ComputeOptions {
4
+ types: HashType[];
5
+ size: number;
6
+ components: Components;
7
+ budget?: number;
8
+ maxPixels?: number;
9
+ }
10
+ export interface ComputedHashes {
11
+ width: number;
12
+ height: number;
13
+ hazehash?: string;
14
+ blurhash?: string;
15
+ thumbhash?: string;
16
+ color?: string;
17
+ preview?: string;
18
+ }
19
+ export declare function dominantColor(rgba: ArrayLike<number>): string | undefined;
20
+ export declare function friendlyMessage(error: unknown, maxPixels: number | undefined): string;
21
+ export declare function computeHashes(sharp: SharpFactory, input: string | Uint8Array, options: ComputeOptions): Promise<ComputedHashes>;
@@ -0,0 +1,104 @@
1
+ import { encode as encodeBlurhash } from 'blurhash';
2
+ import { encodeToString as encodeHazehash } from 'hazehash/encode';
3
+ import { rgbaToThumbHash, thumbHashToRGBA } from 'thumbhash';
4
+ import { DEFAULT_HAZEHASH_BUDGET, resolveComponents, } from './core.js';
5
+ export function dominantColor(rgba) {
6
+ const buckets = new Map();
7
+ for (let i = 0; i + 3 < rgba.length; i += 4) {
8
+ if (rgba[i + 3] < 128)
9
+ continue;
10
+ const r = rgba[i];
11
+ const g = rgba[i + 1];
12
+ const b = rgba[i + 2];
13
+ const key = ((r >> 4) << 8) | ((g >> 4) << 4) | (b >> 4);
14
+ const bucket = buckets.get(key);
15
+ if (bucket) {
16
+ bucket.count++;
17
+ bucket.r += r;
18
+ bucket.g += g;
19
+ bucket.b += b;
20
+ }
21
+ else {
22
+ buckets.set(key, { count: 1, r, g, b });
23
+ }
24
+ }
25
+ let best;
26
+ for (const bucket of buckets.values()) {
27
+ if (!best || bucket.count > best.count)
28
+ best = bucket;
29
+ }
30
+ if (!best)
31
+ return undefined;
32
+ const hex = (sum) => Math.round(sum / best.count)
33
+ .toString(16)
34
+ .padStart(2, '0');
35
+ return `#${hex(best.r)}${hex(best.g)}${hex(best.b)}`;
36
+ }
37
+ export function friendlyMessage(error, maxPixels) {
38
+ const message = error instanceof Error ? error.message : String(error);
39
+ if (/pixel limit/i.test(message)) {
40
+ const limit = maxPixels === undefined ? 'the default limit' : `${maxPixels} pixels`;
41
+ return `image is larger than ${limit} — raise it with --max-pixels (0 removes the limit)`;
42
+ }
43
+ if (/BudgetTooSmall/.test(message)) {
44
+ return 'the hazehash --budget is too small for this image (an image with transparency needs at least 9 bytes)';
45
+ }
46
+ if (/unsupported image format|corrupt header|bad seek|not a known file format/i.test(message)) {
47
+ return 'not a readable image — the file is corrupt or in an unsupported format';
48
+ }
49
+ if (/premature end|truncated|VipsJpeg|VipsPng|end of stream/i.test(message)) {
50
+ return 'the image file is truncated or damaged';
51
+ }
52
+ return message;
53
+ }
54
+ export async function computeHashes(sharp, input, options) {
55
+ const inputOptions = { failOn: 'truncated' };
56
+ if (options.maxPixels !== undefined) {
57
+ inputOptions.limitInputPixels = options.maxPixels === 0 ? false : options.maxPixels;
58
+ }
59
+ const metadata = await sharp(input, inputOptions).metadata();
60
+ const swapped = (metadata.orientation ?? 1) >= 5;
61
+ const width = (swapped ? metadata.height : metadata.width) ?? 0;
62
+ const height = (swapped ? metadata.width : metadata.height) ?? 0;
63
+ const { data, info } = await sharp(input, inputOptions)
64
+ .rotate()
65
+ .resize({ width: options.size, height: options.size, fit: 'inside', withoutEnlargement: true })
66
+ .toColourspace('srgb')
67
+ .ensureAlpha()
68
+ .raw()
69
+ .toBuffer({ resolveWithObject: true });
70
+ const result = {
71
+ width: width || info.width,
72
+ height: height || info.height,
73
+ };
74
+ if (options.types.includes('hazehash')) {
75
+ result.hazehash = encodeHazehash({ data, width: info.width, height: info.height }, { budget: options.budget ?? DEFAULT_HAZEHASH_BUDGET });
76
+ }
77
+ if (options.types.includes('blurhash')) {
78
+ const components = resolveComponents(options.components, info.width, info.height);
79
+ result.blurhash = encodeBlurhash(new Uint8ClampedArray(data), info.width, info.height, components.x, components.y);
80
+ }
81
+ const needsThumbhash = options.types.includes('thumbhash') || options.types.includes('preview');
82
+ if (needsThumbhash) {
83
+ const hash = rgbaToThumbHash(info.width, info.height, data);
84
+ if (options.types.includes('thumbhash')) {
85
+ result.thumbhash = Buffer.from(hash).toString('base64');
86
+ }
87
+ if (options.types.includes('preview')) {
88
+ const decoded = thumbHashToRGBA(hash);
89
+ const png = await sharp(decoded.rgba, {
90
+ raw: { width: decoded.w, height: decoded.h, channels: 4 },
91
+ })
92
+ .png({ compressionLevel: 9 })
93
+ .toBuffer();
94
+ result.preview = `data:image/png;base64,${Buffer.from(png).toString('base64')}`;
95
+ }
96
+ }
97
+ if (options.types.includes('color')) {
98
+ const color = dominantColor(data);
99
+ if (color !== undefined)
100
+ result.color = color;
101
+ }
102
+ return result;
103
+ }
104
+ //# sourceMappingURL=hash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.js","sourceRoot":"","sources":["../../../src/commands/image-hash/hash.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { type VibesOptions } from '../../format/vibes.js';
2
+ import type { ImageHashReport } from './run.js';
3
+ export declare function renderImageHashReport(report: ImageHashReport, options?: VibesOptions): string;
@@ -0,0 +1,96 @@
1
+ import { banner } from '../../format/vibes.js';
2
+ import { createStyle } from '../../format/style.js';
3
+ import { renderTable } from '../../format/table.js';
4
+ import { ALL_TYPES } from './core.js';
5
+ const TYPE_LABEL = {
6
+ hazehash: 'HazeHash',
7
+ blurhash: 'BlurHash',
8
+ thumbhash: 'ThumbHash',
9
+ color: 'Color',
10
+ preview: 'Preview',
11
+ };
12
+ const PREVIEW_CELL_WIDTH = 28;
13
+ function hashTypesIn(report) {
14
+ return ALL_TYPES.filter((type) => report.entries.some((entry) => entry[type] !== undefined));
15
+ }
16
+ function cellText(type, value) {
17
+ if (value === undefined)
18
+ return '';
19
+ if (type === 'preview' && value.length > PREVIEW_CELL_WIDTH) {
20
+ return `${value.slice(0, PREVIEW_CELL_WIDTH - 1)}…`;
21
+ }
22
+ return value;
23
+ }
24
+ function imageHashTable(report, options) {
25
+ const s = createStyle(options);
26
+ const types = hashTypesIn(report);
27
+ const typeStyle = {
28
+ hazehash: s.value,
29
+ blurhash: s.name,
30
+ thumbhash: s.accent,
31
+ color: s.value,
32
+ preview: s.tag,
33
+ };
34
+ const columns = [
35
+ { header: 'File', shrink: true, style: s.path },
36
+ { header: 'Size', align: 'right', style: s.tag },
37
+ ...types.map((type) => ({ header: TYPE_LABEL[type], style: typeStyle[type] })),
38
+ ];
39
+ const rows = report.entries.map((entry) => [
40
+ entry.file,
41
+ `${entry.width}×${entry.height}`,
42
+ ...types.map((type) => cellText(type, entry[type])),
43
+ ]);
44
+ return renderTable(columns, rows, options);
45
+ }
46
+ export function renderImageHashReport(report, options = {}) {
47
+ const s = createStyle(options);
48
+ const lines = [];
49
+ const isClean = report.errors.length === 0 && report.outdated.length === 0;
50
+ if (options.quiet && isClean)
51
+ return '';
52
+ if (!options.quiet && !options.plain)
53
+ lines.push(banner(options), '');
54
+ if (report.dryRun && report.entries.length > 0) {
55
+ lines.push(...imageHashTable(report, options), '');
56
+ }
57
+ const count = report.entries.length;
58
+ const cachedNote = report.cached > 0 ? `, ${report.cached} from the cache` : '';
59
+ lines.push(s.info(`Hashed ${count} image${count === 1 ? '' : 's'}${cachedNote}.`));
60
+ if (report.check) {
61
+ if (report.outdated.length === 0) {
62
+ lines.push('', s.success(`All ${report.checked} output file${report.checked === 1 ? ' is' : 's are'} up to date.`));
63
+ }
64
+ else {
65
+ lines.push('', s.problem(`${report.outdated.length} of ${report.checked} output file${report.checked === 1 ? '' : 's'} out of date:`));
66
+ for (const item of report.outdated) {
67
+ const reason = item.reason === 'missing' ? 'missing' : 'differs from the images';
68
+ lines.push(` ${s.path(item.file)} ${s.muted('—')} ${s.error(reason)}`);
69
+ }
70
+ lines.push('', s.hint('(regenerate them by running the same command without --check)'));
71
+ }
72
+ }
73
+ if (report.written.length > 0) {
74
+ const verb = report.dryRun ? 'Would write' : 'Wrote';
75
+ const heading = `${verb} ${report.written.length} file${report.written.length === 1 ? '' : 's'}:`;
76
+ lines.push('', report.dryRun ? s.heading(heading) : s.success(heading));
77
+ for (const file of report.written)
78
+ lines.push(` ${s.path(file)}`);
79
+ }
80
+ if (report.pruned > 0) {
81
+ lines.push('', s.info(`Removed ${report.pruned} entr${report.pruned === 1 ? 'y' : 'ies'} whose image no longer exists.`));
82
+ }
83
+ if (report.dryRun) {
84
+ lines.push('', s.hint(report.written.length > 0
85
+ ? '(dry run — nothing written; drop --dry-run to write the files)'
86
+ : '(dry run — nothing written)'));
87
+ }
88
+ if (report.errors.length > 0) {
89
+ lines.push('', s.problem(`${report.errors.length} problem${report.errors.length === 1 ? '' : 's'}:`));
90
+ for (const error of report.errors) {
91
+ lines.push(` ${s.path(error.file)} ${s.muted('—')} ${s.error(error.message)}`);
92
+ }
93
+ }
94
+ return lines.join('\n');
95
+ }
96
+ //# sourceMappingURL=report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../../../src/commands/image-hash/report.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ import { type Components, type HashEntry, type HashType, type OutputFormat } from './core.js';
2
+ import { type SharpFactory } from './sharp-loader.js';
3
+ export interface ImageHashProgress {
4
+ done: number;
5
+ total: number;
6
+ cached: number;
7
+ }
8
+ export interface ImageHashRunOptions {
9
+ paths: string[];
10
+ cwd: string;
11
+ types: HashType[];
12
+ recursive?: boolean;
13
+ extensions?: string[];
14
+ ignoreGlobs?: string[];
15
+ respectGitignore?: boolean;
16
+ components?: Components;
17
+ budget?: number;
18
+ size?: number;
19
+ maxPixels?: number;
20
+ format?: OutputFormat;
21
+ exportName?: string;
22
+ out?: string;
23
+ perFile?: boolean;
24
+ outDir?: string;
25
+ suffix?: string;
26
+ outExtension?: string;
27
+ keyBase?: string;
28
+ keyPrefix?: string;
29
+ cache?: string;
30
+ update?: boolean;
31
+ prune?: boolean;
32
+ check?: boolean;
33
+ concurrency?: number;
34
+ assumeYes?: boolean;
35
+ dryRun?: boolean;
36
+ sharp?: SharpFactory;
37
+ onProgress?: (progress: ImageHashProgress) => void;
38
+ }
39
+ export interface ImageHashError {
40
+ file: string;
41
+ message: string;
42
+ }
43
+ export interface OutdatedOutput {
44
+ file: string;
45
+ reason: 'missing' | 'changed';
46
+ }
47
+ export interface ImageHashReport {
48
+ filesScanned: number;
49
+ entries: HashEntry[];
50
+ written: string[];
51
+ errors: ImageHashError[];
52
+ stdout: string | null;
53
+ dryRun: boolean;
54
+ check: boolean;
55
+ checked: number;
56
+ outdated: OutdatedOutput[];
57
+ cached: number;
58
+ pruned: number;
59
+ exitCode: number;
60
+ }
61
+ export declare function runImageHash(options: ImageHashRunOptions): Promise<ImageHashReport>;