@feasibleone/blong-chain 1.0.1 โ†’ 1.2.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.2.0](https://github.com/feasibleone/blong/compare/blong-chain-v1.1.0...blong-chain-v1.2.0) (2026-02-14)
4
+
5
+
6
+ ### Features
7
+
8
+ * add GitHub adapter with release management capabilities and update CI publish scripts ([bf01aef](https://github.com/feasibleone/blong/commit/bf01aef3d7028edaf6770321a5542bc2651665e0))
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * add validation for non-existent step references in blong-chain ([#26](https://github.com/feasibleone/blong/issues/26)) ([667bb3e](https://github.com/feasibleone/blong/commit/667bb3ee7262d098a8f7c198ac1ddfc66bb5caa5))
14
+ * detect and error on duplicate step names in blong-chain ([#22](https://github.com/feasibleone/blong/issues/22)) ([61229da](https://github.com/feasibleone/blong/commit/61229da03c19019c36407a83a0a01a7f807df926))
15
+
16
+ ## [1.1.0](https://github.com/feasibleone/blong/compare/blong-chain-v1.0.1...blong-chain-v1.1.0) (2026-02-05)
17
+
18
+
19
+ ### Features
20
+
21
+ * add checkpoint support ([#19](https://github.com/feasibleone/blong/issues/19)) ([097a7b8](https://github.com/feasibleone/blong/commit/097a7b80544b28f03f47f0ad6de186baf21004a1))
22
+
3
23
  ## [1.0.1](https://github.com/feasibleone/blong/compare/blong-chain-v1.0.0...blong-chain-v1.0.1) (2026-02-03)
4
24
 
5
25
 
package/README.md ADDED
@@ -0,0 +1,559 @@
1
+ # @feasibleone/blong-chain
2
+
3
+ **Parallel test execution with automatic dependency detection through thenable proxies.**
4
+
5
+ `blong-chain` is a TypeScript test framework that automatically detects
6
+ dependencies between test steps and executes them in parallel when possible,
7
+ maximizing performance while maintaining correctness.
8
+
9
+ ## Key Features
10
+
11
+ - ๐Ÿš€ **Automatic Parallelization** - Independent steps run concurrently
12
+ - ๐Ÿ”— **Dependency Detection** - Access patterns automatically create dependencies
13
+ - ๐Ÿ“Š **Progress Tracking** - Real-time execution monitoring with events
14
+ - ๐ŸŽฏ **Thenable Proxies** - Natural async/await syntax for step dependencies
15
+ - ๐Ÿ“ˆ **Performance Metrics** - Queue time, execution time, and critical path analysis
16
+ - ๐ŸŒณ **Nested Groups** - Hierarchical test organization with proper indentation
17
+ - ๐Ÿ”ง **Error Handling** - Graceful failure with continued execution of
18
+ independent steps
19
+ - ๐Ÿงช **Test Framework Integration** - Works seamlessly with node:test, tap,
20
+ and others
21
+
22
+ ## Installation
23
+
24
+ ```bash
25
+ npm install @feasibleone/blong-chain
26
+ ```
27
+
28
+ ## Quick Start
29
+
30
+ ```typescript
31
+ import {TestExecutor} from '@feasibleone/blong-chain';
32
+ import assert from 'node:assert/strict';
33
+ import {test} from 'node:test';
34
+
35
+ test('parallel execution example', async (t) => {
36
+ const executor = new TestExecutor({concurrency: 10});
37
+
38
+ const steps = [
39
+ async function fetchUser(assert, context) {
40
+ // Independent - runs immediately
41
+ return {id: 1, name: 'Alice'};
42
+ },
43
+
44
+ async function fetchAccount(assert, context) {
45
+ // Independent - runs in parallel with fetchUser
46
+ return {balance: 1000};
47
+ },
48
+
49
+ async function validateUser(assert, {fetchUser}) {
50
+ // Dependent - waits for fetchUser to complete
51
+ const user = await fetchUser;
52
+ assert.equal(user.name, 'Alice');
53
+ return {validated: true};
54
+ },
55
+
56
+ async function generateReport(assert, {fetchUser, fetchAccount}) {
57
+ // Multiple dependencies - waits for both
58
+ const user = await fetchUser;
59
+ const account = await fetchAccount;
60
+ return `User ${user.name} has balance ${account.balance}`;
61
+ },
62
+ ];
63
+
64
+ await executor.execute(steps, {testId: 'example'}, t);
65
+ });
66
+ ```
67
+
68
+ ## Core Concepts
69
+
70
+ ### Thenable Proxies
71
+
72
+ Steps access previous results through thenable proxies that automatically track
73
+ dependencies:
74
+
75
+ ```typescript
76
+ // Pattern 1: Direct await
77
+ async function step1(assert, {previousStep}) {
78
+ const result = await previousStep;
79
+ }
80
+
81
+ // Pattern 2: Destructure then await
82
+ async function step2(assert, {previousStep}) {
83
+ const result = await previousStep;
84
+ }
85
+
86
+ // Pattern 3: Nested property access
87
+ async function step3(assert, {previousStep}) {
88
+ const name = await previousStep.user.name;
89
+ }
90
+
91
+ // Pattern 4: Deep destructuring
92
+ async function step4(assert, {previousStep: {user: {name}}}) {
93
+ const userName = await name;
94
+ }
95
+ ```
96
+
97
+ ### Automatic Parallelization
98
+
99
+ The executor analyzes your access patterns and runs independent steps concurrently:
100
+
101
+ ```typescript
102
+ const steps = [
103
+ async function stepA() {
104
+ // Runs immediately
105
+ await someAsyncWork();
106
+ return {dataA: 'A'};
107
+ },
108
+
109
+ async function stepB() {
110
+ // Runs immediately in parallel with stepA
111
+ await someAsyncWork();
112
+ return {dataB: 'B'};
113
+ },
114
+
115
+ async function stepC(assert, {stepA}) {
116
+ // Waits for stepA (automatic dependency)
117
+ const a = await stepA;
118
+ return {dataC: a.dataA + 'C'};
119
+ },
120
+
121
+ async function stepD(assert, {stepA, stepB}) {
122
+ // Waits for both stepA and stepB (parallel wait)
123
+ const a = await stepA;
124
+ const b = await stepB;
125
+ assert.ok(a.dataA);
126
+ assert.ok(b.dataB);
127
+ return {dataD: 'D'};
128
+ },
129
+ ];
130
+ ```
131
+
132
+ ### Meta Information
133
+
134
+ The special `$meta` property is always available directly without await:
135
+
136
+ ```typescript
137
+ async function myStep(assert, {$meta}) {
138
+ // Access meta synchronously
139
+ console.log($meta.testId);
140
+ console.log($meta.environment);
141
+
142
+ // Meta is passed when executing
143
+ await executor.execute(steps, {
144
+ testId: 'test-123',
145
+ environment: 'production',
146
+ });
147
+ }
148
+ ```
149
+
150
+ ## Advanced Features
151
+
152
+ ### Nested Test Groups
153
+
154
+ Organize steps into hierarchical groups for better structure and output:
155
+
156
+ ```typescript
157
+ const databaseSetup = [
158
+ async function connect() { return {connected: true}; },
159
+ async function createSchema() { return {created: true}; },
160
+ async function seedData() { return {users: []}; },
161
+ ] as any;
162
+ databaseSetup.name = 'Database Setup';
163
+
164
+ const apiTests = [
165
+ async function testEndpoint1() { return {status: 200}; },
166
+ async function testEndpoint2() { return {status: 200}; },
167
+ ] as any;
168
+ apiTests.name = 'API Tests';
169
+
170
+ const steps = [
171
+ async function initialize() { return {ready: true}; },
172
+ databaseSetup, // Nested group
173
+ apiTests, // Nested group
174
+ async function cleanup() { return {done: true}; },
175
+ ];
176
+
177
+ await executor.execute(steps, {}, t);
178
+ ```
179
+
180
+ **Output:**
181
+
182
+ ```text
183
+ โ–ถ Test Name
184
+ โœ” initialize
185
+ โ–ถ Database Setup
186
+ โœ” connect
187
+ โœ” createSchema
188
+ โœ” seedData
189
+ โœ” Database Setup
190
+ โ–ถ API Tests
191
+ โœ” testEndpoint1
192
+ โœ” testEndpoint2
193
+ โœ” API Tests
194
+ โœ” cleanup
195
+ ```
196
+
197
+ ### Checkpoints (Synchronization Barriers)
198
+
199
+ Use empty arrays `[]` as checkpoints to synchronize parallel execution. All steps before a checkpoint must complete before any steps after it begin:
200
+
201
+ ```typescript
202
+ const steps = [
203
+ // Phase 1: These run in parallel
204
+ async function loadConfig() {
205
+ await fetchConfig();
206
+ return {apiUrl: 'https://api.example.com'};
207
+ },
208
+
209
+ async function initializeCache() {
210
+ await setupCache();
211
+ return {cacheReady: true};
212
+ },
213
+
214
+ async function setupLogging() {
215
+ await configureLogger();
216
+ return {loggerReady: true};
217
+ },
218
+
219
+ // Checkpoint: Wait for all Phase 1 steps to complete
220
+ [],
221
+
222
+ // Phase 2: These run in parallel, but only after Phase 1 completes
223
+ async function loadUsers({loadConfig}) {
224
+ const config = await loadConfig;
225
+ return await fetchUsers(config.apiUrl);
226
+ },
227
+
228
+ async function loadProducts({loadConfig}) {
229
+ const config = await loadConfig;
230
+ return await fetchProducts(config.apiUrl);
231
+ },
232
+
233
+ // Another checkpoint
234
+ [],
235
+
236
+ // Phase 3: Runs only after Phase 2 completes
237
+ async function generateReport({loadUsers, loadProducts}) {
238
+ const users = await loadUsers;
239
+ const products = await loadProducts;
240
+ return {report: combineData(users, products)};
241
+ },
242
+ ];
243
+ ```
244
+
245
+ **Use Cases:**
246
+ - **Phased execution**: Separate initialization, data loading, processing, and cleanup phases
247
+ - **Resource management**: Ensure all resources are ready before proceeding
248
+ - **Testing stages**: Complete all setup before running tests, then cleanup
249
+ - **Performance control**: Balance parallelism with resource constraints
250
+
251
+ ### Progress Tracking and Events
252
+
253
+ Monitor test execution in real-time:
254
+
255
+ ```typescript
256
+ const executor = new TestExecutor({concurrency: 10});
257
+
258
+ executor.on('test:start', (progress) => {
259
+ console.log('Test started:', progress.testName);
260
+ });
261
+
262
+ executor.on('step:start', (stepName, progress) => {
263
+ console.log('Step started:', stepName);
264
+ });
265
+
266
+ executor.on('step:end', (stepName, progress) => {
267
+ console.log('Step completed:', stepName, `in ${progress.duration}ms`);
268
+ });
269
+
270
+ executor.on('step:error', (stepName, error, progress) => {
271
+ console.error('Step failed:', stepName, error.message);
272
+ });
273
+
274
+ await executor.execute(steps, {});
275
+
276
+ // Get final progress
277
+ const progress = executor.getProgress();
278
+ console.log(`Completed ${progress.completedSteps}/${progress.totalSteps} steps`);
279
+ console.log(`Failed: ${progress.failedSteps}`);
280
+ ```
281
+
282
+ ### Dependency Graph Analysis
283
+
284
+ Inspect the dependency relationships:
285
+
286
+ ```typescript
287
+ await executor.execute(steps, {});
288
+
289
+ const graph = executor.getDependencyGraph();
290
+
291
+ // View all steps
292
+ for (const [name, node] of graph.nodes) {
293
+ console.log(`${name}: ${node.status}`);
294
+ }
295
+
296
+ // View dependencies
297
+ for (const edge of graph.edges) {
298
+ console.log(`${edge.from} depends on ${edge.to} via ${edge.property}`);
299
+ }
300
+ ```
301
+
302
+ ### Performance Metrics
303
+
304
+ Analyze execution performance:
305
+
306
+ ```typescript
307
+ await executor.execute(steps, {});
308
+
309
+ const latency = executor.getLatencyReport();
310
+
311
+ console.log(`Total duration: ${latency.totalDuration}ms`);
312
+ console.log(`Parallel efficiency: ${latency.parallelEfficiency.toFixed(2)}x`);
313
+ console.log(`Critical path: ${latency.criticalPath.join(' โ†’ ')}`);
314
+
315
+ // View bottlenecks
316
+ for (const bottleneck of latency.bottlenecks) {
317
+ console.log(
318
+ `${bottleneck.stepName} blocked ${bottleneck.blockedSteps.length} steps`
319
+ );
320
+ }
321
+
322
+ // View individual step metrics
323
+ for (const [name, metrics] of latency.steps) {
324
+ console.log(`${name}:`, {
325
+ queue: metrics.queueTime,
326
+ wait: metrics.waitTime,
327
+ exec: metrics.executionTime,
328
+ });
329
+ }
330
+ ```
331
+
332
+ ### Error Handling
333
+
334
+ Steps fail gracefully while independent steps continue:
335
+
336
+ ```typescript
337
+ const steps = [
338
+ async function stepA() {
339
+ return {data: 'A'};
340
+ },
341
+
342
+ async function stepB() {
343
+ throw new Error('Step B failed');
344
+ },
345
+
346
+ async function stepC(assert, {stepA}) {
347
+ // This still runs - it's independent of stepB
348
+ const a = await stepA;
349
+ return {data: 'C'};
350
+ },
351
+
352
+ async function stepD(assert, {stepB}) {
353
+ // This can handle the error if needed
354
+ try {
355
+ await stepB;
356
+ } catch (error) {
357
+ assert.ok(error.message.includes('Step B failed'));
358
+ return {handled: true};
359
+ }
360
+ },
361
+ ];
362
+
363
+ await executor.execute(steps, {});
364
+
365
+ // Check which steps failed
366
+ const progress = executor.getProgress();
367
+ for (const [name, step] of progress.steps) {
368
+ if (step.status === 'failed') {
369
+ console.log(`${name} failed:`, step.error?.message);
370
+ }
371
+ }
372
+ ```
373
+
374
+ ## Configuration Options
375
+
376
+ ```typescript
377
+ const executor = new TestExecutor({
378
+ // Maximum concurrent steps (default: 10)
379
+ concurrency: 5,
380
+
381
+ // Capture stack traces for better error reporting (default: false)
382
+ // Note: Has performance impact
383
+ captureStackTraces: true,
384
+
385
+ // Test framework context (optional)
386
+ // Passed automatically when using test framework integration
387
+ framework: undefined,
388
+ });
389
+ ```
390
+
391
+ ## Real-World Example
392
+
393
+ ```typescript
394
+ test('e-commerce checkout flow', async (t) => {
395
+ const executor = new TestExecutor({concurrency: 5});
396
+
397
+ const steps = [
398
+ async function loadProduct(assert, context) {
399
+ await new Promise(resolve => setTimeout(resolve, 30));
400
+ return {productId: 'PROD-123', price: 99.99, inStock: true};
401
+ },
402
+
403
+ async function loadCart(assert, context) {
404
+ await new Promise(resolve => setTimeout(resolve, 30));
405
+ return {cartId: 'CART-456', items: 2};
406
+ },
407
+
408
+ async function validateInventory(assert, {loadProduct}) {
409
+ const product = await loadProduct;
410
+ assert.ok(product.inStock);
411
+ return {valid: true, reservationId: 'RES-789'};
412
+ },
413
+
414
+ async function calculateShipping(assert, {loadCart}) {
415
+ const cart = await loadCart;
416
+ return {cost: 9.99, days: 3};
417
+ },
418
+
419
+ async function calculateTax(assert, {loadProduct}) {
420
+ const product = await loadProduct;
421
+ return {amount: product.price * 0.08};
422
+ },
423
+
424
+ async function calculateTotal(assert, {
425
+ loadProduct, calculateShipping, calculateTax
426
+ }) {
427
+ const product = await loadProduct;
428
+ const shipping = await calculateShipping;
429
+ const tax = await calculateTax;
430
+
431
+ return {
432
+ total: product.price + shipping.cost + tax.amount,
433
+ breakdown: {
434
+ product: product.price,
435
+ shipping: shipping.cost,
436
+ tax: tax.amount,
437
+ },
438
+ };
439
+ },
440
+
441
+ async function processPayment(assert, {
442
+ calculateTotal, validateInventory
443
+ }) {
444
+ const total = await calculateTotal;
445
+ const inventory = await validateInventory;
446
+
447
+ assert.ok(inventory.valid);
448
+ await new Promise(resolve => setTimeout(resolve, 40));
449
+
450
+ return {
451
+ paymentId: 'PAY-999',
452
+ amount: total.total,
453
+ status: 'completed',
454
+ };
455
+ },
456
+
457
+ async function createOrder(assert, {processPayment}) {
458
+ const payment = await processPayment;
459
+ assert.equal(payment.status, 'completed');
460
+
461
+ return {
462
+ orderId: 'ORD-111',
463
+ paymentId: payment.paymentId,
464
+ };
465
+ },
466
+ ];
467
+
468
+ await executor.execute(steps, {
469
+ testId: 'checkout-001',
470
+ environment: 'test',
471
+ }, t);
472
+
473
+ // Verify results
474
+ const progress = executor.getProgress();
475
+ assert.equal(progress.status, 'completed');
476
+ assert.equal(progress.failedSteps, 0);
477
+
478
+ const latency = executor.getLatencyReport();
479
+ console.log(`Completed in ${latency.totalDuration}ms`);
480
+ console.log(`Parallel efficiency: ${latency.parallelEfficiency.toFixed(2)}x`);
481
+ });
482
+ ```
483
+
484
+ In this example:
485
+
486
+ - `loadProduct` and `loadCart` run in parallel immediately
487
+ - `validateInventory` and `calculateShipping` wait only for their specific dependencies
488
+ - `calculateTax` runs as soon as `loadProduct` completes
489
+ - `calculateTotal` waits for all pricing components
490
+ - `processPayment` and `createOrder` form the critical path
491
+ - Total execution time is significantly less than sequential execution
492
+
493
+ ## Documentation
494
+
495
+ - **[SHOWCASE.md](./SHOWCASE.md)** - Comprehensive feature showcase with all patterns
496
+ - **[TESTING.md](./TESTING.md)** - Testing guide and CI integration
497
+ - **[NESTED_TEST_CONTEXT.md](./NESTED_TEST_CONTEXT.md)** - Test framework
498
+ integration details
499
+ - **[test-types.ts](./test-types.ts)** - Complete TypeScript API documentation
500
+
501
+ ## Running Tests
502
+
503
+ ```bash
504
+ # Run unit tests
505
+ npm test
506
+
507
+ # Run showcase examples
508
+ npm run build
509
+ node --test dist/showcase.test.js
510
+
511
+ # Run all tests
512
+ npm run test:all
513
+ ```
514
+
515
+ ## How It Works
516
+
517
+ 1. **Detection Phase**: When you destructure or access `context.stepName`, a
518
+ thenable proxy is returned
519
+ 2. **Dependency Tracking**: The access is recorded as a dependency
520
+ 3. **Scheduling Phase**: Steps are added to a priority queue based on dependencies
521
+ 4. **Execution Phase**: Steps run as soon as all their dependencies complete
522
+ 5. **Resolution Phase**: Step results are stored and proxies are resolved
523
+ 6. **Checkpoints**: Empty arrays `[]` create synchronization barriers, waiting for
524
+ all previous steps to complete before continuing
525
+
526
+ This creates a dynamic dependency graph that enables maximum parallelization
527
+ while ensuring correctness, with optional synchronization points for phased execution.
528
+
529
+ ## Use Cases
530
+
531
+ - **Integration Tests** - Test complex workflows with many async operations
532
+ - **E2E Tests** - Reduce test suite execution time through parallelization
533
+ - **Data Pipelines** - Orchestrate parallel data processing steps
534
+ - **API Testing** - Test multiple endpoints with shared setup steps
535
+ - **Performance Testing** - Identify bottlenecks with built-in metrics
536
+
537
+ ## TypeScript Support
538
+
539
+ Full TypeScript support with comprehensive type definitions:
540
+
541
+ ```typescript
542
+ import type {
543
+ ITestExecutor,
544
+ ITestContext,
545
+ ITestProgress,
546
+ IDependencyGraph,
547
+ ITestLatency,
548
+ StepFunction,
549
+ StepArray,
550
+ } from '@feasibleone/blong-chain';
551
+ ```
552
+
553
+ ## License
554
+
555
+ Part of the [Blong Framework](https://github.com/feasibleone/blong)
556
+
557
+ ## Contributing
558
+
559
+ Issues and pull requests welcome at <https://github.com/feasibleone/blong>
package/dist/index.d.ts CHANGED
@@ -24,6 +24,7 @@ export declare class TestExecutor extends EventEmitter {
24
24
  private realContext;
25
25
  private promiseManager;
26
26
  private testContext?;
27
+ private stepNamesUsed;
27
28
  constructor(config?: ITestExecutorConfig);
28
29
  /**
29
30
  * Executes an array of test steps
@@ -41,6 +42,14 @@ export declare class TestExecutor extends EventEmitter {
41
42
  * Counts total number of steps (including nested)
42
43
  */
43
44
  private _countSteps;
45
+ /**
46
+ * Collects all step names (including nested)
47
+ */
48
+ private _collectStepNames;
49
+ /**
50
+ * Checks for duplicate step names and throws an error if found
51
+ */
52
+ private _checkForDuplicateStepName;
44
53
  /**
45
54
  * Gets the current progress snapshot
46
55
  */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EAAC,YAAY,EAAC,MAAM,aAAa,CAAC;AAEzC,OAAO,KAAK,EAER,gBAAgB,EAChB,KAAK,EAOL,WAAW,EACX,mBAAmB,EACnB,YAAY,EACZ,aAAa,EAEb,SAAS,EAEZ,MAAM,iBAAiB,CAAC;AA2TzB;;GAEG;AACH,qBAAa,YAAa,SAAQ,YAAY;IAC1C,OAAO,CAAC,MAAM,CAAgC;IAC9C,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,iBAAiB,CAA2B;IAGpD,OAAO,CAAC,QAAQ,CASd;IAGF,OAAO,CAAC,KAAK,CAGX;IAGF,OAAO,CAAC,cAAc,CAAmC;IAGzD,OAAO,CAAC,WAAW,CAA+B;IAGlD,OAAO,CAAC,cAAc,CAAiB;IAGvC,OAAO,CAAC,WAAW,CAAC,CAAkD;gBAE1D,MAAM,GAAE,mBAAwB;IAe5C;;OAEG;IACG,OAAO,CACT,KAAK,EAAE,SAAS,EAChB,KAAK,EAAE,KAAK,EACZ,WAAW,CAAC,EAAE,OAAO,iBAAiB,EAAE,qBAAqB,GAC9D,OAAO,CAAC,IAAI,CAAC;IAsChB;;OAEG;YACW,aAAa;IA8C3B;;OAEG;YACW,YAAY;IAiK1B;;OAEG;IACH,OAAO,CAAC,WAAW;IAcnB;;OAEG;IACH,WAAW,IAAI,aAAa;IAI5B;;OAEG;IACH,kBAAkB,IAAI,gBAAgB;IAItC;;OAEG;IACH,gBAAgB,IAAI,YAAY;IA4BhC;;OAEG;IACH,OAAO,CAAC,sBAAsB;IA+C9B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IA4B5B;;OAEG;IACH,EAAE,CAAC,CAAC,SAAS,MAAM,WAAW,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,IAAI;IAIxE,IAAI,CAAC,CAAC,SAAS,MAAM,WAAW,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO;CAG5F;AAGD,mBAAmB,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EAAC,YAAY,EAAC,MAAM,aAAa,CAAC;AAEzC,OAAO,KAAK,EAER,gBAAgB,EAChB,KAAK,EAOL,WAAW,EACX,mBAAmB,EACnB,YAAY,EACZ,aAAa,EAEb,SAAS,EAEZ,MAAM,iBAAiB,CAAC;AA+UzB;;GAEG;AACH,qBAAa,YAAa,SAAQ,YAAY;IAC1C,OAAO,CAAC,MAAM,CAAgC;IAC9C,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,iBAAiB,CAA2B;IAGpD,OAAO,CAAC,QAAQ,CASd;IAGF,OAAO,CAAC,KAAK,CAGX;IAGF,OAAO,CAAC,cAAc,CAAmC;IAGzD,OAAO,CAAC,WAAW,CAA+B;IAGlD,OAAO,CAAC,cAAc,CAAiB;IAGvC,OAAO,CAAC,WAAW,CAAC,CAAkD;IAGtE,OAAO,CAAC,aAAa,CAAqB;gBAE9B,MAAM,GAAE,mBAAwB;IAe5C;;OAEG;IACG,OAAO,CACT,KAAK,EAAE,SAAS,EAChB,KAAK,EAAE,KAAK,EACZ,WAAW,CAAC,EAAE,OAAO,iBAAiB,EAAE,qBAAqB,GAC9D,OAAO,CAAC,IAAI,CAAC;IAwDhB;;OAEG;YACW,aAAa;IAsD3B;;OAEG;YACW,YAAY;IAoK1B;;OAEG;IACH,OAAO,CAAC,WAAW;IAcnB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAiBzB;;OAEG;IACH,OAAO,CAAC,0BAA0B;IAUlC;;OAEG;IACH,WAAW,IAAI,aAAa;IAI5B;;OAEG;IACH,kBAAkB,IAAI,gBAAgB;IAItC;;OAEG;IACH,gBAAgB,IAAI,YAAY;IA4BhC;;OAEG;IACH,OAAO,CAAC,sBAAsB;IA+C9B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IA4B5B;;OAEG;IACH,EAAE,CAAC,CAAC,SAAS,MAAM,WAAW,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,IAAI;IAIxE,IAAI,CAAC,CAAC,SAAS,MAAM,WAAW,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO;CAG5F;AAGD,mBAAmB,iBAAiB,CAAC"}