ugly-app 0.1.76 → 0.1.78
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/README.md +143 -6
- package/dist/cli/version.d.ts +1 -1
- package/dist/cli/version.js +1 -1
- package/dist/client/components/DateRangePicker.d.ts +0 -1
- package/dist/client/components/DateRangePicker.d.ts.map +1 -1
- package/dist/client/components/DateRangePicker.js +0 -2
- package/dist/client/components/DateRangePicker.js.map +1 -1
- package/dist/client/createSocket.d.ts +34 -7
- package/dist/client/createSocket.d.ts.map +1 -1
- package/dist/client/createSocket.js +389 -50
- package/dist/client/createSocket.js.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/server/Cache.d.ts +9 -0
- package/dist/server/Cache.d.ts.map +1 -1
- package/dist/server/Cache.js +15 -0
- package/dist/server/Cache.js.map +1 -1
- package/dist/server/DB.d.ts.map +1 -1
- package/dist/server/DB.js +11 -2
- package/dist/server/DB.js.map +1 -1
- package/dist/server/EventCounter.d.ts +20 -0
- package/dist/server/EventCounter.d.ts.map +1 -0
- package/dist/server/EventCounter.js +157 -0
- package/dist/server/EventCounter.js.map +1 -0
- package/dist/server/Socket.d.ts +8 -2
- package/dist/server/Socket.d.ts.map +1 -1
- package/dist/server/Socket.js +58 -42
- package/dist/server/Socket.js.map +1 -1
- package/dist/server/ai/providers/UglyBotTextGenProvider.d.ts.map +1 -1
- package/dist/server/ai/providers/UglyBotTextGenProvider.js +9 -1
- package/dist/server/ai/providers/UglyBotTextGenProvider.js.map +1 -1
- package/dist/server/index.d.ts +5 -3
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +5 -3
- package/dist/server/index.js.map +1 -1
- package/dist/shared/DB.d.ts +37 -9
- package/dist/shared/DB.d.ts.map +1 -1
- package/dist/shared/DB.js.map +1 -1
- package/dist/shared/EventCounter.d.ts +32 -0
- package/dist/shared/EventCounter.d.ts.map +1 -0
- package/dist/shared/EventCounter.js +3 -0
- package/dist/shared/EventCounter.js.map +1 -0
- package/dist/shared/index.d.ts +1 -0
- package/dist/shared/index.d.ts.map +1 -1
- package/dist/shared/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/client/allPages.ts +1 -0
- package/templates/client/pages/AITestPage.tsx +11 -10
- package/templates/client/pages/HomePage.tsx +5 -0
- package/templates/client/pages/UIComponentsPage.tsx +1017 -0
- package/templates/server/index.ts +12 -0
- package/templates/shared/api.ts +22 -0
- package/templates/shared/pages.ts +1 -0
package/README.md
CHANGED
|
@@ -8,7 +8,8 @@ A full-stack TypeScript framework for building production-ready web applications
|
|
|
8
8
|
- **Client**: React + Vite with typed routing, lazy pages, and popup management
|
|
9
9
|
- **Database**: MongoDB with typed collections, dot-notation updates, indexes, migrations, and live document tracking
|
|
10
10
|
- **Auth**: JWT + HttpOnly cookies, ugly.bot OAuth out of the box, extensible via `AuthProvider`
|
|
11
|
-
- **AI**: Text generation (Together, Claude, OpenAI, Google, Groq, Fireworks) + image generation (Together, FAL, Google, Wavespeed) + embeddings + STT/TTS
|
|
11
|
+
- **AI**: Text generation (Together, Claude, OpenAI, Google, Groq, Fireworks, Kie) + image generation (Together, FAL, Google, Wavespeed, Kie) + embeddings + STT/TTS
|
|
12
|
+
- **Analytics**: EventCounter (high-throughput counters), EventLog (event capture), A/B experiments
|
|
12
13
|
- **Storage**: Cloudflare R2 / AWS S3 with presigned uploads
|
|
13
14
|
- **CLI**: `ugly-app` commands for dev, build, deploy, migrations, logs, and auth utilities
|
|
14
15
|
|
|
@@ -31,16 +32,22 @@ Entry point for the server. Creates an Express + WebSocket server with typed RPC
|
|
|
31
32
|
```typescript
|
|
32
33
|
import {
|
|
33
34
|
createApp,
|
|
35
|
+
createImageGen,
|
|
36
|
+
createTextGen,
|
|
34
37
|
createUserHelper,
|
|
38
|
+
eventLogCapture,
|
|
39
|
+
eventLogServerCapture,
|
|
35
40
|
getFeedbackHandlers,
|
|
41
|
+
getExperimentAssignments,
|
|
36
42
|
type AppConfigurator,
|
|
37
43
|
type RequestHandlers,
|
|
38
44
|
} from 'ugly-app';
|
|
39
45
|
import { dbDefaults } from 'ugly-app/shared';
|
|
40
46
|
import { requests } from '../shared/api';
|
|
47
|
+
import type { User } from '../shared/collections';
|
|
41
48
|
import { collections } from '../shared/collections';
|
|
49
|
+
import { experiments } from '../shared/experiments';
|
|
42
50
|
import { pages } from '../shared/pages';
|
|
43
|
-
import type { User } from '../shared/collections';
|
|
44
51
|
|
|
45
52
|
const userHelper = createUserHelper<User>(collections.user);
|
|
46
53
|
const maintainBotUserId = process.env.MAINTAIN_BOT_USER_ID ?? '';
|
|
@@ -49,10 +56,38 @@ const app = createApp(
|
|
|
49
56
|
{ requests },
|
|
50
57
|
{
|
|
51
58
|
...getFeedbackHandlers(maintainBotUserId),
|
|
59
|
+
|
|
52
60
|
getMe: async (userId: string) => {
|
|
53
61
|
const user = await userHelper.get(app.db, userId);
|
|
54
62
|
return { userId, email: user?.email, phone: user?.phone };
|
|
55
63
|
},
|
|
64
|
+
|
|
65
|
+
// Experiment bucketing + session start event
|
|
66
|
+
initSession: async (userId, { sessionId }) => {
|
|
67
|
+
const branches = getExperimentAssignments(userId, sessionId, experiments);
|
|
68
|
+
await eventLogServerCapture('SESSION_START', {}, sessionId, userId, branches);
|
|
69
|
+
return { branches };
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
// Generic event capture with experiment branch tagging
|
|
73
|
+
captureEvent: async (userId, { eventName, sessionId, properties }) => {
|
|
74
|
+
const branches = getExperimentAssignments(userId, sessionId, experiments);
|
|
75
|
+
const { eventId } = await eventLogCapture(
|
|
76
|
+
{ eventName, sessionId, userId, properties: properties ?? {}, experimentBranches: branches },
|
|
77
|
+
userId,
|
|
78
|
+
);
|
|
79
|
+
return { eventId };
|
|
80
|
+
},
|
|
81
|
+
|
|
82
|
+
textGen: async (userId, { model, messages }) => {
|
|
83
|
+
const text = await createTextGen(userId).generate(messages, { model });
|
|
84
|
+
return { text };
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
imageGen: async (userId, { model, prompt }) => {
|
|
88
|
+
const url = await createImageGen(userId).generate(prompt, { model });
|
|
89
|
+
return { url };
|
|
90
|
+
},
|
|
56
91
|
} satisfies RequestHandlers<typeof requests>,
|
|
57
92
|
collections,
|
|
58
93
|
(configurator: AppConfigurator) => {
|
|
@@ -637,14 +672,16 @@ Run `npm run db:init` to create/update indexes.
|
|
|
637
672
|
### Text generation
|
|
638
673
|
|
|
639
674
|
```typescript
|
|
640
|
-
import {
|
|
641
|
-
const textGen =
|
|
675
|
+
import { createTextGen } from 'ugly-app';
|
|
676
|
+
const textGen = createTextGen(userId);
|
|
642
677
|
|
|
643
678
|
const text = await textGen.generate(messages);
|
|
644
679
|
const json = await textGen.generateJson(schema, messages); // Zod schema, retries on parse failure
|
|
645
680
|
const result = await textGen.generateWithTools(messages, tools); // automatic tool-call loop
|
|
646
681
|
```
|
|
647
682
|
|
|
683
|
+
`createTextGen(userId, defaults?)` creates a client scoped to a user (for rate limiting and billing). Optional `defaults` set provider, model, temperature, etc.
|
|
684
|
+
|
|
648
685
|
| Provider | `provider` value | Default model | JSON | Tools | Vision |
|
|
649
686
|
|----------|-----------------|---------------|------|-------|--------|
|
|
650
687
|
| Together AI | `'together'` | Llama-4-Maverick-17B-128E | yes | yes | yes |
|
|
@@ -660,12 +697,14 @@ Use `provider: 'auto'` (default) to let the system pick based on requirements.
|
|
|
660
697
|
### Image generation
|
|
661
698
|
|
|
662
699
|
```typescript
|
|
663
|
-
import {
|
|
664
|
-
const imageGen =
|
|
700
|
+
import { createImageGen } from 'ugly-app';
|
|
701
|
+
const imageGen = createImageGen(userId);
|
|
665
702
|
|
|
666
703
|
const url = await imageGen.generate(prompt, { width: 1024, height: 1024 });
|
|
667
704
|
```
|
|
668
705
|
|
|
706
|
+
`createImageGen(userId, defaults?)` works the same way — user-scoped with optional defaults.
|
|
707
|
+
|
|
669
708
|
| Provider | `provider` value |
|
|
670
709
|
|----------|-----------------|
|
|
671
710
|
| Together AI (FLUX schnell) | `'together'` |
|
|
@@ -846,6 +885,104 @@ submitFeedback: authReq({
|
|
|
846
885
|
|
|
847
886
|
The framework enforces rate limits automatically before calling the handler.
|
|
848
887
|
|
|
888
|
+
### EventCounter
|
|
889
|
+
|
|
890
|
+
High-throughput counters aggregated into hourly buckets in MongoDB. Increments are instant (in-memory) and flushed every 60 seconds.
|
|
891
|
+
|
|
892
|
+
```typescript
|
|
893
|
+
import {
|
|
894
|
+
eventCounterIncrement,
|
|
895
|
+
startEventCounterFlush,
|
|
896
|
+
flushCountersToMongo,
|
|
897
|
+
eventCounterGetCounts,
|
|
898
|
+
eventCounterGetTopTypes,
|
|
899
|
+
} from 'ugly-app';
|
|
900
|
+
|
|
901
|
+
// Increment a counter (instant, no DB write)
|
|
902
|
+
eventCounterIncrement('api_getMe');
|
|
903
|
+
|
|
904
|
+
// Start periodic flush — call once at server startup
|
|
905
|
+
startEventCounterFlush();
|
|
906
|
+
|
|
907
|
+
// Manually flush (e.g. on graceful shutdown)
|
|
908
|
+
await flushCountersToMongo();
|
|
909
|
+
|
|
910
|
+
// Query counts (admin only)
|
|
911
|
+
const { counts } = await eventCounterGetCounts(
|
|
912
|
+
{ granularity: 'hours', intervals: 24, category: 'api' },
|
|
913
|
+
isAdmin,
|
|
914
|
+
);
|
|
915
|
+
|
|
916
|
+
// Query top counter types (admin only)
|
|
917
|
+
const { types } = await eventCounterGetTopTypes(
|
|
918
|
+
{ limit: 10, category: 'api' },
|
|
919
|
+
isAdmin,
|
|
920
|
+
);
|
|
921
|
+
```
|
|
922
|
+
|
|
923
|
+
Counter type names use a `category_name` convention (e.g. `api_getMe`, `ai_textGen`). Data is auto-expired after 30 days via MongoDB TTL.
|
|
924
|
+
|
|
925
|
+
### EventLog
|
|
926
|
+
|
|
927
|
+
Structured event capture for analytics. Events are stored in MongoDB with session, user, and experiment branch associations.
|
|
928
|
+
|
|
929
|
+
```typescript
|
|
930
|
+
import { eventLogCapture, eventLogServerCapture } from 'ugly-app';
|
|
931
|
+
|
|
932
|
+
// Capture an event (returns eventId)
|
|
933
|
+
const { eventId } = await eventLogCapture(
|
|
934
|
+
{
|
|
935
|
+
eventName: 'BUTTON_CLICK',
|
|
936
|
+
sessionId,
|
|
937
|
+
userId,
|
|
938
|
+
properties: { page: 'home', target: 'cta' },
|
|
939
|
+
experimentBranches: branches,
|
|
940
|
+
},
|
|
941
|
+
userId,
|
|
942
|
+
);
|
|
943
|
+
|
|
944
|
+
// Server-side shorthand (fire-and-forget, no eventId returned)
|
|
945
|
+
await eventLogServerCapture('SESSION_START', { source: 'web' }, sessionId, userId, branches);
|
|
946
|
+
```
|
|
947
|
+
|
|
948
|
+
Admin query functions: `eventLogGetList`, `eventLogGetCounts`, `eventLogGetTopEvents`, `eventLogGetTopUsers`, `eventLogGetTopSessions`, `eventLogGetUniqueUsersCounts`, `eventLogGetUniqueSessionsCounts`.
|
|
949
|
+
|
|
950
|
+
### Experiments (A/B testing)
|
|
951
|
+
|
|
952
|
+
Define experiments in `shared/experiments.ts` and use deterministic bucketing to assign users to branches.
|
|
953
|
+
|
|
954
|
+
```typescript
|
|
955
|
+
// shared/experiments.ts
|
|
956
|
+
import type { Experiment } from 'ugly-app/shared';
|
|
957
|
+
|
|
958
|
+
export const experiments: Experiment[] = [
|
|
959
|
+
{
|
|
960
|
+
id: 'onboarding-v2',
|
|
961
|
+
name: 'Onboarding V2',
|
|
962
|
+
description: 'Test new onboarding flow',
|
|
963
|
+
branches: [
|
|
964
|
+
{ id: 'control', name: 'Control', weight: 1 },
|
|
965
|
+
{ id: 'variant', name: 'Variant', weight: 1 },
|
|
966
|
+
],
|
|
967
|
+
events: ['ONBOARDING_COMPLETE', 'SIGNUP'],
|
|
968
|
+
active: true,
|
|
969
|
+
},
|
|
970
|
+
];
|
|
971
|
+
```
|
|
972
|
+
|
|
973
|
+
```typescript
|
|
974
|
+
// Server-side assignment
|
|
975
|
+
import { getExperimentAssignments, getExperimentBranch } from 'ugly-app';
|
|
976
|
+
|
|
977
|
+
// Get all branch assignments for a user/session (deterministic hash)
|
|
978
|
+
const branches = getExperimentAssignments(userId, sessionId, experiments);
|
|
979
|
+
|
|
980
|
+
// Get a single experiment branch
|
|
981
|
+
const branch = getExperimentBranch(userId, sessionId, experiment);
|
|
982
|
+
```
|
|
983
|
+
|
|
984
|
+
Shared helpers: `getActiveExperiments`, `getExperimentById`, `getExperimentBranch`, `getExperimentAssignments`. Server admin: `experimentGetMetrics` for per-branch analytics.
|
|
985
|
+
|
|
849
986
|
---
|
|
850
987
|
|
|
851
988
|
## Built-in endpoints
|
package/dist/cli/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const CLI_VERSION = "0.1.
|
|
1
|
+
export declare const CLI_VERSION = "0.1.78";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/cli/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DateRangePicker.d.ts","sourceRoot":"","sources":["../../../src/client/components/DateRangePicker.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"DateRangePicker.d.ts","sourceRoot":"","sources":["../../../src/client/components/DateRangePicker.tsx"],"names":[],"mappings":"AAMA,MAAM,MAAM,eAAe,GACvB,UAAU,GACV,aAAa,GACb,WAAW,GACX,YAAY,GACZ,QAAQ,CAAC;AAEb,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,eAAe,CAAC;IACxB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,cAAc,GAAG;IAC5D,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB,CAmBA;AAED,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;AAE9D,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,gBAAgB,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,2BAA2B,CACzC,SAAS,EAAE,cAAc,GACxB,WAAW,CA0Cb;AAqDD,wBAAgB,eAAe,CAAC,KAAK,EAAE;IACrC,KAAK,EAAE,cAAc,CAAC;IACtB,QAAQ,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;CAC3C,2CA+EA"}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
// Note: CSS import order matters — react-datepicker must come before any overrides
|
|
3
|
-
import 'react-datepicker/dist/react-datepicker.css';
|
|
4
2
|
import { useState } from 'react';
|
|
5
3
|
import { default as ReactDatePickerBase } from 'react-datepicker';
|
|
6
4
|
// Workaround for esModuleInterop + NodeNext moduleResolution with react-datepicker
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DateRangePicker.js","sourceRoot":"","sources":["../../../src/client/components/DateRangePicker.tsx"],"names":[],"mappings":";AAAA,
|
|
1
|
+
{"version":3,"file":"DateRangePicker.js","sourceRoot":"","sources":["../../../src/client/components/DateRangePicker.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,27 +1,54 @@
|
|
|
1
1
|
import type { AppRegistryBase, RequestInput, RequestOutput } from '../shared/Api.js';
|
|
2
|
-
import type {
|
|
2
|
+
import type { DBObject, UserBase } from '../shared/DB.js';
|
|
3
|
+
export type ConnectionState = 'connecting' | 'connected' | 'reconnecting' | 'disconnected' | 'idle-disconnected';
|
|
3
4
|
type Unsubscribe = () => void;
|
|
4
5
|
type TrackCallback<T> = (data: T) => void;
|
|
5
6
|
export interface AppSocket<R extends AppRegistryBase> {
|
|
6
7
|
connect(token: string): Promise<UserBase>;
|
|
7
8
|
request<K extends keyof R['requests']>(name: K, input: RequestInput<R['requests'][K]>): Promise<RequestOutput<R['requests'][K]>>;
|
|
8
9
|
getDoc<T extends DBObject>(collection: string, id: string): Promise<T | null>;
|
|
10
|
+
getDocs<T extends DBObject>(collection: string, filter?: Record<string, unknown>, options?: {
|
|
11
|
+
sort?: Record<string, 1 | -1>;
|
|
12
|
+
limit?: number;
|
|
13
|
+
skip?: number;
|
|
14
|
+
}): Promise<T[]>;
|
|
15
|
+
getQuery<T>(collection: string, pipeline: Record<string, unknown>[], options?: {
|
|
16
|
+
skip?: number;
|
|
17
|
+
limit?: number;
|
|
18
|
+
}): Promise<T[]>;
|
|
9
19
|
trackDoc<T extends DBObject>(collection: string, id: string, cb: TrackCallback<T | null>): Unsubscribe;
|
|
10
|
-
trackDocs<T extends DBObject
|
|
11
|
-
keys
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
where?: Partial<T>;
|
|
15
|
-
sort?: Partial<Record<keyof T, 1 | -1>>;
|
|
20
|
+
trackDocs<T extends DBObject>(collection: string, params: {
|
|
21
|
+
keys?: Record<string, string>;
|
|
22
|
+
filter?: Record<string, unknown>;
|
|
23
|
+
sort?: Record<string, 1 | -1>;
|
|
16
24
|
limit?: number;
|
|
17
25
|
skip?: number;
|
|
18
26
|
}, cb: TrackCallback<T[]>): Unsubscribe;
|
|
19
27
|
uploadFile(file: File, key: string): Promise<string>;
|
|
28
|
+
/** Fire-and-forget — no response expected. */
|
|
29
|
+
emit(type: string, data: object): void;
|
|
30
|
+
/** RPC — waits for a response message with the same id. */
|
|
31
|
+
send(type: string, data: object, timeout?: number): Promise<unknown>;
|
|
32
|
+
waitForConnection(timeout?: number): Promise<void>;
|
|
33
|
+
readonly connectionState: ConnectionState;
|
|
20
34
|
disconnect(): void;
|
|
21
35
|
}
|
|
22
36
|
export interface CreateSocketOptions<R extends AppRegistryBase> {
|
|
23
37
|
requests: R['requests'];
|
|
24
38
|
url?: string;
|
|
39
|
+
/** If provided, sends a 'buildId' check after connect and fires a
|
|
40
|
+
* 'version-mismatch' CustomEvent when the server returns a different value. */
|
|
41
|
+
buildId?: string;
|
|
42
|
+
/** Called for any message type not handled by the framework. */
|
|
43
|
+
onCustomMessage?: (msg: {
|
|
44
|
+
type: string;
|
|
45
|
+
data?: unknown;
|
|
46
|
+
[key: string]: unknown;
|
|
47
|
+
}) => void;
|
|
48
|
+
/** Called on every connect/reconnect to get extra URL query params (e.g. auth token). */
|
|
49
|
+
getUrlParams?: () => Record<string, string>;
|
|
50
|
+
/** JSON parse reviver applied to every incoming message. */
|
|
51
|
+
messageReviver?: (key: string, value: unknown) => unknown;
|
|
25
52
|
}
|
|
26
53
|
export declare function createSocket<R extends AppRegistryBase>(opts: CreateSocketOptions<R>): AppSocket<R>;
|
|
27
54
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createSocket.d.ts","sourceRoot":"","sources":["../../src/client/createSocket.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EACZ,aAAa,EACd,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"createSocket.d.ts","sourceRoot":"","sources":["../../src/client/createSocket.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EACZ,aAAa,EACd,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE1D,MAAM,MAAM,eAAe,GACvB,YAAY,GACZ,WAAW,GACX,cAAc,GACd,cAAc,GACd,mBAAmB,CAAC;AAExB,KAAK,WAAW,GAAG,MAAM,IAAI,CAAC;AAC9B,KAAK,aAAa,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC;AAE1C,MAAM,WAAW,SAAS,CAAC,CAAC,SAAS,eAAe;IAClD,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC1C,OAAO,CAAC,CAAC,SAAS,MAAM,CAAC,CAAC,UAAU,CAAC,EACnC,IAAI,EAAE,CAAC,EACP,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,GACpC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5C,MAAM,CAAC,CAAC,SAAS,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAC9E,OAAO,CAAC,CAAC,SAAS,QAAQ,EACxB,UAAU,EAAE,MAAM,EAClB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GACzE,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;IAChB,QAAQ,CAAC,CAAC,EACR,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EACnC,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAC1C,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;IAChB,QAAQ,CAAC,CAAC,SAAS,QAAQ,EACzB,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,aAAa,CAAC,CAAC,GAAG,IAAI,CAAC,GAC1B,WAAW,CAAC;IACf,SAAS,CAAC,CAAC,SAAS,QAAQ,EAC1B,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE;QACN,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC9B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACjC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,EACD,EAAE,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,GACrB,WAAW,CAAC;IACf,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,8CAA8C;IAC9C,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,2DAA2D;IAC3D,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACrE,iBAAiB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;IAC1C,UAAU,IAAI,IAAI,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB,CAAC,CAAC,SAAS,eAAe;IAC5D,QAAQ,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;oFACgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gEAAgE;IAChE,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE;QACtB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,CAAC,EAAE,OAAO,CAAC;QACf,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,KAAK,IAAI,CAAC;IACX,yFAAyF;IACzF,YAAY,CAAC,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,4DAA4D;IAC5D,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;CAC3D;AAED,wBAAgB,YAAY,CAAC,CAAC,SAAS,eAAe,EACpD,IAAI,EAAE,mBAAmB,CAAC,CAAC,CAAC,GAC3B,SAAS,CAAC,CAAC,CAAC,CA2jBd"}
|