cloakbrowser 0.3.32 → 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 +26 -7
- package/dist/config.d.ts +4 -3
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +46 -12
- package/dist/config.js.map +1 -1
- package/dist/download.d.ts +64 -2
- package/dist/download.d.ts.map +1 -1
- package/dist/download.js +387 -19
- package/dist/download.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/license.d.ts +31 -0
- package/dist/license.d.ts.map +1 -0
- package/dist/license.js +179 -0
- package/dist/license.js.map +1 -0
- package/dist/playwright.d.ts +0 -7
- package/dist/playwright.d.ts.map +1 -1
- package/dist/playwright.js +49 -4
- package/dist/playwright.js.map +1 -1
- package/dist/puppeteer.d.ts.map +1 -1
- package/dist/puppeteer.js +21 -2
- package/dist/puppeteer.js.map +1 -1
- package/dist/types.d.ts +5 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -231,11 +231,30 @@ const page = await browser.newPage();
|
|
|
231
231
|
|
|
232
232
|
| Platform | Chromium | Patches | Status |
|
|
233
233
|
|---|---|---|---|
|
|
234
|
-
| Linux x86_64 |
|
|
235
|
-
| Linux arm64 (RPi, Graviton) |
|
|
236
|
-
| macOS arm64 (Apple Silicon) | 145 | 26 | ✅
|
|
237
|
-
| macOS x86_64 (Intel) | 145 | 26 | ✅
|
|
238
|
-
| Windows x86_64 |
|
|
234
|
+
| Linux x86_64 | 146 | 58 | ✅ Latest |
|
|
235
|
+
| Linux arm64 (RPi, Graviton) | 146 | 58 | ✅ |
|
|
236
|
+
| macOS arm64 (Apple Silicon) | 145 | 26 | ✅ |
|
|
237
|
+
| macOS x86_64 (Intel) | 145 | 26 | ✅ |
|
|
238
|
+
| Windows x86_64 | 146 | 58 | ✅ Latest |
|
|
239
|
+
|
|
240
|
+
## CloakBrowser Pro
|
|
241
|
+
|
|
242
|
+
The wrapper (Python + JS) is MIT, free forever. The binary uses a delayed
|
|
243
|
+
free-release model:
|
|
244
|
+
|
|
245
|
+
- **Free (v146)** — free forever on [GitHub Releases](https://github.com/CloakHQ/cloakbrowser/releases). Unlimited sessions. Works today, goes stale as detection evolves.
|
|
246
|
+
- **Pro (latest, v148)** — the newest patches and Chromium upgrades first, so the [test results](#test-results) stay green as anti-bot systems change. Linux + Windows (macOS coming).
|
|
247
|
+
|
|
248
|
+
Anti-bot detection updates constantly — an older binary degrades within weeks.
|
|
249
|
+
Pro keeps you on the build that's actively maintained against it.
|
|
250
|
+
|
|
251
|
+
Activate with your license key (env var, `licenseKey` option, or `~/.cloakbrowser/license.key`):
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
export CLOAKBROWSER_LICENSE_KEY=cb_xxxxxxxx
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Pro plans → **[cloakbrowser.dev](https://cloakbrowser.dev)**
|
|
239
258
|
|
|
240
259
|
## Requirements
|
|
241
260
|
|
|
@@ -294,13 +313,13 @@ Other tips for maximizing reCAPTCHA scores:
|
|
|
294
313
|
When auto-update downloads a newer binary, the previous version stays in `~/.cloakbrowser/`. Point `CLOAKBROWSER_BINARY_PATH` to the older cached binary:
|
|
295
314
|
```bash
|
|
296
315
|
# Linux
|
|
297
|
-
export CLOAKBROWSER_BINARY_PATH=~/.cloakbrowser/chromium-
|
|
316
|
+
export CLOAKBROWSER_BINARY_PATH=~/.cloakbrowser/chromium-146.0.7680.177.4/chrome
|
|
298
317
|
|
|
299
318
|
# macOS
|
|
300
319
|
export CLOAKBROWSER_BINARY_PATH=~/.cloakbrowser/chromium-145.0.7632.109.2/Chromium.app/Contents/MacOS/Chromium
|
|
301
320
|
|
|
302
321
|
# Windows
|
|
303
|
-
set CLOAKBROWSER_BINARY_PATH=%USERPROFILE%\.cloakbrowser\chromium-
|
|
322
|
+
set CLOAKBROWSER_BINARY_PATH=%USERPROFILE%\.cloakbrowser\chromium-146.0.7680.177.4\chrome.exe
|
|
304
323
|
```
|
|
305
324
|
|
|
306
325
|
## Links
|
package/dist/config.d.ts
CHANGED
|
@@ -6,11 +6,12 @@ declare let WRAPPER_VERSION: string;
|
|
|
6
6
|
export { WRAPPER_VERSION };
|
|
7
7
|
export declare const CHROMIUM_VERSION = "146.0.7680.177.5";
|
|
8
8
|
export declare const PLATFORM_CHROMIUM_VERSIONS: Record<string, string>;
|
|
9
|
+
export declare const BINARY_SIGNING_PUBKEYS: string[];
|
|
9
10
|
export declare function getChromiumVersion(): string;
|
|
10
11
|
export declare function getPlatformTag(): string;
|
|
11
12
|
export declare function getCacheDir(): string;
|
|
12
|
-
export declare function getBinaryDir(version?: string): string;
|
|
13
|
-
export declare function getBinaryPath(version?: string): string;
|
|
13
|
+
export declare function getBinaryDir(version?: string, pro?: boolean): string;
|
|
14
|
+
export declare function getBinaryPath(version?: string, pro?: boolean): string;
|
|
14
15
|
export declare function checkPlatformAvailable(): void;
|
|
15
16
|
export declare const DOWNLOAD_BASE_URL: string;
|
|
16
17
|
export declare const GITHUB_API_URL = "https://api.github.com/repos/CloakHQ/cloakbrowser/releases";
|
|
@@ -19,7 +20,7 @@ export declare function getArchiveExt(): string;
|
|
|
19
20
|
export declare function getArchiveName(tag?: string): string;
|
|
20
21
|
export declare function getDownloadUrl(version?: string): string;
|
|
21
22
|
export declare function getFallbackDownloadUrl(version?: string): string;
|
|
22
|
-
export declare function getEffectiveVersion(): string;
|
|
23
|
+
export declare function getEffectiveVersion(pro?: boolean): string;
|
|
23
24
|
export declare function parseVersion(v: string): number[];
|
|
24
25
|
export declare function versionNewer(a: string, b: string): boolean;
|
|
25
26
|
export declare function getLocalBinaryOverride(): string | undefined;
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,QAAA,IAAI,eAAe,QAAU,CAAC;AAU9B,OAAO,EAAE,eAAe,EAAE,CAAC;AAQ3B,eAAO,MAAM,gBAAgB,qBAAqB,CAAC;AAEnD,eAAO,MAAM,0BAA0B,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAM7D,CAAC;AAgBF,wBAAgB,kBAAkB,IAAI,MAAM,CAG3C;AAED,wBAAgB,cAAc,IAAI,MAAM,CAmBvC;AAKD,wBAAgB,WAAW,IAAI,MAAM,CAIpC;AAED,wBAAgB,YAAY,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,QAAA,IAAI,eAAe,QAAU,CAAC;AAU9B,OAAO,EAAE,eAAe,EAAE,CAAC;AAQ3B,eAAO,MAAM,gBAAgB,qBAAqB,CAAC;AAEnD,eAAO,MAAM,0BAA0B,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAM7D,CAAC;AAWF,eAAO,MAAM,sBAAsB,EAAE,MAAM,EAE1C,CAAC;AAgBF,wBAAgB,kBAAkB,IAAI,MAAM,CAG3C;AAED,wBAAgB,cAAc,IAAI,MAAM,CAmBvC;AAKD,wBAAgB,WAAW,IAAI,MAAM,CAIpC;AAED,wBAAgB,YAAY,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,UAAQ,GAAG,MAAM,CAGlE;AAED,wBAAgB,aAAa,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,UAAQ,GAAG,MAAM,CASnE;AAED,wBAAgB,sBAAsB,IAAI,IAAI,CAW7C;AAKD,eAAO,MAAM,iBAAiB,QAEF,CAAC;AAE7B,eAAO,MAAM,cAAc,+DACmC,CAAC;AAE/D,eAAO,MAAM,wBAAwB,8DACwB,CAAC;AAE9D,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,wBAAgB,cAAc,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,wBAAgB,cAAc,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAGvD;AAED,wBAAgB,sBAAsB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAG/D;AAED,wBAAgB,mBAAmB,CAAC,GAAG,UAAQ,GAAG,MAAM,CAwCvD;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAEhD;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAQ1D;AAKD,wBAAgB,sBAAsB,IAAI,MAAM,GAAG,SAAS,CAE3D;AAQD,eAAO,MAAM,mBAAmB,UAAyD,CAAC;AAU1F,eAAO,MAAM,gBAAgB;;;CAA+B,CAAC;AAE7D,wBAAgB,qBAAqB,IAAI,MAAM,EAAE,CAmBhD"}
|
package/dist/config.js
CHANGED
|
@@ -34,6 +34,18 @@ export const PLATFORM_CHROMIUM_VERSIONS = {
|
|
|
34
34
|
"windows-x64": "146.0.7680.177.5",
|
|
35
35
|
};
|
|
36
36
|
// ---------------------------------------------------------------------------
|
|
37
|
+
// Ed25519 public keys for verifying downloaded binaries.
|
|
38
|
+
//
|
|
39
|
+
// Each release publishes SHA256SUMS and a detached signature SHA256SUMS.sig.
|
|
40
|
+
// The wrapper verifies that signature against the keys below before trusting
|
|
41
|
+
// any hash in the manifest, so the download origin alone cannot certify a
|
|
42
|
+
// tampered binary. Values are base64 of the 32-byte raw public key. Multiple
|
|
43
|
+
// entries are accepted to allow key rotation. Keep in parity with config.py.
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
export const BINARY_SIGNING_PUBKEYS = [
|
|
46
|
+
"MKFKwIhUcKWq5xTuNA0Ovg99njcDEcEJvmWYYhApvaU=",
|
|
47
|
+
];
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
37
49
|
// Platform detection
|
|
38
50
|
// ---------------------------------------------------------------------------
|
|
39
51
|
const SUPPORTED_PLATFORMS = {
|
|
@@ -79,11 +91,12 @@ export function getCacheDir() {
|
|
|
79
91
|
return custom;
|
|
80
92
|
return path.join(os.homedir(), ".cloakbrowser");
|
|
81
93
|
}
|
|
82
|
-
export function getBinaryDir(version) {
|
|
83
|
-
|
|
94
|
+
export function getBinaryDir(version, pro = false) {
|
|
95
|
+
const suffix = pro ? "-pro" : "";
|
|
96
|
+
return path.join(getCacheDir(), `chromium-${version || getChromiumVersion()}${suffix}`);
|
|
84
97
|
}
|
|
85
|
-
export function getBinaryPath(version) {
|
|
86
|
-
const binaryDir = getBinaryDir(version);
|
|
98
|
+
export function getBinaryPath(version, pro = false) {
|
|
99
|
+
const binaryDir = getBinaryDir(version, pro);
|
|
87
100
|
if (process.platform === "darwin") {
|
|
88
101
|
return path.join(binaryDir, "Chromium.app", "Contents", "MacOS", "Chromium");
|
|
89
102
|
}
|
|
@@ -123,10 +136,28 @@ export function getFallbackDownloadUrl(version) {
|
|
|
123
136
|
const v = version || getChromiumVersion();
|
|
124
137
|
return `${GITHUB_DOWNLOAD_BASE_URL}/chromium-v${v}/${getArchiveName()}`;
|
|
125
138
|
}
|
|
126
|
-
export function getEffectiveVersion() {
|
|
139
|
+
export function getEffectiveVersion(pro = false) {
|
|
127
140
|
const base = getChromiumVersion();
|
|
128
141
|
const cacheDir = getCacheDir();
|
|
129
|
-
|
|
142
|
+
if (pro) {
|
|
143
|
+
const marker = path.join(cacheDir, `latest_pro_version_${getPlatformTag()}`);
|
|
144
|
+
try {
|
|
145
|
+
if (fs.existsSync(marker)) {
|
|
146
|
+
const version = fs.readFileSync(marker, "utf-8").trim();
|
|
147
|
+
if (version) {
|
|
148
|
+
const binary = getBinaryPath(version, true);
|
|
149
|
+
if (fs.existsSync(binary)) {
|
|
150
|
+
return version;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
// Marker unreadable
|
|
157
|
+
}
|
|
158
|
+
return base;
|
|
159
|
+
}
|
|
160
|
+
// Free tier: try platform-scoped marker first, fall back to legacy marker for upgrades from <0.3.0
|
|
130
161
|
for (const name of [`latest_version_${getPlatformTag()}`, "latest_version"]) {
|
|
131
162
|
const marker = path.join(cacheDir, name);
|
|
132
163
|
try {
|
|
@@ -176,9 +207,11 @@ export const IGNORE_DEFAULT_ARGS = ["--enable-automation", "--enable-unsafe-swif
|
|
|
176
207
|
// ---------------------------------------------------------------------------
|
|
177
208
|
// Default stealth arguments
|
|
178
209
|
// ---------------------------------------------------------------------------
|
|
179
|
-
// Default viewport —
|
|
180
|
-
//
|
|
181
|
-
//
|
|
210
|
+
// Default viewport — used for HEADLESS only (headed launches use no viewport so
|
|
211
|
+
// the page tracks the real window). Headless has no window chrome, so a fixed
|
|
212
|
+
// viewport stays coherent (outer == inner) and gives deterministic dimensions.
|
|
213
|
+
// Models a maximized Chrome on 1080p Windows: screen=1920x1080,
|
|
214
|
+
// innerHeight=947 (minus ~85px Chrome UI: tabs + address bar + bookmarks).
|
|
182
215
|
export const DEFAULT_VIEWPORT = { width: 1920, height: 947 };
|
|
183
216
|
export function getDefaultStealthArgs() {
|
|
184
217
|
const seed = Math.floor(Math.random() * 90000) + 10000; // 10000-99999
|
|
@@ -191,9 +224,10 @@ export function getDefaultStealthArgs() {
|
|
|
191
224
|
// macOS: run as native Mac browser — GPU/UA match natively
|
|
192
225
|
return [...base, "--fingerprint-platform=macos"];
|
|
193
226
|
}
|
|
194
|
-
// Linux/Windows: spoof as Windows desktop
|
|
195
|
-
//
|
|
196
|
-
//
|
|
227
|
+
// Linux/Windows: spoof as Windows desktop.
|
|
228
|
+
// Screen and window size come from the real display, not this flag (verified:
|
|
229
|
+
// identical across seeds), so the wrapper must not emulate a viewport on top in
|
|
230
|
+
// headed mode — that would break outerWidth >= innerWidth coherence.
|
|
197
231
|
return [...base, "--fingerprint-platform=windows"];
|
|
198
232
|
}
|
|
199
233
|
//# sourceMappingURL=config.js.map
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/download.d.ts
CHANGED
|
@@ -4,22 +4,84 @@
|
|
|
4
4
|
* Mirrors Python cloakbrowser/download.py.
|
|
5
5
|
*/
|
|
6
6
|
import type { BinaryInfo } from "./types.js";
|
|
7
|
+
/**
|
|
8
|
+
* A downloaded binary could not be authenticated (bad/missing signature,
|
|
9
|
+
* version mismatch, or checksum failure). Distinct from transient
|
|
10
|
+
* download/network errors: a verification failure is a tampering signal and
|
|
11
|
+
* MUST surface, never silently fall back to another binary. The Pro routing in
|
|
12
|
+
* ensureBinary re-throws this rather than downgrading to the free tier.
|
|
13
|
+
*/
|
|
14
|
+
export declare class BinaryVerificationError extends Error {
|
|
15
|
+
constructor(message: string);
|
|
16
|
+
}
|
|
7
17
|
/**
|
|
8
18
|
* Ensure the stealth Chromium binary is available. Download if needed.
|
|
9
19
|
* Returns the path to the chrome executable.
|
|
10
20
|
*/
|
|
11
|
-
export declare function ensureBinary(): Promise<string>;
|
|
21
|
+
export declare function ensureBinary(licenseKey?: string): Promise<string>;
|
|
12
22
|
/** Remove all cached binaries. Forces re-download on next launch. */
|
|
13
23
|
export declare function clearCache(): void;
|
|
14
|
-
/**
|
|
24
|
+
/**
|
|
25
|
+
* Return info about the current binary installation.
|
|
26
|
+
*
|
|
27
|
+
* tier reflects what is actually installed on disk, not merely whether a license
|
|
28
|
+
* is cached — a cached license with no Pro binary downloaded yet is still
|
|
29
|
+
* effectively running the free binary, and the active key may differ from the
|
|
30
|
+
* cached one.
|
|
31
|
+
*/
|
|
15
32
|
export declare function binaryInfo(): BinaryInfo;
|
|
16
33
|
/** Manually check for a newer Chromium version. Returns new version or null. */
|
|
17
34
|
export declare function checkForUpdate(): Promise<string | null>;
|
|
18
35
|
/** @internal Exported for testing only. */
|
|
36
|
+
export declare function verifyDownloadChecksum(filePath: string, version?: string): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Read the 'version=<v>' line from a signed manifest. null if absent.
|
|
39
|
+
* The line has no internal whitespace so older wrappers' SHA256SUMS parsers
|
|
40
|
+
* ignore it (they only accept '<hash> <filename>' lines).
|
|
41
|
+
* @internal Exported for testing only.
|
|
42
|
+
*/
|
|
43
|
+
export declare function parseManifestVersion(text: string): string | null;
|
|
44
|
+
/**
|
|
45
|
+
* Fetch (SHA256SUMS, SHA256SUMS.sig) raw bytes for a version, or null.
|
|
46
|
+
* Both files come from the SAME origin so the signature always matches the
|
|
47
|
+
* exact manifest bytes it certifies. Primary origin first, then GitHub mirror.
|
|
48
|
+
* @internal Exported for testing only.
|
|
49
|
+
*/
|
|
50
|
+
export declare function fetchSignedManifest(version?: string): Promise<{
|
|
51
|
+
manifestBytes: Uint8Array;
|
|
52
|
+
sigBytes: Uint8Array;
|
|
53
|
+
} | null>;
|
|
54
|
+
/**
|
|
55
|
+
* Verify a detached Ed25519 signature over the raw manifest bytes.
|
|
56
|
+
* sigB64Bytes is the (base64-text) content of SHA256SUMS.sig. Tries each pinned
|
|
57
|
+
* key; succeeds if any validates. Throws if malformed or no key validates.
|
|
58
|
+
* @internal Exported for testing only.
|
|
59
|
+
*/
|
|
60
|
+
export declare function verifySignature(manifestBytes: Uint8Array, sigB64Bytes: Uint8Array): void;
|
|
61
|
+
/** @internal Exported for testing only. */
|
|
19
62
|
export declare function fetchChecksums(version?: string): Promise<Map<string, string> | null>;
|
|
20
63
|
/** @internal Exported for testing only. */
|
|
21
64
|
export declare function parseChecksums(text: string): Map<string, string>;
|
|
22
65
|
/** @internal Exported for testing only. */
|
|
66
|
+
export declare function downloadProBinary(version: string, licenseKey: string): Promise<void>;
|
|
67
|
+
/**
|
|
68
|
+
* Verify a Pro archive with the same non-bypassable Ed25519 signature check as
|
|
69
|
+
* official free downloads. Pro binaries are served from cloakbrowser.dev (same
|
|
70
|
+
* origin as the free tier), so a tampered same-origin SHA256SUMS could
|
|
71
|
+
* otherwise certify a tampered binary (M1, #308). Fetch the Pro SHA256SUMS +
|
|
72
|
+
* detached SHA256SUMS.sig, verify the signature against the pinned keys FIRST,
|
|
73
|
+
* bind the manifest to the requested version, then verify the archive's
|
|
74
|
+
* SHA-256.
|
|
75
|
+
*
|
|
76
|
+
* An invalid signature, checksum, or version mismatch throws
|
|
77
|
+
* BinaryVerificationError (a tampering signal the router surfaces verbatim);
|
|
78
|
+
* CLOAKBROWSER_SKIP_CHECKSUM cannot bypass it. A failed manifest FETCH is
|
|
79
|
+
* transient — nothing was validated — and throws a plain Error. A valid-license
|
|
80
|
+
* user is never silently downgraded to the free binary.
|
|
81
|
+
* @internal Exported for testing only.
|
|
82
|
+
*/
|
|
83
|
+
export declare function verifyProDownload(filePath: string, version: string): Promise<void>;
|
|
84
|
+
/** @internal Exported for testing only. */
|
|
23
85
|
export declare function getLatestChromiumVersion(): Promise<string | null>;
|
|
24
86
|
/** @internal Exported for testing only. */
|
|
25
87
|
export declare function resetWrapperUpdateChecked(): void;
|
package/dist/download.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"download.d.ts","sourceRoot":"","sources":["../src/download.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAUH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"download.d.ts","sourceRoot":"","sources":["../src/download.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAUH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AA2B7C;;;;;;GAMG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;gBACpC,OAAO,EAAE,MAAM;CAI5B;AAMD;;;GAGG;AACH,wBAAsB,YAAY,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAoFvE;AAED,qEAAqE;AACrE,wBAAgB,UAAU,IAAI,IAAI,CAMjC;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,IAAI,UAAU,CAkBvC;AAED,gFAAgF;AAChF,wBAAsB,cAAc,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAc7D;AA0ED,2CAA2C;AAC3C,wBAAsB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAkE9F;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQhE;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC;IAAE,aAAa,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,UAAU,CAAA;CAAE,GAAG,IAAI,CAAC,CA2BrE;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,aAAa,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,GAAG,IAAI,CA0CxF;AAED,2CAA2C;AAC3C,wBAAsB,cAAc,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC,CAuB1F;AAED,2CAA2C;AAC3C,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAWhE;AAqJD,2CAA2C;AAC3C,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAkC1F;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAwDxF;AA4ID,2CAA2C;AAC3C,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA0BvE;AAaD,2CAA2C;AAC3C,wBAAgB,yBAAyB,IAAI,IAAI,CAEhD;AAED,2CAA2C;AAC3C,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAoBxD"}
|