@vielzeug/necromancer 2.1.0 → 3.0.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 (51) hide show
  1. package/README.md +9 -41
  2. package/dist/_elements.cjs.map +1 -1
  3. package/dist/_elements.d.ts +1 -1
  4. package/dist/_elements.d.ts.map +1 -1
  5. package/dist/_elements.js.map +1 -1
  6. package/dist/_handle.cjs +1 -1
  7. package/dist/_handle.cjs.map +1 -1
  8. package/dist/_handle.d.ts.map +1 -1
  9. package/dist/_handle.js +1 -1
  10. package/dist/_handle.js.map +1 -1
  11. package/dist/_motion.cjs +1 -1
  12. package/dist/_motion.cjs.map +1 -1
  13. package/dist/_motion.d.ts.map +1 -1
  14. package/dist/_motion.js +8 -15
  15. package/dist/_motion.js.map +1 -1
  16. package/dist/animate-each.cjs +1 -1
  17. package/dist/animate-each.cjs.map +1 -1
  18. package/dist/animate-each.d.ts +1 -1
  19. package/dist/animate-each.d.ts.map +1 -1
  20. package/dist/animate-each.js +3 -1
  21. package/dist/animate-each.js.map +1 -1
  22. package/dist/animate.cjs +1 -1
  23. package/dist/animate.cjs.map +1 -1
  24. package/dist/animate.d.ts.map +1 -1
  25. package/dist/animate.js +9 -11
  26. package/dist/animate.js.map +1 -1
  27. package/dist/layout.cjs.map +1 -1
  28. package/dist/layout.d.ts +1 -1
  29. package/dist/layout.d.ts.map +1 -1
  30. package/dist/layout.js.map +1 -1
  31. package/dist/necromancer.cjs +1 -1
  32. package/dist/necromancer.cjs.map +1 -1
  33. package/dist/necromancer.iife.js +1 -1
  34. package/dist/necromancer.iife.js.map +1 -1
  35. package/dist/necromancer.js +1 -1
  36. package/dist/necromancer.js.map +1 -1
  37. package/dist/testing/index.d.ts +7 -7
  38. package/dist/testing/index.d.ts.map +1 -1
  39. package/dist/testing.cjs +1 -1
  40. package/dist/testing.cjs.map +1 -1
  41. package/dist/testing.js +9 -6
  42. package/dist/testing.js.map +1 -1
  43. package/dist/types.d.ts +11 -16
  44. package/dist/types.d.ts.map +1 -1
  45. package/package.json +9 -8
  46. package/dist/_active.cjs +0 -2
  47. package/dist/_active.cjs.map +0 -1
  48. package/dist/_active.d.ts +0 -6
  49. package/dist/_active.d.ts.map +0 -1
  50. package/dist/_active.js +0 -15
  51. package/dist/_active.js.map +0 -1
package/dist/types.d.ts CHANGED
@@ -14,12 +14,12 @@ export type Keyframes = readonly Keyframe[] | PropertyIndexedKeyframes;
14
14
  /**
15
15
  * Native Web Animations timing options with Necromancer's ownership controls.
16
16
  *
17
- * `duration` defaults to `180` milliseconds. `motion` defaults to `'system'`.
18
- * `signal` disposes the returned handle when aborted.
17
+ * `motion` defaults to `'system'`. `signal` disposes the returned handle when aborted.
19
18
  *
20
19
  * Deliberately extends native `KeyframeAnimationOptions` in full rather than a narrower,
21
20
  * Necromancer-specific timing type: every native field (`easing`, `fill`, `iterations`, a
22
- * string `delay`/`duration`, etc.) reaches `element.animate()` unchanged. Callers already
21
+ * string `delay`/`duration`, etc.) reaches `element.animate()` unchanged unless reduced motion
22
+ * normalizes timing. Callers already
23
23
  * fluent in the Web Animations API bring that knowledge here directly, instead of learning
24
24
  * a second, smaller timing vocabulary — the option chain below only ever *adds* ownership
25
25
  * fields on top, never narrows what's already native.
@@ -27,36 +27,31 @@ export type Keyframes = readonly Keyframe[] | PropertyIndexedKeyframes;
27
27
  * Option chain: `AnimateOptions` -> `AnimateEachOptions` (+`stagger`) -> `LayoutAnimationOptions`
28
28
  * (+`elements`). Each layer's implementation module strips only the field it added before
29
29
  * forwarding the rest down (see `animate-each.ts`, `layout.ts`, and `_motion.ts`'s
30
- * `resolveAnimationOptions()`, which is the last stop and strips `interrupt`/`motion`/`signal`).
30
+ * `resolveAnimationOptions()`, which is the last stop and strips `motion`/`signal`).
31
31
  */
32
32
  export type AnimateOptions = KeyframeAnimationOptions & {
33
- /**
34
- * Cancels every active Necromancer-owned animation on the element as this
35
- * animation begins. Native animations owned outside Necromancer are untouched.
36
- */
37
- readonly interrupt?: 'cancel';
38
33
  readonly motion?: MotionMode;
39
34
  readonly signal?: AbortSignal;
40
35
  };
41
36
  /** Produces keyframes for an element at a stable position in an animation group. */
42
- export type KeyframeFactory = (element: Element, index: number, total: number) => Keyframes;
37
+ export type KeyframeFactory<ElementType extends Element = Element> = (element: ElementType, index: number, total: number) => Keyframes;
43
38
  /** Options for animating a group of elements. */
44
39
  export type AnimateEachOptions = AnimateOptions & {
45
40
  /** Milliseconds to delay each element after the preceding element. Defaults to `0`. */
46
41
  readonly stagger?: number;
47
42
  };
48
43
  /** Options for animating positional layout changes captured by {@link captureLayout}. */
49
- export type LayoutAnimationOptions = AnimateEachOptions & {
44
+ export type LayoutAnimationOptions<ElementType extends Element = Element> = AnimateEachOptions & {
50
45
  /**
51
46
  * Elements in their committed layout. With {@link LayoutCaptureOptions.getKey},
52
47
  * replacement elements match their captured predecessors by key.
53
48
  */
54
- readonly elements?: Iterable<Element>;
49
+ readonly elements?: Iterable<ElementType>;
55
50
  };
56
51
  /** Options for capturing positional layout changes. */
57
- export interface LayoutCaptureOptions {
52
+ export interface LayoutCaptureOptions<ElementType extends Element = Element> {
58
53
  /** Maps an element to its stable, non-empty identity across a DOM replacement. */
59
- readonly getKey?: (element: Element) => string;
54
+ readonly getKey?: (element: ElementType) => string;
60
55
  }
61
56
  /** A lifecycle-owned native Web Animation. */
62
57
  export interface AnimationHandle {
@@ -85,13 +80,13 @@ export interface AnimationGroup {
85
80
  [Symbol.dispose](): void;
86
81
  }
87
82
  /** A one-shot positional layout transition returned by {@link captureLayout}. */
88
- export interface LayoutTransition {
83
+ export interface LayoutTransition<ElementType extends Element = Element> {
89
84
  /**
90
85
  * Measures the current layout and animates elements from their captured positions.
91
86
  *
92
87
  * Omit `options.elements` to animate the captured elements, or supply the
93
88
  * committed replacements when the transition was captured with `getKey`.
94
89
  */
95
- animate(options?: LayoutAnimationOptions): AnimationGroup;
90
+ animate(options?: LayoutAnimationOptions<ElementType>): AnimationGroup;
96
91
  }
97
92
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,CAAC;AAEvD,0DAA0D;AAC1D,MAAM,MAAM,eAAe,GACvB;IAAE,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAA;CAAE,GAC/B;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAA;CAAE,GAC9B;IAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;CAAE,CAAC;AAEhE,oDAAoD;AACpD,MAAM,MAAM,SAAS,GAAG,SAAS,QAAQ,EAAE,GAAG,wBAAwB,CAAC;AAEvE;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,MAAM,cAAc,GAAG,wBAAwB,GAAG;IACtD;;;OAGG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC;IAC9B,QAAQ,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B,CAAC;AAEF,oFAAoF;AACpF,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,SAAS,CAAC;AAE5F,iDAAiD;AACjD,MAAM,MAAM,kBAAkB,GAAG,cAAc,GAAG;IAChD,uFAAuF;IACvF,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,yFAAyF;AACzF,MAAM,MAAM,sBAAsB,GAAG,kBAAkB,GAAG;IACxD;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;CACvC,CAAC;AAEF,uDAAuD;AACvD,MAAM,WAAW,oBAAoB;IACnC,kFAAkF;IAClF,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAC;CAChD;AAED,8CAA8C;AAC9C,MAAM,WAAW,eAAe;IAC9B,gDAAgD;IAChD,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,iEAAiE;IACjE,OAAO,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAChC,6CAA6C;IAC7C,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,yEAAyE;IACzE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IAC1C,6BAA6B;IAC7B,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC;CAC1B;AAED,kDAAkD;AAClD,MAAM,WAAW,cAAc;IAC7B,yDAAyD;IACzD,OAAO,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAChC,4CAA4C;IAC5C,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,kEAAkE;IAClE,QAAQ,CAAC,OAAO,EAAE,SAAS,eAAe,EAAE,CAAC;IAC7C,iEAAiE;IACjE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,SAAS,eAAe,EAAE,CAAC,CAAC;IACtD,6BAA6B;IAC7B,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC;CAC1B;AAED,iFAAiF;AACjF,MAAM,WAAW,gBAAgB;IAC/B;;;;;OAKG;IACH,OAAO,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,cAAc,CAAC;CAC3D"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,CAAC;AAEvD,0DAA0D;AAC1D,MAAM,MAAM,eAAe,GACvB;IAAE,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAA;CAAE,GAC/B;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAA;CAAE,GAC9B;IAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;CAAE,CAAC;AAEhE,oDAAoD;AACpD,MAAM,MAAM,SAAS,GAAG,SAAS,QAAQ,EAAE,GAAG,wBAAwB,CAAC;AAEvE;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,MAAM,cAAc,GAAG,wBAAwB,GAAG;IACtD,QAAQ,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B,CAAC;AAEF,oFAAoF;AACpF,MAAM,MAAM,eAAe,CAAC,WAAW,SAAS,OAAO,GAAG,OAAO,IAAI,CACnE,OAAO,EAAE,WAAW,EACpB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,KACV,SAAS,CAAC;AAEf,iDAAiD;AACjD,MAAM,MAAM,kBAAkB,GAAG,cAAc,GAAG;IAChD,uFAAuF;IACvF,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,yFAAyF;AACzF,MAAM,MAAM,sBAAsB,CAAC,WAAW,SAAS,OAAO,GAAG,OAAO,IAAI,kBAAkB,GAAG;IAC/F;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;CAC3C,CAAC;AAEF,uDAAuD;AACvD,MAAM,WAAW,oBAAoB,CAAC,WAAW,SAAS,OAAO,GAAG,OAAO;IACzE,kFAAkF;IAClF,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,MAAM,CAAC;CACpD;AAED,8CAA8C;AAC9C,MAAM,WAAW,eAAe;IAC9B,gDAAgD;IAChD,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,iEAAiE;IACjE,OAAO,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAChC,6CAA6C;IAC7C,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,yEAAyE;IACzE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IAC1C,6BAA6B;IAC7B,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC;CAC1B;AAED,kDAAkD;AAClD,MAAM,WAAW,cAAc;IAC7B,yDAAyD;IACzD,OAAO,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAChC,4CAA4C;IAC5C,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,kEAAkE;IAClE,QAAQ,CAAC,OAAO,EAAE,SAAS,eAAe,EAAE,CAAC;IAC7C,iEAAiE;IACjE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,SAAS,eAAe,EAAE,CAAC,CAAC;IACtD,6BAA6B;IAC7B,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC;CAC1B;AAED,iFAAiF;AACjF,MAAM,WAAW,gBAAgB,CAAC,WAAW,SAAS,OAAO,GAAG,OAAO;IACrE;;;;;OAKG;IACH,OAAO,CAAC,OAAO,CAAC,EAAE,sBAAsB,CAAC,WAAW,CAAC,GAAG,cAAc,CAAC;CACxE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vielzeug/necromancer",
3
- "version": "2.1.0",
3
+ "version": "3.0.0",
4
4
  "description": "Dependency-free, lifecycle-owned animation primitives built on the Web Animations API",
5
5
  "repository": {
6
6
  "type": "git",
@@ -42,21 +42,22 @@
42
42
  "registry": "https://registry.npmjs.org/"
43
43
  },
44
44
  "scripts": {
45
- "build": "vite build && pnpm run build:bundle && pnpm run build:types",
45
+ "build": "vite build && pnpm --silent run build:bundle && pnpm --silent run build:types && pnpm --silent run test:types",
46
46
  "build:bundle": "vite build --config vite.bundle.config.ts",
47
47
  "build:types": "tsc -p tsconfig.declarations.json",
48
48
  "fix": "biome check --write src",
49
49
  "lint": "biome ci src",
50
- "prepublishOnly": "pnpm run build",
50
+ "prepublishOnly": "pnpm --silent run build",
51
51
  "test": "vitest",
52
- "test:e2e": "pnpm run build && playwright test"
52
+ "test:e2e": "pnpm --silent run build && playwright test",
53
+ "test:types": "tsc -p tsconfig.type-tests.json"
53
54
  },
54
55
  "devDependencies": {
55
- "@playwright/test": "^1.62.1",
56
- "@types/node": "^26.2.0",
56
+ "@playwright/test": "^1.63.0",
57
+ "@types/node": "^26.4.1",
57
58
  "jsdom": "^30.0.1",
58
59
  "typescript": "^6.0.3",
59
- "vite": "^8.2.1",
60
- "vitest": "^4.1.10"
60
+ "vite": "^8.2.2",
61
+ "vitest": "^5.0.0"
61
62
  }
62
63
  }
package/dist/_active.cjs DELETED
@@ -1,2 +0,0 @@
1
- var e=new WeakMap;function t(t){for(let n of e.get(t)??[])n.dispose()}function n(t,n){let r=e.get(t);r||(r=new Set,e.set(t,r)),r.add(n),n.result.then(()=>{r?.delete(n),r?.size===0&&e.delete(t)})}exports.interruptAnimations=t,exports.trackAnimation=n;
2
- //# sourceMappingURL=_active.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"_active.cjs","names":[],"sources":["../src/_active.ts"],"sourcesContent":["import type { AnimationHandle } from './types';\n\n// Scoped to one DOM element by design: `interrupt: 'cancel'` answers \"replace whatever\n// Necromancer is doing to *this* element\", not \"coordinate across element categories\".\n// A caller that needs to cancel an animation on a different element (or coordinate several\n// elements as one unit) already has that element's own handle, or should use `animateEach()`\n// and a shared `signal` instead. Keeping the WeakMap element-scoped means it only ever needs\n// to answer one question and never grows into a general-purpose animation registry.\nconst handlesByElement = new WeakMap<Element, Set<AnimationHandle>>();\n\n/** Cancels active Necromancer-owned animations without touching native animations owned by callers. */\nexport function interruptAnimations(element: Element): void {\n for (const handle of handlesByElement.get(element) ?? []) handle.dispose();\n}\n\n/** Tracks a handle until its terminal result releases the element association. */\nexport function trackAnimation(element: Element, handle: AnimationHandle): void {\n let handles = handlesByElement.get(element);\n\n if (!handles) {\n handles = new Set();\n handlesByElement.set(element, handles);\n }\n\n handles.add(handle);\n\n void handle.result.then(() => {\n handles?.delete(handle);\n\n if (handles?.size === 0) handlesByElement.delete(element);\n });\n}\n"],"mappings":"AAQA,IAAM,EAAmB,IAAI,QAG7B,SAAgB,EAAoB,EAAwB,CAC1D,IAAK,IAAM,KAAU,EAAiB,IAAI,CAAO,GAAK,CAAC,EAAG,EAAO,QAAQ,CAC3E,CAGA,SAAgB,EAAe,EAAkB,EAA+B,CAC9E,IAAI,EAAU,EAAiB,IAAI,CAAO,EAErC,IACH,EAAU,IAAI,IACd,EAAiB,IAAI,EAAS,CAAO,GAGvC,EAAQ,IAAI,CAAM,EAElB,EAAY,OAAO,SAAW,CAC5B,GAAS,OAAO,CAAM,EAElB,GAAS,OAAS,GAAG,EAAiB,OAAO,CAAO,CAC1D,CAAC,CACH"}
package/dist/_active.d.ts DELETED
@@ -1,6 +0,0 @@
1
- import type { AnimationHandle } from './types';
2
- /** Cancels active Necromancer-owned animations without touching native animations owned by callers. */
3
- export declare function interruptAnimations(element: Element): void;
4
- /** Tracks a handle until its terminal result releases the element association. */
5
- export declare function trackAnimation(element: Element, handle: AnimationHandle): void;
6
- //# sourceMappingURL=_active.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"_active.d.ts","sourceRoot":"","sources":["../src/_active.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAU/C,uGAAuG;AACvG,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAE1D;AAED,kFAAkF;AAClF,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAe9E"}
package/dist/_active.js DELETED
@@ -1,15 +0,0 @@
1
- //#region src/_active.ts
2
- var e = /* @__PURE__ */ new WeakMap();
3
- function t(t) {
4
- for (let n of e.get(t) ?? []) n.dispose();
5
- }
6
- function n(t, n) {
7
- let r = e.get(t);
8
- r || (r = /* @__PURE__ */ new Set(), e.set(t, r)), r.add(n), n.result.then(() => {
9
- r?.delete(n), r?.size === 0 && e.delete(t);
10
- });
11
- }
12
- //#endregion
13
- export { t as interruptAnimations, n as trackAnimation };
14
-
15
- //# sourceMappingURL=_active.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"_active.js","names":[],"sources":["../src/_active.ts"],"sourcesContent":["import type { AnimationHandle } from './types';\n\n// Scoped to one DOM element by design: `interrupt: 'cancel'` answers \"replace whatever\n// Necromancer is doing to *this* element\", not \"coordinate across element categories\".\n// A caller that needs to cancel an animation on a different element (or coordinate several\n// elements as one unit) already has that element's own handle, or should use `animateEach()`\n// and a shared `signal` instead. Keeping the WeakMap element-scoped means it only ever needs\n// to answer one question and never grows into a general-purpose animation registry.\nconst handlesByElement = new WeakMap<Element, Set<AnimationHandle>>();\n\n/** Cancels active Necromancer-owned animations without touching native animations owned by callers. */\nexport function interruptAnimations(element: Element): void {\n for (const handle of handlesByElement.get(element) ?? []) handle.dispose();\n}\n\n/** Tracks a handle until its terminal result releases the element association. */\nexport function trackAnimation(element: Element, handle: AnimationHandle): void {\n let handles = handlesByElement.get(element);\n\n if (!handles) {\n handles = new Set();\n handlesByElement.set(element, handles);\n }\n\n handles.add(handle);\n\n void handle.result.then(() => {\n handles?.delete(handle);\n\n if (handles?.size === 0) handlesByElement.delete(element);\n });\n}\n"],"mappings":";AAQA,IAAM,oBAAmB,IAAI,QAAuC;AAGpE,SAAgB,EAAoB,GAAwB;CAC1D,KAAK,IAAM,KAAU,EAAiB,IAAI,CAAO,KAAK,CAAC,GAAG,EAAO,QAAQ;AAC3E;AAGA,SAAgB,EAAe,GAAkB,GAA+B;CAC9E,IAAI,IAAU,EAAiB,IAAI,CAAO;CAS1C,AAPK,MACH,oBAAU,IAAI,IAAI,GAClB,EAAiB,IAAI,GAAS,CAAO,IAGvC,EAAQ,IAAI,CAAM,GAElB,EAAY,OAAO,WAAW;EAG5B,AAFA,GAAS,OAAO,CAAM,GAElB,GAAS,SAAS,KAAG,EAAiB,OAAO,CAAO;CAC1D,CAAC;AACH"}