@cepseudo/engine 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +209 -0
  3. package/dist/component_types.d.ts +92 -0
  4. package/dist/component_types.d.ts.map +1 -0
  5. package/dist/component_types.js +93 -0
  6. package/dist/component_types.js.map +1 -0
  7. package/dist/digital_twin_engine.d.ts +390 -0
  8. package/dist/digital_twin_engine.d.ts.map +1 -0
  9. package/dist/digital_twin_engine.js +1200 -0
  10. package/dist/digital_twin_engine.js.map +1 -0
  11. package/dist/endpoints.d.ts +45 -0
  12. package/dist/endpoints.d.ts.map +1 -0
  13. package/dist/endpoints.js +87 -0
  14. package/dist/endpoints.js.map +1 -0
  15. package/dist/error_handler.d.ts +20 -0
  16. package/dist/error_handler.d.ts.map +1 -0
  17. package/dist/error_handler.js +68 -0
  18. package/dist/error_handler.js.map +1 -0
  19. package/dist/global_assets_handler.d.ts +63 -0
  20. package/dist/global_assets_handler.d.ts.map +1 -0
  21. package/dist/global_assets_handler.js +127 -0
  22. package/dist/global_assets_handler.js.map +1 -0
  23. package/dist/graceful_shutdown.d.ts +44 -0
  24. package/dist/graceful_shutdown.d.ts.map +1 -0
  25. package/dist/graceful_shutdown.js +79 -0
  26. package/dist/graceful_shutdown.js.map +1 -0
  27. package/dist/health.d.ts +112 -0
  28. package/dist/health.d.ts.map +1 -0
  29. package/dist/health.js +190 -0
  30. package/dist/health.js.map +1 -0
  31. package/dist/index.d.ts +19 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +25 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/initializer.d.ts +62 -0
  36. package/dist/initializer.d.ts.map +1 -0
  37. package/dist/initializer.js +110 -0
  38. package/dist/initializer.js.map +1 -0
  39. package/dist/loader/component_loader.d.ts +133 -0
  40. package/dist/loader/component_loader.d.ts.map +1 -0
  41. package/dist/loader/component_loader.js +340 -0
  42. package/dist/loader/component_loader.js.map +1 -0
  43. package/dist/openapi/generator.d.ts +93 -0
  44. package/dist/openapi/generator.d.ts.map +1 -0
  45. package/dist/openapi/generator.js +293 -0
  46. package/dist/openapi/generator.js.map +1 -0
  47. package/dist/queue_manager.d.ts +87 -0
  48. package/dist/queue_manager.d.ts.map +1 -0
  49. package/dist/queue_manager.js +196 -0
  50. package/dist/queue_manager.js.map +1 -0
  51. package/dist/scheduler.d.ts +29 -0
  52. package/dist/scheduler.d.ts.map +1 -0
  53. package/dist/scheduler.js +375 -0
  54. package/dist/scheduler.js.map +1 -0
  55. package/package.json +78 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Axel Hoffmann
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,209 @@
1
+ # @cepseudo/engine
2
+
3
+ [![Node.js](https://img.shields.io/badge/node-%3E%3D20.0.0-brightgreen)](https://nodejs.org/)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](./LICENSE)
5
+
6
+ Central orchestrator for the Digital Twin Framework. Wires together components, databases, storage, authentication, queues, and HTTP serving into a single runnable application.
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ pnpm add @cepseudo/engine
12
+ ```
13
+
14
+ This package depends on the full stack of `@cepseudo/*` packages (shared, database, storage, auth, assets, components) and requires Redis for queue management.
15
+
16
+ ## Quick Start
17
+
18
+ ```typescript
19
+ import { DigitalTwinEngine } from '@cepseudo/engine'
20
+ import { KnexDatabaseAdapter } from '@cepseudo/database'
21
+ import { StorageServiceFactory } from '@cepseudo/storage'
22
+ import { MyCollector } from './collectors/my_collector.js'
23
+
24
+ const database = new KnexDatabaseAdapter({
25
+ client: 'pg',
26
+ connection: process.env.DATABASE_URL
27
+ })
28
+
29
+ const storage = StorageServiceFactory.create()
30
+
31
+ const engine = new DigitalTwinEngine({
32
+ storage,
33
+ database,
34
+ collectors: [new MyCollector()],
35
+ server: { port: 3000 }
36
+ })
37
+
38
+ await engine.start()
39
+ ```
40
+
41
+ ## Features
42
+
43
+ - **Component lifecycle management** -- registers, validates, and initializes collectors, harvesters, handlers, assets managers, and custom table managers
44
+ - **Dependency injection** -- automatically injects database, storage, and auth middleware into components
45
+ - **BullMQ scheduling** -- cron-based and event-driven scheduling across 4 queues (collectors, harvesters, priority, uploads)
46
+ - **HTTP server** -- Express-compatible server (via ultimate-express) with automatic endpoint registration from components
47
+ - **Health checks** -- aggregated health status for Kubernetes readiness/liveness probes (database, Redis, storage)
48
+ - **OpenAPI generation** -- auto-generates OpenAPI 3.0.3 specs from registered components
49
+ - **Graceful shutdown** -- handles SIGTERM/SIGINT with configurable timeout and ordered resource cleanup
50
+ - **Dynamic component loading** -- loads components from user project directories at runtime
51
+
52
+ ## Configuration
53
+
54
+ The `EngineOptions` interface controls engine behavior:
55
+
56
+ ```typescript
57
+ interface EngineOptions {
58
+ // Required
59
+ storage: StorageService
60
+ database: DatabaseAdapter
61
+
62
+ // Components (register via constructor or engine.register())
63
+ collectors?: Collector[]
64
+ harvesters?: Harvester[]
65
+ handlers?: Handler[]
66
+ assetsManagers?: AssetsManager[]
67
+ customTableManagers?: CustomTableManager[]
68
+
69
+ // Redis & queues
70
+ redis?: ConnectionOptions
71
+ queues?: {
72
+ multiQueue?: boolean // default: true
73
+ workers?: {
74
+ collectors?: number // default: 1
75
+ harvesters?: number // default: 1
76
+ }
77
+ options?: QueueConfig['queueOptions']
78
+ }
79
+
80
+ // HTTP server
81
+ server?: {
82
+ port: number // default: 3000
83
+ host?: string // default: '0.0.0.0'
84
+ }
85
+
86
+ // Logging
87
+ logging?: {
88
+ level: LogLevel // default: LogLevel.INFO
89
+ format?: 'json' | 'text' // default: 'text'
90
+ }
91
+
92
+ dryRun?: boolean // default: false
93
+ autoMigration?: boolean // default: true
94
+ }
95
+ ```
96
+
97
+ ## Usage Examples
98
+
99
+ ### Registering components dynamically
100
+
101
+ Components can be registered after construction, before calling `start()`:
102
+
103
+ ```typescript
104
+ const engine = new DigitalTwinEngine({ storage, database })
105
+
106
+ engine.register(new WeatherCollector())
107
+ engine.register(new AirQualityHandler())
108
+ engine.registerAll([new TilesetManager(), new MapManager()])
109
+
110
+ await engine.start()
111
+ ```
112
+
113
+ ### Health checks
114
+
115
+ The engine includes built-in health checks for database, Redis, and storage. Custom checks can be added:
116
+
117
+ ```typescript
118
+ import {
119
+ HealthChecker,
120
+ createDatabaseCheck,
121
+ createRedisCheck,
122
+ createStorageCheck
123
+ } from '@cepseudo/engine'
124
+
125
+ const checker = new HealthChecker()
126
+ checker.register('database', createDatabaseCheck(database))
127
+ checker.register('redis', createRedisCheck(queueManager))
128
+ checker.register('storage', createStorageCheck(storage))
129
+
130
+ // Returns { status: 'healthy' | 'degraded' | 'unhealthy', checks: {...} }
131
+ const status = await checker.check()
132
+ ```
133
+
134
+ The engine automatically registers health endpoints:
135
+ - `GET /health` -- full health status (readiness probe)
136
+ - `GET /health/live` -- lightweight liveness probe
137
+
138
+ ### OpenAPI spec generation
139
+
140
+ ```typescript
141
+ import { OpenAPIGenerator } from '@cepseudo/engine'
142
+
143
+ const generator = new OpenAPIGenerator({
144
+ title: 'My Digital Twin API',
145
+ version: '1.0.0',
146
+ description: 'Digital twin for city infrastructure'
147
+ })
148
+
149
+ // Components expose their endpoint schemas via getConfiguration()
150
+ const spec = generator.generate(components)
151
+ // Returns an OpenAPI 3.0.3 JSON object
152
+ ```
153
+
154
+ ### Graceful shutdown
155
+
156
+ ```typescript
157
+ import { setupGracefulShutdown } from '@cepseudo/engine'
158
+
159
+ // Automatically handles SIGTERM and SIGINT
160
+ setupGracefulShutdown({
161
+ engine,
162
+ timeout: 30000 // ms before forced exit
163
+ })
164
+ ```
165
+
166
+ ### Dynamic component loading
167
+
168
+ Load components from a user project directory at runtime:
169
+
170
+ ```typescript
171
+ import { loadComponents } from '@cepseudo/engine'
172
+
173
+ const result = await loadComponents({
174
+ directory: './src/components',
175
+ recursive: true
176
+ })
177
+
178
+ engine.registerAll([
179
+ ...result.collectors,
180
+ ...result.harvesters,
181
+ ...result.handlers
182
+ ])
183
+ ```
184
+
185
+ ## Architecture
186
+
187
+ `@cepseudo/engine` is the LAYER 3 (top layer) package in the Digital Twin Framework. It depends on all lower layers and acts as the composition root that ties everything together.
188
+
189
+ ```
190
+ LAYER 3: engine -- orchestration, HTTP, scheduling, health
191
+ LAYER 2: assets, components -- business logic, file management
192
+ LAYER 1: database, storage, auth -- infrastructure adapters
193
+ LAYER 0: shared -- types, errors, utilities, validation
194
+ ```
195
+
196
+ On `engine.start()`, the following sequence executes:
197
+
198
+ 1. **Database initialization** -- runs migrations, creates component tables
199
+ 2. **Component initialization** -- injects dependencies (database, storage, auth middleware) into active components
200
+ 3. **Endpoint registration** -- maps component HTTP endpoints to Express routes
201
+ 4. **Queue setup** -- creates BullMQ queues and workers backed by Redis
202
+ 5. **Scheduling** -- registers cron schedules and event triggers for collectors/harvesters
203
+ 6. **Server start** -- binds the HTTP server and begins accepting requests
204
+
205
+ On `engine.stop()`, resources are cleaned up in reverse order with a configurable timeout to allow in-flight requests and queue jobs to complete.
206
+
207
+ ## License
208
+
209
+ MIT
@@ -0,0 +1,92 @@
1
+ /**
2
+ * @fileoverview Type definitions and guards for dynamic component registration
3
+ *
4
+ * Provides type-safe utilities for runtime component type detection and
5
+ * dynamic registration with the DigitalTwinEngine.
6
+ */
7
+ import type { Collector, Harvester, Handler, CustomTableManager } from '@cepseudo/components';
8
+ import type { AssetsManager } from '@cepseudo/assets';
9
+ /**
10
+ * String literal union of all component type names.
11
+ * Used for discriminated unions and type narrowing.
12
+ */
13
+ export type ComponentTypeName = 'collector' | 'harvester' | 'handler' | 'assets_manager' | 'custom_table_manager';
14
+ /**
15
+ * Union type of all component class instances that can be registered.
16
+ */
17
+ export type AnyComponent = Collector | Harvester | Handler | AssetsManager | CustomTableManager;
18
+ /**
19
+ * Union type of components that can be scheduled (have run() and getSchedule()).
20
+ */
21
+ export type SchedulableComponent = Collector | Harvester;
22
+ /**
23
+ * Union type of components that require setDependencies(db, storage).
24
+ */
25
+ export type ActiveComponent = Collector | Harvester;
26
+ /**
27
+ * Map of component type names to their corresponding class types.
28
+ * Enables type-safe lookups and factory patterns.
29
+ */
30
+ export interface ComponentTypeMap {
31
+ collector: Collector;
32
+ harvester: Harvester;
33
+ handler: Handler;
34
+ assets_manager: AssetsManager;
35
+ custom_table_manager: CustomTableManager;
36
+ }
37
+ /**
38
+ * Result of loading components from a directory.
39
+ */
40
+ export interface LoadedComponents {
41
+ collectors: Collector[];
42
+ harvesters: Harvester[];
43
+ handlers: Handler[];
44
+ assetsManagers: AssetsManager[];
45
+ customTableManagers: CustomTableManager[];
46
+ }
47
+ /**
48
+ * Type guard: Check if component is a Collector.
49
+ * Collectors have collect() method and getSchedule().
50
+ */
51
+ export declare function isCollector(component: AnyComponent): component is Collector;
52
+ /**
53
+ * Type guard: Check if component is a Harvester.
54
+ * Harvesters have harvest() method and getUserConfiguration().
55
+ */
56
+ export declare function isHarvester(component: AnyComponent): component is Harvester;
57
+ /**
58
+ * Type guard: Check if component is a Handler.
59
+ * Handlers have getEndpoints() but NOT setDependencies() by default,
60
+ * and don't have collect() or harvest().
61
+ */
62
+ export declare function isHandler(component: AnyComponent): component is Handler;
63
+ /**
64
+ * Type guard: Check if component is an AssetsManager.
65
+ * AssetsManager has uploadAsset() and getAllAssets().
66
+ */
67
+ export declare function isAssetsManager(component: AnyComponent): component is AssetsManager;
68
+ /**
69
+ * Type guard: Check if component is a CustomTableManager.
70
+ * CustomTableManager has initializeTable() and findAll().
71
+ */
72
+ export declare function isCustomTableManager(component: AnyComponent): component is CustomTableManager;
73
+ /**
74
+ * Type guard: Check if component is an active (schedulable) component.
75
+ */
76
+ export declare function isActiveComponent(component: AnyComponent): component is ActiveComponent;
77
+ /**
78
+ * Detect the component type from an instance.
79
+ * Uses type guards for accurate detection.
80
+ *
81
+ * @param component - The component instance to detect
82
+ * @returns The detected component type name
83
+ * @throws Error if component type cannot be determined
84
+ *
85
+ * @example
86
+ * ```typescript
87
+ * const type = detectComponentType(myComponent)
88
+ * // type: 'collector' | 'harvester' | 'handler' | 'assets_manager' | 'custom_table_manager'
89
+ * ```
90
+ */
91
+ export declare function detectComponentType(component: AnyComponent): ComponentTypeName;
92
+ //# sourceMappingURL=component_types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"component_types.d.ts","sourceRoot":"","sources":["../src/component_types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AAC7F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAErD;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,WAAW,GAAG,SAAS,GAAG,gBAAgB,GAAG,sBAAsB,CAAA;AAEjH;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,aAAa,GAAG,kBAAkB,CAAA;AAE/F;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,SAAS,GAAG,SAAS,CAAA;AAExD;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,SAAS,CAAA;AAEnD;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC7B,SAAS,EAAE,SAAS,CAAA;IACpB,SAAS,EAAE,SAAS,CAAA;IACpB,OAAO,EAAE,OAAO,CAAA;IAChB,cAAc,EAAE,aAAa,CAAA;IAC7B,oBAAoB,EAAE,kBAAkB,CAAA;CAC3C;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC7B,UAAU,EAAE,SAAS,EAAE,CAAA;IACvB,UAAU,EAAE,SAAS,EAAE,CAAA;IACvB,QAAQ,EAAE,OAAO,EAAE,CAAA;IACnB,cAAc,EAAE,aAAa,EAAE,CAAA;IAC/B,mBAAmB,EAAE,kBAAkB,EAAE,CAAA;CAC5C;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,YAAY,GAAG,SAAS,IAAI,SAAS,CAO3E;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,YAAY,GAAG,SAAS,IAAI,SAAS,CAO3E;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,SAAS,EAAE,YAAY,GAAG,SAAS,IAAI,OAAO,CASvE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,YAAY,GAAG,SAAS,IAAI,aAAa,CAMnF;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,YAAY,GAAG,SAAS,IAAI,kBAAkB,CAO7F;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,YAAY,GAAG,SAAS,IAAI,eAAe,CAEvF;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,YAAY,GAAG,iBAAiB,CAW9E"}
@@ -0,0 +1,93 @@
1
+ /**
2
+ * @fileoverview Type definitions and guards for dynamic component registration
3
+ *
4
+ * Provides type-safe utilities for runtime component type detection and
5
+ * dynamic registration with the DigitalTwinEngine.
6
+ */
7
+ /**
8
+ * Type guard: Check if component is a Collector.
9
+ * Collectors have collect() method and getSchedule().
10
+ */
11
+ export function isCollector(component) {
12
+ return (typeof component.collect === 'function' &&
13
+ typeof component.getSchedule === 'function' &&
14
+ typeof component.setDependencies === 'function' &&
15
+ typeof component.run === 'function');
16
+ }
17
+ /**
18
+ * Type guard: Check if component is a Harvester.
19
+ * Harvesters have harvest() method and getUserConfiguration().
20
+ */
21
+ export function isHarvester(component) {
22
+ return (typeof component.harvest === 'function' &&
23
+ typeof component.getUserConfiguration === 'function' &&
24
+ typeof component.setDependencies === 'function' &&
25
+ typeof component.run === 'function');
26
+ }
27
+ /**
28
+ * Type guard: Check if component is a Handler.
29
+ * Handlers have getEndpoints() but NOT setDependencies() by default,
30
+ * and don't have collect() or harvest().
31
+ */
32
+ export function isHandler(component) {
33
+ return (typeof component.getEndpoints === 'function' &&
34
+ typeof component.getConfiguration === 'function' &&
35
+ !('collect' in component && typeof component.collect === 'function') &&
36
+ !('harvest' in component && typeof component.harvest === 'function') &&
37
+ !('uploadAsset' in component && typeof component.uploadAsset === 'function') &&
38
+ !('initializeTable' in component && typeof component.initializeTable === 'function'));
39
+ }
40
+ /**
41
+ * Type guard: Check if component is an AssetsManager.
42
+ * AssetsManager has uploadAsset() and getAllAssets().
43
+ */
44
+ export function isAssetsManager(component) {
45
+ return (typeof component.uploadAsset === 'function' &&
46
+ typeof component.getAllAssets === 'function' &&
47
+ typeof component.setDependencies === 'function');
48
+ }
49
+ /**
50
+ * Type guard: Check if component is a CustomTableManager.
51
+ * CustomTableManager has initializeTable() and findAll().
52
+ */
53
+ export function isCustomTableManager(component) {
54
+ return (typeof component.initializeTable === 'function' &&
55
+ typeof component.findAll === 'function' &&
56
+ typeof component.create === 'function' &&
57
+ typeof component.setDependencies === 'function');
58
+ }
59
+ /**
60
+ * Type guard: Check if component is an active (schedulable) component.
61
+ */
62
+ export function isActiveComponent(component) {
63
+ return isCollector(component) || isHarvester(component);
64
+ }
65
+ /**
66
+ * Detect the component type from an instance.
67
+ * Uses type guards for accurate detection.
68
+ *
69
+ * @param component - The component instance to detect
70
+ * @returns The detected component type name
71
+ * @throws Error if component type cannot be determined
72
+ *
73
+ * @example
74
+ * ```typescript
75
+ * const type = detectComponentType(myComponent)
76
+ * // type: 'collector' | 'harvester' | 'handler' | 'assets_manager' | 'custom_table_manager'
77
+ * ```
78
+ */
79
+ export function detectComponentType(component) {
80
+ // Order matters: check more specific types first
81
+ if (isCollector(component))
82
+ return 'collector';
83
+ if (isHarvester(component))
84
+ return 'harvester';
85
+ if (isCustomTableManager(component))
86
+ return 'custom_table_manager';
87
+ if (isAssetsManager(component))
88
+ return 'assets_manager';
89
+ if (isHandler(component))
90
+ return 'handler';
91
+ throw new Error('Unable to detect component type. Component must extend Collector, Harvester, Handler, AssetsManager, or CustomTableManager.');
92
+ }
93
+ //# sourceMappingURL=component_types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"component_types.js","sourceRoot":"","sources":["../src/component_types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAiDH;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,SAAuB;IAC/C,OAAO,CACH,OAAQ,SAAuB,CAAC,OAAO,KAAK,UAAU;QACtD,OAAQ,SAAuB,CAAC,WAAW,KAAK,UAAU;QAC1D,OAAQ,SAAuB,CAAC,eAAe,KAAK,UAAU;QAC9D,OAAQ,SAAuB,CAAC,GAAG,KAAK,UAAU,CACrD,CAAA;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,SAAuB;IAC/C,OAAO,CACH,OAAQ,SAAuB,CAAC,OAAO,KAAK,UAAU;QACtD,OAAQ,SAAuB,CAAC,oBAAoB,KAAK,UAAU;QACnE,OAAQ,SAAuB,CAAC,eAAe,KAAK,UAAU;QAC9D,OAAQ,SAAuB,CAAC,GAAG,KAAK,UAAU,CACrD,CAAA;AACL,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,SAAuB;IAC7C,OAAO,CACH,OAAQ,SAAqB,CAAC,YAAY,KAAK,UAAU;QACzD,OAAQ,SAAqB,CAAC,gBAAgB,KAAK,UAAU;QAC7D,CAAC,CAAC,SAAS,IAAI,SAAS,IAAI,OAAQ,SAAiB,CAAC,OAAO,KAAK,UAAU,CAAC;QAC7E,CAAC,CAAC,SAAS,IAAI,SAAS,IAAI,OAAQ,SAAiB,CAAC,OAAO,KAAK,UAAU,CAAC;QAC7E,CAAC,CAAC,aAAa,IAAI,SAAS,IAAI,OAAQ,SAAiB,CAAC,WAAW,KAAK,UAAU,CAAC;QACrF,CAAC,CAAC,iBAAiB,IAAI,SAAS,IAAI,OAAQ,SAAiB,CAAC,eAAe,KAAK,UAAU,CAAC,CAChG,CAAA;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,SAAuB;IACnD,OAAO,CACH,OAAQ,SAA2B,CAAC,WAAW,KAAK,UAAU;QAC9D,OAAQ,SAA2B,CAAC,YAAY,KAAK,UAAU;QAC/D,OAAQ,SAA2B,CAAC,eAAe,KAAK,UAAU,CACrE,CAAA;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,SAAuB;IACxD,OAAO,CACH,OAAQ,SAAgC,CAAC,eAAe,KAAK,UAAU;QACvE,OAAQ,SAAgC,CAAC,OAAO,KAAK,UAAU;QAC/D,OAAQ,SAAgC,CAAC,MAAM,KAAK,UAAU;QAC9D,OAAQ,SAAgC,CAAC,eAAe,KAAK,UAAU,CAC1E,CAAA;AACL,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,SAAuB;IACrD,OAAO,WAAW,CAAC,SAAS,CAAC,IAAI,WAAW,CAAC,SAAS,CAAC,CAAA;AAC3D,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,mBAAmB,CAAC,SAAuB;IACvD,iDAAiD;IACjD,IAAI,WAAW,CAAC,SAAS,CAAC;QAAE,OAAO,WAAW,CAAA;IAC9C,IAAI,WAAW,CAAC,SAAS,CAAC;QAAE,OAAO,WAAW,CAAA;IAC9C,IAAI,oBAAoB,CAAC,SAAS,CAAC;QAAE,OAAO,sBAAsB,CAAA;IAClE,IAAI,eAAe,CAAC,SAAS,CAAC;QAAE,OAAO,gBAAgB,CAAA;IACvD,IAAI,SAAS,CAAC,SAAS,CAAC;QAAE,OAAO,SAAS,CAAA;IAE1C,MAAM,IAAI,KAAK,CACX,6HAA6H,CAChI,CAAA;AACL,CAAC"}