effect 3.3.4 → 3.4.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/Micro/package.json +6 -0
- package/dist/cjs/Array.js +18 -3
- package/dist/cjs/Array.js.map +1 -1
- package/dist/cjs/Chunk.js +13 -2
- package/dist/cjs/Chunk.js.map +1 -1
- package/dist/cjs/Config.js.map +1 -1
- package/dist/cjs/Effect.js +249 -23
- package/dist/cjs/Effect.js.map +1 -1
- package/dist/cjs/Either.js +31 -1
- package/dist/cjs/Either.js.map +1 -1
- package/dist/cjs/ManagedRuntime.js.map +1 -1
- package/dist/cjs/Micro.js +2383 -0
- package/dist/cjs/Micro.js.map +1 -0
- package/dist/cjs/Option.js +1 -2
- package/dist/cjs/Option.js.map +1 -1
- package/dist/cjs/Schedule.js +2 -2
- package/dist/cjs/Stream.js.map +1 -1
- package/dist/cjs/Tuple.js +16 -9
- package/dist/cjs/Tuple.js.map +1 -1
- package/dist/cjs/index.js +4 -2
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/internal/core-effect.js +4 -2
- package/dist/cjs/internal/core-effect.js.map +1 -1
- package/dist/cjs/internal/core.js +12 -2
- package/dist/cjs/internal/core.js.map +1 -1
- package/dist/cjs/internal/fiberRuntime.js +32 -0
- package/dist/cjs/internal/fiberRuntime.js.map +1 -1
- package/dist/cjs/internal/stream.js.map +1 -1
- package/dist/cjs/internal/version.js +1 -1
- package/dist/dts/Array.d.ts +14 -0
- package/dist/dts/Array.d.ts.map +1 -1
- package/dist/dts/Cause.d.ts +1 -1
- package/dist/dts/Chunk.d.ts +11 -0
- package/dist/dts/Chunk.d.ts.map +1 -1
- package/dist/dts/Config.d.ts +3 -4
- package/dist/dts/Config.d.ts.map +1 -1
- package/dist/dts/Effect.d.ts +248 -20
- package/dist/dts/Effect.d.ts.map +1 -1
- package/dist/dts/Either.d.ts +35 -0
- package/dist/dts/Either.d.ts.map +1 -1
- package/dist/dts/ManagedRuntime.d.ts +15 -0
- package/dist/dts/ManagedRuntime.d.ts.map +1 -1
- package/dist/dts/Micro.d.ts +2002 -0
- package/dist/dts/Micro.d.ts.map +1 -0
- package/dist/dts/Option.d.ts +2 -0
- package/dist/dts/Option.d.ts.map +1 -1
- package/dist/dts/Schedule.d.ts +2 -2
- package/dist/dts/Stream.d.ts +45 -6
- package/dist/dts/Stream.d.ts.map +1 -1
- package/dist/dts/Tuple.d.ts +18 -0
- package/dist/dts/Tuple.d.ts.map +1 -1
- package/dist/dts/index.d.ts +7 -0
- package/dist/dts/index.d.ts.map +1 -1
- package/dist/dts/internal/core-effect.d.ts.map +1 -1
- package/dist/dts/internal/core.d.ts.map +1 -1
- package/dist/dts/internal/fiberRuntime.d.ts.map +1 -1
- package/dist/esm/Array.js +14 -0
- package/dist/esm/Array.js.map +1 -1
- package/dist/esm/Chunk.js +11 -0
- package/dist/esm/Chunk.js.map +1 -1
- package/dist/esm/Config.js.map +1 -1
- package/dist/esm/Effect.js +246 -20
- package/dist/esm/Effect.js.map +1 -1
- package/dist/esm/Either.js +30 -0
- package/dist/esm/Either.js.map +1 -1
- package/dist/esm/ManagedRuntime.js.map +1 -1
- package/dist/esm/Micro.js +2307 -0
- package/dist/esm/Micro.js.map +1 -0
- package/dist/esm/Option.js +1 -1
- package/dist/esm/Option.js.map +1 -1
- package/dist/esm/Schedule.js +2 -2
- package/dist/esm/Stream.js.map +1 -1
- package/dist/esm/Tuple.js +15 -8
- package/dist/esm/Tuple.js.map +1 -1
- package/dist/esm/index.js +7 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/internal/core-effect.js +2 -0
- package/dist/esm/internal/core-effect.js.map +1 -1
- package/dist/esm/internal/core.js +10 -1
- package/dist/esm/internal/core.js.map +1 -1
- package/dist/esm/internal/fiberRuntime.js +32 -0
- package/dist/esm/internal/fiberRuntime.js.map +1 -1
- package/dist/esm/internal/stream.js.map +1 -1
- package/dist/esm/internal/version.js +1 -1
- package/package.json +9 -1
- package/src/Array.ts +15 -0
- package/src/Cause.ts +1 -1
- package/src/Chunk.ts +12 -0
- package/src/Config.ts +7 -5
- package/src/Effect.ts +256 -20
- package/src/Either.ts +51 -0
- package/src/ManagedRuntime.ts +16 -0
- package/src/Micro.ts +3826 -0
- package/src/Option.ts +12 -1
- package/src/Schedule.ts +2 -2
- package/src/Stream.ts +60 -8
- package/src/Tuple.ts +18 -8
- package/src/index.ts +8 -0
- package/src/internal/core-effect.ts +33 -0
- package/src/internal/core.ts +18 -1
- package/src/internal/fiberRuntime.ts +32 -0
- package/src/internal/stream.ts +8 -4
- package/src/internal/version.ts +1 -1
package/dist/dts/Effect.d.ts
CHANGED
|
@@ -228,8 +228,38 @@ export declare namespace Effect {
|
|
|
228
228
|
*/
|
|
229
229
|
export declare const isEffect: (u: unknown) => u is Effect<unknown, unknown, unknown>;
|
|
230
230
|
/**
|
|
231
|
-
* Returns an effect that
|
|
232
|
-
*
|
|
231
|
+
* Returns an effect that caches its result for a specified duration, known as
|
|
232
|
+
* the `timeToLive`. When the cache expires after the duration, the effect will be
|
|
233
|
+
* recomputed upon next evaluation.
|
|
234
|
+
*
|
|
235
|
+
* @example
|
|
236
|
+
* import { Effect, Console } from "effect"
|
|
237
|
+
*
|
|
238
|
+
* let i = 1
|
|
239
|
+
* const expensiveTask = Effect.promise<string>(() => {
|
|
240
|
+
* console.log("expensive task...")
|
|
241
|
+
* return new Promise((resolve) => {
|
|
242
|
+
* setTimeout(() => {
|
|
243
|
+
* resolve(`result ${i++}`)
|
|
244
|
+
* }, 100)
|
|
245
|
+
* })
|
|
246
|
+
* })
|
|
247
|
+
*
|
|
248
|
+
* const program = Effect.gen(function* () {
|
|
249
|
+
* const cached = yield* Effect.cachedWithTTL(expensiveTask, "150 millis")
|
|
250
|
+
* yield* cached.pipe(Effect.andThen(Console.log))
|
|
251
|
+
* yield* cached.pipe(Effect.andThen(Console.log))
|
|
252
|
+
* yield* Effect.sleep("100 millis")
|
|
253
|
+
* yield* cached.pipe(Effect.andThen(Console.log))
|
|
254
|
+
* })
|
|
255
|
+
*
|
|
256
|
+
* Effect.runFork(program)
|
|
257
|
+
* // Output:
|
|
258
|
+
* // expensive task...
|
|
259
|
+
* // result 1
|
|
260
|
+
* // result 1
|
|
261
|
+
* // expensive task...
|
|
262
|
+
* // result 2
|
|
233
263
|
*
|
|
234
264
|
* @since 2.0.0
|
|
235
265
|
* @category caching
|
|
@@ -239,10 +269,41 @@ export declare const cachedWithTTL: {
|
|
|
239
269
|
<A, E, R>(self: Effect<A, E, R>, timeToLive: Duration.DurationInput): Effect<Effect<A, E>, never, R>;
|
|
240
270
|
};
|
|
241
271
|
/**
|
|
242
|
-
*
|
|
243
|
-
*
|
|
244
|
-
*
|
|
245
|
-
*
|
|
272
|
+
* Similar to {@link cachedWithTTL}, this function caches an effect's result for a
|
|
273
|
+
* specified duration. It also includes an additional effect for manually
|
|
274
|
+
* invalidating the cached value before it naturally expires.
|
|
275
|
+
*
|
|
276
|
+
* @example
|
|
277
|
+
* import { Effect, Console } from "effect"
|
|
278
|
+
*
|
|
279
|
+
* let i = 1
|
|
280
|
+
* const expensiveTask = Effect.promise<string>(() => {
|
|
281
|
+
* console.log("expensive task...")
|
|
282
|
+
* return new Promise((resolve) => {
|
|
283
|
+
* setTimeout(() => {
|
|
284
|
+
* resolve(`result ${i++}`)
|
|
285
|
+
* }, 100)
|
|
286
|
+
* })
|
|
287
|
+
* })
|
|
288
|
+
*
|
|
289
|
+
* const program = Effect.gen(function* () {
|
|
290
|
+
* const [cached, invalidate] = yield* Effect.cachedInvalidateWithTTL(
|
|
291
|
+
* expensiveTask,
|
|
292
|
+
* "1 hour"
|
|
293
|
+
* )
|
|
294
|
+
* yield* cached.pipe(Effect.andThen(Console.log))
|
|
295
|
+
* yield* cached.pipe(Effect.andThen(Console.log))
|
|
296
|
+
* yield* invalidate
|
|
297
|
+
* yield* cached.pipe(Effect.andThen(Console.log))
|
|
298
|
+
* })
|
|
299
|
+
*
|
|
300
|
+
* Effect.runFork(program)
|
|
301
|
+
* // Output:
|
|
302
|
+
* // expensive task...
|
|
303
|
+
* // result 1
|
|
304
|
+
* // result 1
|
|
305
|
+
* // expensive task...
|
|
306
|
+
* // result 2
|
|
246
307
|
*
|
|
247
308
|
* @since 2.0.0
|
|
248
309
|
* @category caching
|
|
@@ -252,39 +313,102 @@ export declare const cachedInvalidateWithTTL: {
|
|
|
252
313
|
<A, E, R>(self: Effect<A, E, R>, timeToLive: Duration.DurationInput): Effect<[Effect<A, E>, Effect<void>], never, R>;
|
|
253
314
|
};
|
|
254
315
|
/**
|
|
255
|
-
* Returns an effect that
|
|
256
|
-
*
|
|
316
|
+
* Returns an effect that computes a result lazily and caches it. Subsequent
|
|
317
|
+
* evaluations of this effect will return the cached result without re-executing
|
|
318
|
+
* the logic.
|
|
319
|
+
*
|
|
320
|
+
* @example
|
|
321
|
+
* import { Effect, Console } from "effect"
|
|
322
|
+
*
|
|
323
|
+
* let i = 1
|
|
324
|
+
* const expensiveTask = Effect.promise<string>(() => {
|
|
325
|
+
* console.log("expensive task...")
|
|
326
|
+
* return new Promise((resolve) => {
|
|
327
|
+
* setTimeout(() => {
|
|
328
|
+
* resolve(`result ${i++}`)
|
|
329
|
+
* }, 100)
|
|
330
|
+
* })
|
|
331
|
+
* })
|
|
332
|
+
*
|
|
333
|
+
* const program = Effect.gen(function* () {
|
|
334
|
+
* console.log("non-cached version:")
|
|
335
|
+
* yield* expensiveTask.pipe(Effect.andThen(Console.log))
|
|
336
|
+
* yield* expensiveTask.pipe(Effect.andThen(Console.log))
|
|
337
|
+
* console.log("cached version:")
|
|
338
|
+
* const cached = yield* Effect.cached(expensiveTask)
|
|
339
|
+
* yield* cached.pipe(Effect.andThen(Console.log))
|
|
340
|
+
* yield* cached.pipe(Effect.andThen(Console.log))
|
|
341
|
+
* })
|
|
342
|
+
*
|
|
343
|
+
* Effect.runFork(program)
|
|
344
|
+
* // Output:
|
|
345
|
+
* // non-cached version:
|
|
346
|
+
* // expensive task...
|
|
347
|
+
* // result 1
|
|
348
|
+
* // expensive task...
|
|
349
|
+
* // result 2
|
|
350
|
+
* // cached version:
|
|
351
|
+
* // expensive task...
|
|
352
|
+
* // result 3
|
|
353
|
+
* // result 3
|
|
257
354
|
*
|
|
258
355
|
* @since 2.0.0
|
|
259
356
|
* @category caching
|
|
260
357
|
*/
|
|
261
358
|
export declare const cached: <A, E, R>(self: Effect<A, E, R>) => Effect<Effect<A, E, R>>;
|
|
262
359
|
/**
|
|
263
|
-
* Returns a memoized version of
|
|
360
|
+
* Returns a memoized version of a function with effects. Memoization ensures
|
|
361
|
+
* that results are stored and reused for the same inputs, reducing the need to
|
|
362
|
+
* recompute them.
|
|
363
|
+
*
|
|
364
|
+
* @example
|
|
365
|
+
* import { Effect, Random } from "effect"
|
|
366
|
+
*
|
|
367
|
+
* const program = Effect.gen(function* () {
|
|
368
|
+
* const randomNumber = (n: number) => Random.nextIntBetween(1, n)
|
|
369
|
+
* console.log("non-memoized version:")
|
|
370
|
+
* console.log(yield* randomNumber(10))
|
|
371
|
+
* console.log(yield* randomNumber(10))
|
|
372
|
+
*
|
|
373
|
+
* console.log("memoized version:")
|
|
374
|
+
* const memoized = yield* Effect.cachedFunction(randomNumber)
|
|
375
|
+
* console.log(yield* memoized(10))
|
|
376
|
+
* console.log(yield* memoized(10))
|
|
377
|
+
* })
|
|
378
|
+
*
|
|
379
|
+
* Effect.runFork(program)
|
|
380
|
+
* // Example Output:
|
|
381
|
+
* // non-memoized version:
|
|
382
|
+
* // 2
|
|
383
|
+
* // 8
|
|
384
|
+
* // memoized version:
|
|
385
|
+
* // 5
|
|
386
|
+
* // 5
|
|
264
387
|
*
|
|
265
388
|
* @since 2.0.0
|
|
266
389
|
* @category caching
|
|
267
390
|
*/
|
|
268
391
|
export declare const cachedFunction: <A, B, E, R>(f: (a: A) => Effect<B, E, R>, eq?: Equivalence<A>) => Effect<(a: A) => Effect<B, E, R>>;
|
|
269
392
|
/**
|
|
270
|
-
* Returns an effect that
|
|
271
|
-
*
|
|
393
|
+
* Returns an effect that executes only once, regardless of how many times it's
|
|
394
|
+
* called.
|
|
272
395
|
*
|
|
273
396
|
* @example
|
|
274
397
|
* import { Effect, Console } from "effect"
|
|
275
398
|
*
|
|
276
|
-
* const program = Effect.gen(function* (
|
|
277
|
-
* const
|
|
278
|
-
* yield*
|
|
279
|
-
* const
|
|
280
|
-
* yield*
|
|
399
|
+
* const program = Effect.gen(function* () {
|
|
400
|
+
* const task1 = Console.log("task1")
|
|
401
|
+
* yield* Effect.repeatN(task1, 2)
|
|
402
|
+
* const task2 = yield* Effect.once(Console.log("task2"))
|
|
403
|
+
* yield* Effect.repeatN(task2, 2)
|
|
281
404
|
* })
|
|
282
405
|
*
|
|
283
406
|
* Effect.runFork(program)
|
|
284
407
|
* // Output:
|
|
285
|
-
* //
|
|
286
|
-
* //
|
|
287
|
-
* //
|
|
408
|
+
* // task1
|
|
409
|
+
* // task1
|
|
410
|
+
* // task1
|
|
411
|
+
* // task2
|
|
288
412
|
*
|
|
289
413
|
* @since 2.0.0
|
|
290
414
|
* @category caching
|
|
@@ -1415,6 +1539,32 @@ export declare const uninterruptible: <A, E, R>(self: Effect<A, E, R>) => Effect
|
|
|
1415
1539
|
* @category interruption
|
|
1416
1540
|
*/
|
|
1417
1541
|
export declare const uninterruptibleMask: <A, E, R>(f: (restore: <AX, EX, RX>(effect: Effect<AX, EX, RX>) => Effect<AX, EX, RX>) => Effect<A, E, R>) => Effect<A, E, R>;
|
|
1542
|
+
/**
|
|
1543
|
+
* Transforms a `Predicate` function into an `Effect` returning the input value if the predicate returns `true`
|
|
1544
|
+
* or failing with specified error if the predicate fails
|
|
1545
|
+
*
|
|
1546
|
+
* @param predicate - A `Predicate` function that takes in a value of type `A` and returns a boolean.
|
|
1547
|
+
*
|
|
1548
|
+
* @example
|
|
1549
|
+
* import { Effect } from "effect"
|
|
1550
|
+
*
|
|
1551
|
+
* const isPositive = (n: number): boolean => n > 0
|
|
1552
|
+
*
|
|
1553
|
+
* // succeeds with `1`
|
|
1554
|
+
* Effect.liftPredicate(1, isPositive, n => `${n} is not positive`)
|
|
1555
|
+
*
|
|
1556
|
+
* // fails with `"0 is not positive"`
|
|
1557
|
+
* Effect.liftPredicate(0, isPositive, n => `${n} is not positive`)
|
|
1558
|
+
*
|
|
1559
|
+
* @category lifting
|
|
1560
|
+
* @since 3.4.0
|
|
1561
|
+
*/
|
|
1562
|
+
export declare const liftPredicate: {
|
|
1563
|
+
<A, B extends A, E>(refinement: Refinement<NoInfer<A>, B>, orFailWith: (a: NoInfer<A>) => E): (a: A) => Effect<B, E>;
|
|
1564
|
+
<A, E>(predicate: Predicate<NoInfer<A>>, orFailWith: (a: NoInfer<A>) => E): (a: A) => Effect<A, E>;
|
|
1565
|
+
<A, E, B extends A>(self: A, refinement: Refinement<A, B>, orFailWith: (a: A) => E): Effect<B, E>;
|
|
1566
|
+
<A, E>(self: A, predicate: Predicate<NoInfer<A>>, orFailWith: (a: NoInfer<A>) => E): Effect<A, E>;
|
|
1567
|
+
};
|
|
1418
1568
|
/**
|
|
1419
1569
|
* This function maps the success value of an `Effect` value to a specified
|
|
1420
1570
|
* constant value.
|
|
@@ -1758,7 +1908,7 @@ export declare const scope: Effect<Scope.Scope, never, Scope.Scope>;
|
|
|
1758
1908
|
*/
|
|
1759
1909
|
export declare const scopeWith: <A, E, R>(f: (scope: Scope.Scope) => Effect<A, E, R>) => Effect<A, E, R | Scope.Scope>;
|
|
1760
1910
|
/**
|
|
1761
|
-
* Scopes all resources
|
|
1911
|
+
* Scopes all resources used in this workflow to the lifetime of the workflow,
|
|
1762
1912
|
* ensuring that their finalizers are run as soon as this workflow completes
|
|
1763
1913
|
* execution, whether by success, failure, or interruption.
|
|
1764
1914
|
*
|
|
@@ -3751,6 +3901,55 @@ export declare const validateWith: {
|
|
|
3751
3901
|
} | undefined): Effect<C, E | E1, R | R1>;
|
|
3752
3902
|
};
|
|
3753
3903
|
/**
|
|
3904
|
+
* The `Effect.zip` function allows you to combine two effects into a single
|
|
3905
|
+
* effect. This combined effect yields a tuple containing the results of both
|
|
3906
|
+
* input effects once they succeed.
|
|
3907
|
+
*
|
|
3908
|
+
* Note that `Effect.zip` processes effects sequentially: it first completes the
|
|
3909
|
+
* effect on the left and then the effect on the right.
|
|
3910
|
+
*
|
|
3911
|
+
* If you want to run the effects concurrently, you can use the `concurrent` option.
|
|
3912
|
+
*
|
|
3913
|
+
* @example
|
|
3914
|
+
* import { Effect } from "effect"
|
|
3915
|
+
*
|
|
3916
|
+
* const task1 = Effect.succeed(1).pipe(
|
|
3917
|
+
* Effect.delay("200 millis"),
|
|
3918
|
+
* Effect.tap(Effect.log("task1 done"))
|
|
3919
|
+
* )
|
|
3920
|
+
* const task2 = Effect.succeed("hello").pipe(
|
|
3921
|
+
* Effect.delay("100 millis"),
|
|
3922
|
+
* Effect.tap(Effect.log("task2 done"))
|
|
3923
|
+
* )
|
|
3924
|
+
*
|
|
3925
|
+
* const task3 = Effect.zip(task1, task2)
|
|
3926
|
+
*
|
|
3927
|
+
* Effect.runPromise(task3).then(console.log)
|
|
3928
|
+
* // Output:
|
|
3929
|
+
* // timestamp=... level=INFO fiber=#0 message="task1 done"
|
|
3930
|
+
* // timestamp=... level=INFO fiber=#0 message="task2 done"
|
|
3931
|
+
* // [ 1, 'hello' ]
|
|
3932
|
+
*
|
|
3933
|
+
* @example
|
|
3934
|
+
* import { Effect } from "effect"
|
|
3935
|
+
*
|
|
3936
|
+
* const task1 = Effect.succeed(1).pipe(
|
|
3937
|
+
* Effect.delay("200 millis"),
|
|
3938
|
+
* Effect.tap(Effect.log("task1 done"))
|
|
3939
|
+
* )
|
|
3940
|
+
* const task2 = Effect.succeed("hello").pipe(
|
|
3941
|
+
* Effect.delay("100 millis"),
|
|
3942
|
+
* Effect.tap(Effect.log("task2 done"))
|
|
3943
|
+
* )
|
|
3944
|
+
*
|
|
3945
|
+
* const task3 = Effect.zip(task1, task2, { concurrent: true })
|
|
3946
|
+
*
|
|
3947
|
+
* Effect.runPromise(task3).then(console.log)
|
|
3948
|
+
* // Output:
|
|
3949
|
+
* // timestamp=... level=INFO fiber=#0 message="task2 done"
|
|
3950
|
+
* // timestamp=... level=INFO fiber=#0 message="task1 done"
|
|
3951
|
+
* // [ 1, 'hello' ]
|
|
3952
|
+
*
|
|
3754
3953
|
* @since 2.0.0
|
|
3755
3954
|
* @category zipping
|
|
3756
3955
|
*/
|
|
@@ -3825,6 +4024,35 @@ export declare const zipRight: {
|
|
|
3825
4024
|
}): Effect<A2, E2 | E, R2 | R>;
|
|
3826
4025
|
};
|
|
3827
4026
|
/**
|
|
4027
|
+
* The `Effect.zipWith` function operates similarly to {@link zip} by combining
|
|
4028
|
+
* two effects. However, instead of returning a tuple, it allows you to apply a
|
|
4029
|
+
* function to the results of the combined effects, transforming them into a
|
|
4030
|
+
* single value
|
|
4031
|
+
*
|
|
4032
|
+
* @example
|
|
4033
|
+
* import { Effect } from "effect"
|
|
4034
|
+
*
|
|
4035
|
+
* const task1 = Effect.succeed(1).pipe(
|
|
4036
|
+
* Effect.delay("200 millis"),
|
|
4037
|
+
* Effect.tap(Effect.log("task1 done"))
|
|
4038
|
+
* )
|
|
4039
|
+
* const task2 = Effect.succeed("hello").pipe(
|
|
4040
|
+
* Effect.delay("100 millis"),
|
|
4041
|
+
* Effect.tap(Effect.log("task2 done"))
|
|
4042
|
+
* )
|
|
4043
|
+
*
|
|
4044
|
+
* const task3 = Effect.zipWith(
|
|
4045
|
+
* task1,
|
|
4046
|
+
* task2,
|
|
4047
|
+
* (number, string) => number + string.length
|
|
4048
|
+
* )
|
|
4049
|
+
*
|
|
4050
|
+
* Effect.runPromise(task3).then(console.log)
|
|
4051
|
+
* // Output:
|
|
4052
|
+
* // timestamp=... level=INFO fiber=#3 message="task1 done"
|
|
4053
|
+
* // timestamp=... level=INFO fiber=#2 message="task2 done"
|
|
4054
|
+
* // 6
|
|
4055
|
+
*
|
|
3828
4056
|
* @since 2.0.0
|
|
3829
4057
|
* @category zipping
|
|
3830
4058
|
*/
|