@corpus-core/colibri-tor 1.1.22
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 +90 -0
- package/dist/browser.d.ts +48 -0
- package/dist/browser.js +96 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +24 -0
- package/dist/node.d.ts +34 -0
- package/dist/node.js +275 -0
- package/dist/types.d.ts +39 -0
- package/dist/types.js +23 -0
- package/node_modules/tor-js/README.md +166 -0
- package/node_modules/tor-js/dist/Log.d.ts +24 -0
- package/node_modules/tor-js/dist/Log.d.ts.map +1 -0
- package/node_modules/tor-js/dist/TorClient.d.ts +37 -0
- package/node_modules/tor-js/dist/TorClient.d.ts.map +1 -0
- package/node_modules/tor-js/dist/commonExports.d.ts +6 -0
- package/node_modules/tor-js/dist/commonExports.d.ts.map +1 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-base64/index.d.ts +3 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-base64/index.d.ts.map +1 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-base64/index.js +2139 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-base64/index.js.map +1 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-base64/singleton.d.ts +4 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-base64/singleton.d.ts.map +1 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-base64/singleton.js +2187 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-base64/singleton.js.map +1 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-cdn/index.d.ts +3 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-cdn/index.d.ts.map +1 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-cdn/index.js +2242 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-cdn/index.js.map +1 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-cdn/singleton.d.ts +4 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-cdn/singleton.d.ts.map +1 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-cdn/singleton.js +2290 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-cdn/singleton.js.map +1 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-file/index.d.ts +3 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-file/index.d.ts.map +1 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-file/index.js +2139 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-file/index.js.map +1 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-file/singleton.d.ts +4 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-file/singleton.d.ts.map +1 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-file/singleton.js +2187 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-file/singleton.js.map +1 -0
- package/node_modules/tor-js/dist/helpers.d.ts +7 -0
- package/node_modules/tor-js/dist/helpers.d.ts.map +1 -0
- package/node_modules/tor-js/dist/polyfills.d.ts +1 -0
- package/node_modules/tor-js/dist/polyfills.d.ts.map +1 -0
- package/node_modules/tor-js/dist/singleton.d.ts +24 -0
- package/node_modules/tor-js/dist/singleton.d.ts.map +1 -0
- package/node_modules/tor-js/dist/socketProvider.d.ts +76 -0
- package/node_modules/tor-js/dist/socketProvider.d.ts.map +1 -0
- package/node_modules/tor-js/dist/storage/filesystem.d.ts +18 -0
- package/node_modules/tor-js/dist/storage/filesystem.d.ts.map +1 -0
- package/node_modules/tor-js/dist/storage/index.d.ts +7 -0
- package/node_modules/tor-js/dist/storage/index.d.ts.map +1 -0
- package/node_modules/tor-js/dist/storage/indexeddb.d.ts +14 -0
- package/node_modules/tor-js/dist/storage/indexeddb.d.ts.map +1 -0
- package/node_modules/tor-js/dist/storage/locking.d.ts +15 -0
- package/node_modules/tor-js/dist/storage/locking.d.ts.map +1 -0
- package/node_modules/tor-js/dist/storage/memory.d.ts +13 -0
- package/node_modules/tor-js/dist/storage/memory.d.ts.map +1 -0
- package/node_modules/tor-js/dist/storage/node-deps.d.ts +8 -0
- package/node_modules/tor-js/dist/storage/node-deps.d.ts.map +1 -0
- package/node_modules/tor-js/dist/tor_js_bg.wasm +0 -0
- package/node_modules/tor-js/dist/types.d.ts +41 -0
- package/node_modules/tor-js/dist/types.d.ts.map +1 -0
- package/node_modules/tor-js/dist/wasm-B6es-efC.d.ts +302 -0
- package/node_modules/tor-js/dist/wasm-pkg/tor_js.d.ts +311 -0
- package/node_modules/tor-js/dist/wasm-pkg/tor_js.js +1159 -0
- package/node_modules/tor-js/dist/wasm.d.ts +31 -0
- package/node_modules/tor-js/dist/wasm.d.ts.map +1 -0
- package/node_modules/tor-js/package.json +61 -0
- package/node_modules/tor-js/src/Log.ts +100 -0
- package/node_modules/tor-js/src/TorClient.ts +134 -0
- package/node_modules/tor-js/src/commonExports.ts +7 -0
- package/node_modules/tor-js/src/entryPoints/wasm-base64/index.ts +17 -0
- package/node_modules/tor-js/src/entryPoints/wasm-base64/singleton.ts +7 -0
- package/node_modules/tor-js/src/entryPoints/wasm-cdn/index.ts +155 -0
- package/node_modules/tor-js/src/entryPoints/wasm-cdn/singleton.ts +7 -0
- package/node_modules/tor-js/src/entryPoints/wasm-file/index.ts +19 -0
- package/node_modules/tor-js/src/entryPoints/wasm-file/singleton.ts +7 -0
- package/node_modules/tor-js/src/globals.d.ts +2 -0
- package/node_modules/tor-js/src/helpers.ts +20 -0
- package/node_modules/tor-js/src/polyfills.ts +4 -0
- package/node_modules/tor-js/src/singleton.ts +54 -0
- package/node_modules/tor-js/src/socketProvider.ts +405 -0
- package/node_modules/tor-js/src/storage/filesystem.ts +171 -0
- package/node_modules/tor-js/src/storage/index.ts +21 -0
- package/node_modules/tor-js/src/storage/indexeddb.ts +99 -0
- package/node_modules/tor-js/src/storage/locking.ts +195 -0
- package/node_modules/tor-js/src/storage/memory.ts +42 -0
- package/node_modules/tor-js/src/storage/node-deps.ts +23 -0
- package/node_modules/tor-js/src/types.ts +48 -0
- package/node_modules/tor-js/src/wasm-base64-data.d.ts +3 -0
- package/node_modules/tor-js/src/wasm.ts +135 -0
- package/package.json +67 -0
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# tor-js
|
|
2
|
+
|
|
3
|
+
Make HTTP requests through Tor from JavaScript. Works in browsers and Node.js.
|
|
4
|
+
|
|
5
|
+
Uses [Arti](https://gitlab.torproject.org/tpo/core/arti) (the Tor Project's Rust implementation) compiled to WebAssembly.
|
|
6
|
+
|
|
7
|
+
**[Live Demo](https://voltrevo.github.io/arti/)**
|
|
8
|
+
|
|
9
|
+
## Quick start
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
npm install tor-js
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
```javascript
|
|
16
|
+
import { TorClient } from 'tor-js';
|
|
17
|
+
|
|
18
|
+
const client = new TorClient({
|
|
19
|
+
gateway: 'https://tor-js-gateway.voltrevo.com',
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const response = await client.fetch('https://check.torproject.org/api/ip');
|
|
23
|
+
console.log(await response.json()); // { IsTor: true, IP: "..." }
|
|
24
|
+
|
|
25
|
+
client.close();
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
In Node.js, the gateway is optional (connects via direct TCP):
|
|
29
|
+
|
|
30
|
+
```javascript
|
|
31
|
+
const client = new TorClient();
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Entry points
|
|
35
|
+
|
|
36
|
+
The package offers three ways to load the WASM binary. All export the same API.
|
|
37
|
+
|
|
38
|
+
| Import | WASM loading | Size (gzip) | Best for |
|
|
39
|
+
|---|---|---|---|
|
|
40
|
+
| `tor-js` | Fetched from CDN, cached locally | 16 kB | Production web apps |
|
|
41
|
+
| `tor-js/wasm-base64` | Embedded in the JS bundle | 2.3 MB | Single-file deploys |
|
|
42
|
+
| `tor-js/wasm-file` | Loaded from `tor_js_bg.wasm` next to the module | 15 kB + 1.7 MB | Self-hosted, server-side |
|
|
43
|
+
|
|
44
|
+
Each also has a `/singleton` variant (see [Singleton](#singleton) below).
|
|
45
|
+
|
|
46
|
+
## API
|
|
47
|
+
|
|
48
|
+
### `new TorClient(options)`
|
|
49
|
+
|
|
50
|
+
Creates a Tor client and begins bootstrapping immediately.
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
type TorClientOptions = {
|
|
54
|
+
gateway?: string; // Gateway URL (required in browsers, optional in Node.js/Deno)
|
|
55
|
+
log?: Log; // Logger instance (default: silent)
|
|
56
|
+
storage?: TorStorage; // Persistent storage (default: auto-detected)
|
|
57
|
+
logLevel?: LogLevel; // 'trace' | 'debug' | 'info' | 'warn' | 'error'
|
|
58
|
+
};
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
In browsers, the gateway proxies relay connections via WebRTC or WebSocket. In Node.js/Deno, connections go via direct TCP and the gateway is only used for fast bootstrap (optional).
|
|
62
|
+
|
|
63
|
+
### `client.fetch(url, init?)`
|
|
64
|
+
|
|
65
|
+
Make an HTTP request through Tor. Returns a standard `Response` object.
|
|
66
|
+
|
|
67
|
+
Waits for the client to be fully ready before sending the request.
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
const res = await client.fetch('https://example.com', {
|
|
71
|
+
method: 'POST',
|
|
72
|
+
headers: { 'Content-Type': 'application/json' },
|
|
73
|
+
body: JSON.stringify({ key: 'value' }),
|
|
74
|
+
signal: AbortSignal.timeout(30_000),
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### `client.ready()`
|
|
79
|
+
|
|
80
|
+
Wait for the client to be ready for traffic (guard connected, usable consensus, sufficient microdescs). Called automatically by `fetch()`, but useful to call early if you want to measure bootstrap time or show a loading state.
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
const client = new TorClient({ ... });
|
|
84
|
+
await client.ready();
|
|
85
|
+
console.log('Bootstrap complete');
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### `client.setLogLevel(level)`
|
|
89
|
+
|
|
90
|
+
Change the log level at runtime. Accepts `'trace'`, `'debug'`, `'info'`, `'warn'`, or `'error'`.
|
|
91
|
+
|
|
92
|
+
### `client.close()`
|
|
93
|
+
|
|
94
|
+
Close the client and release resources. Also available as `Symbol.dispose` for use with `using`:
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
{
|
|
98
|
+
using client = new TorClient({ ... });
|
|
99
|
+
await client.fetch('https://example.com');
|
|
100
|
+
} // automatically closed
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Singleton
|
|
104
|
+
|
|
105
|
+
For simple use cases, import the singleton wrapper:
|
|
106
|
+
|
|
107
|
+
```javascript
|
|
108
|
+
import { tor } from 'tor-js/singleton';
|
|
109
|
+
|
|
110
|
+
const response = await tor.fetch('https://check.torproject.org/api/ip');
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
The singleton auto-opens on first `fetch()`. Use `tor.configure(options)` to change settings, or `tor.close()` to shut down.
|
|
114
|
+
|
|
115
|
+
## Storage
|
|
116
|
+
|
|
117
|
+
By default, `TorClient` auto-detects the best storage for the environment:
|
|
118
|
+
|
|
119
|
+
- **Browser**: IndexedDB
|
|
120
|
+
- **Node.js**: `~/.local/share/tor-js/`
|
|
121
|
+
|
|
122
|
+
Cached consensus and microdescriptors are persisted, so subsequent connections bootstrap faster.
|
|
123
|
+
|
|
124
|
+
You can provide your own storage:
|
|
125
|
+
|
|
126
|
+
```javascript
|
|
127
|
+
import { TorClient, storage } from 'tor-js';
|
|
128
|
+
|
|
129
|
+
// Explicit IndexedDB
|
|
130
|
+
const client = new TorClient({
|
|
131
|
+
storage: new storage.IndexedDBStorage('my-app'),
|
|
132
|
+
// ...
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// In-memory (no persistence)
|
|
136
|
+
const client = new TorClient({
|
|
137
|
+
storage: new storage.MemoryStorage(),
|
|
138
|
+
// ...
|
|
139
|
+
});
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Logging
|
|
143
|
+
|
|
144
|
+
Pass a `Log` instance to see bootstrap progress and debug info:
|
|
145
|
+
|
|
146
|
+
```javascript
|
|
147
|
+
import { TorClient, Log } from 'tor-js';
|
|
148
|
+
|
|
149
|
+
const client = new TorClient({
|
|
150
|
+
log: new Log(), // logs to console with timestamps
|
|
151
|
+
logLevel: 'info', // minimum level (default: 'debug')
|
|
152
|
+
// ...
|
|
153
|
+
});
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Custom log sink:
|
|
157
|
+
|
|
158
|
+
```javascript
|
|
159
|
+
const log = new Log({
|
|
160
|
+
rawLog: (level, ...args) => myLogger[level](...args),
|
|
161
|
+
});
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## License
|
|
165
|
+
|
|
166
|
+
MIT OR Apache-2.0
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error';
|
|
2
|
+
interface LogConstructorParams {
|
|
3
|
+
rawLog?: (level: LogLevel, ...args: unknown[]) => void;
|
|
4
|
+
parentStartTime?: number;
|
|
5
|
+
namePrefix?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare class Log {
|
|
8
|
+
private rawLog;
|
|
9
|
+
private parentStartTime;
|
|
10
|
+
private namePrefix;
|
|
11
|
+
constructor(params?: LogConstructorParams);
|
|
12
|
+
child(name: string): Log;
|
|
13
|
+
trace(...args: unknown[]): void;
|
|
14
|
+
debug(...args: unknown[]): void;
|
|
15
|
+
info(...args: unknown[]): void;
|
|
16
|
+
warn(...args: unknown[]): void;
|
|
17
|
+
error(...args: unknown[]): void;
|
|
18
|
+
/** @internal Create a callback for WASM setLogCallback */
|
|
19
|
+
_makeWasmCallback(): (level: string, target: string, message: string) => void;
|
|
20
|
+
private log;
|
|
21
|
+
private defaultRawLog;
|
|
22
|
+
}
|
|
23
|
+
export {};
|
|
24
|
+
//# sourceMappingURL=Log.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Log.d.ts","sourceRoot":"","sources":["../src/Log.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAErE,UAAU,oBAAoB;IAC5B,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IACvD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,GAAG;IACd,OAAO,CAAC,MAAM,CAAgD;IAC9D,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,UAAU,CAAS;gBAEf,MAAM,GAAE,oBAAyB;IAM7C,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG;IASxB,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAI/B,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAI/B,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAI9B,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAI9B,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAI/B,0DAA0D;IAC1D,iBAAiB,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI;IAW7E,OAAO,CAAC,GAAG;IAUX,OAAO,CAAC,aAAa;CAGtB"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { TorClientOptions, FetchInit, LogLevel } from './types.js';
|
|
2
|
+
export declare class TorClient {
|
|
3
|
+
private log;
|
|
4
|
+
private clientPromise;
|
|
5
|
+
private removeLogListener;
|
|
6
|
+
private wasmCallback;
|
|
7
|
+
private closed;
|
|
8
|
+
private readyPromise;
|
|
9
|
+
private socketProvider;
|
|
10
|
+
constructor(options?: TorClientOptions);
|
|
11
|
+
private bootstrap;
|
|
12
|
+
/**
|
|
13
|
+
* Make an HTTP fetch request through Tor.
|
|
14
|
+
* Returns a standard browser Response object.
|
|
15
|
+
*/
|
|
16
|
+
fetch(url: string, init?: FetchInit): Promise<Response>;
|
|
17
|
+
/**
|
|
18
|
+
* Wait for the Tor client to be ready for traffic
|
|
19
|
+
* (guard connected, usable consensus, and sufficient microdescs).
|
|
20
|
+
*
|
|
21
|
+
* Parallel callers share the same underlying promise — a single WS
|
|
22
|
+
* connection failure rejects all waiters. The cached promise is cleared
|
|
23
|
+
* on settle so the next call creates a fresh attempt.
|
|
24
|
+
*/
|
|
25
|
+
ready(): Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* Change the log level for this client's listener.
|
|
28
|
+
* Also re-syncs the global WASM filter to the broadest level across all clients.
|
|
29
|
+
*/
|
|
30
|
+
setLogLevel(level: LogLevel): void;
|
|
31
|
+
/**
|
|
32
|
+
* Close the TorClient and release resources.
|
|
33
|
+
*/
|
|
34
|
+
close(): void;
|
|
35
|
+
[Symbol.dispose](): void;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=TorClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TorClient.d.ts","sourceRoot":"","sources":["../src/TorClient.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAKxE,qBAAa,SAAS;IACpB,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,aAAa,CAAyB;IAC9C,OAAO,CAAC,iBAAiB,CAA6B;IACtD,OAAO,CAAC,YAAY,CAA2E;IAC/F,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,YAAY,CAA8B;IAClD,OAAO,CAAC,cAAc,CAAmC;gBAE7C,OAAO,GAAE,gBAAqB;YAK5B,SAAS;IA0CvB;;;OAGG;IACG,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,QAAQ,CAAC;IAQ7D;;;;;;;OAOG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAkB5B;;;OAGG;IACH,WAAW,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI;IAMlC;;OAEG;IACH,KAAK,IAAI,IAAI;IAWb,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI;CAGzB"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export type { TorClientOptions, FetchInit, TorStorage } from './types.js';
|
|
2
|
+
export { Log, type LogLevel } from './Log.js';
|
|
3
|
+
export * as storage from './storage/index.js';
|
|
4
|
+
export { setWasmUrl } from './wasm.js';
|
|
5
|
+
export { ArtiSocketProvider, ArtiSocket, type ArtiSocketProviderOptions } from './socketProvider.js';
|
|
6
|
+
//# sourceMappingURL=commonExports.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commonExports.d.ts","sourceRoot":"","sources":["../src/commonExports.ts"],"names":[],"mappings":"AAEA,YAAY,EAAE,gBAAgB,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC1E,OAAO,EAAE,GAAG,EAAE,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,KAAK,OAAO,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,KAAK,yBAAyB,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/entryPoints/wasm-base64/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,cAAc,wBAAwB,CAAC"}
|