@fuzdev/fuz_util 0.42.0 → 0.43.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 (46) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +19 -12
  3. package/dist/async.d.ts +2 -2
  4. package/dist/async.d.ts.map +1 -1
  5. package/dist/async.js +2 -2
  6. package/dist/benchmark.d.ts +179 -0
  7. package/dist/benchmark.d.ts.map +1 -0
  8. package/dist/benchmark.js +400 -0
  9. package/dist/benchmark_baseline.d.ts +195 -0
  10. package/dist/benchmark_baseline.d.ts.map +1 -0
  11. package/dist/benchmark_baseline.js +415 -0
  12. package/dist/benchmark_format.d.ts +92 -0
  13. package/dist/benchmark_format.d.ts.map +1 -0
  14. package/dist/benchmark_format.js +327 -0
  15. package/dist/benchmark_stats.d.ts +112 -0
  16. package/dist/benchmark_stats.d.ts.map +1 -0
  17. package/dist/benchmark_stats.js +336 -0
  18. package/dist/benchmark_types.d.ts +174 -0
  19. package/dist/benchmark_types.d.ts.map +1 -0
  20. package/dist/benchmark_types.js +1 -0
  21. package/dist/library_json.d.ts +3 -3
  22. package/dist/library_json.d.ts.map +1 -1
  23. package/dist/library_json.js +1 -1
  24. package/dist/object.js +1 -1
  25. package/dist/stats.d.ts +126 -0
  26. package/dist/stats.d.ts.map +1 -0
  27. package/dist/stats.js +262 -0
  28. package/dist/time.d.ts +161 -0
  29. package/dist/time.d.ts.map +1 -0
  30. package/dist/time.js +260 -0
  31. package/dist/timings.d.ts +1 -7
  32. package/dist/timings.d.ts.map +1 -1
  33. package/dist/timings.js +16 -16
  34. package/package.json +21 -19
  35. package/src/lib/async.ts +3 -3
  36. package/src/lib/benchmark.ts +498 -0
  37. package/src/lib/benchmark_baseline.ts +573 -0
  38. package/src/lib/benchmark_format.ts +379 -0
  39. package/src/lib/benchmark_stats.ts +448 -0
  40. package/src/lib/benchmark_types.ts +197 -0
  41. package/src/lib/library_json.ts +3 -3
  42. package/src/lib/object.ts +1 -1
  43. package/src/lib/stats.ts +353 -0
  44. package/src/lib/time.ts +314 -0
  45. package/src/lib/timings.ts +17 -17
  46. package/src/lib/types.ts +2 -2
@@ -0,0 +1,327 @@
1
+ import { time_unit_detect_best, time_format } from './time.js';
2
+ /**
3
+ * Calculate the display width of a string in terminal columns.
4
+ * Emojis and other wide characters take 2 columns.
5
+ */
6
+ const string_display_width = (str) => {
7
+ let width = 0;
8
+ for (const char of str) {
9
+ const code = char.codePointAt(0);
10
+ // Emoji and other wide characters (rough heuristic)
11
+ // - Most emoji are in range 0x1F300-0x1FAFF
12
+ // - Some are in 0x2600-0x27BF (misc symbols)
13
+ // - CJK characters 0x4E00-0x9FFF also double-width but not handling here
14
+ if ((code >= 0x1f300 && code <= 0x1faff) ||
15
+ (code >= 0x2600 && code <= 0x27bf) ||
16
+ (code >= 0x1f600 && code <= 0x1f64f) ||
17
+ (code >= 0x1f680 && code <= 0x1f6ff)) {
18
+ width += 2;
19
+ }
20
+ else {
21
+ width += 1;
22
+ }
23
+ }
24
+ return width;
25
+ };
26
+ /**
27
+ * Pad a string to a target display width (accounting for wide characters).
28
+ */
29
+ const pad_to_width = (str, target_width, align = 'left') => {
30
+ const current_width = string_display_width(str);
31
+ const padding = Math.max(0, target_width - current_width);
32
+ if (align === 'left') {
33
+ return str + ' '.repeat(padding);
34
+ }
35
+ else {
36
+ return ' '.repeat(padding) + str;
37
+ }
38
+ };
39
+ /**
40
+ * Format results as an ASCII table with percentiles, min/max, and relative performance.
41
+ * All times use the same unit for easy comparison.
42
+ * @param results - Array of benchmark results
43
+ * @returns Formatted table string with enhanced metrics
44
+ *
45
+ * @example
46
+ * ```ts
47
+ * console.log(benchmark_format_table(results));
48
+ * // ┌────┬─────────────┬────────────┬────────────┬──────────┬──────────┬──────────┬──────────┬──────────┬──────────┬──────────┐
49
+ * // │ │ Task Name │ ops/sec │ median(μs) │ p75 (μs) │ p90 (μs) │ p95 (μs) │ p99 (μs) │ min (μs) │ max (μs) │ vs Best │
50
+ * // ├────┼─────────────┼────────────┼────────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┤
51
+ * // │ 🐇 │ slugify v2 │ 1,237,144 │ 0.81 │ 0.85 │ 0.89 │ 0.95 │ 1.20 │ 0.72 │ 2.45 │ baseline │
52
+ * // │ 🐢 │ slugify │ 261,619 │ 3.82 │ 3.95 │ 4.12 │ 4.35 │ 5.10 │ 3.21 │ 12.45 │ 4.73x │
53
+ * // └────┴─────────────┴────────────┴────────────┴──────────┴──────────┴──────────┴──────────┴──────────┴──────────┴──────────┘
54
+ * ```
55
+ *
56
+ * **Performance tier animals:**
57
+ * - 🐆 Cheetah: >1M ops/sec (extremely fast)
58
+ * - 🐇 Rabbit: >100K ops/sec (fast)
59
+ * - 🐢 Turtle: >10K ops/sec (moderate)
60
+ * - 🐌 Snail: <10K ops/sec (slow)
61
+ */
62
+ export const benchmark_format_table = (results) => {
63
+ if (results.length === 0)
64
+ return '(no results)';
65
+ // Detect best unit for all results
66
+ const mean_times = results.map((r) => r.stats.mean_ns);
67
+ const unit = time_unit_detect_best(mean_times);
68
+ const unit_str = UNIT_LABELS[unit];
69
+ // Find fastest for relative comparison
70
+ const fastest_ops = Math.max(...results.map((r) => r.stats.ops_per_second));
71
+ const rows = [];
72
+ // Header with unit
73
+ rows.push([
74
+ '',
75
+ 'Task Name',
76
+ 'ops/sec',
77
+ `median (${unit_str})`,
78
+ `p75 (${unit_str})`,
79
+ `p90 (${unit_str})`,
80
+ `p95 (${unit_str})`,
81
+ `p99 (${unit_str})`,
82
+ `min (${unit_str})`,
83
+ `max (${unit_str})`,
84
+ 'vs Best',
85
+ ]);
86
+ // Data rows - all use same unit
87
+ results.forEach((r) => {
88
+ const tier = get_perf_tier(r.stats.ops_per_second);
89
+ const ops_sec = benchmark_format_number(r.stats.ops_per_second, 2);
90
+ const median = time_format(r.stats.median_ns, unit, 2).replace(unit_str, '').trim();
91
+ const p75 = time_format(r.stats.p75_ns, unit, 2).replace(unit_str, '').trim();
92
+ const p90 = time_format(r.stats.p90_ns, unit, 2).replace(unit_str, '').trim();
93
+ const p95 = time_format(r.stats.p95_ns, unit, 2).replace(unit_str, '').trim();
94
+ const p99 = time_format(r.stats.p99_ns, unit, 2).replace(unit_str, '').trim();
95
+ const min = time_format(r.stats.min_ns, unit, 2).replace(unit_str, '').trim();
96
+ const max = time_format(r.stats.max_ns, unit, 2).replace(unit_str, '').trim();
97
+ // Calculate relative performance
98
+ const ratio = fastest_ops / r.stats.ops_per_second;
99
+ const vs_best = ratio === 1.0 ? 'baseline' : `${ratio.toFixed(2)}x`;
100
+ rows.push([tier, r.name, ops_sec, median, p75, p90, p95, p99, min, max, vs_best]);
101
+ });
102
+ // Calculate column widths (using display width for proper emoji handling)
103
+ const widths = rows[0].map((_, col_i) => {
104
+ return Math.max(...rows.map((row) => string_display_width(row[col_i])));
105
+ });
106
+ // Build table
107
+ const lines = [];
108
+ // Top border
109
+ lines.push('┌' + widths.map((w) => '─'.repeat(w + 2)).join('┬') + '┐');
110
+ // Header
111
+ const header = rows[0].map((cell, i) => ' ' + pad_to_width(cell, widths[i]) + ' ').join('│');
112
+ lines.push('│' + header + '│');
113
+ // Header separator
114
+ lines.push('├' + widths.map((w) => '─'.repeat(w + 2)).join('┼') + '┤');
115
+ // Data rows
116
+ for (let i = 1; i < rows.length; i++) {
117
+ const row = rows[i].map((cell, col_i) => {
118
+ const width = widths[col_i];
119
+ // Left-align tier emoji and task name, right-align numbers
120
+ if (col_i === 0 || col_i === 1) {
121
+ return ' ' + pad_to_width(cell, width, 'left') + ' ';
122
+ }
123
+ else {
124
+ return ' ' + pad_to_width(cell, width, 'right') + ' ';
125
+ }
126
+ }).join('│');
127
+ lines.push('│' + row + '│');
128
+ }
129
+ // Bottom border
130
+ lines.push('└' + widths.map((w) => '─'.repeat(w + 2)).join('┴') + '┘');
131
+ return lines.join('\n');
132
+ };
133
+ /**
134
+ * Format results as a Markdown table with key metrics.
135
+ * All times use the same unit for easy comparison.
136
+ * @param results - Array of benchmark results
137
+ * @returns Formatted markdown table string
138
+ *
139
+ * @example
140
+ * ```ts
141
+ * console.log(benchmark_format_markdown(results));
142
+ * // | Task Name | ops/sec | median (μs) | p75 (μs) | p90 (μs) | p95 (μs) | p99 (μs) | min (μs) | max (μs) | vs Best |
143
+ * // |------------|------------|-------------|----------|----------|----------|----------|----------|----------|----------|
144
+ * // | slugify v2 | 1,237,144 | 0.81 | 0.85 | 0.89 | 0.95 | 1.20 | 0.72 | 2.45 | baseline |
145
+ * // | slugify | 261,619 | 3.82 | 3.95 | 4.12 | 4.35 | 5.10 | 3.21 | 12.45 | 4.73x |
146
+ * ```
147
+ */
148
+ export const benchmark_format_markdown = (results) => {
149
+ if (results.length === 0)
150
+ return '(no results)';
151
+ // Detect best unit for all results
152
+ const mean_times = results.map((r) => r.stats.mean_ns);
153
+ const unit = time_unit_detect_best(mean_times);
154
+ const unit_str = UNIT_LABELS[unit];
155
+ // Find fastest for relative comparison
156
+ const fastest_ops = Math.max(...results.map((r) => r.stats.ops_per_second));
157
+ const rows = [];
158
+ // Header with unit
159
+ rows.push([
160
+ 'Task Name',
161
+ 'ops/sec',
162
+ `median (${unit_str})`,
163
+ `p75 (${unit_str})`,
164
+ `p90 (${unit_str})`,
165
+ `p95 (${unit_str})`,
166
+ `p99 (${unit_str})`,
167
+ `min (${unit_str})`,
168
+ `max (${unit_str})`,
169
+ 'vs Best',
170
+ ]);
171
+ // Data rows - all use same unit
172
+ results.forEach((r) => {
173
+ const ops_sec = benchmark_format_number(r.stats.ops_per_second, 2);
174
+ const median = time_format(r.stats.median_ns, unit, 2).replace(unit_str, '').trim();
175
+ const p75 = time_format(r.stats.p75_ns, unit, 2).replace(unit_str, '').trim();
176
+ const p90 = time_format(r.stats.p90_ns, unit, 2).replace(unit_str, '').trim();
177
+ const p95 = time_format(r.stats.p95_ns, unit, 2).replace(unit_str, '').trim();
178
+ const p99 = time_format(r.stats.p99_ns, unit, 2).replace(unit_str, '').trim();
179
+ const min = time_format(r.stats.min_ns, unit, 2).replace(unit_str, '').trim();
180
+ const max = time_format(r.stats.max_ns, unit, 2).replace(unit_str, '').trim();
181
+ // Calculate relative performance
182
+ const ratio = fastest_ops / r.stats.ops_per_second;
183
+ const vs_best = ratio === 1.0 ? 'baseline' : `${ratio.toFixed(2)}x`;
184
+ rows.push([r.name, ops_sec, median, p75, p90, p95, p99, min, max, vs_best]);
185
+ });
186
+ // Calculate column widths
187
+ const widths = rows[0].map((_, col_i) => {
188
+ return Math.max(...rows.map((row) => row[col_i].length));
189
+ });
190
+ // Build table
191
+ const lines = [];
192
+ // Header
193
+ const header = rows[0].map((cell, i) => cell.padEnd(widths[i])).join(' | ');
194
+ lines.push('| ' + header + ' |');
195
+ // Separator
196
+ const separator = widths.map((w) => '-'.repeat(w)).join(' | ');
197
+ lines.push('| ' + separator + ' |');
198
+ // Data rows
199
+ for (let i = 1; i < rows.length; i++) {
200
+ const row = rows[i].map((cell, col_i) => {
201
+ const width = widths[col_i];
202
+ // Right-align numbers, left-align names
203
+ if (col_i === 0) {
204
+ return cell.padEnd(width);
205
+ }
206
+ else {
207
+ return cell.padStart(width);
208
+ }
209
+ }).join(' | ');
210
+ lines.push('| ' + row + ' |');
211
+ }
212
+ return lines.join('\n');
213
+ };
214
+ /**
215
+ * Format results as JSON.
216
+ * @param results - Array of benchmark results
217
+ * @param options - Formatting options
218
+ * @returns JSON string
219
+ *
220
+ * @example
221
+ * ```ts
222
+ * console.log(format_json(results));
223
+ * console.log(format_json(results, {pretty: false}));
224
+ * console.log(format_json(results, {include_timings: true}));
225
+ * ```
226
+ */
227
+ export const benchmark_format_json = (results, options) => {
228
+ const pretty = options?.pretty ?? true;
229
+ const include_timings = options?.include_timings ?? false;
230
+ // Flatten stats into result object for easier consumption
231
+ const flattened = results.map((r) => ({
232
+ name: r.name,
233
+ iterations: r.iterations,
234
+ total_time_ms: r.total_time_ms,
235
+ ops_per_second: r.stats.ops_per_second,
236
+ mean_ns: r.stats.mean_ns,
237
+ median_ns: r.stats.median_ns,
238
+ std_dev_ns: r.stats.std_dev_ns,
239
+ min_ns: r.stats.min_ns,
240
+ max_ns: r.stats.max_ns,
241
+ p75_ns: r.stats.p75_ns,
242
+ p90_ns: r.stats.p90_ns,
243
+ p95_ns: r.stats.p95_ns,
244
+ p99_ns: r.stats.p99_ns,
245
+ cv: r.stats.cv,
246
+ confidence_interval_ns: r.stats.confidence_interval_ns,
247
+ outliers: r.stats.outliers_ns.length,
248
+ outlier_ratio: r.stats.outlier_ratio,
249
+ sample_size: r.stats.sample_size,
250
+ raw_sample_size: r.stats.raw_sample_size,
251
+ failed_iterations: r.stats.failed_iterations,
252
+ ...(include_timings ? { timings_ns: r.timings_ns } : {}),
253
+ }));
254
+ return pretty ? JSON.stringify(flattened, null, 2) : JSON.stringify(flattened);
255
+ };
256
+ /**
257
+ * Format results as a grouped table with visual separators between groups.
258
+ * @param results - Array of benchmark results
259
+ * @param groups - Array of group definitions
260
+ * @returns Formatted table string with group separators
261
+ *
262
+ * @example
263
+ * ```ts
264
+ * const groups = [
265
+ * { name: 'FAST PATHS', filter: (r) => r.name.includes('fast') },
266
+ * { name: 'SLOW PATHS', filter: (r) => r.name.includes('slow') },
267
+ * ];
268
+ * console.log(benchmark_format_table_grouped(results, groups));
269
+ * // 📦 FAST PATHS
270
+ * // ┌────┬─────────────┬────────────┬...┐
271
+ * // │ 🐆 │ fast test 1 │ 1,237,144 │...│
272
+ * // │ 🐇 │ fast test 2 │ 261,619 │...│
273
+ * // └────┴─────────────┴────────────┴...┘
274
+ * //
275
+ * // 📦 SLOW PATHS
276
+ * // ┌────┬─────────────┬────────────┬...┐
277
+ * // │ 🐢 │ slow test 1 │ 10,123 │...│
278
+ * // └────┴─────────────┴────────────┴...┘
279
+ * ```
280
+ */
281
+ export const benchmark_format_table_grouped = (results, groups) => {
282
+ if (results.length === 0)
283
+ return '(no results)';
284
+ const sections = [];
285
+ for (const group of groups) {
286
+ const group_results = results.filter(group.filter);
287
+ if (group_results.length === 0)
288
+ continue;
289
+ // Add group header and table
290
+ const header = group.description
291
+ ? `\n📦 ${group.name}\n ${group.description}`
292
+ : `\n📦 ${group.name}`;
293
+ sections.push(header);
294
+ sections.push(benchmark_format_table(group_results));
295
+ }
296
+ // Handle ungrouped results (those that don't match any group)
297
+ const grouped_names = new Set(groups.flatMap((g) => results.filter(g.filter).map((r) => r.name)));
298
+ const ungrouped = results.filter((r) => !grouped_names.has(r.name));
299
+ if (ungrouped.length > 0) {
300
+ sections.push('\n📦 Other');
301
+ sections.push(benchmark_format_table(ungrouped));
302
+ }
303
+ return sections.join('\n');
304
+ };
305
+ // TODO consider extracting to a general format utility module when more formatters are needed
306
+ /**
307
+ * Format a number with fixed decimal places and thousands separators.
308
+ */
309
+ export const benchmark_format_number = (n, decimals = 2) => {
310
+ if (!isFinite(n))
311
+ return String(n);
312
+ return n.toFixed(decimals).replace(/\B(?=(\d{3})+(?!\d))/g, ',');
313
+ };
314
+ /**
315
+ * Get performance tier symbol based on ops/sec.
316
+ */
317
+ const get_perf_tier = (ops_per_sec) => {
318
+ if (ops_per_sec >= 1_000_000)
319
+ return '🐆'; // > 1M ops/sec (cheetah - extremely fast)
320
+ if (ops_per_sec >= 100_000)
321
+ return '🐇'; // > 100K ops/sec (rabbit - fast)
322
+ if (ops_per_sec >= 10_000)
323
+ return '🐢'; // > 10K ops/sec (turtle - moderate)
324
+ return '🐌'; // < 10K ops/sec (snail - slow)
325
+ };
326
+ /** Unit labels for display (μs instead of us). */
327
+ const UNIT_LABELS = { ns: 'ns', us: 'μs', ms: 'ms', s: 's' };
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Benchmark-specific statistical analysis.
3
+ * Uses the general stats utilities from stats.ts for timing/performance analysis.
4
+ * All timing values are in nanoseconds.
5
+ */
6
+ /**
7
+ * Minimal stats interface for comparison.
8
+ * This allows comparing stats from different sources (e.g., loaded baselines).
9
+ */
10
+ export interface BenchmarkStatsComparable {
11
+ mean_ns: number;
12
+ std_dev_ns: number;
13
+ sample_size: number;
14
+ confidence_interval_ns: [number, number];
15
+ }
16
+ /**
17
+ * Effect size magnitude interpretation (Cohen's d).
18
+ */
19
+ export type EffectMagnitude = 'negligible' | 'small' | 'medium' | 'large';
20
+ /**
21
+ * Result from comparing two benchmark stats.
22
+ */
23
+ export interface BenchmarkComparison {
24
+ /** Which benchmark is faster ('a', 'b', or 'equal' if difference is negligible) */
25
+ faster: 'a' | 'b' | 'equal';
26
+ /** How much faster the winner is (e.g., 1.5 means 1.5x faster) */
27
+ speedup_ratio: number;
28
+ /** Whether the difference is statistically significant at the given alpha */
29
+ significant: boolean;
30
+ /** P-value from Welch's t-test (lower = more confident the difference is real) */
31
+ p_value: number;
32
+ /** Cohen's d effect size (magnitude of difference independent of sample size) */
33
+ effect_size: number;
34
+ /** Interpretation of effect size */
35
+ effect_magnitude: EffectMagnitude;
36
+ /** Whether the 95% confidence intervals overlap */
37
+ ci_overlap: boolean;
38
+ /** Human-readable interpretation of the comparison */
39
+ recommendation: string;
40
+ }
41
+ /**
42
+ * Options for benchmark comparison.
43
+ */
44
+ export interface BenchmarkCompareOptions {
45
+ /** Significance level for hypothesis testing (default: 0.05) */
46
+ alpha?: number;
47
+ }
48
+ /**
49
+ * Complete statistical analysis of timing measurements.
50
+ * Includes outlier detection, descriptive statistics, and performance metrics.
51
+ * All timing values are in nanoseconds.
52
+ */
53
+ export declare class BenchmarkStats {
54
+ /** Mean (average) time in nanoseconds */
55
+ readonly mean_ns: number;
56
+ /** Median time in nanoseconds */
57
+ readonly median_ns: number;
58
+ /** Standard deviation in nanoseconds */
59
+ readonly std_dev_ns: number;
60
+ /** Minimum time in nanoseconds */
61
+ readonly min_ns: number;
62
+ /** Maximum time in nanoseconds */
63
+ readonly max_ns: number;
64
+ /** 75th percentile in nanoseconds */
65
+ readonly p75_ns: number;
66
+ /** 90th percentile in nanoseconds */
67
+ readonly p90_ns: number;
68
+ /** 95th percentile in nanoseconds */
69
+ readonly p95_ns: number;
70
+ /** 99th percentile in nanoseconds */
71
+ readonly p99_ns: number;
72
+ /** Coefficient of variation (std_dev / mean) */
73
+ readonly cv: number;
74
+ /** 95% confidence interval for the mean in nanoseconds */
75
+ readonly confidence_interval_ns: [number, number];
76
+ /** Array of detected outlier values in nanoseconds */
77
+ readonly outliers_ns: Array<number>;
78
+ /** Ratio of outliers to total samples */
79
+ readonly outlier_ratio: number;
80
+ /** Number of samples after outlier removal */
81
+ readonly sample_size: number;
82
+ /** Original number of samples (before outlier removal) */
83
+ readonly raw_sample_size: number;
84
+ /** Operations per second (NS_PER_SEC / mean_ns) */
85
+ readonly ops_per_second: number;
86
+ /** Number of failed iterations (NaN, Infinity, or negative values) */
87
+ readonly failed_iterations: number;
88
+ constructor(timings_ns: Array<number>);
89
+ /**
90
+ * Format stats as a human-readable string.
91
+ */
92
+ toString(): string;
93
+ }
94
+ /**
95
+ * Compare two benchmark results for statistical significance.
96
+ * Uses Welch's t-test (handles unequal variances) and Cohen's d effect size.
97
+ *
98
+ * @param a - First benchmark stats (or any object with required properties)
99
+ * @param b - Second benchmark stats (or any object with required properties)
100
+ * @param options - Comparison options
101
+ * @returns Comparison result with significance, effect size, and recommendation
102
+ *
103
+ * @example
104
+ * ```ts
105
+ * const comparison = benchmark_stats_compare(result_a.stats, result_b.stats);
106
+ * if (comparison.significant) {
107
+ * console.log(`${comparison.faster} is ${comparison.speedup_ratio.toFixed(2)}x faster`);
108
+ * }
109
+ * ```
110
+ */
111
+ export declare const benchmark_stats_compare: (a: BenchmarkStatsComparable, b: BenchmarkStatsComparable, options?: BenchmarkCompareOptions) => BenchmarkComparison;
112
+ //# sourceMappingURL=benchmark_stats.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"benchmark_stats.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/benchmark_stats.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAcH;;;GAGG;AACH,MAAM,WAAW,wBAAwB;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,sBAAsB,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACzC;AAED;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,YAAY,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE1E;;GAEG;AACH,MAAM,WAAW,mBAAmB;IACnC,mFAAmF;IACnF,MAAM,EAAE,GAAG,GAAG,GAAG,GAAG,OAAO,CAAC;IAC5B,kEAAkE;IAClE,aAAa,EAAE,MAAM,CAAC;IACtB,6EAA6E;IAC7E,WAAW,EAAE,OAAO,CAAC;IACrB,kFAAkF;IAClF,OAAO,EAAE,MAAM,CAAC;IAChB,iFAAiF;IACjF,WAAW,EAAE,MAAM,CAAC;IACpB,oCAAoC;IACpC,gBAAgB,EAAE,eAAe,CAAC;IAClC,mDAAmD;IACnD,UAAU,EAAE,OAAO,CAAC;IACpB,sDAAsD;IACtD,cAAc,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACvC,gEAAgE;IAChE,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;GAIG;AACH,qBAAa,cAAc;IAC1B,yCAAyC;IACzC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,iCAAiC;IACjC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,wCAAwC;IACxC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,kCAAkC;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,kCAAkC;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,qCAAqC;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,qCAAqC;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,qCAAqC;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,qCAAqC;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,gDAAgD;IAChD,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,0DAA0D;IAC1D,QAAQ,CAAC,sBAAsB,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClD,sDAAsD;IACtD,QAAQ,CAAC,WAAW,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACpC,yCAAyC;IACzC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,8CAA8C;IAC9C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,0DAA0D;IAC1D,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,mDAAmD;IACnD,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,sEAAsE;IACtE,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;gBAEvB,UAAU,EAAE,KAAK,CAAC,MAAM,CAAC;IAiErC;;OAEG;IACH,QAAQ,IAAI,MAAM;CAGlB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,uBAAuB,GACnC,GAAG,wBAAwB,EAC3B,GAAG,wBAAwB,EAC3B,UAAU,uBAAuB,KAC/B,mBA6GF,CAAC"}