@bun-win32/shell32 1.0.0 → 1.0.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/index.ts +0 -2
- package/package.json +8 -5
- package/structs/Shell32.ts +6 -79
- package/types/Shell32.ts +2 -29
- package/runtime/extensions.ts +0 -210
package/index.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"author": "Stev Peifer <stev@bell.net>",
|
|
3
3
|
"bugs": {
|
|
4
|
-
"url": "https://github.com/bun-win32/
|
|
4
|
+
"url": "https://github.com/ObscuritySRL/bun-win32/issues"
|
|
5
|
+
},
|
|
6
|
+
"dependencies": {
|
|
7
|
+
"@bun-win32/core": "workspace:*"
|
|
5
8
|
},
|
|
6
9
|
"description": "Zero-dependency, zero-overhead Win32 SHELL32 bindings for Bun (FFI) on Windows.",
|
|
7
10
|
"devDependencies": {
|
|
@@ -17,13 +20,14 @@
|
|
|
17
20
|
"typescript": "^5"
|
|
18
21
|
},
|
|
19
22
|
"private": false,
|
|
20
|
-
"homepage": "https://github.com/bun-win32
|
|
23
|
+
"homepage": "https://github.com/ObscuritySRL/bun-win32#readme",
|
|
21
24
|
"repository": {
|
|
22
25
|
"type": "git",
|
|
23
|
-
"url": "git://github.com/bun-win32
|
|
26
|
+
"url": "git://github.com/ObscuritySRL/bun-win32.git",
|
|
27
|
+
"directory": "packages/shell32"
|
|
24
28
|
},
|
|
25
29
|
"type": "module",
|
|
26
|
-
"version": "1.0.
|
|
30
|
+
"version": "1.0.1",
|
|
27
31
|
"main": "./index.ts",
|
|
28
32
|
"keywords": [
|
|
29
33
|
"bun",
|
|
@@ -37,7 +41,6 @@
|
|
|
37
41
|
],
|
|
38
42
|
"files": [
|
|
39
43
|
"index.ts",
|
|
40
|
-
"runtime/*.ts",
|
|
41
44
|
"structs/*.ts",
|
|
42
45
|
"types/*.ts",
|
|
43
46
|
"README.md"
|
package/structs/Shell32.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { type FFIFunction, FFIType
|
|
1
|
+
import { type FFIFunction, FFIType } from 'bun:ffi';
|
|
2
|
+
import { Win32 } from '@bun-win32/core';
|
|
2
3
|
|
|
3
4
|
import type {
|
|
4
5
|
ASSOC_FILTER,
|
|
@@ -104,85 +105,11 @@ import type {
|
|
|
104
105
|
* Shell32.Preload(['SHGetKnownFolderPath', 'ShellExecuteW']);
|
|
105
106
|
* ```
|
|
106
107
|
*/
|
|
107
|
-
class Shell32 {
|
|
108
|
-
|
|
109
|
-
* Lazily binds a single `shell32.dll` export and memoizes it on the class.
|
|
110
|
-
*
|
|
111
|
-
* If the symbol has already been bound (property is non-configurable), this is a no-op.
|
|
112
|
-
* Subsequent calls go directly through the memoized native function.
|
|
113
|
-
*
|
|
114
|
-
* @param method Exact export name from `Symbols`.
|
|
115
|
-
* @returns The bound native function, typed to the corresponding static method.
|
|
116
|
-
* @example
|
|
117
|
-
* ```ts
|
|
118
|
-
* // Internal usage: public wrappers call Load on first invocation
|
|
119
|
-
* // return Shell32.Load('SHGetKnownFolderPath')();
|
|
120
|
-
* ```
|
|
121
|
-
*/
|
|
122
|
-
private static Load<T extends keyof typeof Shell32.Symbols>(method: T): (typeof Shell32)[T] {
|
|
123
|
-
const skip = Object.getOwnPropertyDescriptor(Shell32, method)?.configurable === false;
|
|
124
|
-
|
|
125
|
-
if (skip) {
|
|
126
|
-
return Shell32[method];
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
const library = dlopen('shell32.dll', { [method]: Shell32.Symbols[method] });
|
|
130
|
-
|
|
131
|
-
const propertyDescriptor = { configurable: false, value: library.symbols[method] };
|
|
132
|
-
Object.defineProperty(Shell32, method, propertyDescriptor);
|
|
133
|
-
|
|
134
|
-
return Shell32[method];
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Eagerly binds one or more `shell32.dll` exports in a single `dlopen` call.
|
|
139
|
-
*
|
|
140
|
-
* When called with no arguments, every symbol in `Symbols` is bound.
|
|
141
|
-
* Already-bound symbols are skipped.
|
|
142
|
-
*
|
|
143
|
-
* @param methods Optional list of export names to preload. Defaults to all symbols.
|
|
144
|
-
* @example
|
|
145
|
-
* ```ts
|
|
146
|
-
* // Preload specific hot-path symbols
|
|
147
|
-
* Shell32.Preload(['ShellExecuteW', 'SHGetKnownFolderPath', 'SHGetFileInfoW']);
|
|
148
|
-
*
|
|
149
|
-
* // Or preload everything
|
|
150
|
-
* Shell32.Preload();
|
|
151
|
-
* ```
|
|
152
|
-
*/
|
|
153
|
-
public static Preload(methods?: (keyof typeof Shell32.Symbols)[]): void {
|
|
154
|
-
methods ??= Object.keys(Shell32.Symbols) as (keyof typeof Shell32.Symbols)[];
|
|
155
|
-
|
|
156
|
-
const symbols = Object.fromEntries(
|
|
157
|
-
methods
|
|
158
|
-
.filter((method) => Object.getOwnPropertyDescriptor(Shell32, method)?.configurable !== false)
|
|
159
|
-
.map((method) => [method, Shell32.Symbols[method]])
|
|
160
|
-
);
|
|
161
|
-
|
|
162
|
-
const library = dlopen('shell32.dll', symbols);
|
|
163
|
-
|
|
164
|
-
const propertyDescriptorMap = Object.fromEntries(
|
|
165
|
-
Object.entries(library.symbols).map(([key, value]) => [key, { configurable: false, value }])
|
|
166
|
-
);
|
|
167
|
-
|
|
168
|
-
Object.defineProperties(Shell32, propertyDescriptorMap);
|
|
169
|
-
}
|
|
108
|
+
class Shell32 extends Win32 {
|
|
109
|
+
protected static override name = 'shell32.dll';
|
|
170
110
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
//
|
|
174
|
-
// FFIType reference:
|
|
175
|
-
// FFIType.i32 → BOOL, int, LONG, HRESULT
|
|
176
|
-
// FFIType.u32 → DWORD, UINT, ULONG
|
|
177
|
-
// FFIType.u64 → HANDLE, HWND, HICON, HDROP, HINSTANCE, HKEY (returned as bigint)
|
|
178
|
-
// FFIType.i64 → INT_PTR, LPARAM, LRESULT
|
|
179
|
-
// FFIType.ptr → any pointer parameter (LPVOID, LPWSTR, LPCWSTR, PIDLIST_ABSOLUTE, etc.)
|
|
180
|
-
// FFIType.void → void return
|
|
181
|
-
//
|
|
182
|
-
// Consult the Win32 docs for each function's exact signature:
|
|
183
|
-
// https://learn.microsoft.com/en-us/windows/win32/api/{header}/nf-{header}-{functionname}
|
|
184
|
-
// ---------------------------------------------------------------------------
|
|
185
|
-
private static readonly Symbols = {
|
|
111
|
+
/** @inheritdoc */
|
|
112
|
+
protected static override readonly Symbols = {
|
|
186
113
|
AssocCreateForClasses: { args: [FFIType.ptr, FFIType.u32, FFIType.ptr, FFIType.ptr], returns: FFIType.i32 },
|
|
187
114
|
AssocGetDetailsOfPropKey: { args: [FFIType.ptr, FFIType.ptr, FFIType.ptr, FFIType.ptr, FFIType.ptr], returns: FFIType.i32 },
|
|
188
115
|
CDefFolderMenu_Create2: { args: [FFIType.ptr, FFIType.u64, FFIType.u32, FFIType.ptr, FFIType.ptr, FFIType.ptr, FFIType.u32, FFIType.ptr, FFIType.ptr], returns: FFIType.i32 },
|
package/types/Shell32.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { Pointer } from 'bun:ffi';
|
|
2
2
|
|
|
3
|
+
export type { ACCESS_MASK, BOOL, BOOLEAN, BYTE, CHAR, DWORD, DWORD_PTR, HANDLE, HINSTANCE, HMODULE, HRESULT, HWND, INT, INT_PTR, LONG, LONG_PTR, LPARAM, LPBOOL, LPBYTE, LPCSTR, LPCVOID, LPCWSTR, LPDWORD, LPHANDLE, LPSECURITY_ATTRIBUTES, LPSTR, LPVOID, LPWSTR, LRESULT, NULL, PBYTE, PDWORD, PHANDLE, PULONG, PVOID, SHORT, SIZE_T, UINT, UINT_PTR, ULONG, ULONG_PTR, USHORT, VOID, WCHAR, WORD, WPARAM } from '@bun-win32/core';
|
|
4
|
+
|
|
3
5
|
// ---------------------------------------------------------------------------
|
|
4
6
|
// Win32 type aliases
|
|
5
7
|
//
|
|
@@ -398,40 +400,24 @@ export enum StockIconId {
|
|
|
398
400
|
}
|
|
399
401
|
|
|
400
402
|
export type ASSOC_FILTER = number;
|
|
401
|
-
export type BOOL = number;
|
|
402
|
-
export type DWORD = number;
|
|
403
|
-
export type DWORD_PTR = bigint;
|
|
404
403
|
export type GETPROPERTYSTOREFLAGS = number;
|
|
405
|
-
export type HANDLE = bigint;
|
|
406
404
|
export type HDROP = bigint;
|
|
407
405
|
export type HICON = bigint;
|
|
408
406
|
export type HIMAGELIST = bigint;
|
|
409
|
-
export type HINSTANCE = bigint;
|
|
410
407
|
export type HKEY = bigint;
|
|
411
408
|
export type HMENU = bigint;
|
|
412
409
|
export type HPSXA = bigint;
|
|
413
|
-
export type HRESULT = number;
|
|
414
|
-
export type HWND = bigint;
|
|
415
|
-
export type INT = number;
|
|
416
|
-
export type INT_PTR = bigint;
|
|
417
|
-
export type LONG = number;
|
|
418
|
-
export type LPARAM = bigint;
|
|
419
410
|
export type LPAUTO_SCROLL_DATA = Pointer;
|
|
420
411
|
export type LPBROWSEINFOA = Pointer;
|
|
421
412
|
export type LPBROWSEINFOW = Pointer;
|
|
422
413
|
export type LPCITEMIDLIST = Pointer;
|
|
423
414
|
export type LPCSFV = Pointer;
|
|
424
415
|
export type LPCSHITEMID = Pointer;
|
|
425
|
-
export type LPCSTR = Pointer;
|
|
426
|
-
export type LPCVOID = Pointer;
|
|
427
|
-
export type LPCWSTR = Pointer;
|
|
428
|
-
export type LPDWORD = Pointer;
|
|
429
416
|
export type LPFNADDPROPSHEETPAGE = Pointer;
|
|
430
417
|
export type LPFNDFMCALLBACK = Pointer;
|
|
431
418
|
export type LPITEMIDLIST = Pointer;
|
|
432
419
|
export type LPPOINT = Pointer;
|
|
433
420
|
export type LPRECT = Pointer;
|
|
434
|
-
export type LPSECURITY_ATTRIBUTES = Pointer;
|
|
435
421
|
export type LPSHCREATEPROCESSINFOW = Pointer;
|
|
436
422
|
export type LPSHELLEXECUTEINFOA = Pointer;
|
|
437
423
|
export type LPSHELLEXECUTEINFOW = Pointer;
|
|
@@ -443,11 +429,7 @@ export type LPSHFILEOPSTRUCTA = Pointer;
|
|
|
443
429
|
export type LPSHFILEOPSTRUCTW = Pointer;
|
|
444
430
|
export type LPSHELLFLAGSTATE = Pointer;
|
|
445
431
|
export type LPSHSTOCKICONINFO = Pointer;
|
|
446
|
-
export type LPSTR = Pointer;
|
|
447
|
-
export type LPVOID = Pointer;
|
|
448
432
|
export type LPWORD = Pointer;
|
|
449
|
-
export type LPWSTR = Pointer;
|
|
450
|
-
export type LRESULT = bigint;
|
|
451
433
|
export type PAPPBARDATA = Pointer;
|
|
452
434
|
export type PCABINETSTATE = Pointer;
|
|
453
435
|
export type PCDEFCONTEXTMENU = Pointer;
|
|
@@ -472,15 +454,6 @@ export type PUITEMID_CHILD = Pointer;
|
|
|
472
454
|
export type PWSTR = Pointer;
|
|
473
455
|
export type SFGAOF = number;
|
|
474
456
|
export type SIGDN = number;
|
|
475
|
-
export type SIZE_T = bigint;
|
|
476
|
-
export type UINT = number;
|
|
477
|
-
export type UINT_PTR = bigint;
|
|
478
|
-
export type ULONG = number;
|
|
479
|
-
export type VOID = void;
|
|
480
|
-
export type WCHAR = number;
|
|
481
|
-
export type WORD = number;
|
|
482
|
-
|
|
483
|
-
export type NULL = null;
|
|
484
457
|
|
|
485
458
|
/**
|
|
486
459
|
* A POINT struct packed into a 64-bit integer for by-value passing in the x64 ABI.
|
package/runtime/extensions.ts
DELETED
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
import { type Pointer, ptr } from 'bun:ffi';
|
|
2
|
-
|
|
3
|
-
declare global {
|
|
4
|
-
/**
|
|
5
|
-
* Adds a native pointer property to all ArrayBuffer, Buffer, DataView, and TypedArray types.
|
|
6
|
-
*
|
|
7
|
-
* The `ptr` property returns a native pointer usable with Bun FFI.
|
|
8
|
-
*
|
|
9
|
-
* @example
|
|
10
|
-
* ```ts
|
|
11
|
-
* const arr = new Uint8Array([1, 2, 3]);
|
|
12
|
-
* nativeFunction(arr.ptr, arr.length);
|
|
13
|
-
* ```
|
|
14
|
-
*/
|
|
15
|
-
interface ArrayBuffer {
|
|
16
|
-
/**
|
|
17
|
-
* Native pointer to ArrayBuffer memory for Bun FFI.
|
|
18
|
-
* @example
|
|
19
|
-
* ```ts
|
|
20
|
-
* const buf = new ArrayBuffer(8);
|
|
21
|
-
* nativeFunction(buf.ptr, buf.byteLength);
|
|
22
|
-
* ```
|
|
23
|
-
*/
|
|
24
|
-
readonly ptr: Pointer;
|
|
25
|
-
}
|
|
26
|
-
interface BigInt64Array {
|
|
27
|
-
/**
|
|
28
|
-
* Native pointer to BigInt64Array memory for Bun FFI.
|
|
29
|
-
* @example
|
|
30
|
-
* ```ts
|
|
31
|
-
* const arr = new BigInt64Array([1n, 2n]);
|
|
32
|
-
* nativeFunction(arr.ptr, arr.length);
|
|
33
|
-
* ```
|
|
34
|
-
*/
|
|
35
|
-
readonly ptr: Pointer;
|
|
36
|
-
}
|
|
37
|
-
interface BigUint64Array {
|
|
38
|
-
/**
|
|
39
|
-
* Native pointer to BigUint64Array memory for Bun FFI.
|
|
40
|
-
* @example
|
|
41
|
-
* ```ts
|
|
42
|
-
* const arr = new BigUint64Array([1n, 2n]);
|
|
43
|
-
* nativeFunction(arr.ptr, arr.length);
|
|
44
|
-
* ```
|
|
45
|
-
*/
|
|
46
|
-
readonly ptr: Pointer;
|
|
47
|
-
}
|
|
48
|
-
interface Buffer {
|
|
49
|
-
/**
|
|
50
|
-
* Native pointer to Buffer memory for Bun FFI.
|
|
51
|
-
* @example
|
|
52
|
-
* ```ts
|
|
53
|
-
* const buf = Buffer.from([1, 2, 3]);
|
|
54
|
-
* nativeFunction(buf.ptr, buf.length);
|
|
55
|
-
* ```
|
|
56
|
-
*/
|
|
57
|
-
readonly ptr: Pointer;
|
|
58
|
-
}
|
|
59
|
-
interface DataView {
|
|
60
|
-
/**
|
|
61
|
-
* Native pointer to DataView memory for Bun FFI.
|
|
62
|
-
* @example
|
|
63
|
-
* ```ts
|
|
64
|
-
* const view = new DataView(new ArrayBuffer(4));
|
|
65
|
-
* nativeFunction(view.ptr, view.byteLength);
|
|
66
|
-
* ```
|
|
67
|
-
*/
|
|
68
|
-
readonly ptr: Pointer;
|
|
69
|
-
}
|
|
70
|
-
interface Float32Array {
|
|
71
|
-
/**
|
|
72
|
-
* Native pointer to Float32Array memory for Bun FFI.
|
|
73
|
-
* @example
|
|
74
|
-
* ```ts
|
|
75
|
-
* const arr = new Float32Array([1, 2, 3]);
|
|
76
|
-
* nativeFunction(arr.ptr, arr.length);
|
|
77
|
-
* ```
|
|
78
|
-
*/
|
|
79
|
-
readonly ptr: Pointer;
|
|
80
|
-
}
|
|
81
|
-
interface Float64Array {
|
|
82
|
-
/**
|
|
83
|
-
* Native pointer to Float64Array memory for Bun FFI.
|
|
84
|
-
* @example
|
|
85
|
-
* ```ts
|
|
86
|
-
* const arr = new Float64Array([1, 2, 3]);
|
|
87
|
-
* nativeFunction(arr.ptr, arr.length);
|
|
88
|
-
* ```
|
|
89
|
-
*/
|
|
90
|
-
readonly ptr: Pointer;
|
|
91
|
-
}
|
|
92
|
-
interface Int16Array {
|
|
93
|
-
/**
|
|
94
|
-
* Native pointer to Int16Array memory for Bun FFI.
|
|
95
|
-
* @example
|
|
96
|
-
* ```ts
|
|
97
|
-
* const arr = new Int16Array([1, 2, 3]);
|
|
98
|
-
* nativeFunction(arr.ptr, arr.length);
|
|
99
|
-
* ```
|
|
100
|
-
*/
|
|
101
|
-
readonly ptr: Pointer;
|
|
102
|
-
}
|
|
103
|
-
interface Int32Array {
|
|
104
|
-
/**
|
|
105
|
-
* Native pointer to Int32Array memory for Bun FFI.
|
|
106
|
-
* @example
|
|
107
|
-
* ```ts
|
|
108
|
-
* const arr = new Int32Array([1, 2, 3]);
|
|
109
|
-
* nativeFunction(arr.ptr, arr.length);
|
|
110
|
-
* ```
|
|
111
|
-
*/
|
|
112
|
-
readonly ptr: Pointer;
|
|
113
|
-
}
|
|
114
|
-
interface Int8Array {
|
|
115
|
-
/**
|
|
116
|
-
* Native pointer to Int8Array memory for Bun FFI.
|
|
117
|
-
* @example
|
|
118
|
-
* ```ts
|
|
119
|
-
* const arr = new Int8Array([1, 2, 3]);
|
|
120
|
-
* nativeFunction(arr.ptr, arr.length);
|
|
121
|
-
* ```
|
|
122
|
-
*/
|
|
123
|
-
readonly ptr: Pointer;
|
|
124
|
-
}
|
|
125
|
-
interface SharedArrayBuffer {
|
|
126
|
-
/**
|
|
127
|
-
* Native pointer to SharedArrayBuffer memory for Bun FFI.
|
|
128
|
-
* @example
|
|
129
|
-
* ```ts
|
|
130
|
-
* const buf = new SharedArrayBuffer(8);
|
|
131
|
-
* nativeFunction(buf.ptr, buf.byteLength);
|
|
132
|
-
* ```
|
|
133
|
-
*/
|
|
134
|
-
readonly ptr: Pointer;
|
|
135
|
-
}
|
|
136
|
-
interface Uint16Array {
|
|
137
|
-
/**
|
|
138
|
-
* Native pointer to Uint16Array memory for Bun FFI.
|
|
139
|
-
* @example
|
|
140
|
-
* ```ts
|
|
141
|
-
* const arr = new Uint16Array([1, 2, 3]);
|
|
142
|
-
* nativeFunction(arr.ptr, arr.length);
|
|
143
|
-
* ```
|
|
144
|
-
*/
|
|
145
|
-
readonly ptr: Pointer;
|
|
146
|
-
}
|
|
147
|
-
interface Uint32Array {
|
|
148
|
-
/**
|
|
149
|
-
* Native pointer to Uint32Array memory for Bun FFI.
|
|
150
|
-
* @example
|
|
151
|
-
* ```ts
|
|
152
|
-
* const arr = new Uint32Array([1, 2, 3]);
|
|
153
|
-
* nativeFunction(arr.ptr, arr.length);
|
|
154
|
-
* ```
|
|
155
|
-
*/
|
|
156
|
-
readonly ptr: Pointer;
|
|
157
|
-
}
|
|
158
|
-
interface Uint8Array {
|
|
159
|
-
/**
|
|
160
|
-
* Native pointer to Uint8Array memory for Bun FFI.
|
|
161
|
-
* @example
|
|
162
|
-
* ```ts
|
|
163
|
-
* const arr = new Uint8Array([1, 2, 3]);
|
|
164
|
-
* nativeFunction(arr.ptr, arr.length);
|
|
165
|
-
* ```
|
|
166
|
-
*/
|
|
167
|
-
readonly ptr: Pointer;
|
|
168
|
-
}
|
|
169
|
-
interface Uint8ClampedArray {
|
|
170
|
-
/**
|
|
171
|
-
* Native pointer to Uint8ClampedArray memory for Bun FFI.
|
|
172
|
-
* @example
|
|
173
|
-
* ```ts
|
|
174
|
-
* const arr = new Uint8ClampedArray([1, 2, 3]);
|
|
175
|
-
* nativeFunction(arr.ptr, arr.length);
|
|
176
|
-
* ```
|
|
177
|
-
*/
|
|
178
|
-
readonly ptr: Pointer;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Installs the `ptr` property on all supported binary view prototypes.
|
|
184
|
-
*
|
|
185
|
-
* The property is non-enumerable and non-configurable. The getter calls `ptr(this)`.
|
|
186
|
-
*/
|
|
187
|
-
const constructors = [ArrayBuffer, BigInt64Array, BigUint64Array, Buffer, DataView, Float32Array, Float64Array, Int16Array, Int32Array, Int8Array, SharedArrayBuffer, Uint16Array, Uint32Array, Uint8Array, Uint8ClampedArray] as const;
|
|
188
|
-
|
|
189
|
-
constructors.forEach(
|
|
190
|
-
({ prototype }) =>
|
|
191
|
-
!Object.getOwnPropertyDescriptor(prototype, 'ptr') &&
|
|
192
|
-
Object.defineProperty(prototype, 'ptr', {
|
|
193
|
-
configurable: false,
|
|
194
|
-
enumerable: false,
|
|
195
|
-
/**
|
|
196
|
-
* Returns a native pointer to the underlying memory.
|
|
197
|
-
* @returns Native pointer for Bun FFI.
|
|
198
|
-
* @example
|
|
199
|
-
* ```ts
|
|
200
|
-
* const arr = new Uint8Array([1, 2, 3]);
|
|
201
|
-
* nativeFunction(arr.ptr, arr.length);
|
|
202
|
-
* ```
|
|
203
|
-
*/
|
|
204
|
-
get(this): Pointer {
|
|
205
|
-
return ptr(this);
|
|
206
|
-
},
|
|
207
|
-
})
|
|
208
|
-
);
|
|
209
|
-
|
|
210
|
-
export {};
|