princejs 1.7.0 β†’ 1.7.2

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 CHANGED
@@ -1,12 +1,15 @@
1
- # PrinceJS β€” The Fastest Bun Framework in History
1
+ # 🌐 **PrinceJS**
2
2
 
3
- **2.8 kB gzipped** β€’ **19,200 req/s** β€’ **Built by a 13yo Nigerian**
3
+ ### ⚑ Ultra-clean, modern & minimal Bun web framework
4
4
 
5
- > *"I didn't beat Elysia. I destroyed it."* β€” @Lil_Prince_1218
5
+ ![npm](https://img.shields.io/npm/v/princejs)
6
+ ![stars](https://img.shields.io/github/stars/MatthewTheCoder1218/princejs)
7
+ ![downloads](https://img.shields.io/npm/dt/princejs)
8
+ ![license](https://img.shields.io/github/license/MatthewTheCoder1218/princejs)
6
9
 
7
10
  ---
8
11
 
9
- ## πŸ† World Record: Fastest Framework Under 3 kB
12
+ ## πŸš€ Quick Start
10
13
 
11
14
  ```bash
12
15
  bun create princejs my-app
@@ -31,60 +34,6 @@ app.listen(3000);
31
34
 
32
35
  ---
33
36
 
34
- ## βš”οΈ Size War (Gzipped β€” Real World)
35
-
36
- | Framework | Gzipped | Minified | vs PrinceJS |
37
- | ------------ | ---------- | -------- | --------------- |
38
- | **PrinceJS** | **2.8 kB** | 7.8 kB | β€” |
39
- | Hono | 7.3 kB | 18.7 kB | **2.6Γ— bigger** |
40
- | Elysia | 62.5 kB | 245 kB | **22Γ— bigger** |
41
-
42
- PrinceJS fits in a tweet. Elysia needs a ZIP file.
43
-
44
- ---
45
-
46
- ## ⚑ Benchmarks (autocannon -c 100 -d 30)
47
-
48
- **Windows 11 β€’ November 15, 2025 β€’ 100 connections β€’ 30 seconds**
49
- **Route:** `GET /users/:id`
50
-
51
- | Rank | Framework | Req/s | Requests (30s) | Throughput |
52
- | --------------- | ---------- | ----- | -------------- | ---------- |
53
- | πŸ₯‡ **PrinceJS** | **19,200** | 576k | 2.34 MB/s | |
54
- | πŸ₯ˆ Hono | 16,212 | 486k | 1.98 MB/s | |
55
- | πŸ₯‰ Elysia | 15,862 | 476k | 1.94 MB/s | |
56
- | 4️⃣ Express | 9,325 | 280k | 1.84 MB/s | |
57
-
58
- ### Summary
59
-
60
- * PrinceJS beats **Elysia by 21%** (3,338 more req/s)
61
- * PrinceJS beats **Hono by 18%** (2,988 more req/s)
62
- * PrinceJS beats **Express by 106%** (over 2Γ— faster)
63
-
64
- > PrinceJS is the FASTEST framework under 10 kB. Period.
65
-
66
- ---
67
-
68
- ## πŸ”₯ Why PrinceJS Wins
69
-
70
- ### 1. **Trie-Based Router (Cached)**
71
-
72
- Most frameworks rebuild routes on every request. PrinceJS builds once and caches.
73
-
74
- ### 2. **Zero Overhead Middleware**
75
-
76
- Middleware tracking prevents duplicate execution. No wasted cycles.
77
-
78
- ### 3. **Optimized for Bun**
79
-
80
- Native `Bun.serve()` with WebSocket support. No abstraction layers.
81
-
82
- ### 4. **Smart Body Parsing**
83
-
84
- Only parses body when needed. GET requests skip parsing entirely.
85
-
86
- ---
87
-
88
37
  ## 🧰 Features
89
38
 
90
39
  ```ts
@@ -94,7 +43,7 @@ import { z } from "zod";
94
43
 
95
44
  app
96
45
  .use(cors())
97
- .use(logger({ format: "dev" }))
46
+ .use(logger())
98
47
  .use(rateLimit({ max: 100, window: 60 }))
99
48
  .use(serve({ root: "./public" }))
100
49
  .use(validate(z.object({
@@ -110,9 +59,7 @@ app
110
59
  * Rate Limiting
111
60
  * Static Files
112
61
 
113
- ### βœ“ Validation
114
-
115
- * Zod schema validation
62
+ ### βœ“ Validation (Zod)
116
63
 
117
64
  ### βœ“ WebSocket Support
118
65
 
@@ -124,33 +71,19 @@ app
124
71
 
125
72
  ---
126
73
 
127
- ## New Tree-Shakable Features
74
+ ## New Tree‑Shakable Features
128
75
 
129
76
  ```ts
130
77
  import { cache, email, upload } from "princejs/helpers";
131
78
  import { cron, openapi } from "princejs/scheduler";
132
79
  ```
133
80
 
134
- * `cache(60)(handler)` β€” In-memory cache
135
- * `email(to, subject, html)` β€” Resend.com
136
- * `upload()` β€” 1-line file upload
137
- * `cron("*/2 * * * *", task)` β€” Cron support
81
+ * `cache(60)(handler)` β€” In‑memory cache
82
+ * `email(to, subject, html)` β€” Email helper
83
+ * `upload()` β€” One‑line file upload
84
+ * `cron("*/2 * * * *", task)` β€” Cron jobs
138
85
  * `openapi({ title, version })` β€” Auto docs
139
86
 
140
- **Tree-shakable = only what you import gets bundled**
141
-
142
- ---
143
-
144
- ## πŸ“¦ Installation
145
-
146
- ```bash
147
- npm install princejs
148
- # or
149
- bun add princejs
150
- # or
151
- yarn add princejs
152
- ```
153
-
154
87
  ---
155
88
 
156
89
  ## 🎯 Full Example
@@ -163,47 +96,29 @@ import { cache, ai, upload } from "princejs/helpers";
163
96
  import { cron } from "princejs/scheduler";
164
97
  import { z } from "zod";
165
98
 
166
- const app = prince(true); // dev mode
99
+ const app = prince(true);
167
100
 
168
- // Middleware
169
101
  app.use(cors());
170
102
  app.use(logger());
171
103
  app.use(rateLimit({ max: 100, window: 60 }));
172
104
 
173
- // Validation
174
105
  app.use(validate(z.object({ name: z.string() })));
175
106
 
176
- // Routes
177
- app.get("/", () => ({
178
- message: "Welcome to PrinceJS",
179
- version: "3.3.1"
180
- }));
107
+ app.get("/", () => ({ message: "Welcome to PrinceJS" }));
181
108
 
182
- app.get("/users/:id", (req) => ({
183
- id: req.params.id,
184
- name: "John Doe"
185
- }));
109
+ app.get("/users/:id", (req) => ({ id: req.params.id }));
186
110
 
187
- // New: Cache
188
111
  app.get("/data", cache(60)(() => ({ time: Date.now() })));
189
112
 
190
- // New: AI
191
113
  app.post("/ai", async (req) => ({ reply: await ai(req.body.q) }));
192
114
 
193
- // New: Upload
194
- app.post("/upload", upload(), (req) => ({
195
- files: Object.keys(req.files || {}),
196
- body: req.body
197
- }));
115
+ app.post("/upload", upload(), (req) => ({ files: Object.keys(req.files || {}) }));
198
116
 
199
- // New: Cron
200
117
  cron("*/1 * * * *", () => console.log("PrinceJS heartbeat"));
201
118
 
202
- // WebSocket
203
119
  app.ws("/chat", {
204
120
  open: (ws) => ws.send("Welcome!"),
205
- message: (ws, msg) => ws.send(`Echo: ${msg}`),
206
- close: () => console.log("Disconnected")
121
+ message: (ws, msg) => ws.send(`Echo: ${msg}`)
207
122
  });
208
123
 
209
124
  app.listen(3000);
@@ -211,6 +126,18 @@ app.listen(3000);
211
126
 
212
127
  ---
213
128
 
129
+ ## πŸ“¦ Installation
130
+
131
+ ```bash
132
+ npm install princejs
133
+ # or
134
+ bun add princejs
135
+ # or
136
+ yarn add princejs
137
+ ```
138
+
139
+ ---
140
+
214
141
  ## πŸ“š Documentation
215
142
 
216
143
  Visit: **princejs.vercel.app**
@@ -219,8 +146,6 @@ Visit: **princejs.vercel.app**
219
146
 
220
147
  ## 🀝 Contributing
221
148
 
222
- Issues and PRs welcome!
223
-
224
149
  ```bash
225
150
  git clone https://github.com/MatthewTheCoder1218/princejs
226
151
  cd princejs
@@ -230,35 +155,20 @@ bun test
230
155
 
231
156
  ---
232
157
 
233
- ## πŸ‡³πŸ‡¬ Built in Nigeria
234
-
235
- Made by **@Lil_Prince_1218 β€” Age 13**
236
- *"2.8 kB. 19,200 req/s. The fastest framework under 10 kB."*
237
-
238
- Inspired by the greats (Express, Hono, Elysia) but built to win.
239
-
240
- ---
241
-
242
- ## πŸ“„ License
243
-
244
- MIT Β© 2025 **Matthew Michael**
245
-
246
- ---
247
-
248
158
  ## ⭐ Star This Repo
249
159
 
250
160
  If PrinceJS helped you, star the repo!
251
161
 
252
- GitHub: [github.com/MatthewTheCoder1218/princejs](https://github.com/MatthewTheCoder1218/princejs)
162
+ GitHub: [https://github.com/MatthewTheCoder1218/princejs](https://github.com/MatthewTheCoder1218/princejs)
253
163
 
254
164
  ---
255
165
 
256
166
  ## πŸ”— Links
257
167
 
258
- - [npm](https://www.npmjs.com/package/princejs)
259
- - [GitHub](https://github.com/MatthewTheCoder1218/princejs)
260
- - [Twitter](https://twitter.com/Lil_Prince_1218)
168
+ * npm: [https://www.npmjs.com/package/princejs](https://www.npmjs.com/package/princejs)
169
+ * GitHub: [https://github.com/MatthewTheCoder1218/princejs](https://github.com/MatthewTheCoder1218/princejs)
170
+ * Twitter: [https://twitter.com/Lil_Prince_1218](https://twitter.com/Lil_Prince_1218)
261
171
 
262
172
  ---
263
173
 
264
- **PrinceJS: Small in size. Giant in speed. πŸš€**
174
+ **PrinceJS: Small in size. Giant in capability. πŸš€**
package/dist/helpers.d.ts CHANGED
@@ -1,17 +1,5 @@
1
1
  import type { PrinceRequest } from "./prince";
2
2
  export declare const cache: (ttl: number) => (handler: any) => (req: PrinceRequest) => Promise<any>;
3
3
  export declare const email: (to: string, subject: string, html: string) => Promise<void>;
4
- export declare const upload: (fieldName?: string) => (req: PrinceRequest) => Promise<{
5
- name: any;
6
- size: any;
7
- type: any;
8
- success: boolean;
9
- error?: undefined;
10
- } | {
11
- error: string;
12
- name?: undefined;
13
- size?: undefined;
14
- type?: undefined;
15
- success?: undefined;
16
- }>;
4
+ export declare const upload: () => (req: PrinceRequest) => Promise<Response>;
17
5
  //# sourceMappingURL=helpers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAG9C,eAAO,MAAM,KAAK,GAAI,KAAK,MAAM,MAEvB,SAAS,GAAG,MAAY,KAAK,aAAa,iBASnD,CAAC;AAGF,eAAO,MAAM,KAAK,GAAU,IAAI,MAAM,EAAE,SAAS,MAAM,EAAE,MAAM,MAAM,kBAMpE,CAAC;AAGF,eAAO,MAAM,MAAM,GAAI,kBAAkB,MACzB,KAAK,aAAa;;;;;;;;;;;;EAiCjC,CAAC"}
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAG9C,eAAO,MAAM,KAAK,GAAI,KAAK,MAAM,MAEvB,SAAS,GAAG,MAAY,KAAK,aAAa,iBASnD,CAAC;AAGF,eAAO,MAAM,KAAK,GAAU,IAAI,MAAM,EAAE,SAAS,MAAM,EAAE,MAAM,MAAM,kBAMpE,CAAC;AAGF,eAAO,MAAM,MAAM,SACH,KAAK,aAAa,sBA4CjC,CAAC"}
package/dist/helpers.js CHANGED
@@ -20,31 +20,34 @@ var email = async (to, subject, html) => {
20
20
  body: JSON.stringify({ from: "no-reply@princejs.dev", to, subject, html })
21
21
  });
22
22
  };
23
- var upload = (fieldName = "file") => {
23
+ var upload = () => {
24
24
  return async (req) => {
25
25
  try {
26
- if (req.files && req.files[fieldName]) {
27
- const file = req.files[fieldName];
28
- return {
29
- name: file.name,
30
- size: file.size,
31
- type: file.type,
32
- success: true
33
- };
26
+ const contentType = req.headers.get("content-type") || "";
27
+ if (!contentType.includes("multipart/form-data")) {
28
+ return new Response(JSON.stringify({ error: "Expected multipart/form-data" }), { status: 400, headers: { "Content-Type": "application/json" } });
34
29
  }
35
- if (req.body && req.body.files && req.body.files[fieldName]) {
36
- const file = req.body.files[fieldName];
37
- return {
38
- name: file.name,
39
- size: file.size,
40
- type: file.type,
41
- success: true
42
- };
30
+ const formData = await req.formData();
31
+ const file = formData.get("file");
32
+ if (!file || !(file instanceof File)) {
33
+ return new Response(JSON.stringify({ error: "No file provided or invalid file" }), { status: 400, headers: { "Content-Type": "application/json" } });
43
34
  }
44
- return { error: `No file found with field name: ${fieldName}` };
35
+ const fileInfo = {
36
+ name: file.name,
37
+ size: file.size,
38
+ type: file.type,
39
+ lastModified: file.lastModified
40
+ };
41
+ return new Response(JSON.stringify(fileInfo), {
42
+ status: 200,
43
+ headers: { "Content-Type": "application/json" }
44
+ });
45
45
  } catch (error) {
46
- console.error("Upload processing error:", error);
47
- return { error: "File processing failed" };
46
+ console.error("Upload error:", error);
47
+ return new Response(JSON.stringify({ error: "Upload failed" }), {
48
+ status: 500,
49
+ headers: { "Content-Type": "application/json" }
50
+ });
48
51
  }
49
52
  };
50
53
  };
package/dist/jsx.d.ts ADDED
@@ -0,0 +1,16 @@
1
+ export interface JSXProps {
2
+ children?: any;
3
+ [key: string]: any;
4
+ }
5
+ export declare const jsx: (tag: string | Function, props: JSXProps, ...children: any[]) => any;
6
+ export declare const jsxs: (tag: string | Function, props: JSXProps, ...children: any[]) => any;
7
+ export declare const jsxDEV: (tag: string | Function, props: JSXProps, ...children: any[]) => any;
8
+ export declare const Fragment: (props: JSXProps) => any;
9
+ export declare const Html: (props: any) => string;
10
+ export declare const Head: (props: any) => string;
11
+ export declare const Body: (props: any) => string;
12
+ export declare const H1: (props: any) => string;
13
+ export declare const P: (props: any) => string;
14
+ export declare const Div: (props: any) => string;
15
+ export declare const render: (jsxContent: any) => Response;
16
+ //# sourceMappingURL=jsx.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsx.d.ts","sourceRoot":"","sources":["../src/jsx.ts"],"names":[],"mappings":"AACA,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,EAAE,GAAG,CAAC;IACf,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,eAAO,MAAM,GAAG,GAAI,KAAK,MAAM,GAAG,QAAQ,EAAE,OAAO,QAAQ,EAAE,GAAG,UAAU,GAAG,EAAE,KAAG,GAcjF,CAAC;AAEF,eAAO,MAAM,IAAI,QAhBQ,MAAM,GAAG,QAAQ,SAAS,QAAQ,eAAe,GAAG,EAAE,KAAG,GAgB3D,CAAC;AACxB,eAAO,MAAM,MAAM,QAjBM,MAAM,GAAG,QAAQ,SAAS,QAAQ,eAAe,GAAG,EAAE,KAAG,GAiBzD,CAAC;AAC1B,eAAO,MAAM,QAAQ,GAAI,OAAO,QAAQ,QAAmB,CAAC;AAI5D,eAAO,MAAM,IAAI,GAAI,OAAO,GAAG,WAE9B,CAAC;AAEF,eAAO,MAAM,IAAI,GAAI,OAAO,GAAG,WAE9B,CAAC;AAEF,eAAO,MAAM,IAAI,GAAI,OAAO,GAAG,WAE9B,CAAC;AAEF,eAAO,MAAM,EAAE,GAAI,OAAO,GAAG,WAE5B,CAAC;AAEF,eAAO,MAAM,CAAC,GAAI,OAAO,GAAG,WAE3B,CAAC;AAEF,eAAO,MAAM,GAAG,GAAI,OAAO,GAAG,WAU7B,CAAC;AAIF,eAAO,MAAM,MAAM,GAAI,YAAY,GAAG,aAKrC,CAAC"}
package/dist/jsx.js ADDED
@@ -0,0 +1,66 @@
1
+ // @bun
2
+ // src/jsx.ts
3
+ var jsx = (tag, props, ...children) => {
4
+ if (typeof tag === "function") {
5
+ return tag({ ...props, children });
6
+ }
7
+ const attrs = Object.entries(props || {}).filter(([key]) => key !== "children").map(([key, value]) => ` ${key}="${String(value).replace(/"/g, "&quot;")}"`).join("");
8
+ const content = children.flat().filter(Boolean).join("");
9
+ return `<${tag}${attrs}>${content}</${tag}>`;
10
+ };
11
+ var jsxs = jsx;
12
+ var jsxDEV = jsx;
13
+ var Fragment = (props) => props.children;
14
+ var Html = (props) => {
15
+ return `<html>${renderChildren(props.children)}</html>`;
16
+ };
17
+ var Head = (props) => {
18
+ return `<head>${renderChildren(props.children)}</head>`;
19
+ };
20
+ var Body = (props) => {
21
+ return `<body>${renderChildren(props.children)}</body>`;
22
+ };
23
+ var H1 = (props) => {
24
+ return `<h1>${renderChildren(props.children)}</h1>`;
25
+ };
26
+ var P = (props) => {
27
+ return `<p>${renderChildren(props.children)}</p>`;
28
+ };
29
+ var Div = (props) => {
30
+ const attrs = Object.keys(props).filter((key) => key !== "children").map((key) => {
31
+ if (key === "className")
32
+ return `class="${props[key]}"`;
33
+ return `${key}="${props[key]}"`;
34
+ }).join(" ");
35
+ return `<div ${attrs}>${renderChildren(props.children)}</div>`;
36
+ };
37
+ var render = (jsxContent) => {
38
+ const html = typeof jsxContent === "string" ? jsxContent : String(jsxContent);
39
+ return new Response(html, {
40
+ headers: { "Content-Type": "text/html; charset=utf-8" }
41
+ });
42
+ };
43
+ var renderChildren = (children) => {
44
+ if (!children)
45
+ return "";
46
+ if (Array.isArray(children))
47
+ return children.map(renderChildren).join("");
48
+ if (typeof children === "object") {
49
+ const rendered = render(children);
50
+ return typeof rendered === "string" ? rendered : "";
51
+ }
52
+ return String(children);
53
+ };
54
+ export {
55
+ render,
56
+ jsxs,
57
+ jsxDEV,
58
+ jsx,
59
+ P,
60
+ Html,
61
+ Head,
62
+ H1,
63
+ Fragment,
64
+ Div,
65
+ Body
66
+ };
@@ -1,11 +1,11 @@
1
1
  import type { PrinceRequest } from "./prince";
2
2
  import { z } from "zod";
3
3
  type Next = () => Promise<Response | undefined>;
4
- export declare const cors: (origin?: string) => (req: PrinceRequest, next: Next) => Promise<Response | undefined>;
4
+ export declare const cors: (origin?: string) => (req: any, next: Function) => Promise<any>;
5
5
  export declare const logger: () => (req: PrinceRequest, next: Next) => Promise<Response | undefined>;
6
- export declare const signJWT: (payload: object, key: Uint8Array, exp?: string) => Promise<string>;
6
+ export declare const signJWT: (payload: any, secret: Uint8Array, expiresIn: string) => Promise<string>;
7
7
  export declare const jwt: (key: Uint8Array) => (req: PrinceRequest, next: Next) => Promise<Response | undefined>;
8
8
  export declare const rateLimit: (max: number, window?: number) => (req: PrinceRequest, next: Next) => Promise<Response | undefined>;
9
- export declare const validate: <T>(schema: z.ZodSchema<T>) => (req: PrinceRequest, next: Next) => Promise<Response | undefined>;
9
+ export declare const validate: (schema: z.ZodSchema) => (req: any, next: Function) => Promise<any>;
10
10
  export {};
11
11
  //# sourceMappingURL=middleware.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,KAAK,IAAI,GAAG,MAAM,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC,CAAC;AAIhD,eAAO,MAAM,IAAI,GAAI,eAAY,MACjB,KAAK,aAAa,EAAE,MAAM,IAAI,kCAgC7C,CAAC;AAGF,eAAO,MAAM,MAAM,SACH,KAAK,aAAa,EAAE,MAAM,IAAI,kCAM7C,CAAC;AAGF,eAAO,MAAM,OAAO,GAClB,SAAS,MAAM,EACf,KAAK,UAAU,EACf,MAAK,MAAa,KACjB,OAAO,CAAC,MAAM,CAMhB,CAAC;AAGF,eAAO,MAAM,GAAG,GAAI,KAAK,UAAU,MACnB,KAAK,aAAa,EAAE,MAAM,IAAI,kCAuB7C,CAAC;AAGF,eAAO,MAAM,SAAS,GAAI,KAAK,MAAM,EAAE,eAAW,MAGlC,KAAK,aAAa,EAAE,MAAM,IAAI,kCAuC7C,CAAC;AAGF,eAAO,MAAM,QAAQ,GAAI,CAAC,EAAE,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAClC,KAAK,aAAa,EAAE,MAAM,IAAI,kCAQ7C,CAAC"}
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,KAAK,IAAI,GAAG,MAAM,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC,CAAC;AAKhD,eAAO,MAAM,IAAI,GAAI,SAAQ,MAAY,MACzB,KAAK,GAAG,EAAE,MAAM,QAAQ,iBA+BvC,CAAC;AAGF,eAAO,MAAM,MAAM,SACH,KAAK,aAAa,EAAE,MAAM,IAAI,kCAM7C,CAAC;AAGF,eAAO,MAAM,OAAO,GAAU,SAAS,GAAG,EAAE,QAAQ,UAAU,EAAE,WAAW,MAAM,oBAQhF,CAAC;AAGF,eAAO,MAAM,GAAG,GAAI,KAAK,UAAU,MACnB,KAAK,aAAa,EAAE,MAAM,IAAI,kCAuB7C,CAAC;AAGF,eAAO,MAAM,SAAS,GAAI,KAAK,MAAM,EAAE,eAAW,MAGlC,KAAK,aAAa,EAAE,MAAM,IAAI,kCAuC7C,CAAC;AAIF,eAAO,MAAM,QAAQ,GAAI,QAAQ,CAAC,CAAC,SAAS,MAC5B,KAAK,GAAG,EAAE,MAAM,QAAQ,iBAiCvC,CAAC"}