Commit 8c981a4
* fix(studio): restore timeline move/resize fallback parity (review #1466)
The §3.2 sdkTimingPersist rewrite regressed the non-SDK fallback path vs the
pre-cutover behavior. Restored, on both fallback entry points (no-session and
sdkTimingPersist-returned-unhandled):
- Resize live DOM patch dropped the conditional data-playback-start/media-start
attr — restored so a start-trim updates the preview's in-point immediately.
- Move/resize fallback dropped the GSAP-position sync (shift/scaleGsapPositions)
+ reloadPreview — restored so server-path edits keep GSAP tweens in sync and
refresh the preview (the SDK path folds both into setTiming).
- Undo-coalesce drift: fallback enqueueEdit carried no coalesceKey while the SDK
branch did — plumbed coalesceKey through persistTimelineEdit so undo
granularity is identical on either path.
- Documented the hasPbsAdjustment second clause + sdkTimingPersist before-capture
transition limitation.
Flag-off (dark launch) so this lands as one fix PR at the stack tip rather than
restacking the mid-stack §3.2 commit. #1500 review items: parity-harness gap
already closed at the tip (arc/unroll recast-vs-acorn parity added); blockRemoveRange
flagged 'potential' but verified correct (no comma residue on any block position).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(sdk): retire duplicate removeGsapKeyframe keyframeIndex variant (review #1498)
EditOp had two removeGsapKeyframe members with the same discriminant but
different shapes (keyframeIndex vs percentage) — TS can't discriminate them and
a handler could get the wrong shape. Per both reviewers (option 2): retire the
keyframeIndex variant. It had no production caller (Studio dispatches percentage
only); removed the dead by-index handleRemoveGsapKeyframe + simplified the
dispatcher. resolveKeyframe stays (setGsapKeyframe still uses keyframeIndex).
Converted the one by-index test to the percentage API.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(studio): gate ALL cutover persist paths on the flag — true dark launch (review #1469 finding #6)
Only sdkCutoverPersist (style/text/attr) checked STUDIO_SDK_CUTOVER_ENABLED.
sdkTimingPersist, dispatchGsapOpAndPersist (every GSAP op) and sdkDeletePersist
guarded only on `!sdkSession` — and useSdkSession opens a session by default
for shadow/selection, so timing/GSAP/keyframe/delete cutover was ALWAYS live
regardless of the flag. Flipping the flag OFF could not disable it, so the
data-loss bugs in those paths (single-prop wipe, wrong-keyframe match, tween
collapse, arc strip) ship LIVE on merge instead of being dark-launched.
Added the flag guard at all three chokepoints → flag OFF returns false → callers
fall back to the legacy server path. Makes the stack genuinely dark-launchable:
merge is now a no-op in prod, and the remaining cutover correctness bugs become
flip-prerequisites rather than merge-blockers.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(core,sdk): correct 8 GSAP write-path review findings (#1539)
Eight correctness bugs from the SDK-cutover review. Several were cases where
BOTH writers were identically wrong, so the recast-vs-acorn parity suite stayed
green; the new tests assert the real-world-correct result, not agreement.
- #2 findKfPropByPct: match the CLOSEST keyframe within tolerance, not the first
within 2% — removing/updating 50% on 0/49/50/100 no longer hits 49%.
- #3 handleSetTiming: shift each tween by the start DELTA and scale duration by
the clip-duration RATIO per-tween, instead of writing absolute newStart/
newDuration onto every tween (which collapsed staggers and blew durations).
- #4 enableArcPath: insert motionPath via appendRight at the object start so the
insertion can't collide with the x/y remove-range end (which made MagicString
discard the append and emit '{}').
- #5 splitAnimationsInScript: compute the inherited baseline in a forward pre-pass
so the split-spanning midpoint sees earlier tweens (the reverse write loop is
kept for stable count-suffixed ids).
- #9 unrollDynamicAnimations: preserve non-target loop-body statements (e.g.
tl.set initial-state) per iteration instead of overwriting the whole loop.
- #10 buildMotionPathObjectCode (both writers): emit the cubic form when segment
curviness varies so per-segment curviness survives, not just segments[0].
- #11 readLastWaypointXY: handle UnaryExpression so negative destination coords
are recovered when disabling an arc path.
- #15 no-bang: removed every `!` non-null assertion in the touched files,
replaced with guards/fallbacks.
Tests: gsapWriter.reviewFixes.test.ts (#2/#4/#5/#9/#10/#11) and
mutate.gsap.test.ts setTiming GSAP-sync block (#3). All fail on the base and
pass after the fix; tsc + full core/sdk suites + parity stay green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(studio): SDK cutover review fixes — merge tween props, stabilize debounce, serialize gsap writes, on-disk undo baseline, self-write identity
Addresses 5 SDK-cutover review findings (studio-only):
- #1 useGsapPropertyDebounce: editing one GSAP tween property no longer drops
the tween's other animated props. setGsapTween REPLACES the property set, so
merge the single edit into the tween's CURRENT properties (read from the SDK
doc) before dispatching, mirroring the legacy server merge.
- #7 useGsapPropertyDebounce: stabilize the flush callback by reading sdk deps
from a ref instead of an unmemoized literal, so a parent re-render mid-edit
no longer tears down + flushes the debounce (one commit/undo entry per render).
- #8 sdkCutover/useGsapScriptCommits: route SDK gsap-write persists through the
same per-file keyed serializer the legacy commitMutation uses, so concurrent
same-file read-modify-writes can't interleave and lose an edit.
- #12 sdkCutover/useTimelineEditing: capture the exact on-disk bytes as the undo
'before' for timing/GSAP persists (matching the style/delete paths) instead of
a normalized SDK serialize() re-emit that reformatted the whole file on undo.
- #14 useSdkSession/sdkSelfWriteRegistry: discriminate a cutover echo from an
undo write by CONTENT identity (registered self-write hash), not just the 2 s
timestamp window — an undo write always reloads the SDK session.
Tests: useGsapPropertyDebounce(.test), useGsapPropertyDebounceFlush.test,
sdkSelfWriteRegistry.test, and new sdkCutover.test cases; each reproduces the
review scenario and asserts the corrected behavior (verified red before fix).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(core): extract split/collapse helpers to satisfy no-fallow-ignore rule
The #5 (split) and #15 (no-bang guards) fixes pushed splitAnimationsInScript and
removeAllKeyframesFromScript over fallow's complexity threshold, and a fallow-ignore
had been added to splitAnimationsInScript. Per the hard rule (never ignore — fix),
extracted buildSpanningSplit + applyTweenSplit (split) and buildCollapsedFlatVars
(collapse), and removed the ignore. Both functions now under threshold; fallow new-only
gate reports 0 new findings. Behavior unchanged — core 1811 green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(studio): pin dark-launch flag-gate contract (review #1539, Rames/Via)
flag OFF ⇒ sdkTimingPersist / sdkGsapTweenPersist (GSAP-op chokepoint) /
sdkDeletePersist all return false even with a valid session → legacy fallback.
The prod flag-flip rests on this contract; sdkCutover.test.ts only mocks the flag
TRUE, so a future gate refactor could silently re-enable cutover on flag-off
without failing CI. This sibling file mocks it FALSE and locks the three guards.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(studio): leading flag-gate on sdkGsapTweenPersist (review #1539 nit, Via)
The add-op getElement existence check ran before the inner gate, so flag-off did
an SDK touch before falling back. Lead with the flag guard to match the other
three chokepoints — flag-off is now a clean no-op at every entry point.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(core): unroll-preservation regressions — non-for loops + AST index substitution (review R2)
The #9 unroll-preservation fix had two confirmed regressions:
- Non-for loops (forEach/for-of/for-in/while): loopIndexVarName returns null, so
substitution no-op'd and preserved siblings kept a now-undefined loop variable
(e.g. `item`) → ReferenceError at render. Now returns null for those forms →
caller falls back to the blanket loop overwrite (drops siblings, valid code).
The #9 fixture only used `for(let i…)` so it never caught this.
- substituteLoopIndex did a \bvar\b regex over raw source including string
literals, corrupting selectors like ".row-i" → ".row-0". Now AST-based:
substitutes only real Identifier uses, skipping string literals and non-computed
member/key positions (extracted isIndexBindingPosition helper to stay under the
fallow complexity threshold — no ignore added).
Two regression tests added (forEach no-dangling-var; for-loop string-literal intact).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(sdk,core): unrollDynamicAnimations rejects empty element list (R1 #1501b)
An empty `elements` array has no unrolled form — the writer would overwrite
the loop/statement with zero tween calls, silently deleting the animation.
- gsapWriterAcorn: unrollDynamicAnimations returns the script verbatim on an
empty list (no-op instead of a destructive overwrite).
- validateOp: reject unrollDynamicAnimations with empty elements as
E_INVALID_ARGS so callers get a clean error rather than silent corruption.
- Tests: writer no-op on []; validateOp E_INVALID_ARGS on [].
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* perf(sdk): cache draft element in applyDraft, drop HTMLElement casts (R1 #1490a)
applyDraft runs at 60fps during a drag but re-ran doc.querySelector on every
call — the _draftEl/_draftId fields were only consumed by commit/cancel, never
to skip the query. Reuse the tracked element when the id matches and the node
is still connected; re-query only on id change or detach (iframe reload).
Retypes _draftEl to HTMLElement | null (only ever set from
querySelector<HTMLElement>), which removes the `as HTMLElement` casts in
commitPreview / _clearDraft. Test asserts a repeated same-id drag queries once.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(sdk,core): round-3 correctness — unroll AST safety, single-dispatch undo, empty-arg guards, persist decouple
Addresses the highest-severity round-3 review findings:
- gsapWriterAcorn unroll (R3 #1/#2/#9): the round-2 AST-substitution fix emitted
invalid GSAP for object shorthand `{ i }` (→ `{ 0 }`) and shadowed inner
bindings (→ `for(let i=0;0<3;0++)`), and silently dropped sibling statements on
non-`for` loops (forEach/for-of). The unroll now REFUSES (no-ops, leaving the
dynamic loop intact) whenever siblings can't be safely reproduced — a non-`for`
loop, an unmodeled statement, or an unsafe index use — instead of dropping or
corrupting. Plain `for` loops with safe siblings still unroll.
- session single-dispatch undo (R3 #5/#11): _dispatch now reverses the inverse
patch list (parity with batch()). A single op emitting order-dependent inverse
patches — a nested parent+child removeElement, an aliased multi-target — undid
forward and dropped the child subtree / landed on an intermediate value.
- materializeKeyframes empty-array (R3 #10): the unguarded twin of the just-fixed
unrollDynamicAnimations. Writer no-ops on an empty keyframe list; validateOp
rejects it as E_INVALID_ARGS (shared gsapScriptMissing helper).
- history:false persist decouple (R3 #4): persist (auto-save) no longer lives
inside the history-enable block, so opting out of SDK undo no longer silently
disables all disk writes (data-loss trap for #1496's flag consumers).
Tests: unroll refuse cases (shorthand/shadow/forEach) + safe-for-loop regression;
nested removeElement undo; materializeKeyframes writer no-op + validateOp reject;
history:false-still-persists.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(core): stripGsapForId re-parses per removal so all tweens for a deleted element are stripped (R3 #3)
Animation ids are count-based (positional), so removing one tween renumbers the
survivors. stripGsapForId captured every matching id from a single up-front parse
then removed against the mutating script — after the first removal the later ids
were stale and silently no-op'd, leaving an orphaned tl.to() referencing the
just-deleted element. Now re-parse after each removal and strip the first
still-matching animation until none remain.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(core): gsap writer — keyframe ease routing, convert preserves delay, addLabel dedup (R3 #7/#8/#12)
- #7: updateAnimationInScript routes an ease update on a keyframe tween to
keyframes.easeEach (per-keyframe), not a top-level ease that GSAP ignores —
the user's keyframe-easing edit was silently a no-op.
- #8: convertToKeyframesFromScript now preserves every non-editable vars key
(delay/callbacks/stagger/yoyo/…) verbatim via preservedVarsEntries instead of
rebuilding from the GsapAnimation object, which had no `delay` field and
dropped it — shifting the tween's start time.
- #12: addLabelToScript moves an existing same-named label (overwrites its
position) instead of appending a duplicate; duplicates made removeLabel
over-remove (it deletes every match, including a pre-existing label).
Tests: easeEach routing, delay preservation, addLabel move-not-duplicate +
hand-authored-dup removal. Updated the old "no dedup contract" corpus test.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(sdk): handleSetTiming #domId + data-duration sync; validateOp resolves ids + arc/selector (R3 #6/#13, CF2 #15/#16)
CF2 #15: handleSetTiming re-synced GSAP tweens only when the selector matched the
element's hf-id. The common #domId-targeted tween (authored by the Studio panel)
never matched, so moving/resizing a clip via the SDK timing path left its
animations unsynced. Now match the tween selector against the DOM id too.
CF2 #16: handleSetTiming read/wrote only data-end. Clips authored with
data-duration (what the runtime prefers) got a fresh data-end beside a stale
data-duration (no playback change) and oldDuration=null collapsed the GSAP
duration-scale ratio to 1. Now read duration preferring data-duration, and write
back to whichever attribute the clip uses (timingPath gains a "duration" field).
R3 #13b: deleteAllForSelector compared selectors with strict === and missed the
alternate quote style ([data-hf-id='x'] vs "x"); now quote-insensitive.
R3 #6/#13a: validateOp now resolves the animationId for id-bearing GSAP ops
(E_TARGET_NOT_FOUND instead of a misleading ok that no-ops at apply), and
updateArcSegment validates the arc is enabled + the segment index is in range.
Tests: #domId move sync, data-duration resize + scale, quote-insensitive delete,
unresolved-id rejection, arc-segment preconditions. Updated the loose-can() test.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(core,sdk): name the acorn-node type alias; keyToPath round-trips timing.duration (R3 #14)
- gsapWriterAcorn: replace the bare `: any` AST-node annotations with the named
`type Node = any` alias, matching the established convention in
gsapParserAcorn.ts / gsapInline.ts ("acorn ESTree nodes are structurally
untyped"). Documents intent and is greppable; type-identical (zero runtime
change). A full ESTree typing is a deliberate architecture decision the
codebase has not taken and is out of scope here.
- patches: keyToPath/timingPath now include the "duration" timing field added
for the data-duration resize fix, so a timing.duration override round-trips on
T3 replay instead of being dropped.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(sdk): cascadeRemoveAnimations re-parses per removal (R4 — SDK twin of #3)
cascadeRemoveAnimations captured every matching animation id from a single
up-front parse, then removed against the mutating script — the SDK-side twin of
the stripGsapForId bug (R3 #3). Animation ids are positional, so removing the
first tween for an element renumbered the survivors and the stale later ids
no-op'd, orphaning those tweens on the just-removed element. Now re-parse after
each removal and strip the first still-matching animation until none remain.
Also adds the reviewer's defense-in-depth test: an aliased multi-target setStyle
(same id twice) undoes to the original, not the intermediate (exercises the
single-dispatch inverse reversal from R3 #5/#11).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 09cefc1 commit 8c981a4
29 files changed
Lines changed: 2319 additions & 343 deletions
File tree
- packages
- core/src/parsers
- sdk/src
- adapters
- engine
- studio/src
- hooks
- utils
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2170 | 2170 | | |
2171 | 2171 | | |
2172 | 2172 | | |
| 2173 | + | |
| 2174 | + | |
| 2175 | + | |
| 2176 | + | |
| 2177 | + | |
| 2178 | + | |
| 2179 | + | |
2173 | 2180 | | |
2174 | 2181 | | |
2175 | | - | |
| 2182 | + | |
2176 | 2183 | | |
2177 | 2184 | | |
2178 | 2185 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
120 | 120 | | |
121 | 121 | | |
122 | 122 | | |
123 | | - | |
| 123 | + | |
| 124 | + | |
124 | 125 | | |
125 | 126 | | |
126 | 127 | | |
127 | 128 | | |
128 | | - | |
| 129 | + | |
129 | 130 | | |
130 | | - | |
131 | | - | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
132 | 137 | | |
133 | 138 | | |
134 | 139 | | |
| |||
527 | 532 | | |
528 | 533 | | |
529 | 534 | | |
530 | | - | |
| 535 | + | |
| 536 | + | |
| 537 | + | |
531 | 538 | | |
532 | | - | |
533 | | - | |
| 539 | + | |
| 540 | + | |
| 541 | + | |
| 542 | + | |
| 543 | + | |
534 | 544 | | |
535 | 545 | | |
536 | 546 | | |
| |||
543 | 553 | | |
544 | 554 | | |
545 | 555 | | |
546 | | - | |
| 556 | + | |
| 557 | + | |
| 558 | + | |
| 559 | + | |
| 560 | + | |
| 561 | + | |
| 562 | + | |
| 563 | + | |
| 564 | + | |
| 565 | + | |
| 566 | + | |
547 | 567 | | |
548 | 568 | | |
549 | 569 | | |
| |||
Lines changed: 317 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
0 commit comments