@patterkit/play-helpers 0.5.0 → 0.6.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.
package/dist/index.d.ts CHANGED
@@ -1,13 +1,9 @@
1
- import { SaveGame, Engine, StepResult, Bundle as Bundle$1, BundleDescription } from '@patterkit/runtime';
2
- import { StateSnapshot, StateChange, ScalarValue as ScalarValue$1 } from '@wildwinter/scoperegistry';
1
+ import { Engine, StepResult, Bundle, BundleDescription } from '@patterkit/runtime';
2
+ import { SaveEnvelope, Bundle as Bundle$1 } from '@patterkit/model';
3
+ export { SAVE_SCHEMA, SaveEnvelope } from '@patterkit/model';
4
+ import { StateSnapshot, StateChange, ScalarValue } from '@wildwinter/scoperegistry';
3
5
  export { StateChange, StateSnapshot, diffState } from '@wildwinter/scoperegistry';
4
6
 
5
- declare const SAVE_SCHEMA = "patter/save@0";
6
- interface SaveEnvelope {
7
- schema: typeof SAVE_SCHEMA;
8
- /** The engine save-game: shared `@patter`/`@scene` state, visit counts, and every live flow. */
9
- save: SaveGame;
10
- }
11
7
  /** Capture the whole game as a tagged envelope (wraps `engine.saveGame()`). */
12
8
  declare function saveState(engine: Engine): SaveEnvelope;
13
9
  /** Restore a {@link saveState} envelope into an engine (fresh or live). Throws on a foreign/blank blob. */
@@ -28,7 +24,7 @@ declare function setProperties(engine: Engine, values: Record<string, PropertyVa
28
24
 
29
25
  /** A flattened runtime-state value: a Patter scalar. The kernel calls this `ScalarValue`;
30
26
  * the alias stays because it is exported API and reads in Patter's own vocabulary. */
31
- type StateValue = ScalarValue$1;
27
+ type StateValue = ScalarValue;
32
28
  /** Flatten the engine's whole-game state into a path -> value map (shared scopes + every live
33
29
  * flow), off `saveGame()`. The logger no longer diffs this - it mounts the bags directly - but
34
30
  * it stays as the public "what is the state right now" call, and as the definition of the path
@@ -107,7 +103,7 @@ interface LiveBundleResult {
107
103
  /** The engine to keep using: the same instance for a "text" swap, a replacement for "structure". */
108
104
  engine: Engine;
109
105
  /** The parsed pushed bundle - hold on to it for the next apply's comparison. */
110
- bundle: Bundle$1;
106
+ bundle: Bundle;
111
107
  /** Which tier applied: "text" (strings-only, nothing restarted) or "structure" (full hot swap). */
112
108
  kind: "text" | "structure";
113
109
  }
@@ -117,7 +113,7 @@ interface LiveBundleResult {
117
113
  * unparseable JSON - a structural swap's edge cases are absorbed by the §9.8 drift policy inside
118
114
  * `hotSwap`, which never throws for ordinary edits.
119
115
  */
120
- declare function applyLiveBundle(engine: Engine, current: Bundle$1, data: string): LiveBundleResult;
116
+ declare function applyLiveBundle(engine: Engine, current: Bundle, data: string): LiveBundleResult;
121
117
 
122
118
  interface PropertyInspectorOptions {
123
119
  /** Where to mount the panel. If omitted, append the returned `el` yourself. */
@@ -137,324 +133,6 @@ interface PropertyInspector {
137
133
  }
138
134
  declare function createPropertyInspector(engine: Engine, opts?: PropertyInspectorOptions): PropertyInspector;
139
135
 
140
- type BinaryOp = "==" | "!=" | ">" | ">=" | "<" | "<=" | "+" | "-" | "*" | "/" | "and" | "or";
141
- type UnaryOp = "not" | "neg";
142
- type AstNode = ["b", boolean] | ["n", number] | ["s", string] | ["sv", string, string] | ["u", UnaryOp, AstNode] | ["bin", BinaryOp, AstNode, AstNode] | ["call", string, ...AstNode[]] | ["fd", "+" | "-", string];
143
-
144
- type ScalarValue = boolean | number | string | string[];
145
- /** Developer-defined host metadata (spec §17). Opaque to Patter. */
146
- type GameData = Record<string, unknown>;
147
- /** A scene/block id, or the reserved "END". */
148
- type JumpTarget = string;
149
- interface Jump {
150
- to: JumpTarget;
151
- /** "jump" (one-way, default) or "call" (jump-and-return via the flow callstack). */
152
- mode?: "jump" | "call";
153
- }
154
- interface LineBeat {
155
- id: string;
156
- kind: "line";
157
- /** Speaker; must be a member of the project cast (validated). */
158
- character?: string;
159
- /** Performance direction, language-neutral (never localised). */
160
- direction?: string;
161
- gameData?: GameData;
162
- /** Author-defined freeform tags (#215): a cross-cutting label layer that travels to the runtime.
163
- * At runtime a beat's tags are the UNION of its own and every ancestor's (scene → block → group(s) →
164
- * snippet → beat). Each tag is letters/digits/symbols with NO comma and NO whitespace; deduped. */
165
- tags?: string[];
166
- }
167
- /**
168
- * Authorial voice / narration - speaker-less prose (spec §2). Never voiced; its
169
- * localised text always permits inline `{@name}` interpolation (spec §16). This
170
- * is the on-screen-text role (e.g. "A door slams!") - distinct from a game-event
171
- * beat, which is a pure engine instruction with no localised content.
172
- */
173
- interface TextBeat {
174
- id: string;
175
- kind: "text";
176
- gameData?: GameData;
177
- /** Author tags (#215). See LineBeat.tags. */
178
- tags?: string[];
179
- }
180
- /**
181
- * A GAME EVENT (spec §2): a pure engine instruction with no player-facing text - just `gameData` the host
182
- * reads when the beat plays (comments / docs attach via the authoring file by id). Named "game event"
183
- * rather than "action" because a screenplay's "action" is prose, which is our text beat. Player-facing
184
- * words are a line or text beat instead.
185
- */
186
- interface GameEventBeat {
187
- id: string;
188
- kind: "gameEvent";
189
- gameData?: GameData;
190
- /** Author tags (#215). See LineBeat.tags. */
191
- tags?: string[];
192
- }
193
- type Beat = LineBeat | TextBeat | GameEventBeat;
194
- type Selector = "run" | "branch" | "sequence" | "choice";
195
- /** How a `sequence` walks its children. `specificity` = **Best match**: pick the eligible
196
- * child whose condition most specifically fits the current state (the most atomic constraints
197
- * actively holding it true); equally-specific ties break by the seeded shuffle. A child with no
198
- * condition scores zero, so it acts as the filler that wins only when nothing more specific is
199
- * eligible. Composes with `exhaust`: `repeat` re-scores every visit (re-pickable, the Best-match
200
- * default), `once` uses each pick up so the group slides down to the filler (graceful degradation). */
201
- type SelectorOrder = "sequential" | "shuffle" | "specificity";
202
- /** What a `sequence` does after one full pass through its children. */
203
- type SelectorExhaust = "once" | "repeat" | "stick";
204
- /**
205
- * `sequence` selector config (spec §4). One stateful picker with two orthogonal
206
- * axes subsumes Ink's stopping / cycle / once / shuffle and their combinations.
207
- * Defaults: `order: "sequential"`, `exhaust: "once"`. `shuffle` draws without
208
- * replacement and never repeats a line back-to-back (built in).
209
- */
210
- interface SequenceOptions {
211
- order?: SelectorOrder;
212
- exhaust?: SelectorExhaust;
213
- }
214
- /** An option's prompt beat (spec §5): a single line | text beat - the choice text. */
215
- type PromptBeat = LineBeat | TextBeat;
216
- type PropertyType = "boolean" | "number" | "string" | "flags" | "enum" | "quality";
217
- interface PropertyDecl {
218
- name: string;
219
- type: PropertyType;
220
- default?: ScalarValue;
221
- /**
222
- * The orthogonal *sharing* axis (spec §7): is this property's value shared across
223
- * all flows (one world value) or kept per-flow? It does NOT change the reference
224
- * syntax - sharing is set here, on the declaration, not by a different scope token.
225
- * The default depends on the scope it is declared in: a **global** property
226
- * (project `properties` -> `@patter`) defaults to **shared**; a **scene-local**
227
- * property (scene `sceneProps` -> `@scene`) defaults to **not shared** (per-flow).
228
- */
229
- shared?: boolean;
230
- /**
231
- * Persistence axis, for **scene-local (`@scene`) properties** (spec §7). Default
232
- * `false`: the value PERSISTS across scene re-entries (like every other property).
233
- * `true`: the value is **reseeded to its default on every scene entry** - "fresh
234
- * each playthrough" (Ink's `temp`). Orthogonal to `shared`. Ignored on global
235
- * (`@patter`) properties, which always persist for the life of the piece.
236
- */
237
- temporary?: boolean;
238
- /** For enum / flags. */
239
- values?: string[];
240
- /** For quality: the ORDERED ladder of stage names (the shared engine's quality type, expr 0.4.0).
241
- * Ordering operators compare by position in this list and `advance()` steps along it, so the order
242
- * is the meaning - unlike `values`, whose order is presentation only. Default seeds to the first
243
- * stage when no `default` is declared. */
244
- stages?: string[];
245
- /** Free-text author note documenting what this property is for (authoring only; shown as a hint). */
246
- purpose?: string;
247
- }
248
- /**
249
- * A property of a host / world scope (`@world`, `@game`, ...). The same shape the
250
- * `@wildwinter/scoperegistry` `scopeRegistrySpec` uses, declared structurally here
251
- * so the model stays free of a runtime dependency. `default` seeds the standalone
252
- * runtime's self-backed bag (see `HostScopeSpec`); `writable: false` makes the
253
- * property read-only to the story (validated at compile time).
254
- */
255
- interface HostScopeDecl {
256
- name: string;
257
- type: PropertyType;
258
- values?: string[];
259
- /** For quality: the ordered stage ladder (see `PropertyDecl.stages`). */
260
- stages?: string[];
261
- default?: ScalarValue;
262
- writable?: boolean;
263
- /** Free-text author note documenting the property (authoring only; shown as a hint). */
264
- purpose?: string;
265
- }
266
- /** One scope (`token`) in a project's host-scope registry. */
267
- interface HostScopeSpec {
268
- /** The scope token after `@` (e.g. `"world"`). Must not collide with Patter's own
269
- * `patter` / `scene` / `flow`. */
270
- token: string;
271
- /** Scope-level read/write default for its declarations (default true). */
272
- writable?: boolean;
273
- /** Property declarations; omit for an opaque scope (any name, unchecked). */
274
- declarations?: HostScopeDecl[];
275
- }
276
- /**
277
- * A project's host-scope registry: the `scopeRegistrySpec` it OWNS (spec
278
- * design/scope-registry.md §6). Makes `@world` (and any host scope) first-class
279
- * in a standalone project: the compiler validates references into it, the runtime
280
- * self-backs it from declaration defaults when no host resolver claims the token,
281
- * and coverage drives its values. Structurally identical to scoperegistry's
282
- * `ScopeRegistrySpec` so it threads straight through the compiler.
283
- */
284
- interface HostScopeRegistry {
285
- version: number;
286
- scopes: HostScopeSpec[];
287
- }
288
- /** A character's grammatical gender, for localisation. Translators need it to inflect the speaker's own
289
- * lines in gendered languages (adjectives, participles, pronouns), which the source text alone often
290
- * cannot tell them. Absent means "not specified". Authoring-only: it never reaches the runtime bundle,
291
- * but it IS carried into the localisation handoff formats as translator context (spec §14).
292
- *
293
- * Free text, not a closed set: real languages need more than three genders (common/utrum, animate/
294
- * inanimate, and so on) and translators name them differently. `COMMON_GENDERS` seeds the editor's
295
- * auto-suggest so the everyday values stay spelled consistently; anything else is still valid. */
296
- type GrammaticalGender = string;
297
- interface CastMember {
298
- /** Canonical speaker name (matched by a beat's `character`); language-neutral key. */
299
- name: string;
300
- /** Localised player-facing name - a localisation id (project-level strings). */
301
- displayName?: string;
302
- /** Grammatical gender for translators (see `GrammaticalGender`); absent = not specified. */
303
- gender?: GrammaticalGender;
304
- /** Free-text production notes about the character (casting, voice, intent) - authoring only. */
305
- notes?: string;
306
- /** The voice actor cast for this character, if known - surfaced in the VO script export (spec §16).
307
- * Authoring-only (not shipped in the runtime bundle). */
308
- actor?: string;
309
- gameData?: GameData;
310
- }
311
- /** The cast as it reaches a compiled bundle: the player-facing fields only. `notes`, `actor` and
312
- * `gender` are authoring / production / translation context, and the compiler drops them, so a shipped
313
- * game never carries a real person's name or a writer's private notes. The compiler copies the shipping
314
- * fields across explicitly (an allow-list), which is what actually keeps a new authoring field out of
315
- * the bundle; this type states the resulting contract for anyone reading a bundle. */
316
- type BundleCastMember = Omit<CastMember, "notes" | "actor" | "gender">;
317
- /** A node TYPE that can carry author-defined gameData fields (the gameData schema, project-level).
318
- * Beat kinds map straight through: dialogue = `line`, narration = `text`, game event = `gameEvent`. */
319
- type GameDataNodeKind = "scene" | "block" | "snippet" | "line" | "text" | "gameEvent";
320
- /** The value type of a gameData field - the property-type vocabulary plus a multiline-text variant.
321
- * Drives the inspector's editor widget (text / textarea / number / toggle / enum dropdown). */
322
- type GameDataFieldType = "text" | "multiline" | "number" | "boolean" | "enum";
323
- /** One author-defined custom field on a node type (host-integration metadata, NOT expression state). */
324
- interface GameDataField {
325
- /** Field key - also the key a node stores its value under in `gameData` (values are name-keyed). */
326
- name: string;
327
- type: GameDataFieldType;
328
- /** The value used when a node sets nothing. Storage is SPARSE - nodes hold only their overrides, and
329
- * a reader falls back to this default (so changing it here propagates to every node that didn't set it). */
330
- default?: ScalarValue;
331
- /** Allowed values when `type` is "enum". */
332
- values?: string[];
333
- /** Free-text description of what the field is for - shown as a rollover hint in the inspector. */
334
- purpose?: string;
335
- }
336
- /** Author-defined gameData fields, grouped by the node type they attach to (project-level schema). */
337
- type GameDataFields = Partial<Record<GameDataNodeKind, GameDataField[]>>;
338
- /** A compiled expression envelope: canonical source + pre-derived tagged-tuple AST. */
339
- interface Expression {
340
- src: string;
341
- ast: AstNode;
342
- }
343
- type CompiledEffect = {
344
- kind: "set";
345
- target: string;
346
- value: Expression;
347
- };
348
- interface CompiledSnippet {
349
- id: string;
350
- type: "snippet";
351
- condition?: Expression;
352
- beats?: Beat[];
353
- onEnter?: CompiledEffect[];
354
- onExit?: CompiledEffect[];
355
- gameData?: GameData;
356
- tags?: string[];
357
- jump?: Jump;
358
- secretUntilEligible?: boolean;
359
- /** Option-position: repeatable (spec §5). Default false = once-only. */
360
- sticky?: boolean;
361
- /** Option-position: the choice's fallback, auto-followed when last (spec §5). */
362
- fallback?: boolean;
363
- }
364
- interface CompiledGroup {
365
- id: string;
366
- type: "group";
367
- condition?: Expression;
368
- /** Default (omitted) = `"run"`. */
369
- selector?: Selector;
370
- /** Selector cursor shared across flows (default false = per-flow). */
371
- shared?: boolean;
372
- options?: SequenceOptions;
373
- children: Array<CompiledGroup | CompiledSnippet>;
374
- gameData?: GameData;
375
- tags?: string[];
376
- /** Option-position fields (spec §5) - only when a direct child of a `choice`. */
377
- prompt?: PromptBeat;
378
- secretUntilEligible?: boolean;
379
- /** Repeatable (spec §5). Default false = once-only. */
380
- sticky?: boolean;
381
- /** The choice's fallback, auto-followed when last (spec §5). */
382
- fallback?: boolean;
383
- }
384
- interface CompiledBlock {
385
- id: string;
386
- type: "block";
387
- name: string;
388
- /** Host-facing address (spec §6); the runtime resolves it to `id`. Absent = derived from `name`. */
389
- gameId?: string;
390
- children: Array<CompiledGroup | CompiledSnippet>;
391
- gameData?: GameData;
392
- tags?: string[];
393
- }
394
- interface CompiledScene {
395
- id: string;
396
- type: "scene";
397
- name: string;
398
- /** Host-facing address (spec §6); the runtime resolves it to `id`. Absent = derived from `name`. */
399
- gameId?: string;
400
- gameData?: GameData;
401
- tags?: string[];
402
- onEntry?: CompiledEffect[];
403
- sceneProps?: PropertyDecl[];
404
- blocks: CompiledBlock[];
405
- }
406
- interface Bundle {
407
- schema: string;
408
- /** `hash` fingerprints the WHOLE bundle (binds saves, gates staleness); `structureHash` is the same
409
- * fingerprint with the string tables left out, so same structureHash + a different hash = a
410
- * text-only edit, safe to hot-swap in place (live bundle refresh). */
411
- content: {
412
- project: string;
413
- version?: string;
414
- hash?: string;
415
- structureHash?: string;
416
- };
417
- voiced: boolean;
418
- locales: {
419
- default: string;
420
- included: string[];
421
- };
422
- /** Player-facing cast only: the compiler strips notes / actor / gender (see `BundleCastMember`). */
423
- cast?: BundleCastMember[];
424
- properties?: PropertyDecl[];
425
- /** Host / world scope declarations, baked from the project so the runtime can self-back a declared
426
- * scope (`@world`, ...) when no host resolver claims its token. Absent = no host scopes. */
427
- scopeRegistry?: HostScopeRegistry;
428
- gameDataFields?: GameDataFields;
429
- scenes: Record<string, CompiledScene>;
430
- /** locale -> (beatId -> text). In "embedded" localisation this carries every included locale; in "ids"
431
- * it is EMPTY (the runtime emits beat IDs), unless `localisation.sourceDebug` embedded the source locale
432
- * for debug playback. `content.hash` is computed over the FULL strings regardless, so the staleness gate
433
- * is unaffected. */
434
- strings: Record<string, Record<string, string>>;
435
- /** How strings ship + resolve (spec §11). Absent = "embedded" (back-compat default): the runtime resolves
436
- * `strings` per locale. "ids": the runtime emits beat IDs and the game localises them itself; `sourceDebug`
437
- * means the source locale is embedded purely for debug playback and the runtime should flag the build as
438
- * not shippable. */
439
- localisation?: {
440
- mode: "embedded" | "ids";
441
- sourceDebug?: boolean;
442
- };
443
- /** Closed-caption delimiters baked from the project (#214). Absent = the default `(` / `)`; the
444
- * runtime strips spans between them from line text when a game disables captions. */
445
- closedCaptions?: CaptionDelimiters;
446
- }
447
- /** Closed-caption configuration (#214). `open`/`close` wrap a caption cue inside a dialogue line (both
448
- * non-empty; they MAY be the same token, e.g. `*…*`). `character` names a cast member whose lines are a
449
- * pure caption: when captions are off, ALL of that character's dialogue (and its speaker label) is
450
- * omitted - delimiters or not - leaving a silent line that still fires (so audio plays). Absent / empty
451
- * `character` resolves to the default `SFX` (you "disable" it simply by never using that speaker). */
452
- interface CaptionDelimiters {
453
- open: string;
454
- close: string;
455
- character?: string;
456
- }
457
-
458
136
  interface BundleInspectorOptions {
459
137
  /** Where to mount the panel. If omitted, append the returned `el` yourself. */
460
138
  container?: HTMLElement;
@@ -477,7 +155,7 @@ interface BundleInspector {
477
155
  * Build a read-only panel describing a compiled bundle: what it is, what game
478
156
  * code may call on it, and what the host must supply.
479
157
  */
480
- declare function createBundleInspector(bundle: Bundle, opts?: BundleInspectorOptions): BundleInspector;
158
+ declare function createBundleInspector(bundle: Bundle$1, opts?: BundleInspectorOptions): BundleInspector;
481
159
 
482
160
  interface AudioResolver {
483
161
  /** The full path/URL of a beat's winning audio take, or null when it has none. */
@@ -490,4 +168,4 @@ interface AudioResolver {
490
168
  */
491
169
  declare function createAudioResolver(manifestJson: string, basePath: string): AudioResolver;
492
170
 
493
- export { type AudioResolver, type BundleInspector, type BundleInspectorOptions, type BundleSection, type DebugLink, type DebugLinkOptions, type DebugSocketLike, type LiveBundleResult, type PropertyInspector, type PropertyInspectorOptions, type PropertyValue, SAVE_SCHEMA, type SaveEnvelope, type StateLogger, type StateLoggerOptions, type StateValue, applyLiveBundle, createAudioResolver, createBundleInspector, createDebugLink, createPropertyInspector, createStateLogger, deserializeState, getProperty, loadState, saveState, serializeState, setProperties, setProperty, snapshotState };
171
+ export { type AudioResolver, type BundleInspector, type BundleInspectorOptions, type BundleSection, type DebugLink, type DebugLinkOptions, type DebugSocketLike, type LiveBundleResult, type PropertyInspector, type PropertyInspectorOptions, type PropertyValue, type StateLogger, type StateLoggerOptions, type StateValue, applyLiveBundle, createAudioResolver, createBundleInspector, createDebugLink, createPropertyInspector, createStateLogger, deserializeState, getProperty, loadState, saveState, serializeState, setProperties, setProperty, snapshotState };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/save.ts
2
- var SAVE_SCHEMA = "patter/save@0";
2
+ import { SAVE_SCHEMA } from "@patterkit/model";
3
3
  function saveState(engine) {
4
4
  return { schema: SAVE_SCHEMA, save: engine.saveGame() };
5
5
  }
@@ -555,3 +555,4 @@ export {
555
555
  setProperty,
556
556
  snapshotState
557
557
  };
558
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/save.ts","../src/properties.ts","../src/logger.ts","../src/debug.ts","../src/refresh.ts","../src/inspector.ts","../src/bundle-inspector.ts","../src/audio.ts"],"sourcesContent":["// ---------------------------------------------------------------------------\n// Save / load: wrap the Engine's whole-game snapshot in a tagged, versioned\n// envelope so a host can drop it into localStorage / a file and restore it\n// safely (a foreign blob throws instead of corrupting a run).\n// ---------------------------------------------------------------------------\n\nimport type { Engine } from \"@patterkit/runtime\";\nimport { SAVE_SCHEMA } from \"@patterkit/model\";\nimport type { SaveEnvelope } from \"@patterkit/model\";\n\n// The envelope (`schema` + `save`) and the save shape inside it are the FAMILY's contract, defined in\n// @patterkit/model and written identically by every Patterplay runtime. Re-exported so existing\n// imports keep working.\nexport { SAVE_SCHEMA };\nexport type { SaveEnvelope };\n\n/** Capture the whole game as a tagged envelope (wraps `engine.saveGame()`). */\nexport function saveState(engine: Engine): SaveEnvelope {\n return { schema: SAVE_SCHEMA, save: engine.saveGame() };\n}\n\n/** Restore a {@link saveState} envelope into an engine (fresh or live). Throws on a foreign/blank blob. */\nexport function loadState(engine: Engine, env: SaveEnvelope): void {\n if (!env || env.schema !== SAVE_SCHEMA || !env.save) {\n throw new Error(`loadState: not a ${SAVE_SCHEMA} envelope`);\n }\n engine.loadGame(env.save);\n}\n\n/** Serialise the whole game to a JSON string (envelope + save-game) - drop into localStorage or a file. */\nexport function serializeState(engine: Engine): string {\n return JSON.stringify(saveState(engine));\n}\n\n/** Parse + restore a {@link serializeState} string. Throws on malformed JSON or a foreign envelope. */\nexport function deserializeState(engine: Engine, json: string): void {\n loadState(engine, JSON.parse(json) as SaveEnvelope);\n}\n","// ---------------------------------------------------------------------------\n// Runtime property setters: read / write `@patter` globals, `@scene` props, or\n// a wired foreign scope at runtime - e.g. the game pushing inventory into the\n// dialogue, or reading a flag the dialogue set. Thin pass-throughs to the\n// Engine, plus a batch setter for convenience.\n// ---------------------------------------------------------------------------\n\nimport type { Engine } from \"@patterkit/runtime\";\n\n/** A property value the engine accepts (a Patter scalar: number / boolean / string / string[] flags). */\nexport type PropertyValue = Parameters<Engine[\"setProperty\"]>[1];\n\n/** Read a runtime property (`@hp`, `@scene.locked`, a foreign `@world.x`). Undefined when unset. */\nexport function getProperty(engine: Engine, ref: string): PropertyValue | undefined {\n return engine.getProperty(ref);\n}\n\n/** Set one runtime property. Mirrors `engine.setProperty`, exported here for discoverability + symmetry. */\nexport function setProperty(engine: Engine, ref: string, value: PropertyValue): void {\n engine.setProperty(ref, value);\n}\n\n/** Set many at once, e.g. `setProperties(engine, { \"@hp\": 10, \"@scene.locked\": false })`. */\nexport function setProperties(engine: Engine, values: Record<string, PropertyValue>): void {\n for (const [ref, value] of Object.entries(values)) engine.setProperty(ref, value);\n}\n","// ---------------------------------------------------------------------------\n// The Patterplay state logger: an ADAPTER over the kernel logger in\n// @wildwinter/scoperegistry, plus `logStep`, which is this product's own.\n//\n// It used to diff whole `engine.saveGame()` snapshots. That could only ever say\n// what changed BETWEEN captures, which means it could not see a value that\n// changed and changed back, could not name the reason a host attached to a\n// write, and reported a write only once something asked. The kernel logs a\n// property write as it LANDS, on the PropertyBag audit hook, and keeps the diff\n// for state that has no hook - here, the visit counts.\n//\n// The Storylet Engine's logger was already this shape; its core is what moved\n// into the kernel. Same core, two adapters.\n//\n// Paths, unchanged:\n// @patter.x the shared globals\n// @scene:<sceneId>.x the shared scene props\n// visit:<nodeId> shared visit counts\n// <flowId>/... the same three, per flow (its not-shared halves)\n// ---------------------------------------------------------------------------\n\nimport type { Engine, StepResult } from \"@patterkit/runtime\";\nimport { createStateLogger as createKernelStateLogger, diffState } from \"@wildwinter/scoperegistry\";\nimport type { LogMount, ScalarValue, StateChange, StateSnapshot } from \"@wildwinter/scoperegistry\";\n\n// Re-exported: these were declared here, and a host importing them from\n// @patterkit/play-helpers should not have to care that they moved.\nexport { diffState };\nexport type { StateChange, StateSnapshot };\n\n/** A flattened runtime-state value: a Patter scalar. The kernel calls this `ScalarValue`;\n * the alias stays because it is exported API and reads in Patter's own vocabulary. */\nexport type StateValue = ScalarValue;\n\n/** Flatten the engine's whole-game state into a path -> value map (shared scopes + every live\n * flow), off `saveGame()`. The logger no longer diffs this - it mounts the bags directly - but\n * it stays as the public \"what is the state right now\" call, and as the definition of the path\n * space the mounts compose. */\nexport function snapshotState(engine: Engine): StateSnapshot {\n const save = engine.saveGame();\n const out: StateSnapshot = {};\n for (const [name, v] of Object.entries(save.shared.patter ?? {})) out[`@patter.${name}`] = v as ScalarValue;\n for (const [scene, vals] of Object.entries(save.stageBags))\n for (const [name, v] of Object.entries(vals)) out[`@scene:${scene}.${name}`] = v as ScalarValue;\n for (const [id, n] of Object.entries(save.sharedVisits)) out[`visit:${id}`] = n;\n for (const [fid, snap] of Object.entries(save.flows)) {\n for (const [name, v] of Object.entries(snap.scopes.patter ?? {})) out[`${fid}/@patter.${name}`] = v as ScalarValue;\n for (const [scene, vals] of Object.entries(snap.sceneBags))\n for (const [name, v] of Object.entries(vals)) out[`${fid}/@scene:${scene}.${name}`] = v as ScalarValue;\n for (const [id, n] of Object.entries(snap.visits)) out[`${fid}/visit:${id}`] = n;\n }\n return out;\n}\n\nexport interface StateLoggerOptions {\n /** Where lines go; defaults to `console.log`. */\n sink?: (line: string) => void;\n /** Prefix tag for every line, e.g. the flow / save-slot name. */\n label?: string;\n}\n\nexport interface StateLogger {\n /** The current flattened state (no logging). */\n snapshot(): StateSnapshot;\n /** Everything since the last capture: the property writes already logged as they landed,\n * plus the visit counts, diffed and re-baselined. */\n capture(): StateChange[];\n /** Trace one played step (line / text / game-event / choice / end), including any `gameData`. */\n logStep(step: StepResult): void;\n /** Unhook the bag auditors. The logger is inert afterwards. */\n dispose(): void;\n}\n\nfunction describeStep(step: StepResult): string {\n switch (step.type) {\n case \"line\": return `line ${step.character ?? \"?\"}: ${JSON.stringify(step.text)}${gd(step.gameData)}`;\n case \"text\": return `text: ${JSON.stringify(step.text)}${gd(step.gameData)}`;\n case \"gameEvent\": return `game event ${step.id}${gd(step.gameData)}`;\n case \"choice\": return `choice (${step.options.length} option${step.options.length === 1 ? \"\" : \"s\"})`;\n case \"end\": return \"end\";\n }\n}\nconst gd = (data: unknown): string => (data ? ` gameData=${JSON.stringify(data)}` : \"\");\n\n/** The visit counts, which live in no bag and so have no audit hook: the kernel diffs\n * these on capture, exactly as the whole logger used to work. */\nfunction visitState(engine: Engine): StateSnapshot {\n const save = engine.saveGame();\n const out: StateSnapshot = {};\n for (const [id, n] of Object.entries(save.sharedVisits)) out[`visit:${id}`] = n;\n for (const [fid, snap] of Object.entries(save.flows)) {\n for (const [id, n] of Object.entries(snap.visits)) out[`${fid}/visit:${id}`] = n;\n }\n return out;\n}\n\n/** Create a state logger over an engine. Property writes log as they land; call `capture()`\n * after each `advance`/`choose` to pick up the visit counts and re-baseline. */\nexport function createStateLogger(engine: Engine, opts: StateLoggerOptions = {}): StateLogger {\n const tag = opts.label ? `[${opts.label}] ` : \"\";\n const kernel = createKernelStateLogger({\n // Re-read on every capture: openFlow and loadGame both replace bags, and the kernel\n // re-mounts whatever it is handed.\n mounts: (): LogMount[] => [...engine.listBags(), ...engine.flows().flatMap((f) => f.listBags())],\n extra: () => visitState(engine),\n }, { sink: opts.sink, label: tag });\n\n return {\n snapshot: () => snapshotState(engine),\n capture: () => kernel.capture(),\n dispose: () => kernel.dispose(),\n logStep(step) { (opts.sink ?? ((l: string) => console.log(l)))(`${tag}${describeStep(step)}`); },\n };\n}\n","// ---------------------------------------------------------------------------\n// Live debug link (#181) - the game-side client.\n//\n// Streams a running game's story position to Patterpad over a localhost\n// WebSocket, so the editor can follow the live cursor like a debugger. It is\n// OBSERVE-ONLY: the game stays in control; the editor is a passive mirror.\n//\n// Wire protocol `patterplay/debug@1` (one JSON object per message):\n// hello : { t:\"hello\", v:1, build, project?, flows? } - on connect\n// frame : { t:\"frame\", flow, sceneId, beatId, type, choiceId? } - per transition\n// flow : { t:\"flowOpen\" | \"flowClose\", flow } - lifecycle\n// bundle: { t:\"bundle\", v:1, build, data } - EDITOR -> game: live bundle refresh.\n// `data` is the full .patterc JSON. Pass an `onBundle` handler (or just feed it to\n// `applyLiveBundle`, which picks strings-only vs full hot swap itself), then call\n// `link.setBuild(newHash)` so the editor's match/stale pill updates.\n//\n// The link is loopback-only on the editor side (127.0.0.1), so there's no pairing\n// token - only processes on the same machine can reach it. The client never throws\n// into the game loop - a missing/closed editor just means frames go nowhere. Wire\n// it up after each advance()/choose():\n//\n// const link = createDebugLink({ build: bundle.content.hash });\n// link.flowOpened(\"main\");\n// // ...after each step:\n// link.observe(\"main\", flow.currentScene, step.id ?? null, step.type);\n// ---------------------------------------------------------------------------\n\n/** A minimal structural type for a WebSocket implementation (browsers + Node 21+ have a global one). */\nexport interface DebugSocketLike {\n readyState: number;\n send(data: string): void;\n close(): void;\n addEventListener(type: \"open\" | \"close\" | \"error\", listener: () => void): void;\n /** Incoming editor messages (live bundle refresh). Optional so a bare-bones send-only socket still fits. */\n addEventListener(type: \"message\", listener: (ev: { data: unknown }) => void): void;\n}\ntype DebugSocketCtor = new (url: string) => DebugSocketLike;\n\nexport interface DebugLinkOptions {\n /** The running bundle's build identity - pass `bundle.content.hash`. Lets the editor detect a stale build. */\n build: string;\n /** Optional project name, shown in the editor's debug panel. */\n project?: string;\n /** Editor WebSocket URL. Default `ws://127.0.0.1:4471`. */\n url?: string;\n /** A WebSocket constructor to use instead of the global one (Node < 21, or tests with `ws`). */\n WebSocket?: DebugSocketCtor;\n /** Live bundle refresh: the editor pushed a freshly compiled bundle. `data` is the .patterc JSON;\n * hand it (with your current engine + bundle) to `applyLiveBundle`, re-bind your flow handles if it\n * hot-swapped, then call `link.setBuild(build)`. Never called with malformed payloads. */\n onBundle?: (msg: { build: string; data: string }) => void;\n}\n\nexport interface DebugLink {\n /** Tell the editor a flow opened (so it can list it in the follow selector). */\n flowOpened(flowId: string): void;\n /** Report the current position of a flow - call after each advance()/choose(). */\n observe(flowId: string, sceneId: string | null, beatId: string | null, type: string, choiceId?: string): void;\n /** Tell the editor a flow closed. */\n flowClosed(flowId: string): void;\n /** After applying a pushed bundle: report the build now running (re-hellos, so the editor's\n * match/stale pill updates and it stops re-pushing the same bundle). */\n setBuild(build: string): void;\n /** Close the link. */\n close(): void;\n}\n\nconst OPEN = 1; // WebSocket.OPEN\n\n/**\n * Open a live debug link to Patterpad. Returns a handle whose calls are no-ops once the editor disconnects\n * or if it was never listening - safe to leave wired into a shipping build behind a flag.\n */\nexport function createDebugLink(opts: DebugLinkOptions): DebugLink {\n const url = opts.url ?? \"ws://127.0.0.1:4471\";\n const Ctor: DebugSocketCtor | undefined = opts.WebSocket ?? (globalThis as { WebSocket?: DebugSocketCtor }).WebSocket;\n const flows = new Set<string>();\n let queue: string[] = [];\n let sock: DebugSocketLike | null = null;\n let closed = false;\n let build = opts.build; // mutable: setBuild() after a live bundle refresh lands\n\n const flush = (): void => {\n if (!sock || sock.readyState !== OPEN) return;\n for (const m of queue) { try { sock.send(m); } catch { /* socket went away */ } }\n queue = [];\n };\n const post = (msg: object): void => {\n if (closed) return;\n queue.push(JSON.stringify(msg));\n flush();\n };\n\n if (!Ctor) {\n // No WebSocket available (old Node, no impl passed) - degrade to a silent no-op link.\n return { flowOpened() {}, observe() {}, flowClosed() {}, setBuild() {}, close() { closed = true; } };\n }\n\n const sendHello = (): void => {\n const hello = JSON.stringify({ t: \"hello\", v: 1, build, project: opts.project, flows: [...flows] });\n try { sock?.send(hello); } catch { /* race: closed immediately */ }\n };\n\n try {\n sock = new Ctor(url);\n sock.addEventListener(\"open\", () => {\n // Handshake first, so the editor can verify the build + seed the flow list before frames arrive.\n sendHello();\n flush();\n });\n // Live bundle refresh: the editor pushed a new bundle. Validate the shape here so the host's\n // handler never sees a malformed payload; everything else the editor might send is ignored.\n sock.addEventListener(\"message\", (ev: { data: unknown }) => {\n if (!opts.onBundle || typeof ev.data !== \"string\") return;\n try {\n const msg = JSON.parse(ev.data) as Record<string, unknown>;\n if (msg.t === \"bundle\" && typeof msg.build === \"string\" && typeof msg.data === \"string\") {\n opts.onBundle({ build: msg.build, data: msg.data });\n }\n } catch { /* not for us */ }\n });\n sock.addEventListener(\"error\", () => { /* editor not listening - stay a no-op */ });\n sock.addEventListener(\"close\", () => { sock = null; });\n } catch { sock = null; } // malformed URL etc. - never throw into the game\n\n return {\n flowOpened(flowId: string): void { flows.add(flowId); post({ t: \"flowOpen\", flow: flowId }); },\n flowClosed(flowId: string): void { flows.delete(flowId); post({ t: \"flowClose\", flow: flowId }); },\n observe(flowId: string, sceneId: string | null, beatId: string | null, type: string, choiceId?: string): void {\n // A flow reports itself. `flowOpened` is the host's job and nothing could check it, so a game\n // that opened a flow and forgot to announce it left the editor's list short - and the omission\n // survived a reconnect, because the hello sends this set. Observing a flow we have not seen\n // announces it first, which makes the host's call a courtesy (it lists the flow before its\n // first step) rather than something to remember.\n if (!flows.has(flowId)) { flows.add(flowId); post({ t: \"flowOpen\", flow: flowId }); }\n post({ t: \"frame\", flow: flowId, sceneId, beatId, type, choiceId });\n },\n setBuild(next: string): void {\n if (closed || next === build) return;\n build = next;\n if (sock && sock.readyState === OPEN) sendHello(); // re-handshake: the editor re-reads the build\n },\n close(): void { closed = true; queue = []; try { sock?.close(); } catch { /* already gone */ } sock = null; },\n };\n}\n","// ---------------------------------------------------------------------------\n// Live bundle refresh (design/proposals/live-bundle-refresh.md) - the game-side\n// applier. The editor pushes a freshly compiled bundle over the debug link\n// (createDebugLink's `onBundle`); this helper picks the right tier and applies\n// it:\n// - same structureHash -> tier 1: engine.replaceStrings() - nothing restarts.\n// - changed structure -> tier 2: engine.hotSwap() - the run carried over,\n// content drift resolved by the save system (§9.8).\n// Returns the engine to keep using (the SAME one for \"text\", a REPLACEMENT for\n// \"structure\" - re-bind your Flow handles via engine.getFlow(id)) plus the\n// parsed bundle for the next comparison. Wire-up:\n//\n// let { engine, bundle } = boot();\n// const link = createDebugLink({\n// build: bundle.content.hash!,\n// onBundle: ({ build, data }) => {\n// const r = applyLiveBundle(engine, bundle, data);\n// engine = r.engine; bundle = r.bundle;\n// if (r.kind === \"structure\") flow = engine.getFlow(\"main\")!;\n// link.setBuild(build);\n// },\n// });\n// ---------------------------------------------------------------------------\n\nimport { Engine } from \"@patterkit/runtime\";\nimport type { Bundle } from \"@patterkit/runtime\";\n\nexport interface LiveBundleResult {\n /** The engine to keep using: the same instance for a \"text\" swap, a replacement for \"structure\". */\n engine: Engine;\n /** The parsed pushed bundle - hold on to it for the next apply's comparison. */\n bundle: Bundle;\n /** Which tier applied: \"text\" (strings-only, nothing restarted) or \"structure\" (full hot swap). */\n kind: \"text\" | \"structure\";\n}\n\n/**\n * Apply a bundle the editor pushed over the debug link. `current` is the bundle `engine` is running\n * (needed for the structure-hash comparison); `data` is the pushed .patterc JSON. Throws only on\n * unparseable JSON - a structural swap's edge cases are absorbed by the §9.8 drift policy inside\n * `hotSwap`, which never throws for ordinary edits.\n */\nexport function applyLiveBundle(engine: Engine, current: Bundle, data: string): LiveBundleResult {\n const next = JSON.parse(data) as Bundle;\n // Same structure = a text-only edit: swap the string tables in place and keep everything running.\n // Missing structureHash on either side (an older compiler) falls through to the full swap - safe,\n // just less gentle than it could be.\n const sameStructure = current.content.structureHash !== undefined\n && current.content.structureHash === next.content.structureHash;\n if (sameStructure) {\n engine.replaceStrings(next);\n return { engine, bundle: next, kind: \"text\" };\n }\n return { engine: engine.hotSwap(next), bundle: next, kind: \"structure\" };\n}\n","/// <reference lib=\"dom\" />\n// ---------------------------------------------------------------------------\n// A live @patter property inspector for the browser: a small DOM panel that\n// watches AND edits a running Engine's shared @patter properties. Type-aware\n// editors (bool / number / text / enum / flags), a reset-to-default per row, and\n// a poll that refreshes values WITHOUT clobbering the field you're editing.\n//\n// The JS parity of the Unity PatterStateWindow / Godot PatterStatePanel. Those\n// use a PatterDebug registry because the editor window is separate from the game;\n// here the game runs in-process, so you just pass the engine directly:\n//\n// const inspector = createPropertyInspector(engine, { container: document.body });\n// // ...later: inspector.destroy();\n// ---------------------------------------------------------------------------\n\nimport type { Engine, PropertyRow } from \"@patterkit/runtime\";\nimport { serializeState, deserializeState } from \"./save.js\";\nimport type { PropertyValue } from \"./properties.js\";\n\nexport interface PropertyInspectorOptions {\n /** Where to mount the panel. If omitted, append the returned `el` yourself. */\n container?: HTMLElement;\n /** Panel heading. Default \"Runtime state\". */\n title?: string;\n /** Live-refresh interval in ms; 0 disables polling (call `refresh()` yourself). Default 250. */\n pollMs?: number;\n}\n\nexport interface PropertyInspector {\n /** The panel root (already inside `container` if you passed one). */\n readonly el: HTMLElement;\n /** Re-read every property and update the editors, skipping the field you're editing. */\n refresh(): void;\n /** Stop polling and remove the panel from the DOM. */\n destroy(): void;\n}\n\nconst STYLE_ID = \"pp-inspector-style\";\nconst CSS = `\n.pp-insp{font:13px/1.4 ui-sans-serif,system-ui,sans-serif;color:#15201e;background:#f4efe6;border:1px solid #cfc7b8;border-radius:10px;padding:.6rem .7rem;max-width:22rem;box-shadow:0 6px 20px rgba(21,32,30,.12)}\n.pp-insp h4{margin:0 0 .4rem;font:600 .72rem/1 ui-sans-serif,system-ui,sans-serif;letter-spacing:.08em;text-transform:uppercase;color:#5c6b62}\n.pp-insp-empty{color:#8a9691;font-style:italic}\n.pp-insp-io { display: flex; gap: 6px; margin: 0 0 8px; }\n .pp-insp-io button { font: inherit; padding: 2px 8px; cursor: pointer; }\n .pp-insp-row{display:flex;align-items:center;gap:.4rem;margin:.18rem 0}\n.pp-insp-ref{flex:0 0 8rem;font-family:ui-monospace,monospace;font-size:.78rem;color:#214f4b;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.pp-insp-ctl{flex:1;min-width:0;display:flex}\n.pp-insp-ctl input[type=text],.pp-insp-ctl input[type=number],.pp-insp-ctl select{width:100%;box-sizing:border-box;font:inherit;padding:.15rem .3rem;border:1px solid #cfc7b8;border-radius:6px;background:#fff;color:inherit}\n.pp-insp-reset{flex:0 0 auto;border:1px solid #cfc7b8;background:#fff;border-radius:6px;cursor:pointer;color:#5c6b62;width:1.6rem;height:1.6rem;line-height:1;padding:0}\n.pp-insp-reset:disabled{opacity:.35;cursor:default}\n`;\n\nfunction injectStyle(doc: Document): void {\n if (doc.getElementById(STYLE_ID)) return;\n const s = doc.createElement(\"style\");\n s.id = STYLE_ID;\n s.textContent = CSS;\n (doc.head ?? doc.documentElement).appendChild(s);\n}\n\n/** Has the DISPLAYED value changed? Order-sensitive on purpose, and deliberately\n * NOT the language's value equality, which compares flags as a set: this asks\n * whether the row needs redrawing, and the row renders the list in its stored\n * order, so a reordering is a change here even though it is not a change to\n * what the value means. */\nfunction sameValue(a: PropertyValue | undefined, b: PropertyValue | undefined): boolean {\n if (Array.isArray(a) && Array.isArray(b)) return a.length === b.length && a.every((x, i) => x === b[i]);\n return a === b;\n}\n\nexport function createPropertyInspector(engine: Engine, opts: PropertyInspectorOptions = {}): PropertyInspector {\n const doc = opts.container?.ownerDocument ?? document;\n injectStyle(doc);\n\n const el = doc.createElement(\"div\");\n el.className = \"pp-insp\";\n const heading = doc.createElement(\"h4\");\n heading.textContent = opts.title ?? \"Runtime state\";\n const list = doc.createElement(\"div\");\n\n // Save/Load the whole run as a patter/save@0 envelope file - the parity of Unity's\n // PatterStateWindow buttons, Godot's state-panel dialogs, and Unreal's Slate panel.\n const io = doc.createElement(\"div\");\n io.className = \"pp-insp-io\";\n const saveBtn = doc.createElement(\"button\");\n saveBtn.type = \"button\";\n saveBtn.textContent = \"Save state\\u2026\";\n saveBtn.addEventListener(\"click\", () => {\n const blob = new Blob([serializeState(engine)], { type: \"application/json\" });\n const a = doc.createElement(\"a\");\n a.href = URL.createObjectURL(blob);\n a.download = \"save.patterstate\";\n a.click();\n URL.revokeObjectURL(a.href);\n });\n const loadBtn = doc.createElement(\"button\");\n loadBtn.type = \"button\";\n loadBtn.textContent = \"Load state\\u2026\";\n loadBtn.addEventListener(\"click\", () => {\n const input = doc.createElement(\"input\");\n input.type = \"file\";\n input.accept = \".patterstate,application/json\";\n input.addEventListener(\"change\", () => {\n const file = input.files?.[0];\n if (!file) return;\n void file.text().then((text) => {\n try { deserializeState(engine, text); refresh(); }\n catch (err) { console.error(\"Load state failed:\", err instanceof Error ? err.message : err); }\n });\n });\n input.click();\n });\n io.append(saveBtn, loadBtn);\n el.append(heading, io, list);\n\n const rowRefreshers: Array<() => void> = [];\n\n const buildRow = (row: PropertyRow): void => {\n const r = doc.createElement(\"div\");\n r.className = \"pp-insp-row\";\n const label = doc.createElement(\"span\");\n label.className = \"pp-insp-ref\";\n label.textContent = row.path;\n label.title = row.path;\n const ctl = doc.createElement(\"div\");\n ctl.className = \"pp-insp-ctl\";\n const reset = doc.createElement(\"button\");\n reset.className = \"pp-insp-reset\";\n reset.type = \"button\";\n reset.textContent = \"↺\"; // ↺\n reset.title = \"Reset to default\";\n r.append(label, ctl, reset);\n list.appendChild(r);\n\n // `read` pushes the live engine value into the editor, but never while that editor has focus\n // (so it can't wipe what you're typing). `syncReset` disables the ↺ when the value is the default.\n let read: () => void;\n const commit = (v: PropertyValue): void => { engine.setProperty(row.path, v); syncReset(); };\n const focused = (node: Element): boolean => doc.activeElement === node;\n function syncReset(): void { reset.disabled = sameValue(engine.getProperty(row.path), row.default); }\n reset.addEventListener(\"click\", () => { engine.setProperty(row.path, row.default); read(); syncReset(); });\n\n if (row.type === \"boolean\") {\n const cb = doc.createElement(\"input\");\n cb.type = \"checkbox\";\n cb.addEventListener(\"change\", () => commit(cb.checked));\n ctl.appendChild(cb);\n read = () => { if (!focused(cb)) cb.checked = engine.getProperty(row.path) === true; };\n } else if (row.type === \"number\") {\n const inp = doc.createElement(\"input\");\n inp.type = \"number\";\n inp.addEventListener(\"change\", () => commit(Number(inp.value)));\n ctl.appendChild(inp);\n read = () => { if (!focused(inp)) inp.value = String(engine.getProperty(row.path) ?? \"\"); };\n } else if (row.type === \"enum\" || row.type === \"quality\") {\n // A quality edits as a dropdown of its STAGES - the ladder is closed, like an enum's values.\n const sel = doc.createElement(\"select\");\n for (const v of (row.type === \"quality\" ? row.stages : row.values) ?? []) {\n const o = doc.createElement(\"option\");\n o.value = v; o.textContent = v;\n sel.appendChild(o);\n }\n sel.addEventListener(\"change\", () => commit(sel.value));\n ctl.appendChild(sel);\n read = () => { if (!focused(sel)) sel.value = String(engine.getProperty(row.path) ?? \"\"); };\n } else if (row.type === \"flags\") {\n const inp = doc.createElement(\"input\");\n inp.type = \"text\";\n inp.placeholder = \"comma, separated, flags\";\n inp.addEventListener(\"change\", () => commit(inp.value.split(\",\").map((s) => s.trim()).filter((s) => s.length > 0)));\n ctl.appendChild(inp);\n read = () => { if (!focused(inp)) { const v = engine.getProperty(row.path); inp.value = Array.isArray(v) ? v.join(\", \") : \"\"; } };\n } else {\n // string (and any unrecognised type) -> a text field\n const inp = doc.createElement(\"input\");\n inp.type = \"text\";\n inp.addEventListener(\"change\", () => commit(inp.value));\n ctl.appendChild(inp);\n read = () => { if (!focused(inp)) inp.value = String(engine.getProperty(row.path) ?? \"\"); };\n }\n\n read();\n syncReset();\n rowRefreshers.push(() => { read(); syncReset(); });\n };\n\n // Properties are fixed for a bundle, so build the rows once; polling just refreshes their values.\n const props = engine.listProperties();\n if (props.length === 0) {\n const empty = doc.createElement(\"div\");\n empty.className = \"pp-insp-empty\";\n empty.textContent = \"No @patter properties.\";\n list.appendChild(empty);\n } else {\n for (const row of props) buildRow(row);\n }\n\n const refresh = (): void => { for (const fn of rowRefreshers) fn(); };\n\n opts.container?.appendChild(el);\n const pollMs = opts.pollMs ?? 250;\n let timer: ReturnType<typeof setInterval> | undefined;\n if (pollMs > 0) timer = setInterval(refresh, pollMs);\n\n return {\n el,\n refresh,\n destroy() { if (timer !== undefined) clearInterval(timer); el.remove(); },\n };\n}\n","/// <reference lib=\"dom\" />\n// ---------------------------------------------------------------------------\n// The bundle inspector's VIEW, for the web: a read-only panel over\n// `describeBundle`, in the same visual grammar as the live property inspector.\n//\n// The other three runtimes hang their view off an imported asset - a Unity\n// CustomEditor, an Unreal details customisation, a Godot EditorInspectorPlugin.\n// JS has no asset pipeline, so there is no inspector to extend and the summary\n// function IS the surface. This exists because \"the function is the surface\"\n// leaves the JS side without the thing the other three give you for free: a\n// place to LOOK at a bundle. A drop-in page can now do\n//\n// const panel = createBundleInspector(bundle, { container: document.body });\n// // ...later: panel.destroy();\n//\n// Read-only on purpose. The live inspector edits because a running game has\n// state worth changing; this describes an artefact, and there is nothing here a\n// reader could sensibly write to.\n// ---------------------------------------------------------------------------\n\nimport { describeBundle } from \"@patterkit/runtime\";\nimport type { Bundle } from \"@patterkit/model\";\nimport type { BundleDescription, PropertySummary } from \"@patterkit/runtime\";\n\nexport interface BundleInspectorOptions {\n /** Where to mount the panel. If omitted, append the returned `el` yourself. */\n container?: HTMLElement;\n /** Panel heading. Default \"Bundle\". */\n title?: string;\n /** Sections open on mount. Default: identity and addresses, the two an\n * integrator reaches for first; the rest are a click away. */\n open?: BundleSection[];\n}\n\nexport type BundleSection = \"identity\" | \"addresses\" | \"hostScopes\" | \"properties\" | \"gameData\" | \"counts\";\n\nexport interface BundleInspector {\n /** The panel root (already inside `container` if you passed one). */\n readonly el: HTMLElement;\n /** The description the panel is showing, for a caller that wants the data too. */\n readonly description: BundleDescription;\n /** Remove the panel from the DOM. */\n destroy(): void;\n}\n\nconst STYLE_ID = \"pp-bundle-style\";\n// Deliberately the property inspector's palette and metrics: the two panels are\n// often on the same page, and a second look-and-feel would read as a second tool.\nconst CSS = `\n.pp-bundle{font:13px/1.4 ui-sans-serif,system-ui,sans-serif;color:#15201e;background:#f4efe6;border:1px solid #cfc7b8;border-radius:10px;padding:.6rem .7rem;max-width:26rem;box-shadow:0 6px 20px rgba(21,32,30,.12)}\n.pp-bundle h4{margin:0 0 .4rem;font:600 .72rem/1 ui-sans-serif,system-ui,sans-serif;letter-spacing:.08em;text-transform:uppercase;color:#5c6b62}\n.pp-bundle details{border-top:1px solid #e3dccf;padding:.3rem 0}\n.pp-bundle details:first-of-type{border-top:0}\n.pp-bundle summary{cursor:pointer;font-weight:600;color:#214f4b;list-style:none}\n.pp-bundle summary::-webkit-details-marker{display:none}\n.pp-bundle summary::before{content:\"\\\\25B8\";display:inline-block;width:1rem;color:#8a9691}\n.pp-bundle details[open]>summary::before{content:\"\\\\25BE\"}\n.pp-bundle-count{color:#8a9691;font-weight:400}\n.pp-bundle-row{display:flex;gap:.4rem;margin:.16rem 0 .16rem 1rem}\n.pp-bundle-key{flex:0 0 8rem;color:#5c6b62}\n.pp-bundle-val,.pp-bundle-addr{font-family:ui-monospace,monospace;font-size:.78rem;color:#214f4b;word-break:break-all}\n.pp-bundle-sub{margin-left:2rem}\n.pp-bundle-empty{color:#8a9691;font-style:italic;margin-left:1rem}\n.pp-bundle-warn{color:#8a3a2f;font-weight:600}\n.pp-bundle-tag{font-size:.7rem;color:#5c6b62;border:1px solid #cfc7b8;border-radius:5px;padding:0 .25rem;margin-left:.3rem}\n`;\n\nfunction injectStyle(doc: Document): void {\n if (doc.getElementById(STYLE_ID)) return;\n const s = doc.createElement(\"style\");\n s.id = STYLE_ID;\n s.textContent = CSS;\n (doc.head ?? doc.documentElement).appendChild(s);\n}\n\nconst el = (doc: Document, tag: string, cls?: string, text?: string): HTMLElement => {\n const e = doc.createElement(tag);\n if (cls) e.className = cls;\n if (text !== undefined) e.textContent = text;\n return e;\n};\n\n/** One \"key: value\" line. */\nfunction row(doc: Document, key: string, value: string, valueClass = \"pp-bundle-val\"): HTMLElement {\n const r = el(doc, \"div\", \"pp-bundle-row\");\n r.append(el(doc, \"span\", \"pp-bundle-key\", key), el(doc, \"span\", valueClass, value));\n return r;\n}\n\n/** A property line: the name, its type, and whether the HOST must supply a value.\n * \"no default\" is the part an integrator is actually scanning for. */\nfunction propertyRow(doc: Document, p: PropertySummary): HTMLElement {\n const r = el(doc, \"div\", \"pp-bundle-row\");\n r.append(el(doc, \"span\", \"pp-bundle-key pp-bundle-addr\", p.name));\n const meta = el(doc, \"span\", \"pp-bundle-val\", p.type);\n if (!p.hasDefault) meta.append(el(doc, \"span\", \"pp-bundle-tag\", \"no default\"));\n r.append(meta);\n return r;\n}\n\nfunction section(doc: Document, name: BundleSection, label: string, count: number | null, open: boolean): HTMLDetailsElement {\n const d = doc.createElement(\"details\");\n d.dataset[\"section\"] = name;\n d.open = open;\n const s = doc.createElement(\"summary\");\n s.textContent = label;\n if (count !== null) s.append(el(doc, \"span\", \"pp-bundle-count\", ` ${count}`));\n d.append(s);\n return d;\n}\n\n/**\n * Build a read-only panel describing a compiled bundle: what it is, what game\n * code may call on it, and what the host must supply.\n */\nexport function createBundleInspector(bundle: Bundle, opts: BundleInspectorOptions = {}): BundleInspector {\n const doc = opts.container?.ownerDocument ?? document;\n injectStyle(doc);\n const d = describeBundle(bundle);\n const open = new Set<BundleSection>(opts.open ?? [\"identity\", \"addresses\"]);\n\n const root = el(doc, \"div\", \"pp-bundle\");\n root.append(el(doc, \"h4\", undefined, opts.title ?? \"Bundle\"));\n\n // --- identity ------------------------------------------------------------\n const id = section(doc, \"identity\", d.identity.project || \"(unnamed project)\", null, open.has(\"identity\"));\n if (d.identity.version) id.append(row(doc, \"version\", d.identity.version));\n id.append(row(doc, \"schema\", d.identity.schema));\n id.append(row(doc, \"locales\", `${d.identity.defaultLocale}${d.identity.locales.length > 1 ? ` (+${d.identity.locales.length - 1})` : \"\"}`));\n id.append(row(doc, \"strings\", d.identity.localisation));\n if (d.identity.voiced) id.append(row(doc, \"voiced\", \"yes\"));\n if (d.identity.hash) id.append(row(doc, \"hash\", d.identity.hash));\n // Equal structureHash + a different hash = a text-only edit, which is what makes\n // a live hot-swap safe. Both are shown so an integrator can tell those apart.\n if (d.identity.structureHash) id.append(row(doc, \"structure\", d.identity.structureHash));\n if (d.identity.sourceDebug) {\n id.append(row(doc, \"build\", \"SOURCE DEBUG - not shippable\", \"pp-bundle-val pp-bundle-warn\"));\n }\n root.append(id);\n\n // --- addresses -----------------------------------------------------------\n const addr = section(doc, \"addresses\", \"Addresses\", d.addresses.length, open.has(\"addresses\"));\n if (!d.addresses.length) addr.append(el(doc, \"div\", \"pp-bundle-empty\", \"no scenes\"));\n for (const a of d.addresses) {\n const r = el(doc, \"div\", \"pp-bundle-row\");\n r.append(el(doc, \"span\", \"pp-bundle-key pp-bundle-addr\", a.gameId), el(doc, \"span\", \"pp-bundle-val\", a.name));\n addr.append(r);\n // Nested, because a block address is scene-scoped: the pair is the address.\n for (const b of a.blocks) {\n const br = el(doc, \"div\", \"pp-bundle-row pp-bundle-sub\");\n br.append(el(doc, \"span\", \"pp-bundle-key pp-bundle-addr\", b.gameId), el(doc, \"span\", \"pp-bundle-val\", b.name));\n addr.append(br);\n }\n }\n root.append(addr);\n\n // --- host scopes ---------------------------------------------------------\n // Counted in PROPERTIES rather than scopes: the heading says \"properties\", and a\n // reader comparing it with the rows below should not have to work out which it meant.\n // An opaque scope contributes none, and says so on its own row.\n const hostCount = d.hostScopes.reduce((n, s) => n + s.properties.length, 0);\n const host = section(doc, \"hostScopes\", \"Host properties\", hostCount, open.has(\"hostScopes\"));\n if (!d.hostScopes.length) host.append(el(doc, \"div\", \"pp-bundle-empty\", \"the game supplies nothing\"));\n for (const s of d.hostScopes) {\n const head = el(doc, \"div\", \"pp-bundle-row\");\n head.append(el(doc, \"span\", \"pp-bundle-key pp-bundle-addr\", `@${s.token}`));\n const meta = el(doc, \"span\", \"pp-bundle-val\", s.opaque ? \"any name, unchecked\" : `${s.properties.length} declared`);\n if (!s.writable) meta.append(el(doc, \"span\", \"pp-bundle-tag\", \"read-only\"));\n head.append(meta);\n host.append(head);\n for (const p of s.properties) {\n const pr = propertyRow(doc, p);\n pr.classList.add(\"pp-bundle-sub\");\n host.append(pr);\n }\n }\n root.append(host);\n\n // --- owned properties ----------------------------------------------------\n const ownedCount = d.properties.patter.length + d.properties.scene.reduce((n, s) => n + s.properties.length, 0);\n const owned = section(doc, \"properties\", \"Story properties\", ownedCount, open.has(\"properties\"));\n if (!ownedCount) owned.append(el(doc, \"div\", \"pp-bundle-empty\", \"none declared\"));\n for (const p of d.properties.patter) owned.append(propertyRow(doc, p));\n for (const s of d.properties.scene) {\n owned.append(row(doc, `@scene`, s.gameId, \"pp-bundle-val pp-bundle-addr\"));\n for (const p of s.properties) {\n const pr = propertyRow(doc, p);\n pr.classList.add(\"pp-bundle-sub\");\n owned.append(pr);\n }\n }\n root.append(owned);\n\n // --- gameData ------------------------------------------------------------\n if (d.gameData.length) {\n const gd = section(doc, \"gameData\", \"Game data\", d.gameData.reduce((n, g) => n + g.fields.length, 0), open.has(\"gameData\"));\n for (const g of d.gameData) {\n gd.append(row(doc, \"on\", g.kind));\n for (const f of g.fields) {\n const fr = el(doc, \"div\", \"pp-bundle-row pp-bundle-sub\");\n fr.append(el(doc, \"span\", \"pp-bundle-key pp-bundle-addr\", f.name), el(doc, \"span\", \"pp-bundle-val\", f.type));\n gd.append(fr);\n }\n }\n root.append(gd);\n }\n\n // --- counts --------------------------------------------------------------\n const counts = section(doc, \"counts\", \"Counts\", null, open.has(\"counts\"));\n for (const [key, value] of Object.entries(d.counts)) counts.append(row(doc, key, String(value)));\n root.append(counts);\n\n opts.container?.append(root);\n return {\n el: root,\n description: d,\n destroy() { root.remove(); },\n };\n}\n","// ---------------------------------------------------------------------------\n// Audio resolver (#206): map a beat id to the path/URL of its winning audio\n// take, using the `patteraudio.json` manifest Patterpad (or the CLI) emits next\n// to the Audio Folders. It RESOLVES ONLY - playback stays yours (Web Audio, an\n// <audio> element, etc.), which can't be portable across platforms anyway.\n//\n// The manifest already encodes the highest-rung \"winner\" per beat, so there's no\n// folder search at runtime. Deploy your audio folder somewhere your game can read\n// (e.g. under /public), fetch the manifest once, and:\n//\n// const audio = createAudioResolver(manifestJson, \"audio\"); // base = where the folder is served\n// const src = audio.resolve(step.id); // \"audio/final/L1.wav\", or null when the beat has no recording\n// if (src) new Audio(src).play();\n// ---------------------------------------------------------------------------\n\nexport interface AudioResolver {\n /** The full path/URL of a beat's winning audio take, or null when it has none. */\n resolve(beatId: string): string | null;\n}\n\ninterface AudioManifest {\n schema?: string;\n clips?: Record<string, { file: string; status?: string }>;\n}\n\n/**\n * Build an audio resolver from a `patteraudio.json` manifest string plus the base path/URL its files live\n * under (wherever you deployed the audio folder). `resolve(beatId)` joins the base with the winning clip's\n * relative path, or returns null when the beat has no recording. Never throws on a missing beat.\n */\nexport function createAudioResolver(manifestJson: string, basePath: string): AudioResolver {\n const manifest = JSON.parse(manifestJson) as AudioManifest;\n const clips = manifest.clips ?? {};\n const base = basePath.replace(/[/\\\\]+$/, \"\"); // trim trailing slash(es); we add exactly one when joining\n return {\n resolve(beatId: string): string | null {\n const clip = clips[beatId];\n if (!clip || !clip.file) return null;\n return base ? `${base}/${clip.file}` : clip.file;\n },\n };\n}\n"],"mappings":";AAOA,SAAS,mBAAmB;AAUrB,SAAS,UAAU,QAA8B;AACtD,SAAO,EAAE,QAAQ,aAAa,MAAM,OAAO,SAAS,EAAE;AACxD;AAGO,SAAS,UAAU,QAAgB,KAAyB;AACjE,MAAI,CAAC,OAAO,IAAI,WAAW,eAAe,CAAC,IAAI,MAAM;AACnD,UAAM,IAAI,MAAM,oBAAoB,WAAW,WAAW;AAAA,EAC5D;AACA,SAAO,SAAS,IAAI,IAAI;AAC1B;AAGO,SAAS,eAAe,QAAwB;AACrD,SAAO,KAAK,UAAU,UAAU,MAAM,CAAC;AACzC;AAGO,SAAS,iBAAiB,QAAgB,MAAoB;AACnE,YAAU,QAAQ,KAAK,MAAM,IAAI,CAAiB;AACpD;;;ACxBO,SAAS,YAAY,QAAgB,KAAwC;AAClF,SAAO,OAAO,YAAY,GAAG;AAC/B;AAGO,SAAS,YAAY,QAAgB,KAAa,OAA4B;AACnF,SAAO,YAAY,KAAK,KAAK;AAC/B;AAGO,SAAS,cAAc,QAAgB,QAA6C;AACzF,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,EAAG,QAAO,YAAY,KAAK,KAAK;AAClF;;;ACHA,SAAS,qBAAqB,yBAAyB,iBAAiB;AAgBjE,SAAS,cAAc,QAA+B;AAC3D,QAAM,OAAO,OAAO,SAAS;AAC7B,QAAM,MAAqB,CAAC;AAC5B,aAAW,CAAC,MAAM,CAAC,KAAK,OAAO,QAAQ,KAAK,OAAO,UAAU,CAAC,CAAC,EAAG,KAAI,WAAW,IAAI,EAAE,IAAI;AAC3F,aAAW,CAAC,OAAO,IAAI,KAAK,OAAO,QAAQ,KAAK,SAAS;AACvD,eAAW,CAAC,MAAM,CAAC,KAAK,OAAO,QAAQ,IAAI,EAAG,KAAI,UAAU,KAAK,IAAI,IAAI,EAAE,IAAI;AACjF,aAAW,CAAC,IAAI,CAAC,KAAK,OAAO,QAAQ,KAAK,YAAY,EAAG,KAAI,SAAS,EAAE,EAAE,IAAI;AAC9E,aAAW,CAAC,KAAK,IAAI,KAAK,OAAO,QAAQ,KAAK,KAAK,GAAG;AACpD,eAAW,CAAC,MAAM,CAAC,KAAK,OAAO,QAAQ,KAAK,OAAO,UAAU,CAAC,CAAC,EAAG,KAAI,GAAG,GAAG,YAAY,IAAI,EAAE,IAAI;AAClG,eAAW,CAAC,OAAO,IAAI,KAAK,OAAO,QAAQ,KAAK,SAAS;AACvD,iBAAW,CAAC,MAAM,CAAC,KAAK,OAAO,QAAQ,IAAI,EAAG,KAAI,GAAG,GAAG,WAAW,KAAK,IAAI,IAAI,EAAE,IAAI;AACxF,eAAW,CAAC,IAAI,CAAC,KAAK,OAAO,QAAQ,KAAK,MAAM,EAAG,KAAI,GAAG,GAAG,UAAU,EAAE,EAAE,IAAI;AAAA,EACjF;AACA,SAAO;AACT;AAqBA,SAAS,aAAa,MAA0B;AAC9C,UAAQ,KAAK,MAAM;AAAA,IACjB,KAAK;AAAQ,aAAO,QAAQ,KAAK,aAAa,GAAG,KAAK,KAAK,UAAU,KAAK,IAAI,CAAC,GAAG,GAAG,KAAK,QAAQ,CAAC;AAAA,IACnG,KAAK;AAAQ,aAAO,SAAS,KAAK,UAAU,KAAK,IAAI,CAAC,GAAG,GAAG,KAAK,QAAQ,CAAC;AAAA,IAC1E,KAAK;AAAa,aAAO,cAAc,KAAK,EAAE,GAAG,GAAG,KAAK,QAAQ,CAAC;AAAA,IAClE,KAAK;AAAU,aAAO,WAAW,KAAK,QAAQ,MAAM,UAAU,KAAK,QAAQ,WAAW,IAAI,KAAK,GAAG;AAAA,IAClG,KAAK;AAAO,aAAO;AAAA,EACrB;AACF;AACA,IAAM,KAAK,CAAC,SAA2B,OAAO,aAAa,KAAK,UAAU,IAAI,CAAC,KAAK;AAIpF,SAAS,WAAW,QAA+B;AACjD,QAAM,OAAO,OAAO,SAAS;AAC7B,QAAM,MAAqB,CAAC;AAC5B,aAAW,CAAC,IAAI,CAAC,KAAK,OAAO,QAAQ,KAAK,YAAY,EAAG,KAAI,SAAS,EAAE,EAAE,IAAI;AAC9E,aAAW,CAAC,KAAK,IAAI,KAAK,OAAO,QAAQ,KAAK,KAAK,GAAG;AACpD,eAAW,CAAC,IAAI,CAAC,KAAK,OAAO,QAAQ,KAAK,MAAM,EAAG,KAAI,GAAG,GAAG,UAAU,EAAE,EAAE,IAAI;AAAA,EACjF;AACA,SAAO;AACT;AAIO,SAAS,kBAAkB,QAAgB,OAA2B,CAAC,GAAgB;AAC5F,QAAM,MAAM,KAAK,QAAQ,IAAI,KAAK,KAAK,OAAO;AAC9C,QAAM,SAAS,wBAAwB;AAAA;AAAA;AAAA,IAGrC,QAAQ,MAAkB,CAAC,GAAG,OAAO,SAAS,GAAG,GAAG,OAAO,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AAAA,IAC/F,OAAO,MAAM,WAAW,MAAM;AAAA,EAChC,GAAG,EAAE,MAAM,KAAK,MAAM,OAAO,IAAI,CAAC;AAElC,SAAO;AAAA,IACL,UAAU,MAAM,cAAc,MAAM;AAAA,IACpC,SAAS,MAAM,OAAO,QAAQ;AAAA,IAC9B,SAAS,MAAM,OAAO,QAAQ;AAAA,IAC9B,QAAQ,MAAM;AAAE,OAAC,KAAK,SAAS,CAAC,MAAc,QAAQ,IAAI,CAAC,IAAI,GAAG,GAAG,GAAG,aAAa,IAAI,CAAC,EAAE;AAAA,IAAG;AAAA,EACjG;AACF;;;AC9CA,IAAM,OAAO;AAMN,SAAS,gBAAgB,MAAmC;AACjE,QAAM,MAAM,KAAK,OAAO;AACxB,QAAM,OAAoC,KAAK,aAAc,WAA+C;AAC5G,QAAM,QAAQ,oBAAI,IAAY;AAC9B,MAAI,QAAkB,CAAC;AACvB,MAAI,OAA+B;AACnC,MAAI,SAAS;AACb,MAAI,QAAQ,KAAK;AAEjB,QAAM,QAAQ,MAAY;AACxB,QAAI,CAAC,QAAQ,KAAK,eAAe,KAAM;AACvC,eAAW,KAAK,OAAO;AAAE,UAAI;AAAE,aAAK,KAAK,CAAC;AAAA,MAAG,QAAQ;AAAA,MAAyB;AAAA,IAAE;AAChF,YAAQ,CAAC;AAAA,EACX;AACA,QAAM,OAAO,CAAC,QAAsB;AAClC,QAAI,OAAQ;AACZ,UAAM,KAAK,KAAK,UAAU,GAAG,CAAC;AAC9B,UAAM;AAAA,EACR;AAEA,MAAI,CAAC,MAAM;AAET,WAAO,EAAE,aAAa;AAAA,IAAC,GAAG,UAAU;AAAA,IAAC,GAAG,aAAa;AAAA,IAAC,GAAG,WAAW;AAAA,IAAC,GAAG,QAAQ;AAAE,eAAS;AAAA,IAAM,EAAE;AAAA,EACrG;AAEA,QAAM,YAAY,MAAY;AAC5B,UAAM,QAAQ,KAAK,UAAU,EAAE,GAAG,SAAS,GAAG,GAAG,OAAO,SAAS,KAAK,SAAS,OAAO,CAAC,GAAG,KAAK,EAAE,CAAC;AAClG,QAAI;AAAE,YAAM,KAAK,KAAK;AAAA,IAAG,QAAQ;AAAA,IAAiC;AAAA,EACpE;AAEA,MAAI;AACF,WAAO,IAAI,KAAK,GAAG;AACnB,SAAK,iBAAiB,QAAQ,MAAM;AAElC,gBAAU;AACV,YAAM;AAAA,IACR,CAAC;AAGD,SAAK,iBAAiB,WAAW,CAAC,OAA0B;AAC1D,UAAI,CAAC,KAAK,YAAY,OAAO,GAAG,SAAS,SAAU;AACnD,UAAI;AACF,cAAM,MAAM,KAAK,MAAM,GAAG,IAAI;AAC9B,YAAI,IAAI,MAAM,YAAY,OAAO,IAAI,UAAU,YAAY,OAAO,IAAI,SAAS,UAAU;AACvF,eAAK,SAAS,EAAE,OAAO,IAAI,OAAO,MAAM,IAAI,KAAK,CAAC;AAAA,QACpD;AAAA,MACF,QAAQ;AAAA,MAAmB;AAAA,IAC7B,CAAC;AACD,SAAK,iBAAiB,SAAS,MAAM;AAAA,IAA4C,CAAC;AAClF,SAAK,iBAAiB,SAAS,MAAM;AAAE,aAAO;AAAA,IAAM,CAAC;AAAA,EACvD,QAAQ;AAAE,WAAO;AAAA,EAAM;AAEvB,SAAO;AAAA,IACL,WAAW,QAAsB;AAAE,YAAM,IAAI,MAAM;AAAG,WAAK,EAAE,GAAG,YAAY,MAAM,OAAO,CAAC;AAAA,IAAG;AAAA,IAC7F,WAAW,QAAsB;AAAE,YAAM,OAAO,MAAM;AAAG,WAAK,EAAE,GAAG,aAAa,MAAM,OAAO,CAAC;AAAA,IAAG;AAAA,IACjG,QAAQ,QAAgB,SAAwB,QAAuB,MAAc,UAAyB;AAM5G,UAAI,CAAC,MAAM,IAAI,MAAM,GAAG;AAAE,cAAM,IAAI,MAAM;AAAG,aAAK,EAAE,GAAG,YAAY,MAAM,OAAO,CAAC;AAAA,MAAG;AACpF,WAAK,EAAE,GAAG,SAAS,MAAM,QAAQ,SAAS,QAAQ,MAAM,SAAS,CAAC;AAAA,IACpE;AAAA,IACA,SAAS,MAAoB;AAC3B,UAAI,UAAU,SAAS,MAAO;AAC9B,cAAQ;AACR,UAAI,QAAQ,KAAK,eAAe,KAAM,WAAU;AAAA,IAClD;AAAA,IACA,QAAc;AAAE,eAAS;AAAM,cAAQ,CAAC;AAAG,UAAI;AAAE,cAAM,MAAM;AAAA,MAAG,QAAQ;AAAA,MAAqB;AAAE,aAAO;AAAA,IAAM;AAAA,EAC9G;AACF;;;ACxHA,OAAuB;AAkBhB,SAAS,gBAAgB,QAAgB,SAAiB,MAAgC;AAC/F,QAAM,OAAO,KAAK,MAAM,IAAI;AAI5B,QAAM,gBAAgB,QAAQ,QAAQ,kBAAkB,UACnD,QAAQ,QAAQ,kBAAkB,KAAK,QAAQ;AACpD,MAAI,eAAe;AACjB,WAAO,eAAe,IAAI;AAC1B,WAAO,EAAE,QAAQ,QAAQ,MAAM,MAAM,OAAO;AAAA,EAC9C;AACA,SAAO,EAAE,QAAQ,OAAO,QAAQ,IAAI,GAAG,QAAQ,MAAM,MAAM,YAAY;AACzE;;;ACjBA,IAAM,WAAW;AACjB,IAAM,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAcZ,SAAS,YAAY,KAAqB;AACxC,MAAI,IAAI,eAAe,QAAQ,EAAG;AAClC,QAAM,IAAI,IAAI,cAAc,OAAO;AACnC,IAAE,KAAK;AACP,IAAE,cAAc;AAChB,GAAC,IAAI,QAAQ,IAAI,iBAAiB,YAAY,CAAC;AACjD;AAOA,SAAS,UAAU,GAA8B,GAAuC;AACtF,MAAI,MAAM,QAAQ,CAAC,KAAK,MAAM,QAAQ,CAAC,EAAG,QAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,CAAC,GAAG,MAAM,MAAM,EAAE,CAAC,CAAC;AACtG,SAAO,MAAM;AACf;AAEO,SAAS,wBAAwB,QAAgB,OAAiC,CAAC,GAAsB;AAC9G,QAAM,MAAM,KAAK,WAAW,iBAAiB;AAC7C,cAAY,GAAG;AAEf,QAAMA,MAAK,IAAI,cAAc,KAAK;AAClC,EAAAA,IAAG,YAAY;AACf,QAAM,UAAU,IAAI,cAAc,IAAI;AACtC,UAAQ,cAAc,KAAK,SAAS;AACpC,QAAM,OAAO,IAAI,cAAc,KAAK;AAIpC,QAAM,KAAK,IAAI,cAAc,KAAK;AAClC,KAAG,YAAY;AACf,QAAM,UAAU,IAAI,cAAc,QAAQ;AAC1C,UAAQ,OAAO;AACf,UAAQ,cAAc;AACtB,UAAQ,iBAAiB,SAAS,MAAM;AACtC,UAAM,OAAO,IAAI,KAAK,CAAC,eAAe,MAAM,CAAC,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAC5E,UAAM,IAAI,IAAI,cAAc,GAAG;AAC/B,MAAE,OAAO,IAAI,gBAAgB,IAAI;AACjC,MAAE,WAAW;AACb,MAAE,MAAM;AACR,QAAI,gBAAgB,EAAE,IAAI;AAAA,EAC5B,CAAC;AACD,QAAM,UAAU,IAAI,cAAc,QAAQ;AAC1C,UAAQ,OAAO;AACf,UAAQ,cAAc;AACtB,UAAQ,iBAAiB,SAAS,MAAM;AACtC,UAAM,QAAQ,IAAI,cAAc,OAAO;AACvC,UAAM,OAAO;AACb,UAAM,SAAS;AACf,UAAM,iBAAiB,UAAU,MAAM;AACrC,YAAM,OAAO,MAAM,QAAQ,CAAC;AAC5B,UAAI,CAAC,KAAM;AACX,WAAK,KAAK,KAAK,EAAE,KAAK,CAAC,SAAS;AAC9B,YAAI;AAAE,2BAAiB,QAAQ,IAAI;AAAG,kBAAQ;AAAA,QAAG,SAC1C,KAAK;AAAE,kBAAQ,MAAM,sBAAsB,eAAe,QAAQ,IAAI,UAAU,GAAG;AAAA,QAAG;AAAA,MAC/F,CAAC;AAAA,IACH,CAAC;AACD,UAAM,MAAM;AAAA,EACd,CAAC;AACD,KAAG,OAAO,SAAS,OAAO;AAC1B,EAAAA,IAAG,OAAO,SAAS,IAAI,IAAI;AAE3B,QAAM,gBAAmC,CAAC;AAE1C,QAAM,WAAW,CAACC,SAA2B;AAC3C,UAAM,IAAI,IAAI,cAAc,KAAK;AACjC,MAAE,YAAY;AACd,UAAM,QAAQ,IAAI,cAAc,MAAM;AACtC,UAAM,YAAY;AAClB,UAAM,cAAcA,KAAI;AACxB,UAAM,QAAQA,KAAI;AAClB,UAAM,MAAM,IAAI,cAAc,KAAK;AACnC,QAAI,YAAY;AAChB,UAAM,QAAQ,IAAI,cAAc,QAAQ;AACxC,UAAM,YAAY;AAClB,UAAM,OAAO;AACb,UAAM,cAAc;AACpB,UAAM,QAAQ;AACd,MAAE,OAAO,OAAO,KAAK,KAAK;AAC1B,SAAK,YAAY,CAAC;AAIlB,QAAI;AACJ,UAAM,SAAS,CAAC,MAA2B;AAAE,aAAO,YAAYA,KAAI,MAAM,CAAC;AAAG,gBAAU;AAAA,IAAG;AAC3F,UAAM,UAAU,CAAC,SAA2B,IAAI,kBAAkB;AAClE,aAAS,YAAkB;AAAE,YAAM,WAAW,UAAU,OAAO,YAAYA,KAAI,IAAI,GAAGA,KAAI,OAAO;AAAA,IAAG;AACpG,UAAM,iBAAiB,SAAS,MAAM;AAAE,aAAO,YAAYA,KAAI,MAAMA,KAAI,OAAO;AAAG,WAAK;AAAG,gBAAU;AAAA,IAAG,CAAC;AAEzG,QAAIA,KAAI,SAAS,WAAW;AAC1B,YAAM,KAAK,IAAI,cAAc,OAAO;AACpC,SAAG,OAAO;AACV,SAAG,iBAAiB,UAAU,MAAM,OAAO,GAAG,OAAO,CAAC;AACtD,UAAI,YAAY,EAAE;AAClB,aAAO,MAAM;AAAE,YAAI,CAAC,QAAQ,EAAE,EAAG,IAAG,UAAU,OAAO,YAAYA,KAAI,IAAI,MAAM;AAAA,MAAM;AAAA,IACvF,WAAWA,KAAI,SAAS,UAAU;AAChC,YAAM,MAAM,IAAI,cAAc,OAAO;AACrC,UAAI,OAAO;AACX,UAAI,iBAAiB,UAAU,MAAM,OAAO,OAAO,IAAI,KAAK,CAAC,CAAC;AAC9D,UAAI,YAAY,GAAG;AACnB,aAAO,MAAM;AAAE,YAAI,CAAC,QAAQ,GAAG,EAAG,KAAI,QAAQ,OAAO,OAAO,YAAYA,KAAI,IAAI,KAAK,EAAE;AAAA,MAAG;AAAA,IAC5F,WAAWA,KAAI,SAAS,UAAUA,KAAI,SAAS,WAAW;AAExD,YAAM,MAAM,IAAI,cAAc,QAAQ;AACtC,iBAAW,MAAMA,KAAI,SAAS,YAAYA,KAAI,SAASA,KAAI,WAAW,CAAC,GAAG;AACxE,cAAM,IAAI,IAAI,cAAc,QAAQ;AACpC,UAAE,QAAQ;AAAG,UAAE,cAAc;AAC7B,YAAI,YAAY,CAAC;AAAA,MACnB;AACA,UAAI,iBAAiB,UAAU,MAAM,OAAO,IAAI,KAAK,CAAC;AACtD,UAAI,YAAY,GAAG;AACnB,aAAO,MAAM;AAAE,YAAI,CAAC,QAAQ,GAAG,EAAG,KAAI,QAAQ,OAAO,OAAO,YAAYA,KAAI,IAAI,KAAK,EAAE;AAAA,MAAG;AAAA,IAC5F,WAAWA,KAAI,SAAS,SAAS;AAC/B,YAAM,MAAM,IAAI,cAAc,OAAO;AACrC,UAAI,OAAO;AACX,UAAI,cAAc;AAClB,UAAI,iBAAiB,UAAU,MAAM,OAAO,IAAI,MAAM,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;AAClH,UAAI,YAAY,GAAG;AACnB,aAAO,MAAM;AAAE,YAAI,CAAC,QAAQ,GAAG,GAAG;AAAE,gBAAM,IAAI,OAAO,YAAYA,KAAI,IAAI;AAAG,cAAI,QAAQ,MAAM,QAAQ,CAAC,IAAI,EAAE,KAAK,IAAI,IAAI;AAAA,QAAI;AAAA,MAAE;AAAA,IAClI,OAAO;AAEL,YAAM,MAAM,IAAI,cAAc,OAAO;AACrC,UAAI,OAAO;AACX,UAAI,iBAAiB,UAAU,MAAM,OAAO,IAAI,KAAK,CAAC;AACtD,UAAI,YAAY,GAAG;AACnB,aAAO,MAAM;AAAE,YAAI,CAAC,QAAQ,GAAG,EAAG,KAAI,QAAQ,OAAO,OAAO,YAAYA,KAAI,IAAI,KAAK,EAAE;AAAA,MAAG;AAAA,IAC5F;AAEA,SAAK;AACL,cAAU;AACV,kBAAc,KAAK,MAAM;AAAE,WAAK;AAAG,gBAAU;AAAA,IAAG,CAAC;AAAA,EACnD;AAGA,QAAM,QAAQ,OAAO,eAAe;AACpC,MAAI,MAAM,WAAW,GAAG;AACtB,UAAM,QAAQ,IAAI,cAAc,KAAK;AACrC,UAAM,YAAY;AAClB,UAAM,cAAc;AACpB,SAAK,YAAY,KAAK;AAAA,EACxB,OAAO;AACL,eAAWA,QAAO,MAAO,UAASA,IAAG;AAAA,EACvC;AAEA,QAAM,UAAU,MAAY;AAAE,eAAW,MAAM,cAAe,IAAG;AAAA,EAAG;AAEpE,OAAK,WAAW,YAAYD,GAAE;AAC9B,QAAM,SAAS,KAAK,UAAU;AAC9B,MAAI;AACJ,MAAI,SAAS,EAAG,SAAQ,YAAY,SAAS,MAAM;AAEnD,SAAO;AAAA,IACL,IAAAA;AAAA,IACA;AAAA,IACA,UAAU;AAAE,UAAI,UAAU,OAAW,eAAc,KAAK;AAAG,MAAAA,IAAG,OAAO;AAAA,IAAG;AAAA,EAC1E;AACF;;;AC7LA,SAAS,sBAAsB;AAyB/B,IAAME,YAAW;AAGjB,IAAMC,OAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmBZ,SAASC,aAAY,KAAqB;AACxC,MAAI,IAAI,eAAeF,SAAQ,EAAG;AAClC,QAAM,IAAI,IAAI,cAAc,OAAO;AACnC,IAAE,KAAKA;AACP,IAAE,cAAcC;AAChB,GAAC,IAAI,QAAQ,IAAI,iBAAiB,YAAY,CAAC;AACjD;AAEA,IAAM,KAAK,CAAC,KAAe,KAAa,KAAc,SAA+B;AACnF,QAAM,IAAI,IAAI,cAAc,GAAG;AAC/B,MAAI,IAAK,GAAE,YAAY;AACvB,MAAI,SAAS,OAAW,GAAE,cAAc;AACxC,SAAO;AACT;AAGA,SAAS,IAAI,KAAe,KAAa,OAAe,aAAa,iBAA8B;AACjG,QAAM,IAAI,GAAG,KAAK,OAAO,eAAe;AACxC,IAAE,OAAO,GAAG,KAAK,QAAQ,iBAAiB,GAAG,GAAG,GAAG,KAAK,QAAQ,YAAY,KAAK,CAAC;AAClF,SAAO;AACT;AAIA,SAAS,YAAY,KAAe,GAAiC;AACnE,QAAM,IAAI,GAAG,KAAK,OAAO,eAAe;AACxC,IAAE,OAAO,GAAG,KAAK,QAAQ,gCAAgC,EAAE,IAAI,CAAC;AAChE,QAAM,OAAO,GAAG,KAAK,QAAQ,iBAAiB,EAAE,IAAI;AACpD,MAAI,CAAC,EAAE,WAAY,MAAK,OAAO,GAAG,KAAK,QAAQ,iBAAiB,YAAY,CAAC;AAC7E,IAAE,OAAO,IAAI;AACb,SAAO;AACT;AAEA,SAAS,QAAQ,KAAe,MAAqB,OAAe,OAAsB,MAAmC;AAC3H,QAAM,IAAI,IAAI,cAAc,SAAS;AACrC,IAAE,QAAQ,SAAS,IAAI;AACvB,IAAE,OAAO;AACT,QAAM,IAAI,IAAI,cAAc,SAAS;AACrC,IAAE,cAAc;AAChB,MAAI,UAAU,KAAM,GAAE,OAAO,GAAG,KAAK,QAAQ,mBAAmB,IAAI,KAAK,EAAE,CAAC;AAC5E,IAAE,OAAO,CAAC;AACV,SAAO;AACT;AAMO,SAAS,sBAAsB,QAAgB,OAA+B,CAAC,GAAoB;AACxG,QAAM,MAAM,KAAK,WAAW,iBAAiB;AAC7C,EAAAC,aAAY,GAAG;AACf,QAAM,IAAI,eAAe,MAAM;AAC/B,QAAM,OAAO,IAAI,IAAmB,KAAK,QAAQ,CAAC,YAAY,WAAW,CAAC;AAE1E,QAAM,OAAO,GAAG,KAAK,OAAO,WAAW;AACvC,OAAK,OAAO,GAAG,KAAK,MAAM,QAAW,KAAK,SAAS,QAAQ,CAAC;AAG5D,QAAM,KAAK,QAAQ,KAAK,YAAY,EAAE,SAAS,WAAW,qBAAqB,MAAM,KAAK,IAAI,UAAU,CAAC;AACzG,MAAI,EAAE,SAAS,QAAS,IAAG,OAAO,IAAI,KAAK,WAAW,EAAE,SAAS,OAAO,CAAC;AACzE,KAAG,OAAO,IAAI,KAAK,UAAU,EAAE,SAAS,MAAM,CAAC;AAC/C,KAAG,OAAO,IAAI,KAAK,WAAW,GAAG,EAAE,SAAS,aAAa,GAAG,EAAE,SAAS,QAAQ,SAAS,IAAI,MAAM,EAAE,SAAS,QAAQ,SAAS,CAAC,MAAM,EAAE,EAAE,CAAC;AAC1I,KAAG,OAAO,IAAI,KAAK,WAAW,EAAE,SAAS,YAAY,CAAC;AACtD,MAAI,EAAE,SAAS,OAAQ,IAAG,OAAO,IAAI,KAAK,UAAU,KAAK,CAAC;AAC1D,MAAI,EAAE,SAAS,KAAM,IAAG,OAAO,IAAI,KAAK,QAAQ,EAAE,SAAS,IAAI,CAAC;AAGhE,MAAI,EAAE,SAAS,cAAe,IAAG,OAAO,IAAI,KAAK,aAAa,EAAE,SAAS,aAAa,CAAC;AACvF,MAAI,EAAE,SAAS,aAAa;AAC1B,OAAG,OAAO,IAAI,KAAK,SAAS,gCAAgC,8BAA8B,CAAC;AAAA,EAC7F;AACA,OAAK,OAAO,EAAE;AAGd,QAAM,OAAO,QAAQ,KAAK,aAAa,aAAa,EAAE,UAAU,QAAQ,KAAK,IAAI,WAAW,CAAC;AAC7F,MAAI,CAAC,EAAE,UAAU,OAAQ,MAAK,OAAO,GAAG,KAAK,OAAO,mBAAmB,WAAW,CAAC;AACnF,aAAW,KAAK,EAAE,WAAW;AAC3B,UAAM,IAAI,GAAG,KAAK,OAAO,eAAe;AACxC,MAAE,OAAO,GAAG,KAAK,QAAQ,gCAAgC,EAAE,MAAM,GAAG,GAAG,KAAK,QAAQ,iBAAiB,EAAE,IAAI,CAAC;AAC5G,SAAK,OAAO,CAAC;AAEb,eAAW,KAAK,EAAE,QAAQ;AACxB,YAAM,KAAK,GAAG,KAAK,OAAO,6BAA6B;AACvD,SAAG,OAAO,GAAG,KAAK,QAAQ,gCAAgC,EAAE,MAAM,GAAG,GAAG,KAAK,QAAQ,iBAAiB,EAAE,IAAI,CAAC;AAC7G,WAAK,OAAO,EAAE;AAAA,IAChB;AAAA,EACF;AACA,OAAK,OAAO,IAAI;AAMhB,QAAM,YAAY,EAAE,WAAW,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,WAAW,QAAQ,CAAC;AAC1E,QAAM,OAAO,QAAQ,KAAK,cAAc,mBAAmB,WAAW,KAAK,IAAI,YAAY,CAAC;AAC5F,MAAI,CAAC,EAAE,WAAW,OAAQ,MAAK,OAAO,GAAG,KAAK,OAAO,mBAAmB,2BAA2B,CAAC;AACpG,aAAW,KAAK,EAAE,YAAY;AAC5B,UAAM,OAAO,GAAG,KAAK,OAAO,eAAe;AAC3C,SAAK,OAAO,GAAG,KAAK,QAAQ,gCAAgC,IAAI,EAAE,KAAK,EAAE,CAAC;AAC1E,UAAM,OAAO,GAAG,KAAK,QAAQ,iBAAiB,EAAE,SAAS,wBAAwB,GAAG,EAAE,WAAW,MAAM,WAAW;AAClH,QAAI,CAAC,EAAE,SAAU,MAAK,OAAO,GAAG,KAAK,QAAQ,iBAAiB,WAAW,CAAC;AAC1E,SAAK,OAAO,IAAI;AAChB,SAAK,OAAO,IAAI;AAChB,eAAW,KAAK,EAAE,YAAY;AAC5B,YAAM,KAAK,YAAY,KAAK,CAAC;AAC7B,SAAG,UAAU,IAAI,eAAe;AAChC,WAAK,OAAO,EAAE;AAAA,IAChB;AAAA,EACF;AACA,OAAK,OAAO,IAAI;AAGhB,QAAM,aAAa,EAAE,WAAW,OAAO,SAAS,EAAE,WAAW,MAAM,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,WAAW,QAAQ,CAAC;AAC9G,QAAM,QAAQ,QAAQ,KAAK,cAAc,oBAAoB,YAAY,KAAK,IAAI,YAAY,CAAC;AAC/F,MAAI,CAAC,WAAY,OAAM,OAAO,GAAG,KAAK,OAAO,mBAAmB,eAAe,CAAC;AAChF,aAAW,KAAK,EAAE,WAAW,OAAQ,OAAM,OAAO,YAAY,KAAK,CAAC,CAAC;AACrE,aAAW,KAAK,EAAE,WAAW,OAAO;AAClC,UAAM,OAAO,IAAI,KAAK,UAAU,EAAE,QAAQ,8BAA8B,CAAC;AACzE,eAAW,KAAK,EAAE,YAAY;AAC5B,YAAM,KAAK,YAAY,KAAK,CAAC;AAC7B,SAAG,UAAU,IAAI,eAAe;AAChC,YAAM,OAAO,EAAE;AAAA,IACjB;AAAA,EACF;AACA,OAAK,OAAO,KAAK;AAGjB,MAAI,EAAE,SAAS,QAAQ;AACrB,UAAMC,MAAK,QAAQ,KAAK,YAAY,aAAa,EAAE,SAAS,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,OAAO,QAAQ,CAAC,GAAG,KAAK,IAAI,UAAU,CAAC;AAC1H,eAAW,KAAK,EAAE,UAAU;AAC1B,MAAAA,IAAG,OAAO,IAAI,KAAK,MAAM,EAAE,IAAI,CAAC;AAChC,iBAAW,KAAK,EAAE,QAAQ;AACxB,cAAM,KAAK,GAAG,KAAK,OAAO,6BAA6B;AACvD,WAAG,OAAO,GAAG,KAAK,QAAQ,gCAAgC,EAAE,IAAI,GAAG,GAAG,KAAK,QAAQ,iBAAiB,EAAE,IAAI,CAAC;AAC3G,QAAAA,IAAG,OAAO,EAAE;AAAA,MACd;AAAA,IACF;AACA,SAAK,OAAOA,GAAE;AAAA,EAChB;AAGA,QAAM,SAAS,QAAQ,KAAK,UAAU,UAAU,MAAM,KAAK,IAAI,QAAQ,CAAC;AACxE,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,EAAE,MAAM,EAAG,QAAO,OAAO,IAAI,KAAK,KAAK,OAAO,KAAK,CAAC,CAAC;AAC/F,OAAK,OAAO,MAAM;AAElB,OAAK,WAAW,OAAO,IAAI;AAC3B,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,aAAa;AAAA,IACb,UAAU;AAAE,WAAK,OAAO;AAAA,IAAG;AAAA,EAC7B;AACF;;;AC5LO,SAAS,oBAAoB,cAAsB,UAAiC;AACzF,QAAM,WAAW,KAAK,MAAM,YAAY;AACxC,QAAM,QAAQ,SAAS,SAAS,CAAC;AACjC,QAAM,OAAO,SAAS,QAAQ,WAAW,EAAE;AAC3C,SAAO;AAAA,IACL,QAAQ,QAA+B;AACrC,YAAM,OAAO,MAAM,MAAM;AACzB,UAAI,CAAC,QAAQ,CAAC,KAAK,KAAM,QAAO;AAChC,aAAO,OAAO,GAAG,IAAI,IAAI,KAAK,IAAI,KAAK,KAAK;AAAA,IAC9C;AAAA,EACF;AACF;","names":["el","row","STYLE_ID","CSS","injectStyle","gd"]}