@saiden/browse 0.2.5

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.
Files changed (50) hide show
  1. package/README.md +210 -0
  2. package/dist/browser.d.ts +48 -0
  3. package/dist/browser.d.ts.map +1 -0
  4. package/dist/browser.integration.test.d.ts +2 -0
  5. package/dist/browser.integration.test.d.ts.map +1 -0
  6. package/dist/browser.integration.test.js +173 -0
  7. package/dist/browser.integration.test.js.map +1 -0
  8. package/dist/browser.js +250 -0
  9. package/dist/browser.js.map +1 -0
  10. package/dist/browser.test.d.ts +2 -0
  11. package/dist/browser.test.d.ts.map +1 -0
  12. package/dist/browser.test.js +73 -0
  13. package/dist/browser.test.js.map +1 -0
  14. package/dist/cli.d.ts +3 -0
  15. package/dist/cli.d.ts.map +1 -0
  16. package/dist/cli.js +247 -0
  17. package/dist/cli.js.map +1 -0
  18. package/dist/image.d.ts +21 -0
  19. package/dist/image.d.ts.map +1 -0
  20. package/dist/image.js +131 -0
  21. package/dist/image.js.map +1 -0
  22. package/dist/index.d.ts +6 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +4 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/logger.d.ts +41 -0
  27. package/dist/logger.d.ts.map +1 -0
  28. package/dist/logger.js +103 -0
  29. package/dist/logger.js.map +1 -0
  30. package/dist/logger.test.d.ts +2 -0
  31. package/dist/logger.test.d.ts.map +1 -0
  32. package/dist/logger.test.js +146 -0
  33. package/dist/logger.test.js.map +1 -0
  34. package/dist/mcp.d.ts +3 -0
  35. package/dist/mcp.d.ts.map +1 -0
  36. package/dist/mcp.js +541 -0
  37. package/dist/mcp.js.map +1 -0
  38. package/dist/server.d.ts +20 -0
  39. package/dist/server.d.ts.map +1 -0
  40. package/dist/server.js +88 -0
  41. package/dist/server.js.map +1 -0
  42. package/dist/server.test.d.ts +2 -0
  43. package/dist/server.test.d.ts.map +1 -0
  44. package/dist/server.test.js +164 -0
  45. package/dist/server.test.js.map +1 -0
  46. package/dist/types.d.ts +125 -0
  47. package/dist/types.d.ts.map +1 -0
  48. package/dist/types.js +2 -0
  49. package/dist/types.js.map +1 -0
  50. package/package.json +74 -0
package/README.md ADDED
@@ -0,0 +1,210 @@
1
+ # @saiden/browse
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@saiden/browse.svg)](https://www.npmjs.com/package/@saiden/browse)
4
+ [![CI](https://github.com/saiden-dev/browse/actions/workflows/ci.yml/badge.svg)](https://github.com/saiden-dev/browse/actions/workflows/ci.yml)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
+ [![Node.js](https://img.shields.io/node/v/@saiden/browse.svg)](https://nodejs.org)
7
+
8
+ #### Headless browser automation for Claude Code using Playwright WebKit.
9
+
10
+ <img width="1040" height="588" alt="image" src="https://github.com/user-attachments/assets/e5436f5c-b46d-4d1b-8f5a-54044969d095" />
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ npm install @saiden/browse
16
+ npx playwright install webkit
17
+ ```
18
+
19
+ ## CLI Usage
20
+
21
+ ```bash
22
+ # Take a screenshot
23
+ claude-browse https://example.com
24
+
25
+ # Custom viewport and output
26
+ claude-browse -o page.png -w 1920 -h 1080 https://example.com
27
+
28
+ # Query elements
29
+ claude-browse -q "a[href]" https://example.com
30
+ claude-browse -q "img" -j https://example.com # JSON output
31
+
32
+ # Click and interact
33
+ claude-browse -c "button.submit" https://example.com
34
+ claude-browse -t "input[name=q]=hello" -c "button[type=submit]" https://google.com
35
+
36
+ # Chain actions
37
+ claude-browse -c ".cookie-accept" -c "a.nav-link" -q "h1" https://example.com
38
+
39
+ # Interactive mode (visible browser)
40
+ claude-browse -i --headed https://example.com
41
+ ```
42
+
43
+ ## Server Mode
44
+
45
+ Start a persistent browser server that accepts commands via HTTP:
46
+
47
+ ```bash
48
+ claude-browse -s 3000 # headless
49
+ claude-browse -s 3000 --headed # visible browser
50
+ ```
51
+
52
+ Send commands:
53
+
54
+ ```bash
55
+ # Navigate
56
+ curl -X POST localhost:3000 -d '{"cmd":"goto","url":"https://example.com"}'
57
+
58
+ # Click
59
+ curl -X POST localhost:3000 -d '{"cmd":"click","selector":"button.submit"}'
60
+
61
+ # Type
62
+ curl -X POST localhost:3000 -d '{"cmd":"type","selector":"#search","text":"hello"}'
63
+
64
+ # Query elements
65
+ curl -X POST localhost:3000 -d '{"cmd":"query","selector":"a[href]"}'
66
+
67
+ # Screenshot
68
+ curl -X POST localhost:3000 -d '{"cmd":"screenshot","path":"page.png"}'
69
+
70
+ # Get current URL
71
+ curl -X POST localhost:3000 -d '{"cmd":"url"}'
72
+
73
+ # Get page HTML
74
+ curl -X POST localhost:3000 -d '{"cmd":"html"}'
75
+
76
+ # Navigation
77
+ curl -X POST localhost:3000 -d '{"cmd":"back"}'
78
+ curl -X POST localhost:3000 -d '{"cmd":"forward"}'
79
+ curl -X POST localhost:3000 -d '{"cmd":"reload"}'
80
+
81
+ # Wait
82
+ curl -X POST localhost:3000 -d '{"cmd":"wait","ms":2000}'
83
+
84
+ # Close server
85
+ curl -X POST localhost:3000 -d '{"cmd":"close"}'
86
+ ```
87
+
88
+ ## Claude Code Plugin (Recommended)
89
+
90
+ Install as a Claude Code plugin for the best integration:
91
+
92
+ ```bash
93
+ # Via marketplace (recommended)
94
+ claude plugin marketplace add https://github.com/saiden-dev/claude-plugins
95
+ claude plugin install browse
96
+
97
+ # Or direct from GitHub
98
+ claude plugin install github:saiden-dev/browse
99
+ ```
100
+
101
+ **Prerequisites:** Node.js 18+ (the MCP server runs via npx)
102
+
103
+ ### Plugin Features
104
+
105
+ **Slash Commands:**
106
+
107
+ | Command | Description |
108
+ |---------|-------------|
109
+ | `/browse:start` | Start an interactive browsing session |
110
+ | `/browse:goto <url>` | Navigate to URL and describe findings |
111
+ | `/browse:screenshot` | Take a screenshot of the current page |
112
+ | `/browse:scrape <url>` | Scrape content from a webpage |
113
+ | `/browse:analyze` | Analyze current page content and structure |
114
+ | `/browse:extract [selector]` | Extract structured data from page |
115
+ | `/browse:fill [data]` | Help fill out forms |
116
+ | `/browse:compare [action]` | Compare page states before/after action |
117
+ | `/browse:save` | Save current session state to file |
118
+ | `/browse:restore` | Restore a previously saved session |
119
+ | `/browse:end` | End the browsing session and close browser |
120
+
121
+ **MCP Resources (@ mentions):**
122
+
123
+ | Resource | Description |
124
+ |----------|-------------|
125
+ | `@browse:browser://state` | Browser state (URL, title, launched) |
126
+ | `@browse:browser://html` | Page HTML (truncated to 10KB) |
127
+ | `@browse:browser://html/full` | Complete page HTML |
128
+ | `@browse:browser://screenshot` | Page screenshot as base64 PNG |
129
+
130
+ ## MCP Server (Standalone)
131
+
132
+ Use with any MCP-compatible client:
133
+
134
+ ```bash
135
+ # Run the MCP server
136
+ browse-mcp
137
+ ```
138
+
139
+ Add to Claude Code's MCP config (`~/.claude/settings.json`):
140
+
141
+ ```json
142
+ {
143
+ "mcpServers": {
144
+ "browser": {
145
+ "command": "browse-mcp"
146
+ }
147
+ }
148
+ }
149
+ ```
150
+
151
+ **Available Tools:** `goto`, `click`, `type`, `query`, `screenshot`, `url`, `html`, `back`, `forward`, `reload`, `wait`, `eval`
152
+
153
+ **Image Processing Tools:** `favicon`, `convert`, `resize`, `crop`, `compress`, `thumbnail`
154
+
155
+ ## Programmatic Usage
156
+
157
+ ```typescript
158
+ import { ClaudeBrowser, startServer } from '@saiden/browse';
159
+
160
+ // Direct browser control
161
+ const browser = new ClaudeBrowser({
162
+ headless: true,
163
+ width: 1280,
164
+ height: 800,
165
+ });
166
+
167
+ await browser.launch();
168
+ await browser.goto('https://example.com');
169
+
170
+ const elements = await browser.query('a[href]');
171
+ console.log(elements);
172
+
173
+ await browser.click('button.submit');
174
+ await browser.type('#input', 'hello');
175
+ await browser.screenshot('page.png');
176
+
177
+ await browser.close();
178
+
179
+ // Or start a server
180
+ const server = await startServer({ port: 3000, headless: false });
181
+ // Server runs until closed via HTTP or SIGINT
182
+ ```
183
+
184
+ ## API
185
+
186
+ ### ClaudeBrowser
187
+
188
+ - `launch()` - Launch the browser
189
+ - `close()` - Close the browser
190
+ - `goto(url)` - Navigate to URL
191
+ - `click(selector)` - Click element
192
+ - `type(selector, text)` - Type into input
193
+ - `query(selector)` - Query elements, returns attributes
194
+ - `screenshot(path?, fullPage?)` - Take screenshot
195
+ - `getUrl()` - Get current URL and title
196
+ - `getHtml(full?)` - Get page HTML
197
+ - `back()` / `forward()` / `reload()` - Navigation
198
+ - `wait(ms)` - Wait for timeout
199
+ - `newPage()` - Open new page
200
+ - `executeCommand(cmd)` - Execute a command object
201
+
202
+ ### BrowserServer
203
+
204
+ - `start()` - Start HTTP server
205
+ - `stop()` - Stop server and close browser
206
+ - `getPort()` - Get server port
207
+
208
+ ## License
209
+
210
+ MIT
@@ -0,0 +1,48 @@
1
+ import { type BrowserContext, type Page } from 'playwright';
2
+ import type { BrowserCommand, BrowserOptions, CommandResponse, ElementInfo } from './types.js';
3
+ export declare class ClaudeBrowser {
4
+ private browser;
5
+ private context;
6
+ private page;
7
+ private options;
8
+ constructor(options?: BrowserOptions);
9
+ launch(): Promise<void>;
10
+ close(): Promise<void>;
11
+ private ensurePage;
12
+ /** Get the current page instance (for advanced usage) */
13
+ getPage(): Page | null;
14
+ /** Get the browser context (for advanced usage like cookies) */
15
+ getContext(): BrowserContext | null;
16
+ goto(url: string): Promise<{
17
+ url: string;
18
+ title: string;
19
+ }>;
20
+ click(selector: string): Promise<{
21
+ url: string;
22
+ }>;
23
+ type(selector: string, text: string): Promise<void>;
24
+ query(selector: string): Promise<ElementInfo[]>;
25
+ screenshot(path?: string, fullPage?: boolean): Promise<{
26
+ path: string;
27
+ buffer?: Buffer;
28
+ }>;
29
+ getUrl(): Promise<{
30
+ url: string;
31
+ title: string;
32
+ }>;
33
+ getHtml(full?: boolean): Promise<string>;
34
+ back(): Promise<{
35
+ url: string;
36
+ }>;
37
+ forward(): Promise<{
38
+ url: string;
39
+ }>;
40
+ reload(): Promise<{
41
+ url: string;
42
+ }>;
43
+ wait(ms?: number): Promise<void>;
44
+ newPage(): Promise<void>;
45
+ eval(script: string): Promise<unknown>;
46
+ executeCommand(cmd: BrowserCommand): Promise<CommandResponse>;
47
+ }
48
+ //# sourceMappingURL=browser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,KAAK,cAAc,EAAE,KAAK,IAAI,EAAU,MAAM,YAAY,CAAC;AAElF,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE/F,qBAAa,aAAa;IACxB,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,IAAI,CAAqB;IACjC,OAAO,CAAC,OAAO,CAA2B;gBAE9B,OAAO,GAAE,cAAmB;IAQlC,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAWvB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAS5B,OAAO,CAAC,UAAU;IAOlB,yDAAyD;IACzD,OAAO,IAAI,IAAI,GAAG,IAAI;IAItB,gEAAgE;IAChE,UAAU,IAAI,cAAc,GAAG,IAAI;IAI7B,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAM1D,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAOjD,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKnD,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAiB/C,UAAU,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,UAAQ,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAOvF,MAAM,IAAI,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAKjD,OAAO,CAAC,IAAI,UAAQ,GAAG,OAAO,CAAC,MAAM,CAAC;IAMtC,IAAI,IAAI,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAMhC,OAAO,IAAI,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAMnC,MAAM,IAAI,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAMlC,IAAI,CAAC,EAAE,SAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAK9B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAOxB,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAKtC,cAAc,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;CAsIpE"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=browser.integration.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser.integration.test.d.ts","sourceRoot":"","sources":["../src/browser.integration.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,173 @@
1
+ import { afterAll, beforeAll, describe, expect, it } from 'vitest';
2
+ import { ClaudeBrowser } from './browser.js';
3
+ describe('ClaudeBrowser Integration', () => {
4
+ let browser;
5
+ beforeAll(async () => {
6
+ browser = new ClaudeBrowser({ headless: true });
7
+ await browser.launch();
8
+ }, 30000);
9
+ afterAll(async () => {
10
+ await browser.close();
11
+ });
12
+ describe('navigation', () => {
13
+ it('navigates to a URL and returns title', async () => {
14
+ const result = await browser.goto('https://example.com');
15
+ expect(result.url).toContain('example.com');
16
+ expect(result.title).toBe('Example Domain');
17
+ });
18
+ it('gets current URL and title', async () => {
19
+ const result = await browser.getUrl();
20
+ expect(result.url).toContain('example.com');
21
+ expect(result.title).toBe('Example Domain');
22
+ });
23
+ it('gets page HTML', async () => {
24
+ const html = await browser.getHtml();
25
+ expect(html.toLowerCase()).toContain('<!doctype html>');
26
+ expect(html).toContain('Example Domain');
27
+ });
28
+ it('gets full page HTML', async () => {
29
+ const html = await browser.getHtml(true);
30
+ expect(html.toLowerCase()).toContain('<!doctype html>');
31
+ expect(html.length).toBeGreaterThan(100);
32
+ });
33
+ it('reloads the page', async () => {
34
+ const result = await browser.reload();
35
+ expect(result.url).toContain('example.com');
36
+ });
37
+ });
38
+ describe('DOM interaction', () => {
39
+ it('queries elements', async () => {
40
+ const elements = await browser.query('h1');
41
+ expect(elements.length).toBe(1);
42
+ expect(elements[0].tag).toBe('h1');
43
+ expect(elements[0].text).toContain('Example Domain');
44
+ });
45
+ it('queries multiple elements', async () => {
46
+ const elements = await browser.query('p');
47
+ expect(elements.length).toBeGreaterThan(0);
48
+ expect(elements[0].tag).toBe('p');
49
+ });
50
+ it('clicks an element', async () => {
51
+ await browser.goto('https://example.com');
52
+ const result = await browser.click('a');
53
+ expect(result.url).toBeDefined();
54
+ });
55
+ });
56
+ describe('screenshots', () => {
57
+ it('takes a screenshot', async () => {
58
+ await browser.goto('https://example.com');
59
+ const result = await browser.screenshot('screenshots/test-integration.png');
60
+ expect(result.path).toContain('test-integration.png');
61
+ expect(result.buffer).toBeDefined();
62
+ });
63
+ it('takes a full page screenshot', async () => {
64
+ const result = await browser.screenshot('screenshots/test-full.png', true);
65
+ expect(result.path).toContain('test-full.png');
66
+ });
67
+ });
68
+ describe('wait', () => {
69
+ it('waits for specified time', async () => {
70
+ const start = Date.now();
71
+ await browser.wait(100);
72
+ const elapsed = Date.now() - start;
73
+ expect(elapsed).toBeGreaterThanOrEqual(90);
74
+ });
75
+ });
76
+ describe('eval', () => {
77
+ it('evaluates JavaScript', async () => {
78
+ await browser.goto('https://example.com');
79
+ const result = await browser.eval('document.title');
80
+ expect(result).toBe('Example Domain');
81
+ });
82
+ it('evaluates expressions', async () => {
83
+ const result = await browser.eval('1 + 1');
84
+ expect(result).toBe(2);
85
+ });
86
+ it('evaluates complex expressions', async () => {
87
+ const result = await browser.eval('document.querySelectorAll("p").length');
88
+ expect(result).toBeGreaterThan(0);
89
+ });
90
+ });
91
+ describe('pages', () => {
92
+ it('creates a new page', async () => {
93
+ await browser.newPage();
94
+ const result = await browser.getUrl();
95
+ expect(result.url).toBe('about:blank');
96
+ });
97
+ it('navigates in new page', async () => {
98
+ const result = await browser.goto('https://example.com');
99
+ expect(result.title).toBe('Example Domain');
100
+ });
101
+ });
102
+ describe('executeCommand', () => {
103
+ it('handles goto command', async () => {
104
+ const result = await browser.executeCommand({ cmd: 'goto', url: 'https://example.com' });
105
+ expect(result.ok).toBe(true);
106
+ if (result.ok) {
107
+ expect(result.title).toBe('Example Domain');
108
+ }
109
+ });
110
+ it('handles query command', async () => {
111
+ const result = await browser.executeCommand({ cmd: 'query', selector: 'h1' });
112
+ expect(result.ok).toBe(true);
113
+ if (result.ok) {
114
+ expect(result.count).toBe(1);
115
+ }
116
+ });
117
+ it('handles url command', async () => {
118
+ const result = await browser.executeCommand({ cmd: 'url' });
119
+ expect(result.ok).toBe(true);
120
+ if (result.ok) {
121
+ expect(result.url).toContain('example.com');
122
+ }
123
+ });
124
+ it('handles html command', async () => {
125
+ const result = await browser.executeCommand({ cmd: 'html' });
126
+ expect(result.ok).toBe(true);
127
+ if (result.ok) {
128
+ expect(result.html).toContain('Example');
129
+ }
130
+ });
131
+ it('handles wait command', async () => {
132
+ const result = await browser.executeCommand({ cmd: 'wait', ms: 50 });
133
+ expect(result.ok).toBe(true);
134
+ });
135
+ it('handles eval command', async () => {
136
+ const result = await browser.executeCommand({ cmd: 'eval', script: '2+2' });
137
+ expect(result.ok).toBe(true);
138
+ if (result.ok) {
139
+ expect(result.result).toBe(4);
140
+ }
141
+ });
142
+ it('handles screenshot command', async () => {
143
+ const result = await browser.executeCommand({
144
+ cmd: 'screenshot',
145
+ path: 'screenshots/cmd-test.png',
146
+ });
147
+ expect(result.ok).toBe(true);
148
+ });
149
+ it('handles reload command', async () => {
150
+ const result = await browser.executeCommand({ cmd: 'reload' });
151
+ expect(result.ok).toBe(true);
152
+ });
153
+ it('handles click command', async () => {
154
+ await browser.executeCommand({ cmd: 'goto', url: 'https://example.com' });
155
+ const result = await browser.executeCommand({ cmd: 'click', selector: 'a' });
156
+ expect(result.ok).toBe(true);
157
+ });
158
+ it('handles newpage command', async () => {
159
+ const result = await browser.executeCommand({ cmd: 'newpage' });
160
+ expect(result.ok).toBe(true);
161
+ });
162
+ it('handles back command', async () => {
163
+ await browser.executeCommand({ cmd: 'goto', url: 'https://example.com' });
164
+ const result = await browser.executeCommand({ cmd: 'back' });
165
+ expect(result.ok).toBe(true);
166
+ });
167
+ it('handles forward command', async () => {
168
+ const result = await browser.executeCommand({ cmd: 'forward' });
169
+ expect(result.ok).toBe(true);
170
+ });
171
+ });
172
+ });
173
+ //# sourceMappingURL=browser.integration.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser.integration.test.js","sourceRoot":"","sources":["../src/browser.integration.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,QAAQ,CAAC,2BAA2B,EAAE,GAAG,EAAE;IACzC,IAAI,OAAsB,CAAC;IAE3B,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,OAAO,GAAG,IAAI,aAAa,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAChD,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC;IACzB,CAAC,EAAE,KAAK,CAAC,CAAC;IAEV,QAAQ,CAAC,KAAK,IAAI,EAAE;QAClB,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;QAC1B,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;YACpD,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;YACzD,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;YAC5C,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QAC9C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;YAC1C,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC;YACtC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;YAC5C,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QAC9C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,gBAAgB,EAAE,KAAK,IAAI,EAAE;YAC9B,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;YACrC,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;YACxD,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qBAAqB,EAAE,KAAK,IAAI,EAAE;YACnC,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YACzC,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;YACxD,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kBAAkB,EAAE,KAAK,IAAI,EAAE;YAChC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC;YACtC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;QAC9C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;QAC/B,EAAE,CAAC,kBAAkB,EAAE,KAAK,IAAI,EAAE;YAChC,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC3C,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAChC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACnC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;QACvD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,2BAA2B,EAAE,KAAK,IAAI,EAAE;YACzC,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC1C,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;YAC3C,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mBAAmB,EAAE,KAAK,IAAI,EAAE;YACjC,MAAM,OAAO,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;YAC1C,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACxC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;QACnC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;QAC3B,EAAE,CAAC,oBAAoB,EAAE,KAAK,IAAI,EAAE;YAClC,MAAM,OAAO,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;YAC1C,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,kCAAkC,CAAC,CAAC;YAC5E,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,sBAAsB,CAAC,CAAC;YACtD,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;QACtC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8BAA8B,EAAE,KAAK,IAAI,EAAE;YAC5C,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,2BAA2B,EAAE,IAAI,CAAC,CAAC;YAC3E,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;QACjD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,MAAM,EAAE,GAAG,EAAE;QACpB,EAAE,CAAC,0BAA0B,EAAE,KAAK,IAAI,EAAE;YACxC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACzB,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACxB,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;YACnC,MAAM,CAAC,OAAO,CAAC,CAAC,sBAAsB,CAAC,EAAE,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,MAAM,EAAE,GAAG,EAAE;QACpB,EAAE,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE;YACpC,MAAM,OAAO,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;YAC1C,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;YACpD,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uBAAuB,EAAE,KAAK,IAAI,EAAE;YACrC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC3C,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,+BAA+B,EAAE,KAAK,IAAI,EAAE;YAC7C,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC;YAC3E,MAAM,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,OAAO,EAAE,GAAG,EAAE;QACrB,EAAE,CAAC,oBAAoB,EAAE,KAAK,IAAI,EAAE;YAClC,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;YACxB,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC;YACtC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uBAAuB,EAAE,KAAK,IAAI,EAAE;YACrC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;YACzD,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QAC9C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;QAC9B,EAAE,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE;YACpC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,qBAAqB,EAAE,CAAC,CAAC;YACzF,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC7B,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;gBACd,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;YAC9C,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uBAAuB,EAAE,KAAK,IAAI,EAAE;YACrC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;YAC9E,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC7B,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;gBACd,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC/B,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qBAAqB,EAAE,KAAK,IAAI,EAAE;YACnC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC;YAC5D,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC7B,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;gBACd,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;YAC9C,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE;YACpC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;YAC7D,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC7B,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;gBACd,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;YAC3C,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE;YACpC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;YACrE,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE;YACpC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;YAC5E,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC7B,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;gBACd,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAChC,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;YAC1C,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC;gBAC1C,GAAG,EAAE,YAAY;gBACjB,IAAI,EAAE,0BAA0B;aACjC,CAAC,CAAC;YACH,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wBAAwB,EAAE,KAAK,IAAI,EAAE;YACtC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC;YAC/D,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uBAAuB,EAAE,KAAK,IAAI,EAAE;YACrC,MAAM,OAAO,CAAC,cAAc,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,qBAAqB,EAAE,CAAC,CAAC;YAC1E,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC;YAC7E,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yBAAyB,EAAE,KAAK,IAAI,EAAE;YACvC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC;YAChE,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE;YACpC,MAAM,OAAO,CAAC,cAAc,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,qBAAqB,EAAE,CAAC,CAAC;YAC1E,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;YAC7D,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yBAAyB,EAAE,KAAK,IAAI,EAAE;YACvC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC;YAChE,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}