@lzm04521/ssh-mcp-server 1.1.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 (78) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +157 -0
  3. package/admin-web/dist/assets/index-DXbr5DVR.js +494 -0
  4. package/admin-web/dist/index.html +6 -0
  5. package/admin-web/dist/logo.png +0 -0
  6. package/build/cli/command-line-parser.js +715 -0
  7. package/build/cli/command-line-parser.js.map +1 -0
  8. package/build/cli/run-mode.js +44 -0
  9. package/build/cli/run-mode.js.map +1 -0
  10. package/build/cli/stdio-proxy.js +304 -0
  11. package/build/cli/stdio-proxy.js.map +1 -0
  12. package/build/config/index.js +5 -0
  13. package/build/config/index.js.map +1 -0
  14. package/build/config/server.js +16 -0
  15. package/build/config/server.js.map +1 -0
  16. package/build/core/mcp-http-server.js +14 -0
  17. package/build/core/mcp-http-server.js.map +1 -0
  18. package/build/core/mcp-server.js +95 -0
  19. package/build/core/mcp-server.js.map +1 -0
  20. package/build/index.js +98 -0
  21. package/build/index.js.map +1 -0
  22. package/build/models/admin-types.js +135 -0
  23. package/build/models/admin-types.js.map +1 -0
  24. package/build/models/types.js +2 -0
  25. package/build/models/types.js.map +1 -0
  26. package/build/server/index.js +128 -0
  27. package/build/server/index.js.map +1 -0
  28. package/build/server/routes/admin.js +929 -0
  29. package/build/server/routes/admin.js.map +1 -0
  30. package/build/server/routes/audit.js +9 -0
  31. package/build/server/routes/audit.js.map +1 -0
  32. package/build/server/routes/backups.js +11 -0
  33. package/build/server/routes/backups.js.map +1 -0
  34. package/build/server/routes/mcp.js +52 -0
  35. package/build/server/routes/mcp.js.map +1 -0
  36. package/build/server/routes/settings.js +49 -0
  37. package/build/server/routes/settings.js.map +1 -0
  38. package/build/server/routes/system.js +147 -0
  39. package/build/server/routes/system.js.map +1 -0
  40. package/build/services/audit-store.js +123 -0
  41. package/build/services/audit-store.js.map +1 -0
  42. package/build/services/autostart-service.js +55 -0
  43. package/build/services/autostart-service.js.map +1 -0
  44. package/build/services/backup-scheduler.js +90 -0
  45. package/build/services/backup-scheduler.js.map +1 -0
  46. package/build/services/backup-service.js +113 -0
  47. package/build/services/backup-service.js.map +1 -0
  48. package/build/services/config-store.js +163 -0
  49. package/build/services/config-store.js.map +1 -0
  50. package/build/services/defaults.js +35 -0
  51. package/build/services/defaults.js.map +1 -0
  52. package/build/services/restart-helper.js +43 -0
  53. package/build/services/restart-helper.js.map +1 -0
  54. package/build/services/ssh-connection-manager.js +1775 -0
  55. package/build/services/ssh-connection-manager.js.map +1 -0
  56. package/build/services/update-service.js +93 -0
  57. package/build/services/update-service.js.map +1 -0
  58. package/build/tools/download.js +41 -0
  59. package/build/tools/download.js.map +1 -0
  60. package/build/tools/execute-command.js +53 -0
  61. package/build/tools/execute-command.js.map +1 -0
  62. package/build/tools/index.js +17 -0
  63. package/build/tools/index.js.map +1 -0
  64. package/build/tools/list-directory.js +57 -0
  65. package/build/tools/list-directory.js.map +1 -0
  66. package/build/tools/list-servers.js +51 -0
  67. package/build/tools/list-servers.js.map +1 -0
  68. package/build/tools/upload.js +41 -0
  69. package/build/tools/upload.js.map +1 -0
  70. package/build/utils/logger.js +28 -0
  71. package/build/utils/logger.js.map +1 -0
  72. package/build/utils/ssh-config-parser.js +195 -0
  73. package/build/utils/ssh-config-parser.js.map +1 -0
  74. package/build/utils/status-collector.js +226 -0
  75. package/build/utils/status-collector.js.map +1 -0
  76. package/build/utils/tool-error.js +20 -0
  77. package/build/utils/tool-error.js.map +1 -0
  78. package/package.json +69 -0
package/build/index.js ADDED
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env node
2
+ import { SshMcpServer } from "./core/mcp-server.js";
3
+ import { SERVER_CONFIG } from "./config/server.js";
4
+ import { Logger } from "./utils/logger.js";
5
+ import { CommandLineParser } from "./cli/command-line-parser.js";
6
+ import { resolveRunMode } from "./cli/run-mode.js";
7
+ import { runProxyMode } from "./cli/stdio-proxy.js";
8
+ import { ConfigStore, getGlobalConfigPath } from "./services/config-store.js";
9
+ import { DEFAULT_ADMIN_PORT } from "./models/admin-types.js";
10
+ import { startAdminServer } from "./server/index.js";
11
+ const HELP_TEXT = `Usage: ssh-mcp-server [options] [host port username password]
12
+
13
+ Options:
14
+ --config-file <path> Load SSH server configs from a JSON file
15
+ --ssh-config-file <path> Read host aliases from SSH config (default: ~/.ssh/config)
16
+ --ssh <config> Add an SSH config as JSON or legacy key=value pairs (repeatable)
17
+ -h, --host <host> SSH host or SSH config alias for single-host mode
18
+ -p, --port <port> SSH port for single-host mode
19
+ -u, --username <name> SSH username for single-host mode
20
+ -w, --password <password> SSH password for single-host mode
21
+ -k, --privateKey <path> SSH private key path for single-host mode
22
+ -P, --passphrase <passphrase> SSH private key passphrase
23
+ -a, --agent <path> SSH agent socket path or pageant on Windows
24
+ -W, --whitelist <patterns> Command whitelist regexes, comma-separated
25
+ -B, --blacklist <patterns> Command blacklist regexes, comma-separated
26
+ --proxy <url> Proxy URL (SOCKS5, HTTP, or HTTPS)
27
+ -s, --socksProxy <url> Legacy SOCKS5 proxy URL
28
+ --allowed-local-paths <paths> Extra allowed local paths, comma-separated
29
+ --allowed-remote-paths <paths> Allowed remote POSIX absolute paths, comma-separated
30
+ --transport-mode <mode> SSH transport mode: exec or shell (default: exec)
31
+ --shell-ready-timeout <ms> Shell readiness probe timeout (default: 10000)
32
+ --command-template <template> Wrap commands with <command> or <quotedCommand>
33
+ --pty Allocate pseudo-tty for exec mode commands (default: true)
34
+ --try-keyboard Enable keyboard-interactive authentication
35
+ --pre-connect Pre-connect to all SSH servers on startup
36
+ --stdio Force legacy stdio MCP mode (no auto-started admin daemon)
37
+ --admin Start admin HTTP server (127.0.0.1:${DEFAULT_ADMIN_PORT})
38
+ --admin-port <port> Admin HTTP port (default ${DEFAULT_ADMIN_PORT}, overrides config file)
39
+ --version, -v Print package version
40
+ --help Print this help message`;
41
+ function hasArg(...names) {
42
+ return process.argv.slice(2).some((arg) => names.includes(arg));
43
+ }
44
+ function getArgValue(name) {
45
+ const idx = process.argv.indexOf(name);
46
+ if (idx !== -1 && idx + 1 < process.argv.length)
47
+ return process.argv[idx + 1];
48
+ return undefined;
49
+ }
50
+ /**
51
+ * Main program entry
52
+ */
53
+ async function main() {
54
+ if (hasArg("--help")) {
55
+ console.log(HELP_TEXT);
56
+ return;
57
+ }
58
+ if (hasArg("--version", "-v")) {
59
+ console.log(SERVER_CONFIG.version);
60
+ return;
61
+ }
62
+ const runMode = resolveRunMode(process.argv.slice(2));
63
+ // Admin mode: single Fastify host 127.0.0.1, priority CLI > file > default
64
+ if (runMode.mode === "admin") {
65
+ const parsed = CommandLineParser.parseArgs();
66
+ // --admin-port is the authoritative admin port (distinct from --port SSH port)
67
+ const cliPort = runMode.adminPort;
68
+ // Config file override chain: --config-file > SSH_MCP_CONFIG env > global path
69
+ const configPath = parsed.configFile ?? process.env.SSH_MCP_CONFIG ?? getGlobalConfigPath();
70
+ // For admin mode, we still need to respect stored port if no CLI override
71
+ let filePort;
72
+ try {
73
+ const store = new ConfigStore({ configPath });
74
+ const cfg = await store.load();
75
+ filePort = cfg.port;
76
+ }
77
+ catch { }
78
+ const port = cliPort ?? filePort ?? DEFAULT_ADMIN_PORT;
79
+ const srv = await startAdminServer({ port, configPath });
80
+ Logger.log(`Admin server listening on 127.0.0.1:${srv.port}`, "info");
81
+ return;
82
+ }
83
+ // Proxy mode(npx 默认): 确保 admin 常驻服务运行后做 stdio→HTTP 转发
84
+ if (runMode.mode === "proxy") {
85
+ try {
86
+ await runProxyMode({ adminPort: runMode.adminPort });
87
+ }
88
+ catch (error) {
89
+ Logger.log(error instanceof Error ? error.message : String(error), "error");
90
+ process.exitCode = 1;
91
+ }
92
+ return;
93
+ }
94
+ const sshMcpServer = new SshMcpServer();
95
+ await sshMcpServer.run();
96
+ }
97
+ main().catch((error) => Logger.handleError(error, "【SSH MCP Server Error】", true));
98
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,135 @@
1
+ import { z } from "zod";
2
+ // 管理端口默认值的唯一来源:models 层定义,services/server/cli 各处引用,避免多处写死漂移
3
+ export const DEFAULT_ADMIN_PORT = 61823;
4
+ const MAX_TIMEOUT_MS = 2_147_483_647; // setTimeout/setInterval 32-bit signed int 上限
5
+ const timeout = z.number().int().positive().max(MAX_TIMEOUT_MS).optional();
6
+ export const ConnectionSchema = z
7
+ .object({
8
+ name: z.string().min(1),
9
+ host: z.string().min(1),
10
+ port: z.number().int().min(1).max(65535),
11
+ username: z.string().min(1),
12
+ password: z.string().optional(),
13
+ privateKey: z.string().optional(),
14
+ passphrase: z.string().optional(),
15
+ agent: z.string().optional(),
16
+ tryKeyboard: z.boolean().optional(),
17
+ proxy: z.string().optional(),
18
+ socksProxy: z.string().optional(),
19
+ pty: z.boolean().optional(),
20
+ transportMode: z.enum(["exec", "shell"]).optional(),
21
+ shellReadyTimeoutMs: timeout,
22
+ shellCommandTimeoutMs: timeout,
23
+ commandTimeoutMs: timeout,
24
+ connectionTimeoutMs: timeout,
25
+ sftpTimeoutMs: timeout,
26
+ maxOutputBytes: z.number().int().min(0).optional(),
27
+ keepaliveIntervalMs: timeout,
28
+ keepaliveCountMax: timeout,
29
+ commandTemplate: z
30
+ .string()
31
+ .optional()
32
+ .refine((v) => !v || v.includes("<command>") || v.includes("<quotedCommand>"), "commandTemplate 必须包含 <command> 或 <quotedCommand>"),
33
+ allowedLocalPaths: z.array(z.string()).optional(),
34
+ allowedRemotePaths: z
35
+ .array(z.string())
36
+ .optional()
37
+ .refine((v) => !v || v.every((p) => p.startsWith("/")), "远端路径必须为绝对 POSIX 路径"),
38
+ commandWhitelist: z
39
+ .array(z.string())
40
+ .optional()
41
+ .refine((v) => !v ||
42
+ v.every((s) => {
43
+ try {
44
+ new RegExp(s);
45
+ return true;
46
+ }
47
+ catch {
48
+ return false;
49
+ }
50
+ }), "正则格式不正确"),
51
+ commandBlacklist: z
52
+ .array(z.string())
53
+ .optional()
54
+ .refine((v) => !v ||
55
+ v.every((s) => {
56
+ try {
57
+ new RegExp(s);
58
+ return true;
59
+ }
60
+ catch {
61
+ return false;
62
+ }
63
+ }), "正则格式不正确"),
64
+ algorithms: z.record(z.string(), z.any()).optional(),
65
+ })
66
+ .passthrough();
67
+ export const HostSchema = ConnectionSchema;
68
+ export const EnvironmentSchema = z
69
+ .object({
70
+ displayName: z.string().max(100).optional(),
71
+ hostOrder: z.array(z.string()).optional(),
72
+ hosts: z.record(z.string().min(1), HostSchema),
73
+ })
74
+ .passthrough();
75
+ export const ProjectSchema = z
76
+ .object({
77
+ displayName: z.string().max(100).optional(),
78
+ defaultEnvironment: z.string().min(1).optional(),
79
+ environments: z.record(z.string().min(1), EnvironmentSchema).default({}),
80
+ })
81
+ .passthrough()
82
+ .superRefine((p, ctx) => {
83
+ if (p.defaultEnvironment && !p.environments[p.defaultEnvironment]) {
84
+ ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["defaultEnvironment"], message: "默认环境不存在" });
85
+ }
86
+ });
87
+ export const SettingsSchema = z.object({
88
+ port: z.coerce.number().int().min(1).max(65535).optional(),
89
+ preConnect: z.boolean().optional(),
90
+ audit: z
91
+ .object({
92
+ enabled: z.boolean().optional(),
93
+ retentionDays: z.number().int().min(1).max(365).optional(),
94
+ logResults: z.boolean().optional(),
95
+ })
96
+ .optional(),
97
+ backups: z
98
+ .object({
99
+ retentionDays: z.number().int().min(1).max(365).optional(),
100
+ maxCount: z.number().int().min(1).optional(),
101
+ autoEnabled: z.boolean().optional(),
102
+ intervalHours: z.number().int().min(1).max(720).optional(),
103
+ })
104
+ .optional(),
105
+ });
106
+ export const GlobalConfigSchema = z.object({
107
+ port: z.number().int().min(0).max(65535).default(DEFAULT_ADMIN_PORT),
108
+ projects: z.record(z.string().min(1), ProjectSchema).default({}),
109
+ projectOrder: z.array(z.string()).optional(),
110
+ audit: z
111
+ .object({
112
+ enabled: z.boolean().optional(),
113
+ retentionDays: z.number().int().min(1).max(365).optional(),
114
+ logResults: z.boolean().optional(),
115
+ })
116
+ .optional(),
117
+ backups: z
118
+ .object({
119
+ retentionDays: z.number().int().min(1).max(365).optional(),
120
+ maxCount: z.number().int().min(1).optional(),
121
+ autoEnabled: z.boolean().optional(),
122
+ intervalHours: z.number().int().min(1).max(720).optional(),
123
+ })
124
+ .optional(),
125
+ security: z
126
+ .object({
127
+ commandWhitelist: z.array(z.string()).optional(),
128
+ commandBlacklist: z.array(z.string()).optional(),
129
+ allowedLocalPaths: z.array(z.string()).optional(),
130
+ allowedRemotePaths: z.array(z.string()).optional(),
131
+ })
132
+ .optional(),
133
+ preConnect: z.boolean().optional(),
134
+ });
135
+ //# sourceMappingURL=admin-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin-types.js","sourceRoot":"","sources":["../../src/models/admin-types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/models/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,128 @@
1
+ import Fastify from "fastify";
2
+ import fastifyStatic from "@fastify/static";
3
+ import path from "node:path";
4
+ import fs from "node:fs";
5
+ import { fileURLToPath } from "node:url";
6
+ import { DEFAULT_ADMIN_PORT } from "../models/admin-types.js";
7
+ import { ConfigStore } from "../services/config-store.js";
8
+ import { registerAdminRoutes } from "./routes/admin.js";
9
+ import { registerMcpRoutes } from "./routes/mcp.js";
10
+ import { registerAuditRoutes } from "./routes/audit.js";
11
+ import { registerBackupRoutes } from "./routes/backups.js";
12
+ import { registerSystemRoutes } from "./routes/system.js";
13
+ import { registerSettingsRoutes } from "./routes/settings.js";
14
+ import { BackupService } from "../services/backup-service.js";
15
+ import { startBackupScheduler, stopBackupScheduler } from "../services/backup-scheduler.js";
16
+ import { SSHConnectionManager } from "../services/ssh-connection-manager.js";
17
+ async function createServerInstance(opts = {}, onRestart) {
18
+ const store = new ConfigStore({ configPath: opts.configPath });
19
+ const cfg = await store.load();
20
+ const port = opts.port ?? cfg.port ?? DEFAULT_ADMIN_PORT;
21
+ const app = Fastify({ logger: false });
22
+ // 仅信任本地回环 Host 头:接口无鉴权,靠该校验阻断网页经 DNS rebinding 读配置/调 /mcp
23
+ const trustedHosts = new Set(["127.0.0.1", "localhost", "[::1]", "::1"]);
24
+ app.addHook("onRequest", async (req, reply) => {
25
+ const raw = String(req.headers.host || "").toLowerCase();
26
+ let hostname = raw;
27
+ if (hostname.startsWith("[")) {
28
+ const end = hostname.indexOf("]");
29
+ hostname = end > 0 ? hostname.slice(0, end + 1) : hostname;
30
+ }
31
+ else {
32
+ const idx = hostname.lastIndexOf(":");
33
+ if (idx > 0)
34
+ hostname = hostname.slice(0, idx);
35
+ }
36
+ if (!trustedHosts.has(hostname)) {
37
+ return reply.code(403).send({ ok: false, code: "HOST_FORBIDDEN", message: "不允许的 Host 头" });
38
+ }
39
+ });
40
+ registerAdminRoutes(app, store);
41
+ registerSettingsRoutes(app, store);
42
+ registerAuditRoutes(app);
43
+ registerBackupRoutes(app, store);
44
+ // 同进程软重启:不依赖外部拉起进程(沙箱/服务/终端环境均可靠),由外层 holder 负责先关旧实例
45
+ registerSystemRoutes(app, store, { onRestart });
46
+ // HTTP /mcp 与 stdio 共用 SSHConnectionManager 单例:启动即加载 UI 配置,
47
+ // 配置文件变更时热同步(仅 projects/security 变化才重置,避免改端口等误断开所有连接)
48
+ const sshManager = SSHConnectionManager.getInstance();
49
+ let mcpConfigSig = null;
50
+ const applyMcpConfig = (c) => {
51
+ const sig = JSON.stringify({ projects: c.projects, security: c.security });
52
+ if (sig === mcpConfigSig)
53
+ return;
54
+ mcpConfigSig = sig;
55
+ sshManager.setConfig(c);
56
+ if (c?.preConnect) {
57
+ void sshManager.connectAll().catch(() => { });
58
+ }
59
+ };
60
+ applyMcpConfig(cfg);
61
+ // 独立于备份调度器的配置 watcher:UI 保存配置后 HTTP /mcp 即时生效
62
+ const stopMcpWatch = store.onChange((nextCfg) => {
63
+ try {
64
+ applyMcpConfig(nextCfg);
65
+ }
66
+ catch { }
67
+ });
68
+ await registerMcpRoutes(app);
69
+ // R6/R7: 静态托管 admin-web/dist 于 /admin/ (同端口)
70
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
71
+ const dist = path.join(__dirname, "../../admin-web/dist");
72
+ if (fs.existsSync(dist)) {
73
+ await app.register(fastifyStatic, { root: dist, prefix: "/admin/" });
74
+ // SPA fallback: /admin -> index.html (fastifyStatic 已处理 /admin/,此处补 /admin 无斜杠)
75
+ app.get("/admin", async (_req, reply) => reply.sendFile("index.html"));
76
+ // 根路径直接跳转管理界面,避免裸 / 404
77
+ app.get("/", async (_req, reply) => reply.redirect("/admin/"));
78
+ }
79
+ await app.listen({ host: "127.0.0.1", port });
80
+ const addr = app.server.address();
81
+ const actualPort = addr.port;
82
+ // 定时备份调度
83
+ let stopWatch = null;
84
+ try {
85
+ const svc = new BackupService(store);
86
+ startBackupScheduler(store, svc, cfg);
87
+ // 配置变更时重调度(热重载)
88
+ stopWatch = store.onChange((nextCfg) => {
89
+ try {
90
+ startBackupScheduler(store, svc, nextCfg);
91
+ }
92
+ catch { }
93
+ });
94
+ }
95
+ catch { }
96
+ return {
97
+ port: actualPort,
98
+ close: async () => { try {
99
+ stopBackupScheduler();
100
+ }
101
+ catch { } try {
102
+ stopWatch?.();
103
+ }
104
+ catch { } try {
105
+ stopMcpWatch();
106
+ }
107
+ catch { } return app.close(); },
108
+ app,
109
+ };
110
+ }
111
+ export async function startAdminServer(opts = {}) {
112
+ // 重启 = 关闭当前实例(释放端口、停调度器/watcher)→ 以最新配置重建并监听
113
+ const holder = {};
114
+ const onRestart = async () => {
115
+ if (holder.current)
116
+ await holder.current.close();
117
+ const next = await createServerInstance(opts, onRestart);
118
+ holder.current = next;
119
+ return next.port;
120
+ };
121
+ holder.current = await createServerInstance(opts, onRestart);
122
+ return {
123
+ get port() { return holder.current.port; },
124
+ get app() { return holder.current.app; },
125
+ close: async () => holder.current.close(),
126
+ };
127
+ }
128
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,aAAa,MAAM,iBAAiB,CAAC;AAC5C,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAC5F,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAO7E,KAAK,UAAU,oBAAoB,CAAC,OAAgC,EAAE,EAAE,SAAgC;IACtG,MAAM,KAAK,GAAG,IAAI,WAAW,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC;IAC/D,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;IAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,kBAAkB,CAAC;IAEzD,MAAM,GAAG,GAAG,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IAEvC,0DAA0D;IAC1D,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;IACzE,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;QAC5C,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;QACzD,IAAI,QAAQ,GAAG,GAAG,CAAC;QACnB,IAAI,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAC7B,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAClC,QAAQ,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;QAC7D,CAAC;aAAM,CAAC;YACN,MAAM,GAAG,GAAG,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;YACtC,IAAI,GAAG,GAAG,CAAC;gBAAE,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QACjD,CAAC;QACD,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;YAChC,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC,CAAC;QAC7F,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,mBAAmB,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAChC,sBAAsB,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACnC,mBAAmB,CAAC,GAAG,CAAC,CAAC;IACzB,oBAAoB,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACjC,qDAAqD;IACrD,oBAAoB,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;IAEhD,4DAA4D;IAC5D,sDAAsD;IACtD,MAAM,UAAU,GAAG,oBAAoB,CAAC,WAAW,EAAE,CAAC;IACtD,IAAI,YAAY,GAAkB,IAAI,CAAC;IACvC,MAAM,cAAc,GAAG,CAAC,CAAM,EAAE,EAAE;QAChC,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC3E,IAAI,GAAG,KAAK,YAAY;YAAE,OAAO;QACjC,YAAY,GAAG,GAAG,CAAC;QACnB,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QACxB,IAAI,CAAC,EAAE,UAAU,EAAE,CAAC;YAClB,KAAK,UAAU,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC,CAAC;IACF,cAAc,CAAC,GAAG,CAAC,CAAC;IACpB,8CAA8C;IAC9C,MAAM,YAAY,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,OAAY,EAAE,EAAE;QACnD,IAAI,CAAC;YAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,MAAM,iBAAiB,CAAC,GAAG,CAAC,CAAC;IAE7B,6CAA6C;IAC7C,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC/D,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,sBAAsB,CAAC,CAAC;IAC1D,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,MAAM,GAAG,CAAC,QAAQ,CAAC,aAAoB,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;QAC5E,gFAAgF;QAChF,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC;QACvE,wBAAwB;QACxB,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;IACjE,CAAC;IAED,MAAM,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,OAAO,EAAS,CAAC;IACzC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC;IAC7B,SAAS;IACT,IAAI,SAAS,GAAwB,IAAI,CAAC;IAC1C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,aAAa,CAAC,KAAK,CAAC,CAAC;QACrC,oBAAoB,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QACtC,gBAAgB;QAChB,SAAS,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,OAAY,EAAE,EAAE;YAC1C,IAAI,CAAC;gBAAC,oBAAoB,CAAC,KAAK,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAA,CAAC;QAC7D,CAAC,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IACV,OAAO;QACL,IAAI,EAAE,UAAU;QAChB,KAAK,EAAE,KAAK,IAAI,EAAE,GAAG,IAAI,CAAC;YAAC,mBAAmB,EAAE,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC,CAAC,IAAI,CAAC;YAAC,SAAS,EAAE,EAAE,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC,CAAC,IAAI,CAAC;YAAC,YAAY,EAAE,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC,CAAC,OAAO,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QACnJ,GAAG;KACJ,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,OAAgC,EAAE;IACvE,6CAA6C;IAC7C,MAAM,MAAM,GAAmE,EAAE,CAAC;IAClF,MAAM,SAAS,GAAG,KAAK,IAAqB,EAAE;QAC5C,IAAI,MAAM,CAAC,OAAO;YAAE,MAAM,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACjD,MAAM,IAAI,GAAG,MAAM,oBAAoB,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QACzD,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;QACtB,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC,CAAC;IACF,MAAM,CAAC,OAAO,GAAG,MAAM,oBAAoB,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAC7D,OAAO;QACL,IAAI,IAAI,KAAK,OAAO,MAAM,CAAC,OAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;QAC3C,IAAI,GAAG,KAAK,OAAO,MAAM,CAAC,OAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;QACzC,KAAK,EAAE,KAAK,IAAI,EAAE,CAAC,MAAM,CAAC,OAAQ,CAAC,KAAK,EAAE;KAC3C,CAAC;AACJ,CAAC"}