@bpmnkit/casen-report 0.1.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.
@@ -0,0 +1,5 @@
1
+
2
+
3
+ > @bpmnkit/casen-report@0.1.0 build /home/adam/github.com/bpmnkit/monorepo/plugins-cli/casen-report
4
+ > tsc
5
+
@@ -0,0 +1,6 @@
1
+
2
+
3
+ > @bpmnkit/casen-report@0.1.0 check /home/adam/github.com/bpmnkit/monorepo/plugins-cli/casen-report
4
+ > biome check .
5
+
6
+ Checked 6 files in 26ms. No fixes applied.
@@ -0,0 +1,6 @@
1
+
2
+
3
+ > @bpmnkit/casen-report@0.1.0 test /home/adam/github.com/bpmnkit/monorepo/plugins-cli/casen-report
4
+ > echo "no tests"
5
+
6
+ no tests
@@ -0,0 +1,5 @@
1
+
2
+
3
+ > @bpmnkit/casen-report@0.1.0 typecheck /home/adam/github.com/bpmnkit/monorepo/plugins-cli/casen-report
4
+ > tsc --noEmit
5
+
package/README.md ADDED
@@ -0,0 +1,111 @@
1
+ <div align="center">
2
+ <a href="https://bpmnkit.com"><img src="https://bpmnkit.com/favicon.svg" width="72" height="72" alt="BPMN Kit logo"></a>
3
+ <h1>@bpmnkit/casen-report</h1>
4
+ <p>Render HTML reports from Camunda 8 incident and SLA data</p>
5
+
6
+ [![npm](https://img.shields.io/npm/v/@bpmnkit/casen-report?style=flat-square&color=6244d7)](https://www.npmjs.com/package/@bpmnkit/casen-report)
7
+ [![license](https://img.shields.io/npm/l/@bpmnkit/casen-report?style=flat-square)](https://github.com/bpmnkit/monorepo/blob/main/LICENSE)
8
+ [![typescript](https://img.shields.io/badge/TypeScript-strict-6244d7?style=flat-square&logo=typescript&logoColor=white)](https://github.com/bpmnkit/monorepo)
9
+
10
+ [Website](https://bpmnkit.com) · [Documentation](https://docs.bpmnkit.com) · [GitHub](https://github.com/bpmnkit/monorepo) · [Changelog](https://github.com/bpmnkit/monorepo/blob/main/plugins-cli/casen-report/CHANGELOG.md)
11
+ </div>
12
+
13
+ ---
14
+
15
+ ## Overview
16
+
17
+ `casen-report` is an official `casen` CLI plugin that generates HTML reports from live Camunda 8 data. Install it once and run `casen report incidents` or `casen report sla` from any terminal.
18
+
19
+ ## Installation
20
+
21
+ ```sh
22
+ casen plugin install casen-report
23
+ ```
24
+
25
+ ## Commands
26
+
27
+ ### `casen report incidents`
28
+
29
+ Fetch active incidents and render an HTML report grouped by process.
30
+
31
+ ```sh
32
+ # Print table to stdout
33
+ casen report incidents
34
+
35
+ # Filter by process definition ID
36
+ casen report incidents --process-id order-process
37
+
38
+ # Write self-contained HTML file
39
+ casen report incidents --out incidents.html
40
+
41
+ # Limit fetch size
42
+ casen report incidents --limit 500 --out incidents.html
43
+ ```
44
+
45
+ **Flags**
46
+
47
+ | Flag | Short | Description | Default |
48
+ |------|-------|-------------|---------|
49
+ | `--process-id` | `-p` | Filter by process definition ID | — |
50
+ | `--limit` | `-l` | Max incidents to fetch | 200 |
51
+ | `--out` | `-o` | Write HTML to this file path | — |
52
+
53
+ ### `casen report sla`
54
+
55
+ Fetch process instances and generate an SLA compliance report. Instances whose duration exceeds the threshold are marked as **BREACHED**.
56
+
57
+ ```sh
58
+ # Print table (30-minute SLA threshold)
59
+ casen report sla --threshold 30
60
+
61
+ # SLA report for a specific process, save to file
62
+ casen report sla --threshold 60 --process-id order-process --out sla.html
63
+ ```
64
+
65
+ **Flags**
66
+
67
+ | Flag | Short | Description | Default |
68
+ |------|-------|-------------|---------|
69
+ | `--threshold` | `-t` | SLA threshold in minutes (required) | — |
70
+ | `--process-id` | `-p` | Filter by process definition ID | — |
71
+ | `--limit` | `-l` | Max instances to fetch | 200 |
72
+ | `--out` | `-o` | Write HTML to this file path | — |
73
+
74
+ ## Report Format
75
+
76
+ HTML reports are self-contained single-file documents — no external CSS, no fonts to load. They use the BPMN Kit dark theme and include:
77
+
78
+ - **Summary stat cards** — totals, breach counts, compliance rate
79
+ - **Sortable data table** — all fetched rows with status badges
80
+ - **Generated timestamp** — so reports can be archived
81
+
82
+ ---
83
+
84
+ ## Related Packages
85
+
86
+ | Package | Description |
87
+ |---------|-------------|
88
+ | [`@bpmnkit/core`](https://www.npmjs.com/package/@bpmnkit/core) | BPMN/DMN/Form parser, builder, layout engine |
89
+ | [`@bpmnkit/canvas`](https://www.npmjs.com/package/@bpmnkit/canvas) | Zero-dependency SVG BPMN viewer |
90
+ | [`@bpmnkit/editor`](https://www.npmjs.com/package/@bpmnkit/editor) | Full-featured interactive BPMN editor |
91
+ | [`@bpmnkit/engine`](https://www.npmjs.com/package/@bpmnkit/engine) | Lightweight BPMN process execution engine |
92
+ | [`@bpmnkit/feel`](https://www.npmjs.com/package/@bpmnkit/feel) | FEEL expression language parser & evaluator |
93
+ | [`@bpmnkit/plugins`](https://www.npmjs.com/package/@bpmnkit/plugins) | 22 composable canvas plugins |
94
+ | [`@bpmnkit/api`](https://www.npmjs.com/package/@bpmnkit/api) | Camunda 8 REST API TypeScript client |
95
+ | [`@bpmnkit/ascii`](https://www.npmjs.com/package/@bpmnkit/ascii) | Render BPMN diagrams as Unicode ASCII art |
96
+ | [`@bpmnkit/ui`](https://www.npmjs.com/package/@bpmnkit/ui) | Shared design tokens and UI components |
97
+ | [`@bpmnkit/profiles`](https://www.npmjs.com/package/@bpmnkit/profiles) | Shared auth, profile storage, and client factories for CLI & proxy |
98
+ | [`@bpmnkit/operate`](https://www.npmjs.com/package/@bpmnkit/operate) | Monitoring & operations frontend for Camunda clusters |
99
+ | [`@bpmnkit/connector-gen`](https://www.npmjs.com/package/@bpmnkit/connector-gen) | Generate connector templates from OpenAPI specs |
100
+ | [`@bpmnkit/cli`](https://www.npmjs.com/package/@bpmnkit/cli) | Camunda 8 command-line interface (casen) |
101
+ | [`@bpmnkit/proxy`](https://www.npmjs.com/package/@bpmnkit/proxy) | Local AI bridge and Camunda API proxy server |
102
+ | [`@bpmnkit/cli-sdk`](https://www.npmjs.com/package/@bpmnkit/cli-sdk) | Plugin authoring SDK for the casen CLI |
103
+ | [`@bpmnkit/create-casen-plugin`](https://www.npmjs.com/package/@bpmnkit/create-casen-plugin) | Scaffold a new casen CLI plugin in seconds |
104
+
105
+ ## License
106
+
107
+ [MIT](https://github.com/bpmnkit/monorepo/blob/main/LICENSE) © BPMN Kit — made by [u11g](https://u11g.com)
108
+
109
+ <div align="center">
110
+ <a href="https://bpmnkit.com"><img src="https://bpmnkit.com/favicon.svg" width="32" height="32" alt="BPMN Kit"></a>
111
+ </div>
@@ -0,0 +1,3 @@
1
+ import type { Command } from "@bpmnkit/cli-sdk";
2
+ export declare const incidentsCommand: Command;
3
+ //# sourceMappingURL=incidents.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"incidents.d.ts","sourceRoot":"","sources":["../../src/commands/incidents.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAc,MAAM,kBAAkB,CAAA;AAkB3D,eAAO,MAAM,gBAAgB,EAAE,OAqH9B,CAAA"}
@@ -0,0 +1,120 @@
1
+ import { writeFileSync } from "node:fs";
2
+ import { badge, buildReport } from "../report.js";
3
+ function asIncident(raw) {
4
+ return raw;
5
+ }
6
+ export const incidentsCommand = {
7
+ name: "incidents",
8
+ description: "Generate an HTML report of current incidents",
9
+ flags: [
10
+ {
11
+ name: "process-id",
12
+ short: "p",
13
+ description: "Filter by process definition ID",
14
+ type: "string",
15
+ },
16
+ {
17
+ name: "limit",
18
+ short: "l",
19
+ description: "Maximum number of incidents to fetch",
20
+ type: "number",
21
+ default: 200,
22
+ },
23
+ {
24
+ name: "out",
25
+ short: "o",
26
+ description: "Write HTML report to this file path",
27
+ type: "string",
28
+ placeholder: "FILE",
29
+ },
30
+ ],
31
+ examples: [
32
+ { description: "Report all active incidents", command: "casen report incidents" },
33
+ {
34
+ description: "Report incidents for a specific process",
35
+ command: "casen report incidents --process-id order-process",
36
+ },
37
+ {
38
+ description: "Save HTML report to file",
39
+ command: "casen report incidents --out incidents.html",
40
+ },
41
+ ],
42
+ async run(ctx) {
43
+ const client = (await ctx.getClient());
44
+ const limit = Number(ctx.flags.limit ?? 200);
45
+ const processId = ctx.flags["process-id"];
46
+ const outFile = ctx.flags.out;
47
+ const filter = {};
48
+ if (processId)
49
+ filter.processDefinitionId = processId;
50
+ const result = await client.incident.searchIncidents({
51
+ filter,
52
+ page: { from: 0, limit },
53
+ });
54
+ const raw = result;
55
+ const items = (raw.items ?? []).map(asIncident);
56
+ const total = raw.page?.totalItems ?? items.length;
57
+ if (outFile) {
58
+ const activeCount = items.filter((i) => i.state?.toUpperCase() !== "RESOLVED").length;
59
+ const resolvedCount = items.length - activeCount;
60
+ // Group by process definition
61
+ const byProcess = new Map();
62
+ for (const item of items) {
63
+ const key = item.processDefinitionId ?? "unknown";
64
+ byProcess.set(key, (byProcess.get(key) ?? 0) + 1);
65
+ }
66
+ const html = buildReport({
67
+ title: "Incident Report",
68
+ subtitle: processId ? `Process: ${processId}` : "All processes",
69
+ stats: [
70
+ { label: "Total incidents", value: total },
71
+ { label: "Active", value: activeCount, color: "#f87171" },
72
+ { label: "Resolved", value: resolvedCount, color: "#22c55e" },
73
+ { label: "Processes affected", value: byProcess.size },
74
+ ],
75
+ columns: [
76
+ { header: "Incident Key", render: (r) => asIncident(r).incidentKey ?? "", isHtml: false },
77
+ {
78
+ header: "Process Instance",
79
+ render: (r) => `<span class="key">${asIncident(r).processInstanceKey ?? ""}</span>`,
80
+ isHtml: true,
81
+ },
82
+ { header: "Process", render: (r) => asIncident(r).processDefinitionId ?? "" },
83
+ {
84
+ header: "State",
85
+ render: (r) => {
86
+ const state = asIncident(r).state ?? "";
87
+ const cls = state.toUpperCase() === "RESOLVED" ? "resolved" : "active";
88
+ return badge(state || "ACTIVE", cls);
89
+ },
90
+ isHtml: true,
91
+ },
92
+ { header: "Type", render: (r) => asIncident(r).type ?? "" },
93
+ { header: "Message", render: (r) => (asIncident(r).message ?? "").slice(0, 120) },
94
+ {
95
+ header: "Created",
96
+ render: (r) => {
97
+ const ts = asIncident(r).creationTime;
98
+ return ts ? new Date(ts).toLocaleString() : "";
99
+ },
100
+ },
101
+ ],
102
+ rows: items,
103
+ });
104
+ writeFileSync(outFile, html, "utf8");
105
+ ctx.output.ok(`Report written to ${outFile} (${items.length} incidents)`);
106
+ }
107
+ else {
108
+ ctx.output.printList({ items }, [
109
+ { key: "incidentKey", header: "INCIDENT KEY", maxWidth: 22 },
110
+ { key: "processInstanceKey", header: "PROCESS INSTANCE", maxWidth: 22 },
111
+ { key: "processDefinitionId", header: "PROCESS", maxWidth: 30 },
112
+ { key: "state", header: "STATE", maxWidth: 10 },
113
+ { key: "type", header: "TYPE", maxWidth: 28 },
114
+ { key: "message", header: "MESSAGE", maxWidth: 60 },
115
+ ]);
116
+ ctx.output.info(`Showing ${items.length} of ${total} incidents`);
117
+ }
118
+ },
119
+ };
120
+ //# sourceMappingURL=incidents.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"incidents.js","sourceRoot":"","sources":["../../src/commands/incidents.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from "@bpmnkit/cli-sdk";
2
+ export declare const slaCommand: Command;
3
+ //# sourceMappingURL=sla.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sla.d.ts","sourceRoot":"","sources":["../../src/commands/sla.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAc,MAAM,kBAAkB,CAAA;AAkC3D,eAAO,MAAM,UAAU,EAAE,OA6KxB,CAAA"}
@@ -0,0 +1,188 @@
1
+ import { writeFileSync } from "node:fs";
2
+ import { badge, buildReport } from "../report.js";
3
+ function asInstance(raw) {
4
+ return raw;
5
+ }
6
+ function durationMs(item) {
7
+ if (!item.startDate)
8
+ return 0;
9
+ const start = new Date(item.startDate).getTime();
10
+ const end = item.endDate ? new Date(item.endDate).getTime() : Date.now();
11
+ return end - start;
12
+ }
13
+ function fmtDuration(ms) {
14
+ const totalSeconds = Math.floor(ms / 1000);
15
+ const hours = Math.floor(totalSeconds / 3600);
16
+ const minutes = Math.floor((totalSeconds % 3600) / 60);
17
+ const seconds = totalSeconds % 60;
18
+ if (hours > 0)
19
+ return `${hours}h ${minutes}m`;
20
+ if (minutes > 0)
21
+ return `${minutes}m ${seconds}s`;
22
+ return `${seconds}s`;
23
+ }
24
+ export const slaCommand = {
25
+ name: "sla",
26
+ description: "Generate an SLA compliance report for process instances",
27
+ flags: [
28
+ {
29
+ name: "threshold",
30
+ short: "t",
31
+ description: "SLA threshold in minutes",
32
+ type: "number",
33
+ required: true,
34
+ placeholder: "MINUTES",
35
+ },
36
+ {
37
+ name: "process-id",
38
+ short: "p",
39
+ description: "Filter by process definition ID",
40
+ type: "string",
41
+ },
42
+ {
43
+ name: "limit",
44
+ short: "l",
45
+ description: "Maximum number of instances to fetch",
46
+ type: "number",
47
+ default: 200,
48
+ },
49
+ {
50
+ name: "out",
51
+ short: "o",
52
+ description: "Write HTML report to this file path",
53
+ type: "string",
54
+ placeholder: "FILE",
55
+ },
56
+ ],
57
+ examples: [
58
+ {
59
+ description: "Check SLA with 30-minute threshold",
60
+ command: "casen report sla --threshold 30",
61
+ },
62
+ {
63
+ description: "SLA report for a specific process",
64
+ command: "casen report sla --threshold 60 --process-id order-process",
65
+ },
66
+ {
67
+ description: "Save SLA report to file",
68
+ command: "casen report sla --threshold 30 --out sla.html",
69
+ },
70
+ ],
71
+ async run(ctx) {
72
+ const client = (await ctx.getClient());
73
+ const thresholdMinutes = Number(ctx.flags.threshold);
74
+ const limit = Number(ctx.flags.limit ?? 200);
75
+ const processId = ctx.flags["process-id"];
76
+ const outFile = ctx.flags.out;
77
+ if (!thresholdMinutes || thresholdMinutes <= 0) {
78
+ throw new Error("--threshold must be a positive number of minutes");
79
+ }
80
+ const thresholdMs = thresholdMinutes * 60 * 1000;
81
+ const filter = {};
82
+ if (processId)
83
+ filter.processDefinitionId = processId;
84
+ const result = await client.processInstance.searchProcessInstances({
85
+ filter,
86
+ page: { from: 0, limit },
87
+ });
88
+ const raw = result;
89
+ const items = (raw.items ?? []).map(asInstance);
90
+ const total = raw.page?.totalItems ?? items.length;
91
+ const rows = items.map((item) => {
92
+ const ms = durationMs(item);
93
+ return { ...item, durationMs: ms, breached: ms > thresholdMs };
94
+ });
95
+ const breachedCount = rows.filter((r) => r.breached).length;
96
+ const compliantCount = rows.length - breachedCount;
97
+ const complianceRate = rows.length > 0 ? Math.round((compliantCount / rows.length) * 100) : 100;
98
+ if (outFile) {
99
+ const html = buildReport({
100
+ title: "SLA Compliance Report",
101
+ subtitle: processId
102
+ ? `Process: ${processId} — SLA: ${thresholdMinutes}m`
103
+ : `All processes — SLA: ${thresholdMinutes}m`,
104
+ stats: [
105
+ { label: "Total instances", value: total },
106
+ { label: "Compliant", value: compliantCount, color: "#22c55e" },
107
+ {
108
+ label: "Breached",
109
+ value: breachedCount,
110
+ color: breachedCount > 0 ? "#f59e0b" : "#22c55e",
111
+ },
112
+ {
113
+ label: "Compliance rate",
114
+ value: `${complianceRate}%`,
115
+ color: complianceRate >= 90 ? "#22c55e" : complianceRate >= 70 ? "#f59e0b" : "#f87171",
116
+ },
117
+ ],
118
+ columns: [
119
+ {
120
+ header: "Process Instance",
121
+ render: (r) => `<span class="key">${r.processInstanceKey ?? ""}</span>`,
122
+ isHtml: true,
123
+ },
124
+ { header: "Process", render: (r) => r.processDefinitionId ?? "" },
125
+ {
126
+ header: "State",
127
+ render: (r) => {
128
+ const state = r.state ?? "";
129
+ const cls = state.toLowerCase();
130
+ return badge(state || "UNKNOWN", cls);
131
+ },
132
+ isHtml: true,
133
+ },
134
+ {
135
+ header: "Duration",
136
+ render: (r) => fmtDuration(r.durationMs),
137
+ },
138
+ {
139
+ header: `SLA (${thresholdMinutes}m)`,
140
+ render: (r) => {
141
+ const row = r;
142
+ return badge(row.breached ? "BREACHED" : "OK", row.breached ? "breached" : "ok");
143
+ },
144
+ isHtml: true,
145
+ },
146
+ {
147
+ header: "Started",
148
+ render: (r) => {
149
+ const ts = r.startDate;
150
+ return ts ? new Date(ts).toLocaleString() : "";
151
+ },
152
+ },
153
+ {
154
+ header: "Ended",
155
+ render: (r) => {
156
+ const ts = r.endDate;
157
+ return ts ? new Date(ts).toLocaleString() : "—";
158
+ },
159
+ },
160
+ ],
161
+ rows,
162
+ });
163
+ writeFileSync(outFile, html, "utf8");
164
+ ctx.output.ok(`Report written to ${outFile} (${rows.length} instances, ${complianceRate}% compliant)`);
165
+ }
166
+ else {
167
+ ctx.output.printList({ items: rows }, [
168
+ { key: "processInstanceKey", header: "PROCESS INSTANCE", maxWidth: 22 },
169
+ { key: "processDefinitionId", header: "PROCESS", maxWidth: 30 },
170
+ { key: "state", header: "STATE", maxWidth: 12 },
171
+ {
172
+ key: "durationMs",
173
+ header: "DURATION",
174
+ maxWidth: 12,
175
+ transform: (v) => fmtDuration(Number(v)),
176
+ },
177
+ {
178
+ key: "breached",
179
+ header: `SLA (${thresholdMinutes}m)`,
180
+ maxWidth: 10,
181
+ transform: (v) => (v ? "BREACHED" : "OK"),
182
+ },
183
+ ]);
184
+ ctx.output.info(`Showing ${rows.length} of ${total} instances — ${complianceRate}% compliant`);
185
+ }
186
+ },
187
+ };
188
+ //# sourceMappingURL=sla.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sla.js","sourceRoot":"","sources":["../../src/commands/sla.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { CasenPlugin } from "@bpmnkit/cli-sdk";
2
+ declare const plugin: CasenPlugin;
3
+ export default plugin;
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAInD,QAAA,MAAM,MAAM,EAAE,WAWb,CAAA;AAED,eAAe,MAAM,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,16 @@
1
+ import { incidentsCommand } from "./commands/incidents.js";
2
+ import { slaCommand } from "./commands/sla.js";
3
+ const plugin = {
4
+ id: "com.bpmnkit.casen-report",
5
+ name: "Report",
6
+ version: "0.1.0",
7
+ groups: [
8
+ {
9
+ name: "report",
10
+ description: "Render HTML reports from incident and SLA data",
11
+ commands: [incidentsCommand, slaCommand],
12
+ },
13
+ ],
14
+ };
15
+ export default plugin;
16
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAE9C,MAAM,MAAM,GAAgB;IAC3B,EAAE,EAAE,0BAA0B;IAC9B,IAAI,EAAE,QAAQ;IACd,OAAO,EAAE,OAAO;IAChB,MAAM,EAAE;QACP;YACC,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,gDAAgD;YAC7D,QAAQ,EAAE,CAAC,gBAAgB,EAAE,UAAU,CAAC;SACxC;KACD;CACD,CAAA;AAED,eAAe,MAAM,CAAA"}
@@ -0,0 +1,19 @@
1
+ /** Generates a self-contained dark-theme HTML report. */
2
+ export interface ReportColumn {
3
+ header: string;
4
+ render: (row: unknown) => string;
5
+ isHtml?: boolean;
6
+ }
7
+ export declare function buildReport(opts: {
8
+ title: string;
9
+ subtitle?: string;
10
+ stats: {
11
+ label: string;
12
+ value: string | number;
13
+ color?: string;
14
+ }[];
15
+ columns: ReportColumn[];
16
+ rows: unknown[];
17
+ }): string;
18
+ export declare function badge(text: string, cls: string): string;
19
+ //# sourceMappingURL=report.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAAA,yDAAyD;AAiEzD,MAAM,WAAW,YAAY;IAC5B,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,MAAM,CAAA;IAChC,MAAM,CAAC,EAAE,OAAO,CAAA;CAChB;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE;IACjC,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IAClE,OAAO,EAAE,YAAY,EAAE,CAAA;IACvB,IAAI,EAAE,OAAO,EAAE,CAAA;CACf,GAAG,MAAM,CA+CT;AAUD,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAEvD"}