signalium 0.2.8 → 0.3.1

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 (161) hide show
  1. package/.turbo/turbo-build.log +12 -0
  2. package/CHANGELOG.md +12 -0
  3. package/dist/cjs/config.d.ts +14 -5
  4. package/dist/cjs/config.d.ts.map +1 -1
  5. package/dist/cjs/config.js +23 -14
  6. package/dist/cjs/config.js.map +1 -1
  7. package/dist/cjs/debug.d.ts +3 -0
  8. package/dist/cjs/debug.d.ts.map +1 -0
  9. package/dist/cjs/debug.js +16 -0
  10. package/dist/cjs/debug.js.map +1 -0
  11. package/dist/cjs/hooks.d.ts +45 -0
  12. package/dist/cjs/hooks.d.ts.map +1 -0
  13. package/dist/cjs/hooks.js +263 -0
  14. package/dist/cjs/hooks.js.map +1 -0
  15. package/dist/cjs/index.d.ts +5 -3
  16. package/dist/cjs/index.d.ts.map +1 -1
  17. package/dist/cjs/index.js +21 -8
  18. package/dist/cjs/index.js.map +1 -1
  19. package/dist/cjs/react/context.d.ts +4 -0
  20. package/dist/cjs/react/context.d.ts.map +1 -0
  21. package/dist/cjs/react/context.js +10 -0
  22. package/dist/cjs/react/context.js.map +1 -0
  23. package/dist/cjs/react/index.d.ts +5 -0
  24. package/dist/cjs/react/index.d.ts.map +1 -0
  25. package/dist/cjs/react/index.js +12 -0
  26. package/dist/cjs/react/index.js.map +1 -0
  27. package/dist/cjs/react/provider.d.ts +7 -0
  28. package/dist/cjs/react/provider.d.ts.map +1 -0
  29. package/dist/cjs/react/provider.js +13 -0
  30. package/dist/cjs/react/provider.js.map +1 -0
  31. package/dist/cjs/react/setup.d.ts +2 -0
  32. package/dist/cjs/react/setup.d.ts.map +1 -0
  33. package/dist/cjs/react/setup.js +13 -0
  34. package/dist/cjs/react/setup.js.map +1 -0
  35. package/dist/cjs/react/signal-value.d.ts +2 -0
  36. package/dist/cjs/react/signal-value.d.ts.map +1 -0
  37. package/dist/cjs/react/signal-value.js +35 -0
  38. package/dist/cjs/react/signal-value.js.map +1 -0
  39. package/dist/cjs/react/state.d.ts +3 -0
  40. package/dist/cjs/react/state.d.ts.map +1 -0
  41. package/dist/cjs/react/state.js +13 -0
  42. package/dist/cjs/react/state.js.map +1 -0
  43. package/dist/cjs/scheduling.d.ts +5 -0
  44. package/dist/cjs/scheduling.d.ts.map +1 -1
  45. package/dist/cjs/scheduling.js +59 -5
  46. package/dist/cjs/scheduling.js.map +1 -1
  47. package/dist/cjs/signals.d.ts +28 -68
  48. package/dist/cjs/signals.d.ts.map +1 -1
  49. package/dist/cjs/signals.js +223 -76
  50. package/dist/cjs/signals.js.map +1 -1
  51. package/dist/cjs/trace.d.ts +127 -0
  52. package/dist/cjs/trace.d.ts.map +1 -0
  53. package/dist/cjs/trace.js +319 -0
  54. package/dist/cjs/trace.js.map +1 -0
  55. package/dist/cjs/types.d.ts +66 -0
  56. package/dist/cjs/types.d.ts.map +1 -0
  57. package/dist/cjs/types.js +3 -0
  58. package/dist/cjs/types.js.map +1 -0
  59. package/dist/cjs/utils.d.ts +4 -0
  60. package/dist/cjs/utils.d.ts.map +1 -0
  61. package/dist/cjs/utils.js +80 -0
  62. package/dist/cjs/utils.js.map +1 -0
  63. package/dist/esm/config.d.ts +14 -5
  64. package/dist/esm/config.d.ts.map +1 -1
  65. package/dist/esm/config.js +19 -11
  66. package/dist/esm/config.js.map +1 -1
  67. package/dist/esm/debug.d.ts +3 -0
  68. package/dist/esm/debug.d.ts.map +1 -0
  69. package/dist/esm/debug.js +3 -0
  70. package/dist/esm/debug.js.map +1 -0
  71. package/dist/esm/hooks.d.ts +45 -0
  72. package/dist/esm/hooks.d.ts.map +1 -0
  73. package/dist/esm/hooks.js +246 -0
  74. package/dist/esm/hooks.js.map +1 -0
  75. package/dist/esm/index.d.ts +5 -3
  76. package/dist/esm/index.d.ts.map +1 -1
  77. package/dist/esm/index.js +4 -2
  78. package/dist/esm/index.js.map +1 -1
  79. package/dist/esm/react/context.d.ts +4 -0
  80. package/dist/esm/react/context.d.ts.map +1 -0
  81. package/dist/esm/react/context.js +6 -0
  82. package/dist/esm/react/context.js.map +1 -0
  83. package/dist/esm/react/index.d.ts +5 -0
  84. package/dist/esm/react/index.d.ts.map +1 -0
  85. package/dist/esm/react/index.js +5 -0
  86. package/dist/esm/react/index.js.map +1 -0
  87. package/dist/esm/react/provider.d.ts +7 -0
  88. package/dist/esm/react/provider.d.ts.map +1 -0
  89. package/dist/esm/react/provider.js +10 -0
  90. package/dist/esm/react/provider.js.map +1 -0
  91. package/dist/esm/react/setup.d.ts +2 -0
  92. package/dist/esm/react/setup.d.ts.map +1 -0
  93. package/dist/esm/react/setup.js +10 -0
  94. package/dist/esm/react/setup.js.map +1 -0
  95. package/dist/esm/react/signal-value.d.ts +2 -0
  96. package/dist/esm/react/signal-value.d.ts.map +1 -0
  97. package/dist/esm/react/signal-value.js +32 -0
  98. package/dist/esm/react/signal-value.js.map +1 -0
  99. package/dist/esm/react/state.d.ts +3 -0
  100. package/dist/esm/react/state.d.ts.map +1 -0
  101. package/dist/esm/react/state.js +10 -0
  102. package/dist/esm/react/state.js.map +1 -0
  103. package/dist/esm/scheduling.d.ts +5 -0
  104. package/dist/esm/scheduling.d.ts.map +1 -1
  105. package/dist/esm/scheduling.js +51 -1
  106. package/dist/esm/scheduling.js.map +1 -1
  107. package/dist/esm/signals.d.ts +28 -68
  108. package/dist/esm/signals.d.ts.map +1 -1
  109. package/dist/esm/signals.js +215 -72
  110. package/dist/esm/signals.js.map +1 -1
  111. package/dist/esm/trace.d.ts +127 -0
  112. package/dist/esm/trace.d.ts.map +1 -0
  113. package/dist/esm/trace.js +311 -0
  114. package/dist/esm/trace.js.map +1 -0
  115. package/dist/esm/types.d.ts +66 -0
  116. package/dist/esm/types.d.ts.map +1 -0
  117. package/dist/esm/types.js +2 -0
  118. package/dist/esm/types.js.map +1 -0
  119. package/dist/esm/utils.d.ts +4 -0
  120. package/dist/esm/utils.d.ts.map +1 -0
  121. package/dist/esm/utils.js +75 -0
  122. package/dist/esm/utils.js.map +1 -0
  123. package/package.json +43 -2
  124. package/src/__tests__/hooks/async-computed.test.ts +190 -0
  125. package/src/__tests__/hooks/async-task.test.ts +227 -0
  126. package/src/__tests__/hooks/computed.test.ts +126 -0
  127. package/src/__tests__/hooks/context.test.ts +527 -0
  128. package/src/__tests__/hooks/nesting.test.ts +303 -0
  129. package/src/__tests__/hooks/params-and-state.test.ts +168 -0
  130. package/src/__tests__/hooks/subscription.test.ts +97 -0
  131. package/src/__tests__/signals/async.test.ts +416 -0
  132. package/src/__tests__/signals/basic.test.ts +399 -0
  133. package/src/__tests__/signals/subscription.test.ts +632 -0
  134. package/src/__tests__/signals/watcher.test.ts +253 -0
  135. package/src/__tests__/utils/async.ts +6 -0
  136. package/src/__tests__/utils/builders.ts +22 -0
  137. package/src/__tests__/utils/instrumented-hooks.ts +309 -0
  138. package/src/__tests__/utils/instrumented-signals.ts +281 -0
  139. package/src/__tests__/utils/permute.ts +74 -0
  140. package/src/config.ts +32 -17
  141. package/src/debug.ts +14 -0
  142. package/src/hooks.ts +433 -0
  143. package/src/index.ts +28 -3
  144. package/src/react/__tests__/react.test.tsx +227 -0
  145. package/src/react/context.ts +8 -0
  146. package/src/react/index.ts +4 -0
  147. package/src/react/provider.tsx +18 -0
  148. package/src/react/setup.ts +10 -0
  149. package/src/react/signal-value.ts +49 -0
  150. package/src/react/state.ts +13 -0
  151. package/src/scheduling.ts +69 -1
  152. package/src/signals.ts +328 -169
  153. package/src/trace.ts +449 -0
  154. package/src/types.ts +86 -0
  155. package/src/utils.ts +83 -0
  156. package/tsconfig.json +2 -1
  157. package/vitest.workspace.ts +24 -0
  158. package/src/__tests__/async.test.ts +0 -426
  159. package/src/__tests__/basic.test.ts +0 -378
  160. package/src/__tests__/subscription.test.ts +0 -645
  161. package/src/__tests__/utils/instrumented.ts +0 -326
@@ -0,0 +1,399 @@
1
+ import { describe, expect, test } from 'vitest';
2
+ import { createStateSignal, createComputedSignal } from '../utils/instrumented-signals.js';
3
+
4
+ describe('Basic Signal functionality', () => {
5
+ test('Can run basic computed', () => {
6
+ const a = createStateSignal(1);
7
+ const b = createStateSignal(2);
8
+
9
+ const c = createComputedSignal(() => {
10
+ return a.get() + b.get();
11
+ });
12
+
13
+ expect(c).toHaveSignalValueAndCounts(3, { compute: 1, get: 1 });
14
+
15
+ // stability
16
+ expect(c).toHaveSignalValueAndCounts(3, { compute: 1, get: 2 });
17
+ });
18
+
19
+ test('Computeds can be updated', () => {
20
+ const a = createStateSignal(1);
21
+ const b = createStateSignal(2);
22
+
23
+ const c = createComputedSignal(() => {
24
+ return a.get() + b.get();
25
+ });
26
+
27
+ expect(c).toHaveSignalValueAndCounts(3, { compute: 1, get: 1 });
28
+
29
+ a.set(2);
30
+
31
+ expect(c).toHaveSignalValueAndCounts(4, { compute: 2, get: 2 });
32
+ });
33
+
34
+ test('Does not update if value is the same', () => {
35
+ const a = createStateSignal(1);
36
+ const b = createStateSignal(2);
37
+
38
+ const c = createComputedSignal(() => {
39
+ return a.get() + b.get();
40
+ });
41
+
42
+ expect(c).toHaveSignalValueAndCounts(3, { compute: 1, get: 1 });
43
+
44
+ a.set(1);
45
+
46
+ expect(c).toHaveSignalValueAndCounts(3, { compute: 1, get: 2 });
47
+ });
48
+
49
+ describe('Nesting', () => {
50
+ test('Can nest computeds', () => {
51
+ const a = createStateSignal(1);
52
+ const b = createStateSignal(2);
53
+ const c = createStateSignal(2);
54
+
55
+ const inner = createComputedSignal(() => {
56
+ return a.get() + b.get();
57
+ });
58
+
59
+ const outer = createComputedSignal(() => {
60
+ return inner.get() + c.get();
61
+ });
62
+
63
+ expect(inner).toHaveSignalValueAndCounts(3, { compute: 1, get: 1 });
64
+ expect(outer).toHaveSignalValueAndCounts(5, { compute: 1, get: 1 });
65
+
66
+ // stability
67
+ expect(inner).toHaveSignalValueAndCounts(3, { compute: 1, get: 3 });
68
+ expect(outer).toHaveSignalValueAndCounts(5, { compute: 1, get: 2 });
69
+ });
70
+
71
+ test('Can dirty inner computed and update parent', () => {
72
+ const a = createStateSignal(1);
73
+ const b = createStateSignal(2);
74
+ const c = createStateSignal(2);
75
+
76
+ const inner = createComputedSignal(() => {
77
+ return a.get() + b.get();
78
+ });
79
+
80
+ const outer = createComputedSignal(() => {
81
+ return inner.get() + c.get();
82
+ });
83
+
84
+ expect(inner).toHaveSignalValueAndCounts(3, { compute: 1, get: 1 });
85
+ expect(outer).toHaveSignalValueAndCounts(5, { compute: 1, get: 1 });
86
+
87
+ a.set(2);
88
+
89
+ expect(inner).toHaveSignalValueAndCounts(4, { compute: 2, get: 3 });
90
+ expect(outer).toHaveSignalValueAndCounts(6, { compute: 2, get: 2 });
91
+ });
92
+
93
+ test('Can dirty outer computed and inner stays cached', () => {
94
+ const a = createStateSignal(1);
95
+ const b = createStateSignal(2);
96
+ const c = createStateSignal(2);
97
+
98
+ const inner = createComputedSignal(() => {
99
+ return a.get() + b.get();
100
+ });
101
+
102
+ const outer = createComputedSignal(() => {
103
+ return inner.get() + c.get();
104
+ });
105
+
106
+ expect(inner).toHaveSignalValueAndCounts(3, { compute: 1, get: 1 });
107
+ expect(outer).toHaveSignalValueAndCounts(5, { compute: 1, get: 1 });
108
+
109
+ c.set(3);
110
+
111
+ expect(inner).toHaveSignalValueAndCounts(3, { compute: 1, get: 3 });
112
+ expect(outer).toHaveSignalValueAndCounts(6, { compute: 2, get: 2 });
113
+ });
114
+
115
+ test('Can nest multiple levels', () => {
116
+ const a = createStateSignal(1);
117
+ const b = createStateSignal(2);
118
+ const c = createStateSignal(2);
119
+ const d = createStateSignal(2);
120
+
121
+ const inner = createComputedSignal(() => {
122
+ return a.get() + b.get();
123
+ });
124
+
125
+ const mid = createComputedSignal(() => {
126
+ return inner.get() + c.get();
127
+ });
128
+
129
+ const outer = createComputedSignal(() => {
130
+ return mid.get() + d.get();
131
+ });
132
+
133
+ expect(inner).toHaveSignalValueAndCounts(3, { compute: 1 });
134
+ expect(mid).toHaveSignalValueAndCounts(5, { compute: 1 });
135
+ expect(outer).toHaveSignalValueAndCounts(7, { compute: 1 });
136
+
137
+ a.set(2);
138
+
139
+ expect(inner).toHaveSignalValueAndCounts(4, { compute: 2 });
140
+ expect(mid).toHaveSignalValueAndCounts(6, { compute: 2 });
141
+ expect(outer).toHaveSignalValueAndCounts(8, { compute: 2 });
142
+
143
+ c.set(3);
144
+
145
+ expect(inner).toHaveSignalValueAndCounts(4, { compute: 2 });
146
+ expect(mid).toHaveSignalValueAndCounts(7, { compute: 3 });
147
+ expect(outer).toHaveSignalValueAndCounts(9, { compute: 3 });
148
+
149
+ d.set(3);
150
+
151
+ expect(inner).toHaveSignalValueAndCounts(4, { compute: 2 });
152
+ expect(mid).toHaveSignalValueAndCounts(7, { compute: 3 });
153
+ expect(outer).toHaveSignalValueAndCounts(10, { compute: 4 });
154
+ });
155
+ });
156
+
157
+ describe('Propagation', () => {
158
+ test('it works with multiple parents', () => {
159
+ const a = createStateSignal(1);
160
+ const b = createStateSignal(2);
161
+ const c = createStateSignal(2);
162
+ const d = createStateSignal(2);
163
+
164
+ const inner = createComputedSignal(() => {
165
+ return a.get() + b.get();
166
+ });
167
+
168
+ const outer1 = createComputedSignal(() => {
169
+ return inner.get() + c.get();
170
+ });
171
+
172
+ const outer2 = createComputedSignal(() => {
173
+ return inner.get() + d.get();
174
+ });
175
+
176
+ expect(inner).toHaveSignalValueAndCounts(3, { compute: 1 });
177
+ expect(outer1).toHaveSignalValueAndCounts(5, { compute: 1 });
178
+ expect(outer2).toHaveSignalValueAndCounts(5, { compute: 1 });
179
+
180
+ a.set(2);
181
+
182
+ expect(inner).toHaveSignalValueAndCounts(4, { compute: 2 });
183
+ expect(outer1).toHaveSignalValueAndCounts(6, { compute: 2 });
184
+ expect(outer2).toHaveSignalValueAndCounts(6, { compute: 2 });
185
+
186
+ b.set(3);
187
+
188
+ expect(inner).toHaveSignalValueAndCounts(5, { compute: 3 });
189
+ expect(outer2).toHaveSignalValueAndCounts(7, { compute: 3 });
190
+ expect(outer1).toHaveSignalValueAndCounts(7, { compute: 3 });
191
+
192
+ c.set(3);
193
+
194
+ expect(inner).toHaveSignalValueAndCounts(5, { compute: 3 });
195
+ expect(outer1).toHaveSignalValueAndCounts(8, { compute: 4 });
196
+ expect(outer2).toHaveSignalValueAndCounts(7, { compute: 3 });
197
+
198
+ d.set(3);
199
+
200
+ expect(inner).toHaveSignalValueAndCounts(5, { compute: 3 });
201
+ expect(outer1).toHaveSignalValueAndCounts(8, { compute: 4 });
202
+ expect(outer2).toHaveSignalValueAndCounts(8, { compute: 4 });
203
+ });
204
+
205
+ test('it stops propagation if the result is the same', () => {
206
+ const a = createStateSignal(1);
207
+ const b = createStateSignal(2);
208
+ const c = createStateSignal(2);
209
+ const d = createStateSignal(2);
210
+
211
+ const inner = createComputedSignal(
212
+ () => {
213
+ return a.get() + b.get();
214
+ },
215
+ { desc: 'inner' },
216
+ );
217
+
218
+ const outer1 = createComputedSignal(
219
+ () => {
220
+ return inner.get() + c.get();
221
+ },
222
+ { desc: 'outer1' },
223
+ );
224
+
225
+ const outer2 = createComputedSignal(
226
+ () => {
227
+ return inner.get() + d.get();
228
+ },
229
+ { desc: 'outer2' },
230
+ );
231
+
232
+ expect(() => {
233
+ expect(outer1).toHaveSignalValueAndCounts(5, { compute: 1 });
234
+ expect(outer2).toHaveSignalValueAndCounts(5, { compute: 1 });
235
+ expect(inner).toHaveSignalValueAndCounts(3, { compute: 1 });
236
+ }).toHaveComputedOrder(['outer1', 'inner', 'outer2']);
237
+
238
+ a.set(2);
239
+ b.set(1);
240
+
241
+ expect(() => {
242
+ expect(outer1).toHaveSignalValueAndCounts(5, { compute: 1 });
243
+ expect(outer2).toHaveSignalValueAndCounts(5, { compute: 1 });
244
+ expect(inner).toHaveSignalValueAndCounts(3, { compute: 2 });
245
+ }).toHaveComputedOrder(['inner']);
246
+
247
+ b.set(2);
248
+
249
+ expect(() => {
250
+ expect(outer2).toHaveSignalValueAndCounts(6, { compute: 2 });
251
+ expect(outer1).toHaveSignalValueAndCounts(6, { compute: 2 });
252
+ expect(inner).toHaveSignalValueAndCounts(4, { compute: 3 });
253
+ }).toHaveComputedOrder(['inner', 'outer2', 'outer1']);
254
+ });
255
+
256
+ test('it continues propagation if any child is different', () => {
257
+ const a = createStateSignal(1);
258
+ const b = createStateSignal(2);
259
+ const c = createStateSignal(2);
260
+ const d = createStateSignal(2);
261
+
262
+ const inner1 = createComputedSignal(
263
+ () => {
264
+ return a.get() + b.get();
265
+ },
266
+ { desc: 'inner1' },
267
+ );
268
+
269
+ const inner2 = createComputedSignal(
270
+ () => {
271
+ return c.get();
272
+ },
273
+ { desc: 'inner2' },
274
+ );
275
+
276
+ const inner3 = createComputedSignal(
277
+ () => {
278
+ return d.get();
279
+ },
280
+ { desc: 'inner3' },
281
+ );
282
+
283
+ const outer = createComputedSignal(
284
+ () => {
285
+ return inner1.get() + inner2.get() + inner3.get();
286
+ },
287
+ { desc: 'outer' },
288
+ );
289
+
290
+ expect(() => {
291
+ expect(outer).toHaveSignalValueAndCounts(7, { compute: 1 });
292
+ }).toHaveComputedOrder(['outer', 'inner1', 'inner2', 'inner3']);
293
+
294
+ d.set(4);
295
+ a.set(2);
296
+ c.set(3);
297
+ b.set(1);
298
+
299
+ expect(() => {
300
+ expect(outer).toHaveSignalValueAndCounts(10, { compute: 2 });
301
+ expect(inner1).toHaveSignalCounts({ compute: 2 });
302
+ expect(inner2).toHaveSignalCounts({ compute: 2 });
303
+ }).toHaveComputedOrder(['inner1', 'inner2', 'outer', 'inner3']);
304
+ });
305
+ });
306
+
307
+ describe('Laziness', () => {
308
+ test('it does not compute values that are not used', () => {
309
+ const a = createStateSignal(1);
310
+ const b = createStateSignal(2);
311
+ const c = createStateSignal(2);
312
+ const d = createStateSignal(2);
313
+
314
+ const inner1 = createComputedSignal(() => {
315
+ return a.get() + b.get();
316
+ });
317
+
318
+ const inner2 = createComputedSignal(() => {
319
+ return c.get() + d.get();
320
+ });
321
+
322
+ const outer = createComputedSignal(() => {
323
+ if (inner1.get() <= 3) {
324
+ return inner2.get();
325
+ } else {
326
+ return -1;
327
+ }
328
+ });
329
+
330
+ expect(outer).toHaveSignalValueAndCounts(4, { compute: 1 });
331
+
332
+ a.set(2);
333
+ c.set(3);
334
+
335
+ expect(outer).toHaveSignalValueAndCounts(-1, { compute: 2 });
336
+ expect(inner1).toHaveSignalCounts({ compute: 2 });
337
+ expect(inner2).toHaveSignalCounts({ compute: 1 });
338
+ });
339
+ });
340
+
341
+ describe('Equality', () => {
342
+ test('Does not update if value is the same (custom equality fn)', () => {
343
+ const a = createStateSignal(1);
344
+ const b = createStateSignal(2);
345
+
346
+ const c = createComputedSignal(
347
+ () => {
348
+ return a.get() + b.get();
349
+ },
350
+ {
351
+ equals(prev, next) {
352
+ return Math.abs(prev - next) < 2;
353
+ },
354
+ },
355
+ );
356
+
357
+ expect(c).toHaveSignalValueAndCounts(3, { compute: 1 });
358
+
359
+ a.set(2);
360
+
361
+ expect(c).toHaveSignalValueAndCounts(3, { compute: 2 });
362
+ });
363
+
364
+ test('It stops propagation if the result is the same (custom equality fn)', () => {
365
+ const a = createStateSignal(1);
366
+ const b = createStateSignal(2);
367
+ const c = createStateSignal(2);
368
+ const d = createStateSignal(2);
369
+
370
+ const inner = createComputedSignal(
371
+ () => {
372
+ return a.get() + b.get();
373
+ },
374
+ {
375
+ equals(prev, next) {
376
+ return Math.abs(prev - next) < 2;
377
+ },
378
+ },
379
+ );
380
+
381
+ const outer1 = createComputedSignal(() => {
382
+ return inner.get() + c.get();
383
+ });
384
+
385
+ const outer2 = createComputedSignal(() => {
386
+ return inner.get() + d.get();
387
+ });
388
+
389
+ expect(inner).toHaveSignalValueAndCounts(3, { compute: 1 });
390
+
391
+ a.set(2);
392
+ b.set(2);
393
+
394
+ expect(inner).toHaveSignalValueAndCounts(3, { compute: 2 });
395
+ expect(outer1).toHaveSignalValueAndCounts(5, { compute: 1 });
396
+ expect(outer2).toHaveSignalValueAndCounts(5, { compute: 1 });
397
+ });
398
+ });
399
+ });