toilscript 0.1.4 → 0.1.6
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/cli.js +3480 -21
- package/dist/cli.js.map +2 -2
- package/dist/importmap.json +2 -2
- package/dist/web.js +3 -3
- package/package.json +1 -1
- package/std/assembly/bignum/LICENSE +201 -0
- package/std/assembly/bignum/NOTICE +7 -0
- package/std/assembly/bignum/fixed/fp128.ts +58 -0
- package/std/assembly/bignum/fixed/fp256.ts +9 -0
- package/std/assembly/bignum/fixed/index.ts +38 -0
- package/std/assembly/bignum/fixed/safe/fp128.ts +3 -0
- package/std/assembly/bignum/fixed/safe/fp256.ts +3 -0
- package/std/assembly/bignum/fixed/types.ts +103 -0
- package/std/assembly/bignum/globals.ts +546 -0
- package/std/assembly/bignum/index.ts +1 -0
- package/std/assembly/bignum/integer/i128.ts +413 -0
- package/std/assembly/bignum/integer/i256.ts +50 -0
- package/std/assembly/bignum/integer/index.ts +3 -0
- package/std/assembly/bignum/integer/u128.ts +963 -0
- package/std/assembly/bignum/integer/u256.ts +1007 -0
- package/std/assembly/bignum/utils.ts +260 -0
- package/std/assembly/bignum.ts +18 -0
- package/std/assembly/index.d.ts +1 -1
- package/std/assembly/toilscript.d.ts +273 -0
- package/std/assembly/toilscript.ts +0 -16
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
import { u128 } from './u128';
|
|
2
|
+
import { i256 } from './i256';
|
|
3
|
+
import { u256 } from './u256';
|
|
4
|
+
|
|
5
|
+
import { __clz128, __ctz128, } from '../globals';
|
|
6
|
+
|
|
7
|
+
import { atou128 } from '../utils';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 128-bit signed integer in two's complement representation.
|
|
11
|
+
* The `hi` field is signed, storing sign bits for negative values.
|
|
12
|
+
*/
|
|
13
|
+
export class i128 {
|
|
14
|
+
|
|
15
|
+
constructor(public lo: u64 = 0, public hi: i64 = 0) {
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
@inline static get Zero(): i128 {
|
|
19
|
+
return new i128();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@inline static get One(): i128 {
|
|
23
|
+
return new i128(1, 0);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@inline static get Min(): i128 {
|
|
27
|
+
return new i128(0, 0x8000000000000000);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@inline static get Max(): i128 {
|
|
31
|
+
return new i128(u64.MAX_VALUE, 0x7FFFFFFFFFFFFFFF);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Construct from decimal or hex string
|
|
35
|
+
@inline
|
|
36
|
+
static fromString(value: string, radix: i32 = 10): i128 {
|
|
37
|
+
// If the string is prefixed with "-" we rely on atou128 + two’s complement wrap
|
|
38
|
+
// in the final reinterpret.
|
|
39
|
+
return changetype<i128>(atou128(value, radix));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@inline
|
|
43
|
+
static fromI256(value: i256): i128 {
|
|
44
|
+
// Truncates top bits (value.hi1, value.hi2)
|
|
45
|
+
return new i128(value.lo1, value.lo2);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@inline
|
|
49
|
+
static fromU256(value: u256): i128 {
|
|
50
|
+
// Also truncation
|
|
51
|
+
return new i128(value.lo1, <i64>value.lo2);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@inline
|
|
55
|
+
static fromI128(value: i128): i128 {
|
|
56
|
+
return new i128(value.lo, value.hi);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@inline
|
|
60
|
+
static fromU128(value: u128): i128 {
|
|
61
|
+
return new i128(value.lo, <i64>value.hi);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
@inline
|
|
65
|
+
static fromI64(value: i64): i128 {
|
|
66
|
+
return new i128(<u64>value, value >> 63);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
@inline
|
|
70
|
+
static fromU64(value: u64): i128 {
|
|
71
|
+
return new i128(value, 0);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
@inline
|
|
75
|
+
static fromF64(value: f64): i128 {
|
|
76
|
+
let i = <i64>value; // convert f64 -> i64 (round/truncate)
|
|
77
|
+
return new i128(<u64>i, i >> 63);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
@inline
|
|
81
|
+
static fromF32(value: f32): i128 {
|
|
82
|
+
let i = <i64>value; // or <i32> then sign-extend
|
|
83
|
+
return new i128(<u64>i, i >> 63);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
@inline
|
|
87
|
+
static fromI32(value: i32): i128 {
|
|
88
|
+
return new i128(<u64>value, <i64>(value >> 31));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
@inline
|
|
92
|
+
static fromU32(value: u32): i128 {
|
|
93
|
+
return new i128(<u64>value, 0);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
@inline
|
|
97
|
+
static fromBits(lo1: i32, lo2: i32, hi1: i32, hi2: i32): i128 {
|
|
98
|
+
let lo = ((<u64>lo2) << 32) | (<u64>(lo1) & 0xffffffff);
|
|
99
|
+
let hi = ((<i64>hi2) << 32) | (<i64>(hi1) & 0xffffffff);
|
|
100
|
+
return new i128(lo, hi);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
@inline
|
|
104
|
+
static fromBytes<T>(array: T, bigEndian: bool = false): i128 {
|
|
105
|
+
if (array instanceof u8[]) {
|
|
106
|
+
return bigEndian
|
|
107
|
+
// @ts-ignore
|
|
108
|
+
? i128.fromBytesBE(<u8[]>array)
|
|
109
|
+
: i128.fromBytesLE(<u8[]>array);
|
|
110
|
+
} else if (array instanceof Uint8Array) {
|
|
111
|
+
return bigEndian
|
|
112
|
+
? i128.fromUint8ArrayBE(<Uint8Array>array)
|
|
113
|
+
: i128.fromUint8ArrayLE(<Uint8Array>array);
|
|
114
|
+
} else {
|
|
115
|
+
throw new TypeError("Unsupported generic type");
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
@inline
|
|
120
|
+
static fromBytesLE(array: u8[]): i128 {
|
|
121
|
+
return i128.fromUint8ArrayLE(changetype<Uint8Array>(array));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
@inline
|
|
125
|
+
static fromBytesBE(array: u8[]): i128 {
|
|
126
|
+
return i128.fromUint8ArrayBE(changetype<Uint8Array>(array));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
@inline
|
|
130
|
+
static fromUint8ArrayLE(array: Uint8Array): i128 {
|
|
131
|
+
assert(array.length && (array.length & 15) == 0);
|
|
132
|
+
let buffer = array.dataStart;
|
|
133
|
+
return new i128(
|
|
134
|
+
load<u64>(buffer, 0 * sizeof<u64>()),
|
|
135
|
+
load<u64>(buffer, 1 * sizeof<u64>())
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
static fromUint8ArrayBE(array: Uint8Array): i128 {
|
|
140
|
+
assert(array.length && (array.length & 15) == 0);
|
|
141
|
+
let buffer = array.dataStart;
|
|
142
|
+
return new i128(
|
|
143
|
+
bswap<u64>(load<u64>(buffer, 1 * sizeof<u64>())),
|
|
144
|
+
bswap<u64>(load<u64>(buffer, 0 * sizeof<u64>()))
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Create 128-bit signed integer from a generic type T
|
|
150
|
+
* @param value
|
|
151
|
+
* @return 128-bit signed integer
|
|
152
|
+
*/
|
|
153
|
+
@inline
|
|
154
|
+
static from<T>(value: T): i128 {
|
|
155
|
+
if (value instanceof bool) return i128.fromU64(<u64>value);
|
|
156
|
+
else if (value instanceof i8) return i128.fromI64(<i64>value);
|
|
157
|
+
else if (value instanceof u8) return i128.fromU64(<u64>value);
|
|
158
|
+
else if (value instanceof i16) return i128.fromI64(<i64>value);
|
|
159
|
+
else if (value instanceof u16) return i128.fromU64(<u64>value);
|
|
160
|
+
else if (value instanceof i32) return i128.fromI64(<i64>value);
|
|
161
|
+
else if (value instanceof u32) return i128.fromU64(<u64>value);
|
|
162
|
+
else if (value instanceof i64) return i128.fromI64(<i64>value);
|
|
163
|
+
else if (value instanceof u64) return i128.fromU64(<u64>value);
|
|
164
|
+
else if (value instanceof f32) return i128.fromF64(<f64>value);
|
|
165
|
+
else if (value instanceof f64) return i128.fromF64(<f64>value);
|
|
166
|
+
else if (value instanceof i128) return i128.fromI128(<i128>value);
|
|
167
|
+
else if (value instanceof u128) return i128.fromU128(<u128>value);
|
|
168
|
+
else if (value instanceof i256) return i128.fromI256(<i256>value);
|
|
169
|
+
else if (value instanceof u256) return i128.fromU256(<u256>value);
|
|
170
|
+
else if (value instanceof u8[]) return i128.fromBytes(<u8[]>value);
|
|
171
|
+
else throw new TypeError("Unsupported generic type");
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
@inline @operator.prefix('!')
|
|
175
|
+
static isEmpty(value: i128): bool {
|
|
176
|
+
return value.isZero();
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
@inline @operator('|')
|
|
180
|
+
static or(a: i128, b: i128): i128 {
|
|
181
|
+
return new i128(a.lo | b.lo, a.hi | b.hi);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
@inline @operator('^')
|
|
185
|
+
static xor(a: i128, b: i128): i128 {
|
|
186
|
+
return new i128(a.lo ^ b.lo, a.hi ^ b.hi);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
@inline @operator('&')
|
|
190
|
+
static and(a: i128, b: i128): i128 {
|
|
191
|
+
return new i128(a.lo & b.lo, a.hi & b.hi);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
@inline @operator('<<')
|
|
195
|
+
static shl(value: i128, shift: i32): i128 {
|
|
196
|
+
shift &= 127;
|
|
197
|
+
0xFFFFFFFFFFFFFFFF
|
|
198
|
+
if (!shift) return value;
|
|
199
|
+
|
|
200
|
+
let lo = value.lo;
|
|
201
|
+
let hi = value.hi;
|
|
202
|
+
if (shift < 64) {
|
|
203
|
+
let newLo = lo << shift;
|
|
204
|
+
let newHi = (hi << shift) | i64(lo >>> (64 - shift));
|
|
205
|
+
return new i128(newLo, newHi);
|
|
206
|
+
} else {
|
|
207
|
+
// shift >= 64
|
|
208
|
+
let s = shift - 64;
|
|
209
|
+
if (s == 0) {
|
|
210
|
+
// exactly 64
|
|
211
|
+
return new i128(0, lo as i64);
|
|
212
|
+
} else {
|
|
213
|
+
// 1..63
|
|
214
|
+
return new i128(0, (lo << s) as i64);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
@inline @operator('>>>')
|
|
220
|
+
static shr_u(value: i128, shift: i32): i128 {
|
|
221
|
+
// an unsigned right shift of a *signed* 128
|
|
222
|
+
shift &= 127;
|
|
223
|
+
if (!shift) return value;
|
|
224
|
+
|
|
225
|
+
let lo = value.lo;
|
|
226
|
+
let hi = u64(value.hi); // reinterpret sign as high bits
|
|
227
|
+
|
|
228
|
+
if (shift < 64) {
|
|
229
|
+
let newLo = (lo >>> shift) | (hi << (64 - shift));
|
|
230
|
+
let newHi = hi >>> shift;
|
|
231
|
+
return new i128(newLo, newHi as i64);
|
|
232
|
+
} else {
|
|
233
|
+
// shift >= 64
|
|
234
|
+
let s = shift - 64;
|
|
235
|
+
if (s == 0) {
|
|
236
|
+
return new i128(hi, 0);
|
|
237
|
+
} else {
|
|
238
|
+
// 1..63
|
|
239
|
+
return new i128(hi >>> s, 0);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
@inline @operator('+')
|
|
245
|
+
static add(a: i128, b: i128): i128 {
|
|
246
|
+
let lo = a.lo + b.lo;
|
|
247
|
+
let carry = (lo < a.lo) ? 1 : 0;
|
|
248
|
+
let hi = a.hi + b.hi + (carry as i64);
|
|
249
|
+
return new i128(lo, hi);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
@inline @operator('-')
|
|
253
|
+
static sub(a: i128, b: i128): i128 {
|
|
254
|
+
let lo = a.lo - b.lo;
|
|
255
|
+
let borrow = (lo > a.lo) ? 1 : 0;
|
|
256
|
+
let hi = a.hi - b.hi - (borrow as i64);
|
|
257
|
+
return new i128(lo, hi);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
@inline @operator('==')
|
|
261
|
+
static eq(a: i128, b: i128): bool {
|
|
262
|
+
return a.hi == b.hi && a.lo == b.lo;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
@inline @operator('!=')
|
|
266
|
+
static ne(a: i128, b: i128): bool {
|
|
267
|
+
return !i128.eq(a, b);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
@inline @operator('<')
|
|
271
|
+
static lt(a: i128, b: i128): bool {
|
|
272
|
+
let ah = a.hi, bh = b.hi;
|
|
273
|
+
// If hi parts differ, that decides the sign. Otherwise compare lo.
|
|
274
|
+
return ah == bh ? a.lo < b.lo : ah < bh;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
@inline @operator('>')
|
|
278
|
+
static gt(a: i128, b: i128): bool {
|
|
279
|
+
return b < a;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
@inline @operator('<=')
|
|
283
|
+
static le(a: i128, b: i128): bool {
|
|
284
|
+
return !i128.gt(a, b);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
@inline @operator('>=')
|
|
288
|
+
static ge(a: i128, b: i128): bool {
|
|
289
|
+
return !i128.lt(a, b);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
@inline
|
|
293
|
+
static ord(a: i128, b: i128): i32 {
|
|
294
|
+
// Return -1, 0, 1
|
|
295
|
+
if (a == b) return 0;
|
|
296
|
+
return i128.lt(a, b) ? -1 : 1;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
@inline
|
|
300
|
+
static popcnt(value: i128): i32 {
|
|
301
|
+
return <i32>(popcnt(value.lo) + popcnt(value.hi));
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
@inline
|
|
305
|
+
static clz(value: i128): i32 {
|
|
306
|
+
return __clz128(value.lo, value.hi);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
@inline
|
|
310
|
+
static ctz(value: i128): i32 {
|
|
311
|
+
return __ctz128(value.lo, value.hi);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
@inline
|
|
315
|
+
static abs(value: i128): i128 {
|
|
316
|
+
// if negative, return -value
|
|
317
|
+
return value.isNeg() ? value.neg() : value;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
@inline
|
|
321
|
+
isPos(): bool {
|
|
322
|
+
return this.hi >= 0;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
@inline
|
|
326
|
+
isNeg(): bool {
|
|
327
|
+
return this.hi < 0;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
@inline
|
|
331
|
+
isZero(): bool {
|
|
332
|
+
return !(this.lo | this.hi);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
@inline @operator.prefix('~')
|
|
336
|
+
not(): i128 {
|
|
337
|
+
return new i128(~this.lo, ~this.hi);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
@inline @operator.prefix('+')
|
|
341
|
+
pos(): i128 {
|
|
342
|
+
return this;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
@inline @operator.prefix('-')
|
|
346
|
+
neg(): i128 {
|
|
347
|
+
// two's complement: ~x + 1
|
|
348
|
+
let nlo = ~this.lo;
|
|
349
|
+
let nhi = ~this.hi;
|
|
350
|
+
|
|
351
|
+
let sum = nlo + 1;
|
|
352
|
+
let carry = (sum < nlo) ? 1 : 0;
|
|
353
|
+
let hi2 = nhi + (carry as i64);
|
|
354
|
+
|
|
355
|
+
return new i128(sum, hi2);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Convert to a normal array of bytes (16 bytes for 128 bits).
|
|
360
|
+
* @param bigEndian If true, the highest bytes come first.
|
|
361
|
+
*/
|
|
362
|
+
@inline
|
|
363
|
+
toBytes(bigEndian: bool = false): u8[] {
|
|
364
|
+
let result = new Array<u8>(16);
|
|
365
|
+
this.toArrayBuffer(result.dataStart, bigEndian);
|
|
366
|
+
return result;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Convert to a StaticArray<u8> of length 16.
|
|
371
|
+
* @param bigEndian If true, the highest bytes come first.
|
|
372
|
+
* @returns StaticArray<u8>
|
|
373
|
+
*/
|
|
374
|
+
@inline
|
|
375
|
+
toStaticBytes(bigEndian: bool = false): StaticArray<u8> {
|
|
376
|
+
let result = new StaticArray<u8>(16);
|
|
377
|
+
this.toArrayBuffer(changetype<usize>(result), bigEndian);
|
|
378
|
+
return result;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Convert to Uint8Array
|
|
383
|
+
* @param bigEndian Little or Big Endian? Default: false
|
|
384
|
+
* @returns Uint8Array
|
|
385
|
+
*/
|
|
386
|
+
@inline
|
|
387
|
+
toUint8Array(bigEndian: bool = false): Uint8Array {
|
|
388
|
+
let result = new Uint8Array(16);
|
|
389
|
+
this.toArrayBuffer(result.dataStart, bigEndian);
|
|
390
|
+
return result;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
@inline
|
|
394
|
+
private toArrayBufferLE(buffer: usize): void {
|
|
395
|
+
store<u64>(buffer, this.lo, 0 * sizeof<u64>());
|
|
396
|
+
store<u64>(buffer, this.hi, 1 * sizeof<u64>());
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
@inline
|
|
400
|
+
private toArrayBufferBE(buffer: usize): void {
|
|
401
|
+
store<u64>(buffer, bswap<u64>(this.hi), 0 * sizeof<u64>());
|
|
402
|
+
store<u64>(buffer, bswap<u64>(this.lo), 1 * sizeof<u64>());
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
@inline
|
|
406
|
+
private toArrayBuffer(buffer: usize, bigEndian: bool = false): void {
|
|
407
|
+
if (bigEndian) {
|
|
408
|
+
this.toArrayBufferBE(buffer);
|
|
409
|
+
} else {
|
|
410
|
+
this.toArrayBufferLE(buffer);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export class i256 {
|
|
2
|
+
|
|
3
|
+
constructor(
|
|
4
|
+
public lo1: i64 = 0,
|
|
5
|
+
public lo2: i64 = 0,
|
|
6
|
+
public hi1: i64 = 0,
|
|
7
|
+
public hi2: i64 = 0,
|
|
8
|
+
) {
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
@inline static get Zero(): i256 {
|
|
12
|
+
return new i256();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
@inline static get One(): i256 {
|
|
16
|
+
return new i256(1);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
@inline static get Min(): i256 {
|
|
20
|
+
return new i256(0, 0, 0, 0x8000000000000000);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@inline static get Max(): i256 {
|
|
24
|
+
return new i256(u64.MAX_VALUE, u64.MAX_VALUE, u64.MAX_VALUE, 0x7FFFFFFFFFFFFFFF);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@inline @operator.prefix('!')
|
|
28
|
+
static isEmpty(value: i256): bool {
|
|
29
|
+
return value.isZero();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@inline
|
|
33
|
+
isNeg(): bool {
|
|
34
|
+
return <bool>(this.hi2 >>> 63);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@inline
|
|
38
|
+
isZero(): bool {
|
|
39
|
+
return !(this.lo1 | this.lo2 | this.hi1 | this.hi2);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/*
|
|
43
|
+
@inline
|
|
44
|
+
static abs(value: i128): i128 {
|
|
45
|
+
return value < 0 ? value.neg() : value;
|
|
46
|
+
}
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
// TODO
|
|
50
|
+
}
|