effect 3.15.4 → 3.16.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.
Files changed (128) hide show
  1. package/ExecutionPlan/package.json +6 -0
  2. package/dist/cjs/Array.js +67 -5
  3. package/dist/cjs/Array.js.map +1 -1
  4. package/dist/cjs/BigDecimal.js +150 -1
  5. package/dist/cjs/BigDecimal.js.map +1 -1
  6. package/dist/cjs/Chunk.js +16 -3
  7. package/dist/cjs/Chunk.js.map +1 -1
  8. package/dist/cjs/Config.js +16 -2
  9. package/dist/cjs/Config.js.map +1 -1
  10. package/dist/cjs/Effect.js +31 -3
  11. package/dist/cjs/Effect.js.map +1 -1
  12. package/dist/cjs/ExecutionPlan.js +108 -0
  13. package/dist/cjs/ExecutionPlan.js.map +1 -0
  14. package/dist/cjs/HashMap.js +18 -1
  15. package/dist/cjs/HashMap.js.map +1 -1
  16. package/dist/cjs/Iterable.js +27 -1
  17. package/dist/cjs/Iterable.js.map +1 -1
  18. package/dist/cjs/LayerMap.js +86 -64
  19. package/dist/cjs/LayerMap.js.map +1 -1
  20. package/dist/cjs/Schedule.js +7 -1
  21. package/dist/cjs/Schedule.js.map +1 -1
  22. package/dist/cjs/Stream.js +15 -2
  23. package/dist/cjs/Stream.js.map +1 -1
  24. package/dist/cjs/index.js +4 -2
  25. package/dist/cjs/index.js.map +1 -1
  26. package/dist/cjs/internal/config.js +18 -1
  27. package/dist/cjs/internal/config.js.map +1 -1
  28. package/dist/cjs/internal/effect/circular.js +1 -4
  29. package/dist/cjs/internal/effect/circular.js.map +1 -1
  30. package/dist/cjs/internal/executionPlan.js +68 -0
  31. package/dist/cjs/internal/executionPlan.js.map +1 -0
  32. package/dist/cjs/internal/hashMap.js +3 -1
  33. package/dist/cjs/internal/hashMap.js.map +1 -1
  34. package/dist/cjs/internal/metric/polling.js +3 -4
  35. package/dist/cjs/internal/metric/polling.js.map +1 -1
  36. package/dist/cjs/internal/schedule.js +66 -25
  37. package/dist/cjs/internal/schedule.js.map +1 -1
  38. package/dist/cjs/internal/stream.js +60 -10
  39. package/dist/cjs/internal/stream.js.map +1 -1
  40. package/dist/cjs/internal/version.js +1 -1
  41. package/dist/dts/Array.d.ts +110 -0
  42. package/dist/dts/Array.d.ts.map +1 -1
  43. package/dist/dts/BigDecimal.d.ts +235 -0
  44. package/dist/dts/BigDecimal.d.ts.map +1 -1
  45. package/dist/dts/Chunk.d.ts +13 -0
  46. package/dist/dts/Chunk.d.ts.map +1 -1
  47. package/dist/dts/Config.d.ts +38 -1
  48. package/dist/dts/Config.d.ts.map +1 -1
  49. package/dist/dts/Effect.d.ts +99 -27
  50. package/dist/dts/Effect.d.ts.map +1 -1
  51. package/dist/dts/ExecutionPlan.d.ts +213 -0
  52. package/dist/dts/ExecutionPlan.d.ts.map +1 -0
  53. package/dist/dts/HashMap.d.ts +52 -0
  54. package/dist/dts/HashMap.d.ts.map +1 -1
  55. package/dist/dts/Iterable.d.ts +49 -0
  56. package/dist/dts/Iterable.d.ts.map +1 -1
  57. package/dist/dts/LayerMap.d.ts +79 -72
  58. package/dist/dts/LayerMap.d.ts.map +1 -1
  59. package/dist/dts/Schedule.d.ts +26 -0
  60. package/dist/dts/Schedule.d.ts.map +1 -1
  61. package/dist/dts/Stream.d.ts +57 -2
  62. package/dist/dts/Stream.d.ts.map +1 -1
  63. package/dist/dts/index.d.ts +5 -0
  64. package/dist/dts/index.d.ts.map +1 -1
  65. package/dist/dts/internal/executionPlan.d.ts +2 -0
  66. package/dist/dts/internal/executionPlan.d.ts.map +1 -0
  67. package/dist/dts/internal/hashMap.d.ts.map +1 -1
  68. package/dist/dts/internal/stream.d.ts.map +1 -1
  69. package/dist/esm/Array.js +65 -3
  70. package/dist/esm/Array.js.map +1 -1
  71. package/dist/esm/BigDecimal.js +148 -0
  72. package/dist/esm/BigDecimal.js.map +1 -1
  73. package/dist/esm/Chunk.js +15 -2
  74. package/dist/esm/Chunk.js.map +1 -1
  75. package/dist/esm/Config.js +15 -1
  76. package/dist/esm/Config.js.map +1 -1
  77. package/dist/esm/Effect.js +29 -1
  78. package/dist/esm/Effect.js.map +1 -1
  79. package/dist/esm/ExecutionPlan.js +99 -0
  80. package/dist/esm/ExecutionPlan.js.map +1 -0
  81. package/dist/esm/HashMap.js +17 -0
  82. package/dist/esm/HashMap.js.map +1 -1
  83. package/dist/esm/Iterable.js +26 -0
  84. package/dist/esm/Iterable.js.map +1 -1
  85. package/dist/esm/LayerMap.js +86 -64
  86. package/dist/esm/LayerMap.js.map +1 -1
  87. package/dist/esm/Schedule.js +5 -0
  88. package/dist/esm/Schedule.js.map +1 -1
  89. package/dist/esm/Stream.js +13 -0
  90. package/dist/esm/Stream.js.map +1 -1
  91. package/dist/esm/index.js +5 -0
  92. package/dist/esm/index.js.map +1 -1
  93. package/dist/esm/internal/config.js +16 -0
  94. package/dist/esm/internal/config.js.map +1 -1
  95. package/dist/esm/internal/effect/circular.js +0 -3
  96. package/dist/esm/internal/effect/circular.js.map +1 -1
  97. package/dist/esm/internal/executionPlan.js +59 -0
  98. package/dist/esm/internal/executionPlan.js.map +1 -0
  99. package/dist/esm/internal/hashMap.js +2 -0
  100. package/dist/esm/internal/hashMap.js.map +1 -1
  101. package/dist/esm/internal/metric/polling.js +3 -4
  102. package/dist/esm/internal/metric/polling.js.map +1 -1
  103. package/dist/esm/internal/schedule.js +61 -23
  104. package/dist/esm/internal/schedule.js.map +1 -1
  105. package/dist/esm/internal/stream.js +57 -7
  106. package/dist/esm/internal/stream.js.map +1 -1
  107. package/dist/esm/internal/version.js +1 -1
  108. package/package.json +9 -1
  109. package/src/Array.ts +147 -4
  110. package/src/BigDecimal.ts +355 -0
  111. package/src/Chunk.ts +28 -3
  112. package/src/Config.ts +40 -1
  113. package/src/Effect.ts +145 -36
  114. package/src/ExecutionPlan.ts +302 -0
  115. package/src/HashMap.ts +56 -0
  116. package/src/Iterable.ts +66 -0
  117. package/src/LayerMap.ts +126 -114
  118. package/src/Schedule.ts +32 -0
  119. package/src/Stream.ts +51 -2
  120. package/src/index.ts +6 -0
  121. package/src/internal/config.ts +55 -0
  122. package/src/internal/effect/circular.ts +0 -15
  123. package/src/internal/executionPlan.ts +114 -0
  124. package/src/internal/hashMap.ts +6 -0
  125. package/src/internal/metric/polling.ts +3 -4
  126. package/src/internal/schedule.ts +169 -50
  127. package/src/internal/stream.ts +140 -15
  128. package/src/internal/version.ts +1 -1
@@ -0,0 +1,302 @@
1
+ /**
2
+ * @since 3.16.0
3
+ * @experimental
4
+ */
5
+ import type { NonEmptyReadonlyArray } from "./Array.js"
6
+ import type * as Context from "./Context.js"
7
+ import * as Effect from "./Effect.js"
8
+ import * as internal from "./internal/executionPlan.js"
9
+ import * as Layer from "./Layer.js"
10
+ import type { Pipeable } from "./Pipeable.js"
11
+ import { pipeArguments } from "./Pipeable.js"
12
+ import type * as Schedule from "./Schedule.js"
13
+
14
+ /**
15
+ * @since 3.16.0
16
+ * @category Symbols
17
+ * @experimental
18
+ */
19
+ export const TypeId: unique symbol = internal.TypeId
20
+
21
+ /**
22
+ * @since 3.16.0
23
+ * @category Symbols
24
+ * @experimental
25
+ */
26
+ export type TypeId = typeof TypeId
27
+
28
+ /**
29
+ * @since 3.16.0
30
+ * @category Guards
31
+ * @experimental
32
+ */
33
+ export const isExecutionPlan: (u: unknown) => u is ExecutionPlan<any> = internal.isExecutionPlan
34
+
35
+ /**
36
+ * A `ExecutionPlan` can be used with `Effect.withExecutionPlan` or `Stream.withExecutionPlan`, allowing you to provide different resources for each step of execution until the effect succeeds or the plan is exhausted.
37
+ *
38
+ * ```ts
39
+ * import { type AiLanguageModel } from "@effect/ai"
40
+ * import type { Layer } from "effect"
41
+ * import { Effect, ExecutionPlan, Schedule } from "effect"
42
+ *
43
+ * declare const layerBad: Layer.Layer<AiLanguageModel.AiLanguageModel>
44
+ * declare const layerGood: Layer.Layer<AiLanguageModel.AiLanguageModel>
45
+ *
46
+ * const ThePlan = ExecutionPlan.make(
47
+ * {
48
+ * // First try with the bad layer 2 times with a 3 second delay between attempts
49
+ * provide: layerBad,
50
+ * attempts: 2,
51
+ * schedule: Schedule.spaced(3000)
52
+ * },
53
+ * // Then try with the bad layer 3 times with a 1 second delay between attempts
54
+ * {
55
+ * provide: layerBad,
56
+ * attempts: 3,
57
+ * schedule: Schedule.spaced(1000)
58
+ * },
59
+ * // Finally try with the good layer.
60
+ * //
61
+ * // If `attempts` is omitted, the plan will only attempt once, unless a schedule is provided.
62
+ * {
63
+ * provide: layerGood
64
+ * }
65
+ * )
66
+ *
67
+ * declare const effect: Effect.Effect<
68
+ * void,
69
+ * never,
70
+ * AiLanguageModel.AiLanguageModel
71
+ * >
72
+ * const withPlan: Effect.Effect<void> = Effect.withExecutionPlan(effect, ThePlan)
73
+ * ```
74
+ *
75
+ * @since 3.16.0
76
+ * @category Models
77
+ * @experimental
78
+ */
79
+ export interface ExecutionPlan<
80
+ Types extends {
81
+ provides: any
82
+ input: any
83
+ error: any
84
+ requirements: any
85
+ }
86
+ > extends Pipeable {
87
+ readonly [TypeId]: TypeId
88
+ readonly steps: NonEmptyReadonlyArray<{
89
+ readonly provide:
90
+ | Context.Context<Types["provides"]>
91
+ | Layer.Layer<Types["provides"], Types["error"], Types["requirements"]>
92
+ readonly attempts?: number | undefined
93
+ readonly while?:
94
+ | ((input: Types["input"]) => Effect.Effect<boolean, Types["error"], Types["requirements"]>)
95
+ | undefined
96
+ readonly schedule?: Schedule.Schedule<any, Types["input"], Types["requirements"]> | undefined
97
+ }>
98
+
99
+ /**
100
+ * Returns an equivalent `ExecutionPlan` with the requirements satisfied,
101
+ * using the current context.
102
+ */
103
+ readonly withRequirements: Effect.Effect<
104
+ ExecutionPlan<{
105
+ provides: Types["provides"]
106
+ input: Types["input"]
107
+ error: Types["error"]
108
+ requirements: never
109
+ }>,
110
+ never,
111
+ Types["requirements"]
112
+ >
113
+ }
114
+
115
+ /**
116
+ * @since 3.16.0
117
+ * @experimental
118
+ */
119
+ export type TypesBase = {
120
+ provides: any
121
+ input: any
122
+ error: any
123
+ requirements: any
124
+ }
125
+
126
+ /**
127
+ * Create an `ExecutionPlan`, which can be used with `Effect.withExecutionPlan` or `Stream.withExecutionPlan`, allowing you to provide different resources for each step of execution until the effect succeeds or the plan is exhausted.
128
+ *
129
+ * ```ts
130
+ * import { type AiLanguageModel } from "@effect/ai"
131
+ * import type { Layer } from "effect"
132
+ * import { Effect, ExecutionPlan, Schedule } from "effect"
133
+ *
134
+ * declare const layerBad: Layer.Layer<AiLanguageModel.AiLanguageModel>
135
+ * declare const layerGood: Layer.Layer<AiLanguageModel.AiLanguageModel>
136
+ *
137
+ * const ThePlan = ExecutionPlan.make(
138
+ * {
139
+ * // First try with the bad layer 2 times with a 3 second delay between attempts
140
+ * provide: layerBad,
141
+ * attempts: 2,
142
+ * schedule: Schedule.spaced(3000)
143
+ * },
144
+ * // Then try with the bad layer 3 times with a 1 second delay between attempts
145
+ * {
146
+ * provide: layerBad,
147
+ * attempts: 3,
148
+ * schedule: Schedule.spaced(1000)
149
+ * },
150
+ * // Finally try with the good layer.
151
+ * //
152
+ * // If `attempts` is omitted, the plan will only attempt once, unless a schedule is provided.
153
+ * {
154
+ * provide: layerGood
155
+ * }
156
+ * )
157
+ *
158
+ * declare const effect: Effect.Effect<
159
+ * void,
160
+ * never,
161
+ * AiLanguageModel.AiLanguageModel
162
+ * >
163
+ * const withPlan: Effect.Effect<void> = Effect.withExecutionPlan(effect, ThePlan)
164
+ * ```
165
+ *
166
+ * @since 3.16.0
167
+ * @category Constructors
168
+ * @experimental
169
+ */
170
+ export const make = <const Steps extends NonEmptyReadonlyArray<make.Step>>(
171
+ ...steps: Steps & { [K in keyof Steps]: make.Step }
172
+ ): ExecutionPlan<{
173
+ provides: make.StepProvides<Steps[number]>
174
+ input: make.StepInput<Steps>
175
+ error: make.StepError<Steps[number]>
176
+ requirements: make.StepRequirements<Steps[number]>
177
+ }> =>
178
+ makeProto(steps.map((options, i) => {
179
+ if (options.attempts && options.attempts < 1) {
180
+ throw new Error(`ExecutionPlan.make: step[${i}].attempts must be greater than 0`)
181
+ }
182
+ return {
183
+ schedule: options.schedule,
184
+ attempts: options.attempts,
185
+ while: options.while
186
+ ? (input: any) =>
187
+ Effect.suspend(() => {
188
+ const result = options.while!(input)
189
+ return typeof result === "boolean" ? Effect.succeed(result) : result
190
+ })
191
+ : undefined,
192
+ provide: options.provide
193
+ }
194
+ }) as any)
195
+
196
+ /**
197
+ * @since 3.16.0
198
+ * @experimental
199
+ */
200
+ export declare namespace make {
201
+ /**
202
+ * @since 3.16.0
203
+ * @experimental
204
+ */
205
+ export type Step = {
206
+ readonly provide: Context.Context<any> | Context.Context<never> | Layer.Layer.Any
207
+ readonly attempts?: number | undefined
208
+ readonly while?: ((input: any) => boolean | Effect.Effect<boolean, any, any>) | undefined
209
+ readonly schedule?: Schedule.Schedule<any, any, any> | undefined
210
+ }
211
+
212
+ /**
213
+ * @since 3.16.0
214
+ * @experimental
215
+ */
216
+ export type StepProvides<S extends Step> = S["provide"] extends
217
+ Context.Context<infer P> | Layer.Layer<infer P, infer _E, infer _R> ? P : never
218
+
219
+ /**
220
+ * @since 3.16.0
221
+ * @experimental
222
+ */
223
+ export type StepInput<Steps extends ReadonlyArray<any>, Out = unknown> = Steps extends
224
+ readonly [infer Step, ...infer Rest] ? StepInput<
225
+ Rest,
226
+ & Out
227
+ & (
228
+ & (Step extends { readonly while: (input: infer I) => infer _ } ? I : unknown)
229
+ & (Step extends { readonly schedule: Schedule.Schedule<infer _O, infer I, infer _R> } ? I : unknown)
230
+ )
231
+ > :
232
+ Out
233
+
234
+ /**
235
+ * @since 3.16.0
236
+ * @experimental
237
+ */
238
+ export type PlanInput<Plans extends ReadonlyArray<any>, Out = unknown> = Plans extends
239
+ readonly [infer Plan, ...infer Rest] ?
240
+ PlanInput<Rest, Out & (Plan extends ExecutionPlan<infer T> ? T["input"] : never)> :
241
+ Out
242
+
243
+ /**
244
+ * @since 3.16.0
245
+ * @experimental
246
+ */
247
+ export type StepError<S extends Step> =
248
+ | (S["provide"] extends Context.Context<infer _P> | Layer.Layer<infer _P, infer E, infer _R> ? E : never)
249
+ | (S["while"] extends (input: infer _I) => Effect.Effect<infer _A, infer _E, infer _R> ? _E : never)
250
+
251
+ /**
252
+ * @since 3.16.0
253
+ * @experimental
254
+ */
255
+ export type StepRequirements<S extends Step> =
256
+ | (S["provide"] extends Layer.Layer<infer _A, infer _E, infer R> ? R : never)
257
+ | (S["while"] extends (input: infer _I) => Effect.Effect<infer _A, infer _E, infer R> ? R : never)
258
+ | (S["schedule"] extends Schedule.Schedule<infer _O, infer _I, infer R> ? R : never)
259
+ }
260
+
261
+ const Proto: Omit<ExecutionPlan<any>, "steps"> = {
262
+ [TypeId]: TypeId,
263
+ get withRequirements() {
264
+ const self = this as any as ExecutionPlan<any>
265
+ return Effect.contextWith((context: Context.Context<any>) =>
266
+ makeProto(self.steps.map((step) => ({
267
+ ...step,
268
+ provide: Layer.isLayer(step.provide) ? Layer.provide(step.provide, Layer.succeedContext(context)) : step.provide
269
+ })) as any)
270
+ )
271
+ },
272
+ pipe() {
273
+ return pipeArguments(this, arguments)
274
+ }
275
+ }
276
+
277
+ const makeProto = <Provides, In, PlanE, PlanR>(
278
+ steps: ExecutionPlan<{
279
+ provides: Provides
280
+ input: In
281
+ error: PlanE
282
+ requirements: PlanR
283
+ }>["steps"]
284
+ ) => {
285
+ const self = Object.create(Proto)
286
+ self.steps = steps
287
+ return self
288
+ }
289
+
290
+ /**
291
+ * @since 3.16.0
292
+ * @category Combining
293
+ * @experimental
294
+ */
295
+ export const merge = <const Plans extends NonEmptyReadonlyArray<ExecutionPlan<any>>>(
296
+ ...plans: Plans
297
+ ): ExecutionPlan<{
298
+ provides: Plans[number] extends ExecutionPlan<infer T> ? T["provides"] : never
299
+ input: make.PlanInput<Plans>
300
+ error: Plans[number] extends ExecutionPlan<infer T> ? T["error"] : never
301
+ requirements: Plans[number] extends ExecutionPlan<infer T> ? T["requirements"] : never
302
+ }> => makeProto(plans.flatMap((plan) => plan.steps) as any)
package/src/HashMap.ts CHANGED
@@ -268,6 +268,62 @@ export const hasHash: {
268
268
  <K1 extends K, K, V>(self: HashMap<K, V>, key: K1, hash: number): boolean
269
269
  } = HM.hasHash
270
270
 
271
+ /**
272
+ * Checks if an element matching the given predicate exists in the given `HashMap`.
273
+ *
274
+ * @example
275
+ * ```ts
276
+ * import { HashMap } from "effect"
277
+ *
278
+ * const hm = HashMap.make([1, 'a'])
279
+ * HashMap.hasBy(hm, (value, key) => value === 'a' && key === 1); // -> true
280
+ * HashMap.hasBy(hm, (value) => value === 'b'); // -> false
281
+ *
282
+ * ```
283
+ *
284
+ * @since 3.16.0
285
+ * @category elements
286
+ */
287
+ export const hasBy: {
288
+ /**
289
+ * Checks if an element matching the given predicate exists in the given `HashMap`.
290
+ *
291
+ * @example
292
+ * ```ts
293
+ * import { HashMap } from "effect"
294
+ *
295
+ * const hm = HashMap.make([1, 'a'])
296
+ * HashMap.hasBy(hm, (value, key) => value === 'a' && key === 1); // -> true
297
+ * HashMap.hasBy(hm, (value) => value === 'b'); // -> false
298
+ *
299
+ * ```
300
+ *
301
+ * @since 3.16.0
302
+ * @category elements
303
+ */
304
+ <K, V>(predicate: (value: NoInfer<V>, key: NoInfer<K>) => boolean): (self: HashMap<K, V>) => boolean
305
+ /**
306
+ * Checks if an element matching the given predicate exists in the given `HashMap`.
307
+ *
308
+ * @example
309
+ * ```ts
310
+ * import { HashMap } from "effect"
311
+ *
312
+ * const hm = HashMap.make([1, 'a'])
313
+ * HashMap.hasBy(hm, (value, key) => value === 'a' && key === 1); // -> true
314
+ * HashMap.hasBy(hm, (value) => value === 'b'); // -> false
315
+ *
316
+ * ```
317
+ *
318
+ * @since 3.16.0
319
+ * @category elements
320
+ */
321
+ <K, V>(
322
+ self: HashMap<K, V>,
323
+ predicate: (value: NoInfer<V>, key: NoInfer<K>) => boolean
324
+ ): boolean
325
+ } = HM.hasBy
326
+
271
327
  /**
272
328
  * Sets the specified key to the specified value using the internal hashing
273
329
  * function.
package/src/Iterable.ts CHANGED
@@ -1538,3 +1538,69 @@ export const cartesian: {
1538
1538
  2,
1539
1539
  <A, B>(self: Iterable<A>, that: Iterable<B>): Iterable<[A, B]> => cartesianWith(self, that, (a, b) => [a, b])
1540
1540
  )
1541
+
1542
+ /**
1543
+ * Counts all the element of the given iterable that pass the given predicate
1544
+ *
1545
+ * **Example**
1546
+ *
1547
+ * ```ts
1548
+ * import { Iterable } from "effect"
1549
+ *
1550
+ * const result = Iterable.countBy([1, 2, 3, 4, 5], n => n % 2 === 0)
1551
+ * console.log(result) // 2
1552
+ * ```
1553
+ *
1554
+ * @category folding
1555
+ * @since 3.16.0
1556
+ */
1557
+ export const countBy: {
1558
+ /**
1559
+ * Counts all the element of the given iterable that pass the given predicate
1560
+ *
1561
+ * **Example**
1562
+ *
1563
+ * ```ts
1564
+ * import { Iterable } from "effect"
1565
+ *
1566
+ * const result = Iterable.countBy([1, 2, 3, 4, 5], n => n % 2 === 0)
1567
+ * console.log(result) // 2
1568
+ * ```
1569
+ *
1570
+ * @category folding
1571
+ * @since 3.16.0
1572
+ */
1573
+ <A>(predicate: (a: NoInfer<A>, i: number) => boolean): (self: Iterable<A>) => number
1574
+ /**
1575
+ * Counts all the element of the given iterable that pass the given predicate
1576
+ *
1577
+ * **Example**
1578
+ *
1579
+ * ```ts
1580
+ * import { Iterable } from "effect"
1581
+ *
1582
+ * const result = Iterable.countBy([1, 2, 3, 4, 5], n => n % 2 === 0)
1583
+ * console.log(result) // 2
1584
+ * ```
1585
+ *
1586
+ * @category folding
1587
+ * @since 3.16.0
1588
+ */
1589
+ <A>(self: Iterable<A>, predicate: (a: A, i: number) => boolean): number
1590
+ } = dual(
1591
+ 2,
1592
+ <A>(
1593
+ self: Iterable<A>,
1594
+ f: (a: A, i: number) => boolean
1595
+ ): number => {
1596
+ let count = 0
1597
+ let i = 0
1598
+ for (const a of self) {
1599
+ if (f(a, i)) {
1600
+ count++
1601
+ }
1602
+ i++
1603
+ }
1604
+ return count
1605
+ }
1606
+ )