svedit 0.12.0 → 0.13.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 (86) hide show
  1. package/README.md +33 -21
  2. package/dist/Command.svelte.d.ts +38 -30
  3. package/dist/Command.svelte.d.ts.map +1 -1
  4. package/dist/Command.svelte.js +271 -326
  5. package/dist/CustomProperty.svelte +3 -5
  6. package/dist/CustomProperty.svelte.d.ts +3 -6
  7. package/dist/CustomProperty.svelte.d.ts.map +1 -1
  8. package/dist/KeyMapper.svelte.d.ts +19 -6
  9. package/dist/KeyMapper.svelte.d.ts.map +1 -1
  10. package/dist/KeyMapper.svelte.js +95 -112
  11. package/dist/Node.svelte +16 -13
  12. package/dist/Node.svelte.d.ts +3 -5
  13. package/dist/Node.svelte.d.ts.map +1 -1
  14. package/dist/NodeArrayProperty.svelte +39 -22
  15. package/dist/NodeArrayProperty.svelte.d.ts +3 -5
  16. package/dist/NodeArrayProperty.svelte.d.ts.map +1 -1
  17. package/dist/NodeCaret.svelte +1 -1
  18. package/dist/NodeCaret.svelte.d.ts +6 -14
  19. package/dist/NodeCaret.svelte.d.ts.map +1 -1
  20. package/dist/NodeGap.svelte +12 -6
  21. package/dist/NodeGap.svelte.d.ts +7 -14
  22. package/dist/NodeGap.svelte.d.ts.map +1 -1
  23. package/dist/NodeGapMarkers.svelte +19 -10
  24. package/dist/NodeGapMarkers.svelte.d.ts +6 -11
  25. package/dist/NodeGapMarkers.svelte.d.ts.map +1 -1
  26. package/dist/NodeSelectionMarkers.svelte +20 -6
  27. package/dist/NodeSelectionMarkers.svelte.d.ts +2 -5
  28. package/dist/NodeSelectionMarkers.svelte.d.ts.map +1 -1
  29. package/dist/Session.svelte.d.ts +81 -129
  30. package/dist/Session.svelte.d.ts.map +1 -1
  31. package/dist/Session.svelte.js +542 -648
  32. package/dist/Svedit.svelte +144 -138
  33. package/dist/Svedit.svelte.d.ts +30 -10
  34. package/dist/Svedit.svelte.d.ts.map +1 -1
  35. package/dist/TextProperty.svelte +32 -18
  36. package/dist/TextProperty.svelte.d.ts +3 -5
  37. package/dist/TextProperty.svelte.d.ts.map +1 -1
  38. package/dist/Transaction.svelte.d.ts +64 -127
  39. package/dist/Transaction.svelte.d.ts.map +1 -1
  40. package/dist/Transaction.svelte.js +839 -1001
  41. package/dist/UnknownNode.svelte +4 -3
  42. package/dist/UnknownNode.svelte.d.ts +5 -9
  43. package/dist/UnknownNode.svelte.d.ts.map +1 -1
  44. package/dist/doc_utils.d.ts +67 -155
  45. package/dist/doc_utils.d.ts.map +1 -1
  46. package/dist/doc_utils.js +619 -863
  47. package/dist/index.d.ts +20 -17
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +1 -17
  50. package/dist/node_visibility.svelte.d.ts +110 -9
  51. package/dist/node_visibility.svelte.d.ts.map +1 -1
  52. package/dist/node_visibility.svelte.js +473 -544
  53. package/dist/paste_utils.d.ts +11 -44
  54. package/dist/paste_utils.d.ts.map +1 -1
  55. package/dist/paste_utils.js +111 -152
  56. package/dist/transforms.svelte.d.ts +9 -7
  57. package/dist/transforms.svelte.d.ts.map +1 -1
  58. package/dist/transforms.svelte.js +125 -150
  59. package/dist/types.d.ts +277 -309
  60. package/dist/types.d.ts.map +1 -0
  61. package/dist/types.js +1 -0
  62. package/dist/utils.d.ts +40 -119
  63. package/dist/utils.d.ts.map +1 -1
  64. package/dist/utils.js +346 -473
  65. package/package.json +69 -70
  66. package/src/lib/{Command.svelte.js → Command.svelte.ts} +29 -17
  67. package/src/lib/CustomProperty.svelte +3 -5
  68. package/src/lib/{KeyMapper.svelte.js → KeyMapper.svelte.ts} +28 -11
  69. package/src/lib/Node.svelte +16 -13
  70. package/src/lib/NodeArrayProperty.svelte +39 -22
  71. package/src/lib/NodeCaret.svelte +1 -1
  72. package/src/lib/NodeGap.svelte +12 -6
  73. package/src/lib/NodeGapMarkers.svelte +19 -10
  74. package/src/lib/NodeSelectionMarkers.svelte +20 -6
  75. package/src/lib/{Session.svelte.js → Session.svelte.ts} +130 -127
  76. package/src/lib/Svedit.svelte +144 -138
  77. package/src/lib/TextProperty.svelte +32 -18
  78. package/src/lib/{Transaction.svelte.js → Transaction.svelte.ts} +139 -143
  79. package/src/lib/UnknownNode.svelte +4 -3
  80. package/src/lib/{doc_utils.js → doc_utils.ts} +247 -206
  81. package/src/lib/{index.js → index.ts} +47 -0
  82. package/src/lib/{node_visibility.svelte.js → node_visibility.svelte.ts} +68 -92
  83. package/src/lib/{paste_utils.js → paste_utils.ts} +47 -58
  84. package/src/lib/{transforms.svelte.js → transforms.svelte.ts} +39 -21
  85. package/src/lib/{types.d.ts → types.ts} +143 -66
  86. package/src/lib/{utils.js → utils.ts} +110 -129
package/README.md CHANGED
@@ -1,9 +1,9 @@
1
1
  # Svedit
2
2
 
3
- Svedit (think Svelte Edit) is a tiny library for building editable websites in Svelte. Model content in JSON, render it with custom components, and let site owners **edit directly in the layout** — no CMS needed.
3
+ Svedit is Editing for Svelte. It offers structured, full-canvas content editing. Model content in JSON, render it with custom components, and **edit it directly in the layout**.
4
4
 
5
5
  - Try the [Svedit demo](https://svedit.dev) — watch the debug output at the bottom of the page
6
- - Try [Editable Website](https://editable.website) — utilizes Svedit to enable CMS-free editable websites
6
+ - Try [Editable](https://editable.website) — build Svelte websites you can edit on the page
7
7
 
8
8
  ## Why Svedit?
9
9
 
@@ -16,13 +16,13 @@ The fastest way to get started is to clone the `hello-svedit` template and turn
16
16
  ```bash
17
17
  git clone https://github.com/michael/hello-svedit
18
18
  cd hello-svedit
19
- npm install
20
- npm run dev
19
+ pnpm install
20
+ pnpm dev
21
21
  ```
22
22
 
23
- Now make it your own. The next thing you probably want to do is define your own [node types](./src/routes/create_demo_session.js), add a [Toolbar](./src/routes/components/Toolbar.svelte), and render custom [Overlays](./src/routes/components/Overlays.svelte). For that just get inspired by the [Svedit demo code](./src/routes).
23
+ Now make it your own. The next thing you probably want to do is define your own [node types](./src/routes/demo_schema.ts), add a [Toolbar](./src/routes/components/Toolbar.svelte), and render custom [Overlays](./src/routes/components/Overlays.svelte). For that just get inspired by the [Svedit demo code](./src/routes).
24
24
 
25
- You can also install Svedit into an existing SvelteKit project with `npm install svedit`, but you'll need to set up the session, schema, config, and components yourself. See the [hello-svedit repo](https://github.com/michael/hello-svedit) or this repo's [`src/routes`](./src/routes) for reference.
25
+ You can also install Svedit into an existing SvelteKit project with `pnpm add svedit`, but you'll need to set up the session, schema, config, and components yourself. See the [hello-svedit repo](https://github.com/michael/hello-svedit) or this repo's [`src/routes`](./src/routes) for reference.
26
26
 
27
27
  ## Principles
28
28
 
@@ -117,9 +117,9 @@ flowchart TD
117
117
 
118
118
  Properties of nodes can hold values:
119
119
 
120
- - `string`: A good old JavaScript string
120
+ - `string`: A good old JavaScript string. Use optional `values` to restrict it to an ordered set of allowed strings.
121
121
  - `number`: Just like a number in JavaScript
122
- - `integer`: A number for which Number.isInteger(number) returns true
122
+ - `integer`: A number for which Number.isInteger(number) returns true. Optional `min` and `max` bounds are inclusive.
123
123
  - `boolean`: true or false
124
124
  - `datetime`: A date/time string parseable by `Date.parse()`
125
125
  - `string_array`: An array of strings
@@ -409,7 +409,11 @@ const document_schema = {
409
409
  paragraph: {
410
410
  kind: 'text',
411
411
  properties: {
412
- layout: { type: 'integer', default: 1 },
412
+ layout: {
413
+ type: 'string',
414
+ values: ['image-left', 'image-right', 'stacked'],
415
+ default: 'image-left'
416
+ },
413
417
  content: {
414
418
  type: 'text',
415
419
  allow_newlines: true
@@ -422,7 +426,7 @@ const migrated_doc = fill_document_defaults(existing_doc, document_schema);
422
426
  const session = new Session(document_schema, migrated_doc, config);
423
427
  ```
424
428
 
425
- This only fills properties that are missing. Explicit schema `default` values are used when present; otherwise Svedit uses built-in defaults for value types such as strings, numbers, booleans, arrays, `node_array`, and `text`. Existing values are preserved, and the original document object is not mutated.
429
+ This only fills properties that are missing. Explicit schema `default` values are used when present; otherwise Svedit uses built-in defaults for value types such as strings, numbers, booleans, arrays, `node_array`, and `text`. Constraints such as `values`, `min`, and `max` do not change those defaults, so declare an explicit `default` when the built-in value would be invalid. Existing values are preserved, and the original document object is not mutated.
426
430
 
427
431
  Defaults make it safe to add new defaultable properties, but they are not a replacement for real document migrations. If you rename a property, remove a property, split one property into several, change node types, or need to transform existing data, write your own migration first and use `fill_document_defaults` only as a helper where appropriate.
428
432
 
@@ -430,17 +434,17 @@ Defaults make it safe to add new defaultable properties, but they are not a repl
430
434
 
431
435
  ## Config
432
436
 
433
- Documents need a config object that tells Svedit how to render and manipulate your content. See the full example in [`src/routes/create_demo_session.js`](src/routes/create_demo_session.js).
437
+ Documents need a config object that tells Svedit how to render and manipulate your content. See the full example in [`src/routes/demo_config.ts`](src/routes/demo_config.ts).
434
438
 
435
439
  Two optional hooks are especially useful when integrating custom media workflows:
436
440
 
437
441
  - `handle_media_paste(session, pasted_media)`
438
442
  Called when media is pasted. You can upload/process files, replace an existing media property, or return a node payload to insert new content.
439
- See example implementation in [`src/routes/create_demo_session.js`](src/routes/create_demo_session.js).
443
+ See example implementation in [`src/routes/demo_config.ts`](src/routes/demo_config.ts).
440
444
 
441
445
  - `handle_property_deletion(session, path)`
442
446
  Called when deleting/cutting a property selection. Use it to define app-specific reset behavior (for example clearing an image property or resetting a referenced media node).
443
- See example implementation in [`src/routes/create_demo_session.js`](src/routes/create_demo_session.js).
447
+ See example implementation in [`src/routes/demo_config.ts`](src/routes/demo_config.ts).
444
448
 
445
449
  ```js
446
450
  const session_config = {
@@ -653,7 +657,11 @@ function insert_heading(tr) {
653
657
 
654
658
  // Create and insert a heading node
655
659
  const heading_id = tr.generate_id();
656
- tr.create({ id: heading_id, type: 'heading', content: { content: '', marks: [], annotations: [] } });
660
+ tr.create({
661
+ id: heading_id,
662
+ type: 'heading',
663
+ content: { content: '', marks: [], annotations: [] }
664
+ });
657
665
  tr.insert_nodes([heading_id]);
658
666
 
659
667
  return true;
@@ -676,7 +684,11 @@ session.apply(tr); // Apply atomically
676
684
 
677
685
  ```js
678
686
  // Create a new node (must include all required properties from schema)
679
- tr.create({ id: 'paragraph_1', type: 'paragraph', content: { content: '', marks: [], annotations: [] } });
687
+ tr.create({
688
+ id: 'paragraph_1',
689
+ type: 'paragraph',
690
+ content: { content: '', marks: [], annotations: [] }
691
+ });
680
692
 
681
693
  // Delete a node (cascades to unreferenced child nodes)
682
694
  tr.delete('paragraph_26');
@@ -816,7 +828,7 @@ Svedit provides several [core commands](src/lib/Command.svelte.js) out of the bo
816
828
 
817
829
  #### Using document commands
818
830
 
819
- Commands are created by passing them a context object from the Svedit component. See a complete example in [`src/routes/create_demo_session.js`](src/routes/create_demo_session.js) in the `create_commands_and_keymap` configuration function:
831
+ Commands are created by passing them a context object from the Svedit component. See a complete example in [`src/routes/demo_config.ts`](src/routes/demo_config.ts) in the `create_commands_and_keymap` configuration function:
820
832
 
821
833
  ```js
822
834
  create_commands_and_keymap: (context) => {
@@ -1440,10 +1452,10 @@ The source code is compact and readable — less than 3000 LOC across a handful
1440
1452
 
1441
1453
  ## Developing Svedit
1442
1454
 
1443
- Once you've cloned the Svedit repository and installed dependencies with `npm install`, start a development server:
1455
+ Once you've cloned the Svedit repository and installed dependencies with `pnpm install`, start a development server:
1444
1456
 
1445
1457
  ```bash
1446
- npm run dev
1458
+ pnpm dev
1447
1459
  ```
1448
1460
 
1449
1461
  ## Building
@@ -1451,10 +1463,10 @@ npm run dev
1451
1463
  To create a production version of your app:
1452
1464
 
1453
1465
  ```bash
1454
- npm run build
1466
+ pnpm build
1455
1467
  ```
1456
1468
 
1457
- You can preview the production build with `npm run preview`.
1469
+ You can preview the production build with `pnpm preview`.
1458
1470
 
1459
1471
  ## Contributing
1460
1472
 
@@ -1481,4 +1493,4 @@ It's still early. Expect bugs. Expect missing features. Expect the need for more
1481
1493
 
1482
1494
  ## Credits
1483
1495
 
1484
- Svedit is led by [Michael Aufreiter](https://michaelaufreiter.com) with guidance and support from [Johannes Mutter](https://mutter.co).
1496
+ Svedit is made by [Michael Aufreiter](https://michaelaufreiter.com) (maintainer) and [Johannes Mutter](https://mutter.co) (design and engineering). Illustrations and icons are hand-crafted by Johannes.
@@ -1,3 +1,9 @@
1
+ import type Session from './Session.svelte.js';
2
+ type CommandSession = Session<any>;
3
+ export type CommandContext = {
4
+ session: CommandSession;
5
+ editable: boolean;
6
+ };
1
7
  /**
2
8
  * Base class for commands that can be executed in response to user actions
3
9
  * like keyboard shortcuts, menu items, or toolbar buttons.
@@ -21,53 +27,50 @@
21
27
  * ```
22
28
  */
23
29
  export default class Command {
24
- /**
25
- * Creates a new Command instance.
26
- *
27
- * @param {any} context - The context object providing access to application state
28
- */
29
- constructor(context: any);
30
+ context: CommandContext;
30
31
  /**
31
32
  * Derived state that indicates if the command is disabled.
32
33
  * Automatically computed from is_enabled().
33
34
  */
34
35
  disabled: boolean;
35
- context: any;
36
+ /**
37
+ * Creates a new Command instance.
38
+ *
39
+ * @param context - The context object providing access to application state
40
+ */
41
+ constructor(context: CommandContext);
36
42
  /**
37
43
  * Determines if the command can currently be executed.
38
44
  * Override this method to implement command-specific logic.
39
- *
40
- * @returns {boolean} true if the command can be executed, false otherwise
41
45
  */
42
46
  is_enabled(): boolean;
43
47
  /**
44
48
  * Executes the command.
45
49
  * Override this method to implement the command's behavior.
46
50
  * Can be async for commands that need to perform asynchronous operations.
47
- *
48
- * @returns {void | Promise<void>}
49
51
  */
50
52
  execute(): void | Promise<void>;
51
53
  }
52
54
  /**
53
55
  * Command that undoes the last change to the document.
54
56
  */
55
- export class UndoCommand extends Command {
56
- is_enabled(): any;
57
+ export declare class UndoCommand extends Command {
58
+ is_enabled(): boolean;
57
59
  execute(): void;
58
60
  }
59
61
  /**
60
62
  * Command that redoes the last undone change to the document.
61
63
  */
62
- export class RedoCommand extends Command {
63
- is_enabled(): any;
64
+ export declare class RedoCommand extends Command {
65
+ is_enabled(): boolean;
64
66
  execute(): void;
65
67
  }
66
68
  /**
67
69
  * Command that selects the parent of the current selection.
68
70
  * Useful for navigating up the document hierarchy.
69
71
  */
70
- export class SelectParentCommand extends Command {
72
+ export declare class SelectParentCommand extends Command {
73
+ is_enabled(): boolean;
71
74
  execute(): void;
72
75
  }
73
76
  /**
@@ -77,11 +80,12 @@ export class SelectParentCommand extends Command {
77
80
  * are removed, a single touched property-less mark may switch type, and mixed
78
81
  * touched types disable the command. Annotations never affect mark toggling.
79
82
  */
80
- export class ToggleMarkCommand extends Command {
81
- constructor(node_type: any, context: any);
82
- node_type: any;
83
- active: any;
84
- is_active(): any;
83
+ export declare class ToggleMarkCommand extends Command {
84
+ node_type: string;
85
+ constructor(node_type: string, context: CommandContext);
86
+ active: boolean;
87
+ is_active(): boolean;
88
+ is_enabled(): boolean;
85
89
  execute(): void;
86
90
  }
87
91
  /**
@@ -91,19 +95,20 @@ export class ToggleMarkCommand extends Command {
91
95
  * same-type annotations are removed, otherwise a new annotation is created.
92
96
  * Marks and other annotation types never block the toggle.
93
97
  */
94
- export class ToggleAnnotationCommand extends Command {
95
- constructor(node_type: any, context: any);
96
- node_type: any;
98
+ export declare class ToggleAnnotationCommand extends Command {
99
+ node_type: string;
100
+ constructor(node_type: string, context: CommandContext);
97
101
  active: boolean;
98
- relevant_annotations(): any;
102
+ relevant_annotations(): import("./doc_utils.js").SelectedAttachment[];
99
103
  is_active(): boolean;
104
+ is_enabled(): boolean;
100
105
  execute(): void;
101
106
  }
102
107
  /**
103
108
  * Command that adds a new line character at the current caret position.
104
109
  * Only works in text selections where newlines are allowed.
105
110
  */
106
- export class AddNewLineCommand extends Command {
111
+ export declare class AddNewLineCommand extends Command {
107
112
  is_enabled(): any;
108
113
  execute(): void;
109
114
  }
@@ -112,22 +117,25 @@ export class AddNewLineCommand extends Command {
112
117
  * Creates a new node and splits the content between the current and new node.
113
118
  * Only works in text selections.
114
119
  */
115
- export class BreakTextNodeCommand extends Command {
120
+ export declare class BreakTextNodeCommand extends Command {
121
+ is_enabled(): boolean;
116
122
  execute(): void;
117
123
  }
118
124
  /**
119
125
  * Command that selects all content in the current context.
120
126
  * Progressively expands selection from text → node → parent node array.
121
127
  */
122
- export class SelectAllCommand extends Command {
123
- is_enabled(): any;
128
+ export declare class SelectAllCommand extends Command {
129
+ is_enabled(): boolean;
124
130
  execute(): void;
125
131
  }
126
132
  /**
127
133
  * Command that inserts a default node at the current caret position.
128
134
  * Only works when a collapsed node selection is active.
129
135
  */
130
- export class InsertDefaultNodeCommand extends Command {
136
+ export declare class InsertDefaultNodeCommand extends Command {
137
+ is_enabled(): boolean;
131
138
  execute(): void;
132
139
  }
140
+ export {};
133
141
  //# sourceMappingURL=Command.svelte.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Command.svelte.d.ts","sourceRoot":"","sources":["../src/lib/Command.svelte.js"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH;IAOC;;;;OAIG;IACH,qBAFW,GAAG,EAIb;IAbD;;;OAGG;IACH,kBAAwC;IAQvC,aAAsB;IAGvB;;;;;OAKG;IACH,cAFa,OAAO,CAInB;IAED;;;;;;OAMG;IACH,WAFa,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAIhC;CACD;AAED;;GAEG;AACH;IACC,kBAEC;IAED,gBAEC;CACD;AAED;;GAEG;AACH;IACC,kBAEC;IAED,gBAEC;CACD;AAED;;;GAGG;AACH;IASC,gBAEC;CACD;AAED;;;;;;GAMG;AACH;IACC,0CAGC;IADA,eAA0B;IAG3B,YAAoC;IAEpC,iBAMC;IA2BD,gBAEC;CACD;AAED;;;;;;GAMG;AACH;IACC,0CAGC;IADA,eAA0B;IAG3B,gBAAoC;IAIpC,4BAIC;IAED,qBAEC;IAmBD,gBAEC;CACD;AAED;;;GAGG;AACH;IACC,kBASC;IAED,gBAqBC;CACD;AAED;;;;GAIG;AACH;IAaC,gBAKC;CACD;AAED;;;GAGG;AACH;IACC,kBAEC;IAED,gBAwGC;CACD;AAED;;;GAGG;AACH;IAUC,gBAIC;CACD"}
1
+ {"version":3,"file":"Command.svelte.d.ts","sourceRoot":"","sources":["../src/lib/Command.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAC;AAI/C,KAAK,cAAc,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;AAEnC,MAAM,MAAM,cAAc,GAAG;IAC5B,OAAO,EAAE,cAAc,CAAC;IACxB,QAAQ,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,CAAC,OAAO,OAAO,OAAO;IAC3B,OAAO,EAAE,cAAc,CAAC;IAExB;;;OAGG;IACH,QAAQ,UAAgC;IAExC;;;;OAIG;gBACS,OAAO,EAAE,cAAc;IAInC;;;OAGG;IACH,UAAU,IAAI,OAAO;IAIrB;;;;OAIG;IACH,OAAO,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;CAG/B;AAED;;GAEG;AACH,qBAAa,WAAY,SAAQ,OAAO;IACvC,UAAU;IAIV,OAAO;CAGP;AAED;;GAEG;AACH,qBAAa,WAAY,SAAQ,OAAO;IACvC,UAAU;IAIV,OAAO;CAGP;AAED;;;GAGG;AACH,qBAAa,mBAAoB,SAAQ,OAAO;IAC/C,UAAU;IAQV,OAAO;CAGP;AAED;;;;;;GAMG;AACH,qBAAa,iBAAkB,SAAQ,OAAO;IAC7C,SAAS,EAAE,MAAM,CAAC;gBAEN,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc;IAKtD,MAAM,UAA8B;IAEpC,SAAS;IAOT,UAAU;IAyBV,OAAO;CAGP;AAED;;;;;;GAMG;AACH,qBAAa,uBAAwB,SAAQ,OAAO;IACnD,SAAS,EAAE,MAAM,CAAC;gBAEN,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc;IAKtD,MAAM,UAA8B;IAIpC,oBAAoB;IAMpB,SAAS;IAIT,UAAU;IAiBV,OAAO;CAGP;AAED;;;GAGG;AACH,qBAAa,iBAAkB,SAAQ,OAAO;IAC7C,UAAU;IAWV,OAAO;CAuBP;AAED;;;;GAIG;AACH,qBAAa,oBAAqB,SAAQ,OAAO;IAChD,UAAU;IAYV,OAAO;CAMP;AAED;;;GAGG;AACH,qBAAa,gBAAiB,SAAQ,OAAO;IAC5C,UAAU;IAIV,OAAO;CAyGP;AAED;;;GAGG;AACH,qBAAa,wBAAyB,SAAQ,OAAO;IACpD,UAAU;IASV,OAAO;CAKP"}