@unrulysystems/native-motion-core 0.1.0-alpha.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/CHANGELOG.md +9 -0
- package/LICENSE +21 -0
- package/README.md +48 -0
- package/dist/clock.cjs +71 -0
- package/dist/clock.d.cts +23 -0
- package/dist/clock.d.ts +23 -0
- package/dist/clock.js +66 -0
- package/dist/collect-reads.cjs +68 -0
- package/dist/collect-reads.d.cts +23 -0
- package/dist/collect-reads.d.ts +23 -0
- package/dist/collect-reads.js +62 -0
- package/dist/component/boundedArray.cjs +74 -0
- package/dist/component/boundedArray.d.cts +25 -0
- package/dist/component/boundedArray.d.ts +25 -0
- package/dist/component/boundedArray.js +68 -0
- package/dist/component/index.cjs +57 -0
- package/dist/component/index.d.cts +12 -0
- package/dist/component/index.d.ts +12 -0
- package/dist/component/index.js +22 -0
- package/dist/component/orchestration.cjs +129 -0
- package/dist/component/orchestration.d.cts +66 -0
- package/dist/component/orchestration.d.ts +66 -0
- package/dist/component/orchestration.js +124 -0
- package/dist/component/resolve.cjs +104 -0
- package/dist/component/resolve.d.cts +11 -0
- package/dist/component/resolve.d.ts +11 -0
- package/dist/component/resolve.js +97 -0
- package/dist/component/transition.cjs +352 -0
- package/dist/component/transition.d.cts +33 -0
- package/dist/component/transition.d.ts +33 -0
- package/dist/component/transition.js +339 -0
- package/dist/component/types.cjs +114 -0
- package/dist/component/types.d.cts +60 -0
- package/dist/component/types.d.ts +60 -0
- package/dist/component/types.js +111 -0
- package/dist/component/validate.cjs +1015 -0
- package/dist/component/validate.d.cts +37 -0
- package/dist/component/validate.d.ts +37 -0
- package/dist/component/validate.js +1002 -0
- package/dist/component/variants.cjs +333 -0
- package/dist/component/variants.d.cts +106 -0
- package/dist/component/variants.d.ts +106 -0
- package/dist/component/variants.js +321 -0
- package/dist/config/constants.cjs +41 -0
- package/dist/config/constants.d.cts +29 -0
- package/dist/config/constants.d.ts +29 -0
- package/dist/config/constants.js +38 -0
- package/dist/delay.cjs +72 -0
- package/dist/delay.d.cts +26 -0
- package/dist/delay.d.ts +26 -0
- package/dist/delay.js +70 -0
- package/dist/derived.cjs +143 -0
- package/dist/derived.d.cts +41 -0
- package/dist/derived.d.ts +41 -0
- package/dist/derived.js +139 -0
- package/dist/driver/index.cjs +22 -0
- package/dist/driver/index.d.cts +7 -0
- package/dist/driver/index.d.ts +7 -0
- package/dist/driver/index.js +14 -0
- package/dist/driver/keyframeTiming.cjs +130 -0
- package/dist/driver/keyframeTiming.d.cts +18 -0
- package/dist/driver/keyframeTiming.d.ts +18 -0
- package/dist/driver/keyframeTiming.js +124 -0
- package/dist/driver/keyframeTimingConfig.cjs +24 -0
- package/dist/driver/keyframeTimingConfig.d.cts +5 -0
- package/dist/driver/keyframeTimingConfig.d.ts +5 -0
- package/dist/driver/keyframeTimingConfig.js +22 -0
- package/dist/driver/prepare.cjs +459 -0
- package/dist/driver/prepare.d.cts +4 -0
- package/dist/driver/prepare.d.ts +4 -0
- package/dist/driver/prepare.js +454 -0
- package/dist/driver/reference.cjs +762 -0
- package/dist/driver/reference.d.cts +53 -0
- package/dist/driver/reference.d.ts +53 -0
- package/dist/driver/reference.js +757 -0
- package/dist/driver/step.cjs +55 -0
- package/dist/driver/step.d.cts +9 -0
- package/dist/driver/step.d.ts +9 -0
- package/dist/driver/step.js +52 -0
- package/dist/driver/tiers.cjs +40 -0
- package/dist/driver/tiers.d.cts +2 -0
- package/dist/driver/tiers.d.ts +2 -0
- package/dist/driver/tiers.js +37 -0
- package/dist/driver/types.cjs +9 -0
- package/dist/driver/types.d.cts +68 -0
- package/dist/driver/types.d.ts +68 -0
- package/dist/driver/types.js +8 -0
- package/dist/external-animation-ledger.cjs +1250 -0
- package/dist/external-animation-ledger.d.cts +416 -0
- package/dist/external-animation-ledger.d.ts +416 -0
- package/dist/external-animation-ledger.js +1243 -0
- package/dist/gesture/directionLock.cjs +25 -0
- package/dist/gesture/directionLock.d.cts +8 -0
- package/dist/gesture/directionLock.d.ts +8 -0
- package/dist/gesture/directionLock.js +21 -0
- package/dist/gesture/dragConfig.cjs +634 -0
- package/dist/gesture/dragConfig.d.cts +298 -0
- package/dist/gesture/dragConfig.d.ts +298 -0
- package/dist/gesture/dragConfig.js +624 -0
- package/dist/gesture/elastic.cjs +44 -0
- package/dist/gesture/elastic.d.cts +4 -0
- package/dist/gesture/elastic.d.ts +4 -0
- package/dist/gesture/elastic.js +39 -0
- package/dist/gesture/handoffSession.cjs +161 -0
- package/dist/gesture/handoffSession.d.cts +35 -0
- package/dist/gesture/handoffSession.d.ts +35 -0
- package/dist/gesture/handoffSession.js +158 -0
- package/dist/gesture/index.cjs +37 -0
- package/dist/gesture/index.d.cts +12 -0
- package/dist/gesture/index.d.ts +12 -0
- package/dist/gesture/index.js +11 -0
- package/dist/gesture/projection.cjs +95 -0
- package/dist/gesture/projection.d.cts +7 -0
- package/dist/gesture/projection.d.ts +7 -0
- package/dist/gesture/projection.js +87 -0
- package/dist/gesture/session.cjs +162 -0
- package/dist/gesture/session.d.cts +29 -0
- package/dist/gesture/session.d.ts +29 -0
- package/dist/gesture/session.js +158 -0
- package/dist/gesture/types.cjs +5 -0
- package/dist/gesture/types.d.cts +13 -0
- package/dist/gesture/types.d.ts +13 -0
- package/dist/gesture/types.js +4 -0
- package/dist/gesture/viewportConstraints.cjs +38 -0
- package/dist/gesture/viewportConstraints.d.cts +6 -0
- package/dist/gesture/viewportConstraints.d.ts +6 -0
- package/dist/gesture/viewportConstraints.js +34 -0
- package/dist/graph.cjs +226 -0
- package/dist/graph.d.cts +2 -0
- package/dist/graph.d.ts +2 -0
- package/dist/graph.js +223 -0
- package/dist/index.cjs +140 -0
- package/dist/index.d.cts +33 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +70 -0
- package/dist/inertia.cjs +214 -0
- package/dist/inertia.d.cts +53 -0
- package/dist/inertia.d.ts +53 -0
- package/dist/inertia.js +212 -0
- package/dist/instant.cjs +66 -0
- package/dist/instant.d.cts +16 -0
- package/dist/instant.d.ts +16 -0
- package/dist/instant.js +63 -0
- package/dist/internal-driver.cjs +81 -0
- package/dist/internal-driver.d.cts +19 -0
- package/dist/internal-driver.d.ts +19 -0
- package/dist/internal-driver.js +35 -0
- package/dist/keyframes.cjs +191 -0
- package/dist/keyframes.d.cts +13 -0
- package/dist/keyframes.d.ts +13 -0
- package/dist/keyframes.js +188 -0
- package/dist/layout/commitDetector.cjs +67 -0
- package/dist/layout/commitDetector.d.cts +21 -0
- package/dist/layout/commitDetector.d.ts +21 -0
- package/dist/layout/commitDetector.js +64 -0
- package/dist/layout/compose.cjs +67 -0
- package/dist/layout/compose.d.cts +30 -0
- package/dist/layout/compose.d.ts +30 -0
- package/dist/layout/compose.js +65 -0
- package/dist/layout/constants.cjs +13 -0
- package/dist/layout/constants.d.cts +6 -0
- package/dist/layout/constants.d.ts +6 -0
- package/dist/layout/constants.js +10 -0
- package/dist/layout/identity.cjs +700 -0
- package/dist/layout/identity.d.cts +67 -0
- package/dist/layout/identity.d.ts +67 -0
- package/dist/layout/identity.js +698 -0
- package/dist/layout/index.cjs +36 -0
- package/dist/layout/index.d.cts +18 -0
- package/dist/layout/index.d.ts +18 -0
- package/dist/layout/index.js +13 -0
- package/dist/layout/measure.cjs +81 -0
- package/dist/layout/measure.d.cts +43 -0
- package/dist/layout/measure.d.ts +43 -0
- package/dist/layout/measure.js +78 -0
- package/dist/layout/projection.cjs +99 -0
- package/dist/layout/projection.d.cts +23 -0
- package/dist/layout/projection.d.ts +23 -0
- package/dist/layout/projection.js +97 -0
- package/dist/layout/scroll.cjs +27 -0
- package/dist/layout/scroll.d.cts +13 -0
- package/dist/layout/scroll.d.ts +13 -0
- package/dist/layout/scroll.js +24 -0
- package/dist/layout/session.cjs +207 -0
- package/dist/layout/session.d.cts +73 -0
- package/dist/layout/session.d.ts +73 -0
- package/dist/layout/session.js +205 -0
- package/dist/layout/tree.cjs +826 -0
- package/dist/layout/tree.d.cts +70 -0
- package/dist/layout/tree.d.ts +70 -0
- package/dist/layout/tree.js +823 -0
- package/dist/layout/types.cjs +36 -0
- package/dist/layout/types.d.cts +31 -0
- package/dist/layout/types.d.ts +31 -0
- package/dist/layout/types.js +35 -0
- package/dist/motion-arc.cjs +184 -0
- package/dist/motion-arc.d.cts +78 -0
- package/dist/motion-arc.d.ts +78 -0
- package/dist/motion-arc.js +183 -0
- package/dist/motion-mix.cjs +205 -0
- package/dist/motion-mix.d.cts +3 -0
- package/dist/motion-mix.d.ts +3 -0
- package/dist/motion-mix.js +202 -0
- package/dist/motion-value-driver-port.cjs +636 -0
- package/dist/motion-value-driver-port.d.cts +406 -0
- package/dist/motion-value-driver-port.d.ts +406 -0
- package/dist/motion-value-driver-port.js +627 -0
- package/dist/motion-value.cjs +189 -0
- package/dist/motion-value.d.cts +51 -0
- package/dist/motion-value.d.ts +51 -0
- package/dist/motion-value.js +185 -0
- package/dist/presence/controller.cjs +657 -0
- package/dist/presence/controller.d.cts +6 -0
- package/dist/presence/controller.d.ts +6 -0
- package/dist/presence/controller.js +652 -0
- package/dist/presence/index.cjs +19 -0
- package/dist/presence/index.d.cts +4 -0
- package/dist/presence/index.d.ts +4 -0
- package/dist/presence/index.js +12 -0
- package/dist/presence/machine.cjs +50 -0
- package/dist/presence/machine.d.cts +10 -0
- package/dist/presence/machine.d.ts +10 -0
- package/dist/presence/machine.js +46 -0
- package/dist/presence/types.cjs +6 -0
- package/dist/presence/types.d.cts +32 -0
- package/dist/presence/types.d.ts +32 -0
- package/dist/presence/types.js +5 -0
- package/dist/repeat.cjs +311 -0
- package/dist/repeat.d.cts +174 -0
- package/dist/repeat.d.ts +174 -0
- package/dist/repeat.js +300 -0
- package/dist/spring.cjs +128 -0
- package/dist/spring.d.cts +18 -0
- package/dist/spring.d.ts +18 -0
- package/dist/spring.js +125 -0
- package/dist/subscriptions.cjs +74 -0
- package/dist/subscriptions.d.cts +19 -0
- package/dist/subscriptions.d.ts +19 -0
- package/dist/subscriptions.js +69 -0
- package/dist/subset/index.cjs +23 -0
- package/dist/subset/index.d.cts +6 -0
- package/dist/subset/index.d.ts +6 -0
- package/dist/subset/index.js +13 -0
- package/dist/subset/normalize.cjs +90 -0
- package/dist/subset/normalize.d.cts +10 -0
- package/dist/subset/normalize.d.ts +10 -0
- package/dist/subset/normalize.js +85 -0
- package/dist/subset/registry.cjs +259 -0
- package/dist/subset/registry.d.cts +25 -0
- package/dist/subset/registry.d.ts +25 -0
- package/dist/subset/registry.js +256 -0
- package/dist/subset/resolve.cjs +98 -0
- package/dist/subset/resolve.d.cts +24 -0
- package/dist/subset/resolve.d.ts +24 -0
- package/dist/subset/resolve.js +90 -0
- package/dist/timing.cjs +206 -0
- package/dist/timing.d.cts +17 -0
- package/dist/timing.d.ts +17 -0
- package/dist/timing.js +201 -0
- package/dist/transformTemplate.cjs +219 -0
- package/dist/transformTemplate.d.cts +29 -0
- package/dist/transformTemplate.d.ts +29 -0
- package/dist/transformTemplate.js +215 -0
- package/dist/transition.cjs +231 -0
- package/dist/transition.d.cts +89 -0
- package/dist/transition.d.ts +89 -0
- package/dist/transition.js +223 -0
- package/dist/types.cjs +4 -0
- package/dist/types.d.cts +175 -0
- package/dist/types.d.ts +175 -0
- package/dist/types.js +3 -0
- package/dist/value-types/color.cjs +220 -0
- package/dist/value-types/color.d.cts +19 -0
- package/dist/value-types/color.d.ts +19 -0
- package/dist/value-types/color.js +218 -0
- package/dist/value-types/complex.cjs +160 -0
- package/dist/value-types/complex.d.cts +19 -0
- package/dist/value-types/complex.d.ts +19 -0
- package/dist/value-types/complex.js +155 -0
- package/dist/value-types/constants.cjs +15 -0
- package/dist/value-types/constants.d.cts +6 -0
- package/dist/value-types/constants.d.ts +6 -0
- package/dist/value-types/constants.js +12 -0
- package/dist/value-types/discrete.cjs +62 -0
- package/dist/value-types/discrete.d.cts +4 -0
- package/dist/value-types/discrete.d.ts +4 -0
- package/dist/value-types/discrete.js +56 -0
- package/dist/value-types/index.cjs +59 -0
- package/dist/value-types/index.d.cts +14 -0
- package/dist/value-types/index.d.ts +14 -0
- package/dist/value-types/index.js +24 -0
- package/dist/value-types/measure-resolve.cjs +325 -0
- package/dist/value-types/measure-resolve.d.cts +91 -0
- package/dist/value-types/measure-resolve.d.ts +91 -0
- package/dist/value-types/measure-resolve.js +313 -0
- package/dist/value-types/mix.cjs +90 -0
- package/dist/value-types/mix.d.cts +27 -0
- package/dist/value-types/mix.d.ts +27 -0
- package/dist/value-types/mix.js +85 -0
- package/dist/value-types/named-colors.cjs +61 -0
- package/dist/value-types/named-colors.d.cts +2 -0
- package/dist/value-types/named-colors.d.ts +2 -0
- package/dist/value-types/named-colors.js +58 -0
- package/dist/value-types/numeric.cjs +86 -0
- package/dist/value-types/numeric.d.cts +16 -0
- package/dist/value-types/numeric.d.ts +16 -0
- package/dist/value-types/numeric.js +79 -0
- package/dist/worklet-layout/config/constants.js +39 -0
- package/dist/worklet-layout/layout/constants.js +11 -0
- package/dist/worklet-layout/layout/identity.js +699 -0
- package/dist/worklet-layout/layout/projection.js +98 -0
- package/dist/worklet-layout/layout/session.js +206 -0
- package/dist/worklet-layout/layout/tree.js +824 -0
- package/dist/worklet-layout/layout/types.js +36 -0
- package/dist/worklet-layout/spring.js +125 -0
- package/dist/worklet-layout/timing.js +201 -0
- package/dist/worklet-layout/transition.js +223 -0
- package/dist/worklet-layout.cjs +47 -0
- package/dist/worklet-layout.d.cts +15 -0
- package/dist/worklet-layout.d.ts +15 -0
- package/dist/worklet-layout.js +28 -0
- package/dist/wrap.cjs +7 -0
- package/dist/wrap.d.cts +1 -0
- package/dist/wrap.d.ts +1 -0
- package/dist/wrap.js +4 -0
- package/package.json +45 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// MotionValue implementation (REQ-VALUE-001/010/011/012). Clock-timestamped velocity follows
|
|
3
|
+
// Motion 12.42.2's `motionValue.getVelocity` formula (the parity target pinned by M1b conformance):
|
|
4
|
+
// velocity from the last two timed samples, zero once the last sample is older than the staleness
|
|
5
|
+
// window, zero for non-numeric values. `subscribe` never triggers a host render.
|
|
6
|
+
//
|
|
7
|
+
// Two write paths, deliberately distinct (see M1-BUILD-PACKET gotchas): `set`/`jump` are the manual,
|
|
8
|
+
// clock-timestamped path; `applyAnimationSample` is the animation path that writes value+velocity
|
|
9
|
+
// straight from a generator without re-deriving velocity from the clock. While an animation drives
|
|
10
|
+
// this value, `getVelocity` reports the animation velocity; a manual `set`/`jump` reverts to the
|
|
11
|
+
// clock-sampled velocity. Methods below the public interface are internal seams for the graph.
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.MotionValueImpl = void 0;
|
|
14
|
+
const collect_reads_1 = require("./collect-reads.cjs");
|
|
15
|
+
const constants_1 = require("./config/constants.cjs");
|
|
16
|
+
const subscriptions_1 = require("./subscriptions.cjs");
|
|
17
|
+
class MotionValueImpl {
|
|
18
|
+
#clock;
|
|
19
|
+
#subs = new subscriptions_1.Subscriptions();
|
|
20
|
+
#current;
|
|
21
|
+
// Previous *numeric* sample and the two timestamps used for clock velocity. `#prev` is undefined
|
|
22
|
+
// whenever the prior value was non-numeric or after a teleport, which forces velocity to 0.
|
|
23
|
+
#prev;
|
|
24
|
+
#updatedAt;
|
|
25
|
+
#prevUpdatedAt;
|
|
26
|
+
// Velocity supplied by the driving animation, if any; takes precedence over the clock sample.
|
|
27
|
+
#animatedVelocity;
|
|
28
|
+
// Stop hook installed by the graph while an animation drives this value (REQ from `stop`).
|
|
29
|
+
#stopAnimation;
|
|
30
|
+
constructor(initial, clock) {
|
|
31
|
+
this.#current = initial;
|
|
32
|
+
this.#clock = clock;
|
|
33
|
+
this.#updatedAt = clock.now();
|
|
34
|
+
this.#prev = undefined;
|
|
35
|
+
this.#prevUpdatedAt = undefined;
|
|
36
|
+
this.#animatedVelocity = undefined;
|
|
37
|
+
this.#stopAnimation = undefined;
|
|
38
|
+
}
|
|
39
|
+
get() {
|
|
40
|
+
(0, collect_reads_1.reportMotionValueRead)(this);
|
|
41
|
+
return this.#current;
|
|
42
|
+
}
|
|
43
|
+
set(value) {
|
|
44
|
+
// Manual write reverts velocity tracking to the clock path.
|
|
45
|
+
this.#animatedVelocity = undefined;
|
|
46
|
+
// The pinned FRAME window (motion-dom updateAndNotify at the SS B pin, r15 4cf8a7d291e3):
|
|
47
|
+
// the previous sample rolls ONLY when time moved, so every same-frame write keeps
|
|
48
|
+
// comparing against the frame-START value and their velocities COMPOUND like the pin —
|
|
49
|
+
// never a per-write replacement that hides intra-frame motion.
|
|
50
|
+
const now = this.#clock.now();
|
|
51
|
+
if (now !== this.#updatedAt) {
|
|
52
|
+
this.#prev = typeof this.#current === 'number' ? this.#current : undefined;
|
|
53
|
+
this.#prevUpdatedAt = this.#updatedAt;
|
|
54
|
+
this.#updatedAt = now;
|
|
55
|
+
}
|
|
56
|
+
const previous = this.#current;
|
|
57
|
+
this.#current = value;
|
|
58
|
+
// Pinned suppression: an identical-value write does not notify (strict !== like the pin).
|
|
59
|
+
if (this.#current !== previous)
|
|
60
|
+
this.#subs.emitChange(this.#current);
|
|
61
|
+
}
|
|
62
|
+
jump(value) {
|
|
63
|
+
// Pinned jump ORDER (motion-dom `jump(v, endAnimation = true)`, r16/r17 — sealed by the
|
|
64
|
+
// motion-seams canary): (1) updateAndNotify — EXACTLY the set() path, so the change
|
|
65
|
+
// listener reads the teleport write's CLOCK velocity (never the generator's) with the
|
|
66
|
+
// animation still live; (2) the velocity window resets; (3) stop() — whose cancellation
|
|
67
|
+
// is notified while the animation is still observable and reads velocity 0. A dead flight
|
|
68
|
+
// can never overwrite the teleported value on the next frame (r15 59b71ef82c44).
|
|
69
|
+
this.set(value);
|
|
70
|
+
this.#prev = undefined;
|
|
71
|
+
this.#prevUpdatedAt = undefined;
|
|
72
|
+
this.#updatedAt = this.#clock.now();
|
|
73
|
+
this.stop();
|
|
74
|
+
}
|
|
75
|
+
subscribe(listener) {
|
|
76
|
+
return this.#subs.subscribe(listener);
|
|
77
|
+
}
|
|
78
|
+
getVelocity() {
|
|
79
|
+
if (this.#animatedVelocity !== undefined)
|
|
80
|
+
return this.#animatedVelocity;
|
|
81
|
+
const current = this.#current;
|
|
82
|
+
const prev = this.#prev;
|
|
83
|
+
const prevUpdatedAt = this.#prevUpdatedAt;
|
|
84
|
+
if (typeof current !== 'number' || prev === undefined || prevUpdatedAt === undefined)
|
|
85
|
+
return 0;
|
|
86
|
+
// Stale: no fresh sample within the window → treat as at rest (REQ-VALUE-011).
|
|
87
|
+
if (this.#clock.now() - this.#updatedAt > constants_1.MAX_VELOCITY_DELTA_MS)
|
|
88
|
+
return 0;
|
|
89
|
+
const dt = Math.min(this.#updatedAt - prevUpdatedAt, constants_1.MAX_VELOCITY_DELTA_MS);
|
|
90
|
+
if (dt <= 0)
|
|
91
|
+
return 0;
|
|
92
|
+
return ((current - prev) * 1000) / dt;
|
|
93
|
+
}
|
|
94
|
+
on(event, listener) {
|
|
95
|
+
// The implementation signature stays broad for delegation; it is NOT a public overload
|
|
96
|
+
// (r16 major 5 — lifecycle listeners are payload-free by contract).
|
|
97
|
+
return this.#subs.on(event, listener);
|
|
98
|
+
}
|
|
99
|
+
// The stop hook exists exactly while an animation drives this value (installed at animate,
|
|
100
|
+
// removed at endAnimation) — it IS the animation-liveness state, so no second flag can skew.
|
|
101
|
+
isAnimating() {
|
|
102
|
+
return this.#stopAnimation !== undefined;
|
|
103
|
+
}
|
|
104
|
+
stop() {
|
|
105
|
+
const stopper = this.#stopAnimation;
|
|
106
|
+
if (stopper === undefined)
|
|
107
|
+
return;
|
|
108
|
+
// Pinned lifecycle ORDER (r17, sealed by the motion-seams canary): the cancellation is
|
|
109
|
+
// notified while the animation is STILL OBSERVABLE (the pin clears `animation` only after
|
|
110
|
+
// notifying); the stopper — which also clears liveness through endAnimation — runs after.
|
|
111
|
+
// The emission lives here, not in destroy(), whose teardown is not a cancel.
|
|
112
|
+
this.#subs.emit('animationCancel');
|
|
113
|
+
stopper();
|
|
114
|
+
}
|
|
115
|
+
destroy() {
|
|
116
|
+
// Pinned teardown ORDER (r16 major 1): destroy announces itself FIRST — the listener
|
|
117
|
+
// observes the still-live animation — then the silent stop (never an animationCancel from
|
|
118
|
+
// teardown), then subscriptions drop.
|
|
119
|
+
this.#subs.emit('destroy');
|
|
120
|
+
this.#stopAnimation?.();
|
|
121
|
+
this.#subs.clear();
|
|
122
|
+
}
|
|
123
|
+
// --- internal seams for the graph (not part of the public MotionValue contract) ---------------
|
|
124
|
+
/**
|
|
125
|
+
* @internal Write an animation-produced sample: value and velocity straight from the generator,
|
|
126
|
+
* bypassing the clock-velocity path so velocity is not double-counted.
|
|
127
|
+
*/
|
|
128
|
+
applyAnimationSample(value, velocity) {
|
|
129
|
+
this.#current = value;
|
|
130
|
+
this.#animatedVelocity = velocity;
|
|
131
|
+
this.#subs.emitChange(this.#current);
|
|
132
|
+
}
|
|
133
|
+
/** @internal Fire a lifecycle event (`animationStart`/`animationComplete`) on this value. */
|
|
134
|
+
emitEvent(event) {
|
|
135
|
+
this.#subs.emit(event);
|
|
136
|
+
}
|
|
137
|
+
/** @internal Install the stop hook the graph uses to wire `value.stop()` to the registry. */
|
|
138
|
+
attachAnimationStopper(stop) {
|
|
139
|
+
this.#stopAnimation = stop;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* @internal Driver-port seam (REQ-VALUE-015): drop the stop hook WITHOUT invoking it — the
|
|
143
|
+
* token-blind public-control-slot clear changes `isAnimating()` only and must never stop the
|
|
144
|
+
* retained physical execution (pinned post-listener slot clear).
|
|
145
|
+
*/
|
|
146
|
+
detachAnimationStopper() {
|
|
147
|
+
this.#stopAnimation = undefined;
|
|
148
|
+
}
|
|
149
|
+
/** @internal Driver-port seam: change-observer presence for transported-write classification. */
|
|
150
|
+
hasChangeObservers() {
|
|
151
|
+
return this.#subs.hasChangeObservers();
|
|
152
|
+
}
|
|
153
|
+
/** @internal Driver-port seam: derived-dependent presence among the change listeners. */
|
|
154
|
+
hasDerivedDependentObserver() {
|
|
155
|
+
return this.#subs.hasDerivedDependentObserver();
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* @internal Driver-port seam: adopt an externally transported numeric sample — the value plus
|
|
159
|
+
* its OWNED sample history (never clock re-derived) — with change notification under the
|
|
160
|
+
* caller's control: transported writes notify; guarded candidate-cache terminals and
|
|
161
|
+
* synchronous snapshots adopt silently. A throwing observer propagates unchanged (the pinned
|
|
162
|
+
* notify law); the caller owns drain progress accounting across that abort.
|
|
163
|
+
*/
|
|
164
|
+
applyExternalNumericSample(value, previousValue, currentTimestampMs, previousTimestampMs, notifyChange) {
|
|
165
|
+
this.#animatedVelocity = undefined;
|
|
166
|
+
this.#current = value;
|
|
167
|
+
this.#prev = previousValue;
|
|
168
|
+
this.#prevUpdatedAt = previousTimestampMs;
|
|
169
|
+
this.#updatedAt = currentTimestampMs;
|
|
170
|
+
if (notifyChange)
|
|
171
|
+
this.#subs.emitChange(this.#current);
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* @internal Called when the animation driving this value ends (natural completion or stop). Puts
|
|
175
|
+
* the value at rest at its current value as of now: clears the animation velocity AND resets the
|
|
176
|
+
* clock-velocity samples (so `getVelocity` cannot leak a stale manual velocity from a `set` that
|
|
177
|
+
* preceded the animation, nor synthesize one from the animation's final value against a stale
|
|
178
|
+
* previous sample). Removes the stop hook. NOT called on interruption, where the current velocity
|
|
179
|
+
* must carry into the replacement generator's seed.
|
|
180
|
+
*/
|
|
181
|
+
endAnimation() {
|
|
182
|
+
this.#animatedVelocity = undefined;
|
|
183
|
+
this.#prev = undefined;
|
|
184
|
+
this.#prevUpdatedAt = undefined;
|
|
185
|
+
this.#updatedAt = this.#clock.now();
|
|
186
|
+
this.#stopAnimation = undefined;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
exports.MotionValueImpl = MotionValueImpl;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { Clock, MotionValue, MotionValueEvent, ValueChangeListener } from "./types.cjs";
|
|
2
|
+
export declare class MotionValueImpl<T> implements MotionValue<T> {
|
|
3
|
+
#private;
|
|
4
|
+
constructor(initial: T, clock: Clock);
|
|
5
|
+
get(): T;
|
|
6
|
+
set(value: T): void;
|
|
7
|
+
jump(value: T): void;
|
|
8
|
+
subscribe(listener: ValueChangeListener<T>): () => void;
|
|
9
|
+
getVelocity(): number;
|
|
10
|
+
on(event: 'change', listener: (latest: T) => void): () => void;
|
|
11
|
+
on(event: Exclude<MotionValueEvent, 'change'>, listener: () => void): () => void;
|
|
12
|
+
isAnimating(): boolean;
|
|
13
|
+
stop(): void;
|
|
14
|
+
destroy(): void;
|
|
15
|
+
/**
|
|
16
|
+
* @internal Write an animation-produced sample: value and velocity straight from the generator,
|
|
17
|
+
* bypassing the clock-velocity path so velocity is not double-counted.
|
|
18
|
+
*/
|
|
19
|
+
applyAnimationSample(value: T, velocity: number): void;
|
|
20
|
+
/** @internal Fire a lifecycle event (`animationStart`/`animationComplete`) on this value. */
|
|
21
|
+
emitEvent(event: Exclude<MotionValueEvent, 'change'>): void;
|
|
22
|
+
/** @internal Install the stop hook the graph uses to wire `value.stop()` to the registry. */
|
|
23
|
+
attachAnimationStopper(stop: () => void): void;
|
|
24
|
+
/**
|
|
25
|
+
* @internal Driver-port seam (REQ-VALUE-015): drop the stop hook WITHOUT invoking it — the
|
|
26
|
+
* token-blind public-control-slot clear changes `isAnimating()` only and must never stop the
|
|
27
|
+
* retained physical execution (pinned post-listener slot clear).
|
|
28
|
+
*/
|
|
29
|
+
detachAnimationStopper(): void;
|
|
30
|
+
/** @internal Driver-port seam: change-observer presence for transported-write classification. */
|
|
31
|
+
hasChangeObservers(): boolean;
|
|
32
|
+
/** @internal Driver-port seam: derived-dependent presence among the change listeners. */
|
|
33
|
+
hasDerivedDependentObserver(): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* @internal Driver-port seam: adopt an externally transported numeric sample — the value plus
|
|
36
|
+
* its OWNED sample history (never clock re-derived) — with change notification under the
|
|
37
|
+
* caller's control: transported writes notify; guarded candidate-cache terminals and
|
|
38
|
+
* synchronous snapshots adopt silently. A throwing observer propagates unchanged (the pinned
|
|
39
|
+
* notify law); the caller owns drain progress accounting across that abort.
|
|
40
|
+
*/
|
|
41
|
+
applyExternalNumericSample(value: T, previousValue: number | undefined, currentTimestampMs: number, previousTimestampMs: number | undefined, notifyChange: boolean): void;
|
|
42
|
+
/**
|
|
43
|
+
* @internal Called when the animation driving this value ends (natural completion or stop). Puts
|
|
44
|
+
* the value at rest at its current value as of now: clears the animation velocity AND resets the
|
|
45
|
+
* clock-velocity samples (so `getVelocity` cannot leak a stale manual velocity from a `set` that
|
|
46
|
+
* preceded the animation, nor synthesize one from the animation's final value against a stale
|
|
47
|
+
* previous sample). Removes the stop hook. NOT called on interruption, where the current velocity
|
|
48
|
+
* must carry into the replacement generator's seed.
|
|
49
|
+
*/
|
|
50
|
+
endAnimation(): void;
|
|
51
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { Clock, MotionValue, MotionValueEvent, ValueChangeListener } from "./types.js";
|
|
2
|
+
export declare class MotionValueImpl<T> implements MotionValue<T> {
|
|
3
|
+
#private;
|
|
4
|
+
constructor(initial: T, clock: Clock);
|
|
5
|
+
get(): T;
|
|
6
|
+
set(value: T): void;
|
|
7
|
+
jump(value: T): void;
|
|
8
|
+
subscribe(listener: ValueChangeListener<T>): () => void;
|
|
9
|
+
getVelocity(): number;
|
|
10
|
+
on(event: 'change', listener: (latest: T) => void): () => void;
|
|
11
|
+
on(event: Exclude<MotionValueEvent, 'change'>, listener: () => void): () => void;
|
|
12
|
+
isAnimating(): boolean;
|
|
13
|
+
stop(): void;
|
|
14
|
+
destroy(): void;
|
|
15
|
+
/**
|
|
16
|
+
* @internal Write an animation-produced sample: value and velocity straight from the generator,
|
|
17
|
+
* bypassing the clock-velocity path so velocity is not double-counted.
|
|
18
|
+
*/
|
|
19
|
+
applyAnimationSample(value: T, velocity: number): void;
|
|
20
|
+
/** @internal Fire a lifecycle event (`animationStart`/`animationComplete`) on this value. */
|
|
21
|
+
emitEvent(event: Exclude<MotionValueEvent, 'change'>): void;
|
|
22
|
+
/** @internal Install the stop hook the graph uses to wire `value.stop()` to the registry. */
|
|
23
|
+
attachAnimationStopper(stop: () => void): void;
|
|
24
|
+
/**
|
|
25
|
+
* @internal Driver-port seam (REQ-VALUE-015): drop the stop hook WITHOUT invoking it — the
|
|
26
|
+
* token-blind public-control-slot clear changes `isAnimating()` only and must never stop the
|
|
27
|
+
* retained physical execution (pinned post-listener slot clear).
|
|
28
|
+
*/
|
|
29
|
+
detachAnimationStopper(): void;
|
|
30
|
+
/** @internal Driver-port seam: change-observer presence for transported-write classification. */
|
|
31
|
+
hasChangeObservers(): boolean;
|
|
32
|
+
/** @internal Driver-port seam: derived-dependent presence among the change listeners. */
|
|
33
|
+
hasDerivedDependentObserver(): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* @internal Driver-port seam: adopt an externally transported numeric sample — the value plus
|
|
36
|
+
* its OWNED sample history (never clock re-derived) — with change notification under the
|
|
37
|
+
* caller's control: transported writes notify; guarded candidate-cache terminals and
|
|
38
|
+
* synchronous snapshots adopt silently. A throwing observer propagates unchanged (the pinned
|
|
39
|
+
* notify law); the caller owns drain progress accounting across that abort.
|
|
40
|
+
*/
|
|
41
|
+
applyExternalNumericSample(value: T, previousValue: number | undefined, currentTimestampMs: number, previousTimestampMs: number | undefined, notifyChange: boolean): void;
|
|
42
|
+
/**
|
|
43
|
+
* @internal Called when the animation driving this value ends (natural completion or stop). Puts
|
|
44
|
+
* the value at rest at its current value as of now: clears the animation velocity AND resets the
|
|
45
|
+
* clock-velocity samples (so `getVelocity` cannot leak a stale manual velocity from a `set` that
|
|
46
|
+
* preceded the animation, nor synthesize one from the animation's final value against a stale
|
|
47
|
+
* previous sample). Removes the stop hook. NOT called on interruption, where the current velocity
|
|
48
|
+
* must carry into the replacement generator's seed.
|
|
49
|
+
*/
|
|
50
|
+
endAnimation(): void;
|
|
51
|
+
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
// MotionValue implementation (REQ-VALUE-001/010/011/012). Clock-timestamped velocity follows
|
|
2
|
+
// Motion 12.42.2's `motionValue.getVelocity` formula (the parity target pinned by M1b conformance):
|
|
3
|
+
// velocity from the last two timed samples, zero once the last sample is older than the staleness
|
|
4
|
+
// window, zero for non-numeric values. `subscribe` never triggers a host render.
|
|
5
|
+
//
|
|
6
|
+
// Two write paths, deliberately distinct (see M1-BUILD-PACKET gotchas): `set`/`jump` are the manual,
|
|
7
|
+
// clock-timestamped path; `applyAnimationSample` is the animation path that writes value+velocity
|
|
8
|
+
// straight from a generator without re-deriving velocity from the clock. While an animation drives
|
|
9
|
+
// this value, `getVelocity` reports the animation velocity; a manual `set`/`jump` reverts to the
|
|
10
|
+
// clock-sampled velocity. Methods below the public interface are internal seams for the graph.
|
|
11
|
+
import { reportMotionValueRead } from "./collect-reads.js";
|
|
12
|
+
import { MAX_VELOCITY_DELTA_MS } from "./config/constants.js";
|
|
13
|
+
import { Subscriptions } from "./subscriptions.js";
|
|
14
|
+
export class MotionValueImpl {
|
|
15
|
+
#clock;
|
|
16
|
+
#subs = new Subscriptions();
|
|
17
|
+
#current;
|
|
18
|
+
// Previous *numeric* sample and the two timestamps used for clock velocity. `#prev` is undefined
|
|
19
|
+
// whenever the prior value was non-numeric or after a teleport, which forces velocity to 0.
|
|
20
|
+
#prev;
|
|
21
|
+
#updatedAt;
|
|
22
|
+
#prevUpdatedAt;
|
|
23
|
+
// Velocity supplied by the driving animation, if any; takes precedence over the clock sample.
|
|
24
|
+
#animatedVelocity;
|
|
25
|
+
// Stop hook installed by the graph while an animation drives this value (REQ from `stop`).
|
|
26
|
+
#stopAnimation;
|
|
27
|
+
constructor(initial, clock) {
|
|
28
|
+
this.#current = initial;
|
|
29
|
+
this.#clock = clock;
|
|
30
|
+
this.#updatedAt = clock.now();
|
|
31
|
+
this.#prev = undefined;
|
|
32
|
+
this.#prevUpdatedAt = undefined;
|
|
33
|
+
this.#animatedVelocity = undefined;
|
|
34
|
+
this.#stopAnimation = undefined;
|
|
35
|
+
}
|
|
36
|
+
get() {
|
|
37
|
+
reportMotionValueRead(this);
|
|
38
|
+
return this.#current;
|
|
39
|
+
}
|
|
40
|
+
set(value) {
|
|
41
|
+
// Manual write reverts velocity tracking to the clock path.
|
|
42
|
+
this.#animatedVelocity = undefined;
|
|
43
|
+
// The pinned FRAME window (motion-dom updateAndNotify at the SS B pin, r15 4cf8a7d291e3):
|
|
44
|
+
// the previous sample rolls ONLY when time moved, so every same-frame write keeps
|
|
45
|
+
// comparing against the frame-START value and their velocities COMPOUND like the pin —
|
|
46
|
+
// never a per-write replacement that hides intra-frame motion.
|
|
47
|
+
const now = this.#clock.now();
|
|
48
|
+
if (now !== this.#updatedAt) {
|
|
49
|
+
this.#prev = typeof this.#current === 'number' ? this.#current : undefined;
|
|
50
|
+
this.#prevUpdatedAt = this.#updatedAt;
|
|
51
|
+
this.#updatedAt = now;
|
|
52
|
+
}
|
|
53
|
+
const previous = this.#current;
|
|
54
|
+
this.#current = value;
|
|
55
|
+
// Pinned suppression: an identical-value write does not notify (strict !== like the pin).
|
|
56
|
+
if (this.#current !== previous)
|
|
57
|
+
this.#subs.emitChange(this.#current);
|
|
58
|
+
}
|
|
59
|
+
jump(value) {
|
|
60
|
+
// Pinned jump ORDER (motion-dom `jump(v, endAnimation = true)`, r16/r17 — sealed by the
|
|
61
|
+
// motion-seams canary): (1) updateAndNotify — EXACTLY the set() path, so the change
|
|
62
|
+
// listener reads the teleport write's CLOCK velocity (never the generator's) with the
|
|
63
|
+
// animation still live; (2) the velocity window resets; (3) stop() — whose cancellation
|
|
64
|
+
// is notified while the animation is still observable and reads velocity 0. A dead flight
|
|
65
|
+
// can never overwrite the teleported value on the next frame (r15 59b71ef82c44).
|
|
66
|
+
this.set(value);
|
|
67
|
+
this.#prev = undefined;
|
|
68
|
+
this.#prevUpdatedAt = undefined;
|
|
69
|
+
this.#updatedAt = this.#clock.now();
|
|
70
|
+
this.stop();
|
|
71
|
+
}
|
|
72
|
+
subscribe(listener) {
|
|
73
|
+
return this.#subs.subscribe(listener);
|
|
74
|
+
}
|
|
75
|
+
getVelocity() {
|
|
76
|
+
if (this.#animatedVelocity !== undefined)
|
|
77
|
+
return this.#animatedVelocity;
|
|
78
|
+
const current = this.#current;
|
|
79
|
+
const prev = this.#prev;
|
|
80
|
+
const prevUpdatedAt = this.#prevUpdatedAt;
|
|
81
|
+
if (typeof current !== 'number' || prev === undefined || prevUpdatedAt === undefined)
|
|
82
|
+
return 0;
|
|
83
|
+
// Stale: no fresh sample within the window → treat as at rest (REQ-VALUE-011).
|
|
84
|
+
if (this.#clock.now() - this.#updatedAt > MAX_VELOCITY_DELTA_MS)
|
|
85
|
+
return 0;
|
|
86
|
+
const dt = Math.min(this.#updatedAt - prevUpdatedAt, MAX_VELOCITY_DELTA_MS);
|
|
87
|
+
if (dt <= 0)
|
|
88
|
+
return 0;
|
|
89
|
+
return ((current - prev) * 1000) / dt;
|
|
90
|
+
}
|
|
91
|
+
on(event, listener) {
|
|
92
|
+
// The implementation signature stays broad for delegation; it is NOT a public overload
|
|
93
|
+
// (r16 major 5 — lifecycle listeners are payload-free by contract).
|
|
94
|
+
return this.#subs.on(event, listener);
|
|
95
|
+
}
|
|
96
|
+
// The stop hook exists exactly while an animation drives this value (installed at animate,
|
|
97
|
+
// removed at endAnimation) — it IS the animation-liveness state, so no second flag can skew.
|
|
98
|
+
isAnimating() {
|
|
99
|
+
return this.#stopAnimation !== undefined;
|
|
100
|
+
}
|
|
101
|
+
stop() {
|
|
102
|
+
const stopper = this.#stopAnimation;
|
|
103
|
+
if (stopper === undefined)
|
|
104
|
+
return;
|
|
105
|
+
// Pinned lifecycle ORDER (r17, sealed by the motion-seams canary): the cancellation is
|
|
106
|
+
// notified while the animation is STILL OBSERVABLE (the pin clears `animation` only after
|
|
107
|
+
// notifying); the stopper — which also clears liveness through endAnimation — runs after.
|
|
108
|
+
// The emission lives here, not in destroy(), whose teardown is not a cancel.
|
|
109
|
+
this.#subs.emit('animationCancel');
|
|
110
|
+
stopper();
|
|
111
|
+
}
|
|
112
|
+
destroy() {
|
|
113
|
+
// Pinned teardown ORDER (r16 major 1): destroy announces itself FIRST — the listener
|
|
114
|
+
// observes the still-live animation — then the silent stop (never an animationCancel from
|
|
115
|
+
// teardown), then subscriptions drop.
|
|
116
|
+
this.#subs.emit('destroy');
|
|
117
|
+
this.#stopAnimation?.();
|
|
118
|
+
this.#subs.clear();
|
|
119
|
+
}
|
|
120
|
+
// --- internal seams for the graph (not part of the public MotionValue contract) ---------------
|
|
121
|
+
/**
|
|
122
|
+
* @internal Write an animation-produced sample: value and velocity straight from the generator,
|
|
123
|
+
* bypassing the clock-velocity path so velocity is not double-counted.
|
|
124
|
+
*/
|
|
125
|
+
applyAnimationSample(value, velocity) {
|
|
126
|
+
this.#current = value;
|
|
127
|
+
this.#animatedVelocity = velocity;
|
|
128
|
+
this.#subs.emitChange(this.#current);
|
|
129
|
+
}
|
|
130
|
+
/** @internal Fire a lifecycle event (`animationStart`/`animationComplete`) on this value. */
|
|
131
|
+
emitEvent(event) {
|
|
132
|
+
this.#subs.emit(event);
|
|
133
|
+
}
|
|
134
|
+
/** @internal Install the stop hook the graph uses to wire `value.stop()` to the registry. */
|
|
135
|
+
attachAnimationStopper(stop) {
|
|
136
|
+
this.#stopAnimation = stop;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* @internal Driver-port seam (REQ-VALUE-015): drop the stop hook WITHOUT invoking it — the
|
|
140
|
+
* token-blind public-control-slot clear changes `isAnimating()` only and must never stop the
|
|
141
|
+
* retained physical execution (pinned post-listener slot clear).
|
|
142
|
+
*/
|
|
143
|
+
detachAnimationStopper() {
|
|
144
|
+
this.#stopAnimation = undefined;
|
|
145
|
+
}
|
|
146
|
+
/** @internal Driver-port seam: change-observer presence for transported-write classification. */
|
|
147
|
+
hasChangeObservers() {
|
|
148
|
+
return this.#subs.hasChangeObservers();
|
|
149
|
+
}
|
|
150
|
+
/** @internal Driver-port seam: derived-dependent presence among the change listeners. */
|
|
151
|
+
hasDerivedDependentObserver() {
|
|
152
|
+
return this.#subs.hasDerivedDependentObserver();
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* @internal Driver-port seam: adopt an externally transported numeric sample — the value plus
|
|
156
|
+
* its OWNED sample history (never clock re-derived) — with change notification under the
|
|
157
|
+
* caller's control: transported writes notify; guarded candidate-cache terminals and
|
|
158
|
+
* synchronous snapshots adopt silently. A throwing observer propagates unchanged (the pinned
|
|
159
|
+
* notify law); the caller owns drain progress accounting across that abort.
|
|
160
|
+
*/
|
|
161
|
+
applyExternalNumericSample(value, previousValue, currentTimestampMs, previousTimestampMs, notifyChange) {
|
|
162
|
+
this.#animatedVelocity = undefined;
|
|
163
|
+
this.#current = value;
|
|
164
|
+
this.#prev = previousValue;
|
|
165
|
+
this.#prevUpdatedAt = previousTimestampMs;
|
|
166
|
+
this.#updatedAt = currentTimestampMs;
|
|
167
|
+
if (notifyChange)
|
|
168
|
+
this.#subs.emitChange(this.#current);
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* @internal Called when the animation driving this value ends (natural completion or stop). Puts
|
|
172
|
+
* the value at rest at its current value as of now: clears the animation velocity AND resets the
|
|
173
|
+
* clock-velocity samples (so `getVelocity` cannot leak a stale manual velocity from a `set` that
|
|
174
|
+
* preceded the animation, nor synthesize one from the animation's final value against a stale
|
|
175
|
+
* previous sample). Removes the stop hook. NOT called on interruption, where the current velocity
|
|
176
|
+
* must carry into the replacement generator's seed.
|
|
177
|
+
*/
|
|
178
|
+
endAnimation() {
|
|
179
|
+
this.#animatedVelocity = undefined;
|
|
180
|
+
this.#prev = undefined;
|
|
181
|
+
this.#prevUpdatedAt = undefined;
|
|
182
|
+
this.#updatedAt = this.#clock.now();
|
|
183
|
+
this.#stopAnimation = undefined;
|
|
184
|
+
}
|
|
185
|
+
}
|