nomen-lang 0.0.7 → 0.0.8
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/NOMEN_AGENTS.md +235 -0
- package/core/System/Ansi.nm +150 -0
- package/core/System/Array.nm +358 -0
- package/core/System/BigInt.nm +887 -0
- package/core/System/Buffer.nm +526 -0
- package/core/System/Channel.nm +198 -0
- package/core/System/ClassBuffer.nm +229 -0
- package/core/System/Console.nm +211 -0
- package/core/System/Controls/Button.nm +138 -0
- package/core/System/Controls/CheckBox.nm +158 -0
- package/core/System/Controls/Container.nm +1562 -0
- package/core/System/Controls/Control.nm +28 -0
- package/core/System/Controls/Geometry.nm +101 -0
- package/core/System/Controls/Layout.nm +228 -0
- package/core/System/Controls/LayoutParams.nm +50 -0
- package/core/System/Controls/Text.nm +129 -0
- package/core/System/Controls/TextBox.nm +157 -0
- package/core/System/Controls/Window.nm +280 -0
- package/core/System/Disposable.nm +8 -0
- package/core/System/Enumerable.nm +10 -0
- package/core/System/Equatable.nm +10 -0
- package/core/System/Graph.nm +68 -0
- package/core/System/Hashable.nm +13 -0
- package/core/System/Init.nm +21 -0
- package/core/System/LinkedList.nm +64 -0
- package/core/System/List.nm +44 -0
- package/core/System/Map.nm +153 -0
- package/core/System/Math.nm +54 -0
- package/core/System/Mutex.nm +78 -0
- package/core/System/Nursery.nm +27 -0
- package/core/System/Sendable.nm +9 -0
- package/core/System/Set.nm +97 -0
- package/core/System/Stream/Directory.nm +176 -0
- package/core/System/Stream/File.nm +432 -0
- package/core/System/Stream/Http.nm +453 -0
- package/core/System/String.nm +154 -0
- package/core/System/StringBuilder.nm +249 -0
- package/core/System/Stringable.nm +8 -0
- package/core/System/Task.nm +263 -0
- package/core/System/Test.nm +241 -0
- package/core/System/Text/Json.nm +377 -0
- package/core/System/Text/JsonTree.nm +187 -0
- package/core/System/Text/Regex.nm +655 -0
- package/core/System/Time.nm +112 -0
- package/core/System/Tree.nm +70 -0
- package/core/System/Viewable.nm +27 -0
- package/core/System/bool.nm +66 -0
- package/core/System/char.nm +42 -0
- package/core/System/float.nm +43 -0
- package/core/System/int.nm +54 -0
- package/core/System/int64.nm +42 -0
- package/core/System/int8.nm +42 -0
- package/core/System/uint.nm +42 -0
- package/core/System/uint64.nm +42 -0
- package/core/System/uint8.nm +42 -0
- package/core/docs/System/Ansi.md +40 -0
- package/core/docs/System/Array.md +16 -0
- package/core/docs/System/BigInt.md +30 -0
- package/core/docs/System/Buffer.md +31 -0
- package/core/docs/System/Channel.md +10 -0
- package/core/docs/System/ClassBuffer.md +15 -0
- package/core/docs/System/Console.md +13 -0
- package/core/docs/System/Controls/Button.md +12 -0
- package/core/docs/System/Controls/CheckBox.md +15 -0
- package/core/docs/System/Controls/Container.md +82 -0
- package/core/docs/System/Controls/Control.md +5 -0
- package/core/docs/System/Controls/Geometry.md +26 -0
- package/core/docs/System/Controls/Layout.md +37 -0
- package/core/docs/System/Controls/LayoutParams.md +13 -0
- package/core/docs/System/Controls/Text.md +12 -0
- package/core/docs/System/Controls/TextBox.md +13 -0
- package/core/docs/System/Controls/Window.md +20 -0
- package/core/docs/System/Disposable.md +5 -0
- package/core/docs/System/Enumerable.md +5 -0
- package/core/docs/System/Graph.md +17 -0
- package/core/docs/System/Init.md +9 -0
- package/core/docs/System/LinkedList.md +16 -0
- package/core/docs/System/List.md +13 -0
- package/core/docs/System/Map.md +14 -0
- package/core/docs/System/Math.md +11 -0
- package/core/docs/System/Mutex.md +10 -0
- package/core/docs/System/Nursery.md +5 -0
- package/core/docs/System/Sendable.md +5 -0
- package/core/docs/System/Set.md +14 -0
- package/core/docs/System/Stream/Directory.md +12 -0
- package/core/docs/System/Stream/File.md +21 -0
- package/core/docs/System/String.md +14 -0
- package/core/docs/System/StringBuilder.md +12 -0
- package/core/docs/System/Stringable.md +5 -0
- package/core/docs/System/Task.md +15 -0
- package/core/docs/System/Text/Json.md +12 -0
- package/core/docs/System/Text/JsonTree.md +21 -0
- package/core/docs/System/Text/Regex.md +12 -0
- package/core/docs/System/Time.md +11 -0
- package/core/docs/System/Tree.md +18 -0
- package/core/docs/System/Viewable.md +5 -0
- package/core/docs/System/bool.md +9 -0
- package/core/docs/System/char.md +9 -0
- package/core/docs/System/float.md +9 -0
- package/core/docs/System/int.md +10 -0
- package/core/docs/System/int64.md +9 -0
- package/core/docs/System/int8.md +9 -0
- package/core/docs/System/uint.md +9 -0
- package/core/docs/System/uint64.md +9 -0
- package/core/docs/System/uint8.md +9 -0
- package/core/package.jsonc +4 -0
- package/dist/index.mjs +417 -5490
- package/package.json +33 -30
- package/src/args.ts +171 -0
- package/src/index.ts +53 -104
- package/src/init.ts +128 -0
- package/src/test.ts +6 -2
- package/test/fixtures/build/calc.test +0 -0
- package/test/fixtures/build/calc.test.c +0 -969
- package/test/fixtures/build/main.h +0 -170
- package/test/fixtures/calc.test.nm +0 -32
- package/tsconfig.json +0 -21
- package/vite.config.ts +0 -7
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A fixed-length array of values, created with a literal (`[1, 2, 3]`) and addressable by index
|
|
3
|
+
**/
|
|
4
|
+
pub struct Array<T>: Viewable {
|
|
5
|
+
pub const int length
|
|
6
|
+
|
|
7
|
+
pub func #init = (...T items) {
|
|
8
|
+
```
|
|
9
|
+
#arch: c
|
|
10
|
+
self->length = _items_len;
|
|
11
|
+
T* data = (T*)((char*)self + sizeof(*self));
|
|
12
|
+
for (int i = 0; i < _items_len; i++) data[i] = items[i];
|
|
13
|
+
```
|
|
14
|
+
```
|
|
15
|
+
#arch: aarch64
|
|
16
|
+
// x19 = self (struct pointer), variadic items packed at call site
|
|
17
|
+
// _items_len at [x29, #0], items ptr at [x29, #8]
|
|
18
|
+
|
|
19
|
+
// Store length
|
|
20
|
+
ldr x0, [x29, #0]
|
|
21
|
+
str x0, [x19, #8]
|
|
22
|
+
|
|
23
|
+
// Copy items: memcpy(self + 16, items, len * T_SIZE)
|
|
24
|
+
ldr x2, [x29, #0]
|
|
25
|
+
mov x3, #T_SIZE
|
|
26
|
+
mul x2, x2, x3
|
|
27
|
+
add x0, x19, #16
|
|
28
|
+
ldr x1, [x29, #8]
|
|
29
|
+
bl _memcpy
|
|
30
|
+
```
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
pub func at = (self, int index: index >= 0 && index < self.length, out T) {
|
|
34
|
+
```
|
|
35
|
+
#arch: c
|
|
36
|
+
T* _data = (T*)((char*)self + sizeof(*self));
|
|
37
|
+
return _data[index];
|
|
38
|
+
```
|
|
39
|
+
```
|
|
40
|
+
#arch: aarch64
|
|
41
|
+
// x19 = self (first elem), x1 = index
|
|
42
|
+
mov x2, #T_SIZE
|
|
43
|
+
mul x1, x1, x2
|
|
44
|
+
ldr x0, [x19, x1]
|
|
45
|
+
```
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
pub func first = (self: self.length > 0, out T) {
|
|
49
|
+
```
|
|
50
|
+
#arch: c
|
|
51
|
+
T* _data = (T*)((char*)self + sizeof(*self));
|
|
52
|
+
return _data[0];
|
|
53
|
+
```
|
|
54
|
+
```
|
|
55
|
+
#arch: aarch64
|
|
56
|
+
// x19 = self (first elem)
|
|
57
|
+
ldr x0, [x19]
|
|
58
|
+
```
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
pub func set = (ref self, int index: index >= 0 && index < self.length, T value) {
|
|
62
|
+
```
|
|
63
|
+
#arch: c
|
|
64
|
+
T* _data = (T*)((char*)self + sizeof(*self));
|
|
65
|
+
// T_NEEDS_STRDUP is 1 when T is string: the slot must own a heap copy
|
|
66
|
+
// (free the outgoing string, strdup the incoming one) so auto_free can
|
|
67
|
+
// soundly free every slot at scope exit and reassigning a slot doesn't
|
|
68
|
+
// leak the previous value. 0 for all other T (plain assignment).
|
|
69
|
+
#if T_NEEDS_STRDUP
|
|
70
|
+
free(_data[index]);
|
|
71
|
+
_data[index] = (T)strdup(value);
|
|
72
|
+
#else
|
|
73
|
+
_data[index] = value;
|
|
74
|
+
#endif
|
|
75
|
+
```
|
|
76
|
+
```
|
|
77
|
+
#arch: aarch64
|
|
78
|
+
// x19 = self (first elem), x1 = index, x2 = value
|
|
79
|
+
mov x3, #T_SIZE
|
|
80
|
+
mul x1, x1, x3
|
|
81
|
+
// Only use the 8-byte store when T_SIZE is exactly 8 (int/string/ptr).
|
|
82
|
+
// For smaller types (char/bool/int8/etc.) strb/strh/str w/ would
|
|
83
|
+
// clobber adjacent slots, so fall through to a size-aware store.
|
|
84
|
+
cmp x3, #8
|
|
85
|
+
b.ne .L_set_byte
|
|
86
|
+
str x2, [x19, x1]
|
|
87
|
+
b .L_set_done
|
|
88
|
+
.L_set_byte:
|
|
89
|
+
strb w2, [x19, x1]
|
|
90
|
+
.L_set_done:
|
|
91
|
+
```
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
pub func at_end = (self, out T) {
|
|
95
|
+
```
|
|
96
|
+
#arch: c
|
|
97
|
+
T* _data = (T*)((char*)self + sizeof(*self));
|
|
98
|
+
return _data[self->length - 1];
|
|
99
|
+
```
|
|
100
|
+
```
|
|
101
|
+
#arch: aarch64
|
|
102
|
+
// x19 = self (first elem), length at [x19 - 8]
|
|
103
|
+
ldr x0, [x19, #-8]
|
|
104
|
+
sub x0, x0, #1
|
|
105
|
+
mov x1, #T_SIZE
|
|
106
|
+
mul x0, x0, x1
|
|
107
|
+
ldr x0, [x19, x0]
|
|
108
|
+
```
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// A non-owning (ptr, len) slice [start, end) over self's inline element
|
|
112
|
+
// storage, returned as a `view T`. Borrows from self (may not outlive it,
|
|
113
|
+
// invalidated on reassignment). Element access via view.at / view.length.
|
|
114
|
+
pub func slice = (
|
|
115
|
+
self,
|
|
116
|
+
int start: start >= 0 && start <= self.length,
|
|
117
|
+
int end: end >= start && end <= self.length,
|
|
118
|
+
out view T
|
|
119
|
+
) {
|
|
120
|
+
```
|
|
121
|
+
#arch: c
|
|
122
|
+
nomen_view _r;
|
|
123
|
+
T* _data = (T*)((char*)self + sizeof(*self));
|
|
124
|
+
_r.ptr = (void*)(_data + start);
|
|
125
|
+
_r.len = (long)(end - start);
|
|
126
|
+
return _r;
|
|
127
|
+
```
|
|
128
|
+
```
|
|
129
|
+
#arch: aarch64
|
|
130
|
+
// x19 = self (first elem), x1 = start, x2 = end.
|
|
131
|
+
// Return (ptr, len) in x0/x1.
|
|
132
|
+
mov x3, #T_SIZE
|
|
133
|
+
madd x0, x1, x3, x19
|
|
134
|
+
sub x1, x2, x1
|
|
135
|
+
```
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
pub func with = (T value, int count: count >= 0, out Array<T>: out.length == count) {
|
|
139
|
+
```
|
|
140
|
+
#arch: c
|
|
141
|
+
long _header = 16;
|
|
142
|
+
void* _result = malloc(_header + count * T_SIZE);
|
|
143
|
+
((long*)_result)[1] = count;
|
|
144
|
+
T* _data = (T*)((char*)_result + _header);
|
|
145
|
+
for (long i = 0; i < count; i++) {
|
|
146
|
+
// T_NEEDS_STRDUP is 1 when T is string (a `char*` pointer whose
|
|
147
|
+
// backing bytes must be heap-copied per slot — otherwise all n
|
|
148
|
+
// slots would share one pointer and auto_free would n-free it).
|
|
149
|
+
// For all other T it is 0 and the plain assignment runs.
|
|
150
|
+
#if T_NEEDS_STRDUP
|
|
151
|
+
_data[i] = (T)strdup(value);
|
|
152
|
+
#else
|
|
153
|
+
_data[i] = value;
|
|
154
|
+
#endif
|
|
155
|
+
}
|
|
156
|
+
return _result;
|
|
157
|
+
```
|
|
158
|
+
```
|
|
159
|
+
#arch: aarch64
|
|
160
|
+
// x0 = value, x1 = count
|
|
161
|
+
// Returns x0 = heap-allocated array pointer ([ptr]=length, [ptr+8..]=data).
|
|
162
|
+
// This is a regular static function: the caller receives the pointer in x0,
|
|
163
|
+
// so no sret/x8 buffer is involved.
|
|
164
|
+
stp x19, x20, [sp, #-16]!
|
|
165
|
+
stp x1, x0, [sp, #-16]! // [sp]=count, [sp+8]=value
|
|
166
|
+
|
|
167
|
+
// ptr = malloc(8 + count * T_SIZE)
|
|
168
|
+
mov x2, #T_SIZE
|
|
169
|
+
mul x0, x1, x2
|
|
170
|
+
add x0, x0, #8
|
|
171
|
+
bl _malloc
|
|
172
|
+
mov x19, x0 // x19 = ptr
|
|
173
|
+
|
|
174
|
+
// Store the length prefix and set up the data area.
|
|
175
|
+
ldr x1, [sp] // count
|
|
176
|
+
str x1, [x19] // [ptr] = count
|
|
177
|
+
add x20, x19, #8 // x20 = data area
|
|
178
|
+
|
|
179
|
+
cbz x1, .Larray_with_end
|
|
180
|
+
|
|
181
|
+
ldr x0, [sp, #8] // value
|
|
182
|
+
mov x2, #0 // i = 0
|
|
183
|
+
.Larray_with_loop:
|
|
184
|
+
mov x3, #T_SIZE
|
|
185
|
+
mul x4, x2, x3 // offset = i * T_SIZE
|
|
186
|
+
add x5, x20, x4 // addr = data + offset
|
|
187
|
+
|
|
188
|
+
// Store the value (in x0) into [x5] using a width that matches
|
|
189
|
+
// T_SIZE. For T_SIZE <= 8 the value is in x0 directly (char/int/
|
|
190
|
+
// pointer); for T_SIZE > 8 (struct) x0 is a pointer to the bytes
|
|
191
|
+
// and we copy them one by one.
|
|
192
|
+
cmp x3, #8
|
|
193
|
+
b.gt .Larray_with_copy_loop
|
|
194
|
+
cmp x3, #4
|
|
195
|
+
b.eq .Larray_with_store4
|
|
196
|
+
cmp x3, #2
|
|
197
|
+
b.eq .Larray_with_store2
|
|
198
|
+
cmp x3, #1
|
|
199
|
+
b.eq .Larray_with_store1
|
|
200
|
+
// T_SIZE == 8 (int/string-ptr/class-ptr): single 8-byte store
|
|
201
|
+
str x0, [x5]
|
|
202
|
+
b .Larray_with_next
|
|
203
|
+
.Larray_with_store4:
|
|
204
|
+
str w0, [x5]
|
|
205
|
+
b .Larray_with_next
|
|
206
|
+
.Larray_with_store2:
|
|
207
|
+
strh w0, [x5]
|
|
208
|
+
b .Larray_with_next
|
|
209
|
+
.Larray_with_store1:
|
|
210
|
+
strb w0, [x5]
|
|
211
|
+
b .Larray_with_next
|
|
212
|
+
|
|
213
|
+
.Larray_with_copy_loop:
|
|
214
|
+
// Struct element (T_SIZE > 8): x0 is a pointer to the bytes — copy
|
|
215
|
+
// them one by one so adjacent slots aren't clobbered.
|
|
216
|
+
mov x6, #0 // j = 0
|
|
217
|
+
.Larray_with_byte:
|
|
218
|
+
ldrb w7, [x0, x6]
|
|
219
|
+
strb w7, [x5, x6]
|
|
220
|
+
add x6, x6, #1
|
|
221
|
+
cmp x6, x3
|
|
222
|
+
blt .Larray_with_byte
|
|
223
|
+
|
|
224
|
+
.Larray_with_next:
|
|
225
|
+
add x2, x2, #1
|
|
226
|
+
ldr x1, [sp]
|
|
227
|
+
cmp x2, x1
|
|
228
|
+
blt .Larray_with_loop
|
|
229
|
+
|
|
230
|
+
.Larray_with_end:
|
|
231
|
+
mov x0, x19 // return heap pointer
|
|
232
|
+
add sp, sp, #16
|
|
233
|
+
ldp x19, x20, [sp], #16
|
|
234
|
+
```
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
pub func add = (self, Array other, out Array) {
|
|
238
|
+
```
|
|
239
|
+
#arch: c
|
|
240
|
+
long _self_len = self->length;
|
|
241
|
+
long _other_len = other->length;
|
|
242
|
+
long _result_len = _self_len + _other_len;
|
|
243
|
+
long _header = sizeof(*self);
|
|
244
|
+
void* _result = malloc(_header + _result_len * T_SIZE);
|
|
245
|
+
((long*)_result)[0] = 0;
|
|
246
|
+
((long*)_result)[1] = _result_len;
|
|
247
|
+
T* _data = (T*)((char*)_result + _header);
|
|
248
|
+
T* self_data = (T*)((char*)self + _header);
|
|
249
|
+
T* other_data = (T*)((char*)other + _header);
|
|
250
|
+
memcpy(_data, self_data, _self_len * T_SIZE);
|
|
251
|
+
memcpy(_data + _self_len, other_data, _other_len * T_SIZE);
|
|
252
|
+
return _result;
|
|
253
|
+
```
|
|
254
|
+
```
|
|
255
|
+
#arch: aarch64
|
|
256
|
+
// x19 = self (first elem), x20 = other (first elem), x8 = return buf (first elem)
|
|
257
|
+
// Length prefix is at [base - 8]
|
|
258
|
+
|
|
259
|
+
// Save return buffer (clobbered by _memcpy)
|
|
260
|
+
str x8, [sp, #-16]!
|
|
261
|
+
|
|
262
|
+
// Load lengths and store result length
|
|
263
|
+
ldr x2, [x19, #-8]
|
|
264
|
+
ldr x3, [x20, #-8]
|
|
265
|
+
add x4, x2, x3
|
|
266
|
+
ldr x8, [sp]
|
|
267
|
+
str x4, [x8, #-8]
|
|
268
|
+
|
|
269
|
+
// self_bytes = self_len * T_SIZE
|
|
270
|
+
mov x5, #T_SIZE
|
|
271
|
+
mul x5, x2, x5
|
|
272
|
+
|
|
273
|
+
// memcpy(return_buf, self, self_bytes)
|
|
274
|
+
mov x0, x8
|
|
275
|
+
mov x1, x19
|
|
276
|
+
mov x2, x5
|
|
277
|
+
bl _memcpy
|
|
278
|
+
|
|
279
|
+
// Reload return buf and self_len (clobbered by memcpy)
|
|
280
|
+
ldr x8, [sp]
|
|
281
|
+
ldr x2, [x19, #-8]
|
|
282
|
+
mov x5, #T_SIZE
|
|
283
|
+
mul x5, x2, x5
|
|
284
|
+
|
|
285
|
+
// other_bytes
|
|
286
|
+
ldr x3, [x20, #-8]
|
|
287
|
+
mov x6, #T_SIZE
|
|
288
|
+
mul x6, x3, x6
|
|
289
|
+
|
|
290
|
+
// memcpy(return_buf + self_bytes, other, other_bytes)
|
|
291
|
+
add x0, x8, x5
|
|
292
|
+
mov x1, x20
|
|
293
|
+
mov x2, x6
|
|
294
|
+
bl _memcpy
|
|
295
|
+
|
|
296
|
+
add sp, sp, #16
|
|
297
|
+
```
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
pub func mul = (self, int other, out Array) {
|
|
301
|
+
```
|
|
302
|
+
#arch: c
|
|
303
|
+
long _self_len = self->length;
|
|
304
|
+
long _result_len = _self_len * other;
|
|
305
|
+
long _header = sizeof(*self);
|
|
306
|
+
void* _result = malloc(_header + _result_len * T_SIZE);
|
|
307
|
+
((long*)_result)[0] = 0;
|
|
308
|
+
((long*)_result)[1] = _result_len;
|
|
309
|
+
T* _data = (T*)((char*)_result + _header);
|
|
310
|
+
T* self_data = (T*)((char*)self + _header);
|
|
311
|
+
for (long i = 0; i < other; i++) {
|
|
312
|
+
memcpy(_data + i * _self_len, self_data, _self_len * T_SIZE);
|
|
313
|
+
}
|
|
314
|
+
return _result;
|
|
315
|
+
```
|
|
316
|
+
```
|
|
317
|
+
#arch: aarch64
|
|
318
|
+
// x19 = self (first elem), x1 = multiplier, x8 = return buf (first elem)
|
|
319
|
+
|
|
320
|
+
// Save return buf and multiplier
|
|
321
|
+
stp x8, x1, [sp, #-16]!
|
|
322
|
+
|
|
323
|
+
// self_len and self_bytes
|
|
324
|
+
ldr x2, [x19, #-8]
|
|
325
|
+
mov x5, #T_SIZE
|
|
326
|
+
mul x5, x2, x5
|
|
327
|
+
|
|
328
|
+
// result_len = self_len * multiplier
|
|
329
|
+
mul x3, x2, x1
|
|
330
|
+
ldr x8, [sp]
|
|
331
|
+
str x3, [x8, #-8]
|
|
332
|
+
|
|
333
|
+
// Loop: copy self to result multiplier times
|
|
334
|
+
mov x4, #0
|
|
335
|
+
|
|
336
|
+
.Larray_mul_loop:
|
|
337
|
+
ldr x1, [sp, #8]
|
|
338
|
+
cmp x4, x1
|
|
339
|
+
b.ge .Larray_mul_end
|
|
340
|
+
|
|
341
|
+
// dest = return_buf + x4 * self_bytes
|
|
342
|
+
ldr x8, [sp]
|
|
343
|
+
mul x6, x4, x5
|
|
344
|
+
add x0, x8, x6
|
|
345
|
+
|
|
346
|
+
// memcpy(dest, self, self_bytes)
|
|
347
|
+
mov x1, x19
|
|
348
|
+
mov x2, x5
|
|
349
|
+
bl _memcpy
|
|
350
|
+
|
|
351
|
+
add x4, x4, #1
|
|
352
|
+
b .Larray_mul_loop
|
|
353
|
+
|
|
354
|
+
.Larray_mul_end:
|
|
355
|
+
add sp, sp, #16
|
|
356
|
+
```
|
|
357
|
+
}
|
|
358
|
+
}
|