vitest-pool-assemblyscript 0.3.0 → 0.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/README.md +6 -4
- package/assembly/compare.ts +127 -0
- package/assembly/expect.ts +125 -16
- package/package.json +1 -1
- package/prebuilds/darwin-arm64/vitest-pool-assemblyscript.glibc.node +0 -0
- package/prebuilds/darwin-x64/vitest-pool-assemblyscript.glibc.node +0 -0
- package/prebuilds/linux-arm64/vitest-pool-assemblyscript.glibc.node +0 -0
- package/prebuilds/win32-arm64/vitest-pool-assemblyscript.glibc.node +0 -0
- package/prebuilds/win32-x64/vitest-pool-assemblyscript.glibc.node +0 -0
package/README.md
CHANGED
|
@@ -141,7 +141,8 @@ npx vitest run
|
|
|
141
141
|
- Suite and test definition using `describe()` and `test()` in AssemblyScript
|
|
142
142
|
- Inline test option configuration for common vitest options: `timeout`, `retry`, `skip`, `only`, `fails`
|
|
143
143
|
- Assertion matching API based on vitest/jest `expect()` API
|
|
144
|
-
- `.not`, `toBe`, `toBeCloseTo`, `toEqual` (with caveats*), `toStrictEqual`, `toHaveLength`, `toThrowError`, `toBeTruthy`, `toBeFalsy`, `toBeNull`, `toBeNullable`, `toBeNaN`
|
|
144
|
+
- `.not`, `toBe`, `toBeCloseTo`, `toEqual` (with caveats*), `toStrictEqual`, `toBeGreaterThan`, `toBeGreaterThanOrEqual`, `toBeLessThan`, `toBeLessThanOrEqual`, `toHaveLength`, `toThrowError`, `toBeTruthy`, `toBeFalsy`, `toBeNull`, `toBeNullable`, `toBeNaN`
|
|
145
|
+
- See [Matchers API](docs/matchers-api.md) for details and differences from JavaScript
|
|
145
146
|
- Highlighted diffs for assertion and runtime failures, which point to source code
|
|
146
147
|
- Source-mapped WASM error stack traces (accurate AssemblyScript source `function file:line:column`)
|
|
147
148
|
- AssemblyScript console output captured and provided to vitest for display
|
|
@@ -286,12 +287,13 @@ These are known limitations which are currently being worked on.
|
|
|
286
287
|
- Lifecycle hooks (`beforeEach`, `afterEach`, `beforeAll`, `afterAll`)
|
|
287
288
|
- Watch mode: re-run applicable tests on source file changes
|
|
288
289
|
- `toEqual` reflection for deep equality inspection of user objects
|
|
290
|
+
- `describe.for/each` and `test.for/each`
|
|
289
291
|
- expect.soft to prevent fail-fast behavior
|
|
290
292
|
- Allow delegating JS/TS to istanbul coverage provider in addition to v8
|
|
291
293
|
- Maybe: Per-file compilation setting override
|
|
292
294
|
|
|
293
295
|
**Epic: Expand expect matcher API**
|
|
294
|
-
- Planned: `toBeDefined`, `toBeUndefined`, `
|
|
296
|
+
- Planned: `toBeDefined`, `toBeUndefined`, `toContain`, `toContainEqual`
|
|
295
297
|
- Likely: `toBeOneOf`, `toBeTypeOf`, `toBeInstanceOf`, `toHaveProperty`, `toMatch`
|
|
296
298
|
|
|
297
299
|
**Epic: Spy and Mock**
|
|
@@ -309,10 +311,10 @@ These are known limitations which are currently being worked on.
|
|
|
309
311
|
## Performance
|
|
310
312
|
|
|
311
313
|
Efforts have been made to compile and run tests as quickly as possible:
|
|
312
|
-
- Separate compile and test execution
|
|
314
|
+
- Separate compile and test execution thread pools, workers, and runners for quicker startup and respawn
|
|
313
315
|
- Compile threads tuned to take advantage of significant Node V8 engine warmup time savings on consecutive AssemblyScript compilations
|
|
314
316
|
- In-memory compiled files and source maps to eliminate intermediate disk I/O
|
|
315
|
-
- Enforced hard timeouts for long-running WASM via thread termination, with intelligent resume
|
|
317
|
+
- Enforced hard timeouts for long-running WASM tests via thread termination, with intelligent resume
|
|
316
318
|
|
|
317
319
|
As such, it is capable of compiling dozens of test files comprising hundreds of tests in a few seconds.
|
|
318
320
|
|
package/assembly/compare.ts
CHANGED
|
@@ -219,6 +219,133 @@ export function equals<T, U>(actual: T, expected: U): bool {
|
|
|
219
219
|
);
|
|
220
220
|
}
|
|
221
221
|
|
|
222
|
+
export enum InequalityOperation {
|
|
223
|
+
LessThan,
|
|
224
|
+
LessThanOrEqual,
|
|
225
|
+
GreaterThan,
|
|
226
|
+
GreaterThanOrEqual,
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Applies an inequality operation to two values of the same promoted type.
|
|
231
|
+
* Handles <, <=, >, >= for any type that supports these operators (numbers, strings).
|
|
232
|
+
*/
|
|
233
|
+
function applyInequalityOp<T>(a: T, b: T, op: InequalityOperation): bool {
|
|
234
|
+
if (op == InequalityOperation.LessThan) return a < b;
|
|
235
|
+
if (op == InequalityOperation.LessThanOrEqual) return a <= b;
|
|
236
|
+
if (op == InequalityOperation.GreaterThan) return a > b;
|
|
237
|
+
return a >= b; // GreaterThanOrEqual
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Generic inequality comparison. Promotes both values to a common type and applies
|
|
242
|
+
* the requested inequality operation.
|
|
243
|
+
*
|
|
244
|
+
* Strings are compared lexicographically. Booleans are treated as integers (true=1, false=0).
|
|
245
|
+
* Non-string references are not comparable and throw an error.
|
|
246
|
+
*
|
|
247
|
+
* Cross-sign integer comparisons are supported (more permissive than AS's own operators)
|
|
248
|
+
* via signed-negative early return + u64 promotion. Float/integer combinations where the
|
|
249
|
+
* float's mantissa cannot losslessly represent the integer type's range are rejected,
|
|
250
|
+
* matching AS compiler behavior. See docs/matcher-research.md for details.
|
|
251
|
+
*/
|
|
252
|
+
export function compareInequality<T, U>(actual: T, compareTo: U, expectedOperation: InequalityOperation): bool {
|
|
253
|
+
// --- Strings: lexicographic comparison ---
|
|
254
|
+
if (isString<T>() && isString<U>()) {
|
|
255
|
+
// Guard against null before casting, mirroring identical()'s pattern
|
|
256
|
+
const actualIsNull = isNullable<T>() && actual == null;
|
|
257
|
+
const compareToIsNull = isNullable<U>() && compareTo == null;
|
|
258
|
+
if (actualIsNull || compareToIsNull) {
|
|
259
|
+
throw new Error(
|
|
260
|
+
"Cannot compare null string with inequality operators: the result is undefined."
|
|
261
|
+
+ " Use toBeNull() to check for null values."
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
return applyInequalityOp(<string>actual, <string>compareTo, expectedOperation);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// --- Reject non-string references (objects, arrays, etc.) ---
|
|
268
|
+
if (isReference<T>() || isReference<U>()) {
|
|
269
|
+
throw new Error(
|
|
270
|
+
"Inequality comparison is not supported for " + nameof<T>() + " and " + nameof<U>()
|
|
271
|
+
+ ". Only numeric types and strings can be compared with inequality matchers."
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// --- Float/integer precision-loss rejection ---
|
|
276
|
+
// Reject combinations where the float's mantissa cannot losslessly represent
|
|
277
|
+
// the integer type's full range (sizeof(integer) >= sizeof(float)).
|
|
278
|
+
// This mirrors AS's own operator rejection (e.g. f32 > i32, f64 > i64).
|
|
279
|
+
if (isFloat<T>() && isInteger<U>()) {
|
|
280
|
+
if (sizeof<U>() >= sizeof<T>()) {
|
|
281
|
+
throw new Error(
|
|
282
|
+
"Cannot compare " + nameof<T>() + " with " + nameof<U>()
|
|
283
|
+
+ ": float precision is insufficient for the integer type's range."
|
|
284
|
+
+ " Cast both values to f64 before comparing, e.g. expect(f64(a)).toBeGreaterThan(f64(b))."
|
|
285
|
+
+ " Note: large integer values may lose precision when cast to f64, which could cause false positives."
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
} else if (isInteger<T>() && isFloat<U>()) {
|
|
289
|
+
if (sizeof<T>() >= sizeof<U>()) {
|
|
290
|
+
throw new Error(
|
|
291
|
+
"Cannot compare " + nameof<T>() + " with " + nameof<U>()
|
|
292
|
+
+ ": float precision is insufficient for the integer type's range."
|
|
293
|
+
+ " Cast both values to f64 before comparing, e.g. expect(f64(a)).toBeGreaterThan(f64(b))."
|
|
294
|
+
+ " Note: large integer values may lose precision when cast to f64, which could cause false positives."
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// --- Numeric comparisons ---
|
|
300
|
+
// Booleans flow through here naturally (isInteger<bool>() is true in AS).
|
|
301
|
+
|
|
302
|
+
if (isInteger<T>() && isInteger<U>()) {
|
|
303
|
+
// Both signed → promote to i64
|
|
304
|
+
if (isSigned<T>() && isSigned<U>()) {
|
|
305
|
+
return applyInequalityOp(i64(actual), i64(compareTo), expectedOperation);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Both unsigned → promote to u64
|
|
309
|
+
if (!isSigned<T>() && !isSigned<U>()) {
|
|
310
|
+
return applyInequalityOp(u64(actual), u64(compareTo), expectedOperation);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Mixed sign — more permissive than AS, which rejects these at compile time.
|
|
314
|
+
// If the signed value is negative, the result is deterministic: signed < unsigned.
|
|
315
|
+
if (isSigned<T>() && !isSigned<U>()) {
|
|
316
|
+
if (i64(actual) < 0) {
|
|
317
|
+
// actual (signed negative) is always less than compareTo (unsigned)
|
|
318
|
+
return expectedOperation == InequalityOperation.LessThan
|
|
319
|
+
|| expectedOperation == InequalityOperation.LessThanOrEqual;
|
|
320
|
+
}
|
|
321
|
+
return applyInequalityOp(u64(actual), u64(compareTo), expectedOperation);
|
|
322
|
+
} else {
|
|
323
|
+
// !isSigned<T>() && isSigned<U>()
|
|
324
|
+
if (i64(compareTo) < 0) {
|
|
325
|
+
// compareTo (signed negative) is always less than actual (unsigned)
|
|
326
|
+
return expectedOperation == InequalityOperation.GreaterThan
|
|
327
|
+
|| expectedOperation == InequalityOperation.GreaterThanOrEqual;
|
|
328
|
+
}
|
|
329
|
+
return applyInequalityOp(u64(actual), u64(compareTo), expectedOperation);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Both floats → promote to f64
|
|
334
|
+
if (isFloat<T>() && isFloat<U>()) {
|
|
335
|
+
return applyInequalityOp(f64(actual), f64(compareTo), expectedOperation);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// Supported float/integer combo (passed precision-loss check above) → promote to f64
|
|
339
|
+
if ( (isFloat<T>() && isInteger<U>()) || (isInteger<T>() && isFloat<U>()) ) {
|
|
340
|
+
return applyInequalityOp(f64(actual), f64(compareTo), expectedOperation);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Unsupported type combination (e.g. vectors)
|
|
344
|
+
throw new Error(
|
|
345
|
+
"Inequality comparison is not supported for " + nameof<T>() + " and " + nameof<U>() + "."
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
|
|
222
349
|
export function truthyOrFalsey<T>(actual: T, expected: bool): bool {
|
|
223
350
|
return actual ? expected == true : expected == false;
|
|
224
351
|
}
|
package/assembly/expect.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
closeTo,
|
|
3
|
+
compareInequality,
|
|
3
4
|
equals,
|
|
4
5
|
identical,
|
|
6
|
+
InequalityOperation,
|
|
5
7
|
isNull,
|
|
6
8
|
nan,
|
|
7
9
|
truthyOrFalsey
|
|
@@ -97,11 +99,12 @@ abstract class BaseExpectMatcher<T> {
|
|
|
97
99
|
* objects, arrays, etc).
|
|
98
100
|
*
|
|
99
101
|
* Cross-type numeric comparisons are allowed where AssemblyScript's own `==` operator
|
|
100
|
-
* permits them (e.g. `f64` vs `i32`).
|
|
101
|
-
*
|
|
102
|
-
*
|
|
102
|
+
* permits them (e.g. `f64` vs `i32`). `toBeCloseTo()` is safer for any comparison
|
|
103
|
+
* involving a float and allows all numeric types because it can still produce accurate
|
|
104
|
+
* results in precision-loss casting edge cases.
|
|
103
105
|
*
|
|
104
|
-
*
|
|
106
|
+
* @throws When comparing float/integer types where the float's mantissa cannot losslessly
|
|
107
|
+
* represent the integer type's range (e.g. `f32` vs `i32`, `f64` vs `i64`).
|
|
105
108
|
*
|
|
106
109
|
* @example
|
|
107
110
|
* expect(1 + 1).toBe(2);
|
|
@@ -122,15 +125,17 @@ abstract class BaseExpectMatcher<T> {
|
|
|
122
125
|
}
|
|
123
126
|
|
|
124
127
|
/**
|
|
125
|
-
* Checks if a value is close to what you expect
|
|
126
|
-
* numbers
|
|
127
|
-
* to represent floats in binary. This rounding
|
|
128
|
+
* Checks if a value is close to what you expect, most useful for comparing floating point
|
|
129
|
+
* numbers to any other numbers. Using exact equality with floating point numbers often doesn't
|
|
130
|
+
* work correctly, because of internal rounding to represent floats in binary. This rounding
|
|
131
|
+
* means intuitive comparisons will often fail, so this matcher checks if they are "close enough"
|
|
132
|
+
* to be considered equal.
|
|
128
133
|
*
|
|
129
|
-
* Strings are compared by value equality
|
|
134
|
+
* Strings are compared by value equality as with `toBe`. Non-numeric, non-string types return false.
|
|
130
135
|
*
|
|
131
|
-
* @param precision - Specify
|
|
132
|
-
*
|
|
133
|
-
*
|
|
136
|
+
* @param precision - Specify the number of decimal places that must match for values to be
|
|
137
|
+
* considered close. Defaults to 2 digits, meaning effectively that values must be within 0.005 of
|
|
138
|
+
* each other.
|
|
134
139
|
*
|
|
135
140
|
* @example
|
|
136
141
|
* expect(0.1 + 0.2).toBeCloseTo(0.3);
|
|
@@ -139,7 +144,109 @@ abstract class BaseExpectMatcher<T> {
|
|
|
139
144
|
toBeCloseTo<U>(val: U, precision: i32 = 2): void {
|
|
140
145
|
this.assertComparison(closeTo(this.actual, val, precision), this.actual, val, "to be close to", true);
|
|
141
146
|
}
|
|
142
|
-
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Checks that a value is greater than the expected value. Supports numeric types
|
|
150
|
+
* (integers, floats, booleans) and strings (lexicographic comparison).
|
|
151
|
+
*
|
|
152
|
+
* Cross-type numeric comparisons are allowed where safe, including cross-sign integers
|
|
153
|
+
* (more permissive than AS's own `>` operator). Booleans are treated as numeric
|
|
154
|
+
* (true=1, false=0).
|
|
155
|
+
*
|
|
156
|
+
* @throws When comparing float/integer types where the float's mantissa cannot losslessly
|
|
157
|
+
* represent the integer type's range (e.g. `f32` vs `i32`, `f64` vs `i64`).
|
|
158
|
+
* @throws When comparing nullable strings where either value is null. Use `toBeNull()`
|
|
159
|
+
* to check for null values.
|
|
160
|
+
* @throws When comparing non-string reference types (objects, arrays, etc).
|
|
161
|
+
*
|
|
162
|
+
* @example
|
|
163
|
+
* expect(10).toBeGreaterThan(5);
|
|
164
|
+
* expect(3.14).toBeGreaterThan(3);
|
|
165
|
+
* expect("banana").toBeGreaterThan("apple");
|
|
166
|
+
*/
|
|
167
|
+
toBeGreaterThan<U>(val: U): void {
|
|
168
|
+
this.assertComparison(
|
|
169
|
+
compareInequality(this.actual, val, InequalityOperation.GreaterThan),
|
|
170
|
+
this.actual, val, "to be greater than", true
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Checks that a value is greater than or equal to the expected value. Supports numeric
|
|
176
|
+
* types (integers, floats, booleans) and strings (lexicographic comparison).
|
|
177
|
+
*
|
|
178
|
+
* Cross-type numeric comparisons are allowed where safe, including cross-sign integers
|
|
179
|
+
* (more permissive than AS's own `>=` operator). Booleans are treated as numeric
|
|
180
|
+
* (true=1, false=0).
|
|
181
|
+
*
|
|
182
|
+
* @throws When comparing float/integer types where the float's mantissa cannot losslessly
|
|
183
|
+
* represent the integer type's range (e.g. `f32` vs `i32`, `f64` vs `i64`).
|
|
184
|
+
* @throws When comparing nullable strings where either value is null. Use `toBeNull()`
|
|
185
|
+
* to check for null values.
|
|
186
|
+
* @throws When comparing non-string reference types (objects, arrays, etc).
|
|
187
|
+
*
|
|
188
|
+
* @example
|
|
189
|
+
* expect(10).toBeGreaterThanOrEqual(10);
|
|
190
|
+
* expect(3.14).toBeGreaterThanOrEqual(3);
|
|
191
|
+
*/
|
|
192
|
+
toBeGreaterThanOrEqual<U>(val: U): void {
|
|
193
|
+
this.assertComparison(
|
|
194
|
+
compareInequality(this.actual, val, InequalityOperation.GreaterThanOrEqual),
|
|
195
|
+
this.actual, val, "to be greater than or equal to", true
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Checks that a value is less than the expected value. Supports numeric types
|
|
201
|
+
* (integers, floats, booleans) and strings (lexicographic comparison).
|
|
202
|
+
*
|
|
203
|
+
* Cross-type numeric comparisons are allowed where safe, including cross-sign integers
|
|
204
|
+
* (more permissive than AS's own `<` operator). Booleans are treated as numeric
|
|
205
|
+
* (true=1, false=0).
|
|
206
|
+
*
|
|
207
|
+
* @throws When comparing float/integer types where the float's mantissa cannot losslessly
|
|
208
|
+
* represent the integer type's range (e.g. `f32` vs `i32`, `f64` vs `i64`).
|
|
209
|
+
* @throws When comparing nullable strings where either value is null. Use `toBeNull()`
|
|
210
|
+
* to check for null values.
|
|
211
|
+
* @throws When comparing non-string reference types (objects, arrays, etc).
|
|
212
|
+
*
|
|
213
|
+
* @example
|
|
214
|
+
* expect(5).toBeLessThan(10);
|
|
215
|
+
* expect(3).toBeLessThan(3.14);
|
|
216
|
+
* expect("apple").toBeLessThan("banana");
|
|
217
|
+
*/
|
|
218
|
+
toBeLessThan<U>(val: U): void {
|
|
219
|
+
this.assertComparison(
|
|
220
|
+
compareInequality(this.actual, val, InequalityOperation.LessThan),
|
|
221
|
+
this.actual, val, "to be less than", true
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Checks that a value is less than or equal to the expected value. Supports numeric
|
|
227
|
+
* types (integers, floats, booleans) and strings (lexicographic comparison).
|
|
228
|
+
*
|
|
229
|
+
* Cross-type numeric comparisons are allowed where safe, including cross-sign integers
|
|
230
|
+
* (more permissive than AS's own `<=` operator). Booleans are treated as numeric
|
|
231
|
+
* (true=1, false=0).
|
|
232
|
+
*
|
|
233
|
+
* @throws When comparing float/integer types where the float's mantissa cannot losslessly
|
|
234
|
+
* represent the integer type's range (e.g. `f32` vs `i32`, `f64` vs `i64`).
|
|
235
|
+
* @throws When comparing nullable strings where either value is null. Use `toBeNull()`
|
|
236
|
+
* to check for null values.
|
|
237
|
+
* @throws When comparing non-string reference types (objects, arrays, etc).
|
|
238
|
+
*
|
|
239
|
+
* @example
|
|
240
|
+
* expect(5).toBeLessThanOrEqual(5);
|
|
241
|
+
* expect(3).toBeLessThanOrEqual(3.14);
|
|
242
|
+
*/
|
|
243
|
+
toBeLessThanOrEqual<U>(val: U): void {
|
|
244
|
+
this.assertComparison(
|
|
245
|
+
compareInequality(this.actual, val, InequalityOperation.LessThanOrEqual),
|
|
246
|
+
this.actual, val, "to be less than or equal to", true
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
|
|
143
250
|
/**
|
|
144
251
|
* Checks that two values have the same value (deep equality). Currently supports
|
|
145
252
|
* checking equality of Arrays, Sets, Maps, and nulls. Values inside arrays are
|
|
@@ -148,11 +255,13 @@ abstract class BaseExpectMatcher<T> {
|
|
|
148
255
|
* `toBe()` rules.
|
|
149
256
|
*
|
|
150
257
|
* Like `toBe`, cross-type numeric comparisons follow AssemblyScript's own `==` operator
|
|
151
|
-
* restrictions.
|
|
152
|
-
*
|
|
153
|
-
*
|
|
258
|
+
* restrictions. `toBeCloseTo()` is safer for any comparison involving a float and
|
|
259
|
+
* accurately handles precision-loss edge cases.
|
|
260
|
+
*
|
|
261
|
+
* ⚠️ IMPORTANT: Does not yet support user-defined object deep equality checking.
|
|
154
262
|
*
|
|
155
|
-
*
|
|
263
|
+
* @throws When comparing float/integer types where the float's mantissa cannot losslessly
|
|
264
|
+
* represent the integer type's range (e.g. `f32` vs `i32`, `f64` vs `i64`).
|
|
156
265
|
*
|
|
157
266
|
* @example
|
|
158
267
|
* expect([1, 2, 3]).toEqual([1, 2, 3]);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vitest-pool-assemblyscript",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "AssemblyScript testing with Vitest - Simple, fast, familiar, AS-native, with full coverage output",
|
|
5
5
|
"author": "Matt Ritter <matthew.d.ritter@gmail.com>",
|
|
6
6
|
"license": "MIT",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|