koffi 2.3.21-beta.4 → 2.4.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.
- package/CHANGELOG.md +22 -5
- package/build/{2.3.21-beta.4 → 2.4.1}/koffi_win32_arm64/koffi.node +0 -0
- package/build/{2.3.21-beta.4 → 2.4.1}/koffi_win32_ia32/koffi.node +0 -0
- package/build/{2.3.21-beta.4 → 2.4.1}/koffi_win32_x64/koffi.node +0 -0
- package/doc/callbacks.md +12 -6
- package/doc/conf.py +1 -1
- package/doc/functions.md +55 -1
- package/doc/index.rst +2 -2
- package/doc/migration.md +6 -2
- package/doc/{calls.md → parameters.md} +4 -56
- package/doc/pointers.md +2 -2
- package/doc/types.md +2 -2
- package/package.json +2 -2
- /package/build/{2.3.21-beta.4 → 2.4.1}/koffi_darwin_arm64/koffi.node +0 -0
- /package/build/{2.3.21-beta.4 → 2.4.1}/koffi_darwin_x64/koffi.node +0 -0
- /package/build/{2.3.21-beta.4 → 2.4.1}/koffi_freebsd_arm64/koffi.node +0 -0
- /package/build/{2.3.21-beta.4 → 2.4.1}/koffi_freebsd_ia32/koffi.node +0 -0
- /package/build/{2.3.21-beta.4 → 2.4.1}/koffi_freebsd_x64/koffi.node +0 -0
- /package/build/{2.3.21-beta.4 → 2.4.1}/koffi_linux_arm32hf/koffi.node +0 -0
- /package/build/{2.3.21-beta.4 → 2.4.1}/koffi_linux_arm64/koffi.node +0 -0
- /package/build/{2.3.21-beta.4 → 2.4.1}/koffi_linux_ia32/koffi.node +0 -0
- /package/build/{2.3.21-beta.4 → 2.4.1}/koffi_linux_riscv64hf64/koffi.node +0 -0
- /package/build/{2.3.21-beta.4 → 2.4.1}/koffi_linux_x64/koffi.node +0 -0
- /package/build/{2.3.21-beta.4 → 2.4.1}/koffi_openbsd_ia32/koffi.node +0 -0
- /package/build/{2.3.21-beta.4 → 2.4.1}/koffi_openbsd_x64/koffi.node +0 -0
- /package/build/{2.3.21-beta.4 → 2.4.1}/koffi_win32_arm64/koffi.exp +0 -0
- /package/build/{2.3.21-beta.4 → 2.4.1}/koffi_win32_arm64/koffi.lib +0 -0
- /package/build/{2.3.21-beta.4 → 2.4.1}/koffi_win32_ia32/koffi.exp +0 -0
- /package/build/{2.3.21-beta.4 → 2.4.1}/koffi_win32_ia32/koffi.lib +0 -0
- /package/build/{2.3.21-beta.4 → 2.4.1}/koffi_win32_x64/koffi.exp +0 -0
- /package/build/{2.3.21-beta.4 → 2.4.1}/koffi_win32_x64/koffi.lib +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
## Version history
|
|
4
4
|
|
|
5
|
+
### Koffi 2.4
|
|
6
|
+
|
|
7
|
+
#### Koffi 2.4.1
|
|
8
|
+
|
|
9
|
+
**Main changes:**
|
|
10
|
+
|
|
11
|
+
- Support decoding pointers to callable functions
|
|
12
|
+
- Support calling function pointers with [koffi.call()]
|
|
13
|
+
- Deprecate `koffi.callback` in favor of `koffi.proto`
|
|
14
|
+
|
|
15
|
+
**Other changes:**
|
|
16
|
+
|
|
17
|
+
- Increase maximum number of callbacks to 8192
|
|
18
|
+
- Build Koffi with static CRT on Windows
|
|
19
|
+
- Reorganize Koffi data conversion documentation
|
|
20
|
+
- Add deprecated `koffi.handle` to TS file
|
|
21
|
+
|
|
5
22
|
### Koffi 2.3
|
|
6
23
|
|
|
7
24
|
#### Koffi 2.3.20
|
|
@@ -133,7 +150,7 @@
|
|
|
133
150
|
|
|
134
151
|
**Main changes:**
|
|
135
152
|
|
|
136
|
-
- Fix type parser issues (such as ignoring some [disposable qualifiers](
|
|
153
|
+
- Fix type parser issues (such as ignoring some [disposable qualifiers](parameters.md#heap-allocated-values))
|
|
137
154
|
- Fix crash when using disposable types in output parameters
|
|
138
155
|
- Add basic [koffi.stats()](misc.md#usage-statistics) interface
|
|
139
156
|
|
|
@@ -155,7 +172,7 @@
|
|
|
155
172
|
**Main changes:**
|
|
156
173
|
|
|
157
174
|
- Allow buffers (TypedArray or ArrayBuffer) values for input and/or output pointer arguments (for polymorphic arguments)
|
|
158
|
-
- Support opaque buffers (TypedArray or ArrayBuffer) values in `koffi.decode()` to [decode output buffers](
|
|
175
|
+
- Support opaque buffers (TypedArray or ArrayBuffer) values in `koffi.decode()` to [decode output buffers](parameters.md#output-buffers)
|
|
159
176
|
- Decode non-string types as arrays when an [explicit length is passed to koffi.decode()](callbacks.md#decoding-pointer-arguments)
|
|
160
177
|
|
|
161
178
|
**Other changes:**
|
|
@@ -220,7 +237,7 @@
|
|
|
220
237
|
**New features:**
|
|
221
238
|
|
|
222
239
|
- Add [koffi.decode()](callbacks.md#decoding-pointer-arguments) for callback pointer arguments
|
|
223
|
-
- Support transparent [output string parameters](
|
|
240
|
+
- Support transparent [output string parameters](parameters.md#output-parameters)
|
|
224
241
|
- Add `koffi.offsetof()` utility function
|
|
225
242
|
- Support optional *this* binding in `koffi.register()`
|
|
226
243
|
|
|
@@ -270,7 +287,7 @@
|
|
|
270
287
|
|
|
271
288
|
**Main changes:**
|
|
272
289
|
|
|
273
|
-
- Add [koffi.as()](
|
|
290
|
+
- Add [koffi.as()](parameters.md#polymorphic-parameters) to support polymorphic APIs based on `void *` parameters
|
|
274
291
|
- Add [endian-sensitive integer types](types.md#endian-sensitive-types): `intX_le_t`, `intX_be_t`, `uintX_le_t`, `uintX_be_t`
|
|
275
292
|
- Accept typed arrays for `void *` parameters
|
|
276
293
|
- Introduce `koffi.opaque()` to replace `koffi.handle()` (which remains supported until Koffi 3.0)
|
|
@@ -296,7 +313,7 @@
|
|
|
296
313
|
|
|
297
314
|
**Major new features:**
|
|
298
315
|
|
|
299
|
-
- Add [disposable types](
|
|
316
|
+
- Add [disposable types](parameters.md#heap-allocated-values) for automatic disposal of C values (such as heap-allocated strings)
|
|
300
317
|
- Add support for [registered callbacks](callbacks.md#registered-callbacks), that can be called after the initial FFI call
|
|
301
318
|
- Support named pointer types
|
|
302
319
|
- Support complex type specifications outside of prototype parser
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/doc/callbacks.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Callbacks
|
|
2
2
|
|
|
3
|
+
*Changed in Koffi 2.4*
|
|
4
|
+
|
|
5
|
+
```{note}
|
|
6
|
+
The function `koffi.proto()` was introduced in Koffi 2.4, it was called `koffi.callback()` in earlier versions.
|
|
7
|
+
```
|
|
8
|
+
|
|
3
9
|
## Callback types
|
|
4
10
|
|
|
5
11
|
In order to pass a JS function to a C function expecting a callback, you must first create a callback type with the expected return type and parameters. The syntax is similar to the one used to load functions from a shared library.
|
|
@@ -8,10 +14,10 @@ In order to pass a JS function to a C function expecting a callback, you must fi
|
|
|
8
14
|
const koffi = require('koffi');
|
|
9
15
|
|
|
10
16
|
// With the classic syntax, this callback expects an integer and returns nothing
|
|
11
|
-
const ExampleCallback = koffi.
|
|
17
|
+
const ExampleCallback = koffi.proto('ExampleCallback', 'void', ['int']);
|
|
12
18
|
|
|
13
19
|
// With the prototype parser, this callback expects a double and float, and returns the sum as a double
|
|
14
|
-
const AddDoubleFloat = koffi.
|
|
20
|
+
const AddDoubleFloat = koffi.proto('double AddDoubleFloat(double d, float f)');
|
|
15
21
|
```
|
|
16
22
|
|
|
17
23
|
Once your callback type is declared, you can use a pointer to it in struct definitions, or as function parameters and/or return types.
|
|
@@ -56,7 +62,7 @@ int TransferToJS(const char *name, int age, int (*cb)(const char *str, int age))
|
|
|
56
62
|
const koffi = require('koffi');
|
|
57
63
|
const lib = koffi.load('./callbacks.so'); // Fake path
|
|
58
64
|
|
|
59
|
-
const TransferCallback = koffi.
|
|
65
|
+
const TransferCallback = koffi.proto('int TransferCallback(const char *str, int age)');
|
|
60
66
|
|
|
61
67
|
const TransferToJS = lib.func('TransferToJS', 'int', ['str', 'int', koffi.pointer(TransferCallback)]);
|
|
62
68
|
|
|
@@ -104,8 +110,8 @@ void SayIt(const char *name)
|
|
|
104
110
|
const koffi = require('koffi');
|
|
105
111
|
const lib = koffi.load('./callbacks.so'); // Fake path
|
|
106
112
|
|
|
107
|
-
const GetCallback = koffi.
|
|
108
|
-
const PrintCallback = koffi.
|
|
113
|
+
const GetCallback = koffi.proto('const char *GetCallback(const char *name)');
|
|
114
|
+
const PrintCallback = koffi.proto('void PrintCallback(const char *str)');
|
|
109
115
|
|
|
110
116
|
const RegisterFunctions = lib.func('void RegisterFunctions(GetCallback *cb1, PrintCallback *cb2)');
|
|
111
117
|
const SayIt = lib.func('void SayIt(const char *name)');
|
|
@@ -155,7 +161,7 @@ The following example sorts an array of strings (in-place) with `qsort()`:
|
|
|
155
161
|
const koffi = require('koffi');
|
|
156
162
|
const lib = koffi.load('libc.so.6');
|
|
157
163
|
|
|
158
|
-
const SortCallback = koffi.
|
|
164
|
+
const SortCallback = koffi.proto('int SortCallback(const void *first, const void *second)');
|
|
159
165
|
const qsort = lib.func('void qsort(_Inout_ void *array, size_t count, size_t size, SortCallback *cb)');
|
|
160
166
|
|
|
161
167
|
let array = ['foo', 'bar', '123', 'foobar'];
|
package/doc/conf.py
CHANGED
package/doc/functions.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Native functions
|
|
2
2
|
|
|
3
3
|
## Loading libraries
|
|
4
4
|
|
|
@@ -88,3 +88,57 @@ const lib = koffi.load('user32.dll');
|
|
|
88
88
|
const MessageBoxA_1 = lib.stdcall('MessageBoxA', 'int', ['void *', 'str', 'str', 'uint']);
|
|
89
89
|
const MessageBoxA_2 = lib.func('int __stdcall MessageBoxA(void *hwnd, str text, str caption, uint type)');
|
|
90
90
|
```
|
|
91
|
+
|
|
92
|
+
## Function calls
|
|
93
|
+
|
|
94
|
+
### Synchronous calls
|
|
95
|
+
|
|
96
|
+
Once a native function has been declared, you can simply call it as you would any other JS function.
|
|
97
|
+
|
|
98
|
+
```js
|
|
99
|
+
const atoi = lib.func('int atoi(const char *str)');
|
|
100
|
+
|
|
101
|
+
let value = atoi('1257');
|
|
102
|
+
console.log(value);
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
For [variadic functions](functions.md#variadic-functions), you msut specificy the type and the value for each additional argument.
|
|
106
|
+
|
|
107
|
+
```js
|
|
108
|
+
const printf = lib.func('printf', 'int', ['str', '...']);
|
|
109
|
+
|
|
110
|
+
// The variadic arguments are: 6 (int), 8.5 (double), 'THE END' (const char *)
|
|
111
|
+
printf('Integer %d, double %g, str %s', 'int', 6, 'double', 8.5, 'str', 'THE END');
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Asynchronous calls
|
|
115
|
+
|
|
116
|
+
You can issue asynchronous calls by calling the function through its async member. In this case, you need to provide a callback function as the last argument, with `(err, res)` parameters.
|
|
117
|
+
|
|
118
|
+
```js
|
|
119
|
+
const koffi = require('koffi');
|
|
120
|
+
const lib = koffi.load('libc.so.6');
|
|
121
|
+
|
|
122
|
+
const atoi = lib.func('int atoi(const char *str)');
|
|
123
|
+
|
|
124
|
+
atoi.async('1257', (err, res) => {
|
|
125
|
+
console.log('Result:', res);
|
|
126
|
+
})
|
|
127
|
+
console.log('Hello World!');
|
|
128
|
+
|
|
129
|
+
// This program will print:
|
|
130
|
+
// Hello World!
|
|
131
|
+
// Result: 1257
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
These calls are executed by worker threads. It is **your responsibility to deal with data sharing issues** in the native code that may be caused by multi-threading.
|
|
135
|
+
|
|
136
|
+
You can easily convert this callback-style async function to a promise-based version with `util.promisify()` from the Node.js standard library.
|
|
137
|
+
|
|
138
|
+
Variadic functions cannot be called asynchronously.
|
|
139
|
+
|
|
140
|
+
## Thread safety
|
|
141
|
+
|
|
142
|
+
Asynchronous functions run on worker threads. You need to deal with thread safety issues if you share data between threads.
|
|
143
|
+
|
|
144
|
+
Callbacks must be called from the main thread, or more precisely from the same thread as the V8 intepreter. Calling a callback from another thread is undefined behavior, and will likely lead to a crash or a big mess. You've been warned!
|
package/doc/index.rst
CHANGED
package/doc/migration.md
CHANGED
|
@@ -32,7 +32,7 @@ The two versions below illustrate the API difference between Koffi 1.x and Koffi
|
|
|
32
32
|
```js
|
|
33
33
|
// Koffi 1.x
|
|
34
34
|
|
|
35
|
-
const TransferCallback = koffi.
|
|
35
|
+
const TransferCallback = koffi.proto('int TransferCallback(const char *str, int age)');
|
|
36
36
|
|
|
37
37
|
const TransferToJS = lib.func('TransferToJS', 'int', ['str', 'int', TransferCallback]);
|
|
38
38
|
// Equivalent to: const TransferToJS = lib.func('int TransferToJS(str s, int x, TransferCallback cb)');
|
|
@@ -48,7 +48,7 @@ console.log(ret);
|
|
|
48
48
|
```js
|
|
49
49
|
// Koffi 2.x
|
|
50
50
|
|
|
51
|
-
const TransferCallback = koffi.
|
|
51
|
+
const TransferCallback = koffi.proto('int TransferCallback(const char *str, int age)');
|
|
52
52
|
|
|
53
53
|
const TransferToJS = lib.func('TransferToJS', 'int', ['str', 'int', koffi.pointer(TransferCallback)]);
|
|
54
54
|
// Equivalent to: const TransferToJS = lib.func('int TransferToJS(str s, int x, TransferCallback *cb)');
|
|
@@ -63,6 +63,10 @@ console.log(ret);
|
|
|
63
63
|
|
|
64
64
|
Koffi 1.x only supported [transient callbacks](callbacks.md#callbacks), you must use Koffi 2.x for registered callbacks.
|
|
65
65
|
|
|
66
|
+
```{note}
|
|
67
|
+
The function `koffi.proto()` was introduced in Koffi 2.4, it was called `koffi.callback()` in earlier versions.
|
|
68
|
+
```
|
|
69
|
+
|
|
66
70
|
### Opaque types
|
|
67
71
|
|
|
68
72
|
In Koffi 1.x, opaque handles were defined in a way that made them usable directly as parameter and return types, obscuring the underlying pointer. Now, in Koffi 2.0, you must use them through a pointer, and use an array for output parameters.
|
|
@@ -1,57 +1,11 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Special parameters
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## Direction
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Once a native function has been declared, you can simply call it as you would any other JS function.
|
|
8
|
-
|
|
9
|
-
```js
|
|
10
|
-
const atoi = lib.func('int atoi(const char *str)');
|
|
11
|
-
|
|
12
|
-
let value = atoi('1257');
|
|
13
|
-
console.log(value);
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
For [variadic functions](functions.md#variadic-functions), you msut specificy the type and the value for each additional argument.
|
|
17
|
-
|
|
18
|
-
```js
|
|
19
|
-
const printf = lib.func('printf', 'int', ['str', '...']);
|
|
20
|
-
|
|
21
|
-
// The variadic arguments are: 6 (int), 8.5 (double), 'THE END' (const char *)
|
|
22
|
-
printf('Integer %d, double %g, str %s', 'int', 6, 'double', 8.5, 'str', 'THE END');
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
### Asynchronous calls
|
|
26
|
-
|
|
27
|
-
You can issue asynchronous calls by calling the function through its async member. In this case, you need to provide a callback function as the last argument, with `(err, res)` parameters.
|
|
28
|
-
|
|
29
|
-
```js
|
|
30
|
-
const koffi = require('koffi');
|
|
31
|
-
const lib = koffi.load('libc.so.6');
|
|
32
|
-
|
|
33
|
-
const atoi = lib.func('int atoi(const char *str)');
|
|
34
|
-
|
|
35
|
-
atoi.async('1257', (err, res) => {
|
|
36
|
-
console.log('Result:', res);
|
|
37
|
-
})
|
|
38
|
-
console.log('Hello World!');
|
|
39
|
-
|
|
40
|
-
// This program will print:
|
|
41
|
-
// Hello World!
|
|
42
|
-
// Result: 1257
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
These calls are executed by worker threads. It is **your responsibility to deal with data sharing issues** in the native code that may be caused by multi-threading.
|
|
46
|
-
|
|
47
|
-
You can easily convert this callback-style async function to a promise-based version with `util.promisify()` from the Node.js standard library.
|
|
48
|
-
|
|
49
|
-
Variadic functions cannot be called asynchronously.
|
|
5
|
+
By default, Koffi will only forward arguments from Javascript to C. However, many C functions use pointer arguments for output values, or input/output values.
|
|
50
6
|
|
|
51
7
|
## Output parameters
|
|
52
8
|
|
|
53
|
-
By default, Koffi will only forward arguments from Javascript to C. However, many C functions use pointer arguments for output values, or input/output values.
|
|
54
|
-
|
|
55
9
|
For simplicity, and because Javascript only has value semantics for primitive types, Koffi can marshal out (or in/out) two types of parameters:
|
|
56
10
|
|
|
57
11
|
- [Structs](types.md#struct-types) (to/from JS objects)
|
|
@@ -348,7 +302,7 @@ let copy = strdup('Hello!');
|
|
|
348
302
|
console.log(copy); // Prints Hello!
|
|
349
303
|
```
|
|
350
304
|
|
|
351
|
-
When you declare functions with the [prototype-like syntax](functions.md#
|
|
305
|
+
When you declare functions with the [prototype-like syntax](functions.md#definition-syntax), you can either use named disposable types or use the '!' shortcut qualifier with compatibles types, as shown in the example below. This qualifier creates an anonymous disposable type that calls `koffi.free(ptr)`.
|
|
352
306
|
|
|
353
307
|
```js
|
|
354
308
|
const koffi = require('koffi');
|
|
@@ -366,9 +320,3 @@ Disposable types can only be created from pointer or string types.
|
|
|
366
320
|
```{warning}
|
|
367
321
|
Be careful on Windows: if your shared library uses a different CRT (such as msvcrt), the memory could have been allocated by a different malloc/free implementation or heap, resulting in undefined behavior if you use `koffi.free()`.
|
|
368
322
|
```
|
|
369
|
-
|
|
370
|
-
## Thread safety
|
|
371
|
-
|
|
372
|
-
Asynchronous functions run on worker threads. You need to deal with thread safety issues if you share data between threads.
|
|
373
|
-
|
|
374
|
-
Callbacks must be called from the main thread, or more precisely from the same thread as the V8 intepreter. Calling a callback from another thread is undefined behavior, and will likely lead to a crash or a big mess. You've been warned!
|
package/doc/pointers.md
CHANGED
|
@@ -126,13 +126,13 @@ let total = ComputeTotalLength(strings);
|
|
|
126
126
|
console.log(total); // Prints 14
|
|
127
127
|
```
|
|
128
128
|
|
|
129
|
-
By default, just like for objects, array arguments are copied from JS to C but not vice-versa. You can however change the direction as documented in the section on [output parameters](
|
|
129
|
+
By default, just like for objects, array arguments are copied from JS to C but not vice-versa. You can however change the direction as documented in the section on [output parameters](parameters.md#output-parameters).
|
|
130
130
|
|
|
131
131
|
## Disposable types
|
|
132
132
|
|
|
133
133
|
Disposable types allow you to register a function that will automatically called after each C to JS conversion performed by Koffi. This can be used to avoid leaking heap-allocated strings, for example.
|
|
134
134
|
|
|
135
|
-
Read the documentation for [disposable types](
|
|
135
|
+
Read the documentation for [disposable types](parameters.md#heap-allocated-values) on the page about function calls.
|
|
136
136
|
|
|
137
137
|
## Unwrap pointers
|
|
138
138
|
|
package/doc/types.md
CHANGED
|
@@ -142,14 +142,14 @@ const Function2 = lib.func('Function', A, [A]);
|
|
|
142
142
|
|
|
143
143
|
Many C libraries use some kind of object-oriented API, with a pair of functions dedicated to create and delete objects. An obvious example of this can be found in stdio.h, with the opaque `FILE *` pointer. You can open and close files with `fopen()` and `fclose()`, and manipule the opaque pointer with other functions such as `fread()` or `ftell()`.
|
|
144
144
|
|
|
145
|
-
In Koffi, you can manage this with opaque types. Declare the opaque type with `koffi.opaque(name)`, and use a pointer to this type either as a return type or some kind of [output parameter](
|
|
145
|
+
In Koffi, you can manage this with opaque types. Declare the opaque type with `koffi.opaque(name)`, and use a pointer to this type either as a return type or some kind of [output parameter](parameters.md#output-parameters) (with a double pointer).
|
|
146
146
|
|
|
147
147
|
```{note}
|
|
148
148
|
Opaque types **have changed in version 2.0, and again in version 2.1**.
|
|
149
149
|
|
|
150
150
|
In Koffi 1.x, opaque handles were defined in a way that made them usable directly as parameter and return types, obscuring the underlying pointer.
|
|
151
151
|
|
|
152
|
-
Now, you must use them through a pointer, and use an array for output parameters. This is shown in the example below (look for the call to `ConcatNewOut` in the JS part), and is described in the section on [output parameters](
|
|
152
|
+
Now, you must use them through a pointer, and use an array for output parameters. This is shown in the example below (look for the call to `ConcatNewOut` in the JS part), and is described in the section on [output parameters](parameters.md#output-parameters).
|
|
153
153
|
|
|
154
154
|
In addition to this, you should use `koffi.opaque()` (introduced in Koffi 2.1) instead of `koffi.handle()` which is deprecated, and will be removed eventually in Koffi 3.0.
|
|
155
155
|
|
package/package.json
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|