@webda/debug 4.0.0-beta.3

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 (66) hide show
  1. package/LICENSE +166 -0
  2. package/README.md +95 -0
  3. package/lib/bodycapture.d.ts +66 -0
  4. package/lib/bodycapture.js +162 -0
  5. package/lib/bodycapture.js.map +1 -0
  6. package/lib/debugservice.service.d.ts +166 -0
  7. package/lib/debugservice.service.js +609 -0
  8. package/lib/debugservice.service.js.map +1 -0
  9. package/lib/index.d.ts +7 -0
  10. package/lib/index.js +7 -0
  11. package/lib/index.js.map +1 -0
  12. package/lib/introspection.d.ts +115 -0
  13. package/lib/introspection.js +260 -0
  14. package/lib/introspection.js.map +1 -0
  15. package/lib/logbuffer.d.ts +75 -0
  16. package/lib/logbuffer.js +98 -0
  17. package/lib/logbuffer.js.map +1 -0
  18. package/lib/requestlog.d.ts +181 -0
  19. package/lib/requestlog.js +153 -0
  20. package/lib/requestlog.js.map +1 -0
  21. package/lib/tui/client.d.ts +165 -0
  22. package/lib/tui/client.js +220 -0
  23. package/lib/tui/client.js.map +1 -0
  24. package/lib/tui/panels/config.d.ts +79 -0
  25. package/lib/tui/panels/config.js +291 -0
  26. package/lib/tui/panels/config.js.map +1 -0
  27. package/lib/tui/panels/logs.d.ts +106 -0
  28. package/lib/tui/panels/logs.js +342 -0
  29. package/lib/tui/panels/logs.js.map +1 -0
  30. package/lib/tui/panels/models.d.ts +47 -0
  31. package/lib/tui/panels/models.js +193 -0
  32. package/lib/tui/panels/models.js.map +1 -0
  33. package/lib/tui/panels/operations.d.ts +55 -0
  34. package/lib/tui/panels/operations.js +241 -0
  35. package/lib/tui/panels/operations.js.map +1 -0
  36. package/lib/tui/panels/panel.d.ts +55 -0
  37. package/lib/tui/panels/panel.js +31 -0
  38. package/lib/tui/panels/panel.js.map +1 -0
  39. package/lib/tui/panels/requests.d.ts +156 -0
  40. package/lib/tui/panels/requests.js +512 -0
  41. package/lib/tui/panels/requests.js.map +1 -0
  42. package/lib/tui/panels/routes.d.ts +45 -0
  43. package/lib/tui/panels/routes.js +154 -0
  44. package/lib/tui/panels/routes.js.map +1 -0
  45. package/lib/tui/panels/services.d.ts +49 -0
  46. package/lib/tui/panels/services.js +266 -0
  47. package/lib/tui/panels/services.js.map +1 -0
  48. package/lib/tui/tui.d.ts +58 -0
  49. package/lib/tui/tui.js +236 -0
  50. package/lib/tui/tui.js.map +1 -0
  51. package/package.json +60 -0
  52. package/webui/app.js +177 -0
  53. package/webui/components/logs.js +128 -0
  54. package/webui/components/model-graph.js +292 -0
  55. package/webui/components/models.js +213 -0
  56. package/webui/components/operations.js +315 -0
  57. package/webui/components/requests.js +264 -0
  58. package/webui/components/schema-form.js +268 -0
  59. package/webui/components/services.js +248 -0
  60. package/webui/index.html +22 -0
  61. package/webui/logo.svg +1 -0
  62. package/webui/styles.css +685 -0
  63. package/webui/vendor/htm.js +1 -0
  64. package/webui/vendor/preact-hooks.js +2 -0
  65. package/webui/vendor/preact.js +2 -0
  66. package/webui/webda.png +0 -0
@@ -0,0 +1,220 @@
1
+ import { WebSocket } from "ws";
2
+ /**
3
+ * HTTP + WebSocket client for the debug server API.
4
+ *
5
+ * Connects to the debug server started by `webda debug` and provides
6
+ * typed methods for each introspection endpoint, plus a reconnecting
7
+ * WebSocket subscription for live request events.
8
+ */
9
+ export class DebugClient {
10
+ /**
11
+ * Creates a new DebugClient.
12
+ *
13
+ * @param baseUrl - Base URL of the debug server, e.g. "http://localhost:18181"
14
+ */
15
+ constructor(baseUrl = "http://localhost:18181") {
16
+ /** Whether the client should try to reconnect */
17
+ this.shouldReconnect = false;
18
+ /** Current reconnect delay in ms */
19
+ this.reconnectDelay = 1000;
20
+ /** Maximum reconnect delay in ms */
21
+ this.maxReconnectDelay = 30000;
22
+ /** Event subscribers */
23
+ this.subscribers = new Set();
24
+ /** Connection status */
25
+ this._connected = false;
26
+ this.baseUrl = baseUrl.replace(/\/$/, "");
27
+ }
28
+ /**
29
+ * Whether the WebSocket is currently connected.
30
+ * @returns true if the WebSocket connection is open
31
+ */
32
+ get connected() {
33
+ return this._connected;
34
+ }
35
+ /**
36
+ * Fetch parsed JSON from a debug API endpoint.
37
+ *
38
+ * @param path - API path starting with /
39
+ * @returns Parsed JSON response
40
+ */
41
+ async fetchJson(path) {
42
+ const res = await fetch(`${this.baseUrl}${path}`);
43
+ if (!res.ok) {
44
+ throw new Error(`HTTP ${res.status}: ${res.statusText}`);
45
+ }
46
+ return res.json();
47
+ }
48
+ /**
49
+ * Fetch all registered models.
50
+ * @returns array of model metadata objects
51
+ */
52
+ async getModels() {
53
+ return this.fetchJson("/api/models");
54
+ }
55
+ /**
56
+ * Fetch a single model by identifier.
57
+ *
58
+ * @param id - Fully-qualified model identifier
59
+ * @returns model metadata object
60
+ */
61
+ async getModel(id) {
62
+ return this.fetchJson(`/api/models/${encodeURIComponent(id)}`);
63
+ }
64
+ /**
65
+ * Fetch all registered services.
66
+ * @returns array of service info objects
67
+ */
68
+ async getServices() {
69
+ return this.fetchJson("/api/services");
70
+ }
71
+ /**
72
+ * Fetch all registered operations.
73
+ * @returns array of operation info objects
74
+ */
75
+ async getOperations() {
76
+ return this.fetchJson("/api/operations");
77
+ }
78
+ /**
79
+ * Fetch all registered routes.
80
+ * @returns array of route info objects
81
+ */
82
+ async getRoutes() {
83
+ return this.fetchJson("/api/routes");
84
+ }
85
+ /**
86
+ * Fetch the resolved application configuration.
87
+ * @returns resolved configuration record
88
+ */
89
+ async getConfig() {
90
+ return this.fetchJson("/api/config");
91
+ }
92
+ /**
93
+ * Fetch the OpenAPI specification.
94
+ * @returns OpenAPI 3.0.3 document
95
+ */
96
+ async getOpenAPI() {
97
+ return this.fetchJson("/api/openapi");
98
+ }
99
+ /**
100
+ * Fetch recent request log entries (summary fields only — no headers/bodies).
101
+ * @returns array of request log entry summaries
102
+ */
103
+ async getRequests() {
104
+ return this.fetchJson("/api/requests");
105
+ }
106
+ /**
107
+ * Fetch the full detail of a single request by id, including captured
108
+ * headers, bodies, and any error.
109
+ *
110
+ * @param id - The request id (as returned in the summary list).
111
+ * @returns The detailed request entry.
112
+ */
113
+ async getRequestDetail(id) {
114
+ return this.fetchJson(`/api/requests/${encodeURIComponent(id)}`);
115
+ }
116
+ /**
117
+ * Fetch recent application log entries.
118
+ * @returns array of log entries
119
+ */
120
+ async getLogs() {
121
+ return this.fetchJson("/api/logs");
122
+ }
123
+ /**
124
+ * Fetch application info (package name, version, working directory).
125
+ * @returns project information record
126
+ */
127
+ async getAppInfo() {
128
+ return this.fetchJson("/api/info");
129
+ }
130
+ /**
131
+ * Search application log entries by query string.
132
+ *
133
+ * @param query - search text to filter logs
134
+ * @returns array of matching log entries
135
+ */
136
+ async searchLogs(query) {
137
+ return this.fetchJson(`/api/logs?q=${encodeURIComponent(query)}`);
138
+ }
139
+ /**
140
+ * Subscribe to WebSocket events.
141
+ *
142
+ * @param callback - Called for each event received
143
+ * @returns Unsubscribe function
144
+ */
145
+ onEvent(callback) {
146
+ this.subscribers.add(callback);
147
+ return () => this.subscribers.delete(callback);
148
+ }
149
+ /**
150
+ * Connect to the debug server WebSocket and begin receiving events.
151
+ * Automatically reconnects with exponential backoff on disconnect.
152
+ */
153
+ connectWebSocket() {
154
+ this.shouldReconnect = true;
155
+ this.doConnect();
156
+ }
157
+ /**
158
+ * Internal: establish the WebSocket connection.
159
+ */
160
+ doConnect() {
161
+ const wsUrl = this.baseUrl.replace(/^http/, "ws") + "/ws";
162
+ try {
163
+ this.ws = new WebSocket(wsUrl);
164
+ }
165
+ catch {
166
+ this.scheduleReconnect();
167
+ return;
168
+ }
169
+ this.ws.on("open", () => {
170
+ this._connected = true;
171
+ this.reconnectDelay = 1000;
172
+ });
173
+ this.ws.on("message", (data) => {
174
+ try {
175
+ const event = JSON.parse(data.toString());
176
+ for (const cb of this.subscribers) {
177
+ cb(event);
178
+ }
179
+ }
180
+ catch {
181
+ // Ignore malformed messages
182
+ }
183
+ });
184
+ this.ws.on("close", () => {
185
+ this._connected = false;
186
+ this.scheduleReconnect();
187
+ });
188
+ this.ws.on("error", () => {
189
+ this._connected = false;
190
+ // close event will fire after error, triggering reconnect
191
+ });
192
+ }
193
+ /**
194
+ * Schedule a reconnection attempt with exponential backoff.
195
+ */
196
+ scheduleReconnect() {
197
+ if (!this.shouldReconnect)
198
+ return;
199
+ this.reconnectTimer = setTimeout(() => {
200
+ this.reconnectDelay = Math.min(this.reconnectDelay * 2, this.maxReconnectDelay);
201
+ this.doConnect();
202
+ }, this.reconnectDelay);
203
+ }
204
+ /**
205
+ * Disconnect the WebSocket and stop reconnecting.
206
+ */
207
+ disconnect() {
208
+ this.shouldReconnect = false;
209
+ if (this.reconnectTimer) {
210
+ clearTimeout(this.reconnectTimer);
211
+ this.reconnectTimer = undefined;
212
+ }
213
+ if (this.ws) {
214
+ this.ws.close();
215
+ this.ws = undefined;
216
+ }
217
+ this._connected = false;
218
+ }
219
+ }
220
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/tui/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,79 @@
1
+ import type { Panel } from "./panel.js";
2
+ import type { DebugClient } from "../client.js";
3
+ /**
4
+ * Config panel: displays the resolved application configuration
5
+ * as an interactive, collapsible JSON tree with syntax highlighting.
6
+ *
7
+ * Navigate with Up/Down arrows, toggle collapse with Enter or Space.
8
+ * Top-level keys start expanded; deeper levels start collapsed.
9
+ */
10
+ export declare class ConfigPanel implements Panel {
11
+ private client;
12
+ name: string;
13
+ private nodes;
14
+ private collapsed;
15
+ private cursor;
16
+ private scrollOffset;
17
+ private visibleRows;
18
+ /**
19
+ * @param client - Debug API client
20
+ */
21
+ constructor(client: DebugClient);
22
+ /**
23
+ * Fetch configuration and build the tree.
24
+ */
25
+ refresh(): Promise<void>;
26
+ /**
27
+ * Recursively build a flat list of tree nodes from a JSON value.
28
+ *
29
+ * @param obj - The value to process
30
+ * @param depth - Current nesting depth
31
+ * @param parentPath - Dot-separated path of the parent
32
+ * @param key - Property name if this is an object property
33
+ * @param index - Array index if this is an array element
34
+ */
35
+ private buildTree;
36
+ /**
37
+ * Compute the list of visible nodes by filtering out
38
+ * children of collapsed nodes.
39
+ *
40
+ * @returns array of nodes that should be rendered
41
+ */
42
+ private getVisibleNodes;
43
+ /**
44
+ * Handle keyboard input for navigation and toggling.
45
+ *
46
+ * @param key - key name from terminal-kit
47
+ */
48
+ onKey(key: string): void;
49
+ /**
50
+ * Render the JSON tree with syntax highlighting and collapse indicators.
51
+ *
52
+ * @param term - terminal-kit instance
53
+ * @param startRow - first available row
54
+ * @param endRow - last available row
55
+ * @param width - terminal width in columns
56
+ */
57
+ render(term: any, startRow: number, endRow: number, width: number): void;
58
+ /**
59
+ * Render a single tree node with indentation, collapse indicator,
60
+ * key, and value with syntax-highlighted colors.
61
+ *
62
+ * @param term - terminal-kit instance
63
+ * @param node - the tree node to render
64
+ * @param width - terminal width
65
+ * @param highlighted - whether this line is the cursor line
66
+ */
67
+ private renderNode;
68
+ /**
69
+ * Render a leaf value with type-appropriate coloring.
70
+ *
71
+ * @param term - terminal-kit instance
72
+ * @param value - the value to render
73
+ */
74
+ private renderValue;
75
+ /**
76
+ * Clean up panel resources.
77
+ */
78
+ destroy(): void;
79
+ }
@@ -0,0 +1,291 @@
1
+ /**
2
+ * Config panel: displays the resolved application configuration
3
+ * as an interactive, collapsible JSON tree with syntax highlighting.
4
+ *
5
+ * Navigate with Up/Down arrows, toggle collapse with Enter or Space.
6
+ * Top-level keys start expanded; deeper levels start collapsed.
7
+ */
8
+ export class ConfigPanel {
9
+ /**
10
+ * @param client - Debug API client
11
+ */
12
+ constructor(client) {
13
+ this.client = client;
14
+ this.name = "Config";
15
+ this.nodes = [];
16
+ this.collapsed = new Set();
17
+ this.cursor = 0;
18
+ this.scrollOffset = 0;
19
+ this.visibleRows = 0;
20
+ }
21
+ /**
22
+ * Fetch configuration and build the tree.
23
+ */
24
+ async refresh() {
25
+ try {
26
+ const config = await this.client.getConfig();
27
+ this.nodes = [];
28
+ this.collapsed = new Set();
29
+ this.buildTree(config, 0, "root");
30
+ this.cursor = Math.min(this.cursor, Math.max(0, this.getVisibleNodes().length - 1));
31
+ }
32
+ catch {
33
+ this.nodes = [];
34
+ this.collapsed = new Set();
35
+ }
36
+ }
37
+ /**
38
+ * Recursively build a flat list of tree nodes from a JSON value.
39
+ *
40
+ * @param obj - The value to process
41
+ * @param depth - Current nesting depth
42
+ * @param parentPath - Dot-separated path of the parent
43
+ * @param key - Property name if this is an object property
44
+ * @param index - Array index if this is an array element
45
+ */
46
+ buildTree(obj, depth, parentPath, key, index) {
47
+ const pathSegment = key !== undefined ? key : index !== undefined ? String(index) : "root";
48
+ const path = parentPath === "" ? pathSegment : `${parentPath}.${pathSegment}`;
49
+ const isObject = obj !== null && typeof obj === "object" && !Array.isArray(obj);
50
+ const isArray = Array.isArray(obj);
51
+ const hasChildren = isObject || isArray;
52
+ const childCount = hasChildren ? (isArray ? obj.length : Object.keys(obj).length) : 0;
53
+ const node = {
54
+ key,
55
+ index,
56
+ value: obj,
57
+ depth,
58
+ collapsed: false,
59
+ hasChildren,
60
+ path,
61
+ childCount,
62
+ isArray
63
+ };
64
+ this.nodes.push(node);
65
+ if (hasChildren) {
66
+ if (isArray) {
67
+ for (let i = 0; i < obj.length; i++) {
68
+ this.buildTree(obj[i], depth + 1, path, undefined, i);
69
+ }
70
+ }
71
+ else {
72
+ const keys = Object.keys(obj);
73
+ for (const k of keys) {
74
+ this.buildTree(obj[k], depth + 1, path, k);
75
+ }
76
+ }
77
+ }
78
+ }
79
+ /**
80
+ * Compute the list of visible nodes by filtering out
81
+ * children of collapsed nodes.
82
+ *
83
+ * @returns array of nodes that should be rendered
84
+ */
85
+ getVisibleNodes() {
86
+ const visible = [];
87
+ let skipUntilDepth = -1;
88
+ for (const node of this.nodes) {
89
+ // If we are skipping children of a collapsed node
90
+ if (skipUntilDepth >= 0 && node.depth > skipUntilDepth) {
91
+ continue;
92
+ }
93
+ skipUntilDepth = -1;
94
+ visible.push(node);
95
+ // If this node is collapsed, skip its children
96
+ if (node.hasChildren && this.collapsed.has(node.path)) {
97
+ skipUntilDepth = node.depth;
98
+ }
99
+ }
100
+ return visible;
101
+ }
102
+ /**
103
+ * Handle keyboard input for navigation and toggling.
104
+ *
105
+ * @param key - key name from terminal-kit
106
+ */
107
+ onKey(key) {
108
+ const visible = this.getVisibleNodes();
109
+ if (visible.length === 0)
110
+ return;
111
+ switch (key) {
112
+ case "UP":
113
+ if (this.cursor > 0)
114
+ this.cursor--;
115
+ break;
116
+ case "DOWN":
117
+ if (this.cursor < visible.length - 1)
118
+ this.cursor++;
119
+ break;
120
+ case "PAGE_UP":
121
+ this.cursor = Math.max(0, this.cursor - this.visibleRows);
122
+ break;
123
+ case "PAGE_DOWN":
124
+ this.cursor = Math.min(visible.length - 1, this.cursor + this.visibleRows);
125
+ break;
126
+ case "HOME":
127
+ this.cursor = 0;
128
+ this.scrollOffset = 0;
129
+ break;
130
+ case "END":
131
+ this.cursor = visible.length - 1;
132
+ break;
133
+ case "ENTER":
134
+ case " ": {
135
+ const node = visible[this.cursor];
136
+ if (node?.hasChildren) {
137
+ if (this.collapsed.has(node.path)) {
138
+ this.collapsed.delete(node.path);
139
+ node.collapsed = false;
140
+ }
141
+ else {
142
+ this.collapsed.add(node.path);
143
+ node.collapsed = true;
144
+ }
145
+ }
146
+ break;
147
+ }
148
+ }
149
+ // Adjust scroll to keep cursor visible
150
+ if (this.cursor < this.scrollOffset) {
151
+ this.scrollOffset = this.cursor;
152
+ }
153
+ else if (this.cursor >= this.scrollOffset + this.visibleRows) {
154
+ this.scrollOffset = this.cursor - this.visibleRows + 1;
155
+ }
156
+ }
157
+ /**
158
+ * Render the JSON tree with syntax highlighting and collapse indicators.
159
+ *
160
+ * @param term - terminal-kit instance
161
+ * @param startRow - first available row
162
+ * @param endRow - last available row
163
+ * @param width - terminal width in columns
164
+ */
165
+ render(term, startRow, endRow, width) {
166
+ this.visibleRows = endRow - startRow;
167
+ if (this.nodes.length === 0) {
168
+ term.moveTo(1, startRow);
169
+ term.eraseLine();
170
+ term(" No configuration loaded.");
171
+ return;
172
+ }
173
+ const visible = this.getVisibleNodes();
174
+ // Clamp cursor/scroll in case the tree changed
175
+ if (this.cursor >= visible.length) {
176
+ this.cursor = Math.max(0, visible.length - 1);
177
+ }
178
+ if (this.scrollOffset > this.cursor) {
179
+ this.scrollOffset = this.cursor;
180
+ }
181
+ for (let i = 0; i < this.visibleRows; i++) {
182
+ const idx = this.scrollOffset + i;
183
+ const row = startRow + i;
184
+ term.moveTo(1, row);
185
+ term.eraseLine();
186
+ if (idx >= visible.length)
187
+ continue;
188
+ const node = visible[idx];
189
+ const isCurrent = idx === this.cursor;
190
+ if (isCurrent) {
191
+ term.bgGray();
192
+ }
193
+ this.renderNode(term, node, width, isCurrent);
194
+ if (isCurrent) {
195
+ // Fill rest of line with highlight background
196
+ term.styleReset();
197
+ }
198
+ }
199
+ }
200
+ /**
201
+ * Render a single tree node with indentation, collapse indicator,
202
+ * key, and value with syntax-highlighted colors.
203
+ *
204
+ * @param term - terminal-kit instance
205
+ * @param node - the tree node to render
206
+ * @param width - terminal width
207
+ * @param highlighted - whether this line is the cursor line
208
+ */
209
+ renderNode(term, node, width, highlighted) {
210
+ const indent = " ".repeat(node.depth);
211
+ term(indent);
212
+ if (node.hasChildren) {
213
+ // Collapse indicator
214
+ const indicator = this.collapsed.has(node.path) ? "\u25B6 " : "\u25BC ";
215
+ term.white(indicator);
216
+ // Key or index label
217
+ if (node.key !== undefined) {
218
+ term.cyan(node.key);
219
+ term(": ");
220
+ }
221
+ else if (node.index !== undefined) {
222
+ term.dim(`[${node.index}]`);
223
+ term(": ");
224
+ }
225
+ // Collapsed summary or opening bracket
226
+ if (this.collapsed.has(node.path)) {
227
+ if (node.isArray) {
228
+ term.dim(`[...] (${node.childCount} items)`);
229
+ }
230
+ else {
231
+ term.dim(`{...} (${node.childCount} keys)`);
232
+ }
233
+ }
234
+ else {
235
+ term.dim(node.isArray ? "[" : "{");
236
+ }
237
+ }
238
+ else {
239
+ // Leaf node: spaces in place of collapse indicator
240
+ term(" ");
241
+ // Key or index label
242
+ if (node.key !== undefined) {
243
+ term.cyan(node.key);
244
+ term(": ");
245
+ }
246
+ else if (node.index !== undefined) {
247
+ term.dim(`[${node.index}]`);
248
+ term(": ");
249
+ }
250
+ // Value with type-appropriate color
251
+ this.renderValue(term, node.value);
252
+ }
253
+ if (highlighted) {
254
+ term.styleReset();
255
+ }
256
+ }
257
+ /**
258
+ * Render a leaf value with type-appropriate coloring.
259
+ *
260
+ * @param term - terminal-kit instance
261
+ * @param value - the value to render
262
+ */
263
+ renderValue(term, value) {
264
+ if (value === null) {
265
+ term.red("null");
266
+ }
267
+ else if (value === undefined) {
268
+ term.red("undefined");
269
+ }
270
+ else if (typeof value === "string") {
271
+ term.green(`"${value}"`);
272
+ }
273
+ else if (typeof value === "number") {
274
+ term.yellow(String(value));
275
+ }
276
+ else if (typeof value === "boolean") {
277
+ term.magenta(String(value));
278
+ }
279
+ else {
280
+ term(String(value));
281
+ }
282
+ }
283
+ /**
284
+ * Clean up panel resources.
285
+ */
286
+ destroy() {
287
+ this.nodes = [];
288
+ this.collapsed.clear();
289
+ }
290
+ }
291
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/tui/panels/config.ts"],"names":[],"mappings":"AA2BA;;;;;;GAMG;AACH,MAAM,OAAO,WAAW;IAQtB;;OAEG;IACH,YAAoB,MAAmB;QAAnB,WAAM,GAAN,MAAM,CAAa;QAVvC,SAAI,GAAG,QAAQ,CAAC;QACR,UAAK,GAAmB,EAAE,CAAC;QAC3B,cAAS,GAAgB,IAAI,GAAG,EAAE,CAAC;QACnC,WAAM,GAAG,CAAC,CAAC;QACX,iBAAY,GAAG,CAAC,CAAC;QACjB,gBAAW,GAAG,CAAC,CAAC;IAKkB,CAAC;IAE3C;;OAEG;IACH,KAAK,CAAC,OAAO;QACX,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;YAC7C,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;YAChB,IAAI,CAAC,SAAS,GAAG,IAAI,GAAG,EAAE,CAAC;YAC3B,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC;YAElC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,eAAe,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QACtF,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;YAChB,IAAI,CAAC,SAAS,GAAG,IAAI,GAAG,EAAE,CAAC;QAC7B,CAAC;IACH,CAAC;IAED;;;;;;;;OAQG;IACK,SAAS,CAAC,GAAQ,EAAE,KAAa,EAAE,UAAkB,EAAE,GAAY,EAAE,KAAc;QACzF,MAAM,WAAW,GAAG,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QAC3F,MAAM,IAAI,GAAG,UAAU,KAAK,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,UAAU,IAAI,WAAW,EAAE,CAAC;QAE9E,MAAM,QAAQ,GAAG,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAChF,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACnC,MAAM,WAAW,GAAG,QAAQ,IAAI,OAAO,CAAC;QACxC,MAAM,UAAU,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAEtF,MAAM,IAAI,GAAiB;YACzB,GAAG;YACH,KAAK;YACL,KAAK,EAAE,GAAG;YACV,KAAK;YACL,SAAS,EAAE,KAAK;YAChB,WAAW;YACX,IAAI;YACJ,UAAU;YACV,OAAO;SACR,CAAC;QACF,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEtB,IAAI,WAAW,EAAE,CAAC;YAChB,IAAI,OAAO,EAAE,CAAC;gBACZ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;oBACpC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;gBACxD,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBAC9B,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;oBACrB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;gBAC7C,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACK,eAAe;QACrB,MAAM,OAAO,GAAmB,EAAE,CAAC;QACnC,IAAI,cAAc,GAAG,CAAC,CAAC,CAAC;QAExB,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC9B,kDAAkD;YAClD,IAAI,cAAc,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,GAAG,cAAc,EAAE,CAAC;gBACvD,SAAS;YACX,CAAC;YACD,cAAc,GAAG,CAAC,CAAC,CAAC;YAEpB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAEnB,+CAA+C;YAC/C,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBACtD,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC;YAC9B,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,GAAW;QACf,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;QACvC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAEjC,QAAQ,GAAG,EAAE,CAAC;YACZ,KAAK,IAAI;gBACP,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;oBAAE,IAAI,CAAC,MAAM,EAAE,CAAC;gBACnC,MAAM;YACR,KAAK,MAAM;gBACT,IAAI,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC;oBAAE,IAAI,CAAC,MAAM,EAAE,CAAC;gBACpD,MAAM;YACR,KAAK,SAAS;gBACZ,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC;gBAC1D,MAAM;YACR,KAAK,WAAW;gBACd,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC;gBAC3E,MAAM;YACR,KAAK,MAAM;gBACT,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;gBAChB,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC;gBACtB,MAAM;YACR,KAAK,KAAK;gBACR,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;gBACjC,MAAM;YACR,KAAK,OAAO,CAAC;YACb,KAAK,GAAG,EAAE,CAAC;gBACT,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBAClC,IAAI,IAAI,EAAE,WAAW,EAAE,CAAC;oBACtB,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;wBAClC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;wBACjC,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;oBACzB,CAAC;yBAAM,CAAC;wBACN,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;wBAC9B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;oBACxB,CAAC;gBACH,CAAC;gBACD,MAAM;YACR,CAAC;QACH,CAAC;QAED,uCAAuC;QACvC,IAAI,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;YACpC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC;QAClC,CAAC;aAAM,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;YAC/D,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC;QACzD,CAAC;IACH,CAAC;IAED;;;;;;;OAOG;IACH,MAAM,CAAC,IAAS,EAAE,QAAgB,EAAE,MAAc,EAAE,KAAa;QAC/D,IAAI,CAAC,WAAW,GAAG,MAAM,GAAG,QAAQ,CAAC;QAErC,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5B,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;YACzB,IAAI,CAAC,SAAS,EAAE,CAAC;YACjB,IAAI,CAAC,4BAA4B,CAAC,CAAC;YACnC,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;QAEvC,+CAA+C;QAC/C,IAAI,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YAClC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAChD,CAAC;QACD,IAAI,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;YACpC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC;QAClC,CAAC;QAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,EAAE,EAAE,CAAC;YAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC;YAClC,MAAM,GAAG,GAAG,QAAQ,GAAG,CAAC,CAAC;YACzB,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;YACpB,IAAI,CAAC,SAAS,EAAE,CAAC;YAEjB,IAAI,GAAG,IAAI,OAAO,CAAC,MAAM;gBAAE,SAAS;YAEpC,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;YAC1B,MAAM,SAAS,GAAG,GAAG,KAAK,IAAI,CAAC,MAAM,CAAC;YAEtC,IAAI,SAAS,EAAE,CAAC;gBACd,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,CAAC;YAED,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;YAE9C,IAAI,SAAS,EAAE,CAAC;gBACd,8CAA8C;gBAC9C,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;;;;;;OAQG;IACK,UAAU,CAAC,IAAS,EAAE,IAAkB,EAAE,KAAa,EAAE,WAAoB;QACnF,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvC,IAAI,CAAC,MAAM,CAAC,CAAC;QAEb,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,qBAAqB;YACrB,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;YACxE,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;YAEtB,qBAAqB;YACrB,IAAI,IAAI,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;gBAC3B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBACpB,IAAI,CAAC,IAAI,CAAC,CAAC;YACb,CAAC;iBAAM,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;gBACpC,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;gBAC5B,IAAI,CAAC,IAAI,CAAC,CAAC;YACb,CAAC;YAED,uCAAuC;YACvC,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBAClC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;oBACjB,IAAI,CAAC,GAAG,CAAC,UAAU,IAAI,CAAC,UAAU,SAAS,CAAC,CAAC;gBAC/C,CAAC;qBAAM,CAAC;oBACN,IAAI,CAAC,GAAG,CAAC,UAAU,IAAI,CAAC,UAAU,QAAQ,CAAC,CAAC;gBAC9C,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YACrC,CAAC;QACH,CAAC;aAAM,CAAC;YACN,mDAAmD;YACnD,IAAI,CAAC,IAAI,CAAC,CAAC;YAEX,qBAAqB;YACrB,IAAI,IAAI,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;gBAC3B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBACpB,IAAI,CAAC,IAAI,CAAC,CAAC;YACb,CAAC;iBAAM,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;gBACpC,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;gBAC5B,IAAI,CAAC,IAAI,CAAC,CAAC;YACb,CAAC;YAED,oCAAoC;YACpC,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QACrC,CAAC;QAED,IAAI,WAAW,EAAE,CAAC;YAChB,IAAI,CAAC,UAAU,EAAE,CAAC;QACpB,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACK,WAAW,CAAC,IAAS,EAAE,KAAU;QACvC,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACnB,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACnB,CAAC;aAAM,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YAC/B,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACxB,CAAC;aAAM,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YACrC,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC;QAC3B,CAAC;aAAM,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YACrC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC7B,CAAC;aAAM,IAAI,OAAO,KAAK,KAAK,SAAS,EAAE,CAAC;YACtC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC9B,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IAED;;OAEG;IACH,OAAO;QACL,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;QAChB,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;IACzB,CAAC;CACF"}