@crowsgear/escl-protocol-scanner 1.1.1 → 1.2.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.
Files changed (45) hide show
  1. package/LICENSE +21 -21
  2. package/README.ko.md +177 -0
  3. package/README.md +177 -173
  4. package/dist/main.d.ts +5 -5
  5. package/dist/main.js +1 -1
  6. package/dist/services/client.js +22 -22
  7. package/dist/services/discovery.d.ts +1 -1
  8. package/dist/services/discovery.d.ts.map +1 -1
  9. package/dist/services/discovery.js +45 -35
  10. package/dist/services/discovery.js.map +1 -1
  11. package/package.json +70 -70
  12. package/python/__main__.py +23 -0
  13. package/python/app.py +91 -0
  14. package/python/base/__init__.py +2 -0
  15. package/python/base/service.py +23 -0
  16. package/python/common/__init__.py +4 -0
  17. package/python/common/exceptions.py +28 -0
  18. package/python/common/logger.py +25 -0
  19. package/python/common/response.py +26 -0
  20. package/python/decorators/__init__.py +2 -0
  21. package/python/decorators/scanner.py +30 -0
  22. package/python/escl-scanner.spec +98 -84
  23. package/python/services/__init__.py +2 -0
  24. package/python/services/escl/__init__.py +3 -0
  25. package/python/services/escl/discovery.py +53 -0
  26. package/python/services/escl/protocol.py +358 -0
  27. package/python/services/scanner.py +31 -0
  28. package/scripts/check-python-deps.js +269 -206
  29. package/dist/client.d.ts +0 -78
  30. package/dist/client.d.ts.map +0 -1
  31. package/dist/client.js +0 -384
  32. package/dist/client.js.map +0 -1
  33. package/dist/discovery.d.ts +0 -80
  34. package/dist/discovery.d.ts.map +0 -1
  35. package/dist/discovery.js +0 -304
  36. package/dist/discovery.js.map +0 -1
  37. package/dist/types.d.ts +0 -172
  38. package/dist/types.d.ts.map +0 -1
  39. package/dist/types.js +0 -7
  40. package/dist/types.js.map +0 -1
  41. package/python/__pycache__/base.cpython-312.pyc +0 -0
  42. package/python/__pycache__/escl_backend.cpython-312.pyc +0 -0
  43. package/python/base.py +0 -57
  44. package/python/escl_backend.py +0 -559
  45. package/python/escl_main.py +0 -119
@@ -1,206 +1,269 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Python 의존성 확인 및 설치 스크립트
5
- * - 시스템에 Python 3 설치 여부 확인
6
- * - 필요한 패키지(zeroconf, pillow) 설치 여부 확인
7
- * - 대화형 설치 프롬프트
8
- *
9
- * 사용자는 PYTHON_PATH 환경변수로 어느 Python을 사용할지 결정
10
- */
11
-
12
- const fs = require('fs');
13
- const path = require('path');
14
- const { execSync, spawnSync } = require('child_process');
15
- const readline = require('readline');
16
-
17
- const REQUIRED_PACKAGES = ['zeroconf', 'pillow'];
18
- const PACKAGE_JSON_PATH = path.join(__dirname, '..', 'package.json');
19
- const PROJECT_ROOT = path.dirname(path.dirname(PACKAGE_JSON_PATH));
20
-
21
- /**
22
- * 플랫폼별 바이너리 존재 여부 확인
23
- */
24
- function checkBinaryExists() {
25
- const platform = process.platform; // 'win32', 'darwin', 'linux'
26
- const binDir = path.join(__dirname, '..', 'bin', platform);
27
- const binaryName = platform === 'win32' ? 'escl-scanner.exe' : 'escl-scanner';
28
- const binaryPath = path.join(binDir, binaryName);
29
-
30
- return fs.existsSync(binaryPath);
31
- }
32
-
33
- // 색상 코드
34
- const colors = {
35
- reset: '\x1b[0m',
36
- bright: '\x1b[1m',
37
- red: '\x1b[31m',
38
- green: '\x1b[32m',
39
- yellow: '\x1b[33m',
40
- blue: '\x1b[34m',
41
- cyan: '\x1b[36m',
42
- };
43
-
44
- const log = {
45
- info: (msg) => console.log(`${colors.blue}ℹ️ ${msg}${colors.reset}`),
46
- success: (msg) => console.log(`${colors.green}✅ ${msg}${colors.reset}`),
47
- warn: (msg) => console.log(`${colors.yellow}⚠️ ${msg}${colors.reset}`),
48
- error: (msg) => console.log(`${colors.red}❌ ${msg}${colors.reset}`),
49
- header: (msg) => console.log(`\n${colors.bright}${colors.cyan}${msg}${colors.reset}\n`),
50
- };
51
-
52
- /**
53
- * 시스템 Python 경로 찾기
54
- */
55
- function findPythonPath() {
56
- // PYTHON_PATH 환경변수가 설정되어 있으면 사용
57
- if (process.env.PYTHON_PATH) {
58
- log.success(`PYTHON_PATH 환경변수 사용: ${process.env.PYTHON_PATH}`);
59
- return process.env.PYTHON_PATH;
60
- }
61
-
62
- // 아니면 시스템 python3 사용
63
- try {
64
- const pythonPath = execSync('which python3', { encoding: 'utf-8' }).trim();
65
- log.info(`시스템 Python 사용: ${pythonPath}`);
66
- return pythonPath;
67
- } catch (error) {
68
- log.error('python3를 찾을 수 없습니다. Python 3을 설치하세요.');
69
- process.exit(1);
70
- }
71
- }
72
-
73
- /**
74
- * 패키지 설치 여부 확인
75
- */
76
- function checkPackageInstalled(pythonPath, packageName) {
77
- try {
78
- execSync(`${pythonPath} -c "import ${packageName}"`, {
79
- stdio: 'pipe',
80
- encoding: 'utf-8',
81
- });
82
- return true;
83
- } catch (error) {
84
- return false;
85
- }
86
- }
87
-
88
- /**
89
- * 설치된 패키지 확인
90
- */
91
- function checkInstalledPackages(pythonPath) {
92
- const missing = [];
93
-
94
- for (const pkg of REQUIRED_PACKAGES) {
95
- const installed = checkPackageInstalled(pythonPath, pkg);
96
-
97
- if (installed) {
98
- log.success(`${pkg} 설치됨`);
99
- } else {
100
- log.warn(`${pkg} 미설치`);
101
- missing.push(pkg);
102
- }
103
- }
104
-
105
- return missing;
106
- }
107
-
108
- /**
109
- * 사용자 입력 프롬프트
110
- */
111
- function prompt(question) {
112
- return new Promise((resolve) => {
113
- const rl = readline.createInterface({
114
- input: process.stdin,
115
- output: process.stdout,
116
- });
117
-
118
- rl.question(question, (answer) => {
119
- rl.close();
120
- resolve(answer.toLowerCase());
121
- });
122
- });
123
- }
124
-
125
- /**
126
- * 패키지 설치
127
- */
128
- async function installPackages(pythonPath, packages) {
129
- log.header(`Python 패키지 설치`);
130
-
131
- const installCmd = `${pythonPath} -m pip install ${packages.join(' ')}`;
132
-
133
- console.log(`설치 명령어: ${colors.cyan}${installCmd}${colors.reset}\n`);
134
-
135
- const answer = await prompt(
136
- `${colors.bright}패키지를 설치하시겠습니까? (y/n): ${colors.reset}`
137
- );
138
-
139
- if (answer === 'y' || answer === 'yes') {
140
- try {
141
- log.info('설치 중...');
142
- execSync(installCmd, { stdio: 'inherit' });
143
- log.success('패키지 설치 완료');
144
- return true;
145
- } catch (error) {
146
- log.error(`설치 실패: ${error.message}`);
147
- return false;
148
- }
149
- } else {
150
- log.warn('사용자가 설치를 거부했습니다.');
151
- log.info(`수동 설치 명령어: ${colors.cyan}${installCmd}${colors.reset}`);
152
- return false;
153
- }
154
- }
155
-
156
- /**
157
- * 메인 함수
158
- */
159
- async function main() {
160
- log.header('eSCL Protocol Scanner - Python 의존성 확인');
161
-
162
- // 바이너리 존재 여부 확인 - 있으면 Python 체크 스킵
163
- if (checkBinaryExists()) {
164
- log.success('Pre-built 바이너리가 존재합니다. Python 의존성 체크를 건너뜁니다.');
165
- console.log();
166
- process.exit(0);
167
- }
168
-
169
- log.info('Pre-built 바이너리가 없습니다. Python 의존성을 확인합니다...');
170
-
171
- // Python 경로 결정
172
- const pythonPath = findPythonPath();
173
-
174
- // 패키지 확인
175
- log.header('필수 패키지 확인');
176
- const missing = checkInstalledPackages(pythonPath);
177
-
178
- if (missing.length === 0) {
179
- log.success('모든 필수 패키지가 설치되어 있습니다.');
180
- console.log();
181
- process.exit(0);
182
- }
183
-
184
- // 설치 필요
185
- log.header('필수 패키지 설치 필요');
186
- log.warn(`다음 패키지가 필요합니다: ${missing.join(', ')}`);
187
-
188
- const installed = await installPackages(pythonPath, missing);
189
-
190
- if (!installed) {
191
- log.error('필수 패키지 없이는 eSCL 스캐너를 사용할 수 없습니다.');
192
- console.log(
193
- `\n${colors.bright}수동 설치 방법:${colors.reset}`
194
- );
195
-
196
- console.log(`${colors.cyan}${pythonPath} -m pip install ${missing.join(' ')}${colors.reset}`);
197
- console.log();
198
- process.exit(1);
199
- }
200
- }
201
-
202
- // 실행
203
- main().catch((error) => {
204
- log.error(`예기치 않은 오류: ${error.message}`);
205
- process.exit(1);
206
- });
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Python 의존성 확인 및 설치 스크립트
5
+ * - 시스템에 Python 3 설치 여부 확인
6
+ * - 필요한 패키지(zeroconf, pillow) 설치 여부 확인
7
+ * - 대화형 설치 프롬프트
8
+ *
9
+ * 사용자는 PYTHON_PATH 환경변수로 어느 Python을 사용할지 결정
10
+ */
11
+
12
+ const fs = require("fs");
13
+ const path = require("path");
14
+ const { execSync, spawnSync } = require("child_process");
15
+ const readline = require("readline");
16
+
17
+ const REQUIRED_PACKAGES = ["zeroconf", "pillow"];
18
+ const PACKAGE_JSON_PATH = path.join(__dirname, "..", "package.json");
19
+ const PROJECT_ROOT = path.dirname(path.dirname(PACKAGE_JSON_PATH));
20
+
21
+ /**
22
+ * 플랫폼별 바이너리 존재 여부 확인
23
+ */
24
+ function checkBinaryExists() {
25
+ const platform = process.platform; // 'win32', 'darwin', 'linux'
26
+ const binDir = path.join(__dirname, "..", "bin", platform);
27
+ const binaryName = platform === "win32" ? "escl-scanner.exe" : "escl-scanner";
28
+ const binaryPath = path.join(binDir, binaryName);
29
+
30
+ return fs.existsSync(binaryPath);
31
+ }
32
+
33
+ // 색상 코드
34
+ const colors = {
35
+ reset: "\x1b[0m",
36
+ bright: "\x1b[1m",
37
+ red: "\x1b[31m",
38
+ green: "\x1b[32m",
39
+ yellow: "\x1b[33m",
40
+ blue: "\x1b[34m",
41
+ cyan: "\x1b[36m",
42
+ };
43
+
44
+ const log = {
45
+ info: (msg) => console.log(`${colors.blue}ℹ️ ${msg}${colors.reset}`),
46
+ success: (msg) => console.log(`${colors.green}✅ ${msg}${colors.reset}`),
47
+ warn: (msg) => console.log(`${colors.yellow}⚠️ ${msg}${colors.reset}`),
48
+ error: (msg) => console.log(`${colors.red}❌ ${msg}${colors.reset}`),
49
+ header: (msg) => console.log(`\n${colors.bright}${colors.cyan}${msg}${colors.reset}\n`),
50
+ };
51
+
52
+ /**
53
+ * 시스템 Python 경로 찾기
54
+ */
55
+ function findPythonPath() {
56
+ // PYTHON_PATH 환경변수가 설정되어 있으면 사용
57
+ if (process.env.PYTHON_PATH) {
58
+ log.success(`PYTHON_PATH 환경변수 사용: ${process.env.PYTHON_PATH}`);
59
+ return process.env.PYTHON_PATH;
60
+ }
61
+
62
+ const isWindows = process.platform === "win32";
63
+ const whichCmd = isWindows ? "where" : "which";
64
+ // 윈도우에서는 python3이 없을 있으므로 python도 시도
65
+ const candidates = isWindows ? ["python3", "python"] : ["python3"];
66
+
67
+ for (const candidate of candidates) {
68
+ try {
69
+ const result = execSync(`${whichCmd} ${candidate}`, {
70
+ encoding: "utf-8",
71
+ stdio: ["pipe", "pipe", "pipe"],
72
+ }).trim();
73
+ // where 명령어는 여러 줄을 반환할 수 있으므로 첫 번째 경로 사용
74
+ const pythonPath = result.split(/\r?\n/)[0].trim();
75
+
76
+ // python인 경우 Python 3인지 확인
77
+ if (candidate === "python") {
78
+ try {
79
+ const version = execSync(`${pythonPath} --version`, {
80
+ encoding: "utf-8",
81
+ stdio: ["pipe", "pipe", "pipe"],
82
+ }).trim();
83
+ if (!version.startsWith("Python 3")) {
84
+ continue;
85
+ }
86
+ } catch {
87
+ continue;
88
+ }
89
+ }
90
+
91
+ log.info(`시스템 Python 사용: ${pythonPath}`);
92
+ return pythonPath;
93
+ } catch {
94
+ // candidate를 찾지 못함, 다음 시도
95
+ }
96
+ }
97
+
98
+ log.error("Python 3을 찾을 수 없습니다. Python 3을 설치하세요.");
99
+ process.exit(1);
100
+ }
101
+
102
+ /**
103
+ * 패키지 설치 여부 확인
104
+ */
105
+ function checkPackageInstalled(pythonPath, packageName) {
106
+ try {
107
+ execSync(`${pythonPath} -c "import ${packageName}"`, {
108
+ stdio: "pipe",
109
+ encoding: "utf-8",
110
+ });
111
+ return true;
112
+ } catch (error) {
113
+ return false;
114
+ }
115
+ }
116
+
117
+ /**
118
+ * 설치된 패키지 확인
119
+ */
120
+ function checkInstalledPackages(pythonPath) {
121
+ const missing = [];
122
+
123
+ for (const pkg of REQUIRED_PACKAGES) {
124
+ const installed = checkPackageInstalled(pythonPath, pkg);
125
+
126
+ if (installed) {
127
+ log.success(`${pkg} 설치됨`);
128
+ } else {
129
+ log.warn(`${pkg} 미설치`);
130
+ missing.push(pkg);
131
+ }
132
+ }
133
+
134
+ return missing;
135
+ }
136
+
137
+ /**
138
+ * 사용자 입력 프롬프트
139
+ */
140
+ function prompt(question) {
141
+ return new Promise((resolve) => {
142
+ const rl = readline.createInterface({
143
+ input: process.stdin,
144
+ output: process.stdout,
145
+ });
146
+
147
+ rl.question(question, (answer) => {
148
+ rl.close();
149
+ resolve(answer.toLowerCase());
150
+ });
151
+ });
152
+ }
153
+
154
+ /**
155
+ * 가상환경 사용 안내 출력
156
+ */
157
+ function showVenvGuide(packages) {
158
+ log.header("가상환경 사용 안내");
159
+ log.info("애플리케이션에서 pythonPath 옵션으로 가상환경 경로를 직접 전달합니다.(패키지 직접 설치)");
160
+
161
+ const isWindows = process.platform === "win32";
162
+ const venvPython = isWindows ? ".venv\\Scripts\\python.exe" : ".venv/bin/python3";
163
+ const activateCmd = isWindows ? ".venv\\Scripts\\activate" : "source .venv/bin/activate";
164
+
165
+ console.log(`\n${colors.bright}가상환경 설정 방법:${colors.reset}`);
166
+ console.log(` 1. 가상환경 생성: ${colors.cyan}python -m venv .venv${colors.reset}`);
167
+ console.log(` 2. 가상환경 활성화: ${colors.cyan}${activateCmd}${colors.reset}`);
168
+ console.log(` 3. 패키지 설치: ${colors.cyan}pip install ${packages.join(" ")}${colors.reset}`);
169
+
170
+ console.log(`\n${colors.bright}애플리케이션에서 사용:${colors.reset}`);
171
+ console.log(` ${colors.cyan}const app = new Application({ pythonPath: '${venvPython}' });${colors.reset}`);
172
+ console.log();
173
+ }
174
+
175
+ /**
176
+ * 패키지 설치 방법 선택
177
+ */
178
+ async function handleMissingPackages(pythonPath, packages) {
179
+ log.header("설치 방법 선택");
180
+
181
+ console.log(` ${colors.bright}1)${colors.reset} 시스템 Python에 직접 설치 (pip install)`);
182
+ console.log(` ${colors.bright}2)${colors.reset} 가상환경 사용 (애플리케이션 내 가상환경 경로 직접 전달)`);
183
+ console.log(` ${colors.bright}3)${colors.reset} 건너뛰기`);
184
+ console.log();
185
+
186
+ const answer = await prompt(`${colors.bright}선택하세요 (1/2/3): ${colors.reset}`);
187
+
188
+ switch (answer) {
189
+ case "1": {
190
+ const installCmd = `${pythonPath} -m pip install ${packages.join(" ")}`;
191
+ console.log(`\n설치 명령어: ${colors.cyan}${installCmd}${colors.reset}\n`);
192
+ const confirm = await prompt(`${colors.bright}설치를 진행하시겠습니까? (y/n): ${colors.reset}`);
193
+ if (confirm === "y" || confirm === "yes") {
194
+ try {
195
+ log.info("설치 중...");
196
+ execSync(installCmd, { stdio: "inherit" });
197
+ log.success("패키지 설치 완료");
198
+ return true;
199
+ } catch (error) {
200
+ log.error(`설치 실패: ${error.message}`);
201
+ return false;
202
+ }
203
+ }
204
+ log.warn("사용자가 설치를 취소했습니다.");
205
+ return false;
206
+ }
207
+ case "2": {
208
+ showVenvGuide(packages);
209
+ log.success("가상환경 모드를 선택했습니다. 위 안내에 따라 설정하세요.");
210
+ return true;
211
+ }
212
+ default: {
213
+ log.warn("설치를 건너뛰었습니다.");
214
+ log.info(
215
+ `수동 설치 명령어: ${colors.cyan}${pythonPath} -m pip install ${packages.join(" ")}${colors.reset}`,
216
+ );
217
+ return false;
218
+ }
219
+ }
220
+ }
221
+
222
+ /**
223
+ * 메인 함수
224
+ */
225
+ async function main() {
226
+ log.header("eSCL Protocol Scanner - Python 의존성 확인");
227
+
228
+ // 바이너리 존재 여부 확인 - 있으면 Python 체크 스킵
229
+ if (checkBinaryExists()) {
230
+ log.success("Pre-built 바이너리가 존재합니다. Python 의존성 체크를 건너뜁니다.");
231
+ console.log();
232
+ process.exit(0);
233
+ }
234
+
235
+ log.info("Pre-built 바이너리가 없습니다. Python 의존성을 확인합니다...");
236
+
237
+ // Python 경로 결정
238
+ const pythonPath = findPythonPath();
239
+
240
+ // 패키지 확인
241
+ log.header("필수 패키지 확인");
242
+ const missing = checkInstalledPackages(pythonPath);
243
+
244
+ if (missing.length === 0) {
245
+ log.success("모든 필수 패키지가 설치되어 있습니다.");
246
+ console.log();
247
+ process.exit(0);
248
+ }
249
+
250
+ // 설치 필요
251
+ log.warn(`다음 패키지가 필요합니다: ${missing.join(", ")}`);
252
+
253
+ const resolved = await handleMissingPackages(pythonPath, missing);
254
+
255
+ if (!resolved) {
256
+ log.error("필수 패키지 없이는 eSCL 스캐너를 사용할 수 없습니다.");
257
+ console.log(`\n${colors.bright}수동 설치 방법:${colors.reset}`);
258
+
259
+ console.log(`${colors.cyan}${pythonPath} -m pip install ${missing.join(" ")}${colors.reset}`);
260
+ console.log();
261
+ process.exit(1);
262
+ }
263
+ }
264
+
265
+ // 실행
266
+ main().catch((error) => {
267
+ log.error(`예기치 않은 오류: ${error.message}`);
268
+ process.exit(1);
269
+ });
package/dist/client.d.ts DELETED
@@ -1,78 +0,0 @@
1
- /**
2
- * eSCL Protocol Client for Node.js
3
- * HTTP client for communicating with eSCL/AirPrint network scanners
4
- */
5
- import { ESCLScanner, ESCLCapabilities } from './types';
6
- /**
7
- * eSCL HTTP Client
8
- * Handles all HTTP communication with eSCL-compatible network scanners
9
- */
10
- export declare class ESCLClient {
11
- private timeout;
12
- constructor(timeout?: number);
13
- /**
14
- * Get scanner capabilities
15
- * @param scanner Target scanner
16
- * @param debug Enable debug logging (default: false)
17
- * @returns Scanner capabilities
18
- */
19
- getCapabilities(scanner: ESCLScanner, debug?: boolean): Promise<ESCLCapabilities | null>;
20
- /**
21
- * Start scan job
22
- * @param scanner Target scanner
23
- * @param dpi Resolution in DPI
24
- * @param colorMode Color mode (BlackAndWhite1, Grayscale8, RGB24)
25
- * @param source Scan source (Platen, Feeder)
26
- * @param documentFormat Document format MIME type
27
- * @param width Scan width in mm (optional)
28
- * @param height Scan height in mm (optional)
29
- * @returns Scan job UUID
30
- */
31
- createScanJob(scanner: ESCLScanner, dpi: number, colorMode: string, source: string, documentFormat: string, width?: number, height?: number): Promise<string | null>;
32
- /**
33
- * Poll scan job status
34
- * @param scanner Target scanner
35
- * @param jobId Scan job ID
36
- * @returns Job status and image URLs if complete
37
- */
38
- getScanJobStatus(scanner: ESCLScanner, jobId: string): Promise<{
39
- status: 'Processing' | 'Completed' | 'Aborted' | 'Unknown';
40
- images: string[];
41
- }>;
42
- /**
43
- * Download scanned image
44
- * @param scanner Target scanner
45
- * @param imageUrl Relative image URL
46
- * @returns PNG image data as Buffer
47
- */
48
- downloadImage(scanner: ESCLScanner, imageUrl: string): Promise<Buffer | null>;
49
- /**
50
- * Build eSCL scan settings XML
51
- * @param dpi Resolution in DPI
52
- * @param colorMode Color mode
53
- * @param source Scan source
54
- * @param documentFormat Document format MIME type
55
- * @param width Scan width in mm (optional)
56
- * @param height Scan height in mm (optional)
57
- */
58
- private buildScanSettings;
59
- /**
60
- * Parse scanner capabilities from XML response
61
- * @param xml XML response from scanner
62
- * @param debug Enable debug logging (default: false)
63
- */
64
- private parseCapabilities;
65
- /**
66
- * HTTP GET request
67
- */
68
- private httpGet;
69
- /**
70
- * HTTP GET request (binary)
71
- */
72
- private httpGetBinary;
73
- /**
74
- * HTTP POST request
75
- */
76
- private httpPost;
77
- }
78
- //# sourceMappingURL=client.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAgB,MAAM,SAAS,CAAC;AAEtE;;;GAGG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,OAAO,CAAiB;gBAEpB,OAAO,CAAC,EAAE,MAAM;IAM5B;;;;;OAKG;IACG,eAAe,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,GAAE,OAAe,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;IAarG;;;;;;;;;;OAUG;IACG,aAAa,CACjB,OAAO,EAAE,WAAW,EACpB,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,EACtB,KAAK,CAAC,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAsCzB;;;;;OAKG;IACG,gBAAgB,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;QACnE,MAAM,EAAE,YAAY,GAAG,WAAW,GAAG,SAAS,GAAG,SAAS,CAAC;QAC3D,MAAM,EAAE,MAAM,EAAE,CAAC;KAClB,CAAC;IAyBF;;;;;OAKG;IACG,aAAa,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAUnF;;;;;;;;OAQG;IACH,OAAO,CAAC,iBAAiB;IAiCzB;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAkHzB;;OAEG;IACH,OAAO,CAAC,OAAO;IAyBf;;OAEG;IACH,OAAO,CAAC,aAAa;IAyBrB;;OAEG;IACH,OAAO,CAAC,QAAQ;CAmCjB"}