solid-js 2.0.0-experimental.14 → 2.0.0-experimental.15

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/dist/solid.cjs CHANGED
@@ -38,8 +38,44 @@ const sharedConfig = {
38
38
  return signals.getNextChildId(o);
39
39
  }
40
40
  };
41
+ let _hydrationEndCallbacks = null;
42
+ let _pendingBoundaries = 0;
43
+ let _hydrationDone = false;
44
+ let _snapshotRootOwner = null;
45
+ function markTopLevelSnapshotScope() {
46
+ if (_snapshotRootOwner) return;
47
+ let owner = signals.getOwner();
48
+ if (!owner) return;
49
+ while (owner._parent) owner = owner._parent;
50
+ signals.markSnapshotScope(owner);
51
+ _snapshotRootOwner = owner;
52
+ }
53
+ function drainHydrationCallbacks() {
54
+ if (_hydrationDone) return;
55
+ _hydrationDone = true;
56
+ _doneValue = true;
57
+ signals.clearSnapshots();
58
+ signals.setSnapshotCapture(false);
59
+ signals.flush();
60
+ const cbs = _hydrationEndCallbacks;
61
+ _hydrationEndCallbacks = null;
62
+ if (cbs) for (const cb of cbs) cb();
63
+ setTimeout(() => {
64
+ if (globalThis._$HY) globalThis._$HY.done = true;
65
+ });
66
+ }
67
+ function checkHydrationComplete() {
68
+ if (_pendingBoundaries === 0) drainHydrationCallbacks();
69
+ }
70
+ let _hydratingValue = false;
71
+ let _doneValue = false;
41
72
  let _createMemo;
42
73
  let _createSignal;
74
+ let _createErrorBoundary;
75
+ let _createOptimistic;
76
+ let _createProjection;
77
+ let _createStore;
78
+ let _createOptimisticStore;
43
79
  class MockPromise {
44
80
  static all() {
45
81
  return new MockPromise();
@@ -75,14 +111,110 @@ function subFetch(fn, prev) {
75
111
  try {
76
112
  window.fetch = () => new MockPromise();
77
113
  Promise = MockPromise;
78
- return fn(prev);
114
+ const result = fn(prev);
115
+ if (result && typeof result[Symbol.asyncIterator] === "function") {
116
+ result[Symbol.asyncIterator]().next();
117
+ }
118
+ return result;
79
119
  } finally {
80
120
  window.fetch = ogFetch;
81
121
  Promise = ogPromise;
82
122
  }
83
123
  }
124
+ function consumeFirstSync(ai) {
125
+ const iter = ai[Symbol.asyncIterator]();
126
+ const r = iter.next();
127
+ const value = !(r instanceof Promise) && !r.done ? r.value : undefined;
128
+ return [value, iter];
129
+ }
130
+ function applyPatches(target, patches) {
131
+ for (const patch of patches) {
132
+ const path = patch[0];
133
+ let current = target;
134
+ for (let i = 0; i < path.length - 1; i++) current = current[path[i]];
135
+ const key = path[path.length - 1];
136
+ if (patch.length === 1) {
137
+ Array.isArray(current) ? current.splice(key, 1) : delete current[key];
138
+ } else if (patch.length === 3) {
139
+ current.splice(key, 0, patch[1]);
140
+ } else {
141
+ current[key] = patch[1];
142
+ }
143
+ }
144
+ }
145
+ function scheduleIteratorConsumption(iter, apply) {
146
+ const consume = () => {
147
+ while (true) {
148
+ const n = iter.next();
149
+ if (n instanceof Promise) {
150
+ n.then(r => {
151
+ if (r.done) return;
152
+ apply(r.value);
153
+ consume();
154
+ });
155
+ return;
156
+ }
157
+ if (n.done) break;
158
+ apply(n.value);
159
+ }
160
+ };
161
+ consume();
162
+ }
163
+ function isAsyncIterable(v) {
164
+ return v != null && typeof v[Symbol.asyncIterator] === "function";
165
+ }
166
+ function hydrateSignalFromAsyncIterable(coreFn, compute, value, options) {
167
+ const parent = signals.getOwner();
168
+ const expectedId = signals.peekNextChildId(parent);
169
+ if (!sharedConfig.has(expectedId)) return null;
170
+ const initP = sharedConfig.load(expectedId);
171
+ if (!isAsyncIterable(initP)) return null;
172
+ const [firstValue, iter] = consumeFirstSync(initP);
173
+ const [get, set] = signals.createSignal(firstValue);
174
+ const result = coreFn(() => get(), firstValue, options);
175
+ scheduleIteratorConsumption(iter, v => {
176
+ set(() => v);
177
+ signals.flush();
178
+ });
179
+ return result;
180
+ }
181
+ function hydrateStoreFromAsyncIterable(coreFn, initialValue, options) {
182
+ const parent = signals.getOwner();
183
+ const expectedId = signals.peekNextChildId(parent);
184
+ if (!sharedConfig.has(expectedId)) return null;
185
+ const initP = sharedConfig.load(expectedId);
186
+ if (!isAsyncIterable(initP)) return null;
187
+ const [firstState, iter] = consumeFirstSync(initP);
188
+ const [store, setStore] = coreFn(() => {}, firstState ?? initialValue, options);
189
+ scheduleIteratorConsumption(iter, patches => {
190
+ setStore(d => {
191
+ applyPatches(d, patches);
192
+ });
193
+ });
194
+ return [store, setStore];
195
+ }
84
196
  function hydratedCreateMemo(compute, value, options) {
85
197
  if (!sharedConfig.hydrating) return signals.createMemo(compute, value, options);
198
+ markTopLevelSnapshotScope();
199
+ const ssrSource = options?.ssrSource;
200
+ if (ssrSource === "client") {
201
+ const [hydrated, setHydrated] = signals.createSignal(false);
202
+ const memo = signals.createMemo(prev => {
203
+ if (!hydrated()) return prev ?? value;
204
+ return compute(prev);
205
+ }, value, options);
206
+ setHydrated(true);
207
+ return memo;
208
+ }
209
+ if (ssrSource === "initial") {
210
+ return signals.createMemo(prev => {
211
+ if (!sharedConfig.hydrating) return compute(prev);
212
+ subFetch(compute, prev);
213
+ return prev ?? value;
214
+ }, value, options);
215
+ }
216
+ const aiResult = hydrateSignalFromAsyncIterable(signals.createMemo, compute, value, options);
217
+ if (aiResult !== null) return aiResult;
86
218
  return signals.createMemo(prev => {
87
219
  const o = signals.getOwner();
88
220
  if (!sharedConfig.hydrating) return compute(prev);
@@ -94,6 +226,26 @@ function hydratedCreateMemo(compute, value, options) {
94
226
  }
95
227
  function hydratedCreateSignal(fn, second, third) {
96
228
  if (typeof fn !== "function" || !sharedConfig.hydrating) return signals.createSignal(fn, second, third);
229
+ markTopLevelSnapshotScope();
230
+ const ssrSource = third?.ssrSource;
231
+ if (ssrSource === "client") {
232
+ const [hydrated, setHydrated] = signals.createSignal(false);
233
+ const sig = signals.createSignal(prev => {
234
+ if (!hydrated()) return prev ?? second;
235
+ return fn(prev);
236
+ }, second, third);
237
+ setHydrated(true);
238
+ return sig;
239
+ }
240
+ if (ssrSource === "initial") {
241
+ return signals.createSignal(prev => {
242
+ if (!sharedConfig.hydrating) return fn(prev);
243
+ subFetch(fn, prev);
244
+ return prev ?? second;
245
+ }, second, third);
246
+ }
247
+ const aiResult = hydrateSignalFromAsyncIterable(signals.createSignal, fn, second, third);
248
+ if (aiResult !== null) return aiResult;
97
249
  return signals.createSignal(prev => {
98
250
  if (!sharedConfig.hydrating) return fn(prev);
99
251
  const o = signals.getOwner();
@@ -103,17 +255,215 @@ function hydratedCreateSignal(fn, second, third) {
103
255
  return init != null ? (subFetch(fn, prev), init) : fn(prev);
104
256
  }, second, third);
105
257
  }
258
+ function hydratedCreateErrorBoundary(fn, fallback) {
259
+ if (!sharedConfig.hydrating) return signals.createErrorBoundary(fn, fallback);
260
+ markTopLevelSnapshotScope();
261
+ const parent = signals.getOwner();
262
+ const expectedId = signals.peekNextChildId(parent);
263
+ if (sharedConfig.has(expectedId)) {
264
+ const err = sharedConfig.load(expectedId);
265
+ if (err !== undefined) {
266
+ let hydrated = true;
267
+ return signals.createErrorBoundary(() => {
268
+ if (hydrated) {
269
+ hydrated = false;
270
+ throw err;
271
+ }
272
+ return fn();
273
+ }, fallback);
274
+ }
275
+ }
276
+ return signals.createErrorBoundary(fn, fallback);
277
+ }
278
+ function hydratedCreateOptimistic(fn, second, third) {
279
+ if (typeof fn !== "function" || !sharedConfig.hydrating) return signals.createOptimistic(fn, second, third);
280
+ markTopLevelSnapshotScope();
281
+ const ssrSource = third?.ssrSource;
282
+ if (ssrSource === "client") {
283
+ const [hydrated, setHydrated] = signals.createSignal(false);
284
+ const sig = signals.createOptimistic(prev => {
285
+ if (!hydrated()) return prev ?? second;
286
+ return fn(prev);
287
+ }, second, third);
288
+ setHydrated(true);
289
+ return sig;
290
+ }
291
+ if (ssrSource === "initial") {
292
+ return signals.createOptimistic(prev => {
293
+ if (!sharedConfig.hydrating) return fn(prev);
294
+ subFetch(fn, prev);
295
+ return prev ?? second;
296
+ }, second, third);
297
+ }
298
+ const aiResult = hydrateSignalFromAsyncIterable(signals.createOptimistic, fn, second, third);
299
+ if (aiResult !== null) return aiResult;
300
+ return signals.createOptimistic(prev => {
301
+ const o = signals.getOwner();
302
+ if (!sharedConfig.hydrating) return fn(prev);
303
+ let initP;
304
+ if (sharedConfig.has(o.id)) initP = sharedConfig.load(o.id);
305
+ const init = initP?.v ?? initP;
306
+ return init != null ? (subFetch(fn, prev), init) : fn(prev);
307
+ }, second, third);
308
+ }
309
+ function wrapStoreFn(fn, ssrSource) {
310
+ if (ssrSource === "initial") {
311
+ return draft => {
312
+ if (!sharedConfig.hydrating) return fn(draft);
313
+ subFetch(fn, draft);
314
+ return undefined;
315
+ };
316
+ }
317
+ return draft => {
318
+ const o = signals.getOwner();
319
+ if (!sharedConfig.hydrating) return fn(draft);
320
+ let initP;
321
+ if (sharedConfig.has(o.id)) initP = sharedConfig.load(o.id);
322
+ const init = initP?.v ?? initP;
323
+ return init != null ? (subFetch(fn, draft), init) : fn(draft);
324
+ };
325
+ }
326
+ function hydratedCreateStore(first, second, third) {
327
+ if (typeof first !== "function" || !sharedConfig.hydrating) return signals.createStore(first, second, third);
328
+ markTopLevelSnapshotScope();
329
+ const ssrSource = third?.ssrSource;
330
+ if (ssrSource === "client" || ssrSource === "initial") {
331
+ return signals.createStore(second ?? {}, undefined, third);
332
+ }
333
+ const aiResult = hydrateStoreFromAsyncIterable(signals.createStore, second ?? {}, third);
334
+ if (aiResult !== null) return aiResult;
335
+ return signals.createStore(wrapStoreFn(first, ssrSource), second, third);
336
+ }
337
+ function hydratedCreateOptimisticStore(first, second, third) {
338
+ if (typeof first !== "function" || !sharedConfig.hydrating) return signals.createOptimisticStore(first, second, third);
339
+ markTopLevelSnapshotScope();
340
+ const ssrSource = third?.ssrSource;
341
+ if (ssrSource === "client" || ssrSource === "initial") {
342
+ return signals.createOptimisticStore(second ?? {}, undefined, third);
343
+ }
344
+ const aiResult = hydrateStoreFromAsyncIterable(signals.createOptimisticStore, second ?? {}, third);
345
+ if (aiResult !== null) return aiResult;
346
+ return signals.createOptimisticStore(wrapStoreFn(first, ssrSource), second, third);
347
+ }
348
+ function hydratedCreateProjection(fn, initialValue, options) {
349
+ if (!sharedConfig.hydrating) return signals.createProjection(fn, initialValue, options);
350
+ markTopLevelSnapshotScope();
351
+ const ssrSource = options?.ssrSource;
352
+ if (ssrSource === "client" || ssrSource === "initial") {
353
+ return signals.createProjection(draft => draft, initialValue, options);
354
+ }
355
+ const aiResult = hydrateStoreFromAsyncIterable(signals.createStore, initialValue, options);
356
+ if (aiResult !== null) return aiResult[0];
357
+ return signals.createProjection(wrapStoreFn(fn, ssrSource), initialValue, options);
358
+ }
106
359
  function enableHydration() {
107
360
  _createMemo = hydratedCreateMemo;
108
361
  _createSignal = hydratedCreateSignal;
362
+ _createErrorBoundary = hydratedCreateErrorBoundary;
363
+ _createOptimistic = hydratedCreateOptimistic;
364
+ _createProjection = hydratedCreateProjection;
365
+ _createStore = hydratedCreateStore;
366
+ _createOptimisticStore = hydratedCreateOptimisticStore;
367
+ _hydratingValue = sharedConfig.hydrating;
368
+ _doneValue = sharedConfig.done;
369
+ Object.defineProperty(sharedConfig, "hydrating", {
370
+ get() {
371
+ return _hydratingValue;
372
+ },
373
+ set(v) {
374
+ const was = _hydratingValue;
375
+ _hydratingValue = v;
376
+ if (!was && v) {
377
+ _hydrationDone = false;
378
+ _doneValue = false;
379
+ _pendingBoundaries = 0;
380
+ signals.setSnapshotCapture(true);
381
+ _snapshotRootOwner = null;
382
+ } else if (was && !v) {
383
+ if (_snapshotRootOwner) {
384
+ signals.releaseSnapshotScope(_snapshotRootOwner);
385
+ _snapshotRootOwner = null;
386
+ }
387
+ checkHydrationComplete();
388
+ }
389
+ },
390
+ configurable: true,
391
+ enumerable: true
392
+ });
393
+ Object.defineProperty(sharedConfig, "done", {
394
+ get() {
395
+ return _doneValue;
396
+ },
397
+ set(v) {
398
+ _doneValue = v;
399
+ if (v) drainHydrationCallbacks();
400
+ },
401
+ configurable: true,
402
+ enumerable: true
403
+ });
109
404
  }
110
405
  const createMemo = (...args) => (_createMemo || signals.createMemo)(...args);
111
406
  const createSignal = (...args) => (_createSignal || signals.createSignal)(...args);
407
+ const createErrorBoundary = (...args) => (_createErrorBoundary || signals.createErrorBoundary)(...args);
408
+ const createOptimistic = (...args) => (_createOptimistic || signals.createOptimistic)(...args);
409
+ const createProjection = (...args) => (_createProjection || signals.createProjection)(...args);
410
+ const createStore = (...args) => (_createStore || signals.createStore)(...args);
411
+ const createOptimisticStore = (...args) => (_createOptimisticStore || signals.createOptimisticStore)(...args);
412
+ function loadModuleAssets(mapping) {
413
+ const hy = globalThis._$HY;
414
+ if (!hy) return;
415
+ if (!hy.modules) hy.modules = {};
416
+ if (!hy.loading) hy.loading = {};
417
+ const pending = [];
418
+ for (const moduleUrl in mapping) {
419
+ if (hy.modules[moduleUrl]) continue;
420
+ const entryUrl = mapping[moduleUrl];
421
+ if (!hy.loading[moduleUrl]) {
422
+ hy.loading[moduleUrl] = import(entryUrl).then(mod => {
423
+ hy.modules[moduleUrl] = mod;
424
+ });
425
+ }
426
+ pending.push(hy.loading[moduleUrl]);
427
+ }
428
+ return pending.length ? Promise.all(pending).then(() => {}) : undefined;
429
+ }
430
+ function createBoundaryTrigger() {
431
+ signals.setSnapshotCapture(false);
432
+ const [s, set] = signals.createSignal(undefined, {
433
+ equals: false
434
+ });
435
+ s();
436
+ signals.setSnapshotCapture(true);
437
+ return set;
438
+ }
439
+ function resumeBoundaryHydration(o, id, set) {
440
+ _pendingBoundaries--;
441
+ if (signals.isDisposed(o)) {
442
+ checkHydrationComplete();
443
+ return;
444
+ }
445
+ sharedConfig.gather(id);
446
+ _hydratingValue = true;
447
+ signals.markSnapshotScope(o);
448
+ _snapshotRootOwner = o;
449
+ set();
450
+ signals.flush();
451
+ _snapshotRootOwner = null;
452
+ _hydratingValue = false;
453
+ signals.releaseSnapshotScope(o);
454
+ signals.flush();
455
+ checkHydrationComplete();
456
+ }
112
457
  function Loading(props) {
113
458
  if (!sharedConfig.hydrating) return signals.createLoadBoundary(() => props.children, () => props.fallback);
114
459
  return signals.createMemo(() => {
115
460
  const o = signals.getOwner();
116
461
  const id = o.id;
462
+ let assetPromise;
463
+ if (sharedConfig.hydrating && sharedConfig.has(id + "_assets")) {
464
+ const mapping = sharedConfig.load(id + "_assets");
465
+ if (mapping && typeof mapping === "object") assetPromise = loadModuleAssets(mapping);
466
+ }
117
467
  if (sharedConfig.hydrating && sharedConfig.has(id)) {
118
468
  let ref = sharedConfig.load(id);
119
469
  let p;
@@ -121,24 +471,38 @@ function Loading(props) {
121
471
  if (typeof ref !== "object" || ref.s !== 1) p = ref;else sharedConfig.gather(id);
122
472
  }
123
473
  if (p) {
124
- const [s, set] = signals.createSignal(undefined, {
125
- equals: false
474
+ _pendingBoundaries++;
475
+ signals.onCleanup(() => {
476
+ if (!signals.isDisposed(o)) return;
477
+ sharedConfig.cleanupFragment?.(id);
126
478
  });
127
- s();
479
+ const set = createBoundaryTrigger();
128
480
  if (p !== "$$f") {
129
- p.then(() => {
130
- sharedConfig.gather(id);
131
- sharedConfig.hydrating = true;
481
+ const waitFor = assetPromise ? Promise.all([p, assetPromise]) : p;
482
+ waitFor.then(() => resumeBoundaryHydration(o, id, set), err => {
483
+ _pendingBoundaries--;
484
+ checkHydrationComplete();
485
+ signals.runWithOwner(o, () => {
486
+ throw err;
487
+ });
488
+ });
489
+ } else {
490
+ const afterAssets = () => {
491
+ _pendingBoundaries--;
132
492
  set();
133
- signals.flush();
134
- sharedConfig.hydrating = false;
135
- }, err => signals.runWithOwner(o, () => {
136
- throw err;
137
- }));
138
- } else queueMicrotask(set);
493
+ checkHydrationComplete();
494
+ };
495
+ if (assetPromise) assetPromise.then(() => queueMicrotask(afterAssets));else queueMicrotask(afterAssets);
496
+ }
139
497
  return props.fallback;
140
498
  }
141
499
  }
500
+ if (assetPromise) {
501
+ _pendingBoundaries++;
502
+ const set = createBoundaryTrigger();
503
+ assetPromise.then(() => resumeBoundaryHydration(o, id, set));
504
+ return undefined;
505
+ }
142
506
  return signals.createLoadBoundary(() => props.children, () => props.fallback);
143
507
  });
144
508
  }
@@ -146,11 +510,24 @@ function Loading(props) {
146
510
  function createComponent(Comp, props) {
147
511
  return signals.untrack(() => Comp(props || {}));
148
512
  }
149
- function lazy(fn) {
513
+ function lazy(fn, moduleUrl) {
150
514
  let comp;
151
515
  let p;
152
516
  const wrap = props => {
153
- comp = signals.createMemo(() => (p || (p = fn())).then(mod => mod.default));
517
+ if (sharedConfig.hydrating && moduleUrl) {
518
+ const cached = globalThis._$HY?.modules?.[moduleUrl];
519
+ if (!cached) {
520
+ throw new Error(`lazy() module "${moduleUrl}" was not preloaded before hydration. ` + "Ensure it is inside a Loading boundary.");
521
+ }
522
+ comp = () => cached.default;
523
+ }
524
+ if (!comp) {
525
+ p || (p = fn());
526
+ p.then(mod => {
527
+ comp = () => mod.default;
528
+ });
529
+ comp = signals.createMemo(() => p.then(mod => mod.default));
530
+ }
154
531
  let Comp;
155
532
  return signals.createMemo(() => (Comp = comp()) ? signals.untrack(() => {
156
533
  return Comp(props);
@@ -192,10 +569,15 @@ function Show(props) {
192
569
  if (c) {
193
570
  const child = props.children;
194
571
  const fn = typeof child === "function" && child.length > 0;
195
- return fn ? signals.untrack(() => child(() => {
196
- if (!signals.untrack(condition)) throw narrowedError("Show");
197
- return conditionValue();
198
- })) : child;
572
+ return fn ? signals.untrack(() => {
573
+ try {
574
+ return child(() => {
575
+ if (!signals.untrack(condition)) throw narrowedError("Show");
576
+ return conditionValue();
577
+ });
578
+ } finally {
579
+ }
580
+ }) : child;
199
581
  }
200
582
  return props.fallback;
201
583
  }, undefined, undefined);
@@ -223,17 +605,22 @@ function Switch(props) {
223
605
  const [index, conditionValue, mp] = sel;
224
606
  const child = mp.children;
225
607
  const fn = typeof child === "function" && child.length > 0;
226
- return fn ? signals.untrack(() => child(() => {
227
- if (signals.untrack(switchFunc)()?.[0] !== index) throw narrowedError("Match");
228
- return conditionValue();
229
- })) : child;
608
+ return fn ? signals.untrack(() => {
609
+ try {
610
+ return child(() => {
611
+ if (signals.untrack(switchFunc)()?.[0] !== index) throw narrowedError("Match");
612
+ return conditionValue();
613
+ });
614
+ } finally {
615
+ }
616
+ }) : child;
230
617
  }, undefined, undefined);
231
618
  }
232
619
  function Match(props) {
233
620
  return props;
234
621
  }
235
622
  function Errored(props) {
236
- return signals.createErrorBoundary(() => props.children, (err, reset) => {
623
+ return createErrorBoundary(() => props.children, (err, reset) => {
237
624
  const f = props.fallback;
238
625
  return typeof f === "function" && f.length ? f(err, reset) : f;
239
626
  });
@@ -263,18 +650,6 @@ Object.defineProperty(exports, "createEffect", {
263
650
  enumerable: true,
264
651
  get: function () { return signals.createEffect; }
265
652
  });
266
- Object.defineProperty(exports, "createOptimistic", {
267
- enumerable: true,
268
- get: function () { return signals.createOptimistic; }
269
- });
270
- Object.defineProperty(exports, "createOptimisticStore", {
271
- enumerable: true,
272
- get: function () { return signals.createOptimisticStore; }
273
- });
274
- Object.defineProperty(exports, "createProjection", {
275
- enumerable: true,
276
- get: function () { return signals.createProjection; }
277
- });
278
653
  Object.defineProperty(exports, "createReaction", {
279
654
  enumerable: true,
280
655
  get: function () { return signals.createReaction; }
@@ -287,10 +662,6 @@ Object.defineProperty(exports, "createRoot", {
287
662
  enumerable: true,
288
663
  get: function () { return signals.createRoot; }
289
664
  });
290
- Object.defineProperty(exports, "createStore", {
291
- enumerable: true,
292
- get: function () { return signals.createStore; }
293
- });
294
665
  Object.defineProperty(exports, "createTrackedEffect", {
295
666
  enumerable: true,
296
667
  get: function () { return signals.createTrackedEffect; }
@@ -396,7 +767,11 @@ exports.children = children;
396
767
  exports.createComponent = createComponent;
397
768
  exports.createContext = createContext;
398
769
  exports.createMemo = createMemo;
770
+ exports.createOptimistic = createOptimistic;
771
+ exports.createOptimisticStore = createOptimisticStore;
772
+ exports.createProjection = createProjection;
399
773
  exports.createSignal = createSignal;
774
+ exports.createStore = createStore;
400
775
  exports.createUniqueId = createUniqueId;
401
776
  exports.enableHydration = enableHydration;
402
777
  exports.lazy = lazy;