@rs-x/cli 2.0.0-next.0 → 2.0.0-next.11

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 (33) hide show
  1. package/README.md +10 -4
  2. package/bin/rsx.cjs +679 -153
  3. package/package.json +14 -1
  4. package/{rs-x-vscode-extension-2.0.0-next.0.vsix → rs-x-vscode-extension-2.0.0-next.11.vsix} +0 -0
  5. package/templates/angular-demo/README.md +115 -0
  6. package/templates/angular-demo/src/app/app.component.css +97 -0
  7. package/templates/angular-demo/src/app/app.component.html +58 -0
  8. package/templates/angular-demo/src/app/app.component.ts +52 -0
  9. package/templates/angular-demo/src/app/virtual-table/row-data.ts +35 -0
  10. package/templates/angular-demo/src/app/virtual-table/row-model.ts +45 -0
  11. package/templates/angular-demo/src/app/virtual-table/virtual-table-data.service.ts +136 -0
  12. package/templates/angular-demo/src/app/virtual-table/virtual-table-model.ts +224 -0
  13. package/templates/angular-demo/src/app/virtual-table/virtual-table.component.css +174 -0
  14. package/templates/angular-demo/src/app/virtual-table/virtual-table.component.html +50 -0
  15. package/templates/angular-demo/src/app/virtual-table/virtual-table.component.ts +83 -0
  16. package/templates/angular-demo/src/index.html +11 -0
  17. package/templates/angular-demo/src/main.ts +16 -0
  18. package/templates/angular-demo/src/styles.css +261 -0
  19. package/templates/react-demo/README.md +113 -0
  20. package/templates/react-demo/index.html +12 -0
  21. package/templates/react-demo/src/app/app.tsx +87 -0
  22. package/templates/react-demo/src/app/hooks/use-virtual-table-controller.ts +24 -0
  23. package/templates/react-demo/src/app/hooks/use-virtual-table-viewport.ts +39 -0
  24. package/templates/react-demo/src/app/virtual-table/row-data.ts +35 -0
  25. package/templates/react-demo/src/app/virtual-table/row-model.ts +45 -0
  26. package/templates/react-demo/src/app/virtual-table/virtual-table-controller.ts +247 -0
  27. package/templates/react-demo/src/app/virtual-table/virtual-table-data.service.ts +126 -0
  28. package/templates/react-demo/src/app/virtual-table/virtual-table-row.tsx +38 -0
  29. package/templates/react-demo/src/app/virtual-table/virtual-table-shell.tsx +83 -0
  30. package/templates/react-demo/src/main.tsx +23 -0
  31. package/templates/react-demo/src/rsx-bootstrap.ts +18 -0
  32. package/templates/react-demo/src/styles.css +422 -0
  33. package/templates/react-demo/tsconfig.json +17 -0
@@ -0,0 +1,261 @@
1
+ :root {
2
+ --font-sans:
3
+ ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI',
4
+ sans-serif;
5
+ --font-mono:
6
+ ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Courier New',
7
+ monospace;
8
+
9
+ --bg: #f6f8fc;
10
+ --surface: rgba(255, 255, 255, 0.86);
11
+ --surface-2: rgba(255, 255, 255, 0.72);
12
+ --surface-solid: #ffffff;
13
+ --text: #0b1324;
14
+ --muted: rgba(11, 19, 36, 0.66);
15
+ --border: rgba(10, 25, 55, 0.14);
16
+ --border-soft: rgba(10, 25, 55, 0.1);
17
+ --brand: #0b66ff;
18
+ --brand-2: #2bb6a9;
19
+ --focus: rgba(11, 102, 255, 0.35);
20
+ --shadow-1:
21
+ 0 1px 2px rgba(16, 24, 40, 0.06), 0 12px 34px rgba(16, 24, 40, 0.1);
22
+ --shadow-2:
23
+ 0 2px 10px rgba(16, 24, 40, 0.08), 0 18px 52px rgba(16, 24, 40, 0.12);
24
+ --page-glow-a: rgba(11, 102, 255, 0.06);
25
+ --page-glow-b: rgba(43, 182, 169, 0.05);
26
+ --code-surface: #f7f9ff;
27
+ --hero-section-bg: linear-gradient(
28
+ 180deg,
29
+ rgba(255, 255, 255, 0.72),
30
+ rgba(255, 255, 255, 0.42)
31
+ );
32
+ --r-xl: 1.75rem;
33
+ --sp-2: 0.5rem;
34
+ --sp-3: 0.75rem;
35
+ --sp-4: 1rem;
36
+ --sp-5: 1.25rem;
37
+ --sp-6: 1.5rem;
38
+ --sp-7: 2rem;
39
+ --sp-8: 2.5rem;
40
+ --sp-9: 3rem;
41
+ --sp-10: 4rem;
42
+ --container: 1120px;
43
+ }
44
+
45
+ html[data-theme='dark'],
46
+ body[data-theme='dark'] {
47
+ --bg: #070b14;
48
+ --surface: rgba(12, 18, 35, 0.82);
49
+ --surface-2: rgba(12, 18, 35, 0.68);
50
+ --surface-solid: #0c1223;
51
+ --text: #edf2ff;
52
+ --muted: rgba(237, 242, 255, 0.7);
53
+ --border: rgba(237, 242, 255, 0.16);
54
+ --border-soft: rgba(237, 242, 255, 0.12);
55
+ --brand: #7ab6ff;
56
+ --brand-2: #49d9c8;
57
+ --focus: rgba(122, 182, 255, 0.35);
58
+ --shadow-1: 0 1px 2px rgba(0, 0, 0, 0.22), 0 12px 34px rgba(0, 0, 0, 0.32);
59
+ --shadow-2: 0 2px 10px rgba(0, 0, 0, 0.24), 0 18px 52px rgba(0, 0, 0, 0.34);
60
+ --page-glow-a: rgba(122, 182, 255, 0.1);
61
+ --page-glow-b: rgba(73, 217, 200, 0.08);
62
+ --code-surface: #0f182b;
63
+ --hero-section-bg: linear-gradient(
64
+ 180deg,
65
+ rgba(12, 18, 35, 0.56),
66
+ rgba(12, 18, 35, 0.24)
67
+ );
68
+ }
69
+
70
+ *,
71
+ *::before,
72
+ *::after {
73
+ box-sizing: border-box;
74
+ }
75
+
76
+ html,
77
+ body {
78
+ height: 100%;
79
+ }
80
+
81
+ html {
82
+ color-scheme: light;
83
+ background: var(--bg);
84
+ }
85
+
86
+ html[data-theme='dark'] {
87
+ color-scheme: dark;
88
+ background: var(--bg);
89
+ }
90
+
91
+ body {
92
+ margin: 0;
93
+ font-family: var(--font-sans);
94
+ color: var(--text);
95
+ background-color: var(--bg);
96
+ background:
97
+ radial-gradient(circle at top, var(--page-glow-a), transparent 32%),
98
+ radial-gradient(circle at 85% 12%, var(--page-glow-b), transparent 28%),
99
+ var(--bg);
100
+ transition:
101
+ background 180ms ease,
102
+ color 180ms ease;
103
+ }
104
+
105
+ html[data-theme='dark'] body,
106
+ body[data-theme='dark'] {
107
+ background-color: var(--bg);
108
+ background:
109
+ radial-gradient(circle at top, var(--page-glow-a), transparent 32%),
110
+ radial-gradient(circle at 85% 12%, var(--page-glow-b), transparent 28%),
111
+ var(--bg);
112
+ }
113
+
114
+ button,
115
+ input,
116
+ select,
117
+ textarea {
118
+ font: inherit;
119
+ }
120
+
121
+ .container {
122
+ max-width: var(--container);
123
+ margin: 0 auto;
124
+ padding: 0 var(--sp-6);
125
+ }
126
+
127
+ .hero {
128
+ position: relative;
129
+ padding: calc(var(--sp-10) + 1rem) 0 calc(var(--sp-8) + 0.5rem);
130
+ background: var(--hero-section-bg);
131
+ }
132
+
133
+ .heroGrid {
134
+ display: grid;
135
+ grid-template-columns: minmax(540px, 1.05fr) minmax(300px, 0.95fr);
136
+ column-gap: var(--sp-6);
137
+ row-gap: var(--sp-8);
138
+ align-items: center;
139
+ }
140
+
141
+ .heroLeft {
142
+ min-width: 0;
143
+ padding-top: var(--sp-4);
144
+ }
145
+
146
+ .hTitle {
147
+ margin: 0 0 var(--sp-5);
148
+ font-size: clamp(3.6rem, 5.2vw, 4.8rem);
149
+ line-height: 0.96;
150
+ letter-spacing: -0.052em;
151
+ }
152
+
153
+ .hSubhead {
154
+ margin: 0 0 var(--sp-2);
155
+ font-size: clamp(1.42rem, 2vw, 1.82rem);
156
+ font-weight: 640;
157
+ letter-spacing: -0.03em;
158
+ line-height: 1.08;
159
+ }
160
+
161
+ .hSub {
162
+ margin: var(--sp-5) 0 0;
163
+ color: var(--muted);
164
+ font-size: 1.1rem;
165
+ line-height: 1.72;
166
+ max-width: 31.5rem;
167
+ }
168
+
169
+ .heroActions {
170
+ display: flex;
171
+ flex-wrap: wrap;
172
+ gap: var(--sp-3);
173
+ margin-top: var(--sp-5);
174
+ }
175
+
176
+ .btn {
177
+ display: inline-flex;
178
+ align-items: center;
179
+ justify-content: center;
180
+ gap: var(--sp-2);
181
+ padding: 0.82rem 1.18rem;
182
+ border-radius: 14px;
183
+ border: 1px solid transparent;
184
+ font-weight: 800;
185
+ line-height: 1;
186
+ white-space: nowrap;
187
+ transition:
188
+ transform 160ms ease,
189
+ background 240ms ease,
190
+ border-color 240ms ease,
191
+ box-shadow 240ms ease;
192
+ }
193
+
194
+ .btn:active {
195
+ transform: translateY(1px);
196
+ }
197
+
198
+ .btnGhost {
199
+ background: var(--surface-2);
200
+ color: var(--text);
201
+ border-color: var(--border);
202
+ box-shadow: none;
203
+ }
204
+
205
+ .btnGhost:hover {
206
+ box-shadow: var(--shadow-1);
207
+ }
208
+
209
+ .card {
210
+ position: relative;
211
+ min-width: 0;
212
+ border: 1px solid var(--border-soft);
213
+ background: linear-gradient(180deg, var(--surface), var(--surface-2));
214
+ border-radius: var(--r-xl);
215
+ padding: var(--sp-6);
216
+ box-shadow: var(--shadow-1);
217
+ display: flex;
218
+ flex-direction: column;
219
+ }
220
+
221
+ .cardTitle {
222
+ margin: 0 0 var(--sp-3);
223
+ font-weight: 700;
224
+ font-size: clamp(1.12rem, 0.96vw, 1.22rem);
225
+ letter-spacing: -0.02em;
226
+ }
227
+
228
+ .cardText {
229
+ margin: 0;
230
+ color: var(--muted);
231
+ line-height: 1.62;
232
+ }
233
+
234
+ .heroNote {
235
+ align-self: center;
236
+ margin-top: 0;
237
+ }
238
+
239
+ .section {
240
+ padding: var(--sp-7) 0 var(--sp-10);
241
+ }
242
+
243
+ @media (max-width: 920px) {
244
+ .heroGrid {
245
+ grid-template-columns: 1fr;
246
+ }
247
+ }
248
+
249
+ @media (max-width: 720px) {
250
+ .container {
251
+ padding: 0 var(--sp-4);
252
+ }
253
+
254
+ .hero {
255
+ padding: calc(var(--sp-8) + 0.5rem) 0 var(--sp-8);
256
+ }
257
+
258
+ .hTitle {
259
+ font-size: clamp(2.9rem, 14vw, 3.6rem);
260
+ }
261
+ }
@@ -0,0 +1,113 @@
1
+ # rsx-react-example
2
+
3
+ React demo app for RS-X.
4
+
5
+ **Website & docs:** [rsxjs.com](https://www.rsxjs.com/)
6
+
7
+ This example shows a million-row virtual table that:
8
+
9
+ - uses the `useRsxExpression` hook from `@rs-x/react`
10
+ - creates row expressions with `rsx(...)`
11
+ - keeps a fixed pool of row models and expressions
12
+ - loads pages on demand while scrolling
13
+ - keeps memory bounded by reusing the row pool and pruning old page data
14
+
15
+ ## Install
16
+
17
+ ```bash
18
+ cd rsx-react-example
19
+ npm install
20
+ ```
21
+
22
+ ## Start
23
+
24
+ ```bash
25
+ npm run dev
26
+ ```
27
+
28
+ `npm run dev` first runs the RS-X build step, then starts Vite.
29
+
30
+ ## Build
31
+
32
+ ```bash
33
+ npm run build
34
+ ```
35
+
36
+ This runs:
37
+
38
+ 1. `rsx build --project tsconfig.json --no-emit --prod`
39
+ 2. `vite build`
40
+
41
+ So the example gets:
42
+
43
+ - RS-X semantic checks
44
+ - generated AOT RS-X caches
45
+ - React production build output
46
+
47
+ ## Basic RS-X React setup
48
+
49
+ The example uses the normal React RS-X setup:
50
+
51
+ ### 1. Initialize RS-X before rendering React
52
+
53
+ In `src/rsx-bootstrap.ts`:
54
+
55
+ ```ts
56
+ import { InjectionContainer } from '@rs-x/core';
57
+ import { RsXExpressionParserModule } from '@rs-x/expression-parser';
58
+
59
+ export async function initRsx(): Promise<void> {
60
+ await InjectionContainer.load(RsXExpressionParserModule);
61
+ }
62
+ ```
63
+
64
+ ### 2. Create expressions with `rsx(...)`
65
+
66
+ In `src/app/virtual-table/row-model.ts`:
67
+
68
+ ```ts
69
+ idExpr: rsx<number>('id')(model),
70
+ nameExpr: rsx<string>('name')(model),
71
+ totalExpr: rsx<number>('price * quantity')(model),
72
+ ```
73
+
74
+ ### 3. Bind them with `useRsxExpression`
75
+
76
+ In `src/app/virtual-table/virtual-table-row.tsx`:
77
+
78
+ ```tsx
79
+ const total = useRsxExpression(row.totalExpr);
80
+ return <span>{total}</span>;
81
+ ```
82
+
83
+ ## Why this example is useful
84
+
85
+ The point of the demo is not just rendering a table. It shows how RS-X behaves in a realistic React scenario:
86
+
87
+ - large logical dataset: `1,000,000` rows
88
+ - small live expression pool: only the pooled row models stay active
89
+ - page loading is async to simulate real server requests
90
+ - old loaded pages are pruned so scrolling does not grow memory forever
91
+
92
+ ## About the React integration in this demo
93
+
94
+ This example uses `useRsxExpression` directly in row components so the RS-X behavior is easy to see.
95
+
96
+ That is a demo choice, not a restriction.
97
+
98
+ In a real React app, you can also bridge RS-X values into other React-friendly state shapes such as `useSyncExternalStore`, memoized selectors, or your preferred state container if that fits better.
99
+
100
+ ## Key files
101
+
102
+ - `src/main.tsx`
103
+ - `src/rsx-bootstrap.ts`
104
+ - `src/app/app.tsx`
105
+ - `src/app/virtual-table/virtual-table-shell.tsx`
106
+ - `src/app/virtual-table/virtual-table-row.tsx`
107
+ - `src/app/virtual-table/virtual-table-controller.ts`
108
+ - `src/app/virtual-table/virtual-table-data.service.ts`
109
+ - `src/app/virtual-table/row-model.ts`
110
+
111
+ ## Notes
112
+
113
+ - The virtual table uses a bounded pool and bounded page retention on purpose, so performance characteristics stay visible while memory stays under control.
@@ -0,0 +1,12 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>RS-X React Demo</title>
7
+ </head>
8
+ <body>
9
+ <div id="root"></div>
10
+ <script type="module" src="/src/main.tsx"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,87 @@
1
+ import { type FC, useEffect, useState } from 'react';
2
+
3
+ import { VirtualTableShell } from './virtual-table/virtual-table-shell';
4
+
5
+ type ThemeMode = 'light' | 'dark';
6
+
7
+ function getInitialTheme(): ThemeMode {
8
+ const storedTheme = window.localStorage.getItem('rsx-theme');
9
+ if (storedTheme === 'light' || storedTheme === 'dark') {
10
+ return storedTheme;
11
+ }
12
+
13
+ return 'dark';
14
+ }
15
+
16
+ export const App: FC = () => {
17
+ const [theme, setTheme] = useState<ThemeMode>(() => getInitialTheme());
18
+
19
+ useEffect(() => {
20
+ document.documentElement.setAttribute('data-theme', theme);
21
+ document.body.setAttribute('data-theme', theme);
22
+ window.localStorage.setItem('rsx-theme', theme);
23
+ }, [theme]);
24
+
25
+ return (
26
+ <main className="app-shell">
27
+ <section className="hero">
28
+ <div className="container">
29
+ <div className="heroGrid">
30
+ <div className="heroLeft">
31
+ <p className="app-eyebrow">RS-X React Demo</p>
32
+ <h1 className="hTitle">Virtual Table</h1>
33
+ <p className="hSubhead">
34
+ Million-row scrolling with a fixed RS-X expression pool.
35
+ </p>
36
+ <p className="hSub">
37
+ This demo keeps rendering bounded while streaming pages on demand,
38
+ so scrolling stays smooth without growing expression memory with the
39
+ dataset.
40
+ </p>
41
+
42
+ <div className="heroActions">
43
+ <a
44
+ className="btn btnGhost"
45
+ href="https://www.rsxjs.com/"
46
+ target="_blank"
47
+ rel="noreferrer"
48
+ >
49
+ rs-x
50
+ </a>
51
+ <button
52
+ type="button"
53
+ className="btn btnGhost theme-toggle"
54
+ aria-label={`Switch to ${theme === 'dark' ? 'light' : 'dark'} mode`}
55
+ onClick={() => {
56
+ setTheme((currentTheme) =>
57
+ currentTheme === 'dark' ? 'light' : 'dark',
58
+ );
59
+ }}
60
+ >
61
+ {theme === 'dark' ? 'Light mode' : 'Dark mode'}
62
+ </button>
63
+ </div>
64
+ </div>
65
+
66
+ <aside className="card heroNote">
67
+ <h2 className="cardTitle">What This Shows</h2>
68
+ <p className="cardText">
69
+ Only a small row-model pool stays alive while pages stream in
70
+ around the viewport. That means one million logical rows without
71
+ one million live bindings.
72
+ </p>
73
+ </aside>
74
+ </div>
75
+ </div>
76
+ </section>
77
+
78
+ <section className="section">
79
+ <div className="container">
80
+ <section className="app-panel card">
81
+ <VirtualTableShell />
82
+ </section>
83
+ </div>
84
+ </section>
85
+ </main>
86
+ );
87
+ };
@@ -0,0 +1,24 @@
1
+ import { useRef, useSyncExternalStore } from 'react';
2
+
3
+ import {
4
+ VirtualTableController,
5
+ type VirtualTableSnapshot,
6
+ } from '../virtual-table/virtual-table-controller';
7
+
8
+ export function useVirtualTableController(): {
9
+ controller: VirtualTableController;
10
+ snapshot: VirtualTableSnapshot;
11
+ } {
12
+ const controllerRef = useRef<VirtualTableController | null>(null);
13
+ if (!controllerRef.current) {
14
+ controllerRef.current = new VirtualTableController();
15
+ }
16
+ const controller = controllerRef.current;
17
+ const snapshot = useSyncExternalStore(
18
+ controller.subscribe,
19
+ controller.getSnapshot,
20
+ controller.getSnapshot,
21
+ );
22
+
23
+ return { controller, snapshot };
24
+ }
@@ -0,0 +1,39 @@
1
+ import { type RefObject, useEffect, useRef } from 'react';
2
+
3
+ import type { VirtualTableController } from '../virtual-table/virtual-table-controller';
4
+
5
+ const COMPACT_BREAKPOINT_PX = 720;
6
+ const DEFAULT_ROW_HEIGHT = 36;
7
+ const COMPACT_ROW_HEIGHT = 168;
8
+
9
+ export function useVirtualTableViewport(
10
+ controller: VirtualTableController,
11
+ ): RefObject<HTMLDivElement | null> {
12
+ const viewportRef = useRef<HTMLDivElement | null>(null);
13
+
14
+ useEffect(() => {
15
+ const viewport = viewportRef.current;
16
+ if (!viewport) {
17
+ return;
18
+ }
19
+
20
+ const syncMetrics = (): void => {
21
+ controller.setViewportHeight(viewport.clientHeight);
22
+ controller.setRowHeight(
23
+ viewport.clientWidth <= COMPACT_BREAKPOINT_PX
24
+ ? COMPACT_ROW_HEIGHT
25
+ : DEFAULT_ROW_HEIGHT,
26
+ );
27
+ };
28
+
29
+ syncMetrics();
30
+ const observer = new ResizeObserver(syncMetrics);
31
+ observer.observe(viewport);
32
+
33
+ return () => {
34
+ observer.disconnect();
35
+ };
36
+ }, [controller]);
37
+
38
+ return viewportRef;
39
+ }
@@ -0,0 +1,35 @@
1
+ export type SortKey = 'id' | 'name' | 'price' | 'quantity' | 'category';
2
+ export type SortDirection = 'asc' | 'desc';
3
+
4
+ export type RowData = {
5
+ id: number;
6
+ name: string;
7
+ price: number;
8
+ quantity: number;
9
+ category: string;
10
+ updatedAt: string;
11
+ };
12
+
13
+ const categories = ['Hardware', 'Software', 'Design', 'Ops'];
14
+
15
+ function pad(value: number): string {
16
+ return value.toString().padStart(2, '0');
17
+ }
18
+
19
+ export function createRowData(id: number): RowData {
20
+ const zeroBasedId = id - 1;
21
+ const price = 25 + (zeroBasedId % 1000) / 10;
22
+ const quantity = 1 + (Math.floor(zeroBasedId / 1000) % 100);
23
+ const category = categories[zeroBasedId % categories.length] ?? 'General';
24
+ const month = pad(((zeroBasedId * 7) % 12) + 1);
25
+ const day = pad(((zeroBasedId * 11) % 28) + 1);
26
+
27
+ return {
28
+ id,
29
+ name: `Product ${id.toString().padStart(7, '0')}`,
30
+ price,
31
+ quantity,
32
+ category,
33
+ updatedAt: `2026-${month}-${day}`,
34
+ };
35
+ }
@@ -0,0 +1,45 @@
1
+ import { rsx, type IExpression } from '@rs-x/expression-parser';
2
+
3
+ import type { RowData } from './row-data';
4
+
5
+ export type RowModel = {
6
+ model: RowData;
7
+ idExpr: IExpression<number>;
8
+ nameExpr: IExpression<string>;
9
+ categoryExpr: IExpression<string>;
10
+ priceExpr: IExpression<number>;
11
+ quantityExpr: IExpression<number>;
12
+ updatedAtExpr: IExpression<string>;
13
+ totalExpr: IExpression<number>;
14
+ };
15
+
16
+ export function createRowModel(): RowModel {
17
+ const model: RowData = {
18
+ id: 0,
19
+ name: '',
20
+ price: 0,
21
+ quantity: 0,
22
+ category: 'General',
23
+ updatedAt: '2026-01-01',
24
+ };
25
+
26
+ return {
27
+ model,
28
+ idExpr: rsx<number>('id')(model),
29
+ nameExpr: rsx<string>('name')(model),
30
+ categoryExpr: rsx<string>('category')(model),
31
+ priceExpr: rsx<number>('price')(model),
32
+ quantityExpr: rsx<number>('quantity')(model),
33
+ updatedAtExpr: rsx<string>('updatedAt')(model),
34
+ totalExpr: rsx<number>('price * quantity')(model),
35
+ };
36
+ }
37
+
38
+ export function updateRowModel(target: RowModel, data: RowData): void {
39
+ target.model.id = data.id;
40
+ target.model.name = data.name;
41
+ target.model.price = data.price;
42
+ target.model.quantity = data.quantity;
43
+ target.model.category = data.category;
44
+ target.model.updatedAt = data.updatedAt;
45
+ }