ember-nav-stack 7.1.1 → 7.1.2
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.
|
@@ -67,6 +67,14 @@ class NavStacks extends Service {
|
|
|
67
67
|
didUpdate() {} // hook
|
|
68
68
|
|
|
69
69
|
_schedule() {
|
|
70
|
+
// Lazy-open the initial-render token here (idempotent + no-op once
|
|
71
|
+
// the initial render has completed). The token bridges the gap
|
|
72
|
+
// between a consumer's first ToNavStack mounting and `_process`
|
|
73
|
+
// running afterRender. Opening it lazily means a NavStacks service
|
|
74
|
+
// that's instantiated but never pushed to doesn't leak a pending
|
|
75
|
+
// waiter that would hang `await settled()` in unrelated tests
|
|
76
|
+
// (see Y-1306).
|
|
77
|
+
this._waiter.beginInitialRender();
|
|
70
78
|
this._waiter.beginStackUpdate();
|
|
71
79
|
scheduleOnce('afterRender', this, this._process);
|
|
72
80
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nav-stacks.js","sources":["../../src/services/nav-stacks.js"],"sourcesContent":["import Service from '@ember/service';\nimport { next, scheduleOnce } from '@ember/runloop';\nimport { tracked } from '@glimmer/tracking';\nimport WaiterState from '../utils/waiter-state.js';\n\nexport default class NavStacks extends Service {\n @tracked stacks = {};\n @tracked isInitialRender = true;\n\n constructor() {\n super(...arguments);\n this._waiter = new WaiterState();\n this._listeners = [];\n this._itemsById = {};\n this._counter = 1;\n }\n\n pushItem(sourceId, layer, component, headerComponent) {\n this._itemsById[sourceId] = {\n layer,\n component,\n headerComponent,\n order: this._counter++,\n };\n this._schedule();\n }\n\n removeItem(sourceId) {\n delete this._itemsById[sourceId];\n this._schedule();\n }\n\n register(layerContainerComponent) {\n this._listeners.push(layerContainerComponent);\n }\n\n unregister(layerContainerComponent) {\n let idx = this._listeners.indexOf(layerContainerComponent);\n if (idx !== -1) {\n this._listeners.splice(idx, 1);\n }\n }\n\n notifyTransitionStart() {\n this._waiter.beginTransition();\n }\n\n notifyTransitionEnd() {\n this._waiter.endTransition();\n next(this._waiter, this._waiter.maybeResolveIdle);\n }\n\n runningTransitions() {\n return this._waiter.runningTransitions();\n }\n\n isRunningTransitions() {\n return this._waiter.isRunningTransitions();\n }\n\n waitUntilTransitionIdle() {\n let promise = this._waiter.whenIdle();\n next(this._waiter, this._waiter.maybeResolveIdle);\n return promise;\n }\n\n didUpdate() {} // hook\n\n _schedule() {\n this._waiter.beginStackUpdate();\n scheduleOnce('afterRender', this, this._process);\n }\n\n _process() {\n let newStacks = {};\n let itemsById = this._itemsById;\n let wasInitialRender = this.isInitialRender === true;\n\n for (let sourceId in itemsById) {\n let { layer, component, headerComponent, order } = itemsById[sourceId];\n let layerName = `layer${layer}`;\n newStacks[layerName] = newStacks[layerName] || [];\n let newItem = component ? { component, headerComponent, order } : null;\n newStacks[layerName].push(newItem);\n }\n for (let layerName in newStacks) {\n newStacks[layerName].sort((a, b) => a.order - b.order);\n }\n // Detect layers that just emptied (had items in the prior snapshot,\n // none in the new). Those NavStacks are about to be torn down by the\n // host's `{{#each (nav-layer-indices)}}` once we publish `this.stacks`,\n // and their willDestroy fires too late to capture a slide-down clone\n // (Glimmer detaches the element before willDestroy runs). Notify them\n // here, while their DOM is still attached, so they can start a\n // detached dismissal animation that outlives the impending teardown.\n let oldStacks = this.stacks;\n for (let listener of this._listeners) {\n let layer = listener.args?.layer ?? listener.layer;\n let oldList = oldStacks[`layer${layer}`];\n let newList = newStacks[`layer${layer}`];\n if ((oldList?.length ?? 0) > 0 && (newList?.length ?? 0) === 0) {\n listener.layerDidEmpty?.();\n }\n }\n this.stacks = newStacks;\n if (this.isInitialRender === true) {\n next(this, this._clearIsInitialRender);\n }\n for (let listener of this._listeners) {\n listener.stackItemsDidChange?.();\n }\n this.didUpdate();\n next(() => {\n if (wasInitialRender) {\n this._waiter.markInitialRenderComplete();\n }\n this._waiter.endStackUpdate();\n this._waiter.maybeResolveIdle();\n });\n }\n\n _clearIsInitialRender() {\n if (this.isDestroyed || this.isDestroying) {\n return;\n }\n this.isInitialRender = false;\n }\n}\n"],"names":["NavStacks","Service","g","prototype","tracked","i","constructor","arguments","_waiter","WaiterState","_listeners","_itemsById","_counter","pushItem","sourceId","layer","component","headerComponent","order","_schedule","removeItem","register","layerContainerComponent","push","unregister","idx","indexOf","splice","notifyTransitionStart","beginTransition","notifyTransitionEnd","endTransition","next","maybeResolveIdle","runningTransitions","isRunningTransitions","waitUntilTransitionIdle","promise","whenIdle","didUpdate","beginStackUpdate","scheduleOnce","_process","newStacks","itemsById","wasInitialRender","isInitialRender","layerName","newItem","sort","a","b","oldStacks","stacks","listener","args","oldList","newList","length","layerDidEmpty","_clearIsInitialRender","stackItemsDidChange","markInitialRenderComplete","endStackUpdate","isDestroyed","isDestroying"],"mappings":"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
|
|
1
|
+
{"version":3,"file":"nav-stacks.js","sources":["../../src/services/nav-stacks.js"],"sourcesContent":["import Service from '@ember/service';\nimport { next, scheduleOnce } from '@ember/runloop';\nimport { tracked } from '@glimmer/tracking';\nimport WaiterState from '../utils/waiter-state.js';\n\nexport default class NavStacks extends Service {\n @tracked stacks = {};\n @tracked isInitialRender = true;\n\n constructor() {\n super(...arguments);\n this._waiter = new WaiterState();\n this._listeners = [];\n this._itemsById = {};\n this._counter = 1;\n }\n\n pushItem(sourceId, layer, component, headerComponent) {\n this._itemsById[sourceId] = {\n layer,\n component,\n headerComponent,\n order: this._counter++,\n };\n this._schedule();\n }\n\n removeItem(sourceId) {\n delete this._itemsById[sourceId];\n this._schedule();\n }\n\n register(layerContainerComponent) {\n this._listeners.push(layerContainerComponent);\n }\n\n unregister(layerContainerComponent) {\n let idx = this._listeners.indexOf(layerContainerComponent);\n if (idx !== -1) {\n this._listeners.splice(idx, 1);\n }\n }\n\n notifyTransitionStart() {\n this._waiter.beginTransition();\n }\n\n notifyTransitionEnd() {\n this._waiter.endTransition();\n next(this._waiter, this._waiter.maybeResolveIdle);\n }\n\n runningTransitions() {\n return this._waiter.runningTransitions();\n }\n\n isRunningTransitions() {\n return this._waiter.isRunningTransitions();\n }\n\n waitUntilTransitionIdle() {\n let promise = this._waiter.whenIdle();\n next(this._waiter, this._waiter.maybeResolveIdle);\n return promise;\n }\n\n didUpdate() {} // hook\n\n _schedule() {\n // Lazy-open the initial-render token here (idempotent + no-op once\n // the initial render has completed). The token bridges the gap\n // between a consumer's first ToNavStack mounting and `_process`\n // running afterRender. Opening it lazily means a NavStacks service\n // that's instantiated but never pushed to doesn't leak a pending\n // waiter that would hang `await settled()` in unrelated tests\n // (see Y-1306).\n this._waiter.beginInitialRender();\n this._waiter.beginStackUpdate();\n scheduleOnce('afterRender', this, this._process);\n }\n\n _process() {\n let newStacks = {};\n let itemsById = this._itemsById;\n let wasInitialRender = this.isInitialRender === true;\n\n for (let sourceId in itemsById) {\n let { layer, component, headerComponent, order } = itemsById[sourceId];\n let layerName = `layer${layer}`;\n newStacks[layerName] = newStacks[layerName] || [];\n let newItem = component ? { component, headerComponent, order } : null;\n newStacks[layerName].push(newItem);\n }\n for (let layerName in newStacks) {\n newStacks[layerName].sort((a, b) => a.order - b.order);\n }\n // Detect layers that just emptied (had items in the prior snapshot,\n // none in the new). Those NavStacks are about to be torn down by the\n // host's `{{#each (nav-layer-indices)}}` once we publish `this.stacks`,\n // and their willDestroy fires too late to capture a slide-down clone\n // (Glimmer detaches the element before willDestroy runs). Notify them\n // here, while their DOM is still attached, so they can start a\n // detached dismissal animation that outlives the impending teardown.\n let oldStacks = this.stacks;\n for (let listener of this._listeners) {\n let layer = listener.args?.layer ?? listener.layer;\n let oldList = oldStacks[`layer${layer}`];\n let newList = newStacks[`layer${layer}`];\n if ((oldList?.length ?? 0) > 0 && (newList?.length ?? 0) === 0) {\n listener.layerDidEmpty?.();\n }\n }\n this.stacks = newStacks;\n if (this.isInitialRender === true) {\n next(this, this._clearIsInitialRender);\n }\n for (let listener of this._listeners) {\n listener.stackItemsDidChange?.();\n }\n this.didUpdate();\n next(() => {\n if (wasInitialRender) {\n this._waiter.markInitialRenderComplete();\n }\n this._waiter.endStackUpdate();\n this._waiter.maybeResolveIdle();\n });\n }\n\n _clearIsInitialRender() {\n if (this.isDestroyed || this.isDestroying) {\n return;\n }\n this.isInitialRender = false;\n }\n}\n"],"names":["NavStacks","Service","g","prototype","tracked","i","constructor","arguments","_waiter","WaiterState","_listeners","_itemsById","_counter","pushItem","sourceId","layer","component","headerComponent","order","_schedule","removeItem","register","layerContainerComponent","push","unregister","idx","indexOf","splice","notifyTransitionStart","beginTransition","notifyTransitionEnd","endTransition","next","maybeResolveIdle","runningTransitions","isRunningTransitions","waitUntilTransitionIdle","promise","whenIdle","didUpdate","beginInitialRender","beginStackUpdate","scheduleOnce","_process","newStacks","itemsById","wasInitialRender","isInitialRender","layerName","newItem","sort","a","b","oldStacks","stacks","listener","args","oldList","newList","length","layerDidEmpty","_clearIsInitialRender","stackItemsDidChange","markInitialRenderComplete","endStackUpdate","isDestroyed","isDestroying"],"mappings":"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"}
|
|
@@ -19,9 +19,15 @@ const STACK_WAITER = buildWaiter('ember-nav-stack:stack-update');
|
|
|
19
19
|
// closes when runningTransitions returns to 0
|
|
20
20
|
// - stackUpdate opens on beginStackUpdate (idempotent),
|
|
21
21
|
// closes on endStackUpdate
|
|
22
|
-
// - initialRender opens once
|
|
23
|
-
//
|
|
24
|
-
//
|
|
22
|
+
// - initialRender opens once on the first beginInitialRender call
|
|
23
|
+
// (no-op if already opened or already completed),
|
|
24
|
+
// closes once on markInitialRenderComplete. Opening
|
|
25
|
+
// is deliberately LAZY: if a consumer instantiates
|
|
26
|
+
// the NavStacks service but never pushes a stack
|
|
27
|
+
// item, no token ever opens — so `await settled()`
|
|
28
|
+
// in unrelated tests doesn't hang on a waiter for
|
|
29
|
+
// an initial render that's never going to happen
|
|
30
|
+
// (see Y-1306).
|
|
25
31
|
//
|
|
26
32
|
// isIdle === all three tokens CLOSED && runningTransitions === 0
|
|
27
33
|
//
|
|
@@ -38,7 +44,8 @@ class WaiterState {
|
|
|
38
44
|
constructor() {
|
|
39
45
|
this._transitionToken = null;
|
|
40
46
|
this._stackUpdateToken = null;
|
|
41
|
-
this._initialRenderToken =
|
|
47
|
+
this._initialRenderToken = null;
|
|
48
|
+
this._initialRenderDone = false;
|
|
42
49
|
this._runningTransitions = 0;
|
|
43
50
|
this._whenIdlePromise = null;
|
|
44
51
|
this._whenIdleResolve = null;
|
|
@@ -86,13 +93,24 @@ class WaiterState {
|
|
|
86
93
|
return !!this._stackUpdateToken;
|
|
87
94
|
}
|
|
88
95
|
|
|
89
|
-
// Initial-render token (
|
|
96
|
+
// Initial-render token (opens lazily on first beginInitialRender call,
|
|
97
|
+
// closes at most once on markInitialRenderComplete)
|
|
90
98
|
|
|
99
|
+
// Open the initial-render token if it hasn't been opened yet and hasn't
|
|
100
|
+
// already been completed. Called from `NavStacks._schedule()` so the
|
|
101
|
+
// token only exists when there's actually a first render to bridge.
|
|
102
|
+
beginInitialRender() {
|
|
103
|
+
if (this._initialRenderDone || this._initialRenderToken) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
this._initialRenderToken = STACK_WAITER.beginAsync();
|
|
107
|
+
}
|
|
91
108
|
markInitialRenderComplete() {
|
|
92
109
|
if (this._initialRenderToken) {
|
|
93
110
|
STACK_WAITER.endAsync(this._initialRenderToken);
|
|
94
111
|
this._initialRenderToken = null;
|
|
95
112
|
}
|
|
113
|
+
this._initialRenderDone = true;
|
|
96
114
|
}
|
|
97
115
|
hasPendingInitialRender() {
|
|
98
116
|
return !!this._initialRenderToken;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"waiter-state.js","sources":["../../src/utils/waiter-state.js"],"sourcesContent":["import { buildWaiter } from '@ember/test-waiters';\n\n// `buildWaiter` registers a named waiter globally in `@ember/test-waiters`.\n// Hoist these to module scope so every WaiterState instance shares the same\n// two waiters — without this, each `new WaiterState()` (notably in unit\n// tests) would register a fresh duplicate, accumulating noise in the global\n// waiter registry over a test run.\nconst TRANSITION_WAITER = buildWaiter('ember-nav-stack:transition');\nconst STACK_WAITER = buildWaiter('ember-nav-stack:stack-update');\n\n// Encapsulates the three test-waiter tokens NavStacks needs to manage\n// (transition, stack-update, initial-render), a counter for currently\n// running transitions, and a single-resolver \"wait until idle\" promise.\n//\n// State diagram:\n//\n// Tokens (each independently OPEN or CLOSED):\n// - transition opens when runningTransitions goes 0 → 1,\n// closes when runningTransitions returns to 0\n// - stackUpdate opens on beginStackUpdate (idempotent),\n// closes on endStackUpdate\n// - initialRender opens once
|
|
1
|
+
{"version":3,"file":"waiter-state.js","sources":["../../src/utils/waiter-state.js"],"sourcesContent":["import { buildWaiter } from '@ember/test-waiters';\n\n// `buildWaiter` registers a named waiter globally in `@ember/test-waiters`.\n// Hoist these to module scope so every WaiterState instance shares the same\n// two waiters — without this, each `new WaiterState()` (notably in unit\n// tests) would register a fresh duplicate, accumulating noise in the global\n// waiter registry over a test run.\nconst TRANSITION_WAITER = buildWaiter('ember-nav-stack:transition');\nconst STACK_WAITER = buildWaiter('ember-nav-stack:stack-update');\n\n// Encapsulates the three test-waiter tokens NavStacks needs to manage\n// (transition, stack-update, initial-render), a counter for currently\n// running transitions, and a single-resolver \"wait until idle\" promise.\n//\n// State diagram:\n//\n// Tokens (each independently OPEN or CLOSED):\n// - transition opens when runningTransitions goes 0 → 1,\n// closes when runningTransitions returns to 0\n// - stackUpdate opens on beginStackUpdate (idempotent),\n// closes on endStackUpdate\n// - initialRender opens once on the first beginInitialRender call\n// (no-op if already opened or already completed),\n// closes once on markInitialRenderComplete. Opening\n// is deliberately LAZY: if a consumer instantiates\n// the NavStacks service but never pushes a stack\n// item, no token ever opens — so `await settled()`\n// in unrelated tests doesn't hang on a waiter for\n// an initial render that's never going to happen\n// (see Y-1306).\n//\n// isIdle === all three tokens CLOSED && runningTransitions === 0\n//\n// whenIdle() returns a Promise that resolves the next time isIdle()\n// becomes true and maybeResolveIdle() is invoked. Repeat callers\n// while waiting share one promise.\n//\n// `maybeResolveIdle()` is an explicit method (not auto-called from\n// end*/markX) so the caller can wrap it in `next()` (or any other\n// scheduler) — that defers resolution past the current runloop tick,\n// giving other code in the same tick a chance to start another\n// transition before \"idle\" is declared.\nexport default class WaiterState {\n constructor() {\n this._transitionToken = null;\n this._stackUpdateToken = null;\n this._initialRenderToken = null;\n this._initialRenderDone = false;\n this._runningTransitions = 0;\n this._whenIdlePromise = null;\n this._whenIdleResolve = null;\n }\n\n // Transition counter\n\n beginTransition() {\n this._runningTransitions++;\n if (this._runningTransitions === 1) {\n this._transitionToken = TRANSITION_WAITER.beginAsync();\n }\n }\n\n endTransition() {\n this._runningTransitions--;\n if (this._runningTransitions < 0) {\n this._runningTransitions = 0;\n }\n if (this._runningTransitions === 0 && this._transitionToken) {\n TRANSITION_WAITER.endAsync(this._transitionToken);\n this._transitionToken = null;\n }\n }\n\n runningTransitions() {\n return this._runningTransitions;\n }\n\n isRunningTransitions() {\n return this._runningTransitions > 0;\n }\n\n // Stack-update token (coalesced across pushItem/removeItem in one flush)\n\n beginStackUpdate() {\n if (!this._stackUpdateToken) {\n this._stackUpdateToken = STACK_WAITER.beginAsync();\n }\n }\n\n endStackUpdate() {\n if (this._stackUpdateToken) {\n STACK_WAITER.endAsync(this._stackUpdateToken);\n this._stackUpdateToken = null;\n }\n }\n\n hasPendingStackUpdate() {\n return !!this._stackUpdateToken;\n }\n\n // Initial-render token (opens lazily on first beginInitialRender call,\n // closes at most once on markInitialRenderComplete)\n\n // Open the initial-render token if it hasn't been opened yet and hasn't\n // already been completed. Called from `NavStacks._schedule()` so the\n // token only exists when there's actually a first render to bridge.\n beginInitialRender() {\n if (this._initialRenderDone || this._initialRenderToken) {\n return;\n }\n this._initialRenderToken = STACK_WAITER.beginAsync();\n }\n\n markInitialRenderComplete() {\n if (this._initialRenderToken) {\n STACK_WAITER.endAsync(this._initialRenderToken);\n this._initialRenderToken = null;\n }\n this._initialRenderDone = true;\n }\n\n hasPendingInitialRender() {\n return !!this._initialRenderToken;\n }\n\n // Idle queries + promise\n\n isIdle() {\n return (\n this._runningTransitions === 0 &&\n !this._stackUpdateToken &&\n !this._initialRenderToken\n );\n }\n\n whenIdle() {\n if (this._whenIdlePromise) {\n return this._whenIdlePromise;\n }\n this._whenIdlePromise = new Promise((resolve) => {\n this._whenIdleResolve = resolve;\n });\n return this._whenIdlePromise;\n }\n\n // Resolves any outstanding whenIdle() promise if all tokens are closed\n // and no transitions are running. No-op otherwise. Callers schedule this\n // via `next()` (or similar) to defer resolution past the current tick.\n maybeResolveIdle() {\n if (this.isIdle() && this._whenIdleResolve) {\n let resolve = this._whenIdleResolve;\n this._whenIdleResolve = null;\n this._whenIdlePromise = null;\n resolve();\n }\n }\n}\n"],"names":["TRANSITION_WAITER","buildWaiter","STACK_WAITER","WaiterState","constructor","_transitionToken","_stackUpdateToken","_initialRenderToken","_initialRenderDone","_runningTransitions","_whenIdlePromise","_whenIdleResolve","beginTransition","beginAsync","endTransition","endAsync","runningTransitions","isRunningTransitions","beginStackUpdate","endStackUpdate","hasPendingStackUpdate","beginInitialRender","markInitialRenderComplete","hasPendingInitialRender","isIdle","whenIdle","Promise","resolve","maybeResolveIdle"],"mappings":";;AAEA;AACA;AACA;AACA;AACA;AACA,MAAMA,iBAAiB,GAAGC,WAAW,CAAC,4BAA4B,CAAC;AACnE,MAAMC,YAAY,GAAGD,WAAW,CAAC,8BAA8B,CAAC;;AAEhE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACe,MAAME,WAAW,CAAC;AAC/BC,EAAAA,WAAWA,GAAG;IACZ,IAAI,CAACC,gBAAgB,GAAG,IAAI;IAC5B,IAAI,CAACC,iBAAiB,GAAG,IAAI;IAC7B,IAAI,CAACC,mBAAmB,GAAG,IAAI;IAC/B,IAAI,CAACC,kBAAkB,GAAG,KAAK;IAC/B,IAAI,CAACC,mBAAmB,GAAG,CAAC;IAC5B,IAAI,CAACC,gBAAgB,GAAG,IAAI;IAC5B,IAAI,CAACC,gBAAgB,GAAG,IAAI;AAC9B,EAAA;;AAEA;;AAEAC,EAAAA,eAAeA,GAAG;IAChB,IAAI,CAACH,mBAAmB,EAAE;AAC1B,IAAA,IAAI,IAAI,CAACA,mBAAmB,KAAK,CAAC,EAAE;AAClC,MAAA,IAAI,CAACJ,gBAAgB,GAAGL,iBAAiB,CAACa,UAAU,EAAE;AACxD,IAAA;AACF,EAAA;AAEAC,EAAAA,aAAaA,GAAG;IACd,IAAI,CAACL,mBAAmB,EAAE;AAC1B,IAAA,IAAI,IAAI,CAACA,mBAAmB,GAAG,CAAC,EAAE;MAChC,IAAI,CAACA,mBAAmB,GAAG,CAAC;AAC9B,IAAA;IACA,IAAI,IAAI,CAACA,mBAAmB,KAAK,CAAC,IAAI,IAAI,CAACJ,gBAAgB,EAAE;AAC3DL,MAAAA,iBAAiB,CAACe,QAAQ,CAAC,IAAI,CAACV,gBAAgB,CAAC;MACjD,IAAI,CAACA,gBAAgB,GAAG,IAAI;AAC9B,IAAA;AACF,EAAA;AAEAW,EAAAA,kBAAkBA,GAAG;IACnB,OAAO,IAAI,CAACP,mBAAmB;AACjC,EAAA;AAEAQ,EAAAA,oBAAoBA,GAAG;AACrB,IAAA,OAAO,IAAI,CAACR,mBAAmB,GAAG,CAAC;AACrC,EAAA;;AAEA;;AAEAS,EAAAA,gBAAgBA,GAAG;AACjB,IAAA,IAAI,CAAC,IAAI,CAACZ,iBAAiB,EAAE;AAC3B,MAAA,IAAI,CAACA,iBAAiB,GAAGJ,YAAY,CAACW,UAAU,EAAE;AACpD,IAAA;AACF,EAAA;AAEAM,EAAAA,cAAcA,GAAG;IACf,IAAI,IAAI,CAACb,iBAAiB,EAAE;AAC1BJ,MAAAA,YAAY,CAACa,QAAQ,CAAC,IAAI,CAACT,iBAAiB,CAAC;MAC7C,IAAI,CAACA,iBAAiB,GAAG,IAAI;AAC/B,IAAA;AACF,EAAA;AAEAc,EAAAA,qBAAqBA,GAAG;AACtB,IAAA,OAAO,CAAC,CAAC,IAAI,CAACd,iBAAiB;AACjC,EAAA;;AAEA;AACA;;AAEA;AACA;AACA;AACAe,EAAAA,kBAAkBA,GAAG;AACnB,IAAA,IAAI,IAAI,CAACb,kBAAkB,IAAI,IAAI,CAACD,mBAAmB,EAAE;AACvD,MAAA;AACF,IAAA;AACA,IAAA,IAAI,CAACA,mBAAmB,GAAGL,YAAY,CAACW,UAAU,EAAE;AACtD,EAAA;AAEAS,EAAAA,yBAAyBA,GAAG;IAC1B,IAAI,IAAI,CAACf,mBAAmB,EAAE;AAC5BL,MAAAA,YAAY,CAACa,QAAQ,CAAC,IAAI,CAACR,mBAAmB,CAAC;MAC/C,IAAI,CAACA,mBAAmB,GAAG,IAAI;AACjC,IAAA;IACA,IAAI,CAACC,kBAAkB,GAAG,IAAI;AAChC,EAAA;AAEAe,EAAAA,uBAAuBA,GAAG;AACxB,IAAA,OAAO,CAAC,CAAC,IAAI,CAAChB,mBAAmB;AACnC,EAAA;;AAEA;;AAEAiB,EAAAA,MAAMA,GAAG;AACP,IAAA,OACE,IAAI,CAACf,mBAAmB,KAAK,CAAC,IAC9B,CAAC,IAAI,CAACH,iBAAiB,IACvB,CAAC,IAAI,CAACC,mBAAmB;AAE7B,EAAA;AAEAkB,EAAAA,QAAQA,GAAG;IACT,IAAI,IAAI,CAACf,gBAAgB,EAAE;MACzB,OAAO,IAAI,CAACA,gBAAgB;AAC9B,IAAA;AACA,IAAA,IAAI,CAACA,gBAAgB,GAAG,IAAIgB,OAAO,CAAEC,OAAO,IAAK;MAC/C,IAAI,CAAChB,gBAAgB,GAAGgB,OAAO;AACjC,IAAA,CAAC,CAAC;IACF,OAAO,IAAI,CAACjB,gBAAgB;AAC9B,EAAA;;AAEA;AACA;AACA;AACAkB,EAAAA,gBAAgBA,GAAG;IACjB,IAAI,IAAI,CAACJ,MAAM,EAAE,IAAI,IAAI,CAACb,gBAAgB,EAAE;AAC1C,MAAA,IAAIgB,OAAO,GAAG,IAAI,CAAChB,gBAAgB;MACnC,IAAI,CAACA,gBAAgB,GAAG,IAAI;MAC5B,IAAI,CAACD,gBAAgB,GAAG,IAAI;AAC5BiB,MAAAA,OAAO,EAAE;AACX,IAAA;AACF,EAAA;AACF;;;;"}
|