@typeonce/ritmo-tools 0.17.0 → 0.19.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 (131) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/README.md +304 -24
  3. package/dist/cli.js +5 -1
  4. package/dist/cli.js.map +1 -1
  5. package/dist/internal/version.d.ts +1 -1
  6. package/dist/internal/version.js +1 -1
  7. package/dist/music/cli/commands.d.ts +15 -0
  8. package/dist/music/cli/commands.d.ts.map +1 -0
  9. package/dist/music/cli/commands.js +180 -0
  10. package/dist/music/cli/commands.js.map +1 -0
  11. package/dist/music/cli/io.d.ts +11 -0
  12. package/dist/music/cli/io.d.ts.map +1 -0
  13. package/dist/music/cli/io.js +28 -0
  14. package/dist/music/cli/io.js.map +1 -0
  15. package/dist/music/cli/serve.d.ts +13 -0
  16. package/dist/music/cli/serve.d.ts.map +1 -0
  17. package/dist/music/cli/serve.js +168 -0
  18. package/dist/music/cli/serve.js.map +1 -0
  19. package/dist/music/core/audio.d.ts +22 -0
  20. package/dist/music/core/audio.d.ts.map +1 -0
  21. package/dist/music/core/audio.js +95 -0
  22. package/dist/music/core/audio.js.map +1 -0
  23. package/dist/music/core/check.d.ts +51 -0
  24. package/dist/music/core/check.d.ts.map +1 -0
  25. package/dist/music/core/check.js +113 -0
  26. package/dist/music/core/check.js.map +1 -0
  27. package/dist/music/core/instruments.d.ts +179 -0
  28. package/dist/music/core/instruments.d.ts.map +1 -0
  29. package/dist/music/core/instruments.js +531 -0
  30. package/dist/music/core/instruments.js.map +1 -0
  31. package/dist/music/core/listen.d.ts +32 -0
  32. package/dist/music/core/listen.d.ts.map +1 -0
  33. package/dist/music/core/listen.js +350 -0
  34. package/dist/music/core/listen.js.map +1 -0
  35. package/dist/music/core/midi.d.ts +4 -0
  36. package/dist/music/core/midi.d.ts.map +1 -0
  37. package/dist/music/core/midi.js +76 -0
  38. package/dist/music/core/midi.js.map +1 -0
  39. package/dist/music/core/render.d.ts +37 -0
  40. package/dist/music/core/render.d.ts.map +1 -0
  41. package/dist/music/core/render.js +204 -0
  42. package/dist/music/core/render.js.map +1 -0
  43. package/dist/music/core/review.d.ts +41 -0
  44. package/dist/music/core/review.d.ts.map +1 -0
  45. package/dist/music/core/review.js +139 -0
  46. package/dist/music/core/review.js.map +1 -0
  47. package/dist/music/core/song.d.ts +144 -0
  48. package/dist/music/core/song.d.ts.map +1 -0
  49. package/dist/music/core/song.js +291 -0
  50. package/dist/music/core/song.js.map +1 -0
  51. package/dist/music/page/assets/index-BfO_jOqP.js +4 -0
  52. package/dist/music/page/assets/index-Dw14kxkL.css +1 -0
  53. package/dist/music/page/index.html +19 -0
  54. package/dist/pixel/cli/commands.d.ts.map +1 -1
  55. package/dist/pixel/cli/commands.js +122 -46
  56. package/dist/pixel/cli/commands.js.map +1 -1
  57. package/dist/pixel/cli/io.d.ts +5 -1
  58. package/dist/pixel/cli/io.d.ts.map +1 -1
  59. package/dist/pixel/cli/io.js +16 -1
  60. package/dist/pixel/cli/io.js.map +1 -1
  61. package/dist/pixel/core/animation.d.ts +23 -8
  62. package/dist/pixel/core/animation.d.ts.map +1 -1
  63. package/dist/pixel/core/animation.js +41 -18
  64. package/dist/pixel/core/animation.js.map +1 -1
  65. package/dist/pixel/core/grid.d.ts +3 -2
  66. package/dist/pixel/core/grid.d.ts.map +1 -1
  67. package/dist/pixel/core/grid.js +14 -6
  68. package/dist/pixel/core/grid.js.map +1 -1
  69. package/dist/pixel/core/preview.d.ts +8 -3
  70. package/dist/pixel/core/preview.d.ts.map +1 -1
  71. package/dist/pixel/core/preview.js +39 -25
  72. package/dist/pixel/core/preview.js.map +1 -1
  73. package/dist/pixel/core/project.d.ts +27 -0
  74. package/dist/pixel/core/project.d.ts.map +1 -0
  75. package/dist/pixel/core/project.js +117 -0
  76. package/dist/pixel/core/project.js.map +1 -0
  77. package/dist/pixel/core/recipe.d.ts.map +1 -1
  78. package/dist/pixel/core/recipe.js +43 -6
  79. package/dist/pixel/core/recipe.js.map +1 -1
  80. package/dist/pixel/core/report.d.ts +21 -3
  81. package/dist/pixel/core/report.d.ts.map +1 -1
  82. package/dist/pixel/core/report.js +52 -22
  83. package/dist/pixel/core/report.js.map +1 -1
  84. package/dist/pixel/core/sheet.d.ts +68 -8
  85. package/dist/pixel/core/sheet.d.ts.map +1 -1
  86. package/dist/pixel/core/sheet.js +250 -32
  87. package/dist/pixel/core/sheet.js.map +1 -1
  88. package/dist/pixel/core/spritesheet.d.ts +43 -35
  89. package/dist/pixel/core/spritesheet.d.ts.map +1 -1
  90. package/dist/pixel/core/spritesheet.js +63 -59
  91. package/dist/pixel/core/spritesheet.js.map +1 -1
  92. package/dist/sound/cli/commands.d.ts +25 -0
  93. package/dist/sound/cli/commands.d.ts.map +1 -0
  94. package/dist/sound/cli/commands.js +137 -0
  95. package/dist/sound/cli/commands.js.map +1 -0
  96. package/dist/sound/cli/io.d.ts +24 -0
  97. package/dist/sound/cli/io.d.ts.map +1 -0
  98. package/dist/sound/cli/io.js +51 -0
  99. package/dist/sound/cli/io.js.map +1 -0
  100. package/dist/sound/cli/serve.d.ts +11 -0
  101. package/dist/sound/cli/serve.d.ts.map +1 -0
  102. package/dist/sound/cli/serve.js +147 -0
  103. package/dist/sound/cli/serve.js.map +1 -0
  104. package/dist/sound/core/measure.d.ts +67 -0
  105. package/dist/sound/core/measure.d.ts.map +1 -0
  106. package/dist/sound/core/measure.js +138 -0
  107. package/dist/sound/core/measure.js.map +1 -0
  108. package/dist/sound/core/recipe.d.ts +143 -0
  109. package/dist/sound/core/recipe.d.ts.map +1 -0
  110. package/dist/sound/core/recipe.js +292 -0
  111. package/dist/sound/core/recipe.js.map +1 -0
  112. package/dist/sound/core/render.d.ts +37 -0
  113. package/dist/sound/core/render.d.ts.map +1 -0
  114. package/dist/sound/core/render.js +317 -0
  115. package/dist/sound/core/render.js.map +1 -0
  116. package/dist/sound/core/review.d.ts +52 -0
  117. package/dist/sound/core/review.d.ts.map +1 -0
  118. package/dist/sound/core/review.js +89 -0
  119. package/dist/sound/core/review.js.map +1 -0
  120. package/dist/sound/core/takes.d.ts +29 -0
  121. package/dist/sound/core/takes.d.ts.map +1 -0
  122. package/dist/sound/core/takes.js +109 -0
  123. package/dist/sound/core/takes.js.map +1 -0
  124. package/dist/sound/core/wav.d.ts +4 -0
  125. package/dist/sound/core/wav.d.ts.map +1 -0
  126. package/dist/sound/core/wav.js +28 -0
  127. package/dist/sound/core/wav.js.map +1 -0
  128. package/dist/sound/page/assets/index-Cjun5b92.js +6 -0
  129. package/dist/sound/page/assets/index-DZm59wkQ.css +1 -0
  130. package/dist/sound/page/index.html +19 -0
  131. package/package.json +10 -4
@@ -0,0 +1,138 @@
1
+ import { fft, render } from "./render.js";
2
+ const db = (amplitude) => (amplitude <= 1e-9 ? -180 : 20 * Math.log10(amplitude));
3
+ const round = (value, digits = 1) => Math.round(value * 10 ** digits) / 10 ** digits;
4
+ export const measure = ({ samples, sampleRate }) => {
5
+ let peak = 0;
6
+ for (const x of samples)
7
+ peak = Math.max(peak, Math.abs(x));
8
+ let last = 0;
9
+ const quiet = 0.001;
10
+ for (let i = samples.length - 1; i >= 0; i--) {
11
+ if (Math.abs(samples[i]) >= quiet) {
12
+ last = i + 1;
13
+ break;
14
+ }
15
+ }
16
+ let first = 0;
17
+ while (first < samples.length && Math.abs(samples[first]) < peak * 0.1)
18
+ first++;
19
+ // The loudest 50 ms, in steps of 5 ms.
20
+ const window = Math.round(sampleRate * 0.05);
21
+ const hop = Math.round(sampleRate * 0.005);
22
+ let loudest = 0;
23
+ let loudestAt = 0;
24
+ for (let start = 0; start < Math.max(1, samples.length - window + 1); start += hop) {
25
+ let sum = 0;
26
+ const end = Math.min(samples.length, start + window);
27
+ for (let i = start; i < end; i++)
28
+ sum += samples[i] * samples[i];
29
+ const rms = Math.sqrt(sum / window);
30
+ if (rms > loudest) {
31
+ loudest = rms;
32
+ loudestAt = start;
33
+ }
34
+ }
35
+ const tail = Math.round(sampleRate * 0.001);
36
+ let ending = 0;
37
+ for (let i = Math.max(0, last - tail); i < last; i++)
38
+ ending = Math.max(ending, Math.abs(samples[i]));
39
+ return {
40
+ duration: round(last / sampleRate, 3),
41
+ peak: round(db(peak)),
42
+ loudness: round(db(loudest)),
43
+ attack: round((first / sampleRate) * 1000),
44
+ brightness: Math.round(centroid(samples, sampleRate, loudestAt, window)),
45
+ ending: round(db(ending))
46
+ };
47
+ };
48
+ /** The spectral centroid of `size` samples from `start` (Hann windowed, zero-padded to a power of two). */
49
+ const centroid = (samples, sampleRate, start, size) => {
50
+ let n = 1;
51
+ while (n < size)
52
+ n <<= 1;
53
+ const re = new Float64Array(n);
54
+ const im = new Float64Array(n);
55
+ for (let i = 0; i < size && start + i < samples.length; i++)
56
+ re[i] = samples[start + i] * (0.5 - 0.5 * Math.cos((2 * Math.PI * i) / (size - 1)));
57
+ fft(re, im, false);
58
+ let weighted = 0;
59
+ let total = 0;
60
+ for (let k = 1; k < n / 2; k++) {
61
+ const magnitude = Math.hypot(re[k], im[k]);
62
+ weighted += magnitude * ((k * sampleRate) / n);
63
+ total += magnitude;
64
+ }
65
+ return total === 0 ? 0 : weighted / total;
66
+ };
67
+ /** Limits a sound is checked against. */
68
+ export const limits = {
69
+ /** A sound quieter than this at its peak is not heard in a game (dBFS). */
70
+ silent: -40,
71
+ /** Past full scale, samples are clipped: the sound distorts (dBFS). */
72
+ clipping: 0,
73
+ /** A game sound must answer an action at once: later than this (ms) feels late (a swing's whoosh builds for about 60). */
74
+ lateStart: 80,
75
+ /** Longer than this (s) is long for an effect. */
76
+ long: 3,
77
+ /** A last millisecond louder than this (dBFS) ends with a click. */
78
+ endClick: -40,
79
+ /** Louder or quieter than the middle of its kind (heavy or not) by this many dB stands out. */
80
+ louder: 10,
81
+ quieter: 14
82
+ };
83
+ /** The issues of one sound, given the middle loudness of its kind in the bank (the median of the heavy sounds, or of the others). */
84
+ export const issuesOf = (recipe, measures, middle) => {
85
+ const issues = [];
86
+ if (recipe.layers.length === 0)
87
+ return [{ rule: "empty", severity: "error", message: "No layers: the sound is silent." }];
88
+ if (measures.peak < limits.silent)
89
+ issues.push({ rule: "silent", severity: "error", message: `Peaks at ${measures.peak} dBFS: too quiet to be heard. Raise the layers' gain.` });
90
+ if (measures.peak > limits.clipping)
91
+ issues.push({ rule: "clipping", severity: "error", message: `Peaks at +${measures.peak} dBFS: it clips and distorts. Lower the gain (or the tune's volume) by ${Math.ceil(measures.peak + 1)} dB.` });
92
+ if (measures.attack > limits.lateStart)
93
+ issues.push({
94
+ rule: "late-start",
95
+ severity: "warning",
96
+ message: `Reaches a tenth of its peak after ${measures.attack} ms: it will feel late if it answers an action (fine for a swell). Shorten the first layer's attack, or start a layer at once.`
97
+ });
98
+ if (measures.duration > limits.long)
99
+ issues.push({ rule: "long", severity: "warning", message: `Lasts ${measures.duration} s, long for an effect.` });
100
+ if (measures.ending > limits.endClick)
101
+ issues.push({ rule: "end-click", severity: "warning", message: `Stops abruptly (${measures.ending} dBFS in its last millisecond): it ends with a click.` });
102
+ if (middle !== undefined && measures.loudness > middle + limits.louder)
103
+ issues.push({ rule: "too-loud", severity: "warning", message: `${round(measures.loudness - middle)} dB louder than the middle of its kind (${middle} dBFS${recipe.heavy === true ? ", heavy sounds" : ""}): it will stand out.` });
104
+ if (middle !== undefined && measures.loudness < middle - limits.quieter)
105
+ issues.push({ rule: "too-quiet", severity: "warning", message: `${round(middle - measures.loudness)} dB quieter than the middle of its kind (${middle} dBFS${recipe.heavy === true ? ", heavy sounds" : ""}): it may get lost.` });
106
+ return issues;
107
+ };
108
+ const median = (values) => {
109
+ if (values.length === 0)
110
+ return undefined;
111
+ const sorted = [...values].sort((a, b) => a - b);
112
+ const mid = Math.floor(sorted.length / 2);
113
+ return round(sorted.length % 2 === 1 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2);
114
+ };
115
+ /** Measures every sound (or the named ones) of a bank, each against the whole bank's middle loudness. */
116
+ export const checkBank = (bank, names) => {
117
+ const all = Object.entries(bank.sounds).map(([name, recipe]) => ({ name, recipe, measures: measure(render(recipe, { master: bank.master })) }));
118
+ const kind = (heavy) => all.filter((entry) => entry.recipe.layers.length > 0 && (entry.recipe.heavy === true) === heavy).map((entry) => entry.measures.loudness);
119
+ const heavy = kind(true);
120
+ const other = kind(false);
121
+ // A kind of fewer than three sounds has no middle to stand out from.
122
+ const middle = { heavy: heavy.length >= 3 ? median(heavy) : undefined, other: other.length >= 3 ? median(other) : undefined };
123
+ const chosen = names === undefined || names.length === 0 ? all : all.filter((entry) => names.includes(entry.name));
124
+ const sounds = chosen.map(({ name, recipe, measures }) => ({
125
+ name,
126
+ about: recipe.about,
127
+ ...measures,
128
+ issues: issuesOf(recipe, measures, recipe.heavy === true ? middle.heavy : middle.other)
129
+ }));
130
+ const errors = sounds.reduce((n, sound) => n + sound.issues.filter((issue) => issue.severity === "error").length, 0);
131
+ const warnings = sounds.reduce((n, sound) => n + sound.issues.filter((issue) => issue.severity === "warning").length, 0);
132
+ const verdict = errors > 0 ? "errors" : warnings > 0 ? "warnings" : "clean";
133
+ const summary = verdict === "clean"
134
+ ? `${sounds.length} sound${sounds.length === 1 ? "" : "s"}, nothing to fix.`
135
+ : `${sounds.length} sound${sounds.length === 1 ? "" : "s"}: ${errors} error${errors === 1 ? "" : "s"}, ${warnings} warning${warnings === 1 ? "" : "s"}.`;
136
+ return { verdict, summary, middle, sounds };
137
+ };
138
+ //# sourceMappingURL=measure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"measure.js","sourceRoot":"","sources":["../../../src/sound/core/measure.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Sound recipes: a game sound as plain JSON, a few layers built from small
3
+ * instruments, mixed into a room. The renderer (`render.ts`) turns a recipe
4
+ * into samples the same way in Node and in the browser, so what the page
5
+ * plays, what the CLI measures, and what the game plays are one sound.
6
+ *
7
+ * ```json
8
+ * {
9
+ * "reverb": 0.12,
10
+ * "layers": [
11
+ * { "type": "click", "gain": 0.45 },
12
+ * { "type": "tone", "wave": "sine", "from": 160, "to": 55, "duration": 0.12, "gain": 0.65, "attack": 0.002 },
13
+ * { "type": "crunch", "from": 1500, "to": 500, "duration": 0.07, "gain": 0.3 }
14
+ * ]
15
+ * }
16
+ * ```
17
+ *
18
+ * A bank is a file of named recipes (`{"version": 1, "master": 0.6,
19
+ * "sounds": {...}}`): the game's sounds, one file, and the master volume the
20
+ * game plays them at.
21
+ */
22
+ export type Wave = "sine" | "triangle" | "square" | "sawtooth";
23
+ export declare const waves: ReadonlyArray<Wave>;
24
+ export type Filter = "lowpass" | "highpass" | "bandpass";
25
+ export declare const filters: ReadonlyArray<Filter>;
26
+ /** Every layer starts `delay` seconds after the sound does, and fades in over `attack` seconds. */
27
+ interface Timed {
28
+ readonly delay: number;
29
+ readonly gain: number;
30
+ }
31
+ /** A tone gliding from `from` to `to` Hz over its duration, fading in and dying away: thuds, notes, hums. */
32
+ export interface ToneLayer extends Timed {
33
+ readonly type: "tone";
34
+ readonly wave: Wave;
35
+ readonly from: number;
36
+ readonly to: number;
37
+ readonly duration: number;
38
+ readonly attack: number;
39
+ }
40
+ /** A burst of noise through a filter gliding from `from` to `to` Hz: air, debris, hiss, rumble. */
41
+ export interface NoiseLayer extends Timed {
42
+ readonly type: "noise";
43
+ readonly filter: Filter;
44
+ readonly from: number;
45
+ readonly to: number;
46
+ /** How narrow the band (bandpass), or how much the cutoff rings (lowpass, highpass, in dB). */
47
+ readonly q: number;
48
+ readonly duration: number;
49
+ readonly attack: number;
50
+ }
51
+ /**
52
+ * A swing through the air: a band of noise rising from `low` to `peak` Hz
53
+ * as the swing speeds up, loudest at `peakAt` (a share of the duration),
54
+ * then falling away.
55
+ */
56
+ export interface SwishLayer extends Timed {
57
+ readonly type: "swish";
58
+ readonly low: number;
59
+ readonly peak: number;
60
+ readonly peakAt: number;
61
+ readonly q: number;
62
+ readonly duration: number;
63
+ }
64
+ /** Distorted band-passed noise gliding from `from` to `to` Hz: the crack of a blow. */
65
+ export interface CrunchLayer extends Timed {
66
+ readonly type: "crunch";
67
+ readonly from: number;
68
+ readonly to: number;
69
+ readonly duration: number;
70
+ }
71
+ /** A metallic ring: inharmonic partials of `pitch` Hz, the higher ones dying first. */
72
+ export interface MetalLayer extends Timed {
73
+ readonly type: "metal";
74
+ readonly pitch: number;
75
+ readonly duration: number;
76
+ }
77
+ /** The contact of a blow: a very short, bright tick. */
78
+ export interface ClickLayer extends Timed {
79
+ readonly type: "click";
80
+ }
81
+ export type Layer = ToneLayer | NoiseLayer | SwishLayer | CrunchLayer | MetalLayer | ClickLayer;
82
+ export type LayerType = Layer["type"];
83
+ export declare const layerTypes: ReadonlyArray<LayerType>;
84
+ /**
85
+ * Broad changes over the whole sound, made by the person with sliders, kept
86
+ * apart from the layers so they can be read and undone at a glance.
87
+ */
88
+ export interface Tune {
89
+ /** Semitones up (or down): every frequency, tones and filters. */
90
+ readonly pitch: number;
91
+ /** Every duration and delay times this. */
92
+ readonly length: number;
93
+ /** Semitones up (or down) for the filters only: brighter or darker without changing the notes. */
94
+ readonly brightness: number;
95
+ /** Added to the room's share (0 to 1 in all). */
96
+ readonly echo: number;
97
+ /** Decibels up (or down). */
98
+ readonly volume: number;
99
+ }
100
+ export declare const neutralTune: Tune;
101
+ export interface Recipe {
102
+ /** What the sound is for, in a few words: the agent's intent, shown to the person. */
103
+ readonly about?: string | undefined;
104
+ /** How much of the sound goes to the room, 0 to 1. */
105
+ readonly reverb: number;
106
+ /** A heavy sound turns the others down for a moment (the game's mixer reads this). */
107
+ readonly heavy?: boolean | undefined;
108
+ /** The least time between two plays, in seconds (the game's mixer reads this). */
109
+ readonly interval?: number | undefined;
110
+ readonly layers: ReadonlyArray<Layer>;
111
+ readonly tune?: Tune | undefined;
112
+ }
113
+ export interface Bank {
114
+ /** The game's master volume over every sound, 1 by default: sounds are measured as the game plays them. */
115
+ readonly master?: number | undefined;
116
+ readonly sounds: Readonly<Record<string, Recipe>>;
117
+ }
118
+ export type Decoded<A> = {
119
+ readonly ok: true;
120
+ readonly value: A;
121
+ } | {
122
+ readonly ok: false;
123
+ readonly error: string;
124
+ };
125
+ /** Reads one recipe from parsed JSON; `at` names it in errors. */
126
+ export declare const decodeRecipeValue: (raw: unknown, at: string, errors: Array<string>) => Recipe | undefined;
127
+ /** Reads one recipe written by `encodeRecipe` (or by hand). */
128
+ export declare const decodeRecipe: (text: string) => Decoded<Recipe>;
129
+ /** Sound names are ids the game's code refers to: letters, digits, `-`, `_`, and `.`. */
130
+ export declare const isSoundName: (name: string) => boolean;
131
+ /** Reads a bank file: `{"version": 1, "sounds": {"name": recipe, ...}}`, reporting every problem at once. */
132
+ export declare const decodeBank: (text: string) => Decoded<Bank>;
133
+ /** A recipe as JSON values, with defaults and empty fields left out, so files stay short. */
134
+ export declare const recipeValue: (recipe: Recipe) => Record<string, unknown>;
135
+ export declare const isNeutral: (tune: Tune) => boolean;
136
+ export declare const encodeRecipe: (recipe: Recipe) => string;
137
+ export declare const encodeBank: (bank: Bank) => string;
138
+ /** The recipe with its tune folded into the layers: what the renderer plays, and what a game without tunes would ship. */
139
+ export declare const applyTune: (recipe: Recipe) => Recipe;
140
+ /** A layer in a few words, for lists: "tone sine 160→55 Hz, 0.12 s". */
141
+ export declare const describeLayer: (layer: Layer) => string;
142
+ export {};
143
+ //# sourceMappingURL=recipe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recipe.d.ts","sourceRoot":"","sources":["../../../src/sound/core/recipe.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,292 @@
1
+ /**
2
+ * Sound recipes: a game sound as plain JSON, a few layers built from small
3
+ * instruments, mixed into a room. The renderer (`render.ts`) turns a recipe
4
+ * into samples the same way in Node and in the browser, so what the page
5
+ * plays, what the CLI measures, and what the game plays are one sound.
6
+ *
7
+ * ```json
8
+ * {
9
+ * "reverb": 0.12,
10
+ * "layers": [
11
+ * { "type": "click", "gain": 0.45 },
12
+ * { "type": "tone", "wave": "sine", "from": 160, "to": 55, "duration": 0.12, "gain": 0.65, "attack": 0.002 },
13
+ * { "type": "crunch", "from": 1500, "to": 500, "duration": 0.07, "gain": 0.3 }
14
+ * ]
15
+ * }
16
+ * ```
17
+ *
18
+ * A bank is a file of named recipes (`{"version": 1, "master": 0.6,
19
+ * "sounds": {...}}`): the game's sounds, one file, and the master volume the
20
+ * game plays them at.
21
+ */
22
+ export const waves = ["sine", "triangle", "square", "sawtooth"];
23
+ export const filters = ["lowpass", "highpass", "bandpass"];
24
+ export const layerTypes = ["tone", "noise", "swish", "crunch", "metal", "click"];
25
+ export const neutralTune = { pitch: 0, length: 1, brightness: 0, echo: 0, volume: 0 };
26
+ const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
27
+ /** Reads values out of untrusted JSON, collecting every problem with where it is. */
28
+ const reader = (errors) => {
29
+ const number = (value, name, fallback, min, max) => {
30
+ if (value === undefined) {
31
+ if (fallback === undefined)
32
+ errors.push(`${name} is missing`);
33
+ return fallback ?? 0;
34
+ }
35
+ if (typeof value !== "number" || !Number.isFinite(value)) {
36
+ errors.push(`${name} must be a number`);
37
+ return fallback ?? 0;
38
+ }
39
+ if (min !== undefined && value < min)
40
+ errors.push(`${name} must be at least ${min}`);
41
+ if (max !== undefined && value > max)
42
+ errors.push(`${name} must be at most ${max}`);
43
+ return value;
44
+ };
45
+ const oneOf = (value, name, options, fallback) => {
46
+ if (value === undefined)
47
+ return fallback;
48
+ const found = options.find((option) => option === value);
49
+ if (found !== undefined)
50
+ return found;
51
+ errors.push(`${name} must be one of ${options.join(", ")}`);
52
+ return fallback;
53
+ };
54
+ return { number, oneOf };
55
+ };
56
+ /** The highest frequency a layer may ask for: past it, nothing is heard at 44.1 kHz. */
57
+ const NYQUIST = 20000;
58
+ const decodeLayer = (raw, at, errors) => {
59
+ if (!isRecord(raw)) {
60
+ errors.push(`${at} must be an object`);
61
+ return undefined;
62
+ }
63
+ const { number, oneOf } = reader(errors);
64
+ const type = raw.type;
65
+ const delay = number(raw.delay, `${at}.delay`, 0, 0);
66
+ const gain = number(raw.gain, `${at}.gain`, undefined, 0, 4);
67
+ const hz = (key, fallback) => number(raw[key], `${at}.${key}`, fallback, 1, NYQUIST);
68
+ const duration = () => number(raw.duration, `${at}.duration`, undefined, 0.001, 10);
69
+ switch (type) {
70
+ case "tone":
71
+ return {
72
+ type,
73
+ wave: oneOf(raw.wave, `${at}.wave`, waves, "sine"),
74
+ from: hz("from"),
75
+ to: hz("to", typeof raw.from === "number" ? raw.from : undefined),
76
+ duration: duration(),
77
+ gain,
78
+ delay,
79
+ attack: number(raw.attack, `${at}.attack`, 0.006, 0.0005)
80
+ };
81
+ case "noise":
82
+ return {
83
+ type,
84
+ filter: oneOf(raw.filter, `${at}.filter`, filters, "lowpass"),
85
+ from: hz("from"),
86
+ to: hz("to", typeof raw.from === "number" ? raw.from : undefined),
87
+ q: number(raw.q, `${at}.q`, 1, 0.01, 40),
88
+ duration: duration(),
89
+ gain,
90
+ delay,
91
+ attack: number(raw.attack, `${at}.attack`, 0.004, 0.0005)
92
+ };
93
+ case "swish":
94
+ return {
95
+ type,
96
+ low: hz("low"),
97
+ peak: hz("peak"),
98
+ peakAt: number(raw.peakAt, `${at}.peakAt`, 0.4, 0.01, 0.99),
99
+ q: number(raw.q, `${at}.q`, 1, 0.01, 40),
100
+ duration: duration(),
101
+ gain,
102
+ delay
103
+ };
104
+ case "crunch":
105
+ return { type, from: hz("from"), to: hz("to", typeof raw.from === "number" ? raw.from : undefined), duration: duration(), gain, delay };
106
+ case "metal":
107
+ return { type, pitch: hz("pitch"), duration: duration(), gain, delay };
108
+ case "click":
109
+ return { type, gain, delay };
110
+ default:
111
+ errors.push(`${at}.type must be one of ${layerTypes.join(", ")}`);
112
+ return undefined;
113
+ }
114
+ };
115
+ const decodeTune = (raw, at, errors) => {
116
+ if (raw === undefined)
117
+ return undefined;
118
+ if (!isRecord(raw)) {
119
+ errors.push(`${at} must be an object`);
120
+ return undefined;
121
+ }
122
+ const { number } = reader(errors);
123
+ return {
124
+ pitch: number(raw.pitch, `${at}.pitch`, 0, -24, 24),
125
+ length: number(raw.length, `${at}.length`, 1, 0.25, 4),
126
+ brightness: number(raw.brightness, `${at}.brightness`, 0, -24, 24),
127
+ echo: number(raw.echo, `${at}.echo`, 0, -1, 1),
128
+ volume: number(raw.volume, `${at}.volume`, 0, -40, 24)
129
+ };
130
+ };
131
+ /** Reads one recipe from parsed JSON; `at` names it in errors. */
132
+ export const decodeRecipeValue = (raw, at, errors) => {
133
+ if (!isRecord(raw)) {
134
+ errors.push(`${at} must be an object`);
135
+ return undefined;
136
+ }
137
+ const { number } = reader(errors);
138
+ if (!Array.isArray(raw.layers)) {
139
+ errors.push(`${at}.layers must be a list`);
140
+ return undefined;
141
+ }
142
+ const layers = raw.layers.flatMap((layer, i) => decodeLayer(layer, `${at}.layers[${i}]`, errors) ?? []);
143
+ if (raw.about !== undefined && typeof raw.about !== "string")
144
+ errors.push(`${at}.about must be text`);
145
+ if (raw.heavy !== undefined && typeof raw.heavy !== "boolean")
146
+ errors.push(`${at}.heavy must be true or false`);
147
+ const recipe = {
148
+ about: typeof raw.about === "string" ? raw.about : undefined,
149
+ reverb: number(raw.reverb, `${at}.reverb`, 0, 0, 1),
150
+ heavy: raw.heavy === true ? true : undefined,
151
+ interval: raw.interval === undefined ? undefined : number(raw.interval, `${at}.interval`, 0, 0),
152
+ layers,
153
+ tune: decodeTune(raw.tune, `${at}.tune`, errors)
154
+ };
155
+ return recipe;
156
+ };
157
+ const parse = (text) => {
158
+ try {
159
+ return { ok: true, value: JSON.parse(text) };
160
+ }
161
+ catch (error) {
162
+ return { ok: false, error: `not JSON: ${error instanceof Error ? error.message : String(error)}` };
163
+ }
164
+ };
165
+ /** Reads one recipe written by `encodeRecipe` (or by hand). */
166
+ export const decodeRecipe = (text) => {
167
+ const parsed = parse(text);
168
+ if (!parsed.ok)
169
+ return parsed;
170
+ const errors = [];
171
+ const recipe = decodeRecipeValue(parsed.value, "recipe", errors);
172
+ return recipe === undefined || errors.length > 0 ? { ok: false, error: errors.join("; ") } : { ok: true, value: recipe };
173
+ };
174
+ /** Sound names are ids the game's code refers to: letters, digits, `-`, `_`, and `.`. */
175
+ export const isSoundName = (name) => /^[A-Za-z][\w.-]{0,63}$/.test(name);
176
+ /** Reads a bank file: `{"version": 1, "sounds": {"name": recipe, ...}}`, reporting every problem at once. */
177
+ export const decodeBank = (text) => {
178
+ const parsed = parse(text);
179
+ if (!parsed.ok)
180
+ return parsed;
181
+ const raw = parsed.value;
182
+ if (!isRecord(raw) || !isRecord(raw.sounds))
183
+ return { ok: false, error: 'a bank is {"version": 1, "sounds": {"name": recipe, ...}}' };
184
+ if (raw.version !== undefined && raw.version !== 1)
185
+ return { ok: false, error: `bank version ${String(raw.version)} is not known (this tool reads version 1)` };
186
+ const errors = [];
187
+ const sounds = {};
188
+ for (const [name, value] of Object.entries(raw.sounds)) {
189
+ if (!isSoundName(name))
190
+ errors.push(`"${name}" is not a sound name (letters, digits, -, _, and ., starting with a letter)`);
191
+ const recipe = decodeRecipeValue(value, name, errors);
192
+ if (recipe !== undefined)
193
+ sounds[name] = recipe;
194
+ }
195
+ const master = raw.master === undefined ? undefined : reader(errors).number(raw.master, "master", 1, 0.01, 4);
196
+ return errors.length > 0 ? { ok: false, error: errors.join("; ") } : { ok: true, value: { master, sounds } };
197
+ };
198
+ /** A recipe as JSON values, with defaults and empty fields left out, so files stay short. */
199
+ export const recipeValue = (recipe) => {
200
+ const layers = recipe.layers.map((layer) => {
201
+ const { delay, ...rest } = layer;
202
+ const out = { ...rest };
203
+ if (delay !== 0)
204
+ out.delay = delay;
205
+ return out;
206
+ });
207
+ const tune = recipe.tune === undefined || isNeutral(recipe.tune) ? undefined : recipe.tune;
208
+ return {
209
+ ...(recipe.about === undefined ? {} : { about: recipe.about }),
210
+ reverb: recipe.reverb,
211
+ ...(recipe.heavy === true ? { heavy: true } : {}),
212
+ ...(recipe.interval === undefined ? {} : { interval: recipe.interval }),
213
+ layers,
214
+ ...(tune === undefined ? {} : { tune })
215
+ };
216
+ };
217
+ export const isNeutral = (tune) => tune.pitch === 0 && tune.length === 1 && tune.brightness === 0 && tune.echo === 0 && tune.volume === 0;
218
+ /**
219
+ * JSON with each layer on one line: a bank is read and diffed by people and
220
+ * agents, and a layer is one thought.
221
+ */
222
+ const write = (value, indent) => {
223
+ if (Array.isArray(value)) {
224
+ if (value.length === 0)
225
+ return "[]";
226
+ return `[\n${value.map((item) => `${indent} ${JSON.stringify(item)}`).join(",\n")}\n${indent}]`;
227
+ }
228
+ if (isRecord(value)) {
229
+ const entries = Object.entries(value).filter(([, item]) => item !== undefined);
230
+ if (entries.length === 0)
231
+ return "{}";
232
+ return `{\n${entries.map(([key, item]) => `${indent} ${JSON.stringify(key)}: ${key === "tune" ? JSON.stringify(item) : write(item, `${indent} `)}`).join(",\n")}\n${indent}}`;
233
+ }
234
+ return JSON.stringify(value);
235
+ };
236
+ export const encodeRecipe = (recipe) => write(recipeValue(recipe), "") + "\n";
237
+ export const encodeBank = (bank) => {
238
+ const sounds = {};
239
+ for (const [name, recipe] of Object.entries(bank.sounds))
240
+ sounds[name] = recipeValue(recipe);
241
+ return write({ version: 1, ...(bank.master === undefined ? {} : { master: bank.master }), sounds }, "") + "\n";
242
+ };
243
+ /** The recipe with its tune folded into the layers: what the renderer plays, and what a game without tunes would ship. */
244
+ export const applyTune = (recipe) => {
245
+ const tune = recipe.tune;
246
+ if (tune === undefined || isNeutral(tune))
247
+ return recipe;
248
+ const pitch = Math.pow(2, tune.pitch / 12);
249
+ const bright = pitch * Math.pow(2, tune.brightness / 12);
250
+ const gain = Math.pow(10, tune.volume / 20);
251
+ const time = tune.length;
252
+ const layers = recipe.layers.map((layer) => {
253
+ const delay = layer.delay * time;
254
+ const g = layer.gain * gain;
255
+ switch (layer.type) {
256
+ case "tone":
257
+ return { ...layer, from: clampHz(layer.from * pitch), to: clampHz(layer.to * pitch), duration: layer.duration * time, attack: layer.attack * time, delay, gain: g };
258
+ case "noise":
259
+ return { ...layer, from: clampHz(layer.from * bright), to: clampHz(layer.to * bright), duration: layer.duration * time, attack: layer.attack * time, delay, gain: g };
260
+ case "swish":
261
+ return { ...layer, low: clampHz(layer.low * bright), peak: clampHz(layer.peak * bright), duration: layer.duration * time, delay, gain: g };
262
+ case "crunch":
263
+ return { ...layer, from: clampHz(layer.from * bright), to: clampHz(layer.to * bright), duration: layer.duration * time, delay, gain: g };
264
+ case "metal":
265
+ return { ...layer, pitch: clampHz(layer.pitch * pitch), duration: layer.duration * time, delay, gain: g };
266
+ case "click":
267
+ return { ...layer, delay, gain: g };
268
+ }
269
+ });
270
+ return { ...recipe, reverb: Math.min(1, Math.max(0, recipe.reverb + tune.echo)), layers, tune: undefined };
271
+ };
272
+ const clampHz = (hz) => Math.min(NYQUIST, Math.max(1, hz));
273
+ /** A layer in a few words, for lists: "tone sine 160→55 Hz, 0.12 s". */
274
+ export const describeLayer = (layer) => {
275
+ const s = (seconds) => `${seconds < 0.1 ? Math.round(seconds * 1000) + " ms" : Math.round(seconds * 100) / 100 + " s"}`;
276
+ const glide = (from, to) => (Math.round(from) === Math.round(to) ? `${Math.round(from)} Hz` : `${Math.round(from)}→${Math.round(to)} Hz`);
277
+ switch (layer.type) {
278
+ case "tone":
279
+ return `${layer.wave} ${glide(layer.from, layer.to)}, ${s(layer.duration)}`;
280
+ case "noise":
281
+ return `${layer.filter} ${glide(layer.from, layer.to)}, ${s(layer.duration)}`;
282
+ case "swish":
283
+ return `${Math.round(layer.low)}→${Math.round(layer.peak)} Hz, ${s(layer.duration)}`;
284
+ case "crunch":
285
+ return `${glide(layer.from, layer.to)}, ${s(layer.duration)}`;
286
+ case "metal":
287
+ return `${Math.round(layer.pitch)} Hz, ${s(layer.duration)}`;
288
+ case "click":
289
+ return "tick";
290
+ }
291
+ };
292
+ //# sourceMappingURL=recipe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recipe.js","sourceRoot":"","sources":["../../../src/sound/core/recipe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,MAAM,CAAC,MAAM,KAAK,GAAwB,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAA;AAGpF,MAAM,CAAC,MAAM,OAAO,GAA0B,CAAC,SAAS,EAAE,UAAU,EAAE,UAAU,CAAC,CAAA;AAkEjF,MAAM,CAAC,MAAM,UAAU,GAA6B,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAA;AAmB1G,MAAM,CAAC,MAAM,WAAW,GAAS,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAA;AAuB3F,MAAM,QAAQ,GAAG,CAAC,KAAc,EAAoC,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;AAE3I,qFAAqF;AACrF,MAAM,MAAM,GAAG,CAAC,MAAqB,EAAE,EAAE;IACvC,MAAM,MAAM,GAAG,CAAC,KAAc,EAAE,IAAY,EAAE,QAA4B,EAAE,GAAY,EAAE,GAAY,EAAU,EAAE;QAChH,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,IAAI,QAAQ,KAAK,SAAS;gBAAE,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,aAAa,CAAC,CAAA;YAC7D,OAAO,QAAQ,IAAI,CAAC,CAAA;QACtB,CAAC;QACD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACzD,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,mBAAmB,CAAC,CAAA;YACvC,OAAO,QAAQ,IAAI,CAAC,CAAA;QACtB,CAAC;QACD,IAAI,GAAG,KAAK,SAAS,IAAI,KAAK,GAAG,GAAG;YAAE,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,qBAAqB,GAAG,EAAE,CAAC,CAAA;QACpF,IAAI,GAAG,KAAK,SAAS,IAAI,KAAK,GAAG,GAAG;YAAE,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,oBAAoB,GAAG,EAAE,CAAC,CAAA;QACnF,OAAO,KAAK,CAAA;IACd,CAAC,CAAA;IACD,MAAM,KAAK,GAAG,CAAmB,KAAc,EAAE,IAAY,EAAE,OAAyB,EAAE,QAAW,EAAK,EAAE;QAC1G,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,QAAQ,CAAA;QACxC,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,KAAK,KAAK,CAAC,CAAA;QACxD,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,KAAK,CAAA;QACrC,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,mBAAmB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAC3D,OAAO,QAAQ,CAAA;IACjB,CAAC,CAAA;IACD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAA;AAC1B,CAAC,CAAA;AAED,wFAAwF;AACxF,MAAM,OAAO,GAAG,KAAK,CAAA;AAErB,MAAM,WAAW,GAAG,CAAC,GAAY,EAAE,EAAU,EAAE,MAAqB,EAAqB,EAAE;IACzF,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACnB,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,oBAAoB,CAAC,CAAA;QACtC,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,CAAA;IACxC,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAA;IACrB,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;IACpD,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;IAC5D,MAAM,EAAE,GAAG,CAAC,GAAW,EAAE,QAAiB,EAAU,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,IAAI,GAAG,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO,CAAC,CAAA;IAC7G,MAAM,QAAQ,GAAG,GAAW,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,EAAE,WAAW,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,CAAC,CAAA;IAC3F,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,MAAM;YACT,OAAO;gBACL,IAAI;gBACJ,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC;gBAClD,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC;gBAChB,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;gBACjE,QAAQ,EAAE,QAAQ,EAAE;gBACpB,IAAI;gBACJ,KAAK;gBACL,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,CAAC;aAC1D,CAAA;QACH,KAAK,OAAO;YACV,OAAO;gBACL,IAAI;gBACJ,MAAM,EAAE,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,CAAC;gBAC7D,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC;gBAChB,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;gBACjE,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC;gBACxC,QAAQ,EAAE,QAAQ,EAAE;gBACpB,IAAI;gBACJ,KAAK;gBACL,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,CAAC;aAC1D,CAAA;QACH,KAAK,OAAO;YACV,OAAO;gBACL,IAAI;gBACJ,GAAG,EAAE,EAAE,CAAC,KAAK,CAAC;gBACd,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC;gBAChB,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC;gBAC3D,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC;gBACxC,QAAQ,EAAE,QAAQ,EAAE;gBACpB,IAAI;gBACJ,KAAK;aACN,CAAA;QACH,KAAK,QAAQ;YACX,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAA;QACzI,KAAK,OAAO;YACV,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAA;QACxE,KAAK,OAAO;YACV,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAA;QAC9B;YACE,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,wBAAwB,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YACjE,OAAO,SAAS,CAAA;IACpB,CAAC;AACH,CAAC,CAAA;AAED,MAAM,UAAU,GAAG,CAAC,GAAY,EAAE,EAAU,EAAE,MAAqB,EAAoB,EAAE;IACvF,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,SAAS,CAAA;IACvC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACnB,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,oBAAoB,CAAC,CAAA;QACtC,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,CAAA;IACjC,OAAO;QACL,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC;QACnD,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QACtD,UAAU,EAAE,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,EAAE,aAAa,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC;QAClE,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;QAC9C,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC;KACvD,CAAA;AACH,CAAC,CAAA;AAED,kEAAkE;AAClE,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,GAAY,EAAE,EAAU,EAAE,MAAqB,EAAsB,EAAE;IACvG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACnB,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,oBAAoB,CAAC,CAAA;QACtC,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,CAAA;IACjC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;QAC/B,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,wBAAwB,CAAC,CAAA;QAC1C,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAc,EAAE,CAAS,EAAE,EAAE,CAAC,WAAW,CAAC,KAAK,EAAE,GAAG,EAAE,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAA;IACxH,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS,IAAI,OAAO,GAAG,CAAC,KAAK,KAAK,QAAQ;QAAE,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,qBAAqB,CAAC,CAAA;IACrG,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS,IAAI,OAAO,GAAG,CAAC,KAAK,KAAK,SAAS;QAAE,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,8BAA8B,CAAC,CAAA;IAC/G,MAAM,MAAM,GAAW;QACrB,KAAK,EAAE,OAAO,GAAG,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS;QAC5D,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACnD,KAAK,EAAE,GAAG,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;QAC5C,QAAQ,EAAE,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC,CAAC;QAC/F,MAAM;QACN,IAAI,EAAE,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC;KACjD,CAAA;IACD,OAAO,MAAM,CAAA;AACf,CAAC,CAAA;AAED,MAAM,KAAK,GAAG,CAAC,IAAY,EAAoB,EAAE;IAC/C,IAAI,CAAC;QACH,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAA;IAC9C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,CAAA;IACpG,CAAC;AACH,CAAC,CAAA;AAED,+DAA+D;AAC/D,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,IAAY,EAAmB,EAAE;IAC5D,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,CAAA;IAC1B,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,OAAO,MAAM,CAAA;IAC7B,MAAM,MAAM,GAAkB,EAAE,CAAA;IAChC,MAAM,MAAM,GAAG,iBAAiB,CAAC,MAAM,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAA;IAChE,OAAO,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,CAAA;AAC1H,CAAC,CAAA;AAED,yFAAyF;AACzF,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,IAAY,EAAW,EAAE,CAAC,wBAAwB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAEzF,6GAA6G;AAC7G,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,IAAY,EAAiB,EAAE;IACxD,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,CAAA;IAC1B,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,OAAO,MAAM,CAAA;IAC7B,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAA;IACxB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,2DAA2D,EAAE,CAAA;IACrI,IAAI,GAAG,CAAC,OAAO,KAAK,SAAS,IAAI,GAAG,CAAC,OAAO,KAAK,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,gBAAgB,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,2CAA2C,EAAE,CAAA;IAC/J,MAAM,MAAM,GAAkB,EAAE,CAAA;IAChC,MAAM,MAAM,GAA2B,EAAE,CAAA;IACzC,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;QACvD,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;YAAE,MAAM,CAAC,IAAI,CAAC,IAAI,IAAI,8EAA8E,CAAC,CAAA;QAC3H,MAAM,MAAM,GAAG,iBAAiB,CAAC,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC,CAAA;QACrD,IAAI,MAAM,KAAK,SAAS;YAAE,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,CAAA;IACjD,CAAC;IACD,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;IAC7G,OAAO,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,CAAA;AAC9G,CAAC,CAAA;AAED,6FAA6F;AAC7F,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,MAAc,EAA2B,EAAE;IACrE,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QACzC,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,CAAA;QAChC,MAAM,GAAG,GAA4B,EAAE,GAAG,IAAI,EAAE,CAAA;QAChD,IAAI,KAAK,KAAK,CAAC;YAAE,GAAG,CAAC,KAAK,GAAG,KAAK,CAAA;QAClC,OAAO,GAAG,CAAA;IACZ,CAAC,CAAC,CAAA;IACF,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,KAAK,SAAS,IAAI,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAA;IAC1F,OAAO;QACL,GAAG,CAAC,MAAM,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;QAC9D,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,GAAG,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACjD,GAAG,CAAC,MAAM,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC;QACvE,MAAM;QACN,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;KACxC,CAAA;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,IAAU,EAAW,EAAE,CAC/C,IAAI,CAAC,KAAK,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,UAAU,KAAK,CAAC,IAAI,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,CAAA;AAExG;;;GAGG;AACH,MAAM,KAAK,GAAG,CAAC,KAAc,EAAE,MAAc,EAAU,EAAE;IACvD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAA;QACnC,OAAO,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,MAAM,KAAK,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,MAAM,GAAG,CAAA;IAClG,CAAC;IACD,IAAI,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACpB,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,KAAK,SAAS,CAAC,CAAA;QAC9E,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAA;QACrC,OAAO,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,GAAG,MAAM,KAAK,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,GAAG,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,MAAM,GAAG,CAAA;IACjL,CAAC;IACD,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;AAC9B,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,MAAc,EAAU,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,CAAA;AAE7F,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,IAAU,EAAU,EAAE;IAC/C,MAAM,MAAM,GAA4B,EAAE,CAAA;IAC1C,KAAK,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,MAAM,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,MAAM,CAAC,CAAA;IAC5F,OAAO,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,GAAG,IAAI,CAAA;AAChH,CAAC,CAAA;AAED,0HAA0H;AAC1H,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,MAAc,EAAU,EAAE;IAClD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAA;IACxB,IAAI,IAAI,KAAK,SAAS,IAAI,SAAS,CAAC,IAAI,CAAC;QAAE,OAAO,MAAM,CAAA;IACxD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC,CAAA;IAC1C,MAAM,MAAM,GAAG,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC,CAAA;IACxD,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC,CAAA;IAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAA;IACxB,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAS,EAAE;QAChD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,GAAG,IAAI,CAAA;QAChC,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,GAAG,IAAI,CAAA;QAC3B,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;YACnB,KAAK,MAAM;gBACT,OAAO,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,KAAK,CAAC,EAAE,GAAG,KAAK,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,GAAG,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EAAE,CAAA;YACrK,KAAK,OAAO;gBACV,OAAO,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,IAAI,GAAG,MAAM,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,KAAK,CAAC,EAAE,GAAG,MAAM,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,GAAG,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EAAE,CAAA;YACvK,KAAK,OAAO;gBACV,OAAO,EAAE,GAAG,KAAK,EAAE,GAAG,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,GAAG,MAAM,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,IAAI,GAAG,MAAM,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,GAAG,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EAAE,CAAA;YAC5I,KAAK,QAAQ;gBACX,OAAO,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,IAAI,GAAG,MAAM,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,KAAK,CAAC,EAAE,GAAG,MAAM,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,GAAG,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EAAE,CAAA;YAC1I,KAAK,OAAO;gBACV,OAAO,EAAE,GAAG,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,GAAG,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EAAE,CAAA;YAC3G,KAAK,OAAO;gBACV,OAAO,EAAE,GAAG,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EAAE,CAAA;QACvC,CAAC;IACH,CAAC,CAAC,CAAA;IACF,OAAO,EAAE,GAAG,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,CAAA;AAC5G,CAAC,CAAA;AAED,MAAM,OAAO,GAAG,CAAC,EAAU,EAAU,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;AAE1E,wEAAwE;AACxE,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,KAAY,EAAU,EAAE;IACpD,MAAM,CAAC,GAAG,CAAC,OAAe,EAAU,EAAE,CAAC,GAAG,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,GAAG,CAAC,GAAG,GAAG,GAAG,IAAI,EAAE,CAAA;IACvI,MAAM,KAAK,GAAG,CAAC,IAAY,EAAE,EAAU,EAAU,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAA;IACjK,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,MAAM;YACT,OAAO,GAAG,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAA;QAC7E,KAAK,OAAO;YACV,OAAO,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAA;QAC/E,KAAK,OAAO;YACV,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAA;QACtF,KAAK,QAAQ;YACX,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAA;QAC/D,KAAK,OAAO;YACV,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAA;QAC9D,KAAK,OAAO;YACV,OAAO,MAAM,CAAA;IACjB,CAAC;AACH,CAAC,CAAA"}