@enerlence/suntropy-cli 0.11.7 → 0.11.8

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index.ts","../../src/config.ts","../../src/client.ts","../../src/output.ts","../../src/commands/auth.ts","../../src/commands/config/shared.ts","../../src/commands/config/theme.ts","../../src/commands/config/advanced.ts","../../src/commands/config/solarform.ts","../../src/commands/config.ts","../../src/commands/inventory/factory.ts","../../src/commands/inventory/kits.ts","../../src/commands/inventory/manufacturers.ts","../../src/commands/inventory/custom-fields.ts","../../src/commands/inventory/index.ts","../../src/commands/studies/builder.ts","../../node_modules/uuid/dist/esm-node/rng.js","../../node_modules/uuid/dist/esm-node/regex.js","../../node_modules/uuid/dist/esm-node/validate.js","../../node_modules/uuid/dist/esm-node/stringify.js","../../node_modules/uuid/dist/esm-node/v4.js","../../src/commands/studies/index.ts","../../src/commands/curves/index.ts","../../src/commands/consumption/index.ts","../../src/commands/solarform/index.ts","../../src/commands/ppa/index.ts","../../src/commands/shareables/index.ts","../../src/commands/templates/index.ts","../../src/commands/geocode/index.ts","../../src/commands/notifications/index.ts","../../src/access.ts","../../src/commands/command-profile.ts","../../bin/suntropy.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { registerAuthCommands } from './commands/auth.js';\nimport { registerConfigCommands } from './commands/config.js';\nimport { registerInventoryCommands } from './commands/inventory/index.js';\nimport { registerStudiesCommands } from './commands/studies/index.js';\nimport { registerCurvesCommands } from './commands/curves/index.js';\nimport { registerConsumptionCommands } from './commands/consumption/index.js';\nimport { registerSolarformCommands } from './commands/solarform/index.js';\nimport { registerPPACommands } from './commands/ppa/index.js';\nimport { registerShareableCommands } from './commands/shareables/index.js';\nimport { registerTemplatesCommands } from './commands/templates/index.js';\nimport { registerGeocodeCommands } from './commands/geocode/index.js';\nimport { registerNotificationsCommands } from './commands/notifications/index.js';\nimport { registerCommandProfileCommand } from './commands/command-profile.js';\nimport { applyCommandProfile } from './access.js';\n\n// Injected at build time by tsup (define) from package.json. In dev (tsx, no\n// define) the identifier is undefined, so we fall back without throwing.\ndeclare const __CLI_VERSION__: string;\nconst CLI_VERSION = typeof __CLI_VERSION__ !== 'undefined' ? __CLI_VERSION__ : '0.0.0-dev';\n\nexport function createProgram(): Command {\n const program = new Command();\n\n program\n .name('suntropy')\n .description('Agent-first CLI for Suntropy solar platform. Optimized for programmatic data manipulation and progressive exploration.')\n .version(CLI_VERSION)\n .option('--format <format>', 'Output format: json (default), human, csv', 'json')\n .option('--fields <fields>', 'Comma-separated fields to include in output')\n .option('--server <url>', 'Override API server URL')\n .option('--token <jwt>', 'Override authentication token')\n .option('--profile <name>', 'Use a specific config profile')\n .option('--verbose', 'Show HTTP request/response details on stderr')\n .option('--quiet', 'Suppress non-data output')\n .option('--save <file>', 'Save output to file (also writes to stdout)');\n\n registerAuthCommands(program);\n registerConfigCommands(program);\n registerInventoryCommands(program);\n registerStudiesCommands(program);\n registerCurvesCommands(program);\n registerConsumptionCommands(program);\n registerSolarformCommands(program);\n registerPPACommands(program);\n registerShareableCommands(program);\n registerTemplatesCommands(program);\n registerGeocodeCommands(program);\n registerNotificationsCommands(program);\n\n // Hidden admin command to manage the command access profile. Registered last\n // and always exempt from gating, so it can raise/lower the tier from any tier.\n registerCommandProfileCommand(program);\n\n // Gate the command tree by the active permission tier (env > config > default\n // 'delete'). Commands above the tier are pruned: absent from --help and\n // reported as \"unknown command\" when invoked.\n applyCommandProfile(program);\n\n return program;\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\nimport { homedir } from 'os';\nimport { join } from 'path';\n\nexport interface SuntropyProfile {\n server: string;\n token?: string;\n authMethod?: 'api-key' | 'login';\n email?: string;\n clientUID?: string;\n userUID?: string;\n}\n\nexport interface SuntropyConfig {\n activeProfile: string;\n profiles: Record<string, SuntropyProfile>;\n /**\n * Command access profile (permission tier). Gates which commands are\n * registered/visible. Cumulative: read ⊂ write ⊂ delete. Absent → 'delete'\n * (full access, preserves legacy behavior). Managed via the hidden\n * `command-profile` admin command or the SUNTROPY_COMMAND_PROFILE env var.\n */\n commandProfile?: 'read' | 'write' | 'delete';\n}\n\nconst CONFIG_DIR = join(homedir(), '.suntropy');\nconst CONFIG_FILE = join(CONFIG_DIR, 'config.json');\n\nconst DEFAULT_CONFIG: SuntropyConfig = {\n activeProfile: 'default',\n profiles: {\n default: {\n server: 'https://api.enerlence.com',\n },\n },\n};\n\nfunction ensureConfigDir(): void {\n if (!existsSync(CONFIG_DIR)) {\n mkdirSync(CONFIG_DIR, { recursive: true });\n }\n}\n\nexport function loadConfig(): SuntropyConfig {\n ensureConfigDir();\n if (!existsSync(CONFIG_FILE)) {\n writeFileSync(CONFIG_FILE, JSON.stringify(DEFAULT_CONFIG, null, 2));\n return { ...DEFAULT_CONFIG };\n }\n return JSON.parse(readFileSync(CONFIG_FILE, 'utf-8'));\n}\n\nexport function saveConfig(config: SuntropyConfig): void {\n ensureConfigDir();\n writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));\n}\n\nexport function getActiveProfile(config: SuntropyConfig, profileOverride?: string): SuntropyProfile {\n const name = profileOverride || config.activeProfile;\n const profile = config.profiles[name];\n if (!profile) {\n throw new Error(`Profile \"${name}\" not found. Available: ${Object.keys(config.profiles).join(', ')}`);\n }\n return profile;\n}\n\nexport function setConfigValue(key: string, value: string, profileName?: string): void {\n const config = loadConfig();\n const name = profileName || config.activeProfile;\n if (!config.profiles[name]) {\n config.profiles[name] = { server: 'https://api.enerlence.com' };\n }\n const profile = config.profiles[name] as Record<string, unknown>;\n profile[key] = value;\n saveConfig(config);\n}\n\nexport function getConfigValue(key: string, profileName?: string): unknown {\n const config = loadConfig();\n const profile = getActiveProfile(config, profileName);\n return (profile as Record<string, unknown>)[key];\n}\n\n/** Service path mapping */\nconst SERVICE_PATHS: Record<string, string> = {\n security: '/security',\n solar: '/solar',\n templates: '/templates',\n profiles: '/profiles',\n periods: '/periods',\n notifications: '/notifications',\n};\n\nconst LOCAL_PORTS: Record<string, number> = {\n security: 8080,\n solar: 8086,\n templates: 8090,\n profiles: 8085,\n periods: 8084,\n notifications: 8093,\n};\n\nexport function getServiceUrl(baseServer: string, service: keyof typeof SERVICE_PATHS): string {\n // If baseServer looks like localhost without path, use port-based routing\n if (baseServer.includes('localhost') || baseServer.match(/:\\d+$/)) {\n const port = LOCAL_PORTS[service];\n const host = baseServer.replace(/:\\d+$/, '').replace(/\\/$/, '');\n return `${host}:${port}`;\n }\n // Production: path-based routing\n return `${baseServer.replace(/\\/$/, '')}${SERVICE_PATHS[service]}`;\n}\n","import axios, { AxiosInstance, AxiosError } from 'axios';\nimport { loadConfig, getActiveProfile, getServiceUrl, type SuntropyProfile } from './config.js';\n\nexport interface ClientOptions {\n server?: string;\n token?: string;\n profile?: string;\n verbose?: boolean;\n}\n\nexport interface ApiError {\n error: true;\n status: number;\n message: string;\n details?: unknown;\n}\n\nfunction resolveAuth(opts: ClientOptions): { server: string; token: string } {\n const config = loadConfig();\n const profile = getActiveProfile(config, opts.profile);\n const server = opts.server || profile.server;\n // Auth token resolution order: explicit --token flag > SUNTROPY_API_KEY env var > stored profile token.\n // The env var fallback lets host runtimes (e.g. ShellPilot) inject a just-in-time credential\n // without requiring a prior `auth login` / `auth set-key` to write the config file.\n const token = opts.token || process.env.SUNTROPY_API_KEY || profile.token;\n if (!token) {\n throw new Error('Not authenticated. Run: suntropy auth set-key --key <jwt> or suntropy auth login, or set the SUNTROPY_API_KEY env var.');\n }\n return { server, token };\n}\n\nexport function createServiceClient(service: 'security' | 'solar' | 'templates' | 'profiles' | 'periods' | 'notifications', opts: ClientOptions): AxiosInstance {\n const { server, token } = resolveAuth(opts);\n const baseURL = getServiceUrl(server, service);\n\n const client = axios.create({\n baseURL,\n timeout: 30000,\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (opts.verbose) {\n client.interceptors.request.use((req) => {\n process.stderr.write(`→ ${req.method?.toUpperCase()} ${req.baseURL}${req.url}\\n`);\n if (req.data) process.stderr.write(` Body: ${JSON.stringify(req.data).slice(0, 200)}\\n`);\n return req;\n });\n client.interceptors.response.use(\n (res) => {\n process.stderr.write(`← ${res.status} (${JSON.stringify(res.data).length} bytes)\\n`);\n return res;\n },\n (err: AxiosError) => {\n process.stderr.write(`← ERROR ${err.response?.status || 'NETWORK'}: ${err.message}\\n`);\n return Promise.reject(err);\n },\n );\n }\n\n return client;\n}\n\n/** Unauthenticated client for login */\nexport function createUnauthClient(baseURL: string): AxiosInstance {\n return axios.create({\n baseURL,\n timeout: 15000,\n headers: { 'Content-Type': 'application/json' },\n });\n}\n\n/** A MongoDB ObjectId serializes to exactly 24 hexadecimal characters. */\nconst OBJECT_ID_RE = /^[a-f0-9]{24}$/i;\n\n/**\n * Guards a solar-study `_id` argument before it reaches the backend.\n *\n * `GET /solar-study/findById/:_id` runs `solarStudyModel.findOne({ _id })`,\n * which makes Mongoose cast the value to an ObjectId. A non-ObjectId string\n * (e.g. a UUID like a chat/shareable uid) throws a `CastError` server-side and\n * surfaces as an opaque **HTTP 500**, so the caller gets no hint about what\n * went wrong. Every real study `_id` is a 24-hex ObjectId, so we can reject\n * bad ids client-side with an actionable message instead.\n *\n * Throws so the caller's try/catch surfaces it via `outputError` (exit != 0).\n */\nexport function assertStudyObjectId(id: string): string {\n if (OBJECT_ID_RE.test(id)) return id;\n const looksLikeUuid = /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i.test(id);\n const hint = looksLikeUuid\n ? `It looks like a UUID (e.g. a chat or shareable uid), not a study _id.`\n : `A study _id is a 24-character hex MongoDB ObjectId.`;\n throw new Error(\n `Invalid study id: \"${id}\". ${hint} ` +\n `Get the correct id from \\`suntropy studies list\\` (the \\`solarStudyId\\` field).`,\n );\n}\n\n/**\n * Validates that an API response body actually contains an entity.\n *\n * The solar backend returns `200` with an EMPTY body when `findById` /\n * `addSolarStudyComment` don't match a document (wrong id, or the id belongs to\n * a different clientUID / environment). Without this guard the CLI either\n * crashes downstream (`'_id' in data`, `data.solarStudyProgress = ...` on `\"\"`)\n * or — worse, for writes — reports `success` even though nothing was saved.\n *\n * Throws a clear, actionable error so the caller's try/catch surfaces it via\n * `outputError` with a non-zero exit code.\n */\nexport function assertFound<T>(data: T, entity: string, id: string): T {\n const isEmptyObject =\n data != null &&\n typeof data === 'object' &&\n !Array.isArray(data) &&\n Object.keys(data as Record<string, unknown>).length === 0;\n if (data == null || typeof data !== 'object' || Array.isArray(data) || isEmptyObject) {\n throw new Error(\n `${entity} not found: ${id}. The backend returned an empty response — ` +\n `verify the id is correct and belongs to your account and environment ` +\n `(the CLI and the app must point to the same backend).`,\n );\n }\n return data;\n}\n\nexport function handleApiError(err: unknown): ApiError {\n if (axios.isAxiosError(err)) {\n const ae = err as AxiosError;\n return {\n error: true,\n status: ae.response?.status || 0,\n message: ae.response?.statusText || ae.message,\n details: ae.response?.data,\n };\n }\n return {\n error: true,\n status: 0,\n message: err instanceof Error ? err.message : String(err),\n };\n}\n","import chalk from 'chalk';\nimport { writeFileSync } from 'fs';\n\nexport type OutputFormat = 'json' | 'human' | 'csv';\n\nexport interface OutputOptions {\n format?: OutputFormat;\n fields?: string;\n quiet?: boolean;\n save?: string;\n}\n\n/** Pick only specified fields from an object */\nfunction pickFields(obj: Record<string, unknown>, fields: string[]): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const f of fields) {\n if (f.includes('.')) {\n const parts = f.split('.');\n let val: unknown = obj;\n for (const p of parts) {\n val = val && typeof val === 'object' ? (val as Record<string, unknown>)[p] : undefined;\n }\n result[f] = val;\n } else {\n result[f] = obj[f];\n }\n }\n return result;\n}\n\nfunction applyFieldSelection(data: unknown, fields?: string): unknown {\n if (!fields) return data;\n const fieldList = fields.split(',').map((f) => f.trim());\n if (Array.isArray(data)) {\n return data.map((item) => pickFields(item as Record<string, unknown>, fieldList));\n }\n if (typeof data === 'object' && data !== null) {\n return pickFields(data as Record<string, unknown>, fieldList);\n }\n return data;\n}\n\nfunction formatHumanValue(val: unknown): string {\n if (val === null || val === undefined) return '-';\n if (typeof val === 'object') return JSON.stringify(val);\n return String(val);\n}\n\nfunction formatHuman(data: unknown): string {\n if (Array.isArray(data)) {\n if (data.length === 0) return chalk.dim('(empty)');\n const keys = Object.keys(data[0] as Record<string, unknown>);\n const widths = keys.map((k) => Math.max(k.length, ...data.map((r) => formatHumanValue((r as Record<string, unknown>)[k]).length)));\n const header = keys.map((k, i) => chalk.bold(k.padEnd(widths[i]))).join(' ');\n const rows = data.map((row) =>\n keys.map((k, i) => formatHumanValue((row as Record<string, unknown>)[k]).padEnd(widths[i])).join(' '),\n );\n return [header, keys.map((_, i) => '─'.repeat(widths[i])).join(' '), ...rows].join('\\n');\n }\n if (typeof data === 'object' && data !== null) {\n const entries = Object.entries(data as Record<string, unknown>);\n const maxKey = Math.max(...entries.map(([k]) => k.length));\n return entries.map(([k, v]) => `${chalk.bold(k.padEnd(maxKey))} ${formatHumanValue(v)}`).join('\\n');\n }\n return String(data);\n}\n\nfunction formatCsv(data: unknown): string {\n if (!Array.isArray(data)) {\n if (typeof data === 'object' && data !== null) data = [data];\n else return String(data);\n }\n const arr = data as Record<string, unknown>[];\n if (arr.length === 0) return '';\n const keys = Object.keys(arr[0]);\n const escape = (v: unknown) => {\n const s = v === null || v === undefined ? '' : String(v);\n return s.includes(',') || s.includes('\"') || s.includes('\\n') ? `\"${s.replace(/\"/g, '\"\"')}\"` : s;\n };\n return [keys.join(','), ...arr.map((r) => keys.map((k) => escape(r[k])).join(','))].join('\\n');\n}\n\nexport function output(data: unknown, opts: OutputOptions = {}): void {\n const filtered = applyFieldSelection(data, opts.fields);\n let text: string;\n\n switch (opts.format) {\n case 'human':\n text = formatHuman(filtered);\n break;\n case 'csv':\n text = formatCsv(filtered);\n break;\n default:\n text = JSON.stringify(filtered, null, 2);\n }\n\n process.stdout.write(text + '\\n');\n\n if (opts.save) {\n writeFileSync(opts.save, JSON.stringify(filtered, null, 2));\n }\n}\n\nexport function outputError(err: unknown): void {\n if (err && typeof err === 'object' && 'error' in err) {\n // ApiError object — include details\n const apiErr = err as { error: boolean; status?: number; message?: string; details?: unknown };\n const out: Record<string, unknown> = { error: true, message: apiErr.message || 'Unknown error' };\n if (apiErr.status) out.status = apiErr.status;\n if (apiErr.details) out.details = apiErr.details;\n process.stderr.write(JSON.stringify(out) + '\\n');\n } else {\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(JSON.stringify({ error: true, message: msg }) + '\\n');\n }\n process.exitCode = 1;\n}\n\n/** Wrap paginated response */\nexport function outputPaginated(data: unknown[], total: number, limit: number, offset: number, opts: OutputOptions = {}): void {\n if (opts.format === 'human') {\n const filtered = applyFieldSelection(data, opts.fields);\n const end = Math.min(offset + limit, total);\n process.stdout.write(chalk.dim(`Showing ${offset + 1}-${end} of ${total}\\n\\n`));\n process.stdout.write(formatHuman(filtered) + '\\n');\n } else {\n output({ data: applyFieldSelection(data, opts.fields), total, limit, offset, hasMore: offset + limit < total }, { ...opts, fields: undefined });\n }\n}\n","import { Command } from 'commander';\nimport { loadConfig, saveConfig, getActiveProfile, getServiceUrl } from '../config.js';\nimport { createUnauthClient, createServiceClient, handleApiError } from '../client.js';\nimport { output, outputError, type OutputOptions } from '../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\nexport function registerAuthCommands(program: Command): void {\n const auth = program.command('auth').description('Authentication management');\n\n // --- set-key (preferred for agents) ---\n auth\n .command('set-key')\n .description('Set an API key (JWT) for authentication. Preferred method for agents.')\n .requiredOption('--key <jwt>', 'JWT API key')\n .action(async (opts) => {\n try {\n // --server / --profile are global root options (see createProgram);\n // read them from there instead of redefining them locally, otherwise\n // Commander assigns them to the root and they never reach this action.\n const global = getGlobalOpts(auth);\n const config = loadConfig();\n const profileName = (global.profile as string) || config.activeProfile;\n if (!config.profiles[profileName]) {\n config.profiles[profileName] = { server: 'https://api.enerlence.com' };\n }\n const profile = config.profiles[profileName];\n profile.token = opts.key;\n profile.authMethod = 'api-key';\n if (global.server) profile.server = global.server as string;\n\n // Decode JWT to extract clientUID\n try {\n const payload = JSON.parse(Buffer.from(opts.key.split('.')[1], 'base64').toString());\n profile.clientUID = payload.clientUID;\n profile.userUID = payload.userUID;\n } catch {\n // If JWT decode fails, just save the key\n }\n\n saveConfig(config);\n output({ success: true, method: 'api-key', profile: profileName, clientUID: profile.clientUID, server: profile.server }, getGlobalOpts(auth));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- login ---\n auth\n .command('login')\n .description('Login with email and password')\n .requiredOption('--email <email>', 'User email')\n .requiredOption('--password <password>', 'User password')\n .action(async (opts) => {\n try {\n // --server / --profile come from the global root options.\n const global = getGlobalOpts(auth);\n const config = loadConfig();\n const profileName = (global.profile as string) || config.activeProfile;\n if (!config.profiles[profileName]) {\n config.profiles[profileName] = { server: 'https://api.enerlence.com' };\n }\n const profile = config.profiles[profileName];\n if (global.server) profile.server = global.server as string;\n\n const securityUrl = getServiceUrl(profile.server, 'security');\n const client = createUnauthClient(securityUrl);\n const res = await client.post('/auth/login', { email: opts.email, password: opts.password });\n\n if (res.data?.token?.access_token) {\n profile.token = res.data.token.access_token;\n profile.authMethod = 'login';\n profile.email = opts.email;\n profile.clientUID = res.data.user?.clientUID;\n profile.userUID = res.data.user?.userUID;\n saveConfig(config);\n output({\n success: true,\n method: 'login',\n profile: profileName,\n user: {\n email: res.data.user?.email,\n clientUID: res.data.user?.clientUID,\n userUID: res.data.user?.userUID,\n },\n }, getGlobalOpts(auth));\n } else {\n outputError(new Error(res.data?.errors?.[0]?.message || 'Login failed'));\n }\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- status ---\n auth\n .command('status')\n .description('Show current authentication status')\n .action(async () => {\n try {\n // --profile is a global root option.\n const global = getGlobalOpts(auth);\n const config = loadConfig();\n const profile = getActiveProfile(config, global.profile as string);\n if (!profile.token) {\n output({ authenticated: false, message: 'No token configured' }, getGlobalOpts(auth));\n return;\n }\n\n // Decode JWT to check expiry\n let expiresAt: string | undefined;\n let expired = false;\n try {\n const payload = JSON.parse(Buffer.from(profile.token.split('.')[1], 'base64').toString());\n if (payload.exp) {\n const expDate = new Date(payload.exp * 1000);\n expiresAt = expDate.toISOString();\n expired = expDate < new Date();\n }\n } catch {\n // ignore decode errors\n }\n\n output({\n authenticated: !expired,\n method: profile.authMethod || 'unknown',\n server: profile.server,\n email: profile.email,\n clientUID: profile.clientUID,\n userUID: profile.userUID,\n expiresAt,\n expired,\n }, getGlobalOpts(auth));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- refresh ---\n auth\n .command('refresh')\n .description('Refresh the current JWT token')\n .action(async () => {\n try {\n // --profile is a global root option.\n const globalOpts = getGlobalOpts(auth);\n const config = loadConfig();\n const profileName = (globalOpts.profile as string) || config.activeProfile;\n const client = createServiceClient('security', { ...globalOpts, profile: profileName });\n const res = await client.get('/auth/jwt/refreshToken');\n\n if (res.data?.access_token || res.data?.token?.access_token) {\n const newToken = res.data.access_token || res.data.token.access_token;\n config.profiles[profileName].token = newToken;\n saveConfig(config);\n output({ success: true, message: 'Token refreshed' }, getGlobalOpts(auth));\n } else {\n outputError(new Error('Refresh failed'));\n }\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- logout ---\n auth\n .command('logout')\n .description(\n 'Clear stored credentials for the active profile (or --profile). Removes the\\n' +\n 'token and account identity but keeps the profile and its server URL.\\n' +\n 'Use --all to log out of every profile.'\n )\n .option('--all', 'Clear credentials for ALL profiles')\n .action(async (opts) => {\n try {\n // --profile is a global root option.\n const global = getGlobalOpts(auth);\n const config = loadConfig();\n\n // Strip credentials/identity from a profile, keep server. Returns\n // whether the profile actually had a token before clearing.\n const clearProfile = (name: string): boolean => {\n const profile = config.profiles[name];\n if (!profile) return false;\n const hadToken = !!profile.token;\n delete profile.token;\n delete profile.authMethod;\n delete profile.email;\n delete profile.clientUID;\n delete profile.userUID;\n return hadToken;\n };\n\n if (opts.all) {\n const names = Object.keys(config.profiles);\n const clearedWithToken = names.filter(clearProfile);\n saveConfig(config);\n output({\n success: true,\n message: `Logged out of ${names.length} profile(s).`,\n profiles: names,\n hadCredentials: clearedWithToken,\n }, global);\n return;\n }\n\n const profileName = (global.profile as string) || config.activeProfile;\n if (!config.profiles[profileName]) {\n outputError(new Error(`Profile \"${profileName}\" not found. Available: ${Object.keys(config.profiles).join(', ')}`));\n return;\n }\n const hadToken = clearProfile(profileName);\n saveConfig(config);\n output({\n success: true,\n profile: profileName,\n message: hadToken\n ? `Logged out of profile \"${profileName}\". Credentials cleared (server kept).`\n : `Profile \"${profileName}\" had no stored credentials.`,\n }, global);\n } catch (err) {\n outputError(err);\n }\n });\n}\n","import { Command } from 'commander';\nimport { readFileSync, writeFileSync, unlinkSync } from 'fs';\nimport { tmpdir } from 'os';\nimport { join } from 'path';\nimport { spawnSync } from 'child_process';\nimport type { OutputOptions } from '../../output.js';\n\nexport type GlobalOpts = OutputOptions & Record<string, unknown>;\n\n/** Walk up to the root program and return its options. */\nexport function getGlobalOpts(cmd: Command): GlobalOpts {\n let root: Command = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as GlobalOpts;\n}\n\n/** Coerce a string value into boolean / number / JSON when it makes sense. */\nexport function coerceValue(raw: string): unknown {\n if (raw === 'true') return true;\n if (raw === 'false') return false;\n if (raw === 'null') return null;\n if (/^-?\\d+$/.test(raw)) return parseInt(raw, 10);\n if (/^-?\\d*\\.\\d+$/.test(raw)) return parseFloat(raw);\n if ((raw.startsWith('{') && raw.endsWith('}')) || (raw.startsWith('[') && raw.endsWith(']'))) {\n try { return JSON.parse(raw); } catch { /* fall through to string */ }\n }\n return raw;\n}\n\n/** Parse an array of `--set key=value` entries into a flat object. */\nexport function parseSetFlags(entries: string[] | undefined): Record<string, unknown> {\n if (!entries || entries.length === 0) return {};\n const out: Record<string, unknown> = {};\n for (const entry of entries) {\n const eq = entry.indexOf('=');\n if (eq < 0) throw new Error(`Invalid --set value \"${entry}\" (expected key=value)`);\n const key = entry.slice(0, eq).trim();\n const rawVal = entry.slice(eq + 1);\n if (!key) throw new Error(`Invalid --set value \"${entry}\" (empty key)`);\n out[key] = coerceValue(rawVal);\n }\n return out;\n}\n\n/** Load a JSON file (absolute or relative path). */\nexport function loadFromFile(path: string): Record<string, unknown> {\n const raw = readFileSync(path, 'utf-8');\n const parsed = JSON.parse(raw);\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new Error(`File ${path} must contain a JSON object at the top level`);\n }\n return parsed as Record<string, unknown>;\n}\n\n/** Pick a subset of keys from an object (shallow). */\nexport function pickKeys<T extends Record<string, unknown>>(obj: T | undefined | null, keys: readonly string[]): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n if (!obj) return out;\n for (const k of keys) {\n if (k in obj) out[k] = (obj as Record<string, unknown>)[k];\n }\n return out;\n}\n\n/** Build a merge payload from: --from-file, --set key=value, and direct flag mappings. */\nexport function buildPayload(\n flagValues: Record<string, unknown>,\n setEntries: string[] | undefined,\n fromFile: string | undefined,\n allowedKeys?: readonly string[],\n): Record<string, unknown> {\n const payload: Record<string, unknown> = {};\n if (fromFile) Object.assign(payload, loadFromFile(fromFile));\n if (setEntries) Object.assign(payload, parseSetFlags(setEntries));\n for (const [k, v] of Object.entries(flagValues)) {\n if (v !== undefined) payload[k] = v;\n }\n if (allowedKeys) {\n for (const k of Object.keys(payload)) {\n if (!allowedKeys.includes(k)) {\n throw new Error(`Field \"${k}\" does not belong to this section. Allowed: ${allowedKeys.join(', ')}`);\n }\n }\n }\n return payload;\n}\n\n/** Open $EDITOR (or vi) on a JSON blob and return the parsed result. */\nexport function editJson(initial: unknown, filenameHint = 'config'): Record<string, unknown> {\n const editor = process.env.EDITOR || process.env.VISUAL || 'vi';\n const tmp = join(tmpdir(), `suntropy-${filenameHint}-${Date.now()}.json`);\n writeFileSync(tmp, JSON.stringify(initial ?? {}, null, 2));\n try {\n const res = spawnSync(editor, [tmp], { stdio: 'inherit' });\n if (res.status !== 0) throw new Error(`Editor \"${editor}\" exited with status ${res.status}`);\n const updated = readFileSync(tmp, 'utf-8');\n const parsed = JSON.parse(updated);\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new Error('Edited content must be a JSON object at the top level');\n }\n return parsed as Record<string, unknown>;\n } finally {\n try { unlinkSync(tmp); } catch { /* ignore */ }\n }\n}\n","import { Command } from 'commander';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError } from '../../output.js';\nimport { getGlobalOpts, buildPayload, editJson, pickKeys } from './shared.js';\n\n/**\n * Keys accepted by POST /clients/config/updateTheme.\n * Mirrors ClientThemeConfig in backend/security.\n */\nconst THEME_KEYS = [\n 'idClientThemeConfig',\n 'primary',\n 'btnPrimary',\n 'btnSecondary',\n 'background',\n 'navbarBackgroundColor',\n 'graph1', 'graph2', 'graph3', 'graph4', 'graph5', 'graph6',\n 'logoUrl',\n 'faviconUrl',\n 'clientAppTitle',\n 'carouselLinks',\n 'enableCustomTheme',\n] as const;\n\nexport function registerThemeCommands(configRoot: Command): void {\n const theme = configRoot\n .command('theme')\n .description(\n 'Client branding & theme (security service).\\n' +\n 'Colours, logo, favicon and app title applied across Suntropy.\\n' +\n 'Endpoints: GET /clients/config/clientThemeByClientUID/:uid (public)\\n' +\n ' POST /clients/config/updateTheme (requires admin role)\\n\\n' +\n 'Fields:\\n' +\n ' primary, btnPrimary, btnSecondary Core palette (hex).\\n' +\n ' background, navbarBackgroundColor Surface colours.\\n' +\n ' graph1..graph6 Chart palette (6 slots).\\n' +\n ' logoUrl, faviconUrl Asset URLs.\\n' +\n ' clientAppTitle Visible app title.\\n' +\n ' carouselLinks JSON-serialised carousel config.\\n' +\n ' enableCustomTheme Toggles the custom theme on/off.'\n );\n\n theme\n .command('get')\n .description('Fetch the theme of a client (public endpoint, no auth required for reads).')\n .requiredOption('--client-uid <uid>', 'Client UID whose theme should be fetched')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(theme);\n const client = createServiceClient('security', global);\n const res = await client.get(`/clients/config/clientThemeByClientUID/${opts.clientUid}`);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n theme\n .command('set')\n .description(\n 'Update the theme of the authenticated client (requires admin role).\\n' +\n 'Combine individual flags, repeatable --set key=value, and/or --from-file.\\n' +\n 'Example:\\n' +\n ' suntropy config theme set --primary \"#0066ff\" --logo-url https://cdn/logo.svg\\n' +\n ' suntropy config theme set --set graph1=#ff0000 --set graph2=#00ff00\\n' +\n ' suntropy config theme set --from-file theme.json'\n )\n .option('--primary <hex>', 'Primary colour')\n .option('--btn-primary <hex>', 'Primary button colour')\n .option('--btn-secondary <hex>', 'Secondary button colour')\n .option('--background <hex>', 'Background colour')\n .option('--navbar-background-color <hex>', 'Navbar background colour')\n .option('--logo-url <url>', 'Logo URL')\n .option('--favicon-url <url>', 'Favicon URL')\n .option('--client-app-title <title>', 'Visible app title')\n .option('--enable-custom-theme [bool]', 'Toggle the custom theme (true/false)')\n .option('--set <entries...>', 'Additional field assignments as key=value (repeatable)')\n .option('--from-file <path>', 'Load a partial payload from a JSON file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(theme);\n const client = createServiceClient('security', global);\n\n const flagValues: Record<string, unknown> = {\n primary: opts.primary,\n btnPrimary: opts.btnPrimary,\n btnSecondary: opts.btnSecondary,\n background: opts.background,\n navbarBackgroundColor: opts.navbarBackgroundColor,\n logoUrl: opts.logoUrl,\n faviconUrl: opts.faviconUrl,\n clientAppTitle: opts.clientAppTitle,\n enableCustomTheme: opts.enableCustomTheme === undefined ? undefined : opts.enableCustomTheme === true || opts.enableCustomTheme === 'true',\n };\n\n const payload = buildPayload(flagValues, opts.set, opts.fromFile, THEME_KEYS);\n if (Object.keys(payload).length === 0) {\n outputError(new Error('No fields provided. Use flags, --set, or --from-file.'));\n return;\n }\n\n const res = await client.post('/clients/config/updateTheme', payload);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n theme\n .command('edit')\n .description('Open $EDITOR with the theme JSON and PUT the edited result.')\n .requiredOption('--client-uid <uid>', 'Client UID to fetch the current theme from')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(theme);\n const client = createServiceClient('security', global);\n const current = await client.get(`/clients/config/clientThemeByClientUID/${opts.clientUid}`);\n const subset = pickKeys(current.data as Record<string, unknown>, THEME_KEYS);\n const edited = editJson(subset, 'theme');\n const res = await client.post('/clients/config/updateTheme', edited);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import { Command } from 'commander';\nimport { AxiosInstance } from 'axios';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError } from '../../output.js';\nimport { getGlobalOpts, buildPayload, editJson, pickKeys, coerceValue } from './shared.js';\n\n/** camelCase → kebab-case (\"logoUrl\" → \"logo-url\"). */\nfunction kebab(key: string): string {\n return key.replace(/[A-Z0-9]+/g, (m, i) => (i === 0 ? m.toLowerCase() : '-' + m.toLowerCase()));\n}\n\n/** One category of the advanced panel. */\ninterface Section {\n name: string;\n title: string;\n summary: string;\n fields: readonly string[];\n fieldDocs: Record<string, string>;\n}\n\nconst GENERAL: Section = {\n name: 'general',\n title: 'General configuration (branding, language, tracking, base aesthetics).',\n summary:\n 'Applies to the entire widget: navbar, favicon, global theme, analytics/pixels\\n' +\n 'and page-wide injected scripts. Equivalent to the \"General Configuration\"\\n' +\n 'panel in the Suntropy admin.',\n fields: [\n 'logoUrl', 'faviconUrl', 'tabTitle',\n 'onAddressButtonClick', 'onSendButtonClick',\n 'googleConversionId', 'googleConversionLabelOnAddress', 'googleConversionLabelOnSend',\n 'metaConversionId', 'customTrackingHTML',\n 'defaultLanguage', 'enableLanguageMenu',\n 'customColorOfElements', 'steticVariant', 'themeColor', 'navbarColor',\n 'addNumberToSteps', 'showFooter',\n ],\n fieldDocs: {\n logoUrl: 'Logo displayed in the navbar (and on the cover if includeLogoInCover=true). Empty = no logo.',\n faviconUrl: 'Browser tab favicon.',\n tabTitle: 'Browser tab title (HTML <title>).',\n onAddressButtonClick: 'JavaScript evaluated (eval) when the user hits \"Continue\" on the address step. ⚠ XSS risk; never accept untrusted input.',\n onSendButtonClick: 'JavaScript evaluated (eval) when the final form is submitted. Same XSS risk as above.',\n googleConversionId: 'Google Ads ID; injects gtag.js in <head>.',\n googleConversionLabelOnAddress: 'Google conversion label fired after the address step.',\n googleConversionLabelOnSend: 'Google conversion label fired on submit.',\n metaConversionId: 'Meta/Facebook pixel ID; fires a \"Lead\" event on submit.',\n customTrackingHTML: 'Arbitrary HTML/JS injected in <head> (Hotjar, Mixpanel, GTM…).',\n defaultLanguage: 'Initial language: en|es|fr|it|pt|cat. Falls back to browser pref, then \"en\".',\n enableLanguageMenu: 'Shows the language picker in the navbar. false pins the user to defaultLanguage.',\n customColorOfElements: 'Accent colour for buttons / active borders.',\n steticVariant: 'Visual variant: default (rounded) | sharped (hard corners) | simple (minimalist, no shadows).',\n themeColor: 'Primary colour (navbar, buttons, focus ring). Default #575757.',\n navbarColor: 'Overrides themeColor for the navbar only.',\n addNumberToSteps: 'Prefix step names with their number (\"1. Address\", …).',\n showFooter: 'Pins the footer to the bottom instead of inlining it in the flow.',\n },\n};\n\nconst COVER: Section = {\n name: 'cover',\n title: 'Cover / hero screen shown before the address step.',\n summary: 'Configures the first screen the user sees: title, subtitle, carousel background, colours and logo placement.',\n fields: [\n 'coverTitle', 'coverSubtitle',\n 'coverBackgroundImageUrl1', 'coverBackgroundImageUrl2', 'coverBackgroundImageUrl3', 'coverBackgroundImageUrl4',\n 'staticCoverImages',\n 'coverTextColor', 'coverFilterColor',\n 'includeLogoInCover',\n ],\n fieldDocs: {\n coverTitle: 'Hero title.',\n coverSubtitle: 'Hero subtitle below the title.',\n coverBackgroundImageUrl1: 'Background image #1 (also first frame of the carousel).',\n coverBackgroundImageUrl2: 'Background image #2.',\n coverBackgroundImageUrl3: 'Background image #3.',\n coverBackgroundImageUrl4: 'Background image #4.',\n staticCoverImages: 'true = no rotation (always shows the first image). false = carousel auto-rotates.',\n coverTextColor: 'Colour applied to coverTitle and coverSubtitle.',\n coverFilterColor: 'Overlay colour on top of the image. Default rgba(75,55,30,0.7); improves text contrast.',\n includeLogoInCover: 'true repeats the navbar logo on the cover. false keeps it only in the navbar.',\n },\n};\n\nconst SURFACES: Section = {\n name: 'surfaces',\n title: 'Surfaces step: the map where the user draws the roof polygon(s).',\n summary: 'Controls whether the step runs, how many surfaces are allowed, and the per-device help messages.',\n fields: ['surfaceStepEnabled', 'multipleSurfaces', 'enableMapMarker', 'messageOnDesktopDevices', 'messageOnMobileDevices'],\n fieldDocs: {\n surfaceStepEnabled: 'Enables/disables the whole step. false = the lead is sized without any polygon input.',\n multipleSurfaces: 'Allows drawing more than one roof surface per lead.',\n enableMapMarker: 'Drops a pin on the installation location over the satellite view.',\n messageOnDesktopDevices: 'Instruction text shown on desktop during the step.',\n messageOnMobileDevices: 'Instruction text shown on mobile (e.g. \"Tap to draw\").',\n },\n};\n\nconst CONSUMER: Section = {\n name: 'consumer',\n title: 'Consumer step: residential / commercial / community picker.',\n summary: 'Each subtype has its own visibility flag, image and label. defaultConsumptionPattern feeds the calculation engine.',\n fields: [\n 'consumerStepEnabled',\n 'residentialConsumerTypeEnabled', 'residentialConsumerImageUrl', 'residentialConsumerTitle',\n 'commercialConsumerTypeEnabled', 'commercialConsumerImageUrl', 'commercialConsumerTitle',\n 'communityConsumerTypeEnabled', 'communityConsumerImageUrl', 'communityConsumerTitle',\n 'defaultConsumptionPattern',\n ],\n fieldDocs: {\n consumerStepEnabled: 'Shows/hides the whole step.',\n residentialConsumerTypeEnabled: 'Makes the \"Residential\" option visible.',\n residentialConsumerImageUrl: 'Icon/photo for the Residential option.',\n residentialConsumerTitle: 'Residential label (e.g. \"Home\").',\n commercialConsumerTypeEnabled: 'Makes the \"Commercial\" option visible.',\n commercialConsumerImageUrl: 'Icon/photo for the Commercial option.',\n commercialConsumerTitle: 'Commercial label (e.g. \"Business\").',\n communityConsumerTypeEnabled: 'Makes the \"Community\" option visible.',\n communityConsumerImageUrl: 'Icon/photo for the Community option.',\n communityConsumerTitle: 'Community label.',\n defaultConsumptionPattern: 'Preselected pattern: Balance | Nightly | Morning | Afternoon | Domestic | Commercial | Community. Feeds the hourly curve used by the engine.',\n },\n};\n\nconst INCLINATION: Section = {\n name: 'inclination',\n title: 'Roof inclination step (flat / inclined / very inclined).',\n summary: 'Each variant carries its own image and label. defaultInclination is also used when the step is disabled.',\n fields: [\n 'inclinationStepEnabled',\n 'flatRoofImageUrl', 'textFlatRoof',\n 'inclinedRoofImageUrl', 'textInclinedRoof',\n 'veryInclinedRoofImageUrl', 'textVeryInclinedRoof',\n 'defaultInclination', 'inclinationStepTitle',\n ],\n fieldDocs: {\n inclinationStepEnabled: 'Shows/hides the step. When false, defaultInclination is fed directly into the calculation.',\n flatRoofImageUrl: 'Image for the flat-roof option (0-15°).',\n textFlatRoof: 'Label for flat roof. Default \"0-15°\".',\n inclinedRoofImageUrl: 'Image for the inclined-roof option (15-30°).',\n textInclinedRoof: 'Label for inclined roof. Default \"15-30°\".',\n veryInclinedRoofImageUrl: 'Image for the very-inclined option (>30°).',\n textVeryInclinedRoof: 'Label for very inclined roof. Default \">30°\".',\n defaultInclination: 'Degrees (0-90). Preselected value and fallback when the step is disabled.',\n inclinationStepTitle: 'Title for the step.',\n },\n};\n\nconst ORIENTATION: Section = {\n name: 'orientation',\n title: 'Roof orientation (azimuth) step.',\n summary: 'Directly impacts yield estimates.',\n fields: ['orientationStepEnabled', 'defaultOrientation'],\n fieldDocs: {\n orientationStepEnabled: 'Shows/hides the step. When false, defaultOrientation is fed to the engine.',\n defaultOrientation: 'Degrees 0-360 (0=N, 90=E, 180=S, 270=W).',\n },\n};\n\nconst PANELS: Section = {\n name: 'panels',\n title: 'Solar panel & kit-category selection step.',\n summary: 'Drives which panel + kit category the lead is sized with.',\n fields: ['panelStepEnabled', 'defaultSolarPanel', 'kitCategories', 'defaultKitCategoryId', 'panelSectionTitle', 'panelTitle'],\n fieldDocs: {\n panelStepEnabled: 'Shows/hides the step. When false, the backend uses defaultSolarPanel + defaultKitCategoryId unattended.',\n defaultSolarPanel: 'ID of the preselected SolarPanel (reference to the client inventory).',\n kitCategories: 'Array of kit categories offered to the lead. Each item: { id, name, description, priority }. Use --from-file for multi-item payloads.',\n defaultKitCategoryId: 'ID of the preselected kit category.',\n panelSectionTitle: 'Navbar/breadcrumb label for the panel section.',\n panelTitle: 'Step title.',\n },\n};\n\nconst CONSUMPTION: Section = {\n name: 'consumption',\n title: 'Electric-consumption input step.',\n summary: 'Controls the input mode and display density of the consumption step.',\n fields: ['showOnlyOneConsumptionFieldAtATime', 'defaultConsumptionIntroductionMode'],\n fieldDocs: {\n showOnlyOneConsumptionFieldAtATime: 'true = guided mode (one field per screen). false = all fields visible at once.',\n defaultConsumptionIntroductionMode: 'monthlyConsumption (kWh/month) | monthlySpending (EUR/month). User can toggle if both are enabled.',\n },\n};\n\nconst RESULTS: Section = {\n name: 'results',\n title: 'Results screen, contact form and calculation-engine hooks.',\n summary: 'Largest section: visual layout, form fields for lead capture, confirmation modal, and engine toggles (batteries, PPA, alternative endpoint).',\n fields: [\n 'resultsMode', 'resultsBackgroundImageUrl', 'hideBackgroundImageInResults', 'colorOfBackgroundInResults',\n 'includeLogoInResults', 'includeMapInResults', 'hideResults', 'hideROI', 'formTitle', 'formSubtitle',\n 'resultsWhenSent', 'colorOfResultsPanelBackground',\n 'showDniFieldOnResults', 'showPhonePrefixFieldOnResults', 'showTypeOfDocumentFieldOnResults',\n 'showDniValidationFieldOnResults', 'showPhoneNumberValidationFieldOnResults',\n 'showIdentifierValidationFieldOnResults', 'showSurnameValidationFieldOnResults', 'showTypeOfClientSelectorOnResults',\n 'titleModalOfConfirm', 'textModalOfConfirm',\n 'businessName', 'enablePeakPowerLimitation', 'includeBatteries', 'enabledPPACalculation',\n 'hideCommentField', 'alternativeCalculationEndpoint', 'alternativeCalculationLoadingMessage', 'redirectToShareable',\n ],\n fieldDocs: {\n resultsMode: 'Default (ROI, payback, savings) | SolarResource (irradiance map + technical data).',\n resultsBackgroundImageUrl: 'Background image behind the results panel.',\n hideBackgroundImageInResults: 'Hides the background image even when set.',\n colorOfBackgroundInResults: 'Overlay colour on top of the background image. Default rgba(75,55,30,0.7).',\n colorOfResultsPanelBackground: 'Background of the metrics card. Default rgba(0,0,0,0.5).',\n includeLogoInResults: 'Shows the logo on the results screen.',\n includeMapInResults: 'Shows the interactive map with the drawn panels.',\n hideResults: 'true = no metrics shown, only the contact form.',\n hideROI: 'Hides the payback/ROI widget.',\n formTitle: 'Contact form title.',\n formSubtitle: 'Contact form subtitle.',\n resultsWhenSent: 'true = results shown before submit. false = form must be filled first.',\n showDniFieldOnResults: 'Adds a DNI/CIF input to the form.',\n showPhonePrefixFieldOnResults: 'Adds a phone-prefix selector.',\n showTypeOfDocumentFieldOnResults: 'Adds a document-type selector.',\n showDniValidationFieldOnResults: 'Visual DNI validation (green check).',\n showPhoneNumberValidationFieldOnResults: 'Visual phone validation.',\n showIdentifierValidationFieldOnResults: 'Visual identifier validation.',\n showSurnameValidationFieldOnResults: 'Visual surname validation.',\n showTypeOfClientSelectorOnResults: 'Selector for Individual / Company / Community.',\n titleModalOfConfirm: 'Title of the confirmation modal shown before submit.',\n textModalOfConfirm: 'Body of the confirmation modal.',\n businessName: 'Adds a \"Business name\" field to the form.',\n enablePeakPowerLimitation: 'Adds a peak-power limiter to the consumption section. Affects engine sizing.',\n includeBatteries: 'Includes battery sizing in the results.',\n enabledPPACalculation: 'Enables PPA (Power Purchase Agreement) modelling.',\n hideCommentField: 'Hides the free-text comment field.',\n alternativeCalculationEndpoint: 'URL to which calculation data is POSTed instead of the default engine endpoint. For white-label integrations.',\n alternativeCalculationLoadingMessage: 'Loading text while awaiting the alternative endpoint response.',\n redirectToShareable: 'After calculation, redirect to the shareable-study URL instead of rendering results in-place.',\n },\n};\n\nconst CUSTOM_FIELDS: Section = {\n name: 'custom-fields',\n title: 'Extra lead fields persisted on the SolarStudy (plugin-gated).',\n summary: 'Only available when the client has the \"studyCustomFields\" plugin active.',\n fields: ['solarStudyCustomFields'],\n fieldDocs: {\n solarStudyCustomFields: 'Array of custom-field definitions, serialised. Each item: { id, label, type, required, options? }. Types: text|number|select|boolean. Use --from-file to avoid quoting headaches.',\n },\n};\n\nconst SECTIONS: readonly Section[] = [\n GENERAL, COVER, SURFACES, CONSUMER, INCLINATION, ORIENTATION, PANELS, CONSUMPTION, RESULTS, CUSTOM_FIELDS,\n];\n\nfunction getAdvanced(client: AxiosInstance): Promise<Record<string, unknown>> {\n return client.get('/solar-form/config/advanced').then((r) => r.data as Record<string, unknown>);\n}\n\nfunction putAdvanced(client: AxiosInstance, payload: Record<string, unknown>): Promise<unknown> {\n return client.put('/solar-form/config/advanced', payload).then((r) => r.data);\n}\n\n/** Build a \"Fields:\" help block for a section. */\nfunction formatFieldsHelp(section: Section): string {\n const longest = Math.max(...section.fields.map((f) => f.length));\n return [\n section.title,\n '',\n section.summary,\n '',\n 'Fields:',\n ...section.fields.map((f) => ` ${f.padEnd(longest)} ${section.fieldDocs[f] ?? ''}`),\n '',\n 'Operations: get | set [--set key=value] [--from-file] [--<field> <value>] | edit',\n ].join('\\n');\n}\n\nfunction attachSectionCommand(advanced: Command, section: Section): void {\n const sec = advanced\n .command(section.name)\n .description(formatFieldsHelp(section));\n\n sec\n .command('get')\n .description(`Fetch only the ${section.name} fields of the advanced config.`)\n .action(async () => {\n try {\n const global = getGlobalOpts(sec);\n const client = createServiceClient('solar', global);\n const doc = await getAdvanced(client);\n output(pickKeys(doc, section.fields), global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n const setCmd = sec\n .command('set')\n .description(\n `Update the ${section.name} fields of the advanced config.\\n` +\n 'Combine per-field flags, repeatable --set key=value, and/or --from-file.\\n' +\n 'Internally GETs the current config, merges this section, and PUTs the whole thing.'\n )\n .option('--set <entries...>', 'Field assignments as key=value (repeatable)')\n .option('--from-file <path>', 'Load a partial payload from a JSON file');\n\n for (const field of section.fields) {\n setCmd.option(`--${kebab(field)} <value>`, section.fieldDocs[field] ?? field);\n }\n\n setCmd.action(async (opts) => {\n try {\n const global = getGlobalOpts(sec);\n const client = createServiceClient('solar', global);\n\n const flagValues: Record<string, unknown> = {};\n for (const field of section.fields) {\n const val = opts[field];\n if (val !== undefined) flagValues[field] = coerceValue(String(val));\n }\n const partial = buildPayload(flagValues, opts.set, opts.fromFile, section.fields);\n if (Object.keys(partial).length === 0) {\n outputError(new Error('No fields provided. Use flags, --set, or --from-file.'));\n return;\n }\n\n const current = await getAdvanced(client);\n const merged = { ...current, ...partial };\n const res = await putAdvanced(client, merged);\n output(pickKeys(res as Record<string, unknown>, section.fields), global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n sec\n .command('edit')\n .description(`Open $EDITOR on the ${section.name} subset of the advanced config, then PUT the whole config.`)\n .action(async () => {\n try {\n const global = getGlobalOpts(sec);\n const client = createServiceClient('solar', global);\n const current = await getAdvanced(client);\n const subset = pickKeys(current, section.fields);\n const edited = editJson(subset, `advanced-${section.name}`);\n const merged = { ...current, ...edited };\n const res = await putAdvanced(client, merged);\n output(pickKeys(res as Record<string, unknown>, section.fields), global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n\nexport function registerAdvancedCommands(solarform: Command): void {\n const advanced = solarform\n .command('advanced')\n .description(\n 'SolarForm Advanced configuration (white-label microsite).\\n' +\n 'Each subcommand maps 1:1 with a section of the admin accordion and with a\\n' +\n 'subset of fields in the AdvancedSolarFormConfig DTO.\\n\\n' +\n 'Whole-payload operations:\\n' +\n ' get Fetch the full advanced config.\\n' +\n ' update Merge a partial payload (--set / --from-file).\\n' +\n ' delete Delete the authenticated client\\'s advanced config.\\n' +\n ' init-default Create the default config for a clientUID (superadmin / localhost).\\n\\n' +\n 'Sections (each: get / set / edit):\\n' +\n SECTIONS.map((s) => ` ${s.name.padEnd(14)} ${s.title}`).join('\\n') + '\\n\\n' +\n 'Conventions:\\n' +\n ' --set <field>=<value> Assign a single field (repeatable).\\n' +\n ' --from-file <path> Load a partial payload from JSON.\\n' +\n ' edit Open $EDITOR on the section\\'s current state.'\n );\n\n advanced\n .command('get')\n .description('Fetch the full AdvancedSolarFormConfig for the authenticated client.')\n .action(async () => {\n try {\n const global = getGlobalOpts(advanced);\n const client = createServiceClient('solar', global);\n const data = await getAdvanced(client);\n output(data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n advanced\n .command('update')\n .description('Merge a partial AdvancedSolarFormConfig from --set / --from-file and PUT.')\n .option('--set <entries...>', 'Field assignments as key=value (repeatable)')\n .option('--from-file <path>', 'Load a partial payload from a JSON file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(advanced);\n const client = createServiceClient('solar', global);\n const partial = buildPayload({}, opts.set, opts.fromFile);\n if (Object.keys(partial).length === 0) {\n outputError(new Error('No fields provided. Use --set or --from-file.'));\n return;\n }\n const current = await getAdvanced(client);\n const res = await putAdvanced(client, { ...current, ...partial });\n output(res, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n advanced\n .command('delete')\n .description('Delete the authenticated client\\'s advanced config.')\n .action(async () => {\n try {\n const global = getGlobalOpts(advanced);\n const client = createServiceClient('solar', global);\n const res = await client.delete('/solar-form/config/advanced');\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n advanced\n .command('init-default')\n .description(\n 'Create the default advanced config for a clientUID.\\n' +\n 'Restricted: requires the \"suntropy-auth: <clientUID>\" header or localhost execution.'\n )\n .requiredOption('--client-uid <uid>', 'Client UID to initialise')\n .option('--email <email>', 'Operator email (optional)')\n .option('--url <url>', 'Site URL (optional)')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(advanced);\n const client = createServiceClient('solar', global);\n const params: Record<string, string> = {};\n if (opts.email) params.email = opts.email;\n if (opts.url) params.url = opts.url;\n const res = await client.post(\n `/solar-form/config/default/advanced/${opts.clientUid}`,\n {},\n { params, headers: { 'suntropy-auth': opts.clientUid } },\n );\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n for (const section of SECTIONS) attachSectionCommand(advanced, section);\n}\n","import { Command } from 'commander';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError } from '../../output.js';\nimport { getGlobalOpts, buildPayload, editJson, pickKeys } from './shared.js';\nimport { registerAdvancedCommands } from './advanced.js';\n\n/** Fields accepted on SolarFormConfig (solar backend). */\nconst SOLARFORM_KEYS = [\n 'idSolarFormConfig',\n 'clientUID',\n 'solarFormUrl',\n 'enabled',\n 'notificationEmailAddress',\n 'confirmationReplytoEmailAdress',\n 'notificationEmailSubject',\n 'enableNotificationEmail',\n 'enableSendConfirmationEmailToClient',\n 'confirmationEmailSubject',\n 'confirmationEmailBody',\n 'enableConfirmationEmailBody',\n 'formTitle',\n 'formSubtitle',\n 'formBackgroundColor',\n 'formBackgroundImageURL',\n 'formFaviconUrl',\n 'locationMode',\n 'hideFinalProjectPrice',\n 'enableRequiredPhoneNumberField',\n 'enableRequiredNameField',\n 'callToActionButtonText',\n 'renderPDF',\n 'defaultSolarStudyTemplateId',\n 'redirectUrl',\n 'privacyPolicy',\n 'advertisingPolicy',\n 'generateShareable',\n 'incentiveTemplateGroup',\n 'disabledSolarForm',\n 'redirectOnClose',\n] as const;\n\nexport function registerSolarformConfigCommands(configRoot: Command): void {\n const solarform = configRoot\n .command('solarform')\n .description(\n 'SolarForm (basic) and SolarForm Advanced configuration (solar service).\\n' +\n 'The basic config controls the public lead-capture form (URL, notifications,\\n' +\n 'appearance, mandatory fields). The advanced subtree configures the modern\\n' +\n 'white-label widget rendered by the \"advanced-solar-form\" microsite.\\n\\n' +\n 'Endpoints:\\n' +\n ' GET /solar-form/get-solar-form-config?getParameters=\\n' +\n ' GET /solar-form/solar-form-config (public, resolved by Origin)\\n' +\n ' POST /solar-form/solar-form-config?getParameters=\\n' +\n ' PUT /solar-form/solar-form-config/:id'\n );\n\n solarform\n .command('get')\n .description('Fetch the current SolarForm configuration for the authenticated client.')\n .option('--with-parameters', 'Include the associated SolarFormParameters in the response')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(solarform);\n const client = createServiceClient('solar', global);\n const params: Record<string, string> = {};\n if (opts.withParameters) params.getParameters = 'true';\n const res = await client.get('/solar-form/get-solar-form-config', { params });\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n solarform\n .command('create')\n .description(\n 'Create a new SolarFormConfig for the authenticated client.\\n' +\n '--url is the public slug/URL of the form. Other fields may come from flags,\\n' +\n '--set key=value, or --from-file. Accepted keys:\\n' +\n ' ' + SOLARFORM_KEYS.join(', ')\n )\n .requiredOption('--url <slug>', 'Public URL/slug of the form (solarFormUrl)')\n .option('--enabled [bool]', 'Whether the form is publicly enabled', 'true')\n .option('--form-title <text>', 'Form title displayed to the end user')\n .option('--form-subtitle <text>', 'Form subtitle')\n .option('--form-background-color <color>', 'Background colour of the form container')\n .option('--form-background-image-url <url>', 'Background image URL')\n .option('--form-favicon-url <url>', 'Favicon URL')\n .option('--call-to-action-button-text <text>', 'Primary CTA button label')\n .option('--notification-email-address <email>', 'Where new lead notifications go')\n .option('--location-mode <mode>', 'fullSurface | locationOnly')\n .option('--with-parameters', 'Include SolarFormParameters in the response')\n .option('--set <entries...>', 'Additional field assignments as key=value (repeatable)')\n .option('--from-file <path>', 'Load a payload from a JSON file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(solarform);\n const client = createServiceClient('solar', global);\n\n const flagValues: Record<string, unknown> = {\n solarFormUrl: opts.url,\n enabled: opts.enabled === undefined ? undefined : opts.enabled === true || opts.enabled === 'true',\n formTitle: opts.formTitle,\n formSubtitle: opts.formSubtitle,\n formBackgroundColor: opts.formBackgroundColor,\n formBackgroundImageURL: opts.formBackgroundImageUrl,\n formFaviconUrl: opts.formFaviconUrl,\n callToActionButtonText: opts.callToActionButtonText,\n notificationEmailAddress: opts.notificationEmailAddress,\n locationMode: opts.locationMode,\n };\n const payload = buildPayload(flagValues, opts.set, opts.fromFile, SOLARFORM_KEYS);\n\n const params: Record<string, string> = {};\n if (opts.withParameters) params.getParameters = 'true';\n const res = await client.post('/solar-form/solar-form-config', payload, { params });\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n solarform\n .command('update <idSolarFormConfig>')\n .description('Update an existing SolarFormConfig by numeric ID.')\n .option('--set <entries...>', 'Additional field assignments as key=value (repeatable)')\n .option('--from-file <path>', 'Load a payload from a JSON file')\n .option('--form-title <text>', 'Form title')\n .option('--form-subtitle <text>', 'Form subtitle')\n .option('--enabled [bool]', 'Whether the form is publicly enabled')\n .option('--disabled-solar-form [bool]', 'Explicit disable flag')\n .action(async (idSolarFormConfig, opts) => {\n try {\n const global = getGlobalOpts(solarform);\n const client = createServiceClient('solar', global);\n\n const flagValues: Record<string, unknown> = {\n formTitle: opts.formTitle,\n formSubtitle: opts.formSubtitle,\n enabled: opts.enabled === undefined ? undefined : opts.enabled === true || opts.enabled === 'true',\n disabledSolarForm: opts.disabledSolarForm === undefined ? undefined : opts.disabledSolarForm === true || opts.disabledSolarForm === 'true',\n };\n const payload = buildPayload(flagValues, opts.set, opts.fromFile, SOLARFORM_KEYS);\n if (Object.keys(payload).length === 0) {\n outputError(new Error('No fields to update.'));\n return;\n }\n\n const res = await client.put(`/solar-form/solar-form-config/${idSolarFormConfig}`, payload);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n solarform\n .command('edit')\n .description('Fetch the current SolarForm config, open $EDITOR, and PUT the edited result.')\n .action(async () => {\n try {\n const global = getGlobalOpts(solarform);\n const client = createServiceClient('solar', global);\n const current = await client.get('/solar-form/get-solar-form-config');\n const doc = current.data as Record<string, unknown>;\n const id = doc?.idSolarFormConfig;\n if (!id) {\n outputError(new Error('No existing SolarFormConfig found to edit. Use \"create\" first.'));\n return;\n }\n const subset = pickKeys(doc, SOLARFORM_KEYS);\n const edited = editJson(subset, 'solarform');\n const res = await client.put(`/solar-form/solar-form-config/${id}`, edited);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n registerAdvancedCommands(solarform);\n}\n","import { Command } from 'commander';\nimport { loadConfig, saveConfig, setConfigValue, getConfigValue } from '../config.js';\nimport { output, outputError } from '../output.js';\nimport { registerThemeCommands } from './config/theme.js';\nimport { registerSolarformConfigCommands } from './config/solarform.js';\n\nexport function registerConfigCommands(program: Command): void {\n const cfg = program\n .command('config')\n .description(\n 'CLI configuration (profiles, server, token) plus tenant configuration\\n' +\n '(theme & SolarForm / SolarForm Advanced) served by the security and solar backends.'\n );\n\n cfg\n .command('set <key> <value>')\n .description('Set a configuration value. Keys: server, token, activeProfile')\n .option('--profile <name>', 'Profile to modify')\n .action((key, value, opts) => {\n try {\n if (key === 'activeProfile') {\n const config = loadConfig();\n config.activeProfile = value;\n saveConfig(config);\n } else {\n setConfigValue(key, value, opts.profile);\n }\n output({ success: true, key, value });\n } catch (err) {\n outputError(err);\n }\n });\n\n cfg\n .command('get <key>')\n .description('Get a configuration value')\n .option('--profile <name>', 'Profile to read from')\n .action((key, opts) => {\n try {\n if (key === 'activeProfile') {\n const config = loadConfig();\n output({ activeProfile: config.activeProfile });\n } else {\n output({ [key]: getConfigValue(key, opts.profile) });\n }\n } catch (err) {\n outputError(err);\n }\n });\n\n cfg\n .command('list')\n .description('Show all configuration')\n .action(() => {\n try {\n const config = loadConfig();\n // Redact tokens for display\n const safe = JSON.parse(JSON.stringify(config));\n for (const [name, profile] of Object.entries(safe.profiles)) {\n const p = profile as Record<string, unknown>;\n if (p.token) p.token = (p.token as string).slice(0, 20) + '...';\n }\n output(safe);\n } catch (err) {\n outputError(err);\n }\n });\n\n cfg\n .command('create-profile <name>')\n .description('Create a new profile')\n .option('--server <url>', 'API server URL', 'https://api.enerlence.com')\n .action((name, opts) => {\n try {\n const config = loadConfig();\n if (config.profiles[name]) {\n outputError(new Error(`Profile \"${name}\" already exists`));\n return;\n }\n config.profiles[name] = { server: opts.server };\n saveConfig(config);\n output({ success: true, profile: name, server: opts.server });\n } catch (err) {\n outputError(err);\n }\n });\n\n cfg\n .command('use <name>')\n .description('Switch to a profile')\n .action((name) => {\n try {\n const config = loadConfig();\n if (!config.profiles[name]) {\n outputError(new Error(`Profile \"${name}\" not found. Available: ${Object.keys(config.profiles).join(', ')}`));\n return;\n }\n config.activeProfile = name;\n saveConfig(config);\n output({ success: true, activeProfile: name });\n } catch (err) {\n outputError(err);\n }\n });\n\n registerThemeCommands(cfg);\n registerSolarformConfigCommands(cfg);\n}\n","import { Command } from 'commander';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, outputPaginated, type OutputOptions } from '../../output.js';\n\nexport interface ResourceConfig {\n /** Command name (e.g. 'panels') */\n name: string;\n /** Singular display name (e.g. 'solar panel') */\n singular: string;\n /** API base path (e.g. '/solar-panels') */\n basePath: string;\n /** ID field name in the entity (e.g. 'solarPanelId') */\n idField: string;\n /** Fields to show in list view (summary) */\n listFields: string[];\n /** POST path for advanced filter, if different from basePath + '/filter' */\n filterPath?: string;\n /** Batch delete path suffix */\n batchDeletePath?: string;\n /** PUT uses body without ID in URL (some endpoints use PUT / with body containing id) */\n putBodyOnly?: boolean;\n /** Backend service */\n service?: 'solar' | 'templates' | 'security';\n /** Custom GET path pattern. Use ':id' as placeholder (e.g. '/custom-asset/id/:id') */\n getPath?: string;\n /** Use POST filter to get by ID (when no GET :id endpoint exists) */\n getViaFilter?: boolean;\n}\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & { server?: string; token?: string; profile?: string; verbose?: boolean } {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\nfunction parseData(data: string | undefined): Record<string, unknown> | undefined {\n if (!data) return undefined;\n if (data === '-') {\n // Read from stdin - synchronous for simplicity\n const { readFileSync } = require('fs');\n const input = readFileSync(0, 'utf-8');\n return JSON.parse(input);\n }\n return JSON.parse(data);\n}\n\nexport function createResourceCommands(cfg: ResourceConfig): Command {\n const cmd = new Command(cfg.name).description(`Manage ${cfg.singular}s`);\n const service = cfg.service || 'solar';\n\n // --- list ---\n cmd\n .command('list')\n .description(`List ${cfg.singular}s with pagination. Fields: ${cfg.listFields.join(', ')}`)\n .option('--limit <n>', 'Max results', '20')\n .option('--offset <n>', 'Skip results', '0')\n .option('--active-only', 'Only active items (exclude inactive)')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(cmd);\n const client = createServiceClient(service, global);\n const params: Record<string, unknown> = {\n limit: parseInt(opts.limit),\n offset: parseInt(opts.offset),\n };\n if (!opts.activeOnly) params.unactive = true;\n\n const res = await client.get(cfg.basePath, { params });\n // API may return: [items[], totalCount] tuple, {data: [], total} object, or plain array\n let data: unknown[];\n let total: number;\n if (Array.isArray(res.data) && res.data.length >= 2 && Array.isArray(res.data[0]) && typeof res.data[1] === 'number') {\n // Tuple format: [items[], totalCount]\n data = res.data[0];\n total = res.data[1];\n } else if (Array.isArray(res.data)) {\n data = res.data;\n total = res.data.length;\n } else {\n data = res.data?.data || [];\n total = res.data?.total ?? data.length;\n }\n\n // Apply list field summary unless user specified --fields\n const outOpts: OutputOptions = { ...global };\n if (!global.fields && cfg.listFields.length > 0) {\n outOpts.fields = [cfg.idField, ...cfg.listFields].join(',');\n }\n\n if (Array.isArray(data)) {\n outputPaginated(data, total, parseInt(opts.limit), parseInt(opts.offset), outOpts);\n } else {\n output(data, outOpts);\n }\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- get ---\n cmd\n .command('get <id>')\n .description(`Get a ${cfg.singular} by ID. All fields returned by default.`)\n .action(async (id) => {\n try {\n const global = getGlobalOpts(cmd);\n const client = createServiceClient(service, global);\n if (cfg.getViaFilter) {\n // No GET :id endpoint — fetch all and filter client-side\n const res = await client.get(cfg.basePath, { params: { unactive: true } });\n const all = Array.isArray(res.data) ? res.data : (Array.isArray(res.data?.[0]) ? res.data[0] : res.data?.data || []);\n const idNum = parseInt(id);\n const item = all.find((r: Record<string, unknown>) => r[cfg.idField] === idNum || r[cfg.idField] === id);\n if (!item) { outputError(new Error(`${cfg.singular} with ${cfg.idField}=${id} not found`)); return; }\n output(item, global);\n } else {\n const url = cfg.getPath ? cfg.getPath.replace(':id', id) : `${cfg.basePath}/${id}`;\n const res = await client.get(url);\n output(res.data, global);\n }\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- create ---\n cmd\n .command('create')\n .description(`Create a new ${cfg.singular}. Pass JSON via --data or stdin (--data -)`)\n .requiredOption('--data <json>', 'JSON data (or - for stdin)')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(cmd);\n const client = createServiceClient(service, global);\n const body = parseData(opts.data);\n const res = await client.post(cfg.basePath, body);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- update ---\n cmd\n .command('update <id>')\n .description(`Update a ${cfg.singular}`)\n .requiredOption('--data <json>', 'JSON data with fields to update (or - for stdin)')\n .action(async (id, opts) => {\n try {\n const global = getGlobalOpts(cmd);\n const client = createServiceClient(service, global);\n const body = parseData(opts.data);\n if (cfg.putBodyOnly) {\n const res = await client.put(cfg.basePath, { ...body, [cfg.idField]: id });\n output(res.data, global);\n } else {\n const res = await client.put(`${cfg.basePath}/${id}`, body);\n output(res.data, global);\n }\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- delete ---\n cmd\n .command('delete <id>')\n .description(`Delete a ${cfg.singular}`)\n .action(async (id) => {\n try {\n const global = getGlobalOpts(cmd);\n const client = createServiceClient(service, global);\n const res = await client.delete(`${cfg.basePath}/${id}`);\n output(res.data ?? { success: true, deleted: id }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- delete-batch ---\n if (cfg.batchDeletePath) {\n cmd\n .command('delete-batch')\n .description(`Batch delete ${cfg.singular}s`)\n .requiredOption('--ids <ids>', 'Comma-separated IDs')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(cmd);\n const client = createServiceClient(service, global);\n const ids = opts.ids.split(',').map((s: string) => s.trim());\n const res = await client.post(`${cfg.basePath}/${cfg.batchDeletePath}`, ids);\n output(res.data ?? { success: true, deleted: ids.length }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n }\n\n // --- filter ---\n cmd\n .command('filter')\n .description(`Advanced filter for ${cfg.singular}s. Pass filter query as JSON.`)\n .requiredOption('--query <json>', 'Filter query JSON (or - for stdin)')\n .option('--limit <n>', 'Max results', '20')\n .option('--offset <n>', 'Skip results', '0')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(cmd);\n const client = createServiceClient(service, global);\n const query = parseData(opts.query);\n const filterUrl = cfg.filterPath || `${cfg.basePath}/filter`;\n const res = await client.post(filterUrl, {\n ...query,\n limit: parseInt(opts.limit),\n offset: parseInt(opts.offset),\n });\n const data = Array.isArray(res.data) ? res.data : res.data?.data || res.data;\n const total = res.data?.total ?? (Array.isArray(data) ? data.length : 0);\n outputPaginated(data, total, parseInt(opts.limit), parseInt(opts.offset), global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { createResourceCommands } from './factory.js';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\nfunction parseData(data: string): Record<string, unknown> {\n if (data === '-') {\n const { readFileSync } = require('fs');\n return JSON.parse(readFileSync(0, 'utf-8'));\n }\n return JSON.parse(data);\n}\n\nexport function registerKitsCommands(inventory: Command): void {\n // Base kit CRUD via factory\n const kits = createResourceCommands({\n name: 'kits',\n singular: 'solar kit',\n basePath: '/solar-kits',\n idField: 'idSolarKit',\n listFields: ['identifier', 'peakPower', 'panelNumber', 'inverterNumber', 'price', 'totalPrice', 'phaseNumber', 'active'],\n filterPath: '/solar-kits/filters',\n batchDeletePath: 'delete-batch-solar-kits',\n getViaFilter: true,\n });\n\n // Remove factory-generated 'create' — use 'assemble' instead for safe kit creation\n const kitsCreateIdx = kits.commands.findIndex((c: Command) => c.name() === 'create');\n if (kitsCreateIdx !== -1) kits.commands.splice(kitsCreateIdx, 1);\n\n // --- archive ---\n kits\n .command('archive <kitId>')\n .description('Archive a solar kit (soft-disable)')\n .action(async (kitId) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.put(`/solar-kits/archive/${kitId}`);\n output(res.data ?? { success: true, archived: kitId }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- Kit panels sub-commands ---\n const kitPanels = kits.command('panels').description('Manage kit solar panels');\n\n kitPanels\n .command('list')\n .description('List all kit solar panels. Fields: idKitSolarPanel, name, manufacturer, peakPower, efficiency, costPerUnit')\n .option('--limit <n>', 'Max results', '50')\n .option('--offset <n>', 'Skip results', '0')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.get('/solar-kits/solar-panels', { params: { limit: opts.limit, offset: opts.offset } });\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitPanels\n .command('get <id>')\n .description('Get a kit solar panel by ID')\n .action(async (id) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n // Use filter to get by ID since there's no direct GET by ID\n const res = await client.post('/solar-kits/solar-panels/filter', { idKitSolarPanel: id });\n const data = Array.isArray(res.data) ? res.data[0] : res.data?.data?.[0] || res.data;\n output(data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitPanels\n .command('create')\n .description('Create a kit solar panel')\n .requiredOption('--data <json>', 'JSON data')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.post('/solar-kits/solar-panels', parseData(opts.data));\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitPanels\n .command('update <id>')\n .description('Update a kit solar panel')\n .requiredOption('--data <json>', 'JSON data')\n .action(async (id, opts) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.put(`/solar-kits/solar-panels/${id}`, parseData(opts.data));\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitPanels\n .command('delete <id>')\n .description('Delete a kit solar panel')\n .action(async (id) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.delete(`/solar-kits/solar-panels/${id}`);\n output(res.data ?? { success: true, deleted: id }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitPanels\n .command('featured <kitPanelId>')\n .description('List solar kits that feature this kit panel')\n .action(async (kitPanelId) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.get(`/solar-kits/solar-panels/findFeaturedSolarKits/${kitPanelId}`);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- Kit inverters sub-commands ---\n const kitInverters = kits.command('inverters').description('Manage kit inverters');\n\n kitInverters\n .command('list')\n .description('List all kit inverters. Fields: idKitInverter, name, manufacturer, nominalPower, efficiency, costPerUnit')\n .option('--limit <n>', 'Max results', '50')\n .option('--offset <n>', 'Skip results', '0')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.get('/solar-kits/inverters', { params: { limit: opts.limit, offset: opts.offset } });\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitInverters\n .command('create')\n .description('Create a kit inverter')\n .requiredOption('--data <json>', 'JSON data')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.post('/solar-kits/inverters', parseData(opts.data));\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitInverters\n .command('update <id>')\n .description('Update a kit inverter')\n .requiredOption('--data <json>', 'JSON data')\n .action(async (id, opts) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.put(`/solar-kits/inverters/${id}`, parseData(opts.data));\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitInverters\n .command('delete <id>')\n .description('Delete a kit inverter')\n .action(async (id) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.delete(`/solar-kits/inverters/${id}`);\n output(res.data ?? { success: true, deleted: id }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitInverters\n .command('featured <kitInverterId>')\n .description('List solar kits that feature this kit inverter')\n .action(async (kitInverterId) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.get(`/solar-kits/inverters/findFeaturedSolarKits/${kitInverterId}`);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- Kit batteries sub-commands ---\n const kitBatteries = kits.command('batteries').description('Manage kit batteries');\n\n kitBatteries\n .command('list')\n .description('List all kit batteries. Fields: idKitBattery, name, manufacturer, capacity, costPerUnit')\n .option('--limit <n>', 'Max results', '50')\n .option('--offset <n>', 'Skip results', '0')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.get('/solar-kits/batteries', { params: { limit: opts.limit, offset: opts.offset } });\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitBatteries\n .command('create')\n .description('Create a kit battery')\n .requiredOption('--data <json>', 'JSON data')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.post('/solar-kits/batteries', parseData(opts.data));\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitBatteries\n .command('delete <id>')\n .description('Delete a kit battery')\n .action(async (id) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.delete(`/solar-kits/batteries/${id}`);\n output(res.data ?? { success: true, deleted: id }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- assemble: create kit from existing components by ID ---\n kits\n .command('assemble')\n .description(\n 'Assemble a solar kit from existing components by ID.\\n' +\n 'References kit panels, inverters, batteries, and custom assets by their IDs.\\n\\n' +\n 'Custom assets format: --custom-asset <assetId>:<units> (repeatable)\\n\\n' +\n 'Examples:\\n' +\n ' suntropy inventory kits assemble --name \"Kit 5kW\" --panel 123 --inverter 456 --panels-count 12 --price 6500\\n' +\n ' suntropy inventory kits assemble --name \"Kit Premium\" --panel 123 --inverter 456 --battery 789 \\\\\\n' +\n ' --panels-count 12 --inverters-count 1 --batteries-count 1 --peak-power 5.4 --price 8500 \\\\\\n' +\n ' --custom-asset 100:12 --custom-asset 200:1 --phase single_phase'\n )\n .requiredOption('--name <identifier>', 'Kit name/identifier')\n .option('--panel <kitPanelId>', 'Kit panel ID (idKitSolarPanel)')\n .option('--inverter <kitInverterId>', 'Kit inverter ID (idKitInverter)')\n .option('--battery <batteryId>', 'Battery ID from inventory (batteryId)')\n .option('--panels-count <n>', 'Number of panels', '12')\n .option('--inverters-count <n>', 'Number of inverters', '1')\n .option('--batteries-count <n>', 'Number of batteries', '0')\n .option('--peak-power <kW>', 'Total peak power in kW')\n .requiredOption('--price <eur>', 'Kit price in EUR (required)')\n .option('--phase <type>', 'Phase: single_phase or three_phase', 'single_phase')\n .option('--coplanar', 'Coplanar mounting')\n .option('--taxes <pct>', 'Default tax percentage', '21')\n .option('--custom-asset <id:units>', 'Custom asset as id:units (repeatable)', collectCustomAssets, [])\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n\n // Validate component IDs exist as kit entities before assembling\n const validationErrors: string[] = [];\n\n if (opts.panel) {\n try {\n const res = await client.post('/solar-kits/solar-panels/filter', { idKitSolarPanel: parseInt(opts.panel) });\n const data = Array.isArray(res.data) ? res.data : res.data?.data || [];\n if (data.length === 0) {\n validationErrors.push(\n `Panel ID ${opts.panel} is not a KitSolarPanel. ` +\n `Use \"suntropy inventory kits panels list\" to see available kit panels, ` +\n `or \"suntropy inventory kits panels create --data '{...}'\" to create one first.`\n );\n }\n } catch {\n validationErrors.push(\n `Could not validate panel ID ${opts.panel}. ` +\n `Make sure it is a KitSolarPanel ID (not a regular inventory panel). ` +\n `Use \"suntropy inventory kits panels list\" to see available kit panels.`\n );\n }\n }\n\n if (opts.inverter) {\n try {\n const res = await client.get('/solar-kits/inverters', { params: { limit: 200 } });\n const inverters = Array.isArray(res.data) ? res.data : res.data?.data || [];\n const found = inverters.find((inv: Record<string, unknown>) =>\n String(inv.idKitInverter) === String(opts.inverter)\n );\n if (!found) {\n validationErrors.push(\n `Inverter ID ${opts.inverter} is not a KitInverter. ` +\n `Use \"suntropy inventory kits inverters list\" to see available kit inverters, ` +\n `or \"suntropy inventory kits inverters create --data '{...}'\" to create one first.`\n );\n }\n } catch {\n validationErrors.push(\n `Could not validate inverter ID ${opts.inverter}. ` +\n `Make sure it is a KitInverter ID (not a regular inventory inverter). ` +\n `Use \"suntropy inventory kits inverters list\" to see available kit inverters.`\n );\n }\n }\n\n if (opts.battery) {\n try {\n const res = await client.get('/solar-kits/batteries', { params: { limit: 200 } });\n const batteries = Array.isArray(res.data) ? res.data : res.data?.data || [];\n const found = batteries.find((bat: Record<string, unknown>) =>\n String(bat.idKitBattery) === String(opts.battery)\n );\n if (!found) {\n validationErrors.push(\n `Battery ID ${opts.battery} is not a KitBattery. ` +\n `Use \"suntropy inventory kits batteries list\" to see available kit batteries, ` +\n `or \"suntropy inventory kits batteries create --data '{...}'\" to create one first.`\n );\n }\n } catch {\n validationErrors.push(\n `Could not validate battery ID ${opts.battery}. ` +\n `Make sure it is a KitBattery ID (not a regular inventory battery). ` +\n `Use \"suntropy inventory kits batteries list\" to see available kit batteries.`\n );\n }\n }\n\n if (validationErrors.length > 0) {\n outputError({\n error: true,\n message: 'Kit assembly validation failed',\n issues: validationErrors,\n hint: 'The assemble command requires KitSolarPanel, KitInverter, and KitBattery IDs — these are kit-specific entities, not regular inventory items.',\n });\n return;\n }\n\n const body: Record<string, unknown> = {\n identifier: opts.name,\n panelNumber: parseInt(opts.panelsCount),\n inverterNumber: parseInt(opts.invertersCount),\n batteriesNumber: parseInt(opts.batteriesCount),\n phaseNumber: opts.phase,\n defaultTaxesPercentage: parseFloat(opts.taxes),\n active: true,\n };\n\n if (opts.panel) body.kitSolarPanel = { idKitSolarPanel: parseInt(opts.panel) };\n if (opts.inverter) body.kitInverter = { idKitInverter: parseInt(opts.inverter) };\n if (opts.battery) body.battery = { batteryId: parseInt(opts.battery) };\n if (opts.peakPower) body.peakPower = parseFloat(opts.peakPower);\n body.price = parseFloat(opts.price);\n if (opts.coplanar) body.coplanar = true;\n\n if (opts.customAsset && opts.customAsset.length > 0) {\n body.solarKitCustomAssets = opts.customAsset.map((ca: { id: number; units: number }) => ({\n customAsset: { idCustomAsset: ca.id },\n units: ca.units,\n }));\n }\n\n const res = await client.post('/solar-kits', body);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n inventory.addCommand(kits);\n}\n\n/** Collector for repeatable --custom-asset <id:units> option */\nfunction collectCustomAssets(value: string, previous: { id: number; units: number }[]): { id: number; units: number }[] {\n const [idStr, unitsStr] = value.split(':');\n const id = parseInt(idStr);\n const units = unitsStr ? parseInt(unitsStr) : 1;\n if (isNaN(id)) throw new Error(`Invalid custom asset format: \"${value}\". Use <id>:<units> (e.g. 100:12)`);\n return [...previous, { id, units }];\n}\n","import { Command } from 'commander';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\nexport function registerManufacturersCommands(inventory: Command): void {\n const mfr = inventory.command('manufacturers').description('Manage manufacturers (referenced by all inventory devices)');\n\n mfr\n .command('list')\n .description('List all manufacturers. Fields: idManufacturer, name, imageUrl')\n .action(async () => {\n try {\n const global = getGlobalOpts(mfr);\n const client = createServiceClient('solar', global);\n const res = await client.get('/manufacturers');\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n mfr\n .command('create')\n .description('Create a new manufacturer')\n .requiredOption('--data <json>', 'JSON: { \"name\": \"Manufacturer Name\", \"imageUrl\": \"...\" }')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(mfr);\n const client = createServiceClient('solar', global);\n const body = JSON.parse(opts.data);\n const res = await client.post('/manufacturers', body);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import { Command } from 'commander';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\nfunction parseData(data: string | undefined): Record<string, unknown> | undefined {\n if (!data) return undefined;\n return JSON.parse(data);\n}\n\nexport function registerCustomFieldsCommands(inventory: Command): void {\n const fields = inventory.command('custom-fields').description(\n 'Manage custom fields for custom asset types.\\n' +\n 'Fields define the schema of a custom asset type (e.g. text, number, options).\\n' +\n 'Types: text, number, date, datetime, time, email, phonenumber, website, options, labels, currency, large_text, user'\n );\n\n // --- list ---\n fields\n .command('list')\n .description('List all custom fields')\n .action(async () => {\n try {\n const global = getGlobalOpts(fields);\n const client = createServiceClient('solar', global);\n const res = await client.get('/custom-asset/custom-field/all');\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- get ---\n fields\n .command('get <id>')\n .description('Get a custom field by ID')\n .action(async (id) => {\n try {\n const global = getGlobalOpts(fields);\n const client = createServiceClient('solar', global);\n const res = await client.get(`/custom-asset/custom-field/id/${id}`);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- create ---\n fields\n .command('create')\n .description(\n 'Create a custom field for a custom asset type.\\n' +\n 'Required: label, type, customAssetTypeId\\n' +\n 'For options/labels type, include customFieldOptions array.\\n\\n' +\n 'Example:\\n' +\n ' suntropy inventory custom-fields create --data \\'{\"label\":\"Power\",\"type\":\"number\",\"customAssetTypeId\":1}\\'\\n' +\n ' suntropy inventory custom-fields create --data \\'{\"label\":\"Size\",\"type\":\"options\",\"customAssetTypeId\":1,\"customFieldOptions\":[{\"label\":\"S\",\"value\":\"s\"},{\"label\":\"M\",\"value\":\"m\"},{\"label\":\"L\",\"value\":\"l\"}]}\\''\n )\n .requiredOption('--data <json>', 'Field definition as JSON')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(fields);\n const client = createServiceClient('solar', global);\n const body = parseData(opts.data);\n const res = await client.post('/custom-asset/custom-field', body);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- update ---\n fields\n .command('update <id>')\n .description('Update a custom field')\n .requiredOption('--data <json>', 'Updated field data as JSON')\n .action(async (id, opts) => {\n try {\n const global = getGlobalOpts(fields);\n const client = createServiceClient('solar', global);\n const body = parseData(opts.data);\n const res = await client.put(`/custom-asset/custom-field/${id}`, body);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- delete ---\n fields\n .command('delete <id>')\n .description('Delete a custom field')\n .action(async (id) => {\n try {\n const global = getGlobalOpts(fields);\n const client = createServiceClient('solar', global);\n const res = await client.delete(`/custom-asset/custom-field/${id}`);\n output(res.data ?? { success: true, deleted: id }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import { Command } from 'commander';\nimport { createResourceCommands, type ResourceConfig } from './factory.js';\nimport { registerKitsCommands } from './kits.js';\nimport { registerManufacturersCommands } from './manufacturers.js';\nimport { registerCustomFieldsCommands } from './custom-fields.js';\n\nconst RESOURCES: ResourceConfig[] = [\n {\n name: 'panels',\n singular: 'solar panel',\n basePath: '/solar-panels',\n idField: 'solarPanelId',\n listFields: ['name', 'manufacturer', 'peakPower', 'efficiency', 'costPerUnit', 'active'],\n batchDeletePath: 'delete-batch-solar-panels',\n },\n {\n name: 'inverters',\n singular: 'solar inverter',\n basePath: '/solar-inverter',\n idField: 'idInverter',\n listFields: ['name', 'manufacturer', 'nominalPower', 'efficiency', 'phaseNumber', 'isMicroinverter', 'isHybrid', 'costPerUnit', 'active'],\n batchDeletePath: 'delete-batch-solar-inverters',\n putBodyOnly: true,\n },\n {\n name: 'batteries',\n singular: 'battery',\n basePath: '/solar-battery',\n idField: 'batteryId',\n listFields: ['name', 'manufacturer', 'capacity', 'isModular', 'costPerUnit', 'active'],\n batchDeletePath: 'delete-batch-solar-batteries',\n },\n {\n name: 'chargers',\n singular: 'VE charger',\n basePath: '/charger',\n idField: 'idCharger',\n listFields: ['name', 'manufacturer', 'maxPower', 'connectorType', 'phaseNumber', 'costPerUnit', 'active'],\n batchDeletePath: 'delete-batch-chargers',\n putBodyOnly: true,\n },\n {\n name: 'heatpumps',\n singular: 'heat pump',\n basePath: '/heat-pump',\n idField: 'idHeatpump',\n listFields: ['name', 'manufacturer', 'lowerPower', 'upperPower', 'scop', 'costPerUnit', 'active'],\n batchDeletePath: 'delete-batch-heatpumps',\n putBodyOnly: true,\n },\n {\n name: 'custom-assets',\n singular: 'custom asset',\n basePath: '/custom-asset',\n idField: 'idCustomAsset',\n listFields: ['label', 'customAssetType', 'identifier', 'isMaterial', 'costPerUnit', 'active'],\n getPath: '/custom-asset/id/:id',\n },\n {\n name: 'custom-asset-types',\n singular: 'custom asset type',\n basePath: '/custom-asset/type',\n idField: 'idCustomAssetType',\n listFields: ['label', 'isMaterialConcept', 'panelsQuantity'],\n getPath: '/custom-asset/type/id/:id',\n },\n {\n name: 'charger-kits',\n singular: 'VE charger kit',\n basePath: '/charger/ve-charger-kits',\n idField: 'idVEChargerKit',\n listFields: ['identifier', 'charger', 'price', 'phaseNumber', 'active'],\n filterPath: '/charger/ve-charger-kits/filter',\n batchDeletePath: 'delete-batch-ve-charger-kits',\n putBodyOnly: true,\n },\n {\n name: 'heatpump-kits',\n singular: 'heat pump kit',\n basePath: '/heat-pump/heatpump-kits',\n idField: 'idHeatpumpKit',\n listFields: ['identifier', 'heatpump', 'price', 'phaseNumber', 'active'],\n filterPath: '/heat-pump/heatpump-kits/filter',\n batchDeletePath: 'delete-batch-heatpump-kits',\n putBodyOnly: true,\n },\n];\n\nexport function registerInventoryCommands(program: Command): void {\n const inventory = program.command('inventory').description('Manage inventory: panels, inverters, batteries, chargers, heatpumps, custom-assets, kits');\n\n // Register manufacturer commands (special - simpler CRUD)\n registerManufacturersCommands(inventory);\n\n // Register all standard CRUD resources\n for (const resource of RESOURCES) {\n inventory.addCommand(createResourceCommands(resource));\n }\n\n // Register custom fields (separate CRUD)\n registerCustomFieldsCommands(inventory);\n\n // Register kits (complex - has sub-resources)\n registerKitsCommands(inventory);\n}\n","import { Command, Option } from 'commander';\nimport { readFileSync, writeFileSync, existsSync } from 'fs';\nimport { v4 } from 'uuid';\nimport { createServiceClient, handleApiError, assertFound, assertStudyObjectId } from '../../client.js';\nimport { loadConfig, getActiveProfile } from '../../config.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\n// ─── Types ───\n\ninterface StepsProgress {\n clientDetails: boolean | undefined;\n consumption: boolean | undefined;\n surfacesSelector: boolean | undefined;\n production: boolean | undefined;\n results: boolean | undefined;\n economicBalance: boolean | undefined;\n}\n\ninterface SolarStudyProgress {\n stepsProgress: StepsProgress;\n stepsUpdates: Record<string, boolean | undefined>;\n editingSolarStudy: boolean;\n lastStateUpdateMomentMS: number;\n}\n\ninterface ByPeriodValues {\n p1?: number;\n p2?: number;\n p3?: number;\n p4?: number;\n p5?: number;\n p6?: number;\n [key: string]: number | undefined;\n}\n\ntype Study = Record<string, unknown>;\n\n// ─── Study defaults (replicates SolarStudy constructor) ───\n\nfunction createDefaultStudy(name?: string): Study {\n const now = new Date();\n const dateStr = now.toISOString().split('T')[0];\n return {\n id: v4(),\n surfaces: undefined,\n clientDetails: {\n identifier: undefined,\n sector: undefined,\n email: undefined,\n cups: undefined,\n phoneNumber: undefined,\n address: undefined,\n instalationLocation: undefined,\n region: undefined,\n subregion: undefined,\n addressCode: undefined,\n dniOrCif: undefined,\n includeTaxes: false,\n taxesPercentage: 0,\n },\n location: undefined,\n atrTariff: undefined,\n geographicalZone: undefined,\n energyPrices: { units: '€/kWh' },\n contractedPower: {},\n powerPrices: { units: '€/kW · dia' },\n results: undefined,\n consumptionIntroductionMode: 'periods',\n peakPowerIntroductionMode: 'solarKit',\n instalationPhaseNumber: 'single_phase',\n peakPowerOptimizationMethod: {\n maxNumberOfOverproductionMonths: 3,\n },\n useAlternativePrices: false,\n economicResults: {\n guaranteeProductionPercentage: 85,\n inflation: 3,\n instalationLifeTime: 25,\n commercialFeePercentage: 85,\n instalationFinancingPercentage: 0,\n taxesPercentage: 21,\n includeTaxes: false,\n margen: 0,\n },\n creationTimestamp: dateStr,\n solarStudyProgress: {\n stepsProgress: {\n clientDetails: undefined,\n consumption: undefined,\n economicBalance: undefined,\n production: undefined,\n results: undefined,\n surfacesSelector: undefined,\n },\n stepsUpdates: {\n clientDetails: false,\n consumption: false,\n economicBalance: false,\n production: false,\n results: false,\n surfacesSelector: false,\n },\n editingSolarStudy: false,\n lastStateUpdateMomentMS: now.getTime(),\n } as SolarStudyProgress,\n activeBatteries: false,\n batteriesConfiguration: {\n initialCapacityPercentage: 100,\n maxCapacityPercentage: 100,\n minCapacityPercentage: 0,\n },\n layout: 'v2',\n lastStateUpdateMomentMS: now.getTime(),\n name: name || `Estudio Solar ${dateStr}`,\n notes: undefined,\n market: 'es',\n };\n}\n\n// ─── Auto-validation engine (replicates frontend step conditions) ───\n\nfunction checkByPeriodCompletion(periodNumber: number, element: ByPeriodValues | undefined): boolean {\n if (!element) return false;\n let assigned = 0;\n for (let i = 1; i <= 6; i++) {\n const val = element['p' + i];\n if (val !== undefined && val !== null && !isNaN(val)) {\n assigned++;\n }\n }\n return assigned >= periodNumber;\n}\n\nfunction evaluateSteps(study: Study): { stepsProgress: StepsProgress; missing: Record<string, string> } {\n const missing: Record<string, string> = {};\n\n // --- clientDetails ---\n const atrTariff = study.atrTariff as { periods?: number } | undefined;\n const energyPrices = study.energyPrices as ByPeriodValues | undefined;\n const geographicalZone = study.geographicalZone as Record<string, unknown> | undefined;\n const market = study.market as string | undefined;\n const extraCostPrice = study.extraCostPrice as ByPeriodValues | undefined;\n\n let clientDetailsComplete = true;\n if (!atrTariff) {\n clientDetailsComplete = false;\n missing.clientDetails = 'Needs atrTariff (use: studies set tariff)';\n } else if (!checkByPeriodCompletion(atrTariff.periods || 3, energyPrices)) {\n clientDetailsComplete = false;\n missing.clientDetails = `Needs energyPrices with ${atrTariff.periods || 3} periods filled (use: studies set prices)`;\n } else if (!geographicalZone) {\n clientDetailsComplete = false;\n missing.clientDetails = 'Needs geographicalZone (use: studies set tariff --zone-id N)';\n } else if (market === 'pt' && !checkByPeriodCompletion(1, extraCostPrice)) {\n clientDetailsComplete = false;\n missing.clientDetails = 'PT market needs extraCostPrice with 1 period (use: studies set prices --extra-cost-p1 N)';\n }\n\n // --- consumption ---\n const consumption = study.consumption as { days?: unknown[] } | undefined;\n const consumptionComplete = !!consumption?.days?.length;\n if (!consumptionComplete) {\n missing.consumption = 'Needs consumption curve (use: studies set consumption)';\n }\n\n // --- surfacesSelector ---\n const surfaces = study.surfaces as unknown[] | undefined;\n const surfacesComplete = !!surfaces?.length;\n if (!surfacesComplete) {\n missing.surfacesSelector = 'Needs at least one surface (use: studies add surface)';\n }\n\n // --- production ---\n // Requires: at least one surface with production curve AND equipment (panel or kit) selected\n const solarPanel = study.solarPanel as Record<string, unknown> | undefined;\n const solarKit = study.solarKit as Record<string, unknown> | undefined;\n const hasEquipment = !!solarPanel || !!solarKit;\n let hasProductionCurve = false;\n if (surfaces && surfaces.length > 0) {\n for (const s of surfaces) {\n const surf = s as { production?: { days?: unknown[] } };\n if (surf.production?.days?.length) {\n hasProductionCurve = true;\n break;\n }\n }\n }\n const productionComplete = hasProductionCurve && hasEquipment;\n if (!productionComplete) {\n const reasons: string[] = [];\n if (!hasEquipment) reasons.push('no panel or kit selected (use: studies set panel or studies set kit)');\n if (!hasProductionCurve) reasons.push('no surface has a production curve (use: studies calculate production)');\n missing.production = reasons.join('; ');\n }\n\n // --- results ---\n const results = study.results as Record<string, unknown> | undefined;\n const resultsComplete = results !== undefined;\n if (!resultsComplete) {\n missing.results = 'Results not calculated (use: studies calculate results)';\n }\n\n // --- economicBalance ---\n const economicResults = study.economicResults as Record<string, unknown> | undefined;\n const economicBalanceComplete =\n economicResults?.margen !== undefined &&\n economicResults?.totalCost !== undefined &&\n results !== undefined;\n if (!economicBalanceComplete) {\n const reasons: string[] = [];\n if (economicResults?.margen === undefined) reasons.push('margen');\n if (economicResults?.totalCost === undefined) reasons.push('totalCost');\n if (!results) reasons.push('results');\n missing.economicBalance = `Needs: ${reasons.join(', ')} (use: studies set economics)`;\n }\n\n return {\n stepsProgress: {\n clientDetails: clientDetailsComplete,\n consumption: consumptionComplete,\n surfacesSelector: surfacesComplete,\n production: productionComplete,\n results: resultsComplete,\n economicBalance: economicBalanceComplete,\n },\n missing,\n };\n}\n\nfunction calculateCompletionPercentage(stepsProgress: StepsProgress): number {\n const completed = Object.values(stepsProgress).filter(Boolean).length;\n return Math.round((completed / 6) * 100);\n}\n\n// ─── Cascade resets ───\n\ntype StepName = keyof StepsProgress;\n\nconst CASCADE_RESETS: Record<string, StepName[]> = {\n consumption: ['production', 'results', 'economicBalance'],\n surfaces: ['production', 'results', 'economicBalance'],\n};\n\nfunction applyCascadeResets(study: Study, changedField: string): string[] {\n const resetSteps = CASCADE_RESETS[changedField];\n if (!resetSteps) return [];\n\n const progress = (study.solarStudyProgress as SolarStudyProgress);\n const resets: string[] = [];\n for (const step of resetSteps) {\n if (progress.stepsProgress[step] !== undefined) {\n progress.stepsProgress[step] = undefined;\n resets.push(step);\n }\n }\n\n // Also clear dependent data for full resets\n if (changedField === 'consumption') {\n // Don't clear surfaces production, only results\n study.results = undefined;\n }\n if (changedField === 'surfaces') {\n study.results = undefined;\n }\n\n return resets;\n}\n\n// ─── File I/O helpers ───\n\nfunction readStudy(filePath: string): Study {\n if (!existsSync(filePath)) {\n throw new Error(`Study file not found: ${filePath}. Use 'studies init --file ${filePath}' to create one.`);\n }\n return JSON.parse(readFileSync(filePath, 'utf-8'));\n}\n\nfunction writeStudy(filePath: string, study: Study): void {\n writeFileSync(filePath, JSON.stringify(study, null, 2), 'utf-8');\n}\n\n/** Read study, apply changes, re-validate, write back, return status */\nfunction updateStudy(\n filePath: string,\n updater: (study: Study) => string | undefined, // returns cascade field name or undefined\n): { stepsProgress: StepsProgress; completionPercentage: number; missing: Record<string, string>; cascadeResets: string[] } {\n const study = readStudy(filePath);\n const cascadeField = updater(study);\n\n // Apply cascade resets\n let cascadeResets: string[] = [];\n if (cascadeField) {\n cascadeResets = applyCascadeResets(study, cascadeField);\n }\n\n // Re-evaluate all steps\n const { stepsProgress, missing } = evaluateSteps(study);\n\n // Update solarStudyProgress\n const progress = study.solarStudyProgress as SolarStudyProgress;\n progress.stepsProgress = stepsProgress;\n progress.lastStateUpdateMomentMS = Date.now();\n study.lastStateUpdateMomentMS = Date.now();\n\n writeStudy(filePath, study);\n\n return {\n stepsProgress,\n completionPercentage: calculateCompletionPercentage(stepsProgress),\n missing,\n cascadeResets,\n };\n}\n\n/** Deep merge: target ← source (non-destructive, arrays replaced not merged) */\nfunction deepMerge(target: Record<string, unknown>, source: Record<string, unknown>): void {\n for (const key of Object.keys(source)) {\n const sv = source[key];\n const tv = target[key];\n if (sv && typeof sv === 'object' && !Array.isArray(sv) && tv && typeof tv === 'object' && !Array.isArray(tv)) {\n deepMerge(tv as Record<string, unknown>, sv as Record<string, unknown>);\n } else {\n target[key] = sv;\n }\n }\n}\n\n// ─── CLI helpers ───\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\nfunction resolveFile(opts: { file?: string }): string {\n return opts.file || process.env.SUNTROPY_STUDY || './study.json';\n}\n\ntype LatLng = { lat: number; lng: number };\n\n/**\n * Resolve the geographic coordinates used to calculate a surface, in order of\n * preference:\n * 1. surface.center — explicit surface centre (e.g. set by `add surface`)\n * 2. study.location — study-level location\n * 3. polygonPath centroid — average of the drawn polygon vertices\n * 4. polygonPath first point — fallback when the centroid is degenerate\n *\n * A surface drawn in the editor arrives with a full `polygonPath` but no\n * `center`, and studies from that flow may also lack `location`. Deriving the\n * coordinate from the polygon lets those surfaces be calculated instead of\n * failing with \"no coordinates\". Returns null only when no usable point exists.\n */\nexport function resolveSurfaceCoordinates(\n surface: Record<string, unknown>,\n study: Study,\n): LatLng | null {\n const isValid = (c: unknown): c is LatLng => {\n const p = c as LatLng | undefined;\n return !!p && Number.isFinite(p.lat) && Number.isFinite(p.lng);\n };\n\n const center = surface.center as LatLng | undefined;\n if (isValid(center)) return { lat: center.lat, lng: center.lng };\n\n const studyLocation = study.location as LatLng | undefined;\n if (isValid(studyLocation)) return { lat: studyLocation.lat, lng: studyLocation.lng };\n\n const path = surface.polygonPath as Array<{ lat?: number; lng?: number }> | undefined;\n if (Array.isArray(path) && path.length > 0) {\n const points = path.filter(\n (p): p is LatLng => Number.isFinite(p?.lat) && Number.isFinite(p?.lng),\n );\n if (points.length > 0) {\n // Centroid: average of the polygon vertices.\n const sum = points.reduce(\n (acc, p): LatLng => ({ lat: acc.lat + p.lat, lng: acc.lng + p.lng }),\n { lat: 0, lng: 0 },\n );\n const centroid = { lat: sum.lat / points.length, lng: sum.lng / points.length };\n if (isValid(centroid)) return centroid;\n // Fallback: first valid point of the path.\n return { lat: points[0].lat, lng: points[0].lng };\n }\n }\n\n return null;\n}\n\n/**\n * Installed DC power (Watts) sent to `/solar-study/calculateProduction` for a\n * surface, replicating the frontend `generateCalculateProductionDto`:\n *\n * installedPower = (panelsLayoutPolygons?.length ?? panelNumber) * panelPeakPower\n *\n * The panel peak power comes from `study.solarPanel.peakPower` — kit mode also\n * populates `solarPanel` from `solarKit.kitSolarPanel`, so both peak-power modes\n * resolve. An explicit `surface.installedPower` (e.g. from `add surface --power`)\n * takes precedence. The old code read only `surface.installedPower || 5000`, a\n * field the frontend never sets, so studies built in the UI were silently\n * calculated for the 5000 W (5 kWp) default.\n *\n * Returns `isDefault: true` when it had to fall back to 5000 W so the caller can\n * warn instead of emitting wrong production numbers silently.\n */\nexport function resolveSurfaceInstalledPower(\n surface: Record<string, unknown>,\n study: Study,\n): { installedPower: number; isDefault: boolean } {\n const explicit = surface.installedPower as number | undefined;\n if (Number.isFinite(explicit) && (explicit as number) > 0) {\n return { installedPower: explicit as number, isDefault: false };\n }\n\n const solarPanel = study.solarPanel as { peakPower?: number } | undefined;\n const kitPanel = (study.solarKit as { kitSolarPanel?: { peakPower?: number } } | undefined)?.kitSolarPanel;\n const panelPeakPower = (solarPanel?.peakPower as number) || (kitPanel?.peakPower as number) || undefined;\n\n // Frontend precedence: drawn panel layout length, else surface.panelNumber.\n const layout = surface.panelsLayoutPolygons as unknown[] | undefined;\n const panelCount = layout !== undefined\n ? (layout.length || 0)\n : (surface.panelNumber as number | undefined);\n\n if (panelPeakPower && Number.isFinite(panelCount) && (panelCount as number) > 0) {\n return { installedPower: (panelCount as number) * panelPeakPower, isDefault: false };\n }\n\n return { installedPower: 5000, isDefault: true };\n}\n\n// ─── Register commands ───\n\nexport function registerStudyBuilderCommands(studies: Command): void {\n\n // ═══════════════════════════════════════════\n // INIT\n // ═══════════════════════════════════════════\n studies\n .command('init')\n .description(\n 'Create a new study workspace (local JSON file with defaults).\\n' +\n 'Example: suntropy studies init --file /tmp/study.json --name \"Residencial 5kW\"'\n )\n .option('--file <path>', 'Output file path (default: ./study.json)')\n .option('--name <studyName>', 'Study name')\n .option('--market <code>', 'Market country: es, pt, it, fr, de, etc.', 'es')\n .action(async (opts) => {\n try {\n const filePath = resolveFile(opts);\n const study = createDefaultStudy(opts.name);\n if (opts.market) study.market = opts.market;\n writeStudy(filePath, study);\n const { stepsProgress, missing } = evaluateSteps(study);\n output({\n file: filePath,\n id: study.id,\n name: study.name,\n stepsProgress,\n completionPercentage: 0,\n missing,\n }, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // ═══════════════════════════════════════════\n // VALIDATE\n // ═══════════════════════════════════════════\n studies\n .command('validate')\n .description(\n 'Check completion status of all study steps.\\n' +\n 'Returns stepsProgress, completionPercentage, and what is missing for each incomplete step.'\n )\n .option('--file <path>', 'Study file path')\n .action(async (opts) => {\n try {\n const study = readStudy(resolveFile(opts));\n const { stepsProgress, missing } = evaluateSteps(study);\n output({\n name: study.name,\n stepsProgress,\n completionPercentage: calculateCompletionPercentage(stepsProgress),\n missing,\n }, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // ═══════════════════════════════════════════\n // SAVE\n // ═══════════════════════════════════════════\n studies\n .command('save')\n .description(\n 'Save study to the backend (POST /solar-study).\\n' +\n 'If the study has _id, it updates the existing study. Otherwise creates new.\\n' +\n 'Example: suntropy studies save --file /tmp/study.json --state-id 1'\n )\n .option('--file <path>', 'Study file path')\n .option('--state-id <n>', 'Solar study metadata state ID')\n .option('--credit-amount <n>', 'Credit amount to consume')\n .option('--save-as-new', 'Force save as new study (even if _id exists)')\n .action(async (opts) => {\n try {\n const filePath = resolveFile(opts);\n const global = getGlobalOpts(studies);\n const study = readStudy(filePath);\n\n // Re-validate before saving\n const { stepsProgress } = evaluateSteps(study);\n const progress = study.solarStudyProgress as SolarStudyProgress;\n progress.stepsProgress = stepsProgress;\n progress.lastStateUpdateMomentMS = Date.now();\n\n // Auto-add comment like frontend SaveStudyModal\n const isEditing = progress.editingSolarStudy || !!study._id;\n const comments = (study.comments || []) as Record<string, unknown>[];\n const commentType = opts.saveAsNew ? 'duplicated' : (isEditing ? 'modified' : 'created');\n comments.push(createComment(commentType));\n study.comments = comments;\n\n if (opts.saveAsNew) {\n delete study._id;\n }\n\n const client = createServiceClient('solar', global);\n const params: Record<string, string> = {};\n if (opts.stateId) params.idSolarStudyState = opts.stateId;\n if (opts.creditAmount) params.creditAmount = opts.creditAmount;\n if (opts.saveAsNew) params.saveAsNew = 'true';\n\n const queryString = Object.entries(params)\n .map(([k, v]) => `${k}=${encodeURIComponent(v)}`)\n .join('&');\n const url = `/solar-study${queryString ? '?' + queryString : ''}`;\n\n const res = await client.post(url, study);\n\n // If response contains _id or solarStudyId, update local file\n const responseData = res.data as Record<string, unknown>;\n if (responseData?.solarStudyId) {\n study._id = responseData.solarStudyId as string;\n progress.editingSolarStudy = true;\n writeStudy(filePath, study);\n }\n\n output({\n saved: true,\n metadata: responseData,\n file: filePath,\n completionPercentage: calculateCompletionPercentage(stepsProgress),\n }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // ═══════════════════════════════════════════\n // PULL\n // ═══════════════════════════════════════════\n studies\n .command('pull <studyId>')\n .description(\n 'Download an existing study from the backend into a local file.\\n' +\n 'Example: suntropy studies pull abc123 --file /tmp/study.json'\n )\n .option('--file <path>', 'Output file path')\n .action(async (studyId, opts) => {\n try {\n assertStudyObjectId(studyId);\n const filePath = resolveFile(opts);\n const global = getGlobalOpts(studies);\n const client = createServiceClient('solar', global);\n const res = await client.get(`/solar-study/findById/${studyId}`);\n const study = assertFound(res.data, 'Solar study', studyId) as Study;\n\n // Re-validate\n const { stepsProgress, missing } = evaluateSteps(study);\n const progress = (study.solarStudyProgress || {}) as SolarStudyProgress;\n progress.stepsProgress = stepsProgress;\n progress.editingSolarStudy = true;\n study.solarStudyProgress = progress;\n\n writeStudy(filePath, study);\n output({\n file: filePath,\n _id: study._id,\n name: study.name,\n stepsProgress,\n completionPercentage: calculateCompletionPercentage(stepsProgress),\n missing,\n }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // ═══════════════════════════════════════════\n // SET — parent command for all sub-commands\n // ═══════════════════════════════════════════\n const set = studies.command('set').description('Set study properties. Each sub-command auto-validates after changes.');\n\n // --- set name ---\n set\n .command('name')\n .description('Set the study name')\n .option('--file <path>', 'Study file path')\n .requiredOption('--name <studyName>', 'Study name')\n .action(async (opts) => {\n try {\n const result = updateStudy(resolveFile(opts), (study) => {\n study.name = opts.name;\n return undefined;\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- set market ---\n set\n .command('market')\n .description('Set the market country code (es, pt, it, fr, de, etc.)')\n .option('--file <path>', 'Study file path')\n .requiredOption('--market <code>', 'Market country code')\n .action(async (opts) => {\n try {\n const result = updateStudy(resolveFile(opts), (study) => {\n study.market = opts.market;\n return undefined;\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- set client ---\n set\n .command('client')\n .description(\n 'Set client details (name, email, phone, cups, address, etc.)\\n' +\n 'Example: suntropy studies set client --file study.json --name \"Juan García\" --email j@co.com --cups ES001234'\n )\n .option('--file <path>', 'Study file path')\n .option('--name <clientName>', 'Client name (identifier/razón social)')\n .option('--email <email>', 'Client email')\n .option('--phone <phone>', 'Phone number')\n .option('--cups <cups>', 'CUPS code')\n .option('--address <addr>', 'Address')\n .option('--city <city>', 'City')\n .option('--region <region>', 'Region (comunidad autónoma)')\n .option('--subregion <subregion>', 'Subregion (provincia)')\n .option('--dni <dni>', 'DNI or CIF')\n .option('--sector <sector>', 'Client sector')\n .option('--installation-location <loc>', 'Installation location description')\n .action(async (opts) => {\n try {\n const result = updateStudy(resolveFile(opts), (study) => {\n const cd = (study.clientDetails || {}) as Record<string, unknown>;\n if (opts.name) cd.identifier = opts.name;\n if (opts.email) cd.email = opts.email;\n if (opts.phone) cd.phoneNumber = opts.phone;\n if (opts.cups) cd.cups = opts.cups;\n if (opts.address) cd.address = opts.address;\n if (opts.city) cd.city = opts.city;\n if (opts.region) cd.region = opts.region;\n if (opts.subregion) cd.subregion = opts.subregion;\n if (opts.dni) cd.dniOrCif = opts.dni;\n if (opts.sector) cd.sector = opts.sector;\n if (opts.installationLocation) cd.instalationLocation = opts.installationLocation;\n study.clientDetails = cd;\n return undefined;\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- set tariff ---\n set\n .command('tariff')\n .description(\n 'Set ATR tariff and geographical zone. Auto-sets phase (>3 periods → three_phase).\\n' +\n 'Common tariff IDs (Spain): 13=2.0TD (3 periods), 14=3.0TD (6 periods)\\n' +\n 'Zone IDs (Spain): 1=Peninsula, 2=Canarias, 3=Baleares\\n' +\n 'Example: suntropy studies set tariff --file study.json --tariff-id 13 --zone-id 1'\n )\n .option('--file <path>', 'Study file path')\n .requiredOption('--tariff-id <n>', 'ATR tariff ID')\n .option('--zone-id <n>', 'Geographical zone ID', '1')\n .option('--market <code>', 'Market code for tariff lookup', 'es')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const client = createServiceClient('periods', global);\n\n // Fetch tariff info\n const tariffRes = await client.get('/tarifas-atr', {\n params: { market: opts.market },\n });\n const tariffs = (Array.isArray(tariffRes.data) ? tariffRes.data : tariffRes.data?.data || []) as Record<string, unknown>[];\n const tariffId = parseInt(opts.tariffId);\n const tariff = tariffs.find((t) => t.idTarifaATR === tariffId);\n if (!tariff) {\n outputError(new Error(`Tariff ID ${tariffId} not found. Available: ${tariffs.map((t) => `${t.idTarifaATR}=${t.nombre}`).join(', ')}`));\n return;\n }\n\n // Fetch zone info\n const zoneRes = await client.get('/zonas', {\n params: { market: opts.market },\n });\n const zones = (Array.isArray(zoneRes.data) ? zoneRes.data : zoneRes.data?.data || []) as Record<string, unknown>[];\n const zoneId = parseInt(opts.zoneId);\n const zone = zones.find((z) => z.idZona === zoneId);\n\n const result = updateStudy(resolveFile(opts), (study) => {\n study.atrTariff = tariff;\n if (zone) study.geographicalZone = zone;\n\n // Auto-set phase based on tariff periods (replicates frontend logic)\n const periods = (tariff.periods as number) || 3;\n study.instalationPhaseNumber = periods > 3 ? 'three_phase' : 'single_phase';\n\n return undefined; // no cascade reset for tariff change\n });\n\n output(result, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- set prices ---\n set\n .command('prices')\n .description(\n 'Set energy prices by period.\\n' +\n 'Examples:\\n' +\n ' suntropy studies set prices --file study.json --energy \\'{\"p1\":0.15,\"p2\":0.08,\"p3\":0.06}\\'\\n' +\n ' suntropy studies set prices --file study.json --energy-p1 0.15 --energy-p2 0.08 --energy-p3 0.06\\n' +\n ' suntropy studies set prices --file study.json --energy \\'{\"p1\":0.15,...}\\' --power \\'{\"p1\":40,...}\\' --contracted \\'{\"p1\":5.5,...}\\''\n )\n .option('--file <path>', 'Study file path')\n .option('--energy <json>', 'Energy prices JSON: {\"p1\":N,\"p2\":N,...}')\n .option('--energy-p1 <n>', 'Energy price period 1 (€/kWh)')\n .option('--energy-p2 <n>', 'Energy price period 2 (€/kWh)')\n .option('--energy-p3 <n>', 'Energy price period 3 (€/kWh)')\n .option('--energy-p4 <n>', 'Energy price period 4 (€/kWh)')\n .option('--energy-p5 <n>', 'Energy price period 5 (€/kWh)')\n .option('--energy-p6 <n>', 'Energy price period 6 (€/kWh)')\n .option('--power <json>', 'Power prices JSON: {\"p1\":N,\"p2\":N,...} (€/kW·day)')\n .option('--contracted <json>', 'Contracted power JSON: {\"p1\":N,\"p2\":N,...} (kW)')\n .option('--extra-cost-p1 <n>', 'Extra cost price P1 (Portugal market)')\n .action(async (opts) => {\n try {\n const result = updateStudy(resolveFile(opts), (study) => {\n // Energy prices: from JSON or individual flags\n const ep = (study.energyPrices || { units: '€/kWh' }) as Record<string, unknown>;\n if (opts.energy) {\n const parsed = JSON.parse(opts.energy);\n Object.assign(ep, parsed);\n }\n for (let i = 1; i <= 6; i++) {\n const val = opts[`energyP${i}`];\n if (val !== undefined) ep[`p${i}`] = parseFloat(val);\n }\n study.energyPrices = ep;\n\n // Power prices\n if (opts.power) {\n const pp = (study.powerPrices || { units: '€/kW · dia' }) as Record<string, unknown>;\n Object.assign(pp, JSON.parse(opts.power));\n study.powerPrices = pp;\n }\n\n // Contracted power\n if (opts.contracted) {\n const cp = (study.contractedPower || {}) as Record<string, unknown>;\n Object.assign(cp, JSON.parse(opts.contracted));\n study.contractedPower = cp;\n }\n\n // Extra cost (Portugal)\n if (opts.extraCostP1 !== undefined) {\n study.extraCostPrice = { p1: parseFloat(opts.extraCostP1), units: '€/kWh' };\n }\n\n return undefined; // no cascade\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- set consumption ---\n set\n .command('consumption')\n .description(\n 'Set the consumption curve.\\n' +\n 'Modes:\\n' +\n ' --from-file <path> Load PowerCurve from JSON file\\n' +\n ' --annual + --pattern Generate via consumption-estimation API\\n' +\n ' --by-period <json> Period consumption: {\"p1\":N,\"p2\":N,\"p3\":N} + REE profile\\n' +\n ' --monthly <json> Monthly consumption: {\"1\":N,\"2\":N,...,\"12\":N} + REE profile\\n' +\n ' --monthly-by-period Monthly by period: {\"1\":{\"p1\":N,\"p2\":N},...} + REE profile\\n\\n' +\n 'Examples:\\n' +\n ' suntropy studies set consumption --file study.json --from-file /tmp/cons.json\\n' +\n ' suntropy studies set consumption --file study.json --annual 4000 --pattern Balance\\n' +\n ' suntropy studies set consumption --file study.json --by-period \\'{\"p1\":2500,\"p2\":1000,\"p3\":500}\\'\\n' +\n ' suntropy studies set consumption --file study.json --monthly \\'{\"1\":350,\"2\":320,...}\\''\n )\n .option('--file <path>', 'Study file path')\n .option('--from-file <curvePath>', 'Load PowerCurve from JSON file')\n .option('--annual <kWh>', 'Annual consumption in kWh')\n .option('--pattern <name>', 'Pattern: Balance, Nightly, Morning, Afternoon, Domestic, Commercial')\n .option('--by-period <json>', 'Period consumption JSON: {\"p1\":N,\"p2\":N,...}')\n .option('--monthly <json>', 'Monthly consumption JSON: {\"1\":N,...,\"12\":N}')\n .option('--monthly-by-period <json>', 'Monthly by period: {\"1\":{\"p1\":N,...},...}')\n .option('--tariff <code>', 'Tariff code for profile lookup (default: from study)')\n .option('--market <code>', 'Market code (default: from study)')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const filePath = resolveFile(opts);\n const study = readStudy(filePath);\n const studyTariff = (study.atrTariff as Record<string, unknown>)?.nombre as string || '3.0TD';\n const studyMarket = (study.market as string) || 'es';\n const tariff = opts.tariff || studyTariff;\n const market = opts.market || studyMarket;\n const year = new Date().getFullYear();\n\n let curveData: unknown;\n let introductionMode: string;\n\n if (opts.fromFile) {\n // Load from file\n curveData = JSON.parse(readFileSync(opts.fromFile, 'utf-8'));\n introductionMode = 'upload';\n\n } else if (opts.annual && opts.pattern) {\n // Generate via backend /consumption-estimation\n const profilesClient = createServiceClient('profiles', global);\n const params: Record<string, string> = {\n startDate: `${year}-01-01`,\n endDate: `${year}-12-31`,\n tariff,\n type: 'Final',\n anualConsumption: opts.annual,\n market,\n consumptionType: opts.pattern,\n };\n const queryString = Object.entries(params)\n .map(([k, v]) => `${k}=${encodeURIComponent(v)}`)\n .join('&');\n const res = await profilesClient.post(`/consumption-estimation?${queryString}`, {});\n curveData = res.data;\n introductionMode = 'consumption_patterns';\n\n } else if (opts.byPeriod) {\n // Fetch REE profile + period distribution, apply locally\n const periodValues = JSON.parse(opts.byPeriod);\n curveData = await generateFromProfile(global, tariff, market, year, 'CONSUMPTION_BY_PERIOD', periodValues);\n introductionMode = 'periods';\n\n } else if (opts.monthly) {\n // Fetch REE profile, apply monthly consumption\n const monthValues = JSON.parse(opts.monthly);\n curveData = await generateFromProfile(global, tariff, market, year, 'MONTH_CONSUMPTION', monthValues);\n introductionMode = 'monthly_consumption';\n\n } else if (opts.monthlyByPeriod) {\n // Complex: monthly by period\n const monthPeriodValues = JSON.parse(opts.monthlyByPeriod);\n curveData = await generateFromProfile(global, tariff, market, year, 'MONTHLY_BY_PERIOD', monthPeriodValues);\n introductionMode = 'monthly_periods';\n\n } else {\n outputError(new Error('Specify one of: --from-file, --annual + --pattern, --by-period, --monthly, --monthly-by-period'));\n return;\n }\n\n // Update study with consumption\n const result = updateStudy(filePath, (s) => {\n s.consumption = curveData;\n s.consumptionIntroductionMode = introductionMode;\n if (opts.annual) s.monthlyConsumption = parseFloat(opts.annual) / 12;\n if (opts.pattern) s.selectedConsumptionPattern = opts.pattern;\n if (opts.byPeriod) s.periodConsumptionDictionary = JSON.parse(opts.byPeriod);\n if (opts.monthly) s.monthConsumptionDictionary = JSON.parse(opts.monthly);\n if (opts.monthlyByPeriod) s.monthPeriodConsumptionDictionary = JSON.parse(opts.monthlyByPeriod);\n return 'consumption'; // trigger cascade\n });\n\n output(result, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- add surface ---\n studies\n .command('add')\n .description('Add elements to the study')\n .command('surface')\n .description(\n 'Add a solar surface to the study.\\n' +\n 'Example: suntropy studies add surface --file study.json --lat 37.39 --lon -5.99 --angle 30 --azimuth 180 --power 5000'\n )\n .option('--file <path>', 'Study file path')\n .requiredOption('--lat <n>', 'Latitude')\n .requiredOption('--lon <n>', 'Longitude')\n .option('--angle <n>', 'Panel inclination degrees', '30')\n .option('--azimuth <n>', 'Panel azimuth degrees (0=N, 180=S)', '180')\n .option('--power <w>', 'Installed power in Watts')\n .option('--panels-count <n>', 'Number of panels')\n .option('--production <file>', 'Production PowerCurve JSON file to attach')\n .option('--identifier <name>', 'Surface name/identifier')\n .action(async (opts) => {\n try {\n const result = updateStudy(resolveFile(opts), (study) => {\n const lat = parseFloat(opts.lat);\n const lng = parseFloat(opts.lon);\n const surface: Record<string, unknown> = {\n surfaceId: v4(),\n name: opts.identifier || `Surface ${((study.surfaces as unknown[])?.length || 0) + 1}`,\n inclination: parseFloat(opts.angle),\n orientation: parseFloat(opts.azimuth),\n panelInclination: parseFloat(opts.angle),\n panelOrientation: parseFloat(opts.azimuth),\n lossesPercentage: 14,\n // polygonPath required by backend metadata constructor\n polygonPath: [{ lat, lng }],\n };\n if (opts.power) surface.installedPower = parseFloat(opts.power);\n if (opts.panelsCount) surface.panelNumber = parseInt(opts.panelsCount);\n if (opts.production) {\n surface.production = JSON.parse(readFileSync(opts.production, 'utf-8'));\n }\n\n // Also set study-level location\n study.location = { lat: parseFloat(opts.lat), lng: parseFloat(opts.lon) };\n study.mapCenter = { lat: parseFloat(opts.lat), lng: parseFloat(opts.lon) };\n\n const surfaces = (study.surfaces as unknown[]) || [];\n surfaces.push(surface);\n study.surfaces = surfaces;\n\n return 'surfaces'; // cascade\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- remove surface ---\n studies\n .command('remove')\n .description('Remove elements from the study')\n .command('surface')\n .description('Remove a surface by index')\n .option('--file <path>', 'Study file path')\n .requiredOption('--index <n>', 'Surface index (0-based)')\n .action(async (opts) => {\n try {\n const result = updateStudy(resolveFile(opts), (study) => {\n const surfaces = (study.surfaces as unknown[]) || [];\n const idx = parseInt(opts.index);\n if (idx < 0 || idx >= surfaces.length) {\n throw new Error(`Surface index ${idx} out of range (0-${surfaces.length - 1})`);\n }\n surfaces.splice(idx, 1);\n study.surfaces = surfaces.length > 0 ? surfaces : undefined;\n return 'surfaces'; // cascade\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- set panel ---\n set\n .command('panel')\n .description(\n 'Set solar panel for the study. Auto-sets peakPowerIntroductionMode to \"solarPanel\".\\n' +\n 'Fetches full panel data from inventory.\\n' +\n 'Example: suntropy studies set panel --file study.json --panel-id 456 --panels-count 12'\n )\n .option('--file <path>', 'Study file path')\n .requiredOption('--panel-id <n>', 'Solar panel ID from inventory')\n .option('--panels-count <n>', 'Number of panels')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const solarClient = createServiceClient('solar', global);\n\n // Fetch full panel data\n const panelRes = await solarClient.get(`/solar-panels/${opts.panelId}`);\n const panel = panelRes.data;\n\n const result = updateStudy(resolveFile(opts), (study) => {\n study.solarPanel = panel;\n study.peakPowerIntroductionMode = 'solarPanel';\n // Clear kit when switching to panel mode\n study.solarKit = undefined;\n if (opts.panelsCount) {\n // Set panels count on first surface if exists\n const surfaces = study.surfaces as Record<string, unknown>[] | undefined;\n if (surfaces?.length) {\n surfaces[0].panelNumber = parseInt(opts.panelsCount);\n }\n }\n return undefined;\n });\n output(result, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- set kit ---\n set\n .command('kit')\n .description(\n 'Set solar kit for the study. Auto-sets peakPowerIntroductionMode to \"solarKit\".\\n' +\n 'Fetches full kit data from inventory.\\n' +\n 'Example: suntropy studies set kit --file study.json --kit-id 123'\n )\n .option('--file <path>', 'Study file path')\n .requiredOption('--kit-id <n>', 'Solar kit ID from inventory')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const solarClient = createServiceClient('solar', global);\n\n // Kits use getViaFilter (no GET /:id)\n const kitsRes = await solarClient.get('/solar-kits', { params: { unactive: true } });\n const allKits = Array.isArray(kitsRes.data) && Array.isArray(kitsRes.data[0])\n ? kitsRes.data[0]\n : (Array.isArray(kitsRes.data) ? kitsRes.data : kitsRes.data?.data || []);\n const kitId = parseInt(opts.kitId);\n const kit = allKits.find((k: Record<string, unknown>) => k.idSolarKit === kitId);\n if (!kit) {\n outputError(new Error(`Kit ${kitId} not found`));\n return;\n }\n\n const result = updateStudy(resolveFile(opts), (study) => {\n study.solarKit = kit;\n study.peakPowerIntroductionMode = 'solarKit';\n // Clear panel + inverters when switching to kit mode\n study.solarPanel = undefined;\n study.solarInverters = undefined;\n return undefined;\n });\n output(result, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- set inverter ---\n set\n .command('inverter')\n .description(\n 'Set inverter(s) for the study (when using solarPanel mode).\\n' +\n 'Example: suntropy studies set inverter --file study.json --inverter-id 789'\n )\n .option('--file <path>', 'Study file path')\n .requiredOption('--inverter-id <ids>', 'Inverter ID(s), comma-separated for multiple')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const solarClient = createServiceClient('solar', global);\n const ids = opts.inverterId.split(',').map((s: string) => parseInt(s.trim()));\n\n const inverters: unknown[] = [];\n for (const id of ids) {\n const res = await solarClient.get(`/solar-inverter/${id}`);\n inverters.push(res.data);\n }\n\n const result = updateStudy(resolveFile(opts), (study) => {\n study.solarInverters = inverters;\n return undefined;\n });\n output(result, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- set phase ---\n set\n .command('phase')\n .description('Manually set installation phase (overrides auto-set from tariff)')\n .option('--file <path>', 'Study file path')\n .requiredOption('--phase <type>', 'Phase: single_phase or three_phase')\n .action(async (opts) => {\n try {\n if (!['single_phase', 'three_phase'].includes(opts.phase)) {\n outputError(new Error('Phase must be single_phase or three_phase'));\n return;\n }\n const result = updateStudy(resolveFile(opts), (study) => {\n study.instalationPhaseNumber = opts.phase;\n return undefined;\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- set economics ---\n set\n .command('economics')\n .description(\n 'Set economic parameters for the study.\\n' +\n 'Example: suntropy studies set economics --file study.json --margin 15 --total-cost 6500 --lifetime 25'\n )\n .option('--file <path>', 'Study file path')\n .option('--margin <n>', 'Margin percentage')\n .option('--total-cost <n>', 'Total installation cost (€)')\n .option('--lifetime <n>', 'Installation lifetime in years')\n .option('--inflation <n>', 'Inflation rate percentage')\n .option('--taxes-pct <n>', 'Tax percentage')\n .option('--include-taxes', 'Include taxes in pricing')\n .option('--commercial-fee <n>', 'Commercial fee percentage')\n .option('--excesses-mode <mode>', 'Excesses compensation: gridSelling, PPA, noInjection, virtualBattery')\n .option('--excesses-buy-price <n>', 'Excesses buy price (€/MWh)')\n .option('--excesses-selling-price <n>', 'Excesses selling price (€/MWh)')\n .option('--peak-power-cost <n>', 'Cost per Wp (€/Wp). If --total-cost is omitted, totalCost is derived as cost × installed peak power (W)')\n .option('--guarantee-production <n>', 'Guarantee production percentage')\n .action(async (opts) => {\n try {\n const result = updateStudy(resolveFile(opts), (study) => {\n const er = (study.economicResults || {}) as Record<string, unknown>;\n if (opts.margin !== undefined) er.margen = parseFloat(opts.margin);\n if (opts.totalCost !== undefined) er.totalCost = parseFloat(opts.totalCost);\n if (opts.lifetime !== undefined) er.instalationLifeTime = parseInt(opts.lifetime);\n if (opts.inflation !== undefined) er.inflation = parseFloat(opts.inflation);\n if (opts.taxesPct !== undefined) er.taxesPercentage = parseFloat(opts.taxesPct);\n if (opts.includeTaxes) er.includeTaxes = true;\n if (opts.commercialFee !== undefined) er.commercialFeePercentage = parseFloat(opts.commercialFee);\n if (opts.excessesMode) er.excessesCompensationMode = opts.excessesMode;\n if (opts.excessesBuyPrice !== undefined) er.excessesBuyPrice = parseFloat(opts.excessesBuyPrice);\n if (opts.excessesSellingPrice !== undefined) er.excessesSellingPrice = parseFloat(opts.excessesSellingPrice);\n if (opts.peakPowerCost !== undefined) er.peakPowerCost = parseFloat(opts.peakPowerCost);\n if (opts.guaranteeProduction !== undefined) er.guaranteeProductionPercentage = parseFloat(opts.guaranteeProduction);\n\n // Auto-derive totalCost from the per-Wp cost when --peak-power-cost is set\n // but --total-cost is not. The economic balance uses economicResults.totalCost\n // as the source of truth; the frontend only derives the €/Wp figure from it\n // (totalCost / installedPeakPowerWp). We invert that here so setting the €/Wp\n // cost alone yields a correct total instead of leaving totalCost untouched\n // (which previously kept the balance at 0). Installed peak power is the sum of\n // the surfaces' resolved installedPower (W); peakPowerCost is €/Wp, so\n // totalCost = cost × watts. If no surface has a resolvable power we warn\n // (non-fatal) instead of writing a wrong total.\n if (opts.peakPowerCost !== undefined && opts.totalCost === undefined) {\n const surfaces = (study.surfaces as Record<string, unknown>[] | undefined) || [];\n let totalWatts = 0;\n let resolvedCount = 0;\n let anyDefault = false;\n for (const surface of surfaces) {\n const { installedPower, isDefault } = resolveSurfaceInstalledPower(surface, study);\n if (isDefault) {\n anyDefault = true;\n continue;\n }\n totalWatts += installedPower;\n resolvedCount += 1;\n }\n if (resolvedCount > 0 && !anyDefault) {\n er.totalCost = Math.round(parseFloat(opts.peakPowerCost) * totalWatts * 100) / 100;\n } else {\n process.stderr.write(\n JSON.stringify({\n warning:\n 'Set --peak-power-cost but could not derive totalCost: ' +\n (surfaces.length === 0\n ? 'the study has no surfaces.'\n : 'some surfaces have no resolvable installed power (set panels + kit/panel first).') +\n ' Pass --total-cost explicitly to set it.',\n }) + '\\n',\n );\n }\n }\n\n study.economicResults = er;\n return undefined;\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- set custom-assets ---\n set\n .command('custom-assets')\n .description(\n 'Set selected custom assets for the study.\\n' +\n 'Example: suntropy studies set custom-assets --file study.json --asset 100:12 --asset 200:1'\n )\n .option('--file <path>', 'Study file path')\n .requiredOption('--asset <id:qty>', 'Custom asset as id:quantity (repeatable)', collectAssets, [])\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const solarClient = createServiceClient('solar', global);\n\n // Fetch full custom asset data for each\n const assets: unknown[] = [];\n for (const { id, quantity } of opts.asset) {\n const res = await solarClient.get(`/custom-asset/id/${id}`);\n assets.push({ customAsset: res.data, quantity });\n }\n\n const result = updateStudy(resolveFile(opts), (study) => {\n study.selectedCustomAssets = assets;\n return undefined;\n });\n output(result, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- set batteries ---\n set\n .command('batteries')\n .description(\n 'Enable/disable batteries and set configuration.\\n' +\n 'Example: suntropy studies set batteries --file study.json --enable --battery-id 789 --count 1'\n )\n .option('--file <path>', 'Study file path')\n .option('--enable', 'Enable batteries')\n .option('--disable', 'Disable batteries')\n .option('--battery-id <n>', 'Battery ID from inventory')\n .option('--count <n>', 'Number of batteries')\n .action(async (opts) => {\n try {\n const result = updateStudy(resolveFile(opts), (study) => {\n if (opts.enable) study.activeBatteries = true;\n if (opts.disable) study.activeBatteries = false;\n if (opts.batteryId) {\n // Store battery reference — the full battery object would be fetched when calculating\n const config = (study.batteriesConfiguration || {}) as Record<string, unknown>;\n config.batteryId = parseInt(opts.batteryId);\n if (opts.count) config.batteriesNumber = parseInt(opts.count);\n study.batteriesConfiguration = config;\n }\n return undefined;\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- set data (generic fallback) ---\n set\n .command('data')\n .description(\n 'Generic JSON merge into the study (fallback for any field).\\n' +\n 'Example: suntropy studies set data --file study.json --data \\'{\"referenceId\":\"REF-001\"}\\''\n )\n .option('--file <path>', 'Study file path')\n .requiredOption('--data <json>', 'JSON to merge into the study')\n .action(async (opts) => {\n try {\n const parsed = JSON.parse(opts.data);\n // Detect cascade fields\n const cascadeFields = Object.keys(parsed);\n let cascadeField: string | undefined;\n if (cascadeFields.includes('consumption')) cascadeField = 'consumption';\n if (cascadeFields.includes('surfaces')) cascadeField = 'surfaces';\n\n const result = updateStudy(resolveFile(opts), (study) => {\n deepMerge(study, parsed);\n return cascadeField;\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // ═══════════════════════════════════════════\n // CALCULATE — commands that call backend APIs\n // ═══════════════════════════════════════════\n\n // --- calculate production ---\n studies\n .command('calculate')\n .description('Calculate derived data for the study')\n .command('production')\n .description(\n 'Calculate production for study surfaces using backend API.\\n' +\n 'Example: suntropy studies calculate production --file study.json [--surface-index 0 | --all-surfaces]'\n )\n .option('--file <path>', 'Study file path')\n .option('--surface-index <n>', 'Calculate for specific surface index')\n .option('--all-surfaces', 'Calculate for all surfaces')\n .option('--losses <n>', 'Losses percentage', '14')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const filePath = resolveFile(opts);\n const study = readStudy(filePath);\n const surfaces = study.surfaces as Record<string, unknown>[] | undefined;\n\n if (!surfaces?.length) {\n outputError(new Error('No surfaces in study. Use: studies add surface'));\n return;\n }\n\n const solarClient = createServiceClient('solar', global);\n const indicesToCalc = opts.surfaceIndex !== undefined\n ? [parseInt(opts.surfaceIndex)]\n : Array.from({ length: surfaces.length }, (_, i) => i);\n\n for (const idx of indicesToCalc) {\n const surface = surfaces[idx];\n if (!surface) continue;\n // Coordinates: surface center → study location → drawn polygon (centroid, else first point)\n const coords = resolveSurfaceCoordinates(surface, study);\n if (!coords) {\n outputError(new Error(`Surface ${idx} has no coordinates. Use: studies add surface --lat N --lon N`));\n continue;\n }\n const { lat, lng } = coords;\n // Installed power: explicit → (panel layout | panelNumber) × panel peak power (frontend parity)\n const { installedPower, isDefault } = resolveSurfaceInstalledPower(surface, study);\n if (isDefault) {\n outputError(new Error(\n `Surface ${idx} has no resolvable installed power (no installedPower, and no panel layout / panelNumber with a solarPanel/solarKit peak power). `\n + `Using the 5000W default — production will be wrong. Set the panels and kit/panel before calculating.`,\n ));\n }\n const body = {\n lat,\n long: lng,\n instaledPower: installedPower,\n angle: (surface.inclination as number) || (surface.angle as number) || 30,\n azimuth: (surface.orientation as number) || (surface.azimuth as number) || 180,\n lossesPercentage: parseFloat(opts.losses),\n year: new Date().getFullYear(),\n isOptimized: false,\n };\n const res = await solarClient.post('/solar-study/calculateProduction', body);\n surface.production = res.data;\n }\n\n // Write back and validate\n const result = updateStudy(filePath, (s) => {\n s.surfaces = surfaces;\n return undefined; // don't cascade — we're setting production, not changing surfaces\n });\n output(result, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- calculate results ---\n studies\n .command('calculate-results')\n .description(\n 'Calculate energy results replicating frontend SolarResultCalculator.\\n' +\n 'Computes: net consumption, excesses, spending/savings by period, coverage.\\n' +\n 'Requires: consumption, production, energyPrices, atrTariff.\\n' +\n 'Example: suntropy studies calculate-results --file study.json'\n )\n .option('--file <path>', 'Study file path')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const filePath = resolveFile(opts);\n const study = readStudy(filePath);\n\n const consumption = study.consumption as { days?: unknown[]; identifier?: string } | undefined;\n if (!consumption?.days?.length) {\n outputError(new Error('No consumption curve. Use: studies set consumption'));\n return;\n }\n\n const surfaces = study.surfaces as Record<string, unknown>[] | undefined;\n if (!surfaces?.length) {\n outputError(new Error('No surfaces. Use: studies add surface'));\n return;\n }\n\n const energyPrices = study.energyPrices as ByPeriodValues | undefined;\n if (!energyPrices) {\n outputError(new Error('No energy prices. Use: studies set prices'));\n return;\n }\n\n const { PowerCurve } = await import('energy-types/lib/energy/classes/powerCurve.class.js');\n\n // Build consumption PowerCurve\n const consCurve = new PowerCurve(consumption.days, false, consumption.identifier || 'consumption', false);\n\n // Aggregate production from all surfaces (replicates SolarResultCalculator.aggregateProductionResults)\n let totalProdCurve: InstanceType<typeof PowerCurve> | null = null;\n for (const surf of surfaces) {\n const prod = surf.production as { days?: unknown[]; identifier?: string } | undefined;\n if (prod?.days?.length) {\n const surfProd = new PowerCurve(prod.days, false, prod.identifier || 'production', false);\n totalProdCurve = totalProdCurve ? totalProdCurve.aggregatePowerCurve(surfProd) : surfProd;\n }\n }\n\n if (!totalProdCurve) {\n outputError(new Error('No production curves found. Use: studies calculate production'));\n return;\n }\n\n const results: Record<string, unknown> = {};\n\n // --- Core energy calculations (always computed) ---\n\n // Net consumption = consumption - production\n const netConsumptionCurve = consCurve.aggregatePowerCurve(totalProdCurve.applyMultiplier(-1));\n results.netConsumption = netConsumptionCurve;\n\n // Total production\n results.totalProduction = totalProdCurve.getTotalAcumulate();\n\n // Consumption coverage percentage\n results.totalConsumptionCoverage =\n ((results.totalProduction as number) / consCurve.getTotalAcumulate()) * 100;\n\n // --- Period-based economic calculations (replicates SolarResultCalculator.calculateResults) ---\n const periodDistribution = await fetchPeriodDistribution(study, global);\n\n if (periodDistribution) {\n const clientDetails = study.clientDetails as Record<string, unknown> | undefined;\n const market = study.market as string | undefined;\n const oneBaseEnergyDiscountFactor = 1 - ((study.energyPricesDiscount as number) || 0) / 100;\n const oneBasePowerDiscountFactor = 1 - ((study.powerPricesDiscount as number) || 0) / 100;\n\n // Positive net consumption (filter out negatives = energy still needed from grid)\n const positiveNetConsumptionCurve = netConsumptionCurve.filterNegativeValues();\n const positiveNetByPeriod = positiveNetConsumptionCurve.aggregateByPeriod(periodDistribution);\n const rawConsumptionByPeriod = consCurve.aggregateByPeriod(periodDistribution);\n\n // Contracted power costs (if useAlternativePrices)\n const contractedPower = (study.contractedPower || {}) as ByPeriodValues;\n const powerPrices = (study.powerPrices || {}) as ByPeriodValues;\n const contractedPowerRawCostByPeriod: ByPeriodValues = {};\n if (study.useAlternativePrices) {\n for (let i = 1; i <= 6; i++) {\n const p = `p${i}`;\n if (contractedPower[p] && powerPrices[p]) {\n contractedPowerRawCostByPeriod[p] =\n (contractedPower[p] as number) * 365 * (powerPrices[p] as number) * oneBasePowerDiscountFactor;\n }\n }\n }\n\n // PT market peak cost\n if (market === 'pt') {\n const extraCostPrice = (study.extraCostPrice || {}) as ByPeriodValues;\n let numberOfP1hours = 0;\n periodDistribution.forEach((day: any) => {\n Object.values(day.valuesList).forEach((hour: any) => {\n if (hour === 1) numberOfP1hours++;\n });\n });\n const coefficient =\n (1 / numberOfP1hours) * ((extraCostPrice.p1 as number) || 0) * netConsumptionCurve.days.length;\n results.rawPeakConsumptionCostPt = ((rawConsumptionByPeriod as any)?.p1 || 0) * coefficient;\n results.netPeakConsumptionCostPt = ((positiveNetByPeriod as any)?.p1 || 0) * coefficient;\n }\n\n // Raw spending by period\n const totalRawSpendingByPeriod: ByPeriodValues = {};\n for (let i = 1; i <= 6; i++) {\n const p = `p${i}`;\n const rawConsP = (rawConsumptionByPeriod as any)?.[p] || 0;\n const priceP = (energyPrices[p] as number) || 0;\n const includeTaxes = clientDetails?.includeTaxes;\n const taxPct = (clientDetails?.taxesPercentage as number) || 0;\n const priceWithTax = includeTaxes && taxPct ? priceP * (1 + taxPct / 100) : priceP;\n totalRawSpendingByPeriod[p] =\n rawConsP * priceWithTax * oneBaseEnergyDiscountFactor +\n ((contractedPowerRawCostByPeriod[p] as number) || 0);\n }\n results.totalRawSpendingByPeriod = totalRawSpendingByPeriod;\n\n // Total raw spending\n results.totalRawSpending =\n Object.values(totalRawSpendingByPeriod)\n .filter((v): v is number => typeof v === 'number')\n .reduce((a, b) => a + b, 0) + ((results.rawPeakConsumptionCostPt as number) || 0);\n\n // Net spending by period + alternative prices\n const alternativeEnergyPrices = (study.alternativeEnergyPrices || {}) as ByPeriodValues;\n const alternativePowerPrices = (study.alternativePowerPrices || {}) as ByPeriodValues;\n const contractedPowerFinalCostByPeriod: ByPeriodValues = {};\n const contractedPowerSavingsByPeriod: ByPeriodValues = {};\n\n if (study.useAlternativePrices) {\n for (let i = 1; i <= 6; i++) {\n const p = `p${i}`;\n if (contractedPower[p] && alternativePowerPrices[p]) {\n contractedPowerFinalCostByPeriod[p] =\n (contractedPower[p] as number) * 365 * (alternativePowerPrices[p] as number);\n }\n if (contractedPower[p] && powerPrices[p] && alternativePowerPrices[p]) {\n contractedPowerSavingsByPeriod[p] =\n (contractedPower[p] as number) * 365 * (powerPrices[p] as number) * oneBasePowerDiscountFactor -\n (contractedPower[p] as number) * 365 * (alternativePowerPrices[p] as number) * oneBasePowerDiscountFactor;\n }\n }\n results.contractedPowerSavingsByPeriod = contractedPowerSavingsByPeriod;\n }\n\n const totalNetSpendingByPeriod: ByPeriodValues = {};\n const alternativeTotalNetSpendingByPeriod: ByPeriodValues = {};\n\n for (let i = 1; i <= 6; i++) {\n const p = `p${i}`;\n const posNetP = (positiveNetByPeriod as any)?.[p] || 0;\n const priceP = (energyPrices[p] as number) || 0;\n const altPriceP = (alternativeEnergyPrices[p] as number) || 0;\n const includeTaxes = clientDetails?.includeTaxes;\n const taxPct = (clientDetails?.taxesPercentage as number) || 0;\n\n totalNetSpendingByPeriod[p] =\n posNetP * (includeTaxes ? priceP * (1 + taxPct / 100) : priceP) * oneBaseEnergyDiscountFactor;\n\n if (study.alternativeEnergyPrices) {\n alternativeTotalNetSpendingByPeriod[p] =\n posNetP * altPriceP + ((contractedPowerFinalCostByPeriod[p] as number) || 0);\n }\n }\n results.totalNetSpendingByPeriod = totalNetSpendingByPeriod;\n if (study.alternativeEnergyPrices) {\n results.alternativeTotalNetSpendingByPeriod = alternativeTotalNetSpendingByPeriod;\n }\n\n // Total net spending\n results.totalNetSpending =\n Object.values(totalNetSpendingByPeriod)\n .filter((v): v is number => typeof v === 'number')\n .reduce((a, b) => a + b, 0) + ((results.netPeakConsumptionCostPt as number) || 0);\n\n // Savings by period = raw - net\n const totalSavingsByPeriod: ByPeriodValues = {};\n for (let i = 1; i <= 6; i++) {\n const p = `p${i}`;\n totalSavingsByPeriod[p] =\n ((totalRawSpendingByPeriod[p] as number) || 0) - ((totalNetSpendingByPeriod[p] as number) || 0);\n }\n results.totalSavingsByPeriod = totalSavingsByPeriod;\n\n // Alternative savings by period\n if (study.alternativeEnergyPrices) {\n const altSavings: ByPeriodValues = {};\n for (let i = 1; i <= 6; i++) {\n const p = `p${i}`;\n altSavings[p] =\n ((totalRawSpendingByPeriod[p] as number) || 0) -\n ((alternativeTotalNetSpendingByPeriod[p] as number) || 0);\n }\n results.totalSavingsByPeriodAlternativeSavings = altSavings;\n }\n\n // Total savings\n results.totalSavings =\n Object.values(totalSavingsByPeriod)\n .filter((v): v is number => typeof v === 'number')\n .reduce((a, b) => a + b, 0) +\n (((results.rawPeakConsumptionCostPt as number) || 0) -\n ((results.netPeakConsumptionCostPt as number) || 0));\n\n // Total savings with alternative prices\n if (study.alternativeEnergyPrices) {\n results.totalSavingsAlternativePrices =\n Object.values(alternativeTotalNetSpendingByPeriod)\n .filter((v): v is number => typeof v === 'number')\n .reduce((a, b) => a + b, 0) +\n (((results.rawPeakConsumptionCostPt as number) || 0) -\n ((results.netPeakConsumptionCostPt as number) || 0));\n }\n\n // Excesses curve = (production - consumption), keep positive\n const excessesCurve = totalProdCurve\n .aggregatePowerCurve(consCurve.applyMultiplier(-1))\n .filterNegativeValues();\n results.excessesCurve = excessesCurve;\n\n // Excesses by period\n results.totalExcessesByPeriod = excessesCurve.aggregateByPeriod(periodDistribution);\n results.totalExcesses = Object.values(results.totalExcessesByPeriod as ByPeriodValues)\n .filter((v): v is number => typeof v === 'number')\n .reduce((a, b) => a + b, 0);\n }\n\n const result = updateStudy(filePath, (s) => {\n s.results = results;\n return undefined;\n });\n output(result, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // ═══════════════════════════════════════════\n // OPTIMIZE PEAK POWER\n // ═══════════════════════════════════════════\n\n studies\n .command('optimize-peakpower')\n .description(\n 'Optimize peak power based on consumption.\\n\\n' +\n 'Supports two modes:\\n' +\n ' - Panel mode (default or when solarPanel is set): iterates peak power\\n' +\n ' - Kit mode (when solarKit is set or --use-kits): evaluates available kits\\n\\n' +\n 'Optimization criteria (pick one):\\n' +\n ' --energy-savings <pct> Target energy savings percentage\\n' +\n ' --raw-consumption <pct> Production as percentage of consumption\\n' +\n ' --max-excesses <pct> Max excesses as percentage of production\\n' +\n ' --max-overproduction-months <n> Max months with overproduction\\n\\n' +\n 'Surface constraints:\\n' +\n ' If surfaces have area + panel dimensions, max panels per surface is calculated.\\n' +\n ' Without area, no surface constraint is applied (unlimited space).\\n\\n' +\n 'Examples:\\n' +\n ' suntropy studies optimize-peakpower --file study.json --energy-savings 70\\n' +\n ' suntropy studies optimize-peakpower --file study.json --raw-consumption 100 --use-kits\\n' +\n ' suntropy studies optimize-peakpower --file study.json --max-excesses 15'\n )\n .option('--file <path>', 'Study file path')\n .option('--energy-savings <pct>', 'Target energy savings %')\n .option('--raw-consumption <pct>', 'Target production as % of consumption')\n .option('--max-excesses <pct>', 'Max excesses as % of production')\n .option('--max-overproduction-months <n>', 'Max months with overproduction')\n .option('--use-kits', 'Force kit mode (fetch all active kits and select optimal)')\n .option('--apply', 'Apply the result to the study file (set peakpower/kit, recalculate production)')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const filePath = resolveFile(opts);\n const study = readStudy(filePath);\n\n // Determine evaluation mode\n const evaluationMode: Record<string, number> = {};\n if (opts.energySavings !== undefined) evaluationMode.energyPercentageSavings = parseFloat(opts.energySavings);\n else if (opts.rawConsumption !== undefined) evaluationMode.rawConsumptionPercentage = parseFloat(opts.rawConsumption);\n else if (opts.maxExcesses !== undefined) evaluationMode.maxExcessesPercentage = parseFloat(opts.maxExcesses);\n else if (opts.maxOverproductionMonths !== undefined) evaluationMode.maxNumberOfOverproductionMonths = parseInt(opts.maxOverproductionMonths);\n else {\n // Default: 100% raw consumption (match consumption)\n evaluationMode.rawConsumptionPercentage = 100;\n }\n\n // Validate study has consumption and production\n const surfaces = study.surfaces as Record<string, unknown>[] | undefined;\n if (!surfaces?.length) {\n outputError(new Error('No surfaces in study. Use: studies add surface'));\n return;\n }\n const consumptionData = study.consumption as Record<string, unknown> | undefined;\n if (!consumptionData) {\n outputError(new Error('No consumption in study. Use: studies set consumption'));\n return;\n }\n\n // Check all surfaces have production\n const surfacesWithoutProduction = surfaces.filter((s) => !s.production);\n if (surfacesWithoutProduction.length > 0) {\n outputError(new Error(`${surfacesWithoutProduction.length} surface(s) without production. Use: studies calculate production --all-surfaces`));\n return;\n }\n\n const { PowerCurve } = await import('energy-types/lib/energy/classes/powerCurve.class.js');\n\n // Build consumption PowerCurve\n const cd = consumptionData as any;\n const consumptionCurve = new PowerCurve(cd.days || cd, cd.ignore0 ?? false, cd.identifier || 'consumption', cd.parseDate ?? false);\n const totalConsumption = consumptionCurve.getTotalAcumulate();\n\n // Build base production (1 kWp) for each surface\n const baseProduction: Record<string, any> = {};\n for (const surface of surfaces) {\n const sid = surface.surfaceId as string;\n const prodData = surface.production as any;\n const prodCurve = new PowerCurve(prodData.days || prodData, false, sid, false);\n const installedPower = (surface.installedPower as number) || 5000;\n // Normalize to 1kWp base\n baseProduction[sid] = prodCurve.applyMultiplier(1 / (installedPower / 1000));\n }\n\n // Determine mode: kit vs panel\n const useKits = opts.useKits || study.peakPowerIntroductionMode === 'solarKit';\n const solarClient = createServiceClient('solar', global);\n\n if (useKits) {\n // ── KIT MODE ──\n const phaseNumber = (study.phaseNumber as string) || 'single_phase';\n\n // Fetch all active kits\n const kitsRes = await solarClient.get('/solar-kits', { params: { limit: 500 } });\n let allKits = Array.isArray(kitsRes.data) && Array.isArray(kitsRes.data[0])\n ? kitsRes.data[0]\n : (Array.isArray(kitsRes.data) ? kitsRes.data : kitsRes.data?.data || []);\n\n // Filter by phase\n allKits = allKits.filter((k: any) => k.phaseNumber === phaseNumber && k.active !== false);\n\n // Check coplanar compatibility\n const isCoplanar = surfaces.every((s) => !(s.panelInclination as number));\n allKits = allKits.filter((k: any) =>\n isCoplanar === undefined ? true : isCoplanar === (k.coplanar === null ? true : k.coplanar)\n );\n\n // Sort by peak power ascending (smallest first)\n allKits.sort((a: any, b: any) =>\n (a.panelNumber * (a.kitSolarPanel?.peakPower || 0)) - (b.panelNumber * (b.kitSolarPanel?.peakPower || 0))\n );\n\n if (allKits.length === 0) {\n outputError(new Error('No compatible kits found for current phase/surface configuration'));\n return;\n }\n\n let selectedKit: any = null;\n let bestApproxKit: any = null;\n let bestApproxValue = -Infinity;\n let firstValidKit: any = null;\n const optimizationLog: Record<number, any> = {};\n\n for (const kit of allKits) {\n const kitPanel = kit.kitSolarPanel;\n if (!kitPanel) continue;\n\n // Distribute panels across surfaces\n let remainingPanels = kit.panelNumber || 0;\n const surfPanelCount: Record<string, number> = {};\n let fits = true;\n\n for (const surface of surfaces) {\n const sid = surface.surfaceId as string;\n const area = surface.area as number | undefined;\n let maxPanels: number;\n\n if (area && kitPanel.width && kitPanel.heigth) {\n // Calculate max panels from area\n maxPanels = calculateMaxPanels(\n area,\n kitPanel,\n (surface.availableAreaPercentage as number) || 85,\n (surface.panelInclination as number) || 0,\n (surface.inclination as number) || 0,\n (surface.panelPosition as string) || 'vertical',\n resolveSurfaceCoordinates(surface, study)?.lat ?? 37,\n );\n } else {\n // No area constraint — unlimited\n maxPanels = remainingPanels;\n }\n\n const assigned = Math.min(remainingPanels, maxPanels);\n surfPanelCount[sid] = assigned;\n remainingPanels -= assigned;\n }\n\n if (remainingPanels > 0) continue; // Kit doesn't fit\n\n if (!firstValidKit) firstValidKit = kit;\n\n // Calculate production for this kit\n let totalProd: any = null;\n for (const surface of surfaces) {\n const sid = surface.surfaceId as string;\n const panelCount = surfPanelCount[sid] || 0;\n const surfPeakPower = (panelCount * kitPanel.peakPower) / 1000;\n const surfProd = baseProduction[sid].applyMultiplier(surfPeakPower);\n totalProd = totalProd ? totalProd.aggregatePowerCurve(surfProd) : surfProd;\n }\n\n const netConsumption = consumptionCurve.aggregatePowerCurve(totalProd.applyMultiplier(-1));\n const kitPeakPower = ((kit.panelNumber || 0) * kitPanel.peakPower) / 1000;\n const totalProdKwh = totalProd.getTotalAcumulate();\n\n // Evaluate criteria\n let criterionValue: number;\n let criterionMet = false;\n\n if (evaluationMode.energyPercentageSavings !== undefined) {\n const netFiltered = netConsumption.filterNegativeValues().getTotalAcumulate();\n criterionValue = ((totalConsumption - netFiltered) / totalConsumption) * 100;\n criterionMet = criterionValue >= evaluationMode.energyPercentageSavings;\n } else if (evaluationMode.rawConsumptionPercentage !== undefined) {\n criterionValue = (totalProdKwh / totalConsumption) * 100;\n criterionMet = criterionValue >= evaluationMode.rawConsumptionPercentage;\n } else if (evaluationMode.maxExcessesPercentage !== undefined) {\n const excessesCurve = netConsumption.filterPositiveValues();\n criterionValue = (excessesCurve.getTotalAcumulate() / totalProdKwh) * 100 * -1;\n criterionMet = criterionValue <= evaluationMode.maxExcessesPercentage;\n } else if (evaluationMode.maxNumberOfOverproductionMonths !== undefined) {\n const stats = netConsumption.calculateStatistics().statistics.anualMonthAccumulate;\n let byMonth = stats[Object.keys(stats).find((k) => k !== 'definition') || ''] || {};\n delete byMonth.yearly;\n criterionValue = Object.values(byMonth).filter((v: any) => v < 0).length;\n criterionMet = criterionValue <= evaluationMode.maxNumberOfOverproductionMonths;\n } else {\n criterionValue = 0;\n }\n\n optimizationLog[kit.idSolarKit] = {\n identifier: kit.identifier,\n peakPower: kitPeakPower,\n totalProduction: totalProdKwh,\n criterionValue,\n criterionMet,\n panelDistribution: surfPanelCount,\n };\n\n if (criterionValue > bestApproxValue) {\n bestApproxValue = criterionValue;\n bestApproxKit = kit;\n }\n\n if (criterionMet) {\n selectedKit = kit;\n break;\n }\n }\n\n if (!selectedKit) {\n selectedKit = bestApproxKit || firstValidKit;\n }\n\n const resultData: Record<string, unknown> = {\n mode: 'kit',\n evaluationMode,\n selectedKit: selectedKit ? {\n idSolarKit: selectedKit.idSolarKit,\n identifier: selectedKit.identifier,\n peakPower: ((selectedKit.panelNumber || 0) * (selectedKit.kitSolarPanel?.peakPower || 0)) / 1000,\n panelNumber: selectedKit.panelNumber,\n price: selectedKit.price,\n } : null,\n kitsEvaluated: Object.keys(optimizationLog).length,\n optimizationLog,\n };\n\n if (opts.apply && selectedKit) {\n updateStudy(filePath, (s) => {\n s.solarKit = selectedKit;\n s.peakPowerIntroductionMode = 'solarKit';\n s.solarPanel = undefined;\n s.solarInverters = undefined;\n s.peakPowerOptimizationMethod = evaluationMode;\n return undefined;\n });\n resultData.applied = true;\n }\n\n output(resultData, global);\n } else {\n // ── PANEL MODE ──\n const panel = study.solarPanel as Record<string, unknown> | undefined;\n if (!panel) {\n outputError(new Error('No solar panel set. Use: studies set panel --panel-id <id>'));\n return;\n }\n\n const panelPeakPower = (panel.peakPower as number) || 450;\n const panelWidth = (panel.width as number) || 1134;\n const panelHeight = (panel.heigth as number) || (panel.height as number) || 1762;\n const panelObj = { peakPower: panelPeakPower, width: panelWidth, heigth: panelHeight };\n\n // Calculate max peak power per surface\n const surfacesMaxPeakPower: Record<string, number> = {};\n let totalMaxPeakPower = 0;\n\n for (const surface of surfaces) {\n const sid = surface.surfaceId as string;\n const area = surface.area as number | undefined;\n\n if (area && panelWidth && panelHeight) {\n const maxPanels = calculateMaxPanels(\n area,\n panelObj,\n (surface.availableAreaPercentage as number) || 85,\n (surface.panelInclination as number) || 0,\n (surface.inclination as number) || 0,\n (surface.panelPosition as string) || 'vertical',\n resolveSurfaceCoordinates(surface, study)?.lat ?? 37,\n );\n surfacesMaxPeakPower[sid] = (maxPanels * panelPeakPower) / 1000;\n } else {\n // No area constraint — use large value (500 kWp per surface)\n surfacesMaxPeakPower[sid] = 500;\n }\n totalMaxPeakPower += surfacesMaxPeakPower[sid];\n }\n\n // Determine iteration direction and initial value\n const isAscending = evaluationMode.energyPercentageSavings !== undefined\n || evaluationMode.economicPercentageSavings !== undefined\n || evaluationMode.rawConsumptionPercentage !== undefined;\n\n let peakPower = isAscending ? panelPeakPower / 1000 : totalMaxPeakPower;\n const optimizationLog: Record<number, any> = {};\n let resultPeakPower: Record<string, number> = {};\n let lastResult: number | undefined;\n const MAX_ITERATIONS = 200;\n const TOLERANCE = 0.005;\n let correctionFactor = 1;\n let itersSinceCorrection = 0;\n\n for (let iter = 0; iter < MAX_ITERATIONS && peakPower > 0 && peakPower <= totalMaxPeakPower; iter++) {\n peakPower = parseFloat(peakPower.toFixed(2));\n itersSinceCorrection++;\n\n if (itersSinceCorrection >= 20) {\n correctionFactor += 1.1;\n itersSinceCorrection = 0;\n }\n\n // Calculate change rate\n let changeRate: number;\n if (peakPower < 20) changeRate = (panelPeakPower / 1000) * correctionFactor;\n else if (peakPower < 500) changeRate = 5 * correctionFactor;\n else changeRate = 50 * correctionFactor;\n\n // Distribute peak power across surfaces\n let remaining = peakPower;\n let totalProd: any = null;\n resultPeakPower = {};\n\n for (const surface of surfaces) {\n const sid = surface.surfaceId as string;\n const surfPP = Math.min(remaining, surfacesMaxPeakPower[sid]);\n remaining -= surfPP;\n resultPeakPower[sid] = surfPP;\n const surfProd = baseProduction[sid].applyMultiplier(surfPP);\n totalProd = totalProd ? totalProd.aggregatePowerCurve(surfProd) : surfProd;\n }\n\n const netConsumption = consumptionCurve.aggregatePowerCurve(totalProd.applyMultiplier(-1));\n const totalProdKwh = totalProd.getTotalAcumulate();\n\n // Evaluate criterion\n let criterionValue: number;\n let criterionMet = false;\n\n if (evaluationMode.energyPercentageSavings !== undefined) {\n const netFiltered = netConsumption.filterNegativeValues().getTotalAcumulate();\n criterionValue = ((totalConsumption - netFiltered) / totalConsumption) * 100;\n criterionMet = criterionValue >= evaluationMode.energyPercentageSavings;\n } else if (evaluationMode.rawConsumptionPercentage !== undefined) {\n criterionValue = (totalProdKwh / totalConsumption) * 100;\n criterionMet = criterionValue >= evaluationMode.rawConsumptionPercentage;\n } else if (evaluationMode.maxExcessesPercentage !== undefined) {\n const excessesCurve = netConsumption.filterPositiveValues();\n criterionValue = (excessesCurve.getTotalAcumulate() / totalProdKwh) * 100 * -1;\n criterionMet = criterionValue <= evaluationMode.maxExcessesPercentage;\n } else if (evaluationMode.maxNumberOfOverproductionMonths !== undefined) {\n const stats = netConsumption.calculateStatistics().statistics.anualMonthAccumulate;\n let byMonth = stats[Object.keys(stats).find((k) => k !== 'definition') || ''] || {};\n delete byMonth.yearly;\n criterionValue = Object.values(byMonth).filter((v: any) => v < 0).length;\n criterionMet = criterionValue <= evaluationMode.maxNumberOfOverproductionMonths;\n } else {\n criterionValue = 0;\n }\n\n optimizationLog[peakPower] = {\n totalProduction: totalProdKwh,\n criterionValue,\n criterionMet,\n surfacesPeakpower: { ...resultPeakPower },\n };\n\n if (criterionMet) break;\n\n // Tolerance check — stop if no meaningful progress\n if (isAscending && lastResult !== undefined && lastResult * (1 + TOLERANCE) >= criterionValue) {\n break;\n }\n lastResult = criterionValue;\n\n peakPower += isAscending ? changeRate : -changeRate;\n }\n\n // Compute final totals\n const totalOptimizedPeakPower = Object.values(resultPeakPower).reduce((a, b) => a + b, 0);\n const totalPanels = Math.round(totalOptimizedPeakPower / (panelPeakPower / 1000));\n\n const resultData: Record<string, unknown> = {\n mode: 'panel',\n evaluationMode,\n optimizedPeakPower: parseFloat(totalOptimizedPeakPower.toFixed(2)),\n estimatedPanels: totalPanels,\n surfacesPeakpower: resultPeakPower,\n iterations: Object.keys(optimizationLog).length,\n optimizationLog,\n };\n\n if (opts.apply) {\n updateStudy(filePath, (s) => {\n const surfs = s.surfaces as Record<string, unknown>[] | undefined;\n if (surfs) {\n for (const surf of surfs) {\n const sid = surf.surfaceId as string;\n if (resultPeakPower[sid] !== undefined) {\n const surfPanels = Math.round(resultPeakPower[sid] / (panelPeakPower / 1000));\n surf.panelNumber = surfPanels;\n surf.installedPower = resultPeakPower[sid] * 1000;\n }\n }\n }\n s.peakPowerOptimizationMethod = evaluationMode;\n return 'surfaces';\n });\n resultData.applied = true;\n }\n\n output(resultData, global);\n }\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // ═══════════════════════════════════════════\n // COMMENTS\n // ═══════════════════════════════════════════\n\n // --- add comment (local study file) ---\n studies\n .command('add-comment')\n .description(\n 'Add a comment to the local study file.\\n' +\n 'Example: suntropy studies add-comment --file study.json --content \"Panel layout reviewed\"'\n )\n .option('--file <path>', 'Study file path')\n .requiredOption('--content <text>', 'Comment text')\n .action(async (opts) => {\n try {\n const result = updateStudy(resolveFile(opts), (study) => {\n const comments = (study.comments || []) as Record<string, unknown>[];\n comments.push(createComment('commented', opts.content));\n study.comments = comments;\n return undefined;\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- comment (API — add to existing study in backend) ---\n studies\n .command('comment <studyId>')\n .description(\n 'Add a comment to an existing study via API.\\n' +\n 'Example: suntropy studies comment abc123 --content \"Revisado por agente\"'\n )\n .requiredOption('--content <text>', 'Comment text')\n // Hidden flags for the \"Tag de Alexandria en comentarios\" workflow (sprint\n // Suntropy AI). They are intentionally omitted from --help / docs: the\n // Alexandria agent is instructed to use them in that specific workflow only.\n // - `--as-alexandria` signs the comment as Alexandria.\n // - `--reply-to-user`/`--reply-to-name` prepend a mention `@[name](userUID)`\n // with the markup the backend parses to notify that user.\n .addOption(new Option('--as-alexandria').hideHelp())\n .addOption(new Option('--reply-to-user <userUID>').hideHelp())\n .addOption(new Option('--reply-to-name <name>').hideHelp())\n .action(async (studyId, opts) => {\n try {\n assertStudyObjectId(studyId);\n const global = getGlobalOpts(studies);\n const client = createServiceClient('solar', global);\n const comment = createComment('commented', opts.content, {\n asAlexandria: Boolean(opts.asAlexandria),\n replyToUser: opts.replyToUser,\n replyToName: opts.replyToName,\n });\n const res = await client.post(`/solar-study/addSolarStudyComment/${studyId}`, comment);\n // The endpoint returns the FULL updated study (and an EMPTY body when the\n // study isn't found). Keep the guard so we never report a non-saved\n // comment as success, but DON'T dump the whole study: emit a compact\n // confirmation of the comment that was created.\n const saved = assertFound(res.data, 'Solar study', studyId) as {\n comments?: unknown[];\n };\n output(\n {\n success: true,\n message: `Comentario añadido al estudio ${studyId}`,\n studyId,\n commentsCount: Array.isArray(saved.comments)\n ? saved.comments.length\n : undefined,\n comment: {\n type: comment.type,\n creationUserUID: comment.creationUserUID,\n creationTimestamp: comment.creationTimestamp,\n aiGenerated: comment.aiGenerated ?? false,\n content: comment.content,\n },\n },\n global,\n );\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n\n// ─── Helpers ───\n\n/** Generate consumption curve from REE profile + period/monthly data using energy-types */\nasync function generateFromProfile(\n global: OutputOptions & Record<string, unknown>,\n tariff: string,\n market: string,\n year: number,\n mode: 'CONSUMPTION_BY_PERIOD' | 'MONTH_CONSUMPTION' | 'MONTHLY_BY_PERIOD',\n data: unknown,\n): Promise<unknown> {\n const profilesClient = createServiceClient('profiles', global);\n const periodsClient = createServiceClient('periods', global);\n\n // 1. Fetch REE profile\n const profileRes = await profilesClient.get('/ree-profiles', {\n params: {\n startDate: `${year}-01-01`,\n endDate: `${year}-12-31`,\n tariff,\n type: 'Final',\n market,\n },\n });\n const profile = profileRes.data?.profile || profileRes.data;\n if (!profile || !Array.isArray(profile) || profile.length === 0) {\n throw new Error('Failed to fetch REE profiles');\n }\n\n // 2. Import energy-types\n const { applyProfileToConsumption, ConsumptionIntroductionModes } =\n await import('energy-types/lib/energy/calculations/applyProfileToConsumption');\n\n if (mode === 'CONSUMPTION_BY_PERIOD') {\n // Need period distribution\n const tariffIdMap: Record<string, number> = { '2.0TD': 13, '3.0TD': 14, '6.1TD': 15 };\n const tariffId = tariffIdMap[tariff] || 14;\n const periodsRes = await periodsClient.get('/periodos', {\n params: {\n idTarifa: tariffId,\n idZona: 1,\n fechaInicio: `${year}-01-01`,\n fechaFin: `${year}-12-31`,\n market,\n },\n });\n const periodDistribution = periodsRes.data;\n\n const result = applyProfileToConsumption(\n ConsumptionIntroductionModes.CONSUMPTION_BY_PERIOD,\n profile,\n data,\n periodDistribution,\n );\n return result;\n\n } else if (mode === 'MONTH_CONSUMPTION') {\n // Transform flat {month: value} into {year: {month: value}} expected by energy-types\n const flatData = data as Record<string, number>;\n const yearMonthData: Record<number, Record<number, number>> = { [year]: {} };\n for (const [month, value] of Object.entries(flatData)) {\n yearMonthData[year][parseInt(month)] = value;\n }\n const result = applyProfileToConsumption(\n ConsumptionIntroductionModes.MONTH_CONSUMPTION,\n profile,\n yearMonthData,\n );\n return result;\n\n } else if (mode === 'MONTHLY_BY_PERIOD') {\n // For monthly by period, we need to process month by month\n // This is more complex — for now, use the MONTH_CONSUMPTION as fallback\n // with aggregated monthly totals\n const monthlyData = data as Record<string, Record<string, number>>;\n const monthTotals: Record<string, number> = {};\n for (const [month, periods] of Object.entries(monthlyData)) {\n monthTotals[month] = Object.values(periods).reduce((a, b) => a + b, 0);\n }\n const result = applyProfileToConsumption(\n ConsumptionIntroductionModes.MONTH_CONSUMPTION,\n profile,\n monthTotals,\n );\n return result;\n }\n\n throw new Error(`Unknown consumption mode: ${mode}`);\n}\n\n/** Calculate max panels that fit in an area (replicates frontend calculateSolarPanelsInArea) */\nfunction calculateMaxPanels(\n areaM2: number,\n panel: { width: number; heigth: number; peakPower?: number },\n availablePercentage: number,\n panelInclination: number,\n surfaceInclination: number,\n panelPosition: string,\n latitude: number,\n): number {\n const { heigth, width } = panel;\n // Convert m² to mm² and apply available percentage\n let area = areaM2 * 1000000 * (availablePercentage / 100);\n const x = 1 / Math.atan(61 - (latitude - surfaceInclination));\n let totalPanelNumber: number;\n\n if (panelPosition === 'horizontal') {\n const h = width * Math.asin(panelInclination * (Math.PI / 180));\n const minimumDistance = x * h;\n const panelArea = (heigth + 20) * (width + minimumDistance);\n totalPanelNumber = area / panelArea;\n } else {\n const h = heigth * Math.asin(panelInclination * (Math.PI / 180));\n const minimumDistance = x * h;\n const panelArea = (width + 20) * (heigth + minimumDistance);\n totalPanelNumber = area / panelArea;\n }\n\n return isNaN(totalPanelNumber) ? 0 : Math.floor(totalPanelNumber);\n}\n\n/** Collector for repeatable --asset <id:qty> */\nfunction collectAssets(value: string, previous: { id: number; quantity: number }[]): { id: number; quantity: number }[] {\n const [idStr, qtyStr] = value.split(':');\n const id = parseInt(idStr);\n const quantity = qtyStr ? parseInt(qtyStr) : 1;\n if (isNaN(id)) throw new Error(`Invalid asset format: \"${value}\". Use <id>:<quantity>`);\n return [...previous, { id, quantity }];\n}\n\n/** Fetch period distribution from periods service (needed for economic calculations) */\nasync function fetchPeriodDistribution(\n study: Study,\n global: OutputOptions & Record<string, unknown>,\n): Promise<unknown[] | null> {\n const atrTariff = study.atrTariff as Record<string, unknown> | undefined;\n const geoZone = study.geographicalZone as Record<string, unknown> | undefined;\n if (!atrTariff) return null;\n\n const tariffId = atrTariff.idTarifaATR as number;\n const zoneId = (geoZone?.idZona as number) || 1;\n const market = (study.market as string) || 'es';\n const year = new Date().getFullYear();\n\n try {\n const periodsClient = createServiceClient('periods', global);\n const res = await periodsClient.get('/periodos', {\n params: {\n idTarifa: tariffId,\n idZona: zoneId,\n fechaInicio: `${year}-01-01`,\n fechaFin: `${year}-12-31`,\n market,\n },\n });\n const data = res.data;\n if (Array.isArray(data) && data.length > 0) return data;\n return null;\n } catch {\n return null;\n }\n}\n\ninterface CreateCommentExtra {\n /** Sign the comment as Alexandria (AI assistant) instead of the active user. */\n asAlexandria?: boolean;\n /** userUID to mention at the start of the comment so the backend notifies them. */\n replyToUser?: string;\n /** Display name for the mentioned user (defaults to the userUID). */\n replyToName?: string;\n}\n\n/** Create a study comment (replicates frontend createNewComment) */\nfunction createComment(\n type: string,\n content?: string,\n extra?: CreateCommentExtra\n): Record<string, unknown> {\n const config = loadConfig();\n const profile = getActiveProfile(config);\n const autoContent: Record<string, string> = {\n created: 'Estudio creado via CLI',\n modified: 'Estudio actualizado via CLI',\n };\n\n let body = content || autoContent[type] || '';\n // Prepend a mention so the backend parses it and notifies the user. The\n // markup must match react-mentions / the backend regex: @[name](userUID).\n if (extra?.replyToUser) {\n const name = extra.replyToName || extra.replyToUser;\n body = `@[${name}](${extra.replyToUser}) ${body}`.trim();\n }\n\n const comment: Record<string, unknown> = {\n content: body,\n type,\n creationTimestamp: new Date().toISOString(),\n creationUserUID: extra?.asAlexandria\n ? 'alexandria'\n : profile.userUID || 'cli-agent',\n };\n // Mark AI-authored comments so the frontend renders them as Alexandria.\n if (extra?.asAlexandria) {\n comment.aiGenerated = true;\n }\n return comment;\n}\n","import crypto from 'crypto';\nconst rnds8Pool = new Uint8Array(256); // # of random values to pre-allocate\n\nlet poolPtr = rnds8Pool.length;\nexport default function rng() {\n if (poolPtr > rnds8Pool.length - 16) {\n crypto.randomFillSync(rnds8Pool);\n poolPtr = 0;\n }\n\n return rnds8Pool.slice(poolPtr, poolPtr += 16);\n}","export default /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i;","import REGEX from './regex.js';\n\nfunction validate(uuid) {\n return typeof uuid === 'string' && REGEX.test(uuid);\n}\n\nexport default validate;","import validate from './validate.js';\n/**\n * Convert array of 16 byte values to UUID string format of the form:\n * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX\n */\n\nconst byteToHex = [];\n\nfor (let i = 0; i < 256; ++i) {\n byteToHex.push((i + 0x100).toString(16).substr(1));\n}\n\nfunction stringify(arr, offset = 0) {\n // Note: Be careful editing this code! It's been tuned for performance\n // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434\n const uuid = (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase(); // Consistency check for valid UUID. If this throws, it's likely due to one\n // of the following:\n // - One or more input array values don't map to a hex octet (leading to\n // \"undefined\" in the uuid)\n // - Invalid input values for the RFC `version` or `variant` fields\n\n if (!validate(uuid)) {\n throw TypeError('Stringified UUID is invalid');\n }\n\n return uuid;\n}\n\nexport default stringify;","import rng from './rng.js';\nimport stringify from './stringify.js';\n\nfunction v4(options, buf, offset) {\n options = options || {};\n const rnds = options.random || (options.rng || rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`\n\n rnds[6] = rnds[6] & 0x0f | 0x40;\n rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided\n\n if (buf) {\n offset = offset || 0;\n\n for (let i = 0; i < 16; ++i) {\n buf[offset + i] = rnds[i];\n }\n\n return buf;\n }\n\n return stringify(rnds);\n}\n\nexport default v4;","import { Command } from 'commander';\nimport { createServiceClient, handleApiError, assertFound, assertStudyObjectId } from '../../client.js';\nimport { output, outputError, outputPaginated, type OutputOptions } from '../../output.js';\nimport { registerStudyBuilderCommands } from './builder.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\n/** Replace PowerCurve objects with lightweight summaries to save tokens */\nfunction compactCurves(obj: unknown): unknown {\n if (obj === null || obj === undefined || typeof obj !== 'object') return obj;\n if (Array.isArray(obj)) return obj.map(compactCurves);\n\n const record = obj as Record<string, unknown>;\n\n // Detect PowerCurve: has 'days' array with objects containing 'valuesList'\n if (Array.isArray(record.days) && record.days.length > 0 && record.identifier !== undefined) {\n return { _type: 'PowerCurve', days: record.days.length, identifier: record.identifier };\n }\n\n // Detect inline DayCurve arrays (consumption, production fields that are PowerCurve-like)\n const result: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(record)) {\n if (val && typeof val === 'object' && !Array.isArray(val)) {\n const v = val as Record<string, unknown>;\n if (Array.isArray(v.days) && v.days.length > 0 && v.identifier !== undefined) {\n result[key] = { _type: 'PowerCurve', days: v.days.length, identifier: v.identifier };\n continue;\n }\n }\n result[key] = compactCurves(val);\n }\n return result;\n}\n\n/** Expand sections: pick which parts of study to include */\nconst EXPAND_SECTIONS: Record<string, string[]> = {\n surfaces: ['surfaces'],\n results: ['results'],\n economics: ['economicResults'],\n batteries: ['activeBatteries', 'batteriesConfiguration', 'batteriesEnergyBalance', 'batteriesResults', 'bateries'],\n consumption: ['consumption', 'consumptionIntroductionMode', 'monthConsumptionDictionary', 'monthPeriodConsumptionDictionary', 'periodConsumptionDictionary'],\n equipment: ['solarPanel', 'solarKit', 'solarInverters', 'selectedChargers', 'selectedCustomAssets'],\n client: ['clientDetails', 'clientsDetails'],\n location: ['location', 'mapCenter', 'geographicalZone', 'atrTariff'],\n};\n\n/**\n * Fields that users often ask for on the study but actually live on the\n * metadata entity (MySQL) — surfaced via `studies list` or `studies metadata`.\n */\nconst METADATA_ONLY_FIELDS: Record<string, string> = {\n peakPower: 'metadata',\n sellingPrice: 'metadata',\n totalCost: 'metadata',\n anualProduction: 'metadata',\n anualConsumption: 'metadata',\n currentState: 'metadata',\n clientName: 'metadata',\n idSolarStudyMetadata: 'metadata',\n solarStudyId: 'metadata',\n};\n\n/**\n * Fields that don't exist on either the study document or its metadata —\n * they are computed client-side (builder) or simply don't exist in this API.\n */\nconst COMPUTED_OR_UNKNOWN_FIELDS: Record<string, string> = {\n completionPercentage: 'computed by `studies validate` / `studies save` from stepsProgress',\n isCompleted: 'not a persisted field; derive from solarStudyProgress or completionPercentage',\n stepsProgress: 'computed by `studies validate` / `studies save`',\n};\n\nfunction explainMissingStudyFields(missing: string[], studyId: string): void {\n const metadataFields = missing.filter(f => f in METADATA_ONLY_FIELDS);\n const computedFields = missing.filter(f => f in COMPUTED_OR_UNKNOWN_FIELDS);\n const unknownFields = missing.filter(f => !(f in METADATA_ONLY_FIELDS) && !(f in COMPUTED_OR_UNKNOWN_FIELDS));\n\n const lines: string[] = [];\n lines.push(`warning: ${missing.length} requested field(s) are not present on the study document returned by findById.`);\n\n if (metadataFields.length > 0) {\n lines.push('');\n lines.push(` These fields live on the STUDY METADATA (MySQL), not on the study document:`);\n for (const f of metadataFields) lines.push(` - ${f}`);\n lines.push(` Use: suntropy studies metadata ${studyId} --by-study-id --fields ${metadataFields.join(',')}`);\n lines.push(` Or: suntropy studies list --client-name <name> (list already projects these fields)`);\n }\n\n if (computedFields.length > 0) {\n lines.push('');\n lines.push(` These fields are not persisted on the study:`);\n for (const f of computedFields) lines.push(` - ${f}: ${COMPUTED_OR_UNKNOWN_FIELDS[f]}`);\n lines.push(` Use: suntropy studies validate ${studyId} (returns stepsProgress + completionPercentage)`);\n }\n\n if (unknownFields.length > 0) {\n lines.push('');\n lines.push(` These fields were not found on the study document:`);\n for (const f of unknownFields) lines.push(` - ${f}`);\n lines.push(` If you expected them, try: suntropy studies get ${studyId} --expand all --format json`);\n lines.push(` and inspect the full payload to locate the correct field path.`);\n }\n\n process.stderr.write(lines.join('\\n') + '\\n');\n}\n\n/** Core identity fields always included in get */\nconst CORE_FIELDS = [\n '_id', 'id', 'name', 'identifier', 'clientUID',\n 'creationTimestamp', 'lastEditTimestamp',\n 'assignedUserUID', 'creationUserUID',\n 'selectedSolarStudyMode', 'solarStudyProgress',\n 'market', 'layout',\n 'peakPowerIntroductionMode', 'instalationPhaseNumber',\n];\n\nfunction filterStudy(study: Record<string, unknown>, expand?: string): Record<string, unknown> {\n if (expand === 'all') return study;\n\n const sections = expand ? expand.split(',').map(s => s.trim()) : [];\n const allowedFields = new Set(CORE_FIELDS);\n\n for (const section of sections) {\n const fields = EXPAND_SECTIONS[section];\n if (fields) fields.forEach(f => allowedFields.add(f));\n }\n\n // If no expand, include summary numeric fields\n if (sections.length === 0) {\n ['peakPowerIntroductionMode', 'instalationPhaseNumber', 'location', 'atrTariff'].forEach(f => allowedFields.add(f));\n }\n\n const result: Record<string, unknown> = {};\n for (const key of allowedFields) {\n if (key in study) result[key] = study[key];\n }\n\n return compactCurves(result) as Record<string, unknown>;\n}\n\nexport function registerStudiesCommands(program: Command): void {\n const studies = program.command('studies').description(\n 'Explore and manage solar studies. Progressive exploration: list → metadata → get → get --expand → curves'\n );\n\n // --- list ---\n studies\n .command('list')\n .description('List solar studies metadata. Fields: idSolarStudyMetadata, solarStudyId, clientName, peakPower, currentState, creationTimestamp')\n .option('--limit <n>', 'Max results', '20')\n .option('--offset <n>', 'Skip results', '0')\n .option('--state <state>', 'Filter by state name')\n .option('--client-name <name>', 'Filter by client name')\n .option('--from <date>', 'Filter from date (YYYY-MM-DD)')\n .option('--to <date>', 'Filter to date (YYYY-MM-DD)')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const client = createServiceClient('solar', global);\n const body: Record<string, unknown> = {\n limit: parseInt(opts.limit),\n offset: parseInt(opts.offset),\n };\n if (opts.state) body.state = opts.state;\n if (opts.clientName) body.clientName = opts.clientName;\n if (opts.from) body.fromDate = opts.from;\n if (opts.to) body.toDate = opts.to;\n\n const res = await client.post('/solar-study/findWithPaginationAndFilters', body);\n // Response: [items[], totalCount, ...] tuple or {data, total}\n let data: unknown[];\n let total: number;\n if (Array.isArray(res.data) && res.data.length >= 2 && Array.isArray(res.data[0]) && typeof res.data[1] === 'number') {\n data = res.data[0];\n total = res.data[1];\n } else if (Array.isArray(res.data)) {\n data = res.data;\n total = res.data.length;\n } else {\n data = res.data?.data || res.data?.solarStudiesMetadata || [];\n total = res.data?.total ?? res.data?.count ?? (Array.isArray(data) ? data.length : 0);\n }\n\n const outOpts: OutputOptions = { ...global };\n if (!global.fields) {\n outOpts.fields = 'idSolarStudyMetadata,solarStudyId,clientName,peakPower,anualProduction,anualConsumption,totalCost,sellingPrice,currentState,creationTimestamp';\n }\n outputPaginated(data, total, parseInt(opts.limit), parseInt(opts.offset), outOpts);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- metadata ---\n studies\n .command('metadata <id>')\n .description('Get solar study metadata by metadata ID (relational). Full MySQL record with state, costs, versions.')\n .option('--by-study-id', 'Interpret <id> as MongoDB solarStudyId instead of metadata ID')\n .action(async (id, opts) => {\n try {\n // --by-study-id resolves against the MongoDB solarStudyId, so guard it\n // the same way as `get`; the default path uses a numeric metadata id.\n if (opts.byStudyId) assertStudyObjectId(id);\n const global = getGlobalOpts(studies);\n const client = createServiceClient('solar', global);\n const path = opts.byStudyId\n ? `/solar-study/metadata/solar-study-id/${id}`\n : `/solar-study/findSolarStudyMetadataById/${id}`;\n const res = await client.get(path);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- get ---\n studies\n .command('get <studyId>')\n .description(\n 'Get solar study by MongoDB ID. By default returns summary (no heavy curves).\\n' +\n 'Expand sections: surfaces, results, economics, batteries, consumption, equipment, client, location\\n' +\n 'Examples:\\n' +\n ' suntropy studies get abc123\\n' +\n ' suntropy studies get abc123 --expand surfaces,results\\n' +\n ' suntropy studies get abc123 --expand all\\n' +\n ' suntropy studies get abc123 --fields name,market (bypasses expand filter)'\n )\n .option('--expand <sections>', 'Comma-separated sections to expand (or \"all\")')\n .action(async (studyId, opts) => {\n try {\n assertStudyObjectId(studyId);\n const global = getGlobalOpts(studies);\n const client = createServiceClient('solar', global);\n const res = await client.get(`/solar-study/findById/${studyId}`);\n const study = assertFound(res.data, 'Solar study', studyId) as Record<string, unknown>;\n // If the user passes --fields, they have already expressed exactly what\n // they want — don't pre-filter the study, let output() select from the\n // full object. Otherwise apply the expand-based summary filter.\n const filtered = global.fields ? study : filterStudy(study, opts.expand);\n\n if (global.fields) {\n const requested = global.fields.split(',').map(f => f.trim());\n const topLevel = requested.map(f => f.split('.')[0]);\n const missing = topLevel.filter(f => !(f in study));\n if (missing.length > 0) {\n explainMissingStudyFields(missing, studyId);\n }\n }\n\n output(filtered, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- curves ---\n studies\n .command('curves <studyId> <curveName>')\n .description(\n 'Extract and analyze a PowerCurve from a study.\\n' +\n 'Curve names: consumption, production, net-consumption, excesses\\n' +\n 'Default: --stats. Use --raw for full hourly data (8760 values).\\n' +\n 'Use --monthly for monthly aggregates, --daily for daily totals.'\n )\n .option('--stats', 'Show statistics (default if no other flag)')\n .option('--monthly', 'Monthly accumulated values')\n .option('--daily', 'Daily accumulated values')\n .option('--raw', 'Full hourly DayCurve[] data')\n .option('--total', 'Just the total accumulated value')\n .option('--surface-index <n>', 'Surface index for production curve', '0')\n .option('--save <file>', 'Save curve data to file')\n .action(async (studyId, curveName, opts) => {\n try {\n assertStudyObjectId(studyId);\n const global = getGlobalOpts(studies);\n const client = createServiceClient('solar', global);\n const res = await client.get(`/solar-study/findById/${studyId}`);\n const study = assertFound(res.data, 'Solar study', studyId) as Record<string, unknown>;\n\n // Extract the requested curve\n let curveData: unknown;\n switch (curveName) {\n case 'consumption':\n curveData = study.consumption;\n break;\n case 'production': {\n const surfaces = study.surfaces as any[];\n const idx = parseInt(opts.surfaceIndex);\n if (surfaces && surfaces[idx]?.production) {\n curveData = surfaces[idx].production;\n } else {\n outputError(new Error(`No production curve at surface index ${idx}. Study has ${surfaces?.length || 0} surfaces.`));\n return;\n }\n break;\n }\n case 'net-consumption':\n curveData = (study.results as any)?.netConsumption;\n break;\n case 'excesses':\n curveData = (study.results as any)?.excessesCurve;\n break;\n default:\n outputError(new Error(`Unknown curve: ${curveName}. Available: consumption, production, net-consumption, excesses`));\n return;\n }\n\n if (!curveData) {\n outputError(new Error(`Curve \"${curveName}\" not found or empty in this study.`));\n return;\n }\n\n // Import PowerCurve from energy-types\n const { PowerCurve } = await import('energy-types/lib/energy/classes/powerCurve.class.js');\n const cd = curveData as any;\n const pc = new PowerCurve(cd.days || cd, cd.ignore0 ?? false, cd.identifier || curveName, cd.parseDate ?? false);\n\n // Determine output mode\n const showRaw = opts.raw;\n const showMonthly = opts.monthly;\n const showDaily = opts.daily;\n const showTotal = opts.total;\n const showStats = opts.stats || (!showRaw && !showMonthly && !showDaily && !showTotal);\n\n let result: unknown;\n\n if (showRaw) {\n result = pc.days;\n } else if (showTotal) {\n result = { total: pc.getTotalAcumulate(), identifier: curveName, days: pc.days.length };\n } else if (showStats) {\n const raw = pc.calculateStatistics();\n result = raw.statistics || raw;\n } else if (showMonthly) {\n const raw = pc.calculateStatistics();\n const s = raw.statistics || raw;\n result = { anualMonthAccumulate: s.anualMonthAccumulate, anualMonthCount: s.anualMonthCount, anualMonthlyAverage: s.anualMonthlyAverage };\n } else if (showDaily) {\n const raw = pc.calculateStatistics();\n const s = raw.statistics || raw;\n result = { dailyAccumulate: s.dailyAccumulate };\n }\n\n const outOpts = { ...global, save: opts.save || global.save };\n output(result, outOpts);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- calculate-production ---\n studies\n .command('calculate-production')\n .description('Calculate solar production curve for given coordinates and configuration')\n .requiredOption('--lat <n>', 'Latitude')\n .requiredOption('--lon <n>', 'Longitude')\n .requiredOption('--power <w>', 'Installed power in Watts')\n .option('--angle <n>', 'Panel inclination degrees', '30')\n .option('--azimuth <n>', 'Panel orientation degrees (0=north, 180=south)', '180')\n .option('--losses <n>', 'Losses percentage', '14')\n .option('--year <n>', 'Year for calculation', String(new Date().getFullYear()))\n .option('--save <file>', 'Save result to file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const client = createServiceClient('solar', global);\n const body = {\n lat: parseFloat(opts.lat),\n long: parseFloat(opts.lon),\n instaledPower: parseFloat(opts.power),\n angle: parseFloat(opts.angle),\n azimuth: parseFloat(opts.azimuth),\n lossesPercentage: parseFloat(opts.losses),\n year: parseInt(opts.year),\n isOptimized: false,\n };\n const res = await client.post('/solar-study/calculateProduction', body);\n output(res.data, { ...global, save: opts.save || global.save });\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- optimize-surfaces ---\n studies\n .command('optimize-surfaces')\n .description('Calculate optimal panel angle and azimuth for coordinates')\n .requiredOption('--lat <n>', 'Latitude')\n .requiredOption('--lon <n>', 'Longitude')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const client = createServiceClient('solar', global);\n const res = await client.get('/solar-study/optimizeSurfaces', {\n params: { lat: parseFloat(opts.lat), lon: parseFloat(opts.lon) },\n });\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // Register study builder commands (init, validate, save, pull, set, add, remove, calculate)\n registerStudyBuilderCommands(studies);\n}\n","import { Command } from 'commander';\nimport { readFileSync } from 'fs';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\n/** Read all stdin as a promise */\nfunction readStdin(): Promise<string> {\n return new Promise((resolve, reject) => {\n let data = '';\n process.stdin.setEncoding('utf-8');\n process.stdin.on('data', (chunk) => { data += chunk; });\n process.stdin.on('end', () => resolve(data));\n process.stdin.on('error', reject);\n });\n}\n\n/** Read curve data from file, stdin, or --input flag */\nasync function readCurveInput(inputPath?: string): Promise<any> {\n let raw: string;\n if (inputPath && inputPath !== '-') {\n raw = readFileSync(inputPath, 'utf-8');\n } else {\n raw = await readStdin();\n }\n return JSON.parse(raw);\n}\n\n/** Build a PowerCurve from parsed JSON data */\nasync function buildCurve(data: any, identifier = 'curve') {\n const { PowerCurve } = await import('energy-types/lib/energy/classes/powerCurve.class.js');\n // Data might be: { days: [...], identifier } or just a DayCurve[]\n if (Array.isArray(data)) {\n return new PowerCurve(data, false, identifier, false);\n }\n return new PowerCurve(data.days || data, data.ignore0 ?? false, data.identifier || identifier, data.parseDate ?? false);\n}\n\n/** Serialize PowerCurve back to JSON-friendly format */\nfunction serializeCurve(pc: any): any {\n return { days: pc.days, identifier: pc.identifier, ignore0: pc.ignore0 };\n}\n\nexport function registerCurvesCommands(program: Command): void {\n const curves = program.command('curves').description(\n 'PowerCurve operations (pipe-friendly). Accept input via --input <file> or stdin.\\n' +\n 'Curve-returning commands output serialized PowerCurve JSON for chaining.\\n' +\n 'Use --save <file> to persist and still output to stdout.'\n );\n\n // --- stats ---\n curves\n .command('stats')\n .description('Calculate comprehensive statistics: monthly/daily/hourly averages, max, min, period aggregation')\n .option('--input <file>', 'Input file (or - for stdin)')\n .action(async (opts) => {\n try {\n const data = await readCurveInput(opts.input);\n const pc = await buildCurve(data, 'stats');\n const raw = pc.calculateStatistics();\n output(raw.statistics || raw, getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- total ---\n curves\n .command('total')\n .description('Calculate total accumulated value across all hours')\n .option('--input <file>', 'Input file (or - for stdin)')\n .action(async (opts) => {\n try {\n const data = await readCurveInput(opts.input);\n const pc = await buildCurve(data, 'total');\n output({ total: pc.getTotalAcumulate(), days: pc.days.length }, getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- multiply ---\n curves\n .command('multiply <factor>')\n .description('Multiply all hourly values by a factor. Returns a new PowerCurve.')\n .option('--input <file>', 'Input file (or - for stdin)')\n .action(async (factor, opts) => {\n try {\n const data = await readCurveInput(opts.input);\n const pc = await buildCurve(data, 'multiplied');\n const result = pc.applyMultiplier(parseFloat(factor));\n output(serializeCurve(result), getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- aggregate ---\n curves\n .command('aggregate')\n .description('Sum two PowerCurves (A + B). Returns a new PowerCurve.')\n .requiredOption('--a <file>', 'First curve file')\n .requiredOption('--b <file>', 'Second curve file')\n .action(async (opts) => {\n try {\n const dataA = JSON.parse(readFileSync(opts.a, 'utf-8'));\n const dataB = JSON.parse(readFileSync(opts.b, 'utf-8'));\n const pcA = await buildCurve(dataA, 'a');\n const pcB = await buildCurve(dataB, 'b');\n const result = pcA.aggregatePowerCurve(pcB);\n output(serializeCurve(result), getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- subtract ---\n curves\n .command('subtract')\n .description('Subtract two PowerCurves (A - B). Returns a new PowerCurve.')\n .requiredOption('--a <file>', 'First curve file (minuend)')\n .requiredOption('--b <file>', 'Second curve file (subtrahend)')\n .action(async (opts) => {\n try {\n const dataA = JSON.parse(readFileSync(opts.a, 'utf-8'));\n const dataB = JSON.parse(readFileSync(opts.b, 'utf-8'));\n const pcA = await buildCurve(dataA, 'a');\n const pcB = await buildCurve(dataB, 'b');\n const negB = pcB.applyMultiplier(-1);\n const result = pcA.aggregatePowerCurve(negB);\n output(serializeCurve(result), getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- filter-positive ---\n curves\n .command('filter-positive')\n .description('Keep only non-negative hourly values (zero out negatives). Returns a new PowerCurve.')\n .option('--input <file>', 'Input file (or - for stdin)')\n .action(async (opts) => {\n try {\n const data = await readCurveInput(opts.input);\n const pc = await buildCurve(data, 'positive');\n const result = pc.filterNegativeValues(); // filterNegativeValues returns curve with negatives zeroed\n output(serializeCurve(result), getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- filter-negative ---\n curves\n .command('filter-negative')\n .description('Keep only non-positive hourly values (zero out positives). Returns a new PowerCurve.')\n .option('--input <file>', 'Input file (or - for stdin)')\n .action(async (opts) => {\n try {\n const data = await readCurveInput(opts.input);\n const pc = await buildCurve(data, 'negative');\n const result = pc.filterPositiveValues(); // filterPositiveValues returns curve with positives zeroed\n output(serializeCurve(result), getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- sort ---\n curves\n .command('sort')\n .description('Sort curve days by date ascending. Returns a new PowerCurve.')\n .option('--input <file>', 'Input file (or - for stdin)')\n .action(async (opts) => {\n try {\n const data = await readCurveInput(opts.input);\n const pc = await buildCurve(data, 'sorted');\n const sortedDays = pc.sortByDate();\n output({ days: sortedDays, identifier: pc.identifier, ignore0: pc.ignore0 }, getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- filter-dates ---\n curves\n .command('filter-dates')\n .description('Filter curve to a date range. Returns a new PowerCurve.')\n .option('--input <file>', 'Input file (or - for stdin)')\n .option('--start <date>', 'Start date (YYYY-MM-DD)')\n .option('--end <date>', 'End date (YYYY-MM-DD)')\n .action(async (opts) => {\n try {\n const data = await readCurveInput(opts.input);\n const pc = await buildCurve(data, 'filtered');\n const start = opts.start ? new Date(opts.start) : undefined;\n const end = opts.end ? new Date(opts.end) : undefined;\n const filteredDays = pc.filterByDates(start, end);\n output({ days: filteredDays, identifier: pc.identifier, ignore0: pc.ignore0 }, getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- to-serie ---\n curves\n .command('to-serie')\n .description('Convert curve to chart-ready series format (x/y arrays)')\n .option('--input <file>', 'Input file (or - for stdin)')\n .action(async (opts) => {\n try {\n const data = await readCurveInput(opts.input);\n const pc = await buildCurve(data, 'serie');\n const serie = pc.convertoToSerie();\n output(serie, getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- by-period ---\n curves\n .command('by-period')\n .description(\n 'Aggregate a PowerCurve by tariff periods (P1-P6) using a period distribution.\\n' +\n 'Returns { p1, p2, p3, p4, p5, p6 } with accumulated kWh per period.\\n\\n' +\n 'The period distribution maps each hour of each day to a tariff period.\\n' +\n 'Get it with: suntropy consumption periods --save /tmp/periods.json\\n\\n' +\n 'Examples:\\n' +\n ' suntropy curves by-period --input /tmp/production.json --periods /tmp/periods.json\\n' +\n ' suntropy curves by-period --input /tmp/consumption.json --periods /tmp/periods.json'\n )\n .requiredOption('--periods <file>', 'Period distribution file (DayCurve[] from consumption periods)')\n .option('--input <file>', 'Input PowerCurve file (or stdin)')\n .action(async (opts) => {\n try {\n const data = await readCurveInput(opts.input);\n const pc = await buildCurve(data, 'by-period');\n const periodsData = JSON.parse(readFileSync(opts.periods, 'utf-8'));\n const result = pc.aggregateByPeriod(periodsData);\n output(result, getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n}\n","import { Command } from 'commander';\nimport { readFileSync } from 'fs';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\nexport function registerConsumptionCommands(program: Command): void {\n const consumption = program.command('consumption').description(\n 'Generate consumption curves using the profiles service.\\n' +\n 'Supports multiple estimation methods: standard patterns, custom profiles, monthly data.\\n' +\n 'Returns PowerCurve JSON compatible with `suntropy curves` for further processing.'\n );\n\n // --- estimate ---\n consumption\n .command('estimate')\n .description(\n 'Generate a consumption PowerCurve from patterns and annual consumption.\\n' +\n 'Patterns: Balance, Nightly, Morning, Afternoon, Domestic, Commercial\\n' +\n 'Examples:\\n' +\n ' suntropy consumption estimate --annual 5000 --pattern Balance\\n' +\n ' suntropy consumption estimate --annual 8000 --pattern Domestic --tariff 3.0TD --market es\\n' +\n ' suntropy consumption estimate --annual 3500 --monthly-data \\'{\"1\":300,\"2\":280,...}\\'\\n' +\n ' suntropy consumption estimate --annual 5000 --custom-profile-id abc123'\n )\n .requiredOption('--annual <kWh>', 'Annual consumption in kWh')\n .option('--pattern <name>', 'Consumption pattern: Balance, Nightly, Morning, Afternoon, Domestic, Commercial')\n .option('--start-date <YYYY-MM-DD>', 'Start date (default: Jan 1 current year)')\n .option('--end-date <YYYY-MM-DD>', 'End date (default: Dec 31 current year)')\n .option('--tariff <code>', 'Electricity tariff code (e.g. 3.0TD)', '3.0TD')\n .option('--type <type>', 'Profile type: Initial or Final', 'Final')\n .option('--market <code>', 'Market: es, pt, it', 'es')\n .option('--custom-profile-id <id>', 'Use a custom consumption profile by ID')\n .option('--monthly-data <json>', 'Monthly consumption JSON: {\"1\":val,\"2\":val,...,\"12\":val}')\n .option('--daily-curve <json>', 'Custom daily curve JSON (DayCurve format)')\n .option('--save <file>', 'Save result to file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(consumption);\n const client = createServiceClient('profiles', global);\n\n const year = new Date().getFullYear();\n const startDate = opts.startDate || `${year}-01-01`;\n const endDate = opts.endDate || `${year}-12-31`;\n\n // Build query params\n const params: Record<string, string> = {\n startDate,\n endDate,\n tariff: opts.tariff,\n type: opts.type,\n anualConsumption: opts.annual,\n market: opts.market,\n };\n\n if (opts.pattern) params.consumptionType = opts.pattern;\n if (opts.customProfileId) params.customProfileId = opts.customProfileId;\n\n // Build optional body\n let body: Record<string, unknown> | undefined;\n if (opts.monthlyData || opts.dailyCurve) {\n body = {};\n if (opts.monthlyData) body.consumptionByMonth = JSON.parse(opts.monthlyData);\n if (opts.dailyCurve) body.dailyCurve = JSON.parse(opts.dailyCurve);\n }\n\n const queryString = Object.entries(params)\n .map(([k, v]) => `${k}=${encodeURIComponent(v)}`)\n .join('&');\n\n const res = await client.post(`/consumption-estimation?${queryString}`, body || {});\n output(res.data, { ...global, save: opts.save || global.save });\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- ree-profiles ---\n consumption\n .command('ree-profiles')\n .description(\n 'Fetch REE (Red Eléctrica) hourly profiles for a date range and tariff.\\n' +\n 'Returns the raw profile data used as basis for consumption estimation.\\n' +\n 'Example: suntropy consumption ree-profiles --start 2024-01-01 --end 2024-12-31 --tariff 3.0TD'\n )\n .requiredOption('--start <YYYY-MM-DD>', 'Start date')\n .requiredOption('--end <YYYY-MM-DD>', 'End date')\n .option('--tariff <code>', 'Tariff code', '3.0TD')\n .option('--type <type>', 'Profile type: Initial or Final', 'Final')\n .option('--market <code>', 'Market code: es, pt, it', 'es')\n .option('--save <file>', 'Save result to file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(consumption);\n const client = createServiceClient('profiles', global);\n const res = await client.get('/ree-profiles', {\n params: {\n startDate: opts.start,\n endDate: opts.end,\n tariff: opts.tariff,\n type: opts.type,\n market: opts.market,\n },\n });\n output(res.data, { ...global, save: opts.save || global.save });\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- custom-tags ---\n consumption\n .command('custom-tags')\n .description('List available custom consumption profile tags for the authenticated client')\n .action(async () => {\n try {\n const global = getGlobalOpts(consumption);\n const client = createServiceClient('profiles', global);\n const res = await client.get('/custom-profiles/getTags');\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- custom-profile-info ---\n consumption\n .command('custom-profile-info')\n .description('Get details of a custom consumption profile by ID')\n .requiredOption('--id <profileId>', 'Custom profile ID')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(consumption);\n const client = createServiceClient('profiles', global);\n const res = await client.get('/custom-profiles/getInfo', {\n params: { id: opts.id },\n });\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- periods ---\n consumption\n .command('periods')\n .description(\n 'Fetch period distribution (hour→P1-P6 mapping) from the periods service.\\n' +\n 'Returns DayCurve[] where each hour\\'s value is the period number (1-6).\\n' +\n 'Use with `suntropy curves by-period` to aggregate any curve by tariff period.\\n\\n' +\n 'Common tariff IDs (Spain): 13=2.0TD, 14=3.0TD\\n' +\n 'Zone IDs (Spain): 1=Peninsula, 2=Canarias, 3=Baleares\\n\\n' +\n 'Examples:\\n' +\n ' suntropy consumption periods --tariff-id 14 --zone-id 1 --save /tmp/periods.json\\n' +\n ' suntropy consumption periods --tariff-id 13 --start 2025-01-01 --end 2025-12-31'\n )\n .option('--tariff-id <n>', 'ATR tariff ID (13=2.0TD, 14=3.0TD)', '14')\n .option('--zone-id <n>', 'Geographical zone ID (1=Peninsula)', '1')\n .option('--start <YYYY-MM-DD>', 'Start date (default: Jan 1 current year)')\n .option('--end <YYYY-MM-DD>', 'End date (default: Dec 31 current year)')\n .option('--market <code>', 'Market: es, pt, it, fr', 'es')\n .option('--save <file>', 'Save result to file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(consumption);\n const client = createServiceClient('periods', global);\n const year = new Date().getFullYear();\n const res = await client.get('/periodos', {\n params: {\n idTarifa: parseInt(opts.tariffId),\n idZona: parseInt(opts.zoneId),\n fechaInicio: opts.start || `${year}-01-01`,\n fechaFin: opts.end || `${year}-12-31`,\n market: opts.market,\n },\n });\n output(res.data, { ...global, save: opts.save || global.save });\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- from-file ---\n consumption\n .command('from-file')\n .description(\n 'Generate consumption curve from an uploaded file.\\n' +\n 'Supported formats: Portuguese EREDES ZIP files.\\n' +\n 'Example: suntropy consumption from-file --eredes-zip /path/to/file.zip'\n )\n .option('--eredes-zip <path>', 'Path to Portuguese EREDES ZIP file')\n .option('--save <file>', 'Save result to file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(consumption);\n const client = createServiceClient('profiles', global);\n\n if (opts.eredesZip) {\n const FormData = (await import('form-data')).default;\n const form = new FormData();\n form.append('file', readFileSync(opts.eredesZip), {\n filename: opts.eredesZip.split('/').pop(),\n contentType: 'application/zip',\n });\n const res = await client.post('/consumption-files-processor/portugal/eredes-zip', form, {\n headers: form.getHeaders(),\n });\n output(res.data, { ...global, save: opts.save || global.save });\n } else {\n outputError(new Error('Specify a file format: --eredes-zip <path>'));\n }\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import { Command } from 'commander';\nimport { readFileSync } from 'fs';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\n/** Read all stdin as a promise */\nfunction readStdin(): Promise<string> {\n return new Promise((resolve, reject) => {\n let data = '';\n process.stdin.setEncoding('utf-8');\n process.stdin.on('data', (chunk) => { data += chunk; });\n process.stdin.on('end', () => resolve(data));\n process.stdin.on('error', reject);\n });\n}\n\n/** Read JSON data from --data flag or stdin */\nasync function parseData(data: string | undefined): Promise<Record<string, unknown> | undefined> {\n if (!data) return undefined;\n if (data === '-') {\n const input = await readStdin();\n return JSON.parse(input);\n }\n return JSON.parse(data);\n}\n\n/** Unwrap PublicApiResponse: { code, data, error } → data or throw */\nfunction unwrapPublicApiResponse(resData: unknown): unknown {\n if (resData && typeof resData === 'object' && !Array.isArray(resData)) {\n const r = resData as Record<string, unknown>;\n // Detect PublicApiResponse shape: has 'code' field (number)\n if ('code' in r && typeof r.code === 'number') {\n // Prefer data if present (API may return both error and data)\n if (r.data !== undefined) return r.data;\n // No data — check for error\n if (r.error) {\n const err = r.error as Record<string, unknown>;\n throw new Error(`API error (${err.code || r.code}): ${err.message || JSON.stringify(err)}`);\n }\n // code present but no data and no error — return as-is\n return resData;\n }\n }\n return resData;\n}\n\n/** Compact study output: replace heavy PowerCurve objects with summaries */\nfunction compactStudyOutput(study: unknown): unknown {\n if (study === null || study === undefined || typeof study !== 'object') return study;\n if (Array.isArray(study)) return study.map(compactStudyOutput);\n\n const record = study as Record<string, unknown>;\n\n // Detect PowerCurve: has 'days' array with objects and identifier\n if (Array.isArray(record.days) && record.days.length > 0 && record.identifier !== undefined) {\n return { _type: 'PowerCurve', days: record.days.length, identifier: record.identifier };\n }\n\n const result: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(record)) {\n if (val && typeof val === 'object' && !Array.isArray(val)) {\n const v = val as Record<string, unknown>;\n if (Array.isArray(v.days) && v.days.length > 0 && v.identifier !== undefined) {\n result[key] = { _type: 'PowerCurve', days: v.days.length, identifier: v.identifier };\n continue;\n }\n }\n result[key] = compactStudyOutput(val);\n }\n return result;\n}\n\nexport function registerSolarformCommands(program: Command): void {\n const solarform = program.command('solarform').description(\n 'Create solar studies via the Solar Form API.\\n' +\n 'Two modes: \"simple\" (minimal params, auto-optimized) and \"calculate\" (full control).\\n' +\n 'Use --save flag to persist the study to the database.'\n );\n\n // --- simple ---\n solarform\n .command('simple')\n .description(\n 'Create a solar study with minimal parameters (simplified mode).\\n' +\n 'Automatically resolves location from region/subregion, applies consumption patterns,\\n' +\n 'and optimizes kit selection.\\n\\n' +\n 'Consumption patterns: Balance, Nightly, Morning, Afternoon, Domestic, Commercial\\n' +\n 'Consumption mode: monthlyConsumption (kWh) or monthlySpending (EUR)\\n' +\n 'Excesses modes: PPA, gridSelling, noInjection, virtualBattery\\n\\n' +\n 'Examples:\\n' +\n ' suntropy solarform simple --region \"Andalucía\" --sub-region \"Sevilla\" --consumption 5000\\n' +\n ' suntropy solarform simple --region \"Cataluña\" --sub-region \"Barcelona\" --consumption 300 --consumption-mode monthlySpending --save\\n' +\n ' suntropy solarform simple --region \"Madrid\" --sub-region \"Madrid\" --consumption 8000 --pattern Domestic --kit-id abc123 --save'\n )\n .requiredOption('--region <name>', 'Region name (must exist in database)')\n .requiredOption('--sub-region <name>', 'Sub-region name')\n .requiredOption('--consumption <value>', 'Consumption value (kWh or EUR depending on --consumption-mode)')\n .option('--pattern <name>', 'Consumption pattern: Balance, Nightly, Morning, Afternoon, Domestic, Commercial', 'Balance')\n .option('--consumption-mode <mode>', 'monthlyConsumption (kWh) or monthlySpending (EUR)', 'monthlyConsumption')\n .option('--kit-id <id>', 'Use a specific solar kit instead of auto-optimization')\n .option('--excesses-mode <mode>', 'Excesses compensation: PPA, gridSelling, noInjection, virtualBattery')\n .option('--assigned-user <uid>', 'Assign study to a user UID')\n .option('--email <email>', 'Send results to this email')\n .option('--save', 'Save study to database')\n .option('--raw', 'Return full study with PowerCurve data (no compaction)')\n .option('--save-file <file>', 'Save result to local file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(solarform);\n const client = createServiceClient('solar', global);\n\n const body: Record<string, unknown> = {\n region: opts.region,\n subRegion: opts.subRegion,\n selectedConsumptionPattern: opts.pattern,\n consumptionQuantity: parseFloat(opts.consumption),\n consumptionQuantityIntroductionMode: opts.consumptionMode,\n };\n\n if (opts.assignedUser) body.assignedUserUID = opts.assignedUser;\n\n // Build query params\n const params: Record<string, string> = {};\n if (opts.save) params.save = 'true';\n if (opts.email) params.email = opts.email;\n if (opts.kitId) params.solarKitId = opts.kitId;\n if (opts.excessesMode) params.excessesCompensationMode = opts.excessesMode;\n\n const queryString = Object.entries(params)\n .map(([k, v]) => `${k}=${encodeURIComponent(v)}`)\n .join('&');\n\n const url = `/api/solar-form/simple${queryString ? '?' + queryString : ''}`;\n const res = await client.post(url, body);\n\n const study = unwrapPublicApiResponse(res.data);\n const result = opts.raw ? study : compactStudyOutput(study);\n output(result, { ...global, save: opts.saveFile || global.save });\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- calculate ---\n solarform\n .command('calculate')\n .description(\n 'Create a solar study with full control over all parameters.\\n' +\n 'Pass the complete SimplifiedSolarStudy body as JSON.\\n\\n' +\n 'Required body fields:\\n' +\n ' center: { lat, lng } — Installation coordinates\\n' +\n ' surfaces: [{ path, inclination, orientation }] — Panel surfaces\\n' +\n ' consumptionMode: \"cups\" | \"consumptionPatterns\"\\n' +\n ' clientDetails: { name, email, phone }\\n\\n' +\n 'Optional: atrTariff, geographicalZone, location, contractedPower,\\n' +\n ' monthPeriodConsumptionDictionary, selectedConsumptionPattern,\\n' +\n ' consumptionQuantity, consumptionQuantityIntroductionMode\\n\\n' +\n 'Examples:\\n' +\n ' suntropy solarform calculate --data \\'{\"center\":{\"lat\":37.39,\"lng\":-5.99},...}\\' --save\\n' +\n ' cat study-input.json | suntropy solarform calculate --data - --save --email client@co.com'\n )\n .requiredOption('--data <json>', 'Full SimplifiedSolarStudy JSON body (or - for stdin)')\n .option('--save', 'Save study to database')\n .option('--email <email>', 'Send results to this email')\n .option('--raw', 'Return full study with PowerCurve data (no compaction)')\n .option('--save-file <file>', 'Save result to local file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(solarform);\n const client = createServiceClient('solar', global);\n\n const body = await parseData(opts.data);\n if (!body) {\n outputError(new Error('--data is required. Pass JSON or - for stdin.'));\n return;\n }\n\n const params: Record<string, string> = {};\n if (opts.save) params.save = 'true';\n if (opts.email) params.email = opts.email;\n\n const queryString = Object.entries(params)\n .map(([k, v]) => `${k}=${encodeURIComponent(v)}`)\n .join('&');\n\n const url = `/api/solar-form${queryString ? '?' + queryString : ''}`;\n const res = await client.post(url, body);\n\n const study = unwrapPublicApiResponse(res.data);\n if (!study || (typeof study === 'object' && !Array.isArray(study) && !('selectedSolarStudyMode' in (study as Record<string, unknown>)))) {\n outputError(new Error('API returned no study data. The /api/solar-form endpoint requires a complete body with: center, surfaces, consumptionMode, and typically locationMode. Use \"solarform simple\" for minimal-parameter study creation.'));\n return;\n }\n const result = opts.raw ? study : compactStudyOutput(study);\n output(result, { ...global, save: opts.saveFile || global.save });\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- config ---\n solarform\n .command('config')\n .description(\n 'Get the solar form configuration for the authenticated client.\\n' +\n 'Returns form settings, appearance, enabled steps, custom fields, etc.'\n )\n .action(async () => {\n try {\n const global = getGlobalOpts(solarform);\n const client = createServiceClient('solar', global);\n const res = await client.get('/solar-form/solar-form-config');\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- statistics ---\n solarform\n .command('statistics')\n .description(\n 'List or create solar form submission statistics.\\n' +\n 'Used for tracking form analytics and conversion data.'\n )\n .option('--create', 'Create a new statistics entry')\n .option('--update', 'Update an existing statistics entry')\n .option('--data <json>', 'Statistics data as JSON')\n .option('--stats-id <id>', 'Statistics ID (for update or linking)')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(solarform);\n const client = createServiceClient('solar', global);\n\n if (opts.update) {\n const body = await parseData(opts.data);\n const res = await client.put('/solar-form/solar-form-statistics', body);\n output(res.data, global);\n } else if (opts.create) {\n const body = (await parseData(opts.data)) || {};\n const params: Record<string, string> = {};\n if (opts.statsId) params.statsId = opts.statsId;\n const res = await client.post('/solar-form/solar-form-statistics', body, { params });\n output(res.data, global);\n } else {\n outputError(new Error('Specify --create or --update'));\n }\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import { Command } from 'commander';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\n/** Read all stdin as a promise */\nfunction readStdin(): Promise<string> {\n return new Promise((resolve, reject) => {\n let data = '';\n process.stdin.setEncoding('utf-8');\n process.stdin.on('data', (chunk) => { data += chunk; });\n process.stdin.on('end', () => resolve(data));\n process.stdin.on('error', reject);\n });\n}\n\n/** Read JSON data from --data flag or stdin */\nasync function parseData(data: string | undefined): Promise<Record<string, unknown> | undefined> {\n if (!data) return undefined;\n if (data === '-') {\n const input = await readStdin();\n return JSON.parse(input);\n }\n return JSON.parse(data);\n}\n\n/** Compact study output: replace heavy PowerCurve objects with summaries */\nfunction compactStudyOutput(study: unknown): unknown {\n if (study === null || study === undefined || typeof study !== 'object') return study;\n if (Array.isArray(study)) return study.map(compactStudyOutput);\n\n const record = study as Record<string, unknown>;\n\n // Detect PowerCurve: has 'days' array with objects and identifier\n if (Array.isArray(record.days) && record.days.length > 0 && record.identifier !== undefined) {\n return { _type: 'PowerCurve', days: record.days.length, identifier: record.identifier };\n }\n\n const result: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(record)) {\n if (val && typeof val === 'object' && !Array.isArray(val)) {\n const v = val as Record<string, unknown>;\n if (Array.isArray(v.days) && v.days.length > 0 && v.identifier !== undefined) {\n result[key] = { _type: 'PowerCurve', days: v.days.length, identifier: v.identifier };\n continue;\n }\n }\n result[key] = compactStudyOutput(val);\n }\n return result;\n}\n\nexport function registerPPACommands(program: Command): void {\n const ppa = program.command('ppa').description(\n 'PPA (Power Purchase Agreement) analysis.\\n' +\n 'Read PPA templates and run PPA simulations on a solar study.'\n );\n\n // --- ppa templates (read-only sub-group) ---\n const templates = ppa\n .command('templates')\n .description('Read-only access to the client PPA templates.');\n\n templates\n .command('list')\n .description(\n 'List all PPA templates for the authenticated client.\\n' +\n 'Example:\\n' +\n ' suntropy ppa templates list --fields _id,name,mode,ppaPrice,useInSolarForm'\n )\n .action(async () => {\n try {\n const global = getGlobalOpts(ppa);\n const client = createServiceClient('solar', global);\n const res = await client.get('/solar-study/ppa-templates');\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n templates\n .command('get <id>')\n .description(\n 'Get a single PPA template by its Mongo _id.\\n' +\n 'Example:\\n' +\n ' suntropy ppa templates get 665f0a1b2c3d4e5f60718293'\n )\n .action(async (id: string) => {\n try {\n const global = getGlobalOpts(ppa);\n const client = createServiceClient('solar', global);\n const res = await client.get(`/solar-study/ppa-templates/${id}`);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- ppa calculate ---\n ppa\n .command('calculate')\n .description(\n 'Run PPA simulations on a solar study (read-only, does not persist).\\n\\n' +\n 'Provide the study via --study <id> (downloaded from the API) or --data <json>|- (full SolarStudy).\\n' +\n 'With --template <ppaTemplateId> the simulation uses that single PPA template;\\n' +\n 'without it, the backend uses the client templates flagged useInSolarForm.\\n\\n' +\n 'Note: the study must include consumption and economicResults (a study fetched\\n' +\n 'by --study already does). The response is the study with economicResults.ppaAnalysis populated.\\n\\n' +\n 'Examples:\\n' +\n ' suntropy ppa calculate --study 665f0a1b2c3d4e5f60718293\\n' +\n ' suntropy ppa calculate --study 665f... --template 6700aa11bb22cc33dd44ee55\\n' +\n ' cat study.json | suntropy ppa calculate --data -'\n )\n .option('--study <id>', 'Solar study Mongo id to download and analyze')\n .option('--data <json>', 'Full SolarStudy JSON body (or - for stdin)')\n .option('--template <ppaTemplateId>', 'PPA template id to apply (defaults to client useInSolarForm templates)')\n .option('--raw', 'Return full study with PowerCurve data (no compaction)')\n .option('--save-file <file>', 'Save result to local file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(ppa);\n const client = createServiceClient('solar', global);\n\n let study: unknown;\n if (opts.study) {\n const res = await client.get(`/solar-study/findById/${opts.study}`);\n study = res.data;\n } else if (opts.data) {\n study = await parseData(opts.data);\n } else {\n outputError(new Error('Provide --study <id> or --data <json>|- (full SolarStudy).'));\n return;\n }\n\n const body: Record<string, unknown> = { data: study };\n if (opts.template) body.ppaTemplateId = opts.template;\n\n const res = await client.post('/solar-study/calculate-ppa-on-study', body);\n const result = opts.raw ? res.data : compactStudyOutput(res.data);\n output(result, { ...global, save: opts.saveFile || global.save });\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import { Command } from 'commander';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\n/** Read all stdin as a promise */\nfunction readStdin(): Promise<string> {\n return new Promise((resolve, reject) => {\n let data = '';\n process.stdin.setEncoding('utf-8');\n process.stdin.on('data', (chunk) => { data += chunk; });\n process.stdin.on('end', () => resolve(data));\n process.stdin.on('error', reject);\n });\n}\n\n/** Read JSON data from --data flag or stdin */\nasync function parseData(data: string | undefined): Promise<Record<string, unknown> | undefined> {\n if (!data) return undefined;\n if (data === '-') {\n const input = await readStdin();\n return JSON.parse(input);\n }\n return JSON.parse(data);\n}\n\nexport function registerShareableCommands(program: Command): void {\n const shareables = program.command('shareables').description(\n 'Create shareable links for studies (sharing service, exposed under /templates).'\n );\n\n // --- create ---\n shareables\n .command('create')\n .description(\n 'Create a shareable link for a study (POST /shareable).\\n' +\n 'The backend fills uid, url, clientUID and idShareable from the token.\\n\\n' +\n 'elementType: solarStudy (default), colectiveSolarStudy, veChargerStudy, heatpumpStudy, billing\\n' +\n 'shareableType: TEMPLATE (default), CONTRACT\\n' +\n 'privacy: PUBLIC (default), PRIVATE (use --password)\\n\\n' +\n 'Examples:\\n' +\n ' suntropy shareables create --element-id 665f0a1b2c3d4e5f60718293\\n' +\n ' suntropy shareables create --element-id 665f... --template-id 6700aa... --name \"Estudio Juan\"\\n' +\n ' suntropy shareables create --element-id 665f... --privacy PRIVATE --password secret --email-list \"a@x.com;b@y.com\"\\n' +\n ' suntropy shareables create --element-id 665f... --expiration-date 2026-12-31 --link-params \"utm_source=cli\"'\n )\n .requiredOption('--element-id <id>', 'Id of the element (study) to share')\n .option('--element-type <type>', 'solarStudy | colectiveSolarStudy | veChargerStudy | heatpumpStudy | billing', 'solarStudy')\n .option('--shareable-type <type>', 'TEMPLATE | CONTRACT', 'TEMPLATE')\n .option('--privacy <privacy>', 'PUBLIC | PRIVATE', 'PUBLIC')\n .option('--template-id <id>', 'Template id to apply to the shareable')\n .option('--name <name>', 'Descriptive name for the shareable')\n .option('--password <pwd>', 'Protect the link with a password (implies PRIVATE)')\n .option('--expiration-date <date>', 'Expiration date (e.g. 2026-12-31)')\n .option('--activation-date <date>', 'Activation date (e.g. 2026-01-01)')\n .option('--email-list <emails>', 'Semicolon-separated list of recipient emails')\n .option('--reply-to <email>', 'Reply-to email for notifications')\n .option('--custom-layout', 'Enable custom layout')\n .option('--read-only', 'Mark the shareable as read-only')\n .option('--link-params <qs>', 'Extra query params appended to the shareable link (k=v&k2=v2)')\n .option('--data <json>', 'Extra ShareableDto fields as JSON (or - for stdin), merged last')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(shareables);\n const client = createServiceClient('templates', global);\n\n const extra = (await parseData(opts.data)) || {};\n const body: Record<string, unknown> = {\n elementId: opts.elementId,\n elementType: opts.elementType,\n shareableType: opts.shareableType,\n privacy: opts.password ? 'PRIVATE' : opts.privacy,\n ...(opts.templateId ? { templateId: opts.templateId } : {}),\n ...(opts.name ? { name: opts.name } : {}),\n ...(opts.password ? { password: opts.password, passwordConfirm: opts.password } : {}),\n ...(opts.expirationDate ? { expirationDate: opts.expirationDate } : {}),\n ...(opts.activationDate ? { activationDate: opts.activationDate } : {}),\n ...(opts.emailList ? { emailList: opts.emailList } : {}),\n ...(opts.replyTo ? { replyTo: opts.replyTo } : {}),\n ...(opts.customLayout ? { customLayout: true } : {}),\n ...(opts.readOnly ? { readOnly: true } : {}),\n ...extra,\n };\n\n const url = opts.linkParams ? `/shareable?${opts.linkParams}` : '/shareable';\n const res = await client.post(url, body);\n output(res.data, { ...global, save: global.save });\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import { Command } from 'commander';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\nexport function registerTemplatesCommands(program: Command): void {\n const templates = program.command('templates').description(\n 'Read client document templates (id + name), proxied via solar from the sharing service.'\n );\n\n // --- list ---\n templates\n .command('list')\n .description(\n 'List templates returning only _id and templateName (GET /api/templates).\\n' +\n 'Defaults to the solar study templates (--type solarStudy).\\n\\n' +\n 'Types: solarStudy (default) | colectiveSolarStudy | veChargerStudy.\\n' +\n 'Use --type generic for the generic (untyped) templates.\\n\\n' +\n 'Examples:\\n' +\n ' suntropy templates list\\n' +\n ' suntropy templates list --type colectiveSolarStudy\\n' +\n ' suntropy templates list --type generic --fields _id,templateName --format csv'\n )\n .option(\n '--type <identifier>',\n 'solarStudy (default) | colectiveSolarStudy | veChargerStudy | generic',\n 'solarStudy',\n )\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(templates);\n const client = createServiceClient('solar', global);\n\n const params: Record<string, string> = {};\n // 'generic' means the untyped templates -> omit the identifier so the\n // backend forwards no filter (sharing returns templateIdentifier: null).\n if (opts.type && opts.type !== 'generic') {\n params.templateIdentifier = opts.type;\n }\n\n const res = await client.get('/api/templates', { params });\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import { Command } from 'commander';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\ninterface GeocodeResult {\n formattedAddress: string;\n lat: number;\n lng: number;\n locationType: string;\n placeId: string;\n types: string[];\n addressComponents: { longName: string; shortName: string; types: string[] }[];\n}\n\ninterface GeocodeResponse {\n status: 'OK' | 'ZERO_RESULTS';\n count: number;\n results: GeocodeResult[];\n}\n\n/** Envelope returned by the solar public API (/api/*). */\ninterface PublicApiResponse<T> {\n code?: number;\n error?: { code?: string; message?: string };\n warning?: { code?: string; message?: string };\n data?: T;\n}\n\n/**\n * Unwrap the PublicApiResponse envelope, print the best match by default (or the\n * full candidate list with --all), and surface API-level errors consistently.\n */\nfunction emit(\n envelope: PublicApiResponse<GeocodeResponse>,\n all: boolean | undefined,\n query: Record<string, unknown>,\n global: OutputOptions,\n): void {\n if (envelope.error) {\n outputError({\n error: true,\n status: envelope.code,\n message: envelope.error.message || envelope.error.code || 'Geocoding error',\n details: envelope.error,\n });\n return;\n }\n\n const data = envelope.data;\n if (!data) {\n output({ found: false, ...query }, global);\n return;\n }\n if (all) {\n output(data.results, global);\n return;\n }\n if (data.count === 0) {\n output({ found: false, ...query }, global);\n return;\n }\n output(data.results[0], global);\n}\n\nexport function registerGeocodeCommands(program: Command): void {\n const geocode = program.command('geocode').description(\n 'Geocoding via the solar service (proxy to Google Geocoding API).\\n' +\n 'Resolve an address into coordinates and vice versa.',\n );\n\n // --- geocode resolve (address -> coordinates) ---\n geocode\n .command('resolve')\n .description(\n 'Resolve an address into coordinates (lat/lng + formatted address).\\n' +\n 'Examples:\\n' +\n ' suntropy geocode resolve --address \"Calle Mayor 1, Madrid\"\\n' +\n ' suntropy geocode resolve --address \"Gran Vía, Madrid\" --country es --all',\n )\n .requiredOption('--address <string>', 'Address to geocode (quote it)')\n .option('--country <code>', 'Bias results to a country (ISO code, e.g. es, pt, it)')\n .option('--all', 'Return all candidate matches instead of only the best one')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(geocode);\n const client = createServiceClient('solar', global);\n const res = await client.get<PublicApiResponse<GeocodeResponse>>(\n '/api/geocode',\n { params: { address: opts.address, country: opts.country } },\n );\n emit(res.data, opts.all, { address: opts.address }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- geocode reverse (coordinates -> address) ---\n geocode\n .command('reverse')\n .description(\n 'Resolve coordinates into an address (reverse geocoding).\\n' +\n 'Example:\\n' +\n ' suntropy geocode reverse --lat 40.4168 --lng -3.7038',\n )\n .requiredOption('--lat <number>', 'Latitude')\n .requiredOption('--lng <number>', 'Longitude')\n .option('--all', 'Return all candidate matches instead of only the best one')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(geocode);\n const client = createServiceClient('solar', global);\n const res = await client.get<PublicApiResponse<GeocodeResponse>>(\n '/api/reverse-geocode',\n { params: { lat: opts.lat, lng: opts.lng } },\n );\n emit(res.data, opts.all, { lat: opts.lat, lng: opts.lng }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import { Command, Option } from 'commander';\nimport { createServiceClient, handleApiError, assertStudyObjectId } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\nimport { loadConfig, getActiveProfile } from '../../config.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\n/**\n * Well-known Suntropy user identity for the Alexandria agent. The front resolves\n * this uid to Alexandria's name/avatar (see `isAlexandriaComment`), so a\n * notification whose `fromUserUid` is this value is rendered as coming FROM\n * Alexandria — not as a self-notification from the acting user whose token the\n * CLI runs with.\n */\nconst ALEXANDRIA_USER_UID = 'alexandria';\n\nconst SEVERITIES = ['info', 'warning', 'urgent'] as const;\ntype Severity = (typeof SEVERITIES)[number];\n\nexport function registerNotificationsCommands(program: Command): void {\n const notifications = program\n .command('notifications')\n .description(\n 'Send in-app (and email) notifications to Suntropy users.\\n' +\n 'Useful for Alexandria to proactively tell a user a task is done, since a\\n' +\n 'direct/email execution leaves no study comment (and thus no auto-notification).',\n );\n\n // --- send ---\n notifications\n .command('send')\n .description(\n 'Send a notification to a user. It appears in the recipient\\'s notification\\n' +\n 'bell and, if enabled in their config, is also emailed. Sent FROM Alexandria\\n' +\n 'by default so it is not shown as a self-notification.\\n' +\n 'Examples:\\n' +\n ' suntropy notifications send --to-user <userUID> --message \"He terminado el estudio.\"\\n' +\n ' suntropy notifications send --to-user <userUID> --title \"Estudio listo\" \\\\\\n' +\n ' --message \"Revisa los resultados.\" --study <solarStudyId> --mention',\n )\n .requiredOption('--to-user <userUID>', 'Recipient userUID (who gets notified)')\n .requiredOption('--message <text>', 'Notification body (supports Markdown)')\n .option('--title <text>', 'Notification title', 'Alexandria')\n .option('--severity <severity>', `Severity: ${SEVERITIES.join(' | ')}`, 'info')\n .option(\n '--mention',\n 'Send as a mention (type new_mention) instead of an update (new_comment). ' +\n 'Mentions are gated by the user\\'s \"mention\" notification setting.',\n )\n .option(\n '--study <solarStudyId>',\n 'Link the notification to a solar study: makes it click-through to that study',\n )\n .option('--link <url>', 'Custom link for the email call-to-action')\n .option(\n '--from-user <userUID>',\n 'Sender userUID shown as the author (default: the authenticated user)',\n )\n // Hidden flag mirroring `studies comment --as-alexandria`: signs the\n // notification as Alexandria (fromUserUid = \"alexandria\", which the front\n // resolves to Alexandria's name/avatar). Omitted from --help; the agent is\n // instructed to use it. `--from-user` still takes precedence if provided.\n .addOption(new Option('--as-alexandria').hideHelp())\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(notifications);\n\n const severity = opts.severity as Severity;\n if (!SEVERITIES.includes(severity)) {\n throw new Error(\n `Invalid --severity \"${opts.severity}\". Use one of: ${SEVERITIES.join(', ')}.`,\n );\n }\n // A linked study must be an actual study _id (24-hex ObjectId), or the\n // click-through would point nowhere.\n if (opts.study) assertStudyObjectId(opts.study);\n\n const client = createServiceClient('notifications', global);\n\n // Sender identity: explicit --from-user wins; else --as-alexandria signs\n // it as Alexandria; else fall back to the authenticated user (a plain\n // user-to-user notification).\n const profile = getActiveProfile(loadConfig());\n const fromUserUid = opts.fromUser\n ? opts.fromUser\n : opts.asAlexandria\n ? ALEXANDRIA_USER_UID\n : profile.userUID;\n\n const notification = {\n notificationType: opts.mention ? 'new_mention' : 'new_comment',\n severity,\n origin: opts.asAlexandria ? 'ALEXANDRIA' : 'CLI',\n fromUserUid,\n toUserUid: opts.toUser,\n notificationContent: {\n contentType: 'COMMENT',\n name: opts.title,\n description: opts.message,\n ...(opts.study ? { externalId: opts.study } : {}),\n ...(opts.link ? { link: opts.link } : {}),\n // The notifications backend only persists notificationContent when a\n // `data` payload is present (the OneToOne isn't cascaded), so without\n // this the notification renders blank in the bell. Always send a\n // small data object; harmless once the backend also persists content\n // without it. Not read by the front for these types.\n data: {\n source: opts.asAlexandria ? 'alexandria' : 'cli',\n ...(opts.study ? { studyId: opts.study } : {}),\n },\n },\n };\n\n // `@Controller('notifications')` behind the `/notifications` gateway\n // prefix → the create route is `/notifications`. clientUID/creator come\n // from the JWT; `toUserUid` in the body is the recipient.\n const res = await client.post('/notifications', notification);\n\n // The service returns the created Notification, or a string reason when\n // the client/type has notifications disabled — surface both clearly.\n if (typeof res.data === 'string') {\n output(\n { sent: false, reason: res.data, toUser: opts.toUser },\n global,\n );\n return;\n }\n output(\n {\n sent: true,\n notificationId: res.data?.idNotification,\n toUser: opts.toUser,\n type: notification.notificationType,\n severity,\n },\n global,\n );\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import type { Command } from 'commander';\nimport { loadConfig, saveConfig } from './config.js';\n\n/**\n * Command access profiles (\"permission tiers\").\n *\n * The CLI can be locked to a permission tier so that only a subset of commands\n * is registered. Tiers are CUMULATIVE:\n *\n * read ⊂ write (read + write) ⊂ delete (read + write + delete = full)\n *\n * Commands above the active tier are pruned from the command tree before\n * parsing, so they (a) never appear in `--help` and (b) when invoked, Commander\n * reports them natively as `error: unknown command 'X'` — i.e. \"the command\n * does not exist\". This is an admin/automation control (e.g. to constrain the\n * Alexandria agent's sandbox to read-only). It is intentionally not advertised\n * in the user-facing help; it is driven by the hidden `command-profile` command\n * or the SUNTROPY_COMMAND_PROFILE environment variable.\n */\nexport type CommandTier = 'read' | 'write' | 'delete';\n\nexport const COMMAND_TIERS: CommandTier[] = ['read', 'write', 'delete'];\n\nconst TIER_VALUE: Record<CommandTier, number> = { read: 0, write: 1, delete: 2 };\n\n/** Default when nothing is configured: full access (legacy behavior). */\nexport const DEFAULT_TIER: CommandTier = 'delete';\n\nexport const ENV_VAR = 'SUNTROPY_COMMAND_PROFILE';\n\nexport function tierValue(t: CommandTier): number {\n return TIER_VALUE[t];\n}\n\nexport function isValidTier(value: unknown): value is CommandTier {\n return typeof value === 'string' && (COMMAND_TIERS as string[]).includes(value);\n}\n\nexport interface ResolvedCommandProfile {\n tier: CommandTier;\n source: 'env' | 'config' | 'default';\n /** Raw env value when present but invalid (for diagnostics). */\n invalidEnv?: string;\n}\n\n/**\n * Resolve the active tier. Precedence: env var > config file > default.\n * Pure (no side effects) so it can be called from both the gating step and the\n * `command-profile` status command.\n */\nexport function getActiveCommandProfile(): ResolvedCommandProfile {\n const envRaw = process.env[ENV_VAR]?.trim();\n if (envRaw) {\n const envNorm = envRaw.toLowerCase();\n if (isValidTier(envNorm)) return { tier: envNorm, source: 'env' };\n // Invalid env value: fall through to config/default but report it.\n const fallback = resolveFromConfig();\n return { ...fallback, invalidEnv: envRaw };\n }\n return resolveFromConfig();\n}\n\nfunction resolveFromConfig(): ResolvedCommandProfile {\n try {\n const cfg = loadConfig();\n if (isValidTier(cfg.commandProfile)) return { tier: cfg.commandProfile, source: 'config' };\n } catch {\n // ignore: fall back to default\n }\n return { tier: DEFAULT_TIER, source: 'default' };\n}\n\n/** Persist (or clear, when null) the stored command profile. */\nexport function setStoredCommandProfile(tier: CommandTier | null): void {\n const cfg = loadConfig();\n if (tier === null) delete cfg.commandProfile;\n else cfg.commandProfile = tier;\n saveConfig(cfg);\n}\n\n// ─── Classification ───────────────────────────────────────────────────────\n//\n// A command's tier is the MAX tier over the verbs in its path. Verbs are the\n// command/group names, so e.g. `studies set name` inherits `write` from `set`,\n// and `inventory kits panels delete` inherits `delete` from `delete`.\n\nconst DELETE_VERBS = new Set(['delete', 'delete-batch', 'archive']);\n\nconst WRITE_VERBS = new Set([\n 'create', 'update', 'edit', 'set', 'add', 'remove', 'assemble', 'featured',\n 'save', 'init', 'init-default', 'add-comment', 'comment', 'send',\n 'calculate-results', 'optimize-peakpower',\n]);\n\n/**\n * Explicit overrides for paths whose verbs are ambiguous. `studies calculate\n * production` writes to the local draft (write), but the bare verb `calculate`\n * is also used by pure-compute commands (`ppa calculate`, `solarform calculate`,\n * `studies calculate-production`) that are read-only — so `calculate` is NOT a\n * global write verb; this path is pinned instead.\n */\nconst PATH_OVERRIDES: Record<string, CommandTier> = {\n 'studies calculate production': 'write',\n};\n\nexport function classifyPath(segs: string[]): CommandTier {\n const key = segs.join(' ');\n if (PATH_OVERRIDES[key]) return PATH_OVERRIDES[key];\n let tier: CommandTier = 'read';\n for (const seg of segs) {\n if (DELETE_VERBS.has(seg)) return 'delete';\n if (WRITE_VERBS.has(seg)) tier = 'write';\n }\n return tier;\n}\n\n// ─── Exemptions ───────────────────────────────────────────────────────────\n//\n// CLI plumbing that must always work regardless of the active tier: you always\n// need to authenticate, configure the CLI, and manage the command profile\n// itself. NOTE: only the *local* `config` leaves are exempt — the tenant\n// configuration subtrees (`config theme`, `config solarform …`) hit the backend\n// and are gated like any other business command.\n\nconst EXEMPT_CONFIG_LEAVES = new Set(['set', 'get', 'list', 'create-profile', 'use']);\n\nexport function isExemptPath(segs: string[]): boolean {\n if (segs[0] === 'auth') return true;\n if (segs[0] === 'command-profile') return true;\n if (segs[0] === 'config' && segs.length === 2 && EXEMPT_CONFIG_LEAVES.has(segs[1])) return true;\n return false;\n}\n\n// ─── Pruning ──────────────────────────────────────────────────────────────\n\n/**\n * Prune the command tree in place according to the active command profile.\n * Returns the resolved tier so the caller can surface it if needed.\n */\nexport function applyCommandProfile(program: Command): ResolvedCommandProfile {\n const resolved = getActiveCommandProfile();\n pruneChildren(program, [], tierValue(resolved.tier));\n return resolved;\n}\n\nfunction pruneChildren(parent: Command, parentSegs: string[], max: number): void {\n const kept = parent.commands.filter((child) => {\n const segs = [...parentSegs, child.name()];\n return keepCommand(child, segs, max);\n });\n // Commander types `commands` as readonly, but pruning must replace its\n // contents. Mutate the array in place (rather than reassigning the property)\n // so Commander keeps using the same reference for help and dispatch.\n const mutable = parent.commands as Command[];\n mutable.length = 0;\n mutable.push(...kept);\n}\n\nfunction keepCommand(cmd: Command, segs: string[], max: number): boolean {\n if (cmd.commands.length > 0) {\n // Group: prune its descendants first, then keep it only if something\n // survived (or it's an exempt subtree).\n pruneChildren(cmd, segs, max);\n if (cmd.commands.length > 0) return true;\n return isExemptPath(segs);\n }\n // Leaf:\n if (isExemptPath(segs)) return true;\n return tierValue(classifyPath(segs)) <= max;\n}\n","import { Command } from 'commander';\nimport { output, outputError, type OutputOptions } from '../output.js';\nimport {\n COMMAND_TIERS,\n DEFAULT_TIER,\n ENV_VAR,\n getActiveCommandProfile,\n isValidTier,\n setStoredCommandProfile,\n} from '../access.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as OutputOptions;\n}\n\n/**\n * Hidden admin command to manage the CLI command access profile (permission\n * tier). Registered with `{ hidden: true }` so it never shows in `--help`, but\n * remains invocable in any tier (it is exempt from gating). Changes take effect\n * on the next invocation, since gating happens at startup.\n *\n * suntropy command-profile show the active tier + source\n * suntropy command-profile read lock the CLI to read-only\n * suntropy command-profile write allow read + write\n * suntropy command-profile delete allow everything (default)\n * suntropy command-profile reset clear the stored value (back to default)\n */\nexport function registerCommandProfileCommand(program: Command): void {\n program\n .command('command-profile [tier]', { hidden: true })\n .description('Admin: get/set the command access profile (read | write | delete | reset)')\n .action((tier?: string) => {\n try {\n const global = getGlobalOpts(program);\n\n // No argument → report current state.\n if (!tier) {\n const resolved = getActiveCommandProfile();\n output(\n {\n commandProfile: resolved.tier,\n source: resolved.source,\n ...(resolved.invalidEnv\n ? { warning: `Ignoring invalid ${ENV_VAR}=\"${resolved.invalidEnv}\" (expected: ${COMMAND_TIERS.join(' | ')})` }\n : {}),\n available: COMMAND_TIERS,\n envVar: ENV_VAR,\n },\n global,\n );\n return;\n }\n\n const value = tier.trim().toLowerCase();\n\n if (value === 'reset') {\n setStoredCommandProfile(null);\n const resolved = getActiveCommandProfile();\n output(\n {\n success: true,\n message: `Stored command profile cleared. Effective tier: ${resolved.tier} (${resolved.source}).`,\n commandProfile: resolved.tier,\n source: resolved.source,\n },\n global,\n );\n return;\n }\n\n if (!isValidTier(value)) {\n outputError(new Error(`Invalid tier \"${tier}\". Expected one of: ${COMMAND_TIERS.join(', ')}, or \"reset\".`));\n return;\n }\n\n setStoredCommandProfile(value);\n const envOverride = getActiveCommandProfile();\n const message =\n envOverride.source === 'env'\n ? `Stored command profile set to \"${value}\", but ${ENV_VAR}=\"${process.env[ENV_VAR]}\" overrides it (effective: ${envOverride.tier}). Unset the env var for the stored value to apply.`\n : `Command profile set to \"${value}\". Takes effect on the next command.`;\n output(\n {\n success: true,\n commandProfile: value,\n effectiveTier: envOverride.tier,\n effectiveSource: envOverride.source,\n default: DEFAULT_TIER,\n message,\n },\n global,\n );\n } catch (err) {\n outputError(err);\n }\n });\n}\n","import { createProgram } from '../src/index.js';\n\nconst program = createProgram();\nprogram.parseAsync(process.argv).catch((err) => {\n process.stderr.write(JSON.stringify({ error: true, message: err.message }) + '\\n');\n process.exit(1);\n});\n"],"mappings":";;;;;;;;;AAAA,SAAS,WAAAA,gBAAe;;;ACAxB,SAAS,YAAY,WAAW,cAAc,qBAAqB;AACnE,SAAS,eAAe;AACxB,SAAS,YAAY;AAuBrB,IAAM,aAAa,KAAK,QAAQ,GAAG,WAAW;AAC9C,IAAM,cAAc,KAAK,YAAY,aAAa;AAElD,IAAM,iBAAiC;AAAA,EACrC,eAAe;AAAA,EACf,UAAU;AAAA,IACR,SAAS;AAAA,MACP,QAAQ;AAAA,IACV;AAAA,EACF;AACF;AAEA,SAAS,kBAAwB;AAC/B,MAAI,CAAC,WAAW,UAAU,GAAG;AAC3B,cAAU,YAAY,EAAE,WAAW,KAAK,CAAC;AAAA,EAC3C;AACF;AAEO,SAAS,aAA6B;AAC3C,kBAAgB;AAChB,MAAI,CAAC,WAAW,WAAW,GAAG;AAC5B,kBAAc,aAAa,KAAK,UAAU,gBAAgB,MAAM,CAAC,CAAC;AAClE,WAAO,EAAE,GAAG,eAAe;AAAA,EAC7B;AACA,SAAO,KAAK,MAAM,aAAa,aAAa,OAAO,CAAC;AACtD;AAEO,SAAS,WAAW,QAA8B;AACvD,kBAAgB;AAChB,gBAAc,aAAa,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAC5D;AAEO,SAAS,iBAAiB,QAAwB,iBAA2C;AAClG,QAAM,OAAO,mBAAmB,OAAO;AACvC,QAAM,UAAU,OAAO,SAAS,IAAI;AACpC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,YAAY,IAAI,2BAA2B,OAAO,KAAK,OAAO,QAAQ,EAAE,KAAK,IAAI,CAAC,EAAE;AAAA,EACtG;AACA,SAAO;AACT;AAEO,SAAS,eAAe,KAAa,OAAe,aAA4B;AACrF,QAAM,SAAS,WAAW;AAC1B,QAAM,OAAO,eAAe,OAAO;AACnC,MAAI,CAAC,OAAO,SAAS,IAAI,GAAG;AAC1B,WAAO,SAAS,IAAI,IAAI,EAAE,QAAQ,4BAA4B;AAAA,EAChE;AACA,QAAM,UAAU,OAAO,SAAS,IAAI;AACpC,UAAQ,GAAG,IAAI;AACf,aAAW,MAAM;AACnB;AAEO,SAAS,eAAe,KAAa,aAA+B;AACzE,QAAM,SAAS,WAAW;AAC1B,QAAM,UAAU,iBAAiB,QAAQ,WAAW;AACpD,SAAQ,QAAoC,GAAG;AACjD;AAGA,IAAM,gBAAwC;AAAA,EAC5C,UAAU;AAAA,EACV,OAAO;AAAA,EACP,WAAW;AAAA,EACX,UAAU;AAAA,EACV,SAAS;AAAA,EACT,eAAe;AACjB;AAEA,IAAM,cAAsC;AAAA,EAC1C,UAAU;AAAA,EACV,OAAO;AAAA,EACP,WAAW;AAAA,EACX,UAAU;AAAA,EACV,SAAS;AAAA,EACT,eAAe;AACjB;AAEO,SAAS,cAAc,YAAoB,SAA6C;AAE7F,MAAI,WAAW,SAAS,WAAW,KAAK,WAAW,MAAM,OAAO,GAAG;AACjE,UAAM,OAAO,YAAY,OAAO;AAChC,UAAM,OAAO,WAAW,QAAQ,SAAS,EAAE,EAAE,QAAQ,OAAO,EAAE;AAC9D,WAAO,GAAG,IAAI,IAAI,IAAI;AAAA,EACxB;AAEA,SAAO,GAAG,WAAW,QAAQ,OAAO,EAAE,CAAC,GAAG,cAAc,OAAO,CAAC;AAClE;;;AC/GA,OAAO,WAA0C;AAiBjD,SAAS,YAAY,MAAwD;AAC3E,QAAM,SAAS,WAAW;AAC1B,QAAM,UAAU,iBAAiB,QAAQ,KAAK,OAAO;AACrD,QAAM,SAAS,KAAK,UAAU,QAAQ;AAItC,QAAM,QAAQ,KAAK,SAAS,QAAQ,IAAI,oBAAoB,QAAQ;AACpE,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,wHAAwH;AAAA,EAC1I;AACA,SAAO,EAAE,QAAQ,MAAM;AACzB;AAEO,SAAS,oBAAoB,SAAwF,MAAoC;AAC9J,QAAM,EAAE,QAAQ,MAAM,IAAI,YAAY,IAAI;AAC1C,QAAM,UAAU,cAAc,QAAQ,OAAO;AAE7C,QAAM,SAAS,MAAM,OAAO;AAAA,IAC1B;AAAA,IACA,SAAS;AAAA,IACT,SAAS;AAAA,MACP,gBAAgB;AAAA,MAChB,eAAe,UAAU,KAAK;AAAA,IAChC;AAAA,EACF,CAAC;AAED,MAAI,KAAK,SAAS;AAChB,WAAO,aAAa,QAAQ,IAAI,CAAC,QAAQ;AACvC,cAAQ,OAAO,MAAM,UAAK,IAAI,QAAQ,YAAY,CAAC,IAAI,IAAI,OAAO,GAAG,IAAI,GAAG;AAAA,CAAI;AAChF,UAAI,IAAI,KAAM,SAAQ,OAAO,MAAM,WAAW,KAAK,UAAU,IAAI,IAAI,EAAE,MAAM,GAAG,GAAG,CAAC;AAAA,CAAI;AACxF,aAAO;AAAA,IACT,CAAC;AACD,WAAO,aAAa,SAAS;AAAA,MAC3B,CAAC,QAAQ;AACP,gBAAQ,OAAO,MAAM,UAAK,IAAI,MAAM,KAAK,KAAK,UAAU,IAAI,IAAI,EAAE,MAAM;AAAA,CAAW;AACnF,eAAO;AAAA,MACT;AAAA,MACA,CAAC,QAAoB;AACnB,gBAAQ,OAAO,MAAM,gBAAW,IAAI,UAAU,UAAU,SAAS,KAAK,IAAI,OAAO;AAAA,CAAI;AACrF,eAAO,QAAQ,OAAO,GAAG;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAGO,SAAS,mBAAmB,SAAgC;AACjE,SAAO,MAAM,OAAO;AAAA,IAClB;AAAA,IACA,SAAS;AAAA,IACT,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,EAChD,CAAC;AACH;AAGA,IAAM,eAAe;AAcd,SAAS,oBAAoB,IAAoB;AACtD,MAAI,aAAa,KAAK,EAAE,EAAG,QAAO;AAClC,QAAM,gBAAgB,kEAAkE,KAAK,EAAE;AAC/F,QAAM,OAAO,gBACT,0EACA;AACJ,QAAM,IAAI;AAAA,IACR,sBAAsB,EAAE,MAAM,IAAI;AAAA,EAEpC;AACF;AAcO,SAAS,YAAe,MAAS,QAAgB,IAAe;AACrE,QAAM,gBACJ,QAAQ,QACR,OAAO,SAAS,YAChB,CAAC,MAAM,QAAQ,IAAI,KACnB,OAAO,KAAK,IAA+B,EAAE,WAAW;AAC1D,MAAI,QAAQ,QAAQ,OAAO,SAAS,YAAY,MAAM,QAAQ,IAAI,KAAK,eAAe;AACpF,UAAM,IAAI;AAAA,MACR,GAAG,MAAM,eAAe,EAAE;AAAA,IAG5B;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,eAAe,KAAwB;AACrD,MAAI,MAAM,aAAa,GAAG,GAAG;AAC3B,UAAM,KAAK;AACX,WAAO;AAAA,MACL,OAAO;AAAA,MACP,QAAQ,GAAG,UAAU,UAAU;AAAA,MAC/B,SAAS,GAAG,UAAU,cAAc,GAAG;AAAA,MACvC,SAAS,GAAG,UAAU;AAAA,IACxB;AAAA,EACF;AACA,SAAO;AAAA,IACL,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,EAC1D;AACF;;;AChJA,OAAO,WAAW;AAClB,SAAS,iBAAAC,sBAAqB;AAY9B,SAAS,WAAW,KAA8B,QAA2C;AAC3F,QAAM,SAAkC,CAAC;AACzC,aAAW,KAAK,QAAQ;AACtB,QAAI,EAAE,SAAS,GAAG,GAAG;AACnB,YAAM,QAAQ,EAAE,MAAM,GAAG;AACzB,UAAI,MAAe;AACnB,iBAAW,KAAK,OAAO;AACrB,cAAM,OAAO,OAAO,QAAQ,WAAY,IAAgC,CAAC,IAAI;AAAA,MAC/E;AACA,aAAO,CAAC,IAAI;AAAA,IACd,OAAO;AACL,aAAO,CAAC,IAAI,IAAI,CAAC;AAAA,IACnB;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,oBAAoB,MAAe,QAA0B;AACpE,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,YAAY,OAAO,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;AACvD,MAAI,MAAM,QAAQ,IAAI,GAAG;AACvB,WAAO,KAAK,IAAI,CAAC,SAAS,WAAW,MAAiC,SAAS,CAAC;AAAA,EAClF;AACA,MAAI,OAAO,SAAS,YAAY,SAAS,MAAM;AAC7C,WAAO,WAAW,MAAiC,SAAS;AAAA,EAC9D;AACA,SAAO;AACT;AAEA,SAAS,iBAAiB,KAAsB;AAC9C,MAAI,QAAQ,QAAQ,QAAQ,OAAW,QAAO;AAC9C,MAAI,OAAO,QAAQ,SAAU,QAAO,KAAK,UAAU,GAAG;AACtD,SAAO,OAAO,GAAG;AACnB;AAEA,SAAS,YAAY,MAAuB;AAC1C,MAAI,MAAM,QAAQ,IAAI,GAAG;AACvB,QAAI,KAAK,WAAW,EAAG,QAAO,MAAM,IAAI,SAAS;AACjD,UAAM,OAAO,OAAO,KAAK,KAAK,CAAC,CAA4B;AAC3D,UAAM,SAAS,KAAK,IAAI,CAAC,MAAM,KAAK,IAAI,EAAE,QAAQ,GAAG,KAAK,IAAI,CAAC,MAAM,iBAAkB,EAA8B,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;AACjI,UAAM,SAAS,KAAK,IAAI,CAAC,GAAG,MAAM,MAAM,KAAK,EAAE,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI;AAC5E,UAAM,OAAO,KAAK;AAAA,MAAI,CAAC,QACrB,KAAK,IAAI,CAAC,GAAG,MAAM,iBAAkB,IAAgC,CAAC,CAAC,EAAE,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI;AAAA,IACvG;AACA,WAAO,CAAC,QAAQ,KAAK,IAAI,CAAC,GAAG,MAAM,SAAI,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,GAAG,GAAG,IAAI,EAAE,KAAK,IAAI;AAAA,EAC1F;AACA,MAAI,OAAO,SAAS,YAAY,SAAS,MAAM;AAC7C,UAAM,UAAU,OAAO,QAAQ,IAA+B;AAC9D,UAAM,SAAS,KAAK,IAAI,GAAG,QAAQ,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC;AACzD,WAAO,QAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,MAAM,KAAK,EAAE,OAAO,MAAM,CAAC,CAAC,KAAK,iBAAiB,CAAC,CAAC,EAAE,EAAE,KAAK,IAAI;AAAA,EACrG;AACA,SAAO,OAAO,IAAI;AACpB;AAEA,SAAS,UAAU,MAAuB;AACxC,MAAI,CAAC,MAAM,QAAQ,IAAI,GAAG;AACxB,QAAI,OAAO,SAAS,YAAY,SAAS,KAAM,QAAO,CAAC,IAAI;AAAA,QACtD,QAAO,OAAO,IAAI;AAAA,EACzB;AACA,QAAM,MAAM;AACZ,MAAI,IAAI,WAAW,EAAG,QAAO;AAC7B,QAAM,OAAO,OAAO,KAAK,IAAI,CAAC,CAAC;AAC/B,QAAM,SAAS,CAAC,MAAe;AAC7B,UAAM,IAAI,MAAM,QAAQ,MAAM,SAAY,KAAK,OAAO,CAAC;AACvD,WAAO,EAAE,SAAS,GAAG,KAAK,EAAE,SAAS,GAAG,KAAK,EAAE,SAAS,IAAI,IAAI,IAAI,EAAE,QAAQ,MAAM,IAAI,CAAC,MAAM;AAAA,EACjG;AACA,SAAO,CAAC,KAAK,KAAK,GAAG,GAAG,GAAG,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,EAAE,KAAK,IAAI;AAC/F;AAEO,SAAS,OAAO,MAAe,OAAsB,CAAC,GAAS;AACpE,QAAM,WAAW,oBAAoB,MAAM,KAAK,MAAM;AACtD,MAAI;AAEJ,UAAQ,KAAK,QAAQ;AAAA,IACnB,KAAK;AACH,aAAO,YAAY,QAAQ;AAC3B;AAAA,IACF,KAAK;AACH,aAAO,UAAU,QAAQ;AACzB;AAAA,IACF;AACE,aAAO,KAAK,UAAU,UAAU,MAAM,CAAC;AAAA,EAC3C;AAEA,UAAQ,OAAO,MAAM,OAAO,IAAI;AAEhC,MAAI,KAAK,MAAM;AACb,IAAAA,eAAc,KAAK,MAAM,KAAK,UAAU,UAAU,MAAM,CAAC,CAAC;AAAA,EAC5D;AACF;AAEO,SAAS,YAAY,KAAoB;AAC9C,MAAI,OAAO,OAAO,QAAQ,YAAY,WAAW,KAAK;AAEpD,UAAM,SAAS;AACf,UAAM,MAA+B,EAAE,OAAO,MAAM,SAAS,OAAO,WAAW,gBAAgB;AAC/F,QAAI,OAAO,OAAQ,KAAI,SAAS,OAAO;AACvC,QAAI,OAAO,QAAS,KAAI,UAAU,OAAO;AACzC,YAAQ,OAAO,MAAM,KAAK,UAAU,GAAG,IAAI,IAAI;AAAA,EACjD,OAAO;AACL,UAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,YAAQ,OAAO,MAAM,KAAK,UAAU,EAAE,OAAO,MAAM,SAAS,IAAI,CAAC,IAAI,IAAI;AAAA,EAC3E;AACA,UAAQ,WAAW;AACrB;AAGO,SAAS,gBAAgB,MAAiB,OAAe,OAAe,QAAgB,OAAsB,CAAC,GAAS;AAC7H,MAAI,KAAK,WAAW,SAAS;AAC3B,UAAM,WAAW,oBAAoB,MAAM,KAAK,MAAM;AACtD,UAAM,MAAM,KAAK,IAAI,SAAS,OAAO,KAAK;AAC1C,YAAQ,OAAO,MAAM,MAAM,IAAI,WAAW,SAAS,CAAC,IAAI,GAAG,OAAO,KAAK;AAAA;AAAA,CAAM,CAAC;AAC9E,YAAQ,OAAO,MAAM,YAAY,QAAQ,IAAI,IAAI;AAAA,EACnD,OAAO;AACL,WAAO,EAAE,MAAM,oBAAoB,MAAM,KAAK,MAAM,GAAG,OAAO,OAAO,QAAQ,SAAS,SAAS,QAAQ,MAAM,GAAG,EAAE,GAAG,MAAM,QAAQ,OAAU,CAAC;AAAA,EAChJ;AACF;;;AC5HA,SAAS,cAAc,KAAuD;AAC5E,MAAI,OAAO;AACX,SAAO,KAAK,OAAQ,QAAO,KAAK;AAChC,SAAO,KAAK,KAAK;AACnB;AAEO,SAAS,qBAAqBC,UAAwB;AAC3D,QAAM,OAAOA,SAAQ,QAAQ,MAAM,EAAE,YAAY,2BAA2B;AAG5E,OACG,QAAQ,SAAS,EACjB,YAAY,uEAAuE,EACnF,eAAe,eAAe,aAAa,EAC3C,OAAO,OAAO,SAAS;AACtB,QAAI;AAIF,YAAM,SAAS,cAAc,IAAI;AACjC,YAAM,SAAS,WAAW;AAC1B,YAAM,cAAe,OAAO,WAAsB,OAAO;AACzD,UAAI,CAAC,OAAO,SAAS,WAAW,GAAG;AACjC,eAAO,SAAS,WAAW,IAAI,EAAE,QAAQ,4BAA4B;AAAA,MACvE;AACA,YAAM,UAAU,OAAO,SAAS,WAAW;AAC3C,cAAQ,QAAQ,KAAK;AACrB,cAAQ,aAAa;AACrB,UAAI,OAAO,OAAQ,SAAQ,SAAS,OAAO;AAG3C,UAAI;AACF,cAAM,UAAU,KAAK,MAAM,OAAO,KAAK,KAAK,IAAI,MAAM,GAAG,EAAE,CAAC,GAAG,QAAQ,EAAE,SAAS,CAAC;AACnF,gBAAQ,YAAY,QAAQ;AAC5B,gBAAQ,UAAU,QAAQ;AAAA,MAC5B,QAAQ;AAAA,MAER;AAEA,iBAAW,MAAM;AACjB,aAAO,EAAE,SAAS,MAAM,QAAQ,WAAW,SAAS,aAAa,WAAW,QAAQ,WAAW,QAAQ,QAAQ,OAAO,GAAG,cAAc,IAAI,CAAC;AAAA,IAC9I,SAAS,KAAK;AACZ,kBAAY,GAAG;AAAA,IACjB;AAAA,EACF,CAAC;AAGH,OACG,QAAQ,OAAO,EACf,YAAY,+BAA+B,EAC3C,eAAe,mBAAmB,YAAY,EAC9C,eAAe,yBAAyB,eAAe,EACvD,OAAO,OAAO,SAAS;AACtB,QAAI;AAEF,YAAM,SAAS,cAAc,IAAI;AACjC,YAAM,SAAS,WAAW;AAC1B,YAAM,cAAe,OAAO,WAAsB,OAAO;AACzD,UAAI,CAAC,OAAO,SAAS,WAAW,GAAG;AACjC,eAAO,SAAS,WAAW,IAAI,EAAE,QAAQ,4BAA4B;AAAA,MACvE;AACA,YAAM,UAAU,OAAO,SAAS,WAAW;AAC3C,UAAI,OAAO,OAAQ,SAAQ,SAAS,OAAO;AAE3C,YAAM,cAAc,cAAc,QAAQ,QAAQ,UAAU;AAC5D,YAAM,SAAS,mBAAmB,WAAW;AAC7C,YAAM,MAAM,MAAM,OAAO,KAAK,eAAe,EAAE,OAAO,KAAK,OAAO,UAAU,KAAK,SAAS,CAAC;AAE3F,UAAI,IAAI,MAAM,OAAO,cAAc;AACjC,gBAAQ,QAAQ,IAAI,KAAK,MAAM;AAC/B,gBAAQ,aAAa;AACrB,gBAAQ,QAAQ,KAAK;AACrB,gBAAQ,YAAY,IAAI,KAAK,MAAM;AACnC,gBAAQ,UAAU,IAAI,KAAK,MAAM;AACjC,mBAAW,MAAM;AACjB,eAAO;AAAA,UACL,SAAS;AAAA,UACT,QAAQ;AAAA,UACR,SAAS;AAAA,UACT,MAAM;AAAA,YACJ,OAAO,IAAI,KAAK,MAAM;AAAA,YACtB,WAAW,IAAI,KAAK,MAAM;AAAA,YAC1B,SAAS,IAAI,KAAK,MAAM;AAAA,UAC1B;AAAA,QACF,GAAG,cAAc,IAAI,CAAC;AAAA,MACxB,OAAO;AACL,oBAAY,IAAI,MAAM,IAAI,MAAM,SAAS,CAAC,GAAG,WAAW,cAAc,CAAC;AAAA,MACzE;AAAA,IACF,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAGH,OACG,QAAQ,QAAQ,EAChB,YAAY,oCAAoC,EAChD,OAAO,YAAY;AAClB,QAAI;AAEF,YAAM,SAAS,cAAc,IAAI;AACjC,YAAM,SAAS,WAAW;AAC1B,YAAM,UAAU,iBAAiB,QAAQ,OAAO,OAAiB;AACjE,UAAI,CAAC,QAAQ,OAAO;AAClB,eAAO,EAAE,eAAe,OAAO,SAAS,sBAAsB,GAAG,cAAc,IAAI,CAAC;AACpF;AAAA,MACF;AAGA,UAAI;AACJ,UAAI,UAAU;AACd,UAAI;AACF,cAAM,UAAU,KAAK,MAAM,OAAO,KAAK,QAAQ,MAAM,MAAM,GAAG,EAAE,CAAC,GAAG,QAAQ,EAAE,SAAS,CAAC;AACxF,YAAI,QAAQ,KAAK;AACf,gBAAM,UAAU,IAAI,KAAK,QAAQ,MAAM,GAAI;AAC3C,sBAAY,QAAQ,YAAY;AAChC,oBAAU,UAAU,oBAAI,KAAK;AAAA,QAC/B;AAAA,MACF,QAAQ;AAAA,MAER;AAEA,aAAO;AAAA,QACL,eAAe,CAAC;AAAA,QAChB,QAAQ,QAAQ,cAAc;AAAA,QAC9B,QAAQ,QAAQ;AAAA,QAChB,OAAO,QAAQ;AAAA,QACf,WAAW,QAAQ;AAAA,QACnB,SAAS,QAAQ;AAAA,QACjB;AAAA,QACA;AAAA,MACF,GAAG,cAAc,IAAI,CAAC;AAAA,IACxB,SAAS,KAAK;AACZ,kBAAY,GAAG;AAAA,IACjB;AAAA,EACF,CAAC;AAGH,OACG,QAAQ,SAAS,EACjB,YAAY,+BAA+B,EAC3C,OAAO,YAAY;AAClB,QAAI;AAEF,YAAM,aAAa,cAAc,IAAI;AACrC,YAAM,SAAS,WAAW;AAC1B,YAAM,cAAe,WAAW,WAAsB,OAAO;AAC7D,YAAM,SAAS,oBAAoB,YAAY,EAAE,GAAG,YAAY,SAAS,YAAY,CAAC;AACtF,YAAM,MAAM,MAAM,OAAO,IAAI,wBAAwB;AAErD,UAAI,IAAI,MAAM,gBAAgB,IAAI,MAAM,OAAO,cAAc;AAC3D,cAAM,WAAW,IAAI,KAAK,gBAAgB,IAAI,KAAK,MAAM;AACzD,eAAO,SAAS,WAAW,EAAE,QAAQ;AACrC,mBAAW,MAAM;AACjB,eAAO,EAAE,SAAS,MAAM,SAAS,kBAAkB,GAAG,cAAc,IAAI,CAAC;AAAA,MAC3E,OAAO;AACL,oBAAY,IAAI,MAAM,gBAAgB,CAAC;AAAA,MACzC;AAAA,IACF,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAGH,OACG,QAAQ,QAAQ,EAChB;AAAA,IACC;AAAA,EAGF,EACC,OAAO,SAAS,oCAAoC,EACpD,OAAO,OAAO,SAAS;AACtB,QAAI;AAEF,YAAM,SAAS,cAAc,IAAI;AACjC,YAAM,SAAS,WAAW;AAI1B,YAAM,eAAe,CAAC,SAA0B;AAC9C,cAAM,UAAU,OAAO,SAAS,IAAI;AACpC,YAAI,CAAC,QAAS,QAAO;AACrB,cAAMC,YAAW,CAAC,CAAC,QAAQ;AAC3B,eAAO,QAAQ;AACf,eAAO,QAAQ;AACf,eAAO,QAAQ;AACf,eAAO,QAAQ;AACf,eAAO,QAAQ;AACf,eAAOA;AAAA,MACT;AAEA,UAAI,KAAK,KAAK;AACZ,cAAM,QAAQ,OAAO,KAAK,OAAO,QAAQ;AACzC,cAAM,mBAAmB,MAAM,OAAO,YAAY;AAClD,mBAAW,MAAM;AACjB,eAAO;AAAA,UACL,SAAS;AAAA,UACT,SAAS,iBAAiB,MAAM,MAAM;AAAA,UACtC,UAAU;AAAA,UACV,gBAAgB;AAAA,QAClB,GAAG,MAAM;AACT;AAAA,MACF;AAEA,YAAM,cAAe,OAAO,WAAsB,OAAO;AACzD,UAAI,CAAC,OAAO,SAAS,WAAW,GAAG;AACjC,oBAAY,IAAI,MAAM,YAAY,WAAW,2BAA2B,OAAO,KAAK,OAAO,QAAQ,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;AAClH;AAAA,MACF;AACA,YAAM,WAAW,aAAa,WAAW;AACzC,iBAAW,MAAM;AACjB,aAAO;AAAA,QACL,SAAS;AAAA,QACT,SAAS;AAAA,QACT,SAAS,WACL,0BAA0B,WAAW,0CACrC,YAAY,WAAW;AAAA,MAC7B,GAAG,MAAM;AAAA,IACX,SAAS,KAAK;AACZ,kBAAY,GAAG;AAAA,IACjB;AAAA,EACF,CAAC;AACL;;;ACnOA,SAAS,gBAAAC,eAAc,iBAAAC,gBAAe,kBAAkB;AACxD,SAAS,cAAc;AACvB,SAAS,QAAAC,aAAY;AACrB,SAAS,iBAAiB;AAMnB,SAASC,eAAc,KAA0B;AACtD,MAAI,OAAgB;AACpB,SAAO,KAAK,OAAQ,QAAO,KAAK;AAChC,SAAO,KAAK,KAAK;AACnB;AAGO,SAAS,YAAY,KAAsB;AAChD,MAAI,QAAQ,OAAQ,QAAO;AAC3B,MAAI,QAAQ,QAAS,QAAO;AAC5B,MAAI,QAAQ,OAAQ,QAAO;AAC3B,MAAI,UAAU,KAAK,GAAG,EAAG,QAAO,SAAS,KAAK,EAAE;AAChD,MAAI,eAAe,KAAK,GAAG,EAAG,QAAO,WAAW,GAAG;AACnD,MAAK,IAAI,WAAW,GAAG,KAAK,IAAI,SAAS,GAAG,KAAO,IAAI,WAAW,GAAG,KAAK,IAAI,SAAS,GAAG,GAAI;AAC5F,QAAI;AAAE,aAAO,KAAK,MAAM,GAAG;AAAA,IAAG,QAAQ;AAAA,IAA+B;AAAA,EACvE;AACA,SAAO;AACT;AAGO,SAAS,cAAc,SAAwD;AACpF,MAAI,CAAC,WAAW,QAAQ,WAAW,EAAG,QAAO,CAAC;AAC9C,QAAM,MAA+B,CAAC;AACtC,aAAW,SAAS,SAAS;AAC3B,UAAM,KAAK,MAAM,QAAQ,GAAG;AAC5B,QAAI,KAAK,EAAG,OAAM,IAAI,MAAM,wBAAwB,KAAK,wBAAwB;AACjF,UAAM,MAAM,MAAM,MAAM,GAAG,EAAE,EAAE,KAAK;AACpC,UAAM,SAAS,MAAM,MAAM,KAAK,CAAC;AACjC,QAAI,CAAC,IAAK,OAAM,IAAI,MAAM,wBAAwB,KAAK,eAAe;AACtE,QAAI,GAAG,IAAI,YAAY,MAAM;AAAA,EAC/B;AACA,SAAO;AACT;AAGO,SAAS,aAAa,MAAuC;AAClE,QAAM,MAAMH,cAAa,MAAM,OAAO;AACtC,QAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,MAAI,CAAC,UAAU,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,GAAG;AAClE,UAAM,IAAI,MAAM,QAAQ,IAAI,8CAA8C;AAAA,EAC5E;AACA,SAAO;AACT;AAGO,SAAS,SAA4C,KAA2B,MAAkD;AACvI,QAAM,MAA+B,CAAC;AACtC,MAAI,CAAC,IAAK,QAAO;AACjB,aAAW,KAAK,MAAM;AACpB,QAAI,KAAK,IAAK,KAAI,CAAC,IAAK,IAAgC,CAAC;AAAA,EAC3D;AACA,SAAO;AACT;AAGO,SAAS,aACd,YACA,YACA,UACA,aACyB;AACzB,QAAM,UAAmC,CAAC;AAC1C,MAAI,SAAU,QAAO,OAAO,SAAS,aAAa,QAAQ,CAAC;AAC3D,MAAI,WAAY,QAAO,OAAO,SAAS,cAAc,UAAU,CAAC;AAChE,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,UAAU,GAAG;AAC/C,QAAI,MAAM,OAAW,SAAQ,CAAC,IAAI;AAAA,EACpC;AACA,MAAI,aAAa;AACf,eAAW,KAAK,OAAO,KAAK,OAAO,GAAG;AACpC,UAAI,CAAC,YAAY,SAAS,CAAC,GAAG;AAC5B,cAAM,IAAI,MAAM,UAAU,CAAC,+CAA+C,YAAY,KAAK,IAAI,CAAC,EAAE;AAAA,MACpG;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAGO,SAAS,SAAS,SAAkB,eAAe,UAAmC;AAC3F,QAAM,SAAS,QAAQ,IAAI,UAAU,QAAQ,IAAI,UAAU;AAC3D,QAAM,MAAME,MAAK,OAAO,GAAG,YAAY,YAAY,IAAI,KAAK,IAAI,CAAC,OAAO;AACxE,EAAAD,eAAc,KAAK,KAAK,UAAU,WAAW,CAAC,GAAG,MAAM,CAAC,CAAC;AACzD,MAAI;AACF,UAAM,MAAM,UAAU,QAAQ,CAAC,GAAG,GAAG,EAAE,OAAO,UAAU,CAAC;AACzD,QAAI,IAAI,WAAW,EAAG,OAAM,IAAI,MAAM,WAAW,MAAM,wBAAwB,IAAI,MAAM,EAAE;AAC3F,UAAM,UAAUD,cAAa,KAAK,OAAO;AACzC,UAAM,SAAS,KAAK,MAAM,OAAO;AACjC,QAAI,CAAC,UAAU,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,GAAG;AAClE,YAAM,IAAI,MAAM,uDAAuD;AAAA,IACzE;AACA,WAAO;AAAA,EACT,UAAE;AACA,QAAI;AAAE,iBAAW,GAAG;AAAA,IAAG,QAAQ;AAAA,IAAe;AAAA,EAChD;AACF;;;AC/FA,IAAM,aAAa;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAAU;AAAA,EAAU;AAAA,EAAU;AAAA,EAAU;AAAA,EAAU;AAAA,EAClD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEO,SAAS,sBAAsB,YAA2B;AAC/D,QAAM,QAAQ,WACX,QAAQ,OAAO,EACf;AAAA,IACC;AAAA,EAYF;AAEF,QACG,QAAQ,KAAK,EACb,YAAY,4EAA4E,EACxF,eAAe,sBAAsB,0CAA0C,EAC/E,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASI,eAAc,KAAK;AAClC,YAAM,SAAS,oBAAoB,YAAY,MAAM;AACrD,YAAM,MAAM,MAAM,OAAO,IAAI,0CAA0C,KAAK,SAAS,EAAE;AACvF,aAAO,IAAI,MAAM,MAAM;AAAA,IACzB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAEH,QACG,QAAQ,KAAK,EACb;AAAA,IACC;AAAA,EAMF,EACC,OAAO,mBAAmB,gBAAgB,EAC1C,OAAO,uBAAuB,uBAAuB,EACrD,OAAO,yBAAyB,yBAAyB,EACzD,OAAO,sBAAsB,mBAAmB,EAChD,OAAO,mCAAmC,0BAA0B,EACpE,OAAO,oBAAoB,UAAU,EACrC,OAAO,uBAAuB,aAAa,EAC3C,OAAO,8BAA8B,mBAAmB,EACxD,OAAO,gCAAgC,sCAAsC,EAC7E,OAAO,sBAAsB,wDAAwD,EACrF,OAAO,sBAAsB,yCAAyC,EACtE,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASA,eAAc,KAAK;AAClC,YAAM,SAAS,oBAAoB,YAAY,MAAM;AAErD,YAAM,aAAsC;AAAA,QAC1C,SAAS,KAAK;AAAA,QACd,YAAY,KAAK;AAAA,QACjB,cAAc,KAAK;AAAA,QACnB,YAAY,KAAK;AAAA,QACjB,uBAAuB,KAAK;AAAA,QAC5B,SAAS,KAAK;AAAA,QACd,YAAY,KAAK;AAAA,QACjB,gBAAgB,KAAK;AAAA,QACrB,mBAAmB,KAAK,sBAAsB,SAAY,SAAY,KAAK,sBAAsB,QAAQ,KAAK,sBAAsB;AAAA,MACtI;AAEA,YAAM,UAAU,aAAa,YAAY,KAAK,KAAK,KAAK,UAAU,UAAU;AAC5E,UAAI,OAAO,KAAK,OAAO,EAAE,WAAW,GAAG;AACrC,oBAAY,IAAI,MAAM,uDAAuD,CAAC;AAC9E;AAAA,MACF;AAEA,YAAM,MAAM,MAAM,OAAO,KAAK,+BAA+B,OAAO;AACpE,aAAO,IAAI,MAAM,MAAM;AAAA,IACzB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAEH,QACG,QAAQ,MAAM,EACd,YAAY,6DAA6D,EACzE,eAAe,sBAAsB,4CAA4C,EACjF,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASA,eAAc,KAAK;AAClC,YAAM,SAAS,oBAAoB,YAAY,MAAM;AACrD,YAAM,UAAU,MAAM,OAAO,IAAI,0CAA0C,KAAK,SAAS,EAAE;AAC3F,YAAM,SAAS,SAAS,QAAQ,MAAiC,UAAU;AAC3E,YAAM,SAAS,SAAS,QAAQ,OAAO;AACvC,YAAM,MAAM,MAAM,OAAO,KAAK,+BAA+B,MAAM;AACnE,aAAO,IAAI,MAAM,MAAM;AAAA,IACzB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AACL;;;ACtHA,SAAS,MAAM,KAAqB;AAClC,SAAO,IAAI,QAAQ,cAAc,CAAC,GAAG,MAAO,MAAM,IAAI,EAAE,YAAY,IAAI,MAAM,EAAE,YAAY,CAAE;AAChG;AAWA,IAAM,UAAmB;AAAA,EACvB,MAAM;AAAA,EACN,OAAO;AAAA,EACP,SACE;AAAA,EAGF,QAAQ;AAAA,IACN;AAAA,IAAW;AAAA,IAAc;AAAA,IACzB;AAAA,IAAwB;AAAA,IACxB;AAAA,IAAsB;AAAA,IAAkC;AAAA,IACxD;AAAA,IAAoB;AAAA,IACpB;AAAA,IAAmB;AAAA,IACnB;AAAA,IAAyB;AAAA,IAAiB;AAAA,IAAc;AAAA,IACxD;AAAA,IAAoB;AAAA,EACtB;AAAA,EACA,WAAW;AAAA,IACT,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,sBAAsB;AAAA,IACtB,mBAAmB;AAAA,IACnB,oBAAoB;AAAA,IACpB,gCAAgC;AAAA,IAChC,6BAA6B;AAAA,IAC7B,kBAAkB;AAAA,IAClB,oBAAoB;AAAA,IACpB,iBAAiB;AAAA,IACjB,oBAAoB;AAAA,IACpB,uBAAuB;AAAA,IACvB,eAAe;AAAA,IACf,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,kBAAkB;AAAA,IAClB,YAAY;AAAA,EACd;AACF;AAEA,IAAM,QAAiB;AAAA,EACrB,MAAM;AAAA,EACN,OAAO;AAAA,EACP,SAAS;AAAA,EACT,QAAQ;AAAA,IACN;AAAA,IAAc;AAAA,IACd;AAAA,IAA4B;AAAA,IAA4B;AAAA,IAA4B;AAAA,IACpF;AAAA,IACA;AAAA,IAAkB;AAAA,IAClB;AAAA,EACF;AAAA,EACA,WAAW;AAAA,IACT,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,0BAA0B;AAAA,IAC1B,0BAA0B;AAAA,IAC1B,0BAA0B;AAAA,IAC1B,0BAA0B;AAAA,IAC1B,mBAAmB;AAAA,IACnB,gBAAgB;AAAA,IAChB,kBAAkB;AAAA,IAClB,oBAAoB;AAAA,EACtB;AACF;AAEA,IAAM,WAAoB;AAAA,EACxB,MAAM;AAAA,EACN,OAAO;AAAA,EACP,SAAS;AAAA,EACT,QAAQ,CAAC,sBAAsB,oBAAoB,mBAAmB,2BAA2B,wBAAwB;AAAA,EACzH,WAAW;AAAA,IACT,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,IACjB,yBAAyB;AAAA,IACzB,wBAAwB;AAAA,EAC1B;AACF;AAEA,IAAM,WAAoB;AAAA,EACxB,MAAM;AAAA,EACN,OAAO;AAAA,EACP,SAAS;AAAA,EACT,QAAQ;AAAA,IACN;AAAA,IACA;AAAA,IAAkC;AAAA,IAA+B;AAAA,IACjE;AAAA,IAAiC;AAAA,IAA8B;AAAA,IAC/D;AAAA,IAAgC;AAAA,IAA6B;AAAA,IAC7D;AAAA,EACF;AAAA,EACA,WAAW;AAAA,IACT,qBAAqB;AAAA,IACrB,gCAAgC;AAAA,IAChC,6BAA6B;AAAA,IAC7B,0BAA0B;AAAA,IAC1B,+BAA+B;AAAA,IAC/B,4BAA4B;AAAA,IAC5B,yBAAyB;AAAA,IACzB,8BAA8B;AAAA,IAC9B,2BAA2B;AAAA,IAC3B,wBAAwB;AAAA,IACxB,2BAA2B;AAAA,EAC7B;AACF;AAEA,IAAM,cAAuB;AAAA,EAC3B,MAAM;AAAA,EACN,OAAO;AAAA,EACP,SAAS;AAAA,EACT,QAAQ;AAAA,IACN;AAAA,IACA;AAAA,IAAoB;AAAA,IACpB;AAAA,IAAwB;AAAA,IACxB;AAAA,IAA4B;AAAA,IAC5B;AAAA,IAAsB;AAAA,EACxB;AAAA,EACA,WAAW;AAAA,IACT,wBAAwB;AAAA,IACxB,kBAAkB;AAAA,IAClB,cAAc;AAAA,IACd,sBAAsB;AAAA,IACtB,kBAAkB;AAAA,IAClB,0BAA0B;AAAA,IAC1B,sBAAsB;AAAA,IACtB,oBAAoB;AAAA,IACpB,sBAAsB;AAAA,EACxB;AACF;AAEA,IAAM,cAAuB;AAAA,EAC3B,MAAM;AAAA,EACN,OAAO;AAAA,EACP,SAAS;AAAA,EACT,QAAQ,CAAC,0BAA0B,oBAAoB;AAAA,EACvD,WAAW;AAAA,IACT,wBAAwB;AAAA,IACxB,oBAAoB;AAAA,EACtB;AACF;AAEA,IAAM,SAAkB;AAAA,EACtB,MAAM;AAAA,EACN,OAAO;AAAA,EACP,SAAS;AAAA,EACT,QAAQ,CAAC,oBAAoB,qBAAqB,iBAAiB,wBAAwB,qBAAqB,YAAY;AAAA,EAC5H,WAAW;AAAA,IACT,kBAAkB;AAAA,IAClB,mBAAmB;AAAA,IACnB,eAAe;AAAA,IACf,sBAAsB;AAAA,IACtB,mBAAmB;AAAA,IACnB,YAAY;AAAA,EACd;AACF;AAEA,IAAM,cAAuB;AAAA,EAC3B,MAAM;AAAA,EACN,OAAO;AAAA,EACP,SAAS;AAAA,EACT,QAAQ,CAAC,sCAAsC,oCAAoC;AAAA,EACnF,WAAW;AAAA,IACT,oCAAoC;AAAA,IACpC,oCAAoC;AAAA,EACtC;AACF;AAEA,IAAM,UAAmB;AAAA,EACvB,MAAM;AAAA,EACN,OAAO;AAAA,EACP,SAAS;AAAA,EACT,QAAQ;AAAA,IACN;AAAA,IAAe;AAAA,IAA6B;AAAA,IAAgC;AAAA,IAC5E;AAAA,IAAwB;AAAA,IAAuB;AAAA,IAAe;AAAA,IAAW;AAAA,IAAa;AAAA,IACtF;AAAA,IAAmB;AAAA,IACnB;AAAA,IAAyB;AAAA,IAAiC;AAAA,IAC1D;AAAA,IAAmC;AAAA,IACnC;AAAA,IAA0C;AAAA,IAAuC;AAAA,IACjF;AAAA,IAAuB;AAAA,IACvB;AAAA,IAAgB;AAAA,IAA6B;AAAA,IAAoB;AAAA,IACjE;AAAA,IAAoB;AAAA,IAAkC;AAAA,IAAwC;AAAA,EAChG;AAAA,EACA,WAAW;AAAA,IACT,aAAa;AAAA,IACb,2BAA2B;AAAA,IAC3B,8BAA8B;AAAA,IAC9B,4BAA4B;AAAA,IAC5B,+BAA+B;AAAA,IAC/B,sBAAsB;AAAA,IACtB,qBAAqB;AAAA,IACrB,aAAa;AAAA,IACb,SAAS;AAAA,IACT,WAAW;AAAA,IACX,cAAc;AAAA,IACd,iBAAiB;AAAA,IACjB,uBAAuB;AAAA,IACvB,+BAA+B;AAAA,IAC/B,kCAAkC;AAAA,IAClC,iCAAiC;AAAA,IACjC,yCAAyC;AAAA,IACzC,wCAAwC;AAAA,IACxC,qCAAqC;AAAA,IACrC,mCAAmC;AAAA,IACnC,qBAAqB;AAAA,IACrB,oBAAoB;AAAA,IACpB,cAAc;AAAA,IACd,2BAA2B;AAAA,IAC3B,kBAAkB;AAAA,IAClB,uBAAuB;AAAA,IACvB,kBAAkB;AAAA,IAClB,gCAAgC;AAAA,IAChC,sCAAsC;AAAA,IACtC,qBAAqB;AAAA,EACvB;AACF;AAEA,IAAM,gBAAyB;AAAA,EAC7B,MAAM;AAAA,EACN,OAAO;AAAA,EACP,SAAS;AAAA,EACT,QAAQ,CAAC,wBAAwB;AAAA,EACjC,WAAW;AAAA,IACT,wBAAwB;AAAA,EAC1B;AACF;AAEA,IAAM,WAA+B;AAAA,EACnC;AAAA,EAAS;AAAA,EAAO;AAAA,EAAU;AAAA,EAAU;AAAA,EAAa;AAAA,EAAa;AAAA,EAAQ;AAAA,EAAa;AAAA,EAAS;AAC9F;AAEA,SAAS,YAAY,QAAyD;AAC5E,SAAO,OAAO,IAAI,6BAA6B,EAAE,KAAK,CAAC,MAAM,EAAE,IAA+B;AAChG;AAEA,SAAS,YAAY,QAAuB,SAAoD;AAC9F,SAAO,OAAO,IAAI,+BAA+B,OAAO,EAAE,KAAK,CAAC,MAAM,EAAE,IAAI;AAC9E;AAGA,SAAS,iBAAiB,SAA0B;AAClD,QAAM,UAAU,KAAK,IAAI,GAAG,QAAQ,OAAO,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC;AAC/D,SAAO;AAAA,IACL,QAAQ;AAAA,IACR;AAAA,IACA,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA,GAAG,QAAQ,OAAO,IAAI,CAAC,MAAM,KAAK,EAAE,OAAO,OAAO,CAAC,KAAK,QAAQ,UAAU,CAAC,KAAK,EAAE,EAAE;AAAA,IACpF;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAEA,SAAS,qBAAqB,UAAmB,SAAwB;AACvE,QAAM,MAAM,SACT,QAAQ,QAAQ,IAAI,EACpB,YAAY,iBAAiB,OAAO,CAAC;AAExC,MACG,QAAQ,KAAK,EACb,YAAY,kBAAkB,QAAQ,IAAI,iCAAiC,EAC3E,OAAO,YAAY;AAClB,QAAI;AACF,YAAM,SAASC,eAAc,GAAG;AAChC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,MAAM,MAAM,YAAY,MAAM;AACpC,aAAO,SAAS,KAAK,QAAQ,MAAM,GAAG,MAAM;AAAA,IAC9C,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAEH,QAAM,SAAS,IACZ,QAAQ,KAAK,EACb;AAAA,IACC,cAAc,QAAQ,IAAI;AAAA;AAAA;AAAA,EAG5B,EACC,OAAO,sBAAsB,6CAA6C,EAC1E,OAAO,sBAAsB,yCAAyC;AAEzE,aAAW,SAAS,QAAQ,QAAQ;AAClC,WAAO,OAAO,KAAK,MAAM,KAAK,CAAC,YAAY,QAAQ,UAAU,KAAK,KAAK,KAAK;AAAA,EAC9E;AAEA,SAAO,OAAO,OAAO,SAAS;AAC5B,QAAI;AACF,YAAM,SAASA,eAAc,GAAG;AAChC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAElD,YAAM,aAAsC,CAAC;AAC7C,iBAAW,SAAS,QAAQ,QAAQ;AAClC,cAAM,MAAM,KAAK,KAAK;AACtB,YAAI,QAAQ,OAAW,YAAW,KAAK,IAAI,YAAY,OAAO,GAAG,CAAC;AAAA,MACpE;AACA,YAAM,UAAU,aAAa,YAAY,KAAK,KAAK,KAAK,UAAU,QAAQ,MAAM;AAChF,UAAI,OAAO,KAAK,OAAO,EAAE,WAAW,GAAG;AACrC,oBAAY,IAAI,MAAM,uDAAuD,CAAC;AAC9E;AAAA,MACF;AAEA,YAAM,UAAU,MAAM,YAAY,MAAM;AACxC,YAAM,SAAS,EAAE,GAAG,SAAS,GAAG,QAAQ;AACxC,YAAM,MAAM,MAAM,YAAY,QAAQ,MAAM;AAC5C,aAAO,SAAS,KAAgC,QAAQ,MAAM,GAAG,MAAM;AAAA,IACzE,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAED,MACG,QAAQ,MAAM,EACd,YAAY,uBAAuB,QAAQ,IAAI,4DAA4D,EAC3G,OAAO,YAAY;AAClB,QAAI;AACF,YAAM,SAASA,eAAc,GAAG;AAChC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,UAAU,MAAM,YAAY,MAAM;AACxC,YAAM,SAAS,SAAS,SAAS,QAAQ,MAAM;AAC/C,YAAM,SAAS,SAAS,QAAQ,YAAY,QAAQ,IAAI,EAAE;AAC1D,YAAM,SAAS,EAAE,GAAG,SAAS,GAAG,OAAO;AACvC,YAAM,MAAM,MAAM,YAAY,QAAQ,MAAM;AAC5C,aAAO,SAAS,KAAgC,QAAQ,MAAM,GAAG,MAAM;AAAA,IACzE,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AACL;AAEO,SAAS,yBAAyB,WAA0B;AACjE,QAAM,WAAW,UACd,QAAQ,UAAU,EAClB;AAAA,IACC,kjBASA,SAAS,IAAI,CAAC,MAAM,KAAK,EAAE,KAAK,OAAO,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,KAAK,IAAI,IAAI;AAAA,EAKxE;AAEF,WACG,QAAQ,KAAK,EACb,YAAY,sEAAsE,EAClF,OAAO,YAAY;AAClB,QAAI;AACF,YAAM,SAASA,eAAc,QAAQ;AACrC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,OAAO,MAAM,YAAY,MAAM;AACrC,aAAO,MAAM,MAAM;AAAA,IACrB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAEH,WACG,QAAQ,QAAQ,EAChB,YAAY,2EAA2E,EACvF,OAAO,sBAAsB,6CAA6C,EAC1E,OAAO,sBAAsB,yCAAyC,EACtE,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASA,eAAc,QAAQ;AACrC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,UAAU,aAAa,CAAC,GAAG,KAAK,KAAK,KAAK,QAAQ;AACxD,UAAI,OAAO,KAAK,OAAO,EAAE,WAAW,GAAG;AACrC,oBAAY,IAAI,MAAM,+CAA+C,CAAC;AACtE;AAAA,MACF;AACA,YAAM,UAAU,MAAM,YAAY,MAAM;AACxC,YAAM,MAAM,MAAM,YAAY,QAAQ,EAAE,GAAG,SAAS,GAAG,QAAQ,CAAC;AAChE,aAAO,KAAK,MAAM;AAAA,IACpB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAEH,WACG,QAAQ,QAAQ,EAChB,YAAY,oDAAqD,EACjE,OAAO,YAAY;AAClB,QAAI;AACF,YAAM,SAASA,eAAc,QAAQ;AACrC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,MAAM,MAAM,OAAO,OAAO,6BAA6B;AAC7D,aAAO,IAAI,MAAM,MAAM;AAAA,IACzB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAEH,WACG,QAAQ,cAAc,EACtB;AAAA,IACC;AAAA,EAEF,EACC,eAAe,sBAAsB,0BAA0B,EAC/D,OAAO,mBAAmB,2BAA2B,EACrD,OAAO,eAAe,qBAAqB,EAC3C,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASA,eAAc,QAAQ;AACrC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,SAAiC,CAAC;AACxC,UAAI,KAAK,MAAO,QAAO,QAAQ,KAAK;AACpC,UAAI,KAAK,IAAK,QAAO,MAAM,KAAK;AAChC,YAAM,MAAM,MAAM,OAAO;AAAA,QACvB,uCAAuC,KAAK,SAAS;AAAA,QACrD,CAAC;AAAA,QACD,EAAE,QAAQ,SAAS,EAAE,iBAAiB,KAAK,UAAU,EAAE;AAAA,MACzD;AACA,aAAO,IAAI,MAAM,MAAM;AAAA,IACzB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAEH,aAAW,WAAW,SAAU,sBAAqB,UAAU,OAAO;AACxE;;;ACtbA,IAAM,iBAAiB;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEO,SAAS,gCAAgC,YAA2B;AACzE,QAAM,YAAY,WACf,QAAQ,WAAW,EACnB;AAAA,IACC;AAAA,EASF;AAEF,YACG,QAAQ,KAAK,EACb,YAAY,yEAAyE,EACrF,OAAO,qBAAqB,4DAA4D,EACxF,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASC,eAAc,SAAS;AACtC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,SAAiC,CAAC;AACxC,UAAI,KAAK,eAAgB,QAAO,gBAAgB;AAChD,YAAM,MAAM,MAAM,OAAO,IAAI,qCAAqC,EAAE,OAAO,CAAC;AAC5E,aAAO,IAAI,MAAM,MAAM;AAAA,IACzB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAEH,YACG,QAAQ,QAAQ,EAChB;AAAA,IACC,iMAGO,eAAe,KAAK,IAAI;AAAA,EACjC,EACC,eAAe,gBAAgB,4CAA4C,EAC3E,OAAO,oBAAoB,wCAAwC,MAAM,EACzE,OAAO,uBAAuB,sCAAsC,EACpE,OAAO,0BAA0B,eAAe,EAChD,OAAO,mCAAmC,yCAAyC,EACnF,OAAO,qCAAqC,sBAAsB,EAClE,OAAO,4BAA4B,aAAa,EAChD,OAAO,uCAAuC,0BAA0B,EACxE,OAAO,wCAAwC,iCAAiC,EAChF,OAAO,0BAA0B,4BAA4B,EAC7D,OAAO,qBAAqB,6CAA6C,EACzE,OAAO,sBAAsB,wDAAwD,EACrF,OAAO,sBAAsB,iCAAiC,EAC9D,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASA,eAAc,SAAS;AACtC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAElD,YAAM,aAAsC;AAAA,QAC1C,cAAc,KAAK;AAAA,QACnB,SAAS,KAAK,YAAY,SAAY,SAAY,KAAK,YAAY,QAAQ,KAAK,YAAY;AAAA,QAC5F,WAAW,KAAK;AAAA,QAChB,cAAc,KAAK;AAAA,QACnB,qBAAqB,KAAK;AAAA,QAC1B,wBAAwB,KAAK;AAAA,QAC7B,gBAAgB,KAAK;AAAA,QACrB,wBAAwB,KAAK;AAAA,QAC7B,0BAA0B,KAAK;AAAA,QAC/B,cAAc,KAAK;AAAA,MACrB;AACA,YAAM,UAAU,aAAa,YAAY,KAAK,KAAK,KAAK,UAAU,cAAc;AAEhF,YAAM,SAAiC,CAAC;AACxC,UAAI,KAAK,eAAgB,QAAO,gBAAgB;AAChD,YAAM,MAAM,MAAM,OAAO,KAAK,iCAAiC,SAAS,EAAE,OAAO,CAAC;AAClF,aAAO,IAAI,MAAM,MAAM;AAAA,IACzB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAEH,YACG,QAAQ,4BAA4B,EACpC,YAAY,mDAAmD,EAC/D,OAAO,sBAAsB,wDAAwD,EACrF,OAAO,sBAAsB,iCAAiC,EAC9D,OAAO,uBAAuB,YAAY,EAC1C,OAAO,0BAA0B,eAAe,EAChD,OAAO,oBAAoB,sCAAsC,EACjE,OAAO,gCAAgC,uBAAuB,EAC9D,OAAO,OAAO,mBAAmB,SAAS;AACzC,QAAI;AACF,YAAM,SAASA,eAAc,SAAS;AACtC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAElD,YAAM,aAAsC;AAAA,QAC1C,WAAW,KAAK;AAAA,QAChB,cAAc,KAAK;AAAA,QACnB,SAAS,KAAK,YAAY,SAAY,SAAY,KAAK,YAAY,QAAQ,KAAK,YAAY;AAAA,QAC5F,mBAAmB,KAAK,sBAAsB,SAAY,SAAY,KAAK,sBAAsB,QAAQ,KAAK,sBAAsB;AAAA,MACtI;AACA,YAAM,UAAU,aAAa,YAAY,KAAK,KAAK,KAAK,UAAU,cAAc;AAChF,UAAI,OAAO,KAAK,OAAO,EAAE,WAAW,GAAG;AACrC,oBAAY,IAAI,MAAM,sBAAsB,CAAC;AAC7C;AAAA,MACF;AAEA,YAAM,MAAM,MAAM,OAAO,IAAI,iCAAiC,iBAAiB,IAAI,OAAO;AAC1F,aAAO,IAAI,MAAM,MAAM;AAAA,IACzB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAEH,YACG,QAAQ,MAAM,EACd,YAAY,8EAA8E,EAC1F,OAAO,YAAY;AAClB,QAAI;AACF,YAAM,SAASA,eAAc,SAAS;AACtC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,UAAU,MAAM,OAAO,IAAI,mCAAmC;AACpE,YAAM,MAAM,QAAQ;AACpB,YAAM,KAAK,KAAK;AAChB,UAAI,CAAC,IAAI;AACP,oBAAY,IAAI,MAAM,gEAAgE,CAAC;AACvF;AAAA,MACF;AACA,YAAM,SAAS,SAAS,KAAK,cAAc;AAC3C,YAAM,SAAS,SAAS,QAAQ,WAAW;AAC3C,YAAM,MAAM,MAAM,OAAO,IAAI,iCAAiC,EAAE,IAAI,MAAM;AAC1E,aAAO,IAAI,MAAM,MAAM;AAAA,IACzB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAEH,2BAAyB,SAAS;AACpC;;;AC7KO,SAAS,uBAAuBC,UAAwB;AAC7D,QAAM,MAAMA,SACT,QAAQ,QAAQ,EAChB;AAAA,IACC;AAAA,EAEF;AAEF,MACG,QAAQ,mBAAmB,EAC3B,YAAY,+DAA+D,EAC3E,OAAO,oBAAoB,mBAAmB,EAC9C,OAAO,CAAC,KAAK,OAAO,SAAS;AAC5B,QAAI;AACF,UAAI,QAAQ,iBAAiB;AAC3B,cAAM,SAAS,WAAW;AAC1B,eAAO,gBAAgB;AACvB,mBAAW,MAAM;AAAA,MACnB,OAAO;AACL,uBAAe,KAAK,OAAO,KAAK,OAAO;AAAA,MACzC;AACA,aAAO,EAAE,SAAS,MAAM,KAAK,MAAM,CAAC;AAAA,IACtC,SAAS,KAAK;AACZ,kBAAY,GAAG;AAAA,IACjB;AAAA,EACF,CAAC;AAEH,MACG,QAAQ,WAAW,EACnB,YAAY,2BAA2B,EACvC,OAAO,oBAAoB,sBAAsB,EACjD,OAAO,CAAC,KAAK,SAAS;AACrB,QAAI;AACF,UAAI,QAAQ,iBAAiB;AAC3B,cAAM,SAAS,WAAW;AAC1B,eAAO,EAAE,eAAe,OAAO,cAAc,CAAC;AAAA,MAChD,OAAO;AACL,eAAO,EAAE,CAAC,GAAG,GAAG,eAAe,KAAK,KAAK,OAAO,EAAE,CAAC;AAAA,MACrD;AAAA,IACF,SAAS,KAAK;AACZ,kBAAY,GAAG;AAAA,IACjB;AAAA,EACF,CAAC;AAEH,MACG,QAAQ,MAAM,EACd,YAAY,wBAAwB,EACpC,OAAO,MAAM;AACZ,QAAI;AACF,YAAM,SAAS,WAAW;AAE1B,YAAM,OAAO,KAAK,MAAM,KAAK,UAAU,MAAM,CAAC;AAC9C,iBAAW,CAAC,MAAM,OAAO,KAAK,OAAO,QAAQ,KAAK,QAAQ,GAAG;AAC3D,cAAM,IAAI;AACV,YAAI,EAAE,MAAO,GAAE,QAAS,EAAE,MAAiB,MAAM,GAAG,EAAE,IAAI;AAAA,MAC5D;AACA,aAAO,IAAI;AAAA,IACb,SAAS,KAAK;AACZ,kBAAY,GAAG;AAAA,IACjB;AAAA,EACF,CAAC;AAEH,MACG,QAAQ,uBAAuB,EAC/B,YAAY,sBAAsB,EAClC,OAAO,kBAAkB,kBAAkB,2BAA2B,EACtE,OAAO,CAAC,MAAM,SAAS;AACtB,QAAI;AACF,YAAM,SAAS,WAAW;AAC1B,UAAI,OAAO,SAAS,IAAI,GAAG;AACzB,oBAAY,IAAI,MAAM,YAAY,IAAI,kBAAkB,CAAC;AACzD;AAAA,MACF;AACA,aAAO,SAAS,IAAI,IAAI,EAAE,QAAQ,KAAK,OAAO;AAC9C,iBAAW,MAAM;AACjB,aAAO,EAAE,SAAS,MAAM,SAAS,MAAM,QAAQ,KAAK,OAAO,CAAC;AAAA,IAC9D,SAAS,KAAK;AACZ,kBAAY,GAAG;AAAA,IACjB;AAAA,EACF,CAAC;AAEH,MACG,QAAQ,YAAY,EACpB,YAAY,qBAAqB,EACjC,OAAO,CAAC,SAAS;AAChB,QAAI;AACF,YAAM,SAAS,WAAW;AAC1B,UAAI,CAAC,OAAO,SAAS,IAAI,GAAG;AAC1B,oBAAY,IAAI,MAAM,YAAY,IAAI,2BAA2B,OAAO,KAAK,OAAO,QAAQ,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;AAC3G;AAAA,MACF;AACA,aAAO,gBAAgB;AACvB,iBAAW,MAAM;AACjB,aAAO,EAAE,SAAS,MAAM,eAAe,KAAK,CAAC;AAAA,IAC/C,SAAS,KAAK;AACZ,kBAAY,GAAG;AAAA,IACjB;AAAA,EACF,CAAC;AAEH,wBAAsB,GAAG;AACzB,kCAAgC,GAAG;AACrC;;;AC3GA,SAAS,eAAe;AA6BxB,SAASC,eAAc,KAAwG;AAC7H,MAAI,OAAO;AACX,SAAO,KAAK,OAAQ,QAAO,KAAK;AAChC,SAAO,KAAK,KAAK;AACnB;AAEA,SAAS,UAAU,MAA+D;AAChF,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI,SAAS,KAAK;AAEhB,UAAM,EAAE,cAAAC,cAAa,IAAI,UAAQ,IAAI;AACrC,UAAM,QAAQA,cAAa,GAAG,OAAO;AACrC,WAAO,KAAK,MAAM,KAAK;AAAA,EACzB;AACA,SAAO,KAAK,MAAM,IAAI;AACxB;AAEO,SAAS,uBAAuB,KAA8B;AACnE,QAAM,MAAM,IAAI,QAAQ,IAAI,IAAI,EAAE,YAAY,UAAU,IAAI,QAAQ,GAAG;AACvE,QAAM,UAAU,IAAI,WAAW;AAG/B,MACG,QAAQ,MAAM,EACd,YAAY,QAAQ,IAAI,QAAQ,8BAA8B,IAAI,WAAW,KAAK,IAAI,CAAC,EAAE,EACzF,OAAO,eAAe,eAAe,IAAI,EACzC,OAAO,gBAAgB,gBAAgB,GAAG,EAC1C,OAAO,iBAAiB,sCAAsC,EAC9D,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASD,eAAc,GAAG;AAChC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,SAAkC;AAAA,QACtC,OAAO,SAAS,KAAK,KAAK;AAAA,QAC1B,QAAQ,SAAS,KAAK,MAAM;AAAA,MAC9B;AACA,UAAI,CAAC,KAAK,WAAY,QAAO,WAAW;AAExC,YAAM,MAAM,MAAM,OAAO,IAAI,IAAI,UAAU,EAAE,OAAO,CAAC;AAErD,UAAI;AACJ,UAAI;AACJ,UAAI,MAAM,QAAQ,IAAI,IAAI,KAAK,IAAI,KAAK,UAAU,KAAK,MAAM,QAAQ,IAAI,KAAK,CAAC,CAAC,KAAK,OAAO,IAAI,KAAK,CAAC,MAAM,UAAU;AAEpH,eAAO,IAAI,KAAK,CAAC;AACjB,gBAAQ,IAAI,KAAK,CAAC;AAAA,MACpB,WAAW,MAAM,QAAQ,IAAI,IAAI,GAAG;AAClC,eAAO,IAAI;AACX,gBAAQ,IAAI,KAAK;AAAA,MACnB,OAAO;AACL,eAAO,IAAI,MAAM,QAAQ,CAAC;AAC1B,gBAAQ,IAAI,MAAM,SAAS,KAAK;AAAA,MAClC;AAGA,YAAM,UAAyB,EAAE,GAAG,OAAO;AAC3C,UAAI,CAAC,OAAO,UAAU,IAAI,WAAW,SAAS,GAAG;AAC/C,gBAAQ,SAAS,CAAC,IAAI,SAAS,GAAG,IAAI,UAAU,EAAE,KAAK,GAAG;AAAA,MAC5D;AAEA,UAAI,MAAM,QAAQ,IAAI,GAAG;AACvB,wBAAgB,MAAM,OAAO,SAAS,KAAK,KAAK,GAAG,SAAS,KAAK,MAAM,GAAG,OAAO;AAAA,MACnF,OAAO;AACL,eAAO,MAAM,OAAO;AAAA,MACtB;AAAA,IACF,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAGH,MACG,QAAQ,UAAU,EAClB,YAAY,SAAS,IAAI,QAAQ,yCAAyC,EAC1E,OAAO,OAAO,OAAO;AACpB,QAAI;AACF,YAAM,SAASA,eAAc,GAAG;AAChC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,UAAI,IAAI,cAAc;AAEpB,cAAM,MAAM,MAAM,OAAO,IAAI,IAAI,UAAU,EAAE,QAAQ,EAAE,UAAU,KAAK,EAAE,CAAC;AACzE,cAAM,MAAM,MAAM,QAAQ,IAAI,IAAI,IAAI,IAAI,OAAQ,MAAM,QAAQ,IAAI,OAAO,CAAC,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,IAAI,MAAM,QAAQ,CAAC;AAClH,cAAM,QAAQ,SAAS,EAAE;AACzB,cAAM,OAAO,IAAI,KAAK,CAAC,MAA+B,EAAE,IAAI,OAAO,MAAM,SAAS,EAAE,IAAI,OAAO,MAAM,EAAE;AACvG,YAAI,CAAC,MAAM;AAAE,sBAAY,IAAI,MAAM,GAAG,IAAI,QAAQ,SAAS,IAAI,OAAO,IAAI,EAAE,YAAY,CAAC;AAAG;AAAA,QAAQ;AACpG,eAAO,MAAM,MAAM;AAAA,MACrB,OAAO;AACL,cAAM,MAAM,IAAI,UAAU,IAAI,QAAQ,QAAQ,OAAO,EAAE,IAAI,GAAG,IAAI,QAAQ,IAAI,EAAE;AAChF,cAAM,MAAM,MAAM,OAAO,IAAI,GAAG;AAChC,eAAO,IAAI,MAAM,MAAM;AAAA,MACzB;AAAA,IACF,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAGH,MACG,QAAQ,QAAQ,EAChB,YAAY,gBAAgB,IAAI,QAAQ,4CAA4C,EACpF,eAAe,iBAAiB,4BAA4B,EAC5D,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASA,eAAc,GAAG;AAChC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,OAAO,UAAU,KAAK,IAAI;AAChC,YAAM,MAAM,MAAM,OAAO,KAAK,IAAI,UAAU,IAAI;AAChD,aAAO,IAAI,MAAM,MAAM;AAAA,IACzB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAGH,MACG,QAAQ,aAAa,EACrB,YAAY,YAAY,IAAI,QAAQ,EAAE,EACtC,eAAe,iBAAiB,kDAAkD,EAClF,OAAO,OAAO,IAAI,SAAS;AAC1B,QAAI;AACF,YAAM,SAASA,eAAc,GAAG;AAChC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,OAAO,UAAU,KAAK,IAAI;AAChC,UAAI,IAAI,aAAa;AACnB,cAAM,MAAM,MAAM,OAAO,IAAI,IAAI,UAAU,EAAE,GAAG,MAAM,CAAC,IAAI,OAAO,GAAG,GAAG,CAAC;AACzE,eAAO,IAAI,MAAM,MAAM;AAAA,MACzB,OAAO;AACL,cAAM,MAAM,MAAM,OAAO,IAAI,GAAG,IAAI,QAAQ,IAAI,EAAE,IAAI,IAAI;AAC1D,eAAO,IAAI,MAAM,MAAM;AAAA,MACzB;AAAA,IACF,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAGH,MACG,QAAQ,aAAa,EACrB,YAAY,YAAY,IAAI,QAAQ,EAAE,EACtC,OAAO,OAAO,OAAO;AACpB,QAAI;AACF,YAAM,SAASA,eAAc,GAAG;AAChC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,MAAM,MAAM,OAAO,OAAO,GAAG,IAAI,QAAQ,IAAI,EAAE,EAAE;AACvD,aAAO,IAAI,QAAQ,EAAE,SAAS,MAAM,SAAS,GAAG,GAAG,MAAM;AAAA,IAC3D,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAGH,MAAI,IAAI,iBAAiB;AACvB,QACG,QAAQ,cAAc,EACtB,YAAY,gBAAgB,IAAI,QAAQ,GAAG,EAC3C,eAAe,eAAe,qBAAqB,EACnD,OAAO,OAAO,SAAS;AACtB,UAAI;AACF,cAAM,SAASA,eAAc,GAAG;AAChC,cAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,cAAM,MAAM,KAAK,IAAI,MAAM,GAAG,EAAE,IAAI,CAAC,MAAc,EAAE,KAAK,CAAC;AAC3D,cAAM,MAAM,MAAM,OAAO,KAAK,GAAG,IAAI,QAAQ,IAAI,IAAI,eAAe,IAAI,GAAG;AAC3E,eAAO,IAAI,QAAQ,EAAE,SAAS,MAAM,SAAS,IAAI,OAAO,GAAG,MAAM;AAAA,MACnE,SAAS,KAAK;AACZ,oBAAY,eAAe,GAAG,CAAC;AAAA,MACjC;AAAA,IACF,CAAC;AAAA,EACL;AAGA,MACG,QAAQ,QAAQ,EAChB,YAAY,uBAAuB,IAAI,QAAQ,+BAA+B,EAC9E,eAAe,kBAAkB,oCAAoC,EACrE,OAAO,eAAe,eAAe,IAAI,EACzC,OAAO,gBAAgB,gBAAgB,GAAG,EAC1C,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASA,eAAc,GAAG;AAChC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,QAAQ,UAAU,KAAK,KAAK;AAClC,YAAM,YAAY,IAAI,cAAc,GAAG,IAAI,QAAQ;AACnD,YAAM,MAAM,MAAM,OAAO,KAAK,WAAW;AAAA,QACvC,GAAG;AAAA,QACH,OAAO,SAAS,KAAK,KAAK;AAAA,QAC1B,QAAQ,SAAS,KAAK,MAAM;AAAA,MAC9B,CAAC;AACD,YAAM,OAAO,MAAM,QAAQ,IAAI,IAAI,IAAI,IAAI,OAAO,IAAI,MAAM,QAAQ,IAAI;AACxE,YAAM,QAAQ,IAAI,MAAM,UAAU,MAAM,QAAQ,IAAI,IAAI,KAAK,SAAS;AACtE,sBAAgB,MAAM,OAAO,SAAS,KAAK,KAAK,GAAG,SAAS,KAAK,MAAM,GAAG,MAAM;AAAA,IAClF,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAEH,SAAO;AACT;;;AC5NA,SAASE,eAAc,KAAuD;AAC5E,MAAI,OAAO;AACX,SAAO,KAAK,OAAQ,QAAO,KAAK;AAChC,SAAO,KAAK,KAAK;AACnB;AAEA,SAASC,WAAU,MAAuC;AACxD,MAAI,SAAS,KAAK;AAChB,UAAM,EAAE,cAAAC,cAAa,IAAI,UAAQ,IAAI;AACrC,WAAO,KAAK,MAAMA,cAAa,GAAG,OAAO,CAAC;AAAA,EAC5C;AACA,SAAO,KAAK,MAAM,IAAI;AACxB;AAEO,SAAS,qBAAqB,WAA0B;AAE7D,QAAM,OAAO,uBAAuB;AAAA,IAClC,MAAM;AAAA,IACN,UAAU;AAAA,IACV,UAAU;AAAA,IACV,SAAS;AAAA,IACT,YAAY,CAAC,cAAc,aAAa,eAAe,kBAAkB,SAAS,cAAc,eAAe,QAAQ;AAAA,IACvH,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,cAAc;AAAA,EAChB,CAAC;AAGD,QAAM,gBAAgB,KAAK,SAAS,UAAU,CAAC,MAAe,EAAE,KAAK,MAAM,QAAQ;AACnF,MAAI,kBAAkB,GAAI,MAAK,SAAS,OAAO,eAAe,CAAC;AAG/D,OACG,QAAQ,iBAAiB,EACzB,YAAY,oCAAoC,EAChD,OAAO,OAAO,UAAU;AACvB,QAAI;AACF,YAAM,SAASF,eAAc,IAAI;AACjC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,MAAM,MAAM,OAAO,IAAI,uBAAuB,KAAK,EAAE;AAC3D,aAAO,IAAI,QAAQ,EAAE,SAAS,MAAM,UAAU,MAAM,GAAG,MAAM;AAAA,IAC/D,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAGH,QAAM,YAAY,KAAK,QAAQ,QAAQ,EAAE,YAAY,yBAAyB;AAE9E,YACG,QAAQ,MAAM,EACd,YAAY,4GAA4G,EACxH,OAAO,eAAe,eAAe,IAAI,EACzC,OAAO,gBAAgB,gBAAgB,GAAG,EAC1C,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASA,eAAc,IAAI;AACjC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,MAAM,MAAM,OAAO,IAAI,4BAA4B,EAAE,QAAQ,EAAE,OAAO,KAAK,OAAO,QAAQ,KAAK,OAAO,EAAE,CAAC;AAC/G,aAAO,IAAI,MAAM,MAAM;AAAA,IACzB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAEH,YACG,QAAQ,UAAU,EAClB,YAAY,6BAA6B,EACzC,OAAO,OAAO,OAAO;AACpB,QAAI;AACF,YAAM,SAASA,eAAc,IAAI;AACjC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAElD,YAAM,MAAM,MAAM,OAAO,KAAK,mCAAmC,EAAE,iBAAiB,GAAG,CAAC;AACxF,YAAM,OAAO,MAAM,QAAQ,IAAI,IAAI,IAAI,IAAI,KAAK,CAAC,IAAI,IAAI,MAAM,OAAO,CAAC,KAAK,IAAI;AAChF,aAAO,MAAM,MAAM;AAAA,IACrB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAEH,YACG,QAAQ,QAAQ,EAChB,YAAY,0BAA0B,EACtC,eAAe,iBAAiB,WAAW,EAC3C,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASA,eAAc,IAAI;AACjC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,MAAM,MAAM,OAAO,KAAK,4BAA4BC,WAAU,KAAK,IAAI,CAAC;AAC9E,aAAO,IAAI,MAAM,MAAM;AAAA,IACzB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAEH,YACG,QAAQ,aAAa,EACrB,YAAY,0BAA0B,EACtC,eAAe,iBAAiB,WAAW,EAC3C,OAAO,OAAO,IAAI,SAAS;AAC1B,QAAI;AACF,YAAM,SAASD,eAAc,IAAI;AACjC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,MAAM,MAAM,OAAO,IAAI,4BAA4B,EAAE,IAAIC,WAAU,KAAK,IAAI,CAAC;AACnF,aAAO,IAAI,MAAM,MAAM;AAAA,IACzB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAEH,YACG,QAAQ,aAAa,EACrB,YAAY,0BAA0B,EACtC,OAAO,OAAO,OAAO;AACpB,QAAI;AACF,YAAM,SAASD,eAAc,IAAI;AACjC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,MAAM,MAAM,OAAO,OAAO,4BAA4B,EAAE,EAAE;AAChE,aAAO,IAAI,QAAQ,EAAE,SAAS,MAAM,SAAS,GAAG,GAAG,MAAM;AAAA,IAC3D,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAEH,YACG,QAAQ,uBAAuB,EAC/B,YAAY,6CAA6C,EACzD,OAAO,OAAO,eAAe;AAC5B,QAAI;AACF,YAAM,SAASA,eAAc,IAAI;AACjC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,MAAM,MAAM,OAAO,IAAI,kDAAkD,UAAU,EAAE;AAC3F,aAAO,IAAI,MAAM,MAAM;AAAA,IACzB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAGH,QAAM,eAAe,KAAK,QAAQ,WAAW,EAAE,YAAY,sBAAsB;AAEjF,eACG,QAAQ,MAAM,EACd,YAAY,0GAA0G,EACtH,OAAO,eAAe,eAAe,IAAI,EACzC,OAAO,gBAAgB,gBAAgB,GAAG,EAC1C,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASA,eAAc,IAAI;AACjC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,MAAM,MAAM,OAAO,IAAI,yBAAyB,EAAE,QAAQ,EAAE,OAAO,KAAK,OAAO,QAAQ,KAAK,OAAO,EAAE,CAAC;AAC5G,aAAO,IAAI,MAAM,MAAM;AAAA,IACzB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAEH,eACG,QAAQ,QAAQ,EAChB,YAAY,uBAAuB,EACnC,eAAe,iBAAiB,WAAW,EAC3C,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASA,eAAc,IAAI;AACjC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,MAAM,MAAM,OAAO,KAAK,yBAAyBC,WAAU,KAAK,IAAI,CAAC;AAC3E,aAAO,IAAI,MAAM,MAAM;AAAA,IACzB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAEH,eACG,QAAQ,aAAa,EACrB,YAAY,uBAAuB,EACnC,eAAe,iBAAiB,WAAW,EAC3C,OAAO,OAAO,IAAI,SAAS;AAC1B,QAAI;AACF,YAAM,SAASD,eAAc,IAAI;AACjC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,MAAM,MAAM,OAAO,IAAI,yBAAyB,EAAE,IAAIC,WAAU,KAAK,IAAI,CAAC;AAChF,aAAO,IAAI,MAAM,MAAM;AAAA,IACzB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAEH,eACG,QAAQ,aAAa,EACrB,YAAY,uBAAuB,EACnC,OAAO,OAAO,OAAO;AACpB,QAAI;AACF,YAAM,SAASD,eAAc,IAAI;AACjC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,MAAM,MAAM,OAAO,OAAO,yBAAyB,EAAE,EAAE;AAC7D,aAAO,IAAI,QAAQ,EAAE,SAAS,MAAM,SAAS,GAAG,GAAG,MAAM;AAAA,IAC3D,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAEH,eACG,QAAQ,0BAA0B,EAClC,YAAY,gDAAgD,EAC5D,OAAO,OAAO,kBAAkB;AAC/B,QAAI;AACF,YAAM,SAASA,eAAc,IAAI;AACjC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,MAAM,MAAM,OAAO,IAAI,+CAA+C,aAAa,EAAE;AAC3F,aAAO,IAAI,MAAM,MAAM;AAAA,IACzB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAGH,QAAM,eAAe,KAAK,QAAQ,WAAW,EAAE,YAAY,sBAAsB;AAEjF,eACG,QAAQ,MAAM,EACd,YAAY,yFAAyF,EACrG,OAAO,eAAe,eAAe,IAAI,EACzC,OAAO,gBAAgB,gBAAgB,GAAG,EAC1C,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASA,eAAc,IAAI;AACjC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,MAAM,MAAM,OAAO,IAAI,yBAAyB,EAAE,QAAQ,EAAE,OAAO,KAAK,OAAO,QAAQ,KAAK,OAAO,EAAE,CAAC;AAC5G,aAAO,IAAI,MAAM,MAAM;AAAA,IACzB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAEH,eACG,QAAQ,QAAQ,EAChB,YAAY,sBAAsB,EAClC,eAAe,iBAAiB,WAAW,EAC3C,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASA,eAAc,IAAI;AACjC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,MAAM,MAAM,OAAO,KAAK,yBAAyBC,WAAU,KAAK,IAAI,CAAC;AAC3E,aAAO,IAAI,MAAM,MAAM;AAAA,IACzB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAEH,eACG,QAAQ,aAAa,EACrB,YAAY,sBAAsB,EAClC,OAAO,OAAO,OAAO;AACpB,QAAI;AACF,YAAM,SAASD,eAAc,IAAI;AACjC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,MAAM,MAAM,OAAO,OAAO,yBAAyB,EAAE,EAAE;AAC7D,aAAO,IAAI,QAAQ,EAAE,SAAS,MAAM,SAAS,GAAG,GAAG,MAAM;AAAA,IAC3D,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAGH,OACG,QAAQ,UAAU,EAClB;AAAA,IACC;AAAA,EAQF,EACC,eAAe,uBAAuB,qBAAqB,EAC3D,OAAO,wBAAwB,gCAAgC,EAC/D,OAAO,8BAA8B,iCAAiC,EACtE,OAAO,yBAAyB,uCAAuC,EACvE,OAAO,sBAAsB,oBAAoB,IAAI,EACrD,OAAO,yBAAyB,uBAAuB,GAAG,EAC1D,OAAO,yBAAyB,uBAAuB,GAAG,EAC1D,OAAO,qBAAqB,wBAAwB,EACpD,eAAe,iBAAiB,6BAA6B,EAC7D,OAAO,kBAAkB,sCAAsC,cAAc,EAC7E,OAAO,cAAc,mBAAmB,EACxC,OAAO,iBAAiB,0BAA0B,IAAI,EACtD,OAAO,6BAA6B,yCAAyC,qBAAqB,CAAC,CAAC,EACpG,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASA,eAAc,IAAI;AACjC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAGlD,YAAM,mBAA6B,CAAC;AAEpC,UAAI,KAAK,OAAO;AACd,YAAI;AACF,gBAAMG,OAAM,MAAM,OAAO,KAAK,mCAAmC,EAAE,iBAAiB,SAAS,KAAK,KAAK,EAAE,CAAC;AAC1G,gBAAM,OAAO,MAAM,QAAQA,KAAI,IAAI,IAAIA,KAAI,OAAOA,KAAI,MAAM,QAAQ,CAAC;AACrE,cAAI,KAAK,WAAW,GAAG;AACrB,6BAAiB;AAAA,cACf,YAAY,KAAK,KAAK;AAAA,YAGxB;AAAA,UACF;AAAA,QACF,QAAQ;AACN,2BAAiB;AAAA,YACf,+BAA+B,KAAK,KAAK;AAAA,UAG3C;AAAA,QACF;AAAA,MACF;AAEA,UAAI,KAAK,UAAU;AACjB,YAAI;AACF,gBAAMA,OAAM,MAAM,OAAO,IAAI,yBAAyB,EAAE,QAAQ,EAAE,OAAO,IAAI,EAAE,CAAC;AAChF,gBAAM,YAAY,MAAM,QAAQA,KAAI,IAAI,IAAIA,KAAI,OAAOA,KAAI,MAAM,QAAQ,CAAC;AAC1E,gBAAM,QAAQ,UAAU;AAAA,YAAK,CAAC,QAC5B,OAAO,IAAI,aAAa,MAAM,OAAO,KAAK,QAAQ;AAAA,UACpD;AACA,cAAI,CAAC,OAAO;AACV,6BAAiB;AAAA,cACf,eAAe,KAAK,QAAQ;AAAA,YAG9B;AAAA,UACF;AAAA,QACF,QAAQ;AACN,2BAAiB;AAAA,YACf,kCAAkC,KAAK,QAAQ;AAAA,UAGjD;AAAA,QACF;AAAA,MACF;AAEA,UAAI,KAAK,SAAS;AAChB,YAAI;AACF,gBAAMA,OAAM,MAAM,OAAO,IAAI,yBAAyB,EAAE,QAAQ,EAAE,OAAO,IAAI,EAAE,CAAC;AAChF,gBAAM,YAAY,MAAM,QAAQA,KAAI,IAAI,IAAIA,KAAI,OAAOA,KAAI,MAAM,QAAQ,CAAC;AAC1E,gBAAM,QAAQ,UAAU;AAAA,YAAK,CAAC,QAC5B,OAAO,IAAI,YAAY,MAAM,OAAO,KAAK,OAAO;AAAA,UAClD;AACA,cAAI,CAAC,OAAO;AACV,6BAAiB;AAAA,cACf,cAAc,KAAK,OAAO;AAAA,YAG5B;AAAA,UACF;AAAA,QACF,QAAQ;AACN,2BAAiB;AAAA,YACf,iCAAiC,KAAK,OAAO;AAAA,UAG/C;AAAA,QACF;AAAA,MACF;AAEA,UAAI,iBAAiB,SAAS,GAAG;AAC/B,oBAAY;AAAA,UACV,OAAO;AAAA,UACP,SAAS;AAAA,UACT,QAAQ;AAAA,UACR,MAAM;AAAA,QACR,CAAC;AACD;AAAA,MACF;AAEA,YAAM,OAAgC;AAAA,QACpC,YAAY,KAAK;AAAA,QACjB,aAAa,SAAS,KAAK,WAAW;AAAA,QACtC,gBAAgB,SAAS,KAAK,cAAc;AAAA,QAC5C,iBAAiB,SAAS,KAAK,cAAc;AAAA,QAC7C,aAAa,KAAK;AAAA,QAClB,wBAAwB,WAAW,KAAK,KAAK;AAAA,QAC7C,QAAQ;AAAA,MACV;AAEA,UAAI,KAAK,MAAO,MAAK,gBAAgB,EAAE,iBAAiB,SAAS,KAAK,KAAK,EAAE;AAC7E,UAAI,KAAK,SAAU,MAAK,cAAc,EAAE,eAAe,SAAS,KAAK,QAAQ,EAAE;AAC/E,UAAI,KAAK,QAAS,MAAK,UAAU,EAAE,WAAW,SAAS,KAAK,OAAO,EAAE;AACrE,UAAI,KAAK,UAAW,MAAK,YAAY,WAAW,KAAK,SAAS;AAC9D,WAAK,QAAQ,WAAW,KAAK,KAAK;AAClC,UAAI,KAAK,SAAU,MAAK,WAAW;AAEnC,UAAI,KAAK,eAAe,KAAK,YAAY,SAAS,GAAG;AACnD,aAAK,uBAAuB,KAAK,YAAY,IAAI,CAAC,QAAuC;AAAA,UACvF,aAAa,EAAE,eAAe,GAAG,GAAG;AAAA,UACpC,OAAO,GAAG;AAAA,QACZ,EAAE;AAAA,MACJ;AAEA,YAAM,MAAM,MAAM,OAAO,KAAK,eAAe,IAAI;AACjD,aAAO,IAAI,MAAM,MAAM;AAAA,IACzB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAEH,YAAU,WAAW,IAAI;AAC3B;AAGA,SAAS,oBAAoB,OAAe,UAA4E;AACtH,QAAM,CAAC,OAAO,QAAQ,IAAI,MAAM,MAAM,GAAG;AACzC,QAAM,KAAK,SAAS,KAAK;AACzB,QAAM,QAAQ,WAAW,SAAS,QAAQ,IAAI;AAC9C,MAAI,MAAM,EAAE,EAAG,OAAM,IAAI,MAAM,iCAAiC,KAAK,mCAAmC;AACxG,SAAO,CAAC,GAAG,UAAU,EAAE,IAAI,MAAM,CAAC;AACpC;;;AChaA,SAASC,eAAc,KAAuD;AAC5E,MAAI,OAAO;AACX,SAAO,KAAK,OAAQ,QAAO,KAAK;AAChC,SAAO,KAAK,KAAK;AACnB;AAEO,SAAS,8BAA8B,WAA0B;AACtE,QAAM,MAAM,UAAU,QAAQ,eAAe,EAAE,YAAY,4DAA4D;AAEvH,MACG,QAAQ,MAAM,EACd,YAAY,gEAAgE,EAC5E,OAAO,YAAY;AAClB,QAAI;AACF,YAAM,SAASA,eAAc,GAAG;AAChC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,MAAM,MAAM,OAAO,IAAI,gBAAgB;AAC7C,aAAO,IAAI,MAAM,MAAM;AAAA,IACzB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAEH,MACG,QAAQ,QAAQ,EAChB,YAAY,2BAA2B,EACvC,eAAe,iBAAiB,0DAA0D,EAC1F,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASA,eAAc,GAAG;AAChC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,OAAO,KAAK,MAAM,KAAK,IAAI;AACjC,YAAM,MAAM,MAAM,OAAO,KAAK,kBAAkB,IAAI;AACpD,aAAO,IAAI,MAAM,MAAM;AAAA,IACzB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AACL;;;ACtCA,SAASC,eAAc,KAAuD;AAC5E,MAAI,OAAO;AACX,SAAO,KAAK,OAAQ,QAAO,KAAK;AAChC,SAAO,KAAK,KAAK;AACnB;AAEA,SAASC,WAAU,MAA+D;AAChF,MAAI,CAAC,KAAM,QAAO;AAClB,SAAO,KAAK,MAAM,IAAI;AACxB;AAEO,SAAS,6BAA6B,WAA0B;AACrE,QAAM,SAAS,UAAU,QAAQ,eAAe,EAAE;AAAA,IAChD;AAAA,EAGF;AAGA,SACG,QAAQ,MAAM,EACd,YAAY,wBAAwB,EACpC,OAAO,YAAY;AAClB,QAAI;AACF,YAAM,SAASD,eAAc,MAAM;AACnC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,MAAM,MAAM,OAAO,IAAI,gCAAgC;AAC7D,aAAO,IAAI,MAAM,MAAM;AAAA,IACzB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAGH,SACG,QAAQ,UAAU,EAClB,YAAY,0BAA0B,EACtC,OAAO,OAAO,OAAO;AACpB,QAAI;AACF,YAAM,SAASA,eAAc,MAAM;AACnC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,MAAM,MAAM,OAAO,IAAI,iCAAiC,EAAE,EAAE;AAClE,aAAO,IAAI,MAAM,MAAM;AAAA,IACzB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAGH,SACG,QAAQ,QAAQ,EAChB;AAAA,IACC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMF,EACC,eAAe,iBAAiB,0BAA0B,EAC1D,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASA,eAAc,MAAM;AACnC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,OAAOC,WAAU,KAAK,IAAI;AAChC,YAAM,MAAM,MAAM,OAAO,KAAK,8BAA8B,IAAI;AAChE,aAAO,IAAI,MAAM,MAAM;AAAA,IACzB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAGH,SACG,QAAQ,aAAa,EACrB,YAAY,uBAAuB,EACnC,eAAe,iBAAiB,4BAA4B,EAC5D,OAAO,OAAO,IAAI,SAAS;AAC1B,QAAI;AACF,YAAM,SAASD,eAAc,MAAM;AACnC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,OAAOC,WAAU,KAAK,IAAI;AAChC,YAAM,MAAM,MAAM,OAAO,IAAI,8BAA8B,EAAE,IAAI,IAAI;AACrE,aAAO,IAAI,MAAM,MAAM;AAAA,IACzB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAGH,SACG,QAAQ,aAAa,EACrB,YAAY,uBAAuB,EACnC,OAAO,OAAO,OAAO;AACpB,QAAI;AACF,YAAM,SAASD,eAAc,MAAM;AACnC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,MAAM,MAAM,OAAO,OAAO,8BAA8B,EAAE,EAAE;AAClE,aAAO,IAAI,QAAQ,EAAE,SAAS,MAAM,SAAS,GAAG,GAAG,MAAM;AAAA,IAC3D,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AACL;;;ACrGA,IAAM,YAA8B;AAAA,EAClC;AAAA,IACE,MAAM;AAAA,IACN,UAAU;AAAA,IACV,UAAU;AAAA,IACV,SAAS;AAAA,IACT,YAAY,CAAC,QAAQ,gBAAgB,aAAa,cAAc,eAAe,QAAQ;AAAA,IACvF,iBAAiB;AAAA,EACnB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,UAAU;AAAA,IACV,UAAU;AAAA,IACV,SAAS;AAAA,IACT,YAAY,CAAC,QAAQ,gBAAgB,gBAAgB,cAAc,eAAe,mBAAmB,YAAY,eAAe,QAAQ;AAAA,IACxI,iBAAiB;AAAA,IACjB,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,UAAU;AAAA,IACV,UAAU;AAAA,IACV,SAAS;AAAA,IACT,YAAY,CAAC,QAAQ,gBAAgB,YAAY,aAAa,eAAe,QAAQ;AAAA,IACrF,iBAAiB;AAAA,EACnB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,UAAU;AAAA,IACV,UAAU;AAAA,IACV,SAAS;AAAA,IACT,YAAY,CAAC,QAAQ,gBAAgB,YAAY,iBAAiB,eAAe,eAAe,QAAQ;AAAA,IACxG,iBAAiB;AAAA,IACjB,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,UAAU;AAAA,IACV,UAAU;AAAA,IACV,SAAS;AAAA,IACT,YAAY,CAAC,QAAQ,gBAAgB,cAAc,cAAc,QAAQ,eAAe,QAAQ;AAAA,IAChG,iBAAiB;AAAA,IACjB,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,UAAU;AAAA,IACV,UAAU;AAAA,IACV,SAAS;AAAA,IACT,YAAY,CAAC,SAAS,mBAAmB,cAAc,cAAc,eAAe,QAAQ;AAAA,IAC5F,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,UAAU;AAAA,IACV,UAAU;AAAA,IACV,SAAS;AAAA,IACT,YAAY,CAAC,SAAS,qBAAqB,gBAAgB;AAAA,IAC3D,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,UAAU;AAAA,IACV,UAAU;AAAA,IACV,SAAS;AAAA,IACT,YAAY,CAAC,cAAc,WAAW,SAAS,eAAe,QAAQ;AAAA,IACtE,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,UAAU;AAAA,IACV,UAAU;AAAA,IACV,SAAS;AAAA,IACT,YAAY,CAAC,cAAc,YAAY,SAAS,eAAe,QAAQ;AAAA,IACvE,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,aAAa;AAAA,EACf;AACF;AAEO,SAAS,0BAA0BE,UAAwB;AAChE,QAAM,YAAYA,SAAQ,QAAQ,WAAW,EAAE,YAAY,0FAA0F;AAGrJ,gCAA8B,SAAS;AAGvC,aAAW,YAAY,WAAW;AAChC,cAAU,WAAW,uBAAuB,QAAQ,CAAC;AAAA,EACvD;AAGA,+BAA6B,SAAS;AAGtC,uBAAqB,SAAS;AAChC;;;ACxGA,SAAkB,cAAc;AAChC,SAAS,gBAAAC,eAAc,iBAAAC,gBAAe,cAAAC,mBAAkB;;;ACDxD,OAAO,YAAY;AACnB,IAAM,YAAY,IAAI,WAAW,GAAG;AAEpC,IAAI,UAAU,UAAU;AACT,SAAR,MAAuB;AAC5B,MAAI,UAAU,UAAU,SAAS,IAAI;AACnC,WAAO,eAAe,SAAS;AAC/B,cAAU;AAAA,EACZ;AAEA,SAAO,UAAU,MAAM,SAAS,WAAW,EAAE;AAC/C;;;ACXA,IAAO,gBAAQ;;;ACEf,SAAS,SAAS,MAAM;AACtB,SAAO,OAAO,SAAS,YAAY,cAAM,KAAK,IAAI;AACpD;AAEA,IAAO,mBAAQ;;;ACAf,IAAM,YAAY,CAAC;AAEnB,SAAS,IAAI,GAAG,IAAI,KAAK,EAAE,GAAG;AAC5B,YAAU,MAAM,IAAI,KAAO,SAAS,EAAE,EAAE,OAAO,CAAC,CAAC;AACnD;AAEA,SAAS,UAAU,KAAK,SAAS,GAAG;AAGlC,QAAM,QAAQ,UAAU,IAAI,SAAS,CAAC,CAAC,IAAI,UAAU,IAAI,SAAS,CAAC,CAAC,IAAI,UAAU,IAAI,SAAS,CAAC,CAAC,IAAI,UAAU,IAAI,SAAS,CAAC,CAAC,IAAI,MAAM,UAAU,IAAI,SAAS,CAAC,CAAC,IAAI,UAAU,IAAI,SAAS,CAAC,CAAC,IAAI,MAAM,UAAU,IAAI,SAAS,CAAC,CAAC,IAAI,UAAU,IAAI,SAAS,CAAC,CAAC,IAAI,MAAM,UAAU,IAAI,SAAS,CAAC,CAAC,IAAI,UAAU,IAAI,SAAS,CAAC,CAAC,IAAI,MAAM,UAAU,IAAI,SAAS,EAAE,CAAC,IAAI,UAAU,IAAI,SAAS,EAAE,CAAC,IAAI,UAAU,IAAI,SAAS,EAAE,CAAC,IAAI,UAAU,IAAI,SAAS,EAAE,CAAC,IAAI,UAAU,IAAI,SAAS,EAAE,CAAC,IAAI,UAAU,IAAI,SAAS,EAAE,CAAC,GAAG,YAAY;AAMvgB,MAAI,CAAC,iBAAS,IAAI,GAAG;AACnB,UAAM,UAAU,6BAA6B;AAAA,EAC/C;AAEA,SAAO;AACT;AAEA,IAAO,oBAAQ;;;ACzBf,SAAS,GAAG,SAAS,KAAK,QAAQ;AAChC,YAAU,WAAW,CAAC;AACtB,QAAM,OAAO,QAAQ,WAAW,QAAQ,OAAO,KAAK;AAEpD,OAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAO;AAC3B,OAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAO;AAE3B,MAAI,KAAK;AACP,aAAS,UAAU;AAEnB,aAAS,IAAI,GAAG,IAAI,IAAI,EAAE,GAAG;AAC3B,UAAI,SAAS,CAAC,IAAI,KAAK,CAAC;AAAA,IAC1B;AAEA,WAAO;AAAA,EACT;AAEA,SAAO,kBAAU,IAAI;AACvB;AAEA,IAAO,aAAQ;;;ALgBf,SAAS,mBAAmB,MAAsB;AAChD,QAAM,MAAM,oBAAI,KAAK;AACrB,QAAM,UAAU,IAAI,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC;AAC9C,SAAO;AAAA,IACL,IAAI,WAAG;AAAA,IACP,UAAU;AAAA,IACV,eAAe;AAAA,MACb,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,MAAM;AAAA,MACN,aAAa;AAAA,MACb,SAAS;AAAA,MACT,qBAAqB;AAAA,MACrB,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,aAAa;AAAA,MACb,UAAU;AAAA,MACV,cAAc;AAAA,MACd,iBAAiB;AAAA,IACnB;AAAA,IACA,UAAU;AAAA,IACV,WAAW;AAAA,IACX,kBAAkB;AAAA,IAClB,cAAc,EAAE,OAAO,aAAQ;AAAA,IAC/B,iBAAiB,CAAC;AAAA,IAClB,aAAa,EAAE,OAAO,qBAAa;AAAA,IACnC,SAAS;AAAA,IACT,6BAA6B;AAAA,IAC7B,2BAA2B;AAAA,IAC3B,wBAAwB;AAAA,IACxB,6BAA6B;AAAA,MAC3B,iCAAiC;AAAA,IACnC;AAAA,IACA,sBAAsB;AAAA,IACtB,iBAAiB;AAAA,MACf,+BAA+B;AAAA,MAC/B,WAAW;AAAA,MACX,qBAAqB;AAAA,MACrB,yBAAyB;AAAA,MACzB,gCAAgC;AAAA,MAChC,iBAAiB;AAAA,MACjB,cAAc;AAAA,MACd,QAAQ;AAAA,IACV;AAAA,IACA,mBAAmB;AAAA,IACnB,oBAAoB;AAAA,MAClB,eAAe;AAAA,QACb,eAAe;AAAA,QACf,aAAa;AAAA,QACb,iBAAiB;AAAA,QACjB,YAAY;AAAA,QACZ,SAAS;AAAA,QACT,kBAAkB;AAAA,MACpB;AAAA,MACA,cAAc;AAAA,QACZ,eAAe;AAAA,QACf,aAAa;AAAA,QACb,iBAAiB;AAAA,QACjB,YAAY;AAAA,QACZ,SAAS;AAAA,QACT,kBAAkB;AAAA,MACpB;AAAA,MACA,mBAAmB;AAAA,MACnB,yBAAyB,IAAI,QAAQ;AAAA,IACvC;AAAA,IACA,iBAAiB;AAAA,IACjB,wBAAwB;AAAA,MACtB,2BAA2B;AAAA,MAC3B,uBAAuB;AAAA,MACvB,uBAAuB;AAAA,IACzB;AAAA,IACA,QAAQ;AAAA,IACR,yBAAyB,IAAI,QAAQ;AAAA,IACrC,MAAM,QAAQ,iBAAiB,OAAO;AAAA,IACtC,OAAO;AAAA,IACP,QAAQ;AAAA,EACV;AACF;AAIA,SAAS,wBAAwB,cAAsB,SAA8C;AACnG,MAAI,CAAC,QAAS,QAAO;AACrB,MAAI,WAAW;AACf,WAAS,IAAI,GAAG,KAAK,GAAG,KAAK;AAC3B,UAAM,MAAM,QAAQ,MAAM,CAAC;AAC3B,QAAI,QAAQ,UAAa,QAAQ,QAAQ,CAAC,MAAM,GAAG,GAAG;AACpD;AAAA,IACF;AAAA,EACF;AACA,SAAO,YAAY;AACrB;AAEA,SAAS,cAAc,OAAiF;AACtG,QAAM,UAAkC,CAAC;AAGzC,QAAM,YAAY,MAAM;AACxB,QAAM,eAAe,MAAM;AAC3B,QAAM,mBAAmB,MAAM;AAC/B,QAAM,SAAS,MAAM;AACrB,QAAM,iBAAiB,MAAM;AAE7B,MAAI,wBAAwB;AAC5B,MAAI,CAAC,WAAW;AACd,4BAAwB;AACxB,YAAQ,gBAAgB;AAAA,EAC1B,WAAW,CAAC,wBAAwB,UAAU,WAAW,GAAG,YAAY,GAAG;AACzE,4BAAwB;AACxB,YAAQ,gBAAgB,2BAA2B,UAAU,WAAW,CAAC;AAAA,EAC3E,WAAW,CAAC,kBAAkB;AAC5B,4BAAwB;AACxB,YAAQ,gBAAgB;AAAA,EAC1B,WAAW,WAAW,QAAQ,CAAC,wBAAwB,GAAG,cAAc,GAAG;AACzE,4BAAwB;AACxB,YAAQ,gBAAgB;AAAA,EAC1B;AAGA,QAAM,cAAc,MAAM;AAC1B,QAAM,sBAAsB,CAAC,CAAC,aAAa,MAAM;AACjD,MAAI,CAAC,qBAAqB;AACxB,YAAQ,cAAc;AAAA,EACxB;AAGA,QAAM,WAAW,MAAM;AACvB,QAAM,mBAAmB,CAAC,CAAC,UAAU;AACrC,MAAI,CAAC,kBAAkB;AACrB,YAAQ,mBAAmB;AAAA,EAC7B;AAIA,QAAM,aAAa,MAAM;AACzB,QAAM,WAAW,MAAM;AACvB,QAAM,eAAe,CAAC,CAAC,cAAc,CAAC,CAAC;AACvC,MAAI,qBAAqB;AACzB,MAAI,YAAY,SAAS,SAAS,GAAG;AACnC,eAAW,KAAK,UAAU;AACxB,YAAM,OAAO;AACb,UAAI,KAAK,YAAY,MAAM,QAAQ;AACjC,6BAAqB;AACrB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,QAAM,qBAAqB,sBAAsB;AACjD,MAAI,CAAC,oBAAoB;AACvB,UAAM,UAAoB,CAAC;AAC3B,QAAI,CAAC,aAAc,SAAQ,KAAK,sEAAsE;AACtG,QAAI,CAAC,mBAAoB,SAAQ,KAAK,uEAAuE;AAC7G,YAAQ,aAAa,QAAQ,KAAK,IAAI;AAAA,EACxC;AAGA,QAAM,UAAU,MAAM;AACtB,QAAM,kBAAkB,YAAY;AACpC,MAAI,CAAC,iBAAiB;AACpB,YAAQ,UAAU;AAAA,EACpB;AAGA,QAAM,kBAAkB,MAAM;AAC9B,QAAM,0BACJ,iBAAiB,WAAW,UAC5B,iBAAiB,cAAc,UAC/B,YAAY;AACd,MAAI,CAAC,yBAAyB;AAC5B,UAAM,UAAoB,CAAC;AAC3B,QAAI,iBAAiB,WAAW,OAAW,SAAQ,KAAK,QAAQ;AAChE,QAAI,iBAAiB,cAAc,OAAW,SAAQ,KAAK,WAAW;AACtE,QAAI,CAAC,QAAS,SAAQ,KAAK,SAAS;AACpC,YAAQ,kBAAkB,UAAU,QAAQ,KAAK,IAAI,CAAC;AAAA,EACxD;AAEA,SAAO;AAAA,IACL,eAAe;AAAA,MACb,eAAe;AAAA,MACf,aAAa;AAAA,MACb,kBAAkB;AAAA,MAClB,YAAY;AAAA,MACZ,SAAS;AAAA,MACT,iBAAiB;AAAA,IACnB;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,8BAA8B,eAAsC;AAC3E,QAAM,YAAY,OAAO,OAAO,aAAa,EAAE,OAAO,OAAO,EAAE;AAC/D,SAAO,KAAK,MAAO,YAAY,IAAK,GAAG;AACzC;AAMA,IAAM,iBAA6C;AAAA,EACjD,aAAa,CAAC,cAAc,WAAW,iBAAiB;AAAA,EACxD,UAAU,CAAC,cAAc,WAAW,iBAAiB;AACvD;AAEA,SAAS,mBAAmB,OAAc,cAAgC;AACxE,QAAM,aAAa,eAAe,YAAY;AAC9C,MAAI,CAAC,WAAY,QAAO,CAAC;AAEzB,QAAM,WAAY,MAAM;AACxB,QAAM,SAAmB,CAAC;AAC1B,aAAW,QAAQ,YAAY;AAC7B,QAAI,SAAS,cAAc,IAAI,MAAM,QAAW;AAC9C,eAAS,cAAc,IAAI,IAAI;AAC/B,aAAO,KAAK,IAAI;AAAA,IAClB;AAAA,EACF;AAGA,MAAI,iBAAiB,eAAe;AAElC,UAAM,UAAU;AAAA,EAClB;AACA,MAAI,iBAAiB,YAAY;AAC/B,UAAM,UAAU;AAAA,EAClB;AAEA,SAAO;AACT;AAIA,SAAS,UAAU,UAAyB;AAC1C,MAAI,CAACC,YAAW,QAAQ,GAAG;AACzB,UAAM,IAAI,MAAM,yBAAyB,QAAQ,8BAA8B,QAAQ,kBAAkB;AAAA,EAC3G;AACA,SAAO,KAAK,MAAMC,cAAa,UAAU,OAAO,CAAC;AACnD;AAEA,SAAS,WAAW,UAAkB,OAAoB;AACxD,EAAAC,eAAc,UAAU,KAAK,UAAU,OAAO,MAAM,CAAC,GAAG,OAAO;AACjE;AAGA,SAAS,YACP,UACA,SAC0H;AAC1H,QAAM,QAAQ,UAAU,QAAQ;AAChC,QAAM,eAAe,QAAQ,KAAK;AAGlC,MAAI,gBAA0B,CAAC;AAC/B,MAAI,cAAc;AAChB,oBAAgB,mBAAmB,OAAO,YAAY;AAAA,EACxD;AAGA,QAAM,EAAE,eAAe,QAAQ,IAAI,cAAc,KAAK;AAGtD,QAAM,WAAW,MAAM;AACvB,WAAS,gBAAgB;AACzB,WAAS,0BAA0B,KAAK,IAAI;AAC5C,QAAM,0BAA0B,KAAK,IAAI;AAEzC,aAAW,UAAU,KAAK;AAE1B,SAAO;AAAA,IACL;AAAA,IACA,sBAAsB,8BAA8B,aAAa;AAAA,IACjE;AAAA,IACA;AAAA,EACF;AACF;AAGA,SAAS,UAAU,QAAiC,QAAuC;AACzF,aAAW,OAAO,OAAO,KAAK,MAAM,GAAG;AACrC,UAAM,KAAK,OAAO,GAAG;AACrB,UAAM,KAAK,OAAO,GAAG;AACrB,QAAI,MAAM,OAAO,OAAO,YAAY,CAAC,MAAM,QAAQ,EAAE,KAAK,MAAM,OAAO,OAAO,YAAY,CAAC,MAAM,QAAQ,EAAE,GAAG;AAC5G,gBAAU,IAA+B,EAA6B;AAAA,IACxE,OAAO;AACL,aAAO,GAAG,IAAI;AAAA,IAChB;AAAA,EACF;AACF;AAIA,SAASC,eAAc,KAAuD;AAC5E,MAAI,OAAO;AACX,SAAO,KAAK,OAAQ,QAAO,KAAK;AAChC,SAAO,KAAK,KAAK;AACnB;AAEA,SAAS,YAAY,MAAiC;AACpD,SAAO,KAAK,QAAQ,QAAQ,IAAI,kBAAkB;AACpD;AAiBO,SAAS,0BACd,SACA,OACe;AACf,QAAM,UAAU,CAAC,MAA4B;AAC3C,UAAM,IAAI;AACV,WAAO,CAAC,CAAC,KAAK,OAAO,SAAS,EAAE,GAAG,KAAK,OAAO,SAAS,EAAE,GAAG;AAAA,EAC/D;AAEA,QAAM,SAAS,QAAQ;AACvB,MAAI,QAAQ,MAAM,EAAG,QAAO,EAAE,KAAK,OAAO,KAAK,KAAK,OAAO,IAAI;AAE/D,QAAM,gBAAgB,MAAM;AAC5B,MAAI,QAAQ,aAAa,EAAG,QAAO,EAAE,KAAK,cAAc,KAAK,KAAK,cAAc,IAAI;AAEpF,QAAM,OAAO,QAAQ;AACrB,MAAI,MAAM,QAAQ,IAAI,KAAK,KAAK,SAAS,GAAG;AAC1C,UAAM,SAAS,KAAK;AAAA,MAClB,CAAC,MAAmB,OAAO,SAAS,GAAG,GAAG,KAAK,OAAO,SAAS,GAAG,GAAG;AAAA,IACvE;AACA,QAAI,OAAO,SAAS,GAAG;AAErB,YAAM,MAAM,OAAO;AAAA,QACjB,CAAC,KAAK,OAAe,EAAE,KAAK,IAAI,MAAM,EAAE,KAAK,KAAK,IAAI,MAAM,EAAE,IAAI;AAAA,QAClE,EAAE,KAAK,GAAG,KAAK,EAAE;AAAA,MACnB;AACA,YAAM,WAAW,EAAE,KAAK,IAAI,MAAM,OAAO,QAAQ,KAAK,IAAI,MAAM,OAAO,OAAO;AAC9E,UAAI,QAAQ,QAAQ,EAAG,QAAO;AAE9B,aAAO,EAAE,KAAK,OAAO,CAAC,EAAE,KAAK,KAAK,OAAO,CAAC,EAAE,IAAI;AAAA,IAClD;AAAA,EACF;AAEA,SAAO;AACT;AAkBO,SAAS,6BACd,SACA,OACgD;AAChD,QAAM,WAAW,QAAQ;AACzB,MAAI,OAAO,SAAS,QAAQ,KAAM,WAAsB,GAAG;AACzD,WAAO,EAAE,gBAAgB,UAAoB,WAAW,MAAM;AAAA,EAChE;AAEA,QAAM,aAAa,MAAM;AACzB,QAAM,WAAY,MAAM,UAAqE;AAC7F,QAAM,iBAAkB,YAAY,aAAyB,UAAU,aAAwB;AAG/F,QAAM,SAAS,QAAQ;AACvB,QAAM,aAAa,WAAW,SACzB,OAAO,UAAU,IACjB,QAAQ;AAEb,MAAI,kBAAkB,OAAO,SAAS,UAAU,KAAM,aAAwB,GAAG;AAC/E,WAAO,EAAE,gBAAiB,aAAwB,gBAAgB,WAAW,MAAM;AAAA,EACrF;AAEA,SAAO,EAAE,gBAAgB,KAAM,WAAW,KAAK;AACjD;AAIO,SAAS,6BAA6B,SAAwB;AAKnE,UACG,QAAQ,MAAM,EACd;AAAA,IACC;AAAA,EAEF,EACC,OAAO,iBAAiB,0CAA0C,EAClE,OAAO,sBAAsB,YAAY,EACzC,OAAO,mBAAmB,4CAA4C,IAAI,EAC1E,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,WAAW,YAAY,IAAI;AACjC,YAAM,QAAQ,mBAAmB,KAAK,IAAI;AAC1C,UAAI,KAAK,OAAQ,OAAM,SAAS,KAAK;AACrC,iBAAW,UAAU,KAAK;AAC1B,YAAM,EAAE,eAAe,QAAQ,IAAI,cAAc,KAAK;AACtD,aAAO;AAAA,QACL,MAAM;AAAA,QACN,IAAI,MAAM;AAAA,QACV,MAAM,MAAM;AAAA,QACZ;AAAA,QACA,sBAAsB;AAAA,QACtB;AAAA,MACF,GAAGA,eAAc,OAAO,CAAC;AAAA,IAC3B,SAAS,KAAK;AACZ,kBAAY,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,CAAC;AAAA,IACjE;AAAA,EACF,CAAC;AAKH,UACG,QAAQ,UAAU,EAClB;AAAA,IACC;AAAA,EAEF,EACC,OAAO,iBAAiB,iBAAiB,EACzC,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,QAAQ,UAAU,YAAY,IAAI,CAAC;AACzC,YAAM,EAAE,eAAe,QAAQ,IAAI,cAAc,KAAK;AACtD,aAAO;AAAA,QACL,MAAM,MAAM;AAAA,QACZ;AAAA,QACA,sBAAsB,8BAA8B,aAAa;AAAA,QACjE;AAAA,MACF,GAAGA,eAAc,OAAO,CAAC;AAAA,IAC3B,SAAS,KAAK;AACZ,kBAAY,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,CAAC;AAAA,IACjE;AAAA,EACF,CAAC;AAKH,UACG,QAAQ,MAAM,EACd;AAAA,IACC;AAAA,EAGF,EACC,OAAO,iBAAiB,iBAAiB,EACzC,OAAO,kBAAkB,+BAA+B,EACxD,OAAO,uBAAuB,0BAA0B,EACxD,OAAO,iBAAiB,8CAA8C,EACtE,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,WAAW,YAAY,IAAI;AACjC,YAAM,SAASA,eAAc,OAAO;AACpC,YAAM,QAAQ,UAAU,QAAQ;AAGhC,YAAM,EAAE,cAAc,IAAI,cAAc,KAAK;AAC7C,YAAM,WAAW,MAAM;AACvB,eAAS,gBAAgB;AACzB,eAAS,0BAA0B,KAAK,IAAI;AAG5C,YAAM,YAAY,SAAS,qBAAqB,CAAC,CAAC,MAAM;AACxD,YAAM,WAAY,MAAM,YAAY,CAAC;AACrC,YAAM,cAAc,KAAK,YAAY,eAAgB,YAAY,aAAa;AAC9E,eAAS,KAAK,cAAc,WAAW,CAAC;AACxC,YAAM,WAAW;AAEjB,UAAI,KAAK,WAAW;AAClB,eAAO,MAAM;AAAA,MACf;AAEA,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,SAAiC,CAAC;AACxC,UAAI,KAAK,QAAS,QAAO,oBAAoB,KAAK;AAClD,UAAI,KAAK,aAAc,QAAO,eAAe,KAAK;AAClD,UAAI,KAAK,UAAW,QAAO,YAAY;AAEvC,YAAM,cAAc,OAAO,QAAQ,MAAM,EACtC,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,mBAAmB,CAAC,CAAC,EAAE,EAC/C,KAAK,GAAG;AACX,YAAM,MAAM,eAAe,cAAc,MAAM,cAAc,EAAE;AAE/D,YAAM,MAAM,MAAM,OAAO,KAAK,KAAK,KAAK;AAGxC,YAAM,eAAe,IAAI;AACzB,UAAI,cAAc,cAAc;AAC9B,cAAM,MAAM,aAAa;AACzB,iBAAS,oBAAoB;AAC7B,mBAAW,UAAU,KAAK;AAAA,MAC5B;AAEA,aAAO;AAAA,QACL,OAAO;AAAA,QACP,UAAU;AAAA,QACV,MAAM;AAAA,QACN,sBAAsB,8BAA8B,aAAa;AAAA,MACnE,GAAG,MAAM;AAAA,IACX,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAKH,UACG,QAAQ,gBAAgB,EACxB;AAAA,IACC;AAAA,EAEF,EACC,OAAO,iBAAiB,kBAAkB,EAC1C,OAAO,OAAO,SAAS,SAAS;AAC/B,QAAI;AACF,0BAAoB,OAAO;AAC3B,YAAM,WAAW,YAAY,IAAI;AACjC,YAAM,SAASA,eAAc,OAAO;AACpC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,MAAM,MAAM,OAAO,IAAI,yBAAyB,OAAO,EAAE;AAC/D,YAAM,QAAQ,YAAY,IAAI,MAAM,eAAe,OAAO;AAG1D,YAAM,EAAE,eAAe,QAAQ,IAAI,cAAc,KAAK;AACtD,YAAM,WAAY,MAAM,sBAAsB,CAAC;AAC/C,eAAS,gBAAgB;AACzB,eAAS,oBAAoB;AAC7B,YAAM,qBAAqB;AAE3B,iBAAW,UAAU,KAAK;AAC1B,aAAO;AAAA,QACL,MAAM;AAAA,QACN,KAAK,MAAM;AAAA,QACX,MAAM,MAAM;AAAA,QACZ;AAAA,QACA,sBAAsB,8BAA8B,aAAa;AAAA,QACjE;AAAA,MACF,GAAG,MAAM;AAAA,IACX,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAKH,QAAM,MAAM,QAAQ,QAAQ,KAAK,EAAE,YAAY,sEAAsE;AAGrH,MACG,QAAQ,MAAM,EACd,YAAY,oBAAoB,EAChC,OAAO,iBAAiB,iBAAiB,EACzC,eAAe,sBAAsB,YAAY,EACjD,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAAS,YAAY,YAAY,IAAI,GAAG,CAAC,UAAU;AACvD,cAAM,OAAO,KAAK;AAClB,eAAO;AAAA,MACT,CAAC;AACD,aAAO,QAAQA,eAAc,OAAO,CAAC;AAAA,IACvC,SAAS,KAAK;AACZ,kBAAY,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,CAAC;AAAA,IACjE;AAAA,EACF,CAAC;AAGH,MACG,QAAQ,QAAQ,EAChB,YAAY,wDAAwD,EACpE,OAAO,iBAAiB,iBAAiB,EACzC,eAAe,mBAAmB,qBAAqB,EACvD,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAAS,YAAY,YAAY,IAAI,GAAG,CAAC,UAAU;AACvD,cAAM,SAAS,KAAK;AACpB,eAAO;AAAA,MACT,CAAC;AACD,aAAO,QAAQA,eAAc,OAAO,CAAC;AAAA,IACvC,SAAS,KAAK;AACZ,kBAAY,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,CAAC;AAAA,IACjE;AAAA,EACF,CAAC;AAGH,MACG,QAAQ,QAAQ,EAChB;AAAA,IACC;AAAA,EAEF,EACC,OAAO,iBAAiB,iBAAiB,EACzC,OAAO,uBAAuB,0CAAuC,EACrE,OAAO,mBAAmB,cAAc,EACxC,OAAO,mBAAmB,cAAc,EACxC,OAAO,iBAAiB,WAAW,EACnC,OAAO,oBAAoB,SAAS,EACpC,OAAO,iBAAiB,MAAM,EAC9B,OAAO,qBAAqB,gCAA6B,EACzD,OAAO,2BAA2B,uBAAuB,EACzD,OAAO,eAAe,YAAY,EAClC,OAAO,qBAAqB,eAAe,EAC3C,OAAO,iCAAiC,mCAAmC,EAC3E,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAAS,YAAY,YAAY,IAAI,GAAG,CAAC,UAAU;AACvD,cAAM,KAAM,MAAM,iBAAiB,CAAC;AACpC,YAAI,KAAK,KAAM,IAAG,aAAa,KAAK;AACpC,YAAI,KAAK,MAAO,IAAG,QAAQ,KAAK;AAChC,YAAI,KAAK,MAAO,IAAG,cAAc,KAAK;AACtC,YAAI,KAAK,KAAM,IAAG,OAAO,KAAK;AAC9B,YAAI,KAAK,QAAS,IAAG,UAAU,KAAK;AACpC,YAAI,KAAK,KAAM,IAAG,OAAO,KAAK;AAC9B,YAAI,KAAK,OAAQ,IAAG,SAAS,KAAK;AAClC,YAAI,KAAK,UAAW,IAAG,YAAY,KAAK;AACxC,YAAI,KAAK,IAAK,IAAG,WAAW,KAAK;AACjC,YAAI,KAAK,OAAQ,IAAG,SAAS,KAAK;AAClC,YAAI,KAAK,qBAAsB,IAAG,sBAAsB,KAAK;AAC7D,cAAM,gBAAgB;AACtB,eAAO;AAAA,MACT,CAAC;AACD,aAAO,QAAQA,eAAc,OAAO,CAAC;AAAA,IACvC,SAAS,KAAK;AACZ,kBAAY,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,CAAC;AAAA,IACjE;AAAA,EACF,CAAC;AAGH,MACG,QAAQ,QAAQ,EAChB;AAAA,IACC;AAAA,EAIF,EACC,OAAO,iBAAiB,iBAAiB,EACzC,eAAe,mBAAmB,eAAe,EACjD,OAAO,iBAAiB,wBAAwB,GAAG,EACnD,OAAO,mBAAmB,iCAAiC,IAAI,EAC/D,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASA,eAAc,OAAO;AACpC,YAAM,SAAS,oBAAoB,WAAW,MAAM;AAGpD,YAAM,YAAY,MAAM,OAAO,IAAI,gBAAgB;AAAA,QACjD,QAAQ,EAAE,QAAQ,KAAK,OAAO;AAAA,MAChC,CAAC;AACD,YAAM,UAAW,MAAM,QAAQ,UAAU,IAAI,IAAI,UAAU,OAAO,UAAU,MAAM,QAAQ,CAAC;AAC3F,YAAM,WAAW,SAAS,KAAK,QAAQ;AACvC,YAAM,SAAS,QAAQ,KAAK,CAAC,MAAM,EAAE,gBAAgB,QAAQ;AAC7D,UAAI,CAAC,QAAQ;AACX,oBAAY,IAAI,MAAM,aAAa,QAAQ,0BAA0B,QAAQ,IAAI,CAAC,MAAM,GAAG,EAAE,WAAW,IAAI,EAAE,MAAM,EAAE,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;AACrI;AAAA,MACF;AAGA,YAAM,UAAU,MAAM,OAAO,IAAI,UAAU;AAAA,QACzC,QAAQ,EAAE,QAAQ,KAAK,OAAO;AAAA,MAChC,CAAC;AACD,YAAM,QAAS,MAAM,QAAQ,QAAQ,IAAI,IAAI,QAAQ,OAAO,QAAQ,MAAM,QAAQ,CAAC;AACnF,YAAM,SAAS,SAAS,KAAK,MAAM;AACnC,YAAM,OAAO,MAAM,KAAK,CAAC,MAAM,EAAE,WAAW,MAAM;AAElD,YAAM,SAAS,YAAY,YAAY,IAAI,GAAG,CAAC,UAAU;AACvD,cAAM,YAAY;AAClB,YAAI,KAAM,OAAM,mBAAmB;AAGnC,cAAM,UAAW,OAAO,WAAsB;AAC9C,cAAM,yBAAyB,UAAU,IAAI,gBAAgB;AAE7D,eAAO;AAAA,MACT,CAAC;AAED,aAAO,QAAQ,MAAM;AAAA,IACvB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAGH,MACG,QAAQ,QAAQ,EAChB;AAAA,IACC;AAAA;AAAA;AAAA;AAAA;AAAA,EAKF,EACC,OAAO,iBAAiB,iBAAiB,EACzC,OAAO,mBAAmB,yCAAyC,EACnE,OAAO,mBAAmB,oCAA+B,EACzD,OAAO,mBAAmB,oCAA+B,EACzD,OAAO,mBAAmB,oCAA+B,EACzD,OAAO,mBAAmB,oCAA+B,EACzD,OAAO,mBAAmB,oCAA+B,EACzD,OAAO,mBAAmB,oCAA+B,EACzD,OAAO,kBAAkB,2DAAmD,EAC5E,OAAO,uBAAuB,iDAAiD,EAC/E,OAAO,uBAAuB,uCAAuC,EACrE,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAAS,YAAY,YAAY,IAAI,GAAG,CAAC,UAAU;AAEvD,cAAM,KAAM,MAAM,gBAAgB,EAAE,OAAO,aAAQ;AACnD,YAAI,KAAK,QAAQ;AACf,gBAAM,SAAS,KAAK,MAAM,KAAK,MAAM;AACrC,iBAAO,OAAO,IAAI,MAAM;AAAA,QAC1B;AACA,iBAAS,IAAI,GAAG,KAAK,GAAG,KAAK;AAC3B,gBAAM,MAAM,KAAK,UAAU,CAAC,EAAE;AAC9B,cAAI,QAAQ,OAAW,IAAG,IAAI,CAAC,EAAE,IAAI,WAAW,GAAG;AAAA,QACrD;AACA,cAAM,eAAe;AAGrB,YAAI,KAAK,OAAO;AACd,gBAAM,KAAM,MAAM,eAAe,EAAE,OAAO,qBAAa;AACvD,iBAAO,OAAO,IAAI,KAAK,MAAM,KAAK,KAAK,CAAC;AACxC,gBAAM,cAAc;AAAA,QACtB;AAGA,YAAI,KAAK,YAAY;AACnB,gBAAM,KAAM,MAAM,mBAAmB,CAAC;AACtC,iBAAO,OAAO,IAAI,KAAK,MAAM,KAAK,UAAU,CAAC;AAC7C,gBAAM,kBAAkB;AAAA,QAC1B;AAGA,YAAI,KAAK,gBAAgB,QAAW;AAClC,gBAAM,iBAAiB,EAAE,IAAI,WAAW,KAAK,WAAW,GAAG,OAAO,aAAQ;AAAA,QAC5E;AAEA,eAAO;AAAA,MACT,CAAC;AACD,aAAO,QAAQA,eAAc,OAAO,CAAC;AAAA,IACvC,SAAS,KAAK;AACZ,kBAAY,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,CAAC;AAAA,IACjE;AAAA,EACF,CAAC;AAGH,MACG,QAAQ,aAAa,EACrB;AAAA,IACC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYF,EACC,OAAO,iBAAiB,iBAAiB,EACzC,OAAO,2BAA2B,gCAAgC,EAClE,OAAO,kBAAkB,2BAA2B,EACpD,OAAO,oBAAoB,qEAAqE,EAChG,OAAO,sBAAsB,8CAA8C,EAC3E,OAAO,oBAAoB,8CAA8C,EACzE,OAAO,8BAA8B,2CAA2C,EAChF,OAAO,mBAAmB,sDAAsD,EAChF,OAAO,mBAAmB,mCAAmC,EAC7D,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASA,eAAc,OAAO;AACpC,YAAM,WAAW,YAAY,IAAI;AACjC,YAAM,QAAQ,UAAU,QAAQ;AAChC,YAAM,cAAe,MAAM,WAAuC,UAAoB;AACtF,YAAM,cAAe,MAAM,UAAqB;AAChD,YAAM,SAAS,KAAK,UAAU;AAC9B,YAAM,SAAS,KAAK,UAAU;AAC9B,YAAM,QAAO,oBAAI,KAAK,GAAE,YAAY;AAEpC,UAAI;AACJ,UAAI;AAEJ,UAAI,KAAK,UAAU;AAEjB,oBAAY,KAAK,MAAMF,cAAa,KAAK,UAAU,OAAO,CAAC;AAC3D,2BAAmB;AAAA,MAErB,WAAW,KAAK,UAAU,KAAK,SAAS;AAEtC,cAAM,iBAAiB,oBAAoB,YAAY,MAAM;AAC7D,cAAM,SAAiC;AAAA,UACrC,WAAW,GAAG,IAAI;AAAA,UAClB,SAAS,GAAG,IAAI;AAAA,UAChB;AAAA,UACA,MAAM;AAAA,UACN,kBAAkB,KAAK;AAAA,UACvB;AAAA,UACA,iBAAiB,KAAK;AAAA,QACxB;AACA,cAAM,cAAc,OAAO,QAAQ,MAAM,EACtC,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,mBAAmB,CAAC,CAAC,EAAE,EAC/C,KAAK,GAAG;AACX,cAAM,MAAM,MAAM,eAAe,KAAK,2BAA2B,WAAW,IAAI,CAAC,CAAC;AAClF,oBAAY,IAAI;AAChB,2BAAmB;AAAA,MAErB,WAAW,KAAK,UAAU;AAExB,cAAM,eAAe,KAAK,MAAM,KAAK,QAAQ;AAC7C,oBAAY,MAAM,oBAAoB,QAAQ,QAAQ,QAAQ,MAAM,yBAAyB,YAAY;AACzG,2BAAmB;AAAA,MAErB,WAAW,KAAK,SAAS;AAEvB,cAAM,cAAc,KAAK,MAAM,KAAK,OAAO;AAC3C,oBAAY,MAAM,oBAAoB,QAAQ,QAAQ,QAAQ,MAAM,qBAAqB,WAAW;AACpG,2BAAmB;AAAA,MAErB,WAAW,KAAK,iBAAiB;AAE/B,cAAM,oBAAoB,KAAK,MAAM,KAAK,eAAe;AACzD,oBAAY,MAAM,oBAAoB,QAAQ,QAAQ,QAAQ,MAAM,qBAAqB,iBAAiB;AAC1G,2BAAmB;AAAA,MAErB,OAAO;AACL,oBAAY,IAAI,MAAM,gGAAgG,CAAC;AACvH;AAAA,MACF;AAGA,YAAM,SAAS,YAAY,UAAU,CAAC,MAAM;AAC1C,UAAE,cAAc;AAChB,UAAE,8BAA8B;AAChC,YAAI,KAAK,OAAQ,GAAE,qBAAqB,WAAW,KAAK,MAAM,IAAI;AAClE,YAAI,KAAK,QAAS,GAAE,6BAA6B,KAAK;AACtD,YAAI,KAAK,SAAU,GAAE,8BAA8B,KAAK,MAAM,KAAK,QAAQ;AAC3E,YAAI,KAAK,QAAS,GAAE,6BAA6B,KAAK,MAAM,KAAK,OAAO;AACxE,YAAI,KAAK,gBAAiB,GAAE,mCAAmC,KAAK,MAAM,KAAK,eAAe;AAC9F,eAAO;AAAA,MACT,CAAC;AAED,aAAO,QAAQ,MAAM;AAAA,IACvB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAGH,UACG,QAAQ,KAAK,EACb,YAAY,2BAA2B,EACvC,QAAQ,SAAS,EACjB;AAAA,IACC;AAAA,EAEF,EACC,OAAO,iBAAiB,iBAAiB,EACzC,eAAe,aAAa,UAAU,EACtC,eAAe,aAAa,WAAW,EACvC,OAAO,eAAe,6BAA6B,IAAI,EACvD,OAAO,iBAAiB,sCAAsC,KAAK,EACnE,OAAO,eAAe,0BAA0B,EAChD,OAAO,sBAAsB,kBAAkB,EAC/C,OAAO,uBAAuB,2CAA2C,EACzE,OAAO,uBAAuB,yBAAyB,EACvD,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAAS,YAAY,YAAY,IAAI,GAAG,CAAC,UAAU;AACvD,cAAM,MAAM,WAAW,KAAK,GAAG;AAC/B,cAAM,MAAM,WAAW,KAAK,GAAG;AAC/B,cAAM,UAAmC;AAAA,UACvC,WAAW,WAAG;AAAA,UACd,MAAM,KAAK,cAAc,YAAa,MAAM,UAAwB,UAAU,KAAK,CAAC;AAAA,UACpF,aAAa,WAAW,KAAK,KAAK;AAAA,UAClC,aAAa,WAAW,KAAK,OAAO;AAAA,UACpC,kBAAkB,WAAW,KAAK,KAAK;AAAA,UACvC,kBAAkB,WAAW,KAAK,OAAO;AAAA,UACzC,kBAAkB;AAAA;AAAA,UAElB,aAAa,CAAC,EAAE,KAAK,IAAI,CAAC;AAAA,QAC5B;AACA,YAAI,KAAK,MAAO,SAAQ,iBAAiB,WAAW,KAAK,KAAK;AAC9D,YAAI,KAAK,YAAa,SAAQ,cAAc,SAAS,KAAK,WAAW;AACrE,YAAI,KAAK,YAAY;AACnB,kBAAQ,aAAa,KAAK,MAAMA,cAAa,KAAK,YAAY,OAAO,CAAC;AAAA,QACxE;AAGA,cAAM,WAAW,EAAE,KAAK,WAAW,KAAK,GAAG,GAAG,KAAK,WAAW,KAAK,GAAG,EAAE;AACxE,cAAM,YAAY,EAAE,KAAK,WAAW,KAAK,GAAG,GAAG,KAAK,WAAW,KAAK,GAAG,EAAE;AAEzE,cAAM,WAAY,MAAM,YAA0B,CAAC;AACnD,iBAAS,KAAK,OAAO;AACrB,cAAM,WAAW;AAEjB,eAAO;AAAA,MACT,CAAC;AACD,aAAO,QAAQE,eAAc,OAAO,CAAC;AAAA,IACvC,SAAS,KAAK;AACZ,kBAAY,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,CAAC;AAAA,IACjE;AAAA,EACF,CAAC;AAGH,UACG,QAAQ,QAAQ,EAChB,YAAY,gCAAgC,EAC5C,QAAQ,SAAS,EACjB,YAAY,2BAA2B,EACvC,OAAO,iBAAiB,iBAAiB,EACzC,eAAe,eAAe,yBAAyB,EACvD,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAAS,YAAY,YAAY,IAAI,GAAG,CAAC,UAAU;AACvD,cAAM,WAAY,MAAM,YAA0B,CAAC;AACnD,cAAM,MAAM,SAAS,KAAK,KAAK;AAC/B,YAAI,MAAM,KAAK,OAAO,SAAS,QAAQ;AACrC,gBAAM,IAAI,MAAM,iBAAiB,GAAG,oBAAoB,SAAS,SAAS,CAAC,GAAG;AAAA,QAChF;AACA,iBAAS,OAAO,KAAK,CAAC;AACtB,cAAM,WAAW,SAAS,SAAS,IAAI,WAAW;AAClD,eAAO;AAAA,MACT,CAAC;AACD,aAAO,QAAQA,eAAc,OAAO,CAAC;AAAA,IACvC,SAAS,KAAK;AACZ,kBAAY,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,CAAC;AAAA,IACjE;AAAA,EACF,CAAC;AAGH,MACG,QAAQ,OAAO,EACf;AAAA,IACC;AAAA,EAGF,EACC,OAAO,iBAAiB,iBAAiB,EACzC,eAAe,kBAAkB,+BAA+B,EAChE,OAAO,sBAAsB,kBAAkB,EAC/C,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASA,eAAc,OAAO;AACpC,YAAM,cAAc,oBAAoB,SAAS,MAAM;AAGvD,YAAM,WAAW,MAAM,YAAY,IAAI,iBAAiB,KAAK,OAAO,EAAE;AACtE,YAAM,QAAQ,SAAS;AAEvB,YAAM,SAAS,YAAY,YAAY,IAAI,GAAG,CAAC,UAAU;AACvD,cAAM,aAAa;AACnB,cAAM,4BAA4B;AAElC,cAAM,WAAW;AACjB,YAAI,KAAK,aAAa;AAEpB,gBAAM,WAAW,MAAM;AACvB,cAAI,UAAU,QAAQ;AACpB,qBAAS,CAAC,EAAE,cAAc,SAAS,KAAK,WAAW;AAAA,UACrD;AAAA,QACF;AACA,eAAO;AAAA,MACT,CAAC;AACD,aAAO,QAAQ,MAAM;AAAA,IACvB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAGH,MACG,QAAQ,KAAK,EACb;AAAA,IACC;AAAA,EAGF,EACC,OAAO,iBAAiB,iBAAiB,EACzC,eAAe,gBAAgB,6BAA6B,EAC5D,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASA,eAAc,OAAO;AACpC,YAAM,cAAc,oBAAoB,SAAS,MAAM;AAGvD,YAAM,UAAU,MAAM,YAAY,IAAI,eAAe,EAAE,QAAQ,EAAE,UAAU,KAAK,EAAE,CAAC;AACnF,YAAM,UAAU,MAAM,QAAQ,QAAQ,IAAI,KAAK,MAAM,QAAQ,QAAQ,KAAK,CAAC,CAAC,IACxE,QAAQ,KAAK,CAAC,IACb,MAAM,QAAQ,QAAQ,IAAI,IAAI,QAAQ,OAAO,QAAQ,MAAM,QAAQ,CAAC;AACzE,YAAM,QAAQ,SAAS,KAAK,KAAK;AACjC,YAAM,MAAM,QAAQ,KAAK,CAAC,MAA+B,EAAE,eAAe,KAAK;AAC/E,UAAI,CAAC,KAAK;AACR,oBAAY,IAAI,MAAM,OAAO,KAAK,YAAY,CAAC;AAC/C;AAAA,MACF;AAEA,YAAM,SAAS,YAAY,YAAY,IAAI,GAAG,CAAC,UAAU;AACvD,cAAM,WAAW;AACjB,cAAM,4BAA4B;AAElC,cAAM,aAAa;AACnB,cAAM,iBAAiB;AACvB,eAAO;AAAA,MACT,CAAC;AACD,aAAO,QAAQ,MAAM;AAAA,IACvB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAGH,MACG,QAAQ,UAAU,EAClB;AAAA,IACC;AAAA,EAEF,EACC,OAAO,iBAAiB,iBAAiB,EACzC,eAAe,uBAAuB,8CAA8C,EACpF,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASA,eAAc,OAAO;AACpC,YAAM,cAAc,oBAAoB,SAAS,MAAM;AACvD,YAAM,MAAM,KAAK,WAAW,MAAM,GAAG,EAAE,IAAI,CAAC,MAAc,SAAS,EAAE,KAAK,CAAC,CAAC;AAE5E,YAAM,YAAuB,CAAC;AAC9B,iBAAW,MAAM,KAAK;AACpB,cAAM,MAAM,MAAM,YAAY,IAAI,mBAAmB,EAAE,EAAE;AACzD,kBAAU,KAAK,IAAI,IAAI;AAAA,MACzB;AAEA,YAAM,SAAS,YAAY,YAAY,IAAI,GAAG,CAAC,UAAU;AACvD,cAAM,iBAAiB;AACvB,eAAO;AAAA,MACT,CAAC;AACD,aAAO,QAAQ,MAAM;AAAA,IACvB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAGH,MACG,QAAQ,OAAO,EACf,YAAY,kEAAkE,EAC9E,OAAO,iBAAiB,iBAAiB,EACzC,eAAe,kBAAkB,oCAAoC,EACrE,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,UAAI,CAAC,CAAC,gBAAgB,aAAa,EAAE,SAAS,KAAK,KAAK,GAAG;AACzD,oBAAY,IAAI,MAAM,2CAA2C,CAAC;AAClE;AAAA,MACF;AACA,YAAM,SAAS,YAAY,YAAY,IAAI,GAAG,CAAC,UAAU;AACvD,cAAM,yBAAyB,KAAK;AACpC,eAAO;AAAA,MACT,CAAC;AACD,aAAO,QAAQA,eAAc,OAAO,CAAC;AAAA,IACvC,SAAS,KAAK;AACZ,kBAAY,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,CAAC;AAAA,IACjE;AAAA,EACF,CAAC;AAGH,MACG,QAAQ,WAAW,EACnB;AAAA,IACC;AAAA,EAEF,EACC,OAAO,iBAAiB,iBAAiB,EACzC,OAAO,gBAAgB,mBAAmB,EAC1C,OAAO,oBAAoB,kCAA6B,EACxD,OAAO,kBAAkB,gCAAgC,EACzD,OAAO,mBAAmB,2BAA2B,EACrD,OAAO,mBAAmB,gBAAgB,EAC1C,OAAO,mBAAmB,0BAA0B,EACpD,OAAO,wBAAwB,2BAA2B,EAC1D,OAAO,0BAA0B,sEAAsE,EACvG,OAAO,4BAA4B,iCAA4B,EAC/D,OAAO,gCAAgC,qCAAgC,EACvE,OAAO,yBAAyB,iHAAyG,EACzI,OAAO,8BAA8B,iCAAiC,EACtE,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAAS,YAAY,YAAY,IAAI,GAAG,CAAC,UAAU;AACvD,cAAM,KAAM,MAAM,mBAAmB,CAAC;AACtC,YAAI,KAAK,WAAW,OAAW,IAAG,SAAS,WAAW,KAAK,MAAM;AACjE,YAAI,KAAK,cAAc,OAAW,IAAG,YAAY,WAAW,KAAK,SAAS;AAC1E,YAAI,KAAK,aAAa,OAAW,IAAG,sBAAsB,SAAS,KAAK,QAAQ;AAChF,YAAI,KAAK,cAAc,OAAW,IAAG,YAAY,WAAW,KAAK,SAAS;AAC1E,YAAI,KAAK,aAAa,OAAW,IAAG,kBAAkB,WAAW,KAAK,QAAQ;AAC9E,YAAI,KAAK,aAAc,IAAG,eAAe;AACzC,YAAI,KAAK,kBAAkB,OAAW,IAAG,0BAA0B,WAAW,KAAK,aAAa;AAChG,YAAI,KAAK,aAAc,IAAG,2BAA2B,KAAK;AAC1D,YAAI,KAAK,qBAAqB,OAAW,IAAG,mBAAmB,WAAW,KAAK,gBAAgB;AAC/F,YAAI,KAAK,yBAAyB,OAAW,IAAG,uBAAuB,WAAW,KAAK,oBAAoB;AAC3G,YAAI,KAAK,kBAAkB,OAAW,IAAG,gBAAgB,WAAW,KAAK,aAAa;AACtF,YAAI,KAAK,wBAAwB,OAAW,IAAG,gCAAgC,WAAW,KAAK,mBAAmB;AAWlH,YAAI,KAAK,kBAAkB,UAAa,KAAK,cAAc,QAAW;AACpE,gBAAM,WAAY,MAAM,YAAsD,CAAC;AAC/E,cAAI,aAAa;AACjB,cAAI,gBAAgB;AACpB,cAAI,aAAa;AACjB,qBAAW,WAAW,UAAU;AAC9B,kBAAM,EAAE,gBAAgB,UAAU,IAAI,6BAA6B,SAAS,KAAK;AACjF,gBAAI,WAAW;AACb,2BAAa;AACb;AAAA,YACF;AACA,0BAAc;AACd,6BAAiB;AAAA,UACnB;AACA,cAAI,gBAAgB,KAAK,CAAC,YAAY;AACpC,eAAG,YAAY,KAAK,MAAM,WAAW,KAAK,aAAa,IAAI,aAAa,GAAG,IAAI;AAAA,UACjF,OAAO;AACL,oBAAQ,OAAO;AAAA,cACb,KAAK,UAAU;AAAA,gBACb,SACE,4DACC,SAAS,WAAW,IACjB,+BACA,sFACJ;AAAA,cACJ,CAAC,IAAI;AAAA,YACP;AAAA,UACF;AAAA,QACF;AAEA,cAAM,kBAAkB;AACxB,eAAO;AAAA,MACT,CAAC;AACD,aAAO,QAAQA,eAAc,OAAO,CAAC;AAAA,IACvC,SAAS,KAAK;AACZ,kBAAY,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,CAAC;AAAA,IACjE;AAAA,EACF,CAAC;AAGH,MACG,QAAQ,eAAe,EACvB;AAAA,IACC;AAAA,EAEF,EACC,OAAO,iBAAiB,iBAAiB,EACzC,eAAe,oBAAoB,4CAA4C,eAAe,CAAC,CAAC,EAChG,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASA,eAAc,OAAO;AACpC,YAAM,cAAc,oBAAoB,SAAS,MAAM;AAGvD,YAAM,SAAoB,CAAC;AAC3B,iBAAW,EAAE,IAAI,SAAS,KAAK,KAAK,OAAO;AACzC,cAAM,MAAM,MAAM,YAAY,IAAI,oBAAoB,EAAE,EAAE;AAC1D,eAAO,KAAK,EAAE,aAAa,IAAI,MAAM,SAAS,CAAC;AAAA,MACjD;AAEA,YAAM,SAAS,YAAY,YAAY,IAAI,GAAG,CAAC,UAAU;AACvD,cAAM,uBAAuB;AAC7B,eAAO;AAAA,MACT,CAAC;AACD,aAAO,QAAQ,MAAM;AAAA,IACvB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAGH,MACG,QAAQ,WAAW,EACnB;AAAA,IACC;AAAA,EAEF,EACC,OAAO,iBAAiB,iBAAiB,EACzC,OAAO,YAAY,kBAAkB,EACrC,OAAO,aAAa,mBAAmB,EACvC,OAAO,oBAAoB,2BAA2B,EACtD,OAAO,eAAe,qBAAqB,EAC3C,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAAS,YAAY,YAAY,IAAI,GAAG,CAAC,UAAU;AACvD,YAAI,KAAK,OAAQ,OAAM,kBAAkB;AACzC,YAAI,KAAK,QAAS,OAAM,kBAAkB;AAC1C,YAAI,KAAK,WAAW;AAElB,gBAAM,SAAU,MAAM,0BAA0B,CAAC;AACjD,iBAAO,YAAY,SAAS,KAAK,SAAS;AAC1C,cAAI,KAAK,MAAO,QAAO,kBAAkB,SAAS,KAAK,KAAK;AAC5D,gBAAM,yBAAyB;AAAA,QACjC;AACA,eAAO;AAAA,MACT,CAAC;AACD,aAAO,QAAQA,eAAc,OAAO,CAAC;AAAA,IACvC,SAAS,KAAK;AACZ,kBAAY,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,CAAC;AAAA,IACjE;AAAA,EACF,CAAC;AAGH,MACG,QAAQ,MAAM,EACd;AAAA,IACC;AAAA;AAAA,EAEF,EACC,OAAO,iBAAiB,iBAAiB,EACzC,eAAe,iBAAiB,8BAA8B,EAC9D,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAAS,KAAK,MAAM,KAAK,IAAI;AAEnC,YAAM,gBAAgB,OAAO,KAAK,MAAM;AACxC,UAAI;AACJ,UAAI,cAAc,SAAS,aAAa,EAAG,gBAAe;AAC1D,UAAI,cAAc,SAAS,UAAU,EAAG,gBAAe;AAEvD,YAAM,SAAS,YAAY,YAAY,IAAI,GAAG,CAAC,UAAU;AACvD,kBAAU,OAAO,MAAM;AACvB,eAAO;AAAA,MACT,CAAC;AACD,aAAO,QAAQA,eAAc,OAAO,CAAC;AAAA,IACvC,SAAS,KAAK;AACZ,kBAAY,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,CAAC;AAAA,IACjE;AAAA,EACF,CAAC;AAOH,UACG,QAAQ,WAAW,EACnB,YAAY,sCAAsC,EAClD,QAAQ,YAAY,EACpB;AAAA,IACC;AAAA,EAEF,EACC,OAAO,iBAAiB,iBAAiB,EACzC,OAAO,uBAAuB,sCAAsC,EACpE,OAAO,kBAAkB,4BAA4B,EACrD,OAAO,gBAAgB,qBAAqB,IAAI,EAChD,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASA,eAAc,OAAO;AACpC,YAAM,WAAW,YAAY,IAAI;AACjC,YAAM,QAAQ,UAAU,QAAQ;AAChC,YAAM,WAAW,MAAM;AAEvB,UAAI,CAAC,UAAU,QAAQ;AACrB,oBAAY,IAAI,MAAM,gDAAgD,CAAC;AACvE;AAAA,MACF;AAEA,YAAM,cAAc,oBAAoB,SAAS,MAAM;AACvD,YAAM,gBAAgB,KAAK,iBAAiB,SACxC,CAAC,SAAS,KAAK,YAAY,CAAC,IAC5B,MAAM,KAAK,EAAE,QAAQ,SAAS,OAAO,GAAG,CAAC,GAAG,MAAM,CAAC;AAEvD,iBAAW,OAAO,eAAe;AAC/B,cAAM,UAAU,SAAS,GAAG;AAC5B,YAAI,CAAC,QAAS;AAEd,cAAM,SAAS,0BAA0B,SAAS,KAAK;AACvD,YAAI,CAAC,QAAQ;AACX,sBAAY,IAAI,MAAM,WAAW,GAAG,+DAA+D,CAAC;AACpG;AAAA,QACF;AACA,cAAM,EAAE,KAAK,IAAI,IAAI;AAErB,cAAM,EAAE,gBAAgB,UAAU,IAAI,6BAA6B,SAAS,KAAK;AACjF,YAAI,WAAW;AACb,sBAAY,IAAI;AAAA,YACd,WAAW,GAAG;AAAA,UAEhB,CAAC;AAAA,QACH;AACA,cAAM,OAAO;AAAA,UACX;AAAA,UACA,MAAM;AAAA,UACN,eAAe;AAAA,UACf,OAAQ,QAAQ,eAA2B,QAAQ,SAAoB;AAAA,UACvE,SAAU,QAAQ,eAA2B,QAAQ,WAAsB;AAAA,UAC3E,kBAAkB,WAAW,KAAK,MAAM;AAAA,UACxC,OAAM,oBAAI,KAAK,GAAE,YAAY;AAAA,UAC7B,aAAa;AAAA,QACf;AACA,cAAM,MAAM,MAAM,YAAY,KAAK,oCAAoC,IAAI;AAC3E,gBAAQ,aAAa,IAAI;AAAA,MAC3B;AAGA,YAAM,SAAS,YAAY,UAAU,CAAC,MAAM;AAC1C,UAAE,WAAW;AACb,eAAO;AAAA,MACT,CAAC;AACD,aAAO,QAAQ,MAAM;AAAA,IACvB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAGH,UACG,QAAQ,mBAAmB,EAC3B;AAAA,IACC;AAAA,EAIF,EACC,OAAO,iBAAiB,iBAAiB,EACzC,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASA,eAAc,OAAO;AACpC,YAAM,WAAW,YAAY,IAAI;AACjC,YAAM,QAAQ,UAAU,QAAQ;AAEhC,YAAM,cAAc,MAAM;AAC1B,UAAI,CAAC,aAAa,MAAM,QAAQ;AAC9B,oBAAY,IAAI,MAAM,oDAAoD,CAAC;AAC3E;AAAA,MACF;AAEA,YAAM,WAAW,MAAM;AACvB,UAAI,CAAC,UAAU,QAAQ;AACrB,oBAAY,IAAI,MAAM,uCAAuC,CAAC;AAC9D;AAAA,MACF;AAEA,YAAM,eAAe,MAAM;AAC3B,UAAI,CAAC,cAAc;AACjB,oBAAY,IAAI,MAAM,2CAA2C,CAAC;AAClE;AAAA,MACF;AAEA,YAAM,EAAE,WAAW,IAAI,MAAM,OAAO,qDAAqD;AAGzF,YAAM,YAAY,IAAI,WAAW,YAAY,MAAM,OAAO,YAAY,cAAc,eAAe,KAAK;AAGxG,UAAI,iBAAyD;AAC7D,iBAAW,QAAQ,UAAU;AAC3B,cAAM,OAAO,KAAK;AAClB,YAAI,MAAM,MAAM,QAAQ;AACtB,gBAAM,WAAW,IAAI,WAAW,KAAK,MAAM,OAAO,KAAK,cAAc,cAAc,KAAK;AACxF,2BAAiB,iBAAiB,eAAe,oBAAoB,QAAQ,IAAI;AAAA,QACnF;AAAA,MACF;AAEA,UAAI,CAAC,gBAAgB;AACnB,oBAAY,IAAI,MAAM,+DAA+D,CAAC;AACtF;AAAA,MACF;AAEA,YAAM,UAAmC,CAAC;AAK1C,YAAM,sBAAsB,UAAU,oBAAoB,eAAe,gBAAgB,EAAE,CAAC;AAC5F,cAAQ,iBAAiB;AAGzB,cAAQ,kBAAkB,eAAe,kBAAkB;AAG3D,cAAQ,2BACJ,QAAQ,kBAA6B,UAAU,kBAAkB,IAAK;AAG1E,YAAM,qBAAqB,MAAM,wBAAwB,OAAO,MAAM;AAEtE,UAAI,oBAAoB;AACtB,cAAM,gBAAgB,MAAM;AAC5B,cAAM,SAAS,MAAM;AACrB,cAAM,8BAA8B,KAAM,MAAM,wBAAmC,KAAK;AACxF,cAAM,6BAA6B,KAAM,MAAM,uBAAkC,KAAK;AAGtF,cAAM,8BAA8B,oBAAoB,qBAAqB;AAC7E,cAAM,sBAAsB,4BAA4B,kBAAkB,kBAAkB;AAC5F,cAAM,yBAAyB,UAAU,kBAAkB,kBAAkB;AAG7E,cAAM,kBAAmB,MAAM,mBAAmB,CAAC;AACnD,cAAM,cAAe,MAAM,eAAe,CAAC;AAC3C,cAAM,iCAAiD,CAAC;AACxD,YAAI,MAAM,sBAAsB;AAC9B,mBAAS,IAAI,GAAG,KAAK,GAAG,KAAK;AAC3B,kBAAM,IAAI,IAAI,CAAC;AACf,gBAAI,gBAAgB,CAAC,KAAK,YAAY,CAAC,GAAG;AACxC,6CAA+B,CAAC,IAC7B,gBAAgB,CAAC,IAAe,MAAO,YAAY,CAAC,IAAe;AAAA,YACxE;AAAA,UACF;AAAA,QACF;AAGA,YAAI,WAAW,MAAM;AACnB,gBAAM,iBAAkB,MAAM,kBAAkB,CAAC;AACjD,cAAI,kBAAkB;AACtB,6BAAmB,QAAQ,CAAC,QAAa;AACvC,mBAAO,OAAO,IAAI,UAAU,EAAE,QAAQ,CAAC,SAAc;AACnD,kBAAI,SAAS,EAAG;AAAA,YAClB,CAAC;AAAA,UACH,CAAC;AACD,gBAAM,cACH,IAAI,mBAAqB,eAAe,MAAiB,KAAK,oBAAoB,KAAK;AAC1F,kBAAQ,4BAA6B,wBAAgC,MAAM,KAAK;AAChF,kBAAQ,4BAA6B,qBAA6B,MAAM,KAAK;AAAA,QAC/E;AAGA,cAAM,2BAA2C,CAAC;AAClD,iBAAS,IAAI,GAAG,KAAK,GAAG,KAAK;AAC3B,gBAAM,IAAI,IAAI,CAAC;AACf,gBAAM,WAAY,yBAAiC,CAAC,KAAK;AACzD,gBAAM,SAAU,aAAa,CAAC,KAAgB;AAC9C,gBAAM,eAAe,eAAe;AACpC,gBAAM,SAAU,eAAe,mBAA8B;AAC7D,gBAAM,eAAe,gBAAgB,SAAS,UAAU,IAAI,SAAS,OAAO;AAC5E,mCAAyB,CAAC,IACxB,WAAW,eAAe,+BACxB,+BAA+B,CAAC,KAAgB;AAAA,QACtD;AACA,gBAAQ,2BAA2B;AAGnC,gBAAQ,mBACN,OAAO,OAAO,wBAAwB,EACnC,OAAO,CAAC,MAAmB,OAAO,MAAM,QAAQ,EAChD,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC,KAAM,QAAQ,4BAAuC;AAGnF,cAAM,0BAA2B,MAAM,2BAA2B,CAAC;AACnE,cAAM,yBAA0B,MAAM,0BAA0B,CAAC;AACjE,cAAM,mCAAmD,CAAC;AAC1D,cAAM,iCAAiD,CAAC;AAExD,YAAI,MAAM,sBAAsB;AAC9B,mBAAS,IAAI,GAAG,KAAK,GAAG,KAAK;AAC3B,kBAAM,IAAI,IAAI,CAAC;AACf,gBAAI,gBAAgB,CAAC,KAAK,uBAAuB,CAAC,GAAG;AACnD,+CAAiC,CAAC,IAC/B,gBAAgB,CAAC,IAAe,MAAO,uBAAuB,CAAC;AAAA,YACpE;AACA,gBAAI,gBAAgB,CAAC,KAAK,YAAY,CAAC,KAAK,uBAAuB,CAAC,GAAG;AACrE,6CAA+B,CAAC,IAC7B,gBAAgB,CAAC,IAAe,MAAO,YAAY,CAAC,IAAe,6BACnE,gBAAgB,CAAC,IAAe,MAAO,uBAAuB,CAAC,IAAe;AAAA,YACnF;AAAA,UACF;AACA,kBAAQ,iCAAiC;AAAA,QAC3C;AAEA,cAAM,2BAA2C,CAAC;AAClD,cAAM,sCAAsD,CAAC;AAE7D,iBAAS,IAAI,GAAG,KAAK,GAAG,KAAK;AAC3B,gBAAM,IAAI,IAAI,CAAC;AACf,gBAAM,UAAW,sBAA8B,CAAC,KAAK;AACrD,gBAAM,SAAU,aAAa,CAAC,KAAgB;AAC9C,gBAAM,YAAa,wBAAwB,CAAC,KAAgB;AAC5D,gBAAM,eAAe,eAAe;AACpC,gBAAM,SAAU,eAAe,mBAA8B;AAE7D,mCAAyB,CAAC,IACxB,WAAW,eAAe,UAAU,IAAI,SAAS,OAAO,UAAU;AAEpE,cAAI,MAAM,yBAAyB;AACjC,gDAAoC,CAAC,IACnC,UAAU,aAAc,iCAAiC,CAAC,KAAgB;AAAA,UAC9E;AAAA,QACF;AACA,gBAAQ,2BAA2B;AACnC,YAAI,MAAM,yBAAyB;AACjC,kBAAQ,sCAAsC;AAAA,QAChD;AAGA,gBAAQ,mBACN,OAAO,OAAO,wBAAwB,EACnC,OAAO,CAAC,MAAmB,OAAO,MAAM,QAAQ,EAChD,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC,KAAM,QAAQ,4BAAuC;AAGnF,cAAM,uBAAuC,CAAC;AAC9C,iBAAS,IAAI,GAAG,KAAK,GAAG,KAAK;AAC3B,gBAAM,IAAI,IAAI,CAAC;AACf,+BAAqB,CAAC,KAClB,yBAAyB,CAAC,KAAgB,MAAO,yBAAyB,CAAC,KAAgB;AAAA,QACjG;AACA,gBAAQ,uBAAuB;AAG/B,YAAI,MAAM,yBAAyB;AACjC,gBAAM,aAA6B,CAAC;AACpC,mBAAS,IAAI,GAAG,KAAK,GAAG,KAAK;AAC3B,kBAAM,IAAI,IAAI,CAAC;AACf,uBAAW,CAAC,KACR,yBAAyB,CAAC,KAAgB,MAC1C,oCAAoC,CAAC,KAAgB;AAAA,UAC3D;AACA,kBAAQ,yCAAyC;AAAA,QACnD;AAGA,gBAAQ,eACN,OAAO,OAAO,oBAAoB,EAC/B,OAAO,CAAC,MAAmB,OAAO,MAAM,QAAQ,EAChD,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC,MACzB,QAAQ,4BAAuC,MAC9C,QAAQ,4BAAuC;AAGrD,YAAI,MAAM,yBAAyB;AACjC,kBAAQ,gCACN,OAAO,OAAO,mCAAmC,EAC9C,OAAO,CAAC,MAAmB,OAAO,MAAM,QAAQ,EAChD,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC,MACzB,QAAQ,4BAAuC,MAC9C,QAAQ,4BAAuC;AAAA,QACvD;AAGA,cAAM,gBAAgB,eACnB,oBAAoB,UAAU,gBAAgB,EAAE,CAAC,EACjD,qBAAqB;AACxB,gBAAQ,gBAAgB;AAGxB,gBAAQ,wBAAwB,cAAc,kBAAkB,kBAAkB;AAClF,gBAAQ,gBAAgB,OAAO,OAAO,QAAQ,qBAAuC,EAClF,OAAO,CAAC,MAAmB,OAAO,MAAM,QAAQ,EAChD,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC;AAAA,MAC9B;AAEA,YAAM,SAAS,YAAY,UAAU,CAAC,MAAM;AAC1C,UAAE,UAAU;AACZ,eAAO;AAAA,MACT,CAAC;AACD,aAAO,QAAQ,MAAM;AAAA,IACvB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAMH,UACG,QAAQ,oBAAoB,EAC5B;AAAA,IACC;AAAA,EAgBF,EACC,OAAO,iBAAiB,iBAAiB,EACzC,OAAO,0BAA0B,yBAAyB,EAC1D,OAAO,2BAA2B,uCAAuC,EACzE,OAAO,wBAAwB,iCAAiC,EAChE,OAAO,mCAAmC,gCAAgC,EAC1E,OAAO,cAAc,2DAA2D,EAChF,OAAO,WAAW,gFAAgF,EAClG,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASA,eAAc,OAAO;AACpC,YAAM,WAAW,YAAY,IAAI;AACjC,YAAM,QAAQ,UAAU,QAAQ;AAGhC,YAAM,iBAAyC,CAAC;AAChD,UAAI,KAAK,kBAAkB,OAAW,gBAAe,0BAA0B,WAAW,KAAK,aAAa;AAAA,eACnG,KAAK,mBAAmB,OAAW,gBAAe,2BAA2B,WAAW,KAAK,cAAc;AAAA,eAC3G,KAAK,gBAAgB,OAAW,gBAAe,wBAAwB,WAAW,KAAK,WAAW;AAAA,eAClG,KAAK,4BAA4B,OAAW,gBAAe,kCAAkC,SAAS,KAAK,uBAAuB;AAAA,WACtI;AAEH,uBAAe,2BAA2B;AAAA,MAC5C;AAGA,YAAM,WAAW,MAAM;AACvB,UAAI,CAAC,UAAU,QAAQ;AACrB,oBAAY,IAAI,MAAM,gDAAgD,CAAC;AACvE;AAAA,MACF;AACA,YAAM,kBAAkB,MAAM;AAC9B,UAAI,CAAC,iBAAiB;AACpB,oBAAY,IAAI,MAAM,uDAAuD,CAAC;AAC9E;AAAA,MACF;AAGA,YAAM,4BAA4B,SAAS,OAAO,CAAC,MAAM,CAAC,EAAE,UAAU;AACtE,UAAI,0BAA0B,SAAS,GAAG;AACxC,oBAAY,IAAI,MAAM,GAAG,0BAA0B,MAAM,kFAAkF,CAAC;AAC5I;AAAA,MACF;AAEA,YAAM,EAAE,WAAW,IAAI,MAAM,OAAO,qDAAqD;AAGzF,YAAM,KAAK;AACX,YAAM,mBAAmB,IAAI,WAAW,GAAG,QAAQ,IAAI,GAAG,WAAW,OAAO,GAAG,cAAc,eAAe,GAAG,aAAa,KAAK;AACjI,YAAM,mBAAmB,iBAAiB,kBAAkB;AAG5D,YAAM,iBAAsC,CAAC;AAC7C,iBAAW,WAAW,UAAU;AAC9B,cAAM,MAAM,QAAQ;AACpB,cAAM,WAAW,QAAQ;AACzB,cAAM,YAAY,IAAI,WAAW,SAAS,QAAQ,UAAU,OAAO,KAAK,KAAK;AAC7E,cAAM,iBAAkB,QAAQ,kBAA6B;AAE7D,uBAAe,GAAG,IAAI,UAAU,gBAAgB,KAAK,iBAAiB,IAAK;AAAA,MAC7E;AAGA,YAAM,UAAU,KAAK,WAAW,MAAM,8BAA8B;AACpE,YAAM,cAAc,oBAAoB,SAAS,MAAM;AAEvD,UAAI,SAAS;AAEX,cAAM,cAAe,MAAM,eAA0B;AAGrD,cAAM,UAAU,MAAM,YAAY,IAAI,eAAe,EAAE,QAAQ,EAAE,OAAO,IAAI,EAAE,CAAC;AAC/E,YAAI,UAAU,MAAM,QAAQ,QAAQ,IAAI,KAAK,MAAM,QAAQ,QAAQ,KAAK,CAAC,CAAC,IACtE,QAAQ,KAAK,CAAC,IACb,MAAM,QAAQ,QAAQ,IAAI,IAAI,QAAQ,OAAO,QAAQ,MAAM,QAAQ,CAAC;AAGzE,kBAAU,QAAQ,OAAO,CAAC,MAAW,EAAE,gBAAgB,eAAe,EAAE,WAAW,KAAK;AAGxF,cAAM,aAAa,SAAS,MAAM,CAAC,MAAM,CAAE,EAAE,gBAA2B;AACxE,kBAAU,QAAQ;AAAA,UAAO,CAAC,MACxB,eAAe,SAAY,OAAO,gBAAgB,EAAE,aAAa,OAAO,OAAO,EAAE;AAAA,QACnF;AAGA,gBAAQ;AAAA,UAAK,CAAC,GAAQ,MACnB,EAAE,eAAe,EAAE,eAAe,aAAa,KAAO,EAAE,eAAe,EAAE,eAAe,aAAa;AAAA,QACxG;AAEA,YAAI,QAAQ,WAAW,GAAG;AACxB,sBAAY,IAAI,MAAM,kEAAkE,CAAC;AACzF;AAAA,QACF;AAEA,YAAI,cAAmB;AACvB,YAAI,gBAAqB;AACzB,YAAI,kBAAkB;AACtB,YAAI,gBAAqB;AACzB,cAAM,kBAAuC,CAAC;AAE9C,mBAAW,OAAO,SAAS;AACzB,gBAAM,WAAW,IAAI;AACrB,cAAI,CAAC,SAAU;AAGf,cAAI,kBAAkB,IAAI,eAAe;AACzC,gBAAM,iBAAyC,CAAC;AAChD,cAAI,OAAO;AAEX,qBAAW,WAAW,UAAU;AAC9B,kBAAM,MAAM,QAAQ;AACpB,kBAAM,OAAO,QAAQ;AACrB,gBAAI;AAEJ,gBAAI,QAAQ,SAAS,SAAS,SAAS,QAAQ;AAE7C,0BAAY;AAAA,gBACV;AAAA,gBACA;AAAA,gBACC,QAAQ,2BAAsC;AAAA,gBAC9C,QAAQ,oBAA+B;AAAA,gBACvC,QAAQ,eAA0B;AAAA,gBAClC,QAAQ,iBAA4B;AAAA,gBACrC,0BAA0B,SAAS,KAAK,GAAG,OAAO;AAAA,cACpD;AAAA,YACF,OAAO;AAEL,0BAAY;AAAA,YACd;AAEA,kBAAM,WAAW,KAAK,IAAI,iBAAiB,SAAS;AACpD,2BAAe,GAAG,IAAI;AACtB,+BAAmB;AAAA,UACrB;AAEA,cAAI,kBAAkB,EAAG;AAEzB,cAAI,CAAC,cAAe,iBAAgB;AAGpC,cAAI,YAAiB;AACrB,qBAAW,WAAW,UAAU;AAC9B,kBAAM,MAAM,QAAQ;AACpB,kBAAM,aAAa,eAAe,GAAG,KAAK;AAC1C,kBAAM,gBAAiB,aAAa,SAAS,YAAa;AAC1D,kBAAM,WAAW,eAAe,GAAG,EAAE,gBAAgB,aAAa;AAClE,wBAAY,YAAY,UAAU,oBAAoB,QAAQ,IAAI;AAAA,UACpE;AAEA,gBAAM,iBAAiB,iBAAiB,oBAAoB,UAAU,gBAAgB,EAAE,CAAC;AACzF,gBAAM,gBAAiB,IAAI,eAAe,KAAK,SAAS,YAAa;AACrE,gBAAM,eAAe,UAAU,kBAAkB;AAGjD,cAAI;AACJ,cAAI,eAAe;AAEnB,cAAI,eAAe,4BAA4B,QAAW;AACxD,kBAAM,cAAc,eAAe,qBAAqB,EAAE,kBAAkB;AAC5E,8BAAmB,mBAAmB,eAAe,mBAAoB;AACzE,2BAAe,kBAAkB,eAAe;AAAA,UAClD,WAAW,eAAe,6BAA6B,QAAW;AAChE,6BAAkB,eAAe,mBAAoB;AACrD,2BAAe,kBAAkB,eAAe;AAAA,UAClD,WAAW,eAAe,0BAA0B,QAAW;AAC7D,kBAAM,gBAAgB,eAAe,qBAAqB;AAC1D,6BAAkB,cAAc,kBAAkB,IAAI,eAAgB,MAAM;AAC5E,2BAAe,kBAAkB,eAAe;AAAA,UAClD,WAAW,eAAe,oCAAoC,QAAW;AACvE,kBAAM,QAAQ,eAAe,oBAAoB,EAAE,WAAW;AAC9D,gBAAI,UAAU,MAAM,OAAO,KAAK,KAAK,EAAE,KAAK,CAAC,MAAM,MAAM,YAAY,KAAK,EAAE,KAAK,CAAC;AAClF,mBAAO,QAAQ;AACf,6BAAiB,OAAO,OAAO,OAAO,EAAE,OAAO,CAAC,MAAW,IAAI,CAAC,EAAE;AAClE,2BAAe,kBAAkB,eAAe;AAAA,UAClD,OAAO;AACL,6BAAiB;AAAA,UACnB;AAEA,0BAAgB,IAAI,UAAU,IAAI;AAAA,YAChC,YAAY,IAAI;AAAA,YAChB,WAAW;AAAA,YACX,iBAAiB;AAAA,YACjB;AAAA,YACA;AAAA,YACA,mBAAmB;AAAA,UACrB;AAEA,cAAI,iBAAiB,iBAAiB;AACpC,8BAAkB;AAClB,4BAAgB;AAAA,UAClB;AAEA,cAAI,cAAc;AAChB,0BAAc;AACd;AAAA,UACF;AAAA,QACF;AAEA,YAAI,CAAC,aAAa;AAChB,wBAAc,iBAAiB;AAAA,QACjC;AAEA,cAAM,aAAsC;AAAA,UAC1C,MAAM;AAAA,UACN;AAAA,UACA,aAAa,cAAc;AAAA,YACzB,YAAY,YAAY;AAAA,YACxB,YAAY,YAAY;AAAA,YACxB,YAAa,YAAY,eAAe,MAAM,YAAY,eAAe,aAAa,KAAM;AAAA,YAC5F,aAAa,YAAY;AAAA,YACzB,OAAO,YAAY;AAAA,UACrB,IAAI;AAAA,UACJ,eAAe,OAAO,KAAK,eAAe,EAAE;AAAA,UAC5C;AAAA,QACF;AAEA,YAAI,KAAK,SAAS,aAAa;AAC7B,sBAAY,UAAU,CAAC,MAAM;AAC3B,cAAE,WAAW;AACb,cAAE,4BAA4B;AAC9B,cAAE,aAAa;AACf,cAAE,iBAAiB;AACnB,cAAE,8BAA8B;AAChC,mBAAO;AAAA,UACT,CAAC;AACD,qBAAW,UAAU;AAAA,QACvB;AAEA,eAAO,YAAY,MAAM;AAAA,MAC3B,OAAO;AAEL,cAAM,QAAQ,MAAM;AACpB,YAAI,CAAC,OAAO;AACV,sBAAY,IAAI,MAAM,4DAA4D,CAAC;AACnF;AAAA,QACF;AAEA,cAAM,iBAAkB,MAAM,aAAwB;AACtD,cAAM,aAAc,MAAM,SAAoB;AAC9C,cAAM,cAAe,MAAM,UAAsB,MAAM,UAAqB;AAC5E,cAAM,WAAW,EAAE,WAAW,gBAAgB,OAAO,YAAY,QAAQ,YAAY;AAGrF,cAAM,uBAA+C,CAAC;AACtD,YAAI,oBAAoB;AAExB,mBAAW,WAAW,UAAU;AAC9B,gBAAM,MAAM,QAAQ;AACpB,gBAAM,OAAO,QAAQ;AAErB,cAAI,QAAQ,cAAc,aAAa;AACrC,kBAAM,YAAY;AAAA,cAChB;AAAA,cACA;AAAA,cACC,QAAQ,2BAAsC;AAAA,cAC9C,QAAQ,oBAA+B;AAAA,cACvC,QAAQ,eAA0B;AAAA,cAClC,QAAQ,iBAA4B;AAAA,cACrC,0BAA0B,SAAS,KAAK,GAAG,OAAO;AAAA,YACpD;AACA,iCAAqB,GAAG,IAAK,YAAY,iBAAkB;AAAA,UAC7D,OAAO;AAEL,iCAAqB,GAAG,IAAI;AAAA,UAC9B;AACA,+BAAqB,qBAAqB,GAAG;AAAA,QAC/C;AAGA,cAAM,cAAc,eAAe,4BAA4B,UAC1D,eAAe,8BAA8B,UAC7C,eAAe,6BAA6B;AAEjD,YAAI,YAAY,cAAc,iBAAiB,MAAO;AACtD,cAAM,kBAAuC,CAAC;AAC9C,YAAI,kBAA0C,CAAC;AAC/C,YAAI;AACJ,cAAM,iBAAiB;AACvB,cAAM,YAAY;AAClB,YAAI,mBAAmB;AACvB,YAAI,uBAAuB;AAE3B,iBAAS,OAAO,GAAG,OAAO,kBAAkB,YAAY,KAAK,aAAa,mBAAmB,QAAQ;AACnG,sBAAY,WAAW,UAAU,QAAQ,CAAC,CAAC;AAC3C;AAEA,cAAI,wBAAwB,IAAI;AAC9B,gCAAoB;AACpB,mCAAuB;AAAA,UACzB;AAGA,cAAI;AACJ,cAAI,YAAY,GAAI,cAAc,iBAAiB,MAAQ;AAAA,mBAClD,YAAY,IAAK,cAAa,IAAI;AAAA,cACtC,cAAa,KAAK;AAGvB,cAAI,YAAY;AAChB,cAAI,YAAiB;AACrB,4BAAkB,CAAC;AAEnB,qBAAW,WAAW,UAAU;AAC9B,kBAAM,MAAM,QAAQ;AACpB,kBAAM,SAAS,KAAK,IAAI,WAAW,qBAAqB,GAAG,CAAC;AAC5D,yBAAa;AACb,4BAAgB,GAAG,IAAI;AACvB,kBAAM,WAAW,eAAe,GAAG,EAAE,gBAAgB,MAAM;AAC3D,wBAAY,YAAY,UAAU,oBAAoB,QAAQ,IAAI;AAAA,UACpE;AAEA,gBAAM,iBAAiB,iBAAiB,oBAAoB,UAAU,gBAAgB,EAAE,CAAC;AACzF,gBAAM,eAAe,UAAU,kBAAkB;AAGjD,cAAI;AACJ,cAAI,eAAe;AAEnB,cAAI,eAAe,4BAA4B,QAAW;AACxD,kBAAM,cAAc,eAAe,qBAAqB,EAAE,kBAAkB;AAC5E,8BAAmB,mBAAmB,eAAe,mBAAoB;AACzE,2BAAe,kBAAkB,eAAe;AAAA,UAClD,WAAW,eAAe,6BAA6B,QAAW;AAChE,6BAAkB,eAAe,mBAAoB;AACrD,2BAAe,kBAAkB,eAAe;AAAA,UAClD,WAAW,eAAe,0BAA0B,QAAW;AAC7D,kBAAM,gBAAgB,eAAe,qBAAqB;AAC1D,6BAAkB,cAAc,kBAAkB,IAAI,eAAgB,MAAM;AAC5E,2BAAe,kBAAkB,eAAe;AAAA,UAClD,WAAW,eAAe,oCAAoC,QAAW;AACvE,kBAAM,QAAQ,eAAe,oBAAoB,EAAE,WAAW;AAC9D,gBAAI,UAAU,MAAM,OAAO,KAAK,KAAK,EAAE,KAAK,CAAC,MAAM,MAAM,YAAY,KAAK,EAAE,KAAK,CAAC;AAClF,mBAAO,QAAQ;AACf,6BAAiB,OAAO,OAAO,OAAO,EAAE,OAAO,CAAC,MAAW,IAAI,CAAC,EAAE;AAClE,2BAAe,kBAAkB,eAAe;AAAA,UAClD,OAAO;AACL,6BAAiB;AAAA,UACnB;AAEA,0BAAgB,SAAS,IAAI;AAAA,YAC3B,iBAAiB;AAAA,YACjB;AAAA,YACA;AAAA,YACA,mBAAmB,EAAE,GAAG,gBAAgB;AAAA,UAC1C;AAEA,cAAI,aAAc;AAGlB,cAAI,eAAe,eAAe,UAAa,cAAc,IAAI,cAAc,gBAAgB;AAC7F;AAAA,UACF;AACA,uBAAa;AAEb,uBAAa,cAAc,aAAa,CAAC;AAAA,QAC3C;AAGA,cAAM,0BAA0B,OAAO,OAAO,eAAe,EAAE,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC;AACxF,cAAM,cAAc,KAAK,MAAM,2BAA2B,iBAAiB,IAAK;AAEhF,cAAM,aAAsC;AAAA,UAC1C,MAAM;AAAA,UACN;AAAA,UACA,oBAAoB,WAAW,wBAAwB,QAAQ,CAAC,CAAC;AAAA,UACjE,iBAAiB;AAAA,UACjB,mBAAmB;AAAA,UACnB,YAAY,OAAO,KAAK,eAAe,EAAE;AAAA,UACzC;AAAA,QACF;AAEA,YAAI,KAAK,OAAO;AACd,sBAAY,UAAU,CAAC,MAAM;AAC3B,kBAAM,QAAQ,EAAE;AAChB,gBAAI,OAAO;AACT,yBAAW,QAAQ,OAAO;AACxB,sBAAM,MAAM,KAAK;AACjB,oBAAI,gBAAgB,GAAG,MAAM,QAAW;AACtC,wBAAM,aAAa,KAAK,MAAM,gBAAgB,GAAG,KAAK,iBAAiB,IAAK;AAC5E,uBAAK,cAAc;AACnB,uBAAK,iBAAiB,gBAAgB,GAAG,IAAI;AAAA,gBAC/C;AAAA,cACF;AAAA,YACF;AACA,cAAE,8BAA8B;AAChC,mBAAO;AAAA,UACT,CAAC;AACD,qBAAW,UAAU;AAAA,QACvB;AAEA,eAAO,YAAY,MAAM;AAAA,MAC3B;AAAA,IACF,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAOH,UACG,QAAQ,aAAa,EACrB;AAAA,IACC;AAAA,EAEF,EACC,OAAO,iBAAiB,iBAAiB,EACzC,eAAe,oBAAoB,cAAc,EACjD,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAAS,YAAY,YAAY,IAAI,GAAG,CAAC,UAAU;AACvD,cAAM,WAAY,MAAM,YAAY,CAAC;AACrC,iBAAS,KAAK,cAAc,aAAa,KAAK,OAAO,CAAC;AACtD,cAAM,WAAW;AACjB,eAAO;AAAA,MACT,CAAC;AACD,aAAO,QAAQA,eAAc,OAAO,CAAC;AAAA,IACvC,SAAS,KAAK;AACZ,kBAAY,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,CAAC;AAAA,IACjE;AAAA,EACF,CAAC;AAGH,UACG,QAAQ,mBAAmB,EAC3B;AAAA,IACC;AAAA,EAEF,EACC,eAAe,oBAAoB,cAAc,EAOjD,UAAU,IAAI,OAAO,iBAAiB,EAAE,SAAS,CAAC,EAClD,UAAU,IAAI,OAAO,2BAA2B,EAAE,SAAS,CAAC,EAC5D,UAAU,IAAI,OAAO,wBAAwB,EAAE,SAAS,CAAC,EACzD,OAAO,OAAO,SAAS,SAAS;AAC/B,QAAI;AACF,0BAAoB,OAAO;AAC3B,YAAM,SAASA,eAAc,OAAO;AACpC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,UAAU,cAAc,aAAa,KAAK,SAAS;AAAA,QACvD,cAAc,QAAQ,KAAK,YAAY;AAAA,QACvC,aAAa,KAAK;AAAA,QAClB,aAAa,KAAK;AAAA,MACpB,CAAC;AACD,YAAM,MAAM,MAAM,OAAO,KAAK,qCAAqC,OAAO,IAAI,OAAO;AAKrF,YAAM,QAAQ,YAAY,IAAI,MAAM,eAAe,OAAO;AAG1D;AAAA,QACE;AAAA,UACE,SAAS;AAAA,UACT,SAAS,oCAAiC,OAAO;AAAA,UACjD;AAAA,UACA,eAAe,MAAM,QAAQ,MAAM,QAAQ,IACvC,MAAM,SAAS,SACf;AAAA,UACJ,SAAS;AAAA,YACP,MAAM,QAAQ;AAAA,YACd,iBAAiB,QAAQ;AAAA,YACzB,mBAAmB,QAAQ;AAAA,YAC3B,aAAa,QAAQ,eAAe;AAAA,YACpC,SAAS,QAAQ;AAAA,UACnB;AAAA,QACF;AAAA,QACA;AAAA,MACF;AAAA,IACF,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AACL;AAKA,eAAe,oBACb,QACA,QACA,QACA,MACA,MACA,MACkB;AAClB,QAAM,iBAAiB,oBAAoB,YAAY,MAAM;AAC7D,QAAM,gBAAgB,oBAAoB,WAAW,MAAM;AAG3D,QAAM,aAAa,MAAM,eAAe,IAAI,iBAAiB;AAAA,IAC3D,QAAQ;AAAA,MACN,WAAW,GAAG,IAAI;AAAA,MAClB,SAAS,GAAG,IAAI;AAAA,MAChB;AAAA,MACA,MAAM;AAAA,MACN;AAAA,IACF;AAAA,EACF,CAAC;AACD,QAAM,UAAU,WAAW,MAAM,WAAW,WAAW;AACvD,MAAI,CAAC,WAAW,CAAC,MAAM,QAAQ,OAAO,KAAK,QAAQ,WAAW,GAAG;AAC/D,UAAM,IAAI,MAAM,8BAA8B;AAAA,EAChD;AAGA,QAAM,EAAE,2BAA2B,6BAA6B,IAC9D,MAAM,OAAO,gEAAgE;AAE/E,MAAI,SAAS,yBAAyB;AAEpC,UAAM,cAAsC,EAAE,SAAS,IAAI,SAAS,IAAI,SAAS,GAAG;AACpF,UAAM,WAAW,YAAY,MAAM,KAAK;AACxC,UAAM,aAAa,MAAM,cAAc,IAAI,aAAa;AAAA,MACtD,QAAQ;AAAA,QACN,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,aAAa,GAAG,IAAI;AAAA,QACpB,UAAU,GAAG,IAAI;AAAA,QACjB;AAAA,MACF;AAAA,IACF,CAAC;AACD,UAAM,qBAAqB,WAAW;AAEtC,UAAM,SAAS;AAAA,MACb,6BAA6B;AAAA,MAC7B;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,WAAO;AAAA,EAET,WAAW,SAAS,qBAAqB;AAEvC,UAAM,WAAW;AACjB,UAAM,gBAAwD,EAAE,CAAC,IAAI,GAAG,CAAC,EAAE;AAC3E,eAAW,CAAC,OAAO,KAAK,KAAK,OAAO,QAAQ,QAAQ,GAAG;AACrD,oBAAc,IAAI,EAAE,SAAS,KAAK,CAAC,IAAI;AAAA,IACzC;AACA,UAAM,SAAS;AAAA,MACb,6BAA6B;AAAA,MAC7B;AAAA,MACA;AAAA,IACF;AACA,WAAO;AAAA,EAET,WAAW,SAAS,qBAAqB;AAIvC,UAAM,cAAc;AACpB,UAAM,cAAsC,CAAC;AAC7C,eAAW,CAAC,OAAO,OAAO,KAAK,OAAO,QAAQ,WAAW,GAAG;AAC1D,kBAAY,KAAK,IAAI,OAAO,OAAO,OAAO,EAAE,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC;AAAA,IACvE;AACA,UAAM,SAAS;AAAA,MACb,6BAA6B;AAAA,MAC7B;AAAA,MACA;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,QAAM,IAAI,MAAM,6BAA6B,IAAI,EAAE;AACrD;AAGA,SAAS,mBACP,QACA,OACA,qBACA,kBACA,oBACA,eACA,UACQ;AACR,QAAM,EAAE,QAAQ,MAAM,IAAI;AAE1B,MAAI,OAAO,SAAS,OAAW,sBAAsB;AACrD,QAAM,IAAI,IAAI,KAAK,KAAK,MAAM,WAAW,mBAAmB;AAC5D,MAAI;AAEJ,MAAI,kBAAkB,cAAc;AAClC,UAAM,IAAI,QAAQ,KAAK,KAAK,oBAAoB,KAAK,KAAK,IAAI;AAC9D,UAAM,kBAAkB,IAAI;AAC5B,UAAM,aAAa,SAAS,OAAO,QAAQ;AAC3C,uBAAmB,OAAO;AAAA,EAC5B,OAAO;AACL,UAAM,IAAI,SAAS,KAAK,KAAK,oBAAoB,KAAK,KAAK,IAAI;AAC/D,UAAM,kBAAkB,IAAI;AAC5B,UAAM,aAAa,QAAQ,OAAO,SAAS;AAC3C,uBAAmB,OAAO;AAAA,EAC5B;AAEA,SAAO,MAAM,gBAAgB,IAAI,IAAI,KAAK,MAAM,gBAAgB;AAClE;AAGA,SAAS,cAAc,OAAe,UAAkF;AACtH,QAAM,CAAC,OAAO,MAAM,IAAI,MAAM,MAAM,GAAG;AACvC,QAAM,KAAK,SAAS,KAAK;AACzB,QAAM,WAAW,SAAS,SAAS,MAAM,IAAI;AAC7C,MAAI,MAAM,EAAE,EAAG,OAAM,IAAI,MAAM,0BAA0B,KAAK,wBAAwB;AACtF,SAAO,CAAC,GAAG,UAAU,EAAE,IAAI,SAAS,CAAC;AACvC;AAGA,eAAe,wBACb,OACA,QAC2B;AAC3B,QAAM,YAAY,MAAM;AACxB,QAAM,UAAU,MAAM;AACtB,MAAI,CAAC,UAAW,QAAO;AAEvB,QAAM,WAAW,UAAU;AAC3B,QAAM,SAAU,SAAS,UAAqB;AAC9C,QAAM,SAAU,MAAM,UAAqB;AAC3C,QAAM,QAAO,oBAAI,KAAK,GAAE,YAAY;AAEpC,MAAI;AACF,UAAM,gBAAgB,oBAAoB,WAAW,MAAM;AAC3D,UAAM,MAAM,MAAM,cAAc,IAAI,aAAa;AAAA,MAC/C,QAAQ;AAAA,QACN,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,aAAa,GAAG,IAAI;AAAA,QACpB,UAAU,GAAG,IAAI;AAAA,QACjB;AAAA,MACF;AAAA,IACF,CAAC;AACD,UAAM,OAAO,IAAI;AACjB,QAAI,MAAM,QAAQ,IAAI,KAAK,KAAK,SAAS,EAAG,QAAO;AACnD,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAYA,SAAS,cACP,MACA,SACA,OACyB;AACzB,QAAM,SAAS,WAAW;AAC1B,QAAM,UAAU,iBAAiB,MAAM;AACvC,QAAM,cAAsC;AAAA,IAC1C,SAAS;AAAA,IACT,UAAU;AAAA,EACZ;AAEA,MAAI,OAAO,WAAW,YAAY,IAAI,KAAK;AAG3C,MAAI,OAAO,aAAa;AACtB,UAAM,OAAO,MAAM,eAAe,MAAM;AACxC,WAAO,KAAK,IAAI,KAAK,MAAM,WAAW,KAAK,IAAI,GAAG,KAAK;AAAA,EACzD;AAEA,QAAM,UAAmC;AAAA,IACvC,SAAS;AAAA,IACT;AAAA,IACA,oBAAmB,oBAAI,KAAK,GAAE,YAAY;AAAA,IAC1C,iBAAiB,OAAO,eACpB,eACA,QAAQ,WAAW;AAAA,EACzB;AAEA,MAAI,OAAO,cAAc;AACvB,YAAQ,cAAc;AAAA,EACxB;AACA,SAAO;AACT;;;AM7xEA,SAASC,eAAc,KAAuD;AAC5E,MAAI,OAAO;AACX,SAAO,KAAK,OAAQ,QAAO,KAAK;AAChC,SAAO,KAAK,KAAK;AACnB;AAGA,SAAS,cAAc,KAAuB;AAC5C,MAAI,QAAQ,QAAQ,QAAQ,UAAa,OAAO,QAAQ,SAAU,QAAO;AACzE,MAAI,MAAM,QAAQ,GAAG,EAAG,QAAO,IAAI,IAAI,aAAa;AAEpD,QAAM,SAAS;AAGf,MAAI,MAAM,QAAQ,OAAO,IAAI,KAAK,OAAO,KAAK,SAAS,KAAK,OAAO,eAAe,QAAW;AAC3F,WAAO,EAAE,OAAO,cAAc,MAAM,OAAO,KAAK,QAAQ,YAAY,OAAO,WAAW;AAAA,EACxF;AAGA,QAAM,SAAkC,CAAC;AACzC,aAAW,CAAC,KAAK,GAAG,KAAK,OAAO,QAAQ,MAAM,GAAG;AAC/C,QAAI,OAAO,OAAO,QAAQ,YAAY,CAAC,MAAM,QAAQ,GAAG,GAAG;AACzD,YAAM,IAAI;AACV,UAAI,MAAM,QAAQ,EAAE,IAAI,KAAK,EAAE,KAAK,SAAS,KAAK,EAAE,eAAe,QAAW;AAC5E,eAAO,GAAG,IAAI,EAAE,OAAO,cAAc,MAAM,EAAE,KAAK,QAAQ,YAAY,EAAE,WAAW;AACnF;AAAA,MACF;AAAA,IACF;AACA,WAAO,GAAG,IAAI,cAAc,GAAG;AAAA,EACjC;AACA,SAAO;AACT;AAGA,IAAM,kBAA4C;AAAA,EAChD,UAAU,CAAC,UAAU;AAAA,EACrB,SAAS,CAAC,SAAS;AAAA,EACnB,WAAW,CAAC,iBAAiB;AAAA,EAC7B,WAAW,CAAC,mBAAmB,0BAA0B,0BAA0B,oBAAoB,UAAU;AAAA,EACjH,aAAa,CAAC,eAAe,+BAA+B,8BAA8B,oCAAoC,6BAA6B;AAAA,EAC3J,WAAW,CAAC,cAAc,YAAY,kBAAkB,oBAAoB,sBAAsB;AAAA,EAClG,QAAQ,CAAC,iBAAiB,gBAAgB;AAAA,EAC1C,UAAU,CAAC,YAAY,aAAa,oBAAoB,WAAW;AACrE;AAMA,IAAM,uBAA+C;AAAA,EACnD,WAAW;AAAA,EACX,cAAc;AAAA,EACd,WAAW;AAAA,EACX,iBAAiB;AAAA,EACjB,kBAAkB;AAAA,EAClB,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,sBAAsB;AAAA,EACtB,cAAc;AAChB;AAMA,IAAM,6BAAqD;AAAA,EACzD,sBAAsB;AAAA,EACtB,aAAa;AAAA,EACb,eAAe;AACjB;AAEA,SAAS,0BAA0B,SAAmB,SAAuB;AAC3E,QAAM,iBAAiB,QAAQ,OAAO,OAAK,KAAK,oBAAoB;AACpE,QAAM,iBAAiB,QAAQ,OAAO,OAAK,KAAK,0BAA0B;AAC1E,QAAM,gBAAgB,QAAQ,OAAO,OAAK,EAAE,KAAK,yBAAyB,EAAE,KAAK,2BAA2B;AAE5G,QAAM,QAAkB,CAAC;AACzB,QAAM,KAAK,YAAY,QAAQ,MAAM,iFAAiF;AAEtH,MAAI,eAAe,SAAS,GAAG;AAC7B,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,+EAA+E;AAC1F,eAAW,KAAK,eAAgB,OAAM,KAAK,SAAS,CAAC,EAAE;AACvD,UAAM,KAAK,qCAAqC,OAAO,2BAA2B,eAAe,KAAK,GAAG,CAAC,EAAE;AAC5G,UAAM,KAAK,2FAA2F;AAAA,EACxG;AAEA,MAAI,eAAe,SAAS,GAAG;AAC7B,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,gDAAgD;AAC3D,eAAW,KAAK,eAAgB,OAAM,KAAK,SAAS,CAAC,KAAK,2BAA2B,CAAC,CAAC,EAAE;AACzF,UAAM,KAAK,qCAAqC,OAAO,mDAAmD;AAAA,EAC5G;AAEA,MAAI,cAAc,SAAS,GAAG;AAC5B,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,sDAAsD;AACjE,eAAW,KAAK,cAAe,OAAM,KAAK,SAAS,CAAC,EAAE;AACtD,UAAM,KAAK,sDAAsD,OAAO,6BAA6B;AACrG,UAAM,KAAK,kEAAkE;AAAA,EAC/E;AAEA,UAAQ,OAAO,MAAM,MAAM,KAAK,IAAI,IAAI,IAAI;AAC9C;AAGA,IAAM,cAAc;AAAA,EAClB;AAAA,EAAO;AAAA,EAAM;AAAA,EAAQ;AAAA,EAAc;AAAA,EACnC;AAAA,EAAqB;AAAA,EACrB;AAAA,EAAmB;AAAA,EACnB;AAAA,EAA0B;AAAA,EAC1B;AAAA,EAAU;AAAA,EACV;AAAA,EAA6B;AAC/B;AAEA,SAAS,YAAY,OAAgC,QAA0C;AAC7F,MAAI,WAAW,MAAO,QAAO;AAE7B,QAAM,WAAW,SAAS,OAAO,MAAM,GAAG,EAAE,IAAI,OAAK,EAAE,KAAK,CAAC,IAAI,CAAC;AAClE,QAAM,gBAAgB,IAAI,IAAI,WAAW;AAEzC,aAAW,WAAW,UAAU;AAC9B,UAAM,SAAS,gBAAgB,OAAO;AACtC,QAAI,OAAQ,QAAO,QAAQ,OAAK,cAAc,IAAI,CAAC,CAAC;AAAA,EACtD;AAGA,MAAI,SAAS,WAAW,GAAG;AACzB,KAAC,6BAA6B,0BAA0B,YAAY,WAAW,EAAE,QAAQ,OAAK,cAAc,IAAI,CAAC,CAAC;AAAA,EACpH;AAEA,QAAM,SAAkC,CAAC;AACzC,aAAW,OAAO,eAAe;AAC/B,QAAI,OAAO,MAAO,QAAO,GAAG,IAAI,MAAM,GAAG;AAAA,EAC3C;AAEA,SAAO,cAAc,MAAM;AAC7B;AAEO,SAAS,wBAAwBC,UAAwB;AAC9D,QAAM,UAAUA,SAAQ,QAAQ,SAAS,EAAE;AAAA,IACzC;AAAA,EACF;AAGA,UACG,QAAQ,MAAM,EACd,YAAY,iIAAiI,EAC7I,OAAO,eAAe,eAAe,IAAI,EACzC,OAAO,gBAAgB,gBAAgB,GAAG,EAC1C,OAAO,mBAAmB,sBAAsB,EAChD,OAAO,wBAAwB,uBAAuB,EACtD,OAAO,iBAAiB,+BAA+B,EACvD,OAAO,eAAe,6BAA6B,EACnD,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASD,eAAc,OAAO;AACpC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,OAAgC;AAAA,QACpC,OAAO,SAAS,KAAK,KAAK;AAAA,QAC1B,QAAQ,SAAS,KAAK,MAAM;AAAA,MAC9B;AACA,UAAI,KAAK,MAAO,MAAK,QAAQ,KAAK;AAClC,UAAI,KAAK,WAAY,MAAK,aAAa,KAAK;AAC5C,UAAI,KAAK,KAAM,MAAK,WAAW,KAAK;AACpC,UAAI,KAAK,GAAI,MAAK,SAAS,KAAK;AAEhC,YAAM,MAAM,MAAM,OAAO,KAAK,6CAA6C,IAAI;AAE/E,UAAI;AACJ,UAAI;AACJ,UAAI,MAAM,QAAQ,IAAI,IAAI,KAAK,IAAI,KAAK,UAAU,KAAK,MAAM,QAAQ,IAAI,KAAK,CAAC,CAAC,KAAK,OAAO,IAAI,KAAK,CAAC,MAAM,UAAU;AACpH,eAAO,IAAI,KAAK,CAAC;AACjB,gBAAQ,IAAI,KAAK,CAAC;AAAA,MACpB,WAAW,MAAM,QAAQ,IAAI,IAAI,GAAG;AAClC,eAAO,IAAI;AACX,gBAAQ,IAAI,KAAK;AAAA,MACnB,OAAO;AACL,eAAO,IAAI,MAAM,QAAQ,IAAI,MAAM,wBAAwB,CAAC;AAC5D,gBAAQ,IAAI,MAAM,SAAS,IAAI,MAAM,UAAU,MAAM,QAAQ,IAAI,IAAI,KAAK,SAAS;AAAA,MACrF;AAEA,YAAM,UAAyB,EAAE,GAAG,OAAO;AAC3C,UAAI,CAAC,OAAO,QAAQ;AAClB,gBAAQ,SAAS;AAAA,MACnB;AACA,sBAAgB,MAAM,OAAO,SAAS,KAAK,KAAK,GAAG,SAAS,KAAK,MAAM,GAAG,OAAO;AAAA,IACnF,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAGH,UACG,QAAQ,eAAe,EACvB,YAAY,sGAAsG,EAClH,OAAO,iBAAiB,+DAA+D,EACvF,OAAO,OAAO,IAAI,SAAS;AAC1B,QAAI;AAGF,UAAI,KAAK,UAAW,qBAAoB,EAAE;AAC1C,YAAM,SAASA,eAAc,OAAO;AACpC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,OAAO,KAAK,YACd,wCAAwC,EAAE,KAC1C,2CAA2C,EAAE;AACjD,YAAM,MAAM,MAAM,OAAO,IAAI,IAAI;AACjC,aAAO,IAAI,MAAM,MAAM;AAAA,IACzB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAGH,UACG,QAAQ,eAAe,EACvB;AAAA,IACC;AAAA,EAOF,EACC,OAAO,uBAAuB,+CAA+C,EAC7E,OAAO,OAAO,SAAS,SAAS;AAC/B,QAAI;AACF,0BAAoB,OAAO;AAC3B,YAAM,SAASA,eAAc,OAAO;AACpC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,MAAM,MAAM,OAAO,IAAI,yBAAyB,OAAO,EAAE;AAC/D,YAAM,QAAQ,YAAY,IAAI,MAAM,eAAe,OAAO;AAI1D,YAAM,WAAW,OAAO,SAAS,QAAQ,YAAY,OAAO,KAAK,MAAM;AAEvE,UAAI,OAAO,QAAQ;AACjB,cAAM,YAAY,OAAO,OAAO,MAAM,GAAG,EAAE,IAAI,OAAK,EAAE,KAAK,CAAC;AAC5D,cAAM,WAAW,UAAU,IAAI,OAAK,EAAE,MAAM,GAAG,EAAE,CAAC,CAAC;AACnD,cAAM,UAAU,SAAS,OAAO,OAAK,EAAE,KAAK,MAAM;AAClD,YAAI,QAAQ,SAAS,GAAG;AACtB,oCAA0B,SAAS,OAAO;AAAA,QAC5C;AAAA,MACF;AAEA,aAAO,UAAU,MAAM;AAAA,IACzB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAGH,UACG,QAAQ,8BAA8B,EACtC;AAAA,IACC;AAAA,EAIF,EACC,OAAO,WAAW,4CAA4C,EAC9D,OAAO,aAAa,4BAA4B,EAChD,OAAO,WAAW,0BAA0B,EAC5C,OAAO,SAAS,6BAA6B,EAC7C,OAAO,WAAW,kCAAkC,EACpD,OAAO,uBAAuB,sCAAsC,GAAG,EACvE,OAAO,iBAAiB,yBAAyB,EACjD,OAAO,OAAO,SAAS,WAAW,SAAS;AAC1C,QAAI;AACF,0BAAoB,OAAO;AAC3B,YAAM,SAASA,eAAc,OAAO;AACpC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,MAAM,MAAM,OAAO,IAAI,yBAAyB,OAAO,EAAE;AAC/D,YAAM,QAAQ,YAAY,IAAI,MAAM,eAAe,OAAO;AAG1D,UAAI;AACJ,cAAQ,WAAW;AAAA,QACjB,KAAK;AACH,sBAAY,MAAM;AAClB;AAAA,QACF,KAAK,cAAc;AACjB,gBAAM,WAAW,MAAM;AACvB,gBAAM,MAAM,SAAS,KAAK,YAAY;AACtC,cAAI,YAAY,SAAS,GAAG,GAAG,YAAY;AACzC,wBAAY,SAAS,GAAG,EAAE;AAAA,UAC5B,OAAO;AACL,wBAAY,IAAI,MAAM,wCAAwC,GAAG,eAAe,UAAU,UAAU,CAAC,YAAY,CAAC;AAClH;AAAA,UACF;AACA;AAAA,QACF;AAAA,QACA,KAAK;AACH,sBAAa,MAAM,SAAiB;AACpC;AAAA,QACF,KAAK;AACH,sBAAa,MAAM,SAAiB;AACpC;AAAA,QACF;AACE,sBAAY,IAAI,MAAM,kBAAkB,SAAS,iEAAiE,CAAC;AACnH;AAAA,MACJ;AAEA,UAAI,CAAC,WAAW;AACd,oBAAY,IAAI,MAAM,UAAU,SAAS,qCAAqC,CAAC;AAC/E;AAAA,MACF;AAGA,YAAM,EAAE,WAAW,IAAI,MAAM,OAAO,qDAAqD;AACzF,YAAM,KAAK;AACX,YAAM,KAAK,IAAI,WAAW,GAAG,QAAQ,IAAI,GAAG,WAAW,OAAO,GAAG,cAAc,WAAW,GAAG,aAAa,KAAK;AAG/G,YAAM,UAAU,KAAK;AACrB,YAAM,cAAc,KAAK;AACzB,YAAM,YAAY,KAAK;AACvB,YAAM,YAAY,KAAK;AACvB,YAAM,YAAY,KAAK,SAAU,CAAC,WAAW,CAAC,eAAe,CAAC,aAAa,CAAC;AAE5E,UAAI;AAEJ,UAAI,SAAS;AACX,iBAAS,GAAG;AAAA,MACd,WAAW,WAAW;AACpB,iBAAS,EAAE,OAAO,GAAG,kBAAkB,GAAG,YAAY,WAAW,MAAM,GAAG,KAAK,OAAO;AAAA,MACxF,WAAW,WAAW;AACpB,cAAM,MAAM,GAAG,oBAAoB;AACnC,iBAAS,IAAI,cAAc;AAAA,MAC7B,WAAW,aAAa;AACtB,cAAM,MAAM,GAAG,oBAAoB;AACnC,cAAM,IAAI,IAAI,cAAc;AAC5B,iBAAS,EAAE,sBAAsB,EAAE,sBAAsB,iBAAiB,EAAE,iBAAiB,qBAAqB,EAAE,oBAAoB;AAAA,MAC1I,WAAW,WAAW;AACpB,cAAM,MAAM,GAAG,oBAAoB;AACnC,cAAM,IAAI,IAAI,cAAc;AAC5B,iBAAS,EAAE,iBAAiB,EAAE,gBAAgB;AAAA,MAChD;AAEA,YAAM,UAAU,EAAE,GAAG,QAAQ,MAAM,KAAK,QAAQ,OAAO,KAAK;AAC5D,aAAO,QAAQ,OAAO;AAAA,IACxB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAGH,UACG,QAAQ,sBAAsB,EAC9B,YAAY,0EAA0E,EACtF,eAAe,aAAa,UAAU,EACtC,eAAe,aAAa,WAAW,EACvC,eAAe,eAAe,0BAA0B,EACxD,OAAO,eAAe,6BAA6B,IAAI,EACvD,OAAO,iBAAiB,kDAAkD,KAAK,EAC/E,OAAO,gBAAgB,qBAAqB,IAAI,EAChD,OAAO,cAAc,wBAAwB,QAAO,oBAAI,KAAK,GAAE,YAAY,CAAC,CAAC,EAC7E,OAAO,iBAAiB,qBAAqB,EAC7C,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASA,eAAc,OAAO;AACpC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,OAAO;AAAA,QACX,KAAK,WAAW,KAAK,GAAG;AAAA,QACxB,MAAM,WAAW,KAAK,GAAG;AAAA,QACzB,eAAe,WAAW,KAAK,KAAK;AAAA,QACpC,OAAO,WAAW,KAAK,KAAK;AAAA,QAC5B,SAAS,WAAW,KAAK,OAAO;AAAA,QAChC,kBAAkB,WAAW,KAAK,MAAM;AAAA,QACxC,MAAM,SAAS,KAAK,IAAI;AAAA,QACxB,aAAa;AAAA,MACf;AACA,YAAM,MAAM,MAAM,OAAO,KAAK,oCAAoC,IAAI;AACtE,aAAO,IAAI,MAAM,EAAE,GAAG,QAAQ,MAAM,KAAK,QAAQ,OAAO,KAAK,CAAC;AAAA,IAChE,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAGH,UACG,QAAQ,mBAAmB,EAC3B,YAAY,2DAA2D,EACvE,eAAe,aAAa,UAAU,EACtC,eAAe,aAAa,WAAW,EACvC,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASA,eAAc,OAAO;AACpC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,MAAM,MAAM,OAAO,IAAI,iCAAiC;AAAA,QAC5D,QAAQ,EAAE,KAAK,WAAW,KAAK,GAAG,GAAG,KAAK,WAAW,KAAK,GAAG,EAAE;AAAA,MACjE,CAAC;AACD,aAAO,IAAI,MAAM,MAAM;AAAA,IACzB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAGH,+BAA6B,OAAO;AACtC;;;ACvZA,SAAS,gBAAAE,qBAAoB;AAG7B,SAASC,eAAc,KAAuD;AAC5E,MAAI,OAAO;AACX,SAAO,KAAK,OAAQ,QAAO,KAAK;AAChC,SAAO,KAAK,KAAK;AACnB;AAGA,SAAS,YAA6B;AACpC,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,QAAI,OAAO;AACX,YAAQ,MAAM,YAAY,OAAO;AACjC,YAAQ,MAAM,GAAG,QAAQ,CAAC,UAAU;AAAE,cAAQ;AAAA,IAAO,CAAC;AACtD,YAAQ,MAAM,GAAG,OAAO,MAAM,QAAQ,IAAI,CAAC;AAC3C,YAAQ,MAAM,GAAG,SAAS,MAAM;AAAA,EAClC,CAAC;AACH;AAGA,eAAe,eAAe,WAAkC;AAC9D,MAAI;AACJ,MAAI,aAAa,cAAc,KAAK;AAClC,UAAMC,cAAa,WAAW,OAAO;AAAA,EACvC,OAAO;AACL,UAAM,MAAM,UAAU;AAAA,EACxB;AACA,SAAO,KAAK,MAAM,GAAG;AACvB;AAGA,eAAe,WAAW,MAAW,aAAa,SAAS;AACzD,QAAM,EAAE,WAAW,IAAI,MAAM,OAAO,qDAAqD;AAEzF,MAAI,MAAM,QAAQ,IAAI,GAAG;AACvB,WAAO,IAAI,WAAW,MAAM,OAAO,YAAY,KAAK;AAAA,EACtD;AACA,SAAO,IAAI,WAAW,KAAK,QAAQ,MAAM,KAAK,WAAW,OAAO,KAAK,cAAc,YAAY,KAAK,aAAa,KAAK;AACxH;AAGA,SAAS,eAAe,IAAc;AACpC,SAAO,EAAE,MAAM,GAAG,MAAM,YAAY,GAAG,YAAY,SAAS,GAAG,QAAQ;AACzE;AAEO,SAAS,uBAAuBC,UAAwB;AAC7D,QAAM,SAASA,SAAQ,QAAQ,QAAQ,EAAE;AAAA,IACvC;AAAA,EAGF;AAGA,SACG,QAAQ,OAAO,EACf,YAAY,iGAAiG,EAC7G,OAAO,kBAAkB,6BAA6B,EACtD,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,OAAO,MAAM,eAAe,KAAK,KAAK;AAC5C,YAAM,KAAK,MAAM,WAAW,MAAM,OAAO;AACzC,YAAM,MAAM,GAAG,oBAAoB;AACnC,aAAO,IAAI,cAAc,KAAKF,eAAc,MAAM,CAAC;AAAA,IACrD,SAAS,KAAK;AACZ,kBAAY,GAAG;AAAA,IACjB;AAAA,EACF,CAAC;AAGH,SACG,QAAQ,OAAO,EACf,YAAY,oDAAoD,EAChE,OAAO,kBAAkB,6BAA6B,EACtD,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,OAAO,MAAM,eAAe,KAAK,KAAK;AAC5C,YAAM,KAAK,MAAM,WAAW,MAAM,OAAO;AACzC,aAAO,EAAE,OAAO,GAAG,kBAAkB,GAAG,MAAM,GAAG,KAAK,OAAO,GAAGA,eAAc,MAAM,CAAC;AAAA,IACvF,SAAS,KAAK;AACZ,kBAAY,GAAG;AAAA,IACjB;AAAA,EACF,CAAC;AAGH,SACG,QAAQ,mBAAmB,EAC3B,YAAY,mEAAmE,EAC/E,OAAO,kBAAkB,6BAA6B,EACtD,OAAO,OAAO,QAAQ,SAAS;AAC9B,QAAI;AACF,YAAM,OAAO,MAAM,eAAe,KAAK,KAAK;AAC5C,YAAM,KAAK,MAAM,WAAW,MAAM,YAAY;AAC9C,YAAM,SAAS,GAAG,gBAAgB,WAAW,MAAM,CAAC;AACpD,aAAO,eAAe,MAAM,GAAGA,eAAc,MAAM,CAAC;AAAA,IACtD,SAAS,KAAK;AACZ,kBAAY,GAAG;AAAA,IACjB;AAAA,EACF,CAAC;AAGH,SACG,QAAQ,WAAW,EACnB,YAAY,wDAAwD,EACpE,eAAe,cAAc,kBAAkB,EAC/C,eAAe,cAAc,mBAAmB,EAChD,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,QAAQ,KAAK,MAAMC,cAAa,KAAK,GAAG,OAAO,CAAC;AACtD,YAAM,QAAQ,KAAK,MAAMA,cAAa,KAAK,GAAG,OAAO,CAAC;AACtD,YAAM,MAAM,MAAM,WAAW,OAAO,GAAG;AACvC,YAAM,MAAM,MAAM,WAAW,OAAO,GAAG;AACvC,YAAM,SAAS,IAAI,oBAAoB,GAAG;AAC1C,aAAO,eAAe,MAAM,GAAGD,eAAc,MAAM,CAAC;AAAA,IACtD,SAAS,KAAK;AACZ,kBAAY,GAAG;AAAA,IACjB;AAAA,EACF,CAAC;AAGH,SACG,QAAQ,UAAU,EAClB,YAAY,6DAA6D,EACzE,eAAe,cAAc,4BAA4B,EACzD,eAAe,cAAc,gCAAgC,EAC7D,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,QAAQ,KAAK,MAAMC,cAAa,KAAK,GAAG,OAAO,CAAC;AACtD,YAAM,QAAQ,KAAK,MAAMA,cAAa,KAAK,GAAG,OAAO,CAAC;AACtD,YAAM,MAAM,MAAM,WAAW,OAAO,GAAG;AACvC,YAAM,MAAM,MAAM,WAAW,OAAO,GAAG;AACvC,YAAM,OAAO,IAAI,gBAAgB,EAAE;AACnC,YAAM,SAAS,IAAI,oBAAoB,IAAI;AAC3C,aAAO,eAAe,MAAM,GAAGD,eAAc,MAAM,CAAC;AAAA,IACtD,SAAS,KAAK;AACZ,kBAAY,GAAG;AAAA,IACjB;AAAA,EACF,CAAC;AAGH,SACG,QAAQ,iBAAiB,EACzB,YAAY,sFAAsF,EAClG,OAAO,kBAAkB,6BAA6B,EACtD,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,OAAO,MAAM,eAAe,KAAK,KAAK;AAC5C,YAAM,KAAK,MAAM,WAAW,MAAM,UAAU;AAC5C,YAAM,SAAS,GAAG,qBAAqB;AACvC,aAAO,eAAe,MAAM,GAAGA,eAAc,MAAM,CAAC;AAAA,IACtD,SAAS,KAAK;AACZ,kBAAY,GAAG;AAAA,IACjB;AAAA,EACF,CAAC;AAGH,SACG,QAAQ,iBAAiB,EACzB,YAAY,sFAAsF,EAClG,OAAO,kBAAkB,6BAA6B,EACtD,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,OAAO,MAAM,eAAe,KAAK,KAAK;AAC5C,YAAM,KAAK,MAAM,WAAW,MAAM,UAAU;AAC5C,YAAM,SAAS,GAAG,qBAAqB;AACvC,aAAO,eAAe,MAAM,GAAGA,eAAc,MAAM,CAAC;AAAA,IACtD,SAAS,KAAK;AACZ,kBAAY,GAAG;AAAA,IACjB;AAAA,EACF,CAAC;AAGH,SACG,QAAQ,MAAM,EACd,YAAY,8DAA8D,EAC1E,OAAO,kBAAkB,6BAA6B,EACtD,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,OAAO,MAAM,eAAe,KAAK,KAAK;AAC5C,YAAM,KAAK,MAAM,WAAW,MAAM,QAAQ;AAC1C,YAAM,aAAa,GAAG,WAAW;AACjC,aAAO,EAAE,MAAM,YAAY,YAAY,GAAG,YAAY,SAAS,GAAG,QAAQ,GAAGA,eAAc,MAAM,CAAC;AAAA,IACpG,SAAS,KAAK;AACZ,kBAAY,GAAG;AAAA,IACjB;AAAA,EACF,CAAC;AAGH,SACG,QAAQ,cAAc,EACtB,YAAY,yDAAyD,EACrE,OAAO,kBAAkB,6BAA6B,EACtD,OAAO,kBAAkB,yBAAyB,EAClD,OAAO,gBAAgB,uBAAuB,EAC9C,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,OAAO,MAAM,eAAe,KAAK,KAAK;AAC5C,YAAM,KAAK,MAAM,WAAW,MAAM,UAAU;AAC5C,YAAM,QAAQ,KAAK,QAAQ,IAAI,KAAK,KAAK,KAAK,IAAI;AAClD,YAAM,MAAM,KAAK,MAAM,IAAI,KAAK,KAAK,GAAG,IAAI;AAC5C,YAAM,eAAe,GAAG,cAAc,OAAO,GAAG;AAChD,aAAO,EAAE,MAAM,cAAc,YAAY,GAAG,YAAY,SAAS,GAAG,QAAQ,GAAGA,eAAc,MAAM,CAAC;AAAA,IACtG,SAAS,KAAK;AACZ,kBAAY,GAAG;AAAA,IACjB;AAAA,EACF,CAAC;AAGH,SACG,QAAQ,UAAU,EAClB,YAAY,yDAAyD,EACrE,OAAO,kBAAkB,6BAA6B,EACtD,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,OAAO,MAAM,eAAe,KAAK,KAAK;AAC5C,YAAM,KAAK,MAAM,WAAW,MAAM,OAAO;AACzC,YAAM,QAAQ,GAAG,gBAAgB;AACjC,aAAO,OAAOA,eAAc,MAAM,CAAC;AAAA,IACrC,SAAS,KAAK;AACZ,kBAAY,GAAG;AAAA,IACjB;AAAA,EACF,CAAC;AAGH,SACG,QAAQ,WAAW,EACnB;AAAA,IACC;AAAA,EAOF,EACC,eAAe,oBAAoB,gEAAgE,EACnG,OAAO,kBAAkB,kCAAkC,EAC3D,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,OAAO,MAAM,eAAe,KAAK,KAAK;AAC5C,YAAM,KAAK,MAAM,WAAW,MAAM,WAAW;AAC7C,YAAM,cAAc,KAAK,MAAMC,cAAa,KAAK,SAAS,OAAO,CAAC;AAClE,YAAM,SAAS,GAAG,kBAAkB,WAAW;AAC/C,aAAO,QAAQD,eAAc,MAAM,CAAC;AAAA,IACtC,SAAS,KAAK;AACZ,kBAAY,GAAG;AAAA,IACjB;AAAA,EACF,CAAC;AACL;;;ACxPA,SAAS,gBAAAG,qBAAoB;AAI7B,SAASC,gBAAc,KAAuD;AAC5E,MAAI,OAAO;AACX,SAAO,KAAK,OAAQ,QAAO,KAAK;AAChC,SAAO,KAAK,KAAK;AACnB;AAEO,SAAS,4BAA4BC,UAAwB;AAClE,QAAM,cAAcA,SAAQ,QAAQ,aAAa,EAAE;AAAA,IACjD;AAAA,EAGF;AAGA,cACG,QAAQ,UAAU,EAClB;AAAA,IACC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOF,EACC,eAAe,kBAAkB,2BAA2B,EAC5D,OAAO,oBAAoB,iFAAiF,EAC5G,OAAO,6BAA6B,0CAA0C,EAC9E,OAAO,2BAA2B,yCAAyC,EAC3E,OAAO,mBAAmB,wCAAwC,OAAO,EACzE,OAAO,iBAAiB,kCAAkC,OAAO,EACjE,OAAO,mBAAmB,sBAAsB,IAAI,EACpD,OAAO,4BAA4B,wCAAwC,EAC3E,OAAO,yBAAyB,0DAA0D,EAC1F,OAAO,wBAAwB,2CAA2C,EAC1E,OAAO,iBAAiB,qBAAqB,EAC7C,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASD,gBAAc,WAAW;AACxC,YAAM,SAAS,oBAAoB,YAAY,MAAM;AAErD,YAAM,QAAO,oBAAI,KAAK,GAAE,YAAY;AACpC,YAAM,YAAY,KAAK,aAAa,GAAG,IAAI;AAC3C,YAAM,UAAU,KAAK,WAAW,GAAG,IAAI;AAGvC,YAAM,SAAiC;AAAA,QACrC;AAAA,QACA;AAAA,QACA,QAAQ,KAAK;AAAA,QACb,MAAM,KAAK;AAAA,QACX,kBAAkB,KAAK;AAAA,QACvB,QAAQ,KAAK;AAAA,MACf;AAEA,UAAI,KAAK,QAAS,QAAO,kBAAkB,KAAK;AAChD,UAAI,KAAK,gBAAiB,QAAO,kBAAkB,KAAK;AAGxD,UAAI;AACJ,UAAI,KAAK,eAAe,KAAK,YAAY;AACvC,eAAO,CAAC;AACR,YAAI,KAAK,YAAa,MAAK,qBAAqB,KAAK,MAAM,KAAK,WAAW;AAC3E,YAAI,KAAK,WAAY,MAAK,aAAa,KAAK,MAAM,KAAK,UAAU;AAAA,MACnE;AAEA,YAAM,cAAc,OAAO,QAAQ,MAAM,EACtC,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,mBAAmB,CAAC,CAAC,EAAE,EAC/C,KAAK,GAAG;AAEX,YAAM,MAAM,MAAM,OAAO,KAAK,2BAA2B,WAAW,IAAI,QAAQ,CAAC,CAAC;AAClF,aAAO,IAAI,MAAM,EAAE,GAAG,QAAQ,MAAM,KAAK,QAAQ,OAAO,KAAK,CAAC;AAAA,IAChE,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAGH,cACG,QAAQ,cAAc,EACtB;AAAA,IACC;AAAA,EAGF,EACC,eAAe,wBAAwB,YAAY,EACnD,eAAe,sBAAsB,UAAU,EAC/C,OAAO,mBAAmB,eAAe,OAAO,EAChD,OAAO,iBAAiB,kCAAkC,OAAO,EACjE,OAAO,mBAAmB,2BAA2B,IAAI,EACzD,OAAO,iBAAiB,qBAAqB,EAC7C,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASA,gBAAc,WAAW;AACxC,YAAM,SAAS,oBAAoB,YAAY,MAAM;AACrD,YAAM,MAAM,MAAM,OAAO,IAAI,iBAAiB;AAAA,QAC5C,QAAQ;AAAA,UACN,WAAW,KAAK;AAAA,UAChB,SAAS,KAAK;AAAA,UACd,QAAQ,KAAK;AAAA,UACb,MAAM,KAAK;AAAA,UACX,QAAQ,KAAK;AAAA,QACf;AAAA,MACF,CAAC;AACD,aAAO,IAAI,MAAM,EAAE,GAAG,QAAQ,MAAM,KAAK,QAAQ,OAAO,KAAK,CAAC;AAAA,IAChE,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAGH,cACG,QAAQ,aAAa,EACrB,YAAY,6EAA6E,EACzF,OAAO,YAAY;AAClB,QAAI;AACF,YAAM,SAASA,gBAAc,WAAW;AACxC,YAAM,SAAS,oBAAoB,YAAY,MAAM;AACrD,YAAM,MAAM,MAAM,OAAO,IAAI,0BAA0B;AACvD,aAAO,IAAI,MAAM,MAAM;AAAA,IACzB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAGH,cACG,QAAQ,qBAAqB,EAC7B,YAAY,mDAAmD,EAC/D,eAAe,oBAAoB,mBAAmB,EACtD,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASA,gBAAc,WAAW;AACxC,YAAM,SAAS,oBAAoB,YAAY,MAAM;AACrD,YAAM,MAAM,MAAM,OAAO,IAAI,4BAA4B;AAAA,QACvD,QAAQ,EAAE,IAAI,KAAK,GAAG;AAAA,MACxB,CAAC;AACD,aAAO,IAAI,MAAM,MAAM;AAAA,IACzB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAGH,cACG,QAAQ,SAAS,EACjB;AAAA,IACC;AAAA,EAQF,EACC,OAAO,mBAAmB,sCAAsC,IAAI,EACpE,OAAO,iBAAiB,sCAAsC,GAAG,EACjE,OAAO,wBAAwB,0CAA0C,EACzE,OAAO,sBAAsB,yCAAyC,EACtE,OAAO,mBAAmB,0BAA0B,IAAI,EACxD,OAAO,iBAAiB,qBAAqB,EAC7C,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASA,gBAAc,WAAW;AACxC,YAAM,SAAS,oBAAoB,WAAW,MAAM;AACpD,YAAM,QAAO,oBAAI,KAAK,GAAE,YAAY;AACpC,YAAM,MAAM,MAAM,OAAO,IAAI,aAAa;AAAA,QACxC,QAAQ;AAAA,UACN,UAAU,SAAS,KAAK,QAAQ;AAAA,UAChC,QAAQ,SAAS,KAAK,MAAM;AAAA,UAC5B,aAAa,KAAK,SAAS,GAAG,IAAI;AAAA,UAClC,UAAU,KAAK,OAAO,GAAG,IAAI;AAAA,UAC7B,QAAQ,KAAK;AAAA,QACf;AAAA,MACF,CAAC;AACD,aAAO,IAAI,MAAM,EAAE,GAAG,QAAQ,MAAM,KAAK,QAAQ,OAAO,KAAK,CAAC;AAAA,IAChE,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAGH,cACG,QAAQ,WAAW,EACnB;AAAA,IACC;AAAA,EAGF,EACC,OAAO,uBAAuB,oCAAoC,EAClE,OAAO,iBAAiB,qBAAqB,EAC7C,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASA,gBAAc,WAAW;AACxC,YAAM,SAAS,oBAAoB,YAAY,MAAM;AAErD,UAAI,KAAK,WAAW;AAClB,cAAM,YAAY,MAAM,OAAO,WAAW,GAAG;AAC7C,cAAM,OAAO,IAAI,SAAS;AAC1B,aAAK,OAAO,QAAQE,cAAa,KAAK,SAAS,GAAG;AAAA,UAChD,UAAU,KAAK,UAAU,MAAM,GAAG,EAAE,IAAI;AAAA,UACxC,aAAa;AAAA,QACf,CAAC;AACD,cAAM,MAAM,MAAM,OAAO,KAAK,oDAAoD,MAAM;AAAA,UACtF,SAAS,KAAK,WAAW;AAAA,QAC3B,CAAC;AACD,eAAO,IAAI,MAAM,EAAE,GAAG,QAAQ,MAAM,KAAK,QAAQ,OAAO,KAAK,CAAC;AAAA,MAChE,OAAO;AACL,oBAAY,IAAI,MAAM,4CAA4C,CAAC;AAAA,MACrE;AAAA,IACF,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AACL;;;ACvNA,SAASC,gBAAc,KAAuD;AAC5E,MAAI,OAAO;AACX,SAAO,KAAK,OAAQ,QAAO,KAAK;AAChC,SAAO,KAAK,KAAK;AACnB;AAGA,SAASC,aAA6B;AACpC,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,QAAI,OAAO;AACX,YAAQ,MAAM,YAAY,OAAO;AACjC,YAAQ,MAAM,GAAG,QAAQ,CAAC,UAAU;AAAE,cAAQ;AAAA,IAAO,CAAC;AACtD,YAAQ,MAAM,GAAG,OAAO,MAAM,QAAQ,IAAI,CAAC;AAC3C,YAAQ,MAAM,GAAG,SAAS,MAAM;AAAA,EAClC,CAAC;AACH;AAGA,eAAeC,WAAU,MAAwE;AAC/F,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI,SAAS,KAAK;AAChB,UAAM,QAAQ,MAAMD,WAAU;AAC9B,WAAO,KAAK,MAAM,KAAK;AAAA,EACzB;AACA,SAAO,KAAK,MAAM,IAAI;AACxB;AAGA,SAAS,wBAAwB,SAA2B;AAC1D,MAAI,WAAW,OAAO,YAAY,YAAY,CAAC,MAAM,QAAQ,OAAO,GAAG;AACrE,UAAM,IAAI;AAEV,QAAI,UAAU,KAAK,OAAO,EAAE,SAAS,UAAU;AAE7C,UAAI,EAAE,SAAS,OAAW,QAAO,EAAE;AAEnC,UAAI,EAAE,OAAO;AACX,cAAM,MAAM,EAAE;AACd,cAAM,IAAI,MAAM,cAAc,IAAI,QAAQ,EAAE,IAAI,MAAM,IAAI,WAAW,KAAK,UAAU,GAAG,CAAC,EAAE;AAAA,MAC5F;AAEA,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAGA,SAAS,mBAAmB,OAAyB;AACnD,MAAI,UAAU,QAAQ,UAAU,UAAa,OAAO,UAAU,SAAU,QAAO;AAC/E,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,MAAM,IAAI,kBAAkB;AAE7D,QAAM,SAAS;AAGf,MAAI,MAAM,QAAQ,OAAO,IAAI,KAAK,OAAO,KAAK,SAAS,KAAK,OAAO,eAAe,QAAW;AAC3F,WAAO,EAAE,OAAO,cAAc,MAAM,OAAO,KAAK,QAAQ,YAAY,OAAO,WAAW;AAAA,EACxF;AAEA,QAAM,SAAkC,CAAC;AACzC,aAAW,CAAC,KAAK,GAAG,KAAK,OAAO,QAAQ,MAAM,GAAG;AAC/C,QAAI,OAAO,OAAO,QAAQ,YAAY,CAAC,MAAM,QAAQ,GAAG,GAAG;AACzD,YAAM,IAAI;AACV,UAAI,MAAM,QAAQ,EAAE,IAAI,KAAK,EAAE,KAAK,SAAS,KAAK,EAAE,eAAe,QAAW;AAC5E,eAAO,GAAG,IAAI,EAAE,OAAO,cAAc,MAAM,EAAE,KAAK,QAAQ,YAAY,EAAE,WAAW;AACnF;AAAA,MACF;AAAA,IACF;AACA,WAAO,GAAG,IAAI,mBAAmB,GAAG;AAAA,EACtC;AACA,SAAO;AACT;AAEO,SAAS,0BAA0BE,UAAwB;AAChE,QAAM,YAAYA,SAAQ,QAAQ,WAAW,EAAE;AAAA,IAC7C;AAAA,EAGF;AAGA,YACG,QAAQ,QAAQ,EAChB;AAAA,IACC;AAAA,EAUF,EACC,eAAe,mBAAmB,sCAAsC,EACxE,eAAe,uBAAuB,iBAAiB,EACvD,eAAe,yBAAyB,gEAAgE,EACxG,OAAO,oBAAoB,mFAAmF,SAAS,EACvH,OAAO,6BAA6B,qDAAqD,oBAAoB,EAC7G,OAAO,iBAAiB,uDAAuD,EAC/E,OAAO,0BAA0B,sEAAsE,EACvG,OAAO,yBAAyB,4BAA4B,EAC5D,OAAO,mBAAmB,4BAA4B,EACtD,OAAO,UAAU,wBAAwB,EACzC,OAAO,SAAS,wDAAwD,EACxE,OAAO,sBAAsB,2BAA2B,EACxD,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASH,gBAAc,SAAS;AACtC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAElD,YAAM,OAAgC;AAAA,QACpC,QAAQ,KAAK;AAAA,QACb,WAAW,KAAK;AAAA,QAChB,4BAA4B,KAAK;AAAA,QACjC,qBAAqB,WAAW,KAAK,WAAW;AAAA,QAChD,qCAAqC,KAAK;AAAA,MAC5C;AAEA,UAAI,KAAK,aAAc,MAAK,kBAAkB,KAAK;AAGnD,YAAM,SAAiC,CAAC;AACxC,UAAI,KAAK,KAAM,QAAO,OAAO;AAC7B,UAAI,KAAK,MAAO,QAAO,QAAQ,KAAK;AACpC,UAAI,KAAK,MAAO,QAAO,aAAa,KAAK;AACzC,UAAI,KAAK,aAAc,QAAO,2BAA2B,KAAK;AAE9D,YAAM,cAAc,OAAO,QAAQ,MAAM,EACtC,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,mBAAmB,CAAC,CAAC,EAAE,EAC/C,KAAK,GAAG;AAEX,YAAM,MAAM,yBAAyB,cAAc,MAAM,cAAc,EAAE;AACzE,YAAM,MAAM,MAAM,OAAO,KAAK,KAAK,IAAI;AAEvC,YAAM,QAAQ,wBAAwB,IAAI,IAAI;AAC9C,YAAM,SAAS,KAAK,MAAM,QAAQ,mBAAmB,KAAK;AAC1D,aAAO,QAAQ,EAAE,GAAG,QAAQ,MAAM,KAAK,YAAY,OAAO,KAAK,CAAC;AAAA,IAClE,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAGH,YACG,QAAQ,WAAW,EACnB;AAAA,IACC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaF,EACC,eAAe,iBAAiB,sDAAsD,EACtF,OAAO,UAAU,wBAAwB,EACzC,OAAO,mBAAmB,4BAA4B,EACtD,OAAO,SAAS,wDAAwD,EACxE,OAAO,sBAAsB,2BAA2B,EACxD,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASA,gBAAc,SAAS;AACtC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAElD,YAAM,OAAO,MAAME,WAAU,KAAK,IAAI;AACtC,UAAI,CAAC,MAAM;AACT,oBAAY,IAAI,MAAM,+CAA+C,CAAC;AACtE;AAAA,MACF;AAEA,YAAM,SAAiC,CAAC;AACxC,UAAI,KAAK,KAAM,QAAO,OAAO;AAC7B,UAAI,KAAK,MAAO,QAAO,QAAQ,KAAK;AAEpC,YAAM,cAAc,OAAO,QAAQ,MAAM,EACtC,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,mBAAmB,CAAC,CAAC,EAAE,EAC/C,KAAK,GAAG;AAEX,YAAM,MAAM,kBAAkB,cAAc,MAAM,cAAc,EAAE;AAClE,YAAM,MAAM,MAAM,OAAO,KAAK,KAAK,IAAI;AAEvC,YAAM,QAAQ,wBAAwB,IAAI,IAAI;AAC9C,UAAI,CAAC,SAAU,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,KAAK,EAAE,4BAA6B,QAAqC;AACvI,oBAAY,IAAI,MAAM,qNAAqN,CAAC;AAC5O;AAAA,MACF;AACA,YAAM,SAAS,KAAK,MAAM,QAAQ,mBAAmB,KAAK;AAC1D,aAAO,QAAQ,EAAE,GAAG,QAAQ,MAAM,KAAK,YAAY,OAAO,KAAK,CAAC;AAAA,IAClE,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAGH,YACG,QAAQ,QAAQ,EAChB;AAAA,IACC;AAAA,EAEF,EACC,OAAO,YAAY;AAClB,QAAI;AACF,YAAM,SAASF,gBAAc,SAAS;AACtC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,MAAM,MAAM,OAAO,IAAI,+BAA+B;AAC5D,aAAO,IAAI,MAAM,MAAM;AAAA,IACzB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAGH,YACG,QAAQ,YAAY,EACpB;AAAA,IACC;AAAA,EAEF,EACC,OAAO,YAAY,+BAA+B,EAClD,OAAO,YAAY,qCAAqC,EACxD,OAAO,iBAAiB,yBAAyB,EACjD,OAAO,mBAAmB,uCAAuC,EACjE,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASA,gBAAc,SAAS;AACtC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAElD,UAAI,KAAK,QAAQ;AACf,cAAM,OAAO,MAAME,WAAU,KAAK,IAAI;AACtC,cAAM,MAAM,MAAM,OAAO,IAAI,qCAAqC,IAAI;AACtE,eAAO,IAAI,MAAM,MAAM;AAAA,MACzB,WAAW,KAAK,QAAQ;AACtB,cAAM,OAAQ,MAAMA,WAAU,KAAK,IAAI,KAAM,CAAC;AAC9C,cAAM,SAAiC,CAAC;AACxC,YAAI,KAAK,QAAS,QAAO,UAAU,KAAK;AACxC,cAAM,MAAM,MAAM,OAAO,KAAK,qCAAqC,MAAM,EAAE,OAAO,CAAC;AACnF,eAAO,IAAI,MAAM,MAAM;AAAA,MACzB,OAAO;AACL,oBAAY,IAAI,MAAM,8BAA8B,CAAC;AAAA,MACvD;AAAA,IACF,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AACL;;;AC7PA,SAASE,gBAAc,KAAuD;AAC5E,MAAI,OAAO;AACX,SAAO,KAAK,OAAQ,QAAO,KAAK;AAChC,SAAO,KAAK,KAAK;AACnB;AAGA,SAASC,aAA6B;AACpC,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,QAAI,OAAO;AACX,YAAQ,MAAM,YAAY,OAAO;AACjC,YAAQ,MAAM,GAAG,QAAQ,CAAC,UAAU;AAAE,cAAQ;AAAA,IAAO,CAAC;AACtD,YAAQ,MAAM,GAAG,OAAO,MAAM,QAAQ,IAAI,CAAC;AAC3C,YAAQ,MAAM,GAAG,SAAS,MAAM;AAAA,EAClC,CAAC;AACH;AAGA,eAAeC,WAAU,MAAwE;AAC/F,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI,SAAS,KAAK;AAChB,UAAM,QAAQ,MAAMD,WAAU;AAC9B,WAAO,KAAK,MAAM,KAAK;AAAA,EACzB;AACA,SAAO,KAAK,MAAM,IAAI;AACxB;AAGA,SAASE,oBAAmB,OAAyB;AACnD,MAAI,UAAU,QAAQ,UAAU,UAAa,OAAO,UAAU,SAAU,QAAO;AAC/E,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,MAAM,IAAIA,mBAAkB;AAE7D,QAAM,SAAS;AAGf,MAAI,MAAM,QAAQ,OAAO,IAAI,KAAK,OAAO,KAAK,SAAS,KAAK,OAAO,eAAe,QAAW;AAC3F,WAAO,EAAE,OAAO,cAAc,MAAM,OAAO,KAAK,QAAQ,YAAY,OAAO,WAAW;AAAA,EACxF;AAEA,QAAM,SAAkC,CAAC;AACzC,aAAW,CAAC,KAAK,GAAG,KAAK,OAAO,QAAQ,MAAM,GAAG;AAC/C,QAAI,OAAO,OAAO,QAAQ,YAAY,CAAC,MAAM,QAAQ,GAAG,GAAG;AACzD,YAAM,IAAI;AACV,UAAI,MAAM,QAAQ,EAAE,IAAI,KAAK,EAAE,KAAK,SAAS,KAAK,EAAE,eAAe,QAAW;AAC5E,eAAO,GAAG,IAAI,EAAE,OAAO,cAAc,MAAM,EAAE,KAAK,QAAQ,YAAY,EAAE,WAAW;AACnF;AAAA,MACF;AAAA,IACF;AACA,WAAO,GAAG,IAAIA,oBAAmB,GAAG;AAAA,EACtC;AACA,SAAO;AACT;AAEO,SAAS,oBAAoBC,UAAwB;AAC1D,QAAM,MAAMA,SAAQ,QAAQ,KAAK,EAAE;AAAA,IACjC;AAAA,EAEF;AAGA,QAAM,YAAY,IACf,QAAQ,WAAW,EACnB,YAAY,+CAA+C;AAE9D,YACG,QAAQ,MAAM,EACd;AAAA,IACC;AAAA,EAGF,EACC,OAAO,YAAY;AAClB,QAAI;AACF,YAAM,SAASJ,gBAAc,GAAG;AAChC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,MAAM,MAAM,OAAO,IAAI,4BAA4B;AACzD,aAAO,IAAI,MAAM,MAAM;AAAA,IACzB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAEH,YACG,QAAQ,UAAU,EAClB;AAAA,IACC;AAAA,EAGF,EACC,OAAO,OAAO,OAAe;AAC5B,QAAI;AACF,YAAM,SAASA,gBAAc,GAAG;AAChC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,MAAM,MAAM,OAAO,IAAI,8BAA8B,EAAE,EAAE;AAC/D,aAAO,IAAI,MAAM,MAAM;AAAA,IACzB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAGH,MACG,QAAQ,WAAW,EACnB;AAAA,IACC;AAAA,EAUF,EACC,OAAO,gBAAgB,8CAA8C,EACrE,OAAO,iBAAiB,4CAA4C,EACpE,OAAO,8BAA8B,wEAAwE,EAC7G,OAAO,SAAS,wDAAwD,EACxE,OAAO,sBAAsB,2BAA2B,EACxD,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASA,gBAAc,GAAG;AAChC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAElD,UAAI;AACJ,UAAI,KAAK,OAAO;AACd,cAAMK,OAAM,MAAM,OAAO,IAAI,yBAAyB,KAAK,KAAK,EAAE;AAClE,gBAAQA,KAAI;AAAA,MACd,WAAW,KAAK,MAAM;AACpB,gBAAQ,MAAMH,WAAU,KAAK,IAAI;AAAA,MACnC,OAAO;AACL,oBAAY,IAAI,MAAM,4DAA4D,CAAC;AACnF;AAAA,MACF;AAEA,YAAM,OAAgC,EAAE,MAAM,MAAM;AACpD,UAAI,KAAK,SAAU,MAAK,gBAAgB,KAAK;AAE7C,YAAM,MAAM,MAAM,OAAO,KAAK,uCAAuC,IAAI;AACzE,YAAM,SAAS,KAAK,MAAM,IAAI,OAAOC,oBAAmB,IAAI,IAAI;AAChE,aAAO,QAAQ,EAAE,GAAG,QAAQ,MAAM,KAAK,YAAY,OAAO,KAAK,CAAC;AAAA,IAClE,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AACL;;;AClJA,SAASG,gBAAc,KAAuD;AAC5E,MAAI,OAAO;AACX,SAAO,KAAK,OAAQ,QAAO,KAAK;AAChC,SAAO,KAAK,KAAK;AACnB;AAGA,SAASC,aAA6B;AACpC,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,QAAI,OAAO;AACX,YAAQ,MAAM,YAAY,OAAO;AACjC,YAAQ,MAAM,GAAG,QAAQ,CAAC,UAAU;AAAE,cAAQ;AAAA,IAAO,CAAC;AACtD,YAAQ,MAAM,GAAG,OAAO,MAAM,QAAQ,IAAI,CAAC;AAC3C,YAAQ,MAAM,GAAG,SAAS,MAAM;AAAA,EAClC,CAAC;AACH;AAGA,eAAeC,WAAU,MAAwE;AAC/F,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI,SAAS,KAAK;AAChB,UAAM,QAAQ,MAAMD,WAAU;AAC9B,WAAO,KAAK,MAAM,KAAK;AAAA,EACzB;AACA,SAAO,KAAK,MAAM,IAAI;AACxB;AAEO,SAAS,0BAA0BE,UAAwB;AAChE,QAAM,aAAaA,SAAQ,QAAQ,YAAY,EAAE;AAAA,IAC/C;AAAA,EACF;AAGA,aACG,QAAQ,QAAQ,EAChB;AAAA,IACC;AAAA,EAUF,EACC,eAAe,qBAAqB,oCAAoC,EACxE,OAAO,yBAAyB,+EAA+E,YAAY,EAC3H,OAAO,2BAA2B,uBAAuB,UAAU,EACnE,OAAO,uBAAuB,oBAAoB,QAAQ,EAC1D,OAAO,sBAAsB,uCAAuC,EACpE,OAAO,iBAAiB,oCAAoC,EAC5D,OAAO,oBAAoB,oDAAoD,EAC/E,OAAO,4BAA4B,mCAAmC,EACtE,OAAO,4BAA4B,mCAAmC,EACtE,OAAO,yBAAyB,8CAA8C,EAC9E,OAAO,sBAAsB,kCAAkC,EAC/D,OAAO,mBAAmB,sBAAsB,EAChD,OAAO,eAAe,iCAAiC,EACvD,OAAO,sBAAsB,+DAA+D,EAC5F,OAAO,iBAAiB,iEAAiE,EACzF,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASH,gBAAc,UAAU;AACvC,YAAM,SAAS,oBAAoB,aAAa,MAAM;AAEtD,YAAM,QAAS,MAAME,WAAU,KAAK,IAAI,KAAM,CAAC;AAC/C,YAAM,OAAgC;AAAA,QACpC,WAAW,KAAK;AAAA,QAChB,aAAa,KAAK;AAAA,QAClB,eAAe,KAAK;AAAA,QACpB,SAAS,KAAK,WAAW,YAAY,KAAK;AAAA,QAC1C,GAAI,KAAK,aAAa,EAAE,YAAY,KAAK,WAAW,IAAI,CAAC;AAAA,QACzD,GAAI,KAAK,OAAO,EAAE,MAAM,KAAK,KAAK,IAAI,CAAC;AAAA,QACvC,GAAI,KAAK,WAAW,EAAE,UAAU,KAAK,UAAU,iBAAiB,KAAK,SAAS,IAAI,CAAC;AAAA,QACnF,GAAI,KAAK,iBAAiB,EAAE,gBAAgB,KAAK,eAAe,IAAI,CAAC;AAAA,QACrE,GAAI,KAAK,iBAAiB,EAAE,gBAAgB,KAAK,eAAe,IAAI,CAAC;AAAA,QACrE,GAAI,KAAK,YAAY,EAAE,WAAW,KAAK,UAAU,IAAI,CAAC;AAAA,QACtD,GAAI,KAAK,UAAU,EAAE,SAAS,KAAK,QAAQ,IAAI,CAAC;AAAA,QAChD,GAAI,KAAK,eAAe,EAAE,cAAc,KAAK,IAAI,CAAC;AAAA,QAClD,GAAI,KAAK,WAAW,EAAE,UAAU,KAAK,IAAI,CAAC;AAAA,QAC1C,GAAG;AAAA,MACL;AAEA,YAAM,MAAM,KAAK,aAAa,cAAc,KAAK,UAAU,KAAK;AAChE,YAAM,MAAM,MAAM,OAAO,KAAK,KAAK,IAAI;AACvC,aAAO,IAAI,MAAM,EAAE,GAAG,QAAQ,MAAM,OAAO,KAAK,CAAC;AAAA,IACnD,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AACL;;;AC5FA,SAASE,gBAAc,KAAuD;AAC5E,MAAI,OAAO;AACX,SAAO,KAAK,OAAQ,QAAO,KAAK;AAChC,SAAO,KAAK,KAAK;AACnB;AAEO,SAAS,0BAA0BC,UAAwB;AAChE,QAAM,YAAYA,SAAQ,QAAQ,WAAW,EAAE;AAAA,IAC7C;AAAA,EACF;AAGA,YACG,QAAQ,MAAM,EACd;AAAA,IACC;AAAA,EAQF,EACC;AAAA,IACC;AAAA,IACA;AAAA,IACA;AAAA,EACF,EACC,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASD,gBAAc,SAAS;AACtC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAElD,YAAM,SAAiC,CAAC;AAGxC,UAAI,KAAK,QAAQ,KAAK,SAAS,WAAW;AACxC,eAAO,qBAAqB,KAAK;AAAA,MACnC;AAEA,YAAM,MAAM,MAAM,OAAO,IAAI,kBAAkB,EAAE,OAAO,CAAC;AACzD,aAAO,IAAI,MAAM,MAAM;AAAA,IACzB,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AACL;;;AC/CA,SAASE,gBAAc,KAAuD;AAC5E,MAAI,OAAO;AACX,SAAO,KAAK,OAAQ,QAAO,KAAK;AAChC,SAAO,KAAK,KAAK;AACnB;AA8BA,SAAS,KACP,UACA,KACA,OACA,QACM;AACN,MAAI,SAAS,OAAO;AAClB,gBAAY;AAAA,MACV,OAAO;AAAA,MACP,QAAQ,SAAS;AAAA,MACjB,SAAS,SAAS,MAAM,WAAW,SAAS,MAAM,QAAQ;AAAA,MAC1D,SAAS,SAAS;AAAA,IACpB,CAAC;AACD;AAAA,EACF;AAEA,QAAM,OAAO,SAAS;AACtB,MAAI,CAAC,MAAM;AACT,WAAO,EAAE,OAAO,OAAO,GAAG,MAAM,GAAG,MAAM;AACzC;AAAA,EACF;AACA,MAAI,KAAK;AACP,WAAO,KAAK,SAAS,MAAM;AAC3B;AAAA,EACF;AACA,MAAI,KAAK,UAAU,GAAG;AACpB,WAAO,EAAE,OAAO,OAAO,GAAG,MAAM,GAAG,MAAM;AACzC;AAAA,EACF;AACA,SAAO,KAAK,QAAQ,CAAC,GAAG,MAAM;AAChC;AAEO,SAAS,wBAAwBC,UAAwB;AAC9D,QAAM,UAAUA,SAAQ,QAAQ,SAAS,EAAE;AAAA,IACzC;AAAA,EAEF;AAGA,UACG,QAAQ,SAAS,EACjB;AAAA,IACC;AAAA,EAIF,EACC,eAAe,sBAAsB,+BAA+B,EACpE,OAAO,oBAAoB,uDAAuD,EAClF,OAAO,SAAS,2DAA2D,EAC3E,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASD,gBAAc,OAAO;AACpC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,MAAM,MAAM,OAAO;AAAA,QACvB;AAAA,QACA,EAAE,QAAQ,EAAE,SAAS,KAAK,SAAS,SAAS,KAAK,QAAQ,EAAE;AAAA,MAC7D;AACA,WAAK,IAAI,MAAM,KAAK,KAAK,EAAE,SAAS,KAAK,QAAQ,GAAG,MAAM;AAAA,IAC5D,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAGH,UACG,QAAQ,SAAS,EACjB;AAAA,IACC;AAAA,EAGF,EACC,eAAe,kBAAkB,UAAU,EAC3C,eAAe,kBAAkB,WAAW,EAC5C,OAAO,SAAS,2DAA2D,EAC3E,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASA,gBAAc,OAAO;AACpC,YAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,YAAM,MAAM,MAAM,OAAO;AAAA,QACvB;AAAA,QACA,EAAE,QAAQ,EAAE,KAAK,KAAK,KAAK,KAAK,KAAK,IAAI,EAAE;AAAA,MAC7C;AACA,WAAK,IAAI,MAAM,KAAK,KAAK,EAAE,KAAK,KAAK,KAAK,KAAK,KAAK,IAAI,GAAG,MAAM;AAAA,IACnE,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AACL;;;AC9HA,SAAkB,UAAAE,eAAc;AAKhC,SAASC,gBAAc,KAAuD;AAC5E,MAAI,OAAO;AACX,SAAO,KAAK,OAAQ,QAAO,KAAK;AAChC,SAAO,KAAK,KAAK;AACnB;AASA,IAAM,sBAAsB;AAE5B,IAAM,aAAa,CAAC,QAAQ,WAAW,QAAQ;AAGxC,SAAS,8BAA8BC,UAAwB;AACpE,QAAM,gBAAgBA,SACnB,QAAQ,eAAe,EACvB;AAAA,IACC;AAAA,EAGF;AAGF,gBACG,QAAQ,MAAM,EACd;AAAA,IACC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOF,EACC,eAAe,uBAAuB,uCAAuC,EAC7E,eAAe,oBAAoB,uCAAuC,EAC1E,OAAO,kBAAkB,sBAAsB,YAAY,EAC3D,OAAO,yBAAyB,aAAa,WAAW,KAAK,KAAK,CAAC,IAAI,MAAM,EAC7E;AAAA,IACC;AAAA,IACA;AAAA,EAEF,EACC;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC,OAAO,gBAAgB,0CAA0C,EACjE;AAAA,IACC;AAAA,IACA;AAAA,EACF,EAKC,UAAU,IAAIC,QAAO,iBAAiB,EAAE,SAAS,CAAC,EAClD,OAAO,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,SAASF,gBAAc,aAAa;AAE1C,YAAM,WAAW,KAAK;AACtB,UAAI,CAAC,WAAW,SAAS,QAAQ,GAAG;AAClC,cAAM,IAAI;AAAA,UACR,uBAAuB,KAAK,QAAQ,kBAAkB,WAAW,KAAK,IAAI,CAAC;AAAA,QAC7E;AAAA,MACF;AAGA,UAAI,KAAK,MAAO,qBAAoB,KAAK,KAAK;AAE9C,YAAM,SAAS,oBAAoB,iBAAiB,MAAM;AAK1D,YAAM,UAAU,iBAAiB,WAAW,CAAC;AAC7C,YAAM,cAAc,KAAK,WACrB,KAAK,WACL,KAAK,eACH,sBACA,QAAQ;AAEd,YAAM,eAAe;AAAA,QACnB,kBAAkB,KAAK,UAAU,gBAAgB;AAAA,QACjD;AAAA,QACA,QAAQ,KAAK,eAAe,eAAe;AAAA,QAC3C;AAAA,QACA,WAAW,KAAK;AAAA,QAChB,qBAAqB;AAAA,UACnB,aAAa;AAAA,UACb,MAAM,KAAK;AAAA,UACX,aAAa,KAAK;AAAA,UAClB,GAAI,KAAK,QAAQ,EAAE,YAAY,KAAK,MAAM,IAAI,CAAC;AAAA,UAC/C,GAAI,KAAK,OAAO,EAAE,MAAM,KAAK,KAAK,IAAI,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UAMvC,MAAM;AAAA,YACJ,QAAQ,KAAK,eAAe,eAAe;AAAA,YAC3C,GAAI,KAAK,QAAQ,EAAE,SAAS,KAAK,MAAM,IAAI,CAAC;AAAA,UAC9C;AAAA,QACF;AAAA,MACF;AAKA,YAAM,MAAM,MAAM,OAAO,KAAK,kBAAkB,YAAY;AAI5D,UAAI,OAAO,IAAI,SAAS,UAAU;AAChC;AAAA,UACE,EAAE,MAAM,OAAO,QAAQ,IAAI,MAAM,QAAQ,KAAK,OAAO;AAAA,UACrD;AAAA,QACF;AACA;AAAA,MACF;AACA;AAAA,QACE;AAAA,UACE,MAAM;AAAA,UACN,gBAAgB,IAAI,MAAM;AAAA,UAC1B,QAAQ,KAAK;AAAA,UACb,MAAM,aAAa;AAAA,UACnB;AAAA,QACF;AAAA,QACA;AAAA,MACF;AAAA,IACF,SAAS,KAAK;AACZ,kBAAY,eAAe,GAAG,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AACL;;;AC5HO,IAAM,gBAA+B,CAAC,QAAQ,SAAS,QAAQ;AAEtE,IAAM,aAA0C,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,EAAE;AAGxE,IAAM,eAA4B;AAElC,IAAM,UAAU;AAEhB,SAAS,UAAU,GAAwB;AAChD,SAAO,WAAW,CAAC;AACrB;AAEO,SAAS,YAAY,OAAsC;AAChE,SAAO,OAAO,UAAU,YAAa,cAA2B,SAAS,KAAK;AAChF;AAcO,SAAS,0BAAkD;AAChE,QAAM,SAAS,QAAQ,IAAI,OAAO,GAAG,KAAK;AAC1C,MAAI,QAAQ;AACV,UAAM,UAAU,OAAO,YAAY;AACnC,QAAI,YAAY,OAAO,EAAG,QAAO,EAAE,MAAM,SAAS,QAAQ,MAAM;AAEhE,UAAM,WAAW,kBAAkB;AACnC,WAAO,EAAE,GAAG,UAAU,YAAY,OAAO;AAAA,EAC3C;AACA,SAAO,kBAAkB;AAC3B;AAEA,SAAS,oBAA4C;AACnD,MAAI;AACF,UAAM,MAAM,WAAW;AACvB,QAAI,YAAY,IAAI,cAAc,EAAG,QAAO,EAAE,MAAM,IAAI,gBAAgB,QAAQ,SAAS;AAAA,EAC3F,QAAQ;AAAA,EAER;AACA,SAAO,EAAE,MAAM,cAAc,QAAQ,UAAU;AACjD;AAGO,SAAS,wBAAwB,MAAgC;AACtE,QAAM,MAAM,WAAW;AACvB,MAAI,SAAS,KAAM,QAAO,IAAI;AAAA,MACzB,KAAI,iBAAiB;AAC1B,aAAW,GAAG;AAChB;AAQA,IAAM,eAAe,oBAAI,IAAI,CAAC,UAAU,gBAAgB,SAAS,CAAC;AAElE,IAAM,cAAc,oBAAI,IAAI;AAAA,EAC1B;AAAA,EAAU;AAAA,EAAU;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAO;AAAA,EAAU;AAAA,EAAY;AAAA,EAChE;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAgB;AAAA,EAAe;AAAA,EAAW;AAAA,EAC1D;AAAA,EAAqB;AACvB,CAAC;AASD,IAAM,iBAA8C;AAAA,EAClD,gCAAgC;AAClC;AAEO,SAAS,aAAa,MAA6B;AACxD,QAAM,MAAM,KAAK,KAAK,GAAG;AACzB,MAAI,eAAe,GAAG,EAAG,QAAO,eAAe,GAAG;AAClD,MAAI,OAAoB;AACxB,aAAW,OAAO,MAAM;AACtB,QAAI,aAAa,IAAI,GAAG,EAAG,QAAO;AAClC,QAAI,YAAY,IAAI,GAAG,EAAG,QAAO;AAAA,EACnC;AACA,SAAO;AACT;AAUA,IAAM,uBAAuB,oBAAI,IAAI,CAAC,OAAO,OAAO,QAAQ,kBAAkB,KAAK,CAAC;AAE7E,SAAS,aAAa,MAAyB;AACpD,MAAI,KAAK,CAAC,MAAM,OAAQ,QAAO;AAC/B,MAAI,KAAK,CAAC,MAAM,kBAAmB,QAAO;AAC1C,MAAI,KAAK,CAAC,MAAM,YAAY,KAAK,WAAW,KAAK,qBAAqB,IAAI,KAAK,CAAC,CAAC,EAAG,QAAO;AAC3F,SAAO;AACT;AAQO,SAAS,oBAAoBG,UAA0C;AAC5E,QAAM,WAAW,wBAAwB;AACzC,gBAAcA,UAAS,CAAC,GAAG,UAAU,SAAS,IAAI,CAAC;AACnD,SAAO;AACT;AAEA,SAAS,cAAc,QAAiB,YAAsB,KAAmB;AAC/E,QAAM,OAAO,OAAO,SAAS,OAAO,CAAC,UAAU;AAC7C,UAAM,OAAO,CAAC,GAAG,YAAY,MAAM,KAAK,CAAC;AACzC,WAAO,YAAY,OAAO,MAAM,GAAG;AAAA,EACrC,CAAC;AAID,QAAM,UAAU,OAAO;AACvB,UAAQ,SAAS;AACjB,UAAQ,KAAK,GAAG,IAAI;AACtB;AAEA,SAAS,YAAY,KAAc,MAAgB,KAAsB;AACvE,MAAI,IAAI,SAAS,SAAS,GAAG;AAG3B,kBAAc,KAAK,MAAM,GAAG;AAC5B,QAAI,IAAI,SAAS,SAAS,EAAG,QAAO;AACpC,WAAO,aAAa,IAAI;AAAA,EAC1B;AAEA,MAAI,aAAa,IAAI,EAAG,QAAO;AAC/B,SAAO,UAAU,aAAa,IAAI,CAAC,KAAK;AAC1C;;;AC9JA,SAASC,gBAAc,KAA6B;AAClD,MAAI,OAAO;AACX,SAAO,KAAK,OAAQ,QAAO,KAAK;AAChC,SAAO,KAAK,KAAK;AACnB;AAcO,SAAS,8BAA8BC,UAAwB;AACpE,EAAAA,SACG,QAAQ,0BAA0B,EAAE,QAAQ,KAAK,CAAC,EAClD,YAAY,2EAA2E,EACvF,OAAO,CAAC,SAAkB;AACzB,QAAI;AACF,YAAM,SAASD,gBAAcC,QAAO;AAGpC,UAAI,CAAC,MAAM;AACT,cAAM,WAAW,wBAAwB;AACzC;AAAA,UACE;AAAA,YACE,gBAAgB,SAAS;AAAA,YACzB,QAAQ,SAAS;AAAA,YACjB,GAAI,SAAS,aACT,EAAE,SAAS,oBAAoB,OAAO,KAAK,SAAS,UAAU,gBAAgB,cAAc,KAAK,KAAK,CAAC,IAAI,IAC3G,CAAC;AAAA,YACL,WAAW;AAAA,YACX,QAAQ;AAAA,UACV;AAAA,UACA;AAAA,QACF;AACA;AAAA,MACF;AAEA,YAAM,QAAQ,KAAK,KAAK,EAAE,YAAY;AAEtC,UAAI,UAAU,SAAS;AACrB,gCAAwB,IAAI;AAC5B,cAAM,WAAW,wBAAwB;AACzC;AAAA,UACE;AAAA,YACE,SAAS;AAAA,YACT,SAAS,mDAAmD,SAAS,IAAI,KAAK,SAAS,MAAM;AAAA,YAC7F,gBAAgB,SAAS;AAAA,YACzB,QAAQ,SAAS;AAAA,UACnB;AAAA,UACA;AAAA,QACF;AACA;AAAA,MACF;AAEA,UAAI,CAAC,YAAY,KAAK,GAAG;AACvB,oBAAY,IAAI,MAAM,iBAAiB,IAAI,uBAAuB,cAAc,KAAK,IAAI,CAAC,eAAe,CAAC;AAC1G;AAAA,MACF;AAEA,8BAAwB,KAAK;AAC7B,YAAM,cAAc,wBAAwB;AAC5C,YAAM,UACJ,YAAY,WAAW,QACnB,kCAAkC,KAAK,UAAU,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,8BAA8B,YAAY,IAAI,wDAC/H,2BAA2B,KAAK;AACtC;AAAA,QACE;AAAA,UACE,SAAS;AAAA,UACT,gBAAgB;AAAA,UAChB,eAAe,YAAY;AAAA,UAC3B,iBAAiB,YAAY;AAAA,UAC7B,SAAS;AAAA,UACT;AAAA,QACF;AAAA,QACA;AAAA,MACF;AAAA,IACF,SAAS,KAAK;AACZ,kBAAY,GAAG;AAAA,IACjB;AAAA,EACF,CAAC;AACL;;;A/B/EA,IAAM,cAAc,OAAyC,WAAkB;AAExE,SAAS,gBAAyB;AACvC,QAAMC,WAAU,IAAIC,SAAQ;AAE5B,EAAAD,SACG,KAAK,UAAU,EACf,YAAY,wHAAwH,EACpI,QAAQ,WAAW,EACnB,OAAO,qBAAqB,6CAA6C,MAAM,EAC/E,OAAO,qBAAqB,6CAA6C,EACzE,OAAO,kBAAkB,yBAAyB,EAClD,OAAO,iBAAiB,+BAA+B,EACvD,OAAO,oBAAoB,+BAA+B,EAC1D,OAAO,aAAa,8CAA8C,EAClE,OAAO,WAAW,0BAA0B,EAC5C,OAAO,iBAAiB,6CAA6C;AAExE,uBAAqBA,QAAO;AAC5B,yBAAuBA,QAAO;AAC9B,4BAA0BA,QAAO;AACjC,0BAAwBA,QAAO;AAC/B,yBAAuBA,QAAO;AAC9B,8BAA4BA,QAAO;AACnC,4BAA0BA,QAAO;AACjC,sBAAoBA,QAAO;AAC3B,4BAA0BA,QAAO;AACjC,4BAA0BA,QAAO;AACjC,0BAAwBA,QAAO;AAC/B,gCAA8BA,QAAO;AAIrC,gCAA8BA,QAAO;AAKrC,sBAAoBA,QAAO;AAE3B,SAAOA;AACT;;;AgC1DA,IAAM,UAAU,cAAc;AAC9B,QAAQ,WAAW,QAAQ,IAAI,EAAE,MAAM,CAAC,QAAQ;AAC9C,UAAQ,OAAO,MAAM,KAAK,UAAU,EAAE,OAAO,MAAM,SAAS,IAAI,QAAQ,CAAC,IAAI,IAAI;AACjF,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":["Command","writeFileSync","program","hadToken","readFileSync","writeFileSync","join","getGlobalOpts","getGlobalOpts","getGlobalOpts","getGlobalOpts","program","getGlobalOpts","readFileSync","getGlobalOpts","parseData","readFileSync","res","getGlobalOpts","getGlobalOpts","parseData","program","readFileSync","writeFileSync","existsSync","existsSync","readFileSync","writeFileSync","getGlobalOpts","getGlobalOpts","program","readFileSync","getGlobalOpts","readFileSync","program","readFileSync","getGlobalOpts","program","readFileSync","getGlobalOpts","readStdin","parseData","program","getGlobalOpts","readStdin","parseData","compactStudyOutput","program","res","getGlobalOpts","readStdin","parseData","program","getGlobalOpts","program","getGlobalOpts","program","Option","getGlobalOpts","program","Option","program","getGlobalOpts","program","program","Command"]}
1
+ {"version":3,"sources":["../../src/index.ts","../../src/config.ts","../../src/client.ts","../../src/output.ts","../../src/commands/auth.ts","../../src/commands/config/shared.ts","../../src/commands/config/theme.ts","../../src/commands/config/advanced.ts","../../src/commands/config/solarform.ts","../../src/commands/config.ts","../../src/commands/inventory/factory.ts","../../src/commands/inventory/kits.ts","../../src/commands/inventory/manufacturers.ts","../../src/commands/inventory/custom-fields.ts","../../src/commands/inventory/index.ts","../../src/commands/studies/builder.ts","../../node_modules/uuid/dist/esm-node/rng.js","../../node_modules/uuid/dist/esm-node/regex.js","../../node_modules/uuid/dist/esm-node/validate.js","../../node_modules/uuid/dist/esm-node/stringify.js","../../node_modules/uuid/dist/esm-node/v4.js","../../src/commands/studies/index.ts","../../src/commands/curves/index.ts","../../src/commands/consumption/index.ts","../../src/commands/solarform/index.ts","../../src/commands/ppa/index.ts","../../src/commands/shareables/index.ts","../../src/commands/templates/index.ts","../../src/commands/geocode/index.ts","../../src/commands/notifications/index.ts","../../src/access.ts","../../src/commands/command-profile.ts","../../bin/suntropy.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { registerAuthCommands } from './commands/auth.js';\nimport { registerConfigCommands } from './commands/config.js';\nimport { registerInventoryCommands } from './commands/inventory/index.js';\nimport { registerStudiesCommands } from './commands/studies/index.js';\nimport { registerCurvesCommands } from './commands/curves/index.js';\nimport { registerConsumptionCommands } from './commands/consumption/index.js';\nimport { registerSolarformCommands } from './commands/solarform/index.js';\nimport { registerPPACommands } from './commands/ppa/index.js';\nimport { registerShareableCommands } from './commands/shareables/index.js';\nimport { registerTemplatesCommands } from './commands/templates/index.js';\nimport { registerGeocodeCommands } from './commands/geocode/index.js';\nimport { registerNotificationsCommands } from './commands/notifications/index.js';\nimport { registerCommandProfileCommand } from './commands/command-profile.js';\nimport { applyCommandProfile } from './access.js';\n\n// Injected at build time by tsup (define) from package.json. In dev (tsx, no\n// define) the identifier is undefined, so we fall back without throwing.\ndeclare const __CLI_VERSION__: string;\nconst CLI_VERSION = typeof __CLI_VERSION__ !== 'undefined' ? __CLI_VERSION__ : '0.0.0-dev';\n\nexport function createProgram(): Command {\n const program = new Command();\n\n program\n .name('suntropy')\n .description('Agent-first CLI for Suntropy solar platform. Optimized for programmatic data manipulation and progressive exploration.')\n .version(CLI_VERSION)\n .option('--format <format>', 'Output format: json (default), human, csv', 'json')\n .option('--fields <fields>', 'Comma-separated fields to include in output')\n .option('--server <url>', 'Override API server URL')\n .option('--token <jwt>', 'Override authentication token')\n .option('--profile <name>', 'Use a specific config profile')\n .option('--verbose', 'Show HTTP request/response details on stderr')\n .option('--quiet', 'Suppress non-data output')\n .option('--save <file>', 'Save output to file (also writes to stdout)');\n\n registerAuthCommands(program);\n registerConfigCommands(program);\n registerInventoryCommands(program);\n registerStudiesCommands(program);\n registerCurvesCommands(program);\n registerConsumptionCommands(program);\n registerSolarformCommands(program);\n registerPPACommands(program);\n registerShareableCommands(program);\n registerTemplatesCommands(program);\n registerGeocodeCommands(program);\n registerNotificationsCommands(program);\n\n // Hidden admin command to manage the command access profile. Registered last\n // and always exempt from gating, so it can raise/lower the tier from any tier.\n registerCommandProfileCommand(program);\n\n // Gate the command tree by the active permission tier (env > config > default\n // 'delete'). Commands above the tier are pruned: absent from --help and\n // reported as \"unknown command\" when invoked.\n applyCommandProfile(program);\n\n return program;\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\nimport { homedir } from 'os';\nimport { join } from 'path';\n\nexport interface SuntropyProfile {\n server: string;\n token?: string;\n authMethod?: 'api-key' | 'login';\n email?: string;\n clientUID?: string;\n userUID?: string;\n}\n\nexport interface SuntropyConfig {\n activeProfile: string;\n profiles: Record<string, SuntropyProfile>;\n /**\n * Command access profile (permission tier). Gates which commands are\n * registered/visible. Cumulative: read ⊂ write ⊂ delete. Absent → 'delete'\n * (full access, preserves legacy behavior). Managed via the hidden\n * `command-profile` admin command or the SUNTROPY_COMMAND_PROFILE env var.\n */\n commandProfile?: 'read' | 'write' | 'delete';\n}\n\nconst CONFIG_DIR = join(homedir(), '.suntropy');\nconst CONFIG_FILE = join(CONFIG_DIR, 'config.json');\n\nconst DEFAULT_CONFIG: SuntropyConfig = {\n activeProfile: 'default',\n profiles: {\n default: {\n server: 'https://api.enerlence.com',\n },\n },\n};\n\nfunction ensureConfigDir(): void {\n if (!existsSync(CONFIG_DIR)) {\n mkdirSync(CONFIG_DIR, { recursive: true });\n }\n}\n\nexport function loadConfig(): SuntropyConfig {\n ensureConfigDir();\n if (!existsSync(CONFIG_FILE)) {\n writeFileSync(CONFIG_FILE, JSON.stringify(DEFAULT_CONFIG, null, 2));\n return { ...DEFAULT_CONFIG };\n }\n return JSON.parse(readFileSync(CONFIG_FILE, 'utf-8'));\n}\n\nexport function saveConfig(config: SuntropyConfig): void {\n ensureConfigDir();\n writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));\n}\n\nexport function getActiveProfile(config: SuntropyConfig, profileOverride?: string): SuntropyProfile {\n const name = profileOverride || config.activeProfile;\n const profile = config.profiles[name];\n if (!profile) {\n throw new Error(`Profile \"${name}\" not found. Available: ${Object.keys(config.profiles).join(', ')}`);\n }\n return profile;\n}\n\nexport function setConfigValue(key: string, value: string, profileName?: string): void {\n const config = loadConfig();\n const name = profileName || config.activeProfile;\n if (!config.profiles[name]) {\n config.profiles[name] = { server: 'https://api.enerlence.com' };\n }\n const profile = config.profiles[name] as Record<string, unknown>;\n profile[key] = value;\n saveConfig(config);\n}\n\nexport function getConfigValue(key: string, profileName?: string): unknown {\n const config = loadConfig();\n const profile = getActiveProfile(config, profileName);\n return (profile as Record<string, unknown>)[key];\n}\n\n/** Service path mapping */\nconst SERVICE_PATHS: Record<string, string> = {\n security: '/security',\n solar: '/solar',\n templates: '/templates',\n profiles: '/profiles',\n periods: '/periods',\n notifications: '/notifications',\n};\n\nconst LOCAL_PORTS: Record<string, number> = {\n security: 8080,\n solar: 8086,\n templates: 8090,\n profiles: 8085,\n periods: 8084,\n notifications: 8093,\n};\n\nexport function getServiceUrl(baseServer: string, service: keyof typeof SERVICE_PATHS): string {\n // If baseServer looks like localhost without path, use port-based routing\n if (baseServer.includes('localhost') || baseServer.match(/:\\d+$/)) {\n const port = LOCAL_PORTS[service];\n const host = baseServer.replace(/:\\d+$/, '').replace(/\\/$/, '');\n return `${host}:${port}`;\n }\n // Production: path-based routing\n return `${baseServer.replace(/\\/$/, '')}${SERVICE_PATHS[service]}`;\n}\n","import axios, { AxiosInstance, AxiosError } from 'axios';\nimport { loadConfig, getActiveProfile, getServiceUrl, type SuntropyProfile } from './config.js';\n\nexport interface ClientOptions {\n server?: string;\n token?: string;\n profile?: string;\n verbose?: boolean;\n}\n\nexport interface ApiError {\n error: true;\n status: number;\n message: string;\n details?: unknown;\n}\n\nfunction resolveAuth(opts: ClientOptions): { server: string; token: string } {\n const config = loadConfig();\n const profile = getActiveProfile(config, opts.profile);\n const server = opts.server || profile.server;\n // Auth token resolution order: explicit --token flag > SUNTROPY_API_KEY env var > stored profile token.\n // The env var fallback lets host runtimes (e.g. ShellPilot) inject a just-in-time credential\n // without requiring a prior `auth login` / `auth set-key` to write the config file.\n const token = opts.token || process.env.SUNTROPY_API_KEY || profile.token;\n if (!token) {\n throw new Error('Not authenticated. Run: suntropy auth set-key --key <jwt> or suntropy auth login, or set the SUNTROPY_API_KEY env var.');\n }\n return { server, token };\n}\n\nexport function createServiceClient(service: 'security' | 'solar' | 'templates' | 'profiles' | 'periods' | 'notifications', opts: ClientOptions): AxiosInstance {\n const { server, token } = resolveAuth(opts);\n const baseURL = getServiceUrl(server, service);\n\n const client = axios.create({\n baseURL,\n timeout: 30000,\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (opts.verbose) {\n client.interceptors.request.use((req) => {\n process.stderr.write(`→ ${req.method?.toUpperCase()} ${req.baseURL}${req.url}\\n`);\n if (req.data) process.stderr.write(` Body: ${JSON.stringify(req.data).slice(0, 200)}\\n`);\n return req;\n });\n client.interceptors.response.use(\n (res) => {\n process.stderr.write(`← ${res.status} (${JSON.stringify(res.data).length} bytes)\\n`);\n return res;\n },\n (err: AxiosError) => {\n process.stderr.write(`← ERROR ${err.response?.status || 'NETWORK'}: ${err.message}\\n`);\n return Promise.reject(err);\n },\n );\n }\n\n return client;\n}\n\n/** Unauthenticated client for login */\nexport function createUnauthClient(baseURL: string): AxiosInstance {\n return axios.create({\n baseURL,\n timeout: 15000,\n headers: { 'Content-Type': 'application/json' },\n });\n}\n\n/** A MongoDB ObjectId serializes to exactly 24 hexadecimal characters. */\nconst OBJECT_ID_RE = /^[a-f0-9]{24}$/i;\n\n/**\n * Guards a solar-study `_id` argument before it reaches the backend.\n *\n * `GET /solar-study/findById/:_id` runs `solarStudyModel.findOne({ _id })`,\n * which makes Mongoose cast the value to an ObjectId. A non-ObjectId string\n * (e.g. a UUID like a chat/shareable uid) throws a `CastError` server-side and\n * surfaces as an opaque **HTTP 500**, so the caller gets no hint about what\n * went wrong. Every real study `_id` is a 24-hex ObjectId, so we can reject\n * bad ids client-side with an actionable message instead.\n *\n * Throws so the caller's try/catch surfaces it via `outputError` (exit != 0).\n */\nexport function assertStudyObjectId(id: string): string {\n if (OBJECT_ID_RE.test(id)) return id;\n const looksLikeUuid = /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i.test(id);\n const hint = looksLikeUuid\n ? `It looks like a UUID (e.g. a chat or shareable uid), not a study _id.`\n : `A study _id is a 24-character hex MongoDB ObjectId.`;\n throw new Error(\n `Invalid study id: \"${id}\". ${hint} ` +\n `Get the correct id from \\`suntropy studies list\\` (the \\`solarStudyId\\` field).`,\n );\n}\n\n/**\n * Validates that an API response body actually contains an entity.\n *\n * The solar backend returns `200` with an EMPTY body when `findById` /\n * `addSolarStudyComment` don't match a document (wrong id, or the id belongs to\n * a different clientUID / environment). Without this guard the CLI either\n * crashes downstream (`'_id' in data`, `data.solarStudyProgress = ...` on `\"\"`)\n * or — worse, for writes — reports `success` even though nothing was saved.\n *\n * Throws a clear, actionable error so the caller's try/catch surfaces it via\n * `outputError` with a non-zero exit code.\n */\nexport function assertFound<T>(data: T, entity: string, id: string): T {\n const isEmptyObject =\n data != null &&\n typeof data === 'object' &&\n !Array.isArray(data) &&\n Object.keys(data as Record<string, unknown>).length === 0;\n if (data == null || typeof data !== 'object' || Array.isArray(data) || isEmptyObject) {\n throw new Error(\n `${entity} not found: ${id}. The backend returned an empty response — ` +\n `verify the id is correct and belongs to your account and environment ` +\n `(the CLI and the app must point to the same backend).`,\n );\n }\n return data;\n}\n\nexport function handleApiError(err: unknown): ApiError {\n if (axios.isAxiosError(err)) {\n const ae = err as AxiosError;\n return {\n error: true,\n status: ae.response?.status || 0,\n message: ae.response?.statusText || ae.message,\n details: ae.response?.data,\n };\n }\n return {\n error: true,\n status: 0,\n message: err instanceof Error ? err.message : String(err),\n };\n}\n","import chalk from 'chalk';\nimport { writeFileSync } from 'fs';\n\nexport type OutputFormat = 'json' | 'human' | 'csv';\n\nexport interface OutputOptions {\n format?: OutputFormat;\n fields?: string;\n quiet?: boolean;\n save?: string;\n}\n\n/** Pick only specified fields from an object */\nfunction pickFields(obj: Record<string, unknown>, fields: string[]): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const f of fields) {\n if (f.includes('.')) {\n const parts = f.split('.');\n let val: unknown = obj;\n for (const p of parts) {\n val = val && typeof val === 'object' ? (val as Record<string, unknown>)[p] : undefined;\n }\n result[f] = val;\n } else {\n result[f] = obj[f];\n }\n }\n return result;\n}\n\nfunction applyFieldSelection(data: unknown, fields?: string): unknown {\n if (!fields) return data;\n const fieldList = fields.split(',').map((f) => f.trim());\n if (Array.isArray(data)) {\n return data.map((item) => pickFields(item as Record<string, unknown>, fieldList));\n }\n if (typeof data === 'object' && data !== null) {\n return pickFields(data as Record<string, unknown>, fieldList);\n }\n return data;\n}\n\nfunction formatHumanValue(val: unknown): string {\n if (val === null || val === undefined) return '-';\n if (typeof val === 'object') return JSON.stringify(val);\n return String(val);\n}\n\nfunction formatHuman(data: unknown): string {\n if (Array.isArray(data)) {\n if (data.length === 0) return chalk.dim('(empty)');\n const keys = Object.keys(data[0] as Record<string, unknown>);\n const widths = keys.map((k) => Math.max(k.length, ...data.map((r) => formatHumanValue((r as Record<string, unknown>)[k]).length)));\n const header = keys.map((k, i) => chalk.bold(k.padEnd(widths[i]))).join(' ');\n const rows = data.map((row) =>\n keys.map((k, i) => formatHumanValue((row as Record<string, unknown>)[k]).padEnd(widths[i])).join(' '),\n );\n return [header, keys.map((_, i) => '─'.repeat(widths[i])).join(' '), ...rows].join('\\n');\n }\n if (typeof data === 'object' && data !== null) {\n const entries = Object.entries(data as Record<string, unknown>);\n const maxKey = Math.max(...entries.map(([k]) => k.length));\n return entries.map(([k, v]) => `${chalk.bold(k.padEnd(maxKey))} ${formatHumanValue(v)}`).join('\\n');\n }\n return String(data);\n}\n\nfunction formatCsv(data: unknown): string {\n if (!Array.isArray(data)) {\n if (typeof data === 'object' && data !== null) data = [data];\n else return String(data);\n }\n const arr = data as Record<string, unknown>[];\n if (arr.length === 0) return '';\n const keys = Object.keys(arr[0]);\n const escape = (v: unknown) => {\n const s = v === null || v === undefined ? '' : String(v);\n return s.includes(',') || s.includes('\"') || s.includes('\\n') ? `\"${s.replace(/\"/g, '\"\"')}\"` : s;\n };\n return [keys.join(','), ...arr.map((r) => keys.map((k) => escape(r[k])).join(','))].join('\\n');\n}\n\nexport function output(data: unknown, opts: OutputOptions = {}): void {\n const filtered = applyFieldSelection(data, opts.fields);\n let text: string;\n\n switch (opts.format) {\n case 'human':\n text = formatHuman(filtered);\n break;\n case 'csv':\n text = formatCsv(filtered);\n break;\n default:\n text = JSON.stringify(filtered, null, 2);\n }\n\n process.stdout.write(text + '\\n');\n\n if (opts.save) {\n writeFileSync(opts.save, JSON.stringify(filtered, null, 2));\n }\n}\n\nexport function outputError(err: unknown): void {\n if (err && typeof err === 'object' && 'error' in err) {\n // ApiError object — include details\n const apiErr = err as { error: boolean; status?: number; message?: string; details?: unknown };\n const out: Record<string, unknown> = { error: true, message: apiErr.message || 'Unknown error' };\n if (apiErr.status) out.status = apiErr.status;\n if (apiErr.details) out.details = apiErr.details;\n process.stderr.write(JSON.stringify(out) + '\\n');\n } else {\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(JSON.stringify({ error: true, message: msg }) + '\\n');\n }\n process.exitCode = 1;\n}\n\n/** Wrap paginated response */\nexport function outputPaginated(data: unknown[], total: number, limit: number, offset: number, opts: OutputOptions = {}): void {\n if (opts.format === 'human') {\n const filtered = applyFieldSelection(data, opts.fields);\n const end = Math.min(offset + limit, total);\n process.stdout.write(chalk.dim(`Showing ${offset + 1}-${end} of ${total}\\n\\n`));\n process.stdout.write(formatHuman(filtered) + '\\n');\n } else {\n output({ data: applyFieldSelection(data, opts.fields), total, limit, offset, hasMore: offset + limit < total }, { ...opts, fields: undefined });\n }\n}\n","import { Command } from 'commander';\nimport { loadConfig, saveConfig, getActiveProfile, getServiceUrl } from '../config.js';\nimport { createUnauthClient, createServiceClient, handleApiError } from '../client.js';\nimport { output, outputError, type OutputOptions } from '../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\nexport function registerAuthCommands(program: Command): void {\n const auth = program.command('auth').description('Authentication management');\n\n // --- set-key (preferred for agents) ---\n auth\n .command('set-key')\n .description('Set an API key (JWT) for authentication. Preferred method for agents.')\n .requiredOption('--key <jwt>', 'JWT API key')\n .action(async (opts) => {\n try {\n // --server / --profile are global root options (see createProgram);\n // read them from there instead of redefining them locally, otherwise\n // Commander assigns them to the root and they never reach this action.\n const global = getGlobalOpts(auth);\n const config = loadConfig();\n const profileName = (global.profile as string) || config.activeProfile;\n if (!config.profiles[profileName]) {\n config.profiles[profileName] = { server: 'https://api.enerlence.com' };\n }\n const profile = config.profiles[profileName];\n profile.token = opts.key;\n profile.authMethod = 'api-key';\n if (global.server) profile.server = global.server as string;\n\n // Decode JWT to extract clientUID\n try {\n const payload = JSON.parse(Buffer.from(opts.key.split('.')[1], 'base64').toString());\n profile.clientUID = payload.clientUID;\n profile.userUID = payload.userUID;\n } catch {\n // If JWT decode fails, just save the key\n }\n\n saveConfig(config);\n output({ success: true, method: 'api-key', profile: profileName, clientUID: profile.clientUID, server: profile.server }, getGlobalOpts(auth));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- login ---\n auth\n .command('login')\n .description('Login with email and password')\n .requiredOption('--email <email>', 'User email')\n .requiredOption('--password <password>', 'User password')\n .action(async (opts) => {\n try {\n // --server / --profile come from the global root options.\n const global = getGlobalOpts(auth);\n const config = loadConfig();\n const profileName = (global.profile as string) || config.activeProfile;\n if (!config.profiles[profileName]) {\n config.profiles[profileName] = { server: 'https://api.enerlence.com' };\n }\n const profile = config.profiles[profileName];\n if (global.server) profile.server = global.server as string;\n\n const securityUrl = getServiceUrl(profile.server, 'security');\n const client = createUnauthClient(securityUrl);\n const res = await client.post('/auth/login', { email: opts.email, password: opts.password });\n\n if (res.data?.token?.access_token) {\n profile.token = res.data.token.access_token;\n profile.authMethod = 'login';\n profile.email = opts.email;\n profile.clientUID = res.data.user?.clientUID;\n profile.userUID = res.data.user?.userUID;\n saveConfig(config);\n output({\n success: true,\n method: 'login',\n profile: profileName,\n user: {\n email: res.data.user?.email,\n clientUID: res.data.user?.clientUID,\n userUID: res.data.user?.userUID,\n },\n }, getGlobalOpts(auth));\n } else {\n outputError(new Error(res.data?.errors?.[0]?.message || 'Login failed'));\n }\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- status ---\n auth\n .command('status')\n .description('Show current authentication status')\n .action(async () => {\n try {\n // --profile is a global root option.\n const global = getGlobalOpts(auth);\n const config = loadConfig();\n const profile = getActiveProfile(config, global.profile as string);\n if (!profile.token) {\n output({ authenticated: false, message: 'No token configured' }, getGlobalOpts(auth));\n return;\n }\n\n // Decode JWT to check expiry\n let expiresAt: string | undefined;\n let expired = false;\n try {\n const payload = JSON.parse(Buffer.from(profile.token.split('.')[1], 'base64').toString());\n if (payload.exp) {\n const expDate = new Date(payload.exp * 1000);\n expiresAt = expDate.toISOString();\n expired = expDate < new Date();\n }\n } catch {\n // ignore decode errors\n }\n\n output({\n authenticated: !expired,\n method: profile.authMethod || 'unknown',\n server: profile.server,\n email: profile.email,\n clientUID: profile.clientUID,\n userUID: profile.userUID,\n expiresAt,\n expired,\n }, getGlobalOpts(auth));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- refresh ---\n auth\n .command('refresh')\n .description('Refresh the current JWT token')\n .action(async () => {\n try {\n // --profile is a global root option.\n const globalOpts = getGlobalOpts(auth);\n const config = loadConfig();\n const profileName = (globalOpts.profile as string) || config.activeProfile;\n const client = createServiceClient('security', { ...globalOpts, profile: profileName });\n const res = await client.get('/auth/jwt/refreshToken');\n\n if (res.data?.access_token || res.data?.token?.access_token) {\n const newToken = res.data.access_token || res.data.token.access_token;\n config.profiles[profileName].token = newToken;\n saveConfig(config);\n output({ success: true, message: 'Token refreshed' }, getGlobalOpts(auth));\n } else {\n outputError(new Error('Refresh failed'));\n }\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- logout ---\n auth\n .command('logout')\n .description(\n 'Clear stored credentials for the active profile (or --profile). Removes the\\n' +\n 'token and account identity but keeps the profile and its server URL.\\n' +\n 'Use --all to log out of every profile.'\n )\n .option('--all', 'Clear credentials for ALL profiles')\n .action(async (opts) => {\n try {\n // --profile is a global root option.\n const global = getGlobalOpts(auth);\n const config = loadConfig();\n\n // Strip credentials/identity from a profile, keep server. Returns\n // whether the profile actually had a token before clearing.\n const clearProfile = (name: string): boolean => {\n const profile = config.profiles[name];\n if (!profile) return false;\n const hadToken = !!profile.token;\n delete profile.token;\n delete profile.authMethod;\n delete profile.email;\n delete profile.clientUID;\n delete profile.userUID;\n return hadToken;\n };\n\n if (opts.all) {\n const names = Object.keys(config.profiles);\n const clearedWithToken = names.filter(clearProfile);\n saveConfig(config);\n output({\n success: true,\n message: `Logged out of ${names.length} profile(s).`,\n profiles: names,\n hadCredentials: clearedWithToken,\n }, global);\n return;\n }\n\n const profileName = (global.profile as string) || config.activeProfile;\n if (!config.profiles[profileName]) {\n outputError(new Error(`Profile \"${profileName}\" not found. Available: ${Object.keys(config.profiles).join(', ')}`));\n return;\n }\n const hadToken = clearProfile(profileName);\n saveConfig(config);\n output({\n success: true,\n profile: profileName,\n message: hadToken\n ? `Logged out of profile \"${profileName}\". Credentials cleared (server kept).`\n : `Profile \"${profileName}\" had no stored credentials.`,\n }, global);\n } catch (err) {\n outputError(err);\n }\n });\n}\n","import { Command } from 'commander';\nimport { readFileSync, writeFileSync, unlinkSync } from 'fs';\nimport { tmpdir } from 'os';\nimport { join } from 'path';\nimport { spawnSync } from 'child_process';\nimport type { OutputOptions } from '../../output.js';\n\nexport type GlobalOpts = OutputOptions & Record<string, unknown>;\n\n/** Walk up to the root program and return its options. */\nexport function getGlobalOpts(cmd: Command): GlobalOpts {\n let root: Command = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as GlobalOpts;\n}\n\n/** Coerce a string value into boolean / number / JSON when it makes sense. */\nexport function coerceValue(raw: string): unknown {\n if (raw === 'true') return true;\n if (raw === 'false') return false;\n if (raw === 'null') return null;\n if (/^-?\\d+$/.test(raw)) return parseInt(raw, 10);\n if (/^-?\\d*\\.\\d+$/.test(raw)) return parseFloat(raw);\n if ((raw.startsWith('{') && raw.endsWith('}')) || (raw.startsWith('[') && raw.endsWith(']'))) {\n try { return JSON.parse(raw); } catch { /* fall through to string */ }\n }\n return raw;\n}\n\n/** Parse an array of `--set key=value` entries into a flat object. */\nexport function parseSetFlags(entries: string[] | undefined): Record<string, unknown> {\n if (!entries || entries.length === 0) return {};\n const out: Record<string, unknown> = {};\n for (const entry of entries) {\n const eq = entry.indexOf('=');\n if (eq < 0) throw new Error(`Invalid --set value \"${entry}\" (expected key=value)`);\n const key = entry.slice(0, eq).trim();\n const rawVal = entry.slice(eq + 1);\n if (!key) throw new Error(`Invalid --set value \"${entry}\" (empty key)`);\n out[key] = coerceValue(rawVal);\n }\n return out;\n}\n\n/** Load a JSON file (absolute or relative path). */\nexport function loadFromFile(path: string): Record<string, unknown> {\n const raw = readFileSync(path, 'utf-8');\n const parsed = JSON.parse(raw);\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new Error(`File ${path} must contain a JSON object at the top level`);\n }\n return parsed as Record<string, unknown>;\n}\n\n/** Pick a subset of keys from an object (shallow). */\nexport function pickKeys<T extends Record<string, unknown>>(obj: T | undefined | null, keys: readonly string[]): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n if (!obj) return out;\n for (const k of keys) {\n if (k in obj) out[k] = (obj as Record<string, unknown>)[k];\n }\n return out;\n}\n\n/** Build a merge payload from: --from-file, --set key=value, and direct flag mappings. */\nexport function buildPayload(\n flagValues: Record<string, unknown>,\n setEntries: string[] | undefined,\n fromFile: string | undefined,\n allowedKeys?: readonly string[],\n): Record<string, unknown> {\n const payload: Record<string, unknown> = {};\n if (fromFile) Object.assign(payload, loadFromFile(fromFile));\n if (setEntries) Object.assign(payload, parseSetFlags(setEntries));\n for (const [k, v] of Object.entries(flagValues)) {\n if (v !== undefined) payload[k] = v;\n }\n if (allowedKeys) {\n for (const k of Object.keys(payload)) {\n if (!allowedKeys.includes(k)) {\n throw new Error(`Field \"${k}\" does not belong to this section. Allowed: ${allowedKeys.join(', ')}`);\n }\n }\n }\n return payload;\n}\n\n/** Open $EDITOR (or vi) on a JSON blob and return the parsed result. */\nexport function editJson(initial: unknown, filenameHint = 'config'): Record<string, unknown> {\n const editor = process.env.EDITOR || process.env.VISUAL || 'vi';\n const tmp = join(tmpdir(), `suntropy-${filenameHint}-${Date.now()}.json`);\n writeFileSync(tmp, JSON.stringify(initial ?? {}, null, 2));\n try {\n const res = spawnSync(editor, [tmp], { stdio: 'inherit' });\n if (res.status !== 0) throw new Error(`Editor \"${editor}\" exited with status ${res.status}`);\n const updated = readFileSync(tmp, 'utf-8');\n const parsed = JSON.parse(updated);\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new Error('Edited content must be a JSON object at the top level');\n }\n return parsed as Record<string, unknown>;\n } finally {\n try { unlinkSync(tmp); } catch { /* ignore */ }\n }\n}\n","import { Command } from 'commander';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError } from '../../output.js';\nimport { getGlobalOpts, buildPayload, editJson, pickKeys } from './shared.js';\n\n/**\n * Keys accepted by POST /clients/config/updateTheme.\n * Mirrors ClientThemeConfig in backend/security.\n */\nconst THEME_KEYS = [\n 'idClientThemeConfig',\n 'primary',\n 'btnPrimary',\n 'btnSecondary',\n 'background',\n 'navbarBackgroundColor',\n 'graph1', 'graph2', 'graph3', 'graph4', 'graph5', 'graph6',\n 'logoUrl',\n 'faviconUrl',\n 'clientAppTitle',\n 'carouselLinks',\n 'enableCustomTheme',\n] as const;\n\nexport function registerThemeCommands(configRoot: Command): void {\n const theme = configRoot\n .command('theme')\n .description(\n 'Client branding & theme (security service).\\n' +\n 'Colours, logo, favicon and app title applied across Suntropy.\\n' +\n 'Endpoints: GET /clients/config/clientThemeByClientUID/:uid (public)\\n' +\n ' POST /clients/config/updateTheme (requires admin role)\\n\\n' +\n 'Fields:\\n' +\n ' primary, btnPrimary, btnSecondary Core palette (hex).\\n' +\n ' background, navbarBackgroundColor Surface colours.\\n' +\n ' graph1..graph6 Chart palette (6 slots).\\n' +\n ' logoUrl, faviconUrl Asset URLs.\\n' +\n ' clientAppTitle Visible app title.\\n' +\n ' carouselLinks JSON-serialised carousel config.\\n' +\n ' enableCustomTheme Toggles the custom theme on/off.'\n );\n\n theme\n .command('get')\n .description('Fetch the theme of a client (public endpoint, no auth required for reads).')\n .requiredOption('--client-uid <uid>', 'Client UID whose theme should be fetched')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(theme);\n const client = createServiceClient('security', global);\n const res = await client.get(`/clients/config/clientThemeByClientUID/${opts.clientUid}`);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n theme\n .command('set')\n .description(\n 'Update the theme of the authenticated client (requires admin role).\\n' +\n 'Combine individual flags, repeatable --set key=value, and/or --from-file.\\n' +\n 'Example:\\n' +\n ' suntropy config theme set --primary \"#0066ff\" --logo-url https://cdn/logo.svg\\n' +\n ' suntropy config theme set --set graph1=#ff0000 --set graph2=#00ff00\\n' +\n ' suntropy config theme set --from-file theme.json'\n )\n .option('--primary <hex>', 'Primary colour')\n .option('--btn-primary <hex>', 'Primary button colour')\n .option('--btn-secondary <hex>', 'Secondary button colour')\n .option('--background <hex>', 'Background colour')\n .option('--navbar-background-color <hex>', 'Navbar background colour')\n .option('--logo-url <url>', 'Logo URL')\n .option('--favicon-url <url>', 'Favicon URL')\n .option('--client-app-title <title>', 'Visible app title')\n .option('--enable-custom-theme [bool]', 'Toggle the custom theme (true/false)')\n .option('--set <entries...>', 'Additional field assignments as key=value (repeatable)')\n .option('--from-file <path>', 'Load a partial payload from a JSON file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(theme);\n const client = createServiceClient('security', global);\n\n const flagValues: Record<string, unknown> = {\n primary: opts.primary,\n btnPrimary: opts.btnPrimary,\n btnSecondary: opts.btnSecondary,\n background: opts.background,\n navbarBackgroundColor: opts.navbarBackgroundColor,\n logoUrl: opts.logoUrl,\n faviconUrl: opts.faviconUrl,\n clientAppTitle: opts.clientAppTitle,\n enableCustomTheme: opts.enableCustomTheme === undefined ? undefined : opts.enableCustomTheme === true || opts.enableCustomTheme === 'true',\n };\n\n const payload = buildPayload(flagValues, opts.set, opts.fromFile, THEME_KEYS);\n if (Object.keys(payload).length === 0) {\n outputError(new Error('No fields provided. Use flags, --set, or --from-file.'));\n return;\n }\n\n const res = await client.post('/clients/config/updateTheme', payload);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n theme\n .command('edit')\n .description('Open $EDITOR with the theme JSON and PUT the edited result.')\n .requiredOption('--client-uid <uid>', 'Client UID to fetch the current theme from')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(theme);\n const client = createServiceClient('security', global);\n const current = await client.get(`/clients/config/clientThemeByClientUID/${opts.clientUid}`);\n const subset = pickKeys(current.data as Record<string, unknown>, THEME_KEYS);\n const edited = editJson(subset, 'theme');\n const res = await client.post('/clients/config/updateTheme', edited);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import { Command } from 'commander';\nimport { AxiosInstance } from 'axios';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError } from '../../output.js';\nimport { getGlobalOpts, buildPayload, editJson, pickKeys, coerceValue } from './shared.js';\n\n/** camelCase → kebab-case (\"logoUrl\" → \"logo-url\"). */\nfunction kebab(key: string): string {\n return key.replace(/[A-Z0-9]+/g, (m, i) => (i === 0 ? m.toLowerCase() : '-' + m.toLowerCase()));\n}\n\n/** One category of the advanced panel. */\ninterface Section {\n name: string;\n title: string;\n summary: string;\n fields: readonly string[];\n fieldDocs: Record<string, string>;\n}\n\nconst GENERAL: Section = {\n name: 'general',\n title: 'General configuration (branding, language, tracking, base aesthetics).',\n summary:\n 'Applies to the entire widget: navbar, favicon, global theme, analytics/pixels\\n' +\n 'and page-wide injected scripts. Equivalent to the \"General Configuration\"\\n' +\n 'panel in the Suntropy admin.',\n fields: [\n 'logoUrl', 'faviconUrl', 'tabTitle',\n 'onAddressButtonClick', 'onSendButtonClick',\n 'googleConversionId', 'googleConversionLabelOnAddress', 'googleConversionLabelOnSend',\n 'metaConversionId', 'customTrackingHTML',\n 'defaultLanguage', 'enableLanguageMenu',\n 'customColorOfElements', 'steticVariant', 'themeColor', 'navbarColor',\n 'addNumberToSteps', 'showFooter',\n ],\n fieldDocs: {\n logoUrl: 'Logo displayed in the navbar (and on the cover if includeLogoInCover=true). Empty = no logo.',\n faviconUrl: 'Browser tab favicon.',\n tabTitle: 'Browser tab title (HTML <title>).',\n onAddressButtonClick: 'JavaScript evaluated (eval) when the user hits \"Continue\" on the address step. ⚠ XSS risk; never accept untrusted input.',\n onSendButtonClick: 'JavaScript evaluated (eval) when the final form is submitted. Same XSS risk as above.',\n googleConversionId: 'Google Ads ID; injects gtag.js in <head>.',\n googleConversionLabelOnAddress: 'Google conversion label fired after the address step.',\n googleConversionLabelOnSend: 'Google conversion label fired on submit.',\n metaConversionId: 'Meta/Facebook pixel ID; fires a \"Lead\" event on submit.',\n customTrackingHTML: 'Arbitrary HTML/JS injected in <head> (Hotjar, Mixpanel, GTM…).',\n defaultLanguage: 'Initial language: en|es|fr|it|pt|cat. Falls back to browser pref, then \"en\".',\n enableLanguageMenu: 'Shows the language picker in the navbar. false pins the user to defaultLanguage.',\n customColorOfElements: 'Accent colour for buttons / active borders.',\n steticVariant: 'Visual variant: default (rounded) | sharped (hard corners) | simple (minimalist, no shadows).',\n themeColor: 'Primary colour (navbar, buttons, focus ring). Default #575757.',\n navbarColor: 'Overrides themeColor for the navbar only.',\n addNumberToSteps: 'Prefix step names with their number (\"1. Address\", …).',\n showFooter: 'Pins the footer to the bottom instead of inlining it in the flow.',\n },\n};\n\nconst COVER: Section = {\n name: 'cover',\n title: 'Cover / hero screen shown before the address step.',\n summary: 'Configures the first screen the user sees: title, subtitle, carousel background, colours and logo placement.',\n fields: [\n 'coverTitle', 'coverSubtitle',\n 'coverBackgroundImageUrl1', 'coverBackgroundImageUrl2', 'coverBackgroundImageUrl3', 'coverBackgroundImageUrl4',\n 'staticCoverImages',\n 'coverTextColor', 'coverFilterColor',\n 'includeLogoInCover',\n ],\n fieldDocs: {\n coverTitle: 'Hero title.',\n coverSubtitle: 'Hero subtitle below the title.',\n coverBackgroundImageUrl1: 'Background image #1 (also first frame of the carousel).',\n coverBackgroundImageUrl2: 'Background image #2.',\n coverBackgroundImageUrl3: 'Background image #3.',\n coverBackgroundImageUrl4: 'Background image #4.',\n staticCoverImages: 'true = no rotation (always shows the first image). false = carousel auto-rotates.',\n coverTextColor: 'Colour applied to coverTitle and coverSubtitle.',\n coverFilterColor: 'Overlay colour on top of the image. Default rgba(75,55,30,0.7); improves text contrast.',\n includeLogoInCover: 'true repeats the navbar logo on the cover. false keeps it only in the navbar.',\n },\n};\n\nconst SURFACES: Section = {\n name: 'surfaces',\n title: 'Surfaces step: the map where the user draws the roof polygon(s).',\n summary: 'Controls whether the step runs, how many surfaces are allowed, and the per-device help messages.',\n fields: ['surfaceStepEnabled', 'multipleSurfaces', 'enableMapMarker', 'messageOnDesktopDevices', 'messageOnMobileDevices'],\n fieldDocs: {\n surfaceStepEnabled: 'Enables/disables the whole step. false = the lead is sized without any polygon input.',\n multipleSurfaces: 'Allows drawing more than one roof surface per lead.',\n enableMapMarker: 'Drops a pin on the installation location over the satellite view.',\n messageOnDesktopDevices: 'Instruction text shown on desktop during the step.',\n messageOnMobileDevices: 'Instruction text shown on mobile (e.g. \"Tap to draw\").',\n },\n};\n\nconst CONSUMER: Section = {\n name: 'consumer',\n title: 'Consumer step: residential / commercial / community picker.',\n summary: 'Each subtype has its own visibility flag, image and label. defaultConsumptionPattern feeds the calculation engine.',\n fields: [\n 'consumerStepEnabled',\n 'residentialConsumerTypeEnabled', 'residentialConsumerImageUrl', 'residentialConsumerTitle',\n 'commercialConsumerTypeEnabled', 'commercialConsumerImageUrl', 'commercialConsumerTitle',\n 'communityConsumerTypeEnabled', 'communityConsumerImageUrl', 'communityConsumerTitle',\n 'defaultConsumptionPattern',\n ],\n fieldDocs: {\n consumerStepEnabled: 'Shows/hides the whole step.',\n residentialConsumerTypeEnabled: 'Makes the \"Residential\" option visible.',\n residentialConsumerImageUrl: 'Icon/photo for the Residential option.',\n residentialConsumerTitle: 'Residential label (e.g. \"Home\").',\n commercialConsumerTypeEnabled: 'Makes the \"Commercial\" option visible.',\n commercialConsumerImageUrl: 'Icon/photo for the Commercial option.',\n commercialConsumerTitle: 'Commercial label (e.g. \"Business\").',\n communityConsumerTypeEnabled: 'Makes the \"Community\" option visible.',\n communityConsumerImageUrl: 'Icon/photo for the Community option.',\n communityConsumerTitle: 'Community label.',\n defaultConsumptionPattern: 'Preselected pattern: Balance | Nightly | Morning | Afternoon | Domestic | Commercial | Community. Feeds the hourly curve used by the engine.',\n },\n};\n\nconst INCLINATION: Section = {\n name: 'inclination',\n title: 'Roof inclination step (flat / inclined / very inclined).',\n summary: 'Each variant carries its own image and label. defaultInclination is also used when the step is disabled.',\n fields: [\n 'inclinationStepEnabled',\n 'flatRoofImageUrl', 'textFlatRoof',\n 'inclinedRoofImageUrl', 'textInclinedRoof',\n 'veryInclinedRoofImageUrl', 'textVeryInclinedRoof',\n 'defaultInclination', 'inclinationStepTitle',\n ],\n fieldDocs: {\n inclinationStepEnabled: 'Shows/hides the step. When false, defaultInclination is fed directly into the calculation.',\n flatRoofImageUrl: 'Image for the flat-roof option (0-15°).',\n textFlatRoof: 'Label for flat roof. Default \"0-15°\".',\n inclinedRoofImageUrl: 'Image for the inclined-roof option (15-30°).',\n textInclinedRoof: 'Label for inclined roof. Default \"15-30°\".',\n veryInclinedRoofImageUrl: 'Image for the very-inclined option (>30°).',\n textVeryInclinedRoof: 'Label for very inclined roof. Default \">30°\".',\n defaultInclination: 'Degrees (0-90). Preselected value and fallback when the step is disabled.',\n inclinationStepTitle: 'Title for the step.',\n },\n};\n\nconst ORIENTATION: Section = {\n name: 'orientation',\n title: 'Roof orientation (azimuth) step.',\n summary: 'Directly impacts yield estimates.',\n fields: ['orientationStepEnabled', 'defaultOrientation'],\n fieldDocs: {\n orientationStepEnabled: 'Shows/hides the step. When false, defaultOrientation is fed to the engine.',\n defaultOrientation: 'Degrees 0-360 (0=N, 90=E, 180=S, 270=W).',\n },\n};\n\nconst PANELS: Section = {\n name: 'panels',\n title: 'Solar panel & kit-category selection step.',\n summary: 'Drives which panel + kit category the lead is sized with.',\n fields: ['panelStepEnabled', 'defaultSolarPanel', 'kitCategories', 'defaultKitCategoryId', 'panelSectionTitle', 'panelTitle'],\n fieldDocs: {\n panelStepEnabled: 'Shows/hides the step. When false, the backend uses defaultSolarPanel + defaultKitCategoryId unattended.',\n defaultSolarPanel: 'ID of the preselected SolarPanel (reference to the client inventory).',\n kitCategories: 'Array of kit categories offered to the lead. Each item: { id, name, description, priority }. Use --from-file for multi-item payloads.',\n defaultKitCategoryId: 'ID of the preselected kit category.',\n panelSectionTitle: 'Navbar/breadcrumb label for the panel section.',\n panelTitle: 'Step title.',\n },\n};\n\nconst CONSUMPTION: Section = {\n name: 'consumption',\n title: 'Electric-consumption input step.',\n summary: 'Controls the input mode and display density of the consumption step.',\n fields: ['showOnlyOneConsumptionFieldAtATime', 'defaultConsumptionIntroductionMode'],\n fieldDocs: {\n showOnlyOneConsumptionFieldAtATime: 'true = guided mode (one field per screen). false = all fields visible at once.',\n defaultConsumptionIntroductionMode: 'monthlyConsumption (kWh/month) | monthlySpending (EUR/month). User can toggle if both are enabled.',\n },\n};\n\nconst RESULTS: Section = {\n name: 'results',\n title: 'Results screen, contact form and calculation-engine hooks.',\n summary: 'Largest section: visual layout, form fields for lead capture, confirmation modal, and engine toggles (batteries, PPA, alternative endpoint).',\n fields: [\n 'resultsMode', 'resultsBackgroundImageUrl', 'hideBackgroundImageInResults', 'colorOfBackgroundInResults',\n 'includeLogoInResults', 'includeMapInResults', 'hideResults', 'hideROI', 'formTitle', 'formSubtitle',\n 'resultsWhenSent', 'colorOfResultsPanelBackground',\n 'showDniFieldOnResults', 'showPhonePrefixFieldOnResults', 'showTypeOfDocumentFieldOnResults',\n 'showDniValidationFieldOnResults', 'showPhoneNumberValidationFieldOnResults',\n 'showIdentifierValidationFieldOnResults', 'showSurnameValidationFieldOnResults', 'showTypeOfClientSelectorOnResults',\n 'titleModalOfConfirm', 'textModalOfConfirm',\n 'businessName', 'enablePeakPowerLimitation', 'includeBatteries', 'enabledPPACalculation',\n 'hideCommentField', 'alternativeCalculationEndpoint', 'alternativeCalculationLoadingMessage', 'redirectToShareable',\n ],\n fieldDocs: {\n resultsMode: 'Default (ROI, payback, savings) | SolarResource (irradiance map + technical data).',\n resultsBackgroundImageUrl: 'Background image behind the results panel.',\n hideBackgroundImageInResults: 'Hides the background image even when set.',\n colorOfBackgroundInResults: 'Overlay colour on top of the background image. Default rgba(75,55,30,0.7).',\n colorOfResultsPanelBackground: 'Background of the metrics card. Default rgba(0,0,0,0.5).',\n includeLogoInResults: 'Shows the logo on the results screen.',\n includeMapInResults: 'Shows the interactive map with the drawn panels.',\n hideResults: 'true = no metrics shown, only the contact form.',\n hideROI: 'Hides the payback/ROI widget.',\n formTitle: 'Contact form title.',\n formSubtitle: 'Contact form subtitle.',\n resultsWhenSent: 'true = results shown before submit. false = form must be filled first.',\n showDniFieldOnResults: 'Adds a DNI/CIF input to the form.',\n showPhonePrefixFieldOnResults: 'Adds a phone-prefix selector.',\n showTypeOfDocumentFieldOnResults: 'Adds a document-type selector.',\n showDniValidationFieldOnResults: 'Visual DNI validation (green check).',\n showPhoneNumberValidationFieldOnResults: 'Visual phone validation.',\n showIdentifierValidationFieldOnResults: 'Visual identifier validation.',\n showSurnameValidationFieldOnResults: 'Visual surname validation.',\n showTypeOfClientSelectorOnResults: 'Selector for Individual / Company / Community.',\n titleModalOfConfirm: 'Title of the confirmation modal shown before submit.',\n textModalOfConfirm: 'Body of the confirmation modal.',\n businessName: 'Adds a \"Business name\" field to the form.',\n enablePeakPowerLimitation: 'Adds a peak-power limiter to the consumption section. Affects engine sizing.',\n includeBatteries: 'Includes battery sizing in the results.',\n enabledPPACalculation: 'Enables PPA (Power Purchase Agreement) modelling.',\n hideCommentField: 'Hides the free-text comment field.',\n alternativeCalculationEndpoint: 'URL to which calculation data is POSTed instead of the default engine endpoint. For white-label integrations.',\n alternativeCalculationLoadingMessage: 'Loading text while awaiting the alternative endpoint response.',\n redirectToShareable: 'After calculation, redirect to the shareable-study URL instead of rendering results in-place.',\n },\n};\n\nconst CUSTOM_FIELDS: Section = {\n name: 'custom-fields',\n title: 'Extra lead fields persisted on the SolarStudy (plugin-gated).',\n summary: 'Only available when the client has the \"studyCustomFields\" plugin active.',\n fields: ['solarStudyCustomFields'],\n fieldDocs: {\n solarStudyCustomFields: 'Array of custom-field definitions, serialised. Each item: { id, label, type, required, options? }. Types: text|number|select|boolean. Use --from-file to avoid quoting headaches.',\n },\n};\n\nconst SECTIONS: readonly Section[] = [\n GENERAL, COVER, SURFACES, CONSUMER, INCLINATION, ORIENTATION, PANELS, CONSUMPTION, RESULTS, CUSTOM_FIELDS,\n];\n\nfunction getAdvanced(client: AxiosInstance): Promise<Record<string, unknown>> {\n return client.get('/solar-form/config/advanced').then((r) => r.data as Record<string, unknown>);\n}\n\nfunction putAdvanced(client: AxiosInstance, payload: Record<string, unknown>): Promise<unknown> {\n return client.put('/solar-form/config/advanced', payload).then((r) => r.data);\n}\n\n/** Build a \"Fields:\" help block for a section. */\nfunction formatFieldsHelp(section: Section): string {\n const longest = Math.max(...section.fields.map((f) => f.length));\n return [\n section.title,\n '',\n section.summary,\n '',\n 'Fields:',\n ...section.fields.map((f) => ` ${f.padEnd(longest)} ${section.fieldDocs[f] ?? ''}`),\n '',\n 'Operations: get | set [--set key=value] [--from-file] [--<field> <value>] | edit',\n ].join('\\n');\n}\n\nfunction attachSectionCommand(advanced: Command, section: Section): void {\n const sec = advanced\n .command(section.name)\n .description(formatFieldsHelp(section));\n\n sec\n .command('get')\n .description(`Fetch only the ${section.name} fields of the advanced config.`)\n .action(async () => {\n try {\n const global = getGlobalOpts(sec);\n const client = createServiceClient('solar', global);\n const doc = await getAdvanced(client);\n output(pickKeys(doc, section.fields), global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n const setCmd = sec\n .command('set')\n .description(\n `Update the ${section.name} fields of the advanced config.\\n` +\n 'Combine per-field flags, repeatable --set key=value, and/or --from-file.\\n' +\n 'Internally GETs the current config, merges this section, and PUTs the whole thing.'\n )\n .option('--set <entries...>', 'Field assignments as key=value (repeatable)')\n .option('--from-file <path>', 'Load a partial payload from a JSON file');\n\n for (const field of section.fields) {\n setCmd.option(`--${kebab(field)} <value>`, section.fieldDocs[field] ?? field);\n }\n\n setCmd.action(async (opts) => {\n try {\n const global = getGlobalOpts(sec);\n const client = createServiceClient('solar', global);\n\n const flagValues: Record<string, unknown> = {};\n for (const field of section.fields) {\n const val = opts[field];\n if (val !== undefined) flagValues[field] = coerceValue(String(val));\n }\n const partial = buildPayload(flagValues, opts.set, opts.fromFile, section.fields);\n if (Object.keys(partial).length === 0) {\n outputError(new Error('No fields provided. Use flags, --set, or --from-file.'));\n return;\n }\n\n const current = await getAdvanced(client);\n const merged = { ...current, ...partial };\n const res = await putAdvanced(client, merged);\n output(pickKeys(res as Record<string, unknown>, section.fields), global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n sec\n .command('edit')\n .description(`Open $EDITOR on the ${section.name} subset of the advanced config, then PUT the whole config.`)\n .action(async () => {\n try {\n const global = getGlobalOpts(sec);\n const client = createServiceClient('solar', global);\n const current = await getAdvanced(client);\n const subset = pickKeys(current, section.fields);\n const edited = editJson(subset, `advanced-${section.name}`);\n const merged = { ...current, ...edited };\n const res = await putAdvanced(client, merged);\n output(pickKeys(res as Record<string, unknown>, section.fields), global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n\nexport function registerAdvancedCommands(solarform: Command): void {\n const advanced = solarform\n .command('advanced')\n .description(\n 'SolarForm Advanced configuration (white-label microsite).\\n' +\n 'Each subcommand maps 1:1 with a section of the admin accordion and with a\\n' +\n 'subset of fields in the AdvancedSolarFormConfig DTO.\\n\\n' +\n 'Whole-payload operations:\\n' +\n ' get Fetch the full advanced config.\\n' +\n ' update Merge a partial payload (--set / --from-file).\\n' +\n ' delete Delete the authenticated client\\'s advanced config.\\n' +\n ' init-default Create the default config for a clientUID (superadmin / localhost).\\n\\n' +\n 'Sections (each: get / set / edit):\\n' +\n SECTIONS.map((s) => ` ${s.name.padEnd(14)} ${s.title}`).join('\\n') + '\\n\\n' +\n 'Conventions:\\n' +\n ' --set <field>=<value> Assign a single field (repeatable).\\n' +\n ' --from-file <path> Load a partial payload from JSON.\\n' +\n ' edit Open $EDITOR on the section\\'s current state.'\n );\n\n advanced\n .command('get')\n .description('Fetch the full AdvancedSolarFormConfig for the authenticated client.')\n .action(async () => {\n try {\n const global = getGlobalOpts(advanced);\n const client = createServiceClient('solar', global);\n const data = await getAdvanced(client);\n output(data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n advanced\n .command('update')\n .description('Merge a partial AdvancedSolarFormConfig from --set / --from-file and PUT.')\n .option('--set <entries...>', 'Field assignments as key=value (repeatable)')\n .option('--from-file <path>', 'Load a partial payload from a JSON file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(advanced);\n const client = createServiceClient('solar', global);\n const partial = buildPayload({}, opts.set, opts.fromFile);\n if (Object.keys(partial).length === 0) {\n outputError(new Error('No fields provided. Use --set or --from-file.'));\n return;\n }\n const current = await getAdvanced(client);\n const res = await putAdvanced(client, { ...current, ...partial });\n output(res, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n advanced\n .command('delete')\n .description('Delete the authenticated client\\'s advanced config.')\n .action(async () => {\n try {\n const global = getGlobalOpts(advanced);\n const client = createServiceClient('solar', global);\n const res = await client.delete('/solar-form/config/advanced');\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n advanced\n .command('init-default')\n .description(\n 'Create the default advanced config for a clientUID.\\n' +\n 'Restricted: requires the \"suntropy-auth: <clientUID>\" header or localhost execution.'\n )\n .requiredOption('--client-uid <uid>', 'Client UID to initialise')\n .option('--email <email>', 'Operator email (optional)')\n .option('--url <url>', 'Site URL (optional)')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(advanced);\n const client = createServiceClient('solar', global);\n const params: Record<string, string> = {};\n if (opts.email) params.email = opts.email;\n if (opts.url) params.url = opts.url;\n const res = await client.post(\n `/solar-form/config/default/advanced/${opts.clientUid}`,\n {},\n { params, headers: { 'suntropy-auth': opts.clientUid } },\n );\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n for (const section of SECTIONS) attachSectionCommand(advanced, section);\n}\n","import { Command } from 'commander';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError } from '../../output.js';\nimport { getGlobalOpts, buildPayload, editJson, pickKeys } from './shared.js';\nimport { registerAdvancedCommands } from './advanced.js';\n\n/** Fields accepted on SolarFormConfig (solar backend). */\nconst SOLARFORM_KEYS = [\n 'idSolarFormConfig',\n 'clientUID',\n 'solarFormUrl',\n 'enabled',\n 'notificationEmailAddress',\n 'confirmationReplytoEmailAdress',\n 'notificationEmailSubject',\n 'enableNotificationEmail',\n 'enableSendConfirmationEmailToClient',\n 'confirmationEmailSubject',\n 'confirmationEmailBody',\n 'enableConfirmationEmailBody',\n 'formTitle',\n 'formSubtitle',\n 'formBackgroundColor',\n 'formBackgroundImageURL',\n 'formFaviconUrl',\n 'locationMode',\n 'hideFinalProjectPrice',\n 'enableRequiredPhoneNumberField',\n 'enableRequiredNameField',\n 'callToActionButtonText',\n 'renderPDF',\n 'defaultSolarStudyTemplateId',\n 'redirectUrl',\n 'privacyPolicy',\n 'advertisingPolicy',\n 'generateShareable',\n 'incentiveTemplateGroup',\n 'disabledSolarForm',\n 'redirectOnClose',\n] as const;\n\nexport function registerSolarformConfigCommands(configRoot: Command): void {\n const solarform = configRoot\n .command('solarform')\n .description(\n 'SolarForm (basic) and SolarForm Advanced configuration (solar service).\\n' +\n 'The basic config controls the public lead-capture form (URL, notifications,\\n' +\n 'appearance, mandatory fields). The advanced subtree configures the modern\\n' +\n 'white-label widget rendered by the \"advanced-solar-form\" microsite.\\n\\n' +\n 'Endpoints:\\n' +\n ' GET /solar-form/get-solar-form-config?getParameters=\\n' +\n ' GET /solar-form/solar-form-config (public, resolved by Origin)\\n' +\n ' POST /solar-form/solar-form-config?getParameters=\\n' +\n ' PUT /solar-form/solar-form-config/:id'\n );\n\n solarform\n .command('get')\n .description('Fetch the current SolarForm configuration for the authenticated client.')\n .option('--with-parameters', 'Include the associated SolarFormParameters in the response')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(solarform);\n const client = createServiceClient('solar', global);\n const params: Record<string, string> = {};\n if (opts.withParameters) params.getParameters = 'true';\n const res = await client.get('/solar-form/get-solar-form-config', { params });\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n solarform\n .command('create')\n .description(\n 'Create a new SolarFormConfig for the authenticated client.\\n' +\n '--url is the public slug/URL of the form. Other fields may come from flags,\\n' +\n '--set key=value, or --from-file. Accepted keys:\\n' +\n ' ' + SOLARFORM_KEYS.join(', ')\n )\n .requiredOption('--url <slug>', 'Public URL/slug of the form (solarFormUrl)')\n .option('--enabled [bool]', 'Whether the form is publicly enabled', 'true')\n .option('--form-title <text>', 'Form title displayed to the end user')\n .option('--form-subtitle <text>', 'Form subtitle')\n .option('--form-background-color <color>', 'Background colour of the form container')\n .option('--form-background-image-url <url>', 'Background image URL')\n .option('--form-favicon-url <url>', 'Favicon URL')\n .option('--call-to-action-button-text <text>', 'Primary CTA button label')\n .option('--notification-email-address <email>', 'Where new lead notifications go')\n .option('--location-mode <mode>', 'fullSurface | locationOnly')\n .option('--with-parameters', 'Include SolarFormParameters in the response')\n .option('--set <entries...>', 'Additional field assignments as key=value (repeatable)')\n .option('--from-file <path>', 'Load a payload from a JSON file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(solarform);\n const client = createServiceClient('solar', global);\n\n const flagValues: Record<string, unknown> = {\n solarFormUrl: opts.url,\n enabled: opts.enabled === undefined ? undefined : opts.enabled === true || opts.enabled === 'true',\n formTitle: opts.formTitle,\n formSubtitle: opts.formSubtitle,\n formBackgroundColor: opts.formBackgroundColor,\n formBackgroundImageURL: opts.formBackgroundImageUrl,\n formFaviconUrl: opts.formFaviconUrl,\n callToActionButtonText: opts.callToActionButtonText,\n notificationEmailAddress: opts.notificationEmailAddress,\n locationMode: opts.locationMode,\n };\n const payload = buildPayload(flagValues, opts.set, opts.fromFile, SOLARFORM_KEYS);\n\n const params: Record<string, string> = {};\n if (opts.withParameters) params.getParameters = 'true';\n const res = await client.post('/solar-form/solar-form-config', payload, { params });\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n solarform\n .command('update <idSolarFormConfig>')\n .description('Update an existing SolarFormConfig by numeric ID.')\n .option('--set <entries...>', 'Additional field assignments as key=value (repeatable)')\n .option('--from-file <path>', 'Load a payload from a JSON file')\n .option('--form-title <text>', 'Form title')\n .option('--form-subtitle <text>', 'Form subtitle')\n .option('--enabled [bool]', 'Whether the form is publicly enabled')\n .option('--disabled-solar-form [bool]', 'Explicit disable flag')\n .action(async (idSolarFormConfig, opts) => {\n try {\n const global = getGlobalOpts(solarform);\n const client = createServiceClient('solar', global);\n\n const flagValues: Record<string, unknown> = {\n formTitle: opts.formTitle,\n formSubtitle: opts.formSubtitle,\n enabled: opts.enabled === undefined ? undefined : opts.enabled === true || opts.enabled === 'true',\n disabledSolarForm: opts.disabledSolarForm === undefined ? undefined : opts.disabledSolarForm === true || opts.disabledSolarForm === 'true',\n };\n const payload = buildPayload(flagValues, opts.set, opts.fromFile, SOLARFORM_KEYS);\n if (Object.keys(payload).length === 0) {\n outputError(new Error('No fields to update.'));\n return;\n }\n\n const res = await client.put(`/solar-form/solar-form-config/${idSolarFormConfig}`, payload);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n solarform\n .command('edit')\n .description('Fetch the current SolarForm config, open $EDITOR, and PUT the edited result.')\n .action(async () => {\n try {\n const global = getGlobalOpts(solarform);\n const client = createServiceClient('solar', global);\n const current = await client.get('/solar-form/get-solar-form-config');\n const doc = current.data as Record<string, unknown>;\n const id = doc?.idSolarFormConfig;\n if (!id) {\n outputError(new Error('No existing SolarFormConfig found to edit. Use \"create\" first.'));\n return;\n }\n const subset = pickKeys(doc, SOLARFORM_KEYS);\n const edited = editJson(subset, 'solarform');\n const res = await client.put(`/solar-form/solar-form-config/${id}`, edited);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n registerAdvancedCommands(solarform);\n}\n","import { Command } from 'commander';\nimport { loadConfig, saveConfig, setConfigValue, getConfigValue } from '../config.js';\nimport { output, outputError } from '../output.js';\nimport { registerThemeCommands } from './config/theme.js';\nimport { registerSolarformConfigCommands } from './config/solarform.js';\n\nexport function registerConfigCommands(program: Command): void {\n const cfg = program\n .command('config')\n .description(\n 'CLI configuration (profiles, server, token) plus tenant configuration\\n' +\n '(theme & SolarForm / SolarForm Advanced) served by the security and solar backends.'\n );\n\n cfg\n .command('set <key> <value>')\n .description('Set a configuration value. Keys: server, token, activeProfile')\n .option('--profile <name>', 'Profile to modify')\n .action((key, value, opts) => {\n try {\n if (key === 'activeProfile') {\n const config = loadConfig();\n config.activeProfile = value;\n saveConfig(config);\n } else {\n setConfigValue(key, value, opts.profile);\n }\n output({ success: true, key, value });\n } catch (err) {\n outputError(err);\n }\n });\n\n cfg\n .command('get <key>')\n .description('Get a configuration value')\n .option('--profile <name>', 'Profile to read from')\n .action((key, opts) => {\n try {\n if (key === 'activeProfile') {\n const config = loadConfig();\n output({ activeProfile: config.activeProfile });\n } else {\n output({ [key]: getConfigValue(key, opts.profile) });\n }\n } catch (err) {\n outputError(err);\n }\n });\n\n cfg\n .command('list')\n .description('Show all configuration')\n .action(() => {\n try {\n const config = loadConfig();\n // Redact tokens for display\n const safe = JSON.parse(JSON.stringify(config));\n for (const [name, profile] of Object.entries(safe.profiles)) {\n const p = profile as Record<string, unknown>;\n if (p.token) p.token = (p.token as string).slice(0, 20) + '...';\n }\n output(safe);\n } catch (err) {\n outputError(err);\n }\n });\n\n cfg\n .command('create-profile <name>')\n .description('Create a new profile')\n .option('--server <url>', 'API server URL', 'https://api.enerlence.com')\n .action((name, opts) => {\n try {\n const config = loadConfig();\n if (config.profiles[name]) {\n outputError(new Error(`Profile \"${name}\" already exists`));\n return;\n }\n config.profiles[name] = { server: opts.server };\n saveConfig(config);\n output({ success: true, profile: name, server: opts.server });\n } catch (err) {\n outputError(err);\n }\n });\n\n cfg\n .command('use <name>')\n .description('Switch to a profile')\n .action((name) => {\n try {\n const config = loadConfig();\n if (!config.profiles[name]) {\n outputError(new Error(`Profile \"${name}\" not found. Available: ${Object.keys(config.profiles).join(', ')}`));\n return;\n }\n config.activeProfile = name;\n saveConfig(config);\n output({ success: true, activeProfile: name });\n } catch (err) {\n outputError(err);\n }\n });\n\n registerThemeCommands(cfg);\n registerSolarformConfigCommands(cfg);\n}\n","import { Command } from 'commander';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, outputPaginated, type OutputOptions } from '../../output.js';\n\nexport interface ResourceConfig {\n /** Command name (e.g. 'panels') */\n name: string;\n /** Singular display name (e.g. 'solar panel') */\n singular: string;\n /** API base path (e.g. '/solar-panels') */\n basePath: string;\n /** ID field name in the entity (e.g. 'solarPanelId') */\n idField: string;\n /** Fields to show in list view (summary) */\n listFields: string[];\n /** POST path for advanced filter, if different from basePath + '/filter' */\n filterPath?: string;\n /** Batch delete path suffix */\n batchDeletePath?: string;\n /** PUT uses body without ID in URL (some endpoints use PUT / with body containing id) */\n putBodyOnly?: boolean;\n /** Backend service */\n service?: 'solar' | 'templates' | 'security';\n /** Custom GET path pattern. Use ':id' as placeholder (e.g. '/custom-asset/id/:id') */\n getPath?: string;\n /** Use POST filter to get by ID (when no GET :id endpoint exists) */\n getViaFilter?: boolean;\n}\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & { server?: string; token?: string; profile?: string; verbose?: boolean } {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\nfunction parseData(data: string | undefined): Record<string, unknown> | undefined {\n if (!data) return undefined;\n if (data === '-') {\n // Read from stdin - synchronous for simplicity\n const { readFileSync } = require('fs');\n const input = readFileSync(0, 'utf-8');\n return JSON.parse(input);\n }\n return JSON.parse(data);\n}\n\nexport function createResourceCommands(cfg: ResourceConfig): Command {\n const cmd = new Command(cfg.name).description(`Manage ${cfg.singular}s`);\n const service = cfg.service || 'solar';\n\n // --- list ---\n cmd\n .command('list')\n .description(`List ${cfg.singular}s with pagination. Fields: ${cfg.listFields.join(', ')}`)\n .option('--limit <n>', 'Max results', '20')\n .option('--offset <n>', 'Skip results', '0')\n .option('--active-only', 'Only active items (exclude inactive)')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(cmd);\n const client = createServiceClient(service, global);\n const params: Record<string, unknown> = {\n limit: parseInt(opts.limit),\n offset: parseInt(opts.offset),\n };\n if (!opts.activeOnly) params.unactive = true;\n\n const res = await client.get(cfg.basePath, { params });\n // API may return: [items[], totalCount] tuple, {data: [], total} object, or plain array\n let data: unknown[];\n let total: number;\n if (Array.isArray(res.data) && res.data.length >= 2 && Array.isArray(res.data[0]) && typeof res.data[1] === 'number') {\n // Tuple format: [items[], totalCount]\n data = res.data[0];\n total = res.data[1];\n } else if (Array.isArray(res.data)) {\n data = res.data;\n total = res.data.length;\n } else {\n data = res.data?.data || [];\n total = res.data?.total ?? data.length;\n }\n\n // Apply list field summary unless user specified --fields\n const outOpts: OutputOptions = { ...global };\n if (!global.fields && cfg.listFields.length > 0) {\n outOpts.fields = [cfg.idField, ...cfg.listFields].join(',');\n }\n\n if (Array.isArray(data)) {\n outputPaginated(data, total, parseInt(opts.limit), parseInt(opts.offset), outOpts);\n } else {\n output(data, outOpts);\n }\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- get ---\n cmd\n .command('get <id>')\n .description(`Get a ${cfg.singular} by ID. All fields returned by default.`)\n .action(async (id) => {\n try {\n const global = getGlobalOpts(cmd);\n const client = createServiceClient(service, global);\n if (cfg.getViaFilter) {\n // No GET :id endpoint — fetch all and filter client-side\n const res = await client.get(cfg.basePath, { params: { unactive: true } });\n const all = Array.isArray(res.data) ? res.data : (Array.isArray(res.data?.[0]) ? res.data[0] : res.data?.data || []);\n const idNum = parseInt(id);\n const item = all.find((r: Record<string, unknown>) => r[cfg.idField] === idNum || r[cfg.idField] === id);\n if (!item) { outputError(new Error(`${cfg.singular} with ${cfg.idField}=${id} not found`)); return; }\n output(item, global);\n } else {\n const url = cfg.getPath ? cfg.getPath.replace(':id', id) : `${cfg.basePath}/${id}`;\n const res = await client.get(url);\n output(res.data, global);\n }\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- create ---\n cmd\n .command('create')\n .description(`Create a new ${cfg.singular}. Pass JSON via --data or stdin (--data -)`)\n .requiredOption('--data <json>', 'JSON data (or - for stdin)')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(cmd);\n const client = createServiceClient(service, global);\n const body = parseData(opts.data);\n const res = await client.post(cfg.basePath, body);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- update ---\n cmd\n .command('update <id>')\n .description(`Update a ${cfg.singular}`)\n .requiredOption('--data <json>', 'JSON data with fields to update (or - for stdin)')\n .action(async (id, opts) => {\n try {\n const global = getGlobalOpts(cmd);\n const client = createServiceClient(service, global);\n const body = parseData(opts.data);\n if (cfg.putBodyOnly) {\n const res = await client.put(cfg.basePath, { ...body, [cfg.idField]: id });\n output(res.data, global);\n } else {\n const res = await client.put(`${cfg.basePath}/${id}`, body);\n output(res.data, global);\n }\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- delete ---\n cmd\n .command('delete <id>')\n .description(`Delete a ${cfg.singular}`)\n .action(async (id) => {\n try {\n const global = getGlobalOpts(cmd);\n const client = createServiceClient(service, global);\n const res = await client.delete(`${cfg.basePath}/${id}`);\n output(res.data ?? { success: true, deleted: id }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- delete-batch ---\n if (cfg.batchDeletePath) {\n cmd\n .command('delete-batch')\n .description(`Batch delete ${cfg.singular}s`)\n .requiredOption('--ids <ids>', 'Comma-separated IDs')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(cmd);\n const client = createServiceClient(service, global);\n const ids = opts.ids.split(',').map((s: string) => s.trim());\n const res = await client.post(`${cfg.basePath}/${cfg.batchDeletePath}`, ids);\n output(res.data ?? { success: true, deleted: ids.length }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n }\n\n // --- filter ---\n cmd\n .command('filter')\n .description(`Advanced filter for ${cfg.singular}s. Pass filter query as JSON.`)\n .requiredOption('--query <json>', 'Filter query JSON (or - for stdin)')\n .option('--limit <n>', 'Max results', '20')\n .option('--offset <n>', 'Skip results', '0')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(cmd);\n const client = createServiceClient(service, global);\n const query = parseData(opts.query);\n const filterUrl = cfg.filterPath || `${cfg.basePath}/filter`;\n const res = await client.post(filterUrl, {\n ...query,\n limit: parseInt(opts.limit),\n offset: parseInt(opts.offset),\n });\n const data = Array.isArray(res.data) ? res.data : res.data?.data || res.data;\n const total = res.data?.total ?? (Array.isArray(data) ? data.length : 0);\n outputPaginated(data, total, parseInt(opts.limit), parseInt(opts.offset), global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { createResourceCommands } from './factory.js';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\nfunction parseData(data: string): Record<string, unknown> {\n if (data === '-') {\n const { readFileSync } = require('fs');\n return JSON.parse(readFileSync(0, 'utf-8'));\n }\n return JSON.parse(data);\n}\n\nexport function registerKitsCommands(inventory: Command): void {\n // Base kit CRUD via factory\n const kits = createResourceCommands({\n name: 'kits',\n singular: 'solar kit',\n basePath: '/solar-kits',\n idField: 'idSolarKit',\n listFields: ['identifier', 'peakPower', 'panelNumber', 'inverterNumber', 'price', 'totalPrice', 'phaseNumber', 'active'],\n filterPath: '/solar-kits/filters',\n batchDeletePath: 'delete-batch-solar-kits',\n getViaFilter: true,\n });\n\n // Remove factory-generated 'create' — use 'assemble' instead for safe kit creation\n const kitsCreateIdx = kits.commands.findIndex((c: Command) => c.name() === 'create');\n if (kitsCreateIdx !== -1) kits.commands.splice(kitsCreateIdx, 1);\n\n // --- archive ---\n kits\n .command('archive <kitId>')\n .description('Archive a solar kit (soft-disable)')\n .action(async (kitId) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.put(`/solar-kits/archive/${kitId}`);\n output(res.data ?? { success: true, archived: kitId }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- Kit panels sub-commands ---\n const kitPanels = kits.command('panels').description('Manage kit solar panels');\n\n kitPanels\n .command('list')\n .description('List all kit solar panels. Fields: idKitSolarPanel, name, manufacturer, peakPower, efficiency, costPerUnit')\n .option('--limit <n>', 'Max results', '50')\n .option('--offset <n>', 'Skip results', '0')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.get('/solar-kits/solar-panels', { params: { limit: opts.limit, offset: opts.offset } });\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitPanels\n .command('get <id>')\n .description('Get a kit solar panel by ID')\n .action(async (id) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n // Use filter to get by ID since there's no direct GET by ID\n const res = await client.post('/solar-kits/solar-panels/filter', { idKitSolarPanel: id });\n const data = Array.isArray(res.data) ? res.data[0] : res.data?.data?.[0] || res.data;\n output(data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitPanels\n .command('create')\n .description('Create a kit solar panel')\n .requiredOption('--data <json>', 'JSON data')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.post('/solar-kits/solar-panels', parseData(opts.data));\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitPanels\n .command('update <id>')\n .description('Update a kit solar panel')\n .requiredOption('--data <json>', 'JSON data')\n .action(async (id, opts) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.put(`/solar-kits/solar-panels/${id}`, parseData(opts.data));\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitPanels\n .command('delete <id>')\n .description('Delete a kit solar panel')\n .action(async (id) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.delete(`/solar-kits/solar-panels/${id}`);\n output(res.data ?? { success: true, deleted: id }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitPanels\n .command('featured <kitPanelId>')\n .description('List solar kits that feature this kit panel')\n .action(async (kitPanelId) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.get(`/solar-kits/solar-panels/findFeaturedSolarKits/${kitPanelId}`);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- Kit inverters sub-commands ---\n const kitInverters = kits.command('inverters').description('Manage kit inverters');\n\n kitInverters\n .command('list')\n .description('List all kit inverters. Fields: idKitInverter, name, manufacturer, nominalPower, efficiency, costPerUnit')\n .option('--limit <n>', 'Max results', '50')\n .option('--offset <n>', 'Skip results', '0')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.get('/solar-kits/inverters', { params: { limit: opts.limit, offset: opts.offset } });\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitInverters\n .command('create')\n .description('Create a kit inverter')\n .requiredOption('--data <json>', 'JSON data')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.post('/solar-kits/inverters', parseData(opts.data));\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitInverters\n .command('update <id>')\n .description('Update a kit inverter')\n .requiredOption('--data <json>', 'JSON data')\n .action(async (id, opts) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.put(`/solar-kits/inverters/${id}`, parseData(opts.data));\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitInverters\n .command('delete <id>')\n .description('Delete a kit inverter')\n .action(async (id) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.delete(`/solar-kits/inverters/${id}`);\n output(res.data ?? { success: true, deleted: id }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitInverters\n .command('featured <kitInverterId>')\n .description('List solar kits that feature this kit inverter')\n .action(async (kitInverterId) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.get(`/solar-kits/inverters/findFeaturedSolarKits/${kitInverterId}`);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- Kit batteries sub-commands ---\n const kitBatteries = kits.command('batteries').description('Manage kit batteries');\n\n kitBatteries\n .command('list')\n .description('List all kit batteries. Fields: idKitBattery, name, manufacturer, capacity, costPerUnit')\n .option('--limit <n>', 'Max results', '50')\n .option('--offset <n>', 'Skip results', '0')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.get('/solar-kits/batteries', { params: { limit: opts.limit, offset: opts.offset } });\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitBatteries\n .command('create')\n .description('Create a kit battery')\n .requiredOption('--data <json>', 'JSON data')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.post('/solar-kits/batteries', parseData(opts.data));\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitBatteries\n .command('delete <id>')\n .description('Delete a kit battery')\n .action(async (id) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.delete(`/solar-kits/batteries/${id}`);\n output(res.data ?? { success: true, deleted: id }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- assemble: create kit from existing components by ID ---\n kits\n .command('assemble')\n .description(\n 'Assemble a solar kit from existing components by ID.\\n' +\n 'References kit panels, inverters, batteries, and custom assets by their IDs.\\n\\n' +\n 'Custom assets format: --custom-asset <assetId>:<units> (repeatable)\\n\\n' +\n 'Examples:\\n' +\n ' suntropy inventory kits assemble --name \"Kit 5kW\" --panel 123 --inverter 456 --panels-count 12 --price 6500\\n' +\n ' suntropy inventory kits assemble --name \"Kit Premium\" --panel 123 --inverter 456 --battery 789 \\\\\\n' +\n ' --panels-count 12 --inverters-count 1 --batteries-count 1 --peak-power 5.4 --price 8500 \\\\\\n' +\n ' --custom-asset 100:12 --custom-asset 200:1 --phase single_phase'\n )\n .requiredOption('--name <identifier>', 'Kit name/identifier')\n .option('--panel <kitPanelId>', 'Kit panel ID (idKitSolarPanel)')\n .option('--inverter <kitInverterId>', 'Kit inverter ID (idKitInverter)')\n .option('--battery <batteryId>', 'Battery ID from inventory (batteryId)')\n .option('--panels-count <n>', 'Number of panels', '12')\n .option('--inverters-count <n>', 'Number of inverters', '1')\n .option('--batteries-count <n>', 'Number of batteries', '0')\n .option('--peak-power <kW>', 'Total peak power in kW')\n .requiredOption('--price <eur>', 'Kit price in EUR (required)')\n .option('--phase <type>', 'Phase: single_phase or three_phase', 'single_phase')\n .option('--coplanar', 'Coplanar mounting')\n .option('--taxes <pct>', 'Default tax percentage', '21')\n .option('--custom-asset <id:units>', 'Custom asset as id:units (repeatable)', collectCustomAssets, [])\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n\n // Validate component IDs exist as kit entities before assembling\n const validationErrors: string[] = [];\n\n if (opts.panel) {\n try {\n const res = await client.post('/solar-kits/solar-panels/filter', { idKitSolarPanel: parseInt(opts.panel) });\n const data = Array.isArray(res.data) ? res.data : res.data?.data || [];\n if (data.length === 0) {\n validationErrors.push(\n `Panel ID ${opts.panel} is not a KitSolarPanel. ` +\n `Use \"suntropy inventory kits panels list\" to see available kit panels, ` +\n `or \"suntropy inventory kits panels create --data '{...}'\" to create one first.`\n );\n }\n } catch {\n validationErrors.push(\n `Could not validate panel ID ${opts.panel}. ` +\n `Make sure it is a KitSolarPanel ID (not a regular inventory panel). ` +\n `Use \"suntropy inventory kits panels list\" to see available kit panels.`\n );\n }\n }\n\n if (opts.inverter) {\n try {\n const res = await client.get('/solar-kits/inverters', { params: { limit: 200 } });\n const inverters = Array.isArray(res.data) ? res.data : res.data?.data || [];\n const found = inverters.find((inv: Record<string, unknown>) =>\n String(inv.idKitInverter) === String(opts.inverter)\n );\n if (!found) {\n validationErrors.push(\n `Inverter ID ${opts.inverter} is not a KitInverter. ` +\n `Use \"suntropy inventory kits inverters list\" to see available kit inverters, ` +\n `or \"suntropy inventory kits inverters create --data '{...}'\" to create one first.`\n );\n }\n } catch {\n validationErrors.push(\n `Could not validate inverter ID ${opts.inverter}. ` +\n `Make sure it is a KitInverter ID (not a regular inventory inverter). ` +\n `Use \"suntropy inventory kits inverters list\" to see available kit inverters.`\n );\n }\n }\n\n if (opts.battery) {\n try {\n const res = await client.get('/solar-kits/batteries', { params: { limit: 200 } });\n const batteries = Array.isArray(res.data) ? res.data : res.data?.data || [];\n const found = batteries.find((bat: Record<string, unknown>) =>\n String(bat.idKitBattery) === String(opts.battery)\n );\n if (!found) {\n validationErrors.push(\n `Battery ID ${opts.battery} is not a KitBattery. ` +\n `Use \"suntropy inventory kits batteries list\" to see available kit batteries, ` +\n `or \"suntropy inventory kits batteries create --data '{...}'\" to create one first.`\n );\n }\n } catch {\n validationErrors.push(\n `Could not validate battery ID ${opts.battery}. ` +\n `Make sure it is a KitBattery ID (not a regular inventory battery). ` +\n `Use \"suntropy inventory kits batteries list\" to see available kit batteries.`\n );\n }\n }\n\n if (validationErrors.length > 0) {\n outputError({\n error: true,\n message: 'Kit assembly validation failed',\n issues: validationErrors,\n hint: 'The assemble command requires KitSolarPanel, KitInverter, and KitBattery IDs — these are kit-specific entities, not regular inventory items.',\n });\n return;\n }\n\n const body: Record<string, unknown> = {\n identifier: opts.name,\n panelNumber: parseInt(opts.panelsCount),\n inverterNumber: parseInt(opts.invertersCount),\n batteriesNumber: parseInt(opts.batteriesCount),\n phaseNumber: opts.phase,\n defaultTaxesPercentage: parseFloat(opts.taxes),\n active: true,\n };\n\n if (opts.panel) body.kitSolarPanel = { idKitSolarPanel: parseInt(opts.panel) };\n if (opts.inverter) body.kitInverter = { idKitInverter: parseInt(opts.inverter) };\n if (opts.battery) body.battery = { batteryId: parseInt(opts.battery) };\n if (opts.peakPower) body.peakPower = parseFloat(opts.peakPower);\n body.price = parseFloat(opts.price);\n if (opts.coplanar) body.coplanar = true;\n\n if (opts.customAsset && opts.customAsset.length > 0) {\n body.solarKitCustomAssets = opts.customAsset.map((ca: { id: number; units: number }) => ({\n customAsset: { idCustomAsset: ca.id },\n units: ca.units,\n }));\n }\n\n const res = await client.post('/solar-kits', body);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n inventory.addCommand(kits);\n}\n\n/** Collector for repeatable --custom-asset <id:units> option */\nfunction collectCustomAssets(value: string, previous: { id: number; units: number }[]): { id: number; units: number }[] {\n const [idStr, unitsStr] = value.split(':');\n const id = parseInt(idStr);\n const units = unitsStr ? parseInt(unitsStr) : 1;\n if (isNaN(id)) throw new Error(`Invalid custom asset format: \"${value}\". Use <id>:<units> (e.g. 100:12)`);\n return [...previous, { id, units }];\n}\n","import { Command } from 'commander';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\nexport function registerManufacturersCommands(inventory: Command): void {\n const mfr = inventory.command('manufacturers').description('Manage manufacturers (referenced by all inventory devices)');\n\n mfr\n .command('list')\n .description('List all manufacturers. Fields: idManufacturer, name, imageUrl')\n .action(async () => {\n try {\n const global = getGlobalOpts(mfr);\n const client = createServiceClient('solar', global);\n const res = await client.get('/manufacturers');\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n mfr\n .command('create')\n .description('Create a new manufacturer')\n .requiredOption('--data <json>', 'JSON: { \"name\": \"Manufacturer Name\", \"imageUrl\": \"...\" }')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(mfr);\n const client = createServiceClient('solar', global);\n const body = JSON.parse(opts.data);\n const res = await client.post('/manufacturers', body);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import { Command } from 'commander';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\nfunction parseData(data: string | undefined): Record<string, unknown> | undefined {\n if (!data) return undefined;\n return JSON.parse(data);\n}\n\nexport function registerCustomFieldsCommands(inventory: Command): void {\n const fields = inventory.command('custom-fields').description(\n 'Manage custom fields for custom asset types.\\n' +\n 'Fields define the schema of a custom asset type (e.g. text, number, options).\\n' +\n 'Types: text, number, date, datetime, time, email, phonenumber, website, options, labels, currency, large_text, user'\n );\n\n // --- list ---\n fields\n .command('list')\n .description('List all custom fields')\n .action(async () => {\n try {\n const global = getGlobalOpts(fields);\n const client = createServiceClient('solar', global);\n const res = await client.get('/custom-asset/custom-field/all');\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- get ---\n fields\n .command('get <id>')\n .description('Get a custom field by ID')\n .action(async (id) => {\n try {\n const global = getGlobalOpts(fields);\n const client = createServiceClient('solar', global);\n const res = await client.get(`/custom-asset/custom-field/id/${id}`);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- create ---\n fields\n .command('create')\n .description(\n 'Create a custom field for a custom asset type.\\n' +\n 'Required: label, type, customAssetTypeId\\n' +\n 'For options/labels type, include customFieldOptions array.\\n\\n' +\n 'Example:\\n' +\n ' suntropy inventory custom-fields create --data \\'{\"label\":\"Power\",\"type\":\"number\",\"customAssetTypeId\":1}\\'\\n' +\n ' suntropy inventory custom-fields create --data \\'{\"label\":\"Size\",\"type\":\"options\",\"customAssetTypeId\":1,\"customFieldOptions\":[{\"label\":\"S\",\"value\":\"s\"},{\"label\":\"M\",\"value\":\"m\"},{\"label\":\"L\",\"value\":\"l\"}]}\\''\n )\n .requiredOption('--data <json>', 'Field definition as JSON')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(fields);\n const client = createServiceClient('solar', global);\n const body = parseData(opts.data);\n const res = await client.post('/custom-asset/custom-field', body);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- update ---\n fields\n .command('update <id>')\n .description('Update a custom field')\n .requiredOption('--data <json>', 'Updated field data as JSON')\n .action(async (id, opts) => {\n try {\n const global = getGlobalOpts(fields);\n const client = createServiceClient('solar', global);\n const body = parseData(opts.data);\n const res = await client.put(`/custom-asset/custom-field/${id}`, body);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- delete ---\n fields\n .command('delete <id>')\n .description('Delete a custom field')\n .action(async (id) => {\n try {\n const global = getGlobalOpts(fields);\n const client = createServiceClient('solar', global);\n const res = await client.delete(`/custom-asset/custom-field/${id}`);\n output(res.data ?? { success: true, deleted: id }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import { Command } from 'commander';\nimport { createResourceCommands, type ResourceConfig } from './factory.js';\nimport { registerKitsCommands } from './kits.js';\nimport { registerManufacturersCommands } from './manufacturers.js';\nimport { registerCustomFieldsCommands } from './custom-fields.js';\n\nconst RESOURCES: ResourceConfig[] = [\n {\n name: 'panels',\n singular: 'solar panel',\n basePath: '/solar-panels',\n idField: 'solarPanelId',\n listFields: ['name', 'manufacturer', 'peakPower', 'efficiency', 'costPerUnit', 'active'],\n batchDeletePath: 'delete-batch-solar-panels',\n },\n {\n name: 'inverters',\n singular: 'solar inverter',\n basePath: '/solar-inverter',\n idField: 'idInverter',\n listFields: ['name', 'manufacturer', 'nominalPower', 'efficiency', 'phaseNumber', 'isMicroinverter', 'isHybrid', 'costPerUnit', 'active'],\n batchDeletePath: 'delete-batch-solar-inverters',\n putBodyOnly: true,\n },\n {\n name: 'batteries',\n singular: 'battery',\n basePath: '/solar-battery',\n idField: 'batteryId',\n listFields: ['name', 'manufacturer', 'capacity', 'isModular', 'costPerUnit', 'active'],\n batchDeletePath: 'delete-batch-solar-batteries',\n },\n {\n name: 'chargers',\n singular: 'VE charger',\n basePath: '/charger',\n idField: 'idCharger',\n listFields: ['name', 'manufacturer', 'maxPower', 'connectorType', 'phaseNumber', 'costPerUnit', 'active'],\n batchDeletePath: 'delete-batch-chargers',\n putBodyOnly: true,\n },\n {\n name: 'heatpumps',\n singular: 'heat pump',\n basePath: '/heat-pump',\n idField: 'idHeatpump',\n listFields: ['name', 'manufacturer', 'lowerPower', 'upperPower', 'scop', 'costPerUnit', 'active'],\n batchDeletePath: 'delete-batch-heatpumps',\n putBodyOnly: true,\n },\n {\n name: 'custom-assets',\n singular: 'custom asset',\n basePath: '/custom-asset',\n idField: 'idCustomAsset',\n listFields: ['label', 'customAssetType', 'identifier', 'isMaterial', 'costPerUnit', 'active'],\n getPath: '/custom-asset/id/:id',\n },\n {\n name: 'custom-asset-types',\n singular: 'custom asset type',\n basePath: '/custom-asset/type',\n idField: 'idCustomAssetType',\n listFields: ['label', 'isMaterialConcept', 'panelsQuantity'],\n getPath: '/custom-asset/type/id/:id',\n },\n {\n name: 'charger-kits',\n singular: 'VE charger kit',\n basePath: '/charger/ve-charger-kits',\n idField: 'idVEChargerKit',\n listFields: ['identifier', 'charger', 'price', 'phaseNumber', 'active'],\n filterPath: '/charger/ve-charger-kits/filter',\n batchDeletePath: 'delete-batch-ve-charger-kits',\n putBodyOnly: true,\n },\n {\n name: 'heatpump-kits',\n singular: 'heat pump kit',\n basePath: '/heat-pump/heatpump-kits',\n idField: 'idHeatpumpKit',\n listFields: ['identifier', 'heatpump', 'price', 'phaseNumber', 'active'],\n filterPath: '/heat-pump/heatpump-kits/filter',\n batchDeletePath: 'delete-batch-heatpump-kits',\n putBodyOnly: true,\n },\n];\n\nexport function registerInventoryCommands(program: Command): void {\n const inventory = program.command('inventory').description('Manage inventory: panels, inverters, batteries, chargers, heatpumps, custom-assets, kits');\n\n // Register manufacturer commands (special - simpler CRUD)\n registerManufacturersCommands(inventory);\n\n // Register all standard CRUD resources\n for (const resource of RESOURCES) {\n inventory.addCommand(createResourceCommands(resource));\n }\n\n // Register custom fields (separate CRUD)\n registerCustomFieldsCommands(inventory);\n\n // Register kits (complex - has sub-resources)\n registerKitsCommands(inventory);\n}\n","import { Command, Option } from 'commander';\nimport { readFileSync, writeFileSync, existsSync } from 'fs';\nimport { v4 } from 'uuid';\nimport { createServiceClient, handleApiError, assertFound, assertStudyObjectId } from '../../client.js';\nimport { loadConfig, getActiveProfile } from '../../config.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\n// ─── Types ───\n\ninterface StepsProgress {\n clientDetails: boolean | undefined;\n consumption: boolean | undefined;\n surfacesSelector: boolean | undefined;\n production: boolean | undefined;\n results: boolean | undefined;\n economicBalance: boolean | undefined;\n}\n\ninterface SolarStudyProgress {\n stepsProgress: StepsProgress;\n stepsUpdates: Record<string, boolean | undefined>;\n editingSolarStudy: boolean;\n lastStateUpdateMomentMS: number;\n}\n\ninterface ByPeriodValues {\n p1?: number;\n p2?: number;\n p3?: number;\n p4?: number;\n p5?: number;\n p6?: number;\n [key: string]: number | undefined;\n}\n\ntype Study = Record<string, unknown>;\n\n// ─── Study defaults (replicates SolarStudy constructor) ───\n\nfunction createDefaultStudy(name?: string): Study {\n const now = new Date();\n const dateStr = now.toISOString().split('T')[0];\n return {\n id: v4(),\n surfaces: undefined,\n clientDetails: {\n identifier: undefined,\n sector: undefined,\n email: undefined,\n cups: undefined,\n phoneNumber: undefined,\n address: undefined,\n instalationLocation: undefined,\n region: undefined,\n subregion: undefined,\n addressCode: undefined,\n dniOrCif: undefined,\n includeTaxes: false,\n taxesPercentage: 0,\n },\n location: undefined,\n atrTariff: undefined,\n geographicalZone: undefined,\n energyPrices: { units: '€/kWh' },\n contractedPower: {},\n powerPrices: { units: '€/kW · dia' },\n results: undefined,\n consumptionIntroductionMode: 'periods',\n peakPowerIntroductionMode: 'solarKit',\n instalationPhaseNumber: 'single_phase',\n peakPowerOptimizationMethod: {\n maxNumberOfOverproductionMonths: 3,\n },\n useAlternativePrices: false,\n economicResults: {\n guaranteeProductionPercentage: 85,\n inflation: 3,\n instalationLifeTime: 25,\n commercialFeePercentage: 85,\n instalationFinancingPercentage: 0,\n taxesPercentage: 21,\n includeTaxes: false,\n margen: 0,\n },\n creationTimestamp: dateStr,\n solarStudyProgress: {\n stepsProgress: {\n clientDetails: undefined,\n consumption: undefined,\n economicBalance: undefined,\n production: undefined,\n results: undefined,\n surfacesSelector: undefined,\n },\n stepsUpdates: {\n clientDetails: false,\n consumption: false,\n economicBalance: false,\n production: false,\n results: false,\n surfacesSelector: false,\n },\n editingSolarStudy: false,\n lastStateUpdateMomentMS: now.getTime(),\n } as SolarStudyProgress,\n activeBatteries: false,\n batteriesConfiguration: {\n initialCapacityPercentage: 100,\n maxCapacityPercentage: 100,\n minCapacityPercentage: 0,\n },\n layout: 'v2',\n lastStateUpdateMomentMS: now.getTime(),\n name: name || `Estudio Solar ${dateStr}`,\n notes: undefined,\n market: 'es',\n };\n}\n\n// ─── Auto-validation engine (replicates frontend step conditions) ───\n\nfunction checkByPeriodCompletion(periodNumber: number, element: ByPeriodValues | undefined): boolean {\n if (!element) return false;\n let assigned = 0;\n for (let i = 1; i <= 6; i++) {\n const val = element['p' + i];\n if (val !== undefined && val !== null && !isNaN(val)) {\n assigned++;\n }\n }\n return assigned >= periodNumber;\n}\n\nfunction evaluateSteps(study: Study): { stepsProgress: StepsProgress; missing: Record<string, string> } {\n const missing: Record<string, string> = {};\n\n // --- clientDetails ---\n const atrTariff = study.atrTariff as { periods?: number } | undefined;\n const energyPrices = study.energyPrices as ByPeriodValues | undefined;\n const geographicalZone = study.geographicalZone as Record<string, unknown> | undefined;\n const market = study.market as string | undefined;\n const extraCostPrice = study.extraCostPrice as ByPeriodValues | undefined;\n\n let clientDetailsComplete = true;\n if (!atrTariff) {\n clientDetailsComplete = false;\n missing.clientDetails = 'Needs atrTariff (use: studies set tariff)';\n } else if (!checkByPeriodCompletion(atrTariff.periods || 3, energyPrices)) {\n clientDetailsComplete = false;\n missing.clientDetails = `Needs energyPrices with ${atrTariff.periods || 3} periods filled (use: studies set prices)`;\n } else if (!geographicalZone) {\n clientDetailsComplete = false;\n missing.clientDetails = 'Needs geographicalZone (use: studies set tariff --zone-id N)';\n } else if (market === 'pt' && !checkByPeriodCompletion(1, extraCostPrice)) {\n clientDetailsComplete = false;\n missing.clientDetails = 'PT market needs extraCostPrice with 1 period (use: studies set prices --extra-cost-p1 N)';\n }\n\n // --- consumption ---\n const consumption = study.consumption as { days?: unknown[] } | undefined;\n const consumptionComplete = !!consumption?.days?.length;\n if (!consumptionComplete) {\n missing.consumption = 'Needs consumption curve (use: studies set consumption)';\n }\n\n // --- surfacesSelector ---\n const surfaces = study.surfaces as unknown[] | undefined;\n const surfacesComplete = !!surfaces?.length;\n if (!surfacesComplete) {\n missing.surfacesSelector = 'Needs at least one surface (use: studies add surface)';\n }\n\n // --- production ---\n // Requires: at least one surface with production curve AND equipment (panel or kit) selected\n const solarPanel = study.solarPanel as Record<string, unknown> | undefined;\n const solarKit = study.solarKit as Record<string, unknown> | undefined;\n const hasEquipment = !!solarPanel || !!solarKit;\n let hasProductionCurve = false;\n if (surfaces && surfaces.length > 0) {\n for (const s of surfaces) {\n const surf = s as { production?: { days?: unknown[] } };\n if (surf.production?.days?.length) {\n hasProductionCurve = true;\n break;\n }\n }\n }\n const productionComplete = hasProductionCurve && hasEquipment;\n if (!productionComplete) {\n const reasons: string[] = [];\n if (!hasEquipment) reasons.push('no panel or kit selected (use: studies set panel or studies set kit)');\n if (!hasProductionCurve) reasons.push('no surface has a production curve (use: studies calculate production)');\n missing.production = reasons.join('; ');\n }\n\n // --- results ---\n const results = study.results as Record<string, unknown> | undefined;\n const resultsComplete = results !== undefined;\n if (!resultsComplete) {\n missing.results = 'Results not calculated (use: studies calculate results)';\n }\n\n // --- economicBalance ---\n const economicResults = study.economicResults as Record<string, unknown> | undefined;\n const economicBalanceComplete =\n economicResults?.margen !== undefined &&\n economicResults?.totalCost !== undefined &&\n results !== undefined;\n if (!economicBalanceComplete) {\n const reasons: string[] = [];\n if (economicResults?.margen === undefined) reasons.push('margen');\n if (economicResults?.totalCost === undefined) reasons.push('totalCost');\n if (!results) reasons.push('results');\n missing.economicBalance = `Needs: ${reasons.join(', ')} (use: studies set economics)`;\n }\n\n return {\n stepsProgress: {\n clientDetails: clientDetailsComplete,\n consumption: consumptionComplete,\n surfacesSelector: surfacesComplete,\n production: productionComplete,\n results: resultsComplete,\n economicBalance: economicBalanceComplete,\n },\n missing,\n };\n}\n\nfunction calculateCompletionPercentage(stepsProgress: StepsProgress): number {\n const completed = Object.values(stepsProgress).filter(Boolean).length;\n return Math.round((completed / 6) * 100);\n}\n\n// ─── Cascade resets ───\n\ntype StepName = keyof StepsProgress;\n\nconst CASCADE_RESETS: Record<string, StepName[]> = {\n consumption: ['production', 'results', 'economicBalance'],\n surfaces: ['production', 'results', 'economicBalance'],\n};\n\nfunction applyCascadeResets(study: Study, changedField: string): string[] {\n const resetSteps = CASCADE_RESETS[changedField];\n if (!resetSteps) return [];\n\n const progress = (study.solarStudyProgress as SolarStudyProgress);\n const resets: string[] = [];\n for (const step of resetSteps) {\n if (progress.stepsProgress[step] !== undefined) {\n progress.stepsProgress[step] = undefined;\n resets.push(step);\n }\n }\n\n // Also clear dependent data for full resets\n if (changedField === 'consumption') {\n // Don't clear surfaces production, only results\n study.results = undefined;\n }\n if (changedField === 'surfaces') {\n study.results = undefined;\n }\n\n return resets;\n}\n\n// ─── File I/O helpers ───\n\nfunction readStudy(filePath: string): Study {\n if (!existsSync(filePath)) {\n throw new Error(`Study file not found: ${filePath}. Use 'studies init --file ${filePath}' to create one.`);\n }\n return JSON.parse(readFileSync(filePath, 'utf-8'));\n}\n\nfunction writeStudy(filePath: string, study: Study): void {\n writeFileSync(filePath, JSON.stringify(study, null, 2), 'utf-8');\n}\n\n/** Read study, apply changes, re-validate, write back, return status */\nfunction updateStudy(\n filePath: string,\n updater: (study: Study) => string | undefined, // returns cascade field name or undefined\n): { stepsProgress: StepsProgress; completionPercentage: number; missing: Record<string, string>; cascadeResets: string[] } {\n const study = readStudy(filePath);\n const cascadeField = updater(study);\n\n // Apply cascade resets\n let cascadeResets: string[] = [];\n if (cascadeField) {\n cascadeResets = applyCascadeResets(study, cascadeField);\n }\n\n // Re-evaluate all steps\n const { stepsProgress, missing } = evaluateSteps(study);\n\n // Update solarStudyProgress\n const progress = study.solarStudyProgress as SolarStudyProgress;\n progress.stepsProgress = stepsProgress;\n progress.lastStateUpdateMomentMS = Date.now();\n study.lastStateUpdateMomentMS = Date.now();\n\n writeStudy(filePath, study);\n\n return {\n stepsProgress,\n completionPercentage: calculateCompletionPercentage(stepsProgress),\n missing,\n cascadeResets,\n };\n}\n\n/** Deep merge: target ← source (non-destructive, arrays replaced not merged) */\nfunction deepMerge(target: Record<string, unknown>, source: Record<string, unknown>): void {\n for (const key of Object.keys(source)) {\n const sv = source[key];\n const tv = target[key];\n if (sv && typeof sv === 'object' && !Array.isArray(sv) && tv && typeof tv === 'object' && !Array.isArray(tv)) {\n deepMerge(tv as Record<string, unknown>, sv as Record<string, unknown>);\n } else {\n target[key] = sv;\n }\n }\n}\n\n// ─── CLI helpers ───\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\nfunction resolveFile(opts: { file?: string }): string {\n return opts.file || process.env.SUNTROPY_STUDY || './study.json';\n}\n\ntype LatLng = { lat: number; lng: number };\n\n/**\n * Resolve the geographic coordinates used to calculate a surface, in order of\n * preference:\n * 1. surface.center — explicit surface centre (e.g. set by `add surface`)\n * 2. study.location — study-level location\n * 3. polygonPath centroid — average of the drawn polygon vertices\n * 4. polygonPath first point — fallback when the centroid is degenerate\n *\n * A surface drawn in the editor arrives with a full `polygonPath` but no\n * `center`, and studies from that flow may also lack `location`. Deriving the\n * coordinate from the polygon lets those surfaces be calculated instead of\n * failing with \"no coordinates\". Returns null only when no usable point exists.\n */\nexport function resolveSurfaceCoordinates(\n surface: Record<string, unknown>,\n study: Study,\n): LatLng | null {\n const isValid = (c: unknown): c is LatLng => {\n const p = c as LatLng | undefined;\n return !!p && Number.isFinite(p.lat) && Number.isFinite(p.lng);\n };\n\n const center = surface.center as LatLng | undefined;\n if (isValid(center)) return { lat: center.lat, lng: center.lng };\n\n const studyLocation = study.location as LatLng | undefined;\n if (isValid(studyLocation)) return { lat: studyLocation.lat, lng: studyLocation.lng };\n\n const path = surface.polygonPath as Array<{ lat?: number; lng?: number }> | undefined;\n if (Array.isArray(path) && path.length > 0) {\n const points = path.filter(\n (p): p is LatLng => Number.isFinite(p?.lat) && Number.isFinite(p?.lng),\n );\n if (points.length > 0) {\n // Centroid: average of the polygon vertices.\n const sum = points.reduce(\n (acc, p): LatLng => ({ lat: acc.lat + p.lat, lng: acc.lng + p.lng }),\n { lat: 0, lng: 0 },\n );\n const centroid = { lat: sum.lat / points.length, lng: sum.lng / points.length };\n if (isValid(centroid)) return centroid;\n // Fallback: first valid point of the path.\n return { lat: points[0].lat, lng: points[0].lng };\n }\n }\n\n return null;\n}\n\n/**\n * Installed DC power (Watts) sent to `/solar-study/calculateProduction` for a\n * surface, replicating the frontend `generateCalculateProductionDto`:\n *\n * installedPower = (panelsLayoutPolygons?.length ?? panelNumber) * panelPeakPower\n *\n * The panel peak power comes from `study.solarPanel.peakPower` — kit mode also\n * populates `solarPanel` from `solarKit.kitSolarPanel`, so both peak-power modes\n * resolve. An explicit `surface.installedPower` (e.g. from `add surface --power`)\n * takes precedence. The old code read only `surface.installedPower || 5000`, a\n * field the frontend never sets, so studies built in the UI were silently\n * calculated for the 5000 W (5 kWp) default.\n *\n * Returns `isDefault: true` when it had to fall back to 5000 W so the caller can\n * warn instead of emitting wrong production numbers silently.\n */\nexport function resolveSurfaceInstalledPower(\n surface: Record<string, unknown>,\n study: Study,\n): { installedPower: number; isDefault: boolean } {\n const explicit = surface.installedPower as number | undefined;\n if (Number.isFinite(explicit) && (explicit as number) > 0) {\n return { installedPower: explicit as number, isDefault: false };\n }\n\n const solarPanel = study.solarPanel as { peakPower?: number } | undefined;\n const kitPanel = (study.solarKit as { kitSolarPanel?: { peakPower?: number } } | undefined)?.kitSolarPanel;\n const panelPeakPower = (solarPanel?.peakPower as number) || (kitPanel?.peakPower as number) || undefined;\n\n // Frontend precedence: drawn panel layout length, else surface.panelNumber.\n const layout = surface.panelsLayoutPolygons as unknown[] | undefined;\n const panelCount = layout !== undefined\n ? (layout.length || 0)\n : (surface.panelNumber as number | undefined);\n\n if (panelPeakPower && Number.isFinite(panelCount) && (panelCount as number) > 0) {\n return { installedPower: (panelCount as number) * panelPeakPower, isDefault: false };\n }\n\n return { installedPower: 5000, isDefault: true };\n}\n\n// ─── Register commands ───\n\nexport function registerStudyBuilderCommands(studies: Command): void {\n\n // ═══════════════════════════════════════════\n // INIT\n // ═══════════════════════════════════════════\n studies\n .command('init')\n .description(\n 'Create a new study workspace (local JSON file with defaults).\\n' +\n 'Example: suntropy studies init --file /tmp/study.json --name \"Residencial 5kW\"'\n )\n .option('--file <path>', 'Output file path (default: ./study.json)')\n .option('--name <studyName>', 'Study name')\n .option('--market <code>', 'Market country: es, pt, it, fr, de, etc.', 'es')\n .action(async (opts) => {\n try {\n const filePath = resolveFile(opts);\n const study = createDefaultStudy(opts.name);\n if (opts.market) study.market = opts.market;\n writeStudy(filePath, study);\n const { stepsProgress, missing } = evaluateSteps(study);\n output({\n file: filePath,\n id: study.id,\n name: study.name,\n stepsProgress,\n completionPercentage: 0,\n missing,\n }, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // ═══════════════════════════════════════════\n // VALIDATE\n // ═══════════════════════════════════════════\n studies\n .command('validate')\n .description(\n 'Check completion status of all study steps.\\n' +\n 'Returns stepsProgress, completionPercentage, and what is missing for each incomplete step.'\n )\n .option('--file <path>', 'Study file path')\n .action(async (opts) => {\n try {\n const study = readStudy(resolveFile(opts));\n const { stepsProgress, missing } = evaluateSteps(study);\n output({\n name: study.name,\n stepsProgress,\n completionPercentage: calculateCompletionPercentage(stepsProgress),\n missing,\n }, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // ═══════════════════════════════════════════\n // SAVE\n // ═══════════════════════════════════════════\n studies\n .command('save')\n .description(\n 'Save study to the backend (POST /solar-study).\\n' +\n 'If the study has _id, it updates the existing study. Otherwise creates new.\\n' +\n 'Example: suntropy studies save --file /tmp/study.json --state-id 1'\n )\n .option('--file <path>', 'Study file path')\n .option('--state-id <n>', 'Solar study metadata state ID')\n .option('--credit-amount <n>', 'Credit amount to consume')\n .option('--save-as-new', 'Force save as new study (even if _id exists)')\n .action(async (opts) => {\n try {\n const filePath = resolveFile(opts);\n const global = getGlobalOpts(studies);\n const study = readStudy(filePath);\n\n // Re-validate before saving\n const { stepsProgress } = evaluateSteps(study);\n const progress = study.solarStudyProgress as SolarStudyProgress;\n progress.stepsProgress = stepsProgress;\n progress.lastStateUpdateMomentMS = Date.now();\n\n // Auto-add comment like frontend SaveStudyModal\n const isEditing = progress.editingSolarStudy || !!study._id;\n const comments = (study.comments || []) as Record<string, unknown>[];\n const commentType = opts.saveAsNew ? 'duplicated' : (isEditing ? 'modified' : 'created');\n comments.push(createComment(commentType));\n study.comments = comments;\n\n if (opts.saveAsNew) {\n delete study._id;\n }\n\n const client = createServiceClient('solar', global);\n const params: Record<string, string> = {};\n if (opts.stateId) params.idSolarStudyState = opts.stateId;\n if (opts.creditAmount) params.creditAmount = opts.creditAmount;\n if (opts.saveAsNew) params.saveAsNew = 'true';\n\n const queryString = Object.entries(params)\n .map(([k, v]) => `${k}=${encodeURIComponent(v)}`)\n .join('&');\n const url = `/solar-study${queryString ? '?' + queryString : ''}`;\n\n const res = await client.post(url, study);\n\n // If response contains _id or solarStudyId, update local file\n const responseData = res.data as Record<string, unknown>;\n if (responseData?.solarStudyId) {\n study._id = responseData.solarStudyId as string;\n progress.editingSolarStudy = true;\n writeStudy(filePath, study);\n }\n\n output({\n saved: true,\n metadata: responseData,\n file: filePath,\n completionPercentage: calculateCompletionPercentage(stepsProgress),\n }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // ═══════════════════════════════════════════\n // PULL\n // ═══════════════════════════════════════════\n studies\n .command('pull <studyId>')\n .description(\n 'Download an existing study from the backend into a local file.\\n' +\n 'Example: suntropy studies pull abc123 --file /tmp/study.json'\n )\n .option('--file <path>', 'Output file path')\n .action(async (studyId, opts) => {\n try {\n assertStudyObjectId(studyId);\n const filePath = resolveFile(opts);\n const global = getGlobalOpts(studies);\n const client = createServiceClient('solar', global);\n const res = await client.get(`/solar-study/findById/${studyId}`);\n const study = assertFound(res.data, 'Solar study', studyId) as Study;\n\n // Re-validate\n const { stepsProgress, missing } = evaluateSteps(study);\n const progress = (study.solarStudyProgress || {}) as SolarStudyProgress;\n progress.stepsProgress = stepsProgress;\n progress.editingSolarStudy = true;\n study.solarStudyProgress = progress;\n\n writeStudy(filePath, study);\n output({\n file: filePath,\n _id: study._id,\n name: study.name,\n stepsProgress,\n completionPercentage: calculateCompletionPercentage(stepsProgress),\n missing,\n }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // ═══════════════════════════════════════════\n // SET — parent command for all sub-commands\n // ═══════════════════════════════════════════\n const set = studies.command('set').description('Set study properties. Each sub-command auto-validates after changes.');\n\n // --- set name ---\n set\n .command('name')\n .description('Set the study name')\n .option('--file <path>', 'Study file path')\n .requiredOption('--name <studyName>', 'Study name')\n .action(async (opts) => {\n try {\n const result = updateStudy(resolveFile(opts), (study) => {\n study.name = opts.name;\n return undefined;\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- set market ---\n set\n .command('market')\n .description('Set the market country code (es, pt, it, fr, de, etc.)')\n .option('--file <path>', 'Study file path')\n .requiredOption('--market <code>', 'Market country code')\n .action(async (opts) => {\n try {\n const result = updateStudy(resolveFile(opts), (study) => {\n study.market = opts.market;\n return undefined;\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- set client ---\n set\n .command('client')\n .description(\n 'Set client details (name, email, phone, cups, address, etc.)\\n' +\n 'Example: suntropy studies set client --file study.json --name \"Juan García\" --email j@co.com --cups ES001234'\n )\n .option('--file <path>', 'Study file path')\n .option('--name <clientName>', 'Client name (identifier/razón social)')\n .option('--email <email>', 'Client email')\n .option('--phone <phone>', 'Phone number')\n .option('--cups <cups>', 'CUPS code')\n .option('--address <addr>', 'Address')\n .option('--city <city>', 'City')\n .option('--region <region>', 'Region (comunidad autónoma)')\n .option('--subregion <subregion>', 'Subregion (provincia)')\n .option('--dni <dni>', 'DNI or CIF')\n .option('--sector <sector>', 'Client sector')\n .option('--installation-location <loc>', 'Installation location description')\n .action(async (opts) => {\n try {\n const result = updateStudy(resolveFile(opts), (study) => {\n const cd = (study.clientDetails || {}) as Record<string, unknown>;\n if (opts.name) cd.identifier = opts.name;\n if (opts.email) cd.email = opts.email;\n if (opts.phone) cd.phoneNumber = opts.phone;\n if (opts.cups) cd.cups = opts.cups;\n if (opts.address) cd.address = opts.address;\n if (opts.city) cd.city = opts.city;\n if (opts.region) cd.region = opts.region;\n if (opts.subregion) cd.subregion = opts.subregion;\n if (opts.dni) cd.dniOrCif = opts.dni;\n if (opts.sector) cd.sector = opts.sector;\n if (opts.installationLocation) cd.instalationLocation = opts.installationLocation;\n study.clientDetails = cd;\n return undefined;\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- set tariff ---\n set\n .command('tariff')\n .description(\n 'Set ATR tariff and geographical zone. Auto-sets phase (>3 periods → three_phase).\\n' +\n 'Common tariff IDs (Spain): 13=2.0TD (3 periods), 14=3.0TD (6 periods)\\n' +\n 'Zone IDs (Spain): 1=Peninsula, 2=Canarias, 3=Baleares\\n' +\n 'Example: suntropy studies set tariff --file study.json --tariff-id 13 --zone-id 1'\n )\n .option('--file <path>', 'Study file path')\n .requiredOption('--tariff-id <n>', 'ATR tariff ID')\n .option('--zone-id <n>', 'Geographical zone ID', '1')\n .option('--market <code>', 'Market code for tariff lookup', 'es')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const client = createServiceClient('periods', global);\n\n // Fetch tariff info\n const tariffRes = await client.get('/tarifas-atr', {\n params: { market: opts.market },\n });\n const tariffs = (Array.isArray(tariffRes.data) ? tariffRes.data : tariffRes.data?.data || []) as Record<string, unknown>[];\n const tariffId = parseInt(opts.tariffId);\n const tariff = tariffs.find((t) => t.idTarifaATR === tariffId);\n if (!tariff) {\n outputError(new Error(`Tariff ID ${tariffId} not found. Available: ${tariffs.map((t) => `${t.idTarifaATR}=${t.nombre}`).join(', ')}`));\n return;\n }\n\n // Fetch zone info\n const zoneRes = await client.get('/zonas', {\n params: { market: opts.market },\n });\n const zones = (Array.isArray(zoneRes.data) ? zoneRes.data : zoneRes.data?.data || []) as Record<string, unknown>[];\n const zoneId = parseInt(opts.zoneId);\n const zone = zones.find((z) => z.idZona === zoneId);\n\n const result = updateStudy(resolveFile(opts), (study) => {\n study.atrTariff = tariff;\n if (zone) study.geographicalZone = zone;\n\n // Auto-set phase based on tariff periods (replicates frontend logic)\n const periods = (tariff.periods as number) || 3;\n study.instalationPhaseNumber = periods > 3 ? 'three_phase' : 'single_phase';\n\n return undefined; // no cascade reset for tariff change\n });\n\n output(result, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- set prices ---\n set\n .command('prices')\n .description(\n 'Set energy prices by period.\\n' +\n 'Examples:\\n' +\n ' suntropy studies set prices --file study.json --energy \\'{\"p1\":0.15,\"p2\":0.08,\"p3\":0.06}\\'\\n' +\n ' suntropy studies set prices --file study.json --energy-p1 0.15 --energy-p2 0.08 --energy-p3 0.06\\n' +\n ' suntropy studies set prices --file study.json --energy \\'{\"p1\":0.15,...}\\' --power \\'{\"p1\":40,...}\\' --contracted \\'{\"p1\":5.5,...}\\''\n )\n .option('--file <path>', 'Study file path')\n .option('--energy <json>', 'Energy prices JSON: {\"p1\":N,\"p2\":N,...}')\n .option('--energy-p1 <n>', 'Energy price period 1 (€/kWh)')\n .option('--energy-p2 <n>', 'Energy price period 2 (€/kWh)')\n .option('--energy-p3 <n>', 'Energy price period 3 (€/kWh)')\n .option('--energy-p4 <n>', 'Energy price period 4 (€/kWh)')\n .option('--energy-p5 <n>', 'Energy price period 5 (€/kWh)')\n .option('--energy-p6 <n>', 'Energy price period 6 (€/kWh)')\n .option('--power <json>', 'Power prices JSON: {\"p1\":N,\"p2\":N,...} (€/kW·day)')\n .option('--contracted <json>', 'Contracted power JSON: {\"p1\":N,\"p2\":N,...} (kW)')\n .option('--extra-cost-p1 <n>', 'Extra cost price P1 (Portugal market)')\n .action(async (opts) => {\n try {\n const result = updateStudy(resolveFile(opts), (study) => {\n // Energy prices: from JSON or individual flags\n const ep = (study.energyPrices || { units: '€/kWh' }) as Record<string, unknown>;\n if (opts.energy) {\n const parsed = JSON.parse(opts.energy);\n Object.assign(ep, parsed);\n }\n for (let i = 1; i <= 6; i++) {\n const val = opts[`energyP${i}`];\n if (val !== undefined) ep[`p${i}`] = parseFloat(val);\n }\n study.energyPrices = ep;\n\n // Power prices\n if (opts.power) {\n const pp = (study.powerPrices || { units: '€/kW · dia' }) as Record<string, unknown>;\n Object.assign(pp, JSON.parse(opts.power));\n study.powerPrices = pp;\n }\n\n // Contracted power\n if (opts.contracted) {\n const cp = (study.contractedPower || {}) as Record<string, unknown>;\n Object.assign(cp, JSON.parse(opts.contracted));\n study.contractedPower = cp;\n }\n\n // Extra cost (Portugal)\n if (opts.extraCostP1 !== undefined) {\n study.extraCostPrice = { p1: parseFloat(opts.extraCostP1), units: '€/kWh' };\n }\n\n return undefined; // no cascade\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- set consumption ---\n set\n .command('consumption')\n .description(\n 'Set the consumption curve.\\n' +\n 'Modes:\\n' +\n ' --from-file <path> Load PowerCurve from JSON file\\n' +\n ' --annual + --pattern Generate via consumption-estimation API\\n' +\n ' --by-period <json> Period consumption: {\"p1\":N,\"p2\":N,\"p3\":N} + REE profile\\n' +\n ' --monthly <json> Monthly consumption: {\"1\":N,\"2\":N,...,\"12\":N} + REE profile\\n' +\n ' --monthly-by-period Monthly by period: {\"1\":{\"p1\":N,\"p2\":N},...} + REE profile\\n\\n' +\n 'Examples:\\n' +\n ' suntropy studies set consumption --file study.json --from-file /tmp/cons.json\\n' +\n ' suntropy studies set consumption --file study.json --annual 4000 --pattern Balance\\n' +\n ' suntropy studies set consumption --file study.json --by-period \\'{\"p1\":2500,\"p2\":1000,\"p3\":500}\\'\\n' +\n ' suntropy studies set consumption --file study.json --monthly \\'{\"1\":350,\"2\":320,...}\\''\n )\n .option('--file <path>', 'Study file path')\n .option('--from-file <curvePath>', 'Load PowerCurve from JSON file')\n .option('--annual <kWh>', 'Annual consumption in kWh')\n .option('--pattern <name>', 'Pattern: Balance, Nightly, Morning, Afternoon, Domestic, Commercial')\n .option('--by-period <json>', 'Period consumption JSON: {\"p1\":N,\"p2\":N,...}')\n .option('--monthly <json>', 'Monthly consumption JSON: {\"1\":N,...,\"12\":N}')\n .option('--monthly-by-period <json>', 'Monthly by period: {\"1\":{\"p1\":N,...},...}')\n .option('--tariff <code>', 'Tariff code for profile lookup (default: from study)')\n .option('--market <code>', 'Market code (default: from study)')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const filePath = resolveFile(opts);\n const study = readStudy(filePath);\n const studyTariff = (study.atrTariff as Record<string, unknown>)?.nombre as string || '3.0TD';\n const studyMarket = (study.market as string) || 'es';\n const tariff = opts.tariff || studyTariff;\n const market = opts.market || studyMarket;\n const year = new Date().getFullYear();\n\n let curveData: unknown;\n let introductionMode: string;\n\n if (opts.fromFile) {\n // Load from file\n curveData = JSON.parse(readFileSync(opts.fromFile, 'utf-8'));\n introductionMode = 'upload';\n\n } else if (opts.annual && opts.pattern) {\n // Generate via backend /consumption-estimation\n const profilesClient = createServiceClient('profiles', global);\n const params: Record<string, string> = {\n startDate: `${year}-01-01`,\n endDate: `${year}-12-31`,\n tariff,\n type: 'Final',\n anualConsumption: opts.annual,\n market,\n consumptionType: opts.pattern,\n };\n const queryString = Object.entries(params)\n .map(([k, v]) => `${k}=${encodeURIComponent(v)}`)\n .join('&');\n const res = await profilesClient.post(`/consumption-estimation?${queryString}`, {});\n curveData = res.data;\n introductionMode = 'consumption_patterns';\n\n } else if (opts.byPeriod) {\n // Fetch REE profile + period distribution, apply locally\n const periodValues = JSON.parse(opts.byPeriod);\n curveData = await generateFromProfile(global, tariff, market, year, 'CONSUMPTION_BY_PERIOD', periodValues);\n introductionMode = 'periods';\n\n } else if (opts.monthly) {\n // Fetch REE profile, apply monthly consumption\n const monthValues = JSON.parse(opts.monthly);\n curveData = await generateFromProfile(global, tariff, market, year, 'MONTH_CONSUMPTION', monthValues);\n introductionMode = 'monthly_consumption';\n\n } else if (opts.monthlyByPeriod) {\n // Complex: monthly by period\n const monthPeriodValues = JSON.parse(opts.monthlyByPeriod);\n curveData = await generateFromProfile(global, tariff, market, year, 'MONTHLY_BY_PERIOD', monthPeriodValues);\n introductionMode = 'monthly_periods';\n\n } else {\n outputError(new Error('Specify one of: --from-file, --annual + --pattern, --by-period, --monthly, --monthly-by-period'));\n return;\n }\n\n // Update study with consumption\n const result = updateStudy(filePath, (s) => {\n s.consumption = curveData;\n s.consumptionIntroductionMode = introductionMode;\n if (opts.annual) s.monthlyConsumption = parseFloat(opts.annual) / 12;\n if (opts.pattern) s.selectedConsumptionPattern = opts.pattern;\n if (opts.byPeriod) s.periodConsumptionDictionary = JSON.parse(opts.byPeriod);\n if (opts.monthly) s.monthConsumptionDictionary = JSON.parse(opts.monthly);\n if (opts.monthlyByPeriod) s.monthPeriodConsumptionDictionary = JSON.parse(opts.monthlyByPeriod);\n return 'consumption'; // trigger cascade\n });\n\n output(result, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- add surface ---\n studies\n .command('add')\n .description('Add elements to the study')\n .command('surface')\n .description(\n 'Add a solar surface to the study.\\n' +\n 'Example: suntropy studies add surface --file study.json --lat 37.39 --lon -5.99 --angle 30 --azimuth 180 --power 5000'\n )\n .option('--file <path>', 'Study file path')\n .requiredOption('--lat <n>', 'Latitude')\n .requiredOption('--lon <n>', 'Longitude')\n .option('--angle <n>', 'Panel inclination degrees', '30')\n .option('--azimuth <n>', 'Panel azimuth degrees (0=N, 180=S)', '180')\n .option('--power <w>', 'Installed power in Watts')\n .option('--panels-count <n>', 'Number of panels')\n .option('--production <file>', 'Production PowerCurve JSON file to attach')\n .option('--identifier <name>', 'Surface name/identifier')\n .action(async (opts) => {\n try {\n const result = updateStudy(resolveFile(opts), (study) => {\n const lat = parseFloat(opts.lat);\n const lng = parseFloat(opts.lon);\n const surface: Record<string, unknown> = {\n surfaceId: v4(),\n name: opts.identifier || `Surface ${((study.surfaces as unknown[])?.length || 0) + 1}`,\n inclination: parseFloat(opts.angle),\n orientation: parseFloat(opts.azimuth),\n panelInclination: parseFloat(opts.angle),\n panelOrientation: parseFloat(opts.azimuth),\n lossesPercentage: 14,\n // polygonPath required by backend metadata constructor\n polygonPath: [{ lat, lng }],\n };\n if (opts.power) surface.installedPower = parseFloat(opts.power);\n if (opts.panelsCount) surface.panelNumber = parseInt(opts.panelsCount);\n if (opts.production) {\n surface.production = JSON.parse(readFileSync(opts.production, 'utf-8'));\n }\n\n // Also set study-level location\n study.location = { lat: parseFloat(opts.lat), lng: parseFloat(opts.lon) };\n study.mapCenter = { lat: parseFloat(opts.lat), lng: parseFloat(opts.lon) };\n\n const surfaces = (study.surfaces as unknown[]) || [];\n surfaces.push(surface);\n study.surfaces = surfaces;\n\n return 'surfaces'; // cascade\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- remove surface ---\n studies\n .command('remove')\n .description('Remove elements from the study')\n .command('surface')\n .description('Remove a surface by index')\n .option('--file <path>', 'Study file path')\n .requiredOption('--index <n>', 'Surface index (0-based)')\n .action(async (opts) => {\n try {\n const result = updateStudy(resolveFile(opts), (study) => {\n const surfaces = (study.surfaces as unknown[]) || [];\n const idx = parseInt(opts.index);\n if (idx < 0 || idx >= surfaces.length) {\n throw new Error(`Surface index ${idx} out of range (0-${surfaces.length - 1})`);\n }\n surfaces.splice(idx, 1);\n study.surfaces = surfaces.length > 0 ? surfaces : undefined;\n return 'surfaces'; // cascade\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- set panel ---\n set\n .command('panel')\n .description(\n 'Set solar panel for the study. Auto-sets peakPowerIntroductionMode to \"solarPanel\".\\n' +\n 'Fetches full panel data from inventory.\\n' +\n 'Example: suntropy studies set panel --file study.json --panel-id 456 --panels-count 12'\n )\n .option('--file <path>', 'Study file path')\n .requiredOption('--panel-id <n>', 'Solar panel ID from inventory')\n .option('--panels-count <n>', 'Number of panels')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const solarClient = createServiceClient('solar', global);\n\n // Fetch full panel data\n const panelRes = await solarClient.get(`/solar-panels/${opts.panelId}`);\n const panel = panelRes.data;\n\n const result = updateStudy(resolveFile(opts), (study) => {\n study.solarPanel = panel;\n study.peakPowerIntroductionMode = 'solarPanel';\n // Clear kit when switching to panel mode\n study.solarKit = undefined;\n if (opts.panelsCount) {\n // Set panels count on first surface if exists\n const surfaces = study.surfaces as Record<string, unknown>[] | undefined;\n if (surfaces?.length) {\n surfaces[0].panelNumber = parseInt(opts.panelsCount);\n }\n }\n return undefined;\n });\n output(result, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- set kit ---\n set\n .command('kit')\n .description(\n 'Set solar kit for the study. Auto-sets peakPowerIntroductionMode to \"solarKit\".\\n' +\n 'Fetches full kit data from inventory.\\n' +\n 'Example: suntropy studies set kit --file study.json --kit-id 123'\n )\n .option('--file <path>', 'Study file path')\n .requiredOption('--kit-id <n>', 'Solar kit ID from inventory')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const solarClient = createServiceClient('solar', global);\n\n // Kits use getViaFilter (no GET /:id)\n const kitsRes = await solarClient.get('/solar-kits', { params: { unactive: true } });\n const allKits = Array.isArray(kitsRes.data) && Array.isArray(kitsRes.data[0])\n ? kitsRes.data[0]\n : (Array.isArray(kitsRes.data) ? kitsRes.data : kitsRes.data?.data || []);\n const kitId = parseInt(opts.kitId);\n const kit = allKits.find((k: Record<string, unknown>) => k.idSolarKit === kitId);\n if (!kit) {\n outputError(new Error(`Kit ${kitId} not found`));\n return;\n }\n\n const result = updateStudy(resolveFile(opts), (study) => {\n study.solarKit = kit;\n study.peakPowerIntroductionMode = 'solarKit';\n // Clear panel + inverters when switching to kit mode\n study.solarPanel = undefined;\n study.solarInverters = undefined;\n return undefined;\n });\n output(result, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- set inverter ---\n set\n .command('inverter')\n .description(\n 'Set inverter(s) for the study (when using solarPanel mode).\\n' +\n 'Example: suntropy studies set inverter --file study.json --inverter-id 789'\n )\n .option('--file <path>', 'Study file path')\n .requiredOption('--inverter-id <ids>', 'Inverter ID(s), comma-separated for multiple')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const solarClient = createServiceClient('solar', global);\n const ids = opts.inverterId.split(',').map((s: string) => parseInt(s.trim()));\n\n const inverters: unknown[] = [];\n for (const id of ids) {\n const res = await solarClient.get(`/solar-inverter/${id}`);\n inverters.push(res.data);\n }\n\n const result = updateStudy(resolveFile(opts), (study) => {\n study.solarInverters = inverters;\n return undefined;\n });\n output(result, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- set phase ---\n set\n .command('phase')\n .description('Manually set installation phase (overrides auto-set from tariff)')\n .option('--file <path>', 'Study file path')\n .requiredOption('--phase <type>', 'Phase: single_phase or three_phase')\n .action(async (opts) => {\n try {\n if (!['single_phase', 'three_phase'].includes(opts.phase)) {\n outputError(new Error('Phase must be single_phase or three_phase'));\n return;\n }\n const result = updateStudy(resolveFile(opts), (study) => {\n study.instalationPhaseNumber = opts.phase;\n return undefined;\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- set economics ---\n set\n .command('economics')\n .description(\n 'Set economic parameters for the study.\\n' +\n 'Example: suntropy studies set economics --file study.json --margin 15 --total-cost 6500 --lifetime 25'\n )\n .option('--file <path>', 'Study file path')\n .option('--margin <n>', 'Margin percentage')\n .option('--total-cost <n>', 'Total installation cost (€)')\n .option('--lifetime <n>', 'Installation lifetime in years')\n .option('--inflation <n>', 'Inflation rate percentage')\n .option('--taxes-pct <n>', 'Tax percentage')\n .option('--include-taxes', 'Include taxes in pricing')\n .option('--commercial-fee <n>', 'Commercial fee percentage')\n .option('--excesses-mode <mode>', 'Excesses compensation: gridSelling, PPA, noInjection, virtualBattery')\n .option('--excesses-buy-price <n>', 'Excesses buy price (€/MWh)')\n .option('--excesses-selling-price <n>', 'Excesses selling price (€/MWh)')\n .option('--peak-power-cost <n>', 'Cost per Wp (€/Wp). If --total-cost is omitted, totalCost is derived as cost × installed peak power (W)')\n .option('--guarantee-production <n>', 'Guarantee production percentage')\n .action(async (opts) => {\n try {\n const result = updateStudy(resolveFile(opts), (study) => {\n const er = (study.economicResults || {}) as Record<string, unknown>;\n if (opts.margin !== undefined) er.margen = parseFloat(opts.margin);\n if (opts.totalCost !== undefined) er.totalCost = parseFloat(opts.totalCost);\n if (opts.lifetime !== undefined) er.instalationLifeTime = parseInt(opts.lifetime);\n if (opts.inflation !== undefined) er.inflation = parseFloat(opts.inflation);\n if (opts.taxesPct !== undefined) er.taxesPercentage = parseFloat(opts.taxesPct);\n if (opts.includeTaxes) er.includeTaxes = true;\n if (opts.commercialFee !== undefined) er.commercialFeePercentage = parseFloat(opts.commercialFee);\n if (opts.excessesMode) er.excessesCompensationMode = opts.excessesMode;\n if (opts.excessesBuyPrice !== undefined) er.excessesBuyPrice = parseFloat(opts.excessesBuyPrice);\n if (opts.excessesSellingPrice !== undefined) er.excessesSellingPrice = parseFloat(opts.excessesSellingPrice);\n if (opts.peakPowerCost !== undefined) er.peakPowerCost = parseFloat(opts.peakPowerCost);\n if (opts.guaranteeProduction !== undefined) er.guaranteeProductionPercentage = parseFloat(opts.guaranteeProduction);\n\n // Auto-derive totalCost from the per-Wp cost when --peak-power-cost is set\n // but --total-cost is not. The economic balance uses economicResults.totalCost\n // as the source of truth; the frontend only derives the €/Wp figure from it\n // (totalCost / installedPeakPowerWp). We invert that here so setting the €/Wp\n // cost alone yields a correct total instead of leaving totalCost untouched\n // (which previously kept the balance at 0). Installed peak power is the sum of\n // the surfaces' resolved installedPower (W); peakPowerCost is €/Wp, so\n // totalCost = cost × watts. If no surface has a resolvable power we warn\n // (non-fatal) instead of writing a wrong total.\n if (opts.peakPowerCost !== undefined && opts.totalCost === undefined) {\n const surfaces = (study.surfaces as Record<string, unknown>[] | undefined) || [];\n let totalWatts = 0;\n let resolvedCount = 0;\n let anyDefault = false;\n for (const surface of surfaces) {\n const { installedPower, isDefault } = resolveSurfaceInstalledPower(surface, study);\n if (isDefault) {\n anyDefault = true;\n continue;\n }\n totalWatts += installedPower;\n resolvedCount += 1;\n }\n if (resolvedCount > 0 && !anyDefault) {\n er.totalCost = Math.round(parseFloat(opts.peakPowerCost) * totalWatts * 100) / 100;\n } else {\n process.stderr.write(\n JSON.stringify({\n warning:\n 'Set --peak-power-cost but could not derive totalCost: ' +\n (surfaces.length === 0\n ? 'the study has no surfaces.'\n : 'some surfaces have no resolvable installed power (set panels + kit/panel first).') +\n ' Pass --total-cost explicitly to set it.',\n }) + '\\n',\n );\n }\n }\n\n study.economicResults = er;\n return undefined;\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- set custom-assets ---\n set\n .command('custom-assets')\n .description(\n 'Set selected custom assets for the study.\\n' +\n 'Example: suntropy studies set custom-assets --file study.json --asset 100:12 --asset 200:1'\n )\n .option('--file <path>', 'Study file path')\n .requiredOption('--asset <id:qty>', 'Custom asset as id:quantity (repeatable)', collectAssets, [])\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const solarClient = createServiceClient('solar', global);\n\n // Fetch full custom asset data for each\n const assets: unknown[] = [];\n for (const { id, quantity } of opts.asset) {\n const res = await solarClient.get(`/custom-asset/id/${id}`);\n assets.push({ customAsset: res.data, quantity });\n }\n\n const result = updateStudy(resolveFile(opts), (study) => {\n study.selectedCustomAssets = assets;\n return undefined;\n });\n output(result, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- set batteries ---\n set\n .command('batteries')\n .description(\n 'Enable/disable batteries and set configuration.\\n' +\n 'Example: suntropy studies set batteries --file study.json --enable --battery-id 789 --count 1'\n )\n .option('--file <path>', 'Study file path')\n .option('--enable', 'Enable batteries')\n .option('--disable', 'Disable batteries')\n .option('--battery-id <n>', 'Battery ID from inventory')\n .option('--count <n>', 'Number of batteries')\n .action(async (opts) => {\n try {\n const result = updateStudy(resolveFile(opts), (study) => {\n if (opts.enable) study.activeBatteries = true;\n if (opts.disable) study.activeBatteries = false;\n if (opts.batteryId) {\n // Store battery reference — the full battery object would be fetched when calculating\n const config = (study.batteriesConfiguration || {}) as Record<string, unknown>;\n config.batteryId = parseInt(opts.batteryId);\n if (opts.count) config.batteriesNumber = parseInt(opts.count);\n study.batteriesConfiguration = config;\n }\n return undefined;\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- set data (generic fallback) ---\n set\n .command('data')\n .description(\n 'Generic JSON merge into the study (fallback for any field).\\n' +\n 'Example: suntropy studies set data --file study.json --data \\'{\"referenceId\":\"REF-001\"}\\''\n )\n .option('--file <path>', 'Study file path')\n .requiredOption('--data <json>', 'JSON to merge into the study')\n .action(async (opts) => {\n try {\n const parsed = JSON.parse(opts.data);\n // Detect cascade fields\n const cascadeFields = Object.keys(parsed);\n let cascadeField: string | undefined;\n if (cascadeFields.includes('consumption')) cascadeField = 'consumption';\n if (cascadeFields.includes('surfaces')) cascadeField = 'surfaces';\n\n const result = updateStudy(resolveFile(opts), (study) => {\n deepMerge(study, parsed);\n return cascadeField;\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // ═══════════════════════════════════════════\n // CALCULATE — commands that call backend APIs\n // ═══════════════════════════════════════════\n\n // --- calculate production ---\n studies\n .command('calculate')\n .description('Calculate derived data for the study')\n .command('production')\n .description(\n 'Calculate production for study surfaces using backend API.\\n' +\n 'Example: suntropy studies calculate production --file study.json [--surface-index 0 | --all-surfaces]'\n )\n .option('--file <path>', 'Study file path')\n .option('--surface-index <n>', 'Calculate for specific surface index')\n .option('--all-surfaces', 'Calculate for all surfaces')\n .option('--losses <n>', 'Losses percentage', '14')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const filePath = resolveFile(opts);\n const study = readStudy(filePath);\n const surfaces = study.surfaces as Record<string, unknown>[] | undefined;\n\n if (!surfaces?.length) {\n outputError(new Error('No surfaces in study. Use: studies add surface'));\n return;\n }\n\n const solarClient = createServiceClient('solar', global);\n const indicesToCalc = opts.surfaceIndex !== undefined\n ? [parseInt(opts.surfaceIndex)]\n : Array.from({ length: surfaces.length }, (_, i) => i);\n\n for (const idx of indicesToCalc) {\n const surface = surfaces[idx];\n if (!surface) continue;\n // Coordinates: surface center → study location → drawn polygon (centroid, else first point)\n const coords = resolveSurfaceCoordinates(surface, study);\n if (!coords) {\n outputError(new Error(`Surface ${idx} has no coordinates. Use: studies add surface --lat N --lon N`));\n continue;\n }\n const { lat, lng } = coords;\n // Installed power: explicit → (panel layout | panelNumber) × panel peak power (frontend parity)\n const { installedPower, isDefault } = resolveSurfaceInstalledPower(surface, study);\n if (isDefault) {\n outputError(new Error(\n `Surface ${idx} has no resolvable installed power (no installedPower, and no panel layout / panelNumber with a solarPanel/solarKit peak power). `\n + `Using the 5000W default — production will be wrong. Set the panels and kit/panel before calculating.`,\n ));\n }\n const body = {\n lat,\n long: lng,\n instaledPower: installedPower,\n angle: (surface.inclination as number) || (surface.angle as number) || 30,\n azimuth: (surface.orientation as number) || (surface.azimuth as number) || 180,\n lossesPercentage: parseFloat(opts.losses),\n year: new Date().getFullYear(),\n isOptimized: false,\n };\n const res = await solarClient.post('/solar-study/calculateProduction', body);\n surface.production = res.data;\n }\n\n // Write back and validate\n const result = updateStudy(filePath, (s) => {\n s.surfaces = surfaces;\n return undefined; // don't cascade — we're setting production, not changing surfaces\n });\n output(result, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- calculate results ---\n studies\n .command('calculate-results')\n .description(\n 'Calculate energy results replicating frontend SolarResultCalculator.\\n' +\n 'Computes: net consumption, excesses, spending/savings by period, coverage.\\n' +\n 'Requires: consumption, production, energyPrices, atrTariff.\\n' +\n 'Example: suntropy studies calculate-results --file study.json'\n )\n .option('--file <path>', 'Study file path')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const filePath = resolveFile(opts);\n const study = readStudy(filePath);\n\n const consumption = study.consumption as { days?: unknown[]; identifier?: string } | undefined;\n if (!consumption?.days?.length) {\n outputError(new Error('No consumption curve. Use: studies set consumption'));\n return;\n }\n\n const surfaces = study.surfaces as Record<string, unknown>[] | undefined;\n if (!surfaces?.length) {\n outputError(new Error('No surfaces. Use: studies add surface'));\n return;\n }\n\n const energyPrices = study.energyPrices as ByPeriodValues | undefined;\n if (!energyPrices) {\n outputError(new Error('No energy prices. Use: studies set prices'));\n return;\n }\n\n const { PowerCurve } = await import('energy-types/lib/energy/classes/powerCurve.class.js');\n\n // Build consumption PowerCurve\n const consCurve = new PowerCurve(consumption.days, false, consumption.identifier || 'consumption', false);\n\n // Aggregate production from all surfaces (replicates SolarResultCalculator.aggregateProductionResults)\n let totalProdCurve: InstanceType<typeof PowerCurve> | null = null;\n for (const surf of surfaces) {\n const prod = surf.production as { days?: unknown[]; identifier?: string } | undefined;\n if (prod?.days?.length) {\n const surfProd = new PowerCurve(prod.days, false, prod.identifier || 'production', false);\n totalProdCurve = totalProdCurve ? totalProdCurve.aggregatePowerCurve(surfProd) : surfProd;\n }\n }\n\n if (!totalProdCurve) {\n outputError(new Error('No production curves found. Use: studies calculate production'));\n return;\n }\n\n const results: Record<string, unknown> = {};\n\n // --- Core energy calculations (always computed) ---\n\n // Net consumption = consumption - production\n const netConsumptionCurve = consCurve.aggregatePowerCurve(totalProdCurve.applyMultiplier(-1));\n results.netConsumption = netConsumptionCurve;\n\n // Total production\n results.totalProduction = totalProdCurve.getTotalAcumulate();\n\n // Consumption coverage percentage\n results.totalConsumptionCoverage =\n ((results.totalProduction as number) / consCurve.getTotalAcumulate()) * 100;\n\n // --- Period-based economic calculations (replicates SolarResultCalculator.calculateResults) ---\n const periodDistribution = await fetchPeriodDistribution(study, global);\n\n if (periodDistribution) {\n const clientDetails = study.clientDetails as Record<string, unknown> | undefined;\n const market = study.market as string | undefined;\n const oneBaseEnergyDiscountFactor = 1 - ((study.energyPricesDiscount as number) || 0) / 100;\n const oneBasePowerDiscountFactor = 1 - ((study.powerPricesDiscount as number) || 0) / 100;\n\n // Positive net consumption (filter out negatives = energy still needed from grid)\n const positiveNetConsumptionCurve = netConsumptionCurve.filterNegativeValues();\n const positiveNetByPeriod = positiveNetConsumptionCurve.aggregateByPeriod(periodDistribution);\n const rawConsumptionByPeriod = consCurve.aggregateByPeriod(periodDistribution);\n\n // Contracted power costs (if useAlternativePrices)\n const contractedPower = (study.contractedPower || {}) as ByPeriodValues;\n const powerPrices = (study.powerPrices || {}) as ByPeriodValues;\n const contractedPowerRawCostByPeriod: ByPeriodValues = {};\n if (study.useAlternativePrices) {\n for (let i = 1; i <= 6; i++) {\n const p = `p${i}`;\n if (contractedPower[p] && powerPrices[p]) {\n contractedPowerRawCostByPeriod[p] =\n (contractedPower[p] as number) * 365 * (powerPrices[p] as number) * oneBasePowerDiscountFactor;\n }\n }\n }\n\n // PT market peak cost\n if (market === 'pt') {\n const extraCostPrice = (study.extraCostPrice || {}) as ByPeriodValues;\n let numberOfP1hours = 0;\n periodDistribution.forEach((day: any) => {\n Object.values(day.valuesList).forEach((hour: any) => {\n if (hour === 1) numberOfP1hours++;\n });\n });\n const coefficient =\n (1 / numberOfP1hours) * ((extraCostPrice.p1 as number) || 0) * netConsumptionCurve.days.length;\n results.rawPeakConsumptionCostPt = ((rawConsumptionByPeriod as any)?.p1 || 0) * coefficient;\n results.netPeakConsumptionCostPt = ((positiveNetByPeriod as any)?.p1 || 0) * coefficient;\n }\n\n // Raw spending by period\n const totalRawSpendingByPeriod: ByPeriodValues = {};\n for (let i = 1; i <= 6; i++) {\n const p = `p${i}`;\n const rawConsP = (rawConsumptionByPeriod as any)?.[p] || 0;\n const priceP = (energyPrices[p] as number) || 0;\n const includeTaxes = clientDetails?.includeTaxes;\n const taxPct = (clientDetails?.taxesPercentage as number) || 0;\n const priceWithTax = includeTaxes && taxPct ? priceP * (1 + taxPct / 100) : priceP;\n totalRawSpendingByPeriod[p] =\n rawConsP * priceWithTax * oneBaseEnergyDiscountFactor +\n ((contractedPowerRawCostByPeriod[p] as number) || 0);\n }\n results.totalRawSpendingByPeriod = totalRawSpendingByPeriod;\n\n // Total raw spending\n results.totalRawSpending =\n Object.values(totalRawSpendingByPeriod)\n .filter((v): v is number => typeof v === 'number')\n .reduce((a, b) => a + b, 0) + ((results.rawPeakConsumptionCostPt as number) || 0);\n\n // Net spending by period + alternative prices\n const alternativeEnergyPrices = (study.alternativeEnergyPrices || {}) as ByPeriodValues;\n const alternativePowerPrices = (study.alternativePowerPrices || {}) as ByPeriodValues;\n const contractedPowerFinalCostByPeriod: ByPeriodValues = {};\n const contractedPowerSavingsByPeriod: ByPeriodValues = {};\n\n if (study.useAlternativePrices) {\n for (let i = 1; i <= 6; i++) {\n const p = `p${i}`;\n if (contractedPower[p] && alternativePowerPrices[p]) {\n contractedPowerFinalCostByPeriod[p] =\n (contractedPower[p] as number) * 365 * (alternativePowerPrices[p] as number);\n }\n if (contractedPower[p] && powerPrices[p] && alternativePowerPrices[p]) {\n contractedPowerSavingsByPeriod[p] =\n (contractedPower[p] as number) * 365 * (powerPrices[p] as number) * oneBasePowerDiscountFactor -\n (contractedPower[p] as number) * 365 * (alternativePowerPrices[p] as number) * oneBasePowerDiscountFactor;\n }\n }\n results.contractedPowerSavingsByPeriod = contractedPowerSavingsByPeriod;\n }\n\n const totalNetSpendingByPeriod: ByPeriodValues = {};\n const alternativeTotalNetSpendingByPeriod: ByPeriodValues = {};\n\n for (let i = 1; i <= 6; i++) {\n const p = `p${i}`;\n const posNetP = (positiveNetByPeriod as any)?.[p] || 0;\n const priceP = (energyPrices[p] as number) || 0;\n const altPriceP = (alternativeEnergyPrices[p] as number) || 0;\n const includeTaxes = clientDetails?.includeTaxes;\n const taxPct = (clientDetails?.taxesPercentage as number) || 0;\n\n totalNetSpendingByPeriod[p] =\n posNetP * (includeTaxes ? priceP * (1 + taxPct / 100) : priceP) * oneBaseEnergyDiscountFactor;\n\n if (study.alternativeEnergyPrices) {\n alternativeTotalNetSpendingByPeriod[p] =\n posNetP * altPriceP + ((contractedPowerFinalCostByPeriod[p] as number) || 0);\n }\n }\n results.totalNetSpendingByPeriod = totalNetSpendingByPeriod;\n if (study.alternativeEnergyPrices) {\n results.alternativeTotalNetSpendingByPeriod = alternativeTotalNetSpendingByPeriod;\n }\n\n // Total net spending\n results.totalNetSpending =\n Object.values(totalNetSpendingByPeriod)\n .filter((v): v is number => typeof v === 'number')\n .reduce((a, b) => a + b, 0) + ((results.netPeakConsumptionCostPt as number) || 0);\n\n // Savings by period = raw - net\n const totalSavingsByPeriod: ByPeriodValues = {};\n for (let i = 1; i <= 6; i++) {\n const p = `p${i}`;\n totalSavingsByPeriod[p] =\n ((totalRawSpendingByPeriod[p] as number) || 0) - ((totalNetSpendingByPeriod[p] as number) || 0);\n }\n results.totalSavingsByPeriod = totalSavingsByPeriod;\n\n // Alternative savings by period\n if (study.alternativeEnergyPrices) {\n const altSavings: ByPeriodValues = {};\n for (let i = 1; i <= 6; i++) {\n const p = `p${i}`;\n altSavings[p] =\n ((totalRawSpendingByPeriod[p] as number) || 0) -\n ((alternativeTotalNetSpendingByPeriod[p] as number) || 0);\n }\n results.totalSavingsByPeriodAlternativeSavings = altSavings;\n }\n\n // Total savings\n results.totalSavings =\n Object.values(totalSavingsByPeriod)\n .filter((v): v is number => typeof v === 'number')\n .reduce((a, b) => a + b, 0) +\n (((results.rawPeakConsumptionCostPt as number) || 0) -\n ((results.netPeakConsumptionCostPt as number) || 0));\n\n // Total savings with alternative prices\n if (study.alternativeEnergyPrices) {\n results.totalSavingsAlternativePrices =\n Object.values(alternativeTotalNetSpendingByPeriod)\n .filter((v): v is number => typeof v === 'number')\n .reduce((a, b) => a + b, 0) +\n (((results.rawPeakConsumptionCostPt as number) || 0) -\n ((results.netPeakConsumptionCostPt as number) || 0));\n }\n\n // Excesses curve = (production - consumption), keep positive\n const excessesCurve = totalProdCurve\n .aggregatePowerCurve(consCurve.applyMultiplier(-1))\n .filterNegativeValues();\n results.excessesCurve = excessesCurve;\n\n // Excesses by period\n results.totalExcessesByPeriod = excessesCurve.aggregateByPeriod(periodDistribution);\n results.totalExcesses = Object.values(results.totalExcessesByPeriod as ByPeriodValues)\n .filter((v): v is number => typeof v === 'number')\n .reduce((a, b) => a + b, 0);\n }\n\n const result = updateStudy(filePath, (s) => {\n s.results = results;\n return undefined;\n });\n output(result, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // ═══════════════════════════════════════════\n // OPTIMIZE PEAK POWER\n // ═══════════════════════════════════════════\n\n studies\n .command('optimize-peakpower')\n .description(\n 'Optimize peak power based on consumption.\\n\\n' +\n 'Supports two modes:\\n' +\n ' - Panel mode (default or when solarPanel is set): iterates peak power\\n' +\n ' - Kit mode (when solarKit is set or --use-kits): evaluates available kits\\n\\n' +\n 'Optimization criteria (pick one):\\n' +\n ' --energy-savings <pct> Target energy savings percentage\\n' +\n ' --raw-consumption <pct> Production as percentage of consumption\\n' +\n ' --max-excesses <pct> Max excesses as percentage of production\\n' +\n ' --max-overproduction-months <n> Max months with overproduction\\n\\n' +\n 'Surface constraints:\\n' +\n ' If surfaces have area + panel dimensions, max panels per surface is calculated.\\n' +\n ' Without area, no surface constraint is applied (unlimited space).\\n\\n' +\n 'Examples:\\n' +\n ' suntropy studies optimize-peakpower --file study.json --energy-savings 70\\n' +\n ' suntropy studies optimize-peakpower --file study.json --raw-consumption 100 --use-kits\\n' +\n ' suntropy studies optimize-peakpower --file study.json --max-excesses 15'\n )\n .option('--file <path>', 'Study file path')\n .option('--energy-savings <pct>', 'Target energy savings %')\n .option('--raw-consumption <pct>', 'Target production as % of consumption')\n .option('--max-excesses <pct>', 'Max excesses as % of production')\n .option('--max-overproduction-months <n>', 'Max months with overproduction')\n .option('--use-kits', 'Force kit mode (fetch all active kits and select optimal)')\n .option('--apply', 'Apply the result to the study file (set peakpower/kit, recalculate production)')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const filePath = resolveFile(opts);\n const study = readStudy(filePath);\n\n // Determine evaluation mode\n const evaluationMode: Record<string, number> = {};\n if (opts.energySavings !== undefined) evaluationMode.energyPercentageSavings = parseFloat(opts.energySavings);\n else if (opts.rawConsumption !== undefined) evaluationMode.rawConsumptionPercentage = parseFloat(opts.rawConsumption);\n else if (opts.maxExcesses !== undefined) evaluationMode.maxExcessesPercentage = parseFloat(opts.maxExcesses);\n else if (opts.maxOverproductionMonths !== undefined) evaluationMode.maxNumberOfOverproductionMonths = parseInt(opts.maxOverproductionMonths);\n else {\n // Default: 100% raw consumption (match consumption)\n evaluationMode.rawConsumptionPercentage = 100;\n }\n\n // Validate study has consumption and production\n const surfaces = study.surfaces as Record<string, unknown>[] | undefined;\n if (!surfaces?.length) {\n outputError(new Error('No surfaces in study. Use: studies add surface'));\n return;\n }\n const consumptionData = study.consumption as Record<string, unknown> | undefined;\n if (!consumptionData) {\n outputError(new Error('No consumption in study. Use: studies set consumption'));\n return;\n }\n\n // Check all surfaces have production\n const surfacesWithoutProduction = surfaces.filter((s) => !s.production);\n if (surfacesWithoutProduction.length > 0) {\n outputError(new Error(`${surfacesWithoutProduction.length} surface(s) without production. Use: studies calculate production --all-surfaces`));\n return;\n }\n\n const { PowerCurve } = await import('energy-types/lib/energy/classes/powerCurve.class.js');\n\n // Build consumption PowerCurve\n const cd = consumptionData as any;\n const consumptionCurve = new PowerCurve(cd.days || cd, cd.ignore0 ?? false, cd.identifier || 'consumption', cd.parseDate ?? false);\n const totalConsumption = consumptionCurve.getTotalAcumulate();\n\n // Build base production (1 kWp) for each surface\n const baseProduction: Record<string, any> = {};\n for (const surface of surfaces) {\n const sid = surface.surfaceId as string;\n const prodData = surface.production as any;\n const prodCurve = new PowerCurve(prodData.days || prodData, false, sid, false);\n const installedPower = (surface.installedPower as number) || 5000;\n // Normalize to 1kWp base\n baseProduction[sid] = prodCurve.applyMultiplier(1 / (installedPower / 1000));\n }\n\n // Determine mode: kit vs panel\n const useKits = opts.useKits || study.peakPowerIntroductionMode === 'solarKit';\n const solarClient = createServiceClient('solar', global);\n\n if (useKits) {\n // ── KIT MODE ──\n const phaseNumber = (study.phaseNumber as string) || 'single_phase';\n\n // Fetch all active kits\n const kitsRes = await solarClient.get('/solar-kits', { params: { limit: 500 } });\n let allKits = Array.isArray(kitsRes.data) && Array.isArray(kitsRes.data[0])\n ? kitsRes.data[0]\n : (Array.isArray(kitsRes.data) ? kitsRes.data : kitsRes.data?.data || []);\n\n // Filter by phase\n allKits = allKits.filter((k: any) => k.phaseNumber === phaseNumber && k.active !== false);\n\n // Check coplanar compatibility\n const isCoplanar = surfaces.every((s) => !(s.panelInclination as number));\n allKits = allKits.filter((k: any) =>\n isCoplanar === undefined ? true : isCoplanar === (k.coplanar === null ? true : k.coplanar)\n );\n\n // Sort by peak power ascending (smallest first)\n allKits.sort((a: any, b: any) =>\n (a.panelNumber * (a.kitSolarPanel?.peakPower || 0)) - (b.panelNumber * (b.kitSolarPanel?.peakPower || 0))\n );\n\n if (allKits.length === 0) {\n outputError(new Error('No compatible kits found for current phase/surface configuration'));\n return;\n }\n\n let selectedKit: any = null;\n let bestApproxKit: any = null;\n let bestApproxValue = -Infinity;\n let firstValidKit: any = null;\n const optimizationLog: Record<number, any> = {};\n\n for (const kit of allKits) {\n const kitPanel = kit.kitSolarPanel;\n if (!kitPanel) continue;\n\n // Distribute panels across surfaces\n let remainingPanels = kit.panelNumber || 0;\n const surfPanelCount: Record<string, number> = {};\n let fits = true;\n\n for (const surface of surfaces) {\n const sid = surface.surfaceId as string;\n const area = surface.area as number | undefined;\n let maxPanels: number;\n\n if (area && kitPanel.width && kitPanel.heigth) {\n // Calculate max panels from area\n maxPanels = calculateMaxPanels(\n area,\n kitPanel,\n (surface.availableAreaPercentage as number) || 85,\n (surface.panelInclination as number) || 0,\n (surface.inclination as number) || 0,\n (surface.panelPosition as string) || 'vertical',\n resolveSurfaceCoordinates(surface, study)?.lat ?? 37,\n );\n } else {\n // No area constraint — unlimited\n maxPanels = remainingPanels;\n }\n\n const assigned = Math.min(remainingPanels, maxPanels);\n surfPanelCount[sid] = assigned;\n remainingPanels -= assigned;\n }\n\n if (remainingPanels > 0) continue; // Kit doesn't fit\n\n if (!firstValidKit) firstValidKit = kit;\n\n // Calculate production for this kit\n let totalProd: any = null;\n for (const surface of surfaces) {\n const sid = surface.surfaceId as string;\n const panelCount = surfPanelCount[sid] || 0;\n const surfPeakPower = (panelCount * kitPanel.peakPower) / 1000;\n const surfProd = baseProduction[sid].applyMultiplier(surfPeakPower);\n totalProd = totalProd ? totalProd.aggregatePowerCurve(surfProd) : surfProd;\n }\n\n const netConsumption = consumptionCurve.aggregatePowerCurve(totalProd.applyMultiplier(-1));\n const kitPeakPower = ((kit.panelNumber || 0) * kitPanel.peakPower) / 1000;\n const totalProdKwh = totalProd.getTotalAcumulate();\n\n // Evaluate criteria\n let criterionValue: number;\n let criterionMet = false;\n\n if (evaluationMode.energyPercentageSavings !== undefined) {\n const netFiltered = netConsumption.filterNegativeValues().getTotalAcumulate();\n criterionValue = ((totalConsumption - netFiltered) / totalConsumption) * 100;\n criterionMet = criterionValue >= evaluationMode.energyPercentageSavings;\n } else if (evaluationMode.rawConsumptionPercentage !== undefined) {\n criterionValue = (totalProdKwh / totalConsumption) * 100;\n criterionMet = criterionValue >= evaluationMode.rawConsumptionPercentage;\n } else if (evaluationMode.maxExcessesPercentage !== undefined) {\n const excessesCurve = netConsumption.filterPositiveValues();\n criterionValue = (excessesCurve.getTotalAcumulate() / totalProdKwh) * 100 * -1;\n criterionMet = criterionValue <= evaluationMode.maxExcessesPercentage;\n } else if (evaluationMode.maxNumberOfOverproductionMonths !== undefined) {\n const stats = netConsumption.calculateStatistics().statistics.anualMonthAccumulate;\n let byMonth = stats[Object.keys(stats).find((k) => k !== 'definition') || ''] || {};\n delete byMonth.yearly;\n criterionValue = Object.values(byMonth).filter((v: any) => v < 0).length;\n criterionMet = criterionValue <= evaluationMode.maxNumberOfOverproductionMonths;\n } else {\n criterionValue = 0;\n }\n\n optimizationLog[kit.idSolarKit] = {\n identifier: kit.identifier,\n peakPower: kitPeakPower,\n totalProduction: totalProdKwh,\n criterionValue,\n criterionMet,\n panelDistribution: surfPanelCount,\n };\n\n if (criterionValue > bestApproxValue) {\n bestApproxValue = criterionValue;\n bestApproxKit = kit;\n }\n\n if (criterionMet) {\n selectedKit = kit;\n break;\n }\n }\n\n if (!selectedKit) {\n selectedKit = bestApproxKit || firstValidKit;\n }\n\n const resultData: Record<string, unknown> = {\n mode: 'kit',\n evaluationMode,\n selectedKit: selectedKit ? {\n idSolarKit: selectedKit.idSolarKit,\n identifier: selectedKit.identifier,\n peakPower: ((selectedKit.panelNumber || 0) * (selectedKit.kitSolarPanel?.peakPower || 0)) / 1000,\n panelNumber: selectedKit.panelNumber,\n price: selectedKit.price,\n } : null,\n kitsEvaluated: Object.keys(optimizationLog).length,\n optimizationLog,\n };\n\n if (opts.apply && selectedKit) {\n updateStudy(filePath, (s) => {\n s.solarKit = selectedKit;\n s.peakPowerIntroductionMode = 'solarKit';\n s.solarPanel = undefined;\n s.solarInverters = undefined;\n s.peakPowerOptimizationMethod = evaluationMode;\n return undefined;\n });\n resultData.applied = true;\n }\n\n output(resultData, global);\n } else {\n // ── PANEL MODE ──\n const panel = study.solarPanel as Record<string, unknown> | undefined;\n if (!panel) {\n outputError(new Error('No solar panel set. Use: studies set panel --panel-id <id>'));\n return;\n }\n\n const panelPeakPower = (panel.peakPower as number) || 450;\n const panelWidth = (panel.width as number) || 1134;\n const panelHeight = (panel.heigth as number) || (panel.height as number) || 1762;\n const panelObj = { peakPower: panelPeakPower, width: panelWidth, heigth: panelHeight };\n\n // Calculate max peak power per surface\n const surfacesMaxPeakPower: Record<string, number> = {};\n let totalMaxPeakPower = 0;\n\n for (const surface of surfaces) {\n const sid = surface.surfaceId as string;\n const area = surface.area as number | undefined;\n\n if (area && panelWidth && panelHeight) {\n const maxPanels = calculateMaxPanels(\n area,\n panelObj,\n (surface.availableAreaPercentage as number) || 85,\n (surface.panelInclination as number) || 0,\n (surface.inclination as number) || 0,\n (surface.panelPosition as string) || 'vertical',\n resolveSurfaceCoordinates(surface, study)?.lat ?? 37,\n );\n surfacesMaxPeakPower[sid] = (maxPanels * panelPeakPower) / 1000;\n } else {\n // No area constraint — use large value (500 kWp per surface)\n surfacesMaxPeakPower[sid] = 500;\n }\n totalMaxPeakPower += surfacesMaxPeakPower[sid];\n }\n\n // Determine iteration direction and initial value\n const isAscending = evaluationMode.energyPercentageSavings !== undefined\n || evaluationMode.economicPercentageSavings !== undefined\n || evaluationMode.rawConsumptionPercentage !== undefined;\n\n let peakPower = isAscending ? panelPeakPower / 1000 : totalMaxPeakPower;\n const optimizationLog: Record<number, any> = {};\n let resultPeakPower: Record<string, number> = {};\n let lastResult: number | undefined;\n const MAX_ITERATIONS = 200;\n const TOLERANCE = 0.005;\n let correctionFactor = 1;\n let itersSinceCorrection = 0;\n\n for (let iter = 0; iter < MAX_ITERATIONS && peakPower > 0 && peakPower <= totalMaxPeakPower; iter++) {\n peakPower = parseFloat(peakPower.toFixed(2));\n itersSinceCorrection++;\n\n if (itersSinceCorrection >= 20) {\n correctionFactor += 1.1;\n itersSinceCorrection = 0;\n }\n\n // Calculate change rate\n let changeRate: number;\n if (peakPower < 20) changeRate = (panelPeakPower / 1000) * correctionFactor;\n else if (peakPower < 500) changeRate = 5 * correctionFactor;\n else changeRate = 50 * correctionFactor;\n\n // Distribute peak power across surfaces\n let remaining = peakPower;\n let totalProd: any = null;\n resultPeakPower = {};\n\n for (const surface of surfaces) {\n const sid = surface.surfaceId as string;\n const surfPP = Math.min(remaining, surfacesMaxPeakPower[sid]);\n remaining -= surfPP;\n resultPeakPower[sid] = surfPP;\n const surfProd = baseProduction[sid].applyMultiplier(surfPP);\n totalProd = totalProd ? totalProd.aggregatePowerCurve(surfProd) : surfProd;\n }\n\n const netConsumption = consumptionCurve.aggregatePowerCurve(totalProd.applyMultiplier(-1));\n const totalProdKwh = totalProd.getTotalAcumulate();\n\n // Evaluate criterion\n let criterionValue: number;\n let criterionMet = false;\n\n if (evaluationMode.energyPercentageSavings !== undefined) {\n const netFiltered = netConsumption.filterNegativeValues().getTotalAcumulate();\n criterionValue = ((totalConsumption - netFiltered) / totalConsumption) * 100;\n criterionMet = criterionValue >= evaluationMode.energyPercentageSavings;\n } else if (evaluationMode.rawConsumptionPercentage !== undefined) {\n criterionValue = (totalProdKwh / totalConsumption) * 100;\n criterionMet = criterionValue >= evaluationMode.rawConsumptionPercentage;\n } else if (evaluationMode.maxExcessesPercentage !== undefined) {\n const excessesCurve = netConsumption.filterPositiveValues();\n criterionValue = (excessesCurve.getTotalAcumulate() / totalProdKwh) * 100 * -1;\n criterionMet = criterionValue <= evaluationMode.maxExcessesPercentage;\n } else if (evaluationMode.maxNumberOfOverproductionMonths !== undefined) {\n const stats = netConsumption.calculateStatistics().statistics.anualMonthAccumulate;\n let byMonth = stats[Object.keys(stats).find((k) => k !== 'definition') || ''] || {};\n delete byMonth.yearly;\n criterionValue = Object.values(byMonth).filter((v: any) => v < 0).length;\n criterionMet = criterionValue <= evaluationMode.maxNumberOfOverproductionMonths;\n } else {\n criterionValue = 0;\n }\n\n optimizationLog[peakPower] = {\n totalProduction: totalProdKwh,\n criterionValue,\n criterionMet,\n surfacesPeakpower: { ...resultPeakPower },\n };\n\n if (criterionMet) break;\n\n // Tolerance check — stop if no meaningful progress\n if (isAscending && lastResult !== undefined && lastResult * (1 + TOLERANCE) >= criterionValue) {\n break;\n }\n lastResult = criterionValue;\n\n peakPower += isAscending ? changeRate : -changeRate;\n }\n\n // Compute final totals\n const totalOptimizedPeakPower = Object.values(resultPeakPower).reduce((a, b) => a + b, 0);\n const totalPanels = Math.round(totalOptimizedPeakPower / (panelPeakPower / 1000));\n\n const resultData: Record<string, unknown> = {\n mode: 'panel',\n evaluationMode,\n optimizedPeakPower: parseFloat(totalOptimizedPeakPower.toFixed(2)),\n estimatedPanels: totalPanels,\n surfacesPeakpower: resultPeakPower,\n iterations: Object.keys(optimizationLog).length,\n optimizationLog,\n };\n\n if (opts.apply) {\n updateStudy(filePath, (s) => {\n const surfs = s.surfaces as Record<string, unknown>[] | undefined;\n if (surfs) {\n for (const surf of surfs) {\n const sid = surf.surfaceId as string;\n if (resultPeakPower[sid] !== undefined) {\n const surfPanels = Math.round(resultPeakPower[sid] / (panelPeakPower / 1000));\n surf.panelNumber = surfPanels;\n surf.installedPower = resultPeakPower[sid] * 1000;\n }\n }\n }\n s.peakPowerOptimizationMethod = evaluationMode;\n return 'surfaces';\n });\n resultData.applied = true;\n }\n\n output(resultData, global);\n }\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // ═══════════════════════════════════════════\n // COMMENTS\n // ═══════════════════════════════════════════\n\n // --- add comment (local study file) ---\n studies\n .command('add-comment')\n .description(\n 'Add a comment to the local study file.\\n' +\n 'Example: suntropy studies add-comment --file study.json --content \"Panel layout reviewed\"'\n )\n .option('--file <path>', 'Study file path')\n .requiredOption('--content <text>', 'Comment text')\n .action(async (opts) => {\n try {\n const result = updateStudy(resolveFile(opts), (study) => {\n const comments = (study.comments || []) as Record<string, unknown>[];\n comments.push(createComment('commented', opts.content));\n study.comments = comments;\n return undefined;\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- comment (API — add to existing study in backend) ---\n studies\n .command('comment <studyId>')\n .description(\n 'Add a comment to an existing study via API.\\n' +\n 'Example: suntropy studies comment abc123 --content \"Revisado por agente\"'\n )\n .requiredOption('--content <text>', 'Comment text')\n // Hidden flags for the \"Tag de Alexandria en comentarios\" workflow (sprint\n // Suntropy AI). They are intentionally omitted from --help / docs: the\n // Alexandria agent is instructed to use them in that specific workflow only.\n // - `--as-alexandria` signs the comment as Alexandria.\n // - `--reply-to-user`/`--reply-to-name` prepend a mention `@[name](userUID)`\n // with the markup the backend parses to notify that user.\n .addOption(new Option('--as-alexandria').hideHelp())\n .addOption(new Option('--reply-to-user <userUID>').hideHelp())\n .addOption(new Option('--reply-to-name <name>').hideHelp())\n .action(async (studyId, opts) => {\n try {\n assertStudyObjectId(studyId);\n const global = getGlobalOpts(studies);\n const client = createServiceClient('solar', global);\n const comment = createComment('commented', opts.content, {\n asAlexandria: Boolean(opts.asAlexandria),\n replyToUser: opts.replyToUser,\n replyToName: opts.replyToName,\n });\n const res = await client.post(`/solar-study/addSolarStudyComment/${studyId}`, comment);\n // The endpoint returns the FULL updated study (and an EMPTY body when the\n // study isn't found). Keep the guard so we never report a non-saved\n // comment as success, but DON'T dump the whole study: emit a compact\n // confirmation of the comment that was created.\n const saved = assertFound(res.data, 'Solar study', studyId) as {\n comments?: unknown[];\n };\n output(\n {\n success: true,\n message: `Comentario añadido al estudio ${studyId}`,\n studyId,\n commentsCount: Array.isArray(saved.comments)\n ? saved.comments.length\n : undefined,\n comment: {\n type: comment.type,\n creationUserUID: comment.creationUserUID,\n creationTimestamp: comment.creationTimestamp,\n aiGenerated: comment.aiGenerated ?? false,\n content: comment.content,\n },\n },\n global,\n );\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n\n// ─── Helpers ───\n\n/** Generate consumption curve from REE profile + period/monthly data using energy-types */\nasync function generateFromProfile(\n global: OutputOptions & Record<string, unknown>,\n tariff: string,\n market: string,\n year: number,\n mode: 'CONSUMPTION_BY_PERIOD' | 'MONTH_CONSUMPTION' | 'MONTHLY_BY_PERIOD',\n data: unknown,\n): Promise<unknown> {\n const profilesClient = createServiceClient('profiles', global);\n const periodsClient = createServiceClient('periods', global);\n\n // 1. Fetch REE profile\n const profileRes = await profilesClient.get('/ree-profiles', {\n params: {\n startDate: `${year}-01-01`,\n endDate: `${year}-12-31`,\n tariff,\n type: 'Final',\n market,\n },\n });\n const profile = profileRes.data?.profile || profileRes.data;\n if (!profile || !Array.isArray(profile) || profile.length === 0) {\n throw new Error('Failed to fetch REE profiles');\n }\n\n // 2. Import energy-types\n const { applyProfileToConsumption, ConsumptionIntroductionModes } =\n await import('energy-types/lib/energy/calculations/applyProfileToConsumption.js');\n\n if (mode === 'CONSUMPTION_BY_PERIOD') {\n // Need period distribution\n const tariffIdMap: Record<string, number> = { '2.0TD': 13, '3.0TD': 14, '6.1TD': 15 };\n const tariffId = tariffIdMap[tariff] || 14;\n const periodsRes = await periodsClient.get('/periodos', {\n params: {\n idTarifa: tariffId,\n idZona: 1,\n fechaInicio: `${year}-01-01`,\n fechaFin: `${year}-12-31`,\n market,\n },\n });\n const periodDistribution = periodsRes.data;\n\n const result = applyProfileToConsumption(\n ConsumptionIntroductionModes.CONSUMPTION_BY_PERIOD,\n profile,\n data,\n periodDistribution,\n );\n return result;\n\n } else if (mode === 'MONTH_CONSUMPTION') {\n // Transform flat {month: value} into {year: {month: value}} expected by energy-types\n const flatData = data as Record<string, number>;\n const yearMonthData: Record<number, Record<number, number>> = { [year]: {} };\n for (const [month, value] of Object.entries(flatData)) {\n yearMonthData[year][parseInt(month)] = value;\n }\n const result = applyProfileToConsumption(\n ConsumptionIntroductionModes.MONTH_CONSUMPTION,\n profile,\n yearMonthData,\n );\n return result;\n\n } else if (mode === 'MONTHLY_BY_PERIOD') {\n // For monthly by period, we need to process month by month\n // This is more complex — for now, use the MONTH_CONSUMPTION as fallback\n // with aggregated monthly totals\n const monthlyData = data as Record<string, Record<string, number>>;\n const monthTotals: Record<string, number> = {};\n for (const [month, periods] of Object.entries(monthlyData)) {\n monthTotals[month] = Object.values(periods).reduce((a, b) => a + b, 0);\n }\n const result = applyProfileToConsumption(\n ConsumptionIntroductionModes.MONTH_CONSUMPTION,\n profile,\n monthTotals,\n );\n return result;\n }\n\n throw new Error(`Unknown consumption mode: ${mode}`);\n}\n\n/** Calculate max panels that fit in an area (replicates frontend calculateSolarPanelsInArea) */\nfunction calculateMaxPanels(\n areaM2: number,\n panel: { width: number; heigth: number; peakPower?: number },\n availablePercentage: number,\n panelInclination: number,\n surfaceInclination: number,\n panelPosition: string,\n latitude: number,\n): number {\n const { heigth, width } = panel;\n // Convert m² to mm² and apply available percentage\n let area = areaM2 * 1000000 * (availablePercentage / 100);\n const x = 1 / Math.atan(61 - (latitude - surfaceInclination));\n let totalPanelNumber: number;\n\n if (panelPosition === 'horizontal') {\n const h = width * Math.asin(panelInclination * (Math.PI / 180));\n const minimumDistance = x * h;\n const panelArea = (heigth + 20) * (width + minimumDistance);\n totalPanelNumber = area / panelArea;\n } else {\n const h = heigth * Math.asin(panelInclination * (Math.PI / 180));\n const minimumDistance = x * h;\n const panelArea = (width + 20) * (heigth + minimumDistance);\n totalPanelNumber = area / panelArea;\n }\n\n return isNaN(totalPanelNumber) ? 0 : Math.floor(totalPanelNumber);\n}\n\n/** Collector for repeatable --asset <id:qty> */\nfunction collectAssets(value: string, previous: { id: number; quantity: number }[]): { id: number; quantity: number }[] {\n const [idStr, qtyStr] = value.split(':');\n const id = parseInt(idStr);\n const quantity = qtyStr ? parseInt(qtyStr) : 1;\n if (isNaN(id)) throw new Error(`Invalid asset format: \"${value}\". Use <id>:<quantity>`);\n return [...previous, { id, quantity }];\n}\n\n/** Fetch period distribution from periods service (needed for economic calculations) */\nasync function fetchPeriodDistribution(\n study: Study,\n global: OutputOptions & Record<string, unknown>,\n): Promise<unknown[] | null> {\n const atrTariff = study.atrTariff as Record<string, unknown> | undefined;\n const geoZone = study.geographicalZone as Record<string, unknown> | undefined;\n if (!atrTariff) return null;\n\n const tariffId = atrTariff.idTarifaATR as number;\n const zoneId = (geoZone?.idZona as number) || 1;\n const market = (study.market as string) || 'es';\n const year = new Date().getFullYear();\n\n try {\n const periodsClient = createServiceClient('periods', global);\n const res = await periodsClient.get('/periodos', {\n params: {\n idTarifa: tariffId,\n idZona: zoneId,\n fechaInicio: `${year}-01-01`,\n fechaFin: `${year}-12-31`,\n market,\n },\n });\n const data = res.data;\n if (Array.isArray(data) && data.length > 0) return data;\n return null;\n } catch {\n return null;\n }\n}\n\ninterface CreateCommentExtra {\n /** Sign the comment as Alexandria (AI assistant) instead of the active user. */\n asAlexandria?: boolean;\n /** userUID to mention at the start of the comment so the backend notifies them. */\n replyToUser?: string;\n /** Display name for the mentioned user (defaults to the userUID). */\n replyToName?: string;\n}\n\n/** Create a study comment (replicates frontend createNewComment) */\nfunction createComment(\n type: string,\n content?: string,\n extra?: CreateCommentExtra\n): Record<string, unknown> {\n const config = loadConfig();\n const profile = getActiveProfile(config);\n const autoContent: Record<string, string> = {\n created: 'Estudio creado via CLI',\n modified: 'Estudio actualizado via CLI',\n };\n\n let body = content || autoContent[type] || '';\n // Prepend a mention so the backend parses it and notifies the user. The\n // markup must match react-mentions / the backend regex: @[name](userUID).\n if (extra?.replyToUser) {\n const name = extra.replyToName || extra.replyToUser;\n body = `@[${name}](${extra.replyToUser}) ${body}`.trim();\n }\n\n const comment: Record<string, unknown> = {\n content: body,\n type,\n creationTimestamp: new Date().toISOString(),\n creationUserUID: extra?.asAlexandria\n ? 'alexandria'\n : profile.userUID || 'cli-agent',\n };\n // Mark AI-authored comments so the frontend renders them as Alexandria.\n if (extra?.asAlexandria) {\n comment.aiGenerated = true;\n }\n return comment;\n}\n","import crypto from 'crypto';\nconst rnds8Pool = new Uint8Array(256); // # of random values to pre-allocate\n\nlet poolPtr = rnds8Pool.length;\nexport default function rng() {\n if (poolPtr > rnds8Pool.length - 16) {\n crypto.randomFillSync(rnds8Pool);\n poolPtr = 0;\n }\n\n return rnds8Pool.slice(poolPtr, poolPtr += 16);\n}","export default /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i;","import REGEX from './regex.js';\n\nfunction validate(uuid) {\n return typeof uuid === 'string' && REGEX.test(uuid);\n}\n\nexport default validate;","import validate from './validate.js';\n/**\n * Convert array of 16 byte values to UUID string format of the form:\n * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX\n */\n\nconst byteToHex = [];\n\nfor (let i = 0; i < 256; ++i) {\n byteToHex.push((i + 0x100).toString(16).substr(1));\n}\n\nfunction stringify(arr, offset = 0) {\n // Note: Be careful editing this code! It's been tuned for performance\n // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434\n const uuid = (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase(); // Consistency check for valid UUID. If this throws, it's likely due to one\n // of the following:\n // - One or more input array values don't map to a hex octet (leading to\n // \"undefined\" in the uuid)\n // - Invalid input values for the RFC `version` or `variant` fields\n\n if (!validate(uuid)) {\n throw TypeError('Stringified UUID is invalid');\n }\n\n return uuid;\n}\n\nexport default stringify;","import rng from './rng.js';\nimport stringify from './stringify.js';\n\nfunction v4(options, buf, offset) {\n options = options || {};\n const rnds = options.random || (options.rng || rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`\n\n rnds[6] = rnds[6] & 0x0f | 0x40;\n rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided\n\n if (buf) {\n offset = offset || 0;\n\n for (let i = 0; i < 16; ++i) {\n buf[offset + i] = rnds[i];\n }\n\n return buf;\n }\n\n return stringify(rnds);\n}\n\nexport default v4;","import { Command } from 'commander';\nimport { createServiceClient, handleApiError, assertFound, assertStudyObjectId } from '../../client.js';\nimport { output, outputError, outputPaginated, type OutputOptions } from '../../output.js';\nimport { registerStudyBuilderCommands } from './builder.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\n/** Replace PowerCurve objects with lightweight summaries to save tokens */\nfunction compactCurves(obj: unknown): unknown {\n if (obj === null || obj === undefined || typeof obj !== 'object') return obj;\n if (Array.isArray(obj)) return obj.map(compactCurves);\n\n const record = obj as Record<string, unknown>;\n\n // Detect PowerCurve: has 'days' array with objects containing 'valuesList'\n if (Array.isArray(record.days) && record.days.length > 0 && record.identifier !== undefined) {\n return { _type: 'PowerCurve', days: record.days.length, identifier: record.identifier };\n }\n\n // Detect inline DayCurve arrays (consumption, production fields that are PowerCurve-like)\n const result: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(record)) {\n if (val && typeof val === 'object' && !Array.isArray(val)) {\n const v = val as Record<string, unknown>;\n if (Array.isArray(v.days) && v.days.length > 0 && v.identifier !== undefined) {\n result[key] = { _type: 'PowerCurve', days: v.days.length, identifier: v.identifier };\n continue;\n }\n }\n result[key] = compactCurves(val);\n }\n return result;\n}\n\n/** Expand sections: pick which parts of study to include */\nconst EXPAND_SECTIONS: Record<string, string[]> = {\n surfaces: ['surfaces'],\n results: ['results'],\n economics: ['economicResults'],\n batteries: ['activeBatteries', 'batteriesConfiguration', 'batteriesEnergyBalance', 'batteriesResults', 'bateries'],\n consumption: ['consumption', 'consumptionIntroductionMode', 'monthConsumptionDictionary', 'monthPeriodConsumptionDictionary', 'periodConsumptionDictionary'],\n equipment: ['solarPanel', 'solarKit', 'solarInverters', 'selectedChargers', 'selectedCustomAssets'],\n client: ['clientDetails', 'clientsDetails'],\n location: ['location', 'mapCenter', 'geographicalZone', 'atrTariff'],\n};\n\n/**\n * Fields that users often ask for on the study but actually live on the\n * metadata entity (MySQL) — surfaced via `studies list` or `studies metadata`.\n */\nconst METADATA_ONLY_FIELDS: Record<string, string> = {\n peakPower: 'metadata',\n sellingPrice: 'metadata',\n totalCost: 'metadata',\n anualProduction: 'metadata',\n anualConsumption: 'metadata',\n currentState: 'metadata',\n clientName: 'metadata',\n idSolarStudyMetadata: 'metadata',\n solarStudyId: 'metadata',\n};\n\n/**\n * Fields that don't exist on either the study document or its metadata —\n * they are computed client-side (builder) or simply don't exist in this API.\n */\nconst COMPUTED_OR_UNKNOWN_FIELDS: Record<string, string> = {\n completionPercentage: 'computed by `studies validate` / `studies save` from stepsProgress',\n isCompleted: 'not a persisted field; derive from solarStudyProgress or completionPercentage',\n stepsProgress: 'computed by `studies validate` / `studies save`',\n};\n\nfunction explainMissingStudyFields(missing: string[], studyId: string): void {\n const metadataFields = missing.filter(f => f in METADATA_ONLY_FIELDS);\n const computedFields = missing.filter(f => f in COMPUTED_OR_UNKNOWN_FIELDS);\n const unknownFields = missing.filter(f => !(f in METADATA_ONLY_FIELDS) && !(f in COMPUTED_OR_UNKNOWN_FIELDS));\n\n const lines: string[] = [];\n lines.push(`warning: ${missing.length} requested field(s) are not present on the study document returned by findById.`);\n\n if (metadataFields.length > 0) {\n lines.push('');\n lines.push(` These fields live on the STUDY METADATA (MySQL), not on the study document:`);\n for (const f of metadataFields) lines.push(` - ${f}`);\n lines.push(` Use: suntropy studies metadata ${studyId} --by-study-id --fields ${metadataFields.join(',')}`);\n lines.push(` Or: suntropy studies list --client-name <name> (list already projects these fields)`);\n }\n\n if (computedFields.length > 0) {\n lines.push('');\n lines.push(` These fields are not persisted on the study:`);\n for (const f of computedFields) lines.push(` - ${f}: ${COMPUTED_OR_UNKNOWN_FIELDS[f]}`);\n lines.push(` Use: suntropy studies validate ${studyId} (returns stepsProgress + completionPercentage)`);\n }\n\n if (unknownFields.length > 0) {\n lines.push('');\n lines.push(` These fields were not found on the study document:`);\n for (const f of unknownFields) lines.push(` - ${f}`);\n lines.push(` If you expected them, try: suntropy studies get ${studyId} --expand all --format json`);\n lines.push(` and inspect the full payload to locate the correct field path.`);\n }\n\n process.stderr.write(lines.join('\\n') + '\\n');\n}\n\n/** Core identity fields always included in get */\nconst CORE_FIELDS = [\n '_id', 'id', 'name', 'identifier', 'clientUID',\n 'creationTimestamp', 'lastEditTimestamp',\n 'assignedUserUID', 'creationUserUID',\n 'selectedSolarStudyMode', 'solarStudyProgress',\n 'market', 'layout',\n 'peakPowerIntroductionMode', 'instalationPhaseNumber',\n];\n\nfunction filterStudy(study: Record<string, unknown>, expand?: string): Record<string, unknown> {\n if (expand === 'all') return study;\n\n const sections = expand ? expand.split(',').map(s => s.trim()) : [];\n const allowedFields = new Set(CORE_FIELDS);\n\n for (const section of sections) {\n const fields = EXPAND_SECTIONS[section];\n if (fields) fields.forEach(f => allowedFields.add(f));\n }\n\n // If no expand, include summary numeric fields\n if (sections.length === 0) {\n ['peakPowerIntroductionMode', 'instalationPhaseNumber', 'location', 'atrTariff'].forEach(f => allowedFields.add(f));\n }\n\n const result: Record<string, unknown> = {};\n for (const key of allowedFields) {\n if (key in study) result[key] = study[key];\n }\n\n return compactCurves(result) as Record<string, unknown>;\n}\n\nexport function registerStudiesCommands(program: Command): void {\n const studies = program.command('studies').description(\n 'Explore and manage solar studies. Progressive exploration: list → metadata → get → get --expand → curves'\n );\n\n // --- list ---\n studies\n .command('list')\n .description('List solar studies metadata. Fields: idSolarStudyMetadata, solarStudyId, clientName, peakPower, currentState, creationTimestamp')\n .option('--limit <n>', 'Max results', '20')\n .option('--offset <n>', 'Skip results', '0')\n .option('--state <state>', 'Filter by state name')\n .option('--client-name <name>', 'Filter by client name')\n .option('--from <date>', 'Filter from date (YYYY-MM-DD)')\n .option('--to <date>', 'Filter to date (YYYY-MM-DD)')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const client = createServiceClient('solar', global);\n const body: Record<string, unknown> = {\n limit: parseInt(opts.limit),\n offset: parseInt(opts.offset),\n };\n if (opts.state) body.state = opts.state;\n if (opts.clientName) body.clientName = opts.clientName;\n if (opts.from) body.fromDate = opts.from;\n if (opts.to) body.toDate = opts.to;\n\n const res = await client.post('/solar-study/findWithPaginationAndFilters', body);\n // Response: [items[], totalCount, ...] tuple or {data, total}\n let data: unknown[];\n let total: number;\n if (Array.isArray(res.data) && res.data.length >= 2 && Array.isArray(res.data[0]) && typeof res.data[1] === 'number') {\n data = res.data[0];\n total = res.data[1];\n } else if (Array.isArray(res.data)) {\n data = res.data;\n total = res.data.length;\n } else {\n data = res.data?.data || res.data?.solarStudiesMetadata || [];\n total = res.data?.total ?? res.data?.count ?? (Array.isArray(data) ? data.length : 0);\n }\n\n const outOpts: OutputOptions = { ...global };\n if (!global.fields) {\n outOpts.fields = 'idSolarStudyMetadata,solarStudyId,clientName,peakPower,anualProduction,anualConsumption,totalCost,sellingPrice,currentState,creationTimestamp';\n }\n outputPaginated(data, total, parseInt(opts.limit), parseInt(opts.offset), outOpts);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- metadata ---\n studies\n .command('metadata <id>')\n .description('Get solar study metadata by metadata ID (relational). Full MySQL record with state, costs, versions.')\n .option('--by-study-id', 'Interpret <id> as MongoDB solarStudyId instead of metadata ID')\n .action(async (id, opts) => {\n try {\n // --by-study-id resolves against the MongoDB solarStudyId, so guard it\n // the same way as `get`; the default path uses a numeric metadata id.\n if (opts.byStudyId) assertStudyObjectId(id);\n const global = getGlobalOpts(studies);\n const client = createServiceClient('solar', global);\n const path = opts.byStudyId\n ? `/solar-study/metadata/solar-study-id/${id}`\n : `/solar-study/findSolarStudyMetadataById/${id}`;\n const res = await client.get(path);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- get ---\n studies\n .command('get <studyId>')\n .description(\n 'Get solar study by MongoDB ID. By default returns summary (no heavy curves).\\n' +\n 'Expand sections: surfaces, results, economics, batteries, consumption, equipment, client, location\\n' +\n 'Examples:\\n' +\n ' suntropy studies get abc123\\n' +\n ' suntropy studies get abc123 --expand surfaces,results\\n' +\n ' suntropy studies get abc123 --expand all\\n' +\n ' suntropy studies get abc123 --fields name,market (bypasses expand filter)'\n )\n .option('--expand <sections>', 'Comma-separated sections to expand (or \"all\")')\n .action(async (studyId, opts) => {\n try {\n assertStudyObjectId(studyId);\n const global = getGlobalOpts(studies);\n const client = createServiceClient('solar', global);\n const res = await client.get(`/solar-study/findById/${studyId}`);\n const study = assertFound(res.data, 'Solar study', studyId) as Record<string, unknown>;\n // If the user passes --fields, they have already expressed exactly what\n // they want — don't pre-filter the study, let output() select from the\n // full object. Otherwise apply the expand-based summary filter.\n const filtered = global.fields ? study : filterStudy(study, opts.expand);\n\n if (global.fields) {\n const requested = global.fields.split(',').map(f => f.trim());\n const topLevel = requested.map(f => f.split('.')[0]);\n const missing = topLevel.filter(f => !(f in study));\n if (missing.length > 0) {\n explainMissingStudyFields(missing, studyId);\n }\n }\n\n output(filtered, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- curves ---\n studies\n .command('curves <studyId> <curveName>')\n .description(\n 'Extract and analyze a PowerCurve from a study.\\n' +\n 'Curve names: consumption, production, net-consumption, excesses\\n' +\n 'Default: --stats. Use --raw for full hourly data (8760 values).\\n' +\n 'Use --monthly for monthly aggregates, --daily for daily totals.'\n )\n .option('--stats', 'Show statistics (default if no other flag)')\n .option('--monthly', 'Monthly accumulated values')\n .option('--daily', 'Daily accumulated values')\n .option('--raw', 'Full hourly DayCurve[] data')\n .option('--total', 'Just the total accumulated value')\n .option('--surface-index <n>', 'Surface index for production curve', '0')\n .option('--save <file>', 'Save curve data to file')\n .action(async (studyId, curveName, opts) => {\n try {\n assertStudyObjectId(studyId);\n const global = getGlobalOpts(studies);\n const client = createServiceClient('solar', global);\n const res = await client.get(`/solar-study/findById/${studyId}`);\n const study = assertFound(res.data, 'Solar study', studyId) as Record<string, unknown>;\n\n // Extract the requested curve\n let curveData: unknown;\n switch (curveName) {\n case 'consumption':\n curveData = study.consumption;\n break;\n case 'production': {\n const surfaces = study.surfaces as any[];\n const idx = parseInt(opts.surfaceIndex);\n if (surfaces && surfaces[idx]?.production) {\n curveData = surfaces[idx].production;\n } else {\n outputError(new Error(`No production curve at surface index ${idx}. Study has ${surfaces?.length || 0} surfaces.`));\n return;\n }\n break;\n }\n case 'net-consumption':\n curveData = (study.results as any)?.netConsumption;\n break;\n case 'excesses':\n curveData = (study.results as any)?.excessesCurve;\n break;\n default:\n outputError(new Error(`Unknown curve: ${curveName}. Available: consumption, production, net-consumption, excesses`));\n return;\n }\n\n if (!curveData) {\n outputError(new Error(`Curve \"${curveName}\" not found or empty in this study.`));\n return;\n }\n\n // Import PowerCurve from energy-types\n const { PowerCurve } = await import('energy-types/lib/energy/classes/powerCurve.class.js');\n const cd = curveData as any;\n const pc = new PowerCurve(cd.days || cd, cd.ignore0 ?? false, cd.identifier || curveName, cd.parseDate ?? false);\n\n // Determine output mode\n const showRaw = opts.raw;\n const showMonthly = opts.monthly;\n const showDaily = opts.daily;\n const showTotal = opts.total;\n const showStats = opts.stats || (!showRaw && !showMonthly && !showDaily && !showTotal);\n\n let result: unknown;\n\n if (showRaw) {\n result = pc.days;\n } else if (showTotal) {\n result = { total: pc.getTotalAcumulate(), identifier: curveName, days: pc.days.length };\n } else if (showStats) {\n const raw = pc.calculateStatistics();\n result = raw.statistics || raw;\n } else if (showMonthly) {\n const raw = pc.calculateStatistics();\n const s = raw.statistics || raw;\n result = { anualMonthAccumulate: s.anualMonthAccumulate, anualMonthCount: s.anualMonthCount, anualMonthlyAverage: s.anualMonthlyAverage };\n } else if (showDaily) {\n const raw = pc.calculateStatistics();\n const s = raw.statistics || raw;\n result = { dailyAccumulate: s.dailyAccumulate };\n }\n\n const outOpts = { ...global, save: opts.save || global.save };\n output(result, outOpts);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- calculate-production ---\n studies\n .command('calculate-production')\n .description('Calculate solar production curve for given coordinates and configuration')\n .requiredOption('--lat <n>', 'Latitude')\n .requiredOption('--lon <n>', 'Longitude')\n .requiredOption('--power <w>', 'Installed power in Watts')\n .option('--angle <n>', 'Panel inclination degrees', '30')\n .option('--azimuth <n>', 'Panel orientation degrees (0=north, 180=south)', '180')\n .option('--losses <n>', 'Losses percentage', '14')\n .option('--year <n>', 'Year for calculation', String(new Date().getFullYear()))\n .option('--save <file>', 'Save result to file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const client = createServiceClient('solar', global);\n const body = {\n lat: parseFloat(opts.lat),\n long: parseFloat(opts.lon),\n instaledPower: parseFloat(opts.power),\n angle: parseFloat(opts.angle),\n azimuth: parseFloat(opts.azimuth),\n lossesPercentage: parseFloat(opts.losses),\n year: parseInt(opts.year),\n isOptimized: false,\n };\n const res = await client.post('/solar-study/calculateProduction', body);\n output(res.data, { ...global, save: opts.save || global.save });\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- optimize-surfaces ---\n studies\n .command('optimize-surfaces')\n .description('Calculate optimal panel angle and azimuth for coordinates')\n .requiredOption('--lat <n>', 'Latitude')\n .requiredOption('--lon <n>', 'Longitude')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const client = createServiceClient('solar', global);\n const res = await client.get('/solar-study/optimizeSurfaces', {\n params: { lat: parseFloat(opts.lat), lon: parseFloat(opts.lon) },\n });\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // Register study builder commands (init, validate, save, pull, set, add, remove, calculate)\n registerStudyBuilderCommands(studies);\n}\n","import { Command } from 'commander';\nimport { readFileSync } from 'fs';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\n/** Read all stdin as a promise */\nfunction readStdin(): Promise<string> {\n return new Promise((resolve, reject) => {\n let data = '';\n process.stdin.setEncoding('utf-8');\n process.stdin.on('data', (chunk) => { data += chunk; });\n process.stdin.on('end', () => resolve(data));\n process.stdin.on('error', reject);\n });\n}\n\n/** Read curve data from file, stdin, or --input flag */\nasync function readCurveInput(inputPath?: string): Promise<any> {\n let raw: string;\n if (inputPath && inputPath !== '-') {\n raw = readFileSync(inputPath, 'utf-8');\n } else {\n raw = await readStdin();\n }\n return JSON.parse(raw);\n}\n\n/** Build a PowerCurve from parsed JSON data */\nasync function buildCurve(data: any, identifier = 'curve') {\n const { PowerCurve } = await import('energy-types/lib/energy/classes/powerCurve.class.js');\n // Data might be: { days: [...], identifier } or just a DayCurve[]\n if (Array.isArray(data)) {\n return new PowerCurve(data, false, identifier, false);\n }\n return new PowerCurve(data.days || data, data.ignore0 ?? false, data.identifier || identifier, data.parseDate ?? false);\n}\n\n/** Serialize PowerCurve back to JSON-friendly format */\nfunction serializeCurve(pc: any): any {\n return { days: pc.days, identifier: pc.identifier, ignore0: pc.ignore0 };\n}\n\nexport function registerCurvesCommands(program: Command): void {\n const curves = program.command('curves').description(\n 'PowerCurve operations (pipe-friendly). Accept input via --input <file> or stdin.\\n' +\n 'Curve-returning commands output serialized PowerCurve JSON for chaining.\\n' +\n 'Use --save <file> to persist and still output to stdout.'\n );\n\n // --- stats ---\n curves\n .command('stats')\n .description('Calculate comprehensive statistics: monthly/daily/hourly averages, max, min, period aggregation')\n .option('--input <file>', 'Input file (or - for stdin)')\n .action(async (opts) => {\n try {\n const data = await readCurveInput(opts.input);\n const pc = await buildCurve(data, 'stats');\n const raw = pc.calculateStatistics();\n output(raw.statistics || raw, getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- total ---\n curves\n .command('total')\n .description('Calculate total accumulated value across all hours')\n .option('--input <file>', 'Input file (or - for stdin)')\n .action(async (opts) => {\n try {\n const data = await readCurveInput(opts.input);\n const pc = await buildCurve(data, 'total');\n output({ total: pc.getTotalAcumulate(), days: pc.days.length }, getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- multiply ---\n curves\n .command('multiply <factor>')\n .description('Multiply all hourly values by a factor. Returns a new PowerCurve.')\n .option('--input <file>', 'Input file (or - for stdin)')\n .action(async (factor, opts) => {\n try {\n const data = await readCurveInput(opts.input);\n const pc = await buildCurve(data, 'multiplied');\n const result = pc.applyMultiplier(parseFloat(factor));\n output(serializeCurve(result), getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- aggregate ---\n curves\n .command('aggregate')\n .description('Sum two PowerCurves (A + B). Returns a new PowerCurve.')\n .requiredOption('--a <file>', 'First curve file')\n .requiredOption('--b <file>', 'Second curve file')\n .action(async (opts) => {\n try {\n const dataA = JSON.parse(readFileSync(opts.a, 'utf-8'));\n const dataB = JSON.parse(readFileSync(opts.b, 'utf-8'));\n const pcA = await buildCurve(dataA, 'a');\n const pcB = await buildCurve(dataB, 'b');\n const result = pcA.aggregatePowerCurve(pcB);\n output(serializeCurve(result), getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- subtract ---\n curves\n .command('subtract')\n .description('Subtract two PowerCurves (A - B). Returns a new PowerCurve.')\n .requiredOption('--a <file>', 'First curve file (minuend)')\n .requiredOption('--b <file>', 'Second curve file (subtrahend)')\n .action(async (opts) => {\n try {\n const dataA = JSON.parse(readFileSync(opts.a, 'utf-8'));\n const dataB = JSON.parse(readFileSync(opts.b, 'utf-8'));\n const pcA = await buildCurve(dataA, 'a');\n const pcB = await buildCurve(dataB, 'b');\n const negB = pcB.applyMultiplier(-1);\n const result = pcA.aggregatePowerCurve(negB);\n output(serializeCurve(result), getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- filter-positive ---\n curves\n .command('filter-positive')\n .description('Keep only non-negative hourly values (zero out negatives). Returns a new PowerCurve.')\n .option('--input <file>', 'Input file (or - for stdin)')\n .action(async (opts) => {\n try {\n const data = await readCurveInput(opts.input);\n const pc = await buildCurve(data, 'positive');\n const result = pc.filterNegativeValues(); // filterNegativeValues returns curve with negatives zeroed\n output(serializeCurve(result), getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- filter-negative ---\n curves\n .command('filter-negative')\n .description('Keep only non-positive hourly values (zero out positives). Returns a new PowerCurve.')\n .option('--input <file>', 'Input file (or - for stdin)')\n .action(async (opts) => {\n try {\n const data = await readCurveInput(opts.input);\n const pc = await buildCurve(data, 'negative');\n const result = pc.filterPositiveValues(); // filterPositiveValues returns curve with positives zeroed\n output(serializeCurve(result), getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- sort ---\n curves\n .command('sort')\n .description('Sort curve days by date ascending. Returns a new PowerCurve.')\n .option('--input <file>', 'Input file (or - for stdin)')\n .action(async (opts) => {\n try {\n const data = await readCurveInput(opts.input);\n const pc = await buildCurve(data, 'sorted');\n const sortedDays = pc.sortByDate();\n output({ days: sortedDays, identifier: pc.identifier, ignore0: pc.ignore0 }, getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- filter-dates ---\n curves\n .command('filter-dates')\n .description('Filter curve to a date range. Returns a new PowerCurve.')\n .option('--input <file>', 'Input file (or - for stdin)')\n .option('--start <date>', 'Start date (YYYY-MM-DD)')\n .option('--end <date>', 'End date (YYYY-MM-DD)')\n .action(async (opts) => {\n try {\n const data = await readCurveInput(opts.input);\n const pc = await buildCurve(data, 'filtered');\n const start = opts.start ? new Date(opts.start) : undefined;\n const end = opts.end ? new Date(opts.end) : undefined;\n const filteredDays = pc.filterByDates(start, end);\n output({ days: filteredDays, identifier: pc.identifier, ignore0: pc.ignore0 }, getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- to-serie ---\n curves\n .command('to-serie')\n .description('Convert curve to chart-ready series format (x/y arrays)')\n .option('--input <file>', 'Input file (or - for stdin)')\n .action(async (opts) => {\n try {\n const data = await readCurveInput(opts.input);\n const pc = await buildCurve(data, 'serie');\n const serie = pc.convertoToSerie();\n output(serie, getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- by-period ---\n curves\n .command('by-period')\n .description(\n 'Aggregate a PowerCurve by tariff periods (P1-P6) using a period distribution.\\n' +\n 'Returns { p1, p2, p3, p4, p5, p6 } with accumulated kWh per period.\\n\\n' +\n 'The period distribution maps each hour of each day to a tariff period.\\n' +\n 'Get it with: suntropy consumption periods --save /tmp/periods.json\\n\\n' +\n 'Examples:\\n' +\n ' suntropy curves by-period --input /tmp/production.json --periods /tmp/periods.json\\n' +\n ' suntropy curves by-period --input /tmp/consumption.json --periods /tmp/periods.json'\n )\n .requiredOption('--periods <file>', 'Period distribution file (DayCurve[] from consumption periods)')\n .option('--input <file>', 'Input PowerCurve file (or stdin)')\n .action(async (opts) => {\n try {\n const data = await readCurveInput(opts.input);\n const pc = await buildCurve(data, 'by-period');\n const periodsData = JSON.parse(readFileSync(opts.periods, 'utf-8'));\n const result = pc.aggregateByPeriod(periodsData);\n output(result, getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n}\n","import { Command } from 'commander';\nimport { readFileSync } from 'fs';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\nexport function registerConsumptionCommands(program: Command): void {\n const consumption = program.command('consumption').description(\n 'Generate consumption curves using the profiles service.\\n' +\n 'Supports multiple estimation methods: standard patterns, custom profiles, monthly data.\\n' +\n 'Returns PowerCurve JSON compatible with `suntropy curves` for further processing.'\n );\n\n // --- estimate ---\n consumption\n .command('estimate')\n .description(\n 'Generate a consumption PowerCurve from patterns and annual consumption.\\n' +\n 'Patterns: Balance, Nightly, Morning, Afternoon, Domestic, Commercial\\n' +\n 'Examples:\\n' +\n ' suntropy consumption estimate --annual 5000 --pattern Balance\\n' +\n ' suntropy consumption estimate --annual 8000 --pattern Domestic --tariff 3.0TD --market es\\n' +\n ' suntropy consumption estimate --annual 3500 --monthly-data \\'{\"1\":300,\"2\":280,...}\\'\\n' +\n ' suntropy consumption estimate --annual 5000 --custom-profile-id abc123'\n )\n .requiredOption('--annual <kWh>', 'Annual consumption in kWh')\n .option('--pattern <name>', 'Consumption pattern: Balance, Nightly, Morning, Afternoon, Domestic, Commercial')\n .option('--start-date <YYYY-MM-DD>', 'Start date (default: Jan 1 current year)')\n .option('--end-date <YYYY-MM-DD>', 'End date (default: Dec 31 current year)')\n .option('--tariff <code>', 'Electricity tariff code (e.g. 3.0TD)', '3.0TD')\n .option('--type <type>', 'Profile type: Initial or Final', 'Final')\n .option('--market <code>', 'Market: es, pt, it', 'es')\n .option('--custom-profile-id <id>', 'Use a custom consumption profile by ID')\n .option('--monthly-data <json>', 'Monthly consumption JSON: {\"1\":val,\"2\":val,...,\"12\":val}')\n .option('--daily-curve <json>', 'Custom daily curve JSON (DayCurve format)')\n .option('--save <file>', 'Save result to file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(consumption);\n const client = createServiceClient('profiles', global);\n\n const year = new Date().getFullYear();\n const startDate = opts.startDate || `${year}-01-01`;\n const endDate = opts.endDate || `${year}-12-31`;\n\n // Build query params\n const params: Record<string, string> = {\n startDate,\n endDate,\n tariff: opts.tariff,\n type: opts.type,\n anualConsumption: opts.annual,\n market: opts.market,\n };\n\n if (opts.pattern) params.consumptionType = opts.pattern;\n if (opts.customProfileId) params.customProfileId = opts.customProfileId;\n\n // Build optional body\n let body: Record<string, unknown> | undefined;\n if (opts.monthlyData || opts.dailyCurve) {\n body = {};\n if (opts.monthlyData) body.consumptionByMonth = JSON.parse(opts.monthlyData);\n if (opts.dailyCurve) body.dailyCurve = JSON.parse(opts.dailyCurve);\n }\n\n const queryString = Object.entries(params)\n .map(([k, v]) => `${k}=${encodeURIComponent(v)}`)\n .join('&');\n\n const res = await client.post(`/consumption-estimation?${queryString}`, body || {});\n output(res.data, { ...global, save: opts.save || global.save });\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- ree-profiles ---\n consumption\n .command('ree-profiles')\n .description(\n 'Fetch REE (Red Eléctrica) hourly profiles for a date range and tariff.\\n' +\n 'Returns the raw profile data used as basis for consumption estimation.\\n' +\n 'Example: suntropy consumption ree-profiles --start 2024-01-01 --end 2024-12-31 --tariff 3.0TD'\n )\n .requiredOption('--start <YYYY-MM-DD>', 'Start date')\n .requiredOption('--end <YYYY-MM-DD>', 'End date')\n .option('--tariff <code>', 'Tariff code', '3.0TD')\n .option('--type <type>', 'Profile type: Initial or Final', 'Final')\n .option('--market <code>', 'Market code: es, pt, it', 'es')\n .option('--save <file>', 'Save result to file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(consumption);\n const client = createServiceClient('profiles', global);\n const res = await client.get('/ree-profiles', {\n params: {\n startDate: opts.start,\n endDate: opts.end,\n tariff: opts.tariff,\n type: opts.type,\n market: opts.market,\n },\n });\n output(res.data, { ...global, save: opts.save || global.save });\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- custom-tags ---\n consumption\n .command('custom-tags')\n .description('List available custom consumption profile tags for the authenticated client')\n .action(async () => {\n try {\n const global = getGlobalOpts(consumption);\n const client = createServiceClient('profiles', global);\n const res = await client.get('/custom-profiles/getTags');\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- custom-profile-info ---\n consumption\n .command('custom-profile-info')\n .description('Get details of a custom consumption profile by ID')\n .requiredOption('--id <profileId>', 'Custom profile ID')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(consumption);\n const client = createServiceClient('profiles', global);\n const res = await client.get('/custom-profiles/getInfo', {\n params: { id: opts.id },\n });\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- periods ---\n consumption\n .command('periods')\n .description(\n 'Fetch period distribution (hour→P1-P6 mapping) from the periods service.\\n' +\n 'Returns DayCurve[] where each hour\\'s value is the period number (1-6).\\n' +\n 'Use with `suntropy curves by-period` to aggregate any curve by tariff period.\\n\\n' +\n 'Common tariff IDs (Spain): 13=2.0TD, 14=3.0TD\\n' +\n 'Zone IDs (Spain): 1=Peninsula, 2=Canarias, 3=Baleares\\n\\n' +\n 'Examples:\\n' +\n ' suntropy consumption periods --tariff-id 14 --zone-id 1 --save /tmp/periods.json\\n' +\n ' suntropy consumption periods --tariff-id 13 --start 2025-01-01 --end 2025-12-31'\n )\n .option('--tariff-id <n>', 'ATR tariff ID (13=2.0TD, 14=3.0TD)', '14')\n .option('--zone-id <n>', 'Geographical zone ID (1=Peninsula)', '1')\n .option('--start <YYYY-MM-DD>', 'Start date (default: Jan 1 current year)')\n .option('--end <YYYY-MM-DD>', 'End date (default: Dec 31 current year)')\n .option('--market <code>', 'Market: es, pt, it, fr', 'es')\n .option('--save <file>', 'Save result to file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(consumption);\n const client = createServiceClient('periods', global);\n const year = new Date().getFullYear();\n const res = await client.get('/periodos', {\n params: {\n idTarifa: parseInt(opts.tariffId),\n idZona: parseInt(opts.zoneId),\n fechaInicio: opts.start || `${year}-01-01`,\n fechaFin: opts.end || `${year}-12-31`,\n market: opts.market,\n },\n });\n output(res.data, { ...global, save: opts.save || global.save });\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- from-file ---\n consumption\n .command('from-file')\n .description(\n 'Generate consumption curve from an uploaded file.\\n' +\n 'Supported formats: Portuguese EREDES ZIP files.\\n' +\n 'Example: suntropy consumption from-file --eredes-zip /path/to/file.zip'\n )\n .option('--eredes-zip <path>', 'Path to Portuguese EREDES ZIP file')\n .option('--save <file>', 'Save result to file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(consumption);\n const client = createServiceClient('profiles', global);\n\n if (opts.eredesZip) {\n const FormData = (await import('form-data')).default;\n const form = new FormData();\n form.append('file', readFileSync(opts.eredesZip), {\n filename: opts.eredesZip.split('/').pop(),\n contentType: 'application/zip',\n });\n const res = await client.post('/consumption-files-processor/portugal/eredes-zip', form, {\n headers: form.getHeaders(),\n });\n output(res.data, { ...global, save: opts.save || global.save });\n } else {\n outputError(new Error('Specify a file format: --eredes-zip <path>'));\n }\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import { Command } from 'commander';\nimport { readFileSync } from 'fs';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\n/** Read all stdin as a promise */\nfunction readStdin(): Promise<string> {\n return new Promise((resolve, reject) => {\n let data = '';\n process.stdin.setEncoding('utf-8');\n process.stdin.on('data', (chunk) => { data += chunk; });\n process.stdin.on('end', () => resolve(data));\n process.stdin.on('error', reject);\n });\n}\n\n/** Read JSON data from --data flag or stdin */\nasync function parseData(data: string | undefined): Promise<Record<string, unknown> | undefined> {\n if (!data) return undefined;\n if (data === '-') {\n const input = await readStdin();\n return JSON.parse(input);\n }\n return JSON.parse(data);\n}\n\n/** Unwrap PublicApiResponse: { code, data, error } → data or throw */\nfunction unwrapPublicApiResponse(resData: unknown): unknown {\n if (resData && typeof resData === 'object' && !Array.isArray(resData)) {\n const r = resData as Record<string, unknown>;\n // Detect PublicApiResponse shape: has 'code' field (number)\n if ('code' in r && typeof r.code === 'number') {\n // Prefer data if present (API may return both error and data)\n if (r.data !== undefined) return r.data;\n // No data — check for error\n if (r.error) {\n const err = r.error as Record<string, unknown>;\n throw new Error(`API error (${err.code || r.code}): ${err.message || JSON.stringify(err)}`);\n }\n // code present but no data and no error — return as-is\n return resData;\n }\n }\n return resData;\n}\n\n/** Compact study output: replace heavy PowerCurve objects with summaries */\nfunction compactStudyOutput(study: unknown): unknown {\n if (study === null || study === undefined || typeof study !== 'object') return study;\n if (Array.isArray(study)) return study.map(compactStudyOutput);\n\n const record = study as Record<string, unknown>;\n\n // Detect PowerCurve: has 'days' array with objects and identifier\n if (Array.isArray(record.days) && record.days.length > 0 && record.identifier !== undefined) {\n return { _type: 'PowerCurve', days: record.days.length, identifier: record.identifier };\n }\n\n const result: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(record)) {\n if (val && typeof val === 'object' && !Array.isArray(val)) {\n const v = val as Record<string, unknown>;\n if (Array.isArray(v.days) && v.days.length > 0 && v.identifier !== undefined) {\n result[key] = { _type: 'PowerCurve', days: v.days.length, identifier: v.identifier };\n continue;\n }\n }\n result[key] = compactStudyOutput(val);\n }\n return result;\n}\n\nexport function registerSolarformCommands(program: Command): void {\n const solarform = program.command('solarform').description(\n 'Create solar studies via the Solar Form API.\\n' +\n 'Two modes: \"simple\" (minimal params, auto-optimized) and \"calculate\" (full control).\\n' +\n 'Use --save flag to persist the study to the database.'\n );\n\n // --- simple ---\n solarform\n .command('simple')\n .description(\n 'Create a solar study with minimal parameters (simplified mode).\\n' +\n 'Automatically resolves location from region/subregion, applies consumption patterns,\\n' +\n 'and optimizes kit selection.\\n\\n' +\n 'Consumption patterns: Balance, Nightly, Morning, Afternoon, Domestic, Commercial\\n' +\n 'Consumption mode: monthlyConsumption (kWh) or monthlySpending (EUR)\\n' +\n 'Excesses modes: PPA, gridSelling, noInjection, virtualBattery\\n\\n' +\n 'Examples:\\n' +\n ' suntropy solarform simple --region \"Andalucía\" --sub-region \"Sevilla\" --consumption 5000\\n' +\n ' suntropy solarform simple --region \"Cataluña\" --sub-region \"Barcelona\" --consumption 300 --consumption-mode monthlySpending --save\\n' +\n ' suntropy solarform simple --region \"Madrid\" --sub-region \"Madrid\" --consumption 8000 --pattern Domestic --kit-id abc123 --save'\n )\n .requiredOption('--region <name>', 'Region name (must exist in database)')\n .requiredOption('--sub-region <name>', 'Sub-region name')\n .requiredOption('--consumption <value>', 'Consumption value (kWh or EUR depending on --consumption-mode)')\n .option('--pattern <name>', 'Consumption pattern: Balance, Nightly, Morning, Afternoon, Domestic, Commercial', 'Balance')\n .option('--consumption-mode <mode>', 'monthlyConsumption (kWh) or monthlySpending (EUR)', 'monthlyConsumption')\n .option('--kit-id <id>', 'Use a specific solar kit instead of auto-optimization')\n .option('--excesses-mode <mode>', 'Excesses compensation: PPA, gridSelling, noInjection, virtualBattery')\n .option('--assigned-user <uid>', 'Assign study to a user UID')\n .option('--email <email>', 'Send results to this email')\n .option('--save', 'Save study to database')\n .option('--raw', 'Return full study with PowerCurve data (no compaction)')\n .option('--save-file <file>', 'Save result to local file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(solarform);\n const client = createServiceClient('solar', global);\n\n const body: Record<string, unknown> = {\n region: opts.region,\n subRegion: opts.subRegion,\n selectedConsumptionPattern: opts.pattern,\n consumptionQuantity: parseFloat(opts.consumption),\n consumptionQuantityIntroductionMode: opts.consumptionMode,\n };\n\n if (opts.assignedUser) body.assignedUserUID = opts.assignedUser;\n\n // Build query params\n const params: Record<string, string> = {};\n if (opts.save) params.save = 'true';\n if (opts.email) params.email = opts.email;\n if (opts.kitId) params.solarKitId = opts.kitId;\n if (opts.excessesMode) params.excessesCompensationMode = opts.excessesMode;\n\n const queryString = Object.entries(params)\n .map(([k, v]) => `${k}=${encodeURIComponent(v)}`)\n .join('&');\n\n const url = `/api/solar-form/simple${queryString ? '?' + queryString : ''}`;\n const res = await client.post(url, body);\n\n const study = unwrapPublicApiResponse(res.data);\n const result = opts.raw ? study : compactStudyOutput(study);\n output(result, { ...global, save: opts.saveFile || global.save });\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- calculate ---\n solarform\n .command('calculate')\n .description(\n 'Create a solar study with full control over all parameters.\\n' +\n 'Pass the complete SimplifiedSolarStudy body as JSON.\\n\\n' +\n 'Required body fields:\\n' +\n ' center: { lat, lng } — Installation coordinates\\n' +\n ' surfaces: [{ path, inclination, orientation }] — Panel surfaces\\n' +\n ' consumptionMode: \"cups\" | \"consumptionPatterns\"\\n' +\n ' clientDetails: { name, email, phone }\\n\\n' +\n 'Optional: atrTariff, geographicalZone, location, contractedPower,\\n' +\n ' monthPeriodConsumptionDictionary, selectedConsumptionPattern,\\n' +\n ' consumptionQuantity, consumptionQuantityIntroductionMode\\n\\n' +\n 'Examples:\\n' +\n ' suntropy solarform calculate --data \\'{\"center\":{\"lat\":37.39,\"lng\":-5.99},...}\\' --save\\n' +\n ' cat study-input.json | suntropy solarform calculate --data - --save --email client@co.com'\n )\n .requiredOption('--data <json>', 'Full SimplifiedSolarStudy JSON body (or - for stdin)')\n .option('--save', 'Save study to database')\n .option('--email <email>', 'Send results to this email')\n .option('--raw', 'Return full study with PowerCurve data (no compaction)')\n .option('--save-file <file>', 'Save result to local file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(solarform);\n const client = createServiceClient('solar', global);\n\n const body = await parseData(opts.data);\n if (!body) {\n outputError(new Error('--data is required. Pass JSON or - for stdin.'));\n return;\n }\n\n const params: Record<string, string> = {};\n if (opts.save) params.save = 'true';\n if (opts.email) params.email = opts.email;\n\n const queryString = Object.entries(params)\n .map(([k, v]) => `${k}=${encodeURIComponent(v)}`)\n .join('&');\n\n const url = `/api/solar-form${queryString ? '?' + queryString : ''}`;\n const res = await client.post(url, body);\n\n const study = unwrapPublicApiResponse(res.data);\n if (!study || (typeof study === 'object' && !Array.isArray(study) && !('selectedSolarStudyMode' in (study as Record<string, unknown>)))) {\n outputError(new Error('API returned no study data. The /api/solar-form endpoint requires a complete body with: center, surfaces, consumptionMode, and typically locationMode. Use \"solarform simple\" for minimal-parameter study creation.'));\n return;\n }\n const result = opts.raw ? study : compactStudyOutput(study);\n output(result, { ...global, save: opts.saveFile || global.save });\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- config ---\n solarform\n .command('config')\n .description(\n 'Get the solar form configuration for the authenticated client.\\n' +\n 'Returns form settings, appearance, enabled steps, custom fields, etc.'\n )\n .action(async () => {\n try {\n const global = getGlobalOpts(solarform);\n const client = createServiceClient('solar', global);\n const res = await client.get('/solar-form/solar-form-config');\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- statistics ---\n solarform\n .command('statistics')\n .description(\n 'List or create solar form submission statistics.\\n' +\n 'Used for tracking form analytics and conversion data.'\n )\n .option('--create', 'Create a new statistics entry')\n .option('--update', 'Update an existing statistics entry')\n .option('--data <json>', 'Statistics data as JSON')\n .option('--stats-id <id>', 'Statistics ID (for update or linking)')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(solarform);\n const client = createServiceClient('solar', global);\n\n if (opts.update) {\n const body = await parseData(opts.data);\n const res = await client.put('/solar-form/solar-form-statistics', body);\n output(res.data, global);\n } else if (opts.create) {\n const body = (await parseData(opts.data)) || {};\n const params: Record<string, string> = {};\n if (opts.statsId) params.statsId = opts.statsId;\n const res = await client.post('/solar-form/solar-form-statistics', body, { params });\n output(res.data, global);\n } else {\n outputError(new Error('Specify --create or --update'));\n }\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import { Command } from 'commander';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\n/** Read all stdin as a promise */\nfunction readStdin(): Promise<string> {\n return new Promise((resolve, reject) => {\n let data = '';\n process.stdin.setEncoding('utf-8');\n process.stdin.on('data', (chunk) => { data += chunk; });\n process.stdin.on('end', () => resolve(data));\n process.stdin.on('error', reject);\n });\n}\n\n/** Read JSON data from --data flag or stdin */\nasync function parseData(data: string | undefined): Promise<Record<string, unknown> | undefined> {\n if (!data) return undefined;\n if (data === '-') {\n const input = await readStdin();\n return JSON.parse(input);\n }\n return JSON.parse(data);\n}\n\n/** Compact study output: replace heavy PowerCurve objects with summaries */\nfunction compactStudyOutput(study: unknown): unknown {\n if (study === null || study === undefined || typeof study !== 'object') return study;\n if (Array.isArray(study)) return study.map(compactStudyOutput);\n\n const record = study as Record<string, unknown>;\n\n // Detect PowerCurve: has 'days' array with objects and identifier\n if (Array.isArray(record.days) && record.days.length > 0 && record.identifier !== undefined) {\n return { _type: 'PowerCurve', days: record.days.length, identifier: record.identifier };\n }\n\n const result: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(record)) {\n if (val && typeof val === 'object' && !Array.isArray(val)) {\n const v = val as Record<string, unknown>;\n if (Array.isArray(v.days) && v.days.length > 0 && v.identifier !== undefined) {\n result[key] = { _type: 'PowerCurve', days: v.days.length, identifier: v.identifier };\n continue;\n }\n }\n result[key] = compactStudyOutput(val);\n }\n return result;\n}\n\nexport function registerPPACommands(program: Command): void {\n const ppa = program.command('ppa').description(\n 'PPA (Power Purchase Agreement) analysis.\\n' +\n 'Read PPA templates and run PPA simulations on a solar study.'\n );\n\n // --- ppa templates (read-only sub-group) ---\n const templates = ppa\n .command('templates')\n .description('Read-only access to the client PPA templates.');\n\n templates\n .command('list')\n .description(\n 'List all PPA templates for the authenticated client.\\n' +\n 'Example:\\n' +\n ' suntropy ppa templates list --fields _id,name,mode,ppaPrice,useInSolarForm'\n )\n .action(async () => {\n try {\n const global = getGlobalOpts(ppa);\n const client = createServiceClient('solar', global);\n const res = await client.get('/solar-study/ppa-templates');\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n templates\n .command('get <id>')\n .description(\n 'Get a single PPA template by its Mongo _id.\\n' +\n 'Example:\\n' +\n ' suntropy ppa templates get 665f0a1b2c3d4e5f60718293'\n )\n .action(async (id: string) => {\n try {\n const global = getGlobalOpts(ppa);\n const client = createServiceClient('solar', global);\n const res = await client.get(`/solar-study/ppa-templates/${id}`);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- ppa calculate ---\n ppa\n .command('calculate')\n .description(\n 'Run PPA simulations on a solar study (read-only, does not persist).\\n\\n' +\n 'Provide the study via --study <id> (downloaded from the API) or --data <json>|- (full SolarStudy).\\n' +\n 'With --template <ppaTemplateId> the simulation uses that single PPA template;\\n' +\n 'without it, the backend uses the client templates flagged useInSolarForm.\\n\\n' +\n 'Note: the study must include consumption and economicResults (a study fetched\\n' +\n 'by --study already does). The response is the study with economicResults.ppaAnalysis populated.\\n\\n' +\n 'Examples:\\n' +\n ' suntropy ppa calculate --study 665f0a1b2c3d4e5f60718293\\n' +\n ' suntropy ppa calculate --study 665f... --template 6700aa11bb22cc33dd44ee55\\n' +\n ' cat study.json | suntropy ppa calculate --data -'\n )\n .option('--study <id>', 'Solar study Mongo id to download and analyze')\n .option('--data <json>', 'Full SolarStudy JSON body (or - for stdin)')\n .option('--template <ppaTemplateId>', 'PPA template id to apply (defaults to client useInSolarForm templates)')\n .option('--raw', 'Return full study with PowerCurve data (no compaction)')\n .option('--save-file <file>', 'Save result to local file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(ppa);\n const client = createServiceClient('solar', global);\n\n let study: unknown;\n if (opts.study) {\n const res = await client.get(`/solar-study/findById/${opts.study}`);\n study = res.data;\n } else if (opts.data) {\n study = await parseData(opts.data);\n } else {\n outputError(new Error('Provide --study <id> or --data <json>|- (full SolarStudy).'));\n return;\n }\n\n const body: Record<string, unknown> = { data: study };\n if (opts.template) body.ppaTemplateId = opts.template;\n\n const res = await client.post('/solar-study/calculate-ppa-on-study', body);\n const result = opts.raw ? res.data : compactStudyOutput(res.data);\n output(result, { ...global, save: opts.saveFile || global.save });\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import { Command } from 'commander';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\n/** Read all stdin as a promise */\nfunction readStdin(): Promise<string> {\n return new Promise((resolve, reject) => {\n let data = '';\n process.stdin.setEncoding('utf-8');\n process.stdin.on('data', (chunk) => { data += chunk; });\n process.stdin.on('end', () => resolve(data));\n process.stdin.on('error', reject);\n });\n}\n\n/** Read JSON data from --data flag or stdin */\nasync function parseData(data: string | undefined): Promise<Record<string, unknown> | undefined> {\n if (!data) return undefined;\n if (data === '-') {\n const input = await readStdin();\n return JSON.parse(input);\n }\n return JSON.parse(data);\n}\n\nexport function registerShareableCommands(program: Command): void {\n const shareables = program.command('shareables').description(\n 'Create shareable links for studies (sharing service, exposed under /templates).'\n );\n\n // --- create ---\n shareables\n .command('create')\n .description(\n 'Create a shareable link for a study (POST /shareable).\\n' +\n 'The backend fills uid, url, clientUID and idShareable from the token.\\n\\n' +\n 'elementType: solarStudy (default), colectiveSolarStudy, veChargerStudy, heatpumpStudy, billing\\n' +\n 'shareableType: TEMPLATE (default), CONTRACT\\n' +\n 'privacy: PUBLIC (default), PRIVATE (use --password)\\n\\n' +\n 'Examples:\\n' +\n ' suntropy shareables create --element-id 665f0a1b2c3d4e5f60718293\\n' +\n ' suntropy shareables create --element-id 665f... --template-id 6700aa... --name \"Estudio Juan\"\\n' +\n ' suntropy shareables create --element-id 665f... --privacy PRIVATE --password secret --email-list \"a@x.com;b@y.com\"\\n' +\n ' suntropy shareables create --element-id 665f... --expiration-date 2026-12-31 --link-params \"utm_source=cli\"'\n )\n .requiredOption('--element-id <id>', 'Id of the element (study) to share')\n .option('--element-type <type>', 'solarStudy | colectiveSolarStudy | veChargerStudy | heatpumpStudy | billing', 'solarStudy')\n .option('--shareable-type <type>', 'TEMPLATE | CONTRACT', 'TEMPLATE')\n .option('--privacy <privacy>', 'PUBLIC | PRIVATE', 'PUBLIC')\n .option('--template-id <id>', 'Template id to apply to the shareable')\n .option('--name <name>', 'Descriptive name for the shareable')\n .option('--password <pwd>', 'Protect the link with a password (implies PRIVATE)')\n .option('--expiration-date <date>', 'Expiration date (e.g. 2026-12-31)')\n .option('--activation-date <date>', 'Activation date (e.g. 2026-01-01)')\n .option('--email-list <emails>', 'Semicolon-separated list of recipient emails')\n .option('--reply-to <email>', 'Reply-to email for notifications')\n .option('--custom-layout', 'Enable custom layout')\n .option('--read-only', 'Mark the shareable as read-only')\n .option('--link-params <qs>', 'Extra query params appended to the shareable link (k=v&k2=v2)')\n .option('--data <json>', 'Extra ShareableDto fields as JSON (or - for stdin), merged last')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(shareables);\n const client = createServiceClient('templates', global);\n\n const extra = (await parseData(opts.data)) || {};\n const body: Record<string, unknown> = {\n elementId: opts.elementId,\n elementType: opts.elementType,\n shareableType: opts.shareableType,\n privacy: opts.password ? 'PRIVATE' : opts.privacy,\n ...(opts.templateId ? { templateId: opts.templateId } : {}),\n ...(opts.name ? { name: opts.name } : {}),\n ...(opts.password ? { password: opts.password, passwordConfirm: opts.password } : {}),\n ...(opts.expirationDate ? { expirationDate: opts.expirationDate } : {}),\n ...(opts.activationDate ? { activationDate: opts.activationDate } : {}),\n ...(opts.emailList ? { emailList: opts.emailList } : {}),\n ...(opts.replyTo ? { replyTo: opts.replyTo } : {}),\n ...(opts.customLayout ? { customLayout: true } : {}),\n ...(opts.readOnly ? { readOnly: true } : {}),\n ...extra,\n };\n\n const url = opts.linkParams ? `/shareable?${opts.linkParams}` : '/shareable';\n const res = await client.post(url, body);\n output(res.data, { ...global, save: global.save });\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import { Command } from 'commander';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\nexport function registerTemplatesCommands(program: Command): void {\n const templates = program.command('templates').description(\n 'Read client document templates (id + name), proxied via solar from the sharing service.'\n );\n\n // --- list ---\n templates\n .command('list')\n .description(\n 'List templates returning only _id and templateName (GET /api/templates).\\n' +\n 'Defaults to the solar study templates (--type solarStudy).\\n\\n' +\n 'Types: solarStudy (default) | colectiveSolarStudy | veChargerStudy.\\n' +\n 'Use --type generic for the generic (untyped) templates.\\n\\n' +\n 'Examples:\\n' +\n ' suntropy templates list\\n' +\n ' suntropy templates list --type colectiveSolarStudy\\n' +\n ' suntropy templates list --type generic --fields _id,templateName --format csv'\n )\n .option(\n '--type <identifier>',\n 'solarStudy (default) | colectiveSolarStudy | veChargerStudy | generic',\n 'solarStudy',\n )\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(templates);\n const client = createServiceClient('solar', global);\n\n const params: Record<string, string> = {};\n // 'generic' means the untyped templates -> omit the identifier so the\n // backend forwards no filter (sharing returns templateIdentifier: null).\n if (opts.type && opts.type !== 'generic') {\n params.templateIdentifier = opts.type;\n }\n\n const res = await client.get('/api/templates', { params });\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import { Command } from 'commander';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\ninterface GeocodeResult {\n formattedAddress: string;\n lat: number;\n lng: number;\n locationType: string;\n placeId: string;\n types: string[];\n addressComponents: { longName: string; shortName: string; types: string[] }[];\n}\n\ninterface GeocodeResponse {\n status: 'OK' | 'ZERO_RESULTS';\n count: number;\n results: GeocodeResult[];\n}\n\n/** Envelope returned by the solar public API (/api/*). */\ninterface PublicApiResponse<T> {\n code?: number;\n error?: { code?: string; message?: string };\n warning?: { code?: string; message?: string };\n data?: T;\n}\n\n/**\n * Unwrap the PublicApiResponse envelope, print the best match by default (or the\n * full candidate list with --all), and surface API-level errors consistently.\n */\nfunction emit(\n envelope: PublicApiResponse<GeocodeResponse>,\n all: boolean | undefined,\n query: Record<string, unknown>,\n global: OutputOptions,\n): void {\n if (envelope.error) {\n outputError({\n error: true,\n status: envelope.code,\n message: envelope.error.message || envelope.error.code || 'Geocoding error',\n details: envelope.error,\n });\n return;\n }\n\n const data = envelope.data;\n if (!data) {\n output({ found: false, ...query }, global);\n return;\n }\n if (all) {\n output(data.results, global);\n return;\n }\n if (data.count === 0) {\n output({ found: false, ...query }, global);\n return;\n }\n output(data.results[0], global);\n}\n\nexport function registerGeocodeCommands(program: Command): void {\n const geocode = program.command('geocode').description(\n 'Geocoding via the solar service (proxy to Google Geocoding API).\\n' +\n 'Resolve an address into coordinates and vice versa.',\n );\n\n // --- geocode resolve (address -> coordinates) ---\n geocode\n .command('resolve')\n .description(\n 'Resolve an address into coordinates (lat/lng + formatted address).\\n' +\n 'Examples:\\n' +\n ' suntropy geocode resolve --address \"Calle Mayor 1, Madrid\"\\n' +\n ' suntropy geocode resolve --address \"Gran Vía, Madrid\" --country es --all',\n )\n .requiredOption('--address <string>', 'Address to geocode (quote it)')\n .option('--country <code>', 'Bias results to a country (ISO code, e.g. es, pt, it)')\n .option('--all', 'Return all candidate matches instead of only the best one')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(geocode);\n const client = createServiceClient('solar', global);\n const res = await client.get<PublicApiResponse<GeocodeResponse>>(\n '/api/geocode',\n { params: { address: opts.address, country: opts.country } },\n );\n emit(res.data, opts.all, { address: opts.address }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- geocode reverse (coordinates -> address) ---\n geocode\n .command('reverse')\n .description(\n 'Resolve coordinates into an address (reverse geocoding).\\n' +\n 'Example:\\n' +\n ' suntropy geocode reverse --lat 40.4168 --lng -3.7038',\n )\n .requiredOption('--lat <number>', 'Latitude')\n .requiredOption('--lng <number>', 'Longitude')\n .option('--all', 'Return all candidate matches instead of only the best one')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(geocode);\n const client = createServiceClient('solar', global);\n const res = await client.get<PublicApiResponse<GeocodeResponse>>(\n '/api/reverse-geocode',\n { params: { lat: opts.lat, lng: opts.lng } },\n );\n emit(res.data, opts.all, { lat: opts.lat, lng: opts.lng }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import { Command, Option } from 'commander';\nimport { createServiceClient, handleApiError, assertStudyObjectId } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\nimport { loadConfig, getActiveProfile } from '../../config.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\n/**\n * Well-known Suntropy user identity for the Alexandria agent. The front resolves\n * this uid to Alexandria's name/avatar (see `isAlexandriaComment`), so a\n * notification whose `fromUserUid` is this value is rendered as coming FROM\n * Alexandria — not as a self-notification from the acting user whose token the\n * CLI runs with.\n */\nconst ALEXANDRIA_USER_UID = 'alexandria';\n\nconst SEVERITIES = ['info', 'warning', 'urgent'] as const;\ntype Severity = (typeof SEVERITIES)[number];\n\nexport function registerNotificationsCommands(program: Command): void {\n const notifications = program\n .command('notifications')\n .description(\n 'Send in-app (and email) notifications to Suntropy users.\\n' +\n 'Useful for Alexandria to proactively tell a user a task is done, since a\\n' +\n 'direct/email execution leaves no study comment (and thus no auto-notification).',\n );\n\n // --- send ---\n notifications\n .command('send')\n .description(\n 'Send a notification to a user. It appears in the recipient\\'s notification\\n' +\n 'bell and, if enabled in their config, is also emailed. Sent FROM Alexandria\\n' +\n 'by default so it is not shown as a self-notification.\\n' +\n 'Examples:\\n' +\n ' suntropy notifications send --to-user <userUID> --message \"He terminado el estudio.\"\\n' +\n ' suntropy notifications send --to-user <userUID> --title \"Estudio listo\" \\\\\\n' +\n ' --message \"Revisa los resultados.\" --study <solarStudyId> --mention',\n )\n .requiredOption('--to-user <userUID>', 'Recipient userUID (who gets notified)')\n .requiredOption('--message <text>', 'Notification body (supports Markdown)')\n .option('--title <text>', 'Notification title', 'Alexandria')\n .option('--severity <severity>', `Severity: ${SEVERITIES.join(' | ')}`, 'info')\n .option(\n '--mention',\n 'Send as a mention (type new_mention) instead of an update (new_comment). ' +\n 'Mentions are gated by the user\\'s \"mention\" notification setting.',\n )\n .option(\n '--study <solarStudyId>',\n 'Link the notification to a solar study: makes it click-through to that study',\n )\n .option('--link <url>', 'Custom link for the email call-to-action')\n .option(\n '--from-user <userUID>',\n 'Sender userUID shown as the author (default: the authenticated user)',\n )\n // Hidden flag mirroring `studies comment --as-alexandria`: signs the\n // notification as Alexandria (fromUserUid = \"alexandria\", which the front\n // resolves to Alexandria's name/avatar). Omitted from --help; the agent is\n // instructed to use it. `--from-user` still takes precedence if provided.\n .addOption(new Option('--as-alexandria').hideHelp())\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(notifications);\n\n const severity = opts.severity as Severity;\n if (!SEVERITIES.includes(severity)) {\n throw new Error(\n `Invalid --severity \"${opts.severity}\". Use one of: ${SEVERITIES.join(', ')}.`,\n );\n }\n // A linked study must be an actual study _id (24-hex ObjectId), or the\n // click-through would point nowhere.\n if (opts.study) assertStudyObjectId(opts.study);\n\n const client = createServiceClient('notifications', global);\n\n // Sender identity: explicit --from-user wins; else --as-alexandria signs\n // it as Alexandria; else fall back to the authenticated user (a plain\n // user-to-user notification).\n const profile = getActiveProfile(loadConfig());\n const fromUserUid = opts.fromUser\n ? opts.fromUser\n : opts.asAlexandria\n ? ALEXANDRIA_USER_UID\n : profile.userUID;\n\n const notification = {\n notificationType: opts.mention ? 'new_mention' : 'new_comment',\n severity,\n origin: opts.asAlexandria ? 'ALEXANDRIA' : 'CLI',\n fromUserUid,\n toUserUid: opts.toUser,\n notificationContent: {\n contentType: 'COMMENT',\n name: opts.title,\n description: opts.message,\n ...(opts.study ? { externalId: opts.study } : {}),\n ...(opts.link ? { link: opts.link } : {}),\n // The notifications backend only persists notificationContent when a\n // `data` payload is present (the OneToOne isn't cascaded), so without\n // this the notification renders blank in the bell. Always send a\n // small data object; harmless once the backend also persists content\n // without it. Not read by the front for these types.\n data: {\n source: opts.asAlexandria ? 'alexandria' : 'cli',\n ...(opts.study ? { studyId: opts.study } : {}),\n },\n },\n };\n\n // `@Controller('notifications')` behind the `/notifications` gateway\n // prefix → the create route is `/notifications`. clientUID/creator come\n // from the JWT; `toUserUid` in the body is the recipient.\n const res = await client.post('/notifications', notification);\n\n // The service returns the created Notification, or a string reason when\n // the client/type has notifications disabled — surface both clearly.\n if (typeof res.data === 'string') {\n output(\n { sent: false, reason: res.data, toUser: opts.toUser },\n global,\n );\n return;\n }\n output(\n {\n sent: true,\n notificationId: res.data?.idNotification,\n toUser: opts.toUser,\n type: notification.notificationType,\n severity,\n },\n global,\n );\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import type { Command } from 'commander';\nimport { loadConfig, saveConfig } from './config.js';\n\n/**\n * Command access profiles (\"permission tiers\").\n *\n * The CLI can be locked to a permission tier so that only a subset of commands\n * is registered. Tiers are CUMULATIVE:\n *\n * read ⊂ write (read + write) ⊂ delete (read + write + delete = full)\n *\n * Commands above the active tier are pruned from the command tree before\n * parsing, so they (a) never appear in `--help` and (b) when invoked, Commander\n * reports them natively as `error: unknown command 'X'` — i.e. \"the command\n * does not exist\". This is an admin/automation control (e.g. to constrain the\n * Alexandria agent's sandbox to read-only). It is intentionally not advertised\n * in the user-facing help; it is driven by the hidden `command-profile` command\n * or the SUNTROPY_COMMAND_PROFILE environment variable.\n */\nexport type CommandTier = 'read' | 'write' | 'delete';\n\nexport const COMMAND_TIERS: CommandTier[] = ['read', 'write', 'delete'];\n\nconst TIER_VALUE: Record<CommandTier, number> = { read: 0, write: 1, delete: 2 };\n\n/** Default when nothing is configured: full access (legacy behavior). */\nexport const DEFAULT_TIER: CommandTier = 'delete';\n\nexport const ENV_VAR = 'SUNTROPY_COMMAND_PROFILE';\n\nexport function tierValue(t: CommandTier): number {\n return TIER_VALUE[t];\n}\n\nexport function isValidTier(value: unknown): value is CommandTier {\n return typeof value === 'string' && (COMMAND_TIERS as string[]).includes(value);\n}\n\nexport interface ResolvedCommandProfile {\n tier: CommandTier;\n source: 'env' | 'config' | 'default';\n /** Raw env value when present but invalid (for diagnostics). */\n invalidEnv?: string;\n}\n\n/**\n * Resolve the active tier. Precedence: env var > config file > default.\n * Pure (no side effects) so it can be called from both the gating step and the\n * `command-profile` status command.\n */\nexport function getActiveCommandProfile(): ResolvedCommandProfile {\n const envRaw = process.env[ENV_VAR]?.trim();\n if (envRaw) {\n const envNorm = envRaw.toLowerCase();\n if (isValidTier(envNorm)) return { tier: envNorm, source: 'env' };\n // Invalid env value: fall through to config/default but report it.\n const fallback = resolveFromConfig();\n return { ...fallback, invalidEnv: envRaw };\n }\n return resolveFromConfig();\n}\n\nfunction resolveFromConfig(): ResolvedCommandProfile {\n try {\n const cfg = loadConfig();\n if (isValidTier(cfg.commandProfile)) return { tier: cfg.commandProfile, source: 'config' };\n } catch {\n // ignore: fall back to default\n }\n return { tier: DEFAULT_TIER, source: 'default' };\n}\n\n/** Persist (or clear, when null) the stored command profile. */\nexport function setStoredCommandProfile(tier: CommandTier | null): void {\n const cfg = loadConfig();\n if (tier === null) delete cfg.commandProfile;\n else cfg.commandProfile = tier;\n saveConfig(cfg);\n}\n\n// ─── Classification ───────────────────────────────────────────────────────\n//\n// A command's tier is the MAX tier over the verbs in its path. Verbs are the\n// command/group names, so e.g. `studies set name` inherits `write` from `set`,\n// and `inventory kits panels delete` inherits `delete` from `delete`.\n\nconst DELETE_VERBS = new Set(['delete', 'delete-batch', 'archive']);\n\nconst WRITE_VERBS = new Set([\n 'create', 'update', 'edit', 'set', 'add', 'remove', 'assemble', 'featured',\n 'save', 'init', 'init-default', 'add-comment', 'comment', 'send',\n 'calculate-results', 'optimize-peakpower',\n]);\n\n/**\n * Explicit overrides for paths whose verbs are ambiguous. `studies calculate\n * production` writes to the local draft (write), but the bare verb `calculate`\n * is also used by pure-compute commands (`ppa calculate`, `solarform calculate`,\n * `studies calculate-production`) that are read-only — so `calculate` is NOT a\n * global write verb; this path is pinned instead.\n */\nconst PATH_OVERRIDES: Record<string, CommandTier> = {\n 'studies calculate production': 'write',\n};\n\nexport function classifyPath(segs: string[]): CommandTier {\n const key = segs.join(' ');\n if (PATH_OVERRIDES[key]) return PATH_OVERRIDES[key];\n let tier: CommandTier = 'read';\n for (const seg of segs) {\n if (DELETE_VERBS.has(seg)) return 'delete';\n if (WRITE_VERBS.has(seg)) tier = 'write';\n }\n return tier;\n}\n\n// ─── Exemptions ───────────────────────────────────────────────────────────\n//\n// CLI plumbing that must always work regardless of the active tier: you always\n// need to authenticate, configure the CLI, and manage the command profile\n// itself. NOTE: only the *local* `config` leaves are exempt — the tenant\n// configuration subtrees (`config theme`, `config solarform …`) hit the backend\n// and are gated like any other business command.\n\nconst EXEMPT_CONFIG_LEAVES = new Set(['set', 'get', 'list', 'create-profile', 'use']);\n\nexport function isExemptPath(segs: string[]): boolean {\n if (segs[0] === 'auth') return true;\n if (segs[0] === 'command-profile') return true;\n if (segs[0] === 'config' && segs.length === 2 && EXEMPT_CONFIG_LEAVES.has(segs[1])) return true;\n return false;\n}\n\n// ─── Pruning ──────────────────────────────────────────────────────────────\n\n/**\n * Prune the command tree in place according to the active command profile.\n * Returns the resolved tier so the caller can surface it if needed.\n */\nexport function applyCommandProfile(program: Command): ResolvedCommandProfile {\n const resolved = getActiveCommandProfile();\n pruneChildren(program, [], tierValue(resolved.tier));\n return resolved;\n}\n\nfunction pruneChildren(parent: Command, parentSegs: string[], max: number): void {\n const kept = parent.commands.filter((child) => {\n const segs = [...parentSegs, child.name()];\n return keepCommand(child, segs, max);\n });\n // Commander types `commands` as readonly, but pruning must replace its\n // contents. Mutate the array in place (rather than reassigning the property)\n // so Commander keeps using the same reference for help and dispatch.\n const mutable = parent.commands as Command[];\n mutable.length = 0;\n mutable.push(...kept);\n}\n\nfunction keepCommand(cmd: Command, segs: string[], max: number): boolean {\n if (cmd.commands.length > 0) {\n // Group: prune its descendants first, then keep it only if something\n // survived (or it's an exempt subtree).\n pruneChildren(cmd, segs, max);\n if (cmd.commands.length > 0) return true;\n return isExemptPath(segs);\n }\n // Leaf:\n if (isExemptPath(segs)) return true;\n return tierValue(classifyPath(segs)) <= max;\n}\n","import { Command } from 'commander';\nimport { output, outputError, type OutputOptions } from '../output.js';\nimport {\n COMMAND_TIERS,\n DEFAULT_TIER,\n ENV_VAR,\n getActiveCommandProfile,\n isValidTier,\n setStoredCommandProfile,\n} from '../access.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as OutputOptions;\n}\n\n/**\n * Hidden admin command to manage the CLI command access profile (permission\n * tier). Registered with `{ hidden: true }` so it never shows in `--help`, but\n * remains invocable in any tier (it is exempt from gating). Changes take effect\n * on the next invocation, since gating happens at startup.\n *\n * suntropy command-profile show the active tier + source\n * suntropy command-profile read lock the CLI to read-only\n * suntropy command-profile write allow read + write\n * suntropy command-profile delete allow everything (default)\n * suntropy command-profile reset clear the stored value (back to default)\n */\nexport function registerCommandProfileCommand(program: Command): void {\n program\n .command('command-profile [tier]', { hidden: true })\n .description('Admin: get/set the command access profile (read | write | delete | reset)')\n .action((tier?: string) => {\n try {\n const global = getGlobalOpts(program);\n\n // No argument → report current state.\n if (!tier) {\n const resolved = getActiveCommandProfile();\n output(\n {\n commandProfile: resolved.tier,\n source: resolved.source,\n ...(resolved.invalidEnv\n ? { warning: `Ignoring invalid ${ENV_VAR}=\"${resolved.invalidEnv}\" (expected: ${COMMAND_TIERS.join(' | ')})` }\n : {}),\n available: COMMAND_TIERS,\n envVar: ENV_VAR,\n },\n global,\n );\n return;\n }\n\n const value = tier.trim().toLowerCase();\n\n if (value === 'reset') {\n setStoredCommandProfile(null);\n const resolved = getActiveCommandProfile();\n output(\n {\n success: true,\n message: `Stored command profile cleared. Effective tier: ${resolved.tier} (${resolved.source}).`,\n commandProfile: resolved.tier,\n source: resolved.source,\n },\n global,\n );\n return;\n }\n\n if (!isValidTier(value)) {\n outputError(new Error(`Invalid tier \"${tier}\". Expected one of: ${COMMAND_TIERS.join(', ')}, or \"reset\".`));\n return;\n }\n\n setStoredCommandProfile(value);\n const envOverride = getActiveCommandProfile();\n const message =\n envOverride.source === 'env'\n ? `Stored command profile set to \"${value}\", but ${ENV_VAR}=\"${process.env[ENV_VAR]}\" overrides it (effective: ${envOverride.tier}). Unset the env var for the stored value to apply.`\n : `Command profile set to \"${value}\". Takes effect on the next command.`;\n output(\n {\n success: true,\n commandProfile: value,\n effectiveTier: envOverride.tier,\n effectiveSource: envOverride.source,\n default: DEFAULT_TIER,\n message,\n },\n global,\n );\n } catch (err) {\n outputError(err);\n }\n });\n}\n","import { createProgram } from '../src/index.js';\n\nconst program = createProgram();\nprogram.parseAsync(process.argv).catch((err) => {\n process.stderr.write(JSON.stringify({ error: true, message: err.message }) + '\\n');\n process.exit(1);\n});\n"],"mappings":"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","names":["Command","writeFileSync","program","hadToken","readFileSync","writeFileSync","join","getGlobalOpts","getGlobalOpts","getGlobalOpts","getGlobalOpts","program","getGlobalOpts","readFileSync","getGlobalOpts","parseData","readFileSync","res","getGlobalOpts","getGlobalOpts","parseData","program","readFileSync","writeFileSync","existsSync","existsSync","readFileSync","writeFileSync","getGlobalOpts","getGlobalOpts","program","readFileSync","getGlobalOpts","readFileSync","program","readFileSync","getGlobalOpts","program","readFileSync","getGlobalOpts","readStdin","parseData","program","getGlobalOpts","readStdin","parseData","compactStudyOutput","program","res","getGlobalOpts","readStdin","parseData","program","getGlobalOpts","program","getGlobalOpts","program","Option","getGlobalOpts","program","Option","program","getGlobalOpts","program","program","Command"]}