atcoder-gui 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 firewood <174658+firewood@users.noreply.github.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,149 @@
1
+ # AtCoder GUI
2
+
3
+ A browser automation tool for AtCoder with CLI interface built with Node.js, TypeScript, and Playwright.
4
+
5
+ ## Features
6
+
7
+ - **Browser Automation**: Launch a browser with UI using Playwright
8
+ - **Session Management**: Persistent browser sessions with automatic restoration
9
+ - **CLI Commands**: Interactive command line interface
10
+ - **Configuration Management**: Persistent settings using the conf module
11
+ - **URL Opening**: Open URLs with the `open URL` command
12
+ - **Automatic Startup**: Opens default URL on application launch
13
+
14
+ ## Project Structure
15
+
16
+ ```
17
+ atcoder-gui/
18
+ ├── src/
19
+ │ ├── main.ts # CLI application entry point and command handling
20
+ │ ├── browser.ts # Playwright browser management and automation
21
+ │ ├── config.ts # Configuration management using conf module
22
+ │ ├── session.ts # Session persistence and restoration
23
+ │ └── *.test.ts # Test files
24
+ ├── dist/ # Compiled JavaScript output
25
+ ├── eslint.config.js # ESLint configuration
26
+ └── package.json # Project configuration
27
+ ```
28
+
29
+ ## Installation
30
+
31
+ 1. Clone the repository
32
+ 2. Install dependencies:
33
+ ```bash
34
+ npm install
35
+ ```
36
+ 3. Install Playwright browsers:
37
+ ```bash
38
+ npx playwright install chromium
39
+ ```
40
+ 4. Build the project:
41
+ ```bash
42
+ npm run build
43
+ ```
44
+
45
+ ## Usage
46
+
47
+ ### Interactive CLI
48
+
49
+ Start the interactive command prompt:
50
+
51
+ ```bash
52
+ npm run start
53
+ ```
54
+
55
+ This will start an interactive CLI with a command prompt where you can enter commands:
56
+
57
+ ```
58
+ AtCoder GUI Interactive CLI
59
+ Type "help" for available commands or "exit" to quit
60
+ command> open https://atcoder.jp
61
+ command> config
62
+ command> help
63
+ command> exit
64
+ ```
65
+
66
+ ### Available Commands
67
+
68
+ - `open <URL>` - Open a URL in the browser
69
+ - `config` - Show current configuration
70
+ - `help` - Show available commands
71
+ - `exit` - Exit the application
72
+
73
+ ### Configuration
74
+
75
+ Configuration is automatically managed using the `conf` module (similar to atcoder-cli). Settings are stored in the standard configuration directory for your operating system:
76
+
77
+ - **Windows**: `%APPDATA%\atcoder-gui\config.json`
78
+ - **macOS**: `~/Library/Preferences/atcoder-gui/config.json`
79
+ - **Linux**: `~/.config/atcoder-gui/config.json`
80
+
81
+ Default configuration values:
82
+
83
+ ```typescript
84
+ {
85
+ theme: 'light',
86
+ autoStart: false,
87
+ defaultUrl: 'https://atcoder.jp',
88
+ windowSize: {
89
+ width: 1200,
90
+ height: 800
91
+ },
92
+ headless: false,
93
+ devtools: true
94
+ }
95
+ ```
96
+
97
+ You can modify settings programmatically through the configuration API, and they will be automatically persisted.
98
+
99
+ ### Session Management
100
+
101
+ The application automatically saves and restores browser sessions, including:
102
+ - Cookies
103
+ - Local storage data
104
+ - Login states
105
+
106
+ Session data is stored separately from configuration and is automatically restored when the browser launches.
107
+
108
+ ## Development
109
+
110
+ ### Available Scripts
111
+
112
+ - `npm run build` - Compile TypeScript to JavaScript
113
+ - `npm run dev` - Watch mode compilation
114
+ - `npm run test` - Run tests in watch mode
115
+ - `npm run test:run` - Run tests once
116
+ - `npm run lint` - Run ESLint
117
+ - `npm run lint:fix` - Fix ESLint issues automatically
118
+ - `npm run start` - Run the compiled CLI application
119
+ - `npm run clean` - Remove compiled output
120
+
121
+ ### Testing
122
+
123
+ Run tests with Vitest:
124
+
125
+ ```bash
126
+ npm run test
127
+ ```
128
+
129
+ ### Code Quality
130
+
131
+ The project uses ESLint with TypeScript-specific rules for code quality:
132
+
133
+ ```bash
134
+ npm run lint # Check code quality
135
+ npm run lint:fix # Auto-fix issues where possible
136
+ ```
137
+
138
+ ## Technology Stack
139
+
140
+ - **Node.js** - Runtime environment
141
+ - **TypeScript** - Programming language
142
+ - **Playwright** - Browser automation
143
+ - **Vitest** - Testing framework
144
+ - **ESLint** - Code linting
145
+ - **conf** - Configuration management library
146
+
147
+ ## License
148
+
149
+ MIT
@@ -0,0 +1,59 @@
1
+ import { Browser, Page } from 'playwright';
2
+ import { SessionManager } from './session.js';
3
+ export declare class BrowserManager {
4
+ private browser;
5
+ private context;
6
+ private page;
7
+ private sessionManager;
8
+ private onPageClose;
9
+ constructor();
10
+ /**
11
+ * Set the callback function to be called when the browser page closes
12
+ */
13
+ setOnPageClose(callback: (() => void) | null): void;
14
+ /**
15
+ * Launch a new browser instance with UI
16
+ */
17
+ launch(): Promise<void>;
18
+ /**
19
+ * Open a URL in the browser
20
+ */
21
+ openUrl(url: string): Promise<void>;
22
+ /**
23
+ * Get the current page instance
24
+ */
25
+ getCurrentPage(): Page | null;
26
+ /**
27
+ * Get the current browser instance
28
+ */
29
+ getBrowser(): Browser | null;
30
+ /**
31
+ * Close the browser
32
+ */
33
+ close(): Promise<void>;
34
+ /**
35
+ * Check if browser is running
36
+ */
37
+ isRunning(): boolean;
38
+ /**
39
+ * Get session manager for manual session operations
40
+ */
41
+ getSessionManager(): SessionManager;
42
+ /**
43
+ * Manually save the current session state
44
+ */
45
+ saveSession(): Promise<void>;
46
+ /**
47
+ * Clear the stored session data
48
+ */
49
+ clearSession(): void;
50
+ /**
51
+ * Get session information
52
+ */
53
+ getSessionInfo(): {
54
+ hasSession: boolean;
55
+ cookieCount: number;
56
+ originCount: number;
57
+ };
58
+ }
59
+ //# sourceMappingURL=browser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAY,IAAI,EAAkB,MAAM,YAAY,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,IAAI,CAAqB;IACjC,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,WAAW,CAA6B;;IAMhD;;OAEG;IACH,cAAc,CAAC,QAAQ,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,GAAG,IAAI;IAYnD;;OAEG;IACG,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IA6B7B;;OAEG;IACG,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQzC;;OAEG;IACH,cAAc,IAAI,IAAI,GAAG,IAAI;IAI7B;;OAEG;IACH,UAAU,IAAI,OAAO,GAAG,IAAI;IAI5B;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAmB5B;;OAEG;IACH,SAAS,IAAI,OAAO;IAIpB;;OAEG;IACH,iBAAiB,IAAI,cAAc;IAInC;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAQlC;;OAEG;IACH,YAAY,IAAI,IAAI;IAIpB;;OAEG;IACH,cAAc,IAAI;QAAE,UAAU,EAAE,OAAO,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE;CAGpF"}
@@ -0,0 +1,130 @@
1
+ import { chromium } from 'playwright';
2
+ import { SessionManager } from './session.js';
3
+ export class BrowserManager {
4
+ browser = null;
5
+ context = null;
6
+ page = null;
7
+ sessionManager;
8
+ onPageClose = null;
9
+ constructor() {
10
+ this.sessionManager = new SessionManager();
11
+ }
12
+ /**
13
+ * Set the callback function to be called when the browser page closes
14
+ */
15
+ setOnPageClose(callback) {
16
+ if (this.page) {
17
+ if (this.onPageClose) {
18
+ this.page.off('close', this.onPageClose);
19
+ }
20
+ this.onPageClose = callback;
21
+ if (callback) {
22
+ this.page.on('close', callback);
23
+ }
24
+ }
25
+ }
26
+ /**
27
+ * Launch a new browser instance with UI
28
+ */
29
+ async launch() {
30
+ if (this.browser) {
31
+ await this.close();
32
+ }
33
+ this.browser = await chromium.launch({
34
+ headless: false, // UI mode
35
+ args: [
36
+ '--disable-blink-features=AutomationControlled',
37
+ ],
38
+ });
39
+ // Create context with existing storage state if available
40
+ const storageState = this.sessionManager.getStorageState();
41
+ this.context = await this.browser.newContext({
42
+ storageState: storageState
43
+ });
44
+ this.page = await this.context.newPage();
45
+ // Log session restoration status
46
+ const sessionInfo = this.sessionManager.getSessionInfo();
47
+ if (sessionInfo.hasSession) {
48
+ console.log(`Session restored: ${sessionInfo.cookieCount} cookies, ${sessionInfo.originCount} origins`);
49
+ }
50
+ else {
51
+ console.log('Starting with fresh session');
52
+ }
53
+ }
54
+ /**
55
+ * Open a URL in the browser
56
+ */
57
+ async openUrl(url) {
58
+ if (!this.page) {
59
+ throw new Error('Browser not launched. Call launch() first.');
60
+ }
61
+ await this.page.goto(url);
62
+ }
63
+ /**
64
+ * Get the current page instance
65
+ */
66
+ getCurrentPage() {
67
+ return this.page;
68
+ }
69
+ /**
70
+ * Get the current browser instance
71
+ */
72
+ getBrowser() {
73
+ return this.browser;
74
+ }
75
+ /**
76
+ * Close the browser
77
+ */
78
+ async close() {
79
+ if (this.page) {
80
+ this.setOnPageClose(null);
81
+ await this.saveSession();
82
+ await this.page.close();
83
+ this.page = null;
84
+ }
85
+ if (this.context) {
86
+ await this.context.close();
87
+ this.context = null;
88
+ }
89
+ if (this.browser) {
90
+ await this.browser.close();
91
+ this.browser = null;
92
+ }
93
+ }
94
+ /**
95
+ * Check if browser is running
96
+ */
97
+ isRunning() {
98
+ return this.browser !== null && this.page !== null;
99
+ }
100
+ /**
101
+ * Get session manager for manual session operations
102
+ */
103
+ getSessionManager() {
104
+ return this.sessionManager;
105
+ }
106
+ /**
107
+ * Manually save the current session state
108
+ */
109
+ async saveSession() {
110
+ if (this.context) {
111
+ await this.sessionManager.saveStorageState(this.context);
112
+ }
113
+ else {
114
+ console.log('No browser context available to save');
115
+ }
116
+ }
117
+ /**
118
+ * Clear the stored session data
119
+ */
120
+ clearSession() {
121
+ this.sessionManager.clearSession();
122
+ }
123
+ /**
124
+ * Get session information
125
+ */
126
+ getSessionInfo() {
127
+ return this.sessionManager.getSessionInfo();
128
+ }
129
+ }
130
+ //# sourceMappingURL=browser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser.js","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ export interface AppConfig {
2
+ theme?: 'light' | 'dark';
3
+ defaultUrl?: string;
4
+ windowSize?: {
5
+ width: number;
6
+ height: number;
7
+ };
8
+ }
9
+ export declare class ConfigManager {
10
+ private conf;
11
+ constructor();
12
+ /**
13
+ * Initialize user config file with default template if it doesn't exist
14
+ */
15
+ private initializeUserConfigIfNeeded;
16
+ /**
17
+ * Get the entire configuration object
18
+ */
19
+ getConfig(): AppConfig;
20
+ /**
21
+ * Get a specific configuration value
22
+ */
23
+ get<K extends keyof AppConfig>(key: K): AppConfig[K];
24
+ /**
25
+ * Set a specific configuration value
26
+ */
27
+ set<K extends keyof AppConfig>(key: K, value: AppConfig[K]): void;
28
+ /**
29
+ * Set multiple configuration values
30
+ */
31
+ setMultiple(config: Partial<AppConfig>): void;
32
+ /**
33
+ * Delete a configuration value (revert to default)
34
+ */
35
+ delete<K extends keyof AppConfig>(key: K): void;
36
+ /**
37
+ * Clear all configuration (revert to defaults)
38
+ */
39
+ clear(): void;
40
+ /**
41
+ * Check if a configuration key exists
42
+ */
43
+ has<K extends keyof AppConfig>(key: K): boolean;
44
+ /**
45
+ * Get the path to the configuration file
46
+ */
47
+ getConfigPath(): string;
48
+ /**
49
+ * Get the configuration file size
50
+ */
51
+ getSize(): number;
52
+ }
53
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,SAAS;IACxB,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE;QACX,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,IAAI,CAAkB;;IAiB9B;;OAEG;IACH,OAAO,CAAC,4BAA4B;IAyBpC;;OAEG;IACH,SAAS,IAAI,SAAS;IAItB;;OAEG;IACH,GAAG,CAAC,CAAC,SAAS,MAAM,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC;IAIpD;;OAEG;IACH,GAAG,CAAC,CAAC,SAAS,MAAM,SAAS,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI;IAIjE;;OAEG;IACH,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,IAAI;IAM7C;;OAEG;IACH,MAAM,CAAC,CAAC,SAAS,MAAM,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,IAAI;IAI/C;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,GAAG,CAAC,CAAC,SAAS,MAAM,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,OAAO;IAI/C;;OAEG;IACH,aAAa,IAAI,MAAM;IAIvB;;OAEG;IACH,OAAO,IAAI,MAAM;CAGlB"}
package/dist/config.js ADDED
@@ -0,0 +1,103 @@
1
+ import Conf from 'conf';
2
+ import JSON5 from 'json5';
3
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
4
+ import { join, dirname } from 'path';
5
+ import { fileURLToPath } from 'url';
6
+ export class ConfigManager {
7
+ conf;
8
+ constructor() {
9
+ this.conf = new Conf({
10
+ projectName: 'atcoder-gui',
11
+ projectVersion: '0.1.0',
12
+ configName: 'config',
13
+ fileExtension: 'json5',
14
+ serialize: (value) => JSON5.stringify(value, null, 2),
15
+ deserialize: (text) => JSON5.parse(text),
16
+ defaults: {}
17
+ });
18
+ // Initialize user config with default template on first launch
19
+ this.initializeUserConfigIfNeeded();
20
+ }
21
+ /**
22
+ * Initialize user config file with default template if it doesn't exist
23
+ */
24
+ initializeUserConfigIfNeeded() {
25
+ try {
26
+ // Check if user config file already exists
27
+ if (!existsSync(this.conf.path)) {
28
+ console.log('First launch detected, creating config file with default template...');
29
+ // Ensure config directory exists
30
+ const configDir = dirname(this.conf.path);
31
+ if (!existsSync(configDir)) {
32
+ mkdirSync(configDir, { recursive: true });
33
+ }
34
+ // Read default config.json5 template
35
+ const defaultConfigPath = dirname(fileURLToPath(import.meta.url));
36
+ const defaultTemplate = readFileSync(join(defaultConfigPath, 'config.json5'), 'utf-8');
37
+ // Write the template directly to user config path using fs
38
+ writeFileSync(this.conf.path, defaultTemplate, 'utf-8');
39
+ console.log(`Config file created at: ${this.conf.path}`);
40
+ }
41
+ }
42
+ catch (error) {
43
+ console.warn('Failed to initialize user config file:', error);
44
+ }
45
+ }
46
+ /**
47
+ * Get the entire configuration object
48
+ */
49
+ getConfig() {
50
+ return this.conf.store;
51
+ }
52
+ /**
53
+ * Get a specific configuration value
54
+ */
55
+ get(key) {
56
+ return this.conf.get(key);
57
+ }
58
+ /**
59
+ * Set a specific configuration value
60
+ */
61
+ set(key, value) {
62
+ this.conf.set(key, value);
63
+ }
64
+ /**
65
+ * Set multiple configuration values
66
+ */
67
+ setMultiple(config) {
68
+ for (const [key, value] of Object.entries(config)) {
69
+ this.conf.set(key, value);
70
+ }
71
+ }
72
+ /**
73
+ * Delete a configuration value (revert to default)
74
+ */
75
+ delete(key) {
76
+ this.conf.delete(key);
77
+ }
78
+ /**
79
+ * Clear all configuration (revert to defaults)
80
+ */
81
+ clear() {
82
+ this.conf.clear();
83
+ }
84
+ /**
85
+ * Check if a configuration key exists
86
+ */
87
+ has(key) {
88
+ return this.conf.has(key);
89
+ }
90
+ /**
91
+ * Get the path to the configuration file
92
+ */
93
+ getConfigPath() {
94
+ return this.conf.path;
95
+ }
96
+ /**
97
+ * Get the configuration file size
98
+ */
99
+ getSize() {
100
+ return this.conf.size;
101
+ }
102
+ }
103
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ {
2
+ // atcoder-gui configuration
3
+
4
+ // UI Theme: 'light' or 'dark'
5
+ theme: 'light',
6
+
7
+ // Default URL to navigate to
8
+ defaultUrl: 'https://atcoder.jp',
9
+
10
+ // Browser window size
11
+ windowSize: {
12
+ width: 1200,
13
+ height: 800,
14
+ },
15
+ }
@@ -0,0 +1,43 @@
1
+ import { BrowserManager } from './browser.js';
2
+ export declare class CookieExporter {
3
+ private browserManager;
4
+ constructor(browserManager: BrowserManager);
5
+ /**
6
+ * Get the oj (online-judge-tools) cookie path by running oj command
7
+ */
8
+ private static getOjCookiePath;
9
+ /**
10
+ * Get AtCoder cookies from current browser session
11
+ */
12
+ private getAtCoderCookies;
13
+ /**
14
+ * Export cookies to atcoder-tools cookie.txt file
15
+ */
16
+ exportCookiesForAtCoderTools(): Promise<void>;
17
+ /**
18
+ * Export cookies to oj (online-judge-tools) cookie.jar file
19
+ */
20
+ exportCookiesForOj(): Promise<void>;
21
+ /**
22
+ * Export cookies to oj (online-judge-tools) cookie.jar file
23
+ */
24
+ exportCookies(cookiePath: string): Promise<void>;
25
+ /**
26
+ * Generate LWP-Cookies-2.0 format content from Playwright cookies
27
+ */
28
+ private generateLWPCookiesContent;
29
+ /**
30
+ * Convert Playwright cookie to LWP-Cookies-2.0 Set-Cookie3 format
31
+ */
32
+ private convertToLWPFormat;
33
+ /**
34
+ * Write cookie content to atcoder-tools cookie.txt file
35
+ * Only overwrites existing cookie.txt files
36
+ */
37
+ private writeCookieFile;
38
+ /**
39
+ * Get the path to atcoder-tools cookie.txt file
40
+ */
41
+ static getAtCoderToolsCookiePath(): string;
42
+ }
43
+ //# sourceMappingURL=cookie-export.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cookie-export.d.ts","sourceRoot":"","sources":["../src/cookie-export.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAc9C,qBAAa,cAAc;IACzB,OAAO,CAAC,cAAc,CAAiB;gBAE3B,cAAc,EAAE,cAAc;IAI1C;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,eAAe;IAiB9B;;OAEG;YACW,iBAAiB;IA8B/B;;OAEG;IACG,4BAA4B,IAAI,OAAO,CAAC,IAAI,CAAC;IAKnD;;OAEG;IACG,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;IAKzC;;OAEG;IACG,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IActD;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAYjC;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAwC1B;;;OAGG;YACW,eAAe;IAe7B;;OAEG;IACH,MAAM,CAAC,yBAAyB,IAAI,MAAM;CAG3C"}