@crownpeak/dqm-react-component 1.0.0 → 1.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.
- package/CHANGELOG.md +31 -0
- package/DEVELOPMENT.md +36 -1
- package/EXAMPLES.md +187 -0
- package/QUICKSTART.md +7 -0
- package/README.md +75 -1
- package/dist/DQMSidebar.d.ts.map +1 -1
- package/dist/auth-ui/assets/index-CczTRrba.js +158 -0
- package/dist/auth-ui/index.html +1 -1
- package/dist/components/renderers/BrowserViewRenderer.d.ts +1 -0
- package/dist/components/renderers/BrowserViewRenderer.d.ts.map +1 -1
- package/dist/components/sidebar/CloseButton.d.ts +6 -0
- package/dist/components/sidebar/CloseButton.d.ts.map +1 -0
- package/dist/components/sidebar/SidebarContent.d.ts.map +1 -1
- package/dist/components/sidebar/SidebarFooter.d.ts.map +1 -1
- package/dist/components/sidebar/SidebarHeader.d.ts.map +1 -1
- package/dist/components/sidebar/SidebarSkeleton.d.ts.map +1 -1
- package/dist/components/sidebar/StyledDrawer.d.ts +6 -1
- package/dist/components/sidebar/StyledDrawer.d.ts.map +1 -1
- package/dist/components/sidebar/StyledFab.d.ts +4 -1
- package/dist/components/sidebar/StyledFab.d.ts.map +1 -1
- package/dist/dqm-widget.d.ts +107 -0
- package/dist/dqm-widget.esm.js +386 -0
- package/dist/dqm-widget.iife.js +132 -0
- package/dist/html-pages/DQMWidget.d.ts +36 -0
- package/dist/html-pages/DQMWidget.d.ts.map +1 -0
- package/dist/html-pages/index.d.ts +32 -0
- package/dist/html-pages/index.d.ts.map +1 -0
- package/dist/index.cjs +27 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.html +498 -0
- package/dist/index.js +4665 -4424
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +83 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/useDomPresence.d.ts +210 -0
- package/dist/utils/useDomPresence.d.ts.map +1 -0
- package/package.json +26 -17
- package/dist/auth-ui/assets/index-CehNKFGj.js +0 -158
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,37 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.1.0] - 2025-12-17
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **Overlay Configuration**: New `overlayConfig` option in `DQMConfig` for customizing overlay/toolbar detection
|
|
12
|
+
- `selector`: Custom CSS selector for overlay elements
|
|
13
|
+
- `validateIframe`: Option to validate iFrame contentWindow availability
|
|
14
|
+
- `pollMs`: Configurable polling interval for cross-origin iFrame detection
|
|
15
|
+
- `manualOffset`: Manual offset configuration for cases where auto-detection fails
|
|
16
|
+
- **Enhanced `useDomPresence` Hook**: Now returns comprehensive element information including:
|
|
17
|
+
- `rect`: Element bounding rectangle (height, width, top, bottom, left, right)
|
|
18
|
+
- `position`: Detected position ('top', 'bottom', 'left', 'right', 'center')
|
|
19
|
+
- `contentOffset`: Ready-to-use offsets for positioning UI elements
|
|
20
|
+
- **New Exports**:
|
|
21
|
+
- `useOverlayResistant` hook for advanced overlay handling
|
|
22
|
+
- `OverlayConfig`, `OverlayOffsetPosition`, `OverlayInfo`, `OverlayPosition` types
|
|
23
|
+
- **Standalone Widget Bundle**: New widget build (IIFE + ESM) with `initDQMWidget`, Shadow DOM isolation, and Emotion cache binding for safe embedding on any site.
|
|
24
|
+
- **Widget Tooling & Types**: Added loader utilities, TypeScript declarations, and public exports for widget consumers.
|
|
25
|
+
- **Integration Demos**: New demo pages for IIFE, ESM, dynamic loading, and standalone widget usage to test the bundled widget end-to-end.
|
|
26
|
+
- **Config Option `disableLogout`**: Allows host apps to hide the sidebar logout control when session lifecycle is managed externally.
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
- `useOverlayResistant` hook now accepts configuration options
|
|
30
|
+
- `OverlayInfo` interface now includes `isManualOffset` flag
|
|
31
|
+
- Sidebar header, content, footer, skeleton, and FAB now respect overlay offsets for consistent spacing around external toolbars.
|
|
32
|
+
|
|
33
|
+
## [1.0.1] - 2025-12-08
|
|
34
|
+
|
|
35
|
+
### Fixed
|
|
36
|
+
- Resolved issue with error highlighting in certain browsers
|
|
37
|
+
- Fixed TypeScript type definition for DQMSidebar props
|
|
38
|
+
|
|
8
39
|
## [1.0.0] - 2025-10-30
|
|
9
40
|
|
|
10
41
|
### Added
|
package/DEVELOPMENT.md
CHANGED
|
@@ -39,6 +39,7 @@ crownpeak-dqm-react-component/
|
|
|
39
39
|
│ ├── index.ts # Library entry point
|
|
40
40
|
│ ├── App.tsx # Dev test harness
|
|
41
41
|
│ └── main.tsx # Dev app entry
|
|
42
|
+
│ ├── html-pages/ # Widget entrypoint, loaders, declarations
|
|
42
43
|
│
|
|
43
44
|
├── server/ # Backend API
|
|
44
45
|
│ ├── routes/ # API endpoints
|
|
@@ -55,9 +56,14 @@ crownpeak-dqm-react-component/
|
|
|
55
56
|
├── dist/ # Build output
|
|
56
57
|
│ ├── index.js # Library ESM
|
|
57
58
|
│ ├── index.cjs # Library CommonJS
|
|
58
|
-
│ ├── index.d.ts #
|
|
59
|
+
│ ├── index.d.ts # Library type declarations
|
|
60
|
+
│ ├── dqm-widget.esm.js # Widget bundle (ESM)
|
|
61
|
+
│ ├── dqm-widget.iife.js # Widget bundle (IIFE)
|
|
62
|
+
│ └── dqm-widget.d.ts # Widget type declarations
|
|
59
63
|
│ └── server/ # Compiled server code
|
|
60
64
|
│
|
|
65
|
+
├── test/ # Demo pages for widget bundles
|
|
66
|
+
├── public/ # Landing page for demos
|
|
61
67
|
├── vite.config.ts # Vite configuration
|
|
62
68
|
├── tsconfig.json # TypeScript base config
|
|
63
69
|
├── tsconfig.lib.json # Library build config
|
|
@@ -134,6 +140,14 @@ npm run build:lib
|
|
|
134
140
|
|
|
135
141
|
Output: `dist/index.{js,cjs,d.ts}`
|
|
136
142
|
|
|
143
|
+
### Build Widget Bundle
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
npm run build:widget
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Output: `dist/dqm-widget.{esm.js,iife.js,d.ts}` (fully bundled, Shadow DOM-safe)
|
|
150
|
+
|
|
137
151
|
### Build Server
|
|
138
152
|
|
|
139
153
|
```bash
|
|
@@ -142,6 +156,14 @@ npm run build:server
|
|
|
142
156
|
|
|
143
157
|
Output: `dist/server/`
|
|
144
158
|
|
|
159
|
+
### Build Everything
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
npm run build
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Runs library + widget + backend + auth UI builds.
|
|
166
|
+
|
|
145
167
|
### Test Library Build
|
|
146
168
|
|
|
147
169
|
```bash
|
|
@@ -149,6 +171,19 @@ npm pack
|
|
|
149
171
|
# Creates: crownpeak-dqm-react-component-1.0.0.tgz
|
|
150
172
|
```
|
|
151
173
|
|
|
174
|
+
### Preview Widget Bundle Locally
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
npm run build:widget
|
|
178
|
+
npm run serve:widget
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Serves `dist/` plus demo pages via `serve.json` rewrites:
|
|
182
|
+
- `/test/demo-iife.html` for IIFE bundle
|
|
183
|
+
- `/test/demo-esm.html` for ESM bundle
|
|
184
|
+
- `/test/demo-dynamic.html` for lazy loading
|
|
185
|
+
- `/test/widget-standalone.html` for full standalone demo
|
|
186
|
+
|
|
152
187
|
## Environment Configuration
|
|
153
188
|
|
|
154
189
|
### Frontend (.env)
|
package/EXAMPLES.md
CHANGED
|
@@ -192,3 +192,190 @@ function App() {
|
|
|
192
192
|
}
|
|
193
193
|
```
|
|
194
194
|
|
|
195
|
+
## With Overlay/Toolbar Configuration
|
|
196
|
+
|
|
197
|
+
Use `overlayConfig` to offset the sidebar when toolbars or overlays are present.
|
|
198
|
+
|
|
199
|
+
### Auto-Detection (Toolbar Selector)
|
|
200
|
+
|
|
201
|
+
```tsx
|
|
202
|
+
import { DQMSidebar } from '@crownpeak/dqm-react-component';
|
|
203
|
+
|
|
204
|
+
function App() {
|
|
205
|
+
const [sidebarOpen, setSidebarOpen] = useState(false);
|
|
206
|
+
|
|
207
|
+
return (
|
|
208
|
+
<DQMSidebar
|
|
209
|
+
open={sidebarOpen}
|
|
210
|
+
onClose={() => setSidebarOpen(false)}
|
|
211
|
+
onOpen={() => setSidebarOpen(true)}
|
|
212
|
+
config={{
|
|
213
|
+
overlayConfig: {
|
|
214
|
+
// Example toolbar anchored to the top edge
|
|
215
|
+
selector: '.preview-toolbar',
|
|
216
|
+
validateIframe: false
|
|
217
|
+
}
|
|
218
|
+
}}
|
|
219
|
+
/>
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
### Auto-Detection (Custom Selector)
|
|
224
|
+
|
|
225
|
+
```tsx
|
|
226
|
+
import { DQMSidebar } from '@crownpeak/dqm-react-component';
|
|
227
|
+
|
|
228
|
+
function App() {
|
|
229
|
+
const [open, setOpen] = useState(false);
|
|
230
|
+
|
|
231
|
+
return (
|
|
232
|
+
<DQMSidebar
|
|
233
|
+
open={open}
|
|
234
|
+
onClose={() => setOpen(false)}
|
|
235
|
+
onOpen={() => setOpen(true)}
|
|
236
|
+
config={{
|
|
237
|
+
overlayConfig: {
|
|
238
|
+
selector: 'iframe#my-overlay',
|
|
239
|
+
}
|
|
240
|
+
}}
|
|
241
|
+
/>
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Custom Selector
|
|
247
|
+
|
|
248
|
+
```tsx
|
|
249
|
+
import { DQMSidebar } from '@crownpeak/dqm-react-component';
|
|
250
|
+
|
|
251
|
+
function App() {
|
|
252
|
+
const [open, setOpen] = useState(false);
|
|
253
|
+
|
|
254
|
+
return (
|
|
255
|
+
<DQMSidebar
|
|
256
|
+
open={open}
|
|
257
|
+
onClose={() => setOpen(false)}
|
|
258
|
+
onOpen={() => setOpen(true)}
|
|
259
|
+
config={{
|
|
260
|
+
overlayConfig: {
|
|
261
|
+
// Custom selector for your admin toolbar
|
|
262
|
+
selector: '.admin-toolbar-header',
|
|
263
|
+
// Disable iFrame validation for non-iFrame elements
|
|
264
|
+
validateIframe: false,
|
|
265
|
+
}
|
|
266
|
+
}}
|
|
267
|
+
/>
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### Manual Offset (for Cross-Origin iFrames)
|
|
273
|
+
|
|
274
|
+
When the overlay is a cross-origin iFrame that fills the entire screen but has
|
|
275
|
+
a smaller internal toolbar, auto-detection won't work. Use manual offset:
|
|
276
|
+
|
|
277
|
+
```tsx
|
|
278
|
+
import { DQMSidebar } from '@crownpeak/dqm-react-component';
|
|
279
|
+
|
|
280
|
+
function App() {
|
|
281
|
+
const [open, setOpen] = useState(false);
|
|
282
|
+
|
|
283
|
+
return (
|
|
284
|
+
<DQMSidebar
|
|
285
|
+
open={open}
|
|
286
|
+
onClose={() => setOpen(false)}
|
|
287
|
+
onOpen={() => setOpen(true)}
|
|
288
|
+
config={{
|
|
289
|
+
overlayConfig: {
|
|
290
|
+
// Manual offset: 50px from the top
|
|
291
|
+
manualOffset: {
|
|
292
|
+
position: 'top',
|
|
293
|
+
pixels: 50
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}}
|
|
297
|
+
/>
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### Disable Overlay Detection
|
|
303
|
+
|
|
304
|
+
```tsx
|
|
305
|
+
import { DQMSidebar } from '@crownpeak/dqm-react-component';
|
|
306
|
+
|
|
307
|
+
function App() {
|
|
308
|
+
const [open, setOpen] = useState(false);
|
|
309
|
+
|
|
310
|
+
return (
|
|
311
|
+
<DQMSidebar
|
|
312
|
+
open={open}
|
|
313
|
+
onClose={() => setOpen(false)}
|
|
314
|
+
onOpen={() => setOpen(true)}
|
|
315
|
+
config={{
|
|
316
|
+
overlayConfig: {
|
|
317
|
+
// Disable all overlay detection
|
|
318
|
+
selector: null
|
|
319
|
+
}
|
|
320
|
+
}}
|
|
321
|
+
/>
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### Disable Logout Button
|
|
327
|
+
|
|
328
|
+
```tsx
|
|
329
|
+
import { DQMSidebar } from '@crownpeak/dqm-react-component';
|
|
330
|
+
|
|
331
|
+
function App() {
|
|
332
|
+
const [open, setOpen] = useState(false);
|
|
333
|
+
|
|
334
|
+
return (
|
|
335
|
+
<DQMSidebar
|
|
336
|
+
open={open}
|
|
337
|
+
onClose={() => setOpen(false)}
|
|
338
|
+
onOpen={() => setOpen(true)}
|
|
339
|
+
config={{
|
|
340
|
+
// Host app controls session lifecycle; hide logout control in the sidebar
|
|
341
|
+
disableLogout: true,
|
|
342
|
+
}}
|
|
343
|
+
/>
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### Advanced: Using the Hook Directly
|
|
349
|
+
|
|
350
|
+
For custom UI components that need overlay information:
|
|
351
|
+
|
|
352
|
+
```tsx
|
|
353
|
+
import { useOverlayResistant } from '@crownpeak/dqm-react-component';
|
|
354
|
+
import type { OverlayInfo } from '@crownpeak/dqm-react-component';
|
|
355
|
+
|
|
356
|
+
function MyFloatingButton() {
|
|
357
|
+
const overlay: OverlayInfo = useOverlayResistant({
|
|
358
|
+
selector: '...',
|
|
359
|
+
validateIframe: true,
|
|
360
|
+
pollMs: 1000,
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
return (
|
|
364
|
+
<button
|
|
365
|
+
style={{
|
|
366
|
+
position: 'fixed',
|
|
367
|
+
top: overlay.present
|
|
368
|
+
? `${overlay.contentOffset.top + 16}px`
|
|
369
|
+
: '16px',
|
|
370
|
+
right: '16px',
|
|
371
|
+
zIndex: 9999,
|
|
372
|
+
}}
|
|
373
|
+
>
|
|
374
|
+
{overlay.present
|
|
375
|
+
? `Toolbar at ${overlay.position} (${overlay.height}px)`
|
|
376
|
+
: 'No toolbar detected'}
|
|
377
|
+
</button>
|
|
378
|
+
);
|
|
379
|
+
}
|
|
380
|
+
```
|
|
381
|
+
|
package/QUICKSTART.md
CHANGED
|
@@ -12,6 +12,13 @@ npm install
|
|
|
12
12
|
npm run build
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
+
### Build widget only (for standalone script usage)
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm run build:widget
|
|
19
|
+
npm run serve:widget # preview demos at http://localhost:4173/test/demo-iife.html etc.
|
|
20
|
+
```
|
|
21
|
+
|
|
15
22
|
## Start Development
|
|
16
23
|
|
|
17
24
|
```bash
|
package/README.md
CHANGED
|
@@ -70,6 +70,8 @@ export default App;
|
|
|
70
70
|
- **[Authentication Guide](./AUTHENTICATION.md)** - OAuth 2.0 setup and configuration
|
|
71
71
|
- **[Backend API](./BACKEND-API.md)** - API endpoints and usage
|
|
72
72
|
- **[Development Guide](./DEVELOPMENT.md)** - Contributing and local development
|
|
73
|
+
- **Standalone Widget** - Use the fully bundled widget via `/dist/dqm-widget.{esm.js,iife.js}` (see Quick Start and test
|
|
74
|
+
demos under `test/`)
|
|
73
75
|
|
|
74
76
|
## 🔑 Authentication Setup
|
|
75
77
|
|
|
@@ -143,6 +145,71 @@ See [REDIS-SETUP.md](./REDIS-SETUP.md) for Redis installation.
|
|
|
143
145
|
| `onClose` | `() => void` | ✅ | Callback when sidebar closes |
|
|
144
146
|
| `onOpen` | `() => void` | ✅ | Callback when sidebar opens |
|
|
145
147
|
| `debugHtml` | `string` | ❌ | HTML for testing (dev only) |
|
|
148
|
+
| `config` | `DQMConfig` | ❌ | Configuration options |
|
|
149
|
+
|
|
150
|
+
### DQMConfig Options
|
|
151
|
+
|
|
152
|
+
| Option | Type | Default | Description |
|
|
153
|
+
|-------------------|-----------------|---------|------------------------------------------------|
|
|
154
|
+
| `apiKey` | `string` | - | Direct API key (not for production) |
|
|
155
|
+
| `websiteId` | `string` | - | Website ID for DQM |
|
|
156
|
+
| `authBackendUrl` | `string` | - | Backend URL for session management |
|
|
157
|
+
| `useLocalStorage` | `boolean` | `true` | Persist credentials in localStorage |
|
|
158
|
+
| `disabled` | `boolean` | `false` | Disable DQM completely |
|
|
159
|
+
| `disableLogout` | `boolean` | `false` | Hide the logout control (host manages session) |
|
|
160
|
+
| `shadowDomMode` | `boolean` | `false` | Enable for Shadow DOM embedding |
|
|
161
|
+
| `overlayConfig` | `OverlayConfig` | - | Overlay/toolbar detection config |
|
|
162
|
+
|
|
163
|
+
### OverlayConfig (for Toolbars & Overlays)
|
|
164
|
+
|
|
165
|
+
Configure how the sidebar adapts to fixed overlays (e.g., admin toolbars):
|
|
166
|
+
|
|
167
|
+
```tsx
|
|
168
|
+
<DQMSidebar
|
|
169
|
+
config={{
|
|
170
|
+
overlayConfig: {
|
|
171
|
+
// CSS selector for the overlay element
|
|
172
|
+
selector: 'iframe#MyToolbar',
|
|
173
|
+
|
|
174
|
+
// Validate iFrame has contentWindow (default: true)
|
|
175
|
+
validateIframe: true,
|
|
176
|
+
|
|
177
|
+
// Polling interval in ms for cross-origin iFrames (default: 1000)
|
|
178
|
+
pollMs: 1000,
|
|
179
|
+
|
|
180
|
+
// OR: Manual offset when auto-detection doesn't work
|
|
181
|
+
// (e.g., for iFrames that fill screen but have smaller internal content)
|
|
182
|
+
manualOffset: {
|
|
183
|
+
position: 'top', // 'top' | 'bottom' | 'left' | 'right'
|
|
184
|
+
pixels: 50
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}}
|
|
188
|
+
/>
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
**Common overlay configurations:**
|
|
192
|
+
|
|
193
|
+
[//]: # (@formatter:off)
|
|
194
|
+
```tsx
|
|
195
|
+
// Disable overlay detection
|
|
196
|
+
overlayConfig: {
|
|
197
|
+
selector: null
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Manual 50px offset from top
|
|
201
|
+
overlayConfig: {
|
|
202
|
+
manualOffset: {
|
|
203
|
+
position: 'top', pixels: 50
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Custom selector without iFrame validation
|
|
208
|
+
overlayConfig: {
|
|
209
|
+
selector: '.admin-toolbar', validateIframe: false
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
[//]: # (@formatter:on)
|
|
146
213
|
|
|
147
214
|
### Exported Types
|
|
148
215
|
|
|
@@ -151,8 +218,15 @@ import type {
|
|
|
151
218
|
AnalysisState,
|
|
152
219
|
Checkpoint,
|
|
153
220
|
AnalysisData,
|
|
154
|
-
DQMSidebarProps
|
|
221
|
+
DQMSidebarProps,
|
|
222
|
+
DQMConfig,
|
|
223
|
+
OverlayConfig,
|
|
224
|
+
OverlayOffsetPosition
|
|
155
225
|
} from '@crownpeak/dqm-react-component';
|
|
226
|
+
|
|
227
|
+
// For advanced overlay handling
|
|
228
|
+
import {useOverlayResistant} from '@crownpeak/dqm-react-component';
|
|
229
|
+
import type {OverlayInfo, OverlayPosition} from '@crownpeak/dqm-react-component';
|
|
156
230
|
```
|
|
157
231
|
|
|
158
232
|
See [TypeScript examples](./EXAMPLES.md#typescript-configuration) for full type definitions.
|
package/dist/DQMSidebar.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DQMSidebar.d.ts","sourceRoot":"","sources":["../src/DQMSidebar.tsx"],"names":[],"mappings":"AACA,OAAO,KAAyC,MAAM,OAAO,CAAC;AAuC9D,OAAO,KAAK,EAA8B,eAAe,EAAc,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"DQMSidebar.d.ts","sourceRoot":"","sources":["../src/DQMSidebar.tsx"],"names":[],"mappings":"AACA,OAAO,KAAyC,MAAM,OAAO,CAAC;AAuC9D,OAAO,KAAK,EAA8B,eAAe,EAAc,MAAM,SAAS,CAAC;AAoBvF,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CAkpEhD,CAAC;AAEF,eAAe,UAAU,CAAC"}
|