@dqcai/sqlite 2.1.1 → 2.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.d.ts +0 -40
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +7 -39
- package/lib/index.mjs.map +1 -1
- package/lib/index.umd.js +1 -1
- package/lib/index.umd.js.map +1 -1
- package/package.json +1 -1
- package/lib/utils/csv-import.d.ts +0 -102
- package/lib/utils/csv-import.d.ts.map +0 -1
- package/lib/utils/index.d.ts +0 -3
- package/lib/utils/index.d.ts.map +0 -1
- package/lib/utils/migration-manager.d.ts +0 -184
- package/lib/utils/migration-manager.d.ts.map +0 -1
package/lib/index.umd.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.umd.js","sources":["../src/core/universal-dao.ts","../src/core/database-factory.ts","../src/core/database-manager.ts","../src/core/base-service.ts","../src/query/query-builder.ts","../src/utils/migration-manager.ts","../src/utils/csv-import.ts","../src/core/service-manager.ts","../src/adapters/base-adapter.ts","../src/index.ts"],"sourcesContent":["// src/core/universal-dao.ts\r\nimport {\r\n ColumnDefinition,\r\n DatabaseSchema,\r\n ImportOptions,\r\n ImportResult,\r\n IndexDefinition,\r\n QueryTable,\r\n SQLiteAdapter,\r\n SQLiteConnection,\r\n SQLiteResult,\r\n SQLiteRow,\r\n TableDefinition,\r\n TypeMappingConfig,\r\n WhereClause,\r\n ColumnMapping\r\n} from \"../types\";\r\n\r\nexport class UniversalDAO {\r\n private connection: SQLiteConnection | null = null;\r\n private isConnected: boolean = false;\r\n private inTransaction: boolean = false;\r\n private typeMappingConfig: TypeMappingConfig[\"type_mapping\"] | null = null;\r\n private createIfNotExists: boolean = false;\r\n private forceRecreate: boolean = false;\r\n\r\n constructor(\r\n private adapter: SQLiteAdapter,\r\n private dbPath: string,\r\n private options?: {\r\n createIfNotExists?: boolean; // Mặc định false - không tạo mới nếu đã tồn tại\r\n forceRecreate?: boolean; // Mặc định false - ép tạo lại = true\r\n }\r\n ) {\r\n this.createIfNotExists = options?.createIfNotExists ?? false;\r\n this.forceRecreate = options?.forceRecreate ?? false;\r\n }\r\n\r\n async connect(): Promise<void> {\r\n if (this.isConnected) {\r\n return;\r\n }\r\n\r\n this.connection = await this.adapter.connect(this.dbPath);\r\n this.isConnected = true;\r\n }\r\n\r\n async disconnect(): Promise<void> {\r\n if (this.connection && this.isConnected) {\r\n await this.connection.close();\r\n this.connection = null;\r\n this.isConnected = false;\r\n }\r\n }\r\n\r\n async close(): Promise<void> {\r\n await this.disconnect();\r\n }\r\n\r\n // Type mapping utilities\r\n setTypeMappingConfig(config: TypeMappingConfig[\"type_mapping\"]): void {\r\n this.typeMappingConfig = config;\r\n }\r\n\r\n private convertToSQLiteType(genericType: string): string {\r\n if (!this.typeMappingConfig || !this.typeMappingConfig.sqlite) {\r\n return this.getDefaultSQLiteType(genericType);\r\n }\r\n\r\n const sqliteMapping = this.typeMappingConfig.sqlite;\r\n return sqliteMapping[genericType.toLowerCase()] || \"TEXT\";\r\n }\r\n\r\n private getDefaultSQLiteType(genericType: string): string {\r\n const defaultMapping: Record<string, string> = {\r\n string: \"TEXT\",\r\n varchar: \"TEXT\",\r\n char: \"TEXT\",\r\n email: \"TEXT\",\r\n url: \"TEXT\",\r\n uuid: \"TEXT\",\r\n integer: \"INTEGER\",\r\n bigint: \"INTEGER\",\r\n smallint: \"INTEGER\",\r\n tinyint: \"INTEGER\",\r\n decimal: \"REAL\",\r\n numeric: \"REAL\",\r\n float: \"REAL\",\r\n double: \"REAL\",\r\n boolean: \"INTEGER\",\r\n timestamp: \"TEXT\",\r\n datetime: \"TEXT\",\r\n date: \"TEXT\",\r\n time: \"TEXT\",\r\n json: \"TEXT\",\r\n array: \"TEXT\",\r\n blob: \"BLOB\",\r\n binary: \"BLOB\",\r\n };\r\n return defaultMapping[genericType.toLowerCase()] || \"TEXT\";\r\n }\r\n\r\n private processColumnDefinition(col: ColumnDefinition): ColumnDefinition {\r\n const processedCol: ColumnDefinition = { ...col };\r\n processedCol.type = this.convertToSQLiteType(col.type);\r\n\r\n const options: string[] = [];\r\n if (col.constraints) {\r\n const constraints = col.constraints.toUpperCase().split(\" \");\r\n if (constraints.includes(\"PRIMARY\")) {\r\n options.push(\"PRIMARY KEY\");\r\n processedCol.primary_key = true;\r\n }\r\n if (\r\n constraints.includes(\"AUTO_INCREMENT\") ||\r\n constraints.includes(\"AUTOINCREMENT\")\r\n ) {\r\n if (processedCol.primary_key) options.push(\"AUTOINCREMENT\");\r\n processedCol.auto_increment = true;\r\n }\r\n if (constraints.includes(\"NOT\") && constraints.includes(\"NULL\")) {\r\n options.push(\"NOT NULL\");\r\n processedCol.nullable = false;\r\n }\r\n if (constraints.includes(\"UNIQUE\")) {\r\n if (!processedCol.primary_key) options.push(\"UNIQUE\");\r\n processedCol.unique = true;\r\n }\r\n // Handle DEFAULT values\r\n const defaultIndex = constraints.indexOf(\"DEFAULT\");\r\n if (defaultIndex !== -1 && constraints.length > defaultIndex + 1) {\r\n const defaultValue = constraints[defaultIndex + 1];\r\n options.push(`DEFAULT ${defaultValue}`);\r\n processedCol.default = defaultValue;\r\n }\r\n }\r\n\r\n processedCol.option_key = options.join(\" \").trim();\r\n return processedCol;\r\n }\r\n\r\n // Schema initialization with enhanced options\r\n async initializeFromSchema(schema: DatabaseSchema): Promise<void> {\r\n this.ensureConnected();\r\n\r\n // Check if schema already exists\r\n let hasExistingSchema = false;\r\n try {\r\n const result = await this.execute(\r\n \"SELECT version FROM _schema_info ORDER BY applied_at DESC LIMIT 1\"\r\n );\r\n hasExistingSchema = result.rows.length > 0;\r\n } catch (error) {\r\n hasExistingSchema = false;\r\n }\r\n\r\n // Handle existing schema based on options\r\n if (hasExistingSchema && !this.createIfNotExists && !this.forceRecreate) {\r\n if (schema.type_mapping) {\r\n this.setTypeMappingConfig(schema.type_mapping);\r\n }\r\n return;\r\n }\r\n\r\n if (hasExistingSchema && this.forceRecreate) {\r\n await this.dropAllTables();\r\n }\r\n\r\n if (schema.type_mapping) {\r\n this.setTypeMappingConfig(schema.type_mapping);\r\n }\r\n\r\n try {\r\n await this.execute(\"PRAGMA foreign_keys = ON\");\r\n } catch {}\r\n\r\n await this.beginTransaction();\r\n\r\n try {\r\n for (const [tableName, tableConfig] of Object.entries(schema.schemas)) {\r\n const tableDefinition: TableDefinition = {\r\n name: tableName,\r\n cols: tableConfig.cols.map((col) =>\r\n this.processColumnDefinition(col)\r\n ),\r\n description: tableConfig.description,\r\n indexes: tableConfig.indexes,\r\n foreign_keys: tableConfig.foreign_keys,\r\n };\r\n await this.createTableWithForeignKeys(tableDefinition);\r\n }\r\n\r\n for (const [tableName, tableConfig] of Object.entries(schema.schemas)) {\r\n if (tableConfig.indexes?.length) {\r\n await this.createIndexesForTable(tableName, tableConfig.indexes);\r\n }\r\n }\r\n\r\n await this.setSchemaVersion(schema.version);\r\n await this.commitTransaction();\r\n } catch (error) {\r\n await this.rollbackTransaction();\r\n throw error;\r\n }\r\n }\r\n\r\n private async dropAllTables(): Promise<void> {\r\n const tables = await this.execute(\r\n \"SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'\"\r\n );\r\n\r\n await this.beginTransaction();\r\n\r\n try {\r\n for (const table of tables.rows) {\r\n await this.execute(`DROP TABLE IF EXISTS ${table.name}`);\r\n }\r\n await this.commitTransaction();\r\n } catch (error) {\r\n await this.rollbackTransaction();\r\n throw error;\r\n }\r\n }\r\n\r\n private async createTableWithForeignKeys(\r\n table: TableDefinition\r\n ): Promise<void> {\r\n const columnDefs = table.cols.map((col) =>\r\n `${col.name} ${col.type} ${col.option_key || \"\"}`.trim()\r\n );\r\n\r\n const foreignKeyDefs: string[] = [];\r\n if (table.foreign_keys) {\r\n for (const fk of table.foreign_keys) {\r\n let fkSql = `FOREIGN KEY (${fk.column}) REFERENCES ${fk.references.table}(${fk.references.column})`;\r\n if (fk.on_delete) fkSql += ` ON DELETE ${fk.on_delete}`;\r\n if (fk.on_update) fkSql += ` ON UPDATE ${fk.on_update}`;\r\n foreignKeyDefs.push(fkSql);\r\n }\r\n }\r\n\r\n const allDefs = [...columnDefs, ...foreignKeyDefs];\r\n const sql = `CREATE TABLE IF NOT EXISTS ${table.name} (${allDefs.join(\r\n \", \"\r\n )})`;\r\n await this.execute(sql);\r\n }\r\n\r\n private async createIndexesForTable(\r\n tableName: string,\r\n indexes: IndexDefinition[]\r\n ): Promise<void> {\r\n for (const index of indexes) {\r\n const columns = index.columns.join(\", \");\r\n const isUnique = index.unique || false;\r\n const sql = `CREATE ${isUnique ? \"UNIQUE\" : \"\"} INDEX IF NOT EXISTS ${\r\n index.name\r\n } ON ${tableName} (${columns})`;\r\n await this.execute(sql);\r\n }\r\n }\r\n\r\n // Transaction management\r\n async beginTransaction(): Promise<void> {\r\n if (this.inTransaction) {\r\n throw new Error(\"Transaction already in progress\");\r\n }\r\n await this.execute(\"BEGIN TRANSACTION\");\r\n this.inTransaction = true;\r\n }\r\n\r\n async commitTransaction(): Promise<void> {\r\n if (!this.inTransaction) {\r\n throw new Error(\"No transaction in progress\");\r\n }\r\n await this.execute(\"COMMIT\");\r\n this.inTransaction = false;\r\n }\r\n\r\n async rollbackTransaction(): Promise<void> {\r\n if (!this.inTransaction) {\r\n throw new Error(\"No transaction in progress\");\r\n }\r\n await this.execute(\"ROLLBACK\");\r\n this.inTransaction = false;\r\n }\r\n\r\n // Schema management\r\n async getSchemaVersion(): Promise<string> {\r\n try {\r\n const result = await this.getRst(\r\n \"SELECT version FROM _schema_info ORDER BY applied_at DESC LIMIT 1\"\r\n );\r\n return result.version || \"0\";\r\n } catch {\r\n return \"0\";\r\n }\r\n }\r\n\r\n async setSchemaVersion(version: string): Promise<void> {\r\n await this.execute(`CREATE TABLE IF NOT EXISTS _schema_info (\r\n version TEXT NOT NULL,\r\n applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP\r\n )`);\r\n await this.execute(`INSERT INTO _schema_info (version) VALUES (?)`, [\r\n version,\r\n ]);\r\n }\r\n\r\n // CRUD Operations\r\n async insert(insertTable: QueryTable): Promise<SQLiteResult> {\r\n const validCols = insertTable.cols.filter(\r\n (col) => col.value !== undefined && col.value !== null\r\n );\r\n if (validCols.length === 0) {\r\n throw new Error(\"No valid columns to insert\");\r\n }\r\n\r\n const columnNames = validCols.map((col) => col.name).join(\", \");\r\n const placeholders = validCols.map(() => \"?\").join(\", \");\r\n const params = validCols.map((col) =>\r\n typeof col.value === \"object\" ? JSON.stringify(col.value) : col.value\r\n );\r\n\r\n const sql = `INSERT INTO ${insertTable.name} (${columnNames}) VALUES (${placeholders})`;\r\n return await this.execute(sql, params);\r\n }\r\n\r\n async update(updateTable: QueryTable): Promise<SQLiteResult> {\r\n const setCols = updateTable.cols.filter(\r\n (col) =>\r\n col.value !== undefined &&\r\n !updateTable.wheres?.some((w) => w.name === col.name)\r\n );\r\n\r\n if (setCols.length === 0) {\r\n throw new Error(\"No columns to update\");\r\n }\r\n\r\n const setClause = setCols.map((col) => `${col.name} = ?`).join(\", \");\r\n const params = setCols.map((col) =>\r\n typeof col.value === \"object\" ? JSON.stringify(col.value) : col.value\r\n );\r\n\r\n let sql = `UPDATE ${updateTable.name} SET ${setClause}`;\r\n const whereClause = this.buildWhereClause(updateTable.wheres);\r\n\r\n if (!whereClause.sql) {\r\n throw new Error(\"WHERE clause is required for UPDATE operation\");\r\n }\r\n\r\n sql += whereClause.sql;\r\n params.push(...whereClause.params);\r\n\r\n return await this.execute(sql, params);\r\n }\r\n\r\n async delete(deleteTable: QueryTable): Promise<SQLiteResult> {\r\n let sql = `DELETE FROM ${deleteTable.name}`;\r\n const whereClause = this.buildWhereClause(deleteTable.wheres);\r\n\r\n if (!whereClause.sql) {\r\n throw new Error(\"WHERE clause is required for DELETE operation\");\r\n }\r\n\r\n sql += whereClause.sql;\r\n return await this.execute(sql, whereClause.params);\r\n }\r\n\r\n async select(selectTable: QueryTable): Promise<SQLiteRow> {\r\n const { sql, params } = this.buildSelectQuery(selectTable, \" LIMIT 1\");\r\n const result = await this.execute(sql, params);\r\n return result.rows[0] || {};\r\n }\r\n\r\n async selectAll(selectTable: QueryTable): Promise<SQLiteRow[]> {\r\n const { sql, params } = this.buildSelectQuery(selectTable);\r\n const result = await this.execute(sql, params);\r\n return result.rows;\r\n }\r\n\r\n // Utility methods\r\n private buildSelectQuery(\r\n selectTable: QueryTable,\r\n suffix: string = \"\"\r\n ): { sql: string; params: any[] } {\r\n const columns =\r\n selectTable.cols.length > 0\r\n ? selectTable.cols.map((col) => col.name).join(\", \")\r\n : \"*\";\r\n\r\n let sql = `SELECT ${columns} FROM ${selectTable.name}`;\r\n const whereClause = this.buildWhereClause(selectTable.wheres);\r\n sql += whereClause.sql;\r\n\r\n if (selectTable.orderbys?.length) {\r\n const orderBy = selectTable.orderbys\r\n .map((o) => `${o.name} ${o.direction || \"ASC\"}`)\r\n .join(\", \");\r\n sql += ` ORDER BY ${orderBy}`;\r\n }\r\n\r\n if (selectTable.limitOffset) {\r\n if (selectTable.limitOffset.limit)\r\n sql += ` LIMIT ${selectTable.limitOffset.limit}`;\r\n if (selectTable.limitOffset.offset)\r\n sql += ` OFFSET ${selectTable.limitOffset.offset}`;\r\n }\r\n\r\n sql += suffix;\r\n return { sql, params: whereClause.params };\r\n }\r\n\r\n private buildWhereClause(\r\n wheres?: WhereClause[],\r\n clause: string = \"WHERE\"\r\n ): { sql: string; params: any[] } {\r\n if (!wheres || wheres.length === 0) {\r\n return { sql: \"\", params: [] };\r\n }\r\n\r\n const conditions: string[] = [];\r\n const params: any[] = [];\r\n\r\n for (const where of wheres) {\r\n const operator = where.operator || \"=\";\r\n conditions.push(`${where.name} ${operator} ?`);\r\n params.push(where.value);\r\n }\r\n\r\n return { sql: ` ${clause} ${conditions.join(\" AND \")}`, params };\r\n }\r\n\r\n convertJsonToQueryTable(\r\n tableName: string,\r\n json: Record<string, any>,\r\n idFields: string[] = [\"id\"]\r\n ): QueryTable {\r\n const queryTable: QueryTable = { name: tableName, cols: [], wheres: [] };\r\n\r\n for (const [key, value] of Object.entries(json)) {\r\n queryTable.cols.push({ name: key, value });\r\n if (idFields.includes(key) && value !== undefined) {\r\n queryTable.wheres?.push({ name: key, value });\r\n }\r\n }\r\n\r\n return queryTable;\r\n }\r\n\r\n // Enhanced Data Import functionality\r\n async importData(options: ImportOptions): Promise<ImportResult> {\r\n const startTime = Date.now();\r\n const result: ImportResult = {\r\n totalRows: options.data.length,\r\n successRows: 0,\r\n errorRows: 0,\r\n errors: [],\r\n executionTime: 0,\r\n };\r\n\r\n if (!this.isConnected) {\r\n throw new Error(\"Database is not connected\");\r\n }\r\n\r\n if (!options.data || options.data.length === 0) {\r\n result.executionTime = Date.now() - startTime;\r\n return result;\r\n }\r\n\r\n const tableInfo = await this.getTableInfo(options.tableName);\r\n if (tableInfo.length === 0) {\r\n throw new Error(`Table '${options.tableName}' does not exist`);\r\n }\r\n\r\n const columnMap = new Map(\r\n tableInfo.map((col) => [col.name.toLowerCase(), col])\r\n );\r\n const batchSize = options.batchSize || 1000;\r\n let processedCount = 0;\r\n const skipAutoIncrementPK = !options.includeAutoIncrementPK;\r\n\r\n try {\r\n await this.beginTransaction();\r\n\r\n for (let i = 0; i < options.data.length; i += batchSize) {\r\n const batch = options.data.slice(i, i + batchSize);\r\n\r\n for (let j = 0; j < batch.length; j++) {\r\n const rowIndex = i + j;\r\n const rowData = batch[j];\r\n\r\n try {\r\n const processedData = options.validateData\r\n ? this.validateAndTransformRow(\r\n rowData,\r\n columnMap,\r\n options.tableName,\r\n skipAutoIncrementPK\r\n )\r\n : this.transformRowData(rowData, columnMap, skipAutoIncrementPK);\r\n\r\n if (options.updateOnConflict && options.conflictColumns) {\r\n await this.insertOrUpdate(\r\n options.tableName,\r\n processedData,\r\n options.conflictColumns\r\n );\r\n } else {\r\n await this.insertRow(options.tableName, processedData);\r\n }\r\n\r\n result.successRows++;\r\n } catch (error) {\r\n result.errorRows++;\r\n const errorInfo = {\r\n rowIndex,\r\n error: error instanceof Error ? error.message : String(error),\r\n rowData,\r\n };\r\n result.errors.push(errorInfo);\r\n\r\n if (options.onError) {\r\n options.onError(\r\n error instanceof Error ? error : new Error(String(error)),\r\n rowIndex,\r\n rowData\r\n );\r\n }\r\n\r\n if (!options.skipErrors) {\r\n throw error;\r\n }\r\n }\r\n\r\n processedCount++;\r\n if (options.onProgress && processedCount % 100 === 0) {\r\n options.onProgress(processedCount, options.data.length);\r\n }\r\n }\r\n }\r\n\r\n await this.commitTransaction();\r\n } catch (error) {\r\n await this.rollbackTransaction();\r\n throw error;\r\n }\r\n\r\n if (options.onProgress) {\r\n options.onProgress(processedCount, options.data.length);\r\n }\r\n\r\n result.executionTime = Date.now() - startTime;\r\n return result;\r\n }\r\n\r\n // Import with column mapping\r\n async importDataWithMapping(\r\n tableName: string,\r\n data: Record<string, any>[],\r\n columnMappings: ColumnMapping[],\r\n options: Partial<ImportOptions> = {}\r\n ): Promise<ImportResult> {\r\n const transformedData = data.map((row) => {\r\n const newRow: Record<string, any> = {};\r\n\r\n columnMappings.forEach((mapping) => {\r\n if (row.hasOwnProperty(mapping.sourceColumn)) {\r\n let value = row[mapping.sourceColumn];\r\n\r\n if (mapping.transform) {\r\n value = mapping.transform(value);\r\n }\r\n\r\n newRow[mapping.targetColumn] = value;\r\n }\r\n });\r\n\r\n return newRow;\r\n });\r\n\r\n return await this.importData({\r\n tableName,\r\n data: transformedData,\r\n ...options,\r\n });\r\n }\r\n\r\n // Import from CSV\r\n async importFromCSV(\r\n tableName: string,\r\n csvData: string,\r\n options: {\r\n delimiter?: string;\r\n hasHeader?: boolean;\r\n columnMappings?: ColumnMapping[];\r\n } & Partial<ImportOptions> = {}\r\n ): Promise<ImportResult> {\r\n const delimiter = options.delimiter || \",\";\r\n const hasHeader = options.hasHeader !== false;\r\n\r\n const lines = csvData.split(\"\\n\").filter((line) => line.trim());\r\n if (lines.length === 0) {\r\n throw new Error(\"CSV data is empty\");\r\n }\r\n\r\n let headers: string[] = [];\r\n let dataStartIndex = 0;\r\n\r\n if (hasHeader) {\r\n headers = lines[0]\r\n .split(delimiter)\r\n .map((h) => h.trim().replace(/^[\"']|[\"']$/g, \"\"));\r\n dataStartIndex = 1;\r\n } else {\r\n const firstRowCols = lines[0].split(delimiter).length;\r\n headers = Array.from(\r\n { length: firstRowCols },\r\n (_, i) => `column_${i + 1}`\r\n );\r\n }\r\n\r\n const data: Record<string, any>[] = [];\r\n for (let i = dataStartIndex; i < lines.length; i++) {\r\n const values = lines[i]\r\n .split(delimiter)\r\n .map((v) => v.trim().replace(/^[\"']|[\"']$/g, \"\"));\r\n const row: Record<string, any> = {};\r\n\r\n headers.forEach((header, index) => {\r\n row[header] = values[index] || null;\r\n });\r\n\r\n data.push(row);\r\n }\r\n\r\n if (options.columnMappings) {\r\n return await this.importDataWithMapping(\r\n tableName,\r\n data,\r\n options.columnMappings,\r\n options\r\n );\r\n } else {\r\n return await this.importData({\r\n tableName,\r\n data,\r\n ...options,\r\n });\r\n }\r\n }\r\n\r\n private validateAndTransformRow(\r\n rowData: Record<string, any>,\r\n columnMap: Map<string, any>,\r\n tableName: string,\r\n skipAutoIncrementPK: boolean = true\r\n ): Record<string, any> {\r\n const processedRow: Record<string, any> = {};\r\n\r\n for (const [columnName, columnInfo] of columnMap.entries()) {\r\n const isRequired = columnInfo.notnull === 1 && !columnInfo.dflt_value;\r\n const isPrimaryKey = columnInfo.pk === 1;\r\n const isAutoIncrementPK =\r\n isPrimaryKey && columnInfo.type.toLowerCase().includes(\"integer\");\r\n\r\n if (skipAutoIncrementPK && isAutoIncrementPK) {\r\n continue;\r\n }\r\n\r\n const value = this.findValueForColumn(rowData, columnName);\r\n\r\n if (isRequired && (value === null || value === undefined)) {\r\n throw new Error(\r\n `Required column '${columnName}' is missing or null in table '${tableName}'`\r\n );\r\n }\r\n\r\n if (value !== null && value !== undefined) {\r\n processedRow[columnName] = this.convertValueToColumnType(\r\n value,\r\n columnInfo.type\r\n );\r\n }\r\n }\r\n\r\n return processedRow;\r\n }\r\n\r\n private transformRowData(\r\n rowData: Record<string, any>,\r\n columnMap: Map<string, any>,\r\n skipAutoIncrementPK: boolean = true\r\n ): Record<string, any> {\r\n const processedRow: Record<string, any> = {};\r\n\r\n for (const [key, value] of Object.entries(rowData)) {\r\n const columnName = key.toLowerCase();\r\n const columnInfo = columnMap.get(columnName);\r\n\r\n if (!columnInfo) {\r\n continue;\r\n }\r\n\r\n const isPrimaryKey = columnInfo.pk === 1;\r\n const isAutoIncrementPK =\r\n isPrimaryKey && columnInfo.type.toLowerCase().includes(\"integer\");\r\n\r\n if (skipAutoIncrementPK && isAutoIncrementPK) {\r\n continue;\r\n }\r\n\r\n if (value !== null && value !== undefined) {\r\n processedRow[key] = this.convertValueToColumnType(\r\n value,\r\n columnInfo.type\r\n );\r\n }\r\n }\r\n\r\n return processedRow;\r\n }\r\n\r\n private findValueForColumn(\r\n rowData: Record<string, any>,\r\n columnName: string\r\n ): any {\r\n if (rowData.hasOwnProperty(columnName)) {\r\n return rowData[columnName];\r\n }\r\n\r\n const lowerColumnName = columnName.toLowerCase();\r\n for (const [key, value] of Object.entries(rowData)) {\r\n if (key.toLowerCase() === lowerColumnName) {\r\n return value;\r\n }\r\n }\r\n\r\n return undefined;\r\n }\r\n\r\n private convertValueToColumnType(value: any, columnType: string): any {\r\n if (value === null || value === undefined) {\r\n return null;\r\n }\r\n\r\n const type = columnType.toLowerCase();\r\n\r\n try {\r\n if (type.includes(\"integer\") || type.includes(\"int\")) {\r\n if (typeof value === \"boolean\") {\r\n return value ? 1 : 0;\r\n }\r\n const num = parseInt(String(value));\r\n return isNaN(num) ? null : num;\r\n }\r\n\r\n if (\r\n type.includes(\"real\") ||\r\n type.includes(\"float\") ||\r\n type.includes(\"decimal\")\r\n ) {\r\n const num = parseFloat(String(value));\r\n return isNaN(num) ? null : num;\r\n }\r\n\r\n if (type.includes(\"boolean\")) {\r\n if (typeof value === \"boolean\") {\r\n return value ? 1 : 0;\r\n }\r\n if (typeof value === \"string\") {\r\n const lower = value.toLowerCase();\r\n return lower === \"true\" || lower === \"1\" || lower === \"yes\" ? 1 : 0;\r\n }\r\n return value ? 1 : 0;\r\n }\r\n\r\n if (type.includes(\"json\")) {\r\n if (typeof value === \"object\") {\r\n return JSON.stringify(value);\r\n }\r\n if (typeof value === \"string\") {\r\n try {\r\n JSON.parse(value);\r\n return value;\r\n } catch {\r\n throw new Error(\r\n `Invalid JSON format for column type '${columnType}'`\r\n );\r\n }\r\n }\r\n return JSON.stringify(value);\r\n }\r\n\r\n if (type.includes(\"timestamp\") || type.includes(\"datetime\")) {\r\n if (value instanceof Date) {\r\n return value.toISOString();\r\n }\r\n if (typeof value === \"string\" || typeof value === \"number\") {\r\n const date = new Date(value);\r\n return isNaN(date.getTime()) ? value : date.toISOString();\r\n }\r\n return String(value);\r\n }\r\n\r\n return String(value);\r\n } catch (error) {\r\n throw new Error(\r\n `Cannot convert value '${value}' to column type '${columnType}'`\r\n );\r\n }\r\n }\r\n\r\n private async insertRow(\r\n tableName: string,\r\n data: Record<string, any>\r\n ): Promise<void> {\r\n const columns = Object.keys(data);\r\n const values = Object.values(data);\r\n const placeholders = columns.map(() => \"?\").join(\", \");\r\n\r\n const sql = `INSERT INTO ${tableName} (${columns.join(\r\n \", \"\r\n )}) VALUES (${placeholders})`;\r\n await this.execute(sql, values);\r\n }\r\n\r\n private async insertOrUpdate(\r\n tableName: string,\r\n data: Record<string, any>,\r\n conflictColumns: string[]\r\n ): Promise<void> {\r\n try {\r\n await this.insertRow(tableName, data);\r\n } catch (error) {\r\n if (this.isConflictError(error)) {\r\n await this.updateRowByColumns(tableName, data, conflictColumns);\r\n } else {\r\n throw error;\r\n }\r\n }\r\n }\r\n\r\n private async updateRowByColumns(\r\n tableName: string,\r\n data: Record<string, any>,\r\n conflictColumns: string[]\r\n ): Promise<void> {\r\n const allColumns = Object.keys(data);\r\n const updateColumns = allColumns.filter(\r\n (col) => !conflictColumns.includes(col)\r\n );\r\n const whereColumns = conflictColumns;\r\n\r\n if (updateColumns.length === 0) {\r\n return;\r\n }\r\n\r\n const setClause = updateColumns.map((col) => `${col} = ?`).join(\", \");\r\n const whereClause = whereColumns.map((col) => `${col} = ?`).join(\" AND \");\r\n\r\n const updateValues = updateColumns.map((col) => data[col]);\r\n const whereValues = whereColumns.map((col) => data[col]);\r\n const allValues = [...updateValues, ...whereValues];\r\n\r\n const sql = `UPDATE ${tableName} SET ${setClause} WHERE ${whereClause}`;\r\n await this.execute(sql, allValues);\r\n }\r\n\r\n private isConflictError(error: any): boolean {\r\n return (\r\n error.code === \"SQLITE_CONSTRAINT_UNIQUE\" ||\r\n error.code === \"SQLITE_CONSTRAINT_PRIMARYKEY\" ||\r\n (error.message && error.message.includes(\"UNIQUE constraint failed\"))\r\n );\r\n }\r\n\r\n // Database info methods\r\n async getDatabaseInfo(): Promise<any> {\r\n const tables = await this.execute(\r\n \"SELECT name FROM sqlite_master WHERE type='table'\"\r\n );\r\n const version = await this.getSchemaVersion();\r\n\r\n return {\r\n name: this.dbPath,\r\n tables: tables.rows.map((t) => t.name),\r\n isConnected: this.isConnected,\r\n version,\r\n };\r\n }\r\n\r\n async getTableInfo(tableName: string): Promise<any[]> {\r\n const result = await this.execute(`PRAGMA table_info(${tableName})`);\r\n return result.rows;\r\n }\r\n\r\n async dropTable(tableName: string): Promise<void> {\r\n const sql = `DROP TABLE IF EXISTS ${tableName}`;\r\n await this.execute(sql);\r\n }\r\n\r\n // Connection check method\r\n isConnectionOpen(): boolean {\r\n return this.isConnected && !!this.connection;\r\n }\r\n\r\n async ensureConnected(): Promise<void> {\r\n if (!this.isConnectionOpen()) {\r\n await this.connect();\r\n }\r\n }\r\n\r\n async execute(sql: string, params: any[] = []): Promise<SQLiteResult> {\r\n this.ensureConnected();\r\n return await this.connection!.execute(sql, params);\r\n }\r\n\r\n async getRst(sql: string, params: any[] = []): Promise<SQLiteRow> {\r\n const result = await this.execute(sql, params);\r\n return result.rows[0] || {};\r\n }\r\n\r\n async getRsts(sql: string, params: any[] = []): Promise<SQLiteRow[]> {\r\n const result = await this.execute(sql, params);\r\n return result.rows;\r\n }\r\n}\r\n","// src/core/database-factory.ts\r\nimport { SQLiteAdapter, DatabaseSchema, DbFactoryOptions } from \"../types\";\r\nimport { UniversalDAO } from \"./universal-dao\";\r\n\r\n/**\r\n * Universal DatabaseFactory - A powerful utility class designed to create and manage\r\n * UniversalDAO instances from JSON schema across all operating systems and frameworks\r\n * using TypeScript and JavaScript. It provides methods for creating new, opening existing\r\n * databases, checking integrity, and managing database lifecycle.\r\n */\r\nexport class DatabaseFactory {\r\n private static adapters: SQLiteAdapter[] = [];\r\n\r\n /**\r\n * Register a SQLite adapter for use by the factory\r\n * @param adapter The SQLite adapter to register\r\n */\r\n static registerAdapter(adapter: SQLiteAdapter): void {\r\n this.adapters.push(adapter);\r\n }\r\n\r\n /**\r\n * Get information about the current runtime environment\r\n * @returns A string describing the current environment\r\n */\r\n static getEnvironmentInfo(): string {\r\n if (\r\n typeof navigator !== \"undefined\" &&\r\n navigator.product === \"ReactNative\"\r\n ) {\r\n return \"React Native\";\r\n }\r\n if (typeof globalThis.Bun !== \"undefined\") return \"Bun\";\r\n if (typeof globalThis.Deno !== \"undefined\") return \"Deno\";\r\n if (typeof window !== \"undefined\") return \"Browser\";\r\n if (typeof process !== \"undefined\") return \"Node.js\";\r\n return \"Unknown\";\r\n }\r\n\r\n /**\r\n * Detect the best available SQLite adapter for the current environment\r\n * @returns The best available SQLite adapter\r\n * @throws Error if no supported adapter is found\r\n */\r\n private static detectBestAdapter(): SQLiteAdapter {\r\n for (const adapter of this.adapters) {\r\n if (adapter.isSupported()) {\r\n return adapter;\r\n }\r\n }\r\n throw new Error(\"No supported SQLite adapter found\");\r\n }\r\n\r\n /**\r\n * Validate schema version compatibility between database and config\r\n * @param dao The UniversalDAO instance\r\n * @param schema The database schema configuration\r\n */\r\n private static async validateSchemaVersion(\r\n dao: UniversalDAO,\r\n schema: DatabaseSchema\r\n ): Promise<void> {\r\n try {\r\n const dbInfo = await dao.getDatabaseInfo();\r\n if (dbInfo.version !== schema.version) {\r\n throw new Error(\r\n `Schema version mismatch: database (${dbInfo.version}) vs config (${schema.version})`\r\n );\r\n }\r\n } catch (error) {\r\n throw new Error(\r\n `Error validating schema version for ${schema.database_name}: ${\r\n (error as Error).message\r\n }`\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Validate the provided schema object to ensure it has minimum required properties\r\n * @param schema The schema object to validate\r\n * @returns True if the schema is valid, otherwise throws an error\r\n */\r\n private static validateSchema(schema: any): schema is DatabaseSchema {\r\n if (!schema) {\r\n throw new Error(\"Schema configuration is null or undefined.\");\r\n }\r\n if (\r\n typeof schema.database_name !== \"string\" ||\r\n schema.database_name.trim() === \"\"\r\n ) {\r\n throw new Error(\r\n \"Invalid or missing 'database_name' in schema. This is required to name the database file.\"\r\n );\r\n }\r\n if (\r\n typeof schema.schemas !== \"object\" ||\r\n schema.schemas === null ||\r\n Object.keys(schema.schemas).length === 0\r\n ) {\r\n throw new Error(\r\n \"Invalid or missing 'schemas' object in schema. At least one table definition is required.\"\r\n );\r\n }\r\n return true;\r\n }\r\n\r\n /**\r\n * Create a new UniversalDAO instance (equivalent to SQLiteDAO)\r\n * @param dbPath Path to the database file\r\n * @param options Configuration options\r\n * @returns A new UniversalDAO instance\r\n */\r\n static createDAO(\r\n dbPath: string,\r\n options?: {\r\n adapter?: SQLiteAdapter;\r\n createIfNotExists?: boolean;\r\n forceRecreate?: boolean;\r\n }\r\n ): UniversalDAO {\r\n let adapter: SQLiteAdapter;\r\n\r\n if (options?.adapter) {\r\n adapter = options.adapter;\r\n } else {\r\n adapter = this.detectBestAdapter();\r\n }\r\n\r\n return new UniversalDAO(adapter, dbPath, {\r\n createIfNotExists: options?.createIfNotExists ?? false,\r\n forceRecreate: options?.forceRecreate ?? false,\r\n });\r\n }\r\n\r\n /**\r\n * Opens an existing database without initializing its schema.\r\n * Includes integrity check to detect corrupted files.\r\n * @param dbName The name of the database (e.g., 'core.db' or 'core').\r\n * @param options Additional options for database connection.\r\n * @returns A promise that resolves to a connected UniversalDAO instance.\r\n */\r\n public static async openExisting(\r\n dbName: string,\r\n options: Omit<\r\n DbFactoryOptions,\r\n \"config\" | \"configAsset\" | \"configPath\"\r\n > = {}\r\n ): Promise<UniversalDAO> {\r\n // Determine the database file path\r\n const dbFileName = dbName.endsWith(\".db\") ? dbName : `${dbName}.db`;\r\n\r\n // Create and connect DAO instance\r\n const dao = this.createDAO(dbFileName, options);\r\n\r\n try {\r\n await dao.connect();\r\n // Run integrity check to detect corrupted files\r\n await dao.execute(\"PRAGMA integrity_check\");\r\n return dao;\r\n } catch (error) {\r\n await dao.close();\r\n throw new Error(\r\n `Error opening database '${dbFileName}': ${(error as Error).message}`\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Internal method to create or open database with various options\r\n * @param options Configuration options\r\n * @param isForceInit Allow re-initialization of existing database\r\n * @param isForceDelete Force delete and recreate database\r\n * @returns Promise that resolves to initialized UniversalDAO\r\n */\r\n private static async createOrOpenInternal(\r\n options: DbFactoryOptions,\r\n isForceInit: boolean = false,\r\n isForceDelete: boolean = false\r\n ): Promise<UniversalDAO> {\r\n let schema: DatabaseSchema;\r\n\r\n // Step 1: Load schema\r\n if (options.config) {\r\n schema = options.config;\r\n } else if (options.configAsset) {\r\n schema = options.configAsset;\r\n } else {\r\n throw new Error(\r\n \"Either 'config', 'configAsset', or 'configPath' must be provided to the factory.\"\r\n );\r\n }\r\n\r\n // Step 2: Validate schema\r\n this.validateSchema(schema);\r\n\r\n // Step 3: Determine database path\r\n const dbFileName = schema.database_name.endsWith(\".db\")\r\n ? schema.database_name\r\n : `${schema.database_name}.db`;\r\n\r\n // Step 4: Create DAO instance\r\n const dao = this.createDAO(dbFileName, {\r\n adapter: options.adapter,\r\n createIfNotExists: isForceInit,\r\n forceRecreate: isForceDelete,\r\n });\r\n\r\n try {\r\n // Step 5: Connect to database\r\n await dao.connect();\r\n\r\n // Step 6: Initialize schema if needed\r\n await dao.initializeFromSchema(schema);\r\n\r\n // Step 7: Validate schema version compatibility\r\n // Validate schema version compatibility\r\n try {\r\n await this.validateSchemaVersion(dao, schema);\r\n } catch (schemaError: any) {\r\n await dao.close();\r\n throw new Error(\r\n `Schema mismatch in existing database. Use forceRecreate=true to recreate with updated schema. Error: ${schemaError.message}`\r\n );\r\n }\r\n return dao;\r\n } catch (error) {\r\n if (dao.isConnectionOpen()) {\r\n await dao.close();\r\n }\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Create a new database (DANGEROUS - will delete existing database)\r\n * Only use this for migrations or development, not in production\r\n * @param options Configuration options\r\n * @returns Promise that resolves to initialized UniversalDAO\r\n */\r\n public static async create(options: DbFactoryOptions): Promise<UniversalDAO> {\r\n return this.createOrOpenInternal(options, true, true);\r\n }\r\n\r\n /**\r\n * Smart method to create or open database\r\n * Only creates new tables if they don't exist and initializes file initially\r\n * Will check if file exists and is valid before deciding to create new or open existing\r\n * @param options Database configuration options\r\n * @param isForceInit Force re-initialization of tables even if they exist (default: false)\r\n * @returns Promise that resolves to initialized UniversalDAO\r\n */\r\n public static async createOrOpen(\r\n options: DbFactoryOptions,\r\n isForceInit: boolean = false\r\n ): Promise<UniversalDAO> {\r\n return this.createOrOpenInternal(options, isForceInit);\r\n }\r\n\r\n /**\r\n * Convenience method to create a database from a JSON asset\r\n * @param configAsset The imported/required JSON configuration\r\n * @param options Additional options for database creation\r\n * @returns Promise that resolves to initialized UniversalDAO\r\n */\r\n public static async createFromAsset(\r\n configAsset: DatabaseSchema,\r\n options: Omit<\r\n DbFactoryOptions,\r\n \"config\" | \"configAsset\" | \"configPath\"\r\n > = {}\r\n ): Promise<UniversalDAO> {\r\n try {\r\n return await this.create({\r\n ...options,\r\n configAsset,\r\n });\r\n } catch (error) {\r\n throw new Error(\r\n `Error creating database from asset: ${(error as Error).message}`\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Convenience method to create a database from a configuration object\r\n * @param config The database schema configuration object\r\n * @param options Additional options for database creation\r\n * @returns Promise that resolves to initialized UniversalDAO\r\n */\r\n public static async createFromConfig(\r\n config: DatabaseSchema,\r\n options: Omit<\r\n DbFactoryOptions,\r\n \"config\" | \"configAsset\" | \"configPath\"\r\n > = {}\r\n ): Promise<UniversalDAO> {\r\n try {\r\n return await this.create({\r\n ...options,\r\n config,\r\n });\r\n } catch (error) {\r\n throw new Error(\r\n `Error creating database from config: ${(error as Error).message}`\r\n );\r\n }\r\n }\r\n}\r\n\r\nexport default DatabaseFactory;\r\n","// src/core/database-manager.ts\r\n\r\nimport { DatabaseSchema, ImportOptions, ImportResult, ColumnMapping } from \"../types\";\r\nimport { DatabaseFactory } from \"./database-factory\";\r\nimport { UniversalDAO } from \"./universal-dao\";\r\n\r\nexport type DatabaseConnections = {\r\n [key: string]: UniversalDAO;\r\n};\r\n\r\nexport interface RoleConfig {\r\n roleName: string;\r\n requiredDatabases: string[];\r\n optionalDatabases?: string[];\r\n priority?: number;\r\n}\r\n\r\nexport type RoleRegistry = {\r\n [roleName: string]: RoleConfig;\r\n};\r\n\r\nexport interface DatabaseImportConfig {\r\n databaseKey: string;\r\n tableName: string;\r\n data: Record<string, any>[];\r\n options?: Partial<ImportOptions>;\r\n columnMappings?: ColumnMapping[];\r\n}\r\n\r\nexport interface BulkImportResult {\r\n totalDatabases: number;\r\n successDatabases: number;\r\n results: Record<string, ImportResult>;\r\n errors: Record<string, Error>;\r\n executionTime: number;\r\n}\r\n\r\nexport interface SchemaManager {\r\n getSchema(key: string): DatabaseSchema | undefined;\r\n registerSchema(key: string, schema: DatabaseSchema): void;\r\n getAllSchemaKeys(): string[];\r\n hasSchema(key: string): boolean;\r\n}\r\n\r\nexport class DatabaseManager {\r\n private static maxConnections = 10;\r\n private static connections: DatabaseConnections = {};\r\n private static isInitialized = false;\r\n private static roleRegistry: RoleRegistry = {};\r\n private static currentRole: string | null = null;\r\n private static currentUserRoles: string[] = [];\r\n private static activeDatabases: Set<string> = new Set();\r\n private static isClosingConnections = false;\r\n \r\n // Schema management - support dynamic schemas\r\n private static schemaConfigurations: Record<string, DatabaseSchema> = {};\r\n private static schemaManager: SchemaManager | null = null;\r\n \r\n // Event system for database reconnection\r\n private static eventListeners: Map<string, Array<(dao: UniversalDAO) => void>> = new Map();\r\n\r\n /**\r\n * Get the maximum number of allowed database connections\r\n */\r\n public static getMaxConnections(): number {\r\n return this.maxConnections;\r\n }\r\n\r\n /**\r\n * Set the maximum number of allowed database connections\r\n * @param maxConnections - The maximum number of connections (must be positive)\r\n * @throws Error if maxConnections is not positive or if current connections exceed the new limit\r\n */\r\n public static setMaxConnections(maxConnections: number): void {\r\n if (maxConnections <= 0) {\r\n throw new Error('Maximum connections must be a positive number');\r\n }\r\n\r\n const currentConnectionCount = Object.keys(this.connections).length;\r\n if (currentConnectionCount > maxConnections) {\r\n throw new Error(\r\n `Cannot set maximum connections to ${maxConnections}. ` +\r\n `Current active connections (${currentConnectionCount}) exceed the new limit. ` +\r\n `Please close some connections first.`\r\n );\r\n }\r\n\r\n this.maxConnections = maxConnections;\r\n }\r\n\r\n /**\r\n * Set a schema manager for dynamic schema handling\r\n */\r\n public static setSchemaManager(manager: SchemaManager): void {\r\n this.schemaManager = manager;\r\n }\r\n\r\n /**\r\n * Register a schema configuration dynamically\r\n */\r\n public static registerSchema(key: string, schema: DatabaseSchema): void {\r\n this.schemaConfigurations[key] = schema;\r\n }\r\n\r\n /**\r\n * Register multiple schemas at once\r\n */\r\n public static registerSchemas(schemas: Record<string, DatabaseSchema>): void {\r\n Object.entries(schemas).forEach(([key, schema]) => {\r\n this.registerSchema(key, schema);\r\n });\r\n }\r\n\r\n /**\r\n * Get schema from internal store or external manager\r\n */\r\n private static getSchema(key: string): DatabaseSchema | undefined {\r\n // Try internal schemas first\r\n if (this.schemaConfigurations[key]) {\r\n return this.schemaConfigurations[key];\r\n }\r\n \r\n // Try external schema manager\r\n if (this.schemaManager) {\r\n return this.schemaManager.getSchema(key);\r\n }\r\n \r\n return undefined;\r\n }\r\n\r\n /**\r\n * Get all available schema keys\r\n */\r\n public static getAvailableSchemas(): string[] {\r\n const internalKeys = Object.keys(this.schemaConfigurations);\r\n const externalKeys = this.schemaManager?.getAllSchemaKeys() || [];\r\n return [...new Set([...internalKeys, ...externalKeys])];\r\n }\r\n\r\n /**\r\n * Register a role configuration\r\n */\r\n public static registerRole(roleConfig: RoleConfig): void {\r\n this.roleRegistry[roleConfig.roleName] = roleConfig;\r\n }\r\n\r\n /**\r\n * Register multiple roles\r\n */\r\n public static registerRoles(roleConfigs: RoleConfig[]): void {\r\n roleConfigs.forEach(config => this.registerRole(config));\r\n }\r\n\r\n /**\r\n * Get all registered roles\r\n */\r\n public static getRegisteredRoles(): RoleRegistry {\r\n return { ...this.roleRegistry };\r\n }\r\n\r\n /**\r\n * Get databases for a specific role\r\n */\r\n public static getRoleDatabases(roleName: string): string[] {\r\n const roleConfig = this.roleRegistry[roleName];\r\n if (!roleConfig) {\r\n throw new Error(`Role '${roleName}' is not registered.`);\r\n }\r\n return [\r\n ...roleConfig.requiredDatabases,\r\n ...(roleConfig.optionalDatabases || []),\r\n ];\r\n }\r\n\r\n /**\r\n * Get databases for current user roles\r\n */\r\n public static getCurrentUserDatabases(): string[] {\r\n const allDatabases = new Set<string>();\r\n allDatabases.add('core'); // Core database is always included\r\n \r\n for (const roleName of this.currentUserRoles) {\r\n const roleConfig = this.roleRegistry[roleName];\r\n if (roleConfig) {\r\n roleConfig.requiredDatabases.forEach(db => allDatabases.add(db));\r\n if (roleConfig.optionalDatabases) {\r\n roleConfig.optionalDatabases.forEach(db => allDatabases.add(db));\r\n }\r\n }\r\n }\r\n \r\n return Array.from(allDatabases);\r\n }\r\n\r\n /**\r\n * Initialize core database connection\r\n */\r\n public static async initializeCoreConnection(): Promise<void> {\r\n if (this.connections['core']) {\r\n return;\r\n }\r\n\r\n try {\r\n const coreSchema = this.getSchema('core');\r\n if (!coreSchema) {\r\n throw new Error('Core database schema not found.');\r\n }\r\n\r\n const dao = await DatabaseFactory.createOrOpen({ config: coreSchema }, false);\r\n await dao.execute('PRAGMA integrity_check');\r\n this.connections['core'] = dao;\r\n } catch (error) {\r\n throw new Error(`Error initializing core database: ${(error as Error).message}`);\r\n }\r\n }\r\n\r\n /**\r\n * Set current user roles and initialize connections\r\n */\r\n public static async setCurrentUserRoles(\r\n userRoles: string[],\r\n primaryRole?: string,\r\n ): Promise<void> {\r\n // Validate roles exist\r\n for (const roleName of userRoles) {\r\n if (!this.roleRegistry[roleName]) {\r\n throw new Error(`Role '${roleName}' is not registered. Please register it first.`);\r\n }\r\n }\r\n\r\n const previousRoles = [...this.currentUserRoles];\r\n this.currentUserRoles = userRoles;\r\n this.currentRole = primaryRole || userRoles[0] || null;\r\n\r\n await this.initializeUserRoleConnections();\r\n await this.cleanupUnusedConnections(previousRoles);\r\n }\r\n\r\n /**\r\n * Get current user roles\r\n */\r\n public static getCurrentUserRoles(): string[] {\r\n return [...this.currentUserRoles];\r\n }\r\n\r\n /**\r\n * Get current primary role\r\n */\r\n public static getCurrentRole(): string | null {\r\n return this.currentRole;\r\n }\r\n\r\n /**\r\n * Initialize connections for current user roles\r\n */\r\n private static async initializeUserRoleConnections(): Promise<void> {\r\n const requiredDatabases = this.getCurrentUserDatabases();\r\n const failedInitializations: { key: string; error: Error }[] = [];\r\n\r\n const initPromises = requiredDatabases.map(async dbKey => {\r\n if (this.connections[dbKey]) {\r\n return; // Already connected\r\n }\r\n\r\n try {\r\n const schema = this.getSchema(dbKey);\r\n if (!schema) {\r\n throw new Error(`Database key '${dbKey}' not found in schema configurations.`);\r\n }\r\n\r\n const dao = await DatabaseFactory.createOrOpen({ config: schema }, false);\r\n await dao.execute('PRAGMA integrity_check');\r\n this.connections[dbKey] = dao;\r\n } catch (error) {\r\n const err = error instanceof Error ? error : new Error(String(error));\r\n \r\n // Check if database is required for any role\r\n const isRequired = this.currentUserRoles.some(roleName => {\r\n const roleConfig = this.roleRegistry[roleName];\r\n return roleConfig && roleConfig.requiredDatabases.includes(dbKey);\r\n });\r\n\r\n if (isRequired) {\r\n failedInitializations.push({ key: dbKey, error: err });\r\n }\r\n // Optional databases that fail are ignored\r\n }\r\n });\r\n\r\n await Promise.all(initPromises);\r\n\r\n if (failedInitializations.length > 0) {\r\n const errorSummary = failedInitializations\r\n .map(f => ` - ${f.key}: ${f.error.message}`)\r\n .join('\\n');\r\n throw new Error(`Failed to initialize required databases for user roles:\\n${errorSummary}`);\r\n }\r\n }\r\n\r\n /**\r\n * Cleanup unused connections\r\n */\r\n private static async cleanupUnusedConnections(previousRoles: string[]): Promise<void> {\r\n const previousDatabases = new Set<string>();\r\n previousDatabases.add('core');\r\n\r\n for (const roleName of previousRoles) {\r\n const roleConfig = this.roleRegistry[roleName];\r\n if (roleConfig) {\r\n roleConfig.requiredDatabases.forEach(db => previousDatabases.add(db));\r\n if (roleConfig.optionalDatabases) {\r\n roleConfig.optionalDatabases.forEach(db => previousDatabases.add(db));\r\n }\r\n }\r\n }\r\n\r\n const currentDatabases = new Set(this.getCurrentUserDatabases());\r\n const databasesToClose = Array.from(previousDatabases).filter(\r\n db => !currentDatabases.has(db),\r\n );\r\n\r\n if (databasesToClose.length > 0) {\r\n for (const dbKey of databasesToClose) {\r\n if (this.connections[dbKey]) {\r\n try {\r\n await this.connections[dbKey].close();\r\n delete this.connections[dbKey];\r\n } catch (error) {\r\n // Log error but continue cleanup\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Check if current user has access to database\r\n */\r\n public static hasAccessToDatabase(dbKey: string): boolean {\r\n // For universal version, we can implement more flexible access control\r\n // Currently allowing access to all registered schemas\r\n return this.getSchema(dbKey) !== undefined;\r\n }\r\n\r\n /**\r\n * Get database connection\r\n */\r\n public static get(key: string): UniversalDAO {\r\n if (!this.hasAccessToDatabase(key)) {\r\n throw new Error(`Access denied: Database '${key}' is not accessible.`);\r\n }\r\n\r\n const dao = this.connections[key];\r\n if (!dao) {\r\n throw new Error(`Database '${key}' is not connected. Please ensure it's initialized.`);\r\n }\r\n\r\n return dao;\r\n }\r\n\r\n /**\r\n * Register event listener for database reconnection\r\n */\r\n public static onDatabaseReconnect(\r\n schemaName: string,\r\n callback: (dao: UniversalDAO) => void,\r\n ): void {\r\n if (!this.eventListeners.has(schemaName)) {\r\n this.eventListeners.set(schemaName, []);\r\n }\r\n this.eventListeners.get(schemaName)!.push(callback);\r\n }\r\n\r\n /**\r\n * Remove event listener for database reconnection\r\n */\r\n public static offDatabaseReconnect(\r\n schemaName: string,\r\n callback: (dao: UniversalDAO) => void,\r\n ): void {\r\n const listeners = this.eventListeners.get(schemaName);\r\n if (listeners) {\r\n const index = listeners.indexOf(callback);\r\n if (index > -1) {\r\n listeners.splice(index, 1);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Notify listeners of database reconnection\r\n */\r\n private static notifyDatabaseReconnect(schemaName: string, dao: UniversalDAO): void {\r\n const listeners = this.eventListeners.get(schemaName);\r\n if (listeners) {\r\n listeners.forEach(callback => {\r\n try {\r\n callback(dao);\r\n } catch (error) {\r\n // Handle callback errors gracefully\r\n }\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Close all connections\r\n */\r\n private static async closeAllConnections(): Promise<void> {\r\n if (this.isClosingConnections) {\r\n return;\r\n }\r\n\r\n this.isClosingConnections = true;\r\n try {\r\n // Save active databases\r\n const currentActiveDb = Object.keys(this.connections);\r\n currentActiveDb.forEach(dbKey => this.activeDatabases.add(dbKey));\r\n\r\n const closePromises = Object.entries(this.connections).map(\r\n async ([dbKey, dao]) => {\r\n try {\r\n await dao.close();\r\n } catch (error) {\r\n // Log error but continue closing\r\n }\r\n },\r\n );\r\n\r\n await Promise.all(closePromises);\r\n this.connections = {};\r\n } finally {\r\n this.isClosingConnections = false;\r\n }\r\n }\r\n\r\n /**\r\n * Reopen connections\r\n */\r\n public static async reopenConnections(): Promise<void> {\r\n await this.initializeCoreConnection();\r\n \r\n if (this.currentUserRoles.length > 0) {\r\n await this.initializeUserRoleConnections();\r\n }\r\n\r\n // Reinitialize previously active databases\r\n const activeDbArray = Array.from(this.activeDatabases);\r\n if (activeDbArray.length > 0) {\r\n for (const dbKey of activeDbArray) {\r\n if (!this.connections[dbKey]) {\r\n const schema = this.getSchema(dbKey);\r\n if (schema) {\r\n try {\r\n const dao = await DatabaseFactory.createOrOpen({ config: schema }, false);\r\n await dao.connect();\r\n this.connections[dbKey] = dao;\r\n this.notifyDatabaseReconnect(dbKey, dao);\r\n } catch (error) {\r\n // Log error but continue\r\n }\r\n }\r\n } else if (this.connections[dbKey]) {\r\n // Database exists, notify services\r\n this.notifyDatabaseReconnect(dbKey, this.connections[dbKey]);\r\n }\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Ensure database connection exists and is active\r\n */\r\n public static async ensureDatabaseConnection(key: string): Promise<UniversalDAO> {\r\n this.activeDatabases.add(key);\r\n\r\n if (!this.hasAccessToDatabase(key)) {\r\n throw new Error(`Access denied: Database '${key}' is not accessible.`);\r\n }\r\n\r\n if (this.connections[key]) {\r\n try {\r\n const isConnected = this.connections[key].isConnectionOpen();\r\n if (isConnected) {\r\n return this.connections[key];\r\n } else {\r\n // Clean up inactive connection\r\n try {\r\n await this.connections[key].close().catch(() => {});\r\n } catch (error) {\r\n // Ignore cleanup errors\r\n }\r\n delete this.connections[key];\r\n }\r\n } catch (error) {\r\n delete this.connections[key];\r\n }\r\n }\r\n\r\n // Create new connection\r\n return await this.getLazyLoading(key);\r\n }\r\n\r\n /**\r\n * Get all connections\r\n */\r\n public static getConnections(): DatabaseConnections {\r\n return { ...this.connections };\r\n }\r\n\r\n /**\r\n * Open all existing databases\r\n */\r\n public static async openAllExisting(databaseKeys: string[]): Promise<boolean> {\r\n const failedOpens: { key: string; error: Error }[] = [];\r\n\r\n for (const key of databaseKeys) {\r\n try {\r\n const schema = this.getSchema(key);\r\n if (!schema) {\r\n throw new Error(`Invalid database key: ${key}. Schema not found.`);\r\n }\r\n\r\n const dao = await DatabaseFactory.createOrOpen({ config: schema }, false);\r\n await dao.execute('PRAGMA integrity_check');\r\n this.connections[key] = dao;\r\n } catch (error) {\r\n const err = error instanceof Error ? error : new Error(String(error));\r\n failedOpens.push({ key, error: err });\r\n }\r\n }\r\n\r\n if (failedOpens.length > 0) {\r\n const errorSummary = failedOpens\r\n .map(f => ` - ${f.key}: ${f.error.message}`)\r\n .join('\\n');\r\n throw new Error(`Failed to open one or more databases:\\n${errorSummary}`);\r\n }\r\n\r\n this.isInitialized = true;\r\n return true;\r\n }\r\n\r\n /**\r\n * Initialize databases lazily\r\n */\r\n public static async initLazySchema(databaseKeys: string[]): Promise<boolean> {\r\n const invalidKeys = databaseKeys.filter(key => !this.getSchema(key));\r\n if (invalidKeys.length > 0) {\r\n throw new Error(`Invalid database keys: ${invalidKeys.join(', ')}. Schemas not found.`);\r\n }\r\n\r\n const newConnectionsCount = databaseKeys.filter(key => !this.connections[key]).length;\r\n const currentConnectionsCount = Object.keys(this.connections).length;\r\n \r\n if (currentConnectionsCount + newConnectionsCount > this.maxConnections) {\r\n throw new Error(\r\n `Cannot initialize ${newConnectionsCount} new connections. Would exceed maximum of ${this.maxConnections} connections. Current: ${currentConnectionsCount}`,\r\n );\r\n }\r\n\r\n const failedInitializations: { key: string; error: Error }[] = [];\r\n const initPromises = databaseKeys.map(async key => {\r\n if (this.connections[key]) {\r\n return; // Already initialized\r\n }\r\n\r\n try {\r\n const schema = this.getSchema(key)!;\r\n const dao = await DatabaseFactory.createOrOpen({ config: schema }, false);\r\n await dao.execute('PRAGMA integrity_check');\r\n this.connections[key] = dao;\r\n } catch (error) {\r\n const err = error instanceof Error ? error : new Error(String(error));\r\n failedInitializations.push({ key, error: err });\r\n }\r\n });\r\n\r\n await Promise.all(initPromises);\r\n\r\n if (failedInitializations.length > 0) {\r\n const errorSummary = failedInitializations\r\n .map(f => ` - ${f.key}: ${f.error.message}`)\r\n .join('\\n');\r\n throw new Error(`Failed to initialize one or more databases:\\n${errorSummary}`);\r\n }\r\n\r\n if (Object.keys(this.connections).length > 0) {\r\n this.isInitialized = true;\r\n }\r\n\r\n return true;\r\n }\r\n\r\n /**\r\n * Initialize all available databases\r\n */\r\n public static async initializeAll(): Promise<void> {\r\n if (this.isInitialized) {\r\n return;\r\n }\r\n\r\n const availableSchemas = this.getAvailableSchemas();\r\n const failedInitializations: { key: string; error: Error }[] = [];\r\n\r\n const initPromises = availableSchemas.map(async key => {\r\n try {\r\n const schema = this.getSchema(key)!;\r\n const dao = await DatabaseFactory.createOrOpen({ config: schema }, false);\r\n this.connections[key] = dao;\r\n } catch (error) {\r\n const err = error instanceof Error ? error : new Error(String(error));\r\n failedInitializations.push({ key, error: err });\r\n }\r\n });\r\n\r\n await Promise.all(initPromises);\r\n\r\n if (failedInitializations.length > 0) {\r\n this.isInitialized = false;\r\n const errorSummary = failedInitializations\r\n .map(f => ` - ${f.key}: ${f.error.message}`)\r\n .join('\\n');\r\n throw new Error(`Failed to initialize one or more databases:\\n${errorSummary}`);\r\n }\r\n\r\n this.isInitialized = true;\r\n }\r\n\r\n /**\r\n * Get database with lazy loading\r\n */\r\n public static async getLazyLoading(key: string): Promise<UniversalDAO> {\r\n this.activeDatabases.add(key);\r\n\r\n if (!this.hasAccessToDatabase(key)) {\r\n throw new Error(`Access denied: Database '${key}' is not accessible.`);\r\n }\r\n\r\n if (!this.connections[key]) {\r\n const schema = this.getSchema(key);\r\n if (!schema) {\r\n throw new Error(`Invalid database key: ${key}. Schema not found.`);\r\n }\r\n\r\n if (Object.keys(this.connections).length >= this.maxConnections) {\r\n throw new Error('Maximum number of database connections reached');\r\n }\r\n\r\n const dao = await DatabaseFactory.createOrOpen({ config: schema }, false);\r\n await dao.connect();\r\n this.connections[key] = dao;\r\n }\r\n\r\n this.isInitialized = true;\r\n return this.connections[key];\r\n }\r\n\r\n /**\r\n * Execute cross-schema transaction\r\n */\r\n public static async executeCrossSchemaTransaction(\r\n schemas: string[],\r\n callback: (daos: Record<string, UniversalDAO>) => Promise<void>,\r\n ): Promise<void> {\r\n for (const key of schemas) {\r\n if (!this.hasAccessToDatabase(key)) {\r\n throw new Error(`Access denied: Database '${key}' is not accessible.`);\r\n }\r\n }\r\n\r\n const daos = schemas.reduce((acc, key) => {\r\n acc[key] = this.get(key);\r\n return acc;\r\n }, {} as Record<string, UniversalDAO>);\r\n\r\n try {\r\n await Promise.all(Object.values(daos).map(dao => dao.beginTransaction()));\r\n await callback(daos);\r\n await Promise.all(Object.values(daos).map(dao => dao.commitTransaction()));\r\n } catch (error) {\r\n await Promise.all(Object.values(daos).map(dao => dao.rollbackTransaction()));\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Import data to table\r\n */\r\n public static async importDataToTable(\r\n databaseKey: string,\r\n tableName: string,\r\n data: Record<string, any>[],\r\n options: Partial<ImportOptions> = {},\r\n ): Promise<ImportResult> {\r\n if (!this.hasAccessToDatabase(databaseKey)) {\r\n throw new Error(`Access denied: Database '${databaseKey}' is not accessible.`);\r\n }\r\n\r\n const dao = this.get(databaseKey);\r\n try {\r\n const result = await dao.importData({\r\n tableName,\r\n data,\r\n ...options,\r\n });\r\n return result;\r\n } catch (error) {\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Import data with column mapping\r\n */\r\n public static async importDataWithMapping(\r\n databaseKey: string,\r\n tableName: string,\r\n data: Record<string, any>[],\r\n columnMappings: ColumnMapping[],\r\n options: Partial<ImportOptions> = {},\r\n ): Promise<ImportResult> {\r\n if (!this.hasAccessToDatabase(databaseKey)) {\r\n throw new Error(`Access denied: Database '${databaseKey}' is not accessible.`);\r\n }\r\n\r\n const dao = this.get(databaseKey);\r\n try {\r\n const result = await dao.importDataWithMapping(\r\n tableName,\r\n data,\r\n columnMappings,\r\n options,\r\n );\r\n return result;\r\n } catch (error) {\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Bulk import data\r\n */\r\n public static async bulkImport(importConfigs: DatabaseImportConfig[]): Promise<BulkImportResult> {\r\n const startTime = Date.now();\r\n const result: BulkImportResult = {\r\n totalDatabases: importConfigs.length,\r\n successDatabases: 0,\r\n results: {},\r\n errors: {},\r\n executionTime: 0,\r\n };\r\n\r\n for (const config of importConfigs) {\r\n const configKey = `${config.databaseKey}.${config.tableName}`;\r\n try {\r\n if (!this.hasAccessToDatabase(config.databaseKey)) {\r\n throw new Error(`Access denied: Database '${config.databaseKey}' is not accessible.`);\r\n }\r\n\r\n const dao = this.get(config.databaseKey);\r\n let importResult: ImportResult;\r\n\r\n if (config.columnMappings) {\r\n importResult = await dao.importDataWithMapping(\r\n config.tableName,\r\n config.data,\r\n config.columnMappings,\r\n config.options,\r\n );\r\n } else {\r\n importResult = await dao.importData({\r\n tableName: config.tableName,\r\n data: config.data,\r\n ...config.options,\r\n });\r\n }\r\n\r\n result.results[configKey] = importResult;\r\n result.successDatabases++;\r\n } catch (error) {\r\n const err = error instanceof Error ? error : new Error(String(error));\r\n result.errors[configKey] = err;\r\n }\r\n }\r\n\r\n result.executionTime = Date.now() - startTime;\r\n return result;\r\n }\r\n\r\n /**\r\n * Import from CSV\r\n */\r\n public static async importFromCSV(\r\n databaseKey: string,\r\n tableName: string,\r\n csvData: string,\r\n options: {\r\n delimiter?: string;\r\n hasHeader?: boolean;\r\n columnMappings?: ColumnMapping[];\r\n } & Partial<ImportOptions> = {},\r\n ): Promise<ImportResult> {\r\n if (!this.hasAccessToDatabase(databaseKey)) {\r\n throw new Error(`Access denied: Database '${databaseKey}' is not accessible.`);\r\n }\r\n\r\n const dao = this.get(databaseKey);\r\n try {\r\n const result = await dao.importFromCSV(tableName, csvData, options);\r\n return result;\r\n } catch (error) {\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Get connection count\r\n */\r\n public static getConnectionCount(): number {\r\n return Object.keys(this.connections).length;\r\n }\r\n\r\n /**\r\n * List all active connections\r\n */\r\n public static listConnections(): string[] {\r\n return Object.keys(this.connections);\r\n }\r\n\r\n /**\r\n * Close specific connection\r\n */\r\n public static async closeConnection(dbKey: string): Promise<void> {\r\n const dao = this.connections[dbKey];\r\n if (dao) {\r\n await dao.disconnect();\r\n delete this.connections[dbKey];\r\n }\r\n }\r\n\r\n /**\r\n * Close all connections and reset state\r\n */\r\n public static async closeAll(): Promise<void> {\r\n await this.closeAllConnections();\r\n \r\n this.currentUserRoles = [];\r\n this.currentRole = null;\r\n this.isInitialized = false;\r\n this.activeDatabases.clear();\r\n this.eventListeners.clear();\r\n this.isClosingConnections = false;\r\n }\r\n\r\n /**\r\n * Logout user - close role-specific connections\r\n */\r\n public static async logout(): Promise<void> {\r\n const connectionsToClose = Object.keys(this.connections).filter(\r\n key => key !== 'core',\r\n );\r\n\r\n for (const dbKey of connectionsToClose) {\r\n try {\r\n await this.connections[dbKey].close();\r\n delete this.connections[dbKey];\r\n } catch (error) {\r\n // Log error but continue cleanup\r\n }\r\n }\r\n\r\n this.currentUserRoles = [];\r\n this.currentRole = null;\r\n }\r\n}","// src/core/base-service.ts\r\nimport {\r\n QueryTable,\r\n WhereClause,\r\n OrderByClause,\r\n ImportResult,\r\n ColumnMapping,\r\n ImportOptions,\r\n ServiceStatus,\r\n HealthCheckResult,\r\n} from \"../types\";\r\nimport { UniversalDAO } from \"./universal-dao\";\r\nimport { DatabaseManager } from \"./database-manager\";\r\n\r\nexport interface FindOptions {\r\n where?: WhereClause[];\r\n orderBy?: OrderByClause[];\r\n limit?: number;\r\n offset?: number;\r\n columns?: string[];\r\n}\r\n\r\nexport type ErrorHandler = (error: Error) => void;\r\nexport type EventHandler = (data: any) => void;\r\n\r\n/**\r\n * Universal BaseService - An enhanced abstract base class designed to provide\r\n * comprehensive CRUD operations and database management features across all\r\n * operating systems and frameworks using TypeScript and JavaScript.\r\n */\r\nexport abstract class BaseService<T = any> {\r\n protected dao: UniversalDAO | null = null;\r\n protected schemaName: string;\r\n protected tableName: string;\r\n protected isOpened: boolean = false;\r\n protected isInitialized: boolean = false;\r\n protected errorHandlers: Map<string, ErrorHandler> = new Map();\r\n protected eventListeners: Map<string, EventHandler[]> = new Map();\r\n protected primaryKeyFields: string[] = [\"id\"];\r\n private cache: Map<string, any> = new Map();\r\n private reconnectHandler: (dao: UniversalDAO) => void;\r\n\r\n constructor(schemaName: string, tableName?: string) {\r\n this.schemaName = schemaName;\r\n this.tableName = tableName || schemaName;\r\n\r\n // Register reconnect listener for database reconnection\r\n this.reconnectHandler = (newDao: UniversalDAO) => {\r\n this.dao = newDao;\r\n this._emit(\"daoReconnected\", { schemaName: this.schemaName });\r\n };\r\n\r\n DatabaseManager.onDatabaseReconnect(schemaName, this.reconnectHandler);\r\n this.bindMethods();\r\n }\r\n\r\n private bindMethods(): void {\r\n const methods = Object.getOwnPropertyNames(Object.getPrototypeOf(this));\r\n methods.forEach((method) => {\r\n if (\r\n typeof (this as any)[method] === \"function\" &&\r\n method !== \"constructor\"\r\n ) {\r\n (this as any)[method] = (this as any)[method].bind(this);\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Set primary key fields for the service\r\n */\r\n setPrimaryKeyFields(fields: string[]): this {\r\n this.primaryKeyFields = fields;\r\n return this;\r\n }\r\n\r\n /**\r\n * Initialize the service and establish database connection\r\n */\r\n async init(): Promise<this> {\r\n try {\r\n if (this.isInitialized) {\r\n return this;\r\n }\r\n\r\n this.dao = await DatabaseManager.getLazyLoading(this.schemaName);\r\n\r\n if (!this.dao) {\r\n throw new Error(\r\n `Failed to initialize DAO for schema: ${this.schemaName}`\r\n );\r\n }\r\n\r\n if (!this.dao.isConnectionOpen()) {\r\n await this.dao.connect();\r\n }\r\n\r\n this.isOpened = true;\r\n this.isInitialized = true;\r\n this._emit(\"initialized\", { schemaName: this.schemaName });\r\n\r\n return this;\r\n } catch (error) {\r\n this._handleError(\"INIT_ERROR\", error as Error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Create a new record - Safe version với comprehensive error handling\r\n */\r\n async create(data: Partial<T>): Promise<T | null> {\r\n await this._ensureInitialized();\r\n await this.ensureValidConnection();\r\n try {\r\n this._validateData(data);\r\n const queryTable = this.buildDataTable(data as Record<string, any>);\r\n const result = await this.dao!.insert(queryTable);\r\n if (result.rowsAffected === 0) {\r\n throw new Error(\"Insert operation failed - no rows affected\");\r\n }\r\n let createdRecord: T | null = null;\r\n const primaryKeyValue = data[this.primaryKeyFields[0] as keyof T];\r\n try {\r\n if (primaryKeyValue !== undefined && primaryKeyValue !== null) {\r\n createdRecord = await this.findById(primaryKeyValue as any);\r\n } else if (result.lastInsertRowId) {\r\n createdRecord = await this.findById(result.lastInsertRowId);\r\n }\r\n } catch (findError) {\r\n console.warn(`Warning: Could not retrieve created record:`, findError);\r\n }\r\n if (!createdRecord) {\r\n createdRecord = data as T;\r\n }\r\n this._emit(\"dataCreated\", { operation: \"create\", data: createdRecord });\r\n return createdRecord;\r\n } catch (error) {\r\n this._handleError(\"CREATE_ERROR\", error as Error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Update an existing record\r\n */\r\n async update(id: any, data: Partial<T>): Promise<T | null> {\r\n await this._ensureInitialized();\r\n\r\n try {\r\n if (!id) {\r\n throw new Error(\"ID is required for update\");\r\n }\r\n\r\n this._validateData(data);\r\n const updateData = {\r\n ...data,\r\n [this.primaryKeyFields[0]]: id,\r\n };\r\n\r\n const queryTable = this.buildDataTable(updateData as Record<string, any>);\r\n await this.dao!.update(queryTable);\r\n\r\n const result = await this.findById(id);\r\n this._emit(\"dataUpdated\", { operation: \"update\", id, data: result });\r\n return result;\r\n } catch (error) {\r\n this._handleError(\"UPDATE_ERROR\", error as Error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Delete a record by ID\r\n */\r\n async delete(id: any): Promise<boolean> {\r\n await this._ensureInitialized();\r\n\r\n try {\r\n if (!id) {\r\n throw new Error(\"ID is required for delete\");\r\n }\r\n\r\n const queryTable: QueryTable = {\r\n name: this.tableName,\r\n cols: [],\r\n wheres: [{ name: this.primaryKeyFields[0], value: id }],\r\n };\r\n\r\n const result = await this.dao!.delete(queryTable);\r\n const success = result.rowsAffected > 0;\r\n\r\n if (success) {\r\n this._emit(\"dataDeleted\", { operation: \"delete\", id });\r\n }\r\n\r\n return success;\r\n } catch (error) {\r\n this._handleError(\"DELETE_ERROR\", error as Error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Find a record by ID\r\n */\r\n async findById(id: any): Promise<T | null> {\r\n await this._ensureInitialized();\r\n\r\n try {\r\n if (!id) {\r\n throw new Error(\"ID is required\");\r\n }\r\n\r\n const conditions = { [this.primaryKeyFields[0]]: id };\r\n const queryTable = this.buildSelectTable(conditions);\r\n const result = await this.dao!.select(queryTable);\r\n\r\n const record = Object.keys(result).length > 0 ? (result as T) : null;\r\n this._emit(\"dataFetched\", { operation: \"findById\", id });\r\n return record;\r\n } catch (error) {\r\n this._handleError(\"FIND_BY_ID_ERROR\", error as Error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Find the first record matching conditions\r\n */\r\n async findFirst(conditions: Record<string, any> = {}): Promise<T | null> {\r\n await this._ensureInitialized();\r\n\r\n try {\r\n const queryTable = this.buildSelectTable(conditions);\r\n const result = await this.dao!.select(queryTable);\r\n\r\n const record = Object.keys(result).length > 0 ? (result as T) : null;\r\n this._emit(\"dataFetched\", { operation: \"findFirst\" });\r\n return record;\r\n } catch (error) {\r\n this._handleError(\"FIND_FIRST_ERROR\", error as Error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Find all records matching conditions\r\n */\r\n async findAll(\r\n conditions: Record<string, any> = {},\r\n options: FindOptions = {}\r\n ): Promise<T[]> {\r\n await this._ensureInitialized();\r\n\r\n try {\r\n // Build where clauses from conditions\r\n const whereFromConditions = this.buildWhereFromObject(conditions);\r\n const allWheres = [...whereFromConditions, ...(options.where || [])];\r\n\r\n const queryTable: QueryTable = {\r\n name: this.tableName,\r\n cols: options.columns ? options.columns.map((name) => ({ name })) : [],\r\n wheres: allWheres,\r\n orderbys: options.orderBy,\r\n limitOffset: {\r\n limit: options.limit,\r\n offset: options.offset,\r\n },\r\n };\r\n\r\n const results = await this.dao!.selectAll(queryTable);\r\n this._emit(\"dataFetched\", {\r\n operation: \"findAll\",\r\n count: results.length,\r\n });\r\n return results as T[];\r\n } catch (error) {\r\n this._handleError(\"FIND_ALL_ERROR\", error as Error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Count records matching conditions\r\n */\r\n async count(where?: WhereClause[] | Record<string, any>): Promise<number> {\r\n await this._ensureInitialized();\r\n\r\n try {\r\n let whereConditions: WhereClause[] = [];\r\n\r\n if (Array.isArray(where)) {\r\n whereConditions = where;\r\n } else if (where && typeof where === \"object\") {\r\n whereConditions = this.buildWhereFromObject(where);\r\n }\r\n\r\n const queryTable: QueryTable = {\r\n name: this.tableName,\r\n cols: [{ name: \"COUNT(*) as count\" }],\r\n wheres: whereConditions,\r\n };\r\n\r\n const result = await this.dao!.select(queryTable);\r\n return result.count || 0;\r\n } catch (error) {\r\n this._handleError(\"COUNT_ERROR\", error as Error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Check if a record exists by ID\r\n */\r\n async exists(id: any): Promise<boolean> {\r\n const item = await this.findById(id);\r\n return item !== null;\r\n }\r\n\r\n /**\r\n * Truncate table (delete all records and reset auto-increment)\r\n */\r\n async truncate(): Promise<void> {\r\n await this._ensureInitialized();\r\n\r\n try {\r\n await this.dao!.execute(`DELETE FROM ${this.tableName}`);\r\n await this.dao!.execute(\r\n `DELETE FROM sqlite_sequence WHERE name='${this.tableName}'`\r\n );\r\n this._emit(\"tableTruncated\", { tableName: this.tableName });\r\n } catch (error) {\r\n this._handleError(\"TRUNCATE_ERROR\", error as Error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Bulk insert records\r\n */\r\n async bulkInsert(items: Partial<T>[]): Promise<ImportResult> {\r\n await this._ensureInitialized();\r\n\r\n try {\r\n if (!Array.isArray(items) || items.length === 0) {\r\n throw new Error(\"Items must be a non-empty array\");\r\n }\r\n\r\n const result = await this.dao!.importData({\r\n tableName: this.tableName,\r\n data: items as Record<string, any>[],\r\n batchSize: 1000,\r\n skipErrors: false,\r\n validateData: true,\r\n });\r\n\r\n this._emit(\"dataBulkCreated\", {\r\n operation: \"bulkInsert\",\r\n count: result.successRows,\r\n });\r\n return result;\r\n } catch (error) {\r\n this._handleError(\"BULK_INSERT_ERROR\", error as Error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Bulk create records with transaction support\r\n */\r\n async bulkCreate(dataArray: Record<string, any>[]): Promise<T[]> {\r\n await this._ensureInitialized();\r\n\r\n try {\r\n if (!Array.isArray(dataArray) || dataArray.length === 0) {\r\n throw new Error(\"Data must be a non-empty array\");\r\n }\r\n\r\n const results: T[] = [];\r\n await this.executeTransaction(async () => {\r\n for (const data of dataArray) {\r\n this._validateData(data);\r\n const queryTable = this.buildDataTable(data);\r\n await this.dao!.insert(queryTable);\r\n results.push(data as T);\r\n }\r\n });\r\n\r\n this._emit(\"dataBulkCreated\", {\r\n operation: \"bulkCreate\",\r\n count: results.length,\r\n });\r\n return results;\r\n } catch (error) {\r\n this._handleError(\"BULK_CREATE_ERROR\", error as Error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Execute operations within a transaction\r\n */\r\n async executeTransaction(callback: () => Promise<any>): Promise<any> {\r\n await this._ensureInitialized();\r\n\r\n try {\r\n await this.dao!.beginTransaction();\r\n const result = await callback();\r\n await this.dao!.commitTransaction();\r\n this._emit(\"transactionCompleted\", { operation: \"transaction\" });\r\n return result;\r\n } catch (error) {\r\n try {\r\n await this.dao!.rollbackTransaction();\r\n } catch (rollbackError) {\r\n this._handleError(\"ROLLBACK_ERROR\", rollbackError as Error);\r\n }\r\n this._handleError(\"TRANSACTION_ERROR\", error as Error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Import data from CSV\r\n */\r\n async importFromCSV(\r\n csvData: string,\r\n options: {\r\n delimiter?: string;\r\n hasHeader?: boolean;\r\n columnMappings?: ColumnMapping[];\r\n } & Partial<ImportOptions> = {}\r\n ): Promise<ImportResult> {\r\n await this._ensureInitialized();\r\n\r\n try {\r\n const result = await this.dao!.importFromCSV(\r\n this.tableName,\r\n csvData,\r\n options\r\n );\r\n this._emit(\"dataImported\", { operation: \"importFromCSV\", result });\r\n return result;\r\n } catch (error) {\r\n this._handleError(\"IMPORT_CSV_ERROR\", error as Error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Import data with column mapping\r\n */\r\n async importDataWithMapping(\r\n data: Record<string, any>[],\r\n columnMappings: ColumnMapping[],\r\n options: Partial<ImportOptions> = {}\r\n ): Promise<ImportResult> {\r\n await this._ensureInitialized();\r\n\r\n try {\r\n const result = await this.dao!.importDataWithMapping(\r\n this.tableName,\r\n data,\r\n columnMappings,\r\n options\r\n );\r\n this._emit(\"dataImported\", { operation: \"importWithMapping\", result });\r\n return result;\r\n } catch (error) {\r\n this._handleError(\"IMPORT_MAPPING_ERROR\", error as Error);\r\n throw error;\r\n }\r\n }\r\n\r\n // Utility methods\r\n protected buildSelectTable(\r\n conditions: Record<string, any> = {},\r\n options: FindOptions = {}\r\n ): QueryTable {\r\n const queryTable: QueryTable = {\r\n name: this.tableName,\r\n cols: [],\r\n wheres: [],\r\n orderbys: options.orderBy || [],\r\n limitOffset: {},\r\n };\r\n\r\n if (options.columns && options.columns.length > 0) {\r\n queryTable.cols = options.columns.map((name) => ({ name }));\r\n }\r\n\r\n if (conditions && Object.keys(conditions).length > 0) {\r\n queryTable.wheres = Object.entries(conditions).map(([key, value]) => ({\r\n name: key,\r\n value,\r\n operator: \"=\",\r\n }));\r\n }\r\n\r\n if (options.limit !== undefined) {\r\n queryTable.limitOffset!.limit = options.limit;\r\n }\r\n if (options.offset !== undefined) {\r\n queryTable.limitOffset!.offset = options.offset;\r\n }\r\n\r\n return queryTable;\r\n }\r\n\r\n protected buildDataTable(data: Record<string, any>): QueryTable {\r\n return this.dao!.convertJsonToQueryTable(\r\n this.tableName,\r\n data,\r\n this.primaryKeyFields\r\n );\r\n }\r\n\r\n protected buildWhereFromObject(obj: Record<string, any>): WhereClause[] {\r\n return Object.entries(obj)\r\n .filter(([_, value]) => value !== undefined)\r\n .map(([key, value]) => ({ name: key, value }));\r\n }\r\n\r\n // Event system\r\n on(event: string, handler: EventHandler): this {\r\n if (!this.eventListeners.has(event)) {\r\n this.eventListeners.set(event, []);\r\n }\r\n this.eventListeners.get(event)!.push(handler);\r\n return this;\r\n }\r\n\r\n off(event: string, handler: EventHandler): this {\r\n const handlers = this.eventListeners.get(event);\r\n if (handlers) {\r\n const index = handlers.indexOf(handler);\r\n if (index > -1) {\r\n handlers.splice(index, 1);\r\n }\r\n }\r\n return this;\r\n }\r\n\r\n protected _emit(event: string, data: any): void {\r\n const handlers = this.eventListeners.get(event);\r\n if (handlers) {\r\n handlers.forEach((handler) => {\r\n try {\r\n handler(data);\r\n } catch (error) {\r\n // Handle error in event handler\r\n }\r\n });\r\n }\r\n }\r\n\r\n // Error handling\r\n setErrorHandler(errorType: string, handler: ErrorHandler): this {\r\n this.errorHandlers.set(errorType, handler);\r\n return this;\r\n }\r\n\r\n protected _handleError(errorType: string, error: Error): void {\r\n const handler = this.errorHandlers.get(errorType);\r\n if (handler) {\r\n try {\r\n handler(error);\r\n } catch (handlerError) {\r\n // Handle error in error handler\r\n }\r\n }\r\n this._emit(\"error\", { errorType, error });\r\n }\r\n\r\n protected _validateData(data: any): void {\r\n if (!data || typeof data !== \"object\") {\r\n throw new Error(\"Data must be a valid object\");\r\n }\r\n }\r\n\r\n protected async _ensureInitialized(): Promise<void> {\r\n if (!this.isInitialized) {\r\n await this.init();\r\n }\r\n }\r\n\r\n private async ensureValidConnection(): Promise<void> {\r\n try {\r\n const isConnected = this.dao?.isConnectionOpen();\r\n if (!isConnected) {\r\n this.dao = await DatabaseManager.ensureDatabaseConnection(\r\n this.schemaName\r\n );\r\n }\r\n } catch (error) {\r\n this.dao = await DatabaseManager.ensureDatabaseConnection(\r\n this.schemaName\r\n );\r\n }\r\n }\r\n\r\n // Information and status methods\r\n async getDatabaseInfo(): Promise<any> {\r\n await this._ensureInitialized();\r\n return await this.dao!.getDatabaseInfo();\r\n }\r\n\r\n async getTableInfo(): Promise<any[]> {\r\n await this._ensureInitialized();\r\n return await this.dao!.getTableInfo(this.tableName);\r\n }\r\n\r\n getStatus(): ServiceStatus {\r\n return {\r\n schemaName: this.schemaName,\r\n tableName:this.tableName,\r\n isOpened: this.isOpened,\r\n isInitialized: this.isInitialized,\r\n hasDao: !!this.dao,\r\n };\r\n }\r\n\r\n async healthCheck(): Promise<HealthCheckResult> {\r\n try {\r\n await this._ensureInitialized();\r\n const count = await this.count();\r\n return {\r\n healthy: true,\r\n schemaName: this.schemaName,\r\n recordCount: count,\r\n timestamp: new Date().toISOString(),\r\n };\r\n } catch (error) {\r\n return {\r\n healthy: false,\r\n schemaName: this.schemaName,\r\n error: (error as Error).message,\r\n timestamp: new Date().toISOString(),\r\n };\r\n }\r\n }\r\n\r\n // Lifecycle management\r\n async close(): Promise<boolean> {\r\n try {\r\n if (this.dao) {\r\n await this.dao.close();\r\n }\r\n\r\n this.isOpened = false;\r\n this.isInitialized = false;\r\n this.eventListeners.clear();\r\n this.errorHandlers.clear();\r\n this.cache.clear();\r\n\r\n this._emit(\"closed\", { schemaName: this.schemaName });\r\n return true;\r\n } catch (error) {\r\n this._handleError(\"CLOSE_ERROR\", error as Error);\r\n throw error;\r\n }\r\n }\r\n\r\n public destroy(): void {\r\n // Remove reconnect listener\r\n DatabaseManager.offDatabaseReconnect(\r\n this.schemaName,\r\n this.reconnectHandler\r\n );\r\n\r\n // Clear all resources\r\n this.eventListeners.clear();\r\n this.errorHandlers.clear();\r\n this.cache.clear();\r\n }\r\n\r\n // Alias methods for backward compatibility\r\n async getAll(\r\n conditions: Record<string, any> = {},\r\n options: FindOptions = {}\r\n ): Promise<T[]> {\r\n return this.findAll(conditions, options);\r\n }\r\n\r\n async getById(id: string | number): Promise<T | null> {\r\n return this.findById(id);\r\n }\r\n\r\n async getFirst(conditions: Record<string, any> = {}): Promise<T | null> {\r\n return this.findFirst(conditions);\r\n }\r\n}\r\n","// src/query/query-builder.ts\r\nimport { UniversalDAO } from '../core/universal-dao';\r\nimport { SQLiteResult, SQLiteRow } from '../types';\r\n\r\nexport interface QueryCondition {\r\n field: string;\r\n operator: string;\r\n value: any;\r\n}\r\n\r\nexport interface JoinClause {\r\n type: 'INNER' | 'LEFT' | 'RIGHT' | 'FULL OUTER';\r\n table: string;\r\n condition: string;\r\n}\r\n\r\nexport interface SubQuery {\r\n query: QueryBuilder;\r\n alias: string;\r\n}\r\n\r\n/**\r\n * Enhanced QueryBuilder with advanced SQL query construction capabilities\r\n */\r\nexport class QueryBuilder {\r\n private tableName = '';\r\n private selectFields: string[] = ['*'];\r\n private joinClauses: JoinClause[] = [];\r\n private whereConditions: QueryCondition[] = [];\r\n private groupByFields: string[] = [];\r\n private havingConditions: QueryCondition[] = [];\r\n private orderByFields: string[] = [];\r\n private limitValue: number | null = null;\r\n private offsetValue: number | null = null;\r\n private params: any[] = [];\r\n private unionQueries: QueryBuilder[] = [];\r\n private subQueries: SubQuery[] = [];\r\n private cteQueries: Map<string, QueryBuilder> = new Map();\r\n private dao: UniversalDAO | null = null;\r\n\r\n constructor(dao?: UniversalDAO) {\r\n this.dao = dao || null;\r\n }\r\n\r\n static table(name: string, dao?: UniversalDAO): QueryBuilder {\r\n const builder = new QueryBuilder(dao);\r\n builder.tableName = name;\r\n return builder;\r\n }\r\n\r\n static from(name: string, dao?: UniversalDAO): QueryBuilder {\r\n return QueryBuilder.table(name, dao);\r\n }\r\n\r\n // SELECT operations\r\n select(fields: string | string[]): QueryBuilder {\r\n this.selectFields = Array.isArray(fields) ? fields : [fields];\r\n return this;\r\n }\r\n\r\n selectRaw(raw: string): QueryBuilder {\r\n this.selectFields = [raw];\r\n return this;\r\n }\r\n\r\n selectDistinct(fields: string | string[]): QueryBuilder {\r\n const fieldList = Array.isArray(fields) ? fields.join(', ') : fields;\r\n this.selectFields = [`DISTINCT ${fieldList}`];\r\n return this;\r\n }\r\n\r\n // JOIN operations\r\n join(table: string, condition: string, type: JoinClause['type'] = 'INNER'): QueryBuilder {\r\n this.joinClauses.push({ type, table, condition });\r\n return this;\r\n }\r\n\r\n innerJoin(table: string, condition: string): QueryBuilder {\r\n return this.join(table, condition, 'INNER');\r\n }\r\n\r\n leftJoin(table: string, condition: string): QueryBuilder {\r\n return this.join(table, condition, 'LEFT');\r\n }\r\n\r\n rightJoin(table: string, condition: string): QueryBuilder {\r\n return this.join(table, condition, 'RIGHT');\r\n }\r\n\r\n fullOuterJoin(table: string, condition: string): QueryBuilder {\r\n return this.join(table, condition, 'FULL OUTER');\r\n }\r\n\r\n // WHERE conditions\r\n where(field: string, operator: string, value?: any): QueryBuilder;\r\n where(field: string, value: any): QueryBuilder;\r\n where(conditions: Record<string, any>): QueryBuilder;\r\n where(fieldOrConditions: string | Record<string, any>, operatorOrValue?: string | any, value?: any): QueryBuilder {\r\n if (typeof fieldOrConditions === 'object') {\r\n // Handle object of conditions\r\n Object.entries(fieldOrConditions).forEach(([field, val]) => {\r\n this.whereConditions.push({ field, operator: '=', value: val });\r\n });\r\n return this;\r\n }\r\n\r\n let operator = '=';\r\n let actualValue = operatorOrValue;\r\n\r\n if (arguments.length === 3) {\r\n operator = operatorOrValue;\r\n actualValue = value;\r\n }\r\n\r\n this.whereConditions.push({ \r\n field: fieldOrConditions, \r\n operator, \r\n value: actualValue \r\n });\r\n \r\n return this;\r\n }\r\n\r\n whereEquals(field: string, value: any): QueryBuilder {\r\n return this.where(field, '=', value);\r\n }\r\n\r\n whereNot(field: string, value: any): QueryBuilder {\r\n return this.where(field, '!=', value);\r\n }\r\n\r\n whereLike(field: string, value: string): QueryBuilder {\r\n return this.where(field, 'LIKE', value);\r\n }\r\n\r\n whereNotLike(field: string, value: string): QueryBuilder {\r\n return this.where(field, 'NOT LIKE', value);\r\n }\r\n\r\n whereIn(field: string, values: any[]): QueryBuilder {\r\n this.whereConditions.push({ field, operator: 'IN', value: values });\r\n return this;\r\n }\r\n\r\n whereNotIn(field: string, values: any[]): QueryBuilder {\r\n this.whereConditions.push({ field, operator: 'NOT IN', value: values });\r\n return this;\r\n }\r\n\r\n whereBetween(field: string, min: any, max: any): QueryBuilder {\r\n this.whereConditions.push({ field, operator: 'BETWEEN', value: [min, max] });\r\n return this;\r\n }\r\n\r\n whereNotBetween(field: string, min: any, max: any): QueryBuilder {\r\n this.whereConditions.push({ field, operator: 'NOT BETWEEN', value: [min, max] });\r\n return this;\r\n }\r\n\r\n whereNull(field: string): QueryBuilder {\r\n this.whereConditions.push({ field, operator: 'IS NULL', value: null });\r\n return this;\r\n }\r\n\r\n whereNotNull(field: string): QueryBuilder {\r\n this.whereConditions.push({ field, operator: 'IS NOT NULL', value: null });\r\n return this;\r\n }\r\n\r\n whereExists(subquery: QueryBuilder): QueryBuilder {\r\n this.whereConditions.push({ \r\n field: '', \r\n operator: 'EXISTS', \r\n value: subquery \r\n });\r\n return this;\r\n }\r\n\r\n whereNotExists(subquery: QueryBuilder): QueryBuilder {\r\n this.whereConditions.push({ \r\n field: '', \r\n operator: 'NOT EXISTS', \r\n value: subquery \r\n });\r\n return this;\r\n }\r\n\r\n // OR WHERE conditions\r\n orWhere(field: string, operator: string, value?: any): QueryBuilder;\r\n orWhere(field: string, value: any): QueryBuilder;\r\n orWhere(field: string, operatorOrValue?: string | any, value?: any): QueryBuilder {\r\n // Implementation similar to where() but with OR logic\r\n // This would require refactoring the condition structure to support AND/OR\r\n return this.where(field, operatorOrValue as string, value);\r\n }\r\n\r\n // GROUP BY and HAVING\r\n groupBy(fields: string | string[]): QueryBuilder {\r\n this.groupByFields = Array.isArray(fields) ? fields : [fields];\r\n return this;\r\n }\r\n\r\n having(field: string, operator: string, value?: any): QueryBuilder {\r\n let actualOperator = '=';\r\n let actualValue = operator;\r\n\r\n if (arguments.length === 3) {\r\n actualOperator = operator;\r\n actualValue = value;\r\n }\r\n\r\n this.havingConditions.push({ \r\n field, \r\n operator: actualOperator, \r\n value: actualValue \r\n });\r\n return this;\r\n }\r\n\r\n havingCount(field: string, operator: string, value: number): QueryBuilder {\r\n return this.having(`COUNT(${field})`, operator, value);\r\n }\r\n\r\n // ORDER BY\r\n orderBy(field: string, direction: 'ASC' | 'DESC' = 'ASC'): QueryBuilder {\r\n this.orderByFields.push(`${field} ${direction}`);\r\n return this;\r\n }\r\n\r\n orderByDesc(field: string): QueryBuilder {\r\n return this.orderBy(field, 'DESC');\r\n }\r\n\r\n orderByRaw(raw: string): QueryBuilder {\r\n this.orderByFields.push(raw);\r\n return this;\r\n }\r\n\r\n latest(field: string = 'created_at'): QueryBuilder {\r\n return this.orderByDesc(field);\r\n }\r\n\r\n oldest(field: string = 'created_at'): QueryBuilder {\r\n return this.orderBy(field, 'ASC');\r\n }\r\n\r\n // LIMIT and OFFSET\r\n limit(count: number): QueryBuilder {\r\n this.limitValue = count;\r\n return this;\r\n }\r\n\r\n offset(count: number): QueryBuilder {\r\n this.offsetValue = count;\r\n return this;\r\n }\r\n\r\n skip(count: number): QueryBuilder {\r\n return this.offset(count);\r\n }\r\n\r\n take(count: number): QueryBuilder {\r\n return this.limit(count);\r\n }\r\n\r\n firstRow(): QueryBuilder {\r\n return this.limit(1);\r\n }\r\n\r\n paginate(page: number, perPage: number): QueryBuilder {\r\n this.limitValue = perPage;\r\n this.offsetValue = (page - 1) * perPage;\r\n return this;\r\n }\r\n\r\n // UNION operations\r\n union(query: QueryBuilder): QueryBuilder {\r\n this.unionQueries.push(query);\r\n return this;\r\n }\r\n\r\n unionAll(query: QueryBuilder): QueryBuilder {\r\n // Note: SQLite doesn't differentiate UNION and UNION ALL like other databases\r\n return this.union(query);\r\n }\r\n\r\n // CTE (Common Table Expressions)\r\n with(alias: string, query: QueryBuilder): QueryBuilder {\r\n this.cteQueries.set(alias, query);\r\n return this;\r\n }\r\n\r\n // Subqueries\r\n whereSubQuery(field: string, operator: string, subquery: QueryBuilder): QueryBuilder {\r\n this.subQueries.push({ query: subquery, alias: '' });\r\n this.whereConditions.push({ field, operator, value: subquery });\r\n return this;\r\n }\r\n\r\n // Aggregation functions\r\n count(field: string = '*'): QueryBuilder {\r\n this.selectFields = [`COUNT(${field}) as count`];\r\n return this;\r\n }\r\n\r\n sum(field: string): QueryBuilder {\r\n this.selectFields = [`SUM(${field}) as sum`];\r\n return this;\r\n }\r\n\r\n avg(field: string): QueryBuilder {\r\n this.selectFields = [`AVG(${field}) as avg`];\r\n return this;\r\n }\r\n\r\n max(field: string): QueryBuilder {\r\n this.selectFields = [`MAX(${field}) as max`];\r\n return this;\r\n }\r\n\r\n min(field: string): QueryBuilder {\r\n this.selectFields = [`MIN(${field}) as min`];\r\n return this;\r\n }\r\n\r\n // SQL Generation\r\n toSQL(): { sql: string; params: any[] } {\r\n let sql = '';\r\n const params: any[] = [];\r\n\r\n // CTE queries\r\n if (this.cteQueries.size > 0) {\r\n const cteList: string[] = [];\r\n this.cteQueries.forEach((query, alias) => {\r\n const { sql: cteSql, params: cteParams } = query.toSQL();\r\n cteList.push(`${alias} AS (${cteSql})`);\r\n params.push(...cteParams);\r\n });\r\n sql += `WITH ${cteList.join(', ')} `;\r\n }\r\n\r\n // Main SELECT\r\n sql += `SELECT ${this.selectFields.join(', ')} FROM ${this.tableName}`;\r\n\r\n // JOINs\r\n if (this.joinClauses.length > 0) {\r\n this.joinClauses.forEach(join => {\r\n sql += ` ${join.type} JOIN ${join.table} ON ${join.condition}`;\r\n });\r\n }\r\n\r\n // WHERE conditions\r\n if (this.whereConditions.length > 0) {\r\n const conditions: string[] = [];\r\n this.whereConditions.forEach(condition => {\r\n const { clause, conditionParams } = this.buildCondition(condition);\r\n conditions.push(clause);\r\n params.push(...conditionParams);\r\n });\r\n sql += ` WHERE ${conditions.join(' AND ')}`;\r\n }\r\n\r\n // GROUP BY\r\n if (this.groupByFields.length > 0) {\r\n sql += ` GROUP BY ${this.groupByFields.join(', ')}`;\r\n }\r\n\r\n // HAVING\r\n if (this.havingConditions.length > 0) {\r\n const conditions: string[] = [];\r\n this.havingConditions.forEach(condition => {\r\n const { clause, conditionParams } = this.buildCondition(condition);\r\n conditions.push(clause);\r\n params.push(...conditionParams);\r\n });\r\n sql += ` HAVING ${conditions.join(' AND ')}`;\r\n }\r\n\r\n // ORDER BY\r\n if (this.orderByFields.length > 0) {\r\n sql += ` ORDER BY ${this.orderByFields.join(', ')}`;\r\n }\r\n\r\n // LIMIT\r\n if (this.limitValue !== null) {\r\n sql += ` LIMIT ${this.limitValue}`;\r\n }\r\n\r\n // OFFSET\r\n if (this.offsetValue !== null) {\r\n sql += ` OFFSET ${this.offsetValue}`;\r\n }\r\n\r\n // UNION queries\r\n if (this.unionQueries.length > 0) {\r\n this.unionQueries.forEach(unionQuery => {\r\n const { sql: unionSql, params: unionParams } = unionQuery.toSQL();\r\n sql += ` UNION ${unionSql}`;\r\n params.push(...unionParams);\r\n });\r\n }\r\n\r\n return { sql, params };\r\n }\r\n\r\n private buildCondition(condition: QueryCondition): { clause: string; conditionParams: any[] } {\r\n const { field, operator, value } = condition;\r\n const params: any[] = [];\r\n\r\n switch (operator.toUpperCase()) {\r\n case 'IN':\r\n case 'NOT IN':\r\n const placeholders = (value as any[]).map(() => '?').join(', ');\r\n params.push(...(value as any[]));\r\n return { \r\n clause: `${field} ${operator} (${placeholders})`, \r\n conditionParams: params \r\n };\r\n\r\n case 'BETWEEN':\r\n case 'NOT BETWEEN':\r\n params.push(value[0], value[1]);\r\n return { \r\n clause: `${field} ${operator} ? AND ?`, \r\n conditionParams: params \r\n };\r\n\r\n case 'IS NULL':\r\n case 'IS NOT NULL':\r\n return { \r\n clause: `${field} ${operator}`, \r\n conditionParams: [] \r\n };\r\n\r\n case 'EXISTS':\r\n case 'NOT EXISTS':\r\n const { sql: subSql, params: subParams } = (value as QueryBuilder).toSQL();\r\n params.push(...subParams);\r\n return { \r\n clause: `${operator} (${subSql})`, \r\n conditionParams: params \r\n };\r\n\r\n default:\r\n if (value instanceof QueryBuilder) {\r\n const { sql: subSql, params: subParams } = value.toSQL();\r\n params.push(...subParams);\r\n return { \r\n clause: `${field} ${operator} (${subSql})`, \r\n conditionParams: params \r\n };\r\n }\r\n params.push(value);\r\n return { \r\n clause: `${field} ${operator} ?`, \r\n conditionParams: params \r\n };\r\n }\r\n }\r\n\r\n // Execution methods (require DAO)\r\n async get(): Promise<SQLiteRow[]> {\r\n if (!this.dao) {\r\n throw new Error('DAO instance required for query execution');\r\n }\r\n const { sql, params } = this.toSQL();\r\n const result = await this.dao.execute(sql, params);\r\n return result.rows;\r\n }\r\n\r\n async first(): Promise<SQLiteRow | null> {\r\n this.limit(1);\r\n const results = await this.get(); // This will apply the limit(1) set by firstRow()\r\n return results.length > 0 ? results[0] : null;\r\n }\r\n\r\n async pluck(column: string): Promise<any[]> {\r\n this.select(column);\r\n const results = await this.get();\r\n return results.map(row => row[column]);\r\n }\r\n\r\n async exists(): Promise<boolean> {\r\n this.select('1').limit(1);\r\n const results = await this.get();\r\n return results.length > 0;\r\n }\r\n\r\n async countResult(): Promise<number> {\r\n this.count();\r\n const result = await this.first();\r\n return result ? result.count : 0;\r\n }\r\n\r\n // Static helper methods for DML operations\r\n static insert(tableName: string, data: Record<string, any>): { sql: string; params: any[] } {\r\n const fields = Object.keys(data);\r\n const values = Object.values(data);\r\n const placeholders = values.map(() => '?').join(', ');\r\n\r\n return {\r\n sql: `INSERT INTO ${tableName} (${fields.join(', ')}) VALUES (${placeholders})`,\r\n params: values\r\n };\r\n }\r\n\r\n static insertMany(tableName: string, dataArray: Record<string, any>[]): { sql: string; params: any[] } {\r\n if (dataArray.length === 0) {\r\n throw new Error('Data array cannot be empty');\r\n }\r\n\r\n const fields = Object.keys(dataArray[0]);\r\n const placeholders = fields.map(() => '?').join(', ');\r\n const valueGroups = dataArray.map(() => `(${placeholders})`).join(', ');\r\n\r\n const allValues = dataArray.flatMap(data => Object.values(data));\r\n\r\n return {\r\n sql: `INSERT INTO ${tableName} (${fields.join(', ')}) VALUES ${valueGroups}`,\r\n params: allValues\r\n };\r\n }\r\n\r\n static update(tableName: string, data: Record<string, any>, where: string, whereParams: any[] = []): { sql: string; params: any[] } {\r\n const sets = Object.keys(data).map(key => `${key} = ?`).join(', ');\r\n const params = [...Object.values(data), ...whereParams];\r\n\r\n return {\r\n sql: `UPDATE ${tableName} SET ${sets} WHERE ${where}`,\r\n params\r\n };\r\n }\r\n\r\n static delete(tableName: string, where: string, whereParams: any[] = []): { sql: string; params: any[] } {\r\n return {\r\n sql: `DELETE FROM ${tableName} WHERE ${where}`,\r\n params: whereParams\r\n };\r\n }\r\n\r\n static upsert(tableName: string, data: Record<string, any>, conflictColumns: string[]): { sql: string; params: any[] } {\r\n const fields = Object.keys(data);\r\n const values = Object.values(data);\r\n const placeholders = values.map(() => '?').join(', ');\r\n\r\n const updateColumns = fields.filter(field => !conflictColumns.includes(field));\r\n const updateClause = updateColumns.length > 0\r\n ? updateColumns.map(col => `${col} = excluded.${col}`).join(', ')\r\n : '';\r\n\r\n let sql = `INSERT INTO ${tableName} (${fields.join(', ')}) VALUES (${placeholders})`;\r\n\r\n if (updateColumns.length > 0) {\r\n sql += ` ON CONFLICT(${conflictColumns.join(', ')}) DO UPDATE SET ${updateClause}`;\r\n } else {\r\n sql += ` ON CONFLICT(${conflictColumns.join(', ')}) DO NOTHING`;\r\n }\r\n\r\n return { sql, params: values };\r\n }\r\n\r\n // Utility methods\r\n clone(): QueryBuilder {\r\n if (!this.dao) throw new Error('DAO instance required for cloning QueryBuilder');\r\n const cloned = new QueryBuilder(this.dao);\r\n cloned.tableName = this.tableName;\r\n cloned.selectFields = [...this.selectFields];\r\n cloned.joinClauses = [...this.joinClauses];\r\n cloned.whereConditions = [...this.whereConditions];\r\n cloned.groupByFields = [...this.groupByFields];\r\n cloned.havingConditions = [...this.havingConditions];\r\n cloned.orderByFields = [...this.orderByFields];\r\n cloned.limitValue = this.limitValue;\r\n cloned.offsetValue = this.offsetValue;\r\n cloned.unionQueries = [...this.unionQueries];\r\n cloned.subQueries = [...this.subQueries];\r\n cloned.cteQueries = new Map(this.cteQueries);\r\n return cloned;\r\n }\r\n\r\n toRawSQL(): string {\r\n const { sql, params } = this.toSQL();\r\n let rawSql = sql;\r\n params.forEach(param => {\r\n if (typeof param === 'string') {\r\n rawSql = rawSql.replace('?', `'${param.replace(/'/g, \"''\")}'`);\r\n } else if (param === null || param === undefined) {\r\n rawSql = rawSql.replace('?', 'NULL');\r\n } else {\r\n rawSql = rawSql.replace('?', String(param));\r\n }\r\n });\r\n return rawSql;\r\n }\r\n\r\n explain(): QueryBuilder {\r\n this.selectFields = ['EXPLAIN QUERY PLAN ' + this.selectFields.join(', ')];\r\n return this;\r\n }\r\n}","// src/utils/migration-manager.ts\r\nimport { UniversalDAO } from \"../core/universal-dao\";\r\nimport { DatabaseSchema, TableDefinition, ColumnDefinition } from \"../types\";\r\n\r\nexport interface Migration {\r\n version: string;\r\n description: string;\r\n up: (dao: UniversalDAO) => Promise<void>;\r\n down: (dao: UniversalDAO) => Promise<void>;\r\n dependencies?: string[]; // Migration dependencies\r\n category?: string; // Optional category for grouping\r\n}\r\n\r\nexport interface MigrationRecord {\r\n version: string;\r\n description: string;\r\n category?: string;\r\n applied_at: string;\r\n execution_time_ms: number;\r\n checksum?: string;\r\n}\r\n\r\nexport interface MigrationStatus {\r\n version: string;\r\n description: string;\r\n category?: string;\r\n applied: boolean;\r\n applied_at?: string;\r\n execution_time_ms?: number;\r\n dependencies_met: boolean;\r\n missing_dependencies: string[];\r\n}\r\n\r\nexport interface MigrationPlan {\r\n toApply: Migration[];\r\n toRollback: Migration[];\r\n conflicts: string[];\r\n estimatedTime: number;\r\n}\r\n\r\nexport interface MigrationOptions {\r\n dryRun?: boolean;\r\n stopOnError?: boolean;\r\n validateChecksums?: boolean;\r\n timeout?: number; // in milliseconds\r\n onProgress?: (current: number, total: number, migration: Migration) => void;\r\n onError?: (error: Error, migration: Migration) => void;\r\n}\r\n\r\nexport class MigrationManager {\r\n private dao: UniversalDAO;\r\n private migrations: Map<string, Migration> = new Map();\r\n private migrationTable: string = \"_migrations\";\r\n private schemaVersion: string = \"1.0.0\";\r\n\r\n constructor(\r\n dao: UniversalDAO,\r\n options?: {\r\n migrationTable?: string;\r\n schemaVersion?: string;\r\n }\r\n ) {\r\n this.dao = dao;\r\n this.migrationTable = options?.migrationTable || \"_migrations\";\r\n this.schemaVersion = options?.schemaVersion || \"1.0.0\";\r\n }\r\n\r\n /**\r\n * Add a single migration\r\n */\r\n addMigration(migration: Migration): void {\r\n this.validateMigration(migration);\r\n this.migrations.set(migration.version, migration);\r\n }\r\n\r\n /**\r\n * Add multiple migrations\r\n */\r\n addMigrations(migrations: Migration[]): void {\r\n for (const migration of migrations) {\r\n this.addMigration(migration);\r\n }\r\n }\r\n\r\n /**\r\n * Load migrations from a directory or configuration\r\n */\r\n loadMigrations(migrations: Record<string, Migration>): void {\r\n Object.values(migrations).forEach((migration) => {\r\n this.addMigration(migration);\r\n });\r\n }\r\n\r\n /**\r\n * Remove a migration\r\n */\r\n removeMigration(version: string): boolean {\r\n return this.migrations.delete(version);\r\n }\r\n\r\n /**\r\n * Get all registered migrations\r\n */\r\n getMigrations(): Migration[] {\r\n return Array.from(this.migrations.values()).sort((a, b) =>\r\n this.compareVersions(a.version, b.version)\r\n );\r\n }\r\n\r\n /**\r\n * Get migration by version\r\n */\r\n getMigration(version: string): Migration | undefined {\r\n return this.migrations.get(version);\r\n }\r\n\r\n /**\r\n * Initialize the migration tracking table\r\n */\r\n async initMigrationTable(): Promise<void> {\r\n const createTableSQL = `\r\n CREATE TABLE IF NOT EXISTS ${this.migrationTable} (\r\n version TEXT PRIMARY KEY,\r\n description TEXT NOT NULL,\r\n category TEXT,\r\n applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\r\n execution_time_ms INTEGER DEFAULT 0,\r\n checksum TEXT,\r\n schema_version TEXT DEFAULT '${this.schemaVersion}'\r\n )\r\n `;\r\n\r\n await this.dao.execute(createTableSQL);\r\n\r\n // Create index for better query performance\r\n await this.dao.execute(`\r\n CREATE INDEX IF NOT EXISTS idx_migrations_applied_at \r\n ON ${this.migrationTable} (applied_at)\r\n `);\r\n\r\n await this.dao.execute(`\r\n CREATE INDEX IF NOT EXISTS idx_migrations_category \r\n ON ${this.migrationTable} (category)\r\n `);\r\n }\r\n\r\n /**\r\n * Get all applied migrations\r\n */\r\n async getAppliedMigrations(): Promise<MigrationRecord[]> {\r\n try {\r\n const result = await this.dao.execute(`\r\n SELECT version, description, category, applied_at, execution_time_ms, checksum\r\n FROM ${this.migrationTable} \r\n ORDER BY applied_at ASC\r\n `);\r\n return result.rows as MigrationRecord[];\r\n } catch (error) {\r\n // If table doesn't exist, return empty array\r\n return [];\r\n }\r\n }\r\n\r\n /**\r\n * Get pending migrations\r\n */\r\n async getPendingMigrations(): Promise<Migration[]> {\r\n const appliedMigrations = await this.getAppliedMigrations();\r\n const appliedVersions = new Set(appliedMigrations.map((m) => m.version));\r\n\r\n return this.getMigrations().filter(\r\n (migration) => !appliedVersions.has(migration.version)\r\n );\r\n }\r\n\r\n /**\r\n * Get detailed status of all migrations\r\n */\r\n async getDetailedStatus(): Promise<MigrationStatus[]> {\r\n await this.initMigrationTable();\r\n const appliedMigrations = await this.getAppliedMigrations();\r\n const appliedMap = new Map(appliedMigrations.map((m) => [m.version, m]));\r\n\r\n return this.getMigrations().map((migration) => {\r\n const applied = appliedMap.get(migration.version);\r\n const { dependenciesMet, missingDependencies } =\r\n this.checkDependencies(migration);\r\n\r\n return {\r\n version: migration.version,\r\n description: migration.description,\r\n category: migration.category,\r\n applied: !!applied,\r\n applied_at: applied?.applied_at,\r\n execution_time_ms: applied?.execution_time_ms,\r\n dependencies_met: dependenciesMet,\r\n missing_dependencies: missingDependencies,\r\n };\r\n });\r\n }\r\n\r\n /**\r\n * Create a migration plan\r\n */\r\n async createMigrationPlan(\r\n targetVersion?: string,\r\n direction: \"up\" | \"down\" = \"up\"\r\n ): Promise<MigrationPlan> {\r\n const appliedMigrations = await this.getAppliedMigrations();\r\n const appliedVersions = new Set(appliedMigrations.map((m) => m.version));\r\n const allMigrations = this.getMigrations();\r\n\r\n const plan: MigrationPlan = {\r\n toApply: [],\r\n toRollback: [],\r\n conflicts: [],\r\n estimatedTime: 0,\r\n };\r\n\r\n if (direction === \"up\") {\r\n // Forward migration\r\n for (const migration of allMigrations) {\r\n if (\r\n targetVersion &&\r\n this.compareVersions(migration.version, targetVersion) > 0\r\n ) {\r\n break;\r\n }\r\n\r\n if (!appliedVersions.has(migration.version)) {\r\n const { dependenciesMet, missingDependencies } =\r\n this.checkDependencies(migration);\r\n\r\n if (!dependenciesMet) {\r\n plan.conflicts.push(\r\n `Migration ${\r\n migration.version\r\n } has unmet dependencies: ${missingDependencies.join(\", \")}`\r\n );\r\n } else {\r\n plan.toApply.push(migration);\r\n }\r\n }\r\n }\r\n } else {\r\n // Rollback migration\r\n const reversedApplied = appliedMigrations\r\n .filter(\r\n (applied) =>\r\n !targetVersion ||\r\n this.compareVersions(applied.version, targetVersion) > 0\r\n )\r\n .sort((a, b) => this.compareVersions(b.version, a.version));\r\n\r\n for (const appliedRecord of reversedApplied) {\r\n const migration = this.migrations.get(appliedRecord.version);\r\n if (migration) {\r\n plan.toRollback.push(migration);\r\n }\r\n }\r\n }\r\n\r\n // Estimate execution time (rough estimate based on complexity)\r\n plan.estimatedTime = (plan.toApply.length + plan.toRollback.length) * 1000; // 1s per migration\r\n\r\n return plan;\r\n }\r\n\r\n /**\r\n * Run migrations up to a target version\r\n */\r\n async migrate(\r\n targetVersion?: string,\r\n options: MigrationOptions = {}\r\n ): Promise<MigrationRecord[]> {\r\n await this.initMigrationTable();\r\n\r\n const plan = await this.createMigrationPlan(targetVersion, \"up\");\r\n\r\n if (plan.conflicts.length > 0) {\r\n throw new Error(\r\n `Migration conflicts detected:\\n${plan.conflicts.join(\"\\n\")}`\r\n );\r\n }\r\n\r\n if (options.dryRun) {\r\n console.log(\"Dry run - would apply the following migrations:\");\r\n plan.toApply.forEach((m) =>\r\n console.log(` - ${m.version}: ${m.description}`)\r\n );\r\n return [];\r\n }\r\n\r\n const results: MigrationRecord[] = [];\r\n const total = plan.toApply.length;\r\n\r\n for (let i = 0; i < plan.toApply.length; i++) {\r\n const migration = plan.toApply[i];\r\n\r\n try {\r\n options.onProgress?.(i + 1, total, migration);\r\n\r\n const result = await this.applyMigration(migration, options);\r\n results.push(result);\r\n } catch (error) {\r\n const migrationError =\r\n error instanceof Error ? error : new Error(String(error));\r\n options.onError?.(migrationError, migration);\r\n\r\n if (options.stopOnError !== false) {\r\n throw new Error(\r\n `Migration ${migration.version} failed: ${migrationError.message}`\r\n );\r\n }\r\n }\r\n }\r\n\r\n return results;\r\n }\r\n\r\n /**\r\n * Rollback migrations to a target version\r\n */\r\n async rollback(\r\n targetVersion?: string,\r\n options: MigrationOptions = {}\r\n ): Promise<void> {\r\n await this.initMigrationTable();\r\n\r\n const plan = await this.createMigrationPlan(targetVersion, \"down\");\r\n\r\n if (options.dryRun) {\r\n console.log(\"Dry run - would rollback the following migrations:\");\r\n plan.toRollback.forEach((m) =>\r\n console.log(` - ${m.version}: ${m.description}`)\r\n );\r\n return;\r\n }\r\n\r\n const total = plan.toRollback.length;\r\n\r\n for (let i = 0; i < plan.toRollback.length; i++) {\r\n const migration = plan.toRollback[i];\r\n\r\n try {\r\n options.onProgress?.(i + 1, total, migration);\r\n\r\n await this.rollbackMigration(migration, options);\r\n } catch (error) {\r\n const migrationError =\r\n error instanceof Error ? error : new Error(String(error));\r\n options.onError?.(migrationError, migration);\r\n\r\n if (options.stopOnError !== false) {\r\n throw new Error(\r\n `Rollback of migration ${migration.version} failed: ${migrationError.message}`\r\n );\r\n }\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Apply a single migration\r\n */\r\n private async applyMigration(\r\n migration: Migration,\r\n options: MigrationOptions\r\n ): Promise<MigrationRecord> {\r\n const startTime = Date.now();\r\n const timeout = options.timeout || 30000; // 30 seconds default\r\n\r\n await this.dao.beginTransaction();\r\n\r\n try {\r\n // Set timeout for migration execution\r\n const migrationPromise = migration.up(this.dao);\r\n\r\n if (timeout > 0) {\r\n const timeoutPromise = new Promise((_, reject) => {\r\n setTimeout(\r\n () => reject(new Error(`Migration timeout after ${timeout}ms`)),\r\n timeout\r\n );\r\n });\r\n\r\n await Promise.race([migrationPromise, timeoutPromise]);\r\n } else {\r\n await migrationPromise;\r\n }\r\n\r\n const executionTime = Date.now() - startTime;\r\n const checksum = options.validateChecksums\r\n ? this.generateChecksum(migration)\r\n : undefined;\r\n\r\n // Record migration\r\n await this.dao.execute(\r\n `\r\n INSERT INTO ${this.migrationTable} \r\n (version, description, category, execution_time_ms, checksum) \r\n VALUES (?, ?, ?, ?, ?)\r\n `,\r\n [\r\n migration.version,\r\n migration.description,\r\n migration.category || null,\r\n executionTime,\r\n checksum || null,\r\n ]\r\n );\r\n\r\n await this.dao.commitTransaction();\r\n\r\n return {\r\n version: migration.version,\r\n description: migration.description,\r\n category: migration.category,\r\n applied_at: new Date().toISOString(),\r\n execution_time_ms: executionTime,\r\n checksum,\r\n };\r\n } catch (error) {\r\n await this.dao.rollbackTransaction();\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Rollback a single migration\r\n */\r\n private async rollbackMigration(\r\n migration: Migration,\r\n options: MigrationOptions\r\n ): Promise<void> {\r\n const timeout = options.timeout || 30000;\r\n\r\n await this.dao.beginTransaction();\r\n\r\n try {\r\n // Set timeout for migration rollback\r\n const rollbackPromise = migration.down(this.dao);\r\n\r\n if (timeout > 0) {\r\n const timeoutPromise = new Promise((_, reject) => {\r\n setTimeout(\r\n () => reject(new Error(`Rollback timeout after ${timeout}ms`)),\r\n timeout\r\n );\r\n });\r\n\r\n await Promise.race([rollbackPromise, timeoutPromise]);\r\n } else {\r\n await rollbackPromise;\r\n }\r\n\r\n // Remove migration record\r\n await this.dao.execute(\r\n `\r\n DELETE FROM ${this.migrationTable} WHERE version = ?\r\n `,\r\n [migration.version]\r\n );\r\n\r\n await this.dao.commitTransaction();\r\n } catch (error) {\r\n await this.dao.rollbackTransaction();\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Reset all migrations (DANGEROUS - use with caution)\r\n */\r\n async reset(options: { force?: boolean } = {}): Promise<void> {\r\n if (!options.force) {\r\n throw new Error(\r\n \"Reset requires explicit force option to prevent accidental data loss\"\r\n );\r\n }\r\n\r\n await this.dao.beginTransaction();\r\n\r\n try {\r\n // Get all applied migrations in reverse order\r\n const appliedMigrations = await this.getAppliedMigrations();\r\n const reversedMigrations = appliedMigrations.sort((a, b) =>\r\n this.compareVersions(b.version, a.version)\r\n );\r\n\r\n // Rollback all migrations\r\n for (const applied of reversedMigrations) {\r\n const migration = this.migrations.get(applied.version);\r\n if (migration) {\r\n await migration.down(this.dao);\r\n }\r\n }\r\n\r\n // Clear migration table\r\n await this.dao.execute(`DELETE FROM ${this.migrationTable}`);\r\n\r\n await this.dao.commitTransaction();\r\n } catch (error) {\r\n await this.dao.rollbackTransaction();\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Validate migration integrity\r\n */\r\n async validateIntegrity(): Promise<{\r\n valid: boolean;\r\n issues: string[];\r\n }> {\r\n const issues: string[] = [];\r\n\r\n try {\r\n const appliedMigrations = await this.getAppliedMigrations();\r\n\r\n for (const applied of appliedMigrations) {\r\n const migration = this.migrations.get(applied.version);\r\n\r\n if (!migration) {\r\n issues.push(\r\n `Applied migration ${applied.version} not found in registered migrations`\r\n );\r\n continue;\r\n }\r\n\r\n // Check dependencies\r\n const { dependenciesMet, missingDependencies } =\r\n this.checkDependencies(migration);\r\n if (!dependenciesMet) {\r\n issues.push(\r\n `Migration ${\r\n applied.version\r\n } has unmet dependencies: ${missingDependencies.join(\", \")}`\r\n );\r\n }\r\n\r\n // Check checksum if available\r\n if (applied.checksum) {\r\n const currentChecksum = this.generateChecksum(migration);\r\n if (currentChecksum !== applied.checksum) {\r\n issues.push(\r\n `Migration ${applied.version} has changed since it was applied (checksum mismatch)`\r\n );\r\n }\r\n }\r\n }\r\n\r\n return {\r\n valid: issues.length === 0,\r\n issues,\r\n };\r\n } catch (error) {\r\n return {\r\n valid: false,\r\n issues: [\r\n `Error validating migration integrity: ${(error as Error).message}`,\r\n ],\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Get migration history with statistics\r\n */\r\n async getHistory(): Promise<{\r\n totalMigrations: number;\r\n appliedMigrations: number;\r\n pendingMigrations: number;\r\n categories: Record<string, number>;\r\n totalExecutionTime: number;\r\n averageExecutionTime: number;\r\n recentMigrations: MigrationRecord[];\r\n }> {\r\n const applied = await this.getAppliedMigrations();\r\n const pending = await this.getPendingMigrations();\r\n\r\n const categories: Record<string, number> = {};\r\n let totalExecutionTime = 0;\r\n\r\n for (const migration of applied) {\r\n if (migration.category) {\r\n categories[migration.category] =\r\n (categories[migration.category] || 0) + 1;\r\n }\r\n totalExecutionTime += migration.execution_time_ms || 0;\r\n }\r\n\r\n return {\r\n totalMigrations: this.migrations.size,\r\n appliedMigrations: applied.length,\r\n pendingMigrations: pending.length,\r\n categories,\r\n totalExecutionTime,\r\n averageExecutionTime:\r\n applied.length > 0 ? totalExecutionTime / applied.length : 0,\r\n recentMigrations: applied.slice(-10), // Last 10 migrations\r\n };\r\n }\r\n\r\n /**\r\n * Create a migration from schema differences\r\n */\r\n static createMigrationFromSchema(\r\n fromSchema: DatabaseSchema,\r\n toSchema: DatabaseSchema,\r\n version: string,\r\n description?: string\r\n ): Migration {\r\n const migrationDescription =\r\n description || `Schema update to version ${version}`;\r\n\r\n return {\r\n version,\r\n description: migrationDescription,\r\n up: async (dao: UniversalDAO) => {\r\n // This is a simplified implementation\r\n // In practice, you'd want to do proper schema diffing\r\n for (const [tableName, tableConfig] of Object.entries(\r\n toSchema.schemas\r\n )) {\r\n if (!fromSchema.schemas[tableName]) {\r\n // New table - create it\r\n const tableDefinition: TableDefinition = {\r\n name: tableName,\r\n cols: tableConfig.cols,\r\n description: tableConfig.description,\r\n indexes: tableConfig.indexes,\r\n foreign_keys: tableConfig.foreign_keys,\r\n };\r\n\r\n // This would need to be implemented with proper SQL generation\r\n // For now, we'll throw an error to indicate this needs custom implementation\r\n throw new Error(\r\n \"Automatic schema migration generation not fully implemented. Please create migrations manually.\"\r\n );\r\n }\r\n }\r\n },\r\n down: async (dao: UniversalDAO) => {\r\n // Reverse the changes\r\n throw new Error(\r\n \"Automatic rollback generation not fully implemented. Please create rollback manually.\"\r\n );\r\n },\r\n };\r\n }\r\n\r\n // Private utility methods\r\n\r\n private validateMigration(migration: Migration): void {\r\n if (!migration.version || typeof migration.version !== \"string\") {\r\n throw new Error(\"Migration version is required and must be a string\");\r\n }\r\n\r\n if (!migration.description || typeof migration.description !== \"string\") {\r\n throw new Error(\"Migration description is required and must be a string\");\r\n }\r\n\r\n if (typeof migration.up !== \"function\") {\r\n throw new Error(\"Migration up function is required\");\r\n }\r\n\r\n if (typeof migration.down !== \"function\") {\r\n throw new Error(\"Migration down function is required\");\r\n }\r\n\r\n // Check for duplicate version\r\n if (this.migrations.has(migration.version)) {\r\n throw new Error(\r\n `Migration with version ${migration.version} already exists`\r\n );\r\n }\r\n }\r\n\r\n private checkDependencies(migration: Migration): {\r\n dependenciesMet: boolean;\r\n missingDependencies: string[];\r\n } {\r\n if (!migration.dependencies || migration.dependencies.length === 0) {\r\n return { dependenciesMet: true, missingDependencies: [] };\r\n }\r\n\r\n const missingDependencies = migration.dependencies.filter(\r\n (dep) => !this.migrations.has(dep)\r\n );\r\n\r\n return {\r\n dependenciesMet: missingDependencies.length === 0,\r\n missingDependencies,\r\n };\r\n }\r\n\r\n private compareVersions(version1: string, version2: string): number {\r\n // Simple semantic version comparison\r\n const v1Parts = version1.split(\".\").map(Number);\r\n const v2Parts = version2.split(\".\").map(Number);\r\n\r\n for (let i = 0; i < Math.max(v1Parts.length, v2Parts.length); i++) {\r\n const v1Part = v1Parts[i] || 0;\r\n const v2Part = v2Parts[i] || 0;\r\n\r\n if (v1Part < v2Part) return -1;\r\n if (v1Part > v2Part) return 1;\r\n }\r\n\r\n return 0;\r\n }\r\n\r\n private generateChecksum(migration: Migration): string {\r\n // Simple checksum based on function string representation\r\n // In production, you might want to use a more sophisticated approach\r\n const content = migration.up.toString() + migration.down.toString();\r\n let hash = 0;\r\n\r\n for (let i = 0; i < content.length; i++) {\r\n const char = content.charCodeAt(i);\r\n hash = (hash << 5) - hash + char;\r\n hash = hash & hash; // Convert to 32-bit integer\r\n }\r\n\r\n return hash.toString(16);\r\n }\r\n}\r\n\r\n// Helper functions for creating common migration patterns\r\n\r\nexport const MigrationHelpers = {\r\n /**\r\n * Create a migration to add a new table\r\n */\r\n createTable(\r\n version: string,\r\n tableName: string,\r\n columns: ColumnDefinition[],\r\n options?: {\r\n description?: string;\r\n category?: string;\r\n indexes?: Array<{ name: string; columns: string[]; unique?: boolean }>;\r\n }\r\n ): Migration {\r\n return {\r\n version,\r\n description: options?.description || `Create table ${tableName}`,\r\n category: options?.category,\r\n up: async (dao: UniversalDAO) => {\r\n const columnDefs = columns.map((col) =>\r\n `${col.name} ${col.type} ${col.constraints || \"\"}`.trim()\r\n );\r\n\r\n await dao.execute(`\r\n CREATE TABLE ${tableName} (\r\n ${columnDefs.join(\",\\n \")}\r\n )\r\n `);\r\n\r\n // Create indexes if specified\r\n if (options?.indexes) {\r\n for (const index of options.indexes) {\r\n const uniqueStr = index.unique ? \"UNIQUE\" : \"\";\r\n await dao.execute(`\r\n CREATE ${uniqueStr} INDEX ${index.name} \r\n ON ${tableName} (${index.columns.join(\", \")})\r\n `);\r\n }\r\n }\r\n },\r\n down: async (dao: UniversalDAO) => {\r\n await dao.execute(`DROP TABLE IF EXISTS ${tableName}`);\r\n },\r\n };\r\n },\r\n\r\n /**\r\n * Create a migration to add a column\r\n */\r\n addColumn(\r\n version: string,\r\n tableName: string,\r\n columnName: string,\r\n columnType: string,\r\n options?: {\r\n description?: string;\r\n category?: string;\r\n defaultValue?: any;\r\n nullable?: boolean;\r\n }\r\n ): Migration {\r\n return {\r\n version,\r\n description:\r\n options?.description || `Add column ${columnName} to ${tableName}`,\r\n category: options?.category,\r\n up: async (dao: UniversalDAO) => {\r\n let sql = `ALTER TABLE ${tableName} ADD COLUMN ${columnName} ${columnType}`;\r\n\r\n if (options?.defaultValue !== undefined) {\r\n sql += ` DEFAULT ${options.defaultValue}`;\r\n }\r\n\r\n if (options?.nullable === false) {\r\n sql += ` NOT NULL`;\r\n }\r\n\r\n await dao.execute(sql);\r\n },\r\n down: async (dao: UniversalDAO) => {\r\n // SQLite doesn't support DROP COLUMN directly\r\n throw new Error(\r\n \"SQLite does not support dropping columns. Manual rollback required.\"\r\n );\r\n },\r\n };\r\n },\r\n\r\n /**\r\n * Create a migration to add an index\r\n */\r\n addIndex(\r\n version: string,\r\n tableName: string,\r\n indexName: string,\r\n columns: string[],\r\n options?: {\r\n description?: string;\r\n category?: string;\r\n unique?: boolean;\r\n }\r\n ): Migration {\r\n return {\r\n version,\r\n description:\r\n options?.description || `Add index ${indexName} to ${tableName}`,\r\n category: options?.category,\r\n up: async (dao: UniversalDAO) => {\r\n const uniqueStr = options?.unique ? \"UNIQUE\" : \"\";\r\n await dao.execute(`\r\n CREATE ${uniqueStr} INDEX ${indexName} \r\n ON ${tableName} (${columns.join(\", \")})\r\n `);\r\n },\r\n down: async (dao: UniversalDAO) => {\r\n await dao.execute(`DROP INDEX IF EXISTS ${indexName}`);\r\n },\r\n };\r\n },\r\n\r\n /**\r\n * Create a migration to run custom SQL\r\n */\r\n rawSQL(\r\n version: string,\r\n upSQL: string,\r\n downSQL: string,\r\n options?: {\r\n description?: string;\r\n category?: string;\r\n }\r\n ): Migration {\r\n return {\r\n version,\r\n description: options?.description || `Custom SQL migration ${version}`,\r\n category: options?.category,\r\n up: async (dao: UniversalDAO) => {\r\n await dao.execute(upSQL);\r\n },\r\n down: async (dao: UniversalDAO) => {\r\n await dao.execute(downSQL);\r\n },\r\n };\r\n },\r\n};\r\n","// src/utils/csv-import.ts\r\nimport { UniversalDAO } from '../core/universal-dao';\r\nimport { ImportOptions, ImportResult, ColumnMapping } from '../types';\r\n\r\nexport interface CSVParseOptions {\r\n delimiter?: string;\r\n quote?: string;\r\n escape?: string;\r\n hasHeader?: boolean;\r\n skipEmptyLines?: boolean;\r\n trimWhitespace?: boolean;\r\n encoding?: string;\r\n}\r\n\r\nexport interface CSVImportOptions extends CSVParseOptions {\r\n columnMappings?: Record<string, string> | ColumnMapping[];\r\n transform?: Record<string, (value: any, row: Record<string, any>, index: number) => any>;\r\n validate?: Record<string, (value: any, row: Record<string, any>, index: number) => boolean | string>;\r\n onRowParsed?: (row: Record<string, any>, index: number) => Record<string, any> | null;\r\n onRowError?: (error: Error, row: Record<string, any>, index: number) => boolean; // return true to skip, false to abort\r\n maxRows?: number;\r\n startFromRow?: number;\r\n dateFormats?: string[];\r\n booleanValues?: {\r\n true: string[];\r\n false: string[];\r\n };\r\n}\r\n\r\nexport interface CSVParseResult {\r\n data: Record<string, any>[];\r\n headers: string[];\r\n totalRows: number;\r\n parsedRows: number;\r\n skippedRows: number;\r\n errors: Array<{\r\n row: number;\r\n column?: string;\r\n error: string;\r\n rawData?: string;\r\n }>;\r\n}\r\n\r\nexport class CSVImporter {\r\n private dao: UniversalDAO;\r\n\r\n constructor(dao: UniversalDAO) {\r\n this.dao = dao;\r\n }\r\n\r\n /**\r\n * Parse CSV string into structured data\r\n */\r\n parseCSV(csvData: string, options: CSVParseOptions = {}): CSVParseResult {\r\n const opts = {\r\n delimiter: ',',\r\n quote: '\"',\r\n escape: '\"',\r\n hasHeader: true,\r\n skipEmptyLines: true,\r\n trimWhitespace: true,\r\n ...options,\r\n };\r\n\r\n const result: CSVParseResult = {\r\n data: [],\r\n headers: [],\r\n totalRows: 0,\r\n parsedRows: 0,\r\n skippedRows: 0,\r\n errors: [],\r\n };\r\n\r\n if (!csvData || csvData.trim().length === 0) {\r\n result.errors.push({\r\n row: 0,\r\n error: 'CSV data is empty',\r\n });\r\n return result;\r\n }\r\n\r\n try {\r\n const lines = this.splitCSVLines(csvData, opts);\r\n result.totalRows = lines.length;\r\n\r\n if (lines.length === 0) {\r\n result.errors.push({\r\n row: 0,\r\n error: 'No valid lines found in CSV data',\r\n });\r\n return result;\r\n }\r\n\r\n // Parse headers\r\n let dataStartIndex = 0;\r\n if (opts.hasHeader && lines.length > 0) {\r\n try {\r\n result.headers = this.parseCSVRow(lines[0], opts);\r\n if (opts.trimWhitespace) {\r\n result.headers = result.headers.map(h => h.trim());\r\n }\r\n dataStartIndex = 1;\r\n } catch (error) {\r\n result.errors.push({\r\n row: 1,\r\n error: `Failed to parse header row: ${(error as Error).message}`,\r\n rawData: lines[0],\r\n });\r\n return result;\r\n }\r\n } else {\r\n // Generate default headers\r\n const firstRow = this.parseCSVRow(lines[0], opts);\r\n result.headers = firstRow.map((_, index) => `column_${index + 1}`);\r\n }\r\n\r\n // Parse data rows\r\n for (let i = dataStartIndex; i < lines.length; i++) {\r\n const lineNumber = i + 1;\r\n const line = lines[i];\r\n\r\n if (opts.skipEmptyLines && line.trim().length === 0) {\r\n result.skippedRows++;\r\n continue;\r\n }\r\n\r\n try {\r\n const values = this.parseCSVRow(line, opts);\r\n const row: Record<string, any> = {};\r\n\r\n // Map values to headers\r\n result.headers.forEach((header, index) => {\r\n let value = values[index] || null;\r\n \r\n if (opts.trimWhitespace && typeof value === 'string') {\r\n value = value.trim();\r\n }\r\n\r\n // Convert empty strings to null\r\n if (value === '') {\r\n value = null;\r\n }\r\n\r\n row[header] = value;\r\n });\r\n\r\n result.data.push(row);\r\n result.parsedRows++;\r\n } catch (error) {\r\n result.errors.push({\r\n row: lineNumber,\r\n error: `Failed to parse row: ${(error as Error).message}`,\r\n rawData: line,\r\n });\r\n result.skippedRows++;\r\n }\r\n }\r\n\r\n return result;\r\n } catch (error) {\r\n result.errors.push({\r\n row: 0,\r\n error: `CSV parsing failed: ${(error as Error).message}`,\r\n });\r\n return result;\r\n }\r\n }\r\n\r\n /**\r\n * Advanced CSV import with comprehensive options\r\n */\r\n async importFromCSV(\r\n tableName: string,\r\n csvData: string,\r\n options: CSVImportOptions & Partial<ImportOptions> = {}\r\n ): Promise<ImportResult & { parseResult: CSVParseResult }> {\r\n const startTime = Date.now();\r\n\r\n // Parse CSV first\r\n const parseResult = this.parseCSV(csvData, options);\r\n \r\n if (parseResult.errors.length > 0 && parseResult.data.length === 0) {\r\n throw new Error(`CSV parsing failed: ${parseResult.errors.map(e => e.error).join('; ')}`);\r\n }\r\n\r\n let processedData = parseResult.data;\r\n\r\n // Apply row limits\r\n if (options.startFromRow && options.startFromRow > 0) {\r\n processedData = processedData.slice(options.startFromRow);\r\n }\r\n \r\n if (options.maxRows && options.maxRows > 0) {\r\n processedData = processedData.slice(0, options.maxRows);\r\n }\r\n\r\n // Apply column mappings\r\n if (options.columnMappings) {\r\n processedData = this.applyColumnMappings(processedData, options.columnMappings);\r\n }\r\n\r\n // Apply transformations and validations\r\n const transformedData: Record<string, any>[] = [];\r\n const transformErrors: Array<{ row: number; error: string }> = [];\r\n\r\n for (let i = 0; i < processedData.length; i++) {\r\n const row = processedData[i];\r\n let transformedRow = { ...row };\r\n\r\n try {\r\n // Apply onRowParsed callback\r\n if (options.onRowParsed) {\r\n const result = options.onRowParsed(transformedRow, i);\r\n if (result === null) {\r\n continue; // Skip this row\r\n }\r\n transformedRow = result;\r\n }\r\n\r\n // Apply field transformations\r\n if (options.transform) {\r\n for (const [field, transformer] of Object.entries(options.transform)) {\r\n if (transformedRow.hasOwnProperty(field)) {\r\n try {\r\n transformedRow[field] = transformer(transformedRow[field], transformedRow, i);\r\n } catch (error) {\r\n transformErrors.push({\r\n row: i + 1,\r\n error: `Transform error for field '${field}': ${(error as Error).message}`,\r\n });\r\n \r\n if (options.onRowError) {\r\n const shouldSkip = options.onRowError(error as Error, transformedRow, i);\r\n if (!shouldSkip) {\r\n throw error;\r\n }\r\n continue;\r\n }\r\n throw error;\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Apply field validations\r\n if (options.validate) {\r\n for (const [field, validator] of Object.entries(options.validate)) {\r\n if (transformedRow.hasOwnProperty(field)) {\r\n try {\r\n const validationResult = validator(transformedRow[field], transformedRow, i);\r\n if (validationResult !== true) {\r\n const errorMessage = typeof validationResult === 'string' \r\n ? validationResult \r\n : `Validation failed for field '${field}'`;\r\n \r\n const validationError = new Error(errorMessage);\r\n \r\n if (options.onRowError) {\r\n const shouldSkip = options.onRowError(validationError, transformedRow, i);\r\n if (!shouldSkip) {\r\n throw validationError;\r\n }\r\n continue;\r\n }\r\n throw validationError;\r\n }\r\n } catch (error) {\r\n transformErrors.push({\r\n row: i + 1,\r\n error: `Validation error for field '${field}': ${(error as Error).message}`,\r\n });\r\n throw error;\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Apply automatic type conversion\r\n transformedRow = this.autoConvertTypes(transformedRow, options);\r\n \r\n transformedData.push(transformedRow);\r\n } catch (error) {\r\n if (options.onRowError) {\r\n const shouldSkip = options.onRowError(error as Error, transformedRow, i);\r\n if (shouldSkip) {\r\n continue;\r\n }\r\n }\r\n throw error;\r\n }\r\n }\r\n\r\n // Import to database\r\n const importResult = await this.dao.importData({\r\n tableName,\r\n data: transformedData,\r\n batchSize: options.batchSize || 1000,\r\n onProgress: options.onProgress,\r\n onError: options.onError,\r\n skipErrors: options.skipErrors || false,\r\n validateData: options.validateData !== false,\r\n updateOnConflict: options.updateOnConflict || false,\r\n conflictColumns: options.conflictColumns,\r\n includeAutoIncrementPK: options.includeAutoIncrementPK || false,\r\n });\r\n\r\n // Combine parse errors with import errors\r\n const allErrors = [\r\n ...parseResult.errors.map(e => ({\r\n rowIndex: e.row - 1,\r\n error: e.error,\r\n rowData: e.rawData ? { _raw: e.rawData } : {},\r\n })),\r\n ...transformErrors.map(e => ({\r\n rowIndex: e.row - 1,\r\n error: e.error,\r\n rowData: {},\r\n })),\r\n ...importResult.errors,\r\n ];\r\n\r\n return {\r\n ...importResult,\r\n errors: allErrors,\r\n parseResult,\r\n };\r\n }\r\n\r\n /**\r\n * Import CSV from file path (Node.js/Deno environments)\r\n */\r\n async importFromFile(\r\n tableName: string,\r\n filePath: string,\r\n options: CSVImportOptions & Partial<ImportOptions> = {}\r\n ): Promise<ImportResult & { parseResult: CSVParseResult }> {\r\n let csvData: string;\r\n\r\n try {\r\n // Try Deno first\r\n if (typeof globalThis.Deno !== 'undefined' && globalThis.Deno.readTextFile) {\r\n csvData = await globalThis.Deno.readTextFile(filePath);\r\n }\r\n // Try Node.js\r\n else if (typeof require !== 'undefined') {\r\n const fs = require('fs').promises;\r\n csvData = await fs.readFile(filePath, options.encoding || 'utf8');\r\n }\r\n // Try browser File API (if file is provided as File object)\r\n else if (typeof filePath === 'object' && 'text' in filePath) {\r\n csvData = await (filePath as any).text();\r\n }\r\n else {\r\n throw new Error('File reading not supported in this environment');\r\n }\r\n } catch (error) {\r\n throw new Error(`Failed to read CSV file '${filePath}': ${(error as Error).message}`);\r\n }\r\n\r\n return await this.importFromCSV(tableName, csvData, options);\r\n }\r\n\r\n /**\r\n * Export table data to CSV format\r\n */\r\n async exportToCSV(\r\n tableName: string,\r\n options: {\r\n columns?: string[];\r\n where?: string;\r\n orderBy?: string;\r\n limit?: number;\r\n delimiter?: string;\r\n quote?: string;\r\n includeHeaders?: boolean;\r\n dateFormat?: string;\r\n nullValue?: string;\r\n } = {}\r\n ): Promise<string> {\r\n const opts = {\r\n delimiter: ',',\r\n quote: '\"',\r\n includeHeaders: true,\r\n dateFormat: 'YYYY-MM-DD HH:mm:ss',\r\n nullValue: '',\r\n ...options,\r\n };\r\n\r\n // Build query\r\n let sql = `SELECT ${options.columns ? options.columns.join(', ') : '*'} FROM ${tableName}`;\r\n const params: any[] = [];\r\n\r\n if (options.where) {\r\n sql += ` WHERE ${options.where}`;\r\n }\r\n\r\n if (options.orderBy) {\r\n sql += ` ORDER BY ${options.orderBy}`;\r\n }\r\n\r\n if (options.limit) {\r\n sql += ` LIMIT ${options.limit}`;\r\n }\r\n\r\n // Execute query\r\n const result = await this.dao.execute(sql, params);\r\n \r\n if (result.rows.length === 0) {\r\n return opts.includeHeaders && options.columns \r\n ? this.formatCSVRow(options.columns, opts) \r\n : '';\r\n }\r\n\r\n const rows: string[] = [];\r\n\r\n // Add headers\r\n if (opts.includeHeaders) {\r\n const headers = options.columns || Object.keys(result.rows[0]);\r\n rows.push(this.formatCSVRow(headers, opts));\r\n }\r\n\r\n // Add data rows\r\n for (const row of result.rows) {\r\n const values = Object.values(row).map(value => {\r\n if (value === null || value === undefined) {\r\n return opts.nullValue;\r\n }\r\n if (value instanceof Date) {\r\n return this.formatDate(value, opts.dateFormat);\r\n }\r\n return String(value);\r\n });\r\n \r\n rows.push(this.formatCSVRow(values, opts));\r\n }\r\n\r\n return rows.join('\\n');\r\n }\r\n\r\n // Private helper methods\r\n\r\n private splitCSVLines(csvData: string, options: CSVParseOptions): string[] {\r\n const lines: string[] = [];\r\n let currentLine = '';\r\n let inQuotes = false;\r\n let quoteCount = 0;\r\n\r\n for (let i = 0; i < csvData.length; i++) {\r\n const char = csvData[i];\r\n const nextChar = csvData[i + 1];\r\n\r\n if (char === options.quote) {\r\n quoteCount++;\r\n inQuotes = !inQuotes;\r\n \r\n // Handle escaped quotes\r\n if (nextChar === options.quote && options.escape === options.quote) {\r\n currentLine += char + nextChar;\r\n i++; // Skip next quote\r\n quoteCount++;\r\n continue;\r\n }\r\n }\r\n\r\n if (char === '\\n' && !inQuotes) {\r\n if (options.skipEmptyLines && currentLine.trim().length === 0) {\r\n currentLine = '';\r\n continue;\r\n }\r\n lines.push(currentLine);\r\n currentLine = '';\r\n inQuotes = false;\r\n quoteCount = 0;\r\n } else if (char === '\\r' && nextChar === '\\n' && !inQuotes) {\r\n if (options.skipEmptyLines && currentLine.trim().length === 0) {\r\n currentLine = '';\r\n i++; // Skip \\n\r\n continue;\r\n }\r\n lines.push(currentLine);\r\n currentLine = '';\r\n i++; // Skip \\n\r\n inQuotes = false;\r\n quoteCount = 0;\r\n } else {\r\n currentLine += char;\r\n }\r\n }\r\n\r\n // Add last line if it exists\r\n if (currentLine.length > 0) {\r\n if (!options.skipEmptyLines || currentLine.trim().length > 0) {\r\n lines.push(currentLine);\r\n }\r\n }\r\n\r\n return lines;\r\n }\r\n\r\n private parseCSVRow(line: string, options: CSVParseOptions): string[] {\r\n const values: string[] = [];\r\n let currentValue = '';\r\n let inQuotes = false;\r\n\r\n for (let i = 0; i < line.length; i++) {\r\n const char = line[i];\r\n const nextChar = line[i + 1];\r\n\r\n if (char === options.quote) {\r\n if (inQuotes && nextChar === options.quote && options.escape === options.quote) {\r\n // Escaped quote\r\n currentValue += options.quote;\r\n i++; // Skip next quote\r\n } else {\r\n inQuotes = !inQuotes;\r\n }\r\n } else if (char === options.delimiter && !inQuotes) {\r\n values.push(currentValue);\r\n currentValue = '';\r\n } else {\r\n currentValue += char;\r\n }\r\n }\r\n\r\n // Add last value\r\n values.push(currentValue);\r\n\r\n return values;\r\n }\r\n\r\n private formatCSVRow(values: string[], options: { delimiter: string; quote: string }): string {\r\n return values.map(value => {\r\n const strValue = String(value);\r\n \r\n // Quote if contains delimiter, quote, or newline\r\n if (strValue.includes(options.delimiter) || \r\n strValue.includes(options.quote) || \r\n strValue.includes('\\n') || \r\n strValue.includes('\\r')) {\r\n return options.quote + strValue.replace(new RegExp(options.quote, 'g'), options.quote + options.quote) + options.quote;\r\n }\r\n \r\n return strValue;\r\n }).join(options.delimiter);\r\n }\r\n\r\n private applyColumnMappings(\r\n data: Record<string, any>[], \r\n mappings: Record<string, string> | ColumnMapping[]\r\n ): Record<string, any>[] {\r\n if (Array.isArray(mappings)) {\r\n // ColumnMapping[] format\r\n return data.map(row => {\r\n const newRow: Record<string, any> = {};\r\n \r\n mappings.forEach(mapping => {\r\n if (row.hasOwnProperty(mapping.sourceColumn)) {\r\n let value = row[mapping.sourceColumn];\r\n \r\n if (mapping.transform) {\r\n value = mapping.transform(value);\r\n }\r\n \r\n newRow[mapping.targetColumn] = value;\r\n }\r\n });\r\n \r\n return newRow;\r\n });\r\n } else {\r\n // Record<string, string> format\r\n return data.map(row => {\r\n const newRow: Record<string, any> = {};\r\n \r\n Object.entries(row).forEach(([key, value]) => {\r\n const newKey = mappings[key] || key;\r\n newRow[newKey] = value;\r\n });\r\n \r\n return newRow;\r\n });\r\n }\r\n }\r\n\r\n private autoConvertTypes(\r\n row: Record<string, any>, \r\n options: CSVImportOptions\r\n ): Record<string, any> {\r\n const converted: Record<string, any> = {};\r\n\r\n Object.entries(row).forEach(([key, value]) => {\r\n converted[key] = this.convertValue(value, options);\r\n });\r\n\r\n return converted;\r\n }\r\n\r\n private convertValue(value: any, options: CSVImportOptions): any {\r\n if (value === null || value === undefined || value === '') {\r\n return null;\r\n }\r\n\r\n const strValue = String(value).trim();\r\n\r\n // Boolean conversion\r\n if (options.booleanValues) {\r\n const lowerValue = strValue.toLowerCase();\r\n if (options.booleanValues.true.some(t => t.toLowerCase() === lowerValue)) {\r\n return true;\r\n }\r\n if (options.booleanValues.false.some(f => f.toLowerCase() === lowerValue)) {\r\n return false;\r\n }\r\n } else {\r\n // Default boolean values\r\n const lowerValue = strValue.toLowerCase();\r\n if (['true', '1', 'yes', 'on'].includes(lowerValue)) {\r\n return true;\r\n }\r\n if (['false', '0', 'no', 'off'].includes(lowerValue)) {\r\n return false;\r\n }\r\n }\r\n\r\n // Number conversion\r\n if (/^-?\\d+$/.test(strValue)) {\r\n const intValue = parseInt(strValue);\r\n if (!isNaN(intValue)) {\r\n return intValue;\r\n }\r\n }\r\n\r\n if (/^-?\\d*\\.?\\d+$/.test(strValue)) {\r\n const floatValue = parseFloat(strValue);\r\n if (!isNaN(floatValue)) {\r\n return floatValue;\r\n }\r\n }\r\n\r\n // Date conversion\r\n if (options.dateFormats) {\r\n for (const format of options.dateFormats) {\r\n const date = this.parseDate(strValue, format);\r\n if (date) {\r\n return date.toISOString();\r\n }\r\n }\r\n } else {\r\n // Default date parsing\r\n const date = new Date(strValue);\r\n if (!isNaN(date.getTime()) && strValue.match(/\\d{4}-\\d{2}-\\d{2}/)) {\r\n return date.toISOString();\r\n }\r\n }\r\n\r\n return strValue;\r\n }\r\n\r\n private parseDate(dateString: string, format: string): Date | null {\r\n // Simple date format parsing - you might want to use a more robust library like date-fns\r\n try {\r\n // This is a simplified implementation\r\n const date = new Date(dateString);\r\n return isNaN(date.getTime()) ? null : date;\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n private formatDate(date: Date, format: string): string {\r\n // Simple date formatting - you might want to use a more robust library\r\n const year = date.getFullYear();\r\n const month = String(date.getMonth() + 1).padStart(2, '0');\r\n const day = String(date.getDate()).padStart(2, '0');\r\n const hours = String(date.getHours()).padStart(2, '0');\r\n const minutes = String(date.getMinutes()).padStart(2, '0');\r\n const seconds = String(date.getSeconds()).padStart(2, '0');\r\n\r\n return format\r\n .replace('YYYY', String(year))\r\n .replace('MM', month)\r\n .replace('DD', day)\r\n .replace('HH', hours)\r\n .replace('mm', minutes)\r\n .replace('ss', seconds);\r\n }\r\n\r\n /**\r\n * Static utility methods for parsing CSV values\r\n */\r\n static parseCSVValue(value: string, options: { \r\n autoConvert?: boolean;\r\n booleanValues?: { true: string[]; false: string[] };\r\n dateFormats?: string[];\r\n } = {}): any {\r\n if (value === '' || value === null) return null;\r\n \r\n const opts = {\r\n autoConvert: true,\r\n booleanValues: {\r\n true: ['true', '1', 'yes', 'on'],\r\n false: ['false', '0', 'no', 'off']\r\n },\r\n ...options\r\n };\r\n\r\n if (!opts.autoConvert) {\r\n return value;\r\n }\r\n\r\n const strValue = String(value).trim().toLowerCase();\r\n\r\n // Boolean conversion\r\n if (opts.booleanValues.true.includes(strValue)) {\r\n return true;\r\n }\r\n if (opts.booleanValues.false.includes(strValue)) {\r\n return false;\r\n }\r\n\r\n // Number conversion\r\n if (/^-?\\d+$/.test(value)) {\r\n const intValue = parseInt(value);\r\n if (!isNaN(intValue)) return intValue;\r\n }\r\n\r\n if (/^-?\\d*\\.?\\d+$/.test(value)) {\r\n const floatValue = parseFloat(value);\r\n if (!isNaN(floatValue)) return floatValue;\r\n }\r\n\r\n // Date conversion\r\n const date = new Date(value);\r\n if (!isNaN(date.getTime()) && value.match(/\\d{4}-\\d{2}-\\d{2}/)) {\r\n return date.toISOString();\r\n }\r\n\r\n return value;\r\n }\r\n\r\n /**\r\n * Validate CSV structure\r\n */\r\n static validateCSVStructure(csvData: string, options: CSVParseOptions = {}): {\r\n isValid: boolean;\r\n errors: string[];\r\n rowCount: number;\r\n columnCount: number;\r\n headers: string[];\r\n } {\r\n const result = {\r\n isValid: true,\r\n errors: [] as string[],\r\n rowCount: 0,\r\n columnCount: 0,\r\n headers: [] as string[],\r\n };\r\n\r\n try {\r\n const importer = new CSVImporter({} as UniversalDAO);\r\n const parseResult = importer.parseCSV(csvData, options);\r\n\r\n result.rowCount = parseResult.totalRows;\r\n result.headers = parseResult.headers;\r\n result.columnCount = parseResult.headers.length;\r\n\r\n if (parseResult.errors.length > 0) {\r\n result.isValid = false;\r\n result.errors = parseResult.errors.map(e => e.error);\r\n }\r\n\r\n if (parseResult.data.length === 0) {\r\n result.isValid = false;\r\n result.errors.push('No valid data rows found');\r\n }\r\n\r\n // Check for consistent column count\r\n const inconsistentRows = parseResult.data.filter(row => \r\n Object.keys(row).length !== result.columnCount\r\n );\r\n\r\n if (inconsistentRows.length > 0) {\r\n result.isValid = false;\r\n result.errors.push(`${inconsistentRows.length} rows have inconsistent column count`);\r\n }\r\n\r\n } catch (error) {\r\n result.isValid = false;\r\n result.errors.push(`Validation failed: ${(error as Error).message}`);\r\n }\r\n\r\n return result;\r\n }\r\n}","// src/core/service-manager.ts\r\nimport { BaseService } from './base-service';\r\nimport { ServiceStatus, HealthCheckResult } from '../types';\r\n\r\n// Concrete service class mặc định\r\nexport class DefaultService extends BaseService {\r\n // BaseService đã cung cấp đầy đủ functionality\r\n}\r\n\r\n// Interface cho cấu hình service\r\nexport interface ServiceConfig {\r\n schemaName: string;\r\n tableName: string;\r\n primaryKeyFields?: string[];\r\n serviceClass?: new (schemaName: string, tableName: string) => BaseService;\r\n}\r\n\r\n// Interface cho trạng thái service\r\nexport interface ServiceInfo {\r\n key: string;\r\n schemaName: string;\r\n tableName: string;\r\n status: ServiceStatus;\r\n isRegistered: boolean;\r\n createdAt: string;\r\n lastAccessed?: string;\r\n}\r\n\r\n// Interface cho báo cáo sức khỏe\r\nexport interface HealthReport {\r\n totalServices: number;\r\n healthyServices: number;\r\n unhealthyServices: number;\r\n services: Array<HealthCheckResult & { serviceKey: string }>;\r\n timestamp: string;\r\n overallHealth: boolean;\r\n}\r\n\r\n// Event types cho ServiceManager\r\nexport interface ServiceManagerEvent {\r\n type: 'SERVICE_CREATED' | 'SERVICE_DESTROYED' | 'SERVICE_ERROR' | 'HEALTH_CHECK_COMPLETED';\r\n serviceKey: string;\r\n schemaName: string;\r\n tableName: string;\r\n timestamp: string;\r\n data?: any;\r\n error?: Error;\r\n}\r\n\r\nexport type ServiceManagerEventHandler = (event: ServiceManagerEvent) => void;\r\n\r\n/**\r\n * ServiceManager - Quản lý vòng đời các service con kế thừa từ BaseService\r\n * Không can thiệp vào DatabaseManager, chỉ tập trung quản lý service instances\r\n */\r\nexport class ServiceManager {\r\n private static instance: ServiceManager | null = null;\r\n \r\n // Service registry\r\n private services: Map<string, BaseService> = new Map();\r\n private serviceConfigs: Map<string, ServiceConfig> = new Map();\r\n private serviceMetadata: Map<string, { createdAt: string; lastAccessed?: string }> = new Map();\r\n \r\n // Event system\r\n private eventHandlers: Map<string, ServiceManagerEventHandler[]> = new Map();\r\n \r\n // Lifecycle management\r\n private isShuttingDown = false;\r\n private cleanupInterval: NodeJS.Timeout | null = null;\r\n \r\n private constructor() {\r\n this.bindMethods();\r\n this.startPeriodicCleanup();\r\n }\r\n\r\n /**\r\n * Singleton instance\r\n */\r\n public static getInstance(): ServiceManager {\r\n if (!ServiceManager.instance) {\r\n ServiceManager.instance = new ServiceManager();\r\n }\r\n return ServiceManager.instance;\r\n }\r\n\r\n /**\r\n * Reset singleton (chủ yếu cho testing)\r\n */\r\n public static resetInstance(): void {\r\n if (ServiceManager.instance) {\r\n ServiceManager.instance.destroy();\r\n ServiceManager.instance = null;\r\n }\r\n }\r\n\r\n private bindMethods(): void {\r\n const methods = Object.getOwnPropertyNames(Object.getPrototypeOf(this));\r\n methods.forEach(method => {\r\n if (typeof (this as any)[method] === 'function' && method !== 'constructor') {\r\n (this as any)[method] = (this as any)[method].bind(this);\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Tạo service key duy nhất\r\n */\r\n private createServiceKey(schemaName: string, tableName: string): string {\r\n return `${schemaName}:${tableName}`;\r\n }\r\n\r\n /**\r\n * Validate service config\r\n */\r\n private validateServiceConfig(config: ServiceConfig): void {\r\n if (!config.schemaName?.trim()) {\r\n throw new Error('Schema name is required and cannot be empty');\r\n }\r\n if (!config.tableName?.trim()) {\r\n throw new Error('Table name is required and cannot be empty');\r\n }\r\n }\r\n\r\n /**\r\n * Đăng ký cấu hình service\r\n */\r\n public registerService(config: ServiceConfig): this {\r\n this.validateServiceConfig(config);\r\n \r\n const serviceKey = this.createServiceKey(config.schemaName, config.tableName);\r\n \r\n // Normalize config\r\n const normalizedConfig: ServiceConfig = {\r\n schemaName: config.schemaName.trim(),\r\n tableName: config.tableName.trim(),\r\n primaryKeyFields: config.primaryKeyFields || ['id'],\r\n serviceClass: config.serviceClass || DefaultService,\r\n };\r\n \r\n this.serviceConfigs.set(serviceKey, normalizedConfig);\r\n \r\n return this;\r\n }\r\n\r\n /**\r\n * Đăng ký nhiều services\r\n */\r\n public registerServices(configs: ServiceConfig[]): this {\r\n configs.forEach(config => this.registerService(config));\r\n return this;\r\n }\r\n\r\n /**\r\n * Tạo service instance từ config\r\n */\r\n private async createServiceInstance(config: ServiceConfig): Promise<BaseService> {\r\n const ServiceClass = config.serviceClass || DefaultService;\r\n const service = new ServiceClass(config.schemaName, config.tableName);\r\n \r\n if (config.primaryKeyFields) {\r\n service.setPrimaryKeyFields(config.primaryKeyFields);\r\n }\r\n \r\n return service;\r\n }\r\n\r\n /**\r\n * Lấy service (tự động tạo nếu chưa tồn tại)\r\n */\r\n public async getService(schemaName: string, tableName: string): Promise<BaseService> {\r\n if (this.isShuttingDown) {\r\n throw new Error('ServiceManager is shutting down');\r\n }\r\n\r\n const serviceKey = this.createServiceKey(schemaName, tableName);\r\n \r\n // Update access time\r\n const metadata = this.serviceMetadata.get(serviceKey);\r\n if (metadata) {\r\n metadata.lastAccessed = new Date().toISOString();\r\n }\r\n \r\n // Return existing service\r\n if (this.services.has(serviceKey)) {\r\n return this.services.get(serviceKey)!;\r\n }\r\n \r\n // Get or create default config\r\n let config = this.serviceConfigs.get(serviceKey);\r\n if (!config) {\r\n config = {\r\n schemaName,\r\n tableName,\r\n primaryKeyFields: ['id'],\r\n serviceClass: DefaultService,\r\n };\r\n this.serviceConfigs.set(serviceKey, config);\r\n }\r\n \r\n try {\r\n const service = await this.createServiceInstance(config);\r\n this.services.set(serviceKey, service);\r\n \r\n // Track metadata\r\n this.serviceMetadata.set(serviceKey, {\r\n createdAt: new Date().toISOString(),\r\n lastAccessed: new Date().toISOString(),\r\n });\r\n \r\n this.emit('SERVICE_CREATED', {\r\n serviceKey,\r\n schemaName,\r\n tableName,\r\n });\r\n \r\n return service;\r\n } catch (error) {\r\n this.emit('SERVICE_ERROR', {\r\n serviceKey,\r\n schemaName,\r\n tableName,\r\n error: error as Error,\r\n });\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Lấy service đã tồn tại (không tự động tạo)\r\n */\r\n public getExistingService(schemaName: string, tableName: string): BaseService | null {\r\n const serviceKey = this.createServiceKey(schemaName, tableName);\r\n return this.services.get(serviceKey) || null;\r\n }\r\n\r\n /**\r\n * Khởi tạo service\r\n */\r\n public async initializeService(schemaName: string, tableName: string): Promise<BaseService> {\r\n const service = await this.getService(schemaName, tableName);\r\n await service.init();\r\n return service;\r\n }\r\n\r\n /**\r\n * Hủy service instance\r\n */\r\n public async destroyService(schemaName: string, tableName: string): Promise<boolean> {\r\n const serviceKey = this.createServiceKey(schemaName, tableName);\r\n const service = this.services.get(serviceKey);\r\n \r\n if (!service) {\r\n return false;\r\n }\r\n \r\n try {\r\n await service.close();\r\n service.destroy();\r\n \r\n this.services.delete(serviceKey);\r\n this.serviceMetadata.delete(serviceKey);\r\n \r\n this.emit('SERVICE_DESTROYED', {\r\n serviceKey,\r\n schemaName,\r\n tableName,\r\n });\r\n \r\n return true;\r\n } catch (error) {\r\n this.emit('SERVICE_ERROR', {\r\n serviceKey,\r\n schemaName,\r\n tableName,\r\n error: error as Error,\r\n });\r\n return false;\r\n }\r\n }\r\n\r\n /**\r\n * Lấy danh sách services theo schema\r\n */\r\n public getServicesBySchema(schemaName: string): BaseService[] {\r\n const services: BaseService[] = [];\r\n \r\n for (const [serviceKey, service] of this.services) {\r\n const [keySchema] = serviceKey.split(':');\r\n if (keySchema === schemaName) {\r\n services.push(service);\r\n }\r\n }\r\n \r\n return services;\r\n }\r\n\r\n /**\r\n * Lấy danh sách service keys theo schema\r\n */\r\n public getServiceKeysBySchema(schemaName: string): string[] {\r\n const keys: string[] = [];\r\n \r\n for (const serviceKey of this.services.keys()) {\r\n const [keySchema] = serviceKey.split(':');\r\n if (keySchema === schemaName) {\r\n keys.push(serviceKey);\r\n }\r\n }\r\n \r\n return keys;\r\n }\r\n\r\n /**\r\n * Hủy tất cả services trong một schema\r\n */\r\n public async destroyServicesBySchema(schemaName: string): Promise<void> {\r\n const serviceKeys = this.getServiceKeysBySchema(schemaName);\r\n \r\n const destroyPromises = serviceKeys.map(async serviceKey => {\r\n const [, tableName] = serviceKey.split(':');\r\n return this.destroyService(schemaName, tableName);\r\n });\r\n \r\n await Promise.all(destroyPromises);\r\n }\r\n\r\n /**\r\n * Lấy thông tin tất cả services\r\n */\r\n public getAllServiceInfo(): ServiceInfo[] {\r\n const infos: ServiceInfo[] = [];\r\n \r\n // Registered services\r\n for (const [serviceKey, config] of this.serviceConfigs) {\r\n const service = this.services.get(serviceKey);\r\n const metadata = this.serviceMetadata.get(serviceKey);\r\n \r\n infos.push({\r\n key: serviceKey,\r\n schemaName: config.schemaName,\r\n tableName: config.tableName,\r\n status: service ? service.getStatus() : {\r\n schemaName: config.schemaName,\r\n tableName: config.tableName,\r\n isOpened: false,\r\n isInitialized: false,\r\n hasDao: false,\r\n },\r\n isRegistered: true,\r\n createdAt: metadata?.createdAt || 'N/A',\r\n lastAccessed: metadata?.lastAccessed,\r\n });\r\n }\r\n \r\n // Unregistered services (created on-the-fly)\r\n for (const [serviceKey, service] of this.services) {\r\n if (!this.serviceConfigs.has(serviceKey)) {\r\n const [schemaName, tableName] = serviceKey.split(':');\r\n const metadata = this.serviceMetadata.get(serviceKey);\r\n \r\n infos.push({\r\n key: serviceKey,\r\n schemaName,\r\n tableName,\r\n status: service.getStatus(),\r\n isRegistered: false,\r\n createdAt: metadata?.createdAt || 'N/A',\r\n lastAccessed: metadata?.lastAccessed,\r\n });\r\n }\r\n }\r\n \r\n return infos;\r\n }\r\n\r\n /**\r\n * Kiểm tra sức khỏe tất cả services\r\n */\r\n public async healthCheck(): Promise<HealthReport> {\r\n const services = Array.from(this.services.entries());\r\n const healthPromises = services.map(async ([serviceKey, service]) => {\r\n try {\r\n const health = await service.healthCheck();\r\n return { ...health, serviceKey };\r\n } catch (error) {\r\n const [schemaName, tableName] = serviceKey.split(':');\r\n return {\r\n healthy: false,\r\n schemaName,\r\n error: (error as Error).message,\r\n timestamp: new Date().toISOString(),\r\n serviceKey,\r\n };\r\n }\r\n });\r\n \r\n const results = await Promise.all(healthPromises);\r\n const healthyCount = results.filter(r => r.healthy).length;\r\n \r\n const report: HealthReport = {\r\n totalServices: results.length,\r\n healthyServices: healthyCount,\r\n unhealthyServices: results.length - healthyCount,\r\n services: results,\r\n timestamp: new Date().toISOString(),\r\n overallHealth: healthyCount === results.length,\r\n };\r\n \r\n this.emit('HEALTH_CHECK_COMPLETED', {\r\n serviceKey: '*',\r\n schemaName: '*',\r\n tableName: '*',\r\n data: report,\r\n });\r\n \r\n return report;\r\n }\r\n\r\n /**\r\n * Thực hiện transaction trên nhiều services trong cùng schema\r\n * (Vì SQLite transaction chỉ hoạt động trong cùng database connection)\r\n */\r\n public async executeSchemaTransaction<T>(\r\n schemaName: string,\r\n callback: (services: BaseService[]) => Promise<T>\r\n ): Promise<T> {\r\n const services = this.getServicesBySchema(schemaName);\r\n \r\n if (services.length === 0) {\r\n throw new Error(`No services found for schema: ${schemaName}`);\r\n }\r\n \r\n // Ensure all services are initialized\r\n for (const service of services) {\r\n await service.init();\r\n }\r\n \r\n // Execute transaction on the first service (they share the same database)\r\n const primaryService = services[0];\r\n \r\n return await primaryService.executeTransaction(async () => {\r\n return await callback(services);\r\n });\r\n }\r\n\r\n /**\r\n * Periodic cleanup for unused services\r\n */\r\n private startPeriodicCleanup(): void {\r\n // Cleanup every 5 minutes\r\n this.cleanupInterval = setInterval(() => {\r\n this.cleanupUnusedServices();\r\n }, 5 * 60 * 1000);\r\n }\r\n\r\n /**\r\n * Cleanup services not accessed for a long time\r\n */\r\n private async cleanupUnusedServices(maxIdleTime: number = 30 * 60 * 1000): Promise<void> {\r\n if (this.isShuttingDown) {\r\n return;\r\n }\r\n\r\n const now = Date.now();\r\n const servicesToDestroy: string[] = [];\r\n \r\n for (const [serviceKey, metadata] of this.serviceMetadata) {\r\n if (!metadata.lastAccessed) {\r\n continue;\r\n }\r\n \r\n const lastAccessTime = new Date(metadata.lastAccessed).getTime();\r\n if (now - lastAccessTime > maxIdleTime) {\r\n servicesToDestroy.push(serviceKey);\r\n }\r\n }\r\n \r\n for (const serviceKey of servicesToDestroy) {\r\n const [schemaName, tableName] = serviceKey.split(':');\r\n await this.destroyService(schemaName, tableName);\r\n }\r\n }\r\n\r\n /**\r\n * Event system\r\n */\r\n public on(eventType: string, handler: ServiceManagerEventHandler): this {\r\n if (!this.eventHandlers.has(eventType)) {\r\n this.eventHandlers.set(eventType, []);\r\n }\r\n this.eventHandlers.get(eventType)!.push(handler);\r\n return this;\r\n }\r\n\r\n public off(eventType: string, handler: ServiceManagerEventHandler): this {\r\n const handlers = this.eventHandlers.get(eventType);\r\n if (handlers) {\r\n const index = handlers.indexOf(handler);\r\n if (index > -1) {\r\n handlers.splice(index, 1);\r\n }\r\n }\r\n return this;\r\n }\r\n\r\n private emit(\r\n type: ServiceManagerEvent['type'],\r\n data: Omit<ServiceManagerEvent, 'type' | 'timestamp'>\r\n ): void {\r\n const event: ServiceManagerEvent = {\r\n ...data,\r\n type,\r\n timestamp: new Date().toISOString(),\r\n };\r\n\r\n // Emit to specific event handlers\r\n const handlers = this.eventHandlers.get(type);\r\n if (handlers) {\r\n handlers.forEach(handler => {\r\n try {\r\n handler(event);\r\n } catch (error) {\r\n console.error(`ServiceManager: Error in ${type} event handler:`, error);\r\n }\r\n });\r\n }\r\n\r\n // Emit to global event handlers\r\n const globalHandlers = this.eventHandlers.get('*');\r\n if (globalHandlers) {\r\n globalHandlers.forEach(handler => {\r\n try {\r\n handler(event);\r\n } catch (error) {\r\n console.error('ServiceManager: Error in global event handler:', error);\r\n }\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Utility methods\r\n */\r\n public hasService(schemaName: string, tableName: string): boolean {\r\n const serviceKey = this.createServiceKey(schemaName, tableName);\r\n return this.services.has(serviceKey);\r\n }\r\n\r\n public isRegistered(schemaName: string, tableName: string): boolean {\r\n const serviceKey = this.createServiceKey(schemaName, tableName);\r\n return this.serviceConfigs.has(serviceKey);\r\n }\r\n\r\n public getServiceCount(): number {\r\n return this.services.size;\r\n }\r\n\r\n public getRegisteredCount(): number {\r\n return this.serviceConfigs.size;\r\n }\r\n\r\n public getSchemas(): string[] {\r\n const schemas = new Set<string>();\r\n \r\n for (const serviceKey of this.services.keys()) {\r\n const [schemaName] = serviceKey.split(':');\r\n schemas.add(schemaName);\r\n }\r\n \r\n return Array.from(schemas);\r\n }\r\n\r\n /**\r\n * Destroy all services and cleanup resources\r\n */\r\n public async destroy(): Promise<void> {\r\n this.isShuttingDown = true;\r\n \r\n // Clear cleanup interval\r\n if (this.cleanupInterval) {\r\n clearInterval(this.cleanupInterval);\r\n this.cleanupInterval = null;\r\n }\r\n \r\n // Destroy all services\r\n const destroyPromises = Array.from(this.services.entries()).map(\r\n async ([serviceKey, service]) => {\r\n try {\r\n await service.close();\r\n service.destroy();\r\n } catch (error) {\r\n console.error(`Error destroying service ${serviceKey}:`, error);\r\n }\r\n }\r\n );\r\n \r\n await Promise.all(destroyPromises);\r\n \r\n // Clear all data\r\n this.services.clear();\r\n this.serviceConfigs.clear();\r\n this.serviceMetadata.clear();\r\n this.eventHandlers.clear();\r\n \r\n this.isShuttingDown = false;\r\n }\r\n}\r\n\r\n// Export singleton instance\r\nexport const serviceManager = ServiceManager.getInstance();","// src/adapters/base-adapter.ts\r\nimport { SQLiteAdapter, SQLiteConnection } from '../types';\r\nexport abstract class BaseAdapter implements SQLiteAdapter {\r\n abstract connect(path: string): Promise<SQLiteConnection>;\r\n abstract isSupported(): boolean;\r\n\r\n protected sanitizeSQL(sql: string): string {\r\n return sql.trim();\r\n }\r\n\r\n protected bindParameters(sql: string, params?: any[]): string {\r\n if (!params || params.length === 0) {\r\n return sql;\r\n }\r\n\r\n let paramIndex = 0;\r\n return sql.replace(/\\?/g, () => {\r\n if (paramIndex < params.length) {\r\n const param = params[paramIndex++];\r\n if (typeof param === 'string') {\r\n return `'${param.replace(/'/g, \"''\")}'`;\r\n }\r\n if (param === null || param === undefined) {\r\n return 'NULL';\r\n }\r\n return String(param);\r\n }\r\n return '?';\r\n });\r\n }\r\n}","// src/index.ts - Main exports for UniversalSQLite Library\r\nimport { DatabaseManager } from \"./core/database-manager\";\r\nimport { UniversalDAO } from \"./core/universal-dao\";\r\nimport { BaseService } from \"./core/base-service\";\r\nimport { DatabaseFactory } from \"./core/database-factory\";\r\nimport { QueryBuilder } from \"./query/query-builder\";\r\nimport { MigrationManager } from \"./utils/migration-manager\";\r\nimport { CSVImporter } from \"./utils/csv-import\";\r\nimport {\r\n SQLiteAdapter,\r\n SQLiteResult,\r\n SQLiteRow,\r\n DatabaseSchema,\r\n DbFactoryOptions,\r\n ImportOptions,\r\n ImportResult,\r\n ColumnMapping\r\n} from \"./types\";\r\n\r\n// ========================== CORE EXPORTS ==========================\r\nexport { UniversalDAO } from \"./core/universal-dao\";\r\nexport { DatabaseFactory } from \"./core/database-factory\";\r\nexport { DatabaseManager } from \"./core/database-manager\";\r\nexport { BaseService } from \"./core/base-service\";\r\nexport {\r\n ServiceManager,\r\n DefaultService,\r\n type ServiceConfig,\r\n type ServiceInfo,\r\n type HealthReport,\r\n type ServiceManagerEvent,\r\n type ServiceManagerEventHandler,\r\n} from \"./core/service-manager\";\r\n\r\n// ========================== QUERY & UTILITIES ==========================\r\nexport { QueryBuilder } from \"./query/query-builder\";\r\nexport { MigrationManager, type Migration } from \"./utils/migration-manager\";\r\nexport { CSVImporter } from \"./utils/csv-import\";\r\n\r\n// ========================== ADAPTERS ==========================\r\nexport { BaseAdapter } from \"./adapters/base-adapter\";\r\n\r\n// ========================== TYPE EXPORTS ==========================\r\nexport * from \"./types\";\r\n\r\n// ========================== UNIFIED INTERFACE ==========================\r\n\r\n/**\r\n * UniversalSQLite - The main unified interface providing a comprehensive\r\n * SQLite database management solution for all environments and platforms.\r\n *\r\n * Features:\r\n * - Cross-platform support (Browser, Node.js, Deno, Bun, React Native)\r\n * - Schema-based database management\r\n * - Role-based access control\r\n * - Advanced query building\r\n * - Data import/export capabilities\r\n * - Migration system\r\n * - Transaction management\r\n * - Connection pooling and lifecycle management\r\n */\r\nexport class UniversalSQLite {\r\n private static instance: UniversalSQLite | null = null;\r\n private currentSchema: string | null = null;\r\n private isInitialized: boolean = false;\r\n private initializationPromise: Promise<void> | null = null;\r\n private eventListeners: Map<string, Array<(...args: any[]) => void>> =\r\n new Map();\r\n\r\n constructor() {\r\n // Private constructor for singleton pattern\r\n if (UniversalSQLite.instance) {\r\n throw new Error(\r\n \"UniversalSQLite is a singleton. Use UniversalSQLite.getInstance() instead.\"\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Get singleton instance of UniversalSQLite\r\n */\r\n static getInstance(): UniversalSQLite {\r\n if (!UniversalSQLite.instance) {\r\n UniversalSQLite.instance = new UniversalSQLite();\r\n }\r\n return UniversalSQLite.instance;\r\n }\r\n\r\n /**\r\n * Reset singleton instance (useful for testing)\r\n */\r\n static resetInstance(): void {\r\n if (UniversalSQLite.instance) {\r\n UniversalSQLite.instance.closeAll().catch(() => {});\r\n }\r\n UniversalSQLite.instance = null;\r\n }\r\n\r\n // ========================== INITIALIZATION METHODS ==========================\r\n\r\n /**\r\n * Initialize UniversalSQLite with schema configurations\r\n * @param schemas - Database schema configurations\r\n * @param options - Additional initialization options\r\n */\r\n async initialize(\r\n schemas: Record<string, DatabaseSchema>,\r\n options: {\r\n registerAdapters?: SQLiteAdapter[];\r\n autoConnectCore?: boolean;\r\n defaultRoles?: string[];\r\n globalErrorHandler?: (error: Error, context: string) => void;\r\n } = {}\r\n ): Promise<void> {\r\n if (this.isInitialized) {\r\n return this.initializationPromise || Promise.resolve();\r\n }\r\n\r\n if (this.initializationPromise) {\r\n return this.initializationPromise;\r\n }\r\n\r\n this.initializationPromise = this._performInitialization(schemas, options);\r\n return this.initializationPromise;\r\n }\r\n\r\n private async _performInitialization(\r\n schemas: Record<string, DatabaseSchema>,\r\n options: {\r\n registerAdapters?: SQLiteAdapter[];\r\n autoConnectCore?: boolean;\r\n defaultRoles?: string[];\r\n globalErrorHandler?: (error: Error, context: string) => void;\r\n }\r\n ): Promise<void> {\r\n try {\r\n // Register adapters if provided\r\n if (options.registerAdapters) {\r\n options.registerAdapters.forEach((adapter) => {\r\n DatabaseFactory.registerAdapter(adapter);\r\n });\r\n }\r\n\r\n // Register global error handler\r\n if (options.globalErrorHandler) {\r\n this.on(\"error\", options.globalErrorHandler);\r\n }\r\n\r\n // Register all schemas with DatabaseManager\r\n DatabaseManager.registerSchemas(schemas);\r\n\r\n // Initialize core connection if core schema exists and autoConnectCore is true\r\n if (schemas.core && options.autoConnectCore !== false) {\r\n await DatabaseManager.initializeCoreConnection();\r\n }\r\n\r\n // Set default roles if provided\r\n if (options.defaultRoles && options.defaultRoles.length > 0) {\r\n await DatabaseManager.setCurrentUserRoles(options.defaultRoles);\r\n }\r\n\r\n this.isInitialized = true;\r\n this._emit(\"initialized\", { schemas: Object.keys(schemas) });\r\n } catch (error) {\r\n this.isInitialized = false;\r\n this.initializationPromise = null;\r\n this._emit(\"error\", error as Error, \"initialization\");\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Initialize from a single schema configuration\r\n */\r\n async initializeFromSchema(\r\n schema: DatabaseSchema,\r\n options: {\r\n registerAdapters?: SQLiteAdapter[];\r\n autoConnect?: boolean;\r\n globalErrorHandler?: (error: Error, context: string) => void;\r\n } = {}\r\n ): Promise<void> {\r\n const schemas = { [schema.database_name]: schema };\r\n return this.initialize(schemas, {\r\n ...options,\r\n autoConnectCore: options.autoConnect !== false,\r\n });\r\n }\r\n\r\n // ========================== CONNECTION MANAGEMENT ==========================\r\n\r\n /**\r\n * Connect to a specific database schema\r\n * @param schemaName - Name of the schema to connect to\r\n * @returns Promise resolving to UniversalDAO instance\r\n */\r\n async connect(schemaName: string): Promise<UniversalDAO> {\r\n this.ensureInitialized();\r\n this.currentSchema = schemaName;\r\n\r\n try {\r\n const dao = await DatabaseManager.getLazyLoading(schemaName);\r\n this._emit(\"connected\", { schemaName });\r\n return dao;\r\n } catch (error) {\r\n this._emit(\"error\", error as Error, \"connection\");\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Get DAO for a specific schema\r\n * @param schemaName - Optional schema name (uses current if not provided)\r\n */\r\n getDAO(schemaName?: string): UniversalDAO {\r\n this.ensureInitialized();\r\n const schema = schemaName || this.currentSchema;\r\n\r\n if (!schema) {\r\n throw new Error(\r\n \"No schema specified. Use connect() first or provide schemaName parameter.\"\r\n );\r\n }\r\n\r\n try {\r\n return DatabaseManager.get(schema);\r\n } catch (error) {\r\n this._emit(\"error\", error as Error, \"getDAO\");\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Get current connected DAO\r\n */\r\n getCurrentDAO(): UniversalDAO {\r\n if (!this.currentSchema) {\r\n throw new Error(\"No current connection. Call connect() first.\");\r\n }\r\n return this.getDAO(this.currentSchema);\r\n }\r\n\r\n /**\r\n * Ensure database connection exists and is active\r\n */\r\n async ensureDatabaseConnection(schemaName: string): Promise<UniversalDAO> {\r\n this.ensureInitialized();\r\n\r\n try {\r\n return await DatabaseManager.ensureDatabaseConnection(schemaName);\r\n } catch (error) {\r\n this._emit(\"error\", error as Error, \"ensureConnection\");\r\n throw error;\r\n }\r\n }\r\n\r\n // ========================== SERVICE CREATION ==========================\r\n\r\n /**\r\n * Create a service for a specific table\r\n * @param tableName - Name of the table\r\n * @param schemaName - Optional schema name (uses current if not provided)\r\n */\r\n createService<T = any>(\r\n tableName: string,\r\n schemaName?: string\r\n ): BaseService<T> {\r\n const schema = schemaName || this.currentSchema;\r\n if (!schema) {\r\n throw new Error(\r\n \"No schema specified. Use connect() first or provide schemaName parameter.\"\r\n );\r\n }\r\n const ServiceClass = class extends BaseService<T> {\r\n constructor() {\r\n if (!schema) {\r\n throw new Error(\r\n \"No schema specified. Use connect() first or provide schemaName parameter.\"\r\n );\r\n }\r\n super(schema, tableName);\r\n }\r\n };\r\n\r\n return new ServiceClass();\r\n }\r\n\r\n /**\r\n * Create multiple services at once\r\n */\r\n createServices<T = any>(\r\n tableNames: string[],\r\n schemaName?: string\r\n ): Record<string, BaseService<T>> {\r\n const services: Record<string, BaseService<T>> = {};\r\n\r\n tableNames.forEach((tableName) => {\r\n services[tableName] = this.createService<T>(tableName, schemaName);\r\n });\r\n\r\n return services;\r\n }\r\n\r\n // ========================== QUERY BUILDING ==========================\r\n\r\n /**\r\n * Create query builder for current connection\r\n */\r\n query(tableName?: string, schemaName?: string): QueryBuilder {\r\n const dao = this.getDAO(schemaName);\r\n\r\n if (tableName) {\r\n return QueryBuilder.table(tableName, dao);\r\n }\r\n\r\n return new QueryBuilder(dao);\r\n }\r\n\r\n /**\r\n * Create query builder from table\r\n */\r\n table(tableName: string, schemaName?: string): QueryBuilder {\r\n return this.query(tableName, schemaName);\r\n }\r\n\r\n /**\r\n * Execute raw SQL on current connection\r\n */\r\n async execute(\r\n sql: string,\r\n params?: any[],\r\n schemaName?: string\r\n ): Promise<SQLiteResult> {\r\n try {\r\n const dao = this.getDAO(schemaName);\r\n const result = await dao.execute(sql, params);\r\n this._emit(\"queryExecuted\", {\r\n sql,\r\n params,\r\n rowCount: result.rowsAffected,\r\n });\r\n return result;\r\n } catch (error) {\r\n this._emit(\"error\", error as Error, \"execute\");\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Get first row from query\r\n */\r\n async getRst(\r\n sql: string,\r\n params?: any[],\r\n schemaName?: string\r\n ): Promise<SQLiteRow> {\r\n const dao = this.getDAO(schemaName);\r\n return await dao.getRst(sql, params);\r\n }\r\n\r\n /**\r\n * Get all rows from query\r\n */\r\n async getRsts(\r\n sql: string,\r\n params?: any[],\r\n schemaName?: string\r\n ): Promise<SQLiteRow[]> {\r\n const dao = this.getDAO(schemaName);\r\n return await dao.getRsts(sql, params);\r\n }\r\n\r\n // ========================== SCHEMA MANAGEMENT ==========================\r\n\r\n /**\r\n * Initialize database from schema\r\n */\r\n async initializeSchema(\r\n schema: DatabaseSchema,\r\n forceRecreate: boolean = false\r\n ): Promise<void> {\r\n try {\r\n const dao = await DatabaseFactory.createOrOpen(\r\n { config: schema },\r\n forceRecreate\r\n );\r\n await dao.initializeFromSchema(schema);\r\n this._emit(\"schemaInitialized\", { schemaName: schema.database_name });\r\n } catch (error) {\r\n this._emit(\"error\", error as Error, \"schemaInitialization\");\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Get schema version for a database\r\n */\r\n async getSchemaVersion(schemaName?: string): Promise<string> {\r\n const dao = this.getDAO(schemaName);\r\n return await dao.getSchemaVersion();\r\n }\r\n\r\n /**\r\n * Get database information\r\n */\r\n async getDatabaseInfo(schemaName?: string): Promise<any> {\r\n const dao = this.getDAO(schemaName);\r\n return await dao.getDatabaseInfo();\r\n }\r\n\r\n /**\r\n * Get table information\r\n */\r\n async getTableInfo(tableName: string, schemaName?: string): Promise<any[]> {\r\n const dao = this.getDAO(schemaName);\r\n return await dao.getTableInfo(tableName);\r\n }\r\n\r\n // ========================== MIGRATION MANAGEMENT ==========================\r\n\r\n /**\r\n * Create migration manager for current connection\r\n */\r\n createMigrationManager(schemaName?: string): MigrationManager {\r\n const dao = this.getDAO(schemaName);\r\n return new MigrationManager(dao);\r\n }\r\n\r\n /**\r\n * Run migrations for a database\r\n */\r\n async runMigrations(\r\n migrations: Array<{\r\n version: string;\r\n description: string;\r\n up: (dao: UniversalDAO) => Promise<void>;\r\n down: (dao: UniversalDAO) => Promise<void>;\r\n }>,\r\n schemaName?: string,\r\n targetVersion?: string\r\n ): Promise<void> {\r\n const migrationManager = this.createMigrationManager(schemaName);\r\n\r\n migrations.forEach((migration) => {\r\n migrationManager.addMigration(migration);\r\n });\r\n\r\n await migrationManager.migrate(targetVersion);\r\n this._emit(\"migrationsCompleted\", {\r\n schemaName: schemaName || this.currentSchema,\r\n });\r\n }\r\n\r\n // ========================== DATA IMPORT/EXPORT ==========================\r\n\r\n /**\r\n * Create CSV importer for current connection\r\n */\r\n createCSVImporter(schemaName?: string): CSVImporter {\r\n const dao = this.getDAO(schemaName);\r\n return new CSVImporter(dao);\r\n }\r\n\r\n /**\r\n * Import data to a specific table\r\n */\r\n async importData(\r\n schemaName: string,\r\n tableName: string,\r\n data: Record<string, any>[],\r\n options?: Partial<ImportOptions>\r\n ): Promise<ImportResult> {\r\n try {\r\n const result = await DatabaseManager.importDataToTable(\r\n schemaName,\r\n tableName,\r\n data,\r\n options\r\n );\r\n this._emit(\"dataImported\", {\r\n schemaName,\r\n tableName,\r\n recordCount: result.successRows,\r\n });\r\n return result;\r\n } catch (error) {\r\n this._emit(\"error\", error as Error, \"dataImport\");\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Import data with column mapping\r\n */\r\n async importDataWithMapping(\r\n schemaName: string,\r\n tableName: string,\r\n data: Record<string, any>[],\r\n columnMappings: ColumnMapping[],\r\n options?: Partial<ImportOptions>\r\n ): Promise<ImportResult> {\r\n try {\r\n const result = await DatabaseManager.importDataWithMapping(\r\n schemaName,\r\n tableName,\r\n data,\r\n columnMappings,\r\n options\r\n );\r\n this._emit(\"dataImported\", {\r\n schemaName,\r\n tableName,\r\n recordCount: result.successRows,\r\n });\r\n return result;\r\n } catch (error) {\r\n this._emit(\"error\", error as Error, \"dataImportWithMapping\");\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Import from CSV\r\n */\r\n async importFromCSV(\r\n schemaName: string,\r\n tableName: string,\r\n csvData: string,\r\n options?: {\r\n delimiter?: string;\r\n hasHeader?: boolean;\r\n columnMappings?: ColumnMapping[];\r\n } & Partial<ImportOptions>\r\n ): Promise<ImportResult> {\r\n try {\r\n const result = await DatabaseManager.importFromCSV(\r\n schemaName,\r\n tableName,\r\n csvData,\r\n options\r\n );\r\n this._emit(\"csvImported\", {\r\n schemaName,\r\n tableName,\r\n recordCount: result.successRows,\r\n });\r\n return result;\r\n } catch (error) {\r\n this._emit(\"error\", error as Error, \"csvImport\");\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Export table data to CSV\r\n */\r\n async exportToCSV(\r\n tableName: string,\r\n schemaName?: string,\r\n options?: {\r\n columns?: string[];\r\n where?: string;\r\n orderBy?: string;\r\n limit?: number;\r\n delimiter?: string;\r\n includeHeaders?: boolean;\r\n }\r\n ): Promise<string> {\r\n const importer = this.createCSVImporter(schemaName);\r\n return await importer.exportToCSV(tableName, options);\r\n }\r\n\r\n // ========================== ROLE & ACCESS MANAGEMENT ==========================\r\n\r\n /**\r\n * Set user roles and initialize role-based connections\r\n */\r\n async setUserRoles(roles: string[], primaryRole?: string): Promise<void> {\r\n this.ensureInitialized();\r\n\r\n try {\r\n await DatabaseManager.setCurrentUserRoles(roles, primaryRole);\r\n this._emit(\"userRolesSet\", { roles, primaryRole });\r\n } catch (error) {\r\n this._emit(\"error\", error as Error, \"setUserRoles\");\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Get current user roles\r\n */\r\n getCurrentUserRoles(): string[] {\r\n return DatabaseManager.getCurrentUserRoles();\r\n }\r\n\r\n /**\r\n * Get current primary role\r\n */\r\n getCurrentRole(): string | null {\r\n return DatabaseManager.getCurrentRole();\r\n }\r\n\r\n /**\r\n * Check if user has access to database\r\n */\r\n hasAccessToDatabase(dbKey: string): boolean {\r\n return DatabaseManager.hasAccessToDatabase(dbKey);\r\n }\r\n\r\n // ========================== TRANSACTION MANAGEMENT ==========================\r\n\r\n /**\r\n * Execute cross-schema transaction\r\n */\r\n async executeTransaction(\r\n schemas: string[],\r\n callback: (daos: Record<string, UniversalDAO>) => Promise<void>\r\n ): Promise<void> {\r\n try {\r\n await DatabaseManager.executeCrossSchemaTransaction(schemas, callback);\r\n this._emit(\"transactionCompleted\", { schemas });\r\n } catch (error) {\r\n this._emit(\"error\", error as Error, \"transaction\");\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Execute transaction on current connection\r\n */\r\n async executeTransactionOnCurrent<T>(\r\n callback: (dao: UniversalDAO) => Promise<T>\r\n ): Promise<T> {\r\n const dao = this.getCurrentDAO();\r\n\r\n try {\r\n await dao.beginTransaction();\r\n const result = await callback(dao);\r\n await dao.commitTransaction();\r\n return result;\r\n } catch (error) {\r\n await dao.rollbackTransaction();\r\n throw error;\r\n }\r\n }\r\n\r\n // ========================== UTILITY & STATUS METHODS ==========================\r\n\r\n /**\r\n * Get environment information\r\n */\r\n getEnvironment(): string {\r\n return DatabaseFactory.getEnvironmentInfo();\r\n }\r\n\r\n /**\r\n * Get connection status\r\n */\r\n getConnectionStatus(): {\r\n isInitialized: boolean;\r\n currentSchema: string | null;\r\n activeConnections: string[];\r\n connectionCount: number;\r\n userRoles: string[];\r\n primaryRole: string | null;\r\n } {\r\n return {\r\n isInitialized: this.isInitialized,\r\n currentSchema: this.currentSchema,\r\n activeConnections: DatabaseManager.listConnections(),\r\n connectionCount: DatabaseManager.getConnectionCount(),\r\n userRoles: this.getCurrentUserRoles(),\r\n primaryRole: this.getCurrentRole(),\r\n };\r\n }\r\n\r\n /**\r\n * Get list of available schemas\r\n */\r\n getAvailableSchemas(): string[] {\r\n return DatabaseManager.getAvailableSchemas();\r\n }\r\n\r\n /**\r\n * Health check for all connections\r\n */\r\n async healthCheck(): Promise<\r\n Record<string, { healthy: boolean; error?: string }>\r\n > {\r\n const connections = DatabaseManager.getConnections();\r\n const healthStatus: Record<string, { healthy: boolean; error?: string }> =\r\n {};\r\n\r\n for (const [schemaName, dao] of Object.entries(connections)) {\r\n try {\r\n await dao.execute(\"SELECT 1\");\r\n healthStatus[schemaName] = { healthy: true };\r\n } catch (error) {\r\n healthStatus[schemaName] = {\r\n healthy: false,\r\n error: (error as Error).message,\r\n };\r\n }\r\n }\r\n\r\n return healthStatus;\r\n }\r\n\r\n // ========================== EVENT SYSTEM ==========================\r\n\r\n /**\r\n * Add event listener\r\n */\r\n on(event: string, handler: (...args: any[]) => void): this {\r\n if (!this.eventListeners.has(event)) {\r\n this.eventListeners.set(event, []);\r\n }\r\n this.eventListeners.get(event)!.push(handler);\r\n return this;\r\n }\r\n\r\n /**\r\n * Remove event listener\r\n */\r\n off(event: string, handler: (...args: any[]) => void): this {\r\n const handlers = this.eventListeners.get(event);\r\n if (handlers) {\r\n const index = handlers.indexOf(handler);\r\n if (index > -1) {\r\n handlers.splice(index, 1);\r\n }\r\n }\r\n return this;\r\n }\r\n\r\n /**\r\n * Emit event\r\n */\r\n private _emit(event: string, ...args: any[]): void {\r\n const handlers = this.eventListeners.get(event);\r\n if (handlers) {\r\n handlers.forEach((handler) => {\r\n try {\r\n handler(...args);\r\n } catch (error) {\r\n // Handle event handler errors gracefully\r\n console.error(\"Error in event handler:\", error);\r\n }\r\n });\r\n }\r\n }\r\n\r\n // ========================== CONNECTION LIFECYCLE ==========================\r\n\r\n /**\r\n * Close specific connection\r\n */\r\n async closeConnection(schemaName: string): Promise<void> {\r\n try {\r\n await DatabaseManager.closeConnection(schemaName);\r\n\r\n if (this.currentSchema === schemaName) {\r\n this.currentSchema = null;\r\n }\r\n\r\n this._emit(\"connectionClosed\", { schemaName });\r\n } catch (error) {\r\n this._emit(\"error\", error as Error, \"closeConnection\");\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Close all connections\r\n */\r\n async closeAll(): Promise<void> {\r\n try {\r\n await DatabaseManager.closeAll();\r\n this.currentSchema = null;\r\n this.isInitialized = false;\r\n this.initializationPromise = null;\r\n this.eventListeners.clear();\r\n this._emit(\"allConnectionsClosed\");\r\n } catch (error) {\r\n this._emit(\"error\", error as Error, \"closeAll\");\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Logout user and close role-specific connections\r\n */\r\n async logout(): Promise<void> {\r\n try {\r\n await DatabaseManager.logout();\r\n this.currentSchema = null;\r\n this._emit(\"userLoggedOut\");\r\n } catch (error) {\r\n this._emit(\"error\", error as Error, \"logout\");\r\n throw error;\r\n }\r\n }\r\n\r\n // ========================== STATIC UTILITY METHODS ==========================\r\n\r\n /**\r\n * Register adapter with DatabaseFactory\r\n */\r\n static registerAdapter(adapter: SQLiteAdapter): void {\r\n DatabaseFactory.registerAdapter(adapter);\r\n }\r\n\r\n /**\r\n * Register role configuration\r\n */\r\n static registerRole(roleConfig: {\r\n roleName: string;\r\n requiredDatabases: string[];\r\n optionalDatabases?: string[];\r\n priority?: number;\r\n }): void {\r\n DatabaseManager.registerRole(roleConfig);\r\n }\r\n\r\n /**\r\n * Register multiple roles\r\n */\r\n static registerRoles(\r\n roleConfigs: Array<{\r\n roleName: string;\r\n requiredDatabases: string[];\r\n optionalDatabases?: string[];\r\n priority?: number;\r\n }>\r\n ): void {\r\n DatabaseManager.registerRoles(roleConfigs);\r\n }\r\n\r\n // ========================== PRIVATE HELPERS ==========================\r\n\r\n private ensureInitialized(): void {\r\n if (!this.isInitialized) {\r\n throw new Error(\r\n \"UniversalSQLite not initialized. Call initialize() first.\"\r\n );\r\n }\r\n }\r\n}\r\n\r\n// ========================== FACTORY FUNCTIONS ==========================\r\n\r\n/**\r\n * Create UniversalDAO instance\r\n */\r\nexport const createUniversalDAO = (\r\n dbPath: string,\r\n options?: {\r\n adapter?: SQLiteAdapter;\r\n createIfNotExists?: boolean;\r\n forceRecreate?: boolean;\r\n }\r\n): UniversalDAO => {\r\n return DatabaseFactory.createDAO(dbPath, options);\r\n};\r\n\r\n/**\r\n * Create database from schema configuration\r\n */\r\nexport const createDatabaseFromSchema = async (\r\n schema: DatabaseSchema,\r\n options?: Omit<DbFactoryOptions, \"config\">\r\n): Promise<UniversalDAO> => {\r\n return await DatabaseFactory.createFromConfig(schema, options);\r\n};\r\n\r\n/**\r\n * Open existing database\r\n */\r\nexport const openExistingDatabase = async (\r\n dbName: string,\r\n options?: Omit<DbFactoryOptions, \"config\" | \"configAsset\">\r\n): Promise<UniversalDAO> => {\r\n return await DatabaseFactory.openExisting(dbName, options);\r\n};\r\n\r\n/**\r\n * Create query builder\r\n */\r\nexport const createQueryBuilder = (dao?: UniversalDAO): QueryBuilder => {\r\n return new QueryBuilder(dao);\r\n};\r\n\r\n/**\r\n * Create base service\r\n */\r\nexport const createBaseService = <T = any>(\r\n schemaName: string,\r\n tableName?: string\r\n): BaseService<T> => {\r\n return new (class extends BaseService<T> {\r\n constructor() {\r\n super(schemaName, tableName);\r\n }\r\n })();\r\n};\r\n\r\n/**\r\n * Create migration manager\r\n */\r\nexport const createMigrationManager = (dao: UniversalDAO): MigrationManager => {\r\n return new MigrationManager(dao);\r\n};\r\n\r\n/**\r\n * Create CSV importer\r\n */\r\nexport const createCSVImporter = (dao: UniversalDAO): CSVImporter => {\r\n return new CSVImporter(dao);\r\n};\r\n\r\n// ========================== CONVENIENCE EXPORTS ==========================\r\n\r\n/**\r\n * Quick setup function for common use cases\r\n */\r\nexport const setupUniversalSQLite = async (config: {\r\n schemas: Record<string, DatabaseSchema>;\r\n adapters?: SQLiteAdapter[];\r\n defaultRoles?: string[];\r\n autoConnect?: string; // schema name to auto-connect to\r\n}): Promise<UniversalSQLite> => {\r\n const sqlite = UniversalSQLite.getInstance();\r\n\r\n await sqlite.initialize(config.schemas, {\r\n registerAdapters: config.adapters,\r\n defaultRoles: config.defaultRoles,\r\n });\r\n\r\n if (config.autoConnect) {\r\n await sqlite.connect(config.autoConnect);\r\n }\r\n\r\n return sqlite;\r\n};\r\n\r\n/**\r\n * Quick database creation from single schema\r\n */\r\nexport const createSingleDatabase = async (\r\n schema: DatabaseSchema,\r\n options?: {\r\n adapter?: SQLiteAdapter;\r\n autoConnect?: boolean;\r\n }\r\n): Promise<{ sqlite: UniversalSQLite; dao: UniversalDAO }> => {\r\n const sqlite = UniversalSQLite.getInstance();\r\n\r\n await sqlite.initializeFromSchema(schema, {\r\n registerAdapters: options?.adapter ? [options.adapter] : undefined,\r\n autoConnect: options?.autoConnect,\r\n });\r\n\r\n const dao =\r\n options?.autoConnect !== false\r\n ? await sqlite.connect(schema.database_name)\r\n : sqlite.getDAO(schema.database_name);\r\n\r\n return { sqlite, dao };\r\n};\r\n\r\n// ========================== DEFAULT EXPORT ==========================\r\n\r\n/**\r\n * Default export is the singleton instance\r\n */\r\nconst defaultInstance = UniversalSQLite.getInstance();\r\nexport default defaultInstance;\r\n"],"names":["UniversalDAO","adapter","dbPath","options","_a","_b","config","genericType","col","processedCol","constraints","defaultIndex","defaultValue","schema","hasExistingSchema","error","tableName","tableConfig","tableDefinition","tables","table","columnDefs","foreignKeyDefs","fk","fkSql","allDefs","sql","indexes","index","columns","version","insertTable","validCols","columnNames","placeholders","params","updateTable","setCols","w","setClause","whereClause","deleteTable","selectTable","suffix","orderBy","o","wheres","clause","conditions","where","operator","json","idFields","queryTable","key","value","startTime","result","tableInfo","columnMap","batchSize","processedCount","skipAutoIncrementPK","i","batch","j","rowIndex","rowData","processedData","errorInfo","data","columnMappings","transformedData","row","newRow","mapping","csvData","delimiter","hasHeader","lines","line","headers","dataStartIndex","h","firstRowCols","_","values","v","header","processedRow","columnName","columnInfo","isRequired","isAutoIncrementPK","lowerColumnName","columnType","type","num","lower","date","conflictColumns","updateColumns","whereColumns","updateValues","whereValues","allValues","t","DatabaseFactory","dao","dbInfo","dbName","dbFileName","isForceInit","isForceDelete","schemaError","configAsset","DatabaseManager","maxConnections","currentConnectionCount","manager","schemas","internalKeys","externalKeys","roleConfig","roleConfigs","roleName","allDatabases","db","coreSchema","userRoles","primaryRole","previousRoles","requiredDatabases","failedInitializations","initPromises","dbKey","err","errorSummary","f","previousDatabases","currentDatabases","databasesToClose","schemaName","callback","listeners","closePromises","activeDbArray","databaseKeys","failedOpens","invalidKeys","newConnectionsCount","currentConnectionsCount","availableSchemas","daos","acc","databaseKey","importConfigs","configKey","importResult","connectionsToClose","BaseService","newDao","method","fields","createdRecord","primaryKeyValue","findError","id","updateData","success","record","allWheres","name","results","whereConditions","items","dataArray","rollbackError","obj","event","handler","handlers","errorType","handlerError","count","QueryBuilder","builder","raw","fieldList","condition","fieldOrConditions","operatorOrValue","field","val","actualValue","min","max","subquery","actualOperator","direction","page","perPage","query","alias","cteList","cteSql","cteParams","join","conditionParams","unionQuery","unionSql","unionParams","subSql","subParams","column","valueGroups","whereParams","sets","updateClause","cloned","rawSql","param","MigrationManager","migration","migrations","a","b","createTableSQL","appliedMigrations","appliedVersions","m","appliedMap","applied","dependenciesMet","missingDependencies","targetVersion","allMigrations","plan","reversedApplied","appliedRecord","total","migrationError","timeout","migrationPromise","timeoutPromise","reject","executionTime","checksum","rollbackPromise","reversedMigrations","issues","pending","categories","totalExecutionTime","fromSchema","toSchema","description","migrationDescription","dep","version1","version2","v1Parts","v2Parts","v1Part","v2Part","content","hash","char","CSVImporter","opts","firstRow","lineNumber","parseResult","e","transformErrors","transformedRow","transformer","validator","validationResult","errorMessage","validationError","allErrors","filePath","rows","currentLine","inQuotes","nextChar","currentValue","strValue","mappings","newKey","converted","lowerValue","intValue","floatValue","format","dateString","year","month","day","hours","minutes","seconds","inconsistentRows","DefaultService","ServiceManager","serviceKey","normalizedConfig","configs","ServiceClass","service","metadata","services","keySchema","keys","destroyPromises","infos","healthPromises","health","healthyCount","r","report","maxIdleTime","now","servicesToDestroy","lastAccessTime","eventType","globalHandlers","BaseAdapter","paramIndex","UniversalSQLite","tableNames","forceRecreate","migrationManager","roles","connections","healthStatus","args","createUniversalDAO","createDatabaseFromSchema","openExistingDatabase","createQueryBuilder","createBaseService","createMigrationManager","createCSVImporter","setupUniversalSQLite","sqlite","createSingleDatabase","defaultInstance"],"mappings":"gQAkBaA,CAAY,CAQvB,YACUC,EACAC,EACAC,EAGP,SALO,KAAA,QAAAF,EACA,KAAA,OAAAC,EACA,KAAA,QAAAC,EAVF,KAAA,WAAsC,KACtC,KAAA,YAAuB,GACvB,KAAA,cAAyB,GACzB,KAAA,kBAA8D,KAC9D,KAAA,kBAA6B,GAC7B,KAAA,cAAyB,GAU/B,KAAK,mBAAoBC,EAAAD,GAAO,KAAA,OAAPA,EAAS,qBAAiB,MAAAC,IAAA,OAAAA,EAAI,GACvD,KAAK,eAAgBC,EAAAF,GAAO,KAAA,OAAPA,EAAS,iBAAa,MAAAE,IAAA,OAAAA,EAAI,EACjD,CAEA,MAAM,SAAO,CACP,KAAK,cAIT,KAAK,WAAa,MAAM,KAAK,QAAQ,QAAQ,KAAK,MAAM,EACxD,KAAK,YAAc,GACrB,CAEA,MAAM,YAAU,CACV,KAAK,YAAc,KAAK,cAC1B,MAAM,KAAK,WAAW,MAAA,EACtB,KAAK,WAAa,KAClB,KAAK,YAAc,GAEvB,CAEA,MAAM,OAAK,CACT,MAAM,KAAK,WAAA,CACb,CAGA,qBAAqBC,EAAyC,CAC5D,KAAK,kBAAoBA,CAC3B,CAEQ,oBAAoBC,EAAmB,CAC7C,MAAI,CAAC,KAAK,mBAAqB,CAAC,KAAK,kBAAkB,OAC9C,KAAK,qBAAqBA,CAAW,EAGxB,KAAK,kBAAkB,OACxBA,EAAY,aAAa,GAAK,MACrD,CAEQ,qBAAqBA,EAAmB,CA0B9C,MAzB+C,CAC7C,OAAQ,OACR,QAAS,OACT,KAAM,OACN,MAAO,OACP,IAAK,OACL,KAAM,OACN,QAAS,UACT,OAAQ,UACR,SAAU,UACV,QAAS,UACT,QAAS,OACT,QAAS,OACT,MAAO,OACP,OAAQ,OACR,QAAS,UACT,UAAW,OACX,SAAU,OACV,KAAM,OACN,KAAM,OACN,KAAM,OACN,MAAO,OACP,KAAM,OACN,OAAQ,QAEYA,EAAY,aAAa,GAAK,MACtD,CAEQ,wBAAwBC,EAAqB,CACnD,MAAMC,EAAY,OAAA,OAAA,CAAA,EAA0BD,CAAG,EAC/CC,EAAa,KAAO,KAAK,oBAAoBD,EAAI,IAAI,EAErD,MAAML,EAAoB,CAAA,EAC1B,GAAIK,EAAI,YAAa,CACnB,MAAME,EAAcF,EAAI,YAAY,YAAA,EAAc,MAAM,GAAG,EACvDE,EAAY,SAAS,SAAS,IAChCP,EAAQ,KAAK,aAAa,EAC1BM,EAAa,YAAc,KAG3BC,EAAY,SAAS,gBAAgB,GACrCA,EAAY,SAAS,eAAe,KAEhCD,EAAa,aAAaN,EAAQ,KAAK,eAAe,EAC1DM,EAAa,eAAiB,IAE5BC,EAAY,SAAS,KAAK,GAAKA,EAAY,SAAS,MAAM,IAC5DP,EAAQ,KAAK,UAAU,EACvBM,EAAa,SAAW,IAEtBC,EAAY,SAAS,QAAQ,IAC1BD,EAAa,aAAaN,EAAQ,KAAK,QAAQ,EACpDM,EAAa,OAAS,IAGxB,MAAME,EAAeD,EAAY,QAAQ,SAAS,EAClD,GAAIC,IAAiB,IAAMD,EAAY,OAASC,EAAe,EAAG,CAChE,MAAMC,EAAeF,EAAYC,EAAe,CAAC,EACjDR,EAAQ,KAAK,WAAWS,CAAY,EAAE,EACtCH,EAAa,QAAUG,CACzB,CACF,CAEA,OAAAH,EAAa,WAAaN,EAAQ,KAAK,GAAG,EAAE,OACrCM,CACT,CAGA,MAAM,qBAAqBI,EAAsB,OAC/C,KAAK,kBAGL,IAAIC,EAAoB,GACxB,GAAI,CAIFA,GAHe,MAAM,KAAK,QACxB,mEAAmE,GAE1C,KAAK,OAAS,CAC3C,OAASC,EAAO,CACdD,EAAoB,EACtB,CAGA,GAAIA,GAAqB,CAAC,KAAK,mBAAqB,CAAC,KAAK,cAAe,CACnED,EAAO,cACT,KAAK,qBAAqBA,EAAO,YAAY,EAE/C,MACF,CAEIC,GAAqB,KAAK,eAC5B,MAAM,KAAK,gBAGTD,EAAO,cACT,KAAK,qBAAqBA,EAAO,YAAY,EAG/C,GAAI,CACF,MAAM,KAAK,QAAQ,0BAA0B,CAC/C,OAAER,EAAM,CAAC,CAET,MAAM,KAAK,iBAAA,EAEX,GAAI,CACF,SAAW,CAACW,EAAWC,CAAW,IAAK,OAAO,QAAQJ,EAAO,OAAO,EAAG,CACrE,MAAMK,EAAmC,CACvC,KAAMF,EACN,KAAMC,EAAY,KAAK,IAAKT,GAC1B,KAAK,wBAAwBA,CAAG,CAAC,EAEnC,YAAaS,EAAY,YACzB,QAASA,EAAY,QACrB,aAAcA,EAAY,cAE5B,MAAM,KAAK,2BAA2BC,CAAe,CACvD,CAEA,SAAW,CAACF,EAAWC,CAAW,IAAK,OAAO,QAAQJ,EAAO,OAAO,OAC9DI,EAAY,WAAO,MAAAb,IAAA,SAAAA,EAAE,QACvB,MAAM,KAAK,sBAAsBY,EAAWC,EAAY,OAAO,EAInE,MAAM,KAAK,iBAAiBJ,EAAO,OAAO,EAC1C,MAAM,KAAK,kBAAA,CACb,OAASE,EAAO,CACd,YAAM,KAAK,sBACLA,CACR,CACF,CAEQ,MAAM,eAAa,CACzB,MAAMI,EAAS,MAAM,KAAK,QACxB,gFAAgF,EAGlF,MAAM,KAAK,iBAAA,EAEX,GAAI,CACF,UAAWC,KAASD,EAAO,KACzB,MAAM,KAAK,QAAQ,wBAAwBC,EAAM,IAAI,EAAE,EAEzD,MAAM,KAAK,kBAAA,CACb,OAASL,EAAO,CACd,YAAM,KAAK,sBACLA,CACR,CACF,CAEQ,MAAM,2BACZK,EAAsB,CAEtB,MAAMC,EAAaD,EAAM,KAAK,IAAKZ,GACjC,GAAGA,EAAI,IAAI,IAAIA,EAAI,IAAI,IAAIA,EAAI,YAAc,EAAE,GAAG,KAAA,CAAM,EAGpDc,EAA2B,CAAA,EACjC,GAAIF,EAAM,aACR,UAAWG,KAAMH,EAAM,aAAc,CACnC,IAAII,EAAQ,gBAAgBD,EAAG,MAAM,gBAAgBA,EAAG,WAAW,KAAK,IAAIA,EAAG,WAAW,MAAM,IAC5FA,EAAG,YAAWC,GAAS,cAAcD,EAAG,SAAS,IACjDA,EAAG,YAAWC,GAAS,cAAcD,EAAG,SAAS,IACrDD,EAAe,KAAKE,CAAK,CAC3B,CAGF,MAAMC,EAAU,CAAC,GAAGJ,EAAY,GAAGC,CAAc,EAC3CI,EAAM,8BAA8BN,EAAM,IAAI,KAAKK,EAAQ,KAC/D,IAAI,CACL,IACD,MAAM,KAAK,QAAQC,CAAG,CACxB,CAEQ,MAAM,sBACZV,EACAW,EAA0B,CAE1B,UAAWC,KAASD,EAAS,CAC3B,MAAME,EAAUD,EAAM,QAAQ,KAAK,IAAI,EAEjCF,EAAM,UADKE,EAAM,OACU,SAAW,EAAE,wBAC5CA,EAAM,IACR,OAAOZ,CAAS,KAAKa,CAAO,IAC5B,MAAM,KAAK,QAAQH,CAAG,CACxB,CACF,CAGA,MAAM,kBAAgB,CACpB,GAAI,KAAK,cACP,MAAM,IAAI,MAAM,iCAAiC,EAEnD,MAAM,KAAK,QAAQ,mBAAmB,EACtC,KAAK,cAAgB,EACvB,CAEA,MAAM,mBAAiB,CACrB,GAAI,CAAC,KAAK,cACR,MAAM,IAAI,MAAM,4BAA4B,EAE9C,MAAM,KAAK,QAAQ,QAAQ,EAC3B,KAAK,cAAgB,EACvB,CAEA,MAAM,qBAAmB,CACvB,GAAI,CAAC,KAAK,cACR,MAAM,IAAI,MAAM,4BAA4B,EAE9C,MAAM,KAAK,QAAQ,UAAU,EAC7B,KAAK,cAAgB,EACvB,CAGA,MAAM,kBAAgB,CACpB,GAAI,CAIF,OAHe,MAAM,KAAK,OACxB,mEAAmE,GAEvD,SAAW,GAC3B,OAAEtB,EAAM,CACN,MAAO,GACT,CACF,CAEA,MAAM,iBAAiB0B,EAAe,CACpC,MAAM,KAAK,QAAQ;AAAA;AAAA;AAAA,MAGjB,EACF,MAAM,KAAK,QAAQ,gDAAiD,CAClEA,CACD,CAAA,CACH,CAGA,MAAM,OAAOC,EAAuB,CAClC,MAAMC,EAAYD,EAAY,KAAK,OAChCvB,GAAQA,EAAI,QAAU,QAAaA,EAAI,QAAU,IAAI,EAExD,GAAIwB,EAAU,SAAW,EACvB,MAAM,IAAI,MAAM,4BAA4B,EAG9C,MAAMC,EAAcD,EAAU,IAAKxB,GAAQA,EAAI,IAAI,EAAE,KAAK,IAAI,EACxD0B,EAAeF,EAAU,IAAI,IAAM,GAAG,EAAE,KAAK,IAAI,EACjDG,EAASH,EAAU,IAAKxB,GAC5B,OAAOA,EAAI,OAAU,SAAW,KAAK,UAAUA,EAAI,KAAK,EAAIA,EAAI,KAAK,EAGjEkB,EAAM,eAAeK,EAAY,IAAI,KAAKE,CAAW,aAAaC,CAAY,IACpF,OAAO,MAAM,KAAK,QAAQR,EAAKS,CAAM,CACvC,CAEA,MAAM,OAAOC,EAAuB,CAClC,MAAMC,EAAUD,EAAY,KAAK,OAC9B5B,GAAO,OACN,OAAAA,EAAI,QAAU,QACd,OAAC4B,EAAY,UAAM,MAAAhC,IAAA,SAAAA,EAAE,KAAMkC,GAAMA,EAAE,OAAS9B,EAAI,IAAI,EAAC,CAAA,EAGzD,GAAI6B,EAAQ,SAAW,EACrB,MAAM,IAAI,MAAM,sBAAsB,EAGxC,MAAME,EAAYF,EAAQ,IAAK7B,GAAQ,GAAGA,EAAI,IAAI,MAAM,EAAE,KAAK,IAAI,EAC7D2B,EAASE,EAAQ,IAAK7B,GAC1B,OAAOA,EAAI,OAAU,SAAW,KAAK,UAAUA,EAAI,KAAK,EAAIA,EAAI,KAAK,EAGvE,IAAIkB,EAAM,UAAUU,EAAY,IAAI,QAAQG,CAAS,GACrD,MAAMC,EAAc,KAAK,iBAAiBJ,EAAY,MAAM,EAE5D,GAAI,CAACI,EAAY,IACf,MAAM,IAAI,MAAM,+CAA+C,EAGjE,OAAAd,GAAOc,EAAY,IACnBL,EAAO,KAAK,GAAGK,EAAY,MAAM,EAE1B,MAAM,KAAK,QAAQd,EAAKS,CAAM,CACvC,CAEA,MAAM,OAAOM,EAAuB,CAClC,IAAIf,EAAM,eAAee,EAAY,IAAI,GACzC,MAAMD,EAAc,KAAK,iBAAiBC,EAAY,MAAM,EAE5D,GAAI,CAACD,EAAY,IACf,MAAM,IAAI,MAAM,+CAA+C,EAGjE,OAAAd,GAAOc,EAAY,IACZ,MAAM,KAAK,QAAQd,EAAKc,EAAY,MAAM,CACnD,CAEA,MAAM,OAAOE,EAAuB,CAClC,KAAM,CAAE,IAAAhB,EAAK,OAAAS,GAAW,KAAK,iBAAiBO,EAAa,UAAU,EAErE,OADe,MAAM,KAAK,QAAQhB,EAAKS,CAAM,GAC/B,KAAK,CAAC,GAAK,CAAA,CAC3B,CAEA,MAAM,UAAUO,EAAuB,CACrC,KAAM,CAAE,IAAAhB,EAAK,OAAAS,CAAM,EAAK,KAAK,iBAAiBO,CAAW,EAEzD,OADe,MAAM,KAAK,QAAQhB,EAAKS,CAAM,GAC/B,IAChB,CAGQ,iBACNO,EACAC,EAAiB,GAAE,OAOnB,IAAIjB,EAAM,UAJRgB,EAAY,KAAK,OAAS,EACtBA,EAAY,KAAK,IAAKlC,GAAQA,EAAI,IAAI,EAAE,KAAK,IAAI,EACjD,GAEqB,SAASkC,EAAY,IAAI,GACpD,MAAMF,EAAc,KAAK,iBAAiBE,EAAY,MAAM,EAG5D,GAFAhB,GAAOc,EAAY,SAEfE,EAAY,YAAQ,MAAAtC,IAAA,SAAAA,EAAE,OAAQ,CAChC,MAAMwC,EAAUF,EAAY,SACzB,IAAKG,GAAM,GAAGA,EAAE,IAAI,IAAIA,EAAE,WAAa,KAAK,EAAE,EAC9C,KAAK,IAAI,EACZnB,GAAO,aAAakB,CAAO,EAC7B,CAEA,OAAIF,EAAY,cACVA,EAAY,YAAY,QAC1BhB,GAAO,UAAUgB,EAAY,YAAY,KAAK,IAC5CA,EAAY,YAAY,SAC1BhB,GAAO,WAAWgB,EAAY,YAAY,MAAM,KAGpDhB,GAAOiB,EACA,CAAE,IAAAjB,EAAK,OAAQc,EAAY,MAAM,CAC1C,CAEQ,iBACNM,EACAC,EAAiB,QAAO,CAExB,GAAI,CAACD,GAAUA,EAAO,SAAW,EAC/B,MAAO,CAAE,IAAK,GAAI,OAAQ,CAAA,CAAE,EAG9B,MAAME,EAAuB,CAAA,EACvBb,EAAgB,CAAA,EAEtB,UAAWc,KAASH,EAAQ,CAC1B,MAAMI,EAAWD,EAAM,UAAY,IACnCD,EAAW,KAAK,GAAGC,EAAM,IAAI,IAAIC,CAAQ,IAAI,EAC7Cf,EAAO,KAAKc,EAAM,KAAK,CACzB,CAEA,MAAO,CAAE,IAAK,IAAIF,CAAM,IAAIC,EAAW,KAAK,OAAO,CAAC,GAAI,OAAAb,EAC1D,CAEA,wBACEnB,EACAmC,EACAC,EAAqB,CAAC,IAAI,EAAC,OAE3B,MAAMC,EAAyB,CAAE,KAAMrC,EAAW,KAAM,GAAI,OAAQ,CAAA,GAEpE,SAAW,CAACsC,EAAKC,CAAK,IAAK,OAAO,QAAQJ,CAAI,EAC5CE,EAAW,KAAK,KAAK,CAAE,KAAMC,EAAK,MAAAC,CAAK,CAAE,EACrCH,EAAS,SAASE,CAAG,GAAKC,IAAU,UACtCnD,EAAAiD,EAAW,UAAM,MAAAjD,IAAA,QAAAA,EAAE,KAAK,CAAE,KAAMkD,EAAK,MAAAC,CAAK,CAAE,GAIhD,OAAOF,CACT,CAGA,MAAM,WAAWlD,EAAsB,CACrC,MAAMqD,EAAY,KAAK,IAAA,EACjBC,EAAuB,CAC3B,UAAWtD,EAAQ,KAAK,OACxB,YAAa,EACb,UAAW,EACX,OAAQ,GACR,cAAe,GAGjB,GAAI,CAAC,KAAK,YACR,MAAM,IAAI,MAAM,2BAA2B,EAG7C,GAAI,CAACA,EAAQ,MAAQA,EAAQ,KAAK,SAAW,EAC3C,OAAAsD,EAAO,cAAgB,KAAK,IAAA,EAAQD,EAC7BC,EAGT,MAAMC,EAAY,MAAM,KAAK,aAAavD,EAAQ,SAAS,EAC3D,GAAIuD,EAAU,SAAW,EACvB,MAAM,IAAI,MAAM,UAAUvD,EAAQ,SAAS,kBAAkB,EAG/D,MAAMwD,EAAY,IAAI,IACpBD,EAAU,IAAKlD,GAAQ,CAACA,EAAI,KAAK,cAAeA,CAAG,CAAC,CAAC,EAEjDoD,EAAYzD,EAAQ,WAAa,IACvC,IAAI0D,EAAiB,EACrB,MAAMC,EAAsB,CAAC3D,EAAQ,uBAErC,GAAI,CACF,MAAM,KAAK,iBAAA,EAEX,QAAS4D,EAAI,EAAGA,EAAI5D,EAAQ,KAAK,OAAQ4D,GAAKH,EAAW,CACvD,MAAMI,EAAQ7D,EAAQ,KAAK,MAAM4D,EAAGA,EAAIH,CAAS,EAEjD,QAASK,EAAI,EAAGA,EAAID,EAAM,OAAQC,IAAK,CACrC,MAAMC,EAAWH,EAAIE,EACfE,EAAUH,EAAMC,CAAC,EAEvB,GAAI,CACF,MAAMG,EAAgBjE,EAAQ,aAC1B,KAAK,wBACHgE,EACAR,EACAxD,EAAQ,UACR2D,CAAmB,EAErB,KAAK,iBAAiBK,EAASR,EAAWG,CAAmB,EAE7D3D,EAAQ,kBAAoBA,EAAQ,gBACtC,MAAM,KAAK,eACTA,EAAQ,UACRiE,EACAjE,EAAQ,eAAe,EAGzB,MAAM,KAAK,UAAUA,EAAQ,UAAWiE,CAAa,EAGvDX,EAAO,aACT,OAAS1C,EAAO,CACd0C,EAAO,YACP,MAAMY,EAAY,CAChB,SAAAH,EACA,MAAOnD,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,EAC5D,QAAAoD,GAYF,GAVAV,EAAO,OAAO,KAAKY,CAAS,EAExBlE,EAAQ,SACVA,EAAQ,QACNY,aAAiB,MAAQA,EAAQ,IAAI,MAAM,OAAOA,CAAK,CAAC,EACxDmD,EACAC,CAAO,EAIP,CAAChE,EAAQ,WACX,MAAMY,CAEV,CAEA8C,IACI1D,EAAQ,YAAc0D,EAAiB,MAAQ,GACjD1D,EAAQ,WAAW0D,EAAgB1D,EAAQ,KAAK,MAAM,CAE1D,CACF,CAEA,MAAM,KAAK,kBAAA,CACb,OAASY,EAAO,CACd,MAAA,MAAM,KAAK,sBACLA,CACR,CAEA,OAAIZ,EAAQ,YACVA,EAAQ,WAAW0D,EAAgB1D,EAAQ,KAAK,MAAM,EAGxDsD,EAAO,cAAgB,KAAK,IAAA,EAAQD,EAC7BC,CACT,CAGA,MAAM,sBACJzC,EACAsD,EACAC,EACApE,EAAkC,CAAA,EAAE,CAEpC,MAAMqE,EAAkBF,EAAK,IAAKG,GAAO,CACvC,MAAMC,EAA8B,CAAA,EAEpC,OAAAH,EAAe,QAASI,GAAW,CACjC,GAAIF,EAAI,eAAeE,EAAQ,YAAY,EAAG,CAC5C,IAAIpB,EAAQkB,EAAIE,EAAQ,YAAY,EAEhCA,EAAQ,YACVpB,EAAQoB,EAAQ,UAAUpB,CAAK,GAGjCmB,EAAOC,EAAQ,YAAY,EAAIpB,CACjC,CACF,CAAC,EAEMmB,CACT,CAAC,EAED,OAAO,MAAM,KAAK,WAAU,OAAA,OAAA,CAC1B,UAAA1D,EACA,KAAMwD,CAAe,EAClBrE,CAAO,EAEd,CAGA,MAAM,cACJa,EACA4D,EACAzE,EAI6B,GAAE,CAE/B,MAAM0E,EAAY1E,EAAQ,WAAa,IACjC2E,EAAY3E,EAAQ,YAAc,GAElC4E,EAAQH,EAAQ,MAAM;AAAA,CAAI,EAAE,OAAQI,GAASA,EAAK,MAAM,EAC9D,GAAID,EAAM,SAAW,EACnB,MAAM,IAAI,MAAM,mBAAmB,EAGrC,IAAIE,EAAoB,CAAA,EACpBC,EAAiB,EAErB,GAAIJ,EACFG,EAAUF,EAAM,CAAC,EACd,MAAMF,CAAS,EACf,IAAKM,GAAMA,EAAE,OAAO,QAAQ,eAAgB,EAAE,CAAC,EAClDD,EAAiB,MACZ,CACL,MAAME,EAAeL,EAAM,CAAC,EAAE,MAAMF,CAAS,EAAE,OAC/CI,EAAU,MAAM,KACd,CAAE,OAAQG,CAAY,EACtB,CAACC,EAAGtB,IAAM,UAAUA,EAAI,CAAC,EAAE,CAE/B,CAEA,MAAMO,EAA8B,CAAA,EACpC,QAASP,EAAImB,EAAgBnB,EAAIgB,EAAM,OAAQhB,IAAK,CAClD,MAAMuB,EAASP,EAAMhB,CAAC,EACnB,MAAMc,CAAS,EACf,IAAKU,GAAMA,EAAE,OAAO,QAAQ,eAAgB,EAAE,CAAC,EAC5Cd,EAA2B,CAAA,EAEjCQ,EAAQ,QAAQ,CAACO,EAAQ5D,IAAS,CAChC6C,EAAIe,CAAM,EAAIF,EAAO1D,CAAK,GAAK,IACjC,CAAC,EAED0C,EAAK,KAAKG,CAAG,CACf,CAEA,OAAItE,EAAQ,eACH,MAAM,KAAK,sBAChBa,EACAsD,EACAnE,EAAQ,eACRA,CAAO,EAGF,MAAM,KAAK,0BAChB,UAAAa,EACA,KAAAsD,CAAI,EACDnE,CAAO,CAAA,CAGhB,CAEQ,wBACNgE,EACAR,EACA3C,EACA8C,EAA+B,GAAI,CAEnC,MAAM2B,EAAoC,CAAA,EAE1C,SAAW,CAACC,EAAYC,CAAU,IAAKhC,EAAU,UAAW,CAC1D,MAAMiC,EAAaD,EAAW,UAAY,GAAK,CAACA,EAAW,WAErDE,EADeF,EAAW,KAAO,GAErBA,EAAW,KAAK,YAAA,EAAc,SAAS,SAAS,EAElE,GAAI7B,GAAuB+B,EACzB,SAGF,MAAMtC,EAAQ,KAAK,mBAAmBY,EAASuB,CAAU,EAEzD,GAAIE,GAAerC,GAAU,KAC3B,MAAM,IAAI,MACR,oBAAoBmC,CAAU,kCAAkC1E,CAAS,GAAG,EAI5EuC,GAAU,OACZkC,EAAaC,CAAU,EAAI,KAAK,yBAC9BnC,EACAoC,EAAW,IAAI,EAGrB,CAEA,OAAOF,CACT,CAEQ,iBACNtB,EACAR,EACAG,EAA+B,GAAI,CAEnC,MAAM2B,EAAoC,CAAA,EAE1C,SAAW,CAACnC,EAAKC,CAAK,IAAK,OAAO,QAAQY,CAAO,EAAG,CAClD,MAAMuB,EAAapC,EAAI,YAAA,EACjBqC,EAAahC,EAAU,IAAI+B,CAAU,EAE3C,GAAI,CAACC,EACH,SAIF,MAAME,EADeF,EAAW,KAAO,GAErBA,EAAW,KAAK,cAAc,SAAS,SAAS,EAE9D7B,GAAuB+B,GAIvBtC,GAAU,OACZkC,EAAanC,CAAG,EAAI,KAAK,yBACvBC,EACAoC,EAAW,IAAI,EAGrB,CAEA,OAAOF,CACT,CAEQ,mBACNtB,EACAuB,EAAkB,CAElB,GAAIvB,EAAQ,eAAeuB,CAAU,EACnC,OAAOvB,EAAQuB,CAAU,EAG3B,MAAMI,EAAkBJ,EAAW,YAAA,EACnC,SAAW,CAACpC,EAAKC,CAAK,IAAK,OAAO,QAAQY,CAAO,EAC/C,GAAIb,EAAI,YAAA,IAAkBwC,EACxB,OAAOvC,CAKb,CAEQ,yBAAyBA,EAAYwC,EAAkB,CAC7D,GAAIxC,GAAU,KACZ,OAAO,KAGT,MAAMyC,EAAOD,EAAW,YAAA,EAExB,GAAI,CACF,GAAIC,EAAK,SAAS,SAAS,GAAKA,EAAK,SAAS,KAAK,EAAG,CACpD,GAAI,OAAOzC,GAAU,UACnB,OAAOA,EAAQ,EAAI,EAErB,MAAM0C,EAAM,SAAS,OAAO1C,CAAK,CAAC,EAClC,OAAO,MAAM0C,CAAG,EAAI,KAAOA,CAC7B,CAEA,GACED,EAAK,SAAS,MAAM,GACpBA,EAAK,SAAS,OAAO,GACrBA,EAAK,SAAS,SAAS,EACvB,CACA,MAAMC,EAAM,WAAW,OAAO1C,CAAK,CAAC,EACpC,OAAO,MAAM0C,CAAG,EAAI,KAAOA,CAC7B,CAEA,GAAID,EAAK,SAAS,SAAS,EAAG,CAC5B,GAAI,OAAOzC,GAAU,UACnB,OAAOA,EAAQ,EAAI,EAErB,GAAI,OAAOA,GAAU,SAAU,CAC7B,MAAM2C,EAAQ3C,EAAM,YAAA,EACpB,OAAO2C,IAAU,QAAUA,IAAU,KAAOA,IAAU,MAAQ,EAAI,CACpE,CACA,OAAO3C,EAAQ,EAAI,CACrB,CAEA,GAAIyC,EAAK,SAAS,MAAM,EAAG,CACzB,GAAI,OAAOzC,GAAU,SACnB,OAAO,KAAK,UAAUA,CAAK,EAE7B,GAAI,OAAOA,GAAU,SACnB,GAAI,CACF,YAAK,MAAMA,CAAK,EACTA,CACT,OAAEnD,EAAM,CACN,MAAM,IAAI,MACR,wCAAwC2F,CAAU,GAAG,CAEzD,CAEF,OAAO,KAAK,UAAUxC,CAAK,CAC7B,CAEA,GAAIyC,EAAK,SAAS,WAAW,GAAKA,EAAK,SAAS,UAAU,EAAG,CAC3D,GAAIzC,aAAiB,KACnB,OAAOA,EAAM,YAAA,EAEf,GAAI,OAAOA,GAAU,UAAY,OAAOA,GAAU,SAAU,CAC1D,MAAM4C,EAAO,IAAI,KAAK5C,CAAK,EAC3B,OAAO,MAAM4C,EAAK,SAAS,EAAI5C,EAAQ4C,EAAK,aAC9C,CACA,OAAO,OAAO5C,CAAK,CACrB,CAEA,OAAO,OAAOA,CAAK,CACrB,OAASxC,EAAO,CACd,MAAM,IAAI,MACR,yBAAyBwC,CAAK,qBAAqBwC,CAAU,GAAG,CAEpE,CACF,CAEQ,MAAM,UACZ/E,EACAsD,EAAyB,CAEzB,MAAMzC,EAAU,OAAO,KAAKyC,CAAI,EAC1BgB,EAAS,OAAO,OAAOhB,CAAI,EAC3BpC,EAAeL,EAAQ,IAAI,IAAM,GAAG,EAAE,KAAK,IAAI,EAE/CH,EAAM,eAAeV,CAAS,KAAKa,EAAQ,KAC/C,IAAI,CACL,aAAaK,CAAY,IAC1B,MAAM,KAAK,QAAQR,EAAK4D,CAAM,CAChC,CAEQ,MAAM,eACZtE,EACAsD,EACA8B,EAAyB,CAEzB,GAAI,CACF,MAAM,KAAK,UAAUpF,EAAWsD,CAAI,CACtC,OAASvD,EAAO,CACd,GAAI,KAAK,gBAAgBA,CAAK,EAC5B,MAAM,KAAK,mBAAmBC,EAAWsD,EAAM8B,CAAe,MAE9D,OAAMrF,CAEV,CACF,CAEQ,MAAM,mBACZC,EACAsD,EACA8B,EAAyB,CAGzB,MAAMC,EADa,OAAO,KAAK/B,CAAI,EACF,OAC9B9D,GAAQ,CAAC4F,EAAgB,SAAS5F,CAAG,CAAC,EAEnC8F,EAAeF,EAErB,GAAIC,EAAc,SAAW,EAC3B,OAGF,MAAM9D,EAAY8D,EAAc,IAAK7F,GAAQ,GAAGA,CAAG,MAAM,EAAE,KAAK,IAAI,EAC9DgC,EAAc8D,EAAa,IAAK9F,GAAQ,GAAGA,CAAG,MAAM,EAAE,KAAK,OAAO,EAElE+F,EAAeF,EAAc,IAAK7F,GAAQ8D,EAAK9D,CAAG,CAAC,EACnDgG,EAAcF,EAAa,IAAK9F,GAAQ8D,EAAK9D,CAAG,CAAC,EACjDiG,EAAY,CAAC,GAAGF,EAAc,GAAGC,CAAW,EAE5C9E,EAAM,UAAUV,CAAS,QAAQuB,CAAS,UAAUC,CAAW,GACrE,MAAM,KAAK,QAAQd,EAAK+E,CAAS,CACnC,CAEQ,gBAAgB1F,EAAU,CAChC,OACEA,EAAM,OAAS,4BACfA,EAAM,OAAS,gCACdA,EAAM,SAAWA,EAAM,QAAQ,SAAS,0BAA0B,CAEvE,CAGA,MAAM,iBAAe,CACnB,MAAMI,EAAS,MAAM,KAAK,QACxB,mDAAmD,EAE/CW,EAAU,MAAM,KAAK,iBAAA,EAE3B,MAAO,CACL,KAAM,KAAK,OACX,OAAQX,EAAO,KAAK,IAAKuF,GAAMA,EAAE,IAAI,EACrC,YAAa,KAAK,YAClB,QAAA5E,EAEJ,CAEA,MAAM,aAAad,EAAiB,CAElC,OADe,MAAM,KAAK,QAAQ,qBAAqBA,CAAS,GAAG,GACrD,IAChB,CAEA,MAAM,UAAUA,EAAiB,CAC/B,MAAMU,EAAM,wBAAwBV,CAAS,GAC7C,MAAM,KAAK,QAAQU,CAAG,CACxB,CAGA,kBAAgB,CACd,OAAO,KAAK,aAAe,CAAC,CAAC,KAAK,UACpC,CAEA,MAAM,iBAAe,CACd,KAAK,oBACR,MAAM,KAAK,QAAA,CAEf,CAEA,MAAM,QAAQA,EAAaS,EAAgB,GAAE,CAC3C,OAAA,KAAK,gBAAA,EACE,MAAM,KAAK,WAAY,QAAQT,EAAKS,CAAM,CACnD,CAEA,MAAM,OAAOT,EAAaS,EAAgB,GAAE,CAE1C,OADe,MAAM,KAAK,QAAQT,EAAKS,CAAM,GAC/B,KAAK,CAAC,GAAK,CAAA,CAC3B,CAEA,MAAM,QAAQT,EAAaS,EAAgB,CAAA,EAAE,CAE3C,OADe,MAAM,KAAK,QAAQT,EAAKS,CAAM,GAC/B,IAChB,CACD,OCr5BYwE,CAAe,CAO1B,OAAO,gBAAgB1G,EAAsB,CAC3C,KAAK,SAAS,KAAKA,CAAO,CAC5B,CAMA,OAAO,oBAAkB,CACvB,OACE,OAAO,WAAc,aACrB,UAAU,UAAY,cAEf,eAEL,OAAO,WAAW,KAAQ,YAAoB,MAC9C,OAAO,WAAW,MAAS,YAAoB,OAC/C,OAAO,QAAW,YAAoB,UACtC,OAAO,SAAY,YAAoB,UACpC,SACT,CAOQ,OAAO,mBAAiB,CAC9B,UAAWA,KAAW,KAAK,SACzB,GAAIA,EAAQ,cACV,OAAOA,EAGX,MAAM,IAAI,MAAM,mCAAmC,CACrD,CAOQ,aAAa,sBACnB2G,EACA/F,EAAsB,CAEtB,GAAI,CACF,MAAMgG,EAAS,MAAMD,EAAI,gBAAA,EACzB,GAAIC,EAAO,UAAYhG,EAAO,QAC5B,MAAM,IAAI,MACR,sCAAsCgG,EAAO,OAAO,gBAAgBhG,EAAO,OAAO,GAAG,CAG3F,OAASE,EAAO,CACd,MAAM,IAAI,MACR,uCAAuCF,EAAO,aAAa,KACxDE,EAAgB,OACnB,EAAE,CAEN,CACF,CAOQ,OAAO,eAAeF,EAAW,CACvC,GAAI,CAACA,EACH,MAAM,IAAI,MAAM,4CAA4C,EAE9D,GACE,OAAOA,EAAO,eAAkB,UAChCA,EAAO,cAAc,SAAW,GAEhC,MAAM,IAAI,MACR,2FAA2F,EAG/F,GACE,OAAOA,EAAO,SAAY,UAC1BA,EAAO,UAAY,MACnB,OAAO,KAAKA,EAAO,OAAO,EAAE,SAAW,EAEvC,MAAM,IAAI,MACR,2FAA2F,EAG/F,MAAO,EACT,CAQA,OAAO,UACLX,EACAC,EAIC,SAED,IAAIF,EAEJ,OAAIE,SAAAA,EAAS,QACXF,EAAUE,EAAQ,QAElBF,EAAU,KAAK,oBAGV,IAAID,EAAaC,EAASC,EAAQ,CACvC,mBAAmBE,EAAAD,GAAO,YAAPA,EAAS,qBAAiB,MAAAC,IAAA,OAAAA,EAAI,GACjD,eAAeC,EAAAF,GAAO,YAAPA,EAAS,iBAAa,MAAAE,IAAA,OAAAA,EAAI,EAC1C,CAAA,CACH,CASO,aAAa,aAClByG,EACA3G,EAGI,CAAA,EAAE,CAGN,MAAM4G,EAAaD,EAAO,SAAS,KAAK,EAAIA,EAAS,GAAGA,CAAM,MAGxDF,EAAM,KAAK,UAAUG,EAAY5G,CAAO,EAE9C,GAAI,CACF,OAAA,MAAMyG,EAAI,UAEV,MAAMA,EAAI,QAAQ,wBAAwB,EACnCA,CACT,OAAS7F,EAAO,CACd,MAAA,MAAM6F,EAAI,MAAA,EACJ,IAAI,MACR,2BAA2BG,CAAU,MAAOhG,EAAgB,OAAO,EAAE,CAEzE,CACF,CASQ,aAAa,qBACnBZ,EACA6G,EAAuB,GACvBC,EAAyB,GAAK,CAE9B,IAAIpG,EAGJ,GAAIV,EAAQ,OACVU,EAASV,EAAQ,eACRA,EAAQ,YACjBU,EAASV,EAAQ,gBAEjB,OAAM,IAAI,MACR,kFAAkF,EAKtF,KAAK,eAAeU,CAAM,EAG1B,MAAMkG,EAAalG,EAAO,cAAc,SAAS,KAAK,EAClDA,EAAO,cACP,GAAGA,EAAO,aAAa,MAGrB+F,EAAM,KAAK,UAAUG,EAAY,CACrC,QAAS5G,EAAQ,QACjB,kBAAmB6G,EACnB,cAAeC,CAChB,CAAA,EAED,GAAI,CAEF,MAAML,EAAI,UAGV,MAAMA,EAAI,qBAAqB/F,CAAM,EAIrC,GAAI,CACF,MAAM,KAAK,sBAAsB+F,EAAK/F,CAAM,CAC9C,OAASqG,EAAkB,CACzB,MAAA,MAAMN,EAAI,MAAA,EACJ,IAAI,MACR,wGAAwGM,EAAY,OAAO,EAAE,CAEjI,CACA,OAAON,CACT,OAAS7F,EAAO,CACd,MAAI6F,EAAI,iBAAA,GACN,MAAMA,EAAI,MAAA,EAEN7F,CACR,CACF,CAQO,aAAa,OAAOZ,EAAyB,CAClD,OAAO,KAAK,qBAAqBA,EAAS,GAAM,EAAI,CACtD,CAUO,aAAa,aAClBA,EACA6G,EAAuB,GAAK,CAE5B,OAAO,KAAK,qBAAqB7G,EAAS6G,CAAW,CACvD,CAQO,aAAa,gBAClBG,EACAhH,EAGI,CAAA,EAAE,CAEN,GAAI,CACF,OAAO,MAAM,KAAK,sCACbA,CAAO,EAAA,CACV,YAAAgH,CAAW,CAAA,CAAA,CAEf,OAASpG,EAAO,CACd,MAAM,IAAI,MACR,uCAAwCA,EAAgB,OAAO,EAAE,CAErE,CACF,CAQO,aAAa,iBAClBT,EACAH,EAGI,CAAA,EAAE,CAEN,GAAI,CACF,OAAO,MAAM,KAAK,sCACbA,CAAO,EAAA,CACV,OAAAG,CAAM,CAAA,CAAA,CAEV,OAASS,EAAO,CACd,MAAM,IAAI,MACR,wCAAyCA,EAAgB,OAAO,EAAE,CAEtE,CACF,EAxSe4F,EAAA,SAA4B,CAAA,QCiChCS,CAAe,CAoBnB,OAAO,mBAAiB,CAC7B,OAAO,KAAK,cACd,CAOO,OAAO,kBAAkBC,EAAsB,CACpD,GAAIA,GAAkB,EACpB,MAAM,IAAI,MAAM,+CAA+C,EAGjE,MAAMC,EAAyB,OAAO,KAAK,KAAK,WAAW,EAAE,OAC7D,GAAIA,EAAyBD,EAC3B,MAAM,IAAI,MACR,qCAAqCA,CAAc,iCACpBC,CAAsB,8DACf,EAI1C,KAAK,eAAiBD,CACxB,CAKO,OAAO,iBAAiBE,EAAsB,CACnD,KAAK,cAAgBA,CACvB,CAKO,OAAO,eAAejE,EAAazC,EAAsB,CAC9D,KAAK,qBAAqByC,CAAG,EAAIzC,CACnC,CAKO,OAAO,gBAAgB2G,EAAuC,CACnE,OAAO,QAAQA,CAAO,EAAE,QAAQ,CAAC,CAAClE,EAAKzC,CAAM,IAAK,CAChD,KAAK,eAAeyC,EAAKzC,CAAM,CACjC,CAAC,CACH,CAKQ,OAAO,UAAUyC,EAAW,CAElC,GAAI,KAAK,qBAAqBA,CAAG,EAC/B,OAAO,KAAK,qBAAqBA,CAAG,EAItC,GAAI,KAAK,cACP,OAAO,KAAK,cAAc,UAAUA,CAAG,CAI3C,CAKO,OAAO,qBAAmB,OAC/B,MAAMmE,EAAe,OAAO,KAAK,KAAK,oBAAoB,EACpDC,IAAetH,EAAA,KAAK,iBAAa,MAAAA,IAAA,OAAA,OAAAA,EAAE,iBAAA,IAAsB,CAAA,EAC/D,MAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAGqH,EAAc,GAAGC,CAAY,CAAC,CAAC,CACxD,CAKO,OAAO,aAAaC,EAAsB,CAC/C,KAAK,aAAaA,EAAW,QAAQ,EAAIA,CAC3C,CAKO,OAAO,cAAcC,EAAyB,CACnDA,EAAY,QAAQtH,GAAU,KAAK,aAAaA,CAAM,CAAC,CACzD,CAKO,OAAO,oBAAkB,CAC9B,OAAA,OAAA,OAAA,CAAA,EAAY,KAAK,YAAY,CAC/B,CAKO,OAAO,iBAAiBuH,EAAgB,CAC7C,MAAMF,EAAa,KAAK,aAAaE,CAAQ,EAC7C,GAAI,CAACF,EACH,MAAM,IAAI,MAAM,SAASE,CAAQ,sBAAsB,EAEzD,MAAO,CACL,GAAGF,EAAW,kBACd,GAAIA,EAAW,mBAAqB,CAAA,EAExC,CAKO,OAAO,yBAAuB,CACnC,MAAMG,EAAe,IAAI,IACzBA,EAAa,IAAI,MAAM,EAEvB,UAAWD,KAAY,KAAK,iBAAkB,CAC5C,MAAMF,EAAa,KAAK,aAAaE,CAAQ,EACzCF,IACFA,EAAW,kBAAkB,QAAQI,GAAMD,EAAa,IAAIC,CAAE,CAAC,EAC3DJ,EAAW,mBACbA,EAAW,kBAAkB,QAAQI,GAAMD,EAAa,IAAIC,CAAE,CAAC,EAGrE,CAEA,OAAO,MAAM,KAAKD,CAAY,CAChC,CAKO,aAAa,0BAAwB,CAC1C,GAAI,CAAA,KAAK,YAAY,KAIrB,GAAI,CACF,MAAME,EAAa,KAAK,UAAU,MAAM,EACxC,GAAI,CAACA,EACH,MAAM,IAAI,MAAM,iCAAiC,EAGnD,MAAMpB,EAAM,MAAMD,EAAgB,aAAa,CAAE,OAAQqB,CAAU,EAAI,EAAK,EAC5E,MAAMpB,EAAI,QAAQ,wBAAwB,EAC1C,KAAK,YAAY,KAAUA,CAC7B,OAAS7F,EAAO,CACd,MAAM,IAAI,MAAM,qCAAsCA,EAAgB,OAAO,EAAE,CACjF,CACF,CAKO,aAAa,oBAClBkH,EACAC,EAAoB,CAGpB,UAAWL,KAAYI,EACrB,GAAI,CAAC,KAAK,aAAaJ,CAAQ,EAC7B,MAAM,IAAI,MAAM,SAASA,CAAQ,gDAAgD,EAIrF,MAAMM,EAAgB,CAAC,GAAG,KAAK,gBAAgB,EAC/C,KAAK,iBAAmBF,EACxB,KAAK,YAAcC,GAAeD,EAAU,CAAC,GAAK,KAElD,MAAM,KAAK,8BAAA,EACX,MAAM,KAAK,yBAAyBE,CAAa,CACnD,CAKO,OAAO,qBAAmB,CAC/B,MAAO,CAAC,GAAG,KAAK,gBAAgB,CAClC,CAKO,OAAO,gBAAc,CAC1B,OAAO,KAAK,WACd,CAKQ,aAAa,+BAA6B,CAChD,MAAMC,EAAoB,KAAK,wBAAA,EACzBC,EAAyD,CAAA,EAEzDC,EAAeF,EAAkB,IAAI,MAAMG,GAAQ,CACvD,GAAI,CAAA,KAAK,YAAYA,CAAK,EAI1B,GAAI,CACF,MAAM1H,EAAS,KAAK,UAAU0H,CAAK,EACnC,GAAI,CAAC1H,EACH,MAAM,IAAI,MAAM,iBAAiB0H,CAAK,uCAAuC,EAG/E,MAAM3B,EAAM,MAAMD,EAAgB,aAAa,CAAE,OAAQ9F,CAAM,EAAI,EAAK,EACxE,MAAM+F,EAAI,QAAQ,wBAAwB,EAC1C,KAAK,YAAY2B,CAAK,EAAI3B,CAC5B,OAAS7F,EAAO,CACd,MAAMyH,EAAMzH,aAAiB,MAAQA,EAAQ,IAAI,MAAM,OAAOA,CAAK,CAAC,EAGjD,KAAK,iBAAiB,KAAK8G,GAAW,CACvD,MAAMF,EAAa,KAAK,aAAaE,CAAQ,EAC7C,OAAOF,GAAcA,EAAW,kBAAkB,SAASY,CAAK,CAClE,CAAC,GAGCF,EAAsB,KAAK,CAAE,IAAKE,EAAO,MAAOC,CAAG,CAAE,CAGzD,CACF,CAAC,EAID,GAFA,MAAM,QAAQ,IAAIF,CAAY,EAE1BD,EAAsB,OAAS,EAAG,CACpC,MAAMI,EAAeJ,EAClB,IAAIK,GAAK,OAAOA,EAAE,GAAG,KAAKA,EAAE,MAAM,OAAO,EAAE,EAC3C,KAAK;AAAA,CAAI,EACZ,MAAM,IAAI,MAAM;AAAA,EAA4DD,CAAY,EAAE,CAC5F,CACF,CAKQ,aAAa,yBAAyBN,EAAuB,CACnE,MAAMQ,EAAoB,IAAI,IAC9BA,EAAkB,IAAI,MAAM,EAE5B,UAAWd,KAAYM,EAAe,CACpC,MAAMR,EAAa,KAAK,aAAaE,CAAQ,EACzCF,IACFA,EAAW,kBAAkB,QAAQI,GAAMY,EAAkB,IAAIZ,CAAE,CAAC,EAChEJ,EAAW,mBACbA,EAAW,kBAAkB,QAAQI,GAAMY,EAAkB,IAAIZ,CAAE,CAAC,EAG1E,CAEA,MAAMa,EAAmB,IAAI,IAAI,KAAK,yBAAyB,EACzDC,EAAmB,MAAM,KAAKF,CAAiB,EAAE,OACrDZ,GAAM,CAACa,EAAiB,IAAIb,CAAE,CAAC,EAGjC,GAAIc,EAAiB,OAAS,GAC5B,UAAWN,KAASM,EAClB,GAAI,KAAK,YAAYN,CAAK,EACxB,GAAI,CACF,MAAM,KAAK,YAAYA,CAAK,EAAE,MAAA,EAC9B,OAAO,KAAK,YAAYA,CAAK,CAC/B,OAASxH,EAAO,CAEhB,EAIR,CAKO,OAAO,oBAAoBwH,EAAa,CAG7C,OAAO,KAAK,UAAUA,CAAK,IAAM,MACnC,CAKO,OAAO,IAAIjF,EAAW,CAC3B,GAAI,CAAC,KAAK,oBAAoBA,CAAG,EAC/B,MAAM,IAAI,MAAM,4BAA4BA,CAAG,sBAAsB,EAGvE,MAAMsD,EAAM,KAAK,YAAYtD,CAAG,EAChC,GAAI,CAACsD,EACH,MAAM,IAAI,MAAM,aAAatD,CAAG,qDAAqD,EAGvF,OAAOsD,CACT,CAKO,OAAO,oBACZkC,EACAC,EAAqC,CAEhC,KAAK,eAAe,IAAID,CAAU,GACrC,KAAK,eAAe,IAAIA,EAAY,CAAA,CAAE,EAExC,KAAK,eAAe,IAAIA,CAAU,EAAG,KAAKC,CAAQ,CACpD,CAKO,OAAO,qBACZD,EACAC,EAAqC,CAErC,MAAMC,EAAY,KAAK,eAAe,IAAIF,CAAU,EACpD,GAAIE,EAAW,CACb,MAAMpH,EAAQoH,EAAU,QAAQD,CAAQ,EACpCnH,EAAQ,IACVoH,EAAU,OAAOpH,EAAO,CAAC,CAE7B,CACF,CAKQ,OAAO,wBAAwBkH,EAAoBlC,EAAiB,CAC1E,MAAMoC,EAAY,KAAK,eAAe,IAAIF,CAAU,EAChDE,GACFA,EAAU,QAAQD,GAAW,CAC3B,GAAI,CACFA,EAASnC,CAAG,CACd,OAAS7F,EAAO,CAEhB,CACF,CAAC,CAEL,CAKQ,aAAa,qBAAmB,CACtC,GAAI,CAAA,KAAK,qBAIT,CAAA,KAAK,qBAAuB,GAC5B,GAAI,CAEsB,OAAO,KAAK,KAAK,WAAW,EACpC,QAAQwH,GAAS,KAAK,gBAAgB,IAAIA,CAAK,CAAC,EAEhE,MAAMU,EAAgB,OAAO,QAAQ,KAAK,WAAW,EAAE,IACrD,MAAO,CAACV,EAAO3B,CAAG,IAAK,CACrB,GAAI,CACF,MAAMA,EAAI,MAAA,CACZ,OAAS7F,EAAO,CAEhB,CACF,CAAC,EAGH,MAAM,QAAQ,IAAIkI,CAAa,EAC/B,KAAK,YAAc,CAAA,CACrB,SACE,KAAK,qBAAuB,EAC9B,CAAA,CACF,CAKO,aAAa,mBAAiB,CACnC,MAAM,KAAK,yBAAA,EAEP,KAAK,iBAAiB,OAAS,GACjC,MAAM,KAAK,8BAAA,EAIb,MAAMC,EAAgB,MAAM,KAAK,KAAK,eAAe,EACrD,GAAIA,EAAc,OAAS,EACzB,UAAWX,KAASW,EAClB,GAAK,KAAK,YAAYX,CAAK,EAYhB,KAAK,YAAYA,CAAK,GAE/B,KAAK,wBAAwBA,EAAO,KAAK,YAAYA,CAAK,CAAC,MAd/B,CAC5B,MAAM1H,EAAS,KAAK,UAAU0H,CAAK,EACnC,GAAI1H,EACF,GAAI,CACF,MAAM+F,EAAM,MAAMD,EAAgB,aAAa,CAAE,OAAQ9F,CAAM,EAAI,EAAK,EACxE,MAAM+F,EAAI,QAAA,EACV,KAAK,YAAY2B,CAAK,EAAI3B,EAC1B,KAAK,wBAAwB2B,EAAO3B,CAAG,CACzC,OAAS7F,EAAO,CAEhB,CAEJ,CAMN,CAKO,aAAa,yBAAyBuC,EAAW,CAGtD,GAFA,KAAK,gBAAgB,IAAIA,CAAG,EAExB,CAAC,KAAK,oBAAoBA,CAAG,EAC/B,MAAM,IAAI,MAAM,4BAA4BA,CAAG,sBAAsB,EAGvE,GAAI,KAAK,YAAYA,CAAG,EACtB,GAAI,CAEF,GADoB,KAAK,YAAYA,CAAG,EAAE,iBAAA,EAExC,OAAO,KAAK,YAAYA,CAAG,EAG3B,GAAI,CACF,MAAM,KAAK,YAAYA,CAAG,EAAE,QAAQ,MAAM,IAAK,CAAE,CAAC,CACpD,OAASvC,EAAO,CAEhB,CACA,OAAO,KAAK,YAAYuC,CAAG,CAE/B,OAASvC,EAAO,CACd,OAAO,KAAK,YAAYuC,CAAG,CAC7B,CAIF,OAAO,MAAM,KAAK,eAAeA,CAAG,CACtC,CAKO,OAAO,gBAAc,CAC1B,OAAA,OAAA,OAAA,CAAA,EAAY,KAAK,WAAW,CAC9B,CAKO,aAAa,gBAAgB6F,EAAsB,CACxD,MAAMC,EAA+C,CAAA,EAErD,UAAW9F,KAAO6F,EAChB,GAAI,CACF,MAAMtI,EAAS,KAAK,UAAUyC,CAAG,EACjC,GAAI,CAACzC,EACH,MAAM,IAAI,MAAM,yBAAyByC,CAAG,qBAAqB,EAGnE,MAAMsD,EAAM,MAAMD,EAAgB,aAAa,CAAE,OAAQ9F,CAAM,EAAI,EAAK,EACxE,MAAM+F,EAAI,QAAQ,wBAAwB,EAC1C,KAAK,YAAYtD,CAAG,EAAIsD,CAC1B,OAAS7F,EAAO,CACd,MAAMyH,EAAMzH,aAAiB,MAAQA,EAAQ,IAAI,MAAM,OAAOA,CAAK,CAAC,EACpEqI,EAAY,KAAK,CAAE,IAAA9F,EAAK,MAAOkF,CAAG,CAAE,CACtC,CAGF,GAAIY,EAAY,OAAS,EAAG,CAC1B,MAAMX,EAAeW,EAClB,IAAIV,GAAK,OAAOA,EAAE,GAAG,KAAKA,EAAE,MAAM,OAAO,EAAE,EAC3C,KAAK;AAAA,CAAI,EACZ,MAAM,IAAI,MAAM;AAAA,EAA0CD,CAAY,EAAE,CAC1E,CAEA,OAAA,KAAK,cAAgB,GACd,EACT,CAKO,aAAa,eAAeU,EAAsB,CACvD,MAAME,EAAcF,EAAa,OAAO7F,GAAO,CAAC,KAAK,UAAUA,CAAG,CAAC,EACnE,GAAI+F,EAAY,OAAS,EACvB,MAAM,IAAI,MAAM,0BAA0BA,EAAY,KAAK,IAAI,CAAC,sBAAsB,EAGxF,MAAMC,EAAsBH,EAAa,OAAO7F,GAAO,CAAC,KAAK,YAAYA,CAAG,CAAC,EAAE,OACzEiG,EAA0B,OAAO,KAAK,KAAK,WAAW,EAAE,OAE9D,GAAIA,EAA0BD,EAAsB,KAAK,eACvD,MAAM,IAAI,MACR,qBAAqBA,CAAmB,6CAA6C,KAAK,cAAc,0BAA0BC,CAAuB,EAAE,EAI/J,MAAMlB,EAAyD,CAAA,EACzDC,EAAea,EAAa,IAAI,MAAM7F,GAAM,CAChD,GAAI,MAAK,YAAYA,CAAG,EAIxB,GAAI,CACF,MAAMzC,EAAS,KAAK,UAAUyC,CAAG,EAC3BsD,EAAM,MAAMD,EAAgB,aAAa,CAAE,OAAQ9F,CAAM,EAAI,EAAK,EACxE,MAAM+F,EAAI,QAAQ,wBAAwB,EAC1C,KAAK,YAAYtD,CAAG,EAAIsD,CAC1B,OAAS7F,EAAO,CACd,MAAMyH,EAAMzH,aAAiB,MAAQA,EAAQ,IAAI,MAAM,OAAOA,CAAK,CAAC,EACpEsH,EAAsB,KAAK,CAAE,IAAA/E,EAAK,MAAOkF,CAAG,CAAE,CAChD,CACF,CAAC,EAID,GAFA,MAAM,QAAQ,IAAIF,CAAY,EAE1BD,EAAsB,OAAS,EAAG,CACpC,MAAMI,EAAeJ,EAClB,IAAIK,GAAK,OAAOA,EAAE,GAAG,KAAKA,EAAE,MAAM,OAAO,EAAE,EAC3C,KAAK;AAAA,CAAI,EACZ,MAAM,IAAI,MAAM;AAAA,EAAgDD,CAAY,EAAE,CAChF,CAEA,OAAI,OAAO,KAAK,KAAK,WAAW,EAAE,OAAS,IACzC,KAAK,cAAgB,IAGhB,EACT,CAKO,aAAa,eAAa,CAC/B,GAAI,KAAK,cACP,OAGF,MAAMe,EAAmB,KAAK,sBACxBnB,EAAyD,CAAA,EAEzDC,EAAekB,EAAiB,IAAI,MAAMlG,GAAM,CACpD,GAAI,CACF,MAAMzC,EAAS,KAAK,UAAUyC,CAAG,EAC3BsD,EAAM,MAAMD,EAAgB,aAAa,CAAE,OAAQ9F,CAAM,EAAI,EAAK,EACxE,KAAK,YAAYyC,CAAG,EAAIsD,CAC1B,OAAS7F,EAAO,CACd,MAAMyH,EAAMzH,aAAiB,MAAQA,EAAQ,IAAI,MAAM,OAAOA,CAAK,CAAC,EACpEsH,EAAsB,KAAK,CAAE,IAAA/E,EAAK,MAAOkF,CAAG,CAAE,CAChD,CACF,CAAC,EAID,GAFA,MAAM,QAAQ,IAAIF,CAAY,EAE1BD,EAAsB,OAAS,EAAG,CACpC,KAAK,cAAgB,GACrB,MAAMI,EAAeJ,EAClB,IAAIK,GAAK,OAAOA,EAAE,GAAG,KAAKA,EAAE,MAAM,OAAO,EAAE,EAC3C,KAAK;AAAA,CAAI,EACZ,MAAM,IAAI,MAAM;AAAA,EAAgDD,CAAY,EAAE,CAChF,CAEA,KAAK,cAAgB,EACvB,CAKO,aAAa,eAAenF,EAAW,CAG5C,GAFA,KAAK,gBAAgB,IAAIA,CAAG,EAExB,CAAC,KAAK,oBAAoBA,CAAG,EAC/B,MAAM,IAAI,MAAM,4BAA4BA,CAAG,sBAAsB,EAGvE,GAAI,CAAC,KAAK,YAAYA,CAAG,EAAG,CAC1B,MAAMzC,EAAS,KAAK,UAAUyC,CAAG,EACjC,GAAI,CAACzC,EACH,MAAM,IAAI,MAAM,yBAAyByC,CAAG,qBAAqB,EAGnE,GAAI,OAAO,KAAK,KAAK,WAAW,EAAE,QAAU,KAAK,eAC/C,MAAM,IAAI,MAAM,gDAAgD,EAGlE,MAAMsD,EAAM,MAAMD,EAAgB,aAAa,CAAE,OAAQ9F,CAAM,EAAI,EAAK,EACxE,MAAM+F,EAAI,QAAA,EACV,KAAK,YAAYtD,CAAG,EAAIsD,CAC1B,CAEA,OAAA,KAAK,cAAgB,GACd,KAAK,YAAYtD,CAAG,CAC7B,CAKO,aAAa,8BAClBkE,EACAuB,EAA+D,CAE/D,UAAWzF,KAAOkE,EAChB,GAAI,CAAC,KAAK,oBAAoBlE,CAAG,EAC/B,MAAM,IAAI,MAAM,4BAA4BA,CAAG,sBAAsB,EAIzE,MAAMmG,EAAOjC,EAAQ,OAAO,CAACkC,EAAKpG,KAChCoG,EAAIpG,CAAG,EAAI,KAAK,IAAIA,CAAG,EAChBoG,GACN,CAAA,CAAkC,EAErC,GAAI,CACF,MAAM,QAAQ,IAAI,OAAO,OAAOD,CAAI,EAAE,IAAI7C,GAAOA,EAAI,iBAAA,CAAkB,CAAC,EACxE,MAAMmC,EAASU,CAAI,EACnB,MAAM,QAAQ,IAAI,OAAO,OAAOA,CAAI,EAAE,IAAI7C,GAAOA,EAAI,mBAAmB,CAAC,CAC3E,OAAS7F,EAAO,CACd,MAAA,MAAM,QAAQ,IAAI,OAAO,OAAO0I,CAAI,EAAE,IAAI7C,GAAOA,EAAI,oBAAA,CAAqB,CAAC,EACrE7F,CACR,CACF,CAKO,aAAa,kBAClB4I,EACA3I,EACAsD,EACAnE,EAAkC,CAAA,EAAE,CAEpC,GAAI,CAAC,KAAK,oBAAoBwJ,CAAW,EACvC,MAAM,IAAI,MAAM,4BAA4BA,CAAW,sBAAsB,EAG/E,MAAM/C,EAAM,KAAK,IAAI+C,CAAW,EAChC,GAAI,CAMF,OALe,MAAM/C,EAAI,0BACvB,UAAA5F,EACA,KAAAsD,CAAI,EACDnE,CAAO,CAAA,CAGd,OAASY,EAAO,CACd,MAAMA,CACR,CACF,CAKO,aAAa,sBAClB4I,EACA3I,EACAsD,EACAC,EACApE,EAAkC,CAAA,EAAE,CAEpC,GAAI,CAAC,KAAK,oBAAoBwJ,CAAW,EACvC,MAAM,IAAI,MAAM,4BAA4BA,CAAW,sBAAsB,EAG/E,MAAM/C,EAAM,KAAK,IAAI+C,CAAW,EAChC,GAAI,CAOF,OANe,MAAM/C,EAAI,sBACvB5F,EACAsD,EACAC,EACApE,CAAO,CAGX,OAASY,EAAO,CACd,MAAMA,CACR,CACF,CAKO,aAAa,WAAW6I,EAAqC,CAClE,MAAMpG,EAAY,KAAK,IAAA,EACjBC,EAA2B,CAC/B,eAAgBmG,EAAc,OAC9B,iBAAkB,EAClB,QAAS,CAAA,EACT,OAAQ,CAAA,EACR,cAAe,GAGjB,UAAWtJ,KAAUsJ,EAAe,CAClC,MAAMC,EAAY,GAAGvJ,EAAO,WAAW,IAAIA,EAAO,SAAS,GAC3D,GAAI,CACF,GAAI,CAAC,KAAK,oBAAoBA,EAAO,WAAW,EAC9C,MAAM,IAAI,MAAM,4BAA4BA,EAAO,WAAW,sBAAsB,EAGtF,MAAMsG,EAAM,KAAK,IAAItG,EAAO,WAAW,EACvC,IAAIwJ,EAEAxJ,EAAO,eACTwJ,EAAe,MAAMlD,EAAI,sBACvBtG,EAAO,UACPA,EAAO,KACPA,EAAO,eACPA,EAAO,OAAO,EAGhBwJ,EAAe,MAAMlD,EAAI,WAAU,OAAA,OAAA,CACjC,UAAWtG,EAAO,UAClB,KAAMA,EAAO,MACVA,EAAO,OAAO,CAAA,EAIrBmD,EAAO,QAAQoG,CAAS,EAAIC,EAC5BrG,EAAO,kBACT,OAAS1C,EAAO,CACd,MAAMyH,EAAMzH,aAAiB,MAAQA,EAAQ,IAAI,MAAM,OAAOA,CAAK,CAAC,EACpE0C,EAAO,OAAOoG,CAAS,EAAIrB,CAC7B,CACF,CAEA,OAAA/E,EAAO,cAAgB,KAAK,IAAA,EAAQD,EAC7BC,CACT,CAKO,aAAa,cAClBkG,EACA3I,EACA4D,EACAzE,EAI6B,CAAA,EAAE,CAE/B,GAAI,CAAC,KAAK,oBAAoBwJ,CAAW,EACvC,MAAM,IAAI,MAAM,4BAA4BA,CAAW,sBAAsB,EAG/E,MAAM/C,EAAM,KAAK,IAAI+C,CAAW,EAChC,GAAI,CAEF,OADe,MAAM/C,EAAI,cAAc5F,EAAW4D,EAASzE,CAAO,CAEpE,OAASY,EAAO,CACd,MAAMA,CACR,CACF,CAKO,OAAO,oBAAkB,CAC9B,OAAO,OAAO,KAAK,KAAK,WAAW,EAAE,MACvC,CAKO,OAAO,iBAAe,CAC3B,OAAO,OAAO,KAAK,KAAK,WAAW,CACrC,CAKO,aAAa,gBAAgBwH,EAAa,CAC/C,MAAM3B,EAAM,KAAK,YAAY2B,CAAK,EAC9B3B,IACF,MAAMA,EAAI,WAAA,EACV,OAAO,KAAK,YAAY2B,CAAK,EAEjC,CAKO,aAAa,UAAQ,CAC1B,MAAM,KAAK,oBAAA,EAEX,KAAK,iBAAmB,CAAA,EACxB,KAAK,YAAc,KACnB,KAAK,cAAgB,GACrB,KAAK,gBAAgB,MAAA,EACrB,KAAK,eAAe,MAAA,EACpB,KAAK,qBAAuB,EAC9B,CAKO,aAAa,QAAM,CACxB,MAAMwB,EAAqB,OAAO,KAAK,KAAK,WAAW,EAAE,OACvDzG,GAAOA,IAAQ,MAAM,EAGvB,UAAWiF,KAASwB,EAClB,GAAI,CACF,MAAM,KAAK,YAAYxB,CAAK,EAAE,MAAA,EAC9B,OAAO,KAAK,YAAYA,CAAK,CAC/B,OAASxH,EAAO,CAEhB,CAGF,KAAK,iBAAmB,CAAA,EACxB,KAAK,YAAc,IACrB,EA7zBeqG,EAAA,eAAiB,GACjBA,EAAA,YAAmC,CAAA,EACnCA,EAAA,cAAgB,GAChBA,EAAA,aAA6B,CAAA,EAC7BA,EAAA,YAA6B,KAC7BA,EAAA,iBAA6B,CAAA,EAC7BA,EAAA,gBAA+B,IAAI,IACnCA,EAAA,qBAAuB,GAGvBA,EAAA,qBAAuD,CAAA,EACvDA,EAAA,cAAsC,KAGtCA,EAAA,eAAkE,IAAI,UC7BjE4C,CAAW,CAY/B,YAAYlB,EAAoB9H,EAAkB,CAXxC,KAAA,IAA2B,KAG3B,KAAA,SAAoB,GACpB,KAAA,cAAyB,GACzB,KAAA,cAA2C,IAAI,IAC/C,KAAA,eAA8C,IAAI,IAClD,KAAA,iBAA6B,CAAC,IAAI,EACpC,KAAA,MAA0B,IAAI,IAIpC,KAAK,WAAa8H,EAClB,KAAK,UAAY9H,GAAa8H,EAG9B,KAAK,iBAAoBmB,GAAwB,CAC/C,KAAK,IAAMA,EACX,KAAK,MAAM,iBAAkB,CAAE,WAAY,KAAK,UAAU,CAAE,CAC9D,EAEA7C,EAAgB,oBAAoB0B,EAAY,KAAK,gBAAgB,EACrE,KAAK,aACP,CAEQ,aAAW,CACD,OAAO,oBAAoB,OAAO,eAAe,IAAI,CAAC,EAC9D,QAASoB,GAAU,CAEvB,OAAQ,KAAaA,CAAM,GAAM,YACjCA,IAAW,gBAEV,KAAaA,CAAM,EAAK,KAAaA,CAAM,EAAE,KAAK,IAAI,EAE3D,CAAC,CACH,CAKA,oBAAoBC,EAAgB,CAClC,OAAA,KAAK,iBAAmBA,EACjB,IACT,CAKA,MAAM,MAAI,CACR,GAAI,CACF,GAAI,KAAK,cACP,OAAO,KAKT,GAFA,KAAK,IAAM,MAAM/C,EAAgB,eAAe,KAAK,UAAU,EAE3D,CAAC,KAAK,IACR,MAAM,IAAI,MACR,wCAAwC,KAAK,UAAU,EAAE,EAI7D,OAAK,KAAK,IAAI,iBAAA,GACZ,MAAM,KAAK,IAAI,UAGjB,KAAK,SAAW,GAChB,KAAK,cAAgB,GACrB,KAAK,MAAM,cAAe,CAAE,WAAY,KAAK,UAAU,CAAE,EAElD,IACT,OAASrG,EAAO,CACd,MAAA,KAAK,aAAa,aAAcA,CAAc,EACxCA,CACR,CACF,CAKA,MAAM,OAAOuD,EAAgB,CAC3B,MAAM,KAAK,qBACX,MAAM,KAAK,sBAAA,EACX,GAAI,CACF,KAAK,cAAcA,CAAI,EACvB,MAAMjB,EAAa,KAAK,eAAeiB,CAA2B,EAC5Db,EAAS,MAAM,KAAK,IAAK,OAAOJ,CAAU,EAChD,GAAII,EAAO,eAAiB,EAC1B,MAAM,IAAI,MAAM,4CAA4C,EAE9D,IAAI2G,EAA0B,KAC9B,MAAMC,EAAkB/F,EAAK,KAAK,iBAAiB,CAAC,CAAY,EAChE,GAAI,CACmC+F,GAAoB,KACvDD,EAAgB,MAAM,KAAK,SAASC,CAAsB,EACjD5G,EAAO,kBAChB2G,EAAgB,MAAM,KAAK,SAAS3G,EAAO,eAAe,EAE9D,OAAS6G,EAAW,CAClB,QAAQ,KAAK,8CAA+CA,CAAS,CACvE,CACA,OAAKF,IACHA,EAAgB9F,GAElB,KAAK,MAAM,cAAe,CAAE,UAAW,SAAU,KAAM8F,CAAa,CAAE,EAC/DA,CACT,OAASrJ,EAAO,CACd,MAAA,KAAK,aAAa,eAAgBA,CAAc,EAC1CA,CACR,CACF,CAKA,MAAM,OAAOwJ,EAASjG,EAAgB,CACpC,MAAM,KAAK,mBAAA,EAEX,GAAI,CACF,GAAI,CAACiG,EACH,MAAM,IAAI,MAAM,2BAA2B,EAG7C,KAAK,cAAcjG,CAAI,EACvB,MAAMkG,EAAU,OAAA,OAAA,OAAA,OAAA,CAAA,EACXlG,CAAI,EAAA,CACP,CAAC,KAAK,iBAAiB,CAAC,CAAC,EAAGiG,IAGxBlH,EAAa,KAAK,eAAemH,CAAiC,EACxE,MAAM,KAAK,IAAK,OAAOnH,CAAU,EAEjC,MAAMI,EAAS,MAAM,KAAK,SAAS8G,CAAE,EACrC,YAAK,MAAM,cAAe,CAAE,UAAW,SAAU,GAAAA,EAAI,KAAM9G,CAAM,CAAE,EAC5DA,CACT,OAAS1C,EAAO,CACd,WAAK,aAAa,eAAgBA,CAAc,EAC1CA,CACR,CACF,CAKA,MAAM,OAAOwJ,EAAO,CAClB,MAAM,KAAK,qBAEX,GAAI,CACF,GAAI,CAACA,EACH,MAAM,IAAI,MAAM,2BAA2B,EAG7C,MAAMlH,EAAyB,CAC7B,KAAM,KAAK,UACX,KAAM,GACN,OAAQ,CAAC,CAAE,KAAM,KAAK,iBAAiB,CAAC,EAAG,MAAOkH,EAAI,GAIlDE,GADS,MAAM,KAAK,IAAK,OAAOpH,CAAU,GACzB,aAAe,EAEtC,OAAIoH,GACF,KAAK,MAAM,cAAe,CAAE,UAAW,SAAU,GAAAF,CAAE,CAAE,EAGhDE,CACT,OAAS1J,EAAO,CACd,MAAA,KAAK,aAAa,eAAgBA,CAAc,EAC1CA,CACR,CACF,CAKA,MAAM,SAASwJ,EAAO,CACpB,MAAM,KAAK,qBAEX,GAAI,CACF,GAAI,CAACA,EACH,MAAM,IAAI,MAAM,gBAAgB,EAGlC,MAAMvH,EAAa,CAAE,CAAC,KAAK,iBAAiB,CAAC,CAAC,EAAGuH,GAC3ClH,EAAa,KAAK,iBAAiBL,CAAU,EAC7CS,EAAS,MAAM,KAAK,IAAK,OAAOJ,CAAU,EAE1CqH,EAAS,OAAO,KAAKjH,CAAM,EAAE,OAAS,EAAKA,EAAe,KAChE,YAAK,MAAM,cAAe,CAAE,UAAW,WAAY,GAAA8G,CAAE,CAAE,EAChDG,CACT,OAAS3J,EAAO,CACd,MAAA,KAAK,aAAa,mBAAoBA,CAAc,EAC9CA,CACR,CACF,CAKA,MAAM,UAAUiC,EAAkC,CAAA,EAAE,CAClD,MAAM,KAAK,mBAAA,EAEX,GAAI,CACF,MAAMK,EAAa,KAAK,iBAAiBL,CAAU,EAC7CS,EAAS,MAAM,KAAK,IAAK,OAAOJ,CAAU,EAE1CqH,EAAS,OAAO,KAAKjH,CAAM,EAAE,OAAS,EAAKA,EAAe,KAChE,OAAA,KAAK,MAAM,cAAe,CAAE,UAAW,WAAW,CAAE,EAC7CiH,CACT,OAAS3J,EAAO,CACd,MAAA,KAAK,aAAa,mBAAoBA,CAAc,EAC9CA,CACR,CACF,CAKA,MAAM,QACJiC,EAAkC,CAAA,EAClC7C,EAAuB,CAAA,EAAE,CAEzB,MAAM,KAAK,qBAEX,GAAI,CAGF,MAAMwK,EAAY,CAAC,GADS,KAAK,qBAAqB3H,CAAU,EACrB,GAAI7C,EAAQ,OAAS,CAAA,CAAG,EAE7DkD,EAAyB,CAC7B,KAAM,KAAK,UACX,KAAMlD,EAAQ,QAAUA,EAAQ,QAAQ,IAAKyK,IAAU,CAAE,KAAAA,CAAI,EAAG,EAAI,CAAA,EACpE,OAAQD,EACR,SAAUxK,EAAQ,QAClB,YAAa,CACX,MAAOA,EAAQ,MACf,OAAQA,EAAQ,MACjB,GAGG0K,EAAU,MAAM,KAAK,IAAK,UAAUxH,CAAU,EACpD,OAAA,KAAK,MAAM,cAAe,CACxB,UAAW,UACX,MAAOwH,EAAQ,MAChB,CAAA,EACMA,CACT,OAAS9J,EAAO,CACd,WAAK,aAAa,iBAAkBA,CAAc,EAC5CA,CACR,CACF,CAKA,MAAM,MAAMkC,EAA2C,CACrD,MAAM,KAAK,mBAAA,EAEX,GAAI,CACF,IAAI6H,EAAiC,CAAA,EAEjC,MAAM,QAAQ7H,CAAK,EACrB6H,EAAkB7H,EACTA,GAAS,OAAOA,GAAU,WACnC6H,EAAkB,KAAK,qBAAqB7H,CAAK,GAGnD,MAAMI,EAAyB,CAC7B,KAAM,KAAK,UACX,KAAM,CAAC,CAAE,KAAM,oBAAqB,EACpC,OAAQyH,GAIV,OADe,MAAM,KAAK,IAAK,OAAOzH,CAAU,GAClC,OAAS,CACzB,OAAStC,EAAO,CACd,MAAA,KAAK,aAAa,cAAeA,CAAc,EACzCA,CACR,CACF,CAKA,MAAM,OAAOwJ,EAAO,CAElB,OADa,MAAM,KAAK,SAASA,CAAE,IACnB,IAClB,CAKA,MAAM,UAAQ,CACZ,MAAM,KAAK,qBAEX,GAAI,CACF,MAAM,KAAK,IAAK,QAAQ,eAAe,KAAK,SAAS,EAAE,EACvD,MAAM,KAAK,IAAK,QACd,2CAA2C,KAAK,SAAS,GAAG,EAE9D,KAAK,MAAM,iBAAkB,CAAE,UAAW,KAAK,SAAS,CAAE,CAC5D,OAASxJ,EAAO,CACd,MAAA,KAAK,aAAa,iBAAkBA,CAAc,EAC5CA,CACR,CACF,CAKA,MAAM,WAAWgK,EAAmB,CAClC,MAAM,KAAK,mBAAA,EAEX,GAAI,CACF,GAAI,CAAC,MAAM,QAAQA,CAAK,GAAKA,EAAM,SAAW,EAC5C,MAAM,IAAI,MAAM,iCAAiC,EAGnD,MAAMtH,EAAS,MAAM,KAAK,IAAK,WAAW,CACxC,UAAW,KAAK,UAChB,KAAMsH,EACN,UAAW,IACX,WAAY,GACZ,aAAc,EACf,CAAA,EAED,YAAK,MAAM,kBAAmB,CAC5B,UAAW,aACX,MAAOtH,EAAO,WACf,CAAA,EACMA,CACT,OAAS1C,EAAO,CACd,MAAA,KAAK,aAAa,oBAAqBA,CAAc,EAC/CA,CACR,CACF,CAKA,MAAM,WAAWiK,EAAgC,CAC/C,MAAM,KAAK,qBAEX,GAAI,CACF,GAAI,CAAC,MAAM,QAAQA,CAAS,GAAKA,EAAU,SAAW,EACpD,MAAM,IAAI,MAAM,gCAAgC,EAGlD,MAAMH,EAAe,CAAA,EACrB,aAAM,KAAK,mBAAmB,SAAW,CACvC,UAAWvG,KAAQ0G,EAAW,CAC5B,KAAK,cAAc1G,CAAI,EACvB,MAAMjB,EAAa,KAAK,eAAeiB,CAAI,EAC3C,MAAM,KAAK,IAAK,OAAOjB,CAAU,EACjCwH,EAAQ,KAAKvG,CAAS,CACxB,CACF,CAAC,EAED,KAAK,MAAM,kBAAmB,CAC5B,UAAW,aACX,MAAOuG,EAAQ,MAChB,CAAA,EACMA,CACT,OAAS9J,EAAO,CACd,MAAA,KAAK,aAAa,oBAAqBA,CAAc,EAC/CA,CACR,CACF,CAKA,MAAM,mBAAmBgI,EAA4B,CACnD,MAAM,KAAK,qBAEX,GAAI,CACF,MAAM,KAAK,IAAK,mBAChB,MAAMtF,EAAS,MAAMsF,IACrB,OAAA,MAAM,KAAK,IAAK,kBAAA,EAChB,KAAK,MAAM,uBAAwB,CAAE,UAAW,aAAa,CAAE,EACxDtF,CACT,OAAS1C,EAAO,CACd,GAAI,CACF,MAAM,KAAK,IAAK,oBAAA,CAClB,OAASkK,EAAe,CACtB,KAAK,aAAa,iBAAkBA,CAAsB,CAC5D,CACA,WAAK,aAAa,oBAAqBlK,CAAc,EAC/CA,CACR,CACF,CAKA,MAAM,cACJ6D,EACAzE,EAI6B,CAAA,EAAE,CAE/B,MAAM,KAAK,qBAEX,GAAI,CACF,MAAMsD,EAAS,MAAM,KAAK,IAAK,cAC7B,KAAK,UACLmB,EACAzE,CAAO,EAET,OAAA,KAAK,MAAM,eAAgB,CAAE,UAAW,gBAAiB,OAAAsD,CAAM,CAAE,EAC1DA,CACT,OAAS1C,EAAO,CACd,MAAA,KAAK,aAAa,mBAAoBA,CAAc,EAC9CA,CACR,CACF,CAKA,MAAM,sBACJuD,EACAC,EACApE,EAAkC,CAAA,EAAE,CAEpC,MAAM,KAAK,qBAEX,GAAI,CACF,MAAMsD,EAAS,MAAM,KAAK,IAAK,sBAC7B,KAAK,UACLa,EACAC,EACApE,CAAO,EAET,YAAK,MAAM,eAAgB,CAAE,UAAW,oBAAqB,OAAAsD,CAAM,CAAE,EAC9DA,CACT,OAAS1C,EAAO,CACd,MAAA,KAAK,aAAa,uBAAwBA,CAAc,EAClDA,CACR,CACF,CAGU,iBACRiC,EAAkC,CAAA,EAClC7C,EAAuB,CAAA,EAAE,CAEzB,MAAMkD,EAAyB,CAC7B,KAAM,KAAK,UACX,KAAM,CAAA,EACN,OAAQ,GACR,SAAUlD,EAAQ,SAAW,CAAA,EAC7B,YAAa,CAAA,GAGf,OAAIA,EAAQ,SAAWA,EAAQ,QAAQ,OAAS,IAC9CkD,EAAW,KAAOlD,EAAQ,QAAQ,IAAKyK,IAAU,CAAE,KAAAA,CAAI,EAAG,GAGxD5H,GAAc,OAAO,KAAKA,CAAU,EAAE,OAAS,IACjDK,EAAW,OAAS,OAAO,QAAQL,CAAU,EAAE,IAAI,CAAC,CAACM,EAAKC,CAAK,KAAO,CACpE,KAAMD,EACN,MAAAC,EACA,SAAU,GACX,EAAC,GAGApD,EAAQ,QAAU,SACpBkD,EAAW,YAAa,MAAQlD,EAAQ,OAEtCA,EAAQ,SAAW,SACrBkD,EAAW,YAAa,OAASlD,EAAQ,QAGpCkD,CACT,CAEU,eAAeiB,EAAyB,CAChD,OAAO,KAAK,IAAK,wBACf,KAAK,UACLA,EACA,KAAK,gBAAgB,CAEzB,CAEU,qBAAqB4G,EAAwB,CACrD,OAAO,OAAO,QAAQA,CAAG,EACtB,OAAO,CAAC,CAAC7F,EAAG9B,CAAK,IAAMA,IAAU,MAAS,EAC1C,IAAI,CAAC,CAACD,EAAKC,CAAK,KAAO,CAAE,KAAMD,EAAK,MAAAC,CAAK,EAAG,CACjD,CAGA,GAAG4H,EAAeC,EAAqB,CACrC,OAAK,KAAK,eAAe,IAAID,CAAK,GAChC,KAAK,eAAe,IAAIA,EAAO,CAAA,CAAE,EAEnC,KAAK,eAAe,IAAIA,CAAK,EAAG,KAAKC,CAAO,EACrC,IACT,CAEA,IAAID,EAAeC,EAAqB,CACtC,MAAMC,EAAW,KAAK,eAAe,IAAIF,CAAK,EAC9C,GAAIE,EAAU,CACZ,MAAMzJ,EAAQyJ,EAAS,QAAQD,CAAO,EAClCxJ,EAAQ,IACVyJ,EAAS,OAAOzJ,EAAO,CAAC,CAE5B,CACA,OAAO,IACT,CAEU,MAAMuJ,EAAe7G,EAAS,CACtC,MAAM+G,EAAW,KAAK,eAAe,IAAIF,CAAK,EAC1CE,GACFA,EAAS,QAASD,GAAW,CAC3B,GAAI,CACFA,EAAQ9G,CAAI,CACd,OAASvD,EAAO,CAEhB,CACF,CAAC,CAEL,CAGA,gBAAgBuK,EAAmBF,EAAqB,CACtD,YAAK,cAAc,IAAIE,EAAWF,CAAO,EAClC,IACT,CAEU,aAAaE,EAAmBvK,EAAY,CACpD,MAAMqK,EAAU,KAAK,cAAc,IAAIE,CAAS,EAChD,GAAIF,EACF,GAAI,CACFA,EAAQrK,CAAK,CACf,OAASwK,EAAc,CAEvB,CAEF,KAAK,MAAM,QAAS,CAAE,UAAAD,EAAW,MAAAvK,CAAK,CAAE,CAC1C,CAEU,cAAcuD,EAAS,CAC/B,GAAI,CAACA,GAAQ,OAAOA,GAAS,SAC3B,MAAM,IAAI,MAAM,6BAA6B,CAEjD,CAEU,MAAM,oBAAkB,CAC3B,KAAK,eACR,MAAM,KAAK,KAAA,CAEf,CAEQ,MAAM,uBAAqB,OACjC,GAAI,CACkBlE,GAAAA,EAAA,KAAK,OAAG,MAAAA,IAAA,SAAAA,EAAE,iBAAA,IAE5B,KAAK,IAAM,MAAMgH,EAAgB,yBAC/B,KAAK,UAAU,EAGrB,OAASrG,EAAO,CACd,KAAK,IAAM,MAAMqG,EAAgB,yBAC/B,KAAK,UAAU,CAEnB,CACF,CAGA,MAAM,iBAAe,CACnB,OAAA,MAAM,KAAK,qBACJ,MAAM,KAAK,IAAK,iBACzB,CAEA,MAAM,cAAY,CAChB,OAAA,MAAM,KAAK,qBACJ,MAAM,KAAK,IAAK,aAAa,KAAK,SAAS,CACpD,CAEA,WAAS,CACP,MAAO,CACL,WAAY,KAAK,WACjB,UAAU,KAAK,UACf,SAAU,KAAK,SACf,cAAe,KAAK,cACpB,OAAQ,CAAC,CAAC,KAAK,IAEnB,CAEA,MAAM,aAAW,CACf,GAAI,CACF,MAAM,KAAK,mBAAA,EACX,MAAMoE,EAAQ,MAAM,KAAK,QACzB,MAAO,CACL,QAAS,GACT,WAAY,KAAK,WACjB,YAAaA,EACb,UAAW,IAAI,KAAA,EAAO,YAAA,EAE1B,OAASzK,EAAO,CACd,MAAO,CACL,QAAS,GACT,WAAY,KAAK,WACjB,MAAQA,EAAgB,QACxB,UAAW,IAAI,KAAA,EAAO,YAAA,EAE1B,CACF,CAGA,MAAM,OAAK,CACT,GAAI,CACF,OAAI,KAAK,KACP,MAAM,KAAK,IAAI,MAAA,EAGjB,KAAK,SAAW,GAChB,KAAK,cAAgB,GACrB,KAAK,eAAe,MAAA,EACpB,KAAK,cAAc,QACnB,KAAK,MAAM,QAEX,KAAK,MAAM,SAAU,CAAE,WAAY,KAAK,UAAU,CAAE,EAC7C,EACT,OAASA,EAAO,CACd,MAAA,KAAK,aAAa,cAAeA,CAAc,EACzCA,CACR,CACF,CAEO,SAAO,CAEZqG,EAAgB,qBACd,KAAK,WACL,KAAK,gBAAgB,EAIvB,KAAK,eAAe,MAAA,EACpB,KAAK,cAAc,QACnB,KAAK,MAAM,MAAA,CACb,CAGA,MAAM,OACJpE,EAAkC,GAClC7C,EAAuB,CAAA,EAAE,CAEzB,OAAO,KAAK,QAAQ6C,EAAY7C,CAAO,CACzC,CAEA,MAAM,QAAQoK,EAAmB,CAC/B,OAAO,KAAK,SAASA,CAAE,CACzB,CAEA,MAAM,SAASvH,EAAkC,CAAA,EAAE,CACjD,OAAO,KAAK,UAAUA,CAAU,CAClC,CACD,OC5pBYyI,CAAY,CAgBvB,YAAY7E,EAAkB,CAftB,KAAA,UAAY,GACZ,KAAA,aAAyB,CAAC,GAAG,EAC7B,KAAA,YAA4B,CAAA,EAC5B,KAAA,gBAAoC,CAAA,EACpC,KAAA,cAA0B,CAAA,EAC1B,KAAA,iBAAqC,CAAA,EACrC,KAAA,cAA0B,GAC1B,KAAA,WAA4B,KAC5B,KAAA,YAA6B,KAC7B,KAAA,OAAgB,CAAA,EAChB,KAAA,aAA+B,CAAA,EAC/B,KAAA,WAAyB,CAAA,EACzB,KAAA,WAAwC,IAAI,IAC5C,KAAA,IAA2B,KAGjC,KAAK,IAAMA,GAAO,IACpB,CAEA,OAAO,MAAMgE,EAAchE,EAAkB,CAC3C,MAAM8E,EAAU,IAAID,EAAa7E,CAAG,EACpC,OAAA8E,EAAQ,UAAYd,EACbc,CACT,CAEA,OAAO,KAAKd,EAAchE,EAAkB,CAC1C,OAAO6E,EAAa,MAAMb,EAAMhE,CAAG,CACrC,CAGA,OAAOuD,EAAyB,CAC9B,OAAA,KAAK,aAAe,MAAM,QAAQA,CAAM,EAAIA,EAAS,CAACA,CAAM,EACrD,IACT,CAEA,UAAUwB,EAAW,CACnB,YAAK,aAAe,CAACA,CAAG,EACjB,IACT,CAEA,eAAexB,EAAyB,CACtC,MAAMyB,EAAY,MAAM,QAAQzB,CAAM,EAAIA,EAAO,KAAK,IAAI,EAAIA,EAC9D,OAAA,KAAK,aAAe,CAAC,YAAYyB,CAAS,EAAE,EACrC,IACT,CAGA,KAAKxK,EAAeyK,EAAmB7F,EAA2B,QAAO,CACvE,OAAA,KAAK,YAAY,KAAK,CAAE,KAAAA,EAAM,MAAA5E,EAAO,UAAAyK,CAAS,CAAE,EACzC,IACT,CAEA,UAAUzK,EAAeyK,EAAiB,CACxC,OAAO,KAAK,KAAKzK,EAAOyK,EAAW,OAAO,CAC5C,CAEA,SAASzK,EAAeyK,EAAiB,CACvC,OAAO,KAAK,KAAKzK,EAAOyK,EAAW,MAAM,CAC3C,CAEA,UAAUzK,EAAeyK,EAAiB,CACxC,OAAO,KAAK,KAAKzK,EAAOyK,EAAW,OAAO,CAC5C,CAEA,cAAczK,EAAeyK,EAAiB,CAC5C,OAAO,KAAK,KAAKzK,EAAOyK,EAAW,YAAY,CACjD,CAMA,MAAMC,EAAiDC,EAAgCxI,EAAW,CAChG,GAAI,OAAOuI,GAAsB,SAE/B,cAAO,QAAQA,CAAiB,EAAE,QAAQ,CAAC,CAACE,EAAOC,CAAG,IAAK,CACzD,KAAK,gBAAgB,KAAK,CAAE,MAAAD,EAAO,SAAU,IAAK,MAAOC,CAAG,CAAE,CAChE,CAAC,EACM,KAGT,IAAI/I,EAAW,IACXgJ,EAAcH,EAElB,OAAI,UAAU,SAAW,IACvB7I,EAAW6I,EACXG,EAAc3I,GAGhB,KAAK,gBAAgB,KAAK,CACxB,MAAOuI,EACP,SAAA5I,EACA,MAAOgJ,CACR,CAAA,EAEM,IACT,CAEA,YAAYF,EAAezI,EAAU,CACnC,OAAO,KAAK,MAAMyI,EAAO,IAAKzI,CAAK,CACrC,CAEA,SAASyI,EAAezI,EAAU,CAChC,OAAO,KAAK,MAAMyI,EAAO,KAAMzI,CAAK,CACtC,CAEA,UAAUyI,EAAezI,EAAa,CACpC,OAAO,KAAK,MAAMyI,EAAO,OAAQzI,CAAK,CACxC,CAEA,aAAayI,EAAezI,EAAa,CACvC,OAAO,KAAK,MAAMyI,EAAO,WAAYzI,CAAK,CAC5C,CAEA,QAAQyI,EAAe1G,EAAa,CAClC,OAAA,KAAK,gBAAgB,KAAK,CAAE,MAAA0G,EAAO,SAAU,KAAM,MAAO1G,CAAM,CAAE,EAC3D,IACT,CAEA,WAAW0G,EAAe1G,EAAa,CACrC,OAAA,KAAK,gBAAgB,KAAK,CAAE,MAAA0G,EAAO,SAAU,SAAU,MAAO1G,CAAM,CAAE,EAC/D,IACT,CAEA,aAAa0G,EAAeG,EAAUC,EAAQ,CAC5C,OAAA,KAAK,gBAAgB,KAAK,CAAE,MAAAJ,EAAO,SAAU,UAAW,MAAO,CAACG,EAAKC,CAAG,CAAC,CAAE,EACpE,IACT,CAEA,gBAAgBJ,EAAeG,EAAUC,EAAQ,CAC/C,YAAK,gBAAgB,KAAK,CAAE,MAAAJ,EAAO,SAAU,cAAe,MAAO,CAACG,EAAKC,CAAG,CAAC,CAAE,EACxE,IACT,CAEA,UAAUJ,EAAa,CACrB,YAAK,gBAAgB,KAAK,CAAE,MAAAA,EAAO,SAAU,UAAW,MAAO,IAAI,CAAE,EAC9D,IACT,CAEA,aAAaA,EAAa,CACxB,OAAA,KAAK,gBAAgB,KAAK,CAAE,MAAAA,EAAO,SAAU,cAAe,MAAO,IAAI,CAAE,EAClE,IACT,CAEA,YAAYK,EAAsB,CAChC,OAAA,KAAK,gBAAgB,KAAK,CACxB,MAAO,GACP,SAAU,SACV,MAAOA,CACR,CAAA,EACM,IACT,CAEA,eAAeA,EAAsB,CACnC,OAAA,KAAK,gBAAgB,KAAK,CACxB,MAAO,GACP,SAAU,aACV,MAAOA,CACR,CAAA,EACM,IACT,CAKA,QAAQL,EAAeD,EAAgCxI,EAAW,CAGhE,OAAO,KAAK,MAAMyI,EAAOD,EAA2BxI,CAAK,CAC3D,CAGA,QAAQ4G,EAAyB,CAC/B,OAAA,KAAK,cAAgB,MAAM,QAAQA,CAAM,EAAIA,EAAS,CAACA,CAAM,EACtD,IACT,CAEA,OAAO6B,EAAe9I,EAAkBK,EAAW,CACjD,IAAI+I,EAAiB,IACjBJ,EAAchJ,EAElB,OAAI,UAAU,SAAW,IACvBoJ,EAAiBpJ,EACjBgJ,EAAc3I,GAGhB,KAAK,iBAAiB,KAAK,CACzB,MAAAyI,EACA,SAAUM,EACV,MAAOJ,CACR,CAAA,EACM,IACT,CAEA,YAAYF,EAAe9I,EAAkBK,EAAa,CACxD,OAAO,KAAK,OAAO,SAASyI,CAAK,IAAK9I,EAAUK,CAAK,CACvD,CAGA,QAAQyI,EAAeO,EAA4B,MAAK,CACtD,OAAA,KAAK,cAAc,KAAK,GAAGP,CAAK,IAAIO,CAAS,EAAE,EACxC,IACT,CAEA,YAAYP,EAAa,CACvB,OAAO,KAAK,QAAQA,EAAO,MAAM,CACnC,CAEA,WAAWL,EAAW,CACpB,OAAA,KAAK,cAAc,KAAKA,CAAG,EACpB,IACT,CAEA,OAAOK,EAAgB,aAAY,CACjC,OAAO,KAAK,YAAYA,CAAK,CAC/B,CAEA,OAAOA,EAAgB,aAAY,CACjC,OAAO,KAAK,QAAQA,EAAO,KAAK,CAClC,CAGA,MAAMR,EAAa,CACjB,OAAA,KAAK,WAAaA,EACX,IACT,CAEA,OAAOA,EAAa,CAClB,OAAA,KAAK,YAAcA,EACZ,IACT,CAEA,KAAKA,EAAa,CAChB,OAAO,KAAK,OAAOA,CAAK,CAC1B,CAEA,KAAKA,EAAa,CAChB,OAAO,KAAK,MAAMA,CAAK,CACzB,CAEA,UAAQ,CACN,OAAO,KAAK,MAAM,CAAC,CACrB,CAEA,SAASgB,EAAcC,EAAe,CACpC,OAAA,KAAK,WAAaA,EAClB,KAAK,aAAeD,EAAO,GAAKC,EACzB,IACT,CAGA,MAAMC,EAAmB,CACvB,OAAA,KAAK,aAAa,KAAKA,CAAK,EACrB,IACT,CAEA,SAASA,EAAmB,CAE1B,OAAO,KAAK,MAAMA,CAAK,CACzB,CAGA,KAAKC,EAAeD,EAAmB,CACrC,OAAA,KAAK,WAAW,IAAIC,EAAOD,CAAK,EACzB,IACT,CAGA,cAAcV,EAAe9I,EAAkBmJ,EAAsB,CACnE,OAAA,KAAK,WAAW,KAAK,CAAE,MAAOA,EAAU,MAAO,EAAE,CAAE,EACnD,KAAK,gBAAgB,KAAK,CAAE,MAAAL,EAAO,SAAA9I,EAAU,MAAOmJ,CAAQ,CAAE,EACvD,IACT,CAGA,MAAML,EAAgB,IAAG,CACvB,OAAA,KAAK,aAAe,CAAC,SAASA,CAAK,YAAY,EACxC,IACT,CAEA,IAAIA,EAAa,CACf,YAAK,aAAe,CAAC,OAAOA,CAAK,UAAU,EACpC,IACT,CAEA,IAAIA,EAAa,CACf,OAAA,KAAK,aAAe,CAAC,OAAOA,CAAK,UAAU,EACpC,IACT,CAEA,IAAIA,EAAa,CACf,OAAA,KAAK,aAAe,CAAC,OAAOA,CAAK,UAAU,EACpC,IACT,CAEA,IAAIA,EAAa,CACf,OAAA,KAAK,aAAe,CAAC,OAAOA,CAAK,UAAU,EACpC,IACT,CAGA,OAAK,CACH,IAAItK,EAAM,GACV,MAAMS,EAAgB,CAAA,EAGtB,GAAI,KAAK,WAAW,KAAO,EAAG,CAC5B,MAAMyK,EAAoB,CAAA,EAC1B,KAAK,WAAW,QAAQ,CAACF,EAAOC,IAAS,CACvC,KAAM,CAAE,IAAKE,EAAQ,OAAQC,CAAS,EAAKJ,EAAM,QACjDE,EAAQ,KAAK,GAAGD,CAAK,QAAQE,CAAM,GAAG,EACtC1K,EAAO,KAAK,GAAG2K,CAAS,CAC1B,CAAC,EACDpL,GAAO,QAAQkL,EAAQ,KAAK,IAAI,CAAC,GACnC,CAaA,GAVAlL,GAAO,UAAU,KAAK,aAAa,KAAK,IAAI,CAAC,SAAS,KAAK,SAAS,GAGhE,KAAK,YAAY,OAAS,GAC5B,KAAK,YAAY,QAAQqL,GAAO,CAC9BrL,GAAO,IAAIqL,EAAK,IAAI,SAASA,EAAK,KAAK,OAAOA,EAAK,SAAS,EAC9D,CAAC,EAIC,KAAK,gBAAgB,OAAS,EAAG,CACnC,MAAM/J,EAAuB,CAAA,EAC7B,KAAK,gBAAgB,QAAQ6I,GAAY,CACvC,KAAM,CAAE,OAAA9I,EAAQ,gBAAAiK,CAAe,EAAK,KAAK,eAAenB,CAAS,EACjE7I,EAAW,KAAKD,CAAM,EACtBZ,EAAO,KAAK,GAAG6K,CAAe,CAChC,CAAC,EACDtL,GAAO,UAAUsB,EAAW,KAAK,OAAO,CAAC,EAC3C,CAQA,GALI,KAAK,cAAc,OAAS,IAC9BtB,GAAO,aAAa,KAAK,cAAc,KAAK,IAAI,CAAC,IAI/C,KAAK,iBAAiB,OAAS,EAAG,CACpC,MAAMsB,EAAuB,CAAA,EAC7B,KAAK,iBAAiB,QAAQ6I,GAAY,CACxC,KAAM,CAAE,OAAA9I,EAAQ,gBAAAiK,CAAe,EAAK,KAAK,eAAenB,CAAS,EACjE7I,EAAW,KAAKD,CAAM,EACtBZ,EAAO,KAAK,GAAG6K,CAAe,CAChC,CAAC,EACDtL,GAAO,WAAWsB,EAAW,KAAK,OAAO,CAAC,EAC5C,CAGA,OAAI,KAAK,cAAc,OAAS,IAC9BtB,GAAO,aAAa,KAAK,cAAc,KAAK,IAAI,CAAC,IAI/C,KAAK,aAAe,OACtBA,GAAO,UAAU,KAAK,UAAU,IAI9B,KAAK,cAAgB,OACvBA,GAAO,WAAW,KAAK,WAAW,IAIhC,KAAK,aAAa,OAAS,GAC7B,KAAK,aAAa,QAAQuL,GAAa,CACrC,KAAM,CAAE,IAAKC,EAAU,OAAQC,CAAW,EAAKF,EAAW,MAAA,EAC1DvL,GAAO,UAAUwL,CAAQ,GACzB/K,EAAO,KAAK,GAAGgL,CAAW,CAC5B,CAAC,EAGI,CAAE,IAAAzL,EAAK,OAAAS,EAChB,CAEQ,eAAe0J,EAAyB,CAC9C,KAAM,CAAE,MAAAG,EAAO,SAAA9I,EAAU,MAAAK,CAAK,EAAKsI,EAC7B1J,EAAgB,GAEtB,OAAQe,EAAS,cAAW,CAC1B,IAAK,KACL,IAAK,SACH,MAAMhB,EAAgBqB,EAAgB,IAAI,IAAM,GAAG,EAAE,KAAK,IAAI,EAC9D,OAAApB,EAAO,KAAK,GAAIoB,CAAe,EACxB,CACL,OAAQ,GAAGyI,CAAK,IAAI9I,CAAQ,KAAKhB,CAAY,IAC7C,gBAAiBC,GAGrB,IAAK,UACL,IAAK,cACH,OAAAA,EAAO,KAAKoB,EAAM,CAAC,EAAGA,EAAM,CAAC,CAAC,EACvB,CACL,OAAQ,GAAGyI,CAAK,IAAI9I,CAAQ,WAC5B,gBAAiBf,GAGrB,IAAK,UACL,IAAK,cACH,MAAO,CACL,OAAQ,GAAG6J,CAAK,IAAI9I,CAAQ,GAC5B,gBAAiB,IAGrB,IAAK,SACL,IAAK,aACH,KAAM,CAAE,IAAKkK,EAAQ,OAAQC,CAAS,EAAM9J,EAAuB,QACnE,OAAApB,EAAO,KAAK,GAAGkL,CAAS,EACjB,CACL,OAAQ,GAAGnK,CAAQ,KAAKkK,CAAM,IAC9B,gBAAiBjL,GAGrB,QACE,GAAIoB,aAAiBkI,EAAc,CACjC,KAAM,CAAE,IAAK2B,EAAQ,OAAQC,CAAS,EAAK9J,EAAM,MAAA,EACjD,OAAApB,EAAO,KAAK,GAAGkL,CAAS,EACjB,CACL,OAAQ,GAAGrB,CAAK,IAAI9I,CAAQ,KAAKkK,CAAM,IACvC,gBAAiBjL,EAErB,CACA,OAAAA,EAAO,KAAKoB,CAAK,EACV,CACL,OAAQ,GAAGyI,CAAK,IAAI9I,CAAQ,KAC5B,gBAAiBf,EAEvB,CACF,CAGA,MAAM,KAAG,CACP,GAAI,CAAC,KAAK,IACR,MAAM,IAAI,MAAM,2CAA2C,EAE7D,KAAM,CAAE,IAAAT,EAAK,OAAAS,CAAM,EAAK,KAAK,MAAA,EAE7B,OADe,MAAM,KAAK,IAAI,QAAQT,EAAKS,CAAM,GACnC,IAChB,CAEA,MAAM,OAAK,CACT,KAAK,MAAM,CAAC,EACZ,MAAM0I,EAAU,MAAM,KAAK,MAC3B,OAAOA,EAAQ,OAAS,EAAIA,EAAQ,CAAC,EAAI,IAC3C,CAEA,MAAM,MAAMyC,EAAc,CACxB,OAAA,KAAK,OAAOA,CAAM,GACF,MAAM,KAAK,OACZ,IAAI7I,GAAOA,EAAI6I,CAAM,CAAC,CACvC,CAEA,MAAM,QAAM,CACV,OAAA,KAAK,OAAO,GAAG,EAAE,MAAM,CAAC,GACR,MAAM,KAAK,IAAA,GACZ,OAAS,CAC1B,CAEA,MAAM,aAAW,CACf,KAAK,QACL,MAAM7J,EAAS,MAAM,KAAK,QAC1B,OAAOA,EAASA,EAAO,MAAQ,CACjC,CAGA,OAAO,OAAOzC,EAAmBsD,EAAyB,CACxD,MAAM6F,EAAS,OAAO,KAAK7F,CAAI,EACzBgB,EAAS,OAAO,OAAOhB,CAAI,EAC3BpC,EAAeoD,EAAO,IAAI,IAAM,GAAG,EAAE,KAAK,IAAI,EAEpD,MAAO,CACL,IAAK,eAAetE,CAAS,KAAKmJ,EAAO,KAAK,IAAI,CAAC,aAAajI,CAAY,IAC5E,OAAQoD,EAEZ,CAEA,OAAO,WAAWtE,EAAmBgK,EAAgC,CACnE,GAAIA,EAAU,SAAW,EACvB,MAAM,IAAI,MAAM,4BAA4B,EAG9C,MAAMb,EAAS,OAAO,KAAKa,EAAU,CAAC,CAAC,EACjC9I,EAAeiI,EAAO,IAAI,IAAM,GAAG,EAAE,KAAK,IAAI,EAC9CoD,EAAcvC,EAAU,IAAI,IAAM,IAAI9I,CAAY,GAAG,EAAE,KAAK,IAAI,EAEhEuE,EAAYuE,EAAU,QAAQ1G,GAAQ,OAAO,OAAOA,CAAI,CAAC,EAE/D,MAAO,CACL,IAAK,eAAetD,CAAS,KAAKmJ,EAAO,KAAK,IAAI,CAAC,YAAYoD,CAAW,GAC1E,OAAQ9G,EAEZ,CAEA,OAAO,OAAOzF,EAAmBsD,EAA2BrB,EAAeuK,EAAqB,GAAE,CAChG,MAAMC,EAAO,OAAO,KAAKnJ,CAAI,EAAE,IAAIhB,GAAO,GAAGA,CAAG,MAAM,EAAE,KAAK,IAAI,EAC3DnB,EAAS,CAAC,GAAG,OAAO,OAAOmC,CAAI,EAAG,GAAGkJ,CAAW,EAEtD,MAAO,CACL,IAAK,UAAUxM,CAAS,QAAQyM,CAAI,UAAUxK,CAAK,GACnD,OAAAd,EAEJ,CAEA,OAAO,OAAOnB,EAAmBiC,EAAeuK,EAAqB,CAAA,EAAE,CACrE,MAAO,CACL,IAAK,eAAexM,CAAS,UAAUiC,CAAK,GAC5C,OAAQuK,EAEZ,CAEA,OAAO,OAAOxM,EAAmBsD,EAA2B8B,EAAyB,CACnF,MAAM+D,EAAS,OAAO,KAAK7F,CAAI,EACzBgB,EAAS,OAAO,OAAOhB,CAAI,EAC3BpC,EAAeoD,EAAO,IAAI,IAAM,GAAG,EAAE,KAAK,IAAI,EAE9Ce,EAAgB8D,EAAO,OAAO6B,GAAS,CAAC5F,EAAgB,SAAS4F,CAAK,CAAC,EACvE0B,EAAerH,EAAc,OAAS,EACxCA,EAAc,IAAI7F,GAAO,GAAGA,CAAG,eAAeA,CAAG,EAAE,EAAE,KAAK,IAAI,EAC9D,GAEJ,IAAIkB,EAAM,eAAeV,CAAS,KAAKmJ,EAAO,KAAK,IAAI,CAAC,aAAajI,CAAY,IAEjF,OAAImE,EAAc,OAAS,EACzB3E,GAAO,gBAAgB0E,EAAgB,KAAK,IAAI,CAAC,mBAAmBsH,CAAY,GAEhFhM,GAAO,gBAAgB0E,EAAgB,KAAK,IAAI,CAAC,eAG5C,CAAE,IAAA1E,EAAK,OAAQ4D,EACxB,CAGA,OAAK,CACH,GAAI,CAAC,KAAK,IAAK,MAAM,IAAI,MAAM,gDAAgD,EAC/E,MAAMqI,EAAS,IAAIlC,EAAa,KAAK,GAAG,EACxC,OAAAkC,EAAO,UAAY,KAAK,UACxBA,EAAO,aAAe,CAAC,GAAG,KAAK,YAAY,EAC3CA,EAAO,YAAc,CAAC,GAAG,KAAK,WAAW,EACzCA,EAAO,gBAAkB,CAAC,GAAG,KAAK,eAAe,EACjDA,EAAO,cAAgB,CAAC,GAAG,KAAK,aAAa,EAC7CA,EAAO,iBAAmB,CAAC,GAAG,KAAK,gBAAgB,EACnDA,EAAO,cAAgB,CAAC,GAAG,KAAK,aAAa,EAC7CA,EAAO,WAAa,KAAK,WACzBA,EAAO,YAAc,KAAK,YAC1BA,EAAO,aAAe,CAAC,GAAG,KAAK,YAAY,EAC3CA,EAAO,WAAa,CAAC,GAAG,KAAK,UAAU,EACvCA,EAAO,WAAa,IAAI,IAAI,KAAK,UAAU,EACpCA,CACT,CAEA,UAAQ,CACN,KAAM,CAAE,IAAAjM,EAAK,OAAAS,CAAM,EAAK,KAAK,MAAA,EAC7B,IAAIyL,EAASlM,EACb,OAAAS,EAAO,QAAQ0L,GAAQ,CACjB,OAAOA,GAAU,SACnBD,EAASA,EAAO,QAAQ,IAAK,IAAIC,EAAM,QAAQ,KAAM,IAAI,CAAC,GAAG,EACpDA,GAAU,KACnBD,EAASA,EAAO,QAAQ,IAAK,MAAM,EAEnCA,EAASA,EAAO,QAAQ,IAAK,OAAOC,CAAK,CAAC,CAE9C,CAAC,EACMD,CACT,CAEA,SAAO,CACL,OAAA,KAAK,aAAe,CAAC,sBAAwB,KAAK,aAAa,KAAK,IAAI,CAAC,EAClE,IACT,CACD,OCtiBYE,CAAgB,CAM3B,YACElH,EACAzG,EAGC,CATK,KAAA,WAAqC,IAAI,IACzC,KAAA,eAAyB,cACzB,KAAA,cAAwB,QAS9B,KAAK,IAAMyG,EACX,KAAK,gBAAiBzG,GAAO,KAAA,OAAPA,EAAS,iBAAkB,cACjD,KAAK,eAAgBA,GAAO,KAAA,OAAPA,EAAS,gBAAiB,OACjD,CAKA,aAAa4N,EAAoB,CAC/B,KAAK,kBAAkBA,CAAS,EAChC,KAAK,WAAW,IAAIA,EAAU,QAASA,CAAS,CAClD,CAKA,cAAcC,EAAuB,CACnC,UAAWD,KAAaC,EACtB,KAAK,aAAaD,CAAS,CAE/B,CAKA,eAAeC,EAAqC,CAClD,OAAO,OAAOA,CAAU,EAAE,QAASD,GAAa,CAC9C,KAAK,aAAaA,CAAS,CAC7B,CAAC,CACH,CAKA,gBAAgBjM,EAAe,CAC7B,OAAO,KAAK,WAAW,OAAOA,CAAO,CACvC,CAKA,eAAa,CACX,OAAO,MAAM,KAAK,KAAK,WAAW,OAAA,CAAQ,EAAE,KAAK,CAACmM,EAAGC,IACnD,KAAK,gBAAgBD,EAAE,QAASC,EAAE,OAAO,CAAC,CAE9C,CAKA,aAAapM,EAAe,CAC1B,OAAO,KAAK,WAAW,IAAIA,CAAO,CACpC,CAKA,MAAM,oBAAkB,CACtB,MAAMqM,EAAiB;AAAA,mCACQ,KAAK,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uCAOf,KAAK,aAAa;AAAA;AAAA,MAIrD,MAAM,KAAK,IAAI,QAAQA,CAAc,EAGrC,MAAM,KAAK,IAAI,QAAQ;AAAA;AAAA,WAEhB,KAAK,cAAc;AAAA,KACzB,EAED,MAAM,KAAK,IAAI,QAAQ;AAAA;AAAA,WAEhB,KAAK,cAAc;AAAA,KACzB,CACH,CAKA,MAAM,sBAAoB,CACxB,GAAI,CAMF,OALe,MAAM,KAAK,IAAI,QAAQ;AAAA;AAAA,eAE7B,KAAK,cAAc;AAAA;AAAA,OAE3B,GACa,IAChB,OAASpN,EAAO,CAEd,MAAO,CAAA,CACT,CACF,CAKA,MAAM,sBAAoB,CACxB,MAAMqN,EAAoB,MAAM,KAAK,qBAAA,EAC/BC,EAAkB,IAAI,IAAID,EAAkB,IAAKE,GAAMA,EAAE,OAAO,CAAC,EAEvE,OAAO,KAAK,cAAA,EAAgB,OACzBP,GAAc,CAACM,EAAgB,IAAIN,EAAU,OAAO,CAAC,CAE1D,CAKA,MAAM,mBAAiB,CACrB,MAAM,KAAK,mBAAA,EACX,MAAMK,EAAoB,MAAM,KAAK,uBAC/BG,EAAa,IAAI,IAAIH,EAAkB,IAAKE,GAAM,CAACA,EAAE,QAASA,CAAC,CAAC,CAAC,EAEvE,OAAO,KAAK,cAAA,EAAgB,IAAKP,GAAa,CAC5C,MAAMS,EAAUD,EAAW,IAAIR,EAAU,OAAO,EAC1C,CAAE,gBAAAU,EAAiB,oBAAAC,CAAmB,EAC1C,KAAK,kBAAkBX,CAAS,EAElC,MAAO,CACL,QAASA,EAAU,QACnB,YAAaA,EAAU,YACvB,SAAUA,EAAU,SACpB,QAAS,CAAC,CAACS,EACX,WAAYA,GAAO,KAAA,OAAPA,EAAS,WACrB,kBAAmBA,GAAO,KAAA,OAAPA,EAAS,kBAC5B,iBAAkBC,EAClB,qBAAsBC,EAE1B,CAAC,CACH,CAKA,MAAM,oBACJC,EACApC,EAA2B,KAAI,CAE/B,MAAM6B,EAAoB,MAAM,KAAK,qBAAA,EAC/BC,EAAkB,IAAI,IAAID,EAAkB,IAAKE,GAAMA,EAAE,OAAO,CAAC,EACjEM,EAAgB,KAAK,cAAA,EAErBC,EAAsB,CAC1B,QAAS,CAAA,EACT,WAAY,CAAA,EACZ,UAAW,CAAA,EACX,cAAe,GAGjB,GAAItC,IAAc,KAEhB,UAAWwB,KAAaa,EAAe,CACrC,GACED,GACA,KAAK,gBAAgBZ,EAAU,QAASY,CAAa,EAAI,EAEzD,MAGF,GAAI,CAACN,EAAgB,IAAIN,EAAU,OAAO,EAAG,CAC3C,KAAM,CAAE,gBAAAU,EAAiB,oBAAAC,CAAmB,EAC1C,KAAK,kBAAkBX,CAAS,EAE7BU,EAOHI,EAAK,QAAQ,KAAKd,CAAS,EAN3Bc,EAAK,UAAU,KACb,aACEd,EAAU,OACZ,4BAA4BW,EAAoB,KAAK,IAAI,CAAC,EAAE,CAKlE,CACF,KACK,CAEL,MAAMI,EAAkBV,EACrB,OACEI,GACC,CAACG,GACD,KAAK,gBAAgBH,EAAQ,QAASG,CAAa,EAAI,CAAC,EAE3D,KAAK,CAACV,EAAGC,IAAM,KAAK,gBAAgBA,EAAE,QAASD,EAAE,OAAO,CAAC,EAE5D,UAAWc,KAAiBD,EAAiB,CAC3C,MAAMf,EAAY,KAAK,WAAW,IAAIgB,EAAc,OAAO,EACvDhB,GACFc,EAAK,WAAW,KAAKd,CAAS,CAElC,CACF,CAGA,OAAAc,EAAK,eAAiBA,EAAK,QAAQ,OAASA,EAAK,WAAW,QAAU,IAE/DA,CACT,CAKA,MAAM,QACJF,EACAxO,EAA4B,CAAA,EAAE,SAE9B,MAAM,KAAK,mBAAA,EAEX,MAAM0O,EAAO,MAAM,KAAK,oBAAoBF,EAAe,IAAI,EAE/D,GAAIE,EAAK,UAAU,OAAS,EAC1B,MAAM,IAAI,MACR;AAAA,EAAkCA,EAAK,UAAU,KAAK;AAAA,CAAI,CAAC,EAAE,EAIjE,GAAI1O,EAAQ,OACV,OAAA,QAAQ,IAAI,iDAAiD,EAC7D0O,EAAK,QAAQ,QAASP,GACpB,QAAQ,IAAI,OAAOA,EAAE,OAAO,KAAKA,EAAE,WAAW,EAAE,CAAC,EAE5C,CAAA,EAGT,MAAMzD,EAA6B,CAAA,EAC7BmE,EAAQH,EAAK,QAAQ,OAE3B,QAAS9K,EAAI,EAAGA,EAAI8K,EAAK,QAAQ,OAAQ9K,IAAK,CAC5C,MAAMgK,EAAYc,EAAK,QAAQ9K,CAAC,EAEhC,GAAI,EACF3D,EAAAD,EAAQ,cAAU,MAAAC,IAAA,QAAAA,EAAA,KAAAD,EAAG4D,EAAI,EAAGiL,EAAOjB,CAAS,EAE5C,MAAMtK,EAAS,MAAM,KAAK,eAAesK,EAAW5N,CAAO,EAC3D0K,EAAQ,KAAKpH,CAAM,CACrB,OAAS1C,EAAO,CACd,MAAMkO,EACJlO,aAAiB,MAAQA,EAAQ,IAAI,MAAM,OAAOA,CAAK,CAAC,EAG1D,IAFAV,EAAAF,EAAQ,WAAO,MAAAE,IAAA,QAAAA,EAAA,KAAAF,EAAG8O,EAAgBlB,CAAS,EAEvC5N,EAAQ,cAAgB,GAC1B,MAAM,IAAI,MACR,aAAa4N,EAAU,OAAO,YAAYkB,EAAe,OAAO,EAAE,CAGxE,CACF,CAEA,OAAOpE,CACT,CAKA,MAAM,SACJ8D,EACAxO,EAA4B,CAAA,EAAE,SAE9B,MAAM,KAAK,mBAAA,EAEX,MAAM0O,EAAO,MAAM,KAAK,oBAAoBF,EAAe,MAAM,EAEjE,GAAIxO,EAAQ,OAAQ,CAClB,QAAQ,IAAI,oDAAoD,EAChE0O,EAAK,WAAW,QAASP,GACvB,QAAQ,IAAI,OAAOA,EAAE,OAAO,KAAKA,EAAE,WAAW,EAAE,CAAC,EAEnD,MACF,CAEA,MAAMU,EAAQH,EAAK,WAAW,OAE9B,QAAS9K,EAAI,EAAGA,EAAI8K,EAAK,WAAW,OAAQ9K,IAAK,CAC/C,MAAMgK,EAAYc,EAAK,WAAW9K,CAAC,EAEnC,GAAI,EACF3D,EAAAD,EAAQ,cAAU,MAAAC,IAAA,QAAAA,EAAA,KAAAD,EAAG4D,EAAI,EAAGiL,EAAOjB,CAAS,EAE5C,MAAM,KAAK,kBAAkBA,EAAW5N,CAAO,CACjD,OAASY,EAAO,CACd,MAAMkO,EACJlO,aAAiB,MAAQA,EAAQ,IAAI,MAAM,OAAOA,CAAK,CAAC,EAG1D,IAFAV,EAAAF,EAAQ,WAAO,MAAAE,IAAA,QAAAA,EAAA,KAAAF,EAAG8O,EAAgBlB,CAAS,EAEvC5N,EAAQ,cAAgB,GAC1B,MAAM,IAAI,MACR,yBAAyB4N,EAAU,OAAO,YAAYkB,EAAe,OAAO,EAAE,CAGpF,CACF,CACF,CAKQ,MAAM,eACZlB,EACA5N,EAAyB,CAEzB,MAAMqD,EAAY,KAAK,MACjB0L,EAAU/O,EAAQ,SAAW,IAEnC,MAAM,KAAK,IAAI,iBAAA,EAEf,GAAI,CAEF,MAAMgP,EAAmBpB,EAAU,GAAG,KAAK,GAAG,EAE9C,GAAImB,EAAU,EAAG,CACf,MAAME,EAAiB,IAAI,QAAQ,CAAC/J,EAAGgK,IAAU,CAC/C,WACE,IAAMA,EAAO,IAAI,MAAM,2BAA2BH,CAAO,IAAI,CAAC,EAC9DA,CAAO,CAEX,CAAC,EAED,MAAM,QAAQ,KAAK,CAACC,EAAkBC,CAAc,CAAC,CACvD,MACE,MAAMD,EAGR,MAAMG,EAAgB,KAAK,IAAA,EAAQ9L,EAC7B+L,EAAWpP,EAAQ,kBACrB,KAAK,iBAAiB4N,CAAS,EAC/B,OAGJ,OAAA,MAAM,KAAK,IAAI,QACb;AAAA,sBACc,KAAK,cAAc;AAAA;AAAA;AAAA,QAIjC,CACEA,EAAU,QACVA,EAAU,YACVA,EAAU,UAAY,KACtBuB,EACAC,GAAY,IACb,CAAA,EAGH,MAAM,KAAK,IAAI,oBAER,CACL,QAASxB,EAAU,QACnB,YAAaA,EAAU,YACvB,SAAUA,EAAU,SACpB,WAAY,IAAI,KAAA,EAAO,YAAA,EACvB,kBAAmBuB,EACnB,SAAAC,EAEJ,OAASxO,EAAO,CACd,YAAM,KAAK,IAAI,oBAAA,EACTA,CACR,CACF,CAKQ,MAAM,kBACZgN,EACA5N,EAAyB,CAEzB,MAAM+O,EAAU/O,EAAQ,SAAW,IAEnC,MAAM,KAAK,IAAI,mBAEf,GAAI,CAEF,MAAMqP,EAAkBzB,EAAU,KAAK,KAAK,GAAG,EAE/C,GAAImB,EAAU,EAAG,CACf,MAAME,EAAiB,IAAI,QAAQ,CAAC/J,EAAGgK,IAAU,CAC/C,WACE,IAAMA,EAAO,IAAI,MAAM,0BAA0BH,CAAO,IAAI,CAAC,EAC7DA,CAAO,CAEX,CAAC,EAED,MAAM,QAAQ,KAAK,CAACM,EAAiBJ,CAAc,CAAC,CACtD,MACE,MAAMI,EAIR,MAAM,KAAK,IAAI,QACb;AAAA,sBACc,KAAK,cAAc;AAAA,QAEjC,CAACzB,EAAU,OAAO,CAAC,EAGrB,MAAM,KAAK,IAAI,kBAAA,CACjB,OAAShN,EAAO,CACd,MAAA,MAAM,KAAK,IAAI,oBAAA,EACTA,CACR,CACF,CAKA,MAAM,MAAMZ,EAA+B,CAAA,EAAE,CAC3C,GAAI,CAACA,EAAQ,MACX,MAAM,IAAI,MACR,sEAAsE,EAI1E,MAAM,KAAK,IAAI,iBAAA,EAEf,GAAI,CAGF,MAAMsP,GADoB,MAAM,KAAK,qBAAA,GACQ,KAAK,CAACxB,EAAGC,IACpD,KAAK,gBAAgBA,EAAE,QAASD,EAAE,OAAO,CAAC,EAI5C,UAAWO,KAAWiB,EAAoB,CACxC,MAAM1B,EAAY,KAAK,WAAW,IAAIS,EAAQ,OAAO,EACjDT,GACF,MAAMA,EAAU,KAAK,KAAK,GAAG,CAEjC,CAGA,MAAM,KAAK,IAAI,QAAQ,eAAe,KAAK,cAAc,EAAE,EAE3D,MAAM,KAAK,IAAI,kBAAA,CACjB,OAAShN,EAAO,CACd,MAAA,MAAM,KAAK,IAAI,oBAAA,EACTA,CACR,CACF,CAKA,MAAM,mBAAiB,CAIrB,MAAM2O,EAAmB,CAAA,EAEzB,GAAI,CACF,MAAMtB,EAAoB,MAAM,KAAK,qBAAA,EAErC,UAAWI,KAAWJ,EAAmB,CACvC,MAAML,EAAY,KAAK,WAAW,IAAIS,EAAQ,OAAO,EAErD,GAAI,CAACT,EAAW,CACd2B,EAAO,KACL,qBAAqBlB,EAAQ,OAAO,qCAAqC,EAE3E,QACF,CAGA,KAAM,CAAE,gBAAAC,EAAiB,oBAAAC,CAAmB,EAC1C,KAAK,kBAAkBX,CAAS,EAC7BU,GACHiB,EAAO,KACL,aACElB,EAAQ,OACV,4BAA4BE,EAAoB,KAAK,IAAI,CAAC,EAAE,EAK5DF,EAAQ,UACc,KAAK,iBAAiBT,CAAS,IAC/BS,EAAQ,UAC9BkB,EAAO,KACL,aAAalB,EAAQ,OAAO,uDAAuD,CAI3F,CAEA,MAAO,CACL,MAAOkB,EAAO,SAAW,EACzB,OAAAA,EAEJ,OAAS3O,EAAO,CACd,MAAO,CACL,MAAO,GACP,OAAQ,CACN,yCAA0CA,EAAgB,OAAO,EAClE,EAEL,CACF,CAKA,MAAM,YAAU,CASd,MAAMyN,EAAU,MAAM,KAAK,qBAAA,EACrBmB,EAAU,MAAM,KAAK,qBAAA,EAErBC,EAAqC,CAAA,EAC3C,IAAIC,EAAqB,EAEzB,UAAW9B,KAAaS,EAClBT,EAAU,WACZ6B,EAAW7B,EAAU,QAAQ,GAC1B6B,EAAW7B,EAAU,QAAQ,GAAK,GAAK,GAE5C8B,GAAsB9B,EAAU,mBAAqB,EAGvD,MAAO,CACL,gBAAiB,KAAK,WAAW,KACjC,kBAAmBS,EAAQ,OAC3B,kBAAmBmB,EAAQ,OAC3B,WAAAC,EACA,mBAAAC,EACA,qBACErB,EAAQ,OAAS,EAAIqB,EAAqBrB,EAAQ,OAAS,EAC7D,iBAAkBA,EAAQ,MAAM,GAAG,EAEvC,CAKA,OAAO,0BACLsB,EACAC,EACAjO,EACAkO,EAAoB,CAEpB,MAAMC,EACJD,GAAe,4BAA4BlO,CAAO,GAEpD,MAAO,CACL,QAAAA,EACA,YAAamO,EACb,GAAI,MAAOrJ,GAAqB,CAG9B,SAAW,CAAC5F,EAAWC,CAAW,IAAK,OAAO,QAC5C8O,EAAS,OAAO,EAEhB,GAAI,CAACD,EAAW,QAAQ9O,CAAS,EAAG,MAI1BC,EAAY,KACLA,EAAY,YAChBA,EAAY,QACPA,EAAY,aAKtB,IAAI,MACR,iGAAiG,CAIzG,EACA,KAAM,MAAO2F,GAAqB,CAEhC,MAAM,IAAI,MACR,uFAAuF,CAE3F,EAEJ,CAIQ,kBAAkBmH,EAAoB,CAC5C,GAAI,CAACA,EAAU,SAAW,OAAOA,EAAU,SAAY,SACrD,MAAM,IAAI,MAAM,oDAAoD,EAGtE,GAAI,CAACA,EAAU,aAAe,OAAOA,EAAU,aAAgB,SAC7D,MAAM,IAAI,MAAM,wDAAwD,EAG1E,GAAI,OAAOA,EAAU,IAAO,WAC1B,MAAM,IAAI,MAAM,mCAAmC,EAGrD,GAAI,OAAOA,EAAU,MAAS,WAC5B,MAAM,IAAI,MAAM,qCAAqC,EAIvD,GAAI,KAAK,WAAW,IAAIA,EAAU,OAAO,EACvC,MAAM,IAAI,MACR,0BAA0BA,EAAU,OAAO,iBAAiB,CAGlE,CAEQ,kBAAkBA,EAAoB,CAI5C,GAAI,CAACA,EAAU,cAAgBA,EAAU,aAAa,SAAW,EAC/D,MAAO,CAAE,gBAAiB,GAAM,oBAAqB,CAAA,CAAE,EAGzD,MAAMW,EAAsBX,EAAU,aAAa,OAChDmC,GAAQ,CAAC,KAAK,WAAW,IAAIA,CAAG,CAAC,EAGpC,MAAO,CACL,gBAAiBxB,EAAoB,SAAW,EAChD,oBAAAA,EAEJ,CAEQ,gBAAgByB,EAAkBC,EAAgB,CAExD,MAAMC,EAAUF,EAAS,MAAM,GAAG,EAAE,IAAI,MAAM,EACxCG,EAAUF,EAAS,MAAM,GAAG,EAAE,IAAI,MAAM,EAE9C,QAASrM,EAAI,EAAGA,EAAI,KAAK,IAAIsM,EAAQ,OAAQC,EAAQ,MAAM,EAAGvM,IAAK,CACjE,MAAMwM,EAASF,EAAQtM,CAAC,GAAK,EACvByM,EAASF,EAAQvM,CAAC,GAAK,EAE7B,GAAIwM,EAASC,EAAQ,MAAO,GAC5B,GAAID,EAASC,EAAQ,QACvB,CAEA,MAAO,EACT,CAEQ,iBAAiBzC,EAAoB,CAG3C,MAAM0C,EAAU1C,EAAU,GAAG,SAAA,EAAaA,EAAU,KAAK,WACzD,IAAI2C,EAAO,EAEX,QAAS3M,EAAI,EAAGA,EAAI0M,EAAQ,OAAQ1M,IAAK,CACvC,MAAM4M,EAAOF,EAAQ,WAAW1M,CAAC,EACjC2M,GAAQA,GAAQ,GAAKA,EAAOC,EAC5BD,EAAOA,EAAOA,CAChB,CAEA,OAAOA,EAAK,SAAS,EAAE,CACzB,CACD,OC5qBYE,CAAW,CAGtB,YAAYhK,EAAiB,CAC3B,KAAK,IAAMA,CACb,CAKA,SAAShC,EAAiBzE,EAA2B,CAAA,EAAE,CACrD,MAAM0Q,EAAI,OAAA,OAAA,CACR,UAAW,IACX,MAAO,IACP,OAAQ,IACR,UAAW,GACX,eAAgB,GAChB,eAAgB,EAAI,EACjB1Q,CAAO,EAGNsD,EAAyB,CAC7B,KAAM,CAAA,EACN,QAAS,GACT,UAAW,EACX,WAAY,EACZ,YAAa,EACb,OAAQ,CAAA,GAGV,GAAI,CAACmB,GAAWA,EAAQ,OAAO,SAAW,EACxC,OAAAnB,EAAO,OAAO,KAAK,CACjB,IAAK,EACL,MAAO,mBACR,CAAA,EACMA,EAGT,GAAI,CACF,MAAMsB,EAAQ,KAAK,cAAcH,EAASiM,CAAI,EAG9C,GAFApN,EAAO,UAAYsB,EAAM,OAErBA,EAAM,SAAW,EACnB,OAAAtB,EAAO,OAAO,KAAK,CACjB,IAAK,EACL,MAAO,kCACR,CAAA,EACMA,EAIT,IAAIyB,EAAiB,EACrB,GAAI2L,EAAK,WAAa9L,EAAM,OAAS,EACnC,GAAI,CACFtB,EAAO,QAAU,KAAK,YAAYsB,EAAM,CAAC,EAAG8L,CAAI,EAC5CA,EAAK,iBACPpN,EAAO,QAAUA,EAAO,QAAQ,IAAI0B,GAAKA,EAAE,KAAA,CAAM,GAEnDD,EAAiB,CACnB,OAASnE,EAAO,CACd,OAAA0C,EAAO,OAAO,KAAK,CACjB,IAAK,EACL,MAAO,+BAAgC1C,EAAgB,OAAO,GAC9D,QAASgE,EAAM,CAAC,CACjB,CAAA,EACMtB,CACT,KACK,CAEL,MAAMqN,EAAW,KAAK,YAAY/L,EAAM,CAAC,EAAG8L,CAAI,EAChDpN,EAAO,QAAUqN,EAAS,IAAI,CAACzL,EAAGzD,IAAU,UAAUA,EAAQ,CAAC,EAAE,CACnE,CAGA,QAASmC,EAAImB,EAAgBnB,EAAIgB,EAAM,OAAQhB,IAAK,CAClD,MAAMgN,EAAahN,EAAI,EACjBiB,EAAOD,EAAMhB,CAAC,EAEpB,GAAI8M,EAAK,gBAAkB7L,EAAK,OAAO,SAAW,EAAG,CACnDvB,EAAO,cACP,QACF,CAEA,GAAI,CACF,MAAM6B,EAAS,KAAK,YAAYN,EAAM6L,CAAI,EACpCpM,EAA2B,CAAA,EAGjChB,EAAO,QAAQ,QAAQ,CAAC+B,EAAQ5D,IAAS,CACvC,IAAI2B,EAAQ+B,EAAO1D,CAAK,GAAK,KAEzBiP,EAAK,gBAAkB,OAAOtN,GAAU,WAC1CA,EAAQA,EAAM,QAIZA,IAAU,KACZA,EAAQ,MAGVkB,EAAIe,CAAM,EAAIjC,CAChB,CAAC,EAEDE,EAAO,KAAK,KAAKgB,CAAG,EACpBhB,EAAO,YACT,OAAS1C,EAAO,CACd0C,EAAO,OAAO,KAAK,CACjB,IAAKsN,EACL,MAAO,wBAAyBhQ,EAAgB,OAAO,GACvD,QAASiE,CACV,CAAA,EACDvB,EAAO,aACT,CACF,CAEA,OAAOA,CACT,OAAS1C,EAAO,CACd,OAAA0C,EAAO,OAAO,KAAK,CACjB,IAAK,EACL,MAAO,uBAAwB1C,EAAgB,OAAO,EACvD,CAAA,EACM0C,CACT,CACF,CAKA,MAAM,cACJzC,EACA4D,EACAzE,EAAqD,CAAA,EAAE,OAKjD6Q,EAAc,KAAK,SAASpM,EAASzE,CAAO,EAElD,GAAI6Q,EAAY,OAAO,OAAS,GAAKA,EAAY,KAAK,SAAW,EAC/D,MAAM,IAAI,MAAM,uBAAuBA,EAAY,OAAO,IAAIC,GAAKA,EAAE,KAAK,EAAE,KAAK,IAAI,CAAC,EAAE,EAG1F,IAAI7M,EAAgB4M,EAAY,KAG5B7Q,EAAQ,cAAgBA,EAAQ,aAAe,IACjDiE,EAAgBA,EAAc,MAAMjE,EAAQ,YAAY,GAGtDA,EAAQ,SAAWA,EAAQ,QAAU,IACvCiE,EAAgBA,EAAc,MAAM,EAAGjE,EAAQ,OAAO,GAIpDA,EAAQ,iBACViE,EAAgB,KAAK,oBAAoBA,EAAejE,EAAQ,cAAc,GAIhF,MAAMqE,EAAyC,CAAA,EACzC0M,EAAyD,CAAA,EAE/D,QAASnN,EAAI,EAAGA,EAAIK,EAAc,OAAQL,IAAK,CAC7C,MAAMU,EAAML,EAAcL,CAAC,EAC3B,IAAIoN,EAAc,OAAA,OAAA,GAAQ1M,CAAG,EAE7B,GAAI,CAEF,GAAItE,EAAQ,YAAa,CACvB,MAAMsD,EAAStD,EAAQ,YAAYgR,EAAgBpN,CAAC,EACpD,GAAIN,IAAW,KACb,SAEF0N,EAAiB1N,CACnB,CAGA,GAAItD,EAAQ,WACV,SAAW,CAAC6L,EAAOoF,CAAW,IAAK,OAAO,QAAQjR,EAAQ,SAAS,EACjE,GAAIgR,EAAe,eAAenF,CAAK,EACrC,GAAI,CACFmF,EAAenF,CAAK,EAAIoF,EAAYD,EAAenF,CAAK,EAAGmF,EAAgBpN,CAAC,CAC9E,OAAShD,EAAO,CAMd,GALAmQ,EAAgB,KAAK,CACnB,IAAKnN,EAAI,EACT,MAAO,8BAA8BiI,CAAK,MAAOjL,EAAgB,OAAO,EACzE,CAAA,EAEGZ,EAAQ,WAAY,CAEtB,GAAI,CADeA,EAAQ,WAAWY,EAAgBoQ,EAAgBpN,CAAC,EAErE,MAAMhD,EAER,QACF,CACA,MAAMA,CACR,EAMN,GAAIZ,EAAQ,UACV,SAAW,CAAC6L,EAAOqF,CAAS,IAAK,OAAO,QAAQlR,EAAQ,QAAQ,EAC9D,GAAIgR,EAAe,eAAenF,CAAK,EACrC,GAAI,CACF,MAAMsF,EAAmBD,EAAUF,EAAenF,CAAK,EAAGmF,EAAgBpN,CAAC,EAC3E,GAAIuN,IAAqB,GAAM,CAC7B,MAAMC,EAAe,OAAOD,GAAqB,SAC7CA,EACA,gCAAgCtF,CAAK,IAEnCwF,EAAkB,IAAI,MAAMD,CAAY,EAE9C,GAAIpR,EAAQ,WAAY,CAEtB,GAAI,CADeA,EAAQ,WAAWqR,EAAiBL,EAAgBpN,CAAC,EAEtE,MAAMyN,EAER,QACF,CACA,MAAMA,CACR,CACF,OAASzQ,EAAO,CACd,MAAAmQ,EAAgB,KAAK,CACnB,IAAKnN,EAAI,EACT,MAAO,+BAA+BiI,CAAK,MAAOjL,EAAgB,OAAO,EAC1E,CAAA,EACKA,CACR,EAMNoQ,EAAiB,KAAK,iBAAiBA,EAAgBhR,CAAO,EAE9DqE,EAAgB,KAAK2M,CAAc,CACrC,OAASpQ,EAAO,CACd,GAAIZ,EAAQ,YACSA,EAAQ,WAAWY,EAAgBoQ,EAAgBpN,CAAC,EAErE,SAGJ,MAAMhD,CACR,CACF,CAGA,MAAM+I,EAAe,MAAM,KAAK,IAAI,WAAW,CAC7C,UAAA9I,EACA,KAAMwD,EACN,UAAWrE,EAAQ,WAAa,IAChC,WAAYA,EAAQ,WACpB,QAASA,EAAQ,QACjB,WAAYA,EAAQ,YAAc,GAClC,aAAcA,EAAQ,eAAiB,GACvC,iBAAkBA,EAAQ,kBAAoB,GAC9C,gBAAiBA,EAAQ,gBACzB,uBAAwBA,EAAQ,wBAA0B,EAC3D,CAAA,EAGKsR,EAAY,CAChB,GAAGT,EAAY,OAAO,IAAIC,IAAM,CAC9B,SAAUA,EAAE,IAAM,EAClB,MAAOA,EAAE,MACT,QAASA,EAAE,QAAU,CAAE,KAAMA,EAAE,SAAY,EAC5C,EAAC,EACF,GAAGC,EAAgB,IAAID,IAAM,CAC3B,SAAUA,EAAE,IAAM,EAClB,MAAOA,EAAE,MACT,QAAS,CAAA,CACV,EAAC,EACF,GAAGnH,EAAa,QAGlB,OAAA,OAAA,OAAA,OAAA,OAAA,GACKA,CAAY,EAAA,CACf,OAAQ2H,EACR,YAAAT,CAAW,CAAA,CAEf,CAKA,MAAM,eACJhQ,EACA0Q,EACAvR,EAAqD,CAAA,EAAE,CAEvD,IAAIyE,EAEJ,GAAI,CAEF,GAAI,OAAO,WAAW,MAAS,aAAe,WAAW,KAAK,aAC5DA,EAAU,MAAM,WAAW,KAAK,aAAa8M,CAAQ,UAG9C,OAAO,SAAY,YAE1B9M,EAAU,MADC,QAAQ,IAAI,EAAE,SACN,SAAS8M,EAAUvR,EAAQ,UAAY,MAAM,UAGzD,OAAOuR,GAAa,UAAY,SAAUA,EACjD9M,EAAU,MAAO8M,EAAiB,KAAA,MAGlC,OAAM,IAAI,MAAM,gDAAgD,CAEpE,OAAS3Q,EAAO,CACd,MAAM,IAAI,MAAM,4BAA4B2Q,CAAQ,MAAO3Q,EAAgB,OAAO,EAAE,CACtF,CAEA,OAAO,MAAM,KAAK,cAAcC,EAAW4D,EAASzE,CAAO,CAC7D,CAKA,MAAM,YACJa,EACAb,EAUI,GAAE,CAEN,MAAM0Q,EAAI,OAAA,OAAA,CACR,UAAW,IACX,MAAO,IACP,eAAgB,GAChB,WAAY,sBACZ,UAAW,EAAE,EACV1Q,CAAO,EAIZ,IAAIuB,EAAM,UAAUvB,EAAQ,QAAUA,EAAQ,QAAQ,KAAK,IAAI,EAAI,GAAG,SAASa,CAAS,GACxF,MAAMmB,EAAgB,GAElBhC,EAAQ,QACVuB,GAAO,UAAUvB,EAAQ,KAAK,IAG5BA,EAAQ,UACVuB,GAAO,aAAavB,EAAQ,OAAO,IAGjCA,EAAQ,QACVuB,GAAO,UAAUvB,EAAQ,KAAK,IAIhC,MAAMsD,EAAS,MAAM,KAAK,IAAI,QAAQ/B,EAAKS,CAAM,EAEjD,GAAIsB,EAAO,KAAK,SAAW,EACzB,OAAOoN,EAAK,gBAAkB1Q,EAAQ,QAClC,KAAK,aAAaA,EAAQ,QAAS0Q,CAAI,EACvC,GAGN,MAAMc,EAAiB,GAGvB,GAAId,EAAK,eAAgB,CACvB,MAAM5L,EAAU9E,EAAQ,SAAW,OAAO,KAAKsD,EAAO,KAAK,CAAC,CAAC,EAC7DkO,EAAK,KAAK,KAAK,aAAa1M,EAAS4L,CAAI,CAAC,CAC5C,CAGA,UAAWpM,KAAOhB,EAAO,KAAM,CAC7B,MAAM6B,EAAS,OAAO,OAAOb,CAAG,EAAE,IAAIlB,GAChCA,GAAU,KACLsN,EAAK,UAEVtN,aAAiB,KACZ,KAAK,WAAWA,EAAOsN,EAAK,UAAU,EAExC,OAAOtN,CAAK,CACpB,EAEDoO,EAAK,KAAK,KAAK,aAAarM,EAAQuL,CAAI,CAAC,CAC3C,CAEA,OAAOc,EAAK,KAAK;AAAA,CAAI,CACvB,CAIQ,cAAc/M,EAAiBzE,EAAwB,CAC7D,MAAM4E,EAAkB,CAAA,EACxB,IAAI6M,EAAc,GACdC,EAAW,GAGf,QAAS9N,EAAI,EAAGA,EAAIa,EAAQ,OAAQb,IAAK,CACvC,MAAM4M,EAAO/L,EAAQb,CAAC,EAChB+N,EAAWlN,EAAQb,EAAI,CAAC,EAE9B,GAAI4M,IAASxQ,EAAQ,QAEnB0R,EAAW,CAACA,EAGRC,IAAa3R,EAAQ,OAASA,EAAQ,SAAWA,EAAQ,OAAO,CAClEyR,GAAejB,EAAOmB,EACtB/N,IAEA,QACF,CAGF,GAAI4M,IAAS;AAAA,GAAQ,CAACkB,EAAU,CAC9B,GAAI1R,EAAQ,gBAAkByR,EAAY,KAAA,EAAO,SAAW,EAAG,CAC7DA,EAAc,GACd,QACF,CACA7M,EAAM,KAAK6M,CAAW,EACtBA,EAAc,GACdC,EAAW,EAEb,SAAWlB,IAAS,MAAQmB,IAAa;AAAA,GAAQ,CAACD,EAAU,CAC1D,GAAI1R,EAAQ,gBAAkByR,EAAY,KAAA,EAAO,SAAW,EAAG,CAC7DA,EAAc,GACd7N,IACA,QACF,CACAgB,EAAM,KAAK6M,CAAW,EACtBA,EAAc,GACd7N,IACA8N,EAAW,EAEb,MACED,GAAejB,CAEnB,CAGA,OAAIiB,EAAY,OAAS,IACnB,CAACzR,EAAQ,gBAAkByR,EAAY,KAAA,EAAO,OAAS,IACzD7M,EAAM,KAAK6M,CAAW,EAInB7M,CACT,CAEQ,YAAYC,EAAc7E,EAAwB,CACxD,MAAMmF,EAAmB,CAAA,EACzB,IAAIyM,EAAe,GACfF,EAAW,GAEf,QAAS9N,EAAI,EAAGA,EAAIiB,EAAK,OAAQjB,IAAK,CACpC,MAAM4M,EAAO3L,EAAKjB,CAAC,EACb+N,EAAW9M,EAAKjB,EAAI,CAAC,EAEvB4M,IAASxQ,EAAQ,MACf0R,GAAYC,IAAa3R,EAAQ,OAASA,EAAQ,SAAWA,EAAQ,OAEvE4R,GAAgB5R,EAAQ,MACxB4D,KAEA8N,EAAW,CAACA,EAELlB,IAASxQ,EAAQ,WAAa,CAAC0R,GACxCvM,EAAO,KAAKyM,CAAY,EACxBA,EAAe,IAEfA,GAAgBpB,CAEpB,CAGA,OAAArL,EAAO,KAAKyM,CAAY,EAEjBzM,CACT,CAEQ,aAAaA,EAAkBnF,EAA6C,CAClF,OAAOmF,EAAO,IAAI/B,GAAQ,CACxB,MAAMyO,EAAW,OAAOzO,CAAK,EAG7B,OAAIyO,EAAS,SAAS7R,EAAQ,SAAS,GACnC6R,EAAS,SAAS7R,EAAQ,KAAK,GAC/B6R,EAAS,SAAS;AAAA,CAAI,GACtBA,EAAS,SAAS,IAAI,EACjB7R,EAAQ,MAAQ6R,EAAS,QAAQ,IAAI,OAAO7R,EAAQ,MAAO,GAAG,EAAGA,EAAQ,MAAQA,EAAQ,KAAK,EAAIA,EAAQ,MAG5G6R,CACT,CAAC,EAAE,KAAK7R,EAAQ,SAAS,CAC3B,CAEQ,oBACNmE,EACA2N,EAAkD,CAElD,OAAI,MAAM,QAAQA,CAAQ,EAEjB3N,EAAK,IAAIG,GAAM,CACpB,MAAMC,EAA8B,CAAA,EAEpC,OAAAuN,EAAS,QAAQtN,GAAU,CACzB,GAAIF,EAAI,eAAeE,EAAQ,YAAY,EAAG,CAC5C,IAAIpB,EAAQkB,EAAIE,EAAQ,YAAY,EAEhCA,EAAQ,YACVpB,EAAQoB,EAAQ,UAAUpB,CAAK,GAGjCmB,EAAOC,EAAQ,YAAY,EAAIpB,CACjC,CACF,CAAC,EAEMmB,CACT,CAAC,EAGMJ,EAAK,IAAIG,GAAM,CACpB,MAAMC,EAA8B,CAAA,EAEpC,OAAA,OAAO,QAAQD,CAAG,EAAE,QAAQ,CAAC,CAACnB,EAAKC,CAAK,IAAK,CAC3C,MAAM2O,EAASD,EAAS3O,CAAG,GAAKA,EAChCoB,EAAOwN,CAAM,EAAI3O,CACnB,CAAC,EAEMmB,CACT,CAAC,CAEL,CAEQ,iBACND,EACAtE,EAAyB,CAEzB,MAAMgS,EAAiC,CAAA,EAEvC,OAAA,OAAO,QAAQ1N,CAAG,EAAE,QAAQ,CAAC,CAACnB,EAAKC,CAAK,IAAK,CAC3C4O,EAAU7O,CAAG,EAAI,KAAK,aAAaC,EAAOpD,CAAO,CACnD,CAAC,EAEMgS,CACT,CAEQ,aAAa5O,EAAYpD,EAAyB,CACxD,GAAIoD,GAAU,MAA+BA,IAAU,GACrD,OAAO,KAGT,MAAMyO,EAAW,OAAOzO,CAAK,EAAE,KAAA,EAG/B,GAAIpD,EAAQ,cAAe,CACzB,MAAMiS,EAAaJ,EAAS,cAC5B,GAAI7R,EAAQ,cAAc,KAAK,KAAKuG,GAAKA,EAAE,YAAA,IAAkB0L,CAAU,EACrE,MAAO,GAET,GAAIjS,EAAQ,cAAc,MAAM,KAAKuI,GAAKA,EAAE,YAAA,IAAkB0J,CAAU,EACtE,MAAO,EAEX,KAAO,CAEL,MAAMA,EAAaJ,EAAS,YAAA,EAC5B,GAAI,CAAC,OAAQ,IAAK,MAAO,IAAI,EAAE,SAASI,CAAU,EAChD,MAAO,GAET,GAAI,CAAC,QAAS,IAAK,KAAM,KAAK,EAAE,SAASA,CAAU,EACjD,MAAO,EAEX,CAGA,GAAI,UAAU,KAAKJ,CAAQ,EAAG,CAC5B,MAAMK,EAAW,SAASL,CAAQ,EAClC,GAAI,CAAC,MAAMK,CAAQ,EACjB,OAAOA,CAEX,CAEA,GAAI,gBAAgB,KAAKL,CAAQ,EAAG,CAClC,MAAMM,EAAa,WAAWN,CAAQ,EACtC,GAAI,CAAC,MAAMM,CAAU,EACnB,OAAOA,CAEX,CAGA,GAAInS,EAAQ,YACV,UAAWoS,KAAUpS,EAAQ,YAAa,CACxC,MAAMgG,EAAO,KAAK,UAAU6L,EAAUO,CAAM,EAC5C,GAAIpM,EACF,OAAOA,EAAK,YAAA,CAEhB,KACK,CAEL,MAAMA,EAAO,IAAI,KAAK6L,CAAQ,EAC9B,GAAI,CAAC,MAAM7L,EAAK,QAAA,CAAS,GAAK6L,EAAS,MAAM,mBAAmB,EAC9D,OAAO7L,EAAK,YAAA,CAEhB,CAEA,OAAO6L,CACT,CAEQ,UAAUQ,EAAoBD,EAAc,CAElD,GAAI,CAEF,MAAMpM,EAAO,IAAI,KAAKqM,CAAU,EAChC,OAAO,MAAMrM,EAAK,QAAA,CAAS,EAAI,KAAOA,CACxC,OAAE/F,EAAM,CACN,OAAO,IACT,CACF,CAEQ,WAAW+F,EAAYoM,EAAc,CAE3C,MAAME,EAAOtM,EAAK,YAAA,EACZuM,EAAQ,OAAOvM,EAAK,SAAA,EAAa,CAAC,EAAE,SAAS,EAAG,GAAG,EACnDwM,EAAM,OAAOxM,EAAK,SAAS,EAAE,SAAS,EAAG,GAAG,EAC5CyM,EAAQ,OAAOzM,EAAK,UAAU,EAAE,SAAS,EAAG,GAAG,EAC/C0M,EAAU,OAAO1M,EAAK,WAAA,CAAY,EAAE,SAAS,EAAG,GAAG,EACnD2M,EAAU,OAAO3M,EAAK,WAAA,CAAY,EAAE,SAAS,EAAG,GAAG,EAEzD,OAAOoM,EACJ,QAAQ,OAAQ,OAAOE,CAAI,CAAC,EAC5B,QAAQ,KAAMC,CAAK,EACnB,QAAQ,KAAMC,CAAG,EACjB,QAAQ,KAAMC,CAAK,EACnB,QAAQ,KAAMC,CAAO,EACrB,QAAQ,KAAMC,CAAO,CAC1B,CAKA,OAAO,cAAcvP,EAAepD,EAIhC,CAAA,EAAE,CACJ,GAAIoD,IAAU,IAAMA,IAAU,KAAM,OAAO,KAE3C,MAAMsN,EAAI,OAAA,OAAA,CACR,YAAa,GACb,cAAe,CACb,KAAM,CAAC,OAAQ,IAAK,MAAO,IAAI,EAC/B,MAAO,CAAC,QAAS,IAAK,KAAM,KAAK,EAClC,EACE1Q,CAAO,EAGZ,GAAI,CAAC0Q,EAAK,YACR,OAAOtN,EAGT,MAAMyO,EAAW,OAAOzO,CAAK,EAAE,KAAA,EAAO,YAAA,EAGtC,GAAIsN,EAAK,cAAc,KAAK,SAASmB,CAAQ,EAC3C,MAAO,GAET,GAAInB,EAAK,cAAc,MAAM,SAASmB,CAAQ,EAC5C,MAAO,GAIT,GAAI,UAAU,KAAKzO,CAAK,EAAG,CACzB,MAAM8O,EAAW,SAAS9O,CAAK,EAC/B,GAAI,CAAC,MAAM8O,CAAQ,EAAG,OAAOA,CAC/B,CAEA,GAAI,gBAAgB,KAAK9O,CAAK,EAAG,CAC/B,MAAM+O,EAAa,WAAW/O,CAAK,EACnC,GAAI,CAAC,MAAM+O,CAAU,EAAG,OAAOA,CACjC,CAGA,MAAMnM,EAAO,IAAI,KAAK5C,CAAK,EAC3B,MAAI,CAAC,MAAM4C,EAAK,QAAA,CAAS,GAAK5C,EAAM,MAAM,mBAAmB,EACpD4C,EAAK,YAAA,EAGP5C,CACT,CAKA,OAAO,qBAAqBqB,EAAiBzE,EAA2B,CAAA,EAAE,CAOxE,MAAMsD,EAAS,CACb,QAAS,GACT,OAAQ,CAAA,EACR,SAAU,EACV,YAAa,EACb,QAAS,CAAA,GAGX,GAAI,CAEF,MAAMuN,EADW,IAAIJ,EAAY,CAAA,CAAkB,EACtB,SAAShM,EAASzE,CAAO,EAEtDsD,EAAO,SAAWuN,EAAY,UAC9BvN,EAAO,QAAUuN,EAAY,QAC7BvN,EAAO,YAAcuN,EAAY,QAAQ,OAErCA,EAAY,OAAO,OAAS,IAC9BvN,EAAO,QAAU,GACjBA,EAAO,OAASuN,EAAY,OAAO,IAAIC,GAAKA,EAAE,KAAK,GAGjDD,EAAY,KAAK,SAAW,IAC9BvN,EAAO,QAAU,GACjBA,EAAO,OAAO,KAAK,0BAA0B,GAI/C,MAAMsP,EAAmB/B,EAAY,KAAK,OAAOvM,GAC/C,OAAO,KAAKA,CAAG,EAAE,SAAWhB,EAAO,WAAW,EAG5CsP,EAAiB,OAAS,IAC5BtP,EAAO,QAAU,GACjBA,EAAO,OAAO,KAAK,GAAGsP,EAAiB,MAAM,sCAAsC,EAGvF,OAAShS,EAAO,CACd0C,EAAO,QAAU,GACjBA,EAAO,OAAO,KAAK,sBAAuB1C,EAAgB,OAAO,EAAE,CACrE,CAEA,OAAO0C,CACT,CACD,CCpxBK,MAAOuP,UAAuBhJ,CAAW,CAAA,OAkDlCiJ,CAAc,CAezB,aAAA,CAXQ,KAAA,SAAqC,IAAI,IACzC,KAAA,eAA6C,IAAI,IACjD,KAAA,gBAA6E,IAAI,IAGjF,KAAA,cAA2D,IAAI,IAG/D,KAAA,eAAiB,GACjB,KAAA,gBAAyC,KAG/C,KAAK,YAAA,EACL,KAAK,qBAAA,CACP,CAKO,OAAO,aAAW,CACvB,OAAKA,EAAe,WAClBA,EAAe,SAAW,IAAIA,GAEzBA,EAAe,QACxB,CAKO,OAAO,eAAa,CACrBA,EAAe,WACjBA,EAAe,SAAS,QAAA,EACxBA,EAAe,SAAW,KAE9B,CAEQ,aAAW,CACD,OAAO,oBAAoB,OAAO,eAAe,IAAI,CAAC,EAC9D,QAAQ/I,GAAS,CACnB,OAAQ,KAAaA,CAAM,GAAM,YAAcA,IAAW,gBAC3D,KAAaA,CAAM,EAAK,KAAaA,CAAM,EAAE,KAAK,IAAI,EAE3D,CAAC,CACH,CAKQ,iBAAiBpB,EAAoB9H,EAAiB,CAC5D,MAAO,GAAG8H,CAAU,IAAI9H,CAAS,EACnC,CAKQ,sBAAsBV,EAAqB,SACjD,GAAI,EAAC,GAAAF,EAAAE,EAAO,cAAU,MAAAF,IAAA,SAAAA,EAAE,QACtB,MAAM,IAAI,MAAM,6CAA6C,EAE/D,GAAI,EAAC,GAAAC,EAAAC,EAAO,aAAS,MAAAD,IAAA,SAAAA,EAAE,KAAA,GACrB,MAAM,IAAI,MAAM,4CAA4C,CAEhE,CAKO,gBAAgBC,EAAqB,CAC1C,KAAK,sBAAsBA,CAAM,EAEjC,MAAM4S,EAAa,KAAK,iBAAiB5S,EAAO,WAAYA,EAAO,SAAS,EAGtE6S,EAAkC,CACtC,WAAY7S,EAAO,WAAW,OAC9B,UAAWA,EAAO,UAAU,OAC5B,iBAAkBA,EAAO,kBAAoB,CAAC,IAAI,EAClD,aAAcA,EAAO,cAAgB0S,GAGvC,OAAA,KAAK,eAAe,IAAIE,EAAYC,CAAgB,EAE7C,IACT,CAKO,iBAAiBC,EAAwB,CAC9C,OAAAA,EAAQ,QAAQ9S,GAAU,KAAK,gBAAgBA,CAAM,CAAC,EAC/C,IACT,CAKQ,MAAM,sBAAsBA,EAAqB,CACvD,MAAM+S,EAAe/S,EAAO,cAAgB0S,EACtCM,EAAU,IAAID,EAAa/S,EAAO,WAAYA,EAAO,SAAS,EAEpE,OAAIA,EAAO,kBACTgT,EAAQ,oBAAoBhT,EAAO,gBAAgB,EAG9CgT,CACT,CAKO,MAAM,WAAWxK,EAAoB9H,EAAiB,CAC3D,GAAI,KAAK,eACP,MAAM,IAAI,MAAM,iCAAiC,EAGnD,MAAMkS,EAAa,KAAK,iBAAiBpK,EAAY9H,CAAS,EAGxDuS,EAAW,KAAK,gBAAgB,IAAIL,CAAU,EAMpD,GALIK,IACFA,EAAS,aAAe,IAAI,KAAA,EAAO,YAAA,GAIjC,KAAK,SAAS,IAAIL,CAAU,EAC9B,OAAO,KAAK,SAAS,IAAIA,CAAU,EAIrC,IAAI5S,EAAS,KAAK,eAAe,IAAI4S,CAAU,EAC1C5S,IACHA,EAAS,CACP,WAAAwI,EACA,UAAA9H,EACA,iBAAkB,CAAC,IAAI,EACvB,aAAcgS,GAEhB,KAAK,eAAe,IAAIE,EAAY5S,CAAM,GAG5C,GAAI,CACF,MAAMgT,EAAU,MAAM,KAAK,sBAAsBhT,CAAM,EACvD,OAAA,KAAK,SAAS,IAAI4S,EAAYI,CAAO,EAGrC,KAAK,gBAAgB,IAAIJ,EAAY,CACnC,UAAW,IAAI,OAAO,YAAA,EACtB,aAAc,IAAI,KAAA,EAAO,YAAA,CAC1B,CAAA,EAED,KAAK,KAAK,kBAAmB,CAC3B,WAAAA,EACA,WAAApK,EACA,UAAA9H,CACD,CAAA,EAEMsS,CACT,OAASvS,EAAO,CACd,MAAA,KAAK,KAAK,gBAAiB,CACzB,WAAAmS,EACA,WAAApK,EACA,UAAA9H,EACA,MAAOD,CACR,CAAA,EACKA,CACR,CACF,CAKO,mBAAmB+H,EAAoB9H,EAAiB,CAC7D,MAAMkS,EAAa,KAAK,iBAAiBpK,EAAY9H,CAAS,EAC9D,OAAO,KAAK,SAAS,IAAIkS,CAAU,GAAK,IAC1C,CAKO,MAAM,kBAAkBpK,EAAoB9H,EAAiB,CAClE,MAAMsS,EAAU,MAAM,KAAK,WAAWxK,EAAY9H,CAAS,EAC3D,OAAA,MAAMsS,EAAQ,KAAA,EACPA,CACT,CAKO,MAAM,eAAexK,EAAoB9H,EAAiB,CAC/D,MAAMkS,EAAa,KAAK,iBAAiBpK,EAAY9H,CAAS,EACxDsS,EAAU,KAAK,SAAS,IAAIJ,CAAU,EAE5C,GAAI,CAACI,EACH,MAAO,GAGT,GAAI,CACF,OAAA,MAAMA,EAAQ,MAAA,EACdA,EAAQ,QAAA,EAER,KAAK,SAAS,OAAOJ,CAAU,EAC/B,KAAK,gBAAgB,OAAOA,CAAU,EAEtC,KAAK,KAAK,oBAAqB,CAC7B,WAAAA,EACA,WAAApK,EACA,UAAA9H,CACD,CAAA,EAEM,EACT,OAASD,EAAO,CACd,YAAK,KAAK,gBAAiB,CACzB,WAAAmS,EACA,WAAApK,EACA,UAAA9H,EACA,MAAOD,CACR,CAAA,EACM,EACT,CACF,CAKO,oBAAoB+H,EAAkB,CAC3C,MAAM0K,EAA0B,CAAA,EAEhC,SAAW,CAACN,EAAYI,CAAO,IAAK,KAAK,SAAU,CACjD,KAAM,CAACG,CAAS,EAAIP,EAAW,MAAM,GAAG,EACpCO,IAAc3K,GAChB0K,EAAS,KAAKF,CAAO,CAEzB,CAEA,OAAOE,CACT,CAKO,uBAAuB1K,EAAkB,CAC9C,MAAM4K,EAAiB,CAAA,EAEvB,UAAWR,KAAc,KAAK,SAAS,OAAQ,CAC7C,KAAM,CAACO,CAAS,EAAIP,EAAW,MAAM,GAAG,EACpCO,IAAc3K,GAChB4K,EAAK,KAAKR,CAAU,CAExB,CAEA,OAAOQ,CACT,CAKO,MAAM,wBAAwB5K,EAAkB,CAGrD,MAAM6K,EAFc,KAAK,uBAAuB7K,CAAU,EAEtB,IAAI,MAAMoK,GAAa,CACzD,KAAM,CAAA,CAAGlS,CAAS,EAAIkS,EAAW,MAAM,GAAG,EAC1C,OAAO,KAAK,eAAepK,EAAY9H,CAAS,CAClD,CAAC,EAED,MAAM,QAAQ,IAAI2S,CAAe,CACnC,CAKO,mBAAiB,CACtB,MAAMC,EAAuB,CAAA,EAG7B,SAAW,CAACV,EAAY5S,CAAM,IAAK,KAAK,eAAgB,CACtD,MAAMgT,EAAU,KAAK,SAAS,IAAIJ,CAAU,EACtCK,EAAW,KAAK,gBAAgB,IAAIL,CAAU,EAEpDU,EAAM,KAAK,CACT,IAAKV,EACL,WAAY5S,EAAO,WACnB,UAAWA,EAAO,UAClB,OAAQgT,EAAUA,EAAQ,UAAA,EAAc,CACtC,WAAYhT,EAAO,WACnB,UAAWA,EAAO,UAClB,SAAU,GACV,cAAe,GACf,OAAQ,EACT,EACD,aAAc,GACd,WAAWiT,GAAQ,YAARA,EAAU,YAAa,MAClC,aAAcA,GAAQ,KAAA,OAARA,EAAU,YACzB,CAAA,CACH,CAGA,SAAW,CAACL,EAAYI,CAAO,IAAK,KAAK,SACvC,GAAI,CAAC,KAAK,eAAe,IAAIJ,CAAU,EAAG,CACxC,KAAM,CAACpK,EAAY9H,CAAS,EAAIkS,EAAW,MAAM,GAAG,EAC9CK,EAAW,KAAK,gBAAgB,IAAIL,CAAU,EAEpDU,EAAM,KAAK,CACT,IAAKV,EACL,WAAApK,EACA,UAAA9H,EACA,OAAQsS,EAAQ,UAAA,EAChB,aAAc,GACd,WAAWC,GAAQ,YAARA,EAAU,YAAa,MAClC,aAAcA,GAAQ,KAAA,OAARA,EAAU,YACzB,CAAA,CACH,CAGF,OAAOK,CACT,CAKO,MAAM,aAAW,CAEtB,MAAMC,EADW,MAAM,KAAK,KAAK,SAAS,QAAA,CAAS,EACnB,IAAI,MAAO,CAACX,EAAYI,CAAO,IAAK,CAClE,GAAI,CACF,MAAMQ,EAAS,MAAMR,EAAQ,YAAA,EAC7B,OAAA,OAAA,OAAA,OAAA,OAAA,CAAA,EAAYQ,CAAM,EAAA,CAAE,WAAAZ,CAAU,CAAA,CAChC,OAASnS,EAAO,CACd,KAAM,CAAC+H,EAAY9H,CAAS,EAAIkS,EAAW,MAAM,GAAG,EACpD,MAAO,CACL,QAAS,GACT,WAAApK,EACA,MAAQ/H,EAAgB,QACxB,UAAW,IAAI,KAAA,EAAO,YAAA,EACtB,WAAAmS,EAEJ,CACF,CAAC,EAEKrI,EAAU,MAAM,QAAQ,IAAIgJ,CAAc,EAC1CE,EAAelJ,EAAQ,OAAOmJ,GAAKA,EAAE,OAAO,EAAE,OAE9CC,EAAuB,CAC3B,cAAepJ,EAAQ,OACvB,gBAAiBkJ,EACjB,kBAAmBlJ,EAAQ,OAASkJ,EACpC,SAAUlJ,EACV,UAAW,IAAI,OAAO,YAAA,EACtB,cAAekJ,IAAiBlJ,EAAQ,QAG1C,OAAA,KAAK,KAAK,yBAA0B,CAClC,WAAY,IACZ,WAAY,IACZ,UAAW,IACX,KAAMoJ,CACP,CAAA,EAEMA,CACT,CAMO,MAAM,yBACXnL,EACAC,EAAiD,CAEjD,MAAMyK,EAAW,KAAK,oBAAoB1K,CAAU,EAEpD,GAAI0K,EAAS,SAAW,EACtB,MAAM,IAAI,MAAM,iCAAiC1K,CAAU,EAAE,EAI/D,UAAWwK,KAAWE,EACpB,MAAMF,EAAQ,KAAA,EAMhB,OAAO,MAFgBE,EAAS,CAAC,EAEL,mBAAmB,SACtC,MAAMzK,EAASyK,CAAQ,CAC/B,CACH,CAKQ,sBAAoB,CAE1B,KAAK,gBAAkB,YAAY,IAAK,CACtC,KAAK,sBAAA,CACP,EAAG,IAAS,GAAI,CAClB,CAKQ,MAAM,sBAAsBU,EAAsB,KAAU,IAAI,CACtE,GAAI,KAAK,eACP,OAGF,MAAMC,EAAM,KAAK,IAAA,EACXC,EAA8B,CAAA,EAEpC,SAAW,CAAClB,EAAYK,CAAQ,IAAK,KAAK,gBAAiB,CACzD,GAAI,CAACA,EAAS,aACZ,SAGF,MAAMc,EAAiB,IAAI,KAAKd,EAAS,YAAY,EAAE,QAAA,EACnDY,EAAME,EAAiBH,GACzBE,EAAkB,KAAKlB,CAAU,CAErC,CAEA,UAAWA,KAAckB,EAAmB,CAC1C,KAAM,CAACtL,EAAY9H,CAAS,EAAIkS,EAAW,MAAM,GAAG,EACpD,MAAM,KAAK,eAAepK,EAAY9H,CAAS,CACjD,CACF,CAKO,GAAGsT,EAAmBlJ,EAAmC,CAC9D,OAAK,KAAK,cAAc,IAAIkJ,CAAS,GACnC,KAAK,cAAc,IAAIA,EAAW,CAAA,CAAE,EAEtC,KAAK,cAAc,IAAIA,CAAS,EAAG,KAAKlJ,CAAO,EACxC,IACT,CAEO,IAAIkJ,EAAmBlJ,EAAmC,CAC/D,MAAMC,EAAW,KAAK,cAAc,IAAIiJ,CAAS,EACjD,GAAIjJ,EAAU,CACZ,MAAMzJ,EAAQyJ,EAAS,QAAQD,CAAO,EAClCxJ,EAAQ,IACVyJ,EAAS,OAAOzJ,EAAO,CAAC,CAE5B,CACA,OAAO,IACT,CAEQ,KACNoE,EACA1B,EAAqD,CAErD,MAAM6G,EAAK,OAAA,OAAA,OAAA,OAAA,CAAA,EACN7G,CAAI,EAAA,CACP,KAAA0B,EACA,UAAW,IAAI,KAAA,EAAO,YAAA,IAIlBqF,EAAW,KAAK,cAAc,IAAIrF,CAAI,EACxCqF,GACFA,EAAS,QAAQD,GAAU,CACzB,GAAI,CACFA,EAAQD,CAAK,CACf,OAASpK,EAAO,CACd,QAAQ,MAAM,4BAA4BiF,CAAI,kBAAmBjF,CAAK,CACxE,CACF,CAAC,EAIH,MAAMwT,EAAiB,KAAK,cAAc,IAAI,GAAG,EAC7CA,GACFA,EAAe,QAAQnJ,GAAU,CAC/B,GAAI,CACFA,EAAQD,CAAK,CACf,OAASpK,EAAO,CACd,QAAQ,MAAM,iDAAkDA,CAAK,CACvE,CACF,CAAC,CAEL,CAKO,WAAW+H,EAAoB9H,EAAiB,CACrD,MAAMkS,EAAa,KAAK,iBAAiBpK,EAAY9H,CAAS,EAC9D,OAAO,KAAK,SAAS,IAAIkS,CAAU,CACrC,CAEO,aAAapK,EAAoB9H,EAAiB,CACvD,MAAMkS,EAAa,KAAK,iBAAiBpK,EAAY9H,CAAS,EAC9D,OAAO,KAAK,eAAe,IAAIkS,CAAU,CAC3C,CAEO,iBAAe,CACpB,OAAO,KAAK,SAAS,IACvB,CAEO,oBAAkB,CACvB,OAAO,KAAK,eAAe,IAC7B,CAEO,YAAU,CACf,MAAM1L,EAAU,IAAI,IAEpB,UAAW0L,KAAc,KAAK,SAAS,KAAA,EAAQ,CAC7C,KAAM,CAACpK,CAAU,EAAIoK,EAAW,MAAM,GAAG,EACzC1L,EAAQ,IAAIsB,CAAU,CACxB,CAEA,OAAO,MAAM,KAAKtB,CAAO,CAC3B,CAKO,MAAM,SAAO,CAClB,KAAK,eAAiB,GAGlB,KAAK,kBACP,cAAc,KAAK,eAAe,EAClC,KAAK,gBAAkB,MAIzB,MAAMmM,EAAkB,MAAM,KAAK,KAAK,SAAS,QAAA,CAAS,EAAE,IAC1D,MAAO,CAACT,EAAYI,CAAO,IAAK,CAC9B,GAAI,CACF,MAAMA,EAAQ,MAAA,EACdA,EAAQ,QAAA,CACV,OAASvS,EAAO,CACd,QAAQ,MAAM,4BAA4BmS,CAAU,IAAKnS,CAAK,CAChE,CACF,CAAC,EAGH,MAAM,QAAQ,IAAI4S,CAAe,EAGjC,KAAK,SAAS,MAAA,EACd,KAAK,eAAe,MAAA,EACpB,KAAK,gBAAgB,QACrB,KAAK,cAAc,MAAA,EAEnB,KAAK,eAAiB,EACxB,EAriBeV,EAAA,SAAkC,KAyiBrBA,EAAe,YAAA,QC/lBvBuB,CAAW,CAIrB,YAAY9S,EAAW,CAC/B,OAAOA,EAAI,MACb,CAEU,eAAeA,EAAaS,EAAc,CAClD,GAAI,CAACA,GAAUA,EAAO,SAAW,EAC/B,OAAOT,EAGT,IAAI+S,EAAa,EACjB,OAAO/S,EAAI,QAAQ,MAAO,IAAK,CAC7B,GAAI+S,EAAatS,EAAO,OAAQ,CAC9B,MAAM0L,EAAQ1L,EAAOsS,GAAY,EACjC,OAAI,OAAO5G,GAAU,SACZ,IAAIA,EAAM,QAAQ,KAAM,IAAI,CAAC,IAElCA,GAAU,KACL,OAEF,OAAOA,CAAK,CACrB,CACA,MAAO,GACT,CAAC,CACH,CACD,OC+BY6G,CAAe,CAQ1B,aAAA,CAEE,GARM,KAAA,cAA+B,KAC/B,KAAA,cAAyB,GACzB,KAAA,sBAA8C,KAC9C,KAAA,eACN,IAAI,IAIAA,EAAgB,SAClB,MAAM,IAAI,MACR,4EAA4E,CAGlF,CAKA,OAAO,aAAW,CAChB,OAAKA,EAAgB,WACnBA,EAAgB,SAAW,IAAIA,GAE1BA,EAAgB,QACzB,CAKA,OAAO,eAAa,CACdA,EAAgB,UAClBA,EAAgB,SAAS,SAAA,EAAW,MAAM,IAAK,CAAE,CAAC,EAEpDA,EAAgB,SAAW,IAC7B,CASA,MAAM,WACJlN,EACArH,EAKI,CAAA,EAAE,CAEN,OAAI,KAAK,cACA,KAAK,uBAAyB,QAAQ,QAAA,EAG3C,KAAK,sBACA,KAAK,uBAGd,KAAK,sBAAwB,KAAK,uBAAuBqH,EAASrH,CAAO,EAClE,KAAK,sBACd,CAEQ,MAAM,uBACZqH,EACArH,EAKC,CAED,GAAI,CAEEA,EAAQ,kBACVA,EAAQ,iBAAiB,QAASF,GAAW,CAC3C0G,EAAgB,gBAAgB1G,CAAO,CACzC,CAAC,EAICE,EAAQ,oBACV,KAAK,GAAG,QAASA,EAAQ,kBAAkB,EAI7CiH,EAAgB,gBAAgBI,CAAO,EAGnCA,EAAQ,MAAQrH,EAAQ,kBAAoB,IAC9C,MAAMiH,EAAgB,2BAIpBjH,EAAQ,cAAgBA,EAAQ,aAAa,OAAS,GACxD,MAAMiH,EAAgB,oBAAoBjH,EAAQ,YAAY,EAGhE,KAAK,cAAgB,GACrB,KAAK,MAAM,cAAe,CAAE,QAAS,OAAO,KAAKqH,CAAO,CAAC,CAAE,CAC7D,OAASzG,EAAO,CACd,WAAK,cAAgB,GACrB,KAAK,sBAAwB,KAC7B,KAAK,MAAM,QAASA,EAAgB,gBAAgB,EAC9CA,CACR,CACF,CAKA,MAAM,qBACJF,EACAV,EAII,GAAE,CAEN,MAAMqH,EAAU,CAAE,CAAC3G,EAAO,aAAa,EAAGA,CAAM,EAChD,OAAO,KAAK,WAAW2G,iCAClBrH,CAAO,EAAA,CACV,gBAAiBA,EAAQ,cAAgB,KAE7C,CASA,MAAM,QAAQ2I,EAAkB,CAC9B,KAAK,kBAAA,EACL,KAAK,cAAgBA,EAErB,GAAI,CACF,MAAMlC,EAAM,MAAMQ,EAAgB,eAAe0B,CAAU,EAC3D,OAAA,KAAK,MAAM,YAAa,CAAE,WAAAA,CAAU,CAAE,EAC/BlC,CACT,OAAS7F,EAAO,CACd,MAAA,KAAK,MAAM,QAASA,EAAgB,YAAY,EAC1CA,CACR,CACF,CAMA,OAAO+H,EAAmB,CACxB,KAAK,kBAAA,EACL,MAAMjI,EAASiI,GAAc,KAAK,cAElC,GAAI,CAACjI,EACH,MAAM,IAAI,MACR,2EAA2E,EAI/E,GAAI,CACF,OAAOuG,EAAgB,IAAIvG,CAAM,CACnC,OAASE,EAAO,CACd,MAAA,KAAK,MAAM,QAASA,EAAgB,QAAQ,EACtCA,CACR,CACF,CAKA,eAAa,CACX,GAAI,CAAC,KAAK,cACR,MAAM,IAAI,MAAM,8CAA8C,EAEhE,OAAO,KAAK,OAAO,KAAK,aAAa,CACvC,CAKA,MAAM,yBAAyB+H,EAAkB,CAC/C,KAAK,oBAEL,GAAI,CACF,OAAO,MAAM1B,EAAgB,yBAAyB0B,CAAU,CAClE,OAAS/H,EAAO,CACd,MAAA,KAAK,MAAM,QAASA,EAAgB,kBAAkB,EAChDA,CACR,CACF,CASA,cACEC,EACA8H,EAAmB,CAEnB,MAAMjI,EAASiI,GAAc,KAAK,cAClC,GAAI,CAACjI,EACH,MAAM,IAAI,MACR,2EAA2E,EAG/E,MAAMwS,EAAe,cAAcrJ,CAAc,CAC/C,aAAA,CACE,GAAI,CAACnJ,EACH,MAAM,IAAI,MACR,2EAA2E,EAG/E,MAAMA,EAAQG,CAAS,CACzB,GAGF,OAAO,IAAIqS,CACb,CAKA,eACEsB,EACA7L,EAAmB,CAEnB,MAAM0K,EAA2C,CAAA,EAEjD,OAAAmB,EAAW,QAAS3T,GAAa,CAC/BwS,EAASxS,CAAS,EAAI,KAAK,cAAiBA,EAAW8H,CAAU,CACnE,CAAC,EAEM0K,CACT,CAOA,MAAMxS,EAAoB8H,EAAmB,CAC3C,MAAMlC,EAAM,KAAK,OAAOkC,CAAU,EAElC,OAAI9H,EACKyK,EAAa,MAAMzK,EAAW4F,CAAG,EAGnC,IAAI6E,EAAa7E,CAAG,CAC7B,CAKA,MAAM5F,EAAmB8H,EAAmB,CAC1C,OAAO,KAAK,MAAM9H,EAAW8H,CAAU,CACzC,CAKA,MAAM,QACJpH,EACAS,EACA2G,EAAmB,CAEnB,GAAI,CAEF,MAAMrF,EAAS,MADH,KAAK,OAAOqF,CAAU,EACT,QAAQpH,EAAKS,CAAM,EAC5C,OAAA,KAAK,MAAM,gBAAiB,CAC1B,IAAAT,EACA,OAAAS,EACA,SAAUsB,EAAO,YAClB,CAAA,EACMA,CACT,OAAS1C,EAAO,CACd,MAAA,KAAK,MAAM,QAASA,EAAgB,SAAS,EACvCA,CACR,CACF,CAKA,MAAM,OACJW,EACAS,EACA2G,EAAmB,CAGnB,OAAO,MADK,KAAK,OAAOA,CAAU,EACjB,OAAOpH,EAAKS,CAAM,CACrC,CAKA,MAAM,QACJT,EACAS,EACA2G,EAAmB,CAGnB,OAAO,MADK,KAAK,OAAOA,CAAU,EACjB,QAAQpH,EAAKS,CAAM,CACtC,CAOA,MAAM,iBACJtB,EACA+T,EAAyB,GAAK,CAE9B,GAAI,CAKF,MAJY,MAAMjO,EAAgB,aAChC,CAAE,OAAQ9F,CAAM,EAChB+T,CAAa,GAEL,qBAAqB/T,CAAM,EACrC,KAAK,MAAM,oBAAqB,CAAE,WAAYA,EAAO,aAAa,CAAE,CACtE,OAASE,EAAO,CACd,MAAA,KAAK,MAAM,QAASA,EAAgB,sBAAsB,EACpDA,CACR,CACF,CAKA,MAAM,iBAAiB+H,EAAmB,CAExC,OAAO,MADK,KAAK,OAAOA,CAAU,EACjB,kBACnB,CAKA,MAAM,gBAAgBA,EAAmB,CAEvC,OAAO,MADK,KAAK,OAAOA,CAAU,EACjB,gBAAA,CACnB,CAKA,MAAM,aAAa9H,EAAmB8H,EAAmB,CAEvD,OAAO,MADK,KAAK,OAAOA,CAAU,EACjB,aAAa9H,CAAS,CACzC,CAOA,uBAAuB8H,EAAmB,CACxC,MAAMlC,EAAM,KAAK,OAAOkC,CAAU,EAClC,OAAO,IAAIgF,EAAiBlH,CAAG,CACjC,CAKA,MAAM,cACJoH,EAMAlF,EACA6F,EAAsB,CAEtB,MAAMkG,EAAmB,KAAK,uBAAuB/L,CAAU,EAE/DkF,EAAW,QAASD,GAAa,CAC/B8G,EAAiB,aAAa9G,CAAS,CACzC,CAAC,EAED,MAAM8G,EAAiB,QAAQlG,CAAa,EAC5C,KAAK,MAAM,sBAAuB,CAChC,WAAY7F,GAAc,KAAK,aAChC,CAAA,CACH,CAOA,kBAAkBA,EAAmB,CACnC,MAAMlC,EAAM,KAAK,OAAOkC,CAAU,EAClC,OAAO,IAAI8H,EAAYhK,CAAG,CAC5B,CAKA,MAAM,WACJkC,EACA9H,EACAsD,EACAnE,EAAgC,CAEhC,GAAI,CACF,MAAMsD,EAAS,MAAM2D,EAAgB,kBACnC0B,EACA9H,EACAsD,EACAnE,CAAO,EAET,YAAK,MAAM,eAAgB,CACzB,WAAA2I,EACA,UAAA9H,EACA,YAAayC,EAAO,WACrB,CAAA,EACMA,CACT,OAAS1C,EAAO,CACd,WAAK,MAAM,QAASA,EAAgB,YAAY,EAC1CA,CACR,CACF,CAKA,MAAM,sBACJ+H,EACA9H,EACAsD,EACAC,EACApE,EAAgC,CAEhC,GAAI,CACF,MAAMsD,EAAS,MAAM2D,EAAgB,sBACnC0B,EACA9H,EACAsD,EACAC,EACApE,CAAO,EAET,OAAA,KAAK,MAAM,eAAgB,CACzB,WAAA2I,EACA,UAAA9H,EACA,YAAayC,EAAO,WACrB,CAAA,EACMA,CACT,OAAS1C,EAAO,CACd,MAAA,KAAK,MAAM,QAASA,EAAgB,uBAAuB,EACrDA,CACR,CACF,CAKA,MAAM,cACJ+H,EACA9H,EACA4D,EACAzE,EAI0B,CAE1B,GAAI,CACF,MAAMsD,EAAS,MAAM2D,EAAgB,cACnC0B,EACA9H,EACA4D,EACAzE,CAAO,EAET,OAAA,KAAK,MAAM,cAAe,CACxB,WAAA2I,EACA,UAAA9H,EACA,YAAayC,EAAO,WACrB,CAAA,EACMA,CACT,OAAS1C,EAAO,CACd,MAAA,KAAK,MAAM,QAASA,EAAgB,WAAW,EACzCA,CACR,CACF,CAKA,MAAM,YACJC,EACA8H,EACA3I,EAOC,CAGD,OAAO,MADU,KAAK,kBAAkB2I,CAAU,EAC5B,YAAY9H,EAAWb,CAAO,CACtD,CAOA,MAAM,aAAa2U,EAAiB5M,EAAoB,CACtD,KAAK,kBAAA,EAEL,GAAI,CACF,MAAMd,EAAgB,oBAAoB0N,EAAO5M,CAAW,EAC5D,KAAK,MAAM,eAAgB,CAAE,MAAA4M,EAAO,YAAA5M,CAAW,CAAE,CACnD,OAASnH,EAAO,CACd,MAAA,KAAK,MAAM,QAASA,EAAgB,cAAc,EAC5CA,CACR,CACF,CAKA,qBAAmB,CACjB,OAAOqG,EAAgB,oBAAA,CACzB,CAKA,gBAAc,CACZ,OAAOA,EAAgB,gBACzB,CAKA,oBAAoBmB,EAAa,CAC/B,OAAOnB,EAAgB,oBAAoBmB,CAAK,CAClD,CAOA,MAAM,mBACJf,EACAuB,EAA+D,CAE/D,GAAI,CACF,MAAM3B,EAAgB,8BAA8BI,EAASuB,CAAQ,EACrE,KAAK,MAAM,uBAAwB,CAAE,QAAAvB,CAAO,CAAE,CAChD,OAASzG,EAAO,CACd,MAAA,KAAK,MAAM,QAASA,EAAgB,aAAa,EAC3CA,CACR,CACF,CAKA,MAAM,4BACJgI,EAA2C,CAE3C,MAAMnC,EAAM,KAAK,gBAEjB,GAAI,CACF,MAAMA,EAAI,mBACV,MAAMnD,EAAS,MAAMsF,EAASnC,CAAG,EACjC,aAAMA,EAAI,kBAAA,EACHnD,CACT,OAAS1C,EAAO,CACd,MAAA,MAAM6F,EAAI,oBAAA,EACJ7F,CACR,CACF,CAOA,gBAAc,CACZ,OAAO4F,EAAgB,mBAAA,CACzB,CAKA,qBAAmB,CAQjB,MAAO,CACL,cAAe,KAAK,cACpB,cAAe,KAAK,cACpB,kBAAmBS,EAAgB,gBAAA,EACnC,gBAAiBA,EAAgB,mBAAA,EACjC,UAAW,KAAK,oBAAA,EAChB,YAAa,KAAK,eAAA,EAEtB,CAKA,qBAAmB,CACjB,OAAOA,EAAgB,oBAAA,CACzB,CAKA,MAAM,aAAW,CAGf,MAAM2N,EAAc3N,EAAgB,eAAA,EAC9B4N,EACJ,CAAA,EAEF,SAAW,CAAClM,EAAYlC,CAAG,IAAK,OAAO,QAAQmO,CAAW,EACxD,GAAI,CACF,MAAMnO,EAAI,QAAQ,UAAU,EAC5BoO,EAAalM,CAAU,EAAI,CAAE,QAAS,EAAI,CAC5C,OAAS/H,EAAO,CACdiU,EAAalM,CAAU,EAAI,CACzB,QAAS,GACT,MAAQ/H,EAAgB,QAE5B,CAGF,OAAOiU,CACT,CAOA,GAAG7J,EAAeC,EAAiC,CACjD,OAAK,KAAK,eAAe,IAAID,CAAK,GAChC,KAAK,eAAe,IAAIA,EAAO,CAAA,CAAE,EAEnC,KAAK,eAAe,IAAIA,CAAK,EAAG,KAAKC,CAAO,EACrC,IACT,CAKA,IAAID,EAAeC,EAAiC,CAClD,MAAMC,EAAW,KAAK,eAAe,IAAIF,CAAK,EAC9C,GAAIE,EAAU,CACZ,MAAMzJ,EAAQyJ,EAAS,QAAQD,CAAO,EAClCxJ,EAAQ,IACVyJ,EAAS,OAAOzJ,EAAO,CAAC,CAE5B,CACA,OAAO,IACT,CAKQ,MAAMuJ,KAAkB8J,EAAW,CACzC,MAAM5J,EAAW,KAAK,eAAe,IAAIF,CAAK,EAC1CE,GACFA,EAAS,QAASD,GAAW,CAC3B,GAAI,CACFA,EAAQ,GAAG6J,CAAI,CACjB,OAASlU,EAAO,CAEd,QAAQ,MAAM,0BAA2BA,CAAK,CAChD,CACF,CAAC,CAEL,CAOA,MAAM,gBAAgB+H,EAAkB,CACtC,GAAI,CACF,MAAM1B,EAAgB,gBAAgB0B,CAAU,EAE5C,KAAK,gBAAkBA,IACzB,KAAK,cAAgB,MAGvB,KAAK,MAAM,mBAAoB,CAAE,WAAAA,CAAU,CAAE,CAC/C,OAAS/H,EAAO,CACd,MAAA,KAAK,MAAM,QAASA,EAAgB,iBAAiB,EAC/CA,CACR,CACF,CAKA,MAAM,UAAQ,CACZ,GAAI,CACF,MAAMqG,EAAgB,SAAA,EACtB,KAAK,cAAgB,KACrB,KAAK,cAAgB,GACrB,KAAK,sBAAwB,KAC7B,KAAK,eAAe,MAAA,EACpB,KAAK,MAAM,sBAAsB,CACnC,OAASrG,EAAO,CACd,MAAA,KAAK,MAAM,QAASA,EAAgB,UAAU,EACxCA,CACR,CACF,CAKA,MAAM,QAAM,CACV,GAAI,CACF,MAAMqG,EAAgB,OAAA,EACtB,KAAK,cAAgB,KACrB,KAAK,MAAM,eAAe,CAC5B,OAASrG,EAAO,CACd,MAAA,KAAK,MAAM,QAASA,EAAgB,QAAQ,EACtCA,CACR,CACF,CAOA,OAAO,gBAAgBd,EAAsB,CAC3C0G,EAAgB,gBAAgB1G,CAAO,CACzC,CAKA,OAAO,aAAa0H,EAKnB,CACCP,EAAgB,aAAaO,CAAU,CACzC,CAKA,OAAO,cACLC,EAKE,CAEFR,EAAgB,cAAcQ,CAAW,CAC3C,CAIQ,mBAAiB,CACvB,GAAI,CAAC,KAAK,cACR,MAAM,IAAI,MACR,2DAA2D,CAGjE,EAjxBe8M,EAAA,SAAmC,KAyxB7C,MAAMQ,EAAqB,CAChChV,EACAC,IAMOwG,EAAgB,UAAUzG,EAAQC,CAAO,EAMrCgV,EAA2B,MACtCtU,EACAV,IAEO,MAAMwG,EAAgB,iBAAiB9F,EAAQV,CAAO,EAMlDiV,EAAuB,MAClCtO,EACA3G,IAEO,MAAMwG,EAAgB,aAAaG,EAAQ3G,CAAO,EAM9CkV,EAAsBzO,GAC1B,IAAI6E,EAAa7E,CAAG,EAMhB0O,EAAoB,CAC/BxM,EACA9H,IAEO,IAAK,cAAcgJ,CAAc,CACtC,aAAA,CACE,MAAMlB,EAAY9H,CAAS,CAC7B,CACD,EAMUuU,EAA0B3O,GAC9B,IAAIkH,EAAiBlH,CAAG,EAMpB4O,EAAqB5O,GACzB,IAAIgK,EAAYhK,CAAG,EAQf6O,EAAuB,MAAOnV,GAKZ,CAC7B,MAAMoV,EAAShB,EAAgB,YAAA,EAE/B,OAAA,MAAMgB,EAAO,WAAWpV,EAAO,QAAS,CACtC,iBAAkBA,EAAO,SACzB,aAAcA,EAAO,YACtB,CAAA,EAEGA,EAAO,aACT,MAAMoV,EAAO,QAAQpV,EAAO,WAAW,EAGlCoV,CACT,EAKaC,EAAuB,MAClC9U,EACAV,IAI2D,CAC3D,MAAMuV,EAAShB,EAAgB,cAE/B,MAAMgB,EAAO,qBAAqB7U,EAAQ,CACxC,iBAAkBV,GAAO,MAAPA,EAAS,QAAU,CAACA,EAAQ,OAAO,EAAI,OACzD,YAAaA,GAAO,KAAA,OAAPA,EAAS,WACvB,CAAA,EAED,MAAMyG,GACJzG,GAAO,KAAA,OAAPA,EAAS,eAAgB,GACrB,MAAMuV,EAAO,QAAQ7U,EAAO,aAAa,EACzC6U,EAAO,OAAO7U,EAAO,aAAa,EAExC,MAAO,CAAE,OAAA6U,EAAQ,IAAA9O,EACnB,EAOMgP,EAAkBlB,EAAgB,YAAA"}
|
|
1
|
+
{"version":3,"file":"index.umd.js","sources":["../src/core/universal-dao.ts","../src/core/database-factory.ts","../src/core/database-manager.ts","../src/core/base-service.ts","../src/query/query-builder.ts","../src/core/service-manager.ts","../src/adapters/base-adapter.ts","../src/index.ts"],"sourcesContent":["// src/core/universal-dao.ts\r\nimport {\r\n ColumnDefinition,\r\n DatabaseSchema,\r\n ImportOptions,\r\n ImportResult,\r\n IndexDefinition,\r\n QueryTable,\r\n SQLiteAdapter,\r\n SQLiteConnection,\r\n SQLiteResult,\r\n SQLiteRow,\r\n TableDefinition,\r\n TypeMappingConfig,\r\n WhereClause,\r\n ColumnMapping\r\n} from \"../types\";\r\n\r\nexport class UniversalDAO {\r\n private connection: SQLiteConnection | null = null;\r\n private isConnected: boolean = false;\r\n private inTransaction: boolean = false;\r\n private typeMappingConfig: TypeMappingConfig[\"type_mapping\"] | null = null;\r\n private createIfNotExists: boolean = false;\r\n private forceRecreate: boolean = false;\r\n\r\n constructor(\r\n private adapter: SQLiteAdapter,\r\n private dbPath: string,\r\n private options?: {\r\n createIfNotExists?: boolean; // Mặc định false - không tạo mới nếu đã tồn tại\r\n forceRecreate?: boolean; // Mặc định false - ép tạo lại = true\r\n }\r\n ) {\r\n this.createIfNotExists = options?.createIfNotExists ?? false;\r\n this.forceRecreate = options?.forceRecreate ?? false;\r\n }\r\n\r\n async connect(): Promise<void> {\r\n if (this.isConnected) {\r\n return;\r\n }\r\n\r\n this.connection = await this.adapter.connect(this.dbPath);\r\n this.isConnected = true;\r\n }\r\n\r\n async disconnect(): Promise<void> {\r\n if (this.connection && this.isConnected) {\r\n await this.connection.close();\r\n this.connection = null;\r\n this.isConnected = false;\r\n }\r\n }\r\n\r\n async close(): Promise<void> {\r\n await this.disconnect();\r\n }\r\n\r\n // Type mapping utilities\r\n setTypeMappingConfig(config: TypeMappingConfig[\"type_mapping\"]): void {\r\n this.typeMappingConfig = config;\r\n }\r\n\r\n private convertToSQLiteType(genericType: string): string {\r\n if (!this.typeMappingConfig || !this.typeMappingConfig.sqlite) {\r\n return this.getDefaultSQLiteType(genericType);\r\n }\r\n\r\n const sqliteMapping = this.typeMappingConfig.sqlite;\r\n return sqliteMapping[genericType.toLowerCase()] || \"TEXT\";\r\n }\r\n\r\n private getDefaultSQLiteType(genericType: string): string {\r\n const defaultMapping: Record<string, string> = {\r\n string: \"TEXT\",\r\n varchar: \"TEXT\",\r\n char: \"TEXT\",\r\n email: \"TEXT\",\r\n url: \"TEXT\",\r\n uuid: \"TEXT\",\r\n integer: \"INTEGER\",\r\n bigint: \"INTEGER\",\r\n smallint: \"INTEGER\",\r\n tinyint: \"INTEGER\",\r\n decimal: \"REAL\",\r\n numeric: \"REAL\",\r\n float: \"REAL\",\r\n double: \"REAL\",\r\n boolean: \"INTEGER\",\r\n timestamp: \"TEXT\",\r\n datetime: \"TEXT\",\r\n date: \"TEXT\",\r\n time: \"TEXT\",\r\n json: \"TEXT\",\r\n array: \"TEXT\",\r\n blob: \"BLOB\",\r\n binary: \"BLOB\",\r\n };\r\n return defaultMapping[genericType.toLowerCase()] || \"TEXT\";\r\n }\r\n\r\n private processColumnDefinition(col: ColumnDefinition): ColumnDefinition {\r\n const processedCol: ColumnDefinition = { ...col };\r\n processedCol.type = this.convertToSQLiteType(col.type);\r\n\r\n const options: string[] = [];\r\n if (col.constraints) {\r\n const constraints = col.constraints.toUpperCase().split(\" \");\r\n if (constraints.includes(\"PRIMARY\")) {\r\n options.push(\"PRIMARY KEY\");\r\n processedCol.primary_key = true;\r\n }\r\n if (\r\n constraints.includes(\"AUTO_INCREMENT\") ||\r\n constraints.includes(\"AUTOINCREMENT\")\r\n ) {\r\n if (processedCol.primary_key) options.push(\"AUTOINCREMENT\");\r\n processedCol.auto_increment = true;\r\n }\r\n if (constraints.includes(\"NOT\") && constraints.includes(\"NULL\")) {\r\n options.push(\"NOT NULL\");\r\n processedCol.nullable = false;\r\n }\r\n if (constraints.includes(\"UNIQUE\")) {\r\n if (!processedCol.primary_key) options.push(\"UNIQUE\");\r\n processedCol.unique = true;\r\n }\r\n // Handle DEFAULT values\r\n const defaultIndex = constraints.indexOf(\"DEFAULT\");\r\n if (defaultIndex !== -1 && constraints.length > defaultIndex + 1) {\r\n const defaultValue = constraints[defaultIndex + 1];\r\n options.push(`DEFAULT ${defaultValue}`);\r\n processedCol.default = defaultValue;\r\n }\r\n }\r\n\r\n processedCol.option_key = options.join(\" \").trim();\r\n return processedCol;\r\n }\r\n\r\n // Schema initialization with enhanced options\r\n async initializeFromSchema(schema: DatabaseSchema): Promise<void> {\r\n this.ensureConnected();\r\n\r\n // Check if schema already exists\r\n let hasExistingSchema = false;\r\n try {\r\n const result = await this.execute(\r\n \"SELECT version FROM _schema_info ORDER BY applied_at DESC LIMIT 1\"\r\n );\r\n hasExistingSchema = result.rows.length > 0;\r\n } catch (error) {\r\n hasExistingSchema = false;\r\n }\r\n\r\n // Handle existing schema based on options\r\n if (hasExistingSchema && !this.createIfNotExists && !this.forceRecreate) {\r\n if (schema.type_mapping) {\r\n this.setTypeMappingConfig(schema.type_mapping);\r\n }\r\n return;\r\n }\r\n\r\n if (hasExistingSchema && this.forceRecreate) {\r\n await this.dropAllTables();\r\n }\r\n\r\n if (schema.type_mapping) {\r\n this.setTypeMappingConfig(schema.type_mapping);\r\n }\r\n\r\n try {\r\n await this.execute(\"PRAGMA foreign_keys = ON\");\r\n } catch {}\r\n\r\n await this.beginTransaction();\r\n\r\n try {\r\n for (const [tableName, tableConfig] of Object.entries(schema.schemas)) {\r\n const tableDefinition: TableDefinition = {\r\n name: tableName,\r\n cols: tableConfig.cols.map((col) =>\r\n this.processColumnDefinition(col)\r\n ),\r\n description: tableConfig.description,\r\n indexes: tableConfig.indexes,\r\n foreign_keys: tableConfig.foreign_keys,\r\n };\r\n await this.createTableWithForeignKeys(tableDefinition);\r\n }\r\n\r\n for (const [tableName, tableConfig] of Object.entries(schema.schemas)) {\r\n if (tableConfig.indexes?.length) {\r\n await this.createIndexesForTable(tableName, tableConfig.indexes);\r\n }\r\n }\r\n\r\n await this.setSchemaVersion(schema.version);\r\n await this.commitTransaction();\r\n } catch (error) {\r\n await this.rollbackTransaction();\r\n throw error;\r\n }\r\n }\r\n\r\n private async dropAllTables(): Promise<void> {\r\n const tables = await this.execute(\r\n \"SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'\"\r\n );\r\n\r\n await this.beginTransaction();\r\n\r\n try {\r\n for (const table of tables.rows) {\r\n await this.execute(`DROP TABLE IF EXISTS ${table.name}`);\r\n }\r\n await this.commitTransaction();\r\n } catch (error) {\r\n await this.rollbackTransaction();\r\n throw error;\r\n }\r\n }\r\n\r\n private async createTableWithForeignKeys(\r\n table: TableDefinition\r\n ): Promise<void> {\r\n const columnDefs = table.cols.map((col) =>\r\n `${col.name} ${col.type} ${col.option_key || \"\"}`.trim()\r\n );\r\n\r\n const foreignKeyDefs: string[] = [];\r\n if (table.foreign_keys) {\r\n for (const fk of table.foreign_keys) {\r\n let fkSql = `FOREIGN KEY (${fk.column}) REFERENCES ${fk.references.table}(${fk.references.column})`;\r\n if (fk.on_delete) fkSql += ` ON DELETE ${fk.on_delete}`;\r\n if (fk.on_update) fkSql += ` ON UPDATE ${fk.on_update}`;\r\n foreignKeyDefs.push(fkSql);\r\n }\r\n }\r\n\r\n const allDefs = [...columnDefs, ...foreignKeyDefs];\r\n const sql = `CREATE TABLE IF NOT EXISTS ${table.name} (${allDefs.join(\r\n \", \"\r\n )})`;\r\n await this.execute(sql);\r\n }\r\n\r\n private async createIndexesForTable(\r\n tableName: string,\r\n indexes: IndexDefinition[]\r\n ): Promise<void> {\r\n for (const index of indexes) {\r\n const columns = index.columns.join(\", \");\r\n const isUnique = index.unique || false;\r\n const sql = `CREATE ${isUnique ? \"UNIQUE\" : \"\"} INDEX IF NOT EXISTS ${\r\n index.name\r\n } ON ${tableName} (${columns})`;\r\n await this.execute(sql);\r\n }\r\n }\r\n\r\n // Transaction management\r\n async beginTransaction(): Promise<void> {\r\n if (this.inTransaction) {\r\n throw new Error(\"Transaction already in progress\");\r\n }\r\n await this.execute(\"BEGIN TRANSACTION\");\r\n this.inTransaction = true;\r\n }\r\n\r\n async commitTransaction(): Promise<void> {\r\n if (!this.inTransaction) {\r\n throw new Error(\"No transaction in progress\");\r\n }\r\n await this.execute(\"COMMIT\");\r\n this.inTransaction = false;\r\n }\r\n\r\n async rollbackTransaction(): Promise<void> {\r\n if (!this.inTransaction) {\r\n throw new Error(\"No transaction in progress\");\r\n }\r\n await this.execute(\"ROLLBACK\");\r\n this.inTransaction = false;\r\n }\r\n\r\n // Schema management\r\n async getSchemaVersion(): Promise<string> {\r\n try {\r\n const result = await this.getRst(\r\n \"SELECT version FROM _schema_info ORDER BY applied_at DESC LIMIT 1\"\r\n );\r\n return result.version || \"0\";\r\n } catch {\r\n return \"0\";\r\n }\r\n }\r\n\r\n async setSchemaVersion(version: string): Promise<void> {\r\n await this.execute(`CREATE TABLE IF NOT EXISTS _schema_info (\r\n version TEXT NOT NULL,\r\n applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP\r\n )`);\r\n await this.execute(`INSERT INTO _schema_info (version) VALUES (?)`, [\r\n version,\r\n ]);\r\n }\r\n\r\n // CRUD Operations\r\n async insert(insertTable: QueryTable): Promise<SQLiteResult> {\r\n const validCols = insertTable.cols.filter(\r\n (col) => col.value !== undefined && col.value !== null\r\n );\r\n if (validCols.length === 0) {\r\n throw new Error(\"No valid columns to insert\");\r\n }\r\n\r\n const columnNames = validCols.map((col) => col.name).join(\", \");\r\n const placeholders = validCols.map(() => \"?\").join(\", \");\r\n const params = validCols.map((col) =>\r\n typeof col.value === \"object\" ? JSON.stringify(col.value) : col.value\r\n );\r\n\r\n const sql = `INSERT INTO ${insertTable.name} (${columnNames}) VALUES (${placeholders})`;\r\n return await this.execute(sql, params);\r\n }\r\n\r\n async update(updateTable: QueryTable): Promise<SQLiteResult> {\r\n const setCols = updateTable.cols.filter(\r\n (col) =>\r\n col.value !== undefined &&\r\n !updateTable.wheres?.some((w) => w.name === col.name)\r\n );\r\n\r\n if (setCols.length === 0) {\r\n throw new Error(\"No columns to update\");\r\n }\r\n\r\n const setClause = setCols.map((col) => `${col.name} = ?`).join(\", \");\r\n const params = setCols.map((col) =>\r\n typeof col.value === \"object\" ? JSON.stringify(col.value) : col.value\r\n );\r\n\r\n let sql = `UPDATE ${updateTable.name} SET ${setClause}`;\r\n const whereClause = this.buildWhereClause(updateTable.wheres);\r\n\r\n if (!whereClause.sql) {\r\n throw new Error(\"WHERE clause is required for UPDATE operation\");\r\n }\r\n\r\n sql += whereClause.sql;\r\n params.push(...whereClause.params);\r\n\r\n return await this.execute(sql, params);\r\n }\r\n\r\n async delete(deleteTable: QueryTable): Promise<SQLiteResult> {\r\n let sql = `DELETE FROM ${deleteTable.name}`;\r\n const whereClause = this.buildWhereClause(deleteTable.wheres);\r\n\r\n if (!whereClause.sql) {\r\n throw new Error(\"WHERE clause is required for DELETE operation\");\r\n }\r\n\r\n sql += whereClause.sql;\r\n return await this.execute(sql, whereClause.params);\r\n }\r\n\r\n async select(selectTable: QueryTable): Promise<SQLiteRow> {\r\n const { sql, params } = this.buildSelectQuery(selectTable, \" LIMIT 1\");\r\n const result = await this.execute(sql, params);\r\n return result.rows[0] || {};\r\n }\r\n\r\n async selectAll(selectTable: QueryTable): Promise<SQLiteRow[]> {\r\n const { sql, params } = this.buildSelectQuery(selectTable);\r\n const result = await this.execute(sql, params);\r\n return result.rows;\r\n }\r\n\r\n // Utility methods\r\n private buildSelectQuery(\r\n selectTable: QueryTable,\r\n suffix: string = \"\"\r\n ): { sql: string; params: any[] } {\r\n const columns =\r\n selectTable.cols.length > 0\r\n ? selectTable.cols.map((col) => col.name).join(\", \")\r\n : \"*\";\r\n\r\n let sql = `SELECT ${columns} FROM ${selectTable.name}`;\r\n const whereClause = this.buildWhereClause(selectTable.wheres);\r\n sql += whereClause.sql;\r\n\r\n if (selectTable.orderbys?.length) {\r\n const orderBy = selectTable.orderbys\r\n .map((o) => `${o.name} ${o.direction || \"ASC\"}`)\r\n .join(\", \");\r\n sql += ` ORDER BY ${orderBy}`;\r\n }\r\n\r\n if (selectTable.limitOffset) {\r\n if (selectTable.limitOffset.limit)\r\n sql += ` LIMIT ${selectTable.limitOffset.limit}`;\r\n if (selectTable.limitOffset.offset)\r\n sql += ` OFFSET ${selectTable.limitOffset.offset}`;\r\n }\r\n\r\n sql += suffix;\r\n return { sql, params: whereClause.params };\r\n }\r\n\r\n private buildWhereClause(\r\n wheres?: WhereClause[],\r\n clause: string = \"WHERE\"\r\n ): { sql: string; params: any[] } {\r\n if (!wheres || wheres.length === 0) {\r\n return { sql: \"\", params: [] };\r\n }\r\n\r\n const conditions: string[] = [];\r\n const params: any[] = [];\r\n\r\n for (const where of wheres) {\r\n const operator = where.operator || \"=\";\r\n conditions.push(`${where.name} ${operator} ?`);\r\n params.push(where.value);\r\n }\r\n\r\n return { sql: ` ${clause} ${conditions.join(\" AND \")}`, params };\r\n }\r\n\r\n convertJsonToQueryTable(\r\n tableName: string,\r\n json: Record<string, any>,\r\n idFields: string[] = [\"id\"]\r\n ): QueryTable {\r\n const queryTable: QueryTable = { name: tableName, cols: [], wheres: [] };\r\n\r\n for (const [key, value] of Object.entries(json)) {\r\n queryTable.cols.push({ name: key, value });\r\n if (idFields.includes(key) && value !== undefined) {\r\n queryTable.wheres?.push({ name: key, value });\r\n }\r\n }\r\n\r\n return queryTable;\r\n }\r\n\r\n // Enhanced Data Import functionality\r\n async importData(options: ImportOptions): Promise<ImportResult> {\r\n const startTime = Date.now();\r\n const result: ImportResult = {\r\n totalRows: options.data.length,\r\n successRows: 0,\r\n errorRows: 0,\r\n errors: [],\r\n executionTime: 0,\r\n };\r\n\r\n if (!this.isConnected) {\r\n throw new Error(\"Database is not connected\");\r\n }\r\n\r\n if (!options.data || options.data.length === 0) {\r\n result.executionTime = Date.now() - startTime;\r\n return result;\r\n }\r\n\r\n const tableInfo = await this.getTableInfo(options.tableName);\r\n if (tableInfo.length === 0) {\r\n throw new Error(`Table '${options.tableName}' does not exist`);\r\n }\r\n\r\n const columnMap = new Map(\r\n tableInfo.map((col) => [col.name.toLowerCase(), col])\r\n );\r\n const batchSize = options.batchSize || 1000;\r\n let processedCount = 0;\r\n const skipAutoIncrementPK = !options.includeAutoIncrementPK;\r\n\r\n try {\r\n await this.beginTransaction();\r\n\r\n for (let i = 0; i < options.data.length; i += batchSize) {\r\n const batch = options.data.slice(i, i + batchSize);\r\n\r\n for (let j = 0; j < batch.length; j++) {\r\n const rowIndex = i + j;\r\n const rowData = batch[j];\r\n\r\n try {\r\n const processedData = options.validateData\r\n ? this.validateAndTransformRow(\r\n rowData,\r\n columnMap,\r\n options.tableName,\r\n skipAutoIncrementPK\r\n )\r\n : this.transformRowData(rowData, columnMap, skipAutoIncrementPK);\r\n\r\n if (options.updateOnConflict && options.conflictColumns) {\r\n await this.insertOrUpdate(\r\n options.tableName,\r\n processedData,\r\n options.conflictColumns\r\n );\r\n } else {\r\n await this.insertRow(options.tableName, processedData);\r\n }\r\n\r\n result.successRows++;\r\n } catch (error) {\r\n result.errorRows++;\r\n const errorInfo = {\r\n rowIndex,\r\n error: error instanceof Error ? error.message : String(error),\r\n rowData,\r\n };\r\n result.errors.push(errorInfo);\r\n\r\n if (options.onError) {\r\n options.onError(\r\n error instanceof Error ? error : new Error(String(error)),\r\n rowIndex,\r\n rowData\r\n );\r\n }\r\n\r\n if (!options.skipErrors) {\r\n throw error;\r\n }\r\n }\r\n\r\n processedCount++;\r\n if (options.onProgress && processedCount % 100 === 0) {\r\n options.onProgress(processedCount, options.data.length);\r\n }\r\n }\r\n }\r\n\r\n await this.commitTransaction();\r\n } catch (error) {\r\n await this.rollbackTransaction();\r\n throw error;\r\n }\r\n\r\n if (options.onProgress) {\r\n options.onProgress(processedCount, options.data.length);\r\n }\r\n\r\n result.executionTime = Date.now() - startTime;\r\n return result;\r\n }\r\n\r\n // Import with column mapping\r\n async importDataWithMapping(\r\n tableName: string,\r\n data: Record<string, any>[],\r\n columnMappings: ColumnMapping[],\r\n options: Partial<ImportOptions> = {}\r\n ): Promise<ImportResult> {\r\n const transformedData = data.map((row) => {\r\n const newRow: Record<string, any> = {};\r\n\r\n columnMappings.forEach((mapping) => {\r\n if (row.hasOwnProperty(mapping.sourceColumn)) {\r\n let value = row[mapping.sourceColumn];\r\n\r\n if (mapping.transform) {\r\n value = mapping.transform(value);\r\n }\r\n\r\n newRow[mapping.targetColumn] = value;\r\n }\r\n });\r\n\r\n return newRow;\r\n });\r\n\r\n return await this.importData({\r\n tableName,\r\n data: transformedData,\r\n ...options,\r\n });\r\n }\r\n\r\n // Import from CSV\r\n async importFromCSV(\r\n tableName: string,\r\n csvData: string,\r\n options: {\r\n delimiter?: string;\r\n hasHeader?: boolean;\r\n columnMappings?: ColumnMapping[];\r\n } & Partial<ImportOptions> = {}\r\n ): Promise<ImportResult> {\r\n const delimiter = options.delimiter || \",\";\r\n const hasHeader = options.hasHeader !== false;\r\n\r\n const lines = csvData.split(\"\\n\").filter((line) => line.trim());\r\n if (lines.length === 0) {\r\n throw new Error(\"CSV data is empty\");\r\n }\r\n\r\n let headers: string[] = [];\r\n let dataStartIndex = 0;\r\n\r\n if (hasHeader) {\r\n headers = lines[0]\r\n .split(delimiter)\r\n .map((h) => h.trim().replace(/^[\"']|[\"']$/g, \"\"));\r\n dataStartIndex = 1;\r\n } else {\r\n const firstRowCols = lines[0].split(delimiter).length;\r\n headers = Array.from(\r\n { length: firstRowCols },\r\n (_, i) => `column_${i + 1}`\r\n );\r\n }\r\n\r\n const data: Record<string, any>[] = [];\r\n for (let i = dataStartIndex; i < lines.length; i++) {\r\n const values = lines[i]\r\n .split(delimiter)\r\n .map((v) => v.trim().replace(/^[\"']|[\"']$/g, \"\"));\r\n const row: Record<string, any> = {};\r\n\r\n headers.forEach((header, index) => {\r\n row[header] = values[index] || null;\r\n });\r\n\r\n data.push(row);\r\n }\r\n\r\n if (options.columnMappings) {\r\n return await this.importDataWithMapping(\r\n tableName,\r\n data,\r\n options.columnMappings,\r\n options\r\n );\r\n } else {\r\n return await this.importData({\r\n tableName,\r\n data,\r\n ...options,\r\n });\r\n }\r\n }\r\n\r\n private validateAndTransformRow(\r\n rowData: Record<string, any>,\r\n columnMap: Map<string, any>,\r\n tableName: string,\r\n skipAutoIncrementPK: boolean = true\r\n ): Record<string, any> {\r\n const processedRow: Record<string, any> = {};\r\n\r\n for (const [columnName, columnInfo] of columnMap.entries()) {\r\n const isRequired = columnInfo.notnull === 1 && !columnInfo.dflt_value;\r\n const isPrimaryKey = columnInfo.pk === 1;\r\n const isAutoIncrementPK =\r\n isPrimaryKey && columnInfo.type.toLowerCase().includes(\"integer\");\r\n\r\n if (skipAutoIncrementPK && isAutoIncrementPK) {\r\n continue;\r\n }\r\n\r\n const value = this.findValueForColumn(rowData, columnName);\r\n\r\n if (isRequired && (value === null || value === undefined)) {\r\n throw new Error(\r\n `Required column '${columnName}' is missing or null in table '${tableName}'`\r\n );\r\n }\r\n\r\n if (value !== null && value !== undefined) {\r\n processedRow[columnName] = this.convertValueToColumnType(\r\n value,\r\n columnInfo.type\r\n );\r\n }\r\n }\r\n\r\n return processedRow;\r\n }\r\n\r\n private transformRowData(\r\n rowData: Record<string, any>,\r\n columnMap: Map<string, any>,\r\n skipAutoIncrementPK: boolean = true\r\n ): Record<string, any> {\r\n const processedRow: Record<string, any> = {};\r\n\r\n for (const [key, value] of Object.entries(rowData)) {\r\n const columnName = key.toLowerCase();\r\n const columnInfo = columnMap.get(columnName);\r\n\r\n if (!columnInfo) {\r\n continue;\r\n }\r\n\r\n const isPrimaryKey = columnInfo.pk === 1;\r\n const isAutoIncrementPK =\r\n isPrimaryKey && columnInfo.type.toLowerCase().includes(\"integer\");\r\n\r\n if (skipAutoIncrementPK && isAutoIncrementPK) {\r\n continue;\r\n }\r\n\r\n if (value !== null && value !== undefined) {\r\n processedRow[key] = this.convertValueToColumnType(\r\n value,\r\n columnInfo.type\r\n );\r\n }\r\n }\r\n\r\n return processedRow;\r\n }\r\n\r\n private findValueForColumn(\r\n rowData: Record<string, any>,\r\n columnName: string\r\n ): any {\r\n if (rowData.hasOwnProperty(columnName)) {\r\n return rowData[columnName];\r\n }\r\n\r\n const lowerColumnName = columnName.toLowerCase();\r\n for (const [key, value] of Object.entries(rowData)) {\r\n if (key.toLowerCase() === lowerColumnName) {\r\n return value;\r\n }\r\n }\r\n\r\n return undefined;\r\n }\r\n\r\n private convertValueToColumnType(value: any, columnType: string): any {\r\n if (value === null || value === undefined) {\r\n return null;\r\n }\r\n\r\n const type = columnType.toLowerCase();\r\n\r\n try {\r\n if (type.includes(\"integer\") || type.includes(\"int\")) {\r\n if (typeof value === \"boolean\") {\r\n return value ? 1 : 0;\r\n }\r\n const num = parseInt(String(value));\r\n return isNaN(num) ? null : num;\r\n }\r\n\r\n if (\r\n type.includes(\"real\") ||\r\n type.includes(\"float\") ||\r\n type.includes(\"decimal\")\r\n ) {\r\n const num = parseFloat(String(value));\r\n return isNaN(num) ? null : num;\r\n }\r\n\r\n if (type.includes(\"boolean\")) {\r\n if (typeof value === \"boolean\") {\r\n return value ? 1 : 0;\r\n }\r\n if (typeof value === \"string\") {\r\n const lower = value.toLowerCase();\r\n return lower === \"true\" || lower === \"1\" || lower === \"yes\" ? 1 : 0;\r\n }\r\n return value ? 1 : 0;\r\n }\r\n\r\n if (type.includes(\"json\")) {\r\n if (typeof value === \"object\") {\r\n return JSON.stringify(value);\r\n }\r\n if (typeof value === \"string\") {\r\n try {\r\n JSON.parse(value);\r\n return value;\r\n } catch {\r\n throw new Error(\r\n `Invalid JSON format for column type '${columnType}'`\r\n );\r\n }\r\n }\r\n return JSON.stringify(value);\r\n }\r\n\r\n if (type.includes(\"timestamp\") || type.includes(\"datetime\")) {\r\n if (value instanceof Date) {\r\n return value.toISOString();\r\n }\r\n if (typeof value === \"string\" || typeof value === \"number\") {\r\n const date = new Date(value);\r\n return isNaN(date.getTime()) ? value : date.toISOString();\r\n }\r\n return String(value);\r\n }\r\n\r\n return String(value);\r\n } catch (error) {\r\n throw new Error(\r\n `Cannot convert value '${value}' to column type '${columnType}'`\r\n );\r\n }\r\n }\r\n\r\n private async insertRow(\r\n tableName: string,\r\n data: Record<string, any>\r\n ): Promise<void> {\r\n const columns = Object.keys(data);\r\n const values = Object.values(data);\r\n const placeholders = columns.map(() => \"?\").join(\", \");\r\n\r\n const sql = `INSERT INTO ${tableName} (${columns.join(\r\n \", \"\r\n )}) VALUES (${placeholders})`;\r\n await this.execute(sql, values);\r\n }\r\n\r\n private async insertOrUpdate(\r\n tableName: string,\r\n data: Record<string, any>,\r\n conflictColumns: string[]\r\n ): Promise<void> {\r\n try {\r\n await this.insertRow(tableName, data);\r\n } catch (error) {\r\n if (this.isConflictError(error)) {\r\n await this.updateRowByColumns(tableName, data, conflictColumns);\r\n } else {\r\n throw error;\r\n }\r\n }\r\n }\r\n\r\n private async updateRowByColumns(\r\n tableName: string,\r\n data: Record<string, any>,\r\n conflictColumns: string[]\r\n ): Promise<void> {\r\n const allColumns = Object.keys(data);\r\n const updateColumns = allColumns.filter(\r\n (col) => !conflictColumns.includes(col)\r\n );\r\n const whereColumns = conflictColumns;\r\n\r\n if (updateColumns.length === 0) {\r\n return;\r\n }\r\n\r\n const setClause = updateColumns.map((col) => `${col} = ?`).join(\", \");\r\n const whereClause = whereColumns.map((col) => `${col} = ?`).join(\" AND \");\r\n\r\n const updateValues = updateColumns.map((col) => data[col]);\r\n const whereValues = whereColumns.map((col) => data[col]);\r\n const allValues = [...updateValues, ...whereValues];\r\n\r\n const sql = `UPDATE ${tableName} SET ${setClause} WHERE ${whereClause}`;\r\n await this.execute(sql, allValues);\r\n }\r\n\r\n private isConflictError(error: any): boolean {\r\n return (\r\n error.code === \"SQLITE_CONSTRAINT_UNIQUE\" ||\r\n error.code === \"SQLITE_CONSTRAINT_PRIMARYKEY\" ||\r\n (error.message && error.message.includes(\"UNIQUE constraint failed\"))\r\n );\r\n }\r\n\r\n // Database info methods\r\n async getDatabaseInfo(): Promise<any> {\r\n const tables = await this.execute(\r\n \"SELECT name FROM sqlite_master WHERE type='table'\"\r\n );\r\n const version = await this.getSchemaVersion();\r\n\r\n return {\r\n name: this.dbPath,\r\n tables: tables.rows.map((t) => t.name),\r\n isConnected: this.isConnected,\r\n version,\r\n };\r\n }\r\n\r\n async getTableInfo(tableName: string): Promise<any[]> {\r\n const result = await this.execute(`PRAGMA table_info(${tableName})`);\r\n return result.rows;\r\n }\r\n\r\n async dropTable(tableName: string): Promise<void> {\r\n const sql = `DROP TABLE IF EXISTS ${tableName}`;\r\n await this.execute(sql);\r\n }\r\n\r\n // Connection check method\r\n isConnectionOpen(): boolean {\r\n return this.isConnected && !!this.connection;\r\n }\r\n\r\n async ensureConnected(): Promise<void> {\r\n if (!this.isConnectionOpen()) {\r\n await this.connect();\r\n }\r\n }\r\n\r\n async execute(sql: string, params: any[] = []): Promise<SQLiteResult> {\r\n this.ensureConnected();\r\n return await this.connection!.execute(sql, params);\r\n }\r\n\r\n async getRst(sql: string, params: any[] = []): Promise<SQLiteRow> {\r\n const result = await this.execute(sql, params);\r\n return result.rows[0] || {};\r\n }\r\n\r\n async getRsts(sql: string, params: any[] = []): Promise<SQLiteRow[]> {\r\n const result = await this.execute(sql, params);\r\n return result.rows;\r\n }\r\n}\r\n","// src/core/database-factory.ts\r\nimport { SQLiteAdapter, DatabaseSchema, DbFactoryOptions } from \"../types\";\r\nimport { UniversalDAO } from \"./universal-dao\";\r\n\r\n/**\r\n * Universal DatabaseFactory - A powerful utility class designed to create and manage\r\n * UniversalDAO instances from JSON schema across all operating systems and frameworks\r\n * using TypeScript and JavaScript. It provides methods for creating new, opening existing\r\n * databases, checking integrity, and managing database lifecycle.\r\n */\r\nexport class DatabaseFactory {\r\n private static adapters: SQLiteAdapter[] = [];\r\n\r\n /**\r\n * Register a SQLite adapter for use by the factory\r\n * @param adapter The SQLite adapter to register\r\n */\r\n static registerAdapter(adapter: SQLiteAdapter): void {\r\n this.adapters.push(adapter);\r\n }\r\n\r\n /**\r\n * Get information about the current runtime environment\r\n * @returns A string describing the current environment\r\n */\r\n static getEnvironmentInfo(): string {\r\n if (\r\n typeof navigator !== \"undefined\" &&\r\n navigator.product === \"ReactNative\"\r\n ) {\r\n return \"React Native\";\r\n }\r\n if (typeof globalThis.Bun !== \"undefined\") return \"Bun\";\r\n if (typeof globalThis.Deno !== \"undefined\") return \"Deno\";\r\n if (typeof window !== \"undefined\") return \"Browser\";\r\n if (typeof process !== \"undefined\") return \"Node.js\";\r\n return \"Unknown\";\r\n }\r\n\r\n /**\r\n * Detect the best available SQLite adapter for the current environment\r\n * @returns The best available SQLite adapter\r\n * @throws Error if no supported adapter is found\r\n */\r\n private static detectBestAdapter(): SQLiteAdapter {\r\n for (const adapter of this.adapters) {\r\n if (adapter.isSupported()) {\r\n return adapter;\r\n }\r\n }\r\n throw new Error(\"No supported SQLite adapter found\");\r\n }\r\n\r\n /**\r\n * Validate schema version compatibility between database and config\r\n * @param dao The UniversalDAO instance\r\n * @param schema The database schema configuration\r\n */\r\n private static async validateSchemaVersion(\r\n dao: UniversalDAO,\r\n schema: DatabaseSchema\r\n ): Promise<void> {\r\n try {\r\n const dbInfo = await dao.getDatabaseInfo();\r\n if (dbInfo.version !== schema.version) {\r\n throw new Error(\r\n `Schema version mismatch: database (${dbInfo.version}) vs config (${schema.version})`\r\n );\r\n }\r\n } catch (error) {\r\n throw new Error(\r\n `Error validating schema version for ${schema.database_name}: ${\r\n (error as Error).message\r\n }`\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Validate the provided schema object to ensure it has minimum required properties\r\n * @param schema The schema object to validate\r\n * @returns True if the schema is valid, otherwise throws an error\r\n */\r\n private static validateSchema(schema: any): schema is DatabaseSchema {\r\n if (!schema) {\r\n throw new Error(\"Schema configuration is null or undefined.\");\r\n }\r\n if (\r\n typeof schema.database_name !== \"string\" ||\r\n schema.database_name.trim() === \"\"\r\n ) {\r\n throw new Error(\r\n \"Invalid or missing 'database_name' in schema. This is required to name the database file.\"\r\n );\r\n }\r\n if (\r\n typeof schema.schemas !== \"object\" ||\r\n schema.schemas === null ||\r\n Object.keys(schema.schemas).length === 0\r\n ) {\r\n throw new Error(\r\n \"Invalid or missing 'schemas' object in schema. At least one table definition is required.\"\r\n );\r\n }\r\n return true;\r\n }\r\n\r\n /**\r\n * Create a new UniversalDAO instance (equivalent to SQLiteDAO)\r\n * @param dbPath Path to the database file\r\n * @param options Configuration options\r\n * @returns A new UniversalDAO instance\r\n */\r\n static createDAO(\r\n dbPath: string,\r\n options?: {\r\n adapter?: SQLiteAdapter;\r\n createIfNotExists?: boolean;\r\n forceRecreate?: boolean;\r\n }\r\n ): UniversalDAO {\r\n let adapter: SQLiteAdapter;\r\n\r\n if (options?.adapter) {\r\n adapter = options.adapter;\r\n } else {\r\n adapter = this.detectBestAdapter();\r\n }\r\n\r\n return new UniversalDAO(adapter, dbPath, {\r\n createIfNotExists: options?.createIfNotExists ?? false,\r\n forceRecreate: options?.forceRecreate ?? false,\r\n });\r\n }\r\n\r\n /**\r\n * Opens an existing database without initializing its schema.\r\n * Includes integrity check to detect corrupted files.\r\n * @param dbName The name of the database (e.g., 'core.db' or 'core').\r\n * @param options Additional options for database connection.\r\n * @returns A promise that resolves to a connected UniversalDAO instance.\r\n */\r\n public static async openExisting(\r\n dbName: string,\r\n options: Omit<\r\n DbFactoryOptions,\r\n \"config\" | \"configAsset\" | \"configPath\"\r\n > = {}\r\n ): Promise<UniversalDAO> {\r\n // Determine the database file path\r\n const dbFileName = dbName.endsWith(\".db\") ? dbName : `${dbName}.db`;\r\n\r\n // Create and connect DAO instance\r\n const dao = this.createDAO(dbFileName, options);\r\n\r\n try {\r\n await dao.connect();\r\n // Run integrity check to detect corrupted files\r\n await dao.execute(\"PRAGMA integrity_check\");\r\n return dao;\r\n } catch (error) {\r\n await dao.close();\r\n throw new Error(\r\n `Error opening database '${dbFileName}': ${(error as Error).message}`\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Internal method to create or open database with various options\r\n * @param options Configuration options\r\n * @param isForceInit Allow re-initialization of existing database\r\n * @param isForceDelete Force delete and recreate database\r\n * @returns Promise that resolves to initialized UniversalDAO\r\n */\r\n private static async createOrOpenInternal(\r\n options: DbFactoryOptions,\r\n isForceInit: boolean = false,\r\n isForceDelete: boolean = false\r\n ): Promise<UniversalDAO> {\r\n let schema: DatabaseSchema;\r\n\r\n // Step 1: Load schema\r\n if (options.config) {\r\n schema = options.config;\r\n } else if (options.configAsset) {\r\n schema = options.configAsset;\r\n } else {\r\n throw new Error(\r\n \"Either 'config', 'configAsset', or 'configPath' must be provided to the factory.\"\r\n );\r\n }\r\n\r\n // Step 2: Validate schema\r\n this.validateSchema(schema);\r\n\r\n // Step 3: Determine database path\r\n const dbFileName = schema.database_name.endsWith(\".db\")\r\n ? schema.database_name\r\n : `${schema.database_name}.db`;\r\n\r\n // Step 4: Create DAO instance\r\n const dao = this.createDAO(dbFileName, {\r\n adapter: options.adapter,\r\n createIfNotExists: isForceInit,\r\n forceRecreate: isForceDelete,\r\n });\r\n\r\n try {\r\n // Step 5: Connect to database\r\n await dao.connect();\r\n\r\n // Step 6: Initialize schema if needed\r\n await dao.initializeFromSchema(schema);\r\n\r\n // Step 7: Validate schema version compatibility\r\n // Validate schema version compatibility\r\n try {\r\n await this.validateSchemaVersion(dao, schema);\r\n } catch (schemaError: any) {\r\n await dao.close();\r\n throw new Error(\r\n `Schema mismatch in existing database. Use forceRecreate=true to recreate with updated schema. Error: ${schemaError.message}`\r\n );\r\n }\r\n return dao;\r\n } catch (error) {\r\n if (dao.isConnectionOpen()) {\r\n await dao.close();\r\n }\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Create a new database (DANGEROUS - will delete existing database)\r\n * Only use this for migrations or development, not in production\r\n * @param options Configuration options\r\n * @returns Promise that resolves to initialized UniversalDAO\r\n */\r\n public static async create(options: DbFactoryOptions): Promise<UniversalDAO> {\r\n return this.createOrOpenInternal(options, true, true);\r\n }\r\n\r\n /**\r\n * Smart method to create or open database\r\n * Only creates new tables if they don't exist and initializes file initially\r\n * Will check if file exists and is valid before deciding to create new or open existing\r\n * @param options Database configuration options\r\n * @param isForceInit Force re-initialization of tables even if they exist (default: false)\r\n * @returns Promise that resolves to initialized UniversalDAO\r\n */\r\n public static async createOrOpen(\r\n options: DbFactoryOptions,\r\n isForceInit: boolean = false\r\n ): Promise<UniversalDAO> {\r\n return this.createOrOpenInternal(options, isForceInit);\r\n }\r\n\r\n /**\r\n * Convenience method to create a database from a JSON asset\r\n * @param configAsset The imported/required JSON configuration\r\n * @param options Additional options for database creation\r\n * @returns Promise that resolves to initialized UniversalDAO\r\n */\r\n public static async createFromAsset(\r\n configAsset: DatabaseSchema,\r\n options: Omit<\r\n DbFactoryOptions,\r\n \"config\" | \"configAsset\" | \"configPath\"\r\n > = {}\r\n ): Promise<UniversalDAO> {\r\n try {\r\n return await this.create({\r\n ...options,\r\n configAsset,\r\n });\r\n } catch (error) {\r\n throw new Error(\r\n `Error creating database from asset: ${(error as Error).message}`\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Convenience method to create a database from a configuration object\r\n * @param config The database schema configuration object\r\n * @param options Additional options for database creation\r\n * @returns Promise that resolves to initialized UniversalDAO\r\n */\r\n public static async createFromConfig(\r\n config: DatabaseSchema,\r\n options: Omit<\r\n DbFactoryOptions,\r\n \"config\" | \"configAsset\" | \"configPath\"\r\n > = {}\r\n ): Promise<UniversalDAO> {\r\n try {\r\n return await this.create({\r\n ...options,\r\n config,\r\n });\r\n } catch (error) {\r\n throw new Error(\r\n `Error creating database from config: ${(error as Error).message}`\r\n );\r\n }\r\n }\r\n}\r\n\r\nexport default DatabaseFactory;\r\n","// src/core/database-manager.ts\r\n\r\nimport { DatabaseSchema, ImportOptions, ImportResult, ColumnMapping } from \"../types\";\r\nimport { DatabaseFactory } from \"./database-factory\";\r\nimport { UniversalDAO } from \"./universal-dao\";\r\n\r\nexport type DatabaseConnections = {\r\n [key: string]: UniversalDAO;\r\n};\r\n\r\nexport interface RoleConfig {\r\n roleName: string;\r\n requiredDatabases: string[];\r\n optionalDatabases?: string[];\r\n priority?: number;\r\n}\r\n\r\nexport type RoleRegistry = {\r\n [roleName: string]: RoleConfig;\r\n};\r\n\r\nexport interface DatabaseImportConfig {\r\n databaseKey: string;\r\n tableName: string;\r\n data: Record<string, any>[];\r\n options?: Partial<ImportOptions>;\r\n columnMappings?: ColumnMapping[];\r\n}\r\n\r\nexport interface BulkImportResult {\r\n totalDatabases: number;\r\n successDatabases: number;\r\n results: Record<string, ImportResult>;\r\n errors: Record<string, Error>;\r\n executionTime: number;\r\n}\r\n\r\nexport interface SchemaManager {\r\n getSchema(key: string): DatabaseSchema | undefined;\r\n registerSchema(key: string, schema: DatabaseSchema): void;\r\n getAllSchemaKeys(): string[];\r\n hasSchema(key: string): boolean;\r\n}\r\n\r\nexport class DatabaseManager {\r\n private static maxConnections = 10;\r\n private static connections: DatabaseConnections = {};\r\n private static isInitialized = false;\r\n private static roleRegistry: RoleRegistry = {};\r\n private static currentRole: string | null = null;\r\n private static currentUserRoles: string[] = [];\r\n private static activeDatabases: Set<string> = new Set();\r\n private static isClosingConnections = false;\r\n \r\n // Schema management - support dynamic schemas\r\n private static schemaConfigurations: Record<string, DatabaseSchema> = {};\r\n private static schemaManager: SchemaManager | null = null;\r\n \r\n // Event system for database reconnection\r\n private static eventListeners: Map<string, Array<(dao: UniversalDAO) => void>> = new Map();\r\n\r\n /**\r\n * Get the maximum number of allowed database connections\r\n */\r\n public static getMaxConnections(): number {\r\n return this.maxConnections;\r\n }\r\n\r\n /**\r\n * Set the maximum number of allowed database connections\r\n * @param maxConnections - The maximum number of connections (must be positive)\r\n * @throws Error if maxConnections is not positive or if current connections exceed the new limit\r\n */\r\n public static setMaxConnections(maxConnections: number): void {\r\n if (maxConnections <= 0) {\r\n throw new Error('Maximum connections must be a positive number');\r\n }\r\n\r\n const currentConnectionCount = Object.keys(this.connections).length;\r\n if (currentConnectionCount > maxConnections) {\r\n throw new Error(\r\n `Cannot set maximum connections to ${maxConnections}. ` +\r\n `Current active connections (${currentConnectionCount}) exceed the new limit. ` +\r\n `Please close some connections first.`\r\n );\r\n }\r\n\r\n this.maxConnections = maxConnections;\r\n }\r\n\r\n /**\r\n * Set a schema manager for dynamic schema handling\r\n */\r\n public static setSchemaManager(manager: SchemaManager): void {\r\n this.schemaManager = manager;\r\n }\r\n\r\n /**\r\n * Register a schema configuration dynamically\r\n */\r\n public static registerSchema(key: string, schema: DatabaseSchema): void {\r\n this.schemaConfigurations[key] = schema;\r\n }\r\n\r\n /**\r\n * Register multiple schemas at once\r\n */\r\n public static registerSchemas(schemas: Record<string, DatabaseSchema>): void {\r\n Object.entries(schemas).forEach(([key, schema]) => {\r\n this.registerSchema(key, schema);\r\n });\r\n }\r\n\r\n /**\r\n * Get schema from internal store or external manager\r\n */\r\n private static getSchema(key: string): DatabaseSchema | undefined {\r\n // Try internal schemas first\r\n if (this.schemaConfigurations[key]) {\r\n return this.schemaConfigurations[key];\r\n }\r\n \r\n // Try external schema manager\r\n if (this.schemaManager) {\r\n return this.schemaManager.getSchema(key);\r\n }\r\n \r\n return undefined;\r\n }\r\n\r\n /**\r\n * Get all available schema keys\r\n */\r\n public static getAvailableSchemas(): string[] {\r\n const internalKeys = Object.keys(this.schemaConfigurations);\r\n const externalKeys = this.schemaManager?.getAllSchemaKeys() || [];\r\n return [...new Set([...internalKeys, ...externalKeys])];\r\n }\r\n\r\n /**\r\n * Register a role configuration\r\n */\r\n public static registerRole(roleConfig: RoleConfig): void {\r\n this.roleRegistry[roleConfig.roleName] = roleConfig;\r\n }\r\n\r\n /**\r\n * Register multiple roles\r\n */\r\n public static registerRoles(roleConfigs: RoleConfig[]): void {\r\n roleConfigs.forEach(config => this.registerRole(config));\r\n }\r\n\r\n /**\r\n * Get all registered roles\r\n */\r\n public static getRegisteredRoles(): RoleRegistry {\r\n return { ...this.roleRegistry };\r\n }\r\n\r\n /**\r\n * Get databases for a specific role\r\n */\r\n public static getRoleDatabases(roleName: string): string[] {\r\n const roleConfig = this.roleRegistry[roleName];\r\n if (!roleConfig) {\r\n throw new Error(`Role '${roleName}' is not registered.`);\r\n }\r\n return [\r\n ...roleConfig.requiredDatabases,\r\n ...(roleConfig.optionalDatabases || []),\r\n ];\r\n }\r\n\r\n /**\r\n * Get databases for current user roles\r\n */\r\n public static getCurrentUserDatabases(): string[] {\r\n const allDatabases = new Set<string>();\r\n allDatabases.add('core'); // Core database is always included\r\n \r\n for (const roleName of this.currentUserRoles) {\r\n const roleConfig = this.roleRegistry[roleName];\r\n if (roleConfig) {\r\n roleConfig.requiredDatabases.forEach(db => allDatabases.add(db));\r\n if (roleConfig.optionalDatabases) {\r\n roleConfig.optionalDatabases.forEach(db => allDatabases.add(db));\r\n }\r\n }\r\n }\r\n \r\n return Array.from(allDatabases);\r\n }\r\n\r\n /**\r\n * Initialize core database connection\r\n */\r\n public static async initializeCoreConnection(): Promise<void> {\r\n if (this.connections['core']) {\r\n return;\r\n }\r\n\r\n try {\r\n const coreSchema = this.getSchema('core');\r\n if (!coreSchema) {\r\n throw new Error('Core database schema not found.');\r\n }\r\n\r\n const dao = await DatabaseFactory.createOrOpen({ config: coreSchema }, false);\r\n await dao.execute('PRAGMA integrity_check');\r\n this.connections['core'] = dao;\r\n } catch (error) {\r\n throw new Error(`Error initializing core database: ${(error as Error).message}`);\r\n }\r\n }\r\n\r\n /**\r\n * Set current user roles and initialize connections\r\n */\r\n public static async setCurrentUserRoles(\r\n userRoles: string[],\r\n primaryRole?: string,\r\n ): Promise<void> {\r\n // Validate roles exist\r\n for (const roleName of userRoles) {\r\n if (!this.roleRegistry[roleName]) {\r\n throw new Error(`Role '${roleName}' is not registered. Please register it first.`);\r\n }\r\n }\r\n\r\n const previousRoles = [...this.currentUserRoles];\r\n this.currentUserRoles = userRoles;\r\n this.currentRole = primaryRole || userRoles[0] || null;\r\n\r\n await this.initializeUserRoleConnections();\r\n await this.cleanupUnusedConnections(previousRoles);\r\n }\r\n\r\n /**\r\n * Get current user roles\r\n */\r\n public static getCurrentUserRoles(): string[] {\r\n return [...this.currentUserRoles];\r\n }\r\n\r\n /**\r\n * Get current primary role\r\n */\r\n public static getCurrentRole(): string | null {\r\n return this.currentRole;\r\n }\r\n\r\n /**\r\n * Initialize connections for current user roles\r\n */\r\n private static async initializeUserRoleConnections(): Promise<void> {\r\n const requiredDatabases = this.getCurrentUserDatabases();\r\n const failedInitializations: { key: string; error: Error }[] = [];\r\n\r\n const initPromises = requiredDatabases.map(async dbKey => {\r\n if (this.connections[dbKey]) {\r\n return; // Already connected\r\n }\r\n\r\n try {\r\n const schema = this.getSchema(dbKey);\r\n if (!schema) {\r\n throw new Error(`Database key '${dbKey}' not found in schema configurations.`);\r\n }\r\n\r\n const dao = await DatabaseFactory.createOrOpen({ config: schema }, false);\r\n await dao.execute('PRAGMA integrity_check');\r\n this.connections[dbKey] = dao;\r\n } catch (error) {\r\n const err = error instanceof Error ? error : new Error(String(error));\r\n \r\n // Check if database is required for any role\r\n const isRequired = this.currentUserRoles.some(roleName => {\r\n const roleConfig = this.roleRegistry[roleName];\r\n return roleConfig && roleConfig.requiredDatabases.includes(dbKey);\r\n });\r\n\r\n if (isRequired) {\r\n failedInitializations.push({ key: dbKey, error: err });\r\n }\r\n // Optional databases that fail are ignored\r\n }\r\n });\r\n\r\n await Promise.all(initPromises);\r\n\r\n if (failedInitializations.length > 0) {\r\n const errorSummary = failedInitializations\r\n .map(f => ` - ${f.key}: ${f.error.message}`)\r\n .join('\\n');\r\n throw new Error(`Failed to initialize required databases for user roles:\\n${errorSummary}`);\r\n }\r\n }\r\n\r\n /**\r\n * Cleanup unused connections\r\n */\r\n private static async cleanupUnusedConnections(previousRoles: string[]): Promise<void> {\r\n const previousDatabases = new Set<string>();\r\n previousDatabases.add('core');\r\n\r\n for (const roleName of previousRoles) {\r\n const roleConfig = this.roleRegistry[roleName];\r\n if (roleConfig) {\r\n roleConfig.requiredDatabases.forEach(db => previousDatabases.add(db));\r\n if (roleConfig.optionalDatabases) {\r\n roleConfig.optionalDatabases.forEach(db => previousDatabases.add(db));\r\n }\r\n }\r\n }\r\n\r\n const currentDatabases = new Set(this.getCurrentUserDatabases());\r\n const databasesToClose = Array.from(previousDatabases).filter(\r\n db => !currentDatabases.has(db),\r\n );\r\n\r\n if (databasesToClose.length > 0) {\r\n for (const dbKey of databasesToClose) {\r\n if (this.connections[dbKey]) {\r\n try {\r\n await this.connections[dbKey].close();\r\n delete this.connections[dbKey];\r\n } catch (error) {\r\n // Log error but continue cleanup\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Check if current user has access to database\r\n */\r\n public static hasAccessToDatabase(dbKey: string): boolean {\r\n // For universal version, we can implement more flexible access control\r\n // Currently allowing access to all registered schemas\r\n return this.getSchema(dbKey) !== undefined;\r\n }\r\n\r\n /**\r\n * Get database connection\r\n */\r\n public static get(key: string): UniversalDAO {\r\n if (!this.hasAccessToDatabase(key)) {\r\n throw new Error(`Access denied: Database '${key}' is not accessible.`);\r\n }\r\n\r\n const dao = this.connections[key];\r\n if (!dao) {\r\n throw new Error(`Database '${key}' is not connected. Please ensure it's initialized.`);\r\n }\r\n\r\n return dao;\r\n }\r\n\r\n /**\r\n * Register event listener for database reconnection\r\n */\r\n public static onDatabaseReconnect(\r\n schemaName: string,\r\n callback: (dao: UniversalDAO) => void,\r\n ): void {\r\n if (!this.eventListeners.has(schemaName)) {\r\n this.eventListeners.set(schemaName, []);\r\n }\r\n this.eventListeners.get(schemaName)!.push(callback);\r\n }\r\n\r\n /**\r\n * Remove event listener for database reconnection\r\n */\r\n public static offDatabaseReconnect(\r\n schemaName: string,\r\n callback: (dao: UniversalDAO) => void,\r\n ): void {\r\n const listeners = this.eventListeners.get(schemaName);\r\n if (listeners) {\r\n const index = listeners.indexOf(callback);\r\n if (index > -1) {\r\n listeners.splice(index, 1);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Notify listeners of database reconnection\r\n */\r\n private static notifyDatabaseReconnect(schemaName: string, dao: UniversalDAO): void {\r\n const listeners = this.eventListeners.get(schemaName);\r\n if (listeners) {\r\n listeners.forEach(callback => {\r\n try {\r\n callback(dao);\r\n } catch (error) {\r\n // Handle callback errors gracefully\r\n }\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Close all connections\r\n */\r\n private static async closeAllConnections(): Promise<void> {\r\n if (this.isClosingConnections) {\r\n return;\r\n }\r\n\r\n this.isClosingConnections = true;\r\n try {\r\n // Save active databases\r\n const currentActiveDb = Object.keys(this.connections);\r\n currentActiveDb.forEach(dbKey => this.activeDatabases.add(dbKey));\r\n\r\n const closePromises = Object.entries(this.connections).map(\r\n async ([dbKey, dao]) => {\r\n try {\r\n await dao.close();\r\n } catch (error) {\r\n // Log error but continue closing\r\n }\r\n },\r\n );\r\n\r\n await Promise.all(closePromises);\r\n this.connections = {};\r\n } finally {\r\n this.isClosingConnections = false;\r\n }\r\n }\r\n\r\n /**\r\n * Reopen connections\r\n */\r\n public static async reopenConnections(): Promise<void> {\r\n await this.initializeCoreConnection();\r\n \r\n if (this.currentUserRoles.length > 0) {\r\n await this.initializeUserRoleConnections();\r\n }\r\n\r\n // Reinitialize previously active databases\r\n const activeDbArray = Array.from(this.activeDatabases);\r\n if (activeDbArray.length > 0) {\r\n for (const dbKey of activeDbArray) {\r\n if (!this.connections[dbKey]) {\r\n const schema = this.getSchema(dbKey);\r\n if (schema) {\r\n try {\r\n const dao = await DatabaseFactory.createOrOpen({ config: schema }, false);\r\n await dao.connect();\r\n this.connections[dbKey] = dao;\r\n this.notifyDatabaseReconnect(dbKey, dao);\r\n } catch (error) {\r\n // Log error but continue\r\n }\r\n }\r\n } else if (this.connections[dbKey]) {\r\n // Database exists, notify services\r\n this.notifyDatabaseReconnect(dbKey, this.connections[dbKey]);\r\n }\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Ensure database connection exists and is active\r\n */\r\n public static async ensureDatabaseConnection(key: string): Promise<UniversalDAO> {\r\n this.activeDatabases.add(key);\r\n\r\n if (!this.hasAccessToDatabase(key)) {\r\n throw new Error(`Access denied: Database '${key}' is not accessible.`);\r\n }\r\n\r\n if (this.connections[key]) {\r\n try {\r\n const isConnected = this.connections[key].isConnectionOpen();\r\n if (isConnected) {\r\n return this.connections[key];\r\n } else {\r\n // Clean up inactive connection\r\n try {\r\n await this.connections[key].close().catch(() => {});\r\n } catch (error) {\r\n // Ignore cleanup errors\r\n }\r\n delete this.connections[key];\r\n }\r\n } catch (error) {\r\n delete this.connections[key];\r\n }\r\n }\r\n\r\n // Create new connection\r\n return await this.getLazyLoading(key);\r\n }\r\n\r\n /**\r\n * Get all connections\r\n */\r\n public static getConnections(): DatabaseConnections {\r\n return { ...this.connections };\r\n }\r\n\r\n /**\r\n * Open all existing databases\r\n */\r\n public static async openAllExisting(databaseKeys: string[]): Promise<boolean> {\r\n const failedOpens: { key: string; error: Error }[] = [];\r\n\r\n for (const key of databaseKeys) {\r\n try {\r\n const schema = this.getSchema(key);\r\n if (!schema) {\r\n throw new Error(`Invalid database key: ${key}. Schema not found.`);\r\n }\r\n\r\n const dao = await DatabaseFactory.createOrOpen({ config: schema }, false);\r\n await dao.execute('PRAGMA integrity_check');\r\n this.connections[key] = dao;\r\n } catch (error) {\r\n const err = error instanceof Error ? error : new Error(String(error));\r\n failedOpens.push({ key, error: err });\r\n }\r\n }\r\n\r\n if (failedOpens.length > 0) {\r\n const errorSummary = failedOpens\r\n .map(f => ` - ${f.key}: ${f.error.message}`)\r\n .join('\\n');\r\n throw new Error(`Failed to open one or more databases:\\n${errorSummary}`);\r\n }\r\n\r\n this.isInitialized = true;\r\n return true;\r\n }\r\n\r\n /**\r\n * Initialize databases lazily\r\n */\r\n public static async initLazySchema(databaseKeys: string[]): Promise<boolean> {\r\n const invalidKeys = databaseKeys.filter(key => !this.getSchema(key));\r\n if (invalidKeys.length > 0) {\r\n throw new Error(`Invalid database keys: ${invalidKeys.join(', ')}. Schemas not found.`);\r\n }\r\n\r\n const newConnectionsCount = databaseKeys.filter(key => !this.connections[key]).length;\r\n const currentConnectionsCount = Object.keys(this.connections).length;\r\n \r\n if (currentConnectionsCount + newConnectionsCount > this.maxConnections) {\r\n throw new Error(\r\n `Cannot initialize ${newConnectionsCount} new connections. Would exceed maximum of ${this.maxConnections} connections. Current: ${currentConnectionsCount}`,\r\n );\r\n }\r\n\r\n const failedInitializations: { key: string; error: Error }[] = [];\r\n const initPromises = databaseKeys.map(async key => {\r\n if (this.connections[key]) {\r\n return; // Already initialized\r\n }\r\n\r\n try {\r\n const schema = this.getSchema(key)!;\r\n const dao = await DatabaseFactory.createOrOpen({ config: schema }, false);\r\n await dao.execute('PRAGMA integrity_check');\r\n this.connections[key] = dao;\r\n } catch (error) {\r\n const err = error instanceof Error ? error : new Error(String(error));\r\n failedInitializations.push({ key, error: err });\r\n }\r\n });\r\n\r\n await Promise.all(initPromises);\r\n\r\n if (failedInitializations.length > 0) {\r\n const errorSummary = failedInitializations\r\n .map(f => ` - ${f.key}: ${f.error.message}`)\r\n .join('\\n');\r\n throw new Error(`Failed to initialize one or more databases:\\n${errorSummary}`);\r\n }\r\n\r\n if (Object.keys(this.connections).length > 0) {\r\n this.isInitialized = true;\r\n }\r\n\r\n return true;\r\n }\r\n\r\n /**\r\n * Initialize all available databases\r\n */\r\n public static async initializeAll(): Promise<void> {\r\n if (this.isInitialized) {\r\n return;\r\n }\r\n\r\n const availableSchemas = this.getAvailableSchemas();\r\n const failedInitializations: { key: string; error: Error }[] = [];\r\n\r\n const initPromises = availableSchemas.map(async key => {\r\n try {\r\n const schema = this.getSchema(key)!;\r\n const dao = await DatabaseFactory.createOrOpen({ config: schema }, false);\r\n this.connections[key] = dao;\r\n } catch (error) {\r\n const err = error instanceof Error ? error : new Error(String(error));\r\n failedInitializations.push({ key, error: err });\r\n }\r\n });\r\n\r\n await Promise.all(initPromises);\r\n\r\n if (failedInitializations.length > 0) {\r\n this.isInitialized = false;\r\n const errorSummary = failedInitializations\r\n .map(f => ` - ${f.key}: ${f.error.message}`)\r\n .join('\\n');\r\n throw new Error(`Failed to initialize one or more databases:\\n${errorSummary}`);\r\n }\r\n\r\n this.isInitialized = true;\r\n }\r\n\r\n /**\r\n * Get database with lazy loading\r\n */\r\n public static async getLazyLoading(key: string): Promise<UniversalDAO> {\r\n this.activeDatabases.add(key);\r\n\r\n if (!this.hasAccessToDatabase(key)) {\r\n throw new Error(`Access denied: Database '${key}' is not accessible.`);\r\n }\r\n\r\n if (!this.connections[key]) {\r\n const schema = this.getSchema(key);\r\n if (!schema) {\r\n throw new Error(`Invalid database key: ${key}. Schema not found.`);\r\n }\r\n\r\n if (Object.keys(this.connections).length >= this.maxConnections) {\r\n throw new Error('Maximum number of database connections reached');\r\n }\r\n\r\n const dao = await DatabaseFactory.createOrOpen({ config: schema }, false);\r\n await dao.connect();\r\n this.connections[key] = dao;\r\n }\r\n\r\n this.isInitialized = true;\r\n return this.connections[key];\r\n }\r\n\r\n /**\r\n * Execute cross-schema transaction\r\n */\r\n public static async executeCrossSchemaTransaction(\r\n schemas: string[],\r\n callback: (daos: Record<string, UniversalDAO>) => Promise<void>,\r\n ): Promise<void> {\r\n for (const key of schemas) {\r\n if (!this.hasAccessToDatabase(key)) {\r\n throw new Error(`Access denied: Database '${key}' is not accessible.`);\r\n }\r\n }\r\n\r\n const daos = schemas.reduce((acc, key) => {\r\n acc[key] = this.get(key);\r\n return acc;\r\n }, {} as Record<string, UniversalDAO>);\r\n\r\n try {\r\n await Promise.all(Object.values(daos).map(dao => dao.beginTransaction()));\r\n await callback(daos);\r\n await Promise.all(Object.values(daos).map(dao => dao.commitTransaction()));\r\n } catch (error) {\r\n await Promise.all(Object.values(daos).map(dao => dao.rollbackTransaction()));\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Import data to table\r\n */\r\n public static async importDataToTable(\r\n databaseKey: string,\r\n tableName: string,\r\n data: Record<string, any>[],\r\n options: Partial<ImportOptions> = {},\r\n ): Promise<ImportResult> {\r\n if (!this.hasAccessToDatabase(databaseKey)) {\r\n throw new Error(`Access denied: Database '${databaseKey}' is not accessible.`);\r\n }\r\n\r\n const dao = this.get(databaseKey);\r\n try {\r\n const result = await dao.importData({\r\n tableName,\r\n data,\r\n ...options,\r\n });\r\n return result;\r\n } catch (error) {\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Import data with column mapping\r\n */\r\n public static async importDataWithMapping(\r\n databaseKey: string,\r\n tableName: string,\r\n data: Record<string, any>[],\r\n columnMappings: ColumnMapping[],\r\n options: Partial<ImportOptions> = {},\r\n ): Promise<ImportResult> {\r\n if (!this.hasAccessToDatabase(databaseKey)) {\r\n throw new Error(`Access denied: Database '${databaseKey}' is not accessible.`);\r\n }\r\n\r\n const dao = this.get(databaseKey);\r\n try {\r\n const result = await dao.importDataWithMapping(\r\n tableName,\r\n data,\r\n columnMappings,\r\n options,\r\n );\r\n return result;\r\n } catch (error) {\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Bulk import data\r\n */\r\n public static async bulkImport(importConfigs: DatabaseImportConfig[]): Promise<BulkImportResult> {\r\n const startTime = Date.now();\r\n const result: BulkImportResult = {\r\n totalDatabases: importConfigs.length,\r\n successDatabases: 0,\r\n results: {},\r\n errors: {},\r\n executionTime: 0,\r\n };\r\n\r\n for (const config of importConfigs) {\r\n const configKey = `${config.databaseKey}.${config.tableName}`;\r\n try {\r\n if (!this.hasAccessToDatabase(config.databaseKey)) {\r\n throw new Error(`Access denied: Database '${config.databaseKey}' is not accessible.`);\r\n }\r\n\r\n const dao = this.get(config.databaseKey);\r\n let importResult: ImportResult;\r\n\r\n if (config.columnMappings) {\r\n importResult = await dao.importDataWithMapping(\r\n config.tableName,\r\n config.data,\r\n config.columnMappings,\r\n config.options,\r\n );\r\n } else {\r\n importResult = await dao.importData({\r\n tableName: config.tableName,\r\n data: config.data,\r\n ...config.options,\r\n });\r\n }\r\n\r\n result.results[configKey] = importResult;\r\n result.successDatabases++;\r\n } catch (error) {\r\n const err = error instanceof Error ? error : new Error(String(error));\r\n result.errors[configKey] = err;\r\n }\r\n }\r\n\r\n result.executionTime = Date.now() - startTime;\r\n return result;\r\n }\r\n\r\n /**\r\n * Import from CSV\r\n */\r\n public static async importFromCSV(\r\n databaseKey: string,\r\n tableName: string,\r\n csvData: string,\r\n options: {\r\n delimiter?: string;\r\n hasHeader?: boolean;\r\n columnMappings?: ColumnMapping[];\r\n } & Partial<ImportOptions> = {},\r\n ): Promise<ImportResult> {\r\n if (!this.hasAccessToDatabase(databaseKey)) {\r\n throw new Error(`Access denied: Database '${databaseKey}' is not accessible.`);\r\n }\r\n\r\n const dao = this.get(databaseKey);\r\n try {\r\n const result = await dao.importFromCSV(tableName, csvData, options);\r\n return result;\r\n } catch (error) {\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Get connection count\r\n */\r\n public static getConnectionCount(): number {\r\n return Object.keys(this.connections).length;\r\n }\r\n\r\n /**\r\n * List all active connections\r\n */\r\n public static listConnections(): string[] {\r\n return Object.keys(this.connections);\r\n }\r\n\r\n /**\r\n * Close specific connection\r\n */\r\n public static async closeConnection(dbKey: string): Promise<void> {\r\n const dao = this.connections[dbKey];\r\n if (dao) {\r\n await dao.disconnect();\r\n delete this.connections[dbKey];\r\n }\r\n }\r\n\r\n /**\r\n * Close all connections and reset state\r\n */\r\n public static async closeAll(): Promise<void> {\r\n await this.closeAllConnections();\r\n \r\n this.currentUserRoles = [];\r\n this.currentRole = null;\r\n this.isInitialized = false;\r\n this.activeDatabases.clear();\r\n this.eventListeners.clear();\r\n this.isClosingConnections = false;\r\n }\r\n\r\n /**\r\n * Logout user - close role-specific connections\r\n */\r\n public static async logout(): Promise<void> {\r\n const connectionsToClose = Object.keys(this.connections).filter(\r\n key => key !== 'core',\r\n );\r\n\r\n for (const dbKey of connectionsToClose) {\r\n try {\r\n await this.connections[dbKey].close();\r\n delete this.connections[dbKey];\r\n } catch (error) {\r\n // Log error but continue cleanup\r\n }\r\n }\r\n\r\n this.currentUserRoles = [];\r\n this.currentRole = null;\r\n }\r\n}","// src/core/base-service.ts\r\nimport {\r\n QueryTable,\r\n WhereClause,\r\n OrderByClause,\r\n ImportResult,\r\n ColumnMapping,\r\n ImportOptions,\r\n ServiceStatus,\r\n HealthCheckResult,\r\n} from \"../types\";\r\nimport { UniversalDAO } from \"./universal-dao\";\r\nimport { DatabaseManager } from \"./database-manager\";\r\n\r\nexport interface FindOptions {\r\n where?: WhereClause[];\r\n orderBy?: OrderByClause[];\r\n limit?: number;\r\n offset?: number;\r\n columns?: string[];\r\n}\r\n\r\nexport type ErrorHandler = (error: Error) => void;\r\nexport type EventHandler = (data: any) => void;\r\n\r\n/**\r\n * Universal BaseService - An enhanced abstract base class designed to provide\r\n * comprehensive CRUD operations and database management features across all\r\n * operating systems and frameworks using TypeScript and JavaScript.\r\n */\r\nexport abstract class BaseService<T = any> {\r\n protected dao: UniversalDAO | null = null;\r\n protected schemaName: string;\r\n protected tableName: string;\r\n protected isOpened: boolean = false;\r\n protected isInitialized: boolean = false;\r\n protected errorHandlers: Map<string, ErrorHandler> = new Map();\r\n protected eventListeners: Map<string, EventHandler[]> = new Map();\r\n protected primaryKeyFields: string[] = [\"id\"];\r\n private cache: Map<string, any> = new Map();\r\n private reconnectHandler: (dao: UniversalDAO) => void;\r\n\r\n constructor(schemaName: string, tableName?: string) {\r\n this.schemaName = schemaName;\r\n this.tableName = tableName || schemaName;\r\n\r\n // Register reconnect listener for database reconnection\r\n this.reconnectHandler = (newDao: UniversalDAO) => {\r\n this.dao = newDao;\r\n this._emit(\"daoReconnected\", { schemaName: this.schemaName });\r\n };\r\n\r\n DatabaseManager.onDatabaseReconnect(schemaName, this.reconnectHandler);\r\n this.bindMethods();\r\n }\r\n\r\n private bindMethods(): void {\r\n const methods = Object.getOwnPropertyNames(Object.getPrototypeOf(this));\r\n methods.forEach((method) => {\r\n if (\r\n typeof (this as any)[method] === \"function\" &&\r\n method !== \"constructor\"\r\n ) {\r\n (this as any)[method] = (this as any)[method].bind(this);\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Set primary key fields for the service\r\n */\r\n setPrimaryKeyFields(fields: string[]): this {\r\n this.primaryKeyFields = fields;\r\n return this;\r\n }\r\n\r\n /**\r\n * Initialize the service and establish database connection\r\n */\r\n async init(): Promise<this> {\r\n try {\r\n if (this.isInitialized) {\r\n return this;\r\n }\r\n\r\n this.dao = await DatabaseManager.getLazyLoading(this.schemaName);\r\n\r\n if (!this.dao) {\r\n throw new Error(\r\n `Failed to initialize DAO for schema: ${this.schemaName}`\r\n );\r\n }\r\n\r\n if (!this.dao.isConnectionOpen()) {\r\n await this.dao.connect();\r\n }\r\n\r\n this.isOpened = true;\r\n this.isInitialized = true;\r\n this._emit(\"initialized\", { schemaName: this.schemaName });\r\n\r\n return this;\r\n } catch (error) {\r\n this._handleError(\"INIT_ERROR\", error as Error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Create a new record - Safe version với comprehensive error handling\r\n */\r\n async create(data: Partial<T>): Promise<T | null> {\r\n await this._ensureInitialized();\r\n await this.ensureValidConnection();\r\n try {\r\n this._validateData(data);\r\n const queryTable = this.buildDataTable(data as Record<string, any>);\r\n const result = await this.dao!.insert(queryTable);\r\n if (result.rowsAffected === 0) {\r\n throw new Error(\"Insert operation failed - no rows affected\");\r\n }\r\n let createdRecord: T | null = null;\r\n const primaryKeyValue = data[this.primaryKeyFields[0] as keyof T];\r\n try {\r\n if (primaryKeyValue !== undefined && primaryKeyValue !== null) {\r\n createdRecord = await this.findById(primaryKeyValue as any);\r\n } else if (result.lastInsertRowId) {\r\n createdRecord = await this.findById(result.lastInsertRowId);\r\n }\r\n } catch (findError) {\r\n console.warn(`Warning: Could not retrieve created record:`, findError);\r\n }\r\n if (!createdRecord) {\r\n createdRecord = data as T;\r\n }\r\n this._emit(\"dataCreated\", { operation: \"create\", data: createdRecord });\r\n return createdRecord;\r\n } catch (error) {\r\n this._handleError(\"CREATE_ERROR\", error as Error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Update an existing record\r\n */\r\n async update(id: any, data: Partial<T>): Promise<T | null> {\r\n await this._ensureInitialized();\r\n\r\n try {\r\n if (!id) {\r\n throw new Error(\"ID is required for update\");\r\n }\r\n\r\n this._validateData(data);\r\n const updateData = {\r\n ...data,\r\n [this.primaryKeyFields[0]]: id,\r\n };\r\n\r\n const queryTable = this.buildDataTable(updateData as Record<string, any>);\r\n await this.dao!.update(queryTable);\r\n\r\n const result = await this.findById(id);\r\n this._emit(\"dataUpdated\", { operation: \"update\", id, data: result });\r\n return result;\r\n } catch (error) {\r\n this._handleError(\"UPDATE_ERROR\", error as Error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Delete a record by ID\r\n */\r\n async delete(id: any): Promise<boolean> {\r\n await this._ensureInitialized();\r\n\r\n try {\r\n if (!id) {\r\n throw new Error(\"ID is required for delete\");\r\n }\r\n\r\n const queryTable: QueryTable = {\r\n name: this.tableName,\r\n cols: [],\r\n wheres: [{ name: this.primaryKeyFields[0], value: id }],\r\n };\r\n\r\n const result = await this.dao!.delete(queryTable);\r\n const success = result.rowsAffected > 0;\r\n\r\n if (success) {\r\n this._emit(\"dataDeleted\", { operation: \"delete\", id });\r\n }\r\n\r\n return success;\r\n } catch (error) {\r\n this._handleError(\"DELETE_ERROR\", error as Error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Find a record by ID\r\n */\r\n async findById(id: any): Promise<T | null> {\r\n await this._ensureInitialized();\r\n\r\n try {\r\n if (!id) {\r\n throw new Error(\"ID is required\");\r\n }\r\n\r\n const conditions = { [this.primaryKeyFields[0]]: id };\r\n const queryTable = this.buildSelectTable(conditions);\r\n const result = await this.dao!.select(queryTable);\r\n\r\n const record = Object.keys(result).length > 0 ? (result as T) : null;\r\n this._emit(\"dataFetched\", { operation: \"findById\", id });\r\n return record;\r\n } catch (error) {\r\n this._handleError(\"FIND_BY_ID_ERROR\", error as Error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Find the first record matching conditions\r\n */\r\n async findFirst(conditions: Record<string, any> = {}): Promise<T | null> {\r\n await this._ensureInitialized();\r\n\r\n try {\r\n const queryTable = this.buildSelectTable(conditions);\r\n const result = await this.dao!.select(queryTable);\r\n\r\n const record = Object.keys(result).length > 0 ? (result as T) : null;\r\n this._emit(\"dataFetched\", { operation: \"findFirst\" });\r\n return record;\r\n } catch (error) {\r\n this._handleError(\"FIND_FIRST_ERROR\", error as Error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Find all records matching conditions\r\n */\r\n async findAll(\r\n conditions: Record<string, any> = {},\r\n options: FindOptions = {}\r\n ): Promise<T[]> {\r\n await this._ensureInitialized();\r\n\r\n try {\r\n // Build where clauses from conditions\r\n const whereFromConditions = this.buildWhereFromObject(conditions);\r\n const allWheres = [...whereFromConditions, ...(options.where || [])];\r\n\r\n const queryTable: QueryTable = {\r\n name: this.tableName,\r\n cols: options.columns ? options.columns.map((name) => ({ name })) : [],\r\n wheres: allWheres,\r\n orderbys: options.orderBy,\r\n limitOffset: {\r\n limit: options.limit,\r\n offset: options.offset,\r\n },\r\n };\r\n\r\n const results = await this.dao!.selectAll(queryTable);\r\n this._emit(\"dataFetched\", {\r\n operation: \"findAll\",\r\n count: results.length,\r\n });\r\n return results as T[];\r\n } catch (error) {\r\n this._handleError(\"FIND_ALL_ERROR\", error as Error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Count records matching conditions\r\n */\r\n async count(where?: WhereClause[] | Record<string, any>): Promise<number> {\r\n await this._ensureInitialized();\r\n\r\n try {\r\n let whereConditions: WhereClause[] = [];\r\n\r\n if (Array.isArray(where)) {\r\n whereConditions = where;\r\n } else if (where && typeof where === \"object\") {\r\n whereConditions = this.buildWhereFromObject(where);\r\n }\r\n\r\n const queryTable: QueryTable = {\r\n name: this.tableName,\r\n cols: [{ name: \"COUNT(*) as count\" }],\r\n wheres: whereConditions,\r\n };\r\n\r\n const result = await this.dao!.select(queryTable);\r\n return result.count || 0;\r\n } catch (error) {\r\n this._handleError(\"COUNT_ERROR\", error as Error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Check if a record exists by ID\r\n */\r\n async exists(id: any): Promise<boolean> {\r\n const item = await this.findById(id);\r\n return item !== null;\r\n }\r\n\r\n /**\r\n * Truncate table (delete all records and reset auto-increment)\r\n */\r\n async truncate(): Promise<void> {\r\n await this._ensureInitialized();\r\n\r\n try {\r\n await this.dao!.execute(`DELETE FROM ${this.tableName}`);\r\n await this.dao!.execute(\r\n `DELETE FROM sqlite_sequence WHERE name='${this.tableName}'`\r\n );\r\n this._emit(\"tableTruncated\", { tableName: this.tableName });\r\n } catch (error) {\r\n this._handleError(\"TRUNCATE_ERROR\", error as Error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Bulk insert records\r\n */\r\n async bulkInsert(items: Partial<T>[]): Promise<ImportResult> {\r\n await this._ensureInitialized();\r\n\r\n try {\r\n if (!Array.isArray(items) || items.length === 0) {\r\n throw new Error(\"Items must be a non-empty array\");\r\n }\r\n\r\n const result = await this.dao!.importData({\r\n tableName: this.tableName,\r\n data: items as Record<string, any>[],\r\n batchSize: 1000,\r\n skipErrors: false,\r\n validateData: true,\r\n });\r\n\r\n this._emit(\"dataBulkCreated\", {\r\n operation: \"bulkInsert\",\r\n count: result.successRows,\r\n });\r\n return result;\r\n } catch (error) {\r\n this._handleError(\"BULK_INSERT_ERROR\", error as Error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Bulk create records with transaction support\r\n */\r\n async bulkCreate(dataArray: Record<string, any>[]): Promise<T[]> {\r\n await this._ensureInitialized();\r\n\r\n try {\r\n if (!Array.isArray(dataArray) || dataArray.length === 0) {\r\n throw new Error(\"Data must be a non-empty array\");\r\n }\r\n\r\n const results: T[] = [];\r\n await this.executeTransaction(async () => {\r\n for (const data of dataArray) {\r\n this._validateData(data);\r\n const queryTable = this.buildDataTable(data);\r\n await this.dao!.insert(queryTable);\r\n results.push(data as T);\r\n }\r\n });\r\n\r\n this._emit(\"dataBulkCreated\", {\r\n operation: \"bulkCreate\",\r\n count: results.length,\r\n });\r\n return results;\r\n } catch (error) {\r\n this._handleError(\"BULK_CREATE_ERROR\", error as Error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Execute operations within a transaction\r\n */\r\n async executeTransaction(callback: () => Promise<any>): Promise<any> {\r\n await this._ensureInitialized();\r\n\r\n try {\r\n await this.dao!.beginTransaction();\r\n const result = await callback();\r\n await this.dao!.commitTransaction();\r\n this._emit(\"transactionCompleted\", { operation: \"transaction\" });\r\n return result;\r\n } catch (error) {\r\n try {\r\n await this.dao!.rollbackTransaction();\r\n } catch (rollbackError) {\r\n this._handleError(\"ROLLBACK_ERROR\", rollbackError as Error);\r\n }\r\n this._handleError(\"TRANSACTION_ERROR\", error as Error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Import data from CSV\r\n */\r\n async importFromCSV(\r\n csvData: string,\r\n options: {\r\n delimiter?: string;\r\n hasHeader?: boolean;\r\n columnMappings?: ColumnMapping[];\r\n } & Partial<ImportOptions> = {}\r\n ): Promise<ImportResult> {\r\n await this._ensureInitialized();\r\n\r\n try {\r\n const result = await this.dao!.importFromCSV(\r\n this.tableName,\r\n csvData,\r\n options\r\n );\r\n this._emit(\"dataImported\", { operation: \"importFromCSV\", result });\r\n return result;\r\n } catch (error) {\r\n this._handleError(\"IMPORT_CSV_ERROR\", error as Error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Import data with column mapping\r\n */\r\n async importDataWithMapping(\r\n data: Record<string, any>[],\r\n columnMappings: ColumnMapping[],\r\n options: Partial<ImportOptions> = {}\r\n ): Promise<ImportResult> {\r\n await this._ensureInitialized();\r\n\r\n try {\r\n const result = await this.dao!.importDataWithMapping(\r\n this.tableName,\r\n data,\r\n columnMappings,\r\n options\r\n );\r\n this._emit(\"dataImported\", { operation: \"importWithMapping\", result });\r\n return result;\r\n } catch (error) {\r\n this._handleError(\"IMPORT_MAPPING_ERROR\", error as Error);\r\n throw error;\r\n }\r\n }\r\n\r\n // Utility methods\r\n protected buildSelectTable(\r\n conditions: Record<string, any> = {},\r\n options: FindOptions = {}\r\n ): QueryTable {\r\n const queryTable: QueryTable = {\r\n name: this.tableName,\r\n cols: [],\r\n wheres: [],\r\n orderbys: options.orderBy || [],\r\n limitOffset: {},\r\n };\r\n\r\n if (options.columns && options.columns.length > 0) {\r\n queryTable.cols = options.columns.map((name) => ({ name }));\r\n }\r\n\r\n if (conditions && Object.keys(conditions).length > 0) {\r\n queryTable.wheres = Object.entries(conditions).map(([key, value]) => ({\r\n name: key,\r\n value,\r\n operator: \"=\",\r\n }));\r\n }\r\n\r\n if (options.limit !== undefined) {\r\n queryTable.limitOffset!.limit = options.limit;\r\n }\r\n if (options.offset !== undefined) {\r\n queryTable.limitOffset!.offset = options.offset;\r\n }\r\n\r\n return queryTable;\r\n }\r\n\r\n protected buildDataTable(data: Record<string, any>): QueryTable {\r\n return this.dao!.convertJsonToQueryTable(\r\n this.tableName,\r\n data,\r\n this.primaryKeyFields\r\n );\r\n }\r\n\r\n protected buildWhereFromObject(obj: Record<string, any>): WhereClause[] {\r\n return Object.entries(obj)\r\n .filter(([_, value]) => value !== undefined)\r\n .map(([key, value]) => ({ name: key, value }));\r\n }\r\n\r\n // Event system\r\n on(event: string, handler: EventHandler): this {\r\n if (!this.eventListeners.has(event)) {\r\n this.eventListeners.set(event, []);\r\n }\r\n this.eventListeners.get(event)!.push(handler);\r\n return this;\r\n }\r\n\r\n off(event: string, handler: EventHandler): this {\r\n const handlers = this.eventListeners.get(event);\r\n if (handlers) {\r\n const index = handlers.indexOf(handler);\r\n if (index > -1) {\r\n handlers.splice(index, 1);\r\n }\r\n }\r\n return this;\r\n }\r\n\r\n protected _emit(event: string, data: any): void {\r\n const handlers = this.eventListeners.get(event);\r\n if (handlers) {\r\n handlers.forEach((handler) => {\r\n try {\r\n handler(data);\r\n } catch (error) {\r\n // Handle error in event handler\r\n }\r\n });\r\n }\r\n }\r\n\r\n // Error handling\r\n setErrorHandler(errorType: string, handler: ErrorHandler): this {\r\n this.errorHandlers.set(errorType, handler);\r\n return this;\r\n }\r\n\r\n protected _handleError(errorType: string, error: Error): void {\r\n const handler = this.errorHandlers.get(errorType);\r\n if (handler) {\r\n try {\r\n handler(error);\r\n } catch (handlerError) {\r\n // Handle error in error handler\r\n }\r\n }\r\n this._emit(\"error\", { errorType, error });\r\n }\r\n\r\n protected _validateData(data: any): void {\r\n if (!data || typeof data !== \"object\") {\r\n throw new Error(\"Data must be a valid object\");\r\n }\r\n }\r\n\r\n protected async _ensureInitialized(): Promise<void> {\r\n if (!this.isInitialized) {\r\n await this.init();\r\n }\r\n }\r\n\r\n private async ensureValidConnection(): Promise<void> {\r\n try {\r\n const isConnected = this.dao?.isConnectionOpen();\r\n if (!isConnected) {\r\n this.dao = await DatabaseManager.ensureDatabaseConnection(\r\n this.schemaName\r\n );\r\n }\r\n } catch (error) {\r\n this.dao = await DatabaseManager.ensureDatabaseConnection(\r\n this.schemaName\r\n );\r\n }\r\n }\r\n\r\n // Information and status methods\r\n async getDatabaseInfo(): Promise<any> {\r\n await this._ensureInitialized();\r\n return await this.dao!.getDatabaseInfo();\r\n }\r\n\r\n async getTableInfo(): Promise<any[]> {\r\n await this._ensureInitialized();\r\n return await this.dao!.getTableInfo(this.tableName);\r\n }\r\n\r\n getStatus(): ServiceStatus {\r\n return {\r\n schemaName: this.schemaName,\r\n tableName:this.tableName,\r\n isOpened: this.isOpened,\r\n isInitialized: this.isInitialized,\r\n hasDao: !!this.dao,\r\n };\r\n }\r\n\r\n async healthCheck(): Promise<HealthCheckResult> {\r\n try {\r\n await this._ensureInitialized();\r\n const count = await this.count();\r\n return {\r\n healthy: true,\r\n schemaName: this.schemaName,\r\n recordCount: count,\r\n timestamp: new Date().toISOString(),\r\n };\r\n } catch (error) {\r\n return {\r\n healthy: false,\r\n schemaName: this.schemaName,\r\n error: (error as Error).message,\r\n timestamp: new Date().toISOString(),\r\n };\r\n }\r\n }\r\n\r\n // Lifecycle management\r\n async close(): Promise<boolean> {\r\n try {\r\n if (this.dao) {\r\n await this.dao.close();\r\n }\r\n\r\n this.isOpened = false;\r\n this.isInitialized = false;\r\n this.eventListeners.clear();\r\n this.errorHandlers.clear();\r\n this.cache.clear();\r\n\r\n this._emit(\"closed\", { schemaName: this.schemaName });\r\n return true;\r\n } catch (error) {\r\n this._handleError(\"CLOSE_ERROR\", error as Error);\r\n throw error;\r\n }\r\n }\r\n\r\n public destroy(): void {\r\n // Remove reconnect listener\r\n DatabaseManager.offDatabaseReconnect(\r\n this.schemaName,\r\n this.reconnectHandler\r\n );\r\n\r\n // Clear all resources\r\n this.eventListeners.clear();\r\n this.errorHandlers.clear();\r\n this.cache.clear();\r\n }\r\n\r\n // Alias methods for backward compatibility\r\n async getAll(\r\n conditions: Record<string, any> = {},\r\n options: FindOptions = {}\r\n ): Promise<T[]> {\r\n return this.findAll(conditions, options);\r\n }\r\n\r\n async getById(id: string | number): Promise<T | null> {\r\n return this.findById(id);\r\n }\r\n\r\n async getFirst(conditions: Record<string, any> = {}): Promise<T | null> {\r\n return this.findFirst(conditions);\r\n }\r\n}\r\n","// src/query/query-builder.ts\r\nimport { UniversalDAO } from '../core/universal-dao';\r\nimport { SQLiteResult, SQLiteRow } from '../types';\r\n\r\nexport interface QueryCondition {\r\n field: string;\r\n operator: string;\r\n value: any;\r\n}\r\n\r\nexport interface JoinClause {\r\n type: 'INNER' | 'LEFT' | 'RIGHT' | 'FULL OUTER';\r\n table: string;\r\n condition: string;\r\n}\r\n\r\nexport interface SubQuery {\r\n query: QueryBuilder;\r\n alias: string;\r\n}\r\n\r\n/**\r\n * Enhanced QueryBuilder with advanced SQL query construction capabilities\r\n */\r\nexport class QueryBuilder {\r\n private tableName = '';\r\n private selectFields: string[] = ['*'];\r\n private joinClauses: JoinClause[] = [];\r\n private whereConditions: QueryCondition[] = [];\r\n private groupByFields: string[] = [];\r\n private havingConditions: QueryCondition[] = [];\r\n private orderByFields: string[] = [];\r\n private limitValue: number | null = null;\r\n private offsetValue: number | null = null;\r\n private params: any[] = [];\r\n private unionQueries: QueryBuilder[] = [];\r\n private subQueries: SubQuery[] = [];\r\n private cteQueries: Map<string, QueryBuilder> = new Map();\r\n private dao: UniversalDAO | null = null;\r\n\r\n constructor(dao?: UniversalDAO) {\r\n this.dao = dao || null;\r\n }\r\n\r\n static table(name: string, dao?: UniversalDAO): QueryBuilder {\r\n const builder = new QueryBuilder(dao);\r\n builder.tableName = name;\r\n return builder;\r\n }\r\n\r\n static from(name: string, dao?: UniversalDAO): QueryBuilder {\r\n return QueryBuilder.table(name, dao);\r\n }\r\n\r\n // SELECT operations\r\n select(fields: string | string[]): QueryBuilder {\r\n this.selectFields = Array.isArray(fields) ? fields : [fields];\r\n return this;\r\n }\r\n\r\n selectRaw(raw: string): QueryBuilder {\r\n this.selectFields = [raw];\r\n return this;\r\n }\r\n\r\n selectDistinct(fields: string | string[]): QueryBuilder {\r\n const fieldList = Array.isArray(fields) ? fields.join(', ') : fields;\r\n this.selectFields = [`DISTINCT ${fieldList}`];\r\n return this;\r\n }\r\n\r\n // JOIN operations\r\n join(table: string, condition: string, type: JoinClause['type'] = 'INNER'): QueryBuilder {\r\n this.joinClauses.push({ type, table, condition });\r\n return this;\r\n }\r\n\r\n innerJoin(table: string, condition: string): QueryBuilder {\r\n return this.join(table, condition, 'INNER');\r\n }\r\n\r\n leftJoin(table: string, condition: string): QueryBuilder {\r\n return this.join(table, condition, 'LEFT');\r\n }\r\n\r\n rightJoin(table: string, condition: string): QueryBuilder {\r\n return this.join(table, condition, 'RIGHT');\r\n }\r\n\r\n fullOuterJoin(table: string, condition: string): QueryBuilder {\r\n return this.join(table, condition, 'FULL OUTER');\r\n }\r\n\r\n // WHERE conditions\r\n where(field: string, operator: string, value?: any): QueryBuilder;\r\n where(field: string, value: any): QueryBuilder;\r\n where(conditions: Record<string, any>): QueryBuilder;\r\n where(fieldOrConditions: string | Record<string, any>, operatorOrValue?: string | any, value?: any): QueryBuilder {\r\n if (typeof fieldOrConditions === 'object') {\r\n // Handle object of conditions\r\n Object.entries(fieldOrConditions).forEach(([field, val]) => {\r\n this.whereConditions.push({ field, operator: '=', value: val });\r\n });\r\n return this;\r\n }\r\n\r\n let operator = '=';\r\n let actualValue = operatorOrValue;\r\n\r\n if (arguments.length === 3) {\r\n operator = operatorOrValue;\r\n actualValue = value;\r\n }\r\n\r\n this.whereConditions.push({ \r\n field: fieldOrConditions, \r\n operator, \r\n value: actualValue \r\n });\r\n \r\n return this;\r\n }\r\n\r\n whereEquals(field: string, value: any): QueryBuilder {\r\n return this.where(field, '=', value);\r\n }\r\n\r\n whereNot(field: string, value: any): QueryBuilder {\r\n return this.where(field, '!=', value);\r\n }\r\n\r\n whereLike(field: string, value: string): QueryBuilder {\r\n return this.where(field, 'LIKE', value);\r\n }\r\n\r\n whereNotLike(field: string, value: string): QueryBuilder {\r\n return this.where(field, 'NOT LIKE', value);\r\n }\r\n\r\n whereIn(field: string, values: any[]): QueryBuilder {\r\n this.whereConditions.push({ field, operator: 'IN', value: values });\r\n return this;\r\n }\r\n\r\n whereNotIn(field: string, values: any[]): QueryBuilder {\r\n this.whereConditions.push({ field, operator: 'NOT IN', value: values });\r\n return this;\r\n }\r\n\r\n whereBetween(field: string, min: any, max: any): QueryBuilder {\r\n this.whereConditions.push({ field, operator: 'BETWEEN', value: [min, max] });\r\n return this;\r\n }\r\n\r\n whereNotBetween(field: string, min: any, max: any): QueryBuilder {\r\n this.whereConditions.push({ field, operator: 'NOT BETWEEN', value: [min, max] });\r\n return this;\r\n }\r\n\r\n whereNull(field: string): QueryBuilder {\r\n this.whereConditions.push({ field, operator: 'IS NULL', value: null });\r\n return this;\r\n }\r\n\r\n whereNotNull(field: string): QueryBuilder {\r\n this.whereConditions.push({ field, operator: 'IS NOT NULL', value: null });\r\n return this;\r\n }\r\n\r\n whereExists(subquery: QueryBuilder): QueryBuilder {\r\n this.whereConditions.push({ \r\n field: '', \r\n operator: 'EXISTS', \r\n value: subquery \r\n });\r\n return this;\r\n }\r\n\r\n whereNotExists(subquery: QueryBuilder): QueryBuilder {\r\n this.whereConditions.push({ \r\n field: '', \r\n operator: 'NOT EXISTS', \r\n value: subquery \r\n });\r\n return this;\r\n }\r\n\r\n // OR WHERE conditions\r\n orWhere(field: string, operator: string, value?: any): QueryBuilder;\r\n orWhere(field: string, value: any): QueryBuilder;\r\n orWhere(field: string, operatorOrValue?: string | any, value?: any): QueryBuilder {\r\n // Implementation similar to where() but with OR logic\r\n // This would require refactoring the condition structure to support AND/OR\r\n return this.where(field, operatorOrValue as string, value);\r\n }\r\n\r\n // GROUP BY and HAVING\r\n groupBy(fields: string | string[]): QueryBuilder {\r\n this.groupByFields = Array.isArray(fields) ? fields : [fields];\r\n return this;\r\n }\r\n\r\n having(field: string, operator: string, value?: any): QueryBuilder {\r\n let actualOperator = '=';\r\n let actualValue = operator;\r\n\r\n if (arguments.length === 3) {\r\n actualOperator = operator;\r\n actualValue = value;\r\n }\r\n\r\n this.havingConditions.push({ \r\n field, \r\n operator: actualOperator, \r\n value: actualValue \r\n });\r\n return this;\r\n }\r\n\r\n havingCount(field: string, operator: string, value: number): QueryBuilder {\r\n return this.having(`COUNT(${field})`, operator, value);\r\n }\r\n\r\n // ORDER BY\r\n orderBy(field: string, direction: 'ASC' | 'DESC' = 'ASC'): QueryBuilder {\r\n this.orderByFields.push(`${field} ${direction}`);\r\n return this;\r\n }\r\n\r\n orderByDesc(field: string): QueryBuilder {\r\n return this.orderBy(field, 'DESC');\r\n }\r\n\r\n orderByRaw(raw: string): QueryBuilder {\r\n this.orderByFields.push(raw);\r\n return this;\r\n }\r\n\r\n latest(field: string = 'created_at'): QueryBuilder {\r\n return this.orderByDesc(field);\r\n }\r\n\r\n oldest(field: string = 'created_at'): QueryBuilder {\r\n return this.orderBy(field, 'ASC');\r\n }\r\n\r\n // LIMIT and OFFSET\r\n limit(count: number): QueryBuilder {\r\n this.limitValue = count;\r\n return this;\r\n }\r\n\r\n offset(count: number): QueryBuilder {\r\n this.offsetValue = count;\r\n return this;\r\n }\r\n\r\n skip(count: number): QueryBuilder {\r\n return this.offset(count);\r\n }\r\n\r\n take(count: number): QueryBuilder {\r\n return this.limit(count);\r\n }\r\n\r\n firstRow(): QueryBuilder {\r\n return this.limit(1);\r\n }\r\n\r\n paginate(page: number, perPage: number): QueryBuilder {\r\n this.limitValue = perPage;\r\n this.offsetValue = (page - 1) * perPage;\r\n return this;\r\n }\r\n\r\n // UNION operations\r\n union(query: QueryBuilder): QueryBuilder {\r\n this.unionQueries.push(query);\r\n return this;\r\n }\r\n\r\n unionAll(query: QueryBuilder): QueryBuilder {\r\n // Note: SQLite doesn't differentiate UNION and UNION ALL like other databases\r\n return this.union(query);\r\n }\r\n\r\n // CTE (Common Table Expressions)\r\n with(alias: string, query: QueryBuilder): QueryBuilder {\r\n this.cteQueries.set(alias, query);\r\n return this;\r\n }\r\n\r\n // Subqueries\r\n whereSubQuery(field: string, operator: string, subquery: QueryBuilder): QueryBuilder {\r\n this.subQueries.push({ query: subquery, alias: '' });\r\n this.whereConditions.push({ field, operator, value: subquery });\r\n return this;\r\n }\r\n\r\n // Aggregation functions\r\n count(field: string = '*'): QueryBuilder {\r\n this.selectFields = [`COUNT(${field}) as count`];\r\n return this;\r\n }\r\n\r\n sum(field: string): QueryBuilder {\r\n this.selectFields = [`SUM(${field}) as sum`];\r\n return this;\r\n }\r\n\r\n avg(field: string): QueryBuilder {\r\n this.selectFields = [`AVG(${field}) as avg`];\r\n return this;\r\n }\r\n\r\n max(field: string): QueryBuilder {\r\n this.selectFields = [`MAX(${field}) as max`];\r\n return this;\r\n }\r\n\r\n min(field: string): QueryBuilder {\r\n this.selectFields = [`MIN(${field}) as min`];\r\n return this;\r\n }\r\n\r\n // SQL Generation\r\n toSQL(): { sql: string; params: any[] } {\r\n let sql = '';\r\n const params: any[] = [];\r\n\r\n // CTE queries\r\n if (this.cteQueries.size > 0) {\r\n const cteList: string[] = [];\r\n this.cteQueries.forEach((query, alias) => {\r\n const { sql: cteSql, params: cteParams } = query.toSQL();\r\n cteList.push(`${alias} AS (${cteSql})`);\r\n params.push(...cteParams);\r\n });\r\n sql += `WITH ${cteList.join(', ')} `;\r\n }\r\n\r\n // Main SELECT\r\n sql += `SELECT ${this.selectFields.join(', ')} FROM ${this.tableName}`;\r\n\r\n // JOINs\r\n if (this.joinClauses.length > 0) {\r\n this.joinClauses.forEach(join => {\r\n sql += ` ${join.type} JOIN ${join.table} ON ${join.condition}`;\r\n });\r\n }\r\n\r\n // WHERE conditions\r\n if (this.whereConditions.length > 0) {\r\n const conditions: string[] = [];\r\n this.whereConditions.forEach(condition => {\r\n const { clause, conditionParams } = this.buildCondition(condition);\r\n conditions.push(clause);\r\n params.push(...conditionParams);\r\n });\r\n sql += ` WHERE ${conditions.join(' AND ')}`;\r\n }\r\n\r\n // GROUP BY\r\n if (this.groupByFields.length > 0) {\r\n sql += ` GROUP BY ${this.groupByFields.join(', ')}`;\r\n }\r\n\r\n // HAVING\r\n if (this.havingConditions.length > 0) {\r\n const conditions: string[] = [];\r\n this.havingConditions.forEach(condition => {\r\n const { clause, conditionParams } = this.buildCondition(condition);\r\n conditions.push(clause);\r\n params.push(...conditionParams);\r\n });\r\n sql += ` HAVING ${conditions.join(' AND ')}`;\r\n }\r\n\r\n // ORDER BY\r\n if (this.orderByFields.length > 0) {\r\n sql += ` ORDER BY ${this.orderByFields.join(', ')}`;\r\n }\r\n\r\n // LIMIT\r\n if (this.limitValue !== null) {\r\n sql += ` LIMIT ${this.limitValue}`;\r\n }\r\n\r\n // OFFSET\r\n if (this.offsetValue !== null) {\r\n sql += ` OFFSET ${this.offsetValue}`;\r\n }\r\n\r\n // UNION queries\r\n if (this.unionQueries.length > 0) {\r\n this.unionQueries.forEach(unionQuery => {\r\n const { sql: unionSql, params: unionParams } = unionQuery.toSQL();\r\n sql += ` UNION ${unionSql}`;\r\n params.push(...unionParams);\r\n });\r\n }\r\n\r\n return { sql, params };\r\n }\r\n\r\n private buildCondition(condition: QueryCondition): { clause: string; conditionParams: any[] } {\r\n const { field, operator, value } = condition;\r\n const params: any[] = [];\r\n\r\n switch (operator.toUpperCase()) {\r\n case 'IN':\r\n case 'NOT IN':\r\n const placeholders = (value as any[]).map(() => '?').join(', ');\r\n params.push(...(value as any[]));\r\n return { \r\n clause: `${field} ${operator} (${placeholders})`, \r\n conditionParams: params \r\n };\r\n\r\n case 'BETWEEN':\r\n case 'NOT BETWEEN':\r\n params.push(value[0], value[1]);\r\n return { \r\n clause: `${field} ${operator} ? AND ?`, \r\n conditionParams: params \r\n };\r\n\r\n case 'IS NULL':\r\n case 'IS NOT NULL':\r\n return { \r\n clause: `${field} ${operator}`, \r\n conditionParams: [] \r\n };\r\n\r\n case 'EXISTS':\r\n case 'NOT EXISTS':\r\n const { sql: subSql, params: subParams } = (value as QueryBuilder).toSQL();\r\n params.push(...subParams);\r\n return { \r\n clause: `${operator} (${subSql})`, \r\n conditionParams: params \r\n };\r\n\r\n default:\r\n if (value instanceof QueryBuilder) {\r\n const { sql: subSql, params: subParams } = value.toSQL();\r\n params.push(...subParams);\r\n return { \r\n clause: `${field} ${operator} (${subSql})`, \r\n conditionParams: params \r\n };\r\n }\r\n params.push(value);\r\n return { \r\n clause: `${field} ${operator} ?`, \r\n conditionParams: params \r\n };\r\n }\r\n }\r\n\r\n // Execution methods (require DAO)\r\n async get(): Promise<SQLiteRow[]> {\r\n if (!this.dao) {\r\n throw new Error('DAO instance required for query execution');\r\n }\r\n const { sql, params } = this.toSQL();\r\n const result = await this.dao.execute(sql, params);\r\n return result.rows;\r\n }\r\n\r\n async first(): Promise<SQLiteRow | null> {\r\n this.limit(1);\r\n const results = await this.get(); // This will apply the limit(1) set by firstRow()\r\n return results.length > 0 ? results[0] : null;\r\n }\r\n\r\n async pluck(column: string): Promise<any[]> {\r\n this.select(column);\r\n const results = await this.get();\r\n return results.map(row => row[column]);\r\n }\r\n\r\n async exists(): Promise<boolean> {\r\n this.select('1').limit(1);\r\n const results = await this.get();\r\n return results.length > 0;\r\n }\r\n\r\n async countResult(): Promise<number> {\r\n this.count();\r\n const result = await this.first();\r\n return result ? result.count : 0;\r\n }\r\n\r\n // Static helper methods for DML operations\r\n static insert(tableName: string, data: Record<string, any>): { sql: string; params: any[] } {\r\n const fields = Object.keys(data);\r\n const values = Object.values(data);\r\n const placeholders = values.map(() => '?').join(', ');\r\n\r\n return {\r\n sql: `INSERT INTO ${tableName} (${fields.join(', ')}) VALUES (${placeholders})`,\r\n params: values\r\n };\r\n }\r\n\r\n static insertMany(tableName: string, dataArray: Record<string, any>[]): { sql: string; params: any[] } {\r\n if (dataArray.length === 0) {\r\n throw new Error('Data array cannot be empty');\r\n }\r\n\r\n const fields = Object.keys(dataArray[0]);\r\n const placeholders = fields.map(() => '?').join(', ');\r\n const valueGroups = dataArray.map(() => `(${placeholders})`).join(', ');\r\n\r\n const allValues = dataArray.flatMap(data => Object.values(data));\r\n\r\n return {\r\n sql: `INSERT INTO ${tableName} (${fields.join(', ')}) VALUES ${valueGroups}`,\r\n params: allValues\r\n };\r\n }\r\n\r\n static update(tableName: string, data: Record<string, any>, where: string, whereParams: any[] = []): { sql: string; params: any[] } {\r\n const sets = Object.keys(data).map(key => `${key} = ?`).join(', ');\r\n const params = [...Object.values(data), ...whereParams];\r\n\r\n return {\r\n sql: `UPDATE ${tableName} SET ${sets} WHERE ${where}`,\r\n params\r\n };\r\n }\r\n\r\n static delete(tableName: string, where: string, whereParams: any[] = []): { sql: string; params: any[] } {\r\n return {\r\n sql: `DELETE FROM ${tableName} WHERE ${where}`,\r\n params: whereParams\r\n };\r\n }\r\n\r\n static upsert(tableName: string, data: Record<string, any>, conflictColumns: string[]): { sql: string; params: any[] } {\r\n const fields = Object.keys(data);\r\n const values = Object.values(data);\r\n const placeholders = values.map(() => '?').join(', ');\r\n\r\n const updateColumns = fields.filter(field => !conflictColumns.includes(field));\r\n const updateClause = updateColumns.length > 0\r\n ? updateColumns.map(col => `${col} = excluded.${col}`).join(', ')\r\n : '';\r\n\r\n let sql = `INSERT INTO ${tableName} (${fields.join(', ')}) VALUES (${placeholders})`;\r\n\r\n if (updateColumns.length > 0) {\r\n sql += ` ON CONFLICT(${conflictColumns.join(', ')}) DO UPDATE SET ${updateClause}`;\r\n } else {\r\n sql += ` ON CONFLICT(${conflictColumns.join(', ')}) DO NOTHING`;\r\n }\r\n\r\n return { sql, params: values };\r\n }\r\n\r\n // Utility methods\r\n clone(): QueryBuilder {\r\n if (!this.dao) throw new Error('DAO instance required for cloning QueryBuilder');\r\n const cloned = new QueryBuilder(this.dao);\r\n cloned.tableName = this.tableName;\r\n cloned.selectFields = [...this.selectFields];\r\n cloned.joinClauses = [...this.joinClauses];\r\n cloned.whereConditions = [...this.whereConditions];\r\n cloned.groupByFields = [...this.groupByFields];\r\n cloned.havingConditions = [...this.havingConditions];\r\n cloned.orderByFields = [...this.orderByFields];\r\n cloned.limitValue = this.limitValue;\r\n cloned.offsetValue = this.offsetValue;\r\n cloned.unionQueries = [...this.unionQueries];\r\n cloned.subQueries = [...this.subQueries];\r\n cloned.cteQueries = new Map(this.cteQueries);\r\n return cloned;\r\n }\r\n\r\n toRawSQL(): string {\r\n const { sql, params } = this.toSQL();\r\n let rawSql = sql;\r\n params.forEach(param => {\r\n if (typeof param === 'string') {\r\n rawSql = rawSql.replace('?', `'${param.replace(/'/g, \"''\")}'`);\r\n } else if (param === null || param === undefined) {\r\n rawSql = rawSql.replace('?', 'NULL');\r\n } else {\r\n rawSql = rawSql.replace('?', String(param));\r\n }\r\n });\r\n return rawSql;\r\n }\r\n\r\n explain(): QueryBuilder {\r\n this.selectFields = ['EXPLAIN QUERY PLAN ' + this.selectFields.join(', ')];\r\n return this;\r\n }\r\n}","// src/core/service-manager.ts\r\nimport { BaseService } from './base-service';\r\nimport { ServiceStatus, HealthCheckResult } from '../types';\r\n\r\n// Concrete service class mặc định\r\nexport class DefaultService extends BaseService {\r\n // BaseService đã cung cấp đầy đủ functionality\r\n}\r\n\r\n// Interface cho cấu hình service\r\nexport interface ServiceConfig {\r\n schemaName: string;\r\n tableName: string;\r\n primaryKeyFields?: string[];\r\n serviceClass?: new (schemaName: string, tableName: string) => BaseService;\r\n}\r\n\r\n// Interface cho trạng thái service\r\nexport interface ServiceInfo {\r\n key: string;\r\n schemaName: string;\r\n tableName: string;\r\n status: ServiceStatus;\r\n isRegistered: boolean;\r\n createdAt: string;\r\n lastAccessed?: string;\r\n}\r\n\r\n// Interface cho báo cáo sức khỏe\r\nexport interface HealthReport {\r\n totalServices: number;\r\n healthyServices: number;\r\n unhealthyServices: number;\r\n services: Array<HealthCheckResult & { serviceKey: string }>;\r\n timestamp: string;\r\n overallHealth: boolean;\r\n}\r\n\r\n// Event types cho ServiceManager\r\nexport interface ServiceManagerEvent {\r\n type: 'SERVICE_CREATED' | 'SERVICE_DESTROYED' | 'SERVICE_ERROR' | 'HEALTH_CHECK_COMPLETED';\r\n serviceKey: string;\r\n schemaName: string;\r\n tableName: string;\r\n timestamp: string;\r\n data?: any;\r\n error?: Error;\r\n}\r\n\r\nexport type ServiceManagerEventHandler = (event: ServiceManagerEvent) => void;\r\n\r\n/**\r\n * ServiceManager - Quản lý vòng đời các service con kế thừa từ BaseService\r\n * Không can thiệp vào DatabaseManager, chỉ tập trung quản lý service instances\r\n */\r\nexport class ServiceManager {\r\n private static instance: ServiceManager | null = null;\r\n \r\n // Service registry\r\n private services: Map<string, BaseService> = new Map();\r\n private serviceConfigs: Map<string, ServiceConfig> = new Map();\r\n private serviceMetadata: Map<string, { createdAt: string; lastAccessed?: string }> = new Map();\r\n \r\n // Event system\r\n private eventHandlers: Map<string, ServiceManagerEventHandler[]> = new Map();\r\n \r\n // Lifecycle management\r\n private isShuttingDown = false;\r\n private cleanupInterval: NodeJS.Timeout | null = null;\r\n \r\n private constructor() {\r\n this.bindMethods();\r\n this.startPeriodicCleanup();\r\n }\r\n\r\n /**\r\n * Singleton instance\r\n */\r\n public static getInstance(): ServiceManager {\r\n if (!ServiceManager.instance) {\r\n ServiceManager.instance = new ServiceManager();\r\n }\r\n return ServiceManager.instance;\r\n }\r\n\r\n /**\r\n * Reset singleton (chủ yếu cho testing)\r\n */\r\n public static resetInstance(): void {\r\n if (ServiceManager.instance) {\r\n ServiceManager.instance.destroy();\r\n ServiceManager.instance = null;\r\n }\r\n }\r\n\r\n private bindMethods(): void {\r\n const methods = Object.getOwnPropertyNames(Object.getPrototypeOf(this));\r\n methods.forEach(method => {\r\n if (typeof (this as any)[method] === 'function' && method !== 'constructor') {\r\n (this as any)[method] = (this as any)[method].bind(this);\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Tạo service key duy nhất\r\n */\r\n private createServiceKey(schemaName: string, tableName: string): string {\r\n return `${schemaName}:${tableName}`;\r\n }\r\n\r\n /**\r\n * Validate service config\r\n */\r\n private validateServiceConfig(config: ServiceConfig): void {\r\n if (!config.schemaName?.trim()) {\r\n throw new Error('Schema name is required and cannot be empty');\r\n }\r\n if (!config.tableName?.trim()) {\r\n throw new Error('Table name is required and cannot be empty');\r\n }\r\n }\r\n\r\n /**\r\n * Đăng ký cấu hình service\r\n */\r\n public registerService(config: ServiceConfig): this {\r\n this.validateServiceConfig(config);\r\n \r\n const serviceKey = this.createServiceKey(config.schemaName, config.tableName);\r\n \r\n // Normalize config\r\n const normalizedConfig: ServiceConfig = {\r\n schemaName: config.schemaName.trim(),\r\n tableName: config.tableName.trim(),\r\n primaryKeyFields: config.primaryKeyFields || ['id'],\r\n serviceClass: config.serviceClass || DefaultService,\r\n };\r\n \r\n this.serviceConfigs.set(serviceKey, normalizedConfig);\r\n \r\n return this;\r\n }\r\n\r\n /**\r\n * Đăng ký nhiều services\r\n */\r\n public registerServices(configs: ServiceConfig[]): this {\r\n configs.forEach(config => this.registerService(config));\r\n return this;\r\n }\r\n\r\n /**\r\n * Tạo service instance từ config\r\n */\r\n private async createServiceInstance(config: ServiceConfig): Promise<BaseService> {\r\n const ServiceClass = config.serviceClass || DefaultService;\r\n const service = new ServiceClass(config.schemaName, config.tableName);\r\n \r\n if (config.primaryKeyFields) {\r\n service.setPrimaryKeyFields(config.primaryKeyFields);\r\n }\r\n \r\n return service;\r\n }\r\n\r\n /**\r\n * Lấy service (tự động tạo nếu chưa tồn tại)\r\n */\r\n public async getService(schemaName: string, tableName: string): Promise<BaseService> {\r\n if (this.isShuttingDown) {\r\n throw new Error('ServiceManager is shutting down');\r\n }\r\n\r\n const serviceKey = this.createServiceKey(schemaName, tableName);\r\n \r\n // Update access time\r\n const metadata = this.serviceMetadata.get(serviceKey);\r\n if (metadata) {\r\n metadata.lastAccessed = new Date().toISOString();\r\n }\r\n \r\n // Return existing service\r\n if (this.services.has(serviceKey)) {\r\n return this.services.get(serviceKey)!;\r\n }\r\n \r\n // Get or create default config\r\n let config = this.serviceConfigs.get(serviceKey);\r\n if (!config) {\r\n config = {\r\n schemaName,\r\n tableName,\r\n primaryKeyFields: ['id'],\r\n serviceClass: DefaultService,\r\n };\r\n this.serviceConfigs.set(serviceKey, config);\r\n }\r\n \r\n try {\r\n const service = await this.createServiceInstance(config);\r\n this.services.set(serviceKey, service);\r\n \r\n // Track metadata\r\n this.serviceMetadata.set(serviceKey, {\r\n createdAt: new Date().toISOString(),\r\n lastAccessed: new Date().toISOString(),\r\n });\r\n \r\n this.emit('SERVICE_CREATED', {\r\n serviceKey,\r\n schemaName,\r\n tableName,\r\n });\r\n \r\n return service;\r\n } catch (error) {\r\n this.emit('SERVICE_ERROR', {\r\n serviceKey,\r\n schemaName,\r\n tableName,\r\n error: error as Error,\r\n });\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Lấy service đã tồn tại (không tự động tạo)\r\n */\r\n public getExistingService(schemaName: string, tableName: string): BaseService | null {\r\n const serviceKey = this.createServiceKey(schemaName, tableName);\r\n return this.services.get(serviceKey) || null;\r\n }\r\n\r\n /**\r\n * Khởi tạo service\r\n */\r\n public async initializeService(schemaName: string, tableName: string): Promise<BaseService> {\r\n const service = await this.getService(schemaName, tableName);\r\n await service.init();\r\n return service;\r\n }\r\n\r\n /**\r\n * Hủy service instance\r\n */\r\n public async destroyService(schemaName: string, tableName: string): Promise<boolean> {\r\n const serviceKey = this.createServiceKey(schemaName, tableName);\r\n const service = this.services.get(serviceKey);\r\n \r\n if (!service) {\r\n return false;\r\n }\r\n \r\n try {\r\n await service.close();\r\n service.destroy();\r\n \r\n this.services.delete(serviceKey);\r\n this.serviceMetadata.delete(serviceKey);\r\n \r\n this.emit('SERVICE_DESTROYED', {\r\n serviceKey,\r\n schemaName,\r\n tableName,\r\n });\r\n \r\n return true;\r\n } catch (error) {\r\n this.emit('SERVICE_ERROR', {\r\n serviceKey,\r\n schemaName,\r\n tableName,\r\n error: error as Error,\r\n });\r\n return false;\r\n }\r\n }\r\n\r\n /**\r\n * Lấy danh sách services theo schema\r\n */\r\n public getServicesBySchema(schemaName: string): BaseService[] {\r\n const services: BaseService[] = [];\r\n \r\n for (const [serviceKey, service] of this.services) {\r\n const [keySchema] = serviceKey.split(':');\r\n if (keySchema === schemaName) {\r\n services.push(service);\r\n }\r\n }\r\n \r\n return services;\r\n }\r\n\r\n /**\r\n * Lấy danh sách service keys theo schema\r\n */\r\n public getServiceKeysBySchema(schemaName: string): string[] {\r\n const keys: string[] = [];\r\n \r\n for (const serviceKey of this.services.keys()) {\r\n const [keySchema] = serviceKey.split(':');\r\n if (keySchema === schemaName) {\r\n keys.push(serviceKey);\r\n }\r\n }\r\n \r\n return keys;\r\n }\r\n\r\n /**\r\n * Hủy tất cả services trong một schema\r\n */\r\n public async destroyServicesBySchema(schemaName: string): Promise<void> {\r\n const serviceKeys = this.getServiceKeysBySchema(schemaName);\r\n \r\n const destroyPromises = serviceKeys.map(async serviceKey => {\r\n const [, tableName] = serviceKey.split(':');\r\n return this.destroyService(schemaName, tableName);\r\n });\r\n \r\n await Promise.all(destroyPromises);\r\n }\r\n\r\n /**\r\n * Lấy thông tin tất cả services\r\n */\r\n public getAllServiceInfo(): ServiceInfo[] {\r\n const infos: ServiceInfo[] = [];\r\n \r\n // Registered services\r\n for (const [serviceKey, config] of this.serviceConfigs) {\r\n const service = this.services.get(serviceKey);\r\n const metadata = this.serviceMetadata.get(serviceKey);\r\n \r\n infos.push({\r\n key: serviceKey,\r\n schemaName: config.schemaName,\r\n tableName: config.tableName,\r\n status: service ? service.getStatus() : {\r\n schemaName: config.schemaName,\r\n tableName: config.tableName,\r\n isOpened: false,\r\n isInitialized: false,\r\n hasDao: false,\r\n },\r\n isRegistered: true,\r\n createdAt: metadata?.createdAt || 'N/A',\r\n lastAccessed: metadata?.lastAccessed,\r\n });\r\n }\r\n \r\n // Unregistered services (created on-the-fly)\r\n for (const [serviceKey, service] of this.services) {\r\n if (!this.serviceConfigs.has(serviceKey)) {\r\n const [schemaName, tableName] = serviceKey.split(':');\r\n const metadata = this.serviceMetadata.get(serviceKey);\r\n \r\n infos.push({\r\n key: serviceKey,\r\n schemaName,\r\n tableName,\r\n status: service.getStatus(),\r\n isRegistered: false,\r\n createdAt: metadata?.createdAt || 'N/A',\r\n lastAccessed: metadata?.lastAccessed,\r\n });\r\n }\r\n }\r\n \r\n return infos;\r\n }\r\n\r\n /**\r\n * Kiểm tra sức khỏe tất cả services\r\n */\r\n public async healthCheck(): Promise<HealthReport> {\r\n const services = Array.from(this.services.entries());\r\n const healthPromises = services.map(async ([serviceKey, service]) => {\r\n try {\r\n const health = await service.healthCheck();\r\n return { ...health, serviceKey };\r\n } catch (error) {\r\n const [schemaName, tableName] = serviceKey.split(':');\r\n return {\r\n healthy: false,\r\n schemaName,\r\n error: (error as Error).message,\r\n timestamp: new Date().toISOString(),\r\n serviceKey,\r\n };\r\n }\r\n });\r\n \r\n const results = await Promise.all(healthPromises);\r\n const healthyCount = results.filter(r => r.healthy).length;\r\n \r\n const report: HealthReport = {\r\n totalServices: results.length,\r\n healthyServices: healthyCount,\r\n unhealthyServices: results.length - healthyCount,\r\n services: results,\r\n timestamp: new Date().toISOString(),\r\n overallHealth: healthyCount === results.length,\r\n };\r\n \r\n this.emit('HEALTH_CHECK_COMPLETED', {\r\n serviceKey: '*',\r\n schemaName: '*',\r\n tableName: '*',\r\n data: report,\r\n });\r\n \r\n return report;\r\n }\r\n\r\n /**\r\n * Thực hiện transaction trên nhiều services trong cùng schema\r\n * (Vì SQLite transaction chỉ hoạt động trong cùng database connection)\r\n */\r\n public async executeSchemaTransaction<T>(\r\n schemaName: string,\r\n callback: (services: BaseService[]) => Promise<T>\r\n ): Promise<T> {\r\n const services = this.getServicesBySchema(schemaName);\r\n \r\n if (services.length === 0) {\r\n throw new Error(`No services found for schema: ${schemaName}`);\r\n }\r\n \r\n // Ensure all services are initialized\r\n for (const service of services) {\r\n await service.init();\r\n }\r\n \r\n // Execute transaction on the first service (they share the same database)\r\n const primaryService = services[0];\r\n \r\n return await primaryService.executeTransaction(async () => {\r\n return await callback(services);\r\n });\r\n }\r\n\r\n /**\r\n * Periodic cleanup for unused services\r\n */\r\n private startPeriodicCleanup(): void {\r\n // Cleanup every 5 minutes\r\n this.cleanupInterval = setInterval(() => {\r\n this.cleanupUnusedServices();\r\n }, 5 * 60 * 1000);\r\n }\r\n\r\n /**\r\n * Cleanup services not accessed for a long time\r\n */\r\n private async cleanupUnusedServices(maxIdleTime: number = 30 * 60 * 1000): Promise<void> {\r\n if (this.isShuttingDown) {\r\n return;\r\n }\r\n\r\n const now = Date.now();\r\n const servicesToDestroy: string[] = [];\r\n \r\n for (const [serviceKey, metadata] of this.serviceMetadata) {\r\n if (!metadata.lastAccessed) {\r\n continue;\r\n }\r\n \r\n const lastAccessTime = new Date(metadata.lastAccessed).getTime();\r\n if (now - lastAccessTime > maxIdleTime) {\r\n servicesToDestroy.push(serviceKey);\r\n }\r\n }\r\n \r\n for (const serviceKey of servicesToDestroy) {\r\n const [schemaName, tableName] = serviceKey.split(':');\r\n await this.destroyService(schemaName, tableName);\r\n }\r\n }\r\n\r\n /**\r\n * Event system\r\n */\r\n public on(eventType: string, handler: ServiceManagerEventHandler): this {\r\n if (!this.eventHandlers.has(eventType)) {\r\n this.eventHandlers.set(eventType, []);\r\n }\r\n this.eventHandlers.get(eventType)!.push(handler);\r\n return this;\r\n }\r\n\r\n public off(eventType: string, handler: ServiceManagerEventHandler): this {\r\n const handlers = this.eventHandlers.get(eventType);\r\n if (handlers) {\r\n const index = handlers.indexOf(handler);\r\n if (index > -1) {\r\n handlers.splice(index, 1);\r\n }\r\n }\r\n return this;\r\n }\r\n\r\n private emit(\r\n type: ServiceManagerEvent['type'],\r\n data: Omit<ServiceManagerEvent, 'type' | 'timestamp'>\r\n ): void {\r\n const event: ServiceManagerEvent = {\r\n ...data,\r\n type,\r\n timestamp: new Date().toISOString(),\r\n };\r\n\r\n // Emit to specific event handlers\r\n const handlers = this.eventHandlers.get(type);\r\n if (handlers) {\r\n handlers.forEach(handler => {\r\n try {\r\n handler(event);\r\n } catch (error) {\r\n console.error(`ServiceManager: Error in ${type} event handler:`, error);\r\n }\r\n });\r\n }\r\n\r\n // Emit to global event handlers\r\n const globalHandlers = this.eventHandlers.get('*');\r\n if (globalHandlers) {\r\n globalHandlers.forEach(handler => {\r\n try {\r\n handler(event);\r\n } catch (error) {\r\n console.error('ServiceManager: Error in global event handler:', error);\r\n }\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Utility methods\r\n */\r\n public hasService(schemaName: string, tableName: string): boolean {\r\n const serviceKey = this.createServiceKey(schemaName, tableName);\r\n return this.services.has(serviceKey);\r\n }\r\n\r\n public isRegistered(schemaName: string, tableName: string): boolean {\r\n const serviceKey = this.createServiceKey(schemaName, tableName);\r\n return this.serviceConfigs.has(serviceKey);\r\n }\r\n\r\n public getServiceCount(): number {\r\n return this.services.size;\r\n }\r\n\r\n public getRegisteredCount(): number {\r\n return this.serviceConfigs.size;\r\n }\r\n\r\n public getSchemas(): string[] {\r\n const schemas = new Set<string>();\r\n \r\n for (const serviceKey of this.services.keys()) {\r\n const [schemaName] = serviceKey.split(':');\r\n schemas.add(schemaName);\r\n }\r\n \r\n return Array.from(schemas);\r\n }\r\n\r\n /**\r\n * Destroy all services and cleanup resources\r\n */\r\n public async destroy(): Promise<void> {\r\n this.isShuttingDown = true;\r\n \r\n // Clear cleanup interval\r\n if (this.cleanupInterval) {\r\n clearInterval(this.cleanupInterval);\r\n this.cleanupInterval = null;\r\n }\r\n \r\n // Destroy all services\r\n const destroyPromises = Array.from(this.services.entries()).map(\r\n async ([serviceKey, service]) => {\r\n try {\r\n await service.close();\r\n service.destroy();\r\n } catch (error) {\r\n console.error(`Error destroying service ${serviceKey}:`, error);\r\n }\r\n }\r\n );\r\n \r\n await Promise.all(destroyPromises);\r\n \r\n // Clear all data\r\n this.services.clear();\r\n this.serviceConfigs.clear();\r\n this.serviceMetadata.clear();\r\n this.eventHandlers.clear();\r\n \r\n this.isShuttingDown = false;\r\n }\r\n}\r\n\r\n// Export singleton instance\r\nexport const serviceManager = ServiceManager.getInstance();","// src/adapters/base-adapter.ts\r\nimport { SQLiteAdapter, SQLiteConnection } from '../types';\r\nexport abstract class BaseAdapter implements SQLiteAdapter {\r\n abstract connect(path: string): Promise<SQLiteConnection>;\r\n abstract isSupported(): boolean;\r\n\r\n protected sanitizeSQL(sql: string): string {\r\n return sql.trim();\r\n }\r\n\r\n protected bindParameters(sql: string, params?: any[]): string {\r\n if (!params || params.length === 0) {\r\n return sql;\r\n }\r\n\r\n let paramIndex = 0;\r\n return sql.replace(/\\?/g, () => {\r\n if (paramIndex < params.length) {\r\n const param = params[paramIndex++];\r\n if (typeof param === 'string') {\r\n return `'${param.replace(/'/g, \"''\")}'`;\r\n }\r\n if (param === null || param === undefined) {\r\n return 'NULL';\r\n }\r\n return String(param);\r\n }\r\n return '?';\r\n });\r\n }\r\n}","// src/index.ts - Main exports for UniversalSQLite Library\r\nimport { DatabaseManager } from \"./core/database-manager\";\r\nimport { UniversalDAO } from \"./core/universal-dao\";\r\nimport { BaseService } from \"./core/base-service\";\r\nimport { DatabaseFactory } from \"./core/database-factory\";\r\nimport { QueryBuilder } from \"./query/query-builder\";\r\nimport {\r\n SQLiteAdapter,\r\n SQLiteResult,\r\n SQLiteRow,\r\n DatabaseSchema,\r\n DbFactoryOptions,\r\n ImportOptions,\r\n ImportResult,\r\n ColumnMapping\r\n} from \"./types\";\r\n\r\n// ========================== CORE EXPORTS ==========================\r\nexport { UniversalDAO } from \"./core/universal-dao\";\r\nexport { DatabaseFactory } from \"./core/database-factory\";\r\nexport { DatabaseManager } from \"./core/database-manager\";\r\nexport { BaseService } from \"./core/base-service\";\r\nexport {\r\n ServiceManager,\r\n DefaultService,\r\n type ServiceConfig,\r\n type ServiceInfo,\r\n type HealthReport,\r\n type ServiceManagerEvent,\r\n type ServiceManagerEventHandler,\r\n} from \"./core/service-manager\";\r\n\r\n// ========================== QUERY & UTILITIES ==========================\r\nexport { QueryBuilder } from \"./query/query-builder\";\r\n\r\n// ========================== ADAPTERS ==========================\r\nexport { BaseAdapter } from \"./adapters/base-adapter\";\r\n\r\n// ========================== TYPE EXPORTS ==========================\r\nexport * from \"./types\";\r\n\r\n// ========================== UNIFIED INTERFACE ==========================\r\n\r\n/**\r\n * UniversalSQLite - The main unified interface providing a comprehensive\r\n * SQLite database management solution for all environments and platforms.\r\n *\r\n * Features:\r\n * - Cross-platform support (Browser, Node.js, Deno, Bun, React Native)\r\n * - Schema-based database management\r\n * - Role-based access control\r\n * - Advanced query building\r\n * - Data import/export capabilities\r\n * - Migration system\r\n * - Transaction management\r\n * - Connection pooling and lifecycle management\r\n */\r\nexport class UniversalSQLite {\r\n private static instance: UniversalSQLite | null = null;\r\n private currentSchema: string | null = null;\r\n private isInitialized: boolean = false;\r\n private initializationPromise: Promise<void> | null = null;\r\n private eventListeners: Map<string, Array<(...args: any[]) => void>> =\r\n new Map();\r\n\r\n constructor() {\r\n // Private constructor for singleton pattern\r\n if (UniversalSQLite.instance) {\r\n throw new Error(\r\n \"UniversalSQLite is a singleton. Use UniversalSQLite.getInstance() instead.\"\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Get singleton instance of UniversalSQLite\r\n */\r\n static getInstance(): UniversalSQLite {\r\n if (!UniversalSQLite.instance) {\r\n UniversalSQLite.instance = new UniversalSQLite();\r\n }\r\n return UniversalSQLite.instance;\r\n }\r\n\r\n /**\r\n * Reset singleton instance (useful for testing)\r\n */\r\n static resetInstance(): void {\r\n if (UniversalSQLite.instance) {\r\n UniversalSQLite.instance.closeAll().catch(() => {});\r\n }\r\n UniversalSQLite.instance = null;\r\n }\r\n\r\n // ========================== INITIALIZATION METHODS ==========================\r\n\r\n /**\r\n * Initialize UniversalSQLite with schema configurations\r\n * @param schemas - Database schema configurations\r\n * @param options - Additional initialization options\r\n */\r\n async initialize(\r\n schemas: Record<string, DatabaseSchema>,\r\n options: {\r\n registerAdapters?: SQLiteAdapter[];\r\n autoConnectCore?: boolean;\r\n defaultRoles?: string[];\r\n globalErrorHandler?: (error: Error, context: string) => void;\r\n } = {}\r\n ): Promise<void> {\r\n if (this.isInitialized) {\r\n return this.initializationPromise || Promise.resolve();\r\n }\r\n\r\n if (this.initializationPromise) {\r\n return this.initializationPromise;\r\n }\r\n\r\n this.initializationPromise = this._performInitialization(schemas, options);\r\n return this.initializationPromise;\r\n }\r\n\r\n private async _performInitialization(\r\n schemas: Record<string, DatabaseSchema>,\r\n options: {\r\n registerAdapters?: SQLiteAdapter[];\r\n autoConnectCore?: boolean;\r\n defaultRoles?: string[];\r\n globalErrorHandler?: (error: Error, context: string) => void;\r\n }\r\n ): Promise<void> {\r\n try {\r\n // Register adapters if provided\r\n if (options.registerAdapters) {\r\n options.registerAdapters.forEach((adapter) => {\r\n DatabaseFactory.registerAdapter(adapter);\r\n });\r\n }\r\n\r\n // Register global error handler\r\n if (options.globalErrorHandler) {\r\n this.on(\"error\", options.globalErrorHandler);\r\n }\r\n\r\n // Register all schemas with DatabaseManager\r\n DatabaseManager.registerSchemas(schemas);\r\n\r\n // Initialize core connection if core schema exists and autoConnectCore is true\r\n if (schemas.core && options.autoConnectCore !== false) {\r\n await DatabaseManager.initializeCoreConnection();\r\n }\r\n\r\n // Set default roles if provided\r\n if (options.defaultRoles && options.defaultRoles.length > 0) {\r\n await DatabaseManager.setCurrentUserRoles(options.defaultRoles);\r\n }\r\n\r\n this.isInitialized = true;\r\n this._emit(\"initialized\", { schemas: Object.keys(schemas) });\r\n } catch (error) {\r\n this.isInitialized = false;\r\n this.initializationPromise = null;\r\n this._emit(\"error\", error as Error, \"initialization\");\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Initialize from a single schema configuration\r\n */\r\n async initializeFromSchema(\r\n schema: DatabaseSchema,\r\n options: {\r\n registerAdapters?: SQLiteAdapter[];\r\n autoConnect?: boolean;\r\n globalErrorHandler?: (error: Error, context: string) => void;\r\n } = {}\r\n ): Promise<void> {\r\n const schemas = { [schema.database_name]: schema };\r\n return this.initialize(schemas, {\r\n ...options,\r\n autoConnectCore: options.autoConnect !== false,\r\n });\r\n }\r\n\r\n // ========================== CONNECTION MANAGEMENT ==========================\r\n\r\n /**\r\n * Connect to a specific database schema\r\n * @param schemaName - Name of the schema to connect to\r\n * @returns Promise resolving to UniversalDAO instance\r\n */\r\n async connect(schemaName: string): Promise<UniversalDAO> {\r\n this.ensureInitialized();\r\n this.currentSchema = schemaName;\r\n\r\n try {\r\n const dao = await DatabaseManager.getLazyLoading(schemaName);\r\n this._emit(\"connected\", { schemaName });\r\n return dao;\r\n } catch (error) {\r\n this._emit(\"error\", error as Error, \"connection\");\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Get DAO for a specific schema\r\n * @param schemaName - Optional schema name (uses current if not provided)\r\n */\r\n getDAO(schemaName?: string): UniversalDAO {\r\n this.ensureInitialized();\r\n const schema = schemaName || this.currentSchema;\r\n\r\n if (!schema) {\r\n throw new Error(\r\n \"No schema specified. Use connect() first or provide schemaName parameter.\"\r\n );\r\n }\r\n\r\n try {\r\n return DatabaseManager.get(schema);\r\n } catch (error) {\r\n this._emit(\"error\", error as Error, \"getDAO\");\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Get current connected DAO\r\n */\r\n getCurrentDAO(): UniversalDAO {\r\n if (!this.currentSchema) {\r\n throw new Error(\"No current connection. Call connect() first.\");\r\n }\r\n return this.getDAO(this.currentSchema);\r\n }\r\n\r\n /**\r\n * Ensure database connection exists and is active\r\n */\r\n async ensureDatabaseConnection(schemaName: string): Promise<UniversalDAO> {\r\n this.ensureInitialized();\r\n\r\n try {\r\n return await DatabaseManager.ensureDatabaseConnection(schemaName);\r\n } catch (error) {\r\n this._emit(\"error\", error as Error, \"ensureConnection\");\r\n throw error;\r\n }\r\n }\r\n\r\n // ========================== SERVICE CREATION ==========================\r\n\r\n /**\r\n * Create a service for a specific table\r\n * @param tableName - Name of the table\r\n * @param schemaName - Optional schema name (uses current if not provided)\r\n */\r\n createService<T = any>(\r\n tableName: string,\r\n schemaName?: string\r\n ): BaseService<T> {\r\n const schema = schemaName || this.currentSchema;\r\n if (!schema) {\r\n throw new Error(\r\n \"No schema specified. Use connect() first or provide schemaName parameter.\"\r\n );\r\n }\r\n const ServiceClass = class extends BaseService<T> {\r\n constructor() {\r\n if (!schema) {\r\n throw new Error(\r\n \"No schema specified. Use connect() first or provide schemaName parameter.\"\r\n );\r\n }\r\n super(schema, tableName);\r\n }\r\n };\r\n\r\n return new ServiceClass();\r\n }\r\n\r\n /**\r\n * Create multiple services at once\r\n */\r\n createServices<T = any>(\r\n tableNames: string[],\r\n schemaName?: string\r\n ): Record<string, BaseService<T>> {\r\n const services: Record<string, BaseService<T>> = {};\r\n\r\n tableNames.forEach((tableName) => {\r\n services[tableName] = this.createService<T>(tableName, schemaName);\r\n });\r\n\r\n return services;\r\n }\r\n\r\n // ========================== QUERY BUILDING ==========================\r\n\r\n /**\r\n * Create query builder for current connection\r\n */\r\n query(tableName?: string, schemaName?: string): QueryBuilder {\r\n const dao = this.getDAO(schemaName);\r\n\r\n if (tableName) {\r\n return QueryBuilder.table(tableName, dao);\r\n }\r\n\r\n return new QueryBuilder(dao);\r\n }\r\n\r\n /**\r\n * Create query builder from table\r\n */\r\n table(tableName: string, schemaName?: string): QueryBuilder {\r\n return this.query(tableName, schemaName);\r\n }\r\n\r\n /**\r\n * Execute raw SQL on current connection\r\n */\r\n async execute(\r\n sql: string,\r\n params?: any[],\r\n schemaName?: string\r\n ): Promise<SQLiteResult> {\r\n try {\r\n const dao = this.getDAO(schemaName);\r\n const result = await dao.execute(sql, params);\r\n this._emit(\"queryExecuted\", {\r\n sql,\r\n params,\r\n rowCount: result.rowsAffected,\r\n });\r\n return result;\r\n } catch (error) {\r\n this._emit(\"error\", error as Error, \"execute\");\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Get first row from query\r\n */\r\n async getRst(\r\n sql: string,\r\n params?: any[],\r\n schemaName?: string\r\n ): Promise<SQLiteRow> {\r\n const dao = this.getDAO(schemaName);\r\n return await dao.getRst(sql, params);\r\n }\r\n\r\n /**\r\n * Get all rows from query\r\n */\r\n async getRsts(\r\n sql: string,\r\n params?: any[],\r\n schemaName?: string\r\n ): Promise<SQLiteRow[]> {\r\n const dao = this.getDAO(schemaName);\r\n return await dao.getRsts(sql, params);\r\n }\r\n\r\n // ========================== SCHEMA MANAGEMENT ==========================\r\n\r\n /**\r\n * Initialize database from schema\r\n */\r\n async initializeSchema(\r\n schema: DatabaseSchema,\r\n forceRecreate: boolean = false\r\n ): Promise<void> {\r\n try {\r\n const dao = await DatabaseFactory.createOrOpen(\r\n { config: schema },\r\n forceRecreate\r\n );\r\n await dao.initializeFromSchema(schema);\r\n this._emit(\"schemaInitialized\", { schemaName: schema.database_name });\r\n } catch (error) {\r\n this._emit(\"error\", error as Error, \"schemaInitialization\");\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Get schema version for a database\r\n */\r\n async getSchemaVersion(schemaName?: string): Promise<string> {\r\n const dao = this.getDAO(schemaName);\r\n return await dao.getSchemaVersion();\r\n }\r\n\r\n /**\r\n * Get database information\r\n */\r\n async getDatabaseInfo(schemaName?: string): Promise<any> {\r\n const dao = this.getDAO(schemaName);\r\n return await dao.getDatabaseInfo();\r\n }\r\n\r\n /**\r\n * Get table information\r\n */\r\n async getTableInfo(tableName: string, schemaName?: string): Promise<any[]> {\r\n const dao = this.getDAO(schemaName);\r\n return await dao.getTableInfo(tableName);\r\n }\r\n\r\n // ========================== DATA IMPORT/EXPORT ==========================\r\n\r\n /**\r\n * Import data to a specific table\r\n */\r\n async importData(\r\n schemaName: string,\r\n tableName: string,\r\n data: Record<string, any>[],\r\n options?: Partial<ImportOptions>\r\n ): Promise<ImportResult> {\r\n try {\r\n const result = await DatabaseManager.importDataToTable(\r\n schemaName,\r\n tableName,\r\n data,\r\n options\r\n );\r\n this._emit(\"dataImported\", {\r\n schemaName,\r\n tableName,\r\n recordCount: result.successRows,\r\n });\r\n return result;\r\n } catch (error) {\r\n this._emit(\"error\", error as Error, \"dataImport\");\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Import data with column mapping\r\n */\r\n async importDataWithMapping(\r\n schemaName: string,\r\n tableName: string,\r\n data: Record<string, any>[],\r\n columnMappings: ColumnMapping[],\r\n options?: Partial<ImportOptions>\r\n ): Promise<ImportResult> {\r\n try {\r\n const result = await DatabaseManager.importDataWithMapping(\r\n schemaName,\r\n tableName,\r\n data,\r\n columnMappings,\r\n options\r\n );\r\n this._emit(\"dataImported\", {\r\n schemaName,\r\n tableName,\r\n recordCount: result.successRows,\r\n });\r\n return result;\r\n } catch (error) {\r\n this._emit(\"error\", error as Error, \"dataImportWithMapping\");\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Import from CSV\r\n */\r\n async importFromCSV(\r\n schemaName: string,\r\n tableName: string,\r\n csvData: string,\r\n options?: {\r\n delimiter?: string;\r\n hasHeader?: boolean;\r\n columnMappings?: ColumnMapping[];\r\n } & Partial<ImportOptions>\r\n ): Promise<ImportResult> {\r\n try {\r\n const result = await DatabaseManager.importFromCSV(\r\n schemaName,\r\n tableName,\r\n csvData,\r\n options\r\n );\r\n this._emit(\"csvImported\", {\r\n schemaName,\r\n tableName,\r\n recordCount: result.successRows,\r\n });\r\n return result;\r\n } catch (error) {\r\n this._emit(\"error\", error as Error, \"csvImport\");\r\n throw error;\r\n }\r\n }\r\n\r\n // ========================== ROLE & ACCESS MANAGEMENT ==========================\r\n\r\n /**\r\n * Set user roles and initialize role-based connections\r\n */\r\n async setUserRoles(roles: string[], primaryRole?: string): Promise<void> {\r\n this.ensureInitialized();\r\n\r\n try {\r\n await DatabaseManager.setCurrentUserRoles(roles, primaryRole);\r\n this._emit(\"userRolesSet\", { roles, primaryRole });\r\n } catch (error) {\r\n this._emit(\"error\", error as Error, \"setUserRoles\");\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Get current user roles\r\n */\r\n getCurrentUserRoles(): string[] {\r\n return DatabaseManager.getCurrentUserRoles();\r\n }\r\n\r\n /**\r\n * Get current primary role\r\n */\r\n getCurrentRole(): string | null {\r\n return DatabaseManager.getCurrentRole();\r\n }\r\n\r\n /**\r\n * Check if user has access to database\r\n */\r\n hasAccessToDatabase(dbKey: string): boolean {\r\n return DatabaseManager.hasAccessToDatabase(dbKey);\r\n }\r\n\r\n // ========================== TRANSACTION MANAGEMENT ==========================\r\n\r\n /**\r\n * Execute cross-schema transaction\r\n */\r\n async executeTransaction(\r\n schemas: string[],\r\n callback: (daos: Record<string, UniversalDAO>) => Promise<void>\r\n ): Promise<void> {\r\n try {\r\n await DatabaseManager.executeCrossSchemaTransaction(schemas, callback);\r\n this._emit(\"transactionCompleted\", { schemas });\r\n } catch (error) {\r\n this._emit(\"error\", error as Error, \"transaction\");\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Execute transaction on current connection\r\n */\r\n async executeTransactionOnCurrent<T>(\r\n callback: (dao: UniversalDAO) => Promise<T>\r\n ): Promise<T> {\r\n const dao = this.getCurrentDAO();\r\n\r\n try {\r\n await dao.beginTransaction();\r\n const result = await callback(dao);\r\n await dao.commitTransaction();\r\n return result;\r\n } catch (error) {\r\n await dao.rollbackTransaction();\r\n throw error;\r\n }\r\n }\r\n\r\n // ========================== UTILITY & STATUS METHODS ==========================\r\n\r\n /**\r\n * Get environment information\r\n */\r\n getEnvironment(): string {\r\n return DatabaseFactory.getEnvironmentInfo();\r\n }\r\n\r\n /**\r\n * Get connection status\r\n */\r\n getConnectionStatus(): {\r\n isInitialized: boolean;\r\n currentSchema: string | null;\r\n activeConnections: string[];\r\n connectionCount: number;\r\n userRoles: string[];\r\n primaryRole: string | null;\r\n } {\r\n return {\r\n isInitialized: this.isInitialized,\r\n currentSchema: this.currentSchema,\r\n activeConnections: DatabaseManager.listConnections(),\r\n connectionCount: DatabaseManager.getConnectionCount(),\r\n userRoles: this.getCurrentUserRoles(),\r\n primaryRole: this.getCurrentRole(),\r\n };\r\n }\r\n\r\n /**\r\n * Get list of available schemas\r\n */\r\n getAvailableSchemas(): string[] {\r\n return DatabaseManager.getAvailableSchemas();\r\n }\r\n\r\n /**\r\n * Health check for all connections\r\n */\r\n async healthCheck(): Promise<\r\n Record<string, { healthy: boolean; error?: string }>\r\n > {\r\n const connections = DatabaseManager.getConnections();\r\n const healthStatus: Record<string, { healthy: boolean; error?: string }> =\r\n {};\r\n\r\n for (const [schemaName, dao] of Object.entries(connections)) {\r\n try {\r\n await dao.execute(\"SELECT 1\");\r\n healthStatus[schemaName] = { healthy: true };\r\n } catch (error) {\r\n healthStatus[schemaName] = {\r\n healthy: false,\r\n error: (error as Error).message,\r\n };\r\n }\r\n }\r\n\r\n return healthStatus;\r\n }\r\n\r\n // ========================== EVENT SYSTEM ==========================\r\n\r\n /**\r\n * Add event listener\r\n */\r\n on(event: string, handler: (...args: any[]) => void): this {\r\n if (!this.eventListeners.has(event)) {\r\n this.eventListeners.set(event, []);\r\n }\r\n this.eventListeners.get(event)!.push(handler);\r\n return this;\r\n }\r\n\r\n /**\r\n * Remove event listener\r\n */\r\n off(event: string, handler: (...args: any[]) => void): this {\r\n const handlers = this.eventListeners.get(event);\r\n if (handlers) {\r\n const index = handlers.indexOf(handler);\r\n if (index > -1) {\r\n handlers.splice(index, 1);\r\n }\r\n }\r\n return this;\r\n }\r\n\r\n /**\r\n * Emit event\r\n */\r\n private _emit(event: string, ...args: any[]): void {\r\n const handlers = this.eventListeners.get(event);\r\n if (handlers) {\r\n handlers.forEach((handler) => {\r\n try {\r\n handler(...args);\r\n } catch (error) {\r\n // Handle event handler errors gracefully\r\n console.error(\"Error in event handler:\", error);\r\n }\r\n });\r\n }\r\n }\r\n\r\n // ========================== CONNECTION LIFECYCLE ==========================\r\n\r\n /**\r\n * Close specific connection\r\n */\r\n async closeConnection(schemaName: string): Promise<void> {\r\n try {\r\n await DatabaseManager.closeConnection(schemaName);\r\n\r\n if (this.currentSchema === schemaName) {\r\n this.currentSchema = null;\r\n }\r\n\r\n this._emit(\"connectionClosed\", { schemaName });\r\n } catch (error) {\r\n this._emit(\"error\", error as Error, \"closeConnection\");\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Close all connections\r\n */\r\n async closeAll(): Promise<void> {\r\n try {\r\n await DatabaseManager.closeAll();\r\n this.currentSchema = null;\r\n this.isInitialized = false;\r\n this.initializationPromise = null;\r\n this.eventListeners.clear();\r\n this._emit(\"allConnectionsClosed\");\r\n } catch (error) {\r\n this._emit(\"error\", error as Error, \"closeAll\");\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Logout user and close role-specific connections\r\n */\r\n async logout(): Promise<void> {\r\n try {\r\n await DatabaseManager.logout();\r\n this.currentSchema = null;\r\n this._emit(\"userLoggedOut\");\r\n } catch (error) {\r\n this._emit(\"error\", error as Error, \"logout\");\r\n throw error;\r\n }\r\n }\r\n\r\n // ========================== STATIC UTILITY METHODS ==========================\r\n\r\n /**\r\n * Register adapter with DatabaseFactory\r\n */\r\n static registerAdapter(adapter: SQLiteAdapter): void {\r\n DatabaseFactory.registerAdapter(adapter);\r\n }\r\n\r\n /**\r\n * Register role configuration\r\n */\r\n static registerRole(roleConfig: {\r\n roleName: string;\r\n requiredDatabases: string[];\r\n optionalDatabases?: string[];\r\n priority?: number;\r\n }): void {\r\n DatabaseManager.registerRole(roleConfig);\r\n }\r\n\r\n /**\r\n * Register multiple roles\r\n */\r\n static registerRoles(\r\n roleConfigs: Array<{\r\n roleName: string;\r\n requiredDatabases: string[];\r\n optionalDatabases?: string[];\r\n priority?: number;\r\n }>\r\n ): void {\r\n DatabaseManager.registerRoles(roleConfigs);\r\n }\r\n\r\n // ========================== PRIVATE HELPERS ==========================\r\n\r\n private ensureInitialized(): void {\r\n if (!this.isInitialized) {\r\n throw new Error(\r\n \"UniversalSQLite not initialized. Call initialize() first.\"\r\n );\r\n }\r\n }\r\n}\r\n\r\n// ========================== FACTORY FUNCTIONS ==========================\r\n\r\n/**\r\n * Create UniversalDAO instance\r\n */\r\nexport const createUniversalDAO = (\r\n dbPath: string,\r\n options?: {\r\n adapter?: SQLiteAdapter;\r\n createIfNotExists?: boolean;\r\n forceRecreate?: boolean;\r\n }\r\n): UniversalDAO => {\r\n return DatabaseFactory.createDAO(dbPath, options);\r\n};\r\n\r\n/**\r\n * Create database from schema configuration\r\n */\r\nexport const createDatabaseFromSchema = async (\r\n schema: DatabaseSchema,\r\n options?: Omit<DbFactoryOptions, \"config\">\r\n): Promise<UniversalDAO> => {\r\n return await DatabaseFactory.createFromConfig(schema, options);\r\n};\r\n\r\n/**\r\n * Open existing database\r\n */\r\nexport const openExistingDatabase = async (\r\n dbName: string,\r\n options?: Omit<DbFactoryOptions, \"config\" | \"configAsset\">\r\n): Promise<UniversalDAO> => {\r\n return await DatabaseFactory.openExisting(dbName, options);\r\n};\r\n\r\n/**\r\n * Create query builder\r\n */\r\nexport const createQueryBuilder = (dao?: UniversalDAO): QueryBuilder => {\r\n return new QueryBuilder(dao);\r\n};\r\n\r\n/**\r\n * Create base service\r\n */\r\nexport const createBaseService = <T = any>(\r\n schemaName: string,\r\n tableName?: string\r\n): BaseService<T> => {\r\n return new (class extends BaseService<T> {\r\n constructor() {\r\n super(schemaName, tableName);\r\n }\r\n })();\r\n};\r\n\r\n// ========================== CONVENIENCE EXPORTS ==========================\r\n\r\n/**\r\n * Quick setup function for common use cases\r\n */\r\nexport const setupUniversalSQLite = async (config: {\r\n schemas: Record<string, DatabaseSchema>;\r\n adapters?: SQLiteAdapter[];\r\n defaultRoles?: string[];\r\n autoConnect?: string; // schema name to auto-connect to\r\n}): Promise<UniversalSQLite> => {\r\n const sqlite = UniversalSQLite.getInstance();\r\n\r\n await sqlite.initialize(config.schemas, {\r\n registerAdapters: config.adapters,\r\n defaultRoles: config.defaultRoles,\r\n });\r\n\r\n if (config.autoConnect) {\r\n await sqlite.connect(config.autoConnect);\r\n }\r\n\r\n return sqlite;\r\n};\r\n\r\n/**\r\n * Quick database creation from single schema\r\n */\r\nexport const createSingleDatabase = async (\r\n schema: DatabaseSchema,\r\n options?: {\r\n adapter?: SQLiteAdapter;\r\n autoConnect?: boolean;\r\n }\r\n): Promise<{ sqlite: UniversalSQLite; dao: UniversalDAO }> => {\r\n const sqlite = UniversalSQLite.getInstance();\r\n\r\n await sqlite.initializeFromSchema(schema, {\r\n registerAdapters: options?.adapter ? [options.adapter] : undefined,\r\n autoConnect: options?.autoConnect,\r\n });\r\n\r\n const dao =\r\n options?.autoConnect !== false\r\n ? await sqlite.connect(schema.database_name)\r\n : sqlite.getDAO(schema.database_name);\r\n\r\n return { sqlite, dao };\r\n};\r\n\r\n// ========================== DEFAULT EXPORT ==========================\r\n\r\n/**\r\n * Default export is the singleton instance\r\n */\r\nconst defaultInstance = UniversalSQLite.getInstance();\r\nexport default defaultInstance;\r\n"],"names":["UniversalDAO","adapter","dbPath","options","_a","_b","config","genericType","col","processedCol","constraints","defaultIndex","defaultValue","schema","hasExistingSchema","error","tableName","tableConfig","tableDefinition","tables","table","columnDefs","foreignKeyDefs","fk","fkSql","allDefs","sql","indexes","index","columns","version","insertTable","validCols","columnNames","placeholders","params","updateTable","setCols","w","setClause","whereClause","deleteTable","selectTable","suffix","orderBy","o","wheres","clause","conditions","where","operator","json","idFields","queryTable","key","value","startTime","result","tableInfo","columnMap","batchSize","processedCount","skipAutoIncrementPK","i","batch","j","rowIndex","rowData","processedData","errorInfo","data","columnMappings","transformedData","row","newRow","mapping","csvData","delimiter","hasHeader","lines","line","headers","dataStartIndex","h","firstRowCols","_","values","v","header","processedRow","columnName","columnInfo","isRequired","isAutoIncrementPK","lowerColumnName","columnType","type","num","lower","date","conflictColumns","updateColumns","whereColumns","updateValues","whereValues","allValues","t","DatabaseFactory","dao","dbInfo","dbName","dbFileName","isForceInit","isForceDelete","schemaError","configAsset","DatabaseManager","maxConnections","currentConnectionCount","manager","schemas","internalKeys","externalKeys","roleConfig","roleConfigs","roleName","allDatabases","db","coreSchema","userRoles","primaryRole","previousRoles","requiredDatabases","failedInitializations","initPromises","dbKey","err","errorSummary","f","previousDatabases","currentDatabases","databasesToClose","schemaName","callback","listeners","closePromises","activeDbArray","databaseKeys","failedOpens","invalidKeys","newConnectionsCount","currentConnectionsCount","availableSchemas","daos","acc","databaseKey","importConfigs","configKey","importResult","connectionsToClose","BaseService","newDao","method","fields","createdRecord","primaryKeyValue","findError","id","updateData","success","record","allWheres","name","results","whereConditions","items","dataArray","rollbackError","obj","event","handler","handlers","errorType","handlerError","count","QueryBuilder","builder","raw","fieldList","condition","fieldOrConditions","operatorOrValue","field","val","actualValue","min","max","subquery","actualOperator","direction","page","perPage","query","alias","cteList","cteSql","cteParams","join","conditionParams","unionQuery","unionSql","unionParams","subSql","subParams","column","valueGroups","whereParams","sets","updateClause","cloned","rawSql","param","DefaultService","ServiceManager","serviceKey","normalizedConfig","configs","ServiceClass","service","metadata","services","keySchema","keys","destroyPromises","infos","healthPromises","health","healthyCount","r","report","maxIdleTime","now","servicesToDestroy","lastAccessTime","eventType","globalHandlers","BaseAdapter","paramIndex","UniversalSQLite","tableNames","forceRecreate","roles","connections","healthStatus","args","createUniversalDAO","createDatabaseFromSchema","openExistingDatabase","createQueryBuilder","createBaseService","setupUniversalSQLite","sqlite","createSingleDatabase","defaultInstance"],"mappings":"gQAkBaA,CAAY,CAQvB,YACUC,EACAC,EACAC,EAGP,SALO,KAAA,QAAAF,EACA,KAAA,OAAAC,EACA,KAAA,QAAAC,EAVF,KAAA,WAAsC,KACtC,KAAA,YAAuB,GACvB,KAAA,cAAyB,GACzB,KAAA,kBAA8D,KAC9D,KAAA,kBAA6B,GAC7B,KAAA,cAAyB,GAU/B,KAAK,mBAAoBC,EAAAD,GAAO,KAAA,OAAPA,EAAS,qBAAiB,MAAAC,IAAA,OAAAA,EAAI,GACvD,KAAK,eAAgBC,EAAAF,GAAO,KAAA,OAAPA,EAAS,iBAAa,MAAAE,IAAA,OAAAA,EAAI,EACjD,CAEA,MAAM,SAAO,CACP,KAAK,cAIT,KAAK,WAAa,MAAM,KAAK,QAAQ,QAAQ,KAAK,MAAM,EACxD,KAAK,YAAc,GACrB,CAEA,MAAM,YAAU,CACV,KAAK,YAAc,KAAK,cAC1B,MAAM,KAAK,WAAW,MAAA,EACtB,KAAK,WAAa,KAClB,KAAK,YAAc,GAEvB,CAEA,MAAM,OAAK,CACT,MAAM,KAAK,WAAA,CACb,CAGA,qBAAqBC,EAAyC,CAC5D,KAAK,kBAAoBA,CAC3B,CAEQ,oBAAoBC,EAAmB,CAC7C,MAAI,CAAC,KAAK,mBAAqB,CAAC,KAAK,kBAAkB,OAC9C,KAAK,qBAAqBA,CAAW,EAGxB,KAAK,kBAAkB,OACxBA,EAAY,aAAa,GAAK,MACrD,CAEQ,qBAAqBA,EAAmB,CA0B9C,MAzB+C,CAC7C,OAAQ,OACR,QAAS,OACT,KAAM,OACN,MAAO,OACP,IAAK,OACL,KAAM,OACN,QAAS,UACT,OAAQ,UACR,SAAU,UACV,QAAS,UACT,QAAS,OACT,QAAS,OACT,MAAO,OACP,OAAQ,OACR,QAAS,UACT,UAAW,OACX,SAAU,OACV,KAAM,OACN,KAAM,OACN,KAAM,OACN,MAAO,OACP,KAAM,OACN,OAAQ,QAEYA,EAAY,aAAa,GAAK,MACtD,CAEQ,wBAAwBC,EAAqB,CACnD,MAAMC,EAAY,OAAA,OAAA,CAAA,EAA0BD,CAAG,EAC/CC,EAAa,KAAO,KAAK,oBAAoBD,EAAI,IAAI,EAErD,MAAML,EAAoB,CAAA,EAC1B,GAAIK,EAAI,YAAa,CACnB,MAAME,EAAcF,EAAI,YAAY,YAAA,EAAc,MAAM,GAAG,EACvDE,EAAY,SAAS,SAAS,IAChCP,EAAQ,KAAK,aAAa,EAC1BM,EAAa,YAAc,KAG3BC,EAAY,SAAS,gBAAgB,GACrCA,EAAY,SAAS,eAAe,KAEhCD,EAAa,aAAaN,EAAQ,KAAK,eAAe,EAC1DM,EAAa,eAAiB,IAE5BC,EAAY,SAAS,KAAK,GAAKA,EAAY,SAAS,MAAM,IAC5DP,EAAQ,KAAK,UAAU,EACvBM,EAAa,SAAW,IAEtBC,EAAY,SAAS,QAAQ,IAC1BD,EAAa,aAAaN,EAAQ,KAAK,QAAQ,EACpDM,EAAa,OAAS,IAGxB,MAAME,EAAeD,EAAY,QAAQ,SAAS,EAClD,GAAIC,IAAiB,IAAMD,EAAY,OAASC,EAAe,EAAG,CAChE,MAAMC,EAAeF,EAAYC,EAAe,CAAC,EACjDR,EAAQ,KAAK,WAAWS,CAAY,EAAE,EACtCH,EAAa,QAAUG,CACzB,CACF,CAEA,OAAAH,EAAa,WAAaN,EAAQ,KAAK,GAAG,EAAE,OACrCM,CACT,CAGA,MAAM,qBAAqBI,EAAsB,OAC/C,KAAK,kBAGL,IAAIC,EAAoB,GACxB,GAAI,CAIFA,GAHe,MAAM,KAAK,QACxB,mEAAmE,GAE1C,KAAK,OAAS,CAC3C,OAASC,EAAO,CACdD,EAAoB,EACtB,CAGA,GAAIA,GAAqB,CAAC,KAAK,mBAAqB,CAAC,KAAK,cAAe,CACnED,EAAO,cACT,KAAK,qBAAqBA,EAAO,YAAY,EAE/C,MACF,CAEIC,GAAqB,KAAK,eAC5B,MAAM,KAAK,gBAGTD,EAAO,cACT,KAAK,qBAAqBA,EAAO,YAAY,EAG/C,GAAI,CACF,MAAM,KAAK,QAAQ,0BAA0B,CAC/C,OAAER,EAAM,CAAC,CAET,MAAM,KAAK,iBAAA,EAEX,GAAI,CACF,SAAW,CAACW,EAAWC,CAAW,IAAK,OAAO,QAAQJ,EAAO,OAAO,EAAG,CACrE,MAAMK,EAAmC,CACvC,KAAMF,EACN,KAAMC,EAAY,KAAK,IAAKT,GAC1B,KAAK,wBAAwBA,CAAG,CAAC,EAEnC,YAAaS,EAAY,YACzB,QAASA,EAAY,QACrB,aAAcA,EAAY,cAE5B,MAAM,KAAK,2BAA2BC,CAAe,CACvD,CAEA,SAAW,CAACF,EAAWC,CAAW,IAAK,OAAO,QAAQJ,EAAO,OAAO,OAC9DI,EAAY,WAAO,MAAAb,IAAA,SAAAA,EAAE,QACvB,MAAM,KAAK,sBAAsBY,EAAWC,EAAY,OAAO,EAInE,MAAM,KAAK,iBAAiBJ,EAAO,OAAO,EAC1C,MAAM,KAAK,kBAAA,CACb,OAASE,EAAO,CACd,YAAM,KAAK,sBACLA,CACR,CACF,CAEQ,MAAM,eAAa,CACzB,MAAMI,EAAS,MAAM,KAAK,QACxB,gFAAgF,EAGlF,MAAM,KAAK,iBAAA,EAEX,GAAI,CACF,UAAWC,KAASD,EAAO,KACzB,MAAM,KAAK,QAAQ,wBAAwBC,EAAM,IAAI,EAAE,EAEzD,MAAM,KAAK,kBAAA,CACb,OAASL,EAAO,CACd,YAAM,KAAK,sBACLA,CACR,CACF,CAEQ,MAAM,2BACZK,EAAsB,CAEtB,MAAMC,EAAaD,EAAM,KAAK,IAAKZ,GACjC,GAAGA,EAAI,IAAI,IAAIA,EAAI,IAAI,IAAIA,EAAI,YAAc,EAAE,GAAG,KAAA,CAAM,EAGpDc,EAA2B,CAAA,EACjC,GAAIF,EAAM,aACR,UAAWG,KAAMH,EAAM,aAAc,CACnC,IAAII,EAAQ,gBAAgBD,EAAG,MAAM,gBAAgBA,EAAG,WAAW,KAAK,IAAIA,EAAG,WAAW,MAAM,IAC5FA,EAAG,YAAWC,GAAS,cAAcD,EAAG,SAAS,IACjDA,EAAG,YAAWC,GAAS,cAAcD,EAAG,SAAS,IACrDD,EAAe,KAAKE,CAAK,CAC3B,CAGF,MAAMC,EAAU,CAAC,GAAGJ,EAAY,GAAGC,CAAc,EAC3CI,EAAM,8BAA8BN,EAAM,IAAI,KAAKK,EAAQ,KAC/D,IAAI,CACL,IACD,MAAM,KAAK,QAAQC,CAAG,CACxB,CAEQ,MAAM,sBACZV,EACAW,EAA0B,CAE1B,UAAWC,KAASD,EAAS,CAC3B,MAAME,EAAUD,EAAM,QAAQ,KAAK,IAAI,EAEjCF,EAAM,UADKE,EAAM,OACU,SAAW,EAAE,wBAC5CA,EAAM,IACR,OAAOZ,CAAS,KAAKa,CAAO,IAC5B,MAAM,KAAK,QAAQH,CAAG,CACxB,CACF,CAGA,MAAM,kBAAgB,CACpB,GAAI,KAAK,cACP,MAAM,IAAI,MAAM,iCAAiC,EAEnD,MAAM,KAAK,QAAQ,mBAAmB,EACtC,KAAK,cAAgB,EACvB,CAEA,MAAM,mBAAiB,CACrB,GAAI,CAAC,KAAK,cACR,MAAM,IAAI,MAAM,4BAA4B,EAE9C,MAAM,KAAK,QAAQ,QAAQ,EAC3B,KAAK,cAAgB,EACvB,CAEA,MAAM,qBAAmB,CACvB,GAAI,CAAC,KAAK,cACR,MAAM,IAAI,MAAM,4BAA4B,EAE9C,MAAM,KAAK,QAAQ,UAAU,EAC7B,KAAK,cAAgB,EACvB,CAGA,MAAM,kBAAgB,CACpB,GAAI,CAIF,OAHe,MAAM,KAAK,OACxB,mEAAmE,GAEvD,SAAW,GAC3B,OAAEtB,EAAM,CACN,MAAO,GACT,CACF,CAEA,MAAM,iBAAiB0B,EAAe,CACpC,MAAM,KAAK,QAAQ;AAAA;AAAA;AAAA,MAGjB,EACF,MAAM,KAAK,QAAQ,gDAAiD,CAClEA,CACD,CAAA,CACH,CAGA,MAAM,OAAOC,EAAuB,CAClC,MAAMC,EAAYD,EAAY,KAAK,OAChCvB,GAAQA,EAAI,QAAU,QAAaA,EAAI,QAAU,IAAI,EAExD,GAAIwB,EAAU,SAAW,EACvB,MAAM,IAAI,MAAM,4BAA4B,EAG9C,MAAMC,EAAcD,EAAU,IAAKxB,GAAQA,EAAI,IAAI,EAAE,KAAK,IAAI,EACxD0B,EAAeF,EAAU,IAAI,IAAM,GAAG,EAAE,KAAK,IAAI,EACjDG,EAASH,EAAU,IAAKxB,GAC5B,OAAOA,EAAI,OAAU,SAAW,KAAK,UAAUA,EAAI,KAAK,EAAIA,EAAI,KAAK,EAGjEkB,EAAM,eAAeK,EAAY,IAAI,KAAKE,CAAW,aAAaC,CAAY,IACpF,OAAO,MAAM,KAAK,QAAQR,EAAKS,CAAM,CACvC,CAEA,MAAM,OAAOC,EAAuB,CAClC,MAAMC,EAAUD,EAAY,KAAK,OAC9B5B,GAAO,OACN,OAAAA,EAAI,QAAU,QACd,OAAC4B,EAAY,UAAM,MAAAhC,IAAA,SAAAA,EAAE,KAAMkC,GAAMA,EAAE,OAAS9B,EAAI,IAAI,EAAC,CAAA,EAGzD,GAAI6B,EAAQ,SAAW,EACrB,MAAM,IAAI,MAAM,sBAAsB,EAGxC,MAAME,EAAYF,EAAQ,IAAK7B,GAAQ,GAAGA,EAAI,IAAI,MAAM,EAAE,KAAK,IAAI,EAC7D2B,EAASE,EAAQ,IAAK7B,GAC1B,OAAOA,EAAI,OAAU,SAAW,KAAK,UAAUA,EAAI,KAAK,EAAIA,EAAI,KAAK,EAGvE,IAAIkB,EAAM,UAAUU,EAAY,IAAI,QAAQG,CAAS,GACrD,MAAMC,EAAc,KAAK,iBAAiBJ,EAAY,MAAM,EAE5D,GAAI,CAACI,EAAY,IACf,MAAM,IAAI,MAAM,+CAA+C,EAGjE,OAAAd,GAAOc,EAAY,IACnBL,EAAO,KAAK,GAAGK,EAAY,MAAM,EAE1B,MAAM,KAAK,QAAQd,EAAKS,CAAM,CACvC,CAEA,MAAM,OAAOM,EAAuB,CAClC,IAAIf,EAAM,eAAee,EAAY,IAAI,GACzC,MAAMD,EAAc,KAAK,iBAAiBC,EAAY,MAAM,EAE5D,GAAI,CAACD,EAAY,IACf,MAAM,IAAI,MAAM,+CAA+C,EAGjE,OAAAd,GAAOc,EAAY,IACZ,MAAM,KAAK,QAAQd,EAAKc,EAAY,MAAM,CACnD,CAEA,MAAM,OAAOE,EAAuB,CAClC,KAAM,CAAE,IAAAhB,EAAK,OAAAS,GAAW,KAAK,iBAAiBO,EAAa,UAAU,EAErE,OADe,MAAM,KAAK,QAAQhB,EAAKS,CAAM,GAC/B,KAAK,CAAC,GAAK,CAAA,CAC3B,CAEA,MAAM,UAAUO,EAAuB,CACrC,KAAM,CAAE,IAAAhB,EAAK,OAAAS,CAAM,EAAK,KAAK,iBAAiBO,CAAW,EAEzD,OADe,MAAM,KAAK,QAAQhB,EAAKS,CAAM,GAC/B,IAChB,CAGQ,iBACNO,EACAC,EAAiB,GAAE,OAOnB,IAAIjB,EAAM,UAJRgB,EAAY,KAAK,OAAS,EACtBA,EAAY,KAAK,IAAKlC,GAAQA,EAAI,IAAI,EAAE,KAAK,IAAI,EACjD,GAEqB,SAASkC,EAAY,IAAI,GACpD,MAAMF,EAAc,KAAK,iBAAiBE,EAAY,MAAM,EAG5D,GAFAhB,GAAOc,EAAY,SAEfE,EAAY,YAAQ,MAAAtC,IAAA,SAAAA,EAAE,OAAQ,CAChC,MAAMwC,EAAUF,EAAY,SACzB,IAAKG,GAAM,GAAGA,EAAE,IAAI,IAAIA,EAAE,WAAa,KAAK,EAAE,EAC9C,KAAK,IAAI,EACZnB,GAAO,aAAakB,CAAO,EAC7B,CAEA,OAAIF,EAAY,cACVA,EAAY,YAAY,QAC1BhB,GAAO,UAAUgB,EAAY,YAAY,KAAK,IAC5CA,EAAY,YAAY,SAC1BhB,GAAO,WAAWgB,EAAY,YAAY,MAAM,KAGpDhB,GAAOiB,EACA,CAAE,IAAAjB,EAAK,OAAQc,EAAY,MAAM,CAC1C,CAEQ,iBACNM,EACAC,EAAiB,QAAO,CAExB,GAAI,CAACD,GAAUA,EAAO,SAAW,EAC/B,MAAO,CAAE,IAAK,GAAI,OAAQ,CAAA,CAAE,EAG9B,MAAME,EAAuB,CAAA,EACvBb,EAAgB,CAAA,EAEtB,UAAWc,KAASH,EAAQ,CAC1B,MAAMI,EAAWD,EAAM,UAAY,IACnCD,EAAW,KAAK,GAAGC,EAAM,IAAI,IAAIC,CAAQ,IAAI,EAC7Cf,EAAO,KAAKc,EAAM,KAAK,CACzB,CAEA,MAAO,CAAE,IAAK,IAAIF,CAAM,IAAIC,EAAW,KAAK,OAAO,CAAC,GAAI,OAAAb,EAC1D,CAEA,wBACEnB,EACAmC,EACAC,EAAqB,CAAC,IAAI,EAAC,OAE3B,MAAMC,EAAyB,CAAE,KAAMrC,EAAW,KAAM,GAAI,OAAQ,CAAA,GAEpE,SAAW,CAACsC,EAAKC,CAAK,IAAK,OAAO,QAAQJ,CAAI,EAC5CE,EAAW,KAAK,KAAK,CAAE,KAAMC,EAAK,MAAAC,CAAK,CAAE,EACrCH,EAAS,SAASE,CAAG,GAAKC,IAAU,UACtCnD,EAAAiD,EAAW,UAAM,MAAAjD,IAAA,QAAAA,EAAE,KAAK,CAAE,KAAMkD,EAAK,MAAAC,CAAK,CAAE,GAIhD,OAAOF,CACT,CAGA,MAAM,WAAWlD,EAAsB,CACrC,MAAMqD,EAAY,KAAK,IAAA,EACjBC,EAAuB,CAC3B,UAAWtD,EAAQ,KAAK,OACxB,YAAa,EACb,UAAW,EACX,OAAQ,GACR,cAAe,GAGjB,GAAI,CAAC,KAAK,YACR,MAAM,IAAI,MAAM,2BAA2B,EAG7C,GAAI,CAACA,EAAQ,MAAQA,EAAQ,KAAK,SAAW,EAC3C,OAAAsD,EAAO,cAAgB,KAAK,IAAA,EAAQD,EAC7BC,EAGT,MAAMC,EAAY,MAAM,KAAK,aAAavD,EAAQ,SAAS,EAC3D,GAAIuD,EAAU,SAAW,EACvB,MAAM,IAAI,MAAM,UAAUvD,EAAQ,SAAS,kBAAkB,EAG/D,MAAMwD,EAAY,IAAI,IACpBD,EAAU,IAAKlD,GAAQ,CAACA,EAAI,KAAK,cAAeA,CAAG,CAAC,CAAC,EAEjDoD,EAAYzD,EAAQ,WAAa,IACvC,IAAI0D,EAAiB,EACrB,MAAMC,EAAsB,CAAC3D,EAAQ,uBAErC,GAAI,CACF,MAAM,KAAK,iBAAA,EAEX,QAAS4D,EAAI,EAAGA,EAAI5D,EAAQ,KAAK,OAAQ4D,GAAKH,EAAW,CACvD,MAAMI,EAAQ7D,EAAQ,KAAK,MAAM4D,EAAGA,EAAIH,CAAS,EAEjD,QAASK,EAAI,EAAGA,EAAID,EAAM,OAAQC,IAAK,CACrC,MAAMC,EAAWH,EAAIE,EACfE,EAAUH,EAAMC,CAAC,EAEvB,GAAI,CACF,MAAMG,EAAgBjE,EAAQ,aAC1B,KAAK,wBACHgE,EACAR,EACAxD,EAAQ,UACR2D,CAAmB,EAErB,KAAK,iBAAiBK,EAASR,EAAWG,CAAmB,EAE7D3D,EAAQ,kBAAoBA,EAAQ,gBACtC,MAAM,KAAK,eACTA,EAAQ,UACRiE,EACAjE,EAAQ,eAAe,EAGzB,MAAM,KAAK,UAAUA,EAAQ,UAAWiE,CAAa,EAGvDX,EAAO,aACT,OAAS1C,EAAO,CACd0C,EAAO,YACP,MAAMY,EAAY,CAChB,SAAAH,EACA,MAAOnD,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,EAC5D,QAAAoD,GAYF,GAVAV,EAAO,OAAO,KAAKY,CAAS,EAExBlE,EAAQ,SACVA,EAAQ,QACNY,aAAiB,MAAQA,EAAQ,IAAI,MAAM,OAAOA,CAAK,CAAC,EACxDmD,EACAC,CAAO,EAIP,CAAChE,EAAQ,WACX,MAAMY,CAEV,CAEA8C,IACI1D,EAAQ,YAAc0D,EAAiB,MAAQ,GACjD1D,EAAQ,WAAW0D,EAAgB1D,EAAQ,KAAK,MAAM,CAE1D,CACF,CAEA,MAAM,KAAK,kBAAA,CACb,OAASY,EAAO,CACd,MAAA,MAAM,KAAK,sBACLA,CACR,CAEA,OAAIZ,EAAQ,YACVA,EAAQ,WAAW0D,EAAgB1D,EAAQ,KAAK,MAAM,EAGxDsD,EAAO,cAAgB,KAAK,IAAA,EAAQD,EAC7BC,CACT,CAGA,MAAM,sBACJzC,EACAsD,EACAC,EACApE,EAAkC,CAAA,EAAE,CAEpC,MAAMqE,EAAkBF,EAAK,IAAKG,GAAO,CACvC,MAAMC,EAA8B,CAAA,EAEpC,OAAAH,EAAe,QAASI,GAAW,CACjC,GAAIF,EAAI,eAAeE,EAAQ,YAAY,EAAG,CAC5C,IAAIpB,EAAQkB,EAAIE,EAAQ,YAAY,EAEhCA,EAAQ,YACVpB,EAAQoB,EAAQ,UAAUpB,CAAK,GAGjCmB,EAAOC,EAAQ,YAAY,EAAIpB,CACjC,CACF,CAAC,EAEMmB,CACT,CAAC,EAED,OAAO,MAAM,KAAK,WAAU,OAAA,OAAA,CAC1B,UAAA1D,EACA,KAAMwD,CAAe,EAClBrE,CAAO,EAEd,CAGA,MAAM,cACJa,EACA4D,EACAzE,EAI6B,GAAE,CAE/B,MAAM0E,EAAY1E,EAAQ,WAAa,IACjC2E,EAAY3E,EAAQ,YAAc,GAElC4E,EAAQH,EAAQ,MAAM;AAAA,CAAI,EAAE,OAAQI,GAASA,EAAK,MAAM,EAC9D,GAAID,EAAM,SAAW,EACnB,MAAM,IAAI,MAAM,mBAAmB,EAGrC,IAAIE,EAAoB,CAAA,EACpBC,EAAiB,EAErB,GAAIJ,EACFG,EAAUF,EAAM,CAAC,EACd,MAAMF,CAAS,EACf,IAAKM,GAAMA,EAAE,OAAO,QAAQ,eAAgB,EAAE,CAAC,EAClDD,EAAiB,MACZ,CACL,MAAME,EAAeL,EAAM,CAAC,EAAE,MAAMF,CAAS,EAAE,OAC/CI,EAAU,MAAM,KACd,CAAE,OAAQG,CAAY,EACtB,CAACC,EAAGtB,IAAM,UAAUA,EAAI,CAAC,EAAE,CAE/B,CAEA,MAAMO,EAA8B,CAAA,EACpC,QAASP,EAAImB,EAAgBnB,EAAIgB,EAAM,OAAQhB,IAAK,CAClD,MAAMuB,EAASP,EAAMhB,CAAC,EACnB,MAAMc,CAAS,EACf,IAAKU,GAAMA,EAAE,OAAO,QAAQ,eAAgB,EAAE,CAAC,EAC5Cd,EAA2B,CAAA,EAEjCQ,EAAQ,QAAQ,CAACO,EAAQ5D,IAAS,CAChC6C,EAAIe,CAAM,EAAIF,EAAO1D,CAAK,GAAK,IACjC,CAAC,EAED0C,EAAK,KAAKG,CAAG,CACf,CAEA,OAAItE,EAAQ,eACH,MAAM,KAAK,sBAChBa,EACAsD,EACAnE,EAAQ,eACRA,CAAO,EAGF,MAAM,KAAK,0BAChB,UAAAa,EACA,KAAAsD,CAAI,EACDnE,CAAO,CAAA,CAGhB,CAEQ,wBACNgE,EACAR,EACA3C,EACA8C,EAA+B,GAAI,CAEnC,MAAM2B,EAAoC,CAAA,EAE1C,SAAW,CAACC,EAAYC,CAAU,IAAKhC,EAAU,UAAW,CAC1D,MAAMiC,EAAaD,EAAW,UAAY,GAAK,CAACA,EAAW,WAErDE,EADeF,EAAW,KAAO,GAErBA,EAAW,KAAK,YAAA,EAAc,SAAS,SAAS,EAElE,GAAI7B,GAAuB+B,EACzB,SAGF,MAAMtC,EAAQ,KAAK,mBAAmBY,EAASuB,CAAU,EAEzD,GAAIE,GAAerC,GAAU,KAC3B,MAAM,IAAI,MACR,oBAAoBmC,CAAU,kCAAkC1E,CAAS,GAAG,EAI5EuC,GAAU,OACZkC,EAAaC,CAAU,EAAI,KAAK,yBAC9BnC,EACAoC,EAAW,IAAI,EAGrB,CAEA,OAAOF,CACT,CAEQ,iBACNtB,EACAR,EACAG,EAA+B,GAAI,CAEnC,MAAM2B,EAAoC,CAAA,EAE1C,SAAW,CAACnC,EAAKC,CAAK,IAAK,OAAO,QAAQY,CAAO,EAAG,CAClD,MAAMuB,EAAapC,EAAI,YAAA,EACjBqC,EAAahC,EAAU,IAAI+B,CAAU,EAE3C,GAAI,CAACC,EACH,SAIF,MAAME,EADeF,EAAW,KAAO,GAErBA,EAAW,KAAK,cAAc,SAAS,SAAS,EAE9D7B,GAAuB+B,GAIvBtC,GAAU,OACZkC,EAAanC,CAAG,EAAI,KAAK,yBACvBC,EACAoC,EAAW,IAAI,EAGrB,CAEA,OAAOF,CACT,CAEQ,mBACNtB,EACAuB,EAAkB,CAElB,GAAIvB,EAAQ,eAAeuB,CAAU,EACnC,OAAOvB,EAAQuB,CAAU,EAG3B,MAAMI,EAAkBJ,EAAW,YAAA,EACnC,SAAW,CAACpC,EAAKC,CAAK,IAAK,OAAO,QAAQY,CAAO,EAC/C,GAAIb,EAAI,YAAA,IAAkBwC,EACxB,OAAOvC,CAKb,CAEQ,yBAAyBA,EAAYwC,EAAkB,CAC7D,GAAIxC,GAAU,KACZ,OAAO,KAGT,MAAMyC,EAAOD,EAAW,YAAA,EAExB,GAAI,CACF,GAAIC,EAAK,SAAS,SAAS,GAAKA,EAAK,SAAS,KAAK,EAAG,CACpD,GAAI,OAAOzC,GAAU,UACnB,OAAOA,EAAQ,EAAI,EAErB,MAAM0C,EAAM,SAAS,OAAO1C,CAAK,CAAC,EAClC,OAAO,MAAM0C,CAAG,EAAI,KAAOA,CAC7B,CAEA,GACED,EAAK,SAAS,MAAM,GACpBA,EAAK,SAAS,OAAO,GACrBA,EAAK,SAAS,SAAS,EACvB,CACA,MAAMC,EAAM,WAAW,OAAO1C,CAAK,CAAC,EACpC,OAAO,MAAM0C,CAAG,EAAI,KAAOA,CAC7B,CAEA,GAAID,EAAK,SAAS,SAAS,EAAG,CAC5B,GAAI,OAAOzC,GAAU,UACnB,OAAOA,EAAQ,EAAI,EAErB,GAAI,OAAOA,GAAU,SAAU,CAC7B,MAAM2C,EAAQ3C,EAAM,YAAA,EACpB,OAAO2C,IAAU,QAAUA,IAAU,KAAOA,IAAU,MAAQ,EAAI,CACpE,CACA,OAAO3C,EAAQ,EAAI,CACrB,CAEA,GAAIyC,EAAK,SAAS,MAAM,EAAG,CACzB,GAAI,OAAOzC,GAAU,SACnB,OAAO,KAAK,UAAUA,CAAK,EAE7B,GAAI,OAAOA,GAAU,SACnB,GAAI,CACF,YAAK,MAAMA,CAAK,EACTA,CACT,OAAEnD,EAAM,CACN,MAAM,IAAI,MACR,wCAAwC2F,CAAU,GAAG,CAEzD,CAEF,OAAO,KAAK,UAAUxC,CAAK,CAC7B,CAEA,GAAIyC,EAAK,SAAS,WAAW,GAAKA,EAAK,SAAS,UAAU,EAAG,CAC3D,GAAIzC,aAAiB,KACnB,OAAOA,EAAM,YAAA,EAEf,GAAI,OAAOA,GAAU,UAAY,OAAOA,GAAU,SAAU,CAC1D,MAAM4C,EAAO,IAAI,KAAK5C,CAAK,EAC3B,OAAO,MAAM4C,EAAK,SAAS,EAAI5C,EAAQ4C,EAAK,aAC9C,CACA,OAAO,OAAO5C,CAAK,CACrB,CAEA,OAAO,OAAOA,CAAK,CACrB,OAASxC,EAAO,CACd,MAAM,IAAI,MACR,yBAAyBwC,CAAK,qBAAqBwC,CAAU,GAAG,CAEpE,CACF,CAEQ,MAAM,UACZ/E,EACAsD,EAAyB,CAEzB,MAAMzC,EAAU,OAAO,KAAKyC,CAAI,EAC1BgB,EAAS,OAAO,OAAOhB,CAAI,EAC3BpC,EAAeL,EAAQ,IAAI,IAAM,GAAG,EAAE,KAAK,IAAI,EAE/CH,EAAM,eAAeV,CAAS,KAAKa,EAAQ,KAC/C,IAAI,CACL,aAAaK,CAAY,IAC1B,MAAM,KAAK,QAAQR,EAAK4D,CAAM,CAChC,CAEQ,MAAM,eACZtE,EACAsD,EACA8B,EAAyB,CAEzB,GAAI,CACF,MAAM,KAAK,UAAUpF,EAAWsD,CAAI,CACtC,OAASvD,EAAO,CACd,GAAI,KAAK,gBAAgBA,CAAK,EAC5B,MAAM,KAAK,mBAAmBC,EAAWsD,EAAM8B,CAAe,MAE9D,OAAMrF,CAEV,CACF,CAEQ,MAAM,mBACZC,EACAsD,EACA8B,EAAyB,CAGzB,MAAMC,EADa,OAAO,KAAK/B,CAAI,EACF,OAC9B9D,GAAQ,CAAC4F,EAAgB,SAAS5F,CAAG,CAAC,EAEnC8F,EAAeF,EAErB,GAAIC,EAAc,SAAW,EAC3B,OAGF,MAAM9D,EAAY8D,EAAc,IAAK7F,GAAQ,GAAGA,CAAG,MAAM,EAAE,KAAK,IAAI,EAC9DgC,EAAc8D,EAAa,IAAK9F,GAAQ,GAAGA,CAAG,MAAM,EAAE,KAAK,OAAO,EAElE+F,EAAeF,EAAc,IAAK7F,GAAQ8D,EAAK9D,CAAG,CAAC,EACnDgG,EAAcF,EAAa,IAAK9F,GAAQ8D,EAAK9D,CAAG,CAAC,EACjDiG,EAAY,CAAC,GAAGF,EAAc,GAAGC,CAAW,EAE5C9E,EAAM,UAAUV,CAAS,QAAQuB,CAAS,UAAUC,CAAW,GACrE,MAAM,KAAK,QAAQd,EAAK+E,CAAS,CACnC,CAEQ,gBAAgB1F,EAAU,CAChC,OACEA,EAAM,OAAS,4BACfA,EAAM,OAAS,gCACdA,EAAM,SAAWA,EAAM,QAAQ,SAAS,0BAA0B,CAEvE,CAGA,MAAM,iBAAe,CACnB,MAAMI,EAAS,MAAM,KAAK,QACxB,mDAAmD,EAE/CW,EAAU,MAAM,KAAK,iBAAA,EAE3B,MAAO,CACL,KAAM,KAAK,OACX,OAAQX,EAAO,KAAK,IAAKuF,GAAMA,EAAE,IAAI,EACrC,YAAa,KAAK,YAClB,QAAA5E,EAEJ,CAEA,MAAM,aAAad,EAAiB,CAElC,OADe,MAAM,KAAK,QAAQ,qBAAqBA,CAAS,GAAG,GACrD,IAChB,CAEA,MAAM,UAAUA,EAAiB,CAC/B,MAAMU,EAAM,wBAAwBV,CAAS,GAC7C,MAAM,KAAK,QAAQU,CAAG,CACxB,CAGA,kBAAgB,CACd,OAAO,KAAK,aAAe,CAAC,CAAC,KAAK,UACpC,CAEA,MAAM,iBAAe,CACd,KAAK,oBACR,MAAM,KAAK,QAAA,CAEf,CAEA,MAAM,QAAQA,EAAaS,EAAgB,GAAE,CAC3C,OAAA,KAAK,gBAAA,EACE,MAAM,KAAK,WAAY,QAAQT,EAAKS,CAAM,CACnD,CAEA,MAAM,OAAOT,EAAaS,EAAgB,GAAE,CAE1C,OADe,MAAM,KAAK,QAAQT,EAAKS,CAAM,GAC/B,KAAK,CAAC,GAAK,CAAA,CAC3B,CAEA,MAAM,QAAQT,EAAaS,EAAgB,CAAA,EAAE,CAE3C,OADe,MAAM,KAAK,QAAQT,EAAKS,CAAM,GAC/B,IAChB,CACD,OCr5BYwE,CAAe,CAO1B,OAAO,gBAAgB1G,EAAsB,CAC3C,KAAK,SAAS,KAAKA,CAAO,CAC5B,CAMA,OAAO,oBAAkB,CACvB,OACE,OAAO,WAAc,aACrB,UAAU,UAAY,cAEf,eAEL,OAAO,WAAW,KAAQ,YAAoB,MAC9C,OAAO,WAAW,MAAS,YAAoB,OAC/C,OAAO,QAAW,YAAoB,UACtC,OAAO,SAAY,YAAoB,UACpC,SACT,CAOQ,OAAO,mBAAiB,CAC9B,UAAWA,KAAW,KAAK,SACzB,GAAIA,EAAQ,cACV,OAAOA,EAGX,MAAM,IAAI,MAAM,mCAAmC,CACrD,CAOQ,aAAa,sBACnB2G,EACA/F,EAAsB,CAEtB,GAAI,CACF,MAAMgG,EAAS,MAAMD,EAAI,gBAAA,EACzB,GAAIC,EAAO,UAAYhG,EAAO,QAC5B,MAAM,IAAI,MACR,sCAAsCgG,EAAO,OAAO,gBAAgBhG,EAAO,OAAO,GAAG,CAG3F,OAASE,EAAO,CACd,MAAM,IAAI,MACR,uCAAuCF,EAAO,aAAa,KACxDE,EAAgB,OACnB,EAAE,CAEN,CACF,CAOQ,OAAO,eAAeF,EAAW,CACvC,GAAI,CAACA,EACH,MAAM,IAAI,MAAM,4CAA4C,EAE9D,GACE,OAAOA,EAAO,eAAkB,UAChCA,EAAO,cAAc,SAAW,GAEhC,MAAM,IAAI,MACR,2FAA2F,EAG/F,GACE,OAAOA,EAAO,SAAY,UAC1BA,EAAO,UAAY,MACnB,OAAO,KAAKA,EAAO,OAAO,EAAE,SAAW,EAEvC,MAAM,IAAI,MACR,2FAA2F,EAG/F,MAAO,EACT,CAQA,OAAO,UACLX,EACAC,EAIC,SAED,IAAIF,EAEJ,OAAIE,SAAAA,EAAS,QACXF,EAAUE,EAAQ,QAElBF,EAAU,KAAK,oBAGV,IAAID,EAAaC,EAASC,EAAQ,CACvC,mBAAmBE,EAAAD,GAAO,YAAPA,EAAS,qBAAiB,MAAAC,IAAA,OAAAA,EAAI,GACjD,eAAeC,EAAAF,GAAO,YAAPA,EAAS,iBAAa,MAAAE,IAAA,OAAAA,EAAI,EAC1C,CAAA,CACH,CASO,aAAa,aAClByG,EACA3G,EAGI,CAAA,EAAE,CAGN,MAAM4G,EAAaD,EAAO,SAAS,KAAK,EAAIA,EAAS,GAAGA,CAAM,MAGxDF,EAAM,KAAK,UAAUG,EAAY5G,CAAO,EAE9C,GAAI,CACF,OAAA,MAAMyG,EAAI,UAEV,MAAMA,EAAI,QAAQ,wBAAwB,EACnCA,CACT,OAAS7F,EAAO,CACd,MAAA,MAAM6F,EAAI,MAAA,EACJ,IAAI,MACR,2BAA2BG,CAAU,MAAOhG,EAAgB,OAAO,EAAE,CAEzE,CACF,CASQ,aAAa,qBACnBZ,EACA6G,EAAuB,GACvBC,EAAyB,GAAK,CAE9B,IAAIpG,EAGJ,GAAIV,EAAQ,OACVU,EAASV,EAAQ,eACRA,EAAQ,YACjBU,EAASV,EAAQ,gBAEjB,OAAM,IAAI,MACR,kFAAkF,EAKtF,KAAK,eAAeU,CAAM,EAG1B,MAAMkG,EAAalG,EAAO,cAAc,SAAS,KAAK,EAClDA,EAAO,cACP,GAAGA,EAAO,aAAa,MAGrB+F,EAAM,KAAK,UAAUG,EAAY,CACrC,QAAS5G,EAAQ,QACjB,kBAAmB6G,EACnB,cAAeC,CAChB,CAAA,EAED,GAAI,CAEF,MAAML,EAAI,UAGV,MAAMA,EAAI,qBAAqB/F,CAAM,EAIrC,GAAI,CACF,MAAM,KAAK,sBAAsB+F,EAAK/F,CAAM,CAC9C,OAASqG,EAAkB,CACzB,MAAA,MAAMN,EAAI,MAAA,EACJ,IAAI,MACR,wGAAwGM,EAAY,OAAO,EAAE,CAEjI,CACA,OAAON,CACT,OAAS7F,EAAO,CACd,MAAI6F,EAAI,iBAAA,GACN,MAAMA,EAAI,MAAA,EAEN7F,CACR,CACF,CAQO,aAAa,OAAOZ,EAAyB,CAClD,OAAO,KAAK,qBAAqBA,EAAS,GAAM,EAAI,CACtD,CAUO,aAAa,aAClBA,EACA6G,EAAuB,GAAK,CAE5B,OAAO,KAAK,qBAAqB7G,EAAS6G,CAAW,CACvD,CAQO,aAAa,gBAClBG,EACAhH,EAGI,CAAA,EAAE,CAEN,GAAI,CACF,OAAO,MAAM,KAAK,sCACbA,CAAO,EAAA,CACV,YAAAgH,CAAW,CAAA,CAAA,CAEf,OAASpG,EAAO,CACd,MAAM,IAAI,MACR,uCAAwCA,EAAgB,OAAO,EAAE,CAErE,CACF,CAQO,aAAa,iBAClBT,EACAH,EAGI,CAAA,EAAE,CAEN,GAAI,CACF,OAAO,MAAM,KAAK,sCACbA,CAAO,EAAA,CACV,OAAAG,CAAM,CAAA,CAAA,CAEV,OAASS,EAAO,CACd,MAAM,IAAI,MACR,wCAAyCA,EAAgB,OAAO,EAAE,CAEtE,CACF,EAxSe4F,EAAA,SAA4B,CAAA,QCiChCS,CAAe,CAoBnB,OAAO,mBAAiB,CAC7B,OAAO,KAAK,cACd,CAOO,OAAO,kBAAkBC,EAAsB,CACpD,GAAIA,GAAkB,EACpB,MAAM,IAAI,MAAM,+CAA+C,EAGjE,MAAMC,EAAyB,OAAO,KAAK,KAAK,WAAW,EAAE,OAC7D,GAAIA,EAAyBD,EAC3B,MAAM,IAAI,MACR,qCAAqCA,CAAc,iCACpBC,CAAsB,8DACf,EAI1C,KAAK,eAAiBD,CACxB,CAKO,OAAO,iBAAiBE,EAAsB,CACnD,KAAK,cAAgBA,CACvB,CAKO,OAAO,eAAejE,EAAazC,EAAsB,CAC9D,KAAK,qBAAqByC,CAAG,EAAIzC,CACnC,CAKO,OAAO,gBAAgB2G,EAAuC,CACnE,OAAO,QAAQA,CAAO,EAAE,QAAQ,CAAC,CAAClE,EAAKzC,CAAM,IAAK,CAChD,KAAK,eAAeyC,EAAKzC,CAAM,CACjC,CAAC,CACH,CAKQ,OAAO,UAAUyC,EAAW,CAElC,GAAI,KAAK,qBAAqBA,CAAG,EAC/B,OAAO,KAAK,qBAAqBA,CAAG,EAItC,GAAI,KAAK,cACP,OAAO,KAAK,cAAc,UAAUA,CAAG,CAI3C,CAKO,OAAO,qBAAmB,OAC/B,MAAMmE,EAAe,OAAO,KAAK,KAAK,oBAAoB,EACpDC,IAAetH,EAAA,KAAK,iBAAa,MAAAA,IAAA,OAAA,OAAAA,EAAE,iBAAA,IAAsB,CAAA,EAC/D,MAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAGqH,EAAc,GAAGC,CAAY,CAAC,CAAC,CACxD,CAKO,OAAO,aAAaC,EAAsB,CAC/C,KAAK,aAAaA,EAAW,QAAQ,EAAIA,CAC3C,CAKO,OAAO,cAAcC,EAAyB,CACnDA,EAAY,QAAQtH,GAAU,KAAK,aAAaA,CAAM,CAAC,CACzD,CAKO,OAAO,oBAAkB,CAC9B,OAAA,OAAA,OAAA,CAAA,EAAY,KAAK,YAAY,CAC/B,CAKO,OAAO,iBAAiBuH,EAAgB,CAC7C,MAAMF,EAAa,KAAK,aAAaE,CAAQ,EAC7C,GAAI,CAACF,EACH,MAAM,IAAI,MAAM,SAASE,CAAQ,sBAAsB,EAEzD,MAAO,CACL,GAAGF,EAAW,kBACd,GAAIA,EAAW,mBAAqB,CAAA,EAExC,CAKO,OAAO,yBAAuB,CACnC,MAAMG,EAAe,IAAI,IACzBA,EAAa,IAAI,MAAM,EAEvB,UAAWD,KAAY,KAAK,iBAAkB,CAC5C,MAAMF,EAAa,KAAK,aAAaE,CAAQ,EACzCF,IACFA,EAAW,kBAAkB,QAAQI,GAAMD,EAAa,IAAIC,CAAE,CAAC,EAC3DJ,EAAW,mBACbA,EAAW,kBAAkB,QAAQI,GAAMD,EAAa,IAAIC,CAAE,CAAC,EAGrE,CAEA,OAAO,MAAM,KAAKD,CAAY,CAChC,CAKO,aAAa,0BAAwB,CAC1C,GAAI,CAAA,KAAK,YAAY,KAIrB,GAAI,CACF,MAAME,EAAa,KAAK,UAAU,MAAM,EACxC,GAAI,CAACA,EACH,MAAM,IAAI,MAAM,iCAAiC,EAGnD,MAAMpB,EAAM,MAAMD,EAAgB,aAAa,CAAE,OAAQqB,CAAU,EAAI,EAAK,EAC5E,MAAMpB,EAAI,QAAQ,wBAAwB,EAC1C,KAAK,YAAY,KAAUA,CAC7B,OAAS7F,EAAO,CACd,MAAM,IAAI,MAAM,qCAAsCA,EAAgB,OAAO,EAAE,CACjF,CACF,CAKO,aAAa,oBAClBkH,EACAC,EAAoB,CAGpB,UAAWL,KAAYI,EACrB,GAAI,CAAC,KAAK,aAAaJ,CAAQ,EAC7B,MAAM,IAAI,MAAM,SAASA,CAAQ,gDAAgD,EAIrF,MAAMM,EAAgB,CAAC,GAAG,KAAK,gBAAgB,EAC/C,KAAK,iBAAmBF,EACxB,KAAK,YAAcC,GAAeD,EAAU,CAAC,GAAK,KAElD,MAAM,KAAK,8BAAA,EACX,MAAM,KAAK,yBAAyBE,CAAa,CACnD,CAKO,OAAO,qBAAmB,CAC/B,MAAO,CAAC,GAAG,KAAK,gBAAgB,CAClC,CAKO,OAAO,gBAAc,CAC1B,OAAO,KAAK,WACd,CAKQ,aAAa,+BAA6B,CAChD,MAAMC,EAAoB,KAAK,wBAAA,EACzBC,EAAyD,CAAA,EAEzDC,EAAeF,EAAkB,IAAI,MAAMG,GAAQ,CACvD,GAAI,CAAA,KAAK,YAAYA,CAAK,EAI1B,GAAI,CACF,MAAM1H,EAAS,KAAK,UAAU0H,CAAK,EACnC,GAAI,CAAC1H,EACH,MAAM,IAAI,MAAM,iBAAiB0H,CAAK,uCAAuC,EAG/E,MAAM3B,EAAM,MAAMD,EAAgB,aAAa,CAAE,OAAQ9F,CAAM,EAAI,EAAK,EACxE,MAAM+F,EAAI,QAAQ,wBAAwB,EAC1C,KAAK,YAAY2B,CAAK,EAAI3B,CAC5B,OAAS7F,EAAO,CACd,MAAMyH,EAAMzH,aAAiB,MAAQA,EAAQ,IAAI,MAAM,OAAOA,CAAK,CAAC,EAGjD,KAAK,iBAAiB,KAAK8G,GAAW,CACvD,MAAMF,EAAa,KAAK,aAAaE,CAAQ,EAC7C,OAAOF,GAAcA,EAAW,kBAAkB,SAASY,CAAK,CAClE,CAAC,GAGCF,EAAsB,KAAK,CAAE,IAAKE,EAAO,MAAOC,CAAG,CAAE,CAGzD,CACF,CAAC,EAID,GAFA,MAAM,QAAQ,IAAIF,CAAY,EAE1BD,EAAsB,OAAS,EAAG,CACpC,MAAMI,EAAeJ,EAClB,IAAIK,GAAK,OAAOA,EAAE,GAAG,KAAKA,EAAE,MAAM,OAAO,EAAE,EAC3C,KAAK;AAAA,CAAI,EACZ,MAAM,IAAI,MAAM;AAAA,EAA4DD,CAAY,EAAE,CAC5F,CACF,CAKQ,aAAa,yBAAyBN,EAAuB,CACnE,MAAMQ,EAAoB,IAAI,IAC9BA,EAAkB,IAAI,MAAM,EAE5B,UAAWd,KAAYM,EAAe,CACpC,MAAMR,EAAa,KAAK,aAAaE,CAAQ,EACzCF,IACFA,EAAW,kBAAkB,QAAQI,GAAMY,EAAkB,IAAIZ,CAAE,CAAC,EAChEJ,EAAW,mBACbA,EAAW,kBAAkB,QAAQI,GAAMY,EAAkB,IAAIZ,CAAE,CAAC,EAG1E,CAEA,MAAMa,EAAmB,IAAI,IAAI,KAAK,yBAAyB,EACzDC,EAAmB,MAAM,KAAKF,CAAiB,EAAE,OACrDZ,GAAM,CAACa,EAAiB,IAAIb,CAAE,CAAC,EAGjC,GAAIc,EAAiB,OAAS,GAC5B,UAAWN,KAASM,EAClB,GAAI,KAAK,YAAYN,CAAK,EACxB,GAAI,CACF,MAAM,KAAK,YAAYA,CAAK,EAAE,MAAA,EAC9B,OAAO,KAAK,YAAYA,CAAK,CAC/B,OAASxH,EAAO,CAEhB,EAIR,CAKO,OAAO,oBAAoBwH,EAAa,CAG7C,OAAO,KAAK,UAAUA,CAAK,IAAM,MACnC,CAKO,OAAO,IAAIjF,EAAW,CAC3B,GAAI,CAAC,KAAK,oBAAoBA,CAAG,EAC/B,MAAM,IAAI,MAAM,4BAA4BA,CAAG,sBAAsB,EAGvE,MAAMsD,EAAM,KAAK,YAAYtD,CAAG,EAChC,GAAI,CAACsD,EACH,MAAM,IAAI,MAAM,aAAatD,CAAG,qDAAqD,EAGvF,OAAOsD,CACT,CAKO,OAAO,oBACZkC,EACAC,EAAqC,CAEhC,KAAK,eAAe,IAAID,CAAU,GACrC,KAAK,eAAe,IAAIA,EAAY,CAAA,CAAE,EAExC,KAAK,eAAe,IAAIA,CAAU,EAAG,KAAKC,CAAQ,CACpD,CAKO,OAAO,qBACZD,EACAC,EAAqC,CAErC,MAAMC,EAAY,KAAK,eAAe,IAAIF,CAAU,EACpD,GAAIE,EAAW,CACb,MAAMpH,EAAQoH,EAAU,QAAQD,CAAQ,EACpCnH,EAAQ,IACVoH,EAAU,OAAOpH,EAAO,CAAC,CAE7B,CACF,CAKQ,OAAO,wBAAwBkH,EAAoBlC,EAAiB,CAC1E,MAAMoC,EAAY,KAAK,eAAe,IAAIF,CAAU,EAChDE,GACFA,EAAU,QAAQD,GAAW,CAC3B,GAAI,CACFA,EAASnC,CAAG,CACd,OAAS7F,EAAO,CAEhB,CACF,CAAC,CAEL,CAKQ,aAAa,qBAAmB,CACtC,GAAI,CAAA,KAAK,qBAIT,CAAA,KAAK,qBAAuB,GAC5B,GAAI,CAEsB,OAAO,KAAK,KAAK,WAAW,EACpC,QAAQwH,GAAS,KAAK,gBAAgB,IAAIA,CAAK,CAAC,EAEhE,MAAMU,EAAgB,OAAO,QAAQ,KAAK,WAAW,EAAE,IACrD,MAAO,CAACV,EAAO3B,CAAG,IAAK,CACrB,GAAI,CACF,MAAMA,EAAI,MAAA,CACZ,OAAS7F,EAAO,CAEhB,CACF,CAAC,EAGH,MAAM,QAAQ,IAAIkI,CAAa,EAC/B,KAAK,YAAc,CAAA,CACrB,SACE,KAAK,qBAAuB,EAC9B,CAAA,CACF,CAKO,aAAa,mBAAiB,CACnC,MAAM,KAAK,yBAAA,EAEP,KAAK,iBAAiB,OAAS,GACjC,MAAM,KAAK,8BAAA,EAIb,MAAMC,EAAgB,MAAM,KAAK,KAAK,eAAe,EACrD,GAAIA,EAAc,OAAS,EACzB,UAAWX,KAASW,EAClB,GAAK,KAAK,YAAYX,CAAK,EAYhB,KAAK,YAAYA,CAAK,GAE/B,KAAK,wBAAwBA,EAAO,KAAK,YAAYA,CAAK,CAAC,MAd/B,CAC5B,MAAM1H,EAAS,KAAK,UAAU0H,CAAK,EACnC,GAAI1H,EACF,GAAI,CACF,MAAM+F,EAAM,MAAMD,EAAgB,aAAa,CAAE,OAAQ9F,CAAM,EAAI,EAAK,EACxE,MAAM+F,EAAI,QAAA,EACV,KAAK,YAAY2B,CAAK,EAAI3B,EAC1B,KAAK,wBAAwB2B,EAAO3B,CAAG,CACzC,OAAS7F,EAAO,CAEhB,CAEJ,CAMN,CAKO,aAAa,yBAAyBuC,EAAW,CAGtD,GAFA,KAAK,gBAAgB,IAAIA,CAAG,EAExB,CAAC,KAAK,oBAAoBA,CAAG,EAC/B,MAAM,IAAI,MAAM,4BAA4BA,CAAG,sBAAsB,EAGvE,GAAI,KAAK,YAAYA,CAAG,EACtB,GAAI,CAEF,GADoB,KAAK,YAAYA,CAAG,EAAE,iBAAA,EAExC,OAAO,KAAK,YAAYA,CAAG,EAG3B,GAAI,CACF,MAAM,KAAK,YAAYA,CAAG,EAAE,QAAQ,MAAM,IAAK,CAAE,CAAC,CACpD,OAASvC,EAAO,CAEhB,CACA,OAAO,KAAK,YAAYuC,CAAG,CAE/B,OAASvC,EAAO,CACd,OAAO,KAAK,YAAYuC,CAAG,CAC7B,CAIF,OAAO,MAAM,KAAK,eAAeA,CAAG,CACtC,CAKO,OAAO,gBAAc,CAC1B,OAAA,OAAA,OAAA,CAAA,EAAY,KAAK,WAAW,CAC9B,CAKO,aAAa,gBAAgB6F,EAAsB,CACxD,MAAMC,EAA+C,CAAA,EAErD,UAAW9F,KAAO6F,EAChB,GAAI,CACF,MAAMtI,EAAS,KAAK,UAAUyC,CAAG,EACjC,GAAI,CAACzC,EACH,MAAM,IAAI,MAAM,yBAAyByC,CAAG,qBAAqB,EAGnE,MAAMsD,EAAM,MAAMD,EAAgB,aAAa,CAAE,OAAQ9F,CAAM,EAAI,EAAK,EACxE,MAAM+F,EAAI,QAAQ,wBAAwB,EAC1C,KAAK,YAAYtD,CAAG,EAAIsD,CAC1B,OAAS7F,EAAO,CACd,MAAMyH,EAAMzH,aAAiB,MAAQA,EAAQ,IAAI,MAAM,OAAOA,CAAK,CAAC,EACpEqI,EAAY,KAAK,CAAE,IAAA9F,EAAK,MAAOkF,CAAG,CAAE,CACtC,CAGF,GAAIY,EAAY,OAAS,EAAG,CAC1B,MAAMX,EAAeW,EAClB,IAAIV,GAAK,OAAOA,EAAE,GAAG,KAAKA,EAAE,MAAM,OAAO,EAAE,EAC3C,KAAK;AAAA,CAAI,EACZ,MAAM,IAAI,MAAM;AAAA,EAA0CD,CAAY,EAAE,CAC1E,CAEA,OAAA,KAAK,cAAgB,GACd,EACT,CAKO,aAAa,eAAeU,EAAsB,CACvD,MAAME,EAAcF,EAAa,OAAO7F,GAAO,CAAC,KAAK,UAAUA,CAAG,CAAC,EACnE,GAAI+F,EAAY,OAAS,EACvB,MAAM,IAAI,MAAM,0BAA0BA,EAAY,KAAK,IAAI,CAAC,sBAAsB,EAGxF,MAAMC,EAAsBH,EAAa,OAAO7F,GAAO,CAAC,KAAK,YAAYA,CAAG,CAAC,EAAE,OACzEiG,EAA0B,OAAO,KAAK,KAAK,WAAW,EAAE,OAE9D,GAAIA,EAA0BD,EAAsB,KAAK,eACvD,MAAM,IAAI,MACR,qBAAqBA,CAAmB,6CAA6C,KAAK,cAAc,0BAA0BC,CAAuB,EAAE,EAI/J,MAAMlB,EAAyD,CAAA,EACzDC,EAAea,EAAa,IAAI,MAAM7F,GAAM,CAChD,GAAI,MAAK,YAAYA,CAAG,EAIxB,GAAI,CACF,MAAMzC,EAAS,KAAK,UAAUyC,CAAG,EAC3BsD,EAAM,MAAMD,EAAgB,aAAa,CAAE,OAAQ9F,CAAM,EAAI,EAAK,EACxE,MAAM+F,EAAI,QAAQ,wBAAwB,EAC1C,KAAK,YAAYtD,CAAG,EAAIsD,CAC1B,OAAS7F,EAAO,CACd,MAAMyH,EAAMzH,aAAiB,MAAQA,EAAQ,IAAI,MAAM,OAAOA,CAAK,CAAC,EACpEsH,EAAsB,KAAK,CAAE,IAAA/E,EAAK,MAAOkF,CAAG,CAAE,CAChD,CACF,CAAC,EAID,GAFA,MAAM,QAAQ,IAAIF,CAAY,EAE1BD,EAAsB,OAAS,EAAG,CACpC,MAAMI,EAAeJ,EAClB,IAAIK,GAAK,OAAOA,EAAE,GAAG,KAAKA,EAAE,MAAM,OAAO,EAAE,EAC3C,KAAK;AAAA,CAAI,EACZ,MAAM,IAAI,MAAM;AAAA,EAAgDD,CAAY,EAAE,CAChF,CAEA,OAAI,OAAO,KAAK,KAAK,WAAW,EAAE,OAAS,IACzC,KAAK,cAAgB,IAGhB,EACT,CAKO,aAAa,eAAa,CAC/B,GAAI,KAAK,cACP,OAGF,MAAMe,EAAmB,KAAK,sBACxBnB,EAAyD,CAAA,EAEzDC,EAAekB,EAAiB,IAAI,MAAMlG,GAAM,CACpD,GAAI,CACF,MAAMzC,EAAS,KAAK,UAAUyC,CAAG,EAC3BsD,EAAM,MAAMD,EAAgB,aAAa,CAAE,OAAQ9F,CAAM,EAAI,EAAK,EACxE,KAAK,YAAYyC,CAAG,EAAIsD,CAC1B,OAAS7F,EAAO,CACd,MAAMyH,EAAMzH,aAAiB,MAAQA,EAAQ,IAAI,MAAM,OAAOA,CAAK,CAAC,EACpEsH,EAAsB,KAAK,CAAE,IAAA/E,EAAK,MAAOkF,CAAG,CAAE,CAChD,CACF,CAAC,EAID,GAFA,MAAM,QAAQ,IAAIF,CAAY,EAE1BD,EAAsB,OAAS,EAAG,CACpC,KAAK,cAAgB,GACrB,MAAMI,EAAeJ,EAClB,IAAIK,GAAK,OAAOA,EAAE,GAAG,KAAKA,EAAE,MAAM,OAAO,EAAE,EAC3C,KAAK;AAAA,CAAI,EACZ,MAAM,IAAI,MAAM;AAAA,EAAgDD,CAAY,EAAE,CAChF,CAEA,KAAK,cAAgB,EACvB,CAKO,aAAa,eAAenF,EAAW,CAG5C,GAFA,KAAK,gBAAgB,IAAIA,CAAG,EAExB,CAAC,KAAK,oBAAoBA,CAAG,EAC/B,MAAM,IAAI,MAAM,4BAA4BA,CAAG,sBAAsB,EAGvE,GAAI,CAAC,KAAK,YAAYA,CAAG,EAAG,CAC1B,MAAMzC,EAAS,KAAK,UAAUyC,CAAG,EACjC,GAAI,CAACzC,EACH,MAAM,IAAI,MAAM,yBAAyByC,CAAG,qBAAqB,EAGnE,GAAI,OAAO,KAAK,KAAK,WAAW,EAAE,QAAU,KAAK,eAC/C,MAAM,IAAI,MAAM,gDAAgD,EAGlE,MAAMsD,EAAM,MAAMD,EAAgB,aAAa,CAAE,OAAQ9F,CAAM,EAAI,EAAK,EACxE,MAAM+F,EAAI,QAAA,EACV,KAAK,YAAYtD,CAAG,EAAIsD,CAC1B,CAEA,OAAA,KAAK,cAAgB,GACd,KAAK,YAAYtD,CAAG,CAC7B,CAKO,aAAa,8BAClBkE,EACAuB,EAA+D,CAE/D,UAAWzF,KAAOkE,EAChB,GAAI,CAAC,KAAK,oBAAoBlE,CAAG,EAC/B,MAAM,IAAI,MAAM,4BAA4BA,CAAG,sBAAsB,EAIzE,MAAMmG,EAAOjC,EAAQ,OAAO,CAACkC,EAAKpG,KAChCoG,EAAIpG,CAAG,EAAI,KAAK,IAAIA,CAAG,EAChBoG,GACN,CAAA,CAAkC,EAErC,GAAI,CACF,MAAM,QAAQ,IAAI,OAAO,OAAOD,CAAI,EAAE,IAAI7C,GAAOA,EAAI,iBAAA,CAAkB,CAAC,EACxE,MAAMmC,EAASU,CAAI,EACnB,MAAM,QAAQ,IAAI,OAAO,OAAOA,CAAI,EAAE,IAAI7C,GAAOA,EAAI,mBAAmB,CAAC,CAC3E,OAAS7F,EAAO,CACd,MAAA,MAAM,QAAQ,IAAI,OAAO,OAAO0I,CAAI,EAAE,IAAI7C,GAAOA,EAAI,oBAAA,CAAqB,CAAC,EACrE7F,CACR,CACF,CAKO,aAAa,kBAClB4I,EACA3I,EACAsD,EACAnE,EAAkC,CAAA,EAAE,CAEpC,GAAI,CAAC,KAAK,oBAAoBwJ,CAAW,EACvC,MAAM,IAAI,MAAM,4BAA4BA,CAAW,sBAAsB,EAG/E,MAAM/C,EAAM,KAAK,IAAI+C,CAAW,EAChC,GAAI,CAMF,OALe,MAAM/C,EAAI,0BACvB,UAAA5F,EACA,KAAAsD,CAAI,EACDnE,CAAO,CAAA,CAGd,OAASY,EAAO,CACd,MAAMA,CACR,CACF,CAKO,aAAa,sBAClB4I,EACA3I,EACAsD,EACAC,EACApE,EAAkC,CAAA,EAAE,CAEpC,GAAI,CAAC,KAAK,oBAAoBwJ,CAAW,EACvC,MAAM,IAAI,MAAM,4BAA4BA,CAAW,sBAAsB,EAG/E,MAAM/C,EAAM,KAAK,IAAI+C,CAAW,EAChC,GAAI,CAOF,OANe,MAAM/C,EAAI,sBACvB5F,EACAsD,EACAC,EACApE,CAAO,CAGX,OAASY,EAAO,CACd,MAAMA,CACR,CACF,CAKO,aAAa,WAAW6I,EAAqC,CAClE,MAAMpG,EAAY,KAAK,IAAA,EACjBC,EAA2B,CAC/B,eAAgBmG,EAAc,OAC9B,iBAAkB,EAClB,QAAS,CAAA,EACT,OAAQ,CAAA,EACR,cAAe,GAGjB,UAAWtJ,KAAUsJ,EAAe,CAClC,MAAMC,EAAY,GAAGvJ,EAAO,WAAW,IAAIA,EAAO,SAAS,GAC3D,GAAI,CACF,GAAI,CAAC,KAAK,oBAAoBA,EAAO,WAAW,EAC9C,MAAM,IAAI,MAAM,4BAA4BA,EAAO,WAAW,sBAAsB,EAGtF,MAAMsG,EAAM,KAAK,IAAItG,EAAO,WAAW,EACvC,IAAIwJ,EAEAxJ,EAAO,eACTwJ,EAAe,MAAMlD,EAAI,sBACvBtG,EAAO,UACPA,EAAO,KACPA,EAAO,eACPA,EAAO,OAAO,EAGhBwJ,EAAe,MAAMlD,EAAI,WAAU,OAAA,OAAA,CACjC,UAAWtG,EAAO,UAClB,KAAMA,EAAO,MACVA,EAAO,OAAO,CAAA,EAIrBmD,EAAO,QAAQoG,CAAS,EAAIC,EAC5BrG,EAAO,kBACT,OAAS1C,EAAO,CACd,MAAMyH,EAAMzH,aAAiB,MAAQA,EAAQ,IAAI,MAAM,OAAOA,CAAK,CAAC,EACpE0C,EAAO,OAAOoG,CAAS,EAAIrB,CAC7B,CACF,CAEA,OAAA/E,EAAO,cAAgB,KAAK,IAAA,EAAQD,EAC7BC,CACT,CAKO,aAAa,cAClBkG,EACA3I,EACA4D,EACAzE,EAI6B,CAAA,EAAE,CAE/B,GAAI,CAAC,KAAK,oBAAoBwJ,CAAW,EACvC,MAAM,IAAI,MAAM,4BAA4BA,CAAW,sBAAsB,EAG/E,MAAM/C,EAAM,KAAK,IAAI+C,CAAW,EAChC,GAAI,CAEF,OADe,MAAM/C,EAAI,cAAc5F,EAAW4D,EAASzE,CAAO,CAEpE,OAASY,EAAO,CACd,MAAMA,CACR,CACF,CAKO,OAAO,oBAAkB,CAC9B,OAAO,OAAO,KAAK,KAAK,WAAW,EAAE,MACvC,CAKO,OAAO,iBAAe,CAC3B,OAAO,OAAO,KAAK,KAAK,WAAW,CACrC,CAKO,aAAa,gBAAgBwH,EAAa,CAC/C,MAAM3B,EAAM,KAAK,YAAY2B,CAAK,EAC9B3B,IACF,MAAMA,EAAI,WAAA,EACV,OAAO,KAAK,YAAY2B,CAAK,EAEjC,CAKO,aAAa,UAAQ,CAC1B,MAAM,KAAK,oBAAA,EAEX,KAAK,iBAAmB,CAAA,EACxB,KAAK,YAAc,KACnB,KAAK,cAAgB,GACrB,KAAK,gBAAgB,MAAA,EACrB,KAAK,eAAe,MAAA,EACpB,KAAK,qBAAuB,EAC9B,CAKO,aAAa,QAAM,CACxB,MAAMwB,EAAqB,OAAO,KAAK,KAAK,WAAW,EAAE,OACvDzG,GAAOA,IAAQ,MAAM,EAGvB,UAAWiF,KAASwB,EAClB,GAAI,CACF,MAAM,KAAK,YAAYxB,CAAK,EAAE,MAAA,EAC9B,OAAO,KAAK,YAAYA,CAAK,CAC/B,OAASxH,EAAO,CAEhB,CAGF,KAAK,iBAAmB,CAAA,EACxB,KAAK,YAAc,IACrB,EA7zBeqG,EAAA,eAAiB,GACjBA,EAAA,YAAmC,CAAA,EACnCA,EAAA,cAAgB,GAChBA,EAAA,aAA6B,CAAA,EAC7BA,EAAA,YAA6B,KAC7BA,EAAA,iBAA6B,CAAA,EAC7BA,EAAA,gBAA+B,IAAI,IACnCA,EAAA,qBAAuB,GAGvBA,EAAA,qBAAuD,CAAA,EACvDA,EAAA,cAAsC,KAGtCA,EAAA,eAAkE,IAAI,UC7BjE4C,CAAW,CAY/B,YAAYlB,EAAoB9H,EAAkB,CAXxC,KAAA,IAA2B,KAG3B,KAAA,SAAoB,GACpB,KAAA,cAAyB,GACzB,KAAA,cAA2C,IAAI,IAC/C,KAAA,eAA8C,IAAI,IAClD,KAAA,iBAA6B,CAAC,IAAI,EACpC,KAAA,MAA0B,IAAI,IAIpC,KAAK,WAAa8H,EAClB,KAAK,UAAY9H,GAAa8H,EAG9B,KAAK,iBAAoBmB,GAAwB,CAC/C,KAAK,IAAMA,EACX,KAAK,MAAM,iBAAkB,CAAE,WAAY,KAAK,UAAU,CAAE,CAC9D,EAEA7C,EAAgB,oBAAoB0B,EAAY,KAAK,gBAAgB,EACrE,KAAK,aACP,CAEQ,aAAW,CACD,OAAO,oBAAoB,OAAO,eAAe,IAAI,CAAC,EAC9D,QAASoB,GAAU,CAEvB,OAAQ,KAAaA,CAAM,GAAM,YACjCA,IAAW,gBAEV,KAAaA,CAAM,EAAK,KAAaA,CAAM,EAAE,KAAK,IAAI,EAE3D,CAAC,CACH,CAKA,oBAAoBC,EAAgB,CAClC,OAAA,KAAK,iBAAmBA,EACjB,IACT,CAKA,MAAM,MAAI,CACR,GAAI,CACF,GAAI,KAAK,cACP,OAAO,KAKT,GAFA,KAAK,IAAM,MAAM/C,EAAgB,eAAe,KAAK,UAAU,EAE3D,CAAC,KAAK,IACR,MAAM,IAAI,MACR,wCAAwC,KAAK,UAAU,EAAE,EAI7D,OAAK,KAAK,IAAI,iBAAA,GACZ,MAAM,KAAK,IAAI,UAGjB,KAAK,SAAW,GAChB,KAAK,cAAgB,GACrB,KAAK,MAAM,cAAe,CAAE,WAAY,KAAK,UAAU,CAAE,EAElD,IACT,OAASrG,EAAO,CACd,MAAA,KAAK,aAAa,aAAcA,CAAc,EACxCA,CACR,CACF,CAKA,MAAM,OAAOuD,EAAgB,CAC3B,MAAM,KAAK,qBACX,MAAM,KAAK,sBAAA,EACX,GAAI,CACF,KAAK,cAAcA,CAAI,EACvB,MAAMjB,EAAa,KAAK,eAAeiB,CAA2B,EAC5Db,EAAS,MAAM,KAAK,IAAK,OAAOJ,CAAU,EAChD,GAAII,EAAO,eAAiB,EAC1B,MAAM,IAAI,MAAM,4CAA4C,EAE9D,IAAI2G,EAA0B,KAC9B,MAAMC,EAAkB/F,EAAK,KAAK,iBAAiB,CAAC,CAAY,EAChE,GAAI,CACmC+F,GAAoB,KACvDD,EAAgB,MAAM,KAAK,SAASC,CAAsB,EACjD5G,EAAO,kBAChB2G,EAAgB,MAAM,KAAK,SAAS3G,EAAO,eAAe,EAE9D,OAAS6G,EAAW,CAClB,QAAQ,KAAK,8CAA+CA,CAAS,CACvE,CACA,OAAKF,IACHA,EAAgB9F,GAElB,KAAK,MAAM,cAAe,CAAE,UAAW,SAAU,KAAM8F,CAAa,CAAE,EAC/DA,CACT,OAASrJ,EAAO,CACd,MAAA,KAAK,aAAa,eAAgBA,CAAc,EAC1CA,CACR,CACF,CAKA,MAAM,OAAOwJ,EAASjG,EAAgB,CACpC,MAAM,KAAK,mBAAA,EAEX,GAAI,CACF,GAAI,CAACiG,EACH,MAAM,IAAI,MAAM,2BAA2B,EAG7C,KAAK,cAAcjG,CAAI,EACvB,MAAMkG,EAAU,OAAA,OAAA,OAAA,OAAA,CAAA,EACXlG,CAAI,EAAA,CACP,CAAC,KAAK,iBAAiB,CAAC,CAAC,EAAGiG,IAGxBlH,EAAa,KAAK,eAAemH,CAAiC,EACxE,MAAM,KAAK,IAAK,OAAOnH,CAAU,EAEjC,MAAMI,EAAS,MAAM,KAAK,SAAS8G,CAAE,EACrC,YAAK,MAAM,cAAe,CAAE,UAAW,SAAU,GAAAA,EAAI,KAAM9G,CAAM,CAAE,EAC5DA,CACT,OAAS1C,EAAO,CACd,WAAK,aAAa,eAAgBA,CAAc,EAC1CA,CACR,CACF,CAKA,MAAM,OAAOwJ,EAAO,CAClB,MAAM,KAAK,qBAEX,GAAI,CACF,GAAI,CAACA,EACH,MAAM,IAAI,MAAM,2BAA2B,EAG7C,MAAMlH,EAAyB,CAC7B,KAAM,KAAK,UACX,KAAM,GACN,OAAQ,CAAC,CAAE,KAAM,KAAK,iBAAiB,CAAC,EAAG,MAAOkH,EAAI,GAIlDE,GADS,MAAM,KAAK,IAAK,OAAOpH,CAAU,GACzB,aAAe,EAEtC,OAAIoH,GACF,KAAK,MAAM,cAAe,CAAE,UAAW,SAAU,GAAAF,CAAE,CAAE,EAGhDE,CACT,OAAS1J,EAAO,CACd,MAAA,KAAK,aAAa,eAAgBA,CAAc,EAC1CA,CACR,CACF,CAKA,MAAM,SAASwJ,EAAO,CACpB,MAAM,KAAK,qBAEX,GAAI,CACF,GAAI,CAACA,EACH,MAAM,IAAI,MAAM,gBAAgB,EAGlC,MAAMvH,EAAa,CAAE,CAAC,KAAK,iBAAiB,CAAC,CAAC,EAAGuH,GAC3ClH,EAAa,KAAK,iBAAiBL,CAAU,EAC7CS,EAAS,MAAM,KAAK,IAAK,OAAOJ,CAAU,EAE1CqH,EAAS,OAAO,KAAKjH,CAAM,EAAE,OAAS,EAAKA,EAAe,KAChE,YAAK,MAAM,cAAe,CAAE,UAAW,WAAY,GAAA8G,CAAE,CAAE,EAChDG,CACT,OAAS3J,EAAO,CACd,MAAA,KAAK,aAAa,mBAAoBA,CAAc,EAC9CA,CACR,CACF,CAKA,MAAM,UAAUiC,EAAkC,CAAA,EAAE,CAClD,MAAM,KAAK,mBAAA,EAEX,GAAI,CACF,MAAMK,EAAa,KAAK,iBAAiBL,CAAU,EAC7CS,EAAS,MAAM,KAAK,IAAK,OAAOJ,CAAU,EAE1CqH,EAAS,OAAO,KAAKjH,CAAM,EAAE,OAAS,EAAKA,EAAe,KAChE,OAAA,KAAK,MAAM,cAAe,CAAE,UAAW,WAAW,CAAE,EAC7CiH,CACT,OAAS3J,EAAO,CACd,MAAA,KAAK,aAAa,mBAAoBA,CAAc,EAC9CA,CACR,CACF,CAKA,MAAM,QACJiC,EAAkC,CAAA,EAClC7C,EAAuB,CAAA,EAAE,CAEzB,MAAM,KAAK,qBAEX,GAAI,CAGF,MAAMwK,EAAY,CAAC,GADS,KAAK,qBAAqB3H,CAAU,EACrB,GAAI7C,EAAQ,OAAS,CAAA,CAAG,EAE7DkD,EAAyB,CAC7B,KAAM,KAAK,UACX,KAAMlD,EAAQ,QAAUA,EAAQ,QAAQ,IAAKyK,IAAU,CAAE,KAAAA,CAAI,EAAG,EAAI,CAAA,EACpE,OAAQD,EACR,SAAUxK,EAAQ,QAClB,YAAa,CACX,MAAOA,EAAQ,MACf,OAAQA,EAAQ,MACjB,GAGG0K,EAAU,MAAM,KAAK,IAAK,UAAUxH,CAAU,EACpD,OAAA,KAAK,MAAM,cAAe,CACxB,UAAW,UACX,MAAOwH,EAAQ,MAChB,CAAA,EACMA,CACT,OAAS9J,EAAO,CACd,WAAK,aAAa,iBAAkBA,CAAc,EAC5CA,CACR,CACF,CAKA,MAAM,MAAMkC,EAA2C,CACrD,MAAM,KAAK,mBAAA,EAEX,GAAI,CACF,IAAI6H,EAAiC,CAAA,EAEjC,MAAM,QAAQ7H,CAAK,EACrB6H,EAAkB7H,EACTA,GAAS,OAAOA,GAAU,WACnC6H,EAAkB,KAAK,qBAAqB7H,CAAK,GAGnD,MAAMI,EAAyB,CAC7B,KAAM,KAAK,UACX,KAAM,CAAC,CAAE,KAAM,oBAAqB,EACpC,OAAQyH,GAIV,OADe,MAAM,KAAK,IAAK,OAAOzH,CAAU,GAClC,OAAS,CACzB,OAAStC,EAAO,CACd,MAAA,KAAK,aAAa,cAAeA,CAAc,EACzCA,CACR,CACF,CAKA,MAAM,OAAOwJ,EAAO,CAElB,OADa,MAAM,KAAK,SAASA,CAAE,IACnB,IAClB,CAKA,MAAM,UAAQ,CACZ,MAAM,KAAK,qBAEX,GAAI,CACF,MAAM,KAAK,IAAK,QAAQ,eAAe,KAAK,SAAS,EAAE,EACvD,MAAM,KAAK,IAAK,QACd,2CAA2C,KAAK,SAAS,GAAG,EAE9D,KAAK,MAAM,iBAAkB,CAAE,UAAW,KAAK,SAAS,CAAE,CAC5D,OAASxJ,EAAO,CACd,MAAA,KAAK,aAAa,iBAAkBA,CAAc,EAC5CA,CACR,CACF,CAKA,MAAM,WAAWgK,EAAmB,CAClC,MAAM,KAAK,mBAAA,EAEX,GAAI,CACF,GAAI,CAAC,MAAM,QAAQA,CAAK,GAAKA,EAAM,SAAW,EAC5C,MAAM,IAAI,MAAM,iCAAiC,EAGnD,MAAMtH,EAAS,MAAM,KAAK,IAAK,WAAW,CACxC,UAAW,KAAK,UAChB,KAAMsH,EACN,UAAW,IACX,WAAY,GACZ,aAAc,EACf,CAAA,EAED,YAAK,MAAM,kBAAmB,CAC5B,UAAW,aACX,MAAOtH,EAAO,WACf,CAAA,EACMA,CACT,OAAS1C,EAAO,CACd,MAAA,KAAK,aAAa,oBAAqBA,CAAc,EAC/CA,CACR,CACF,CAKA,MAAM,WAAWiK,EAAgC,CAC/C,MAAM,KAAK,qBAEX,GAAI,CACF,GAAI,CAAC,MAAM,QAAQA,CAAS,GAAKA,EAAU,SAAW,EACpD,MAAM,IAAI,MAAM,gCAAgC,EAGlD,MAAMH,EAAe,CAAA,EACrB,aAAM,KAAK,mBAAmB,SAAW,CACvC,UAAWvG,KAAQ0G,EAAW,CAC5B,KAAK,cAAc1G,CAAI,EACvB,MAAMjB,EAAa,KAAK,eAAeiB,CAAI,EAC3C,MAAM,KAAK,IAAK,OAAOjB,CAAU,EACjCwH,EAAQ,KAAKvG,CAAS,CACxB,CACF,CAAC,EAED,KAAK,MAAM,kBAAmB,CAC5B,UAAW,aACX,MAAOuG,EAAQ,MAChB,CAAA,EACMA,CACT,OAAS9J,EAAO,CACd,MAAA,KAAK,aAAa,oBAAqBA,CAAc,EAC/CA,CACR,CACF,CAKA,MAAM,mBAAmBgI,EAA4B,CACnD,MAAM,KAAK,qBAEX,GAAI,CACF,MAAM,KAAK,IAAK,mBAChB,MAAMtF,EAAS,MAAMsF,IACrB,OAAA,MAAM,KAAK,IAAK,kBAAA,EAChB,KAAK,MAAM,uBAAwB,CAAE,UAAW,aAAa,CAAE,EACxDtF,CACT,OAAS1C,EAAO,CACd,GAAI,CACF,MAAM,KAAK,IAAK,oBAAA,CAClB,OAASkK,EAAe,CACtB,KAAK,aAAa,iBAAkBA,CAAsB,CAC5D,CACA,WAAK,aAAa,oBAAqBlK,CAAc,EAC/CA,CACR,CACF,CAKA,MAAM,cACJ6D,EACAzE,EAI6B,CAAA,EAAE,CAE/B,MAAM,KAAK,qBAEX,GAAI,CACF,MAAMsD,EAAS,MAAM,KAAK,IAAK,cAC7B,KAAK,UACLmB,EACAzE,CAAO,EAET,OAAA,KAAK,MAAM,eAAgB,CAAE,UAAW,gBAAiB,OAAAsD,CAAM,CAAE,EAC1DA,CACT,OAAS1C,EAAO,CACd,MAAA,KAAK,aAAa,mBAAoBA,CAAc,EAC9CA,CACR,CACF,CAKA,MAAM,sBACJuD,EACAC,EACApE,EAAkC,CAAA,EAAE,CAEpC,MAAM,KAAK,qBAEX,GAAI,CACF,MAAMsD,EAAS,MAAM,KAAK,IAAK,sBAC7B,KAAK,UACLa,EACAC,EACApE,CAAO,EAET,YAAK,MAAM,eAAgB,CAAE,UAAW,oBAAqB,OAAAsD,CAAM,CAAE,EAC9DA,CACT,OAAS1C,EAAO,CACd,MAAA,KAAK,aAAa,uBAAwBA,CAAc,EAClDA,CACR,CACF,CAGU,iBACRiC,EAAkC,CAAA,EAClC7C,EAAuB,CAAA,EAAE,CAEzB,MAAMkD,EAAyB,CAC7B,KAAM,KAAK,UACX,KAAM,CAAA,EACN,OAAQ,GACR,SAAUlD,EAAQ,SAAW,CAAA,EAC7B,YAAa,CAAA,GAGf,OAAIA,EAAQ,SAAWA,EAAQ,QAAQ,OAAS,IAC9CkD,EAAW,KAAOlD,EAAQ,QAAQ,IAAKyK,IAAU,CAAE,KAAAA,CAAI,EAAG,GAGxD5H,GAAc,OAAO,KAAKA,CAAU,EAAE,OAAS,IACjDK,EAAW,OAAS,OAAO,QAAQL,CAAU,EAAE,IAAI,CAAC,CAACM,EAAKC,CAAK,KAAO,CACpE,KAAMD,EACN,MAAAC,EACA,SAAU,GACX,EAAC,GAGApD,EAAQ,QAAU,SACpBkD,EAAW,YAAa,MAAQlD,EAAQ,OAEtCA,EAAQ,SAAW,SACrBkD,EAAW,YAAa,OAASlD,EAAQ,QAGpCkD,CACT,CAEU,eAAeiB,EAAyB,CAChD,OAAO,KAAK,IAAK,wBACf,KAAK,UACLA,EACA,KAAK,gBAAgB,CAEzB,CAEU,qBAAqB4G,EAAwB,CACrD,OAAO,OAAO,QAAQA,CAAG,EACtB,OAAO,CAAC,CAAC7F,EAAG9B,CAAK,IAAMA,IAAU,MAAS,EAC1C,IAAI,CAAC,CAACD,EAAKC,CAAK,KAAO,CAAE,KAAMD,EAAK,MAAAC,CAAK,EAAG,CACjD,CAGA,GAAG4H,EAAeC,EAAqB,CACrC,OAAK,KAAK,eAAe,IAAID,CAAK,GAChC,KAAK,eAAe,IAAIA,EAAO,CAAA,CAAE,EAEnC,KAAK,eAAe,IAAIA,CAAK,EAAG,KAAKC,CAAO,EACrC,IACT,CAEA,IAAID,EAAeC,EAAqB,CACtC,MAAMC,EAAW,KAAK,eAAe,IAAIF,CAAK,EAC9C,GAAIE,EAAU,CACZ,MAAMzJ,EAAQyJ,EAAS,QAAQD,CAAO,EAClCxJ,EAAQ,IACVyJ,EAAS,OAAOzJ,EAAO,CAAC,CAE5B,CACA,OAAO,IACT,CAEU,MAAMuJ,EAAe7G,EAAS,CACtC,MAAM+G,EAAW,KAAK,eAAe,IAAIF,CAAK,EAC1CE,GACFA,EAAS,QAASD,GAAW,CAC3B,GAAI,CACFA,EAAQ9G,CAAI,CACd,OAASvD,EAAO,CAEhB,CACF,CAAC,CAEL,CAGA,gBAAgBuK,EAAmBF,EAAqB,CACtD,YAAK,cAAc,IAAIE,EAAWF,CAAO,EAClC,IACT,CAEU,aAAaE,EAAmBvK,EAAY,CACpD,MAAMqK,EAAU,KAAK,cAAc,IAAIE,CAAS,EAChD,GAAIF,EACF,GAAI,CACFA,EAAQrK,CAAK,CACf,OAASwK,EAAc,CAEvB,CAEF,KAAK,MAAM,QAAS,CAAE,UAAAD,EAAW,MAAAvK,CAAK,CAAE,CAC1C,CAEU,cAAcuD,EAAS,CAC/B,GAAI,CAACA,GAAQ,OAAOA,GAAS,SAC3B,MAAM,IAAI,MAAM,6BAA6B,CAEjD,CAEU,MAAM,oBAAkB,CAC3B,KAAK,eACR,MAAM,KAAK,KAAA,CAEf,CAEQ,MAAM,uBAAqB,OACjC,GAAI,CACkBlE,GAAAA,EAAA,KAAK,OAAG,MAAAA,IAAA,SAAAA,EAAE,iBAAA,IAE5B,KAAK,IAAM,MAAMgH,EAAgB,yBAC/B,KAAK,UAAU,EAGrB,OAASrG,EAAO,CACd,KAAK,IAAM,MAAMqG,EAAgB,yBAC/B,KAAK,UAAU,CAEnB,CACF,CAGA,MAAM,iBAAe,CACnB,OAAA,MAAM,KAAK,qBACJ,MAAM,KAAK,IAAK,iBACzB,CAEA,MAAM,cAAY,CAChB,OAAA,MAAM,KAAK,qBACJ,MAAM,KAAK,IAAK,aAAa,KAAK,SAAS,CACpD,CAEA,WAAS,CACP,MAAO,CACL,WAAY,KAAK,WACjB,UAAU,KAAK,UACf,SAAU,KAAK,SACf,cAAe,KAAK,cACpB,OAAQ,CAAC,CAAC,KAAK,IAEnB,CAEA,MAAM,aAAW,CACf,GAAI,CACF,MAAM,KAAK,mBAAA,EACX,MAAMoE,EAAQ,MAAM,KAAK,QACzB,MAAO,CACL,QAAS,GACT,WAAY,KAAK,WACjB,YAAaA,EACb,UAAW,IAAI,KAAA,EAAO,YAAA,EAE1B,OAASzK,EAAO,CACd,MAAO,CACL,QAAS,GACT,WAAY,KAAK,WACjB,MAAQA,EAAgB,QACxB,UAAW,IAAI,KAAA,EAAO,YAAA,EAE1B,CACF,CAGA,MAAM,OAAK,CACT,GAAI,CACF,OAAI,KAAK,KACP,MAAM,KAAK,IAAI,MAAA,EAGjB,KAAK,SAAW,GAChB,KAAK,cAAgB,GACrB,KAAK,eAAe,MAAA,EACpB,KAAK,cAAc,QACnB,KAAK,MAAM,QAEX,KAAK,MAAM,SAAU,CAAE,WAAY,KAAK,UAAU,CAAE,EAC7C,EACT,OAASA,EAAO,CACd,MAAA,KAAK,aAAa,cAAeA,CAAc,EACzCA,CACR,CACF,CAEO,SAAO,CAEZqG,EAAgB,qBACd,KAAK,WACL,KAAK,gBAAgB,EAIvB,KAAK,eAAe,MAAA,EACpB,KAAK,cAAc,QACnB,KAAK,MAAM,MAAA,CACb,CAGA,MAAM,OACJpE,EAAkC,GAClC7C,EAAuB,CAAA,EAAE,CAEzB,OAAO,KAAK,QAAQ6C,EAAY7C,CAAO,CACzC,CAEA,MAAM,QAAQoK,EAAmB,CAC/B,OAAO,KAAK,SAASA,CAAE,CACzB,CAEA,MAAM,SAASvH,EAAkC,CAAA,EAAE,CACjD,OAAO,KAAK,UAAUA,CAAU,CAClC,CACD,OC5pBYyI,CAAY,CAgBvB,YAAY7E,EAAkB,CAftB,KAAA,UAAY,GACZ,KAAA,aAAyB,CAAC,GAAG,EAC7B,KAAA,YAA4B,CAAA,EAC5B,KAAA,gBAAoC,CAAA,EACpC,KAAA,cAA0B,CAAA,EAC1B,KAAA,iBAAqC,CAAA,EACrC,KAAA,cAA0B,GAC1B,KAAA,WAA4B,KAC5B,KAAA,YAA6B,KAC7B,KAAA,OAAgB,CAAA,EAChB,KAAA,aAA+B,CAAA,EAC/B,KAAA,WAAyB,CAAA,EACzB,KAAA,WAAwC,IAAI,IAC5C,KAAA,IAA2B,KAGjC,KAAK,IAAMA,GAAO,IACpB,CAEA,OAAO,MAAMgE,EAAchE,EAAkB,CAC3C,MAAM8E,EAAU,IAAID,EAAa7E,CAAG,EACpC,OAAA8E,EAAQ,UAAYd,EACbc,CACT,CAEA,OAAO,KAAKd,EAAchE,EAAkB,CAC1C,OAAO6E,EAAa,MAAMb,EAAMhE,CAAG,CACrC,CAGA,OAAOuD,EAAyB,CAC9B,OAAA,KAAK,aAAe,MAAM,QAAQA,CAAM,EAAIA,EAAS,CAACA,CAAM,EACrD,IACT,CAEA,UAAUwB,EAAW,CACnB,YAAK,aAAe,CAACA,CAAG,EACjB,IACT,CAEA,eAAexB,EAAyB,CACtC,MAAMyB,EAAY,MAAM,QAAQzB,CAAM,EAAIA,EAAO,KAAK,IAAI,EAAIA,EAC9D,OAAA,KAAK,aAAe,CAAC,YAAYyB,CAAS,EAAE,EACrC,IACT,CAGA,KAAKxK,EAAeyK,EAAmB7F,EAA2B,QAAO,CACvE,OAAA,KAAK,YAAY,KAAK,CAAE,KAAAA,EAAM,MAAA5E,EAAO,UAAAyK,CAAS,CAAE,EACzC,IACT,CAEA,UAAUzK,EAAeyK,EAAiB,CACxC,OAAO,KAAK,KAAKzK,EAAOyK,EAAW,OAAO,CAC5C,CAEA,SAASzK,EAAeyK,EAAiB,CACvC,OAAO,KAAK,KAAKzK,EAAOyK,EAAW,MAAM,CAC3C,CAEA,UAAUzK,EAAeyK,EAAiB,CACxC,OAAO,KAAK,KAAKzK,EAAOyK,EAAW,OAAO,CAC5C,CAEA,cAAczK,EAAeyK,EAAiB,CAC5C,OAAO,KAAK,KAAKzK,EAAOyK,EAAW,YAAY,CACjD,CAMA,MAAMC,EAAiDC,EAAgCxI,EAAW,CAChG,GAAI,OAAOuI,GAAsB,SAE/B,cAAO,QAAQA,CAAiB,EAAE,QAAQ,CAAC,CAACE,EAAOC,CAAG,IAAK,CACzD,KAAK,gBAAgB,KAAK,CAAE,MAAAD,EAAO,SAAU,IAAK,MAAOC,CAAG,CAAE,CAChE,CAAC,EACM,KAGT,IAAI/I,EAAW,IACXgJ,EAAcH,EAElB,OAAI,UAAU,SAAW,IACvB7I,EAAW6I,EACXG,EAAc3I,GAGhB,KAAK,gBAAgB,KAAK,CACxB,MAAOuI,EACP,SAAA5I,EACA,MAAOgJ,CACR,CAAA,EAEM,IACT,CAEA,YAAYF,EAAezI,EAAU,CACnC,OAAO,KAAK,MAAMyI,EAAO,IAAKzI,CAAK,CACrC,CAEA,SAASyI,EAAezI,EAAU,CAChC,OAAO,KAAK,MAAMyI,EAAO,KAAMzI,CAAK,CACtC,CAEA,UAAUyI,EAAezI,EAAa,CACpC,OAAO,KAAK,MAAMyI,EAAO,OAAQzI,CAAK,CACxC,CAEA,aAAayI,EAAezI,EAAa,CACvC,OAAO,KAAK,MAAMyI,EAAO,WAAYzI,CAAK,CAC5C,CAEA,QAAQyI,EAAe1G,EAAa,CAClC,OAAA,KAAK,gBAAgB,KAAK,CAAE,MAAA0G,EAAO,SAAU,KAAM,MAAO1G,CAAM,CAAE,EAC3D,IACT,CAEA,WAAW0G,EAAe1G,EAAa,CACrC,OAAA,KAAK,gBAAgB,KAAK,CAAE,MAAA0G,EAAO,SAAU,SAAU,MAAO1G,CAAM,CAAE,EAC/D,IACT,CAEA,aAAa0G,EAAeG,EAAUC,EAAQ,CAC5C,OAAA,KAAK,gBAAgB,KAAK,CAAE,MAAAJ,EAAO,SAAU,UAAW,MAAO,CAACG,EAAKC,CAAG,CAAC,CAAE,EACpE,IACT,CAEA,gBAAgBJ,EAAeG,EAAUC,EAAQ,CAC/C,YAAK,gBAAgB,KAAK,CAAE,MAAAJ,EAAO,SAAU,cAAe,MAAO,CAACG,EAAKC,CAAG,CAAC,CAAE,EACxE,IACT,CAEA,UAAUJ,EAAa,CACrB,YAAK,gBAAgB,KAAK,CAAE,MAAAA,EAAO,SAAU,UAAW,MAAO,IAAI,CAAE,EAC9D,IACT,CAEA,aAAaA,EAAa,CACxB,OAAA,KAAK,gBAAgB,KAAK,CAAE,MAAAA,EAAO,SAAU,cAAe,MAAO,IAAI,CAAE,EAClE,IACT,CAEA,YAAYK,EAAsB,CAChC,OAAA,KAAK,gBAAgB,KAAK,CACxB,MAAO,GACP,SAAU,SACV,MAAOA,CACR,CAAA,EACM,IACT,CAEA,eAAeA,EAAsB,CACnC,OAAA,KAAK,gBAAgB,KAAK,CACxB,MAAO,GACP,SAAU,aACV,MAAOA,CACR,CAAA,EACM,IACT,CAKA,QAAQL,EAAeD,EAAgCxI,EAAW,CAGhE,OAAO,KAAK,MAAMyI,EAAOD,EAA2BxI,CAAK,CAC3D,CAGA,QAAQ4G,EAAyB,CAC/B,OAAA,KAAK,cAAgB,MAAM,QAAQA,CAAM,EAAIA,EAAS,CAACA,CAAM,EACtD,IACT,CAEA,OAAO6B,EAAe9I,EAAkBK,EAAW,CACjD,IAAI+I,EAAiB,IACjBJ,EAAchJ,EAElB,OAAI,UAAU,SAAW,IACvBoJ,EAAiBpJ,EACjBgJ,EAAc3I,GAGhB,KAAK,iBAAiB,KAAK,CACzB,MAAAyI,EACA,SAAUM,EACV,MAAOJ,CACR,CAAA,EACM,IACT,CAEA,YAAYF,EAAe9I,EAAkBK,EAAa,CACxD,OAAO,KAAK,OAAO,SAASyI,CAAK,IAAK9I,EAAUK,CAAK,CACvD,CAGA,QAAQyI,EAAeO,EAA4B,MAAK,CACtD,OAAA,KAAK,cAAc,KAAK,GAAGP,CAAK,IAAIO,CAAS,EAAE,EACxC,IACT,CAEA,YAAYP,EAAa,CACvB,OAAO,KAAK,QAAQA,EAAO,MAAM,CACnC,CAEA,WAAWL,EAAW,CACpB,OAAA,KAAK,cAAc,KAAKA,CAAG,EACpB,IACT,CAEA,OAAOK,EAAgB,aAAY,CACjC,OAAO,KAAK,YAAYA,CAAK,CAC/B,CAEA,OAAOA,EAAgB,aAAY,CACjC,OAAO,KAAK,QAAQA,EAAO,KAAK,CAClC,CAGA,MAAMR,EAAa,CACjB,OAAA,KAAK,WAAaA,EACX,IACT,CAEA,OAAOA,EAAa,CAClB,OAAA,KAAK,YAAcA,EACZ,IACT,CAEA,KAAKA,EAAa,CAChB,OAAO,KAAK,OAAOA,CAAK,CAC1B,CAEA,KAAKA,EAAa,CAChB,OAAO,KAAK,MAAMA,CAAK,CACzB,CAEA,UAAQ,CACN,OAAO,KAAK,MAAM,CAAC,CACrB,CAEA,SAASgB,EAAcC,EAAe,CACpC,OAAA,KAAK,WAAaA,EAClB,KAAK,aAAeD,EAAO,GAAKC,EACzB,IACT,CAGA,MAAMC,EAAmB,CACvB,OAAA,KAAK,aAAa,KAAKA,CAAK,EACrB,IACT,CAEA,SAASA,EAAmB,CAE1B,OAAO,KAAK,MAAMA,CAAK,CACzB,CAGA,KAAKC,EAAeD,EAAmB,CACrC,OAAA,KAAK,WAAW,IAAIC,EAAOD,CAAK,EACzB,IACT,CAGA,cAAcV,EAAe9I,EAAkBmJ,EAAsB,CACnE,OAAA,KAAK,WAAW,KAAK,CAAE,MAAOA,EAAU,MAAO,EAAE,CAAE,EACnD,KAAK,gBAAgB,KAAK,CAAE,MAAAL,EAAO,SAAA9I,EAAU,MAAOmJ,CAAQ,CAAE,EACvD,IACT,CAGA,MAAML,EAAgB,IAAG,CACvB,OAAA,KAAK,aAAe,CAAC,SAASA,CAAK,YAAY,EACxC,IACT,CAEA,IAAIA,EAAa,CACf,YAAK,aAAe,CAAC,OAAOA,CAAK,UAAU,EACpC,IACT,CAEA,IAAIA,EAAa,CACf,OAAA,KAAK,aAAe,CAAC,OAAOA,CAAK,UAAU,EACpC,IACT,CAEA,IAAIA,EAAa,CACf,OAAA,KAAK,aAAe,CAAC,OAAOA,CAAK,UAAU,EACpC,IACT,CAEA,IAAIA,EAAa,CACf,OAAA,KAAK,aAAe,CAAC,OAAOA,CAAK,UAAU,EACpC,IACT,CAGA,OAAK,CACH,IAAItK,EAAM,GACV,MAAMS,EAAgB,CAAA,EAGtB,GAAI,KAAK,WAAW,KAAO,EAAG,CAC5B,MAAMyK,EAAoB,CAAA,EAC1B,KAAK,WAAW,QAAQ,CAACF,EAAOC,IAAS,CACvC,KAAM,CAAE,IAAKE,EAAQ,OAAQC,CAAS,EAAKJ,EAAM,QACjDE,EAAQ,KAAK,GAAGD,CAAK,QAAQE,CAAM,GAAG,EACtC1K,EAAO,KAAK,GAAG2K,CAAS,CAC1B,CAAC,EACDpL,GAAO,QAAQkL,EAAQ,KAAK,IAAI,CAAC,GACnC,CAaA,GAVAlL,GAAO,UAAU,KAAK,aAAa,KAAK,IAAI,CAAC,SAAS,KAAK,SAAS,GAGhE,KAAK,YAAY,OAAS,GAC5B,KAAK,YAAY,QAAQqL,GAAO,CAC9BrL,GAAO,IAAIqL,EAAK,IAAI,SAASA,EAAK,KAAK,OAAOA,EAAK,SAAS,EAC9D,CAAC,EAIC,KAAK,gBAAgB,OAAS,EAAG,CACnC,MAAM/J,EAAuB,CAAA,EAC7B,KAAK,gBAAgB,QAAQ6I,GAAY,CACvC,KAAM,CAAE,OAAA9I,EAAQ,gBAAAiK,CAAe,EAAK,KAAK,eAAenB,CAAS,EACjE7I,EAAW,KAAKD,CAAM,EACtBZ,EAAO,KAAK,GAAG6K,CAAe,CAChC,CAAC,EACDtL,GAAO,UAAUsB,EAAW,KAAK,OAAO,CAAC,EAC3C,CAQA,GALI,KAAK,cAAc,OAAS,IAC9BtB,GAAO,aAAa,KAAK,cAAc,KAAK,IAAI,CAAC,IAI/C,KAAK,iBAAiB,OAAS,EAAG,CACpC,MAAMsB,EAAuB,CAAA,EAC7B,KAAK,iBAAiB,QAAQ6I,GAAY,CACxC,KAAM,CAAE,OAAA9I,EAAQ,gBAAAiK,CAAe,EAAK,KAAK,eAAenB,CAAS,EACjE7I,EAAW,KAAKD,CAAM,EACtBZ,EAAO,KAAK,GAAG6K,CAAe,CAChC,CAAC,EACDtL,GAAO,WAAWsB,EAAW,KAAK,OAAO,CAAC,EAC5C,CAGA,OAAI,KAAK,cAAc,OAAS,IAC9BtB,GAAO,aAAa,KAAK,cAAc,KAAK,IAAI,CAAC,IAI/C,KAAK,aAAe,OACtBA,GAAO,UAAU,KAAK,UAAU,IAI9B,KAAK,cAAgB,OACvBA,GAAO,WAAW,KAAK,WAAW,IAIhC,KAAK,aAAa,OAAS,GAC7B,KAAK,aAAa,QAAQuL,GAAa,CACrC,KAAM,CAAE,IAAKC,EAAU,OAAQC,CAAW,EAAKF,EAAW,MAAA,EAC1DvL,GAAO,UAAUwL,CAAQ,GACzB/K,EAAO,KAAK,GAAGgL,CAAW,CAC5B,CAAC,EAGI,CAAE,IAAAzL,EAAK,OAAAS,EAChB,CAEQ,eAAe0J,EAAyB,CAC9C,KAAM,CAAE,MAAAG,EAAO,SAAA9I,EAAU,MAAAK,CAAK,EAAKsI,EAC7B1J,EAAgB,GAEtB,OAAQe,EAAS,cAAW,CAC1B,IAAK,KACL,IAAK,SACH,MAAMhB,EAAgBqB,EAAgB,IAAI,IAAM,GAAG,EAAE,KAAK,IAAI,EAC9D,OAAApB,EAAO,KAAK,GAAIoB,CAAe,EACxB,CACL,OAAQ,GAAGyI,CAAK,IAAI9I,CAAQ,KAAKhB,CAAY,IAC7C,gBAAiBC,GAGrB,IAAK,UACL,IAAK,cACH,OAAAA,EAAO,KAAKoB,EAAM,CAAC,EAAGA,EAAM,CAAC,CAAC,EACvB,CACL,OAAQ,GAAGyI,CAAK,IAAI9I,CAAQ,WAC5B,gBAAiBf,GAGrB,IAAK,UACL,IAAK,cACH,MAAO,CACL,OAAQ,GAAG6J,CAAK,IAAI9I,CAAQ,GAC5B,gBAAiB,IAGrB,IAAK,SACL,IAAK,aACH,KAAM,CAAE,IAAKkK,EAAQ,OAAQC,CAAS,EAAM9J,EAAuB,QACnE,OAAApB,EAAO,KAAK,GAAGkL,CAAS,EACjB,CACL,OAAQ,GAAGnK,CAAQ,KAAKkK,CAAM,IAC9B,gBAAiBjL,GAGrB,QACE,GAAIoB,aAAiBkI,EAAc,CACjC,KAAM,CAAE,IAAK2B,EAAQ,OAAQC,CAAS,EAAK9J,EAAM,MAAA,EACjD,OAAApB,EAAO,KAAK,GAAGkL,CAAS,EACjB,CACL,OAAQ,GAAGrB,CAAK,IAAI9I,CAAQ,KAAKkK,CAAM,IACvC,gBAAiBjL,EAErB,CACA,OAAAA,EAAO,KAAKoB,CAAK,EACV,CACL,OAAQ,GAAGyI,CAAK,IAAI9I,CAAQ,KAC5B,gBAAiBf,EAEvB,CACF,CAGA,MAAM,KAAG,CACP,GAAI,CAAC,KAAK,IACR,MAAM,IAAI,MAAM,2CAA2C,EAE7D,KAAM,CAAE,IAAAT,EAAK,OAAAS,CAAM,EAAK,KAAK,MAAA,EAE7B,OADe,MAAM,KAAK,IAAI,QAAQT,EAAKS,CAAM,GACnC,IAChB,CAEA,MAAM,OAAK,CACT,KAAK,MAAM,CAAC,EACZ,MAAM0I,EAAU,MAAM,KAAK,MAC3B,OAAOA,EAAQ,OAAS,EAAIA,EAAQ,CAAC,EAAI,IAC3C,CAEA,MAAM,MAAMyC,EAAc,CACxB,OAAA,KAAK,OAAOA,CAAM,GACF,MAAM,KAAK,OACZ,IAAI7I,GAAOA,EAAI6I,CAAM,CAAC,CACvC,CAEA,MAAM,QAAM,CACV,OAAA,KAAK,OAAO,GAAG,EAAE,MAAM,CAAC,GACR,MAAM,KAAK,IAAA,GACZ,OAAS,CAC1B,CAEA,MAAM,aAAW,CACf,KAAK,QACL,MAAM7J,EAAS,MAAM,KAAK,QAC1B,OAAOA,EAASA,EAAO,MAAQ,CACjC,CAGA,OAAO,OAAOzC,EAAmBsD,EAAyB,CACxD,MAAM6F,EAAS,OAAO,KAAK7F,CAAI,EACzBgB,EAAS,OAAO,OAAOhB,CAAI,EAC3BpC,EAAeoD,EAAO,IAAI,IAAM,GAAG,EAAE,KAAK,IAAI,EAEpD,MAAO,CACL,IAAK,eAAetE,CAAS,KAAKmJ,EAAO,KAAK,IAAI,CAAC,aAAajI,CAAY,IAC5E,OAAQoD,EAEZ,CAEA,OAAO,WAAWtE,EAAmBgK,EAAgC,CACnE,GAAIA,EAAU,SAAW,EACvB,MAAM,IAAI,MAAM,4BAA4B,EAG9C,MAAMb,EAAS,OAAO,KAAKa,EAAU,CAAC,CAAC,EACjC9I,EAAeiI,EAAO,IAAI,IAAM,GAAG,EAAE,KAAK,IAAI,EAC9CoD,EAAcvC,EAAU,IAAI,IAAM,IAAI9I,CAAY,GAAG,EAAE,KAAK,IAAI,EAEhEuE,EAAYuE,EAAU,QAAQ1G,GAAQ,OAAO,OAAOA,CAAI,CAAC,EAE/D,MAAO,CACL,IAAK,eAAetD,CAAS,KAAKmJ,EAAO,KAAK,IAAI,CAAC,YAAYoD,CAAW,GAC1E,OAAQ9G,EAEZ,CAEA,OAAO,OAAOzF,EAAmBsD,EAA2BrB,EAAeuK,EAAqB,GAAE,CAChG,MAAMC,EAAO,OAAO,KAAKnJ,CAAI,EAAE,IAAIhB,GAAO,GAAGA,CAAG,MAAM,EAAE,KAAK,IAAI,EAC3DnB,EAAS,CAAC,GAAG,OAAO,OAAOmC,CAAI,EAAG,GAAGkJ,CAAW,EAEtD,MAAO,CACL,IAAK,UAAUxM,CAAS,QAAQyM,CAAI,UAAUxK,CAAK,GACnD,OAAAd,EAEJ,CAEA,OAAO,OAAOnB,EAAmBiC,EAAeuK,EAAqB,CAAA,EAAE,CACrE,MAAO,CACL,IAAK,eAAexM,CAAS,UAAUiC,CAAK,GAC5C,OAAQuK,EAEZ,CAEA,OAAO,OAAOxM,EAAmBsD,EAA2B8B,EAAyB,CACnF,MAAM+D,EAAS,OAAO,KAAK7F,CAAI,EACzBgB,EAAS,OAAO,OAAOhB,CAAI,EAC3BpC,EAAeoD,EAAO,IAAI,IAAM,GAAG,EAAE,KAAK,IAAI,EAE9Ce,EAAgB8D,EAAO,OAAO6B,GAAS,CAAC5F,EAAgB,SAAS4F,CAAK,CAAC,EACvE0B,EAAerH,EAAc,OAAS,EACxCA,EAAc,IAAI7F,GAAO,GAAGA,CAAG,eAAeA,CAAG,EAAE,EAAE,KAAK,IAAI,EAC9D,GAEJ,IAAIkB,EAAM,eAAeV,CAAS,KAAKmJ,EAAO,KAAK,IAAI,CAAC,aAAajI,CAAY,IAEjF,OAAImE,EAAc,OAAS,EACzB3E,GAAO,gBAAgB0E,EAAgB,KAAK,IAAI,CAAC,mBAAmBsH,CAAY,GAEhFhM,GAAO,gBAAgB0E,EAAgB,KAAK,IAAI,CAAC,eAG5C,CAAE,IAAA1E,EAAK,OAAQ4D,EACxB,CAGA,OAAK,CACH,GAAI,CAAC,KAAK,IAAK,MAAM,IAAI,MAAM,gDAAgD,EAC/E,MAAMqI,EAAS,IAAIlC,EAAa,KAAK,GAAG,EACxC,OAAAkC,EAAO,UAAY,KAAK,UACxBA,EAAO,aAAe,CAAC,GAAG,KAAK,YAAY,EAC3CA,EAAO,YAAc,CAAC,GAAG,KAAK,WAAW,EACzCA,EAAO,gBAAkB,CAAC,GAAG,KAAK,eAAe,EACjDA,EAAO,cAAgB,CAAC,GAAG,KAAK,aAAa,EAC7CA,EAAO,iBAAmB,CAAC,GAAG,KAAK,gBAAgB,EACnDA,EAAO,cAAgB,CAAC,GAAG,KAAK,aAAa,EAC7CA,EAAO,WAAa,KAAK,WACzBA,EAAO,YAAc,KAAK,YAC1BA,EAAO,aAAe,CAAC,GAAG,KAAK,YAAY,EAC3CA,EAAO,WAAa,CAAC,GAAG,KAAK,UAAU,EACvCA,EAAO,WAAa,IAAI,IAAI,KAAK,UAAU,EACpCA,CACT,CAEA,UAAQ,CACN,KAAM,CAAE,IAAAjM,EAAK,OAAAS,CAAM,EAAK,KAAK,MAAA,EAC7B,IAAIyL,EAASlM,EACb,OAAAS,EAAO,QAAQ0L,GAAQ,CACjB,OAAOA,GAAU,SACnBD,EAASA,EAAO,QAAQ,IAAK,IAAIC,EAAM,QAAQ,KAAM,IAAI,CAAC,GAAG,EACpDA,GAAU,KACnBD,EAASA,EAAO,QAAQ,IAAK,MAAM,EAEnCA,EAASA,EAAO,QAAQ,IAAK,OAAOC,CAAK,CAAC,CAE9C,CAAC,EACMD,CACT,CAEA,SAAO,CACL,OAAA,KAAK,aAAe,CAAC,sBAAwB,KAAK,aAAa,KAAK,IAAI,CAAC,EAClE,IACT,CACD,CCllBK,MAAOE,UAAuB9D,CAAW,CAAA,OAkDlC+D,CAAc,CAezB,aAAA,CAXQ,KAAA,SAAqC,IAAI,IACzC,KAAA,eAA6C,IAAI,IACjD,KAAA,gBAA6E,IAAI,IAGjF,KAAA,cAA2D,IAAI,IAG/D,KAAA,eAAiB,GACjB,KAAA,gBAAyC,KAG/C,KAAK,YAAA,EACL,KAAK,qBAAA,CACP,CAKO,OAAO,aAAW,CACvB,OAAKA,EAAe,WAClBA,EAAe,SAAW,IAAIA,GAEzBA,EAAe,QACxB,CAKO,OAAO,eAAa,CACrBA,EAAe,WACjBA,EAAe,SAAS,QAAA,EACxBA,EAAe,SAAW,KAE9B,CAEQ,aAAW,CACD,OAAO,oBAAoB,OAAO,eAAe,IAAI,CAAC,EAC9D,QAAQ7D,GAAS,CACnB,OAAQ,KAAaA,CAAM,GAAM,YAAcA,IAAW,gBAC3D,KAAaA,CAAM,EAAK,KAAaA,CAAM,EAAE,KAAK,IAAI,EAE3D,CAAC,CACH,CAKQ,iBAAiBpB,EAAoB9H,EAAiB,CAC5D,MAAO,GAAG8H,CAAU,IAAI9H,CAAS,EACnC,CAKQ,sBAAsBV,EAAqB,SACjD,GAAI,EAAC,GAAAF,EAAAE,EAAO,cAAU,MAAAF,IAAA,SAAAA,EAAE,QACtB,MAAM,IAAI,MAAM,6CAA6C,EAE/D,GAAI,EAAC,GAAAC,EAAAC,EAAO,aAAS,MAAAD,IAAA,SAAAA,EAAE,KAAA,GACrB,MAAM,IAAI,MAAM,4CAA4C,CAEhE,CAKO,gBAAgBC,EAAqB,CAC1C,KAAK,sBAAsBA,CAAM,EAEjC,MAAM0N,EAAa,KAAK,iBAAiB1N,EAAO,WAAYA,EAAO,SAAS,EAGtE2N,EAAkC,CACtC,WAAY3N,EAAO,WAAW,OAC9B,UAAWA,EAAO,UAAU,OAC5B,iBAAkBA,EAAO,kBAAoB,CAAC,IAAI,EAClD,aAAcA,EAAO,cAAgBwN,GAGvC,OAAA,KAAK,eAAe,IAAIE,EAAYC,CAAgB,EAE7C,IACT,CAKO,iBAAiBC,EAAwB,CAC9C,OAAAA,EAAQ,QAAQ5N,GAAU,KAAK,gBAAgBA,CAAM,CAAC,EAC/C,IACT,CAKQ,MAAM,sBAAsBA,EAAqB,CACvD,MAAM6N,EAAe7N,EAAO,cAAgBwN,EACtCM,EAAU,IAAID,EAAa7N,EAAO,WAAYA,EAAO,SAAS,EAEpE,OAAIA,EAAO,kBACT8N,EAAQ,oBAAoB9N,EAAO,gBAAgB,EAG9C8N,CACT,CAKO,MAAM,WAAWtF,EAAoB9H,EAAiB,CAC3D,GAAI,KAAK,eACP,MAAM,IAAI,MAAM,iCAAiC,EAGnD,MAAMgN,EAAa,KAAK,iBAAiBlF,EAAY9H,CAAS,EAGxDqN,EAAW,KAAK,gBAAgB,IAAIL,CAAU,EAMpD,GALIK,IACFA,EAAS,aAAe,IAAI,KAAA,EAAO,YAAA,GAIjC,KAAK,SAAS,IAAIL,CAAU,EAC9B,OAAO,KAAK,SAAS,IAAIA,CAAU,EAIrC,IAAI1N,EAAS,KAAK,eAAe,IAAI0N,CAAU,EAC1C1N,IACHA,EAAS,CACP,WAAAwI,EACA,UAAA9H,EACA,iBAAkB,CAAC,IAAI,EACvB,aAAc8M,GAEhB,KAAK,eAAe,IAAIE,EAAY1N,CAAM,GAG5C,GAAI,CACF,MAAM8N,EAAU,MAAM,KAAK,sBAAsB9N,CAAM,EACvD,OAAA,KAAK,SAAS,IAAI0N,EAAYI,CAAO,EAGrC,KAAK,gBAAgB,IAAIJ,EAAY,CACnC,UAAW,IAAI,OAAO,YAAA,EACtB,aAAc,IAAI,KAAA,EAAO,YAAA,CAC1B,CAAA,EAED,KAAK,KAAK,kBAAmB,CAC3B,WAAAA,EACA,WAAAlF,EACA,UAAA9H,CACD,CAAA,EAEMoN,CACT,OAASrN,EAAO,CACd,MAAA,KAAK,KAAK,gBAAiB,CACzB,WAAAiN,EACA,WAAAlF,EACA,UAAA9H,EACA,MAAOD,CACR,CAAA,EACKA,CACR,CACF,CAKO,mBAAmB+H,EAAoB9H,EAAiB,CAC7D,MAAMgN,EAAa,KAAK,iBAAiBlF,EAAY9H,CAAS,EAC9D,OAAO,KAAK,SAAS,IAAIgN,CAAU,GAAK,IAC1C,CAKO,MAAM,kBAAkBlF,EAAoB9H,EAAiB,CAClE,MAAMoN,EAAU,MAAM,KAAK,WAAWtF,EAAY9H,CAAS,EAC3D,OAAA,MAAMoN,EAAQ,KAAA,EACPA,CACT,CAKO,MAAM,eAAetF,EAAoB9H,EAAiB,CAC/D,MAAMgN,EAAa,KAAK,iBAAiBlF,EAAY9H,CAAS,EACxDoN,EAAU,KAAK,SAAS,IAAIJ,CAAU,EAE5C,GAAI,CAACI,EACH,MAAO,GAGT,GAAI,CACF,OAAA,MAAMA,EAAQ,MAAA,EACdA,EAAQ,QAAA,EAER,KAAK,SAAS,OAAOJ,CAAU,EAC/B,KAAK,gBAAgB,OAAOA,CAAU,EAEtC,KAAK,KAAK,oBAAqB,CAC7B,WAAAA,EACA,WAAAlF,EACA,UAAA9H,CACD,CAAA,EAEM,EACT,OAASD,EAAO,CACd,YAAK,KAAK,gBAAiB,CACzB,WAAAiN,EACA,WAAAlF,EACA,UAAA9H,EACA,MAAOD,CACR,CAAA,EACM,EACT,CACF,CAKO,oBAAoB+H,EAAkB,CAC3C,MAAMwF,EAA0B,CAAA,EAEhC,SAAW,CAACN,EAAYI,CAAO,IAAK,KAAK,SAAU,CACjD,KAAM,CAACG,CAAS,EAAIP,EAAW,MAAM,GAAG,EACpCO,IAAczF,GAChBwF,EAAS,KAAKF,CAAO,CAEzB,CAEA,OAAOE,CACT,CAKO,uBAAuBxF,EAAkB,CAC9C,MAAM0F,EAAiB,CAAA,EAEvB,UAAWR,KAAc,KAAK,SAAS,OAAQ,CAC7C,KAAM,CAACO,CAAS,EAAIP,EAAW,MAAM,GAAG,EACpCO,IAAczF,GAChB0F,EAAK,KAAKR,CAAU,CAExB,CAEA,OAAOQ,CACT,CAKO,MAAM,wBAAwB1F,EAAkB,CAGrD,MAAM2F,EAFc,KAAK,uBAAuB3F,CAAU,EAEtB,IAAI,MAAMkF,GAAa,CACzD,KAAM,CAAA,CAAGhN,CAAS,EAAIgN,EAAW,MAAM,GAAG,EAC1C,OAAO,KAAK,eAAelF,EAAY9H,CAAS,CAClD,CAAC,EAED,MAAM,QAAQ,IAAIyN,CAAe,CACnC,CAKO,mBAAiB,CACtB,MAAMC,EAAuB,CAAA,EAG7B,SAAW,CAACV,EAAY1N,CAAM,IAAK,KAAK,eAAgB,CACtD,MAAM8N,EAAU,KAAK,SAAS,IAAIJ,CAAU,EACtCK,EAAW,KAAK,gBAAgB,IAAIL,CAAU,EAEpDU,EAAM,KAAK,CACT,IAAKV,EACL,WAAY1N,EAAO,WACnB,UAAWA,EAAO,UAClB,OAAQ8N,EAAUA,EAAQ,UAAA,EAAc,CACtC,WAAY9N,EAAO,WACnB,UAAWA,EAAO,UAClB,SAAU,GACV,cAAe,GACf,OAAQ,EACT,EACD,aAAc,GACd,WAAW+N,GAAQ,YAARA,EAAU,YAAa,MAClC,aAAcA,GAAQ,KAAA,OAARA,EAAU,YACzB,CAAA,CACH,CAGA,SAAW,CAACL,EAAYI,CAAO,IAAK,KAAK,SACvC,GAAI,CAAC,KAAK,eAAe,IAAIJ,CAAU,EAAG,CACxC,KAAM,CAAClF,EAAY9H,CAAS,EAAIgN,EAAW,MAAM,GAAG,EAC9CK,EAAW,KAAK,gBAAgB,IAAIL,CAAU,EAEpDU,EAAM,KAAK,CACT,IAAKV,EACL,WAAAlF,EACA,UAAA9H,EACA,OAAQoN,EAAQ,UAAA,EAChB,aAAc,GACd,WAAWC,GAAQ,YAARA,EAAU,YAAa,MAClC,aAAcA,GAAQ,KAAA,OAARA,EAAU,YACzB,CAAA,CACH,CAGF,OAAOK,CACT,CAKO,MAAM,aAAW,CAEtB,MAAMC,EADW,MAAM,KAAK,KAAK,SAAS,QAAA,CAAS,EACnB,IAAI,MAAO,CAACX,EAAYI,CAAO,IAAK,CAClE,GAAI,CACF,MAAMQ,EAAS,MAAMR,EAAQ,YAAA,EAC7B,OAAA,OAAA,OAAA,OAAA,OAAA,CAAA,EAAYQ,CAAM,EAAA,CAAE,WAAAZ,CAAU,CAAA,CAChC,OAASjN,EAAO,CACd,KAAM,CAAC+H,EAAY9H,CAAS,EAAIgN,EAAW,MAAM,GAAG,EACpD,MAAO,CACL,QAAS,GACT,WAAAlF,EACA,MAAQ/H,EAAgB,QACxB,UAAW,IAAI,KAAA,EAAO,YAAA,EACtB,WAAAiN,EAEJ,CACF,CAAC,EAEKnD,EAAU,MAAM,QAAQ,IAAI8D,CAAc,EAC1CE,EAAehE,EAAQ,OAAOiE,GAAKA,EAAE,OAAO,EAAE,OAE9CC,EAAuB,CAC3B,cAAelE,EAAQ,OACvB,gBAAiBgE,EACjB,kBAAmBhE,EAAQ,OAASgE,EACpC,SAAUhE,EACV,UAAW,IAAI,OAAO,YAAA,EACtB,cAAegE,IAAiBhE,EAAQ,QAG1C,OAAA,KAAK,KAAK,yBAA0B,CAClC,WAAY,IACZ,WAAY,IACZ,UAAW,IACX,KAAMkE,CACP,CAAA,EAEMA,CACT,CAMO,MAAM,yBACXjG,EACAC,EAAiD,CAEjD,MAAMuF,EAAW,KAAK,oBAAoBxF,CAAU,EAEpD,GAAIwF,EAAS,SAAW,EACtB,MAAM,IAAI,MAAM,iCAAiCxF,CAAU,EAAE,EAI/D,UAAWsF,KAAWE,EACpB,MAAMF,EAAQ,KAAA,EAMhB,OAAO,MAFgBE,EAAS,CAAC,EAEL,mBAAmB,SACtC,MAAMvF,EAASuF,CAAQ,CAC/B,CACH,CAKQ,sBAAoB,CAE1B,KAAK,gBAAkB,YAAY,IAAK,CACtC,KAAK,sBAAA,CACP,EAAG,IAAS,GAAI,CAClB,CAKQ,MAAM,sBAAsBU,EAAsB,KAAU,IAAI,CACtE,GAAI,KAAK,eACP,OAGF,MAAMC,EAAM,KAAK,IAAA,EACXC,EAA8B,CAAA,EAEpC,SAAW,CAAClB,EAAYK,CAAQ,IAAK,KAAK,gBAAiB,CACzD,GAAI,CAACA,EAAS,aACZ,SAGF,MAAMc,EAAiB,IAAI,KAAKd,EAAS,YAAY,EAAE,QAAA,EACnDY,EAAME,EAAiBH,GACzBE,EAAkB,KAAKlB,CAAU,CAErC,CAEA,UAAWA,KAAckB,EAAmB,CAC1C,KAAM,CAACpG,EAAY9H,CAAS,EAAIgN,EAAW,MAAM,GAAG,EACpD,MAAM,KAAK,eAAelF,EAAY9H,CAAS,CACjD,CACF,CAKO,GAAGoO,EAAmBhE,EAAmC,CAC9D,OAAK,KAAK,cAAc,IAAIgE,CAAS,GACnC,KAAK,cAAc,IAAIA,EAAW,CAAA,CAAE,EAEtC,KAAK,cAAc,IAAIA,CAAS,EAAG,KAAKhE,CAAO,EACxC,IACT,CAEO,IAAIgE,EAAmBhE,EAAmC,CAC/D,MAAMC,EAAW,KAAK,cAAc,IAAI+D,CAAS,EACjD,GAAI/D,EAAU,CACZ,MAAMzJ,EAAQyJ,EAAS,QAAQD,CAAO,EAClCxJ,EAAQ,IACVyJ,EAAS,OAAOzJ,EAAO,CAAC,CAE5B,CACA,OAAO,IACT,CAEQ,KACNoE,EACA1B,EAAqD,CAErD,MAAM6G,EAAK,OAAA,OAAA,OAAA,OAAA,CAAA,EACN7G,CAAI,EAAA,CACP,KAAA0B,EACA,UAAW,IAAI,KAAA,EAAO,YAAA,IAIlBqF,EAAW,KAAK,cAAc,IAAIrF,CAAI,EACxCqF,GACFA,EAAS,QAAQD,GAAU,CACzB,GAAI,CACFA,EAAQD,CAAK,CACf,OAASpK,EAAO,CACd,QAAQ,MAAM,4BAA4BiF,CAAI,kBAAmBjF,CAAK,CACxE,CACF,CAAC,EAIH,MAAMsO,EAAiB,KAAK,cAAc,IAAI,GAAG,EAC7CA,GACFA,EAAe,QAAQjE,GAAU,CAC/B,GAAI,CACFA,EAAQD,CAAK,CACf,OAASpK,EAAO,CACd,QAAQ,MAAM,iDAAkDA,CAAK,CACvE,CACF,CAAC,CAEL,CAKO,WAAW+H,EAAoB9H,EAAiB,CACrD,MAAMgN,EAAa,KAAK,iBAAiBlF,EAAY9H,CAAS,EAC9D,OAAO,KAAK,SAAS,IAAIgN,CAAU,CACrC,CAEO,aAAalF,EAAoB9H,EAAiB,CACvD,MAAMgN,EAAa,KAAK,iBAAiBlF,EAAY9H,CAAS,EAC9D,OAAO,KAAK,eAAe,IAAIgN,CAAU,CAC3C,CAEO,iBAAe,CACpB,OAAO,KAAK,SAAS,IACvB,CAEO,oBAAkB,CACvB,OAAO,KAAK,eAAe,IAC7B,CAEO,YAAU,CACf,MAAMxG,EAAU,IAAI,IAEpB,UAAWwG,KAAc,KAAK,SAAS,KAAA,EAAQ,CAC7C,KAAM,CAAClF,CAAU,EAAIkF,EAAW,MAAM,GAAG,EACzCxG,EAAQ,IAAIsB,CAAU,CACxB,CAEA,OAAO,MAAM,KAAKtB,CAAO,CAC3B,CAKO,MAAM,SAAO,CAClB,KAAK,eAAiB,GAGlB,KAAK,kBACP,cAAc,KAAK,eAAe,EAClC,KAAK,gBAAkB,MAIzB,MAAMiH,EAAkB,MAAM,KAAK,KAAK,SAAS,QAAA,CAAS,EAAE,IAC1D,MAAO,CAACT,EAAYI,CAAO,IAAK,CAC9B,GAAI,CACF,MAAMA,EAAQ,MAAA,EACdA,EAAQ,QAAA,CACV,OAASrN,EAAO,CACd,QAAQ,MAAM,4BAA4BiN,CAAU,IAAKjN,CAAK,CAChE,CACF,CAAC,EAGH,MAAM,QAAQ,IAAI0N,CAAe,EAGjC,KAAK,SAAS,MAAA,EACd,KAAK,eAAe,MAAA,EACpB,KAAK,gBAAgB,QACrB,KAAK,cAAc,MAAA,EAEnB,KAAK,eAAiB,EACxB,EAriBeV,EAAA,SAAkC,KAyiBrBA,EAAe,YAAA,QC/lBvBuB,CAAW,CAIrB,YAAY5N,EAAW,CAC/B,OAAOA,EAAI,MACb,CAEU,eAAeA,EAAaS,EAAc,CAClD,GAAI,CAACA,GAAUA,EAAO,SAAW,EAC/B,OAAOT,EAGT,IAAI6N,EAAa,EACjB,OAAO7N,EAAI,QAAQ,MAAO,IAAK,CAC7B,GAAI6N,EAAapN,EAAO,OAAQ,CAC9B,MAAM0L,EAAQ1L,EAAOoN,GAAY,EACjC,OAAI,OAAO1B,GAAU,SACZ,IAAIA,EAAM,QAAQ,KAAM,IAAI,CAAC,IAElCA,GAAU,KACL,OAEF,OAAOA,CAAK,CACrB,CACA,MAAO,GACT,CAAC,CACH,CACD,OC2BY2B,CAAe,CAQ1B,aAAA,CAEE,GARM,KAAA,cAA+B,KAC/B,KAAA,cAAyB,GACzB,KAAA,sBAA8C,KAC9C,KAAA,eACN,IAAI,IAIAA,EAAgB,SAClB,MAAM,IAAI,MACR,4EAA4E,CAGlF,CAKA,OAAO,aAAW,CAChB,OAAKA,EAAgB,WACnBA,EAAgB,SAAW,IAAIA,GAE1BA,EAAgB,QACzB,CAKA,OAAO,eAAa,CACdA,EAAgB,UAClBA,EAAgB,SAAS,WAAW,MAAM,IAAK,CAAE,CAAC,EAEpDA,EAAgB,SAAW,IAC7B,CASA,MAAM,WACJhI,EACArH,EAKI,CAAA,EAAE,CAEN,OAAI,KAAK,cACA,KAAK,uBAAyB,QAAQ,UAG3C,KAAK,sBACA,KAAK,uBAGd,KAAK,sBAAwB,KAAK,uBAAuBqH,EAASrH,CAAO,EAClE,KAAK,sBACd,CAEQ,MAAM,uBACZqH,EACArH,EAKC,CAED,GAAI,CAEEA,EAAQ,kBACVA,EAAQ,iBAAiB,QAASF,GAAW,CAC3C0G,EAAgB,gBAAgB1G,CAAO,CACzC,CAAC,EAICE,EAAQ,oBACV,KAAK,GAAG,QAASA,EAAQ,kBAAkB,EAI7CiH,EAAgB,gBAAgBI,CAAO,EAGnCA,EAAQ,MAAQrH,EAAQ,kBAAoB,IAC9C,MAAMiH,EAAgB,2BAIpBjH,EAAQ,cAAgBA,EAAQ,aAAa,OAAS,GACxD,MAAMiH,EAAgB,oBAAoBjH,EAAQ,YAAY,EAGhE,KAAK,cAAgB,GACrB,KAAK,MAAM,cAAe,CAAE,QAAS,OAAO,KAAKqH,CAAO,CAAC,CAAE,CAC7D,OAASzG,EAAO,CACd,MAAA,KAAK,cAAgB,GACrB,KAAK,sBAAwB,KAC7B,KAAK,MAAM,QAASA,EAAgB,gBAAgB,EAC9CA,CACR,CACF,CAKA,MAAM,qBACJF,EACAV,EAII,CAAA,EAAE,CAEN,MAAMqH,EAAU,CAAE,CAAC3G,EAAO,aAAa,EAAGA,CAAM,EAChD,OAAO,KAAK,WAAW2G,iCAClBrH,CAAO,EAAA,CACV,gBAAiBA,EAAQ,cAAgB,KAE7C,CASA,MAAM,QAAQ2I,EAAkB,CAC9B,KAAK,kBAAA,EACL,KAAK,cAAgBA,EAErB,GAAI,CACF,MAAMlC,EAAM,MAAMQ,EAAgB,eAAe0B,CAAU,EAC3D,OAAA,KAAK,MAAM,YAAa,CAAE,WAAAA,CAAU,CAAE,EAC/BlC,CACT,OAAS7F,EAAO,CACd,MAAA,KAAK,MAAM,QAASA,EAAgB,YAAY,EAC1CA,CACR,CACF,CAMA,OAAO+H,EAAmB,CACxB,KAAK,kBAAA,EACL,MAAMjI,EAASiI,GAAc,KAAK,cAElC,GAAI,CAACjI,EACH,MAAM,IAAI,MACR,2EAA2E,EAI/E,GAAI,CACF,OAAOuG,EAAgB,IAAIvG,CAAM,CACnC,OAASE,EAAO,CACd,MAAA,KAAK,MAAM,QAASA,EAAgB,QAAQ,EACtCA,CACR,CACF,CAKA,eAAa,CACX,GAAI,CAAC,KAAK,cACR,MAAM,IAAI,MAAM,8CAA8C,EAEhE,OAAO,KAAK,OAAO,KAAK,aAAa,CACvC,CAKA,MAAM,yBAAyB+H,EAAkB,CAC/C,KAAK,kBAAA,EAEL,GAAI,CACF,OAAO,MAAM1B,EAAgB,yBAAyB0B,CAAU,CAClE,OAAS/H,EAAO,CACd,WAAK,MAAM,QAASA,EAAgB,kBAAkB,EAChDA,CACR,CACF,CASA,cACEC,EACA8H,EAAmB,CAEnB,MAAMjI,EAASiI,GAAc,KAAK,cAClC,GAAI,CAACjI,EACH,MAAM,IAAI,MACR,2EAA2E,EAG/E,MAAMsN,EAAe,cAAcnE,CAAc,CAC/C,aAAA,CACE,GAAI,CAACnJ,EACH,MAAM,IAAI,MACR,2EAA2E,EAG/E,MAAMA,EAAQG,CAAS,CACzB,GAGF,OAAO,IAAImN,CACb,CAKA,eACEsB,EACA3G,EAAmB,CAEnB,MAAMwF,EAA2C,CAAA,EAEjD,OAAAmB,EAAW,QAASzO,GAAa,CAC/BsN,EAAStN,CAAS,EAAI,KAAK,cAAiBA,EAAW8H,CAAU,CACnE,CAAC,EAEMwF,CACT,CAOA,MAAMtN,EAAoB8H,EAAmB,CAC3C,MAAMlC,EAAM,KAAK,OAAOkC,CAAU,EAElC,OAAI9H,EACKyK,EAAa,MAAMzK,EAAW4F,CAAG,EAGnC,IAAI6E,EAAa7E,CAAG,CAC7B,CAKA,MAAM5F,EAAmB8H,EAAmB,CAC1C,OAAO,KAAK,MAAM9H,EAAW8H,CAAU,CACzC,CAKA,MAAM,QACJpH,EACAS,EACA2G,EAAmB,CAEnB,GAAI,CAEF,MAAMrF,EAAS,MADH,KAAK,OAAOqF,CAAU,EACT,QAAQpH,EAAKS,CAAM,EAC5C,OAAA,KAAK,MAAM,gBAAiB,CAC1B,IAAAT,EACA,OAAAS,EACA,SAAUsB,EAAO,YAClB,CAAA,EACMA,CACT,OAAS1C,EAAO,CACd,MAAA,KAAK,MAAM,QAASA,EAAgB,SAAS,EACvCA,CACR,CACF,CAKA,MAAM,OACJW,EACAS,EACA2G,EAAmB,CAGnB,OAAO,MADK,KAAK,OAAOA,CAAU,EACjB,OAAOpH,EAAKS,CAAM,CACrC,CAKA,MAAM,QACJT,EACAS,EACA2G,EAAmB,CAGnB,OAAO,MADK,KAAK,OAAOA,CAAU,EACjB,QAAQpH,EAAKS,CAAM,CACtC,CAOA,MAAM,iBACJtB,EACA6O,EAAyB,GAAK,CAE9B,GAAI,CAKF,MAJY,MAAM/I,EAAgB,aAChC,CAAE,OAAQ9F,CAAM,EAChB6O,CAAa,GAEL,qBAAqB7O,CAAM,EACrC,KAAK,MAAM,oBAAqB,CAAE,WAAYA,EAAO,aAAa,CAAE,CACtE,OAASE,EAAO,CACd,WAAK,MAAM,QAASA,EAAgB,sBAAsB,EACpDA,CACR,CACF,CAKA,MAAM,iBAAiB+H,EAAmB,CAExC,OAAO,MADK,KAAK,OAAOA,CAAU,EACjB,kBACnB,CAKA,MAAM,gBAAgBA,EAAmB,CAEvC,OAAO,MADK,KAAK,OAAOA,CAAU,EACjB,iBACnB,CAKA,MAAM,aAAa9H,EAAmB8H,EAAmB,CAEvD,OAAO,MADK,KAAK,OAAOA,CAAU,EACjB,aAAa9H,CAAS,CACzC,CAOA,MAAM,WACJ8H,EACA9H,EACAsD,EACAnE,EAAgC,CAEhC,GAAI,CACF,MAAMsD,EAAS,MAAM2D,EAAgB,kBACnC0B,EACA9H,EACAsD,EACAnE,CAAO,EAET,OAAA,KAAK,MAAM,eAAgB,CACzB,WAAA2I,EACA,UAAA9H,EACA,YAAayC,EAAO,WACrB,CAAA,EACMA,CACT,OAAS1C,EAAO,CACd,MAAA,KAAK,MAAM,QAASA,EAAgB,YAAY,EAC1CA,CACR,CACF,CAKA,MAAM,sBACJ+H,EACA9H,EACAsD,EACAC,EACApE,EAAgC,CAEhC,GAAI,CACF,MAAMsD,EAAS,MAAM2D,EAAgB,sBACnC0B,EACA9H,EACAsD,EACAC,EACApE,CAAO,EAET,OAAA,KAAK,MAAM,eAAgB,CACzB,WAAA2I,EACA,UAAA9H,EACA,YAAayC,EAAO,WACrB,CAAA,EACMA,CACT,OAAS1C,EAAO,CACd,WAAK,MAAM,QAASA,EAAgB,uBAAuB,EACrDA,CACR,CACF,CAKA,MAAM,cACJ+H,EACA9H,EACA4D,EACAzE,EAI0B,CAE1B,GAAI,CACF,MAAMsD,EAAS,MAAM2D,EAAgB,cACnC0B,EACA9H,EACA4D,EACAzE,CAAO,EAET,OAAA,KAAK,MAAM,cAAe,CACxB,WAAA2I,EACA,UAAA9H,EACA,YAAayC,EAAO,WACrB,CAAA,EACMA,CACT,OAAS1C,EAAO,CACd,MAAA,KAAK,MAAM,QAASA,EAAgB,WAAW,EACzCA,CACR,CACF,CAOA,MAAM,aAAa4O,EAAiBzH,EAAoB,CACtD,KAAK,kBAAA,EAEL,GAAI,CACF,MAAMd,EAAgB,oBAAoBuI,EAAOzH,CAAW,EAC5D,KAAK,MAAM,eAAgB,CAAE,MAAAyH,EAAO,YAAAzH,CAAW,CAAE,CACnD,OAASnH,EAAO,CACd,WAAK,MAAM,QAASA,EAAgB,cAAc,EAC5CA,CACR,CACF,CAKA,qBAAmB,CACjB,OAAOqG,EAAgB,oBAAA,CACzB,CAKA,gBAAc,CACZ,OAAOA,EAAgB,gBACzB,CAKA,oBAAoBmB,EAAa,CAC/B,OAAOnB,EAAgB,oBAAoBmB,CAAK,CAClD,CAOA,MAAM,mBACJf,EACAuB,EAA+D,CAE/D,GAAI,CACF,MAAM3B,EAAgB,8BAA8BI,EAASuB,CAAQ,EACrE,KAAK,MAAM,uBAAwB,CAAE,QAAAvB,CAAO,CAAE,CAChD,OAASzG,EAAO,CACd,MAAA,KAAK,MAAM,QAASA,EAAgB,aAAa,EAC3CA,CACR,CACF,CAKA,MAAM,4BACJgI,EAA2C,CAE3C,MAAMnC,EAAM,KAAK,cAAA,EAEjB,GAAI,CACF,MAAMA,EAAI,iBAAA,EACV,MAAMnD,EAAS,MAAMsF,EAASnC,CAAG,EACjC,OAAA,MAAMA,EAAI,kBAAA,EACHnD,CACT,OAAS1C,EAAO,CACd,MAAA,MAAM6F,EAAI,oBAAA,EACJ7F,CACR,CACF,CAOA,gBAAc,CACZ,OAAO4F,EAAgB,mBAAA,CACzB,CAKA,qBAAmB,CAQjB,MAAO,CACL,cAAe,KAAK,cACpB,cAAe,KAAK,cACpB,kBAAmBS,EAAgB,gBAAA,EACnC,gBAAiBA,EAAgB,mBAAA,EACjC,UAAW,KAAK,oBAAA,EAChB,YAAa,KAAK,eAAA,EAEtB,CAKA,qBAAmB,CACjB,OAAOA,EAAgB,qBACzB,CAKA,MAAM,aAAW,CAGf,MAAMwI,EAAcxI,EAAgB,eAAA,EAC9ByI,EACJ,CAAA,EAEF,SAAW,CAAC/G,EAAYlC,CAAG,IAAK,OAAO,QAAQgJ,CAAW,EACxD,GAAI,CACF,MAAMhJ,EAAI,QAAQ,UAAU,EAC5BiJ,EAAa/G,CAAU,EAAI,CAAE,QAAS,EAAI,CAC5C,OAAS/H,EAAO,CACd8O,EAAa/G,CAAU,EAAI,CACzB,QAAS,GACT,MAAQ/H,EAAgB,QAE5B,CAGF,OAAO8O,CACT,CAOA,GAAG1E,EAAeC,EAAiC,CACjD,OAAK,KAAK,eAAe,IAAID,CAAK,GAChC,KAAK,eAAe,IAAIA,EAAO,CAAA,CAAE,EAEnC,KAAK,eAAe,IAAIA,CAAK,EAAG,KAAKC,CAAO,EACrC,IACT,CAKA,IAAID,EAAeC,EAAiC,CAClD,MAAMC,EAAW,KAAK,eAAe,IAAIF,CAAK,EAC9C,GAAIE,EAAU,CACZ,MAAMzJ,EAAQyJ,EAAS,QAAQD,CAAO,EAClCxJ,EAAQ,IACVyJ,EAAS,OAAOzJ,EAAO,CAAC,CAE5B,CACA,OAAO,IACT,CAKQ,MAAMuJ,KAAkB2E,EAAW,CACzC,MAAMzE,EAAW,KAAK,eAAe,IAAIF,CAAK,EAC1CE,GACFA,EAAS,QAASD,GAAW,CAC3B,GAAI,CACFA,EAAQ,GAAG0E,CAAI,CACjB,OAAS/O,EAAO,CAEd,QAAQ,MAAM,0BAA2BA,CAAK,CAChD,CACF,CAAC,CAEL,CAOA,MAAM,gBAAgB+H,EAAkB,CACtC,GAAI,CACF,MAAM1B,EAAgB,gBAAgB0B,CAAU,EAE5C,KAAK,gBAAkBA,IACzB,KAAK,cAAgB,MAGvB,KAAK,MAAM,mBAAoB,CAAE,WAAAA,CAAU,CAAE,CAC/C,OAAS/H,EAAO,CACd,WAAK,MAAM,QAASA,EAAgB,iBAAiB,EAC/CA,CACR,CACF,CAKA,MAAM,UAAQ,CACZ,GAAI,CACF,MAAMqG,EAAgB,WACtB,KAAK,cAAgB,KACrB,KAAK,cAAgB,GACrB,KAAK,sBAAwB,KAC7B,KAAK,eAAe,MAAA,EACpB,KAAK,MAAM,sBAAsB,CACnC,OAASrG,EAAO,CACd,WAAK,MAAM,QAASA,EAAgB,UAAU,EACxCA,CACR,CACF,CAKA,MAAM,QAAM,CACV,GAAI,CACF,MAAMqG,EAAgB,SACtB,KAAK,cAAgB,KACrB,KAAK,MAAM,eAAe,CAC5B,OAASrG,EAAO,CACd,MAAA,KAAK,MAAM,QAASA,EAAgB,QAAQ,EACtCA,CACR,CACF,CAOA,OAAO,gBAAgBd,EAAsB,CAC3C0G,EAAgB,gBAAgB1G,CAAO,CACzC,CAKA,OAAO,aAAa0H,EAKnB,CACCP,EAAgB,aAAaO,CAAU,CACzC,CAKA,OAAO,cACLC,EAKE,CAEFR,EAAgB,cAAcQ,CAAW,CAC3C,CAIQ,mBAAiB,CACvB,GAAI,CAAC,KAAK,cACR,MAAM,IAAI,MACR,2DAA2D,CAGjE,EAntBe4H,EAAA,SAAmC,KA2tB7C,MAAMO,EAAqB,CAChC7P,EACAC,IAMOwG,EAAgB,UAAUzG,EAAQC,CAAO,EAMrC6P,EAA2B,MACtCnP,EACAV,IAEO,MAAMwG,EAAgB,iBAAiB9F,EAAQV,CAAO,EAMlD8P,EAAuB,MAClCnJ,EACA3G,IAEO,MAAMwG,EAAgB,aAAaG,EAAQ3G,CAAO,EAM9C+P,EAAsBtJ,GAC1B,IAAI6E,EAAa7E,CAAG,EAMhBuJ,EAAoB,CAC/BrH,EACA9H,IAEO,IAAK,cAAcgJ,CAAc,CACtC,aAAA,CACE,MAAMlB,EAAY9H,CAAS,CAC7B,CACD,EAQUoP,EAAuB,MAAO9P,GAKZ,CAC7B,MAAM+P,EAASb,EAAgB,cAE/B,OAAA,MAAMa,EAAO,WAAW/P,EAAO,QAAS,CACtC,iBAAkBA,EAAO,SACzB,aAAcA,EAAO,YACtB,CAAA,EAEGA,EAAO,aACT,MAAM+P,EAAO,QAAQ/P,EAAO,WAAW,EAGlC+P,CACT,EAKaC,EAAuB,MAClCzP,EACAV,IAI2D,CAC3D,MAAMkQ,EAASb,EAAgB,YAAA,EAE/B,MAAMa,EAAO,qBAAqBxP,EAAQ,CACxC,iBAAkBV,GAAO,MAAPA,EAAS,QAAU,CAACA,EAAQ,OAAO,EAAI,OACzD,YAAaA,GAAO,KAAA,OAAPA,EAAS,WACvB,CAAA,EAED,MAAMyG,GACJzG,GAAO,KAAA,OAAPA,EAAS,eAAgB,GACrB,MAAMkQ,EAAO,QAAQxP,EAAO,aAAa,EACzCwP,EAAO,OAAOxP,EAAO,aAAa,EAExC,MAAO,CAAE,OAAAwP,EAAQ,IAAAzJ,EACnB,EAOM2J,EAAkBf,EAAgB,YAAA"}
|